diff --git a/.gitignore b/.gitignore index 51bd99d6a260..cecb3b040cc1 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,7 @@ # subdirectories here. Add them in the ".gitignore" file # in that subdirectory instead. # -# NOTE! Please use 'git-ls-files -i --exclude-standard' +# NOTE! Please use 'git ls-files -i --exclude-standard' # command after changing this file, to see if there are # any tracked files which get ignored after the change. # @@ -25,6 +25,8 @@ *.elf *.bin *.gz +*.lzma +*.patch # # Top-level generic files @@ -62,6 +64,12 @@ series cscope.* ncscope.* +# gnu global files +GPATH +GRTAGS +GSYMS +GTAGS + *.orig *~ \#*# diff --git a/CREDITS b/CREDITS index 2520ba620ff1..2b88fb37ad50 100644 --- a/CREDITS +++ b/CREDITS @@ -1253,6 +1253,10 @@ S: 8124 Constitution Apt. 7 S: Sterling Heights, Michigan 48313 S: USA +N: Wolfgang Grandegger +E: wg@grandegger.com +D: Controller Area Network (device drivers) + N: William Greathouse E: wgreathouse@smva.com E: wgreathouse@myfavoritei.com diff --git a/Documentation/ABI/testing/sysfs-block b/Documentation/ABI/testing/sysfs-block index 44f52a4f5903..cbbd3e069945 100644 --- a/Documentation/ABI/testing/sysfs-block +++ b/Documentation/ABI/testing/sysfs-block @@ -60,3 +60,62 @@ Description: Indicates whether the block layer should automatically generate checksums for write requests bound for devices that support receiving integrity metadata. + +What: /sys/block//alignment_offset +Date: April 2009 +Contact: Martin K. Petersen +Description: + Storage devices may report a physical block size that is + bigger than the logical block size (for instance a drive + with 4KB physical sectors exposing 512-byte logical + blocks to the operating system). This parameter + indicates how many bytes the beginning of the device is + offset from the disk's natural alignment. + +What: /sys/block///alignment_offset +Date: April 2009 +Contact: Martin K. Petersen +Description: + Storage devices may report a physical block size that is + bigger than the logical block size (for instance a drive + with 4KB physical sectors exposing 512-byte logical + blocks to the operating system). This parameter + indicates how many bytes the beginning of the partition + is offset from the disk's natural alignment. + +What: /sys/block//queue/logical_block_size +Date: May 2009 +Contact: Martin K. Petersen +Description: + This is the smallest unit the storage device can + address. It is typically 512 bytes. + +What: /sys/block//queue/physical_block_size +Date: May 2009 +Contact: Martin K. Petersen +Description: + This is the smallest unit the storage device can write + without resorting to read-modify-write operation. It is + usually the same as the logical block size but may be + bigger. One example is SATA drives with 4KB sectors + that expose a 512-byte logical block size to the + operating system. + +What: /sys/block//queue/minimum_io_size +Date: April 2009 +Contact: Martin K. Petersen +Description: + Storage devices may report a preferred minimum I/O size, + which is the smallest request the device can perform + without incurring a read-modify-write penalty. For disk + drives this is often the physical block size. For RAID + arrays it is often the stripe chunk size. + +What: /sys/block//queue/optimal_io_size +Date: April 2009 +Contact: Martin K. Petersen +Description: + Storage devices may report an optimal I/O size, which is + the device's preferred unit of receiving I/O. This is + rarely reported for disk drives. For RAID devices it is + usually the stripe width or the internal block size. diff --git a/Documentation/ABI/testing/sysfs-bus-pci b/Documentation/ABI/testing/sysfs-bus-pci index 97ad190e13af..6bf68053e4b8 100644 --- a/Documentation/ABI/testing/sysfs-bus-pci +++ b/Documentation/ABI/testing/sysfs-bus-pci @@ -122,3 +122,10 @@ Description: This symbolic link appears when a device is a Virtual Function. The symbolic link points to the PCI device sysfs entry of the Physical Function this device associates with. + +What: /sys/bus/pci/slots/.../module +Date: June 2009 +Contact: linux-pci@vger.kernel.org +Description: + This symbolic link points to the PCI hotplug controller driver + module that manages the hotplug slot. diff --git a/Documentation/ABI/testing/sysfs-bus-pci-devices-cciss b/Documentation/ABI/testing/sysfs-bus-pci-devices-cciss new file mode 100644 index 000000000000..0a92a7c93a62 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-pci-devices-cciss @@ -0,0 +1,33 @@ +Where: /sys/bus/pci/devices//ccissX/cXdY/model +Date: March 2009 +Kernel Version: 2.6.30 +Contact: iss_storagedev@hp.com +Description: Displays the SCSI INQUIRY page 0 model for logical drive + Y of controller X. + +Where: /sys/bus/pci/devices//ccissX/cXdY/rev +Date: March 2009 +Kernel Version: 2.6.30 +Contact: iss_storagedev@hp.com +Description: Displays the SCSI INQUIRY page 0 revision for logical + drive Y of controller X. + +Where: /sys/bus/pci/devices//ccissX/cXdY/unique_id +Date: March 2009 +Kernel Version: 2.6.30 +Contact: iss_storagedev@hp.com +Description: Displays the SCSI INQUIRY page 83 serial number for logical + drive Y of controller X. + +Where: /sys/bus/pci/devices//ccissX/cXdY/vendor +Date: March 2009 +Kernel Version: 2.6.30 +Contact: iss_storagedev@hp.com +Description: Displays the SCSI INQUIRY page 0 vendor for logical drive + Y of controller X. + +Where: /sys/bus/pci/devices//ccissX/cXdY/block:cciss!cXdY +Date: March 2009 +Kernel Version: 2.6.30 +Contact: iss_storagedev@hp.com +Description: A symbolic link to /sys/block/cciss!cXdY diff --git a/Documentation/ABI/testing/sysfs-class-mtd b/Documentation/ABI/testing/sysfs-class-mtd new file mode 100644 index 000000000000..4d55a1888981 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-class-mtd @@ -0,0 +1,125 @@ +What: /sys/class/mtd/ +Date: April 2009 +KernelVersion: 2.6.29 +Contact: linux-mtd@lists.infradead.org +Description: + The mtd/ class subdirectory belongs to the MTD subsystem + (MTD core). + +What: /sys/class/mtd/mtdX/ +Date: April 2009 +KernelVersion: 2.6.29 +Contact: linux-mtd@lists.infradead.org +Description: + The /sys/class/mtd/mtd{0,1,2,3,...} directories correspond + to each /dev/mtdX character device. These may represent + physical/simulated flash devices, partitions on a flash + device, or concatenated flash devices. They exist regardless + of whether CONFIG_MTD_CHAR is actually enabled. + +What: /sys/class/mtd/mtdXro/ +Date: April 2009 +KernelVersion: 2.6.29 +Contact: linux-mtd@lists.infradead.org +Description: + These directories provide the corresponding read-only device + nodes for /sys/class/mtd/mtdX/ . They are only created + (for the benefit of udev) if CONFIG_MTD_CHAR is enabled. + +What: /sys/class/mtd/mtdX/dev +Date: April 2009 +KernelVersion: 2.6.29 +Contact: linux-mtd@lists.infradead.org +Description: + Major and minor numbers of the character device corresponding + to this MTD device (in : format). This is the + read-write device so will be even. + +What: /sys/class/mtd/mtdXro/dev +Date: April 2009 +KernelVersion: 2.6.29 +Contact: linux-mtd@lists.infradead.org +Description: + Major and minor numbers of the character device corresponding + to the read-only variant of thie MTD device (in + : format). In this case will be odd. + +What: /sys/class/mtd/mtdX/erasesize +Date: April 2009 +KernelVersion: 2.6.29 +Contact: linux-mtd@lists.infradead.org +Description: + "Major" erase size for the device. If numeraseregions is + zero, this is the eraseblock size for the entire device. + Otherwise, the MEMGETREGIONCOUNT/MEMGETREGIONINFO ioctls + can be used to determine the actual eraseblock layout. + +What: /sys/class/mtd/mtdX/flags +Date: April 2009 +KernelVersion: 2.6.29 +Contact: linux-mtd@lists.infradead.org +Description: + A hexadecimal value representing the device flags, ORed + together: + + 0x0400: MTD_WRITEABLE - device is writable + 0x0800: MTD_BIT_WRITEABLE - single bits can be flipped + 0x1000: MTD_NO_ERASE - no erase necessary + 0x2000: MTD_POWERUP_LOCK - always locked after reset + +What: /sys/class/mtd/mtdX/name +Date: April 2009 +KernelVersion: 2.6.29 +Contact: linux-mtd@lists.infradead.org +Description: + A human-readable ASCII name for the device or partition. + This will match the name in /proc/mtd . + +What: /sys/class/mtd/mtdX/numeraseregions +Date: April 2009 +KernelVersion: 2.6.29 +Contact: linux-mtd@lists.infradead.org +Description: + For devices that have variable eraseblock sizes, this + provides the total number of erase regions. Otherwise, + it will read back as zero. + +What: /sys/class/mtd/mtdX/oobsize +Date: April 2009 +KernelVersion: 2.6.29 +Contact: linux-mtd@lists.infradead.org +Description: + Number of OOB bytes per page. + +What: /sys/class/mtd/mtdX/size +Date: April 2009 +KernelVersion: 2.6.29 +Contact: linux-mtd@lists.infradead.org +Description: + Total size of the device/partition, in bytes. + +What: /sys/class/mtd/mtdX/type +Date: April 2009 +KernelVersion: 2.6.29 +Contact: linux-mtd@lists.infradead.org +Description: + One of the following ASCII strings, representing the device + type: + + absent, ram, rom, nor, nand, dataflash, ubi, unknown + +What: /sys/class/mtd/mtdX/writesize +Date: April 2009 +KernelVersion: 2.6.29 +Contact: linux-mtd@lists.infradead.org +Description: + Minimal writable flash unit size. This will always be + a positive integer. + + In the case of NOR flash it is 1 (even though individual + bits can be cleared). + + In the case of NAND flash it is one NAND page (or a + half page, or a quarter page). + + In the case of ECC NOR, it is the ECC block size. diff --git a/Documentation/ABI/testing/sysfs-devices-cache_disable b/Documentation/ABI/testing/sysfs-devices-cache_disable new file mode 100644 index 000000000000..175bb4f70512 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-devices-cache_disable @@ -0,0 +1,18 @@ +What: /sys/devices/system/cpu/cpu*/cache/index*/cache_disable_X +Date: August 2008 +KernelVersion: 2.6.27 +Contact: mark.langsdorf@amd.com +Description: These files exist in every cpu's cache index directories. + There are currently 2 cache_disable_# files in each + directory. Reading from these files on a supported + processor will return that cache disable index value + for that processor and node. Writing to one of these + files will cause the specificed cache index to be disabled. + + Currently, only AMD Family 10h Processors support cache index + disable, and only for their L3 caches. See the BIOS and + Kernel Developer's Guide at + http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/31116-Public-GH-BKDG_3.20_2-4-09.pdf + for formatting information and other details on the + cache index disable. +Users: joachim.deguara@amd.com diff --git a/Documentation/ABI/testing/sysfs-fs-ext4 b/Documentation/ABI/testing/sysfs-fs-ext4 index 4e79074de282..5fb709997d96 100644 --- a/Documentation/ABI/testing/sysfs-fs-ext4 +++ b/Documentation/ABI/testing/sysfs-fs-ext4 @@ -79,3 +79,13 @@ Description: This file is read-only and shows the number of kilobytes of data that have been written to this filesystem since it was mounted. + +What: /sys/fs/ext4//inode_goal +Date: June 2008 +Contact: "Theodore Ts'o" +Description: + Tuning parameter which (if non-zero) controls the goal + inode used by the inode allocator in p0reference to + all other allocation hueristics. This is intended for + debugging use only, and should be 0 on production + systems. diff --git a/Documentation/ABI/testing/sysfs-pps b/Documentation/ABI/testing/sysfs-pps new file mode 100644 index 000000000000..25028c7bc37d --- /dev/null +++ b/Documentation/ABI/testing/sysfs-pps @@ -0,0 +1,73 @@ +What: /sys/class/pps/ +Date: February 2008 +Contact: Rodolfo Giometti +Description: + The /sys/class/pps/ directory will contain files and + directories that will provide a unified interface to + the PPS sources. + +What: /sys/class/pps/ppsX/ +Date: February 2008 +Contact: Rodolfo Giometti +Description: + The /sys/class/pps/ppsX/ directory is related to X-th + PPS source into the system. Each directory will + contain files to manage and control its PPS source. + +What: /sys/class/pps/ppsX/assert +Date: February 2008 +Contact: Rodolfo Giometti +Description: + The /sys/class/pps/ppsX/assert file reports the assert events + and the assert sequence number of the X-th source in the form: + + .# + + If the source has no assert events the content of this file + is empty. + +What: /sys/class/pps/ppsX/clear +Date: February 2008 +Contact: Rodolfo Giometti +Description: + The /sys/class/pps/ppsX/clear file reports the clear events + and the clear sequence number of the X-th source in the form: + + .# + + If the source has no clear events the content of this file + is empty. + +What: /sys/class/pps/ppsX/mode +Date: February 2008 +Contact: Rodolfo Giometti +Description: + The /sys/class/pps/ppsX/mode file reports the functioning + mode of the X-th source in hexadecimal encoding. + + Please, refer to linux/include/linux/pps.h for further + info. + +What: /sys/class/pps/ppsX/echo +Date: February 2008 +Contact: Rodolfo Giometti +Description: + The /sys/class/pps/ppsX/echo file reports if the X-th does + or does not support an "echo" function. + +What: /sys/class/pps/ppsX/name +Date: February 2008 +Contact: Rodolfo Giometti +Description: + The /sys/class/pps/ppsX/name file reports the name of the + X-th source. + +What: /sys/class/pps/ppsX/path +Date: February 2008 +Contact: Rodolfo Giometti +Description: + The /sys/class/pps/ppsX/path file reports the path name of + the device connected with the X-th source. + + If the source is not connected with any device the content + of this file is empty. diff --git a/Documentation/Changes b/Documentation/Changes index b95082be4d5e..6d0f1efc5bf6 100644 --- a/Documentation/Changes +++ b/Documentation/Changes @@ -29,7 +29,7 @@ hardware, for example, you probably needn't concern yourself with isdn4k-utils. o Gnu C 3.2 # gcc --version -o Gnu make 3.79.1 # make --version +o Gnu make 3.80 # make --version o binutils 2.12 # ld -v o util-linux 2.10o # fdformat --version o module-init-tools 0.9.10 # depmod -V @@ -48,6 +48,7 @@ o procps 3.2.0 # ps --version o oprofile 0.9 # oprofiled --version o udev 081 # udevinfo -V o grub 0.93 # grub --version +o mcelog 0.6 Kernel compilation ================== @@ -61,7 +62,7 @@ computer. Make ---- -You will need Gnu make 3.79.1 or later to build the kernel. +You will need Gnu make 3.80 or later to build the kernel. Binutils -------- @@ -71,6 +72,13 @@ assembling the 16-bit boot code, removing the need for as86 to compile your kernel. This change does, however, mean that you need a recent release of binutils. +Perl +---- + +You will need perl 5 and the following modules: Getopt::Long, Getopt::Std, +File::Basename, and File::Find to build the kernel. + + System utilities ================ @@ -276,6 +284,16 @@ before running exportfs or mountd. It is recommended that all NFS services be protected from the internet-at-large by a firewall where that is possible. +mcelog +------ + +In Linux 2.6.31+ the i386 kernel needs to run the mcelog utility +as a regular cronjob similar to the x86-64 kernel to process and log +machine check events when CONFIG_X86_NEW_MCE is enabled. Machine check +events are errors reported by the CPU. Processing them is strongly encouraged. +All x86-64 kernels since 2.6.4 require the mcelog utility to +process machine checks. + Getting updated software ======================== @@ -365,6 +383,10 @@ FUSE ---- o +mcelog +------ +o + Networking ********** diff --git a/Documentation/CodingStyle b/Documentation/CodingStyle index 72968cd5eaf3..8bb37237ebd2 100644 --- a/Documentation/CodingStyle +++ b/Documentation/CodingStyle @@ -698,8 +698,8 @@ very often is not. Abundant use of the inline keyword leads to a much bigger kernel, which in turn slows the system as a whole down, due to a bigger icache footprint for the CPU and simply because there is less memory available for the pagecache. Just think about it; a pagecache miss causes a -disk seek, which easily takes 5 miliseconds. There are a LOT of cpu cycles -that can go into these 5 miliseconds. +disk seek, which easily takes 5 milliseconds. There are a LOT of cpu cycles +that can go into these 5 milliseconds. A reasonable rule of thumb is to not put inline at functions that have more than 3 lines of code in them. An exception to this rule are the cases where diff --git a/Documentation/DMA-API.txt b/Documentation/DMA-API.txt index d9aa43d78bcc..5aceb88b3f8b 100644 --- a/Documentation/DMA-API.txt +++ b/Documentation/DMA-API.txt @@ -676,8 +676,8 @@ this directory the following files can currently be found: dma-api/all_errors This file contains a numeric value. If this value is not equal to zero the debugging code will print a warning for every error it finds - into the kernel log. Be carefull with this - option. It can easily flood your logs. + into the kernel log. Be careful with this + option, as it can easily flood your logs. dma-api/disabled This read-only file contains the character 'Y' if the debugging code is disabled. This can @@ -704,12 +704,24 @@ this directory the following files can currently be found: The current number of free dma_debug_entries in the allocator. + dma-api/driver-filter + You can write a name of a driver into this file + to limit the debug output to requests from that + particular driver. Write an empty string to + that file to disable the filter and see + all errors again. + If you have this code compiled into your kernel it will be enabled by default. If you want to boot without the bookkeeping anyway you can provide 'dma_debug=off' as a boot parameter. This will disable DMA-API debugging. Notice that you can not enable it again at runtime. You have to reboot to do so. +If you want to see debug messages only for a special device driver you can +specify the dma_debug_driver= parameter. This will enable the +driver filter at boot time. The debug code will only print errors for that +driver afterwards. This filter can be disabled or changed later using debugfs. + When the code disables itself at runtime this is most likely because it ran out of dma_debug_entries. These entries are preallocated at boot. The number of preallocated entries is defined per architecture. If it is too low for you diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile index b1eb661e6302..9632444f6c62 100644 --- a/Documentation/DocBook/Makefile +++ b/Documentation/DocBook/Makefile @@ -13,7 +13,8 @@ DOCBOOKS := z8530book.xml mcabook.xml device-drivers.xml \ gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml \ genericirq.xml s390-drivers.xml uio-howto.xml scsi.xml \ mac80211.xml debugobjects.xml sh.xml regulator.xml \ - alsa-driver-api.xml writing-an-alsa-driver.xml + alsa-driver-api.xml writing-an-alsa-driver.xml \ + tracepoint.xml ### # The build process is as follows (targets): diff --git a/Documentation/DocBook/debugobjects.tmpl b/Documentation/DocBook/debugobjects.tmpl index 7f5f218015fe..08ff908aa7a2 100644 --- a/Documentation/DocBook/debugobjects.tmpl +++ b/Documentation/DocBook/debugobjects.tmpl @@ -106,7 +106,7 @@ number of errors are printk'ed including a full stack trace. - The statistics are available via debugfs/debug_objects/stats. + The statistics are available via /sys/kernel/debug/debug_objects/stats. They provide information about the number of warnings and the number of successful fixups along with information about the usage of the internal tracking objects and the state of the diff --git a/Documentation/DocBook/mac80211.tmpl b/Documentation/DocBook/mac80211.tmpl index fbeaffc1dcc3..e36986663570 100644 --- a/Documentation/DocBook/mac80211.tmpl +++ b/Documentation/DocBook/mac80211.tmpl @@ -145,7 +145,6 @@ usage should require reading the full document. interface in STA mode at first! !Finclude/net/mac80211.h ieee80211_if_init_conf -!Finclude/net/mac80211.h ieee80211_if_conf diff --git a/Documentation/DocBook/tracepoint.tmpl b/Documentation/DocBook/tracepoint.tmpl new file mode 100644 index 000000000000..b0756d0fd579 --- /dev/null +++ b/Documentation/DocBook/tracepoint.tmpl @@ -0,0 +1,89 @@ + + + + + + The Linux Kernel Tracepoint API + + + + Jason + Baron + +
+ jbaron@redhat.com +
+
+
+
+ + + + This documentation 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 + + + + For more details see the file COPYING in the source + distribution of Linux. + + +
+ + + + Introduction + + Tracepoints are static probe points that are located in strategic points + throughout the kernel. 'Probes' register/unregister with tracepoints + via a callback mechanism. The 'probes' are strictly typed functions that + are passed a unique set of parameters defined by each tracepoint. + + + + From this simple callback mechanism, 'probes' can be used to profile, debug, + and understand kernel behavior. There are a number of tools that provide a + framework for using 'probes'. These tools include Systemtap, ftrace, and + LTTng. + + + + Tracepoints are defined in a number of header files via various macros. Thus, + the purpose of this document is to provide a clear accounting of the available + tracepoints. The intention is to understand not only what tracepoints are + available but also to understand where future tracepoints might be added. + + + + The API presented has functions of the form: + trace_tracepointname(function parameters). These are the + tracepoints callbacks that are found throughout the code. Registering and + unregistering probes with these callback sites is covered in the + Documentation/trace/* directory. + + + + + IRQ +!Iinclude/trace/events/irq.h + + +
diff --git a/Documentation/PCI/pcieaer-howto.txt b/Documentation/PCI/pcieaer-howto.txt index ddeb14beacc8..be21001ab144 100644 --- a/Documentation/PCI/pcieaer-howto.txt +++ b/Documentation/PCI/pcieaer-howto.txt @@ -61,6 +61,10 @@ be initiated although firmwares have no _OSC support. To enable the walkaround, pls. add aerdriver.forceload=y to kernel boot parameter line when booting kernel. Note that forceload=n by default. +nosourceid, another parameter of type bool, can be used when broken +hardware (mostly chipsets) has root ports that cannot obtain the reporting +source ID. nosourceid=n by default. + 2.3 AER error output When a PCI-E AER error is captured, an error message will be outputed to console. If it's a correctable error, it is outputed as a warning. @@ -246,3 +250,24 @@ with the PCI Express AER Root driver? A: It could call the helper functions to enable AER in devices and cleanup uncorrectable status register. Pls. refer to section 3.3. + +4. Software error injection + +Debugging PCIE AER error recovery code is quite difficult because it +is hard to trigger real hardware errors. Software based error +injection can be used to fake various kinds of PCIE errors. + +First you should enable PCIE AER software error injection in kernel +configuration, that is, following item should be in your .config. + +CONFIG_PCIEAER_INJECT=y or CONFIG_PCIEAER_INJECT=m + +After reboot with new kernel or insert the module, a device file named +/dev/aer_inject should be created. + +Then, you need a user space tool named aer-inject, which can be gotten +from: + http://www.kernel.org/pub/linux/utils/pci/aer-inject/ + +More information about aer-inject can be found in the document comes +with its source code. diff --git a/Documentation/RCU/rculist_nulls.txt b/Documentation/RCU/rculist_nulls.txt index 6389dec33459..93cb28d05dcd 100644 --- a/Documentation/RCU/rculist_nulls.txt +++ b/Documentation/RCU/rculist_nulls.txt @@ -118,7 +118,7 @@ to another chain) checking the final 'nulls' value if the lookup met the end of chain. If final 'nulls' value is not the slot number, then we must restart the lookup at the beginning. If the object was moved to the same chain, -then the reader doesnt care : It might eventually +then the reader doesn't care : It might eventually scan the list again without harm. diff --git a/Documentation/RCU/trace.txt b/Documentation/RCU/trace.txt index 068848240a8b..02cced183b2d 100644 --- a/Documentation/RCU/trace.txt +++ b/Documentation/RCU/trace.txt @@ -192,23 +192,24 @@ rcu/rcuhier (which displays the struct rcu_node hierarchy). The output of "cat rcu/rcudata" looks as follows: rcu: - 0 c=4011 g=4012 pq=1 pqc=4011 qp=0 rpfq=1 rp=3c2a dt=23301/73 dn=2 df=1882 of=0 ri=2126 ql=2 b=10 - 1 c=4011 g=4012 pq=1 pqc=4011 qp=0 rpfq=3 rp=39a6 dt=78073/1 dn=2 df=1402 of=0 ri=1875 ql=46 b=10 - 2 c=4010 g=4010 pq=1 pqc=4010 qp=0 rpfq=-5 rp=1d12 dt=16646/0 dn=2 df=3140 of=0 ri=2080 ql=0 b=10 - 3 c=4012 g=4013 pq=1 pqc=4012 qp=1 rpfq=3 rp=2b50 dt=21159/1 dn=2 df=2230 of=0 ri=1923 ql=72 b=10 - 4 c=4012 g=4013 pq=1 pqc=4012 qp=1 rpfq=3 rp=1644 dt=5783/1 dn=2 df=3348 of=0 ri=2805 ql=7 b=10 - 5 c=4012 g=4013 pq=0 pqc=4011 qp=1 rpfq=3 rp=1aac dt=5879/1 dn=2 df=3140 of=0 ri=2066 ql=10 b=10 - 6 c=4012 g=4013 pq=1 pqc=4012 qp=1 rpfq=3 rp=ed8 dt=5847/1 dn=2 df=3797 of=0 ri=1266 ql=10 b=10 - 7 c=4012 g=4013 pq=1 pqc=4012 qp=1 rpfq=3 rp=1fa2 dt=6199/1 dn=2 df=2795 of=0 ri=2162 ql=28 b=10 +rcu: + 0 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=10951/1 dn=0 df=1101 of=0 ri=36 ql=0 b=10 + 1 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=16117/1 dn=0 df=1015 of=0 ri=0 ql=0 b=10 + 2 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=1445/1 dn=0 df=1839 of=0 ri=0 ql=0 b=10 + 3 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=6681/1 dn=0 df=1545 of=0 ri=0 ql=0 b=10 + 4 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=1003/1 dn=0 df=1992 of=0 ri=0 ql=0 b=10 + 5 c=17829 g=17830 pq=1 pqc=17829 qp=1 dt=3887/1 dn=0 df=3331 of=0 ri=4 ql=2 b=10 + 6 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=859/1 dn=0 df=3224 of=0 ri=0 ql=0 b=10 + 7 c=17829 g=17830 pq=0 pqc=17829 qp=1 dt=3761/1 dn=0 df=1818 of=0 ri=0 ql=2 b=10 rcu_bh: - 0 c=-268 g=-268 pq=1 pqc=-268 qp=0 rpfq=-145 rp=21d6 dt=23301/73 dn=2 df=0 of=0 ri=0 ql=0 b=10 - 1 c=-268 g=-268 pq=1 pqc=-268 qp=1 rpfq=-170 rp=20ce dt=78073/1 dn=2 df=26 of=0 ri=5 ql=0 b=10 - 2 c=-268 g=-268 pq=1 pqc=-268 qp=1 rpfq=-83 rp=fbd dt=16646/0 dn=2 df=28 of=0 ri=4 ql=0 b=10 - 3 c=-268 g=-268 pq=1 pqc=-268 qp=0 rpfq=-105 rp=178c dt=21159/1 dn=2 df=28 of=0 ri=2 ql=0 b=10 - 4 c=-268 g=-268 pq=1 pqc=-268 qp=1 rpfq=-30 rp=b54 dt=5783/1 dn=2 df=32 of=0 ri=0 ql=0 b=10 - 5 c=-268 g=-268 pq=1 pqc=-268 qp=1 rpfq=-29 rp=df5 dt=5879/1 dn=2 df=30 of=0 ri=3 ql=0 b=10 - 6 c=-268 g=-268 pq=1 pqc=-268 qp=1 rpfq=-28 rp=788 dt=5847/1 dn=2 df=32 of=0 ri=0 ql=0 b=10 - 7 c=-268 g=-268 pq=1 pqc=-268 qp=1 rpfq=-53 rp=1098 dt=6199/1 dn=2 df=30 of=0 ri=3 ql=0 b=10 + 0 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=10951/1 dn=0 df=0 of=0 ri=0 ql=0 b=10 + 1 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=16117/1 dn=0 df=13 of=0 ri=0 ql=0 b=10 + 2 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=1445/1 dn=0 df=15 of=0 ri=0 ql=0 b=10 + 3 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=6681/1 dn=0 df=9 of=0 ri=0 ql=0 b=10 + 4 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=1003/1 dn=0 df=15 of=0 ri=0 ql=0 b=10 + 5 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=3887/1 dn=0 df=15 of=0 ri=0 ql=0 b=10 + 6 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=859/1 dn=0 df=15 of=0 ri=0 ql=0 b=10 + 7 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=3761/1 dn=0 df=15 of=0 ri=0 ql=0 b=10 The first section lists the rcu_data structures for rcu, the second for rcu_bh. Each section has one line per CPU, or eight for this 8-CPU system. @@ -253,12 +254,6 @@ o "pqc" indicates which grace period the last-observed quiescent o "qp" indicates that RCU still expects a quiescent state from this CPU. -o "rpfq" is the number of rcu_pending() calls on this CPU required - to induce this CPU to invoke force_quiescent_state(). - -o "rp" is low-order four hex digits of the count of how many times - rcu_pending() has been invoked on this CPU. - o "dt" is the current value of the dyntick counter that is incremented when entering or leaving dynticks idle state, either by the scheduler or by irq. The number after the "/" is the interrupt @@ -305,6 +300,9 @@ o "b" is the batch limit for this CPU. If more than this number of RCU callbacks is ready to invoke, then the remainder will be deferred. +There is also an rcu/rcudata.csv file with the same information in +comma-separated-variable spreadsheet format. + The output of "cat rcu/rcugp" looks as follows: @@ -411,3 +409,63 @@ o Each element of the form "1/1 0:127 ^0" represents one struct For example, the first entry at the lowest level shows "^0", indicating that it corresponds to bit zero in the first entry at the middle level. + + +The output of "cat rcu/rcu_pending" looks as follows: + +rcu: + 0 np=255892 qsp=53936 cbr=0 cng=14417 gpc=10033 gps=24320 nf=6445 nn=146741 + 1 np=261224 qsp=54638 cbr=0 cng=25723 gpc=16310 gps=2849 nf=5912 nn=155792 + 2 np=237496 qsp=49664 cbr=0 cng=2762 gpc=45478 gps=1762 nf=1201 nn=136629 + 3 np=236249 qsp=48766 cbr=0 cng=286 gpc=48049 gps=1218 nf=207 nn=137723 + 4 np=221310 qsp=46850 cbr=0 cng=26 gpc=43161 gps=4634 nf=3529 nn=123110 + 5 np=237332 qsp=48449 cbr=0 cng=54 gpc=47920 gps=3252 nf=201 nn=137456 + 6 np=219995 qsp=46718 cbr=0 cng=50 gpc=42098 gps=6093 nf=4202 nn=120834 + 7 np=249893 qsp=49390 cbr=0 cng=72 gpc=38400 gps=17102 nf=41 nn=144888 +rcu_bh: + 0 np=146741 qsp=1419 cbr=0 cng=6 gpc=0 gps=0 nf=2 nn=145314 + 1 np=155792 qsp=12597 cbr=0 cng=0 gpc=4 gps=8 nf=3 nn=143180 + 2 np=136629 qsp=18680 cbr=0 cng=0 gpc=7 gps=6 nf=0 nn=117936 + 3 np=137723 qsp=2843 cbr=0 cng=0 gpc=10 gps=7 nf=0 nn=134863 + 4 np=123110 qsp=12433 cbr=0 cng=0 gpc=4 gps=2 nf=0 nn=110671 + 5 np=137456 qsp=4210 cbr=0 cng=0 gpc=6 gps=5 nf=0 nn=133235 + 6 np=120834 qsp=9902 cbr=0 cng=0 gpc=6 gps=3 nf=2 nn=110921 + 7 np=144888 qsp=26336 cbr=0 cng=0 gpc=8 gps=2 nf=0 nn=118542 + +As always, this is once again split into "rcu" and "rcu_bh" portions. +The fields are as follows: + +o "np" is the number of times that __rcu_pending() has been invoked + for the corresponding flavor of RCU. + +o "qsp" is the number of times that the RCU was waiting for a + quiescent state from this CPU. + +o "cbr" is the number of times that this CPU had RCU callbacks + that had passed through a grace period, and were thus ready + to be invoked. + +o "cng" is the number of times that this CPU needed another + grace period while RCU was idle. + +o "gpc" is the number of times that an old grace period had + completed, but this CPU was not yet aware of it. + +o "gps" is the number of times that a new grace period had started, + but this CPU was not yet aware of it. + +o "nf" is the number of times that this CPU suspected that the + current grace period had run for too long, and thus needed to + be forced. + + Please note that "forcing" consists of sending resched IPIs + to holdout CPUs. If that CPU really still is in an old RCU + read-side critical section, then we really do have to wait for it. + The assumption behing "forcing" is that the CPU is not still in + an old RCU read-side critical section, but has not yet responded + for some other reason. + +o "nn" is the number of times that this CPU needed nothing. Alert + readers will note that the rcu "nn" number for a given CPU very + closely matches the rcu_bh "np" number for that same CPU. This + is due to short-circuit evaluation in rcu_pending(). diff --git a/Documentation/SM501.txt b/Documentation/SM501.txt index 6fc656035925..561826f82093 100644 --- a/Documentation/SM501.txt +++ b/Documentation/SM501.txt @@ -5,7 +5,7 @@ Copyright 2006, 2007 Simtec Electronics The Silicon Motion SM501 multimedia companion chip is a multifunction device which may provide numerous interfaces including USB host controller USB gadget, -Asyncronous Serial ports, Audio functions and a dual display video interface. +asynchronous serial ports, audio functions, and a dual display video interface. The device may be connected by PCI or local bus with varying functions enabled. Core diff --git a/Documentation/Smack.txt b/Documentation/Smack.txt index 629c92e99783..34614b4c708e 100644 --- a/Documentation/Smack.txt +++ b/Documentation/Smack.txt @@ -184,8 +184,9 @@ length. Single character labels using special characters, that being anything other than a letter or digit, are reserved for use by the Smack development team. Smack labels are unstructured, case sensitive, and the only operation ever performed on them is comparison for equality. Smack labels cannot -contain unprintable characters or the "/" (slash) character. Smack labels -cannot begin with a '-', which is reserved for special options. +contain unprintable characters, the "/" (slash), the "\" (backslash), the "'" +(quote) and '"' (double-quote) characters. +Smack labels cannot begin with a '-', which is reserved for special options. There are some predefined labels: @@ -523,3 +524,18 @@ Smack supports some mount options: These mount options apply to all file system types. +Smack auditing + +If you want Smack auditing of security events, you need to set CONFIG_AUDIT +in your kernel configuration. +By default, all denied events will be audited. You can change this behavior by +writing a single character to the /smack/logging file : +0 : no logging +1 : log denied (default) +2 : log accepted +3 : log denied & accepted + +Events are logged as 'key=value' pairs, for each event you at least will get +the subjet, the object, the rights requested, the action, the kernel function +that triggered the event, plus other pairs depending on the type of event +audited. diff --git a/Documentation/SubmitChecklist b/Documentation/SubmitChecklist index ac5e0b2f1097..78a9168ff377 100644 --- a/Documentation/SubmitChecklist +++ b/Documentation/SubmitChecklist @@ -54,7 +54,7 @@ kernel patches. CONFIG_PREEMPT. 14: If the patch affects IO/Disk, etc: has been tested with and without - CONFIG_LBD. + CONFIG_LBDAF. 15: All codepaths have been exercised with all lockdep features enabled. diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches index f309d3c6221c..5c555a8b39e5 100644 --- a/Documentation/SubmittingPatches +++ b/Documentation/SubmittingPatches @@ -91,6 +91,10 @@ Be as specific as possible. The WORST descriptions possible include things like "update driver X", "bug fix for driver X", or "this patch includes updates for subsystem X. Please apply." +The maintainer will thank you if you write your patch description in a +form which can be easily pulled into Linux's source code management +system, git, as a "commit log". See #15, below. + If your description starts to get long, that's a sign that you probably need to split up your patch. See #3, next. @@ -183,8 +187,9 @@ Even if the maintainer did not respond in step #4, make sure to ALWAYS copy the maintainer when you change their code. For small patches you may want to CC the Trivial Patch Monkey -trivial@kernel.org managed by Jesper Juhl; which collects "trivial" -patches. Trivial patches must qualify for one of the following rules: +trivial@kernel.org which collects "trivial" patches. Have a look +into the MAINTAINERS file for its current manager. +Trivial patches must qualify for one of the following rules: Spelling fixes in documentation Spelling fixes which could break grep(1) Warning fixes (cluttering with useless warnings is bad) @@ -196,7 +201,6 @@ patches. Trivial patches must qualify for one of the following rules: since people copy, as long as it's trivial) Any fix by the author/maintainer of the file (ie. patch monkey in re-transmission mode) -URL: @@ -405,7 +409,14 @@ person it names. This tag documents that potentially interested parties have been included in the discussion -14) Using Tested-by: and Reviewed-by: +14) Using Reported-by:, Tested-by: and Reviewed-by: + +If this patch fixes a problem reported by somebody else, consider adding a +Reported-by: tag to credit the reporter for their contribution. Please +note that this tag should not be added without the reporter's permission, +especially if the problem was not reported in a public forum. That said, +if we diligently credit our bug reporters, they will, hopefully, be +inspired to help us again in the future. A Tested-by: tag indicates that the patch has been successfully tested (in some environment) by the person named. This tag informs maintainers that @@ -444,7 +455,7 @@ offer a Reviewed-by tag for a patch. This tag serves to give credit to reviewers and to inform maintainers of the degree of review which has been done on the patch. Reviewed-by: tags, when supplied by reviewers known to understand the subject area and to perform thorough reviews, will normally -increase the liklihood of your patch getting into the kernel. +increase the likelihood of your patch getting into the kernel. 15) The canonical patch format @@ -485,12 +496,33 @@ phrase" should not be a filename. Do not use the same "summary phrase" for every patch in a whole patch series (where a "patch series" is an ordered sequence of multiple, related patches). -Bear in mind that the "summary phrase" of your email becomes -a globally-unique identifier for that patch. It propagates -all the way into the git changelog. The "summary phrase" may -later be used in developer discussions which refer to the patch. -People will want to google for the "summary phrase" to read -discussion regarding that patch. +Bear in mind that the "summary phrase" of your email becomes a +globally-unique identifier for that patch. It propagates all the way +into the git changelog. The "summary phrase" may later be used in +developer discussions which refer to the patch. People will want to +google for the "summary phrase" to read discussion regarding that +patch. It will also be the only thing that people may quickly see +when, two or three months later, they are going through perhaps +thousands of patches using tools such as "gitk" or "git log +--oneline". + +For these reasons, the "summary" must be no more than 70-75 +characters, and it must describe both what the patch changes, as well +as why the patch might be necessary. It is challenging to be both +succinct and descriptive, but that is what a well-written summary +should do. + +The "summary phrase" may be prefixed by tags enclosed in square +brackets: "Subject: [PATCH tag] ". The tags are not +considered part of the summary phrase, but describe how the patch +should be treated. Common tags might include a version descriptor if +the multiple versions of the patch have been sent out in response to +comments (i.e., "v1, v2, v3"), or "RFC" to indicate a request for +comments. If there are four patches in a patch series the individual +patches may be numbered like this: 1/4, 2/4, 3/4, 4/4. This assures +that developers understand the order in which the patches should be +applied and that they have reviewed or applied all of the patches in +the patch series. A couple of example Subjects: @@ -510,19 +542,31 @@ the patch author in the changelog. The explanation body will be committed to the permanent source changelog, so should make sense to a competent reader who has long since forgotten the immediate details of the discussion that might -have led to this patch. +have led to this patch. Including symptoms of the failure which the +patch addresses (kernel log messages, oops messages, etc.) is +especially useful for people who might be searching the commit logs +looking for the applicable patch. If a patch fixes a compile failure, +it may not be necessary to include _all_ of the compile failures; just +enough that it is likely that someone searching for the patch can find +it. As in the "summary phrase", it is important to be both succinct as +well as descriptive. The "---" marker line serves the essential purpose of marking for patch handling tools where the changelog message ends. One good use for the additional comments after the "---" marker is for -a diffstat, to show what files have changed, and the number of inserted -and deleted lines per file. A diffstat is especially useful on bigger -patches. Other comments relevant only to the moment or the maintainer, -not suitable for the permanent changelog, should also go here. -Use diffstat options "-p 1 -w 70" so that filenames are listed from the -top of the kernel source tree and don't use too much horizontal space -(easily fit in 80 columns, maybe with some indentation). +a diffstat, to show what files have changed, and the number of +inserted and deleted lines per file. A diffstat is especially useful +on bigger patches. Other comments relevant only to the moment or the +maintainer, not suitable for the permanent changelog, should also go +here. A good example of such comments might be "patch changelogs" +which describe what has changed between the v1 and v2 version of the +patch. + +If you are going to include a diffstat after the "---" marker, please +use diffstat options "-p 1 -w 70" so that filenames are listed from +the top of the kernel source tree and don't use too much horizontal +space (easily fit in 80 columns, maybe with some indentation). See more details on the proper patch format in the following references. diff --git a/Documentation/accounting/getdelays.c b/Documentation/accounting/getdelays.c index 7ea231172c85..aa73e72fd793 100644 --- a/Documentation/accounting/getdelays.c +++ b/Documentation/accounting/getdelays.c @@ -246,7 +246,8 @@ void print_ioacct(struct taskstats *t) int main(int argc, char *argv[]) { - int c, rc, rep_len, aggr_len, len2, cmd_type; + int c, rc, rep_len, aggr_len, len2; + int cmd_type = TASKSTATS_CMD_ATTR_UNSPEC; __u16 id; __u32 mypid; diff --git a/Documentation/arm/Samsung-S3C24XX/GPIO.txt b/Documentation/arm/Samsung-S3C24XX/GPIO.txt index ea7ccfc4b274..948c8718d967 100644 --- a/Documentation/arm/Samsung-S3C24XX/GPIO.txt +++ b/Documentation/arm/Samsung-S3C24XX/GPIO.txt @@ -51,7 +51,7 @@ PIN Numbers ----------- Each pin has an unique number associated with it in regs-gpio.h, - eg S3C2410_GPA0 or S3C2410_GPF1. These defines are used to tell + eg S3C2410_GPA(0) or S3C2410_GPF(1). These defines are used to tell the GPIO functions which pin is to be used. @@ -65,11 +65,11 @@ Configuring a pin Eg: - s3c2410_gpio_cfgpin(S3C2410_GPA0, S3C2410_GPA0_ADDR0); - s3c2410_gpio_cfgpin(S3C2410_GPE8, S3C2410_GPE8_SDDAT1); + s3c2410_gpio_cfgpin(S3C2410_GPA(0), S3C2410_GPA0_ADDR0); + s3c2410_gpio_cfgpin(S3C2410_GPE(8), S3C2410_GPE8_SDDAT1); - which would turn GPA0 into the lowest Address line A0, and set - GPE8 to be connected to the SDIO/MMC controller's SDDAT1 line. + which would turn GPA(0) into the lowest Address line A0, and set + GPE(8) to be connected to the SDIO/MMC controller's SDDAT1 line. Reading the current configuration diff --git a/Documentation/atomic_ops.txt b/Documentation/atomic_ops.txt index 4ef245010457..396bec3b74ed 100644 --- a/Documentation/atomic_ops.txt +++ b/Documentation/atomic_ops.txt @@ -229,10 +229,10 @@ kernel. It is the use of atomic counters to implement reference counting, and it works such that once the counter falls to zero it can be guaranteed that no other entity can be accessing the object: -static void obj_list_add(struct obj *obj) +static void obj_list_add(struct obj *obj, struct list_head *head) { obj->active = 1; - list_add(&obj->list); + list_add(&obj->list, head); } static void obj_list_del(struct obj *obj) diff --git a/Documentation/block/biodoc.txt b/Documentation/block/biodoc.txt index 6fab97ea7e6b..8d2158a1c6aa 100644 --- a/Documentation/block/biodoc.txt +++ b/Documentation/block/biodoc.txt @@ -186,7 +186,7 @@ a virtual address mapping (unlike the earlier scheme of virtual address do not have a corresponding kernel virtual address space mapping) and low-memory pages. -Note: Please refer to Documentation/PCI/PCI-DMA-mapping.txt for a discussion +Note: Please refer to Documentation/DMA-mapping.txt for a discussion on PCI high mem DMA aspects and mapping of scatter gather lists, and support for 64 bit PCI. diff --git a/Documentation/block/deadline-iosched.txt b/Documentation/block/deadline-iosched.txt index 72576769e0f4..2d82c80322cb 100644 --- a/Documentation/block/deadline-iosched.txt +++ b/Documentation/block/deadline-iosched.txt @@ -58,7 +58,7 @@ same criteria as reads. front_merges (bool) ------------ -Sometimes it happens that a request enters the io scheduler that is contigious +Sometimes it happens that a request enters the io scheduler that is contiguous with a request that is already on the queue. Either it fits in the back of that request, or it fits at the front. That is called either a back merge candidate or a front merge candidate. Due to the way files are typically laid out, diff --git a/Documentation/braille-console.txt b/Documentation/braille-console.txt index 000b0fbdc105..d0d042c2fd5e 100644 --- a/Documentation/braille-console.txt +++ b/Documentation/braille-console.txt @@ -27,7 +27,7 @@ parameter. For simplicity, only one braille console can be enabled, other uses of console=brl,... will be discarded. Also note that it does not interfere with -the console selection mecanism described in serial-console.txt +the console selection mechanism described in serial-console.txt For now, only the VisioBraille device is supported. diff --git a/Documentation/cdrom/packet-writing.txt b/Documentation/cdrom/packet-writing.txt index cf1f8126991c..1c407778c8b2 100644 --- a/Documentation/cdrom/packet-writing.txt +++ b/Documentation/cdrom/packet-writing.txt @@ -117,7 +117,7 @@ Using the pktcdvd debugfs interface To read pktcdvd device infos in human readable form, do: - # cat /debug/pktcdvd/pktcdvd[0-7]/info + # cat /sys/kernel/debug/pktcdvd/pktcdvd[0-7]/info For a description of the debugfs interface look into the file: diff --git a/Documentation/cgroups/memory.txt b/Documentation/cgroups/memory.txt index 1a608877b14e..23d1262c0775 100644 --- a/Documentation/cgroups/memory.txt +++ b/Documentation/cgroups/memory.txt @@ -152,14 +152,19 @@ When swap is accounted, following files are added. usage of mem+swap is limited by memsw.limit_in_bytes. -Note: why 'mem+swap' rather than swap. +* why 'mem+swap' rather than swap. The global LRU(kswapd) can swap out arbitrary pages. Swap-out means to move account from memory to swap...there is no change in usage of -mem+swap. +mem+swap. In other words, when we want to limit the usage of swap without +affecting global LRU, mem+swap limit is better than just limiting swap from +OS point of view. -In other words, when we want to limit the usage of swap without affecting -global LRU, mem+swap limit is better than just limiting swap from OS point -of view. +* What happens when a cgroup hits memory.memsw.limit_in_bytes +When a cgroup his memory.memsw.limit_in_bytes, it's useless to do swap-out +in this cgroup. Then, swap-out will not be done by cgroup routine and file +caches are dropped. But as mentioned above, global LRU can do swapout memory +from it for sanity of the system's memory management state. You can't forbid +it by cgroup. 2.5 Reclaim @@ -204,6 +209,7 @@ We can alter the memory limit: NOTE: We can use a suffix (k, K, m, M, g or G) to indicate values in kilo, mega or gigabytes. +NOTE: We can write "-1" to reset the *.limit_in_bytes(unlimited). # cat /cgroups/0/memory.limit_in_bytes 4194304 diff --git a/Documentation/connector/cn_test.c b/Documentation/connector/cn_test.c index 6977c178729a..f688eba87704 100644 --- a/Documentation/connector/cn_test.c +++ b/Documentation/connector/cn_test.c @@ -41,6 +41,12 @@ void cn_test_callback(void *data) msg->seq, msg->ack, msg->len, (char *)msg->data); } +/* + * Do not remove this function even if no one is using it as + * this is an example of how to get notifications about new + * connector user registration + */ +#if 0 static int cn_test_want_notify(void) { struct cn_ctl_msg *ctl; @@ -117,6 +123,7 @@ nlmsg_failure: kfree_skb(skb); return -EINVAL; } +#endif static u32 cn_test_timer_counter; static void cn_test_timer_func(unsigned long __data) diff --git a/Documentation/cpu-freq/cpu-drivers.txt b/Documentation/cpu-freq/cpu-drivers.txt index 43c743903dd7..75a58d14d3cf 100644 --- a/Documentation/cpu-freq/cpu-drivers.txt +++ b/Documentation/cpu-freq/cpu-drivers.txt @@ -155,7 +155,7 @@ actual frequency must be determined using the following rules: - if relation==CPUFREQ_REL_H, try to select a new_freq lower than or equal target_freq. ("H for highest, but no higher than") -Here again the frequency table helper might assist you - see section 3 +Here again the frequency table helper might assist you - see section 2 for details. diff --git a/Documentation/cpu-freq/governors.txt b/Documentation/cpu-freq/governors.txt index ce73f3eb5ddb..aed082f49d09 100644 --- a/Documentation/cpu-freq/governors.txt +++ b/Documentation/cpu-freq/governors.txt @@ -119,10 +119,6 @@ want the kernel to look at the CPU usage and to make decisions on what to do about the frequency. Typically this is set to values of around '10000' or more. It's default value is (cmp. with users-guide.txt): transition_latency * 1000 -The lowest value you can set is: -transition_latency * 100 or it may get restricted to a value where it -makes not sense for the kernel anymore to poll that often which depends -on your HZ config variable (HZ=1000: max=20000us, HZ=250: max=5000). Be aware that transition latency is in ns and sampling_rate is in us, so you get the same sysfs value by default. Sampling rate should always get adjusted considering the transition latency @@ -131,14 +127,20 @@ in the bash (as said, 1000 is default), do: echo `$(($(cat cpuinfo_transition_latency) * 750 / 1000)) \ >ondemand/sampling_rate -show_sampling_rate_(min|max): THIS INTERFACE IS DEPRECATED, DON'T USE IT. -You can use wider ranges now and the general -cpuinfo_transition_latency variable (cmp. with user-guide.txt) can be -used to obtain exactly the same info: -show_sampling_rate_min = transtition_latency * 500 / 1000 -show_sampling_rate_max = transtition_latency * 500000 / 1000 -(divided by 1000 is to illustrate that sampling rate is in us and -transition latency is exported ns). +show_sampling_rate_min: +The sampling rate is limited by the HW transition latency: +transition_latency * 100 +Or by kernel restrictions: +If CONFIG_NO_HZ is set, the limit is 10ms fixed. +If CONFIG_NO_HZ is not set or no_hz=off boot parameter is used, the +limits depend on the CONFIG_HZ option: +HZ=1000: min=20000us (20ms) +HZ=250: min=80000us (80ms) +HZ=100: min=200000us (200ms) +The highest value of kernel and HW latency restrictions is shown and +used as the minimum sampling rate. + +show_sampling_rate_max: THIS INTERFACE IS DEPRECATED, DON'T USE IT. up_threshold: defines what the average CPU usage between the samplings of 'sampling_rate' needs to be for the kernel to make a decision on diff --git a/Documentation/cpu-freq/user-guide.txt b/Documentation/cpu-freq/user-guide.txt index 75f41193f3e1..5d5f5fadd1c2 100644 --- a/Documentation/cpu-freq/user-guide.txt +++ b/Documentation/cpu-freq/user-guide.txt @@ -31,7 +31,6 @@ Contents: 3. How to change the CPU cpufreq policy and/or speed 3.1 Preferred interface: sysfs -3.2 Deprecated interfaces diff --git a/Documentation/dell_rbu.txt b/Documentation/dell_rbu.txt index c11b931f8f98..15174985ad08 100644 --- a/Documentation/dell_rbu.txt +++ b/Documentation/dell_rbu.txt @@ -76,9 +76,9 @@ Do the steps below to download the BIOS image. The /sys/class/firmware/dell_rbu/ entries will remain till the following is done. -echo -1 > /sys/class/firmware/dell_rbu/loading. +echo -1 > /sys/class/firmware/dell_rbu/loading Until this step is completed the driver cannot be unloaded. -Also echoing either mono ,packet or init in to image_type will free up the +Also echoing either mono, packet or init in to image_type will free up the memory allocated by the driver. If a user by accident executes steps 1 and 3 above without executing step 2; diff --git a/Documentation/development-process/5.Posting b/Documentation/development-process/5.Posting index dd48132a74dd..f622c1e9f0f9 100644 --- a/Documentation/development-process/5.Posting +++ b/Documentation/development-process/5.Posting @@ -119,7 +119,7 @@ which takes quite a bit of time and thought after the "real work" has been done. When done properly, though, it is time well spent. -5.4: PATCH FORMATTING +5.4: PATCH FORMATTING AND CHANGELOGS So now you have a perfect series of patches for posting, but the work is not done quite yet. Each patch needs to be formatted into a message which @@ -146,8 +146,33 @@ that end, each patch will be composed of the following: - One or more tag lines, with, at a minimum, one Signed-off-by: line from the author of the patch. Tags will be described in more detail below. -The above three items should, normally, be the text used when committing -the change to a revision control system. They are followed by: +The items above, together, form the changelog for the patch. Writing good +changelogs is a crucial but often-neglected art; it's worth spending +another moment discussing this issue. When writing a changelog, you should +bear in mind that a number of different people will be reading your words. +These include subsystem maintainers and reviewers who need to decide +whether the patch should be included, distributors and other maintainers +trying to decide whether a patch should be backported to other kernels, bug +hunters wondering whether the patch is responsible for a problem they are +chasing, users who want to know how the kernel has changed, and more. A +good changelog conveys the needed information to all of these people in the +most direct and concise way possible. + +To that end, the summary line should describe the effects of and motivation +for the change as well as possible given the one-line constraint. The +detailed description can then amplify on those topics and provide any +needed additional information. If the patch fixes a bug, cite the commit +which introduced the bug if possible. If a problem is associated with +specific log or compiler output, include that output to help others +searching for a solution to the same problem. If the change is meant to +support other changes coming in later patch, say so. If internal APIs are +changed, detail those changes and how other developers should respond. In +general, the more you can put yourself into the shoes of everybody who will +be reading your changelog, the better that changelog (and the kernel as a +whole) will be. + +Needless to say, the changelog should be the text used when committing the +change to a revision control system. It will be followed by: - The patch itself, in the unified ("-u") patch format. Using the "-p" option to diff will associate function names with changes, making the diff --git a/Documentation/device-mapper/dm-log.txt b/Documentation/device-mapper/dm-log.txt new file mode 100644 index 000000000000..994dd75475a6 --- /dev/null +++ b/Documentation/device-mapper/dm-log.txt @@ -0,0 +1,54 @@ +Device-Mapper Logging +===================== +The device-mapper logging code is used by some of the device-mapper +RAID targets to track regions of the disk that are not consistent. +A region (or portion of the address space) of the disk may be +inconsistent because a RAID stripe is currently being operated on or +a machine died while the region was being altered. In the case of +mirrors, a region would be considered dirty/inconsistent while you +are writing to it because the writes need to be replicated for all +the legs of the mirror and may not reach the legs at the same time. +Once all writes are complete, the region is considered clean again. + +There is a generic logging interface that the device-mapper RAID +implementations use to perform logging operations (see +dm_dirty_log_type in include/linux/dm-dirty-log.h). Various different +logging implementations are available and provide different +capabilities. The list includes: + +Type Files +==== ===== +disk drivers/md/dm-log.c +core drivers/md/dm-log.c +userspace drivers/md/dm-log-userspace* include/linux/dm-log-userspace.h + +The "disk" log type +------------------- +This log implementation commits the log state to disk. This way, the +logging state survives reboots/crashes. + +The "core" log type +------------------- +This log implementation keeps the log state in memory. The log state +will not survive a reboot or crash, but there may be a small boost in +performance. This method can also be used if no storage device is +available for storing log state. + +The "userspace" log type +------------------------ +This log type simply provides a way to export the log API to userspace, +so log implementations can be done there. This is done by forwarding most +logging requests to userspace, where a daemon receives and processes the +request. + +The structure used for communication between kernel and userspace are +located in include/linux/dm-log-userspace.h. Due to the frequency, +diversity, and 2-way communication nature of the exchanges between +kernel and userspace, 'connector' is used as the interface for +communication. + +There are currently two userspace log implementations that leverage this +framework - "clustered_disk" and "clustered_core". These implementations +provide a cluster-coherent log for shared-storage. Device-mapper mirroring +can be used in a shared-storage environment when the cluster log implementations +are employed. diff --git a/Documentation/device-mapper/dm-queue-length.txt b/Documentation/device-mapper/dm-queue-length.txt new file mode 100644 index 000000000000..f4db2562175c --- /dev/null +++ b/Documentation/device-mapper/dm-queue-length.txt @@ -0,0 +1,39 @@ +dm-queue-length +=============== + +dm-queue-length is a path selector module for device-mapper targets, +which selects a path with the least number of in-flight I/Os. +The path selector name is 'queue-length'. + +Table parameters for each path: [] + : The number of I/Os to dispatch using the selected + path before switching to the next path. + If not given, internal default is used. To check + the default value, see the activated table. + +Status for each path: + : 'A' if the path is active, 'F' if the path is failed. + : The number of path failures. + : The number of in-flight I/Os on the path. + + +Algorithm +========= + +dm-queue-length increments/decrements 'in-flight' when an I/O is +dispatched/completed respectively. +dm-queue-length selects a path with the minimum 'in-flight'. + + +Examples +======== +In case that 2 paths (sda and sdb) are used with repeat_count == 128. + +# echo "0 10 multipath 0 0 1 1 queue-length 0 2 1 8:0 128 8:16 128" \ + dmsetup create test +# +# dmsetup table +test: 0 10 multipath 0 0 1 1 queue-length 0 2 1 8:0 128 8:16 128 +# +# dmsetup status +test: 0 10 multipath 2 0 0 0 1 1 E 0 2 1 8:0 A 0 0 8:16 A 0 0 diff --git a/Documentation/device-mapper/dm-service-time.txt b/Documentation/device-mapper/dm-service-time.txt new file mode 100644 index 000000000000..7d00668e97bb --- /dev/null +++ b/Documentation/device-mapper/dm-service-time.txt @@ -0,0 +1,91 @@ +dm-service-time +=============== + +dm-service-time is a path selector module for device-mapper targets, +which selects a path with the shortest estimated service time for +the incoming I/O. + +The service time for each path is estimated by dividing the total size +of in-flight I/Os on a path with the performance value of the path. +The performance value is a relative throughput value among all paths +in a path-group, and it can be specified as a table argument. + +The path selector name is 'service-time'. + +Table parameters for each path: [ []] + : The number of I/Os to dispatch using the selected + path before switching to the next path. + If not given, internal default is used. To check + the default value, see the activated table. + : The relative throughput value of the path + among all paths in the path-group. + The valid range is 0-100. + If not given, minimum value '1' is used. + If '0' is given, the path isn't selected while + other paths having a positive value are available. + +Status for each path: \ + + : 'A' if the path is active, 'F' if the path is failed. + : The number of path failures. + : The size of in-flight I/Os on the path. + : The relative throughput value of the path + among all paths in the path-group. + + +Algorithm +========= + +dm-service-time adds the I/O size to 'in-flight-size' when the I/O is +dispatched and substracts when completed. +Basically, dm-service-time selects a path having minimum service time +which is calculated by: + + ('in-flight-size' + 'size-of-incoming-io') / 'relative_throughput' + +However, some optimizations below are used to reduce the calculation +as much as possible. + + 1. If the paths have the same 'relative_throughput', skip + the division and just compare the 'in-flight-size'. + + 2. If the paths have the same 'in-flight-size', skip the division + and just compare the 'relative_throughput'. + + 3. If some paths have non-zero 'relative_throughput' and others + have zero 'relative_throughput', ignore those paths with zero + 'relative_throughput'. + +If such optimizations can't be applied, calculate service time, and +compare service time. +If calculated service time is equal, the path having maximum +'relative_throughput' may be better. So compare 'relative_throughput' +then. + + +Examples +======== +In case that 2 paths (sda and sdb) are used with repeat_count == 128 +and sda has an average throughput 1GB/s and sdb has 4GB/s, +'relative_throughput' value may be '1' for sda and '4' for sdb. + +# echo "0 10 multipath 0 0 1 1 service-time 0 2 2 8:0 128 1 8:16 128 4" \ + dmsetup create test +# +# dmsetup table +test: 0 10 multipath 0 0 1 1 service-time 0 2 2 8:0 128 1 8:16 128 4 +# +# dmsetup status +test: 0 10 multipath 2 0 0 0 1 1 E 0 2 2 8:0 A 0 0 1 8:16 A 0 0 4 + + +Or '2' for sda and '8' for sdb would be also true. + +# echo "0 10 multipath 0 0 1 1 service-time 0 2 2 8:0 128 2 8:16 128 8" \ + dmsetup create test +# +# dmsetup table +test: 0 10 multipath 0 0 1 1 service-time 0 2 2 8:0 128 2 8:16 128 8 +# +# dmsetup status +test: 0 10 multipath 2 0 0 0 1 1 E 0 2 2 8:0 A 0 0 2 8:16 A 0 0 8 diff --git a/Documentation/driver-model/device.txt b/Documentation/driver-model/device.txt index a7cbfff40d07..a124f3126b0d 100644 --- a/Documentation/driver-model/device.txt +++ b/Documentation/driver-model/device.txt @@ -162,3 +162,35 @@ device_remove_file(dev,&dev_attr_power); The file name will be 'power' with a mode of 0644 (-rw-r--r--). +Word of warning: While the kernel allows device_create_file() and +device_remove_file() to be called on a device at any time, userspace has +strict expectations on when attributes get created. When a new device is +registered in the kernel, a uevent is generated to notify userspace (like +udev) that a new device is available. If attributes are added after the +device is registered, then userspace won't get notified and userspace will +not know about the new attributes. + +This is important for device driver that need to publish additional +attributes for a device at driver probe time. If the device driver simply +calls device_create_file() on the device structure passed to it, then +userspace will never be notified of the new attributes. Instead, it should +probably use class_create() and class->dev_attrs to set up a list of +desired attributes in the modules_init function, and then in the .probe() +hook, and then use device_create() to create a new device as a child +of the probed device. The new device will generate a new uevent and +properly advertise the new attributes to userspace. + +For example, if a driver wanted to add the following attributes: +struct device_attribute mydriver_attribs[] = { + __ATTR(port_count, 0444, port_count_show), + __ATTR(serial_number, 0444, serial_number_show), + NULL +}; + +Then in the module init function is would do: + mydriver_class = class_create(THIS_MODULE, "my_attrs"); + mydriver_class.dev_attr = mydriver_attribs; + +And assuming 'dev' is the struct device passed into the probe hook, the driver +probe function would do something like: + create_device(&mydriver_class, dev, chrdev, &private_data, "my_name"); diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt index 387b8a720f4a..d79aead9418b 100644 --- a/Documentation/driver-model/devres.txt +++ b/Documentation/driver-model/devres.txt @@ -188,7 +188,7 @@ For example, you can do something like the following. void my_midlayer_destroy_something() { - devres_release_group(dev, my_midlayer_create_soemthing); + devres_release_group(dev, my_midlayer_create_something); } diff --git a/Documentation/dvb/get_dvb_firmware b/Documentation/dvb/get_dvb_firmware index 2f21ecd4c205..a52adfc9a57f 100644 --- a/Documentation/dvb/get_dvb_firmware +++ b/Documentation/dvb/get_dvb_firmware @@ -112,7 +112,7 @@ sub tda10045 { sub tda10046 { my $sourcefile = "TT_PCI_2.19h_28_11_2006.zip"; - my $url = "http://technotrend-online.com/download/software/219/$sourcefile"; + my $url = "http://www.tt-download.com/download/updates/219/$sourcefile"; my $hash = "6a7e1e2f2644b162ff0502367553c72d"; my $outfile = "dvb-fe-tda10046.fw"; my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1); @@ -129,8 +129,8 @@ sub tda10046 { } sub tda10046lifeview { - my $sourcefile = "Drv_2.11.02.zip"; - my $url = "http://www.lifeview.com.tw/drivers/pci_card/FlyDVB-T/$sourcefile"; + my $sourcefile = "7%5Cdrv_2.11.02.zip"; + my $url = "http://www.lifeview.hk/dbimages/document/$sourcefile"; my $hash = "1ea24dee4eea8fe971686981f34fd2e0"; my $outfile = "dvb-fe-tda10046.fw"; my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1); @@ -317,7 +317,7 @@ sub nxt2002 { sub nxt2004 { my $sourcefile = "AVerTVHD_MCE_A180_Drv_v1.2.2.16.zip"; - my $url = "http://www.aver.com/support/Drivers/$sourcefile"; + my $url = "http://www.avermedia-usa.com/support/Drivers/$sourcefile"; my $hash = "111cb885b1e009188346d72acfed024c"; my $outfile = "dvb-fe-nxt2004.fw"; my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1); diff --git a/Documentation/edac.txt b/Documentation/edac.txt index 8eda3fb66416..06f8f46692dc 100644 --- a/Documentation/edac.txt +++ b/Documentation/edac.txt @@ -23,8 +23,8 @@ first time, it was renamed to 'EDAC'. The bluesmoke project at sourceforge.net is now utilized as a 'staging area' for EDAC development, before it is sent upstream to kernel.org -At the bluesmoke/EDAC project site, is a series of quilt patches against -recent kernels, stored in a SVN respository. For easier downloading, there +At the bluesmoke/EDAC project site is a series of quilt patches against +recent kernels, stored in a SVN repository. For easier downloading, there is also a tarball snapshot available. ============================================================================ @@ -73,9 +73,9 @@ the vendor should tie the parity status bits to 0 if they do not intend to generate parity. Some vendors do not do this, and thus the parity bit can "float" giving false positives. -In the kernel there is a pci device attribute located in sysfs that is +In the kernel there is a PCI device attribute located in sysfs that is checked by the EDAC PCI scanning code. If that attribute is set, -PCI parity/error scannining is skipped for that device. The attribute +PCI parity/error scanning is skipped for that device. The attribute is: broken_parity_status diff --git a/Documentation/fault-injection/fault-injection.txt b/Documentation/fault-injection/fault-injection.txt index 4bc374a14345..079305640790 100644 --- a/Documentation/fault-injection/fault-injection.txt +++ b/Documentation/fault-injection/fault-injection.txt @@ -29,16 +29,16 @@ o debugfs entries fault-inject-debugfs kernel module provides some debugfs entries for runtime configuration of fault-injection capabilities. -- /debug/fail*/probability: +- /sys/kernel/debug/fail*/probability: likelihood of failure injection, in percent. Format: Note that one-failure-per-hundred is a very high error rate for some testcases. Consider setting probability=100 and configure - /debug/fail*/interval for such testcases. + /sys/kernel/debug/fail*/interval for such testcases. -- /debug/fail*/interval: +- /sys/kernel/debug/fail*/interval: specifies the interval between failures, for calls to should_fail() that pass all the other tests. @@ -46,18 +46,18 @@ configuration of fault-injection capabilities. Note that if you enable this, by setting interval>1, you will probably want to set probability=100. -- /debug/fail*/times: +- /sys/kernel/debug/fail*/times: specifies how many times failures may happen at most. A value of -1 means "no limit". -- /debug/fail*/space: +- /sys/kernel/debug/fail*/space: specifies an initial resource "budget", decremented by "size" on each call to should_fail(,size). Failure injection is suppressed until "space" reaches zero. -- /debug/fail*/verbose +- /sys/kernel/debug/fail*/verbose Format: { 0 | 1 | 2 } specifies the verbosity of the messages when failure is @@ -65,17 +65,17 @@ configuration of fault-injection capabilities. log line per failure; '2' will print a call trace too -- useful to debug the problems revealed by fault injection. -- /debug/fail*/task-filter: +- /sys/kernel/debug/fail*/task-filter: Format: { 'Y' | 'N' } A value of 'N' disables filtering by process (default). Any positive value limits failures to only processes indicated by /proc//make-it-fail==1. -- /debug/fail*/require-start: -- /debug/fail*/require-end: -- /debug/fail*/reject-start: -- /debug/fail*/reject-end: +- /sys/kernel/debug/fail*/require-start: +- /sys/kernel/debug/fail*/require-end: +- /sys/kernel/debug/fail*/reject-start: +- /sys/kernel/debug/fail*/reject-end: specifies the range of virtual addresses tested during stacktrace walking. Failure is injected only if some caller @@ -84,26 +84,26 @@ configuration of fault-injection capabilities. Default required range is [0,ULONG_MAX) (whole of virtual address space). Default rejected range is [0,0). -- /debug/fail*/stacktrace-depth: +- /sys/kernel/debug/fail*/stacktrace-depth: specifies the maximum stacktrace depth walked during search for a caller within [require-start,require-end) OR [reject-start,reject-end). -- /debug/fail_page_alloc/ignore-gfp-highmem: +- /sys/kernel/debug/fail_page_alloc/ignore-gfp-highmem: Format: { 'Y' | 'N' } default is 'N', setting it to 'Y' won't inject failures into highmem/user allocations. -- /debug/failslab/ignore-gfp-wait: -- /debug/fail_page_alloc/ignore-gfp-wait: +- /sys/kernel/debug/failslab/ignore-gfp-wait: +- /sys/kernel/debug/fail_page_alloc/ignore-gfp-wait: Format: { 'Y' | 'N' } default is 'N', setting it to 'Y' will inject failures only into non-sleep allocations (GFP_ATOMIC allocations). -- /debug/fail_page_alloc/min-order: +- /sys/kernel/debug/fail_page_alloc/min-order: specifies the minimum page allocation order to be injected failures. @@ -166,13 +166,13 @@ o Inject slab allocation failures into module init/exit code #!/bin/bash FAILTYPE=failslab -echo Y > /debug/$FAILTYPE/task-filter -echo 10 > /debug/$FAILTYPE/probability -echo 100 > /debug/$FAILTYPE/interval -echo -1 > /debug/$FAILTYPE/times -echo 0 > /debug/$FAILTYPE/space -echo 2 > /debug/$FAILTYPE/verbose -echo 1 > /debug/$FAILTYPE/ignore-gfp-wait +echo Y > /sys/kernel/debug/$FAILTYPE/task-filter +echo 10 > /sys/kernel/debug/$FAILTYPE/probability +echo 100 > /sys/kernel/debug/$FAILTYPE/interval +echo -1 > /sys/kernel/debug/$FAILTYPE/times +echo 0 > /sys/kernel/debug/$FAILTYPE/space +echo 2 > /sys/kernel/debug/$FAILTYPE/verbose +echo 1 > /sys/kernel/debug/$FAILTYPE/ignore-gfp-wait faulty_system() { @@ -217,20 +217,20 @@ then exit 1 fi -cat /sys/module/$module/sections/.text > /debug/$FAILTYPE/require-start -cat /sys/module/$module/sections/.data > /debug/$FAILTYPE/require-end +cat /sys/module/$module/sections/.text > /sys/kernel/debug/$FAILTYPE/require-start +cat /sys/module/$module/sections/.data > /sys/kernel/debug/$FAILTYPE/require-end -echo N > /debug/$FAILTYPE/task-filter -echo 10 > /debug/$FAILTYPE/probability -echo 100 > /debug/$FAILTYPE/interval -echo -1 > /debug/$FAILTYPE/times -echo 0 > /debug/$FAILTYPE/space -echo 2 > /debug/$FAILTYPE/verbose -echo 1 > /debug/$FAILTYPE/ignore-gfp-wait -echo 1 > /debug/$FAILTYPE/ignore-gfp-highmem -echo 10 > /debug/$FAILTYPE/stacktrace-depth +echo N > /sys/kernel/debug/$FAILTYPE/task-filter +echo 10 > /sys/kernel/debug/$FAILTYPE/probability +echo 100 > /sys/kernel/debug/$FAILTYPE/interval +echo -1 > /sys/kernel/debug/$FAILTYPE/times +echo 0 > /sys/kernel/debug/$FAILTYPE/space +echo 2 > /sys/kernel/debug/$FAILTYPE/verbose +echo 1 > /sys/kernel/debug/$FAILTYPE/ignore-gfp-wait +echo 1 > /sys/kernel/debug/$FAILTYPE/ignore-gfp-highmem +echo 10 > /sys/kernel/debug/$FAILTYPE/stacktrace-depth -trap "echo 0 > /debug/$FAILTYPE/probability" SIGINT SIGTERM EXIT +trap "echo 0 > /sys/kernel/debug/$FAILTYPE/probability" SIGINT SIGTERM EXIT echo "Injecting errors into the module $module... (interrupt to stop)" sleep 1000000 diff --git a/Documentation/fb/sh7760fb.txt b/Documentation/fb/sh7760fb.txt index c87bfe5c630a..b994c3b10549 100644 --- a/Documentation/fb/sh7760fb.txt +++ b/Documentation/fb/sh7760fb.txt @@ -1,7 +1,7 @@ SH7760/SH7763 integrated LCDC Framebuffer driver ================================================ -0. Overwiew +0. Overview ----------- The SH7760/SH7763 have an integrated LCD Display controller (LCDC) which supports (in theory) resolutions ranging from 1x1 to 1024x1024, diff --git a/Documentation/fb/vesafb.txt b/Documentation/fb/vesafb.txt index ee277dd204b0..950d5a658cb3 100644 --- a/Documentation/fb/vesafb.txt +++ b/Documentation/fb/vesafb.txt @@ -95,7 +95,7 @@ There is no way to change the vesafb video mode and/or timings after booting linux. If you are not happy with the 60 Hz refresh rate, you have these options: - * configure and load the DOS-Tools for your the graphics board (if + * configure and load the DOS-Tools for the graphics board (if available) and boot linux with loadlin. * use a native driver (matroxfb/atyfb) instead if vesafb. If none is available, write a new one! diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index de491a3e2313..f8cd450be9aa 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -6,6 +6,20 @@ be removed from this file. --------------------------- +What: IRQF_SAMPLE_RANDOM +Check: IRQF_SAMPLE_RANDOM +When: July 2009 + +Why: Many of IRQF_SAMPLE_RANDOM users are technically bogus as entropy + sources in the kernel's current entropy model. To resolve this, every + input point to the kernel's entropy pool needs to better document the + type of entropy source it actually is. This will be replaced with + additional add_*_randomness functions in drivers/char/random.c + +Who: Robin Getz & Matt Mackall + +--------------------------- + What: The ieee80211_regdom module parameter When: March 2010 / desktop catchup @@ -354,16 +368,6 @@ Who: Krzysztof Piotr Oledzki --------------------------- -What: i2c_attach_client(), i2c_detach_client(), i2c_driver->detach_client(), - i2c_adapter->client_register(), i2c_adapter->client_unregister -When: 2.6.30 -Check: i2c_attach_client i2c_detach_client -Why: Deprecated by the new (standard) device driver binding model. Use - i2c_driver->probe() and ->remove() instead. -Who: Jean Delvare - ---------------------------- - What: fscher and fscpos drivers When: June 2009 Why: Deprecated by the new fschmd driver. @@ -437,3 +441,20 @@ Why: Superseded by tdfxfb. I2C/DDC support used to live in a separate driver but this caused driver conflicts. Who: Jean Delvare Krzysztof Helt + +--------------------------- + +What: CONFIG_RFKILL_INPUT +When: 2.6.33 +Why: Should be implemented in userspace, policy daemon. +Who: Johannes Berg + +---------------------------- + +What: CONFIG_X86_OLD_MCE +When: 2.6.32 +Why: Remove the old legacy 32bit machine check code. This has been + superseded by the newer machine check code from the 64bit port, + but the old version has been kept around for easier testing. Note this + doesn't impact the old P5 and WinChip machine check handlers. +Who: Andi Kleen diff --git a/Documentation/filesystems/00-INDEX b/Documentation/filesystems/00-INDEX index 8dd6db76171d..f15621ee5599 100644 --- a/Documentation/filesystems/00-INDEX +++ b/Documentation/filesystems/00-INDEX @@ -66,6 +66,10 @@ mandatory-locking.txt - info on the Linux implementation of Sys V mandatory file locking. ncpfs.txt - info on Novell Netware(tm) filesystem using NCP protocol. +nfs41-server.txt + - info on the Linux server implementation of NFSv4 minor version 1. +nfs-rdma.txt + - how to install and setup the Linux NFS/RDMA client and server software. nfsroot.txt - short guide on setting up a diskless box with NFS root filesystem. nilfs2.txt diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking index 3120f8dd2c31..18b9d0ca0630 100644 --- a/Documentation/filesystems/Locking +++ b/Documentation/filesystems/Locking @@ -109,27 +109,28 @@ prototypes: locking rules: All may block. - BKL s_lock s_umount -alloc_inode: no no no -destroy_inode: no -dirty_inode: no (must not sleep) -write_inode: no -drop_inode: no !!!inode_lock!!! -delete_inode: no -put_super: yes yes no -write_super: no yes read -sync_fs: no no read -freeze_fs: ? -unfreeze_fs: ? -statfs: no no no -remount_fs: yes yes maybe (see below) -clear_inode: no -umount_begin: yes no no -show_options: no (vfsmount->sem) -quota_read: no no no (see below) -quota_write: no no no (see below) + None have BKL + s_umount +alloc_inode: +destroy_inode: +dirty_inode: (must not sleep) +write_inode: +drop_inode: !!!inode_lock!!! +delete_inode: +put_super: write +write_super: read +sync_fs: read +freeze_fs: read +unfreeze_fs: read +statfs: no +remount_fs: maybe (see below) +clear_inode: +umount_begin: no +show_options: no (namespace_sem) +quota_read: no (see below) +quota_write: no (see below) -->remount_fs() will have the s_umount lock if it's already mounted. +->remount_fs() will have the s_umount exclusive lock if it's already mounted. When called from get_sb_single, it does NOT have the s_umount lock. ->quota_read() and ->quota_write() functions are both guaranteed to be the only ones operating on the quota file by the quota code (via @@ -187,7 +188,7 @@ readpages: no write_begin: no locks the page yes write_end: no yes, unlocks yes perform_write: no n/a yes -bmap: yes +bmap: no invalidatepage: no yes releasepage: no yes direct_IO: no diff --git a/Documentation/filesystems/autofs4-mount-control.txt b/Documentation/filesystems/autofs4-mount-control.txt index c6341745df37..8f78ded4b648 100644 --- a/Documentation/filesystems/autofs4-mount-control.txt +++ b/Documentation/filesystems/autofs4-mount-control.txt @@ -369,7 +369,7 @@ The call requires an initialized struct autofs_dev_ioctl. There are two possible variations. Both use the path field set to the path of the mount point to check and the size field adjusted appropriately. One uses the ioctlfd field to identify a specific mount point to check while the other -variation uses the path and optionaly arg1 set to an autofs mount type. +variation uses the path and optionally arg1 set to an autofs mount type. The call returns 1 if this is a mount point and sets arg1 to the device number of the mount and field arg2 to the relevant super block magic number (described below) or 0 if it isn't a mountpoint. In both cases diff --git a/Documentation/filesystems/caching/netfs-api.txt b/Documentation/filesystems/caching/netfs-api.txt index 4db125b3a5c6..2666b1ed5e9e 100644 --- a/Documentation/filesystems/caching/netfs-api.txt +++ b/Documentation/filesystems/caching/netfs-api.txt @@ -184,7 +184,7 @@ This has the following fields: have index children. If this function is not supplied or if it returns NULL then the first - cache in the parent's list will be chosed, or failing that, the first + cache in the parent's list will be chosen, or failing that, the first cache in the master list. (4) A function to retrieve an object's key from the netfs [mandatory]. diff --git a/Documentation/filesystems/debugfs.txt b/Documentation/filesystems/debugfs.txt new file mode 100644 index 000000000000..ed52af60c2d8 --- /dev/null +++ b/Documentation/filesystems/debugfs.txt @@ -0,0 +1,158 @@ +Copyright 2009 Jonathan Corbet + +Debugfs exists as a simple way for kernel developers to make information +available to user space. Unlike /proc, which is only meant for information +about a process, or sysfs, which has strict one-value-per-file rules, +debugfs has no rules at all. Developers can put any information they want +there. The debugfs filesystem is also intended to not serve as a stable +ABI to user space; in theory, there are no stability constraints placed on +files exported there. The real world is not always so simple, though [1]; +even debugfs interfaces are best designed with the idea that they will need +to be maintained forever. + +Debugfs is typically mounted with a command like: + + mount -t debugfs none /sys/kernel/debug + +(Or an equivalent /etc/fstab line). + +Note that the debugfs API is exported GPL-only to modules. + +Code using debugfs should include . Then, the first order +of business will be to create at least one directory to hold a set of +debugfs files: + + struct dentry *debugfs_create_dir(const char *name, struct dentry *parent); + +This call, if successful, will make a directory called name underneath the +indicated parent directory. If parent is NULL, the directory will be +created in the debugfs root. On success, the return value is a struct +dentry pointer which can be used to create files in the directory (and to +clean it up at the end). A NULL return value indicates that something went +wrong. If ERR_PTR(-ENODEV) is returned, that is an indication that the +kernel has been built without debugfs support and none of the functions +described below will work. + +The most general way to create a file within a debugfs directory is with: + + struct dentry *debugfs_create_file(const char *name, mode_t mode, + struct dentry *parent, void *data, + const struct file_operations *fops); + +Here, name is the name of the file to create, mode describes the access +permissions the file should have, parent indicates the directory which +should hold the file, data will be stored in the i_private field of the +resulting inode structure, and fops is a set of file operations which +implement the file's behavior. At a minimum, the read() and/or write() +operations should be provided; others can be included as needed. Again, +the return value will be a dentry pointer to the created file, NULL for +error, or ERR_PTR(-ENODEV) if debugfs support is missing. + +In a number of cases, the creation of a set of file operations is not +actually necessary; the debugfs code provides a number of helper functions +for simple situations. Files containing a single integer value can be +created with any of: + + struct dentry *debugfs_create_u8(const char *name, mode_t mode, + struct dentry *parent, u8 *value); + struct dentry *debugfs_create_u16(const char *name, mode_t mode, + struct dentry *parent, u16 *value); + struct dentry *debugfs_create_u32(const char *name, mode_t mode, + struct dentry *parent, u32 *value); + struct dentry *debugfs_create_u64(const char *name, mode_t mode, + struct dentry *parent, u64 *value); + +These files support both reading and writing the given value; if a specific +file should not be written to, simply set the mode bits accordingly. The +values in these files are in decimal; if hexadecimal is more appropriate, +the following functions can be used instead: + + struct dentry *debugfs_create_x8(const char *name, mode_t mode, + struct dentry *parent, u8 *value); + struct dentry *debugfs_create_x16(const char *name, mode_t mode, + struct dentry *parent, u16 *value); + struct dentry *debugfs_create_x32(const char *name, mode_t mode, + struct dentry *parent, u32 *value); + +Note that there is no debugfs_create_x64(). + +These functions are useful as long as the developer knows the size of the +value to be exported. Some types can have different widths on different +architectures, though, complicating the situation somewhat. There is a +function meant to help out in one special case: + + struct dentry *debugfs_create_size_t(const char *name, mode_t mode, + struct dentry *parent, + size_t *value); + +As might be expected, this function will create a debugfs file to represent +a variable of type size_t. + +Boolean values can be placed in debugfs with: + + struct dentry *debugfs_create_bool(const char *name, mode_t mode, + struct dentry *parent, u32 *value); + +A read on the resulting file will yield either Y (for non-zero values) or +N, followed by a newline. If written to, it will accept either upper- or +lower-case values, or 1 or 0. Any other input will be silently ignored. + +Finally, a block of arbitrary binary data can be exported with: + + struct debugfs_blob_wrapper { + void *data; + unsigned long size; + }; + + struct dentry *debugfs_create_blob(const char *name, mode_t mode, + struct dentry *parent, + struct debugfs_blob_wrapper *blob); + +A read of this file will return the data pointed to by the +debugfs_blob_wrapper structure. Some drivers use "blobs" as a simple way +to return several lines of (static) formatted text output. This function +can be used to export binary information, but there does not appear to be +any code which does so in the mainline. Note that all files created with +debugfs_create_blob() are read-only. + +There are a couple of other directory-oriented helper functions: + + struct dentry *debugfs_rename(struct dentry *old_dir, + struct dentry *old_dentry, + struct dentry *new_dir, + const char *new_name); + + struct dentry *debugfs_create_symlink(const char *name, + struct dentry *parent, + const char *target); + +A call to debugfs_rename() will give a new name to an existing debugfs +file, possibly in a different directory. The new_name must not exist prior +to the call; the return value is old_dentry with updated information. +Symbolic links can be created with debugfs_create_symlink(). + +There is one important thing that all debugfs users must take into account: +there is no automatic cleanup of any directories created in debugfs. If a +module is unloaded without explicitly removing debugfs entries, the result +will be a lot of stale pointers and no end of highly antisocial behavior. +So all debugfs users - at least those which can be built as modules - must +be prepared to remove all files and directories they create there. A file +can be removed with: + + void debugfs_remove(struct dentry *dentry); + +The dentry value can be NULL, in which case nothing will be removed. + +Once upon a time, debugfs users were required to remember the dentry +pointer for every debugfs file they created so that all files could be +cleaned up. We live in more civilized times now, though, and debugfs users +can call: + + void debugfs_remove_recursive(struct dentry *dentry); + +If this function is passed a pointer for the dentry corresponding to the +top-level directory, the entire hierarchy below that directory will be +removed. + +Notes: + [1] http://lwn.net/Articles/309298/ diff --git a/Documentation/filesystems/ext2.txt b/Documentation/filesystems/ext2.txt index e055acb6b2d4..67639f905f10 100644 --- a/Documentation/filesystems/ext2.txt +++ b/Documentation/filesystems/ext2.txt @@ -322,7 +322,7 @@ an upper limit on the block size imposed by the page size of the kernel, so 8kB blocks are only allowed on Alpha systems (and other architectures which support larger pages). -There is an upper limit of 32768 subdirectories in a single directory. +There is an upper limit of 32000 subdirectories in a single directory. There is a "soft" upper limit of about 10-15k files in a single directory with the current linear linked-list directory implementation. This limit diff --git a/Documentation/filesystems/ext4.txt b/Documentation/filesystems/ext4.txt index 97882df04865..7be02ac5fa36 100644 --- a/Documentation/filesystems/ext4.txt +++ b/Documentation/filesystems/ext4.txt @@ -235,6 +235,10 @@ minixdf Make 'df' act like Minix. debug Extra debugging information is sent to syslog. +abort Simulate the effects of calling ext4_abort() for + debugging purposes. This is normally used while + remounting a filesystem which is already mounted. + errors=remount-ro Remount the filesystem read-only on an error. errors=continue Keep going on a filesystem error. errors=panic Panic and halt the machine if an error occurs. @@ -294,7 +298,7 @@ max_batch_time=usec Maximum amount of time ext4 should wait for amount of time (on average) that it takes to finish committing a transaction. Call this time the "commit time". If the time that the - transactoin has been running is less than the + transaction has been running is less than the commit time, ext4 will try sleeping for the commit time to see if other operations will join the transaction. The commit time is capped by @@ -328,7 +332,7 @@ noauto_da_alloc replacing existing files via patterns such as journal commit, in the default data=ordered mode, the data blocks of the new file are forced to disk before the rename() operation is - commited. This provides roughly the same level + committed. This provides roughly the same level of guarantees as ext3, and avoids the "zero-length" problem that can happen when a system crashes before the delayed allocation @@ -358,7 +362,7 @@ written to the journal first, and then to its final location. In the event of a crash, the journal can be replayed, bringing both data and metadata into a consistent state. This mode is the slowest except when data needs to be read from and written to disk at the same time where it -outperforms all others modes. Curently ext4 does not have delayed +outperforms all others modes. Currently ext4 does not have delayed allocation support if this data journalling mode is selected. References diff --git a/Documentation/filesystems/fiemap.txt b/Documentation/filesystems/fiemap.txt index 1e3defcfe50b..606233cd4618 100644 --- a/Documentation/filesystems/fiemap.txt +++ b/Documentation/filesystems/fiemap.txt @@ -204,7 +204,7 @@ fiemap_check_flags() helper: int fiemap_check_flags(struct fiemap_extent_info *fieinfo, u32 fs_flags); -The struct fieinfo should be passed in as recieved from ioctl_fiemap(). The +The struct fieinfo should be passed in as received from ioctl_fiemap(). The set of fiemap flags which the fs understands should be passed via fs_flags. If fiemap_check_flags finds invalid user flags, it will place the bad values in fieinfo->fi_flags and return -EBADR. If the file system gets -EBADR, from diff --git a/Documentation/filesystems/gfs2-glocks.txt b/Documentation/filesystems/gfs2-glocks.txt index 4dae9a3840bf..0494f78d87e4 100644 --- a/Documentation/filesystems/gfs2-glocks.txt +++ b/Documentation/filesystems/gfs2-glocks.txt @@ -60,7 +60,7 @@ go_lock | Called for the first local holder of a lock go_unlock | Called on the final local unlock of a lock go_dump | Called to print content of object for debugfs file, or on | error to dump glock to the log. -go_type; | The type of the glock, LM_TYPE_..... +go_type | The type of the glock, LM_TYPE_..... go_min_hold_time | The minimum hold time The minimum hold time for each lock is the time after a remote lock diff --git a/Documentation/filesystems/gfs2.txt b/Documentation/filesystems/gfs2.txt index 593004b6bbab..5e3ab8f3beff 100644 --- a/Documentation/filesystems/gfs2.txt +++ b/Documentation/filesystems/gfs2.txt @@ -11,18 +11,15 @@ their I/O so file system consistency is maintained. One of the nifty features of GFS is perfect consistency -- changes made to the file system on one machine show up immediately on all other machines in the cluster. -GFS uses interchangable inter-node locking mechanisms. Different lock -modules can plug into GFS and each file system selects the appropriate -lock module at mount time. Lock modules include: +GFS uses interchangable inter-node locking mechanisms, the currently +supported mechanisms are: lock_nolock -- allows gfs to be used as a local file system lock_dlm -- uses a distributed lock manager (dlm) for inter-node locking The dlm is found at linux/fs/dlm/ -In addition to interfacing with an external locking manager, a gfs lock -module is responsible for interacting with external cluster management -systems. Lock_dlm depends on user space cluster management systems found +Lock_dlm depends on user space cluster management systems found at the URL above. To use gfs as a local file system, no external clustering systems are @@ -31,13 +28,19 @@ needed, simply: $ mkfs -t gfs2 -p lock_nolock -j 1 /dev/block_device $ mount -t gfs2 /dev/block_device /dir -GFS2 is not on-disk compatible with previous versions of GFS. +If you are using Fedora, you need to install the gfs2-utils package +and, for lock_dlm, you will also need to install the cman package +and write a cluster.conf as per the documentation. + +GFS2 is not on-disk compatible with previous versions of GFS, but it +is pretty close. The following man pages can be found at the URL above: - gfs2_fsck to repair a filesystem + fsck.gfs2 to repair a filesystem gfs2_grow to expand a filesystem online gfs2_jadd to add journals to a filesystem online gfs2_tool to manipulate, examine and tune a filesystem gfs2_quota to examine and change quota values in a filesystem + gfs2_convert to convert a gfs filesystem to gfs2 in-place mount.gfs2 to help mount(8) mount a filesystem mkfs.gfs2 to make a filesystem diff --git a/Documentation/filesystems/isofs.txt b/Documentation/filesystems/isofs.txt index 6973b980ca2a..3c367c3b3608 100644 --- a/Documentation/filesystems/isofs.txt +++ b/Documentation/filesystems/isofs.txt @@ -23,8 +23,13 @@ Mount options unique to the isofs filesystem. map=off Do not map non-Rock Ridge filenames to lower case map=normal Map non-Rock Ridge filenames to lower case map=acorn As map=normal but also apply Acorn extensions if present - mode=xxx Sets the permissions on files to xxx - dmode=xxx Sets the permissions on directories to xxx + mode=xxx Sets the permissions on files to xxx unless Rock Ridge + extensions set the permissions otherwise + dmode=xxx Sets the permissions on directories to xxx unless Rock Ridge + extensions set the permissions otherwise + overriderockperm Set permissions on files and directories according to + 'mode' and 'dmode' even though Rock Ridge extensions are + present. nojoliet Ignore Joliet extensions if they are present. norock Ignore Rock Ridge extensions if they are present. hide Completely strip hidden files from the file system. diff --git a/Documentation/filesystems/nfs-rdma.txt b/Documentation/filesystems/nfs-rdma.txt index 85eaeaddd27c..e386f7e4bcee 100644 --- a/Documentation/filesystems/nfs-rdma.txt +++ b/Documentation/filesystems/nfs-rdma.txt @@ -100,7 +100,7 @@ Installation $ 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. + by the system mount command. 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 diff --git a/Documentation/filesystems/nilfs2.txt b/Documentation/filesystems/nilfs2.txt index 55c4300abfcb..01539f410676 100644 --- a/Documentation/filesystems/nilfs2.txt +++ b/Documentation/filesystems/nilfs2.txt @@ -39,9 +39,8 @@ Features which NILFS2 does not support yet: - extended attributes - POSIX ACLs - quotas - - writable snapshots - - remote backup (CDP) - - data integrity + - fsck + - resize - defragmentation Mount options diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt index ce84cfc9eae0..fad18f9456e4 100644 --- a/Documentation/filesystems/proc.txt +++ b/Documentation/filesystems/proc.txt @@ -5,11 +5,12 @@ Bodo Bauer 2.4.x update Jorge Nerin November 14 2000 -move /proc/sys Shen Feng April 1 2009 +move /proc/sys Shen Feng April 1 2009 ------------------------------------------------------------------------------ Version 1.3 Kernel version 2.2.12 Kernel version 2.4.0-test11-pre4 ------------------------------------------------------------------------------ +fixes/update part 1.1 Stefani Seibold June 9 2009 Table of Contents ----------------- @@ -116,7 +117,7 @@ The link self points to the process reading the file system. Each process subdirectory has the entries listed in Table 1-1. -Table 1-1: Process specific entries in /proc +Table 1-1: Process specific entries in /proc .............................................................................. File Content clear_refs Clears page referenced bits shown in smaps output @@ -134,46 +135,103 @@ Table 1-1: Process specific entries in /proc status Process status in human readable form wchan If CONFIG_KALLSYMS is set, a pre-decoded wchan stack Report full stack trace, enable via CONFIG_STACKTRACE - smaps Extension based on maps, the rss size for each mapped file + smaps a extension based on maps, showing the memory consumption of + each mapping .............................................................................. For example, to get the status information of a process, all you have to do is read the file /proc/PID/status: - >cat /proc/self/status - Name: cat - State: R (running) - Pid: 5452 - PPid: 743 + >cat /proc/self/status + Name: cat + State: R (running) + Tgid: 5452 + Pid: 5452 + PPid: 743 TracerPid: 0 (2.4) - Uid: 501 501 501 501 - Gid: 100 100 100 100 - Groups: 100 14 16 - VmSize: 1112 kB - VmLck: 0 kB - VmRSS: 348 kB - VmData: 24 kB - VmStk: 12 kB - VmExe: 8 kB - VmLib: 1044 kB - SigPnd: 0000000000000000 - SigBlk: 0000000000000000 - SigIgn: 0000000000000000 - SigCgt: 0000000000000000 - CapInh: 00000000fffffeff - CapPrm: 0000000000000000 - CapEff: 0000000000000000 - + Uid: 501 501 501 501 + Gid: 100 100 100 100 + FDSize: 256 + Groups: 100 14 16 + VmPeak: 5004 kB + VmSize: 5004 kB + VmLck: 0 kB + VmHWM: 476 kB + VmRSS: 476 kB + VmData: 156 kB + VmStk: 88 kB + VmExe: 68 kB + VmLib: 1412 kB + VmPTE: 20 kb + Threads: 1 + SigQ: 0/28578 + SigPnd: 0000000000000000 + ShdPnd: 0000000000000000 + SigBlk: 0000000000000000 + SigIgn: 0000000000000000 + SigCgt: 0000000000000000 + CapInh: 00000000fffffeff + CapPrm: 0000000000000000 + CapEff: 0000000000000000 + CapBnd: ffffffffffffffff + voluntary_ctxt_switches: 0 + nonvoluntary_ctxt_switches: 1 This shows you nearly the same information you would get if you viewed it with the ps command. In fact, ps uses the proc file system to obtain its -information. The statm file contains more detailed information about the -process memory usage. Its seven fields are explained in Table 1-2. The stat -file contains details information about the process itself. Its fields are -explained in Table 1-3. +information. But you get a more detailed view of the process by reading the +file /proc/PID/status. It fields are described in table 1-2. +The statm file contains more detailed information about the process +memory usage. Its seven fields are explained in Table 1-3. The stat file +contains details information about the process itself. Its fields are +explained in Table 1-4. -Table 1-2: Contents of the statm files (as of 2.6.8-rc3) +Table 1-2: Contents of the statm files (as of 2.6.30-rc7) +.............................................................................. + Field Content + Name filename of the executable + State state (R is running, S is sleeping, D is sleeping + in an uninterruptible wait, Z is zombie, + T is traced or stopped) + Tgid thread group ID + Pid process id + PPid process id of the parent process + TracerPid PID of process tracing this process (0 if not) + Uid Real, effective, saved set, and file system UIDs + Gid Real, effective, saved set, and file system GIDs + FDSize number of file descriptor slots currently allocated + Groups supplementary group list + VmPeak peak virtual memory size + VmSize total program size + VmLck locked memory size + VmHWM peak resident set size ("high water mark") + VmRSS size of memory portions + VmData size of data, stack, and text segments + VmStk size of data, stack, and text segments + VmExe size of text segment + VmLib size of shared library code + VmPTE size of page table entries + Threads number of threads + SigQ number of signals queued/max. number for queue + SigPnd bitmap of pending signals for the thread + ShdPnd bitmap of shared pending signals for the process + SigBlk bitmap of blocked signals + SigIgn bitmap of ignored signals + SigCgt bitmap of catched signals + CapInh bitmap of inheritable capabilities + CapPrm bitmap of permitted capabilities + CapEff bitmap of effective capabilities + CapBnd bitmap of capabilities bounding set + Cpus_allowed mask of CPUs on which this process may run + Cpus_allowed_list Same as previous, but in "list format" + Mems_allowed mask of memory nodes allowed to this process + Mems_allowed_list Same as previous, but in "list format" + voluntary_ctxt_switches number of voluntary context switches + nonvoluntary_ctxt_switches number of non voluntary context switches +.............................................................................. + +Table 1-3: Contents of the statm files (as of 2.6.8-rc3) .............................................................................. Field Content size total program size (pages) (same as VmSize in status) @@ -188,7 +246,7 @@ Table 1-2: Contents of the statm files (as of 2.6.8-rc3) .............................................................................. -Table 1-3: Contents of the stat files (as of 2.6.22-rc3) +Table 1-4: Contents of the stat files (as of 2.6.30-rc7) .............................................................................. Field Content pid process id @@ -222,10 +280,10 @@ Table 1-3: Contents of the stat files (as of 2.6.22-rc3) start_stack address of the start of the stack esp current value of ESP eip current value of EIP - pending bitmap of pending signals (obsolete) - blocked bitmap of blocked signals (obsolete) - sigign bitmap of ignored signals (obsolete) - sigcatch bitmap of catched signals (obsolete) + pending bitmap of pending signals + blocked bitmap of blocked signals + sigign bitmap of ignored signals + sigcatch bitmap of catched signals wchan address where process went to sleep 0 (place holder) 0 (place holder) @@ -234,19 +292,99 @@ Table 1-3: Contents of the stat files (as of 2.6.22-rc3) rt_priority realtime priority policy scheduling policy (man sched_setscheduler) blkio_ticks time spent waiting for block IO + gtime guest time of the task in jiffies + cgtime guest time of the task children in jiffies .............................................................................. +The /proc/PID/map file containing the currently mapped memory regions and +their access permissions. + +The format is: + +address perms offset dev inode pathname + +08048000-08049000 r-xp 00000000 03:00 8312 /opt/test +08049000-0804a000 rw-p 00001000 03:00 8312 /opt/test +0804a000-0806b000 rw-p 00000000 00:00 0 [heap] +a7cb1000-a7cb2000 ---p 00000000 00:00 0 +a7cb2000-a7eb2000 rw-p 00000000 00:00 0 +a7eb2000-a7eb3000 ---p 00000000 00:00 0 +a7eb3000-a7ed5000 rw-p 00000000 00:00 0 +a7ed5000-a8008000 r-xp 00000000 03:00 4222 /lib/libc.so.6 +a8008000-a800a000 r--p 00133000 03:00 4222 /lib/libc.so.6 +a800a000-a800b000 rw-p 00135000 03:00 4222 /lib/libc.so.6 +a800b000-a800e000 rw-p 00000000 00:00 0 +a800e000-a8022000 r-xp 00000000 03:00 14462 /lib/libpthread.so.0 +a8022000-a8023000 r--p 00013000 03:00 14462 /lib/libpthread.so.0 +a8023000-a8024000 rw-p 00014000 03:00 14462 /lib/libpthread.so.0 +a8024000-a8027000 rw-p 00000000 00:00 0 +a8027000-a8043000 r-xp 00000000 03:00 8317 /lib/ld-linux.so.2 +a8043000-a8044000 r--p 0001b000 03:00 8317 /lib/ld-linux.so.2 +a8044000-a8045000 rw-p 0001c000 03:00 8317 /lib/ld-linux.so.2 +aff35000-aff4a000 rw-p 00000000 00:00 0 [stack] +ffffe000-fffff000 r-xp 00000000 00:00 0 [vdso] + +where "address" is the address space in the process that it occupies, "perms" +is a set of permissions: + + r = read + w = write + x = execute + s = shared + p = private (copy on write) + +"offset" is the offset into the mapping, "dev" is the device (major:minor), and +"inode" is the inode on that device. 0 indicates that no inode is associated +with the memory region, as the case would be with BSS (uninitialized data). +The "pathname" shows the name associated file for this mapping. If the mapping +is not associated with a file: + + [heap] = the heap of the program + [stack] = the stack of the main process + [vdso] = the "virtual dynamic shared object", + the kernel system call handler + + or if empty, the mapping is anonymous. + + +The /proc/PID/smaps is an extension based on maps, showing the memory +consumption for each of the process's mappings. For each of mappings there +is a series of lines such as the following: + +08048000-080bc000 r-xp 00000000 03:02 13130 /bin/bash +Size: 1084 kB +Rss: 892 kB +Pss: 374 kB +Shared_Clean: 892 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 0 kB +Referenced: 892 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB + +The first of these lines shows the same information as is displayed for the +mapping in /proc/PID/maps. The remaining lines show the size of the mapping, +the amount of the mapping that is currently resident in RAM, the "proportional +set size†(divide each shared page by the number of processes sharing it), the +number of clean and dirty shared pages in the mapping, and the number of clean +and dirty private pages in the mapping. The "Referenced" indicates the amount +of memory currently marked as referenced or accessed. + +This file is only present if the CONFIG_MMU kernel configuration option is +enabled. 1.2 Kernel data --------------- Similar to the process entries, the kernel data files give information about the running kernel. The files used to obtain this information are contained in -/proc and are listed in Table 1-4. Not all of these will be present in your +/proc and are listed in Table 1-5. Not all of these will be present in your system. It depends on the kernel configuration and the loaded modules, which files are there, and which are missing. -Table 1-4: Kernel info in /proc +Table 1-5: Kernel info in /proc .............................................................................. File Content apm Advanced power management info @@ -283,6 +421,7 @@ Table 1-4: Kernel info in /proc rtc Real time clock scsi SCSI info (see text) slabinfo Slab pool info + softirqs softirq usage stat Overall statistics swaps Swap space utilization sys See chapter 2 @@ -366,7 +505,7 @@ just those considered 'most important'. The new vectors are: RES, CAL, TLB -- rescheduling, call and TLB flush interrupts are sent from one CPU to another per the needs of the OS. Typically, their statistics are used by kernel developers and interested users to - determine the occurance of interrupt of the given type. + determine the occurrence of interrupts of the given type. The above IRQ vectors are displayed only when relevent. For example, the threshold vector does not exist on x86_64 platforms. Others are @@ -551,7 +690,7 @@ Committed_AS: The amount of memory presently allocated on the system. memory once that memory has been successfully allocated. VmallocTotal: total size of vmalloc memory area VmallocUsed: amount of vmalloc area which is used -VmallocChunk: largest contigious block of vmalloc area which is free +VmallocChunk: largest contiguous block of vmalloc area which is free .............................................................................. @@ -597,6 +736,25 @@ on the kind of area : 0xffffffffa0017000-0xffffffffa0022000 45056 sys_init_module+0xc27/0x1d00 ... pages=10 vmalloc N0=10 +.............................................................................. + +softirqs: + +Provides counts of softirq handlers serviced since boot time, for each cpu. + +> cat /proc/softirqs + CPU0 CPU1 CPU2 CPU3 + HI: 0 0 0 0 + TIMER: 27166 27120 27097 27034 + NET_TX: 0 0 0 17 + NET_RX: 42 0 0 39 + BLOCK: 0 0 107 1121 + TASKLET: 0 0 0 290 + SCHED: 27035 26983 26971 26746 + HRTIMER: 0 0 0 0 + RCU: 1678 1769 2178 2250 + + 1.3 IDE devices in /proc/ide ---------------------------- @@ -614,10 +772,10 @@ IDE devices: More detailed information can be found in the controller specific subdirectories. These are named ide0, ide1 and so on. Each of these -directories contains the files shown in table 1-5. +directories contains the files shown in table 1-6. -Table 1-5: IDE controller info in /proc/ide/ide? +Table 1-6: IDE controller info in /proc/ide/ide? .............................................................................. File Content channel IDE channel (0 or 1) @@ -627,11 +785,11 @@ Table 1-5: IDE controller info in /proc/ide/ide? .............................................................................. Each device connected to a controller has a separate subdirectory in the -controllers directory. The files listed in table 1-6 are contained in these +controllers directory. The files listed in table 1-7 are contained in these directories. -Table 1-6: IDE device information +Table 1-7: IDE device information .............................................................................. File Content cache The cache @@ -673,12 +831,12 @@ the drive parameters: 1.4 Networking info in /proc/net -------------------------------- -The subdirectory /proc/net follows the usual pattern. Table 1-6 shows the +The subdirectory /proc/net follows the usual pattern. Table 1-8 shows the additional values you get for IP version 6 if you configure the kernel to -support this. Table 1-7 lists the files and their meaning. +support this. Table 1-9 lists the files and their meaning. -Table 1-6: IPv6 info in /proc/net +Table 1-8: IPv6 info in /proc/net .............................................................................. File Content udp6 UDP sockets (IPv6) @@ -693,7 +851,7 @@ Table 1-6: IPv6 info in /proc/net .............................................................................. -Table 1-7: Network info in /proc/net +Table 1-9: Network info in /proc/net .............................................................................. File Content arp Kernel ARP table @@ -817,10 +975,10 @@ The directory /proc/parport contains information about the parallel ports of your system. It has one subdirectory for each port, named after the port number (0,1,2,...). -These directories contain the four files shown in Table 1-8. +These directories contain the four files shown in Table 1-10. -Table 1-8: Files in /proc/parport +Table 1-10: Files in /proc/parport .............................................................................. File Content autoprobe Any IEEE-1284 device ID information that has been acquired. @@ -838,10 +996,10 @@ Table 1-8: Files in /proc/parport Information about the available and actually used tty's can be found in the directory /proc/tty.You'll find entries for drivers and line disciplines in -this directory, as shown in Table 1-9. +this directory, as shown in Table 1-11. -Table 1-9: Files in /proc/tty +Table 1-11: Files in /proc/tty .............................................................................. File Content drivers list of drivers and their usage @@ -883,6 +1041,7 @@ since the system first booted. For a quick look, simply cat the file: processes 2915 procs_running 1 procs_blocked 0 + softirq 183433 0 21755 12 39 1137 231 21459 2263 The very first "cpu" line aggregates the numbers in all of the other "cpuN" lines. These numbers identify the amount of time the CPU has spent performing @@ -918,6 +1077,11 @@ CPUs. The "procs_blocked" line gives the number of processes currently blocked, waiting for I/O to complete. +The "softirq" line gives counts of softirqs serviced since boot time, for each +of the possible system softirqs. The first column is the total of all +softirqs serviced; each subsequent column is the total for that particular +softirq. + 1.9 Ext4 file system parameters ------------------------------ @@ -926,9 +1090,9 @@ Information about mounted ext4 file systems can be found in /proc/fs/ext4. Each mounted filesystem will have a directory in /proc/fs/ext4 based on its device name (i.e., /proc/fs/ext4/hdc or /proc/fs/ext4/dm-0). The files in each per-device directory are shown -in Table 1-10, below. +in Table 1-12, below. -Table 1-10: Files in /proc/fs/ext4/ +Table 1-12: Files in /proc/fs/ext4/ .............................................................................. File Content mb_groups details of multiblock allocator buddy cache of free blocks @@ -1003,11 +1167,13 @@ CHAPTER 3: PER-PROCESS PARAMETERS 3.1 /proc//oom_adj - Adjust the oom-killer score ------------------------------------------------------ -This file can be used to adjust the score used to select which processes -should be killed in an out-of-memory situation. Giving it a high score will -increase the likelihood of this process being killed by the oom-killer. Valid -values are in the range -16 to +15, plus the special value -17, which disables -oom-killing altogether for this process. +This file can be used to adjust the score used to select which processes should +be killed in an out-of-memory situation. The oom_adj value is a characteristic +of the task's mm, so all threads that share an mm with pid will have the same +oom_adj value. A high value will increase the likelihood of this process being +killed by the oom-killer. Valid values are in the range -16 to +15 as +explained below and a special value of -17, which disables oom-killing +altogether for threads sharing pid's mm. The process to be killed in an out-of-memory situation is selected among all others based on its badness score. This value equals the original memory size of the process @@ -1021,6 +1187,9 @@ the parent's score if they do not share the same memory. Thus forking servers are the prime candidates to be killed. Having only one 'hungry' child will make parent less preferable than the child. +/proc//oom_adj cannot be changed for kthreads since they are immune from +oom-killing already. + /proc//oom_score shows process' current badness score. The following heuristics are then applied: diff --git a/Documentation/filesystems/sysfs-pci.txt b/Documentation/filesystems/sysfs-pci.txt index 26e4b8bc53ee..85354b32d731 100644 --- a/Documentation/filesystems/sysfs-pci.txt +++ b/Documentation/filesystems/sysfs-pci.txt @@ -72,7 +72,7 @@ The 'rom' file is special in that it provides read-only access to the device's ROM file, if available. It's disabled by default, however, so applications should write the string "1" to the file to enable it before attempting a read call, and disable it following the access by writing "0" to the file. Note -that the device must be enabled for a rom read to return data succesfully. +that the device must be enabled for a rom read to return data successfully. In the event a driver is not bound to the device, it can be enabled using the 'enable' file, documented above. diff --git a/Documentation/filesystems/vfat.txt b/Documentation/filesystems/vfat.txt index 3a5ddc96901a..b58b84b50fa2 100644 --- a/Documentation/filesystems/vfat.txt +++ b/Documentation/filesystems/vfat.txt @@ -124,14 +124,19 @@ sys_immutable -- If set, ATTR_SYS attribute on FAT is handled as flush -- If set, the filesystem will try to flush to disk more early than normal. Not set by default. -rodir -- FAT has the ATTR_RO (read-only) attribute. But on Windows, - the ATTR_RO of the directory will be just ignored actually, - and is used by only applications as flag. E.g. it's setted - for the customized folder. +rodir -- FAT has the ATTR_RO (read-only) attribute. On Windows, + the ATTR_RO of the directory will just be ignored, + and is used only by applications as a flag (e.g. it's set + for the customized folder). If you want to use ATTR_RO as read-only flag even for the directory, set this option. +errors=panic|continue|remount-ro + -- specify FAT behavior on critical errors: panic, continue + without doing anything or remount the partition in + read-only mode (default behavior). + : 0,1,yes,no,true,false TODO diff --git a/Documentation/firmware_class/README b/Documentation/firmware_class/README index c3480aa66ba8..7eceaff63f5f 100644 --- a/Documentation/firmware_class/README +++ b/Documentation/firmware_class/README @@ -77,7 +77,8 @@ seconds for the whole load operation. - request_firmware_nowait() is also provided for convenience in - non-user contexts. + user contexts to request firmware asynchronously, but can't be called + in atomic contexts. about in-kernel persistence: diff --git a/Documentation/futex-requeue-pi.txt b/Documentation/futex-requeue-pi.txt new file mode 100644 index 000000000000..9dc1ff4fd536 --- /dev/null +++ b/Documentation/futex-requeue-pi.txt @@ -0,0 +1,131 @@ +Futex Requeue PI +---------------- + +Requeueing of tasks from a non-PI futex to a PI futex requires +special handling in order to ensure the underlying rt_mutex is never +left without an owner if it has waiters; doing so would break the PI +boosting logic [see rt-mutex-desgin.txt] For the purposes of +brevity, this action will be referred to as "requeue_pi" throughout +this document. Priority inheritance is abbreviated throughout as +"PI". + +Motivation +---------- + +Without requeue_pi, the glibc implementation of +pthread_cond_broadcast() must resort to waking all the tasks waiting +on a pthread_condvar and letting them try to sort out which task +gets to run first in classic thundering-herd formation. An ideal +implementation would wake the highest-priority waiter, and leave the +rest to the natural wakeup inherent in unlocking the mutex +associated with the condvar. + +Consider the simplified glibc calls: + +/* caller must lock mutex */ +pthread_cond_wait(cond, mutex) +{ + lock(cond->__data.__lock); + unlock(mutex); + do { + unlock(cond->__data.__lock); + futex_wait(cond->__data.__futex); + lock(cond->__data.__lock); + } while(...) + unlock(cond->__data.__lock); + lock(mutex); +} + +pthread_cond_broadcast(cond) +{ + lock(cond->__data.__lock); + unlock(cond->__data.__lock); + futex_requeue(cond->data.__futex, cond->mutex); +} + +Once pthread_cond_broadcast() requeues the tasks, the cond->mutex +has waiters. Note that pthread_cond_wait() attempts to lock the +mutex only after it has returned to user space. This will leave the +underlying rt_mutex with waiters, and no owner, breaking the +previously mentioned PI-boosting algorithms. + +In order to support PI-aware pthread_condvar's, the kernel needs to +be able to requeue tasks to PI futexes. This support implies that +upon a successful futex_wait system call, the caller would return to +user space already holding the PI futex. The glibc implementation +would be modified as follows: + + +/* caller must lock mutex */ +pthread_cond_wait_pi(cond, mutex) +{ + lock(cond->__data.__lock); + unlock(mutex); + do { + unlock(cond->__data.__lock); + futex_wait_requeue_pi(cond->__data.__futex); + lock(cond->__data.__lock); + } while(...) + unlock(cond->__data.__lock); + /* the kernel acquired the the mutex for us */ +} + +pthread_cond_broadcast_pi(cond) +{ + lock(cond->__data.__lock); + unlock(cond->__data.__lock); + futex_requeue_pi(cond->data.__futex, cond->mutex); +} + +The actual glibc implementation will likely test for PI and make the +necessary changes inside the existing calls rather than creating new +calls for the PI cases. Similar changes are needed for +pthread_cond_timedwait() and pthread_cond_signal(). + +Implementation +-------------- + +In order to ensure the rt_mutex has an owner if it has waiters, it +is necessary for both the requeue code, as well as the waiting code, +to be able to acquire the rt_mutex before returning to user space. +The requeue code cannot simply wake the waiter and leave it to +acquire the rt_mutex as it would open a race window between the +requeue call returning to user space and the waiter waking and +starting to run. This is especially true in the uncontended case. + +The solution involves two new rt_mutex helper routines, +rt_mutex_start_proxy_lock() and rt_mutex_finish_proxy_lock(), which +allow the requeue code to acquire an uncontended rt_mutex on behalf +of the waiter and to enqueue the waiter on a contended rt_mutex. +Two new system calls provide the kernel<->user interface to +requeue_pi: FUTEX_WAIT_REQUEUE_PI and FUTEX_REQUEUE_CMP_PI. + +FUTEX_WAIT_REQUEUE_PI is called by the waiter (pthread_cond_wait() +and pthread_cond_timedwait()) to block on the initial futex and wait +to be requeued to a PI-aware futex. The implementation is the +result of a high-speed collision between futex_wait() and +futex_lock_pi(), with some extra logic to check for the additional +wake-up scenarios. + +FUTEX_REQUEUE_CMP_PI is called by the waker +(pthread_cond_broadcast() and pthread_cond_signal()) to requeue and +possibly wake the waiting tasks. Internally, this system call is +still handled by futex_requeue (by passing requeue_pi=1). Before +requeueing, futex_requeue() attempts to acquire the requeue target +PI futex on behalf of the top waiter. If it can, this waiter is +woken. futex_requeue() then proceeds to requeue the remaining +nr_wake+nr_requeue tasks to the PI futex, calling +rt_mutex_start_proxy_lock() prior to each requeue to prepare the +task as a waiter on the underlying rt_mutex. It is possible that +the lock can be acquired at this stage as well, if so, the next +waiter is woken to finish the acquisition of the lock. + +FUTEX_REQUEUE_PI accepts nr_wake and nr_requeue as arguments, but +their sum is all that really matters. futex_requeue() will wake or +requeue up to nr_wake + nr_requeue tasks. It will wake only as many +tasks as it can acquire the lock for, which in the majority of cases +should be 0 as good programming practice dictates that the caller of +either pthread_cond_broadcast() or pthread_cond_signal() acquire the +mutex prior to making the call. FUTEX_REQUEUE_PI requires that +nr_wake=1. nr_requeue should be INT_MAX for broadcast and 0 for +signal. diff --git a/Documentation/gcov.txt b/Documentation/gcov.txt new file mode 100644 index 000000000000..e716aadb3a33 --- /dev/null +++ b/Documentation/gcov.txt @@ -0,0 +1,246 @@ +Using gcov with the Linux kernel +================================ + +1. Introduction +2. Preparation +3. Customization +4. Files +5. Modules +6. Separated build and test machines +7. Troubleshooting +Appendix A: sample script: gather_on_build.sh +Appendix B: sample script: gather_on_test.sh + + +1. Introduction +=============== + +gcov profiling kernel support enables the use of GCC's coverage testing +tool gcov [1] with the Linux kernel. Coverage data of a running kernel +is exported in gcov-compatible format via the "gcov" debugfs directory. +To get coverage data for a specific file, change to the kernel build +directory and use gcov with the -o option as follows (requires root): + +# cd /tmp/linux-out +# gcov -o /sys/kernel/debug/gcov/tmp/linux-out/kernel spinlock.c + +This will create source code files annotated with execution counts +in the current directory. In addition, graphical gcov front-ends such +as lcov [2] can be used to automate the process of collecting data +for the entire kernel and provide coverage overviews in HTML format. + +Possible uses: + +* debugging (has this line been reached at all?) +* test improvement (how do I change my test to cover these lines?) +* minimizing kernel configurations (do I need this option if the + associated code is never run?) + +-- + +[1] http://gcc.gnu.org/onlinedocs/gcc/Gcov.html +[2] http://ltp.sourceforge.net/coverage/lcov.php + + +2. Preparation +============== + +Configure the kernel with: + + CONFIG_DEBUGFS=y + CONFIG_GCOV_KERNEL=y + +and to get coverage data for the entire kernel: + + CONFIG_GCOV_PROFILE_ALL=y + +Note that kernels compiled with profiling flags will be significantly +larger and run slower. Also CONFIG_GCOV_PROFILE_ALL may not be supported +on all architectures. + +Profiling data will only become accessible once debugfs has been +mounted: + + mount -t debugfs none /sys/kernel/debug + + +3. Customization +================ + +To enable profiling for specific files or directories, add a line +similar to the following to the respective kernel Makefile: + + For a single file (e.g. main.o): + GCOV_PROFILE_main.o := y + + For all files in one directory: + GCOV_PROFILE := y + +To exclude files from being profiled even when CONFIG_GCOV_PROFILE_ALL +is specified, use: + + GCOV_PROFILE_main.o := n + and: + GCOV_PROFILE := n + +Only files which are linked to the main kernel image or are compiled as +kernel modules are supported by this mechanism. + + +4. Files +======== + +The gcov kernel support creates the following files in debugfs: + + /sys/kernel/debug/gcov + Parent directory for all gcov-related files. + + /sys/kernel/debug/gcov/reset + Global reset file: resets all coverage data to zero when + written to. + + /sys/kernel/debug/gcov/path/to/compile/dir/file.gcda + The actual gcov data file as understood by the gcov + tool. Resets file coverage data to zero when written to. + + /sys/kernel/debug/gcov/path/to/compile/dir/file.gcno + Symbolic link to a static data file required by the gcov + tool. This file is generated by gcc when compiling with + option -ftest-coverage. + + +5. Modules +========== + +Kernel modules may contain cleanup code which is only run during +module unload time. The gcov mechanism provides a means to collect +coverage data for such code by keeping a copy of the data associated +with the unloaded module. This data remains available through debugfs. +Once the module is loaded again, the associated coverage counters are +initialized with the data from its previous instantiation. + +This behavior can be deactivated by specifying the gcov_persist kernel +parameter: + + gcov_persist=0 + +At run-time, a user can also choose to discard data for an unloaded +module by writing to its data file or the global reset file. + + +6. Separated build and test machines +==================================== + +The gcov kernel profiling infrastructure is designed to work out-of-the +box for setups where kernels are built and run on the same machine. In +cases where the kernel runs on a separate machine, special preparations +must be made, depending on where the gcov tool is used: + +a) gcov is run on the TEST machine + +The gcov tool version on the test machine must be compatible with the +gcc version used for kernel build. Also the following files need to be +copied from build to test machine: + +from the source tree: + - all C source files + headers + +from the build tree: + - all C source files + headers + - all .gcda and .gcno files + - all links to directories + +It is important to note that these files need to be placed into the +exact same file system location on the test machine as on the build +machine. If any of the path components is symbolic link, the actual +directory needs to be used instead (due to make's CURDIR handling). + +b) gcov is run on the BUILD machine + +The following files need to be copied after each test case from test +to build machine: + +from the gcov directory in sysfs: + - all .gcda files + - all links to .gcno files + +These files can be copied to any location on the build machine. gcov +must then be called with the -o option pointing to that directory. + +Example directory setup on the build machine: + + /tmp/linux: kernel source tree + /tmp/out: kernel build directory as specified by make O= + /tmp/coverage: location of the files copied from the test machine + + [user@build] cd /tmp/out + [user@build] gcov -o /tmp/coverage/tmp/out/init main.c + + +7. Troubleshooting +================== + +Problem: Compilation aborts during linker step. +Cause: Profiling flags are specified for source files which are not + linked to the main kernel or which are linked by a custom + linker procedure. +Solution: Exclude affected source files from profiling by specifying + GCOV_PROFILE := n or GCOV_PROFILE_basename.o := n in the + corresponding Makefile. + + +Appendix A: gather_on_build.sh +============================== + +Sample script to gather coverage meta files on the build machine +(see 6a): + +#!/bin/bash + +KSRC=$1 +KOBJ=$2 +DEST=$3 + +if [ -z "$KSRC" ] || [ -z "$KOBJ" ] || [ -z "$DEST" ]; then + echo "Usage: $0 " >&2 + exit 1 +fi + +KSRC=$(cd $KSRC; printf "all:\n\t@echo \${CURDIR}\n" | make -f -) +KOBJ=$(cd $KOBJ; printf "all:\n\t@echo \${CURDIR}\n" | make -f -) + +find $KSRC $KOBJ \( -name '*.gcno' -o -name '*.[ch]' -o -type l \) -a \ + -perm /u+r,g+r | tar cfz $DEST -P -T - + +if [ $? -eq 0 ] ; then + echo "$DEST successfully created, copy to test system and unpack with:" + echo " tar xfz $DEST -P" +else + echo "Could not create file $DEST" +fi + + +Appendix B: gather_on_test.sh +============================= + +Sample script to gather coverage data files on the test machine +(see 6b): + +#!/bin/bash + +DEST=$1 +GCDA=/sys/kernel/debug/gcov + +if [ -z "$DEST" ] ; then + echo "Usage: $0 " >&2 + exit 1 +fi + +find $GCDA -name '*.gcno' -o -name '*.gcda' | tar cfz $DEST -T - + +if [ $? -eq 0 ] ; then + echo "$DEST successfully created, copy to build system and unpack with:" + echo " tar xfz $DEST" +else + echo "Could not create file $DEST" +fi diff --git a/Documentation/gpio.txt b/Documentation/gpio.txt index 145c25a170c7..e4b6985044a2 100644 --- a/Documentation/gpio.txt +++ b/Documentation/gpio.txt @@ -458,7 +458,7 @@ debugfs interface, since it provides control over GPIO direction and value instead of just showing a gpio state summary. Plus, it could be present on production systems without debugging support. -Given approprate hardware documentation for the system, userspace could +Given appropriate hardware documentation for the system, userspace could know for example that GPIO #23 controls the write protect line used to protect boot loader segments in flash memory. System upgrade procedures may need to temporarily remove that protection, first importing a GPIO, diff --git a/Documentation/hwmon/f71882fg b/Documentation/hwmon/f71882fg index a8321267b5b6..bee4c30bc1e2 100644 --- a/Documentation/hwmon/f71882fg +++ b/Documentation/hwmon/f71882fg @@ -2,14 +2,18 @@ Kernel driver f71882fg ====================== Supported chips: - * Fintek F71882FG and F71883FG - Prefix: 'f71882fg' + * Fintek F71858FG + Prefix: 'f71858fg' Addresses scanned: none, address read from Super I/O config space Datasheet: Available from the Fintek website * Fintek F71862FG and F71863FG Prefix: 'f71862fg' Addresses scanned: none, address read from Super I/O config space Datasheet: Available from the Fintek website + * Fintek F71882FG and F71883FG + Prefix: 'f71882fg' + Addresses scanned: none, address read from Super I/O config space + Datasheet: Available from the Fintek website * Fintek F8000 Prefix: 'f8000' Addresses scanned: none, address read from Super I/O config space @@ -66,13 +70,13 @@ printed when loading the driver. Three different fan control modes are supported; the mode number is written to the pwm#_enable file. Note that not all modes are supported on all -chips, and some modes may only be available in RPM / PWM mode on the F8000. +chips, and some modes may only be available in RPM / PWM mode. Writing an unsupported mode will result in an invalid parameter error. * 1: Manual mode You ask for a specific PWM duty cycle / DC voltage or a specific % of fan#_full_speed by writing to the pwm# file. This mode is only - available on the F8000 if the fan channel is in RPM mode. + available on the F71858FG / F8000 if the fan channel is in RPM mode. * 2: Normal auto mode You can define a number of temperature/fan speed trip points, which % the diff --git a/Documentation/hwmon/ibmaem b/Documentation/hwmon/ibmaem index e98bdfea3467..1e0d59e000b4 100644 --- a/Documentation/hwmon/ibmaem +++ b/Documentation/hwmon/ibmaem @@ -7,7 +7,7 @@ henceforth as AEM. Supported systems: * Any recent IBM System X server with AEM support. This includes the x3350, x3550, x3650, x3655, x3755, x3850 M2, - x3950 M2, and certain HS2x/LS2x/QS2x blades. The IPMI host interface + x3950 M2, and certain HC10/HS2x/LS2x/QS2x blades. The IPMI host interface driver ("ipmi-si") needs to be loaded for this driver to do anything. Prefix: 'ibmaem' Datasheet: Not available diff --git a/Documentation/hwmon/sysfs-interface b/Documentation/hwmon/sysfs-interface index 004ee161721e..dcbd502c8792 100644 --- a/Documentation/hwmon/sysfs-interface +++ b/Documentation/hwmon/sysfs-interface @@ -70,6 +70,7 @@ are interpreted as 0! For more on how written strings are interpreted see the [0-*] denotes any positive number starting from 0 [1-*] denotes any positive number starting from 1 RO read only value +WO write only value RW read/write value Read/write values may be read-only for some chips, depending on the @@ -295,6 +296,24 @@ temp[1-*]_label Suggested temperature channel label. user-space. RO +temp[1-*]_lowest + Historical minimum temperature + Unit: millidegree Celsius + RO + +temp[1-*]_highest + Historical maximum temperature + Unit: millidegree Celsius + RO + +temp[1-*]_reset_history + Reset temp_lowest and temp_highest + WO + +temp_reset_history + Reset temp_lowest and temp_highest for all sensors + WO + Some chips measure temperature using external thermistors and an ADC, and report the temperature measurement as a voltage. Converting this voltage back to a temperature (or the other way around for limits) requires diff --git a/Documentation/hwmon/tmp401 b/Documentation/hwmon/tmp401 new file mode 100644 index 000000000000..9fc447249212 --- /dev/null +++ b/Documentation/hwmon/tmp401 @@ -0,0 +1,42 @@ +Kernel driver tmp401 +==================== + +Supported chips: + * Texas Instruments TMP401 + Prefix: 'tmp401' + Addresses scanned: I2C 0x4c + Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp401.html + * Texas Instruments TMP411 + Prefix: 'tmp411' + Addresses scanned: I2C 0x4c + Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp411.html + +Authors: + Hans de Goede + Andre Prendel + +Description +----------- + +This driver implements support for Texas Instruments TMP401 and +TMP411 chips. These chips implements one remote and one local +temperature sensor. Temperature is measured in degrees +Celsius. Resolution of the remote sensor is 0.0625 degree. Local +sensor resolution can be set to 0.5, 0.25, 0.125 or 0.0625 degree (not +supported by the driver so far, so using the default resolution of 0.5 +degree). + +The driver provides the common sysfs-interface for temperatures (see +/Documentation/hwmon/sysfs-interface under Temperatures). + +The TMP411 chip is compatible with TMP401. It provides some additional +features. + +* Minimum and Maximum temperature measured since power-on, chip-reset + + Exported via sysfs attributes tempX_lowest and tempX_highest. + +* Reset of historical minimum/maximum temperature measurements + + Exported via sysfs attribute temp_reset_history. Writing 1 to this + file triggers a reset. diff --git a/Documentation/hwmon/w83627ehf b/Documentation/hwmon/w83627ehf index b6eb59384bb3..02b74899edaf 100644 --- a/Documentation/hwmon/w83627ehf +++ b/Documentation/hwmon/w83627ehf @@ -12,6 +12,10 @@ Supported chips: Addresses scanned: ISA address retrieved from Super I/O registers Datasheet: http://www.nuvoton.com.tw/NR/rdonlyres/7885623D-A487-4CF9-A47F-30C5F73D6FE6/0/W83627DHG.pdf + * Winbond W83627DHG-P + Prefix: 'w83627dhg' + Addresses scanned: ISA address retrieved from Super I/O registers + Datasheet: not available * Winbond W83667HG Prefix: 'w83667hg' Addresses scanned: ISA address retrieved from Super I/O registers @@ -28,8 +32,8 @@ Description ----------- This driver implements support for the Winbond W83627EHF, W83627EHG, -W83627DHG and W83667HG super I/O chips. We will refer to them collectively -as Winbond chips. +W83627DHG, W83627DHG-P and W83667HG super I/O chips. We will refer to them +collectively as Winbond chips. The chips implement three temperature sensors, five fan rotation speed sensors, ten analog voltage sensors (only nine for the 627DHG), one @@ -135,3 +139,6 @@ done in the driver for all register addresses. The DHG also supports PECI, where the DHG queries Intel CPU temperatures, and the ICH8 southbridge gets that data via PECI from the DHG, so that the southbridge drives the fans. And the DHG supports SST, a one-wire serial bus. + +The DHG-P has an additional automatic fan speed control mode named Smart Fan +(TM) III+. This mode is not yet supported by the driver. diff --git a/Documentation/i2c/busses/i2c-ocores b/Documentation/i2c/busses/i2c-ocores index cfcebb10d14e..c269aaa2f26a 100644 --- a/Documentation/i2c/busses/i2c-ocores +++ b/Documentation/i2c/busses/i2c-ocores @@ -20,6 +20,8 @@ platform_device with the base address and interrupt number. The dev.platform_data of the device should also point to a struct ocores_i2c_platform_data (see linux/i2c-ocores.h) describing the distance between registers and the input clock speed. +There is also a possibility to attach a list of i2c_board_info which +the i2c-ocores driver will add to the bus upon creation. E.G. something like: @@ -36,9 +38,24 @@ static struct resource ocores_resources[] = { }, }; +/* optional board info */ +struct i2c_board_info ocores_i2c_board_info[] = { + { + I2C_BOARD_INFO("tsc2003", 0x48), + .platform_data = &tsc2003_platform_data, + .irq = TSC_IRQ + }, + { + I2C_BOARD_INFO("adv7180", 0x42 >> 1), + .irq = ADV_IRQ + } +}; + static struct ocores_i2c_platform_data myi2c_data = { .regstep = 2, /* two bytes between registers */ .clock_khz = 50000, /* input clock of 50MHz */ + .devices = ocores_i2c_board_info, /* optional table of devices */ + .num_devices = ARRAY_SIZE(ocores_i2c_board_info), /* table size */ }; static struct platform_device myi2c = { diff --git a/Documentation/i2c/busses/i2c-viapro b/Documentation/i2c/busses/i2c-viapro index 22efedf60c87..2e758b0e9456 100644 --- a/Documentation/i2c/busses/i2c-viapro +++ b/Documentation/i2c/busses/i2c-viapro @@ -19,6 +19,9 @@ Supported adapters: * VIA Technologies, Inc. VX800/VX820 Datasheet: available on http://linux.via.com.tw + * VIA Technologies, Inc. VX855/VX875 + Datasheet: Availability unknown + Authors: Kyösti Mälkki , Mark D. Studebaker , @@ -53,6 +56,7 @@ Your lspci -n listing must show one of these : device 1106:3287 (VT8251) device 1106:8324 (CX700) device 1106:8353 (VX800/VX820) + device 1106:8409 (VX855/VX875) If none of these show up, you should look in the BIOS for settings like enable ACPI / SMBus or even USB. diff --git a/Documentation/i2c/instantiating-devices b/Documentation/i2c/instantiating-devices index b55ce57a84db..c740b7b41088 100644 --- a/Documentation/i2c/instantiating-devices +++ b/Documentation/i2c/instantiating-devices @@ -165,3 +165,47 @@ was done there. Two significant differences are: Once again, method 3 should be avoided wherever possible. Explicit device instantiation (methods 1 and 2) is much preferred for it is safer and faster. + + +Method 4: Instantiate from user-space +------------------------------------- + +In general, the kernel should know which I2C devices are connected and +what addresses they live at. However, in certain cases, it does not, so a +sysfs interface was added to let the user provide the information. This +interface is made of 2 attribute files which are created in every I2C bus +directory: new_device and delete_device. Both files are write only and you +must write the right parameters to them in order to properly instantiate, +respectively delete, an I2C device. + +File new_device takes 2 parameters: the name of the I2C device (a string) +and the address of the I2C device (a number, typically expressed in +hexadecimal starting with 0x, but can also be expressed in decimal.) + +File delete_device takes a single parameter: the address of the I2C +device. As no two devices can live at the same address on a given I2C +segment, the address is sufficient to uniquely identify the device to be +deleted. + +Example: +# echo eeprom 0x50 > /sys/class/i2c-adapter/i2c-3/new_device + +While this interface should only be used when in-kernel device declaration +can't be done, there is a variety of cases where it can be helpful: +* The I2C driver usually detects devices (method 3 above) but the bus + segment your device lives on doesn't have the proper class bit set and + thus detection doesn't trigger. +* The I2C driver usually detects devices, but your device lives at an + unexpected address. +* The I2C driver usually detects devices, but your device is not detected, + either because the detection routine is too strict, or because your + device is not officially supported yet but you know it is compatible. +* You are developing a driver on a test board, where you soldered the I2C + device yourself. + +This interface is a replacement for the force_* module parameters some I2C +drivers implement. Being implemented in i2c-core rather than in each +device driver individually, it is much more efficient, and also has the +advantage that you do not have to reload the driver to change a setting. +You can also instantiate the device before the driver is loaded or even +available, and you don't need to know what driver the device needs. diff --git a/Documentation/i2c/writing-clients b/Documentation/i2c/writing-clients index c1a06f989cf7..7860aafb483d 100644 --- a/Documentation/i2c/writing-clients +++ b/Documentation/i2c/writing-clients @@ -126,19 +126,9 @@ different) configuration information, as do drivers handling chip variants that can't be distinguished by protocol probing, or which need some board specific information to operate correctly. -Accordingly, the I2C stack now has two models for associating I2C devices -with their drivers: the original "legacy" model, and a newer one that's -fully compatible with the Linux 2.6 driver model. These models do not mix, -since the "legacy" model requires drivers to create "i2c_client" device -objects after SMBus style probing, while the Linux driver model expects -drivers to be given such device objects in their probe() routines. -The legacy model is deprecated now and will soon be removed, so we no -longer document it here. - - -Standard Driver Model Binding ("New Style") -------------------------------------------- +Device/Driver Binding +--------------------- System infrastructure, typically board-specific initialization code or boot firmware, reports what I2C devices exist. For example, there may be @@ -201,7 +191,7 @@ a given I2C bus. This is for example the case of hardware monitoring devices on a PC's SMBus. In that case, you may want to let your driver detect supported devices automatically. This is how the legacy model was working, and is now available as an extension to the standard -driver model (so that we can finally get rid of the legacy model.) +driver model. You simply have to define a detect callback which will attempt to identify supported devices (returning 0 for supported ones and -ENODEV diff --git a/Documentation/ide/ide.txt b/Documentation/ide/ide.txt index 0c78f4b1d9d9..e77bebfa7b0d 100644 --- a/Documentation/ide/ide.txt +++ b/Documentation/ide/ide.txt @@ -216,6 +216,8 @@ Other kernel parameters for ide_core are: * "noflush=[interface_number.device_number]" to disable flush requests +* "nohpa=[interface_number.device_number]" to disable Host Protected Area + * "noprobe=[interface_number.device_number]" to skip probing * "nowerr=[interface_number.device_number]" to ignore the WRERR_STAT bit diff --git a/Documentation/input/input.txt b/Documentation/input/input.txt index 686ee9932dff..b93c08442e3c 100644 --- a/Documentation/input/input.txt +++ b/Documentation/input/input.txt @@ -278,7 +278,7 @@ struct input_event { }; 'time' is the timestamp, it returns the time at which the event happened. -Type is for example EV_REL for relative moment, REL_KEY for a keypress or +Type is for example EV_REL for relative moment, EV_KEY for a keypress or release. More types are defined in include/linux/input.h. 'code' is event code, for example REL_X or KEY_BACKSPACE, again a complete diff --git a/Documentation/input/rotary-encoder.txt b/Documentation/input/rotary-encoder.txt index 435102a26d96..3a6aec40c0b0 100644 --- a/Documentation/input/rotary-encoder.txt +++ b/Documentation/input/rotary-encoder.txt @@ -67,7 +67,12 @@ data with it. struct rotary_encoder_platform_data is declared in include/linux/rotary-encoder.h and needs to be filled with the number of steps the encoder has and can carry information about externally inverted -signals (because of used invertig buffer or other reasons). +signals (because of an inverting buffer or other reasons). The encoder +can be set up to deliver input information as either an absolute or relative +axes. For relative axes the input event returns +/-1 for each step. For +absolute axes the position of the encoder can either roll over between zero +and the number of steps or will clamp at the maximum and zero depending on +the configuration. Because GPIO to IRQ mapping is platform specific, this information must be given in seperately to the driver. See the example below. @@ -85,6 +90,8 @@ be given in seperately to the driver. See the example below. static struct rotary_encoder_platform_data my_rotary_encoder_info = { .steps = 24, .axis = ABS_X, + .relative_axis = false, + .rollover = false, .gpio_a = GPIO_ROTARY_A, .gpio_b = GPIO_ROTARY_B, .inverted_a = 0, diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt index 1f779a25c703..7bb0d934b6d8 100644 --- a/Documentation/ioctl/ioctl-number.txt +++ b/Documentation/ioctl/ioctl-number.txt @@ -149,6 +149,8 @@ Code Seq# Include File Comments 'p' 40-7F linux/nvram.h 'p' 80-9F user-space parport +'p' a1-a4 linux/pps.h LinuxPPS + 'q' 00-1F linux/serio.h 'q' 80-FF Internet PhoneJACK, Internet LineJACK diff --git a/Documentation/isdn/00-INDEX b/Documentation/isdn/00-INDEX index 5a2d69989a8c..e87e336f590e 100644 --- a/Documentation/isdn/00-INDEX +++ b/Documentation/isdn/00-INDEX @@ -14,39 +14,37 @@ README - general info on what you need and what to do for Linux ISDN. README.FAQ - general info for FAQ. -README.audio - - info for running audio over ISDN. -README.fax - - info for using Fax over ISDN. -README.gigaset - - info on the drivers for Siemens Gigaset ISDN adapters. -README.icn - - info on the ICN-ISDN-card and its driver. README.HiSax - info on the HiSax driver which replaces the old teles. -README.hfc-pci - - info on hfc-pci based cards. -README.pcbit - - info on the PCBIT-D ISDN adapter and driver. -README.syncppp - - info on running Sync PPP over ISDN. -syncPPP.FAQ - - frequently asked questions about running PPP over ISDN. -README.avmb1 - - info on driver for AVM-B1 ISDN card. README.act2000 - info on driver for IBM ACT-2000 card. -README.eicon - - info on driver for Eicon active cards. +README.audio + - info for running audio over ISDN. +README.avmb1 + - info on driver for AVM-B1 ISDN card. README.concap - info on "CONCAP" encapsulation protocol interface used for X.25. README.diversion - info on module for isdn diversion services. +README.fax + - info for using Fax over ISDN. +README.gigaset + - info on the drivers for Siemens Gigaset ISDN adapters +README.hfc-pci + - info on hfc-pci based cards. +README.hysdn + - info on driver for Hypercope active HYSDN cards +README.icn + - info on the ICN-ISDN-card and its driver. +README.mISDN + - info on the Modular ISDN subsystem (mISDN) +README.pcbit + - info on the PCBIT-D ISDN adapter and driver. README.sc - info on driver for Spellcaster cards. +README.syncppp + - info on running Sync PPP over ISDN. README.x25 - info for running X.25 over ISDN. -README.hysdn - - info on driver for Hypercope active HYSDN cards -README.mISDN - - info on the Modular ISDN subsystem (mISDN). +syncPPP.FAQ + - frequently asked questions about running PPP over ISDN. diff --git a/Documentation/isdn/INTERFACE.CAPI b/Documentation/isdn/INTERFACE.CAPI index 786d619b36e5..686e107923ec 100644 --- a/Documentation/isdn/INTERFACE.CAPI +++ b/Documentation/isdn/INTERFACE.CAPI @@ -45,7 +45,7 @@ From then on, Kernel CAPI may call the registered callback functions for the device. If the device becomes unusable for any reason (shutdown, disconnect ...), the -driver has to call capi_ctr_reseted(). This will prevent further calls to the +driver has to call capi_ctr_down(). This will prevent further calls to the callback functions by Kernel CAPI. @@ -114,20 +114,36 @@ char *driver_name int (*load_firmware)(struct capi_ctr *ctrlr, capiloaddata *ldata) (optional) pointer to a callback function for sending firmware and configuration data to the device + Return value: 0 on success, error code on error + Called in process context. void (*reset_ctr)(struct capi_ctr *ctrlr) - pointer to a callback function for performing a reset on the device, - releasing all registered applications + (optional) pointer to a callback function for performing a reset on + the device, releasing all registered applications + Called in process context. void (*register_appl)(struct capi_ctr *ctrlr, u16 applid, capi_register_params *rparam) void (*release_appl)(struct capi_ctr *ctrlr, u16 applid) pointers to callback functions for registration and deregistration of applications with the device + Calls to these functions are serialized by Kernel CAPI so that only + one call to any of them is active at any time. u16 (*send_message)(struct capi_ctr *ctrlr, struct sk_buff *skb) pointer to a callback function for sending a CAPI message to the device + Return value: CAPI error code + If the method returns 0 (CAPI_NOERROR) the driver has taken ownership + of the skb and the caller may no longer access it. If it returns a + non-zero (error) value then ownership of the skb returns to the caller + who may reuse or free it. + The return value should only be used to signal problems with respect + to accepting or queueing the message. Errors occurring during the + actual processing of the message should be signaled with an + appropriate reply message. + Calls to this function are not serialized by Kernel CAPI, ie. it must + be prepared to be re-entered. char *(*procinfo)(struct capi_ctr *ctrlr) pointer to a callback function returning the entry for the device in @@ -138,6 +154,8 @@ read_proc_t *ctr_read_proc system entry, /proc/capi/controllers/; will be called with a pointer to the device's capi_ctr structure as the last (data) argument +Note: Callback functions are never called in interrupt context. + - to be filled in before calling capi_ctr_ready(): u8 manu[CAPI_MANUFACTURER_LEN] @@ -153,6 +171,45 @@ u8 serial[CAPI_SERIAL_LEN] value to return for CAPI_GET_SERIAL +4.3 The _cmsg Structure + +(declared in ) + +The _cmsg structure stores the contents of a CAPI 2.0 message in an easily +accessible form. It contains members for all possible CAPI 2.0 parameters, of +which only those appearing in the message type currently being processed are +actually used. Unused members should be set to zero. + +Members are named after the CAPI 2.0 standard names of the parameters they +represent. See for the exact spelling. Member data +types are: + +u8 for CAPI parameters of type 'byte' + +u16 for CAPI parameters of type 'word' + +u32 for CAPI parameters of type 'dword' + +_cstruct for CAPI parameters of type 'struct' not containing any + variably-sized (struct) subparameters (eg. 'Called Party Number') + The member is a pointer to a buffer containing the parameter in + CAPI encoding (length + content). It may also be NULL, which will + be taken to represent an empty (zero length) parameter. + +_cmstruct for CAPI parameters of type 'struct' containing 'struct' + subparameters ('Additional Info' and 'B Protocol') + The representation is a single byte containing one of the values: + CAPI_DEFAULT: the parameter is empty + CAPI_COMPOSE: the values of the subparameters are stored + individually in the corresponding _cmsg structure members + +Functions capi_cmsg2message() and capi_message2cmsg() are provided to convert +messages between their transport encoding described in the CAPI 2.0 standard +and their _cmsg structure representation. Note that capi_cmsg2message() does +not know or check the size of its destination buffer. The caller must make +sure it is big enough to accomodate the resulting CAPI message. + + 5. Lower Layer Interface Functions (declared in ) @@ -166,7 +223,7 @@ int detach_capi_ctr(struct capi_ctr *ctrlr) register/unregister a device (controller) with Kernel CAPI void capi_ctr_ready(struct capi_ctr *ctrlr) -void capi_ctr_reseted(struct capi_ctr *ctrlr) +void capi_ctr_down(struct capi_ctr *ctrlr) signal controller ready/not ready void capi_ctr_suspend_output(struct capi_ctr *ctrlr) @@ -211,3 +268,32 @@ CAPIMSG_CONTROL(m) CAPIMSG_SETCONTROL(m, contr) Controller/PLCI/NCCI (u32) CAPIMSG_DATALEN(m) CAPIMSG_SETDATALEN(m, len) Data Length (u16) + +Library functions for working with _cmsg structures +(from ): + +unsigned capi_cmsg2message(_cmsg *cmsg, u8 *msg) + Assembles a CAPI 2.0 message from the parameters in *cmsg, storing the + result in *msg. + +unsigned capi_message2cmsg(_cmsg *cmsg, u8 *msg) + Disassembles the CAPI 2.0 message in *msg, storing the parameters in + *cmsg. + +unsigned capi_cmsg_header(_cmsg *cmsg, u16 ApplId, u8 Command, u8 Subcommand, + u16 Messagenumber, u32 Controller) + Fills the header part and address field of the _cmsg structure *cmsg + with the given values, zeroing the remainder of the structure so only + parameters with non-default values need to be changed before sending + the message. + +void capi_cmsg_answer(_cmsg *cmsg) + Sets the low bit of the Subcommand field in *cmsg, thereby converting + _REQ to _CONF and _IND to _RESP. + +char *capi_cmd2str(u8 Command, u8 Subcommand) + Returns the CAPI 2.0 message name corresponding to the given command + and subcommand values, as a static ASCII string. The return value may + be NULL if the command/subcommand is not one of those defined in the + CAPI 2.0 standard. + diff --git a/Documentation/isdn/README.gigaset b/Documentation/isdn/README.gigaset index 02c0e9341dd8..f9963103ae3d 100644 --- a/Documentation/isdn/README.gigaset +++ b/Documentation/isdn/README.gigaset @@ -149,10 +149,8 @@ GigaSet 307x Device Driver configuration files and chat scripts in the gigaset-VERSION/ppp directory in the driver packages from http://sourceforge.net/projects/gigaset307x/. Please note that the USB drivers are not able to change the state of the - control lines (the M105 driver can be configured to use some undocumented - control requests, if you really need the control lines, though). This means - you must use "Stupid Mode" if you are using wvdial or you should use the - nocrtscts option of pppd. + control lines. This means you must use "Stupid Mode" if you are using + wvdial or you should use the nocrtscts option of pppd. You must also assure that the ppp_async module is loaded with the parameter flag_time=0. You can do this e.g. by adding a line like @@ -190,20 +188,19 @@ GigaSet 307x Device Driver You can also use /sys/class/tty/ttyGxy/cidmode for changing the CID mode setting (ttyGxy is ttyGU0 or ttyGB0). -2.6. M105 Undocumented USB Requests - ------------------------------ - - The Gigaset M105 USB data box understands a couple of useful, but - undocumented USB commands. These requests are not used in normal - operation (for wireless access to the base), but are needed for access - to the M105's own configuration mode (registration to the base, baudrate - and line format settings, device status queries) via the gigacontr - utility. Their use is controlled by the kernel configuration option - "Support for undocumented USB requests" (CONFIG_GIGASET_UNDOCREQ). If you - encounter error code -ENOTTY when trying to use some features of the - M105, try setting that option to "y" via 'make {x,menu}config' and - recompiling the driver. +2.6. Unregistered Wireless Devices (M101/M105) + ----------------------------------------- + The main purpose of the ser_gigaset and usb_gigaset drivers is to allow + the M101 and M105 wireless devices to be used as ISDN devices for ISDN + connections through a Gigaset base. Therefore they assume that the device + is registered to a DECT base. + If the M101/M105 device is not registered to a base, initialization of + the device fails, and a corresponding error message is logged by the + driver. In that situation, a restricted set of functions is available + which includes, in particular, those necessary for registering the device + to a base or for switching it between Fixed Part and Portable Part + modes. 3. Troubleshooting --------------- @@ -234,11 +231,12 @@ GigaSet 307x Device Driver Select Unimodem mode for all DECT data adapters. (see section 2.4.) Problem: - You want to configure your USB DECT data adapter (M105) but gigacontr - reports an error: "/dev/ttyGU0: Inappropriate ioctl for device". + Messages like this: + usb_gigaset 3-2:1.0: Could not initialize the device. + appear in your syslog. Solution: - Recompile the usb_gigaset driver with the kernel configuration option - CONFIG_GIGASET_UNDOCREQ set to 'y'. (see section 2.6.) + Check whether your M10x wireless device is correctly registered to the + Gigaset base. (see section 2.6.) 3.2. Telling the driver to provide more information ---------------------------------------------- diff --git a/Documentation/ja_JP/SubmitChecklist b/Documentation/ja_JP/SubmitChecklist index 6c42e071d723..2df4576f1173 100644 --- a/Documentation/ja_JP/SubmitChecklist +++ b/Documentation/ja_JP/SubmitChecklist @@ -75,7 +75,7 @@ Linux カーãƒãƒ«ãƒ‘ãƒƒãƒæŠ•ç¨¿è€…å‘ã‘ãƒã‚§ãƒƒã‚¯ãƒªã‚¹ãƒˆ ビルドã—ãŸä¸Šã€å‹•作確èªã‚’行ã£ã¦ãã ã•ã„。 14: ã‚‚ã—パッãƒãŒãƒ‡ã‚£ã‚¹ã‚¯ã®I/O性能ãªã©ã«å½±éŸ¿ã‚’与ãˆã‚‹ã‚ˆã†ã§ã‚れã°ã€ - 'CONFIG_LBD'オプションを有効ã«ã—ãŸå ´åˆã¨ç„¡åйã«ã—ãŸå ´åˆã®ä¸¡æ–¹ã§ + 'CONFIG_LBDAF'オプションを有効ã«ã—ãŸå ´åˆã¨ç„¡åйã«ã—ãŸå ´åˆã®ä¸¡æ–¹ã§ テストを実施ã—ã¦ã¿ã¦ãã ã•ã„。 15: lockdepã®æ©Ÿèƒ½ã‚’å…¨ã¦æœ‰åйã«ã—ãŸä¸Šã§ã€å…¨ã¦ã®ã‚³ãƒ¼ãƒ‰ãƒ‘スを評価ã—ã¦ãã ã•ã„。 diff --git a/Documentation/kbuild/kconfig.txt b/Documentation/kbuild/kconfig.txt index 26a7c0a93193..849b5e56d06f 100644 --- a/Documentation/kbuild/kconfig.txt +++ b/Documentation/kbuild/kconfig.txt @@ -35,6 +35,79 @@ new .config files to see the differences: (Yes, we need something better here.) +______________________________________________________________________ +Environment variables for '*config' + +KCONFIG_CONFIG +-------------------------------------------------- +This environment variable can be used to specify a default kernel config +file name to override the default name of ".config". + +KCONFIG_OVERWRITECONFIG +-------------------------------------------------- +If you set KCONFIG_OVERWRITECONFIG in the environment, Kconfig will not +break symlinks when .config is a symlink to somewhere else. + +KCONFIG_NOTIMESTAMP +-------------------------------------------------- +If this environment variable exists and is non-null, the timestamp line +in generated .config files is omitted. + +______________________________________________________________________ +Environment variables for '{allyes/allmod/allno/rand}config' + +KCONFIG_ALLCONFIG +-------------------------------------------------- +(partially based on lkml email from/by Rob Landley, re: miniconfig) +-------------------------------------------------- +The allyesconfig/allmodconfig/allnoconfig/randconfig variants can +also use the environment variable KCONFIG_ALLCONFIG as a flag or a +filename that contains config symbols that the user requires to be +set to a specific value. If KCONFIG_ALLCONFIG is used without a +filename, "make *config" checks for a file named +"all{yes/mod/no/random}.config" (corresponding to the *config command +that was used) for symbol values that are to be forced. If this file +is not found, it checks for a file named "all.config" to contain forced +values. + +This enables you to create "miniature" config (miniconfig) or custom +config files containing just the config symbols that you are interested +in. Then the kernel config system generates the full .config file, +including symbols of your miniconfig file. + +This 'KCONFIG_ALLCONFIG' file is a config file which contains +(usually a subset of all) preset config symbols. These variable +settings are still subject to normal dependency checks. + +Examples: + KCONFIG_ALLCONFIG=custom-notebook.config make allnoconfig +or + KCONFIG_ALLCONFIG=mini.config make allnoconfig +or + make KCONFIG_ALLCONFIG=mini.config allnoconfig + +These examples will disable most options (allnoconfig) but enable or +disable the options that are explicitly listed in the specified +mini-config files. + +______________________________________________________________________ +Environment variables for 'silentoldconfig' + +KCONFIG_NOSILENTUPDATE +-------------------------------------------------- +If this variable has a non-blank value, it prevents silent kernel +config udpates (requires explicit updates). + +KCONFIG_AUTOCONFIG +-------------------------------------------------- +This environment variable can be set to specify the path & name of the +"auto.conf" file. Its default value is "include/config/auto.conf". + +KCONFIG_AUTOHEADER +-------------------------------------------------- +This environment variable can be set to specify the path & name of the +"autoconf.h" (header) file. Its default value is "include/linux/autoconf.h". + ====================================================================== menuconfig @@ -60,10 +133,11 @@ Searching in menuconfig: /^hotplug - ______________________________________________________________________ -Color Themes for 'menuconfig' +User interface options for 'menuconfig' +MENUCONFIG_COLOR +-------------------------------------------------- It is possible to select different color themes using the variable MENUCONFIG_COLOR. To select a theme use: @@ -75,83 +149,13 @@ Available themes are: classic => theme with blue background. The classic look bluetitle => a LCD friendly version of classic. (default) -______________________________________________________________________ -Environment variables in 'menuconfig' - -KCONFIG_ALLCONFIG --------------------------------------------------- -(partially based on lkml email from/by Rob Landley, re: miniconfig) --------------------------------------------------- -The allyesconfig/allmodconfig/allnoconfig/randconfig variants can -also use the environment variable KCONFIG_ALLCONFIG as a flag or a -filename that contains config symbols that the user requires to be -set to a specific value. If KCONFIG_ALLCONFIG is used without a -filename, "make *config" checks for a file named -"all{yes/mod/no/random}.config" (corresponding to the *config command -that was used) for symbol values that are to be forced. If this file -is not found, it checks for a file named "all.config" to contain forced -values. - -This enables you to create "miniature" config (miniconfig) or custom -config files containing just the config symbols that you are interested -in. Then the kernel config system generates the full .config file, -including dependencies of your miniconfig file, based on the miniconfig -file. - -This 'KCONFIG_ALLCONFIG' file is a config file which contains -(usually a subset of all) preset config symbols. These variable -settings are still subject to normal dependency checks. - -Examples: - KCONFIG_ALLCONFIG=custom-notebook.config make allnoconfig -or - KCONFIG_ALLCONFIG=mini.config make allnoconfig -or - make KCONFIG_ALLCONFIG=mini.config allnoconfig - -These examples will disable most options (allnoconfig) but enable or -disable the options that are explicitly listed in the specified -mini-config files. - -KCONFIG_NOSILENTUPDATE --------------------------------------------------- -If this variable has a non-blank value, it prevents silent kernel -config udpates (requires explicit updates). - -KCONFIG_CONFIG --------------------------------------------------- -This environment variable can be used to specify a default kernel config -file name to override the default name of ".config". - -KCONFIG_OVERWRITECONFIG --------------------------------------------------- -If you set KCONFIG_OVERWRITECONFIG in the environment, Kconfig will not -break symlinks when .config is a symlink to somewhere else. - -KCONFIG_NOTIMESTAMP --------------------------------------------------- -If this environment variable exists and is non-null, the timestamp line -in generated .config files is omitted. - -KCONFIG_AUTOCONFIG --------------------------------------------------- -This environment variable can be set to specify the path & name of the -"auto.conf" file. Its default value is "include/config/auto.conf". - -KCONFIG_AUTOHEADER --------------------------------------------------- -This environment variable can be set to specify the path & name of the -"autoconf.h" (header) file. Its default value is "include/linux/autoconf.h". - -______________________________________________________________________ -menuconfig User Interface Options ----------------------------------------------------------------------- MENUCONFIG_MODE -------------------------------------------------- This mode shows all sub-menus in one large tree. Example: - MENUCONFIG_MODE=single_menu make menuconfig + make MENUCONFIG_MODE=single_menu menuconfig + ====================================================================== xconfig diff --git a/Documentation/kbuild/modules.txt b/Documentation/kbuild/modules.txt index b1096da953c8..0767cf69c69e 100644 --- a/Documentation/kbuild/modules.txt +++ b/Documentation/kbuild/modules.txt @@ -275,7 +275,7 @@ following files: KERNELDIR := /lib/modules/`uname -r`/build all:: - $(MAKE) -C $KERNELDIR M=`pwd` $@ + $(MAKE) -C $(KERNELDIR) M=`pwd` $@ # Module specific targets genbin: diff --git a/Documentation/kdump/kdump.txt b/Documentation/kdump/kdump.txt index 3f4bc840da8b..cab61d842259 100644 --- a/Documentation/kdump/kdump.txt +++ b/Documentation/kdump/kdump.txt @@ -108,7 +108,7 @@ There are two possible methods of using Kdump. 2) Or use the system kernel binary itself as dump-capture kernel and there is no need to build a separate dump-capture kernel. This is possible - only with the architecutres which support a relocatable kernel. As + only with the architectures which support a relocatable kernel. As of today, i386, x86_64, ppc64 and ia64 architectures support relocatable kernel. @@ -222,7 +222,7 @@ Dump-capture kernel config options (Arch Dependent, ia64) ---------------------------------------------------------- - No specific options are required to create a dump-capture kernel - for ia64, other than those specified in the arch idependent section + for ia64, other than those specified in the arch independent section above. This means that it is possible to use the system kernel as a dump-capture kernel if desired. diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index fd5cac013037..d08759aa0903 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -48,6 +48,7 @@ parameter is applicable: EFI EFI Partitioning (GPT) is enabled EIDE EIDE/ATAPI support is enabled. FB The frame buffer device is enabled. + GCOV GCOV profiling is enabled. HW Appropriate hardware is enabled. IA-64 IA-64 architecture is enabled. IMA Integrity measurement architecture is enabled. @@ -56,7 +57,6 @@ parameter is applicable: ISAPNP ISA PnP code is enabled. ISDN Appropriate ISDN support is enabled. JOY Appropriate joystick support is enabled. - KMEMTRACE kmemtrace is enabled. LIBATA Libata driver is enabled LP Printer support is enabled. LOOP Loopback device support is enabled. @@ -229,14 +229,6 @@ and is between 256 and 4096 characters. It is defined in the file to assume that this machine's pmtimer latches its value and always returns good values. - acpi.power_nocheck= [HW,ACPI] - Format: 1/0 enable/disable the check of power state. - On some bogus BIOS the _PSC object/_STA object of - power resource can't return the correct device power - state. In such case it is unneccessary to check its - power state again in power transition. - 1 : disable the power state check - acpi_sci= [HW,ACPI] ACPI System Control Interrupt trigger mode Format: { level | edge | high | low } @@ -329,11 +321,6 @@ and is between 256 and 4096 characters. It is defined in the file flushed before they will be reused, which is a lot of faster - amd_iommu_size= [HW,X86-64] - Define the size of the aperture for the AMD IOMMU - driver. Possible values are: - '32M', '64M' (default), '128M', '256M', '512M', '1G' - amijoy.map= [HW,JOY] Amiga joystick support Map of devices attached to JOY0DAT and JOY1DAT Format: , @@ -497,6 +484,13 @@ and is between 256 and 4096 characters. It is defined in the file Also note the kernel might malfunction if you disable some critical bits. + cmo_free_hint= [PPC] Format: { yes | no } + Specify whether pages are marked as being inactive + when they are freed. This is used in CMO environments + to determine OS memory pressure for page stealing by + a hypervisor. + Default: yes + code_bytes [X86] How many bytes of object code to print in an oops report. Range: 0 - 8192 @@ -545,6 +539,10 @@ and is between 256 and 4096 characters. It is defined in the file console=brl,ttyS0 For now, only VisioBraille is supported. + consoleblank= [KNL] The console blank (screen saver) timeout in + seconds. Defaults to 10*60 = 10mins. A value of 0 + disables the blank timer. + coredump_filter= [KNL] Change the default value for /proc//coredump_filter. @@ -646,6 +644,13 @@ and is between 256 and 4096 characters. It is defined in the file DMA-API debugging code disables itself because the architectural default is too low. + dma_debug_driver= + With this option the DMA-API debugging driver + filter feature can be enabled at boot time. Just + pass the driver to filter for as the parameter. + The filter can be disabled or changed to another + driver later using sysfs. + dscc4.setup= [NET] dtc3181e= [HW,SCSI] @@ -752,12 +757,25 @@ and is between 256 and 4096 characters. It is defined in the file ia64_pal_cache_flush instead of SAL_CACHE_FLUSH. ftrace=[tracer] - [ftrace] will set and start the specified tracer + [FTRACE] will set and start the specified tracer as early as possible in order to facilitate early boot debugging. ftrace_dump_on_oops - [ftrace] will dump the trace buffers on oops. + [FTRACE] will dump the trace buffers on oops. + + ftrace_filter=[function-list] + [FTRACE] Limit the functions traced by the function + tracer at boot up. function-list is a comma separated + list of functions. This list can be changed at run + time by the set_ftrace_filter file in the debugfs + tracing directory. + + ftrace_notrace=[function-list] + [FTRACE] Do not trace the functions specified in + function-list. This list can be changed at run time + by the set_ftrace_notrace file in the debugfs + tracing directory. gamecon.map[2|3]= [HW,JOY] Multisystem joystick and NES/SNES/PSX pad @@ -771,6 +789,12 @@ and is between 256 and 4096 characters. It is defined in the file Format: off | on default: on + gcov_persist= [GCOV] When non-zero (default), profiling data for + kernel modules is saved and remains accessible via + debugfs, even when the module is unloaded/reloaded. + When zero, profiling data is discarded and associated + debugfs files are removed at module unload time. + gdth= [HW,SCSI] See header of drivers/scsi/gdth.c. @@ -873,11 +897,8 @@ and is between 256 and 4096 characters. It is defined in the file ide-core.nodma= [HW] (E)IDE subsystem Format: =0.0 to prevent dma on hda, =0.1 hdb =1.0 hdc - .vlb_clock .pci_clock .noflush .noprobe .nowerr .cdrom - .chs .ignore_cable are additional options - See Documentation/ide/ide.txt. - - idebus= [HW] (E)IDE subsystem - VLB/PCI bus speed + .vlb_clock .pci_clock .noflush .nohpa .noprobe .nowerr + .cdrom .chs .ignore_cable are additional options See Documentation/ide/ide.txt. ide-pci-generic.all-generic-ide [HW] (E)IDE subsystem @@ -914,6 +935,12 @@ and is between 256 and 4096 characters. It is defined in the file Formt: { "sha1" | "md5" } default: "sha1" + ima_tcb [IMA] + Load a policy which meets the needs of the Trusted + Computing Base. This means IMA will measure all + programs exec'd, files mmap'd for exec, and all files + opened for read by uid=0. + in2000= [HW,SCSI] See header of drivers/scsi/in2000.c. @@ -971,6 +998,7 @@ and is between 256 and 4096 characters. It is defined in the file nomerge forcesac soft + pt [x86, IA64] io7= [HW] IO7 for Marvel based alpha systems See comment before marvel_specify_io7 in @@ -1054,24 +1082,19 @@ and is between 256 and 4096 characters. It is defined in the file use the HighMem zone if it exists, and the Normal zone if it does not. - kmemtrace.enable= [KNL,KMEMTRACE] Format: { yes | no } - Controls whether kmemtrace is enabled - at boot-time. - - kmemtrace.subbufs=n [KNL,KMEMTRACE] Overrides the number of - subbufs kmemtrace's relay channel has. Set this - higher than default (KMEMTRACE_N_SUBBUFS in code) if - you experience buffer overruns. - kgdboc= [HW] kgdb over consoles. Requires a tty driver that supports console polling. - (only serial suported for now) + (only serial supported for now) Format: [,baud] kmac= [MIPS] korina ethernet MAC address. Configure the RouterBoard 532 series on-chip Ethernet adapter MAC address. + kmemleak= [KNL] Boot-time kmemleak enable/disable + Valid arguments: on, off + Default: on + kstack=N [X86] Print N words from the kernel stack in oops dumps. @@ -1339,6 +1362,27 @@ and is between 256 and 4096 characters. It is defined in the file min_addr=nn[KMG] [KNL,BOOT,ia64] All physical memory below this physical address is ignored. + mini2440= [ARM,HW,KNL] + Format:[0..2][b][c][t] + Default: "0tb" + MINI2440 configuration specification: + 0 - The attached screen is the 3.5" TFT + 1 - The attached screen is the 7" TFT + 2 - The VGA Shield is attached (1024x768) + Leaving out the screen size parameter will not load + the TFT driver, and the framebuffer will be left + unconfigured. + b - Enable backlight. The TFT backlight pin will be + linked to the kernel VESA blanking code and a GPIO + LED. This parameter is not necessary when using the + VGA shield. + c - Enable the s3c camera interface. + t - Reserved for enabling touchscreen support. The + touchscreen support is not enabled in the mainstream + kernel as of 2.6.30, a preliminary port can be found + in the "bleeding edge" mini2440 support kernel at + http://repo.or.cz/w/linux-2.6/mini2440.git + mminit_loglevel= [KNL] When CONFIG_DEBUG_MEMORY_INIT is set, this parameter allows control of the logging verbosity for @@ -1380,6 +1424,16 @@ and is between 256 and 4096 characters. It is defined in the file mtdparts= [MTD] See drivers/mtd/cmdlinepart.c. + onenand.bdry= [HW,MTD] Flex-OneNAND Boundary Configuration + + Format: [die0_boundary][,die0_lock][,die1_boundary][,die1_lock] + + boundary - index of last SLC block on Flex-OneNAND. + The remaining blocks are configured as MLC blocks. + lock - Configure if Flex-OneNAND boundary should be locked. + Once locked, the boundary cannot be changed. + 1 indicates lock status, 0 indicates unlock status. + mtdset= [ARM] ARM/S3C2412 JIVE boot control @@ -1390,7 +1444,7 @@ and is between 256 and 4096 characters. It is defined in the file ('y', default) or cooked coordinates ('n') mtrr_chunk_size=nn[KMG] [X86] - used for mtrr cleanup. It is largest continous chunk + used for mtrr cleanup. It is largest continuous chunk that could hold holes aka. UC entries. mtrr_gran_size=nn[KMG] [X86] @@ -1575,6 +1629,9 @@ and is between 256 and 4096 characters. It is defined in the file noinitrd [RAM] Tells the kernel not to load any configured initial RAM disk. + nointremap [X86-64, Intel-IOMMU] Do not enable interrupt + remapping. + nointroute [IA-64] nojitter [IA64] Disables jitter checking for ITC timers. @@ -1660,6 +1717,14 @@ and is between 256 and 4096 characters. It is defined in the file oprofile.timer= [HW] Use timer interrupt instead of performance counters + oprofile.cpu_type= Force an oprofile cpu type + This might be useful if you have an older oprofile + userland or if you want common events. + Format: { archperfmon } + archperfmon: [X86] Force use of architectural + perfmon on Intel CPUs instead of the + CPU specific event set. + osst= [HW,SCSI] SCSI Tape Driver Format: , See also Documentation/scsi/st.txt. @@ -1735,6 +1800,9 @@ and is between 256 and 4096 characters. It is defined in the file root domains (aka PCI segments, in ACPI-speak). nommconf [X86] Disable use of MMCONFIG for PCI Configuration + check_enable_amd_mmconf [X86] check for and enable + properly configured MMIO access to PCI + config space on AMD family 10h CPU nomsi [MSI] If the PCI_MSI kernel config parameter is enabled, this kernel boot option can be used to disable the use of MSI interrupts system-wide. @@ -1824,6 +1892,12 @@ and is between 256 and 4096 characters. It is defined in the file PAGE_SIZE is used as alignment. PCI-PCI bridge can be specified, if resource windows need to be expanded. + ecrc= Enable/disable PCIe ECRC (transaction layer + end-to-end CRC checking). + bios: Use BIOS/firmware settings. This is the + the default. + off: Turn ECRC off + on: Turn ECRC on. pcie_aspm= [PCIE] Forcibly enable or disable PCIe Active State Power Management. diff --git a/Documentation/kmemcheck.txt b/Documentation/kmemcheck.txt new file mode 100644 index 000000000000..363044609dad --- /dev/null +++ b/Documentation/kmemcheck.txt @@ -0,0 +1,773 @@ +GETTING STARTED WITH KMEMCHECK +============================== + +Vegard Nossum + + +Contents +======== +0. Introduction +1. Downloading +2. Configuring and compiling +3. How to use +3.1. Booting +3.2. Run-time enable/disable +3.3. Debugging +3.4. Annotating false positives +4. Reporting errors +5. Technical description + + +0. Introduction +=============== + +kmemcheck is a debugging feature for the Linux Kernel. More specifically, it +is a dynamic checker that detects and warns about some uses of uninitialized +memory. + +Userspace programmers might be familiar with Valgrind's memcheck. The main +difference between memcheck and kmemcheck is that memcheck works for userspace +programs only, and kmemcheck works for the kernel only. The implementations +are of course vastly different. Because of this, kmemcheck is not as accurate +as memcheck, but it turns out to be good enough in practice to discover real +programmer errors that the compiler is not able to find through static +analysis. + +Enabling kmemcheck on a kernel will probably slow it down to the extent that +the machine will not be usable for normal workloads such as e.g. an +interactive desktop. kmemcheck will also cause the kernel to use about twice +as much memory as normal. For this reason, kmemcheck is strictly a debugging +feature. + + +1. Downloading +============== + +kmemcheck can only be downloaded using git. If you want to write patches +against the current code, you should use the kmemcheck development branch of +the tip tree. It is also possible to use the linux-next tree, which also +includes the latest version of kmemcheck. + +Assuming that you've already cloned the linux-2.6.git repository, all you +have to do is add the -tip tree as a remote, like this: + + $ git remote add tip git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip.git + +To actually download the tree, fetch the remote: + + $ git fetch tip + +And to check out a new local branch with the kmemcheck code: + + $ git checkout -b kmemcheck tip/kmemcheck + +General instructions for the -tip tree can be found here: +http://people.redhat.com/mingo/tip.git/readme.txt + + +2. Configuring and compiling +============================ + +kmemcheck only works for the x86 (both 32- and 64-bit) platform. A number of +configuration variables must have specific settings in order for the kmemcheck +menu to even appear in "menuconfig". These are: + + o CONFIG_CC_OPTIMIZE_FOR_SIZE=n + + This option is located under "General setup" / "Optimize for size". + + Without this, gcc will use certain optimizations that usually lead to + false positive warnings from kmemcheck. An example of this is a 16-bit + field in a struct, where gcc may load 32 bits, then discard the upper + 16 bits. kmemcheck sees only the 32-bit load, and may trigger a + warning for the upper 16 bits (if they're uninitialized). + + o CONFIG_SLAB=y or CONFIG_SLUB=y + + This option is located under "General setup" / "Choose SLAB + allocator". + + o CONFIG_FUNCTION_TRACER=n + + This option is located under "Kernel hacking" / "Tracers" / "Kernel + Function Tracer" + + When function tracing is compiled in, gcc emits a call to another + function at the beginning of every function. This means that when the + page fault handler is called, the ftrace framework will be called + before kmemcheck has had a chance to handle the fault. If ftrace then + modifies memory that was tracked by kmemcheck, the result is an + endless recursive page fault. + + o CONFIG_DEBUG_PAGEALLOC=n + + This option is located under "Kernel hacking" / "Debug page memory + allocations". + +In addition, I highly recommend turning on CONFIG_DEBUG_INFO=y. This is also +located under "Kernel hacking". With this, you will be able to get line number +information from the kmemcheck warnings, which is extremely valuable in +debugging a problem. This option is not mandatory, however, because it slows +down the compilation process and produces a much bigger kernel image. + +Now the kmemcheck menu should be visible (under "Kernel hacking" / "kmemcheck: +trap use of uninitialized memory"). Here follows a description of the +kmemcheck configuration variables: + + o CONFIG_KMEMCHECK + + This must be enabled in order to use kmemcheck at all... + + o CONFIG_KMEMCHECK_[DISABLED | ENABLED | ONESHOT]_BY_DEFAULT + + This option controls the status of kmemcheck at boot-time. "Enabled" + will enable kmemcheck right from the start, "disabled" will boot the + kernel as normal (but with the kmemcheck code compiled in, so it can + be enabled at run-time after the kernel has booted), and "one-shot" is + a special mode which will turn kmemcheck off automatically after + detecting the first use of uninitialized memory. + + If you are using kmemcheck to actively debug a problem, then you + probably want to choose "enabled" here. + + The one-shot mode is mostly useful in automated test setups because it + can prevent floods of warnings and increase the chances of the machine + surviving in case something is really wrong. In other cases, the one- + shot mode could actually be counter-productive because it would turn + itself off at the very first error -- in the case of a false positive + too -- and this would come in the way of debugging the specific + problem you were interested in. + + If you would like to use your kernel as normal, but with a chance to + enable kmemcheck in case of some problem, it might be a good idea to + choose "disabled" here. When kmemcheck is disabled, most of the run- + time overhead is not incurred, and the kernel will be almost as fast + as normal. + + o CONFIG_KMEMCHECK_QUEUE_SIZE + + Select the maximum number of error reports to store in an internal + (fixed-size) buffer. Since errors can occur virtually anywhere and in + any context, we need a temporary storage area which is guaranteed not + to generate any other page faults when accessed. The queue will be + emptied as soon as a tasklet may be scheduled. If the queue is full, + new error reports will be lost. + + The default value of 64 is probably fine. If some code produces more + than 64 errors within an irqs-off section, then the code is likely to + produce many, many more, too, and these additional reports seldom give + any more information (the first report is usually the most valuable + anyway). + + This number might have to be adjusted if you are not using serial + console or similar to capture the kernel log. If you are using the + "dmesg" command to save the log, then getting a lot of kmemcheck + warnings might overflow the kernel log itself, and the earlier reports + will get lost in that way instead. Try setting this to 10 or so on + such a setup. + + o CONFIG_KMEMCHECK_SHADOW_COPY_SHIFT + + Select the number of shadow bytes to save along with each entry of the + error-report queue. These bytes indicate what parts of an allocation + are initialized, uninitialized, etc. and will be displayed when an + error is detected to help the debugging of a particular problem. + + The number entered here is actually the logarithm of the number of + bytes that will be saved. So if you pick for example 5 here, kmemcheck + will save 2^5 = 32 bytes. + + The default value should be fine for debugging most problems. It also + fits nicely within 80 columns. + + o CONFIG_KMEMCHECK_PARTIAL_OK + + This option (when enabled) works around certain GCC optimizations that + produce 32-bit reads from 16-bit variables where the upper 16 bits are + thrown away afterwards. + + The default value (enabled) is recommended. This may of course hide + some real errors, but disabling it would probably produce a lot of + false positives. + + o CONFIG_KMEMCHECK_BITOPS_OK + + This option silences warnings that would be generated for bit-field + accesses where not all the bits are initialized at the same time. This + may also hide some real bugs. + + This option is probably obsolete, or it should be replaced with + the kmemcheck-/bitfield-annotations for the code in question. The + default value is therefore fine. + +Now compile the kernel as usual. + + +3. How to use +============= + +3.1. Booting +============ + +First some information about the command-line options. There is only one +option specific to kmemcheck, and this is called "kmemcheck". It can be used +to override the default mode as chosen by the CONFIG_KMEMCHECK_*_BY_DEFAULT +option. Its possible settings are: + + o kmemcheck=0 (disabled) + o kmemcheck=1 (enabled) + o kmemcheck=2 (one-shot mode) + +If SLUB debugging has been enabled in the kernel, it may take precedence over +kmemcheck in such a way that the slab caches which are under SLUB debugging +will not be tracked by kmemcheck. In order to ensure that this doesn't happen +(even though it shouldn't by default), use SLUB's boot option "slub_debug", +like this: slub_debug=- + +In fact, this option may also be used for fine-grained control over SLUB vs. +kmemcheck. For example, if the command line includes "kmemcheck=1 +slub_debug=,dentry", then SLUB debugging will be used only for the "dentry" +slab cache, and with kmemcheck tracking all the other caches. This is advanced +usage, however, and is not generally recommended. + + +3.2. Run-time enable/disable +============================ + +When the kernel has booted, it is possible to enable or disable kmemcheck at +run-time. WARNING: This feature is still experimental and may cause false +positive warnings to appear. Therefore, try not to use this. If you find that +it doesn't work properly (e.g. you see an unreasonable amount of warnings), I +will be happy to take bug reports. + +Use the file /proc/sys/kernel/kmemcheck for this purpose, e.g.: + + $ echo 0 > /proc/sys/kernel/kmemcheck # disables kmemcheck + +The numbers are the same as for the kmemcheck= command-line option. + + +3.3. Debugging +============== + +A typical report will look something like this: + +WARNING: kmemcheck: Caught 32-bit read from uninitialized memory (ffff88003e4a2024) +80000000000000000000000000000000000000000088ffff0000000000000000 + i i i i u u u u i i i i i i i i u u u u u u u u u u u u u u u u + ^ + +Pid: 1856, comm: ntpdate Not tainted 2.6.29-rc5 #264 945P-A +RIP: 0010:[] [] __dequeue_signal+0xc8/0x190 +RSP: 0018:ffff88003cdf7d98 EFLAGS: 00210002 +RAX: 0000000000000030 RBX: ffff88003d4ea968 RCX: 0000000000000009 +RDX: ffff88003e5d6018 RSI: ffff88003e5d6024 RDI: ffff88003cdf7e84 +RBP: ffff88003cdf7db8 R08: ffff88003e5d6000 R09: 0000000000000000 +R10: 0000000000000080 R11: 0000000000000000 R12: 000000000000000e +R13: ffff88003cdf7e78 R14: ffff88003d530710 R15: ffff88003d5a98c8 +FS: 0000000000000000(0000) GS:ffff880001982000(0063) knlGS:00000 +CS: 0010 DS: 002b ES: 002b CR0: 0000000080050033 +CR2: ffff88003f806ea0 CR3: 000000003c036000 CR4: 00000000000006a0 +DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 +DR3: 0000000000000000 DR6: 00000000ffff4ff0 DR7: 0000000000000400 + [] dequeue_signal+0x8e/0x170 + [] get_signal_to_deliver+0x98/0x390 + [] do_notify_resume+0xad/0x7d0 + [] int_signal+0x12/0x17 + [] 0xffffffffffffffff + +The single most valuable information in this report is the RIP (or EIP on 32- +bit) value. This will help us pinpoint exactly which instruction that caused +the warning. + +If your kernel was compiled with CONFIG_DEBUG_INFO=y, then all we have to do +is give this address to the addr2line program, like this: + + $ addr2line -e vmlinux -i ffffffff8104ede8 + arch/x86/include/asm/string_64.h:12 + include/asm-generic/siginfo.h:287 + kernel/signal.c:380 + kernel/signal.c:410 + +The "-e vmlinux" tells addr2line which file to look in. IMPORTANT: This must +be the vmlinux of the kernel that produced the warning in the first place! If +not, the line number information will almost certainly be wrong. + +The "-i" tells addr2line to also print the line numbers of inlined functions. +In this case, the flag was very important, because otherwise, it would only +have printed the first line, which is just a call to memcpy(), which could be +called from a thousand places in the kernel, and is therefore not very useful. +These inlined functions would not show up in the stack trace above, simply +because the kernel doesn't load the extra debugging information. This +technique can of course be used with ordinary kernel oopses as well. + +In this case, it's the caller of memcpy() that is interesting, and it can be +found in include/asm-generic/siginfo.h, line 287: + +281 static inline void copy_siginfo(struct siginfo *to, struct siginfo *from) +282 { +283 if (from->si_code < 0) +284 memcpy(to, from, sizeof(*to)); +285 else +286 /* _sigchld is currently the largest know union member */ +287 memcpy(to, from, __ARCH_SI_PREAMBLE_SIZE + sizeof(from->_sifields._sigchld)); +288 } + +Since this was a read (kmemcheck usually warns about reads only, though it can +warn about writes to unallocated or freed memory as well), it was probably the +"from" argument which contained some uninitialized bytes. Following the chain +of calls, we move upwards to see where "from" was allocated or initialized, +kernel/signal.c, line 380: + +359 static void collect_signal(int sig, struct sigpending *list, siginfo_t *info) +360 { +... +367 list_for_each_entry(q, &list->list, list) { +368 if (q->info.si_signo == sig) { +369 if (first) +370 goto still_pending; +371 first = q; +... +377 if (first) { +378 still_pending: +379 list_del_init(&first->list); +380 copy_siginfo(info, &first->info); +381 __sigqueue_free(first); +... +392 } +393 } + +Here, it is &first->info that is being passed on to copy_siginfo(). The +variable "first" was found on a list -- passed in as the second argument to +collect_signal(). We continue our journey through the stack, to figure out +where the item on "list" was allocated or initialized. We move to line 410: + +395 static int __dequeue_signal(struct sigpending *pending, sigset_t *mask, +396 siginfo_t *info) +397 { +... +410 collect_signal(sig, pending, info); +... +414 } + +Now we need to follow the "pending" pointer, since that is being passed on to +collect_signal() as "list". At this point, we've run out of lines from the +"addr2line" output. Not to worry, we just paste the next addresses from the +kmemcheck stack dump, i.e.: + + [] dequeue_signal+0x8e/0x170 + [] get_signal_to_deliver+0x98/0x390 + [] do_notify_resume+0xad/0x7d0 + [] int_signal+0x12/0x17 + + $ addr2line -e vmlinux -i ffffffff8104f04e ffffffff81050bd8 \ + ffffffff8100b87d ffffffff8100c7b5 + kernel/signal.c:446 + kernel/signal.c:1806 + arch/x86/kernel/signal.c:805 + arch/x86/kernel/signal.c:871 + arch/x86/kernel/entry_64.S:694 + +Remember that since these addresses were found on the stack and not as the +RIP value, they actually point to the _next_ instruction (they are return +addresses). This becomes obvious when we look at the code for line 446: + +422 int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info) +423 { +... +431 signr = __dequeue_signal(&tsk->signal->shared_pending, +432 mask, info); +433 /* +434 * itimer signal ? +435 * +436 * itimers are process shared and we restart periodic +437 * itimers in the signal delivery path to prevent DoS +438 * attacks in the high resolution timer case. This is +439 * compliant with the old way of self restarting +440 * itimers, as the SIGALRM is a legacy signal and only +441 * queued once. Changing the restart behaviour to +442 * restart the timer in the signal dequeue path is +443 * reducing the timer noise on heavy loaded !highres +444 * systems too. +445 */ +446 if (unlikely(signr == SIGALRM)) { +... +489 } + +So instead of looking at 446, we should be looking at 431, which is the line +that executes just before 446. Here we see that what we are looking for is +&tsk->signal->shared_pending. + +Our next task is now to figure out which function that puts items on this +"shared_pending" list. A crude, but efficient tool, is git grep: + + $ git grep -n 'shared_pending' kernel/ + ... + kernel/signal.c:828: pending = group ? &t->signal->shared_pending : &t->pending; + kernel/signal.c:1339: pending = group ? &t->signal->shared_pending : &t->pending; + ... + +There were more results, but none of them were related to list operations, +and these were the only assignments. We inspect the line numbers more closely +and find that this is indeed where items are being added to the list: + +816 static int send_signal(int sig, struct siginfo *info, struct task_struct *t, +817 int group) +818 { +... +828 pending = group ? &t->signal->shared_pending : &t->pending; +... +851 q = __sigqueue_alloc(t, GFP_ATOMIC, (sig < SIGRTMIN && +852 (is_si_special(info) || +853 info->si_code >= 0))); +854 if (q) { +855 list_add_tail(&q->list, &pending->list); +... +890 } + +and: + +1309 int send_sigqueue(struct sigqueue *q, struct task_struct *t, int group) +1310 { +.... +1339 pending = group ? &t->signal->shared_pending : &t->pending; +1340 list_add_tail(&q->list, &pending->list); +.... +1347 } + +In the first case, the list element we are looking for, "q", is being returned +from the function __sigqueue_alloc(), which looks like an allocation function. +Let's take a look at it: + +187 static struct sigqueue *__sigqueue_alloc(struct task_struct *t, gfp_t flags, +188 int override_rlimit) +189 { +190 struct sigqueue *q = NULL; +191 struct user_struct *user; +192 +193 /* +194 * We won't get problems with the target's UID changing under us +195 * because changing it requires RCU be used, and if t != current, the +196 * caller must be holding the RCU readlock (by way of a spinlock) and +197 * we use RCU protection here +198 */ +199 user = get_uid(__task_cred(t)->user); +200 atomic_inc(&user->sigpending); +201 if (override_rlimit || +202 atomic_read(&user->sigpending) <= +203 t->signal->rlim[RLIMIT_SIGPENDING].rlim_cur) +204 q = kmem_cache_alloc(sigqueue_cachep, flags); +205 if (unlikely(q == NULL)) { +206 atomic_dec(&user->sigpending); +207 free_uid(user); +208 } else { +209 INIT_LIST_HEAD(&q->list); +210 q->flags = 0; +211 q->user = user; +212 } +213 +214 return q; +215 } + +We see that this function initializes q->list, q->flags, and q->user. It seems +that now is the time to look at the definition of "struct sigqueue", e.g.: + +14 struct sigqueue { +15 struct list_head list; +16 int flags; +17 siginfo_t info; +18 struct user_struct *user; +19 }; + +And, you might remember, it was a memcpy() on &first->info that caused the +warning, so this makes perfect sense. It also seems reasonable to assume that +it is the caller of __sigqueue_alloc() that has the responsibility of filling +out (initializing) this member. + +But just which fields of the struct were uninitialized? Let's look at +kmemcheck's report again: + +WARNING: kmemcheck: Caught 32-bit read from uninitialized memory (ffff88003e4a2024) +80000000000000000000000000000000000000000088ffff0000000000000000 + i i i i u u u u i i i i i i i i u u u u u u u u u u u u u u u u + ^ + +These first two lines are the memory dump of the memory object itself, and the +shadow bytemap, respectively. The memory object itself is in this case +&first->info. Just beware that the start of this dump is NOT the start of the +object itself! The position of the caret (^) corresponds with the address of +the read (ffff88003e4a2024). + +The shadow bytemap dump legend is as follows: + + i - initialized + u - uninitialized + a - unallocated (memory has been allocated by the slab layer, but has not + yet been handed off to anybody) + f - freed (memory has been allocated by the slab layer, but has been freed + by the previous owner) + +In order to figure out where (relative to the start of the object) the +uninitialized memory was located, we have to look at the disassembly. For +that, we'll need the RIP address again: + +RIP: 0010:[] [] __dequeue_signal+0xc8/0x190 + + $ objdump -d --no-show-raw-insn vmlinux | grep -C 8 ffffffff8104ede8: + ffffffff8104edc8: mov %r8,0x8(%r8) + ffffffff8104edcc: test %r10d,%r10d + ffffffff8104edcf: js ffffffff8104ee88 <__dequeue_signal+0x168> + ffffffff8104edd5: mov %rax,%rdx + ffffffff8104edd8: mov $0xc,%ecx + ffffffff8104eddd: mov %r13,%rdi + ffffffff8104ede0: mov $0x30,%eax + ffffffff8104ede5: mov %rdx,%rsi + ffffffff8104ede8: rep movsl %ds:(%rsi),%es:(%rdi) + ffffffff8104edea: test $0x2,%al + ffffffff8104edec: je ffffffff8104edf0 <__dequeue_signal+0xd0> + ffffffff8104edee: movsw %ds:(%rsi),%es:(%rdi) + ffffffff8104edf0: test $0x1,%al + ffffffff8104edf2: je ffffffff8104edf5 <__dequeue_signal+0xd5> + ffffffff8104edf4: movsb %ds:(%rsi),%es:(%rdi) + ffffffff8104edf5: mov %r8,%rdi + ffffffff8104edf8: callq ffffffff8104de60 <__sigqueue_free> + +As expected, it's the "rep movsl" instruction from the memcpy() that causes +the warning. We know about REP MOVSL that it uses the register RCX to count +the number of remaining iterations. By taking a look at the register dump +again (from the kmemcheck report), we can figure out how many bytes were left +to copy: + +RAX: 0000000000000030 RBX: ffff88003d4ea968 RCX: 0000000000000009 + +By looking at the disassembly, we also see that %ecx is being loaded with the +value $0xc just before (ffffffff8104edd8), so we are very lucky. Keep in mind +that this is the number of iterations, not bytes. And since this is a "long" +operation, we need to multiply by 4 to get the number of bytes. So this means +that the uninitialized value was encountered at 4 * (0xc - 0x9) = 12 bytes +from the start of the object. + +We can now try to figure out which field of the "struct siginfo" that was not +initialized. This is the beginning of the struct: + +40 typedef struct siginfo { +41 int si_signo; +42 int si_errno; +43 int si_code; +44 +45 union { +.. +92 } _sifields; +93 } siginfo_t; + +On 64-bit, the int is 4 bytes long, so it must the the union member that has +not been initialized. We can verify this using gdb: + + $ gdb vmlinux + ... + (gdb) p &((struct siginfo *) 0)->_sifields + $1 = (union {...} *) 0x10 + +Actually, it seems that the union member is located at offset 0x10 -- which +means that gcc has inserted 4 bytes of padding between the members si_code +and _sifields. We can now get a fuller picture of the memory dump: + + _----------------------------=> si_code + / _--------------------=> (padding) + | / _------------=> _sifields(._kill._pid) + | | / _----=> _sifields(._kill._uid) + | | | / +-------|-------|-------|-------| +80000000000000000000000000000000000000000088ffff0000000000000000 + i i i i u u u u i i i i i i i i u u u u u u u u u u u u u u u u + +This allows us to realize another important fact: si_code contains the value +0x80. Remember that x86 is little endian, so the first 4 bytes "80000000" are +really the number 0x00000080. With a bit of research, we find that this is +actually the constant SI_KERNEL defined in include/asm-generic/siginfo.h: + +144 #define SI_KERNEL 0x80 /* sent by the kernel from somewhere */ + +This macro is used in exactly one place in the x86 kernel: In send_signal() +in kernel/signal.c: + +816 static int send_signal(int sig, struct siginfo *info, struct task_struct *t, +817 int group) +818 { +... +828 pending = group ? &t->signal->shared_pending : &t->pending; +... +851 q = __sigqueue_alloc(t, GFP_ATOMIC, (sig < SIGRTMIN && +852 (is_si_special(info) || +853 info->si_code >= 0))); +854 if (q) { +855 list_add_tail(&q->list, &pending->list); +856 switch ((unsigned long) info) { +... +865 case (unsigned long) SEND_SIG_PRIV: +866 q->info.si_signo = sig; +867 q->info.si_errno = 0; +868 q->info.si_code = SI_KERNEL; +869 q->info.si_pid = 0; +870 q->info.si_uid = 0; +871 break; +... +890 } + +Not only does this match with the .si_code member, it also matches the place +we found earlier when looking for where siginfo_t objects are enqueued on the +"shared_pending" list. + +So to sum up: It seems that it is the padding introduced by the compiler +between two struct fields that is uninitialized, and this gets reported when +we do a memcpy() on the struct. This means that we have identified a false +positive warning. + +Normally, kmemcheck will not report uninitialized accesses in memcpy() calls +when both the source and destination addresses are tracked. (Instead, we copy +the shadow bytemap as well). In this case, the destination address clearly +was not tracked. We can dig a little deeper into the stack trace from above: + + arch/x86/kernel/signal.c:805 + arch/x86/kernel/signal.c:871 + arch/x86/kernel/entry_64.S:694 + +And we clearly see that the destination siginfo object is located on the +stack: + +782 static void do_signal(struct pt_regs *regs) +783 { +784 struct k_sigaction ka; +785 siginfo_t info; +... +804 signr = get_signal_to_deliver(&info, &ka, regs, NULL); +... +854 } + +And this &info is what eventually gets passed to copy_siginfo() as the +destination argument. + +Now, even though we didn't find an actual error here, the example is still a +good one, because it shows how one would go about to find out what the report +was all about. + + +3.4. Annotating false positives +=============================== + +There are a few different ways to make annotations in the source code that +will keep kmemcheck from checking and reporting certain allocations. Here +they are: + + o __GFP_NOTRACK_FALSE_POSITIVE + + This flag can be passed to kmalloc() or kmem_cache_alloc() (therefore + also to other functions that end up calling one of these) to indicate + that the allocation should not be tracked because it would lead to + a false positive report. This is a "big hammer" way of silencing + kmemcheck; after all, even if the false positive pertains to + particular field in a struct, for example, we will now lose the + ability to find (real) errors in other parts of the same struct. + + Example: + + /* No warnings will ever trigger on accessing any part of x */ + x = kmalloc(sizeof *x, GFP_KERNEL | __GFP_NOTRACK_FALSE_POSITIVE); + + o kmemcheck_bitfield_begin(name)/kmemcheck_bitfield_end(name) and + kmemcheck_annotate_bitfield(ptr, name) + + The first two of these three macros can be used inside struct + definitions to signal, respectively, the beginning and end of a + bitfield. Additionally, this will assign the bitfield a name, which + is given as an argument to the macros. + + Having used these markers, one can later use + kmemcheck_annotate_bitfield() at the point of allocation, to indicate + which parts of the allocation is part of a bitfield. + + Example: + + struct foo { + int x; + + kmemcheck_bitfield_begin(flags); + int flag_a:1; + int flag_b:1; + kmemcheck_bitfield_end(flags); + + int y; + }; + + struct foo *x = kmalloc(sizeof *x); + + /* No warnings will trigger on accessing the bitfield of x */ + kmemcheck_annotate_bitfield(x, flags); + + Note that kmemcheck_annotate_bitfield() can be used even before the + return value of kmalloc() is checked -- in other words, passing NULL + as the first argument is legal (and will do nothing). + + +4. Reporting errors +=================== + +As we have seen, kmemcheck will produce false positive reports. Therefore, it +is not very wise to blindly post kmemcheck warnings to mailing lists and +maintainers. Instead, I encourage maintainers and developers to find errors +in their own code. If you get a warning, you can try to work around it, try +to figure out if it's a real error or not, or simply ignore it. Most +developers know their own code and will quickly and efficiently determine the +root cause of a kmemcheck report. This is therefore also the most efficient +way to work with kmemcheck. + +That said, we (the kmemcheck maintainers) will always be on the lookout for +false positives that we can annotate and silence. So whatever you find, +please drop us a note privately! Kernel configs and steps to reproduce (if +available) are of course a great help too. + +Happy hacking! + + +5. Technical description +======================== + +kmemcheck works by marking memory pages non-present. This means that whenever +somebody attempts to access the page, a page fault is generated. The page +fault handler notices that the page was in fact only hidden, and so it calls +on the kmemcheck code to make further investigations. + +When the investigations are completed, kmemcheck "shows" the page by marking +it present (as it would be under normal circumstances). This way, the +interrupted code can continue as usual. + +But after the instruction has been executed, we should hide the page again, so +that we can catch the next access too! Now kmemcheck makes use of a debugging +feature of the processor, namely single-stepping. When the processor has +finished the one instruction that generated the memory access, a debug +exception is raised. From here, we simply hide the page again and continue +execution, this time with the single-stepping feature turned off. + +kmemcheck requires some assistance from the memory allocator in order to work. +The memory allocator needs to + + 1. Tell kmemcheck about newly allocated pages and pages that are about to + be freed. This allows kmemcheck to set up and tear down the shadow memory + for the pages in question. The shadow memory stores the status of each + byte in the allocation proper, e.g. whether it is initialized or + uninitialized. + + 2. Tell kmemcheck which parts of memory should be marked uninitialized. + There are actually a few more states, such as "not yet allocated" and + "recently freed". + +If a slab cache is set up using the SLAB_NOTRACK flag, it will never return +memory that can take page faults because of kmemcheck. + +If a slab cache is NOT set up using the SLAB_NOTRACK flag, callers can still +request memory with the __GFP_NOTRACK or __GFP_NOTRACK_FALSE_POSITIVE flags. +This does not prevent the page faults from occurring, however, but marks the +object in question as being initialized so that no warnings will ever be +produced for this object. + +Currently, the SLAB and SLUB allocators are supported by kmemcheck. diff --git a/Documentation/kmemleak.txt b/Documentation/kmemleak.txt new file mode 100644 index 000000000000..0112da3b9ab8 --- /dev/null +++ b/Documentation/kmemleak.txt @@ -0,0 +1,142 @@ +Kernel Memory Leak Detector +=========================== + +Introduction +------------ + +Kmemleak provides a way of detecting possible kernel memory leaks in a +way similar to a tracing garbage collector +(http://en.wikipedia.org/wiki/Garbage_collection_%28computer_science%29#Tracing_garbage_collectors), +with the difference that the orphan objects are not freed but only +reported via /sys/kernel/debug/kmemleak. A similar method is used by the +Valgrind tool (memcheck --leak-check) to detect the memory leaks in +user-space applications. + +Usage +----- + +CONFIG_DEBUG_KMEMLEAK in "Kernel hacking" has to be enabled. A kernel +thread scans the memory every 10 minutes (by default) and prints any new +unreferenced objects found. To trigger an intermediate scan and display +all the possible memory leaks: + + # mount -t debugfs nodev /sys/kernel/debug/ + # cat /sys/kernel/debug/kmemleak + +Note that the orphan objects are listed in the order they were allocated +and one object at the beginning of the list may cause other subsequent +objects to be reported as orphan. + +Memory scanning parameters can be modified at run-time by writing to the +/sys/kernel/debug/kmemleak file. The following parameters are supported: + + off - disable kmemleak (irreversible) + stack=on - enable the task stacks scanning + stack=off - disable the tasks stacks scanning + scan=on - start the automatic memory scanning thread + scan=off - stop the automatic memory scanning thread + scan= - set the automatic memory scanning period in seconds (0 + to disable it) + +Kmemleak can also be disabled at boot-time by passing "kmemleak=off" on +the kernel command line. + +Basic Algorithm +--------------- + +The memory allocations via kmalloc, vmalloc, kmem_cache_alloc and +friends are traced and the pointers, together with additional +information like size and stack trace, are stored in a prio search tree. +The corresponding freeing function calls are tracked and the pointers +removed from the kmemleak data structures. + +An allocated block of memory is considered orphan if no pointer to its +start address or to any location inside the block can be found by +scanning the memory (including saved registers). This means that there +might be no way for the kernel to pass the address of the allocated +block to a freeing function and therefore the block is considered a +memory leak. + +The scanning algorithm steps: + + 1. mark all objects as white (remaining white objects will later be + considered orphan) + 2. scan the memory starting with the data section and stacks, checking + the values against the addresses stored in the prio search tree. If + a pointer to a white object is found, the object is added to the + gray list + 3. scan the gray objects for matching addresses (some white objects + can become gray and added at the end of the gray list) until the + gray set is finished + 4. the remaining white objects are considered orphan and reported via + /sys/kernel/debug/kmemleak + +Some allocated memory blocks have pointers stored in the kernel's +internal data structures and they cannot be detected as orphans. To +avoid this, kmemleak can also store the number of values pointing to an +address inside the block address range that need to be found so that the +block is not considered a leak. One example is __vmalloc(). + +Kmemleak API +------------ + +See the include/linux/kmemleak.h header for the functions prototype. + +kmemleak_init - initialize kmemleak +kmemleak_alloc - notify of a memory block allocation +kmemleak_free - notify of a memory block freeing +kmemleak_not_leak - mark an object as not a leak +kmemleak_ignore - do not scan or report an object as leak +kmemleak_scan_area - add scan areas inside a memory block +kmemleak_no_scan - do not scan a memory block +kmemleak_erase - erase an old value in a pointer variable +kmemleak_alloc_recursive - as kmemleak_alloc but checks the recursiveness +kmemleak_free_recursive - as kmemleak_free but checks the recursiveness + +Dealing with false positives/negatives +-------------------------------------- + +The false negatives are real memory leaks (orphan objects) but not +reported by kmemleak because values found during the memory scanning +point to such objects. To reduce the number of false negatives, kmemleak +provides the kmemleak_ignore, kmemleak_scan_area, kmemleak_no_scan and +kmemleak_erase functions (see above). The task stacks also increase the +amount of false negatives and their scanning is not enabled by default. + +The false positives are objects wrongly reported as being memory leaks +(orphan). For objects known not to be leaks, kmemleak provides the +kmemleak_not_leak function. The kmemleak_ignore could also be used if +the memory block is known not to contain other pointers and it will no +longer be scanned. + +Some of the reported leaks are only transient, especially on SMP +systems, because of pointers temporarily stored in CPU registers or +stacks. Kmemleak defines MSECS_MIN_AGE (defaulting to 1000) representing +the minimum age of an object to be reported as a memory leak. + +Limitations and Drawbacks +------------------------- + +The main drawback is the reduced performance of memory allocation and +freeing. To avoid other penalties, the memory scanning is only performed +when the /sys/kernel/debug/kmemleak file is read. Anyway, this tool is +intended for debugging purposes where the performance might not be the +most important requirement. + +To keep the algorithm simple, kmemleak scans for values pointing to any +address inside a block's address range. This may lead to an increased +number of false negatives. However, it is likely that a real memory leak +will eventually become visible. + +Another source of false negatives is the data stored in non-pointer +values. In a future version, kmemleak could only scan the pointer +members in the allocated structures. This feature would solve many of +the false negative cases described above. + +The tool can report false positives. These are cases where an allocated +block doesn't need to be freed (some cases in the init_call functions), +the pointer is calculated by other methods than the usual container_of +macro or the pointer is stored in a location not scanned by kmemleak. + +Page allocations and ioremap are not tracked. Only the ARM and x86 +architectures are currently supported. diff --git a/Documentation/kobject.txt b/Documentation/kobject.txt index b2e374586bd8..c79ab996dada 100644 --- a/Documentation/kobject.txt +++ b/Documentation/kobject.txt @@ -132,7 +132,7 @@ kobject_name(): const char *kobject_name(const struct kobject * kobj); There is a helper function to both initialize and add the kobject to the -kernel at the same time, called supprisingly enough kobject_init_and_add(): +kernel at the same time, called surprisingly enough kobject_init_and_add(): int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype, struct kobject *parent, const char *fmt, ...); diff --git a/Documentation/kprobes.txt b/Documentation/kprobes.txt index 1e7a769a10f9..053037a1fe6d 100644 --- a/Documentation/kprobes.txt +++ b/Documentation/kprobes.txt @@ -507,9 +507,9 @@ http://www.linuxsymposium.org/2006/linuxsymposium_procv2.pdf (pages 101-115) Appendix A: The kprobes debugfs interface With recent kernels (> 2.6.20) the list of registered kprobes is visible -under the /debug/kprobes/ directory (assuming debugfs is mounted at /debug). +under the /sys/kernel/debug/kprobes/ directory (assuming debugfs is mounted at //sys/kernel/debug). -/debug/kprobes/list: Lists all registered probes on the system +/sys/kernel/debug/kprobes/list: Lists all registered probes on the system c015d71a k vfs_read+0x0 c011a316 j do_fork+0x0 @@ -525,7 +525,7 @@ virtual addresses that correspond to modules that've been unloaded), such probes are marked with [GONE]. If the probe is temporarily disabled, such probes are marked with [DISABLED]. -/debug/kprobes/enabled: Turn kprobes ON/OFF forcibly. +/sys/kernel/debug/kprobes/enabled: Turn kprobes ON/OFF forcibly. Provides a knob to globally and forcibly turn registered kprobes ON or OFF. By default, all kprobes are enabled. By echoing "0" to this file, all diff --git a/Documentation/laptops/acer-wmi.txt b/Documentation/laptops/acer-wmi.txt index 5ee2a02b3b40..0768fcc3ba3e 100644 --- a/Documentation/laptops/acer-wmi.txt +++ b/Documentation/laptops/acer-wmi.txt @@ -40,7 +40,7 @@ NOTE: The Acer Aspire One is not supported hardware. It cannot work with acer-wmi until Acer fix their ACPI-WMI implementation on them, so has been blacklisted until that happens. -Please see the website for the current list of known working hardare: +Please see the website for the current list of known working hardware: http://code.google.com/p/aceracpi/wiki/SupportedHardware diff --git a/Documentation/laptops/sony-laptop.txt b/Documentation/laptops/sony-laptop.txt index 8b2bc1572d98..23ce7d350d1a 100644 --- a/Documentation/laptops/sony-laptop.txt +++ b/Documentation/laptops/sony-laptop.txt @@ -22,7 +22,7 @@ If your laptop model supports it, you will find sysfs files in the /sys/class/backlight/sony/ directory. You will be able to query and set the current screen brightness: - brightness get/set screen brightness (an iteger + brightness get/set screen brightness (an integer between 0 and 7) actual_brightness reading from this file will query the HW to get real brightness value diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt index e7e9a69069e1..f2296ecedb89 100644 --- a/Documentation/laptops/thinkpad-acpi.txt +++ b/Documentation/laptops/thinkpad-acpi.txt @@ -506,7 +506,7 @@ generate input device EV_KEY events. In addition to the EV_KEY events, thinkpad-acpi may also issue EV_SW events for switches: -SW_RFKILL_ALL T60 and later hardare rfkill rocker switch +SW_RFKILL_ALL T60 and later hardware rfkill rocker switch SW_TABLET_MODE Tablet ThinkPads HKEY events 0x5009 and 0x500A Non hot-key ACPI HKEY event map: @@ -920,7 +920,7 @@ The available commands are: echo ' off' >/proc/acpi/ibm/led echo ' blink' >/proc/acpi/ibm/led -The range is 0 to 7. The set of LEDs that can be +The range is 0 to 15. The set of LEDs that can be controlled varies from model to model. Here is the common ThinkPad mapping: @@ -932,6 +932,11 @@ mapping: 5 - UltraBase battery slot 6 - (unknown) 7 - standby + 8 - dock status 1 + 9 - dock status 2 + 10, 11 - (unknown) + 12 - thinkvantage + 13, 14, 15 - (unknown) All of the above can be turned on and off and can be made to blink. @@ -940,10 +945,12 @@ sysfs notes: The ThinkPad LED sysfs interface is described in detail by the LED class documentation, in Documentation/leds-class.txt. -The leds are named (in LED ID order, from 0 to 7): +The LEDs are named (in LED ID order, from 0 to 12): "tpacpi::power", "tpacpi:orange:batt", "tpacpi:green:batt", "tpacpi::dock_active", "tpacpi::bay_active", "tpacpi::dock_batt", -"tpacpi::unknown_led", "tpacpi::standby". +"tpacpi::unknown_led", "tpacpi::standby", "tpacpi::dock_status1", +"tpacpi::dock_status2", "tpacpi::unknown_led2", "tpacpi::unknown_led3", +"tpacpi::thinkvantage". Due to limitations in the sysfs LED class, if the status of the LED indicators cannot be read due to an error, thinkpad-acpi will report it as @@ -958,6 +965,12 @@ ThinkPad indicator LED should blink in hardware accelerated mode, use the "timer" trigger, and leave the delay_on and delay_off parameters set to zero (to request hardware acceleration autodetection). +LEDs that are known not to exist in a given ThinkPad model are not +made available through the sysfs interface. If you have a dock and you +notice there are LEDs listed for your ThinkPad that do not exist (and +are not in the dock), or if you notice that there are missing LEDs, +a report to ibm-acpi-devel@lists.sourceforge.net is appreciated. + ACPI sounds -- /proc/acpi/ibm/beep ---------------------------------- @@ -1156,17 +1169,19 @@ may not be distinct. Later Lenovo models that implement the ACPI display backlight brightness control methods have 16 levels, ranging from 0 to 15. -There are two interfaces to the firmware for direct brightness control, -EC and UCMS (or CMOS). To select which one should be used, use the -brightness_mode module parameter: brightness_mode=1 selects EC mode, -brightness_mode=2 selects UCMS mode, brightness_mode=3 selects EC -mode with NVRAM backing (so that brightness changes are remembered -across shutdown/reboot). +For IBM ThinkPads, there are two interfaces to the firmware for direct +brightness control, EC and UCMS (or CMOS). To select which one should be +used, use the brightness_mode module parameter: brightness_mode=1 selects +EC mode, brightness_mode=2 selects UCMS mode, brightness_mode=3 selects EC +mode with NVRAM backing (so that brightness changes are remembered across +shutdown/reboot). The driver tries to select which interface to use from a table of defaults for each ThinkPad model. If it makes a wrong choice, please report this as a bug, so that we can fix it. +Lenovo ThinkPads only support brightness_mode=2 (UCMS). + When display backlight brightness controls are available through the standard ACPI interface, it is best to use it instead of this direct ThinkPad-specific interface. The driver will disable its native @@ -1254,7 +1269,7 @@ Fan control and monitoring: fan speed, fan enable/disable procfs: /proc/acpi/ibm/fan sysfs device attributes: (hwmon "thinkpad") fan1_input, pwm1, - pwm1_enable + pwm1_enable, fan2_input sysfs hwmon driver attributes: fan_watchdog NOTE NOTE NOTE: fan control operations are disabled by default for @@ -1267,6 +1282,9 @@ from the hardware registers of the embedded controller. This is known to work on later R, T, X and Z series ThinkPads but may show a bogus value on other models. +Some Lenovo ThinkPads support a secondary fan. This fan cannot be +controlled separately, it shares the main fan control. + Fan levels: Most ThinkPad fans work in "levels" at the firmware interface. Level 0 @@ -1397,6 +1415,11 @@ hwmon device attribute fan1_input: which can take up to two minutes. May return rubbish on older ThinkPads. +hwmon device attribute fan2_input: + Fan tachometer reading, in RPM, for the secondary fan. + Available only on some ThinkPads. If the secondary fan is + not installed, will always read 0. + hwmon driver attribute fan_watchdog: Fan safety watchdog timer interval, in seconds. Minimum is 1 second, maximum is 120 seconds. 0 disables the watchdog. @@ -1555,3 +1578,7 @@ Sysfs interface changelog: 0x020300: hotkey enable/disable support removed, attributes hotkey_bios_enabled and hotkey_enable deprecated and marked for removal. + +0x020400: Marker for 16 LEDs support. Also, LEDs that are known + to not exist in a given model are not registered with + the LED sysfs class anymore. diff --git a/Documentation/lguest/Makefile b/Documentation/lguest/Makefile index 1f4f9e888bd1..28c8cdfcafd8 100644 --- a/Documentation/lguest/Makefile +++ b/Documentation/lguest/Makefile @@ -1,6 +1,5 @@ # This creates the demonstration utility "lguest" which runs a Linux guest. -CFLAGS:=-Wall -Wmissing-declarations -Wmissing-prototypes -O3 -I../../include -I../../arch/x86/include -U_FORTIFY_SOURCE -LDLIBS:=-lz +CFLAGS:=-m32 -Wall -Wmissing-declarations -Wmissing-prototypes -O3 -I../../include -I../../arch/x86/include -U_FORTIFY_SOURCE all: lguest diff --git a/Documentation/lguest/lguest.c b/Documentation/lguest/lguest.c index d36fcc0f2715..9ebcd6ef361b 100644 --- a/Documentation/lguest/lguest.c +++ b/Documentation/lguest/lguest.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -59,7 +60,6 @@ typedef uint8_t u8; /*:*/ #define PAGE_PRESENT 0x7 /* Present, RW, Execute */ -#define NET_PEERNUM 1 #define BRIDGE_PFX "bridge:" #ifndef SIOCBRADDIF #define SIOCBRADDIF 0x89a2 /* add interface to bridge */ @@ -76,19 +76,12 @@ static bool verbose; do { if (verbose) printf(args); } while(0) /*:*/ -/* File descriptors for the Waker. */ -struct { - int pipe[2]; - int lguest_fd; -} waker_fds; - /* The pointer to the start of guest memory. */ static void *guest_base; /* The maximum guest physical address allowed, and maximum possible. */ static unsigned long guest_limit, guest_max; -/* The pipe for signal hander to write to. */ -static int timeoutpipe[2]; -static unsigned int timeout_usec = 500; +/* The /dev/lguest file descriptor. */ +static int lguest_fd; /* a per-cpu variable indicating whose vcpu is currently running */ static unsigned int __thread cpu_id; @@ -96,11 +89,6 @@ static unsigned int __thread cpu_id; /* This is our list of devices. */ struct device_list { - /* Summary information about the devices in our list: ready to pass to - * select() to ask which need servicing.*/ - fd_set infds; - int max_infd; - /* Counter to assign interrupt numbers. */ unsigned int next_irq; @@ -126,22 +114,21 @@ struct device /* The linked-list pointer. */ struct device *next; - /* The this device's descriptor, as mapped into the Guest. */ + /* The device's descriptor, as mapped into the Guest. */ struct lguest_device_desc *desc; + /* We can't trust desc values once Guest has booted: we use these. */ + unsigned int feature_len; + unsigned int num_vq; + /* The name of this device, for --verbose. */ const char *name; - /* If handle_input is set, it wants to be called when this file - * descriptor is ready. */ - int fd; - bool (*handle_input)(int fd, struct device *me); - /* Any queues attached to this device */ struct virtqueue *vq; - /* Handle status being finalized (ie. feature bits stable). */ - void (*ready)(struct device *me); + /* Is it operational */ + bool running; /* Device-specific data. */ void *priv; @@ -164,22 +151,28 @@ struct virtqueue /* Last available index we saw. */ u16 last_avail_idx; - /* The routine to call when the Guest pings us, or timeout. */ - void (*handle_output)(int fd, struct virtqueue *me, bool timeout); + /* How many are used since we sent last irq? */ + unsigned int pending_used; - /* Outstanding buffers */ - unsigned int inflight; + /* Eventfd where Guest notifications arrive. */ + int eventfd; - /* Is this blocked awaiting a timer? */ - bool blocked; + /* Function for the thread which is servicing this virtqueue. */ + void (*service)(struct virtqueue *vq); + pid_t thread; }; /* Remember the arguments to the program so we can "reboot" */ static char **main_args; -/* Since guest is UP and we don't run at the same time, we don't need barriers. - * But I include them in the code in case others copy it. */ -#define wmb() +/* The original tty settings to restore on exit. */ +static struct termios orig_term; + +/* We have to be careful with barriers: our devices are all run in separate + * threads and so we need to make sure that changes visible to the Guest happen + * in precise order. */ +#define wmb() __asm__ __volatile__("" : : : "memory") +#define mb() __asm__ __volatile__("" : : : "memory") /* Convert an iovec element to the given type. * @@ -245,7 +238,7 @@ static void iov_consume(struct iovec iov[], unsigned num_iov, unsigned len) static u8 *get_feature_bits(struct device *dev) { return (u8 *)(dev->desc + 1) - + dev->desc->num_vq * sizeof(struct lguest_vqconfig); + + dev->num_vq * sizeof(struct lguest_vqconfig); } /*L:100 The Launcher code itself takes us out into userspace, that scary place @@ -505,99 +498,19 @@ static void concat(char *dst, char *args[]) * saw the arguments it expects when we looked at initialize() in lguest_user.c: * the base of Guest "physical" memory, the top physical page to allow and the * entry point for the Guest. */ -static int tell_kernel(unsigned long start) +static void tell_kernel(unsigned long start) { unsigned long args[] = { LHREQ_INITIALIZE, (unsigned long)guest_base, guest_limit / getpagesize(), start }; - int fd; - verbose("Guest: %p - %p (%#lx)\n", guest_base, guest_base + guest_limit, guest_limit); - fd = open_or_die("/dev/lguest", O_RDWR); - if (write(fd, args, sizeof(args)) < 0) + lguest_fd = open_or_die("/dev/lguest", O_RDWR); + if (write(lguest_fd, args, sizeof(args)) < 0) err(1, "Writing to /dev/lguest"); - - /* We return the /dev/lguest file descriptor to control this Guest */ - return fd; } /*:*/ -static void add_device_fd(int fd) -{ - FD_SET(fd, &devices.infds); - if (fd > devices.max_infd) - devices.max_infd = fd; -} - -/*L:200 - * The Waker. - * - * With console, block and network devices, we can have lots of input which we - * need to process. We could try to tell the kernel what file descriptors to - * watch, but handing a file descriptor mask through to the kernel is fairly - * icky. - * - * Instead, we clone off a thread which watches the file descriptors and writes - * the LHREQ_BREAK command to the /dev/lguest file descriptor to tell the Host - * stop running the Guest. This causes the Launcher to return from the - * /dev/lguest read with -EAGAIN, where it will write to /dev/lguest to reset - * the LHREQ_BREAK and wake us up again. - * - * This, of course, is merely a different *kind* of icky. - * - * Given my well-known antipathy to threads, I'd prefer to use processes. But - * it's easier to share Guest memory with threads, and trivial to share the - * devices.infds as the Launcher changes it. - */ -static int waker(void *unused) -{ - /* Close the write end of the pipe: only the Launcher has it open. */ - close(waker_fds.pipe[1]); - - for (;;) { - fd_set rfds = devices.infds; - unsigned long args[] = { LHREQ_BREAK, 1 }; - unsigned int maxfd = devices.max_infd; - - /* We also listen to the pipe from the Launcher. */ - FD_SET(waker_fds.pipe[0], &rfds); - if (waker_fds.pipe[0] > maxfd) - maxfd = waker_fds.pipe[0]; - - /* Wait until input is ready from one of the devices. */ - select(maxfd+1, &rfds, NULL, NULL, NULL); - - /* Message from Launcher? */ - if (FD_ISSET(waker_fds.pipe[0], &rfds)) { - char c; - /* If this fails, then assume Launcher has exited. - * Don't do anything on exit: we're just a thread! */ - if (read(waker_fds.pipe[0], &c, 1) != 1) - _exit(0); - continue; - } - - /* Send LHREQ_BREAK command to snap the Launcher out of it. */ - pwrite(waker_fds.lguest_fd, args, sizeof(args), cpu_id); - } - return 0; -} - -/* This routine just sets up a pipe to the Waker process. */ -static void setup_waker(int lguest_fd) -{ - /* This pipe is closed when Launcher dies, telling Waker. */ - if (pipe(waker_fds.pipe) != 0) - err(1, "Creating pipe for Waker"); - - /* Waker also needs to know the lguest fd */ - waker_fds.lguest_fd = lguest_fd; - - if (clone(waker, malloc(4096) + 4096, CLONE_VM | SIGCHLD, NULL) == -1) - err(1, "Creating Waker"); -} - /* * Device Handling. * @@ -623,49 +536,90 @@ static void *_check_pointer(unsigned long addr, unsigned int size, /* Each buffer in the virtqueues is actually a chain of descriptors. This * function returns the next descriptor in the chain, or vq->vring.num if we're * at the end. */ -static unsigned next_desc(struct virtqueue *vq, unsigned int i) +static unsigned next_desc(struct vring_desc *desc, + unsigned int i, unsigned int max) { unsigned int next; /* If this descriptor says it doesn't chain, we're done. */ - if (!(vq->vring.desc[i].flags & VRING_DESC_F_NEXT)) - return vq->vring.num; + if (!(desc[i].flags & VRING_DESC_F_NEXT)) + return max; /* Check they're not leading us off end of descriptors. */ - next = vq->vring.desc[i].next; + next = desc[i].next; /* Make sure compiler knows to grab that: we don't want it changing! */ wmb(); - if (next >= vq->vring.num) + if (next >= max) errx(1, "Desc next is %u", next); return next; } +/* This actually sends the interrupt for this virtqueue */ +static void trigger_irq(struct virtqueue *vq) +{ + unsigned long buf[] = { LHREQ_IRQ, vq->config.irq }; + + /* Don't inform them if nothing used. */ + if (!vq->pending_used) + return; + vq->pending_used = 0; + + /* If they don't want an interrupt, don't send one, unless empty. */ + if ((vq->vring.avail->flags & VRING_AVAIL_F_NO_INTERRUPT) + && lg_last_avail(vq) != vq->vring.avail->idx) + return; + + /* Send the Guest an interrupt tell them we used something up. */ + if (write(lguest_fd, buf, sizeof(buf)) != 0) + err(1, "Triggering irq %i", vq->config.irq); +} + /* This looks in the virtqueue and for the first available buffer, and converts * it to an iovec for convenient access. Since descriptors consist of some * number of output then some number of input descriptors, it's actually two * iovecs, but we pack them into one and note how many of each there were. * - * This function returns the descriptor number found, or vq->vring.num (which - * is never a valid descriptor number) if none was found. */ -static unsigned get_vq_desc(struct virtqueue *vq, - struct iovec iov[], - unsigned int *out_num, unsigned int *in_num) + * This function returns the descriptor number found. */ +static unsigned wait_for_vq_desc(struct virtqueue *vq, + struct iovec iov[], + unsigned int *out_num, unsigned int *in_num) { - unsigned int i, head; - u16 last_avail; + unsigned int i, head, max; + struct vring_desc *desc; + u16 last_avail = lg_last_avail(vq); + + while (last_avail == vq->vring.avail->idx) { + u64 event; + + /* OK, tell Guest about progress up to now. */ + trigger_irq(vq); + + /* OK, now we need to know about added descriptors. */ + vq->vring.used->flags &= ~VRING_USED_F_NO_NOTIFY; + + /* They could have slipped one in as we were doing that: make + * sure it's written, then check again. */ + mb(); + if (last_avail != vq->vring.avail->idx) { + vq->vring.used->flags |= VRING_USED_F_NO_NOTIFY; + break; + } + + /* Nothing new? Wait for eventfd to tell us they refilled. */ + if (read(vq->eventfd, &event, sizeof(event)) != sizeof(event)) + errx(1, "Event read failed?"); + + /* We don't need to be notified again. */ + vq->vring.used->flags |= VRING_USED_F_NO_NOTIFY; + } /* Check it isn't doing very strange things with descriptor numbers. */ - last_avail = lg_last_avail(vq); if ((u16)(vq->vring.avail->idx - last_avail) > vq->vring.num) errx(1, "Guest moved used index from %u to %u", last_avail, vq->vring.avail->idx); - /* If there's nothing new since last we looked, return invalid. */ - if (vq->vring.avail->idx == last_avail) - return vq->vring.num; - /* Grab the next descriptor number they're advertising, and increment * the index we've seen. */ head = vq->vring.avail->ring[last_avail % vq->vring.num]; @@ -678,15 +632,28 @@ static unsigned get_vq_desc(struct virtqueue *vq, /* When we start there are none of either input nor output. */ *out_num = *in_num = 0; + max = vq->vring.num; + desc = vq->vring.desc; i = head; + + /* If this is an indirect entry, then this buffer contains a descriptor + * table which we handle as if it's any normal descriptor chain. */ + if (desc[i].flags & VRING_DESC_F_INDIRECT) { + if (desc[i].len % sizeof(struct vring_desc)) + errx(1, "Invalid size for indirect buffer table"); + + max = desc[i].len / sizeof(struct vring_desc); + desc = check_pointer(desc[i].addr, desc[i].len); + i = 0; + } + do { /* Grab the first descriptor, and check it's OK. */ - iov[*out_num + *in_num].iov_len = vq->vring.desc[i].len; + iov[*out_num + *in_num].iov_len = desc[i].len; iov[*out_num + *in_num].iov_base - = check_pointer(vq->vring.desc[i].addr, - vq->vring.desc[i].len); + = check_pointer(desc[i].addr, desc[i].len); /* If this is an input descriptor, increment that count. */ - if (vq->vring.desc[i].flags & VRING_DESC_F_WRITE) + if (desc[i].flags & VRING_DESC_F_WRITE) (*in_num)++; else { /* If it's an output descriptor, they're all supposed @@ -697,11 +664,10 @@ static unsigned get_vq_desc(struct virtqueue *vq, } /* If we've got too many, that implies a descriptor loop. */ - if (*out_num + *in_num > vq->vring.num) + if (*out_num + *in_num > max) errx(1, "Looped descriptor"); - } while ((i = next_desc(vq, i)) != vq->vring.num); + } while ((i = next_desc(desc, i, max)) != max); - vq->inflight++; return head; } @@ -719,44 +685,20 @@ static void add_used(struct virtqueue *vq, unsigned int head, int len) /* Make sure buffer is written before we update index. */ wmb(); vq->vring.used->idx++; - vq->inflight--; -} - -/* This actually sends the interrupt for this virtqueue */ -static void trigger_irq(int fd, struct virtqueue *vq) -{ - unsigned long buf[] = { LHREQ_IRQ, vq->config.irq }; - - /* If they don't want an interrupt, don't send one, unless empty. */ - if ((vq->vring.avail->flags & VRING_AVAIL_F_NO_INTERRUPT) - && vq->inflight) - return; - - /* Send the Guest an interrupt tell them we used something up. */ - if (write(fd, buf, sizeof(buf)) != 0) - err(1, "Triggering irq %i", vq->config.irq); + vq->pending_used++; } /* And here's the combo meal deal. Supersize me! */ -static void add_used_and_trigger(int fd, struct virtqueue *vq, - unsigned int head, int len) +static void add_used_and_trigger(struct virtqueue *vq, unsigned head, int len) { add_used(vq, head, len); - trigger_irq(fd, vq); + trigger_irq(vq); } /* * The Console * - * Here is the input terminal setting we save, and the routine to restore them - * on exit so the user gets their terminal back. */ -static struct termios orig_term; -static void restore_term(void) -{ - tcsetattr(STDIN_FILENO, TCSANOW, &orig_term); -} - -/* We associate some data with the console for our exit hack. */ + * We associate some data with the console for our exit hack. */ struct console_abort { /* How many times have they hit ^C? */ @@ -766,276 +708,275 @@ struct console_abort }; /* This is the routine which handles console input (ie. stdin). */ -static bool handle_console_input(int fd, struct device *dev) +static void console_input(struct virtqueue *vq) { int len; unsigned int head, in_num, out_num; - struct iovec iov[dev->vq->vring.num]; - struct console_abort *abort = dev->priv; - - /* First we need a console buffer from the Guests's input virtqueue. */ - head = get_vq_desc(dev->vq, iov, &out_num, &in_num); - - /* If they're not ready for input, stop listening to this file - * descriptor. We'll start again once they add an input buffer. */ - if (head == dev->vq->vring.num) - return false; + struct console_abort *abort = vq->dev->priv; + struct iovec iov[vq->vring.num]; + /* Make sure there's a descriptor waiting. */ + head = wait_for_vq_desc(vq, iov, &out_num, &in_num); if (out_num) errx(1, "Output buffers in console in queue?"); - /* This is why we convert to iovecs: the readv() call uses them, and so - * it reads straight into the Guest's buffer. */ - len = readv(dev->fd, iov, in_num); + /* Read it in. */ + len = readv(STDIN_FILENO, iov, in_num); if (len <= 0) { - /* This implies that the console is closed, is /dev/null, or - * something went terribly wrong. */ + /* Ran out of input? */ warnx("Failed to get console input, ignoring console."); - /* Put the input terminal back. */ - restore_term(); - /* Remove callback from input vq, so it doesn't restart us. */ - dev->vq->handle_output = NULL; - /* Stop listening to this fd: don't call us again. */ - return false; + /* For simplicity, dying threads kill the whole Launcher. So + * just nap here. */ + for (;;) + pause(); } - /* Tell the Guest about the new input. */ - add_used_and_trigger(fd, dev->vq, head, len); + add_used_and_trigger(vq, head, len); /* Three ^C within one second? Exit. * - * This is such a hack, but works surprisingly well. Each ^C has to be - * in a buffer by itself, so they can't be too fast. But we check that - * we get three within about a second, so they can't be too slow. */ - if (len == 1 && ((char *)iov[0].iov_base)[0] == 3) { - if (!abort->count++) - gettimeofday(&abort->start, NULL); - else if (abort->count == 3) { - struct timeval now; - gettimeofday(&now, NULL); - if (now.tv_sec <= abort->start.tv_sec+1) { - unsigned long args[] = { LHREQ_BREAK, 0 }; - /* Close the fd so Waker will know it has to - * exit. */ - close(waker_fds.pipe[1]); - /* Just in case Waker is blocked in BREAK, send - * unbreak now. */ - write(fd, args, sizeof(args)); - exit(2); - } - abort->count = 0; - } - } else - /* Any other key resets the abort counter. */ + * This is such a hack, but works surprisingly well. Each ^C has to + * be in a buffer by itself, so they can't be too fast. But we check + * that we get three within about a second, so they can't be too + * slow. */ + if (len != 1 || ((char *)iov[0].iov_base)[0] != 3) { abort->count = 0; + return; + } - /* Everything went OK! */ - return true; -} - -/* Handling output for console is simple: we just get all the output buffers - * and write them to stdout. */ -static void handle_console_output(int fd, struct virtqueue *vq, bool timeout) -{ - unsigned int head, out, in; - int len; - struct iovec iov[vq->vring.num]; - - /* Keep getting output buffers from the Guest until we run out. */ - while ((head = get_vq_desc(vq, iov, &out, &in)) != vq->vring.num) { - if (in) - errx(1, "Input buffers in output queue?"); - len = writev(STDOUT_FILENO, iov, out); - add_used_and_trigger(fd, vq, head, len); + abort->count++; + if (abort->count == 1) + gettimeofday(&abort->start, NULL); + else if (abort->count == 3) { + struct timeval now; + gettimeofday(&now, NULL); + /* Kill all Launcher processes with SIGINT, like normal ^C */ + if (now.tv_sec <= abort->start.tv_sec+1) + kill(0, SIGINT); + abort->count = 0; } } -/* This is called when we no longer want to hear about Guest changes to a - * virtqueue. This is more efficient in high-traffic cases, but it means we - * have to set a timer to check if any more changes have occurred. */ -static void block_vq(struct virtqueue *vq) +/* This is the routine which handles console output (ie. stdout). */ +static void console_output(struct virtqueue *vq) { - struct itimerval itm; + unsigned int head, out, in; + struct iovec iov[vq->vring.num]; - vq->vring.used->flags |= VRING_USED_F_NO_NOTIFY; - vq->blocked = true; - - itm.it_interval.tv_sec = 0; - itm.it_interval.tv_usec = 0; - itm.it_value.tv_sec = 0; - itm.it_value.tv_usec = timeout_usec; - - setitimer(ITIMER_REAL, &itm, NULL); + head = wait_for_vq_desc(vq, iov, &out, &in); + if (in) + errx(1, "Input buffers in console output queue?"); + while (!iov_empty(iov, out)) { + int len = writev(STDOUT_FILENO, iov, out); + if (len <= 0) + err(1, "Write to stdout gave %i", len); + iov_consume(iov, out, len); + } + add_used(vq, head, 0); } /* * The Network * * Handling output for network is also simple: we get all the output buffers - * and write them (ignoring the first element) to this device's file descriptor - * (/dev/net/tun). + * and write them to /dev/net/tun. */ -static void handle_net_output(int fd, struct virtqueue *vq, bool timeout) +struct net_info { + int tunfd; +}; + +static void net_output(struct virtqueue *vq) { - unsigned int head, out, in, num = 0; - int len; + struct net_info *net_info = vq->dev->priv; + unsigned int head, out, in; struct iovec iov[vq->vring.num]; - static int last_timeout_num; - /* Keep getting output buffers from the Guest until we run out. */ - while ((head = get_vq_desc(vq, iov, &out, &in)) != vq->vring.num) { - if (in) - errx(1, "Input buffers in output queue?"); - len = writev(vq->dev->fd, iov, out); - if (len < 0) - err(1, "Writing network packet to tun"); - add_used_and_trigger(fd, vq, head, len); - num++; - } - - /* Block further kicks and set up a timer if we saw anything. */ - if (!timeout && num) - block_vq(vq); - - /* We never quite know how long should we wait before we check the - * queue again for more packets. We start at 500 microseconds, and if - * we get fewer packets than last time, we assume we made the timeout - * too small and increase it by 10 microseconds. Otherwise, we drop it - * by one microsecond every time. It seems to work well enough. */ - if (timeout) { - if (num < last_timeout_num) - timeout_usec += 10; - else if (timeout_usec > 1) - timeout_usec--; - last_timeout_num = num; - } + head = wait_for_vq_desc(vq, iov, &out, &in); + if (in) + errx(1, "Input buffers in net output queue?"); + if (writev(net_info->tunfd, iov, out) < 0) + errx(1, "Write to tun failed?"); + add_used(vq, head, 0); } -/* This is where we handle a packet coming in from the tun device to our +/* Will reading from this file descriptor block? */ +static bool will_block(int fd) +{ + fd_set fdset; + struct timeval zero = { 0, 0 }; + FD_ZERO(&fdset); + FD_SET(fd, &fdset); + return select(fd+1, &fdset, NULL, NULL, &zero) != 1; +} + +/* This is where we handle packets coming in from the tun device to our * Guest. */ -static bool handle_tun_input(int fd, struct device *dev) +static void net_input(struct virtqueue *vq) { - unsigned int head, in_num, out_num; int len; - struct iovec iov[dev->vq->vring.num]; + unsigned int head, out, in; + struct iovec iov[vq->vring.num]; + struct net_info *net_info = vq->dev->priv; - /* First we need a network buffer from the Guests's recv virtqueue. */ - head = get_vq_desc(dev->vq, iov, &out_num, &in_num); - if (head == dev->vq->vring.num) { - /* Now, it's expected that if we try to send a packet too - * early, the Guest won't be ready yet. Wait until the device - * status says it's ready. */ - /* FIXME: Actually want DRIVER_ACTIVE here. */ + head = wait_for_vq_desc(vq, iov, &out, &in); + if (out) + errx(1, "Output buffers in net input queue?"); - /* Now tell it we want to know if new things appear. */ - dev->vq->vring.used->flags &= ~VRING_USED_F_NO_NOTIFY; - wmb(); + /* Deliver interrupt now, since we're about to sleep. */ + if (vq->pending_used && will_block(net_info->tunfd)) + trigger_irq(vq); - /* We'll turn this back on if input buffers are registered. */ - return false; - } else if (out_num) - errx(1, "Output buffers in network recv queue?"); - - /* Read the packet from the device directly into the Guest's buffer. */ - len = readv(dev->fd, iov, in_num); + len = readv(net_info->tunfd, iov, in); if (len <= 0) - err(1, "reading network"); - - /* Tell the Guest about the new packet. */ - add_used_and_trigger(fd, dev->vq, head, len); - - verbose("tun input packet len %i [%02x %02x] (%s)\n", len, - ((u8 *)iov[1].iov_base)[0], ((u8 *)iov[1].iov_base)[1], - head != dev->vq->vring.num ? "sent" : "discarded"); - - /* All good. */ - return true; + err(1, "Failed to read from tun."); + add_used(vq, head, len); } -/*L:215 This is the callback attached to the network and console input - * virtqueues: it ensures we try again, in case we stopped console or net - * delivery because Guest didn't have any buffers. */ -static void enable_fd(int fd, struct virtqueue *vq, bool timeout) +/* This is the helper to create threads. */ +static int do_thread(void *_vq) { - add_device_fd(vq->dev->fd); - /* Snap the Waker out of its select loop. */ - write(waker_fds.pipe[1], "", 1); + struct virtqueue *vq = _vq; + + for (;;) + vq->service(vq); + return 0; } -static void net_enable_fd(int fd, struct virtqueue *vq, bool timeout) +/* When a child dies, we kill our entire process group with SIGTERM. This + * also has the side effect that the shell restores the console for us! */ +static void kill_launcher(int signal) { - /* We don't need to know again when Guest refills receive buffer. */ - vq->vring.used->flags |= VRING_USED_F_NO_NOTIFY; - enable_fd(fd, vq, timeout); + kill(0, SIGTERM); +} + +static void reset_device(struct device *dev) +{ + struct virtqueue *vq; + + verbose("Resetting device %s\n", dev->name); + + /* Clear any features they've acked. */ + memset(get_feature_bits(dev) + dev->feature_len, 0, dev->feature_len); + + /* We're going to be explicitly killing threads, so ignore them. */ + signal(SIGCHLD, SIG_IGN); + + /* Zero out the virtqueues, get rid of their threads */ + for (vq = dev->vq; vq; vq = vq->next) { + if (vq->thread != (pid_t)-1) { + kill(vq->thread, SIGTERM); + waitpid(vq->thread, NULL, 0); + vq->thread = (pid_t)-1; + } + memset(vq->vring.desc, 0, + vring_size(vq->config.num, LGUEST_VRING_ALIGN)); + lg_last_avail(vq) = 0; + } + dev->running = false; + + /* Now we care if threads die. */ + signal(SIGCHLD, (void *)kill_launcher); +} + +static void create_thread(struct virtqueue *vq) +{ + /* Create stack for thread and run it. Since stack grows + * upwards, we point the stack pointer to the end of this + * region. */ + char *stack = malloc(32768); + unsigned long args[] = { LHREQ_EVENTFD, + vq->config.pfn*getpagesize(), 0 }; + + /* Create a zero-initialized eventfd. */ + vq->eventfd = eventfd(0, 0); + if (vq->eventfd < 0) + err(1, "Creating eventfd"); + args[2] = vq->eventfd; + + /* Attach an eventfd to this virtqueue: it will go off + * when the Guest does an LHCALL_NOTIFY for this vq. */ + if (write(lguest_fd, &args, sizeof(args)) != 0) + err(1, "Attaching eventfd"); + + /* CLONE_VM: because it has to access the Guest memory, and + * SIGCHLD so we get a signal if it dies. */ + vq->thread = clone(do_thread, stack + 32768, CLONE_VM | SIGCHLD, vq); + if (vq->thread == (pid_t)-1) + err(1, "Creating clone"); + /* We close our local copy, now the child has it. */ + close(vq->eventfd); +} + +static void start_device(struct device *dev) +{ + unsigned int i; + struct virtqueue *vq; + + verbose("Device %s OK: offered", dev->name); + for (i = 0; i < dev->feature_len; i++) + verbose(" %02x", get_feature_bits(dev)[i]); + verbose(", accepted"); + for (i = 0; i < dev->feature_len; i++) + verbose(" %02x", get_feature_bits(dev) + [dev->feature_len+i]); + + for (vq = dev->vq; vq; vq = vq->next) { + if (vq->service) + create_thread(vq); + } + dev->running = true; +} + +static void cleanup_devices(void) +{ + struct device *dev; + + for (dev = devices.dev; dev; dev = dev->next) + reset_device(dev); + + /* If we saved off the original terminal settings, restore them now. */ + if (orig_term.c_lflag & (ISIG|ICANON|ECHO)) + tcsetattr(STDIN_FILENO, TCSANOW, &orig_term); } /* When the Guest tells us they updated the status field, we handle it. */ static void update_device_status(struct device *dev) { - struct virtqueue *vq; - - /* This is a reset. */ - if (dev->desc->status == 0) { - verbose("Resetting device %s\n", dev->name); - - /* Clear any features they've acked. */ - memset(get_feature_bits(dev) + dev->desc->feature_len, 0, - dev->desc->feature_len); - - /* Zero out the virtqueues. */ - for (vq = dev->vq; vq; vq = vq->next) { - memset(vq->vring.desc, 0, - vring_size(vq->config.num, LGUEST_VRING_ALIGN)); - lg_last_avail(vq) = 0; - } - } else if (dev->desc->status & VIRTIO_CONFIG_S_FAILED) { + /* A zero status is a reset, otherwise it's a set of flags. */ + if (dev->desc->status == 0) + reset_device(dev); + else if (dev->desc->status & VIRTIO_CONFIG_S_FAILED) { warnx("Device %s configuration FAILED", dev->name); + if (dev->running) + reset_device(dev); } else if (dev->desc->status & VIRTIO_CONFIG_S_DRIVER_OK) { - unsigned int i; - - verbose("Device %s OK: offered", dev->name); - for (i = 0; i < dev->desc->feature_len; i++) - verbose(" %02x", get_feature_bits(dev)[i]); - verbose(", accepted"); - for (i = 0; i < dev->desc->feature_len; i++) - verbose(" %02x", get_feature_bits(dev) - [dev->desc->feature_len+i]); - - if (dev->ready) - dev->ready(dev); + if (!dev->running) + start_device(dev); } } /* This is the generic routine we call when the Guest uses LHCALL_NOTIFY. */ -static void handle_output(int fd, unsigned long addr) +static void handle_output(unsigned long addr) { struct device *i; - struct virtqueue *vq; - /* Check each device and virtqueue. */ + /* Check each device. */ for (i = devices.dev; i; i = i->next) { + struct virtqueue *vq; + /* Notifications to device descriptors update device status. */ if (from_guest_phys(addr) == i->desc) { update_device_status(i); return; } - /* Notifications to virtqueues mean output has occurred. */ + /* Devices *can* be used before status is set to DRIVER_OK. */ for (vq = i->vq; vq; vq = vq->next) { - if (vq->config.pfn != addr/getpagesize()) + if (addr != vq->config.pfn*getpagesize()) continue; - - /* Guest should acknowledge (and set features!) before - * using the device. */ - if (i->desc->status == 0) { - warnx("%s gave early output", i->name); - return; - } - - if (strcmp(vq->dev->name, "console") != 0) - verbose("Output to %s\n", vq->dev->name); - if (vq->handle_output) - vq->handle_output(fd, vq, false); + if (i->running) + errx(1, "Notification on running %s", i->name); + start_device(i); return; } } @@ -1049,71 +990,6 @@ static void handle_output(int fd, unsigned long addr) strnlen(from_guest_phys(addr), guest_limit - addr)); } -static void handle_timeout(int fd) -{ - char buf[32]; - struct device *i; - struct virtqueue *vq; - - /* Clear the pipe */ - read(timeoutpipe[0], buf, sizeof(buf)); - - /* Check each device and virtqueue: flush blocked ones. */ - for (i = devices.dev; i; i = i->next) { - for (vq = i->vq; vq; vq = vq->next) { - if (!vq->blocked) - continue; - - vq->vring.used->flags &= ~VRING_USED_F_NO_NOTIFY; - vq->blocked = false; - if (vq->handle_output) - vq->handle_output(fd, vq, true); - } - } -} - -/* This is called when the Waker wakes us up: check for incoming file - * descriptors. */ -static void handle_input(int fd) -{ - /* select() wants a zeroed timeval to mean "don't wait". */ - struct timeval poll = { .tv_sec = 0, .tv_usec = 0 }; - - for (;;) { - struct device *i; - fd_set fds = devices.infds; - int num; - - num = select(devices.max_infd+1, &fds, NULL, NULL, &poll); - /* Could get interrupted */ - if (num < 0) - continue; - /* If nothing is ready, we're done. */ - if (num == 0) - break; - - /* Otherwise, call the device(s) which have readable file - * descriptors and a method of handling them. */ - for (i = devices.dev; i; i = i->next) { - if (i->handle_input && FD_ISSET(i->fd, &fds)) { - if (i->handle_input(fd, i)) - continue; - - /* If handle_input() returns false, it means we - * should no longer service it. Networking and - * console do this when there's no input - * buffers to deliver into. Console also uses - * it when it discovers that stdin is closed. */ - FD_CLR(i->fd, &devices.infds); - } - } - - /* Is this the timeout fd? */ - if (FD_ISSET(timeoutpipe[0], &fds)) - handle_timeout(fd); - } -} - /*L:190 * Device Setup * @@ -1129,8 +1005,8 @@ static void handle_input(int fd) static u8 *device_config(const struct device *dev) { return (void *)(dev->desc + 1) - + dev->desc->num_vq * sizeof(struct lguest_vqconfig) - + dev->desc->feature_len * 2; + + dev->num_vq * sizeof(struct lguest_vqconfig) + + dev->feature_len * 2; } /* This routine allocates a new "struct lguest_device_desc" from descriptor @@ -1159,7 +1035,7 @@ static struct lguest_device_desc *new_dev_desc(u16 type) /* Each device descriptor is followed by the description of its virtqueues. We * specify how many descriptors the virtqueue is to have. */ static void add_virtqueue(struct device *dev, unsigned int num_descs, - void (*handle_output)(int, struct virtqueue *, bool)) + void (*service)(struct virtqueue *)) { unsigned int pages; struct virtqueue **i, *vq = malloc(sizeof(*vq)); @@ -1174,8 +1050,8 @@ static void add_virtqueue(struct device *dev, unsigned int num_descs, vq->next = NULL; vq->last_avail_idx = 0; vq->dev = dev; - vq->inflight = 0; - vq->blocked = false; + vq->service = service; + vq->thread = (pid_t)-1; /* Initialize the configuration. */ vq->config.num = num_descs; @@ -1191,6 +1067,7 @@ static void add_virtqueue(struct device *dev, unsigned int num_descs, * yet, otherwise we'd be overwriting them. */ assert(dev->desc->config_len == 0 && dev->desc->feature_len == 0); memcpy(device_config(dev), &vq->config, sizeof(vq->config)); + dev->num_vq++; dev->desc->num_vq++; verbose("Virtqueue page %#lx\n", to_guest_phys(p)); @@ -1199,15 +1076,6 @@ static void add_virtqueue(struct device *dev, unsigned int num_descs, * second. */ for (i = &dev->vq; *i; i = &(*i)->next); *i = vq; - - /* Set the routine to call when the Guest does something to this - * virtqueue. */ - vq->handle_output = handle_output; - - /* As an optimization, set the advisory "Don't Notify Me" flag if we - * don't have a handler */ - if (!handle_output) - vq->vring.used->flags = VRING_USED_F_NO_NOTIFY; } /* The first half of the feature bitmask is for us to advertise features. The @@ -1219,7 +1087,7 @@ static void add_feature(struct device *dev, unsigned bit) /* We can't extend the feature bits once we've added config bytes */ if (dev->desc->feature_len <= bit / CHAR_BIT) { assert(dev->desc->config_len == 0); - dev->desc->feature_len = (bit / CHAR_BIT) + 1; + dev->feature_len = dev->desc->feature_len = (bit/CHAR_BIT) + 1; } features[bit / CHAR_BIT] |= (1 << (bit % CHAR_BIT)); @@ -1243,22 +1111,17 @@ static void set_config(struct device *dev, unsigned len, const void *conf) * calling new_dev_desc() to allocate the descriptor and device memory. * * See what I mean about userspace being boring? */ -static struct device *new_device(const char *name, u16 type, int fd, - bool (*handle_input)(int, struct device *)) +static struct device *new_device(const char *name, u16 type) { struct device *dev = malloc(sizeof(*dev)); /* Now we populate the fields one at a time. */ - dev->fd = fd; - /* If we have an input handler for this file descriptor, then we add it - * to the device_list's fdset and maxfd. */ - if (handle_input) - add_device_fd(dev->fd); dev->desc = new_dev_desc(type); - dev->handle_input = handle_input; dev->name = name; dev->vq = NULL; - dev->ready = NULL; + dev->feature_len = 0; + dev->num_vq = 0; + dev->running = false; /* Append to device list. Prepending to a single-linked list is * easier, but the user expects the devices to be arranged on the bus @@ -1286,13 +1149,10 @@ static void setup_console(void) * raw input stream to the Guest. */ term.c_lflag &= ~(ISIG|ICANON|ECHO); tcsetattr(STDIN_FILENO, TCSANOW, &term); - /* If we exit gracefully, the original settings will be - * restored so the user can see what they're typing. */ - atexit(restore_term); } - dev = new_device("console", VIRTIO_ID_CONSOLE, - STDIN_FILENO, handle_console_input); + dev = new_device("console", VIRTIO_ID_CONSOLE); + /* We store the console state in dev->priv, and initialize it. */ dev->priv = malloc(sizeof(struct console_abort)); ((struct console_abort *)dev->priv)->count = 0; @@ -1301,31 +1161,13 @@ static void setup_console(void) * they put something the input queue, we make sure we're listening to * stdin. When they put something in the output queue, we write it to * stdout. */ - add_virtqueue(dev, VIRTQUEUE_NUM, enable_fd); - add_virtqueue(dev, VIRTQUEUE_NUM, handle_console_output); + add_virtqueue(dev, VIRTQUEUE_NUM, console_input); + add_virtqueue(dev, VIRTQUEUE_NUM, console_output); - verbose("device %u: console\n", devices.device_num++); + verbose("device %u: console\n", ++devices.device_num); } /*:*/ -static void timeout_alarm(int sig) -{ - write(timeoutpipe[1], "", 1); -} - -static void setup_timeout(void) -{ - if (pipe(timeoutpipe) != 0) - err(1, "Creating timeout pipe"); - - if (fcntl(timeoutpipe[1], F_SETFL, - fcntl(timeoutpipe[1], F_GETFL) | O_NONBLOCK) != 0) - err(1, "Making timeout pipe nonblocking"); - - add_device_fd(timeoutpipe[0]); - signal(SIGALRM, timeout_alarm); -} - /*M:010 Inter-guest networking is an interesting area. Simplest is to have a * --sharenet= option which opens or creates a named pipe. This can be * used to send packets to another guest in a 1:1 manner. @@ -1447,21 +1289,23 @@ static int get_tun_device(char tapif[IFNAMSIZ]) static void setup_tun_net(char *arg) { struct device *dev; - int netfd, ipfd; + struct net_info *net_info = malloc(sizeof(*net_info)); + int ipfd; u32 ip = INADDR_ANY; bool bridging = false; char tapif[IFNAMSIZ], *p; struct virtio_net_config conf; - netfd = get_tun_device(tapif); + net_info->tunfd = get_tun_device(tapif); /* First we create a new network device. */ - dev = new_device("net", VIRTIO_ID_NET, netfd, handle_tun_input); + dev = new_device("net", VIRTIO_ID_NET); + dev->priv = net_info; /* Network devices need a receive and a send queue, just like * console. */ - add_virtqueue(dev, VIRTQUEUE_NUM, net_enable_fd); - add_virtqueue(dev, VIRTQUEUE_NUM, handle_net_output); + add_virtqueue(dev, VIRTQUEUE_NUM, net_input); + add_virtqueue(dev, VIRTQUEUE_NUM, net_output); /* We need a socket to perform the magic network ioctls to bring up the * tap interface, connect to the bridge etc. Any socket will do! */ @@ -1502,6 +1346,8 @@ static void setup_tun_net(char *arg) add_feature(dev, VIRTIO_NET_F_HOST_TSO4); add_feature(dev, VIRTIO_NET_F_HOST_TSO6); add_feature(dev, VIRTIO_NET_F_HOST_ECN); + /* We handle indirect ring entries */ + add_feature(dev, VIRTIO_RING_F_INDIRECT_DESC); set_config(dev, sizeof(conf), &conf); /* We don't need the socket any more; setup is done. */ @@ -1550,20 +1396,18 @@ struct vblk_info * Remember that the block device is handled by a separate I/O thread. We head * straight into the core of that thread here: */ -static bool service_io(struct device *dev) +static void blk_request(struct virtqueue *vq) { - struct vblk_info *vblk = dev->priv; + struct vblk_info *vblk = vq->dev->priv; unsigned int head, out_num, in_num, wlen; int ret; u8 *in; struct virtio_blk_outhdr *out; - struct iovec iov[dev->vq->vring.num]; + struct iovec iov[vq->vring.num]; off64_t off; - /* See if there's a request waiting. If not, nothing to do. */ - head = get_vq_desc(dev->vq, iov, &out_num, &in_num); - if (head == dev->vq->vring.num) - return false; + /* Get the next request. */ + head = wait_for_vq_desc(vq, iov, &out_num, &in_num); /* Every block request should contain at least one output buffer * (detailing the location on disk and the type of request) and one @@ -1637,83 +1481,21 @@ static bool service_io(struct device *dev) if (out->type & VIRTIO_BLK_T_BARRIER) fdatasync(vblk->fd); - /* We can't trigger an IRQ, because we're not the Launcher. It does - * that when we tell it we're done. */ - add_used(dev->vq, head, wlen); - return true; -} - -/* This is the thread which actually services the I/O. */ -static int io_thread(void *_dev) -{ - struct device *dev = _dev; - struct vblk_info *vblk = dev->priv; - char c; - - /* Close other side of workpipe so we get 0 read when main dies. */ - close(vblk->workpipe[1]); - /* Close the other side of the done_fd pipe. */ - close(dev->fd); - - /* When this read fails, it means Launcher died, so we follow. */ - while (read(vblk->workpipe[0], &c, 1) == 1) { - /* We acknowledge each request immediately to reduce latency, - * rather than waiting until we've done them all. I haven't - * measured to see if it makes any difference. - * - * That would be an interesting test, wouldn't it? You could - * also try having more than one I/O thread. */ - while (service_io(dev)) - write(vblk->done_fd, &c, 1); - } - return 0; -} - -/* Now we've seen the I/O thread, we return to the Launcher to see what happens - * when that thread tells us it's completed some I/O. */ -static bool handle_io_finish(int fd, struct device *dev) -{ - char c; - - /* If the I/O thread died, presumably it printed the error, so we - * simply exit. */ - if (read(dev->fd, &c, 1) != 1) - exit(1); - - /* It did some work, so trigger the irq. */ - trigger_irq(fd, dev->vq); - return true; -} - -/* When the Guest submits some I/O, we just need to wake the I/O thread. */ -static void handle_virtblk_output(int fd, struct virtqueue *vq, bool timeout) -{ - struct vblk_info *vblk = vq->dev->priv; - char c = 0; - - /* Wake up I/O thread and tell it to go to work! */ - if (write(vblk->workpipe[1], &c, 1) != 1) - /* Presumably it indicated why it died. */ - exit(1); + add_used(vq, head, wlen); } /*L:198 This actually sets up a virtual block device. */ static void setup_block_file(const char *filename) { - int p[2]; struct device *dev; struct vblk_info *vblk; - void *stack; struct virtio_blk_config conf; - /* This is the pipe the I/O thread will use to tell us I/O is done. */ - pipe(p); - /* The device responds to return from I/O thread. */ - dev = new_device("block", VIRTIO_ID_BLOCK, p[0], handle_io_finish); + dev = new_device("block", VIRTIO_ID_BLOCK); /* The device has one virtqueue, where the Guest places requests. */ - add_virtqueue(dev, VIRTQUEUE_NUM, handle_virtblk_output); + add_virtqueue(dev, VIRTQUEUE_NUM, blk_request); /* Allocate the room for our own bookkeeping */ vblk = dev->priv = malloc(sizeof(*vblk)); @@ -1735,49 +1517,29 @@ static void setup_block_file(const char *filename) set_config(dev, sizeof(conf), &conf); - /* The I/O thread writes to this end of the pipe when done. */ - vblk->done_fd = p[1]; - - /* This is the second pipe, which is how we tell the I/O thread about - * more work. */ - pipe(vblk->workpipe); - - /* Create stack for thread and run it. Since stack grows upwards, we - * point the stack pointer to the end of this region. */ - stack = malloc(32768); - /* SIGCHLD - We dont "wait" for our cloned thread, so prevent it from - * becoming a zombie. */ - if (clone(io_thread, stack + 32768, CLONE_VM | SIGCHLD, dev) == -1) - err(1, "Creating clone"); - - /* We don't need to keep the I/O thread's end of the pipes open. */ - close(vblk->done_fd); - close(vblk->workpipe[0]); - verbose("device %u: virtblock %llu sectors\n", - devices.device_num, le64_to_cpu(conf.capacity)); + ++devices.device_num, le64_to_cpu(conf.capacity)); } +struct rng_info { + int rfd; +}; + /* Our random number generator device reads from /dev/random into the Guest's * input buffers. The usual case is that the Guest doesn't want random numbers * and so has no buffers although /dev/random is still readable, whereas * console is the reverse. * * The same logic applies, however. */ -static bool handle_rng_input(int fd, struct device *dev) +static void rng_input(struct virtqueue *vq) { int len; unsigned int head, in_num, out_num, totlen = 0; - struct iovec iov[dev->vq->vring.num]; + struct rng_info *rng_info = vq->dev->priv; + struct iovec iov[vq->vring.num]; /* First we need a buffer from the Guests's virtqueue. */ - head = get_vq_desc(dev->vq, iov, &out_num, &in_num); - - /* If they're not ready for input, stop listening to this file - * descriptor. We'll start again once they add an input buffer. */ - if (head == dev->vq->vring.num) - return false; - + head = wait_for_vq_desc(vq, iov, &out_num, &in_num); if (out_num) errx(1, "Output buffers in rng?"); @@ -1785,7 +1547,7 @@ static bool handle_rng_input(int fd, struct device *dev) * it reads straight into the Guest's buffer. We loop to make sure we * fill it. */ while (!iov_empty(iov, in_num)) { - len = readv(dev->fd, iov, in_num); + len = readv(rng_info->rfd, iov, in_num); if (len <= 0) err(1, "Read from /dev/random gave %i", len); iov_consume(iov, in_num, len); @@ -1793,25 +1555,23 @@ static bool handle_rng_input(int fd, struct device *dev) } /* Tell the Guest about the new input. */ - add_used_and_trigger(fd, dev->vq, head, totlen); - - /* Everything went OK! */ - return true; + add_used(vq, head, totlen); } /* And this creates a "hardware" random number device for the Guest. */ static void setup_rng(void) { struct device *dev; - int fd; + struct rng_info *rng_info = malloc(sizeof(*rng_info)); - fd = open_or_die("/dev/random", O_RDONLY); + rng_info->rfd = open_or_die("/dev/random", O_RDONLY); /* The device responds to return from I/O thread. */ - dev = new_device("rng", VIRTIO_ID_RNG, fd, handle_rng_input); + dev = new_device("rng", VIRTIO_ID_RNG); + dev->priv = rng_info; /* The device has one virtqueue, where the Guest places inbufs. */ - add_virtqueue(dev, VIRTQUEUE_NUM, enable_fd); + add_virtqueue(dev, VIRTQUEUE_NUM, rng_input); verbose("device %u: rng\n", devices.device_num++); } @@ -1827,17 +1587,18 @@ static void __attribute__((noreturn)) restart_guest(void) for (i = 3; i < FD_SETSIZE; i++) close(i); - /* The exec automatically gets rid of the I/O and Waker threads. */ + /* Reset all the devices (kills all threads). */ + cleanup_devices(); + execv(main_args[0], main_args); err(1, "Could not exec %s", main_args[0]); } /*L:220 Finally we reach the core of the Launcher which runs the Guest, serves * its input and output, and finally, lays it to rest. */ -static void __attribute__((noreturn)) run_guest(int lguest_fd) +static void __attribute__((noreturn)) run_guest(void) { for (;;) { - unsigned long args[] = { LHREQ_BREAK, 0 }; unsigned long notify_addr; int readval; @@ -1848,8 +1609,7 @@ static void __attribute__((noreturn)) run_guest(int lguest_fd) /* One unsigned long means the Guest did HCALL_NOTIFY */ if (readval == sizeof(notify_addr)) { verbose("Notify on address %#lx\n", notify_addr); - handle_output(lguest_fd, notify_addr); - continue; + handle_output(notify_addr); /* ENOENT means the Guest died. Reading tells us why. */ } else if (errno == ENOENT) { char reason[1024] = { 0 }; @@ -1858,19 +1618,9 @@ static void __attribute__((noreturn)) run_guest(int lguest_fd) /* ERESTART means that we need to reboot the guest */ } else if (errno == ERESTART) { restart_guest(); - /* EAGAIN means a signal (timeout). - * Anything else means a bug or incompatible change. */ - } else if (errno != EAGAIN) + /* Anything else means a bug or incompatible change. */ + } else err(1, "Running guest failed"); - - /* Only service input on thread for CPU 0. */ - if (cpu_id != 0) - continue; - - /* Service input, then unset the BREAK to release the Waker. */ - handle_input(lguest_fd); - if (pwrite(lguest_fd, args, sizeof(args), cpu_id) < 0) - err(1, "Resetting break"); } } /*L:240 @@ -1904,8 +1654,8 @@ int main(int argc, char *argv[]) /* Memory, top-level pagetable, code startpoint and size of the * (optional) initrd. */ unsigned long mem = 0, start, initrd_size = 0; - /* Two temporaries and the /dev/lguest file descriptor. */ - int i, c, lguest_fd; + /* Two temporaries. */ + int i, c; /* The boot information for the Guest. */ struct boot_params *boot; /* If they specify an initrd file to load. */ @@ -1913,18 +1663,10 @@ int main(int argc, char *argv[]) /* Save the args: we "reboot" by execing ourselves again. */ main_args = argv; - /* We don't "wait" for the children, so prevent them from becoming - * zombies. */ - signal(SIGCHLD, SIG_IGN); - /* First we initialize the device list. Since console and network - * device receive input from a file descriptor, we keep an fdset - * (infds) and the maximum fd number (max_infd) with the head of the - * list. We also keep a pointer to the last device. Finally, we keep - * the next interrupt number to use for devices (1: remember that 0 is - * used by the timer). */ - FD_ZERO(&devices.infds); - devices.max_infd = -1; + /* First we initialize the device list. We keep a pointer to the last + * device, and the next interrupt number to use for devices (1: + * remember that 0 is used by the timer). */ devices.lastdev = NULL; devices.next_irq = 1; @@ -1982,9 +1724,6 @@ int main(int argc, char *argv[]) /* We always have a console device */ setup_console(); - /* We can timeout waiting for Guest network transmit. */ - setup_timeout(); - /* Now we load the kernel */ start = load_kernel(open_or_die(argv[optind+1], O_RDONLY)); @@ -2023,15 +1762,16 @@ int main(int argc, char *argv[]) /* We tell the kernel to initialize the Guest: this returns the open * /dev/lguest file descriptor. */ - lguest_fd = tell_kernel(start); + tell_kernel(start); - /* We clone off a thread, which wakes the Launcher whenever one of the - * input file descriptors needs attention. We call this the Waker, and - * we'll cover it in a moment. */ - setup_waker(lguest_fd); + /* Ensure that we terminate if a child dies. */ + signal(SIGCHLD, kill_launcher); + + /* If we exit via err(), this kills all the threads, restores tty. */ + atexit(cleanup_devices); /* Finally, run the Guest. This doesn't return. */ - run_guest(lguest_fd); + run_guest(); } /*:*/ diff --git a/Documentation/lguest/lguest.txt b/Documentation/lguest/lguest.txt index 28c747362f95..efb3a6a045a2 100644 --- a/Documentation/lguest/lguest.txt +++ b/Documentation/lguest/lguest.txt @@ -37,7 +37,6 @@ Running Lguest: "Paravirtualized guest support" = Y "Lguest guest support" = Y "High Memory Support" = off/4GB - "PAE (Physical Address Extension) Support" = N "Alignment value to which kernel should be aligned" = 0x100000 (CONFIG_PARAVIRT=y, CONFIG_LGUEST_GUEST=y, CONFIG_HIGHMEM64G=n and CONFIG_PHYSICAL_ALIGN=0x100000) diff --git a/Documentation/local_ops.txt b/Documentation/local_ops.txt index 23045b8b50f0..300da4bdfdbd 100644 --- a/Documentation/local_ops.txt +++ b/Documentation/local_ops.txt @@ -34,7 +34,7 @@ out of order wrt other memory writes by the owner CPU. It can be done by slightly modifying the standard atomic operations : only their UP variant must be kept. It typically means removing LOCK prefix (on -i386 and x86_64) and any SMP sychronization barrier. If the architecture does +i386 and x86_64) and any SMP synchronization barrier. If the architecture does not have a different behavior between SMP and UP, including asm-generic/local.h in your architecture's local.h is sufficient. diff --git a/Documentation/memory-barriers.txt b/Documentation/memory-barriers.txt index f5b7127f54ac..7f5809eddee6 100644 --- a/Documentation/memory-barriers.txt +++ b/Documentation/memory-barriers.txt @@ -31,6 +31,7 @@ Contents: - Locking functions. - Interrupt disabling functions. + - Sleep and wake-up functions. - Miscellaneous functions. (*) Inter-CPU locking barrier effects. @@ -1217,6 +1218,132 @@ barriers are required in such a situation, they must be provided from some other means. +SLEEP AND WAKE-UP FUNCTIONS +--------------------------- + +Sleeping and waking on an event flagged in global data can be viewed as an +interaction between two pieces of data: the task state of the task waiting for +the event and the global data used to indicate the event. To make sure that +these appear to happen in the right order, the primitives to begin the process +of going to sleep, and the primitives to initiate a wake up imply certain +barriers. + +Firstly, the sleeper normally follows something like this sequence of events: + + for (;;) { + set_current_state(TASK_UNINTERRUPTIBLE); + if (event_indicated) + break; + schedule(); + } + +A general memory barrier is interpolated automatically by set_current_state() +after it has altered the task state: + + CPU 1 + =============================== + set_current_state(); + set_mb(); + STORE current->state + + LOAD event_indicated + +set_current_state() may be wrapped by: + + prepare_to_wait(); + prepare_to_wait_exclusive(); + +which therefore also imply a general memory barrier after setting the state. +The whole sequence above is available in various canned forms, all of which +interpolate the memory barrier in the right place: + + wait_event(); + wait_event_interruptible(); + wait_event_interruptible_exclusive(); + wait_event_interruptible_timeout(); + wait_event_killable(); + wait_event_timeout(); + wait_on_bit(); + wait_on_bit_lock(); + + +Secondly, code that performs a wake up normally follows something like this: + + event_indicated = 1; + wake_up(&event_wait_queue); + +or: + + event_indicated = 1; + wake_up_process(event_daemon); + +A write memory barrier is implied by wake_up() and co. if and only if they wake +something up. The barrier occurs before the task state is cleared, and so sits +between the STORE to indicate the event and the STORE to set TASK_RUNNING: + + CPU 1 CPU 2 + =============================== =============================== + set_current_state(); STORE event_indicated + set_mb(); wake_up(); + STORE current->state + STORE current->state + LOAD event_indicated + +The available waker functions include: + + complete(); + wake_up(); + wake_up_all(); + wake_up_bit(); + wake_up_interruptible(); + wake_up_interruptible_all(); + wake_up_interruptible_nr(); + wake_up_interruptible_poll(); + wake_up_interruptible_sync(); + wake_up_interruptible_sync_poll(); + wake_up_locked(); + wake_up_locked_poll(); + wake_up_nr(); + wake_up_poll(); + wake_up_process(); + + +[!] Note that the memory barriers implied by the sleeper and the waker do _not_ +order multiple stores before the wake-up with respect to loads of those stored +values after the sleeper has called set_current_state(). For instance, if the +sleeper does: + + set_current_state(TASK_INTERRUPTIBLE); + if (event_indicated) + break; + __set_current_state(TASK_RUNNING); + do_something(my_data); + +and the waker does: + + my_data = value; + event_indicated = 1; + wake_up(&event_wait_queue); + +there's no guarantee that the change to event_indicated will be perceived by +the sleeper as coming after the change to my_data. In such a circumstance, the +code on both sides must interpolate its own memory barriers between the +separate data accesses. Thus the above sleeper ought to do: + + set_current_state(TASK_INTERRUPTIBLE); + if (event_indicated) { + smp_rmb(); + do_something(my_data); + } + +and the waker should do: + + my_data = value; + smp_wmb(); + event_indicated = 1; + wake_up(&event_wait_queue); + + MISCELLANEOUS FUNCTIONS ----------------------- @@ -1366,7 +1493,7 @@ WHERE ARE MEMORY BARRIERS NEEDED? Under normal operation, memory operation reordering is generally not going to be a problem as a single-threaded linear piece of code will still appear to -work correctly, even if it's in an SMP kernel. There are, however, three +work correctly, even if it's in an SMP kernel. There are, however, four circumstances in which reordering definitely _could_ be a problem: (*) Interprocessor interaction. diff --git a/Documentation/memory-hotplug.txt b/Documentation/memory-hotplug.txt index 4c2ecf537a4a..bbc8a6a36921 100644 --- a/Documentation/memory-hotplug.txt +++ b/Documentation/memory-hotplug.txt @@ -73,13 +73,13 @@ this phase is triggered automatically. ACPI can notify this event. If not, (see Section 4.). Logical Memory Hotplug phase is to change memory state into -avaiable/unavailable for users. Amount of memory from user's view is +available/unavailable for users. Amount of memory from user's view is changed by this phase. The kernel makes all memory in it as free pages when a memory range is available. In this document, this phase is described as online/offline. -Logical Memory Hotplug phase is triggred by write of sysfs file by system +Logical Memory Hotplug phase is triggered by write of sysfs file by system administrator. For the hot-add case, it must be executed after Physical Hotplug phase by hand. (However, if you writes udev's hotplug scripts for memory hotplug, these @@ -334,7 +334,7 @@ MEMORY_CANCEL_ONLINE Generated if MEMORY_GOING_ONLINE fails. MEMORY_ONLINE - Generated when memory has succesfully brought online. The callback may + Generated when memory has successfully brought online. The callback may allocate pages from the new memory. MEMORY_GOING_OFFLINE @@ -359,7 +359,7 @@ The third argument is passed by pointer of struct memory_notify. struct memory_notify { unsigned long start_pfn; unsigned long nr_pages; - int status_cahnge_nid; + int status_change_nid; } start_pfn is start_pfn of online/offline memory. diff --git a/Documentation/mn10300/ABI.txt b/Documentation/mn10300/ABI.txt index 1fef1f06dfd2..d3507bad428d 100644 --- a/Documentation/mn10300/ABI.txt +++ b/Documentation/mn10300/ABI.txt @@ -26,7 +26,7 @@ registers and the stack. If the first argument is a 64-bit value, it will be passed in D0:D1. If the first argument is not a 64-bit value, but the second is, the second will be passed entirely on the stack and D1 will be unused. -Arguments smaller than 32-bits are not coelesced within a register or a stack +Arguments smaller than 32-bits are not coalesced within a register or a stack word. For example, two byte-sized arguments will always be passed in separate registers or word-sized stack slots. diff --git a/Documentation/mtd/nand_ecc.txt b/Documentation/mtd/nand_ecc.txt index bdf93b7f0f24..274821b35a7f 100644 --- a/Documentation/mtd/nand_ecc.txt +++ b/Documentation/mtd/nand_ecc.txt @@ -50,7 +50,7 @@ byte 255: bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 rp1 rp3 rp5 ... rp15 cp5 cp5 cp5 cp5 cp4 cp4 cp4 cp4 This figure represents a sector of 256 bytes. -cp is my abbreviaton for column parity, rp for row parity. +cp is my abbreviation for column parity, rp for row parity. Let's start to explain column parity. cp0 is the parity that belongs to all bit0, bit2, bit4, bit6. @@ -560,7 +560,7 @@ Measuring this code again showed big gain. When executing the original linux code 1 million times, this took about 1 second on my system. (using time to measure the performance). After this iteration I was back to 0.075 sec. Actually I had to decide to start measuring over 10 -million interations in order not to loose too much accuracy. This one +million iterations in order not to lose too much accuracy. This one definitely seemed to be the jackpot! There is a little bit more room for improvement though. There are three @@ -571,8 +571,8 @@ loop; This eliminates 3 statements per loop. Of course after the loop we need to correct by adding: rp4 ^= rp4_6; rp6 ^= rp4_6 -Furthermore there are 4 sequential assingments to rp8. This can be -encoded slightly more efficient by saving tmppar before those 4 lines +Furthermore there are 4 sequential assignments to rp8. This can be +encoded slightly more efficiently by saving tmppar before those 4 lines and later do rp8 = rp8 ^ tmppar ^ notrp8; (where notrp8 is the value of rp8 before those 4 lines). Again a use of the commutative property of xor. @@ -622,7 +622,7 @@ Not a big change, but every penny counts :-) Analysis 7 ========== -Acutally this made things worse. Not very much, but I don't want to move +Actually this made things worse. Not very much, but I don't want to move into the wrong direction. Maybe something to investigate later. Could have to do with caching again. @@ -642,7 +642,7 @@ Analysis 8 This makes things worse. Let's stick with attempt 6 and continue from there. Although it seems that the code within the loop cannot be optimised further there is still room to optimize the generation of the ecc codes. -We can simply calcualate the total parity. If this is 0 then rp4 = rp5 +We can simply calculate the total parity. If this is 0 then rp4 = rp5 etc. If the parity is 1, then rp4 = !rp5; But if rp4 = rp5 we do not need rp5 etc. We can just write the even bits in the result byte and then do something like diff --git a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt index 08762750f121..d5181ce9ff62 100644 --- a/Documentation/networking/bonding.txt +++ b/Documentation/networking/bonding.txt @@ -221,7 +221,7 @@ ad_select - Any slave's 802.3ad association state changes - - The bond's adminstrative state changes to up + - The bond's administrative state changes to up count or 2 @@ -369,7 +369,7 @@ fail_over_mac 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 + susceptible to loss of the gratuitous ARP, and an appropriate updelay setting may be required. follow or 2 @@ -1794,7 +1794,7 @@ target to query. generally referred to as "trunk failover." This is a feature of the switch that causes the link state of a particular switch port to be set down (or up) when the state of another switch port goes down (or up). -It's purpose is to propogate link failures from logically "exterior" ports +Its purpose is to propagate link failures from logically "exterior" ports to the logically "interior" ports that bonding is able to monitor via miimon. Availability and configuration for trunk failover varies by switch, but this can be a viable alternative to the ARP monitor when using diff --git a/Documentation/networking/can.txt b/Documentation/networking/can.txt index 2035bc4932f2..cd79735013f9 100644 --- a/Documentation/networking/can.txt +++ b/Documentation/networking/can.txt @@ -36,10 +36,15 @@ This file contains 6.2 local loopback of sent frames 6.3 CAN controller hardware filters 6.4 The virtual CAN driver (vcan) - 6.5 currently supported CAN hardware - 6.6 todo + 6.5 The CAN network device driver interface + 6.5.1 Netlink interface to set/get devices properties + 6.5.2 Setting the CAN bit-timing + 6.5.3 Starting and stopping the CAN network device + 6.6 supported CAN hardware - 7 Credits + 7 Socket CAN resources + + 8 Credits ============================================================================ @@ -234,6 +239,8 @@ solution for a couple of reasons: the user application using the common CAN filter mechanisms. Inside this filter definition the (interested) type of errors may be selected. The reception of error frames is disabled by default. + The format of the CAN error frame is briefly decribed in the Linux + header file "include/linux/can/error.h". 4. How to use Socket CAN ------------------------ @@ -327,7 +334,7 @@ solution for a couple of reasons: return 1; } - /* paraniod check ... */ + /* paranoid check ... */ if (nbytes < sizeof(struct can_frame)) { fprintf(stderr, "read: incomplete CAN frame\n"); return 1; @@ -605,61 +612,213 @@ solution for a couple of reasons: removal of vcan network devices can be managed with the ip(8) tool: - Create a virtual CAN network interface: - ip link add type vcan + $ ip link add type vcan - Create a virtual CAN network interface with a specific name 'vcan42': - ip link add dev vcan42 type vcan + $ ip link add dev vcan42 type vcan - Remove a (virtual CAN) network interface 'vcan42': - ip link del vcan42 + $ ip link del vcan42 - The tool 'vcan' from the SocketCAN SVN repository on BerliOS is obsolete. + 6.5 The CAN network device driver interface - Virtual CAN network device creation in older Kernels: - In Linux Kernel versions < 2.6.24 the vcan driver creates 4 vcan - netdevices at module load time by default. This value can be changed - with the module parameter 'numdev'. E.g. 'modprobe vcan numdev=8' + The CAN network device driver interface provides a generic interface + to setup, configure and monitor CAN network devices. The user can then + configure the CAN device, like setting the bit-timing parameters, via + the netlink interface using the program "ip" from the "IPROUTE2" + utility suite. The following chapter describes briefly how to use it. + Furthermore, the interface uses a common data structure and exports a + set of common functions, which all real CAN network device drivers + should use. Please have a look to the SJA1000 or MSCAN driver to + understand how to use them. The name of the module is can-dev.ko. - 6.5 currently supported CAN hardware + 6.5.1 Netlink interface to set/get devices properties - On the project website http://developer.berlios.de/projects/socketcan - there are different drivers available: + The CAN device must be configured via netlink interface. The supported + netlink message types are defined and briefly described in + "include/linux/can/netlink.h". CAN link support for the program "ip" + of the IPROUTE2 utility suite is avaiable and it can be used as shown + below: - vcan: Virtual CAN interface driver (if no real hardware is available) - sja1000: Philips SJA1000 CAN controller (recommended) - i82527: Intel i82527 CAN controller - mscan: Motorola/Freescale CAN controller (e.g. inside SOC MPC5200) - ccan: CCAN controller core (e.g. inside SOC h7202) - slcan: For a bunch of CAN adaptors that are attached via a - serial line ASCII protocol (for serial / USB adaptors) + - Setting CAN device properties: - Additionally the different CAN adaptors (ISA/PCI/PCMCIA/USB/Parport) - from PEAK Systemtechnik support the CAN netdevice driver model - since Linux driver v6.0: http://www.peak-system.com/linux/index.htm + $ ip link set can0 type can help + Usage: ip link set DEVICE type can + [ bitrate BITRATE [ sample-point SAMPLE-POINT] ] | + [ tq TQ prop-seg PROP_SEG phase-seg1 PHASE-SEG1 + phase-seg2 PHASE-SEG2 [ sjw SJW ] ] - Please check the Mailing Lists on the berlios OSS project website. + [ loopback { on | off } ] + [ listen-only { on | off } ] + [ triple-sampling { on | off } ] - 6.6 todo + [ restart-ms TIME-MS ] + [ restart ] - The configuration interface for CAN network drivers is still an open - issue that has not been finalized in the socketcan project. Also the - idea of having a library module (candev.ko) that holds functions - that are needed by all CAN netdevices is not ready to ship. - Your contribution is welcome. + Where: BITRATE := { 1..1000000 } + SAMPLE-POINT := { 0.000..0.999 } + TQ := { NUMBER } + PROP-SEG := { 1..8 } + PHASE-SEG1 := { 1..8 } + PHASE-SEG2 := { 1..8 } + SJW := { 1..4 } + RESTART-MS := { 0 | NUMBER } -7. Credits + - Display CAN device details and statistics: + + $ ip -details -statistics link show can0 + 2: can0: mtu 16 qdisc pfifo_fast state UP qlen 10 + link/can + can state ERROR-ACTIVE restart-ms 100 + bitrate 125000 sample_point 0.875 + tq 125 prop-seg 6 phase-seg1 7 phase-seg2 2 sjw 1 + sja1000: tseg1 1..16 tseg2 1..8 sjw 1..4 brp 1..64 brp-inc 1 + clock 8000000 + re-started bus-errors arbit-lost error-warn error-pass bus-off + 41 17457 0 41 42 41 + RX: bytes packets errors dropped overrun mcast + 140859 17608 17457 0 0 0 + TX: bytes packets errors dropped carrier collsns + 861 112 0 41 0 0 + + More info to the above output: + + "" + Shows the list of selected CAN controller modes: LOOPBACK, + LISTEN-ONLY, or TRIPLE-SAMPLING. + + "state ERROR-ACTIVE" + The current state of the CAN controller: "ERROR-ACTIVE", + "ERROR-WARNING", "ERROR-PASSIVE", "BUS-OFF" or "STOPPED" + + "restart-ms 100" + Automatic restart delay time. If set to a non-zero value, a + restart of the CAN controller will be triggered automatically + in case of a bus-off condition after the specified delay time + in milliseconds. By default it's off. + + "bitrate 125000 sample_point 0.875" + Shows the real bit-rate in bits/sec and the sample-point in the + range 0.000..0.999. If the calculation of bit-timing parameters + is enabled in the kernel (CONFIG_CAN_CALC_BITTIMING=y), the + bit-timing can be defined by setting the "bitrate" argument. + Optionally the "sample-point" can be specified. By default it's + 0.000 assuming CIA-recommended sample-points. + + "tq 125 prop-seg 6 phase-seg1 7 phase-seg2 2 sjw 1" + Shows the time quanta in ns, propagation segment, phase buffer + segment 1 and 2 and the synchronisation jump width in units of + tq. They allow to define the CAN bit-timing in a hardware + independent format as proposed by the Bosch CAN 2.0 spec (see + chapter 8 of http://www.semiconductors.bosch.de/pdf/can2spec.pdf). + + "sja1000: tseg1 1..16 tseg2 1..8 sjw 1..4 brp 1..64 brp-inc 1 + clock 8000000" + Shows the bit-timing constants of the CAN controller, here the + "sja1000". The minimum and maximum values of the time segment 1 + and 2, the synchronisation jump width in units of tq, the + bitrate pre-scaler and the CAN system clock frequency in Hz. + These constants could be used for user-defined (non-standard) + bit-timing calculation algorithms in user-space. + + "re-started bus-errors arbit-lost error-warn error-pass bus-off" + Shows the number of restarts, bus and arbitration lost errors, + and the state changes to the error-warning, error-passive and + bus-off state. RX overrun errors are listed in the "overrun" + field of the standard network statistics. + + 6.5.2 Setting the CAN bit-timing + + The CAN bit-timing parameters can always be defined in a hardware + independent format as proposed in the Bosch CAN 2.0 specification + specifying the arguments "tq", "prop_seg", "phase_seg1", "phase_seg2" + and "sjw": + + $ ip link set canX type can tq 125 prop-seg 6 \ + phase-seg1 7 phase-seg2 2 sjw 1 + + If the kernel option CONFIG_CAN_CALC_BITTIMING is enabled, CIA + recommended CAN bit-timing parameters will be calculated if the bit- + rate is specified with the argument "bitrate": + + $ ip link set canX type can bitrate 125000 + + Note that this works fine for the most common CAN controllers with + standard bit-rates but may *fail* for exotic bit-rates or CAN system + clock frequencies. Disabling CONFIG_CAN_CALC_BITTIMING saves some + space and allows user-space tools to solely determine and set the + bit-timing parameters. The CAN controller specific bit-timing + constants can be used for that purpose. They are listed by the + following command: + + $ ip -details link show can0 + ... + sja1000: clock 8000000 tseg1 1..16 tseg2 1..8 sjw 1..4 brp 1..64 brp-inc 1 + + 6.5.3 Starting and stopping the CAN network device + + A CAN network device is started or stopped as usual with the command + "ifconfig canX up/down" or "ip link set canX up/down". Be aware that + you *must* define proper bit-timing parameters for real CAN devices + before you can start it to avoid error-prone default settings: + + $ ip link set canX up type can bitrate 125000 + + A device may enter the "bus-off" state if too much errors occurred on + the CAN bus. Then no more messages are received or sent. An automatic + bus-off recovery can be enabled by setting the "restart-ms" to a + non-zero value, e.g.: + + $ ip link set canX type can restart-ms 100 + + Alternatively, the application may realize the "bus-off" condition + by monitoring CAN error frames and do a restart when appropriate with + the command: + + $ ip link set canX type can restart + + Note that a restart will also create a CAN error frame (see also + chapter 3.4). + + 6.6 Supported CAN hardware + + Please check the "Kconfig" file in "drivers/net/can" to get an actual + list of the support CAN hardware. On the Socket CAN project website + (see chapter 7) there might be further drivers available, also for + older kernel versions. + +7. Socket CAN resources +----------------------- + + You can find further resources for Socket CAN like user space tools, + support for old kernel versions, more drivers, mailing lists, etc. + at the BerliOS OSS project website for Socket CAN: + + http://developer.berlios.de/projects/socketcan + + If you have questions, bug fixes, etc., don't hesitate to post them to + the Socketcan-Users mailing list. But please search the archives first. + +8. Credits ---------- - Oliver Hartkopp (PF_CAN core, filters, drivers, bcm) + Oliver Hartkopp (PF_CAN core, filters, drivers, bcm, SJA1000 driver) Urs Thuermann (PF_CAN core, kernel integration, socket interfaces, raw, vcan) Jan Kizka (RT-SocketCAN core, Socket-API reconciliation) - Wolfgang Grandegger (RT-SocketCAN core & drivers, Raw Socket-API reviews) + Wolfgang Grandegger (RT-SocketCAN core & drivers, Raw Socket-API reviews, + CAN device driver interface, MSCAN driver) Robert Schwebel (design reviews, PTXdist integration) Marc Kleine-Budde (design reviews, Kernel 2.6 cleanups, drivers) Benedikt Spranger (reviews) Thomas Gleixner (LKML reviews, coding style, posting hints) - Andrey Volkov (kernel subtree structure, ioctls, mscan driver) + Andrey Volkov (kernel subtree structure, ioctls, MSCAN driver) Matthias Brukner (first SJA1000 CAN netdevice implementation Q2/2003) Klaus Hitschler (PEAK driver integration) Uwe Koppe (CAN netdevices with PF_PACKET approach) Michael Schulze (driver layer loopback requirement, RT CAN drivers review) + Pavel Pisa (Bit-timing calculation) + Sascha Hauer (SJA1000 platform driver) + Sebastian Haas (SJA1000 EMS PCI driver) + Markus Plessing (SJA1000 EMS PCI driver) + Per Dalen (SJA1000 Kvaser PCI driver) + Sam Ravnborg (reviews, coding style, kbuild help) diff --git a/Documentation/networking/dm9000.txt b/Documentation/networking/dm9000.txt index 65df3dea5561..5552e2e575c5 100644 --- a/Documentation/networking/dm9000.txt +++ b/Documentation/networking/dm9000.txt @@ -129,7 +129,7 @@ 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 +about link (carrier) availability. 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 diff --git a/Documentation/networking/ieee802154.txt b/Documentation/networking/ieee802154.txt new file mode 100644 index 000000000000..a0280ad2edc9 --- /dev/null +++ b/Documentation/networking/ieee802154.txt @@ -0,0 +1,76 @@ + + Linux IEEE 802.15.4 implementation + + +Introduction +============ + +The Linux-ZigBee project goal is to provide complete implementation +of IEEE 802.15.4 / ZigBee / 6LoWPAN protocols. IEEE 802.15.4 is a stack +of protocols for organizing Low-Rate Wireless Personal Area Networks. + +Currently only IEEE 802.15.4 layer is implemented. We have choosen +to use plain Berkeley socket API, the generic Linux networking stack +to transfer IEEE 802.15.4 messages and a special protocol over genetlink +for configuration/management + + +Socket API +========== + +int sd = socket(PF_IEEE802154, SOCK_DGRAM, 0); +..... + +The address family, socket addresses etc. are defined in the +include/net/ieee802154/af_ieee802154.h header or in the special header +in our userspace package (see either linux-zigbee sourceforge download page +or git tree at git://linux-zigbee.git.sourceforge.net/gitroot/linux-zigbee). + +One can use SOCK_RAW for passing raw data towards device xmit function. YMMV. + + +MLME - MAC Level Management +============================ + +Most of IEEE 802.15.4 MLME interfaces are directly mapped on netlink commands. +See the include/net/ieee802154/nl802154.h header. Our userspace tools package +(see above) provides CLI configuration utility for radio interfaces and simple +coordinator for IEEE 802.15.4 networks as an example users of MLME protocol. + + +Kernel side +============= + +Like with WiFi, there are several types of devices implementing IEEE 802.15.4. +1) 'HardMAC'. The MAC layer is implemented in the device itself, the device + exports MLME and data API. +2) 'SoftMAC' or just radio. These types of devices are just radio transceivers + possibly with some kinds of acceleration like automatic CRC computation and + comparation, automagic ACK handling, address matching, etc. + +Those types of devices require different approach to be hooked into Linux kernel. + + +HardMAC +======= + +See the header include/net/ieee802154/netdevice.h. You have to implement Linux +net_device, with .type = ARPHRD_IEEE802154. Data is exchanged with socket family +code via plain sk_buffs. The control block of sk_buffs will contain additional +info as described in the struct ieee802154_mac_cb. + +To hook the MLME interface you have to populate the ml_priv field of your +net_device with a pointer to struct ieee802154_mlme_ops instance. All fields are +required. + +We provide an example of simple HardMAC driver at drivers/ieee802154/fakehard.c + + +SoftMAC +======= + +We are going to provide intermediate layer impelementing IEEE 802.15.4 MAC +in software. This is currently WIP. + +See header include/net/ieee802154/mac802154.h and several drivers in +drivers/ieee802154/ diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index b121c5db707f..8be76235fe67 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -168,7 +168,16 @@ tcp_dsack - BOOLEAN Allows TCP to send "duplicate" SACKs. tcp_ecn - BOOLEAN - Enable Explicit Congestion Notification in TCP. + Enable Explicit Congestion Notification (ECN) in TCP. ECN is only + used when both ends of the TCP flow support it. It is useful to + avoid losses due to congestion (when the bottleneck router supports + ECN). + Possible values are: + 0 disable ECN + 1 ECN enabled + 2 Only server-side ECN enabled. If the other end does + not support ECN, behavior is like with ECN disabled. + Default: 2 tcp_fack - BOOLEAN Enable FACK congestion avoidance and fast retransmission. @@ -1048,6 +1057,13 @@ disable_ipv6 - BOOLEAN address. Default: FALSE (enable IPv6 operation) + When this value is changed from 1 to 0 (IPv6 is being enabled), + it will dynamically create a link-local address on the given + interface and start Duplicate Address Detection, if necessary. + + When this value is changed from 0 to 1 (IPv6 is being disabled), + it will dynamically delete all address on the given interface. + accept_dad - INTEGER Whether to accept DAD (Duplicate Address Detection). 0: Disable DAD diff --git a/Documentation/networking/ipv6.txt b/Documentation/networking/ipv6.txt index 268e5c103dd8..9fd7e21296c8 100644 --- a/Documentation/networking/ipv6.txt +++ b/Documentation/networking/ipv6.txt @@ -33,3 +33,40 @@ disable A reboot is required to enable IPv6. +autoconf + + Specifies whether to enable IPv6 address autoconfiguration + on all interfaces. This might be used when one does not wish + for addresses to be automatically generated from prefixes + received in Router Advertisements. + + The possible values and their effects are: + + 0 + IPv6 address autoconfiguration is disabled on all interfaces. + + Only the IPv6 loopback address (::1) and link-local addresses + will be added to interfaces. + + 1 + IPv6 address autoconfiguration is enabled on all interfaces. + + This is the default value. + +disable_ipv6 + + Specifies whether to disable IPv6 on all interfaces. + This might be used when no IPv6 addresses are desired. + + The possible values and their effects are: + + 0 + IPv6 is enabled on all interfaces. + + This is the default value. + + 1 + IPv6 is disabled on all interfaces. + + No IPv6 addresses will be added to interfaces. + diff --git a/Documentation/networking/l2tp.txt b/Documentation/networking/l2tp.txt index 2451f551c505..63214b280e00 100644 --- a/Documentation/networking/l2tp.txt +++ b/Documentation/networking/l2tp.txt @@ -158,7 +158,7 @@ Sample Userspace Code } return 0; -Miscellanous +Miscellaneous ============ The PPPoL2TP driver was developed as part of the OpenL2TP project by diff --git a/Documentation/networking/mac80211-injection.txt b/Documentation/networking/mac80211-injection.txt index 84906ef3ed6e..b30e81ad5307 100644 --- a/Documentation/networking/mac80211-injection.txt +++ b/Documentation/networking/mac80211-injection.txt @@ -12,38 +12,22 @@ following format: The radiotap format is discussed in ./Documentation/networking/radiotap-headers.txt. -Despite 13 radiotap argument types are currently defined, most only make sense +Despite many radiotap parameters being currently defined, most only make sense to appear on received packets. The following information is parsed from the radiotap headers and used to control injection: - * IEEE80211_RADIOTAP_RATE - - rate in 500kbps units, automatic if invalid or not present - - - * IEEE80211_RADIOTAP_ANTENNA - - antenna to use, automatic if not present - - - * IEEE80211_RADIOTAP_DBM_TX_POWER - - transmit power in dBm, automatic if not present - - * IEEE80211_RADIOTAP_FLAGS IEEE80211_RADIOTAP_F_FCS: FCS will be removed and recalculated IEEE80211_RADIOTAP_F_WEP: frame will be encrypted if key available IEEE80211_RADIOTAP_F_FRAG: frame will be fragmented if longer than the - current fragmentation threshold. Note that - this flag is only reliable when software - fragmentation is enabled) + current fragmentation threshold. + The injection code can also skip all other currently defined radiotap fields facilitating replay of captured radiotap headers directly. -Here is an example valid radiotap header defining these three parameters +Here is an example valid radiotap header defining some parameters 0x00, 0x00, // <-- radiotap version 0x0b, 0x00, // <- radiotap header length @@ -72,8 +56,8 @@ interface), along the following lines: ... r = pcap_inject(ppcap, u8aSendBuffer, nLength); -You can also find sources for a complete inject test applet here: +You can also find a link to a complete inject application here: -http://penumbra.warmcat.com/_twk/tiki-index.php?page=packetspammer +http://wireless.kernel.org/en/users/Documentation/packetspammer Andy Green diff --git a/Documentation/networking/netdevices.txt b/Documentation/networking/netdevices.txt index a2ab6a0b116d..87b3d15f523a 100644 --- a/Documentation/networking/netdevices.txt +++ b/Documentation/networking/netdevices.txt @@ -74,7 +74,7 @@ dev->hard_start_xmit: for this and return NETDEV_TX_LOCKED when the spin lock fails. The locking there should also properly protect against set_multicast_list. Note that the use of NETIF_F_LLTX is deprecated. - Dont use it for new drivers. + Don't use it for new drivers. Context: Process with BHs disabled or BH (timer), will be called with interrupts disabled by netconsole. diff --git a/Documentation/networking/operstates.txt b/Documentation/networking/operstates.txt index c9074f9b78bb..1a77a3cfae54 100644 --- a/Documentation/networking/operstates.txt +++ b/Documentation/networking/operstates.txt @@ -38,9 +38,6 @@ ifinfomsg::if_flags & IFF_LOWER_UP: ifinfomsg::if_flags & IFF_DORMANT: Driver has signaled netif_dormant_on() -These interface flags can also be queried without netlink using the -SIOCGIFFLAGS ioctl. - TLV IFLA_OPERSTATE contains RFC2863 state of the interface in numeric representation: diff --git a/Documentation/networking/packet_mmap.txt b/Documentation/networking/packet_mmap.txt index 07c53d596035..a22fd85e3796 100644 --- a/Documentation/networking/packet_mmap.txt +++ b/Documentation/networking/packet_mmap.txt @@ -4,16 +4,18 @@ This file documents the CONFIG_PACKET_MMAP option available with the PACKET socket interface on 2.4 and 2.6 kernels. This type of sockets is used for -capture network traffic with utilities like tcpdump or any other that uses -the libpcap library. - -You can find the latest version of this document at +capture network traffic with utilities like tcpdump or any other that needs +raw access to network interface. +You can find the latest version of this document at: http://pusa.uv.es/~ulisses/packet_mmap/ -Please send me your comments to +Howto can be found at: + http://wiki.gnu-log.net (packet_mmap) +Please send your comments to Ulisses Alonso Camaró + Johann Baudy ------------------------------------------------------------------------------- + Why use PACKET_MMAP @@ -25,19 +27,24 @@ to capture each packet, it requires two if you want to get packet's timestamp (like libpcap always does). In the other hand PACKET_MMAP is very efficient. PACKET_MMAP provides a size -configurable circular buffer mapped in user space. This way reading packets just -needs to wait for them, most of the time there is no need to issue a single -system call. By using a shared buffer between the kernel and the user -also has the benefit of minimizing packet copies. +configurable circular buffer mapped in user space that can be used to either +send or receive packets. This way reading packets just needs to wait for them, +most of the time there is no need to issue a single system call. Concerning +transmission, multiple packets can be sent through one system call to get the +highest bandwidth. +By using a shared buffer between the kernel and the user also has the benefit +of minimizing packet copies. -It's fine to use PACKET_MMAP to improve the performance of the capture process, -but it isn't everything. At least, if you are capturing at high speeds (this -is relative to the cpu speed), you should check if the device driver of your -network interface card supports some sort of interrupt load mitigation or -(even better) if it supports NAPI, also make sure it is enabled. +It's fine to use PACKET_MMAP to improve the performance of the capture and +transmission process, but it isn't everything. At least, if you are capturing +at high speeds (this is relative to the cpu speed), you should check if the +device driver of your network interface card supports some sort of interrupt +load mitigation or (even better) if it supports NAPI, also make sure it is +enabled. For transmission, check the MTU (Maximum Transmission Unit) used and +supported by devices of your network. -------------------------------------------------------------------------------- -+ How to use CONFIG_PACKET_MMAP ++ How to use CONFIG_PACKET_MMAP to improve capture process -------------------------------------------------------------------------------- From the user standpoint, you should use the higher level libpcap library, which @@ -57,7 +64,7 @@ the low level details or want to improve libpcap by including PACKET_MMAP support. -------------------------------------------------------------------------------- -+ How to use CONFIG_PACKET_MMAP directly ++ How to use CONFIG_PACKET_MMAP directly to improve capture process -------------------------------------------------------------------------------- From the system calls stand point, the use of PACKET_MMAP involves @@ -66,6 +73,7 @@ the following process: [setup] socket() -------> creation of the capture socket setsockopt() ---> allocation of the circular buffer (ring) + option: PACKET_RX_RING mmap() ---------> mapping of the allocated buffer to the user process @@ -96,6 +104,65 @@ Next I will describe PACKET_MMAP settings and it's constraints, also the mapping of the circular buffer in the user process and the use of this buffer. +-------------------------------------------------------------------------------- ++ How to use CONFIG_PACKET_MMAP directly to improve transmission process +-------------------------------------------------------------------------------- +Transmission process is similar to capture as shown below. + +[setup] socket() -------> creation of the transmission socket + setsockopt() ---> allocation of the circular buffer (ring) + option: PACKET_TX_RING + bind() ---------> bind transmission socket with a network interface + mmap() ---------> mapping of the allocated buffer to the + user process + +[transmission] poll() ---------> wait for free packets (optional) + send() ---------> send all packets that are set as ready in + the ring + The flag MSG_DONTWAIT can be used to return + before end of transfer. + +[shutdown] close() --------> destruction of the transmission socket and + deallocation of all associated resources. + +Binding the socket to your network interface is mandatory (with zero copy) to +know the header size of frames used in the circular buffer. + +As capture, each frame contains two parts: + + -------------------- +| struct tpacket_hdr | Header. It contains the status of +| | of this frame +|--------------------| +| data buffer | +. . Data that will be sent over the network interface. +. . + -------------------- + + bind() associates the socket to your network interface thanks to + sll_ifindex parameter of struct sockaddr_ll. + + Initialization example: + + struct sockaddr_ll my_addr; + struct ifreq s_ifr; + ... + + strncpy (s_ifr.ifr_name, "eth0", sizeof(s_ifr.ifr_name)); + + /* get interface index of eth0 */ + ioctl(this->socket, SIOCGIFINDEX, &s_ifr); + + /* fill sockaddr_ll struct to prepare binding */ + my_addr.sll_family = AF_PACKET; + my_addr.sll_protocol = ETH_P_ALL; + my_addr.sll_ifindex = s_ifr.ifr_ifindex; + + /* bind socket to eth0 */ + bind(this->socket, (struct sockaddr *)&my_addr, sizeof(struct sockaddr_ll)); + + A complete tutorial is available at: http://wiki.gnu-log.net/ + -------------------------------------------------------------------------------- + PACKET_MMAP settings -------------------------------------------------------------------------------- @@ -103,7 +170,10 @@ the use of this buffer. To setup PACKET_MMAP from user level code is done with a call like + - Capture process setsockopt(fd, SOL_PACKET, PACKET_RX_RING, (void *) &req, sizeof(req)) + - Transmission process + setsockopt(fd, SOL_PACKET, PACKET_TX_RING, (void *) &req, sizeof(req)) The most significant argument in the previous call is the req parameter, this parameter must to have the following structure: @@ -117,11 +187,11 @@ this parameter must to have the following structure: }; This structure is defined in /usr/include/linux/if_packet.h and establishes a -circular buffer (ring) of unswappable memory mapped in the capture process. +circular buffer (ring) of unswappable memory. Being mapped in the capture process allows reading the captured frames and related meta-information like timestamps without requiring a system call. -Captured frames are grouped in blocks. Each block is a physically contiguous +Frames are grouped in blocks. Each block is a physically contiguous region of memory and holds tp_block_size/tp_frame_size frames. The total number of blocks is tp_block_nr. Note that tp_frame_nr is a redundant parameter because @@ -336,6 +406,7 @@ struct tpacket_hdr). If this field is 0 means that the frame is ready to be used for the kernel, If not, there is a frame the user can read and the following flags apply: ++++ Capture process: from include/linux/if_packet.h #define TP_STATUS_COPY 2 @@ -391,6 +462,37 @@ packets are in the ring: It doesn't incur in a race condition to first check the status value and then poll for frames. + +++ Transmission process +Those defines are also used for transmission: + + #define TP_STATUS_AVAILABLE 0 // Frame is available + #define TP_STATUS_SEND_REQUEST 1 // Frame will be sent on next send() + #define TP_STATUS_SENDING 2 // Frame is currently in transmission + #define TP_STATUS_WRONG_FORMAT 4 // Frame format is not correct + +First, the kernel initializes all frames to TP_STATUS_AVAILABLE. To send a +packet, the user fills a data buffer of an available frame, sets tp_len to +current data buffer size and sets its status field to TP_STATUS_SEND_REQUEST. +This can be done on multiple frames. Once the user is ready to transmit, it +calls send(). Then all buffers with status equal to TP_STATUS_SEND_REQUEST are +forwarded to the network device. The kernel updates each status of sent +frames with TP_STATUS_SENDING until the end of transfer. +At the end of each transfer, buffer status returns to TP_STATUS_AVAILABLE. + + header->tp_len = in_i_size; + header->tp_status = TP_STATUS_SEND_REQUEST; + retval = send(this->socket, NULL, 0, 0); + +The user can also use poll() to check if a buffer is available: +(status == TP_STATUS_SENDING) + + struct pollfd pfd; + pfd.fd = fd; + pfd.revents = 0; + pfd.events = POLLOUT; + retval = poll(&pfd, 1, timeout); + -------------------------------------------------------------------------------- + THANKS -------------------------------------------------------------------------------- diff --git a/Documentation/networking/phonet.txt b/Documentation/networking/phonet.txt index 6a07e45d4a93..6e8ce09f9c73 100644 --- a/Documentation/networking/phonet.txt +++ b/Documentation/networking/phonet.txt @@ -36,7 +36,7 @@ Phonet packets have a common header as follows: On Linux, the link-layer header includes the pn_media byte (see below). The next 7 bytes are part of the network-layer header. -The device ID is split: the 6 higher-order bits consitute the device +The device ID is split: the 6 higher-order bits constitute the device address, while the 2 lower-order bits are used for multiplexing, as are the 8-bit object identifiers. As such, Phonet can be considered as a network layer with 6 bits of address space and 10 bits for transport diff --git a/Documentation/networking/regulatory.txt b/Documentation/networking/regulatory.txt index dcf31648414a..eaa1a25946c1 100644 --- a/Documentation/networking/regulatory.txt +++ b/Documentation/networking/regulatory.txt @@ -89,7 +89,7 @@ added to this document when its support is enabled. Device drivers who provide their own built regulatory domain do not need a callback as the channels registered by them are the only ones that will be allowed and therefore *additional* -cannels cannot be enabled. +channels cannot be enabled. Example code - drivers hinting an alpha2: ------------------------------------------ diff --git a/Documentation/power/devices.txt b/Documentation/power/devices.txt index 421e7d00ffd0..c9abbd86bc18 100644 --- a/Documentation/power/devices.txt +++ b/Documentation/power/devices.txt @@ -75,9 +75,6 @@ may need to apply in domain-specific ways to their devices: struct bus_type { ... int (*suspend)(struct device *dev, pm_message_t state); - int (*suspend_late)(struct device *dev, pm_message_t state); - - int (*resume_early)(struct device *dev); int (*resume)(struct device *dev); }; @@ -226,20 +223,7 @@ The phases are seen by driver notifications issued in this order: This call should handle parts of device suspend logic that require sleeping. It probably does work to quiesce the device which hasn't - been abstracted into class.suspend() or bus.suspend_late(). - - 3 bus.suspend_late(dev, message) is called with IRQs disabled, and - with only one CPU active. Until the bus.resume_early() phase - completes (see later), IRQs are not enabled again. This method - won't be exposed by all busses; for message based busses like USB, - I2C, or SPI, device interactions normally require IRQs. This bus - call may be morphed into a driver call with bus-specific parameters. - - This call might save low level hardware state that might otherwise - be lost in the upcoming low power state, and actually put the - device into a low power state ... so that in some cases the device - may stay partly usable until this late. This "late" call may also - help when coping with hardware that behaves badly. + been abstracted into class.suspend(). The pm_message_t parameter is currently used to refine those semantics (described later). @@ -351,19 +335,11 @@ devices processing each phase's calls before the next phase begins. The phases are seen by driver notifications issued in this order: - 1 bus.resume_early(dev) is called with IRQs disabled, and with - only one CPU active. As with bus.suspend_late(), this method - won't be supported on busses that require IRQs in order to - interact with devices. + 1 bus.resume(dev) reverses the effects of bus.suspend(). This may + be morphed into a device driver call with bus-specific parameters; + implementations may sleep. - This reverses the effects of bus.suspend_late(). - - 2 bus.resume(dev) is called next. This may be morphed into a device - driver call with bus-specific parameters; implementations may sleep. - - This reverses the effects of bus.suspend(). - - 3 class.resume(dev) is called for devices associated with a class + 2 class.resume(dev) is called for devices associated with a class that has such a method. Implementations may sleep. This reverses the effects of class.suspend(), and would usually diff --git a/Documentation/power/regulator/consumer.txt b/Documentation/power/regulator/consumer.txt index 82b7a43aadba..5f83fd24ea84 100644 --- a/Documentation/power/regulator/consumer.txt +++ b/Documentation/power/regulator/consumer.txt @@ -178,5 +178,5 @@ Consumers can uregister interest by calling :- int regulator_unregister_notifier(struct regulator *regulator, struct notifier_block *nb); -Regulators use the kernel notifier framework to send event to thier interested +Regulators use the kernel notifier framework to send event to their interested consumers. diff --git a/Documentation/power/regulator/overview.txt b/Documentation/power/regulator/overview.txt index bdcb332bd7fb..0cded696ca01 100644 --- a/Documentation/power/regulator/overview.txt +++ b/Documentation/power/regulator/overview.txt @@ -119,7 +119,7 @@ Some terms used in this document:- battery power, USB power) Regulator Domains: is the new current limit within the - regulator operating parameters for input/ouput voltage. + regulator operating parameters for input/output voltage. If the regulator request passes all the constraint tests then the new regulator value is applied. diff --git a/Documentation/power/s2ram.txt b/Documentation/power/s2ram.txt index 2ebdc6091ce1..514b94fc931e 100644 --- a/Documentation/power/s2ram.txt +++ b/Documentation/power/s2ram.txt @@ -63,7 +63,7 @@ hardware during resume operations where a value can be set that will survive a reboot. Consequence is that after a resume (even if it is successful) your system -clock will have a value corresponding to the magic mumber instead of the +clock will have a value corresponding to the magic number instead of the correct date/time! It is therefore advisable to use a program like ntp-date or rdate to reset the correct date/time from an external time source when using this trace option. diff --git a/Documentation/power/userland-swsusp.txt b/Documentation/power/userland-swsusp.txt index 7b99636564c8..b967cd9137d6 100644 --- a/Documentation/power/userland-swsusp.txt +++ b/Documentation/power/userland-swsusp.txt @@ -109,7 +109,7 @@ unfreeze user space processes frozen by SNAPSHOT_UNFREEZE if they are still frozen when the device is being closed). Currently it is assumed that the userland utilities reading/writing the -snapshot image from/to the kernel will use a swap parition, called the resume +snapshot image from/to the kernel will use a swap partition, called the resume partition, or a swap file as storage space (if a swap file is used, the resume partition is the partition that holds this file). However, this is not really required, as they can use, for example, a special (blank) suspend partition or diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt index d16b7a1c3793..8d999d862d0e 100644 --- a/Documentation/powerpc/booting-without-of.txt +++ b/Documentation/powerpc/booting-without-of.txt @@ -1356,7 +1356,7 @@ platforms are moved over to use the flattened-device-tree model. - phy-map : 1 cell, optional, bitmap of addresses to probe the PHY for, used if phy-address is absent. bit 0x00000001 is MDIO address 0. - For Axon it can be absent, thouugh my current driver + For Axon it can be absent, though my current driver doesn't handle phy-address yet so for now, keep 0x00ffffff in it. - rx-fifo-size-gige : 1 cell, Rx fifo size in bytes for 1000 Mb/sec @@ -1438,7 +1438,7 @@ platforms are moved over to use the flattened-device-tree model. The Xilinx EDK toolchain ships with a set of IP cores (devices) for use in Xilinx Spartan and Virtex FPGAs. The devices cover the whole range - of standard device types (network, serial, etc.) and miscellanious + of standard device types (network, serial, etc.) and miscellaneous devices (gpio, LCD, spi, etc). Also, since these devices are implemented within the fpga fabric every instance of the device can be synthesised with different options that change the behaviour. diff --git a/Documentation/powerpc/dts-bindings/can/sja1000.txt b/Documentation/powerpc/dts-bindings/can/sja1000.txt new file mode 100644 index 000000000000..d6d209ded937 --- /dev/null +++ b/Documentation/powerpc/dts-bindings/can/sja1000.txt @@ -0,0 +1,53 @@ +Memory mapped SJA1000 CAN controller from NXP (formerly Philips) + +Required properties: + +- compatible : should be "nxp,sja1000". + +- reg : should specify the chip select, address offset and size required + to map the registers of the SJA1000. The size is usually 0x80. + +- interrupts: property with a value describing the interrupt source + (number and sensitivity) required for the SJA1000. + +Optional properties: + +- nxp,external-clock-frequency : Frequency of the external oscillator + clock in Hz. Note that the internal clock frequency used by the + SJA1000 is half of that value. If not specified, a default value + of 16000000 (16 MHz) is used. + +- nxp,tx-output-mode : operation mode of the TX output control logic: + <0x0> : bi-phase output mode + <0x1> : normal output mode (default) + <0x2> : test output mode + <0x3> : clock output mode + +- nxp,tx-output-config : TX output pin configuration: + <0x01> : TX0 invert + <0x02> : TX0 pull-down (default) + <0x04> : TX0 pull-up + <0x06> : TX0 push-pull + <0x08> : TX1 invert + <0x10> : TX1 pull-down + <0x20> : TX1 pull-up + <0x30> : TX1 push-pull + +- nxp,clock-out-frequency : clock frequency in Hz on the CLKOUT pin. + If not specified or if the specified value is 0, the CLKOUT pin + will be disabled. + +- nxp,no-comparator-bypass : Allows to disable the CAN input comperator. + +For futher information, please have a look to the SJA1000 data sheet. + +Examples: + +can@3,100 { + compatible = "nxp,sja1000"; + reg = <3 0x100 0x80>; + interrupts = <2 0>; + interrupt-parent = <&mpic>; + nxp,external-clock-frequency = <16000000>; +}; + diff --git a/Documentation/powerpc/dts-bindings/ecm.txt b/Documentation/powerpc/dts-bindings/ecm.txt new file mode 100644 index 000000000000..f514f29c67d6 --- /dev/null +++ b/Documentation/powerpc/dts-bindings/ecm.txt @@ -0,0 +1,64 @@ +===================================================================== +E500 LAW & Coherency Module Device Tree Binding +Copyright (C) 2009 Freescale Semiconductor Inc. +===================================================================== + +Local Access Window (LAW) Node + +The LAW node represents the region of CCSR space where local access +windows are configured. For ECM based devices this is the first 4k +of CCSR space that includes CCSRBAR, ALTCBAR, ALTCAR, BPTR, and some +number of local access windows as specified by fsl,num-laws. + +PROPERTIES + + - compatible + Usage: required + Value type: + Definition: Must include "fsl,ecm-law" + + - reg + Usage: required + Value type: + Definition: A standard property. The value specifies the + physical address offset and length of the CCSR space + registers. + + - fsl,num-laws + Usage: required + Value type: + Definition: The value specifies the number of local access + windows for this device. + +===================================================================== + +E500 Coherency Module Node + +The E500 LAW node represents the region of CCSR space where ECM config +and error reporting registers exist, this is the second 4k (0x1000) +of CCSR space. + +PROPERTIES + + - compatible + Usage: required + Value type: + Definition: Must include "fsl,CHIP-ecm", "fsl,ecm" where + CHIP is the processor (mpc8572, mpc8544, etc.) + + - reg + Usage: required + Value type: + Definition: A standard property. The value specifies the + physical address offset and length of the CCSR space + registers. + + - interrupts + Usage: required + Value type: + + - interrupt-parent + Usage: required + Value type: + +===================================================================== diff --git a/Documentation/powerpc/dts-bindings/fsl/board.txt b/Documentation/powerpc/dts-bindings/fsl/board.txt index 6c974d28eeb4..e8b5bc24d0ac 100644 --- a/Documentation/powerpc/dts-bindings/fsl/board.txt +++ b/Documentation/powerpc/dts-bindings/fsl/board.txt @@ -38,7 +38,7 @@ Required properities: - reg : Should contain the address and the length of the GPIO bank register. - #gpio-cells : Should be two. The first cell is the pin number and the - second cell is used to specify optional paramters (currently unused). + second cell is used to specify optional parameters (currently unused). - gpio-controller : Marks the port as GPIO controller. Example: diff --git a/Documentation/powerpc/dts-bindings/fsl/cpm_qe/cpm.txt b/Documentation/powerpc/dts-bindings/fsl/cpm_qe/cpm.txt index 088fc471e03a..160c752484b4 100644 --- a/Documentation/powerpc/dts-bindings/fsl/cpm_qe/cpm.txt +++ b/Documentation/powerpc/dts-bindings/fsl/cpm_qe/cpm.txt @@ -19,7 +19,7 @@ Example: reg = <119c0 30>; } -* Properties common to mulitple CPM/QE devices +* Properties common to multiple CPM/QE devices - fsl,cpm-command : This value is ORed with the opcode and command flag to specify the device on which a CPM command operates. diff --git a/Documentation/powerpc/dts-bindings/fsl/cpm_qe/gpio.txt b/Documentation/powerpc/dts-bindings/fsl/cpm_qe/gpio.txt index 1815dfede1bc..349f79fd7076 100644 --- a/Documentation/powerpc/dts-bindings/fsl/cpm_qe/gpio.txt +++ b/Documentation/powerpc/dts-bindings/fsl/cpm_qe/gpio.txt @@ -11,7 +11,7 @@ Required properties: "fsl,cpm1-pario-bank-c", "fsl,cpm1-pario-bank-d", "fsl,cpm1-pario-bank-e", "fsl,cpm2-pario-bank" - #gpio-cells : Should be two. The first cell is the pin number and the - second cell is used to specify optional paramters (currently unused). + second cell is used to specify optional parameters (currently unused). - gpio-controller : Marks the port as GPIO controller. Example of three SOC GPIO banks defined as gpio-controller nodes: diff --git a/Documentation/powerpc/dts-bindings/fsl/cpm_qe/qe.txt b/Documentation/powerpc/dts-bindings/fsl/cpm_qe/qe.txt index 78790d58dc2c..6e37be1eeb2d 100644 --- a/Documentation/powerpc/dts-bindings/fsl/cpm_qe/qe.txt +++ b/Documentation/powerpc/dts-bindings/fsl/cpm_qe/qe.txt @@ -17,6 +17,9 @@ Required properties: - model : precise model of the QE, Can be "QE", "CPM", or "CPM2" - reg : offset and length of the device registers. - bus-frequency : the clock frequency for QUICC Engine. +- fsl,qe-num-riscs: define how many RISC engines the QE has. +- fsl,qe-num-snums: define how many serial number(SNUM) the QE can use for the + threads. Recommended properties - brg-frequency : the internal clock source frequency for baud-rate diff --git a/Documentation/powerpc/dts-bindings/fsl/esdhc.txt b/Documentation/powerpc/dts-bindings/fsl/esdhc.txt index 600846557763..3ed3797b5086 100644 --- a/Documentation/powerpc/dts-bindings/fsl/esdhc.txt +++ b/Documentation/powerpc/dts-bindings/fsl/esdhc.txt @@ -5,17 +5,18 @@ for MMC, SD, and SDIO types of memory cards. Required properties: - compatible : should be - "fsl,-esdhc", "fsl,mpc8379-esdhc" for MPC83xx processors. - "fsl,-esdhc", "fsl,mpc8536-esdhc" for MPC85xx processors. + "fsl,-esdhc", "fsl,esdhc" - reg : should contain eSDHC registers location and length. - interrupts : should contain eSDHC interrupt. - interrupt-parent : interrupt source phandle. - clock-frequency : specifies eSDHC base clock frequency. + - sdhci,1-bit-only : (optional) specifies that a controller can + only handle 1-bit data transfers. Example: sdhci@2e000 { - compatible = "fsl,mpc8378-esdhc", "fsl,mpc8379-esdhc"; + compatible = "fsl,mpc8378-esdhc", "fsl,esdhc"; reg = <0x2e000 0x1000>; interrupts = <42 0x8>; interrupt-parent = <&ipic>; diff --git a/Documentation/powerpc/dts-bindings/fsl/mcm.txt b/Documentation/powerpc/dts-bindings/fsl/mcm.txt new file mode 100644 index 000000000000..4ceda9b3b413 --- /dev/null +++ b/Documentation/powerpc/dts-bindings/fsl/mcm.txt @@ -0,0 +1,64 @@ +===================================================================== +MPX LAW & Coherency Module Device Tree Binding +Copyright (C) 2009 Freescale Semiconductor Inc. +===================================================================== + +Local Access Window (LAW) Node + +The LAW node represents the region of CCSR space where local access +windows are configured. For MCM based devices this is the first 4k +of CCSR space that includes CCSRBAR, ALTCBAR, ALTCAR, BPTR, and some +number of local access windows as specified by fsl,num-laws. + +PROPERTIES + + - compatible + Usage: required + Value type: + Definition: Must include "fsl,mcm-law" + + - reg + Usage: required + Value type: + Definition: A standard property. The value specifies the + physical address offset and length of the CCSR space + registers. + + - fsl,num-laws + Usage: required + Value type: + Definition: The value specifies the number of local access + windows for this device. + +===================================================================== + +MPX Coherency Module Node + +The MPX LAW node represents the region of CCSR space where MCM config +and error reporting registers exist, this is the second 4k (0x1000) +of CCSR space. + +PROPERTIES + + - compatible + Usage: required + Value type: + Definition: Must include "fsl,CHIP-mcm", "fsl,mcm" where + CHIP is the processor (mpc8641, mpc8610, etc.) + + - reg + Usage: required + Value type: + Definition: A standard property. The value specifies the + physical address offset and length of the CCSR space + registers. + + - interrupts + Usage: required + Value type: + + - interrupt-parent + Usage: required + Value type: + +===================================================================== diff --git a/Documentation/powerpc/dts-bindings/fsl/msi-pic.txt b/Documentation/powerpc/dts-bindings/fsl/msi-pic.txt index b26b91992c55..bcc30bac6831 100644 --- a/Documentation/powerpc/dts-bindings/fsl/msi-pic.txt +++ b/Documentation/powerpc/dts-bindings/fsl/msi-pic.txt @@ -1,6 +1,6 @@ * Freescale MSI interrupt controller -Reguired properities: +Required properties: - compatible : compatible list, contains 2 entries, first is "fsl,CHIP-msi", where CHIP is the processor(mpc8610, mpc8572, etc.) and the second is "fsl,mpic-msi" or "fsl,ipic-msi" depending on diff --git a/Documentation/powerpc/dts-bindings/fsl/pmc.txt b/Documentation/powerpc/dts-bindings/fsl/pmc.txt index 02f6f43ee1b7..07256b7ffcaa 100644 --- a/Documentation/powerpc/dts-bindings/fsl/pmc.txt +++ b/Documentation/powerpc/dts-bindings/fsl/pmc.txt @@ -15,8 +15,8 @@ Properties: compatible; all statements below that apply to "fsl,mpc8548-pmc" also apply to "fsl,mpc8641d-pmc". - Compatibility does not include bit assigments in SCCR/PMCDR/DEVDISR; these - bit assigments are indicated via the sleep specifier in each device's + Compatibility does not include bit assignments in SCCR/PMCDR/DEVDISR; these + bit assignments are indicated via the sleep specifier in each device's sleep property. - reg: For devices compatible with "fsl,mpc8349-pmc", the first resource diff --git a/Documentation/powerpc/qe_firmware.txt b/Documentation/powerpc/qe_firmware.txt index 06da4d4b44f9..2031ddb33d09 100644 --- a/Documentation/powerpc/qe_firmware.txt +++ b/Documentation/powerpc/qe_firmware.txt @@ -225,7 +225,7 @@ For example, to match the 8323, revision 1.0: soc.major = 1 soc.minor = 0 -'padding' is neccessary for structure alignment. This field ensures that the +'padding' is necessary for structure alignment. This field ensures that the 'extended_modes' field is aligned on a 64-bit boundary. 'extended_modes' is a bitfield that defines special functionality which has an diff --git a/Documentation/pps/pps.txt b/Documentation/pps/pps.txt new file mode 100644 index 000000000000..125f4ab48998 --- /dev/null +++ b/Documentation/pps/pps.txt @@ -0,0 +1,172 @@ + + PPS - Pulse Per Second + ---------------------- + +(C) Copyright 2007 Rodolfo Giometti + +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. + + + +Overview +-------- + +LinuxPPS provides a programming interface (API) to define in the +system several PPS sources. + +PPS means "pulse per second" and a PPS source is just a device which +provides a high precision signal each second so that an application +can use it to adjust system clock time. + +A PPS source can be connected to a serial port (usually to the Data +Carrier Detect pin) or to a parallel port (ACK-pin) or to a special +CPU's GPIOs (this is the common case in embedded systems) but in each +case when a new pulse arrives the system must apply to it a timestamp +and record it for userland. + +Common use is the combination of the NTPD as userland program, with a +GPS receiver as PPS source, to obtain a wallclock-time with +sub-millisecond synchronisation to UTC. + + +RFC considerations +------------------ + +While implementing a PPS API as RFC 2783 defines and using an embedded +CPU GPIO-Pin as physical link to the signal, I encountered a deeper +problem: + + At startup it needs a file descriptor as argument for the function + time_pps_create(). + +This implies that the source has a /dev/... entry. This assumption is +ok for the serial and parallel port, where you can do something +useful besides(!) the gathering of timestamps as it is the central +task for a PPS-API. But this assumption does not work for a single +purpose GPIO line. In this case even basic file-related functionality +(like read() and write()) makes no sense at all and should not be a +precondition for the use of a PPS-API. + +The problem can be simply solved if you consider that a PPS source is +not always connected with a GPS data source. + +So your programs should check if the GPS data source (the serial port +for instance) is a PPS source too, and if not they should provide the +possibility to open another device as PPS source. + +In LinuxPPS the PPS sources are simply char devices usually mapped +into files /dev/pps0, /dev/pps1, etc.. + + +Coding example +-------------- + +To register a PPS source into the kernel you should define a struct +pps_source_info_s as follows: + + static struct pps_source_info pps_ktimer_info = { + .name = "ktimer", + .path = "", + .mode = PPS_CAPTUREASSERT | PPS_OFFSETASSERT | \ + PPS_ECHOASSERT | \ + PPS_CANWAIT | PPS_TSFMT_TSPEC, + .echo = pps_ktimer_echo, + .owner = THIS_MODULE, + }; + +and then calling the function pps_register_source() in your +intialization routine as follows: + + source = pps_register_source(&pps_ktimer_info, + PPS_CAPTUREASSERT | PPS_OFFSETASSERT); + +The pps_register_source() prototype is: + + int pps_register_source(struct pps_source_info_s *info, int default_params) + +where "info" is a pointer to a structure that describes a particular +PPS source, "default_params" tells the system what the initial default +parameters for the device should be (it is obvious that these parameters +must be a subset of ones defined in the struct +pps_source_info_s which describe the capabilities of the driver). + +Once you have registered a new PPS source into the system you can +signal an assert event (for example in the interrupt handler routine) +just using: + + pps_event(source, &ts, PPS_CAPTUREASSERT, ptr) + +where "ts" is the event's timestamp. + +The same function may also run the defined echo function +(pps_ktimer_echo(), passing to it the "ptr" pointer) if the user +asked for that... etc.. + +Please see the file drivers/pps/clients/ktimer.c for example code. + + +SYSFS support +------------- + +If the SYSFS filesystem is enabled in the kernel it provides a new class: + + $ ls /sys/class/pps/ + pps0/ pps1/ pps2/ + +Every directory is the ID of a PPS sources defined in the system and +inside you find several files: + + $ ls /sys/class/pps/pps0/ + assert clear echo mode name path subsystem@ uevent + +Inside each "assert" and "clear" file you can find the timestamp and a +sequence number: + + $ cat /sys/class/pps/pps0/assert + 1170026870.983207967#8 + +Where before the "#" is the timestamp in seconds; after it is the +sequence number. Other files are: + +* echo: reports if the PPS source has an echo function or not; + +* mode: reports available PPS functioning modes; + +* name: reports the PPS source's name; + +* path: reports the PPS source's device path, that is the device the + PPS source is connected to (if it exists). + + +Testing the PPS support +----------------------- + +In order to test the PPS support even without specific hardware you can use +the ktimer driver (see the client subsection in the PPS configuration menu) +and the userland tools provided into Documentaion/pps/ directory. + +Once you have enabled the compilation of ktimer just modprobe it (if +not statically compiled): + + # modprobe ktimer + +and the run ppstest as follow: + + $ ./ppstest /dev/pps0 + trying PPS source "/dev/pps1" + found PPS source "/dev/pps1" + ok, found 1 source(s), now start fetching data... + source 0 - assert 1186592699.388832443, sequence: 364 - clear 0.000000000, sequence: 0 + source 0 - assert 1186592700.388931295, sequence: 365 - clear 0.000000000, sequence: 0 + source 0 - assert 1186592701.389032765, sequence: 366 - clear 0.000000000, sequence: 0 + +Please, note that to compile userland programs you need the file timepps.h +(see Documentation/pps/). diff --git a/Documentation/rbtree.txt b/Documentation/rbtree.txt index 7224459b469e..aae8355d3166 100644 --- a/Documentation/rbtree.txt +++ b/Documentation/rbtree.txt @@ -131,8 +131,8 @@ Example: } /* Add new node and rebalance tree. */ - rb_link_node(data->node, parent, new); - rb_insert_color(data->node, root); + rb_link_node(&data->node, parent, new); + rb_insert_color(&data->node, root); return TRUE; } @@ -146,10 +146,10 @@ To remove an existing node from a tree, call: Example: - struct mytype *data = mysearch(mytree, "walrus"); + struct mytype *data = mysearch(&mytree, "walrus"); if (data) { - rb_erase(data->node, mytree); + rb_erase(&data->node, &mytree); myfree(data); } @@ -188,5 +188,5 @@ Example: struct rb_node *node; for (node = rb_first(&mytree); node; node = rb_next(node)) - printk("key=%s\n", rb_entry(node, int, keystring)); + printk("key=%s\n", rb_entry(node, struct mytype, node)->keystring); diff --git a/Documentation/rfkill.txt b/Documentation/rfkill.txt index 4d3ee317a4a3..b4860509c319 100644 --- a/Documentation/rfkill.txt +++ b/Documentation/rfkill.txt @@ -1,575 +1,139 @@ -rfkill - RF switch subsystem support -==================================== +rfkill - RF kill switch support +=============================== -1 Introduction -2 Implementation details -3 Kernel driver guidelines -3.1 wireless device drivers -3.2 platform/switch drivers -3.3 input device drivers -4 Kernel API -5 Userspace support +1. Introduction +2. Implementation details +3. Kernel API +4. Userspace support -1. Introduction: +1. Introduction -The rfkill switch subsystem exists to add a generic interface to circuitry that -can enable or disable the signal output of a wireless *transmitter* of any -type. By far, the most common use is to disable radio-frequency transmitters. +The rfkill subsystem provides a generic interface to disabling any radio +transmitter in the system. When a transmitter is blocked, it shall not +radiate any power. -Note that disabling the signal output means that the the transmitter is to be -made to not emit any energy when "blocked". rfkill is not about blocking data -transmissions, it is about blocking energy emission. +The subsystem also provides the ability to react on button presses and +disable all transmitters of a certain type (or all). This is intended for +situations where transmitters need to be turned off, for example on +aircraft. -The rfkill subsystem offers support for keys and switches often found on -laptops to enable wireless devices like WiFi and Bluetooth, so that these keys -and switches actually perform an action in all wireless devices of a given type -attached to the system. +The rfkill subsystem has a concept of "hard" and "soft" block, which +differ little in their meaning (block == transmitters off) but rather in +whether they can be changed or not: + - hard block: read-only radio block that cannot be overriden by software + - soft block: writable radio block (need not be readable) that is set by + the system software. -The buttons to enable and disable the wireless transmitters are important in -situations where the user is for example using his laptop on a location where -radio-frequency transmitters _must_ be disabled (e.g. airplanes). -Because of this requirement, userspace support for the keys should not be made -mandatory. Because userspace might want to perform some additional smarter -tasks when the key is pressed, rfkill provides userspace the possibility to -take over the task to handle the key events. +2. Implementation details + +The rfkill subsystem is composed of three main components: + * the rfkill core, + * the deprecated rfkill-input module (an input layer handler, being + replaced by userspace policy code) and + * the rfkill drivers. + +The rfkill core provides API for kernel drivers to register their radio +transmitter with the kernel, methods for turning it on and off and, letting +the system know about hardware-disabled states that may be implemented on +the device. + +The rfkill core code also notifies userspace of state changes, and provides +ways for userspace to query the current states. See the "Userspace support" +section below. + +When the device is hard-blocked (either by a call to rfkill_set_hw_state() +or from query_hw_block) set_block() will be invoked for additional software +block, but drivers can ignore the method call since they can use the return +value of the function rfkill_set_hw_state() to sync the software state +instead of keeping track of calls to set_block(). In fact, drivers should +use the return value of rfkill_set_hw_state() unless the hardware actually +keeps track of soft and hard block separately. + + +3. Kernel API + + +Drivers for radio transmitters normally implement an rfkill driver. + +Platform drivers might implement input devices if the rfkill button is just +that, a button. If that button influences the hardware then you need to +implement an rfkill driver instead. This also applies if the platform provides +a way to turn on/off the transmitter(s). + +For some platforms, it is possible that the hardware state changes during +suspend/hibernation, in which case it will be necessary to update the rfkill +core with the current state is at resume time. + +To create an rfkill driver, driver's Kconfig needs to have + + depends on RFKILL || !RFKILL + +to ensure the driver cannot be built-in when rfkill is modular. The !RFKILL +case allows the driver to be built when rfkill is not configured, which which +case all rfkill API can still be used but will be provided by static inlines +which compile to almost nothing. + +Calling rfkill_set_hw_state() when a state change happens is required from +rfkill drivers that control devices that can be hard-blocked unless they also +assign the poll_hw_block() callback (then the rfkill core will poll the +device). Don't do this unless you cannot get the event in any other way. + + + +5. Userspace support + +The recommended userspace interface to use is /dev/rfkill, which is a misc +character device that allows userspace to obtain and set the state of rfkill +devices and sets of devices. It also notifies userspace about device addition +and removal. The API is a simple read/write API that is defined in +linux/rfkill.h, with one ioctl that allows turning off the deprecated input +handler in the kernel for the transition period. + +Except for the one ioctl, communication with the kernel is done via read() +and write() of instances of 'struct rfkill_event'. In this structure, the +soft and hard block are properly separated (unlike sysfs, see below) and +userspace is able to get a consistent snapshot of all rfkill devices in the +system. Also, it is possible to switch all rfkill drivers (or all drivers of +a specified type) into a state which also updates the default state for +hotplugged devices. + +After an application opens /dev/rfkill, it can read the current state of +all devices, and afterwards can poll the descriptor for hotplug or state +change events. + +Applications must ignore operations (the "op" field) they do not handle, +this allows the API to be extended in the future. -=============================================================================== -2: Implementation details - -The rfkill subsystem is composed of various components: the rfkill class, the -rfkill-input module (an input layer handler), and some specific input layer -events. - -The rfkill class provides kernel drivers with an interface that allows them to -know when they should enable or disable a wireless network device transmitter. -This is enabled by the CONFIG_RFKILL Kconfig option. - -The rfkill class support makes sure userspace will be notified of all state -changes on rfkill devices through uevents. It provides a notification chain -for interested parties in the kernel to also get notified of rfkill state -changes in other drivers. It creates several sysfs entries which can be used -by userspace. See section "Userspace support". - -The rfkill-input module provides the kernel with the ability to implement a -basic response when the user presses a key or button (or toggles a switch) -related to rfkill functionality. It is an in-kernel implementation of default -policy of reacting to rfkill-related input events and neither mandatory nor -required for wireless drivers to operate. It is enabled by the -CONFIG_RFKILL_INPUT Kconfig option. - -rfkill-input is a rfkill-related events input layer handler. This handler will -listen to all rfkill key events and will change the rfkill state of the -wireless devices accordingly. With this option enabled userspace could either -do nothing or simply perform monitoring tasks. - -The rfkill-input module also provides EPO (emergency power-off) functionality -for all wireless transmitters. This function cannot be overridden, and it is -always active. rfkill EPO is related to *_RFKILL_ALL input layer events. - - -Important terms for the rfkill subsystem: - -In order to avoid confusion, we avoid the term "switch" in rfkill when it is -referring to an electronic control circuit that enables or disables a -transmitter. We reserve it for the physical device a human manipulates -(which is an input device, by the way): - -rfkill switch: - - A physical device a human manipulates. Its state can be perceived by - the kernel either directly (through a GPIO pin, ACPI GPE) or by its - effect on a rfkill line of a wireless device. - -rfkill controller: - - A hardware circuit that controls the state of a rfkill line, which a - kernel driver can interact with *to modify* that state (i.e. it has - either write-only or read/write access). - -rfkill line: - - An input channel (hardware or software) of a wireless device, which - causes a wireless transmitter to stop emitting energy (BLOCK) when it - is active. Point of view is extremely important here: rfkill lines are - always seen from the PoV of a wireless device (and its driver). - -soft rfkill line/software rfkill line: - - A rfkill line the wireless device driver can directly change the state - of. Related to rfkill_state RFKILL_STATE_SOFT_BLOCKED. - -hard rfkill line/hardware rfkill line: - - A rfkill line that works fully in hardware or firmware, and that cannot - be overridden by the kernel driver. The hardware device or the - firmware just exports its status to the driver, but it is read-only. - Related to rfkill_state RFKILL_STATE_HARD_BLOCKED. - -The enum rfkill_state describes the rfkill state of a transmitter: - -When a rfkill line or rfkill controller is in the RFKILL_STATE_UNBLOCKED state, -the wireless transmitter (radio TX circuit for example) is *enabled*. When the -it is in the RFKILL_STATE_SOFT_BLOCKED or RFKILL_STATE_HARD_BLOCKED, the -wireless transmitter is to be *blocked* from operating. - -RFKILL_STATE_SOFT_BLOCKED indicates that a call to toggle_radio() can change -that state. RFKILL_STATE_HARD_BLOCKED indicates that a call to toggle_radio() -will not be able to change the state and will return with a suitable error if -attempts are made to set the state to RFKILL_STATE_UNBLOCKED. - -RFKILL_STATE_HARD_BLOCKED is used by drivers to signal that the device is -locked in the BLOCKED state by a hardwire rfkill line (typically an input pin -that, when active, forces the transmitter to be disabled) which the driver -CANNOT override. - -Full rfkill functionality requires two different subsystems to cooperate: the -input layer and the rfkill class. The input layer issues *commands* to the -entire system requesting that devices registered to the rfkill class change -state. The way this interaction happens is not complex, but it is not obvious -either: - -Kernel Input layer: - - * Generates KEY_WWAN, KEY_WLAN, KEY_BLUETOOTH, SW_RFKILL_ALL, and - other such events when the user presses certain keys, buttons, or - toggles certain physical switches. - - THE INPUT LAYER IS NEVER USED TO PROPAGATE STATUS, NOTIFICATIONS OR THE - KIND OF STUFF AN ON-SCREEN-DISPLAY APPLICATION WOULD REPORT. It is - used to issue *commands* for the system to change behaviour, and these - commands may or may not be carried out by some kernel driver or - userspace application. It follows that doing user feedback based only - on input events is broken, as there is no guarantee that an input event - will be acted upon. - - Most wireless communication device drivers implementing rfkill - functionality MUST NOT generate these events, and have no reason to - register themselves with the input layer. Doing otherwise is a common - misconception. There is an API to propagate rfkill status change - information, and it is NOT the input layer. - -rfkill class: - - * Calls a hook in a driver to effectively change the wireless - transmitter state; - * Keeps track of the wireless transmitter state (with help from - the driver); - * Generates userspace notifications (uevents) and a call to a - notification chain (kernel) when there is a wireless transmitter - state change; - * Connects a wireless communications driver with the common rfkill - control system, which, for example, allows actions such as - "switch all bluetooth devices offline" to be carried out by - userspace or by rfkill-input. - - THE RFKILL CLASS NEVER ISSUES INPUT EVENTS. THE RFKILL CLASS DOES - NOT LISTEN TO INPUT EVENTS. NO DRIVER USING THE RFKILL CLASS SHALL - EVER LISTEN TO, OR ACT ON RFKILL INPUT EVENTS. Doing otherwise is - a layering violation. - - Most wireless data communication drivers in the kernel have just to - implement the rfkill class API to work properly. Interfacing to the - input layer is not often required (and is very often a *bug*) on - wireless drivers. - - Platform drivers often have to attach to the input layer to *issue* - (but never to listen to) rfkill events for rfkill switches, and also to - the rfkill class to export a control interface for the platform rfkill - controllers to the rfkill subsystem. This does NOT mean the rfkill - switch is attached to a rfkill class (doing so is almost always wrong). - It just means the same kernel module is the driver for different - devices (rfkill switches and rfkill controllers). - - -Userspace input handlers (uevents) or kernel input handlers (rfkill-input): - - * Implements the policy of what should happen when one of the input - layer events related to rfkill operation is received. - * Uses the sysfs interface (userspace) or private rfkill API calls - to tell the devices registered with the rfkill class to change - their state (i.e. translates the input layer event into real - action). - - * rfkill-input implements EPO by handling EV_SW SW_RFKILL_ALL 0 - (power off all transmitters) in a special way: it ignores any - overrides and local state cache and forces all transmitters to the - RFKILL_STATE_SOFT_BLOCKED state (including those which are already - supposed to be BLOCKED). - * rfkill EPO will remain active until rfkill-input receives an - EV_SW SW_RFKILL_ALL 1 event. While the EPO is active, transmitters - are locked in the blocked state (rfkill will refuse to unblock them). - * rfkill-input implements different policies that the user can - select for handling EV_SW SW_RFKILL_ALL 1. It will unlock rfkill, - and either do nothing (leave transmitters blocked, but now unlocked), - restore the transmitters to their state before the EPO, or unblock - them all. - -Userspace uevent handler or kernel platform-specific drivers hooked to the -rfkill notifier chain: - - * Taps into the rfkill notifier chain or to KOBJ_CHANGE uevents, - in order to know when a device that is registered with the rfkill - class changes state; - * Issues feedback notifications to the user; - * In the rare platforms where this is required, synthesizes an input - event to command all *OTHER* rfkill devices to also change their - statues when a specific rfkill device changes state. - - -=============================================================================== -3: Kernel driver guidelines - -Remember: point-of-view is everything for a driver that connects to the rfkill -subsystem. All the details below must be measured/perceived from the point of -view of the specific driver being modified. - -The first thing one needs to know is whether his driver should be talking to -the rfkill class or to the input layer. In rare cases (platform drivers), it -could happen that you need to do both, as platform drivers often handle a -variety of devices in the same driver. - -Do not mistake input devices for rfkill controllers. The only type of "rfkill -switch" device that is to be registered with the rfkill class are those -directly controlling the circuits that cause a wireless transmitter to stop -working (or the software equivalent of them), i.e. what we call a rfkill -controller. Every other kind of "rfkill switch" is just an input device and -MUST NOT be registered with the rfkill class. - -A driver should register a device with the rfkill class when ALL of the -following conditions are met (they define a rfkill controller): - -1. The device is/controls a data communications wireless transmitter; - -2. The kernel can interact with the hardware/firmware to CHANGE the wireless - transmitter state (block/unblock TX operation); - -3. The transmitter can be made to not emit any energy when "blocked": - rfkill is not about blocking data transmissions, it is about blocking - energy emission; - -A driver should register a device with the input subsystem to issue -rfkill-related events (KEY_WLAN, KEY_BLUETOOTH, KEY_WWAN, KEY_WIMAX, -SW_RFKILL_ALL, etc) when ALL of the folowing conditions are met: - -1. It is directly related to some physical device the user interacts with, to - command the O.S./firmware/hardware to enable/disable a data communications - wireless transmitter. - - Examples of the physical device are: buttons, keys and switches the user - will press/touch/slide/switch to enable or disable the wireless - communication device. - -2. It is NOT slaved to another device, i.e. there is no other device that - issues rfkill-related input events in preference to this one. - - Please refer to the corner cases and examples section for more details. - -When in doubt, do not issue input events. For drivers that should generate -input events in some platforms, but not in others (e.g. b43), the best solution -is to NEVER generate input events in the first place. That work should be -deferred to a platform-specific kernel module (which will know when to generate -events through the rfkill notifier chain) or to userspace. This avoids the -usual maintenance problems with DMI whitelisting. - - -Corner cases and examples: -==================================== - -1. If the device is an input device that, because of hardware or firmware, -causes wireless transmitters to be blocked regardless of the kernel's will, it -is still just an input device, and NOT to be registered with the rfkill class. - -2. If the wireless transmitter switch control is read-only, it is an input -device and not to be registered with the rfkill class (and maybe not to be made -an input layer event source either, see below). - -3. If there is some other device driver *closer* to the actual hardware the -user interacted with (the button/switch/key) to issue an input event, THAT is -the device driver that should be issuing input events. - -E.g: - [RFKILL slider switch] -- [GPIO hardware] -- [WLAN card rf-kill input] - (platform driver) (wireless card driver) - -The user is closer to the RFKILL slide switch plaform driver, so the driver -which must issue input events is the platform driver looking at the GPIO -hardware, and NEVER the wireless card driver (which is just a slave). It is -very likely that there are other leaves than just the WLAN card rf-kill input -(e.g. a bluetooth card, etc)... - -On the other hand, some embedded devices do this: - - [RFKILL slider switch] -- [WLAN card rf-kill input] - (wireless card driver) - -In this situation, the wireless card driver *could* register itself as an input -device and issue rf-kill related input events... but in order to AVOID the need -for DMI whitelisting, the wireless card driver does NOT do it. Userspace (HAL) -or a platform driver (that exists only on these embedded devices) will do the -dirty job of issuing the input events. - - -COMMON MISTAKES in kernel drivers, related to rfkill: -==================================== - -1. NEVER confuse input device keys and buttons with input device switches. - - 1a. Switches are always set or reset. They report the current state - (on position or off position). - - 1b. Keys and buttons are either in the pressed or not-pressed state, and - that's it. A "button" that latches down when you press it, and - unlatches when you press it again is in fact a switch as far as input - devices go. - -Add the SW_* events you need for switches, do NOT try to emulate a button using -KEY_* events just because there is no such SW_* event yet. Do NOT try to use, -for example, KEY_BLUETOOTH when you should be using SW_BLUETOOTH instead. - -2. Input device switches (sources of EV_SW events) DO store their current state -(so you *must* initialize it by issuing a gratuitous input layer event on -driver start-up and also when resuming from sleep), and that state CAN be -queried from userspace through IOCTLs. There is no sysfs interface for this, -but that doesn't mean you should break things trying to hook it to the rfkill -class to get a sysfs interface :-) - -3. Do not issue *_RFKILL_ALL events by default, unless you are sure it is the -correct event for your switch/button. These events are emergency power-off -events when they are trying to turn the transmitters off. An example of an -input device which SHOULD generate *_RFKILL_ALL events is the wireless-kill -switch in a laptop which is NOT a hotkey, but a real sliding/rocker switch. -An example of an input device which SHOULD NOT generate *_RFKILL_ALL events by -default, is any sort of hot key that is type-specific (e.g. the one for WLAN). - - -3.1 Guidelines for wireless device drivers ------------------------------------------- - -(in this text, rfkill->foo means the foo field of struct rfkill). - -1. Each independent transmitter in a wireless device (usually there is only one -transmitter per device) should have a SINGLE rfkill class attached to it. - -2. If the device does not have any sort of hardware assistance to allow the -driver to rfkill the device, the driver should emulate it by taking all actions -required to silence the transmitter. - -3. If it is impossible to silence the transmitter (i.e. it still emits energy, -even if it is just in brief pulses, when there is no data to transmit and there -is no hardware support to turn it off) do NOT lie to the users. Do not attach -it to a rfkill class. The rfkill subsystem does not deal with data -transmission, it deals with energy emission. If the transmitter is emitting -energy, it is not blocked in rfkill terms. - -4. It doesn't matter if the device has multiple rfkill input lines affecting -the same transmitter, their combined state is to be exported as a single state -per transmitter (see rule 1). - -This rule exists because users of the rfkill subsystem expect to get (and set, -when possible) the overall transmitter rfkill state, not of a particular rfkill -line. - -5. The wireless device driver MUST NOT leave the transmitter enabled during -suspend and hibernation unless: - - 5.1. The transmitter has to be enabled for some sort of functionality - like wake-on-wireless-packet or autonomous packed forwarding in a mesh - network, and that functionality is enabled for this suspend/hibernation - cycle. - -AND - - 5.2. The device was not on a user-requested BLOCKED state before - the suspend (i.e. the driver must NOT unblock a device, not even - to support wake-on-wireless-packet or remain in the mesh). - -In other words, there is absolutely no allowed scenario where a driver can -automatically take action to unblock a rfkill controller (obviously, this deals -with scenarios where soft-blocking or both soft and hard blocking is happening. -Scenarios where hardware rfkill lines are the only ones blocking the -transmitter are outside of this rule, since the wireless device driver does not -control its input hardware rfkill lines in the first place). - -6. During resume, rfkill will try to restore its previous state. - -7. After a rfkill class is suspended, it will *not* call rfkill->toggle_radio -until it is resumed. - - -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. - -Since the device has a hardware rfkill line, it IS subject to state changes -external to rfkill. Therefore, the driver must make sure that it calls -rfkill_force_state() to keep the status always up-to-date, and it must do a -rfkill_force_state() on resume from sleep. - -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, but -it does not do any polling, so it is not enough on hardware that is subject -to state changes outside of the rfkill subsystem. - -Therefore, calling rfkill_force_state() when a state change happens is -mandatory when the device has a hardware rfkill line, or when something else -like the firmware could cause its state to be changed without going through the -rfkill class. - -Some hardware provides events when its status changes. In these cases, it is -best for the driver to not provide a get_state hook, and instead register the -rfkill class *already* with the correct status, and keep it updated using -rfkill_force_state() when it gets an event from the hardware. - -rfkill_force_state() must be used on the device resume handlers to update the -rfkill status, should there be any chance of the device status changing during -the sleep. - -There is no provision for a statically-allocated rfkill struct. You must -use rfkill_allocate() to allocate one. - -You should: - - rfkill_allocate() - - modify rfkill fields (flags, name) - - modify state to the current hardware state (THIS IS THE ONLY TIME - YOU CAN ACCESS state DIRECTLY) - - rfkill_register() - -The only way to set a device to the RFKILL_STATE_HARD_BLOCKED state is through -a suitable return of get_state() or through rfkill_force_state(). - -When a device is in the RFKILL_STATE_HARD_BLOCKED state, the only way to switch -it to a different state is through a suitable return of get_state() or through -rfkill_force_state(). - -If toggle_radio() is called to set a device to state RFKILL_STATE_SOFT_BLOCKED -when that device is already at the RFKILL_STATE_HARD_BLOCKED state, it should -not return an error. Instead, it should try to double-block the transmitter, -so that its state will change from RFKILL_STATE_HARD_BLOCKED to -RFKILL_STATE_SOFT_BLOCKED should the hardware blocking cease. - -Please refer to the source for more documentation. - -=============================================================================== -5: Userspace support - -rfkill devices issue uevents (with an action of "change"), with the following -environment variables set: +Additionally, each rfkill device is registered in sysfs and there has the +following attributes: + + name: Name assigned by driver to this key (interface or driver name). + type: Driver type string ("wlan", "bluetooth", etc). + persistent: Whether the soft blocked state is initialised from + non-volatile storage at startup. + state: Current state of the transmitter + 0: RFKILL_STATE_SOFT_BLOCKED + transmitter is turned off by software + 1: RFKILL_STATE_UNBLOCKED + transmitter is (potentially) active + 2: RFKILL_STATE_HARD_BLOCKED + transmitter is forced off by something outside of + the driver's control. + This file is deprecated because it can only properly show + three of the four possible states, soft-and-hard-blocked is + missing. + claim: 0: Kernel handles events + This file is deprecated because there no longer is a way to + claim just control over a single rfkill instance. + +rfkill devices also 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 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, the device rfkill state (if not yet in -the requested state), will be will be toggled accordingly. - -For the "claim" entry writing 1 to it means that the kernel no longer handles -key events even though RFKILL_INPUT input was enabled. When "claim" has been -set to 0, userspace should make sure that it listens for the input events or -check the sysfs "state" entry regularly to correctly perform the required tasks -when the rkfill key is pressed. - -A note about input devices and EV_SW events: - -In order to know the current state of an input device switch (like -SW_RFKILL_ALL), you will need to use an IOCTL. That information is not -available through sysfs in a generic way at this time, and it is not available -through the rfkill class AT ALL. +The contents of these variables corresponds to the "name", "state" and +"type" sysfs files explained above. diff --git a/Documentation/robust-futex-ABI.txt b/Documentation/robust-futex-ABI.txt index 535f69fab45f..fd1cd8aae4eb 100644 --- a/Documentation/robust-futex-ABI.txt +++ b/Documentation/robust-futex-ABI.txt @@ -135,7 +135,7 @@ manipulating this list), the user code must observe the following protocol on 'lock entry' insertion and removal: On insertion: - 1) set the 'list_op_pending' word to the address of the 'lock word' + 1) set the 'list_op_pending' word to the address of the 'lock entry' to be inserted, 2) acquire the futex lock, 3) add the lock entry, with its thread id (TID) in the bottom 29 bits @@ -143,7 +143,7 @@ On insertion: 4) clear the 'list_op_pending' word. On removal: - 1) set the 'list_op_pending' word to the address of the 'lock word' + 1) set the 'list_op_pending' word to the address of the 'lock entry' to be removed, 2) remove the lock entry for this lock from the 'head' list, 2) release the futex lock, and diff --git a/Documentation/s390/Debugging390.txt b/Documentation/s390/Debugging390.txt index 10711d9f0788..1eb576a023bd 100644 --- a/Documentation/s390/Debugging390.txt +++ b/Documentation/s390/Debugging390.txt @@ -1984,7 +1984,7 @@ break *$pc break *0x400618 -heres a really useful one for large programs +Here's a really useful one for large programs rbr Set a breakpoint for all functions matching REGEXP e.g. @@ -2211,7 +2211,7 @@ Breakpoint 2 at 0x4d87a4: file top.c, line 2609. #5 0x51692c in readline_internal () at readline.c:521 #6 0x5164fe in readline (prompt=0x7ffff810 "\177ÂÿÂøx\177ÂÿÂ÷ÂØ\177ÂÿÂøxÂÀ") at readline.c:349 -#7 0x4d7a8a in command_line_input (prrompt=0x564420 "(gdb) ", repeat=1, +#7 0x4d7a8a in command_line_input (prompt=0x564420 "(gdb) ", repeat=1, annotation_suffix=0x4d6b44 "prompt") at top.c:2091 #8 0x4d6cf0 in command_loop () at top.c:1345 #9 0x4e25bc in main (argc=1, argv=0x7ffffdf4) at main.c:635 diff --git a/Documentation/scheduler/sched-nice-design.txt b/Documentation/scheduler/sched-nice-design.txt index e2bae5a577e3..3ac1e46d5365 100644 --- a/Documentation/scheduler/sched-nice-design.txt +++ b/Documentation/scheduler/sched-nice-design.txt @@ -55,7 +55,7 @@ To sum it up: we always wanted to make nice levels more consistent, but within the constraints of HZ and jiffies and their nasty design level coupling to timeslices and granularity it was not really viable. -The second (less frequent but still periodically occuring) complaint +The second (less frequent but still periodically occurring) complaint about Linux's nice level support was its assymetry around the origo (which you can see demonstrated in the picture above), or more accurately: the fact that nice level behavior depended on the _absolute_ diff --git a/Documentation/scheduler/sched-rt-group.txt b/Documentation/scheduler/sched-rt-group.txt index 5ba4d3fc625a..1df7f9cdab05 100644 --- a/Documentation/scheduler/sched-rt-group.txt +++ b/Documentation/scheduler/sched-rt-group.txt @@ -4,6 +4,7 @@ CONTENTS ======== +0. WARNING 1. Overview 1.1 The problem 1.2 The solution @@ -14,6 +15,23 @@ CONTENTS 3. Future plans +0. WARNING +========== + + Fiddling with these settings can result in an unstable system, the knobs are + root only and assumes root knows what he is doing. + +Most notable: + + * very small values in sched_rt_period_us can result in an unstable + system when the period is smaller than either the available hrtimer + resolution, or the time it takes to handle the budget refresh itself. + + * very small values in sched_rt_runtime_us can result in an unstable + system when the runtime is so small the system has difficulty making + forward progress (NOTE: the migration thread and kstopmachine both + are real-time processes). + 1. Overview =========== @@ -169,7 +187,7 @@ get their allocated time. Implementing SCHED_EDF might take a while to complete. Priority Inheritance is the biggest challenge as the current linux PI infrastructure is geared towards -the limited static priority levels 0-139. With deadline scheduling you need to +the limited static priority levels 0-99. With deadline scheduling you need to do deadline inheritance (since priority is inversely proportional to the deadline delta (deadline - now). diff --git a/Documentation/scsi/aic79xx.txt b/Documentation/scsi/aic79xx.txt index 683ccae00ad4..c014eccaf19f 100644 --- a/Documentation/scsi/aic79xx.txt +++ b/Documentation/scsi/aic79xx.txt @@ -194,7 +194,7 @@ The following information is available in this file: - Packetized SCSI Protocol at 160MB/s and 320MB/s - Quick Arbitration Selection (QAS) - Retained Training Information (Rev B. ASIC only) - - Interrupt Coalessing + - Interrupt Coalescing - Initiator Mode (target mode not currently supported) - Support for the PCI-X standard up to 133MHz diff --git a/Documentation/scsi/ncr53c8xx.txt b/Documentation/scsi/ncr53c8xx.txt index 230e30846ef2..08e2b4d04aab 100644 --- a/Documentation/scsi/ncr53c8xx.txt +++ b/Documentation/scsi/ncr53c8xx.txt @@ -206,7 +206,7 @@ of MOVE MEMORY instructions. The 896 and the 895A allows handling of the phase mismatch context from SCRIPTS (avoids the phase mismatch interrupt that stops the SCSI processor until the C code has saved the context of the transfer). -Implementing this without using LOAD/STORE instructions would be painfull +Implementing this without using LOAD/STORE instructions would be painful and I didn't even want to try it. The 896 chip supports 64 bit PCI transactions and addressing, while the @@ -240,7 +240,7 @@ characteristics. This feature may also reduce average command latency. In order to really gain advantage of this feature, devices must have a reasonable cache size (No miracle is to be expected for a low-end hard disk with 128 KB or less). -Some kown SCSI devices do not properly support tagged command queuing. +Some known SCSI devices do not properly support tagged command queuing. Generally, firmware revisions that fix this kind of problems are available at respective vendor web/ftp sites. All I can say is that the hard disks I use on my machines behave well with diff --git a/Documentation/scsi/scsi_fc_transport.txt b/Documentation/scsi/scsi_fc_transport.txt index e5b071d46619..d7f181701dc2 100644 --- a/Documentation/scsi/scsi_fc_transport.txt +++ b/Documentation/scsi/scsi_fc_transport.txt @@ -1,10 +1,11 @@ SCSI FC Tansport ============================================= -Date: 4/12/2007 +Date: 11/18/2008 Kernel Revisions for features: rports : <> - vports : 2.6.22 (? TBD) + vports : 2.6.22 + bsg support : 2.6.30 (?TBD?) Introduction @@ -15,6 +16,7 @@ The FC transport can be found at: drivers/scsi/scsi_transport_fc.c include/scsi/scsi_transport_fc.h include/scsi/scsi_netlink_fc.h + include/scsi/scsi_bsg_fc.h This file is found at Documentation/scsi/scsi_fc_transport.txt @@ -472,6 +474,14 @@ int fc_vport_terminate(struct fc_vport *vport) +FC BSG support (CT & ELS passthru, and more) +======================================================================== +<< To Be Supplied >> + + + + + Credits ======= The following people have contributed to this document: diff --git a/Documentation/scsi/scsi_mid_low_api.txt b/Documentation/scsi/scsi_mid_low_api.txt index a6d5354639b2..de67229251d8 100644 --- a/Documentation/scsi/scsi_mid_low_api.txt +++ b/Documentation/scsi/scsi_mid_low_api.txt @@ -1271,6 +1271,11 @@ of interest: hostdata[0] - area reserved for LLD at end of struct Scsi_Host. Size is set by the second argument (named 'xtr_bytes') to scsi_host_alloc() or scsi_register(). + vendor_id - a unique value that identifies the vendor supplying + the LLD for the Scsi_Host. Used most often in validating + vendor-specific message requests. Value consists of an + identifier type and a vendor-specific value. + See scsi_netlink.h for a description of valid formats. The scsi_host structure is defined in include/scsi/scsi_host.h diff --git a/Documentation/scsi/sym53c8xx_2.txt b/Documentation/scsi/sym53c8xx_2.txt index 49ea5c58c6bc..eb9a7b905b64 100644 --- a/Documentation/scsi/sym53c8xx_2.txt +++ b/Documentation/scsi/sym53c8xx_2.txt @@ -206,7 +206,7 @@ characteristics. This feature may also reduce average command latency. In order to really gain advantage of this feature, devices must have a reasonable cache size (No miracle is to be expected for a low-end hard disk with 128 KB or less). -Some kown old SCSI devices do not properly support tagged command queuing. +Some known old SCSI devices do not properly support tagged command queuing. Generally, firmware revisions that fix this kind of problems are available at respective vendor web/ftp sites. All I can say is that I never have had problem with tagged queuing using diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 012858d2b119..4252697a95d6 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -460,6 +460,25 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. The power-management is supported. + Module snd-ctxfi + ---------------- + + Module for Creative Sound Blaster X-Fi boards (20k1 / 20k2 chips) + * Creative Sound Blaster X-Fi Titanium Fatal1ty Champion Series + * Creative Sound Blaster X-Fi Titanium Fatal1ty Professional Series + * Creative Sound Blaster X-Fi Titanium Professional Audio + * Creative Sound Blaster X-Fi Titanium + * Creative Sound Blaster X-Fi Elite Pro + * Creative Sound Blaster X-Fi Platinum + * Creative Sound Blaster X-Fi Fatal1ty + * Creative Sound Blaster X-Fi XtremeGamer + * Creative Sound Blaster X-Fi XtremeMusic + + reference_rate - reference sample rate, 44100 or 48000 (default) + multiple - multiple to ref. sample rate, 1 or 2 (default) + + This module supports multiple cards. + Module snd-darla20 ------------------ @@ -754,7 +773,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. single_cmd - Use single immediate commands to communicate with codecs (for debugging only) enable_msi - Enable Message Signaled Interrupt (MSI) (default = off) - power_save - Automatic power-saving timtout (in second, 0 = + power_save - Automatic power-saving timeout (in second, 0 = disable) power_save_controller - Reset HD-audio controller in power-saving mode (default = on) @@ -925,6 +944,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. * Onkyo SE-90PCI * Onkyo SE-200PCI * ESI Juli@ + * ESI Maya44 * Hercules Fortissimo IV * EGO-SYS WaveTerminal 192M @@ -933,7 +953,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. prodigy71xt, prodigy71hifi, prodigyhd2, prodigy192, juli, aureon51, aureon71, universe, ap192, k8x800, phase22, phase28, ms300, av710, se200pci, se90pci, - fortissimo4, sn25p, WT192M + fortissimo4, sn25p, WT192M, maya44 This module supports multiple cards and autoprobe. @@ -1093,6 +1113,13 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. This module supports multiple cards. The driver requires the firmware loader support on kernel. + Module snd-lx6464es + ------------------- + + Module for Digigram LX6464ES boards + + This module supports multiple cards. + Module snd-maestro3 ------------------- @@ -1543,13 +1570,15 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. Module snd-sc6000 ----------------- - Module for Gallant SC-6000 soundcard. + Module for Gallant SC-6000 soundcard and later models: SC-6600 + and SC-7000. port - Port # (0x220 or 0x240) mss_port - MSS Port # (0x530 or 0xe80) irq - IRQ # (5,7,9,10,11) mpu_irq - MPU-401 IRQ # (5,7,9,10) ,0 - no MPU-401 irq dma - DMA # (1,3,0) + joystick - Enable gameport - 0 = disable (default), 1 = enable This module supports multiple cards. @@ -1859,7 +1888,8 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. ------------------- Module for sound cards based on the Asus AV100/AV200 chips, - i.e., Xonar D1, DX, D2, D2X, HDAV1.3 (Deluxe), and Essence STX. + i.e., Xonar D1, DX, D2, D2X, HDAV1.3 (Deluxe), Essence ST + (Deluxe) and Essence STX. This module supports autoprobe and multiple cards. diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt index 322869fc8a9e..0d8d23581c44 100644 --- a/Documentation/sound/alsa/HD-Audio-Models.txt +++ b/Documentation/sound/alsa/HD-Audio-Models.txt @@ -36,6 +36,7 @@ ALC260 acer Acer TravelMate will Will laptops (PB V7900) replacer Replacer 672V + favorit100 Maxdata Favorit 100XS basic fixed pin assignment (old default model) test for testing/debugging purpose, almost all controls can adjusted. Appearing only when compiled with @@ -85,10 +86,11 @@ ALC269 eeepc-p703 ASUS Eeepc P703 P900A eeepc-p901 ASUS Eeepc P901 S101 fujitsu FSC Amilo + lifebook Fujitsu Lifebook S6420 auto auto-config reading BIOS (default) -ALC662/663 -========== +ALC662/663/272 +============== 3stack-dig 3-stack (2-channel) with SPDIF 3stack-6ch 3-stack (6-channel) 3stack-6ch-dig 3-stack (6-channel) with SPDIF @@ -107,6 +109,9 @@ ALC662/663 asus-mode4 ASUS asus-mode5 ASUS asus-mode6 ASUS + dell Dell with ALC272 + dell-zm1 Dell ZM1 with ALC272 + samsung-nc10 Samsung NC10 mini notebook auto auto-config reading BIOS (default) ALC882/885 @@ -118,6 +123,7 @@ ALC882/885 asus-a7j ASUS A7J asus-a7m ASUS A7M macpro MacPro support + mb5 Macbook 5,1 mbp3 Macbook Pro rev3 imac24 iMac 24'' with jack detection w2jc ASUS W2JC @@ -133,10 +139,13 @@ ALC883/888 acer Acer laptops (Travelmate 3012WTMi, Aspire 5600, etc) acer-aspire Acer Aspire 9810 acer-aspire-4930g Acer Aspire 4930G + acer-aspire-6530g Acer Aspire 6530G + acer-aspire-8930g Acer Aspire 8930G medion Medion Laptops medion-md2 Medion MD2 targa-dig Targa/MSI - targa-2ch-dig Targs/MSI with 2-channel + targa-2ch-dig Targa/MSI with 2-channel + targa-8ch-dig Targa/MSI with 8-channel (MSI GX620) laptop-eapd 3-jack with SPDIF I/O and EAPD (Clevo M540JE, M550JE) lenovo-101e Lenovo 101E lenovo-nb0763 Lenovo NB0763 @@ -150,6 +159,9 @@ ALC883/888 fujitsu-pi2515 Fujitsu AMILO Pi2515 fujitsu-xa3530 Fujitsu AMILO XA3530 3stack-6ch-intel Intel DG33* boards + asus-p5q ASUS P5Q-EM boards + mb31 MacBook 3,1 + sony-vaio-tt Sony VAIO TT auto auto-config reading BIOS (default) ALC861/660 @@ -348,6 +360,7 @@ STAC92HD71B* hp-m4 HP mini 1000 hp-dv5 HP dv series hp-hdx HP HDX series + hp-dv4-1222nr HP dv4-1222nr (with LED support) auto BIOS setup (default) STAC92HD73* diff --git a/Documentation/sound/alsa/HD-Audio.txt b/Documentation/sound/alsa/HD-Audio.txt index 88b7433d2f11..71ac995b1915 100644 --- a/Documentation/sound/alsa/HD-Audio.txt +++ b/Documentation/sound/alsa/HD-Audio.txt @@ -16,7 +16,7 @@ methods for the HD-audio hardware. The HD-audio component consists of two parts: the controller chip and the codec chips on the HD-audio bus. Linux provides a single driver for all controllers, snd-hda-intel. Although the driver name contains -a word of a well-known harware vendor, it's not specific to it but for +a word of a well-known hardware vendor, it's not specific to it but for all controller chips by other companies. Since the HD-audio controllers are supposed to be compatible, the single snd-hda-driver should work in most cases. But, not surprisingly, there are known diff --git a/Documentation/sound/alsa/Procfile.txt b/Documentation/sound/alsa/Procfile.txt index cfac20cf9e33..381908d8ca42 100644 --- a/Documentation/sound/alsa/Procfile.txt +++ b/Documentation/sound/alsa/Procfile.txt @@ -88,26 +88,34 @@ card*/pcm*/info substreams, etc. card*/pcm*/xrun_debug - This file appears when CONFIG_SND_DEBUG=y. - This shows the status of xrun (= buffer overrun/xrun) debug of - ALSA PCM middle layer, as an integer from 0 to 2. The value - can be changed by writing to this file, such as + This file appears when CONFIG_SND_DEBUG=y and + CONFIG_PCM_XRUN_DEBUG=y. + This shows the status of xrun (= buffer overrun/xrun) and + invalid PCM position debug/check of ALSA PCM middle layer. + It takes an integer value, can be changed by writing to this + file, such as - # cat 2 > /proc/asound/card0/pcm0p/xrun_debug + # cat 5 > /proc/asound/card0/pcm0p/xrun_debug - When this value is greater than 0, the driver will show the - messages to kernel log when an xrun is detected. The debug - message is shown also when the invalid H/W pointer is detected - at the update of periods (usually called from the interrupt + The value consists of the following bit flags: + bit 0 = Enable XRUN/jiffies debug messages + bit 1 = Show stack trace at XRUN / jiffies check + bit 2 = Enable additional jiffies check + + When the bit 0 is set, the driver will show the messages to + kernel log when an xrun is detected. The debug message is + shown also when the invalid H/W pointer is detected at the + update of periods (usually called from the interrupt handler). - When this value is greater than 1, the driver will show the - stack trace additionally. This may help the debugging. + When the bit 1 is set, the driver will show the stack trace + additionally. This may help the debugging. - Since 2.6.30, this option also enables the hwptr check using + Since 2.6.30, this option can enable the hwptr check using jiffies. This detects spontaneous invalid pointer callback values, but can be lead to too much corrections for a (mostly buggy) hardware that doesn't give smooth pointer updates. + This feature is enabled via the bit 2. card*/pcm*/sub*/info The general information of this PCM sub-stream. diff --git a/Documentation/sound/alsa/README.maya44 b/Documentation/sound/alsa/README.maya44 new file mode 100644 index 000000000000..0e41576fa13e --- /dev/null +++ b/Documentation/sound/alsa/README.maya44 @@ -0,0 +1,163 @@ +NOTE: The following is the original document of Rainer's patch that the +current maya44 code based on. Some contents might be obsoleted, but I +keep here as reference -- tiwai + +---------------------------------------------------------------- + +STATE OF DEVELOPMENT: + +This driver is being developed on the initiative of Piotr Makowski (oponek@gmail.com) and financed by Lars Bergmann. +Development is carried out by Rainer Zimmermann (mail@lightshed.de). + +ESI provided a sample Maya44 card for the development work. + +However, unfortunately it has turned out difficult to get detailed programming information, so I (Rainer Zimmermann) had to find out some card-specific information by experiment and conjecture. Some information (in particular, several GPIO bits) is still missing. + +This is the first testing version of the Maya44 driver released to the alsa-devel mailing list (Feb 5, 2008). + + +The following functions work, as tested by Rainer Zimmermann and Piotr Makowski: + +- playback and capture at all sampling rates +- input/output level +- crossmixing +- line/mic switch +- phantom power switch +- analogue monitor a.k.a bypass + + +The following functions *should* work, but are not fully tested: + +- Channel 3+4 analogue - S/PDIF input switching +- S/PDIF output +- all inputs/outputs on the M/IO/DIO extension card +- internal/external clock selection + + +*In particular, we would appreciate testing of these functions by anyone who has access to an M/IO/DIO extension card.* + + +Things that do not seem to work: + +- The level meters ("multi track") in 'alsamixer' do not seem to react to signals in (if this is a bug, it would probably be in the existing ICE1724 code). + +- Ardour 2.1 seems to work only via JACK, not using ALSA directly or via OSS. This still needs to be tracked down. + + +DRIVER DETAILS: + +the following files were added: + +pci/ice1724/maya44.c - Maya44 specific code +pci/ice1724/maya44.h +pci/ice1724/ice1724.patch +pci/ice1724/ice1724.h.patch - PROPOSED patch to ice1724.h (see SAMPLING RATES) +i2c/other/wm8776.c - low-level access routines for Wolfson WM8776 codecs +include/wm8776.h + + +Note that the wm8776.c code is meant to be card-independent and does not actually register the codec with the ALSA infrastructure. +This is done in maya44.c, mainly because some of the WM8776 controls are used in Maya44-specific ways, and should be named appropriately. + + +the following files were created in pci/ice1724, simply #including the corresponding file from the alsa-kernel tree: + +wtm.h +vt1720_mobo.h +revo.h +prodigy192.h +pontis.h +phase.h +maya44.h +juli.h +aureon.h +amp.h +envy24ht.h +se.h +prodigy_hifi.h + + +*I hope this is the correct way to do things.* + + +SAMPLING RATES: + +The Maya44 card (or more exactly, the Wolfson WM8776 codecs) allow a maximum sampling rate of 192 kHz for playback and 92 kHz for capture. + +As the ICE1724 chip only allows one global sampling rate, this is handled as follows: + +* setting the sampling rate on any open PCM device on the maya44 card will always set the *global* sampling rate for all playback and capture channels. + +* In the current state of the driver, setting rates of up to 192 kHz is permitted even for capture devices. + +*AVOID CAPTURING AT RATES ABOVE 96kHz*, even though it may appear to work. The codec cannot actually capture at such rates, meaning poor quality. + + +I propose some additional code for limiting the sampling rate when setting on a capture pcm device. However because of the global sampling rate, this logic would be somewhat problematic. + +The proposed code (currently deactivated) is in ice1712.h.patch, ice1724.c and maya44.c (in pci/ice1712). + + +SOUND DEVICES: + +PCM devices correspond to inputs/outputs as follows (assuming Maya44 is card #0): + +hw:0,0 input - stereo, analog input 1+2 +hw:0,0 output - stereo, analog output 1+2 +hw:0,1 input - stereo, analog input 3+4 OR S/PDIF input +hw:0,1 output - stereo, analog output 3+4 (and SPDIF out) + + +NAMING OF MIXER CONTROLS: + +(for more information about the signal flow, please refer to the block diagram on p.24 of the ESI Maya44 manual, or in the ESI windows software). + + +PCM: (digital) output level for channel 1+2 +PCM 1: same for channel 3+4 + +Mic Phantom+48V: switch for +48V phantom power for electrostatic microphones on input 1/2. + Make sure this is not turned on while any other source is connected to input 1/2. + It might damage the source and/or the maya44 card. + +Mic/Line input: if switch is is on, input jack 1/2 is microphone input (mono), otherwise line input (stereo). + +Bypass: analogue bypass from ADC input to output for channel 1+2. Same as "Monitor" in the windows driver. +Bypass 1: same for channel 3+4. + +Crossmix: cross-mixer from channels 1+2 to channels 3+4 +Crossmix 1: cross-mixer from channels 3+4 to channels 1+2 + +IEC958 Output: switch for S/PDIF output. + This is not supported by the ESI windows driver. + S/PDIF should output the same signal as channel 3+4. [untested!] + + +Digitial output selectors: + + These switches allow a direct digital routing from the ADCs to the DACs. + Each switch determines where the digital input data to one of the DACs comes from. + They are not supported by the ESI windows driver. + For normal operation, they should all be set to "PCM out". + +H/W: Output source channel 1 +H/W 1: Output source channel 2 +H/W 2: Output source channel 3 +H/W 3: Output source channel 4 + +H/W 4 ... H/W 9: unknown function, left in to enable testing. + Possibly some of these control S/PDIF output(s). + If these turn out to be unused, they will go away in later driver versions. + +Selectable values for each of the digital output selectors are: + "PCM out" -> DAC output of the corresponding channel (default setting) + "Input 1"... + "Input 4" -> direct routing from ADC output of the selected input channel + + +-------- + +Feb 14, 2008 +Rainer Zimmermann +mail@lightshed.de + diff --git a/Documentation/sound/alsa/hda_codec.txt b/Documentation/sound/alsa/hda_codec.txt index 34e87ec1379c..de8efbc7e4bd 100644 --- a/Documentation/sound/alsa/hda_codec.txt +++ b/Documentation/sound/alsa/hda_codec.txt @@ -114,7 +114,7 @@ For writing a sequence of verbs, use snd_hda_sequence_write(). There are variants of cached read/write, snd_hda_codec_write_cache(), snd_hda_sequence_write_cache(). These are used for recording the -register states for the power-mangement resume. When no PM is needed, +register states for the power-management resume. When no PM is needed, these are equivalent with non-cached version. To retrieve the number of sub nodes connected to the given node, use diff --git a/Documentation/sound/alsa/soc/dapm.txt b/Documentation/sound/alsa/soc/dapm.txt index 9e6763264a2e..9ac842be9b4f 100644 --- a/Documentation/sound/alsa/soc/dapm.txt +++ b/Documentation/sound/alsa/soc/dapm.txt @@ -62,6 +62,7 @@ Audio DAPM widgets fall into a number of types:- o Mic - Mic (and optional Jack) o Line - Line Input/Output (and optional Jack) o Speaker - Speaker + o Supply - Power or clock supply widget used by other widgets. o Pre - Special PRE widget (exec before all others) o Post - Special POST widget (exec after all others) diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt index f11ca7979fa6..322a00bb99d9 100644 --- a/Documentation/sysctl/kernel.txt +++ b/Documentation/sysctl/kernel.txt @@ -32,6 +32,7 @@ show up in /proc/sys/kernel: - kstack_depth_to_print [ X86 only ] - l2cr [ PPC only ] - modprobe ==> Documentation/debugging-modules.txt +- modules_disabled - msgmax - msgmnb - msgmni @@ -184,6 +185,16 @@ kernel stack. ============================================================== +modules_disabled: + +A toggle value indicating if modules are allowed to be loaded +in an otherwise modular kernel. This toggle defaults to off +(0), but can be set true (1). Once true, modules can be +neither loaded nor unloaded, and the toggle cannot be set back +to false. + +============================================================== + osrelease, ostype & version: # cat osrelease diff --git a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt index c302ddf629a0..c4de6359d440 100644 --- a/Documentation/sysctl/vm.txt +++ b/Documentation/sysctl/vm.txt @@ -233,8 +233,8 @@ These protections are added to score to judge whether this zone should be used for page allocation or should be reclaimed. In this example, if normal pages (index=2) are required to this DMA zone and -pages_high is used for watermark, the kernel judges this zone should not be -used because pages_free(1355) is smaller than watermark + protection[2] +watermark[WMARK_HIGH] is used for watermark, the kernel judges this zone should +not be used because pages_free(1355) is smaller than watermark + protection[2] (4 + 2004 = 2008). If this protection value is 0, this zone would be used for normal page requirement. If requirement is DMA zone(index=0), protection[0] (=0) is used. @@ -280,9 +280,10 @@ The default value is 65536. min_free_kbytes: This is used to force the Linux VM to keep a minimum number -of kilobytes free. The VM uses this number to compute a pages_min -value for each lowmem zone in the system. Each lowmem zone gets -a number of reserved free pages based proportionally on its size. +of kilobytes free. The VM uses this number to compute a +watermark[WMARK_MIN] value for each lowmem zone in the system. +Each lowmem zone gets a number of reserved free pages based +proportionally on its size. Some minimal amount of memory is needed to satisfy PF_MEMALLOC allocations; if you set this to lower than 1024KB, your system will @@ -314,10 +315,14 @@ min_unmapped_ratio: This is available only on NUMA kernels. -A percentage of the total pages in each zone. Zone reclaim will only -occur if more than this percentage of pages are file backed and unmapped. -This is to insure that a minimal amount of local pages is still available for -file I/O even if the node is overallocated. +This is a percentage of the total pages in each zone. Zone reclaim will +only occur if more than this percentage of pages are in a state that +zone_reclaim_mode allows to be reclaimed. + +If zone_reclaim_mode has the value 4 OR'd, then the percentage is compared +against all file-backed unmapped pages including swapcache pages and tmpfs +files. Otherwise, only unmapped pages backed by normal files but not tmpfs +files and similar are considered. The default is 1 percent. @@ -358,7 +363,7 @@ nr_pdflush_threads The current number of pdflush threads. This value is read-only. The value changes according to the number of dirty pages in the system. -When neccessary, additional pdflush threads are created, one per second, up to +When necessary, additional pdflush threads are created, one per second, up to nr_pdflush_threads_max. ============================================================== @@ -565,7 +570,7 @@ swappiness This control is used to define how aggressive the kernel will swap memory pages. Higher values will increase agressiveness, lower values -descrease the amount of swap. +decrease the amount of swap. The default value is 60. diff --git a/Documentation/timers/hpet.txt b/Documentation/timers/hpet.txt index e7c09abcfab4..04763a325520 100644 --- a/Documentation/timers/hpet.txt +++ b/Documentation/timers/hpet.txt @@ -7,7 +7,7 @@ by Intel and Microsoft which can be found at Each HPET has one fixed-rate counter (at 10+ MHz, hence "High Precision") and up to 32 comparators. Normally three or more comparators are provided, -each of which can generate oneshot interupts and at least one of which has +each of which can generate oneshot interrupts and at least one of which has additional hardware to support periodic interrupts. The comparators are also called "timers", which can be misleading since usually timers are independent of each other ... these share a counter, complicating resets. diff --git a/Documentation/timers/timer_stats.txt b/Documentation/timers/timer_stats.txt index 20d368c59814..9bd00fc2e823 100644 --- a/Documentation/timers/timer_stats.txt +++ b/Documentation/timers/timer_stats.txt @@ -62,7 +62,7 @@ Timerstats sample period: 3.888770 s The first column is the number of events, the second column the pid, the third column is the name of the process. The forth column shows the function which -initialized the timer and in parantheses the callback function which was +initialized the timer and in parenthesis the callback function which was executed on expiry. Thomas, Ingo diff --git a/Documentation/trace/events.txt b/Documentation/trace/events.txt new file mode 100644 index 000000000000..f157d7594ea7 --- /dev/null +++ b/Documentation/trace/events.txt @@ -0,0 +1,90 @@ + Event Tracing + + Documentation written by Theodore Ts'o + Updated by Li Zefan + +1. Introduction +=============== + +Tracepoints (see Documentation/trace/tracepoints.txt) can be used +without creating custom kernel modules to register probe functions +using the event tracing infrastructure. + +Not all tracepoints can be traced using the event tracing system; +the kernel developer must provide code snippets which define how the +tracing information is saved into the tracing buffer, and how the +tracing information should be printed. + +2. Using Event Tracing +====================== + +2.1 Via the 'set_event' interface +--------------------------------- + +The events which are available for tracing can be found in the file +/debug/tracing/available_events. + +To enable a particular event, such as 'sched_wakeup', simply echo it +to /debug/tracing/set_event. For example: + + # echo sched_wakeup >> /debug/tracing/set_event + +[ Note: '>>' is necessary, otherwise it will firstly disable + all the events. ] + +To disable an event, echo the event name to the set_event file prefixed +with an exclamation point: + + # echo '!sched_wakeup' >> /debug/tracing/set_event + +To disable all events, echo an empty line to the set_event file: + + # echo > /debug/tracing/set_event + +To enable all events, echo '*:*' or '*:' to the set_event file: + + # echo *:* > /debug/tracing/set_event + +The events are organized into subsystems, such as ext4, irq, sched, +etc., and a full event name looks like this: :. The +subsystem name is optional, but it is displayed in the available_events +file. All of the events in a subsystem can be specified via the syntax +":*"; for example, to enable all irq events, you can use the +command: + + # echo 'irq:*' > /debug/tracing/set_event + +2.2 Via the 'enable' toggle +--------------------------- + +The events available are also listed in /debug/tracing/events/ hierarchy +of directories. + +To enable event 'sched_wakeup': + + # echo 1 > /debug/tracing/events/sched/sched_wakeup/enable + +To disable it: + + # echo 0 > /debug/tracing/events/sched/sched_wakeup/enable + +To enable all events in sched subsystem: + + # echo 1 > /debug/tracing/events/sched/enable + +To eanble all events: + + # echo 1 > /debug/tracing/events/enable + +When reading one of these enable files, there are four results: + + 0 - all events this file affects are disabled + 1 - all events this file affects are enabled + X - there is a mixture of events enabled and disabled + ? - this file does not affect any event + +3. Defining an event-enabled tracepoint +======================================= + +See The example provided in samples/trace_events + diff --git a/Documentation/trace/ftrace.txt b/Documentation/trace/ftrace.txt index fd9a3e693813..a39b3c749de5 100644 --- a/Documentation/trace/ftrace.txt +++ b/Documentation/trace/ftrace.txt @@ -7,7 +7,6 @@ Copyright 2008 Red Hat Inc. (dual licensed under the GPL v2) Reviewers: Elias Oltmanns, Randy Dunlap, Andrew Morton, John Kacur, and David Teigland. - Written for: 2.6.28-rc2 Introduction @@ -33,13 +32,26 @@ The File System Ftrace uses the debugfs file system to hold the control files as well as the files to display output. -To mount the debugfs system: +When debugfs is configured into the kernel (which selecting any ftrace +option will do) the directory /sys/kernel/debug will be created. To mount +this directory, you can add to your /etc/fstab file: - # mkdir /debug - # mount -t debugfs nodev /debug + debugfs /sys/kernel/debug debugfs defaults 0 0 -( Note: it is more common to mount at /sys/kernel/debug, but for - simplicity this document will use /debug) +Or you can mount it at run time with: + + mount -t debugfs nodev /sys/kernel/debug + +For quicker access to that directory you may want to make a soft link to +it: + + ln -s /sys/kernel/debug /debug + +Any selected ftrace option will also create a directory called tracing +within the debugfs. The rest of the document will assume that you are in +the ftrace directory (cd /sys/kernel/debug/tracing) and will only concentrate +on the files within that directory and not distract from the content with +the extended "/sys/kernel/debug/tracing" path name. That's it! (assuming that you have ftrace configured into your kernel) @@ -179,7 +191,7 @@ Here is the list of current tracers that may be configured. Function call tracer to trace all kernel functions. - "function_graph_tracer" + "function_graph" Similar to the function tracer except that the function tracer probes the functions on their entry @@ -389,18 +401,18 @@ trace_options The trace_options file is used to control what gets printed in the trace output. To see what is available, simply cat the file: - cat /debug/tracing/trace_options + cat trace_options print-parent nosym-offset nosym-addr noverbose noraw nohex nobin \ noblock nostacktrace nosched-tree nouserstacktrace nosym-userobj To disable one of the options, echo in the option prepended with "no". - echo noprint-parent > /debug/tracing/trace_options + echo noprint-parent > trace_options To enable an option, leave off the "no". - echo sym-offset > /debug/tracing/trace_options + echo sym-offset > trace_options Here are the available options: @@ -476,11 +488,11 @@ sched_switch This tracer simply records schedule switches. Here is an example of how to use it. - # echo sched_switch > /debug/tracing/current_tracer - # echo 1 > /debug/tracing/tracing_enabled + # echo sched_switch > current_tracer + # echo 1 > tracing_enabled # sleep 1 - # echo 0 > /debug/tracing/tracing_enabled - # cat /debug/tracing/trace + # echo 0 > tracing_enabled + # cat trace # tracer: sched_switch # @@ -518,9 +530,18 @@ priority with zero (0) being the highest priority and the nice values starting at 100 (nice -20). Below is a quick chart to map the kernel priority to user land priorities. - Kernel priority: 0 to 99 ==> user RT priority 99 to 0 - Kernel priority: 100 to 139 ==> user nice -20 to 19 - Kernel priority: 140 ==> idle task priority + Kernel Space User Space + =============================================================== + 0(high) to 98(low) user RT priority 99(high) to 1(low) + with SCHED_RR or SCHED_FIFO + --------------------------------------------------------------- + 99 sched_priority is not used in scheduling + decisions(it must be specified as 0) + --------------------------------------------------------------- + 100(high) to 139(low) user nice -20(high) to 19(low) + --------------------------------------------------------------- + 140 idle task priority + --------------------------------------------------------------- The task states are: @@ -574,13 +595,13 @@ new trace is saved. To reset the maximum, echo 0 into tracing_max_latency. Here is an example: - # echo irqsoff > /debug/tracing/current_tracer - # echo 0 > /debug/tracing/tracing_max_latency - # echo 1 > /debug/tracing/tracing_enabled + # echo irqsoff > current_tracer + # echo 0 > tracing_max_latency + # echo 1 > tracing_enabled # ls -ltr [...] - # echo 0 > /debug/tracing/tracing_enabled - # cat /debug/tracing/latency_trace + # echo 0 > tracing_enabled + # cat latency_trace # tracer: irqsoff # irqsoff latency trace v1.1.5 on 2.6.26 @@ -681,13 +702,13 @@ Like the irqsoff tracer, it records the maximum latency for which preemption was disabled. The control of preemptoff tracer is much like the irqsoff tracer. - # echo preemptoff > /debug/tracing/current_tracer - # echo 0 > /debug/tracing/tracing_max_latency - # echo 1 > /debug/tracing/tracing_enabled + # echo preemptoff > current_tracer + # echo 0 > tracing_max_latency + # echo 1 > tracing_enabled # ls -ltr [...] - # echo 0 > /debug/tracing/tracing_enabled - # cat /debug/tracing/latency_trace + # echo 0 > tracing_enabled + # cat latency_trace # tracer: preemptoff # preemptoff latency trace v1.1.5 on 2.6.26-rc8 @@ -828,13 +849,13 @@ tracer. Again, using this trace is much like the irqsoff and preemptoff tracers. - # echo preemptirqsoff > /debug/tracing/current_tracer - # echo 0 > /debug/tracing/tracing_max_latency - # echo 1 > /debug/tracing/tracing_enabled + # echo preemptirqsoff > current_tracer + # echo 0 > tracing_max_latency + # echo 1 > tracing_enabled # ls -ltr [...] - # echo 0 > /debug/tracing/tracing_enabled - # cat /debug/tracing/latency_trace + # echo 0 > tracing_enabled + # cat latency_trace # tracer: preemptirqsoff # preemptirqsoff latency trace v1.1.5 on 2.6.26-rc8 @@ -990,12 +1011,12 @@ slightly differently than we did with the previous tracers. Instead of performing an 'ls', we will run 'sleep 1' under 'chrt' which changes the priority of the task. - # echo wakeup > /debug/tracing/current_tracer - # echo 0 > /debug/tracing/tracing_max_latency - # echo 1 > /debug/tracing/tracing_enabled + # echo wakeup > current_tracer + # echo 0 > tracing_max_latency + # echo 1 > tracing_enabled # chrt -f 5 sleep 1 - # echo 0 > /debug/tracing/tracing_enabled - # cat /debug/tracing/latency_trace + # echo 0 > tracing_enabled + # cat latency_trace # tracer: wakeup # wakeup latency trace v1.1.5 on 2.6.26-rc8 @@ -1105,11 +1126,11 @@ can be done from the debug file system. Make sure the ftrace_enabled is set; otherwise this tracer is a nop. # sysctl kernel.ftrace_enabled=1 - # echo function > /debug/tracing/current_tracer - # echo 1 > /debug/tracing/tracing_enabled + # echo function > current_tracer + # echo 1 > tracing_enabled # usleep 1 - # echo 0 > /debug/tracing/tracing_enabled - # cat /debug/tracing/trace + # echo 0 > tracing_enabled + # cat trace # tracer: function # # TASK-PID CPU# TIMESTAMP FUNCTION @@ -1146,7 +1167,7 @@ int trace_fd; [...] int main(int argc, char *argv[]) { [...] - trace_fd = open("/debug/tracing/tracing_enabled", O_WRONLY); + trace_fd = open(tracing_file("tracing_enabled"), O_WRONLY); [...] if (condition_hit()) { write(trace_fd, "0", 1); @@ -1154,26 +1175,20 @@ int main(int argc, char *argv[]) { [...] } -Note: Here we hard coded the path name. The debugfs mount is not -guaranteed to be at /debug (and is more commonly at -/sys/kernel/debug). For simple one time traces, the above is -sufficent. For anything else, a search through /proc/mounts may -be needed to find where the debugfs file-system is mounted. - Single thread tracing --------------------- -By writing into /debug/tracing/set_ftrace_pid you can trace a +By writing into set_ftrace_pid you can trace a single thread. For example: -# cat /debug/tracing/set_ftrace_pid +# cat set_ftrace_pid no pid -# echo 3111 > /debug/tracing/set_ftrace_pid -# cat /debug/tracing/set_ftrace_pid +# echo 3111 > set_ftrace_pid +# cat set_ftrace_pid 3111 -# echo function > /debug/tracing/current_tracer -# cat /debug/tracing/trace | head +# echo function > current_tracer +# cat trace | head # tracer: function # # TASK-PID CPU# TIMESTAMP FUNCTION @@ -1184,8 +1199,8 @@ no pid yum-updatesd-3111 [003] 1637.254683: lock_hrtimer_base <-hrtimer_try_to_cancel yum-updatesd-3111 [003] 1637.254685: fget_light <-do_sys_poll yum-updatesd-3111 [003] 1637.254686: pipe_poll <-do_sys_poll -# echo -1 > /debug/tracing/set_ftrace_pid -# cat /debug/tracing/trace |head +# echo -1 > set_ftrace_pid +# cat trace |head # tracer: function # # TASK-PID CPU# TIMESTAMP FUNCTION @@ -1207,6 +1222,51 @@ something like this simple program: #include #include +#define _STR(x) #x +#define STR(x) _STR(x) +#define MAX_PATH 256 + +const char *find_debugfs(void) +{ + static char debugfs[MAX_PATH+1]; + static int debugfs_found; + char type[100]; + FILE *fp; + + if (debugfs_found) + return debugfs; + + if ((fp = fopen("/proc/mounts","r")) == NULL) { + perror("/proc/mounts"); + return NULL; + } + + while (fscanf(fp, "%*s %" + STR(MAX_PATH) + "s %99s %*s %*d %*d\n", + debugfs, type) == 2) { + if (strcmp(type, "debugfs") == 0) + break; + } + fclose(fp); + + if (strcmp(type, "debugfs") != 0) { + fprintf(stderr, "debugfs not mounted"); + return NULL; + } + + debugfs_found = 1; + + return debugfs; +} + +const char *tracing_file(const char *file_name) +{ + static char trace_file[MAX_PATH+1]; + snprintf(trace_file, MAX_PATH, "%s/%s", find_debugfs(), file_name); + return trace_file; +} + int main (int argc, char **argv) { if (argc < 1) @@ -1217,12 +1277,12 @@ int main (int argc, char **argv) char line[64]; int s; - ffd = open("/debug/tracing/current_tracer", O_WRONLY); + ffd = open(tracing_file("current_tracer"), O_WRONLY); if (ffd < 0) exit(-1); write(ffd, "nop", 3); - fd = open("/debug/tracing/set_ftrace_pid", O_WRONLY); + fd = open(tracing_file("set_ftrace_pid"), O_WRONLY); s = sprintf(line, "%d\n", getpid()); write(fd, line, s); @@ -1374,22 +1434,22 @@ want, depending on your needs. tracing_cpu_mask file) or you might sometimes see unordered function calls while cpu tracing switch. - hide: echo nofuncgraph-cpu > /debug/tracing/trace_options - show: echo funcgraph-cpu > /debug/tracing/trace_options + hide: echo nofuncgraph-cpu > trace_options + show: echo funcgraph-cpu > trace_options - The duration (function's time of execution) is displayed on the closing bracket line of a function or on the same line than the current function in case of a leaf one. It is default enabled. - hide: echo nofuncgraph-duration > /debug/tracing/trace_options - show: echo funcgraph-duration > /debug/tracing/trace_options + hide: echo nofuncgraph-duration > trace_options + show: echo funcgraph-duration > trace_options - The overhead field precedes the duration field in case of reached duration thresholds. - hide: echo nofuncgraph-overhead > /debug/tracing/trace_options - show: echo funcgraph-overhead > /debug/tracing/trace_options + hide: echo nofuncgraph-overhead > trace_options + show: echo funcgraph-overhead > trace_options depends on: funcgraph-duration ie: @@ -1418,8 +1478,8 @@ want, depending on your needs. - The task/pid field displays the thread cmdline and pid which executed the function. It is default disabled. - hide: echo nofuncgraph-proc > /debug/tracing/trace_options - show: echo funcgraph-proc > /debug/tracing/trace_options + hide: echo nofuncgraph-proc > trace_options + show: echo funcgraph-proc > trace_options ie: @@ -1442,8 +1502,8 @@ want, depending on your needs. system clock since it started. A snapshot of this time is given on each entry/exit of functions - hide: echo nofuncgraph-abstime > /debug/tracing/trace_options - show: echo funcgraph-abstime > /debug/tracing/trace_options + hide: echo nofuncgraph-abstime > trace_options + show: echo funcgraph-abstime > trace_options ie: @@ -1540,7 +1600,7 @@ listed in: available_filter_functions - # cat /debug/tracing/available_filter_functions + # cat available_filter_functions put_prev_task_idle kmem_cache_create pick_next_task_rt @@ -1552,12 +1612,12 @@ mutex_lock If I am only interested in sys_nanosleep and hrtimer_interrupt: # echo sys_nanosleep hrtimer_interrupt \ - > /debug/tracing/set_ftrace_filter - # echo ftrace > /debug/tracing/current_tracer - # echo 1 > /debug/tracing/tracing_enabled + > set_ftrace_filter + # echo ftrace > current_tracer + # echo 1 > tracing_enabled # usleep 1 - # echo 0 > /debug/tracing/tracing_enabled - # cat /debug/tracing/trace + # echo 0 > tracing_enabled + # cat trace # tracer: ftrace # # TASK-PID CPU# TIMESTAMP FUNCTION @@ -1568,7 +1628,7 @@ If I am only interested in sys_nanosleep and hrtimer_interrupt: To see which functions are being traced, you can cat the file: - # cat /debug/tracing/set_ftrace_filter + # cat set_ftrace_filter hrtimer_interrupt sys_nanosleep @@ -1588,7 +1648,7 @@ Note: It is better to use quotes to enclose the wild cards, otherwise the shell may expand the parameters into names of files in the local directory. - # echo 'hrtimer_*' > /debug/tracing/set_ftrace_filter + # echo 'hrtimer_*' > set_ftrace_filter Produces: @@ -1609,7 +1669,7 @@ Produces: Notice that we lost the sys_nanosleep. - # cat /debug/tracing/set_ftrace_filter + # cat set_ftrace_filter hrtimer_run_queues hrtimer_run_pending hrtimer_init @@ -1635,17 +1695,17 @@ To append to the filters, use '>>' To clear out a filter so that all functions will be recorded again: - # echo > /debug/tracing/set_ftrace_filter - # cat /debug/tracing/set_ftrace_filter + # echo > set_ftrace_filter + # cat set_ftrace_filter # Again, now we want to append. - # echo sys_nanosleep > /debug/tracing/set_ftrace_filter - # cat /debug/tracing/set_ftrace_filter + # echo sys_nanosleep > set_ftrace_filter + # cat set_ftrace_filter sys_nanosleep - # echo 'hrtimer_*' >> /debug/tracing/set_ftrace_filter - # cat /debug/tracing/set_ftrace_filter + # echo 'hrtimer_*' >> set_ftrace_filter + # cat set_ftrace_filter hrtimer_run_queues hrtimer_run_pending hrtimer_init @@ -1668,7 +1728,7 @@ hrtimer_init_sleeper The set_ftrace_notrace prevents those functions from being traced. - # echo '*preempt*' '*lock*' > /debug/tracing/set_ftrace_notrace + # echo '*preempt*' '*lock*' > set_ftrace_notrace Produces: @@ -1758,13 +1818,13 @@ the effect on the tracing is different. Every read from trace_pipe is consumed. This means that subsequent reads will be different. The trace is live. - # echo function > /debug/tracing/current_tracer - # cat /debug/tracing/trace_pipe > /tmp/trace.out & + # echo function > current_tracer + # cat trace_pipe > /tmp/trace.out & [1] 4153 - # echo 1 > /debug/tracing/tracing_enabled + # echo 1 > tracing_enabled # usleep 1 - # echo 0 > /debug/tracing/tracing_enabled - # cat /debug/tracing/trace + # echo 0 > tracing_enabled + # cat trace # tracer: function # # TASK-PID CPU# TIMESTAMP FUNCTION @@ -1800,7 +1860,7 @@ number listed is the number of entries that can be recorded per CPU. To know the full size, multiply the number of possible CPUS with the number of entries. - # cat /debug/tracing/buffer_size_kb + # cat buffer_size_kb 1408 (units kilobytes) Note, to modify this, you must have tracing completely disabled. @@ -1808,21 +1868,21 @@ To do that, echo "nop" into the current_tracer. If the current_tracer is not set to "nop", an EINVAL error will be returned. - # echo nop > /debug/tracing/current_tracer - # echo 10000 > /debug/tracing/buffer_size_kb - # cat /debug/tracing/buffer_size_kb + # echo nop > current_tracer + # echo 10000 > buffer_size_kb + # cat buffer_size_kb 10000 (units kilobytes) The number of pages which will be allocated is limited to a percentage of available memory. Allocating too much will produce an error. - # echo 1000000000000 > /debug/tracing/buffer_size_kb + # echo 1000000000000 > buffer_size_kb -bash: echo: write error: Cannot allocate memory - # cat /debug/tracing/buffer_size_kb + # cat buffer_size_kb 85 ----------- More details can be found in the source code, in the -kernel/tracing/*.c files. +kernel/trace/*.c files. diff --git a/Documentation/trace/kmemtrace.txt b/Documentation/trace/kmemtrace.txt index a956d9b7f943..6308735e58ca 100644 --- a/Documentation/trace/kmemtrace.txt +++ b/Documentation/trace/kmemtrace.txt @@ -64,7 +64,7 @@ III. Quick usage guide CONFIG_KMEMTRACE). 2) Get the userspace tool and build it: -$ git-clone git://repo.or.cz/kmemtrace-user.git # current repository +$ git clone git://repo.or.cz/kmemtrace-user.git # current repository $ cd kmemtrace-user/ $ ./autogen.sh $ ./configure diff --git a/Documentation/trace/mmiotrace.txt b/Documentation/trace/mmiotrace.txt index 5731c67abc55..162effbfbdec 100644 --- a/Documentation/trace/mmiotrace.txt +++ b/Documentation/trace/mmiotrace.txt @@ -32,41 +32,41 @@ is no way to automatically detect if you are losing events due to CPUs racing. Usage Quick Reference --------------------- -$ mount -t debugfs debugfs /debug -$ echo mmiotrace > /debug/tracing/current_tracer -$ cat /debug/tracing/trace_pipe > mydump.txt & +$ mount -t debugfs debugfs /sys/kernel/debug +$ echo mmiotrace > /sys/kernel/debug/tracing/current_tracer +$ cat /sys/kernel/debug/tracing/trace_pipe > mydump.txt & Start X or whatever. -$ echo "X is up" > /debug/tracing/trace_marker -$ echo nop > /debug/tracing/current_tracer +$ echo "X is up" > /sys/kernel/debug/tracing/trace_marker +$ echo nop > /sys/kernel/debug/tracing/current_tracer Check for lost events. Usage ----- -Make sure debugfs is mounted to /debug. If not, (requires root privileges) -$ mount -t debugfs debugfs /debug +Make sure debugfs is mounted to /sys/kernel/debug. If not, (requires root privileges) +$ mount -t debugfs debugfs /sys/kernel/debug Check that the driver you are about to trace is not loaded. Activate mmiotrace (requires root privileges): -$ echo mmiotrace > /debug/tracing/current_tracer +$ echo mmiotrace > /sys/kernel/debug/tracing/current_tracer Start storing the trace: -$ cat /debug/tracing/trace_pipe > mydump.txt & +$ cat /sys/kernel/debug/tracing/trace_pipe > mydump.txt & The 'cat' process should stay running (sleeping) in the background. Load the driver you want to trace and use it. Mmiotrace will only catch MMIO accesses to areas that are ioremapped while mmiotrace is active. During tracing you can place comments (markers) into the trace by -$ echo "X is up" > /debug/tracing/trace_marker +$ echo "X is up" > /sys/kernel/debug/tracing/trace_marker This makes it easier to see which part of the (huge) trace corresponds to which action. It is recommended to place descriptive markers about what you do. Shut down mmiotrace (requires root privileges): -$ echo nop > /debug/tracing/current_tracer +$ echo nop > /sys/kernel/debug/tracing/current_tracer The 'cat' process exits. If it does not, kill it by issuing 'fg' command and pressing ctrl+c. @@ -78,10 +78,10 @@ to view your kernel log and look for "mmiotrace has lost events" warning. If events were lost, the trace is incomplete. You should enlarge the buffers and try again. Buffers are enlarged by first seeing how large the current buffers are: -$ cat /debug/tracing/buffer_size_kb +$ cat /sys/kernel/debug/tracing/buffer_size_kb gives you a number. Approximately double this number and write it back, for instance: -$ echo 128000 > /debug/tracing/buffer_size_kb +$ echo 128000 > /sys/kernel/debug/tracing/buffer_size_kb Then start again from the top. If you are doing a trace for a driver project, e.g. Nouveau, you should also diff --git a/Documentation/trace/power.txt b/Documentation/trace/power.txt new file mode 100644 index 000000000000..cd805e16dc27 --- /dev/null +++ b/Documentation/trace/power.txt @@ -0,0 +1,17 @@ +The power tracer collects detailed information about C-state and P-state +transitions, instead of just looking at the high-level "average" +information. + +There is a helper script found in scrips/tracing/power.pl in the kernel +sources which can be used to parse this information and create a +Scalable Vector Graphics (SVG) picture from the trace data. + +To use this tracer: + + echo 0 > /sys/kernel/debug/tracing/tracing_enabled + echo power > /sys/kernel/debug/tracing/current_tracer + echo 1 > /sys/kernel/debug/tracing/tracing_enabled + sleep 1 + echo 0 > /sys/kernel/debug/tracing/tracing_enabled + cat /sys/kernel/debug/tracing/trace | \ + perl scripts/tracing/power.pl > out.sv diff --git a/Documentation/usb/WUSB-Design-overview.txt b/Documentation/usb/WUSB-Design-overview.txt index 4c3d62c7843a..c480e9c32dbd 100644 --- a/Documentation/usb/WUSB-Design-overview.txt +++ b/Documentation/usb/WUSB-Design-overview.txt @@ -84,7 +84,7 @@ The different logical parts of this driver are: *UWB*: the Ultra-Wide-Band stack -- manages the radio and associated spectrum to allow for devices sharing it. Allows to - control bandwidth assingment, beaconing, scanning, etc + control bandwidth assignment, beaconing, scanning, etc * @@ -184,7 +184,7 @@ and sends the replies and notifications back to the API [/uwb_rc_neh_grok()/]. Notifications are handled to the UWB daemon, that is chartered, among other things, to keep the tab of how the UWB radio neighborhood looks, creating and destroying devices as they show up or -dissapear. +disappear. Command execution is very simple: a command block is sent and a event block or reply is expected back. For sending/receiving command/events, a @@ -333,7 +333,7 @@ read descriptors and move our data. *Device life cycle and keep alives* -Everytime there is a succesful transfer to/from a device, we update a +Every time there is a successful transfer to/from a device, we update a per-device activity timestamp. If not, every now and then we check and if the activity timestamp gets old, we ping the device by sending it a Keep Alive IE; it responds with a /DN_Alive/ pong during the DNTS (this @@ -411,7 +411,7 @@ context (wa_xfer) and submit it. When the xfer is done, our callback is called and we assign the status bits and release the xfer resources. In dequeue() we are basically cancelling/aborting the transfer. We issue -a xfer abort request to the HC, cancell all the URBs we had submitted +a xfer abort request to the HC, cancel all the URBs we had submitted and not yet done and when all that is done, the xfer callback will be called--this will call the URB callback. diff --git a/Documentation/usb/anchors.txt b/Documentation/usb/anchors.txt index 6f24f566955a..fe6a99a32bbd 100644 --- a/Documentation/usb/anchors.txt +++ b/Documentation/usb/anchors.txt @@ -27,7 +27,7 @@ Association and disassociation of URBs with anchors An association of URBs to an anchor is made by an explicit call to usb_anchor_urb(). The association is maintained until -an URB is finished by (successfull) completion. Thus disassociation +an URB is finished by (successful) completion. Thus disassociation is automatic. A function is provided to forcibly finish (kill) all URBs associated with an anchor. Furthermore, disassociation can be made with usb_unanchor_urb() @@ -76,4 +76,4 @@ usb_get_from_anchor() Returns the oldest anchored URB of an anchor. The URB is unanchored and returned with a reference. As you may mix URBs to several destinations in one anchor you have no guarantee the chronologically -first submitted URB is returned. \ No newline at end of file +first submitted URB is returned. diff --git a/Documentation/usb/callbacks.txt b/Documentation/usb/callbacks.txt index 7c812411945b..bfb36b34b79e 100644 --- a/Documentation/usb/callbacks.txt +++ b/Documentation/usb/callbacks.txt @@ -65,7 +65,7 @@ Accept or decline an interface. If you accept the device return 0, otherwise -ENODEV or -ENXIO. Other error codes should be used only if a genuine error occurred during initialisation which prevented a driver from accepting a device that would else have been accepted. -You are strongly encouraged to use usbcore'sfacility, +You are strongly encouraged to use usbcore's facility, usb_set_intfdata(), to associate a data structure with an interface, so that you know which internal state and identity you associate with a particular interface. The device will not be suspended and you may do IO diff --git a/Documentation/video4linux/CARDLIST.cx23885 b/Documentation/video4linux/CARDLIST.cx23885 index 91aa3c0f0dd2..450b8f8c389b 100644 --- a/Documentation/video4linux/CARDLIST.cx23885 +++ b/Documentation/video4linux/CARDLIST.cx23885 @@ -16,3 +16,8 @@ 15 -> TeVii S470 [d470:9022] 16 -> DVBWorld DVB-S2 2005 [0001:2005] 17 -> NetUP Dual DVB-S2 CI [1b55:2a2c] + 18 -> Hauppauge WinTV-HVR1270 [0070:2211] + 19 -> Hauppauge WinTV-HVR1275 [0070:2215] + 20 -> Hauppauge WinTV-HVR1255 [0070:2251] + 21 -> Hauppauge WinTV-HVR1210 [0070:2291,0070:2295] + 22 -> Mygica X8506 DMB-TH [14f1:8651] diff --git a/Documentation/video4linux/CARDLIST.cx88 b/Documentation/video4linux/CARDLIST.cx88 index 71e9db0b26f7..0736518b2f88 100644 --- a/Documentation/video4linux/CARDLIST.cx88 +++ b/Documentation/video4linux/CARDLIST.cx88 @@ -6,8 +6,8 @@ 5 -> Leadtek Winfast 2000XP Expert [107d:6611,107d:6613] 6 -> AverTV Studio 303 (M126) [1461:000b] 7 -> MSI TV-@nywhere Master [1462:8606] - 8 -> Leadtek Winfast DV2000 [107d:6620] - 9 -> Leadtek PVR 2000 [107d:663b,107d:663c,107d:6632] + 8 -> Leadtek Winfast DV2000 [107d:6620,107d:6621] + 9 -> Leadtek PVR 2000 [107d:663b,107d:663c,107d:6632,107d:6630,107d:6638,107d:6631,107d:6637,107d:663d] 10 -> IODATA GV-VCP3/PCI [10fc:d003] 11 -> Prolink PlayTV PVR 12 -> ASUS PVR-416 [1043:4823,1461:c111] @@ -59,7 +59,7 @@ 58 -> Pinnacle PCTV HD 800i [11bd:0051] 59 -> DViCO FusionHDTV 5 PCI nano [18ac:d530] 60 -> Pinnacle Hybrid PCTV [12ab:1788] - 61 -> Winfast TV2000 XP Global [107d:6f18] + 61 -> Leadtek TV2000 XP Global [107d:6f18,107d:6618] 62 -> PowerColor RA330 [14f1:ea3d] 63 -> Geniatech X8000-MT DVBT [14f1:8852] 64 -> DViCO FusionHDTV DVB-T PRO [18ac:db30] @@ -78,3 +78,5 @@ 77 -> TBS 8910 DVB-S [8910:8888] 78 -> Prof 6200 DVB-S [b022:3022] 79 -> Terratec Cinergy HT PCI MKII [153b:1177] + 80 -> Hauppauge WinTV-IR Only [0070:9290] + 81 -> Leadtek WinFast DTV1800 Hybrid [107d:6654] diff --git a/Documentation/video4linux/CARDLIST.em28xx b/Documentation/video4linux/CARDLIST.em28xx index 78d0a6eed571..873630e7e53e 100644 --- a/Documentation/video4linux/CARDLIST.em28xx +++ b/Documentation/video4linux/CARDLIST.em28xx @@ -17,7 +17,7 @@ 16 -> Hauppauge WinTV HVR 950 (em2883) [2040:6513,2040:6517,2040:651b] 17 -> Pinnacle PCTV HD Pro Stick (em2880) [2304:0227] 18 -> Hauppauge WinTV HVR 900 (R2) (em2880) [2040:6502] - 19 -> PointNix Intra-Oral Camera (em2860) + 19 -> EM2860/SAA711X Reference Design (em2860) 20 -> AMD ATI TV Wonder HD 600 (em2880) [0438:b002] 21 -> eMPIA Technology, Inc. GrabBeeX+ Video Encoder (em2800) [eb1a:2801] 22 -> Unknown EM2750/EM2751 webcam grabber (em2750) [eb1a:2750,eb1a:2751] @@ -61,3 +61,8 @@ 63 -> Kaiomy TVnPC U2 (em2860) [eb1a:e303] 64 -> Easy Cap Capture DC-60 (em2860) 65 -> IO-DATA GV-MVP/SZ (em2820/em2840) [04bb:0515] + 66 -> Empire dual TV (em2880) + 67 -> Terratec Grabby (em2860) [0ccd:0096] + 68 -> Terratec AV350 (em2860) [0ccd:0084] + 69 -> KWorld ATSC 315U HDTV TV Box (em2882) [eb1a:a313] + 70 -> Evga inDtube (em2882) diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134 index 6dacf2825259..15562427e8a9 100644 --- a/Documentation/video4linux/CARDLIST.saa7134 +++ b/Documentation/video4linux/CARDLIST.saa7134 @@ -124,10 +124,10 @@ 123 -> Beholder BeholdTV 407 [0000:4070] 124 -> Beholder BeholdTV 407 FM [0000:4071] 125 -> Beholder BeholdTV 409 [0000:4090] -126 -> Beholder BeholdTV 505 FM/RDS [0000:5051,0000:505B,5ace:5050] -127 -> Beholder BeholdTV 507 FM/RDS / BeholdTV 509 FM [0000:5071,0000:507B,5ace:5070,5ace:5090] +126 -> Beholder BeholdTV 505 FM [5ace:5050] +127 -> Beholder BeholdTV 507 FM / BeholdTV 509 FM [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] +129 -> Beholder BeholdTV 607 FM [5ace:6070] 130 -> Beholder BeholdTV M6 [5ace:6190] 131 -> Twinhan Hybrid DTV-DVB 3056 PCI [1822:0022] 132 -> Genius TVGO AM11MCE @@ -143,7 +143,7 @@ 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] +145 -> AVerMedia MiniPCI DVB-T Hybrid M103 [1461:f636,1461:f736] 146 -> ASUSTeK P7131 Analog 147 -> Asus Tiger 3in1 [1043:4878] 148 -> Encore ENLTV-FM v5.3 [1a7f:2008] @@ -154,4 +154,16 @@ 153 -> Kworld Plus TV Analog Lite PCI [17de:7128] 154 -> Avermedia AVerTV GO 007 FM Plus [1461:f31d] 155 -> Hauppauge WinTV-HVR1120 ATSC/QAM-Hybrid [0070:6706,0070:6708] -156 -> Hauppauge WinTV-HVR1110r3 [0070:6707,0070:6709,0070:670a] +156 -> Hauppauge WinTV-HVR1110r3 DVB-T/Hybrid [0070:6707,0070:6709,0070:670a] +157 -> Avermedia AVerTV Studio 507UA [1461:a11b] +158 -> AVerMedia Cardbus TV/Radio (E501R) [1461:b7e9] +159 -> Beholder BeholdTV 505 RDS [0000:505B] +160 -> Beholder BeholdTV 507 RDS [0000:5071] +161 -> Beholder BeholdTV 507 RDS [0000:507B] +162 -> Beholder BeholdTV 607 FM [5ace:6071] +163 -> Beholder BeholdTV 609 FM [5ace:6090] +164 -> Beholder BeholdTV 609 FM [5ace:6091] +165 -> Beholder BeholdTV 607 RDS [5ace:6072] +166 -> Beholder BeholdTV 607 RDS [5ace:6073] +167 -> Beholder BeholdTV 609 RDS [5ace:6092] +168 -> Beholder BeholdTV 609 RDS [5ace:6093] diff --git a/Documentation/video4linux/CARDLIST.tuner b/Documentation/video4linux/CARDLIST.tuner index 691d2f37dc57..be67844074dd 100644 --- a/Documentation/video4linux/CARDLIST.tuner +++ b/Documentation/video4linux/CARDLIST.tuner @@ -76,3 +76,5 @@ tuner=75 - Philips TEA5761 FM Radio tuner=76 - Xceive 5000 tuner tuner=77 - TCL tuner MF02GIP-5N-E tuner=78 - Philips FMD1216MEX MK3 Hybrid Tuner +tuner=79 - Philips PAL/SECAM multi (FM1216 MK5) +tuner=80 - Philips FQ1216LME MK3 PAL/SECAM w/active loopthrough diff --git a/Documentation/video4linux/cx18.txt b/Documentation/video4linux/cx18.txt index 914cb7e734a2..4652c0f5da32 100644 --- a/Documentation/video4linux/cx18.txt +++ b/Documentation/video4linux/cx18.txt @@ -11,7 +11,7 @@ encoder chip: 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. + then post to the video4linux or ivtv-users mailing list. 3) VBI (raw or sliced) has not yet been implemented. diff --git a/Documentation/video4linux/gspca.txt b/Documentation/video4linux/gspca.txt index 98529e03a46e..2bcf78896e22 100644 --- a/Documentation/video4linux/gspca.txt +++ b/Documentation/video4linux/gspca.txt @@ -163,10 +163,11 @@ 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:0519 OV519 Microphone ov519 05a9:0530 OmniVision -ov519 05a9:4519 OmniVision +ov519 05a9:4519 Webcam Classic ov519 05a9:8519 OmniVision +ov519 05a9:a518 D-Link DSB-C310 Webcam sunplus 05da:1018 Digital Dream Enigma 1.3 stk014 05e1:0893 Syntek DV4000 spca561 060b:a001 Maxell Compact Pc PM3 @@ -178,6 +179,7 @@ spca506 06e1:a190 ADS Instant VCD ov534 06f8:3002 Hercules Blog Webcam ov534 06f8:3003 Hercules Dualpix HD Weblog sonixj 06f8:3004 Hercules Classic Silver +sonixj 06f8:3008 Hercules Deluxe Optical Glass spca508 0733:0110 ViewQuest VQ110 spca508 0130:0130 Clone Digital Webcam 11043 spca501 0733:0401 Intel Create and Share @@ -209,6 +211,7 @@ sunplus 08ca:2050 Medion MD 41437 sunplus 08ca:2060 Aiptek PocketDV5300 tv8532 0923:010f ICM532 cams mars 093a:050f Mars-Semi Pc-Camera +mr97310a 093a:010f Sakar Digital no. 77379 pac207 093a:2460 Qtec Webcam 100 pac207 093a:2461 HP Webcam pac207 093a:2463 Philips SPC 220 NC @@ -265,6 +268,11 @@ sonixj 0c45:60ec SN9C105+MO4000 sonixj 0c45:60fb Surfer NoName sonixj 0c45:60fc LG-LIC300 sonixj 0c45:60fe Microdia Audio +sonixj 0c45:6100 PC Camera (SN9C128) +sonixj 0c45:610a PC Camera (SN9C128) +sonixj 0c45:610b PC Camera (SN9C128) +sonixj 0c45:610c PC Camera (SN9C128) +sonixj 0c45:610e PC Camera (SN9C128) sonixj 0c45:6128 Microdia/Sonix SNP325 sonixj 0c45:612a Avant Camera sonixj 0c45:612c Typhoon Rasy Cam 1.3MPix diff --git a/Documentation/video4linux/pxa_camera.txt b/Documentation/video4linux/pxa_camera.txt index b1137f9a53eb..4f6d0ca01956 100644 --- a/Documentation/video4linux/pxa_camera.txt +++ b/Documentation/video4linux/pxa_camera.txt @@ -26,6 +26,55 @@ Global video workflow Once the last buffer is filled in, the QCI interface stops. + c) Capture global finite state machine schema + + +----+ +---+ +----+ + | DQ | | Q | | DQ | + | v | v | v + +-----------+ +------------------------+ + | STOP | | Wait for capture start | + +-----------+ Q +------------------------+ ++-> | QCI: stop | ------------------> | QCI: run | <------------+ +| | DMA: stop | | DMA: stop | | +| +-----------+ +-----> +------------------------+ | +| / | | +| / +---+ +----+ | | +|capture list empty / | Q | | DQ | | QCI Irq EOF | +| / | v | v v | +| +--------------------+ +----------------------+ | +| | DMA hotlink missed | | Capture running | | +| +--------------------+ +----------------------+ | +| | QCI: run | +-----> | QCI: run | <-+ | +| | DMA: stop | / | DMA: run | | | +| +--------------------+ / +----------------------+ | Other | +| ^ /DMA still | | channels | +| | capture list / running | DMA Irq End | not | +| | not empty / | | finished | +| | / v | yet | +| +----------------------+ +----------------------+ | | +| | Videobuf released | | Channel completed | | | +| +----------------------+ +----------------------+ | | ++-- | QCI: run | | QCI: run | --+ | + | DMA: run | | DMA: run | | + +----------------------+ +----------------------+ | + ^ / | | + | no overrun / | overrun | + | / v | + +--------------------+ / +----------------------+ | + | Frame completed | / | Frame overran | | + +--------------------+ <-----+ +----------------------+ restart frame | + | QCI: run | | QCI: stop | --------------+ + | DMA: run | | DMA: stop | + +--------------------+ +----------------------+ + + Legend: - each box is a FSM state + - each arrow is the condition to transition to another state + - an arrow with a comment is a mandatory transition (no condition) + - arrow "Q" means : a buffer was enqueued + - arrow "DQ" means : a buffer was dequeued + - "QCI: stop" means the QCI interface is not enabled + - "DMA: stop" means all 3 DMA channels are stopped + - "DMA: run" means at least 1 DMA channel is still running DMA usage --------- diff --git a/Documentation/video4linux/v4l2-framework.txt b/Documentation/video4linux/v4l2-framework.txt index 854808b67fae..ba4706afc5fb 100644 --- a/Documentation/video4linux/v4l2-framework.txt +++ b/Documentation/video4linux/v4l2-framework.txt @@ -89,6 +89,11 @@ from dev (driver name followed by the bus_id, to be precise). If you set it up before calling v4l2_device_register then it will be untouched. If dev is NULL, then you *must* setup v4l2_dev->name before calling v4l2_device_register. +You can use v4l2_device_set_name() to set the name based on a driver name and +a driver-global atomic_t instance. This will generate names like ivtv0, ivtv1, +etc. If the name ends with a digit, then it will insert a dash: cx18-0, +cx18-1, etc. This function returns the instance number. + The first 'dev' argument is normally the struct device pointer of a pci_dev, usb_interface or platform_device. It is rare for dev to be NULL, but it happens with ISA devices or when one device creates multiple PCI devices, thus making @@ -385,6 +390,30 @@ later date. It differs between i2c drivers and as such can be confusing. To see which chip variants are supported you can look in the i2c driver code for the i2c_device_id table. This lists all the possibilities. +There are two more helper functions: + +v4l2_i2c_new_subdev_cfg: this function adds new irq and platform_data +arguments and has both 'addr' and 'probed_addrs' arguments: if addr is not +0 then that will be used (non-probing variant), otherwise the probed_addrs +are probed. + +For example: this will probe for address 0x10: + +struct v4l2_subdev *sd = v4l2_i2c_new_subdev_cfg(v4l2_dev, adapter, + "module_foo", "chipid", 0, NULL, 0, I2C_ADDRS(0x10)); + +v4l2_i2c_new_subdev_board uses an i2c_board_info struct which is passed +to the i2c driver and replaces the irq, platform_data and addr arguments. + +If the subdev supports the s_config core ops, then that op is called with +the irq and platform_data arguments after the subdev was setup. The older +v4l2_i2c_new_(probed_)subdev functions will call s_config as well, but with +irq set to 0 and platform_data set to NULL. + +Note that in the next kernel release the functions v4l2_i2c_new_subdev, +v4l2_i2c_new_probed_subdev and v4l2_i2c_new_probed_subdev_addr will all be +replaced by a single v4l2_i2c_new_subdev that is identical to +v4l2_i2c_new_subdev_cfg but without the irq and platform_data arguments. struct video_device ------------------- diff --git a/Documentation/vm/Makefile b/Documentation/vm/Makefile index 6f562f778b28..5bd269b3731a 100644 --- a/Documentation/vm/Makefile +++ b/Documentation/vm/Makefile @@ -2,7 +2,7 @@ obj- := dummy.o # List of programs to build -hostprogs-y := slabinfo +hostprogs-y := slabinfo page-types # Tell kbuild to always build the programs always := $(hostprogs-y) diff --git a/Documentation/vm/balance b/Documentation/vm/balance index bd3d31bc4915..c46e68cf9344 100644 --- a/Documentation/vm/balance +++ b/Documentation/vm/balance @@ -75,15 +75,15 @@ Page stealing from process memory and shm is done if stealing the page would alleviate memory pressure on any zone in the page's node that has fallen below its watermark. -pages_min/pages_low/pages_high/low_on_memory/zone_wake_kswapd: These are -per-zone fields, used to determine when a zone needs to be balanced. When -the number of pages falls below pages_min, the hysteric field low_on_memory -gets set. This stays set till the number of free pages becomes pages_high. -When low_on_memory is set, page allocation requests will try to free some -pages in the zone (providing GFP_WAIT is set in the request). Orthogonal -to this, is the decision to poke kswapd to free some zone pages. That -decision is not hysteresis based, and is done when the number of free -pages is below pages_low; in which case zone_wake_kswapd is also set. +watemark[WMARK_MIN/WMARK_LOW/WMARK_HIGH]/low_on_memory/zone_wake_kswapd: These +are per-zone fields, used to determine when a zone needs to be balanced. When +the number of pages falls below watermark[WMARK_MIN], the hysteric field +low_on_memory gets set. This stays set till the number of free pages becomes +watermark[WMARK_HIGH]. When low_on_memory is set, page allocation requests will +try to free some pages in the zone (providing GFP_WAIT is set in the request). +Orthogonal to this, is the decision to poke kswapd to free some zone pages. +That decision is not hysteresis based, and is done when the number of free +pages is below watermark[WMARK_LOW]; in which case zone_wake_kswapd is also set. (Good) Ideas that I have heard: diff --git a/Documentation/vm/page-types.c b/Documentation/vm/page-types.c new file mode 100644 index 000000000000..0833f44ba16b --- /dev/null +++ b/Documentation/vm/page-types.c @@ -0,0 +1,698 @@ +/* + * page-types: Tool for querying page flags + * + * Copyright (C) 2009 Intel corporation + * Copyright (C) 2009 Wu Fengguang + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* + * kernel page flags + */ + +#define KPF_BYTES 8 +#define PROC_KPAGEFLAGS "/proc/kpageflags" + +/* copied from kpageflags_read() */ +#define KPF_LOCKED 0 +#define KPF_ERROR 1 +#define KPF_REFERENCED 2 +#define KPF_UPTODATE 3 +#define KPF_DIRTY 4 +#define KPF_LRU 5 +#define KPF_ACTIVE 6 +#define KPF_SLAB 7 +#define KPF_WRITEBACK 8 +#define KPF_RECLAIM 9 +#define KPF_BUDDY 10 + +/* [11-20] new additions in 2.6.31 */ +#define KPF_MMAP 11 +#define KPF_ANON 12 +#define KPF_SWAPCACHE 13 +#define KPF_SWAPBACKED 14 +#define KPF_COMPOUND_HEAD 15 +#define KPF_COMPOUND_TAIL 16 +#define KPF_HUGE 17 +#define KPF_UNEVICTABLE 18 +#define KPF_NOPAGE 20 + +/* [32-] kernel hacking assistances */ +#define KPF_RESERVED 32 +#define KPF_MLOCKED 33 +#define KPF_MAPPEDTODISK 34 +#define KPF_PRIVATE 35 +#define KPF_PRIVATE_2 36 +#define KPF_OWNER_PRIVATE 37 +#define KPF_ARCH 38 +#define KPF_UNCACHED 39 + +/* [48-] take some arbitrary free slots for expanding overloaded flags + * not part of kernel API + */ +#define KPF_READAHEAD 48 +#define KPF_SLOB_FREE 49 +#define KPF_SLUB_FROZEN 50 +#define KPF_SLUB_DEBUG 51 + +#define KPF_ALL_BITS ((uint64_t)~0ULL) +#define KPF_HACKERS_BITS (0xffffULL << 32) +#define KPF_OVERLOADED_BITS (0xffffULL << 48) +#define BIT(name) (1ULL << KPF_##name) +#define BITS_COMPOUND (BIT(COMPOUND_HEAD) | BIT(COMPOUND_TAIL)) + +static char *page_flag_names[] = { + [KPF_LOCKED] = "L:locked", + [KPF_ERROR] = "E:error", + [KPF_REFERENCED] = "R:referenced", + [KPF_UPTODATE] = "U:uptodate", + [KPF_DIRTY] = "D:dirty", + [KPF_LRU] = "l:lru", + [KPF_ACTIVE] = "A:active", + [KPF_SLAB] = "S:slab", + [KPF_WRITEBACK] = "W:writeback", + [KPF_RECLAIM] = "I:reclaim", + [KPF_BUDDY] = "B:buddy", + + [KPF_MMAP] = "M:mmap", + [KPF_ANON] = "a:anonymous", + [KPF_SWAPCACHE] = "s:swapcache", + [KPF_SWAPBACKED] = "b:swapbacked", + [KPF_COMPOUND_HEAD] = "H:compound_head", + [KPF_COMPOUND_TAIL] = "T:compound_tail", + [KPF_HUGE] = "G:huge", + [KPF_UNEVICTABLE] = "u:unevictable", + [KPF_NOPAGE] = "n:nopage", + + [KPF_RESERVED] = "r:reserved", + [KPF_MLOCKED] = "m:mlocked", + [KPF_MAPPEDTODISK] = "d:mappedtodisk", + [KPF_PRIVATE] = "P:private", + [KPF_PRIVATE_2] = "p:private_2", + [KPF_OWNER_PRIVATE] = "O:owner_private", + [KPF_ARCH] = "h:arch", + [KPF_UNCACHED] = "c:uncached", + + [KPF_READAHEAD] = "I:readahead", + [KPF_SLOB_FREE] = "P:slob_free", + [KPF_SLUB_FROZEN] = "A:slub_frozen", + [KPF_SLUB_DEBUG] = "E:slub_debug", +}; + + +/* + * data structures + */ + +static int opt_raw; /* for kernel developers */ +static int opt_list; /* list pages (in ranges) */ +static int opt_no_summary; /* don't show summary */ +static pid_t opt_pid; /* process to walk */ + +#define MAX_ADDR_RANGES 1024 +static int nr_addr_ranges; +static unsigned long opt_offset[MAX_ADDR_RANGES]; +static unsigned long opt_size[MAX_ADDR_RANGES]; + +#define MAX_BIT_FILTERS 64 +static int nr_bit_filters; +static uint64_t opt_mask[MAX_BIT_FILTERS]; +static uint64_t opt_bits[MAX_BIT_FILTERS]; + +static int page_size; + +#define PAGES_BATCH (64 << 10) /* 64k pages */ +static int kpageflags_fd; +static uint64_t kpageflags_buf[KPF_BYTES * PAGES_BATCH]; + +#define HASH_SHIFT 13 +#define HASH_SIZE (1 << HASH_SHIFT) +#define HASH_MASK (HASH_SIZE - 1) +#define HASH_KEY(flags) (flags & HASH_MASK) + +static unsigned long total_pages; +static unsigned long nr_pages[HASH_SIZE]; +static uint64_t page_flags[HASH_SIZE]; + + +/* + * helper functions + */ + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +#define min_t(type, x, y) ({ \ + type __min1 = (x); \ + type __min2 = (y); \ + __min1 < __min2 ? __min1 : __min2; }) + +unsigned long pages2mb(unsigned long pages) +{ + return (pages * page_size) >> 20; +} + +void fatal(const char *x, ...) +{ + va_list ap; + + va_start(ap, x); + vfprintf(stderr, x, ap); + va_end(ap); + exit(EXIT_FAILURE); +} + + +/* + * page flag names + */ + +char *page_flag_name(uint64_t flags) +{ + static char buf[65]; + int present; + int i, j; + + for (i = 0, j = 0; i < ARRAY_SIZE(page_flag_names); i++) { + present = (flags >> i) & 1; + if (!page_flag_names[i]) { + if (present) + fatal("unkown flag bit %d\n", i); + continue; + } + buf[j++] = present ? page_flag_names[i][0] : '_'; + } + + return buf; +} + +char *page_flag_longname(uint64_t flags) +{ + static char buf[1024]; + int i, n; + + for (i = 0, n = 0; i < ARRAY_SIZE(page_flag_names); i++) { + if (!page_flag_names[i]) + continue; + if ((flags >> i) & 1) + n += snprintf(buf + n, sizeof(buf) - n, "%s,", + page_flag_names[i] + 2); + } + if (n) + n--; + buf[n] = '\0'; + + return buf; +} + + +/* + * page list and summary + */ + +void show_page_range(unsigned long offset, uint64_t flags) +{ + static uint64_t flags0; + static unsigned long index; + static unsigned long count; + + if (flags == flags0 && offset == index + count) { + count++; + return; + } + + if (count) + printf("%lu\t%lu\t%s\n", + index, count, page_flag_name(flags0)); + + flags0 = flags; + index = offset; + count = 1; +} + +void show_page(unsigned long offset, uint64_t flags) +{ + printf("%lu\t%s\n", offset, page_flag_name(flags)); +} + +void show_summary(void) +{ + int i; + + printf(" flags\tpage-count MB" + " symbolic-flags\t\t\tlong-symbolic-flags\n"); + + for (i = 0; i < ARRAY_SIZE(nr_pages); i++) { + if (nr_pages[i]) + printf("0x%016llx\t%10lu %8lu %s\t%s\n", + (unsigned long long)page_flags[i], + nr_pages[i], + pages2mb(nr_pages[i]), + page_flag_name(page_flags[i]), + page_flag_longname(page_flags[i])); + } + + printf(" total\t%10lu %8lu\n", + total_pages, pages2mb(total_pages)); +} + + +/* + * page flag filters + */ + +int bit_mask_ok(uint64_t flags) +{ + int i; + + for (i = 0; i < nr_bit_filters; i++) { + if (opt_bits[i] == KPF_ALL_BITS) { + if ((flags & opt_mask[i]) == 0) + return 0; + } else { + if ((flags & opt_mask[i]) != opt_bits[i]) + return 0; + } + } + + return 1; +} + +uint64_t expand_overloaded_flags(uint64_t flags) +{ + /* SLOB/SLUB overload several page flags */ + if (flags & BIT(SLAB)) { + if (flags & BIT(PRIVATE)) + flags ^= BIT(PRIVATE) | BIT(SLOB_FREE); + if (flags & BIT(ACTIVE)) + flags ^= BIT(ACTIVE) | BIT(SLUB_FROZEN); + if (flags & BIT(ERROR)) + flags ^= BIT(ERROR) | BIT(SLUB_DEBUG); + } + + /* PG_reclaim is overloaded as PG_readahead in the read path */ + if ((flags & (BIT(RECLAIM) | BIT(WRITEBACK))) == BIT(RECLAIM)) + flags ^= BIT(RECLAIM) | BIT(READAHEAD); + + return flags; +} + +uint64_t well_known_flags(uint64_t flags) +{ + /* hide flags intended only for kernel hacker */ + flags &= ~KPF_HACKERS_BITS; + + /* hide non-hugeTLB compound pages */ + if ((flags & BITS_COMPOUND) && !(flags & BIT(HUGE))) + flags &= ~BITS_COMPOUND; + + return flags; +} + + +/* + * page frame walker + */ + +int hash_slot(uint64_t flags) +{ + int k = HASH_KEY(flags); + int i; + + /* Explicitly reserve slot 0 for flags 0: the following logic + * cannot distinguish an unoccupied slot from slot (flags==0). + */ + if (flags == 0) + return 0; + + /* search through the remaining (HASH_SIZE-1) slots */ + for (i = 1; i < ARRAY_SIZE(page_flags); i++, k++) { + if (!k || k >= ARRAY_SIZE(page_flags)) + k = 1; + if (page_flags[k] == 0) { + page_flags[k] = flags; + return k; + } + if (page_flags[k] == flags) + return k; + } + + fatal("hash table full: bump up HASH_SHIFT?\n"); + exit(EXIT_FAILURE); +} + +void add_page(unsigned long offset, uint64_t flags) +{ + flags = expand_overloaded_flags(flags); + + if (!opt_raw) + flags = well_known_flags(flags); + + if (!bit_mask_ok(flags)) + return; + + if (opt_list == 1) + show_page_range(offset, flags); + else if (opt_list == 2) + show_page(offset, flags); + + nr_pages[hash_slot(flags)]++; + total_pages++; +} + +void walk_pfn(unsigned long index, unsigned long count) +{ + unsigned long batch; + unsigned long n; + unsigned long i; + + if (index > ULONG_MAX / KPF_BYTES) + fatal("index overflow: %lu\n", index); + + lseek(kpageflags_fd, index * KPF_BYTES, SEEK_SET); + + while (count) { + batch = min_t(unsigned long, count, PAGES_BATCH); + n = read(kpageflags_fd, kpageflags_buf, batch * KPF_BYTES); + if (n == 0) + break; + if (n < 0) { + perror(PROC_KPAGEFLAGS); + exit(EXIT_FAILURE); + } + + if (n % KPF_BYTES != 0) + fatal("partial read: %lu bytes\n", n); + n = n / KPF_BYTES; + + for (i = 0; i < n; i++) + add_page(index + i, kpageflags_buf[i]); + + index += batch; + count -= batch; + } +} + +void walk_addr_ranges(void) +{ + int i; + + kpageflags_fd = open(PROC_KPAGEFLAGS, O_RDONLY); + if (kpageflags_fd < 0) { + perror(PROC_KPAGEFLAGS); + exit(EXIT_FAILURE); + } + + if (!nr_addr_ranges) + walk_pfn(0, ULONG_MAX); + + for (i = 0; i < nr_addr_ranges; i++) + walk_pfn(opt_offset[i], opt_size[i]); + + close(kpageflags_fd); +} + + +/* + * user interface + */ + +const char *page_flag_type(uint64_t flag) +{ + if (flag & KPF_HACKERS_BITS) + return "(r)"; + if (flag & KPF_OVERLOADED_BITS) + return "(o)"; + return " "; +} + +void usage(void) +{ + int i, j; + + printf( +"page-types [options]\n" +" -r|--raw Raw mode, for kernel developers\n" +" -a|--addr addr-spec Walk a range of pages\n" +" -b|--bits bits-spec Walk pages with specified bits\n" +#if 0 /* planned features */ +" -p|--pid pid Walk process address space\n" +" -f|--file filename Walk file address space\n" +#endif +" -l|--list Show page details in ranges\n" +" -L|--list-each Show page details one by one\n" +" -N|--no-summary Don't show summay info\n" +" -h|--help Show this usage message\n" +"addr-spec:\n" +" N one page at offset N (unit: pages)\n" +" N+M pages range from N to N+M-1\n" +" N,M pages range from N to M-1\n" +" N, pages range from N to end\n" +" ,M pages range from 0 to M\n" +"bits-spec:\n" +" bit1,bit2 (flags & (bit1|bit2)) != 0\n" +" bit1,bit2=bit1 (flags & (bit1|bit2)) == bit1\n" +" bit1,~bit2 (flags & (bit1|bit2)) == bit1\n" +" =bit1,bit2 flags == (bit1|bit2)\n" +"bit-names:\n" + ); + + for (i = 0, j = 0; i < ARRAY_SIZE(page_flag_names); i++) { + if (!page_flag_names[i]) + continue; + printf("%16s%s", page_flag_names[i] + 2, + page_flag_type(1ULL << i)); + if (++j > 3) { + j = 0; + putchar('\n'); + } + } + printf("\n " + "(r) raw mode bits (o) overloaded bits\n"); +} + +unsigned long long parse_number(const char *str) +{ + unsigned long long n; + + n = strtoll(str, NULL, 0); + + if (n == 0 && str[0] != '0') + fatal("invalid name or number: %s\n", str); + + return n; +} + +void parse_pid(const char *str) +{ + opt_pid = parse_number(str); +} + +void parse_file(const char *name) +{ +} + +void add_addr_range(unsigned long offset, unsigned long size) +{ + if (nr_addr_ranges >= MAX_ADDR_RANGES) + fatal("too much addr ranges\n"); + + opt_offset[nr_addr_ranges] = offset; + opt_size[nr_addr_ranges] = size; + nr_addr_ranges++; +} + +void parse_addr_range(const char *optarg) +{ + unsigned long offset; + unsigned long size; + char *p; + + p = strchr(optarg, ','); + if (!p) + p = strchr(optarg, '+'); + + if (p == optarg) { + offset = 0; + size = parse_number(p + 1); + } else if (p) { + offset = parse_number(optarg); + if (p[1] == '\0') + size = ULONG_MAX; + else { + size = parse_number(p + 1); + if (*p == ',') { + if (size < offset) + fatal("invalid range: %lu,%lu\n", + offset, size); + size -= offset; + } + } + } else { + offset = parse_number(optarg); + size = 1; + } + + add_addr_range(offset, size); +} + +void add_bits_filter(uint64_t mask, uint64_t bits) +{ + if (nr_bit_filters >= MAX_BIT_FILTERS) + fatal("too much bit filters\n"); + + opt_mask[nr_bit_filters] = mask; + opt_bits[nr_bit_filters] = bits; + nr_bit_filters++; +} + +uint64_t parse_flag_name(const char *str, int len) +{ + int i; + + if (!*str || !len) + return 0; + + if (len <= 8 && !strncmp(str, "compound", len)) + return BITS_COMPOUND; + + for (i = 0; i < ARRAY_SIZE(page_flag_names); i++) { + if (!page_flag_names[i]) + continue; + if (!strncmp(str, page_flag_names[i] + 2, len)) + return 1ULL << i; + } + + return parse_number(str); +} + +uint64_t parse_flag_names(const char *str, int all) +{ + const char *p = str; + uint64_t flags = 0; + + while (1) { + if (*p == ',' || *p == '=' || *p == '\0') { + if ((*str != '~') || (*str == '~' && all && *++str)) + flags |= parse_flag_name(str, p - str); + if (*p != ',') + break; + str = p + 1; + } + p++; + } + + return flags; +} + +void parse_bits_mask(const char *optarg) +{ + uint64_t mask; + uint64_t bits; + const char *p; + + p = strchr(optarg, '='); + if (p == optarg) { + mask = KPF_ALL_BITS; + bits = parse_flag_names(p + 1, 0); + } else if (p) { + mask = parse_flag_names(optarg, 0); + bits = parse_flag_names(p + 1, 0); + } else if (strchr(optarg, '~')) { + mask = parse_flag_names(optarg, 1); + bits = parse_flag_names(optarg, 0); + } else { + mask = parse_flag_names(optarg, 0); + bits = KPF_ALL_BITS; + } + + add_bits_filter(mask, bits); +} + + +struct option opts[] = { + { "raw" , 0, NULL, 'r' }, + { "pid" , 1, NULL, 'p' }, + { "file" , 1, NULL, 'f' }, + { "addr" , 1, NULL, 'a' }, + { "bits" , 1, NULL, 'b' }, + { "list" , 0, NULL, 'l' }, + { "list-each" , 0, NULL, 'L' }, + { "no-summary", 0, NULL, 'N' }, + { "help" , 0, NULL, 'h' }, + { NULL , 0, NULL, 0 } +}; + +int main(int argc, char *argv[]) +{ + int c; + + page_size = getpagesize(); + + while ((c = getopt_long(argc, argv, + "rp:f:a:b:lLNh", opts, NULL)) != -1) { + switch (c) { + case 'r': + opt_raw = 1; + break; + case 'p': + parse_pid(optarg); + break; + case 'f': + parse_file(optarg); + break; + case 'a': + parse_addr_range(optarg); + break; + case 'b': + parse_bits_mask(optarg); + break; + case 'l': + opt_list = 1; + break; + case 'L': + opt_list = 2; + break; + case 'N': + opt_no_summary = 1; + break; + case 'h': + usage(); + exit(0); + default: + usage(); + exit(1); + } + } + + if (opt_list == 1) + printf("offset\tcount\tflags\n"); + if (opt_list == 2) + printf("offset\tflags\n"); + + walk_addr_ranges(); + + if (opt_list == 1) + show_page_range(0, 0); /* drain the buffer */ + + if (opt_no_summary) + return 0; + + if (opt_list) + printf("\n\n"); + + show_summary(); + + return 0; +} diff --git a/Documentation/vm/pagemap.txt b/Documentation/vm/pagemap.txt index ce72c0fe6177..600a304a828c 100644 --- a/Documentation/vm/pagemap.txt +++ b/Documentation/vm/pagemap.txt @@ -12,9 +12,9 @@ There are three components to pagemap: value for each virtual page, containing the following data (from fs/proc/task_mmu.c, above pagemap_read): - * Bits 0-55 page frame number (PFN) if present + * Bits 0-54 page frame number (PFN) if present * Bits 0-4 swap type if swapped - * Bits 5-55 swap offset if swapped + * Bits 5-54 swap offset if swapped * Bits 55-60 page shift (page size = 1<= on-disk one) + 4. DIRTY page has been written to, hence contains new data + ie. for file backed page: (in-memory data revision > on-disk one) + 8. WRITEBACK page is being synced to disk + + [LRU related page flags] + 5. LRU page is in one of the LRU lists + 6. ACTIVE page is in the active LRU list +18. UNEVICTABLE page is in the unevictable (non-)LRU list + It is somehow pinned and not a candidate for LRU page reclaims, + eg. ramfs pages, shmctl(SHM_LOCK) and mlock() memory segments + 2. REFERENCED page has been referenced since last LRU list enqueue/requeue + 9. RECLAIM page will be reclaimed soon after its pageout IO completed +11. MMAP a memory mapped page +12. ANON a memory mapped page that is not part of a file +13. SWAPCACHE page is mapped to swap space, ie. has an associated swap entry +14. SWAPBACKED page is backed by swap/RAM + +The page-types tool in this directory can be used to query the above flags. Using pagemap to do something useful: diff --git a/Documentation/watchdog/hpwdt.txt b/Documentation/watchdog/hpwdt.txt new file mode 100644 index 000000000000..9c24d5ffbb06 --- /dev/null +++ b/Documentation/watchdog/hpwdt.txt @@ -0,0 +1,95 @@ +Last reviewed: 06/02/2009 + + HP iLO2 NMI Watchdog Driver + NMI sourcing for iLO2 based ProLiant Servers + Documentation and Driver by + Thomas Mingarelli + + The HP iLO2 NMI Watchdog driver is a kernel module that provides basic + watchdog functionality and the added benefit of NMI sourcing. Both the + watchdog functionality and the NMI sourcing capability need to be enabled + by the user. Remember that the two modes are not dependant on one another. + A user can have the NMI sourcing without the watchdog timer and vice-versa. + + Watchdog functionality is enabled like any other common watchdog driver. That + is, an application needs to be started that kicks off the watchdog timer. A + basic application exists in the Documentation/watchdog/src directory called + watchdog-test.c. Simply compile the C file and kick it off. If the system + gets into a bad state and hangs, the HP ProLiant iLO 2 timer register will + not be updated in a timely fashion and a hardware system reset (also known as + an Automatic Server Recovery (ASR)) event will occur. + + The hpwdt driver also has four (4) module parameters. They are the following: + + soft_margin - allows the user to set the watchdog timer value + allow_kdump - allows the user to save off a kernel dump image after an NMI + nowayout - basic watchdog parameter that does not allow the timer to + be restarted or an impending ASR to be escaped. + priority - determines whether or not the hpwdt driver is first on the + die_notify list to handle NMIs or last. The default value + for this module parameter is 0 or LAST. If the user wants to + enable NMI sourcing then reload the hpwdt driver with + priority=1 (and boot with nmi_watchdog=0). + + NOTE: More information about watchdog drivers in general, including the ioctl + interface to /dev/watchdog can be found in + Documentation/watchdog/watchdog-api.txt and Documentation/IPMI.txt. + + The priority parameter was introduced due to other kernel software that relied + on handling NMIs (like oprofile). Keeping hpwdt's priority at 0 (or LAST) + enables the users of NMIs for non critical events to be work as expected. + + The NMI sourcing capability is disabled by default due to the inability to + distinguish between "NMI Watchdog Ticks" and "HW generated NMI events" in the + Linux kernel. What this means is that the hpwdt nmi handler code is called + each time the NMI signal fires off. This could amount to several thousands of + NMIs in a matter of seconds. If a user sees the Linux kernel's "dazed and + confused" message in the logs or if the system gets into a hung state, then + the hpwdt driver can be reloaded with the "priority" module parameter set + (priority=1). + + 1. If the kernel has not been booted with nmi_watchdog turned off then + edit /boot/grub/menu.lst and place the nmi_watchdog=0 at the end of the + currently booting kernel line. + 2. reboot the sever + 3. Once the system comes up perform a rmmod hpwdt + 4. insmod /lib/modules/`uname -r`/kernel/drivers/char/watchdog/hpwdt.ko priority=1 + + Now, the hpwdt can successfully receive and source the NMI and provide a log + message that details the reason for the NMI (as determined by the HP BIOS). + + Below is a list of NMIs the HP BIOS understands along with the associated + code (reason): + + No source found 00h + + Uncorrectable Memory Error 01h + + ASR NMI 1Bh + + PCI Parity Error 20h + + NMI Button Press 27h + + SB_BUS_NMI 28h + + ILO Doorbell NMI 29h + + ILO IOP NMI 2Ah + + ILO Watchdog NMI 2Bh + + Proc Throt NMI 2Ch + + Front Side Bus NMI 2Dh + + PCI Express Error 2Fh + + DMA controller NMI 30h + + Hypertransport/CSI Error 31h + + + + -- Tom Mingarelli + (thomas.mingarelli@hp.com) diff --git a/Documentation/x86/boot.txt b/Documentation/x86/boot.txt index e0203662f9e9..8da3a795083f 100644 --- a/Documentation/x86/boot.txt +++ b/Documentation/x86/boot.txt @@ -50,6 +50,10 @@ Protocol 2.08: (Kernel 2.6.26) Added crc32 checksum and ELF format Protocol 2.09: (Kernel 2.6.26) Added a field of 64-bit physical pointer to single linked list of struct setup_data. +Protocol 2.10: (Kernel 2.6.31) Added a protocol for relaxed alignment + beyond the kernel_alignment added, new init_size and + pref_address fields. Added extended boot loader IDs. + **** MEMORY LAYOUT The traditional memory map for the kernel loader, used for Image or @@ -168,12 +172,13 @@ Offset Proto Name Meaning 021C/4 2.00+ ramdisk_size initrd size (set by boot loader) 0220/4 2.00+ bootsect_kludge DO NOT USE - for bootsect.S use only 0224/2 2.01+ heap_end_ptr Free memory after setup end -0226/2 N/A pad1 Unused +0226/1 2.02+(3 ext_loader_ver Extended boot loader version +0227/1 2.02+(3 ext_loader_type Extended boot loader ID 0228/4 2.02+ cmd_line_ptr 32-bit pointer to the kernel command line 022C/4 2.03+ ramdisk_max Highest legal initrd address 0230/4 2.05+ kernel_alignment Physical addr alignment required for kernel 0234/1 2.05+ relocatable_kernel Whether kernel is relocatable or not -0235/1 N/A pad2 Unused +0235/1 2.10+ min_alignment Minimum alignment, as a power of two 0236/2 N/A pad3 Unused 0238/4 2.06+ cmdline_size Maximum size of the kernel command line 023C/4 2.07+ hardware_subarch Hardware subarchitecture @@ -182,6 +187,8 @@ Offset Proto Name Meaning 024C/4 2.08+ payload_length Length of kernel payload 0250/8 2.09+ setup_data 64-bit physical pointer to linked list of struct setup_data +0258/8 2.10+ pref_address Preferred loading address +0260/4 2.10+ init_size Linear memory required during initialization (1) For backwards compatibility, if the setup_sects field contains 0, the real value is 4. @@ -190,6 +197,8 @@ Offset Proto Name Meaning field are unusable, which means the size of a bzImage kernel cannot be determined. +(3) Ignored, but safe to set, for boot protocols 2.02-2.09. + If the "HdrS" (0x53726448) magic number is not found at offset 0x202, the boot protocol version is "old". Loading an old kernel, the following parameters should be assumed: @@ -343,18 +352,32 @@ Protocol: 2.00+ 0xTV here, where T is an identifier for the boot loader and V is a version number. Otherwise, enter 0xFF here. + For boot loader IDs above T = 0xD, write T = 0xE to this field and + write the extended ID minus 0x10 to the ext_loader_type field. + Similarly, the ext_loader_ver field can be used to provide more than + four bits for the bootloader version. + + For example, for T = 0x15, V = 0x234, write: + + type_of_loader <- 0xE4 + ext_loader_type <- 0x05 + ext_loader_ver <- 0x23 + Assigned boot loader ids: 0 LILO (0x00 reserved for pre-2.00 bootloader) 1 Loadlin 2 bootsect-loader (0x20, all other values reserved) - 3 SYSLINUX - 4 EtherBoot + 3 Syslinux + 4 Etherboot/gPXE 5 ELILO 7 GRUB - 8 U-BOOT + 8 U-Boot 9 Xen A Gujin B Qemu + C Arcturus Networks uCbootloader + E Extended (see ext_loader_type) + F Special (0xFF = undefined) Please contact if you need a bootloader ID value assigned. @@ -453,6 +476,35 @@ Protocol: 2.01+ Set this field to the offset (from the beginning of the real-mode code) of the end of the setup stack/heap, minus 0x0200. +Field name: ext_loader_ver +Type: write (optional) +Offset/size: 0x226/1 +Protocol: 2.02+ + + This field is used as an extension of the version number in the + type_of_loader field. The total version number is considered to be + (type_of_loader & 0x0f) + (ext_loader_ver << 4). + + The use of this field is boot loader specific. If not written, it + is zero. + + Kernels prior to 2.6.31 did not recognize this field, but it is safe + to write for protocol version 2.02 or higher. + +Field name: ext_loader_type +Type: write (obligatory if (type_of_loader & 0xf0) == 0xe0) +Offset/size: 0x227/1 +Protocol: 2.02+ + + This field is used as an extension of the type number in + type_of_loader field. If the type in type_of_loader is 0xE, then + the actual type is (ext_loader_type + 0x10). + + This field is ignored if the type in type_of_loader is not 0xE. + + Kernels prior to 2.6.31 did not recognize this field, but it is safe + to write for protocol version 2.02 or higher. + Field name: cmd_line_ptr Type: write (obligatory) Offset/size: 0x228/4 @@ -482,11 +534,19 @@ Protocol: 2.03+ 0x37FFFFFF, you can start your ramdisk at 0x37FE0000.) Field name: kernel_alignment -Type: read (reloc) +Type: read/modify (reloc) Offset/size: 0x230/4 -Protocol: 2.05+ +Protocol: 2.05+ (read), 2.10+ (modify) - Alignment unit required by the kernel (if relocatable_kernel is true.) + Alignment unit required by the kernel (if relocatable_kernel is + true.) A relocatable kernel that is loaded at an alignment + incompatible with the value in this field will be realigned during + kernel initialization. + + Starting with protocol version 2.10, this reflects the kernel + alignment preferred for optimal performance; it is possible for the + loader to modify this field to permit a lesser alignment. See the + min_alignment and pref_address field below. Field name: relocatable_kernel Type: read (reloc) @@ -498,6 +558,22 @@ Protocol: 2.05+ After loading, the boot loader must set the code32_start field to point to the loaded code, or to a boot loader hook. +Field name: min_alignment +Type: read (reloc) +Offset/size: 0x235/1 +Protocol: 2.10+ + + This field, if nonzero, indicates as a power of two the minimum + alignment required, as opposed to preferred, by the kernel to boot. + If a boot loader makes use of this field, it should update the + kernel_alignment field with the alignment unit desired; typically: + + kernel_alignment = 1 << min_alignment + + There may be a considerable performance cost with an excessively + misaligned kernel. Therefore, a loader should typically try each + power-of-two alignment from kernel_alignment down to this alignment. + Field name: cmdline_size Type: read Offset/size: 0x238/4 @@ -582,6 +658,36 @@ Protocol: 2.09+ sure to consider the case where the linked list already contains entries. +Field name: pref_address +Type: read (reloc) +Offset/size: 0x258/8 +Protocol: 2.10+ + + This field, if nonzero, represents a preferred load address for the + kernel. A relocating bootloader should attempt to load at this + address if possible. + + A non-relocatable kernel will unconditionally move itself and to run + at this address. + +Field name: init_size +Type: read +Offset/size: 0x25c/4 + + This field indicates the amount of linear contiguous memory starting + at the kernel runtime start address that the kernel needs before it + is capable of examining its memory map. This is not the same thing + as the total amount of memory the kernel needs to boot, but it can + be used by a relocating boot loader to help select a safe load + address for the kernel. + + The kernel runtime start address is determined by the following algorithm: + + if (relocatable_kernel) + runtime_start = align_up(load_address, kernel_alignment) + else + runtime_start = pref_address + **** THE IMAGE CHECKSUM diff --git a/Documentation/x86/x86_64/boot-options.txt b/Documentation/x86/x86_64/boot-options.txt index 34c13040a718..29a6ff8bc7d3 100644 --- a/Documentation/x86/x86_64/boot-options.txt +++ b/Documentation/x86/x86_64/boot-options.txt @@ -5,21 +5,51 @@ only the AMD64 specific ones are listed here. Machine check - mce=off disable machine check - mce=bootlog Enable logging of machine checks left over from booting. - Disabled by default on AMD because some BIOS leave bogus ones. - If your BIOS doesn't do that it's a good idea to enable though - to make sure you log even machine check events that result - in a reboot. On Intel systems it is enabled by default. + Please see Documentation/x86/x86_64/machinecheck for sysfs runtime tunables. + + mce=off + Disable machine check + mce=no_cmci + Disable CMCI(Corrected Machine Check Interrupt) that + Intel processor supports. Usually this disablement is + not recommended, but it might be handy if your hardware + is misbehaving. + Note that you'll get more problems without CMCI than with + due to the shared banks, i.e. you might get duplicated + error logs. + mce=dont_log_ce + Don't make logs for corrected errors. All events reported + as corrected are silently cleared by OS. + This option will be useful if you have no interest in any + of corrected errors. + mce=ignore_ce + Disable features for corrected errors, e.g. polling timer + and CMCI. All events reported as corrected are not cleared + by OS and remained in its error banks. + Usually this disablement is not recommended, however if + there is an agent checking/clearing corrected errors + (e.g. BIOS or hardware monitoring applications), conflicting + with OS's error handling, and you cannot deactivate the agent, + then this option will be a help. + mce=bootlog + Enable logging of machine checks left over from booting. + Disabled by default on AMD because some BIOS leave bogus ones. + If your BIOS doesn't do that it's a good idea to enable though + to make sure you log even machine check events that result + in a reboot. On Intel systems it is enabled by default. mce=nobootlog Disable boot machine check logging. - mce=tolerancelevel (number) + mce=tolerancelevel[,monarchtimeout] (number,number) + tolerance levels: 0: always panic on uncorrected errors, log corrected errors 1: panic or SIGBUS on uncorrected errors, log corrected errors 2: SIGBUS or log uncorrected errors, log corrected errors 3: never panic or SIGBUS, log all errors (for testing only) Default is 1 Can be also set using sysfs which is preferable. + monarchtimeout: + Sets the time in us to wait for other CPUs on machine checks. 0 + to disable. nomce (for compatibility with i386): same as mce=off @@ -150,11 +180,6 @@ NUMA Otherwise, the remaining system RAM is allocated to an additional node. - numa=hotadd=percent - Only allow hotadd memory to preallocate page structures upto - percent of already available memory. - numa=hotadd=0 will disable hotadd memory. - ACPI acpi=off Don't enable ACPI diff --git a/Documentation/x86/x86_64/machinecheck b/Documentation/x86/x86_64/machinecheck index a05e58e7b159..b1fb30273286 100644 --- a/Documentation/x86/x86_64/machinecheck +++ b/Documentation/x86/x86_64/machinecheck @@ -41,7 +41,9 @@ check_interval the polling interval. When the poller stops finding MCEs, it triggers an exponential backoff (poll less often) on the polling interval. The check_interval variable is both the initial and - maximum polling interval. + maximum polling interval. 0 means no polling for corrected machine + check errors (but some corrected errors might be still reported + in other ways) tolerant Tolerance level. When a machine check exception occurs for a non @@ -67,6 +69,10 @@ trigger Program to run when a machine check event is detected. This is an alternative to running mcelog regularly from cron and allows to detect events faster. +monarch_timeout + How long to wait for the other CPUs to machine check too on a + exception. 0 to disable waiting for other CPUs. + Unit: us TBD document entries for AMD threshold interrupt configuration diff --git a/Documentation/x86/x86_64/mm.txt b/Documentation/x86/x86_64/mm.txt index 29b52b14d0b4..d6498e3cd713 100644 --- a/Documentation/x86/x86_64/mm.txt +++ b/Documentation/x86/x86_64/mm.txt @@ -6,10 +6,11 @@ Virtual memory map with 4 level page tables: 0000000000000000 - 00007fffffffffff (=47 bits) user space, different per mm hole caused by [48:63] sign extension ffff800000000000 - ffff80ffffffffff (=40 bits) guard hole -ffff880000000000 - ffffc0ffffffffff (=57 TB) direct mapping of all phys. memory -ffffc10000000000 - ffffc1ffffffffff (=40 bits) hole -ffffc20000000000 - ffffe1ffffffffff (=45 bits) vmalloc/ioremap space -ffffe20000000000 - ffffe2ffffffffff (=40 bits) virtual memory map (1TB) +ffff880000000000 - ffffc7ffffffffff (=64 TB) direct mapping of all phys. memory +ffffc80000000000 - ffffc8ffffffffff (=40 bits) hole +ffffc90000000000 - ffffe8ffffffffff (=45 bits) vmalloc/ioremap space +ffffe90000000000 - ffffe9ffffffffff (=40 bits) hole +ffffea0000000000 - ffffeaffffffffff (=40 bits) virtual memory map (1TB) ... unused hole ... ffffffff80000000 - ffffffffa0000000 (=512 MB) kernel text mapping, from phys 0 ffffffffa0000000 - fffffffffff00000 (=1536 MB) module mapping space diff --git a/MAINTAINERS b/MAINTAINERS index cf4abddfc8a4..fa2a16def17a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -36,6 +36,12 @@ trivial patch so apply some common sense. (scripts/checkpatch.pl) to catch trival style violations. See Documentation/CodingStyle for guidance here. + PLEASE CC: the maintainers and mailing lists that are generated + by scripts/get_maintainer.pl. The results returned by the + script will be best if you have git installed and are making + your changes in a branch derived from Linus' latest git tree. + See Documentation/SubmittingPatches for details. + PLEASE try to include any credit lines you want added with the patch. It avoids people being missed off by mistake and makes it easier to know who wants adding and who doesn't. @@ -71,7 +77,7 @@ P: Person M: Mail patches to L: Mailing list that is relevant to this area W: Web-page with status/info -T: SCM tree type and location. Type is one of: git, hg, quilt. +T: SCM tree type and location. Type is one of: git, hg, quilt, stgit. S: Status, one of the following: Supported: Someone is actually paid to look after this. @@ -157,9 +163,11 @@ S: Maintained F: drivers/net/r8169.c 8250/16?50 (AND CLONE UARTS) SERIAL DRIVER +P: Alan Cox +M: alan@lxorguk.ukuu.org.uk L: linux-serial@vger.kernel.org W: http://serial.sourceforge.net -S: Orphan +S: Odd Fixes F: drivers/serial/8250* F: include/linux/serial_8250.h @@ -222,6 +230,13 @@ L: linux-acenic@sunsite.dk S: Maintained F: drivers/net/acenic* +ACER ASPIRE ONE TEMPERATURE AND FAN DRIVER +P: Peter Feuerer +M: peter@piie.net +W: http://piie.net/?section=acerhdf +S: Maintained +F: drivers/platform/x86/acerhdf.c + ACER WMI LAPTOP EXTRAS P: Carlos Corbacho M: carlos@strangeworlds.co.uk @@ -487,7 +502,7 @@ AOA (Apple Onboard Audio) ALSA DRIVER P: Johannes Berg M: johannes@sipsolutions.net L: linuxppc-dev@ozlabs.org -L: alsa-devel@alsa-project.org (subscribers-only) +L: alsa-devel@alsa-project.org (moderated for non-subscribers) S: Maintained F: sound/aoa/ @@ -645,6 +660,8 @@ M: laforge@openezx.org L: openezx-devel@lists.openezx.org (subscribers-only) W: http://www.openezx.org/ S: Maintained +T: topgit git://git.openezx.org/openezx.git +F: arch/arm/mach-pxa/ezx.c ARM/FARADAY FA526 PORT P: Paulius Zaleckas @@ -680,6 +697,13 @@ M: sakoman@gmail.com L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only) S: Maintained +ARM/H4700 (HP IPAQ HX4700) MACHINE SUPPORT +P: Philipp Zabel +M: philipp.zabel@gmail.com +S: Maintained +F: arch/arm/mach-pxa/hx4700.c +F: arch/arm/mach-pxa/include/mach/hx4700.h + ARM/HP JORNADA 7XX MACHINE SUPPORT P: Kristoffer Ericson M: kristoffer.ericson@gmail.com @@ -759,11 +783,25 @@ P: Philipp Zabel M: philipp.zabel@gmail.com S: Maintained +ARM/MIOA701 MACHINE SUPPORT +P: Robert Jarzmik +M: robert.jarzmik@free.fr +L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only) +F: arch/arm/mach-pxa/mioa701.c +S: Maintained + ARM/NEC MOBILEPRO 900/c MACHINE SUPPORT P: Michael Petchkovsky M: mkpetch@internode.on.net S: Maintained +ARM/OPENMOKO NEO FREERUNNER (GTA02) MACHINE SUPPORT +P: Nelson Castillo +M: arhuaco@freaks-unidos.net +L: openmoko-kernel@lists.openmoko.org (subscribers-only) +W: http://wiki.openmoko.org/wiki/Neo_FreeRunner +S: Supported + ARM/TOSA MACHINE SUPPORT P: Dmitry Eremin-Solenikov M: dbaryshkov@gmail.com @@ -777,6 +815,12 @@ M: marek.vasut@gmail.com W: http://hackndev.com S: Maintained +ARM/PALM TREO 680 SUPPORT +P: Tomas Cech +M: sleep_walker@suse.cz +W: http://hackndev.com +S: Maintained + ARM/PALMZ72 SUPPORT P: Sergey Lapin M: slapin@ossfans.org @@ -876,8 +920,7 @@ M: corentincj@iksaif.net P: Karol Kozimor M: sziwan@users.sourceforge.net L: acpi4asus-user@lists.sourceforge.net -W: http://sourceforge.net/projects/acpi4asus -W: http://xf.iksaif.net/acpi4asus +W: http://acpi4asus.sf.net S: Maintained F: arch/x86/kernel/acpi/boot.c F: drivers/platform/x86/asus_acpi.c @@ -893,8 +936,7 @@ ASUS LAPTOP EXTRAS DRIVER P: Corentin Chary M: corentincj@iksaif.net L: acpi4asus-user@lists.sourceforge.net -W: http://sourceforge.net/projects/acpi4asus -W: http://xf.iksaif.net/acpi4asus +W: http://acpi4asus.sf.net S: Maintained F: drivers/platform/x86/asus-laptop.c @@ -903,7 +945,6 @@ P: Dan Williams M: dan.j.williams@intel.com P: Maciej Sosnowski M: maciej.sosnowski@intel.com -L: linux-kernel@vger.kernel.org W: http://sourceforge.net/projects/xscaleiop S: Supported F: Documentation/crypto/async-tx-api.txt @@ -932,17 +973,23 @@ M: me@bobcopeland.com L: linux-wireless@vger.kernel.org L: ath5k-devel@lists.ath5k.org S: Maintained -F: drivers/net/wireless/ath5k/ +F: drivers/net/wireless/ath/ath5k/ ATHEROS ATH9K WIRELESS DRIVER P: Luis R. Rodriguez M: lrodriguez@atheros.com P: Jouni Malinen M: jmalinen@atheros.com +P: Sujith Manoharan +M: Sujith.Manoharan@atheros.com +P: Vasanthakumar Thiagarajan +M: vasanth@atheros.com +P: Senthil Balasubramanian +M: senthilkumar@atheros.com L: linux-wireless@vger.kernel.org L: ath9k-devel@lists.ath9k.org S: Supported -F: drivers/net/wireless/ath9k/ +F: drivers/net/wireless/ath/ath9k/ ATHEROS AR9170 WIRELESS DRIVER P: Christian Lamparter @@ -950,7 +997,7 @@ M: chunkeey@web.de L: linux-wireless@vger.kernel.org W: http://wireless.kernel.org/en/users/Drivers/ar9170 S: Maintained -F: drivers/net/wireless/ar9170/ +F: drivers/net/wireless/ath/ar9170/ ATI_REMOTE2 DRIVER P: Ville Syrjala @@ -990,10 +1037,16 @@ W: http://www.at91.com/ S: Maintained F: drivers/mmc/host/at91_mci.c +ATMEL AT91 / AT32 MCI DRIVER +P: Nicolas Ferre +M: nicolas.ferre@atmel.com +S: Maintained +F: drivers/mmc/host/atmel-mci.c +F: drivers/mmc/host/atmel-mci-regs.h + ATMEL AT91 / AT32 SERIAL DRIVER P: Haavard Skinnemoen M: hskinnemoen@atmel.com -L: linux-kernel@vger.kernel.org S: Supported F: drivers/serial/atmel_serial.c @@ -1049,7 +1102,6 @@ F: kernel/audit* AUXILIARY DISPLAY DRIVERS P: Miguel Ojeda Sandonis M: miguel.ojeda.sandonis@gmail.com -L: linux-kernel@vger.kernel.org W: http://miguelojeda.es/auxdisplay.htm W: http://jair.lab.fi.uva.es/~migojed/auxdisplay.htm S: Maintained @@ -1119,7 +1171,6 @@ F: drivers/net/hamradio/baycom* BEFS FILE SYSTEM P: Sergey S. Kostyliov M: rathamahata@php4.ru -L: linux-kernel@vger.kernel.org S: Maintained F: Documentation/filesystems/befs.txt F: fs/befs/ @@ -1127,7 +1178,6 @@ F: fs/befs/ BFS FILE SYSTEM P: Tigran A. Aivazian M: tigran@aivazian.fsnet.co.uk -L: linux-kernel@vger.kernel.org S: Maintained F: Documentation/filesystems/bfs.txt F: fs/bfs/ @@ -1184,7 +1234,6 @@ F: drivers/i2c/busses/i2c-bfin-twi.c BLOCK LAYER P: Jens Axboe M: axboe@kernel.dk -L: linux-kernel@vger.kernel.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-2.6-block.git S: Maintained F: block/ @@ -1311,7 +1360,6 @@ P: Muli Ben-Yehuda M: muli@il.ibm.com P: Jon D. Mason M: jdmason@kudzu.us -L: linux-kernel@vger.kernel.org L: discuss@x86-64.org S: Maintained F: arch/x86/kernel/pci-calgary_64.c @@ -1331,6 +1379,13 @@ F: drivers/net/can/ F: include/linux/can/ F: include/linux/can.h +CAN NETWORK DRIVERS +P: Wolfgang Grandegger +M: wg@grandegger.com +L: socketcan-core@lists.berlios.de (subscribers-only) +W: http://developer.berlios.de/projects/socketcan/ +S: Maintained + CELL BROADBAND ENGINE ARCHITECTURE P: Arnd Bergmann M: arnd@arndb.de @@ -1356,7 +1411,6 @@ F: include/linux/usb/wusb* CFAG12864B LCD DRIVER P: Miguel Ojeda Sandonis M: miguel.ojeda.sandonis@gmail.com -L: linux-kernel@vger.kernel.org W: http://miguelojeda.es/auxdisplay.htm W: http://jair.lab.fi.uva.es/~migojed/auxdisplay.htm S: Maintained @@ -1366,7 +1420,6 @@ F: include/linux/cfag12864b.h CFAG12864BFB LCD FRAMEBUFFER DRIVER P: Miguel Ojeda Sandonis M: miguel.ojeda.sandonis@gmail.com -L: linux-kernel@vger.kernel.org W: http://miguelojeda.es/auxdisplay.htm W: http://jair.lab.fi.uva.es/~migojed/auxdisplay.htm S: Maintained @@ -1386,7 +1439,6 @@ X: net/wireless/wext* CHECKPATCH P: Andy Whitcroft M: apw@canonical.com -L: linux-kernel@vger.kernel.org S: Supported F: scripts/checkpatch.pl @@ -1415,7 +1467,7 @@ F: drivers/usb/host/ohci-ep93xx.c CIRRUS LOGIC CS4270 SOUND DRIVER P: Timur Tabi M: timur@freescale.com -L: alsa-devel@alsa-project.org +L: alsa-devel@alsa-project.org (moderated for non-subscribers) S: Supported F: sound/soc/codecs/cs4270* @@ -1440,6 +1492,7 @@ P: Joe Eykholt M: jeykholt@cisco.com L: linux-scsi@vger.kernel.org S: Supported +F: drivers/scsi/fnic/ CODA FILE SYSTEM P: Jan Harkes @@ -1512,7 +1565,6 @@ F: drivers/usb/atm/cxacru.c CONFIGFS P: Joel Becker M: joel.becker@oracle.com -L: linux-kernel@vger.kernel.org S: Supported F: fs/configfs/ F: include/linux/configfs.h @@ -1526,6 +1578,7 @@ L: containers@lists.linux-foundation.org S: Maintained F: include/linux/cgroup* F: kernel/cgroup* +F: mm/*cgroup* CORETEMP HARDWARE MONITORING DRIVER P: Rudolf Marek @@ -1570,7 +1623,6 @@ F: arch/x86/kernel/msr.c CPUSETS P: Paul Menage M: menage@google.com -L: linux-kernel@vger.kernel.org W: http://www.bullopensource.org/cpuset/ W: http://oss.sgi.com/projects/cpusets/ S: Supported @@ -1589,7 +1641,7 @@ P: Mikael Starvik M: starvik@axis.com P: Jesper Nilsson M: jesper.nilsson@axis.com -L: dev-etrax@axis.com +L: linux-cris-kernel@axis.com W: http://developer.axis.com S: Maintained F: arch/cris/ @@ -1777,7 +1829,6 @@ DEVICE NUMBER REGISTRY P: Torben Mathiasen M: device@lanana.org W: http://lanana.org/docs/device-list/index.html -L: linux-kernel@vger.kernel.org S: Maintained DEVICE-MAPPER (LVM) @@ -1801,10 +1852,9 @@ F: drivers/char/epca* F: drivers/char/digi* DIRECTORY NOTIFICATION (DNOTIFY) -P: Stephen Rothwell -M: sfr@canb.auug.org.au -L: linux-kernel@vger.kernel.org -S: Supported +P: Eric Paris +M: eparis@parisplace.org +S: Maintained F: Documentation/filesystems/dnotify.txt F: fs/notify/dnotify/ F: include/linux/dnotify.h @@ -1820,7 +1870,6 @@ S: Maintained DISKQUOTA P: Jan Kara M: jack@suse.cz -L: linux-kernel@vger.kernel.org S: Maintained F: Documentation/filesystems/quota.txt F: fs/quota/ @@ -1842,7 +1891,6 @@ P: Maciej Sosnowski M: maciej.sosnowski@intel.com P: Dan Williams M: dan.j.williams@intel.com -L: linux-kernel@vger.kernel.org S: Supported F: drivers/dma/ F: include/linux/dma* @@ -1894,7 +1942,6 @@ F: drivers/scsi/dpt/ DRIVER CORE, KOBJECTS, AND SYSFS P: Greg Kroah-Hartman M: gregkh@suse.de -L: linux-kernel@vger.kernel.org T: quilt kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/ S: Supported F: Documentation/kobject.txt @@ -1960,8 +2007,8 @@ F: net/bridge/netfilter/ebt*.c ECRYPT FILE SYSTEM P: Tyler Hicks M: tyhicks@linux.vnet.ibm.com -M: Dustin Kirkland -P: kirkland@canonical.com +P: Dustin Kirkland +M: kirkland@canonical.com L: ecryptfs-devel@lists.launchpad.net W: https://launchpad.net/ecryptfs S: Supported @@ -1978,6 +2025,16 @@ F: Documentation/edac.txt F: drivers/edac/edac_* F: include/linux/edac.h +EDAC-AMD64 +P: Doug Thompson +M: dougthompson@xmission.com +P: Borislav Petkov +M: borislav.petkov@amd.com +L: bluesmoke-devel@lists.sourceforge.net (moderated for non-subscribers) +W: bluesmoke.sourceforge.net +S: Supported +F: drivers/edac/amd64_edac* + EDAC-E752X P: Mark Gross M: mark.gross@intel.com @@ -2030,8 +2087,8 @@ F: drivers/edac/i5400_edac.c EDAC-I82975X P: Ranganathan Desikan -P: Arvind R. M: rdesikan@jetzbroadband.com +P: Arvind R. M: arvind@acarlab.com L: bluesmoke-devel@lists.sourceforge.net (moderated for non-subscribers) W: bluesmoke.sourceforge.net @@ -2058,7 +2115,7 @@ EEEPC LAPTOP EXTRAS DRIVER P: Corentin Chary M: corentincj@iksaif.net L: acpi4asus-user@lists.sourceforge.net -W: http://sourceforge.net/projects/acpi4asus +W: http://acpi4asus.sf.net S: Maintained F: drivers/platform/x86/eeepc-laptop.c @@ -2094,6 +2151,15 @@ W: http://sourceforge.net/projects/lpfcxxxx S: Supported F: drivers/scsi/lpfc/ +ENE CB710 FLASH CARD READER DRIVER +P: MichaÅ‚ MirosÅ‚aw +M: mirq-linux@rere.qmqm.pl +L: linux-kernel@vger.kernel.org +S: Maintained +F: drivers/misc/cb710/ +F: drivers/mmc/host/cb710-mmc.* +F: include/linux/cb710.h + EPSON 1355 FRAMEBUFFER DRIVER P: Christopher Hoover M: ch@murgatroid.com @@ -2222,7 +2288,6 @@ F: drivers/firewire/ F: include/linux/firewire*.h FIRMWARE LOADER (request_firmware) -L: linux-kernel@vger.kernel.org S: Orphan F: Documentation/firmware_class/ F: drivers/base/firmware*.c @@ -2244,11 +2309,9 @@ F: drivers/net/wan/dlci.c F: drivers/net/wan/sdla.c FRAMEBUFFER LAYER -P: Antonino Daplas -M: adaplas@gmail.com L: linux-fbdev-devel@lists.sourceforge.net (moderated for non-subscribers) W: http://linux-fbdev.sourceforge.net/ -S: Maintained +S: Orphan F: Documentation/fb/ F: drivers/video/fb* F: include/linux/fb.h @@ -2259,7 +2322,6 @@ M: leoli@freescale.com P: Zhang Wei M: zw@zh-kernel.org L: linuxppc-dev@ozlabs.org -L: linux-kernel@vger.kernel.org S: Maintained F: drivers/dma/fsldma.* @@ -2325,7 +2387,7 @@ F: drivers/serial/ucc_uart.c FREESCALE SOC SOUND DRIVERS P: Timur Tabi M: timur@freescale.com -L: alsa-devel@alsa-project.org +L: alsa-devel@alsa-project.org (moderated for non-subscribers) L: linuxppc-dev@ozlabs.org S: Supported F: sound/soc/fsl/fsl* @@ -2340,7 +2402,7 @@ F: fs/freevxfs/ FREEZER P: Pavel Machek -M: pavel@suse.cz +M: pavel@ucw.cz P: Rafael J. Wysocki M: rjw@sisk.pl L: linux-pm@lists.linux-foundation.org @@ -2362,7 +2424,7 @@ FTRACE P: Steven Rostedt M: rostedt@goodmis.org S: Maintained -F: Documentation/ftrace.txt +F: Documentation/trace/ftrace.txt F: arch/*/*/*/ftrace.h F: arch/*/kernel/ftrace.c F: include/*/ftrace.h @@ -2425,6 +2487,14 @@ F: drivers/net/wan/pc300too.c F: drivers/net/wan/pci200syn.c F: drivers/net/wan/wanxl* +GENERIC INCLUDE/ASM HEADER FILES +P: Arnd Bergmann +M: arnd@arndb.de +L: linux-arch@vger.kernel.org +T: git git://git.kernel.org/pub/scm/linux/kernel/git/arnd/asm-generic.git +S: Maintained +F: include/asm-generic + GFS2 FILE SYSTEM P: Steven Whitehouse M: swhiteho@redhat.com @@ -2459,7 +2529,6 @@ F: drivers/hwmon/hdaps.c HYPERVISOR VIRTUAL CONSOLE DRIVER L: linuxppc-dev@ozlabs.org -L: linux-kernel@vger.kernel.org S: Odd Fixes F: drivers/char/hvc_* @@ -2526,7 +2595,6 @@ F: sound/parisc/harmony.* HAYES ESP SERIAL DRIVER P: Andrew J. Robinson M: arobinso@nyx.net -L: linux-kernel@vger.kernel.org W: http://www.nyx.net/~arobinso S: Maintained F: Documentation/serial/hayes-esp.txt @@ -2552,7 +2620,6 @@ F: include/linux/cciss_ioctl.h HFS FILESYSTEM P: Roman Zippel M: zippel@linux-m68k.org -L: linux-kernel@vger.kernel.org S: Maintained F: Documentation/filesystems/hfs.txt F: fs/hfs/ @@ -2592,7 +2659,6 @@ F: include/linux/hid* HIGH-RESOLUTION TIMERS, CLOCKEVENTS, DYNTICKS P: Thomas Gleixner M: tglx@linutronix.de -L: linux-kernel@vger.kernel.org S: Maintained F: Documentation/timers/ F: kernel/hrtimer.c @@ -2731,7 +2797,6 @@ F: drivers/i2c/busses/i2c-tiny-usb.c i386 BOOT CODE P: H. Peter Anvin M: hpa@zytor.com -L: Linux-Kernel@vger.kernel.org S: Maintained F: arch/x86/boot/ @@ -2772,10 +2837,10 @@ S: Supported F: drivers/scsi/ips.* IDE SUBSYSTEM -P: Bartlomiej Zolnierkiewicz -M: bzolnier@gmail.com +P: David S. Miller +M: davem@davemloft.net L: linux-ide@vger.kernel.org -T: git git://git.kernel.org/pub/scm/linux/kernel/git/bart/ide-2.6.git +T: git git://git.kernel.org/pub/scm/linux/kernel/git/davem/ide-2.6.git S: Maintained F: Documentation/ide/ F: drivers/ide/ @@ -2816,6 +2881,18 @@ L: linux1394-devel@lists.sourceforge.net S: Maintained F: drivers/ieee1394/raw1394* +IEEE 802.15.4 SUBSYSTEM +P: Dmitry Eremin-Solenikov +M: dbaryshkov@gmail.com +P: Sergey Lapin +M: slapin@ossfans.org +L: linux-zigbee-devel@lists.sourceforge.net +W: http://apps.sourceforge.net/trac/linux-zigbee +T: git git://git.kernel.org/pub/scm/linux/kernel/git/lowpan/lowpan.git +S: Maintained +F: net/ieee802154/ +F: drivers/ieee802154/ + INTEGRITY MEASUREMENT ARCHITECTURE (IMA) P: Mimi Zohar M: zohar@us.ibm.com @@ -2847,7 +2924,8 @@ P: John McCutchan M: john@johnmccutchan.com P: Robert Love M: rlove@rlove.org -L: linux-kernel@vger.kernel.org +P: Eric Paris +M: eparis@parisplace.org S: Maintained F: Documentation/filesystems/inotify.txt F: fs/notify/inotify/ @@ -2895,7 +2973,6 @@ F: arch/x86/kernel/microcode_intel.c INTEL I/OAT DMA DRIVER P: Maciej Sosnowski M: maciej.sosnowski@intel.com -L: linux-kernel@vger.kernel.org S: Supported F: drivers/dma/ioat* @@ -2911,7 +2988,6 @@ F: include/linux/intel-iommu.h INTEL IOP-ADMA DMA DRIVER P: Dan Williams M: dan.j.williams@intel.com -L: linux-kernel@vger.kernel.org S: Supported F: drivers/dma/iop-adma.c @@ -3107,6 +3183,7 @@ M: samuel@sortiz.org L: irda-users@lists.sourceforge.net (subscribers-only) W: http://irda.sourceforge.net/ S: Maintained +T: git git://git.kernel.org/pub/scm/linux/kernel/git/sameo/irda-2.6.git F: Documentation/networking/irda.txt F: drivers/net/irda/ F: include/net/irda/ @@ -3188,7 +3265,6 @@ W: http://www.linux-mtd.infradead.org/doc/jffs2.html S: Maintained F: fs/jffs2/ F: include/linux/jffs2.h -F: include/mtd/jffs2-user.h JOURNALLING LAYER FOR BLOCK DEVICES (JBD) P: Stephen Tweedie @@ -3223,7 +3299,6 @@ M: vgoyal@redhat.com P: Haren Myneni M: hbabu@us.ibm.com L: kexec@lists.infradead.org -L: linux-kernel@vger.kernel.org W: http://lse.sourceforge.net/kdump/ S: Maintained F: Documentation/kdump/ @@ -3333,7 +3408,6 @@ KEXEC P: Eric Biederman M: ebiederm@xmission.com W: http://ftp.kernel.org/pub/linux/kernel/people/horms/kexec-tools/ -L: linux-kernel@vger.kernel.org L: kexec@lists.infradead.org S: Maintained F: include/linux/kexec.h @@ -3350,13 +3424,30 @@ F: drivers/serial/kgdboc.c F: include/linux/kgdb.h F: kernel/kgdb.c +KMEMCHECK +P: Vegard Nossum +M: vegardno@ifi.uio.no +P Pekka Enberg +M: penberg@cs.helsinki.fi +L: linux-kernel@vger.kernel.org +S: Maintained + +KMEMLEAK +P: Catalin Marinas +M: catalin.marinas@arm.com +L: linux-kernel@vger.kernel.org +S: Maintained +F: Documentation/kmemleak.txt +F: include/linux/kmemleak.h +F: mm/kmemleak.c +F: mm/kmemleak-test.c + KMEMTRACE P: Eduard - Gabriel Munteanu M: eduard.munteanu@linux360.ro -L: linux-kernel@vger.kernel.org S: Maintained F: Documentation/trace/kmemtrace.txt -F: include/trace/kmemtrace.h +F: include/linux/kmemtrace.h F: kernel/trace/kmemtrace.c KPROBES @@ -3368,7 +3459,6 @@ P: David S. Miller M: davem@davemloft.net P: Masami Hiramatsu M: mhiramat@redhat.com -L: linux-kernel@vger.kernel.org S: Maintained F: Documentation/kprobes.txt F: include/linux/kprobes.h @@ -3377,7 +3467,6 @@ F: kernel/kprobes.c KS0108 LCD CONTROLLER DRIVER P: Miguel Ojeda Sandonis M: miguel.ojeda.sandonis@gmail.com -L: linux-kernel@vger.kernel.org W: http://miguelojeda.es/auxdisplay.htm W: http://jair.lab.fi.uva.es/~migojed/auxdisplay.htm S: Maintained @@ -3541,7 +3630,6 @@ P: Peter Zijlstra M: peterz@infradead.org P: Ingo Molnar M: mingo@redhat.com -L: linux-kernel@vger.kernel.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/peterz/linux-2.6-lockdep.git S: Maintained F: Documentation/lockdep*.txt @@ -3593,7 +3681,6 @@ L: linux-m32r-ja@ml.linux-m32r.org (in Japanese) W: http://www.linux-m32r.org/ S: Maintained F: arch/m32r/ -F: include/asm-m32r/ M68K ARCHITECTURE P: Geert Uytterhoeven @@ -3677,7 +3764,6 @@ F: include/linux/mv643xx.h MARVELL SOC MMC/SD/SDIO CONTROLLER DRIVER P: Nicolas Pitre M: nico@cam.org -L: linux-kernel@vger.kernel.org S: Maintained MARVELL YUKON / SYSKONNECT DRIVER @@ -3731,7 +3817,6 @@ F: drivers/scsi/megaraid/ MEMORY MANAGEMENT L: linux-mm@kvack.org -L: linux-kernel@vger.kernel.org W: http://www.linux-mm.org S: Maintained F: include/linux/mm.h @@ -3745,7 +3830,6 @@ M: xemul@openvz.org P: KAMEZAWA Hiroyuki M: kamezawa.hiroyu@jp.fujitsu.com L: linux-mm@kvack.org -L: linux-kernel@vger.kernel.org S: Maintained F: mm/memcontrol.c @@ -3788,7 +3872,6 @@ F: arch/mips/ MISCELLANEOUS MCA-SUPPORT P: James Bottomley M: James.Bottomley@HansenPartnership.com -L: linux-kernel@vger.kernel.org S: Maintained F: Documentation/ia64/mca.txt F: Documentation/mca.txt @@ -3798,7 +3881,6 @@ F: include/linux/mca* MODULE SUPPORT P: Rusty Russell M: rusty@rustcorp.com.au -L: linux-kernel@vger.kernel.org S: Maintained F: include/linux/module.h F: kernel/module.c @@ -3822,7 +3904,6 @@ F: drivers/mmc/host/imxmmc.* MOUSE AND MISC DEVICES [GENERAL] P: Alessandro Rubini M: rubini@ipvvis.unipv.it -L: linux-kernel@vger.kernel.org S: Maintained F: drivers/input/mouse/ F: include/linux/gpio_mouse.h @@ -3830,7 +3911,6 @@ F: include/linux/gpio_mouse.h MOXA SMARTIO/INDUSTIO/INTELLIO SERIAL CARD P: Jiri Slaby M: jirislaby@gmail.com -L: linux-kernel@vger.kernel.org S: Maintained F: Documentation/serial/moxa-smartio F: drivers/char/mxser.* @@ -3846,7 +3926,6 @@ F: drivers/platform/x86/msi-laptop.c MULTIFUNCTION DEVICES (MFD) P: Samuel Ortiz M: sameo@linux.intel.com -L: linux-kernel@vger.kernel.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-2.6.git S: Supported F: drivers/mfd/ @@ -3854,7 +3933,6 @@ F: drivers/mfd/ MULTIMEDIA CARD (MMC), SECURE DIGITAL (SD) AND SDIO SUBSYSTEM P: Pierre Ossman M: pierre@ossman.eu -L: linux-kernel@vger.kernel.org S: Maintained F: drivers/mmc/ F: include/linux/mmc/ @@ -3862,7 +3940,6 @@ F: include/linux/mmc/ MULTIMEDIA CARD (MMC) ETC. OVER SPI P: David Brownell M: dbrownell@users.sourceforge.net -L: linux-kernel@vger.kernel.org S: Odd Fixes F: drivers/mmc/host/mmc_spi.c F: include/linux/spi/mmc_spi.h @@ -3877,7 +3954,6 @@ F: sound/oss/msnd* MULTITECH MULTIPORT CARD (ISICOM) P: Jiri Slaby M: jirislaby@gmail.com -L: linux-kernel@vger.kernel.org S: Maintained F: drivers/char/isicom.c F: include/linux/isicom.h @@ -4048,7 +4124,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git S: Maintained F: net/wireless/ F: include/net/ieee80211* -F: include/net/wireless.h +F: include/linux/wireless.h NETWORKING DRIVERS L: netdev@vger.kernel.org @@ -4121,7 +4197,6 @@ NTFS FILESYSTEM P: Anton Altaparmakov M: aia21@cantab.net L: linux-ntfs-dev@lists.sourceforge.net -L: linux-kernel@vger.kernel.org W: http://www.linux-ntfs.org/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/aia21/ntfs-2.6.git S: Maintained @@ -4136,6 +4211,69 @@ S: Maintained F: drivers/video/riva/ F: drivers/video/nvidia/ +OMAP SUPPORT +P: Tony Lindgren +M: tony@atomide.com +L: linux-omap@vger.kernel.org +W: http://www.muru.com/linux/omap/ +W: http://linux.omap.com/ +T: git git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap-2.6.git +S: Maintained +F: arch/arm/*omap* + +OMAP CLOCK FRAMEWORK SUPPORT +P: Paul Walmsley +M: paul@pwsan.com +L: linux-omap@vger.kernel.org +S: Maintained +F: arch/arm/*omap*/*clock* + +OMAP POWER MANAGEMENT SUPPORT +P: Kevin Hilman +M: khilman@deeprootsystems.com +L: linux-omap@vger.kernel.org +S: Maintained +F: arch/arm/*omap*/*pm* + +OMAP AUDIO SUPPORT +P: Jarkko Nikula +M: jhnikula@gmail.com +L: alsa-devel@alsa-project.org (subscribers-only) +L: linux-omap@vger.kernel.org +S: Maintained +F: sound/soc/omap/ + +OMAP FRAMEBUFFER SUPPORT +P: Imre Deak +M: imre.deak@nokia.com +L: linux-fbdev-devel@lists.sourceforge.net (moderated for non-subscribers) +L: linux-omap@vger.kernel.org +S: Maintained +F: drivers/video/omap/ + +OMAP MMC SUPPORT +P: Jarkko Lavinen +M: jarkko.lavinen@nokia.com +L: linux-kernel@vger.kernel.org +L: linux-omap@vger.kernel.org +S: Maintained +F: drivers/mmc/host/*omap* + +OMAP RANDOM NUMBER GENERATOR SUPPORT +P: Deepak Saxena +M: dsaxena@plexity.net +S: Maintained +F: drivers/char/hw_random/omap-rng.c + +OMAP USB SUPPORT +P: Felipe Balbi +M: felipe.balbi@nokia.com +P: David Brownell +M: dbrownell@users.sourceforge.net +L: linux-usb@vger.kernel.org +L: linux-omap@vger.kernel.org +S: Maintained + OMFS FILESYSTEM P: Bob Copeland M: me@bobcopeland.com @@ -4292,7 +4430,6 @@ M: akataria@vmware.com P: Rusty Russell M: rusty@rustcorp.com.au L: virtualization@lists.osdl.org -L: linux-kernel@vger.kernel.org S: Supported F: Documentation/ia64/paravirt_ops.txt F: arch/*/kernel/paravirt* @@ -4343,7 +4480,6 @@ F: include/linux/leds-pca9532.h PCI ERROR RECOVERY P: Linas Vepstas M: linas@austin.ibm.com -L: linux-kernel@vger.kernel.org L: linux-pci@vger.kernel.org S: Supported F: Documentation/PCI/pci-error-recovery.txt @@ -4352,7 +4488,6 @@ F: Documentation/powerpc/eeh-pci-error-recovery.txt PCI SUBSYSTEM P: Jesse Barnes M: jbarnes@virtuousgeek.org -L: linux-kernel@vger.kernel.org L: linux-pci@vger.kernel.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci-2.6.git S: Supported @@ -4387,11 +4522,20 @@ F: drivers/net/pcnet32.c PER-TASK DELAY ACCOUNTING P: Balbir Singh M: balbir@linux.vnet.ibm.com -L: linux-kernel@vger.kernel.org S: Maintained F: include/linux/delayacct.h F: kernel/delayacct.c +PERFORMANCE COUNTER SUBSYSTEM +P: Peter Zijlstra +M: a.p.zijlstra@chello.nl +P: Paul Mackerras +M: paulus@samba.org +P: Ingo Molnar +M: mingo@elte.hu +L: linux-kernel@vger.kernel.org +S: Supported + PERSONALITY HANDLING P: Christoph Hellwig M: hch@infradead.org @@ -4409,7 +4553,6 @@ F: drivers/mtd/devices/phram.c PKTCDVD DRIVER P: Peter Osterlund M: petero2@telia.com -L: linux-kernel@vger.kernel.org S: Maintained F: drivers/block/pktcdvd.c F: include/linux/pktcdvd.h @@ -4417,7 +4560,6 @@ F: include/linux/pktcdvd.h POSIX CLOCKS and TIMERS P: Thomas Gleixner M: tglx@linutronix.de -L: linux-kernel@vger.kernel.org S: Supported F: fs/timerfd.c F: include/linux/timer* @@ -4428,7 +4570,6 @@ P: Anton Vorontsov M: cbou@mail.ru P: David Woodhouse M: dwmw2@infradead.org -L: linux-kernel@vger.kernel.org T: git git://git.infradead.org/battery-2.6.git S: Maintained F: include/linux/power_supply.h @@ -4477,10 +4618,16 @@ S: Maintained F: drivers/net/pppol2tp.c F: include/linux/if_pppol2tp.h +PPS SUPPORT +P: Rodolfo Giometti +M: giometti@enneenne.com +W: http://wiki.enneenne.com/index.php/LinuxPPS_support +L: linuxpps@ml.enneenne.com (subscribers-only) +S: Maintained + PREEMPTIBLE KERNEL P: Robert Love M: rml@tech9.net -L: linux-kernel@vger.kernel.org L: kpreempt-tech@lists.sourceforge.net W: ftp://ftp.kernel.org/pub/linux/kernel/people/rml/preempt-kernel S: Supported @@ -4509,8 +4656,8 @@ S: Maintained F: drivers/ata/sata_promise.* PS3 NETWORK SUPPORT -P: Masakazu Mokuno -M: mokuno@sm.sony.co.jp +P: Geoff Levand +M: geoffrey.levand@am.sony.com L: netdev@vger.kernel.org L: cbe-oss-dev@ozlabs.org S: Supported @@ -4543,7 +4690,6 @@ P: Roland McGrath M: roland@redhat.com P: Oleg Nesterov M: oleg@redhat.com -L: linux-kernel@vger.kernel.org S: Maintained F: include/asm-generic/syscall.h F: include/linux/ptrace.h @@ -4564,7 +4710,7 @@ F: drivers/media/video/pvrusb2/ PXA2xx/PXA3xx SUPPORT P: Eric Miao -M: eric.miao@marvell.com +M: eric.y.miao@gmail.com P: Russell King M: linux@arm.linux.org.uk L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only) @@ -4574,23 +4720,24 @@ F: drivers/pcmcia/pxa2xx* F: drivers/spi/pxa2xx* F: drivers/usb/gadget/pxa2* F: include/sound/pxa2xx-lib.h -F: sound/soc/pxa/pxa2xx* +F: sound/arm/pxa* +F: sound/soc/pxa PXA168 SUPPORT P: Eric Miao -M: eric.miao@marvell.com +M: eric.y.miao@gmail.com P: Jason Chagas M: jason.chagas@marvell.com L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only) T: git git://git.kernel.org/pub/scm/linux/kernel/git/ycmiao/pxa-linux-2.6.git -S: Supported +S: Maintained PXA910 SUPPORT P: Eric Miao -M: eric.miao@marvell.com +M: eric.y.miao@gmail.com L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only) T: git git://git.kernel.org/pub/scm/linux/kernel/git/ycmiao/pxa-linux-2.6.git -S: Supported +S: Maintained PXA MMCI DRIVER S: Orphan @@ -4628,7 +4775,6 @@ F: drivers/net/qlge/ QNX4 FILESYSTEM P: Anders Larsen M: al@alarsen.net -L: linux-kernel@vger.kernel.org W: http://www.alarsen.net/linux/qnx4fs/ S: Maintained F: fs/qnx4/ @@ -4675,7 +4821,6 @@ F: drivers/char/random.c RAPIDIO SUBSYSTEM P: Matt Porter M: mporter@kernel.crashing.org -L: linux-kernel@vger.kernel.org S: Maintained F: drivers/rapidio/ @@ -4689,7 +4834,8 @@ F: drivers/net/wireless/ray* RCUTORTURE MODULE P: Josh Triplett M: josh@freedesktop.org -L: linux-kernel@vger.kernel.org +P: Paul E. McKenney +M: paulmck@linux.vnet.ibm.com S: Maintained F: Documentation/RCU/torture.txt F: kernel/rcutorture.c @@ -4697,7 +4843,6 @@ F: kernel/rcutorture.c RDC R-321X SoC P: Florian Fainelli M: florian@openwrt.org -L: linux-kernel@vger.kernel.org S: Maintained RDC R6040 FAST ETHERNET DRIVER @@ -4710,15 +4855,16 @@ F: drivers/net/r6040.c RDS - RELIABLE DATAGRAM SOCKETS P: Andy Grover M: andy.grover@oracle.com -L: rds-devel@oss.oracle.com +L: rds-devel@oss.oracle.com (moderated for non-subscribers) S: Supported F: net/rds/ READ-COPY UPDATE (RCU) P: Dipankar Sarma M: dipankar@in.ibm.com +P: Paul E. McKenney +M: paulmck@linux.vnet.ibm.com W: http://www.rdrop.com/users/paulmck/rclock/ -L: linux-kernel@vger.kernel.org S: Supported F: Documentation/RCU/rcu.txt F: Documentation/RCU/rcuref.txt @@ -4729,7 +4875,6 @@ F: kernel/rcupdate.c REAL TIME CLOCK DRIVER P: Paul Gortmaker M: p_gortmaker@yahoo.com -L: linux-kernel@vger.kernel.org S: Maintained F: Documentation/rtc.txt F: drivers/rtc/ @@ -4750,9 +4895,9 @@ S: Supported F: fs/reiserfs/ RFKILL -P: Ivo van Doorn -M: IvDoorn@gmail.com -L: netdev@vger.kernel.org +P: Johannes Berg +M: johannes@sipsolutions.net +L: linux-wireless@vger.kernel.org S: Maintained F Documentation/rfkill.txt F: net/rfkill/ @@ -4867,7 +5012,6 @@ S3C24XX SD/MMC Driver P: Ben Dooks M: ben-linux@fluff.org L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only) -L: linux-kernel@vger.kernel.org S: Supported F: drivers/mmc/host/s3cmci.* @@ -4893,7 +5037,6 @@ P: Ingo Molnar M: mingo@elte.hu P: Peter Zijlstra M: peterz@infradead.org -L: linux-kernel@vger.kernel.org S: Maintained F: kernel/sched* F: include/linux/sched.h @@ -4992,10 +5135,16 @@ L: sdhci-devel@lists.ossman.eu S: Maintained F: drivers/mmc/host/sdhci.* +SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) SAMSUNG DRIVER +P: Ben Dooks +M: ben-linux@fluff.org +L: sdhci-devel@lists.ossman.eu +S: Maintained +F: drivers/mmc/host/sdhci-s3c.c + SECURITY SUBSYSTEM P: James Morris M: jmorris@namei.org -L: linux-kernel@vger.kernel.org L: linux-security-module@vger.kernel.org (suggested Cc:) T: git git://www.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6.git W: http://security.wiki.kernel.org/ @@ -5014,7 +5163,6 @@ P: James Morris M: jmorris@namei.org P: Eric Paris M: eparis@parisplace.org -L: linux-kernel@vger.kernel.org (kernel issues) L: selinux@tycho.nsa.gov (subscribers-only, general discussion) W: http://selinuxproject.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6.git @@ -5111,7 +5259,6 @@ P: Vincent Sanders M: support@simtec.co.uk W: http://www.simtec.co.uk/products/EB110ATX/ S: Supported -F: arch/arm/mach-ebsa110/ SIMTEC EB2410ITX (BAST) P: Ben Dooks @@ -5278,7 +5425,6 @@ F: include/linux/sony-laptop.h SONY MEMORYSTICK CARD SUPPORT P: Alex Dubov M: oakad@yahoo.com -L: linux-kernel@vger.kernel.org W: http://tifmxx.berlios.de/ S: Maintained F: drivers/memstick/host/tifm_ms.c @@ -5288,7 +5434,7 @@ P: Jaroslav Kysela M: perex@perex.cz P: Takashi Iwai M: tiwai@suse.de -L: alsa-devel@alsa-project.org (subscribers-only) +L: alsa-devel@alsa-project.org (moderated for non-subscribers) W: http://www.alsa-project.org/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6.git T: git git://git.alsa-project.org/alsa-kernel.git @@ -5302,11 +5448,12 @@ P: Liam Girdwood M: lrg@slimlogic.co.uk P: Mark Brown M: broonie@opensource.wolfsonmicro.com -T: git git://opensource.wolfsonmicro.com/linux-2.6-asoc -L: alsa-devel@alsa-project.org (subscribers-only) +T: git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound-2.6.git +L: alsa-devel@alsa-project.org (moderated for non-subscribers) W: http://alsa-project.org/main/index.php/ASoC S: Supported F: sound/soc/ +F: include/sound/soc* SPARC + UltraSPARC (sparc/sparc64) P: David S. Miller @@ -5320,7 +5467,6 @@ F: arch/sparc/ SPECIALIX IO8+ MULTIPORT SERIAL CARD DRIVER P: Roger Wolff M: R.E.Wolff@BitWizard.nl -L: linux-kernel@vger.kernel.org S: Supported F: Documentation/serial/specialix.txt F: drivers/char/specialix* @@ -5366,7 +5512,6 @@ F: fs/squashfs/ SRM (Alpha) environment access P: Jan-Benedict Glaw M: jbglaw@lug-owl.de -L: linux-kernel@vger.kernel.org S: Maintained F: arch/alpha/kernel/srm_env.c @@ -5381,8 +5526,8 @@ S: Maintained STAGING SUBSYSTEM P: Greg Kroah-Hartman M: gregkh@suse.de -L: linux-kernel@vger.kernel.org T: quilt kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/ +L: devel@driverdev.osuosl.org S: Maintained F: drivers/staging/ @@ -5461,7 +5606,6 @@ F: include/linux/sysv_fs.h TASKSTATS STATISTICS INTERFACE P: Balbir Singh M: balbir@linux.vnet.ibm.com -L: linux-kernel@vger.kernel.org S: Maintained F: Documentation/accounting/taskstats* F: include/linux/taskstats* @@ -5524,20 +5668,6 @@ F: drivers/misc/tifm* F: drivers/mmc/host/tifm_sd.c F: include/linux/tifm.h -TI OMAP MMC INTERFACE DRIVER -P: Carlos Aguiar, Anderson Briglia and Syed Khasim -M: linux-omap@vger.kernel.org -W: http://linux.omap.com -W: http://www.muru.com/linux/omap/ -S: Maintained -F: drivers/mmc/host/omap.c - -TI OMAP RANDOM NUMBER GENERATOR SUPPORT -P: Deepak Saxena -M: dsaxena@plexity.net -S: Maintained -F: drivers/char/hw_random/omap-rng.c - TIPC NETWORK LAYER P: Per Liden M: per.liden@ericsson.com @@ -5568,7 +5698,6 @@ P: Kentaro Takeda M: takedakn@nttdata.co.jp P: Tetsuo Handa M: penguin-kernel@I-love.SAKURA.ne.jp -L: linux-kernel@vger.kernel.org (kernel issues) L: tomoyo-users-en@lists.sourceforge.jp (subscribers-only, for developers and users in English) L: tomoyo-dev@lists.sourceforge.jp (subscribers-only, for developers in Japanese) L: tomoyo-users@lists.sourceforge.jp (subscribers-only, for users in Japanese) @@ -5620,15 +5749,19 @@ F: drivers/char/tpm/ TRIVIAL PATCHES P: Jiri Kosina M: trivial@kernel.org -L: linux-kernel@vger.kernel.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/jikos/trivial.git S: Maintained +F: drivers/char/tty_* +F: drivers/serial/serial_core.c +F: include/linux/serial_core.h +F: include/linux/serial.h +F: include/linux/tty.h TTY LAYER P: Alan Cox M: alan@lxorguk.ukuu.org.uk -L: linux-kernel@vger.kernel.org S: Maintained +T: stgit http://zeniv.linux.org.uk/~alan/ttydev/ TULIP NETWORK DRIVERS P: Grant Grundler @@ -5699,7 +5832,6 @@ F: fs/udf/ UFS FILESYSTEM P: Evgeniy Dushistov M: dushistov@mail.ru -L: linux-kernel@vger.kernel.org S: Maintained F: Documentation/filesystems/ufs.txt F: fs/ufs/ @@ -5716,7 +5848,6 @@ F: include/linux/uwb/ UNIFORM CDROM DRIVER P: Jens Axboe M: axboe@kernel.dk -L: linux-kernel@vger.kernel.org W: http://www.kernel.dk S: Maintained F: Documentation/cdrom/ @@ -5745,7 +5876,6 @@ F: drivers/usb/class/cdc-acm.* USB BLOCK DRIVER (UB ub) P: Pete Zaitcev M: zaitcev@redhat.com -L: linux-kernel@vger.kernel.org L: linux-usb@vger.kernel.org S: Supported F: drivers/block/ub.c @@ -6038,6 +6168,12 @@ L: linux-wireless@vger.kernel.org S: Maintained F: drivers/net/wireless/rndis_wlan.c +USB XHCI DRIVER +P: Sarah Sharp +M: sarah.a.sharp@intel.com +L: linux-usb@vger.kernel.org +S: Supported + USB ZC0301 DRIVER P: Luca Risolia M: luca.risolia@studio.unibo.it @@ -6085,7 +6221,6 @@ P: Hans J. Koch M: hjk@linutronix.de P: Greg Kroah-Hartman M: gregkh@suse.de -L: linux-kernel@vger.kernel.org S: Maintained F: Documentation/DocBook/uio-howto.tmpl F: drivers/uio/ @@ -6111,7 +6246,6 @@ F: drivers/video/uvesafb.* VFAT/FAT/MSDOS FILESYSTEM P: OGAWA Hirofumi M: hirofumi@mail.parknet.co.jp -L: linux-kernel@vger.kernel.org S: Maintained F: Documentation/filesystems/vfat.txt F: fs/fat/ @@ -6130,6 +6264,14 @@ S: Maintained F: Documentation/i2c/busses/i2c-viapro F: drivers/i2c/busses/i2c-viapro.c +VIA SD/MMC CARD CONTROLLER DRIVER +P: Joseph Chan +M: JosephChan@via.com.tw +P: Harald Welte +M: HaraldWelte@viatech.com +S: Maintained +F: drivers/mmc/host/via-sdmmc.c + VIA UNICHROME(PRO)/CHROME9 FRAMEBUFFER DRIVER P: Joseph Chan M: JosephChan@via.com.tw @@ -6155,6 +6297,14 @@ F: drivers/net/macvlan.c F: include/linux/if_*vlan.h F: net/8021q/ +VLYNQ BUS +P: Florian Fainelli +M: florian@openwrt.org +L: openwrt-devel@lists.openwrt.org +S: Maintained +F: drivers/vlynq/vlynq.c +F: include/linux/vlynq.h + VOLTAGE AND CURRENT REGULATOR FRAMEWORK P: Liam Girdwood M: lrg@slimlogic.co.uk @@ -6208,7 +6358,6 @@ F: drivers/hwmon/w83793.c W83L51xD SD/MMC CARD INTERFACE DRIVER P: Pierre Ossman M: pierre@ossman.eu -L: linux-kernel@vger.kernel.org S: Maintained F: drivers/mmc/host/wbsd.* @@ -6295,7 +6444,6 @@ M: mingo@redhat.com P: H. Peter Anvin M: hpa@zytor.com M: x86@kernel.org -L: linux-kernel@vger.kernel.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86.git S: Maintained F: Documentation/x86/ @@ -6331,7 +6479,6 @@ XILINX SYSTEMACE DRIVER P: Grant Likely M: grant.likely@secretlab.ca W: http://www.secretlab.ca/ -L: linux-kernel@vger.kernel.org S: Maintained F: drivers/block/xsysace.c @@ -6396,5 +6543,9 @@ F: drivers/serial/zs.* THE REST P: Linus Torvalds +M: torvalds@linux-foundation.org +L: linux-kernel@vger.kernel.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git S: Buried alive in reporters +F: * +F: */ diff --git a/Makefile b/Makefile index 03373bb703ca..d1216fea0c92 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 -SUBLEVEL = 30 -EXTRAVERSION = +SUBLEVEL = 31 +EXTRAVERSION = -rc1 NAME = Man-Eating Seals of Antiquity # *DOCUMENTATION* @@ -35,10 +35,8 @@ MAKEFLAGS += -rR --no-print-directory # To put more focus on warnings, be less verbose as default # Use 'make V=1' to see the full commands -ifdef V - ifeq ("$(origin V)", "command line") - KBUILD_VERBOSE = $(V) - endif +ifeq ("$(origin V)", "command line") + KBUILD_VERBOSE = $(V) endif ifndef KBUILD_VERBOSE KBUILD_VERBOSE = 0 @@ -54,10 +52,8 @@ endif # See the file "Documentation/sparse.txt" for more details, including # where to get the "sparse" utility. -ifdef C - ifeq ("$(origin C)", "command line") - KBUILD_CHECKSRC = $(C) - endif +ifeq ("$(origin C)", "command line") + KBUILD_CHECKSRC = $(C) endif ifndef KBUILD_CHECKSRC KBUILD_CHECKSRC = 0 @@ -69,12 +65,10 @@ endif ifdef SUBDIRS KBUILD_EXTMOD ?= $(SUBDIRS) endif -ifdef M - ifeq ("$(origin M)", "command line") - KBUILD_EXTMOD := $(M) - endif -endif +ifeq ("$(origin M)", "command line") + KBUILD_EXTMOD := $(M) +endif # kbuild supports saving output files in a separate directory. # To locate output files in a separate directory two syntaxes are supported. @@ -98,10 +92,8 @@ ifeq ($(KBUILD_SRC),) # OK, Make called in directory where kernel src resides # Do we want to locate output files in a separate directory? -ifdef O - ifeq ("$(origin O)", "command line") - KBUILD_OUTPUT := $(O) - endif +ifeq ("$(origin O)", "command line") + KBUILD_OUTPUT := $(O) endif # That's our default target when none is given on the command line @@ -338,6 +330,7 @@ AFLAGS_MODULE = $(MODFLAGS) LDFLAGS_MODULE = CFLAGS_KERNEL = AFLAGS_KERNEL = +CFLAGS_GCOV = -fprofile-arcs -ftest-coverage # Use LINUXINCLUDE when you must reference the include/ directory. @@ -364,7 +357,7 @@ export CPP AR NM STRIP OBJCOPY OBJDUMP MAKE AWK GENKSYMS PERL UTS_MACHINE export HOSTCXX HOSTCXXFLAGS LDFLAGS_MODULE CHECK CHECKFLAGS export KBUILD_CPPFLAGS NOSTDINC_FLAGS LINUXINCLUDE OBJCOPYFLAGS LDFLAGS -export KBUILD_CFLAGS CFLAGS_KERNEL CFLAGS_MODULE +export KBUILD_CFLAGS CFLAGS_KERNEL CFLAGS_MODULE CFLAGS_GCOV export KBUILD_AFLAGS AFLAGS_KERNEL AFLAGS_MODULE # When compiling out-of-tree modules, put MODVERDIR in the module @@ -1224,8 +1217,8 @@ clean: archclean $(clean-dirs) \( -name '*.[oas]' -o -name '*.ko' -o -name '.*.cmd' \ -o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \ -o -name '*.symtypes' -o -name 'modules.order' \ - -o -name 'Module.markers' -o -name '.tmp_*.o.*' \) \ - -type f -print | xargs rm -f + -o -name 'Module.markers' -o -name '.tmp_*.o.*' \ + -o -name '*.gcno' \) -type f -print | xargs rm -f # mrproper - Delete all generated files, including .config # @@ -1429,8 +1422,8 @@ clean: $(clean-dirs) $(call cmd,rmfiles) @find $(KBUILD_EXTMOD) $(RCS_FIND_IGNORE) \ \( -name '*.[oas]' -o -name '*.ko' -o -name '.*.cmd' \ - -o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \) \ - -type f -print | xargs rm -f + -o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \ + -o -name '*.gcno' \) -type f -print | xargs rm -f help: @echo ' Building external modules.' diff --git a/README b/README index d6c6c742c1d7..737838fe73cc 100644 --- a/README +++ b/README @@ -174,8 +174,17 @@ CONFIGURING the kernel: "make silentoldconfig" Like above, but avoids cluttering the screen with questions already answered. + Additionally updates the dependencies. "make defconfig" Create a ./.config file by using the default - symbol values from arch/$ARCH/defconfig. + symbol values from either arch/$ARCH/defconfig + or arch/$ARCH/configs/${PLATFORM}_defconfig, + depending on the architecture. + "make ${PLATFORM}_defconfig" + Create a ./.config file by using the default + symbol values from + arch/$ARCH/configs/${PLATFORM}_defconfig. + Use "make help" to get a list of all available + platforms of your architecture. "make allyesconfig" Create a ./.config file by setting symbol values to 'y' as much as possible. diff --git a/arch/Kconfig b/arch/Kconfig index 78a35e9dc104..99193b160232 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -112,3 +112,5 @@ config HAVE_DMA_API_DEBUG config HAVE_DEFAULT_NO_SPIN_MUTEXES bool + +source "kernel/gcov/Kconfig" diff --git a/arch/alpha/include/asm/8253pit.h b/arch/alpha/include/asm/8253pit.h index fef5c1450e47..a71c9c1455a7 100644 --- a/arch/alpha/include/asm/8253pit.h +++ b/arch/alpha/include/asm/8253pit.h @@ -1,10 +1,3 @@ /* * 8253/8254 Programmable Interval Timer */ - -#ifndef _8253PIT_H -#define _8253PIT_H - -#define PIT_TICK_RATE 1193180UL - -#endif diff --git a/arch/alpha/include/asm/atomic.h b/arch/alpha/include/asm/atomic.h index 62b363584b2b..610dff44d94b 100644 --- a/arch/alpha/include/asm/atomic.h +++ b/arch/alpha/include/asm/atomic.h @@ -256,5 +256,5 @@ static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u) #define smp_mb__before_atomic_inc() smp_mb() #define smp_mb__after_atomic_inc() smp_mb() -#include +#include #endif /* _ALPHA_ATOMIC_H */ diff --git a/arch/alpha/include/asm/bitsperlong.h b/arch/alpha/include/asm/bitsperlong.h new file mode 100644 index 000000000000..ad57f7868203 --- /dev/null +++ b/arch/alpha/include/asm/bitsperlong.h @@ -0,0 +1,8 @@ +#ifndef __ASM_ALPHA_BITSPERLONG_H +#define __ASM_ALPHA_BITSPERLONG_H + +#define __BITS_PER_LONG 64 + +#include + +#endif /* __ASM_ALPHA_BITSPERLONG_H */ diff --git a/arch/alpha/include/asm/errno.h b/arch/alpha/include/asm/errno.h index 69e2655249d2..98099bda9370 100644 --- a/arch/alpha/include/asm/errno.h +++ b/arch/alpha/include/asm/errno.h @@ -120,4 +120,6 @@ #define EOWNERDEAD 136 /* Owner died */ #define ENOTRECOVERABLE 137 /* State not recoverable */ +#define ERFKILL 138 /* Operation not possible due to RF-kill */ + #endif diff --git a/arch/alpha/include/asm/kmap_types.h b/arch/alpha/include/asm/kmap_types.h index 3e6735a34c57..a8d4ec8ea4b6 100644 --- a/arch/alpha/include/asm/kmap_types.h +++ b/arch/alpha/include/asm/kmap_types.h @@ -3,30 +3,12 @@ /* Dummy header just to define km_type. */ - #ifdef CONFIG_DEBUG_HIGHMEM -# define D(n) __KM_FENCE_##n , -#else -# define D(n) +#define __WITH_KM_FENCE #endif -enum km_type { -D(0) KM_BOUNCE_READ, -D(1) KM_SKB_SUNRPC_DATA, -D(2) KM_SKB_DATA_SOFTIRQ, -D(3) KM_USER0, -D(4) KM_USER1, -D(5) KM_BIO_SRC_IRQ, -D(6) KM_BIO_DST_IRQ, -D(7) KM_PTE0, -D(8) KM_PTE1, -D(9) KM_IRQ0, -D(10) KM_IRQ1, -D(11) KM_SOFTIRQ0, -D(12) KM_SOFTIRQ1, -D(13) KM_TYPE_NR -}; +#include -#undef D +#undef __WITH_KM_FENCE #endif diff --git a/arch/alpha/include/asm/page.h b/arch/alpha/include/asm/page.h index 0995f9d13417..07af062544fb 100644 --- a/arch/alpha/include/asm/page.h +++ b/arch/alpha/include/asm/page.h @@ -93,6 +93,6 @@ typedef struct page *pgtable_t; VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) #include -#include +#include #endif /* _ALPHA_PAGE_H */ diff --git a/arch/alpha/include/asm/pci.h b/arch/alpha/include/asm/pci.h index cb04eaa6ba33..d22ace99d13d 100644 --- a/arch/alpha/include/asm/pci.h +++ b/arch/alpha/include/asm/pci.h @@ -237,19 +237,6 @@ extern void pcibios_resource_to_bus(struct pci_dev *, struct pci_bus_region *, extern void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res, struct pci_bus_region *region); -static inline struct resource * -pcibios_select_root(struct pci_dev *pdev, struct resource *res) -{ - struct resource *root = NULL; - - if (res->flags & IORESOURCE_IO) - root = &ioport_resource; - if (res->flags & IORESOURCE_MEM) - root = &iomem_resource; - - return root; -} - #define pci_domain_nr(bus) ((struct pci_controller *)(bus)->sysdata)->index static inline int pci_proc_domain(struct pci_bus *bus) diff --git a/arch/alpha/include/asm/signal.h b/arch/alpha/include/asm/signal.h index 13c2305d35ef..a9388300abb1 100644 --- a/arch/alpha/include/asm/signal.h +++ b/arch/alpha/include/asm/signal.h @@ -111,7 +111,7 @@ typedef unsigned long sigset_t; #define SIG_UNBLOCK 2 /* for unblocking signals */ #define SIG_SETMASK 3 /* for setting the signal mask */ -#include +#include #ifdef __KERNEL__ struct osf_sigaction { diff --git a/arch/alpha/include/asm/suspend.h b/arch/alpha/include/asm/suspend.h deleted file mode 100644 index c7042d575851..000000000000 --- a/arch/alpha/include/asm/suspend.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef __ALPHA_SUSPEND_H -#define __ALPHA_SUSPEND_H - -/* Dummy include. */ - -#endif /* __ALPHA_SUSPEND_H */ diff --git a/arch/alpha/include/asm/types.h b/arch/alpha/include/asm/types.h index f072f344497e..bd621ecd1eb3 100644 --- a/arch/alpha/include/asm/types.h +++ b/arch/alpha/include/asm/types.h @@ -25,9 +25,6 @@ typedef unsigned int umode_t; * These aren't exported outside the kernel to avoid name space clashes */ #ifdef __KERNEL__ - -#define BITS_PER_LONG 64 - #ifndef __ASSEMBLY__ typedef u64 dma_addr_t; diff --git a/arch/alpha/kernel/init_task.c b/arch/alpha/kernel/init_task.c index c2938e574a40..19b86328ffd7 100644 --- a/arch/alpha/kernel/init_task.c +++ b/arch/alpha/kernel/init_task.c @@ -10,10 +10,7 @@ static struct signal_struct init_signals = INIT_SIGNALS(init_signals); static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); -struct mm_struct init_mm = INIT_MM(init_mm); struct task_struct init_task = INIT_TASK(init_task); - -EXPORT_SYMBOL(init_mm); EXPORT_SYMBOL(init_task); union thread_union init_thread_union diff --git a/arch/alpha/kernel/irq_alpha.c b/arch/alpha/kernel/irq_alpha.c index 67c19f8a9944..38c805dfc544 100644 --- a/arch/alpha/kernel/irq_alpha.c +++ b/arch/alpha/kernel/irq_alpha.c @@ -227,7 +227,7 @@ struct irqaction timer_irqaction = { .name = "timer", }; -static struct hw_interrupt_type rtc_irq_type = { +static struct irq_chip rtc_irq_type = { .typename = "RTC", .startup = rtc_startup, .shutdown = rtc_enable_disable, diff --git a/arch/alpha/kernel/irq_i8259.c b/arch/alpha/kernel/irq_i8259.c index 9405bee9894e..50bfec9b588f 100644 --- a/arch/alpha/kernel/irq_i8259.c +++ b/arch/alpha/kernel/irq_i8259.c @@ -83,7 +83,7 @@ i8259a_end_irq(unsigned int irq) i8259a_enable_irq(irq); } -struct hw_interrupt_type i8259a_irq_type = { +struct irq_chip i8259a_irq_type = { .typename = "XT-PIC", .startup = i8259a_startup_irq, .shutdown = i8259a_disable_irq, diff --git a/arch/alpha/kernel/irq_impl.h b/arch/alpha/kernel/irq_impl.h index cc9a8a7aa279..b63ccd7386f1 100644 --- a/arch/alpha/kernel/irq_impl.h +++ b/arch/alpha/kernel/irq_impl.h @@ -36,7 +36,7 @@ extern void i8259a_disable_irq(unsigned int); extern void i8259a_mask_and_ack_irq(unsigned int); extern unsigned int i8259a_startup_irq(unsigned int); extern void i8259a_end_irq(unsigned int); -extern struct hw_interrupt_type i8259a_irq_type; +extern struct irq_chip i8259a_irq_type; extern void init_i8259a_irqs(void); extern void handle_irq(int irq); diff --git a/arch/alpha/kernel/irq_pyxis.c b/arch/alpha/kernel/irq_pyxis.c index d53edbccbfe5..69199a76ec4a 100644 --- a/arch/alpha/kernel/irq_pyxis.c +++ b/arch/alpha/kernel/irq_pyxis.c @@ -70,7 +70,7 @@ pyxis_mask_and_ack_irq(unsigned int irq) *(vulp)PYXIS_INT_MASK; } -static struct hw_interrupt_type pyxis_irq_type = { +static struct irq_chip pyxis_irq_type = { .typename = "PYXIS", .startup = pyxis_startup_irq, .shutdown = pyxis_disable_irq, diff --git a/arch/alpha/kernel/irq_srm.c b/arch/alpha/kernel/irq_srm.c index a03fbca4940e..85229369a1f8 100644 --- a/arch/alpha/kernel/irq_srm.c +++ b/arch/alpha/kernel/irq_srm.c @@ -48,7 +48,7 @@ srm_end_irq(unsigned int irq) } /* Handle interrupts from the SRM, assuming no additional weirdness. */ -static struct hw_interrupt_type srm_irq_type = { +static struct irq_chip srm_irq_type = { .typename = "SRM", .startup = srm_startup_irq, .shutdown = srm_disable_irq, diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c index 42ee05981e71..9a3334ae282e 100644 --- a/arch/alpha/kernel/osf_sys.c +++ b/arch/alpha/kernel/osf_sys.c @@ -371,8 +371,6 @@ SYSCALL_DEFINE4(osf_mount, unsigned long, typenr, char __user *, path, int retval = -EINVAL; char *name; - lock_kernel(); - name = getname(path); retval = PTR_ERR(name); if (IS_ERR(name)) @@ -392,7 +390,6 @@ SYSCALL_DEFINE4(osf_mount, unsigned long, typenr, char __user *, path, } putname(name); out: - unlock_kernel(); return retval; } diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c index 80df86cd746b..d2634e4476b4 100644 --- a/arch/alpha/kernel/setup.c +++ b/arch/alpha/kernel/setup.c @@ -252,9 +252,9 @@ reserve_std_resources(void) } #define PFN_MAX PFN_DOWN(0x80000000) -#define for_each_mem_cluster(memdesc, cluster, i) \ - for ((cluster) = (memdesc)->cluster, (i) = 0; \ - (i) < (memdesc)->numclusters; (i)++, (cluster)++) +#define for_each_mem_cluster(memdesc, _cluster, i) \ + for ((_cluster) = (memdesc)->cluster, (i) = 0; \ + (i) < (memdesc)->numclusters; (i)++, (_cluster)++) static unsigned long __init get_mem_size_limit(char *s) diff --git a/arch/alpha/kernel/sys_alcor.c b/arch/alpha/kernel/sys_alcor.c index e53a1e1c2f21..382035ef7394 100644 --- a/arch/alpha/kernel/sys_alcor.c +++ b/arch/alpha/kernel/sys_alcor.c @@ -89,7 +89,7 @@ alcor_end_irq(unsigned int irq) alcor_enable_irq(irq); } -static struct hw_interrupt_type alcor_irq_type = { +static struct irq_chip alcor_irq_type = { .typename = "ALCOR", .startup = alcor_startup_irq, .shutdown = alcor_disable_irq, diff --git a/arch/alpha/kernel/sys_cabriolet.c b/arch/alpha/kernel/sys_cabriolet.c index ace475c124f6..ed349436732b 100644 --- a/arch/alpha/kernel/sys_cabriolet.c +++ b/arch/alpha/kernel/sys_cabriolet.c @@ -71,7 +71,7 @@ cabriolet_end_irq(unsigned int irq) cabriolet_enable_irq(irq); } -static struct hw_interrupt_type cabriolet_irq_type = { +static struct irq_chip cabriolet_irq_type = { .typename = "CABRIOLET", .startup = cabriolet_startup_irq, .shutdown = cabriolet_disable_irq, diff --git a/arch/alpha/kernel/sys_dp264.c b/arch/alpha/kernel/sys_dp264.c index 9c9d1fd4155f..46e70ece5176 100644 --- a/arch/alpha/kernel/sys_dp264.c +++ b/arch/alpha/kernel/sys_dp264.c @@ -176,25 +176,29 @@ cpu_set_irq_affinity(unsigned int irq, cpumask_t affinity) } } -static void +static int dp264_set_affinity(unsigned int irq, const struct cpumask *affinity) { spin_lock(&dp264_irq_lock); cpu_set_irq_affinity(irq, *affinity); tsunami_update_irq_hw(cached_irq_mask); spin_unlock(&dp264_irq_lock); + + return 0; } -static void +static int clipper_set_affinity(unsigned int irq, const struct cpumask *affinity) { spin_lock(&dp264_irq_lock); cpu_set_irq_affinity(irq - 16, *affinity); tsunami_update_irq_hw(cached_irq_mask); spin_unlock(&dp264_irq_lock); + + return 0; } -static struct hw_interrupt_type dp264_irq_type = { +static struct irq_chip dp264_irq_type = { .typename = "DP264", .startup = dp264_startup_irq, .shutdown = dp264_disable_irq, @@ -205,7 +209,7 @@ static struct hw_interrupt_type dp264_irq_type = { .set_affinity = dp264_set_affinity, }; -static struct hw_interrupt_type clipper_irq_type = { +static struct irq_chip clipper_irq_type = { .typename = "CLIPPER", .startup = clipper_startup_irq, .shutdown = clipper_disable_irq, @@ -294,7 +298,7 @@ clipper_srm_device_interrupt(unsigned long vector) } static void __init -init_tsunami_irqs(struct hw_interrupt_type * ops, int imin, int imax) +init_tsunami_irqs(struct irq_chip * ops, int imin, int imax) { long i; for (i = imin; i <= imax; ++i) { diff --git a/arch/alpha/kernel/sys_eb64p.c b/arch/alpha/kernel/sys_eb64p.c index 9c5a306dc0ee..660c23ef661f 100644 --- a/arch/alpha/kernel/sys_eb64p.c +++ b/arch/alpha/kernel/sys_eb64p.c @@ -69,7 +69,7 @@ eb64p_end_irq(unsigned int irq) eb64p_enable_irq(irq); } -static struct hw_interrupt_type eb64p_irq_type = { +static struct irq_chip eb64p_irq_type = { .typename = "EB64P", .startup = eb64p_startup_irq, .shutdown = eb64p_disable_irq, diff --git a/arch/alpha/kernel/sys_eiger.c b/arch/alpha/kernel/sys_eiger.c index baf60f36cbd7..b99ea488d844 100644 --- a/arch/alpha/kernel/sys_eiger.c +++ b/arch/alpha/kernel/sys_eiger.c @@ -80,7 +80,7 @@ eiger_end_irq(unsigned int irq) eiger_enable_irq(irq); } -static struct hw_interrupt_type eiger_irq_type = { +static struct irq_chip eiger_irq_type = { .typename = "EIGER", .startup = eiger_startup_irq, .shutdown = eiger_disable_irq, diff --git a/arch/alpha/kernel/sys_jensen.c b/arch/alpha/kernel/sys_jensen.c index 2b5caf3d9b15..ef0b83a070ac 100644 --- a/arch/alpha/kernel/sys_jensen.c +++ b/arch/alpha/kernel/sys_jensen.c @@ -118,7 +118,7 @@ jensen_local_end(unsigned int irq) i8259a_end_irq(1); } -static struct hw_interrupt_type jensen_local_irq_type = { +static struct irq_chip jensen_local_irq_type = { .typename = "LOCAL", .startup = jensen_local_startup, .shutdown = jensen_local_shutdown, diff --git a/arch/alpha/kernel/sys_marvel.c b/arch/alpha/kernel/sys_marvel.c index c5a1a2438c67..bbfc4f20ca72 100644 --- a/arch/alpha/kernel/sys_marvel.c +++ b/arch/alpha/kernel/sys_marvel.c @@ -169,7 +169,7 @@ marvel_irq_noop_return(unsigned int irq) return 0; } -static struct hw_interrupt_type marvel_legacy_irq_type = { +static struct irq_chip marvel_legacy_irq_type = { .typename = "LEGACY", .startup = marvel_irq_noop_return, .shutdown = marvel_irq_noop, @@ -179,7 +179,7 @@ static struct hw_interrupt_type marvel_legacy_irq_type = { .end = marvel_irq_noop, }; -static struct hw_interrupt_type io7_lsi_irq_type = { +static struct irq_chip io7_lsi_irq_type = { .typename = "LSI", .startup = io7_startup_irq, .shutdown = io7_disable_irq, @@ -189,7 +189,7 @@ static struct hw_interrupt_type io7_lsi_irq_type = { .end = io7_end_irq, }; -static struct hw_interrupt_type io7_msi_irq_type = { +static struct irq_chip io7_msi_irq_type = { .typename = "MSI", .startup = io7_startup_irq, .shutdown = io7_disable_irq, @@ -273,8 +273,8 @@ init_one_io7_msi(struct io7 *io7, unsigned int which, unsigned int where) static void __init init_io7_irqs(struct io7 *io7, - struct hw_interrupt_type *lsi_ops, - struct hw_interrupt_type *msi_ops) + struct irq_chip *lsi_ops, + struct irq_chip *msi_ops) { long base = (io7->pe << MARVEL_IRQ_VEC_PE_SHIFT) + 16; long i; diff --git a/arch/alpha/kernel/sys_mikasa.c b/arch/alpha/kernel/sys_mikasa.c index 8d3e9429c5ee..4e366641a08e 100644 --- a/arch/alpha/kernel/sys_mikasa.c +++ b/arch/alpha/kernel/sys_mikasa.c @@ -68,7 +68,7 @@ mikasa_end_irq(unsigned int irq) mikasa_enable_irq(irq); } -static struct hw_interrupt_type mikasa_irq_type = { +static struct irq_chip mikasa_irq_type = { .typename = "MIKASA", .startup = mikasa_startup_irq, .shutdown = mikasa_disable_irq, diff --git a/arch/alpha/kernel/sys_noritake.c b/arch/alpha/kernel/sys_noritake.c index 538876b62449..35753a173bac 100644 --- a/arch/alpha/kernel/sys_noritake.c +++ b/arch/alpha/kernel/sys_noritake.c @@ -73,7 +73,7 @@ noritake_end_irq(unsigned int irq) noritake_enable_irq(irq); } -static struct hw_interrupt_type noritake_irq_type = { +static struct irq_chip noritake_irq_type = { .typename = "NORITAKE", .startup = noritake_startup_irq, .shutdown = noritake_disable_irq, diff --git a/arch/alpha/kernel/sys_rawhide.c b/arch/alpha/kernel/sys_rawhide.c index 672cb2df53df..f3aec7e085c8 100644 --- a/arch/alpha/kernel/sys_rawhide.c +++ b/arch/alpha/kernel/sys_rawhide.c @@ -135,7 +135,7 @@ rawhide_end_irq(unsigned int irq) rawhide_enable_irq(irq); } -static struct hw_interrupt_type rawhide_irq_type = { +static struct irq_chip rawhide_irq_type = { .typename = "RAWHIDE", .startup = rawhide_startup_irq, .shutdown = rawhide_disable_irq, diff --git a/arch/alpha/kernel/sys_ruffian.c b/arch/alpha/kernel/sys_ruffian.c index f15a329b6011..d9f9cfeb9931 100644 --- a/arch/alpha/kernel/sys_ruffian.c +++ b/arch/alpha/kernel/sys_ruffian.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include diff --git a/arch/alpha/kernel/sys_rx164.c b/arch/alpha/kernel/sys_rx164.c index ce1faa6f1df1..fc9246373452 100644 --- a/arch/alpha/kernel/sys_rx164.c +++ b/arch/alpha/kernel/sys_rx164.c @@ -72,7 +72,7 @@ rx164_end_irq(unsigned int irq) rx164_enable_irq(irq); } -static struct hw_interrupt_type rx164_irq_type = { +static struct irq_chip rx164_irq_type = { .typename = "RX164", .startup = rx164_startup_irq, .shutdown = rx164_disable_irq, diff --git a/arch/alpha/kernel/sys_sable.c b/arch/alpha/kernel/sys_sable.c index 9e263256a42d..426eb6906d01 100644 --- a/arch/alpha/kernel/sys_sable.c +++ b/arch/alpha/kernel/sys_sable.c @@ -501,7 +501,7 @@ sable_lynx_mask_and_ack_irq(unsigned int irq) spin_unlock(&sable_lynx_irq_lock); } -static struct hw_interrupt_type sable_lynx_irq_type = { +static struct irq_chip sable_lynx_irq_type = { .typename = "SABLE/LYNX", .startup = sable_lynx_startup_irq, .shutdown = sable_lynx_disable_irq, diff --git a/arch/alpha/kernel/sys_takara.c b/arch/alpha/kernel/sys_takara.c index 9bd9a31450c6..830318c21661 100644 --- a/arch/alpha/kernel/sys_takara.c +++ b/arch/alpha/kernel/sys_takara.c @@ -74,7 +74,7 @@ takara_end_irq(unsigned int irq) takara_enable_irq(irq); } -static struct hw_interrupt_type takara_irq_type = { +static struct irq_chip takara_irq_type = { .typename = "TAKARA", .startup = takara_startup_irq, .shutdown = takara_disable_irq, diff --git a/arch/alpha/kernel/sys_titan.c b/arch/alpha/kernel/sys_titan.c index 27f840a4ad3d..88978fc60f83 100644 --- a/arch/alpha/kernel/sys_titan.c +++ b/arch/alpha/kernel/sys_titan.c @@ -157,13 +157,15 @@ titan_cpu_set_irq_affinity(unsigned int irq, cpumask_t affinity) } -static void +static int titan_set_irq_affinity(unsigned int irq, const struct cpumask *affinity) { spin_lock(&titan_irq_lock); titan_cpu_set_irq_affinity(irq - 16, *affinity); titan_update_irq_hw(titan_cached_irq_mask); spin_unlock(&titan_irq_lock); + + return 0; } static void @@ -183,7 +185,7 @@ titan_srm_device_interrupt(unsigned long vector) static void __init -init_titan_irqs(struct hw_interrupt_type * ops, int imin, int imax) +init_titan_irqs(struct irq_chip * ops, int imin, int imax) { long i; for (i = imin; i <= imax; ++i) { @@ -192,7 +194,7 @@ init_titan_irqs(struct hw_interrupt_type * ops, int imin, int imax) } } -static struct hw_interrupt_type titan_irq_type = { +static struct irq_chip titan_irq_type = { .typename = "TITAN", .startup = titan_startup_irq, .shutdown = titan_disable_irq, diff --git a/arch/alpha/kernel/sys_wildfire.c b/arch/alpha/kernel/sys_wildfire.c index 42c3eede4d09..e91b4c3838a8 100644 --- a/arch/alpha/kernel/sys_wildfire.c +++ b/arch/alpha/kernel/sys_wildfire.c @@ -157,7 +157,7 @@ wildfire_end_irq(unsigned int irq) wildfire_enable_irq(irq); } -static struct hw_interrupt_type wildfire_irq_type = { +static struct irq_chip wildfire_irq_type = { .typename = "WILDFIRE", .startup = wildfire_startup_irq, .shutdown = wildfire_disable_irq, diff --git a/arch/alpha/mm/extable.c b/arch/alpha/mm/extable.c index 62dc379d301a..813c9b63c0e1 100644 --- a/arch/alpha/mm/extable.c +++ b/arch/alpha/mm/extable.c @@ -48,6 +48,27 @@ void sort_extable(struct exception_table_entry *start, cmp_ex, swap_ex); } +#ifdef CONFIG_MODULES +/* + * Any entry referring to the module init will be at the beginning or + * the end. + */ +void trim_init_extable(struct module *m) +{ + /*trim the beginning*/ + while (m->num_exentries && + within_module_init(ex_to_addr(&m->extable[0]), m)) { + m->extable++; + m->num_exentries--; + } + /*trim the end*/ + while (m->num_exentries && + within_module_init(ex_to_addr(&m->extable[m->num_exentries-1]), + m)) + m->num_exentries--; +} +#endif /* CONFIG_MODULES */ + const struct exception_table_entry * search_extable(const struct exception_table_entry *first, const struct exception_table_entry *last, diff --git a/arch/alpha/mm/fault.c b/arch/alpha/mm/fault.c index 4829f96585b1..00a31deaa96e 100644 --- a/arch/alpha/mm/fault.c +++ b/arch/alpha/mm/fault.c @@ -146,7 +146,7 @@ do_page_fault(unsigned long address, unsigned long mmcsr, /* If for any reason at all we couldn't handle the fault, make sure we exit gracefully rather than endlessly redo the fault. */ - fault = handle_mm_fault(mm, vma, address, cause > 0); + fault = handle_mm_fault(mm, vma, address, cause > 0 ? FAULT_FLAG_WRITE : 0); up_read(&mm->mmap_sem); if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) diff --git a/arch/alpha/mm/numa.c b/arch/alpha/mm/numa.c index a13de49d1265..0eab55749423 100644 --- a/arch/alpha/mm/numa.c +++ b/arch/alpha/mm/numa.c @@ -28,9 +28,9 @@ EXPORT_SYMBOL(node_data); #define DBGDCONT(args...) #endif -#define for_each_mem_cluster(memdesc, cluster, i) \ - for ((cluster) = (memdesc)->cluster, (i) = 0; \ - (i) < (memdesc)->numclusters; (i)++, (cluster)++) +#define for_each_mem_cluster(memdesc, _cluster, i) \ + for ((_cluster) = (memdesc)->cluster, (i) = 0; \ + (i) < (memdesc)->numclusters; (i)++, (_cluster)++) static void __init show_mem_layout(void) { diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 9d02cdb15b23..aef63c8e3d2d 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -34,15 +34,12 @@ config SYS_SUPPORTS_APM_EMULATION config GENERIC_GPIO bool - default n config GENERIC_TIME bool - default n config GENERIC_CLOCKEVENTS bool - default n config GENERIC_CLOCKEVENTS_BROADCAST bool @@ -55,7 +52,6 @@ config MMU config NO_IOPORT bool - default n config EISA bool @@ -126,11 +122,9 @@ config RWSEM_XCHGADD_ALGORITHM config ARCH_HAS_ILOG2_U32 bool - default n config ARCH_HAS_ILOG2_U64 bool - default n config GENERIC_HWEIGHT bool @@ -253,6 +247,14 @@ config ARCH_CLPS711X help Support for Cirrus Logic 711x/721x based boards. +config ARCH_GEMINI + bool "Cortina Systems Gemini" + select CPU_FA526 + select GENERIC_GPIO + select ARCH_REQUIRE_GPIOLIB + help + Support for the Cortina Systems Gemini family SoCs + config ARCH_EBSA110 bool "EBSA-110" select CPU_SA110 @@ -277,14 +279,6 @@ config ARCH_EP93XX help This enables support for the Cirrus EP93xx series of CPUs. -config ARCH_GEMINI - bool "Cortina Systems Gemini" - select CPU_FA526 - select GENERIC_GPIO - select ARCH_REQUIRE_GPIOLIB - help - Support for the Cortina Systems Gemini family SoCs - config ARCH_FOOTBRIDGE bool "FootBridge" select CPU_SA110 @@ -293,6 +287,30 @@ config ARCH_FOOTBRIDGE Support for systems based on the DC21285 companion chip ("FootBridge"), such as the Simtec CATS and the Rebel NetWinder. +config ARCH_MXC + bool "Freescale MXC/iMX-based" + select GENERIC_TIME + select GENERIC_CLOCKEVENTS + select ARCH_MTD_XIP + select GENERIC_GPIO + select ARCH_REQUIRE_GPIOLIB + select HAVE_CLK + help + Support for Freescale MXC/iMX-based family of processors + +config ARCH_STMP3XXX + bool "Freescale STMP3xxx" + select CPU_ARM926T + select HAVE_CLK + select COMMON_CLKDEV + select ARCH_REQUIRE_GPIOLIB + select GENERIC_TIME + select GENERIC_CLOCKEVENTS + select GENERIC_GPIO + select USB_ARCH_HAS_EHCI + help + Support for systems based on the Freescale 3xxx CPUs. + config ARCH_NETX bool "Hilscher NetX based" select CPU_ARM926T @@ -309,15 +327,6 @@ config ARCH_H720X help This enables support for systems based on the Hynix HMS720x -config ARCH_IMX - bool "IMX" - select CPU_ARM920T - select GENERIC_GPIO - select GENERIC_TIME - select GENERIC_CLOCKEVENTS - help - Support for Motorola's i.MX family of processors (MX1, MXL). - config ARCH_IOP13XX bool "IOP13xx-based" depends on MMU @@ -398,6 +407,7 @@ config ARCH_KIRKWOOD select CPU_FEROCEON select PCI select GENERIC_GPIO + select ARCH_REQUIRE_GPIOLIB select GENERIC_TIME select GENERIC_CLOCKEVENTS select PLAT_ORION @@ -405,6 +415,57 @@ config ARCH_KIRKWOOD Support for the following Marvell Kirkwood series SoCs: 88F6180, 88F6192 and 88F6281. +config ARCH_LOKI + bool "Marvell Loki (88RC8480)" + select CPU_FEROCEON + select GENERIC_TIME + select GENERIC_CLOCKEVENTS + select PLAT_ORION + help + Support for the Marvell Loki (88RC8480) SoC. + +config ARCH_MV78XX0 + bool "Marvell MV78xx0" + select CPU_FEROCEON + select PCI + select GENERIC_GPIO + select ARCH_REQUIRE_GPIOLIB + select GENERIC_TIME + select GENERIC_CLOCKEVENTS + select PLAT_ORION + help + Support for the following Marvell MV78xx0 series SoCs: + MV781x0, MV782x0. + +config ARCH_ORION5X + bool "Marvell Orion" + depends on MMU + select CPU_FEROCEON + select PCI + select GENERIC_GPIO + select ARCH_REQUIRE_GPIOLIB + select GENERIC_TIME + select GENERIC_CLOCKEVENTS + select PLAT_ORION + help + Support for the following Marvell Orion 5x series SoCs: + Orion-1 (5181), Orion-VoIP (5181L), Orion-NAS (5182), + Orion-2 (5281), Orion-1-90 (6183). + +config ARCH_MMP + bool "Marvell PXA168/910" + depends on MMU + select GENERIC_GPIO + select ARCH_REQUIRE_GPIOLIB + select HAVE_CLK + select COMMON_CLKDEV + select GENERIC_TIME + select GENERIC_CLOCKEVENTS + select TICK_ONESHOT + select PLAT_PXA + help + Support for Marvell's PXA168/910 processor line. + config ARCH_KS8695 bool "Micrel/Kendin KS8695" select CPU_ARM922T @@ -427,51 +488,15 @@ config ARCH_NS9XXX -config ARCH_LOKI - bool "Marvell Loki (88RC8480)" - select CPU_FEROCEON - select GENERIC_TIME - select GENERIC_CLOCKEVENTS - select PLAT_ORION - help - Support for the Marvell Loki (88RC8480) SoC. - -config ARCH_MV78XX0 - bool "Marvell MV78xx0" - select CPU_FEROCEON - select PCI - select GENERIC_GPIO - select GENERIC_TIME - select GENERIC_CLOCKEVENTS - select PLAT_ORION - help - Support for the following Marvell MV78xx0 series SoCs: - MV781x0, MV782x0. - -config ARCH_MXC - bool "Freescale MXC/iMX-based" - select GENERIC_TIME - select GENERIC_CLOCKEVENTS - select ARCH_MTD_XIP - select GENERIC_GPIO +config ARCH_W90X900 + bool "Nuvoton W90X900 CPU" + select CPU_ARM926T select ARCH_REQUIRE_GPIOLIB - select HAVE_CLK - help - Support for Freescale MXC/iMX-based family of processors - -config ARCH_ORION5X - bool "Marvell Orion" - depends on MMU - select CPU_FEROCEON - select PCI select GENERIC_GPIO - select GENERIC_TIME - select GENERIC_CLOCKEVENTS - select PLAT_ORION + select COMMON_CLKDEV help - Support for the following Marvell Orion 5x series SoCs: - Orion-1 (5181), Orion-VoIP (5181L), Orion-NAS (5182), - Orion-2 (5281), Orion-1-90 (6183). + Support for Nuvoton (Winbond logic dept.) ARM9 processor,You + can login www.mcuos.com or www.nuvoton.com to know more. config ARCH_PNX4008 bool "Philips Nexperia PNX4008 Mobile" @@ -495,19 +520,16 @@ config ARCH_PXA help Support for Intel/Marvell's PXA2xx/PXA3xx processor line. -config ARCH_MMP - bool "Marvell PXA168/910" - depends on MMU - select GENERIC_GPIO - select ARCH_REQUIRE_GPIOLIB - select HAVE_CLK - select COMMON_CLKDEV +config ARCH_MSM + bool "Qualcomm MSM" + select CPU_V6 select GENERIC_TIME select GENERIC_CLOCKEVENTS - select TICK_ONESHOT - select PLAT_PXA help - Support for Marvell's PXA168/910 processor line. + Support for Qualcomm MSM7K based systems. This runs on the ARM11 + apps processor of the MSM7K and depends on a shared memory + interface to the ARM9 modem processor which runs the baseband stack + and controls some vital subsystems (clock and power control, etc). config ARCH_RPC bool "RiscPC" @@ -576,6 +598,20 @@ config ARCH_LH7A40X core with a wide array of integrated devices for hand-held and low-power applications. +config ARCH_U300 + bool "ST-Ericsson U300 Series" + depends on MMU + select CPU_ARM926T + select ARM_AMBA + select ARM_VIC + select GENERIC_TIME + select GENERIC_CLOCKEVENTS + select HAVE_CLK + select COMMON_CLKDEV + select GENERIC_GPIO + help + Support for ST-Ericsson U300 series mobile platforms. + config ARCH_DAVINCI bool "TI DaVinci" select CPU_ARM926T @@ -587,6 +623,7 @@ config ARCH_DAVINCI select ZONE_DMA select HAVE_IDE select COMMON_CLKDEV + select GENERIC_ALLOCATOR help Support for TI's DaVinci platform. @@ -600,24 +637,6 @@ config ARCH_OMAP help Support for TI's OMAP platform (OMAP1 and OMAP2). -config ARCH_MSM - bool "Qualcomm MSM" - select CPU_V6 - select GENERIC_TIME - select GENERIC_CLOCKEVENTS - help - Support for Qualcomm MSM7K based systems. This runs on the ARM11 - apps processor of the MSM7K and depends on a shared memory - interface to the ARM9 modem processor which runs the baseband stack - and controls some vital subsystems (clock and power control, etc). - -config ARCH_W90X900 - bool "Nuvoton W90X900 CPU" - select CPU_ARM926T - help - Support for Nuvoton (Winbond logic dept.) ARM9 processor,You - can login www.mcuos.com or www.nuvoton.com to know more. - endchoice source "arch/arm/mach-clps711x/Kconfig" @@ -681,9 +700,9 @@ source "arch/arm/mach-s3c6400/Kconfig" source "arch/arm/mach-s3c6410/Kconfig" endif -source "arch/arm/mach-lh7a40x/Kconfig" +source "arch/arm/plat-stmp3xxx/Kconfig" -source "arch/arm/mach-imx/Kconfig" +source "arch/arm/mach-lh7a40x/Kconfig" source "arch/arm/mach-h720x/Kconfig" @@ -707,6 +726,8 @@ source "arch/arm/mach-ks8695/Kconfig" source "arch/arm/mach-msm/Kconfig" +source "arch/arm/mach-u300/Kconfig" + source "arch/arm/mach-w90x900/Kconfig" # Definitions to make life easier @@ -859,8 +880,11 @@ source "kernel/time/Kconfig" config SMP bool "Symmetric Multi-Processing (EXPERIMENTAL)" - depends on EXPERIMENTAL && (REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP) + depends on EXPERIMENTAL && (REALVIEW_EB_ARM11MP || REALVIEW_EB_A9MP ||\ + MACH_REALVIEW_PB11MP || MACH_REALVIEW_PBX || ARCH_OMAP4) + depends on GENERIC_CLOCKEVENTS select USE_GENERIC_SMP_HELPERS + select HAVE_ARM_SCU if (ARCH_REALVIEW || ARCH_OMAP4) help This enables support for systems with more than one CPU. If you have a system with only one CPU, like most personal computers, say N. If @@ -878,6 +902,18 @@ config SMP If you don't know what to do here, say N. +config HAVE_ARM_SCU + bool + depends on SMP + help + This option enables support for the ARM system coherency unit + +config HAVE_ARM_TWD + bool + depends on SMP + help + This options enables support for the ARM timer and watchdog unit + choice prompt "Memory split" default VMSPLIT_3G @@ -916,8 +952,10 @@ config HOTPLUG_CPU config LOCAL_TIMERS bool "Use local timer interrupts" - depends on SMP && (REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP || REALVIEW_EB_A9MP) + depends on SMP && (REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP || \ + REALVIEW_EB_A9MP || MACH_REALVIEW_PBX || ARCH_OMAP4) default y + select HAVE_ARM_TWD if (ARCH_REALVIEW || ARCH_OMAP4) help Enable support for local timers on SMP platforms, rather then the legacy IPI broadcast method. Local timers allows the system @@ -979,7 +1017,6 @@ config OABI_COMPAT config ARCH_HAS_HOLES_MEMORYMODEL bool - default n # Discontigmem is deprecated config ARCH_DISCONTIGMEM_ENABLE @@ -1022,12 +1059,12 @@ source "mm/Kconfig" config LEDS bool "Timer and CPU usage LEDs" depends on ARCH_CDB89712 || ARCH_EBSA110 || \ - ARCH_EBSA285 || ARCH_IMX || ARCH_INTEGRATOR || \ + ARCH_EBSA285 || ARCH_INTEGRATOR || \ ARCH_LUBBOCK || MACH_MAINSTONE || ARCH_NETWINDER || \ ARCH_OMAP || ARCH_P720T || ARCH_PXA_IDP || \ ARCH_SA1100 || ARCH_SHARK || ARCH_VERSATILE || \ ARCH_AT91 || ARCH_DAVINCI || \ - ARCH_KS8695 || MACH_RD88F5182 + ARCH_KS8695 || MACH_RD88F5182 || ARCH_REALVIEW help If you say Y here, the LEDs on your machine will be used to provide useful information about your current system status. @@ -1085,6 +1122,22 @@ config ALIGNMENT_TRAP correct operation of some network protocols. With an IP-only configuration it is safe to say N, otherwise say Y. +config UACCESS_WITH_MEMCPY + bool "Use kernel mem{cpy,set}() for {copy_to,clear}_user() (EXPERIMENTAL)" + depends on MMU && EXPERIMENTAL + default y if CPU_FEROCEON + help + Implement faster copy_to_user and clear_user methods for CPU + cores where a 8-word STM instruction give significantly higher + memory write throughput than a sequence of individual 32bit stores. + + A possible side effect is a slight increase in scheduling latency + between threads sharing the same address space if they invoke + such copy operations with large buffers. + + However, if the CPU data cache is using a write-allocate mode, + this option is unlikely to provide any performance gain. + endmenu menu "Boot options" @@ -1188,7 +1241,7 @@ endmenu menu "CPU Power Management" -if (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_OMAP || ARCH_IMX || ARCH_PXA) +if (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_OMAP || ARCH_PXA || ARCH_S3C64XX) source "drivers/cpufreq/Kconfig" @@ -1213,14 +1266,15 @@ config CPU_FREQ_INTEGRATOR If in doubt, say Y. -config CPU_FREQ_IMX - tristate "CPUfreq driver for i.MX CPUs" - depends on ARCH_IMX && CPU_FREQ - default n - help - This enables the CPUfreq driver for i.MX CPUs. +config CPU_FREQ_PXA + bool + depends on CPU_FREQ && ARCH_PXA && PXA25x + default y + select CPU_FREQ_DEFAULT_GOV_USERSPACE - If in doubt, say N. +config CPU_FREQ_S3C64XX + bool "CPUfreq support for Samsung S3C64XX CPUs" + depends on CPU_FREQ && CPU_S3C6410 endif diff --git a/arch/arm/Makefile b/arch/arm/Makefile index e84729bf13d4..c877d6df23d1 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -11,6 +11,9 @@ # Copyright (C) 1995-2001 by Russell King LDFLAGS_vmlinux :=-p --no-undefined -X +ifeq ($(CONFIG_CPU_ENDIAN_BE8),y) +LDFLAGS_vmlinux += --be8 +endif CPPFLAGS_vmlinux.lds = -DTEXT_OFFSET=$(TEXT_OFFSET) OBJCOPYFLAGS :=-O binary -R .note -R .note.gnu.build-id -R .comment -S GZFLAGS :=-9 @@ -99,64 +102,73 @@ CHECKFLAGS += -D__arm__ #Default value head-y := arch/arm/kernel/head$(MMUEXT).o arch/arm/kernel/init_task.o textofs-y := 0x00008000 - - machine-$(CONFIG_ARCH_RPC) := rpc - machine-$(CONFIG_ARCH_EBSA110) := ebsa110 - machine-$(CONFIG_FOOTBRIDGE) := footbridge - machine-$(CONFIG_ARCH_SHARK) := shark - machine-$(CONFIG_ARCH_SA1100) := sa1100 -ifeq ($(CONFIG_ARCH_SA1100),y) +textofs-$(CONFIG_ARCH_CLPS711X) := 0x00028000 # SA1111 DMA bug: we don't want the kernel to live in precious DMA-able memory - textofs-$(CONFIG_SA1111) := 0x00208000 +ifeq ($(CONFIG_ARCH_SA1100),y) +textofs-$(CONFIG_SA1111) := 0x00208000 endif - machine-$(CONFIG_ARCH_PXA) := pxa - machine-$(CONFIG_ARCH_MMP) := mmp - plat-$(CONFIG_PLAT_PXA) := pxa - machine-$(CONFIG_ARCH_L7200) := l7200 - machine-$(CONFIG_ARCH_INTEGRATOR) := integrator - machine-$(CONFIG_ARCH_GEMINI) := gemini - textofs-$(CONFIG_ARCH_CLPS711X) := 0x00028000 - machine-$(CONFIG_ARCH_CLPS711X) := clps711x - machine-$(CONFIG_ARCH_IOP32X) := iop32x - machine-$(CONFIG_ARCH_IOP33X) := iop33x - machine-$(CONFIG_ARCH_IOP13XX) := iop13xx - plat-$(CONFIG_PLAT_IOP) := iop - machine-$(CONFIG_ARCH_IXP4XX) := ixp4xx - machine-$(CONFIG_ARCH_IXP2000) := ixp2000 - machine-$(CONFIG_ARCH_IXP23XX) := ixp23xx - machine-$(CONFIG_ARCH_OMAP1) := omap1 - machine-$(CONFIG_ARCH_OMAP2) := omap2 - machine-$(CONFIG_ARCH_OMAP3) := omap2 - plat-$(CONFIG_ARCH_OMAP) := omap - machine-$(CONFIG_ARCH_S3C2410) := s3c2410 s3c2400 s3c2412 s3c2440 s3c2442 s3c2443 - machine-$(CONFIG_ARCH_S3C24A0) := s3c24a0 - plat-$(CONFIG_PLAT_S3C24XX) := s3c24xx s3c - machine-$(CONFIG_ARCH_S3C64XX) := s3c6400 s3c6410 - plat-$(CONFIG_PLAT_S3C64XX) := s3c64xx s3c - machine-$(CONFIG_ARCH_LH7A40X) := lh7a40x - machine-$(CONFIG_ARCH_VERSATILE) := versatile - machine-$(CONFIG_ARCH_IMX) := imx - machine-$(CONFIG_ARCH_H720X) := h720x - machine-$(CONFIG_ARCH_AAEC2000) := aaec2000 - machine-$(CONFIG_ARCH_REALVIEW) := realview - machine-$(CONFIG_ARCH_AT91) := at91 - machine-$(CONFIG_ARCH_EP93XX) := ep93xx - machine-$(CONFIG_ARCH_PNX4008) := pnx4008 - machine-$(CONFIG_ARCH_NETX) := netx - machine-$(CONFIG_ARCH_NS9XXX) := ns9xxx - machine-$(CONFIG_ARCH_DAVINCI) := davinci - machine-$(CONFIG_ARCH_KIRKWOOD) := kirkwood - machine-$(CONFIG_ARCH_KS8695) := ks8695 - plat-$(CONFIG_ARCH_MXC) := mxc - machine-$(CONFIG_ARCH_MX2) := mx2 - machine-$(CONFIG_ARCH_MX3) := mx3 - machine-$(CONFIG_ARCH_MX1) := mx1 - machine-$(CONFIG_ARCH_ORION5X) := orion5x - plat-$(CONFIG_PLAT_ORION) := orion - machine-$(CONFIG_ARCH_MSM) := msm - machine-$(CONFIG_ARCH_LOKI) := loki - machine-$(CONFIG_ARCH_MV78XX0) := mv78xx0 - machine-$(CONFIG_ARCH_W90X900) := w90x900 + +# Machine directory name. This list is sorted alphanumerically +# by CONFIG_* macro name. +machine-$(CONFIG_ARCH_AAEC2000) := aaec2000 +machine-$(CONFIG_ARCH_AT91) := at91 +machine-$(CONFIG_ARCH_CLPS711X) := clps711x +machine-$(CONFIG_ARCH_DAVINCI) := davinci +machine-$(CONFIG_ARCH_EBSA110) := ebsa110 +machine-$(CONFIG_ARCH_EP93XX) := ep93xx +machine-$(CONFIG_ARCH_GEMINI) := gemini +machine-$(CONFIG_ARCH_H720X) := h720x +machine-$(CONFIG_ARCH_INTEGRATOR) := integrator +machine-$(CONFIG_ARCH_IOP13XX) := iop13xx +machine-$(CONFIG_ARCH_IOP32X) := iop32x +machine-$(CONFIG_ARCH_IOP33X) := iop33x +machine-$(CONFIG_ARCH_IXP2000) := ixp2000 +machine-$(CONFIG_ARCH_IXP23XX) := ixp23xx +machine-$(CONFIG_ARCH_IXP4XX) := ixp4xx +machine-$(CONFIG_ARCH_KIRKWOOD) := kirkwood +machine-$(CONFIG_ARCH_KS8695) := ks8695 +machine-$(CONFIG_ARCH_L7200) := l7200 +machine-$(CONFIG_ARCH_LH7A40X) := lh7a40x +machine-$(CONFIG_ARCH_LOKI) := loki +machine-$(CONFIG_ARCH_MMP) := mmp +machine-$(CONFIG_ARCH_MSM) := msm +machine-$(CONFIG_ARCH_MV78XX0) := mv78xx0 +machine-$(CONFIG_ARCH_MX1) := mx1 +machine-$(CONFIG_ARCH_MX2) := mx2 +machine-$(CONFIG_ARCH_MX3) := mx3 +machine-$(CONFIG_ARCH_NETX) := netx +machine-$(CONFIG_ARCH_NS9XXX) := ns9xxx +machine-$(CONFIG_ARCH_OMAP1) := omap1 +machine-$(CONFIG_ARCH_OMAP2) := omap2 +machine-$(CONFIG_ARCH_OMAP3) := omap2 +machine-$(CONFIG_ARCH_OMAP4) := omap2 +machine-$(CONFIG_ARCH_ORION5X) := orion5x +machine-$(CONFIG_ARCH_PNX4008) := pnx4008 +machine-$(CONFIG_ARCH_PXA) := pxa +machine-$(CONFIG_ARCH_REALVIEW) := realview +machine-$(CONFIG_ARCH_RPC) := rpc +machine-$(CONFIG_ARCH_S3C2410) := s3c2410 s3c2400 s3c2412 s3c2440 s3c2442 s3c2443 +machine-$(CONFIG_ARCH_S3C24A0) := s3c24a0 +machine-$(CONFIG_ARCH_S3C64XX) := s3c6400 s3c6410 +machine-$(CONFIG_ARCH_SA1100) := sa1100 +machine-$(CONFIG_ARCH_SHARK) := shark +machine-$(CONFIG_ARCH_STMP378X) := stmp378x +machine-$(CONFIG_ARCH_STMP37XX) := stmp37xx +machine-$(CONFIG_ARCH_U300) := u300 +machine-$(CONFIG_ARCH_VERSATILE) := versatile +machine-$(CONFIG_ARCH_W90X900) := w90x900 +machine-$(CONFIG_FOOTBRIDGE) := footbridge + +# Platform directory name. This list is sorted alphanumerically +# by CONFIG_* macro name. +plat-$(CONFIG_ARCH_MXC) := mxc +plat-$(CONFIG_ARCH_OMAP) := omap +plat-$(CONFIG_PLAT_IOP) := iop +plat-$(CONFIG_PLAT_ORION) := orion +plat-$(CONFIG_PLAT_PXA) := pxa +plat-$(CONFIG_PLAT_S3C24XX) := s3c24xx s3c +plat-$(CONFIG_PLAT_S3C64XX) := s3c64xx s3c +plat-$(CONFIG_ARCH_STMP3XXX) := stmp3xxx ifeq ($(CONFIG_ARCH_EBSA110),y) # This is what happens if you forget the IOCS16 line. diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile index fbe5eef1f6c9..ce39dc540085 100644 --- a/arch/arm/boot/compressed/Makefile +++ b/arch/arm/boot/compressed/Makefile @@ -40,7 +40,7 @@ ifeq ($(CONFIG_PXA_SHARPSL),y) OBJS += head-sharpsl.o endif -ifeq ($(CONFIG_CPU_BIG_ENDIAN),y) +ifeq ($(CONFIG_CPU_ENDIAN_BE32),y) ifeq ($(CONFIG_CPU_CP15),y) OBJS += big-endian.o else @@ -78,6 +78,9 @@ EXTRA_AFLAGS := -Wa,-march=all # linker symbols. We only define initrd_phys and params_phys if the # machine class defined the corresponding makefile variable. LDFLAGS_vmlinux := --defsym zreladdr=$(ZRELADDR) +ifeq ($(CONFIG_CPU_ENDIAN_BE8),y) +LDFLAGS_vmlinux += --be8 +endif ifneq ($(INITRD_PHYS),) LDFLAGS_vmlinux += --defsym initrd_phys=$(INITRD_PHYS) endif diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S index b371fba1b954..4515728c5345 100644 --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S @@ -438,6 +438,9 @@ __armv4_mmu_cache_on: mrc p15, 0, r0, c1, c0, 0 @ read control reg orr r0, r0, #0x5000 @ I-cache enable, RR cache replacement orr r0, r0, #0x0030 +#ifdef CONFIG_CPU_ENDIAN_BE8 + orr r0, r0, #1 << 25 @ big-endian page tables +#endif bl __common_mmu_cache_on mov r0, #0 mcr p15, 0, r0, c8, c7, 0 @ flush I,D TLBs @@ -455,6 +458,9 @@ __armv7_mmu_cache_on: mrc p15, 0, r0, c1, c0, 0 @ read control reg orr r0, r0, #0x5000 @ I-cache enable, RR cache replacement orr r0, r0, #0x003c @ write buffer +#ifdef CONFIG_CPU_ENDIAN_BE8 + orr r0, r0, #1 << 25 @ big-endian page tables +#endif orrne r0, r0, #1 @ MMU enabled movne r1, #-1 mcrne p15, 0, r3, c2, c0, 0 @ load page table pointer @@ -668,6 +674,15 @@ proc_types: b __armv4_mmu_cache_off b __armv5tej_mmu_cache_flush +#ifdef CONFIG_CPU_FEROCEON_OLD_ID + /* this conflicts with the standard ARMv5TE entry */ + .long 0x41009260 @ Old Feroceon + .long 0xff00fff0 + b __armv4_mmu_cache_on + b __armv4_mmu_cache_off + b __armv5tej_mmu_cache_flush +#endif + .word 0x66015261 @ FA526 .word 0xff01fff1 b __fa526_cache_on diff --git a/arch/arm/common/Kconfig b/arch/arm/common/Kconfig index a2cd9beaf37d..4efbb9df0444 100644 --- a/arch/arm/common/Kconfig +++ b/arch/arm/common/Kconfig @@ -4,6 +4,14 @@ config ARM_GIC config ARM_VIC bool +config ARM_VIC_NR + int + default 2 + depends on ARM_VIC + help + The maximum number of VICs available in the system, for + power management. + config ICST525 bool @@ -27,10 +35,6 @@ config SHARP_LOCOMO config SHARP_PARAM bool -config SHARPSL_PM - bool - select APM_EMULATION - config SHARP_SCOOP bool diff --git a/arch/arm/common/Makefile b/arch/arm/common/Makefile index 7cb7961d81cb..76be7ff2a7ca 100644 --- a/arch/arm/common/Makefile +++ b/arch/arm/common/Makefile @@ -12,7 +12,6 @@ obj-$(CONFIG_DMABOUNCE) += dmabounce.o obj-$(CONFIG_TIMER_ACORN) += time-acorn.o obj-$(CONFIG_SHARP_LOCOMO) += locomo.o obj-$(CONFIG_SHARP_PARAM) += sharpsl_param.o -obj-$(CONFIG_SHARPSL_PM) += sharpsl_pm.o obj-$(CONFIG_SHARP_SCOOP) += scoop.o obj-$(CONFIG_ARCH_IXP2000) += uengine.o obj-$(CONFIG_ARCH_IXP23XX) += uengine.o diff --git a/arch/arm/common/clkdev.c b/arch/arm/common/clkdev.c index 5589444ff437..f37afd9422f3 100644 --- a/arch/arm/common/clkdev.c +++ b/arch/arm/common/clkdev.c @@ -135,6 +135,24 @@ struct clk_lookup *clkdev_alloc(struct clk *clk, const char *con_id, } EXPORT_SYMBOL(clkdev_alloc); +int clk_add_alias(const char *alias, const char *alias_dev_name, char *id, + struct device *dev) +{ + struct clk *r = clk_get(dev, id); + struct clk_lookup *l; + + if (IS_ERR(r)) + return PTR_ERR(r); + + l = clkdev_alloc(r, alias, alias_dev_name); + clk_put(r); + if (!l) + return -ENODEV; + clkdev_add(l); + return 0; +} +EXPORT_SYMBOL(clk_add_alias); + /* * clkdev_drop - remove a clock dynamically allocated */ diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c index 3e1714c6523f..337741f734ac 100644 --- a/arch/arm/common/gic.c +++ b/arch/arm/common/gic.c @@ -109,7 +109,7 @@ static void gic_unmask_irq(unsigned int irq) } #ifdef CONFIG_SMP -static void gic_set_cpu(unsigned int irq, const struct cpumask *mask_val) +static int gic_set_cpu(unsigned int irq, const struct cpumask *mask_val) { void __iomem *reg = gic_dist_base(irq) + GIC_DIST_TARGET + (gic_irq(irq) & ~3); unsigned int shift = (irq % 4) * 8; @@ -117,11 +117,13 @@ static void gic_set_cpu(unsigned int irq, const struct cpumask *mask_val) u32 val; spin_lock(&irq_controller_lock); - irq_desc[irq].cpu = cpu; + irq_desc[irq].node = cpu; val = readl(reg) & ~(0xff << shift); val |= 1 << (cpu + shift); writel(val, reg); spin_unlock(&irq_controller_lock); + + return 0; } #endif diff --git a/arch/arm/common/sharpsl_pm.c b/arch/arm/common/sharpsl_pm.c deleted file mode 100644 index 140f1d721d50..000000000000 --- a/arch/arm/common/sharpsl_pm.c +++ /dev/null @@ -1,859 +0,0 @@ -/* - * Battery and Power Management code for the Sharp SL-C7xx and SL-Cxx00 - * series of PDAs - * - * Copyright (c) 2004-2005 Richard Purdie - * - * Based on code written by Sharp for 2.4 kernels - * - * 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. - * - */ - -#undef DEBUG - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -/* - * Constants - */ -#define SHARPSL_CHARGE_ON_TIME_INTERVAL (msecs_to_jiffies(1*60*1000)) /* 1 min */ -#define SHARPSL_CHARGE_FINISH_TIME (msecs_to_jiffies(10*60*1000)) /* 10 min */ -#define SHARPSL_BATCHK_TIME (msecs_to_jiffies(15*1000)) /* 15 sec */ -#define SHARPSL_BATCHK_TIME_SUSPEND (60*10) /* 10 min */ - -#define SHARPSL_WAIT_CO_TIME 15 /* 15 sec */ -#define SHARPSL_WAIT_DISCHARGE_ON 100 /* 100 msec */ -#define SHARPSL_CHECK_BATTERY_WAIT_TIME_TEMP 10 /* 10 msec */ -#define SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT 10 /* 10 msec */ -#define SHARPSL_CHECK_BATTERY_WAIT_TIME_ACIN 10 /* 10 msec */ -#define SHARPSL_CHARGE_WAIT_TIME 15 /* 15 msec */ -#define SHARPSL_CHARGE_CO_CHECK_TIME 5 /* 5 msec */ -#define SHARPSL_CHARGE_RETRY_CNT 1 /* eqv. 10 min */ - -/* - * Prototypes - */ -#ifdef CONFIG_PM -static int sharpsl_off_charge_battery(void); -static int sharpsl_check_battery_voltage(void); -static int sharpsl_fatal_check(void); -#endif -static int sharpsl_check_battery_temp(void); -static int sharpsl_ac_check(void); -static int sharpsl_average_value(int ad); -static void sharpsl_average_clear(void); -static void sharpsl_charge_toggle(struct work_struct *private_); -static void sharpsl_battery_thread(struct work_struct *private_); - - -/* - * Variables - */ -struct sharpsl_pm_status sharpsl_pm; -DECLARE_DELAYED_WORK(toggle_charger, sharpsl_charge_toggle); -DECLARE_DELAYED_WORK(sharpsl_bat, sharpsl_battery_thread); -DEFINE_LED_TRIGGER(sharpsl_charge_led_trigger); - - -static int get_percentage(int voltage) -{ - int i = sharpsl_pm.machinfo->bat_levels - 1; - int bl_status = sharpsl_pm.machinfo->backlight_get_status ? sharpsl_pm.machinfo->backlight_get_status() : 0; - struct battery_thresh *thresh; - - if (sharpsl_pm.charge_mode == CHRG_ON) - thresh = bl_status ? sharpsl_pm.machinfo->bat_levels_acin_bl : sharpsl_pm.machinfo->bat_levels_acin; - else - thresh = bl_status ? sharpsl_pm.machinfo->bat_levels_noac_bl : sharpsl_pm.machinfo->bat_levels_noac; - - while (i > 0 && (voltage > thresh[i].voltage)) - i--; - - return thresh[i].percentage; -} - -static int get_apm_status(int voltage) -{ - int low_thresh, high_thresh; - - if (sharpsl_pm.charge_mode == CHRG_ON) { - high_thresh = sharpsl_pm.machinfo->status_high_acin; - low_thresh = sharpsl_pm.machinfo->status_low_acin; - } else { - high_thresh = sharpsl_pm.machinfo->status_high_noac; - low_thresh = sharpsl_pm.machinfo->status_low_noac; - } - - if (voltage >= high_thresh) - return APM_BATTERY_STATUS_HIGH; - if (voltage >= low_thresh) - return APM_BATTERY_STATUS_LOW; - return APM_BATTERY_STATUS_CRITICAL; -} - -void sharpsl_battery_kick(void) -{ - schedule_delayed_work(&sharpsl_bat, msecs_to_jiffies(125)); -} -EXPORT_SYMBOL(sharpsl_battery_kick); - - -static void sharpsl_battery_thread(struct work_struct *private_) -{ - int voltage, percent, apm_status, i = 0; - - if (!sharpsl_pm.machinfo) - return; - - sharpsl_pm.battstat.ac_status = (sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN) ? APM_AC_ONLINE : APM_AC_OFFLINE); - - /* Corgi cannot confirm when battery fully charged so periodically kick! */ - if (!sharpsl_pm.machinfo->batfull_irq && (sharpsl_pm.charge_mode == CHRG_ON) - && time_after(jiffies, sharpsl_pm.charge_start_time + SHARPSL_CHARGE_ON_TIME_INTERVAL)) - schedule_delayed_work(&toggle_charger, 0); - - while(1) { - voltage = sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_VOLT); - - if (voltage > 0) break; - if (i++ > 5) { - voltage = sharpsl_pm.machinfo->bat_levels_noac[0].voltage; - dev_warn(sharpsl_pm.dev, "Warning: Cannot read main battery!\n"); - break; - } - } - - voltage = sharpsl_average_value(voltage); - apm_status = get_apm_status(voltage); - percent = get_percentage(voltage); - - /* At low battery voltages, the voltage has a tendency to start - creeping back up so we try to avoid this here */ - if ((sharpsl_pm.battstat.ac_status == APM_AC_ONLINE) || (apm_status == APM_BATTERY_STATUS_HIGH) || percent <= sharpsl_pm.battstat.mainbat_percent) { - sharpsl_pm.battstat.mainbat_voltage = voltage; - sharpsl_pm.battstat.mainbat_status = apm_status; - sharpsl_pm.battstat.mainbat_percent = percent; - } - - dev_dbg(sharpsl_pm.dev, "Battery: voltage: %d, status: %d, percentage: %d, time: %ld\n", voltage, - sharpsl_pm.battstat.mainbat_status, sharpsl_pm.battstat.mainbat_percent, jiffies); - -#ifdef CONFIG_BACKLIGHT_CORGI - /* If battery is low. limit backlight intensity to save power. */ - if ((sharpsl_pm.battstat.ac_status != APM_AC_ONLINE) - && ((sharpsl_pm.battstat.mainbat_status == APM_BATTERY_STATUS_LOW) || - (sharpsl_pm.battstat.mainbat_status == APM_BATTERY_STATUS_CRITICAL))) { - if (!(sharpsl_pm.flags & SHARPSL_BL_LIMIT)) { - sharpsl_pm.machinfo->backlight_limit(1); - sharpsl_pm.flags |= SHARPSL_BL_LIMIT; - } - } else if (sharpsl_pm.flags & SHARPSL_BL_LIMIT) { - sharpsl_pm.machinfo->backlight_limit(0); - sharpsl_pm.flags &= ~SHARPSL_BL_LIMIT; - } -#endif - - /* Suspend if critical battery level */ - if ((sharpsl_pm.battstat.ac_status != APM_AC_ONLINE) - && (sharpsl_pm.battstat.mainbat_status == APM_BATTERY_STATUS_CRITICAL) - && !(sharpsl_pm.flags & SHARPSL_APM_QUEUED)) { - sharpsl_pm.flags |= SHARPSL_APM_QUEUED; - dev_err(sharpsl_pm.dev, "Fatal Off\n"); - apm_queue_event(APM_CRITICAL_SUSPEND); - } - - schedule_delayed_work(&sharpsl_bat, SHARPSL_BATCHK_TIME); -} - -void sharpsl_pm_led(int val) -{ - if (val == SHARPSL_LED_ERROR) { - dev_err(sharpsl_pm.dev, "Charging Error!\n"); - } else if (val == SHARPSL_LED_ON) { - dev_dbg(sharpsl_pm.dev, "Charge LED On\n"); - led_trigger_event(sharpsl_charge_led_trigger, LED_FULL); - } else { - dev_dbg(sharpsl_pm.dev, "Charge LED Off\n"); - led_trigger_event(sharpsl_charge_led_trigger, LED_OFF); - } -} - -static void sharpsl_charge_on(void) -{ - dev_dbg(sharpsl_pm.dev, "Turning Charger On\n"); - - sharpsl_pm.full_count = 0; - sharpsl_pm.charge_mode = CHRG_ON; - schedule_delayed_work(&toggle_charger, msecs_to_jiffies(250)); - schedule_delayed_work(&sharpsl_bat, msecs_to_jiffies(500)); -} - -static void sharpsl_charge_off(void) -{ - dev_dbg(sharpsl_pm.dev, "Turning Charger Off\n"); - - sharpsl_pm.machinfo->charge(0); - sharpsl_pm_led(SHARPSL_LED_OFF); - sharpsl_pm.charge_mode = CHRG_OFF; - - schedule_delayed_work(&sharpsl_bat, 0); -} - -static void sharpsl_charge_error(void) -{ - sharpsl_pm_led(SHARPSL_LED_ERROR); - sharpsl_pm.machinfo->charge(0); - sharpsl_pm.charge_mode = CHRG_ERROR; -} - -static void sharpsl_charge_toggle(struct work_struct *private_) -{ - dev_dbg(sharpsl_pm.dev, "Toogling Charger at time: %lx\n", jiffies); - - if (!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN)) { - sharpsl_charge_off(); - return; - } else if ((sharpsl_check_battery_temp() < 0) || (sharpsl_ac_check() < 0)) { - sharpsl_charge_error(); - return; - } - - sharpsl_pm_led(SHARPSL_LED_ON); - sharpsl_pm.machinfo->charge(0); - mdelay(SHARPSL_CHARGE_WAIT_TIME); - sharpsl_pm.machinfo->charge(1); - - sharpsl_pm.charge_start_time = jiffies; -} - -static void sharpsl_ac_timer(unsigned long data) -{ - int acin = sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN); - - dev_dbg(sharpsl_pm.dev, "AC Status: %d\n",acin); - - sharpsl_average_clear(); - if (acin && (sharpsl_pm.charge_mode != CHRG_ON)) - sharpsl_charge_on(); - else if (sharpsl_pm.charge_mode == CHRG_ON) - sharpsl_charge_off(); - - schedule_delayed_work(&sharpsl_bat, 0); -} - - -irqreturn_t sharpsl_ac_isr(int irq, void *dev_id) -{ - /* Delay the event slightly to debounce */ - /* Must be a smaller delay than the chrg_full_isr below */ - mod_timer(&sharpsl_pm.ac_timer, jiffies + msecs_to_jiffies(250)); - - return IRQ_HANDLED; -} - -static void sharpsl_chrg_full_timer(unsigned long data) -{ - dev_dbg(sharpsl_pm.dev, "Charge Full at time: %lx\n", jiffies); - - sharpsl_pm.full_count++; - - if (!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN)) { - dev_dbg(sharpsl_pm.dev, "Charge Full: AC removed - stop charging!\n"); - if (sharpsl_pm.charge_mode == CHRG_ON) - sharpsl_charge_off(); - } else if (sharpsl_pm.full_count < 2) { - dev_dbg(sharpsl_pm.dev, "Charge Full: Count too low\n"); - schedule_delayed_work(&toggle_charger, 0); - } else if (time_after(jiffies, sharpsl_pm.charge_start_time + SHARPSL_CHARGE_FINISH_TIME)) { - dev_dbg(sharpsl_pm.dev, "Charge Full: Interrupt generated too slowly - retry.\n"); - schedule_delayed_work(&toggle_charger, 0); - } else { - sharpsl_charge_off(); - sharpsl_pm.charge_mode = CHRG_DONE; - dev_dbg(sharpsl_pm.dev, "Charge Full: Charging Finished\n"); - } -} - -/* Charging Finished Interrupt (Not present on Corgi) */ -/* Can trigger at the same time as an AC status change so - delay until after that has been processed */ -irqreturn_t sharpsl_chrg_full_isr(int irq, void *dev_id) -{ - if (sharpsl_pm.flags & SHARPSL_SUSPENDED) - return IRQ_HANDLED; - - /* delay until after any ac interrupt */ - mod_timer(&sharpsl_pm.chrg_full_timer, jiffies + msecs_to_jiffies(500)); - - return IRQ_HANDLED; -} - -irqreturn_t sharpsl_fatal_isr(int irq, void *dev_id) -{ - int is_fatal = 0; - - if (!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_LOCK)) { - dev_err(sharpsl_pm.dev, "Battery now Unlocked! Suspending.\n"); - is_fatal = 1; - } - - if (!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_FATAL)) { - dev_err(sharpsl_pm.dev, "Fatal Batt Error! Suspending.\n"); - is_fatal = 1; - } - - if (!(sharpsl_pm.flags & SHARPSL_APM_QUEUED) && is_fatal) { - sharpsl_pm.flags |= SHARPSL_APM_QUEUED; - apm_queue_event(APM_CRITICAL_SUSPEND); - } - - return IRQ_HANDLED; -} - -/* - * Maintain an average of the last 10 readings - */ -#define SHARPSL_CNV_VALUE_NUM 10 -static int sharpsl_ad_index; - -static void sharpsl_average_clear(void) -{ - sharpsl_ad_index = 0; -} - -static int sharpsl_average_value(int ad) -{ - int i, ad_val = 0; - static int sharpsl_ad[SHARPSL_CNV_VALUE_NUM+1]; - - if (sharpsl_pm.battstat.mainbat_status != APM_BATTERY_STATUS_HIGH) { - sharpsl_ad_index = 0; - return ad; - } - - sharpsl_ad[sharpsl_ad_index] = ad; - sharpsl_ad_index++; - if (sharpsl_ad_index >= SHARPSL_CNV_VALUE_NUM) { - for (i=0; i < (SHARPSL_CNV_VALUE_NUM-1); i++) - sharpsl_ad[i] = sharpsl_ad[i+1]; - sharpsl_ad_index = SHARPSL_CNV_VALUE_NUM - 1; - } - for (i=0; i < sharpsl_ad_index; i++) - ad_val += sharpsl_ad[i]; - - return (ad_val / sharpsl_ad_index); -} - -/* - * Take an array of 5 integers, remove the maximum and minimum values - * and return the average. - */ -static int get_select_val(int *val) -{ - int i, j, k, temp, sum = 0; - - /* Find MAX val */ - temp = val[0]; - j=0; - for (i=1; i<5; i++) { - if (temp < val[i]) { - temp = val[i]; - j = i; - } - } - - /* Find MIN val */ - temp = val[4]; - k=4; - for (i=3; i>=0; i--) { - if (temp > val[i]) { - temp = val[i]; - k = i; - } - } - - for (i=0; i<5; i++) - if (i != j && i != k ) - sum += val[i]; - - dev_dbg(sharpsl_pm.dev, "Average: %d from values: %d, %d, %d, %d, %d\n", sum/3, val[0], val[1], val[2], val[3], val[4]); - - return (sum/3); -} - -static int sharpsl_check_battery_temp(void) -{ - int val, i, buff[5]; - - /* Check battery temperature */ - for (i=0; i<5; i++) { - mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_TEMP); - sharpsl_pm.machinfo->measure_temp(1); - mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_TEMP); - buff[i] = sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_TEMP); - sharpsl_pm.machinfo->measure_temp(0); - } - - val = get_select_val(buff); - - dev_dbg(sharpsl_pm.dev, "Temperature: %d\n", val); - if (val > sharpsl_pm.machinfo->charge_on_temp) { - printk(KERN_WARNING "Not charging: temperature out of limits.\n"); - return -1; - } - - return 0; -} - -#ifdef CONFIG_PM -static int sharpsl_check_battery_voltage(void) -{ - int val, i, buff[5]; - - /* disable charge, enable discharge */ - sharpsl_pm.machinfo->charge(0); - sharpsl_pm.machinfo->discharge(1); - mdelay(SHARPSL_WAIT_DISCHARGE_ON); - - if (sharpsl_pm.machinfo->discharge1) - sharpsl_pm.machinfo->discharge1(1); - - /* Check battery voltage */ - for (i=0; i<5; i++) { - buff[i] = sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_VOLT); - mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT); - } - - if (sharpsl_pm.machinfo->discharge1) - sharpsl_pm.machinfo->discharge1(0); - - sharpsl_pm.machinfo->discharge(0); - - val = get_select_val(buff); - dev_dbg(sharpsl_pm.dev, "Battery Voltage: %d\n", val); - - if (val < sharpsl_pm.machinfo->charge_on_volt) - return -1; - - return 0; -} -#endif - -static int sharpsl_ac_check(void) -{ - int temp, i, buff[5]; - - for (i=0; i<5; i++) { - buff[i] = sharpsl_pm.machinfo->read_devdata(SHARPSL_ACIN_VOLT); - mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_ACIN); - } - - temp = get_select_val(buff); - dev_dbg(sharpsl_pm.dev, "AC Voltage: %d\n",temp); - - if ((temp > sharpsl_pm.machinfo->charge_acin_high) || (temp < sharpsl_pm.machinfo->charge_acin_low)) { - dev_err(sharpsl_pm.dev, "Error: AC check failed.\n"); - return -1; - } - - return 0; -} - -#ifdef CONFIG_PM -static int sharpsl_pm_suspend(struct platform_device *pdev, pm_message_t state) -{ - sharpsl_pm.flags |= SHARPSL_SUSPENDED; - flush_scheduled_work(); - - if (sharpsl_pm.charge_mode == CHRG_ON) - sharpsl_pm.flags |= SHARPSL_DO_OFFLINE_CHRG; - else - sharpsl_pm.flags &= ~SHARPSL_DO_OFFLINE_CHRG; - - return 0; -} - -static int sharpsl_pm_resume(struct platform_device *pdev) -{ - /* Clear the reset source indicators as they break the bootloader upon reboot */ - RCSR = 0x0f; - sharpsl_average_clear(); - sharpsl_pm.flags &= ~SHARPSL_APM_QUEUED; - sharpsl_pm.flags &= ~SHARPSL_SUSPENDED; - - return 0; -} - -static void corgi_goto_sleep(unsigned long alarm_time, unsigned int alarm_enable, suspend_state_t state) -{ - dev_dbg(sharpsl_pm.dev, "Time is: %08x\n",RCNR); - - dev_dbg(sharpsl_pm.dev, "Offline Charge Activate = %d\n",sharpsl_pm.flags & SHARPSL_DO_OFFLINE_CHRG); - /* not charging and AC-IN! */ - - if ((sharpsl_pm.flags & SHARPSL_DO_OFFLINE_CHRG) && (sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN))) { - dev_dbg(sharpsl_pm.dev, "Activating Offline Charger...\n"); - sharpsl_pm.charge_mode = CHRG_OFF; - sharpsl_pm.flags &= ~SHARPSL_DO_OFFLINE_CHRG; - sharpsl_off_charge_battery(); - } - - sharpsl_pm.machinfo->presuspend(); - - PEDR = 0xffffffff; /* clear it */ - - sharpsl_pm.flags &= ~SHARPSL_ALARM_ACTIVE; - if ((sharpsl_pm.charge_mode == CHRG_ON) && ((alarm_enable && ((alarm_time - RCNR) > (SHARPSL_BATCHK_TIME_SUSPEND + 30))) || !alarm_enable)) { - RTSR &= RTSR_ALE; - RTAR = RCNR + SHARPSL_BATCHK_TIME_SUSPEND; - dev_dbg(sharpsl_pm.dev, "Charging alarm at: %08x\n",RTAR); - sharpsl_pm.flags |= SHARPSL_ALARM_ACTIVE; - } else if (alarm_enable) { - RTSR &= RTSR_ALE; - RTAR = alarm_time; - dev_dbg(sharpsl_pm.dev, "User alarm at: %08x\n",RTAR); - } else { - dev_dbg(sharpsl_pm.dev, "No alarms set.\n"); - } - - pxa_pm_enter(state); - - sharpsl_pm.machinfo->postsuspend(); - - dev_dbg(sharpsl_pm.dev, "Corgi woken up from suspend: %08x\n",PEDR); -} - -static int corgi_enter_suspend(unsigned long alarm_time, unsigned int alarm_enable, suspend_state_t state) -{ - if (!sharpsl_pm.machinfo->should_wakeup(!(sharpsl_pm.flags & SHARPSL_ALARM_ACTIVE) && alarm_enable) ) - { - if (!(sharpsl_pm.flags & SHARPSL_ALARM_ACTIVE)) { - dev_dbg(sharpsl_pm.dev, "No user triggered wakeup events and not charging. Strange. Suspend.\n"); - corgi_goto_sleep(alarm_time, alarm_enable, state); - return 1; - } - if(sharpsl_off_charge_battery()) { - dev_dbg(sharpsl_pm.dev, "Charging. Suspend...\n"); - corgi_goto_sleep(alarm_time, alarm_enable, state); - return 1; - } - dev_dbg(sharpsl_pm.dev, "User triggered wakeup in offline charger.\n"); - } - - if ((!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_LOCK)) || (sharpsl_fatal_check() < 0) ) - { - dev_err(sharpsl_pm.dev, "Fatal condition. Suspend.\n"); - corgi_goto_sleep(alarm_time, alarm_enable, state); - return 1; - } - - return 0; -} - -static int corgi_pxa_pm_enter(suspend_state_t state) -{ - unsigned long alarm_time = RTAR; - unsigned int alarm_status = ((RTSR & RTSR_ALE) != 0); - - dev_dbg(sharpsl_pm.dev, "SharpSL suspending for first time.\n"); - - corgi_goto_sleep(alarm_time, alarm_status, state); - - while (corgi_enter_suspend(alarm_time,alarm_status,state)) - {} - - if (sharpsl_pm.machinfo->earlyresume) - sharpsl_pm.machinfo->earlyresume(); - - dev_dbg(sharpsl_pm.dev, "SharpSL resuming...\n"); - - return 0; -} - -/* - * Check for fatal battery errors - * Fatal returns -1 - */ -static int sharpsl_fatal_check(void) -{ - int buff[5], temp, i, acin; - - dev_dbg(sharpsl_pm.dev, "sharpsl_fatal_check entered\n"); - - /* Check AC-Adapter */ - acin = sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN); - - if (acin && (sharpsl_pm.charge_mode == CHRG_ON)) { - sharpsl_pm.machinfo->charge(0); - udelay(100); - sharpsl_pm.machinfo->discharge(1); /* enable discharge */ - mdelay(SHARPSL_WAIT_DISCHARGE_ON); - } - - if (sharpsl_pm.machinfo->discharge1) - sharpsl_pm.machinfo->discharge1(1); - - /* Check battery : check inserting battery ? */ - for (i=0; i<5; i++) { - buff[i] = sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_VOLT); - mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT); - } - - if (sharpsl_pm.machinfo->discharge1) - sharpsl_pm.machinfo->discharge1(0); - - if (acin && (sharpsl_pm.charge_mode == CHRG_ON)) { - udelay(100); - sharpsl_pm.machinfo->charge(1); - sharpsl_pm.machinfo->discharge(0); - } - - temp = get_select_val(buff); - dev_dbg(sharpsl_pm.dev, "sharpsl_fatal_check: acin: %d, discharge voltage: %d, no discharge: %ld\n", acin, temp, sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_VOLT)); - - if ((acin && (temp < sharpsl_pm.machinfo->fatal_acin_volt)) || - (!acin && (temp < sharpsl_pm.machinfo->fatal_noacin_volt))) - return -1; - return 0; -} - -static int sharpsl_off_charge_error(void) -{ - dev_err(sharpsl_pm.dev, "Offline Charger: Error occurred.\n"); - sharpsl_pm.machinfo->charge(0); - sharpsl_pm_led(SHARPSL_LED_ERROR); - sharpsl_pm.charge_mode = CHRG_ERROR; - return 1; -} - -/* - * Charging Control while suspended - * Return 1 - go straight to sleep - * Return 0 - sleep or wakeup depending on other factors - */ -static int sharpsl_off_charge_battery(void) -{ - int time; - - dev_dbg(sharpsl_pm.dev, "Charge Mode: %d\n", sharpsl_pm.charge_mode); - - if (sharpsl_pm.charge_mode == CHRG_OFF) { - dev_dbg(sharpsl_pm.dev, "Offline Charger: Step 1\n"); - - /* AC Check */ - if ((sharpsl_ac_check() < 0) || (sharpsl_check_battery_temp() < 0)) - return sharpsl_off_charge_error(); - - /* Start Charging */ - sharpsl_pm_led(SHARPSL_LED_ON); - sharpsl_pm.machinfo->charge(0); - mdelay(SHARPSL_CHARGE_WAIT_TIME); - sharpsl_pm.machinfo->charge(1); - - sharpsl_pm.charge_mode = CHRG_ON; - sharpsl_pm.full_count = 0; - - return 1; - } else if (sharpsl_pm.charge_mode != CHRG_ON) { - return 1; - } - - if (sharpsl_pm.full_count == 0) { - int time; - - dev_dbg(sharpsl_pm.dev, "Offline Charger: Step 2\n"); - - if ((sharpsl_check_battery_temp() < 0) || (sharpsl_check_battery_voltage() < 0)) - return sharpsl_off_charge_error(); - - sharpsl_pm.machinfo->charge(0); - mdelay(SHARPSL_CHARGE_WAIT_TIME); - sharpsl_pm.machinfo->charge(1); - sharpsl_pm.charge_mode = CHRG_ON; - - mdelay(SHARPSL_CHARGE_CO_CHECK_TIME); - - time = RCNR; - while(1) { - /* Check if any wakeup event had occurred */ - if (sharpsl_pm.machinfo->charger_wakeup() != 0) - return 0; - /* Check for timeout */ - if ((RCNR - time) > SHARPSL_WAIT_CO_TIME) - return 1; - if (sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_CHRGFULL)) { - dev_dbg(sharpsl_pm.dev, "Offline Charger: Charge full occurred. Retrying to check\n"); - sharpsl_pm.full_count++; - sharpsl_pm.machinfo->charge(0); - mdelay(SHARPSL_CHARGE_WAIT_TIME); - sharpsl_pm.machinfo->charge(1); - return 1; - } - } - } - - dev_dbg(sharpsl_pm.dev, "Offline Charger: Step 3\n"); - - mdelay(SHARPSL_CHARGE_CO_CHECK_TIME); - - time = RCNR; - while(1) { - /* Check if any wakeup event had occurred */ - if (sharpsl_pm.machinfo->charger_wakeup() != 0) - return 0; - /* Check for timeout */ - if ((RCNR-time) > SHARPSL_WAIT_CO_TIME) { - if (sharpsl_pm.full_count > SHARPSL_CHARGE_RETRY_CNT) { - dev_dbg(sharpsl_pm.dev, "Offline Charger: Not charged sufficiently. Retrying.\n"); - sharpsl_pm.full_count = 0; - } - sharpsl_pm.full_count++; - return 1; - } - if (sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_CHRGFULL)) { - dev_dbg(sharpsl_pm.dev, "Offline Charger: Charging complete.\n"); - sharpsl_pm_led(SHARPSL_LED_OFF); - sharpsl_pm.machinfo->charge(0); - sharpsl_pm.charge_mode = CHRG_DONE; - return 1; - } - } -} -#else -#define sharpsl_pm_suspend NULL -#define sharpsl_pm_resume NULL -#endif - -static ssize_t battery_percentage_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%d\n",sharpsl_pm.battstat.mainbat_percent); -} - -static ssize_t battery_voltage_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%d\n",sharpsl_pm.battstat.mainbat_voltage); -} - -static DEVICE_ATTR(battery_percentage, 0444, battery_percentage_show, NULL); -static DEVICE_ATTR(battery_voltage, 0444, battery_voltage_show, NULL); - -extern void (*apm_get_power_status)(struct apm_power_info *); - -static void sharpsl_apm_get_power_status(struct apm_power_info *info) -{ - info->ac_line_status = sharpsl_pm.battstat.ac_status; - - if (sharpsl_pm.charge_mode == CHRG_ON) - info->battery_status = APM_BATTERY_STATUS_CHARGING; - else - info->battery_status = sharpsl_pm.battstat.mainbat_status; - - info->battery_flag = (1 << info->battery_status); - info->battery_life = sharpsl_pm.battstat.mainbat_percent; -} - -#ifdef CONFIG_PM -static struct platform_suspend_ops sharpsl_pm_ops = { - .enter = corgi_pxa_pm_enter, - .valid = suspend_valid_only_mem, -}; -#endif - -static int __init sharpsl_pm_probe(struct platform_device *pdev) -{ - int ret; - - if (!pdev->dev.platform_data) - return -EINVAL; - - sharpsl_pm.dev = &pdev->dev; - sharpsl_pm.machinfo = pdev->dev.platform_data; - sharpsl_pm.charge_mode = CHRG_OFF; - sharpsl_pm.flags = 0; - - init_timer(&sharpsl_pm.ac_timer); - sharpsl_pm.ac_timer.function = sharpsl_ac_timer; - - init_timer(&sharpsl_pm.chrg_full_timer); - sharpsl_pm.chrg_full_timer.function = sharpsl_chrg_full_timer; - - led_trigger_register_simple("sharpsl-charge", &sharpsl_charge_led_trigger); - - sharpsl_pm.machinfo->init(); - - ret = device_create_file(&pdev->dev, &dev_attr_battery_percentage); - ret |= device_create_file(&pdev->dev, &dev_attr_battery_voltage); - if (ret != 0) - dev_warn(&pdev->dev, "Failed to register attributes (%d)\n", ret); - - apm_get_power_status = sharpsl_apm_get_power_status; - -#ifdef CONFIG_PM - suspend_set_ops(&sharpsl_pm_ops); -#endif - - mod_timer(&sharpsl_pm.ac_timer, jiffies + msecs_to_jiffies(250)); - - return 0; -} - -static int sharpsl_pm_remove(struct platform_device *pdev) -{ - suspend_set_ops(NULL); - - device_remove_file(&pdev->dev, &dev_attr_battery_percentage); - device_remove_file(&pdev->dev, &dev_attr_battery_voltage); - - led_trigger_unregister_simple(sharpsl_charge_led_trigger); - - sharpsl_pm.machinfo->exit(); - - del_timer_sync(&sharpsl_pm.chrg_full_timer); - del_timer_sync(&sharpsl_pm.ac_timer); - - return 0; -} - -static struct platform_driver sharpsl_pm_driver = { - .probe = sharpsl_pm_probe, - .remove = sharpsl_pm_remove, - .suspend = sharpsl_pm_suspend, - .resume = sharpsl_pm_resume, - .driver = { - .name = "sharpsl-pm", - }, -}; - -static int __devinit sharpsl_pm_init(void) -{ - return platform_driver_register(&sharpsl_pm_driver); -} - -static void sharpsl_pm_exit(void) -{ - platform_driver_unregister(&sharpsl_pm_driver); -} - -late_initcall(sharpsl_pm_init); -module_exit(sharpsl_pm_exit); diff --git a/arch/arm/common/vic.c b/arch/arm/common/vic.c index b2a781d9ce05..6ed89836e908 100644 --- a/arch/arm/common/vic.c +++ b/arch/arm/common/vic.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -39,11 +40,223 @@ static void vic_unmask_irq(unsigned int irq) writel(1 << irq, base + VIC_INT_ENABLE); } +/** + * vic_init2 - common initialisation code + * @base: Base of the VIC. + * + * Common initialisation code for registeration + * and resume. +*/ +static void vic_init2(void __iomem *base) +{ + int i; + + for (i = 0; i < 16; i++) { + void __iomem *reg = base + VIC_VECT_CNTL0 + (i * 4); + writel(VIC_VECT_CNTL_ENABLE | i, reg); + } + + writel(32, base + VIC_PL190_DEF_VECT_ADDR); +} + +#if defined(CONFIG_PM) +/** + * struct vic_device - VIC PM device + * @sysdev: The system device which is registered. + * @irq: The IRQ number for the base of the VIC. + * @base: The register base for the VIC. + * @resume_sources: A bitmask of interrupts for resume. + * @resume_irqs: The IRQs enabled for resume. + * @int_select: Save for VIC_INT_SELECT. + * @int_enable: Save for VIC_INT_ENABLE. + * @soft_int: Save for VIC_INT_SOFT. + * @protect: Save for VIC_PROTECT. + */ +struct vic_device { + struct sys_device sysdev; + + void __iomem *base; + int irq; + u32 resume_sources; + u32 resume_irqs; + u32 int_select; + u32 int_enable; + u32 soft_int; + u32 protect; +}; + +/* we cannot allocate memory when VICs are initially registered */ +static struct vic_device vic_devices[CONFIG_ARM_VIC_NR]; + +static inline struct vic_device *to_vic(struct sys_device *sys) +{ + return container_of(sys, struct vic_device, sysdev); +} + +static int vic_id; + +static int vic_class_resume(struct sys_device *dev) +{ + struct vic_device *vic = to_vic(dev); + void __iomem *base = vic->base; + + printk(KERN_DEBUG "%s: resuming vic at %p\n", __func__, base); + + /* re-initialise static settings */ + vic_init2(base); + + writel(vic->int_select, base + VIC_INT_SELECT); + writel(vic->protect, base + VIC_PROTECT); + + /* set the enabled ints and then clear the non-enabled */ + writel(vic->int_enable, base + VIC_INT_ENABLE); + writel(~vic->int_enable, base + VIC_INT_ENABLE_CLEAR); + + /* and the same for the soft-int register */ + + writel(vic->soft_int, base + VIC_INT_SOFT); + writel(~vic->soft_int, base + VIC_INT_SOFT_CLEAR); + + return 0; +} + +static int vic_class_suspend(struct sys_device *dev, pm_message_t state) +{ + struct vic_device *vic = to_vic(dev); + void __iomem *base = vic->base; + + printk(KERN_DEBUG "%s: suspending vic at %p\n", __func__, base); + + vic->int_select = readl(base + VIC_INT_SELECT); + vic->int_enable = readl(base + VIC_INT_ENABLE); + vic->soft_int = readl(base + VIC_INT_SOFT); + vic->protect = readl(base + VIC_PROTECT); + + /* set the interrupts (if any) that are used for + * resuming the system */ + + writel(vic->resume_irqs, base + VIC_INT_ENABLE); + writel(~vic->resume_irqs, base + VIC_INT_ENABLE_CLEAR); + + return 0; +} + +struct sysdev_class vic_class = { + .name = "vic", + .suspend = vic_class_suspend, + .resume = vic_class_resume, +}; + +/** + * vic_pm_register - Register a VIC for later power management control + * @base: The base address of the VIC. + * @irq: The base IRQ for the VIC. + * @resume_sources: bitmask of interrupts allowed for resume sources. + * + * Register the VIC with the system device tree so that it can be notified + * of suspend and resume requests and ensure that the correct actions are + * taken to re-instate the settings on resume. + */ +static void __init vic_pm_register(void __iomem *base, unsigned int irq, u32 resume_sources) +{ + struct vic_device *v; + + if (vic_id >= ARRAY_SIZE(vic_devices)) + printk(KERN_ERR "%s: too few VICs, increase CONFIG_ARM_VIC_NR\n", __func__); + else { + v = &vic_devices[vic_id]; + v->base = base; + v->resume_sources = resume_sources; + v->irq = irq; + vic_id++; + } +} + +/** + * vic_pm_init - initicall to register VIC pm + * + * This is called via late_initcall() to register + * the resources for the VICs due to the early + * nature of the VIC's registration. +*/ +static int __init vic_pm_init(void) +{ + struct vic_device *dev = vic_devices; + int err; + int id; + + if (vic_id == 0) + return 0; + + err = sysdev_class_register(&vic_class); + if (err) { + printk(KERN_ERR "%s: cannot register class\n", __func__); + return err; + } + + for (id = 0; id < vic_id; id++, dev++) { + dev->sysdev.id = id; + dev->sysdev.cls = &vic_class; + + err = sysdev_register(&dev->sysdev); + if (err) { + printk(KERN_ERR "%s: failed to register device\n", + __func__); + return err; + } + } + + return 0; +} + +late_initcall(vic_pm_init); + +static struct vic_device *vic_from_irq(unsigned int irq) +{ + struct vic_device *v = vic_devices; + unsigned int base_irq = irq & ~31; + int id; + + for (id = 0; id < vic_id; id++, v++) { + if (v->irq == base_irq) + return v; + } + + return NULL; +} + +static int vic_set_wake(unsigned int irq, unsigned int on) +{ + struct vic_device *v = vic_from_irq(irq); + unsigned int off = irq & 31; + u32 bit = 1 << off; + + if (!v) + return -EINVAL; + + if (!(bit & v->resume_sources)) + return -EINVAL; + + if (on) + v->resume_irqs |= bit; + else + v->resume_irqs &= ~bit; + + return 0; +} + +#else +static inline void vic_pm_register(void __iomem *base, unsigned int irq, u32 arg1) { } + +#define vic_set_wake NULL +#endif /* CONFIG_PM */ + static struct irq_chip vic_chip = { .name = "VIC", .ack = vic_mask_irq, .mask = vic_mask_irq, .unmask = vic_unmask_irq, + .set_wake = vic_set_wake, }; /** @@ -51,9 +264,10 @@ static struct irq_chip vic_chip = { * @base: iomem base address * @irq_start: starting interrupt number, must be muliple of 32 * @vic_sources: bitmask of interrupt sources to allow + * @resume_sources: bitmask of interrupt sources to allow for resume */ void __init vic_init(void __iomem *base, unsigned int irq_start, - u32 vic_sources) + u32 vic_sources, u32 resume_sources) { unsigned int i; @@ -77,12 +291,7 @@ void __init vic_init(void __iomem *base, unsigned int irq_start, writel(value, base + VIC_PL190_VECT_ADDR); } - for (i = 0; i < 16; i++) { - void __iomem *reg = base + VIC_VECT_CNTL0 + (i * 4); - writel(VIC_VECT_CNTL_ENABLE | i, reg); - } - - writel(32, base + VIC_PL190_DEF_VECT_ADDR); + vic_init2(base); for (i = 0; i < 32; i++) { if (vic_sources & (1 << i)) { @@ -94,4 +303,6 @@ void __init vic_init(void __iomem *base, unsigned int irq_start, set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); } } + + vic_pm_register(base, irq_start, resume_sources); } diff --git a/arch/arm/configs/cm_x300_defconfig b/arch/arm/configs/cm_x300_defconfig index 227da0843ead..d18d21bb41e4 100644 --- a/arch/arm/configs/cm_x300_defconfig +++ b/arch/arm/configs/cm_x300_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.27-rc3 -# Tue Aug 19 11:26:54 2008 +# Linux kernel version: 2.6.30-rc8 +# Thu Jun 4 09:53:21 2009 # CONFIG_ARM=y CONFIG_SYS_SUPPORTS_APM_EMULATION=y @@ -22,8 +22,6 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_ARCH_HAS_ILOG2_U64 is not set CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_CALIBRATE_DELAY=y -CONFIG_ARCH_SUPPORTS_AOUT=y -CONFIG_ZONE_DMA=y CONFIG_ARCH_MTD_XIP=y CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y CONFIG_VECTORS_BASE=0xffff0000 @@ -44,15 +42,24 @@ CONFIG_SYSVIPC_SYSCTL=y # CONFIG_BSD_PROCESS_ACCT is not set # CONFIG_TASKSTATS is not set # CONFIG_AUDIT is not set + +# +# RCU Subsystem +# +CONFIG_CLASSIC_RCU=y +# CONFIG_TREE_RCU is not set +# CONFIG_PREEMPT_RCU is not set +# CONFIG_TREE_RCU_TRACE is not set +# CONFIG_PREEMPT_RCU_TRACE is not set CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=18 -# 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_CGROUPS is not set CONFIG_SYSFS_DEPRECATED=y CONFIG_SYSFS_DEPRECATED_V2=y # CONFIG_RELAY is not set @@ -61,31 +68,37 @@ CONFIG_NAMESPACES=y # CONFIG_IPC_NS is not set # CONFIG_USER_NS is not set # CONFIG_PID_NS is not set +# CONFIG_NET_NS is not set CONFIG_BLK_DEV_INITRD=y CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +CONFIG_RD_BZIP2=y +CONFIG_RD_LZMA=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y # CONFIG_EMBEDDED is not set CONFIG_UID16=y CONFIG_SYSCTL_SYSCALL=y CONFIG_KALLSYMS=y # CONFIG_KALLSYMS_ALL is not set # CONFIG_KALLSYMS_EXTRA_PASS is not set +# CONFIG_STRIP_ASM_SYMS is not set CONFIG_HOTPLUG=y CONFIG_PRINTK=y CONFIG_BUG=y CONFIG_ELF_CORE=y -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_AIO=y CONFIG_VM_EVENT_COUNTERS=y CONFIG_SLUB_DEBUG=y +CONFIG_COMPAT_BRK=y # CONFIG_SLAB is not set CONFIG_SLUB=y # CONFIG_SLOB is not set @@ -93,19 +106,13 @@ CONFIG_SLUB=y # CONFIG_MARKERS is not set CONFIG_HAVE_OPROFILE=y # CONFIG_KPROBES is not set -# CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS is not set -# CONFIG_HAVE_IOREMAP_PROT is not set CONFIG_HAVE_KPROBES=y CONFIG_HAVE_KRETPROBES=y -# CONFIG_HAVE_ARCH_TRACEHOOK is not set -# CONFIG_HAVE_DMA_ATTRS is not set -# CONFIG_USE_GENERIC_SMP_HELPERS is not set CONFIG_HAVE_CLK=y -CONFIG_PROC_PAGE_MONITOR=y +# CONFIG_SLOW_WORK is not set CONFIG_HAVE_GENERIC_DMA_COHERENT=y CONFIG_SLABINFO=y CONFIG_RT_MUTEXES=y -# CONFIG_TINY_SHMEM is not set CONFIG_BASE_SMALL=0 CONFIG_MODULES=y # CONFIG_MODULE_FORCE_LOAD is not set @@ -113,11 +120,8 @@ 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=y 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 # CONFIG_BLK_DEV_INTEGRITY is not set @@ -133,7 +137,7 @@ CONFIG_IOSCHED_CFQ=y CONFIG_DEFAULT_CFQ=y # CONFIG_DEFAULT_NOOP is not set CONFIG_DEFAULT_IOSCHED="cfq" -CONFIG_CLASSIC_RCU=y +CONFIG_FREEZER=y # # System Type @@ -143,10 +147,10 @@ CONFIG_CLASSIC_RCU=y # CONFIG_ARCH_REALVIEW is not set # CONFIG_ARCH_VERSATILE is not set # CONFIG_ARCH_AT91 is not set -# CONFIG_ARCH_CLPS7500 is not set # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_EBSA110 is not set # CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_GEMINI is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_NETX is not set # CONFIG_ARCH_H720X is not set @@ -167,14 +171,17 @@ CONFIG_CLASSIC_RCU=y # CONFIG_ARCH_ORION5X is not set # CONFIG_ARCH_PNX4008 is not set CONFIG_ARCH_PXA=y +# CONFIG_ARCH_MMP is not set # CONFIG_ARCH_RPC is not set # CONFIG_ARCH_SA1100 is not set # CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_S3C64XX is not set # CONFIG_ARCH_SHARK is not set # CONFIG_ARCH_LH7A40X is not set # CONFIG_ARCH_DAVINCI is not set # CONFIG_ARCH_OMAP is not set -# CONFIG_ARCH_MSM7X00A is not set +# CONFIG_ARCH_MSM is not set +# CONFIG_ARCH_W90X900 is not set # # Intel PXA2xx/PXA3xx Implementations @@ -187,16 +194,24 @@ CONFIG_CPU_PXA300=y # CONFIG_CPU_PXA310 is not set # CONFIG_CPU_PXA320 is not set # CONFIG_CPU_PXA930 is not set +# CONFIG_CPU_PXA935 is not set # CONFIG_ARCH_GUMSTIX is not set +# CONFIG_MACH_INTELMOTE2 is not set # CONFIG_ARCH_LUBBOCK is not set # CONFIG_MACH_LOGICPD_PXA270 is not set # CONFIG_MACH_MAINSTONE is not set +# CONFIG_MACH_MP900C is not set # CONFIG_ARCH_PXA_IDP is not set # CONFIG_PXA_SHARPSL is not set +# CONFIG_ARCH_VIPER is not set # CONFIG_ARCH_PXA_ESERIES is not set -# CONFIG_MACH_TRIZEPS4 is not set +# CONFIG_TRIZEPS_PXA is not set +# CONFIG_MACH_H5000 is not set # CONFIG_MACH_EM_X270 is not set +# CONFIG_MACH_EXEDA is not set # CONFIG_MACH_COLIBRI is not set +# CONFIG_MACH_COLIBRI300 is not set +# CONFIG_MACH_COLIBRI320 is not set # CONFIG_MACH_ZYLONITE is not set # CONFIG_MACH_LITTLETON is not set # CONFIG_MACH_TAVOREVB is not set @@ -204,19 +219,15 @@ CONFIG_CPU_PXA300=y # CONFIG_MACH_ARMCORE is not set CONFIG_MACH_CM_X300=y # CONFIG_MACH_MAGICIAN is not set +# CONFIG_MACH_HIMALAYA is not set +# CONFIG_MACH_MIOA701 is not set # CONFIG_MACH_PCM027 is not set # CONFIG_ARCH_PXA_PALM is not set +# CONFIG_MACH_CSB726 is not set # CONFIG_PXA_EZX is not set CONFIG_PXA3xx=y # CONFIG_PXA_PWM is not set - -# -# Boot options -# - -# -# Power management -# +CONFIG_PLAT_PXA=y # # Processor Type @@ -241,6 +252,7 @@ CONFIG_IO_36=y CONFIG_OUTER_CACHE=y CONFIG_CACHE_XSC3L2=y CONFIG_IWMMXT=y +CONFIG_COMMON_CLKDEV=y # # Bus support @@ -256,25 +268,33 @@ CONFIG_TICK_ONESHOT=y CONFIG_NO_HZ=y # CONFIG_HIGH_RES_TIMERS is not set CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_1G is not set +CONFIG_PAGE_OFFSET=0xC0000000 # CONFIG_PREEMPT is not set CONFIG_HZ=100 CONFIG_AEABI=y CONFIG_OABI_COMPAT=y -# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set +# CONFIG_ARCH_HAS_HOLES_MEMORYMODEL is not set +# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set +# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set +CONFIG_HIGHMEM=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_PAGEFLAGS_EXTENDED=y CONFIG_SPLIT_PTLOCK_CPUS=4096 -# CONFIG_RESOURCES_64BIT is not set -CONFIG_ZONE_DMA_FLAG=1 +# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 CONFIG_BOUNCE=y CONFIG_VIRT_TO_BUS=y +CONFIG_UNEVICTABLE_LRU=y +CONFIG_HAVE_MLOCK=y +CONFIG_HAVE_MLOCKED_PAGE_BIT=y CONFIG_ALIGNMENT_TRAP=y # @@ -287,7 +307,7 @@ CONFIG_CMDLINE="root=/dev/mtdblock5 rootfstype=jffs2 console=ttyS2,38400" # CONFIG_KEXEC is not set # -# CPU Frequency scaling +# CPU Power Management # CONFIG_CPU_FREQ=y CONFIG_CPU_FREQ_TABLE=y @@ -304,6 +324,7 @@ CONFIG_CPU_FREQ_GOV_PERFORMANCE=y CONFIG_CPU_FREQ_GOV_USERSPACE=y # CONFIG_CPU_FREQ_GOV_ONDEMAND is not set # CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set +# CONFIG_CPU_IDLE is not set # # Floating point emulation @@ -320,6 +341,8 @@ CONFIG_FPE_NWFPE=y # Userspace binary formats # CONFIG_BINFMT_ELF=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_HAVE_AOUT=y # CONFIG_BINFMT_AOUT is not set # CONFIG_BINFMT_MISC is not set @@ -376,6 +399,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic" # CONFIG_TIPC is not set # CONFIG_ATM is not set # CONFIG_BRIDGE is not set +# CONFIG_NET_DSA is not set # CONFIG_VLAN_8021Q is not set # CONFIG_DECNET is not set # CONFIG_LLC2 is not set @@ -385,7 +409,9 @@ CONFIG_DEFAULT_TCP_CONG="cubic" # CONFIG_LAPB is not set # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set +# CONFIG_PHONET is not set # CONFIG_NET_SCHED is not set +# CONFIG_DCB is not set # # Network testing @@ -407,8 +433,7 @@ CONFIG_BT_HIDP=m # # Bluetooth device drivers # -CONFIG_BT_HCIUSB=m -CONFIG_BT_HCIUSB_SCO=y +# CONFIG_BT_HCIBTUSB is not set # CONFIG_BT_HCIBTSDIO is not set # CONFIG_BT_HCIUART is not set # CONFIG_BT_HCIBCM203X is not set @@ -416,19 +441,15 @@ CONFIG_BT_HCIUSB_SCO=y # CONFIG_BT_HCIBFUSB is not set # CONFIG_BT_HCIVHCI is not set # CONFIG_AF_RXRPC is not set - -# -# Wireless -# +CONFIG_WIRELESS=y # CONFIG_CFG80211 is not set +# CONFIG_WIRELESS_OLD_REGULATORY is not set CONFIG_WIRELESS_EXT=y CONFIG_WIRELESS_EXT_SYSFS=y +CONFIG_LIB80211=m +# CONFIG_LIB80211_DEBUG is not set # CONFIG_MAC80211 is not set -CONFIG_IEEE80211=m -# CONFIG_IEEE80211_DEBUG is not set -CONFIG_IEEE80211_CRYPT_WEP=m -CONFIG_IEEE80211_CRYPT_CCMP=m -CONFIG_IEEE80211_CRYPT_TKIP=m +# CONFIG_WIMAX is not set # CONFIG_RFKILL is not set # CONFIG_NET_9P is not set @@ -453,6 +474,7 @@ CONFIG_MTD=y # CONFIG_MTD_DEBUG is not set # CONFIG_MTD_CONCAT is not set CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_TESTS is not set # CONFIG_MTD_REDBOOT_PARTS is not set # CONFIG_MTD_CMDLINE_PARTS is not set # CONFIG_MTD_AFS_PARTS is not set @@ -494,7 +516,6 @@ CONFIG_MTD_CFI_I2=y # Mapping drivers for chip access # # CONFIG_MTD_COMPLEX_MAPPINGS is not set -# CONFIG_MTD_SHARP_SL is not set # CONFIG_MTD_PLATRAM is not set # @@ -516,15 +537,22 @@ CONFIG_MTD_NAND=y # CONFIG_MTD_NAND_ECC_SMC is not set # CONFIG_MTD_NAND_MUSEUM_IDS is not set # CONFIG_MTD_NAND_H1900 is not set +# CONFIG_MTD_NAND_GPIO is not set CONFIG_MTD_NAND_IDS=y # CONFIG_MTD_NAND_DISKONCHIP is not set # CONFIG_MTD_NAND_SHARPSL is not set CONFIG_MTD_NAND_PXA3xx=y +# CONFIG_MTD_NAND_PXA3xx_BUILTIN is not set # CONFIG_MTD_NAND_NANDSIM is not set # CONFIG_MTD_NAND_PLATFORM is not set # CONFIG_MTD_ALAUDA is not set # CONFIG_MTD_ONENAND is not set +# +# LPDDR flash memory drivers +# +# CONFIG_MTD_LPDDR is not set + # # UBI - Unsorted block images # @@ -585,11 +613,15 @@ CONFIG_SCSI_WAIT_SCAN=m # CONFIG_SCSI_SRP_ATTRS is not set CONFIG_SCSI_LOWLEVEL=y # CONFIG_ISCSI_TCP is not set +# CONFIG_LIBFC is not set +# CONFIG_LIBFCOE is not set # CONFIG_SCSI_DEBUG is not set # CONFIG_SCSI_DH is not set +# CONFIG_SCSI_OSD_INITIATOR is not set # CONFIG_ATA is not set # CONFIG_MD is not set CONFIG_NETDEVICES=y +CONFIG_COMPAT_NET_DEV_OPS=y # CONFIG_DUMMY is not set # CONFIG_BONDING is not set # CONFIG_MACVLAN is not set @@ -604,11 +636,17 @@ CONFIG_MII=y CONFIG_DM9000=y CONFIG_DM9000_DEBUGLEVEL=0 CONFIG_DM9000_FORCE_SIMPLE_PHY_POLL=y +# CONFIG_ETHOC is not set # CONFIG_SMC911X is not set +# CONFIG_SMSC911X is not set +# CONFIG_DNET 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_IBM_NEW_EMAC_NO_FLOW_CTRL is not set +# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set +# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set # CONFIG_B44 is not set # CONFIG_NETDEV_1000 is not set # CONFIG_NETDEV_10000 is not set @@ -624,9 +662,12 @@ CONFIG_LIBERTAS_SDIO=m # CONFIG_LIBERTAS_DEBUG is not set # CONFIG_USB_ZD1201 is not set # CONFIG_USB_NET_RNDIS_WLAN is not set -# CONFIG_IWLWIFI_LEDS is not set # CONFIG_HOSTAP is not set +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# + # # USB Network Adapters # @@ -677,18 +718,21 @@ CONFIG_KEYBOARD_PXA27x=m # CONFIG_INPUT_JOYSTICK is not set # CONFIG_INPUT_TABLET is not set CONFIG_INPUT_TOUCHSCREEN=y +# CONFIG_TOUCHSCREEN_AD7879_I2C is not set +# CONFIG_TOUCHSCREEN_AD7879 is not set # CONFIG_TOUCHSCREEN_FUJITSU is not set # CONFIG_TOUCHSCREEN_GUNZE is not set # CONFIG_TOUCHSCREEN_ELO is not set +# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set # CONFIG_TOUCHSCREEN_MTOUCH is not set # CONFIG_TOUCHSCREEN_INEXIO is not set # CONFIG_TOUCHSCREEN_MK712 is not set # CONFIG_TOUCHSCREEN_PENMOUNT is not set # CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set # CONFIG_TOUCHSCREEN_TOUCHWIN is not set -# CONFIG_TOUCHSCREEN_UCB1400 is not set # CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set # CONFIG_TOUCHSCREEN_TOUCHIT213 is not set +# CONFIG_TOUCHSCREEN_TSC2007 is not set # CONFIG_INPUT_MISC is not set # @@ -721,10 +765,10 @@ CONFIG_SERIAL_PXA_CONSOLE=y CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_UNIX98_PTYS=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set # CONFIG_LEGACY_PTYS is not set # CONFIG_IPMI_HANDLER is not set # CONFIG_HW_RANDOM is not set -# CONFIG_NVRAM is not set # CONFIG_R3964 is not set # CONFIG_RAW_DRIVER is not set # CONFIG_TCG_TPM is not set @@ -763,12 +807,8 @@ CONFIG_I2C_PXA=y # Miscellaneous I2C Chip support # # CONFIG_DS1682 is not set -# CONFIG_EEPROM_AT24 is not set -# CONFIG_EEPROM_LEGACY is not set # CONFIG_SENSORS_PCF8574 is not set # CONFIG_PCF8575 is not set -# CONFIG_SENSORS_PCF8591 is not set -# CONFIG_TPS65010 is not set # CONFIG_SENSORS_MAX6875 is not set # CONFIG_SENSORS_TSL2550 is not set # CONFIG_I2C_DEBUG_CORE is not set @@ -781,6 +821,10 @@ CONFIG_GPIOLIB=y # CONFIG_DEBUG_GPIO is not set # CONFIG_GPIO_SYSFS is not set +# +# Memory mapped GPIO expanders: +# + # # I2C GPIO expanders: # @@ -798,12 +842,14 @@ CONFIG_GPIO_PCA953X=y # CONFIG_W1 is not set # CONFIG_POWER_SUPPLY is not set # CONFIG_HWMON is not set +# CONFIG_THERMAL is not set +# CONFIG_THERMAL_HWMON is not set # CONFIG_WATCHDOG is not set +CONFIG_SSB_POSSIBLE=y # # Sonics Silicon Backplane # -CONFIG_SSB_POSSIBLE=y # CONFIG_SSB is not set # @@ -811,12 +857,19 @@ CONFIG_SSB_POSSIBLE=y # # CONFIG_MFD_CORE is not set # CONFIG_MFD_SM501 is not set +# CONFIG_MFD_ASIC3 is not set # CONFIG_HTC_EGPIO is not set # CONFIG_HTC_PASIC3 is not set +# CONFIG_TPS65010 is not set +# CONFIG_TWL4030_CORE is not set # CONFIG_MFD_TMIO is not set # CONFIG_MFD_T7L66XB is not set # CONFIG_MFD_TC6387XB is not set # CONFIG_MFD_TC6393XB is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_PCF50633 is not set # # Multimedia devices @@ -842,6 +895,7 @@ CONFIG_SSB_POSSIBLE=y CONFIG_FB=y # CONFIG_FIRMWARE_EDID is not set # CONFIG_FB_DDC is not set +# CONFIG_FB_BOOT_VESA_SUPPORT is not set CONFIG_FB_CFB_FILLRECT=y CONFIG_FB_CFB_COPYAREA=y CONFIG_FB_CFB_IMAGEBLIT=y @@ -862,12 +916,15 @@ CONFIG_FB_CFB_IMAGEBLIT=y # # CONFIG_FB_S1D13XXX is not set CONFIG_FB_PXA=y +# CONFIG_FB_PXA_OVERLAY is not set # CONFIG_FB_PXA_SMARTPANEL is not set # CONFIG_FB_PXA_PARAMETERS is not set # CONFIG_FB_MBX is not set # CONFIG_FB_W100 is not set -# CONFIG_FB_AM200EPD is not set # CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_MB862XX is not set +# CONFIG_FB_BROADSHEET is not set # CONFIG_BACKLIGHT_LCD_SUPPORT is not set # @@ -899,9 +956,11 @@ CONFIG_LOGO_LINUX_MONO=y CONFIG_LOGO_LINUX_VGA16=y CONFIG_LOGO_LINUX_CLUT224=y CONFIG_SOUND=m +# CONFIG_SOUND_OSS_CORE is not set CONFIG_SND=m CONFIG_SND_TIMER=m CONFIG_SND_PCM=m +CONFIG_SND_JACK=y # CONFIG_SND_SEQUENCER is not set # CONFIG_SND_MIXER_OSS is not set # CONFIG_SND_PCM_OSS is not set @@ -916,12 +975,15 @@ CONFIG_SND_DRIVERS=y # CONFIG_SND_SERIAL_U16550 is not set # CONFIG_SND_MPU401 is not set CONFIG_SND_ARM=y +CONFIG_SND_PXA2XX_LIB=m # CONFIG_SND_PXA2XX_AC97 is not set CONFIG_SND_USB=y # CONFIG_SND_USB_AUDIO is not set # CONFIG_SND_USB_CAIAQ is not set CONFIG_SND_SOC=m CONFIG_SND_PXA2XX_SOC=m +CONFIG_SND_SOC_I2C_AND_SPI=m +# CONFIG_SND_SOC_ALL_CODECS is not set # CONFIG_SOUND_PRIME is not set CONFIG_HID_SUPPORT=y CONFIG_HID=y @@ -932,9 +994,39 @@ CONFIG_HID_DEBUG=y # USB Input Devices # CONFIG_USB_HID=y -# CONFIG_USB_HIDINPUT_POWERBOOK is not set -# CONFIG_HID_FF is not set +# CONFIG_HID_PID is not set # CONFIG_USB_HIDDEV is not set + +# +# Special HID drivers +# +CONFIG_HID_A4TECH=y +CONFIG_HID_APPLE=y +CONFIG_HID_BELKIN=y +CONFIG_HID_CHERRY=y +CONFIG_HID_CHICONY=y +CONFIG_HID_CYPRESS=y +# CONFIG_DRAGONRISE_FF is not set +CONFIG_HID_EZKEY=y +CONFIG_HID_KYE=y +CONFIG_HID_GYRATION=y +CONFIG_HID_KENSINGTON=y +CONFIG_HID_LOGITECH=y +# CONFIG_LOGITECH_FF is not set +# CONFIG_LOGIRUMBLEPAD2_FF is not set +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MONTEREY=y +CONFIG_HID_NTRIG=y +CONFIG_HID_PANTHERLORD=y +# CONFIG_PANTHERLORD_FF is not set +CONFIG_HID_PETALYNX=y +CONFIG_HID_SAMSUNG=y +CONFIG_HID_SONY=y +CONFIG_HID_SUNPLUS=y +# CONFIG_GREENASIA_FF is not set +CONFIG_HID_TOPSEED=y +# CONFIG_THRUSTMASTER_FF is not set +# CONFIG_ZEROPLUS_FF is not set CONFIG_USB_SUPPORT=y CONFIG_USB_ARCH_HAS_HCD=y CONFIG_USB_ARCH_HAS_OHCI=y @@ -952,11 +1044,14 @@ CONFIG_USB_DEVICEFS=y # CONFIG_USB_SUSPEND is not set # CONFIG_USB_OTG is not set CONFIG_USB_MON=y +# CONFIG_USB_WUSB is not set +# CONFIG_USB_WUSB_CBAF is not set # # USB Host Controller Drivers # # CONFIG_USB_C67X00_HCD is not set +# CONFIG_USB_OXU210HP_HCD is not set # CONFIG_USB_ISP116X_HCD is not set # CONFIG_USB_ISP1760_HCD is not set CONFIG_USB_OHCI_HCD=y @@ -965,6 +1060,7 @@ CONFIG_USB_OHCI_HCD=y CONFIG_USB_OHCI_LITTLE_ENDIAN=y # CONFIG_USB_SL811_HCD is not set # CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_HWA_HCD is not set # CONFIG_USB_MUSB_HDRC is not set # @@ -973,20 +1069,20 @@ CONFIG_USB_OHCI_LITTLE_ENDIAN=y # CONFIG_USB_ACM is not set # CONFIG_USB_PRINTER is not set # CONFIG_USB_WDM is not set +# CONFIG_USB_TMC is not set # -# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may # # -# may also be needed; see USB_STORAGE Help for more information +# also be needed; see USB_STORAGE Help for more info # CONFIG_USB_STORAGE=y # CONFIG_USB_STORAGE_DEBUG is not set # CONFIG_USB_STORAGE_DATAFAB is not set # CONFIG_USB_STORAGE_FREECOM is not set # CONFIG_USB_STORAGE_ISD200 is not set -# CONFIG_USB_STORAGE_DPCM is not set # CONFIG_USB_STORAGE_USBAT is not set # CONFIG_USB_STORAGE_SDDR09 is not set # CONFIG_USB_STORAGE_SDDR55 is not set @@ -994,7 +1090,6 @@ CONFIG_USB_STORAGE=y # CONFIG_USB_STORAGE_ALAUDA is not set # CONFIG_USB_STORAGE_ONETOUCH is not set # CONFIG_USB_STORAGE_KARMA is not set -# CONFIG_USB_STORAGE_SIERRA is not set # CONFIG_USB_STORAGE_CYPRESS_ATACB is not set # CONFIG_USB_LIBUSUAL is not set @@ -1015,6 +1110,7 @@ CONFIG_USB_STORAGE=y # CONFIG_USB_EMI62 is not set # CONFIG_USB_EMI26 is not set # CONFIG_USB_ADUTUX is not set +# CONFIG_USB_SEVSEG is not set # CONFIG_USB_RIO500 is not set # CONFIG_USB_LEGOTOWER is not set # CONFIG_USB_LCD is not set @@ -1022,7 +1118,6 @@ CONFIG_USB_STORAGE=y # CONFIG_USB_LED is not set # CONFIG_USB_CYPRESS_CY7C63 is not set # CONFIG_USB_CYTHERM is not set -# CONFIG_USB_PHIDGET is not set # CONFIG_USB_IDMOUSE is not set # CONFIG_USB_FTDI_ELAN is not set # CONFIG_USB_APPLEDISPLAY is not set @@ -1031,13 +1126,20 @@ CONFIG_USB_STORAGE=y # CONFIG_USB_IOWARRIOR is not set # CONFIG_USB_TEST is not set # CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_VST is not set # CONFIG_USB_GADGET is not set + +# +# OTG and related infrastructure +# +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_NOP_USB_XCEIV is not set CONFIG_MMC=m # CONFIG_MMC_DEBUG is not set # CONFIG_MMC_UNSAFE_RESUME is not set # -# MMC/SD Card Drivers +# MMC/SD/SDIO Card Drivers # CONFIG_MMC_BLOCK=m CONFIG_MMC_BLOCK_BOUNCE=y @@ -1045,10 +1147,12 @@ CONFIG_MMC_BLOCK_BOUNCE=y # CONFIG_MMC_TEST is not set # -# MMC/SD Host Controller Drivers +# MMC/SD/SDIO Host Controller Drivers # CONFIG_MMC_PXA=m # CONFIG_MMC_SDHCI is not set +# CONFIG_MEMSTICK is not set +# CONFIG_ACCESSIBILITY is not set CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y @@ -1057,7 +1161,10 @@ CONFIG_LEDS_CLASS=y # # CONFIG_LEDS_PCA9532 is not set CONFIG_LEDS_GPIO=y +CONFIG_LEDS_GPIO_PLATFORM=y +# CONFIG_LEDS_LP5521 is not set # CONFIG_LEDS_PCA955X is not set +# CONFIG_LEDS_BD2802 is not set # # LED Triggers @@ -1065,7 +1172,13 @@ CONFIG_LEDS_GPIO=y CONFIG_LEDS_TRIGGERS=y # CONFIG_LEDS_TRIGGER_TIMER is not set CONFIG_LEDS_TRIGGER_HEARTBEAT=y +# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set +# CONFIG_LEDS_TRIGGER_GPIO is not set # CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set + +# +# iptables trigger is under Netfilter config (LED target) +# CONFIG_RTC_LIB=y CONFIG_RTC_CLASS=y CONFIG_RTC_HCTOSYS=y @@ -1096,6 +1209,7 @@ CONFIG_RTC_INTF_DEV=y # CONFIG_RTC_DRV_M41T80 is not set # CONFIG_RTC_DRV_S35390A is not set # CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8581 is not set # # SPI RTC drivers @@ -1105,28 +1219,27 @@ CONFIG_RTC_INTF_DEV=y # Platform RTC drivers # # CONFIG_RTC_DRV_CMOS is not set +# CONFIG_RTC_DRV_DS1286 is not set # CONFIG_RTC_DRV_DS1511 is not set # CONFIG_RTC_DRV_DS1553 is not set # CONFIG_RTC_DRV_DS1742 is not set # CONFIG_RTC_DRV_STK17TA8 is not set # CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set # CONFIG_RTC_DRV_M48T59 is not set -# CONFIG_RTC_DRV_V3020 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +CONFIG_RTC_DRV_V3020=y # # on-CPU RTC drivers # CONFIG_RTC_DRV_SA1100=y +# CONFIG_RTC_DRV_PXA is not set # CONFIG_DMADEVICES is not set - -# -# Voltage and Current regulators -# +# CONFIG_AUXDISPLAY is not set # CONFIG_REGULATOR is not set -# CONFIG_REGULATOR_FIXED_VOLTAGE is not set -# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set -# CONFIG_REGULATOR_BQ24022 is not set # CONFIG_UIO is not set +# CONFIG_STAGING is not set # # File systems @@ -1135,15 +1248,18 @@ CONFIG_EXT2_FS=y # CONFIG_EXT2_FS_XATTR is not set # CONFIG_EXT2_FS_XIP is not set CONFIG_EXT3_FS=y +# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set # CONFIG_EXT3_FS_XATTR is not set -# CONFIG_EXT4DEV_FS is not set +# CONFIG_EXT4_FS is not set CONFIG_JBD=y # CONFIG_JBD_DEBUG is not set # CONFIG_REISERFS_FS is not set # CONFIG_JFS_FS is not set CONFIG_FS_POSIX_ACL=y +CONFIG_FILE_LOCKING=y # CONFIG_XFS_FS is not set # CONFIG_OCFS2_FS is not set +# CONFIG_BTRFS_FS is not set CONFIG_DNOTIFY=y CONFIG_INOTIFY=y CONFIG_INOTIFY_USER=y @@ -1152,6 +1268,11 @@ CONFIG_INOTIFY_USER=y # CONFIG_AUTOFS4_FS is not set # CONFIG_FUSE_FS is not set +# +# Caches +# +# CONFIG_FSCACHE is not set + # # CD-ROM/DVD Filesystems # @@ -1173,15 +1294,13 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" # CONFIG_PROC_FS=y CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y CONFIG_SYSFS=y CONFIG_TMPFS=y # CONFIG_TMPFS_POSIX_ACL is not set # CONFIG_HUGETLB_PAGE is not set # CONFIG_CONFIGFS_FS is not set - -# -# Miscellaneous filesystems -# +CONFIG_MISC_FILESYSTEMS=y # CONFIG_ADFS_FS is not set # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set @@ -1201,6 +1320,7 @@ CONFIG_JFFS2_ZLIB=y CONFIG_JFFS2_RTIME=y # CONFIG_JFFS2_RUBIN is not set # CONFIG_CRAMFS is not set +# CONFIG_SQUASHFS is not set # CONFIG_VXFS_FS is not set # CONFIG_MINIX_FS is not set # CONFIG_OMFS_FS is not set @@ -1209,6 +1329,7 @@ CONFIG_JFFS2_RTIME=y # CONFIG_ROMFS_FS is not set # CONFIG_SYSV_FS is not set # CONFIG_UFS_FS is not set +# CONFIG_NILFS2_FS is not set CONFIG_NETWORK_FILESYSTEMS=y CONFIG_NFS_FS=y CONFIG_NFS_V3=y @@ -1313,6 +1434,7 @@ CONFIG_DEBUG_FS=y CONFIG_DEBUG_KERNEL=y # CONFIG_DEBUG_SHIRQ is not set # CONFIG_DETECT_SOFTLOCKUP is not set +# CONFIG_DETECT_HUNG_TASK is not set # CONFIG_SCHED_DEBUG is not set # CONFIG_SCHEDSTATS is not set # CONFIG_TIMER_STATS is not set @@ -1329,6 +1451,7 @@ CONFIG_DEBUG_KERNEL=y # CONFIG_DEBUG_SPINLOCK_SLEEP is not set # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set # CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_HIGHMEM is not set CONFIG_DEBUG_BUGVERBOSE=y # CONFIG_DEBUG_INFO is not set # CONFIG_DEBUG_VM is not set @@ -1336,22 +1459,38 @@ CONFIG_DEBUG_BUGVERBOSE=y CONFIG_DEBUG_MEMORY_INIT=y # CONFIG_DEBUG_LIST is not set # CONFIG_DEBUG_SG is not set -CONFIG_FRAME_POINTER=y +# CONFIG_DEBUG_NOTIFIERS is not set # CONFIG_BOOT_PRINTK_DELAY is not set # CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_RCU_CPU_STALL_DETECTOR is not set # CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set # CONFIG_FAULT_INJECTION is not set # CONFIG_LATENCYTOP is not set CONFIG_SYSCTL_SYSCALL_CHECK=y -CONFIG_HAVE_FTRACE=y -CONFIG_HAVE_DYNAMIC_FTRACE=y -# CONFIG_FTRACE is not set +# CONFIG_PAGE_POISONING is not set +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_TRACING_SUPPORT=y + +# +# Tracers +# +# CONFIG_FUNCTION_TRACER is not set # CONFIG_IRQSOFF_TRACER is not set # CONFIG_SCHED_TRACER is not set # CONFIG_CONTEXT_SWITCH_TRACER is not set +# CONFIG_EVENT_TRACER is not set +# CONFIG_BOOT_TRACER is not set +# CONFIG_TRACE_BRANCH_PROFILING is not set +# CONFIG_STACK_TRACER is not set +# CONFIG_KMEMTRACE is not set +# CONFIG_WORKQUEUE_TRACER is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_DYNAMIC_DEBUG is not set # CONFIG_SAMPLES is not set CONFIG_HAVE_ARCH_KGDB=y # CONFIG_KGDB is not set +CONFIG_ARM_UNWIND=y CONFIG_DEBUG_USER=y # CONFIG_DEBUG_ERRORS is not set # CONFIG_DEBUG_STACK_USAGE is not set @@ -1363,17 +1502,28 @@ CONFIG_DEBUG_LL=y # # CONFIG_KEYS is not set # CONFIG_SECURITY is not set +# CONFIG_SECURITYFS is not set # CONFIG_SECURITY_FILE_CAPABILITIES is not set CONFIG_CRYPTO=y # # Crypto core or helper # +# CONFIG_CRYPTO_FIPS is not set CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD2=y CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_BLKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_PCOMP=y CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y # CONFIG_CRYPTO_GF128MUL is not set # CONFIG_CRYPTO_NULL is not set +CONFIG_CRYPTO_WORKQUEUE=y # CONFIG_CRYPTO_CRYPTD is not set # CONFIG_CRYPTO_AUTHENC is not set # CONFIG_CRYPTO_TEST is not set @@ -1442,15 +1592,21 @@ CONFIG_CRYPTO_DES=y # Compression # # CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_ZLIB is not set # CONFIG_CRYPTO_LZO is not set + +# +# Random Number Generation +# +# CONFIG_CRYPTO_ANSI_CPRNG is not set # CONFIG_CRYPTO_HW is not set +# CONFIG_BINARY_PRINTF is not set # # Library routines # CONFIG_BITREVERSE=y -# CONFIG_GENERIC_FIND_FIRST_BIT is not set -# CONFIG_GENERIC_FIND_NEXT_BIT is not set +CONFIG_GENERIC_FIND_LAST_BIT=y # CONFIG_CRC_CCITT is not set # CONFIG_CRC16 is not set CONFIG_CRC_T10DIF=y @@ -1460,7 +1616,10 @@ CONFIG_CRC32=y # CONFIG_LIBCRC32C is not set CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=y -CONFIG_PLIST=y +CONFIG_DECOMPRESS_GZIP=y +CONFIG_DECOMPRESS_BZIP2=y +CONFIG_DECOMPRESS_LZMA=y CONFIG_HAS_IOMEM=y CONFIG_HAS_IOPORT=y CONFIG_HAS_DMA=y +CONFIG_NLATTR=y diff --git a/arch/arm/configs/davinci_all_defconfig b/arch/arm/configs/davinci_all_defconfig index eb2738b5be5f..ac18662f38cc 100644 --- a/arch/arm/configs/davinci_all_defconfig +++ b/arch/arm/configs/davinci_all_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.30-rc2 -# Wed Apr 15 08:16:53 2009 +# Linux kernel version: 2.6.30-rc7 +# Tue May 26 07:24:28 2009 # CONFIG_ARM=y CONFIG_SYS_SUPPORTS_APM_EMULATION=y @@ -179,6 +179,7 @@ CONFIG_ARCH_DAVINCI=y # CONFIG_ARCH_OMAP is not set # CONFIG_ARCH_MSM is not set # CONFIG_ARCH_W90X900 is not set +CONFIG_AINTC=y # # TI DaVinci Implementations @@ -188,11 +189,17 @@ CONFIG_ARCH_DAVINCI=y # DaVinci Core Type # CONFIG_ARCH_DAVINCI_DM644x=y +CONFIG_ARCH_DAVINCI_DM355=y +CONFIG_ARCH_DAVINCI_DM646x=y # # DaVinci Board Type # CONFIG_MACH_DAVINCI_EVM=y +CONFIG_MACH_SFFSDR=y +CONFIG_MACH_DAVINCI_DM355_EVM=y +CONFIG_MACH_DM355_LEOPARD=y +CONFIG_MACH_DAVINCI_DM6467_EVM=y CONFIG_DAVINCI_MUX=y CONFIG_DAVINCI_MUX_DEBUG=y CONFIG_DAVINCI_MUX_WARNINGS=y @@ -245,7 +252,7 @@ CONFIG_PREEMPT=y CONFIG_HZ=100 CONFIG_AEABI=y # CONFIG_OABI_COMPAT is not set -CONFIG_ARCH_FLATMEM_HAS_HOLES=y +# CONFIG_ARCH_HAS_HOLES_MEMORYMODEL is not set # CONFIG_ARCH_SPARSEMEM_DEFAULT is not set # CONFIG_ARCH_SELECT_MEMORY_MODEL is not set # CONFIG_HIGHMEM is not set @@ -661,7 +668,10 @@ CONFIG_NET_ETHERNET=y CONFIG_MII=y # CONFIG_AX88796 is not set # CONFIG_SMC91X is not set -# CONFIG_DM9000 is not set +CONFIG_TI_DAVINCI_EMAC=y +CONFIG_DM9000=y +CONFIG_DM9000_DEBUGLEVEL=4 +# CONFIG_DM9000_FORCE_SIMPLE_PHY_POLL is not set # CONFIG_ETHOC is not set # CONFIG_SMC911X is not set # CONFIG_SMSC911X is not set @@ -963,6 +973,7 @@ CONFIG_SSB_POSSIBLE=y # CONFIG_MFD_CORE is not set # CONFIG_MFD_SM501 is not set # CONFIG_MFD_ASIC3 is not set +# CONFIG_MFD_DM355EVM_MSP is not set # CONFIG_HTC_EGPIO is not set # CONFIG_HTC_PASIC3 is not set # CONFIG_TPS65010 is not set @@ -1317,6 +1328,7 @@ CONFIG_MMC_BLOCK=m # MMC/SD/SDIO Host Controller Drivers # # CONFIG_MMC_SDHCI is not set +# CONFIG_MMC_DAVINCI is not set # CONFIG_MEMSTICK is not set # CONFIG_ACCESSIBILITY is not set CONFIG_NEW_LEDS=y @@ -1778,6 +1790,7 @@ CONFIG_CRC32=y CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=m CONFIG_DECOMPRESS_GZIP=y +CONFIG_GENERIC_ALLOCATOR=y CONFIG_HAS_IOMEM=y CONFIG_HAS_IOPORT=y CONFIG_HAS_DMA=y diff --git a/arch/arm/configs/ep93xx_defconfig b/arch/arm/configs/ep93xx_defconfig index 3f89d5f25bce..3fb083b81b0a 100644 --- a/arch/arm/configs/ep93xx_defconfig +++ b/arch/arm/configs/ep93xx_defconfig @@ -1,12 +1,19 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.20-rc1 -# Sat Dec 16 06:05:24 2006 +# Linux kernel version: 2.6.30-rc3 +# Tue May 19 12:26:49 2009 # CONFIG_ARM=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_GENERIC_GPIO=y # CONFIG_GENERIC_TIME is not set +# CONFIG_GENERIC_CLOCKEVENTS is not set CONFIG_MMU=y +# CONFIG_NO_IOPORT is not set CONFIG_GENERIC_HARDIRQS=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_HAVE_LATENCYTOP_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y CONFIG_TRACE_IRQFLAGS_SUPPORT=y CONFIG_HARDIRQS_SW_RESEND=y CONFIG_GENERIC_IRQ_PROBE=y @@ -15,42 +22,54 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_ARCH_HAS_ILOG2_U64 is not set CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y CONFIG_VECTORS_BASE=0xffff0000 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" # -# Code maturity level options +# General setup # CONFIG_EXPERIMENTAL=y CONFIG_BROKEN_ON_SMP=y CONFIG_INIT_ENV_ARG_LIMIT=32 - -# -# General setup -# CONFIG_LOCALVERSION="" CONFIG_LOCALVERSION_AUTO=y CONFIG_SWAP=y CONFIG_SYSVIPC=y -# CONFIG_IPC_NS is not set +CONFIG_SYSVIPC_SYSCTL=y # CONFIG_POSIX_MQUEUE is not set # CONFIG_BSD_PROCESS_ACCT is not set # CONFIG_TASKSTATS is not set -# CONFIG_UTS_NS is not set # CONFIG_AUDIT is not set + +# +# RCU Subsystem +# +CONFIG_CLASSIC_RCU=y +# CONFIG_TREE_RCU is not set +# CONFIG_PREEMPT_RCU is not set +# CONFIG_TREE_RCU_TRACE is not set +# CONFIG_PREEMPT_RCU_TRACE is not set CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_GROUP_SCHED is not set +# CONFIG_CGROUPS is not set CONFIG_SYSFS_DEPRECATED=y +CONFIG_SYSFS_DEPRECATED_V2=y # CONFIG_RELAY is not set -CONFIG_INITRAMFS_SOURCE="" +# CONFIG_NAMESPACES is not set +# CONFIG_BLK_DEV_INITRD is not set CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y CONFIG_EMBEDDED=y CONFIG_UID16=y CONFIG_SYSCTL_SYSCALL=y CONFIG_KALLSYMS=y # CONFIG_KALLSYMS_ALL is not set # CONFIG_KALLSYMS_EXTRA_PASS is not set +# CONFIG_STRIP_ASM_SYMS is not set CONFIG_HOTPLUG=y CONFIG_PRINTK=y CONFIG_BUG=y @@ -58,31 +77,38 @@ CONFIG_ELF_CORE=y CONFIG_BASE_FULL=y CONFIG_FUTEX=y CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y CONFIG_SHMEM=y -CONFIG_SLAB=y +CONFIG_AIO=y CONFIG_VM_EVENT_COUNTERS=y -CONFIG_RT_MUTEXES=y -# CONFIG_TINY_SHMEM is not set -CONFIG_BASE_SMALL=0 +CONFIG_COMPAT_BRK=y +CONFIG_SLAB=y +# CONFIG_SLUB is not set # CONFIG_SLOB is not set - -# -# Loadable module support -# +# CONFIG_PROFILING is not set +# CONFIG_MARKERS is not set +CONFIG_HAVE_OPROFILE=y +# CONFIG_KPROBES is not set +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_CLK=y +# CONFIG_SLOW_WORK is not set +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y # CONFIG_MODVERSIONS is not set # CONFIG_MODULE_SRCVERSION_ALL is not set -CONFIG_KMOD=y - -# -# Block layer -# 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 +# CONFIG_BLK_DEV_INTEGRITY is not set # # IO Schedulers @@ -96,6 +122,7 @@ CONFIG_DEFAULT_DEADLINE=y # CONFIG_DEFAULT_CFQ is not set # CONFIG_DEFAULT_NOOP is not set CONFIG_DEFAULT_IOSCHED="deadline" +# CONFIG_FREEZER is not set # # System Type @@ -105,29 +132,40 @@ CONFIG_DEFAULT_IOSCHED="deadline" # CONFIG_ARCH_REALVIEW is not set # CONFIG_ARCH_VERSATILE is not set # CONFIG_ARCH_AT91 is not set -# CONFIG_ARCH_CLPS7500 is not set # CONFIG_ARCH_CLPS711X is not set -# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_GEMINI is not set # CONFIG_ARCH_EBSA110 is not set CONFIG_ARCH_EP93XX=y # CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_MXC is not set # CONFIG_ARCH_NETX is not set # CONFIG_ARCH_H720X is not set # CONFIG_ARCH_IMX is not set +# CONFIG_ARCH_IOP13XX is not set # CONFIG_ARCH_IOP32X is not set # CONFIG_ARCH_IOP33X is not set -# CONFIG_ARCH_IOP13XX is not set -# CONFIG_ARCH_IXP4XX is not set -# CONFIG_ARCH_IXP2000 is not set # CONFIG_ARCH_IXP23XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_IXP4XX is not set # CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_KIRKWOOD is not set +# CONFIG_ARCH_LOKI is not set +# CONFIG_ARCH_MV78XX0 is not set +# CONFIG_ARCH_ORION5X is not set +# CONFIG_ARCH_MMP is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_NS9XXX is not set +# CONFIG_ARCH_W90X900 is not set # CONFIG_ARCH_PNX4008 is not set # CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_MSM is not set # CONFIG_ARCH_RPC is not set # CONFIG_ARCH_SA1100 is not set # CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_S3C64XX is not set # CONFIG_ARCH_SHARK is not set # CONFIG_ARCH_LH7A40X is not set +# CONFIG_ARCH_DAVINCI is not set # CONFIG_ARCH_OMAP is not set # @@ -138,14 +176,24 @@ CONFIG_CRUNCH=y # # EP93xx Platforms # +# CONFIG_EP93XX_SDCE0_PHYS_OFFSET is not set +CONFIG_EP93XX_SDCE3_SYNC_PHYS_OFFSET=y CONFIG_MACH_ADSSPHERE=y +CONFIG_MACH_EDB93XX=y +CONFIG_MACH_EDB9301=y CONFIG_MACH_EDB9302=y -CONFIG_MACH_EDB9302A=y +CONFIG_MACH_EDB9307=y CONFIG_MACH_EDB9312=y CONFIG_MACH_EDB9315=y -CONFIG_MACH_EDB9315A=y CONFIG_MACH_GESBC9312=y +CONFIG_MACH_MICRO9=y +CONFIG_MACH_MICRO9H=y +CONFIG_MACH_MICRO9M=y +CONFIG_MACH_MICRO9L=y CONFIG_MACH_TS72XX=y +CONFIG_EP93XX_EARLY_UART1=y +# CONFIG_EP93XX_EARLY_UART2 is not set +# CONFIG_EP93XX_EARLY_UART3 is not set # # Processor Type @@ -154,6 +202,7 @@ CONFIG_CPU_32=y CONFIG_CPU_ARM920T=y CONFIG_CPU_32v4T=y CONFIG_CPU_ABRT_EV4T=y +CONFIG_CPU_PABRT_NOIFAR=y CONFIG_CPU_CACHE_V4WT=y CONFIG_CPU_CACHE_VIVT=y CONFIG_CPU_COPY_V4WB=y @@ -168,34 +217,47 @@ CONFIG_ARM_THUMB=y # CONFIG_CPU_ICACHE_DISABLE is not set # CONFIG_CPU_DCACHE_DISABLE is not set # CONFIG_CPU_DCACHE_WRITETHROUGH is not set +# CONFIG_OUTER_CACHE is not set CONFIG_ARM_VIC=y +CONFIG_COMMON_CLKDEV=y # # Bus support # CONFIG_ARM_AMBA=y - -# -# PCCARD (PCMCIA/CardBus) support -# +# CONFIG_PCI_SYSCALL is not set +# CONFIG_ARCH_SUPPORTS_MSI is not set # CONFIG_PCCARD is not set # # Kernel Features # +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_1G is not set +CONFIG_PAGE_OFFSET=0xC0000000 # CONFIG_PREEMPT is not set CONFIG_HZ=100 -# CONFIG_AEABI is not set -# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set +CONFIG_AEABI=y +CONFIG_OABI_COMPAT=y +CONFIG_ARCH_FLATMEM_HAS_HOLES=y +# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set +# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set +# CONFIG_HIGHMEM is not set 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_PAGEFLAGS_EXTENDED=y CONFIG_SPLIT_PTLOCK_CPUS=4096 -# CONFIG_RESOURCES_64BIT is not set +# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 +CONFIG_VIRT_TO_BUS=y +CONFIG_UNEVICTABLE_LRU=y +CONFIG_HAVE_MLOCK=y +CONFIG_HAVE_MLOCKED_PAGE_BIT=y CONFIG_ALIGNMENT_TRAP=y # @@ -205,6 +267,12 @@ CONFIG_ZBOOT_ROM_TEXT=0x0 CONFIG_ZBOOT_ROM_BSS=0x0 CONFIG_CMDLINE="console=ttyAM0,115200 root=/dev/nfs ip=bootp" # CONFIG_XIP_KERNEL is not set +# CONFIG_KEXEC is not set + +# +# CPU Power Management +# +# CONFIG_CPU_IDLE is not set # # Floating point emulation @@ -221,32 +289,31 @@ CONFIG_FPE_NWFPE_XP=y # Userspace binary formats # CONFIG_BINFMT_ELF=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_HAVE_AOUT=y # CONFIG_BINFMT_AOUT is not set # CONFIG_BINFMT_MISC is not set -# CONFIG_ARTHUR is not set # # Power management options # # CONFIG_PM is not set -# CONFIG_APM is not set - -# -# Networking -# +CONFIG_ARCH_SUSPEND_POSSIBLE=y CONFIG_NET=y # # Networking options # -# CONFIG_NETDEBUG is not set CONFIG_PACKET=y CONFIG_PACKET_MMAP=y CONFIG_UNIX=y CONFIG_XFRM=y # CONFIG_XFRM_USER is not set # CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set CONFIG_NET_KEY=y +# CONFIG_NET_KEY_MIGRATE is not set CONFIG_INET=y # CONFIG_IP_MULTICAST is not set # CONFIG_IP_ADVANCED_ROUTER is not set @@ -267,6 +334,7 @@ CONFIG_SYN_COOKIES=y CONFIG_INET_XFRM_MODE_TRANSPORT=y CONFIG_INET_XFRM_MODE_TUNNEL=y CONFIG_INET_XFRM_MODE_BEET=y +# CONFIG_INET_LRO is not set CONFIG_INET_DIAG=y CONFIG_INET_TCP_DIAG=y # CONFIG_TCP_CONG_ADVANCED is not set @@ -276,6 +344,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic" CONFIG_IPV6=y # CONFIG_IPV6_PRIVACY is not set # CONFIG_IPV6_ROUTER_PREF is not set +# CONFIG_IPV6_OPTIMISTIC_DAD is not set # CONFIG_INET6_AH is not set # CONFIG_INET6_ESP is not set # CONFIG_INET6_IPCOMP is not set @@ -289,25 +358,15 @@ CONFIG_IPV6=y # CONFIG_IPV6_SIT is not set # CONFIG_IPV6_TUNNEL is not set # CONFIG_IPV6_MULTIPLE_TABLES is not set +# CONFIG_IPV6_MROUTE is not set # CONFIG_NETWORK_SECMARK is not set # CONFIG_NETFILTER is not set - -# -# DCCP Configuration (EXPERIMENTAL) -# # CONFIG_IP_DCCP is not set - -# -# SCTP Configuration (EXPERIMENTAL) -# # CONFIG_IP_SCTP is not set - -# -# TIPC Configuration (EXPERIMENTAL) -# # CONFIG_TIPC is not set # CONFIG_ATM is not set # CONFIG_BRIDGE is not set +# CONFIG_NET_DSA is not set # CONFIG_VLAN_8021Q is not set # CONFIG_DECNET is not set # CONFIG_LLC2 is not set @@ -317,20 +376,28 @@ CONFIG_IPV6=y # CONFIG_LAPB is not set # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set - -# -# QoS and/or fair queueing -# +# CONFIG_PHONET is not set # CONFIG_NET_SCHED is not set +# CONFIG_DCB is not set # # Network testing # # CONFIG_NET_PKTGEN is not set # CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set # CONFIG_IRDA is not set # CONFIG_BT is not set -# CONFIG_IEEE80211 is not set +# CONFIG_AF_RXRPC is not set +CONFIG_WIRELESS=y +# CONFIG_CFG80211 is not set +# CONFIG_WIRELESS_OLD_REGULATORY is not set +# CONFIG_WIRELESS_EXT is not set +# CONFIG_LIB80211 is not set +# CONFIG_MAC80211 is not set +# CONFIG_WIMAX is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set # # Device Drivers @@ -339,41 +406,39 @@ CONFIG_IPV6=y # # Generic Driver Options # +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_STANDALONE=y CONFIG_PREVENT_FIRMWARE_BUILD=y # CONFIG_FW_LOADER is not set # CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set # CONFIG_SYS_HYPERVISOR is not set - -# -# Connector - unified userspace <-> kernelspace linker -# # CONFIG_CONNECTOR is not set - -# -# Memory Technology Devices (MTD) -# CONFIG_MTD=y # CONFIG_MTD_DEBUG is not set CONFIG_MTD_CONCAT=y CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_TESTS is not set CONFIG_MTD_REDBOOT_PARTS=y CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1 # CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set # CONFIG_MTD_REDBOOT_PARTS_READONLY is not set CONFIG_MTD_CMDLINE_PARTS=y # CONFIG_MTD_AFS_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 @@ -404,16 +469,13 @@ CONFIG_MTD_CFI_UTIL=y # CONFIG_MTD_RAM is not set CONFIG_MTD_ROM=y # CONFIG_MTD_ABSENT is not set -# CONFIG_MTD_OBSOLETE_CHIPS is not set # # Mapping drivers for chip access # # CONFIG_MTD_COMPLEX_MAPPINGS is not set CONFIG_MTD_PHYSMAP=y -CONFIG_MTD_PHYSMAP_START=0x0 -CONFIG_MTD_PHYSMAP_LEN=0x0 -CONFIG_MTD_PHYSMAP_BANKWIDTH=1 +# CONFIG_MTD_PHYSMAP_COMPAT is not set # CONFIG_MTD_ARM_INTEGRATOR is not set # CONFIG_MTD_PLATRAM is not set @@ -431,49 +493,58 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=1 # CONFIG_MTD_DOC2000 is not set # CONFIG_MTD_DOC2001 is not set # CONFIG_MTD_DOC2001PLUS is not set - -# -# NAND Flash Device Drivers -# CONFIG_MTD_NAND=y CONFIG_MTD_NAND_VERIFY_WRITE=y # CONFIG_MTD_NAND_ECC_SMC is not set -CONFIG_MTD_NAND_TS7250=y +# CONFIG_MTD_NAND_MUSEUM_IDS is not set +# CONFIG_MTD_NAND_GPIO is not set +# CONFIG_MTD_NAND_TS7250 is not set CONFIG_MTD_NAND_IDS=y # CONFIG_MTD_NAND_DISKONCHIP is not set # CONFIG_MTD_NAND_NANDSIM is not set - -# -# OneNAND Flash Device Drivers -# +# CONFIG_MTD_NAND_PLATFORM is not set +# CONFIG_MTD_ALAUDA is not set # CONFIG_MTD_ONENAND is not set # -# Parallel port support +# LPDDR flash memory drivers # +# CONFIG_MTD_LPDDR is not set + +# +# UBI - Unsorted block images +# +# CONFIG_MTD_UBI is not set # CONFIG_PARPORT is not set - -# -# Plug and Play support -# - -# -# Block devices -# +CONFIG_BLK_DEV=y # CONFIG_BLK_DEV_COW_COMMON is not set # CONFIG_BLK_DEV_LOOP is not set CONFIG_BLK_DEV_NBD=y # CONFIG_BLK_DEV_UB is not set # CONFIG_BLK_DEV_RAM is not set -# CONFIG_BLK_DEV_INITRD is not set # CONFIG_CDROM_PKTCDVD is not set # CONFIG_ATA_OVER_ETH is not set +CONFIG_MISC_DEVICES=y +# CONFIG_ICS932S401 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_ISL29003 is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +# CONFIG_EEPROM_AT24 is not set +CONFIG_EEPROM_LEGACY=y +# CONFIG_EEPROM_93CX6 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 is not set @@ -495,6 +566,7 @@ CONFIG_BLK_DEV_SD=y # 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 @@ -502,92 +574,71 @@ CONFIG_BLK_DEV_SD=y # CONFIG_SCSI_SPI_ATTRS is not set # CONFIG_SCSI_FC_ATTRS is not set # CONFIG_SCSI_ISCSI_ATTRS is not set -# CONFIG_SCSI_SAS_ATTRS is not set # CONFIG_SCSI_SAS_LIBSAS is not set - -# -# SCSI low-level drivers -# +# CONFIG_SCSI_SRP_ATTRS is not set +CONFIG_SCSI_LOWLEVEL=y # CONFIG_ISCSI_TCP is not set +# CONFIG_LIBFC is not set +# CONFIG_LIBFCOE is not set # CONFIG_SCSI_DEBUG is not set - -# -# Serial ATA (prod) and Parallel ATA (experimental) drivers -# +# CONFIG_SCSI_DH is not set +# CONFIG_SCSI_OSD_INITIATOR is not set # CONFIG_ATA is not set - -# -# Multi-device support (RAID and LVM) -# # CONFIG_MD is not set - -# -# Fusion MPT device support -# -# CONFIG_FUSION is not set - -# -# IEEE 1394 (FireWire) support -# - -# -# I2O device support -# - -# -# Network device support -# CONFIG_NETDEVICES=y +CONFIG_COMPAT_NET_DEV_OPS=y # 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 - -# -# PHY device support -# +# CONFIG_VETH is not set # CONFIG_PHYLIB is not set - -# -# Ethernet (10 or 100Mbit) -# CONFIG_NET_ETHERNET=y CONFIG_MII=y CONFIG_EP93XX_ETH=y +# CONFIG_AX88796 is not set # CONFIG_SMC91X is not set # CONFIG_DM9000 is not set +# CONFIG_ETHOC is not set +# CONFIG_SMC911X is not set +# CONFIG_SMSC911X is not set +# CONFIG_DNET 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_IBM_NEW_EMAC_NO_FLOW_CTRL is not set +# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set +# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set +# CONFIG_B44 is not set +CONFIG_NETDEV_1000=y +CONFIG_NETDEV_10000=y # -# Ethernet (1000 Mbit) +# Wireless LAN +# +# CONFIG_WLAN_PRE80211 is not set +# CONFIG_WLAN_80211 is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers # # -# Ethernet (10000 Mbit) -# - -# -# Token Ring devices -# - -# -# Wireless LAN (non-hamradio) -# -# CONFIG_NET_RADIO is not set - -# -# Wan interfaces +# USB Network Adapters # +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +CONFIG_USB_RTL8150=y +# CONFIG_USB_USBNET is not set # CONFIG_WAN is not set # CONFIG_PPP is not set # CONFIG_SLIP is not set -# CONFIG_SHAPER is not set # CONFIG_NETCONSOLE is not set # CONFIG_NETPOLL is not set # CONFIG_NET_POLL_CONTROLLER is not set - -# -# ISDN subsystem -# # CONFIG_ISDN is not set # @@ -605,6 +656,7 @@ CONFIG_EP93XX_ETH=y # Character devices # # CONFIG_VT is not set +CONFIG_DEVKMEM=y # CONFIG_SERIAL_NONSTANDARD is not set # @@ -621,104 +673,101 @@ CONFIG_SERIAL_AMBA_PL010_CONSOLE=y CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_UNIX98_PTYS=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set # CONFIG_LEGACY_PTYS is not set - -# -# IPMI -# # CONFIG_IPMI_HANDLER is not set - -# -# Watchdog Cards -# -CONFIG_WATCHDOG=y -# CONFIG_WATCHDOG_NOWAYOUT is not set - -# -# Watchdog Device Drivers -# -# CONFIG_SOFT_WATCHDOG is not set -CONFIG_EP93XX_WATCHDOG=y - -# -# USB-based Watchdog Cards -# -# CONFIG_USBPCWATCHDOG is not set # CONFIG_HW_RANDOM is not set -# CONFIG_NVRAM is not set -# CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_RAW_DRIVER is not set - -# -# TPM devices -# # CONFIG_TCG_TPM is not set - -# -# I2C support -# CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y CONFIG_I2C_CHARDEV=y - -# -# I2C Algorithms -# -CONFIG_I2C_ALGOBIT=y -# CONFIG_I2C_ALGOPCF is not set -# CONFIG_I2C_ALGOPCA is not set +CONFIG_I2C_HELPER_AUTO=y # # I2C Hardware Bus support # + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_GPIO is not set # CONFIG_I2C_OCORES is not set +# CONFIG_I2C_SIMTEC is not set + +# +# External I2C/SMBus adapter drivers +# # CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_PCA_PLATFORM is not set # CONFIG_I2C_STUB is not set -# CONFIG_I2C_PCA_ISA is not set # # Miscellaneous I2C Chip support # -# CONFIG_SENSORS_DS1337 is not set -# CONFIG_SENSORS_DS1374 is not set -CONFIG_EEPROM_LEGACY=y +# CONFIG_DS1682 is not set # CONFIG_SENSORS_PCF8574 is not set +# CONFIG_PCF8575 is not set # CONFIG_SENSORS_PCA9539 is not set -# CONFIG_SENSORS_PCF8591 is not set # CONFIG_SENSORS_MAX6875 is not set +# CONFIG_SENSORS_TSL2550 is not set CONFIG_I2C_DEBUG_CORE=y CONFIG_I2C_DEBUG_ALGO=y CONFIG_I2C_DEBUG_BUS=y CONFIG_I2C_DEBUG_CHIP=y - -# -# SPI support -# # CONFIG_SPI is not set -# CONFIG_SPI_MASTER is not set +CONFIG_ARCH_REQUIRE_GPIOLIB=y +CONFIG_GPIOLIB=y +# CONFIG_DEBUG_GPIO is not set +# CONFIG_GPIO_SYSFS is not set # -# Dallas's 1-wire bus +# Memory mapped GPIO expanders: +# + +# +# I2C GPIO expanders: +# +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_GPIO_PCF857X is not set + +# +# PCI GPIO expanders: +# + +# +# SPI GPIO expanders: # # CONFIG_W1 is not set - -# -# Hardware Monitoring support -# +# CONFIG_POWER_SUPPLY is not set CONFIG_HWMON=y # CONFIG_HWMON_VID is not set -# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 is not set # CONFIG_SENSORS_ADM1021 is not set # CONFIG_SENSORS_ADM1025 is not set # CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1029 is not set # CONFIG_SENSORS_ADM1031 is not set # CONFIG_SENSORS_ADM9240 is not set -# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_ADT7462 is not set +# CONFIG_SENSORS_ADT7470 is not set +# CONFIG_SENSORS_ADT7473 is not set +# CONFIG_SENSORS_ADT7475 is not set # CONFIG_SENSORS_ATXP1 is not set # CONFIG_SENSORS_DS1621 is not set # CONFIG_SENSORS_F71805F is not set -# CONFIG_SENSORS_FSCHER is not set -# CONFIG_SENSORS_FSCPOS is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_G760A is not set # CONFIG_SENSORS_GL518SM is not set # CONFIG_SENSORS_GL520SM is not set # CONFIG_SENSORS_IT87 is not set @@ -732,158 +781,188 @@ CONFIG_HWMON=y # CONFIG_SENSORS_LM87 is not set # CONFIG_SENSORS_LM90 is not set # CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_LM93 is not set +# CONFIG_SENSORS_LTC4215 is not set +# CONFIG_SENSORS_LTC4245 is not set +# CONFIG_SENSORS_LM95241 is not set # CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_MAX6650 is not set # CONFIG_SENSORS_PC87360 is not set # CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_SHT15 is not set +# CONFIG_SENSORS_DME1737 is not set # CONFIG_SENSORS_SMSC47M1 is not set # CONFIG_SENSORS_SMSC47M192 is not set # CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_THMC50 is not set # CONFIG_SENSORS_VT1211 is not set # CONFIG_SENSORS_W83781D is not set # CONFIG_SENSORS_W83791D is not set # CONFIG_SENSORS_W83792D is not set # CONFIG_SENSORS_W83793 is not set # CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83L786NG is not set # CONFIG_SENSORS_W83627HF is not set # CONFIG_SENSORS_W83627EHF is not set # CONFIG_HWMON_DEBUG_CHIP is not set +# CONFIG_THERMAL is not set +# CONFIG_THERMAL_HWMON is not set +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set # -# Misc devices +# Watchdog Device Drivers # -# CONFIG_TIFM_CORE is not set +# CONFIG_SOFT_WATCHDOG is not set +CONFIG_EP93XX_WATCHDOG=y # -# LED devices +# USB-based Watchdog Cards # -# CONFIG_NEW_LEDS is not set +# CONFIG_USBPCWATCHDOG is not set +CONFIG_SSB_POSSIBLE=y # -# LED drivers +# Sonics Silicon Backplane # +# CONFIG_SSB is not set # -# LED Triggers +# Multifunction device drivers # +# CONFIG_MFD_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_ASIC3 is not set +# CONFIG_HTC_EGPIO is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_TPS65010 is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_T7L66XB is not set +# CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_TC6393XB is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_PCF50633 is not set # # Multimedia devices # -# CONFIG_VIDEO_DEV is not set # -# Digital Video Broadcasting Devices +# Multimedia core support # -# CONFIG_DVB is not set -# CONFIG_USB_DABUSB is not set +# CONFIG_VIDEO_DEV is not set +# CONFIG_DVB_CORE is not set +# CONFIG_VIDEO_MEDIA is not set + +# +# Multimedia drivers +# +# CONFIG_DAB is not set # # Graphics support # -# CONFIG_FIRMWARE_EDID 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 # -# Sound +# Display device support # +# CONFIG_DISPLAY_SUPPORT is not set # CONFIG_SOUND is not set - -# -# USB support -# +CONFIG_USB_SUPPORT=y CONFIG_USB_ARCH_HAS_HCD=y CONFIG_USB_ARCH_HAS_OHCI=y # CONFIG_USB_ARCH_HAS_EHCI is not set CONFIG_USB=y CONFIG_USB_DEBUG=y +# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set # # Miscellaneous USB options # CONFIG_USB_DEVICEFS=y -# CONFIG_USB_BANDWIDTH is not set +CONFIG_USB_DEVICE_CLASS=y CONFIG_USB_DYNAMIC_MINORS=y -# CONFIG_USB_MULTITHREAD_PROBE is not set # CONFIG_USB_OTG is not set +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set +# CONFIG_USB_MON is not set +# CONFIG_USB_WUSB is not set +# CONFIG_USB_WUSB_CBAF is not set # # USB Host Controller Drivers # +# CONFIG_USB_C67X00_HCD is not set +# CONFIG_USB_OXU210HP_HCD is not set # CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_ISP1760_HCD is not set CONFIG_USB_OHCI_HCD=y -# CONFIG_USB_OHCI_BIG_ENDIAN is not set +# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set +# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set CONFIG_USB_OHCI_LITTLE_ENDIAN=y # CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_HWA_HCD is not set +# CONFIG_USB_MUSB_HDRC is not set # # USB Device Class drivers # # CONFIG_USB_ACM is not set # CONFIG_USB_PRINTER is not set +# CONFIG_USB_WDM is not set +# CONFIG_USB_TMC is not set # -# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may # # -# may also be needed; see USB_STORAGE Help for more information +# also be needed; see USB_STORAGE Help for more info # CONFIG_USB_STORAGE=y # CONFIG_USB_STORAGE_DEBUG is not set # CONFIG_USB_STORAGE_DATAFAB is not set # CONFIG_USB_STORAGE_FREECOM is not set -# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_ISD200 is not set # CONFIG_USB_STORAGE_USBAT is not set # CONFIG_USB_STORAGE_SDDR09 is not set # CONFIG_USB_STORAGE_SDDR55 is not set # CONFIG_USB_STORAGE_JUMPSHOT is not set # CONFIG_USB_STORAGE_ALAUDA is not set # CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set # CONFIG_USB_LIBUSUAL is not set -# -# USB Input Devices -# - -# -# USB HID Boot Protocol drivers -# - # # USB Imaging devices # # CONFIG_USB_MDC800 is not set # CONFIG_USB_MICROTEK is not set -# -# USB Network Adapters -# -# CONFIG_USB_CATC is not set -# CONFIG_USB_KAWETH is not set -# CONFIG_USB_PEGASUS is not set -CONFIG_USB_RTL8150=y -# CONFIG_USB_USBNET_MII is not set -# CONFIG_USB_USBNET is not set -# CONFIG_USB_MON is not set - # # USB port drivers # - -# -# USB Serial Converter support -# CONFIG_USB_SERIAL=y CONFIG_USB_SERIAL_CONSOLE=y +# CONFIG_USB_EZUSB is not set # CONFIG_USB_SERIAL_GENERIC is not set # CONFIG_USB_SERIAL_AIRCABLE is not set -# CONFIG_USB_SERIAL_AIRPRIME is not set # CONFIG_USB_SERIAL_ARK3116 is not set # CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_CH341 is not set # CONFIG_USB_SERIAL_WHITEHEAT is not set # CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set -# CONFIG_USB_SERIAL_CP2101 is not set +# CONFIG_USB_SERIAL_CP210X is not set # CONFIG_USB_SERIAL_CYPRESS_M8 is not set # CONFIG_USB_SERIAL_EMPEG is not set # CONFIG_USB_SERIAL_FTDI_SIO is not set @@ -895,6 +974,7 @@ CONFIG_USB_SERIAL_CONSOLE=y # CONFIG_USB_SERIAL_EDGEPORT_TI is not set # CONFIG_USB_SERIAL_GARMIN is not set # CONFIG_USB_SERIAL_IPW is not set +# CONFIG_USB_SERIAL_IUU is not set # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set # CONFIG_USB_SERIAL_KEYSPAN is not set # CONFIG_USB_SERIAL_KLSI is not set @@ -902,16 +982,23 @@ CONFIG_USB_SERIAL_CONSOLE=y # CONFIG_USB_SERIAL_MCT_U232 is not set # CONFIG_USB_SERIAL_MOS7720 is not set # CONFIG_USB_SERIAL_MOS7840 is not set +# CONFIG_USB_SERIAL_MOTOROLA is not set # CONFIG_USB_SERIAL_NAVMAN is not set CONFIG_USB_SERIAL_PL2303=y +# CONFIG_USB_SERIAL_OTI6858 is not set +# CONFIG_USB_SERIAL_QUALCOMM is not set +# CONFIG_USB_SERIAL_SPCP8X5 is not set # CONFIG_USB_SERIAL_HP4X is not set # CONFIG_USB_SERIAL_SAFE is not set +# CONFIG_USB_SERIAL_SIEMENS_MPI is not set # CONFIG_USB_SERIAL_SIERRAWIRELESS is not set +# CONFIG_USB_SERIAL_SYMBOL is not set # CONFIG_USB_SERIAL_TI is not set # CONFIG_USB_SERIAL_CYBERJACK is not set # CONFIG_USB_SERIAL_XIRCOM is not set # CONFIG_USB_SERIAL_OPTION is not set # CONFIG_USB_SERIAL_OMNINET is not set +# CONFIG_USB_SERIAL_OPTICON is not set # CONFIG_USB_SERIAL_DEBUG is not set # @@ -920,38 +1007,34 @@ CONFIG_USB_SERIAL_PL2303=y # CONFIG_USB_EMI62 is not set # CONFIG_USB_EMI26 is not set # CONFIG_USB_ADUTUX is not set -# CONFIG_USB_AUERSWALD is not set +# CONFIG_USB_SEVSEG is not set # CONFIG_USB_RIO500 is not set # CONFIG_USB_LEGOTOWER is not set # CONFIG_USB_LCD is not set +# CONFIG_USB_BERRY_CHARGE is not set # CONFIG_USB_LED is not set # CONFIG_USB_CYPRESS_CY7C63 is not set # CONFIG_USB_CYTHERM is not set -# CONFIG_USB_PHIDGET is not set # CONFIG_USB_IDMOUSE is not set # CONFIG_USB_FTDI_ELAN is not set # CONFIG_USB_APPLEDISPLAY is not set # CONFIG_USB_LD is not set # CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set # CONFIG_USB_TEST is not set - -# -# USB DSL modem support -# - -# -# USB Gadget Support -# +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_VST is not set # CONFIG_USB_GADGET is not set # -# MMC/SD Card support +# OTG and related infrastructure # +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_NOP_USB_XCEIV is not set # CONFIG_MMC is not set - -# -# Real Time Clock -# +# CONFIG_MEMSTICK is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_NEW_LEDS is not set CONFIG_RTC_LIB=y CONFIG_RTC_CLASS=y CONFIG_RTC_HCTOSYS=y @@ -965,25 +1048,56 @@ CONFIG_RTC_INTF_SYSFS=y CONFIG_RTC_INTF_PROC=y CONFIG_RTC_INTF_DEV=y # CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set # -# RTC drivers +# I2C RTC drivers # -# CONFIG_RTC_DRV_X1205 is not set CONFIG_RTC_DRV_DS1307=y -# CONFIG_RTC_DRV_DS1553 is not set -# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_DS1374 is not set # CONFIG_RTC_DRV_DS1672 is not set -# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_X1205 is not set # CONFIG_RTC_DRV_PCF8563 is not set # CONFIG_RTC_DRV_PCF8583 is not set -# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8581 is not set + +# +# SPI RTC drivers +# + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set CONFIG_RTC_DRV_M48T86=y -CONFIG_RTC_DRV_EP93XX=y -# CONFIG_RTC_DRV_PL031 is not set -# CONFIG_RTC_DRV_TEST is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_BQ4802 is not set # CONFIG_RTC_DRV_V3020 is not set +# +# on-CPU RTC drivers +# +CONFIG_RTC_DRV_EP93XX=y +# CONFIG_RTC_DRV_PL030 is not set +# CONFIG_RTC_DRV_PL031 is not set +# CONFIG_DMADEVICES is not set +# CONFIG_AUXDISPLAY is not set +# CONFIG_REGULATOR is not set +# CONFIG_UIO is not set +# CONFIG_STAGING is not set + # # File systems # @@ -991,26 +1105,30 @@ CONFIG_EXT2_FS=y # CONFIG_EXT2_FS_XATTR is not set # CONFIG_EXT2_FS_XIP is not set CONFIG_EXT3_FS=y +# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set # CONFIG_EXT3_FS_XATTR is not set -# CONFIG_EXT4DEV_FS is not set +# CONFIG_EXT4_FS is not set CONFIG_JBD=y -# CONFIG_JBD_DEBUG is not set # CONFIG_REISERFS_FS is not set # CONFIG_JFS_FS is not set # CONFIG_FS_POSIX_ACL is not set +CONFIG_FILE_LOCKING=y # CONFIG_XFS_FS is not set -# CONFIG_GFS2_FS is not set # CONFIG_OCFS2_FS is not set -# CONFIG_MINIX_FS is not set -# CONFIG_ROMFS_FS is not set +# CONFIG_BTRFS_FS is not set +CONFIG_DNOTIFY=y CONFIG_INOTIFY=y CONFIG_INOTIFY_USER=y # CONFIG_QUOTA is not set -CONFIG_DNOTIFY=y # CONFIG_AUTOFS_FS is not set # CONFIG_AUTOFS4_FS is not set # CONFIG_FUSE_FS is not set +# +# Caches +# +# CONFIG_FSCACHE is not set + # # CD-ROM/DVD Filesystems # @@ -1032,16 +1150,13 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" # CONFIG_PROC_FS=y CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y CONFIG_SYSFS=y CONFIG_TMPFS=y # CONFIG_TMPFS_POSIX_ACL is not set # CONFIG_HUGETLB_PAGE is not set -CONFIG_RAMFS=y # CONFIG_CONFIGFS_FS is not set - -# -# Miscellaneous filesystems -# +CONFIG_MISC_FILESYSTEMS=y # CONFIG_ADFS_FS is not set # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set @@ -1049,33 +1164,35 @@ CONFIG_RAMFS=y # CONFIG_BEFS_FS is not set # CONFIG_BFS_FS is not set # CONFIG_EFS_FS is not set -# CONFIG_JFFS_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 is not set # CONFIG_JFFS2_FS_XATTR is not set # CONFIG_JFFS2_COMPRESSION_OPTIONS is not set CONFIG_JFFS2_ZLIB=y +# CONFIG_JFFS2_LZO is not set CONFIG_JFFS2_RTIME=y # CONFIG_JFFS2_RUBIN is not set # CONFIG_CRAMFS is not set +# CONFIG_SQUASHFS is not set # CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_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 - -# -# Network File Systems -# +# CONFIG_NILFS2_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y CONFIG_NFS_FS=y CONFIG_NFS_V3=y # CONFIG_NFS_V3_ACL is not set # CONFIG_NFS_V4 is not set -# CONFIG_NFS_DIRECTIO is not set -# CONFIG_NFSD is not set CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set CONFIG_LOCKD=y CONFIG_LOCKD_V4=y CONFIG_NFS_COMMON=y @@ -1087,7 +1204,6 @@ CONFIG_SUNRPC=y # CONFIG_NCP_FS is not set # CONFIG_CODA_FS is not set # CONFIG_AFS_FS is not set -# CONFIG_9P_FS is not set # # Partition Types @@ -1109,10 +1225,7 @@ CONFIG_MSDOS_PARTITION=y # CONFIG_SUN_PARTITION is not set # CONFIG_KARMA_PARTITION is not set # CONFIG_EFI_PARTITION is not set - -# -# Native Language Support -# +# CONFIG_SYSV68_PARTITION is not set CONFIG_NLS=y CONFIG_NLS_DEFAULT="iso8859-1" CONFIG_NLS_CODEPAGE_437=y @@ -1153,49 +1266,83 @@ CONFIG_NLS_ISO8859_1=y # CONFIG_NLS_KOI8_R is not set # CONFIG_NLS_KOI8_U is not set # CONFIG_NLS_UTF8 is not set - -# -# Distributed Lock Manager -# # CONFIG_DLM is not set -# -# Profiling support -# -# CONFIG_PROFILING is not set - # # Kernel hacking # # CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_WARN_DEPRECATED=y CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=1024 CONFIG_MAGIC_SYSRQ=y # CONFIG_UNUSED_SYMBOLS is not set # CONFIG_DEBUG_FS is not set # CONFIG_HEADERS_CHECK is not set CONFIG_DEBUG_KERNEL=y -CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_DEBUG_SHIRQ is not set CONFIG_DETECT_SOFTLOCKUP=y +# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0 +CONFIG_DETECT_HUNG_TASK=y +# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set +CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0 +CONFIG_SCHED_DEBUG=y # CONFIG_SCHEDSTATS is not set +# CONFIG_TIMER_STATS is not set +# CONFIG_DEBUG_OBJECTS is not set CONFIG_DEBUG_SLAB=y # CONFIG_DEBUG_SLAB_LEAK is not set # CONFIG_DEBUG_RT_MUTEXES is not set # CONFIG_RT_MUTEX_TESTER is not set CONFIG_DEBUG_SPINLOCK=y CONFIG_DEBUG_MUTEXES=y -# CONFIG_DEBUG_RWSEMS is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set # CONFIG_DEBUG_SPINLOCK_SLEEP is not set # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set # CONFIG_DEBUG_KOBJECT is not set CONFIG_DEBUG_BUGVERBOSE=y # CONFIG_DEBUG_INFO is not set # CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_WRITECOUNT is not set +# CONFIG_DEBUG_MEMORY_INIT is not set # CONFIG_DEBUG_LIST is not set -CONFIG_FRAME_POINTER=y -CONFIG_FORCED_INLINING=y +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_BOOT_PRINTK_DELAY is not set # CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_RCU_CPU_STALL_DETECTOR is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_LATENCYTOP is not set +# CONFIG_SYSCTL_SYSCALL_CHECK is not set +# CONFIG_PAGE_POISONING is not set +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_TRACING_SUPPORT=y + +# +# Tracers +# +# CONFIG_FUNCTION_TRACER is not set +# CONFIG_SCHED_TRACER is not set +# CONFIG_CONTEXT_SWITCH_TRACER is not set +# CONFIG_EVENT_TRACER is not set +# CONFIG_BOOT_TRACER is not set +# CONFIG_TRACE_BRANCH_PROFILING is not set +# CONFIG_STACK_TRACER is not set +# CONFIG_KMEMTRACE is not set +# CONFIG_WORKQUEUE_TRACER is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +CONFIG_ARM_UNWIND=y CONFIG_DEBUG_USER=y CONFIG_DEBUG_ERRORS=y +# CONFIG_DEBUG_STACK_USAGE is not set CONFIG_DEBUG_LL=y # CONFIG_DEBUG_ICEDCC is not set @@ -1204,21 +1351,115 @@ CONFIG_DEBUG_LL=y # # CONFIG_KEYS is not set # CONFIG_SECURITY is not set +# CONFIG_SECURITYFS is not set +# CONFIG_SECURITY_FILE_CAPABILITIES is not set +CONFIG_CRYPTO=y # -# Cryptographic options +# Crypto core or helper # -# CONFIG_CRYPTO is not set +# CONFIG_CRYPTO_FIPS is not set +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +# CONFIG_CRYPTO_MANAGER is not set +# CONFIG_CRYPTO_MANAGER2 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 is not set + +# +# 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=y +# CONFIG_CRYPTO_MD4 is not set +# CONFIG_CRYPTO_MD5 is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 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_ZLIB is not set +# CONFIG_CRYPTO_LZO is not set + +# +# Random Number Generation +# +# CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_CRYPTO_HW=y +# CONFIG_BINARY_PRINTF is not set # # Library routines # CONFIG_BITREVERSE=y +CONFIG_GENERIC_FIND_LAST_BIT=y # CONFIG_CRC_CCITT is not set # CONFIG_CRC16 is not set +# CONFIG_CRC_T10DIF is not set +# CONFIG_CRC_ITU_T is not set CONFIG_CRC32=y +# CONFIG_CRC7 is not set CONFIG_LIBCRC32C=y CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=y -CONFIG_PLIST=y -CONFIG_IOMAP_COPY=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y +CONFIG_NLATTR=y diff --git a/arch/arm/configs/kirkwood_defconfig b/arch/arm/configs/kirkwood_defconfig index dcf8153a947d..0a1abb978d7e 100644 --- a/arch/arm/configs/kirkwood_defconfig +++ b/arch/arm/configs/kirkwood_defconfig @@ -182,6 +182,7 @@ CONFIG_ARCH_KIRKWOOD=y CONFIG_MACH_DB88F6281_BP=y CONFIG_MACH_RD88F6192_NAS=y CONFIG_MACH_RD88F6281=y +CONFIG_MACH_MV88F6281GTW_GE=y CONFIG_MACH_SHEEVAPLUG=y CONFIG_MACH_TS219=y CONFIG_PLAT_ORION=y @@ -270,7 +271,9 @@ CONFIG_CMDLINE="" # # CPU Power Management # -# CONFIG_CPU_IDLE is not set +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y # # Floating point emulation diff --git a/arch/arm/configs/magician_defconfig b/arch/arm/configs/magician_defconfig index f56837f69ca7..957fd5fa27ca 100644 --- a/arch/arm/configs/magician_defconfig +++ b/arch/arm/configs/magician_defconfig @@ -190,6 +190,7 @@ CONFIG_ARCH_PXA=y # CONFIG_MACH_SAAR is not set # CONFIG_MACH_ARMCORE is not set # CONFIG_MACH_CM_X300 is not set +CONFIG_MACH_H4700=y CONFIG_MACH_MAGICIAN=y # CONFIG_MACH_MIOA701 is not set # CONFIG_MACH_PCM027 is not set @@ -828,7 +829,7 @@ CONFIG_SSB_POSSIBLE=y # # CONFIG_MFD_CORE is not set # CONFIG_MFD_SM501 is not set -# CONFIG_MFD_ASIC3 is not set +CONFIG_MFD_ASIC3=y CONFIG_HTC_EGPIO=y CONFIG_HTC_PASIC3=y # CONFIG_TPS65010 is not set @@ -891,7 +892,7 @@ CONFIG_FB_PXA_OVERLAY=y # CONFIG_FB_PXA_SMARTPANEL is not set # CONFIG_FB_PXA_PARAMETERS is not set # CONFIG_FB_MBX is not set -# CONFIG_FB_W100 is not set +CONFIG_FB_W100=y # CONFIG_FB_VIRTUAL is not set # CONFIG_FB_METRONOME is not set # CONFIG_FB_MB862XX is not set diff --git a/arch/arm/configs/mini2440_defconfig b/arch/arm/configs/mini2440_defconfig new file mode 100644 index 000000000000..e49ed40f3be7 --- /dev/null +++ b/arch/arm/configs/mini2440_defconfig @@ -0,0 +1,2097 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.30-rc6 +# Wed May 20 12:29:51 2009 +# +CONFIG_ARM=y +CONFIG_HAVE_PWM=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_GENERIC_GPIO=y +# CONFIG_GENERIC_TIME is not set +# CONFIG_GENERIC_CLOCKEVENTS is not set +CONFIG_MMU=y +CONFIG_NO_IOPORT=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_HAVE_LATENCYTOP_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y +CONFIG_VECTORS_BASE=0xffff0000 +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=y +CONFIG_POSIX_MQUEUE_SYSCTL=y +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set +# CONFIG_AUDIT is not set + +# +# RCU Subsystem +# +CONFIG_CLASSIC_RCU=y +# CONFIG_TREE_RCU is not set +# CONFIG_PREEMPT_RCU is not set +# CONFIG_TREE_RCU_TRACE is not set +# CONFIG_PREEMPT_RCU_TRACE is not set +# CONFIG_IKCONFIG is not set +CONFIG_LOG_BUF_SHIFT=17 +# CONFIG_GROUP_SCHED is not set +# CONFIG_CGROUPS is not set +# CONFIG_SYSFS_DEPRECATED_V2 is not set +CONFIG_RELAY=y +CONFIG_NAMESPACES=y +CONFIG_UTS_NS=y +CONFIG_IPC_NS=y +# CONFIG_USER_NS is not set +# CONFIG_PID_NS is not set +# CONFIG_NET_NS is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +CONFIG_RD_BZIP2=y +CONFIG_RD_LZMA=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y +# CONFIG_EMBEDDED is not set +CONFIG_UID16=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_STRIP_ASM_SYMS=y +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLUB_DEBUG=y +# CONFIG_COMPAT_BRK is not set +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +# CONFIG_PROFILING is not set +# CONFIG_MARKERS is not set +CONFIG_HAVE_OPROFILE=y +# CONFIG_KPROBES is not set +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_CLK=y +# CONFIG_SLOW_WORK is not set +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +CONFIG_MODULE_FORCE_LOAD=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_BLOCK=y +CONFIG_LBD=y +# CONFIG_BLK_DEV_BSG is not set +CONFIG_BLK_DEV_INTEGRITY=y + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_DEFAULT_AS=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="anticipatory" +CONFIG_FREEZER=y + +# +# System Type +# +# CONFIG_ARCH_AAEC2000 is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_GEMINI is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_IMX is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP23XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_KIRKWOOD is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_NS9XXX is not set +# CONFIG_ARCH_LOKI is not set +# CONFIG_ARCH_MV78XX0 is not set +# CONFIG_ARCH_MXC is not set +# CONFIG_ARCH_ORION5X is not set +# CONFIG_ARCH_PNX4008 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_MMP is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +CONFIG_ARCH_S3C2410=y +# CONFIG_ARCH_S3C64XX is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_LH7A40X is not set +# CONFIG_ARCH_DAVINCI is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_ARCH_MSM is not set +# CONFIG_ARCH_W90X900 is not set +CONFIG_PLAT_S3C24XX=y +CONFIG_S3C2410_CLOCK=y +CONFIG_CPU_S3C244X=y +CONFIG_S3C24XX_PWM=y +CONFIG_S3C24XX_GPIO_EXTRA=0 +CONFIG_S3C2410_DMA=y +# CONFIG_S3C2410_DMA_DEBUG is not set +CONFIG_S3C24XX_ADC=y +CONFIG_PLAT_S3C=y +CONFIG_CPU_LLSERIAL_S3C2440_ONLY=y +CONFIG_CPU_LLSERIAL_S3C2440=y + +# +# Boot options +# +# CONFIG_S3C_BOOT_WATCHDOG is not set +# CONFIG_S3C_BOOT_ERROR_RESET is not set +CONFIG_S3C_BOOT_UART_FORCE_FIFO=y + +# +# Power management +# +# CONFIG_S3C2410_PM_DEBUG is not set +# CONFIG_S3C2410_PM_CHECK is not set +CONFIG_S3C_LOWLEVEL_UART_PORT=0 +CONFIG_S3C_GPIO_SPACE=0 + +# +# S3C2400 Machines +# +CONFIG_S3C2410_PM=y +CONFIG_S3C2410_GPIO=y + +# +# S3C2410 Machines +# +# CONFIG_ARCH_SMDK2410 is not set +# CONFIG_ARCH_H1940 is not set +# CONFIG_MACH_N30 is not set +# CONFIG_ARCH_BAST is not set +# CONFIG_MACH_OTOM is not set +# CONFIG_MACH_AML_M5900 is not set +# CONFIG_MACH_TCT_HAMMER is not set +# CONFIG_MACH_VR1000 is not set +# CONFIG_MACH_QT2410 is not set + +# +# S3C2412 Machines +# +# CONFIG_MACH_JIVE is not set +# CONFIG_MACH_SMDK2413 is not set +# CONFIG_MACH_SMDK2412 is not set +# CONFIG_MACH_VSTMS is not set +CONFIG_CPU_S3C2440=y +CONFIG_S3C2440_DMA=y + +# +# S3C2440 Machines +# +# CONFIG_MACH_ANUBIS is not set +# CONFIG_MACH_OSIRIS is not set +# CONFIG_MACH_RX3715 is not set +# CONFIG_ARCH_S3C2440 is not set +# CONFIG_MACH_NEXCODER_2440 is not set +# CONFIG_MACH_AT2440EVB is not set +CONFIG_MACH_MINI2440=y + +# +# S3C2442 Machines +# + +# +# S3C2443 Machines +# +# CONFIG_MACH_SMDK2443 is not set + +# +# Processor Type +# +CONFIG_CPU_32=y +CONFIG_CPU_ARM920T=y +CONFIG_CPU_32v4T=y +CONFIG_CPU_ABRT_EV4T=y +CONFIG_CPU_PABRT_NOIFAR=y +CONFIG_CPU_CACHE_V4WT=y +CONFIG_CPU_CACHE_VIVT=y +CONFIG_CPU_COPY_V4WB=y +CONFIG_CPU_TLB_V4WBI=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y + +# +# Processor Features +# +CONFIG_ARM_THUMB=y +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_WRITETHROUGH is not set +# CONFIG_OUTER_CACHE is not set + +# +# Bus support +# +# CONFIG_PCI_SYSCALL is not set +# CONFIG_ARCH_SUPPORTS_MSI is not set +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_1G is not set +CONFIG_PAGE_OFFSET=0xC0000000 +# CONFIG_PREEMPT is not set +CONFIG_HZ=200 +CONFIG_AEABI=y +# CONFIG_OABI_COMPAT is not set +CONFIG_ARCH_FLATMEM_HAS_HOLES=y +# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set +# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set +# CONFIG_HIGHMEM is not set +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_PAGEFLAGS_EXTENDED=y +CONFIG_SPLIT_PTLOCK_CPUS=4096 +# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 +CONFIG_VIRT_TO_BUS=y +CONFIG_UNEVICTABLE_LRU=y +CONFIG_HAVE_MLOCK=y +CONFIG_HAVE_MLOCKED_PAGE_BIT=y +CONFIG_ALIGNMENT_TRAP=y + +# +# Boot options +# +CONFIG_ZBOOT_ROM_TEXT=0 +CONFIG_ZBOOT_ROM_BSS=0 +CONFIG_CMDLINE="" +# CONFIG_XIP_KERNEL is not set +CONFIG_KEXEC=y +CONFIG_ATAGS_PROC=y + +# +# CPU Power Management +# +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# + +# +# Userspace binary formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_HAVE_AOUT=y +CONFIG_BINFMT_AOUT=m +CONFIG_BINFMT_MISC=m + +# +# Power management options +# +CONFIG_PM=y +# CONFIG_PM_DEBUG is not set +CONFIG_PM_SLEEP=y +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +CONFIG_APM_EMULATION=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +CONFIG_UNIX=y +CONFIG_XFRM=y +CONFIG_XFRM_USER=m +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +CONFIG_NET_KEY=m +# CONFIG_NET_KEY_MIGRATE 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=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +CONFIG_IP_MROUTE=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +# CONFIG_ARPD is not set +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 is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG 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=y + +# +# Core Netfilter Configuration +# +# CONFIG_NETFILTER_NETLINK_QUEUE is not set +# CONFIG_NETFILTER_NETLINK_LOG is not set +# CONFIG_NF_CONNTRACK is not set +# CONFIG_NETFILTER_XTABLES is not set +# CONFIG_IP_VS is not set + +# +# IP: Netfilter Configuration +# +# CONFIG_NF_DEFRAG_IPV4 is not set +# CONFIG_IP_NF_QUEUE is not set +# CONFIG_IP_NF_IPTABLES is not set +# CONFIG_IP_NF_ARPTABLES is not set +# CONFIG_BRIDGE_NF_EBTABLES 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_STP=m +CONFIG_GARP=m +CONFIG_BRIDGE=m +# CONFIG_NET_DSA is not set +CONFIG_VLAN_8021Q=m +CONFIG_VLAN_8021Q_GVRP=y +# CONFIG_DECNET is not set +CONFIG_LLC=m +# CONFIG_LLC2 is not set +# 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_PHONET is not set +# CONFIG_NET_SCHED is not set +# CONFIG_DCB is not set + +# +# Network testing +# +CONFIG_NET_PKTGEN=m +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_IRDA is not set +CONFIG_BT=m +CONFIG_BT_L2CAP=m +CONFIG_BT_SCO=m +CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=m +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_HIDP=m + +# +# Bluetooth device drivers +# +CONFIG_BT_HCIBTUSB=m +CONFIG_BT_HCIBTSDIO=m +CONFIG_BT_HCIUART=m +CONFIG_BT_HCIUART_H4=y +CONFIG_BT_HCIUART_BCSP=y +CONFIG_BT_HCIUART_LL=y +CONFIG_BT_HCIBCM203X=m +CONFIG_BT_HCIBPA10X=m +CONFIG_BT_HCIBFUSB=m +CONFIG_BT_HCIVHCI=m +# CONFIG_AF_RXRPC is not set +CONFIG_FIB_RULES=y +CONFIG_WIRELESS=y +CONFIG_CFG80211=m +CONFIG_CFG80211_REG_DEBUG=y +CONFIG_WIRELESS_OLD_REGULATORY=y +CONFIG_WIRELESS_EXT=y +CONFIG_WIRELESS_EXT_SYSFS=y +CONFIG_LIB80211=m +CONFIG_LIB80211_CRYPT_WEP=m +CONFIG_LIB80211_CRYPT_CCMP=m +CONFIG_LIB80211_CRYPT_TKIP=m +# CONFIG_LIB80211_DEBUG is not set +CONFIG_MAC80211=m + +# +# Rate control algorithm selection +# +CONFIG_MAC80211_RC_MINSTREL=y +# CONFIG_MAC80211_RC_DEFAULT_PID is not set +CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y +CONFIG_MAC80211_RC_DEFAULT="minstrel" +CONFIG_MAC80211_MESH=y +CONFIG_MAC80211_LEDS=y +# CONFIG_MAC80211_DEBUGFS is not set +# CONFIG_MAC80211_DEBUG_MENU is not set +# CONFIG_WIMAX 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_FIRMWARE_IN_KERNEL is not set +CONFIG_EXTRA_FIRMWARE="" +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +CONFIG_CONNECTOR=m +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_CONCAT=y +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_TESTS is not set +# CONFIG_MTD_REDBOOT_PARTS is not set +CONFIG_MTD_CMDLINE_PARTS=y +# CONFIG_MTD_AFS_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=y +CONFIG_NFTL=y +CONFIG_NFTL_RW=y +CONFIG_INFTL=y +CONFIG_RFD_FTL=y +# CONFIG_SSFDC is not set +# CONFIG_MTD_OOPS is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +CONFIG_MTD_JEDECPROBE=y +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS 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_CFI_INTELEXT is not set +CONFIG_MTD_CFI_AMDSTD=y +CONFIG_MTD_CFI_STAA=y +CONFIG_MTD_CFI_UTIL=y +CONFIG_MTD_RAM=y +CONFIG_MTD_ROM=y +# CONFIG_MTD_ABSENT is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_ARM_INTEGRATOR is not set +# CONFIG_MTD_IMPA7 is not set +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_DATAFLASH is not set +# CONFIG_MTD_M25P80 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# 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_GPIO is not set +CONFIG_MTD_NAND_IDS=y +CONFIG_MTD_NAND_S3C2410=y +# CONFIG_MTD_NAND_S3C2410_DEBUG is not set +# CONFIG_MTD_NAND_S3C2410_HWECC is not set +# CONFIG_MTD_NAND_S3C2410_CLKSTOP is not set +# CONFIG_MTD_NAND_DISKONCHIP is not set +# CONFIG_MTD_NAND_NANDSIM is not set +CONFIG_MTD_NAND_PLATFORM=y +# CONFIG_MTD_ALAUDA is not set +# CONFIG_MTD_ONENAND is not set + +# +# LPDDR flash memory drivers +# +CONFIG_MTD_LPDDR=y +CONFIG_MTD_QINFO_PROBE=y + +# +# UBI - Unsorted block images +# +# CONFIG_MTD_UBI is not set +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=m +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +CONFIG_BLK_DEV_NBD=m +# CONFIG_BLK_DEV_UB is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=65536 +# CONFIG_BLK_DEV_XIP is not set +CONFIG_CDROM_PKTCDVD=m +CONFIG_CDROM_PKTCDVD_BUFFERS=8 +# CONFIG_CDROM_PKTCDVD_WCACHE is not set +# CONFIG_ATA_OVER_ETH is not set +CONFIG_MISC_DEVICES=y +# CONFIG_ICS932S401 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_ISL29003 is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +CONFIG_EEPROM_AT24=y +# CONFIG_EEPROM_AT25 is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_93CX6 is not set +CONFIG_HAVE_IDE=y +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=m +CONFIG_SCSI_DMA=y +# CONFIG_SCSI_TGT is not set +# CONFIG_SCSI_NETLINK is not set +# CONFIG_SCSI_PROC_FS is not set + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=m +# 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=m +# 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 is not set +# CONFIG_SCSI_DH is not set +# CONFIG_SCSI_OSD_INITIATOR is not set +# CONFIG_ATA is not set +# CONFIG_MD is not set +CONFIG_NETDEVICES=y +CONFIG_COMPAT_NET_DEV_OPS=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_MACVLAN is not set +# CONFIG_EQUALIZER is not set +CONFIG_TUN=m +# CONFIG_VETH is not set +# CONFIG_PHYLIB is not set +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_AX88796 is not set +# CONFIG_SMC91X is not set +CONFIG_DM9000=y +CONFIG_DM9000_DEBUGLEVEL=4 +# CONFIG_DM9000_FORCE_SIMPLE_PHY_POLL is not set +# CONFIG_ENC28J60 is not set +# CONFIG_ETHOC is not set +# CONFIG_SMC911X is not set +# CONFIG_SMSC911X is not set +# CONFIG_DNET 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_IBM_NEW_EMAC_NO_FLOW_CTRL is not set +# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set +# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set +# CONFIG_B44 is not set +# CONFIG_NETDEV_1000 is not set +# CONFIG_NETDEV_10000 is not set + +# +# Wireless LAN +# +# CONFIG_WLAN_PRE80211 is not set +CONFIG_WLAN_80211=y +CONFIG_LIBERTAS=m +# CONFIG_LIBERTAS_USB is not set +CONFIG_LIBERTAS_SDIO=m +# CONFIG_LIBERTAS_SPI is not set +# CONFIG_LIBERTAS_DEBUG is not set +# CONFIG_LIBERTAS_THINFIRM is not set +# CONFIG_AT76C50X_USB is not set +# CONFIG_USB_ZD1201 is not set +# CONFIG_USB_NET_RNDIS_WLAN is not set +# CONFIG_RTL8187 is not set +# CONFIG_MAC80211_HWSIM is not set +# CONFIG_P54_COMMON is not set +# CONFIG_AR9170_USB is not set +CONFIG_HOSTAP=m +CONFIG_HOSTAP_FIRMWARE=y +CONFIG_HOSTAP_FIRMWARE_NVRAM=y +# CONFIG_B43 is not set +# CONFIG_B43LEGACY is not set +CONFIG_ZD1211RW=m +CONFIG_ZD1211RW_DEBUG=y +# CONFIG_RT2X00 is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# + +# +# USB Network Adapters +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_USBNET is not set +# CONFIG_WAN is not set +CONFIG_PPP=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_MPPE=m +# CONFIG_PPPOE is not set +# CONFIG_PPPOL2TP is not set +# CONFIG_SLIP is not set +CONFIG_SLHC=m +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y +CONFIG_INPUT_FF_MEMLESS=y +# CONFIG_INPUT_POLLDEV is not set + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_EVBUG=m + +# +# 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=y +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=y +CONFIG_MOUSE_PS2_ALPS=y +CONFIG_MOUSE_PS2_LOGIPS2PP=y +CONFIG_MOUSE_PS2_SYNAPTICS=y +CONFIG_MOUSE_PS2_TRACKPOINT=y +# CONFIG_MOUSE_PS2_ELANTECH is not set +# CONFIG_MOUSE_PS2_TOUCHKIT is not set +# CONFIG_MOUSE_SERIAL is not set +# CONFIG_MOUSE_APPLETOUCH is not set +# CONFIG_MOUSE_BCM5974 is not set +# CONFIG_MOUSE_VSXXXAA is not set +# CONFIG_MOUSE_GPIO is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +CONFIG_INPUT_TOUCHSCREEN=y +# CONFIG_TOUCHSCREEN_ADS7846 is not set +# CONFIG_TOUCHSCREEN_AD7877 is not set +# CONFIG_TOUCHSCREEN_AD7879_I2C is not set +# CONFIG_TOUCHSCREEN_AD7879_SPI is not set +# CONFIG_TOUCHSCREEN_AD7879 is not set +# CONFIG_TOUCHSCREEN_FUJITSU is not set +# CONFIG_TOUCHSCREEN_GUNZE is not set +# CONFIG_TOUCHSCREEN_ELO is not set +# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set +# CONFIG_TOUCHSCREEN_MTOUCH is not set +# CONFIG_TOUCHSCREEN_INEXIO is not set +# CONFIG_TOUCHSCREEN_MK712 is not set +# CONFIG_TOUCHSCREEN_PENMOUNT is not set +# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set +# CONFIG_TOUCHSCREEN_TOUCHWIN is not set +# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set +# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set +# CONFIG_TOUCHSCREEN_TSC2007 is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_SERIO_SERPORT=y +CONFIG_SERIO_LIBPS2=y +CONFIG_SERIO_RAW=y +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +CONFIG_VT_HW_CONSOLE_BINDING=y +CONFIG_DEVKMEM=y +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_SAMSUNG=y +CONFIG_SERIAL_SAMSUNG_UARTS=3 +CONFIG_SERIAL_SAMSUNG_CONSOLE=y +CONFIG_SERIAL_S3C2440=y +# CONFIG_SERIAL_MAX3100 is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=128 +CONFIG_IPMI_HANDLER=m +# CONFIG_IPMI_PANIC_EVENT is not set +CONFIG_IPMI_DEVICE_INTERFACE=m +CONFIG_IPMI_SI=m +CONFIG_IPMI_WATCHDOG=m +CONFIG_IPMI_POWEROFF=m +CONFIG_HW_RANDOM=y +# CONFIG_HW_RANDOM_TIMERIOMEM is not set +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_HELPER_AUTO=y +CONFIG_I2C_ALGOBIT=y + +# +# I2C Hardware Bus support +# + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_GPIO is not set +# CONFIG_I2C_OCORES is not set +CONFIG_I2C_S3C2410=y +CONFIG_I2C_SIMTEC=y + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_STUB is not set + +# +# Miscellaneous I2C Chip support +# +# CONFIG_DS1682 is not set +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_PCF8575 is not set +# CONFIG_SENSORS_PCA9539 is not set +# CONFIG_SENSORS_MAX6875 is not set +CONFIG_SENSORS_TSL2550=m +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +CONFIG_SPI_BITBANG=y +# CONFIG_SPI_GPIO is not set +CONFIG_SPI_S3C24XX=y +# CONFIG_SPI_S3C24XX_GPIO is not set + +# +# SPI Protocol Masters +# +CONFIG_SPI_SPIDEV=y +# CONFIG_SPI_TLE62X0 is not set +CONFIG_ARCH_REQUIRE_GPIOLIB=y +CONFIG_GPIOLIB=y +# CONFIG_DEBUG_GPIO is not set +CONFIG_GPIO_SYSFS=y + +# +# Memory mapped GPIO expanders: +# + +# +# I2C GPIO expanders: +# +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_GPIO_PCF857X is not set + +# +# PCI GPIO expanders: +# + +# +# SPI GPIO expanders: +# +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MCP23S08 is not set +# CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 is not set +# CONFIG_SENSORS_ADCXX is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1029 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ADT7462 is not set +# CONFIG_SENSORS_ADT7470 is not set +# CONFIG_SENSORS_ADT7473 is not set +# CONFIG_SENSORS_ADT7475 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_IBMAEM is not set +# CONFIG_SENSORS_IBMPEX is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM70 is not set +CONFIG_SENSORS_LM75=y +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_LM93 is not set +# CONFIG_SENSORS_LTC4215 is not set +# CONFIG_SENSORS_LTC4245 is not set +# CONFIG_SENSORS_LM95241 is not set +# CONFIG_SENSORS_MAX1111 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_MAX6650 is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_SHT15 is not set +# CONFIG_SENSORS_DME1737 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_THMC50 is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83L786NG is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_SENSORS_LIS3_SPI is not set +# CONFIG_HWMON_DEBUG_CHIP is not set +CONFIG_THERMAL=m +# CONFIG_THERMAL_HWMON is not set +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +# CONFIG_SOFT_WATCHDOG is not set +CONFIG_S3C2410_WATCHDOG=y + +# +# USB-based Watchdog Cards +# +# CONFIG_USBPCWATCHDOG is not set +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_ASIC3 is not set +# CONFIG_HTC_EGPIO is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_TPS65010 is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_T7L66XB is not set +# CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_TC6393XB is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_PCF50633 is not set + +# +# Multimedia devices +# + +# +# Multimedia core support +# +CONFIG_VIDEO_DEV=m +CONFIG_VIDEO_V4L2_COMMON=m +CONFIG_VIDEO_ALLOW_V4L1=y +CONFIG_VIDEO_V4L1_COMPAT=y +CONFIG_DVB_CORE=m +CONFIG_VIDEO_MEDIA=m + +# +# Multimedia drivers +# +# CONFIG_MEDIA_ATTACH is not set +CONFIG_MEDIA_TUNER=m +# CONFIG_MEDIA_TUNER_CUSTOMISE is not set +CONFIG_MEDIA_TUNER_SIMPLE=m +CONFIG_MEDIA_TUNER_TDA8290=m +CONFIG_MEDIA_TUNER_TDA9887=m +CONFIG_MEDIA_TUNER_TEA5761=m +CONFIG_MEDIA_TUNER_TEA5767=m +CONFIG_MEDIA_TUNER_MT20XX=m +CONFIG_MEDIA_TUNER_XC2028=m +CONFIG_MEDIA_TUNER_XC5000=m +CONFIG_MEDIA_TUNER_MC44S803=m +CONFIG_VIDEO_V4L2=m +CONFIG_VIDEO_V4L1=m +CONFIG_VIDEOBUF_GEN=m +CONFIG_VIDEO_CAPTURE_DRIVERS=y +# CONFIG_VIDEO_ADV_DEBUG is not set +# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set +CONFIG_VIDEO_HELPER_CHIPS_AUTO=y +# CONFIG_VIDEO_VIVI is not set +# CONFIG_VIDEO_CPIA is not set +# CONFIG_VIDEO_CPIA2 is not set +# CONFIG_VIDEO_SAA5246A is not set +# CONFIG_VIDEO_SAA5249 is not set +# CONFIG_VIDEO_AU0828 is not set +CONFIG_SOC_CAMERA=m +# CONFIG_SOC_CAMERA_MT9M001 is not set +# CONFIG_SOC_CAMERA_MT9M111 is not set +# CONFIG_SOC_CAMERA_MT9T031 is not set +# CONFIG_SOC_CAMERA_MT9V022 is not set +# CONFIG_SOC_CAMERA_TW9910 is not set +CONFIG_SOC_CAMERA_PLATFORM=m +# CONFIG_SOC_CAMERA_OV772X is not set +# CONFIG_VIDEO_SH_MOBILE_CEU is not set +CONFIG_V4L_USB_DRIVERS=y +# CONFIG_USB_VIDEO_CLASS is not set +CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y +CONFIG_USB_GSPCA=m +# CONFIG_USB_M5602 is not set +# CONFIG_USB_STV06XX is not set +# CONFIG_USB_GSPCA_CONEX is not set +# CONFIG_USB_GSPCA_ETOMS is not set +# CONFIG_USB_GSPCA_FINEPIX is not set +# CONFIG_USB_GSPCA_MARS is not set +# CONFIG_USB_GSPCA_MR97310A is not set +# CONFIG_USB_GSPCA_OV519 is not set +# CONFIG_USB_GSPCA_OV534 is not set +# CONFIG_USB_GSPCA_PAC207 is not set +# CONFIG_USB_GSPCA_PAC7311 is not set +# CONFIG_USB_GSPCA_SONIXB is not set +# CONFIG_USB_GSPCA_SONIXJ is not set +# CONFIG_USB_GSPCA_SPCA500 is not set +# CONFIG_USB_GSPCA_SPCA501 is not set +# CONFIG_USB_GSPCA_SPCA505 is not set +# CONFIG_USB_GSPCA_SPCA506 is not set +# CONFIG_USB_GSPCA_SPCA508 is not set +# CONFIG_USB_GSPCA_SPCA561 is not set +# CONFIG_USB_GSPCA_SQ905 is not set +# CONFIG_USB_GSPCA_SQ905C is not set +# CONFIG_USB_GSPCA_STK014 is not set +# CONFIG_USB_GSPCA_SUNPLUS is not set +# CONFIG_USB_GSPCA_T613 is not set +# CONFIG_USB_GSPCA_TV8532 is not set +# CONFIG_USB_GSPCA_VC032X is not set +CONFIG_USB_GSPCA_ZC3XX=m +# CONFIG_VIDEO_PVRUSB2 is not set +# CONFIG_VIDEO_HDPVR is not set +# CONFIG_VIDEO_EM28XX is not set +# CONFIG_VIDEO_CX231XX is not set +# CONFIG_VIDEO_USBVISION is not set +# CONFIG_USB_VICAM is not set +# CONFIG_USB_IBMCAM is not set +# CONFIG_USB_KONICAWC is not set +# CONFIG_USB_QUICKCAM_MESSENGER is not set +# CONFIG_USB_ET61X251 is not set +# CONFIG_VIDEO_OVCAMCHIP is not set +# CONFIG_USB_OV511 is not set +# CONFIG_USB_SE401 is not set +# CONFIG_USB_SN9C102 is not set +# CONFIG_USB_STV680 is not set +# CONFIG_USB_ZC0301 is not set +# CONFIG_USB_PWC is not set +# CONFIG_USB_PWC_INPUT_EVDEV is not set +# CONFIG_USB_ZR364XX is not set +# CONFIG_USB_STKWEBCAM is not set +# CONFIG_USB_S2255 is not set +CONFIG_RADIO_ADAPTERS=y +# CONFIG_USB_DSBR is not set +# CONFIG_USB_SI470X is not set +# CONFIG_USB_MR800 is not set +# CONFIG_RADIO_TEA5764 is not set +# CONFIG_DVB_DYNAMIC_MINORS is not set +CONFIG_DVB_CAPTURE_DRIVERS=y +# CONFIG_TTPCI_EEPROM is not set + +# +# Supported USB Adapters +# +# CONFIG_DVB_USB is not set +# CONFIG_DVB_SIANO_SMS1XXX is not set + +# +# Supported FlexCopII (B2C2) Adapters +# +# CONFIG_DVB_B2C2_FLEXCOP is not set + +# +# Supported DVB Frontends +# +# CONFIG_DVB_FE_CUSTOMISE is not set +# CONFIG_DAB is not set + +# +# Graphics support +# +# CONFIG_VGASTATE is not set +CONFIG_VIDEO_OUTPUT_CONTROL=y +CONFIG_FB=y +CONFIG_FIRMWARE_EDID=y +# CONFIG_FB_DDC is not set +# CONFIG_FB_BOOT_VESA_SUPPORT is not set +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +# CONFIG_FB_SYS_FILLRECT is not set +# CONFIG_FB_SYS_COPYAREA is not set +# CONFIG_FB_SYS_IMAGEBLIT is not set +# CONFIG_FB_FOREIGN_ENDIAN is not set +# CONFIG_FB_SYS_FOPS is not set +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_BACKLIGHT is not set +CONFIG_FB_MODE_HELPERS=y +CONFIG_FB_TILEBLITTING=y + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_UVESA is not set +# CONFIG_FB_S1D13XXX is not set +CONFIG_FB_S3C2410=y +# CONFIG_FB_S3C2410_DEBUG is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_MB862XX is not set +# CONFIG_FB_BROADSHEET is not set +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_LCD_CLASS_DEVICE=y +# CONFIG_LCD_LTV350QV is not set +# CONFIG_LCD_ILI9320 is not set +# CONFIG_LCD_TDO24M is not set +# CONFIG_LCD_VGG2432A4 is not set +CONFIG_LCD_PLATFORM=y +CONFIG_BACKLIGHT_CLASS_DEVICE=y +# CONFIG_BACKLIGHT_GENERIC is not set +CONFIG_BACKLIGHT_PWM=y + +# +# Display device support +# +CONFIG_DISPLAY_SUPPORT=y + +# +# Display hardware drivers +# + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y +CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y +CONFIG_FONTS=y +CONFIG_FONT_8x8=y +# CONFIG_FONT_8x16 is not set +# CONFIG_FONT_6x11 is not set +# CONFIG_FONT_7x14 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set +CONFIG_FONT_MINI_4x6=y +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_SUN12x22 is not set +# CONFIG_FONT_10x18 is not set +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_LOGO_LINUX_CLUT224=y +CONFIG_SOUND=y +CONFIG_SOUND_OSS_CORE=y +CONFIG_SND=y +CONFIG_SND_TIMER=y +CONFIG_SND_PCM=y +CONFIG_SND_HWDEP=m +CONFIG_SND_RAWMIDI=m +CONFIG_SND_JACK=y +CONFIG_SND_SEQUENCER=m +CONFIG_SND_SEQ_DUMMY=m +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=m +CONFIG_SND_PCM_OSS=m +CONFIG_SND_PCM_OSS_PLUGINS=y +CONFIG_SND_SEQUENCER_OSS=y +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_VERBOSE_PROCFS=y +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set +# CONFIG_SND_DRIVERS is not set +# CONFIG_SND_ARM is not set +# CONFIG_SND_SPI is not set +CONFIG_SND_USB=y +CONFIG_SND_USB_AUDIO=m +CONFIG_SND_USB_CAIAQ=m +CONFIG_SND_USB_CAIAQ_INPUT=y +CONFIG_SND_SOC=y +CONFIG_SND_S3C24XX_SOC=y +CONFIG_SND_S3C24XX_SOC_I2S=y +# CONFIG_SND_S3C24XX_SOC_LN2440SBC_ALC650 is not set +CONFIG_SND_S3C24XX_SOC_S3C24XX_UDA134X=y +CONFIG_SND_SOC_I2C_AND_SPI=y +# CONFIG_SND_SOC_ALL_CODECS is not set +CONFIG_SND_SOC_L3=y +CONFIG_SND_SOC_UDA134X=y +# CONFIG_SOUND_PRIME is not set +CONFIG_HID_SUPPORT=y +CONFIG_HID=y +# CONFIG_HID_DEBUG is not set +CONFIG_HIDRAW=y + +# +# USB Input Devices +# +CONFIG_USB_HID=y +CONFIG_HID_PID=y +CONFIG_USB_HIDDEV=y + +# +# Special HID drivers +# +CONFIG_HID_A4TECH=y +CONFIG_HID_APPLE=y +CONFIG_HID_BELKIN=y +CONFIG_HID_CHERRY=y +CONFIG_HID_CHICONY=y +CONFIG_HID_CYPRESS=y +# CONFIG_DRAGONRISE_FF is not set +CONFIG_HID_EZKEY=y +CONFIG_HID_KYE=y +CONFIG_HID_GYRATION=y +CONFIG_HID_KENSINGTON=y +CONFIG_HID_LOGITECH=y +# CONFIG_LOGITECH_FF is not set +# CONFIG_LOGIRUMBLEPAD2_FF is not set +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MONTEREY=y +CONFIG_HID_NTRIG=y +CONFIG_HID_PANTHERLORD=y +# CONFIG_PANTHERLORD_FF is not set +CONFIG_HID_PETALYNX=y +CONFIG_HID_SAMSUNG=y +CONFIG_HID_SONY=y +CONFIG_HID_SUNPLUS=y +# CONFIG_GREENASIA_FF is not set +CONFIG_HID_TOPSEED=y +# CONFIG_THRUSTMASTER_FF is not set +# CONFIG_ZEROPLUS_FF is not set +CONFIG_USB_SUPPORT=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +# CONFIG_USB_ARCH_HAS_EHCI is not set +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set +# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_DEVICE_CLASS is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_SUSPEND is not set +# CONFIG_USB_OTG is not set +# CONFIG_USB_MON is not set +# CONFIG_USB_WUSB is not set +# CONFIG_USB_WUSB_CBAF is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_ISP1760_HCD is not set +CONFIG_USB_OHCI_HCD=y +# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set +# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_HWA_HCD is not set +# CONFIG_USB_MUSB_HDRC is not set +# CONFIG_USB_GADGET_MUSB_HDRC is not set + +# +# USB Device Class drivers +# +CONFIG_USB_ACM=m +# CONFIG_USB_PRINTER is not set +CONFIG_USB_WDM=m +# CONFIG_USB_TMC is not set + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# + +# +# also be needed; see USB_STORAGE Help for more info +# +CONFIG_USB_STORAGE=m +# CONFIG_USB_STORAGE_DEBUG is not set +CONFIG_USB_STORAGE_DATAFAB=m +# CONFIG_USB_STORAGE_FREECOM is not set +CONFIG_USB_STORAGE_ISD200=m +CONFIG_USB_STORAGE_USBAT=m +CONFIG_USB_STORAGE_SDDR09=m +CONFIG_USB_STORAGE_SDDR55=m +CONFIG_USB_STORAGE_JUMPSHOT=m +CONFIG_USB_STORAGE_ALAUDA=m +# CONFIG_USB_STORAGE_ONETOUCH is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set +CONFIG_USB_LIBUSUAL=y + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set + +# +# USB port drivers +# +CONFIG_USB_SERIAL=m +# CONFIG_USB_EZUSB is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_AIRCABLE is not set +# CONFIG_USB_SERIAL_ARK3116 is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_CH341 is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +CONFIG_USB_SERIAL_CP210X=m +# CONFIG_USB_SERIAL_CYPRESS_M8 is not set +# CONFIG_USB_SERIAL_EMPEG is not set +CONFIG_USB_SERIAL_FTDI_SIO=m +# CONFIG_USB_SERIAL_FUNSOFT is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT_TI is not set +# CONFIG_USB_SERIAL_GARMIN is not set +# CONFIG_USB_SERIAL_IPW is not set +# CONFIG_USB_SERIAL_IUU is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KLSI is not set +# CONFIG_USB_SERIAL_KOBIL_SCT is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_MOS7720 is not set +# CONFIG_USB_SERIAL_MOS7840 is not set +# CONFIG_USB_SERIAL_MOTOROLA is not set +# CONFIG_USB_SERIAL_NAVMAN is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_OTI6858 is not set +# CONFIG_USB_SERIAL_QUALCOMM is not set +CONFIG_USB_SERIAL_SPCP8X5=m +# CONFIG_USB_SERIAL_HP4X is not set +# CONFIG_USB_SERIAL_SAFE is not set +# CONFIG_USB_SERIAL_SIEMENS_MPI is not set +# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set +# CONFIG_USB_SERIAL_SYMBOL is not set +# CONFIG_USB_SERIAL_TI is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OPTION is not set +# CONFIG_USB_SERIAL_OMNINET is not set +# CONFIG_USB_SERIAL_OPTICON is not set +# CONFIG_USB_SERIAL_DEBUG is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_BERRY_CHARGE is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_VST is not set +CONFIG_USB_GADGET=y +# CONFIG_USB_GADGET_DEBUG is not set +# CONFIG_USB_GADGET_DEBUG_FILES is not set +# CONFIG_USB_GADGET_DEBUG_FS is not set +CONFIG_USB_GADGET_VBUS_DRAW=2 +CONFIG_USB_GADGET_SELECTED=y +# CONFIG_USB_GADGET_AT91 is not set +# CONFIG_USB_GADGET_ATMEL_USBA is not set +# CONFIG_USB_GADGET_FSL_USB2 is not set +# CONFIG_USB_GADGET_LH7A40X is not set +# CONFIG_USB_GADGET_OMAP is not set +# CONFIG_USB_GADGET_PXA25X is not set +# CONFIG_USB_GADGET_PXA27X is not set +CONFIG_USB_GADGET_S3C2410=y +CONFIG_USB_S3C2410=y +# CONFIG_USB_S3C2410_DEBUG is not set +# CONFIG_USB_GADGET_IMX is not set +# CONFIG_USB_GADGET_M66592 is not set +# CONFIG_USB_GADGET_AMD5536UDC is not set +# CONFIG_USB_GADGET_FSL_QE is not set +# CONFIG_USB_GADGET_CI13XXX is not set +# CONFIG_USB_GADGET_NET2280 is not set +# CONFIG_USB_GADGET_GOKU is not set +# CONFIG_USB_GADGET_DUMMY_HCD is not set +# CONFIG_USB_GADGET_DUALSPEED is not set +CONFIG_USB_ZERO=m +CONFIG_USB_ETH=m +CONFIG_USB_ETH_RNDIS=y +CONFIG_USB_GADGETFS=m +CONFIG_USB_FILE_STORAGE=m +# CONFIG_USB_FILE_STORAGE_TEST is not set +CONFIG_USB_G_SERIAL=m +# CONFIG_USB_MIDI_GADGET is not set +# CONFIG_USB_G_PRINTER is not set +CONFIG_USB_CDC_COMPOSITE=m + +# +# OTG and related infrastructure +# +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_NOP_USB_XCEIV is not set +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set +# CONFIG_MMC_UNSAFE_RESUME is not set + +# +# MMC/SD/SDIO Card Drivers +# +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_BOUNCE=y +CONFIG_SDIO_UART=y +# CONFIG_MMC_TEST is not set + +# +# MMC/SD/SDIO Host Controller Drivers +# +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SPI=y +CONFIG_MMC_S3C=y +# CONFIG_MEMSTICK is not set +# CONFIG_ACCESSIBILITY is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y + +# +# LED drivers +# +CONFIG_LEDS_S3C24XX=y +# CONFIG_LEDS_PCA9532 is not set +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_GPIO_PLATFORM=y +# CONFIG_LEDS_LP5521 is not set +# CONFIG_LEDS_PCA955X is not set +# CONFIG_LEDS_DAC124S085 is not set +# CONFIG_LEDS_PWM is not set +# CONFIG_LEDS_BD2802 is not set + +# +# LED Triggers +# +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_TIMER=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +CONFIG_LEDS_TRIGGER_BACKLIGHT=y +CONFIG_LEDS_TRIGGER_GPIO=y +CONFIG_LEDS_TRIGGER_DEFAULT_ON=y + +# +# iptables trigger is under Netfilter config (LED target) +# +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +CONFIG_RTC_INTF_DEV_UIE_EMUL=y +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8581 is not set + +# +# SPI RTC drivers +# +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_DS3234 is not set + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_V3020 is not set + +# +# on-CPU RTC drivers +# +CONFIG_RTC_DRV_S3C=y +CONFIG_DMADEVICES=y + +# +# DMA Devices +# +# CONFIG_AUXDISPLAY is not set +# CONFIG_REGULATOR is not set +# CONFIG_UIO is not set +# CONFIG_STAGING is not set + +# +# File systems +# +CONFIG_EXT2_FS=m +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set +CONFIG_EXT3_FS_XATTR=y +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +# CONFIG_EXT4_FS is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_FILE_LOCKING=y +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_BTRFS_FS is not set +CONFIG_DNOTIFY=y +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_QUOTA is not set +CONFIG_AUTOFS_FS=y +CONFIG_AUTOFS4_FS=y +# CONFIG_FUSE_FS is not set +CONFIG_GENERIC_ACL=y + +# +# Caches +# +# CONFIG_FSCACHE is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +# CONFIG_HUGETLB_PAGE is not set +CONFIG_CONFIGFS_FS=m +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_ECRYPT_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 is not set +# CONFIG_JFFS2_FS_XATTR is not set +# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set +CONFIG_JFFS2_ZLIB=y +# CONFIG_JFFS2_LZO is not set +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +CONFIG_CRAMFS=y +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +CONFIG_ROMFS_FS=y +# CONFIG_ROMFS_BACKED_BY_BLOCK is not set +# CONFIG_ROMFS_BACKED_BY_MTD is not set +CONFIG_ROMFS_BACKED_BY_BOTH=y +CONFIG_ROMFS_ON_BLOCK=y +CONFIG_ROMFS_ON_MTD=y +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +# CONFIG_NILFS2_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_ACL_SUPPORT=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +CONFIG_SUNRPC_GSS=y +CONFIG_RPCSEC_GSS_KRB5=y +# CONFIG_RPCSEC_GSS_SPKM3 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 is not set +CONFIG_MSDOS_PARTITION=y +CONFIG_BSD_DISKLABEL=y +CONFIG_MINIX_SUBPARTITION=y +CONFIG_SOLARIS_X86_PARTITION=y +CONFIG_UNIXWARE_DISKLABEL=y +CONFIG_LDM_PARTITION=y +# CONFIG_LDM_DEBUG 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=y +# CONFIG_SYSV68_PARTITION is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="cp437" +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_ASCII=m +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_UTF8=m +# CONFIG_DLM is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +# CONFIG_ENABLE_WARN_DEPRECATED is not set +# 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=y +# CONFIG_HEADERS_CHECK is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +CONFIG_DETECT_SOFTLOCKUP=y +# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0 +CONFIG_DETECT_HUNG_TASK=y +# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set +CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0 +# CONFIG_SCHED_DEBUG is not set +# CONFIG_SCHEDSTATS is not set +# CONFIG_TIMER_STATS is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_SLUB_STATS is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_KOBJECT is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_WRITECOUNT is not set +CONFIG_DEBUG_MEMORY_INIT=y +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_BOOT_PRINTK_DELAY is not set +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_RCU_CPU_STALL_DETECTOR is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_LATENCYTOP is not set +CONFIG_SYSCTL_SYSCALL_CHECK=y +# CONFIG_PAGE_POISONING is not set +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_TRACING_SUPPORT=y + +# +# Tracers +# +# CONFIG_FUNCTION_TRACER is not set +# CONFIG_SCHED_TRACER is not set +# CONFIG_CONTEXT_SWITCH_TRACER is not set +# CONFIG_EVENT_TRACER is not set +# CONFIG_BOOT_TRACER is not set +# CONFIG_TRACE_BRANCH_PROFILING is not set +# CONFIG_STACK_TRACER is not set +# CONFIG_KMEMTRACE is not set +# CONFIG_WORKQUEUE_TRACER is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_DYNAMIC_DEBUG is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +CONFIG_ARM_UNWIND=y +CONFIG_DEBUG_USER=y +# CONFIG_DEBUG_ERRORS is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_LL is not set +CONFIG_DEBUG_S3C_UART=0 + +# +# Security options +# +CONFIG_KEYS=y +# CONFIG_KEYS_DEBUG_PROC_KEYS is not set +# CONFIG_SECURITY is not set +# CONFIG_SECURITYFS is not set +CONFIG_SECURITY_FILE_CAPABILITIES=y +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_FIPS=y +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD=m +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_BLKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG=m +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_PCOMP=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +CONFIG_CRYPTO_GF128MUL=m +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_WORKQUEUE=y +CONFIG_CRYPTO_CRYPTD=m +CONFIG_CRYPTO_AUTHENC=m +CONFIG_CRYPTO_TEST=m + +# +# Authenticated Encryption with Associated Data +# +CONFIG_CRYPTO_CCM=m +CONFIG_CRYPTO_GCM=m +CONFIG_CRYPTO_SEQIV=m + +# +# Block modes +# +CONFIG_CRYPTO_CBC=y +CONFIG_CRYPTO_CTR=m +CONFIG_CRYPTO_CTS=m +CONFIG_CRYPTO_ECB=y +CONFIG_CRYPTO_LRW=m +CONFIG_CRYPTO_PCBC=m +CONFIG_CRYPTO_XTS=m + +# +# Hash modes +# +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_XCBC=m + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=m +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_MICHAEL_MIC=y +CONFIG_CRYPTO_RMD128=m +CONFIG_CRYPTO_RMD160=m +CONFIG_CRYPTO_RMD256=m +CONFIG_CRYPTO_RMD320=m +CONFIG_CRYPTO_SHA1=m +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=m +CONFIG_CRYPTO_TGR192=m +CONFIG_CRYPTO_WP512=m + +# +# Ciphers +# +CONFIG_CRYPTO_AES=y +CONFIG_CRYPTO_ANUBIS=m +CONFIG_CRYPTO_ARC4=y +CONFIG_CRYPTO_BLOWFISH=m +CONFIG_CRYPTO_CAMELLIA=m +CONFIG_CRYPTO_CAST5=m +CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_DES=y +CONFIG_CRYPTO_FCRYPT=m +CONFIG_CRYPTO_KHAZAD=m +CONFIG_CRYPTO_SALSA20=m +CONFIG_CRYPTO_SEED=m +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_TEA=m +CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_TWOFISH_COMMON=m + +# +# Compression +# +CONFIG_CRYPTO_DEFLATE=m +CONFIG_CRYPTO_ZLIB=m +CONFIG_CRYPTO_LZO=m + +# +# Random Number Generation +# +CONFIG_CRYPTO_ANSI_CPRNG=m +CONFIG_CRYPTO_HW=y +# CONFIG_BINARY_PRINTF is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_GENERIC_FIND_LAST_BIT=y +CONFIG_CRC_CCITT=m +CONFIG_CRC16=m +CONFIG_CRC_T10DIF=y +CONFIG_CRC_ITU_T=y +CONFIG_CRC32=y +CONFIG_CRC7=y +CONFIG_LIBCRC32C=m +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=m +CONFIG_LZO_DECOMPRESS=m +CONFIG_DECOMPRESS_GZIP=y +CONFIG_DECOMPRESS_BZIP2=y +CONFIG_DECOMPRESS_LZMA=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_DMA=y +CONFIG_NLATTR=y diff --git a/arch/arm/configs/mx21_defconfig b/arch/arm/configs/mx21_defconfig new file mode 100644 index 000000000000..4b04290d8e81 --- /dev/null +++ b/arch/arm/configs/mx21_defconfig @@ -0,0 +1,1170 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.30-rc1 +# Tue Apr 14 16:58:09 2009 +# +CONFIG_ARM=y +CONFIG_HAVE_PWM=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_GENERIC_GPIO=y +CONFIG_GENERIC_TIME=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_MMU=y +# CONFIG_NO_IOPORT is not set +CONFIG_GENERIC_HARDIRQS=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_HAVE_LATENCYTOP_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_ARCH_MTD_XIP=y +CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y +CONFIG_VECTORS_BASE=0xffff0000 +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +# CONFIG_SWAP is not set +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set +# CONFIG_AUDIT is not set + +# +# RCU Subsystem +# +CONFIG_CLASSIC_RCU=y +# CONFIG_TREE_RCU is not set +# CONFIG_PREEMPT_RCU is not set +# CONFIG_TREE_RCU_TRACE is not set +# CONFIG_PREEMPT_RCU_TRACE is not set +# CONFIG_IKCONFIG is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_GROUP_SCHED is not set +# CONFIG_CGROUPS 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 is not set +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y +CONFIG_EMBEDDED=y +CONFIG_UID16=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_EXTRA_PASS=y +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_COMPAT_BRK=y +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_KPROBES is not set +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +# CONFIG_SLOW_WORK is not set +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_BLOCK=y +# CONFIG_LBD is not set +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_BLK_DEV_INTEGRITY is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_AS is not set +# CONFIG_IOSCHED_DEADLINE is not set +# CONFIG_IOSCHED_CFQ is not set +# CONFIG_DEFAULT_AS is not set +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +CONFIG_DEFAULT_NOOP=y +CONFIG_DEFAULT_IOSCHED="noop" +# CONFIG_FREEZER is not set + +# +# System Type +# +# CONFIG_ARCH_AAEC2000 is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_GEMINI is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP23XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_KIRKWOOD is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_NS9XXX is not set +# CONFIG_ARCH_LOKI is not set +# CONFIG_ARCH_MV78XX0 is not set +CONFIG_ARCH_MXC=y +# CONFIG_ARCH_ORION5X is not set +# CONFIG_ARCH_PNX4008 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_MMP is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_S3C64XX is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_LH7A40X is not set +# CONFIG_ARCH_DAVINCI is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_ARCH_MSM is not set +# CONFIG_ARCH_W90X900 is not set + +# +# Freescale MXC Implementations +# +# CONFIG_ARCH_MX1 is not set +CONFIG_ARCH_MX2=y +# CONFIG_ARCH_MX3 is not set +CONFIG_MACH_MX21=y +# CONFIG_MACH_MX27 is not set + +# +# MX2 platforms: +# +CONFIG_MACH_MX21ADS=y +# CONFIG_MXC_IRQ_PRIOR is not set +CONFIG_MXC_PWM=y + +# +# Processor Type +# +CONFIG_CPU_32=y +CONFIG_CPU_ARM926T=y +CONFIG_CPU_32v5=y +CONFIG_CPU_ABRT_EV5TJ=y +CONFIG_CPU_PABRT_NOIFAR=y +CONFIG_CPU_CACHE_VIVT=y +CONFIG_CPU_COPY_V4WB=y +CONFIG_CPU_TLB_V4WBI=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y + +# +# Processor Features +# +CONFIG_ARM_THUMB=y +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_WRITETHROUGH is not set +# CONFIG_CPU_CACHE_ROUND_ROBIN is not set +# CONFIG_OUTER_CACHE is not set +CONFIG_COMMON_CLKDEV=y + +# +# Bus support +# +# CONFIG_PCI_SYSCALL is not set +# CONFIG_ARCH_SUPPORTS_MSI is not set +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_1G is not set +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_PREEMPT=y +CONFIG_HZ=100 +CONFIG_AEABI=y +CONFIG_OABI_COMPAT=y +CONFIG_ARCH_FLATMEM_HAS_HOLES=y +# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set +# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set +# CONFIG_HIGHMEM is not set +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_PAGEFLAGS_EXTENDED=y +CONFIG_SPLIT_PTLOCK_CPUS=4096 +# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 +CONFIG_VIRT_TO_BUS=y +CONFIG_UNEVICTABLE_LRU=y +CONFIG_HAVE_MLOCK=y +CONFIG_HAVE_MLOCKED_PAGE_BIT=y +CONFIG_ALIGNMENT_TRAP=y + +# +# Boot options +# +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CMDLINE="" +# CONFIG_XIP_KERNEL is not set +# CONFIG_KEXEC is not set + +# +# CPU Power Management +# +# CONFIG_CPU_IDLE is not set + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +# CONFIG_FPE_NWFPE is not set +# CONFIG_FPE_FASTFPE is not set +# CONFIG_VFP is not set + +# +# Userspace binary formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_HAVE_AOUT=y +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set + +# +# Power management options +# +# CONFIG_PM is not set +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_UNIX is not set +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# 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=y +# 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 is not set +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER 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 is not set +# CONFIG_NET_DSA is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# 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_PHONET is not set +# CONFIG_NET_SCHED is not set +# CONFIG_DCB is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO 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_WIRELESS=y +# CONFIG_CFG80211 is not set +# CONFIG_WIRELESS_OLD_REGULATORY is not set +# CONFIG_WIRELESS_EXT is not set +# CONFIG_LIB80211 is not set +# CONFIG_MAC80211 is not set +# CONFIG_WIMAX 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 is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_CONNECTOR is not set +CONFIG_MTD=y +CONFIG_MTD_DEBUG=y +CONFIG_MTD_DEBUG_VERBOSE=3 +# CONFIG_MTD_CONCAT is not set +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_TESTS is not set +CONFIG_MTD_REDBOOT_PARTS=y +CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1 +# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set +# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set +CONFIG_MTD_CMDLINE_PARTS=y +# CONFIG_MTD_AFS_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=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +CONFIG_MTD_CFI_ADV_OPTIONS=y +CONFIG_MTD_CFI_NOSWAP=y +# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set +# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set +CONFIG_MTD_CFI_GEOMETRY=y +# CONFIG_MTD_MAP_BANK_WIDTH_1 is not set +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_OTP is not set +# CONFIG_MTD_CFI_INTELEXT is not set +CONFIG_MTD_CFI_AMDSTD=y +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_XIP is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +CONFIG_MTD_PHYSMAP=y +# CONFIG_MTD_PHYSMAP_COMPAT is not set +# CONFIG_MTD_ARM_INTEGRATOR is not set +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_DATAFLASH is not set +# CONFIG_MTD_M25P80 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# 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 is not set +# CONFIG_MTD_NAND_ECC_SMC is not set +# CONFIG_MTD_NAND_MUSEUM_IDS is not set +# CONFIG_MTD_NAND_GPIO is not set +CONFIG_MTD_NAND_IDS=y +# CONFIG_MTD_NAND_DISKONCHIP is not set +# CONFIG_MTD_NAND_NANDSIM is not set +# CONFIG_MTD_NAND_PLATFORM is not set +CONFIG_MTD_NAND_MXC=y +# CONFIG_MTD_ONENAND is not set + +# +# LPDDR flash memory drivers +# +# CONFIG_MTD_LPDDR is not set + +# +# UBI - Unsorted block images +# +# CONFIG_MTD_UBI is not set +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# 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_RAM is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +CONFIG_MISC_DEVICES=y +# CONFIG_ICS932S401 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_ISL29003 is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_AT25 is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_93CX6 is not set +CONFIG_HAVE_IDE=y +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +# CONFIG_SCSI is not set +# CONFIG_SCSI_DMA is not set +# CONFIG_SCSI_NETLINK is not set +# CONFIG_ATA is not set +# CONFIG_MD is not set +CONFIG_NETDEVICES=y +CONFIG_COMPAT_NET_DEV_OPS=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_MACVLAN is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_VETH is not set +# CONFIG_PHYLIB is not set +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_AX88796 is not set +# CONFIG_SMC91X is not set +# CONFIG_DM9000 is not set +# CONFIG_ENC28J60 is not set +# CONFIG_ETHOC is not set +# CONFIG_SMC911X is not set +# CONFIG_SMSC911X is not set +# CONFIG_DNET 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_IBM_NEW_EMAC_NO_FLOW_CTRL is not set +# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set +# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set +# CONFIG_B44 is not set +CONFIG_CS89x0=y +CONFIG_CS89x0_NONISA_IRQ=y +# CONFIG_NETDEV_1000 is not set +# CONFIG_NETDEV_10000 is not set + +# +# Wireless LAN +# +# CONFIG_WLAN_PRE80211 is not set +# CONFIG_WLAN_80211 is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +# CONFIG_WAN is not set +# CONFIG_PPP is not set +# CONFIG_SLIP 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 + +# +# 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=y +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +CONFIG_INPUT_TOUCHSCREEN=y +# CONFIG_TOUCHSCREEN_ADS7846 is not set +# CONFIG_TOUCHSCREEN_FUJITSU is not set +# CONFIG_TOUCHSCREEN_GUNZE is not set +# CONFIG_TOUCHSCREEN_ELO is not set +# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set +# CONFIG_TOUCHSCREEN_MTOUCH is not set +# CONFIG_TOUCHSCREEN_INEXIO is not set +# CONFIG_TOUCHSCREEN_MK712 is not set +# CONFIG_TOUCHSCREEN_PENMOUNT is not set +# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set +# CONFIG_TOUCHSCREEN_TOUCHWIN is not set +# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set +# CONFIG_TOUCHSCREEN_TSC2007 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=y +# CONFIG_CONSOLE_TRANSLATIONS is not set +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +CONFIG_DEVKMEM=y +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=1 +CONFIG_SERIAL_8250_RUNTIME_UARTS=1 +# CONFIG_SERIAL_8250_EXTENDED is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_MAX3100 is not set +CONFIG_SERIAL_IMX=y +CONFIG_SERIAL_IMX_CONSOLE=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_HELPER_AUTO=y + +# +# I2C Hardware Bus support +# + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_GPIO is not set +CONFIG_I2C_IMX=y +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_SIMTEC is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_TAOS_EVM is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_STUB is not set + +# +# Miscellaneous I2C Chip support +# +# CONFIG_DS1682 is not set +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_PCF8575 is not set +# CONFIG_SENSORS_PCA9539 is not set +# CONFIG_SENSORS_MAX6875 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set +CONFIG_SPI=y +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_BITBANG is not set +# CONFIG_SPI_GPIO is not set + +# +# SPI Protocol Masters +# +# CONFIG_SPI_SPIDEV is not set +# CONFIG_SPI_TLE62X0 is not set +CONFIG_ARCH_REQUIRE_GPIOLIB=y +CONFIG_GPIOLIB=y +# CONFIG_GPIO_SYSFS is not set + +# +# Memory mapped GPIO expanders: +# + +# +# I2C GPIO expanders: +# +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_GPIO_PCF857X is not set + +# +# PCI GPIO expanders: +# + +# +# SPI GPIO expanders: +# +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MCP23S08 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_THERMAL_HWMON is not set +# CONFIG_WATCHDOG is not set +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_ASIC3 is not set +# CONFIG_HTC_EGPIO is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_TPS65010 is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_TC6393XB is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_PCF50633 is not set + +# +# Multimedia devices +# + +# +# Multimedia core support +# +# CONFIG_VIDEO_DEV is not set +# CONFIG_DVB_CORE is not set +# CONFIG_VIDEO_MEDIA is not set + +# +# Multimedia drivers +# +# CONFIG_DAB is not set + +# +# Graphics support +# +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +CONFIG_FB=y +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB_DDC is not set +# CONFIG_FB_BOOT_VESA_SUPPORT is not set +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +# CONFIG_FB_SYS_FILLRECT is not set +# CONFIG_FB_SYS_COPYAREA is not set +# CONFIG_FB_SYS_IMAGEBLIT is not set +# CONFIG_FB_FOREIGN_ENDIAN is not set +# CONFIG_FB_SYS_FOPS is not set +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_BACKLIGHT is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +CONFIG_FB_IMX=y +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_MB862XX is not set +# CONFIG_FB_BROADSHEET is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set +CONFIG_FONTS=y +CONFIG_FONT_8x8=y +# CONFIG_FONT_8x16 is not set +# CONFIG_FONT_6x11 is not set +# CONFIG_FONT_7x14 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set +# CONFIG_FONT_MINI_4x6 is not set +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_SUN12x22 is not set +# CONFIG_FONT_10x18 is not set +CONFIG_LOGO=y +CONFIG_LOGO_LINUX_MONO=y +CONFIG_LOGO_LINUX_VGA16=y +CONFIG_LOGO_LINUX_CLUT224=y +# CONFIG_SOUND is not set +# CONFIG_HID_SUPPORT is not set +# CONFIG_USB_SUPPORT is not set +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set +# CONFIG_MMC_UNSAFE_RESUME is not set + +# +# MMC/SD/SDIO Card Drivers +# +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_BOUNCE=y +# CONFIG_SDIO_UART is not set +# CONFIG_MMC_TEST is not set + +# +# MMC/SD/SDIO Host Controller Drivers +# +# CONFIG_MMC_SDHCI is not set +CONFIG_MMC_MXC=y +# CONFIG_MMC_SPI is not set +# CONFIG_MEMSTICK is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_NEW_LEDS is not set +CONFIG_RTC_LIB=y +# CONFIG_RTC_CLASS is not set +# CONFIG_DMADEVICES is not set +# CONFIG_AUXDISPLAY is not set +# CONFIG_REGULATOR is not set +# CONFIG_UIO is not set +# CONFIG_STAGING is not set + +# +# File systems +# +# CONFIG_EXT2_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_EXT4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +CONFIG_FILE_LOCKING=y +# CONFIG_XFS_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_BTRFS_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 + +# +# Caches +# +# CONFIG_FSCACHE is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +# CONFIG_VFAT_FS is not set +CONFIG_FAT_DEFAULT_CODEPAGE=437 +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_HUGETLB_PAGE is not set +# CONFIG_CONFIGFS_FS is not set +CONFIG_MISC_FILESYSTEMS=y +# 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 is not set +# CONFIG_JFFS2_FS_XATTR is not set +# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set +CONFIG_JFFS2_ZLIB=y +# CONFIG_JFFS2_LZO is not set +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +# CONFIG_CRAMFS is not set +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_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_NILFS2_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 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 is not set +CONFIG_MSDOS_PARTITION=y +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set +# CONFIG_DLM is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_WARN_DEPRECATED=y +CONFIG_ENABLE_MUST_CHECK=y +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_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_RCU_CPU_STALL_DETECTOR is not set +# CONFIG_LATENCYTOP is not set +CONFIG_SYSCTL_SYSCALL_CHECK=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_TRACING_SUPPORT=y + +# +# Tracers +# +# CONFIG_FUNCTION_TRACER is not set +# CONFIG_IRQSOFF_TRACER is not set +# CONFIG_PREEMPT_TRACER is not set +# CONFIG_SCHED_TRACER is not set +# CONFIG_CONTEXT_SWITCH_TRACER is not set +# CONFIG_EVENT_TRACER is not set +# CONFIG_BOOT_TRACER is not set +# CONFIG_TRACE_BRANCH_PROFILING is not set +# CONFIG_STACK_TRACER is not set +# CONFIG_KMEMTRACE is not set +# CONFIG_WORKQUEUE_TRACER is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +CONFIG_ARM_UNWIND=y +# CONFIG_DEBUG_USER is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set +# CONFIG_SECURITYFS is not set +# CONFIG_SECURITY_FILE_CAPABILITIES is not set +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +# CONFIG_CRYPTO_FIPS is not set +# CONFIG_CRYPTO_MANAGER is not set +# CONFIG_CRYPTO_MANAGER2 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 is not set + +# +# 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_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 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_ZLIB is not set +# CONFIG_CRYPTO_LZO is not set + +# +# Random Number Generation +# +# CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_CRYPTO_HW=y +# CONFIG_BINARY_PRINTF is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_GENERIC_FIND_LAST_BIT=y +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set +# CONFIG_CRC_T10DIF is not set +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC7 is not set +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y +CONFIG_NLATTR=y diff --git a/arch/arm/configs/omap3_evm_defconfig b/arch/arm/configs/omap3_evm_defconfig new file mode 100644 index 000000000000..28be17fbc157 --- /dev/null +++ b/arch/arm/configs/omap3_evm_defconfig @@ -0,0 +1,1528 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.30-rc5 +# Mon May 18 14:01:52 2009 +# +CONFIG_ARM=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_GENERIC_GPIO=y +CONFIG_GENERIC_TIME=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_MMU=y +# CONFIG_NO_IOPORT is not set +CONFIG_GENERIC_HARDIRQS=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_HAVE_LATENCYTOP_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y +CONFIG_VECTORS_BASE=0xffff0000 +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=y +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 + +# +# RCU Subsystem +# +CONFIG_CLASSIC_RCU=y +# CONFIG_TREE_RCU is not set +# CONFIG_PREEMPT_RCU is not set +# CONFIG_TREE_RCU_TRACE is not set +# CONFIG_PREEMPT_RCU_TRACE is not set +# CONFIG_IKCONFIG is not set +CONFIG_LOG_BUF_SHIFT=14 +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_CGROUPS 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_RD_GZIP=y +# CONFIG_RD_BZIP2 is not set +# CONFIG_RD_LZMA is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y +CONFIG_EMBEDDED=y +CONFIG_UID16=y +# CONFIG_SYSCTL_SYSCALL is not set +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +CONFIG_KALLSYMS_EXTRA_PASS=y +# CONFIG_STRIP_ASM_SYMS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_COMPAT_BRK=y +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_KPROBES is not set +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_CLK=y +# CONFIG_SLOW_WORK is not set +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SRCVERSION_ALL=y +CONFIG_BLOCK=y +# CONFIG_LBD is not set +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_BLK_DEV_INTEGRITY is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_DEFAULT_AS=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="anticipatory" +CONFIG_FREEZER=y + +# +# System Type +# +# CONFIG_ARCH_AAEC2000 is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_GEMINI is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_IMX is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP23XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_KIRKWOOD is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_NS9XXX is not set +# CONFIG_ARCH_LOKI is not set +# CONFIG_ARCH_MV78XX0 is not set +# CONFIG_ARCH_MXC is not set +# CONFIG_ARCH_ORION5X is not set +# CONFIG_ARCH_PNX4008 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_MMP is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_S3C64XX is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_LH7A40X is not set +# CONFIG_ARCH_DAVINCI is not set +CONFIG_ARCH_OMAP=y +# CONFIG_ARCH_MSM is not set +# CONFIG_ARCH_W90X900 is not set + +# +# TI OMAP Implementations +# +CONFIG_ARCH_OMAP_OTG=y +# CONFIG_ARCH_OMAP1 is not set +# CONFIG_ARCH_OMAP2 is not set +CONFIG_ARCH_OMAP3=y + +# +# OMAP Feature Selections +# +# CONFIG_OMAP_DEBUG_POWERDOMAIN is not set +# CONFIG_OMAP_DEBUG_CLOCKDOMAIN is not set +CONFIG_OMAP_RESET_CLOCKS=y +CONFIG_OMAP_MUX=y +# CONFIG_OMAP_MUX_DEBUG is not set +CONFIG_OMAP_MUX_WARNINGS=y +# CONFIG_OMAP_MCBSP is not set +# CONFIG_OMAP_MBOX_FWK is not set +# CONFIG_OMAP_MPU_TIMER is not set +CONFIG_OMAP_32K_TIMER=y +CONFIG_OMAP_32K_TIMER_HZ=128 +CONFIG_OMAP_DM_TIMER=y +CONFIG_OMAP_LL_DEBUG_UART1=y +# CONFIG_OMAP_LL_DEBUG_UART2 is not set +# CONFIG_OMAP_LL_DEBUG_UART3 is not set +CONFIG_OMAP_SERIAL_WAKE=y +CONFIG_ARCH_OMAP34XX=y +CONFIG_ARCH_OMAP3430=y + +# +# OMAP Board Type +# +# CONFIG_MACH_OMAP3_BEAGLE is not set +# CONFIG_MACH_OMAP_LDP is not set +# CONFIG_MACH_OVERO is not set +CONFIG_MACH_OMAP3EVM=y +# CONFIG_MACH_OMAP3_PANDORA is not set +# CONFIG_MACH_OMAP_3430SDP is not set +# CONFIG_MACH_NOKIA_RX51 is not set + +# +# Processor Type +# +CONFIG_CPU_32=y +CONFIG_CPU_32v6K=y +CONFIG_CPU_V7=y +CONFIG_CPU_32v7=y +CONFIG_CPU_ABRT_EV7=y +CONFIG_CPU_PABRT_IFAR=y +CONFIG_CPU_CACHE_V7=y +CONFIG_CPU_CACHE_VIPT=y +CONFIG_CPU_COPY_V6=y +CONFIG_CPU_TLB_V7=y +CONFIG_CPU_HAS_ASID=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y + +# +# Processor Features +# +CONFIG_ARM_THUMB=y +# CONFIG_ARM_THUMBEE is not set +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_BPREDICT_DISABLE is not set +CONFIG_HAS_TLS_REG=y +# CONFIG_OUTER_CACHE is not set +# CONFIG_ARM_ERRATA_430973 is not set +# CONFIG_ARM_ERRATA_458693 is not set +# CONFIG_ARM_ERRATA_460075 is not set +CONFIG_COMMON_CLKDEV=y + +# +# Bus support +# +# CONFIG_PCI_SYSCALL is not set +# CONFIG_ARCH_SUPPORTS_MSI is not set +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_1G is not set +CONFIG_PAGE_OFFSET=0xC0000000 +# CONFIG_PREEMPT is not set +CONFIG_HZ=128 +CONFIG_AEABI=y +CONFIG_OABI_COMPAT=y +CONFIG_ARCH_FLATMEM_HAS_HOLES=y +# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set +# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set +# CONFIG_HIGHMEM is not set +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_PAGEFLAGS_EXTENDED=y +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 +CONFIG_VIRT_TO_BUS=y +CONFIG_UNEVICTABLE_LRU=y +CONFIG_HAVE_MLOCK=y +CONFIG_HAVE_MLOCKED_PAGE_BIT=y +# CONFIG_LEDS is not set +CONFIG_ALIGNMENT_TRAP=y + +# +# Boot options +# +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CMDLINE="root=/dev/nfs nfsroot=192.168.0.1:/home/user/buildroot ip=192.168.0.2:192.168.0.1:192.168.0.1:255.255.255.0:tgt:eth0:off rw console=ttyS2,115200n8" +# CONFIG_XIP_KERNEL is not set +# CONFIG_KEXEC is not set + +# +# CPU Power Management +# +# CONFIG_CPU_FREQ is not set +# CONFIG_CPU_IDLE is not set + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +CONFIG_FPE_NWFPE=y +# CONFIG_FPE_NWFPE_XP is not set +# CONFIG_FPE_FASTFPE is not set +CONFIG_VFP=y +CONFIG_VFPv3=y +CONFIG_NEON=y + +# +# Userspace binary formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_HAVE_AOUT=y +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_MISC=y + +# +# Power management options +# +CONFIG_PM=y +# CONFIG_PM_DEBUG is not set +CONFIG_PM_SLEEP=y +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +# CONFIG_APM_EMULATION is not set +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +CONFIG_NET_KEY=y +# CONFIG_NET_KEY_MIGRATE is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# 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=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +# CONFIG_INET_LRO is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER 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 is not set +# CONFIG_NET_DSA is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# 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_PHONET is not set +# CONFIG_NET_SCHED is not set +# CONFIG_DCB is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO 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_WIRELESS=y +# CONFIG_CFG80211 is not set +# CONFIG_WIRELESS_OLD_REGULATORY is not set +# CONFIG_WIRELESS_EXT is not set +# CONFIG_LIB80211 is not set +# CONFIG_MAC80211 is not set +# CONFIG_WIMAX 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 is not set +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_CONNECTOR is not set +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_CONCAT=y +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_TESTS is not set +# CONFIG_MTD_REDBOOT_PARTS is not set +CONFIG_MTD_CMDLINE_PARTS=y +# CONFIG_MTD_AFS_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=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS 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_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# 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_PHYSMAP is not set +# CONFIG_MTD_ARM_INTEGRATOR is not set +# CONFIG_MTD_OMAP_NOR is not set +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_DATAFLASH is not set +# CONFIG_MTD_M25P80 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# 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 is not set +# CONFIG_MTD_NAND_ECC_SMC is not set +# CONFIG_MTD_NAND_MUSEUM_IDS is not set +# CONFIG_MTD_NAND_GPIO is not set +CONFIG_MTD_NAND_IDS=y +# CONFIG_MTD_NAND_DISKONCHIP is not set +# CONFIG_MTD_NAND_NANDSIM is not set +# CONFIG_MTD_NAND_PLATFORM is not set +# CONFIG_MTD_ALAUDA is not set +CONFIG_MTD_ONENAND=y +CONFIG_MTD_ONENAND_VERIFY_WRITE=y +# CONFIG_MTD_ONENAND_GENERIC is not set +CONFIG_MTD_ONENAND_OMAP2=y +# CONFIG_MTD_ONENAND_OTP is not set +# CONFIG_MTD_ONENAND_2X_PROGRAM is not set +# CONFIG_MTD_ONENAND_SIM is not set + +# +# LPDDR flash memory drivers +# +# CONFIG_MTD_LPDDR is not set + +# +# UBI - Unsorted block images +# +# CONFIG_MTD_UBI is not set +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_UB is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=16384 +# CONFIG_BLK_DEV_XIP is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_MISC_DEVICES 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=y +# 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_LIBFC is not set +# CONFIG_LIBFCOE is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_DH is not set +# CONFIG_SCSI_OSD_INITIATOR is not set +# CONFIG_ATA is not set +# CONFIG_MD is not set +CONFIG_NETDEVICES=y +CONFIG_COMPAT_NET_DEV_OPS=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_MACVLAN is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_VETH is not set +# CONFIG_PHYLIB is not set +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_AX88796 is not set +# CONFIG_SMC91X is not set +# CONFIG_DM9000 is not set +# CONFIG_ENC28J60 is not set +# CONFIG_ETHOC is not set +CONFIG_SMC911X=y +# CONFIG_SMSC911X is not set +# CONFIG_DNET 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_IBM_NEW_EMAC_NO_FLOW_CTRL is not set +# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set +# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set +# CONFIG_B44 is not set +# CONFIG_NETDEV_1000 is not set +# CONFIG_NETDEV_10000 is not set + +# +# Wireless LAN +# +# CONFIG_WLAN_PRE80211 is not set +# CONFIG_WLAN_80211 is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# + +# +# USB Network Adapters +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_USBNET is not set +# CONFIG_WAN is not set +# CONFIG_PPP is not set +# CONFIG_SLIP 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 + +# +# 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=y +# 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=y +CONFIG_TOUCHSCREEN_ADS7846=y +# CONFIG_TOUCHSCREEN_AD7877 is not set +# CONFIG_TOUCHSCREEN_AD7879_I2C is not set +# CONFIG_TOUCHSCREEN_AD7879_SPI is not set +# CONFIG_TOUCHSCREEN_AD7879 is not set +# CONFIG_TOUCHSCREEN_FUJITSU is not set +# CONFIG_TOUCHSCREEN_GUNZE is not set +# CONFIG_TOUCHSCREEN_ELO is not set +# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set +# CONFIG_TOUCHSCREEN_MTOUCH is not set +# CONFIG_TOUCHSCREEN_INEXIO is not set +# CONFIG_TOUCHSCREEN_MK712 is not set +# CONFIG_TOUCHSCREEN_PENMOUNT is not set +# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set +# CONFIG_TOUCHSCREEN_TOUCHWIN is not set +# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set +# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set +# CONFIG_TOUCHSCREEN_TSC2007 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=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +CONFIG_DEVKMEM=y +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=32 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_MANY_PORTS=y +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_8250_DETECT_IRQ=y +CONFIG_SERIAL_8250_RSA=y + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_MAX3100 is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_IPMI_HANDLER is not set +CONFIG_HW_RANDOM=y +# CONFIG_HW_RANDOM_TIMERIOMEM is not set +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_HELPER_AUTO=y + +# +# I2C Hardware Bus support +# + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_GPIO is not set +# CONFIG_I2C_OCORES is not set +CONFIG_I2C_OMAP=y +# CONFIG_I2C_SIMTEC is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_STUB is not set + +# +# Miscellaneous I2C Chip support +# +# CONFIG_DS1682 is not set +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_PCF8575 is not set +# CONFIG_SENSORS_PCA9539 is not set +# CONFIG_SENSORS_MAX6875 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_BITBANG is not set +# CONFIG_SPI_GPIO is not set +CONFIG_SPI_OMAP24XX=y + +# +# SPI Protocol Masters +# +# CONFIG_SPI_SPIDEV is not set +# CONFIG_SPI_TLE62X0 is not set +CONFIG_ARCH_REQUIRE_GPIOLIB=y +CONFIG_GPIOLIB=y +# CONFIG_DEBUG_GPIO is not set +# CONFIG_GPIO_SYSFS is not set + +# +# Memory mapped GPIO expanders: +# + +# +# I2C GPIO expanders: +# +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_GPIO_PCF857X is not set +CONFIG_GPIO_TWL4030=y + +# +# PCI GPIO expanders: +# + +# +# SPI GPIO expanders: +# +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MCP23S08 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_THERMAL_HWMON is not set +CONFIG_WATCHDOG=y +CONFIG_WATCHDOG_NOWAYOUT=y + +# +# Watchdog Device Drivers +# +# CONFIG_SOFT_WATCHDOG is not set +CONFIG_OMAP_WATCHDOG=y + +# +# USB-based Watchdog Cards +# +# CONFIG_USBPCWATCHDOG is not set +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_ASIC3 is not set +# CONFIG_HTC_EGPIO is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_TPS65010 is not set +CONFIG_TWL4030_CORE=y +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_T7L66XB is not set +# CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_TC6393XB is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_PCF50633 is not set + +# +# Multimedia devices +# + +# +# Multimedia core support +# +# CONFIG_VIDEO_DEV is not set +# CONFIG_DVB_CORE is not set +# CONFIG_VIDEO_MEDIA is not set + +# +# Multimedia drivers +# +CONFIG_DAB=y +# CONFIG_USB_DABUSB is not set + +# +# Graphics support +# +# CONFIG_VGASTATE is not set +CONFIG_VIDEO_OUTPUT_CONTROL=m +# CONFIG_FB is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +# CONFIG_SOUND is not set +CONFIG_HID_SUPPORT=y +CONFIG_HID=y +# CONFIG_HID_DEBUG is not set +# CONFIG_HIDRAW is not set + +# +# USB Input Devices +# +CONFIG_USB_HID=y +# CONFIG_HID_PID is not set +# CONFIG_USB_HIDDEV is not set + +# +# Special HID drivers +# +# CONFIG_HID_A4TECH is not set +# CONFIG_HID_APPLE is not set +# CONFIG_HID_BELKIN is not set +# CONFIG_HID_CHERRY is not set +# CONFIG_HID_CHICONY is not set +# CONFIG_HID_CYPRESS is not set +# CONFIG_DRAGONRISE_FF is not set +# CONFIG_HID_EZKEY is not set +# CONFIG_HID_KYE is not set +# CONFIG_HID_GYRATION is not set +# CONFIG_HID_KENSINGTON is not set +# CONFIG_HID_LOGITECH is not set +# CONFIG_HID_MICROSOFT is not set +# CONFIG_HID_MONTEREY is not set +# CONFIG_HID_NTRIG is not set +# CONFIG_HID_PANTHERLORD is not set +# CONFIG_HID_PETALYNX is not set +# CONFIG_HID_SAMSUNG is not set +# CONFIG_HID_SONY is not set +# CONFIG_HID_SUNPLUS is not set +# CONFIG_GREENASIA_FF is not set +# CONFIG_HID_TOPSEED is not set +# CONFIG_THRUSTMASTER_FF is not set +# CONFIG_ZEROPLUS_FF is not set +CONFIG_USB_SUPPORT=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +# CONFIG_USB_ARCH_HAS_EHCI is not set +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_DEVICE_CLASS is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +CONFIG_USB_SUSPEND=y +CONFIG_USB_OTG=y +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set +CONFIG_USB_MON=y +# CONFIG_USB_WUSB is not set +# CONFIG_USB_WUSB_CBAF is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_ISP1760_HCD is not set +# CONFIG_USB_OHCI_HCD is not set +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_HWA_HCD is not set +CONFIG_USB_MUSB_HDRC=y +CONFIG_USB_MUSB_SOC=y + +# +# OMAP 343x high speed USB support +# +# CONFIG_USB_MUSB_HOST is not set +# CONFIG_USB_MUSB_PERIPHERAL is not set +CONFIG_USB_MUSB_OTG=y +CONFIG_USB_GADGET_MUSB_HDRC=y +CONFIG_USB_MUSB_HDRC_HCD=y +# CONFIG_MUSB_PIO_ONLY is not set +CONFIG_USB_INVENTRA_DMA=y +# CONFIG_USB_TI_CPPI_DMA is not set +# CONFIG_USB_MUSB_DEBUG is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_WDM is not set +# CONFIG_USB_TMC is not set + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# + +# +# also be needed; see USB_STORAGE Help for more info +# +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_ONETOUCH is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set +# CONFIG_USB_LIBUSUAL is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set + +# +# USB port drivers +# +# CONFIG_USB_SERIAL is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_BERRY_CHARGE is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +CONFIG_USB_TEST=y +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_VST is not set +CONFIG_USB_GADGET=y +# CONFIG_USB_GADGET_DEBUG is not set +# CONFIG_USB_GADGET_DEBUG_FILES is not set +CONFIG_USB_GADGET_VBUS_DRAW=2 +CONFIG_USB_GADGET_SELECTED=y +# CONFIG_USB_GADGET_AT91 is not set +# CONFIG_USB_GADGET_ATMEL_USBA is not set +# CONFIG_USB_GADGET_FSL_USB2 is not set +# CONFIG_USB_GADGET_LH7A40X is not set +# CONFIG_USB_GADGET_OMAP is not set +# CONFIG_USB_GADGET_PXA25X is not set +# CONFIG_USB_GADGET_PXA27X is not set +# CONFIG_USB_GADGET_S3C2410 is not set +# CONFIG_USB_GADGET_IMX is not set +# CONFIG_USB_GADGET_M66592 is not set +# CONFIG_USB_GADGET_AMD5536UDC is not set +# CONFIG_USB_GADGET_FSL_QE is not set +# CONFIG_USB_GADGET_CI13XXX is not set +# CONFIG_USB_GADGET_NET2280 is not set +# CONFIG_USB_GADGET_GOKU is not set +# CONFIG_USB_GADGET_DUMMY_HCD is not set +CONFIG_USB_GADGET_DUALSPEED=y +CONFIG_USB_ZERO=m +# CONFIG_USB_ZERO_HNPTEST is not set +# CONFIG_USB_ETH is not set +# CONFIG_USB_GADGETFS is not set +# CONFIG_USB_FILE_STORAGE is not set +# CONFIG_USB_G_SERIAL is not set +# CONFIG_USB_MIDI_GADGET is not set +# CONFIG_USB_G_PRINTER is not set +# CONFIG_USB_CDC_COMPOSITE is not set + +# +# OTG and related infrastructure +# +CONFIG_USB_OTG_UTILS=y +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_ISP1301_OMAP is not set +CONFIG_TWL4030_USB=y +# CONFIG_NOP_USB_XCEIV is not set +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set +# CONFIG_MMC_UNSAFE_RESUME is not set + +# +# MMC/SD/SDIO Card Drivers +# +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_BOUNCE=y +# CONFIG_SDIO_UART is not set +# CONFIG_MMC_TEST is not set + +# +# MMC/SD/SDIO Host Controller Drivers +# +# CONFIG_MMC_SDHCI is not set +# CONFIG_MMC_OMAP is not set +CONFIG_MMC_OMAP_HS=m +# CONFIG_MMC_SPI is not set +# CONFIG_MEMSTICK is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_NEW_LEDS is not set +CONFIG_RTC_LIB=y +# CONFIG_RTC_CLASS is not set +# CONFIG_DMADEVICES is not set +# CONFIG_AUXDISPLAY is not set +CONFIG_REGULATOR=y +# CONFIG_REGULATOR_DEBUG is not set +# CONFIG_REGULATOR_FIXED_VOLTAGE is not set +# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set +# CONFIG_REGULATOR_BQ24022 is not set +CONFIG_REGULATOR_TWL4030=y +# CONFIG_UIO is not set +# CONFIG_STAGING 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=y +# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set +# CONFIG_EXT3_FS_XATTR is not set +# CONFIG_EXT4_FS is not set +CONFIG_JBD=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +CONFIG_FILE_LOCKING=y +# CONFIG_XFS_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_BTRFS_FS is not set +CONFIG_DNOTIFY=y +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +CONFIG_QUOTA=y +# CONFIG_QUOTA_NETLINK_INTERFACE is not set +CONFIG_PRINT_QUOTA_WARNING=y +CONFIG_QUOTA_TREE=y +# CONFIG_QFMT_V1 is not set +CONFIG_QFMT_V2=y +CONFIG_QUOTACTL=y +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# Caches +# +# CONFIG_FSCACHE is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_HUGETLB_PAGE is not set +# CONFIG_CONFIGFS_FS is not set +CONFIG_MISC_FILESYSTEMS=y +# 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 is not set +# 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_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_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_NILFS2_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +CONFIG_NFS_V4=y +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +CONFIG_SUNRPC_GSS=y +CONFIG_RPCSEC_GSS_KRB5=y +# CONFIG_RPCSEC_GSS_SPKM3 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 is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# 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=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +CONFIG_NLS_ISO8859_1=y +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set +# CONFIG_DLM is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_WARN_DEPRECATED=y +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=1024 +CONFIG_MAGIC_SYSRQ=y +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_HEADERS_CHECK is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +CONFIG_DETECT_SOFTLOCKUP=y +# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0 +CONFIG_DETECT_HUNG_TASK=y +# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set +CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0 +# CONFIG_SCHED_DEBUG is not set +# CONFIG_SCHEDSTATS is not set +# CONFIG_TIMER_STATS is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +CONFIG_DEBUG_MUTEXES=y +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_WRITECOUNT is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_BOOT_PRINTK_DELAY is not set +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_RCU_CPU_STALL_DETECTOR is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_LATENCYTOP is not set +# CONFIG_PAGE_POISONING is not set +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_TRACING_SUPPORT=y + +# +# Tracers +# +# CONFIG_FUNCTION_TRACER is not set +# CONFIG_IRQSOFF_TRACER is not set +# CONFIG_SCHED_TRACER is not set +# CONFIG_CONTEXT_SWITCH_TRACER is not set +# CONFIG_EVENT_TRACER is not set +# CONFIG_BOOT_TRACER is not set +# CONFIG_TRACE_BRANCH_PROFILING is not set +# CONFIG_STACK_TRACER is not set +# CONFIG_KMEMTRACE is not set +# CONFIG_WORKQUEUE_TRACER is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +CONFIG_ARM_UNWIND=y +# CONFIG_DEBUG_USER is not set +# CONFIG_DEBUG_ERRORS is not set +# CONFIG_DEBUG_STACK_USAGE is not set +CONFIG_DEBUG_LL=y +# CONFIG_DEBUG_ICEDCC is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set +# CONFIG_SECURITYFS is not set +# CONFIG_SECURITY_FILE_CAPABILITIES is not set +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +# CONFIG_CRYPTO_FIPS is not set +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_BLKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_PCOMP=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_NULL is not set +CONFIG_CRYPTO_WORKQUEUE=y +# CONFIG_CRYPTO_CRYPTD is not set +# CONFIG_CRYPTO_AUTHENC is not set +# CONFIG_CRYPTO_TEST is not set + +# +# 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=y +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +CONFIG_CRYPTO_ECB=m +# CONFIG_CRYPTO_LRW is not set +CONFIG_CRYPTO_PCBC=m +# CONFIG_CRYPTO_XTS is not set + +# +# Hash modes +# +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_XCBC is not set + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=y +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 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=y +# 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_ZLIB is not set +# CONFIG_CRYPTO_LZO is not set + +# +# Random Number Generation +# +# CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_CRYPTO_HW=y +# CONFIG_BINARY_PRINTF is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_GENERIC_FIND_LAST_BIT=y +CONFIG_CRC_CCITT=y +# CONFIG_CRC16 is not set +# CONFIG_CRC_T10DIF is not set +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC7 is not set +CONFIG_LIBCRC32C=y +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_DECOMPRESS_GZIP=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y +CONFIG_NLATTR=y diff --git a/arch/arm/configs/omap_4430sdp_defconfig b/arch/arm/configs/omap_4430sdp_defconfig new file mode 100644 index 000000000000..23e43ea4efa1 --- /dev/null +++ b/arch/arm/configs/omap_4430sdp_defconfig @@ -0,0 +1,866 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.30-rc7 +# Tue Jun 9 12:36:23 2009 +# +CONFIG_ARM=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_GENERIC_GPIO=y +CONFIG_GENERIC_TIME=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_MMU=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y +CONFIG_VECTORS_BASE=0xffff0000 +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_BSD_PROCESS_ACCT=y +# CONFIG_BSD_PROCESS_ACCT_V3 is not set + +# +# RCU Subsystem +# +CONFIG_CLASSIC_RCU=y +# CONFIG_TREE_RCU is not set +# CONFIG_PREEMPT_RCU is not set +# CONFIG_TREE_RCU_TRACE is not set +# CONFIG_PREEMPT_RCU_TRACE is not set +# CONFIG_IKCONFIG is not set +CONFIG_LOG_BUF_SHIFT=14 +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_CGROUPS 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_RD_GZIP=y +# CONFIG_RD_BZIP2 is not set +# CONFIG_RD_LZMA is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y +CONFIG_EMBEDDED=y +CONFIG_UID16=y +# CONFIG_SYSCTL_SYSCALL is not set +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_EXTRA_PASS is not set +# CONFIG_STRIP_ASM_SYMS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +# CONFIG_ELF_CORE is not set +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLUB_DEBUG=y +CONFIG_COMPAT_BRK=y +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +# CONFIG_PROFILING is not set +# CONFIG_MARKERS is not set +CONFIG_HAVE_OPROFILE=y +# CONFIG_KPROBES is not set +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_USE_GENERIC_SMP_HELPERS=y +CONFIG_HAVE_CLK=y +# CONFIG_SLOW_WORK is not set +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SRCVERSION_ALL=y +CONFIG_STOP_MACHINE=y +CONFIG_BLOCK=y +# CONFIG_LBD is not set +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_BLK_DEV_INTEGRITY is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_DEFAULT_AS=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="anticipatory" +# CONFIG_FREEZER is not set + +# +# System Type +# +# CONFIG_ARCH_AAEC2000 is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_GEMINI is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_MXC is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP23XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_KIRKWOOD is not set +# CONFIG_ARCH_LOKI is not set +# CONFIG_ARCH_MV78XX0 is not set +# CONFIG_ARCH_ORION5X is not set +# CONFIG_ARCH_MMP is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_NS9XXX is not set +# CONFIG_ARCH_W90X900 is not set +# CONFIG_ARCH_PNX4008 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_MSM is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_S3C64XX is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_LH7A40X is not set +# CONFIG_ARCH_DAVINCI is not set +CONFIG_ARCH_OMAP=y + +# +# TI OMAP Implementations +# +# CONFIG_ARCH_OMAP1 is not set +# CONFIG_ARCH_OMAP2 is not set +# CONFIG_ARCH_OMAP3 is not set +CONFIG_ARCH_OMAP4=y + +# +# OMAP Feature Selections +# +# CONFIG_OMAP_RESET_CLOCKS is not set +# CONFIG_OMAP_MUX is not set +# CONFIG_OMAP_MCBSP is not set +# CONFIG_OMAP_MBOX_FWK is not set +# CONFIG_OMAP_MPU_TIMER is not set +CONFIG_OMAP_32K_TIMER=y +CONFIG_OMAP_32K_TIMER_HZ=128 +CONFIG_OMAP_DM_TIMER=y +CONFIG_OMAP_LL_DEBUG_UART1=y +# CONFIG_OMAP_LL_DEBUG_UART2 is not set +# CONFIG_OMAP_LL_DEBUG_UART3 is not set + +# +# OMAP Board Type +# +CONFIG_MACH_OMAP_4430SDP=y + +# +# Processor Type +# +CONFIG_CPU_32=y +CONFIG_CPU_32v6K=y +CONFIG_CPU_V7=y +CONFIG_CPU_32v7=y +CONFIG_CPU_ABRT_EV7=y +CONFIG_CPU_PABRT_IFAR=y +CONFIG_CPU_CACHE_V7=y +CONFIG_CPU_CACHE_VIPT=y +CONFIG_CPU_COPY_V6=y +CONFIG_CPU_TLB_V7=y +CONFIG_CPU_HAS_ASID=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y + +# +# Processor Features +# +# CONFIG_ARM_THUMB is not set +# CONFIG_ARM_THUMBEE is not set +# CONFIG_CPU_ICACHE_DISABLE is not set +CONFIG_CPU_DCACHE_DISABLE=y +# CONFIG_CPU_BPREDICT_DISABLE is not set +CONFIG_HAS_TLS_REG=y +# CONFIG_ARM_ERRATA_430973 is not set +# CONFIG_ARM_ERRATA_458693 is not set +# CONFIG_ARM_ERRATA_460075 is not set +CONFIG_ARM_GIC=y + +# +# Bus support +# +# CONFIG_PCI_SYSCALL is not set +# CONFIG_ARCH_SUPPORTS_MSI is not set +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +# CONFIG_NO_HZ is not set +# CONFIG_HIGH_RES_TIMERS is not set +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_SMP=y +CONFIG_HAVE_ARM_SCU=y +CONFIG_HAVE_ARM_TWD=y +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_1G is not set +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_NR_CPUS=2 +# CONFIG_HOTPLUG_CPU is not set +CONFIG_LOCAL_TIMERS=y +# CONFIG_PREEMPT is not set +CONFIG_HZ=128 +CONFIG_AEABI=y +# CONFIG_OABI_COMPAT is not set +# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set +# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set +# CONFIG_HIGHMEM is not set +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_PAGEFLAGS_EXTENDED=y +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 +CONFIG_VIRT_TO_BUS=y +# CONFIG_UNEVICTABLE_LRU is not set +CONFIG_HAVE_MLOCK=y +# CONFIG_LEDS is not set +CONFIG_ALIGNMENT_TRAP=y + +# +# Boot options +# +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CMDLINE="root=/dev/ram0 rw mem=128M console=ttyS0,115200n8 initrd=0x81600000,20M ramdisk_size=20480" +# CONFIG_XIP_KERNEL is not set +# CONFIG_KEXEC is not set + +# +# CPU Power Management +# +# CONFIG_CPU_FREQ is not set +# CONFIG_CPU_IDLE is not set + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +CONFIG_VFP=y +CONFIG_VFPv3=y +# CONFIG_NEON is not set + +# +# Userspace binary formats +# +CONFIG_BINFMT_ELF=y +CONFIG_HAVE_AOUT=y +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_MISC=y + +# +# Power management options +# +# CONFIG_PM is not set +CONFIG_ARCH_SUSPEND_POSSIBLE=y +# CONFIG_NET 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 is not set +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_MTD is not set +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=16384 +# CONFIG_BLK_DEV_XIP is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_MISC_DEVICES is not set +CONFIG_HAVE_IDE=y +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +# CONFIG_SCSI is not set +# CONFIG_SCSI_DMA is not set +# CONFIG_SCSI_NETLINK is not set +# CONFIG_ATA is not set +# CONFIG_MD 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=y +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD 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=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +CONFIG_DEVKMEM=y +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=32 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_MANY_PORTS=y +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_8250_DETECT_IRQ=y +CONFIG_SERIAL_8250_RSA=y + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_IPMI_HANDLER is not set +CONFIG_HW_RANDOM=y +# CONFIG_HW_RANDOM_TIMERIOMEM is not set +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_I2C is not set +# CONFIG_SPI is not set +CONFIG_ARCH_REQUIRE_GPIOLIB=y +CONFIG_GPIOLIB=y +# CONFIG_DEBUG_GPIO is not set +# CONFIG_GPIO_SYSFS is not set + +# +# Memory mapped GPIO expanders: +# + +# +# I2C GPIO expanders: +# + +# +# PCI GPIO expanders: +# + +# +# SPI GPIO expanders: +# +# CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set +# CONFIG_HWMON is not set +# CONFIG_THERMAL is not set +# CONFIG_THERMAL_HWMON is not set +# CONFIG_WATCHDOG is not set +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_ASIC3 is not set +# CONFIG_HTC_EGPIO is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_T7L66XB is not set +# CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_TC6393XB is not set + +# +# Multimedia devices +# + +# +# Multimedia core support +# +# CONFIG_VIDEO_DEV is not set +# CONFIG_VIDEO_MEDIA is not set + +# +# Multimedia drivers +# +CONFIG_DAB=y + +# +# Graphics support +# +# 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 + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +# CONFIG_SOUND is not set +# CONFIG_HID_SUPPORT is not set +# CONFIG_USB_SUPPORT is not set +# CONFIG_MMC is not set +# CONFIG_MEMSTICK is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_NEW_LEDS is not set +CONFIG_RTC_LIB=y +# CONFIG_RTC_CLASS is not set +# CONFIG_DMADEVICES is not set +# CONFIG_AUXDISPLAY is not set +# CONFIG_REGULATOR is not set +# CONFIG_UIO is not set +# CONFIG_STAGING 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=y +# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set +# CONFIG_EXT3_FS_XATTR is not set +# CONFIG_EXT4_FS is not set +CONFIG_JBD=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +CONFIG_FILE_LOCKING=y +# CONFIG_XFS_FS is not set +# CONFIG_BTRFS_FS is not set +CONFIG_DNOTIFY=y +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +CONFIG_QUOTA=y +CONFIG_PRINT_QUOTA_WARNING=y +CONFIG_QUOTA_TREE=y +# CONFIG_QFMT_V1 is not set +CONFIG_QFMT_V2=y +CONFIG_QUOTACTL=y +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# Caches +# +# CONFIG_FSCACHE is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_HUGETLB_PAGE is not set +# CONFIG_CONFIGFS_FS is not set +CONFIG_MISC_FILESYSTEMS=y +# 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_CRAMFS is not set +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_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_NILFS2_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 is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# 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=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +CONFIG_NLS_ISO8859_1=y +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +# CONFIG_ENABLE_WARN_DEPRECATED is not set +# CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_FRAME_WARN=1024 +CONFIG_MAGIC_SYSRQ=y +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_HEADERS_CHECK is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +CONFIG_DETECT_SOFTLOCKUP=y +# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0 +CONFIG_DETECT_HUNG_TASK=y +# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set +CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0 +CONFIG_SCHED_DEBUG=y +# CONFIG_SCHEDSTATS is not set +# CONFIG_TIMER_STATS is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_SLUB_STATS is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_WRITECOUNT is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +CONFIG_FRAME_POINTER=y +# CONFIG_BOOT_PRINTK_DELAY is not set +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_RCU_CPU_STALL_DETECTOR is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_PAGE_POISONING is not set +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_TRACING_SUPPORT=y + +# +# Tracers +# +# CONFIG_FUNCTION_TRACER is not set +# CONFIG_IRQSOFF_TRACER is not set +# CONFIG_SCHED_TRACER is not set +# CONFIG_CONTEXT_SWITCH_TRACER is not set +# CONFIG_EVENT_TRACER is not set +# CONFIG_BOOT_TRACER is not set +# CONFIG_TRACE_BRANCH_PROFILING is not set +# CONFIG_STACK_TRACER is not set +# CONFIG_KMEMTRACE is not set +# CONFIG_WORKQUEUE_TRACER is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +# CONFIG_ARM_UNWIND is not set +# CONFIG_DEBUG_USER is not set +# CONFIG_DEBUG_ERRORS is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_LL is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set +# CONFIG_SECURITYFS is not set +# CONFIG_SECURITY_FILE_CAPABILITIES is not set +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +# CONFIG_CRYPTO_FIPS is not set +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_BLKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_PCOMP=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_NULL is not set +CONFIG_CRYPTO_WORKQUEUE=y +# CONFIG_CRYPTO_CRYPTD is not set +# CONFIG_CRYPTO_AUTHENC is not set +# CONFIG_CRYPTO_TEST is not set + +# +# 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=y +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +CONFIG_CRYPTO_ECB=m +# CONFIG_CRYPTO_LRW is not set +CONFIG_CRYPTO_PCBC=m +# CONFIG_CRYPTO_XTS is not set + +# +# Hash modes +# +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_XCBC is not set + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=y +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 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=y +# 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_ZLIB is not set +# CONFIG_CRYPTO_LZO is not set + +# +# Random Number Generation +# +# CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_CRYPTO_HW=y +# CONFIG_BINARY_PRINTF is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_GENERIC_FIND_LAST_BIT=y +CONFIG_CRC_CCITT=y +# CONFIG_CRC16 is not set +CONFIG_CRC_T10DIF=y +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC7 is not set +CONFIG_LIBCRC32C=y +CONFIG_ZLIB_INFLATE=y +CONFIG_DECOMPRESS_GZIP=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y diff --git a/arch/arm/configs/omap_zoom2_defconfig b/arch/arm/configs/omap_zoom2_defconfig new file mode 100644 index 000000000000..213fe9c5eaae --- /dev/null +++ b/arch/arm/configs/omap_zoom2_defconfig @@ -0,0 +1,1211 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.27-rc5 +# Fri Oct 10 11:49:41 2008 +# +CONFIG_ARM=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_GENERIC_GPIO=y +CONFIG_GENERIC_TIME=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_MMU=y +# CONFIG_NO_IOPORT is not set +CONFIG_GENERIC_HARDIRQS=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_HAVE_LATENCYTOP_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_ARCH_SUPPORTS_AOUT=y +CONFIG_ZONE_DMA=y +CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y +CONFIG_VECTORS_BASE=0xffff0000 +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=y +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_BSD_PROCESS_ACCT=y +# CONFIG_BSD_PROCESS_ACCT_V3 is not set +# CONFIG_IKCONFIG is not set +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_UID16=y +# CONFIG_SYSCTL_SYSCALL is not set +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +CONFIG_KALLSYMS_EXTRA_PASS=y +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +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=y +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_KPROBES is not set +# CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS is not set +# CONFIG_HAVE_IOREMAP_PROT is not set +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +# CONFIG_HAVE_ARCH_TRACEHOOK is not set +# CONFIG_HAVE_DMA_ATTRS is not set +# CONFIG_USE_GENERIC_SMP_HELPERS is not set +CONFIG_HAVE_CLK=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SRCVERSION_ALL=y +CONFIG_KMOD=y +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 +# CONFIG_BLK_DEV_INTEGRITY is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_DEFAULT_AS=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="anticipatory" +CONFIG_CLASSIC_RCU=y + +# +# System Type +# +# CONFIG_ARCH_AAEC2000 is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_IMX is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP23XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_KIRKWOOD is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_NS9XXX is not set +# CONFIG_ARCH_LOKI is not set +# CONFIG_ARCH_MV78XX0 is not set +# CONFIG_ARCH_MXC is not set +# CONFIG_ARCH_ORION5X is not set +# CONFIG_ARCH_PNX4008 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_LH7A40X is not set +# CONFIG_ARCH_DAVINCI is not set +CONFIG_ARCH_OMAP=y +# CONFIG_ARCH_MSM7X00A is not set + +# +# TI OMAP Implementations +# +CONFIG_ARCH_OMAP_OTG=y +# CONFIG_ARCH_OMAP1 is not set +# CONFIG_ARCH_OMAP2 is not set +CONFIG_ARCH_OMAP3=y + +# +# OMAP Feature Selections +# +# CONFIG_OMAP_DEBUG_POWERDOMAIN is not set +# CONFIG_OMAP_DEBUG_CLOCKDOMAIN is not set +# CONFIG_OMAP_RESET_CLOCKS is not set +CONFIG_OMAP_MUX=y +CONFIG_OMAP_MUX_DEBUG=y +CONFIG_OMAP_MUX_WARNINGS=y +CONFIG_OMAP_MCBSP=y +# CONFIG_OMAP_MPU_TIMER is not set +CONFIG_OMAP_32K_TIMER=y +CONFIG_OMAP_32K_TIMER_HZ=128 +CONFIG_OMAP_DM_TIMER=y +# CONFIG_OMAP_LL_DEBUG_UART1 is not set +# CONFIG_OMAP_LL_DEBUG_UART2 is not set +CONFIG_OMAP_LL_DEBUG_UART3=y +CONFIG_OMAP_SERIAL_WAKE=y +CONFIG_ARCH_OMAP34XX=y +CONFIG_ARCH_OMAP3430=y + +# +# OMAP Board Type +# +# CONFIG_MACH_OMAP3_BEAGLE is not set +# CONFIG_MACH_OMAP_LDP is not set +CONFIG_MACH_OMAP_ZOOM2=y +# CONFIG_MACH_OVERO is not set + +# +# Boot options +# + +# +# Power management +# + +# +# Processor Type +# +CONFIG_CPU_32=y +CONFIG_CPU_32v6K=y +CONFIG_CPU_V7=y +CONFIG_CPU_32v7=y +CONFIG_CPU_ABRT_EV7=y +CONFIG_CPU_PABRT_IFAR=y +CONFIG_CPU_CACHE_V7=y +CONFIG_CPU_CACHE_VIPT=y +CONFIG_CPU_COPY_V6=y +CONFIG_CPU_TLB_V7=y +CONFIG_CPU_HAS_ASID=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y + +# +# Processor Features +# +CONFIG_ARM_THUMB=y +# CONFIG_ARM_THUMBEE is not set +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_BPREDICT_DISABLE is not set +CONFIG_HAS_TLS_REG=y +# CONFIG_OUTER_CACHE is not set + +# +# Bus support +# +# CONFIG_PCI_SYSCALL is not set +# CONFIG_ARCH_SUPPORTS_MSI is not set +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +# CONFIG_PREEMPT is not set +CONFIG_HZ=128 +CONFIG_AEABI=y +CONFIG_OABI_COMPAT=y +CONFIG_ARCH_FLATMEM_HAS_HOLES=y +# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set +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_PAGEFLAGS_EXTENDED=y +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_RESOURCES_64BIT is not set +CONFIG_ZONE_DMA_FLAG=1 +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y +# CONFIG_LEDS is not set +CONFIG_ALIGNMENT_TRAP=y + +# +# Boot options +# +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CMDLINE="root=/dev/nfs nfsroot=192.168.0.1:/home/user/buildroot ip=192.168.0.2:192.168.0.1:192.168.0.1:255.255.255.0:tgt:eth0:off rw console=ttyS2,115200n8" +# CONFIG_XIP_KERNEL is not set +# CONFIG_KEXEC is not set + +# +# CPU Frequency scaling +# +# CONFIG_CPU_FREQ is not set + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +CONFIG_FPE_NWFPE=y +# CONFIG_FPE_NWFPE_XP is not set +# CONFIG_FPE_FASTFPE is not set +CONFIG_VFP=y +CONFIG_VFPv3=y +# CONFIG_NEON is not set + +# +# Userspace binary formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_MISC=y + +# +# Power management options +# +# CONFIG_PM is not set +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +CONFIG_XFRM=y +CONFIG_XFRM_USER=y +# CONFIG_XFRM_SUB_POLICY is not set +CONFIG_XFRM_MIGRATE=y +# CONFIG_XFRM_STATISTICS is not set +CONFIG_NET_KEY=y +CONFIG_NET_KEY_MIGRATE=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# 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=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +# CONFIG_INET_LRO is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER 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 is not set +# CONFIG_NET_DSA is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# 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 is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO 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_PHONET is not set +# CONFIG_WIRELESS 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 is not set +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +CONFIG_CONNECTOR=y +CONFIG_PROC_EVENTS=y +# CONFIG_MTD is not set +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=16384 +# CONFIG_BLK_DEV_XIP is not set +# CONFIG_CDROM_PKTCDVD is not set +CONFIG_MISC_DEVICES=y +# CONFIG_EEPROM_93CX6 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=y +# 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_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +CONFIG_SCSI_LOWLEVEL=y +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_DH is not set +# CONFIG_ATA is not set +# CONFIG_MD is not set +CONFIG_NETDEVICES=y +# 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_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_MARVELL_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_VITESSE_PHY is not set +CONFIG_SMSC_PHY=y +# CONFIG_BROADCOM_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_FIXED_PHY is not set +# CONFIG_MDIO_BITBANG is not set +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_AX88796 is not set +# CONFIG_SMC91X is not set +# CONFIG_DM9000 is not set +# CONFIG_ENC28J60 is not set +# CONFIG_SMC911X is not set +CONFIG_SMSC911X=y +# 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_IBM_NEW_EMAC_NO_FLOW_CTRL is not set +# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set +# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set +# CONFIG_B44 is not set +CONFIG_NETDEV_1000=y +CONFIG_NETDEV_10000=y + +# +# Wireless LAN +# +# CONFIG_WLAN_PRE80211 is not set +# CONFIG_WLAN_80211 is not set +# CONFIG_IWLWIFI_LEDS is not set + +# +# USB Network Adapters +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_USBNET is not set +# CONFIG_WAN is not set +# CONFIG_PPP is not set +# CONFIG_SLIP 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 + +# +# 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=y +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_ADS7846=y +# CONFIG_TOUCHSCREEN_FUJITSU is not set +# CONFIG_TOUCHSCREEN_GUNZE is not set +# CONFIG_TOUCHSCREEN_ELO is not set +# CONFIG_TOUCHSCREEN_MTOUCH is not set +# CONFIG_TOUCHSCREEN_INEXIO is not set +# CONFIG_TOUCHSCREEN_MK712 is not set +# CONFIG_TOUCHSCREEN_PENMOUNT is not set +# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set +# CONFIG_TOUCHSCREEN_TOUCHWIN is not set +# CONFIG_TOUCHSCREEN_UCB1400 is not set +# CONFIG_TOUCHSCREEN_TOUCHIT213 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=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +CONFIG_DEVKMEM=y +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=32 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_MANY_PORTS=y +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_8250_DETECT_IRQ=y +CONFIG_SERIAL_8250_RSA=y + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +# CONFIG_LEGACY_PTYS is not set +# CONFIG_IPMI_HANDLER is not set +CONFIG_HW_RANDOM=y +# CONFIG_NVRAM is not set +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_HELPER_AUTO=y + +# +# I2C Hardware Bus support +# + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_GPIO is not set +# CONFIG_I2C_OCORES is not set +CONFIG_I2C_OMAP=y +# CONFIG_I2C_SIMTEC is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_TAOS_EVM is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_STUB is not set + +# +# Miscellaneous I2C Chip support +# +# CONFIG_DS1682 is not set +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_PCF8575 is not set +# CONFIG_SENSORS_PCA9539 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_ISP1301_OMAP is not set +# CONFIG_TPS65010 is not set +# CONFIG_SENSORS_MAX6875 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_BITBANG is not set +CONFIG_SPI_OMAP24XX=y + +# +# SPI Protocol Masters +# +# CONFIG_EEPROM_AT25 is not set +# CONFIG_SPI_SPIDEV is not set +# CONFIG_SPI_TLE62X0 is not set +CONFIG_ARCH_REQUIRE_GPIOLIB=y +CONFIG_GPIOLIB=y +# CONFIG_DEBUG_GPIO is not set +# CONFIG_GPIO_SYSFS is not set + +# +# I2C GPIO expanders: +# +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_GPIO_PCF857X is not set + +# +# PCI GPIO expanders: +# + +# +# SPI GPIO expanders: +# +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MCP23S08 is not set +CONFIG_W1=y + +# +# 1-wire Bus Masters +# +# CONFIG_W1_MASTER_DS2482 is not set +# CONFIG_W1_MASTER_DS1WM is not set +# CONFIG_W1_MASTER_GPIO is not set + +# +# 1-wire Slaves +# +# CONFIG_W1_SLAVE_THERM is not set +# CONFIG_W1_SLAVE_SMEM is not set +# CONFIG_W1_SLAVE_DS2433 is not set +# CONFIG_W1_SLAVE_DS2760 is not set +CONFIG_POWER_SUPPLY=y +# CONFIG_POWER_SUPPLY_DEBUG is not set +# CONFIG_PDA_POWER is not set +# CONFIG_BATTERY_DS2760 is not set +# CONFIG_HWMON is not set +CONFIG_WATCHDOG=y +CONFIG_WATCHDOG_NOWAYOUT=y + +# +# Watchdog Device Drivers +# +# CONFIG_SOFT_WATCHDOG is not set + +# +# Sonics Silicon Backplane +# +CONFIG_SSB_POSSIBLE=y +# CONFIG_SSB is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_HTC_EGPIO is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_T7L66XB is not set +# CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_TC6393XB is not set + +# +# Multimedia devices +# + +# +# Multimedia core support +# +# CONFIG_VIDEO_DEV is not set +# CONFIG_VIDEO_MEDIA is not set + +# +# Multimedia drivers +# +CONFIG_DAB=y + +# +# Graphics support +# +# CONFIG_VGASTATE is not set +CONFIG_VIDEO_OUTPUT_CONTROL=m +# CONFIG_FB is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +CONFIG_SOUND=y +CONFIG_SND=y +# CONFIG_SND_SEQUENCER is not set +# CONFIG_SND_MIXER_OSS is not set +# CONFIG_SND_PCM_OSS is not set +# CONFIG_SND_DYNAMIC_MINORS is not set +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_VERBOSE_PROCFS=y +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set +CONFIG_SND_DRIVERS=y +# CONFIG_SND_DUMMY is not set +# CONFIG_SND_MTPAV is not set +# CONFIG_SND_SERIAL_U16550 is not set +# CONFIG_SND_MPU401 is not set +CONFIG_SND_ARM=y +CONFIG_SND_SPI=y +# CONFIG_SND_SOC is not set +# CONFIG_SOUND_PRIME is not set +CONFIG_HID_SUPPORT=y +CONFIG_HID=y +# CONFIG_HID_DEBUG is not set +# CONFIG_HIDRAW is not set +# CONFIG_USB_SUPPORT is not set +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set +# CONFIG_MMC_UNSAFE_RESUME is not set + +# +# MMC/SD Card Drivers +# +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_BOUNCE=y +# CONFIG_SDIO_UART is not set +# CONFIG_MMC_TEST is not set + +# +# MMC/SD Host Controller Drivers +# +# CONFIG_MMC_SDHCI is not set +# CONFIG_MMC_OMAP is not set +# CONFIG_MMC_SPI is not set +# CONFIG_NEW_LEDS is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_FM3130 is not set + +# +# SPI RTC drivers +# +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RS5C348 is not set + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_V3020 is not set + +# +# on-CPU RTC drivers +# +# CONFIG_DMADEVICES is not set + +# +# Voltage and Current regulators +# +# CONFIG_REGULATOR is not set +# CONFIG_REGULATOR_FIXED_VOLTAGE is not set +# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set +# CONFIG_REGULATOR_BQ24022 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=y +# CONFIG_EXT3_FS_XATTR is not set +# CONFIG_EXT4DEV_FS is not set +CONFIG_JBD=y +# 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_DNOTIFY=y +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +CONFIG_QUOTA=y +CONFIG_PRINT_QUOTA_WARNING=y +# CONFIG_QFMT_V1 is not set +CONFIG_QFMT_V2=y +CONFIG_QUOTACTL=y +# 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_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=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 is not set + +# +# 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_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_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=y +CONFIG_NFS_V3=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_ACL_SUPPORT=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +CONFIG_SUNRPC_GSS=y +# CONFIG_SUNRPC_REGISTER_V4 is not set +CONFIG_RPCSEC_GSS_KRB5=y +# CONFIG_RPCSEC_GSS_SPKM3 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 is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# 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=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +CONFIG_NLS_ISO8859_1=y +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_WARN_DEPRECATED=y +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=1024 +CONFIG_MAGIC_SYSRQ=y +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_HEADERS_CHECK is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +CONFIG_DETECT_SOFTLOCKUP=y +# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0 +CONFIG_SCHED_DEBUG=y +# CONFIG_SCHEDSTATS is not set +# CONFIG_TIMER_STATS is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +CONFIG_DEBUG_MUTEXES=y +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_WRITECOUNT is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_SG is not set +CONFIG_FRAME_POINTER=y +# CONFIG_BOOT_PRINTK_DELAY is not set +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_LATENCYTOP is not set +CONFIG_HAVE_FTRACE=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +# CONFIG_FTRACE is not set +# CONFIG_IRQSOFF_TRACER is not set +# CONFIG_SCHED_TRACER is not set +# CONFIG_CONTEXT_SWITCH_TRACER is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +# CONFIG_DEBUG_USER is not set +# CONFIG_DEBUG_ERRORS is not set +# CONFIG_DEBUG_STACK_USAGE is not set +CONFIG_DEBUG_LL=y +# CONFIG_DEBUG_ICEDCC is not set + +# +# 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=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_MANAGER=y +# 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 is not set + +# +# 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=y +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +CONFIG_CRYPTO_ECB=m +# CONFIG_CRYPTO_LRW is not set +CONFIG_CRYPTO_PCBC=m +# 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=y +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 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=y +# 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=y + +# +# Library routines +# +CONFIG_BITREVERSE=y +# CONFIG_GENERIC_FIND_FIRST_BIT is not set +# CONFIG_GENERIC_FIND_NEXT_BIT is not set +CONFIG_CRC_CCITT=y +# CONFIG_CRC16 is not set +CONFIG_CRC_T10DIF=y +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC7 is not set +CONFIG_LIBCRC32C=y +CONFIG_PLIST=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y diff --git a/arch/arm/configs/orion5x_defconfig b/arch/arm/configs/orion5x_defconfig index 5b98f7645119..9e2385293ecb 100644 --- a/arch/arm/configs/orion5x_defconfig +++ b/arch/arm/configs/orion5x_defconfig @@ -903,7 +903,8 @@ CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=16 # CONFIG_IPMI_HANDLER is not set -# CONFIG_HW_RANDOM is not set +CONFIG_HW_RANDOM=m +CONFIG_HW_RANDOM_TIMERIOMEM=m # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set # CONFIG_RAW_DRIVER is not set diff --git a/arch/arm/configs/rx51_defconfig b/arch/arm/configs/rx51_defconfig index 593102da8cd7..eb2cb31825c0 100644 --- a/arch/arm/configs/rx51_defconfig +++ b/arch/arm/configs/rx51_defconfig @@ -282,7 +282,7 @@ CONFIG_ALIGNMENT_TRAP=y # CONFIG_ZBOOT_ROM_TEXT=0x0 CONFIG_ZBOOT_ROM_BSS=0x0 -CONFIG_CMDLINE="init=/sbin/preinit ubi.mtd=4 root=ubi0:rootfs rootfstype=ubifs rw console=ttyMTD5" +CONFIG_CMDLINE="init=/sbin/preinit ubi.mtd=rootfs root=ubi0:rootfs rootfstype=ubifs rootflags=bulk_read,no_chk_data_crc rw console=ttyMTD,log console=tty0" # CONFIG_XIP_KERNEL is not set # CONFIG_KEXEC is not set diff --git a/arch/arm/configs/stmp378x_defconfig b/arch/arm/configs/stmp378x_defconfig new file mode 100644 index 000000000000..44461f197a17 --- /dev/null +++ b/arch/arm/configs/stmp378x_defconfig @@ -0,0 +1,1141 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.30-rc2 +# Thu Apr 23 02:44:13 2009 +# +CONFIG_ARM=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_GENERIC_GPIO=y +CONFIG_GENERIC_TIME=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_MMU=y +# CONFIG_NO_IOPORT is not set +CONFIG_GENERIC_HARDIRQS=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_HAVE_LATENCYTOP_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y +CONFIG_VECTORS_BASE=0xffff0000 +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_LOCALVERSION="-default" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +CONFIG_POSIX_MQUEUE_SYSCTL=y +CONFIG_BSD_PROCESS_ACCT=y +# CONFIG_BSD_PROCESS_ACCT_V3 is not set +# CONFIG_TASKSTATS is not set +# CONFIG_AUDIT is not set + +# +# RCU Subsystem +# +CONFIG_CLASSIC_RCU=y +# CONFIG_TREE_RCU is not set +# CONFIG_PREEMPT_RCU is not set +# CONFIG_TREE_RCU_TRACE is not set +# CONFIG_PREEMPT_RCU_TRACE is not set +# CONFIG_IKCONFIG is not set +CONFIG_LOG_BUF_SHIFT=17 +# CONFIG_GROUP_SCHED is not set +# CONFIG_CGROUPS is not set +CONFIG_SYSFS_DEPRECATED=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_RELAY=y +# CONFIG_NAMESPACES is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_INITRAMFS_ROOT_UID=0 +CONFIG_INITRAMFS_ROOT_GID=0 +CONFIG_RD_GZIP=y +# CONFIG_RD_BZIP2 is not set +# CONFIG_RD_LZMA is not set +# CONFIG_INITRAMFS_COMPRESSION_NONE is not set +CONFIG_INITRAMFS_COMPRESSION_GZIP=y +# CONFIG_INITRAMFS_COMPRESSION_BZIP2 is not set +# CONFIG_INITRAMFS_COMPRESSION_LZMA is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y +CONFIG_EMBEDDED=y +CONFIG_UID16=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_STRIP_ASM_SYMS=y +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_COMPAT_BRK=y +CONFIG_SLAB=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set +# CONFIG_PROFILING is not set +CONFIG_TRACEPOINTS=y +CONFIG_MARKERS=y +CONFIG_HAVE_OPROFILE=y +# CONFIG_KPROBES is not set +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_CLK=y +# CONFIG_SLOW_WORK is not set +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SRCVERSION_ALL=y +CONFIG_BLOCK=y +CONFIG_LBD=y +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_BLK_DEV_INTEGRITY is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_DEFAULT_AS is not set +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" +# CONFIG_FREEZER is not set + +# +# System Type +# +# CONFIG_ARCH_AAEC2000 is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_GEMINI is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_IMX is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP23XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_KIRKWOOD is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_NS9XXX is not set +# CONFIG_ARCH_LOKI is not set +# CONFIG_ARCH_MV78XX0 is not set +# CONFIG_ARCH_MXC is not set +# CONFIG_ARCH_ORION5X is not set +# CONFIG_ARCH_PNX4008 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_MMP is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_S3C64XX is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_LH7A40X is not set +# CONFIG_ARCH_DAVINCI is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_ARCH_MSM is not set +# CONFIG_ARCH_W90X900 is not set +CONFIG_ARCH_STMP3XXX=y + +# +# Freescale STMP3xxx implementations +# +# CONFIG_ARCH_STMP37XX is not set +CONFIG_ARCH_STMP378X=y +# CONFIG_MACH_STMP37XX is not set +CONFIG_MACH_STMP378X=y + +# +# Processor Type +# +CONFIG_CPU_32=y +CONFIG_CPU_ARM926T=y +CONFIG_CPU_32v5=y +CONFIG_CPU_ABRT_EV5TJ=y +CONFIG_CPU_PABRT_NOIFAR=y +CONFIG_CPU_CACHE_VIVT=y +CONFIG_CPU_COPY_V4WB=y +CONFIG_CPU_TLB_V4WBI=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y + +# +# Processor Features +# +CONFIG_ARM_THUMB=y +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_WRITETHROUGH is not set +# CONFIG_CPU_CACHE_ROUND_ROBIN is not set +# CONFIG_OUTER_CACHE is not set +CONFIG_COMMON_CLKDEV=y + +# +# Bus support +# +# CONFIG_PCI_SYSCALL is not set +# CONFIG_ARCH_SUPPORTS_MSI is not set +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_1G is not set +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_PREEMPT=y +CONFIG_HZ=100 +CONFIG_AEABI=y +CONFIG_OABI_COMPAT=y +CONFIG_ARCH_FLATMEM_HAS_HOLES=y +# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set +# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set +CONFIG_HIGHMEM=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_PAGEFLAGS_EXTENDED=y +CONFIG_SPLIT_PTLOCK_CPUS=4096 +# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y +CONFIG_UNEVICTABLE_LRU=y +CONFIG_HAVE_MLOCK=y +CONFIG_HAVE_MLOCKED_PAGE_BIT=y +CONFIG_ALIGNMENT_TRAP=y + +# +# Boot options +# +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CMDLINE="console=ttySDBG0,115200 mem=32M" +# CONFIG_XIP_KERNEL is not set +# CONFIG_KEXEC is not set + +# +# CPU Power Management +# +# CONFIG_CPU_IDLE is not set + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +# CONFIG_FPE_NWFPE is not set +# CONFIG_FPE_FASTFPE is not set +# CONFIG_VFP is not set + +# +# Userspace binary formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_HAVE_AOUT=y +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set + +# +# Power management options +# +# CONFIG_PM is not set +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +CONFIG_UNIX=y +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +# 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=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +CONFIG_IP_MROUTE=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +# CONFIG_ARPD is not set +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=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +# CONFIG_INET_LRO is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_NETLABEL is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER 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 is not set +# CONFIG_NET_DSA is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# 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_PHONET is not set +CONFIG_NET_SCHED=y + +# +# Queueing/Scheduling +# +# CONFIG_NET_SCH_CBQ is not set +# CONFIG_NET_SCH_HTB is not set +# CONFIG_NET_SCH_HFSC is not set +# CONFIG_NET_SCH_PRIO is not set +# CONFIG_NET_SCH_MULTIQ is not set +# 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 is not set +# CONFIG_NET_SCH_DRR is not set + +# +# Classification +# +# CONFIG_NET_CLS_BASIC is not set +# CONFIG_NET_CLS_TCINDEX is not set +# CONFIG_NET_CLS_ROUTE4 is not set +# CONFIG_NET_CLS_FW is not set +# CONFIG_NET_CLS_U32 is not set +# CONFIG_NET_CLS_RSVP is not set +# CONFIG_NET_CLS_RSVP6 is not set +# CONFIG_NET_CLS_FLOW is not set +# CONFIG_NET_EMATCH is not set +# CONFIG_NET_CLS_ACT is not set +CONFIG_NET_SCH_FIFO=y +# CONFIG_DCB is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NET_DROP_MONITOR is not set +# CONFIG_HAMRADIO 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 +# CONFIG_WIRELESS is not set +# CONFIG_WIMAX 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 is not set +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +CONFIG_FIRMWARE_IN_KERNEL=y +CONFIG_EXTRA_FIRMWARE="" +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# 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 is not set +# CONFIG_MTD_TESTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +# CONFIG_MTD_BLKDEVS is not set +# CONFIG_MTD_BLOCK is not set +# CONFIG_MTD_BLOCK_RO is not set +# 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_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# 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 is not set +# CONFIG_MTD_NAND_ECC_SMC is not set +# CONFIG_MTD_NAND_MUSEUM_IDS is not set +# CONFIG_MTD_NAND_GPIO is not set +CONFIG_MTD_NAND_IDS=y +# CONFIG_MTD_NAND_DISKONCHIP is not set +# CONFIG_MTD_NAND_PLATFORM is not set +# CONFIG_MTD_ONENAND is not set + +# +# LPDDR flash memory drivers +# +# CONFIG_MTD_LPDDR is not set + +# +# UBI - Unsorted block images +# +CONFIG_MTD_UBI=y +CONFIG_MTD_UBI_WL_THRESHOLD=4096 +CONFIG_MTD_UBI_BEB_RESERVE=1 +CONFIG_MTD_UBI_GLUEBI=y + +# +# UBI debugging options +# +# CONFIG_MTD_UBI_DEBUG is not set +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_CRYPTOLOOP=y +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=4 +CONFIG_BLK_DEV_RAM_SIZE=6144 +# CONFIG_BLK_DEV_XIP is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_MISC_DEVICES 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=y +# 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=y +# 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 is not set +# CONFIG_SCSI_DH is not set +# CONFIG_SCSI_OSD_INITIATOR is not set +# CONFIG_ATA is not set +# CONFIG_MD is not set +# CONFIG_NETDEVICES is not set +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set +CONFIG_INPUT_POLLDEV=y + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=320 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=240 +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y +# 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=y +# CONFIG_TOUCHSCREEN_AD7879 is not set +# CONFIG_TOUCHSCREEN_FUJITSU is not set +# CONFIG_TOUCHSCREEN_GUNZE is not set +# CONFIG_TOUCHSCREEN_ELO is not set +# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set +# CONFIG_TOUCHSCREEN_MTOUCH is not set +# CONFIG_TOUCHSCREEN_INEXIO is not set +# CONFIG_TOUCHSCREEN_MK712 is not set +# CONFIG_TOUCHSCREEN_PENMOUNT is not set +# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set +# CONFIG_TOUCHSCREEN_TOUCHWIN is not set +# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set +CONFIG_INPUT_MISC=y +# CONFIG_INPUT_UINPUT is not set +# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +# CONFIG_SERIO_SERPORT is not set +# CONFIG_SERIO_LIBPS2 is not set +# CONFIG_SERIO_RAW is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +CONFIG_VT_HW_CONSOLE_BINDING=y +CONFIG_DEVKMEM=y +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_UNIX98_PTYS=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_IPMI_HANDLER is not set +CONFIG_HW_RANDOM=y +# CONFIG_HW_RANDOM_TIMERIOMEM is not set +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_I2C is not set +# CONFIG_SPI is not set +CONFIG_ARCH_REQUIRE_GPIOLIB=y +CONFIG_GPIOLIB=y +CONFIG_DEBUG_GPIO=y +CONFIG_GPIO_SYSFS=y + +# +# Memory mapped GPIO expanders: +# + +# +# I2C GPIO expanders: +# + +# +# PCI GPIO expanders: +# + +# +# SPI GPIO expanders: +# +# CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set +# CONFIG_HWMON is not set +# CONFIG_THERMAL is not set +# CONFIG_THERMAL_HWMON is not set +# CONFIG_WATCHDOG is not set +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_ASIC3 is not set +# CONFIG_HTC_EGPIO is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_T7L66XB is not set +# CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_TC6393XB is not set + +# +# Multimedia devices +# + +# +# Multimedia core support +# +CONFIG_VIDEO_DEV=y +CONFIG_VIDEO_V4L2_COMMON=y +# CONFIG_VIDEO_ALLOW_V4L1 is not set +# CONFIG_VIDEO_V4L1_COMPAT is not set +# CONFIG_DVB_CORE is not set +CONFIG_VIDEO_MEDIA=y + +# +# Multimedia drivers +# +# CONFIG_MEDIA_ATTACH is not set +CONFIG_VIDEO_V4L2=y +CONFIG_VIDEO_CAPTURE_DRIVERS=y +# CONFIG_VIDEO_ADV_DEBUG is not set +# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set +# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set + +# +# Encoders/decoders and other helper chips +# + +# +# Audio decoders +# + +# +# RDS 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_SOC_CAMERA is not set +# CONFIG_RADIO_ADAPTERS is not set +# CONFIG_DAB is not set + +# +# Graphics support +# +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +CONFIG_FB=y +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB_DDC is not set +# CONFIG_FB_BOOT_VESA_SUPPORT is not set +# CONFIG_FB_CFB_FILLRECT is not set +# CONFIG_FB_CFB_COPYAREA is not set +# CONFIG_FB_CFB_IMAGEBLIT is not set +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +# CONFIG_FB_SYS_FILLRECT is not set +# CONFIG_FB_SYS_COPYAREA is not set +# CONFIG_FB_SYS_IMAGEBLIT is not set +# CONFIG_FB_FOREIGN_ENDIAN is not set +# CONFIG_FB_SYS_FOPS is not set +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_BACKLIGHT is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_MB862XX is not set +# CONFIG_FB_BROADSHEET is not set +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_LCD_CLASS_DEVICE=y +# CONFIG_LCD_ILI9320 is not set +# CONFIG_LCD_PLATFORM is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_GENERIC=y + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set +# CONFIG_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y +CONFIG_LOGO=y +CONFIG_LOGO_LINUX_MONO=y +CONFIG_LOGO_LINUX_VGA16=y +CONFIG_LOGO_LINUX_CLUT224=y +# CONFIG_SOUND is not set +# CONFIG_HID_SUPPORT is not set +# CONFIG_USB_SUPPORT is not set +CONFIG_USB_ARCH_HAS_EHCI=y +# CONFIG_MMC is not set +# CONFIG_MEMSTICK is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_NEW_LEDS is not set +CONFIG_RTC_LIB=y +# CONFIG_RTC_CLASS is not set +# CONFIG_DMADEVICES is not set +# CONFIG_AUXDISPLAY is not set +# CONFIG_REGULATOR is not set +# CONFIG_UIO is not set +# CONFIG_STAGING is not set + +# +# File systems +# +# CONFIG_EXT2_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_EXT4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +CONFIG_FILE_LOCKING=y +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_BTRFS_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 + +# +# Caches +# +# CONFIG_FSCACHE 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_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_CONFIGFS_FS=m +# CONFIG_MISC_FILESYSTEMS is not set +# CONFIG_NETWORK_FILESYSTEMS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_NLS is not set +# CONFIG_DLM is not set + +# +# Kernel hacking +# +# 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=y +# CONFIG_HEADERS_CHECK is not set +CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_SHIRQ=y +CONFIG_DETECT_SOFTLOCKUP=y +# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0 +CONFIG_DETECT_HUNG_TASK=y +# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set +CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0 +# CONFIG_SCHED_DEBUG is not set +# CONFIG_SCHEDSTATS is not set +# CONFIG_TIMER_STATS is not set +CONFIG_DEBUG_OBJECTS=y +CONFIG_DEBUG_OBJECTS_SELFTEST=y +CONFIG_DEBUG_OBJECTS_FREE=y +CONFIG_DEBUG_OBJECTS_TIMERS=y +CONFIG_DEBUG_OBJECTS_ENABLE_DEFAULT=1 +CONFIG_DEBUG_SLAB=y +CONFIG_DEBUG_SLAB_LEAK=y +CONFIG_DEBUG_PREEMPT=y +CONFIG_DEBUG_RT_MUTEXES=y +CONFIG_DEBUG_PI_LIST=y +# CONFIG_RT_MUTEX_TESTER is not set +CONFIG_DEBUG_SPINLOCK=y +CONFIG_DEBUG_MUTEXES=y +CONFIG_DEBUG_LOCK_ALLOC=y +CONFIG_PROVE_LOCKING=y +CONFIG_LOCKDEP=y +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_LOCKDEP is not set +CONFIG_TRACE_IRQFLAGS=y +CONFIG_DEBUG_SPINLOCK_SLEEP=y +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +CONFIG_STACKTRACE=y +CONFIG_DEBUG_KOBJECT=y +# CONFIG_DEBUG_HIGHMEM is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_WRITECOUNT is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +CONFIG_FRAME_POINTER=y +# CONFIG_BOOT_PRINTK_DELAY is not set +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_RCU_CPU_STALL_DETECTOR is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_LATENCYTOP is not set +CONFIG_SYSCTL_SYSCALL_CHECK=y +# CONFIG_PAGE_POISONING is not set +CONFIG_NOP_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_RING_BUFFER=y +CONFIG_TRACING=y +CONFIG_TRACING_SUPPORT=y + +# +# Tracers +# +CONFIG_FUNCTION_TRACER=y +# CONFIG_IRQSOFF_TRACER is not set +# CONFIG_PREEMPT_TRACER is not set +# CONFIG_SCHED_TRACER is not set +CONFIG_CONTEXT_SWITCH_TRACER=y +# CONFIG_EVENT_TRACER is not set +CONFIG_BOOT_TRACER=y +# CONFIG_TRACE_BRANCH_PROFILING is not set +CONFIG_STACK_TRACER=y +# CONFIG_KMEMTRACE is not set +# CONFIG_WORKQUEUE_TRACER is not set +CONFIG_BLK_DEV_IO_TRACE=y +# CONFIG_FTRACE_STARTUP_TEST is not set +# CONFIG_DYNAMIC_DEBUG is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +CONFIG_ARM_UNWIND=y +# CONFIG_DEBUG_USER is not set +# CONFIG_DEBUG_ERRORS is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_LL is not set + +# +# Security options +# +CONFIG_KEYS=y +CONFIG_KEYS_DEBUG_PROC_KEYS=y +CONFIG_SECURITY=y +# CONFIG_SECURITYFS is not set +# CONFIG_SECURITY_NETWORK is not set +# CONFIG_SECURITY_PATH is not set +# CONFIG_SECURITY_FILE_CAPABILITIES is not set +CONFIG_SECURITY_DEFAULT_MMAP_MIN_ADDR=0 +# CONFIG_SECURITY_TOMOYO is not set +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +# CONFIG_CRYPTO_FIPS is not set +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_BLKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_PCOMP=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_NULL is not set +CONFIG_CRYPTO_WORKQUEUE=y +# 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=y +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +CONFIG_CRYPTO_ECB=y +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_XTS is not set + +# +# Hash modes +# +CONFIG_CRYPTO_HMAC=y +# CONFIG_CRYPTO_XCBC is not set + +# +# Digest +# +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +CONFIG_CRYPTO_SHA1=m +# 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=m +# 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=y +# 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=y +# CONFIG_CRYPTO_ZLIB is not set +CONFIG_CRYPTO_LZO=y + +# +# Random Number Generation +# +# CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_CRYPTO_HW=y +CONFIG_BINARY_PRINTF=y + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_GENERIC_FIND_LAST_BIT=y +CONFIG_CRC_CCITT=m +CONFIG_CRC16=y +# CONFIG_CRC_T10DIF is not set +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC7 is not set +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_DECOMPRESS_GZIP=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y +CONFIG_NLATTR=y diff --git a/arch/arm/configs/stmp37xx_defconfig b/arch/arm/configs/stmp37xx_defconfig new file mode 100644 index 000000000000..401279d531d5 --- /dev/null +++ b/arch/arm/configs/stmp37xx_defconfig @@ -0,0 +1,1002 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.29.1 +# Mon Apr 20 04:41:26 2009 +# +CONFIG_ARM=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_GENERIC_GPIO=y +CONFIG_GENERIC_TIME=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_MMU=y +# CONFIG_NO_IOPORT is not set +CONFIG_GENERIC_HARDIRQS=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_HAVE_LATENCYTOP_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y +CONFIG_VECTORS_BASE=0xffff0000 +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_LOCALVERSION="-default" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +CONFIG_BSD_PROCESS_ACCT=y +# CONFIG_BSD_PROCESS_ACCT_V3 is not set +# CONFIG_TASKSTATS is not set +# CONFIG_AUDIT is not set + +# +# RCU Subsystem +# +CONFIG_CLASSIC_RCU=y +# CONFIG_TREE_RCU is not set +# CONFIG_PREEMPT_RCU is not set +# CONFIG_TREE_RCU_TRACE is not set +# CONFIG_PREEMPT_RCU_TRACE is not set +# CONFIG_IKCONFIG is not set +CONFIG_LOG_BUF_SHIFT=17 +# CONFIG_GROUP_SCHED is not set +# CONFIG_CGROUPS is not set +CONFIG_SYSFS_DEPRECATED=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_RELAY=y +# CONFIG_NAMESPACES is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_INITRAMFS_ROOT_UID=0 +CONFIG_INITRAMFS_ROOT_GID=0 +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y +CONFIG_EMBEDDED=y +CONFIG_UID16=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_COMPAT_BRK=y +CONFIG_SLAB=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set +# CONFIG_PROFILING is not set +CONFIG_TRACEPOINTS=y +CONFIG_MARKERS=y +CONFIG_HAVE_OPROFILE=y +# CONFIG_KPROBES is not set +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SRCVERSION_ALL=y +CONFIG_BLOCK=y +CONFIG_LBD=y +CONFIG_BLK_DEV_IO_TRACE=y +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_BLK_DEV_INTEGRITY is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_DEFAULT_AS is not set +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" +# CONFIG_FREEZER is not set + +# +# System Type +# +# CONFIG_ARCH_AAEC2000 is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_IMX is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP23XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_KIRKWOOD is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_NS9XXX is not set +# CONFIG_ARCH_LOKI is not set +# CONFIG_ARCH_MV78XX0 is not set +# CONFIG_ARCH_MXC is not set +# CONFIG_ARCH_ORION5X is not set +# CONFIG_ARCH_PNX4008 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_S3C64XX is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_LH7A40X is not set +# CONFIG_ARCH_DAVINCI is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_ARCH_MSM is not set +# CONFIG_ARCH_W90X900 is not set +CONFIG_ARCH_STMP3XXX=y + +# +# Freescale STMP3xxx implementations +# +CONFIG_ARCH_STMP37XX=y +# CONFIG_ARCH_STMP378X is not set +CONFIG_MACH_STMP37XX=y +# CONFIG_MACH_STMP378X is not set + +# +# Processor Type +# +CONFIG_CPU_32=y +CONFIG_CPU_ARM926T=y +CONFIG_CPU_32v5=y +CONFIG_CPU_ABRT_EV5TJ=y +CONFIG_CPU_PABRT_NOIFAR=y +CONFIG_CPU_CACHE_VIVT=y +CONFIG_CPU_COPY_V4WB=y +CONFIG_CPU_TLB_V4WBI=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y + +# +# Processor Features +# +CONFIG_ARM_THUMB=y +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_WRITETHROUGH is not set +# CONFIG_CPU_CACHE_ROUND_ROBIN is not set +# CONFIG_OUTER_CACHE is not set +CONFIG_COMMON_CLKDEV=y + +# +# Bus support +# +# CONFIG_PCI_SYSCALL is not set +# CONFIG_ARCH_SUPPORTS_MSI is not set +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_1G is not set +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_PREEMPT=y +CONFIG_HZ=100 +CONFIG_AEABI=y +CONFIG_OABI_COMPAT=y +CONFIG_ARCH_FLATMEM_HAS_HOLES=y +# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set +# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set +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_PAGEFLAGS_EXTENDED=y +CONFIG_SPLIT_PTLOCK_CPUS=4096 +# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 +CONFIG_VIRT_TO_BUS=y +CONFIG_UNEVICTABLE_LRU=y +CONFIG_ALIGNMENT_TRAP=y + +# +# Boot options +# +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CMDLINE="console=ttySDBG0,115200 mem=32M lcd_panel=lms350 rdinit=/bin/sh ignore_loglevel" +# CONFIG_XIP_KERNEL is not set +# CONFIG_KEXEC is not set + +# +# CPU Power Management +# +# CONFIG_CPU_IDLE is not set + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +# CONFIG_FPE_NWFPE is not set +# CONFIG_FPE_FASTFPE is not set +# CONFIG_VFP is not set + +# +# Userspace binary formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_HAVE_AOUT=y +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set + +# +# Power management options +# +# CONFIG_PM is not set +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_NET=y + +# +# Networking options +# +CONFIG_COMPAT_NET_DEV_OPS=y +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +CONFIG_UNIX=y +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +# 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=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +CONFIG_IP_MROUTE=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +# CONFIG_ARPD is not set +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=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +# CONFIG_INET_LRO is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_NETLABEL is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER 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 is not set +# CONFIG_NET_DSA is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# 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 is not set +# CONFIG_NET_SCH_HTB is not set +# CONFIG_NET_SCH_HFSC is not set +# CONFIG_NET_SCH_PRIO is not set +# CONFIG_NET_SCH_MULTIQ is not set +# 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 is not set +# CONFIG_NET_SCH_DRR is not set + +# +# Classification +# +# CONFIG_NET_CLS_BASIC is not set +# CONFIG_NET_CLS_TCINDEX is not set +# CONFIG_NET_CLS_ROUTE4 is not set +# CONFIG_NET_CLS_FW is not set +# CONFIG_NET_CLS_U32 is not set +# CONFIG_NET_CLS_RSVP is not set +# CONFIG_NET_CLS_RSVP6 is not set +# CONFIG_NET_CLS_FLOW is not set +# CONFIG_NET_EMATCH is not set +# CONFIG_NET_CLS_ACT is not set +CONFIG_NET_SCH_FIFO=y +# CONFIG_DCB is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO 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_PHONET is not set +CONFIG_FIB_RULES=y +# CONFIG_WIRELESS is not set +# CONFIG_WIMAX 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 is not set +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +CONFIG_FIRMWARE_IN_KERNEL=y +CONFIG_EXTRA_FIRMWARE="" +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_CONNECTOR is not set +# CONFIG_MTD is not set +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_CRYPTOLOOP=y +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=4 +CONFIG_BLK_DEV_RAM_SIZE=6144 +# CONFIG_BLK_DEV_XIP is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_MISC_DEVICES 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=y +# 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=y +# 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 is not set +# CONFIG_SCSI_DH is not set +# CONFIG_ATA is not set +# CONFIG_MD is not set +# CONFIG_NETDEVICES is not set +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set +CONFIG_INPUT_POLLDEV=y + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=320 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=240 +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y +# 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=y +# CONFIG_TOUCHSCREEN_FUJITSU is not set +# CONFIG_TOUCHSCREEN_GUNZE is not set +# CONFIG_TOUCHSCREEN_ELO is not set +# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set +# CONFIG_TOUCHSCREEN_MTOUCH is not set +# CONFIG_TOUCHSCREEN_INEXIO is not set +# CONFIG_TOUCHSCREEN_MK712 is not set +# CONFIG_TOUCHSCREEN_PENMOUNT is not set +# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set +# CONFIG_TOUCHSCREEN_TOUCHWIN is not set +# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set +CONFIG_INPUT_MISC=y +# CONFIG_INPUT_UINPUT is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +# CONFIG_SERIO_SERPORT is not set +# CONFIG_SERIO_LIBPS2 is not set +# CONFIG_SERIO_RAW is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +CONFIG_VT_HW_CONSOLE_BINDING=y +CONFIG_DEVKMEM=y +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_STMP_DBG is not set +CONFIG_UNIX98_PTYS=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_IPMI_HANDLER is not set +CONFIG_HW_RANDOM=y +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_I2C is not set +# CONFIG_SPI is not set +CONFIG_ARCH_REQUIRE_GPIOLIB=y +CONFIG_GPIOLIB=y +CONFIG_DEBUG_GPIO=y +CONFIG_GPIO_SYSFS=y + +# +# Memory mapped GPIO expanders: +# + +# +# I2C GPIO expanders: +# + +# +# PCI GPIO expanders: +# + +# +# SPI GPIO expanders: +# +# CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set +# CONFIG_HWMON is not set +# CONFIG_THERMAL is not set +# CONFIG_THERMAL_HWMON is not set +# CONFIG_WATCHDOG is not set +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_ASIC3 is not set +# CONFIG_HTC_EGPIO is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_T7L66XB is not set +# CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_TC6393XB is not set + +# +# Multimedia devices +# + +# +# Multimedia core support +# +CONFIG_VIDEO_DEV=y +CONFIG_VIDEO_V4L2_COMMON=y +# CONFIG_VIDEO_ALLOW_V4L1 is not set +# CONFIG_VIDEO_V4L1_COMPAT is not set +# CONFIG_DVB_CORE is not set +CONFIG_VIDEO_MEDIA=y + +# +# Multimedia drivers +# +# CONFIG_MEDIA_ATTACH is not set +CONFIG_VIDEO_V4L2=y +CONFIG_VIDEO_CAPTURE_DRIVERS=y +# CONFIG_VIDEO_ADV_DEBUG is not set +# CONFIG_VIDEO_FIXED_MINOR_RANGES 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_SOC_CAMERA is not set +# CONFIG_RADIO_ADAPTERS is not set +# CONFIG_DAB is not set + +# +# Graphics support +# +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +CONFIG_FB=y +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB_DDC is not set +# CONFIG_FB_BOOT_VESA_SUPPORT is not set +# CONFIG_FB_CFB_FILLRECT is not set +# CONFIG_FB_CFB_COPYAREA is not set +# CONFIG_FB_CFB_IMAGEBLIT is not set +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +# CONFIG_FB_SYS_FILLRECT is not set +# CONFIG_FB_SYS_COPYAREA is not set +# CONFIG_FB_SYS_IMAGEBLIT is not set +# CONFIG_FB_FOREIGN_ENDIAN is not set +# CONFIG_FB_SYS_FOPS is not set +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_BACKLIGHT is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_MB862XX is not set +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_LCD_CLASS_DEVICE=y +# CONFIG_LCD_ILI9320 is not set +# CONFIG_LCD_PLATFORM is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_GENERIC=y + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set +# CONFIG_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y +CONFIG_LOGO=y +CONFIG_LOGO_LINUX_MONO=y +CONFIG_LOGO_LINUX_VGA16=y +CONFIG_LOGO_LINUX_CLUT224=y +# CONFIG_SOUND is not set +# CONFIG_HID_SUPPORT is not set +# CONFIG_USB_SUPPORT is not set +CONFIG_USB_ARCH_HAS_EHCI=y +# CONFIG_MMC is not set +# CONFIG_MEMSTICK is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_NEW_LEDS is not set +CONFIG_RTC_LIB=y +# CONFIG_RTC_CLASS is not set +# CONFIG_DMADEVICES is not set +# CONFIG_REGULATOR is not set +# CONFIG_UIO is not set +# CONFIG_STAGING is not set + +# +# File systems +# +# CONFIG_EXT2_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_EXT4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +CONFIG_FILE_LOCKING=y +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_BTRFS_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_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_CONFIGFS_FS=m +# CONFIG_MISC_FILESYSTEMS is not set +# CONFIG_NETWORK_FILESYSTEMS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_NLS is not set +# CONFIG_DLM is not set + +# +# Kernel hacking +# +# 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=y +# CONFIG_HEADERS_CHECK is not set +CONFIG_DEBUG_SECTION_MISMATCH=y +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +CONFIG_DETECT_SOFTLOCKUP=y +# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0 +CONFIG_SCHED_DEBUG=y +# CONFIG_SCHEDSTATS is not set +# CONFIG_TIMER_STATS is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_DEBUG_SLAB is not set +CONFIG_DEBUG_PREEMPT=y +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +CONFIG_STACKTRACE=y +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_INFO is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_WRITECOUNT is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +CONFIG_FRAME_POINTER=y +# CONFIG_BOOT_PRINTK_DELAY is not set +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_RCU_CPU_STALL_DETECTOR is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_LATENCYTOP is not set +CONFIG_SYSCTL_SYSCALL_CHECK=y +CONFIG_NOP_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_RING_BUFFER=y +CONFIG_TRACING=y + +# +# Tracers +# +CONFIG_FUNCTION_TRACER=y +# CONFIG_IRQSOFF_TRACER is not set +# CONFIG_PREEMPT_TRACER is not set +# CONFIG_SCHED_TRACER is not set +CONFIG_CONTEXT_SWITCH_TRACER=y +CONFIG_BOOT_TRACER=y +# CONFIG_TRACE_BRANCH_PROFILING is not set +CONFIG_STACK_TRACER=y +# CONFIG_DYNAMIC_PRINTK_DEBUG is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +# CONFIG_DEBUG_USER is not set +# CONFIG_DEBUG_ERRORS is not set +# CONFIG_DEBUG_STACK_USAGE is not set +CONFIG_DEBUG_LL=y +# CONFIG_DEBUG_ICEDCC is not set + +# +# Security options +# +CONFIG_KEYS=y +CONFIG_KEYS_DEBUG_PROC_KEYS=y +CONFIG_SECURITY=y +# CONFIG_SECURITYFS is not set +# CONFIG_SECURITY_NETWORK is not set +# CONFIG_SECURITY_PATH is not set +# CONFIG_SECURITY_FILE_CAPABILITIES is not set +CONFIG_SECURITY_DEFAULT_MMAP_MIN_ADDR=0 +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +# CONFIG_CRYPTO_FIPS is not set +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_BLKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +# 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=y +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +CONFIG_CRYPTO_ECB=y +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_XTS is not set + +# +# Hash modes +# +CONFIG_CRYPTO_HMAC=y +# CONFIG_CRYPTO_XCBC is not set + +# +# Digest +# +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +CONFIG_CRYPTO_SHA1=m +# 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=m +# 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=y +# 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=y +CONFIG_CRYPTO_LZO=y + +# +# Random Number Generation +# +# CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_CRYPTO_HW=y + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_GENERIC_FIND_LAST_BIT=y +CONFIG_CRC_CCITT=m +CONFIG_CRC16=y +# CONFIG_CRC_T10DIF is not set +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC7 is not set +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_PLIST=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y diff --git a/arch/arm/configs/u300_defconfig b/arch/arm/configs/u300_defconfig new file mode 100644 index 000000000000..2d827e121147 --- /dev/null +++ b/arch/arm/configs/u300_defconfig @@ -0,0 +1,1115 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.30-rc6 +# Mon Jun 1 09:18:22 2009 +# +CONFIG_ARM=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_GENERIC_GPIO=y +CONFIG_GENERIC_TIME=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_MMU=y +# CONFIG_NO_IOPORT is not set +CONFIG_GENERIC_HARDIRQS=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_HAVE_LATENCYTOP_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y +CONFIG_VECTORS_BASE=0xffff0000 +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +# CONFIG_SWAP is not set +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set +# CONFIG_AUDIT is not set + +# +# RCU Subsystem +# +CONFIG_CLASSIC_RCU=y +# CONFIG_TREE_RCU is not set +# CONFIG_PREEMPT_RCU is not set +# CONFIG_TREE_RCU_TRACE is not set +# CONFIG_PREEMPT_RCU_TRACE is not set +# CONFIG_IKCONFIG is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_GROUP_SCHED is not set +# CONFIG_CGROUPS is not set +# CONFIG_SYSFS_DEPRECATED_V2 is not set +# CONFIG_RELAY is not set +# CONFIG_NAMESPACES is not set +# CONFIG_BLK_DEV_INITRD is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y +CONFIG_EMBEDDED=y +CONFIG_UID16=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_EXTRA_PASS is not set +# CONFIG_STRIP_ASM_SYMS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +# CONFIG_AIO is not set +# CONFIG_VM_EVENT_COUNTERS is not set +CONFIG_SLUB_DEBUG=y +CONFIG_COMPAT_BRK=y +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +# CONFIG_PROFILING is not set +# CONFIG_MARKERS is not set +CONFIG_HAVE_OPROFILE=y +# CONFIG_KPROBES is not set +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_CLK=y +# CONFIG_SLOW_WORK is not set +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_BLOCK=y +# CONFIG_LBD is not set +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_BLK_DEV_INTEGRITY 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_FREEZER is not set + +# +# System Type +# +# CONFIG_ARCH_AAEC2000 is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_GEMINI is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_MXC is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_IMX is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP23XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_KIRKWOOD is not set +# CONFIG_ARCH_LOKI is not set +# CONFIG_ARCH_MV78XX0 is not set +# CONFIG_ARCH_ORION5X is not set +# CONFIG_ARCH_MMP is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_NS9XXX is not set +# CONFIG_ARCH_W90X900 is not set +# CONFIG_ARCH_PNX4008 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_MSM is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_S3C64XX is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_LH7A40X is not set +CONFIG_ARCH_U300=y +# CONFIG_ARCH_DAVINCI is not set +# CONFIG_ARCH_OMAP is not set + +# +# ST-Ericsson AB U300/U330/U335/U365 Platform +# + +# +# ST-Ericsson Mobile Platform Products +# +CONFIG_MACH_U300=y + +# +# ST-Ericsson U300/U330/U335/U365 Feature Selections +# +# CONFIG_MACH_U300_BS2X is not set +# CONFIG_MACH_U300_BS330 is not set +CONFIG_MACH_U300_BS335=y +# CONFIG_MACH_U300_BS365 is not set +# CONFIG_MACH_U300_SINGLE_RAM is not set +CONFIG_MACH_U300_DUAL_RAM=y +CONFIG_U300_DEBUG=y +# CONFIG_MACH_U300_SEMI_IS_SHARED is not set + +# +# All the settings below must match the bootloader's settings +# + +# +# Processor Type +# +CONFIG_CPU_32=y +CONFIG_CPU_ARM926T=y +CONFIG_CPU_32v5=y +CONFIG_CPU_ABRT_EV5TJ=y +CONFIG_CPU_PABRT_NOIFAR=y +CONFIG_CPU_CACHE_VIVT=y +CONFIG_CPU_COPY_V4WB=y +CONFIG_CPU_TLB_V4WBI=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y + +# +# Processor Features +# +CONFIG_ARM_THUMB=y +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_WRITETHROUGH is not set +# CONFIG_CPU_CACHE_ROUND_ROBIN is not set +# CONFIG_OUTER_CACHE is not set +CONFIG_ARM_VIC=y +CONFIG_COMMON_CLKDEV=y + +# +# Bus support +# +CONFIG_ARM_AMBA=y +# CONFIG_PCI_SYSCALL is not set +# CONFIG_ARCH_SUPPORTS_MSI is not set +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_1G is not set +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_PREEMPT=y +CONFIG_HZ=100 +CONFIG_AEABI=y +CONFIG_OABI_COMPAT=y +CONFIG_ARCH_FLATMEM_HAS_HOLES=y +# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set +# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set +# CONFIG_HIGHMEM is not set +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_PAGEFLAGS_EXTENDED=y +CONFIG_SPLIT_PTLOCK_CPUS=4096 +# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 +CONFIG_VIRT_TO_BUS=y +CONFIG_UNEVICTABLE_LRU=y +CONFIG_HAVE_MLOCK=y +CONFIG_HAVE_MLOCKED_PAGE_BIT=y +CONFIG_ALIGNMENT_TRAP=y + +# +# Boot options +# +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CMDLINE="root=/dev/mtdblock2 rw rootfstype=yaffs2 console=ttyAMA0,115200n8 ab3100.force=0,0x48 mtdparts=u300nand:128k@0x0(bootrecords)ro,8064k@128k(free)ro,253952k@8192k(platform) lpj=515072" +# CONFIG_XIP_KERNEL is not set +# CONFIG_KEXEC is not set + +# +# CPU Power Management +# +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +CONFIG_FPE_NWFPE=y +# CONFIG_FPE_NWFPE_XP is not set +# CONFIG_FPE_FASTFPE is not set +# CONFIG_VFP is not set + +# +# Userspace binary formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_HAVE_AOUT=y +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set + +# +# Power management options +# +CONFIG_PM=y +# CONFIG_PM_DEBUG is not set +# CONFIG_SUSPEND is not set +# CONFIG_APM_EMULATION is not set +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# 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 is not set +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER 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 is not set +# CONFIG_NET_DSA is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# 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_PHONET is not set +# CONFIG_NET_SCHED is not set +# CONFIG_DCB is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO 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_WIRELESS is not set +# CONFIG_WIMAX 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 is not set +CONFIG_FW_LOADER=y +CONFIG_FIRMWARE_IN_KERNEL=y +CONFIG_EXTRA_FIRMWARE="" +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# 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_TESTS is not set +# CONFIG_MTD_REDBOOT_PARTS is not set +CONFIG_MTD_CMDLINE_PARTS=y +# CONFIG_MTD_AFS_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_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_DATAFLASH is not set +# CONFIG_MTD_M25P80 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# 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 is not set +CONFIG_MTD_NAND_ECC_SMC=y +# CONFIG_MTD_NAND_MUSEUM_IDS is not set +# CONFIG_MTD_NAND_GPIO is not set +CONFIG_MTD_NAND_IDS=y +# CONFIG_MTD_NAND_DISKONCHIP is not set +# CONFIG_MTD_NAND_NANDSIM is not set +# CONFIG_MTD_NAND_PLATFORM is not set +# CONFIG_MTD_ONENAND is not set + +# +# LPDDR flash memory drivers +# +# CONFIG_MTD_LPDDR is not set + +# +# UBI - Unsorted block images +# +# CONFIG_MTD_UBI is not set +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# 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_RAM is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +CONFIG_MISC_DEVICES=y +# CONFIG_ICS932S401 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_ISL29003 is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_AT25 is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_93CX6 is not set +CONFIG_HAVE_IDE=y +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +# CONFIG_SCSI is not set +# CONFIG_SCSI_DMA is not set +# CONFIG_SCSI_NETLINK is not set +# CONFIG_ATA is not set +# CONFIG_MD is not set +# CONFIG_NETDEVICES is not set +# CONFIG_ISDN 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=y +# 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=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +CONFIG_DEVKMEM=y +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_AMBA_PL010 is not set +CONFIG_SERIAL_AMBA_PL011=y +CONFIG_SERIAL_AMBA_PL011_CONSOLE=y +# CONFIG_SERIAL_MAX3100 is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=16 +# CONFIG_IPMI_HANDLER is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +# CONFIG_I2C_CHARDEV is not set +CONFIG_I2C_HELPER_AUTO=y + +# +# I2C Hardware Bus support +# + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_GPIO is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_SIMTEC is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_TAOS_EVM is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_STUB is not set + +# +# Miscellaneous I2C Chip support +# +# CONFIG_DS1682 is not set +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_PCF8575 is not set +# CONFIG_SENSORS_PCA9539 is not set +# CONFIG_SENSORS_MAX6875 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_BITBANG is not set +# CONFIG_SPI_GPIO is not set + +# +# SPI Protocol Masters +# +# CONFIG_SPI_SPIDEV is not set +# CONFIG_SPI_TLE62X0 is not set +# CONFIG_W1 is not set +CONFIG_POWER_SUPPLY=y +# CONFIG_POWER_SUPPLY_DEBUG is not set +# CONFIG_PDA_POWER is not set +# CONFIG_BATTERY_DS2760 is not set +# CONFIG_BATTERY_BQ27x00 is not set +# CONFIG_HWMON is not set +# CONFIG_THERMAL is not set +# CONFIG_THERMAL_HWMON is not set +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +# CONFIG_SOFT_WATCHDOG is not set +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_T7L66XB is not set +# CONFIG_MFD_TC6387XB is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_PCF50633 is not set + +# +# Multimedia devices +# + +# +# Multimedia core support +# +# CONFIG_VIDEO_DEV is not set +# CONFIG_DVB_CORE is not set +# CONFIG_VIDEO_MEDIA is not set + +# +# Multimedia drivers +# +# CONFIG_DAB is not set + +# +# Graphics support +# +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +CONFIG_FB=y +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB_DDC is not set +# CONFIG_FB_BOOT_VESA_SUPPORT is not set +# CONFIG_FB_CFB_FILLRECT is not set +# CONFIG_FB_CFB_COPYAREA is not set +# CONFIG_FB_CFB_IMAGEBLIT is not set +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +# CONFIG_FB_SYS_FILLRECT is not set +# CONFIG_FB_SYS_COPYAREA is not set +# CONFIG_FB_SYS_IMAGEBLIT is not set +# CONFIG_FB_FOREIGN_ENDIAN is not set +# CONFIG_FB_SYS_FOPS is not set +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_BACKLIGHT is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_ARMCLCD is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_MB862XX is not set +# CONFIG_FB_BROADSHEET is not set +CONFIG_BACKLIGHT_LCD_SUPPORT=y +# CONFIG_LCD_CLASS_DEVICE is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_GENERIC=y + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE is not set +# CONFIG_LOGO is not set +CONFIG_SOUND=y +# CONFIG_SOUND_OSS_CORE is not set +CONFIG_SND=y +CONFIG_SND_TIMER=y +CONFIG_SND_PCM=y +CONFIG_SND_JACK=y +# CONFIG_SND_SEQUENCER is not set +# CONFIG_SND_MIXER_OSS is not set +# CONFIG_SND_PCM_OSS is not set +# CONFIG_SND_HRTIMER is not set +# CONFIG_SND_DYNAMIC_MINORS is not set +# CONFIG_SND_SUPPORT_OLD_API is not set +# CONFIG_SND_VERBOSE_PROCFS is not set +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set +# CONFIG_SND_DRIVERS is not set +# CONFIG_SND_ARM is not set +# CONFIG_SND_SPI is not set +CONFIG_SND_SOC=y +CONFIG_SND_SOC_I2C_AND_SPI=y +# CONFIG_SND_SOC_ALL_CODECS is not set +# CONFIG_SOUND_PRIME is not set +# CONFIG_HID_SUPPORT is not set +# CONFIG_USB_SUPPORT is not set +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set +# CONFIG_MMC_UNSAFE_RESUME is not set + +# +# MMC/SD/SDIO Card Drivers +# +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_BOUNCE=y +# CONFIG_SDIO_UART is not set +# CONFIG_MMC_TEST is not set + +# +# MMC/SD/SDIO Host Controller Drivers +# +CONFIG_MMC_ARMMMCI=y +# CONFIG_MMC_SDHCI is not set +# CONFIG_MMC_SPI is not set +# CONFIG_MEMSTICK is not set +# CONFIG_ACCESSIBILITY is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y + +# +# LED drivers +# +# CONFIG_LEDS_PCA9532 is not set +# CONFIG_LEDS_GPIO is not set +# CONFIG_LEDS_LP5521 is not set +# CONFIG_LEDS_PCA955X is not set +# CONFIG_LEDS_DAC124S085 is not set +# CONFIG_LEDS_BD2802 is not set + +# +# LED Triggers +# +CONFIG_LEDS_TRIGGERS=y +# CONFIG_LEDS_TRIGGER_TIMER is not set +# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set +CONFIG_LEDS_TRIGGER_BACKLIGHT=y +# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set + +# +# iptables trigger is under Netfilter config (LED target) +# +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8581 is not set + +# +# SPI RTC drivers +# +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_DS3234 is not set + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_V3020 is not set + +# +# on-CPU RTC drivers +# +# CONFIG_RTC_DRV_PL030 is not set +# CONFIG_RTC_DRV_PL031 is not set +CONFIG_DMADEVICES=y + +# +# DMA Devices +# +# CONFIG_AUXDISPLAY is not set +CONFIG_REGULATOR=y +# CONFIG_REGULATOR_DEBUG is not set +# CONFIG_REGULATOR_FIXED_VOLTAGE is not set +# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set +# CONFIG_REGULATOR_BQ24022 is not set +# CONFIG_UIO is not set +# CONFIG_STAGING is not set + +# +# File systems +# +# CONFIG_EXT2_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_EXT4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +CONFIG_FILE_LOCKING=y +# CONFIG_XFS_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_BTRFS_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=y + +# +# Caches +# +# CONFIG_FSCACHE is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +# CONFIG_MSDOS_FS is not set +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_HUGETLB_PAGE is not set +# CONFIG_CONFIGFS_FS is not set +CONFIG_MISC_FILESYSTEMS=y +# 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 is not set +# CONFIG_CRAMFS is not set +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_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_NILFS2_FS is not set +# CONFIG_NETWORK_FILESYSTEMS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +CONFIG_NLS_ISO8859_1=y +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set +# CONFIG_DLM is not set + +# +# Kernel hacking +# +CONFIG_PRINTK_TIME=y +CONFIG_ENABLE_WARN_DEPRECATED=y +CONFIG_ENABLE_MUST_CHECK=y +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=y +# CONFIG_DEBUG_SHIRQ is not set +# CONFIG_DETECT_SOFTLOCKUP is not set +# CONFIG_DETECT_HUNG_TASK is not set +# CONFIG_SCHED_DEBUG is not set +# CONFIG_SCHEDSTATS is not set +CONFIG_TIMER_STATS=y +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_SLUB_STATS is not set +# CONFIG_DEBUG_PREEMPT is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_KOBJECT is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_WRITECOUNT is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_BOOT_PRINTK_DELAY is not set +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_RCU_CPU_STALL_DETECTOR is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_LATENCYTOP is not set +# CONFIG_SYSCTL_SYSCALL_CHECK is not set +# CONFIG_PAGE_POISONING is not set +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_TRACING_SUPPORT=y + +# +# Tracers +# +# CONFIG_FUNCTION_TRACER is not set +# CONFIG_IRQSOFF_TRACER is not set +# CONFIG_PREEMPT_TRACER is not set +# CONFIG_SCHED_TRACER is not set +# CONFIG_CONTEXT_SWITCH_TRACER is not set +# CONFIG_EVENT_TRACER is not set +# CONFIG_BOOT_TRACER is not set +# CONFIG_TRACE_BRANCH_PROFILING is not set +# CONFIG_STACK_TRACER is not set +# CONFIG_KMEMTRACE is not set +# CONFIG_WORKQUEUE_TRACER is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +CONFIG_ARM_UNWIND=y +# CONFIG_DEBUG_USER is not set +# CONFIG_DEBUG_ERRORS is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_LL is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set +# CONFIG_SECURITYFS is not set +# CONFIG_SECURITY_FILE_CAPABILITIES is not set +# CONFIG_CRYPTO is not set +# CONFIG_BINARY_PRINTF is not set + +# +# Library routines +# +CONFIG_GENERIC_FIND_LAST_BIT=y +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set +# CONFIG_CRC_T10DIF is not set +# CONFIG_CRC_ITU_T is not set +# CONFIG_CRC32 is not set +# CONFIG_CRC7 is not set +# CONFIG_LIBCRC32C is not set +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y +CONFIG_NLATTR=y diff --git a/arch/arm/configs/w90p910_defconfig b/arch/arm/configs/w90p910_defconfig index 56bda7c6d670..5245655a0ad3 100644 --- a/arch/arm/configs/w90p910_defconfig +++ b/arch/arm/configs/w90p910_defconfig @@ -1,11 +1,11 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.27-rc8-git8 -# Sat Nov 15 10:05:00 2008 +# Linux kernel version: 2.6.30 +# Wed Jun 10 22:09:25 2009 # CONFIG_ARM=y CONFIG_SYS_SUPPORTS_APM_EMULATION=y -# CONFIG_GENERIC_GPIO is not set +CONFIG_GENERIC_GPIO=y # CONFIG_GENERIC_TIME is not set # CONFIG_GENERIC_CLOCKEVENTS is not set CONFIG_MMU=y @@ -22,8 +22,6 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_ARCH_HAS_ILOG2_U64 is not set CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_CALIBRATE_DELAY=y -CONFIG_ARCH_SUPPORTS_AOUT=y -CONFIG_ZONE_DMA=y CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y CONFIG_VECTORS_BASE=0xffff0000 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" @@ -42,10 +40,19 @@ CONFIG_SYSVIPC=y CONFIG_SYSVIPC_SYSCTL=y CONFIG_BSD_PROCESS_ACCT=y # CONFIG_BSD_PROCESS_ACCT_V3 is not set + +# +# RCU Subsystem +# +CONFIG_CLASSIC_RCU=y +# CONFIG_TREE_RCU is not set +# CONFIG_PREEMPT_RCU is not set +# CONFIG_TREE_RCU_TRACE is not set +# CONFIG_PREEMPT_RCU_TRACE is not set # CONFIG_IKCONFIG is not set CONFIG_LOG_BUF_SHIFT=17 -# CONFIG_CGROUPS is not set # CONFIG_GROUP_SCHED is not set +# CONFIG_CGROUPS is not set CONFIG_SYSFS_DEPRECATED=y CONFIG_SYSFS_DEPRECATED_V2=y CONFIG_RELAY=y @@ -56,52 +63,53 @@ CONFIG_USER_NS=y # CONFIG_PID_NS is not set CONFIG_BLK_DEV_INITRD=y CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +CONFIG_RD_BZIP2=y +CONFIG_RD_LZMA=y +# CONFIG_INITRAMFS_COMPRESSION_NONE is not set +# CONFIG_INITRAMFS_COMPRESSION_GZIP is not set +# CONFIG_INITRAMFS_COMPRESSION_BZIP2 is not set +# CONFIG_INITRAMFS_COMPRESSION_LZMA is not set CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y # CONFIG_EMBEDDED is not set CONFIG_UID16=y CONFIG_SYSCTL_SYSCALL=y CONFIG_KALLSYMS=y CONFIG_KALLSYMS_EXTRA_PASS=y +# CONFIG_STRIP_ASM_SYMS is not set CONFIG_HOTPLUG=y CONFIG_PRINTK=y CONFIG_BUG=y CONFIG_ELF_CORE=y -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_AIO=y CONFIG_VM_EVENT_COUNTERS=y +CONFIG_COMPAT_BRK=y CONFIG_SLAB=y # CONFIG_SLUB is not set # CONFIG_SLOB is not set # CONFIG_PROFILING is not set +CONFIG_TRACEPOINTS=y # CONFIG_MARKERS is not set CONFIG_HAVE_OPROFILE=y -# CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS is not set -# CONFIG_HAVE_IOREMAP_PROT is not set CONFIG_HAVE_KPROBES=y CONFIG_HAVE_KRETPROBES=y -# CONFIG_HAVE_ARCH_TRACEHOOK is not set -# CONFIG_HAVE_DMA_ATTRS is not set -# CONFIG_USE_GENERIC_SMP_HELPERS is not set -# CONFIG_HAVE_CLK is not set -CONFIG_PROC_PAGE_MONITOR=y +# CONFIG_SLOW_WORK is not set CONFIG_HAVE_GENERIC_DMA_COHERENT=y CONFIG_SLABINFO=y CONFIG_RT_MUTEXES=y -# CONFIG_TINY_SHMEM is not set CONFIG_BASE_SMALL=0 # CONFIG_MODULES is not set CONFIG_BLOCK=y CONFIG_LBD=y -CONFIG_BLK_DEV_IO_TRACE=y -CONFIG_LSF=y CONFIG_BLK_DEV_BSG=y # CONFIG_BLK_DEV_INTEGRITY is not set @@ -117,7 +125,7 @@ CONFIG_IOSCHED_CFQ=y CONFIG_DEFAULT_CFQ=y # CONFIG_DEFAULT_NOOP is not set CONFIG_DEFAULT_IOSCHED="cfq" -CONFIG_CLASSIC_RCU=y +# CONFIG_FREEZER is not set # # System Type @@ -127,10 +135,10 @@ CONFIG_CLASSIC_RCU=y # CONFIG_ARCH_REALVIEW is not set # CONFIG_ARCH_VERSATILE is not set # CONFIG_ARCH_AT91 is not set -# CONFIG_ARCH_CLPS7500 is not set # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_EBSA110 is not set # CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_GEMINI is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_NETX is not set # CONFIG_ARCH_H720X is not set @@ -151,23 +159,17 @@ CONFIG_CLASSIC_RCU=y # CONFIG_ARCH_ORION5X is not set # CONFIG_ARCH_PNX4008 is not set # CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_MMP is not set # CONFIG_ARCH_RPC is not set # CONFIG_ARCH_SA1100 is not set # CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_S3C64XX is not set # CONFIG_ARCH_SHARK is not set # CONFIG_ARCH_LH7A40X is not set # CONFIG_ARCH_DAVINCI is not set # CONFIG_ARCH_OMAP is not set -# CONFIG_ARCH_MSM7X00A is not set +# CONFIG_ARCH_MSM is not set CONFIG_ARCH_W90X900=y - -# -# Boot options -# - -# -# Power management -# CONFIG_CPU_W90P910=y # @@ -198,6 +200,7 @@ CONFIG_ARM_THUMB=y # CONFIG_CPU_DCACHE_WRITETHROUGH is not set # CONFIG_CPU_CACHE_ROUND_ROBIN is not set # CONFIG_OUTER_CACHE is not set +CONFIG_COMMON_CLKDEV=y # # Bus support @@ -209,27 +212,32 @@ CONFIG_ARM_THUMB=y # # Kernel Features # -# CONFIG_TICK_ONESHOT is not set +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_1G is not set +CONFIG_PAGE_OFFSET=0xC0000000 CONFIG_PREEMPT=y CONFIG_HZ=100 CONFIG_AEABI=y CONFIG_OABI_COMPAT=y -CONFIG_ARCH_FLATMEM_HAS_HOLES=y -# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set +# CONFIG_ARCH_HAS_HOLES_MEMORYMODEL is not set +# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set +# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set +# CONFIG_HIGHMEM is not set 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_PAGEFLAGS_EXTENDED=y CONFIG_SPLIT_PTLOCK_CPUS=4096 -# CONFIG_RESOURCES_64BIT is not set -CONFIG_ZONE_DMA_FLAG=1 -CONFIG_BOUNCE=y +# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 CONFIG_VIRT_TO_BUS=y +CONFIG_UNEVICTABLE_LRU=y +CONFIG_HAVE_MLOCK=y +CONFIG_HAVE_MLOCKED_PAGE_BIT=y CONFIG_ALIGNMENT_TRAP=y # @@ -237,11 +245,16 @@ CONFIG_ALIGNMENT_TRAP=y # CONFIG_ZBOOT_ROM_TEXT=0 CONFIG_ZBOOT_ROM_BSS=0 -CONFIG_CMDLINE="root=/dev/ram0 console=ttyS0,115200n8 initrd=0xa00000,4000000 mem=64M" +CONFIG_CMDLINE="root=/dev/ram0 console=ttyS0,115200n8 rdinit=/sbin/init mem=64M" # CONFIG_XIP_KERNEL is not set CONFIG_KEXEC=y CONFIG_ATAGS_PROC=y +# +# CPU Power Management +# +# CONFIG_CPU_IDLE is not set + # # Floating point emulation # @@ -258,6 +271,8 @@ CONFIG_FPE_NWFPE=y # Userspace binary formats # CONFIG_BINFMT_ELF=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_HAVE_AOUT=y # CONFIG_BINFMT_AOUT is not set # CONFIG_BINFMT_MISC is not set @@ -282,11 +297,93 @@ CONFIG_FW_LOADER=y CONFIG_FIRMWARE_IN_KERNEL=y CONFIG_EXTRA_FIRMWARE="" # CONFIG_SYS_HYPERVISOR is not set -# CONFIG_MTD is not set +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_CONCAT=y +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_REDBOOT_PARTS is not set +# CONFIG_MTD_CMDLINE_PARTS is not set +# CONFIG_MTD_AFS_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=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS 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_CFI_INTELEXT is not set +CONFIG_MTD_CFI_AMDSTD=y +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# 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_PHYSMAP=y +# CONFIG_MTD_PHYSMAP_COMPAT is not set +# CONFIG_MTD_ARM_INTEGRATOR is not set +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# 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 is not set +# CONFIG_MTD_ONENAND is not set + +# +# LPDDR flash memory drivers +# +# CONFIG_MTD_LPDDR is not set + +# +# UBI - Unsorted block images +# +# CONFIG_MTD_UBI is not set # CONFIG_PARPORT is not set CONFIG_BLK_DEV=y # CONFIG_BLK_DEV_COW_COMMON is not set # CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_UB is not set CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=16384 @@ -300,9 +397,41 @@ CONFIG_HAVE_IDE=y # SCSI device support # # CONFIG_RAID_ATTRS is not set -# CONFIG_SCSI is not set -# CONFIG_SCSI_DMA 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 is not set + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# 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 + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +# CONFIG_SCSI_LOWLEVEL is not set +# CONFIG_SCSI_DH is not set +# CONFIG_SCSI_OSD_INITIATOR is not set # CONFIG_ATA is not set # CONFIG_MD is not set @@ -354,38 +483,57 @@ CONFIG_HW_CONSOLE=y # # Serial drivers # -# CONFIG_SERIAL_8250 is not set +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=1 +CONFIG_SERIAL_8250_RUNTIME_UARTS=1 +# CONFIG_SERIAL_8250_EXTENDED is not set # # Non-8250 serial port support # -CONFIG_SERIAL_W90X900=y -# CONFIG_SERIAL_W90X900_PORT1 is not set -# CONFIG_SERIAL_W90X900_PORT2 is not set -# CONFIG_SERIAL_W90X900_PORT3 is not set -# CONFIG_SERIAL_W90X900_PORT4 is not set -CONFIG_SERIAL_W90X900_CONSOLE=y CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_UNIX98_PTYS=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set # CONFIG_LEGACY_PTYS is not set # CONFIG_IPMI_HANDLER is not set # CONFIG_HW_RANDOM is not set -# CONFIG_NVRAM is not set # CONFIG_R3964 is not set # CONFIG_RAW_DRIVER is not set # CONFIG_TCG_TPM is not set # CONFIG_I2C is not set # CONFIG_SPI is not set +CONFIG_ARCH_REQUIRE_GPIOLIB=y +CONFIG_GPIOLIB=y +# CONFIG_GPIO_SYSFS is not set + +# +# Memory mapped GPIO expanders: +# + +# +# I2C GPIO expanders: +# + +# +# PCI GPIO expanders: +# + +# +# SPI GPIO expanders: +# # CONFIG_W1 is not set # CONFIG_POWER_SUPPLY is not set # CONFIG_HWMON is not set +# CONFIG_THERMAL is not set +# CONFIG_THERMAL_HWMON is not set # CONFIG_WATCHDOG is not set +CONFIG_SSB_POSSIBLE=y # # Sonics Silicon Backplane # -CONFIG_SSB_POSSIBLE=y # CONFIG_SSB is not set # @@ -393,10 +541,11 @@ CONFIG_SSB_POSSIBLE=y # # CONFIG_MFD_CORE is not set # CONFIG_MFD_SM501 is not set +# CONFIG_MFD_ASIC3 is not set +# CONFIG_HTC_EGPIO is not set # CONFIG_HTC_PASIC3 is not set # CONFIG_MFD_TMIO is not set -# CONFIG_MFD_T7L66XB is not set -# CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_TC6393XB is not set # # Multimedia devices @@ -433,33 +582,131 @@ CONFIG_SSB_POSSIBLE=y CONFIG_DUMMY_CONSOLE=y # CONFIG_SOUND is not set # CONFIG_HID_SUPPORT is not set -# CONFIG_USB_SUPPORT is not set +CONFIG_USB_SUPPORT=y +CONFIG_USB_ARCH_HAS_HCD=y +# CONFIG_USB_ARCH_HAS_OHCI is not set +# CONFIG_USB_ARCH_HAS_EHCI is not set +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set +# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set + +# +# Miscellaneous USB options +# +# CONFIG_USB_DEVICEFS is not set +CONFIG_USB_DEVICE_CLASS=y +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG is not set +CONFIG_USB_MON=y +# CONFIG_USB_WUSB is not set +# CONFIG_USB_WUSB_CBAF is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_ISP1760_HCD is not set +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_HWA_HCD is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_WDM is not set +# CONFIG_USB_TMC is not set + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# + +# +# also be needed; see USB_STORAGE Help for more info +# +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_ONETOUCH is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set +# CONFIG_USB_LIBUSUAL is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set + +# +# USB port drivers +# +# CONFIG_USB_SERIAL is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_BERRY_CHARGE is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_VST is not set +# CONFIG_USB_GADGET is not set + +# +# OTG and related infrastructure +# +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_NOP_USB_XCEIV is not set # CONFIG_MMC is not set +# CONFIG_MEMSTICK is not set +# CONFIG_ACCESSIBILITY is not set # CONFIG_NEW_LEDS is not set CONFIG_RTC_LIB=y # CONFIG_RTC_CLASS is not set # CONFIG_DMADEVICES is not set - -# -# Voltage and Current regulators -# +# CONFIG_AUXDISPLAY is not set # CONFIG_REGULATOR is not set -# CONFIG_REGULATOR_FIXED_VOLTAGE is not set -# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set -# CONFIG_REGULATOR_BQ24022 is not set # CONFIG_UIO is not set +# CONFIG_STAGING is not set # # File systems # # CONFIG_EXT2_FS is not set # CONFIG_EXT3_FS is not set -# CONFIG_EXT4DEV_FS is not set +# CONFIG_EXT4_FS is not set # CONFIG_REISERFS_FS is not set # CONFIG_JFS_FS is not set CONFIG_FS_POSIX_ACL=y +CONFIG_FILE_LOCKING=y # CONFIG_XFS_FS is not set # CONFIG_GFS2_FS is not set +# CONFIG_BTRFS_FS is not set # CONFIG_DNOTIFY is not set # CONFIG_INOTIFY is not set # CONFIG_QUOTA is not set @@ -468,6 +715,11 @@ CONFIG_FS_POSIX_ACL=y # CONFIG_FUSE_FS is not set CONFIG_GENERIC_ACL=y +# +# Caches +# +# CONFIG_FSCACHE is not set + # # CD-ROM/DVD Filesystems # @@ -486,15 +738,13 @@ CONFIG_GENERIC_ACL=y # CONFIG_PROC_FS=y CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y CONFIG_SYSFS=y CONFIG_TMPFS=y CONFIG_TMPFS_POSIX_ACL=y # CONFIG_HUGETLB_PAGE is not set # CONFIG_CONFIGFS_FS is not set - -# -# Miscellaneous filesystems -# +CONFIG_MISC_FILESYSTEMS=y # CONFIG_ADFS_FS is not set # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set @@ -502,15 +752,22 @@ CONFIG_TMPFS_POSIX_ACL=y # CONFIG_BEFS_FS is not set # CONFIG_BFS_FS is not set # CONFIG_EFS_FS is not set +# CONFIG_JFFS2_FS is not set # CONFIG_CRAMFS is not set +# CONFIG_SQUASHFS is not set # CONFIG_VXFS_FS is not set # CONFIG_MINIX_FS is not set # CONFIG_OMFS_FS is not set # CONFIG_HPFS_FS is not set # CONFIG_QNX4FS_FS is not set CONFIG_ROMFS_FS=y +CONFIG_ROMFS_BACKED_BY_BLOCK=y +# CONFIG_ROMFS_BACKED_BY_MTD is not set +# CONFIG_ROMFS_BACKED_BY_BOTH is not set +CONFIG_ROMFS_ON_BLOCK=y # CONFIG_SYSV_FS is not set # CONFIG_UFS_FS is not set +# CONFIG_NILFS2_FS is not set # # Partition Types @@ -586,18 +843,36 @@ CONFIG_FRAME_WARN=1024 CONFIG_DEBUG_FS=y # CONFIG_HEADERS_CHECK is not set # CONFIG_DEBUG_KERNEL is not set +CONFIG_STACKTRACE=y CONFIG_DEBUG_BUGVERBOSE=y CONFIG_DEBUG_MEMORY_INIT=y -CONFIG_FRAME_POINTER=y +# CONFIG_RCU_CPU_STALL_DETECTOR is not set # CONFIG_LATENCYTOP is not set # CONFIG_SYSCTL_SYSCALL_CHECK is not set -CONFIG_HAVE_FTRACE=y -CONFIG_HAVE_DYNAMIC_FTRACE=y -# CONFIG_FTRACE is not set +CONFIG_NOP_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_RING_BUFFER=y +CONFIG_TRACING=y +CONFIG_TRACING_SUPPORT=y + +# +# Tracers +# +# CONFIG_FUNCTION_TRACER is not set # CONFIG_SCHED_TRACER is not set # CONFIG_CONTEXT_SWITCH_TRACER is not set +# CONFIG_EVENT_TRACER is not set +# CONFIG_BOOT_TRACER is not set +# CONFIG_TRACE_BRANCH_PROFILING is not set +# CONFIG_STACK_TRACER is not set +# CONFIG_KMEMTRACE is not set +# CONFIG_WORKQUEUE_TRACER is not set +CONFIG_BLK_DEV_IO_TRACE=y +# CONFIG_FTRACE_STARTUP_TEST is not set +# CONFIG_DYNAMIC_DEBUG is not set # CONFIG_SAMPLES is not set CONFIG_HAVE_ARCH_KGDB=y +CONFIG_ARM_UNWIND=y # CONFIG_DEBUG_USER is not set # @@ -605,14 +880,15 @@ CONFIG_HAVE_ARCH_KGDB=y # # CONFIG_KEYS is not set # CONFIG_SECURITY is not set +# CONFIG_SECURITYFS is not set # CONFIG_SECURITY_FILE_CAPABILITIES is not set # CONFIG_CRYPTO is not set +CONFIG_BINARY_PRINTF=y # # Library routines # -# CONFIG_GENERIC_FIND_FIRST_BIT is not set -# CONFIG_GENERIC_FIND_NEXT_BIT is not set +CONFIG_GENERIC_FIND_LAST_BIT=y # CONFIG_CRC_CCITT is not set # CONFIG_CRC16 is not set # CONFIG_CRC_T10DIF is not set @@ -620,7 +896,10 @@ CONFIG_HAVE_ARCH_KGDB=y # CONFIG_CRC32 is not set # CONFIG_CRC7 is not set # CONFIG_LIBCRC32C is not set -CONFIG_PLIST=y +CONFIG_ZLIB_INFLATE=y +CONFIG_DECOMPRESS_GZIP=y +CONFIG_DECOMPRESS_BZIP2=y +CONFIG_DECOMPRESS_LZMA=y CONFIG_HAS_IOMEM=y CONFIG_HAS_IOPORT=y CONFIG_HAS_DMA=y diff --git a/arch/arm/include/asm/atomic.h b/arch/arm/include/asm/atomic.h index 16b52f397983..9e07fe507029 100644 --- a/arch/arm/include/asm/atomic.h +++ b/arch/arm/include/asm/atomic.h @@ -249,6 +249,6 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u) #define smp_mb__before_atomic_inc() smp_mb() #define smp_mb__after_atomic_inc() smp_mb() -#include +#include #endif #endif diff --git a/arch/arm/include/asm/bitsperlong.h b/arch/arm/include/asm/bitsperlong.h new file mode 100644 index 000000000000..6dc0bb0c13b2 --- /dev/null +++ b/arch/arm/include/asm/bitsperlong.h @@ -0,0 +1 @@ +#include diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h index bb7d695f3900..1a711ea8418b 100644 --- a/arch/arm/include/asm/cacheflush.h +++ b/arch/arm/include/asm/cacheflush.h @@ -429,6 +429,14 @@ static inline void flush_anon_page(struct vm_area_struct *vma, __flush_anon_page(vma, page, vmaddr); } +#define ARCH_HAS_FLUSH_KERNEL_DCACHE_PAGE +static inline void flush_kernel_dcache_page(struct page *page) +{ + /* highmem pages are always flushed upon kunmap already */ + if ((cache_is_vivt() || cache_is_vipt_aliasing()) && !PageHighMem(page)) + __cpuc_flush_dcache_page(page_address(page)); +} + #define flush_dcache_mmap_lock(mapping) \ spin_lock_irq(&(mapping)->tree_lock) #define flush_dcache_mmap_unlock(mapping) \ diff --git a/arch/arm/include/asm/cputype.h b/arch/arm/include/asm/cputype.h index 7b9d27e749b8..b3e656c6fb78 100644 --- a/arch/arm/include/asm/cputype.h +++ b/arch/arm/include/asm/cputype.h @@ -8,6 +8,21 @@ #define CPUID_TCM 2 #define CPUID_TLBTYPE 3 +#define CPUID_EXT_PFR0 "c1, 0" +#define CPUID_EXT_PFR1 "c1, 1" +#define CPUID_EXT_DFR0 "c1, 2" +#define CPUID_EXT_AFR0 "c1, 3" +#define CPUID_EXT_MMFR0 "c1, 4" +#define CPUID_EXT_MMFR1 "c1, 5" +#define CPUID_EXT_MMFR2 "c1, 6" +#define CPUID_EXT_MMFR3 "c1, 7" +#define CPUID_EXT_ISAR0 "c2, 0" +#define CPUID_EXT_ISAR1 "c2, 1" +#define CPUID_EXT_ISAR2 "c2, 2" +#define CPUID_EXT_ISAR3 "c2, 3" +#define CPUID_EXT_ISAR4 "c2, 4" +#define CPUID_EXT_ISAR5 "c2, 5" + #ifdef CONFIG_CPU_CP15 #define read_cpuid(reg) \ ({ \ @@ -18,9 +33,19 @@ : "cc"); \ __val; \ }) +#define read_cpuid_ext(ext_reg) \ + ({ \ + unsigned int __val; \ + asm("mrc p15, 0, %0, c0, " ext_reg \ + : "=r" (__val) \ + : \ + : "cc"); \ + __val; \ + }) #else extern unsigned int processor_id; #define read_cpuid(reg) (processor_id) +#define read_cpuid_ext(reg) 0 #endif /* diff --git a/arch/arm/include/asm/hardware/arm_twd.h b/arch/arm/include/asm/hardware/arm_twd.h deleted file mode 100644 index e521b70713c8..000000000000 --- a/arch/arm/include/asm/hardware/arm_twd.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef __ASM_HARDWARE_TWD_H -#define __ASM_HARDWARE_TWD_H - -#define TWD_TIMER_LOAD 0x00 -#define TWD_TIMER_COUNTER 0x04 -#define TWD_TIMER_CONTROL 0x08 -#define TWD_TIMER_INTSTAT 0x0C - -#define TWD_WDOG_LOAD 0x20 -#define TWD_WDOG_COUNTER 0x24 -#define TWD_WDOG_CONTROL 0x28 -#define TWD_WDOG_INTSTAT 0x2C -#define TWD_WDOG_RESETSTAT 0x30 -#define TWD_WDOG_DISABLE 0x34 - -#define TWD_TIMER_CONTROL_ENABLE (1 << 0) -#define TWD_TIMER_CONTROL_ONESHOT (0 << 1) -#define TWD_TIMER_CONTROL_PERIODIC (1 << 1) -#define TWD_TIMER_CONTROL_IT_ENABLE (1 << 2) - -#endif diff --git a/arch/arm/include/asm/hardware/cache-l2x0.h b/arch/arm/include/asm/hardware/cache-l2x0.h index 64f2252a25cd..cdb9022716fd 100644 --- a/arch/arm/include/asm/hardware/cache-l2x0.h +++ b/arch/arm/include/asm/hardware/cache-l2x0.h @@ -24,6 +24,8 @@ #define L2X0_CACHE_TYPE 0x004 #define L2X0_CTRL 0x100 #define L2X0_AUX_CTRL 0x104 +#define L2X0_TAG_LATENCY_CTRL 0x108 +#define L2X0_DATA_LATENCY_CTRL 0x10C #define L2X0_EVENT_CNT_CTRL 0x200 #define L2X0_EVENT_CNT1_CFG 0x204 #define L2X0_EVENT_CNT0_CFG 0x208 diff --git a/arch/arm/include/asm/hardware/iop_adma.h b/arch/arm/include/asm/hardware/iop_adma.h index bbe8a0475cad..59b8c3892f76 100644 --- a/arch/arm/include/asm/hardware/iop_adma.h +++ b/arch/arm/include/asm/hardware/iop_adma.h @@ -86,6 +86,7 @@ struct iop_adma_chan { * @idx: pool index * @unmap_src_cnt: number of xor sources * @unmap_len: transaction bytecount + * @tx_list: list of descriptors that are associated with one operation * @async_tx: support for the async_tx api * @group_list: list of slots that make up a multi-descriptor transaction * for example transfer lengths larger than the supported hw max @@ -102,6 +103,7 @@ struct iop_adma_desc_slot { u16 idx; u16 unmap_src_cnt; size_t unmap_len; + struct list_head tx_list; struct dma_async_tx_descriptor async_tx; union { u32 *xor_check_result; diff --git a/arch/arm/include/asm/hardware/pl080.h b/arch/arm/include/asm/hardware/pl080.h new file mode 100644 index 000000000000..6a6c66be7f65 --- /dev/null +++ b/arch/arm/include/asm/hardware/pl080.h @@ -0,0 +1,138 @@ +/* arch/arm/include/asm/hardware/pl080.h + * + * Copyright 2008 Openmoko, Inc. + * Copyright 2008 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Ben Dooks + * + * ARM PrimeCell PL080 DMA controller + * + * 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. +*/ + +/* Note, there are some Samsung updates to this controller block which + * make it not entierly compatible with the PL080 specification from + * ARM. When in doubt, check the Samsung documentation first. + * + * The Samsung defines are PL080S, and add an extra controll register, + * the ability to move more than 2^11 counts of data and some extra + * OneNAND features. +*/ + +#define PL080_INT_STATUS (0x00) +#define PL080_TC_STATUS (0x04) +#define PL080_TC_CLEAR (0x08) +#define PL080_ERR_STATUS (0x0C) +#define PL080_ERR_CLEAR (0x10) +#define PL080_RAW_TC_STATUS (0x14) +#define PL080_RAW_ERR_STATUS (0x18) +#define PL080_EN_CHAN (0x1c) +#define PL080_SOFT_BREQ (0x20) +#define PL080_SOFT_SREQ (0x24) +#define PL080_SOFT_LBREQ (0x28) +#define PL080_SOFT_LSREQ (0x2C) + +#define PL080_CONFIG (0x30) +#define PL080_CONFIG_M2_BE (1 << 2) +#define PL080_CONFIG_M1_BE (1 << 1) +#define PL080_CONFIG_ENABLE (1 << 0) + +#define PL080_SYNC (0x34) + +/* Per channel configuration registers */ + +#define PL008_Cx_STRIDE (0x20) +#define PL080_Cx_BASE(x) ((0x100 + (x * 0x20))) +#define PL080_Cx_SRC_ADDR(x) ((0x100 + (x * 0x20))) +#define PL080_Cx_DST_ADDR(x) ((0x104 + (x * 0x20))) +#define PL080_Cx_LLI(x) ((0x108 + (x * 0x20))) +#define PL080_Cx_CONTROL(x) ((0x10C + (x * 0x20))) +#define PL080_Cx_CONFIG(x) ((0x110 + (x * 0x20))) +#define PL080S_Cx_CONTROL2(x) ((0x110 + (x * 0x20))) +#define PL080S_Cx_CONFIG(x) ((0x114 + (x * 0x20))) + +#define PL080_CH_SRC_ADDR (0x00) +#define PL080_CH_DST_ADDR (0x04) +#define PL080_CH_LLI (0x08) +#define PL080_CH_CONTROL (0x0C) +#define PL080_CH_CONFIG (0x10) +#define PL080S_CH_CONTROL2 (0x10) +#define PL080S_CH_CONFIG (0x14) + +#define PL080_LLI_ADDR_MASK (0x3fffffff << 2) +#define PL080_LLI_ADDR_SHIFT (2) +#define PL080_LLI_LM_AHB2 (1 << 0) + +#define PL080_CONTROL_TC_IRQ_EN (1 << 31) +#define PL080_CONTROL_PROT_MASK (0x7 << 28) +#define PL080_CONTROL_PROT_SHIFT (28) +#define PL080_CONTROL_PROT_SYS (1 << 28) +#define PL080_CONTROL_DST_INCR (1 << 27) +#define PL080_CONTROL_SRC_INCR (1 << 26) +#define PL080_CONTROL_DST_AHB2 (1 << 25) +#define PL080_CONTROL_SRC_AHB2 (1 << 24) +#define PL080_CONTROL_DWIDTH_MASK (0x7 << 21) +#define PL080_CONTROL_DWIDTH_SHIFT (21) +#define PL080_CONTROL_SWIDTH_MASK (0x7 << 18) +#define PL080_CONTROL_SWIDTH_SHIFT (18) +#define PL080_CONTROL_DB_SIZE_MASK (0x7 << 15) +#define PL080_CONTROL_DB_SIZE_SHIFT (15) +#define PL080_CONTROL_SB_SIZE_MASK (0x7 << 12) +#define PL080_CONTROL_SB_SIZE_SHIFT (12) +#define PL080_CONTROL_TRANSFER_SIZE_MASK (0xfff << 0) +#define PL080_CONTROL_TRANSFER_SIZE_SHIFT (0) + +#define PL080_BSIZE_1 (0x0) +#define PL080_BSIZE_4 (0x1) +#define PL080_BSIZE_8 (0x2) +#define PL080_BSIZE_16 (0x3) +#define PL080_BSIZE_32 (0x4) +#define PL080_BSIZE_64 (0x5) +#define PL080_BSIZE_128 (0x6) +#define PL080_BSIZE_256 (0x7) + +#define PL080_WIDTH_8BIT (0x0) +#define PL080_WIDTH_16BIT (0x1) +#define PL080_WIDTH_32BIT (0x2) + +#define PL080_CONFIG_HALT (1 << 18) +#define PL080_CONFIG_ACTIVE (1 << 17) /* RO */ +#define PL080_CONFIG_LOCK (1 << 16) +#define PL080_CONFIG_TC_IRQ_MASK (1 << 15) +#define PL080_CONFIG_ERR_IRQ_MASK (1 << 14) +#define PL080_CONFIG_FLOW_CONTROL_MASK (0x7 << 11) +#define PL080_CONFIG_FLOW_CONTROL_SHIFT (11) +#define PL080_CONFIG_DST_SEL_MASK (0xf << 6) +#define PL080_CONFIG_DST_SEL_SHIFT (6) +#define PL080_CONFIG_SRC_SEL_MASK (0xf << 1) +#define PL080_CONFIG_SRC_SEL_SHIFT (1) +#define PL080_CONFIG_ENABLE (1 << 0) + +#define PL080_FLOW_MEM2MEM (0x0) +#define PL080_FLOW_MEM2PER (0x1) +#define PL080_FLOW_PER2MEM (0x2) +#define PL080_FLOW_SRC2DST (0x3) +#define PL080_FLOW_SRC2DST_DST (0x4) +#define PL080_FLOW_MEM2PER_PER (0x5) +#define PL080_FLOW_PER2MEM_PER (0x6) +#define PL080_FLOW_SRC2DST_SRC (0x7) + +/* DMA linked list chain structure */ + +struct pl080_lli { + u32 src_addr; + u32 dst_addr; + u32 next_lli; + u32 control0; +}; + +struct pl080s_lli { + u32 src_addr; + u32 dst_addr; + u32 next_lli; + u32 control0; + u32 control1; +}; + diff --git a/arch/arm/include/asm/hardware/vic.h b/arch/arm/include/asm/hardware/vic.h index f87328d4a180..5d72550a8097 100644 --- a/arch/arm/include/asm/hardware/vic.h +++ b/arch/arm/include/asm/hardware/vic.h @@ -41,7 +41,7 @@ #define VIC_PL192_VECT_ADDR 0xF00 #ifndef __ASSEMBLY__ -void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources); +void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, u32 resume_sources); #endif #endif diff --git a/arch/arm/include/asm/localtimer.h b/arch/arm/include/asm/localtimer.h new file mode 100644 index 000000000000..50c7e7cfd670 --- /dev/null +++ b/arch/arm/include/asm/localtimer.h @@ -0,0 +1,63 @@ +/* + * arch/arm/include/asm/localtimer.h + * + * Copyright (C) 2004-2005 ARM Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_ARM_LOCALTIMER_H +#define __ASM_ARM_LOCALTIMER_H + +struct clock_event_device; + +/* + * Setup a per-cpu timer, whether it be a local timer or dummy broadcast + */ +void percpu_timer_setup(void); + +/* + * Called from assembly, this is the local timer IRQ handler + */ +asmlinkage void do_local_timer(struct pt_regs *); + + +#ifdef CONFIG_LOCAL_TIMERS + +#ifdef CONFIG_HAVE_ARM_TWD + +#include "smp_twd.h" + +#define local_timer_ack() twd_timer_ack() +#define local_timer_stop() twd_timer_stop() + +#else + +/* + * Platform provides this to acknowledge a local timer IRQ. + * Returns true if the local timer IRQ is to be processed. + */ +int local_timer_ack(void); + +/* + * Stop a local timer interrupt. + */ +void local_timer_stop(void); + +#endif + +/* + * Setup a local timer interrupt for a CPU. + */ +void local_timer_setup(struct clock_event_device *); + +#else + +static inline void local_timer_stop(void) +{ +} + +#endif + +#endif diff --git a/arch/arm/include/asm/mach/map.h b/arch/arm/include/asm/mach/map.h index 58cf91f38e6f..742c2aaeb020 100644 --- a/arch/arm/include/asm/mach/map.h +++ b/arch/arm/include/asm/mach/map.h @@ -30,6 +30,14 @@ struct map_desc { #ifdef CONFIG_MMU extern void iotable_init(struct map_desc *, int); + +struct mem_type; +extern const struct mem_type *get_mem_type(unsigned int type); +/* + * external interface to remap single page with appropriate type + */ +extern int ioremap_page(unsigned long virt, unsigned long phys, + const struct mem_type *mtype); #else #define iotable_init(map,num) do { } while (0) #endif diff --git a/arch/arm/include/asm/mman.h b/arch/arm/include/asm/mman.h index 54570d2e95b7..fc26976d8e3a 100644 --- a/arch/arm/include/asm/mman.h +++ b/arch/arm/include/asm/mman.h @@ -1,7 +1,7 @@ #ifndef __ARM_MMAN_H__ #define __ARM_MMAN_H__ -#include +#include #define MAP_GROWSDOWN 0x0100 /* stack-like segment */ #define MAP_DENYWRITE 0x0800 /* ETXTBSY */ diff --git a/arch/arm/include/asm/page.h b/arch/arm/include/asm/page.h index 7b522770f29d..be962c1349c4 100644 --- a/arch/arm/include/asm/page.h +++ b/arch/arm/include/asm/page.h @@ -202,6 +202,6 @@ typedef struct page *pgtable_t; (((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0) | \ VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) -#include +#include #endif diff --git a/arch/arm/include/asm/pci.h b/arch/arm/include/asm/pci.h index 918d0cbbf064..0abf386ba3d3 100644 --- a/arch/arm/include/asm/pci.h +++ b/arch/arm/include/asm/pci.h @@ -65,19 +65,6 @@ extern void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res, struct pci_bus_region *region); -static inline struct resource * -pcibios_select_root(struct pci_dev *pdev, struct resource *res) -{ - struct resource *root = NULL; - - if (res->flags & IORESOURCE_IO) - root = &ioport_resource; - if (res->flags & IORESOURCE_MEM) - root = &iomem_resource; - - return root; -} - /* * Dummy implementation; always return 0. */ diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h index 110295c5461d..1cd2d6416bda 100644 --- a/arch/arm/include/asm/pgtable.h +++ b/arch/arm/include/asm/pgtable.h @@ -342,7 +342,7 @@ static inline pte_t *pmd_page_vaddr(pmd_t pmd) return __va(ptr); } -#define pmd_page(pmd) virt_to_page(__va(pmd_val(pmd))) +#define pmd_page(pmd) pfn_to_page(__phys_to_pfn(pmd_val(pmd))) /* * Conversion functions: convert a page and protection to a page entry, diff --git a/arch/arm/include/asm/processor.h b/arch/arm/include/asm/processor.h index 1845892260e7..6a89567ffc5b 100644 --- a/arch/arm/include/asm/processor.h +++ b/arch/arm/include/asm/processor.h @@ -71,6 +71,7 @@ struct thread_struct { regs->ARM_cpsr = USR26_MODE; \ if (elf_hwcap & HWCAP_THUMB && pc & 1) \ regs->ARM_cpsr |= PSR_T_BIT; \ + regs->ARM_cpsr |= PSR_ENDSTATE; \ regs->ARM_pc = pc & ~1; /* pc */ \ regs->ARM_sp = sp; /* sp */ \ regs->ARM_r2 = stack[2]; /* r2 (envp) */ \ diff --git a/arch/arm/include/asm/ptrace.h b/arch/arm/include/asm/ptrace.h index 236a06b9b7ce..67b833c9b6b9 100644 --- a/arch/arm/include/asm/ptrace.h +++ b/arch/arm/include/asm/ptrace.h @@ -50,6 +50,7 @@ #define PSR_F_BIT 0x00000040 #define PSR_I_BIT 0x00000080 #define PSR_A_BIT 0x00000100 +#define PSR_E_BIT 0x00000200 #define PSR_J_BIT 0x01000000 #define PSR_Q_BIT 0x08000000 #define PSR_V_BIT 0x10000000 @@ -65,6 +66,22 @@ #define PSR_x 0x0000ff00 /* Extension */ #define PSR_c 0x000000ff /* Control */ +/* + * ARMv7 groups of APSR bits + */ +#define PSR_ISET_MASK 0x01000010 /* ISA state (J, T) mask */ +#define PSR_IT_MASK 0x0600fc00 /* If-Then execution state mask */ +#define PSR_ENDIAN_MASK 0x00000200 /* Endianness state mask */ + +/* + * Default endianness state + */ +#ifdef CONFIG_CPU_ENDIAN_BE8 +#define PSR_ENDSTATE PSR_E_BIT +#else +#define PSR_ENDSTATE 0 +#endif + #ifndef __ASSEMBLY__ /* diff --git a/arch/arm/include/asm/signal.h b/arch/arm/include/asm/signal.h index d0fb487aba4f..43ba0fb1c8ad 100644 --- a/arch/arm/include/asm/signal.h +++ b/arch/arm/include/asm/signal.h @@ -111,7 +111,7 @@ typedef unsigned long sigset_t; #define MINSIGSTKSZ 2048 #define SIGSTKSZ 8192 -#include +#include #ifdef __KERNEL__ struct old_sigaction { diff --git a/arch/arm/include/asm/sizes.h b/arch/arm/include/asm/sizes.h index ada93a8fc2ef..4fc1565e4f93 100644 --- a/arch/arm/include/asm/sizes.h +++ b/arch/arm/include/asm/sizes.h @@ -29,6 +29,7 @@ #define SZ_512 0x00000200 #define SZ_1K 0x00000400 +#define SZ_2K 0x00000800 #define SZ_4K 0x00001000 #define SZ_8K 0x00002000 #define SZ_16K 0x00004000 diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h index 5995935338e1..a06e735b262a 100644 --- a/arch/arm/include/asm/smp.h +++ b/arch/arm/include/asm/smp.h @@ -41,7 +41,7 @@ extern void show_ipi_list(struct seq_file *p); asmlinkage void do_IPI(struct pt_regs *regs); /* - * Setup the SMP cpu_possible_map + * Setup the set of possible CPUs (via set_cpu_possible) */ extern void smp_init_cpus(void); @@ -55,11 +55,6 @@ extern void smp_store_cpu_info(unsigned int cpuid); */ extern void smp_cross_call(const struct cpumask *mask); -/* - * Broadcast a clock event to other CPUs. - */ -extern void smp_timer_broadcast(const struct cpumask *mask); - /* * Boot a secondary CPU, and assign it the specified idle task. * This also gives us the initial stack to use for this CPU. @@ -100,44 +95,9 @@ extern void arch_send_call_function_single_ipi(int cpu); extern void arch_send_call_function_ipi_mask(const struct cpumask *mask); #define arch_send_call_function_ipi_mask arch_send_call_function_ipi_mask -/* - * Local timer interrupt handling function (can be IPI'ed). - */ -extern void local_timer_interrupt(void); - -#ifdef CONFIG_LOCAL_TIMERS - -/* - * Stop a local timer interrupt. - */ -extern void local_timer_stop(void); - -/* - * Platform provides this to acknowledge a local timer IRQ - */ -extern int local_timer_ack(void); - -#else - -static inline void local_timer_stop(void) -{ -} - -#endif - -/* - * Setup a local timer interrupt for a CPU. - */ -extern void local_timer_setup(void); - /* * show local interrupt info */ extern void show_local_irqs(struct seq_file *); -/* - * Called from assembly, this is the local timer IRQ handler - */ -asmlinkage void do_local_timer(struct pt_regs *); - #endif /* ifndef __ASM_ARM_SMP_H */ diff --git a/arch/arm/include/asm/smp_scu.h b/arch/arm/include/asm/smp_scu.h new file mode 100644 index 000000000000..2376835015d6 --- /dev/null +++ b/arch/arm/include/asm/smp_scu.h @@ -0,0 +1,7 @@ +#ifndef __ASMARM_ARCH_SCU_H +#define __ASMARM_ARCH_SCU_H + +unsigned int scu_get_core_count(void __iomem *); +void scu_enable(void __iomem *); + +#endif diff --git a/arch/arm/include/asm/smp_twd.h b/arch/arm/include/asm/smp_twd.h new file mode 100644 index 000000000000..7be0978b2625 --- /dev/null +++ b/arch/arm/include/asm/smp_twd.h @@ -0,0 +1,12 @@ +#ifndef __ASMARM_SMP_TWD_H +#define __ASMARM_SMP_TWD_H + +struct clock_event_device; + +extern void __iomem *twd_base; + +void twd_timer_stop(void); +int twd_timer_ack(void); +void twd_timer_setup(struct clock_event_device *); + +#endif diff --git a/arch/arm/include/asm/suspend.h b/arch/arm/include/asm/suspend.h deleted file mode 100644 index cf0d0bdee74d..000000000000 --- a/arch/arm/include/asm/suspend.h +++ /dev/null @@ -1,4 +0,0 @@ -#ifndef _ASMARM_SUSPEND_H -#define _ASMARM_SUSPEND_H - -#endif diff --git a/arch/arm/include/asm/tlbflush.h b/arch/arm/include/asm/tlbflush.h index a62218013c78..c964f3fc3bc5 100644 --- a/arch/arm/include/asm/tlbflush.h +++ b/arch/arm/include/asm/tlbflush.h @@ -40,6 +40,12 @@ #define TLB_V6_I_ASID (1 << 18) #define TLB_BTB (1 << 28) + +/* Unified Inner Shareable TLB operations (ARMv7 MP extensions) */ +#define TLB_V7_UIS_PAGE (1 << 19) +#define TLB_V7_UIS_FULL (1 << 20) +#define TLB_V7_UIS_ASID (1 << 21) + #define TLB_L2CLEAN_FR (1 << 29) /* Feroceon */ #define TLB_DCLEAN (1 << 30) #define TLB_WB (1 << 31) @@ -176,9 +182,17 @@ # define v6wbi_always_flags (-1UL) #endif +#ifdef CONFIG_SMP +#define v7wbi_tlb_flags (TLB_WB | TLB_DCLEAN | TLB_BTB | \ + TLB_V7_UIS_FULL | TLB_V7_UIS_PAGE | TLB_V7_UIS_ASID) +#else +#define v7wbi_tlb_flags (TLB_WB | TLB_DCLEAN | TLB_BTB | \ + TLB_V6_U_FULL | TLB_V6_U_PAGE | TLB_V6_U_ASID) +#endif + #ifdef CONFIG_CPU_TLB_V7 -# define v7wbi_possible_flags v6wbi_tlb_flags -# define v7wbi_always_flags v6wbi_tlb_flags +# define v7wbi_possible_flags v7wbi_tlb_flags +# define v7wbi_always_flags v7wbi_tlb_flags # ifdef _TLB # define MULTI_TLB 1 # else @@ -316,6 +330,8 @@ static inline void local_flush_tlb_all(void) asm("mcr p15, 0, %0, c8, c6, 0" : : "r" (zero) : "cc"); if (tlb_flag(TLB_V4_I_FULL | TLB_V6_I_FULL)) asm("mcr p15, 0, %0, c8, c5, 0" : : "r" (zero) : "cc"); + if (tlb_flag(TLB_V7_UIS_FULL)) + asm("mcr p15, 0, %0, c8, c3, 0" : : "r" (zero) : "cc"); if (tlb_flag(TLB_BTB)) { /* flush the branch target cache */ @@ -351,6 +367,8 @@ static inline void local_flush_tlb_mm(struct mm_struct *mm) asm("mcr p15, 0, %0, c8, c6, 2" : : "r" (asid) : "cc"); if (tlb_flag(TLB_V6_I_ASID)) asm("mcr p15, 0, %0, c8, c5, 2" : : "r" (asid) : "cc"); + if (tlb_flag(TLB_V7_UIS_ASID)) + asm("mcr p15, 0, %0, c8, c3, 2" : : "r" (asid) : "cc"); if (tlb_flag(TLB_BTB)) { /* flush the branch target cache */ @@ -389,6 +407,8 @@ local_flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr) asm("mcr p15, 0, %0, c8, c6, 1" : : "r" (uaddr) : "cc"); if (tlb_flag(TLB_V6_I_PAGE)) asm("mcr p15, 0, %0, c8, c5, 1" : : "r" (uaddr) : "cc"); + if (tlb_flag(TLB_V7_UIS_PAGE)) + asm("mcr p15, 0, %0, c8, c3, 1" : : "r" (uaddr) : "cc"); if (tlb_flag(TLB_BTB)) { /* flush the branch target cache */ @@ -424,6 +444,8 @@ static inline void local_flush_tlb_kernel_page(unsigned long kaddr) asm("mcr p15, 0, %0, c8, c6, 1" : : "r" (kaddr) : "cc"); if (tlb_flag(TLB_V6_I_PAGE)) asm("mcr p15, 0, %0, c8, c5, 1" : : "r" (kaddr) : "cc"); + if (tlb_flag(TLB_V7_UIS_PAGE)) + asm("mcr p15, 0, %0, c8, c3, 1" : : "r" (kaddr) : "cc"); if (tlb_flag(TLB_BTB)) { /* flush the branch target cache */ diff --git a/arch/arm/include/asm/uaccess.h b/arch/arm/include/asm/uaccess.h index 7897464e0c24..0da9bc9b3b1d 100644 --- a/arch/arm/include/asm/uaccess.h +++ b/arch/arm/include/asm/uaccess.h @@ -386,7 +386,9 @@ do { \ #ifdef CONFIG_MMU extern unsigned long __must_check __copy_from_user(void *to, const void __user *from, unsigned long n); extern unsigned long __must_check __copy_to_user(void __user *to, const void *from, unsigned long n); +extern unsigned long __must_check __copy_to_user_std(void __user *to, const void *from, unsigned long n); extern unsigned long __must_check __clear_user(void __user *addr, unsigned long n); +extern unsigned long __must_check __clear_user_std(void __user *addr, unsigned long n); #else #define __copy_from_user(to,from,n) (memcpy(to, (void __force *)from, n), 0) #define __copy_to_user(to,from,n) (memcpy((void __force *)to, from, n), 0) diff --git a/arch/arm/include/asm/unistd.h b/arch/arm/include/asm/unistd.h index 94cc58ef61ae..0e97b8cb77d5 100644 --- a/arch/arm/include/asm/unistd.h +++ b/arch/arm/include/asm/unistd.h @@ -389,6 +389,8 @@ #define __NR_inotify_init1 (__NR_SYSCALL_BASE+360) #define __NR_preadv (__NR_SYSCALL_BASE+361) #define __NR_pwritev (__NR_SYSCALL_BASE+362) +#define __NR_rt_tgsigqueueinfo (__NR_SYSCALL_BASE+363) +#define __NR_perf_counter_open (__NR_SYSCALL_BASE+364) /* * The following SWIs are ARM private. diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index 11a5197a221f..ff89d0b3abc5 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -22,6 +22,8 @@ obj-$(CONFIG_ARTHUR) += arthur.o obj-$(CONFIG_ISA_DMA) += dma-isa.o obj-$(CONFIG_PCI) += bios32.o isa.o obj-$(CONFIG_SMP) += smp.o +obj-$(CONFIG_HAVE_ARM_SCU) += smp_scu.o +obj-$(CONFIG_HAVE_ARM_TWD) += smp_twd.o obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o obj-$(CONFIG_KPROBES) += kprobes.o kprobes-decode.o diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S index 1680e9e9c831..f776e72a4cb8 100644 --- a/arch/arm/kernel/calls.S +++ b/arch/arm/kernel/calls.S @@ -372,6 +372,8 @@ /* 360 */ CALL(sys_inotify_init1) CALL(sys_preadv) CALL(sys_pwritev) + CALL(sys_rt_tgsigqueueinfo) + CALL(sys_perf_counter_open) #ifndef syscalls_counted .equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls #define syscalls_counted diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 83b1da6b7baa..fc8af43c5000 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -482,6 +482,9 @@ __und_usr: subeq r4, r2, #4 @ ARM instr at LR - 4 subne r4, r2, #2 @ Thumb instr at LR - 2 1: ldreqt r0, [r4] +#ifdef CONFIG_CPU_ENDIAN_BE8 + reveq r0, r0 @ little endian instruction +#endif beq call_fpe @ Thumb instruction #if __LINUX_ARM_ARCH__ >= 7 diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index b55cb0331809..366e5097a41a 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S @@ -210,6 +210,9 @@ ENTRY(vector_swi) A710( teq ip, #0x0f000000 ) A710( bne .Larm710bug ) #endif +#ifdef CONFIG_CPU_ENDIAN_BE8 + rev r10, r10 @ little endian instruction +#endif #elif defined(CONFIG_AEABI) diff --git a/arch/arm/kernel/init_task.c b/arch/arm/kernel/init_task.c index e859af349467..3f470866bb89 100644 --- a/arch/arm/kernel/init_task.c +++ b/arch/arm/kernel/init_task.c @@ -14,10 +14,6 @@ static struct signal_struct init_signals = INIT_SIGNALS(init_signals); static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); -struct mm_struct init_mm = INIT_MM(init_mm); - -EXPORT_SYMBOL(init_mm); - /* * Initial thread structure. * diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c index 6874c7dca75a..096f600dc8d8 100644 --- a/arch/arm/kernel/irq.c +++ b/arch/arm/kernel/irq.c @@ -167,7 +167,7 @@ void __init init_IRQ(void) #ifdef CONFIG_SMP cpumask_setall(bad_irq_desc.affinity); - bad_irq_desc.cpu = smp_processor_id(); + bad_irq_desc.node = smp_processor_id(); #endif init_arch_irq(); } @@ -176,7 +176,7 @@ void __init init_IRQ(void) static void route_irq(struct irq_desc *desc, unsigned int irq, unsigned int cpu) { - pr_debug("IRQ%u: moving from cpu%u to cpu%u\n", irq, desc->cpu, cpu); + pr_debug("IRQ%u: moving from cpu%u to cpu%u\n", irq, desc->node, cpu); spin_lock_irq(&desc->lock); desc->chip->set_affinity(irq, cpumask_of(cpu)); @@ -195,7 +195,7 @@ void migrate_irqs(void) for (i = 0; i < NR_IRQS; i++) { struct irq_desc *desc = irq_desc + i; - if (desc->cpu == cpu) { + if (desc->node == cpu) { unsigned int newcpu = cpumask_any_and(desc->affinity, cpu_online_mask); if (newcpu >= nr_cpu_ids) { diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index c3265a2e7cd4..39196dff478c 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -114,9 +114,6 @@ void arm_machine_restart(char mode, const char *cmd) /* * Function pointers to optional machine specific functions */ -void (*pm_idle)(void); -EXPORT_SYMBOL(pm_idle); - void (*pm_power_off)(void); EXPORT_SYMBOL(pm_power_off); @@ -130,20 +127,19 @@ EXPORT_SYMBOL_GPL(arm_pm_restart); */ static void default_idle(void) { - if (hlt_counter) - cpu_relax(); - else { - local_irq_disable(); - if (!need_resched()) - arch_idle(); - local_irq_enable(); - } + if (!need_resched()) + arch_idle(); + local_irq_enable(); } +void (*pm_idle)(void) = default_idle; +EXPORT_SYMBOL(pm_idle); + /* - * The idle thread. We try to conserve power, while trying to keep - * overall latency low. The architecture specific idle is passed - * a value to indicate the level of "idleness" of the system. + * The idle thread, has rather strange semantics for calling pm_idle, + * but this is what x86 does and we need to do the same, so that + * things like cpuidle get called in the same way. The only difference + * is that we always respect 'hlt_counter' to prevent low power idle. */ void cpu_idle(void) { @@ -151,21 +147,31 @@ void cpu_idle(void) /* endless idle loop with no priority at all */ while (1) { - void (*idle)(void) = pm_idle; - + tick_nohz_stop_sched_tick(1); + leds_event(led_idle_start); + while (!need_resched()) { #ifdef CONFIG_HOTPLUG_CPU - if (cpu_is_offline(smp_processor_id())) { - leds_event(led_idle_start); - cpu_die(); - } + if (cpu_is_offline(smp_processor_id())) + cpu_die(); #endif - if (!idle) - idle = default_idle; - leds_event(led_idle_start); - tick_nohz_stop_sched_tick(1); - while (!need_resched()) - idle(); + local_irq_disable(); + if (hlt_counter) { + local_irq_enable(); + cpu_relax(); + } else { + stop_critical_timings(); + pm_idle(); + start_critical_timings(); + /* + * This will eventually be removed - pm_idle + * functions should always return with IRQs + * enabled. + */ + WARN_ON(irqs_disabled()); + local_irq_enable(); + } + } leds_event(led_idle_end); tick_nohz_restart_sched_tick(); preempt_enable_no_resched(); @@ -352,6 +358,23 @@ asm( ".section .text\n" " .size kernel_thread_helper, . - kernel_thread_helper\n" " .previous"); +#ifdef CONFIG_ARM_UNWIND +extern void kernel_thread_exit(long code); +asm( ".section .text\n" +" .align\n" +" .type kernel_thread_exit, #function\n" +"kernel_thread_exit:\n" +" .fnstart\n" +" .cantunwind\n" +" bl do_exit\n" +" nop\n" +" .fnend\n" +" .size kernel_thread_exit, . - kernel_thread_exit\n" +" .previous"); +#else +#define kernel_thread_exit do_exit +#endif + /* * Create a kernel thread. */ @@ -363,9 +386,9 @@ pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) regs.ARM_r1 = (unsigned long)arg; regs.ARM_r2 = (unsigned long)fn; - regs.ARM_r3 = (unsigned long)do_exit; + regs.ARM_r3 = (unsigned long)kernel_thread_exit; regs.ARM_pc = (unsigned long)kernel_thread_helper; - regs.ARM_cpsr = SVC_MODE; + regs.ARM_cpsr = SVC_MODE | PSR_ENDSTATE; return do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); } diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 80b8b5c7e07a..93bb4247b7ed 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -426,9 +426,13 @@ setup_return(struct pt_regs *regs, struct k_sigaction *ka, */ thumb = handler & 1; - if (thumb) + if (thumb) { cpsr |= PSR_T_BIT; - else +#if __LINUX_ARM_ARCH__ >= 7 + /* clear the If-Then Thumb-2 execution state */ + cpsr &= ~PSR_IT_MASK; +#endif + } else cpsr &= ~PSR_T_BIT; } #endif @@ -532,7 +536,7 @@ setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info, return err; } -static inline void restart_syscall(struct pt_regs *regs) +static inline void setup_syscall_restart(struct pt_regs *regs) { regs->ARM_r0 = regs->ARM_ORIG_r0; regs->ARM_pc -= thumb_mode(regs) ? 2 : 4; @@ -567,7 +571,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, } /* fallthrough */ case -ERESTARTNOINTR: - restart_syscall(regs); + setup_syscall_restart(regs); } } @@ -691,7 +695,7 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall) if (regs->ARM_r0 == -ERESTARTNOHAND || regs->ARM_r0 == -ERESTARTSYS || regs->ARM_r0 == -ERESTARTNOINTR) { - restart_syscall(regs); + setup_syscall_restart(regs); } } single_step_set(current); diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 6014dfd22af4..de885fd256c5 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -22,16 +22,20 @@ #include #include #include +#include +#include #include #include #include +#include #include #include #include #include #include #include +#include /* * as from 2.5, kernels no longer have an init_tasks structure @@ -163,7 +167,7 @@ int __cpuexit __cpu_disable(void) * Take this CPU offline. Once we clear this, we can't return, * and we must not schedule until we're ready to give up the cpu. */ - cpu_clear(cpu, cpu_online_map); + set_cpu_online(cpu, false); /* * OK - migrate IRQs away from this CPU @@ -274,9 +278,9 @@ asmlinkage void __cpuinit secondary_start_kernel(void) local_fiq_enable(); /* - * Setup local timer for this CPU. + * Setup the percpu timer for this CPU. */ - local_timer_setup(); + percpu_timer_setup(); calibrate_delay(); @@ -285,7 +289,7 @@ asmlinkage void __cpuinit secondary_start_kernel(void) /* * OK, now it's safe to let the boot CPU continue */ - cpu_set(cpu, cpu_online_map); + set_cpu_online(cpu, true); /* * OK, it's off to the idle thread for us @@ -383,10 +387,16 @@ void show_local_irqs(struct seq_file *p) seq_putc(p, '\n'); } +/* + * Timer (local or broadcast) support + */ +static DEFINE_PER_CPU(struct clock_event_device, percpu_clockevent); + static void ipi_timer(void) { + struct clock_event_device *evt = &__get_cpu_var(percpu_clockevent); irq_enter(); - local_timer_interrupt(); + evt->event_handler(evt); irq_exit(); } @@ -405,6 +415,42 @@ asmlinkage void __exception do_local_timer(struct pt_regs *regs) } #endif +#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST +static void smp_timer_broadcast(const struct cpumask *mask) +{ + send_ipi_message(mask, IPI_TIMER); +} + +static void broadcast_timer_set_mode(enum clock_event_mode mode, + struct clock_event_device *evt) +{ +} + +static void local_timer_setup(struct clock_event_device *evt) +{ + evt->name = "dummy_timer"; + evt->features = CLOCK_EVT_FEAT_ONESHOT | + CLOCK_EVT_FEAT_PERIODIC | + CLOCK_EVT_FEAT_DUMMY; + evt->rating = 400; + evt->mult = 1; + evt->set_mode = broadcast_timer_set_mode; + evt->broadcast = smp_timer_broadcast; + + clockevents_register_device(evt); +} +#endif + +void __cpuinit percpu_timer_setup(void) +{ + unsigned int cpu = smp_processor_id(); + struct clock_event_device *evt = &per_cpu(percpu_clockevent, cpu); + + evt->cpumask = cpumask_of(cpu); + + local_timer_setup(evt); +} + static DEFINE_SPINLOCK(stop_lock); /* @@ -417,7 +463,7 @@ static void ipi_cpu_stop(unsigned int cpu) dump_stack(); spin_unlock(&stop_lock); - cpu_clear(cpu, cpu_online_map); + set_cpu_online(cpu, false); local_fiq_disable(); local_irq_disable(); @@ -501,11 +547,6 @@ void smp_send_reschedule(int cpu) send_ipi_message(cpumask_of(cpu), IPI_RESCHEDULE); } -void smp_timer_broadcast(const struct cpumask *mask) -{ - send_ipi_message(mask, IPI_TIMER); -} - void smp_send_stop(void) { cpumask_t mask = cpu_online_map; @@ -545,6 +586,12 @@ struct tlb_args { unsigned long ta_end; }; +/* all SMP configurations have the extended CPUID registers */ +static inline int tlb_ops_need_broadcast(void) +{ + return ((read_cpuid_ext(CPUID_EXT_MMFR3) >> 12) & 0xf) < 2; +} + static inline void ipi_flush_tlb_all(void *ignored) { local_flush_tlb_all(); @@ -587,51 +634,61 @@ static inline void ipi_flush_tlb_kernel_range(void *arg) void flush_tlb_all(void) { - on_each_cpu(ipi_flush_tlb_all, NULL, 1); + if (tlb_ops_need_broadcast()) + on_each_cpu(ipi_flush_tlb_all, NULL, 1); + else + local_flush_tlb_all(); } void flush_tlb_mm(struct mm_struct *mm) { - on_each_cpu_mask(ipi_flush_tlb_mm, mm, 1, &mm->cpu_vm_mask); + if (tlb_ops_need_broadcast()) + on_each_cpu_mask(ipi_flush_tlb_mm, mm, 1, &mm->cpu_vm_mask); + else + local_flush_tlb_mm(mm); } void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr) { - struct tlb_args ta; - - ta.ta_vma = vma; - ta.ta_start = uaddr; - - on_each_cpu_mask(ipi_flush_tlb_page, &ta, 1, &vma->vm_mm->cpu_vm_mask); + if (tlb_ops_need_broadcast()) { + struct tlb_args ta; + ta.ta_vma = vma; + ta.ta_start = uaddr; + on_each_cpu_mask(ipi_flush_tlb_page, &ta, 1, &vma->vm_mm->cpu_vm_mask); + } else + local_flush_tlb_page(vma, uaddr); } void flush_tlb_kernel_page(unsigned long kaddr) { - struct tlb_args ta; - - ta.ta_start = kaddr; - - on_each_cpu(ipi_flush_tlb_kernel_page, &ta, 1); + if (tlb_ops_need_broadcast()) { + struct tlb_args ta; + ta.ta_start = kaddr; + on_each_cpu(ipi_flush_tlb_kernel_page, &ta, 1); + } else + local_flush_tlb_kernel_page(kaddr); } void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) { - struct tlb_args ta; - - ta.ta_vma = vma; - ta.ta_start = start; - ta.ta_end = end; - - on_each_cpu_mask(ipi_flush_tlb_range, &ta, 1, &vma->vm_mm->cpu_vm_mask); + if (tlb_ops_need_broadcast()) { + struct tlb_args ta; + ta.ta_vma = vma; + ta.ta_start = start; + ta.ta_end = end; + on_each_cpu_mask(ipi_flush_tlb_range, &ta, 1, &vma->vm_mm->cpu_vm_mask); + } else + local_flush_tlb_range(vma, start, end); } void flush_tlb_kernel_range(unsigned long start, unsigned long end) { - struct tlb_args ta; - - ta.ta_start = start; - ta.ta_end = end; - - on_each_cpu(ipi_flush_tlb_kernel_range, &ta, 1); + if (tlb_ops_need_broadcast()) { + struct tlb_args ta; + ta.ta_start = start; + ta.ta_end = end; + on_each_cpu(ipi_flush_tlb_kernel_range, &ta, 1); + } else + local_flush_tlb_kernel_range(start, end); } diff --git a/arch/arm/kernel/smp_scu.c b/arch/arm/kernel/smp_scu.c new file mode 100644 index 000000000000..d3831f616ee9 --- /dev/null +++ b/arch/arm/kernel/smp_scu.c @@ -0,0 +1,48 @@ +/* + * linux/arch/arm/kernel/smp_scu.c + * + * Copyright (C) 2002 ARM Ltd. + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include + +#include +#include + +#define SCU_CTRL 0x00 +#define SCU_CONFIG 0x04 +#define SCU_CPU_STATUS 0x08 +#define SCU_INVALIDATE 0x0c +#define SCU_FPGA_REVISION 0x10 + +/* + * Get the number of CPU cores from the SCU configuration + */ +unsigned int __init scu_get_core_count(void __iomem *scu_base) +{ + unsigned int ncores = __raw_readl(scu_base + SCU_CONFIG); + return (ncores & 0x03) + 1; +} + +/* + * Enable the SCU + */ +void __init scu_enable(void __iomem *scu_base) +{ + u32 scu_ctrl; + + scu_ctrl = __raw_readl(scu_base + SCU_CTRL); + scu_ctrl |= 1; + __raw_writel(scu_ctrl, scu_base + SCU_CTRL); + + /* + * Ensure that the data accessed by CPU0 before the SCU was + * initialised is visible to the other CPUs. + */ + flush_cache_all(); +} diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c new file mode 100644 index 000000000000..d8c88c633c6f --- /dev/null +++ b/arch/arm/kernel/smp_twd.c @@ -0,0 +1,175 @@ +/* + * linux/arch/arm/kernel/smp_twd.c + * + * Copyright (C) 2002 ARM Ltd. + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define TWD_TIMER_LOAD 0x00 +#define TWD_TIMER_COUNTER 0x04 +#define TWD_TIMER_CONTROL 0x08 +#define TWD_TIMER_INTSTAT 0x0C + +#define TWD_WDOG_LOAD 0x20 +#define TWD_WDOG_COUNTER 0x24 +#define TWD_WDOG_CONTROL 0x28 +#define TWD_WDOG_INTSTAT 0x2C +#define TWD_WDOG_RESETSTAT 0x30 +#define TWD_WDOG_DISABLE 0x34 + +#define TWD_TIMER_CONTROL_ENABLE (1 << 0) +#define TWD_TIMER_CONTROL_ONESHOT (0 << 1) +#define TWD_TIMER_CONTROL_PERIODIC (1 << 1) +#define TWD_TIMER_CONTROL_IT_ENABLE (1 << 2) + +/* set up by the platform code */ +void __iomem *twd_base; + +static unsigned long twd_timer_rate; + +static void twd_set_mode(enum clock_event_mode mode, + struct clock_event_device *clk) +{ + unsigned long ctrl; + + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + /* timer load already set up */ + ctrl = TWD_TIMER_CONTROL_ENABLE | TWD_TIMER_CONTROL_IT_ENABLE + | TWD_TIMER_CONTROL_PERIODIC; + break; + case CLOCK_EVT_MODE_ONESHOT: + /* period set, and timer enabled in 'next_event' hook */ + ctrl = TWD_TIMER_CONTROL_IT_ENABLE | TWD_TIMER_CONTROL_ONESHOT; + break; + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + default: + ctrl = 0; + } + + __raw_writel(ctrl, twd_base + TWD_TIMER_CONTROL); +} + +static int twd_set_next_event(unsigned long evt, + struct clock_event_device *unused) +{ + unsigned long ctrl = __raw_readl(twd_base + TWD_TIMER_CONTROL); + + ctrl |= TWD_TIMER_CONTROL_ENABLE; + + __raw_writel(evt, twd_base + TWD_TIMER_COUNTER); + __raw_writel(ctrl, twd_base + TWD_TIMER_CONTROL); + + return 0; +} + +/* + * local_timer_ack: checks for a local timer interrupt. + * + * If a local timer interrupt has occurred, acknowledge and return 1. + * Otherwise, return 0. + */ +int twd_timer_ack(void) +{ + if (__raw_readl(twd_base + TWD_TIMER_INTSTAT)) { + __raw_writel(1, twd_base + TWD_TIMER_INTSTAT); + return 1; + } + + return 0; +} + +static void __cpuinit twd_calibrate_rate(void) +{ + unsigned long load, count; + u64 waitjiffies; + + /* + * If this is the first time round, we need to work out how fast + * the timer ticks + */ + if (twd_timer_rate == 0) { + printk(KERN_INFO "Calibrating local timer... "); + + /* Wait for a tick to start */ + waitjiffies = get_jiffies_64() + 1; + + while (get_jiffies_64() < waitjiffies) + udelay(10); + + /* OK, now the tick has started, let's get the timer going */ + waitjiffies += 5; + + /* enable, no interrupt or reload */ + __raw_writel(0x1, twd_base + TWD_TIMER_CONTROL); + + /* maximum value */ + __raw_writel(0xFFFFFFFFU, twd_base + TWD_TIMER_COUNTER); + + while (get_jiffies_64() < waitjiffies) + udelay(10); + + count = __raw_readl(twd_base + TWD_TIMER_COUNTER); + + twd_timer_rate = (0xFFFFFFFFU - count) * (HZ / 5); + + printk("%lu.%02luMHz.\n", twd_timer_rate / 1000000, + (twd_timer_rate / 100000) % 100); + } + + load = twd_timer_rate / HZ; + + __raw_writel(load, twd_base + TWD_TIMER_LOAD); +} + +/* + * Setup the local clock events for a CPU. + */ +void __cpuinit twd_timer_setup(struct clock_event_device *clk) +{ + unsigned long flags; + + twd_calibrate_rate(); + + clk->name = "local_timer"; + clk->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; + clk->rating = 350; + clk->set_mode = twd_set_mode; + clk->set_next_event = twd_set_next_event; + clk->shift = 20; + clk->mult = div_sc(twd_timer_rate, NSEC_PER_SEC, clk->shift); + clk->max_delta_ns = clockevent_delta2ns(0xffffffff, clk); + clk->min_delta_ns = clockevent_delta2ns(0xf, clk); + + /* Make sure our local interrupt controller has this enabled */ + local_irq_save(flags); + get_irq_chip(clk->irq)->unmask(clk->irq); + local_irq_restore(flags); + + clockevents_register_device(clk); +} + +/* + * take a local timer down + */ +void __cpuexit twd_timer_stop(void) +{ + __raw_writel(0, twd_base + TWD_TIMER_CONTROL); +} diff --git a/arch/arm/kernel/unwind.c b/arch/arm/kernel/unwind.c index 1dedc2c7ff49..dd56e11f339a 100644 --- a/arch/arm/kernel/unwind.c +++ b/arch/arm/kernel/unwind.c @@ -212,7 +212,8 @@ static int unwind_exec_insn(struct unwind_ctrl_block *ctrl) ctrl->vrs[14] = *vsp++; ctrl->vrs[SP] = (unsigned long)vsp; } else if (insn == 0xb0) { - ctrl->vrs[PC] = ctrl->vrs[LR]; + if (ctrl->vrs[PC] == 0) + ctrl->vrs[PC] = ctrl->vrs[LR]; /* no further processing */ ctrl->entries = 0; } else if (insn == 0xb1) { @@ -309,18 +310,20 @@ int unwind_frame(struct stackframe *frame) } while (ctrl.entries > 0) { - int urc; - - if (ctrl.vrs[SP] < low || ctrl.vrs[SP] >= high) - return -URC_FAILURE; - urc = unwind_exec_insn(&ctrl); + int urc = unwind_exec_insn(&ctrl); if (urc < 0) return urc; + if (ctrl.vrs[SP] < low || ctrl.vrs[SP] >= high) + return -URC_FAILURE; } if (ctrl.vrs[PC] == 0) ctrl.vrs[PC] = ctrl.vrs[LR]; + /* check for infinite loop */ + if (frame->pc == ctrl.vrs[PC]) + return -URC_FAILURE; + frame->fp = ctrl.vrs[FP]; frame->sp = ctrl.vrs[SP]; frame->lr = ctrl.vrs[LR]; @@ -332,7 +335,6 @@ int unwind_frame(struct stackframe *frame) void unwind_backtrace(struct pt_regs *regs, struct task_struct *tsk) { struct stackframe frame; - unsigned long high, low; register unsigned long current_sp asm ("sp"); pr_debug("%s(regs = %p tsk = %p)\n", __func__, regs, tsk); @@ -362,9 +364,6 @@ void unwind_backtrace(struct pt_regs *regs, struct task_struct *tsk) frame.pc = thread_saved_pc(tsk); } - low = frame.sp & ~(THREAD_SIZE - 1); - high = low + THREAD_SIZE; - while (1) { int urc; unsigned long where = frame.pc; diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S index c90f27250ead..4340bf3d2c84 100644 --- a/arch/arm/kernel/vmlinux.lds.S +++ b/arch/arm/kernel/vmlinux.lds.S @@ -84,6 +84,14 @@ SECTIONS *(.exitcall.exit) *(.ARM.exidx.exit.text) *(.ARM.extab.exit.text) +#ifndef CONFIG_HOTPLUG_CPU + *(.ARM.exidx.cpuexit.text) + *(.ARM.extab.cpuexit.text) +#endif +#ifndef CONFIG_HOTPLUG + *(.ARM.exidx.devexit.text) + *(.ARM.extab.devexit.text) +#endif #ifndef CONFIG_MMU *(.fixup) *(__ex_table) @@ -141,6 +149,7 @@ SECTIONS .data : AT(__data_loc) { _data = .; /* address in memory */ + _sdata = .; /* * first, the init task union, aligned @@ -192,6 +201,7 @@ SECTIONS __bss_start = .; /* BSS */ *(.bss) *(COMMON) + __bss_stop = .; _end = .; } /* Stabs debugging sections. */ diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile index 866f84a586ff..030ba7219f48 100644 --- a/arch/arm/lib/Makefile +++ b/arch/arm/lib/Makefile @@ -29,6 +29,9 @@ else endif endif +# using lib_ here won't override already available weak symbols +obj-$(CONFIG_UACCESS_WITH_MEMCPY) += uaccess_with_memcpy.o + lib-$(CONFIG_MMU) += $(mmu-y) ifeq ($(CONFIG_CPU_32v3),y) diff --git a/arch/arm/lib/clear_user.S b/arch/arm/lib/clear_user.S index 4d6bc71231f3..844f56785ebc 100644 --- a/arch/arm/lib/clear_user.S +++ b/arch/arm/lib/clear_user.S @@ -18,7 +18,8 @@ * : sz - number of bytes to clear * Returns : number of bytes NOT cleared */ -ENTRY(__clear_user) +ENTRY(__clear_user_std) +WEAK(__clear_user) stmfd sp!, {r1, lr} mov r2, #0 cmp r1, #4 diff --git a/arch/arm/lib/copy_to_user.S b/arch/arm/lib/copy_to_user.S index 22f968bbdffd..878820f0a320 100644 --- a/arch/arm/lib/copy_to_user.S +++ b/arch/arm/lib/copy_to_user.S @@ -86,7 +86,8 @@ .text -ENTRY(__copy_to_user) +ENTRY(__copy_to_user_std) +WEAK(__copy_to_user) #include "copy_template.S" diff --git a/arch/arm/lib/uaccess_with_memcpy.c b/arch/arm/lib/uaccess_with_memcpy.c new file mode 100644 index 000000000000..6b967ffb6552 --- /dev/null +++ b/arch/arm/lib/uaccess_with_memcpy.c @@ -0,0 +1,228 @@ +/* + * linux/arch/arm/lib/uaccess_with_memcpy.c + * + * Written by: Lennert Buytenhek and Nicolas Pitre + * Copyright (C) 2009 Marvell Semiconductor + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include /* for in_atomic() */ +#include +#include + +static int +pin_page_for_write(const void __user *_addr, pte_t **ptep, spinlock_t **ptlp) +{ + unsigned long addr = (unsigned long)_addr; + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + spinlock_t *ptl; + + pgd = pgd_offset(current->mm, addr); + if (unlikely(pgd_none(*pgd) || pgd_bad(*pgd))) + return 0; + + pmd = pmd_offset(pgd, addr); + if (unlikely(pmd_none(*pmd) || pmd_bad(*pmd))) + return 0; + + pte = pte_offset_map_lock(current->mm, pmd, addr, &ptl); + if (unlikely(!pte_present(*pte) || !pte_young(*pte) || + !pte_write(*pte) || !pte_dirty(*pte))) { + pte_unmap_unlock(pte, ptl); + return 0; + } + + *ptep = pte; + *ptlp = ptl; + + return 1; +} + +static unsigned long noinline +__copy_to_user_memcpy(void __user *to, const void *from, unsigned long n) +{ + int atomic; + + if (unlikely(segment_eq(get_fs(), KERNEL_DS))) { + memcpy((void *)to, from, n); + return 0; + } + + /* the mmap semaphore is taken only if not in an atomic context */ + atomic = in_atomic(); + + if (!atomic) + down_read(¤t->mm->mmap_sem); + while (n) { + pte_t *pte; + spinlock_t *ptl; + int tocopy; + + while (!pin_page_for_write(to, &pte, &ptl)) { + if (!atomic) + up_read(¤t->mm->mmap_sem); + if (__put_user(0, (char __user *)to)) + goto out; + if (!atomic) + down_read(¤t->mm->mmap_sem); + } + + tocopy = (~(unsigned long)to & ~PAGE_MASK) + 1; + if (tocopy > n) + tocopy = n; + + memcpy((void *)to, from, tocopy); + to += tocopy; + from += tocopy; + n -= tocopy; + + pte_unmap_unlock(pte, ptl); + } + if (!atomic) + up_read(¤t->mm->mmap_sem); + +out: + return n; +} + +unsigned long +__copy_to_user(void __user *to, const void *from, unsigned long n) +{ + /* + * This test is stubbed out of the main function above to keep + * the overhead for small copies low by avoiding a large + * register dump on the stack just to reload them right away. + * With frame pointer disabled, tail call optimization kicks in + * as well making this test almost invisible. + */ + if (n < 64) + return __copy_to_user_std(to, from, n); + return __copy_to_user_memcpy(to, from, n); +} + +static unsigned long noinline +__clear_user_memset(void __user *addr, unsigned long n) +{ + if (unlikely(segment_eq(get_fs(), KERNEL_DS))) { + memset((void *)addr, 0, n); + return 0; + } + + down_read(¤t->mm->mmap_sem); + while (n) { + pte_t *pte; + spinlock_t *ptl; + int tocopy; + + while (!pin_page_for_write(addr, &pte, &ptl)) { + up_read(¤t->mm->mmap_sem); + if (__put_user(0, (char __user *)addr)) + goto out; + down_read(¤t->mm->mmap_sem); + } + + tocopy = (~(unsigned long)addr & ~PAGE_MASK) + 1; + if (tocopy > n) + tocopy = n; + + memset((void *)addr, 0, tocopy); + addr += tocopy; + n -= tocopy; + + pte_unmap_unlock(pte, ptl); + } + up_read(¤t->mm->mmap_sem); + +out: + return n; +} + +unsigned long __clear_user(void __user *addr, unsigned long n) +{ + /* See rational for this in __copy_to_user() above. */ + if (n < 64) + return __clear_user_std(addr, n); + return __clear_user_memset(addr, n); +} + +#if 0 + +/* + * This code is disabled by default, but kept around in case the chosen + * thresholds need to be revalidated. Some overhead (small but still) + * would be implied by a runtime determined variable threshold, and + * so far the measurement on concerned targets didn't show a worthwhile + * variation. + * + * Note that a fairly precise sched_clock() implementation is needed + * for results to make some sense. + */ + +#include + +static int __init test_size_treshold(void) +{ + struct page *src_page, *dst_page; + void *user_ptr, *kernel_ptr; + unsigned long long t0, t1, t2; + int size, ret; + + ret = -ENOMEM; + src_page = alloc_page(GFP_KERNEL); + if (!src_page) + goto no_src; + dst_page = alloc_page(GFP_KERNEL); + if (!dst_page) + goto no_dst; + kernel_ptr = page_address(src_page); + user_ptr = vmap(&dst_page, 1, VM_IOREMAP, __pgprot(__P010)); + if (!user_ptr) + goto no_vmap; + + /* warm up the src page dcache */ + ret = __copy_to_user_memcpy(user_ptr, kernel_ptr, PAGE_SIZE); + + for (size = PAGE_SIZE; size >= 4; size /= 2) { + t0 = sched_clock(); + ret |= __copy_to_user_memcpy(user_ptr, kernel_ptr, size); + t1 = sched_clock(); + ret |= __copy_to_user_std(user_ptr, kernel_ptr, size); + t2 = sched_clock(); + printk("copy_to_user: %d %llu %llu\n", size, t1 - t0, t2 - t1); + } + + for (size = PAGE_SIZE; size >= 4; size /= 2) { + t0 = sched_clock(); + ret |= __clear_user_memset(user_ptr, size); + t1 = sched_clock(); + ret |= __clear_user_std(user_ptr, size); + t2 = sched_clock(); + printk("clear_user: %d %llu %llu\n", size, t1 - t0, t2 - t1); + } + + if (ret) + ret = -EFAULT; + + vunmap(user_ptr); +no_vmap: + put_page(dst_page); +no_dst: + put_page(src_page); +no_src: + return ret; +} + +subsys_initcall(test_size_treshold); + +#endif diff --git a/arch/arm/mach-at91/board-afeb-9260v1.c b/arch/arm/mach-at91/board-afeb-9260v1.c index e263fda3e2d1..970fd6b6753e 100644 --- a/arch/arm/mach-at91/board-afeb-9260v1.c +++ b/arch/arm/mach-at91/board-afeb-9260v1.c @@ -156,6 +156,8 @@ static struct atmel_nand_data __initdata afeb9260_nand_data = { * MCI (SD/MMC) */ static struct at91_mmc_data __initdata afeb9260_mmc_data = { + .det_pin = AT91_PIN_PC9, + .wp_pin = AT91_PIN_PC4, .slot_b = 1, .wire4 = 1, }; @@ -164,6 +166,8 @@ static struct at91_mmc_data __initdata afeb9260_mmc_data = { static struct i2c_board_info __initdata afeb9260_i2c_devices[] = { { + I2C_BOARD_INFO("tlv320aic23", 0x1a), + }, { I2C_BOARD_INFO("fm3130", 0x68), }, { I2C_BOARD_INFO("24c64", 0x50), @@ -196,6 +200,8 @@ static void __init afeb9260_board_init(void) /* I2C */ at91_add_device_i2c(afeb9260_i2c_devices, ARRAY_SIZE(afeb9260_i2c_devices)); + /* Audio */ + at91_add_device_ssc(AT91SAM9260_ID_SSC, ATMEL_SSC_TX); } MACHINE_START(AFEB9260, "Custom afeb9260 board") diff --git a/arch/arm/mach-at91/board-sam9g20ek.c b/arch/arm/mach-at91/board-sam9g20ek.c index 438efbb17482..cc270beadd5d 100644 --- a/arch/arm/mach-at91/board-sam9g20ek.c +++ b/arch/arm/mach-at91/board-sam9g20ek.c @@ -218,6 +218,13 @@ static struct gpio_led ek_leds[] = { } }; +static struct i2c_board_info __initdata ek_i2c_devices[] = { + { + I2C_BOARD_INFO("24c512", 0x50), + }, +}; + + static void __init ek_board_init(void) { /* Serial */ @@ -235,7 +242,7 @@ static void __init ek_board_init(void) /* MMC */ at91_add_device_mmc(0, &ek_mmc_data); /* I2C */ - at91_add_device_i2c(NULL, 0); + at91_add_device_i2c(ek_i2c_devices, ARRAY_SIZE(ek_i2c_devices)); /* LEDs */ at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds)); /* PCK0 provides MCLK to the WM8731 */ diff --git a/arch/arm/mach-at91/clock.c b/arch/arm/mach-at91/clock.c index e4345106ee57..bac578fe0d3d 100644 --- a/arch/arm/mach-at91/clock.c +++ b/arch/arm/mach-at91/clock.c @@ -43,6 +43,25 @@ #define clk_is_sys(x) ((x)->type & CLK_TYPE_SYSTEM) +/* + * Chips have some kind of clocks : group them by functionality + */ +#define cpu_has_utmi() ( cpu_is_at91cap9() \ + || cpu_is_at91sam9rl()) + +#define cpu_has_800M_plla() (cpu_is_at91sam9g20()) + +#define cpu_has_pllb() (!cpu_is_at91sam9rl()) + +#define cpu_has_upll() (0) + +/* USB host HS & FS */ +#define cpu_has_uhp() (!cpu_is_at91sam9rl()) + +/* USB device FS only */ +#define cpu_has_udpfs() (!cpu_is_at91sam9rl()) + + static LIST_HEAD(clocks); static DEFINE_SPINLOCK(clk_lock); @@ -140,7 +159,7 @@ static struct clk utmi_clk = { }; static struct clk uhpck = { .name = "uhpck", - .parent = &pllb, + /*.parent = ... we choose parent at runtime */ .mode = pmc_sys_mode, }; @@ -173,7 +192,11 @@ static struct clk __init *at91_css_to_clk(unsigned long css) case AT91_PMC_CSS_PLLA: return &plla; case AT91_PMC_CSS_PLLB: - return &pllb; + if (cpu_has_upll()) + /* CSS_PLLB == CSS_UPLL */ + return &utmi_clk; + else if (cpu_has_pllb()) + return &pllb; } return NULL; @@ -322,7 +345,7 @@ int clk_set_rate(struct clk *clk, unsigned long rate) u32 pckr; pckr = at91_sys_read(AT91_PMC_PCKR(clk->id)); - pckr &= AT91_PMC_CSS_PLLB; /* clock selection */ + pckr &= AT91_PMC_CSS; /* clock selection */ pckr |= prescale << 2; at91_sys_write(AT91_PMC_PCKR(clk->id), pckr); clk->rate_hz = actual; @@ -361,7 +384,7 @@ int clk_set_parent(struct clk *clk, struct clk *parent) } EXPORT_SYMBOL(clk_set_parent); -/* establish PCK0..PCK3 parentage and rate */ +/* establish PCK0..PCKN parentage and rate */ static void __init init_programmable_clock(struct clk *clk) { struct clk *parent; @@ -389,11 +412,13 @@ static int at91_clk_show(struct seq_file *s, void *unused) seq_printf(s, "MOR = %8x\n", at91_sys_read(AT91_CKGR_MOR)); seq_printf(s, "MCFR = %8x\n", at91_sys_read(AT91_CKGR_MCFR)); seq_printf(s, "PLLA = %8x\n", at91_sys_read(AT91_CKGR_PLLAR)); - if (!cpu_is_at91sam9rl()) + if (cpu_has_pllb()) seq_printf(s, "PLLB = %8x\n", at91_sys_read(AT91_CKGR_PLLBR)); - if (cpu_is_at91cap9() || cpu_is_at91sam9rl()) + if (cpu_has_utmi()) seq_printf(s, "UCKR = %8x\n", uckr = at91_sys_read(AT91_CKGR_UCKR)); seq_printf(s, "MCKR = %8x\n", at91_sys_read(AT91_PMC_MCKR)); + if (cpu_has_upll()) + seq_printf(s, "USB = %8x\n", at91_sys_read(AT91_PMC_USB)); seq_printf(s, "SR = %8x\n", sr = at91_sys_read(AT91_PMC_SR)); seq_printf(s, "\n"); @@ -554,16 +579,60 @@ static struct clk *const standard_pmc_clocks[] __initdata = { &clk32k, &main_clk, &plla, - &pllb, - - /* PLLB children (USB) */ - &udpck, - &uhpck, /* MCK */ &mck }; +/* PLLB generated USB full speed clock init */ +static void __init at91_pllb_usbfs_clock_init(unsigned long main_clock) +{ + /* + * USB clock init: choose 48 MHz PLLB value, + * disable 48MHz clock during usb peripheral suspend. + * + * REVISIT: assumes MCK doesn't derive from PLLB! + */ + uhpck.parent = &pllb; + + at91_pllb_usb_init = at91_pll_calc(main_clock, 48000000 * 2) | AT91_PMC_USB96M; + pllb.rate_hz = at91_pll_rate(&pllb, main_clock, at91_pllb_usb_init); + if (cpu_is_at91rm9200()) { + uhpck.pmc_mask = AT91RM9200_PMC_UHP; + udpck.pmc_mask = AT91RM9200_PMC_UDP; + at91_sys_write(AT91_PMC_SCER, AT91RM9200_PMC_MCKUDP); + } else if (cpu_is_at91sam9260() || cpu_is_at91sam9261() || cpu_is_at91sam9263() || cpu_is_at91sam9g20()) { + uhpck.pmc_mask = AT91SAM926x_PMC_UHP; + udpck.pmc_mask = AT91SAM926x_PMC_UDP; + } else if (cpu_is_at91cap9()) { + uhpck.pmc_mask = AT91CAP9_PMC_UHP; + } + at91_sys_write(AT91_CKGR_PLLBR, 0); + + udpck.rate_hz = at91_usb_rate(&pllb, pllb.rate_hz, at91_pllb_usb_init); + uhpck.rate_hz = at91_usb_rate(&pllb, pllb.rate_hz, at91_pllb_usb_init); +} + +/* UPLL generated USB full speed clock init */ +static void __init at91_upll_usbfs_clock_init(unsigned long main_clock) +{ + /* + * USB clock init: choose 480 MHz from UPLL, + */ + unsigned int usbr = AT91_PMC_USBS_UPLL; + + /* Setup divider by 10 to reach 48 MHz */ + usbr |= ((10 - 1) << 8) & AT91_PMC_OHCIUSBDIV; + + at91_sys_write(AT91_PMC_USB, usbr); + + /* Now set uhpck values */ + uhpck.parent = &utmi_clk; + uhpck.pmc_mask = AT91SAM926x_PMC_UHP; + uhpck.rate_hz = utmi_clk.parent->rate_hz; + uhpck.rate_hz /= 1 + ((at91_sys_read(AT91_PMC_USB) & AT91_PMC_OHCIUSBDIV) >> 8); +} + int __init at91_clock_init(unsigned long main_clock) { unsigned tmp, freq, mckr; @@ -585,43 +654,37 @@ int __init at91_clock_init(unsigned long main_clock) /* report if PLLA is more than mildly overclocked */ plla.rate_hz = at91_pll_rate(&plla, main_clock, at91_sys_read(AT91_CKGR_PLLAR)); - if ((!cpu_is_at91sam9g20() && plla.rate_hz > 209000000) - || (cpu_is_at91sam9g20() && plla.rate_hz > 800000000)) + if ((!cpu_has_800M_plla() && plla.rate_hz > 209000000) + || (cpu_has_800M_plla() && plla.rate_hz > 800000000)) pr_info("Clocks: PLLA overclocked, %ld MHz\n", plla.rate_hz / 1000000); - /* - * USB clock init: choose 48 MHz PLLB value, - * disable 48MHz clock during usb peripheral suspend. - * - * REVISIT: assumes MCK doesn't derive from PLLB! - */ - at91_pllb_usb_init = at91_pll_calc(main_clock, 48000000 * 2) | AT91_PMC_USB96M; - pllb.rate_hz = at91_pll_rate(&pllb, main_clock, at91_pllb_usb_init); - if (cpu_is_at91rm9200()) { - uhpck.pmc_mask = AT91RM9200_PMC_UHP; - udpck.pmc_mask = AT91RM9200_PMC_UDP; - at91_sys_write(AT91_PMC_SCER, AT91RM9200_PMC_MCKUDP); - } else if (cpu_is_at91sam9260() || cpu_is_at91sam9261() || cpu_is_at91sam9263() || cpu_is_at91sam9g20()) { - uhpck.pmc_mask = AT91SAM926x_PMC_UHP; - udpck.pmc_mask = AT91SAM926x_PMC_UDP; - } else if (cpu_is_at91cap9()) { - uhpck.pmc_mask = AT91CAP9_PMC_UHP; - } - at91_sys_write(AT91_CKGR_PLLBR, 0); - udpck.rate_hz = at91_usb_rate(&pllb, pllb.rate_hz, at91_pllb_usb_init); - uhpck.rate_hz = at91_usb_rate(&pllb, pllb.rate_hz, at91_pllb_usb_init); + if (cpu_has_upll() && !cpu_has_pllb()) { + /* setup UTMI clock as the fourth primary clock + * (instead of pllb) */ + utmi_clk.type |= CLK_TYPE_PRIMARY; + utmi_clk.id = 3; + } + /* * USB HS clock init */ - if (cpu_is_at91cap9() || cpu_is_at91sam9rl()) { + if (cpu_has_utmi()) /* * multiplier is hard-wired to 40 * (obtain the USB High Speed 480 MHz when input is 12 MHz) */ utmi_clk.rate_hz = 40 * utmi_clk.parent->rate_hz; - } + + /* + * USB FS clock init + */ + if (cpu_has_pllb()) + at91_pllb_usbfs_clock_init(main_clock); + if (cpu_has_upll()) + /* assumes that we choose UPLL for USB and not PLLA */ + at91_upll_usbfs_clock_init(main_clock); /* * MCK and CPU derive from one of those primary clocks. @@ -631,21 +694,31 @@ int __init at91_clock_init(unsigned long main_clock) mck.parent = at91_css_to_clk(mckr & AT91_PMC_CSS); freq = mck.parent->rate_hz; freq /= (1 << ((mckr & AT91_PMC_PRES) >> 2)); /* prescale */ - if (cpu_is_at91rm9200()) + if (cpu_is_at91rm9200()) { mck.rate_hz = freq / (1 + ((mckr & AT91_PMC_MDIV) >> 8)); /* mdiv */ - else if (cpu_is_at91sam9g20()) { + } else if (cpu_is_at91sam9g20()) { mck.rate_hz = (mckr & AT91_PMC_MDIV) ? freq / ((mckr & AT91_PMC_MDIV) >> 7) : freq; /* mdiv ; (x >> 7) = ((x >> 8) * 2) */ if (mckr & AT91_PMC_PDIV) freq /= 2; /* processor clock division */ - } else + } else { mck.rate_hz = freq / (1 << ((mckr & AT91_PMC_MDIV) >> 8)); /* mdiv */ + } /* Register the PMC's standard clocks */ for (i = 0; i < ARRAY_SIZE(standard_pmc_clocks); i++) list_add_tail(&standard_pmc_clocks[i]->node, &clocks); - if (cpu_is_at91cap9() || cpu_is_at91sam9rl()) + if (cpu_has_pllb()) + list_add_tail(&pllb.node, &clocks); + + if (cpu_has_uhp()) + list_add_tail(&uhpck.node, &clocks); + + if (cpu_has_udpfs()) + list_add_tail(&udpck.node, &clocks); + + if (cpu_has_utmi()) list_add_tail(&utmi_clk.node, &clocks); /* MCK and CPU clock are "always on" */ diff --git a/arch/arm/mach-at91/include/mach/at91_pmc.h b/arch/arm/mach-at91/include/mach/at91_pmc.h index 9561e33b8a9a..64589eaaaee8 100644 --- a/arch/arm/mach-at91/include/mach/at91_pmc.h +++ b/arch/arm/mach-at91/include/mach/at91_pmc.h @@ -23,7 +23,7 @@ #define AT91_PMC_PCK (1 << 0) /* Processor Clock */ #define AT91RM9200_PMC_UDP (1 << 1) /* USB Devcice Port Clock [AT91RM9200 only] */ #define AT91RM9200_PMC_MCKUDP (1 << 2) /* USB Device Port Master Clock Automatic Disable on Suspend [AT91RM9200 only] */ -#define AT91CAP9_PMC_DDR (1 << 2) /* DDR Clock [AT91CAP9 revC only] */ +#define AT91CAP9_PMC_DDR (1 << 2) /* DDR Clock [CAP9 revC & some SAM9 only] */ #define AT91RM9200_PMC_UHP (1 << 4) /* USB Host Port Clock [AT91RM9200 only] */ #define AT91SAM926x_PMC_UHP (1 << 6) /* USB Host Port Clock [AT91SAM926x only] */ #define AT91CAP9_PMC_UHP (1 << 6) /* USB Host Port Clock [AT91CAP9 only] */ @@ -39,11 +39,11 @@ #define AT91_PMC_PCDR (AT91_PMC + 0x14) /* Peripheral Clock Disable Register */ #define AT91_PMC_PCSR (AT91_PMC + 0x18) /* Peripheral Clock Status Register */ -#define AT91_CKGR_UCKR (AT91_PMC + 0x1C) /* UTMI Clock Register [SAM9RL, CAP9] */ +#define AT91_CKGR_UCKR (AT91_PMC + 0x1C) /* UTMI Clock Register [some SAM9, CAP9] */ #define AT91_PMC_UPLLEN (1 << 16) /* UTMI PLL Enable */ #define AT91_PMC_UPLLCOUNT (0xf << 20) /* UTMI PLL Start-up Time */ #define AT91_PMC_BIASEN (1 << 24) /* UTMI BIAS Enable */ -#define AT91_PMC_BIASCOUNT (0xf << 28) /* UTMI PLL Start-up Time */ +#define AT91_PMC_BIASCOUNT (0xf << 28) /* UTMI BIAS Start-up Time */ #define AT91_CKGR_MOR (AT91_PMC + 0x20) /* Main Oscillator Register [not on SAM9RL] */ #define AT91_PMC_MOSCEN (1 << 0) /* Main Oscillator Enable */ @@ -72,6 +72,7 @@ #define AT91_PMC_CSS_MAIN (1 << 0) #define AT91_PMC_CSS_PLLA (2 << 0) #define AT91_PMC_CSS_PLLB (3 << 0) +#define AT91_PMC_CSS_UPLL (3 << 0) /* [some SAM9 only] */ #define AT91_PMC_PRES (7 << 2) /* Master Clock Prescaler */ #define AT91_PMC_PRES_1 (0 << 2) #define AT91_PMC_PRES_2 (1 << 2) @@ -88,12 +89,25 @@ #define AT91SAM9_PMC_MDIV_1 (0 << 8) /* [SAM9,CAP9 only] */ #define AT91SAM9_PMC_MDIV_2 (1 << 8) #define AT91SAM9_PMC_MDIV_4 (2 << 8) -#define AT91SAM9_PMC_MDIV_6 (3 << 8) +#define AT91SAM9_PMC_MDIV_6 (3 << 8) /* [some SAM9 only] */ +#define AT91SAM9_PMC_MDIV_3 (3 << 8) /* [some SAM9 only] */ #define AT91_PMC_PDIV (1 << 12) /* Processor Clock Division [some SAM9 only] */ #define AT91_PMC_PDIV_1 (0 << 12) #define AT91_PMC_PDIV_2 (1 << 12) +#define AT91_PMC_PLLADIV2 (1 << 12) /* PLLA divisor by 2 [some SAM9 only] */ +#define AT91_PMC_PLLADIV2_OFF (0 << 12) +#define AT91_PMC_PLLADIV2_ON (1 << 12) -#define AT91_PMC_PCKR(n) (AT91_PMC + 0x40 + ((n) * 4)) /* Programmable Clock 0-3 Registers */ +#define AT91_PMC_USB (AT91_PMC + 0x38) /* USB Clock Register [some SAM9 only] */ +#define AT91_PMC_USBS (0x1 << 0) /* USB OHCI Input clock selection */ +#define AT91_PMC_USBS_PLLA (0 << 0) +#define AT91_PMC_USBS_UPLL (1 << 0) +#define AT91_PMC_OHCIUSBDIV (0xF << 8) /* Divider for USB OHCI Clock */ + +#define AT91_PMC_PCKR(n) (AT91_PMC + 0x40 + ((n) * 4)) /* Programmable Clock 0-N Registers */ +#define AT91_PMC_CSSMCK (0x1 << 8) /* CSS or Master Clock Selection */ +#define AT91_PMC_CSSMCK_CSS (0 << 8) +#define AT91_PMC_CSSMCK_MCK (1 << 8) #define AT91_PMC_IER (AT91_PMC + 0x60) /* Interrupt Enable Register */ #define AT91_PMC_IDR (AT91_PMC + 0x64) /* Interrupt Disable Register */ @@ -102,7 +116,7 @@ #define AT91_PMC_LOCKA (1 << 1) /* PLLA Lock */ #define AT91_PMC_LOCKB (1 << 2) /* PLLB Lock */ #define AT91_PMC_MCKRDY (1 << 3) /* Master Clock */ -#define AT91_PMC_LOCKU (1 << 6) /* UPLL Lock [AT91CAP9 only] */ +#define AT91_PMC_LOCKU (1 << 6) /* UPLL Lock [some SAM9, AT91CAP9 only] */ #define AT91_PMC_OSCSEL (1 << 7) /* Slow Clock Oscillator [AT91CAP9 revC only] */ #define AT91_PMC_PCK0RDY (1 << 8) /* Programmable Clock 0 */ #define AT91_PMC_PCK1RDY (1 << 9) /* Programmable Clock 1 */ diff --git a/arch/arm/mach-at91/include/mach/at_hdmac.h b/arch/arm/mach-at91/include/mach/at_hdmac.h new file mode 100644 index 000000000000..187cb58345c0 --- /dev/null +++ b/arch/arm/mach-at91/include/mach/at_hdmac.h @@ -0,0 +1,102 @@ +/* + * Header file for the Atmel AHB DMA Controller driver + * + * Copyright (C) 2008 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ +#ifndef AT_HDMAC_H +#define AT_HDMAC_H + +#include + +/** + * struct at_dma_platform_data - Controller configuration parameters + * @nr_channels: Number of channels supported by hardware (max 8) + * @cap_mask: dma_capability flags supported by the platform + */ +struct at_dma_platform_data { + unsigned int nr_channels; + dma_cap_mask_t cap_mask; +}; + +/** + * enum at_dma_slave_width - DMA slave register access width. + * @AT_DMA_SLAVE_WIDTH_8BIT: Do 8-bit slave register accesses + * @AT_DMA_SLAVE_WIDTH_16BIT: Do 16-bit slave register accesses + * @AT_DMA_SLAVE_WIDTH_32BIT: Do 32-bit slave register accesses + */ +enum at_dma_slave_width { + AT_DMA_SLAVE_WIDTH_8BIT = 0, + AT_DMA_SLAVE_WIDTH_16BIT, + AT_DMA_SLAVE_WIDTH_32BIT, +}; + +/** + * struct at_dma_slave - Controller-specific information about a slave + * @dma_dev: required DMA master device + * @tx_reg: physical address of data register used for + * memory-to-peripheral transfers + * @rx_reg: physical address of data register used for + * peripheral-to-memory transfers + * @reg_width: peripheral register width + * @cfg: Platform-specific initializer for the CFG register + * @ctrla: Platform-specific initializer for the CTRLA register + */ +struct at_dma_slave { + struct device *dma_dev; + dma_addr_t tx_reg; + dma_addr_t rx_reg; + enum at_dma_slave_width reg_width; + u32 cfg; + u32 ctrla; +}; + + +/* Platform-configurable bits in CFG */ +#define ATC_SRC_PER(h) (0xFU & (h)) /* Channel src rq associated with periph handshaking ifc h */ +#define ATC_DST_PER(h) ((0xFU & (h)) << 4) /* Channel dst rq associated with periph handshaking ifc h */ +#define ATC_SRC_REP (0x1 << 8) /* Source Replay Mod */ +#define ATC_SRC_H2SEL (0x1 << 9) /* Source Handshaking Mod */ +#define ATC_SRC_H2SEL_SW (0x0 << 9) +#define ATC_SRC_H2SEL_HW (0x1 << 9) +#define ATC_DST_REP (0x1 << 12) /* Destination Replay Mod */ +#define ATC_DST_H2SEL (0x1 << 13) /* Destination Handshaking Mod */ +#define ATC_DST_H2SEL_SW (0x0 << 13) +#define ATC_DST_H2SEL_HW (0x1 << 13) +#define ATC_SOD (0x1 << 16) /* Stop On Done */ +#define ATC_LOCK_IF (0x1 << 20) /* Interface Lock */ +#define ATC_LOCK_B (0x1 << 21) /* AHB Bus Lock */ +#define ATC_LOCK_IF_L (0x1 << 22) /* Master Interface Arbiter Lock */ +#define ATC_LOCK_IF_L_CHUNK (0x0 << 22) +#define ATC_LOCK_IF_L_BUFFER (0x1 << 22) +#define ATC_AHB_PROT_MASK (0x7 << 24) /* AHB Protection */ +#define ATC_FIFOCFG_MASK (0x3 << 28) /* FIFO Request Configuration */ +#define ATC_FIFOCFG_LARGESTBURST (0x0 << 28) +#define ATC_FIFOCFG_HALFFIFO (0x1 << 28) +#define ATC_FIFOCFG_ENOUGHSPACE (0x2 << 28) + +/* Platform-configurable bits in CTRLA */ +#define ATC_SCSIZE_MASK (0x7 << 16) /* Source Chunk Transfer Size */ +#define ATC_SCSIZE_1 (0x0 << 16) +#define ATC_SCSIZE_4 (0x1 << 16) +#define ATC_SCSIZE_8 (0x2 << 16) +#define ATC_SCSIZE_16 (0x3 << 16) +#define ATC_SCSIZE_32 (0x4 << 16) +#define ATC_SCSIZE_64 (0x5 << 16) +#define ATC_SCSIZE_128 (0x6 << 16) +#define ATC_SCSIZE_256 (0x7 << 16) +#define ATC_DCSIZE_MASK (0x7 << 20) /* Destination Chunk Transfer Size */ +#define ATC_DCSIZE_1 (0x0 << 20) +#define ATC_DCSIZE_4 (0x1 << 20) +#define ATC_DCSIZE_8 (0x2 << 20) +#define ATC_DCSIZE_16 (0x3 << 20) +#define ATC_DCSIZE_32 (0x4 << 20) +#define ATC_DCSIZE_64 (0x5 << 20) +#define ATC_DCSIZE_128 (0x6 << 20) +#define ATC_DCSIZE_256 (0x7 << 20) + +#endif /* AT_HDMAC_H */ diff --git a/arch/arm/mach-davinci/Kconfig b/arch/arm/mach-davinci/Kconfig index a9c78bc72b84..be747f5c6cd8 100644 --- a/arch/arm/mach-davinci/Kconfig +++ b/arch/arm/mach-davinci/Kconfig @@ -1,11 +1,26 @@ if ARCH_DAVINCI +config AINTC + bool + +config CP_INTC + bool + menu "TI DaVinci Implementations" comment "DaVinci Core Type" config ARCH_DAVINCI_DM644x bool "DaVinci 644x based system" + select AINTC + +config ARCH_DAVINCI_DM355 + bool "DaVinci 355 based system" + select AINTC + +config ARCH_DAVINCI_DM646x + bool "DaVinci 646x based system" + select AINTC comment "DaVinci Board Type" @@ -17,6 +32,34 @@ config MACH_DAVINCI_EVM Configure this option to specify the whether the board used for development is a DM644x EVM +config MACH_SFFSDR + bool "Lyrtech SFFSDR" + depends on ARCH_DAVINCI_DM644x + help + Say Y here to select the Lyrtech Small Form Factor + Software Defined Radio (SFFSDR) board. + +config MACH_DAVINCI_DM355_EVM + bool "TI DM355 EVM" + depends on ARCH_DAVINCI_DM355 + help + Configure this option to specify the whether the board used + for development is a DM355 EVM + +config MACH_DM355_LEOPARD + bool "DM355 Leopard board" + depends on ARCH_DAVINCI_DM355 + help + Configure this option to specify the whether the board used + for development is a DM355 Leopard board. + +config MACH_DAVINCI_DM6467_EVM + bool "TI DM6467 EVM" + depends on ARCH_DAVINCI_DM646x + help + Configure this option to specify the whether the board used + for development is a DM6467 EVM + config DAVINCI_MUX bool "DAVINCI multiplexing support" diff --git a/arch/arm/mach-davinci/Makefile b/arch/arm/mach-davinci/Makefile index 1674661942f3..059ab78084ba 100644 --- a/arch/arm/mach-davinci/Makefile +++ b/arch/arm/mach-davinci/Makefile @@ -4,13 +4,22 @@ # # Common objects -obj-y := time.o irq.o clock.o serial.o io.o id.o psc.o \ - gpio.o devices.o dma.o usb.o +obj-y := time.o clock.o serial.o io.o psc.o \ + gpio.o devices.o dma.o usb.o common.o sram.o obj-$(CONFIG_DAVINCI_MUX) += mux.o # Chip specific obj-$(CONFIG_ARCH_DAVINCI_DM644x) += dm644x.o +obj-$(CONFIG_ARCH_DAVINCI_DM355) += dm355.o +obj-$(CONFIG_ARCH_DAVINCI_DM646x) += dm646x.o + +obj-$(CONFIG_AINTC) += irq.o +obj-$(CONFIG_CP_INTC) += cp_intc.o # Board specific obj-$(CONFIG_MACH_DAVINCI_EVM) += board-dm644x-evm.o +obj-$(CONFIG_MACH_SFFSDR) += board-sffsdr.o +obj-$(CONFIG_MACH_DAVINCI_DM355_EVM) += board-dm355-evm.o +obj-$(CONFIG_MACH_DM355_LEOPARD) += board-dm355-leopard.o +obj-$(CONFIG_MACH_DAVINCI_DM6467_EVM) += board-dm646x-evm.o diff --git a/arch/arm/mach-davinci/board-dm355-evm.c b/arch/arm/mach-davinci/board-dm355-evm.c new file mode 100644 index 000000000000..5ac2f565d860 --- /dev/null +++ b/arch/arm/mach-davinci/board-dm355-evm.c @@ -0,0 +1,298 @@ +/* + * TI DaVinci EVM board support + * + * Author: Kevin Hilman, Deep Root Systems, LLC + * + * 2007 (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. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DAVINCI_ASYNC_EMIF_CONTROL_BASE 0x01e10000 +#define DAVINCI_ASYNC_EMIF_DATA_CE0_BASE 0x02000000 + +/* NOTE: this is geared for the standard config, with a socketed + * 2 GByte Micron NAND (MT29F16G08FAA) using 128KB sectors. If you + * swap chips, maybe with a different block size, partitioning may + * need to be changed. + */ +#define NAND_BLOCK_SIZE SZ_128K + +static struct mtd_partition davinci_nand_partitions[] = { + { + /* UBL (a few copies) plus U-Boot */ + .name = "bootloader", + .offset = 0, + .size = 15 * NAND_BLOCK_SIZE, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, { + /* U-Boot environment */ + .name = "params", + .offset = MTDPART_OFS_APPEND, + .size = 1 * NAND_BLOCK_SIZE, + .mask_flags = 0, + }, { + .name = "kernel", + .offset = MTDPART_OFS_APPEND, + .size = SZ_4M, + .mask_flags = 0, + }, { + .name = "filesystem1", + .offset = MTDPART_OFS_APPEND, + .size = SZ_512M, + .mask_flags = 0, + }, { + .name = "filesystem2", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL, + .mask_flags = 0, + } + /* two blocks with bad block table (and mirror) at the end */ +}; + +static struct davinci_nand_pdata davinci_nand_data = { + .mask_chipsel = BIT(14), + .parts = davinci_nand_partitions, + .nr_parts = ARRAY_SIZE(davinci_nand_partitions), + .ecc_mode = NAND_ECC_HW_SYNDROME, + .options = NAND_USE_FLASH_BBT, +}; + +static struct resource davinci_nand_resources[] = { + { + .start = DAVINCI_ASYNC_EMIF_DATA_CE0_BASE, + .end = DAVINCI_ASYNC_EMIF_DATA_CE0_BASE + SZ_32M - 1, + .flags = IORESOURCE_MEM, + }, { + .start = DAVINCI_ASYNC_EMIF_CONTROL_BASE, + .end = DAVINCI_ASYNC_EMIF_CONTROL_BASE + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device davinci_nand_device = { + .name = "davinci_nand", + .id = 0, + + .num_resources = ARRAY_SIZE(davinci_nand_resources), + .resource = davinci_nand_resources, + + .dev = { + .platform_data = &davinci_nand_data, + }, +}; + +static struct davinci_i2c_platform_data i2c_pdata = { + .bus_freq = 400 /* kHz */, + .bus_delay = 0 /* usec */, +}; + +static int dm355evm_mmc_gpios = -EINVAL; + +static void dm355evm_mmcsd_gpios(unsigned gpio) +{ + gpio_request(gpio + 0, "mmc0_ro"); + gpio_request(gpio + 1, "mmc0_cd"); + gpio_request(gpio + 2, "mmc1_ro"); + gpio_request(gpio + 3, "mmc1_cd"); + + /* we "know" these are input-only so we don't + * need to call gpio_direction_input() + */ + + dm355evm_mmc_gpios = gpio; +} + +static struct i2c_board_info dm355evm_i2c_info[] = { + { I2C_BOARD_INFO("dm355evm_msp", 0x25), + .platform_data = dm355evm_mmcsd_gpios, + /* plus irq */ }, + /* { I2C_BOARD_INFO("tlv320aic3x", 0x1b), }, */ + /* { I2C_BOARD_INFO("tvp5146", 0x5d), }, */ +}; + +static void __init evm_init_i2c(void) +{ + davinci_init_i2c(&i2c_pdata); + + gpio_request(5, "dm355evm_msp"); + gpio_direction_input(5); + dm355evm_i2c_info[0].irq = gpio_to_irq(5); + + i2c_register_board_info(1, dm355evm_i2c_info, + ARRAY_SIZE(dm355evm_i2c_info)); +} + +static struct resource dm355evm_dm9000_rsrc[] = { + { + /* addr */ + .start = 0x04014000, + .end = 0x04014001, + .flags = IORESOURCE_MEM, + }, { + /* data */ + .start = 0x04014002, + .end = 0x04014003, + .flags = IORESOURCE_MEM, + }, { + .flags = IORESOURCE_IRQ + | IORESOURCE_IRQ_HIGHEDGE /* rising (active high) */, + }, +}; + +static struct platform_device dm355evm_dm9000 = { + .name = "dm9000", + .id = -1, + .resource = dm355evm_dm9000_rsrc, + .num_resources = ARRAY_SIZE(dm355evm_dm9000_rsrc), +}; + +static struct platform_device *davinci_evm_devices[] __initdata = { + &dm355evm_dm9000, + &davinci_nand_device, +}; + +static struct davinci_uart_config uart_config __initdata = { + .enabled_uarts = (1 << 0), +}; + +static void __init dm355_evm_map_io(void) +{ + dm355_init(); +} + +static int dm355evm_mmc_get_cd(int module) +{ + if (!gpio_is_valid(dm355evm_mmc_gpios)) + return -ENXIO; + /* low == card present */ + return !gpio_get_value_cansleep(dm355evm_mmc_gpios + 2 * module + 1); +} + +static int dm355evm_mmc_get_ro(int module) +{ + if (!gpio_is_valid(dm355evm_mmc_gpios)) + return -ENXIO; + /* high == card's write protect switch active */ + return gpio_get_value_cansleep(dm355evm_mmc_gpios + 2 * module + 0); +} + +static struct davinci_mmc_config dm355evm_mmc_config = { + .get_cd = dm355evm_mmc_get_cd, + .get_ro = dm355evm_mmc_get_ro, + .wires = 4, + .max_freq = 50000000, + .caps = MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED, + .version = MMC_CTLR_VERSION_1, +}; + +/* Don't connect anything to J10 unless you're only using USB host + * mode *and* have to do so with some kind of gender-bender. If + * you have proper Mini-B or Mini-A cables (or Mini-A adapters) + * the ID pin won't need any help. + */ +#ifdef CONFIG_USB_MUSB_PERIPHERAL +#define USB_ID_VALUE 0 /* ID pulled high; *should* float */ +#else +#define USB_ID_VALUE 1 /* ID pulled low */ +#endif + +static struct spi_eeprom at25640a = { + .byte_len = SZ_64K / 8, + .name = "at25640a", + .page_size = 32, + .flags = EE_ADDR2, +}; + +static struct spi_board_info dm355_evm_spi_info[] __initconst = { + { + .modalias = "at25", + .platform_data = &at25640a, + .max_speed_hz = 10 * 1000 * 1000, /* at 3v3 */ + .bus_num = 0, + .chip_select = 0, + .mode = SPI_MODE_0, + }, +}; + +static __init void dm355_evm_init(void) +{ + struct clk *aemif; + + gpio_request(1, "dm9000"); + gpio_direction_input(1); + dm355evm_dm9000_rsrc[2].start = gpio_to_irq(1); + + aemif = clk_get(&dm355evm_dm9000.dev, "aemif"); + if (IS_ERR(aemif)) + WARN("%s: unable to get AEMIF clock\n", __func__); + else + clk_enable(aemif); + + platform_add_devices(davinci_evm_devices, + ARRAY_SIZE(davinci_evm_devices)); + evm_init_i2c(); + davinci_serial_init(&uart_config); + + /* NOTE: NAND flash timings set by the UBL are slower than + * needed by MT29F16G08FAA chips ... EMIF.A1CR is 0x40400204 + * but could be 0x0400008c for about 25% faster page reads. + */ + + gpio_request(2, "usb_id_toggle"); + gpio_direction_output(2, USB_ID_VALUE); + /* irlml6401 switches over 1A in under 8 msec */ + setup_usb(500, 8); + + davinci_setup_mmc(0, &dm355evm_mmc_config); + davinci_setup_mmc(1, &dm355evm_mmc_config); + + dm355_init_spi0(BIT(0), dm355_evm_spi_info, + ARRAY_SIZE(dm355_evm_spi_info)); +} + +static __init void dm355_evm_irq_init(void) +{ + davinci_irq_init(); +} + +MACHINE_START(DAVINCI_DM355_EVM, "DaVinci DM355 EVM") + .phys_io = IO_PHYS, + .io_pg_offst = (__IO_ADDRESS(IO_PHYS) >> 18) & 0xfffc, + .boot_params = (0x80000100), + .map_io = dm355_evm_map_io, + .init_irq = dm355_evm_irq_init, + .timer = &davinci_timer, + .init_machine = dm355_evm_init, +MACHINE_END diff --git a/arch/arm/mach-davinci/board-dm355-leopard.c b/arch/arm/mach-davinci/board-dm355-leopard.c new file mode 100644 index 000000000000..28c9008df4f4 --- /dev/null +++ b/arch/arm/mach-davinci/board-dm355-leopard.c @@ -0,0 +1,296 @@ +/* + * DM355 leopard board support + * + * Based on board-dm355-evm.c + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DAVINCI_ASYNC_EMIF_CONTROL_BASE 0x01e10000 +#define DAVINCI_ASYNC_EMIF_DATA_CE0_BASE 0x02000000 + +/* NOTE: this is geared for the standard config, with a socketed + * 2 GByte Micron NAND (MT29F16G08FAA) using 128KB sectors. If you + * swap chips, maybe with a different block size, partitioning may + * need to be changed. + */ +#define NAND_BLOCK_SIZE SZ_128K + +static struct mtd_partition davinci_nand_partitions[] = { + { + /* UBL (a few copies) plus U-Boot */ + .name = "bootloader", + .offset = 0, + .size = 15 * NAND_BLOCK_SIZE, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, { + /* U-Boot environment */ + .name = "params", + .offset = MTDPART_OFS_APPEND, + .size = 1 * NAND_BLOCK_SIZE, + .mask_flags = 0, + }, { + .name = "kernel", + .offset = MTDPART_OFS_APPEND, + .size = SZ_4M, + .mask_flags = 0, + }, { + .name = "filesystem1", + .offset = MTDPART_OFS_APPEND, + .size = SZ_512M, + .mask_flags = 0, + }, { + .name = "filesystem2", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL, + .mask_flags = 0, + } + /* two blocks with bad block table (and mirror) at the end */ +}; + +static struct davinci_nand_pdata davinci_nand_data = { + .mask_chipsel = BIT(14), + .parts = davinci_nand_partitions, + .nr_parts = ARRAY_SIZE(davinci_nand_partitions), + .ecc_mode = NAND_ECC_HW_SYNDROME, + .options = NAND_USE_FLASH_BBT, +}; + +static struct resource davinci_nand_resources[] = { + { + .start = DAVINCI_ASYNC_EMIF_DATA_CE0_BASE, + .end = DAVINCI_ASYNC_EMIF_DATA_CE0_BASE + SZ_32M - 1, + .flags = IORESOURCE_MEM, + }, { + .start = DAVINCI_ASYNC_EMIF_CONTROL_BASE, + .end = DAVINCI_ASYNC_EMIF_CONTROL_BASE + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device davinci_nand_device = { + .name = "davinci_nand", + .id = 0, + + .num_resources = ARRAY_SIZE(davinci_nand_resources), + .resource = davinci_nand_resources, + + .dev = { + .platform_data = &davinci_nand_data, + }, +}; + +static struct davinci_i2c_platform_data i2c_pdata = { + .bus_freq = 400 /* kHz */, + .bus_delay = 0 /* usec */, +}; + +static int leopard_mmc_gpio = -EINVAL; + +static void dm355leopard_mmcsd_gpios(unsigned gpio) +{ + gpio_request(gpio + 0, "mmc0_ro"); + gpio_request(gpio + 1, "mmc0_cd"); + gpio_request(gpio + 2, "mmc1_ro"); + gpio_request(gpio + 3, "mmc1_cd"); + + /* we "know" these are input-only so we don't + * need to call gpio_direction_input() + */ + + leopard_mmc_gpio = gpio; +} + +static struct i2c_board_info dm355leopard_i2c_info[] = { + { I2C_BOARD_INFO("dm355leopard_msp", 0x25), + .platform_data = dm355leopard_mmcsd_gpios, + /* plus irq */ }, + /* { I2C_BOARD_INFO("tlv320aic3x", 0x1b), }, */ + /* { I2C_BOARD_INFO("tvp5146", 0x5d), }, */ +}; + +static void __init leopard_init_i2c(void) +{ + davinci_init_i2c(&i2c_pdata); + + gpio_request(5, "dm355leopard_msp"); + gpio_direction_input(5); + dm355leopard_i2c_info[0].irq = gpio_to_irq(5); + + i2c_register_board_info(1, dm355leopard_i2c_info, + ARRAY_SIZE(dm355leopard_i2c_info)); +} + +static struct resource dm355leopard_dm9000_rsrc[] = { + { + /* addr */ + .start = 0x04000000, + .end = 0x04000001, + .flags = IORESOURCE_MEM, + }, { + /* data */ + .start = 0x04000016, + .end = 0x04000017, + .flags = IORESOURCE_MEM, + }, { + .flags = IORESOURCE_IRQ + | IORESOURCE_IRQ_HIGHEDGE /* rising (active high) */, + }, +}; + +static struct platform_device dm355leopard_dm9000 = { + .name = "dm9000", + .id = -1, + .resource = dm355leopard_dm9000_rsrc, + .num_resources = ARRAY_SIZE(dm355leopard_dm9000_rsrc), +}; + +static struct platform_device *davinci_leopard_devices[] __initdata = { + &dm355leopard_dm9000, + &davinci_nand_device, +}; + +static struct davinci_uart_config uart_config __initdata = { + .enabled_uarts = (1 << 0), +}; + +static void __init dm355_leopard_map_io(void) +{ + dm355_init(); +} + +static int dm355leopard_mmc_get_cd(int module) +{ + if (!gpio_is_valid(leopard_mmc_gpio)) + return -ENXIO; + /* low == card present */ + return !gpio_get_value_cansleep(leopard_mmc_gpio + 2 * module + 1); +} + +static int dm355leopard_mmc_get_ro(int module) +{ + if (!gpio_is_valid(leopard_mmc_gpio)) + return -ENXIO; + /* high == card's write protect switch active */ + return gpio_get_value_cansleep(leopard_mmc_gpio + 2 * module + 0); +} + +static struct davinci_mmc_config dm355leopard_mmc_config = { + .get_cd = dm355leopard_mmc_get_cd, + .get_ro = dm355leopard_mmc_get_ro, + .wires = 4, + .max_freq = 50000000, + .caps = MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED, +}; + +/* Don't connect anything to J10 unless you're only using USB host + * mode *and* have to do so with some kind of gender-bender. If + * you have proper Mini-B or Mini-A cables (or Mini-A adapters) + * the ID pin won't need any help. + */ +#ifdef CONFIG_USB_MUSB_PERIPHERAL +#define USB_ID_VALUE 0 /* ID pulled high; *should* float */ +#else +#define USB_ID_VALUE 1 /* ID pulled low */ +#endif + +static struct spi_eeprom at25640a = { + .byte_len = SZ_64K / 8, + .name = "at25640a", + .page_size = 32, + .flags = EE_ADDR2, +}; + +static struct spi_board_info dm355_leopard_spi_info[] __initconst = { + { + .modalias = "at25", + .platform_data = &at25640a, + .max_speed_hz = 10 * 1000 * 1000, /* at 3v3 */ + .bus_num = 0, + .chip_select = 0, + .mode = SPI_MODE_0, + }, +}; + +static __init void dm355_leopard_init(void) +{ + struct clk *aemif; + + gpio_request(9, "dm9000"); + gpio_direction_input(9); + dm355leopard_dm9000_rsrc[2].start = gpio_to_irq(9); + + aemif = clk_get(&dm355leopard_dm9000.dev, "aemif"); + if (IS_ERR(aemif)) + WARN("%s: unable to get AEMIF clock\n", __func__); + else + clk_enable(aemif); + + platform_add_devices(davinci_leopard_devices, + ARRAY_SIZE(davinci_leopard_devices)); + leopard_init_i2c(); + davinci_serial_init(&uart_config); + + /* NOTE: NAND flash timings set by the UBL are slower than + * needed by MT29F16G08FAA chips ... EMIF.A1CR is 0x40400204 + * but could be 0x0400008c for about 25% faster page reads. + */ + + gpio_request(2, "usb_id_toggle"); + gpio_direction_output(2, USB_ID_VALUE); + /* irlml6401 switches over 1A in under 8 msec */ + setup_usb(500, 8); + + davinci_setup_mmc(0, &dm355leopard_mmc_config); + davinci_setup_mmc(1, &dm355leopard_mmc_config); + + dm355_init_spi0(BIT(0), dm355_leopard_spi_info, + ARRAY_SIZE(dm355_leopard_spi_info)); +} + +static __init void dm355_leopard_irq_init(void) +{ + davinci_irq_init(); +} + +MACHINE_START(DM355_LEOPARD, "DaVinci DM355 leopard") + .phys_io = IO_PHYS, + .io_pg_offst = (__IO_ADDRESS(IO_PHYS) >> 18) & 0xfffc, + .boot_params = (0x80000100), + .map_io = dm355_leopard_map_io, + .init_irq = dm355_leopard_irq_init, + .timer = &davinci_timer, + .init_machine = dm355_leopard_init, +MACHINE_END diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c index b2e7f9c63bc5..d9d40450bdc5 100644 --- a/arch/arm/mach-davinci/board-dm644x-evm.c +++ b/arch/arm/mach-davinci/board-dm644x-evm.c @@ -16,12 +16,11 @@ #include #include #include -#include #include #include #include - +#include #include #include #include @@ -44,6 +43,9 @@ #include #include #include +#include +#include +#include #define DM644X_EVM_PHY_MASK (0x2) #define DM644X_EVM_MDIO_FREQUENCY (2200000) /* PHY bus frequency */ @@ -436,45 +438,15 @@ static struct pcf857x_platform_data pcf_data_u35 = { * - 0x0039, 1 byte NTSC vs PAL (bit 0x80 == PAL) * - ... newer boards may have more */ -static struct memory_accessor *at24_mem_acc; - -static void at24_setup(struct memory_accessor *mem_acc, void *context) -{ - DECLARE_MAC_BUF(mac_str); - char mac_addr[6]; - - at24_mem_acc = mem_acc; - - /* Read MAC addr from EEPROM */ - if (at24_mem_acc->read(at24_mem_acc, mac_addr, 0x7f00, 6) == 6) { - printk(KERN_INFO "Read MAC addr from EEPROM: %s\n", - print_mac(mac_str, mac_addr)); - } -} static struct at24_platform_data eeprom_info = { .byte_len = (256*1024) / 8, .page_size = 64, .flags = AT24_FLAG_ADDR16, - .setup = at24_setup, + .setup = davinci_get_mac_addr, + .context = (void *)0x7f00, }; -int dm6446evm_eeprom_read(void *buf, off_t off, size_t count) -{ - if (at24_mem_acc) - return at24_mem_acc->read(at24_mem_acc, buf, off, count); - return -ENODEV; -} -EXPORT_SYMBOL(dm6446evm_eeprom_read); - -int dm6446evm_eeprom_write(void *buf, off_t off, size_t count) -{ - if (at24_mem_acc) - return at24_mem_acc->write(at24_mem_acc, buf, off, count); - return -ENODEV; -} -EXPORT_SYMBOL(dm6446evm_eeprom_write); - /* * MSP430 supports RTC, card detection, input from IR remote, and * a bit more. It triggers interrupts on GPIO(7) from pressing @@ -545,6 +517,27 @@ static int dm6444evm_msp430_get_pins(void) return (buf[3] << 8) | buf[2]; } +static int dm6444evm_mmc_get_cd(int module) +{ + int status = dm6444evm_msp430_get_pins(); + + return (status < 0) ? status : !(status & BIT(1)); +} + +static int dm6444evm_mmc_get_ro(int module) +{ + int status = dm6444evm_msp430_get_pins(); + + return (status < 0) ? status : status & BIT(6 + 8); +} + +static struct davinci_mmc_config dm6446evm_mmc_config = { + .get_cd = dm6444evm_mmc_get_cd, + .get_ro = dm6444evm_mmc_get_ro, + .wires = 4, + .version = MMC_CTLR_VERSION_1 +}; + static struct i2c_board_info __initdata i2c_info[] = { { I2C_BOARD_INFO("dm6446evm_msp", 0x23), @@ -598,7 +591,6 @@ static struct davinci_uart_config uart_config __initdata = { static void __init davinci_evm_map_io(void) { - davinci_map_common_io(); dm644x_init(); } @@ -639,6 +631,7 @@ static int davinci_phy_fixup(struct phy_device *phydev) static __init void davinci_evm_init(void) { struct clk *aemif_clk; + struct davinci_soc_info *soc_info = &davinci_soc_info; aemif_clk = clk_get(NULL, "aemif"); clk_enable(aemif_clk); @@ -671,8 +664,13 @@ static __init void davinci_evm_init(void) ARRAY_SIZE(davinci_evm_devices)); evm_init_i2c(); + davinci_setup_mmc(0, &dm6446evm_mmc_config); + davinci_serial_init(&uart_config); + soc_info->emac_pdata->phy_mask = DM644X_EVM_PHY_MASK; + soc_info->emac_pdata->mdio_max_freq = DM644X_EVM_MDIO_FREQUENCY; + /* Register the fixup for PHY on DaVinci */ phy_register_fixup_for_uid(LXT971_PHY_ID, LXT971_PHY_MASK, davinci_phy_fixup); diff --git a/arch/arm/mach-davinci/board-dm646x-evm.c b/arch/arm/mach-davinci/board-dm646x-evm.c new file mode 100644 index 000000000000..e17de6352624 --- /dev/null +++ b/arch/arm/mach-davinci/board-dm646x-evm.c @@ -0,0 +1,262 @@ +/* + * TI DaVinci DM646X EVM board + * + * Derived from: arch/arm/mach-davinci/board-evm.c + * Copyright (C) 2006 Texas Instruments. + * + * (C) 2007-2008, 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. + * + */ + +/************************************************************************** + * Included Files + **************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#define DM646X_EVM_PHY_MASK (0x2) +#define DM646X_EVM_MDIO_FREQUENCY (2200000) /* PHY bus frequency */ + +static struct davinci_uart_config uart_config __initdata = { + .enabled_uarts = (1 << 0), +}; + +/* LEDS */ + +static struct gpio_led evm_leds[] = { + { .name = "DS1", .active_low = 1, }, + { .name = "DS2", .active_low = 1, }, + { .name = "DS3", .active_low = 1, }, + { .name = "DS4", .active_low = 1, }, +}; + +static __initconst struct gpio_led_platform_data evm_led_data = { + .num_leds = ARRAY_SIZE(evm_leds), + .leds = evm_leds, +}; + +static struct platform_device *evm_led_dev; + +static int evm_led_setup(struct i2c_client *client, int gpio, + unsigned int ngpio, void *c) +{ + struct gpio_led *leds = evm_leds; + int status; + + while (ngpio--) { + leds->gpio = gpio++; + leds++; + }; + + evm_led_dev = platform_device_alloc("leds-gpio", 0); + platform_device_add_data(evm_led_dev, &evm_led_data, + sizeof(evm_led_data)); + + evm_led_dev->dev.parent = &client->dev; + status = platform_device_add(evm_led_dev); + if (status < 0) { + platform_device_put(evm_led_dev); + evm_led_dev = NULL; + } + return status; +} + +static int evm_led_teardown(struct i2c_client *client, int gpio, + unsigned ngpio, void *c) +{ + if (evm_led_dev) { + platform_device_unregister(evm_led_dev); + evm_led_dev = NULL; + } + return 0; +} + +static int evm_sw_gpio[4] = { -EINVAL, -EINVAL, -EINVAL, -EINVAL }; + +static int evm_sw_setup(struct i2c_client *client, int gpio, + unsigned ngpio, void *c) +{ + int status; + int i; + char label[10]; + + for (i = 0; i < 4; ++i) { + snprintf(label, 10, "user_sw%d", i); + status = gpio_request(gpio, label); + if (status) + goto out_free; + evm_sw_gpio[i] = gpio++; + + status = gpio_direction_input(evm_sw_gpio[i]); + if (status) { + gpio_free(evm_sw_gpio[i]); + evm_sw_gpio[i] = -EINVAL; + goto out_free; + } + + status = gpio_export(evm_sw_gpio[i], 0); + if (status) { + gpio_free(evm_sw_gpio[i]); + evm_sw_gpio[i] = -EINVAL; + goto out_free; + } + } + return status; +out_free: + for (i = 0; i < 4; ++i) { + if (evm_sw_gpio[i] != -EINVAL) { + gpio_free(evm_sw_gpio[i]); + evm_sw_gpio[i] = -EINVAL; + } + } + return status; +} + +static int evm_sw_teardown(struct i2c_client *client, int gpio, + unsigned ngpio, void *c) +{ + int i; + + for (i = 0; i < 4; ++i) { + if (evm_sw_gpio[i] != -EINVAL) { + gpio_unexport(evm_sw_gpio[i]); + gpio_free(evm_sw_gpio[i]); + evm_sw_gpio[i] = -EINVAL; + } + } + return 0; +} + +static int evm_pcf_setup(struct i2c_client *client, int gpio, + unsigned int ngpio, void *c) +{ + int status; + + if (ngpio < 8) + return -EINVAL; + + status = evm_sw_setup(client, gpio, 4, c); + if (status) + return status; + + return evm_led_setup(client, gpio+4, 4, c); +} + +static int evm_pcf_teardown(struct i2c_client *client, int gpio, + unsigned int ngpio, void *c) +{ + BUG_ON(ngpio < 8); + + evm_sw_teardown(client, gpio, 4, c); + evm_led_teardown(client, gpio+4, 4, c); + + return 0; +} + +static struct pcf857x_platform_data pcf_data = { + .gpio_base = DAVINCI_N_GPIO+1, + .setup = evm_pcf_setup, + .teardown = evm_pcf_teardown, +}; + +/* Most of this EEPROM is unused, but U-Boot uses some data: + * - 0x7f00, 6 bytes Ethernet Address + * - ... newer boards may have more + */ + +static struct at24_platform_data eeprom_info = { + .byte_len = (256*1024) / 8, + .page_size = 64, + .flags = AT24_FLAG_ADDR16, + .setup = davinci_get_mac_addr, + .context = (void *)0x7f00, +}; + +static struct i2c_board_info __initdata i2c_info[] = { + { + I2C_BOARD_INFO("24c256", 0x50), + .platform_data = &eeprom_info, + }, + { + I2C_BOARD_INFO("pcf8574a", 0x38), + .platform_data = &pcf_data, + }, +}; + +static struct davinci_i2c_platform_data i2c_pdata = { + .bus_freq = 100 /* kHz */, + .bus_delay = 0 /* usec */, +}; + +static void __init evm_init_i2c(void) +{ + davinci_init_i2c(&i2c_pdata); + i2c_register_board_info(1, i2c_info, ARRAY_SIZE(i2c_info)); +} + +static void __init davinci_map_io(void) +{ + dm646x_init(); +} + +static __init void evm_init(void) +{ + struct davinci_soc_info *soc_info = &davinci_soc_info; + + evm_init_i2c(); + davinci_serial_init(&uart_config); + + soc_info->emac_pdata->phy_mask = DM646X_EVM_PHY_MASK; + soc_info->emac_pdata->mdio_max_freq = DM646X_EVM_MDIO_FREQUENCY; +} + +static __init void davinci_dm646x_evm_irq_init(void) +{ + davinci_irq_init(); +} + +MACHINE_START(DAVINCI_DM6467_EVM, "DaVinci DM646x EVM") + .phys_io = IO_PHYS, + .io_pg_offst = (__IO_ADDRESS(IO_PHYS) >> 18) & 0xfffc, + .boot_params = (0x80000100), + .map_io = davinci_map_io, + .init_irq = davinci_dm646x_evm_irq_init, + .timer = &davinci_timer, + .init_machine = evm_init, +MACHINE_END + diff --git a/arch/arm/mach-davinci/board-sffsdr.c b/arch/arm/mach-davinci/board-sffsdr.c new file mode 100644 index 000000000000..748a8e48541e --- /dev/null +++ b/arch/arm/mach-davinci/board-sffsdr.c @@ -0,0 +1,189 @@ +/* + * Lyrtech SFFSDR board support. + * + * Copyright (C) 2008 Philip Balister, OpenSDR + * Copyright (C) 2008 Lyrtech + * + * Based on DV-EVM platform, original copyright follows: + * + * Copyright (C) 2007 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. + * + * 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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define SFFSDR_PHY_MASK (0x2) +#define SFFSDR_MDIO_FREQUENCY (2200000) /* PHY bus frequency */ + +#define DAVINCI_ASYNC_EMIF_CONTROL_BASE 0x01e00000 +#define DAVINCI_ASYNC_EMIF_DATA_CE0_BASE 0x02000000 + +struct mtd_partition davinci_sffsdr_nandflash_partition[] = { + /* U-Boot Environment: Block 0 + * UBL: Block 1 + * U-Boot: Blocks 6-7 (256 kb) + * Integrity Kernel: Blocks 8-31 (3 Mb) + * Integrity Data: Blocks 100-END + */ + { + .name = "Linux Kernel", + .offset = 32 * SZ_128K, + .size = 16 * SZ_128K, /* 2 Mb */ + .mask_flags = MTD_WRITEABLE, /* Force read-only */ + }, + { + .name = "Linux ROOT", + .offset = MTDPART_OFS_APPEND, + .size = 256 * SZ_128K, /* 32 Mb */ + .mask_flags = 0, /* R/W */ + }, +}; + +static struct flash_platform_data davinci_sffsdr_nandflash_data = { + .parts = davinci_sffsdr_nandflash_partition, + .nr_parts = ARRAY_SIZE(davinci_sffsdr_nandflash_partition), +}; + +static struct resource davinci_sffsdr_nandflash_resource[] = { + { + .start = DAVINCI_ASYNC_EMIF_DATA_CE0_BASE, + .end = DAVINCI_ASYNC_EMIF_DATA_CE0_BASE + SZ_16M - 1, + .flags = IORESOURCE_MEM, + }, { + .start = DAVINCI_ASYNC_EMIF_CONTROL_BASE, + .end = DAVINCI_ASYNC_EMIF_CONTROL_BASE + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device davinci_sffsdr_nandflash_device = { + .name = "davinci_nand", /* Name of driver */ + .id = 0, + .dev = { + .platform_data = &davinci_sffsdr_nandflash_data, + }, + .num_resources = ARRAY_SIZE(davinci_sffsdr_nandflash_resource), + .resource = davinci_sffsdr_nandflash_resource, +}; + +static struct emac_platform_data sffsdr_emac_pdata = { + .phy_mask = SFFSDR_PHY_MASK, + .mdio_max_freq = SFFSDR_MDIO_FREQUENCY, +}; + +static struct at24_platform_data eeprom_info = { + .byte_len = (64*1024) / 8, + .page_size = 32, + .flags = AT24_FLAG_ADDR16, +}; + +static struct i2c_board_info __initdata i2c_info[] = { + { + I2C_BOARD_INFO("24lc64", 0x50), + .platform_data = &eeprom_info, + }, + /* Other I2C devices: + * MSP430, addr 0x23 (not used) + * PCA9543, addr 0x70 (setup done by U-Boot) + * ADS7828, addr 0x48 (ADC for voltage monitoring.) + */ +}; + +static struct davinci_i2c_platform_data i2c_pdata = { + .bus_freq = 20 /* kHz */, + .bus_delay = 100 /* usec */, +}; + +static void __init sffsdr_init_i2c(void) +{ + davinci_init_i2c(&i2c_pdata); + i2c_register_board_info(1, i2c_info, ARRAY_SIZE(i2c_info)); +} + +static struct platform_device *davinci_sffsdr_devices[] __initdata = { + &davinci_sffsdr_nandflash_device, +}; + +static struct davinci_uart_config uart_config __initdata = { + .enabled_uarts = (1 << 0), +}; + +static void __init davinci_sffsdr_map_io(void) +{ + dm644x_init(); +} + +static __init void davinci_sffsdr_init(void) +{ + struct davinci_soc_info *soc_info = &davinci_soc_info; + + platform_add_devices(davinci_sffsdr_devices, + ARRAY_SIZE(davinci_sffsdr_devices)); + sffsdr_init_i2c(); + davinci_serial_init(&uart_config); + soc_info->emac_pdata->phy_mask = SFFSDR_PHY_MASK; + soc_info->emac_pdata->mdio_max_freq = SFFSDR_MDIO_FREQUENCY; + setup_usb(0, 0); /* We support only peripheral mode. */ + + /* mux VLYNQ pins */ + davinci_cfg_reg(DM644X_VLYNQEN); + davinci_cfg_reg(DM644X_VLYNQWD); +} + +static __init void davinci_sffsdr_irq_init(void) +{ + davinci_irq_init(); +} + +MACHINE_START(SFFSDR, "Lyrtech SFFSDR") + /* Maintainer: Hugo Villeneuve hugo.villeneuve@lyrtech.com */ + .phys_io = IO_PHYS, + .io_pg_offst = (__IO_ADDRESS(IO_PHYS) >> 18) & 0xfffc, + .boot_params = (DAVINCI_DDR_BASE + 0x100), + .map_io = davinci_sffsdr_map_io, + .init_irq = davinci_sffsdr_irq_init, + .timer = &davinci_timer, + .init_machine = davinci_sffsdr_init, +MACHINE_END diff --git a/arch/arm/mach-davinci/clock.c b/arch/arm/mach-davinci/clock.c index f0baaa15a57e..39bf321d70a2 100644 --- a/arch/arm/mach-davinci/clock.c +++ b/arch/arm/mach-davinci/clock.c @@ -42,7 +42,8 @@ static void __clk_enable(struct clk *clk) if (clk->parent) __clk_enable(clk->parent); if (clk->usecount++ == 0 && (clk->flags & CLK_PSC)) - davinci_psc_config(psc_domain(clk), clk->lpsc, 1); + davinci_psc_config(psc_domain(clk), clk->psc_ctlr, + clk->lpsc, 1); } static void __clk_disable(struct clk *clk) @@ -50,7 +51,8 @@ static void __clk_disable(struct clk *clk) if (WARN_ON(clk->usecount == 0)) return; if (--clk->usecount == 0 && !(clk->flags & CLK_PLL)) - davinci_psc_config(psc_domain(clk), clk->lpsc, 0); + davinci_psc_config(psc_domain(clk), clk->psc_ctlr, + clk->lpsc, 0); if (clk->parent) __clk_disable(clk->parent); } @@ -164,11 +166,11 @@ static int __init clk_disable_unused(void) continue; /* ignore if in Disabled or SwRstDisable states */ - if (!davinci_psc_is_clk_active(ck->lpsc)) + if (!davinci_psc_is_clk_active(ck->psc_ctlr, ck->lpsc)) continue; pr_info("Clocks: disable unused %s\n", ck->name); - davinci_psc_config(psc_domain(ck), ck->lpsc, 0); + davinci_psc_config(psc_domain(ck), ck->psc_ctlr, ck->lpsc, 0); } spin_unlock_irq(&clockfw_lock); diff --git a/arch/arm/mach-davinci/clock.h b/arch/arm/mach-davinci/clock.h index 35736ec202f8..27233cb4a2fb 100644 --- a/arch/arm/mach-davinci/clock.h +++ b/arch/arm/mach-davinci/clock.h @@ -67,6 +67,7 @@ struct clk { u8 usecount; u8 flags; u8 lpsc; + u8 psc_ctlr; struct clk *parent; struct pll_data *pll_data; u32 div_reg; @@ -93,4 +94,7 @@ struct davinci_clk { } int davinci_clk_init(struct davinci_clk *clocks); + +extern struct platform_device davinci_wdt_device; + #endif diff --git a/arch/arm/mach-davinci/common.c b/arch/arm/mach-davinci/common.c new file mode 100644 index 000000000000..61ede19c6b54 --- /dev/null +++ b/arch/arm/mach-davinci/common.c @@ -0,0 +1,108 @@ +/* + * Code commons to all DaVinci SoCs. + * + * Author: Mark A. Greer + * + * 2009 (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. + */ +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "clock.h" + +struct davinci_soc_info davinci_soc_info; +EXPORT_SYMBOL(davinci_soc_info); + +void __iomem *davinci_intc_base; +int davinci_intc_type; + +void davinci_get_mac_addr(struct memory_accessor *mem_acc, void *context) +{ + char *mac_addr = davinci_soc_info.emac_pdata->mac_addr; + off_t offset = (off_t)context; + + /* Read MAC addr from EEPROM */ + if (mem_acc->read(mem_acc, mac_addr, offset, ETH_ALEN) == ETH_ALEN) + pr_info("Read MAC addr from EEPROM: %pM\n", mac_addr); +} + +static struct davinci_id * __init davinci_get_id(u32 jtag_id) +{ + int i; + struct davinci_id *dip; + u8 variant = (jtag_id & 0xf0000000) >> 28; + u16 part_no = (jtag_id & 0x0ffff000) >> 12; + + for (i = 0, dip = davinci_soc_info.ids; i < davinci_soc_info.ids_num; + i++, dip++) + /* Don't care about the manufacturer right now */ + if ((dip->part_no == part_no) && (dip->variant == variant)) + return dip; + + return NULL; +} + +void __init davinci_common_init(struct davinci_soc_info *soc_info) +{ + int ret; + struct davinci_id *dip; + + if (!soc_info) { + ret = -EINVAL; + goto err; + } + + memcpy(&davinci_soc_info, soc_info, sizeof(struct davinci_soc_info)); + + if (davinci_soc_info.io_desc && (davinci_soc_info.io_desc_num > 0)) + iotable_init(davinci_soc_info.io_desc, + davinci_soc_info.io_desc_num); + + /* + * Normally devicemaps_init() would flush caches and tlb after + * mdesc->map_io(), but we must also do it here because of the CPU + * revision check below. + */ + local_flush_tlb_all(); + flush_cache_all(); + + /* + * We want to check CPU revision early for cpu_is_xxxx() macros. + * IO space mapping must be initialized before we can do that. + */ + davinci_soc_info.jtag_id = __raw_readl(davinci_soc_info.jtag_id_base); + + dip = davinci_get_id(davinci_soc_info.jtag_id); + if (!dip) { + ret = -EINVAL; + goto err; + } + + davinci_soc_info.cpu_id = dip->cpu_id; + pr_info("DaVinci %s variant 0x%x\n", dip->name, dip->variant); + + if (davinci_soc_info.cpu_clks) { + ret = davinci_clk_init(davinci_soc_info.cpu_clks); + + if (ret != 0) + goto err; + } + + davinci_intc_base = davinci_soc_info.intc_base; + davinci_intc_type = davinci_soc_info.intc_type; + return; + +err: + pr_err("davinci_common_init: SoC Initialization failed\n"); +} diff --git a/arch/arm/mach-davinci/cp_intc.c b/arch/arm/mach-davinci/cp_intc.c new file mode 100644 index 000000000000..96c8e97a7deb --- /dev/null +++ b/arch/arm/mach-davinci/cp_intc.c @@ -0,0 +1,161 @@ +/* + * TI Common Platform Interrupt Controller (cp_intc) driver + * + * Author: Steve Chen + * Copyright (C) 2008-2009, 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. + */ + +#include +#include +#include +#include +#include +#include + +#include + +static void __iomem *cp_intc_base; + +static inline unsigned int cp_intc_read(unsigned offset) +{ + return __raw_readl(cp_intc_base + offset); +} + +static inline void cp_intc_write(unsigned long value, unsigned offset) +{ + __raw_writel(value, cp_intc_base + offset); +} + +static void cp_intc_ack_irq(unsigned int irq) +{ + cp_intc_write(irq, CP_INTC_SYS_STAT_IDX_CLR); +} + +/* Disable interrupt */ +static void cp_intc_mask_irq(unsigned int irq) +{ + /* XXX don't know why we need to disable nIRQ here... */ + cp_intc_write(1, CP_INTC_HOST_ENABLE_IDX_CLR); + cp_intc_write(irq, CP_INTC_SYS_ENABLE_IDX_CLR); + cp_intc_write(1, CP_INTC_HOST_ENABLE_IDX_SET); +} + +/* Enable interrupt */ +static void cp_intc_unmask_irq(unsigned int irq) +{ + cp_intc_write(irq, CP_INTC_SYS_ENABLE_IDX_SET); +} + +static int cp_intc_set_irq_type(unsigned int irq, unsigned int flow_type) +{ + unsigned reg = BIT_WORD(irq); + unsigned mask = BIT_MASK(irq); + unsigned polarity = cp_intc_read(CP_INTC_SYS_POLARITY(reg)); + unsigned type = cp_intc_read(CP_INTC_SYS_TYPE(reg)); + + switch (flow_type) { + case IRQ_TYPE_EDGE_RISING: + polarity |= mask; + type |= mask; + break; + case IRQ_TYPE_EDGE_FALLING: + polarity &= ~mask; + type |= mask; + break; + case IRQ_TYPE_LEVEL_HIGH: + polarity |= mask; + type &= ~mask; + break; + case IRQ_TYPE_LEVEL_LOW: + polarity &= ~mask; + type &= ~mask; + break; + default: + return -EINVAL; + } + + cp_intc_write(polarity, CP_INTC_SYS_POLARITY(reg)); + cp_intc_write(type, CP_INTC_SYS_TYPE(reg)); + + return 0; +} + +static struct irq_chip cp_intc_irq_chip = { + .name = "cp_intc", + .ack = cp_intc_ack_irq, + .mask = cp_intc_mask_irq, + .unmask = cp_intc_unmask_irq, + .set_type = cp_intc_set_irq_type, +}; + +void __init cp_intc_init(void __iomem *base, unsigned short num_irq, + u8 *irq_prio) +{ + unsigned num_reg = BITS_TO_LONGS(num_irq); + int i; + + cp_intc_base = base; + + cp_intc_write(0, CP_INTC_GLOBAL_ENABLE); + + /* Disable all host interrupts */ + cp_intc_write(0, CP_INTC_HOST_ENABLE(0)); + + /* Disable system interrupts */ + for (i = 0; i < num_reg; i++) + cp_intc_write(~0, CP_INTC_SYS_ENABLE_CLR(i)); + + /* Set to normal mode, no nesting, no priority hold */ + cp_intc_write(0, CP_INTC_CTRL); + cp_intc_write(0, CP_INTC_HOST_CTRL); + + /* Clear system interrupt status */ + for (i = 0; i < num_reg; i++) + cp_intc_write(~0, CP_INTC_SYS_STAT_CLR(i)); + + /* Enable nIRQ (what about nFIQ?) */ + cp_intc_write(1, CP_INTC_HOST_ENABLE_IDX_SET); + + /* + * Priority is determined by host channel: lower channel number has + * higher priority i.e. channel 0 has highest priority and channel 31 + * had the lowest priority. + */ + num_reg = (num_irq + 3) >> 2; /* 4 channels per register */ + if (irq_prio) { + unsigned j, k; + u32 val; + + for (k = i = 0; i < num_reg; i++) { + for (val = j = 0; j < 4; j++, k++) { + val >>= 8; + if (k < num_irq) + val |= irq_prio[k] << 24; + } + + cp_intc_write(val, CP_INTC_CHAN_MAP(i)); + } + } else { + /* + * Default everything to channel 15 if priority not specified. + * Note that channel 0-1 are mapped to nFIQ and channels 2-31 + * are mapped to nIRQ. + */ + for (i = 0; i < num_reg; i++) + cp_intc_write(0x0f0f0f0f, CP_INTC_CHAN_MAP(i)); + } + + /* Set up genirq dispatching for cp_intc */ + for (i = 0; i < num_irq; i++) { + set_irq_chip(i, &cp_intc_irq_chip); + set_irq_flags(i, IRQF_VALID | IRQF_PROBE); + set_irq_handler(i, handle_edge_irq); + } + + /* Enable global interrupt */ + cp_intc_write(1, CP_INTC_GLOBAL_ENABLE); +} diff --git a/arch/arm/mach-davinci/devices.c b/arch/arm/mach-davinci/devices.c index a31370b93dd2..de16f347566a 100644 --- a/arch/arm/mach-davinci/devices.c +++ b/arch/arm/mach-davinci/devices.c @@ -23,8 +23,14 @@ #include #include #include +#include +#include +#include #define DAVINCI_I2C_BASE 0x01C21000 +#define DAVINCI_MMCSD0_BASE 0x01E10000 +#define DM355_MMCSD0_BASE 0x01E11000 +#define DM355_MMCSD1_BASE 0x01E00000 static struct resource i2c_resources[] = { { @@ -54,3 +60,208 @@ void __init davinci_init_i2c(struct davinci_i2c_platform_data *pdata) (void) platform_device_register(&davinci_i2c_device); } +#if defined(CONFIG_MMC_DAVINCI) || defined(CONFIG_MMC_DAVINCI_MODULE) + +static u64 mmcsd0_dma_mask = DMA_BIT_MASK(32); + +static struct resource mmcsd0_resources[] = { + { + /* different on dm355 */ + .start = DAVINCI_MMCSD0_BASE, + .end = DAVINCI_MMCSD0_BASE + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + /* IRQs: MMC/SD, then SDIO */ + { + .start = IRQ_MMCINT, + .flags = IORESOURCE_IRQ, + }, { + /* different on dm355 */ + .start = IRQ_SDIOINT, + .flags = IORESOURCE_IRQ, + }, + /* DMA channels: RX, then TX */ + { + .start = DAVINCI_DMA_MMCRXEVT, + .flags = IORESOURCE_DMA, + }, { + .start = DAVINCI_DMA_MMCTXEVT, + .flags = IORESOURCE_DMA, + }, +}; + +static struct platform_device davinci_mmcsd0_device = { + .name = "davinci_mmc", + .id = 0, + .dev = { + .dma_mask = &mmcsd0_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + .num_resources = ARRAY_SIZE(mmcsd0_resources), + .resource = mmcsd0_resources, +}; + +static u64 mmcsd1_dma_mask = DMA_BIT_MASK(32); + +static struct resource mmcsd1_resources[] = { + { + .start = DM355_MMCSD1_BASE, + .end = DM355_MMCSD1_BASE + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + /* IRQs: MMC/SD, then SDIO */ + { + .start = IRQ_DM355_MMCINT1, + .flags = IORESOURCE_IRQ, + }, { + .start = IRQ_DM355_SDIOINT1, + .flags = IORESOURCE_IRQ, + }, + /* DMA channels: RX, then TX */ + { + .start = 30, /* rx */ + .flags = IORESOURCE_DMA, + }, { + .start = 31, /* tx */ + .flags = IORESOURCE_DMA, + }, +}; + +static struct platform_device davinci_mmcsd1_device = { + .name = "davinci_mmc", + .id = 1, + .dev = { + .dma_mask = &mmcsd1_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + .num_resources = ARRAY_SIZE(mmcsd1_resources), + .resource = mmcsd1_resources, +}; + + +void __init davinci_setup_mmc(int module, struct davinci_mmc_config *config) +{ + struct platform_device *pdev = NULL; + + if (WARN_ON(cpu_is_davinci_dm646x())) + return; + + /* REVISIT: update PINMUX, ARM_IRQMUX, and EDMA_EVTMUX here too; + * for example if MMCSD1 is used for SDIO, maybe DAT2 is unused. + * + * FIXME dm6441 (no MMC/SD), dm357 (one), and dm335 (two) are + * not handled right here ... + */ + switch (module) { + case 1: + if (!cpu_is_davinci_dm355()) + break; + + /* REVISIT we may not need all these pins if e.g. this + * is a hard-wired SDIO device... + */ + davinci_cfg_reg(DM355_SD1_CMD); + davinci_cfg_reg(DM355_SD1_CLK); + davinci_cfg_reg(DM355_SD1_DATA0); + davinci_cfg_reg(DM355_SD1_DATA1); + davinci_cfg_reg(DM355_SD1_DATA2); + davinci_cfg_reg(DM355_SD1_DATA3); + + pdev = &davinci_mmcsd1_device; + break; + case 0: + if (cpu_is_davinci_dm355()) { + mmcsd0_resources[0].start = DM355_MMCSD0_BASE; + mmcsd0_resources[0].end = DM355_MMCSD0_BASE + SZ_4K - 1; + mmcsd0_resources[2].start = IRQ_DM355_SDIOINT0; + + /* expose all 6 MMC0 signals: CLK, CMD, DATA[0..3] */ + davinci_cfg_reg(DM355_MMCSD0); + + /* enable RX EDMA */ + davinci_cfg_reg(DM355_EVT26_MMC0_RX); + } + + else if (cpu_is_davinci_dm644x()) { + /* REVISIT: should this be in board-init code? */ + void __iomem *base = + IO_ADDRESS(DAVINCI_SYSTEM_MODULE_BASE); + + /* Power-on 3.3V IO cells */ + __raw_writel(0, base + DM64XX_VDD3P3V_PWDN); + /*Set up the pull regiter for MMC */ + davinci_cfg_reg(DM644X_MSTK); + } + + pdev = &davinci_mmcsd0_device; + break; + } + + if (WARN_ON(!pdev)) + return; + + pdev->dev.platform_data = config; + platform_device_register(pdev); +} + +#else + +void __init davinci_setup_mmc(int module, struct davinci_mmc_config *config) +{ +} + +#endif + +/*-------------------------------------------------------------------------*/ + +static struct resource wdt_resources[] = { + { + .flags = IORESOURCE_MEM, + }, +}; + +struct platform_device davinci_wdt_device = { + .name = "watchdog", + .id = -1, + .num_resources = ARRAY_SIZE(wdt_resources), + .resource = wdt_resources, +}; + +static void davinci_init_wdt(void) +{ + struct davinci_soc_info *soc_info = &davinci_soc_info; + + wdt_resources[0].start = (resource_size_t)soc_info->wdt_base; + wdt_resources[0].end = (resource_size_t)soc_info->wdt_base + SZ_1K - 1; + + platform_device_register(&davinci_wdt_device); +} + +/*-------------------------------------------------------------------------*/ + +struct davinci_timer_instance davinci_timer_instance[2] = { + { + .base = IO_ADDRESS(DAVINCI_TIMER0_BASE), + .bottom_irq = IRQ_TINT0_TINT12, + .top_irq = IRQ_TINT0_TINT34, + }, + { + .base = IO_ADDRESS(DAVINCI_TIMER1_BASE), + .bottom_irq = IRQ_TINT1_TINT12, + .top_irq = IRQ_TINT1_TINT34, + }, +}; + +/*-------------------------------------------------------------------------*/ + +static int __init davinci_init_devices(void) +{ + /* please keep these calls, and their implementations above, + * in alphabetical order so they're easier to sort through. + */ + davinci_init_wdt(); + + return 0; +} +arch_initcall(davinci_init_devices); + diff --git a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach-davinci/dm355.c new file mode 100644 index 000000000000..baaaf328de2e --- /dev/null +++ b/arch/arm/mach-davinci/dm355.c @@ -0,0 +1,730 @@ +/* + * TI DaVinci DM355 chip specific setup + * + * Author: Kevin Hilman, Deep Root Systems, LLC + * + * 2007 (c) Deep Root Systems, LLC. 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 +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clock.h" +#include "mux.h" + +#define DM355_UART2_BASE (IO_PHYS + 0x206000) + +/* + * Device specific clocks + */ +#define DM355_REF_FREQ 24000000 /* 24 or 36 MHz */ + +static struct pll_data pll1_data = { + .num = 1, + .phys_base = DAVINCI_PLL1_BASE, + .flags = PLL_HAS_PREDIV | PLL_HAS_POSTDIV, +}; + +static struct pll_data pll2_data = { + .num = 2, + .phys_base = DAVINCI_PLL2_BASE, + .flags = PLL_HAS_PREDIV, +}; + +static struct clk ref_clk = { + .name = "ref_clk", + /* FIXME -- crystal rate is board-specific */ + .rate = DM355_REF_FREQ, +}; + +static struct clk pll1_clk = { + .name = "pll1", + .parent = &ref_clk, + .flags = CLK_PLL, + .pll_data = &pll1_data, +}; + +static struct clk pll1_aux_clk = { + .name = "pll1_aux_clk", + .parent = &pll1_clk, + .flags = CLK_PLL | PRE_PLL, +}; + +static struct clk pll1_sysclk1 = { + .name = "pll1_sysclk1", + .parent = &pll1_clk, + .flags = CLK_PLL, + .div_reg = PLLDIV1, +}; + +static struct clk pll1_sysclk2 = { + .name = "pll1_sysclk2", + .parent = &pll1_clk, + .flags = CLK_PLL, + .div_reg = PLLDIV2, +}; + +static struct clk pll1_sysclk3 = { + .name = "pll1_sysclk3", + .parent = &pll1_clk, + .flags = CLK_PLL, + .div_reg = PLLDIV3, +}; + +static struct clk pll1_sysclk4 = { + .name = "pll1_sysclk4", + .parent = &pll1_clk, + .flags = CLK_PLL, + .div_reg = PLLDIV4, +}; + +static struct clk pll1_sysclkbp = { + .name = "pll1_sysclkbp", + .parent = &pll1_clk, + .flags = CLK_PLL | PRE_PLL, + .div_reg = BPDIV +}; + +static struct clk vpss_dac_clk = { + .name = "vpss_dac", + .parent = &pll1_sysclk3, + .lpsc = DM355_LPSC_VPSS_DAC, +}; + +static struct clk vpss_master_clk = { + .name = "vpss_master", + .parent = &pll1_sysclk4, + .lpsc = DAVINCI_LPSC_VPSSMSTR, + .flags = CLK_PSC, +}; + +static struct clk vpss_slave_clk = { + .name = "vpss_slave", + .parent = &pll1_sysclk4, + .lpsc = DAVINCI_LPSC_VPSSSLV, +}; + + +static struct clk clkout1_clk = { + .name = "clkout1", + .parent = &pll1_aux_clk, + /* NOTE: clkout1 can be externally gated by muxing GPIO-18 */ +}; + +static struct clk clkout2_clk = { + .name = "clkout2", + .parent = &pll1_sysclkbp, +}; + +static struct clk pll2_clk = { + .name = "pll2", + .parent = &ref_clk, + .flags = CLK_PLL, + .pll_data = &pll2_data, +}; + +static struct clk pll2_sysclk1 = { + .name = "pll2_sysclk1", + .parent = &pll2_clk, + .flags = CLK_PLL, + .div_reg = PLLDIV1, +}; + +static struct clk pll2_sysclkbp = { + .name = "pll2_sysclkbp", + .parent = &pll2_clk, + .flags = CLK_PLL | PRE_PLL, + .div_reg = BPDIV +}; + +static struct clk clkout3_clk = { + .name = "clkout3", + .parent = &pll2_sysclkbp, + /* NOTE: clkout3 can be externally gated by muxing GPIO-16 */ +}; + +static struct clk arm_clk = { + .name = "arm_clk", + .parent = &pll1_sysclk1, + .lpsc = DAVINCI_LPSC_ARM, + .flags = ALWAYS_ENABLED, +}; + +/* + * NOT LISTED below, and not touched by Linux + * - in SyncReset state by default + * .lpsc = DAVINCI_LPSC_TPCC, + * .lpsc = DAVINCI_LPSC_TPTC0, + * .lpsc = DAVINCI_LPSC_TPTC1, + * .lpsc = DAVINCI_LPSC_DDR_EMIF, .parent = &sysclk2_clk, + * .lpsc = DAVINCI_LPSC_MEMSTICK, + * - in Enabled state by default + * .lpsc = DAVINCI_LPSC_SYSTEM_SUBSYS, + * .lpsc = DAVINCI_LPSC_SCR2, // "bus" + * .lpsc = DAVINCI_LPSC_SCR3, // "bus" + * .lpsc = DAVINCI_LPSC_SCR4, // "bus" + * .lpsc = DAVINCI_LPSC_CROSSBAR, // "emulation" + * .lpsc = DAVINCI_LPSC_CFG27, // "test" + * .lpsc = DAVINCI_LPSC_CFG3, // "test" + * .lpsc = DAVINCI_LPSC_CFG5, // "test" + */ + +static struct clk mjcp_clk = { + .name = "mjcp", + .parent = &pll1_sysclk1, + .lpsc = DAVINCI_LPSC_IMCOP, +}; + +static struct clk uart0_clk = { + .name = "uart0", + .parent = &pll1_aux_clk, + .lpsc = DAVINCI_LPSC_UART0, +}; + +static struct clk uart1_clk = { + .name = "uart1", + .parent = &pll1_aux_clk, + .lpsc = DAVINCI_LPSC_UART1, +}; + +static struct clk uart2_clk = { + .name = "uart2", + .parent = &pll1_sysclk2, + .lpsc = DAVINCI_LPSC_UART2, +}; + +static struct clk i2c_clk = { + .name = "i2c", + .parent = &pll1_aux_clk, + .lpsc = DAVINCI_LPSC_I2C, +}; + +static struct clk asp0_clk = { + .name = "asp0", + .parent = &pll1_sysclk2, + .lpsc = DAVINCI_LPSC_McBSP, +}; + +static struct clk asp1_clk = { + .name = "asp1", + .parent = &pll1_sysclk2, + .lpsc = DM355_LPSC_McBSP1, +}; + +static struct clk mmcsd0_clk = { + .name = "mmcsd0", + .parent = &pll1_sysclk2, + .lpsc = DAVINCI_LPSC_MMC_SD, +}; + +static struct clk mmcsd1_clk = { + .name = "mmcsd1", + .parent = &pll1_sysclk2, + .lpsc = DM355_LPSC_MMC_SD1, +}; + +static struct clk spi0_clk = { + .name = "spi0", + .parent = &pll1_sysclk2, + .lpsc = DAVINCI_LPSC_SPI, +}; + +static struct clk spi1_clk = { + .name = "spi1", + .parent = &pll1_sysclk2, + .lpsc = DM355_LPSC_SPI1, +}; + +static struct clk spi2_clk = { + .name = "spi2", + .parent = &pll1_sysclk2, + .lpsc = DM355_LPSC_SPI2, +}; + +static struct clk gpio_clk = { + .name = "gpio", + .parent = &pll1_sysclk2, + .lpsc = DAVINCI_LPSC_GPIO, +}; + +static struct clk aemif_clk = { + .name = "aemif", + .parent = &pll1_sysclk2, + .lpsc = DAVINCI_LPSC_AEMIF, +}; + +static struct clk pwm0_clk = { + .name = "pwm0", + .parent = &pll1_aux_clk, + .lpsc = DAVINCI_LPSC_PWM0, +}; + +static struct clk pwm1_clk = { + .name = "pwm1", + .parent = &pll1_aux_clk, + .lpsc = DAVINCI_LPSC_PWM1, +}; + +static struct clk pwm2_clk = { + .name = "pwm2", + .parent = &pll1_aux_clk, + .lpsc = DAVINCI_LPSC_PWM2, +}; + +static struct clk pwm3_clk = { + .name = "pwm3", + .parent = &pll1_aux_clk, + .lpsc = DM355_LPSC_PWM3, +}; + +static struct clk timer0_clk = { + .name = "timer0", + .parent = &pll1_aux_clk, + .lpsc = DAVINCI_LPSC_TIMER0, +}; + +static struct clk timer1_clk = { + .name = "timer1", + .parent = &pll1_aux_clk, + .lpsc = DAVINCI_LPSC_TIMER1, +}; + +static struct clk timer2_clk = { + .name = "timer2", + .parent = &pll1_aux_clk, + .lpsc = DAVINCI_LPSC_TIMER2, + .usecount = 1, /* REVISIT: why cant' this be disabled? */ +}; + +static struct clk timer3_clk = { + .name = "timer3", + .parent = &pll1_aux_clk, + .lpsc = DM355_LPSC_TIMER3, +}; + +static struct clk rto_clk = { + .name = "rto", + .parent = &pll1_aux_clk, + .lpsc = DM355_LPSC_RTO, +}; + +static struct clk usb_clk = { + .name = "usb", + .parent = &pll1_sysclk2, + .lpsc = DAVINCI_LPSC_USB, +}; + +static struct davinci_clk dm355_clks[] = { + CLK(NULL, "ref", &ref_clk), + CLK(NULL, "pll1", &pll1_clk), + CLK(NULL, "pll1_sysclk1", &pll1_sysclk1), + CLK(NULL, "pll1_sysclk2", &pll1_sysclk2), + CLK(NULL, "pll1_sysclk3", &pll1_sysclk3), + CLK(NULL, "pll1_sysclk4", &pll1_sysclk4), + CLK(NULL, "pll1_aux", &pll1_aux_clk), + CLK(NULL, "pll1_sysclkbp", &pll1_sysclkbp), + CLK(NULL, "vpss_dac", &vpss_dac_clk), + CLK(NULL, "vpss_master", &vpss_master_clk), + CLK(NULL, "vpss_slave", &vpss_slave_clk), + CLK(NULL, "clkout1", &clkout1_clk), + CLK(NULL, "clkout2", &clkout2_clk), + CLK(NULL, "pll2", &pll2_clk), + CLK(NULL, "pll2_sysclk1", &pll2_sysclk1), + CLK(NULL, "pll2_sysclkbp", &pll2_sysclkbp), + CLK(NULL, "clkout3", &clkout3_clk), + CLK(NULL, "arm", &arm_clk), + CLK(NULL, "mjcp", &mjcp_clk), + CLK(NULL, "uart0", &uart0_clk), + CLK(NULL, "uart1", &uart1_clk), + CLK(NULL, "uart2", &uart2_clk), + CLK("i2c_davinci.1", NULL, &i2c_clk), + CLK("soc-audio.0", NULL, &asp0_clk), + CLK("soc-audio.1", NULL, &asp1_clk), + CLK("davinci_mmc.0", NULL, &mmcsd0_clk), + CLK("davinci_mmc.1", NULL, &mmcsd1_clk), + CLK(NULL, "spi0", &spi0_clk), + CLK(NULL, "spi1", &spi1_clk), + CLK(NULL, "spi2", &spi2_clk), + CLK(NULL, "gpio", &gpio_clk), + CLK(NULL, "aemif", &aemif_clk), + CLK(NULL, "pwm0", &pwm0_clk), + CLK(NULL, "pwm1", &pwm1_clk), + CLK(NULL, "pwm2", &pwm2_clk), + CLK(NULL, "pwm3", &pwm3_clk), + CLK(NULL, "timer0", &timer0_clk), + CLK(NULL, "timer1", &timer1_clk), + CLK("watchdog", NULL, &timer2_clk), + CLK(NULL, "timer3", &timer3_clk), + CLK(NULL, "rto", &rto_clk), + CLK(NULL, "usb", &usb_clk), + CLK(NULL, NULL, NULL), +}; + +/*----------------------------------------------------------------------*/ + +static u64 dm355_spi0_dma_mask = DMA_BIT_MASK(32); + +static struct resource dm355_spi0_resources[] = { + { + .start = 0x01c66000, + .end = 0x01c667ff, + .flags = IORESOURCE_MEM, + }, + { + .start = IRQ_DM355_SPINT0_1, + .flags = IORESOURCE_IRQ, + }, + /* Not yet used, so not included: + * IORESOURCE_IRQ: + * - IRQ_DM355_SPINT0_0 + * IORESOURCE_DMA: + * - DAVINCI_DMA_SPI_SPIX + * - DAVINCI_DMA_SPI_SPIR + */ +}; + +static struct platform_device dm355_spi0_device = { + .name = "spi_davinci", + .id = 0, + .dev = { + .dma_mask = &dm355_spi0_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + .num_resources = ARRAY_SIZE(dm355_spi0_resources), + .resource = dm355_spi0_resources, +}; + +void __init dm355_init_spi0(unsigned chipselect_mask, + struct spi_board_info *info, unsigned len) +{ + /* for now, assume we need MISO */ + davinci_cfg_reg(DM355_SPI0_SDI); + + /* not all slaves will be wired up */ + if (chipselect_mask & BIT(0)) + davinci_cfg_reg(DM355_SPI0_SDENA0); + if (chipselect_mask & BIT(1)) + davinci_cfg_reg(DM355_SPI0_SDENA1); + + spi_register_board_info(info, len); + + platform_device_register(&dm355_spi0_device); +} + +/*----------------------------------------------------------------------*/ + +#define PINMUX0 0x00 +#define PINMUX1 0x04 +#define PINMUX2 0x08 +#define PINMUX3 0x0c +#define PINMUX4 0x10 +#define INTMUX 0x18 +#define EVTMUX 0x1c + +/* + * Device specific mux setup + * + * soc description mux mode mode mux dbg + * reg offset mask mode + */ +static const struct mux_config dm355_pins[] = { +#ifdef CONFIG_DAVINCI_MUX +MUX_CFG(DM355, MMCSD0, 4, 2, 1, 0, false) + +MUX_CFG(DM355, SD1_CLK, 3, 6, 1, 1, false) +MUX_CFG(DM355, SD1_CMD, 3, 7, 1, 1, false) +MUX_CFG(DM355, SD1_DATA3, 3, 8, 3, 1, false) +MUX_CFG(DM355, SD1_DATA2, 3, 10, 3, 1, false) +MUX_CFG(DM355, SD1_DATA1, 3, 12, 3, 1, false) +MUX_CFG(DM355, SD1_DATA0, 3, 14, 3, 1, false) + +MUX_CFG(DM355, I2C_SDA, 3, 19, 1, 1, false) +MUX_CFG(DM355, I2C_SCL, 3, 20, 1, 1, false) + +MUX_CFG(DM355, MCBSP0_BDX, 3, 0, 1, 1, false) +MUX_CFG(DM355, MCBSP0_X, 3, 1, 1, 1, false) +MUX_CFG(DM355, MCBSP0_BFSX, 3, 2, 1, 1, false) +MUX_CFG(DM355, MCBSP0_BDR, 3, 3, 1, 1, false) +MUX_CFG(DM355, MCBSP0_R, 3, 4, 1, 1, false) +MUX_CFG(DM355, MCBSP0_BFSR, 3, 5, 1, 1, false) + +MUX_CFG(DM355, SPI0_SDI, 4, 1, 1, 0, false) +MUX_CFG(DM355, SPI0_SDENA0, 4, 0, 1, 0, false) +MUX_CFG(DM355, SPI0_SDENA1, 3, 28, 1, 1, false) + +INT_CFG(DM355, INT_EDMA_CC, 2, 1, 1, false) +INT_CFG(DM355, INT_EDMA_TC0_ERR, 3, 1, 1, false) +INT_CFG(DM355, INT_EDMA_TC1_ERR, 4, 1, 1, false) + +EVT_CFG(DM355, EVT8_ASP1_TX, 0, 1, 0, false) +EVT_CFG(DM355, EVT9_ASP1_RX, 1, 1, 0, false) +EVT_CFG(DM355, EVT26_MMC0_RX, 2, 1, 0, false) +#endif +}; + +static u8 dm355_default_priorities[DAVINCI_N_AINTC_IRQ] = { + [IRQ_DM355_CCDC_VDINT0] = 2, + [IRQ_DM355_CCDC_VDINT1] = 6, + [IRQ_DM355_CCDC_VDINT2] = 6, + [IRQ_DM355_IPIPE_HST] = 6, + [IRQ_DM355_H3AINT] = 6, + [IRQ_DM355_IPIPE_SDR] = 6, + [IRQ_DM355_IPIPEIFINT] = 6, + [IRQ_DM355_OSDINT] = 7, + [IRQ_DM355_VENCINT] = 6, + [IRQ_ASQINT] = 6, + [IRQ_IMXINT] = 6, + [IRQ_USBINT] = 4, + [IRQ_DM355_RTOINT] = 4, + [IRQ_DM355_UARTINT2] = 7, + [IRQ_DM355_TINT6] = 7, + [IRQ_CCINT0] = 5, /* dma */ + [IRQ_CCERRINT] = 5, /* dma */ + [IRQ_TCERRINT0] = 5, /* dma */ + [IRQ_TCERRINT] = 5, /* dma */ + [IRQ_DM355_SPINT2_1] = 7, + [IRQ_DM355_TINT7] = 4, + [IRQ_DM355_SDIOINT0] = 7, + [IRQ_MBXINT] = 7, + [IRQ_MBRINT] = 7, + [IRQ_MMCINT] = 7, + [IRQ_DM355_MMCINT1] = 7, + [IRQ_DM355_PWMINT3] = 7, + [IRQ_DDRINT] = 7, + [IRQ_AEMIFINT] = 7, + [IRQ_DM355_SDIOINT1] = 4, + [IRQ_TINT0_TINT12] = 2, /* clockevent */ + [IRQ_TINT0_TINT34] = 2, /* clocksource */ + [IRQ_TINT1_TINT12] = 7, /* DSP timer */ + [IRQ_TINT1_TINT34] = 7, /* system tick */ + [IRQ_PWMINT0] = 7, + [IRQ_PWMINT1] = 7, + [IRQ_PWMINT2] = 7, + [IRQ_I2C] = 3, + [IRQ_UARTINT0] = 3, + [IRQ_UARTINT1] = 3, + [IRQ_DM355_SPINT0_0] = 3, + [IRQ_DM355_SPINT0_1] = 3, + [IRQ_DM355_GPIO0] = 3, + [IRQ_DM355_GPIO1] = 7, + [IRQ_DM355_GPIO2] = 4, + [IRQ_DM355_GPIO3] = 4, + [IRQ_DM355_GPIO4] = 7, + [IRQ_DM355_GPIO5] = 7, + [IRQ_DM355_GPIO6] = 7, + [IRQ_DM355_GPIO7] = 7, + [IRQ_DM355_GPIO8] = 7, + [IRQ_DM355_GPIO9] = 7, + [IRQ_DM355_GPIOBNK0] = 7, + [IRQ_DM355_GPIOBNK1] = 7, + [IRQ_DM355_GPIOBNK2] = 7, + [IRQ_DM355_GPIOBNK3] = 7, + [IRQ_DM355_GPIOBNK4] = 7, + [IRQ_DM355_GPIOBNK5] = 7, + [IRQ_DM355_GPIOBNK6] = 7, + [IRQ_COMMTX] = 7, + [IRQ_COMMRX] = 7, + [IRQ_EMUINT] = 7, +}; + +/*----------------------------------------------------------------------*/ + +static const s8 dma_chan_dm355_no_event[] = { + 12, 13, 24, 56, 57, + 58, 59, 60, 61, 62, + 63, + -1 +}; + +static struct edma_soc_info dm355_edma_info = { + .n_channel = 64, + .n_region = 4, + .n_slot = 128, + .n_tc = 2, + .noevent = dma_chan_dm355_no_event, +}; + +static struct resource edma_resources[] = { + { + .name = "edma_cc", + .start = 0x01c00000, + .end = 0x01c00000 + SZ_64K - 1, + .flags = IORESOURCE_MEM, + }, + { + .name = "edma_tc0", + .start = 0x01c10000, + .end = 0x01c10000 + SZ_1K - 1, + .flags = IORESOURCE_MEM, + }, + { + .name = "edma_tc1", + .start = 0x01c10400, + .end = 0x01c10400 + SZ_1K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = IRQ_CCINT0, + .flags = IORESOURCE_IRQ, + }, + { + .start = IRQ_CCERRINT, + .flags = IORESOURCE_IRQ, + }, + /* not using (or muxing) TC*_ERR */ +}; + +static struct platform_device dm355_edma_device = { + .name = "edma", + .id = -1, + .dev.platform_data = &dm355_edma_info, + .num_resources = ARRAY_SIZE(edma_resources), + .resource = edma_resources, +}; + +/*----------------------------------------------------------------------*/ + +static struct map_desc dm355_io_desc[] = { + { + .virtual = IO_VIRT, + .pfn = __phys_to_pfn(IO_PHYS), + .length = IO_SIZE, + .type = MT_DEVICE + }, + { + .virtual = SRAM_VIRT, + .pfn = __phys_to_pfn(0x00010000), + .length = SZ_32K, + /* MT_MEMORY_NONCACHED requires supersection alignment */ + .type = MT_DEVICE, + }, +}; + +/* Contents of JTAG ID register used to identify exact cpu type */ +static struct davinci_id dm355_ids[] = { + { + .variant = 0x0, + .part_no = 0xb73b, + .manufacturer = 0x00f, + .cpu_id = DAVINCI_CPU_ID_DM355, + .name = "dm355", + }, +}; + +static void __iomem *dm355_psc_bases[] = { + IO_ADDRESS(DAVINCI_PWR_SLEEP_CNTRL_BASE), +}; + +/* + * T0_BOT: Timer 0, bottom: clockevent source for hrtimers + * T0_TOP: Timer 0, top : clocksource for generic timekeeping + * T1_BOT: Timer 1, bottom: (used by DSP in TI DSPLink code) + * T1_TOP: Timer 1, top : + */ +struct davinci_timer_info dm355_timer_info = { + .timers = davinci_timer_instance, + .clockevent_id = T0_BOT, + .clocksource_id = T0_TOP, +}; + +static struct plat_serial8250_port dm355_serial_platform_data[] = { + { + .mapbase = DAVINCI_UART0_BASE, + .irq = IRQ_UARTINT0, + .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | + UPF_IOREMAP, + .iotype = UPIO_MEM, + .regshift = 2, + }, + { + .mapbase = DAVINCI_UART1_BASE, + .irq = IRQ_UARTINT1, + .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | + UPF_IOREMAP, + .iotype = UPIO_MEM, + .regshift = 2, + }, + { + .mapbase = DM355_UART2_BASE, + .irq = IRQ_DM355_UARTINT2, + .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | + UPF_IOREMAP, + .iotype = UPIO_MEM, + .regshift = 2, + }, + { + .flags = 0 + }, +}; + +static struct platform_device dm355_serial_device = { + .name = "serial8250", + .id = PLAT8250_DEV_PLATFORM, + .dev = { + .platform_data = dm355_serial_platform_data, + }, +}; + +static struct davinci_soc_info davinci_soc_info_dm355 = { + .io_desc = dm355_io_desc, + .io_desc_num = ARRAY_SIZE(dm355_io_desc), + .jtag_id_base = IO_ADDRESS(0x01c40028), + .ids = dm355_ids, + .ids_num = ARRAY_SIZE(dm355_ids), + .cpu_clks = dm355_clks, + .psc_bases = dm355_psc_bases, + .psc_bases_num = ARRAY_SIZE(dm355_psc_bases), + .pinmux_base = IO_ADDRESS(DAVINCI_SYSTEM_MODULE_BASE), + .pinmux_pins = dm355_pins, + .pinmux_pins_num = ARRAY_SIZE(dm355_pins), + .intc_base = IO_ADDRESS(DAVINCI_ARM_INTC_BASE), + .intc_type = DAVINCI_INTC_TYPE_AINTC, + .intc_irq_prios = dm355_default_priorities, + .intc_irq_num = DAVINCI_N_AINTC_IRQ, + .timer_info = &dm355_timer_info, + .wdt_base = IO_ADDRESS(DAVINCI_WDOG_BASE), + .gpio_base = IO_ADDRESS(DAVINCI_GPIO_BASE), + .gpio_num = 104, + .gpio_irq = IRQ_DM355_GPIOBNK0, + .serial_dev = &dm355_serial_device, + .sram_dma = 0x00010000, + .sram_len = SZ_32K, +}; + +void __init dm355_init(void) +{ + davinci_common_init(&davinci_soc_info_dm355); +} + +static int __init dm355_init_devices(void) +{ + if (!cpu_is_davinci_dm355()) + return 0; + + davinci_cfg_reg(DM355_INT_EDMA_CC); + platform_device_register(&dm355_edma_device); + return 0; +} +postcore_initcall(dm355_init_devices); diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c index d428ef192eac..fb5449b3c97b 100644 --- a/arch/arm/mach-davinci/dm644x.c +++ b/arch/arm/mach-davinci/dm644x.c @@ -11,7 +11,11 @@ #include #include #include +#include #include +#include + +#include #include #include @@ -20,6 +24,9 @@ #include #include #include +#include +#include +#include #include "clock.h" #include "mux.h" @@ -312,7 +319,14 @@ struct davinci_clk dm644x_clks[] = { CLK(NULL, NULL, NULL), }; -#if defined(CONFIG_TI_DAVINCI_EMAC) || defined(CONFIG_TI_DAVINCI_EMAC_MODULE) +static struct emac_platform_data dm644x_emac_pdata = { + .ctrl_reg_offset = DM644X_EMAC_CNTRL_OFFSET, + .ctrl_mod_reg_offset = DM644X_EMAC_CNTRL_MOD_OFFSET, + .ctrl_ram_offset = DM644X_EMAC_CNTRL_RAM_OFFSET, + .mdio_reg_offset = DM644X_EMAC_MDIO_OFFSET, + .ctrl_ram_size = DM644X_EMAC_CNTRL_RAM_SIZE, + .version = EMAC_VERSION_1, +}; static struct resource dm644x_emac_resources[] = { { @@ -330,11 +344,15 @@ static struct resource dm644x_emac_resources[] = { static struct platform_device dm644x_emac_device = { .name = "davinci_emac", .id = 1, + .dev = { + .platform_data = &dm644x_emac_pdata, + }, .num_resources = ARRAY_SIZE(dm644x_emac_resources), .resource = dm644x_emac_resources, }; -#endif +#define PINMUX0 0x00 +#define PINMUX1 0x04 /* * Device specific mux setup @@ -343,6 +361,7 @@ static struct platform_device dm644x_emac_device = { * reg offset mask mode */ static const struct mux_config dm644x_pins[] = { +#ifdef CONFIG_DAVINCI_MUX MUX_CFG(DM644X, HDIREN, 0, 16, 1, 1, true) MUX_CFG(DM644X, ATAEN, 0, 17, 1, 1, true) MUX_CFG(DM644X, ATAEN_DISABLE, 0, 17, 1, 0, true) @@ -383,8 +402,76 @@ MUX_CFG(DM644X, RGB666, 0, 22, 1, 1, true) MUX_CFG(DM644X, LOEEN, 0, 24, 1, 1, true) MUX_CFG(DM644X, LFLDEN, 0, 25, 1, 1, false) +#endif }; +/* FIQ are pri 0-1; otherwise 2-7, with 7 lowest priority */ +static u8 dm644x_default_priorities[DAVINCI_N_AINTC_IRQ] = { + [IRQ_VDINT0] = 2, + [IRQ_VDINT1] = 6, + [IRQ_VDINT2] = 6, + [IRQ_HISTINT] = 6, + [IRQ_H3AINT] = 6, + [IRQ_PRVUINT] = 6, + [IRQ_RSZINT] = 6, + [7] = 7, + [IRQ_VENCINT] = 6, + [IRQ_ASQINT] = 6, + [IRQ_IMXINT] = 6, + [IRQ_VLCDINT] = 6, + [IRQ_USBINT] = 4, + [IRQ_EMACINT] = 4, + [14] = 7, + [15] = 7, + [IRQ_CCINT0] = 5, /* dma */ + [IRQ_CCERRINT] = 5, /* dma */ + [IRQ_TCERRINT0] = 5, /* dma */ + [IRQ_TCERRINT] = 5, /* dma */ + [IRQ_PSCIN] = 7, + [21] = 7, + [IRQ_IDE] = 4, + [23] = 7, + [IRQ_MBXINT] = 7, + [IRQ_MBRINT] = 7, + [IRQ_MMCINT] = 7, + [IRQ_SDIOINT] = 7, + [28] = 7, + [IRQ_DDRINT] = 7, + [IRQ_AEMIFINT] = 7, + [IRQ_VLQINT] = 4, + [IRQ_TINT0_TINT12] = 2, /* clockevent */ + [IRQ_TINT0_TINT34] = 2, /* clocksource */ + [IRQ_TINT1_TINT12] = 7, /* DSP timer */ + [IRQ_TINT1_TINT34] = 7, /* system tick */ + [IRQ_PWMINT0] = 7, + [IRQ_PWMINT1] = 7, + [IRQ_PWMINT2] = 7, + [IRQ_I2C] = 3, + [IRQ_UARTINT0] = 3, + [IRQ_UARTINT1] = 3, + [IRQ_UARTINT2] = 3, + [IRQ_SPINT0] = 3, + [IRQ_SPINT1] = 3, + [45] = 7, + [IRQ_DSP2ARM0] = 4, + [IRQ_DSP2ARM1] = 4, + [IRQ_GPIO0] = 7, + [IRQ_GPIO1] = 7, + [IRQ_GPIO2] = 7, + [IRQ_GPIO3] = 7, + [IRQ_GPIO4] = 7, + [IRQ_GPIO5] = 7, + [IRQ_GPIO6] = 7, + [IRQ_GPIO7] = 7, + [IRQ_GPIOBNK0] = 7, + [IRQ_GPIOBNK1] = 7, + [IRQ_GPIOBNK2] = 7, + [IRQ_GPIOBNK3] = 7, + [IRQ_GPIOBNK4] = 7, + [IRQ_COMMTX] = 7, + [IRQ_COMMRX] = 7, + [IRQ_EMUINT] = 7, +}; /*----------------------------------------------------------------------*/ @@ -444,10 +531,118 @@ static struct platform_device dm644x_edma_device = { }; /*----------------------------------------------------------------------*/ + +static struct map_desc dm644x_io_desc[] = { + { + .virtual = IO_VIRT, + .pfn = __phys_to_pfn(IO_PHYS), + .length = IO_SIZE, + .type = MT_DEVICE + }, + { + .virtual = SRAM_VIRT, + .pfn = __phys_to_pfn(0x00008000), + .length = SZ_16K, + /* MT_MEMORY_NONCACHED requires supersection alignment */ + .type = MT_DEVICE, + }, +}; + +/* Contents of JTAG ID register used to identify exact cpu type */ +static struct davinci_id dm644x_ids[] = { + { + .variant = 0x0, + .part_no = 0xb700, + .manufacturer = 0x017, + .cpu_id = DAVINCI_CPU_ID_DM6446, + .name = "dm6446", + }, +}; + +static void __iomem *dm644x_psc_bases[] = { + IO_ADDRESS(DAVINCI_PWR_SLEEP_CNTRL_BASE), +}; + +/* + * T0_BOT: Timer 0, bottom: clockevent source for hrtimers + * T0_TOP: Timer 0, top : clocksource for generic timekeeping + * T1_BOT: Timer 1, bottom: (used by DSP in TI DSPLink code) + * T1_TOP: Timer 1, top : + */ +struct davinci_timer_info dm644x_timer_info = { + .timers = davinci_timer_instance, + .clockevent_id = T0_BOT, + .clocksource_id = T0_TOP, +}; + +static struct plat_serial8250_port dm644x_serial_platform_data[] = { + { + .mapbase = DAVINCI_UART0_BASE, + .irq = IRQ_UARTINT0, + .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | + UPF_IOREMAP, + .iotype = UPIO_MEM, + .regshift = 2, + }, + { + .mapbase = DAVINCI_UART1_BASE, + .irq = IRQ_UARTINT1, + .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | + UPF_IOREMAP, + .iotype = UPIO_MEM, + .regshift = 2, + }, + { + .mapbase = DAVINCI_UART2_BASE, + .irq = IRQ_UARTINT2, + .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | + UPF_IOREMAP, + .iotype = UPIO_MEM, + .regshift = 2, + }, + { + .flags = 0 + }, +}; + +static struct platform_device dm644x_serial_device = { + .name = "serial8250", + .id = PLAT8250_DEV_PLATFORM, + .dev = { + .platform_data = dm644x_serial_platform_data, + }, +}; + +static struct davinci_soc_info davinci_soc_info_dm644x = { + .io_desc = dm644x_io_desc, + .io_desc_num = ARRAY_SIZE(dm644x_io_desc), + .jtag_id_base = IO_ADDRESS(0x01c40028), + .ids = dm644x_ids, + .ids_num = ARRAY_SIZE(dm644x_ids), + .cpu_clks = dm644x_clks, + .psc_bases = dm644x_psc_bases, + .psc_bases_num = ARRAY_SIZE(dm644x_psc_bases), + .pinmux_base = IO_ADDRESS(DAVINCI_SYSTEM_MODULE_BASE), + .pinmux_pins = dm644x_pins, + .pinmux_pins_num = ARRAY_SIZE(dm644x_pins), + .intc_base = IO_ADDRESS(DAVINCI_ARM_INTC_BASE), + .intc_type = DAVINCI_INTC_TYPE_AINTC, + .intc_irq_prios = dm644x_default_priorities, + .intc_irq_num = DAVINCI_N_AINTC_IRQ, + .timer_info = &dm644x_timer_info, + .wdt_base = IO_ADDRESS(DAVINCI_WDOG_BASE), + .gpio_base = IO_ADDRESS(DAVINCI_GPIO_BASE), + .gpio_num = 71, + .gpio_irq = IRQ_GPIOBNK0, + .serial_dev = &dm644x_serial_device, + .emac_pdata = &dm644x_emac_pdata, + .sram_dma = 0x00008000, + .sram_len = SZ_16K, +}; + void __init dm644x_init(void) { - davinci_clk_init(dm644x_clks); - davinci_mux_register(dm644x_pins, ARRAY_SIZE(dm644x_pins)); + davinci_common_init(&davinci_soc_info_dm644x); } static int __init dm644x_init_devices(void) @@ -456,6 +651,7 @@ static int __init dm644x_init_devices(void) return 0; platform_device_register(&dm644x_edma_device); + platform_device_register(&dm644x_emac_device); return 0; } postcore_initcall(dm644x_init_devices); diff --git a/arch/arm/mach-davinci/dm646x.c b/arch/arm/mach-davinci/dm646x.c new file mode 100644 index 000000000000..334f0711e0f5 --- /dev/null +++ b/arch/arm/mach-davinci/dm646x.c @@ -0,0 +1,636 @@ +/* + * TI DaVinci DM644x chip specific setup + * + * Author: Kevin Hilman, Deep Root Systems, LLC + * + * 2007 (c) Deep Root Systems, LLC. 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 +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clock.h" +#include "mux.h" + +/* + * Device specific clocks + */ +#define DM646X_REF_FREQ 27000000 +#define DM646X_AUX_FREQ 24000000 + +static struct pll_data pll1_data = { + .num = 1, + .phys_base = DAVINCI_PLL1_BASE, +}; + +static struct pll_data pll2_data = { + .num = 2, + .phys_base = DAVINCI_PLL2_BASE, +}; + +static struct clk ref_clk = { + .name = "ref_clk", + .rate = DM646X_REF_FREQ, +}; + +static struct clk aux_clkin = { + .name = "aux_clkin", + .rate = DM646X_AUX_FREQ, +}; + +static struct clk pll1_clk = { + .name = "pll1", + .parent = &ref_clk, + .pll_data = &pll1_data, + .flags = CLK_PLL, +}; + +static struct clk pll1_sysclk1 = { + .name = "pll1_sysclk1", + .parent = &pll1_clk, + .flags = CLK_PLL, + .div_reg = PLLDIV1, +}; + +static struct clk pll1_sysclk2 = { + .name = "pll1_sysclk2", + .parent = &pll1_clk, + .flags = CLK_PLL, + .div_reg = PLLDIV2, +}; + +static struct clk pll1_sysclk3 = { + .name = "pll1_sysclk3", + .parent = &pll1_clk, + .flags = CLK_PLL, + .div_reg = PLLDIV3, +}; + +static struct clk pll1_sysclk4 = { + .name = "pll1_sysclk4", + .parent = &pll1_clk, + .flags = CLK_PLL, + .div_reg = PLLDIV4, +}; + +static struct clk pll1_sysclk5 = { + .name = "pll1_sysclk5", + .parent = &pll1_clk, + .flags = CLK_PLL, + .div_reg = PLLDIV5, +}; + +static struct clk pll1_sysclk6 = { + .name = "pll1_sysclk6", + .parent = &pll1_clk, + .flags = CLK_PLL, + .div_reg = PLLDIV6, +}; + +static struct clk pll1_sysclk8 = { + .name = "pll1_sysclk8", + .parent = &pll1_clk, + .flags = CLK_PLL, + .div_reg = PLLDIV8, +}; + +static struct clk pll1_sysclk9 = { + .name = "pll1_sysclk9", + .parent = &pll1_clk, + .flags = CLK_PLL, + .div_reg = PLLDIV9, +}; + +static struct clk pll1_sysclkbp = { + .name = "pll1_sysclkbp", + .parent = &pll1_clk, + .flags = CLK_PLL | PRE_PLL, + .div_reg = BPDIV, +}; + +static struct clk pll1_aux_clk = { + .name = "pll1_aux_clk", + .parent = &pll1_clk, + .flags = CLK_PLL | PRE_PLL, +}; + +static struct clk pll2_clk = { + .name = "pll2_clk", + .parent = &ref_clk, + .pll_data = &pll2_data, + .flags = CLK_PLL, +}; + +static struct clk pll2_sysclk1 = { + .name = "pll2_sysclk1", + .parent = &pll2_clk, + .flags = CLK_PLL, + .div_reg = PLLDIV1, +}; + +static struct clk dsp_clk = { + .name = "dsp", + .parent = &pll1_sysclk1, + .lpsc = DM646X_LPSC_C64X_CPU, + .flags = PSC_DSP, + .usecount = 1, /* REVISIT how to disable? */ +}; + +static struct clk arm_clk = { + .name = "arm", + .parent = &pll1_sysclk2, + .lpsc = DM646X_LPSC_ARM, + .flags = ALWAYS_ENABLED, +}; + +static struct clk uart0_clk = { + .name = "uart0", + .parent = &aux_clkin, + .lpsc = DM646X_LPSC_UART0, +}; + +static struct clk uart1_clk = { + .name = "uart1", + .parent = &aux_clkin, + .lpsc = DM646X_LPSC_UART1, +}; + +static struct clk uart2_clk = { + .name = "uart2", + .parent = &aux_clkin, + .lpsc = DM646X_LPSC_UART2, +}; + +static struct clk i2c_clk = { + .name = "I2CCLK", + .parent = &pll1_sysclk3, + .lpsc = DM646X_LPSC_I2C, +}; + +static struct clk gpio_clk = { + .name = "gpio", + .parent = &pll1_sysclk3, + .lpsc = DM646X_LPSC_GPIO, +}; + +static struct clk aemif_clk = { + .name = "aemif", + .parent = &pll1_sysclk3, + .lpsc = DM646X_LPSC_AEMIF, + .flags = ALWAYS_ENABLED, +}; + +static struct clk emac_clk = { + .name = "emac", + .parent = &pll1_sysclk3, + .lpsc = DM646X_LPSC_EMAC, +}; + +static struct clk pwm0_clk = { + .name = "pwm0", + .parent = &pll1_sysclk3, + .lpsc = DM646X_LPSC_PWM0, + .usecount = 1, /* REVIST: disabling hangs system */ +}; + +static struct clk pwm1_clk = { + .name = "pwm1", + .parent = &pll1_sysclk3, + .lpsc = DM646X_LPSC_PWM1, + .usecount = 1, /* REVIST: disabling hangs system */ +}; + +static struct clk timer0_clk = { + .name = "timer0", + .parent = &pll1_sysclk3, + .lpsc = DM646X_LPSC_TIMER0, +}; + +static struct clk timer1_clk = { + .name = "timer1", + .parent = &pll1_sysclk3, + .lpsc = DM646X_LPSC_TIMER1, +}; + +static struct clk timer2_clk = { + .name = "timer2", + .parent = &pll1_sysclk3, + .flags = ALWAYS_ENABLED, /* no LPSC, always enabled; c.f. spruep9a */ +}; + +static struct clk vpif0_clk = { + .name = "vpif0", + .parent = &ref_clk, + .lpsc = DM646X_LPSC_VPSSMSTR, + .flags = ALWAYS_ENABLED, +}; + +static struct clk vpif1_clk = { + .name = "vpif1", + .parent = &ref_clk, + .lpsc = DM646X_LPSC_VPSSSLV, + .flags = ALWAYS_ENABLED, +}; + +struct davinci_clk dm646x_clks[] = { + CLK(NULL, "ref", &ref_clk), + CLK(NULL, "aux", &aux_clkin), + CLK(NULL, "pll1", &pll1_clk), + CLK(NULL, "pll1_sysclk", &pll1_sysclk1), + CLK(NULL, "pll1_sysclk", &pll1_sysclk2), + CLK(NULL, "pll1_sysclk", &pll1_sysclk3), + CLK(NULL, "pll1_sysclk", &pll1_sysclk4), + CLK(NULL, "pll1_sysclk", &pll1_sysclk5), + CLK(NULL, "pll1_sysclk", &pll1_sysclk6), + CLK(NULL, "pll1_sysclk", &pll1_sysclk8), + CLK(NULL, "pll1_sysclk", &pll1_sysclk9), + CLK(NULL, "pll1_sysclk", &pll1_sysclkbp), + CLK(NULL, "pll1_aux", &pll1_aux_clk), + CLK(NULL, "pll2", &pll2_clk), + CLK(NULL, "pll2_sysclk1", &pll2_sysclk1), + CLK(NULL, "dsp", &dsp_clk), + CLK(NULL, "arm", &arm_clk), + CLK(NULL, "uart0", &uart0_clk), + CLK(NULL, "uart1", &uart1_clk), + CLK(NULL, "uart2", &uart2_clk), + CLK("i2c_davinci.1", NULL, &i2c_clk), + CLK(NULL, "gpio", &gpio_clk), + CLK(NULL, "aemif", &aemif_clk), + CLK("davinci_emac.1", NULL, &emac_clk), + CLK(NULL, "pwm0", &pwm0_clk), + CLK(NULL, "pwm1", &pwm1_clk), + CLK(NULL, "timer0", &timer0_clk), + CLK(NULL, "timer1", &timer1_clk), + CLK("watchdog", NULL, &timer2_clk), + CLK(NULL, "vpif0", &vpif0_clk), + CLK(NULL, "vpif1", &vpif1_clk), + CLK(NULL, NULL, NULL), +}; + +static struct emac_platform_data dm646x_emac_pdata = { + .ctrl_reg_offset = DM646X_EMAC_CNTRL_OFFSET, + .ctrl_mod_reg_offset = DM646X_EMAC_CNTRL_MOD_OFFSET, + .ctrl_ram_offset = DM646X_EMAC_CNTRL_RAM_OFFSET, + .mdio_reg_offset = DM646X_EMAC_MDIO_OFFSET, + .ctrl_ram_size = DM646X_EMAC_CNTRL_RAM_SIZE, + .version = EMAC_VERSION_2, +}; + +static struct resource dm646x_emac_resources[] = { + { + .start = DM646X_EMAC_BASE, + .end = DM646X_EMAC_BASE + 0x47ff, + .flags = IORESOURCE_MEM, + }, + { + .start = IRQ_DM646X_EMACRXTHINT, + .end = IRQ_DM646X_EMACRXTHINT, + .flags = IORESOURCE_IRQ, + }, + { + .start = IRQ_DM646X_EMACRXINT, + .end = IRQ_DM646X_EMACRXINT, + .flags = IORESOURCE_IRQ, + }, + { + .start = IRQ_DM646X_EMACTXINT, + .end = IRQ_DM646X_EMACTXINT, + .flags = IORESOURCE_IRQ, + }, + { + .start = IRQ_DM646X_EMACMISCINT, + .end = IRQ_DM646X_EMACMISCINT, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device dm646x_emac_device = { + .name = "davinci_emac", + .id = 1, + .dev = { + .platform_data = &dm646x_emac_pdata, + }, + .num_resources = ARRAY_SIZE(dm646x_emac_resources), + .resource = dm646x_emac_resources, +}; + +#define PINMUX0 0x00 +#define PINMUX1 0x04 + +/* + * Device specific mux setup + * + * soc description mux mode mode mux dbg + * reg offset mask mode + */ +static const struct mux_config dm646x_pins[] = { +#ifdef CONFIG_DAVINCI_MUX +MUX_CFG(DM646X, ATAEN, 0, 0, 1, 1, true) + +MUX_CFG(DM646X, AUDCK1, 0, 29, 1, 0, false) + +MUX_CFG(DM646X, AUDCK0, 0, 28, 1, 0, false) + +MUX_CFG(DM646X, CRGMUX, 0, 24, 7, 5, true) + +MUX_CFG(DM646X, STSOMUX_DISABLE, 0, 22, 3, 0, true) + +MUX_CFG(DM646X, STSIMUX_DISABLE, 0, 20, 3, 0, true) + +MUX_CFG(DM646X, PTSOMUX_DISABLE, 0, 18, 3, 0, true) + +MUX_CFG(DM646X, PTSIMUX_DISABLE, 0, 16, 3, 0, true) + +MUX_CFG(DM646X, STSOMUX, 0, 22, 3, 2, true) + +MUX_CFG(DM646X, STSIMUX, 0, 20, 3, 2, true) + +MUX_CFG(DM646X, PTSOMUX_PARALLEL, 0, 18, 3, 2, true) + +MUX_CFG(DM646X, PTSIMUX_PARALLEL, 0, 16, 3, 2, true) + +MUX_CFG(DM646X, PTSOMUX_SERIAL, 0, 18, 3, 3, true) + +MUX_CFG(DM646X, PTSIMUX_SERIAL, 0, 16, 3, 3, true) +#endif +}; + +static u8 dm646x_default_priorities[DAVINCI_N_AINTC_IRQ] = { + [IRQ_DM646X_VP_VERTINT0] = 7, + [IRQ_DM646X_VP_VERTINT1] = 7, + [IRQ_DM646X_VP_VERTINT2] = 7, + [IRQ_DM646X_VP_VERTINT3] = 7, + [IRQ_DM646X_VP_ERRINT] = 7, + [IRQ_DM646X_RESERVED_1] = 7, + [IRQ_DM646X_RESERVED_2] = 7, + [IRQ_DM646X_WDINT] = 7, + [IRQ_DM646X_CRGENINT0] = 7, + [IRQ_DM646X_CRGENINT1] = 7, + [IRQ_DM646X_TSIFINT0] = 7, + [IRQ_DM646X_TSIFINT1] = 7, + [IRQ_DM646X_VDCEINT] = 7, + [IRQ_DM646X_USBINT] = 7, + [IRQ_DM646X_USBDMAINT] = 7, + [IRQ_DM646X_PCIINT] = 7, + [IRQ_CCINT0] = 7, /* dma */ + [IRQ_CCERRINT] = 7, /* dma */ + [IRQ_TCERRINT0] = 7, /* dma */ + [IRQ_TCERRINT] = 7, /* dma */ + [IRQ_DM646X_TCERRINT2] = 7, + [IRQ_DM646X_TCERRINT3] = 7, + [IRQ_DM646X_IDE] = 7, + [IRQ_DM646X_HPIINT] = 7, + [IRQ_DM646X_EMACRXTHINT] = 7, + [IRQ_DM646X_EMACRXINT] = 7, + [IRQ_DM646X_EMACTXINT] = 7, + [IRQ_DM646X_EMACMISCINT] = 7, + [IRQ_DM646X_MCASP0TXINT] = 7, + [IRQ_DM646X_MCASP0RXINT] = 7, + [IRQ_AEMIFINT] = 7, + [IRQ_DM646X_RESERVED_3] = 7, + [IRQ_DM646X_MCASP1TXINT] = 7, /* clockevent */ + [IRQ_TINT0_TINT34] = 7, /* clocksource */ + [IRQ_TINT1_TINT12] = 7, /* DSP timer */ + [IRQ_TINT1_TINT34] = 7, /* system tick */ + [IRQ_PWMINT0] = 7, + [IRQ_PWMINT1] = 7, + [IRQ_DM646X_VLQINT] = 7, + [IRQ_I2C] = 7, + [IRQ_UARTINT0] = 7, + [IRQ_UARTINT1] = 7, + [IRQ_DM646X_UARTINT2] = 7, + [IRQ_DM646X_SPINT0] = 7, + [IRQ_DM646X_SPINT1] = 7, + [IRQ_DM646X_DSP2ARMINT] = 7, + [IRQ_DM646X_RESERVED_4] = 7, + [IRQ_DM646X_PSCINT] = 7, + [IRQ_DM646X_GPIO0] = 7, + [IRQ_DM646X_GPIO1] = 7, + [IRQ_DM646X_GPIO2] = 7, + [IRQ_DM646X_GPIO3] = 7, + [IRQ_DM646X_GPIO4] = 7, + [IRQ_DM646X_GPIO5] = 7, + [IRQ_DM646X_GPIO6] = 7, + [IRQ_DM646X_GPIO7] = 7, + [IRQ_DM646X_GPIOBNK0] = 7, + [IRQ_DM646X_GPIOBNK1] = 7, + [IRQ_DM646X_GPIOBNK2] = 7, + [IRQ_DM646X_DDRINT] = 7, + [IRQ_DM646X_AEMIFINT] = 7, + [IRQ_COMMTX] = 7, + [IRQ_COMMRX] = 7, + [IRQ_EMUINT] = 7, +}; + +/*----------------------------------------------------------------------*/ + +static const s8 dma_chan_dm646x_no_event[] = { + 0, 1, 2, 3, 13, + 14, 15, 24, 25, 26, + 27, 30, 31, 54, 55, + 56, + -1 +}; + +static struct edma_soc_info dm646x_edma_info = { + .n_channel = 64, + .n_region = 6, /* 0-1, 4-7 */ + .n_slot = 512, + .n_tc = 4, + .noevent = dma_chan_dm646x_no_event, +}; + +static struct resource edma_resources[] = { + { + .name = "edma_cc", + .start = 0x01c00000, + .end = 0x01c00000 + SZ_64K - 1, + .flags = IORESOURCE_MEM, + }, + { + .name = "edma_tc0", + .start = 0x01c10000, + .end = 0x01c10000 + SZ_1K - 1, + .flags = IORESOURCE_MEM, + }, + { + .name = "edma_tc1", + .start = 0x01c10400, + .end = 0x01c10400 + SZ_1K - 1, + .flags = IORESOURCE_MEM, + }, + { + .name = "edma_tc2", + .start = 0x01c10800, + .end = 0x01c10800 + SZ_1K - 1, + .flags = IORESOURCE_MEM, + }, + { + .name = "edma_tc3", + .start = 0x01c10c00, + .end = 0x01c10c00 + SZ_1K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = IRQ_CCINT0, + .flags = IORESOURCE_IRQ, + }, + { + .start = IRQ_CCERRINT, + .flags = IORESOURCE_IRQ, + }, + /* not using TC*_ERR */ +}; + +static struct platform_device dm646x_edma_device = { + .name = "edma", + .id = -1, + .dev.platform_data = &dm646x_edma_info, + .num_resources = ARRAY_SIZE(edma_resources), + .resource = edma_resources, +}; + +/*----------------------------------------------------------------------*/ + +static struct map_desc dm646x_io_desc[] = { + { + .virtual = IO_VIRT, + .pfn = __phys_to_pfn(IO_PHYS), + .length = IO_SIZE, + .type = MT_DEVICE + }, + { + .virtual = SRAM_VIRT, + .pfn = __phys_to_pfn(0x00010000), + .length = SZ_32K, + /* MT_MEMORY_NONCACHED requires supersection alignment */ + .type = MT_DEVICE, + }, +}; + +/* Contents of JTAG ID register used to identify exact cpu type */ +static struct davinci_id dm646x_ids[] = { + { + .variant = 0x0, + .part_no = 0xb770, + .manufacturer = 0x017, + .cpu_id = DAVINCI_CPU_ID_DM6467, + .name = "dm6467", + }, +}; + +static void __iomem *dm646x_psc_bases[] = { + IO_ADDRESS(DAVINCI_PWR_SLEEP_CNTRL_BASE), +}; + +/* + * T0_BOT: Timer 0, bottom: clockevent source for hrtimers + * T0_TOP: Timer 0, top : clocksource for generic timekeeping + * T1_BOT: Timer 1, bottom: (used by DSP in TI DSPLink code) + * T1_TOP: Timer 1, top : + */ +struct davinci_timer_info dm646x_timer_info = { + .timers = davinci_timer_instance, + .clockevent_id = T0_BOT, + .clocksource_id = T0_TOP, +}; + +static struct plat_serial8250_port dm646x_serial_platform_data[] = { + { + .mapbase = DAVINCI_UART0_BASE, + .irq = IRQ_UARTINT0, + .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | + UPF_IOREMAP, + .iotype = UPIO_MEM32, + .regshift = 2, + }, + { + .mapbase = DAVINCI_UART1_BASE, + .irq = IRQ_UARTINT1, + .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | + UPF_IOREMAP, + .iotype = UPIO_MEM32, + .regshift = 2, + }, + { + .mapbase = DAVINCI_UART2_BASE, + .irq = IRQ_DM646X_UARTINT2, + .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | + UPF_IOREMAP, + .iotype = UPIO_MEM32, + .regshift = 2, + }, + { + .flags = 0 + }, +}; + +static struct platform_device dm646x_serial_device = { + .name = "serial8250", + .id = PLAT8250_DEV_PLATFORM, + .dev = { + .platform_data = dm646x_serial_platform_data, + }, +}; + +static struct davinci_soc_info davinci_soc_info_dm646x = { + .io_desc = dm646x_io_desc, + .io_desc_num = ARRAY_SIZE(dm646x_io_desc), + .jtag_id_base = IO_ADDRESS(0x01c40028), + .ids = dm646x_ids, + .ids_num = ARRAY_SIZE(dm646x_ids), + .cpu_clks = dm646x_clks, + .psc_bases = dm646x_psc_bases, + .psc_bases_num = ARRAY_SIZE(dm646x_psc_bases), + .pinmux_base = IO_ADDRESS(DAVINCI_SYSTEM_MODULE_BASE), + .pinmux_pins = dm646x_pins, + .pinmux_pins_num = ARRAY_SIZE(dm646x_pins), + .intc_base = IO_ADDRESS(DAVINCI_ARM_INTC_BASE), + .intc_type = DAVINCI_INTC_TYPE_AINTC, + .intc_irq_prios = dm646x_default_priorities, + .intc_irq_num = DAVINCI_N_AINTC_IRQ, + .timer_info = &dm646x_timer_info, + .wdt_base = IO_ADDRESS(DAVINCI_WDOG_BASE), + .gpio_base = IO_ADDRESS(DAVINCI_GPIO_BASE), + .gpio_num = 43, /* Only 33 usable */ + .gpio_irq = IRQ_DM646X_GPIOBNK0, + .serial_dev = &dm646x_serial_device, + .emac_pdata = &dm646x_emac_pdata, + .sram_dma = 0x10010000, + .sram_len = SZ_32K, +}; + +void __init dm646x_init(void) +{ + davinci_common_init(&davinci_soc_info_dm646x); +} + +static int __init dm646x_init_devices(void) +{ + if (!cpu_is_davinci_dm646x()) + return 0; + + platform_device_register(&dm646x_edma_device); + platform_device_register(&dm646x_emac_device); + return 0; +} +postcore_initcall(dm646x_init_devices); diff --git a/arch/arm/mach-davinci/gpio.c b/arch/arm/mach-davinci/gpio.c index 1aba41c6351e..1b6532159c58 100644 --- a/arch/arm/mach-davinci/gpio.c +++ b/arch/arm/mach-davinci/gpio.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -37,14 +38,13 @@ struct davinci_gpio { static struct davinci_gpio chips[DIV_ROUND_UP(DAVINCI_N_GPIO, 32)]; -static unsigned __initdata ngpio; - /* create a non-inlined version */ static struct gpio_controller __iomem * __init gpio2controller(unsigned gpio) { return __gpio_to_controller(gpio); } +static int __init davinci_gpio_irq_setup(void); /*--------------------------------------------------------------------------*/ @@ -115,23 +115,16 @@ davinci_gpio_set(struct gpio_chip *chip, unsigned offset, int value) static int __init davinci_gpio_setup(void) { int i, base; + unsigned ngpio; + struct davinci_soc_info *soc_info = &davinci_soc_info; - /* The gpio banks conceptually expose a segmented bitmap, + /* + * The gpio banks conceptually expose a segmented bitmap, * and "ngpio" is one more than the largest zero-based * bit index that's valid. */ - if (cpu_is_davinci_dm355()) { /* or dm335() */ - ngpio = 104; - } else if (cpu_is_davinci_dm644x()) { /* or dm337() */ - ngpio = 71; - } else if (cpu_is_davinci_dm646x()) { - /* NOTE: each bank has several "reserved" bits, - * unusable as GPIOs. Only 33 of the GPIO numbers - * are usable, and we're not rejecting the others. - */ - ngpio = 43; - } else { - /* if cpu_is_davinci_dm643x() ngpio = 111 */ + ngpio = soc_info->gpio_num; + if (ngpio == 0) { pr_err("GPIO setup: how many GPIOs?\n"); return -EINVAL; } @@ -157,6 +150,7 @@ static int __init davinci_gpio_setup(void) gpiochip_add(&chips[i].chip); } + davinci_gpio_irq_setup(); return 0; } pure_initcall(davinci_gpio_setup); @@ -187,10 +181,15 @@ static void gpio_irq_enable(unsigned irq) { struct gpio_controller *__iomem g = get_irq_chip_data(irq); u32 mask = __gpio_mask(irq_to_gpio(irq)); + unsigned status = irq_desc[irq].status; - if (irq_desc[irq].status & IRQ_TYPE_EDGE_FALLING) + status &= IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING; + if (!status) + status = IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING; + + if (status & IRQ_TYPE_EDGE_FALLING) __raw_writel(mask, &g->set_falling); - if (irq_desc[irq].status & IRQ_TYPE_EDGE_RISING) + if (status & IRQ_TYPE_EDGE_RISING) __raw_writel(mask, &g->set_rising); } @@ -205,10 +204,13 @@ static int gpio_irq_type(unsigned irq, unsigned trigger) irq_desc[irq].status &= ~IRQ_TYPE_SENSE_MASK; irq_desc[irq].status |= trigger; - __raw_writel(mask, (trigger & IRQ_TYPE_EDGE_FALLING) - ? &g->set_falling : &g->clr_falling); - __raw_writel(mask, (trigger & IRQ_TYPE_EDGE_RISING) - ? &g->set_rising : &g->clr_rising); + /* don't enable the IRQ if it's currently disabled */ + if (irq_desc[irq].depth == 0) { + __raw_writel(mask, (trigger & IRQ_TYPE_EDGE_FALLING) + ? &g->set_falling : &g->clr_falling); + __raw_writel(mask, (trigger & IRQ_TYPE_EDGE_RISING) + ? &g->set_rising : &g->clr_rising); + } return 0; } @@ -230,6 +232,7 @@ gpio_irq_handler(unsigned irq, struct irq_desc *desc) mask <<= 16; /* temporarily mask (level sensitive) parent IRQ */ + desc->chip->mask(irq); desc->chip->ack(irq); while (1) { u32 status; @@ -268,17 +271,15 @@ gpio_irq_handler(unsigned irq, struct irq_desc *desc) static int __init davinci_gpio_irq_setup(void) { unsigned gpio, irq, bank; - unsigned bank_irq; struct clk *clk; u32 binten = 0; + unsigned ngpio, bank_irq; + struct davinci_soc_info *soc_info = &davinci_soc_info; - if (cpu_is_davinci_dm355()) { /* or dm335() */ - bank_irq = IRQ_DM355_GPIOBNK0; - } else if (cpu_is_davinci_dm644x()) { - bank_irq = IRQ_GPIOBNK0; - } else if (cpu_is_davinci_dm646x()) { - bank_irq = IRQ_DM646X_GPIOBNK0; - } else { + ngpio = soc_info->gpio_num; + + bank_irq = soc_info->gpio_irq; + if (bank_irq == 0) { printk(KERN_ERR "Don't know first GPIO bank IRQ.\n"); return -EINVAL; } @@ -318,11 +319,9 @@ static int __init davinci_gpio_irq_setup(void) /* BINTEN -- per-bank interrupt enable. genirq would also let these * bits be set/cleared dynamically. */ - __raw_writel(binten, (void *__iomem) - IO_ADDRESS(DAVINCI_GPIO_BASE + 0x08)); + __raw_writel(binten, soc_info->gpio_base + 0x08); printk(KERN_INFO "DaVinci: %d gpio irqs\n", irq - gpio_to_irq(0)); return 0; } -arch_initcall(davinci_gpio_irq_setup); diff --git a/arch/arm/mach-davinci/id.c b/arch/arm/mach-davinci/id.c deleted file mode 100644 index 018b994cd794..000000000000 --- a/arch/arm/mach-davinci/id.c +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Davinci CPU identification code - * - * Copyright (C) 2006 Komal Shah - * - * Derived from OMAP1 CPU identification code. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include - -#define JTAG_ID_BASE IO_ADDRESS(0x01c40028) - -static unsigned int davinci_revision; - -struct davinci_id { - u8 variant; /* JTAG ID bits 31:28 */ - u16 part_no; /* JTAG ID bits 27:12 */ - u32 manufacturer; /* JTAG ID bits 11:1 */ - u32 type; /* Cpu id bits [31:8], cpu class bits [7:0] */ -}; - -/* Register values to detect the DaVinci version */ -static struct davinci_id davinci_ids[] __initdata = { - { - /* DM6446 */ - .part_no = 0xb700, - .variant = 0x0, - .manufacturer = 0x017, - .type = 0x64460000, - }, - { - /* DM646X */ - .part_no = 0xb770, - .variant = 0x0, - .manufacturer = 0x017, - .type = 0x64670000, - }, - { - /* DM355 */ - .part_no = 0xb73b, - .variant = 0x0, - .manufacturer = 0x00f, - .type = 0x03550000, - }, -}; - -/* - * Get Device Part No. from JTAG ID register - */ -static u16 __init davinci_get_part_no(void) -{ - u32 dev_id, part_no; - - dev_id = __raw_readl(JTAG_ID_BASE); - - part_no = ((dev_id >> 12) & 0xffff); - - return part_no; -} - -/* - * Get Device Revision from JTAG ID register - */ -static u8 __init davinci_get_variant(void) -{ - u32 variant; - - variant = __raw_readl(JTAG_ID_BASE); - - variant = (variant >> 28) & 0xf; - - return variant; -} - -unsigned int davinci_rev(void) -{ - return davinci_revision >> 16; -} -EXPORT_SYMBOL(davinci_rev); - -void __init davinci_check_revision(void) -{ - int i; - u16 part_no; - u8 variant; - - part_no = davinci_get_part_no(); - variant = davinci_get_variant(); - - /* First check only the major version in a safe way */ - for (i = 0; i < ARRAY_SIZE(davinci_ids); i++) { - if (part_no == (davinci_ids[i].part_no)) { - davinci_revision = davinci_ids[i].type; - break; - } - } - - /* Check if we can find the dev revision */ - for (i = 0; i < ARRAY_SIZE(davinci_ids); i++) { - if (part_no == davinci_ids[i].part_no && - variant == davinci_ids[i].variant) { - davinci_revision = davinci_ids[i].type; - break; - } - } - - printk(KERN_INFO "DaVinci DM%04x variant 0x%x\n", - davinci_rev(), variant); -} diff --git a/arch/arm/mach-davinci/include/mach/board-dm6446evm.h b/arch/arm/mach-davinci/include/mach/board-dm6446evm.h deleted file mode 100644 index 3216f21c1238..000000000000 --- a/arch/arm/mach-davinci/include/mach/board-dm6446evm.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * DaVinci DM6446 EVM board specific headers - * - * Author: Kevin Hilman, Deep Root Systems, LLC - * - * 2007 (c) Deep Root Systems, LLC. 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 ifndef. - */ - -#ifndef _MACH_DAVINCI_DM6446EVM_H -#define _MACH_DAVINCI_DM6446EVM_H - -#include - -int dm6446evm_eeprom_read(char *buf, off_t off, size_t count); -int dm6446evm_eeprom_write(char *buf, off_t off, size_t count); - -#endif diff --git a/arch/arm/mach-davinci/include/mach/common.h b/arch/arm/mach-davinci/include/mach/common.h index 191770976250..a1f03b606d8f 100644 --- a/arch/arm/mach-davinci/include/mach/common.h +++ b/arch/arm/mach-davinci/include/mach/common.h @@ -17,7 +17,8 @@ struct sys_timer; extern struct sys_timer davinci_timer; extern void davinci_irq_init(void); -extern void davinci_map_common_io(void); +extern void __iomem *davinci_intc_base; +extern int davinci_intc_type; /* parameters describe VBUS sourcing for host mode */ extern void setup_usb(unsigned mA, unsigned potpgt_msec); @@ -25,4 +26,56 @@ extern void setup_usb(unsigned mA, unsigned potpgt_msec); /* parameters describe VBUS sourcing for host mode */ extern void setup_usb(unsigned mA, unsigned potpgt_msec); +struct davinci_timer_instance { + void __iomem *base; + u32 bottom_irq; + u32 top_irq; + unsigned long cmp_off; + unsigned int cmp_irq; +}; + +struct davinci_timer_info { + struct davinci_timer_instance *timers; + unsigned int clockevent_id; + unsigned int clocksource_id; +}; + +/* SoC specific init support */ +struct davinci_soc_info { + struct map_desc *io_desc; + unsigned long io_desc_num; + u32 cpu_id; + u32 jtag_id; + void __iomem *jtag_id_base; + struct davinci_id *ids; + unsigned long ids_num; + struct davinci_clk *cpu_clks; + void __iomem **psc_bases; + unsigned long psc_bases_num; + void __iomem *pinmux_base; + const struct mux_config *pinmux_pins; + unsigned long pinmux_pins_num; + void __iomem *intc_base; + int intc_type; + u8 *intc_irq_prios; + unsigned long intc_irq_num; + struct davinci_timer_info *timer_info; + void __iomem *wdt_base; + void __iomem *gpio_base; + unsigned gpio_num; + unsigned gpio_irq; + struct platform_device *serial_dev; + struct emac_platform_data *emac_pdata; + dma_addr_t sram_dma; + unsigned sram_len; +}; + +extern struct davinci_soc_info davinci_soc_info; + +extern void davinci_common_init(struct davinci_soc_info *soc_info); + +/* standard place to map on-chip SRAMs; they *may* support DMA */ +#define SRAM_VIRT 0xfffe0000 +#define SRAM_SIZE SZ_128K + #endif /* __ARCH_ARM_MACH_DAVINCI_COMMON_H */ diff --git a/arch/arm/mach-davinci/include/mach/cp_intc.h b/arch/arm/mach-davinci/include/mach/cp_intc.h new file mode 100644 index 000000000000..c4d27eec8064 --- /dev/null +++ b/arch/arm/mach-davinci/include/mach/cp_intc.h @@ -0,0 +1,57 @@ +/* + * TI Common Platform Interrupt Controller (cp_intc) definitions + * + * Author: Steve Chen + * Copyright (C) 2008-2009, 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. + */ +#ifndef __ASM_HARDWARE_CP_INTC_H +#define __ASM_HARDWARE_CP_INTC_H + +#define CP_INTC_REV 0x00 +#define CP_INTC_CTRL 0x04 +#define CP_INTC_HOST_CTRL 0x0C +#define CP_INTC_GLOBAL_ENABLE 0x10 +#define CP_INTC_GLOBAL_NESTING_LEVEL 0x1C +#define CP_INTC_SYS_STAT_IDX_SET 0x20 +#define CP_INTC_SYS_STAT_IDX_CLR 0x24 +#define CP_INTC_SYS_ENABLE_IDX_SET 0x28 +#define CP_INTC_SYS_ENABLE_IDX_CLR 0x2C +#define CP_INTC_GLOBAL_WAKEUP_ENABLE 0x30 +#define CP_INTC_HOST_ENABLE_IDX_SET 0x34 +#define CP_INTC_HOST_ENABLE_IDX_CLR 0x38 +#define CP_INTC_PACING_PRESCALE 0x40 +#define CP_INTC_VECTOR_BASE 0x50 +#define CP_INTC_VECTOR_SIZE 0x54 +#define CP_INTC_VECTOR_NULL 0x58 +#define CP_INTC_PRIO_IDX 0x80 +#define CP_INTC_PRIO_VECTOR 0x84 +#define CP_INTC_SECURE_ENABLE 0x90 +#define CP_INTC_SECURE_PRIO_IDX 0x94 +#define CP_INTC_PACING_PARAM(n) (0x0100 + (n << 4)) +#define CP_INTC_PACING_DEC(n) (0x0104 + (n << 4)) +#define CP_INTC_PACING_MAP(n) (0x0108 + (n << 4)) +#define CP_INTC_SYS_RAW_STAT(n) (0x0200 + (n << 2)) +#define CP_INTC_SYS_STAT_CLR(n) (0x0280 + (n << 2)) +#define CP_INTC_SYS_ENABLE_SET(n) (0x0300 + (n << 2)) +#define CP_INTC_SYS_ENABLE_CLR(n) (0x0380 + (n << 2)) +#define CP_INTC_CHAN_MAP(n) (0x0400 + (n << 2)) +#define CP_INTC_HOST_MAP(n) (0x0800 + (n << 2)) +#define CP_INTC_HOST_PRIO_IDX(n) (0x0900 + (n << 2)) +#define CP_INTC_SYS_POLARITY(n) (0x0D00 + (n << 2)) +#define CP_INTC_SYS_TYPE(n) (0x0D80 + (n << 2)) +#define CP_INTC_WAKEUP_ENABLE(n) (0x0E00 + (n << 2)) +#define CP_INTC_DEBUG_SELECT(n) (0x0F00 + (n << 2)) +#define CP_INTC_SYS_SECURE_ENABLE(n) (0x1000 + (n << 2)) +#define CP_INTC_HOST_NESTING_LEVEL(n) (0x1100 + (n << 2)) +#define CP_INTC_HOST_ENABLE(n) (0x1500 + (n << 2)) +#define CP_INTC_HOST_PRIO_VECTOR(n) (0x1600 + (n << 2)) +#define CP_INTC_VECTOR_ADDR(n) (0x2000 + (n << 2)) + +void __init cp_intc_init(void __iomem *base, unsigned short num_irq, + u8 *irq_prio); + +#endif /* __ASM_HARDWARE_CP_INTC_H */ diff --git a/arch/arm/mach-davinci/include/mach/cputype.h b/arch/arm/mach-davinci/include/mach/cputype.h index 27cfb1b3a662..d12a5ed2959a 100644 --- a/arch/arm/mach-davinci/include/mach/cputype.h +++ b/arch/arm/mach-davinci/include/mach/cputype.h @@ -16,17 +16,30 @@ #ifndef _ASM_ARCH_CPU_H #define _ASM_ARCH_CPU_H -extern unsigned int davinci_rev(void); +#include -#define IS_DAVINCI_CPU(type, id) \ -static inline int is_davinci_dm ##type(void) \ -{ \ - return (davinci_rev() == (id)) ? 1 : 0; \ +struct davinci_id { + u8 variant; /* JTAG ID bits 31:28 */ + u16 part_no; /* JTAG ID bits 27:12 */ + u16 manufacturer; /* JTAG ID bits 11:1 */ + u32 cpu_id; + char *name; +}; + +/* Can use lower 16 bits of cpu id for a variant when required */ +#define DAVINCI_CPU_ID_DM6446 0x64460000 +#define DAVINCI_CPU_ID_DM6467 0x64670000 +#define DAVINCI_CPU_ID_DM355 0x03550000 + +#define IS_DAVINCI_CPU(type, id) \ +static inline int is_davinci_ ##type(void) \ +{ \ + return (davinci_soc_info.cpu_id == (id)); \ } -IS_DAVINCI_CPU(644x, 0x6446) -IS_DAVINCI_CPU(646x, 0x6467) -IS_DAVINCI_CPU(355, 0x355) +IS_DAVINCI_CPU(dm644x, DAVINCI_CPU_ID_DM6446) +IS_DAVINCI_CPU(dm646x, DAVINCI_CPU_ID_DM6467) +IS_DAVINCI_CPU(dm355, DAVINCI_CPU_ID_DM355) #ifdef CONFIG_ARCH_DAVINCI_DM644x #define cpu_is_davinci_dm644x() is_davinci_dm644x() diff --git a/arch/arm/mach-davinci/include/mach/debug-macro.S b/arch/arm/mach-davinci/include/mach/debug-macro.S index e6c0f0d5d062..de3fc2182b47 100644 --- a/arch/arm/mach-davinci/include/mach/debug-macro.S +++ b/arch/arm/mach-davinci/include/mach/debug-macro.S @@ -9,6 +9,16 @@ * or implied. */ +/* Modifications + * Jan 2009 Chaithrika U S Added senduart, busyuart, waituart + * macros, based on debug-8250.S file + * but using 32-bit accesses required for + * some davinci devices. + */ + +#include +#define UART_SHIFT 2 + .macro addruart, rx mrc p15, 0, \rx, c1, c0 tst \rx, #1 @ MMU enabled? @@ -17,5 +27,22 @@ orr \rx, \rx, #0x00c20000 @ UART 0 .endm -#define UART_SHIFT 2 -#include + .macro senduart,rd,rx + str \rd, [\rx, #UART_TX << UART_SHIFT] + .endm + + .macro busyuart,rd,rx +1002: ldr \rd, [\rx, #UART_LSR << UART_SHIFT] + and \rd, \rd, #UART_LSR_TEMT | UART_LSR_THRE + teq \rd, #UART_LSR_TEMT | UART_LSR_THRE + bne 1002b + .endm + + .macro waituart,rd,rx +#ifdef FLOW_CONTROL +1001: ldr \rd, [\rx, #UART_MSR << UART_SHIFT] + tst \rd, #UART_MSR_CTS + beq 1001b +#endif + .endm + diff --git a/arch/arm/mach-davinci/include/mach/dm355.h b/arch/arm/mach-davinci/include/mach/dm355.h new file mode 100644 index 000000000000..54903b72438e --- /dev/null +++ b/arch/arm/mach-davinci/include/mach/dm355.h @@ -0,0 +1,22 @@ +/* + * Chip specific defines for DM355 SoC + * + * Author: Kevin Hilman, Deep Root Systems, LLC + * + * 2007 (c) Deep Root Systems, LLC. 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. + */ +#ifndef __ASM_ARCH_DM355_H +#define __ASM_ARCH_DM355_H + +#include + +struct spi_board_info; + +void __init dm355_init(void); +void dm355_init_spi0(unsigned chipselect_mask, + struct spi_board_info *info, unsigned len); + +#endif /* __ASM_ARCH_DM355_H */ diff --git a/arch/arm/mach-davinci/include/mach/dm644x.h b/arch/arm/mach-davinci/include/mach/dm644x.h index 3dcb9f4e58b4..15d42b92a8c9 100644 --- a/arch/arm/mach-davinci/include/mach/dm644x.h +++ b/arch/arm/mach-davinci/include/mach/dm644x.h @@ -24,6 +24,7 @@ #include #include +#include #define DM644X_EMAC_BASE (0x01C80000) #define DM644X_EMAC_CNTRL_OFFSET (0x0000) diff --git a/arch/arm/mach-davinci/include/mach/dm646x.h b/arch/arm/mach-davinci/include/mach/dm646x.h new file mode 100644 index 000000000000..1fc764c8646e --- /dev/null +++ b/arch/arm/mach-davinci/include/mach/dm646x.h @@ -0,0 +1,26 @@ +/* + * Chip specific defines for DM646x SoC + * + * Author: Kevin Hilman, Deep Root Systems, LLC + * + * 2007 (c) Deep Root Systems, LLC. 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. + */ +#ifndef __ASM_ARCH_DM646X_H +#define __ASM_ARCH_DM646X_H + +#include +#include + +#define DM646X_EMAC_BASE (0x01C80000) +#define DM646X_EMAC_CNTRL_OFFSET (0x0000) +#define DM646X_EMAC_CNTRL_MOD_OFFSET (0x1000) +#define DM646X_EMAC_CNTRL_RAM_OFFSET (0x2000) +#define DM646X_EMAC_MDIO_OFFSET (0x4000) +#define DM646X_EMAC_CNTRL_RAM_SIZE (0x2000) + +void __init dm646x_init(void); + +#endif /* __ASM_ARCH_DM646X_H */ diff --git a/arch/arm/mach-davinci/include/mach/edma.h b/arch/arm/mach-davinci/include/mach/edma.h index f6fc5396dafc..24a379239d7f 100644 --- a/arch/arm/mach-davinci/include/mach/edma.h +++ b/arch/arm/mach-davinci/include/mach/edma.h @@ -208,10 +208,6 @@ void edma_clear_event(unsigned channel); void edma_pause(unsigned channel); void edma_resume(unsigned channel); -/* UNRELATED TO DMA */ -int davinci_alloc_iram(unsigned size); -void davinci_free_iram(unsigned addr, unsigned size); - /* platform_data for EDMA driver */ struct edma_soc_info { diff --git a/arch/arm/mach-davinci/include/mach/emac.h b/arch/arm/mach-davinci/include/mach/emac.h new file mode 100644 index 000000000000..beff4fb7c845 --- /dev/null +++ b/arch/arm/mach-davinci/include/mach/emac.h @@ -0,0 +1,36 @@ +/* + * TI DaVinci EMAC platform support + * + * Author: Kevin Hilman, Deep Root Systems, LLC + * + * 2007 (c) Deep Root Systems, LLC. 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. + */ +#ifndef _MACH_DAVINCI_EMAC_H +#define _MACH_DAVINCI_EMAC_H + +#include +#include + +struct emac_platform_data { + char mac_addr[ETH_ALEN]; + u32 ctrl_reg_offset; + u32 ctrl_mod_reg_offset; + u32 ctrl_ram_offset; + u32 mdio_reg_offset; + u32 ctrl_ram_size; + u32 phy_mask; + u32 mdio_max_freq; + u8 rmii_en; + u8 version; +}; + +enum { + EMAC_VERSION_1, /* DM644x */ + EMAC_VERSION_2, /* DM646x */ +}; + +void davinci_get_mac_addr(struct memory_accessor *mem_acc, void *context); +#endif diff --git a/arch/arm/mach-davinci/include/mach/entry-macro.S b/arch/arm/mach-davinci/include/mach/entry-macro.S index 039b84f933b3..fbdebc7cb409 100644 --- a/arch/arm/mach-davinci/include/mach/entry-macro.S +++ b/arch/arm/mach-davinci/include/mach/entry-macro.S @@ -15,17 +15,36 @@ .endm .macro get_irqnr_preamble, base, tmp - ldr \base, =IO_ADDRESS(DAVINCI_ARM_INTC_BASE) + ldr \base, =davinci_intc_base + ldr \base, [\base] .endm .macro arch_ret_to_user, tmp1, tmp2 .endm .macro get_irqnr_and_base, irqnr, irqstat, base, tmp +#if defined(CONFIG_AINTC) && defined(CONFIG_CP_INTC) + ldr \tmp, =davinci_intc_type + ldr \tmp, [\tmp] + cmp \tmp, #DAVINCI_INTC_TYPE_CP_INTC + beq 1001f +#endif +#if defined(CONFIG_AINTC) ldr \tmp, [\base, #0x14] - mov \tmp, \tmp, lsr #2 + movs \tmp, \tmp, lsr #2 sub \irqnr, \tmp, #1 - cmp \tmp, #0 + b 1002f +#endif +#if defined(CONFIG_CP_INTC) +1001: ldr \irqnr, [\base, #0x80] /* get irq number */ + and \irqnr, \irqnr, #0xff /* irq is in bits 0-9 */ + mov \tmp, \irqnr, lsr #3 + and \tmp, \tmp, #0xfc + add \tmp, \tmp, #0x280 /* get the register offset */ + ldr \irqstat, [\base, \tmp] /* get the intc status */ + cmp \irqstat, #0x0 +#endif +1002: .endm .macro irq_prio_table diff --git a/arch/arm/mach-davinci/include/mach/gpio.h b/arch/arm/mach-davinci/include/mach/gpio.h index efe3281364e6..ae0745568316 100644 --- a/arch/arm/mach-davinci/include/mach/gpio.h +++ b/arch/arm/mach-davinci/include/mach/gpio.h @@ -17,6 +17,7 @@ #include #include +#include #define DAVINCI_GPIO_BASE 0x01C67000 @@ -67,15 +68,16 @@ static inline struct gpio_controller *__iomem __gpio_to_controller(unsigned gpio) { void *__iomem ptr; + void __iomem *base = davinci_soc_info.gpio_base; if (gpio < 32 * 1) - ptr = IO_ADDRESS(DAVINCI_GPIO_BASE + 0x10); + ptr = base + 0x10; else if (gpio < 32 * 2) - ptr = IO_ADDRESS(DAVINCI_GPIO_BASE + 0x38); + ptr = base + 0x38; else if (gpio < 32 * 3) - ptr = IO_ADDRESS(DAVINCI_GPIO_BASE + 0x60); + ptr = base + 0x60; else if (gpio < 32 * 4) - ptr = IO_ADDRESS(DAVINCI_GPIO_BASE + 0x88); + ptr = base + 0x88; else ptr = NULL; return ptr; @@ -142,13 +144,13 @@ static inline int gpio_to_irq(unsigned gpio) { if (gpio >= DAVINCI_N_GPIO) return -EINVAL; - return DAVINCI_N_AINTC_IRQ + gpio; + return davinci_soc_info.intc_irq_num + gpio; } static inline int irq_to_gpio(unsigned irq) { /* caller guarantees gpio_to_irq() succeeded */ - return irq - DAVINCI_N_AINTC_IRQ; + return irq - davinci_soc_info.intc_irq_num; } #endif /* __DAVINCI_GPIO_H */ diff --git a/arch/arm/mach-davinci/include/mach/irqs.h b/arch/arm/mach-davinci/include/mach/irqs.h index 18066074c995..bc5d6aaa69a3 100644 --- a/arch/arm/mach-davinci/include/mach/irqs.h +++ b/arch/arm/mach-davinci/include/mach/irqs.h @@ -30,6 +30,9 @@ /* Base address */ #define DAVINCI_ARM_INTC_BASE 0x01C48000 +#define DAVINCI_INTC_TYPE_AINTC 0 +#define DAVINCI_INTC_TYPE_CP_INTC 1 + /* Interrupt lines */ #define IRQ_VDINT0 0 #define IRQ_VDINT1 1 diff --git a/arch/arm/mach-davinci/include/mach/memory.h b/arch/arm/mach-davinci/include/mach/memory.h index 86c25c7f3ce3..c712c7cdf38f 100644 --- a/arch/arm/mach-davinci/include/mach/memory.h +++ b/arch/arm/mach-davinci/include/mach/memory.h @@ -21,7 +21,6 @@ * Definitions **************************************************************************/ #define DAVINCI_DDR_BASE 0x80000000 -#define DAVINCI_IRAM_BASE 0x00008000 /* ARM Internal RAM */ #define PHYS_OFFSET DAVINCI_DDR_BASE diff --git a/arch/arm/mach-davinci/include/mach/mmc.h b/arch/arm/mach-davinci/include/mach/mmc.h new file mode 100644 index 000000000000..5a85e24f3673 --- /dev/null +++ b/arch/arm/mach-davinci/include/mach/mmc.h @@ -0,0 +1,33 @@ +/* + * Board-specific MMC configuration + */ + +#ifndef _DAVINCI_MMC_H +#define _DAVINCI_MMC_H + +#include +#include + +struct davinci_mmc_config { + /* get_cd()/get_wp() may sleep */ + int (*get_cd)(int module); + int (*get_ro)(int module); + /* wires == 0 is equivalent to wires == 4 (4-bit parallel) */ + u8 wires; + + u32 max_freq; + + /* any additional host capabilities: OR'd in to mmc->f_caps */ + u32 caps; + + /* Version of the MMC/SD controller */ + u8 version; +}; +void davinci_setup_mmc(int module, struct davinci_mmc_config *config); + +enum { + MMC_CTLR_VERSION_1 = 0, /* DM644x and DM355 */ + MMC_CTLR_VERSION_2, /* DA830 */ +}; + +#endif diff --git a/arch/arm/mach-davinci/include/mach/mux.h b/arch/arm/mach-davinci/include/mach/mux.h index bae22cb3e27b..27378458542f 100644 --- a/arch/arm/mach-davinci/include/mach/mux.h +++ b/arch/arm/mach-davinci/include/mach/mux.h @@ -19,16 +19,6 @@ #ifndef __INC_MACH_MUX_H #define __INC_MACH_MUX_H -/* System module registers */ -#define PINMUX0 0x00 -#define PINMUX1 0x04 -/* dm355 only */ -#define PINMUX2 0x08 -#define PINMUX3 0x0c -#define PINMUX4 0x10 -#define INTMUX 0x18 -#define EVTMUX 0x1c - struct mux_config { const char *name; const char *mux_reg_name; @@ -168,15 +158,9 @@ enum davinci_dm355_index { #ifdef CONFIG_DAVINCI_MUX /* setup pin muxing */ -extern void davinci_mux_init(void); -extern int davinci_mux_register(const struct mux_config *pins, - unsigned long size); extern int davinci_cfg_reg(unsigned long reg_cfg); #else /* boot loader does it all (no warnings from CONFIG_DAVINCI_MUX_WARNINGS) */ -static inline void davinci_mux_init(void) {} -static inline int davinci_mux_register(const struct mux_config *pins, - unsigned long size) { return 0; } static inline int davinci_cfg_reg(unsigned long reg_cfg) { return 0; } #endif diff --git a/arch/arm/mach-davinci/include/mach/nand.h b/arch/arm/mach-davinci/include/mach/nand.h index aa482841270b..b520c4b5678a 100644 --- a/arch/arm/mach-davinci/include/mach/nand.h +++ b/arch/arm/mach-davinci/include/mach/nand.h @@ -68,10 +68,14 @@ struct davinci_nand_pdata { /* platform_data */ /* none == NAND_ECC_NONE (strongly *not* advised!!) * soft == NAND_ECC_SOFT - * 1-bit == NAND_ECC_HW - * 4-bit == NAND_ECC_HW_SYNDROME (not on all chips) + * else == NAND_ECC_HW, according to ecc_bits + * + * All DaVinci-family chips support 1-bit hardware ECC. + * Newer ones also support 4-bit ECC, but are awkward + * using it with large page chips. */ nand_ecc_modes_t ecc_mode; + u8 ecc_bits; /* e.g. NAND_BUSWIDTH_16 or NAND_USE_FLASH_BBT */ unsigned options; diff --git a/arch/arm/mach-davinci/include/mach/psc.h b/arch/arm/mach-davinci/include/mach/psc.h index 55a90d419fac..ab8a2586d1cc 100644 --- a/arch/arm/mach-davinci/include/mach/psc.h +++ b/arch/arm/mach-davinci/include/mach/psc.h @@ -27,6 +27,8 @@ #ifndef __ASM_ARCH_PSC_H #define __ASM_ARCH_PSC_H +#define DAVINCI_PWR_SLEEP_CNTRL_BASE 0x01C41000 + /* Power and Sleep Controller (PSC) Domains */ #define DAVINCI_GPSC_ARMDOMAIN 0 #define DAVINCI_GPSC_DSPDOMAIN 1 @@ -116,8 +118,8 @@ #define DM646X_LPSC_TIMER1 35 #define DM646X_LPSC_ARM_INTC 45 -extern int davinci_psc_is_clk_active(unsigned int id); -extern void davinci_psc_config(unsigned int domain, unsigned int id, - char enable); +extern int davinci_psc_is_clk_active(unsigned int ctlr, unsigned int id); +extern void davinci_psc_config(unsigned int domain, unsigned int ctlr, + unsigned int id, char enable); #endif /* __ASM_ARCH_PSC_H */ diff --git a/arch/arm/mach-davinci/include/mach/serial.h b/arch/arm/mach-davinci/include/mach/serial.h index 632847d74a1c..794fa5cf93c1 100644 --- a/arch/arm/mach-davinci/include/mach/serial.h +++ b/arch/arm/mach-davinci/include/mach/serial.h @@ -18,8 +18,6 @@ #define DAVINCI_UART1_BASE (IO_PHYS + 0x20400) #define DAVINCI_UART2_BASE (IO_PHYS + 0x20800) -#define DM355_UART2_BASE (IO_PHYS + 0x206000) - /* DaVinci UART register offsets */ #define UART_DAVINCI_PWREMU 0x0c #define UART_DM646X_SCR 0x10 @@ -30,6 +28,6 @@ struct davinci_uart_config { unsigned int enabled_uarts; }; -extern void davinci_serial_init(struct davinci_uart_config *); +extern int davinci_serial_init(struct davinci_uart_config *); #endif /* __ASM_ARCH_SERIAL_H */ diff --git a/arch/arm/mach-davinci/include/mach/sram.h b/arch/arm/mach-davinci/include/mach/sram.h new file mode 100644 index 000000000000..111f7cc71e07 --- /dev/null +++ b/arch/arm/mach-davinci/include/mach/sram.h @@ -0,0 +1,27 @@ +/* + * mach/sram.h - DaVinci simple SRAM allocator + * + * Copyright (C) 2009 David Brownell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __MACH_SRAM_H +#define __MACH_SRAM_H + +/* ARBITRARY: SRAM allocations are multiples of this 2^N size */ +#define SRAM_GRANULARITY 512 + +/* + * SRAM allocations return a CPU virtual address, or NULL on error. + * If a DMA address is requested and the SRAM supports DMA, its + * mapped address is also returned. + * + * Errors include SRAM memory not being available, and requesting + * DMA mapped SRAM on systems which don't allow that. + */ +extern void *sram_alloc(size_t len, dma_addr_t *dma); +extern void sram_free(void *addr, size_t len); + +#endif /* __MACH_SRAM_H */ diff --git a/arch/arm/mach-davinci/include/mach/time.h b/arch/arm/mach-davinci/include/mach/time.h new file mode 100644 index 000000000000..1c971d8d8ba8 --- /dev/null +++ b/arch/arm/mach-davinci/include/mach/time.h @@ -0,0 +1,35 @@ +/* + * Local header file for DaVinci time code. + * + * Author: Kevin Hilman, MontaVista Software, Inc. + * + * 2007 (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. + */ +#ifndef __ARCH_ARM_MACH_DAVINCI_TIME_H +#define __ARCH_ARM_MACH_DAVINCI_TIME_H + +#define DAVINCI_TIMER0_BASE (IO_PHYS + 0x21400) +#define DAVINCI_TIMER1_BASE (IO_PHYS + 0x21800) +#define DAVINCI_WDOG_BASE (IO_PHYS + 0x21C00) + +enum { + T0_BOT, + T0_TOP, + T1_BOT, + T1_TOP, + NUM_TIMERS +}; + +#define IS_TIMER1(id) (id & 0x2) +#define IS_TIMER0(id) (!IS_TIMER1(id)) +#define IS_TIMER_TOP(id) ((id & 0x1)) +#define IS_TIMER_BOT(id) (!IS_TIMER_TOP(id)) + +#define ID_TO_TIMER(id) (IS_TIMER1(id) != 0) + +extern struct davinci_timer_instance davinci_timer_instance[]; + +#endif /* __ARCH_ARM_MACH_DAVINCI_TIME_H */ diff --git a/arch/arm/mach-davinci/include/mach/uncompress.h b/arch/arm/mach-davinci/include/mach/uncompress.h index 8c165def37b6..1e27475f9a23 100644 --- a/arch/arm/mach-davinci/include/mach/uncompress.h +++ b/arch/arm/mach-davinci/include/mach/uncompress.h @@ -13,11 +13,24 @@ #include #include +#include + +extern unsigned int __machine_arch_type; + +static u32 *uart; + +static u32 *get_uart_base(void) +{ + /* Add logic here for new platforms, using __macine_arch_type */ + return (u32 *)DAVINCI_UART0_BASE; +} + /* PORT_16C550A, in polled non-fifo mode */ static void putc(char c) { - volatile u32 *uart = (volatile void *) DAVINCI_UART0_BASE; + if (!uart) + uart = get_uart_base(); while (!(uart[UART_LSR] & UART_LSR_THRE)) barrier(); @@ -26,7 +39,9 @@ static void putc(char c) static inline void flush(void) { - volatile u32 *uart = (volatile void *) DAVINCI_UART0_BASE; + if (!uart) + uart = get_uart_base(); + while (!(uart[UART_LSR] & UART_LSR_THRE)) barrier(); } diff --git a/arch/arm/mach-davinci/io.c b/arch/arm/mach-davinci/io.c index a548abb513e2..49912b48b1b0 100644 --- a/arch/arm/mach-davinci/io.c +++ b/arch/arm/mach-davinci/io.c @@ -9,47 +9,9 @@ */ #include -#include -#include #include #include -#include - -#include -#include - -extern void davinci_check_revision(void); - -/* - * The machine specific code may provide the extra mapping besides the - * default mapping provided here. - */ -static struct map_desc davinci_io_desc[] __initdata = { - { - .virtual = IO_VIRT, - .pfn = __phys_to_pfn(IO_PHYS), - .length = IO_SIZE, - .type = MT_DEVICE - }, -}; - -void __init davinci_map_common_io(void) -{ - iotable_init(davinci_io_desc, ARRAY_SIZE(davinci_io_desc)); - - /* Normally devicemaps_init() would flush caches and tlb after - * mdesc->map_io(), but we must also do it here because of the CPU - * revision check below. - */ - local_flush_tlb_all(); - flush_cache_all(); - - /* We want to check CPU revision early for cpu_is_xxxx() macros. - * IO space mapping must be initialized before we can do that. - */ - davinci_check_revision(); -} #define BETWEEN(p, st, sz) ((p) >= (st) && (p) < ((st) + (sz))) #define XLATE(p, pst, vst) ((void __iomem *)((p) - (pst) + (vst))) diff --git a/arch/arm/mach-davinci/irq.c b/arch/arm/mach-davinci/irq.c index 5a324c90e291..af92ffee8471 100644 --- a/arch/arm/mach-davinci/irq.c +++ b/arch/arm/mach-davinci/irq.c @@ -26,6 +26,7 @@ #include #include +#include #include #define IRQ_BIT(irq) ((irq) & 0x1f) @@ -41,18 +42,14 @@ #define IRQ_INTPRI0_REG_OFFSET 0x0030 #define IRQ_INTPRI7_REG_OFFSET 0x004C -const u8 *davinci_def_priorities; - -#define INTC_BASE IO_ADDRESS(DAVINCI_ARM_INTC_BASE) - static inline unsigned int davinci_irq_readl(int offset) { - return __raw_readl(INTC_BASE + offset); + return __raw_readl(davinci_intc_base + offset); } static inline void davinci_irq_writel(unsigned long value, int offset) { - __raw_writel(value, INTC_BASE + offset); + __raw_writel(value, davinci_intc_base + offset); } /* Disable interrupt */ @@ -113,217 +110,11 @@ static struct irq_chip davinci_irq_chip_0 = { .unmask = davinci_unmask_irq, }; -/* FIQ are pri 0-1; otherwise 2-7, with 7 lowest priority */ -static const u8 dm644x_default_priorities[DAVINCI_N_AINTC_IRQ] __initdata = { - [IRQ_VDINT0] = 2, - [IRQ_VDINT1] = 6, - [IRQ_VDINT2] = 6, - [IRQ_HISTINT] = 6, - [IRQ_H3AINT] = 6, - [IRQ_PRVUINT] = 6, - [IRQ_RSZINT] = 6, - [7] = 7, - [IRQ_VENCINT] = 6, - [IRQ_ASQINT] = 6, - [IRQ_IMXINT] = 6, - [IRQ_VLCDINT] = 6, - [IRQ_USBINT] = 4, - [IRQ_EMACINT] = 4, - [14] = 7, - [15] = 7, - [IRQ_CCINT0] = 5, /* dma */ - [IRQ_CCERRINT] = 5, /* dma */ - [IRQ_TCERRINT0] = 5, /* dma */ - [IRQ_TCERRINT] = 5, /* dma */ - [IRQ_PSCIN] = 7, - [21] = 7, - [IRQ_IDE] = 4, - [23] = 7, - [IRQ_MBXINT] = 7, - [IRQ_MBRINT] = 7, - [IRQ_MMCINT] = 7, - [IRQ_SDIOINT] = 7, - [28] = 7, - [IRQ_DDRINT] = 7, - [IRQ_AEMIFINT] = 7, - [IRQ_VLQINT] = 4, - [IRQ_TINT0_TINT12] = 2, /* clockevent */ - [IRQ_TINT0_TINT34] = 2, /* clocksource */ - [IRQ_TINT1_TINT12] = 7, /* DSP timer */ - [IRQ_TINT1_TINT34] = 7, /* system tick */ - [IRQ_PWMINT0] = 7, - [IRQ_PWMINT1] = 7, - [IRQ_PWMINT2] = 7, - [IRQ_I2C] = 3, - [IRQ_UARTINT0] = 3, - [IRQ_UARTINT1] = 3, - [IRQ_UARTINT2] = 3, - [IRQ_SPINT0] = 3, - [IRQ_SPINT1] = 3, - [45] = 7, - [IRQ_DSP2ARM0] = 4, - [IRQ_DSP2ARM1] = 4, - [IRQ_GPIO0] = 7, - [IRQ_GPIO1] = 7, - [IRQ_GPIO2] = 7, - [IRQ_GPIO3] = 7, - [IRQ_GPIO4] = 7, - [IRQ_GPIO5] = 7, - [IRQ_GPIO6] = 7, - [IRQ_GPIO7] = 7, - [IRQ_GPIOBNK0] = 7, - [IRQ_GPIOBNK1] = 7, - [IRQ_GPIOBNK2] = 7, - [IRQ_GPIOBNK3] = 7, - [IRQ_GPIOBNK4] = 7, - [IRQ_COMMTX] = 7, - [IRQ_COMMRX] = 7, - [IRQ_EMUINT] = 7, -}; - -static const u8 dm646x_default_priorities[DAVINCI_N_AINTC_IRQ] = { - [IRQ_DM646X_VP_VERTINT0] = 7, - [IRQ_DM646X_VP_VERTINT1] = 7, - [IRQ_DM646X_VP_VERTINT2] = 7, - [IRQ_DM646X_VP_VERTINT3] = 7, - [IRQ_DM646X_VP_ERRINT] = 7, - [IRQ_DM646X_RESERVED_1] = 7, - [IRQ_DM646X_RESERVED_2] = 7, - [IRQ_DM646X_WDINT] = 7, - [IRQ_DM646X_CRGENINT0] = 7, - [IRQ_DM646X_CRGENINT1] = 7, - [IRQ_DM646X_TSIFINT0] = 7, - [IRQ_DM646X_TSIFINT1] = 7, - [IRQ_DM646X_VDCEINT] = 7, - [IRQ_DM646X_USBINT] = 7, - [IRQ_DM646X_USBDMAINT] = 7, - [IRQ_DM646X_PCIINT] = 7, - [IRQ_CCINT0] = 7, /* dma */ - [IRQ_CCERRINT] = 7, /* dma */ - [IRQ_TCERRINT0] = 7, /* dma */ - [IRQ_TCERRINT] = 7, /* dma */ - [IRQ_DM646X_TCERRINT2] = 7, - [IRQ_DM646X_TCERRINT3] = 7, - [IRQ_DM646X_IDE] = 7, - [IRQ_DM646X_HPIINT] = 7, - [IRQ_DM646X_EMACRXTHINT] = 7, - [IRQ_DM646X_EMACRXINT] = 7, - [IRQ_DM646X_EMACTXINT] = 7, - [IRQ_DM646X_EMACMISCINT] = 7, - [IRQ_DM646X_MCASP0TXINT] = 7, - [IRQ_DM646X_MCASP0RXINT] = 7, - [IRQ_AEMIFINT] = 7, - [IRQ_DM646X_RESERVED_3] = 7, - [IRQ_DM646X_MCASP1TXINT] = 7, /* clockevent */ - [IRQ_TINT0_TINT34] = 7, /* clocksource */ - [IRQ_TINT1_TINT12] = 7, /* DSP timer */ - [IRQ_TINT1_TINT34] = 7, /* system tick */ - [IRQ_PWMINT0] = 7, - [IRQ_PWMINT1] = 7, - [IRQ_DM646X_VLQINT] = 7, - [IRQ_I2C] = 7, - [IRQ_UARTINT0] = 7, - [IRQ_UARTINT1] = 7, - [IRQ_DM646X_UARTINT2] = 7, - [IRQ_DM646X_SPINT0] = 7, - [IRQ_DM646X_SPINT1] = 7, - [IRQ_DM646X_DSP2ARMINT] = 7, - [IRQ_DM646X_RESERVED_4] = 7, - [IRQ_DM646X_PSCINT] = 7, - [IRQ_DM646X_GPIO0] = 7, - [IRQ_DM646X_GPIO1] = 7, - [IRQ_DM646X_GPIO2] = 7, - [IRQ_DM646X_GPIO3] = 7, - [IRQ_DM646X_GPIO4] = 7, - [IRQ_DM646X_GPIO5] = 7, - [IRQ_DM646X_GPIO6] = 7, - [IRQ_DM646X_GPIO7] = 7, - [IRQ_DM646X_GPIOBNK0] = 7, - [IRQ_DM646X_GPIOBNK1] = 7, - [IRQ_DM646X_GPIOBNK2] = 7, - [IRQ_DM646X_DDRINT] = 7, - [IRQ_DM646X_AEMIFINT] = 7, - [IRQ_COMMTX] = 7, - [IRQ_COMMRX] = 7, - [IRQ_EMUINT] = 7, -}; - -static const u8 dm355_default_priorities[DAVINCI_N_AINTC_IRQ] = { - [IRQ_DM355_CCDC_VDINT0] = 2, - [IRQ_DM355_CCDC_VDINT1] = 6, - [IRQ_DM355_CCDC_VDINT2] = 6, - [IRQ_DM355_IPIPE_HST] = 6, - [IRQ_DM355_H3AINT] = 6, - [IRQ_DM355_IPIPE_SDR] = 6, - [IRQ_DM355_IPIPEIFINT] = 6, - [IRQ_DM355_OSDINT] = 7, - [IRQ_DM355_VENCINT] = 6, - [IRQ_ASQINT] = 6, - [IRQ_IMXINT] = 6, - [IRQ_USBINT] = 4, - [IRQ_DM355_RTOINT] = 4, - [IRQ_DM355_UARTINT2] = 7, - [IRQ_DM355_TINT6] = 7, - [IRQ_CCINT0] = 5, /* dma */ - [IRQ_CCERRINT] = 5, /* dma */ - [IRQ_TCERRINT0] = 5, /* dma */ - [IRQ_TCERRINT] = 5, /* dma */ - [IRQ_DM355_SPINT2_1] = 7, - [IRQ_DM355_TINT7] = 4, - [IRQ_DM355_SDIOINT0] = 7, - [IRQ_MBXINT] = 7, - [IRQ_MBRINT] = 7, - [IRQ_MMCINT] = 7, - [IRQ_DM355_MMCINT1] = 7, - [IRQ_DM355_PWMINT3] = 7, - [IRQ_DDRINT] = 7, - [IRQ_AEMIFINT] = 7, - [IRQ_DM355_SDIOINT1] = 4, - [IRQ_TINT0_TINT12] = 2, /* clockevent */ - [IRQ_TINT0_TINT34] = 2, /* clocksource */ - [IRQ_TINT1_TINT12] = 7, /* DSP timer */ - [IRQ_TINT1_TINT34] = 7, /* system tick */ - [IRQ_PWMINT0] = 7, - [IRQ_PWMINT1] = 7, - [IRQ_PWMINT2] = 7, - [IRQ_I2C] = 3, - [IRQ_UARTINT0] = 3, - [IRQ_UARTINT1] = 3, - [IRQ_DM355_SPINT0_0] = 3, - [IRQ_DM355_SPINT0_1] = 3, - [IRQ_DM355_GPIO0] = 3, - [IRQ_DM355_GPIO1] = 7, - [IRQ_DM355_GPIO2] = 4, - [IRQ_DM355_GPIO3] = 4, - [IRQ_DM355_GPIO4] = 7, - [IRQ_DM355_GPIO5] = 7, - [IRQ_DM355_GPIO6] = 7, - [IRQ_DM355_GPIO7] = 7, - [IRQ_DM355_GPIO8] = 7, - [IRQ_DM355_GPIO9] = 7, - [IRQ_DM355_GPIOBNK0] = 7, - [IRQ_DM355_GPIOBNK1] = 7, - [IRQ_DM355_GPIOBNK2] = 7, - [IRQ_DM355_GPIOBNK3] = 7, - [IRQ_DM355_GPIOBNK4] = 7, - [IRQ_DM355_GPIOBNK5] = 7, - [IRQ_DM355_GPIOBNK6] = 7, - [IRQ_COMMTX] = 7, - [IRQ_COMMRX] = 7, - [IRQ_EMUINT] = 7, -}; - /* ARM Interrupt Controller Initialization */ void __init davinci_irq_init(void) { unsigned i; - - if (cpu_is_davinci_dm644x()) - davinci_def_priorities = dm644x_default_priorities; - else if (cpu_is_davinci_dm646x()) - davinci_def_priorities = dm646x_default_priorities; - else if (cpu_is_davinci_dm355()) - davinci_def_priorities = dm355_default_priorities; + const u8 *davinci_def_priorities = davinci_soc_info.intc_irq_prios; /* Clear all interrupt requests */ davinci_irq_writel(~0x0, FIQ_REG0_OFFSET); diff --git a/arch/arm/mach-davinci/mux.c b/arch/arm/mach-davinci/mux.c index bbba0b247a44..d310f579aa85 100644 --- a/arch/arm/mach-davinci/mux.c +++ b/arch/arm/mach-davinci/mux.c @@ -21,18 +21,7 @@ #include #include - -static const struct mux_config *mux_table; -static unsigned long pin_table_sz; - -int __init davinci_mux_register(const struct mux_config *pins, - unsigned long size) -{ - mux_table = pins; - pin_table_sz = size; - - return 0; -} +#include /* * Sets the DAVINCI MUX register based on the table @@ -40,23 +29,24 @@ int __init davinci_mux_register(const struct mux_config *pins, int __init_or_module davinci_cfg_reg(const unsigned long index) { static DEFINE_SPINLOCK(mux_spin_lock); - void __iomem *base = IO_ADDRESS(DAVINCI_SYSTEM_MODULE_BASE); + struct davinci_soc_info *soc_info = &davinci_soc_info; + void __iomem *base = soc_info->pinmux_base; unsigned long flags; const struct mux_config *cfg; unsigned int reg_orig = 0, reg = 0; unsigned int mask, warn = 0; - if (!mux_table) + if (!soc_info->pinmux_pins) BUG(); - if (index >= pin_table_sz) { + if (index >= soc_info->pinmux_pins_num) { printk(KERN_ERR "Invalid pin mux index: %lu (%lu)\n", - index, pin_table_sz); + index, soc_info->pinmux_pins_num); dump_stack(); return -ENODEV; } - cfg = &mux_table[index]; + cfg = &soc_info->pinmux_pins[index]; if (cfg->name == NULL) { printk(KERN_ERR "No entry for the specified index\n"); diff --git a/arch/arm/mach-davinci/psc.c b/arch/arm/mach-davinci/psc.c index 84171abf5f7b..a78b657e916e 100644 --- a/arch/arm/mach-davinci/psc.c +++ b/arch/arm/mach-davinci/psc.c @@ -28,8 +28,6 @@ #include #include -#define DAVINCI_PWR_SLEEP_CNTRL_BASE 0x01C41000 - /* PSC register offsets */ #define EPCPR 0x070 #define PTCMD 0x120 @@ -42,22 +40,42 @@ #define MDSTAT_STATE_MASK 0x1f /* Return nonzero iff the domain's clock is active */ -int __init davinci_psc_is_clk_active(unsigned int id) +int __init davinci_psc_is_clk_active(unsigned int ctlr, unsigned int id) { - void __iomem *psc_base = IO_ADDRESS(DAVINCI_PWR_SLEEP_CNTRL_BASE); - u32 mdstat = __raw_readl(psc_base + MDSTAT + 4 * id); + void __iomem *psc_base; + u32 mdstat; + struct davinci_soc_info *soc_info = &davinci_soc_info; + + if (!soc_info->psc_bases || (ctlr >= soc_info->psc_bases_num)) { + pr_warning("PSC: Bad psc data: 0x%x[%d]\n", + (int)soc_info->psc_bases, ctlr); + return 0; + } + + psc_base = soc_info->psc_bases[ctlr]; + mdstat = __raw_readl(psc_base + MDSTAT + 4 * id); /* if clocked, state can be "Enable" or "SyncReset" */ return mdstat & BIT(12); } /* Enable or disable a PSC domain */ -void davinci_psc_config(unsigned int domain, unsigned int id, char enable) +void davinci_psc_config(unsigned int domain, unsigned int ctlr, + unsigned int id, char enable) { u32 epcpr, ptcmd, ptstat, pdstat, pdctl1, mdstat, mdctl; - void __iomem *psc_base = IO_ADDRESS(DAVINCI_PWR_SLEEP_CNTRL_BASE); + void __iomem *psc_base; + struct davinci_soc_info *soc_info = &davinci_soc_info; u32 next_state = enable ? 0x3 : 0x2; /* 0x3 enables, 0x2 disables */ + if (!soc_info->psc_bases || (ctlr >= soc_info->psc_bases_num)) { + pr_warning("PSC: Bad psc data: 0x%x[%d]\n", + (int)soc_info->psc_bases, ctlr); + return; + } + + psc_base = soc_info->psc_bases[ctlr]; + mdctl = __raw_readl(psc_base + MDCTL + 4 * id); mdctl &= ~MDSTAT_STATE_MASK; mdctl |= next_state; diff --git a/arch/arm/mach-davinci/serial.c b/arch/arm/mach-davinci/serial.c index 695075796522..c530c7333d0a 100644 --- a/arch/arm/mach-davinci/serial.c +++ b/arch/arm/mach-davinci/serial.c @@ -33,6 +33,8 @@ #include #include #include +#include + #include "clock.h" static inline unsigned int serial_read_reg(struct plat_serial8250_port *up, @@ -49,44 +51,6 @@ static inline void serial_write_reg(struct plat_serial8250_port *p, int offset, __raw_writel(value, IO_ADDRESS(p->mapbase) + offset); } -static struct plat_serial8250_port serial_platform_data[] = { - { - .mapbase = DAVINCI_UART0_BASE, - .irq = IRQ_UARTINT0, - .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | - UPF_IOREMAP, - .iotype = UPIO_MEM, - .regshift = 2, - }, - { - .mapbase = DAVINCI_UART1_BASE, - .irq = IRQ_UARTINT1, - .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | - UPF_IOREMAP, - .iotype = UPIO_MEM, - .regshift = 2, - }, - { - .mapbase = DAVINCI_UART2_BASE, - .irq = IRQ_UARTINT2, - .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | - UPF_IOREMAP, - .iotype = UPIO_MEM, - .regshift = 2, - }, - { - .flags = 0 - }, -}; - -static struct platform_device serial_device = { - .name = "serial8250", - .id = PLAT8250_DEV_PLATFORM, - .dev = { - .platform_data = serial_platform_data, - }, -}; - static void __init davinci_serial_reset(struct plat_serial8250_port *p) { unsigned int pwremu = 0; @@ -106,35 +70,22 @@ static void __init davinci_serial_reset(struct plat_serial8250_port *p) UART_DM646X_SCR_TX_WATERMARK); } -void __init davinci_serial_init(struct davinci_uart_config *info) +int __init davinci_serial_init(struct davinci_uart_config *info) { int i; char name[16]; struct clk *uart_clk; - struct device *dev = &serial_device.dev; + struct davinci_soc_info *soc_info = &davinci_soc_info; + struct device *dev = &soc_info->serial_dev->dev; + struct plat_serial8250_port *p = dev->platform_data; /* * Make sure the serial ports are muxed on at this point. - * You have to mux them off in device drivers later on - * if not needed. + * You have to mux them off in device drivers later on if not needed. */ - for (i = 0; i < DAVINCI_MAX_NR_UARTS; i++) { - struct plat_serial8250_port *p = serial_platform_data + i; - - if (!(info->enabled_uarts & (1 << i))) { - p->flags = 0; + for (i = 0; i < DAVINCI_MAX_NR_UARTS; i++, p++) { + if (!(info->enabled_uarts & (1 << i))) continue; - } - - if (cpu_is_davinci_dm646x()) - p->iotype = UPIO_MEM32; - - if (cpu_is_davinci_dm355()) { - if (i == 2) { - p->mapbase = (unsigned long)DM355_UART2_BASE; - p->irq = IRQ_DM355_UARTINT2; - } - } sprintf(name, "uart%d", i); uart_clk = clk_get(dev, name); @@ -147,11 +98,6 @@ void __init davinci_serial_init(struct davinci_uart_config *info) davinci_serial_reset(p); } } -} -static int __init davinci_init(void) -{ - return platform_device_register(&serial_device); + return platform_device_register(soc_info->serial_dev); } - -arch_initcall(davinci_init); diff --git a/arch/arm/mach-davinci/sram.c b/arch/arm/mach-davinci/sram.c new file mode 100644 index 000000000000..db54b2a66b4d --- /dev/null +++ b/arch/arm/mach-davinci/sram.c @@ -0,0 +1,74 @@ +/* + * mach-davinci/sram.c - DaVinci simple SRAM allocator + * + * Copyright (C) 2009 David Brownell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ +#include +#include +#include +#include + +#include +#include +#include + + +static struct gen_pool *sram_pool; + +void *sram_alloc(size_t len, dma_addr_t *dma) +{ + unsigned long vaddr; + dma_addr_t dma_base = davinci_soc_info.sram_dma; + + if (dma) + *dma = 0; + if (!sram_pool || (dma && !dma_base)) + return NULL; + + vaddr = gen_pool_alloc(sram_pool, len); + if (!vaddr) + return NULL; + + if (dma) + *dma = dma_base + (vaddr - SRAM_VIRT); + return (void *)vaddr; + +} +EXPORT_SYMBOL(sram_alloc); + +void sram_free(void *addr, size_t len) +{ + gen_pool_free(sram_pool, (unsigned long) addr, len); +} +EXPORT_SYMBOL(sram_free); + + +/* + * REVISIT This supports CPU and DMA access to/from SRAM, but it + * doesn't (yet?) support some other notable uses of SRAM: as TCM + * for data and/or instructions; and holding code needed to enter + * and exit suspend states (while DRAM can't be used). + */ +static int __init sram_init(void) +{ + unsigned len = davinci_soc_info.sram_len; + int status = 0; + + if (len) { + len = min(len, SRAM_SIZE); + sram_pool = gen_pool_create(ilog2(SRAM_GRANULARITY), -1); + if (!sram_pool) + status = -ENOMEM; + } + if (sram_pool) + status = gen_pool_add(sram_pool, SRAM_VIRT, len, -1); + WARN_ON(status < 0); + return status; +} +core_initcall(sram_init); + diff --git a/arch/arm/mach-davinci/time.c b/arch/arm/mach-davinci/time.c index 494e01bff5c3..0884ca57bfb0 100644 --- a/arch/arm/mach-davinci/time.c +++ b/arch/arm/mach-davinci/time.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -28,52 +29,41 @@ #include #include #include +#include #include "clock.h" static struct clock_event_device clockevent_davinci; static unsigned int davinci_clock_tick_rate; -#define DAVINCI_TIMER0_BASE (IO_PHYS + 0x21400) -#define DAVINCI_TIMER1_BASE (IO_PHYS + 0x21800) -#define DAVINCI_WDOG_BASE (IO_PHYS + 0x21C00) - -enum { - T0_BOT = 0, T0_TOP, T1_BOT, T1_TOP, NUM_TIMERS, -}; - -#define IS_TIMER1(id) (id & 0x2) -#define IS_TIMER0(id) (!IS_TIMER1(id)) -#define IS_TIMER_TOP(id) ((id & 0x1)) -#define IS_TIMER_BOT(id) (!IS_TIMER_TOP(id)) - -static int timer_irqs[NUM_TIMERS] = { - IRQ_TINT0_TINT12, - IRQ_TINT0_TINT34, - IRQ_TINT1_TINT12, - IRQ_TINT1_TINT34, -}; - /* * This driver configures the 2 64-bit count-up timers as 4 independent * 32-bit count-up timers used as follows: - * - * T0_BOT: Timer 0, bottom: clockevent source for hrtimers - * T0_TOP: Timer 0, top : clocksource for generic timekeeping - * T1_BOT: Timer 1, bottom: (used by DSP in TI DSPLink code) - * T1_TOP: Timer 1, top : */ -#define TID_CLOCKEVENT T0_BOT -#define TID_CLOCKSOURCE T0_TOP + +enum { + TID_CLOCKEVENT, + TID_CLOCKSOURCE, +}; /* Timer register offsets */ -#define PID12 0x0 -#define TIM12 0x10 -#define TIM34 0x14 -#define PRD12 0x18 -#define PRD34 0x1c -#define TCR 0x20 -#define TGCR 0x24 -#define WDTCR 0x28 +#define PID12 0x0 +#define TIM12 0x10 +#define TIM34 0x14 +#define PRD12 0x18 +#define PRD34 0x1c +#define TCR 0x20 +#define TGCR 0x24 +#define WDTCR 0x28 + +/* Offsets of the 8 compare registers */ +#define CMP12_0 0x60 +#define CMP12_1 0x64 +#define CMP12_2 0x68 +#define CMP12_3 0x6c +#define CMP12_4 0x70 +#define CMP12_5 0x74 +#define CMP12_6 0x78 +#define CMP12_7 0x7c /* Timer register bitfields */ #define TCR_ENAMODE_DISABLE 0x0 @@ -105,6 +95,7 @@ struct timer_s { unsigned int id; unsigned long period; unsigned long opts; + unsigned long flags; void __iomem *base; unsigned long tim_off; unsigned long prd_off; @@ -114,30 +105,58 @@ struct timer_s { static struct timer_s timers[]; /* values for 'opts' field of struct timer_s */ -#define TIMER_OPTS_DISABLED 0x00 -#define TIMER_OPTS_ONESHOT 0x01 -#define TIMER_OPTS_PERIODIC 0x02 +#define TIMER_OPTS_DISABLED 0x01 +#define TIMER_OPTS_ONESHOT 0x02 +#define TIMER_OPTS_PERIODIC 0x04 +#define TIMER_OPTS_STATE_MASK 0x07 + +#define TIMER_OPTS_USE_COMPARE 0x80000000 +#define USING_COMPARE(t) ((t)->opts & TIMER_OPTS_USE_COMPARE) + +static char *id_to_name[] = { + [T0_BOT] = "timer0_0", + [T0_TOP] = "timer0_1", + [T1_BOT] = "timer1_0", + [T1_TOP] = "timer1_1", +}; static int timer32_config(struct timer_s *t) { - u32 tcr = __raw_readl(t->base + TCR); + u32 tcr; + struct davinci_soc_info *soc_info = &davinci_soc_info; - /* disable timer */ - tcr &= ~(TCR_ENAMODE_MASK << t->enamode_shift); - __raw_writel(tcr, t->base + TCR); + if (USING_COMPARE(t)) { + struct davinci_timer_instance *dtip = + soc_info->timer_info->timers; + int event_timer = ID_TO_TIMER(timers[TID_CLOCKEVENT].id); - /* reset counter to zero, set new period */ - __raw_writel(0, t->base + t->tim_off); - __raw_writel(t->period, t->base + t->prd_off); + /* + * Next interrupt should be the current time reg value plus + * the new period (using 32-bit unsigned addition/wrapping + * to 0 on overflow). This assumes that the clocksource + * is setup to count to 2^32-1 before wrapping around to 0. + */ + __raw_writel(__raw_readl(t->base + t->tim_off) + t->period, + t->base + dtip[event_timer].cmp_off); + } else { + tcr = __raw_readl(t->base + TCR); - /* Set enable mode */ - if (t->opts & TIMER_OPTS_ONESHOT) { - tcr |= TCR_ENAMODE_ONESHOT << t->enamode_shift; - } else if (t->opts & TIMER_OPTS_PERIODIC) { - tcr |= TCR_ENAMODE_PERIODIC << t->enamode_shift; + /* disable timer */ + tcr &= ~(TCR_ENAMODE_MASK << t->enamode_shift); + __raw_writel(tcr, t->base + TCR); + + /* reset counter to zero, set new period */ + __raw_writel(0, t->base + t->tim_off); + __raw_writel(t->period, t->base + t->prd_off); + + /* Set enable mode */ + if (t->opts & TIMER_OPTS_ONESHOT) + tcr |= TCR_ENAMODE_ONESHOT << t->enamode_shift; + else if (t->opts & TIMER_OPTS_PERIODIC) + tcr |= TCR_ENAMODE_PERIODIC << t->enamode_shift; + + __raw_writel(tcr, t->base + TCR); } - - __raw_writel(tcr, t->base + TCR); return 0; } @@ -182,13 +201,14 @@ static struct timer_s timers[] = { static void __init timer_init(void) { - u32 phys_bases[] = {DAVINCI_TIMER0_BASE, DAVINCI_TIMER1_BASE}; + struct davinci_soc_info *soc_info = &davinci_soc_info; + struct davinci_timer_instance *dtip = soc_info->timer_info->timers; int i; /* Global init of each 64-bit timer as a whole */ for(i=0; i<2; i++) { u32 tgcr; - void __iomem *base = IO_ADDRESS(phys_bases[i]); + void __iomem *base = dtip[i].base; /* Disabled, Internal clock source */ __raw_writel(0, base + TCR); @@ -214,33 +234,33 @@ static void __init timer_init(void) /* Init of each timer as a 32-bit timer */ for (i=0; i< ARRAY_SIZE(timers); i++) { struct timer_s *t = &timers[i]; - u32 phys_base; + int timer = ID_TO_TIMER(t->id); + u32 irq; - if (t->name) { - t->id = i; - phys_base = (IS_TIMER1(t->id) ? - DAVINCI_TIMER1_BASE : DAVINCI_TIMER0_BASE); - t->base = IO_ADDRESS(phys_base); + t->base = dtip[timer].base; - if (IS_TIMER_BOT(t->id)) { - t->enamode_shift = 6; - t->tim_off = TIM12; - t->prd_off = PRD12; - } else { - t->enamode_shift = 22; - t->tim_off = TIM34; - t->prd_off = PRD34; - } - - /* Register interrupt */ - t->irqaction.name = t->name; - t->irqaction.dev_id = (void *)t; - if (t->irqaction.handler != NULL) { - setup_irq(timer_irqs[t->id], &t->irqaction); - } - - timer32_config(&timers[i]); + if (IS_TIMER_BOT(t->id)) { + t->enamode_shift = 6; + t->tim_off = TIM12; + t->prd_off = PRD12; + irq = dtip[timer].bottom_irq; + } else { + t->enamode_shift = 22; + t->tim_off = TIM34; + t->prd_off = PRD34; + irq = dtip[timer].top_irq; } + + /* Register interrupt */ + t->irqaction.name = t->name; + t->irqaction.dev_id = (void *)t; + + if (t->irqaction.handler != NULL) { + irq = USING_COMPARE(t) ? dtip[i].cmp_irq : irq; + setup_irq(irq, &t->irqaction); + } + + timer32_config(&timers[i]); } } @@ -255,7 +275,6 @@ static cycle_t read_cycles(struct clocksource *cs) } static struct clocksource clocksource_davinci = { - .name = "timer0_1", .rating = 300, .read = read_cycles, .mask = CLOCKSOURCE_MASK(32), @@ -284,15 +303,18 @@ static void davinci_set_mode(enum clock_event_mode mode, switch (mode) { case CLOCK_EVT_MODE_PERIODIC: t->period = davinci_clock_tick_rate / (HZ); - t->opts = TIMER_OPTS_PERIODIC; + t->opts &= ~TIMER_OPTS_STATE_MASK; + t->opts |= TIMER_OPTS_PERIODIC; timer32_config(t); break; case CLOCK_EVT_MODE_ONESHOT: - t->opts = TIMER_OPTS_ONESHOT; + t->opts &= ~TIMER_OPTS_STATE_MASK; + t->opts |= TIMER_OPTS_ONESHOT; break; case CLOCK_EVT_MODE_UNUSED: case CLOCK_EVT_MODE_SHUTDOWN: - t->opts = TIMER_OPTS_DISABLED; + t->opts &= ~TIMER_OPTS_STATE_MASK; + t->opts |= TIMER_OPTS_DISABLED; break; case CLOCK_EVT_MODE_RESUME: break; @@ -300,7 +322,6 @@ static void davinci_set_mode(enum clock_event_mode mode, } static struct clock_event_device clockevent_davinci = { - .name = "timer0_0", .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, .shift = 32, .set_next_event = davinci_set_next_event, @@ -311,10 +332,42 @@ static struct clock_event_device clockevent_davinci = { static void __init davinci_timer_init(void) { struct clk *timer_clk; - + struct davinci_soc_info *soc_info = &davinci_soc_info; + unsigned int clockevent_id; + unsigned int clocksource_id; static char err[] __initdata = KERN_ERR "%s: can't register clocksource!\n"; + clockevent_id = soc_info->timer_info->clockevent_id; + clocksource_id = soc_info->timer_info->clocksource_id; + + timers[TID_CLOCKEVENT].id = clockevent_id; + timers[TID_CLOCKSOURCE].id = clocksource_id; + + /* + * If using same timer for both clock events & clocksource, + * a compare register must be used to generate an event interrupt. + * This is equivalent to a oneshot timer only (not periodic). + */ + if (clockevent_id == clocksource_id) { + struct davinci_timer_instance *dtip = + soc_info->timer_info->timers; + int event_timer = ID_TO_TIMER(clockevent_id); + + /* Only bottom timers can use compare regs */ + if (IS_TIMER_TOP(clockevent_id)) + pr_warning("davinci_timer_init: Invalid use" + " of system timers. Results unpredictable.\n"); + else if ((dtip[event_timer].cmp_off == 0) + || (dtip[event_timer].cmp_irq == 0)) + pr_warning("davinci_timer_init: Invalid timer instance" + " setup. Results unpredictable.\n"); + else { + timers[TID_CLOCKEVENT].opts |= TIMER_OPTS_USE_COMPARE; + clockevent_davinci.features = CLOCK_EVT_FEAT_ONESHOT; + } + } + /* init timer hw */ timer_init(); @@ -325,6 +378,7 @@ static void __init davinci_timer_init(void) davinci_clock_tick_rate = clk_get_rate(timer_clk); /* setup clocksource */ + clocksource_davinci.name = id_to_name[clocksource_id]; clocksource_davinci.mult = clocksource_khz2mult(davinci_clock_tick_rate/1000, clocksource_davinci.shift); @@ -332,12 +386,12 @@ static void __init davinci_timer_init(void) printk(err, clocksource_davinci.name); /* setup clockevent */ + clockevent_davinci.name = id_to_name[timers[TID_CLOCKEVENT].id]; clockevent_davinci.mult = div_sc(davinci_clock_tick_rate, NSEC_PER_SEC, clockevent_davinci.shift); clockevent_davinci.max_delta_ns = clockevent_delta2ns(0xfffffffe, &clockevent_davinci); - clockevent_davinci.min_delta_ns = - clockevent_delta2ns(1, &clockevent_davinci); + clockevent_davinci.min_delta_ns = 50000; /* 50 usec */ clockevent_davinci.cpumask = cpumask_of(0); clockevents_register_device(&clockevent_davinci); @@ -349,15 +403,14 @@ struct sys_timer davinci_timer = { /* reset board using watchdog timer */ -void davinci_watchdog_reset(void) { +void davinci_watchdog_reset(void) +{ u32 tgcr, wdtcr; - void __iomem *base = IO_ADDRESS(DAVINCI_WDOG_BASE); - struct device dev; + struct davinci_soc_info *soc_info = &davinci_soc_info; + void __iomem *base = soc_info->wdt_base; struct clk *wd_clk; - char *name = "watchdog"; - dev_set_name(&dev, name); - wd_clk = clk_get(&dev, NULL); + wd_clk = clk_get(&davinci_wdt_device.dev, NULL); if (WARN_ON(IS_ERR(wd_clk))) return; clk_enable(wd_clk); diff --git a/arch/arm/mach-ep93xx/Kconfig b/arch/arm/mach-ep93xx/Kconfig index 56bddcef6905..d7291c682a64 100644 --- a/arch/arm/mach-ep93xx/Kconfig +++ b/arch/arm/mach-ep93xx/Kconfig @@ -9,87 +9,135 @@ config CRUNCH comment "EP93xx Platforms" +choice + prompt "EP93xx first SDRAM bank selection" + default EP93XX_SDCE3_SYNC_PHYS_OFFSET + +config EP93XX_SDCE3_SYNC_PHYS_OFFSET + bool "0x00000000 - SDCE3/SyncBoot" + help + Select this option if you want support for EP93xx boards with the + first SDRAM bank at 0x00000000 + +config EP93XX_SDCE0_PHYS_OFFSET + bool "0xc0000000 - SDCEO" + help + Select this option if you want support for EP93xx boards with the + first SDRAM bank at 0xc0000000 + +endchoice + config MACH_ADSSPHERE bool "Support ADS Sphere" + depends on EP93XX_SDCE3_SYNC_PHYS_OFFSET help Say 'Y' here if you want your kernel to support the ADS Sphere board. +config MACH_EDB93XX + bool + +config MACH_EDB9301 + bool "Support Cirrus Logic EDB9301" + depends on EP93XX_SDCE3_SYNC_PHYS_OFFSET + select MACH_EDB93XX + help + Say 'Y' here if you want your kernel to support the Cirrus + Logic EDB9301 Evaluation Board. + config MACH_EDB9302 bool "Support Cirrus Logic EDB9302" + depends on EP93XX_SDCE3_SYNC_PHYS_OFFSET + select MACH_EDB93XX help Say 'Y' here if you want your kernel to support the Cirrus Logic EDB9302 Evaluation Board. config MACH_EDB9302A bool "Support Cirrus Logic EDB9302A" + depends on EP93XX_SDCE0_PHYS_OFFSET + select MACH_EDB93XX help Say 'Y' here if you want your kernel to support the Cirrus Logic EDB9302A Evaluation Board. config MACH_EDB9307 bool "Support Cirrus Logic EDB9307" + depends on EP93XX_SDCE3_SYNC_PHYS_OFFSET + select MACH_EDB93XX help Say 'Y' here if you want your kernel to support the Cirrus Logic EDB9307 Evaluation Board. config MACH_EDB9307A bool "Support Cirrus Logic EDB9307A" + depends on EP93XX_SDCE0_PHYS_OFFSET + select MACH_EDB93XX help Say 'Y' here if you want your kernel to support the Cirrus Logic EDB9307A Evaluation Board. config MACH_EDB9312 bool "Support Cirrus Logic EDB9312" + depends on EP93XX_SDCE3_SYNC_PHYS_OFFSET + select MACH_EDB93XX help Say 'Y' here if you want your kernel to support the Cirrus Logic EDB9312 Evaluation Board. config MACH_EDB9315 bool "Support Cirrus Logic EDB9315" + depends on EP93XX_SDCE3_SYNC_PHYS_OFFSET + select MACH_EDB93XX help Say 'Y' here if you want your kernel to support the Cirrus Logic EDB9315 Evaluation Board. config MACH_EDB9315A bool "Support Cirrus Logic EDB9315A" + depends on EP93XX_SDCE0_PHYS_OFFSET + select MACH_EDB93XX help Say 'Y' here if you want your kernel to support the Cirrus Logic EDB9315A Evaluation Board. config MACH_GESBC9312 + depends on EP93XX_SDCE3_SYNC_PHYS_OFFSET bool "Support Glomation GESBC-9312-sx" help Say 'Y' here if you want your kernel to support the Glomation GESBC-9312-sx board. config MACH_MICRO9 - bool - default n + bool config MACH_MICRO9H - bool "Support Contec Hypercontrol Micro9-H" - select MACH_MICRO9 - help - Say 'Y' here if you want your kernel to support the - Contec Hypercontrol Micro9-H board. + bool "Support Contec Hypercontrol Micro9-H" + depends on EP93XX_SDCE3_SYNC_PHYS_OFFSET + select MACH_MICRO9 + help + Say 'Y' here if you want your kernel to support the + Contec Hypercontrol Micro9-H board. config MACH_MICRO9M - bool "Support Contec Hypercontrol Micro9-M" - select MACH_MICRO9 - help - Say 'Y' here if you want your kernel to support the - Contec Hypercontrol Micro9-M board. + bool "Support Contec Hypercontrol Micro9-M" + depends on EP93XX_SDCE3_SYNC_PHYS_OFFSET + select MACH_MICRO9 + help + Say 'Y' here if you want your kernel to support the + Contec Hypercontrol Micro9-M board. config MACH_MICRO9L - bool "Support Contec Hypercontrol Micro9-L" - select MACH_MICRO9 - help - Say 'Y' here if you want your kernel to support the - Contec Hypercontrol Micro9-L board. + bool "Support Contec Hypercontrol Micro9-L" + depends on EP93XX_SDCE3_SYNC_PHYS_OFFSET + select MACH_MICRO9 + help + Say 'Y' here if you want your kernel to support the + Contec Hypercontrol Micro9-L board. config MACH_TS72XX bool "Support Technologic Systems TS-72xx SBC" + depends on EP93XX_SDCE3_SYNC_PHYS_OFFSET help Say 'Y' here if you want your kernel to support the Technologic Systems TS-72xx board. diff --git a/arch/arm/mach-ep93xx/Makefile b/arch/arm/mach-ep93xx/Makefile index 9522e205b73f..eae6199a9891 100644 --- a/arch/arm/mach-ep93xx/Makefile +++ b/arch/arm/mach-ep93xx/Makefile @@ -7,13 +7,7 @@ obj-n := obj- := obj-$(CONFIG_MACH_ADSSPHERE) += adssphere.o -obj-$(CONFIG_MACH_EDB9302) += edb9302.o -obj-$(CONFIG_MACH_EDB9302A) += edb9302a.o -obj-$(CONFIG_MACH_EDB9307) += edb9307.o -obj-$(CONFIG_MACH_EDB9307A) += edb9307a.o -obj-$(CONFIG_MACH_EDB9312) += edb9312.o -obj-$(CONFIG_MACH_EDB9315) += edb9315.o -obj-$(CONFIG_MACH_EDB9315A) += edb9315a.o +obj-$(CONFIG_MACH_EDB93XX) += edb93xx.o obj-$(CONFIG_MACH_GESBC9312) += gesbc9312.o obj-$(CONFIG_MACH_MICRO9) += micro9.o obj-$(CONFIG_MACH_TS72XX) += ts72xx.o diff --git a/arch/arm/mach-ep93xx/Makefile.boot b/arch/arm/mach-ep93xx/Makefile.boot index d5561ad15bad..27a085a8f12a 100644 --- a/arch/arm/mach-ep93xx/Makefile.boot +++ b/arch/arm/mach-ep93xx/Makefile.boot @@ -1,2 +1,5 @@ - zreladdr-y := 0x00008000 -params_phys-y := 0x00000100 + zreladdr-$(CONFIG_EP93XX_SDCE3_SYNC_PHYS_OFFSET) := 0x00008000 +params_phys-$(CONFIG_EP93XX_SDCE3_SYNC_PHYS_OFFSET) := 0x00000100 + + zreladdr-$(CONFIG_EP93XX_SDCE0_PHYS_OFFSET) := 0xc0008000 +params_phys-$(CONFIG_EP93XX_SDCE0_PHYS_OFFSET) := 0xc0000100 diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c index b2eede5531c8..6c4c1633ed12 100644 --- a/arch/arm/mach-ep93xx/clock.c +++ b/arch/arm/mach-ep93xx/clock.c @@ -72,58 +72,58 @@ static struct clk clk_h; static struct clk clk_p; static struct clk clk_pll2; static struct clk clk_usb_host = { - .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, - .enable_mask = EP93XX_SYSCON_CLOCK_USH_EN, + .enable_reg = EP93XX_SYSCON_PWRCNT, + .enable_mask = EP93XX_SYSCON_PWRCNT_USH_EN, }; /* DMA Clocks */ static struct clk clk_m2p0 = { - .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, - .enable_mask = 0x00020000, + .enable_reg = EP93XX_SYSCON_PWRCNT, + .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P0, }; static struct clk clk_m2p1 = { - .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, - .enable_mask = 0x00010000, + .enable_reg = EP93XX_SYSCON_PWRCNT, + .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P1, }; static struct clk clk_m2p2 = { - .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, - .enable_mask = 0x00080000, + .enable_reg = EP93XX_SYSCON_PWRCNT, + .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P2, }; static struct clk clk_m2p3 = { - .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, - .enable_mask = 0x00040000, + .enable_reg = EP93XX_SYSCON_PWRCNT, + .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P3, }; static struct clk clk_m2p4 = { - .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, - .enable_mask = 0x00200000, + .enable_reg = EP93XX_SYSCON_PWRCNT, + .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P4, }; static struct clk clk_m2p5 = { - .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, - .enable_mask = 0x00100000, + .enable_reg = EP93XX_SYSCON_PWRCNT, + .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P5, }; static struct clk clk_m2p6 = { - .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, - .enable_mask = 0x00800000, + .enable_reg = EP93XX_SYSCON_PWRCNT, + .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P6, }; static struct clk clk_m2p7 = { - .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, - .enable_mask = 0x00400000, + .enable_reg = EP93XX_SYSCON_PWRCNT, + .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P7, }; static struct clk clk_m2p8 = { - .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, - .enable_mask = 0x02000000, + .enable_reg = EP93XX_SYSCON_PWRCNT, + .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P8, }; static struct clk clk_m2p9 = { - .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, - .enable_mask = 0x01000000, + .enable_reg = EP93XX_SYSCON_PWRCNT, + .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P9, }; static struct clk clk_m2m0 = { - .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, - .enable_mask = 0x04000000, + .enable_reg = EP93XX_SYSCON_PWRCNT, + .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2M0, }; static struct clk clk_m2m1 = { - .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, - .enable_mask = 0x08000000, + .enable_reg = EP93XX_SYSCON_PWRCNT, + .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2M1, }; #define INIT_CK(dev,con,ck) \ @@ -138,7 +138,7 @@ static struct clk_lookup clocks[] = { INIT_CK(NULL, "hclk", &clk_h), INIT_CK(NULL, "pclk", &clk_p), INIT_CK(NULL, "pll2", &clk_pll2), - INIT_CK(NULL, "usb_host", &clk_usb_host), + INIT_CK("ep93xx-ohci", NULL, &clk_usb_host), INIT_CK(NULL, "m2p0", &clk_m2p0), INIT_CK(NULL, "m2p1", &clk_m2p1), INIT_CK(NULL, "m2p2", &clk_m2p2), @@ -186,8 +186,8 @@ static unsigned long get_uart_rate(struct clk *clk) { u32 value; - value = __raw_readl(EP93XX_SYSCON_CLOCK_CONTROL); - if (value & EP93XX_SYSCON_CLOCK_UARTBAUD) + value = __raw_readl(EP93XX_SYSCON_PWRCNT); + if (value & EP93XX_SYSCON_PWRCNT_UARTBAUD) return EP93XX_EXT_CLK_RATE; else return EP93XX_EXT_CLK_RATE / 2; diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c index ae24486f858a..204dc5cbd0b8 100644 --- a/arch/arm/mach-ep93xx/core.c +++ b/arch/arm/mach-ep93xx/core.c @@ -155,7 +155,7 @@ static unsigned char gpio_int_unmasked[3]; static unsigned char gpio_int_enabled[3]; static unsigned char gpio_int_type1[3]; static unsigned char gpio_int_type2[3]; -static unsigned char gpio_int_debouce[3]; +static unsigned char gpio_int_debounce[3]; /* Port ordering is: A B F */ static const u8 int_type1_register_offset[3] = { 0x90, 0xac, 0x4c }; @@ -192,11 +192,11 @@ void ep93xx_gpio_int_debounce(unsigned int irq, int enable) int port_mask = 1 << (line & 7); if (enable) - gpio_int_debouce[port] |= port_mask; + gpio_int_debounce[port] |= port_mask; else - gpio_int_debouce[port] &= ~port_mask; + gpio_int_debounce[port] &= ~port_mask; - __raw_writeb(gpio_int_debouce[port], + __raw_writeb(gpio_int_debounce[port], EP93XX_GPIO_REG(int_debounce_register_offset[port])); } EXPORT_SYMBOL(ep93xx_gpio_int_debounce); @@ -362,8 +362,8 @@ void __init ep93xx_init_irq(void) { int gpio_irq; - vic_init((void *)EP93XX_VIC1_BASE, 0, EP93XX_VIC1_VALID_IRQ_MASK); - vic_init((void *)EP93XX_VIC2_BASE, 32, EP93XX_VIC2_VALID_IRQ_MASK); + vic_init((void *)EP93XX_VIC1_BASE, 0, EP93XX_VIC1_VALID_IRQ_MASK, 0); + vic_init((void *)EP93XX_VIC2_BASE, 32, EP93XX_VIC2_VALID_IRQ_MASK, 0); for (gpio_irq = gpio_to_irq(0); gpio_irq <= gpio_to_irq(EP93XX_GPIO_LINE_MAX_IRQ); ++gpio_irq) { @@ -450,10 +450,19 @@ static struct amba_device uart3_device = { }; +static struct resource ep93xx_rtc_resource[] = { + { + .start = EP93XX_RTC_PHYS_BASE, + .end = EP93XX_RTC_PHYS_BASE + 0x10c - 1, + .flags = IORESOURCE_MEM, + }, +}; + static struct platform_device ep93xx_rtc_device = { - .name = "ep93xx-rtc", - .id = -1, - .num_resources = 0, + .name = "ep93xx-rtc", + .id = -1, + .num_resources = ARRAY_SIZE(ep93xx_rtc_resource), + .resource = ep93xx_rtc_resource, }; diff --git a/arch/arm/mach-ep93xx/edb9302.c b/arch/arm/mach-ep93xx/edb9302.c deleted file mode 100644 index 8bf8d7c78f1a..000000000000 --- a/arch/arm/mach-ep93xx/edb9302.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * arch/arm/mach-ep93xx/edb9302.c - * Cirrus Logic EDB9302 support. - * - * Copyright (C) 2006 George Kashperko - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static struct physmap_flash_data edb9302_flash_data = { - .width = 2, -}; - -static struct resource edb9302_flash_resource = { - .start = EP93XX_CS6_PHYS_BASE, - .end = EP93XX_CS6_PHYS_BASE + SZ_16M - 1, - .flags = IORESOURCE_MEM, -}; - -static struct platform_device edb9302_flash = { - .name = "physmap-flash", - .id = 0, - .dev = { - .platform_data = &edb9302_flash_data, - }, - .num_resources = 1, - .resource = &edb9302_flash_resource, -}; - -static struct ep93xx_eth_data edb9302_eth_data = { - .phy_id = 1, -}; - -static void __init edb9302_init_machine(void) -{ - ep93xx_init_devices(); - platform_device_register(&edb9302_flash); - - ep93xx_register_eth(&edb9302_eth_data, 1); -} - -MACHINE_START(EDB9302, "Cirrus Logic EDB9302 Evaluation Board") - /* Maintainer: George Kashperko */ - .phys_io = EP93XX_APB_PHYS_BASE, - .io_pg_offst = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc, - .boot_params = EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100, - .map_io = ep93xx_map_io, - .init_irq = ep93xx_init_irq, - .timer = &ep93xx_timer, - .init_machine = edb9302_init_machine, -MACHINE_END diff --git a/arch/arm/mach-ep93xx/edb9302a.c b/arch/arm/mach-ep93xx/edb9302a.c deleted file mode 100644 index a352c57c7b46..000000000000 --- a/arch/arm/mach-ep93xx/edb9302a.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * arch/arm/mach-ep93xx/edb9302a.c - * Cirrus Logic EDB9302A support. - * - * Copyright (C) 2006 Lennert Buytenhek - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static struct physmap_flash_data edb9302a_flash_data = { - .width = 2, -}; - -static struct resource edb9302a_flash_resource = { - .start = EP93XX_CS6_PHYS_BASE, - .end = EP93XX_CS6_PHYS_BASE + SZ_16M - 1, - .flags = IORESOURCE_MEM, -}; - -static struct platform_device edb9302a_flash = { - .name = "physmap-flash", - .id = 0, - .dev = { - .platform_data = &edb9302a_flash_data, - }, - .num_resources = 1, - .resource = &edb9302a_flash_resource, -}; - -static struct ep93xx_eth_data edb9302a_eth_data = { - .phy_id = 1, -}; - -static void __init edb9302a_init_machine(void) -{ - ep93xx_init_devices(); - platform_device_register(&edb9302a_flash); - - ep93xx_register_eth(&edb9302a_eth_data, 1); -} - -MACHINE_START(EDB9302A, "Cirrus Logic EDB9302A Evaluation Board") - /* Maintainer: Lennert Buytenhek */ - .phys_io = EP93XX_APB_PHYS_BASE, - .io_pg_offst = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc, - .boot_params = EP93XX_SDCE0_PHYS_BASE + 0x100, - .map_io = ep93xx_map_io, - .init_irq = ep93xx_init_irq, - .timer = &ep93xx_timer, - .init_machine = edb9302a_init_machine, -MACHINE_END diff --git a/arch/arm/mach-ep93xx/edb9307.c b/arch/arm/mach-ep93xx/edb9307.c deleted file mode 100644 index 5ab22f63a4eb..000000000000 --- a/arch/arm/mach-ep93xx/edb9307.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * arch/arm/mach-ep93xx/edb9307.c - * Cirrus Logic EDB9307 support. - * - * Copyright (C) 2007 Herbert Valerio Riedel - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static struct physmap_flash_data edb9307_flash_data = { - .width = 4, -}; - -static struct resource edb9307_flash_resource = { - .start = EP93XX_CS6_PHYS_BASE, - .end = EP93XX_CS6_PHYS_BASE + SZ_32M - 1, - .flags = IORESOURCE_MEM, -}; - -static struct platform_device edb9307_flash = { - .name = "physmap-flash", - .id = 0, - .dev = { - .platform_data = &edb9307_flash_data, - }, - .num_resources = 1, - .resource = &edb9307_flash_resource, -}; - -static struct ep93xx_eth_data edb9307_eth_data = { - .phy_id = 1, -}; - -static void __init edb9307_init_machine(void) -{ - ep93xx_init_devices(); - platform_device_register(&edb9307_flash); - - ep93xx_register_eth(&edb9307_eth_data, 1); -} - -MACHINE_START(EDB9307, "Cirrus Logic EDB9307 Evaluation Board") - /* Maintainer: Herbert Valerio Riedel */ - .phys_io = EP93XX_APB_PHYS_BASE, - .io_pg_offst = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc, - .boot_params = EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100, - .map_io = ep93xx_map_io, - .init_irq = ep93xx_init_irq, - .timer = &ep93xx_timer, - .init_machine = edb9307_init_machine, -MACHINE_END diff --git a/arch/arm/mach-ep93xx/edb9307a.c b/arch/arm/mach-ep93xx/edb9307a.c deleted file mode 100644 index 6171167d3315..000000000000 --- a/arch/arm/mach-ep93xx/edb9307a.c +++ /dev/null @@ -1,80 +0,0 @@ -/* - * arch/arm/mach-ep93xx/edb9307a.c - * Cirrus Logic EDB9307A support. - * - * Copyright (C) 2008 H Hartley Sweeten - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static struct physmap_flash_data edb9307a_flash_data = { - .width = 2, -}; - -static struct resource edb9307a_flash_resource = { - .start = EP93XX_CS6_PHYS_BASE, - .end = EP93XX_CS6_PHYS_BASE + SZ_16M - 1, - .flags = IORESOURCE_MEM, -}; - -static struct platform_device edb9307a_flash = { - .name = "physmap-flash", - .id = 0, - .dev = { - .platform_data = &edb9307a_flash_data, - }, - .num_resources = 1, - .resource = &edb9307a_flash_resource, -}; - -static struct ep93xx_eth_data edb9307a_eth_data = { - .phy_id = 1, -}; - -static struct i2c_board_info __initdata edb9307a_i2c_data[] = { - { - /* On-board battery backed RTC */ - I2C_BOARD_INFO("isl1208", 0x6f), - }, - /* - * The I2C signals are also routed to the Expansion Connector (J4) - */ -}; - -static void __init edb9307a_init_machine(void) -{ - ep93xx_init_devices(); - platform_device_register(&edb9307a_flash); - - ep93xx_register_eth(&edb9307a_eth_data, 1); - - ep93xx_init_i2c(edb9307a_i2c_data, ARRAY_SIZE(edb9307a_i2c_data)); -} - -MACHINE_START(EDB9307A, "Cirrus Logic EDB9307A Evaluation Board") - /* Maintainer: H Hartley Sweeten */ - .phys_io = EP93XX_APB_PHYS_BASE, - .io_pg_offst = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc, - .boot_params = EP93XX_SDCE0_PHYS_BASE + 0x100, - .map_io = ep93xx_map_io, - .init_irq = ep93xx_init_irq, - .timer = &ep93xx_timer, - .init_machine = edb9307a_init_machine, -MACHINE_END diff --git a/arch/arm/mach-ep93xx/edb9312.c b/arch/arm/mach-ep93xx/edb9312.c deleted file mode 100644 index d7179f66d804..000000000000 --- a/arch/arm/mach-ep93xx/edb9312.c +++ /dev/null @@ -1,69 +0,0 @@ -/* - * arch/arm/mach-ep93xx/edb9312.c - * Cirrus Logic EDB9312 support. - * - * Copyright (C) 2006 Infosys Technologies Limited - * Toufeeq Hussain - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static struct physmap_flash_data edb9312_flash_data = { - .width = 4, -}; - -static struct resource edb9312_flash_resource = { - .start = EP93XX_CS6_PHYS_BASE, - .end = EP93XX_CS6_PHYS_BASE + SZ_32M - 1, - .flags = IORESOURCE_MEM, -}; - -static struct platform_device edb9312_flash = { - .name = "physmap-flash", - .id = 0, - .dev = { - .platform_data = &edb9312_flash_data, - }, - .num_resources = 1, - .resource = &edb9312_flash_resource, -}; - -static struct ep93xx_eth_data edb9312_eth_data = { - .phy_id = 1, -}; - -static void __init edb9312_init_machine(void) -{ - ep93xx_init_devices(); - platform_device_register(&edb9312_flash); - - ep93xx_register_eth(&edb9312_eth_data, 1); -} - -MACHINE_START(EDB9312, "Cirrus Logic EDB9312 Evaluation Board") - /* Maintainer: Toufeeq Hussain */ - .phys_io = EP93XX_APB_PHYS_BASE, - .io_pg_offst = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc, - .boot_params = EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100, - .map_io = ep93xx_map_io, - .init_irq = ep93xx_init_irq, - .timer = &ep93xx_timer, - .init_machine = edb9312_init_machine, -MACHINE_END diff --git a/arch/arm/mach-ep93xx/edb9315.c b/arch/arm/mach-ep93xx/edb9315.c deleted file mode 100644 index 025af6eaca10..000000000000 --- a/arch/arm/mach-ep93xx/edb9315.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * arch/arm/mach-ep93xx/edb9315.c - * Cirrus Logic EDB9315 support. - * - * Copyright (C) 2006 Lennert Buytenhek - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static struct physmap_flash_data edb9315_flash_data = { - .width = 4, -}; - -static struct resource edb9315_flash_resource = { - .start = EP93XX_CS6_PHYS_BASE, - .end = EP93XX_CS6_PHYS_BASE + SZ_32M - 1, - .flags = IORESOURCE_MEM, -}; - -static struct platform_device edb9315_flash = { - .name = "physmap-flash", - .id = 0, - .dev = { - .platform_data = &edb9315_flash_data, - }, - .num_resources = 1, - .resource = &edb9315_flash_resource, -}; - -static struct ep93xx_eth_data edb9315_eth_data = { - .phy_id = 1, -}; - -static void __init edb9315_init_machine(void) -{ - ep93xx_init_devices(); - platform_device_register(&edb9315_flash); - - ep93xx_register_eth(&edb9315_eth_data, 1); -} - -MACHINE_START(EDB9315, "Cirrus Logic EDB9315 Evaluation Board") - /* Maintainer: Lennert Buytenhek */ - .phys_io = EP93XX_APB_PHYS_BASE, - .io_pg_offst = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc, - .boot_params = EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100, - .map_io = ep93xx_map_io, - .init_irq = ep93xx_init_irq, - .timer = &ep93xx_timer, - .init_machine = edb9315_init_machine, -MACHINE_END diff --git a/arch/arm/mach-ep93xx/edb9315a.c b/arch/arm/mach-ep93xx/edb9315a.c deleted file mode 100644 index 4c9cc8a39f5c..000000000000 --- a/arch/arm/mach-ep93xx/edb9315a.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * arch/arm/mach-ep93xx/edb9315a.c - * Cirrus Logic EDB9315A support. - * - * Copyright (C) 2006 Lennert Buytenhek - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static struct physmap_flash_data edb9315a_flash_data = { - .width = 2, -}; - -static struct resource edb9315a_flash_resource = { - .start = EP93XX_CS6_PHYS_BASE, - .end = EP93XX_CS6_PHYS_BASE + SZ_16M - 1, - .flags = IORESOURCE_MEM, -}; - -static struct platform_device edb9315a_flash = { - .name = "physmap-flash", - .id = 0, - .dev = { - .platform_data = &edb9315a_flash_data, - }, - .num_resources = 1, - .resource = &edb9315a_flash_resource, -}; - -static struct ep93xx_eth_data edb9315a_eth_data = { - .phy_id = 1, -}; - -static void __init edb9315a_init_machine(void) -{ - ep93xx_init_devices(); - platform_device_register(&edb9315a_flash); - - ep93xx_register_eth(&edb9315a_eth_data, 1); -} - -MACHINE_START(EDB9315A, "Cirrus Logic EDB9315A Evaluation Board") - /* Maintainer: Lennert Buytenhek */ - .phys_io = EP93XX_APB_PHYS_BASE, - .io_pg_offst = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc, - .boot_params = EP93XX_SDCE0_PHYS_BASE + 0x100, - .map_io = ep93xx_map_io, - .init_irq = ep93xx_init_irq, - .timer = &ep93xx_timer, - .init_machine = edb9315a_init_machine, -MACHINE_END diff --git a/arch/arm/mach-ep93xx/edb93xx.c b/arch/arm/mach-ep93xx/edb93xx.c new file mode 100644 index 000000000000..e9e45b92457e --- /dev/null +++ b/arch/arm/mach-ep93xx/edb93xx.c @@ -0,0 +1,217 @@ +/* + * arch/arm/mach-ep93xx/edb93xx.c + * Cirrus Logic EDB93xx Development Board support. + * + * EDB93XX, EDB9301, EDB9307A + * Copyright (C) 2008-2009 H Hartley Sweeten + * + * EDB9302 + * Copyright (C) 2006 George Kashperko + * + * EDB9302A, EDB9315, EDB9315A + * Copyright (C) 2006 Lennert Buytenhek + * + * EDB9307 + * Copyright (C) 2007 Herbert Valerio Riedel + * + * EDB9312 + * Copyright (C) 2006 Infosys Technologies Limited + * Toufeeq Hussain + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct physmap_flash_data edb93xx_flash_data; + +static struct resource edb93xx_flash_resource = { + .flags = IORESOURCE_MEM, +}; + +static struct platform_device edb93xx_flash = { + .name = "physmap-flash", + .id = 0, + .dev = { + .platform_data = &edb93xx_flash_data, + }, + .num_resources = 1, + .resource = &edb93xx_flash_resource, +}; + +static void __init __edb93xx_register_flash(unsigned int width, + resource_size_t start, resource_size_t size) +{ + edb93xx_flash_data.width = width; + edb93xx_flash_resource.start = start; + edb93xx_flash_resource.end = start + size - 1; + + platform_device_register(&edb93xx_flash); +} + +static void __init edb93xx_register_flash(void) +{ + if (machine_is_edb9307() || machine_is_edb9312() || + machine_is_edb9315()) { + __edb93xx_register_flash(4, EP93XX_CS6_PHYS_BASE, SZ_32M); + } else { + __edb93xx_register_flash(2, EP93XX_CS6_PHYS_BASE, SZ_16M); + } +} + +static struct ep93xx_eth_data edb93xx_eth_data = { + .phy_id = 1, +}; + +static struct i2c_board_info __initdata edb93xxa_i2c_data[] = { + { + I2C_BOARD_INFO("isl1208", 0x6f), + }, +}; + +static struct i2c_board_info __initdata edb93xx_i2c_data[] = { + { + I2C_BOARD_INFO("ds1337", 0x68), + }, +}; + +static void __init edb93xx_register_i2c(void) +{ + if (machine_is_edb9302a() || machine_is_edb9307a() || + machine_is_edb9315a()) { + ep93xx_register_i2c(edb93xxa_i2c_data, + ARRAY_SIZE(edb93xxa_i2c_data)); + } else if (machine_is_edb9307() || machine_is_edb9312() || + machine_is_edb9315()) { + ep93xx_register_i2c(edb93xx_i2c_data, + ARRAY_SIZE(edb93xx_i2c_data)); + } +} + +static void __init edb93xx_init_machine(void) +{ + ep93xx_init_devices(); + edb93xx_register_flash(); + ep93xx_register_eth(&edb93xx_eth_data, 1); + edb93xx_register_i2c(); +} + + +#ifdef CONFIG_MACH_EDB9301 +MACHINE_START(EDB9301, "Cirrus Logic EDB9301 Evaluation Board") + /* Maintainer: H Hartley Sweeten */ + .phys_io = EP93XX_APB_PHYS_BASE, + .io_pg_offst = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc, + .boot_params = EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100, + .map_io = ep93xx_map_io, + .init_irq = ep93xx_init_irq, + .timer = &ep93xx_timer, + .init_machine = edb93xx_init_machine, +MACHINE_END +#endif + +#ifdef CONFIG_MACH_EDB9302 +MACHINE_START(EDB9302, "Cirrus Logic EDB9302 Evaluation Board") + /* Maintainer: George Kashperko */ + .phys_io = EP93XX_APB_PHYS_BASE, + .io_pg_offst = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc, + .boot_params = EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100, + .map_io = ep93xx_map_io, + .init_irq = ep93xx_init_irq, + .timer = &ep93xx_timer, + .init_machine = edb93xx_init_machine, +MACHINE_END +#endif + +#ifdef CONFIG_MACH_EDB9302A +MACHINE_START(EDB9302A, "Cirrus Logic EDB9302A Evaluation Board") + /* Maintainer: Lennert Buytenhek */ + .phys_io = EP93XX_APB_PHYS_BASE, + .io_pg_offst = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc, + .boot_params = EP93XX_SDCE0_PHYS_BASE + 0x100, + .map_io = ep93xx_map_io, + .init_irq = ep93xx_init_irq, + .timer = &ep93xx_timer, + .init_machine = edb93xx_init_machine, +MACHINE_END +#endif + +#ifdef CONFIG_MACH_EDB9307 +MACHINE_START(EDB9307, "Cirrus Logic EDB9307 Evaluation Board") + /* Maintainer: Herbert Valerio Riedel */ + .phys_io = EP93XX_APB_PHYS_BASE, + .io_pg_offst = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc, + .boot_params = EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100, + .map_io = ep93xx_map_io, + .init_irq = ep93xx_init_irq, + .timer = &ep93xx_timer, + .init_machine = edb93xx_init_machine, +MACHINE_END +#endif + +#ifdef CONFIG_MACH_EDB9307A +MACHINE_START(EDB9307A, "Cirrus Logic EDB9307A Evaluation Board") + /* Maintainer: H Hartley Sweeten */ + .phys_io = EP93XX_APB_PHYS_BASE, + .io_pg_offst = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc, + .boot_params = EP93XX_SDCE0_PHYS_BASE + 0x100, + .map_io = ep93xx_map_io, + .init_irq = ep93xx_init_irq, + .timer = &ep93xx_timer, + .init_machine = edb93xx_init_machine, +MACHINE_END +#endif + +#ifdef CONFIG_MACH_EDB9312 +MACHINE_START(EDB9312, "Cirrus Logic EDB9312 Evaluation Board") + /* Maintainer: Toufeeq Hussain */ + .phys_io = EP93XX_APB_PHYS_BASE, + .io_pg_offst = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc, + .boot_params = EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100, + .map_io = ep93xx_map_io, + .init_irq = ep93xx_init_irq, + .timer = &ep93xx_timer, + .init_machine = edb93xx_init_machine, +MACHINE_END +#endif + +#ifdef CONFIG_MACH_EDB9315 +MACHINE_START(EDB9315, "Cirrus Logic EDB9315 Evaluation Board") + /* Maintainer: Lennert Buytenhek */ + .phys_io = EP93XX_APB_PHYS_BASE, + .io_pg_offst = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc, + .boot_params = EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100, + .map_io = ep93xx_map_io, + .init_irq = ep93xx_init_irq, + .timer = &ep93xx_timer, + .init_machine = edb93xx_init_machine, +MACHINE_END +#endif + +#ifdef CONFIG_MACH_EDB9315A +MACHINE_START(EDB9315A, "Cirrus Logic EDB9315A Evaluation Board") + /* Maintainer: Lennert Buytenhek */ + .phys_io = EP93XX_APB_PHYS_BASE, + .io_pg_offst = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc, + .boot_params = EP93XX_SDCE0_PHYS_BASE + 0x100, + .map_io = ep93xx_map_io, + .init_irq = ep93xx_init_irq, + .timer = &ep93xx_timer, + .init_machine = edb93xx_init_machine, +MACHINE_END +#endif diff --git a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h index 1732de7629a5..967c079180db 100644 --- a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h +++ b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h @@ -147,13 +147,27 @@ #define EP93XX_PWM_BASE (EP93XX_APB_VIRT_BASE + 0x00110000) #define EP93XX_RTC_BASE (EP93XX_APB_VIRT_BASE + 0x00120000) +#define EP93XX_RTC_PHYS_BASE (EP93XX_APB_PHYS_BASE + 0x00120000) #define EP93XX_SYSCON_BASE (EP93XX_APB_VIRT_BASE + 0x00130000) #define EP93XX_SYSCON_REG(x) (EP93XX_SYSCON_BASE + (x)) #define EP93XX_SYSCON_POWER_STATE EP93XX_SYSCON_REG(0x00) -#define EP93XX_SYSCON_CLOCK_CONTROL EP93XX_SYSCON_REG(0x04) -#define EP93XX_SYSCON_CLOCK_UARTBAUD 0x20000000 -#define EP93XX_SYSCON_CLOCK_USH_EN 0x10000000 +#define EP93XX_SYSCON_PWRCNT EP93XX_SYSCON_REG(0x04) +#define EP93XX_SYSCON_PWRCNT_FIR_EN (1<<31) +#define EP93XX_SYSCON_PWRCNT_UARTBAUD (1<<29) +#define EP93XX_SYSCON_PWRCNT_USH_EN (1<<28) +#define EP93XX_SYSCON_PWRCNT_DMA_M2M1 (1<<27) +#define EP93XX_SYSCON_PWRCNT_DMA_M2M0 (1<<26) +#define EP93XX_SYSCON_PWRCNT_DMA_M2P8 (1<<25) +#define EP93XX_SYSCON_PWRCNT_DMA_M2P9 (1<<24) +#define EP93XX_SYSCON_PWRCNT_DMA_M2P6 (1<<23) +#define EP93XX_SYSCON_PWRCNT_DMA_M2P7 (1<<22) +#define EP93XX_SYSCON_PWRCNT_DMA_M2P4 (1<<21) +#define EP93XX_SYSCON_PWRCNT_DMA_M2P5 (1<<20) +#define EP93XX_SYSCON_PWRCNT_DMA_M2P2 (1<<19) +#define EP93XX_SYSCON_PWRCNT_DMA_M2P3 (1<<18) +#define EP93XX_SYSCON_PWRCNT_DMA_M2P0 (1<<17) +#define EP93XX_SYSCON_PWRCNT_DMA_M2P1 (1<<16) #define EP93XX_SYSCON_HALT EP93XX_SYSCON_REG(0x08) #define EP93XX_SYSCON_STANDBY EP93XX_SYSCON_REG(0x0c) #define EP93XX_SYSCON_CLOCK_SET1 EP93XX_SYSCON_REG(0x20) diff --git a/arch/arm/mach-ep93xx/include/mach/ep93xx_keypad.h b/arch/arm/mach-ep93xx/include/mach/ep93xx_keypad.h new file mode 100644 index 000000000000..83f31cd0a274 --- /dev/null +++ b/arch/arm/mach-ep93xx/include/mach/ep93xx_keypad.h @@ -0,0 +1,42 @@ +/* + * arch/arm/mach-ep93xx/include/mach/ep93xx_keypad.h + */ + +#ifndef __ASM_ARCH_EP93XX_KEYPAD_H +#define __ASM_ARCH_EP93XX_KEYPAD_H + +#define MAX_MATRIX_KEY_ROWS (8) +#define MAX_MATRIX_KEY_COLS (8) + +/* flags for the ep93xx_keypad driver */ +#define EP93XX_KEYPAD_DISABLE_3_KEY (1<<0) /* disable 3-key reset */ +#define EP93XX_KEYPAD_DIAG_MODE (1<<1) /* diagnostic mode */ +#define EP93XX_KEYPAD_BACK_DRIVE (1<<2) /* back driving mode */ +#define EP93XX_KEYPAD_TEST_MODE (1<<3) /* scan only column 0 */ +#define EP93XX_KEYPAD_KDIV (1<<4) /* 1/4 clock or 1/16 clock */ +#define EP93XX_KEYPAD_AUTOREPEAT (1<<5) /* enable key autorepeat */ + +/** + * struct ep93xx_keypad_platform_data - platform specific device structure + * @matrix_key_rows: number of rows in the keypad matrix + * @matrix_key_cols: number of columns in the keypad matrix + * @matrix_key_map: array of keycodes defining the keypad matrix + * @matrix_key_map_size: ARRAY_SIZE(matrix_key_map) + * @debounce: debounce start count; terminal count is 0xff + * @prescale: row/column counter pre-scaler load value + * @flags: see above + */ +struct ep93xx_keypad_platform_data { + unsigned int matrix_key_rows; + unsigned int matrix_key_cols; + unsigned int *matrix_key_map; + int matrix_key_map_size; + unsigned int debounce; + unsigned int prescale; + unsigned int flags; +}; + +/* macro for creating the matrix_key_map table */ +#define KEY(row, col, val) (((row) << 28) | ((col) << 24) | (val)) + +#endif /* __ASM_ARCH_EP93XX_KEYPAD_H */ diff --git a/arch/arm/mach-ep93xx/include/mach/memory.h b/arch/arm/mach-ep93xx/include/mach/memory.h index 5c80c3c8158d..925b12ea0990 100644 --- a/arch/arm/mach-ep93xx/include/mach/memory.h +++ b/arch/arm/mach-ep93xx/include/mach/memory.h @@ -5,6 +5,12 @@ #ifndef __ASM_ARCH_MEMORY_H #define __ASM_ARCH_MEMORY_H +#if defined(CONFIG_EP93XX_SDCE3_SYNC_PHYS_OFFSET) #define PHYS_OFFSET UL(0x00000000) +#elif defined(CONFIG_EP93XX_SDCE0_PHYS_OFFSET) +#define PHYS_OFFSET UL(0xc0000000) +#else +#error "Kconfig bug: No EP93xx PHYS_OFFSET set" +#endif #endif diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig deleted file mode 100644 index cddd194ac6eb..000000000000 --- a/arch/arm/mach-imx/Kconfig +++ /dev/null @@ -1,11 +0,0 @@ -menu "IMX Implementations" - depends on ARCH_IMX - -config ARCH_MX1ADS - bool "mx1ads" - depends on ARCH_IMX - select ISA - help - Say Y here if you are using the Motorola MX1ADS board - -endmenu diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile deleted file mode 100644 index b047c7e795a9..000000000000 --- a/arch/arm/mach-imx/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -# -# Makefile for the linux kernel. -# - -# Object file lists. - -obj-y += irq.o time.o dma.o generic.o clock.o - -obj-$(CONFIG_CPU_FREQ_IMX) += cpufreq.o - -# Specific board support -obj-$(CONFIG_ARCH_MX1ADS) += mx1ads.o - -# Support for blinky lights -led-y := leds.o - -obj-$(CONFIG_LEDS) += $(led-y) -led-$(CONFIG_ARCH_MX1ADS) += leds-mx1ads.o diff --git a/arch/arm/mach-imx/Makefile.boot b/arch/arm/mach-imx/Makefile.boot deleted file mode 100644 index fd72ce5b8081..000000000000 --- a/arch/arm/mach-imx/Makefile.boot +++ /dev/null @@ -1,2 +0,0 @@ - zreladdr-$(CONFIG_ARCH_MX1ADS) := 0x08008000 - diff --git a/arch/arm/mach-imx/clock.c b/arch/arm/mach-imx/clock.c deleted file mode 100644 index cf332aeb942e..000000000000 --- a/arch/arm/mach-imx/clock.c +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright (C) 2008 Sascha Hauer , Pengutronix - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include - -#include - -/* - * Very simple approach: We can't disable clocks, so we do - * not need refcounting - */ - -struct clk { - struct list_head node; - const char *name; - unsigned long (*get_rate)(void); -}; - -/* - * get the system pll clock in Hz - * - * mfi + mfn / (mfd +1) - * f = 2 * f_ref * -------------------- - * pd + 1 - */ -static unsigned long imx_decode_pll(unsigned int pll, u32 f_ref) -{ - unsigned long long ll; - unsigned long quot; - - u32 mfi = (pll >> 10) & 0xf; - u32 mfn = pll & 0x3ff; - u32 mfd = (pll >> 16) & 0x3ff; - u32 pd = (pll >> 26) & 0xf; - - mfi = mfi <= 5 ? 5 : mfi; - - ll = 2 * (unsigned long long)f_ref * - ((mfi << 16) + (mfn << 16) / (mfd + 1)); - quot = (pd + 1) * (1 << 16); - ll += quot / 2; - do_div(ll, quot); - return (unsigned long)ll; -} - -static unsigned long imx_get_system_clk(void) -{ - u32 f_ref = (CSCR & CSCR_SYSTEM_SEL) ? 16000000 : (CLK32 * 512); - - return imx_decode_pll(SPCTL0, f_ref); -} - -static unsigned long imx_get_mcu_clk(void) -{ - return imx_decode_pll(MPCTL0, CLK32 * 512); -} - -/* - * get peripheral clock 1 ( UART[12], Timer[12], PWM ) - */ -static unsigned long imx_get_perclk1(void) -{ - return imx_get_system_clk() / (((PCDR) & 0xf)+1); -} - -/* - * get peripheral clock 2 ( LCD, SD, SPI[12] ) - */ -static unsigned long imx_get_perclk2(void) -{ - return imx_get_system_clk() / (((PCDR>>4) & 0xf)+1); -} - -/* - * get peripheral clock 3 ( SSI ) - */ -static unsigned long imx_get_perclk3(void) -{ - return imx_get_system_clk() / (((PCDR>>16) & 0x7f)+1); -} - -/* - * get hclk ( SDRAM, CSI, Memory Stick, I2C, DMA ) - */ -static unsigned long imx_get_hclk(void) -{ - return imx_get_system_clk() / (((CSCR>>10) & 0xf)+1); -} - -static struct clk clk_system_clk = { - .name = "system_clk", - .get_rate = imx_get_system_clk, -}; - -static struct clk clk_hclk = { - .name = "hclk", - .get_rate = imx_get_hclk, -}; - -static struct clk clk_mcu_clk = { - .name = "mcu_clk", - .get_rate = imx_get_mcu_clk, -}; - -static struct clk clk_perclk1 = { - .name = "perclk1", - .get_rate = imx_get_perclk1, -}; - -static struct clk clk_uart_clk = { - .name = "uart_clk", - .get_rate = imx_get_perclk1, -}; - -static struct clk clk_perclk2 = { - .name = "perclk2", - .get_rate = imx_get_perclk2, -}; - -static struct clk clk_perclk3 = { - .name = "perclk3", - .get_rate = imx_get_perclk3, -}; - -static struct clk *clks[] = { - &clk_perclk1, - &clk_perclk2, - &clk_perclk3, - &clk_system_clk, - &clk_hclk, - &clk_mcu_clk, - &clk_uart_clk, -}; - -static LIST_HEAD(clocks); -static DEFINE_MUTEX(clocks_mutex); - -struct clk *clk_get(struct device *dev, const char *id) -{ - struct clk *p, *clk = ERR_PTR(-ENOENT); - - mutex_lock(&clocks_mutex); - list_for_each_entry(p, &clocks, node) { - if (!strcmp(p->name, id)) { - clk = p; - goto found; - } - } - -found: - mutex_unlock(&clocks_mutex); - - return clk; -} -EXPORT_SYMBOL(clk_get); - -void clk_put(struct clk *clk) -{ -} -EXPORT_SYMBOL(clk_put); - -int clk_enable(struct clk *clk) -{ - return 0; -} -EXPORT_SYMBOL(clk_enable); - -void clk_disable(struct clk *clk) -{ -} -EXPORT_SYMBOL(clk_disable); - -unsigned long clk_get_rate(struct clk *clk) -{ - return clk->get_rate(); -} -EXPORT_SYMBOL(clk_get_rate); - -int imx_clocks_init(void) -{ - int i; - - mutex_lock(&clocks_mutex); - for (i = 0; i < ARRAY_SIZE(clks); i++) - list_add(&clks[i]->node, &clocks); - mutex_unlock(&clocks_mutex); - - return 0; -} - diff --git a/arch/arm/mach-imx/cpufreq.c b/arch/arm/mach-imx/cpufreq.c deleted file mode 100644 index 434b4ca0af67..000000000000 --- a/arch/arm/mach-imx/cpufreq.c +++ /dev/null @@ -1,315 +0,0 @@ -/* - * cpu.c: clock scaling for the iMX - * - * Copyright (C) 2000 2001, The Delft University of Technology - * Copyright (c) 2004 Sascha Hauer - * Copyright (C) 2006 Inky Lung - * Copyright (C) 2006 Pavel Pisa, PiKRON - * - * Based on SA1100 version written by: - * - Johan Pouwelse (J.A.Pouwelse@its.tudelft.nl): initial version - * - Erik Mouw (J.A.K.Mouw@its.tudelft.nl): - * - * 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 DEBUG*/ - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "generic.h" - -#ifndef __val2mfld -#define __val2mfld(mask,val) (((mask)&~((mask)<<1))*(val)&(mask)) -#endif -#ifndef __mfld2val -#define __mfld2val(mask,val) (((val)&(mask))/((mask)&~((mask)<<1))) -#endif - -#define CR_920T_CLOCK_MODE 0xC0000000 -#define CR_920T_FASTBUS_MODE 0x00000000 -#define CR_920T_ASYNC_MODE 0xC0000000 - -static u32 mpctl0_at_boot; -static u32 bclk_div_at_boot; - -static struct clk *system_clk, *mcu_clk; - -static void imx_set_async_mode(void) -{ - adjust_cr(CR_920T_CLOCK_MODE, CR_920T_ASYNC_MODE); -} - -static void imx_set_fastbus_mode(void) -{ - adjust_cr(CR_920T_CLOCK_MODE, CR_920T_FASTBUS_MODE); -} - -static void imx_set_mpctl0(u32 mpctl0) -{ - unsigned long flags; - - if (mpctl0 == 0) { - local_irq_save(flags); - CSCR &= ~CSCR_MPEN; - local_irq_restore(flags); - return; - } - - local_irq_save(flags); - MPCTL0 = mpctl0; - CSCR |= CSCR_MPEN; - local_irq_restore(flags); -} - -/** - * imx_compute_mpctl - compute new PLL parameters - * @new_mpctl: pointer to location assigned by new PLL control register value - * @cur_mpctl: current PLL control register parameters - * @f_ref: reference source frequency Hz - * @freq: required frequency in Hz - * @relation: is one of %CPUFREQ_RELATION_L (supremum) - * and %CPUFREQ_RELATION_H (infimum) - */ -long imx_compute_mpctl(u32 *new_mpctl, u32 cur_mpctl, u32 f_ref, unsigned long freq, int relation) -{ - u32 mfi; - u32 mfn; - u32 mfd; - u32 pd; - unsigned long long ll; - long l; - long quot; - - /* Fdppl=2*Fref*(MFI+MFN/(MFD+1))/(PD+1) */ - /* PD=<0,15>, MFD=<1,1023>, MFI=<5,15> MFN=<0,1022> */ - - if (cur_mpctl) { - mfd = ((cur_mpctl >> 16) & 0x3ff) + 1; - pd = ((cur_mpctl >> 26) & 0xf) + 1; - } else { - pd=2; mfd=313; - } - - /* pd=2; mfd=313; mfi=8; mfn=183; */ - /* (MFI+MFN/(MFD)) = Fdppl / (2*Fref) * (PD); */ - - quot = (f_ref + (1 << 9)) >> 10; - l = (freq * pd + quot) / (2 * quot); - mfi = l >> 10; - mfn = ((l & ((1 << 10) - 1)) * mfd + (1 << 9)) >> 10; - - mfd -= 1; - pd -= 1; - - *new_mpctl = ((mfi & 0xf) << 10) | (mfn & 0x3ff) | ((mfd & 0x3ff) << 16) - | ((pd & 0xf) << 26); - - ll = 2 * (unsigned long long)f_ref * ( (mfi<<16) + (mfn<<16) / (mfd+1) ); - quot = (pd+1) * (1<<16); - ll += quot / 2; - do_div(ll, quot); - freq = ll; - - pr_debug(KERN_DEBUG "imx: new PLL parameters pd=%d mfd=%d mfi=%d mfn=%d, freq=%ld\n", - pd, mfd, mfi, mfn, freq); - - return freq; -} - - -static int imx_verify_speed(struct cpufreq_policy *policy) -{ - if (policy->cpu != 0) - return -EINVAL; - - cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, policy->cpuinfo.max_freq); - - return 0; -} - -static unsigned int imx_get_speed(unsigned int cpu) -{ - unsigned int freq; - unsigned int cr; - unsigned int cscr; - unsigned int bclk_div; - - if (cpu) - return 0; - - cscr = CSCR; - bclk_div = __mfld2val(CSCR_BCLK_DIV, cscr) + 1; - cr = get_cr(); - - if((cr & CR_920T_CLOCK_MODE) == CR_920T_FASTBUS_MODE) { - freq = clk_get_rate(system_clk); - freq = (freq + bclk_div/2) / bclk_div; - } else { - freq = clk_get_rate(mcu_clk); - if (cscr & CSCR_MPU_PRESC) - freq /= 2; - } - - freq = (freq + 500) / 1000; - - return freq; -} - -static int imx_set_target(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) -{ - struct cpufreq_freqs freqs; - u32 mpctl0 = 0; - u32 cscr; - unsigned long flags; - long freq; - long sysclk; - unsigned int bclk_div = bclk_div_at_boot; - - /* - * Some governors do not respects CPU and policy lower limits - * which leads to bad things (division by zero etc), ensure - * that such things do not happen. - */ - if(target_freq < policy->cpuinfo.min_freq) - target_freq = policy->cpuinfo.min_freq; - - if(target_freq < policy->min) - target_freq = policy->min; - - freq = target_freq * 1000; - - pr_debug(KERN_DEBUG "imx: requested frequency %ld Hz, mpctl0 at boot 0x%08x\n", - freq, mpctl0_at_boot); - - sysclk = clk_get_rate(system_clk); - - if (freq > sysclk / bclk_div_at_boot + 1000000) { - freq = imx_compute_mpctl(&mpctl0, mpctl0_at_boot, CLK32 * 512, freq, relation); - if (freq < 0) { - printk(KERN_WARNING "imx: target frequency %ld Hz cannot be set\n", freq); - return -EINVAL; - } - } else { - if(freq + 1000 < sysclk) { - if (relation == CPUFREQ_RELATION_L) - bclk_div = (sysclk - 1000) / freq; - else - bclk_div = (sysclk + freq + 1000) / freq; - - if(bclk_div > 16) - bclk_div = 16; - if(bclk_div < bclk_div_at_boot) - bclk_div = bclk_div_at_boot; - } - freq = (sysclk + bclk_div / 2) / bclk_div; - } - - freqs.old = imx_get_speed(0); - freqs.new = (freq + 500) / 1000; - freqs.cpu = 0; - freqs.flags = 0; - - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); - - local_irq_save(flags); - - imx_set_fastbus_mode(); - - imx_set_mpctl0(mpctl0); - - cscr = CSCR; - cscr &= ~CSCR_BCLK_DIV; - cscr |= __val2mfld(CSCR_BCLK_DIV, bclk_div - 1); - CSCR = cscr; - - if(mpctl0) { - CSCR |= CSCR_MPLL_RESTART; - - /* Wait until MPLL is stabilized */ - while( CSCR & CSCR_MPLL_RESTART ); - - imx_set_async_mode(); - } - - local_irq_restore(flags); - - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); - - pr_debug(KERN_INFO "imx: set frequency %ld Hz, running from %s\n", - freq, mpctl0? "MPLL": "SPLL"); - - return 0; -} - -static int __init imx_cpufreq_driver_init(struct cpufreq_policy *policy) -{ - printk(KERN_INFO "i.MX cpu freq change driver v1.0\n"); - - if (policy->cpu != 0) - return -EINVAL; - - policy->cur = policy->min = policy->max = imx_get_speed(0); - policy->cpuinfo.min_freq = 8000; - policy->cpuinfo.max_freq = 200000; - /* Manual states, that PLL stabilizes in two CLK32 periods */ - policy->cpuinfo.transition_latency = 4 * 1000000000LL / CLK32; - return 0; -} - -static struct cpufreq_driver imx_driver = { - .flags = CPUFREQ_STICKY, - .verify = imx_verify_speed, - .target = imx_set_target, - .get = imx_get_speed, - .init = imx_cpufreq_driver_init, - .name = "imx", -}; - -static int __init imx_cpufreq_init(void) -{ - bclk_div_at_boot = __mfld2val(CSCR_BCLK_DIV, CSCR) + 1; - mpctl0_at_boot = 0; - - system_clk = clk_get(NULL, "system_clk"); - if (IS_ERR(system_clk)) - return PTR_ERR(system_clk); - - mcu_clk = clk_get(NULL, "mcu_clk"); - if (IS_ERR(mcu_clk)) { - clk_put(system_clk); - return PTR_ERR(mcu_clk); - } - - if((CSCR & CSCR_MPEN) && - ((get_cr() & CR_920T_CLOCK_MODE) != CR_920T_FASTBUS_MODE)) - mpctl0_at_boot = MPCTL0; - - return cpufreq_register_driver(&imx_driver); -} - -arch_initcall(imx_cpufreq_init); - diff --git a/arch/arm/mach-imx/dma.c b/arch/arm/mach-imx/dma.c deleted file mode 100644 index 1536583eece0..000000000000 --- a/arch/arm/mach-imx/dma.c +++ /dev/null @@ -1,597 +0,0 @@ -/* - * linux/arch/arm/mach-imx/dma.c - * - * imx DMA registration and IRQ dispatching - * - * 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. - * - * 2004-03-03 Sascha Hauer - * initial version heavily inspired by - * linux/arch/arm/mach-pxa/dma.c - * - * 2005-04-17 Pavel Pisa - * Changed to support scatter gather DMA - * by taking Russell's code from RiscPC - * - * 2006-05-31 Pavel Pisa - * Corrected error handling code. - * - */ - -#undef DEBUG - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -struct imx_dma_channel imx_dma_channels[IMX_DMA_CHANNELS]; - -/* - * imx_dma_sg_next - prepare next chunk for scatter-gather DMA emulation - * @dma_ch: i.MX DMA channel number - * @lastcount: number of bytes transferred during last transfer - * - * Functions prepares DMA controller for next sg data chunk transfer. - * The @lastcount argument informs function about number of bytes transferred - * during last block. Zero value can be used for @lastcount to setup DMA - * for the first chunk. - */ -static inline int imx_dma_sg_next(imx_dmach_t dma_ch, unsigned int lastcount) -{ - struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch]; - unsigned int nextcount; - unsigned int nextaddr; - - if (!imxdma->name) { - printk(KERN_CRIT "%s: called for not allocated channel %d\n", - __func__, dma_ch); - return 0; - } - - imxdma->resbytes -= lastcount; - - if (!imxdma->sg) { - pr_debug("imxdma%d: no sg data\n", dma_ch); - return 0; - } - - imxdma->sgbc += lastcount; - if ((imxdma->sgbc >= imxdma->sg->length) || !imxdma->resbytes) { - if ((imxdma->sgcount <= 1) || !imxdma->resbytes) { - pr_debug("imxdma%d: sg transfer limit reached\n", - dma_ch); - imxdma->sgcount=0; - imxdma->sg = NULL; - return 0; - } else { - imxdma->sgcount--; - imxdma->sg++; - imxdma->sgbc = 0; - } - } - nextcount = imxdma->sg->length - imxdma->sgbc; - nextaddr = imxdma->sg->dma_address + imxdma->sgbc; - - if(imxdma->resbytes < nextcount) - nextcount = imxdma->resbytes; - - if ((imxdma->dma_mode & DMA_MODE_MASK) == DMA_MODE_READ) - DAR(dma_ch) = nextaddr; - else - SAR(dma_ch) = nextaddr; - - CNTR(dma_ch) = nextcount; - pr_debug("imxdma%d: next sg chunk dst 0x%08x, src 0x%08x, size 0x%08x\n", - dma_ch, DAR(dma_ch), SAR(dma_ch), CNTR(dma_ch)); - - return nextcount; -} - -/* - * imx_dma_setup_sg_base - scatter-gather DMA emulation - * @dma_ch: i.MX DMA channel number - * @sg: pointer to the scatter-gather list/vector - * @sgcount: scatter-gather list hungs count - * - * Functions sets up i.MX DMA state for emulated scatter-gather transfer - * and sets up channel registers to be ready for the first chunk - */ -static int -imx_dma_setup_sg_base(imx_dmach_t dma_ch, - struct scatterlist *sg, unsigned int sgcount) -{ - struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch]; - - imxdma->sg = sg; - imxdma->sgcount = sgcount; - imxdma->sgbc = 0; - return imx_dma_sg_next(dma_ch, 0); -} - -/** - * imx_dma_setup_single - setup i.MX DMA channel for linear memory to/from device transfer - * @dma_ch: i.MX DMA channel number - * @dma_address: the DMA/physical memory address of the linear data block - * to transfer - * @dma_length: length of the data block in bytes - * @dev_addr: physical device port address - * @dmamode: DMA transfer mode, %DMA_MODE_READ from the device to the memory - * or %DMA_MODE_WRITE from memory to the device - * - * The function setups DMA channel source and destination addresses for transfer - * specified by provided parameters. The scatter-gather emulation is disabled, - * because linear data block - * form the physical address range is transferred. - * Return value: if incorrect parameters are provided -%EINVAL. - * Zero indicates success. - */ -int -imx_dma_setup_single(imx_dmach_t dma_ch, dma_addr_t dma_address, - unsigned int dma_length, unsigned int dev_addr, - unsigned int dmamode) -{ - struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch]; - - imxdma->sg = NULL; - imxdma->sgcount = 0; - imxdma->dma_mode = dmamode; - imxdma->resbytes = dma_length; - - if (!dma_address) { - printk(KERN_ERR "imxdma%d: imx_dma_setup_single null address\n", - dma_ch); - return -EINVAL; - } - - if (!dma_length) { - printk(KERN_ERR "imxdma%d: imx_dma_setup_single zero length\n", - dma_ch); - return -EINVAL; - } - - if ((dmamode & DMA_MODE_MASK) == DMA_MODE_READ) { - pr_debug("imxdma%d: mx_dma_setup_single2dev dma_addressg=0x%08x dma_length=%d dev_addr=0x%08x for read\n", - dma_ch, (unsigned int)dma_address, dma_length, - dev_addr); - SAR(dma_ch) = dev_addr; - DAR(dma_ch) = (unsigned int)dma_address; - } else if ((dmamode & DMA_MODE_MASK) == DMA_MODE_WRITE) { - pr_debug("imxdma%d: mx_dma_setup_single2dev dma_addressg=0x%08x dma_length=%d dev_addr=0x%08x for write\n", - dma_ch, (unsigned int)dma_address, dma_length, - dev_addr); - SAR(dma_ch) = (unsigned int)dma_address; - DAR(dma_ch) = dev_addr; - } else { - printk(KERN_ERR "imxdma%d: imx_dma_setup_single bad dmamode\n", - dma_ch); - return -EINVAL; - } - - CNTR(dma_ch) = dma_length; - - return 0; -} - -/** - * imx_dma_setup_sg - setup i.MX DMA channel SG list to/from device transfer - * @dma_ch: i.MX DMA channel number - * @sg: pointer to the scatter-gather list/vector - * @sgcount: scatter-gather list hungs count - * @dma_length: total length of the transfer request in bytes - * @dev_addr: physical device port address - * @dmamode: DMA transfer mode, %DMA_MODE_READ from the device to the memory - * or %DMA_MODE_WRITE from memory to the device - * - * The function sets up DMA channel state and registers to be ready for transfer - * specified by provided parameters. The scatter-gather emulation is set up - * according to the parameters. - * - * The full preparation of the transfer requires setup of more register - * by the caller before imx_dma_enable() can be called. - * - * %BLR(dma_ch) holds transfer burst length in bytes, 0 means 64 bytes - * - * %RSSR(dma_ch) has to be set to the DMA request line source %DMA_REQ_xxx - * - * %CCR(dma_ch) has to specify transfer parameters, the next settings is typical - * for linear or simple scatter-gather transfers if %DMA_MODE_READ is specified - * - * %CCR_DMOD_LINEAR | %CCR_DSIZ_32 | %CCR_SMOD_FIFO | %CCR_SSIZ_x - * - * The typical setup for %DMA_MODE_WRITE is specified by next options combination - * - * %CCR_SMOD_LINEAR | %CCR_SSIZ_32 | %CCR_DMOD_FIFO | %CCR_DSIZ_x - * - * Be careful here and do not mistakenly mix source and target device - * port sizes constants, they are really different: - * %CCR_SSIZ_8, %CCR_SSIZ_16, %CCR_SSIZ_32, - * %CCR_DSIZ_8, %CCR_DSIZ_16, %CCR_DSIZ_32 - * - * Return value: if incorrect parameters are provided -%EINVAL. - * Zero indicates success. - */ -int -imx_dma_setup_sg(imx_dmach_t dma_ch, - struct scatterlist *sg, unsigned int sgcount, unsigned int dma_length, - unsigned int dev_addr, unsigned int dmamode) -{ - int res; - struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch]; - - imxdma->sg = NULL; - imxdma->sgcount = 0; - imxdma->dma_mode = dmamode; - imxdma->resbytes = dma_length; - - if (!sg || !sgcount) { - printk(KERN_ERR "imxdma%d: imx_dma_setup_sg epty sg list\n", - dma_ch); - return -EINVAL; - } - - if (!sg->length) { - printk(KERN_ERR "imxdma%d: imx_dma_setup_sg zero length\n", - dma_ch); - return -EINVAL; - } - - if ((dmamode & DMA_MODE_MASK) == DMA_MODE_READ) { - pr_debug("imxdma%d: mx_dma_setup_sg2dev sg=%p sgcount=%d total length=%d dev_addr=0x%08x for read\n", - dma_ch, sg, sgcount, dma_length, dev_addr); - SAR(dma_ch) = dev_addr; - } else if ((dmamode & DMA_MODE_MASK) == DMA_MODE_WRITE) { - pr_debug("imxdma%d: mx_dma_setup_sg2dev sg=%p sgcount=%d total length=%d dev_addr=0x%08x for write\n", - dma_ch, sg, sgcount, dma_length, dev_addr); - DAR(dma_ch) = dev_addr; - } else { - printk(KERN_ERR "imxdma%d: imx_dma_setup_sg bad dmamode\n", - dma_ch); - return -EINVAL; - } - - res = imx_dma_setup_sg_base(dma_ch, sg, sgcount); - if (res <= 0) { - printk(KERN_ERR "imxdma%d: no sg chunk ready\n", dma_ch); - return -EINVAL; - } - - return 0; -} - -/** - * imx_dma_setup_handlers - setup i.MX DMA channel end and error notification handlers - * @dma_ch: i.MX DMA channel number - * @irq_handler: the pointer to the function called if the transfer - * ends successfully - * @err_handler: the pointer to the function called if the premature - * end caused by error occurs - * @data: user specified value to be passed to the handlers - */ -int -imx_dma_setup_handlers(imx_dmach_t dma_ch, - void (*irq_handler) (int, void *), - void (*err_handler) (int, void *, int), - void *data) -{ - struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch]; - unsigned long flags; - - if (!imxdma->name) { - printk(KERN_CRIT "%s: called for not allocated channel %d\n", - __func__, dma_ch); - return -ENODEV; - } - - local_irq_save(flags); - DISR = (1 << dma_ch); - imxdma->irq_handler = irq_handler; - imxdma->err_handler = err_handler; - imxdma->data = data; - local_irq_restore(flags); - return 0; -} - -/** - * imx_dma_enable - function to start i.MX DMA channel operation - * @dma_ch: i.MX DMA channel number - * - * The channel has to be allocated by driver through imx_dma_request() - * or imx_dma_request_by_prio() function. - * The transfer parameters has to be set to the channel registers through - * call of the imx_dma_setup_single() or imx_dma_setup_sg() function - * and registers %BLR(dma_ch), %RSSR(dma_ch) and %CCR(dma_ch) has to - * be set prior this function call by the channel user. - */ -void imx_dma_enable(imx_dmach_t dma_ch) -{ - struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch]; - unsigned long flags; - - pr_debug("imxdma%d: imx_dma_enable\n", dma_ch); - - if (!imxdma->name) { - printk(KERN_CRIT "%s: called for not allocated channel %d\n", - __func__, dma_ch); - return; - } - - local_irq_save(flags); - DISR = (1 << dma_ch); - DIMR &= ~(1 << dma_ch); - CCR(dma_ch) |= CCR_CEN; - local_irq_restore(flags); -} - -/** - * imx_dma_disable - stop, finish i.MX DMA channel operatin - * @dma_ch: i.MX DMA channel number - */ -void imx_dma_disable(imx_dmach_t dma_ch) -{ - unsigned long flags; - - pr_debug("imxdma%d: imx_dma_disable\n", dma_ch); - - local_irq_save(flags); - DIMR |= (1 << dma_ch); - CCR(dma_ch) &= ~CCR_CEN; - DISR = (1 << dma_ch); - local_irq_restore(flags); -} - -/** - * imx_dma_request - request/allocate specified channel number - * @dma_ch: i.MX DMA channel number - * @name: the driver/caller own non-%NULL identification - */ -int imx_dma_request(imx_dmach_t dma_ch, const char *name) -{ - struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch]; - unsigned long flags; - - /* basic sanity checks */ - if (!name) - return -EINVAL; - - if (dma_ch >= IMX_DMA_CHANNELS) { - printk(KERN_CRIT "%s: called for non-existed channel %d\n", - __func__, dma_ch); - return -EINVAL; - } - - local_irq_save(flags); - if (imxdma->name) { - local_irq_restore(flags); - return -ENODEV; - } - - imxdma->name = name; - imxdma->irq_handler = NULL; - imxdma->err_handler = NULL; - imxdma->data = NULL; - imxdma->sg = NULL; - local_irq_restore(flags); - return 0; -} - -/** - * imx_dma_free - release previously acquired channel - * @dma_ch: i.MX DMA channel number - */ -void imx_dma_free(imx_dmach_t dma_ch) -{ - unsigned long flags; - struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch]; - - if (!imxdma->name) { - printk(KERN_CRIT - "%s: trying to free channel %d which is already freed\n", - __func__, dma_ch); - return; - } - - local_irq_save(flags); - /* Disable interrupts */ - DIMR |= (1 << dma_ch); - CCR(dma_ch) &= ~CCR_CEN; - imxdma->name = NULL; - local_irq_restore(flags); -} - -/** - * imx_dma_request_by_prio - find and request some of free channels best suiting requested priority - * @name: the driver/caller own non-%NULL identification - * @prio: one of the hardware distinguished priority level: - * %DMA_PRIO_HIGH, %DMA_PRIO_MEDIUM, %DMA_PRIO_LOW - * - * This function tries to find free channel in the specified priority group - * if the priority cannot be achieved it tries to look for free channel - * in the higher and then even lower priority groups. - * - * Return value: If there is no free channel to allocate, -%ENODEV is returned. - * On successful allocation channel is returned. - */ -imx_dmach_t imx_dma_request_by_prio(const char *name, imx_dma_prio prio) -{ - int i; - int best; - - switch (prio) { - case (DMA_PRIO_HIGH): - best = 8; - break; - case (DMA_PRIO_MEDIUM): - best = 4; - break; - case (DMA_PRIO_LOW): - default: - best = 0; - break; - } - - for (i = best; i < IMX_DMA_CHANNELS; i++) { - if (!imx_dma_request(i, name)) { - return i; - } - } - - for (i = best - 1; i >= 0; i--) { - if (!imx_dma_request(i, name)) { - return i; - } - } - - printk(KERN_ERR "%s: no free DMA channel found\n", __func__); - - return -ENODEV; -} - -static irqreturn_t dma_err_handler(int irq, void *dev_id) -{ - int i, disr = DISR; - struct imx_dma_channel *channel; - unsigned int err_mask = DBTOSR | DRTOSR | DSESR | DBOSR; - int errcode; - - DISR = disr & err_mask; - for (i = 0; i < IMX_DMA_CHANNELS; i++) { - if(!(err_mask & (1 << i))) - continue; - channel = &imx_dma_channels[i]; - errcode = 0; - - if (DBTOSR & (1 << i)) { - DBTOSR = (1 << i); - errcode |= IMX_DMA_ERR_BURST; - } - if (DRTOSR & (1 << i)) { - DRTOSR = (1 << i); - errcode |= IMX_DMA_ERR_REQUEST; - } - if (DSESR & (1 << i)) { - DSESR = (1 << i); - errcode |= IMX_DMA_ERR_TRANSFER; - } - if (DBOSR & (1 << i)) { - DBOSR = (1 << i); - errcode |= IMX_DMA_ERR_BUFFER; - } - - /* - * The cleaning of @sg field would be questionable - * there, because its value can help to compute - * remaining/transferred bytes count in the handler - */ - /*imx_dma_channels[i].sg = NULL;*/ - - if (channel->name && channel->err_handler) { - channel->err_handler(i, channel->data, errcode); - continue; - } - - imx_dma_channels[i].sg = NULL; - - printk(KERN_WARNING - "DMA timeout on channel %d (%s) -%s%s%s%s\n", - i, channel->name, - errcode&IMX_DMA_ERR_BURST? " burst":"", - errcode&IMX_DMA_ERR_REQUEST? " request":"", - errcode&IMX_DMA_ERR_TRANSFER? " transfer":"", - errcode&IMX_DMA_ERR_BUFFER? " buffer":""); - } - return IRQ_HANDLED; -} - -static irqreturn_t dma_irq_handler(int irq, void *dev_id) -{ - int i, disr = DISR; - - pr_debug("imxdma: dma_irq_handler called, disr=0x%08x\n", - disr); - - DISR = disr; - for (i = 0; i < IMX_DMA_CHANNELS; i++) { - if (disr & (1 << i)) { - struct imx_dma_channel *channel = &imx_dma_channels[i]; - if (channel->name) { - if (imx_dma_sg_next(i, CNTR(i))) { - CCR(i) &= ~CCR_CEN; - mb(); - CCR(i) |= CCR_CEN; - } else { - if (channel->irq_handler) - channel->irq_handler(i, - channel->data); - } - } else { - /* - * IRQ for an unregistered DMA channel: - * let's clear the interrupts and disable it. - */ - printk(KERN_WARNING - "spurious IRQ for DMA channel %d\n", i); - } - } - } - return IRQ_HANDLED; -} - -static int __init imx_dma_init(void) -{ - int ret; - int i; - - /* reset DMA module */ - DCR = DCR_DRST; - - ret = request_irq(DMA_INT, dma_irq_handler, 0, "DMA", NULL); - if (ret) { - printk(KERN_CRIT "Wow! Can't register IRQ for DMA\n"); - return ret; - } - - ret = request_irq(DMA_ERR, dma_err_handler, 0, "DMA", NULL); - if (ret) { - printk(KERN_CRIT "Wow! Can't register ERRIRQ for DMA\n"); - free_irq(DMA_INT, NULL); - } - - /* enable DMA module */ - DCR = DCR_DEN; - - /* clear all interrupts */ - DISR = (1 << IMX_DMA_CHANNELS) - 1; - - /* enable interrupts */ - DIMR = (1 << IMX_DMA_CHANNELS) - 1; - - for (i = 0; i < IMX_DMA_CHANNELS; i++) { - imx_dma_channels[i].sg = NULL; - imx_dma_channels[i].dma_num = i; - } - - return ret; -} - -arch_initcall(imx_dma_init); - -EXPORT_SYMBOL(imx_dma_setup_single); -EXPORT_SYMBOL(imx_dma_setup_sg); -EXPORT_SYMBOL(imx_dma_setup_handlers); -EXPORT_SYMBOL(imx_dma_enable); -EXPORT_SYMBOL(imx_dma_disable); -EXPORT_SYMBOL(imx_dma_request); -EXPORT_SYMBOL(imx_dma_free); -EXPORT_SYMBOL(imx_dma_request_by_prio); -EXPORT_SYMBOL(imx_dma_channels); diff --git a/arch/arm/mach-imx/generic.c b/arch/arm/mach-imx/generic.c deleted file mode 100644 index 05f1739ee127..000000000000 --- a/arch/arm/mach-imx/generic.c +++ /dev/null @@ -1,271 +0,0 @@ -/* - * arch/arm/mach-imx/generic.c - * - * author: Sascha Hauer - * Created: april 20th, 2004 - * Copyright: Synertronixx GmbH - * - * Common code for i.MX machines - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include - -unsigned long imx_gpio_alloc_map[(GPIO_PORT_MAX + 1) * 32 / BITS_PER_LONG]; - -void imx_gpio_mode(int gpio_mode) -{ - unsigned int pin = gpio_mode & GPIO_PIN_MASK; - unsigned int port = (gpio_mode & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT; - unsigned int ocr = (gpio_mode & GPIO_OCR_MASK) >> GPIO_OCR_SHIFT; - unsigned int tmp; - - /* Pullup enable */ - if(gpio_mode & GPIO_PUEN) - PUEN(port) |= (1<> GPIO_AOUT_SHIFT) & 3) << (pin * 2); - ICONFB1(port) &= ~( 3<<(pin*2)); - ICONFB1(port) |= ((gpio_mode >> GPIO_BOUT_SHIFT) & 3) << (pin * 2); - } else { - tmp = OCR2(port); - tmp &= ~( 3<<((pin-16)*2)); - tmp |= (ocr << ((pin-16)*2)); - OCR2(port) = tmp; - - ICONFA2(port) &= ~( 3<<((pin-16)*2)); - ICONFA2(port) |= ((gpio_mode >> GPIO_AOUT_SHIFT) & 3) << ((pin-16) * 2); - ICONFB2(port) &= ~( 3<<((pin-16)*2)); - ICONFB2(port) |= ((gpio_mode >> GPIO_BOUT_SHIFT) & 3) << ((pin-16) * 2); - } -} - -EXPORT_SYMBOL(imx_gpio_mode); - -int imx_gpio_request(unsigned gpio, const char *label) -{ - if(gpio >= (GPIO_PORT_MAX + 1) * 32) { - printk(KERN_ERR "imx_gpio: Attempt to request nonexistent GPIO %d for \"%s\"\n", - gpio, label ? label : "?"); - return -EINVAL; - } - - if(test_and_set_bit(gpio, imx_gpio_alloc_map)) { - printk(KERN_ERR "imx_gpio: GPIO %d already used. Allocation for \"%s\" failed\n", - gpio, label ? label : "?"); - return -EBUSY; - } - - return 0; -} - -EXPORT_SYMBOL(imx_gpio_request); - -void imx_gpio_free(unsigned gpio) -{ - if(gpio >= (GPIO_PORT_MAX + 1) * 32) - return; - - clear_bit(gpio, imx_gpio_alloc_map); -} - -EXPORT_SYMBOL(imx_gpio_free); - -int imx_gpio_direction_input(unsigned gpio) -{ - imx_gpio_mode(gpio | GPIO_IN | GPIO_GIUS | GPIO_DR); - return 0; -} - -EXPORT_SYMBOL(imx_gpio_direction_input); - -int imx_gpio_direction_output(unsigned gpio, int value) -{ - imx_gpio_set_value(gpio, value); - imx_gpio_mode(gpio | GPIO_OUT | GPIO_GIUS | GPIO_DR); - return 0; -} - -EXPORT_SYMBOL(imx_gpio_direction_output); - -int imx_gpio_setup_multiple_pins(const int *pin_list, unsigned count, - int alloc_mode, const char *label) -{ - const int *p = pin_list; - int i; - unsigned gpio; - unsigned mode; - - for (i = 0; i < count; i++) { - gpio = *p & (GPIO_PIN_MASK | GPIO_PORT_MASK); - mode = *p & ~(GPIO_PIN_MASK | GPIO_PORT_MASK); - - if (gpio >= (GPIO_PORT_MAX + 1) * 32) - goto setup_error; - - if (alloc_mode & IMX_GPIO_ALLOC_MODE_RELEASE) - imx_gpio_free(gpio); - else if (!(alloc_mode & IMX_GPIO_ALLOC_MODE_NO_ALLOC)) - if (imx_gpio_request(gpio, label)) - if (!(alloc_mode & IMX_GPIO_ALLOC_MODE_TRY_ALLOC)) - goto setup_error; - - if (!(alloc_mode & (IMX_GPIO_ALLOC_MODE_ALLOC_ONLY | - IMX_GPIO_ALLOC_MODE_RELEASE))) - imx_gpio_mode(gpio | mode); - - p++; - } - return 0; - -setup_error: - if(alloc_mode & (IMX_GPIO_ALLOC_MODE_NO_ALLOC | - IMX_GPIO_ALLOC_MODE_TRY_ALLOC)) - return -EINVAL; - - while (p != pin_list) { - p--; - gpio = *p & (GPIO_PIN_MASK | GPIO_PORT_MASK); - imx_gpio_free(gpio); - } - - return -EINVAL; -} - -EXPORT_SYMBOL(imx_gpio_setup_multiple_pins); - -void __imx_gpio_set_value(unsigned gpio, int value) -{ - imx_gpio_set_value_inline(gpio, value); -} - -EXPORT_SYMBOL(__imx_gpio_set_value); - -int imx_gpio_to_irq(unsigned gpio) -{ - return IRQ_GPIOA(0) + gpio; -} - -EXPORT_SYMBOL(imx_gpio_to_irq); - -int imx_irq_to_gpio(unsigned irq) -{ - if (irq < IRQ_GPIOA(0)) - return -EINVAL; - return irq - IRQ_GPIOA(0); -} - -EXPORT_SYMBOL(imx_irq_to_gpio); - -static struct resource imx_mmc_resources[] = { - [0] = { - .start = 0x00214000, - .end = 0x002140FF, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = (SDHC_INT), - .end = (SDHC_INT), - .flags = IORESOURCE_IRQ, - }, -}; - -static u64 imxmmmc_dmamask = 0xffffffffUL; - -static struct platform_device imx_mmc_device = { - .name = "imx-mmc", - .id = 0, - .dev = { - .dma_mask = &imxmmmc_dmamask, - .coherent_dma_mask = 0xffffffff, - }, - .num_resources = ARRAY_SIZE(imx_mmc_resources), - .resource = imx_mmc_resources, -}; - -void __init imx_set_mmc_info(struct imxmmc_platform_data *info) -{ - imx_mmc_device.dev.platform_data = info; -} - -static struct platform_device *devices[] __initdata = { - &imx_mmc_device, -}; - -static struct map_desc imx_io_desc[] __initdata = { - { - .virtual = IMX_IO_BASE, - .pfn = __phys_to_pfn(IMX_IO_PHYS), - .length = IMX_IO_SIZE, - .type = MT_DEVICE - } -}; - -void __init -imx_map_io(void) -{ - iotable_init(imx_io_desc, ARRAY_SIZE(imx_io_desc)); -} - -static int __init imx_init(void) -{ - return platform_add_devices(devices, ARRAY_SIZE(devices)); -} - -subsys_initcall(imx_init); diff --git a/arch/arm/mach-imx/generic.h b/arch/arm/mach-imx/generic.h deleted file mode 100644 index e91003e4bef3..000000000000 --- a/arch/arm/mach-imx/generic.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * linux/arch/arm/mach-imx/generic.h - * - * Author: Sascha Hauer - * Copyright: Synertronixx GmbH - * - * 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. - */ - -extern void __init imx_map_io(void); -extern void __init imx_init_irq(void); - -struct sys_timer; -extern struct sys_timer imx_timer; diff --git a/arch/arm/mach-imx/include/mach/debug-macro.S b/arch/arm/mach-imx/include/mach/debug-macro.S deleted file mode 100644 index 87802bbfe633..000000000000 --- a/arch/arm/mach-imx/include/mach/debug-macro.S +++ /dev/null @@ -1,34 +0,0 @@ -/* arch/arm/mach-imx/include/mach/debug-macro.S - * - * Debugging macro include header - * - * Copyright (C) 1994-1999 Russell King - * Moved from linux/arch/arm/kernel/debug.S by Ben Dooks - * - * 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. - * -*/ - - .macro addruart,rx - mrc p15, 0, \rx, c1, c0 - tst \rx, #1 @ MMU enabled? - moveq \rx, #0x00000000 @ physical - movne \rx, #0xe0000000 @ virtual - orreq \rx, \rx, #0x00200000 @ physical - orr \rx, \rx, #0x00006000 @ UART1 offset - .endm - - .macro senduart,rd,rx - str \rd, [\rx, #0x40] @ TXDATA - .endm - - .macro waituart,rd,rx - .endm - - .macro busyuart,rd,rx -1002: ldr \rd, [\rx, #0x98] @ SR2 - tst \rd, #1 << 3 @ TXDC - beq 1002b @ wait until transmit done - .endm diff --git a/arch/arm/mach-imx/include/mach/dma.h b/arch/arm/mach-imx/include/mach/dma.h deleted file mode 100644 index 621ff2c730f2..000000000000 --- a/arch/arm/mach-imx/include/mach/dma.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * linux/include/asm-arm/imxads/dma.h - * - * Copyright (C) 1997,1998 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __ASM_ARCH_DMA_H -#define __ASM_ARCH_DMA_H - -typedef enum { - DMA_PRIO_HIGH = 0, - DMA_PRIO_MEDIUM = 1, - DMA_PRIO_LOW = 2 -} imx_dma_prio; - -#define DMA_REQ_UART3_T 2 -#define DMA_REQ_UART3_R 3 -#define DMA_REQ_SSI2_T 4 -#define DMA_REQ_SSI2_R 5 -#define DMA_REQ_CSI_STAT 6 -#define DMA_REQ_CSI_R 7 -#define DMA_REQ_MSHC 8 -#define DMA_REQ_DSPA_DCT_DOUT 9 -#define DMA_REQ_DSPA_DCT_DIN 10 -#define DMA_REQ_DSPA_MAC 11 -#define DMA_REQ_EXT 12 -#define DMA_REQ_SDHC 13 -#define DMA_REQ_SPI1_R 14 -#define DMA_REQ_SPI1_T 15 -#define DMA_REQ_SSI_T 16 -#define DMA_REQ_SSI_R 17 -#define DMA_REQ_ASP_DAC 18 -#define DMA_REQ_ASP_ADC 19 -#define DMA_REQ_USP_EP(x) (20+(x)) -#define DMA_REQ_SPI2_R 26 -#define DMA_REQ_SPI2_T 27 -#define DMA_REQ_UART2_T 28 -#define DMA_REQ_UART2_R 29 -#define DMA_REQ_UART1_T 30 -#define DMA_REQ_UART1_R 31 - -#endif /* _ASM_ARCH_DMA_H */ diff --git a/arch/arm/mach-imx/include/mach/entry-macro.S b/arch/arm/mach-imx/include/mach/entry-macro.S deleted file mode 100644 index e4db679f7766..000000000000 --- a/arch/arm/mach-imx/include/mach/entry-macro.S +++ /dev/null @@ -1,32 +0,0 @@ -/* - * arch/arm/mach-imx/include/mach/entry-macro.S - * - * Low-level IRQ helper macros for iMX-based platforms - * - * 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 - - .macro disable_fiq - .endm - - .macro get_irqnr_preamble, base, tmp - .endm - - .macro arch_ret_to_user, tmp1, tmp2 - .endm - -#define AITC_NIVECSR 0x40 - .macro get_irqnr_and_base, irqnr, irqstat, base, tmp - ldr \base, =IO_ADDRESS(IMX_AITC_BASE) - @ Load offset & priority of the highest priority - @ interrupt pending. - ldr \irqstat, [\base, #AITC_NIVECSR] - @ Shift off the priority leaving the offset or - @ "interrupt number", use arithmetic shift to - @ transform illegal source (0xffff) as -1 - mov \irqnr, \irqstat, asr #16 - adds \tmp, \irqnr, #1 - .endm diff --git a/arch/arm/mach-imx/include/mach/gpio.h b/arch/arm/mach-imx/include/mach/gpio.h deleted file mode 100644 index 6c2942f82922..000000000000 --- a/arch/arm/mach-imx/include/mach/gpio.h +++ /dev/null @@ -1,106 +0,0 @@ -#ifndef _IMX_GPIO_H - -#include -#include -#include - -#define IMX_GPIO_ALLOC_MODE_NORMAL 0 -#define IMX_GPIO_ALLOC_MODE_NO_ALLOC 1 -#define IMX_GPIO_ALLOC_MODE_TRY_ALLOC 2 -#define IMX_GPIO_ALLOC_MODE_ALLOC_ONLY 4 -#define IMX_GPIO_ALLOC_MODE_RELEASE 8 - -extern int imx_gpio_request(unsigned gpio, const char *label); - -extern void imx_gpio_free(unsigned gpio); - -extern int imx_gpio_setup_multiple_pins(const int *pin_list, unsigned count, - int alloc_mode, const char *label); - -extern int imx_gpio_direction_input(unsigned gpio); - -extern int imx_gpio_direction_output(unsigned gpio, int value); - -extern void __imx_gpio_set_value(unsigned gpio, int value); - -static inline int imx_gpio_get_value(unsigned gpio) -{ - return SSR(gpio >> GPIO_PORT_SHIFT) & (1 << (gpio & GPIO_PIN_MASK)); -} - -static inline void imx_gpio_set_value_inline(unsigned gpio, int value) -{ - unsigned long flags; - - raw_local_irq_save(flags); - if(value) - DR(gpio >> GPIO_PORT_SHIFT) |= (1 << (gpio & GPIO_PIN_MASK)); - else - DR(gpio >> GPIO_PORT_SHIFT) &= ~(1 << (gpio & GPIO_PIN_MASK)); - raw_local_irq_restore(flags); -} - -static inline void imx_gpio_set_value(unsigned gpio, int value) -{ - if(__builtin_constant_p(gpio)) - imx_gpio_set_value_inline(gpio, value); - else - __imx_gpio_set_value(gpio, value); -} - -extern int imx_gpio_to_irq(unsigned gpio); - -extern int imx_irq_to_gpio(unsigned irq); - -/*-------------------------------------------------------------------------*/ - -/* Wrappers for "new style" GPIO calls. These calls i.MX specific versions - * to allow future extension of GPIO logic. - */ - -static inline int gpio_request(unsigned gpio, const char *label) -{ - return imx_gpio_request(gpio, label); -} - -static inline void gpio_free(unsigned gpio) -{ - might_sleep(); - - imx_gpio_free(gpio); -} - -static inline int gpio_direction_input(unsigned gpio) -{ - return imx_gpio_direction_input(gpio); -} - -static inline int gpio_direction_output(unsigned gpio, int value) -{ - return imx_gpio_direction_output(gpio, value); -} - -static inline int gpio_get_value(unsigned gpio) -{ - return imx_gpio_get_value(gpio); -} - -static inline void gpio_set_value(unsigned gpio, int value) -{ - imx_gpio_set_value(gpio, value); -} - -#include /* cansleep wrappers */ - -static inline int gpio_to_irq(unsigned gpio) -{ - return imx_gpio_to_irq(gpio); -} - -static inline int irq_to_gpio(unsigned irq) -{ - return imx_irq_to_gpio(irq); -} - - -#endif diff --git a/arch/arm/mach-imx/include/mach/hardware.h b/arch/arm/mach-imx/include/mach/hardware.h deleted file mode 100644 index c73e9e724c75..000000000000 --- a/arch/arm/mach-imx/include/mach/hardware.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * arch/arm/mach-imx/include/mach/hardware.h - * - * Copyright (C) 1999 ARM Limited. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef __ASM_ARCH_HARDWARE_H -#define __ASM_ARCH_HARDWARE_H - -#include -#include "imx-regs.h" - -#ifndef __ASSEMBLY__ -# define __REG(x) (*((volatile u32 *)IO_ADDRESS(x))) - -# define __REG2(x,y) (*(volatile u32 *)((u32)&__REG(x) + (y))) -#endif - -/* - * Memory map - */ - -#define IMX_IO_PHYS 0x00200000 -#define IMX_IO_SIZE 0x00100000 -#define IMX_IO_BASE 0xe0000000 - -#define IMX_CS0_PHYS 0x10000000 -#define IMX_CS0_SIZE 0x02000000 -#define IMX_CS0_VIRT 0xe8000000 - -#define IMX_CS1_PHYS 0x12000000 -#define IMX_CS1_SIZE 0x01000000 -#define IMX_CS1_VIRT 0xea000000 - -#define IMX_CS2_PHYS 0x13000000 -#define IMX_CS2_SIZE 0x01000000 -#define IMX_CS2_VIRT 0xeb000000 - -#define IMX_CS3_PHYS 0x14000000 -#define IMX_CS3_SIZE 0x01000000 -#define IMX_CS3_VIRT 0xec000000 - -#define IMX_CS4_PHYS 0x15000000 -#define IMX_CS4_SIZE 0x01000000 -#define IMX_CS4_VIRT 0xed000000 - -#define IMX_CS5_PHYS 0x16000000 -#define IMX_CS5_SIZE 0x01000000 -#define IMX_CS5_VIRT 0xee000000 - -#define IMX_FB_VIRT 0xF1000000 -#define IMX_FB_SIZE (256*1024) - -/* macro to get at IO space when running virtually */ -#define IO_ADDRESS(x) ((x) | IMX_IO_BASE) - -#ifndef __ASSEMBLY__ -/* - * Handy routine to set GPIO functions - */ -extern void imx_gpio_mode( int gpio_mode ); - -#endif - -#define MAXIRQNUM 62 -#define MAXFIQNUM 62 -#define MAXSWINUM 62 - -/* - * Use SDRAM for memory - */ -#define MEM_SIZE 0x01000000 - -#ifdef CONFIG_ARCH_MX1ADS -#include "mx1ads.h" -#endif - -#endif diff --git a/arch/arm/mach-imx/include/mach/imx-dma.h b/arch/arm/mach-imx/include/mach/imx-dma.h deleted file mode 100644 index bbe54df7f0de..000000000000 --- a/arch/arm/mach-imx/include/mach/imx-dma.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * linux/include/asm-arm/imxads/dma.h - * - * Copyright (C) 1997,1998 Russell King - * - * 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 - -#ifndef __ASM_ARCH_IMX_DMA_H -#define __ASM_ARCH_IMX_DMA_H - -#define IMX_DMA_CHANNELS 11 - -/* - * struct imx_dma_channel - i.MX specific DMA extension - * @name: name specified by DMA client - * @irq_handler: client callback for end of transfer - * @err_handler: client callback for error condition - * @data: clients context data for callbacks - * @dma_mode: direction of the transfer %DMA_MODE_READ or %DMA_MODE_WRITE - * @sg: pointer to the actual read/written chunk for scatter-gather emulation - * @sgbc: counter of processed bytes in the actual read/written chunk - * @resbytes: total residual number of bytes to transfer - * (it can be lower or same as sum of SG mapped chunk sizes) - * @sgcount: number of chunks to be read/written - * - * Structure is used for IMX DMA processing. It would be probably good - * @struct dma_struct in the future for external interfacing and use - * @struct imx_dma_channel only as extension to it. - */ - -struct imx_dma_channel { - const char *name; - void (*irq_handler) (int, void *); - void (*err_handler) (int, void *, int errcode); - void *data; - unsigned int dma_mode; - struct scatterlist *sg; - unsigned int sgbc; - unsigned int sgcount; - unsigned int resbytes; - int dma_num; -}; - -extern struct imx_dma_channel imx_dma_channels[IMX_DMA_CHANNELS]; - -#define IMX_DMA_ERR_BURST 1 -#define IMX_DMA_ERR_REQUEST 2 -#define IMX_DMA_ERR_TRANSFER 4 -#define IMX_DMA_ERR_BUFFER 8 - -/* The type to distinguish channel numbers parameter from ordinal int type */ -typedef int imx_dmach_t; - -#define DMA_MODE_READ 0 -#define DMA_MODE_WRITE 1 -#define DMA_MODE_MASK 1 - -int -imx_dma_setup_single(imx_dmach_t dma_ch, dma_addr_t dma_address, - unsigned int dma_length, unsigned int dev_addr, unsigned int dmamode); - -int -imx_dma_setup_sg(imx_dmach_t dma_ch, - struct scatterlist *sg, unsigned int sgcount, unsigned int dma_length, - unsigned int dev_addr, unsigned int dmamode); - -int -imx_dma_setup_handlers(imx_dmach_t dma_ch, - void (*irq_handler) (int, void *), - void (*err_handler) (int, void *, int), void *data); - -void imx_dma_enable(imx_dmach_t dma_ch); - -void imx_dma_disable(imx_dmach_t dma_ch); - -int imx_dma_request(imx_dmach_t dma_ch, const char *name); - -void imx_dma_free(imx_dmach_t dma_ch); - -imx_dmach_t imx_dma_request_by_prio(const char *name, imx_dma_prio prio); - - -#endif /* _ASM_ARCH_IMX_DMA_H */ diff --git a/arch/arm/mach-imx/include/mach/imx-regs.h b/arch/arm/mach-imx/include/mach/imx-regs.h deleted file mode 100644 index 490297fc0e38..000000000000 --- a/arch/arm/mach-imx/include/mach/imx-regs.h +++ /dev/null @@ -1,376 +0,0 @@ -#ifndef _IMX_REGS_H -#define _IMX_REGS_H -/* ------------------------------------------------------------------------ - * Motorola IMX system registers - * ------------------------------------------------------------------------ - * - */ - -/* - * Register BASEs, based on OFFSETs - * - */ -#define IMX_AIPI1_BASE (0x00000 + IMX_IO_BASE) -#define IMX_WDT_BASE (0x01000 + IMX_IO_BASE) -#define IMX_TIM1_BASE (0x02000 + IMX_IO_BASE) -#define IMX_TIM2_BASE (0x03000 + IMX_IO_BASE) -#define IMX_RTC_BASE (0x04000 + IMX_IO_BASE) -#define IMX_LCDC_BASE (0x05000 + IMX_IO_BASE) -#define IMX_UART1_BASE (0x06000 + IMX_IO_BASE) -#define IMX_UART2_BASE (0x07000 + IMX_IO_BASE) -#define IMX_PWM_BASE (0x08000 + IMX_IO_BASE) -#define IMX_DMAC_BASE (0x09000 + IMX_IO_BASE) -#define IMX_AIPI2_BASE (0x10000 + IMX_IO_BASE) -#define IMX_SIM_BASE (0x11000 + IMX_IO_BASE) -#define IMX_USBD_BASE (0x12000 + IMX_IO_BASE) -#define IMX_SPI1_BASE (0x13000 + IMX_IO_BASE) -#define IMX_MMC_BASE (0x14000 + IMX_IO_BASE) -#define IMX_ASP_BASE (0x15000 + IMX_IO_BASE) -#define IMX_BTA_BASE (0x16000 + IMX_IO_BASE) -#define IMX_I2C_BASE (0x17000 + IMX_IO_BASE) -#define IMX_SSI_BASE (0x18000 + IMX_IO_BASE) -#define IMX_SPI2_BASE (0x19000 + IMX_IO_BASE) -#define IMX_MSHC_BASE (0x1A000 + IMX_IO_BASE) -#define IMX_PLL_BASE (0x1B000 + IMX_IO_BASE) -#define IMX_GPIO_BASE (0x1C000 + IMX_IO_BASE) -#define IMX_EIM_BASE (0x20000 + IMX_IO_BASE) -#define IMX_SDRAMC_BASE (0x21000 + IMX_IO_BASE) -#define IMX_MMA_BASE (0x22000 + IMX_IO_BASE) -#define IMX_AITC_BASE (0x23000 + IMX_IO_BASE) -#define IMX_CSI_BASE (0x24000 + IMX_IO_BASE) - -/* PLL registers */ -#define CSCR __REG(IMX_PLL_BASE) /* Clock Source Control Register */ -#define CSCR_SPLL_RESTART (1<<22) -#define CSCR_MPLL_RESTART (1<<21) -#define CSCR_SYSTEM_SEL (1<<16) -#define CSCR_BCLK_DIV (0xf<<10) -#define CSCR_MPU_PRESC (1<<15) -#define CSCR_SPEN (1<<1) -#define CSCR_MPEN (1<<0) - -#define MPCTL0 __REG(IMX_PLL_BASE + 0x4) /* MCU PLL Control Register 0 */ -#define MPCTL1 __REG(IMX_PLL_BASE + 0x8) /* MCU PLL and System Clock Register 1 */ -#define SPCTL0 __REG(IMX_PLL_BASE + 0xc) /* System PLL Control Register 0 */ -#define SPCTL1 __REG(IMX_PLL_BASE + 0x10) /* System PLL Control Register 1 */ -#define PCDR __REG(IMX_PLL_BASE + 0x20) /* Peripheral Clock Divider Register */ - -/* - * GPIO Module and I/O Multiplexer - * x = 0..3 for reg_A, reg_B, reg_C, reg_D - */ -#define DDIR(x) __REG2(IMX_GPIO_BASE + 0x00, ((x) & 3) << 8) -#define OCR1(x) __REG2(IMX_GPIO_BASE + 0x04, ((x) & 3) << 8) -#define OCR2(x) __REG2(IMX_GPIO_BASE + 0x08, ((x) & 3) << 8) -#define ICONFA1(x) __REG2(IMX_GPIO_BASE + 0x0c, ((x) & 3) << 8) -#define ICONFA2(x) __REG2(IMX_GPIO_BASE + 0x10, ((x) & 3) << 8) -#define ICONFB1(x) __REG2(IMX_GPIO_BASE + 0x14, ((x) & 3) << 8) -#define ICONFB2(x) __REG2(IMX_GPIO_BASE + 0x18, ((x) & 3) << 8) -#define DR(x) __REG2(IMX_GPIO_BASE + 0x1c, ((x) & 3) << 8) -#define GIUS(x) __REG2(IMX_GPIO_BASE + 0x20, ((x) & 3) << 8) -#define SSR(x) __REG2(IMX_GPIO_BASE + 0x24, ((x) & 3) << 8) -#define ICR1(x) __REG2(IMX_GPIO_BASE + 0x28, ((x) & 3) << 8) -#define ICR2(x) __REG2(IMX_GPIO_BASE + 0x2c, ((x) & 3) << 8) -#define IMR(x) __REG2(IMX_GPIO_BASE + 0x30, ((x) & 3) << 8) -#define ISR(x) __REG2(IMX_GPIO_BASE + 0x34, ((x) & 3) << 8) -#define GPR(x) __REG2(IMX_GPIO_BASE + 0x38, ((x) & 3) << 8) -#define SWR(x) __REG2(IMX_GPIO_BASE + 0x3c, ((x) & 3) << 8) -#define PUEN(x) __REG2(IMX_GPIO_BASE + 0x40, ((x) & 3) << 8) - -#define GPIO_PORT_MAX 3 - -#define GPIO_PIN_MASK 0x1f -#define GPIO_PORT_MASK (0x3 << 5) - -#define GPIO_PORT_SHIFT 5 -#define GPIO_PORTA (0<<5) -#define GPIO_PORTB (1<<5) -#define GPIO_PORTC (2<<5) -#define GPIO_PORTD (3<<5) - -#define GPIO_OUT (1<<7) -#define GPIO_IN (0<<7) -#define GPIO_PUEN (1<<8) - -#define GPIO_PF (0<<9) -#define GPIO_AF (1<<9) - -#define GPIO_OCR_SHIFT 10 -#define GPIO_OCR_MASK (3<<10) -#define GPIO_AIN (0<<10) -#define GPIO_BIN (1<<10) -#define GPIO_CIN (2<<10) -#define GPIO_DR (3<<10) - -#define GPIO_AOUT_SHIFT 12 -#define GPIO_AOUT_MASK (3<<12) -#define GPIO_AOUT (0<<12) -#define GPIO_AOUT_ISR (1<<12) -#define GPIO_AOUT_0 (2<<12) -#define GPIO_AOUT_1 (3<<12) - -#define GPIO_BOUT_SHIFT 14 -#define GPIO_BOUT_MASK (3<<14) -#define GPIO_BOUT (0<<14) -#define GPIO_BOUT_ISR (1<<14) -#define GPIO_BOUT_0 (2<<14) -#define GPIO_BOUT_1 (3<<14) - -#define GPIO_GIUS (1<<16) - -/* assignements for GPIO alternate/primary functions */ - -/* FIXME: This list is not completed. The correct directions are - * missing on some (many) pins - */ -#define PA0_AIN_SPI2_CLK ( GPIO_GIUS | GPIO_PORTA | GPIO_OUT | 0 ) -#define PA0_AF_ETMTRACESYNC ( GPIO_PORTA | GPIO_AF | 0 ) -#define PA1_AOUT_SPI2_RXD ( GPIO_GIUS | GPIO_PORTA | GPIO_IN | 1 ) -#define PA1_PF_TIN ( GPIO_PORTA | GPIO_PF | 1 ) -#define PA2_PF_PWM0 ( GPIO_PORTA | GPIO_OUT | GPIO_PF | 2 ) -#define PA3_PF_CSI_MCLK ( GPIO_PORTA | GPIO_PF | 3 ) -#define PA4_PF_CSI_D0 ( GPIO_PORTA | GPIO_PF | 4 ) -#define PA5_PF_CSI_D1 ( GPIO_PORTA | GPIO_PF | 5 ) -#define PA6_PF_CSI_D2 ( GPIO_PORTA | GPIO_PF | 6 ) -#define PA7_PF_CSI_D3 ( GPIO_PORTA | GPIO_PF | 7 ) -#define PA8_PF_CSI_D4 ( GPIO_PORTA | GPIO_PF | 8 ) -#define PA9_PF_CSI_D5 ( GPIO_PORTA | GPIO_PF | 9 ) -#define PA10_PF_CSI_D6 ( GPIO_PORTA | GPIO_PF | 10 ) -#define PA11_PF_CSI_D7 ( GPIO_PORTA | GPIO_PF | 11 ) -#define PA12_PF_CSI_VSYNC ( GPIO_PORTA | GPIO_PF | 12 ) -#define PA13_PF_CSI_HSYNC ( GPIO_PORTA | GPIO_PF | 13 ) -#define PA14_PF_CSI_PIXCLK ( GPIO_PORTA | GPIO_PF | 14 ) -#define PA15_PF_I2C_SDA ( GPIO_PORTA | GPIO_OUT | GPIO_PF | 15 ) -#define PA16_PF_I2C_SCL ( GPIO_PORTA | GPIO_OUT | GPIO_PF | 16 ) -#define PA17_AF_ETMTRACEPKT4 ( GPIO_PORTA | GPIO_AF | 17 ) -#define PA17_AIN_SPI2_SS ( GPIO_GIUS | GPIO_PORTA | GPIO_OUT | 17 ) -#define PA18_AF_ETMTRACEPKT5 ( GPIO_PORTA | GPIO_AF | 18 ) -#define PA19_AF_ETMTRACEPKT6 ( GPIO_PORTA | GPIO_AF | 19 ) -#define PA20_AF_ETMTRACEPKT7 ( GPIO_PORTA | GPIO_AF | 20 ) -#define PA21_PF_A0 ( GPIO_PORTA | GPIO_PF | 21 ) -#define PA22_PF_CS4 ( GPIO_PORTA | GPIO_PF | 22 ) -#define PA23_PF_CS5 ( GPIO_PORTA | GPIO_PF | 23 ) -#define PA24_PF_A16 ( GPIO_PORTA | GPIO_PF | 24 ) -#define PA24_AF_ETMTRACEPKT0 ( GPIO_PORTA | GPIO_AF | 24 ) -#define PA25_PF_A17 ( GPIO_PORTA | GPIO_PF | 25 ) -#define PA25_AF_ETMTRACEPKT1 ( GPIO_PORTA | GPIO_AF | 25 ) -#define PA26_PF_A18 ( GPIO_PORTA | GPIO_PF | 26 ) -#define PA26_AF_ETMTRACEPKT2 ( GPIO_PORTA | GPIO_AF | 26 ) -#define PA27_PF_A19 ( GPIO_PORTA | GPIO_PF | 27 ) -#define PA27_AF_ETMTRACEPKT3 ( GPIO_PORTA | GPIO_AF | 27 ) -#define PA28_PF_A20 ( GPIO_PORTA | GPIO_PF | 28 ) -#define PA28_AF_ETMPIPESTAT0 ( GPIO_PORTA | GPIO_AF | 28 ) -#define PA29_PF_A21 ( GPIO_PORTA | GPIO_PF | 29 ) -#define PA29_AF_ETMPIPESTAT1 ( GPIO_PORTA | GPIO_AF | 29 ) -#define PA30_PF_A22 ( GPIO_PORTA | GPIO_PF | 30 ) -#define PA30_AF_ETMPIPESTAT2 ( GPIO_PORTA | GPIO_AF | 30 ) -#define PA31_PF_A23 ( GPIO_PORTA | GPIO_PF | 31 ) -#define PA31_AF_ETMTRACECLK ( GPIO_PORTA | GPIO_AF | 31 ) -#define PB8_PF_SD_DAT0 ( GPIO_PORTB | GPIO_PF | GPIO_PUEN | 8 ) -#define PB8_AF_MS_PIO ( GPIO_PORTB | GPIO_AF | 8 ) -#define PB9_PF_SD_DAT1 ( GPIO_PORTB | GPIO_PF | GPIO_PUEN | 9 ) -#define PB9_AF_MS_PI1 ( GPIO_PORTB | GPIO_AF | 9 ) -#define PB10_PF_SD_DAT2 ( GPIO_PORTB | GPIO_PF | GPIO_PUEN | 10 ) -#define PB10_AF_MS_SCLKI ( GPIO_PORTB | GPIO_AF | 10 ) -#define PB11_PF_SD_DAT3 ( GPIO_PORTB | GPIO_PF | 11 ) -#define PB11_AF_MS_SDIO ( GPIO_PORTB | GPIO_AF | 11 ) -#define PB12_PF_SD_CLK ( GPIO_PORTB | GPIO_PF | 12 ) -#define PB12_AF_MS_SCLK0 ( GPIO_PORTB | GPIO_AF | 12 ) -#define PB13_PF_SD_CMD ( GPIO_PORTB | GPIO_PF | GPIO_PUEN | 13 ) -#define PB13_AF_MS_BS ( GPIO_PORTB | GPIO_AF | 13 ) -#define PB14_AF_SSI_RXFS ( GPIO_PORTB | GPIO_AF | 14 ) -#define PB15_AF_SSI_RXCLK ( GPIO_PORTB | GPIO_AF | 15 ) -#define PB16_AF_SSI_RXDAT ( GPIO_PORTB | GPIO_IN | GPIO_AF | 16 ) -#define PB17_AF_SSI_TXDAT ( GPIO_PORTB | GPIO_OUT | GPIO_AF | 17 ) -#define PB18_AF_SSI_TXFS ( GPIO_PORTB | GPIO_AF | 18 ) -#define PB19_AF_SSI_TXCLK ( GPIO_PORTB | GPIO_AF | 19 ) -#define PB20_PF_USBD_AFE ( GPIO_PORTB | GPIO_PF | 20 ) -#define PB21_PF_USBD_OE ( GPIO_PORTB | GPIO_PF | 21 ) -#define PB22_PFUSBD_RCV ( GPIO_PORTB | GPIO_PF | 22 ) -#define PB23_PF_USBD_SUSPND ( GPIO_PORTB | GPIO_PF | 23 ) -#define PB24_PF_USBD_VP ( GPIO_PORTB | GPIO_PF | 24 ) -#define PB25_PF_USBD_VM ( GPIO_PORTB | GPIO_PF | 25 ) -#define PB26_PF_USBD_VPO ( GPIO_PORTB | GPIO_PF | 26 ) -#define PB27_PF_USBD_VMO ( GPIO_PORTB | GPIO_PF | 27 ) -#define PB28_PF_UART2_CTS ( GPIO_PORTB | GPIO_OUT | GPIO_PF | 28 ) -#define PB29_PF_UART2_RTS ( GPIO_PORTB | GPIO_IN | GPIO_PF | 29 ) -#define PB30_PF_UART2_TXD ( GPIO_PORTB | GPIO_OUT | GPIO_PF | 30 ) -#define PB31_PF_UART2_RXD ( GPIO_PORTB | GPIO_IN | GPIO_PF | 31 ) -#define PC3_PF_SSI_RXFS ( GPIO_PORTC | GPIO_PF | 3 ) -#define PC4_PF_SSI_RXCLK ( GPIO_PORTC | GPIO_PF | 4 ) -#define PC5_PF_SSI_RXDAT ( GPIO_PORTC | GPIO_IN | GPIO_PF | 5 ) -#define PC6_PF_SSI_TXDAT ( GPIO_PORTC | GPIO_OUT | GPIO_PF | 6 ) -#define PC7_PF_SSI_TXFS ( GPIO_PORTC | GPIO_PF | 7 ) -#define PC8_PF_SSI_TXCLK ( GPIO_PORTC | GPIO_PF | 8 ) -#define PC9_PF_UART1_CTS ( GPIO_PORTC | GPIO_OUT | GPIO_PF | 9 ) -#define PC10_PF_UART1_RTS ( GPIO_PORTC | GPIO_IN | GPIO_PF | 10 ) -#define PC11_PF_UART1_TXD ( GPIO_PORTC | GPIO_OUT | GPIO_PF | 11 ) -#define PC12_PF_UART1_RXD ( GPIO_PORTC | GPIO_IN | GPIO_PF | 12 ) -#define PC13_PF_SPI1_SPI_RDY ( GPIO_PORTC | GPIO_PF | 13 ) -#define PC14_PF_SPI1_SCLK ( GPIO_PORTC | GPIO_PF | 14 ) -#define PC15_PF_SPI1_SS ( GPIO_PORTC | GPIO_PF | 15 ) -#define PC16_PF_SPI1_MISO ( GPIO_PORTC | GPIO_PF | 16 ) -#define PC17_PF_SPI1_MOSI ( GPIO_PORTC | GPIO_PF | 17 ) -#define PC24_BIN_UART3_RI ( GPIO_GIUS | GPIO_PORTC | GPIO_OUT | GPIO_BIN | 24 ) -#define PC25_BIN_UART3_DSR ( GPIO_GIUS | GPIO_PORTC | GPIO_OUT | GPIO_BIN | 25 ) -#define PC26_AOUT_UART3_DTR ( GPIO_GIUS | GPIO_PORTC | GPIO_IN | 26 ) -#define PC27_BIN_UART3_DCD ( GPIO_GIUS | GPIO_PORTC | GPIO_OUT | GPIO_BIN | 27 ) -#define PC28_BIN_UART3_CTS ( GPIO_GIUS | GPIO_PORTC | GPIO_OUT | GPIO_BIN | 28 ) -#define PC29_AOUT_UART3_RTS ( GPIO_GIUS | GPIO_PORTC | GPIO_IN | 29 ) -#define PC30_BIN_UART3_TX ( GPIO_GIUS | GPIO_PORTC | GPIO_BIN | 30 ) -#define PC31_AOUT_UART3_RX ( GPIO_GIUS | GPIO_PORTC | GPIO_IN | 31) -#define PD6_PF_LSCLK ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 6 ) -#define PD7_PF_REV ( GPIO_PORTD | GPIO_PF | 7 ) -#define PD7_AF_UART2_DTR ( GPIO_GIUS | GPIO_PORTD | GPIO_IN | GPIO_AF | 7 ) -#define PD7_AIN_SPI2_SCLK ( GPIO_GIUS | GPIO_PORTD | GPIO_AIN | 7 ) -#define PD8_PF_CLS ( GPIO_PORTD | GPIO_PF | 8 ) -#define PD8_AF_UART2_DCD ( GPIO_PORTD | GPIO_OUT | GPIO_AF | 8 ) -#define PD8_AIN_SPI2_SS ( GPIO_GIUS | GPIO_PORTD | GPIO_AIN | 8 ) -#define PD9_PF_PS ( GPIO_PORTD | GPIO_PF | 9 ) -#define PD9_AF_UART2_RI ( GPIO_PORTD | GPIO_OUT | GPIO_AF | 9 ) -#define PD9_AOUT_SPI2_RXD ( GPIO_GIUS | GPIO_PORTD | GPIO_IN | 9 ) -#define PD10_PF_SPL_SPR ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 10 ) -#define PD10_AF_UART2_DSR ( GPIO_PORTD | GPIO_OUT | GPIO_AF | 10 ) -#define PD10_AIN_SPI2_TXD ( GPIO_GIUS | GPIO_PORTD | GPIO_OUT | 10 ) -#define PD11_PF_CONTRAST ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 11 ) -#define PD12_PF_ACD_OE ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 12 ) -#define PD13_PF_LP_HSYNC ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 13 ) -#define PD14_PF_FLM_VSYNC ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 14 ) -#define PD15_PF_LD0 ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 15 ) -#define PD16_PF_LD1 ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 16 ) -#define PD17_PF_LD2 ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 17 ) -#define PD18_PF_LD3 ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 18 ) -#define PD19_PF_LD4 ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 19 ) -#define PD20_PF_LD5 ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 20 ) -#define PD21_PF_LD6 ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 21 ) -#define PD22_PF_LD7 ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 22 ) -#define PD23_PF_LD8 ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 23 ) -#define PD24_PF_LD9 ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 24 ) -#define PD25_PF_LD10 ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 25 ) -#define PD26_PF_LD11 ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 26 ) -#define PD27_PF_LD12 ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 27 ) -#define PD28_PF_LD13 ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 28 ) -#define PD29_PF_LD14 ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 29 ) -#define PD30_PF_LD15 ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 30 ) -#define PD31_PF_TMR2OUT ( GPIO_PORTD | GPIO_PF | 31 ) -#define PD31_BIN_SPI2_TXD ( GPIO_GIUS | GPIO_PORTD | GPIO_BIN | 31 ) - -/* - * PWM controller - */ -#define PWMC __REG(IMX_PWM_BASE + 0x00) /* PWM Control Register */ -#define PWMS __REG(IMX_PWM_BASE + 0x04) /* PWM Sample Register */ -#define PWMP __REG(IMX_PWM_BASE + 0x08) /* PWM Period Register */ -#define PWMCNT __REG(IMX_PWM_BASE + 0x0C) /* PWM Counter Register */ - -#define PWMC_HCTR (0x01<<18) /* Halfword FIFO Data Swapping */ -#define PWMC_BCTR (0x01<<17) /* Byte FIFO Data Swapping */ -#define PWMC_SWR (0x01<<16) /* Software Reset */ -#define PWMC_CLKSRC (0x01<<15) /* Clock Source */ -#define PWMC_PRESCALER(x) (((x-1) & 0x7F) << 8) /* PRESCALER */ -#define PWMC_IRQ (0x01<< 7) /* Interrupt Request */ -#define PWMC_IRQEN (0x01<< 6) /* Interrupt Request Enable */ -#define PWMC_FIFOAV (0x01<< 5) /* FIFO Available */ -#define PWMC_EN (0x01<< 4) /* Enables/Disables the PWM */ -#define PWMC_REPEAT(x) (((x) & 0x03) << 2) /* Sample Repeats */ -#define PWMC_CLKSEL(x) (((x) & 0x03) << 0) /* Clock Selection */ - -#define PWMS_SAMPLE(x) ((x) & 0xFFFF) /* Contains a two-sample word */ -#define PWMP_PERIOD(x) ((x) & 0xFFFF) /* Represents the PWM's period */ -#define PWMC_COUNTER(x) ((x) & 0xFFFF) /* Represents the current count value */ - -/* - * DMA Controller - */ -#define DCR __REG(IMX_DMAC_BASE +0x00) /* DMA Control Register */ -#define DISR __REG(IMX_DMAC_BASE +0x04) /* DMA Interrupt status Register */ -#define DIMR __REG(IMX_DMAC_BASE +0x08) /* DMA Interrupt mask Register */ -#define DBTOSR __REG(IMX_DMAC_BASE +0x0c) /* DMA Burst timeout status Register */ -#define DRTOSR __REG(IMX_DMAC_BASE +0x10) /* DMA Request timeout Register */ -#define DSESR __REG(IMX_DMAC_BASE +0x14) /* DMA Transfer Error Status Register */ -#define DBOSR __REG(IMX_DMAC_BASE +0x18) /* DMA Buffer overflow status Register */ -#define DBTOCR __REG(IMX_DMAC_BASE +0x1c) /* DMA Burst timeout control Register */ -#define WSRA __REG(IMX_DMAC_BASE +0x40) /* W-Size Register A */ -#define XSRA __REG(IMX_DMAC_BASE +0x44) /* X-Size Register A */ -#define YSRA __REG(IMX_DMAC_BASE +0x48) /* Y-Size Register A */ -#define WSRB __REG(IMX_DMAC_BASE +0x4c) /* W-Size Register B */ -#define XSRB __REG(IMX_DMAC_BASE +0x50) /* X-Size Register B */ -#define YSRB __REG(IMX_DMAC_BASE +0x54) /* Y-Size Register B */ -#define SAR(x) __REG2( IMX_DMAC_BASE + 0x80, (x) << 6) /* Source Address Registers */ -#define DAR(x) __REG2( IMX_DMAC_BASE + 0x84, (x) << 6) /* Destination Address Registers */ -#define CNTR(x) __REG2( IMX_DMAC_BASE + 0x88, (x) << 6) /* Count Registers */ -#define CCR(x) __REG2( IMX_DMAC_BASE + 0x8c, (x) << 6) /* Control Registers */ -#define RSSR(x) __REG2( IMX_DMAC_BASE + 0x90, (x) << 6) /* Request source select Registers */ -#define BLR(x) __REG2( IMX_DMAC_BASE + 0x94, (x) << 6) /* Burst length Registers */ -#define RTOR(x) __REG2( IMX_DMAC_BASE + 0x98, (x) << 6) /* Request timeout Registers */ -#define BUCR(x) __REG2( IMX_DMAC_BASE + 0x98, (x) << 6) /* Bus Utilization Registers */ - -#define DCR_DRST (1<<1) -#define DCR_DEN (1<<0) -#define DBTOCR_EN (1<<15) -#define DBTOCR_CNT(x) ((x) & 0x7fff ) -#define CNTR_CNT(x) ((x) & 0xffffff ) -#define CCR_DMOD_LINEAR ( 0x0 << 12 ) -#define CCR_DMOD_2D ( 0x1 << 12 ) -#define CCR_DMOD_FIFO ( 0x2 << 12 ) -#define CCR_DMOD_EOBFIFO ( 0x3 << 12 ) -#define CCR_SMOD_LINEAR ( 0x0 << 10 ) -#define CCR_SMOD_2D ( 0x1 << 10 ) -#define CCR_SMOD_FIFO ( 0x2 << 10 ) -#define CCR_SMOD_EOBFIFO ( 0x3 << 10 ) -#define CCR_MDIR_DEC (1<<9) -#define CCR_MSEL_B (1<<8) -#define CCR_DSIZ_32 ( 0x0 << 6 ) -#define CCR_DSIZ_8 ( 0x1 << 6 ) -#define CCR_DSIZ_16 ( 0x2 << 6 ) -#define CCR_SSIZ_32 ( 0x0 << 4 ) -#define CCR_SSIZ_8 ( 0x1 << 4 ) -#define CCR_SSIZ_16 ( 0x2 << 4 ) -#define CCR_REN (1<<3) -#define CCR_RPT (1<<2) -#define CCR_FRC (1<<1) -#define CCR_CEN (1<<0) -#define RTOR_EN (1<<15) -#define RTOR_CLK (1<<14) -#define RTOR_PSC (1<<13) - -/* - * Interrupt controller - */ - -#define IMX_INTCNTL __REG(IMX_AITC_BASE+0x00) -#define INTCNTL_FIAD (1<<19) -#define INTCNTL_NIAD (1<<20) - -#define IMX_NIMASK __REG(IMX_AITC_BASE+0x04) -#define IMX_INTENNUM __REG(IMX_AITC_BASE+0x08) -#define IMX_INTDISNUM __REG(IMX_AITC_BASE+0x0c) -#define IMX_INTENABLEH __REG(IMX_AITC_BASE+0x10) -#define IMX_INTENABLEL __REG(IMX_AITC_BASE+0x14) - -/* - * General purpose timers - */ -#define IMX_TCTL(x) __REG( 0x00 + (x)) -#define TCTL_SWR (1<<15) -#define TCTL_FRR (1<<8) -#define TCTL_CAP_RIS (1<<6) -#define TCTL_CAP_FAL (2<<6) -#define TCTL_CAP_RIS_FAL (3<<6) -#define TCTL_OM (1<<5) -#define TCTL_IRQEN (1<<4) -#define TCTL_CLK_PCLK1 (1<<1) -#define TCTL_CLK_PCLK1_16 (2<<1) -#define TCTL_CLK_TIN (3<<1) -#define TCTL_CLK_32 (4<<1) -#define TCTL_TEN (1<<0) - -#define IMX_TPRER(x) __REG( 0x04 + (x)) -#define IMX_TCMP(x) __REG( 0x08 + (x)) -#define IMX_TCR(x) __REG( 0x0C + (x)) -#define IMX_TCN(x) __REG( 0x10 + (x)) -#define IMX_TSTAT(x) __REG( 0x14 + (x)) -#define TSTAT_CAPT (1<<1) -#define TSTAT_COMP (1<<0) - -#endif // _IMX_REGS_H diff --git a/arch/arm/mach-imx/include/mach/imx-uart.h b/arch/arm/mach-imx/include/mach/imx-uart.h deleted file mode 100644 index d54eb1d48026..000000000000 --- a/arch/arm/mach-imx/include/mach/imx-uart.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef ASMARM_ARCH_UART_H -#define ASMARM_ARCH_UART_H - -#define IMXUART_HAVE_RTSCTS (1<<0) - -struct imxuart_platform_data { - int (*init)(struct platform_device *pdev); - void (*exit)(struct platform_device *pdev); - unsigned int flags; -}; - -#endif diff --git a/arch/arm/mach-imx/include/mach/irqs.h b/arch/arm/mach-imx/include/mach/irqs.h deleted file mode 100644 index 67812c5ac1f9..000000000000 --- a/arch/arm/mach-imx/include/mach/irqs.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * arch/arm/mach-imxads/include/mach/irqs.h - * - * Copyright (C) 1999 ARM Limited - * Copyright (C) 2000 Deep Blue Solutions Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __ARM_IRQS_H__ -#define __ARM_IRQS_H__ - -/* Use the imx definitions */ -#include - -/* - * IMX Interrupt numbers - * - */ -#define INT_SOFTINT 0 -#define CSI_INT 6 -#define DSPA_MAC_INT 7 -#define DSPA_INT 8 -#define COMP_INT 9 -#define MSHC_XINT 10 -#define GPIO_INT_PORTA 11 -#define GPIO_INT_PORTB 12 -#define GPIO_INT_PORTC 13 -#define LCDC_INT 14 -#define SIM_INT 15 -#define SIM_DATA_INT 16 -#define RTC_INT 17 -#define RTC_SAMINT 18 -#define UART2_MINT_PFERR 19 -#define UART2_MINT_RTS 20 -#define UART2_MINT_DTR 21 -#define UART2_MINT_UARTC 22 -#define UART2_MINT_TX 23 -#define UART2_MINT_RX 24 -#define UART1_MINT_PFERR 25 -#define UART1_MINT_RTS 26 -#define UART1_MINT_DTR 27 -#define UART1_MINT_UARTC 28 -#define UART1_MINT_TX 29 -#define UART1_MINT_RX 30 -#define VOICE_DAC_INT 31 -#define VOICE_ADC_INT 32 -#define PEN_DATA_INT 33 -#define PWM_INT 34 -#define SDHC_INT 35 -#define I2C_INT 39 -#define CSPI_INT 41 -#define SSI_TX_INT 42 -#define SSI_TX_ERR_INT 43 -#define SSI_RX_INT 44 -#define SSI_RX_ERR_INT 45 -#define TOUCH_INT 46 -#define USBD_INT0 47 -#define USBD_INT1 48 -#define USBD_INT2 49 -#define USBD_INT3 50 -#define USBD_INT4 51 -#define USBD_INT5 52 -#define USBD_INT6 53 -#define BTSYS_INT 55 -#define BTTIM_INT 56 -#define BTWUI_INT 57 -#define TIM2_INT 58 -#define TIM1_INT 59 -#define DMA_ERR 60 -#define DMA_INT 61 -#define GPIO_INT_PORTD 62 - -#define IMX_IRQS (64) - -/* note: the IMX has four gpio ports (A-D), but only - * the following pins are connected to the outside - * world: - * - * PORT A: bits 0-31 - * PORT B: bits 8-31 - * PORT C: bits 3-17 - * PORT D: bits 6-31 - * - * We map these interrupts straight on. As a result we have - * several holes in the interrupt mapping. We do this for two - * reasons: - * - mapping the interrupts without holes would get - * far more complicated - * - Motorola could well decide to bring some processor - * with more pins connected - */ - -#define IRQ_GPIOA(x) (IMX_IRQS + x) -#define IRQ_GPIOB(x) (IRQ_GPIOA(32) + x) -#define IRQ_GPIOC(x) (IRQ_GPIOB(32) + x) -#define IRQ_GPIOD(x) (IRQ_GPIOC(32) + x) - -/* decode irq number to use with IMR(x), ISR(x) and friends */ -#define IRQ_TO_REG(irq) ((irq - IMX_IRQS) >> 5) - -/* all normal IRQs can be FIQs */ -#define FIQ_START 0 -/* switch betwean IRQ and FIQ */ -extern int imx_set_irq_fiq(unsigned int irq, unsigned int type); - -#define NR_IRQS (IRQ_GPIOD(32) + 1) -#define IRQ_GPIO(x) -#endif diff --git a/arch/arm/mach-imx/include/mach/mmc.h b/arch/arm/mach-imx/include/mach/mmc.h deleted file mode 100644 index 4712f354dcca..000000000000 --- a/arch/arm/mach-imx/include/mach/mmc.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef ASMARM_ARCH_MMC_H -#define ASMARM_ARCH_MMC_H - -#include - -struct device; - -struct imxmmc_platform_data { - int (*card_present)(struct device *); - int (*get_ro)(struct device *); -}; - -extern void imx_set_mmc_info(struct imxmmc_platform_data *info); - -#endif diff --git a/arch/arm/mach-imx/include/mach/mx1ads.h b/arch/arm/mach-imx/include/mach/mx1ads.h deleted file mode 100644 index def05d510eb3..000000000000 --- a/arch/arm/mach-imx/include/mach/mx1ads.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * arch/arm/mach-imx/include/mach/mx1ads.h - * - * Copyright (C) 2004 Robert Schwebel, Pengutronix - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#ifndef __ASM_ARCH_MX1ADS_H -#define __ASM_ARCH_MX1ADS_H - -/* ------------------------------------------------------------------------ */ -/* Memory Map for the M9328MX1ADS (MX1ADS) Board */ -/* ------------------------------------------------------------------------ */ - -#define MX1ADS_FLASH_PHYS 0x10000000 -#define MX1ADS_FLASH_SIZE (16*1024*1024) - -#define IMX_FB_PHYS (0x0C000000 - 0x40000) - -#define CLK32 32000 - -#endif /* __ASM_ARCH_MX1ADS_H */ diff --git a/arch/arm/mach-imx/include/mach/spi_imx.h b/arch/arm/mach-imx/include/mach/spi_imx.h deleted file mode 100644 index 4186430feecf..000000000000 --- a/arch/arm/mach-imx/include/mach/spi_imx.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * arch/arm/mach-imx/include/mach/spi_imx.h - * - * Copyright (C) 2006 SWAPP - * Andrea Paterniani - * - * Initial version inspired by: - * linux-2.6.17-rc3-mm1/arch/arm/mach-pxa/include/mach/pxa2xx_spi.h - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef SPI_IMX_H_ -#define SPI_IMX_H_ - - -/*-------------------------------------------------------------------------*/ -/** - * struct spi_imx_master - device.platform_data for SPI controller devices. - * @num_chipselect: chipselects are used to distinguish individual - * SPI slaves, and are numbered from zero to num_chipselects - 1. - * each slave has a chipselect signal, but it's common that not - * every chipselect is connected to a slave. - * @enable_dma: if true enables DMA driven transfers. -*/ -struct spi_imx_master { - u8 num_chipselect; - u8 enable_dma:1; -}; -/*-------------------------------------------------------------------------*/ - - -/*-------------------------------------------------------------------------*/ -/** - * struct spi_imx_chip - spi_board_info.controller_data for SPI - * slave devices, copied to spi_device.controller_data. - * @enable_loopback : used for test purpouse to internally connect RX and TX - * sections. - * @enable_dma : enables dma transfer (provided that controller driver has - * dma enabled too). - * @ins_ss_pulse : enable /SS pulse insertion between SPI burst. - * @bclk_wait : number of bclk waits between each bits_per_word SPI burst. - * @cs_control : function pointer to board-specific function to assert/deassert - * I/O port to control HW generation of devices chip-select. -*/ -struct spi_imx_chip { - u8 enable_loopback:1; - u8 enable_dma:1; - u8 ins_ss_pulse:1; - u16 bclk_wait:15; - void (*cs_control)(u32 control); -}; - -/* Chip-select state */ -#define SPI_CS_ASSERT (1 << 0) -#define SPI_CS_DEASSERT (1 << 1) -/*-------------------------------------------------------------------------*/ - - -#endif /* SPI_IMX_H_*/ diff --git a/arch/arm/mach-imx/include/mach/uncompress.h b/arch/arm/mach-imx/include/mach/uncompress.h deleted file mode 100644 index 70523e67a8f6..000000000000 --- a/arch/arm/mach-imx/include/mach/uncompress.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * arch/arm/mach-imxads/include/mach/uncompress.h - * - * - * - * Copyright (C) 1999 ARM Limited - * Copyright (C) Shane Nay (shane@minirl.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#define UART(x) (*(volatile unsigned long *)(serial_port + (x))) - -#define UART1_BASE 0x206000 -#define UART2_BASE 0x207000 -#define USR2 0x98 -#define USR2_TXFE (1<<14) -#define TXR 0x40 -#define UCR1 0x80 -#define UCR1_UARTEN 1 - -/* - * The following code assumes the serial port has already been - * initialized by the bootloader. We search for the first enabled - * port in the most probable order. If you didn't setup a port in - * your bootloader then nothing will appear (which might be desired). - * - * This does not append a newline - */ -static void putc(int c) -{ - unsigned long serial_port; - - do { - serial_port = UART1_BASE; - if ( UART(UCR1) & UCR1_UARTEN ) - break; - serial_port = UART2_BASE; - if ( UART(UCR1) & UCR1_UARTEN ) - break; - return; - } while(0); - - while (!(UART(USR2) & USR2_TXFE)) - barrier(); - - UART(TXR) = c; -} - -static inline void flush(void) -{ -} - -/* - * nothing to do - */ -#define arch_decomp_setup() - -#define arch_decomp_wdog() diff --git a/arch/arm/mach-imx/irq.c b/arch/arm/mach-imx/irq.c deleted file mode 100644 index 531b95deadc0..000000000000 --- a/arch/arm/mach-imx/irq.c +++ /dev/null @@ -1,311 +0,0 @@ -/* - * linux/arch/arm/mach-imx/irq.c - * - * Copyright (C) 1999 ARM Limited - * Copyright (C) 2002 Shane Nay (shane@minirl.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * 03/03/2004 Sascha Hauer - * Copied from the motorola bsp package and added gpio demux - * interrupt handler - */ - -#include -#include -#include -#include - -#include -#include - -#include - -/* - * - * We simply use the ENABLE DISABLE registers inside of the IMX - * to turn on/off specific interrupts. - * - */ - -#define INTCNTL_OFF 0x00 -#define NIMASK_OFF 0x04 -#define INTENNUM_OFF 0x08 -#define INTDISNUM_OFF 0x0C -#define INTENABLEH_OFF 0x10 -#define INTENABLEL_OFF 0x14 -#define INTTYPEH_OFF 0x18 -#define INTTYPEL_OFF 0x1C -#define NIPRIORITY_OFF(x) (0x20+4*(7-(x))) -#define NIVECSR_OFF 0x40 -#define FIVECSR_OFF 0x44 -#define INTSRCH_OFF 0x48 -#define INTSRCL_OFF 0x4C -#define INTFRCH_OFF 0x50 -#define INTFRCL_OFF 0x54 -#define NIPNDH_OFF 0x58 -#define NIPNDL_OFF 0x5C -#define FIPNDH_OFF 0x60 -#define FIPNDL_OFF 0x64 - -#define VA_AITC_BASE IO_ADDRESS(IMX_AITC_BASE) -#define IMX_AITC_INTCNTL (VA_AITC_BASE + INTCNTL_OFF) -#define IMX_AITC_NIMASK (VA_AITC_BASE + NIMASK_OFF) -#define IMX_AITC_INTENNUM (VA_AITC_BASE + INTENNUM_OFF) -#define IMX_AITC_INTDISNUM (VA_AITC_BASE + INTDISNUM_OFF) -#define IMX_AITC_INTENABLEH (VA_AITC_BASE + INTENABLEH_OFF) -#define IMX_AITC_INTENABLEL (VA_AITC_BASE + INTENABLEL_OFF) -#define IMX_AITC_INTTYPEH (VA_AITC_BASE + INTTYPEH_OFF) -#define IMX_AITC_INTTYPEL (VA_AITC_BASE + INTTYPEL_OFF) -#define IMX_AITC_NIPRIORITY(x) (VA_AITC_BASE + NIPRIORITY_OFF(x)) -#define IMX_AITC_NIVECSR (VA_AITC_BASE + NIVECSR_OFF) -#define IMX_AITC_FIVECSR (VA_AITC_BASE + FIVECSR_OFF) -#define IMX_AITC_INTSRCH (VA_AITC_BASE + INTSRCH_OFF) -#define IMX_AITC_INTSRCL (VA_AITC_BASE + INTSRCL_OFF) -#define IMX_AITC_INTFRCH (VA_AITC_BASE + INTFRCH_OFF) -#define IMX_AITC_INTFRCL (VA_AITC_BASE + INTFRCL_OFF) -#define IMX_AITC_NIPNDH (VA_AITC_BASE + NIPNDH_OFF) -#define IMX_AITC_NIPNDL (VA_AITC_BASE + NIPNDL_OFF) -#define IMX_AITC_FIPNDH (VA_AITC_BASE + FIPNDH_OFF) -#define IMX_AITC_FIPNDL (VA_AITC_BASE + FIPNDL_OFF) - -#if 0 -#define DEBUG_IRQ(fmt...) printk(fmt) -#else -#define DEBUG_IRQ(fmt...) do { } while (0) -#endif - -static void -imx_mask_irq(unsigned int irq) -{ - __raw_writel(irq, IMX_AITC_INTDISNUM); -} - -static void -imx_unmask_irq(unsigned int irq) -{ - __raw_writel(irq, IMX_AITC_INTENNUM); -} - -#ifdef CONFIG_FIQ -int imx_set_irq_fiq(unsigned int irq, unsigned int type) -{ - unsigned int irqt; - - if (irq >= IMX_IRQS) - return -EINVAL; - - if (irq < IMX_IRQS / 2) { - irqt = __raw_readl(IMX_AITC_INTTYPEL) & ~(1 << irq); - __raw_writel(irqt | (!!type << irq), IMX_AITC_INTTYPEL); - } else { - irq -= IMX_IRQS / 2; - irqt = __raw_readl(IMX_AITC_INTTYPEH) & ~(1 << irq); - __raw_writel(irqt | (!!type << irq), IMX_AITC_INTTYPEH); - } - - return 0; -} -EXPORT_SYMBOL(imx_set_irq_fiq); -#endif /* CONFIG_FIQ */ - -static int -imx_gpio_irq_type(unsigned int _irq, unsigned int type) -{ - unsigned int irq_type = 0, irq, reg, bit; - - irq = _irq - IRQ_GPIOA(0); - reg = irq >> 5; - bit = 1 << (irq % 32); - - if (type == IRQ_TYPE_PROBE) { - /* Don't mess with enabled GPIOs using preconfigured edges or - GPIOs set to alternate function during probe */ - /* TODO: support probe */ -// if ((GPIO_IRQ_rising_edge[idx] | GPIO_IRQ_falling_edge[idx]) & -// GPIO_bit(gpio)) -// return 0; -// if (GAFR(gpio) & (0x3 << (((gpio) & 0xf)*2))) -// return 0; -// type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; - } - - GIUS(reg) |= bit; - DDIR(reg) &= ~(bit); - - DEBUG_IRQ("setting type of irq %d to ", _irq); - - if (type & IRQ_TYPE_EDGE_RISING) { - DEBUG_IRQ("rising edges\n"); - irq_type = 0x0; - } - if (type & IRQ_TYPE_EDGE_FALLING) { - DEBUG_IRQ("falling edges\n"); - irq_type = 0x1; - } - if (type & IRQ_TYPE_LEVEL_LOW) { - DEBUG_IRQ("low level\n"); - irq_type = 0x3; - } - if (type & IRQ_TYPE_LEVEL_HIGH) { - DEBUG_IRQ("high level\n"); - irq_type = 0x2; - } - - if (irq % 32 < 16) { - ICR1(reg) = (ICR1(reg) & ~(0x3 << ((irq % 16) * 2))) | - (irq_type << ((irq % 16) * 2)); - } else { - ICR2(reg) = (ICR2(reg) & ~(0x3 << ((irq % 16) * 2))) | - (irq_type << ((irq % 16) * 2)); - } - - return 0; - -} - -static void -imx_gpio_ack_irq(unsigned int irq) -{ - DEBUG_IRQ("%s: irq %d\n", __func__, irq); - ISR(IRQ_TO_REG(irq)) = 1 << ((irq - IRQ_GPIOA(0)) % 32); -} - -static void -imx_gpio_mask_irq(unsigned int irq) -{ - DEBUG_IRQ("%s: irq %d\n", __func__, irq); - IMR(IRQ_TO_REG(irq)) &= ~( 1 << ((irq - IRQ_GPIOA(0)) % 32)); -} - -static void -imx_gpio_unmask_irq(unsigned int irq) -{ - DEBUG_IRQ("%s: irq %d\n", __func__, irq); - IMR(IRQ_TO_REG(irq)) |= 1 << ((irq - IRQ_GPIOA(0)) % 32); -} - -static void -imx_gpio_handler(unsigned int mask, unsigned int irq, - struct irq_desc *desc) -{ - while (mask) { - if (mask & 1) { - DEBUG_IRQ("handling irq %d\n", irq); - generic_handle_irq(irq); - } - irq++; - mask >>= 1; - } -} - -static void -imx_gpioa_demux_handler(unsigned int irq_unused, struct irq_desc *desc) -{ - unsigned int mask, irq; - - mask = ISR(0); - irq = IRQ_GPIOA(0); - imx_gpio_handler(mask, irq, desc); -} - -static void -imx_gpiob_demux_handler(unsigned int irq_unused, struct irq_desc *desc) -{ - unsigned int mask, irq; - - mask = ISR(1); - irq = IRQ_GPIOB(0); - imx_gpio_handler(mask, irq, desc); -} - -static void -imx_gpioc_demux_handler(unsigned int irq_unused, struct irq_desc *desc) -{ - unsigned int mask, irq; - - mask = ISR(2); - irq = IRQ_GPIOC(0); - imx_gpio_handler(mask, irq, desc); -} - -static void -imx_gpiod_demux_handler(unsigned int irq_unused, struct irq_desc *desc) -{ - unsigned int mask, irq; - - mask = ISR(3); - irq = IRQ_GPIOD(0); - imx_gpio_handler(mask, irq, desc); -} - -static struct irq_chip imx_internal_chip = { - .name = "MPU", - .ack = imx_mask_irq, - .mask = imx_mask_irq, - .unmask = imx_unmask_irq, -}; - -static struct irq_chip imx_gpio_chip = { - .name = "GPIO", - .ack = imx_gpio_ack_irq, - .mask = imx_gpio_mask_irq, - .unmask = imx_gpio_unmask_irq, - .set_type = imx_gpio_irq_type, -}; - -void __init -imx_init_irq(void) -{ - unsigned int irq; - - DEBUG_IRQ("Initializing imx interrupts\n"); - - /* Disable all interrupts initially. */ - /* Do not rely on the bootloader. */ - __raw_writel(0, IMX_AITC_INTENABLEH); - __raw_writel(0, IMX_AITC_INTENABLEL); - - /* Mask all GPIO interrupts as well */ - IMR(0) = 0; - IMR(1) = 0; - IMR(2) = 0; - IMR(3) = 0; - - for (irq = 0; irq < IMX_IRQS; irq++) { - set_irq_chip(irq, &imx_internal_chip); - set_irq_handler(irq, handle_level_irq); - set_irq_flags(irq, IRQF_VALID); - } - - for (irq = IRQ_GPIOA(0); irq < IRQ_GPIOD(32); irq++) { - set_irq_chip(irq, &imx_gpio_chip); - set_irq_handler(irq, handle_edge_irq); - set_irq_flags(irq, IRQF_VALID); - } - - set_irq_chained_handler(GPIO_INT_PORTA, imx_gpioa_demux_handler); - set_irq_chained_handler(GPIO_INT_PORTB, imx_gpiob_demux_handler); - set_irq_chained_handler(GPIO_INT_PORTC, imx_gpioc_demux_handler); - set_irq_chained_handler(GPIO_INT_PORTD, imx_gpiod_demux_handler); - - /* Release masking of interrupts according to priority */ - __raw_writel(-1, IMX_AITC_NIMASK); - -#ifdef CONFIG_FIQ - /* Initialize FIQ */ - init_FIQ(); -#endif -} diff --git a/arch/arm/mach-imx/leds-mx1ads.c b/arch/arm/mach-imx/leds-mx1ads.c deleted file mode 100644 index 1d48f2762cbc..000000000000 --- a/arch/arm/mach-imx/leds-mx1ads.c +++ /dev/null @@ -1,53 +0,0 @@ -/* - * linux/arch/arm/mach-imx/leds-mx1ads.c - * - * Copyright (c) 2004 Sascha Hauer - * - * Original (leds-footbridge.c) by Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - */ - -#include -#include -#include -#include -#include -#include -#include "leds.h" - -/* - * The MX1ADS Board has only one usable LED, - * so select only the timer led or the - * cpu usage led - */ -void -mx1ads_leds_event(led_event_t ledevt) -{ - unsigned long flags; - - local_irq_save(flags); - - switch (ledevt) { -#ifdef CONFIG_LEDS_CPU - case led_idle_start: - DR(0) &= ~(1<<2); - break; - - case led_idle_end: - DR(0) |= 1<<2; - break; -#endif - -#ifdef CONFIG_LEDS_TIMER - case led_timer: - DR(0) ^= 1<<2; -#endif - default: - break; - } - local_irq_restore(flags); -} diff --git a/arch/arm/mach-imx/leds.c b/arch/arm/mach-imx/leds.c deleted file mode 100644 index cf30803e019b..000000000000 --- a/arch/arm/mach-imx/leds.c +++ /dev/null @@ -1,31 +0,0 @@ -/* - * linux/arch/arm/mach-imx/leds.c - * - * Copyright (C) 2004 Sascha Hauer - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - */ - -#include -#include - -#include -#include - -#include "leds.h" - -static int __init -leds_init(void) -{ - if (machine_is_mx1ads()) { - leds_event = mx1ads_leds_event; - } - - return 0; -} - -__initcall(leds_init); diff --git a/arch/arm/mach-imx/leds.h b/arch/arm/mach-imx/leds.h deleted file mode 100644 index 49dc1c1da338..000000000000 --- a/arch/arm/mach-imx/leds.h +++ /dev/null @@ -1,9 +0,0 @@ -/* - * arch/arm/mach-imx/leds.h - * - * Copyright (c) 2004 Sascha Hauer - * - * blinky lights for IMX-based systems - * - */ -extern void mx1ads_leds_event(led_event_t evt); diff --git a/arch/arm/mach-imx/mx1ads.c b/arch/arm/mach-imx/mx1ads.c deleted file mode 100644 index 87fa1ff43b0b..000000000000 --- a/arch/arm/mach-imx/mx1ads.c +++ /dev/null @@ -1,180 +0,0 @@ -/* - * arch/arm/mach-imx/mx1ads.c - * - * Initially based on: - * linux-2.6.7-imx/arch/arm/mach-imx/scb9328.c - * Copyright (c) 2004 Sascha Hauer - * - * 2004 (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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include "generic.h" - -static struct resource cs89x0_resources[] = { - [0] = { - .start = IMX_CS4_PHYS + 0x300, - .end = IMX_CS4_PHYS + 0x300 + 16, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_GPIOC(17), - .end = IRQ_GPIOC(17), - .flags = IORESOURCE_IRQ, - }, -}; - -static struct platform_device cs89x0_device = { - .name = "cirrus-cs89x0", - .num_resources = ARRAY_SIZE(cs89x0_resources), - .resource = cs89x0_resources, -}; - -static struct imxuart_platform_data uart_pdata = { - .flags = IMXUART_HAVE_RTSCTS, -}; - -static struct resource imx_uart1_resources[] = { - [0] = { - .start = 0x00206000, - .end = 0x002060FF, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = (UART1_MINT_RX), - .end = (UART1_MINT_RX), - .flags = IORESOURCE_IRQ, - }, - [2] = { - .start = (UART1_MINT_TX), - .end = (UART1_MINT_TX), - .flags = IORESOURCE_IRQ, - }, - [3] = { - .start = UART1_MINT_RTS, - .end = UART1_MINT_RTS, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct platform_device imx_uart1_device = { - .name = "imx-uart", - .id = 0, - .num_resources = ARRAY_SIZE(imx_uart1_resources), - .resource = imx_uart1_resources, - .dev = { - .platform_data = &uart_pdata, - } -}; - -static struct resource imx_uart2_resources[] = { - [0] = { - .start = 0x00207000, - .end = 0x002070FF, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = (UART2_MINT_RX), - .end = (UART2_MINT_RX), - .flags = IORESOURCE_IRQ, - }, - [2] = { - .start = (UART2_MINT_TX), - .end = (UART2_MINT_TX), - .flags = IORESOURCE_IRQ, - }, - [3] = { - .start = UART2_MINT_RTS, - .end = UART2_MINT_RTS, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct platform_device imx_uart2_device = { - .name = "imx-uart", - .id = 1, - .num_resources = ARRAY_SIZE(imx_uart2_resources), - .resource = imx_uart2_resources, - .dev = { - .platform_data = &uart_pdata, - } -}; - -static struct platform_device *devices[] __initdata = { - &cs89x0_device, - &imx_uart1_device, - &imx_uart2_device, -}; - -#if defined(CONFIG_MMC_IMX) || defined(CONFIG_MMC_IMX_MODULE) -static int mx1ads_mmc_card_present(struct device *dev) -{ - /* MMC/SD Card Detect is PB 20 on MX1ADS V1.0.7 */ - return (SSR(1) & (1 << 20) ? 0 : 1); -} - -static struct imxmmc_platform_data mx1ads_mmc_info = { - .card_present = mx1ads_mmc_card_present, -}; -#endif - -static void __init -mx1ads_init(void) -{ -#ifdef CONFIG_LEDS - imx_gpio_mode(GPIO_PORTA | GPIO_OUT | 2); -#endif -#if defined(CONFIG_MMC_IMX) || defined(CONFIG_MMC_IMX_MODULE) - /* SD/MMC card detect */ - imx_gpio_mode(GPIO_PORTB | GPIO_GIUS | GPIO_IN | 20); - imx_set_mmc_info(&mx1ads_mmc_info); -#endif - - imx_gpio_mode(PC9_PF_UART1_CTS); - imx_gpio_mode(PC10_PF_UART1_RTS); - imx_gpio_mode(PC11_PF_UART1_TXD); - imx_gpio_mode(PC12_PF_UART1_RXD); - - imx_gpio_mode(PB28_PF_UART2_CTS); - imx_gpio_mode(PB29_PF_UART2_RTS); - imx_gpio_mode(PB30_PF_UART2_TXD); - imx_gpio_mode(PB31_PF_UART2_RXD); - - platform_add_devices(devices, ARRAY_SIZE(devices)); -} - -static void __init -mx1ads_map_io(void) -{ - imx_map_io(); -} - -MACHINE_START(MX1ADS, "Motorola MX1ADS") - /* Maintainer: Sascha Hauer, Pengutronix */ - .phys_io = 0x00200000, - .io_pg_offst = ((0xe0000000) >> 18) & 0xfffc, - .boot_params = 0x08000100, - .map_io = mx1ads_map_io, - .init_irq = imx_init_irq, - .timer = &imx_timer, - .init_machine = mx1ads_init, -MACHINE_END diff --git a/arch/arm/mach-imx/time.c b/arch/arm/mach-imx/time.c deleted file mode 100644 index 5aef18b599e5..000000000000 --- a/arch/arm/mach-imx/time.c +++ /dev/null @@ -1,220 +0,0 @@ -/* - * linux/arch/arm/mach-imx/time.c - * - * Copyright (C) 2000-2001 Deep Blue Solutions - * Copyright (C) 2002 Shane Nay (shane@minirl.com) - * Copyright (C) 2006-2007 Pavel Pisa (ppisa@pikron.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 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -/* Use timer 1 as system timer */ -#define TIMER_BASE IMX_TIM1_BASE - -static struct clock_event_device clockevent_imx; -static enum clock_event_mode clockevent_mode = CLOCK_EVT_MODE_UNUSED; - -/* - * IRQ handler for the timer - */ -static irqreturn_t -imx_timer_interrupt(int irq, void *dev_id) -{ - struct clock_event_device *evt = &clockevent_imx; - uint32_t tstat; - irqreturn_t ret = IRQ_NONE; - - /* clear the interrupt */ - tstat = IMX_TSTAT(TIMER_BASE); - IMX_TSTAT(TIMER_BASE) = 0; - - if (tstat & TSTAT_COMP) { - evt->event_handler(evt); - ret = IRQ_HANDLED; - } - - return ret; -} - -static struct irqaction imx_timer_irq = { - .name = "i.MX Timer Tick", - .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, - .handler = imx_timer_interrupt, -}; - -/* - * Set up timer hardware into expected mode and state. - */ -static void __init imx_timer_hardware_init(void) -{ - /* - * Initialise to a known state (all timers off, and timing reset) - */ - IMX_TCTL(TIMER_BASE) = 0; - IMX_TPRER(TIMER_BASE) = 0; - - IMX_TCTL(TIMER_BASE) = TCTL_FRR | TCTL_CLK_PCLK1 | TCTL_TEN; -} - -cycle_t imx_get_cycles(struct clocksource *cs) -{ - return IMX_TCN(TIMER_BASE); -} - -static struct clocksource clocksource_imx = { - .name = "imx_timer1", - .rating = 200, - .read = imx_get_cycles, - .mask = 0xFFFFFFFF, - .shift = 20, - .flags = CLOCK_SOURCE_IS_CONTINUOUS, -}; - -static int __init imx_clocksource_init(unsigned long rate) -{ - clocksource_imx.mult = - clocksource_hz2mult(rate, clocksource_imx.shift); - clocksource_register(&clocksource_imx); - - return 0; -} - -static int imx_set_next_event(unsigned long evt, - struct clock_event_device *unused) -{ - unsigned long tcmp; - - tcmp = IMX_TCN(TIMER_BASE) + evt; - IMX_TCMP(TIMER_BASE) = tcmp; - - return (int32_t)(tcmp - IMX_TCN(TIMER_BASE)) < 0 ? -ETIME : 0; -} - -#ifdef DEBUG -static const char *clock_event_mode_label[]={ - [CLOCK_EVT_MODE_PERIODIC] = "CLOCK_EVT_MODE_PERIODIC", - [CLOCK_EVT_MODE_ONESHOT] = "CLOCK_EVT_MODE_ONESHOT", - [CLOCK_EVT_MODE_SHUTDOWN] = "CLOCK_EVT_MODE_SHUTDOWN", - [CLOCK_EVT_MODE_UNUSED] = "CLOCK_EVT_MODE_UNUSED" -}; -#endif /*DEBUG*/ - -static void imx_set_mode(enum clock_event_mode mode, struct clock_event_device *evt) -{ - unsigned long flags; - - /* - * The timer interrupt generation is disabled at least - * for enough time to call imx_set_next_event() - */ - local_irq_save(flags); - /* Disable interrupt in GPT module */ - IMX_TCTL(TIMER_BASE) &= ~TCTL_IRQEN; - if (mode != clockevent_mode) { - /* Set event time into far-far future */ - IMX_TCMP(TIMER_BASE) = IMX_TCN(TIMER_BASE) - 3; - /* Clear pending interrupt */ - IMX_TSTAT(TIMER_BASE) &= ~TSTAT_COMP; - } - -#ifdef DEBUG - printk(KERN_INFO "imx_set_mode: changing mode from %s to %s\n", - clock_event_mode_label[clockevent_mode], clock_event_mode_label[mode]); -#endif /*DEBUG*/ - - /* Remember timer mode */ - clockevent_mode = mode; - local_irq_restore(flags); - - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - printk(KERN_ERR "imx_set_mode: Periodic mode is not supported for i.MX\n"); - break; - case CLOCK_EVT_MODE_ONESHOT: - /* - * Do not put overhead of interrupt enable/disable into - * imx_set_next_event(), the core has about 4 minutes - * to call imx_set_next_event() or shutdown clock after - * mode switching - */ - local_irq_save(flags); - IMX_TCTL(TIMER_BASE) |= TCTL_IRQEN; - local_irq_restore(flags); - break; - case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_RESUME: - /* Left event sources disabled, no more interrupts appears */ - break; - } -} - -static struct clock_event_device clockevent_imx = { - .name = "imx_timer1", - .features = CLOCK_EVT_FEAT_ONESHOT, - .shift = 32, - .set_mode = imx_set_mode, - .set_next_event = imx_set_next_event, - .rating = 200, -}; - -static int __init imx_clockevent_init(unsigned long rate) -{ - clockevent_imx.mult = div_sc(rate, NSEC_PER_SEC, - clockevent_imx.shift); - clockevent_imx.max_delta_ns = - clockevent_delta2ns(0xfffffffe, &clockevent_imx); - clockevent_imx.min_delta_ns = - clockevent_delta2ns(0xf, &clockevent_imx); - - clockevent_imx.cpumask = cpumask_of(0); - - clockevents_register_device(&clockevent_imx); - - return 0; -} - -extern int imx_clocks_init(void); - -static void __init imx_timer_init(void) -{ - struct clk *clk; - unsigned long rate; - - imx_clocks_init(); - - clk = clk_get(NULL, "perclk1"); - clk_enable(clk); - rate = clk_get_rate(clk); - - imx_timer_hardware_init(); - imx_clocksource_init(rate); - - imx_clockevent_init(rate); - - /* - * Make irqs happen for the system timer - */ - setup_irq(TIM1_INT, &imx_timer_irq); -} - -struct sys_timer imx_timer = { - .init = imx_timer_init, -}; diff --git a/arch/arm/mach-ixp4xx/Kconfig b/arch/arm/mach-ixp4xx/Kconfig index 2c5a02b8520e..264f4d59f898 100644 --- a/arch/arm/mach-ixp4xx/Kconfig +++ b/arch/arm/mach-ixp4xx/Kconfig @@ -78,6 +78,12 @@ config MACH_IXDP465 IXDP465 Development Platform (Also known as BMP). For more information on this platform, see . +config MACH_GORAMO_MLR + bool "GORAMO Multi Link Router" + help + Say 'Y' here if you want your kernel to support GORAMO + MultiLink router. + config MACH_KIXRP435 bool "KIXRP435" help diff --git a/arch/arm/mach-ixp4xx/Makefile b/arch/arm/mach-ixp4xx/Makefile index 2e6bbf927a74..47d1f60d23fa 100644 --- a/arch/arm/mach-ixp4xx/Makefile +++ b/arch/arm/mach-ixp4xx/Makefile @@ -30,6 +30,7 @@ obj-$(CONFIG_MACH_DSMG600) += dsmg600-setup.o obj-$(CONFIG_MACH_GATEWAY7001) += gateway7001-setup.o obj-$(CONFIG_MACH_WG302V2) += wg302v2-setup.o obj-$(CONFIG_MACH_FSG) += fsg-setup.o +obj-$(CONFIG_MACH_GORAMO_MLR) += goramo_mlr.o obj-$(CONFIG_PCI) += $(obj-pci-$(CONFIG_PCI)) common-pci.o obj-$(CONFIG_IXP4XX_QMGR) += ixp4xx_qmgr.o diff --git a/arch/arm/mach-ixp4xx/goramo_mlr.c b/arch/arm/mach-ixp4xx/goramo_mlr.c new file mode 100644 index 000000000000..a733b8ff3cec --- /dev/null +++ b/arch/arm/mach-ixp4xx/goramo_mlr.c @@ -0,0 +1,507 @@ +/* + * Goramo MultiLink router platform code + * Copyright (C) 2006-2009 Krzysztof Halasa + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define xgpio_irq(n) (IRQ_IXP4XX_GPIO ## n) +#define gpio_irq(n) xgpio_irq(n) + +#define SLOT_ETHA 0x0B /* IDSEL = AD21 */ +#define SLOT_ETHB 0x0C /* IDSEL = AD20 */ +#define SLOT_MPCI 0x0D /* IDSEL = AD19 */ +#define SLOT_NEC 0x0E /* IDSEL = AD18 */ + +#define IRQ_ETHA IRQ_IXP4XX_GPIO4 +#define IRQ_ETHB IRQ_IXP4XX_GPIO5 +#define IRQ_NEC IRQ_IXP4XX_GPIO3 +#define IRQ_MPCI IRQ_IXP4XX_GPIO12 + +/* GPIO lines */ +#define GPIO_SCL 0 +#define GPIO_SDA 1 +#define GPIO_STR 2 +#define GPIO_HSS0_DCD_N 6 +#define GPIO_HSS1_DCD_N 7 +#define GPIO_HSS0_CTS_N 10 +#define GPIO_HSS1_CTS_N 11 +#define GPIO_HSS1_RTS_N 13 +#define GPIO_HSS0_RTS_N 14 + +/* Control outputs from 74HC4094 */ +#define CONTROL_HSS0_CLK_INT 0 +#define CONTROL_HSS1_CLK_INT 1 +#define CONTROL_HSS0_DTR_N 2 +#define CONTROL_HSS1_DTR_N 3 +#define CONTROL_EXT 4 +#define CONTROL_AUTO_RESET 5 +#define CONTROL_PCI_RESET_N 6 +#define CONTROL_EEPROM_WC_N 7 + +/* offsets from start of flash ROM = 0x50000000 */ +#define CFG_ETH0_ADDRESS 0x40 /* 6 bytes */ +#define CFG_ETH1_ADDRESS 0x46 /* 6 bytes */ +#define CFG_REV 0x4C /* u32 */ +#define CFG_SDRAM_SIZE 0x50 /* u32 */ +#define CFG_SDRAM_CONF 0x54 /* u32 */ +#define CFG_SDRAM_MODE 0x58 /* u32 */ +#define CFG_SDRAM_REFRESH 0x5C /* u32 */ + +#define CFG_HW_BITS 0x60 /* u32 */ +#define CFG_HW_USB_PORTS 0x00000007 /* 0 = no NEC chip, 1-5 = ports # */ +#define CFG_HW_HAS_PCI_SLOT 0x00000008 +#define CFG_HW_HAS_ETH0 0x00000010 +#define CFG_HW_HAS_ETH1 0x00000020 +#define CFG_HW_HAS_HSS0 0x00000040 +#define CFG_HW_HAS_HSS1 0x00000080 +#define CFG_HW_HAS_UART0 0x00000100 +#define CFG_HW_HAS_UART1 0x00000200 +#define CFG_HW_HAS_EEPROM 0x00000400 + +#define FLASH_CMD_READ_ARRAY 0xFF +#define FLASH_CMD_READ_ID 0x90 +#define FLASH_SER_OFF 0x102 /* 0x81 in 16-bit mode */ + +static u32 hw_bits = 0xFFFFFFFD; /* assume all hardware present */; +static u8 control_value; + +static void set_scl(u8 value) +{ + gpio_line_set(GPIO_SCL, !!value); + udelay(3); +} + +static void set_sda(u8 value) +{ + gpio_line_set(GPIO_SDA, !!value); + udelay(3); +} + +static void set_str(u8 value) +{ + gpio_line_set(GPIO_STR, !!value); + udelay(3); +} + +static inline void set_control(int line, int value) +{ + if (value) + control_value |= (1 << line); + else + control_value &= ~(1 << line); +} + + +static void output_control(void) +{ + int i; + + gpio_line_config(GPIO_SCL, IXP4XX_GPIO_OUT); + gpio_line_config(GPIO_SDA, IXP4XX_GPIO_OUT); + + for (i = 0; i < 8; i++) { + set_scl(0); + set_sda(control_value & (0x80 >> i)); /* MSB first */ + set_scl(1); /* active edge */ + } + + set_str(1); + set_str(0); + + set_scl(0); + set_sda(1); /* Be ready for START */ + set_scl(1); +} + + +static void (*set_carrier_cb_tab[2])(void *pdev, int carrier); + +static int hss_set_clock(int port, unsigned int clock_type) +{ + int ctrl_int = port ? CONTROL_HSS1_CLK_INT : CONTROL_HSS0_CLK_INT; + + switch (clock_type) { + case CLOCK_DEFAULT: + case CLOCK_EXT: + set_control(ctrl_int, 0); + output_control(); + return CLOCK_EXT; + + case CLOCK_INT: + set_control(ctrl_int, 1); + output_control(); + return CLOCK_INT; + + default: + return -EINVAL; + } +} + +static irqreturn_t hss_dcd_irq(int irq, void *pdev) +{ + int i, port = (irq == gpio_irq(GPIO_HSS1_DCD_N)); + gpio_line_get(port ? GPIO_HSS1_DCD_N : GPIO_HSS0_DCD_N, &i); + set_carrier_cb_tab[port](pdev, !i); + return IRQ_HANDLED; +} + + +static int hss_open(int port, void *pdev, + void (*set_carrier_cb)(void *pdev, int carrier)) +{ + int i, irq; + + if (!port) + irq = gpio_irq(GPIO_HSS0_DCD_N); + else + irq = gpio_irq(GPIO_HSS1_DCD_N); + + gpio_line_get(port ? GPIO_HSS1_DCD_N : GPIO_HSS0_DCD_N, &i); + set_carrier_cb(pdev, !i); + + set_carrier_cb_tab[!!port] = set_carrier_cb; + + if ((i = request_irq(irq, hss_dcd_irq, 0, "IXP4xx HSS", pdev)) != 0) { + printk(KERN_ERR "ixp4xx_hss: failed to request IRQ%i (%i)\n", + irq, i); + return i; + } + + set_control(port ? CONTROL_HSS1_DTR_N : CONTROL_HSS0_DTR_N, 0); + output_control(); + gpio_line_set(port ? GPIO_HSS1_RTS_N : GPIO_HSS0_RTS_N, 0); + return 0; +} + +static void hss_close(int port, void *pdev) +{ + free_irq(port ? gpio_irq(GPIO_HSS1_DCD_N) : gpio_irq(GPIO_HSS0_DCD_N), + pdev); + set_carrier_cb_tab[!!port] = NULL; /* catch bugs */ + + set_control(port ? CONTROL_HSS1_DTR_N : CONTROL_HSS0_DTR_N, 1); + output_control(); + gpio_line_set(port ? GPIO_HSS1_RTS_N : GPIO_HSS0_RTS_N, 1); +} + + +/* Flash memory */ +static struct flash_platform_data flash_data = { + .map_name = "cfi_probe", + .width = 2, +}; + +static struct resource flash_resource = { + .flags = IORESOURCE_MEM, +}; + +static struct platform_device device_flash = { + .name = "IXP4XX-Flash", + .id = 0, + .dev = { .platform_data = &flash_data }, + .num_resources = 1, + .resource = &flash_resource, +}; + + +/* I^2C interface */ +static struct i2c_gpio_platform_data i2c_data = { + .sda_pin = GPIO_SDA, + .scl_pin = GPIO_SCL, +}; + +static struct platform_device device_i2c = { + .name = "i2c-gpio", + .id = 0, + .dev = { .platform_data = &i2c_data }, +}; + + +/* IXP425 2 UART ports */ +static struct resource uart_resources[] = { + { + .start = IXP4XX_UART1_BASE_PHYS, + .end = IXP4XX_UART1_BASE_PHYS + 0x0fff, + .flags = IORESOURCE_MEM, + }, + { + .start = IXP4XX_UART2_BASE_PHYS, + .end = IXP4XX_UART2_BASE_PHYS + 0x0fff, + .flags = IORESOURCE_MEM, + } +}; + +static struct plat_serial8250_port uart_data[] = { + { + .mapbase = IXP4XX_UART1_BASE_PHYS, + .membase = (char __iomem *)IXP4XX_UART1_BASE_VIRT + + REG_OFFSET, + .irq = IRQ_IXP4XX_UART1, + .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, + .iotype = UPIO_MEM, + .regshift = 2, + .uartclk = IXP4XX_UART_XTAL, + }, + { + .mapbase = IXP4XX_UART2_BASE_PHYS, + .membase = (char __iomem *)IXP4XX_UART2_BASE_VIRT + + REG_OFFSET, + .irq = IRQ_IXP4XX_UART2, + .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, + .iotype = UPIO_MEM, + .regshift = 2, + .uartclk = IXP4XX_UART_XTAL, + }, + { }, +}; + +static struct platform_device device_uarts = { + .name = "serial8250", + .id = PLAT8250_DEV_PLATFORM, + .dev.platform_data = uart_data, + .num_resources = 2, + .resource = uart_resources, +}; + + +/* Built-in 10/100 Ethernet MAC interfaces */ +static struct eth_plat_info eth_plat[] = { + { + .phy = 0, + .rxq = 3, + .txreadyq = 32, + }, { + .phy = 1, + .rxq = 4, + .txreadyq = 33, + } +}; + +static struct platform_device device_eth_tab[] = { + { + .name = "ixp4xx_eth", + .id = IXP4XX_ETH_NPEB, + .dev.platform_data = eth_plat, + }, { + .name = "ixp4xx_eth", + .id = IXP4XX_ETH_NPEC, + .dev.platform_data = eth_plat + 1, + } +}; + + +/* IXP425 2 synchronous serial ports */ +static struct hss_plat_info hss_plat[] = { + { + .set_clock = hss_set_clock, + .open = hss_open, + .close = hss_close, + .txreadyq = 34, + }, { + .set_clock = hss_set_clock, + .open = hss_open, + .close = hss_close, + .txreadyq = 35, + } +}; + +static struct platform_device device_hss_tab[] = { + { + .name = "ixp4xx_hss", + .id = 0, + .dev.platform_data = hss_plat, + }, { + .name = "ixp4xx_hss", + .id = 1, + .dev.platform_data = hss_plat + 1, + } +}; + + +static struct platform_device *device_tab[6] __initdata = { + &device_flash, /* index 0 */ +}; + +static inline u8 __init flash_readb(u8 __iomem *flash, u32 addr) +{ +#ifdef __ARMEB__ + return __raw_readb(flash + addr); +#else + return __raw_readb(flash + (addr ^ 3)); +#endif +} + +static inline u16 __init flash_readw(u8 __iomem *flash, u32 addr) +{ +#ifdef __ARMEB__ + return __raw_readw(flash + addr); +#else + return __raw_readw(flash + (addr ^ 2)); +#endif +} + +static void __init gmlr_init(void) +{ + u8 __iomem *flash; + int i, devices = 1; /* flash */ + + ixp4xx_sys_init(); + + if ((flash = ioremap(IXP4XX_EXP_BUS_BASE_PHYS, 0x80)) == NULL) + printk(KERN_ERR "goramo-mlr: unable to access system" + " configuration data\n"); + else { + system_rev = __raw_readl(flash + CFG_REV); + hw_bits = __raw_readl(flash + CFG_HW_BITS); + + for (i = 0; i < ETH_ALEN; i++) { + eth_plat[0].hwaddr[i] = + flash_readb(flash, CFG_ETH0_ADDRESS + i); + eth_plat[1].hwaddr[i] = + flash_readb(flash, CFG_ETH1_ADDRESS + i); + } + + __raw_writew(FLASH_CMD_READ_ID, flash); + system_serial_high = flash_readw(flash, FLASH_SER_OFF); + system_serial_high <<= 16; + system_serial_high |= flash_readw(flash, FLASH_SER_OFF + 2); + system_serial_low = flash_readw(flash, FLASH_SER_OFF + 4); + system_serial_low <<= 16; + system_serial_low |= flash_readw(flash, FLASH_SER_OFF + 6); + __raw_writew(FLASH_CMD_READ_ARRAY, flash); + + iounmap(flash); + } + + switch (hw_bits & (CFG_HW_HAS_UART0 | CFG_HW_HAS_UART1)) { + case CFG_HW_HAS_UART0: + memset(&uart_data[1], 0, sizeof(uart_data[1])); + device_uarts.num_resources = 1; + break; + + case CFG_HW_HAS_UART1: + device_uarts.dev.platform_data = &uart_data[1]; + device_uarts.resource = &uart_resources[1]; + device_uarts.num_resources = 1; + break; + } + if (hw_bits & (CFG_HW_HAS_UART0 | CFG_HW_HAS_UART1)) + device_tab[devices++] = &device_uarts; /* max index 1 */ + + if (hw_bits & CFG_HW_HAS_ETH0) + device_tab[devices++] = &device_eth_tab[0]; /* max index 2 */ + if (hw_bits & CFG_HW_HAS_ETH1) + device_tab[devices++] = &device_eth_tab[1]; /* max index 3 */ + + if (hw_bits & CFG_HW_HAS_HSS0) + device_tab[devices++] = &device_hss_tab[0]; /* max index 4 */ + if (hw_bits & CFG_HW_HAS_HSS1) + device_tab[devices++] = &device_hss_tab[1]; /* max index 5 */ + + if (hw_bits & CFG_HW_HAS_EEPROM) + device_tab[devices++] = &device_i2c; /* max index 6 */ + + gpio_line_config(GPIO_SCL, IXP4XX_GPIO_OUT); + gpio_line_config(GPIO_SDA, IXP4XX_GPIO_OUT); + gpio_line_config(GPIO_STR, IXP4XX_GPIO_OUT); + gpio_line_config(GPIO_HSS0_RTS_N, IXP4XX_GPIO_OUT); + gpio_line_config(GPIO_HSS1_RTS_N, IXP4XX_GPIO_OUT); + gpio_line_config(GPIO_HSS0_DCD_N, IXP4XX_GPIO_IN); + gpio_line_config(GPIO_HSS1_DCD_N, IXP4XX_GPIO_IN); + set_irq_type(gpio_irq(GPIO_HSS0_DCD_N), IRQ_TYPE_EDGE_BOTH); + set_irq_type(gpio_irq(GPIO_HSS1_DCD_N), IRQ_TYPE_EDGE_BOTH); + + set_control(CONTROL_HSS0_DTR_N, 1); + set_control(CONTROL_HSS1_DTR_N, 1); + set_control(CONTROL_EEPROM_WC_N, 1); + set_control(CONTROL_PCI_RESET_N, 1); + output_control(); + + msleep(1); /* Wait for PCI devices to initialize */ + + flash_resource.start = IXP4XX_EXP_BUS_BASE(0); + flash_resource.end = IXP4XX_EXP_BUS_BASE(0) + ixp4xx_exp_bus_size - 1; + + platform_add_devices(device_tab, devices); +} + + +#ifdef CONFIG_PCI +static void __init gmlr_pci_preinit(void) +{ + set_irq_type(IRQ_ETHA, IRQ_TYPE_LEVEL_LOW); + set_irq_type(IRQ_ETHB, IRQ_TYPE_LEVEL_LOW); + set_irq_type(IRQ_NEC, IRQ_TYPE_LEVEL_LOW); + set_irq_type(IRQ_MPCI, IRQ_TYPE_LEVEL_LOW); + ixp4xx_pci_preinit(); +} + +static void __init gmlr_pci_postinit(void) +{ + if ((hw_bits & CFG_HW_USB_PORTS) >= 2 && + (hw_bits & CFG_HW_USB_PORTS) < 5) { + /* need to adjust number of USB ports on NEC chip */ + u32 value, addr = BIT(32 - SLOT_NEC) | 0xE0; + if (!ixp4xx_pci_read(addr, NP_CMD_CONFIGREAD, &value)) { + value &= ~7; + value |= (hw_bits & CFG_HW_USB_PORTS); + ixp4xx_pci_write(addr, NP_CMD_CONFIGWRITE, value); + } + } +} + +static int __init gmlr_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + switch(slot) { + case SLOT_ETHA: return IRQ_ETHA; + case SLOT_ETHB: return IRQ_ETHB; + case SLOT_NEC: return IRQ_NEC; + default: return IRQ_MPCI; + } +} + +static struct hw_pci gmlr_hw_pci __initdata = { + .nr_controllers = 1, + .preinit = gmlr_pci_preinit, + .postinit = gmlr_pci_postinit, + .swizzle = pci_std_swizzle, + .setup = ixp4xx_setup, + .scan = ixp4xx_scan_bus, + .map_irq = gmlr_map_irq, +}; + +static int __init gmlr_pci_init(void) +{ + if (machine_is_goramo_mlr() && + (hw_bits & (CFG_HW_USB_PORTS | CFG_HW_HAS_PCI_SLOT))) + pci_common_init(&gmlr_hw_pci); + return 0; +} + +subsys_initcall(gmlr_pci_init); +#endif /* CONFIG_PCI */ + + +MACHINE_START(GORAMO_MLR, "MultiLink") + /* Maintainer: Krzysztof Halasa */ + .phys_io = IXP4XX_PERIPHERAL_BASE_PHYS, + .io_pg_offst = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xFFFC, + .map_io = ixp4xx_map_io, + .init_irq = ixp4xx_init_irq, + .timer = &ixp4xx_timer, + .boot_params = 0x0100, + .init_machine = gmlr_init, +MACHINE_END diff --git a/arch/arm/mach-ixp4xx/include/mach/cpu.h b/arch/arm/mach-ixp4xx/include/mach/cpu.h index def7773be67c..b2ef65db0e91 100644 --- a/arch/arm/mach-ixp4xx/include/mach/cpu.h +++ b/arch/arm/mach-ixp4xx/include/mach/cpu.h @@ -26,6 +26,8 @@ #define IXP46X_PROCESSOR_ID_VALUE 0x69054200 /* including IXP455 */ #define IXP46X_PROCESSOR_ID_MASK 0xfffffff0 +#define cpu_is_ixp42x_rev_a0() ((read_cpuid_id() & (IXP42X_PROCESSOR_ID_MASK | 0xF)) == \ + IXP42X_PROCESSOR_ID_VALUE) #define cpu_is_ixp42x() ((read_cpuid_id() & IXP42X_PROCESSOR_ID_MASK) == \ IXP42X_PROCESSOR_ID_VALUE) #define cpu_is_ixp43x() ((read_cpuid_id() & IXP43X_PROCESSOR_ID_MASK) == \ @@ -35,8 +37,11 @@ static inline u32 ixp4xx_read_feature_bits(void) { - unsigned int val = ~*IXP4XX_EXP_CFG2; + u32 val = ~*IXP4XX_EXP_CFG2; + if (cpu_is_ixp42x_rev_a0()) + return IXP42X_FEATURE_MASK & ~(IXP4XX_FEATURE_RCOMP | + IXP4XX_FEATURE_AES); if (cpu_is_ixp42x()) return val & IXP42X_FEATURE_MASK; if (cpu_is_ixp43x()) diff --git a/arch/arm/mach-ixp4xx/include/mach/qmgr.h b/arch/arm/mach-ixp4xx/include/mach/qmgr.h index 0cbe6ceb67c5..9e7cad2d54cb 100644 --- a/arch/arm/mach-ixp4xx/include/mach/qmgr.h +++ b/arch/arm/mach-ixp4xx/include/mach/qmgr.h @@ -15,7 +15,7 @@ #define DEBUG_QMGR 0 #define HALF_QUEUES 32 -#define QUEUES 64 /* only 32 lower queues currently supported */ +#define QUEUES 64 #define MAX_QUEUE_LENGTH 4 /* in dwords */ #define QUEUE_STAT1_EMPTY 1 /* queue status bits */ @@ -110,48 +110,95 @@ static inline u32 qmgr_get_entry(unsigned int queue) return val; } -static inline int qmgr_get_stat1(unsigned int queue) +static inline int __qmgr_get_stat1(unsigned int queue) { extern struct qmgr_regs __iomem *qmgr_regs; return (__raw_readl(&qmgr_regs->stat1[queue >> 3]) >> ((queue & 7) << 2)) & 0xF; } -static inline int qmgr_get_stat2(unsigned int queue) +static inline int __qmgr_get_stat2(unsigned int queue) { extern struct qmgr_regs __iomem *qmgr_regs; + BUG_ON(queue >= HALF_QUEUES); return (__raw_readl(&qmgr_regs->stat2[queue >> 4]) >> ((queue & 0xF) << 1)) & 0x3; } +/** + * qmgr_stat_empty() - checks if a hardware queue is empty + * @queue: queue number + * + * Returns non-zero value if the queue is empty. + */ static inline int qmgr_stat_empty(unsigned int queue) { - return !!(qmgr_get_stat1(queue) & QUEUE_STAT1_EMPTY); + BUG_ON(queue >= HALF_QUEUES); + return __qmgr_get_stat1(queue) & QUEUE_STAT1_EMPTY; } -static inline int qmgr_stat_nearly_empty(unsigned int queue) +/** + * qmgr_stat_below_low_watermark() - checks if a queue is below low watermark + * @queue: queue number + * + * Returns non-zero value if the queue is below low watermark. + */ +static inline int qmgr_stat_below_low_watermark(unsigned int queue) { - return !!(qmgr_get_stat1(queue) & QUEUE_STAT1_NEARLY_EMPTY); + extern struct qmgr_regs __iomem *qmgr_regs; + if (queue >= HALF_QUEUES) + return (__raw_readl(&qmgr_regs->statne_h) >> + (queue - HALF_QUEUES)) & 0x01; + return __qmgr_get_stat1(queue) & QUEUE_STAT1_NEARLY_EMPTY; } -static inline int qmgr_stat_nearly_full(unsigned int queue) +/** + * qmgr_stat_above_high_watermark() - checks if a queue is above high watermark + * @queue: queue number + * + * Returns non-zero value if the queue is above high watermark + */ +static inline int qmgr_stat_above_high_watermark(unsigned int queue) { - return !!(qmgr_get_stat1(queue) & QUEUE_STAT1_NEARLY_FULL); + BUG_ON(queue >= HALF_QUEUES); + return __qmgr_get_stat1(queue) & QUEUE_STAT1_NEARLY_FULL; } +/** + * qmgr_stat_full() - checks if a hardware queue is full + * @queue: queue number + * + * Returns non-zero value if the queue is full. + */ static inline int qmgr_stat_full(unsigned int queue) { - return !!(qmgr_get_stat1(queue) & QUEUE_STAT1_FULL); + extern struct qmgr_regs __iomem *qmgr_regs; + if (queue >= HALF_QUEUES) + return (__raw_readl(&qmgr_regs->statf_h) >> + (queue - HALF_QUEUES)) & 0x01; + return __qmgr_get_stat1(queue) & QUEUE_STAT1_FULL; } +/** + * qmgr_stat_underflow() - checks if a hardware queue experienced underflow + * @queue: queue number + * + * Returns non-zero value if the queue experienced underflow. + */ static inline int qmgr_stat_underflow(unsigned int queue) { - return !!(qmgr_get_stat2(queue) & QUEUE_STAT2_UNDERFLOW); + return __qmgr_get_stat2(queue) & QUEUE_STAT2_UNDERFLOW; } +/** + * qmgr_stat_overflow() - checks if a hardware queue experienced overflow + * @queue: queue number + * + * Returns non-zero value if the queue experienced overflow. + */ static inline int qmgr_stat_overflow(unsigned int queue) { - return !!(qmgr_get_stat2(queue) & QUEUE_STAT2_OVERFLOW); + return __qmgr_get_stat2(queue) & QUEUE_STAT2_OVERFLOW; } #endif diff --git a/arch/arm/mach-ixp4xx/ixp4xx_npe.c b/arch/arm/mach-ixp4xx/ixp4xx_npe.c index 7bb8e778e4b6..47ac69c7ec78 100644 --- a/arch/arm/mach-ixp4xx/ixp4xx_npe.c +++ b/arch/arm/mach-ixp4xx/ixp4xx_npe.c @@ -386,15 +386,6 @@ static int npe_reset(struct npe *npe) /* reset the NPE */ ixp4xx_write_feature_bits(val & ~(IXP4XX_FEATURE_RESET_NPEA << npe->id)); - for (i = 0; i < MAX_RETRIES; i++) { - if (!(ixp4xx_read_feature_bits() & - (IXP4XX_FEATURE_RESET_NPEA << npe->id))) - break; /* reset completed */ - udelay(1); - } - if (i == MAX_RETRIES) - return -ETIMEDOUT; - /* deassert reset */ ixp4xx_write_feature_bits(val | (IXP4XX_FEATURE_RESET_NPEA << npe->id)); diff --git a/arch/arm/mach-ixp4xx/ixp4xx_qmgr.c b/arch/arm/mach-ixp4xx/ixp4xx_qmgr.c index bfddc73d0a20..bfdbe4b5a3cc 100644 --- a/arch/arm/mach-ixp4xx/ixp4xx_qmgr.c +++ b/arch/arm/mach-ixp4xx/ixp4xx_qmgr.c @@ -18,8 +18,8 @@ struct qmgr_regs __iomem *qmgr_regs; static struct resource *mem_res; static spinlock_t qmgr_lock; static u32 used_sram_bitmap[4]; /* 128 16-dword pages */ -static void (*irq_handlers[HALF_QUEUES])(void *pdev); -static void *irq_pdevs[HALF_QUEUES]; +static void (*irq_handlers[QUEUES])(void *pdev); +static void *irq_pdevs[QUEUES]; #if DEBUG_QMGR char qmgr_queue_descs[QUEUES][32]; @@ -28,51 +28,112 @@ char qmgr_queue_descs[QUEUES][32]; void qmgr_set_irq(unsigned int queue, int src, void (*handler)(void *pdev), void *pdev) { - u32 __iomem *reg = &qmgr_regs->irqsrc[queue / 8]; /* 8 queues / u32 */ - int bit = (queue % 8) * 4; /* 3 bits + 1 reserved bit per queue */ unsigned long flags; - src &= 7; spin_lock_irqsave(&qmgr_lock, flags); - __raw_writel((__raw_readl(reg) & ~(7 << bit)) | (src << bit), reg); + if (queue < HALF_QUEUES) { + u32 __iomem *reg; + int bit; + BUG_ON(src > QUEUE_IRQ_SRC_NOT_FULL); + reg = &qmgr_regs->irqsrc[queue >> 3]; /* 8 queues per u32 */ + bit = (queue % 8) * 4; /* 3 bits + 1 reserved bit per queue */ + __raw_writel((__raw_readl(reg) & ~(7 << bit)) | (src << bit), + reg); + } else + /* IRQ source for queues 32-63 is fixed */ + BUG_ON(src != QUEUE_IRQ_SRC_NOT_NEARLY_EMPTY); + irq_handlers[queue] = handler; irq_pdevs[queue] = pdev; spin_unlock_irqrestore(&qmgr_lock, flags); } -static irqreturn_t qmgr_irq1(int irq, void *pdev) +static irqreturn_t qmgr_irq1_a0(int irq, void *pdev) { - int i; - u32 val = __raw_readl(&qmgr_regs->irqstat[0]); - __raw_writel(val, &qmgr_regs->irqstat[0]); /* ACK */ + int i, ret = 0; + u32 en_bitmap, src, stat; - for (i = 0; i < HALF_QUEUES; i++) - if (val & (1 << i)) + /* ACK - it may clear any bits so don't rely on it */ + __raw_writel(0xFFFFFFFF, &qmgr_regs->irqstat[0]); + + en_bitmap = qmgr_regs->irqen[0]; + while (en_bitmap) { + i = __fls(en_bitmap); /* number of the last "low" queue */ + en_bitmap &= ~BIT(i); + src = qmgr_regs->irqsrc[i >> 3]; + stat = qmgr_regs->stat1[i >> 3]; + if (src & 4) /* the IRQ condition is inverted */ + stat = ~stat; + if (stat & BIT(src & 3)) { irq_handlers[i](irq_pdevs[i]); + ret = IRQ_HANDLED; + } + } + return ret; +} - return val ? IRQ_HANDLED : 0; + +static irqreturn_t qmgr_irq2_a0(int irq, void *pdev) +{ + int i, ret = 0; + u32 req_bitmap; + + /* ACK - it may clear any bits so don't rely on it */ + __raw_writel(0xFFFFFFFF, &qmgr_regs->irqstat[1]); + + req_bitmap = qmgr_regs->irqen[1] & qmgr_regs->statne_h; + while (req_bitmap) { + i = __fls(req_bitmap); /* number of the last "high" queue */ + req_bitmap &= ~BIT(i); + irq_handlers[HALF_QUEUES + i](irq_pdevs[HALF_QUEUES + i]); + ret = IRQ_HANDLED; + } + return ret; +} + + +static irqreturn_t qmgr_irq(int irq, void *pdev) +{ + int i, half = (irq == IRQ_IXP4XX_QM1 ? 0 : 1); + u32 req_bitmap = __raw_readl(&qmgr_regs->irqstat[half]); + + if (!req_bitmap) + return 0; + __raw_writel(req_bitmap, &qmgr_regs->irqstat[half]); /* ACK */ + + while (req_bitmap) { + i = __fls(req_bitmap); /* number of the last queue */ + req_bitmap &= ~BIT(i); + i += half * HALF_QUEUES; + irq_handlers[i](irq_pdevs[i]); + } + return IRQ_HANDLED; } void qmgr_enable_irq(unsigned int queue) { unsigned long flags; + int half = queue / 32; + u32 mask = 1 << (queue & (HALF_QUEUES - 1)); spin_lock_irqsave(&qmgr_lock, flags); - __raw_writel(__raw_readl(&qmgr_regs->irqen[0]) | (1 << queue), - &qmgr_regs->irqen[0]); + __raw_writel(__raw_readl(&qmgr_regs->irqen[half]) | mask, + &qmgr_regs->irqen[half]); spin_unlock_irqrestore(&qmgr_lock, flags); } void qmgr_disable_irq(unsigned int queue) { unsigned long flags; + int half = queue / 32; + u32 mask = 1 << (queue & (HALF_QUEUES - 1)); spin_lock_irqsave(&qmgr_lock, flags); - __raw_writel(__raw_readl(&qmgr_regs->irqen[0]) & ~(1 << queue), - &qmgr_regs->irqen[0]); - __raw_writel(1 << queue, &qmgr_regs->irqstat[0]); /* clear */ + __raw_writel(__raw_readl(&qmgr_regs->irqen[half]) & ~mask, + &qmgr_regs->irqen[half]); + __raw_writel(mask, &qmgr_regs->irqstat[half]); /* clear */ spin_unlock_irqrestore(&qmgr_lock, flags); } @@ -98,8 +159,7 @@ int __qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */, u32 cfg, addr = 0, mask[4]; /* in 16-dwords */ int err; - if (queue >= HALF_QUEUES) - return -ERANGE; + BUG_ON(queue >= QUEUES); if ((nearly_empty_watermark | nearly_full_watermark) & ~7) return -EINVAL; @@ -180,7 +240,7 @@ void qmgr_release_queue(unsigned int queue) { u32 cfg, addr, mask[4]; - BUG_ON(queue >= HALF_QUEUES); /* not in valid range */ + BUG_ON(queue >= QUEUES); /* not in valid range */ spin_lock_irq(&qmgr_lock); cfg = __raw_readl(&qmgr_regs->sram[queue]); @@ -224,6 +284,8 @@ void qmgr_release_queue(unsigned int queue) static int qmgr_init(void) { int i, err; + irq_handler_t handler1, handler2; + mem_res = request_mem_region(IXP4XX_QMGR_BASE_PHYS, IXP4XX_QMGR_REGION_SIZE, "IXP4xx Queue Manager"); @@ -247,23 +309,42 @@ static int qmgr_init(void) __raw_writel(0, &qmgr_regs->irqen[i]); } + __raw_writel(0xFFFFFFFF, &qmgr_regs->statne_h); + __raw_writel(0, &qmgr_regs->statf_h); + for (i = 0; i < QUEUES; i++) __raw_writel(0, &qmgr_regs->sram[i]); - err = request_irq(IRQ_IXP4XX_QM1, qmgr_irq1, 0, - "IXP4xx Queue Manager", NULL); + if (cpu_is_ixp42x_rev_a0()) { + handler1 = qmgr_irq1_a0; + handler2 = qmgr_irq2_a0; + } else + handler1 = handler2 = qmgr_irq; + + err = request_irq(IRQ_IXP4XX_QM1, handler1, 0, "IXP4xx Queue Manager", + NULL); if (err) { - printk(KERN_ERR "qmgr: failed to request IRQ%i\n", - IRQ_IXP4XX_QM1); + printk(KERN_ERR "qmgr: failed to request IRQ%i (%i)\n", + IRQ_IXP4XX_QM1, err); goto error_irq; } + err = request_irq(IRQ_IXP4XX_QM2, handler2, 0, "IXP4xx Queue Manager", + NULL); + if (err) { + printk(KERN_ERR "qmgr: failed to request IRQ%i (%i)\n", + IRQ_IXP4XX_QM2, err); + goto error_irq2; + } + used_sram_bitmap[0] = 0xF; /* 4 first pages reserved for config */ spin_lock_init(&qmgr_lock); printk(KERN_INFO "IXP4xx Queue Manager initialized.\n"); return 0; +error_irq2: + free_irq(IRQ_IXP4XX_QM1, NULL); error_irq: iounmap(qmgr_regs); error_map: @@ -274,7 +355,9 @@ error_map: static void qmgr_remove(void) { free_irq(IRQ_IXP4XX_QM1, NULL); + free_irq(IRQ_IXP4XX_QM2, NULL); synchronize_irq(IRQ_IXP4XX_QM1); + synchronize_irq(IRQ_IXP4XX_QM2); iounmap(qmgr_regs); release_mem_region(IXP4XX_QMGR_BASE_PHYS, IXP4XX_QMGR_REGION_SIZE); } diff --git a/arch/arm/mach-kirkwood/Kconfig b/arch/arm/mach-kirkwood/Kconfig index b5421cccd7e1..25100f7acf4c 100644 --- a/arch/arm/mach-kirkwood/Kconfig +++ b/arch/arm/mach-kirkwood/Kconfig @@ -20,6 +20,12 @@ config MACH_RD88F6281 Say 'Y' here if you want your kernel to support the Marvell RD-88F6281 Reference Board. +config MACH_MV88F6281GTW_GE + bool "Marvell 88F6281 GTW GE Board" + help + Say 'Y' here if you want your kernel to support the + Marvell 88F6281 GTW GE Board. + config MACH_SHEEVAPLUG bool "Marvell SheevaPlug Reference Board" help diff --git a/arch/arm/mach-kirkwood/Makefile b/arch/arm/mach-kirkwood/Makefile index 8f03c9b9bdd9..9dd680e964d6 100644 --- a/arch/arm/mach-kirkwood/Makefile +++ b/arch/arm/mach-kirkwood/Makefile @@ -3,5 +3,8 @@ obj-y += common.o addr-map.o irq.o pcie.o mpp.o obj-$(CONFIG_MACH_DB88F6281_BP) += db88f6281-bp-setup.o obj-$(CONFIG_MACH_RD88F6192_NAS) += rd88f6192-nas-setup.o obj-$(CONFIG_MACH_RD88F6281) += rd88f6281-setup.o +obj-$(CONFIG_MACH_MV88F6281GTW_GE) += mv88f6281gtw_ge-setup.o obj-$(CONFIG_MACH_SHEEVAPLUG) += sheevaplug-setup.o obj-$(CONFIG_MACH_TS219) += ts219-setup.o + +obj-$(CONFIG_CPU_IDLE) += cpuidle.o diff --git a/arch/arm/mach-kirkwood/addr-map.c b/arch/arm/mach-kirkwood/addr-map.c index 5db4f0bbe5ee..1da5d1c18ecb 100644 --- a/arch/arm/mach-kirkwood/addr-map.c +++ b/arch/arm/mach-kirkwood/addr-map.c @@ -20,6 +20,7 @@ */ #define TARGET_DDR 0 #define TARGET_DEV_BUS 1 +#define TARGET_SRAM 3 #define TARGET_PCIE 4 #define ATTR_DEV_SPI_ROM 0x1e #define ATTR_DEV_BOOT 0x1d @@ -30,6 +31,7 @@ #define ATTR_DEV_CS0 0x3e #define ATTR_PCIE_IO 0xe0 #define ATTR_PCIE_MEM 0xe8 +#define ATTR_SRAM 0x01 /* * Helpers to get DDR bank info @@ -48,7 +50,6 @@ struct mbus_dram_target_info kirkwood_mbus_dram_info; -static int __initdata win_alloc_count; static int __init cpu_win_can_remap(int win) { @@ -112,7 +113,11 @@ void __init kirkwood_setup_cpu_mbus(void) setup_cpu_win(2, KIRKWOOD_NAND_MEM_PHYS_BASE, KIRKWOOD_NAND_MEM_SIZE, TARGET_DEV_BUS, ATTR_DEV_NAND, -1); - win_alloc_count = 3; + /* + * Setup window for SRAM. + */ + setup_cpu_win(3, KIRKWOOD_SRAM_PHYS_BASE, KIRKWOOD_SRAM_SIZE, + TARGET_SRAM, ATTR_SRAM, -1); /* * Setup MBUS dram target info. @@ -140,8 +145,3 @@ void __init kirkwood_setup_cpu_mbus(void) } kirkwood_mbus_dram_info.num_cs = cs; } - -void __init kirkwood_setup_sram_win(u32 base, u32 size) -{ - setup_cpu_win(win_alloc_count++, base, size, 0x03, 0x00, -1); -} diff --git a/arch/arm/mach-kirkwood/common.c b/arch/arm/mach-kirkwood/common.c index be1ca28fed3f..0f6919838011 100644 --- a/arch/arm/mach-kirkwood/common.c +++ b/arch/arm/mach-kirkwood/common.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -29,6 +30,7 @@ #include #include #include +#include #include #include "common.h" @@ -54,6 +56,13 @@ void __init kirkwood_map_io(void) iotable_init(kirkwood_io_desc, ARRAY_SIZE(kirkwood_io_desc)); } +/* + * Default clock control bits. Any bit _not_ set in this variable + * will be cleared from the hardware after platform devices have been + * registered. Some reserved bits must be set to 1. + */ +unsigned int kirkwood_clk_ctrl = CGC_DUNIT | CGC_RESERVED; + /***************************************************************************** * EHCI @@ -95,6 +104,7 @@ static struct platform_device kirkwood_ehci = { void __init kirkwood_ehci_init(void) { + kirkwood_clk_ctrl |= CGC_USB0; platform_device_register(&kirkwood_ehci); } @@ -151,6 +161,7 @@ static struct platform_device kirkwood_ge00 = { void __init kirkwood_ge00_init(struct mv643xx_eth_platform_data *eth_data) { + kirkwood_clk_ctrl |= CGC_GE0; eth_data->shared = &kirkwood_ge00_shared; kirkwood_ge00.dev.platform_data = eth_data; @@ -212,6 +223,7 @@ static struct platform_device kirkwood_ge01 = { void __init kirkwood_ge01_init(struct mv643xx_eth_platform_data *eth_data) { + kirkwood_clk_ctrl |= CGC_GE1; eth_data->shared = &kirkwood_ge01_shared; kirkwood_ge01.dev.platform_data = eth_data; @@ -257,6 +269,43 @@ void __init kirkwood_ge00_switch_init(struct dsa_platform_data *d, int irq) } +/***************************************************************************** + * NAND flash + ****************************************************************************/ +static struct resource kirkwood_nand_resource = { + .flags = IORESOURCE_MEM, + .start = KIRKWOOD_NAND_MEM_PHYS_BASE, + .end = KIRKWOOD_NAND_MEM_PHYS_BASE + + KIRKWOOD_NAND_MEM_SIZE - 1, +}; + +static struct orion_nand_data kirkwood_nand_data = { + .cle = 0, + .ale = 1, + .width = 8, +}; + +static struct platform_device kirkwood_nand_flash = { + .name = "orion_nand", + .id = -1, + .dev = { + .platform_data = &kirkwood_nand_data, + }, + .resource = &kirkwood_nand_resource, + .num_resources = 1, +}; + +void __init kirkwood_nand_init(struct mtd_partition *parts, int nr_parts, + int chip_delay) +{ + kirkwood_clk_ctrl |= CGC_RUNIT; + kirkwood_nand_data.parts = parts; + kirkwood_nand_data.nr_parts = nr_parts; + kirkwood_nand_data.chip_delay = chip_delay; + platform_device_register(&kirkwood_nand_flash); +} + + /***************************************************************************** * SoC RTC ****************************************************************************/ @@ -301,6 +350,9 @@ static struct platform_device kirkwood_sata = { void __init kirkwood_sata_init(struct mv_sata_platform_data *sata_data) { + kirkwood_clk_ctrl |= CGC_SATA0; + if (sata_data->n_ports > 1) + kirkwood_clk_ctrl |= CGC_SATA1; sata_data->dram = &kirkwood_mbus_dram_info; kirkwood_sata.dev.platform_data = sata_data; platform_device_register(&kirkwood_sata); @@ -346,6 +398,7 @@ void __init kirkwood_sdio_init(struct mvsdio_platform_data *mvsdio_data) else mvsdio_data->clock = 200000000; mvsdio_data->dram = &kirkwood_mbus_dram_info; + kirkwood_clk_ctrl |= CGC_SDIO; kirkwood_sdio.dev.platform_data = mvsdio_data; platform_device_register(&kirkwood_sdio); } @@ -377,6 +430,7 @@ static struct platform_device kirkwood_spi = { void __init kirkwood_spi_init() { + kirkwood_clk_ctrl |= CGC_RUNIT; platform_device_register(&kirkwood_spi); } @@ -506,6 +560,43 @@ void __init kirkwood_uart1_init(void) } +/***************************************************************************** + * Cryptographic Engines and Security Accelerator (CESA) + ****************************************************************************/ + +static struct resource kirkwood_crypto_res[] = { + { + .name = "regs", + .start = CRYPTO_PHYS_BASE, + .end = CRYPTO_PHYS_BASE + 0xffff, + .flags = IORESOURCE_MEM, + }, { + .name = "sram", + .start = KIRKWOOD_SRAM_PHYS_BASE, + .end = KIRKWOOD_SRAM_PHYS_BASE + KIRKWOOD_SRAM_SIZE - 1, + .flags = IORESOURCE_MEM, + }, { + .name = "crypto interrupt", + .start = IRQ_KIRKWOOD_CRYPTO, + .end = IRQ_KIRKWOOD_CRYPTO, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device kirkwood_crypto_device = { + .name = "mv_crypto", + .id = -1, + .num_resources = ARRAY_SIZE(kirkwood_crypto_res), + .resource = kirkwood_crypto_res, +}; + +void __init kirkwood_crypto_init(void) +{ + kirkwood_clk_ctrl |= CGC_CRYPTO; + platform_device_register(&kirkwood_crypto_device); +} + + /***************************************************************************** * XOR ****************************************************************************/ @@ -597,6 +688,7 @@ static struct platform_device kirkwood_xor01_channel = { static void __init kirkwood_xor0_init(void) { + kirkwood_clk_ctrl |= CGC_XOR0; platform_device_register(&kirkwood_xor0_shared); /* @@ -695,6 +787,7 @@ static struct platform_device kirkwood_xor11_channel = { static void __init kirkwood_xor1_init(void) { + kirkwood_clk_ctrl |= CGC_XOR1; platform_device_register(&kirkwood_xor1_shared); /* @@ -712,6 +805,29 @@ static void __init kirkwood_xor1_init(void) } +/***************************************************************************** + * Watchdog + ****************************************************************************/ +static struct orion_wdt_platform_data kirkwood_wdt_data = { + .tclk = 0, +}; + +static struct platform_device kirkwood_wdt_device = { + .name = "orion_wdt", + .id = -1, + .dev = { + .platform_data = &kirkwood_wdt_data, + }, + .num_resources = 0, +}; + +static void __init kirkwood_wdt_init(void) +{ + kirkwood_wdt_data.tclk = kirkwood_tclk; + platform_device_register(&kirkwood_wdt_device); +} + + /***************************************************************************** * Time handling ****************************************************************************/ @@ -804,6 +920,49 @@ void __init kirkwood_init(void) /* internal devices that every board has */ kirkwood_rtc_init(); + kirkwood_wdt_init(); kirkwood_xor0_init(); kirkwood_xor1_init(); + kirkwood_crypto_init(); } + +static int __init kirkwood_clock_gate(void) +{ + unsigned int curr = readl(CLOCK_GATING_CTRL); + + printk(KERN_DEBUG "Gating clock of unused units\n"); + printk(KERN_DEBUG "before: 0x%08x\n", curr); + + /* Make sure those units are accessible */ + writel(curr | CGC_SATA0 | CGC_SATA1 | CGC_PEX0, CLOCK_GATING_CTRL); + + /* For SATA: first shutdown the phy */ + if (!(kirkwood_clk_ctrl & CGC_SATA0)) { + /* Disable PLL and IVREF */ + writel(readl(SATA0_PHY_MODE_2) & ~0xf, SATA0_PHY_MODE_2); + /* Disable PHY */ + writel(readl(SATA0_IF_CTRL) | 0x200, SATA0_IF_CTRL); + } + if (!(kirkwood_clk_ctrl & CGC_SATA1)) { + /* Disable PLL and IVREF */ + writel(readl(SATA1_PHY_MODE_2) & ~0xf, SATA1_PHY_MODE_2); + /* Disable PHY */ + writel(readl(SATA1_IF_CTRL) | 0x200, SATA1_IF_CTRL); + } + + /* For PCIe: first shutdown the phy */ + if (!(kirkwood_clk_ctrl & CGC_PEX0)) { + writel(readl(PCIE_LINK_CTRL) | 0x10, PCIE_LINK_CTRL); + while (1) + if (readl(PCIE_STATUS) & 0x1) + break; + writel(readl(PCIE_LINK_CTRL) & ~0x10, PCIE_LINK_CTRL); + } + + /* Now gate clock the required units */ + writel(kirkwood_clk_ctrl, CLOCK_GATING_CTRL); + printk(KERN_DEBUG " after: 0x%08x\n", readl(CLOCK_GATING_CTRL)); + + return 0; +} +late_initcall(kirkwood_clock_gate); diff --git a/arch/arm/mach-kirkwood/common.h b/arch/arm/mach-kirkwood/common.h index 6ee88406f381..d7de43464358 100644 --- a/arch/arm/mach-kirkwood/common.h +++ b/arch/arm/mach-kirkwood/common.h @@ -15,6 +15,7 @@ struct dsa_platform_data; struct mv643xx_eth_platform_data; struct mv_sata_platform_data; struct mvsdio_platform_data; +struct mtd_partition; /* * Basic Kirkwood init functions used early by machine-setup. @@ -25,7 +26,6 @@ void kirkwood_init_irq(void); extern struct mbus_dram_target_info kirkwood_mbus_dram_info; void kirkwood_setup_cpu_mbus(void); -void kirkwood_setup_sram_win(u32 base, u32 size); void kirkwood_pcie_id(u32 *dev, u32 *rev); @@ -40,9 +40,11 @@ void kirkwood_spi_init(void); void kirkwood_i2c_init(void); void kirkwood_uart0_init(void); void kirkwood_uart1_init(void); +void kirkwood_nand_init(struct mtd_partition *parts, int nr_parts, int delay); extern int kirkwood_tclk; extern struct sys_timer kirkwood_timer; +#define ARRAY_AND_SIZE(x) (x), ARRAY_SIZE(x) #endif diff --git a/arch/arm/mach-kirkwood/cpuidle.c b/arch/arm/mach-kirkwood/cpuidle.c new file mode 100644 index 000000000000..f68d33f1f396 --- /dev/null +++ b/arch/arm/mach-kirkwood/cpuidle.c @@ -0,0 +1,96 @@ +/* + * arch/arm/mach-kirkwood/cpuidle.c + * + * CPU idle Marvell Kirkwood SoCs + * + * 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. + * + * The cpu idle uses wait-for-interrupt and DDR self refresh in order + * to implement two idle states - + * #1 wait-for-interrupt + * #2 wait-for-interrupt and DDR self refresh + */ + +#include +#include +#include +#include +#include +#include +#include + +#define KIRKWOOD_MAX_STATES 2 + +static struct cpuidle_driver kirkwood_idle_driver = { + .name = "kirkwood_idle", + .owner = THIS_MODULE, +}; + +static DEFINE_PER_CPU(struct cpuidle_device, kirkwood_cpuidle_device); + +/* Actual code that puts the SoC in different idle states */ +static int kirkwood_enter_idle(struct cpuidle_device *dev, + struct cpuidle_state *state) +{ + struct timeval before, after; + int idle_time; + + local_irq_disable(); + do_gettimeofday(&before); + if (state == &dev->states[0]) + /* Wait for interrupt state */ + cpu_do_idle(); + else if (state == &dev->states[1]) { + /* + * Following write will put DDR in self refresh. + * Note that we have 256 cycles before DDR puts it + * self in self-refresh, so the wait-for-interrupt + * call afterwards won't get the DDR from self refresh + * mode. + */ + writel(0x7, DDR_OPERATION_BASE); + cpu_do_idle(); + } + do_gettimeofday(&after); + local_irq_enable(); + idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC + + (after.tv_usec - before.tv_usec); + return idle_time; +} + +/* Initialize CPU idle by registering the idle states */ +static int kirkwood_init_cpuidle(void) +{ + struct cpuidle_device *device; + + cpuidle_register_driver(&kirkwood_idle_driver); + + device = &per_cpu(kirkwood_cpuidle_device, smp_processor_id()); + device->state_count = KIRKWOOD_MAX_STATES; + + /* Wait for interrupt state */ + device->states[0].enter = kirkwood_enter_idle; + device->states[0].exit_latency = 1; + device->states[0].target_residency = 10000; + device->states[0].flags = CPUIDLE_FLAG_TIME_VALID; + strcpy(device->states[0].name, "WFI"); + strcpy(device->states[0].desc, "Wait for interrupt"); + + /* Wait for interrupt and DDR self refresh state */ + device->states[1].enter = kirkwood_enter_idle; + device->states[1].exit_latency = 10; + device->states[1].target_residency = 10000; + device->states[1].flags = CPUIDLE_FLAG_TIME_VALID; + strcpy(device->states[1].name, "DDR SR"); + strcpy(device->states[1].desc, "WFI and DDR Self Refresh"); + + if (cpuidle_register_device(device)) { + printk(KERN_ERR "kirkwood_init_cpuidle: Failed registering\n"); + return -EIO; + } + return 0; +} + +device_initcall(kirkwood_init_cpuidle); diff --git a/arch/arm/mach-kirkwood/db88f6281-bp-setup.c b/arch/arm/mach-kirkwood/db88f6281-bp-setup.c index 5505d5837752..39bdf4bcace9 100644 --- a/arch/arm/mach-kirkwood/db88f6281-bp-setup.c +++ b/arch/arm/mach-kirkwood/db88f6281-bp-setup.c @@ -11,14 +11,12 @@ #include #include #include -#include #include #include #include #include #include #include -#include #include #include "common.h" #include "mpp.h" @@ -39,32 +37,6 @@ static struct mtd_partition db88f6281_nand_parts[] = { }, }; -static struct resource db88f6281_nand_resource = { - .flags = IORESOURCE_MEM, - .start = KIRKWOOD_NAND_MEM_PHYS_BASE, - .end = KIRKWOOD_NAND_MEM_PHYS_BASE + - KIRKWOOD_NAND_MEM_SIZE - 1, -}; - -static struct orion_nand_data db88f6281_nand_data = { - .parts = db88f6281_nand_parts, - .nr_parts = ARRAY_SIZE(db88f6281_nand_parts), - .cle = 0, - .ale = 1, - .width = 8, - .chip_delay = 25, -}; - -static struct platform_device db88f6281_nand_flash = { - .name = "orion_nand", - .id = -1, - .dev = { - .platform_data = &db88f6281_nand_data, - }, - .resource = &db88f6281_nand_resource, - .num_resources = 1, -}; - static struct mv643xx_eth_platform_data db88f6281_ge00_data = { .phy_addr = MV643XX_ETH_PHY_ADDR(8), }; @@ -92,13 +64,12 @@ static void __init db88f6281_init(void) kirkwood_init(); kirkwood_mpp_conf(db88f6281_mpp_config); + kirkwood_nand_init(ARRAY_AND_SIZE(db88f6281_nand_parts), 25); kirkwood_ehci_init(); kirkwood_ge00_init(&db88f6281_ge00_data); kirkwood_sata_init(&db88f6281_sata_data); kirkwood_uart0_init(); kirkwood_sdio_init(&db88f6281_mvsdio_data); - - platform_device_register(&db88f6281_nand_flash); } static int __init db88f6281_pci_init(void) diff --git a/arch/arm/mach-kirkwood/include/mach/bridge-regs.h b/arch/arm/mach-kirkwood/include/mach/bridge-regs.h index 4f7029f521cc..9e80d9232c83 100644 --- a/arch/arm/mach-kirkwood/include/mach/bridge-regs.h +++ b/arch/arm/mach-kirkwood/include/mach/bridge-regs.h @@ -17,12 +17,15 @@ #define CPU_RESET 0x00000002 #define RSTOUTn_MASK (BRIDGE_VIRT_BASE | 0x0108) +#define WDT_RESET_OUT_EN 0x00000002 #define SOFT_RESET_OUT_EN 0x00000004 #define SYSTEM_SOFT_RESET (BRIDGE_VIRT_BASE | 0x010c) #define SOFT_RESET 0x00000001 #define BRIDGE_CAUSE (BRIDGE_VIRT_BASE | 0x0110) +#define WDT_INT_REQ 0x0008 + #define BRIDGE_MASK (BRIDGE_VIRT_BASE | 0x0114) #define BRIDGE_INT_TIMER0 0x0002 #define BRIDGE_INT_TIMER1 0x0004 @@ -39,4 +42,22 @@ #define L2_CONFIG_REG (BRIDGE_VIRT_BASE | 0x0128) #define L2_WRITETHROUGH 0x00000010 +#define CLOCK_GATING_CTRL (BRIDGE_VIRT_BASE | 0x11c) +#define CGC_GE0 (1 << 0) +#define CGC_PEX0 (1 << 2) +#define CGC_USB0 (1 << 3) +#define CGC_SDIO (1 << 4) +#define CGC_TSU (1 << 5) +#define CGC_DUNIT (1 << 6) +#define CGC_RUNIT (1 << 7) +#define CGC_XOR0 (1 << 8) +#define CGC_AUDIO (1 << 9) +#define CGC_SATA0 (1 << 14) +#define CGC_SATA1 (1 << 15) +#define CGC_XOR1 (1 << 16) +#define CGC_CRYPTO (1 << 17) +#define CGC_GE1 (1 << 19) +#define CGC_TDM (1 << 20) +#define CGC_RESERVED ((1 << 18) | (0x6 << 21)) + #endif diff --git a/arch/arm/mach-kirkwood/include/mach/io.h b/arch/arm/mach-kirkwood/include/mach/io.h index be07be0ef522..a643a846d5fb 100644 --- a/arch/arm/mach-kirkwood/include/mach/io.h +++ b/arch/arm/mach-kirkwood/include/mach/io.h @@ -19,6 +19,31 @@ static inline void __iomem *__io(unsigned long addr) + KIRKWOOD_PCIE_IO_VIRT_BASE); } +static inline void __iomem * +__arch_ioremap(unsigned long paddr, size_t size, unsigned int mtype) +{ + void __iomem *retval; + unsigned long offs = paddr - KIRKWOOD_REGS_PHYS_BASE; + if (mtype == MT_DEVICE && size && offs < KIRKWOOD_REGS_SIZE && + size <= KIRKWOOD_REGS_SIZE && offs + size <= KIRKWOOD_REGS_SIZE) { + retval = (void __iomem *)KIRKWOOD_REGS_VIRT_BASE + offs; + } else { + retval = __arm_ioremap(paddr, size, mtype); + } + + return retval; +} + +static inline void +__arch_iounmap(void __iomem *addr) +{ + if (addr < (void __iomem *)KIRKWOOD_REGS_VIRT_BASE || + addr >= (void __iomem *)(KIRKWOOD_REGS_VIRT_BASE + KIRKWOOD_REGS_SIZE)) + __iounmap(addr); +} + +#define __arch_ioremap(p, s, m) __arch_ioremap(p, s, m) +#define __arch_iounmap(a) __arch_iounmap(a) #define __io(a) __io(a) #define __mem_pci(a) (a) diff --git a/arch/arm/mach-kirkwood/include/mach/kirkwood.h b/arch/arm/mach-kirkwood/include/mach/kirkwood.h index b3e13958821d..07af858814a0 100644 --- a/arch/arm/mach-kirkwood/include/mach/kirkwood.h +++ b/arch/arm/mach-kirkwood/include/mach/kirkwood.h @@ -20,16 +20,18 @@ * f1000000 on-chip peripheral registers * f2000000 PCIe I/O space * f3000000 NAND controller address window + * f4000000 Security Accelerator SRAM * * virt phys size * fee00000 f1000000 1M on-chip peripheral registers * fef00000 f2000000 1M PCIe I/O space */ +#define KIRKWOOD_SRAM_PHYS_BASE 0xf4000000 +#define KIRKWOOD_SRAM_SIZE SZ_2K + #define KIRKWOOD_NAND_MEM_PHYS_BASE 0xf3000000 -#define KIRKWOOD_NAND_MEM_SIZE SZ_64K /* 1K is sufficient, but 64K - * is the minimal window size - */ +#define KIRKWOOD_NAND_MEM_SIZE SZ_1K #define KIRKWOOD_PCIE_IO_PHYS_BASE 0xf2000000 #define KIRKWOOD_PCIE_IO_VIRT_BASE 0xfef00000 @@ -48,6 +50,7 @@ */ #define DDR_VIRT_BASE (KIRKWOOD_REGS_VIRT_BASE | 0x00000) #define DDR_WINDOW_CPU_BASE (DDR_VIRT_BASE | 0x1500) +#define DDR_OPERATION_BASE (DDR_VIRT_BASE | 0x1418) #define DEV_BUS_PHYS_BASE (KIRKWOOD_REGS_PHYS_BASE | 0x10000) #define DEV_BUS_VIRT_BASE (KIRKWOOD_REGS_VIRT_BASE | 0x10000) @@ -63,7 +66,11 @@ #define BRIDGE_VIRT_BASE (KIRKWOOD_REGS_VIRT_BASE | 0x20000) +#define CRYPTO_PHYS_BASE (KIRKWOOD_REGS_PHYS_BASE | 0x30000) + #define PCIE_VIRT_BASE (KIRKWOOD_REGS_VIRT_BASE | 0x40000) +#define PCIE_LINK_CTRL (PCIE_VIRT_BASE | 0x70) +#define PCIE_STATUS (PCIE_VIRT_BASE | 0x1a04) #define USB_PHYS_BASE (KIRKWOOD_REGS_PHYS_BASE | 0x50000) @@ -80,6 +87,11 @@ #define GE01_PHYS_BASE (KIRKWOOD_REGS_PHYS_BASE | 0x74000) #define SATA_PHYS_BASE (KIRKWOOD_REGS_PHYS_BASE | 0x80000) +#define SATA_VIRT_BASE (KIRKWOOD_REGS_VIRT_BASE | 0x80000) +#define SATA0_IF_CTRL (SATA_VIRT_BASE | 0x2050) +#define SATA0_PHY_MODE_2 (SATA_VIRT_BASE | 0x2330) +#define SATA1_IF_CTRL (SATA_VIRT_BASE | 0x4050) +#define SATA1_PHY_MODE_2 (SATA_VIRT_BASE | 0x4330) #define SDIO_PHYS_BASE (KIRKWOOD_REGS_PHYS_BASE | 0x90000) diff --git a/arch/arm/mach-kirkwood/mpp.c b/arch/arm/mach-kirkwood/mpp.c index 63c44934391a..a5900f64e38c 100644 --- a/arch/arm/mach-kirkwood/mpp.c +++ b/arch/arm/mach-kirkwood/mpp.c @@ -48,6 +48,9 @@ void __init kirkwood_mpp_conf(unsigned int *mpp_list) if (!variant_mask) return; + /* Initialize gpiolib. */ + orion_gpio_init(); + printk(KERN_DEBUG "initial MPP regs:"); for (i = 0; i < MPP_NR_REGS; i++) { mpp_ctrl[i] = readl(MPP_CTRL(i)); diff --git a/arch/arm/mach-kirkwood/mv88f6281gtw_ge-setup.c b/arch/arm/mach-kirkwood/mv88f6281gtw_ge-setup.c new file mode 100644 index 000000000000..0358f45766cb --- /dev/null +++ b/arch/arm/mach-kirkwood/mv88f6281gtw_ge-setup.c @@ -0,0 +1,173 @@ +/* + * arch/arm/mach-kirkwood/mv88f6281gtw_ge-setup.c + * + * Marvell 88F6281 GTW GE Board Setup + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "common.h" +#include "mpp.h" + +static struct mv643xx_eth_platform_data mv88f6281gtw_ge_ge00_data = { + .phy_addr = MV643XX_ETH_PHY_NONE, + .speed = SPEED_1000, + .duplex = DUPLEX_FULL, +}; + +static struct dsa_chip_data mv88f6281gtw_ge_switch_chip_data = { + .port_names[0] = "lan1", + .port_names[1] = "lan2", + .port_names[2] = "lan3", + .port_names[3] = "lan4", + .port_names[4] = "wan", + .port_names[5] = "cpu", +}; + +static struct dsa_platform_data mv88f6281gtw_ge_switch_plat_data = { + .nr_chips = 1, + .chip = &mv88f6281gtw_ge_switch_chip_data, +}; + +static const struct flash_platform_data mv88f6281gtw_ge_spi_slave_data = { + .type = "mx25l12805d", +}; + +static struct spi_board_info __initdata mv88f6281gtw_ge_spi_slave_info[] = { + { + .modalias = "m25p80", + .platform_data = &mv88f6281gtw_ge_spi_slave_data, + .irq = -1, + .max_speed_hz = 50000000, + .bus_num = 0, + .chip_select = 0, + }, +}; + +static struct gpio_keys_button mv88f6281gtw_ge_button_pins[] = { + { + .code = KEY_RESTART, + .gpio = 47, + .desc = "SWR Button", + .active_low = 1, + }, { + .code = KEY_F1, + .gpio = 46, + .desc = "WPS Button(F1)", + .active_low = 1, + }, +}; + +static struct gpio_keys_platform_data mv88f6281gtw_ge_button_data = { + .buttons = mv88f6281gtw_ge_button_pins, + .nbuttons = ARRAY_SIZE(mv88f6281gtw_ge_button_pins), +}; + +static struct platform_device mv88f6281gtw_ge_buttons = { + .name = "gpio-keys", + .id = -1, + .num_resources = 0, + .dev = { + .platform_data = &mv88f6281gtw_ge_button_data, + }, +}; + +static struct gpio_led mv88f6281gtw_ge_led_pins[] = { + { + .name = "gtw:green:Status", + .gpio = 20, + .active_low = 0, + }, { + .name = "gtw:red:Status", + .gpio = 21, + .active_low = 0, + }, { + .name = "gtw:green:USB", + .gpio = 12, + .active_low = 0, + }, +}; + +static struct gpio_led_platform_data mv88f6281gtw_ge_led_data = { + .leds = mv88f6281gtw_ge_led_pins, + .num_leds = ARRAY_SIZE(mv88f6281gtw_ge_led_pins), +}; + +static struct platform_device mv88f6281gtw_ge_leds = { + .name = "leds-gpio", + .id = -1, + .dev = { + .platform_data = &mv88f6281gtw_ge_led_data, + }, +}; + +static unsigned int mv88f6281gtw_ge_mpp_config[] __initdata = { + MPP12_GPO, /* Status#_USB pin */ + MPP20_GPIO, /* Status#_GLED pin */ + MPP21_GPIO, /* Status#_RLED pin */ + MPP46_GPIO, /* WPS_Switch pin */ + MPP47_GPIO, /* SW_Init pin */ + 0 +}; + +static void __init mv88f6281gtw_ge_init(void) +{ + /* + * Basic setup. Needs to be called early. + */ + kirkwood_init(); + kirkwood_mpp_conf(mv88f6281gtw_ge_mpp_config); + + kirkwood_ehci_init(); + kirkwood_ge00_init(&mv88f6281gtw_ge_ge00_data); + kirkwood_ge00_switch_init(&mv88f6281gtw_ge_switch_plat_data, NO_IRQ); + spi_register_board_info(mv88f6281gtw_ge_spi_slave_info, + ARRAY_SIZE(mv88f6281gtw_ge_spi_slave_info)); + kirkwood_spi_init(); + kirkwood_uart0_init(); + platform_device_register(&mv88f6281gtw_ge_leds); + platform_device_register(&mv88f6281gtw_ge_buttons); +} + +static int __init mv88f6281gtw_ge_pci_init(void) +{ + if (machine_is_mv88f6281gtw_ge()) + kirkwood_pcie_init(); + + return 0; +} +subsys_initcall(mv88f6281gtw_ge_pci_init); + +MACHINE_START(MV88F6281GTW_GE, "Marvell 88F6281 GTW GE Board") + /* Maintainer: Lennert Buytenhek */ + .phys_io = KIRKWOOD_REGS_PHYS_BASE, + .io_pg_offst = ((KIRKWOOD_REGS_VIRT_BASE) >> 18) & 0xfffc, + .boot_params = 0x00000100, + .init_machine = mv88f6281gtw_ge_init, + .map_io = kirkwood_map_io, + .init_irq = kirkwood_init_irq, + .timer = &kirkwood_timer, +MACHINE_END diff --git a/arch/arm/mach-kirkwood/pcie.c b/arch/arm/mach-kirkwood/pcie.c index 73fccacd1a73..d90b9aae308d 100644 --- a/arch/arm/mach-kirkwood/pcie.c +++ b/arch/arm/mach-kirkwood/pcie.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "common.h" @@ -95,6 +96,7 @@ static struct pci_ops pcie_ops = { static int kirkwood_pcie_setup(int nr, struct pci_sys_data *sys) { struct resource *res; + extern unsigned int kirkwood_clk_ctrl; /* * Generic PCIe unit setup. @@ -133,6 +135,8 @@ static int kirkwood_pcie_setup(int nr, struct pci_sys_data *sys) sys->resource[2] = NULL; sys->io_offset = 0; + kirkwood_clk_ctrl |= CGC_PEX0; + return 1; } diff --git a/arch/arm/mach-kirkwood/rd88f6192-nas-setup.c b/arch/arm/mach-kirkwood/rd88f6192-nas-setup.c index 2f0e4ef3db0f..8bf4153d0840 100644 --- a/arch/arm/mach-kirkwood/rd88f6192-nas-setup.c +++ b/arch/arm/mach-kirkwood/rd88f6192-nas-setup.c @@ -11,8 +11,6 @@ #include #include #include -#include -#include #include #include #include diff --git a/arch/arm/mach-kirkwood/rd88f6281-setup.c b/arch/arm/mach-kirkwood/rd88f6281-setup.c index 31e996d65fc4..31708ddbc83e 100644 --- a/arch/arm/mach-kirkwood/rd88f6281-setup.c +++ b/arch/arm/mach-kirkwood/rd88f6281-setup.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -22,7 +21,6 @@ #include #include #include -#include #include "common.h" #include "mpp.h" @@ -42,32 +40,6 @@ static struct mtd_partition rd88f6281_nand_parts[] = { }, }; -static struct resource rd88f6281_nand_resource = { - .flags = IORESOURCE_MEM, - .start = KIRKWOOD_NAND_MEM_PHYS_BASE, - .end = KIRKWOOD_NAND_MEM_PHYS_BASE + - KIRKWOOD_NAND_MEM_SIZE - 1, -}; - -static struct orion_nand_data rd88f6281_nand_data = { - .parts = rd88f6281_nand_parts, - .nr_parts = ARRAY_SIZE(rd88f6281_nand_parts), - .cle = 0, - .ale = 1, - .width = 8, - .chip_delay = 25, -}; - -static struct platform_device rd88f6281_nand_flash = { - .name = "orion_nand", - .id = -1, - .dev = { - .platform_data = &rd88f6281_nand_data, - }, - .resource = &rd88f6281_nand_resource, - .num_resources = 1, -}; - static struct mv643xx_eth_platform_data rd88f6281_ge00_data = { .phy_addr = MV643XX_ETH_PHY_NONE, .speed = SPEED_1000, @@ -114,6 +86,7 @@ static void __init rd88f6281_init(void) kirkwood_init(); kirkwood_mpp_conf(rd88f6281_mpp_config); + kirkwood_nand_init(ARRAY_AND_SIZE(rd88f6281_nand_parts), 25); kirkwood_ehci_init(); kirkwood_ge00_init(&rd88f6281_ge00_data); @@ -129,8 +102,6 @@ static void __init rd88f6281_init(void) kirkwood_sata_init(&rd88f6281_sata_data); kirkwood_sdio_init(&rd88f6281_mvsdio_data); kirkwood_uart0_init(); - - platform_device_register(&rd88f6281_nand_flash); } static int __init rd88f6281_pci_init(void) diff --git a/arch/arm/mach-kirkwood/sheevaplug-setup.c b/arch/arm/mach-kirkwood/sheevaplug-setup.c index 831e4a56cae1..c7319eeac8bb 100644 --- a/arch/arm/mach-kirkwood/sheevaplug-setup.c +++ b/arch/arm/mach-kirkwood/sheevaplug-setup.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -20,7 +19,6 @@ #include #include #include -#include #include "common.h" #include "mpp.h" @@ -40,38 +38,12 @@ static struct mtd_partition sheevaplug_nand_parts[] = { }, }; -static struct resource sheevaplug_nand_resource = { - .flags = IORESOURCE_MEM, - .start = KIRKWOOD_NAND_MEM_PHYS_BASE, - .end = KIRKWOOD_NAND_MEM_PHYS_BASE + - KIRKWOOD_NAND_MEM_SIZE - 1, -}; - -static struct orion_nand_data sheevaplug_nand_data = { - .parts = sheevaplug_nand_parts, - .nr_parts = ARRAY_SIZE(sheevaplug_nand_parts), - .cle = 0, - .ale = 1, - .width = 8, - .chip_delay = 25, -}; - -static struct platform_device sheevaplug_nand_flash = { - .name = "orion_nand", - .id = -1, - .dev = { - .platform_data = &sheevaplug_nand_data, - }, - .resource = &sheevaplug_nand_resource, - .num_resources = 1, -}; - static struct mv643xx_eth_platform_data sheevaplug_ge00_data = { .phy_addr = MV643XX_ETH_PHY_ADDR(0), }; static struct mvsdio_platform_data sheevaplug_mvsdio_data = { - // unfortunately the CD signal has not been connected */ + /* unfortunately the CD signal has not been connected */ }; static struct gpio_led sheevaplug_led_pins[] = { @@ -111,6 +83,7 @@ static void __init sheevaplug_init(void) kirkwood_mpp_conf(sheevaplug_mpp_config); kirkwood_uart0_init(); + kirkwood_nand_init(ARRAY_AND_SIZE(sheevaplug_nand_parts), 25); if (gpio_request(29, "USB Power Enable") != 0 || gpio_direction_output(29, 1) != 0) @@ -120,7 +93,6 @@ static void __init sheevaplug_init(void) kirkwood_ge00_init(&sheevaplug_ge00_data); kirkwood_sdio_init(&sheevaplug_mvsdio_data); - platform_device_register(&sheevaplug_nand_flash); platform_device_register(&sheevaplug_leds); } diff --git a/arch/arm/mach-mmp/include/mach/irqs.h b/arch/arm/mach-mmp/include/mach/irqs.h index e83e45ebf7a4..16295cfd5e29 100644 --- a/arch/arm/mach-mmp/include/mach/irqs.h +++ b/arch/arm/mach-mmp/include/mach/irqs.h @@ -52,6 +52,7 @@ /* * Interrupt numbers for PXA910 */ +#define IRQ_PXA910_NONE (-1) #define IRQ_PXA910_AIRQ 0 #define IRQ_PXA910_SSP3 1 #define IRQ_PXA910_SSP2 2 diff --git a/arch/arm/mach-mmp/include/mach/mfp-pxa168.h b/arch/arm/mach-mmp/include/mach/mfp-pxa168.h index 2e914649b9e4..3b216bf41e7f 100644 --- a/arch/arm/mach-mmp/include/mach/mfp-pxa168.h +++ b/arch/arm/mach-mmp/include/mach/mfp-pxa168.h @@ -253,6 +253,10 @@ #define GPIO58_LCD_PCLK_WR MFP_CFG(GPIO58, AF1) #define GPIO85_LCD_VSYNC MFP_CFG(GPIO85, AF1) +/* I2C */ +#define GPIO105_CI2C_SDA MFP_CFG(GPIO105, AF1) +#define GPIO106_CI2C_SCL MFP_CFG(GPIO106, AF1) + /* I2S */ #define GPIO113_I2S_MCLK MFP_CFG(GPIO113,AF6) #define GPIO114_I2S_FRM MFP_CFG(GPIO114,AF1) @@ -260,4 +264,27 @@ #define GPIO116_I2S_RXD MFP_CFG(GPIO116,AF2) #define GPIO117_I2S_TXD MFP_CFG(GPIO117,AF2) +/* PWM */ +#define GPIO96_PWM3_OUT MFP_CFG(GPIO96, AF1) +#define GPIO97_PWM2_OUT MFP_CFG(GPIO97, AF1) +#define GPIO98_PWM1_OUT MFP_CFG(GPIO98, AF1) +#define GPIO104_PWM4_OUT MFP_CFG(GPIO104, AF1) +#define GPIO106_PWM2_OUT MFP_CFG(GPIO106, AF2) +#define GPIO74_PWM4_OUT MFP_CFG(GPIO74, AF2) +#define GPIO75_PWM3_OUT MFP_CFG(GPIO75, AF2) +#define GPIO76_PWM2_OUT MFP_CFG(GPIO76, AF2) +#define GPIO77_PWM1_OUT MFP_CFG(GPIO77, AF2) +#define GPIO82_PWM4_OUT MFP_CFG(GPIO82, AF2) +#define GPIO83_PWM3_OUT MFP_CFG(GPIO83, AF2) +#define GPIO84_PWM2_OUT MFP_CFG(GPIO84, AF2) +#define GPIO85_PWM1_OUT MFP_CFG(GPIO85, AF2) +#define GPIO84_PWM1_OUT MFP_CFG(GPIO84, AF4) +#define GPIO122_PWM3_OUT MFP_CFG(GPIO122, AF3) +#define GPIO123_PWM1_OUT MFP_CFG(GPIO123, AF1) +#define GPIO124_PWM2_OUT MFP_CFG(GPIO124, AF1) +#define GPIO125_PWM3_OUT MFP_CFG(GPIO125, AF1) +#define GPIO126_PWM4_OUT MFP_CFG(GPIO126, AF1) +#define GPIO86_PWM1_OUT MFP_CFG(GPIO86, AF2) +#define GPIO86_PWM2_OUT MFP_CFG(GPIO86, AF3) + #endif /* __ASM_MACH_MFP_PXA168_H */ diff --git a/arch/arm/mach-mmp/include/mach/mfp-pxa910.h b/arch/arm/mach-mmp/include/mach/mfp-pxa910.h index d97de36c50ad..bf1189ff9a34 100644 --- a/arch/arm/mach-mmp/include/mach/mfp-pxa910.h +++ b/arch/arm/mach-mmp/include/mach/mfp-pxa910.h @@ -159,4 +159,12 @@ #define MMC1_CD_MMC1_CD MFP_CFG_DRV(MMC1_CD, AF0, MEDIUM) #define MMC1_WP_MMC1_WP MFP_CFG_DRV(MMC1_WP, AF0, MEDIUM) +/* PWM */ +#define GPIO27 PWM3 AF2 MFP_CFG(GPIO27, AF2) +#define GPIO51_PWM2_OUT MFP_CFG(GPIO51, AF2) +#define GPIO117_PWM1_OUT MFP_CFG(GPIO117, AF2) +#define GPIO118_PWM2_OUT MFP_CFG(GPIO118, AF2) +#define GPIO119_PWM3_OUT MFP_CFG(GPIO119, AF2) +#define GPIO120_PWM4_OUT MFP_CFG(GPIO120, AF2) + #endif /* __ASM_MACH MFP_PXA910_H */ diff --git a/arch/arm/mach-mmp/include/mach/pxa168.h b/arch/arm/mach-mmp/include/mach/pxa168.h index ef0a8a2076e9..6bf1f0eefcd1 100644 --- a/arch/arm/mach-mmp/include/mach/pxa168.h +++ b/arch/arm/mach-mmp/include/mach/pxa168.h @@ -1,10 +1,18 @@ #ifndef __ASM_MACH_PXA168_H #define __ASM_MACH_PXA168_H +#include #include +#include extern struct pxa_device_desc pxa168_device_uart1; extern struct pxa_device_desc pxa168_device_uart2; +extern struct pxa_device_desc pxa168_device_twsi0; +extern struct pxa_device_desc pxa168_device_twsi1; +extern struct pxa_device_desc pxa168_device_pwm1; +extern struct pxa_device_desc pxa168_device_pwm2; +extern struct pxa_device_desc pxa168_device_pwm3; +extern struct pxa_device_desc pxa168_device_pwm4; static inline int pxa168_add_uart(int id) { @@ -20,4 +28,40 @@ static inline int pxa168_add_uart(int id) return pxa_register_device(d, NULL, 0); } + +static inline int pxa168_add_twsi(int id, struct i2c_pxa_platform_data *data, + struct i2c_board_info *info, unsigned size) +{ + struct pxa_device_desc *d = NULL; + int ret; + + switch (id) { + case 0: d = &pxa168_device_twsi0; break; + case 1: d = &pxa168_device_twsi1; break; + default: + return -EINVAL; + } + + ret = i2c_register_board_info(id, info, size); + if (ret) + return ret; + + return pxa_register_device(d, data, sizeof(*data)); +} + +static inline int pxa168_add_pwm(int id) +{ + struct pxa_device_desc *d = NULL; + + switch (id) { + case 1: d = &pxa168_device_pwm1; break; + case 2: d = &pxa168_device_pwm2; break; + case 3: d = &pxa168_device_pwm3; break; + case 4: d = &pxa168_device_pwm4; break; + default: + return -EINVAL; + } + + return pxa_register_device(d, NULL, 0); +} #endif /* __ASM_MACH_PXA168_H */ diff --git a/arch/arm/mach-mmp/include/mach/pxa910.h b/arch/arm/mach-mmp/include/mach/pxa910.h index b7aeaf574c36..6ae1ed7a0a9f 100644 --- a/arch/arm/mach-mmp/include/mach/pxa910.h +++ b/arch/arm/mach-mmp/include/mach/pxa910.h @@ -1,10 +1,18 @@ #ifndef __ASM_MACH_PXA910_H #define __ASM_MACH_PXA910_H +#include #include +#include extern struct pxa_device_desc pxa910_device_uart1; extern struct pxa_device_desc pxa910_device_uart2; +extern struct pxa_device_desc pxa910_device_twsi0; +extern struct pxa_device_desc pxa910_device_twsi1; +extern struct pxa_device_desc pxa910_device_pwm1; +extern struct pxa_device_desc pxa910_device_pwm2; +extern struct pxa_device_desc pxa910_device_pwm3; +extern struct pxa_device_desc pxa910_device_pwm4; static inline int pxa910_add_uart(int id) { @@ -20,4 +28,40 @@ static inline int pxa910_add_uart(int id) return pxa_register_device(d, NULL, 0); } + +static inline int pxa910_add_twsi(int id, struct i2c_pxa_platform_data *data, + struct i2c_board_info *info, unsigned size) +{ + struct pxa_device_desc *d = NULL; + int ret; + + switch (id) { + case 0: d = &pxa910_device_twsi0; break; + case 1: d = &pxa910_device_twsi1; break; + default: + return -EINVAL; + } + + ret = i2c_register_board_info(id, info, size); + if (ret) + return ret; + + return pxa_register_device(d, data, sizeof(*data)); +} + +static inline int pxa910_add_pwm(int id) +{ + struct pxa_device_desc *d = NULL; + + switch (id) { + case 1: d = &pxa910_device_pwm1; break; + case 2: d = &pxa910_device_pwm2; break; + case 3: d = &pxa910_device_pwm3; break; + case 4: d = &pxa910_device_pwm4; break; + default: + return -EINVAL; + } + + return pxa_register_device(d, NULL, 0); +} #endif /* __ASM_MACH_PXA910_H */ diff --git a/arch/arm/mach-mmp/include/mach/regs-apbc.h b/arch/arm/mach-mmp/include/mach/regs-apbc.h index c6b8c9dc2026..98ccbee4bd0c 100644 --- a/arch/arm/mach-mmp/include/mach/regs-apbc.h +++ b/arch/arm/mach-mmp/include/mach/regs-apbc.h @@ -22,8 +22,10 @@ #define APBC_PXA168_UART1 APBC_REG(0x000) #define APBC_PXA168_UART2 APBC_REG(0x004) #define APBC_PXA168_GPIO APBC_REG(0x008) -#define APBC_PXA168_PWM0 APBC_REG(0x00c) -#define APBC_PXA168_PWM1 APBC_REG(0x010) +#define APBC_PXA168_PWM1 APBC_REG(0x00c) +#define APBC_PXA168_PWM2 APBC_REG(0x010) +#define APBC_PXA168_PWM3 APBC_REG(0x014) +#define APBC_PXA168_PWM4 APBC_REG(0x018) #define APBC_PXA168_SSP1 APBC_REG(0x01c) #define APBC_PXA168_SSP2 APBC_REG(0x020) #define APBC_PXA168_RTC APBC_REG(0x028) @@ -48,10 +50,10 @@ #define APBC_PXA910_UART0 APBC_REG(0x000) #define APBC_PXA910_UART1 APBC_REG(0x004) #define APBC_PXA910_GPIO APBC_REG(0x008) -#define APBC_PXA910_PWM0 APBC_REG(0x00c) -#define APBC_PXA910_PWM1 APBC_REG(0x010) -#define APBC_PXA910_PWM2 APBC_REG(0x014) -#define APBC_PXA910_PWM3 APBC_REG(0x018) +#define APBC_PXA910_PWM1 APBC_REG(0x00c) +#define APBC_PXA910_PWM2 APBC_REG(0x010) +#define APBC_PXA910_PWM3 APBC_REG(0x014) +#define APBC_PXA910_PWM4 APBC_REG(0x018) #define APBC_PXA910_SSP1 APBC_REG(0x01c) #define APBC_PXA910_SSP2 APBC_REG(0x020) #define APBC_PXA910_IPC APBC_REG(0x024) diff --git a/arch/arm/mach-mmp/pxa168.c b/arch/arm/mach-mmp/pxa168.c index ae924468658c..71b1ae338753 100644 --- a/arch/arm/mach-mmp/pxa168.c +++ b/arch/arm/mach-mmp/pxa168.c @@ -65,11 +65,23 @@ void __init pxa168_init_irq(void) /* APB peripheral clocks */ static APBC_CLK(uart1, PXA168_UART1, 1, 14745600); static APBC_CLK(uart2, PXA168_UART2, 1, 14745600); +static APBC_CLK(twsi0, PXA168_TWSI0, 1, 33000000); +static APBC_CLK(twsi1, PXA168_TWSI1, 1, 33000000); +static APBC_CLK(pwm1, PXA168_PWM1, 1, 13000000); +static APBC_CLK(pwm2, PXA168_PWM2, 1, 13000000); +static APBC_CLK(pwm3, PXA168_PWM3, 1, 13000000); +static APBC_CLK(pwm4, PXA168_PWM4, 1, 13000000); /* device and clock bindings */ static struct clk_lookup pxa168_clkregs[] = { INIT_CLKREG(&clk_uart1, "pxa2xx-uart.0", NULL), INIT_CLKREG(&clk_uart2, "pxa2xx-uart.1", NULL), + INIT_CLKREG(&clk_twsi0, "pxa2xx-i2c.0", NULL), + INIT_CLKREG(&clk_twsi1, "pxa2xx-i2c.1", NULL), + INIT_CLKREG(&clk_pwm1, "pxa168-pwm.0", NULL), + INIT_CLKREG(&clk_pwm2, "pxa168-pwm.1", NULL), + INIT_CLKREG(&clk_pwm3, "pxa168-pwm.2", NULL), + INIT_CLKREG(&clk_pwm4, "pxa168-pwm.3", NULL), }; static int __init pxa168_init(void) @@ -109,3 +121,9 @@ struct sys_timer pxa168_timer = { /* on-chip devices */ PXA168_DEVICE(uart1, "pxa2xx-uart", 0, UART1, 0xd4017000, 0x30, 21, 22); PXA168_DEVICE(uart2, "pxa2xx-uart", 1, UART2, 0xd4018000, 0x30, 23, 24); +PXA168_DEVICE(twsi0, "pxa2xx-i2c", 0, TWSI0, 0xd4011000, 0x28); +PXA168_DEVICE(twsi1, "pxa2xx-i2c", 1, TWSI1, 0xd4025000, 0x28); +PXA168_DEVICE(pwm1, "pxa168-pwm", 0, NONE, 0xd401a000, 0x10); +PXA168_DEVICE(pwm2, "pxa168-pwm", 1, NONE, 0xd401a400, 0x10); +PXA168_DEVICE(pwm3, "pxa168-pwm", 2, NONE, 0xd401a800, 0x10); +PXA168_DEVICE(pwm4, "pxa168-pwm", 3, NONE, 0xd401ac00, 0x10); diff --git a/arch/arm/mach-mmp/pxa910.c b/arch/arm/mach-mmp/pxa910.c index 453f8f7758bf..5882ca6b49fb 100644 --- a/arch/arm/mach-mmp/pxa910.c +++ b/arch/arm/mach-mmp/pxa910.c @@ -103,11 +103,23 @@ void __init pxa910_init_irq(void) /* APB peripheral clocks */ static APBC_CLK(uart1, PXA910_UART0, 1, 14745600); static APBC_CLK(uart2, PXA910_UART1, 1, 14745600); +static APBC_CLK(twsi0, PXA168_TWSI0, 1, 33000000); +static APBC_CLK(twsi1, PXA168_TWSI1, 1, 33000000); +static APBC_CLK(pwm1, PXA910_PWM1, 1, 13000000); +static APBC_CLK(pwm2, PXA910_PWM2, 1, 13000000); +static APBC_CLK(pwm3, PXA910_PWM3, 1, 13000000); +static APBC_CLK(pwm4, PXA910_PWM4, 1, 13000000); /* device and clock bindings */ static struct clk_lookup pxa910_clkregs[] = { INIT_CLKREG(&clk_uart1, "pxa2xx-uart.0", NULL), INIT_CLKREG(&clk_uart2, "pxa2xx-uart.1", NULL), + INIT_CLKREG(&clk_twsi0, "pxa2xx-i2c.0", NULL), + INIT_CLKREG(&clk_twsi1, "pxa2xx-i2c.1", NULL), + INIT_CLKREG(&clk_pwm1, "pxa910-pwm.0", NULL), + INIT_CLKREG(&clk_pwm2, "pxa910-pwm.1", NULL), + INIT_CLKREG(&clk_pwm3, "pxa910-pwm.2", NULL), + INIT_CLKREG(&clk_pwm4, "pxa910-pwm.3", NULL), }; static int __init pxa910_init(void) @@ -156,3 +168,9 @@ struct sys_timer pxa910_timer = { */ PXA910_DEVICE(uart1, "pxa2xx-uart", 0, UART2, 0xd4017000, 0x30, 21, 22); PXA910_DEVICE(uart2, "pxa2xx-uart", 1, UART3, 0xd4018000, 0x30, 23, 24); +PXA910_DEVICE(twsi0, "pxa2xx-i2c", 0, TWSI0, 0xd4011000, 0x28); +PXA910_DEVICE(twsi1, "pxa2xx-i2c", 1, TWSI1, 0xd4025000, 0x28); +PXA910_DEVICE(pwm1, "pxa910-pwm", 0, NONE, 0xd401a000, 0x10); +PXA910_DEVICE(pwm2, "pxa910-pwm", 1, NONE, 0xd401a400, 0x10); +PXA910_DEVICE(pwm3, "pxa910-pwm", 2, NONE, 0xd401a800, 0x10); +PXA910_DEVICE(pwm4, "pxa910-pwm", 3, NONE, 0xd401ac00, 0x10); diff --git a/arch/arm/mach-mv78xx0/irq.c b/arch/arm/mach-mv78xx0/irq.c index f289b0ea7dcf..22b4ff893b3c 100644 --- a/arch/arm/mach-mv78xx0/irq.c +++ b/arch/arm/mach-mv78xx0/irq.c @@ -28,6 +28,9 @@ void __init mv78xx0_init_irq(void) { int i; + /* Initialize gpiolib. */ + orion_gpio_init(); + orion_irq_init(0, (void __iomem *)(IRQ_VIRT_BASE + IRQ_MASK_LOW_OFF)); orion_irq_init(32, (void __iomem *)(IRQ_VIRT_BASE + IRQ_MASK_HIGH_OFF)); orion_irq_init(64, (void __iomem *)(IRQ_VIRT_BASE + IRQ_MASK_ERR_OFF)); diff --git a/arch/arm/mach-mx1/generic.c b/arch/arm/mach-mx1/generic.c index 0dec6f300ffc..7622c9b38c97 100644 --- a/arch/arm/mach-mx1/generic.c +++ b/arch/arm/mach-mx1/generic.c @@ -26,6 +26,7 @@ #include +#include #include static struct map_desc imx_io_desc[] __initdata = { @@ -37,7 +38,9 @@ static struct map_desc imx_io_desc[] __initdata = { } }; -void __init mxc_map_io(void) +void __init mx1_map_io(void) { + mxc_set_cpu_type(MXC_CPU_MX1); + iotable_init(imx_io_desc, ARRAY_SIZE(imx_io_desc)); } diff --git a/arch/arm/mach-mx1/mx1ads.c b/arch/arm/mach-mx1/mx1ads.c index e54057fb855b..e5b0c0a83c3b 100644 --- a/arch/arm/mach-mx1/mx1ads.c +++ b/arch/arm/mach-mx1/mx1ads.c @@ -12,77 +12,56 @@ * warranty of any kind, whether express or implied. */ -#include -#include -#include -#include #include #include +#include +#include +#include +#include #include #include #include -#include -#include #include -#include -#include +#include #include +#include #include +#include + #include "devices.h" -/* - * UARTs platform data - */ -static int mxc_uart1_pins[] = { +static int mx1ads_pins[] = { + /* UART1 */ PC9_PF_UART1_CTS, PC10_PF_UART1_RTS, PC11_PF_UART1_TXD, PC12_PF_UART1_RXD, -}; - -static int uart1_mxc_init(struct platform_device *pdev) -{ - return mxc_gpio_setup_multiple_pins(mxc_uart1_pins, - ARRAY_SIZE(mxc_uart1_pins), "UART1"); -} - -static int uart1_mxc_exit(struct platform_device *pdev) -{ - mxc_gpio_release_multiple_pins(mxc_uart1_pins, - ARRAY_SIZE(mxc_uart1_pins)); - return 0; -} - -static int mxc_uart2_pins[] = { + /* UART2 */ PB28_PF_UART2_CTS, PB29_PF_UART2_RTS, PB30_PF_UART2_TXD, PB31_PF_UART2_RXD, + /* I2C */ + PA15_PF_I2C_SDA, + PA16_PF_I2C_SCL, + /* SPI */ + PC13_PF_SPI1_SPI_RDY, + PC14_PF_SPI1_SCLK, + PC15_PF_SPI1_SS, + PC16_PF_SPI1_MISO, + PC17_PF_SPI1_MOSI, }; -static int uart2_mxc_init(struct platform_device *pdev) -{ - return mxc_gpio_setup_multiple_pins(mxc_uart2_pins, - ARRAY_SIZE(mxc_uart2_pins), "UART2"); -} - -static int uart2_mxc_exit(struct platform_device *pdev) -{ - mxc_gpio_release_multiple_pins(mxc_uart2_pins, - ARRAY_SIZE(mxc_uart2_pins)); - return 0; -} +/* + * UARTs platform data + */ static struct imxuart_platform_data uart_pdata[] = { { - .init = uart1_mxc_init, - .exit = uart1_mxc_exit, .flags = IMXUART_HAVE_RTSCTS, }, { - .init = uart2_mxc_init, - .exit = uart2_mxc_exit, .flags = IMXUART_HAVE_RTSCTS, }, }; @@ -111,24 +90,6 @@ static struct platform_device flash_device = { /* * I2C */ - -static int i2c_pins[] = { - PA15_PF_I2C_SDA, - PA16_PF_I2C_SCL, -}; - -static int i2c_init(struct device *dev) -{ - return mxc_gpio_setup_multiple_pins(i2c_pins, - ARRAY_SIZE(i2c_pins), "I2C"); -} - -static void i2c_exit(struct device *dev) -{ - mxc_gpio_release_multiple_pins(i2c_pins, - ARRAY_SIZE(i2c_pins)); -} - static struct pcf857x_platform_data pcf857x_data[] = { { .gpio_base = 4 * 32, @@ -139,8 +100,6 @@ static struct pcf857x_platform_data pcf857x_data[] = { static struct imxi2c_platform_data mx1ads_i2c_data = { .bitrate = 100000, - .init = i2c_init, - .exit = i2c_exit, }; static struct i2c_board_info mx1ads_i2c_devices[] = { @@ -160,6 +119,9 @@ static struct i2c_board_info mx1ads_i2c_devices[] = { */ static void __init mx1ads_init(void) { + mxc_gpio_setup_multiple_pins(mx1ads_pins, + ARRAY_SIZE(mx1ads_pins), "mx1ads"); + /* UART */ mxc_register_device(&imx_uart1_device, &uart_pdata[0]); mxc_register_device(&imx_uart2_device, &uart_pdata[1]); @@ -188,7 +150,7 @@ MACHINE_START(MX1ADS, "Freescale MX1ADS") .phys_io = IMX_IO_PHYS, .io_pg_offst = (IMX_IO_BASE >> 18) & 0xfffc, .boot_params = PHYS_OFFSET + 0x100, - .map_io = mxc_map_io, + .map_io = mx1_map_io, .init_irq = mxc_init_irq, .timer = &mx1ads_timer, .init_machine = mx1ads_init, @@ -198,7 +160,7 @@ MACHINE_START(MXLADS, "Freescale MXLADS") .phys_io = IMX_IO_PHYS, .io_pg_offst = (IMX_IO_BASE >> 18) & 0xfffc, .boot_params = PHYS_OFFSET + 0x100, - .map_io = mxc_map_io, + .map_io = mx1_map_io, .init_irq = mxc_init_irq, .timer = &mx1ads_timer, .init_machine = mx1ads_init, diff --git a/arch/arm/mach-mx1/scb9328.c b/arch/arm/mach-mx1/scb9328.c index 0e71f3fa28bf..20e0b5bcdffc 100644 --- a/arch/arm/mach-mx1/scb9328.c +++ b/arch/arm/mach-mx1/scb9328.c @@ -153,7 +153,7 @@ MACHINE_START(SCB9328, "Synertronixx scb9328") .phys_io = 0x00200000, .io_pg_offst = ((0xe0200000) >> 18) & 0xfffc, .boot_params = 0x08000100, - .map_io = mxc_map_io, + .map_io = mx1_map_io, .init_irq = mxc_init_irq, .timer = &scb9328_timer, .init_machine = scb9328_init, diff --git a/arch/arm/mach-mx2/Kconfig b/arch/arm/mach-mx2/Kconfig index 42a788842f49..c77da586b71d 100644 --- a/arch/arm/mach-mx2/Kconfig +++ b/arch/arm/mach-mx2/Kconfig @@ -18,6 +18,13 @@ endchoice comment "MX2 platforms:" +config MACH_MX21ADS + bool "MX21ADS platform" + depends on MACH_MX21 + help + Include support for MX21ADS platform. This includes specific + configurations for the board and its peripherals. + config MACH_MX27ADS bool "MX27ADS platform" depends on MACH_MX27 @@ -46,4 +53,18 @@ config MACH_PCM970_BASEBOARD endchoice +config MACH_MX27_3DS + bool "MX27PDK platform" + depends on MACH_MX27 + help + Include support for MX27PDK platform. This includes specific + configurations for the board and its peripherals. + +config MACH_MX27LITE + bool "LogicPD MX27 LITEKIT platform" + depends on MACH_MX27 + help + Include support for MX27 LITEKIT platform. This includes specific + configurations for the board and its peripherals. + endif diff --git a/arch/arm/mach-mx2/Makefile b/arch/arm/mach-mx2/Makefile index 950649a91540..b9b1cca4e9bc 100644 --- a/arch/arm/mach-mx2/Makefile +++ b/arch/arm/mach-mx2/Makefile @@ -11,6 +11,10 @@ obj-$(CONFIG_MACH_MX21) += clock_imx21.o obj-$(CONFIG_MACH_MX27) += cpu_imx27.o obj-$(CONFIG_MACH_MX27) += clock_imx27.o +obj-$(CONFIG_MACH_MX21ADS) += mx21ads.o obj-$(CONFIG_MACH_MX27ADS) += mx27ads.o obj-$(CONFIG_MACH_PCM038) += pcm038.o obj-$(CONFIG_MACH_PCM970_BASEBOARD) += pcm970-baseboard.o +obj-$(CONFIG_MACH_MX27_3DS) += mx27pdk.o +obj-$(CONFIG_MACH_MX27LITE) += mx27lite.o + diff --git a/arch/arm/mach-mx2/clock_imx21.c b/arch/arm/mach-mx2/clock_imx21.c index e4b08ca804ea..0850fb88ec15 100644 --- a/arch/arm/mach-mx2/clock_imx21.c +++ b/arch/arm/mach-mx2/clock_imx21.c @@ -48,6 +48,25 @@ static void _clk_disable(struct clk *clk) __raw_writel(reg, clk->enable_reg); } +static unsigned long _clk_generic_round_rate(struct clk *clk, + unsigned long rate, + u32 max_divisor) +{ + u32 div; + unsigned long parent_rate; + + parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + if (parent_rate % rate) + div++; + + if (div > max_divisor) + div = max_divisor; + + return parent_rate / div; +} + static int _clk_spll_enable(struct clk *clk) { u32 reg; @@ -78,19 +97,7 @@ static void _clk_spll_disable(struct clk *clk) static unsigned long _clk_perclkx_round_rate(struct clk *clk, unsigned long rate) { - u32 div; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - div = parent_rate / rate; - if (parent_rate % rate) - div++; - - if (div > 64) - div = 64; - - return parent_rate / div; + return _clk_generic_round_rate(clk, rate, 64); } static int _clk_perclkx_set_rate(struct clk *clk, unsigned long rate) @@ -130,6 +137,32 @@ static unsigned long _clk_usb_recalc(struct clk *clk) return parent_rate / (usb_pdf + 1U); } +static unsigned long _clk_usb_round_rate(struct clk *clk, + unsigned long rate) +{ + return _clk_generic_round_rate(clk, rate, 8); +} + +static int _clk_usb_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg; + u32 div; + unsigned long parent_rate; + + parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + if (div > 8 || div < 1 || ((parent_rate / div) != rate)) + return -EINVAL; + div--; + + reg = CSCR() & ~CCM_CSCR_USB_MASK; + reg |= div << CCM_CSCR_USB_OFFSET; + __raw_writel(reg, CCM_CSCR); + + return 0; +} + static unsigned long _clk_ssix_recalc(struct clk *clk, unsigned long pdf) { unsigned long parent_rate; @@ -595,11 +628,14 @@ static struct clk csi_clk[] = { static struct clk usb_clk[] = { { .parent = &spll_clk, + .secondary = &usb_clk[1], .get_rate = _clk_usb_recalc, .enable = _clk_enable, .enable_reg = CCM_PCCR_USBOTG_REG, .enable_shift = CCM_PCCR_USBOTG_OFFSET, .disable = _clk_disable, + .round_rate = _clk_usb_round_rate, + .set_rate = _clk_usb_set_rate, }, { .parent = &hclk_clk, .enable = _clk_enable, @@ -768,18 +804,7 @@ static struct clk rtc_clk = { static unsigned long _clk_clko_round_rate(struct clk *clk, unsigned long rate) { - u32 div; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - div = parent_rate / rate; - if (parent_rate % rate) - div++; - - if (div > 8) - div = 8; - - return parent_rate / div; + return _clk_generic_round_rate(clk, rate, 8); } static int _clk_clko_set_rate(struct clk *clk, unsigned long rate) @@ -921,7 +946,7 @@ static struct clk_lookup lookups[] = { _REGISTER_CLOCK(NULL, "cspi3", cspi_clk[2]) _REGISTER_CLOCK("imx-fb.0", NULL, lcdc_clk[0]) _REGISTER_CLOCK(NULL, "csi", csi_clk[0]) - _REGISTER_CLOCK(NULL, "usb", usb_clk[0]) + _REGISTER_CLOCK("imx21-hcd.0", NULL, usb_clk[0]) _REGISTER_CLOCK(NULL, "ssi1", ssi_clk[0]) _REGISTER_CLOCK(NULL, "ssi2", ssi_clk[1]) _REGISTER_CLOCK("mxc_nand.0", NULL, nfc_clk) diff --git a/arch/arm/mach-mx2/generic.c b/arch/arm/mach-mx2/generic.c index bd51dd04948e..169372f69d8f 100644 --- a/arch/arm/mach-mx2/generic.c +++ b/arch/arm/mach-mx2/generic.c @@ -69,7 +69,17 @@ static struct map_desc mxc_io_desc[] __initdata = { * system startup to create static physical to virtual * memory map for the IO modules. */ -void __init mxc_map_io(void) +void __init mx21_map_io(void) { + mxc_set_cpu_type(MXC_CPU_MX21); + iotable_init(mxc_io_desc, ARRAY_SIZE(mxc_io_desc)); } + +void __init mx27_map_io(void) +{ + mxc_set_cpu_type(MXC_CPU_MX27); + + iotable_init(mxc_io_desc, ARRAY_SIZE(mxc_io_desc)); +} + diff --git a/arch/arm/mach-mx2/mx21ads.c b/arch/arm/mach-mx2/mx21ads.c new file mode 100644 index 000000000000..a5ee461cb405 --- /dev/null +++ b/arch/arm/mach-mx2/mx21ads.c @@ -0,0 +1,286 @@ +/* + * Copyright (C) 2000 Deep Blue Solutions Ltd + * Copyright (C) 2002 Shane Nay (shane@minirl.com) + * Copyright 2006-2007 Freescale Semiconductor, 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "devices.h" + +static unsigned int mx21ads_pins[] = { + + /* CS8900A */ + (GPIO_PORTE | GPIO_GPIO | GPIO_IN | 11), + + /* UART1 */ + PE12_PF_UART1_TXD, + PE13_PF_UART1_RXD, + PE14_PF_UART1_CTS, + PE15_PF_UART1_RTS, + + /* UART3 (IrDA) - only TXD and RXD */ + PE8_PF_UART3_TXD, + PE9_PF_UART3_RXD, + + /* UART4 */ + PB26_AF_UART4_RTS, + PB28_AF_UART4_TXD, + PB29_AF_UART4_CTS, + PB31_AF_UART4_RXD, + + /* LCDC */ + PA5_PF_LSCLK, + PA6_PF_LD0, + PA7_PF_LD1, + PA8_PF_LD2, + PA9_PF_LD3, + PA10_PF_LD4, + PA11_PF_LD5, + PA12_PF_LD6, + PA13_PF_LD7, + PA14_PF_LD8, + PA15_PF_LD9, + PA16_PF_LD10, + PA17_PF_LD11, + PA18_PF_LD12, + PA19_PF_LD13, + PA20_PF_LD14, + PA21_PF_LD15, + PA22_PF_LD16, + PA24_PF_REV, /* Sharp panel dedicated signal */ + PA25_PF_CLS, /* Sharp panel dedicated signal */ + PA26_PF_PS, /* Sharp panel dedicated signal */ + PA27_PF_SPL_SPR, /* Sharp panel dedicated signal */ + PA28_PF_HSYNC, + PA29_PF_VSYNC, + PA30_PF_CONTRAST, + PA31_PF_OE_ACD, + + /* MMC/SDHC */ + PE18_PF_SD1_D0, + PE19_PF_SD1_D1, + PE20_PF_SD1_D2, + PE21_PF_SD1_D3, + PE22_PF_SD1_CMD, + PE23_PF_SD1_CLK, + + /* NFC */ + PF0_PF_NRFB, + PF1_PF_NFCE, + PF2_PF_NFWP, + PF3_PF_NFCLE, + PF4_PF_NFALE, + PF5_PF_NFRE, + PF6_PF_NFWE, + PF7_PF_NFIO0, + PF8_PF_NFIO1, + PF9_PF_NFIO2, + PF10_PF_NFIO3, + PF11_PF_NFIO4, + PF12_PF_NFIO5, + PF13_PF_NFIO6, + PF14_PF_NFIO7, +}; + +/* ADS's NOR flash: 2x AM29BDS128HE9VKI on 32-bit bus */ +static struct physmap_flash_data mx21ads_flash_data = { + .width = 4, +}; + +static struct resource mx21ads_flash_resource = { + .start = CS0_BASE_ADDR, + .end = CS0_BASE_ADDR + 0x02000000 - 1, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device mx21ads_nor_mtd_device = { + .name = "physmap-flash", + .id = 0, + .dev = { + .platform_data = &mx21ads_flash_data, + }, + .num_resources = 1, + .resource = &mx21ads_flash_resource, +}; + +static struct imxuart_platform_data uart_pdata = { + .flags = IMXUART_HAVE_RTSCTS, +}; + +static struct imxuart_platform_data uart_norts_pdata = { +}; + + +static int mx21ads_fb_init(struct platform_device *pdev) +{ + u16 tmp; + + tmp = __raw_readw(MX21ADS_IO_REG); + tmp |= MX21ADS_IO_LCDON; + __raw_writew(tmp, MX21ADS_IO_REG); + return 0; +} + +static void mx21ads_fb_exit(struct platform_device *pdev) +{ + u16 tmp; + + tmp = __raw_readw(MX21ADS_IO_REG); + tmp &= ~MX21ADS_IO_LCDON; + __raw_writew(tmp, MX21ADS_IO_REG); +} + +/* + * Connected is a portrait Sharp-QVGA display + * of type: LQ035Q7DB02 + */ +static struct imx_fb_platform_data mx21ads_fb_data = { + .pixclock = 188679, /* in ps */ + .xres = 240, + .yres = 320, + + .bpp = 16, + .hsync_len = 2, + .left_margin = 6, + .right_margin = 16, + + .vsync_len = 1, + .upper_margin = 8, + .lower_margin = 10, + .fixed_screen_cpu = 0, + + .pcr = 0xFB108BC7, + .pwmr = 0x00A901ff, + .lscr1 = 0x00120300, + .dmacr = 0x00020008, + + .init = mx21ads_fb_init, + .exit = mx21ads_fb_exit, +}; + +static int mx21ads_sdhc_get_ro(struct device *dev) +{ + return (__raw_readw(MX21ADS_IO_REG) & MX21ADS_IO_SD_WP) ? 1 : 0; +} + +static int mx21ads_sdhc_init(struct device *dev, irq_handler_t detect_irq, + void *data) +{ + int ret; + + ret = request_irq(IRQ_GPIOD(25), detect_irq, + IRQF_TRIGGER_FALLING, "mmc-detect", data); + if (ret) + goto out; + return 0; +out: + return ret; +} + +static void mx21ads_sdhc_exit(struct device *dev, void *data) +{ + free_irq(IRQ_GPIOD(25), data); +} + +static struct imxmmc_platform_data mx21ads_sdhc_pdata = { + .ocr_avail = MMC_VDD_29_30 | MMC_VDD_30_31, /* 3.0V */ + .get_ro = mx21ads_sdhc_get_ro, + .init = mx21ads_sdhc_init, + .exit = mx21ads_sdhc_exit, +}; + +static struct mxc_nand_platform_data mx21ads_nand_board_info = { + .width = 1, + .hw_ecc = 1, +}; + +static struct map_desc mx21ads_io_desc[] __initdata = { + /* + * Memory-mapped I/O on MX21ADS Base board: + * - CS8900A Ethernet controller + * - ST16C2552CJ UART + * - CPU and Base board version + * - Base board I/O register + */ + { + .virtual = MX21ADS_MMIO_BASE_ADDR, + .pfn = __phys_to_pfn(CS1_BASE_ADDR), + .length = MX21ADS_MMIO_SIZE, + .type = MT_DEVICE, + }, +}; + +static void __init mx21ads_map_io(void) +{ + mx21_map_io(); + iotable_init(mx21ads_io_desc, ARRAY_SIZE(mx21ads_io_desc)); +} + +static struct platform_device *platform_devices[] __initdata = { + &mx21ads_nor_mtd_device, +}; + +static void __init mx21ads_board_init(void) +{ + mxc_gpio_setup_multiple_pins(mx21ads_pins, ARRAY_SIZE(mx21ads_pins), + "mx21ads"); + + mxc_register_device(&mxc_uart_device0, &uart_pdata); + mxc_register_device(&mxc_uart_device2, &uart_norts_pdata); + mxc_register_device(&mxc_uart_device3, &uart_pdata); + mxc_register_device(&mxc_fb_device, &mx21ads_fb_data); + mxc_register_device(&mxc_sdhc_device0, &mx21ads_sdhc_pdata); + mxc_register_device(&mxc_nand_device, &mx21ads_nand_board_info); + + platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices)); +} + +static void __init mx21ads_timer_init(void) +{ + mx21_clocks_init(32768, 26000000); +} + +static struct sys_timer mx21ads_timer = { + .init = mx21ads_timer_init, +}; + +MACHINE_START(MX21ADS, "Freescale i.MX21ADS") + /* maintainer: Freescale Semiconductor, Inc. */ + .phys_io = AIPI_BASE_ADDR, + .io_pg_offst = ((AIPI_BASE_ADDR_VIRT) >> 18) & 0xfffc, + .boot_params = PHYS_OFFSET + 0x100, + .map_io = mx21ads_map_io, + .init_irq = mxc_init_irq, + .init_machine = mx21ads_board_init, + .timer = &mx21ads_timer, +MACHINE_END diff --git a/arch/arm/mach-mx2/mx27ads.c b/arch/arm/mach-mx2/mx27ads.c index 4a3b097adc12..02daddac6995 100644 --- a/arch/arm/mach-mx2/mx27ads.c +++ b/arch/arm/mach-mx2/mx27ads.c @@ -23,6 +23,8 @@ #include #include #include +#include +#include #include #include #include @@ -33,9 +35,117 @@ #include #include #include +#include +#include +#include +#include #include "devices.h" +static unsigned int mx27ads_pins[] = { + /* UART0 */ + PE12_PF_UART1_TXD, + PE13_PF_UART1_RXD, + PE14_PF_UART1_CTS, + PE15_PF_UART1_RTS, + /* UART1 */ + PE3_PF_UART2_CTS, + PE4_PF_UART2_RTS, + PE6_PF_UART2_TXD, + PE7_PF_UART2_RXD, + /* UART2 */ + PE8_PF_UART3_TXD, + PE9_PF_UART3_RXD, + PE10_PF_UART3_CTS, + PE11_PF_UART3_RTS, + /* UART3 */ + PB26_AF_UART4_RTS, + PB28_AF_UART4_TXD, + PB29_AF_UART4_CTS, + PB31_AF_UART4_RXD, + /* UART4 */ + PB18_AF_UART5_TXD, + PB19_AF_UART5_RXD, + PB20_AF_UART5_CTS, + PB21_AF_UART5_RTS, + /* UART5 */ + PB10_AF_UART6_TXD, + PB12_AF_UART6_CTS, + PB11_AF_UART6_RXD, + PB13_AF_UART6_RTS, + /* FEC */ + PD0_AIN_FEC_TXD0, + PD1_AIN_FEC_TXD1, + PD2_AIN_FEC_TXD2, + PD3_AIN_FEC_TXD3, + PD4_AOUT_FEC_RX_ER, + PD5_AOUT_FEC_RXD1, + PD6_AOUT_FEC_RXD2, + PD7_AOUT_FEC_RXD3, + PD8_AF_FEC_MDIO, + PD9_AIN_FEC_MDC, + PD10_AOUT_FEC_CRS, + PD11_AOUT_FEC_TX_CLK, + PD12_AOUT_FEC_RXD0, + PD13_AOUT_FEC_RX_DV, + PD14_AOUT_FEC_RX_CLK, + PD15_AOUT_FEC_COL, + PD16_AIN_FEC_TX_ER, + PF23_AIN_FEC_TX_EN, + /* I2C2 */ + PC5_PF_I2C2_SDA, + PC6_PF_I2C2_SCL, + /* FB */ + PA5_PF_LSCLK, + PA6_PF_LD0, + PA7_PF_LD1, + PA8_PF_LD2, + PA9_PF_LD3, + PA10_PF_LD4, + PA11_PF_LD5, + PA12_PF_LD6, + PA13_PF_LD7, + PA14_PF_LD8, + PA15_PF_LD9, + PA16_PF_LD10, + PA17_PF_LD11, + PA18_PF_LD12, + PA19_PF_LD13, + PA20_PF_LD14, + PA21_PF_LD15, + PA22_PF_LD16, + PA23_PF_LD17, + PA24_PF_REV, + PA25_PF_CLS, + PA26_PF_PS, + PA27_PF_SPL_SPR, + PA28_PF_HSYNC, + PA29_PF_VSYNC, + PA30_PF_CONTRAST, + PA31_PF_OE_ACD, + /* OWIRE */ + PE16_AF_OWIRE, + /* SDHC1*/ + PE18_PF_SD1_D0, + PE19_PF_SD1_D1, + PE20_PF_SD1_D2, + PE21_PF_SD1_D3, + PE22_PF_SD1_CMD, + PE23_PF_SD1_CLK, + /* SDHC2*/ + PB4_PF_SD2_D0, + PB5_PF_SD2_D1, + PB6_PF_SD2_D2, + PB7_PF_SD2_D3, + PB8_PF_SD2_CMD, + PB9_PF_SD2_CLK, +}; + +static struct mxc_nand_platform_data mx27ads_nand_board_info = { + .width = 1, + .hw_ecc = 1, +}; + /* ADS's NOR flash */ static struct physmap_flash_data mx27ads_flash_data = { .width = 2, @@ -58,189 +168,113 @@ static struct platform_device mx27ads_nor_mtd_device = { .resource = &mx27ads_flash_resource, }; -static int mxc_uart0_pins[] = { - PE12_PF_UART1_TXD, - PE13_PF_UART1_RXD, - PE14_PF_UART1_CTS, - PE15_PF_UART1_RTS +static struct imxi2c_platform_data mx27ads_i2c_data = { + .bitrate = 100000, }; -static int uart_mxc_port0_init(struct platform_device *pdev) -{ - return mxc_gpio_setup_multiple_pins(mxc_uart0_pins, - ARRAY_SIZE(mxc_uart0_pins), "UART0"); -} - -static int uart_mxc_port0_exit(struct platform_device *pdev) -{ - mxc_gpio_release_multiple_pins(mxc_uart0_pins, - ARRAY_SIZE(mxc_uart0_pins)); - return 0; -} - -static int mxc_uart1_pins[] = { - PE3_PF_UART2_CTS, - PE4_PF_UART2_RTS, - PE6_PF_UART2_TXD, - PE7_PF_UART2_RXD +static struct i2c_board_info mx27ads_i2c_devices[] = { }; -static int uart_mxc_port1_init(struct platform_device *pdev) +void lcd_power(int on) { - return mxc_gpio_setup_multiple_pins(mxc_uart1_pins, - ARRAY_SIZE(mxc_uart1_pins), "UART1"); + if (on) + __raw_writew(PBC_BCTRL1_LCDON, PBC_BCTRL1_SET_REG); + else + __raw_writew(PBC_BCTRL1_LCDON, PBC_BCTRL1_CLEAR_REG); } -static int uart_mxc_port1_exit(struct platform_device *pdev) -{ - mxc_gpio_release_multiple_pins(mxc_uart1_pins, - ARRAY_SIZE(mxc_uart1_pins)); - return 0; -} +static struct imx_fb_platform_data mx27ads_fb_data = { + .pixclock = 188679, + .xres = 240, + .yres = 320, -static int mxc_uart2_pins[] = { - PE8_PF_UART3_TXD, - PE9_PF_UART3_RXD, - PE10_PF_UART3_CTS, - PE11_PF_UART3_RTS + .bpp = 16, + .hsync_len = 1, + .left_margin = 9, + .right_margin = 16, + + .vsync_len = 1, + .upper_margin = 7, + .lower_margin = 9, + .fixed_screen_cpu = 0, + + /* + * - HSYNC active high + * - VSYNC active high + * - clk notenabled while idle + * - clock inverted + * - data not inverted + * - data enable low active + * - enable sharp mode + */ + .pcr = 0xFB008BC0, + .pwmr = 0x00A903FF, + .lscr1 = 0x00120300, + .dmacr = 0x00020010, + + .lcd_power = lcd_power, }; -static int uart_mxc_port2_init(struct platform_device *pdev) +static int mx27ads_sdhc1_init(struct device *dev, irq_handler_t detect_irq, + void *data) { - return mxc_gpio_setup_multiple_pins(mxc_uart2_pins, - ARRAY_SIZE(mxc_uart2_pins), "UART2"); + return request_irq(IRQ_GPIOE(21), detect_irq, IRQF_TRIGGER_RISING, + "sdhc1-card-detect", data); } -static int uart_mxc_port2_exit(struct platform_device *pdev) +static int mx27ads_sdhc2_init(struct device *dev, irq_handler_t detect_irq, + void *data) { - mxc_gpio_release_multiple_pins(mxc_uart2_pins, - ARRAY_SIZE(mxc_uart2_pins)); - return 0; + return request_irq(IRQ_GPIOB(7), detect_irq, IRQF_TRIGGER_RISING, + "sdhc2-card-detect", data); } -static int mxc_uart3_pins[] = { - PB26_AF_UART4_RTS, - PB28_AF_UART4_TXD, - PB29_AF_UART4_CTS, - PB31_AF_UART4_RXD +static void mx27ads_sdhc1_exit(struct device *dev, void *data) +{ + free_irq(IRQ_GPIOE(21), data); +} + +static void mx27ads_sdhc2_exit(struct device *dev, void *data) +{ + free_irq(IRQ_GPIOB(7), data); +} + +static struct imxmmc_platform_data sdhc1_pdata = { + .init = mx27ads_sdhc1_init, + .exit = mx27ads_sdhc1_exit, }; -static int uart_mxc_port3_init(struct platform_device *pdev) -{ - return mxc_gpio_setup_multiple_pins(mxc_uart3_pins, - ARRAY_SIZE(mxc_uart3_pins), "UART3"); -} - -static int uart_mxc_port3_exit(struct platform_device *pdev) -{ - mxc_gpio_release_multiple_pins(mxc_uart3_pins, - ARRAY_SIZE(mxc_uart3_pins)); - return 0; -} - -static int mxc_uart4_pins[] = { - PB18_AF_UART5_TXD, - PB19_AF_UART5_RXD, - PB20_AF_UART5_CTS, - PB21_AF_UART5_RTS +static struct imxmmc_platform_data sdhc2_pdata = { + .init = mx27ads_sdhc2_init, + .exit = mx27ads_sdhc2_exit, }; -static int uart_mxc_port4_init(struct platform_device *pdev) -{ - return mxc_gpio_setup_multiple_pins(mxc_uart4_pins, - ARRAY_SIZE(mxc_uart4_pins), "UART4"); -} - -static int uart_mxc_port4_exit(struct platform_device *pdev) -{ - mxc_gpio_release_multiple_pins(mxc_uart4_pins, - ARRAY_SIZE(mxc_uart4_pins)); - return 0; -} - -static int mxc_uart5_pins[] = { - PB10_AF_UART6_TXD, - PB12_AF_UART6_CTS, - PB11_AF_UART6_RXD, - PB13_AF_UART6_RTS -}; - -static int uart_mxc_port5_init(struct platform_device *pdev) -{ - return mxc_gpio_setup_multiple_pins(mxc_uart5_pins, - ARRAY_SIZE(mxc_uart5_pins), "UART5"); -} - -static int uart_mxc_port5_exit(struct platform_device *pdev) -{ - mxc_gpio_release_multiple_pins(mxc_uart5_pins, - ARRAY_SIZE(mxc_uart5_pins)); - return 0; -} - static struct platform_device *platform_devices[] __initdata = { &mx27ads_nor_mtd_device, &mxc_fec_device, + &mxc_w1_master_device, }; -static int mxc_fec_pins[] = { - PD0_AIN_FEC_TXD0, - PD1_AIN_FEC_TXD1, - PD2_AIN_FEC_TXD2, - PD3_AIN_FEC_TXD3, - PD4_AOUT_FEC_RX_ER, - PD5_AOUT_FEC_RXD1, - PD6_AOUT_FEC_RXD2, - PD7_AOUT_FEC_RXD3, - PD8_AF_FEC_MDIO, - PD9_AIN_FEC_MDC, - PD10_AOUT_FEC_CRS, - PD11_AOUT_FEC_TX_CLK, - PD12_AOUT_FEC_RXD0, - PD13_AOUT_FEC_RX_DV, - PD14_AOUT_FEC_RX_CLK, - PD15_AOUT_FEC_COL, - PD16_AIN_FEC_TX_ER, - PF23_AIN_FEC_TX_EN -}; - -static void gpio_fec_active(void) -{ - mxc_gpio_setup_multiple_pins(mxc_fec_pins, - ARRAY_SIZE(mxc_fec_pins), "FEC"); -} - static struct imxuart_platform_data uart_pdata[] = { { - .init = uart_mxc_port0_init, - .exit = uart_mxc_port0_exit, .flags = IMXUART_HAVE_RTSCTS, }, { - .init = uart_mxc_port1_init, - .exit = uart_mxc_port1_exit, .flags = IMXUART_HAVE_RTSCTS, }, { - .init = uart_mxc_port2_init, - .exit = uart_mxc_port2_exit, .flags = IMXUART_HAVE_RTSCTS, }, { - .init = uart_mxc_port3_init, - .exit = uart_mxc_port3_exit, .flags = IMXUART_HAVE_RTSCTS, }, { - .init = uart_mxc_port4_init, - .exit = uart_mxc_port4_exit, .flags = IMXUART_HAVE_RTSCTS, }, { - .init = uart_mxc_port5_init, - .exit = uart_mxc_port5_exit, .flags = IMXUART_HAVE_RTSCTS, }, }; static void __init mx27ads_board_init(void) { - gpio_fec_active(); + mxc_gpio_setup_multiple_pins(mx27ads_pins, ARRAY_SIZE(mx27ads_pins), + "mx27ads"); mxc_register_device(&mxc_uart_device0, &uart_pdata[0]); mxc_register_device(&mxc_uart_device1, &uart_pdata[1]); @@ -248,6 +282,15 @@ static void __init mx27ads_board_init(void) mxc_register_device(&mxc_uart_device3, &uart_pdata[3]); mxc_register_device(&mxc_uart_device4, &uart_pdata[4]); mxc_register_device(&mxc_uart_device5, &uart_pdata[5]); + mxc_register_device(&mxc_nand_device, &mx27ads_nand_board_info); + + /* only the i2c master 1 is used on this CPU card */ + i2c_register_board_info(1, mx27ads_i2c_devices, + ARRAY_SIZE(mx27ads_i2c_devices)); + mxc_register_device(&mxc_i2c_device1, &mx27ads_i2c_data); + mxc_register_device(&mxc_fb_device, &mx27ads_fb_data); + mxc_register_device(&mxc_sdhc_device0, &sdhc1_pdata); + mxc_register_device(&mxc_sdhc_device1, &sdhc2_pdata); platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices)); } @@ -277,7 +320,7 @@ static struct map_desc mx27ads_io_desc[] __initdata = { static void __init mx27ads_map_io(void) { - mxc_map_io(); + mx27_map_io(); iotable_init(mx27ads_io_desc, ARRAY_SIZE(mx27ads_io_desc)); } diff --git a/arch/arm/mach-mx2/mx27lite.c b/arch/arm/mach-mx2/mx27lite.c new file mode 100644 index 000000000000..3ae11cb8c04b --- /dev/null +++ b/arch/arm/mach-mx2/mx27lite.c @@ -0,0 +1,95 @@ +/* + * Copyright 2007 Robert Schwebel , Pengutronix + * Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de) + * Copyright 2009 Daniel Schaeffer (daniel.schaeffer@timesys.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "devices.h" + +static unsigned int mx27lite_pins[] = { + /* UART1 */ + PE12_PF_UART1_TXD, + PE13_PF_UART1_RXD, + PE14_PF_UART1_CTS, + PE15_PF_UART1_RTS, + /* FEC */ + PD0_AIN_FEC_TXD0, + PD1_AIN_FEC_TXD1, + PD2_AIN_FEC_TXD2, + PD3_AIN_FEC_TXD3, + PD4_AOUT_FEC_RX_ER, + PD5_AOUT_FEC_RXD1, + PD6_AOUT_FEC_RXD2, + PD7_AOUT_FEC_RXD3, + PD8_AF_FEC_MDIO, + PD9_AIN_FEC_MDC, + PD10_AOUT_FEC_CRS, + PD11_AOUT_FEC_TX_CLK, + PD12_AOUT_FEC_RXD0, + PD13_AOUT_FEC_RX_DV, + PD14_AOUT_FEC_RX_CLK, + PD15_AOUT_FEC_COL, + PD16_AIN_FEC_TX_ER, + PF23_AIN_FEC_TX_EN, +}; + +static struct imxuart_platform_data uart_pdata = { + .flags = IMXUART_HAVE_RTSCTS, +}; + +static struct platform_device *platform_devices[] __initdata = { + &mxc_fec_device, +}; + +static void __init mx27lite_init(void) +{ + mxc_gpio_setup_multiple_pins(mx27lite_pins, ARRAY_SIZE(mx27lite_pins), + "imx27lite"); + mxc_register_device(&mxc_uart_device0, &uart_pdata); + platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices)); +} + +static void __init mx27lite_timer_init(void) +{ + mx27_clocks_init(26000000); +} + +static struct sys_timer mx27lite_timer = { + .init = mx27lite_timer_init, +}; + +MACHINE_START(IMX27LITE, "LogicPD i.MX27LITE") + .phys_io = AIPI_BASE_ADDR, + .io_pg_offst = ((AIPI_BASE_ADDR_VIRT) >> 18) & 0xfffc, + .boot_params = PHYS_OFFSET + 0x100, + .map_io = mx27_map_io, + .init_irq = mxc_init_irq, + .init_machine = mx27lite_init, + .timer = &mx27lite_timer, +MACHINE_END diff --git a/arch/arm/mach-mx2/mx27pdk.c b/arch/arm/mach-mx2/mx27pdk.c new file mode 100644 index 000000000000..1d9238c7a6c3 --- /dev/null +++ b/arch/arm/mach-mx2/mx27pdk.c @@ -0,0 +1,95 @@ +/* + * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved. + * + * Author: Fabio Estevam + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "devices.h" + +static unsigned int mx27pdk_pins[] = { + /* UART1 */ + PE12_PF_UART1_TXD, + PE13_PF_UART1_RXD, + PE14_PF_UART1_CTS, + PE15_PF_UART1_RTS, + /* FEC */ + PD0_AIN_FEC_TXD0, + PD1_AIN_FEC_TXD1, + PD2_AIN_FEC_TXD2, + PD3_AIN_FEC_TXD3, + PD4_AOUT_FEC_RX_ER, + PD5_AOUT_FEC_RXD1, + PD6_AOUT_FEC_RXD2, + PD7_AOUT_FEC_RXD3, + PD8_AF_FEC_MDIO, + PD9_AIN_FEC_MDC, + PD10_AOUT_FEC_CRS, + PD11_AOUT_FEC_TX_CLK, + PD12_AOUT_FEC_RXD0, + PD13_AOUT_FEC_RX_DV, + PD14_AOUT_FEC_RX_CLK, + PD15_AOUT_FEC_COL, + PD16_AIN_FEC_TX_ER, + PF23_AIN_FEC_TX_EN, +}; + +static struct imxuart_platform_data uart_pdata = { + .flags = IMXUART_HAVE_RTSCTS, +}; + +static struct platform_device *platform_devices[] __initdata = { + &mxc_fec_device, +}; + +static void __init mx27pdk_init(void) +{ + mxc_gpio_setup_multiple_pins(mx27pdk_pins, ARRAY_SIZE(mx27pdk_pins), + "mx27pdk"); + mxc_register_device(&mxc_uart_device0, &uart_pdata); + platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices)); +} + +static void __init mx27pdk_timer_init(void) +{ + mx27_clocks_init(26000000); +} + +static struct sys_timer mx27pdk_timer = { + .init = mx27pdk_timer_init, +}; + +MACHINE_START(MX27_3DS, "Freescale MX27PDK") + /* maintainer: Freescale Semiconductor, Inc. */ + .phys_io = AIPI_BASE_ADDR, + .io_pg_offst = ((AIPI_BASE_ADDR_VIRT) >> 18) & 0xfffc, + .boot_params = PHYS_OFFSET + 0x100, + .map_io = mx27_map_io, + .init_irq = mxc_init_irq, + .init_machine = mx27pdk_init, + .timer = &mx27pdk_timer, +MACHINE_END diff --git a/arch/arm/mach-mx2/pcm038.c b/arch/arm/mach-mx2/pcm038.c index aa4eaa61d1b5..a4628d004343 100644 --- a/arch/arm/mach-mx2/pcm038.c +++ b/arch/arm/mach-mx2/pcm038.c @@ -17,28 +17,84 @@ * MA 02110-1301, USA. */ -#include -#include -#include -#include #include #include +#include +#include +#include +#include -#include #include +#include +#include + +#include #include #include -#include -#ifdef CONFIG_I2C_IMX #include -#endif -#include +#include #include -#include #include #include "devices.h" +static int pcm038_pins[] = { + /* UART1 */ + PE12_PF_UART1_TXD, + PE13_PF_UART1_RXD, + PE14_PF_UART1_CTS, + PE15_PF_UART1_RTS, + /* UART2 */ + PE3_PF_UART2_CTS, + PE4_PF_UART2_RTS, + PE6_PF_UART2_TXD, + PE7_PF_UART2_RXD, + /* UART3 */ + PE8_PF_UART3_TXD, + PE9_PF_UART3_RXD, + PE10_PF_UART3_CTS, + PE11_PF_UART3_RTS, + /* FEC */ + PD0_AIN_FEC_TXD0, + PD1_AIN_FEC_TXD1, + PD2_AIN_FEC_TXD2, + PD3_AIN_FEC_TXD3, + PD4_AOUT_FEC_RX_ER, + PD5_AOUT_FEC_RXD1, + PD6_AOUT_FEC_RXD2, + PD7_AOUT_FEC_RXD3, + PD8_AF_FEC_MDIO, + PD9_AIN_FEC_MDC, + PD10_AOUT_FEC_CRS, + PD11_AOUT_FEC_TX_CLK, + PD12_AOUT_FEC_RXD0, + PD13_AOUT_FEC_RX_DV, + PD14_AOUT_FEC_RX_CLK, + PD15_AOUT_FEC_COL, + PD16_AIN_FEC_TX_ER, + PF23_AIN_FEC_TX_EN, + /* I2C2 */ + PC5_PF_I2C2_SDA, + PC6_PF_I2C2_SCL, + /* SPI1 */ + PD25_PF_CSPI1_RDY, + PD27_PF_CSPI1_SS1, + PD28_PF_CSPI1_SS0, + PD29_PF_CSPI1_SCLK, + PD30_PF_CSPI1_MISO, + PD31_PF_CSPI1_MOSI, + /* SSI1 */ + PC20_PF_SSI1_FS, + PC21_PF_SSI1_RXD, + PC22_PF_SSI1_TXD, + PC23_PF_SSI1_CLK, + /* SSI4 */ + PC16_PF_SSI4_FS, + PC17_PF_SSI4_RXD, + PC18_PF_SSI4_TXD, + PC19_PF_SSI4_CLK, +}; + /* * Phytec's PCM038 comes with 2MiB battery buffered SRAM, * 16 bit width @@ -88,107 +144,16 @@ static struct platform_device pcm038_nor_mtd_device = { .resource = &pcm038_flash_resource, }; -static int mxc_uart0_pins[] = { - PE12_PF_UART1_TXD, - PE13_PF_UART1_RXD, - PE14_PF_UART1_CTS, - PE15_PF_UART1_RTS -}; - -static int uart_mxc_port0_init(struct platform_device *pdev) -{ - return mxc_gpio_setup_multiple_pins(mxc_uart0_pins, - ARRAY_SIZE(mxc_uart0_pins), "UART0"); -} - -static int uart_mxc_port0_exit(struct platform_device *pdev) -{ - mxc_gpio_release_multiple_pins(mxc_uart0_pins, - ARRAY_SIZE(mxc_uart0_pins)); - return 0; -} - -static int mxc_uart1_pins[] = { - PE3_PF_UART2_CTS, - PE4_PF_UART2_RTS, - PE6_PF_UART2_TXD, - PE7_PF_UART2_RXD -}; - -static int uart_mxc_port1_init(struct platform_device *pdev) -{ - return mxc_gpio_setup_multiple_pins(mxc_uart1_pins, - ARRAY_SIZE(mxc_uart1_pins), "UART1"); -} - -static int uart_mxc_port1_exit(struct platform_device *pdev) -{ - mxc_gpio_release_multiple_pins(mxc_uart1_pins, - ARRAY_SIZE(mxc_uart1_pins)); - return 0; -} - -static int mxc_uart2_pins[] = { PE8_PF_UART3_TXD, - PE9_PF_UART3_RXD, - PE10_PF_UART3_CTS, - PE11_PF_UART3_RTS }; - -static int uart_mxc_port2_init(struct platform_device *pdev) -{ - return mxc_gpio_setup_multiple_pins(mxc_uart2_pins, - ARRAY_SIZE(mxc_uart2_pins), "UART2"); -} - -static int uart_mxc_port2_exit(struct platform_device *pdev) -{ - mxc_gpio_release_multiple_pins(mxc_uart2_pins, - ARRAY_SIZE(mxc_uart2_pins)); - return 0; -} - static struct imxuart_platform_data uart_pdata[] = { { - .init = uart_mxc_port0_init, - .exit = uart_mxc_port0_exit, .flags = IMXUART_HAVE_RTSCTS, }, { - .init = uart_mxc_port1_init, - .exit = uart_mxc_port1_exit, .flags = IMXUART_HAVE_RTSCTS, }, { - .init = uart_mxc_port2_init, - .exit = uart_mxc_port2_exit, .flags = IMXUART_HAVE_RTSCTS, }, }; -static int mxc_fec_pins[] = { - PD0_AIN_FEC_TXD0, - PD1_AIN_FEC_TXD1, - PD2_AIN_FEC_TXD2, - PD3_AIN_FEC_TXD3, - PD4_AOUT_FEC_RX_ER, - PD5_AOUT_FEC_RXD1, - PD6_AOUT_FEC_RXD2, - PD7_AOUT_FEC_RXD3, - PD8_AF_FEC_MDIO, - PD9_AIN_FEC_MDC, - PD10_AOUT_FEC_CRS, - PD11_AOUT_FEC_TX_CLK, - PD12_AOUT_FEC_RXD0, - PD13_AOUT_FEC_RX_DV, - PD14_AOUT_FEC_RX_CLK, - PD15_AOUT_FEC_COL, - PD16_AIN_FEC_TX_ER, - PF23_AIN_FEC_TX_EN -}; - -static void gpio_fec_active(void) -{ - mxc_gpio_setup_multiple_pins(mxc_fec_pins, - ARRAY_SIZE(mxc_fec_pins), "FEC"); -} - static struct mxc_nand_platform_data pcm038_nand_board_info = { .width = 1, .hw_ecc = 1, @@ -210,27 +175,8 @@ static void __init pcm038_init_sram(void) __raw_writel(0x22220a00, CSCR_A(1)); } -#ifdef CONFIG_I2C_IMX -static int mxc_i2c1_pins[] = { - PC5_PF_I2C2_SDA, - PC6_PF_I2C2_SCL -}; - -static int pcm038_i2c_1_init(struct device *dev) -{ - return mxc_gpio_setup_multiple_pins(mxc_i2c1_pins, ARRAY_SIZE(mxc_i2c1_pins), - "I2C1"); -} - -static void pcm038_i2c_1_exit(struct device *dev) -{ - mxc_gpio_release_multiple_pins(mxc_i2c1_pins, ARRAY_SIZE(mxc_i2c1_pins)); -} - static struct imxi2c_platform_data pcm038_i2c_1_data = { .bitrate = 100000, - .init = pcm038_i2c_1_init, - .exit = pcm038_i2c_1_exit, }; static struct at24_platform_data board_eeprom = { @@ -253,11 +199,12 @@ static struct i2c_board_info pcm038_i2c_devices[] = { .type = "lm75" } }; -#endif static void __init pcm038_init(void) { - gpio_fec_active(); + mxc_gpio_setup_multiple_pins(pcm038_pins, ARRAY_SIZE(pcm038_pins), + "PCM038"); + pcm038_init_sram(); mxc_register_device(&mxc_uart_device0, &uart_pdata[0]); @@ -267,13 +214,11 @@ static void __init pcm038_init(void) mxc_gpio_mode(PE16_AF_OWIRE); mxc_register_device(&mxc_nand_device, &pcm038_nand_board_info); -#ifdef CONFIG_I2C_IMX /* only the i2c master 1 is used on this CPU card */ i2c_register_board_info(1, pcm038_i2c_devices, ARRAY_SIZE(pcm038_i2c_devices)); mxc_register_device(&mxc_i2c_device1, &pcm038_i2c_1_data); -#endif platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices)); @@ -295,7 +240,7 @@ MACHINE_START(PCM038, "phyCORE-i.MX27") .phys_io = AIPI_BASE_ADDR, .io_pg_offst = ((AIPI_BASE_ADDR_VIRT) >> 18) & 0xfffc, .boot_params = PHYS_OFFSET + 0x100, - .map_io = mxc_map_io, + .map_io = mx27_map_io, .init_irq = mxc_init_irq, .init_machine = pcm038_init, .timer = &pcm038_timer, diff --git a/arch/arm/mach-mx2/pcm970-baseboard.c b/arch/arm/mach-mx2/pcm970-baseboard.c index bf4e520bc1bc..6a3acaf57dd4 100644 --- a/arch/arm/mach-mx2/pcm970-baseboard.c +++ b/arch/arm/mach-mx2/pcm970-baseboard.c @@ -16,71 +16,107 @@ * MA 02110-1301, USA. */ -#include #include #include +#include #include -#include #include -#include -#include #include +#include +#include +#include #include "devices.h" -static int pcm970_sdhc2_get_ro(struct device *dev) -{ - return gpio_get_value(GPIO_PORTC + 28); -} - -static int pcm970_sdhc2_pins[] = { +static int pcm970_pins[] = { + /* SDHC */ PB4_PF_SD2_D0, PB5_PF_SD2_D1, PB6_PF_SD2_D2, PB7_PF_SD2_D3, PB8_PF_SD2_CMD, PB9_PF_SD2_CLK, + GPIO_PORTC | 28 | GPIO_GPIO | GPIO_IN, /* card detect */ + /* display */ + PA5_PF_LSCLK, + PA6_PF_LD0, + PA7_PF_LD1, + PA8_PF_LD2, + PA9_PF_LD3, + PA10_PF_LD4, + PA11_PF_LD5, + PA12_PF_LD6, + PA13_PF_LD7, + PA14_PF_LD8, + PA15_PF_LD9, + PA16_PF_LD10, + PA17_PF_LD11, + PA18_PF_LD12, + PA19_PF_LD13, + PA20_PF_LD14, + PA21_PF_LD15, + PA22_PF_LD16, + PA23_PF_LD17, + PA24_PF_REV, + PA25_PF_CLS, + PA26_PF_PS, + PA27_PF_SPL_SPR, + PA28_PF_HSYNC, + PA29_PF_VSYNC, + PA30_PF_CONTRAST, + PA31_PF_OE_ACD, + /* + * it seems the data line misses a pullup, so we must enable + * the internal pullup as a local workaround + */ + PD17_PF_I2C_DATA | GPIO_PUEN, + PD18_PF_I2C_CLK, + /* Camera */ + PB10_PF_CSI_D0, + PB11_PF_CSI_D1, + PB12_PF_CSI_D2, + PB13_PF_CSI_D3, + PB14_PF_CSI_D4, + PB15_PF_CSI_MCLK, + PB16_PF_CSI_PIXCLK, + PB17_PF_CSI_D5, + PB18_PF_CSI_D6, + PB19_PF_CSI_D7, + PB20_PF_CSI_VSYNC, + PB21_PF_CSI_HSYNC, }; +static int pcm970_sdhc2_get_ro(struct device *dev) +{ + return gpio_get_value(GPIO_PORTC + 28); +} + static int pcm970_sdhc2_init(struct device *dev, irq_handler_t detect_irq, void *data) { int ret; - ret = mxc_gpio_setup_multiple_pins(pcm970_sdhc2_pins, - ARRAY_SIZE(pcm970_sdhc2_pins), "sdhc2"); - if(ret) - return ret; - - ret = request_irq(IRQ_GPIOC(29), detect_irq, 0, + ret = request_irq(IRQ_GPIOC(29), detect_irq, IRQF_TRIGGER_FALLING, "imx-mmc-detect", data); if (ret) - goto out_release_gpio; - - set_irq_type(IRQ_GPIOC(29), IRQF_TRIGGER_FALLING); + return ret; ret = gpio_request(GPIO_PORTC + 28, "imx-mmc-ro"); - if (ret) - goto out_release_gpio; + if (ret) { + free_irq(IRQ_GPIOC(29), data); + return ret; + } - mxc_gpio_mode((GPIO_PORTC | 28) | GPIO_GPIO | GPIO_IN); gpio_direction_input(GPIO_PORTC + 28); return 0; - -out_release_gpio: - mxc_gpio_release_multiple_pins(pcm970_sdhc2_pins, - ARRAY_SIZE(pcm970_sdhc2_pins)); - return ret; } static void pcm970_sdhc2_exit(struct device *dev, void *data) { free_irq(IRQ_GPIOC(29), data); gpio_free(GPIO_PORTC + 28); - mxc_gpio_release_multiple_pins(pcm970_sdhc2_pins, - ARRAY_SIZE(pcm970_sdhc2_pins)); } static struct imxmmc_platform_data sdhc_pdata = { @@ -89,29 +125,6 @@ static struct imxmmc_platform_data sdhc_pdata = { .exit = pcm970_sdhc2_exit, }; -static int mxc_fb_pins[] = { - PA5_PF_LSCLK, PA6_PF_LD0, PA7_PF_LD1, PA8_PF_LD2, - PA9_PF_LD3, PA10_PF_LD4, PA11_PF_LD5, PA12_PF_LD6, - PA13_PF_LD7, PA14_PF_LD8, PA15_PF_LD9, PA16_PF_LD10, - PA17_PF_LD11, PA18_PF_LD12, PA19_PF_LD13, PA20_PF_LD14, - PA21_PF_LD15, PA22_PF_LD16, PA23_PF_LD17, PA24_PF_REV, - PA25_PF_CLS, PA26_PF_PS, PA27_PF_SPL_SPR, PA28_PF_HSYNC, - PA29_PF_VSYNC, PA30_PF_CONTRAST, PA31_PF_OE_ACD -}; - -static int pcm038_fb_init(struct platform_device *pdev) -{ - return mxc_gpio_setup_multiple_pins(mxc_fb_pins, - ARRAY_SIZE(mxc_fb_pins), "FB"); -} - -static int pcm038_fb_exit(struct platform_device *pdev) -{ - mxc_gpio_release_multiple_pins(mxc_fb_pins, ARRAY_SIZE(mxc_fb_pins)); - - return 0; -} - /* * Connected is a portrait Sharp-QVGA display * of type: LQ035Q7DH06 @@ -144,9 +157,6 @@ static struct imx_fb_platform_data pcm038_fb_data = { .pwmr = 0x00A903FF, .lscr1 = 0x00120300, .dmacr = 0x00020010, - - .init = pcm038_fb_init, - .exit = pcm038_fb_exit, }; /* @@ -157,6 +167,9 @@ static struct imx_fb_platform_data pcm038_fb_data = { */ void __init pcm970_baseboard_init(void) { + mxc_gpio_setup_multiple_pins(pcm970_pins, ARRAY_SIZE(pcm970_pins), + "PCM970"); + mxc_register_device(&mxc_fb_device, &pcm038_fb_data); mxc_register_device(&mxc_sdhc_device1, &sdhc_pdata); } diff --git a/arch/arm/mach-mx3/Kconfig b/arch/arm/mach-mx3/Kconfig index 194b8428bba4..17a21a291e2f 100644 --- a/arch/arm/mach-mx3/Kconfig +++ b/arch/arm/mach-mx3/Kconfig @@ -1,10 +1,12 @@ if ARCH_MX3 config ARCH_MX31 + select ARCH_HAS_RNGA bool config ARCH_MX35 bool + select ARCH_MXC_IOMUX_V3 comment "MX3 platforms:" @@ -37,7 +39,6 @@ config MACH_PCM037 config MACH_MX31LITE bool "Support MX31 LITEKIT (LogicPD)" select ARCH_MX31 - default n help Include support for MX31 LITEKIT platform. This includes specific configurations for the board and its peripherals. @@ -45,7 +46,6 @@ config MACH_MX31LITE config MACH_MX31_3DS bool "Support MX31PDK (3DS)" select ARCH_MX31 - default n help Include support for MX31PDK (3DS) platform. This includes specific configurations for the board and its peripherals. @@ -53,17 +53,43 @@ config MACH_MX31_3DS config MACH_MX31MOBOARD bool "Support mx31moboard platforms (EPFL Mobots group)" select ARCH_MX31 - default n help Include support for mx31moboard platform. This includes specific configurations for the board and its peripherals. +config MACH_MX31LILLY + bool "Support MX31 LILLY-1131 platforms (INCO startec)" + select ARCH_MX31 + help + Include support for mx31 based LILLY1131 modules. This includes + specific configurations for the board and its peripherals. + config MACH_QONG bool "Support Dave/DENX QongEVB-LITE platform" select ARCH_MX31 - default n help Include support for Dave/DENX QongEVB-LITE platform. This includes specific configurations for the board and its peripherals. +config MACH_PCM043 + bool "Support Phytec pcm043 (i.MX35) platforms" + select ARCH_MX35 + help + Include support for Phytec pcm043 platform. This includes + specific configurations for the board and its peripherals. + +config MACH_ARMADILLO5X0 + bool "Support Atmark Armadillo-500 Development Base Board" + select ARCH_MX31 + help + Include support for Atmark Armadillo-500 platform. This includes + specific configurations for the board and its peripherals. + +config MACH_MX35_3DS + bool "Support MX35PDK platform" + select ARCH_MX35 + default n + help + Include support for MX35PDK platform. This includes specific + configurations for the board and its peripherals. endif diff --git a/arch/arm/mach-mx3/Makefile b/arch/arm/mach-mx3/Makefile index 272c8a953b30..0322696bd11a 100644 --- a/arch/arm/mach-mx3/Makefile +++ b/arch/arm/mach-mx3/Makefile @@ -8,9 +8,13 @@ obj-y := mm.o devices.o obj-$(CONFIG_ARCH_MX31) += clock.o iomux.o obj-$(CONFIG_ARCH_MX35) += clock-imx35.o obj-$(CONFIG_MACH_MX31ADS) += mx31ads.o +obj-$(CONFIG_MACH_MX31LILLY) += mx31lilly.o mx31lilly-db.o obj-$(CONFIG_MACH_MX31LITE) += mx31lite.o obj-$(CONFIG_MACH_PCM037) += pcm037.o obj-$(CONFIG_MACH_MX31_3DS) += mx31pdk.o obj-$(CONFIG_MACH_MX31MOBOARD) += mx31moboard.o mx31moboard-devboard.o \ mx31moboard-marxbot.o obj-$(CONFIG_MACH_QONG) += qong.o +obj-$(CONFIG_MACH_PCM043) += pcm043.o +obj-$(CONFIG_MACH_ARMADILLO5X0) += armadillo5x0.o +obj-$(CONFIG_MACH_MX35_3DS) += mx35pdk.o diff --git a/arch/arm/mach-mx3/armadillo5x0.c b/arch/arm/mach-mx3/armadillo5x0.c new file mode 100644 index 000000000000..541181090b37 --- /dev/null +++ b/arch/arm/mach-mx3/armadillo5x0.c @@ -0,0 +1,295 @@ +/* + * armadillo5x0.c + * + * Copyright 2009 Alberto Panizzo + * updates in http://alberdroid.blogspot.com/ + * + * Based on Atmark Techno, Inc. armadillo 500 BSP 2008 + * Based on mx31ads.c and pcm037.c Great Work! + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "devices.h" + +static int armadillo5x0_pins[] = { + /* UART1 */ + MX31_PIN_CTS1__CTS1, + MX31_PIN_RTS1__RTS1, + MX31_PIN_TXD1__TXD1, + MX31_PIN_RXD1__RXD1, + /* UART2 */ + MX31_PIN_CTS2__CTS2, + MX31_PIN_RTS2__RTS2, + MX31_PIN_TXD2__TXD2, + MX31_PIN_RXD2__RXD2, + /* LAN9118_IRQ */ + IOMUX_MODE(MX31_PIN_GPIO1_0, IOMUX_CONFIG_GPIO), + /* SDHC1 */ + MX31_PIN_SD1_DATA3__SD1_DATA3, + MX31_PIN_SD1_DATA2__SD1_DATA2, + MX31_PIN_SD1_DATA1__SD1_DATA1, + MX31_PIN_SD1_DATA0__SD1_DATA0, + MX31_PIN_SD1_CLK__SD1_CLK, + MX31_PIN_SD1_CMD__SD1_CMD, + /* Framebuffer */ + MX31_PIN_LD0__LD0, + MX31_PIN_LD1__LD1, + MX31_PIN_LD2__LD2, + MX31_PIN_LD3__LD3, + MX31_PIN_LD4__LD4, + MX31_PIN_LD5__LD5, + MX31_PIN_LD6__LD6, + MX31_PIN_LD7__LD7, + MX31_PIN_LD8__LD8, + MX31_PIN_LD9__LD9, + MX31_PIN_LD10__LD10, + MX31_PIN_LD11__LD11, + MX31_PIN_LD12__LD12, + MX31_PIN_LD13__LD13, + MX31_PIN_LD14__LD14, + MX31_PIN_LD15__LD15, + MX31_PIN_LD16__LD16, + MX31_PIN_LD17__LD17, + MX31_PIN_VSYNC3__VSYNC3, + MX31_PIN_HSYNC__HSYNC, + MX31_PIN_FPSHIFT__FPSHIFT, + MX31_PIN_DRDY0__DRDY0, + IOMUX_MODE(MX31_PIN_LCS1, IOMUX_CONFIG_GPIO), /*ADV7125_PSAVE*/ + +}; + +/* + * FB support + */ +static const struct fb_videomode fb_modedb[] = { + { /* 640x480 @ 60 Hz */ + .name = "CRT-VGA", + .refresh = 60, + .xres = 640, + .yres = 480, + .pixclock = 39721, + .left_margin = 35, + .right_margin = 115, + .upper_margin = 43, + .lower_margin = 1, + .hsync_len = 10, + .vsync_len = 1, + .sync = FB_SYNC_OE_ACT_HIGH, + .vmode = FB_VMODE_NONINTERLACED, + .flag = 0, + }, {/* 800x600 @ 56 Hz */ + .name = "CRT-SVGA", + .refresh = 56, + .xres = 800, + .yres = 600, + .pixclock = 30000, + .left_margin = 30, + .right_margin = 108, + .upper_margin = 13, + .lower_margin = 10, + .hsync_len = 10, + .vsync_len = 1, + .sync = FB_SYNC_OE_ACT_HIGH | FB_SYNC_HOR_HIGH_ACT | + FB_SYNC_VERT_HIGH_ACT, + .vmode = FB_VMODE_NONINTERLACED, + .flag = 0, + }, +}; + +static struct ipu_platform_data mx3_ipu_data = { + .irq_base = MXC_IPU_IRQ_START, +}; + +static struct mx3fb_platform_data mx3fb_pdata = { + .dma_dev = &mx3_ipu.dev, + .name = "CRT-VGA", + .mode = fb_modedb, + .num_modes = ARRAY_SIZE(fb_modedb), +}; + +/* + * SDHC 1 + * MMC support + */ +static int armadillo5x0_sdhc1_get_ro(struct device *dev) +{ + return gpio_get_value(IOMUX_TO_GPIO(MX31_PIN_ATA_RESET_B)); +} + +static int armadillo5x0_sdhc1_init(struct device *dev, + irq_handler_t detect_irq, void *data) +{ + int ret; + int gpio_det, gpio_wp; + + gpio_det = IOMUX_TO_GPIO(MX31_PIN_ATA_DMACK); + gpio_wp = IOMUX_TO_GPIO(MX31_PIN_ATA_RESET_B); + + ret = gpio_request(gpio_det, "sdhc-card-detect"); + if (ret) + return ret; + + gpio_direction_input(gpio_det); + + ret = gpio_request(gpio_wp, "sdhc-write-protect"); + if (ret) + goto err_gpio_free; + + gpio_direction_input(gpio_wp); + + /* When supported the trigger type have to be BOTH */ + ret = request_irq(IOMUX_TO_IRQ(MX31_PIN_ATA_DMACK), detect_irq, + IRQF_DISABLED | IRQF_TRIGGER_FALLING, + "sdhc-detect", data); + + if (ret) + goto err_gpio_free_2; + + return 0; + +err_gpio_free_2: + gpio_free(gpio_wp); + +err_gpio_free: + gpio_free(gpio_det); + + return ret; + +} + +static void armadillo5x0_sdhc1_exit(struct device *dev, void *data) +{ + free_irq(IOMUX_TO_IRQ(MX31_PIN_ATA_DMACK), data); + gpio_free(IOMUX_TO_GPIO(MX31_PIN_ATA_DMACK)); + gpio_free(IOMUX_TO_GPIO(MX31_PIN_ATA_RESET_B)); +} + +static struct imxmmc_platform_data sdhc_pdata = { + .get_ro = armadillo5x0_sdhc1_get_ro, + .init = armadillo5x0_sdhc1_init, + .exit = armadillo5x0_sdhc1_exit, +}; + +/* + * SMSC 9118 + * Network support + */ +static struct resource armadillo5x0_smc911x_resources[] = { + { + .start = CS3_BASE_ADDR, + .end = CS3_BASE_ADDR + SZ_32M - 1, + .flags = IORESOURCE_MEM, + }, { + .start = IOMUX_TO_IRQ(MX31_PIN_GPIO1_0), + .end = IOMUX_TO_IRQ(MX31_PIN_GPIO1_0), + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL, + }, +}; + +static struct smsc911x_platform_config smsc911x_info = { + .flags = SMSC911X_USE_32BIT, + .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW, + .irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL, +}; + +static struct platform_device armadillo5x0_smc911x_device = { + .name = "smsc911x", + .id = -1, + .num_resources = ARRAY_SIZE(armadillo5x0_smc911x_resources), + .resource = armadillo5x0_smc911x_resources, + .dev = { + .platform_data = &smsc911x_info, + }, +}; + +/* UART device data */ +static struct imxuart_platform_data uart_pdata = { + .flags = IMXUART_HAVE_RTSCTS, +}; + +static struct platform_device *devices[] __initdata = { + &armadillo5x0_smc911x_device, +}; + +/* + * Perform board specific initializations + */ +static void __init armadillo5x0_init(void) +{ + mxc_iomux_setup_multiple_pins(armadillo5x0_pins, + ARRAY_SIZE(armadillo5x0_pins), "armadillo5x0"); + + platform_add_devices(devices, ARRAY_SIZE(devices)); + + /* Register UART */ + mxc_register_device(&mxc_uart_device0, &uart_pdata); + mxc_register_device(&mxc_uart_device1, &uart_pdata); + + /* SMSC9118 IRQ pin */ + gpio_direction_input(MX31_PIN_GPIO1_0); + + /* Register SDHC */ + mxc_register_device(&mxcsdhc_device0, &sdhc_pdata); + + /* Register FB */ + mxc_register_device(&mx3_ipu, &mx3_ipu_data); + mxc_register_device(&mx3_fb, &mx3fb_pdata); +} + +static void __init armadillo5x0_timer_init(void) +{ + mx31_clocks_init(26000000); +} + +static struct sys_timer armadillo5x0_timer = { + .init = armadillo5x0_timer_init, +}; + +MACHINE_START(ARMADILLO5X0, "Armadillo-500") + /* Maintainer: Alberto Panizzo */ + .phys_io = AIPS1_BASE_ADDR, + .io_pg_offst = ((AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc, + .boot_params = PHYS_OFFSET + 0x00000100, + .map_io = mx31_map_io, + .init_irq = mxc_init_irq, + .timer = &armadillo5x0_timer, + .init_machine = armadillo5x0_init, +MACHINE_END diff --git a/arch/arm/mach-mx3/clock-imx35.c b/arch/arm/mach-mx3/clock-imx35.c index 3c1e06f56dd6..577ee83d1f60 100644 --- a/arch/arm/mach-mx3/clock-imx35.c +++ b/arch/arm/mach-mx3/clock-imx35.c @@ -147,34 +147,16 @@ static struct arm_ahb_div clk_consumer[] = { { .arm = 0, .ahb = 0, .sel = 0}, }; -static struct arm_ahb_div clk_automotive[] = { - { .arm = 1, .ahb = 3, .sel = 0}, - { .arm = 1, .ahb = 2, .sel = 1}, - { .arm = 2, .ahb = 1, .sel = 1}, - { .arm = 0, .ahb = 0, .sel = 0}, - { .arm = 1, .ahb = 6, .sel = 0}, - { .arm = 1, .ahb = 4, .sel = 1}, - { .arm = 2, .ahb = 2, .sel = 1}, - { .arm = 0, .ahb = 0, .sel = 0}, -}; - static unsigned long get_rate_arm(void) { unsigned long pdr0 = __raw_readl(CCM_BASE + CCM_PDR0); struct arm_ahb_div *aad; unsigned long fref = get_rate_mpll(); - if (pdr0 & 1) { - /* consumer path */ - aad = &clk_consumer[(pdr0 >> 16) & 0xf]; - if (aad->sel) - fref = fref * 2 / 3; - } else { - /* auto path */ - aad = &clk_automotive[(pdr0 >> 9) & 0x7]; - if (aad->sel) - fref = fref * 3 / 4; - } + aad = &clk_consumer[(pdr0 >> 16) & 0xf]; + if (aad->sel) + fref = fref * 2 / 3; + return fref / aad->arm; } @@ -184,12 +166,7 @@ static unsigned long get_rate_ahb(struct clk *clk) struct arm_ahb_div *aad; unsigned long fref = get_rate_mpll(); - if (pdr0 & 1) - /* consumer path */ - aad = &clk_consumer[(pdr0 >> 16) & 0xf]; - else - /* auto path */ - aad = &clk_automotive[(pdr0 >> 9) & 0x7]; + aad = &clk_consumer[(pdr0 >> 16) & 0xf]; return fref / aad->ahb; } @@ -430,7 +407,8 @@ static struct clk_lookup lookups[] = { _REGISTER_CLOCK("imx-i2c.1", NULL, i2c2_clk) _REGISTER_CLOCK("imx-i2c.2", NULL, i2c3_clk) _REGISTER_CLOCK(NULL, "iomuxc", iomuxc_clk) - _REGISTER_CLOCK(NULL, "ipu", ipu_clk) + _REGISTER_CLOCK("ipu-core", NULL, ipu_clk) + _REGISTER_CLOCK("mx3_sdc_fb", NULL, ipu_clk) _REGISTER_CLOCK(NULL, "kpp", kpp_clk) _REGISTER_CLOCK(NULL, "mlb", mlb_clk) _REGISTER_CLOCK(NULL, "mshc", mshc_clk) @@ -462,8 +440,6 @@ int __init mx35_clocks_init() int i; unsigned int ll = 0; - mxc_set_cpu_type(MXC_CPU_MX35); - #ifdef CONFIG_DEBUG_LL_CONSOLE ll = (3 << 16); #endif diff --git a/arch/arm/mach-mx3/clock.c b/arch/arm/mach-mx3/clock.c index a68fcf981edf..8b14239724c9 100644 --- a/arch/arm/mach-mx3/clock.c +++ b/arch/arm/mach-mx3/clock.c @@ -483,7 +483,7 @@ DEFINE_CLOCK(i2c3_clk, 2, MXC_CCM_CGR0, 30, NULL, NULL, &perclk_clk); DEFINE_CLOCK(mpeg4_clk, 0, MXC_CCM_CGR1, 0, NULL, NULL, &ahb_clk); DEFINE_CLOCK(mstick1_clk, 0, MXC_CCM_CGR1, 2, mstick1_get_rate, NULL, &usb_pll_clk); DEFINE_CLOCK(mstick2_clk, 1, MXC_CCM_CGR1, 4, mstick2_get_rate, NULL, &usb_pll_clk); -DEFINE_CLOCK1(csi_clk, 0, MXC_CCM_CGR1, 6, csi, NULL, &ahb_clk); +DEFINE_CLOCK1(csi_clk, 0, MXC_CCM_CGR1, 6, csi, NULL, &serial_pll_clk); DEFINE_CLOCK(rtc_clk, 0, MXC_CCM_CGR1, 8, NULL, NULL, &ipg_clk); DEFINE_CLOCK(wdog_clk, 0, MXC_CCM_CGR1, 10, NULL, NULL, &ipg_clk); DEFINE_CLOCK(pwm_clk, 0, MXC_CCM_CGR1, 12, NULL, NULL, &perclk_clk); @@ -566,13 +566,18 @@ int __init mx31_clocks_init(unsigned long fref) u32 reg; int i; - mxc_set_cpu_type(MXC_CPU_MX31); - ckih_rate = fref; for (i = 0; i < ARRAY_SIZE(lookups); i++) clkdev_add(&lookups[i]); + /* change the csi_clk parent if necessary */ + reg = __raw_readl(MXC_CCM_CCMR); + if (!(reg & MXC_CCM_CCMR_CSCS)) + if (clk_set_parent(&csi_clk, &usb_pll_clk)) + pr_err("%s: error changing csi_clk parent\n", __func__); + + /* Turn off all possible clocks */ __raw_writel((3 << 4), MXC_CCM_CGR0); __raw_writel(0, MXC_CCM_CGR1); @@ -581,6 +586,12 @@ int __init mx31_clocks_init(unsigned long fref) MX32, but still required to be set */ MXC_CCM_CGR2); + /* + * Before turning off usb_pll make sure ipg_per_clk is generated + * by ipg_clk and not usb_pll. + */ + __raw_writel(__raw_readl(MXC_CCM_CCMR) | (1 << 24), MXC_CCM_CCMR); + usb_pll_disable(&usb_pll_clk); pr_info("Clock input source is %ld\n", clk_get_rate(&ckih_clk)); diff --git a/arch/arm/mach-mx3/devices.c b/arch/arm/mach-mx3/devices.c index 380be0c9b213..d927eddcad46 100644 --- a/arch/arm/mach-mx3/devices.c +++ b/arch/arm/mach-mx3/devices.c @@ -17,13 +17,17 @@ * Boston, MA 02110-1301, USA. */ +#include #include #include #include #include +#include #include #include +#include #include +#include #include "devices.h" @@ -283,6 +287,21 @@ struct platform_device mxcsdhc_device1 = { .num_resources = ARRAY_SIZE(mxcsdhc1_resources), .resource = mxcsdhc1_resources, }; + +static struct resource rnga_resources[] = { + { + .start = RNGA_BASE_ADDR, + .end = RNGA_BASE_ADDR + 0x28, + .flags = IORESOURCE_MEM, + }, +}; + +struct platform_device mxc_rnga_device = { + .name = "mxc_rnga", + .id = -1, + .num_resources = 1, + .resource = rnga_resources, +}; #endif /* CONFIG_ARCH_MX31 */ /* i.MX31 Image Processing Unit */ @@ -329,10 +348,54 @@ struct platform_device mx3_fb = { .num_resources = ARRAY_SIZE(fb_resources), .resource = fb_resources, .dev = { - .coherent_dma_mask = 0xffffffff, + .coherent_dma_mask = DMA_BIT_MASK(32), }, }; +static struct resource camera_resources[] = { + { + .start = IPU_CTRL_BASE_ADDR + 0x60, + .end = IPU_CTRL_BASE_ADDR + 0x87, + .flags = IORESOURCE_MEM, + }, +}; + +struct platform_device mx3_camera = { + .name = "mx3-camera", + .id = 0, + .num_resources = ARRAY_SIZE(camera_resources), + .resource = camera_resources, + .dev = { + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +static struct resource otg_resources[] = { + { + .start = OTG_BASE_ADDR, + .end = OTG_BASE_ADDR + 0x1ff, + .flags = IORESOURCE_MEM, + }, { + .start = MXC_INT_USB3, + .end = MXC_INT_USB3, + .flags = IORESOURCE_IRQ, + }, +}; + +static u64 otg_dmamask = DMA_BIT_MASK(32); + +/* OTG gadget device */ +struct platform_device mxc_otg_udc_device = { + .name = "fsl-usb2-udc", + .id = -1, + .dev = { + .dma_mask = &otg_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + .resource = otg_resources, + .num_resources = ARRAY_SIZE(otg_resources), +}; + #ifdef CONFIG_ARCH_MX35 static struct resource mxc_fec_resources[] = { { @@ -359,6 +422,7 @@ static int mx3_devices_init(void) if (cpu_is_mx31()) { mxc_nand_resources[0].start = MX31_NFC_BASE_ADDR; mxc_nand_resources[0].end = MX31_NFC_BASE_ADDR + 0xfff; + mxc_register_device(&mxc_rnga_device, NULL); } if (cpu_is_mx35()) { mxc_nand_resources[0].start = MX35_NFC_BASE_ADDR; diff --git a/arch/arm/mach-mx3/devices.h b/arch/arm/mach-mx3/devices.h index 88c04b296fab..ffd494ddd4ac 100644 --- a/arch/arm/mach-mx3/devices.h +++ b/arch/arm/mach-mx3/devices.h @@ -11,6 +11,10 @@ extern struct platform_device mxc_i2c_device1; extern struct platform_device mxc_i2c_device2; extern struct platform_device mx3_ipu; extern struct platform_device mx3_fb; +extern struct platform_device mx3_camera; extern struct platform_device mxc_fec_device; extern struct platform_device mxcsdhc_device0; extern struct platform_device mxcsdhc_device1; +extern struct platform_device mxc_otg_udc_device; +extern struct platform_device mxc_rnga_device; + diff --git a/arch/arm/mach-mx3/iomux.c b/arch/arm/mach-mx3/iomux.c index 40ffc5a664d9..c66ccbcdc11b 100644 --- a/arch/arm/mach-mx3/iomux.c +++ b/arch/arm/mach-mx3/iomux.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include @@ -94,15 +93,13 @@ void mxc_iomux_set_pad(enum iomux_pins pin, u32 config) EXPORT_SYMBOL(mxc_iomux_set_pad); /* - * setups a single pin: + * allocs a single pin: * - reserves the pin so that it is not claimed by another driver * - setups the iomux according to the configuration - * - if the pin is configured as a GPIO, we claim it through kernel gpiolib */ -int mxc_iomux_setup_pin(const unsigned int pin, const char *label) +int mxc_iomux_alloc_pin(const unsigned int pin, const char *label) { unsigned pad = pin & IOMUX_PADNUM_MASK; - unsigned gpio; if (pad >= (PIN_MAX + 1)) { printk(KERN_ERR "mxc_iomux: Attempt to request nonexistant pin %u for \"%s\"\n", @@ -113,19 +110,13 @@ int mxc_iomux_setup_pin(const unsigned int pin, const char *label) if (test_and_set_bit(pad, mxc_pin_alloc_map)) { printk(KERN_ERR "mxc_iomux: pin %u already used. Allocation for \"%s\" failed\n", pad, label ? label : "?"); - return -EINVAL; + return -EBUSY; } mxc_iomux_mode(pin); - /* if we have a gpio, we can allocate it */ - gpio = (pin & IOMUX_GPIONUM_MASK) >> IOMUX_GPIONUM_SHIFT; - if (gpio < (GPIO_PORT_MAX + 1) * 32) - if (gpio_request(gpio, label)) - return -EINVAL; - return 0; } -EXPORT_SYMBOL(mxc_iomux_setup_pin); +EXPORT_SYMBOL(mxc_iomux_alloc_pin); int mxc_iomux_setup_multiple_pins(unsigned int *pin_list, unsigned count, const char *label) @@ -135,7 +126,8 @@ int mxc_iomux_setup_multiple_pins(unsigned int *pin_list, unsigned count, int ret = -EINVAL; for (i = 0; i < count; i++) { - if (mxc_iomux_setup_pin(*p, label)) + ret = mxc_iomux_alloc_pin(*p, label); + if (ret) goto setup_error; p++; } @@ -150,14 +142,9 @@ EXPORT_SYMBOL(mxc_iomux_setup_multiple_pins); void mxc_iomux_release_pin(const unsigned int pin) { unsigned pad = pin & IOMUX_PADNUM_MASK; - unsigned gpio; if (pad < (PIN_MAX + 1)) clear_bit(pad, mxc_pin_alloc_map); - - gpio = (pin & IOMUX_GPIONUM_MASK) >> IOMUX_GPIONUM_SHIFT; - if (gpio < (GPIO_PORT_MAX + 1) * 32) - gpio_free(gpio); } EXPORT_SYMBOL(mxc_iomux_release_pin); diff --git a/arch/arm/mach-mx3/mm.c b/arch/arm/mach-mx3/mm.c index 9e1459cb4b74..1f5fdd456cb9 100644 --- a/arch/arm/mach-mx3/mm.c +++ b/arch/arm/mach-mx3/mm.c @@ -72,8 +72,17 @@ static struct map_desc mxc_io_desc[] __initdata = { * system startup to create static physical to virtual memory mappings * for the IO modules. */ -void __init mxc_map_io(void) +void __init mx31_map_io(void) { + mxc_set_cpu_type(MXC_CPU_MX31); + + iotable_init(mxc_io_desc, ARRAY_SIZE(mxc_io_desc)); +} + +void __init mx35_map_io(void) +{ + mxc_set_cpu_type(MXC_CPU_MX35); + iotable_init(mxc_io_desc, ARRAY_SIZE(mxc_io_desc)); } diff --git a/arch/arm/mach-mx3/mx31ads.c b/arch/arm/mach-mx3/mx31ads.c index a6d6efefa6aa..30e2767a78ae 100644 --- a/arch/arm/mach-mx3/mx31ads.c +++ b/arch/arm/mach-mx3/mx31ads.c @@ -187,7 +187,7 @@ static void __init mx31ads_init_expio(void) /* * Configure INT line as GPIO input */ - mxc_iomux_setup_pin(IOMUX_MODE(MX31_PIN_GPIO1_4, IOMUX_CONFIG_GPIO), "expio"); + mxc_iomux_alloc_pin(IOMUX_MODE(MX31_PIN_GPIO1_4, IOMUX_CONFIG_GPIO), "expio"); /* disable the interrupt and clear the status */ __raw_writew(0xFFFF, PBC_INTMASK_CLEAR_REG); @@ -511,7 +511,7 @@ static struct map_desc mx31ads_io_desc[] __initdata = { */ static void __init mx31ads_map_io(void) { - mxc_map_io(); + mx31_map_io(); iotable_init(mx31ads_io_desc, ARRAY_SIZE(mx31ads_io_desc)); } diff --git a/arch/arm/mach-mx3/mx31lilly-db.c b/arch/arm/mach-mx3/mx31lilly-db.c new file mode 100644 index 000000000000..3b3a78f49c23 --- /dev/null +++ b/arch/arm/mach-mx3/mx31lilly-db.c @@ -0,0 +1,216 @@ +/* + * LILLY-1131 development board support + * + * Copyright (c) 2009 Daniel Mack + * + * based on code for other MX31 boards, + * + * Copyright 2005-2007 Freescale Semiconductor + * Copyright (c) 2009 Alberto Panizzo + * Copyright (C) 2009 Valentin Longchamp, EPFL Mobots group + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "devices.h" + +/* + * This file contains board-specific initialization routines for the + * LILLY-1131 development board. If you design an own baseboard for the + * module, use this file as base for support code. + */ + +static unsigned int lilly_db_board_pins[] __initdata = { + MX31_PIN_CTS1__CTS1, + MX31_PIN_RTS1__RTS1, + MX31_PIN_TXD1__TXD1, + MX31_PIN_RXD1__RXD1, + MX31_PIN_CTS2__CTS2, + MX31_PIN_RTS2__RTS2, + MX31_PIN_TXD2__TXD2, + MX31_PIN_RXD2__RXD2, + MX31_PIN_CSPI3_MOSI__RXD3, + MX31_PIN_CSPI3_MISO__TXD3, + MX31_PIN_CSPI3_SCLK__RTS3, + MX31_PIN_CSPI3_SPI_RDY__CTS3, + MX31_PIN_SD1_DATA3__SD1_DATA3, + MX31_PIN_SD1_DATA2__SD1_DATA2, + MX31_PIN_SD1_DATA1__SD1_DATA1, + MX31_PIN_SD1_DATA0__SD1_DATA0, + MX31_PIN_SD1_CLK__SD1_CLK, + MX31_PIN_SD1_CMD__SD1_CMD, + MX31_PIN_LD0__LD0, + MX31_PIN_LD1__LD1, + MX31_PIN_LD2__LD2, + MX31_PIN_LD3__LD3, + MX31_PIN_LD4__LD4, + MX31_PIN_LD5__LD5, + MX31_PIN_LD6__LD6, + MX31_PIN_LD7__LD7, + MX31_PIN_LD8__LD8, + MX31_PIN_LD9__LD9, + MX31_PIN_LD10__LD10, + MX31_PIN_LD11__LD11, + MX31_PIN_LD12__LD12, + MX31_PIN_LD13__LD13, + MX31_PIN_LD14__LD14, + MX31_PIN_LD15__LD15, + MX31_PIN_LD16__LD16, + MX31_PIN_LD17__LD17, + MX31_PIN_VSYNC3__VSYNC3, + MX31_PIN_HSYNC__HSYNC, + MX31_PIN_FPSHIFT__FPSHIFT, + MX31_PIN_DRDY0__DRDY0, + MX31_PIN_CONTRAST__CONTRAST, +}; + +/* UART */ +static struct imxuart_platform_data uart_pdata __initdata = { + .flags = IMXUART_HAVE_RTSCTS, +}; + +/* MMC support */ + +static int mxc_mmc1_get_ro(struct device *dev) +{ + return gpio_get_value(IOMUX_TO_GPIO(MX31_PIN_LCS0)); +} + +static int gpio_det, gpio_wp; + +static int mxc_mmc1_init(struct device *dev, + irq_handler_t detect_irq, void *data) +{ + int ret; + + gpio_det = IOMUX_TO_GPIO(MX31_PIN_GPIO1_1); + gpio_wp = IOMUX_TO_GPIO(MX31_PIN_LCS0); + + ret = gpio_request(gpio_det, "MMC detect"); + if (ret) + return ret; + + ret = gpio_request(gpio_wp, "MMC w/p"); + if (ret) + goto exit_free_det; + + gpio_direction_input(gpio_det); + gpio_direction_input(gpio_wp); + + ret = request_irq(IOMUX_TO_IRQ(MX31_PIN_GPIO1_1), detect_irq, + IRQF_DISABLED | IRQF_TRIGGER_FALLING, + "MMC detect", data); + if (ret) + goto exit_free_wp; + + return 0; + +exit_free_wp: + gpio_free(gpio_wp); + +exit_free_det: + gpio_free(gpio_det); + + return ret; +} + +static void mxc_mmc1_exit(struct device *dev, void *data) +{ + gpio_free(gpio_det); + gpio_free(gpio_wp); + free_irq(IOMUX_TO_IRQ(MX31_PIN_GPIO1_1), data); +} + +static struct imxmmc_platform_data mmc_pdata = { + .get_ro = mxc_mmc1_get_ro, + .init = mxc_mmc1_init, + .exit = mxc_mmc1_exit, +}; + +/* Framebuffer support */ +static struct ipu_platform_data ipu_data __initdata = { + .irq_base = MXC_IPU_IRQ_START, +}; + +static const struct fb_videomode fb_modedb = { + /* 640x480 TFT panel (IPS-056T) */ + .name = "CRT-VGA", + .refresh = 64, + .xres = 640, + .yres = 480, + .pixclock = 30000, + .left_margin = 200, + .right_margin = 2, + .upper_margin = 2, + .lower_margin = 2, + .hsync_len = 3, + .vsync_len = 1, + .sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_OE_ACT_HIGH, + .vmode = FB_VMODE_NONINTERLACED, + .flag = 0, +}; + +static struct mx3fb_platform_data fb_pdata __initdata = { + .dma_dev = &mx3_ipu.dev, + .name = "CRT-VGA", + .mode = &fb_modedb, + .num_modes = 1, +}; + +#define LCD_VCC_EN_GPIO (7) + +static void __init mx31lilly_init_fb(void) +{ + if (gpio_request(LCD_VCC_EN_GPIO, "LCD enable") != 0) { + printk(KERN_WARNING "unable to request LCD_VCC_EN pin.\n"); + return; + } + + mxc_register_device(&mx3_ipu, &ipu_data); + mxc_register_device(&mx3_fb, &fb_pdata); + gpio_direction_output(LCD_VCC_EN_GPIO, 1); +} + +void __init mx31lilly_db_init(void) +{ + mxc_iomux_setup_multiple_pins(lilly_db_board_pins, + ARRAY_SIZE(lilly_db_board_pins), + "development board pins"); + mxc_register_device(&mxc_uart_device0, &uart_pdata); + mxc_register_device(&mxc_uart_device1, &uart_pdata); + mxc_register_device(&mxc_uart_device2, &uart_pdata); + mxc_register_device(&mxcsdhc_device0, &mmc_pdata); + mx31lilly_init_fb(); +} + diff --git a/arch/arm/mach-mx3/mx31lilly.c b/arch/arm/mach-mx3/mx31lilly.c new file mode 100644 index 000000000000..6ab2f163cb95 --- /dev/null +++ b/arch/arm/mach-mx3/mx31lilly.c @@ -0,0 +1,155 @@ +/* + * LILLY-1131 module support + * + * Copyright (c) 2009 Daniel Mack + * + * based on code for other MX31 boards, + * + * Copyright 2005-2007 Freescale Semiconductor + * Copyright (c) 2009 Alberto Panizzo + * Copyright (C) 2009 Valentin Longchamp, EPFL Mobots group + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "devices.h" + +/* + * This file contains module-specific initialization routines for LILLY-1131. + * Initialization of peripherals found on the baseboard is implemented in the + * appropriate baseboard support code. + */ + +/* SMSC ethernet support */ + +static struct resource smsc91x_resources[] = { + { + .start = CS4_BASE_ADDR, + .end = CS4_BASE_ADDR + 0xffff, + .flags = IORESOURCE_MEM, + }, + { + .start = IOMUX_TO_IRQ(MX31_PIN_GPIO1_0), + .end = IOMUX_TO_IRQ(MX31_PIN_GPIO1_0), + .flags = IORESOURCE_IRQ | IRQF_TRIGGER_FALLING, + } +}; + +static struct smsc911x_platform_config smsc911x_config = { + .phy_interface = PHY_INTERFACE_MODE_MII, + .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW, + .irq_type = SMSC911X_IRQ_TYPE_OPEN_DRAIN, + .flags = SMSC911X_USE_32BIT | + SMSC911X_SAVE_MAC_ADDRESS | + SMSC911X_FORCE_INTERNAL_PHY, +}; + +static struct platform_device smsc91x_device = { + .name = "smsc911x", + .id = -1, + .num_resources = ARRAY_SIZE(smsc91x_resources), + .resource = smsc91x_resources, + .dev = { + .platform_data = &smsc911x_config, + } +}; + +/* NOR flash */ +static struct physmap_flash_data nor_flash_data = { + .width = 2, +}; + +static struct resource nor_flash_resource = { + .start = 0xa0000000, + .end = 0xa1ffffff, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device physmap_flash_device = { + .name = "physmap-flash", + .id = 0, + .dev = { + .platform_data = &nor_flash_data, + }, + .resource = &nor_flash_resource, + .num_resources = 1, +}; + +static struct platform_device *devices[] __initdata = { + &smsc91x_device, + &physmap_flash_device, + &mxc_i2c_device1, +}; + +static int mx31lilly_baseboard; +core_param(mx31lilly_baseboard, mx31lilly_baseboard, int, 0444); + +static void __init mx31lilly_board_init(void) +{ + switch (mx31lilly_baseboard) { + case MX31LILLY_NOBOARD: + break; + case MX31LILLY_DB: + mx31lilly_db_init(); + break; + default: + printk(KERN_ERR "Illegal mx31lilly_baseboard type %d\n", + mx31lilly_baseboard); + } + + mxc_iomux_alloc_pin(MX31_PIN_CS4__CS4, "Ethernet CS"); + mxc_iomux_alloc_pin(MX31_PIN_CSPI2_MOSI__SCL, "I2C SCL"); + mxc_iomux_alloc_pin(MX31_PIN_CSPI2_MISO__SDA, "I2C SDA"); + + platform_add_devices(devices, ARRAY_SIZE(devices)); +} + +static void __init mx31lilly_timer_init(void) +{ + mx31_clocks_init(26000000); +} + +static struct sys_timer mx31lilly_timer = { + .init = mx31lilly_timer_init, +}; + +MACHINE_START(LILLY1131, "INCO startec LILLY-1131") + .phys_io = AIPS1_BASE_ADDR, + .io_pg_offst = ((AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc, + .boot_params = PHYS_OFFSET + 0x100, + .map_io = mx31_map_io, + .init_irq = mxc_init_irq, + .init_machine = mx31lilly_board_init, + .timer = &mx31lilly_timer, +MACHINE_END + diff --git a/arch/arm/mach-mx3/mx31lite.c b/arch/arm/mach-mx3/mx31lite.c index 894d98cd9941..86fe70fa3e13 100644 --- a/arch/arm/mach-mx3/mx31lite.c +++ b/arch/arm/mach-mx3/mx31lite.c @@ -22,6 +22,9 @@ #include #include #include +#include +#include +#include #include #include @@ -32,11 +35,64 @@ #include #include #include +#include +#include +#include +#include +#include "devices.h" /* * This file contains the board-specific initialization routines. */ +static unsigned int mx31lite_pins[] = { + /* UART1 */ + MX31_PIN_CTS1__CTS1, + MX31_PIN_RTS1__RTS1, + MX31_PIN_TXD1__TXD1, + MX31_PIN_RXD1__RXD1, + /* LAN9117 IRQ pin */ + IOMUX_MODE(MX31_PIN_SFS6, IOMUX_CONFIG_GPIO), +}; + +static struct imxuart_platform_data uart_pdata = { + .flags = IMXUART_HAVE_RTSCTS, +}; + +static struct mxc_nand_platform_data mx31lite_nand_board_info = { + .width = 1, + .hw_ecc = 1, +}; + +static struct smsc911x_platform_config smsc911x_config = { + .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW, + .irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL, + .flags = SMSC911X_USE_16BIT, +}; + +static struct resource smsc911x_resources[] = { + [0] = { + .start = CS4_BASE_ADDR, + .end = CS4_BASE_ADDR + 0x100, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IOMUX_TO_IRQ(MX31_PIN_SFS6), + .end = IOMUX_TO_IRQ(MX31_PIN_SFS6), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device smsc911x_device = { + .name = "smsc911x", + .id = -1, + .num_resources = ARRAY_SIZE(smsc911x_resources), + .resource = smsc911x_resources, + .dev = { + .platform_data = &smsc911x_config, + }, +}; + /* * This structure defines the MX31 memory map. */ @@ -59,7 +115,7 @@ static struct map_desc mx31lite_io_desc[] __initdata = { */ void __init mx31lite_map_io(void) { - mxc_map_io(); + mx31_map_io(); iotable_init(mx31lite_io_desc, ARRAY_SIZE(mx31lite_io_desc)); } @@ -68,6 +124,22 @@ void __init mx31lite_map_io(void) */ static void __init mxc_board_init(void) { + int ret; + + mxc_iomux_setup_multiple_pins(mx31lite_pins, ARRAY_SIZE(mx31lite_pins), + "mx31lite"); + + mxc_register_device(&mxc_uart_device0, &uart_pdata); + mxc_register_device(&mxc_nand_device, &mx31lite_nand_board_info); + + /* SMSC9117 IRQ pin */ + ret = gpio_request(IOMUX_TO_GPIO(MX31_PIN_SFS6), "sms9117-irq"); + if (ret) + pr_warning("could not get LAN irq gpio\n"); + else { + gpio_direction_input(IOMUX_TO_GPIO(MX31_PIN_SFS6)); + platform_device_register(&smsc911x_device); + } } static void __init mx31lite_timer_init(void) diff --git a/arch/arm/mach-mx3/mx31moboard-devboard.c b/arch/arm/mach-mx3/mx31moboard-devboard.c index d080b4add79c..4704405165a1 100644 --- a/arch/arm/mach-mx3/mx31moboard-devboard.c +++ b/arch/arm/mach-mx3/mx31moboard-devboard.c @@ -16,33 +16,142 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include +#include +#include #include - +#include #include +#include -#include #include #include #include +#include +#include #include "devices.h" +static unsigned int devboard_pins[] = { + /* UART1 */ + MX31_PIN_CTS2__CTS2, MX31_PIN_RTS2__RTS2, + MX31_PIN_TXD2__TXD2, MX31_PIN_RXD2__RXD2, + /* SDHC2 */ + MX31_PIN_PC_PWRON__SD2_DATA3, MX31_PIN_PC_VS1__SD2_DATA2, + MX31_PIN_PC_READY__SD2_DATA1, MX31_PIN_PC_WAIT_B__SD2_DATA0, + MX31_PIN_PC_CD2_B__SD2_CLK, MX31_PIN_PC_CD1_B__SD2_CMD, + MX31_PIN_ATA_DIOR__GPIO3_28, MX31_PIN_ATA_DIOW__GPIO3_29, + /* USB OTG */ + MX31_PIN_USBOTG_DATA0__USBOTG_DATA0, + MX31_PIN_USBOTG_DATA1__USBOTG_DATA1, + MX31_PIN_USBOTG_DATA2__USBOTG_DATA2, + MX31_PIN_USBOTG_DATA3__USBOTG_DATA3, + MX31_PIN_USBOTG_DATA4__USBOTG_DATA4, + MX31_PIN_USBOTG_DATA5__USBOTG_DATA5, + MX31_PIN_USBOTG_DATA6__USBOTG_DATA6, + MX31_PIN_USBOTG_DATA7__USBOTG_DATA7, + MX31_PIN_USBOTG_CLK__USBOTG_CLK, MX31_PIN_USBOTG_DIR__USBOTG_DIR, + MX31_PIN_USBOTG_NXT__USBOTG_NXT, MX31_PIN_USBOTG_STP__USBOTG_STP, + MX31_PIN_USB_OC__GPIO1_30, +}; + static struct imxuart_platform_data uart_pdata = { .flags = IMXUART_HAVE_RTSCTS, }; -static int mxc_uart1_pins[] = { - MX31_PIN_CTS2__CTS2, MX31_PIN_RTS2__RTS2, - MX31_PIN_TXD2__TXD2, MX31_PIN_RXD2__RXD2, +#define SDHC2_CD IOMUX_TO_GPIO(MX31_PIN_ATA_DIOR) +#define SDHC2_WP IOMUX_TO_GPIO(MX31_PIN_ATA_DIOW) + +static int devboard_sdhc2_get_ro(struct device *dev) +{ + return gpio_get_value(SDHC2_WP); +} + +static int devboard_sdhc2_init(struct device *dev, irq_handler_t detect_irq, + void *data) +{ + int ret; + + ret = gpio_request(SDHC2_CD, "sdhc-detect"); + if (ret) + return ret; + + gpio_direction_input(SDHC2_CD); + + ret = gpio_request(SDHC2_WP, "sdhc-wp"); + if (ret) + goto err_gpio_free; + gpio_direction_input(SDHC2_WP); + + ret = request_irq(gpio_to_irq(SDHC2_CD), detect_irq, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + "sdhc2-card-detect", data); + if (ret) + goto err_gpio_free_2; + + return 0; + +err_gpio_free_2: + gpio_free(SDHC2_WP); +err_gpio_free: + gpio_free(SDHC2_CD); + + return ret; +} + +static void devboard_sdhc2_exit(struct device *dev, void *data) +{ + free_irq(gpio_to_irq(SDHC2_CD), data); + gpio_free(SDHC2_WP); + gpio_free(SDHC2_CD); +} + +static struct imxmmc_platform_data sdhc2_pdata = { + .get_ro = devboard_sdhc2_get_ro, + .init = devboard_sdhc2_init, + .exit = devboard_sdhc2_exit, }; +static struct fsl_usb2_platform_data usb_pdata = { + .operating_mode = FSL_USB2_DR_DEVICE, + .phy_mode = FSL_USB2_PHY_ULPI, +}; + +#define OTG_PAD_CFG (PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST) +#define OTG_EN_B IOMUX_TO_GPIO(MX31_PIN_USB_OC) + +static void devboard_usbotg_init(void) +{ + mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA0, OTG_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA1, OTG_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA2, OTG_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA3, OTG_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA4, OTG_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA5, OTG_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA6, OTG_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA7, OTG_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBOTG_CLK, OTG_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBOTG_DIR, OTG_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBOTG_NXT, OTG_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBOTG_STP, OTG_PAD_CFG); + + gpio_request(OTG_EN_B, "usb-udc-en"); + gpio_direction_output(OTG_EN_B, 0); +} + /* * system init for baseboard usage. Will be called by mx31moboard init. */ void __init mx31moboard_devboard_init(void) { printk(KERN_INFO "Initializing mx31devboard peripherals\n"); - mxc_iomux_setup_multiple_pins(mxc_uart1_pins, ARRAY_SIZE(mxc_uart1_pins), "uart1"); + + mxc_iomux_setup_multiple_pins(devboard_pins, ARRAY_SIZE(devboard_pins), + "devboard"); + mxc_register_device(&mxc_uart_device1, &uart_pdata); + + mxc_register_device(&mxcsdhc_device1, &sdhc2_pdata); + + devboard_usbotg_init(); + mxc_register_device(&mxc_otg_udc_device, &usb_pdata); } diff --git a/arch/arm/mach-mx3/mx31moboard-marxbot.c b/arch/arm/mach-mx3/mx31moboard-marxbot.c index 9ef9566823fb..641c3d6153ae 100644 --- a/arch/arm/mach-mx3/mx31moboard-marxbot.c +++ b/arch/arm/mach-mx3/mx31moboard-marxbot.c @@ -16,22 +16,144 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include +#include +#include #include - +#include #include +#include -#include #include +#include #include #include +#include #include "devices.h" +static unsigned int marxbot_pins[] = { + /* SDHC2 */ + MX31_PIN_PC_PWRON__SD2_DATA3, MX31_PIN_PC_VS1__SD2_DATA2, + MX31_PIN_PC_READY__SD2_DATA1, MX31_PIN_PC_WAIT_B__SD2_DATA0, + MX31_PIN_PC_CD2_B__SD2_CLK, MX31_PIN_PC_CD1_B__SD2_CMD, + MX31_PIN_ATA_DIOR__GPIO3_28, MX31_PIN_ATA_DIOW__GPIO3_29, + /* CSI */ + MX31_PIN_CSI_D4__CSI_D4, MX31_PIN_CSI_D5__CSI_D5, + MX31_PIN_CSI_D6__CSI_D6, MX31_PIN_CSI_D7__CSI_D7, + MX31_PIN_CSI_D8__CSI_D8, MX31_PIN_CSI_D9__CSI_D9, + MX31_PIN_CSI_D10__CSI_D10, MX31_PIN_CSI_D11__CSI_D11, + MX31_PIN_CSI_D12__CSI_D12, MX31_PIN_CSI_D13__CSI_D13, + MX31_PIN_CSI_D14__CSI_D14, MX31_PIN_CSI_D15__CSI_D15, + MX31_PIN_CSI_HSYNC__CSI_HSYNC, MX31_PIN_CSI_MCLK__CSI_MCLK, + MX31_PIN_CSI_PIXCLK__CSI_PIXCLK, MX31_PIN_CSI_VSYNC__CSI_VSYNC, + MX31_PIN_GPIO3_0__GPIO3_0, MX31_PIN_GPIO3_1__GPIO3_1, + MX31_PIN_TXD2__GPIO1_28, + /* USB OTG */ + MX31_PIN_USBOTG_DATA0__USBOTG_DATA0, + MX31_PIN_USBOTG_DATA1__USBOTG_DATA1, + MX31_PIN_USBOTG_DATA2__USBOTG_DATA2, + MX31_PIN_USBOTG_DATA3__USBOTG_DATA3, + MX31_PIN_USBOTG_DATA4__USBOTG_DATA4, + MX31_PIN_USBOTG_DATA5__USBOTG_DATA5, + MX31_PIN_USBOTG_DATA6__USBOTG_DATA6, + MX31_PIN_USBOTG_DATA7__USBOTG_DATA7, + MX31_PIN_USBOTG_CLK__USBOTG_CLK, MX31_PIN_USBOTG_DIR__USBOTG_DIR, + MX31_PIN_USBOTG_NXT__USBOTG_NXT, MX31_PIN_USBOTG_STP__USBOTG_STP, + MX31_PIN_USB_OC__GPIO1_30, +}; + +#define SDHC2_CD IOMUX_TO_GPIO(MX31_PIN_ATA_DIOR) +#define SDHC2_WP IOMUX_TO_GPIO(MX31_PIN_ATA_DIOW) + +static int marxbot_sdhc2_get_ro(struct device *dev) +{ + return gpio_get_value(SDHC2_WP); +} + +static int marxbot_sdhc2_init(struct device *dev, irq_handler_t detect_irq, + void *data) +{ + int ret; + + ret = gpio_request(SDHC2_CD, "sdhc-detect"); + if (ret) + return ret; + + gpio_direction_input(SDHC2_CD); + + ret = gpio_request(SDHC2_WP, "sdhc-wp"); + if (ret) + goto err_gpio_free; + gpio_direction_input(SDHC2_WP); + + ret = request_irq(gpio_to_irq(SDHC2_CD), detect_irq, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + "sdhc2-card-detect", data); + if (ret) + goto err_gpio_free_2; + + return 0; + +err_gpio_free_2: + gpio_free(SDHC2_WP); +err_gpio_free: + gpio_free(SDHC2_CD); + + return ret; +} + +static void marxbot_sdhc2_exit(struct device *dev, void *data) +{ + free_irq(gpio_to_irq(SDHC2_CD), data); + gpio_free(SDHC2_WP); + gpio_free(SDHC2_CD); +} + +static struct imxmmc_platform_data sdhc2_pdata = { + .get_ro = marxbot_sdhc2_get_ro, + .init = marxbot_sdhc2_init, + .exit = marxbot_sdhc2_exit, +}; + +static struct fsl_usb2_platform_data usb_pdata = { + .operating_mode = FSL_USB2_DR_DEVICE, + .phy_mode = FSL_USB2_PHY_ULPI, +}; + +#define OTG_PAD_CFG (PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST) +#define OTG_EN_B IOMUX_TO_GPIO(MX31_PIN_USB_OC) + +static void marxbot_usbotg_init(void) +{ + mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA0, OTG_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA1, OTG_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA2, OTG_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA3, OTG_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA4, OTG_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA5, OTG_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA6, OTG_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA7, OTG_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBOTG_CLK, OTG_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBOTG_DIR, OTG_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBOTG_NXT, OTG_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBOTG_STP, OTG_PAD_CFG); + + gpio_request(OTG_EN_B, "usb-udc-en"); + gpio_direction_output(OTG_EN_B, 0); +} + /* * system init for baseboard usage. Will be called by mx31moboard init. */ void __init mx31moboard_marxbot_init(void) { printk(KERN_INFO "Initializing mx31marxbot peripherals\n"); + + mxc_iomux_setup_multiple_pins(marxbot_pins, ARRAY_SIZE(marxbot_pins), + "marxbot"); + + mxc_register_device(&mxcsdhc_device1, &sdhc2_pdata); + + marxbot_usbotg_init(); + mxc_register_device(&mxc_otg_udc_device, &usb_pdata); } diff --git a/arch/arm/mach-mx3/mx31moboard.c b/arch/arm/mach-mx3/mx31moboard.c index 34c2a1b99d4f..a17f2e411609 100644 --- a/arch/arm/mach-mx3/mx31moboard.c +++ b/arch/arm/mach-mx3/mx31moboard.c @@ -16,26 +16,47 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include +#include #include - -#include +#include +#include #include #include -#include +#include +#include -#include #include #include #include #include +#include #include +#include #include #include -#include +#include +#include #include "devices.h" +static unsigned int moboard_pins[] = { + /* UART0 */ + MX31_PIN_CTS1__CTS1, MX31_PIN_RTS1__RTS1, + MX31_PIN_TXD1__TXD1, MX31_PIN_RXD1__RXD1, + /* UART4 */ + MX31_PIN_PC_RST__CTS5, MX31_PIN_PC_VS2__RTS5, + MX31_PIN_PC_BVD2__TXD5, MX31_PIN_PC_BVD1__RXD5, + /* I2C0 */ + MX31_PIN_I2C_DAT__I2C1_SDA, MX31_PIN_I2C_CLK__I2C1_SCL, + /* I2C1 */ + MX31_PIN_DCD_DTE1__I2C2_SDA, MX31_PIN_RI_DTE1__I2C2_SCL, + /* SDHC1 */ + MX31_PIN_SD1_DATA3__SD1_DATA3, MX31_PIN_SD1_DATA2__SD1_DATA2, + MX31_PIN_SD1_DATA1__SD1_DATA1, MX31_PIN_SD1_DATA0__SD1_DATA0, + MX31_PIN_SD1_CLK__SD1_CLK, MX31_PIN_SD1_CMD__SD1_CMD, + MX31_PIN_ATA_CS0__GPIO3_26, MX31_PIN_ATA_CS1__GPIO3_27, +}; + static struct physmap_flash_data mx31moboard_flash_data = { .width = 2, }; @@ -60,17 +81,69 @@ static struct imxuart_platform_data uart_pdata = { .flags = IMXUART_HAVE_RTSCTS, }; -static struct platform_device *devices[] __initdata = { - &mx31moboard_flash, +static struct imxi2c_platform_data moboard_i2c0_pdata = { + .bitrate = 400000, }; -static int mxc_uart0_pins[] = { - MX31_PIN_CTS1__CTS1, MX31_PIN_RTS1__RTS1, - MX31_PIN_TXD1__TXD1, MX31_PIN_RXD1__RXD1, +static struct imxi2c_platform_data moboard_i2c1_pdata = { + .bitrate = 100000, }; -static int mxc_uart4_pins[] = { - MX31_PIN_PC_RST__CTS5, MX31_PIN_PC_VS2__RTS5, - MX31_PIN_PC_BVD2__TXD5, MX31_PIN_PC_BVD1__RXD5, + +#define SDHC1_CD IOMUX_TO_GPIO(MX31_PIN_ATA_CS0) +#define SDHC1_WP IOMUX_TO_GPIO(MX31_PIN_ATA_CS1) + +static int moboard_sdhc1_get_ro(struct device *dev) +{ + return gpio_get_value(SDHC1_WP); +} + +static int moboard_sdhc1_init(struct device *dev, irq_handler_t detect_irq, + void *data) +{ + int ret; + + ret = gpio_request(SDHC1_CD, "sdhc-detect"); + if (ret) + return ret; + + gpio_direction_input(SDHC1_CD); + + ret = gpio_request(SDHC1_WP, "sdhc-wp"); + if (ret) + goto err_gpio_free; + gpio_direction_input(SDHC1_WP); + + ret = request_irq(gpio_to_irq(SDHC1_CD), detect_irq, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + "sdhc1-card-detect", data); + if (ret) + goto err_gpio_free_2; + + return 0; + +err_gpio_free_2: + gpio_free(SDHC1_WP); +err_gpio_free: + gpio_free(SDHC1_CD); + + return ret; +} + +static void moboard_sdhc1_exit(struct device *dev, void *data) +{ + free_irq(gpio_to_irq(SDHC1_CD), data); + gpio_free(SDHC1_WP); + gpio_free(SDHC1_CD); +} + +static struct imxmmc_platform_data sdhc1_pdata = { + .get_ro = moboard_sdhc1_get_ro, + .init = moboard_sdhc1_init, + .exit = moboard_sdhc1_exit, +}; + +static struct platform_device *devices[] __initdata = { + &mx31moboard_flash, }; static int mx31moboard_baseboard; @@ -81,14 +154,19 @@ core_param(mx31moboard_baseboard, mx31moboard_baseboard, int, 0444); */ static void __init mxc_board_init(void) { + mxc_iomux_setup_multiple_pins(moboard_pins, ARRAY_SIZE(moboard_pins), + "moboard"); + platform_add_devices(devices, ARRAY_SIZE(devices)); - mxc_iomux_setup_multiple_pins(mxc_uart0_pins, ARRAY_SIZE(mxc_uart0_pins), "uart0"); mxc_register_device(&mxc_uart_device0, &uart_pdata); - - mxc_iomux_setup_multiple_pins(mxc_uart4_pins, ARRAY_SIZE(mxc_uart4_pins), "uart4"); mxc_register_device(&mxc_uart_device4, &uart_pdata); + mxc_register_device(&mxc_i2c_device0, &moboard_i2c0_pdata); + mxc_register_device(&mxc_i2c_device1, &moboard_i2c1_pdata); + + mxc_register_device(&mxcsdhc_device0, &sdhc1_pdata); + switch (mx31moboard_baseboard) { case MX31NOBOARD: break; @@ -99,7 +177,8 @@ static void __init mxc_board_init(void) mx31moboard_marxbot_init(); break; default: - printk(KERN_ERR "Illegal mx31moboard_baseboard type %d\n", mx31moboard_baseboard); + printk(KERN_ERR "Illegal mx31moboard_baseboard type %d\n", + mx31moboard_baseboard); } } @@ -117,7 +196,7 @@ MACHINE_START(MX31MOBOARD, "EPFL Mobots mx31moboard") .phys_io = AIPS1_BASE_ADDR, .io_pg_offst = ((AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc, .boot_params = PHYS_OFFSET + 0x100, - .map_io = mxc_map_io, + .map_io = mx31_map_io, .init_irq = mxc_init_irq, .init_machine = mxc_board_init, .timer = &mx31moboard_timer, diff --git a/arch/arm/mach-mx3/mx31pdk.c b/arch/arm/mach-mx3/mx31pdk.c index bc63f1785691..c19838d2e369 100644 --- a/arch/arm/mach-mx3/mx31pdk.c +++ b/arch/arm/mach-mx3/mx31pdk.c @@ -20,6 +20,9 @@ #include #include #include +#include +#include +#include #include #include @@ -41,21 +44,192 @@ * @ingroup System */ +static int mx31pdk_pins[] = { + /* UART1 */ + MX31_PIN_CTS1__CTS1, + MX31_PIN_RTS1__RTS1, + MX31_PIN_TXD1__TXD1, + MX31_PIN_RXD1__RXD1, + IOMUX_MODE(MX31_PIN_GPIO1_1, IOMUX_CONFIG_GPIO), +}; + static struct imxuart_platform_data uart_pdata = { .flags = IMXUART_HAVE_RTSCTS, }; -static int uart_pins[] = { - MX31_PIN_CTS1__CTS1, - MX31_PIN_RTS1__RTS1, - MX31_PIN_TXD1__TXD1, - MX31_PIN_RXD1__RXD1 +/* + * Support for the SMSC9217 on the Debug board. + */ + +static struct smsc911x_platform_config smsc911x_config = { + .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW, + .irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL, + .flags = SMSC911X_USE_16BIT | SMSC911X_FORCE_INTERNAL_PHY, + .phy_interface = PHY_INTERFACE_MODE_MII, }; -static inline void mxc_init_imx_uart(void) +static struct resource smsc911x_resources[] = { + { + .start = LAN9217_BASE_ADDR, + .end = LAN9217_BASE_ADDR + 0xff, + .flags = IORESOURCE_MEM, + }, { + .start = EXPIO_INT_ENET, + .end = EXPIO_INT_ENET, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device smsc911x_device = { + .name = "smsc911x", + .id = -1, + .num_resources = ARRAY_SIZE(smsc911x_resources), + .resource = smsc911x_resources, + .dev = { + .platform_data = &smsc911x_config, + }, +}; + +/* + * Routines for the CPLD on the debug board. It contains a CPLD handling + * LEDs, switches, interrupts for Ethernet. + */ + +static void mx31pdk_expio_irq_handler(uint32_t irq, struct irq_desc *desc) { - mxc_iomux_setup_multiple_pins(uart_pins, ARRAY_SIZE(uart_pins), "uart-0"); - mxc_register_device(&mxc_uart_device0, &uart_pdata); + uint32_t imr_val; + uint32_t int_valid; + uint32_t expio_irq; + + imr_val = __raw_readw(CPLD_INT_MASK_REG); + int_valid = __raw_readw(CPLD_INT_STATUS_REG) & ~imr_val; + + expio_irq = MXC_EXP_IO_BASE; + for (; int_valid != 0; int_valid >>= 1, expio_irq++) { + if ((int_valid & 1) == 0) + continue; + generic_handle_irq(expio_irq); + } +} + +/* + * Disable an expio pin's interrupt by setting the bit in the imr. + * @param irq an expio virtual irq number + */ +static void expio_mask_irq(uint32_t irq) +{ + uint16_t reg; + uint32_t expio = MXC_IRQ_TO_EXPIO(irq); + + /* mask the interrupt */ + reg = __raw_readw(CPLD_INT_MASK_REG); + reg |= 1 << expio; + __raw_writew(reg, CPLD_INT_MASK_REG); +} + +/* + * Acknowledge an expanded io pin's interrupt by clearing the bit in the isr. + * @param irq an expanded io virtual irq number + */ +static void expio_ack_irq(uint32_t irq) +{ + uint32_t expio = MXC_IRQ_TO_EXPIO(irq); + + /* clear the interrupt status */ + __raw_writew(1 << expio, CPLD_INT_RESET_REG); + __raw_writew(0, CPLD_INT_RESET_REG); + /* mask the interrupt */ + expio_mask_irq(irq); +} + +/* + * Enable a expio pin's interrupt by clearing the bit in the imr. + * @param irq a expio virtual irq number + */ +static void expio_unmask_irq(uint32_t irq) +{ + uint16_t reg; + uint32_t expio = MXC_IRQ_TO_EXPIO(irq); + + /* unmask the interrupt */ + reg = __raw_readw(CPLD_INT_MASK_REG); + reg &= ~(1 << expio); + __raw_writew(reg, CPLD_INT_MASK_REG); +} + +static struct irq_chip expio_irq_chip = { + .ack = expio_ack_irq, + .mask = expio_mask_irq, + .unmask = expio_unmask_irq, +}; + +static int __init mx31pdk_init_expio(void) +{ + int i; + int ret; + + /* Check if there's a debug board connected */ + if ((__raw_readw(CPLD_MAGIC_NUMBER1_REG) != 0xAAAA) || + (__raw_readw(CPLD_MAGIC_NUMBER2_REG) != 0x5555) || + (__raw_readw(CPLD_MAGIC_NUMBER3_REG) != 0xCAFE)) { + /* No Debug board found */ + return -ENODEV; + } + + pr_info("i.MX31PDK Debug board detected, rev = 0x%04X\n", + __raw_readw(CPLD_CODE_VER_REG)); + + /* + * Configure INT line as GPIO input + */ + ret = gpio_request(IOMUX_TO_GPIO(MX31_PIN_GPIO1_1), "sms9217-irq"); + if (ret) + pr_warning("could not get LAN irq gpio\n"); + else + gpio_direction_input(IOMUX_TO_GPIO(MX31_PIN_GPIO1_1)); + + /* Disable the interrupts and clear the status */ + __raw_writew(0, CPLD_INT_MASK_REG); + __raw_writew(0xFFFF, CPLD_INT_RESET_REG); + __raw_writew(0, CPLD_INT_RESET_REG); + __raw_writew(0x1F, CPLD_INT_MASK_REG); + for (i = MXC_EXP_IO_BASE; + i < (MXC_EXP_IO_BASE + MXC_MAX_EXP_IO_LINES); + i++) { + set_irq_chip(i, &expio_irq_chip); + set_irq_handler(i, handle_level_irq); + set_irq_flags(i, IRQF_VALID); + } + set_irq_type(EXPIO_PARENT_INT, IRQ_TYPE_LEVEL_LOW); + set_irq_chained_handler(EXPIO_PARENT_INT, mx31pdk_expio_irq_handler); + + return 0; +} + +/* + * This structure defines the MX31 memory map. + */ +static struct map_desc mx31pdk_io_desc[] __initdata = { + { + .virtual = SPBA0_BASE_ADDR_VIRT, + .pfn = __phys_to_pfn(SPBA0_BASE_ADDR), + .length = SPBA0_SIZE, + .type = MT_DEVICE_NONSHARED, + }, { + .virtual = CS5_BASE_ADDR_VIRT, + .pfn = __phys_to_pfn(CS5_BASE_ADDR), + .length = CS5_SIZE, + .type = MT_DEVICE, + }, +}; + +/* + * Set up static virtual mappings. + */ +static void __init mx31pdk_map_io(void) +{ + mx31_map_io(); + iotable_init(mx31pdk_io_desc, ARRAY_SIZE(mx31pdk_io_desc)); } /*! @@ -63,7 +237,13 @@ static inline void mxc_init_imx_uart(void) */ static void __init mxc_board_init(void) { - mxc_init_imx_uart(); + mxc_iomux_setup_multiple_pins(mx31pdk_pins, ARRAY_SIZE(mx31pdk_pins), + "mx31pdk"); + + mxc_register_device(&mxc_uart_device0, &uart_pdata); + + if (!mx31pdk_init_expio()) + platform_device_register(&smsc911x_device); } static void __init mx31pdk_timer_init(void) @@ -84,7 +264,7 @@ MACHINE_START(MX31_3DS, "Freescale MX31PDK (3DS)") .phys_io = AIPS1_BASE_ADDR, .io_pg_offst = ((AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc, .boot_params = PHYS_OFFSET + 0x100, - .map_io = mxc_map_io, + .map_io = mx31pdk_map_io, .init_irq = mxc_init_irq, .init_machine = mxc_board_init, .timer = &mx31pdk_timer, diff --git a/arch/arm/mach-mx3/mx35pdk.c b/arch/arm/mach-mx3/mx35pdk.c new file mode 100644 index 000000000000..6d15374414b9 --- /dev/null +++ b/arch/arm/mach-mx3/mx35pdk.c @@ -0,0 +1,104 @@ +/* + * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved. + * + * Author: Fabio Estevam + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "devices.h" + +static struct imxuart_platform_data uart_pdata = { + .flags = IMXUART_HAVE_RTSCTS, +}; + +static struct platform_device *devices[] __initdata = { + &mxc_fec_device, +}; + +static struct pad_desc mx35pdk_pads[] = { + /* UART1 */ + MX35_PAD_CTS1__UART1_CTS, + MX35_PAD_RTS1__UART1_RTS, + MX35_PAD_TXD1__UART1_TXD_MUX, + MX35_PAD_RXD1__UART1_RXD_MUX, + /* FEC */ + MX35_PAD_FEC_TX_CLK__FEC_TX_CLK, + MX35_PAD_FEC_RX_CLK__FEC_RX_CLK, + MX35_PAD_FEC_RX_DV__FEC_RX_DV, + MX35_PAD_FEC_COL__FEC_COL, + MX35_PAD_FEC_RDATA0__FEC_RDATA_0, + MX35_PAD_FEC_TDATA0__FEC_TDATA_0, + MX35_PAD_FEC_TX_EN__FEC_TX_EN, + MX35_PAD_FEC_MDC__FEC_MDC, + MX35_PAD_FEC_MDIO__FEC_MDIO, + MX35_PAD_FEC_TX_ERR__FEC_TX_ERR, + MX35_PAD_FEC_RX_ERR__FEC_RX_ERR, + MX35_PAD_FEC_CRS__FEC_CRS, + MX35_PAD_FEC_RDATA1__FEC_RDATA_1, + MX35_PAD_FEC_TDATA1__FEC_TDATA_1, + MX35_PAD_FEC_RDATA2__FEC_RDATA_2, + MX35_PAD_FEC_TDATA2__FEC_TDATA_2, + MX35_PAD_FEC_RDATA3__FEC_RDATA_3, + MX35_PAD_FEC_TDATA3__FEC_TDATA_3, +}; + +/* + * Board specific initialization. + */ +static void __init mxc_board_init(void) +{ + mxc_iomux_v3_setup_multiple_pads(mx35pdk_pads, ARRAY_SIZE(mx35pdk_pads)); + + platform_add_devices(devices, ARRAY_SIZE(devices)); + + mxc_register_device(&mxc_uart_device0, &uart_pdata); +} + +static void __init mx35pdk_timer_init(void) +{ + mx35_clocks_init(); +} + +struct sys_timer mx35pdk_timer = { + .init = mx35pdk_timer_init, +}; + +MACHINE_START(MX35_3DS, "Freescale MX35PDK") + /* Maintainer: Freescale Semiconductor, Inc */ + .phys_io = AIPS1_BASE_ADDR, + .io_pg_offst = ((AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc, + .boot_params = PHYS_OFFSET + 0x100, + .map_io = mx35_map_io, + .init_irq = mxc_init_irq, + .init_machine = mxc_board_init, + .timer = &mx35pdk_timer, +MACHINE_END diff --git a/arch/arm/mach-mx3/pcm037.c b/arch/arm/mach-mx3/pcm037.c index b5227d837b2f..c6f61a1f06c8 100644 --- a/arch/arm/mach-mx3/pcm037.c +++ b/arch/arm/mach-mx3/pcm037.c @@ -28,6 +28,10 @@ #include #include #include +#include +#include +#include +#include #include #include @@ -37,7 +41,9 @@ #include #include #include +#include #include +#include #include #include #ifdef CONFIG_I2C_IMX @@ -46,6 +52,76 @@ #include "devices.h" +static unsigned int pcm037_pins[] = { + /* I2C */ + MX31_PIN_CSPI2_MOSI__SCL, + MX31_PIN_CSPI2_MISO__SDA, + /* SDHC1 */ + MX31_PIN_SD1_DATA3__SD1_DATA3, + MX31_PIN_SD1_DATA2__SD1_DATA2, + MX31_PIN_SD1_DATA1__SD1_DATA1, + MX31_PIN_SD1_DATA0__SD1_DATA0, + MX31_PIN_SD1_CLK__SD1_CLK, + MX31_PIN_SD1_CMD__SD1_CMD, + IOMUX_MODE(MX31_PIN_SCK6, IOMUX_CONFIG_GPIO), /* card detect */ + IOMUX_MODE(MX31_PIN_SFS6, IOMUX_CONFIG_GPIO), /* write protect */ + /* SPI1 */ + MX31_PIN_CSPI1_MOSI__MOSI, + MX31_PIN_CSPI1_MISO__MISO, + MX31_PIN_CSPI1_SCLK__SCLK, + MX31_PIN_CSPI1_SPI_RDY__SPI_RDY, + MX31_PIN_CSPI1_SS0__SS0, + MX31_PIN_CSPI1_SS1__SS1, + MX31_PIN_CSPI1_SS2__SS2, + /* UART1 */ + MX31_PIN_CTS1__CTS1, + MX31_PIN_RTS1__RTS1, + MX31_PIN_TXD1__TXD1, + MX31_PIN_RXD1__RXD1, + /* UART2 */ + MX31_PIN_TXD2__TXD2, + MX31_PIN_RXD2__RXD2, + MX31_PIN_CTS2__CTS2, + MX31_PIN_RTS2__RTS2, + /* UART3 */ + MX31_PIN_CSPI3_MOSI__RXD3, + MX31_PIN_CSPI3_MISO__TXD3, + MX31_PIN_CSPI3_SCLK__RTS3, + MX31_PIN_CSPI3_SPI_RDY__CTS3, + /* LAN9217 irq pin */ + IOMUX_MODE(MX31_PIN_GPIO3_1, IOMUX_CONFIG_GPIO), + /* Onewire */ + MX31_PIN_BATT_LINE__OWIRE, + /* Framebuffer */ + MX31_PIN_LD0__LD0, + MX31_PIN_LD1__LD1, + MX31_PIN_LD2__LD2, + MX31_PIN_LD3__LD3, + MX31_PIN_LD4__LD4, + MX31_PIN_LD5__LD5, + MX31_PIN_LD6__LD6, + MX31_PIN_LD7__LD7, + MX31_PIN_LD8__LD8, + MX31_PIN_LD9__LD9, + MX31_PIN_LD10__LD10, + MX31_PIN_LD11__LD11, + MX31_PIN_LD12__LD12, + MX31_PIN_LD13__LD13, + MX31_PIN_LD14__LD14, + MX31_PIN_LD15__LD15, + MX31_PIN_LD16__LD16, + MX31_PIN_LD17__LD17, + MX31_PIN_VSYNC3__VSYNC3, + MX31_PIN_HSYNC__HSYNC, + MX31_PIN_FPSHIFT__FPSHIFT, + MX31_PIN_DRDY0__DRDY0, + MX31_PIN_D3_REV__D3_REV, + MX31_PIN_CONTRAST__CONTRAST, + MX31_PIN_D3_SPL__D3_SPL, + MX31_PIN_D3_CLS__D3_CLS, + MX31_PIN_LCS0__GPI03_23, +}; + static struct physmap_flash_data pcm037_flash_data = { .width = 2, }; @@ -56,6 +132,54 @@ static struct resource pcm037_flash_resource = { .flags = IORESOURCE_MEM, }; +static int usbotg_pins[] = { + MX31_PIN_USBOTG_DATA0__USBOTG_DATA0, + MX31_PIN_USBOTG_DATA1__USBOTG_DATA1, + MX31_PIN_USBOTG_DATA2__USBOTG_DATA2, + MX31_PIN_USBOTG_DATA3__USBOTG_DATA3, + MX31_PIN_USBOTG_DATA4__USBOTG_DATA4, + MX31_PIN_USBOTG_DATA5__USBOTG_DATA5, + MX31_PIN_USBOTG_DATA6__USBOTG_DATA6, + MX31_PIN_USBOTG_DATA7__USBOTG_DATA7, + MX31_PIN_USBOTG_CLK__USBOTG_CLK, + MX31_PIN_USBOTG_DIR__USBOTG_DIR, + MX31_PIN_USBOTG_NXT__USBOTG_NXT, + MX31_PIN_USBOTG_STP__USBOTG_STP, +}; + +/* USB OTG HS port */ +static int __init gpio_usbotg_hs_activate(void) +{ + int ret = mxc_iomux_setup_multiple_pins(usbotg_pins, + ARRAY_SIZE(usbotg_pins), "usbotg"); + + if (ret < 0) { + printk(KERN_ERR "Cannot set up OTG pins\n"); + return ret; + } + + mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA0, PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST); + mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA1, PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST); + mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA2, PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST); + mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA3, PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST); + mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA4, PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST); + mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA5, PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST); + mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA6, PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST); + mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA7, PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST); + mxc_iomux_set_pad(MX31_PIN_USBOTG_CLK, PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST); + mxc_iomux_set_pad(MX31_PIN_USBOTG_DIR, PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST); + mxc_iomux_set_pad(MX31_PIN_USBOTG_NXT, PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST); + mxc_iomux_set_pad(MX31_PIN_USBOTG_STP, PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST); + + return 0; +} + +/* OTG config */ +static struct fsl_usb2_platform_data usb_pdata = { + .operating_mode = FSL_USB2_DR_DEVICE, + .phy_mode = FSL_USB2_PHY_ULPI, +}; + static struct platform_device pcm037_flash = { .name = "physmap-flash", .id = 0, @@ -127,26 +251,8 @@ static struct mxc_nand_platform_data pcm037_nand_board_info = { }; #ifdef CONFIG_I2C_IMX -static int i2c_1_pins[] = { - MX31_PIN_CSPI2_MOSI__SCL, - MX31_PIN_CSPI2_MISO__SDA, -}; - -static int pcm037_i2c_1_init(struct device *dev) -{ - return mxc_iomux_setup_multiple_pins(i2c_1_pins, ARRAY_SIZE(i2c_1_pins), - "i2c-1"); -} - -static void pcm037_i2c_1_exit(struct device *dev) -{ - mxc_iomux_release_multiple_pins(i2c_1_pins, ARRAY_SIZE(i2c_1_pins)); -} - static struct imxi2c_platform_data pcm037_i2c_1_data = { .bitrate = 100000, - .init = pcm037_i2c_1_init, - .exit = pcm037_i2c_1_exit, }; static struct at24_platform_data board_eeprom = { @@ -166,48 +272,119 @@ static struct i2c_board_info pcm037_i2c_devices[] = { }; #endif -static int sdhc1_pins[] = { - MX31_PIN_SD1_DATA3__SD1_DATA3, - MX31_PIN_SD1_DATA2__SD1_DATA2, - MX31_PIN_SD1_DATA1__SD1_DATA1, - MX31_PIN_SD1_DATA0__SD1_DATA0, - MX31_PIN_SD1_CLK__SD1_CLK, - MX31_PIN_SD1_CMD__SD1_CMD, -}; - -static int pcm970_sdhc1_init(struct device *dev, irq_handler_t h, void *data) +/* Not connected by default */ +#ifdef PCM970_SDHC_RW_SWITCH +static int pcm970_sdhc1_get_ro(struct device *dev) { - return mxc_iomux_setup_multiple_pins(sdhc1_pins, ARRAY_SIZE(sdhc1_pins), - "sdhc-1"); + return gpio_get_value(IOMUX_TO_GPIO(MX31_PIN_SFS6)); +} +#endif + +#define SDHC1_GPIO_WP IOMUX_TO_GPIO(MX31_PIN_SFS6) +#define SDHC1_GPIO_DET IOMUX_TO_GPIO(MX31_PIN_SCK6) + +static int pcm970_sdhc1_init(struct device *dev, irq_handler_t detect_irq, + void *data) +{ + int ret; + + ret = gpio_request(SDHC1_GPIO_DET, "sdhc-detect"); + if (ret) + return ret; + + gpio_direction_input(SDHC1_GPIO_DET); + +#ifdef PCM970_SDHC_RW_SWITCH + ret = gpio_request(SDHC1_GPIO_WP, "sdhc-wp"); + if (ret) + goto err_gpio_free; + gpio_direction_input(SDHC1_GPIO_WP); +#endif + + ret = request_irq(IOMUX_TO_IRQ(MX31_PIN_SCK6), detect_irq, + IRQF_DISABLED | IRQF_TRIGGER_FALLING, + "sdhc-detect", data); + if (ret) + goto err_gpio_free_2; + + return 0; + +err_gpio_free_2: +#ifdef PCM970_SDHC_RW_SWITCH + gpio_free(SDHC1_GPIO_WP); +err_gpio_free: +#endif + gpio_free(SDHC1_GPIO_DET); + + return ret; } static void pcm970_sdhc1_exit(struct device *dev, void *data) { - mxc_iomux_release_multiple_pins(sdhc1_pins, ARRAY_SIZE(sdhc1_pins)); + free_irq(IOMUX_TO_IRQ(MX31_PIN_SCK6), data); + gpio_free(SDHC1_GPIO_DET); + gpio_free(SDHC1_GPIO_WP); } -/* No card and rw detection at the moment */ static struct imxmmc_platform_data sdhc_pdata = { +#ifdef PCM970_SDHC_RW_SWITCH + .get_ro = pcm970_sdhc1_get_ro, +#endif .init = pcm970_sdhc1_init, .exit = pcm970_sdhc1_exit, }; static struct platform_device *devices[] __initdata = { &pcm037_flash, - &pcm037_eth, &pcm037_sram_device, }; -static int uart0_pins[] = { - MX31_PIN_CTS1__CTS1, - MX31_PIN_RTS1__RTS1, - MX31_PIN_TXD1__TXD1, - MX31_PIN_RXD1__RXD1 +static struct ipu_platform_data mx3_ipu_data = { + .irq_base = MXC_IPU_IRQ_START, }; -static int uart2_pins[] = { - MX31_PIN_CSPI3_MOSI__RXD3, - MX31_PIN_CSPI3_MISO__TXD3 +static const struct fb_videomode fb_modedb[] = { + { + /* 240x320 @ 60 Hz Sharp */ + .name = "Sharp-LQ035Q7DH06-QVGA", + .refresh = 60, + .xres = 240, + .yres = 320, + .pixclock = 185925, + .left_margin = 9, + .right_margin = 16, + .upper_margin = 7, + .lower_margin = 9, + .hsync_len = 1, + .vsync_len = 1, + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_SHARP_MODE | + FB_SYNC_CLK_INVERT | FB_SYNC_CLK_IDLE_EN, + .vmode = FB_VMODE_NONINTERLACED, + .flag = 0, + }, { + /* 240x320 @ 60 Hz */ + .name = "TX090", + .refresh = 60, + .xres = 240, + .yres = 320, + .pixclock = 38255, + .left_margin = 144, + .right_margin = 0, + .upper_margin = 7, + .lower_margin = 40, + .hsync_len = 96, + .vsync_len = 1, + .sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_OE_ACT_HIGH, + .vmode = FB_VMODE_NONINTERLACED, + .flag = 0, + }, +}; + +static struct mx3fb_platform_data mx3fb_pdata = { + .dma_dev = &mx3_ipu.dev, + .name = "Sharp-LQ035Q7DH06-QVGA", + .mode = fb_modedb, + .num_modes = ARRAY_SIZE(fb_modedb), }; /* @@ -215,21 +392,28 @@ static int uart2_pins[] = { */ static void __init mxc_board_init(void) { + int ret; + + mxc_iomux_setup_multiple_pins(pcm037_pins, ARRAY_SIZE(pcm037_pins), + "pcm037"); + platform_add_devices(devices, ARRAY_SIZE(devices)); - mxc_iomux_setup_multiple_pins(uart0_pins, ARRAY_SIZE(uart0_pins), "uart-0"); mxc_register_device(&mxc_uart_device0, &uart_pdata); - - mxc_iomux_setup_multiple_pins(uart2_pins, ARRAY_SIZE(uart2_pins), "uart-2"); + mxc_register_device(&mxc_uart_device1, &uart_pdata); mxc_register_device(&mxc_uart_device2, &uart_pdata); - mxc_iomux_setup_pin(MX31_PIN_BATT_LINE__OWIRE, "batt-0wire"); mxc_register_device(&mxc_w1_master_device, NULL); /* LAN9217 IRQ pin */ - if (!mxc_iomux_setup_pin(IOMUX_MODE(MX31_PIN_GPIO3_1, IOMUX_CONFIG_GPIO), - "pcm037-eth")) + ret = gpio_request(IOMUX_TO_GPIO(MX31_PIN_GPIO3_1), "lan9217-irq"); + if (ret) + pr_warning("could not get LAN irq gpio\n"); + else { gpio_direction_input(IOMUX_TO_GPIO(MX31_PIN_GPIO3_1)); + platform_device_register(&pcm037_eth); + } + #ifdef CONFIG_I2C_IMX i2c_register_board_info(1, pcm037_i2c_devices, @@ -239,6 +423,10 @@ static void __init mxc_board_init(void) #endif mxc_register_device(&mxc_nand_device, &pcm037_nand_board_info); mxc_register_device(&mxcsdhc_device0, &sdhc_pdata); + mxc_register_device(&mx3_ipu, &mx3_ipu_data); + mxc_register_device(&mx3_fb, &mx3fb_pdata); + if (!gpio_usbotg_hs_activate()) + mxc_register_device(&mxc_otg_udc_device, &usb_pdata); } static void __init pcm037_timer_init(void) @@ -255,7 +443,7 @@ MACHINE_START(PCM037, "Phytec Phycore pcm037") .phys_io = AIPS1_BASE_ADDR, .io_pg_offst = ((AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc, .boot_params = PHYS_OFFSET + 0x100, - .map_io = mxc_map_io, + .map_io = mx31_map_io, .init_irq = mxc_init_irq, .init_machine = mxc_board_init, .timer = &pcm037_timer, diff --git a/arch/arm/mach-mx3/pcm043.c b/arch/arm/mach-mx3/pcm043.c new file mode 100644 index 000000000000..8d27c324abf2 --- /dev/null +++ b/arch/arm/mach-mx3/pcm043.c @@ -0,0 +1,252 @@ +/* + * Copyright (C) 2009 Sascha Hauer, Pengutronix + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#if defined CONFIG_I2C_IMX || defined CONFIG_I2C_IMX_MODULE +#include +#endif +#include +#include +#include + +#include "devices.h" + +static const struct fb_videomode fb_modedb[] = { + { + /* 240x320 @ 60 Hz */ + .name = "Sharp-LQ035Q7", + .refresh = 60, + .xres = 240, + .yres = 320, + .pixclock = 185925, + .left_margin = 9, + .right_margin = 16, + .upper_margin = 7, + .lower_margin = 9, + .hsync_len = 1, + .vsync_len = 1, + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_SHARP_MODE | FB_SYNC_CLK_INVERT | FB_SYNC_CLK_IDLE_EN, + .vmode = FB_VMODE_NONINTERLACED, + .flag = 0, + }, { + /* 240x320 @ 60 Hz */ + .name = "TX090", + .refresh = 60, + .xres = 240, + .yres = 320, + .pixclock = 38255, + .left_margin = 144, + .right_margin = 0, + .upper_margin = 7, + .lower_margin = 40, + .hsync_len = 96, + .vsync_len = 1, + .sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_OE_ACT_HIGH, + .vmode = FB_VMODE_NONINTERLACED, + .flag = 0, + }, +}; + +static struct ipu_platform_data mx3_ipu_data = { + .irq_base = MXC_IPU_IRQ_START, +}; + +static struct mx3fb_platform_data mx3fb_pdata = { + .dma_dev = &mx3_ipu.dev, + .name = "Sharp-LQ035Q7", + .mode = fb_modedb, + .num_modes = ARRAY_SIZE(fb_modedb), +}; + +static struct physmap_flash_data pcm043_flash_data = { + .width = 2, +}; + +static struct resource pcm043_flash_resource = { + .start = 0xa0000000, + .end = 0xa1ffffff, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device pcm043_flash = { + .name = "physmap-flash", + .id = 0, + .dev = { + .platform_data = &pcm043_flash_data, + }, + .resource = &pcm043_flash_resource, + .num_resources = 1, +}; + +static struct imxuart_platform_data uart_pdata = { + .flags = IMXUART_HAVE_RTSCTS, +}; + +#if defined CONFIG_I2C_IMX || defined CONFIG_I2C_IMX_MODULE +static struct imxi2c_platform_data pcm043_i2c_1_data = { + .bitrate = 50000, +}; + +static struct at24_platform_data board_eeprom = { + .byte_len = 4096, + .page_size = 32, + .flags = AT24_FLAG_ADDR16, +}; + +static struct i2c_board_info pcm043_i2c_devices[] = { + { + I2C_BOARD_INFO("at24", 0x52), /* E0=0, E1=1, E2=0 */ + .platform_data = &board_eeprom, + }, { + I2C_BOARD_INFO("rtc-pcf8563", 0x51), + .type = "pcf8563", + } +}; +#endif + +static struct platform_device *devices[] __initdata = { + &pcm043_flash, + &mxc_fec_device, +}; + +static struct pad_desc pcm043_pads[] = { + /* UART1 */ + MX35_PAD_CTS1__UART1_CTS, + MX35_PAD_RTS1__UART1_RTS, + MX35_PAD_TXD1__UART1_TXD_MUX, + MX35_PAD_RXD1__UART1_RXD_MUX, + /* UART2 */ + MX35_PAD_CTS2__UART2_CTS, + MX35_PAD_RTS2__UART2_RTS, + MX35_PAD_TXD2__UART2_TXD_MUX, + MX35_PAD_RXD2__UART2_RXD_MUX, + /* FEC */ + MX35_PAD_FEC_TX_CLK__FEC_TX_CLK, + MX35_PAD_FEC_RX_CLK__FEC_RX_CLK, + MX35_PAD_FEC_RX_DV__FEC_RX_DV, + MX35_PAD_FEC_COL__FEC_COL, + MX35_PAD_FEC_RDATA0__FEC_RDATA_0, + MX35_PAD_FEC_TDATA0__FEC_TDATA_0, + MX35_PAD_FEC_TX_EN__FEC_TX_EN, + MX35_PAD_FEC_MDC__FEC_MDC, + MX35_PAD_FEC_MDIO__FEC_MDIO, + MX35_PAD_FEC_TX_ERR__FEC_TX_ERR, + MX35_PAD_FEC_RX_ERR__FEC_RX_ERR, + MX35_PAD_FEC_CRS__FEC_CRS, + MX35_PAD_FEC_RDATA1__FEC_RDATA_1, + MX35_PAD_FEC_TDATA1__FEC_TDATA_1, + MX35_PAD_FEC_RDATA2__FEC_RDATA_2, + MX35_PAD_FEC_TDATA2__FEC_TDATA_2, + MX35_PAD_FEC_RDATA3__FEC_RDATA_3, + MX35_PAD_FEC_TDATA3__FEC_TDATA_3, + /* I2C1 */ + MX35_PAD_I2C1_CLK__I2C1_SCL, + MX35_PAD_I2C1_DAT__I2C1_SDA, + /* Display */ + MX35_PAD_LD0__IPU_DISPB_DAT_0, + MX35_PAD_LD1__IPU_DISPB_DAT_1, + MX35_PAD_LD2__IPU_DISPB_DAT_2, + MX35_PAD_LD3__IPU_DISPB_DAT_3, + MX35_PAD_LD4__IPU_DISPB_DAT_4, + MX35_PAD_LD5__IPU_DISPB_DAT_5, + MX35_PAD_LD6__IPU_DISPB_DAT_6, + MX35_PAD_LD7__IPU_DISPB_DAT_7, + MX35_PAD_LD8__IPU_DISPB_DAT_8, + MX35_PAD_LD9__IPU_DISPB_DAT_9, + MX35_PAD_LD10__IPU_DISPB_DAT_10, + MX35_PAD_LD11__IPU_DISPB_DAT_11, + MX35_PAD_LD12__IPU_DISPB_DAT_12, + MX35_PAD_LD13__IPU_DISPB_DAT_13, + MX35_PAD_LD14__IPU_DISPB_DAT_14, + MX35_PAD_LD15__IPU_DISPB_DAT_15, + MX35_PAD_LD16__IPU_DISPB_DAT_16, + MX35_PAD_LD17__IPU_DISPB_DAT_17, + MX35_PAD_D3_HSYNC__IPU_DISPB_D3_HSYNC, + MX35_PAD_D3_FPSHIFT__IPU_DISPB_D3_CLK, + MX35_PAD_D3_DRDY__IPU_DISPB_D3_DRDY, + MX35_PAD_CONTRAST__IPU_DISPB_CONTR, + MX35_PAD_D3_VSYNC__IPU_DISPB_D3_VSYNC, + MX35_PAD_D3_REV__IPU_DISPB_D3_REV, + MX35_PAD_D3_CLS__IPU_DISPB_D3_CLS, + MX35_PAD_D3_SPL__IPU_DISPB_D3_SPL +}; + +/* + * Board specific initialization. + */ +static void __init mxc_board_init(void) +{ + mxc_iomux_v3_setup_multiple_pads(pcm043_pads, ARRAY_SIZE(pcm043_pads)); + + platform_add_devices(devices, ARRAY_SIZE(devices)); + + mxc_register_device(&mxc_uart_device0, &uart_pdata); + + mxc_register_device(&mxc_uart_device1, &uart_pdata); + +#if defined CONFIG_I2C_IMX || defined CONFIG_I2C_IMX_MODULE + i2c_register_board_info(0, pcm043_i2c_devices, + ARRAY_SIZE(pcm043_i2c_devices)); + + mxc_register_device(&mxc_i2c_device0, &pcm043_i2c_1_data); +#endif + + mxc_register_device(&mx3_ipu, &mx3_ipu_data); + mxc_register_device(&mx3_fb, &mx3fb_pdata); +} + +static void __init pcm043_timer_init(void) +{ + mx35_clocks_init(); +} + +struct sys_timer pcm043_timer = { + .init = pcm043_timer_init, +}; + +MACHINE_START(PCM043, "Phytec Phycore pcm043") + /* Maintainer: Pengutronix */ + .phys_io = AIPS1_BASE_ADDR, + .io_pg_offst = ((AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc, + .boot_params = PHYS_OFFSET + 0x100, + .map_io = mx35_map_io, + .init_irq = mxc_init_irq, + .init_machine = mxc_board_init, + .timer = &pcm043_timer, +MACHINE_END + diff --git a/arch/arm/mach-mx3/qong.c b/arch/arm/mach-mx3/qong.c index 5a01e48fd8f1..82b31c4ab11f 100644 --- a/arch/arm/mach-mx3/qong.c +++ b/arch/arm/mach-mx3/qong.c @@ -279,7 +279,7 @@ MACHINE_START(QONG, "Dave/DENX QongEVB-LITE") .phys_io = AIPS1_BASE_ADDR, .io_pg_offst = ((AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc, .boot_params = PHYS_OFFSET + 0x100, - .map_io = mxc_map_io, + .map_io = mx31_map_io, .init_irq = mxc_init_irq, .init_machine = mxc_board_init, .timer = &qong_timer, diff --git a/arch/arm/mach-netx/generic.c b/arch/arm/mach-netx/generic.c index 79df60c20e70..43da8bb4926b 100644 --- a/arch/arm/mach-netx/generic.c +++ b/arch/arm/mach-netx/generic.c @@ -168,7 +168,7 @@ void __init netx_init_irq(void) { int irq; - vic_init(__io(io_p2v(NETX_PA_VIC)), 0, ~0); + vic_init(__io(io_p2v(NETX_PA_VIC)), 0, ~0, 0); for (irq = NETX_IRQ_HIF_CHAINED(0); irq <= NETX_IRQ_HIF_LAST; irq++) { set_irq_chip(irq, &netx_hif_chip); diff --git a/arch/arm/mach-omap1/Kconfig b/arch/arm/mach-omap1/Kconfig index cd8de89c5fad..55ecc01ea206 100644 --- a/arch/arm/mach-omap1/Kconfig +++ b/arch/arm/mach-omap1/Kconfig @@ -46,7 +46,6 @@ config MACH_OMAP_H2 config MACH_OMAP_H3 bool "TI H3 Support" depends on ARCH_OMAP1 && ARCH_OMAP16XX -# select GPIOEXPANDER_OMAP help TI OMAP 1710 H3 board support. Say Y here if you have such a board. diff --git a/arch/arm/mach-omap1/Makefile b/arch/arm/mach-omap1/Makefile index 1bda8f5d7546..6867cd3ad0b4 100644 --- a/arch/arm/mach-omap1/Makefile +++ b/arch/arm/mach-omap1/Makefile @@ -13,6 +13,10 @@ obj-$(CONFIG_OMAP_32K_TIMER) += timer32k.o # Power Management obj-$(CONFIG_PM) += pm.o sleep.o +# DSP +obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox_mach.o +mailbox_mach-objs := mailbox.o + led-y := leds.o # Specific board support diff --git a/arch/arm/mach-omap1/board-nokia770.c b/arch/arm/mach-omap1/board-nokia770.c index d1ed1365319e..e70fc7c66bbb 100644 --- a/arch/arm/mach-omap1/board-nokia770.c +++ b/arch/arm/mach-omap1/board-nokia770.c @@ -33,8 +33,11 @@ #include #include #include +#include #include #include +#include +#include #define ADS7846_PENDOWN_GPIO 15 @@ -162,6 +165,15 @@ static struct spi_board_info nokia770_spi_board_info[] __initdata = { }, }; +static struct hwa742_platform_data nokia770_hwa742_platform_data = { + .te_connected = 1, +}; + +static void hwa742_dev_init(void) +{ + clk_add_alias("hwa_sys_ck", NULL, "bclk", NULL); + omapfb_set_ctrl_platform_data(&nokia770_hwa742_platform_data); +} /* assume no Mini-AB port */ @@ -370,6 +382,7 @@ static void __init omap_nokia770_init(void) omap_serial_init(); omap_register_i2c_bus(1, 100, NULL, 0); omap_dsp_init(); + hwa742_dev_init(); ads7846_dev_init(); mipid_dev_init(); omap_usb_init(&nokia770_usb_config); diff --git a/arch/arm/mach-omap1/clock.c b/arch/arm/mach-omap1/clock.c index 336e51dc6127..436eed22801b 100644 --- a/arch/arm/mach-omap1/clock.c +++ b/arch/arm/mach-omap1/clock.c @@ -776,7 +776,7 @@ int __init omap1_clk_init(void) arm_idlect1_mask = ~0; for (c = omap_clks; c < omap_clks + ARRAY_SIZE(omap_clks); c++) - clk_init_one(c->lk.clk); + clk_preinit(c->lk.clk); cpu_mask = 0; if (cpu_is_omap16xx()) diff --git a/arch/arm/mach-omap1/pm.c b/arch/arm/mach-omap1/pm.c index 9774c1f5311e..5218943c91c0 100644 --- a/arch/arm/mach-omap1/pm.c +++ b/arch/arm/mach-omap1/pm.c @@ -53,11 +53,12 @@ #include #include #include -#include #include #include #include +#include "pm.h" + static unsigned int arm_sleep_save[ARM_SLEEP_SAVE_SIZE]; static unsigned short dsp_sleep_save[DSP_SLEEP_SAVE_SIZE]; static unsigned short ulpd_sleep_save[ULPD_SLEEP_SAVE_SIZE]; @@ -101,7 +102,7 @@ static void (*omap_sram_suspend)(unsigned long r0, unsigned long r1) = NULL; * going idle we continue to do idle even if we get * a clock tick interrupt . . */ -void omap_pm_idle(void) +void omap1_pm_idle(void) { extern __u32 arm_idlect1_mask; __u32 use_idlect1 = arm_idlect1_mask; @@ -222,7 +223,7 @@ static void omap_pm_wakeup_setup(void) #define EN_APICK 6 /* ARM_IDLECT2 */ #define DSP_EN 1 /* ARM_RSTCT1 */ -void omap_pm_suspend(void) +void omap1_pm_suspend(void) { unsigned long arg0 = 0, arg1 = 0; @@ -610,7 +611,7 @@ static int omap_pm_enter(suspend_state_t state) { case PM_SUSPEND_STANDBY: case PM_SUSPEND_MEM: - omap_pm_suspend(); + omap1_pm_suspend(); break; default: return -EINVAL; @@ -683,7 +684,7 @@ static int __init omap_pm_init(void) return -ENODEV; } - pm_idle = omap_pm_idle; + pm_idle = omap1_pm_idle; if (cpu_is_omap730()) setup_irq(INT_730_WAKE_UP_REQ, &omap_wakeup_irq); diff --git a/arch/arm/plat-omap/include/mach/pm.h b/arch/arm/mach-omap1/pm.h similarity index 76% rename from arch/arm/plat-omap/include/mach/pm.h rename to arch/arm/mach-omap1/pm.h index ce6ee7927537..9ed5e2c1de4d 100644 --- a/arch/arm/plat-omap/include/mach/pm.h +++ b/arch/arm/mach-omap1/pm.h @@ -1,7 +1,7 @@ /* - * arch/arm/plat-omap/include/mach/pm.h + * arch/arm/mach-omap1/pm.h * - * Header file for OMAP Power Management Routines + * Header file for OMAP1 Power Management Routines * * Author: MontaVista Software, Inc. * support@mvista.com @@ -31,8 +31,8 @@ * 675 Mass Ave, Cambridge, MA 02139, USA. */ -#ifndef __ASM_ARCH_OMAP_PM_H -#define __ASM_ARCH_OMAP_PM_H +#ifndef __ARCH_ARM_MACH_OMAP1_PM_H +#define __ARCH_ARM_MACH_OMAP1_PM_H /* * ---------------------------------------------------------------------------- @@ -106,8 +106,7 @@ #if !defined(CONFIG_ARCH_OMAP730) && \ !defined(CONFIG_ARCH_OMAP15XX) && \ - !defined(CONFIG_ARCH_OMAP16XX) && \ - !defined(CONFIG_ARCH_OMAP24XX) + !defined(CONFIG_ARCH_OMAP16XX) #warning "Power management for this processor not implemented yet" #endif @@ -115,29 +114,27 @@ #include +extern struct kset power_subsys; + extern void prevent_idle_sleep(void); extern void allow_idle_sleep(void); -extern void omap_pm_idle(void); -extern void omap_pm_suspend(void); +extern void omap1_pm_idle(void); +extern void omap1_pm_suspend(void); + extern void omap730_cpu_suspend(unsigned short, unsigned short); extern void omap1510_cpu_suspend(unsigned short, unsigned short); extern void omap1610_cpu_suspend(unsigned short, unsigned short); -extern void omap24xx_cpu_suspend(u32 dll_ctrl, void __iomem *sdrc_dlla_ctrl, - void __iomem *sdrc_power); extern void omap730_idle_loop_suspend(void); extern void omap1510_idle_loop_suspend(void); extern void omap1610_idle_loop_suspend(void); -extern void omap24xx_idle_loop_suspend(void); extern unsigned int omap730_cpu_suspend_sz; extern unsigned int omap1510_cpu_suspend_sz; extern unsigned int omap1610_cpu_suspend_sz; -extern unsigned int omap24xx_cpu_suspend_sz; extern unsigned int omap730_idle_loop_suspend_sz; extern unsigned int omap1510_idle_loop_suspend_sz; extern unsigned int omap1610_idle_loop_suspend_sz; -extern unsigned int omap24xx_idle_loop_suspend_sz; #ifdef CONFIG_OMAP_SERIAL_WAKE extern void omap_serial_wake_trigger(int enable); @@ -170,10 +167,6 @@ extern void omap_serial_wake_trigger(int enable); #define MPUI1610_RESTORE(x) omap_writel((mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_##x]), (x)) #define MPUI1610_SHOW(x) mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_##x] -#define OMAP24XX_SAVE(x) omap24xx_sleep_save[OMAP24XX_SLEEP_SAVE_##x] = x -#define OMAP24XX_RESTORE(x) x = omap24xx_sleep_save[OMAP24XX_SLEEP_SAVE_##x] -#define OMAP24XX_SHOW(x) omap24xx_sleep_save[OMAP24XX_SLEEP_SAVE_##x] - /* * List of global OMAP registers to preserve. * More ones like CP and general purpose register values are preserved @@ -283,63 +276,5 @@ enum mpui1610_save_state { #endif }; -enum omap24xx_save_state { - OMAP24XX_SLEEP_SAVE_START = 0, - OMAP24XX_SLEEP_SAVE_INTC_MIR0, - OMAP24XX_SLEEP_SAVE_INTC_MIR1, - OMAP24XX_SLEEP_SAVE_INTC_MIR2, - - OMAP24XX_SLEEP_SAVE_CM_CLKSTCTRL_MPU, - OMAP24XX_SLEEP_SAVE_CM_CLKSTCTRL_CORE, - OMAP24XX_SLEEP_SAVE_CM_CLKSTCTRL_GFX, - OMAP24XX_SLEEP_SAVE_CM_CLKSTCTRL_DSP, - OMAP24XX_SLEEP_SAVE_CM_CLKSTCTRL_MDM, - - OMAP24XX_SLEEP_SAVE_PM_PWSTCTRL_MPU, - OMAP24XX_SLEEP_SAVE_PM_PWSTCTRL_CORE, - OMAP24XX_SLEEP_SAVE_PM_PWSTCTRL_GFX, - OMAP24XX_SLEEP_SAVE_PM_PWSTCTRL_DSP, - OMAP24XX_SLEEP_SAVE_PM_PWSTCTRL_MDM, - - OMAP24XX_SLEEP_SAVE_CM_IDLEST1_CORE, - OMAP24XX_SLEEP_SAVE_CM_IDLEST2_CORE, - OMAP24XX_SLEEP_SAVE_CM_IDLEST3_CORE, - OMAP24XX_SLEEP_SAVE_CM_IDLEST4_CORE, - OMAP24XX_SLEEP_SAVE_CM_IDLEST_GFX, - OMAP24XX_SLEEP_SAVE_CM_IDLEST_WKUP, - OMAP24XX_SLEEP_SAVE_CM_IDLEST_CKGEN, - OMAP24XX_SLEEP_SAVE_CM_IDLEST_DSP, - OMAP24XX_SLEEP_SAVE_CM_IDLEST_MDM, - - OMAP24XX_SLEEP_SAVE_CM_AUTOIDLE1_CORE, - OMAP24XX_SLEEP_SAVE_CM_AUTOIDLE2_CORE, - OMAP24XX_SLEEP_SAVE_CM_AUTOIDLE3_CORE, - OMAP24XX_SLEEP_SAVE_CM_AUTOIDLE4_CORE, - OMAP24XX_SLEEP_SAVE_CM_AUTOIDLE_WKUP, - OMAP24XX_SLEEP_SAVE_CM_AUTOIDLE_PLL, - OMAP24XX_SLEEP_SAVE_CM_AUTOIDLE_DSP, - OMAP24XX_SLEEP_SAVE_CM_AUTOIDLE_MDM, - - OMAP24XX_SLEEP_SAVE_CM_FCLKEN1_CORE, - OMAP24XX_SLEEP_SAVE_CM_FCLKEN2_CORE, - OMAP24XX_SLEEP_SAVE_CM_ICLKEN1_CORE, - OMAP24XX_SLEEP_SAVE_CM_ICLKEN2_CORE, - OMAP24XX_SLEEP_SAVE_CM_ICLKEN3_CORE, - OMAP24XX_SLEEP_SAVE_CM_ICLKEN4_CORE, - OMAP24XX_SLEEP_SAVE_GPIO1_IRQENABLE1, - OMAP24XX_SLEEP_SAVE_GPIO2_IRQENABLE1, - OMAP24XX_SLEEP_SAVE_GPIO3_IRQENABLE1, - OMAP24XX_SLEEP_SAVE_GPIO4_IRQENABLE1, - OMAP24XX_SLEEP_SAVE_GPIO3_OE, - OMAP24XX_SLEEP_SAVE_GPIO4_OE, - OMAP24XX_SLEEP_SAVE_GPIO3_RISINGDETECT, - OMAP24XX_SLEEP_SAVE_GPIO3_FALLINGDETECT, - OMAP24XX_SLEEP_SAVE_CONTROL_PADCONF_SPI1_NCS2, - OMAP24XX_SLEEP_SAVE_CONTROL_PADCONF_MCBSP1_DX, - OMAP24XX_SLEEP_SAVE_CONTROL_PADCONF_SSI1_FLAG_TX, - OMAP24XX_SLEEP_SAVE_CONTROL_PADCONF_SYS_NIRQW0, - OMAP24XX_SLEEP_SAVE_SIZE -}; - #endif /* ASSEMBLER */ #endif /* __ASM_ARCH_OMAP_PM_H */ diff --git a/arch/arm/mach-omap1/serial.c b/arch/arm/mach-omap1/serial.c index 842090b148f1..f754cee4f3c3 100644 --- a/arch/arm/mach-omap1/serial.c +++ b/arch/arm/mach-omap1/serial.c @@ -26,9 +26,6 @@ #include #include #include -#ifdef CONFIG_PM -#include -#endif static struct clk * uart1_ck; static struct clk * uart2_ck; diff --git a/arch/arm/mach-omap1/sleep.S b/arch/arm/mach-omap1/sleep.S index f3eac932092d..22e8568339b0 100644 --- a/arch/arm/mach-omap1/sleep.S +++ b/arch/arm/mach-omap1/sleep.S @@ -35,7 +35,7 @@ #include #include #include -#include +#include "pm.h" .text diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig index 64ab386a65c7..a755eb5e2361 100644 --- a/arch/arm/mach-omap2/Kconfig +++ b/arch/arm/mach-omap2/Kconfig @@ -25,7 +25,7 @@ config ARCH_OMAP3430 select ARCH_OMAP_OTG comment "OMAP Board Type" - depends on ARCH_OMAP2 || ARCH_OMAP3 + depends on ARCH_OMAP2 || ARCH_OMAP3 || ARCH_OMAP4 config MACH_OMAP_GENERIC bool "Generic OMAP board" @@ -56,6 +56,10 @@ config MACH_OVERO bool "Gumstix Overo board" depends on ARCH_OMAP3 && ARCH_OMAP34XX +config MACH_OMAP3EVM + bool "OMAP 3530 EVM board" + depends on ARCH_OMAP3 && ARCH_OMAP34XX + config MACH_OMAP3_PANDORA bool "OMAP3 Pandora" depends on ARCH_OMAP3 && ARCH_OMAP34XX @@ -67,3 +71,11 @@ config MACH_OMAP_3430SDP config MACH_NOKIA_RX51 bool "Nokia RX-51 board" depends on ARCH_OMAP3 && ARCH_OMAP34XX + +config MACH_OMAP_ZOOM2 + bool "OMAP3 Zoom2 board" + depends on ARCH_OMAP3 && ARCH_OMAP34XX + +config MACH_OMAP_4430SDP + bool "OMAP 4430 SDP board" + depends on ARCH_OMAP4 diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index c49d9bfa3abd..735bae5b0dec 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -3,12 +3,21 @@ # # Common support -obj-y := irq.o id.o io.o sdrc.o control.o prcm.o clock.o mux.o \ - devices.o serial.o gpmc.o timer-gp.o powerdomain.o \ - clockdomain.o +obj-y := id.o io.o control.o mux.o devices.o serial.o gpmc.o timer-gp.o + +omap-2-3-common = irq.o sdrc.o +prcm-common = prcm.o powerdomain.o +clock-common = clock.o clockdomain.o + +obj-$(CONFIG_ARCH_OMAP2) += $(omap-2-3-common) $(prcm-common) $(clock-common) +obj-$(CONFIG_ARCH_OMAP3) += $(omap-2-3-common) $(prcm-common) $(clock-common) obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o +# SMP support ONLY available for OMAP4 +obj-$(CONFIG_SMP) += omap-smp.o omap-headsmp.o +obj-$(CONFIG_LOCAL_TIMERS) += timer-mpu.o + # Functions loaded to SRAM obj-$(CONFIG_ARCH_OMAP2420) += sram242x.o obj-$(CONFIG_ARCH_OMAP2430) += sram243x.o @@ -20,14 +29,21 @@ obj-$(CONFIG_ARCH_OMAP2) += sdrc2xxx.o # Power Management ifeq ($(CONFIG_PM),y) -obj-y += pm.o +obj-$(CONFIG_ARCH_OMAP2) += pm24xx.o obj-$(CONFIG_ARCH_OMAP24XX) += sleep24xx.o +obj-$(CONFIG_ARCH_OMAP3) += pm34xx.o sleep34xx.o +obj-$(CONFIG_PM_DEBUG) += pm-debug.o endif # Clock framework obj-$(CONFIG_ARCH_OMAP2) += clock24xx.o obj-$(CONFIG_ARCH_OMAP3) += clock34xx.o +iommu-y += iommu2.o +iommu-$(CONFIG_ARCH_OMAP3) += omap3-iommu.o + +obj-$(CONFIG_OMAP_IOMMU) += $(iommu-y) + # Specific board support obj-$(CONFIG_MACH_OMAP_GENERIC) += board-generic.o obj-$(CONFIG_MACH_OMAP_H4) += board-h4.o @@ -40,6 +56,8 @@ obj-$(CONFIG_MACH_OMAP_LDP) += board-ldp.o \ mmc-twl4030.o obj-$(CONFIG_MACH_OVERO) += board-overo.o \ mmc-twl4030.o +obj-$(CONFIG_MACH_OMAP3EVM) += board-omap3evm.o \ + mmc-twl4030.o obj-$(CONFIG_MACH_OMAP3_PANDORA) += board-omap3pandora.o \ mmc-twl4030.o obj-$(CONFIG_MACH_OMAP_3430SDP) += board-3430sdp.o \ @@ -48,8 +66,17 @@ obj-$(CONFIG_MACH_OMAP_3430SDP) += board-3430sdp.o \ obj-$(CONFIG_MACH_NOKIA_RX51) += board-rx51.o \ board-rx51-peripherals.o \ mmc-twl4030.o +obj-$(CONFIG_MACH_OMAP_ZOOM2) += board-zoom2.o \ + mmc-twl4030.o \ + board-zoom-debugboard.o + +obj-$(CONFIG_MACH_OMAP_4430SDP) += board-4430sdp.o # Platform specific device init code -ifeq ($(CONFIG_USB_MUSB_SOC),y) obj-y += usb-musb.o -endif + +onenand-$(CONFIG_MTD_ONENAND_OMAP2) := gpmc-onenand.o +obj-y += $(onenand-m) $(onenand-y) + +smc91x-$(CONFIG_SMC91X) := gpmc-smc91x.o +obj-y += $(smc91x-m) $(smc91x-y) diff --git a/arch/arm/mach-omap2/board-2430sdp.c b/arch/arm/mach-omap2/board-2430sdp.c index 22143651037e..9c3fdcdf76c3 100644 --- a/arch/arm/mach-omap2/board-2430sdp.c +++ b/arch/arm/mach-omap2/board-2430sdp.c @@ -36,14 +36,12 @@ #include #include #include +#include #include "mmc-twl4030.h" #define SDP2430_CS0_BASE 0x04000000 -#define SDP2430_FLASH_CS 0 -#define SDP2430_SMC91X_CS 5 - -#define SDP2430_ETHR_GPIO_IRQ 149 +#define SECONDARY_LCD_GPIO 147 static struct mtd_partition sdp2430_partitions[] = { /* bootloader (U-Boot, etc) in first sector */ @@ -99,100 +97,53 @@ static struct platform_device sdp2430_flash_device = { .resource = &sdp2430_flash_resource, }; -static struct resource sdp2430_smc91x_resources[] = { - [0] = { - .start = SDP2430_CS0_BASE, - .end = SDP2430_CS0_BASE + SZ_64M - 1, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = OMAP_GPIO_IRQ(SDP2430_ETHR_GPIO_IRQ), - .end = OMAP_GPIO_IRQ(SDP2430_ETHR_GPIO_IRQ), - .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL, - }, -}; - -static struct platform_device sdp2430_smc91x_device = { - .name = "smc91x", +static struct platform_device sdp2430_lcd_device = { + .name = "sdp2430_lcd", .id = -1, - .num_resources = ARRAY_SIZE(sdp2430_smc91x_resources), - .resource = sdp2430_smc91x_resources, }; static struct platform_device *sdp2430_devices[] __initdata = { - &sdp2430_smc91x_device, &sdp2430_flash_device, + &sdp2430_lcd_device, }; -static inline void __init sdp2430_init_smc91x(void) +static struct omap_lcd_config sdp2430_lcd_config __initdata = { + .ctrl_name = "internal", +}; + +#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91x_MODULE) + +static struct omap_smc91x_platform_data board_smc91x_data = { + .cs = 5, + .gpio_irq = 149, + .flags = GPMC_MUX_ADD_DATA | GPMC_TIMINGS_SMC91C96 | + IORESOURCE_IRQ_LOWLEVEL, + +}; + +static void __init board_smc91x_init(void) { - int eth_cs; - unsigned long cs_mem_base; - unsigned int rate; - struct clk *gpmc_fck; + if (omap_rev() > OMAP3430_REV_ES1_0) + board_smc91x_data.gpio_irq = 6; + else + board_smc91x_data.gpio_irq = 29; - eth_cs = SDP2430_SMC91X_CS; - - gpmc_fck = clk_get(NULL, "gpmc_fck"); /* Always on ENABLE_ON_INIT */ - if (IS_ERR(gpmc_fck)) { - WARN_ON(1); - return; - } - - clk_enable(gpmc_fck); - rate = clk_get_rate(gpmc_fck); - - /* Make sure CS1 timings are correct, for 2430 always muxed */ - gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG1, 0x00011200); - - if (rate >= 160000000) { - gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG2, 0x001f1f01); - gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG3, 0x00080803); - gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG4, 0x1c0b1c0a); - gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG5, 0x041f1F1F); - gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG6, 0x000004C4); - } else if (rate >= 130000000) { - gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG2, 0x001f1f00); - gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG3, 0x00080802); - gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG4, 0x1C091C09); - gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG5, 0x041f1F1F); - gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG6, 0x000004C4); - } else { /* rate = 100000000 */ - gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG2, 0x001f1f00); - gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG3, 0x00080802); - gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG4, 0x1C091C09); - gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG5, 0x031A1F1F); - gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG6, 0x000003C2); - } - - if (gpmc_cs_request(eth_cs, SZ_16M, &cs_mem_base) < 0) { - printk(KERN_ERR "Failed to request GPMC mem for smc91x\n"); - goto out; - } - - sdp2430_smc91x_resources[0].start = cs_mem_base + 0x300; - sdp2430_smc91x_resources[0].end = cs_mem_base + 0x30f; - udelay(100); - - if (gpio_request(SDP2430_ETHR_GPIO_IRQ, "SMC91x irq") < 0) { - printk(KERN_ERR "Failed to request GPIO%d for smc91x IRQ\n", - SDP2430_ETHR_GPIO_IRQ); - gpmc_cs_free(eth_cs); - goto out; - } - gpio_direction_input(SDP2430_ETHR_GPIO_IRQ); - -out: - clk_disable(gpmc_fck); - clk_put(gpmc_fck); + gpmc_smc91x_init(&board_smc91x_data); } +#else + +static inline void board_smc91x_init(void) +{ +} + +#endif + static void __init omap_2430sdp_init_irq(void) { omap2_init_common_hw(NULL); omap_init_irq(); omap_gpio_init(); - sdp2430_init_smc91x(); } static struct omap_uart_config sdp2430_uart_config __initdata = { @@ -201,6 +152,7 @@ static struct omap_uart_config sdp2430_uart_config __initdata = { static struct omap_board_config_kernel sdp2430_config[] = { {OMAP_TAG_UART, &sdp2430_uart_config}, + {OMAP_TAG_LCD, &sdp2430_lcd_config}, }; @@ -248,6 +200,8 @@ static struct twl4030_hsmmc_info mmc[] __initdata = { static void __init omap_2430sdp_init(void) { + int ret; + omap2430_i2c_init(); platform_add_devices(sdp2430_devices, ARRAY_SIZE(sdp2430_devices)); @@ -256,6 +210,12 @@ static void __init omap_2430sdp_init(void) omap_serial_init(); twl4030_mmc_init(mmc); usb_musb_init(); + board_smc91x_init(); + + /* Turn off secondary LCD backlight */ + ret = gpio_request(SECONDARY_LCD_GPIO, "Secondary LCD backlight"); + if (ret == 0) + gpio_direction_output(SECONDARY_LCD_GPIO, 0); } static void __init omap_2430sdp_map_io(void) diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c index ed9274972122..496a90e4ea7a 100644 --- a/arch/arm/mach-omap2/board-3430sdp.c +++ b/arch/arm/mach-omap2/board-3430sdp.c @@ -39,15 +39,13 @@ #include #include +#include +#include "sdram-qimonda-hyb18m512160af-6.h" #include "mmc-twl4030.h" #define CONFIG_DISABLE_HFCLK 1 -#define SDP3430_ETHR_GPIO_IRQ_SDPV1 29 -#define SDP3430_ETHR_GPIO_IRQ_SDPV2 6 -#define SDP3430_SMC91X_CS 3 - #define SDP3430_TS_GPIO_IRQ_SDPV1 3 #define SDP3430_TS_GPIO_IRQ_SDPV2 2 @@ -56,24 +54,6 @@ #define TWL4030_MSECURE_GPIO 22 -static struct resource sdp3430_smc91x_resources[] = { - [0] = { - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = 0, - .end = 0, - .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL, - }, -}; - -static struct platform_device sdp3430_smc91x_device = { - .name = "smc91x", - .id = -1, - .num_resources = ARRAY_SIZE(sdp3430_smc91x_resources), - .resource = sdp3430_smc91x_resources, -}; - static int sdp3430_keymap[] = { KEY(0, 0, KEY_LEFT), KEY(0, 1, KEY_RIGHT), @@ -184,48 +164,14 @@ static struct regulator_consumer_supply sdp3430_vdvi_supply = { }; static struct platform_device *sdp3430_devices[] __initdata = { - &sdp3430_smc91x_device, &sdp3430_lcd_device, }; -static inline void __init sdp3430_init_smc91x(void) -{ - int eth_cs; - unsigned long cs_mem_base; - int eth_gpio = 0; - - eth_cs = SDP3430_SMC91X_CS; - - if (gpmc_cs_request(eth_cs, SZ_16M, &cs_mem_base) < 0) { - printk(KERN_ERR "Failed to request GPMC mem for smc91x\n"); - return; - } - - sdp3430_smc91x_resources[0].start = cs_mem_base + 0x300; - sdp3430_smc91x_resources[0].end = cs_mem_base + 0x30f; - udelay(100); - - if (omap_rev() > OMAP3430_REV_ES1_0) - eth_gpio = SDP3430_ETHR_GPIO_IRQ_SDPV2; - else - eth_gpio = SDP3430_ETHR_GPIO_IRQ_SDPV1; - - sdp3430_smc91x_resources[1].start = gpio_to_irq(eth_gpio); - - if (gpio_request(eth_gpio, "SMC91x irq") < 0) { - printk(KERN_ERR "Failed to request GPIO%d for smc91x IRQ\n", - eth_gpio); - return; - } - gpio_direction_input(eth_gpio); -} - static void __init omap_3430sdp_init_irq(void) { - omap2_init_common_hw(NULL); + omap2_init_common_hw(hyb18m512160af6_sdrc_params); omap_init_irq(); omap_gpio_init(); - sdp3430_init_smc91x(); } static struct omap_uart_config sdp3430_uart_config __initdata = { @@ -506,6 +452,32 @@ static int __init omap3430_i2c_init(void) return 0; } +#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE) + +static struct omap_smc91x_platform_data board_smc91x_data = { + .cs = 3, + .flags = GPMC_MUX_ADD_DATA | GPMC_TIMINGS_SMC91C96 | + IORESOURCE_IRQ_LOWLEVEL, +}; + +static void __init board_smc91x_init(void) +{ + if (omap_rev() > OMAP3430_REV_ES1_0) + board_smc91x_data.gpio_irq = 6; + else + board_smc91x_data.gpio_irq = 29; + + gpmc_smc91x_init(&board_smc91x_data); +} + +#else + +static inline void board_smc91x_init(void) +{ +} + +#endif + static void __init omap_3430sdp_init(void) { omap3430_i2c_init(); @@ -522,6 +494,7 @@ static void __init omap_3430sdp_init(void) ads7846_dev_init(); omap_serial_init(); usb_musb_init(); + board_smc91x_init(); } static void __init omap_3430sdp_map_io(void) diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c new file mode 100644 index 000000000000..57e477bd89c6 --- /dev/null +++ b/arch/arm/mach-omap2/board-4430sdp.c @@ -0,0 +1,94 @@ +/* + * Board support file for OMAP4430 SDP. + * + * Copyright (C) 2009 Texas Instruments + * + * Author: Santosh Shilimkar + * + * Based on mach-omap2/board-3430sdp.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +static struct platform_device sdp4430_lcd_device = { + .name = "sdp4430_lcd", + .id = -1, +}; + +static struct platform_device *sdp4430_devices[] __initdata = { + &sdp4430_lcd_device, +}; + +static struct omap_uart_config sdp4430_uart_config __initdata = { + .enabled_uarts = (1 << 0) | (1 << 1) | (1 << 2), +}; + +static struct omap_lcd_config sdp4430_lcd_config __initdata = { + .ctrl_name = "internal", +}; + +static struct omap_board_config_kernel sdp4430_config[] __initdata = { + { OMAP_TAG_UART, &sdp4430_uart_config }, + { OMAP_TAG_LCD, &sdp4430_lcd_config }, +}; + +static void __init gic_init_irq(void) +{ + gic_dist_init(0, IO_ADDRESS(OMAP44XX_GIC_DIST_BASE), 29); + gic_cpu_init(0, IO_ADDRESS(OMAP44XX_GIC_CPU_BASE)); +} + +static void __init omap_4430sdp_init_irq(void) +{ + omap2_init_common_hw(NULL); +#ifdef CONFIG_OMAP_32K_TIMER + omap2_gp_clockevent_set_gptimer(1); +#endif + gic_init_irq(); + omap_gpio_init(); +} + + +static void __init omap_4430sdp_init(void) +{ + platform_add_devices(sdp4430_devices, ARRAY_SIZE(sdp4430_devices)); + omap_board_config = sdp4430_config; + omap_board_config_size = ARRAY_SIZE(sdp4430_config); + omap_serial_init(); +} + +static void __init omap_4430sdp_map_io(void) +{ + omap2_set_globals_443x(); + omap2_map_common_io(); +} + +MACHINE_START(OMAP_4430SDP, "OMAP4430 4430SDP board") + /* Maintainer: Santosh Shilimkar - Texas Instruments Inc */ + .phys_io = 0x48000000, + .io_pg_offst = ((0xd8000000) >> 18) & 0xfffc, + .boot_params = 0x80000100, + .map_io = omap_4430sdp_map_io, + .init_irq = omap_4430sdp_init_irq, + .init_machine = omap_4430sdp_init, + .timer = &omap_timer, +MACHINE_END diff --git a/arch/arm/mach-omap2/board-ldp.c b/arch/arm/mach-omap2/board-ldp.c index da57b0fcda14..d8bc0a7dcb8d 100644 --- a/arch/arm/mach-omap2/board-ldp.c +++ b/arch/arm/mach-omap2/board-ldp.c @@ -16,11 +16,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -39,6 +41,7 @@ #include #include #include +#include #include "mmc-twl4030.h" @@ -77,8 +80,163 @@ static struct platform_device ldp_smsc911x_device = { }, }; -static struct platform_device *ldp_devices[] __initdata = { - &ldp_smsc911x_device, +static int ldp_twl4030_keymap[] = { + KEY(0, 0, KEY_1), + KEY(1, 0, KEY_2), + KEY(2, 0, KEY_3), + KEY(0, 1, KEY_4), + KEY(1, 1, KEY_5), + KEY(2, 1, KEY_6), + KEY(3, 1, KEY_F5), + KEY(0, 2, KEY_7), + KEY(1, 2, KEY_8), + KEY(2, 2, KEY_9), + KEY(3, 2, KEY_F6), + KEY(0, 3, KEY_F7), + KEY(1, 3, KEY_0), + KEY(2, 3, KEY_F8), + PERSISTENT_KEY(4, 5), + KEY(4, 4, KEY_VOLUMEUP), + KEY(5, 5, KEY_VOLUMEDOWN), + 0 +}; + +static struct twl4030_keypad_data ldp_kp_twl4030_data = { + .rows = 6, + .cols = 6, + .keymap = ldp_twl4030_keymap, + .keymapsize = ARRAY_SIZE(ldp_twl4030_keymap), + .rep = 1, +}; + +static struct gpio_keys_button ldp_gpio_keys_buttons[] = { + [0] = { + .code = KEY_ENTER, + .gpio = 101, + .desc = "enter sw", + .active_low = 1, + .debounce_interval = 30, + }, + [1] = { + .code = KEY_F1, + .gpio = 102, + .desc = "func 1", + .active_low = 1, + .debounce_interval = 30, + }, + [2] = { + .code = KEY_F2, + .gpio = 103, + .desc = "func 2", + .active_low = 1, + .debounce_interval = 30, + }, + [3] = { + .code = KEY_F3, + .gpio = 104, + .desc = "func 3", + .active_low = 1, + .debounce_interval = 30, + }, + [4] = { + .code = KEY_F4, + .gpio = 105, + .desc = "func 4", + .active_low = 1, + .debounce_interval = 30, + }, + [5] = { + .code = KEY_LEFT, + .gpio = 106, + .desc = "left sw", + .active_low = 1, + .debounce_interval = 30, + }, + [6] = { + .code = KEY_RIGHT, + .gpio = 107, + .desc = "right sw", + .active_low = 1, + .debounce_interval = 30, + }, + [7] = { + .code = KEY_UP, + .gpio = 108, + .desc = "up sw", + .active_low = 1, + .debounce_interval = 30, + }, + [8] = { + .code = KEY_DOWN, + .gpio = 109, + .desc = "down sw", + .active_low = 1, + .debounce_interval = 30, + }, +}; + +static struct gpio_keys_platform_data ldp_gpio_keys = { + .buttons = ldp_gpio_keys_buttons, + .nbuttons = ARRAY_SIZE(ldp_gpio_keys_buttons), + .rep = 1, +}; + +static struct platform_device ldp_gpio_keys_device = { + .name = "gpio-keys", + .id = -1, + .dev = { + .platform_data = &ldp_gpio_keys, + }, +}; + +static int ts_gpio; + +/** + * @brief ads7846_dev_init : Requests & sets GPIO line for pen-irq + * + * @return - void. If request gpio fails then Flag KERN_ERR. + */ +static void ads7846_dev_init(void) +{ + if (gpio_request(ts_gpio, "ads7846 irq") < 0) { + printk(KERN_ERR "can't get ads746 pen down GPIO\n"); + return; + } + + gpio_direction_input(ts_gpio); + omap_set_gpio_debounce(ts_gpio, 1); + omap_set_gpio_debounce_time(ts_gpio, 0xa); +} + +static int ads7846_get_pendown_state(void) +{ + return !gpio_get_value(ts_gpio); +} + +static struct ads7846_platform_data tsc2046_config __initdata = { + .get_pendown_state = ads7846_get_pendown_state, + .keep_vref_on = 1, +}; + +static struct omap2_mcspi_device_config tsc2046_mcspi_config = { + .turbo_mode = 0, + .single_channel = 1, /* 0: slave, 1: master */ +}; + +static struct spi_board_info ldp_spi_board_info[] __initdata = { + [0] = { + /* + * TSC2046 operates at a max freqency of 2MHz, so + * operate slightly below at 1.5MHz + */ + .modalias = "ads7846", + .bus_num = 1, + .chip_select = 0, + .max_speed_hz = 1500000, + .controller_data = &tsc2046_mcspi_config, + .irq = 0, + .platform_data = &tsc2046_config, + }, }; static inline void __init ldp_init_smsc911x(void) @@ -122,8 +280,22 @@ static struct omap_uart_config ldp_uart_config __initdata = { .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)), }; +static struct platform_device ldp_lcd_device = { + .name = "ldp_lcd", + .id = -1, +}; + +static struct omap_lcd_config ldp_lcd_config __initdata = { + .ctrl_name = "internal", +}; + static struct omap_board_config_kernel ldp_config[] __initdata = { { OMAP_TAG_UART, &ldp_uart_config }, + { OMAP_TAG_LCD, &ldp_lcd_config }, +}; + +static struct twl4030_usb_data ldp_usb_data = { + .usb_mode = T2_USB_MODE_ULPI, }; static struct twl4030_gpio_platform_data ldp_gpio_data = { @@ -132,12 +304,39 @@ static struct twl4030_gpio_platform_data ldp_gpio_data = { .irq_end = TWL4030_GPIO_IRQ_END, }; +static struct twl4030_madc_platform_data ldp_madc_data = { + .irq_line = 1, +}; + +static struct regulator_consumer_supply ldp_vmmc1_supply = { + .supply = "vmmc", +}; + +/* VMMC1 for MMC1 pins CMD, CLK, DAT0..DAT3 (20 mA, plus card == max 220 mA) */ +static struct regulator_init_data ldp_vmmc1 = { + .constraints = { + .min_uV = 1850000, + .max_uV = 3150000, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE + | REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = 1, + .consumer_supplies = &ldp_vmmc1_supply, +}; + static struct twl4030_platform_data ldp_twldata = { .irq_base = TWL4030_IRQ_BASE, .irq_end = TWL4030_IRQ_END, /* platform_data for children goes here */ + .madc = &ldp_madc_data, + .usb = &ldp_usb_data, + .vmmc1 = &ldp_vmmc1, .gpio = &ldp_gpio_data, + .keypad = &ldp_kp_twl4030_data, }; static struct i2c_board_info __initdata ldp_i2c_boardinfo[] = { @@ -168,15 +367,29 @@ static struct twl4030_hsmmc_info mmc[] __initdata = { {} /* Terminator */ }; +static struct platform_device *ldp_devices[] __initdata = { + &ldp_smsc911x_device, + &ldp_lcd_device, + &ldp_gpio_keys_device, +}; + static void __init omap_ldp_init(void) { omap_i2c_init(); platform_add_devices(ldp_devices, ARRAY_SIZE(ldp_devices)); omap_board_config = ldp_config; omap_board_config_size = ARRAY_SIZE(ldp_config); + ts_gpio = 54; + ldp_spi_board_info[0].irq = gpio_to_irq(ts_gpio); + spi_register_board_info(ldp_spi_board_info, + ARRAY_SIZE(ldp_spi_board_info)); + ads7846_dev_init(); omap_serial_init(); - twl4030_mmc_init(mmc); usb_musb_init(); + + twl4030_mmc_init(mmc); + /* link regulators to MMC adapters */ + ldp_vmmc1_supply.dev = mmc[0].dev; } static void __init omap_ldp_map_io(void) diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c index 3a7a29d1f9a7..991ac9c38032 100644 --- a/arch/arm/mach-omap2/board-omap3beagle.c +++ b/arch/arm/mach-omap2/board-omap3beagle.c @@ -28,6 +28,7 @@ #include #include +#include #include #include @@ -105,6 +106,8 @@ static struct platform_device omap3beagle_nand_device = { .resource = &omap3beagle_nand_resource, }; +#include "sdram-micron-mt46h32m32lf-6.h" + static struct omap_uart_config omap3_beagle_uart_config __initdata = { .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)), }; @@ -118,6 +121,23 @@ static struct twl4030_hsmmc_info mmc[] = { {} /* Terminator */ }; +static struct platform_device omap3_beagle_lcd_device = { + .name = "omap3beagle_lcd", + .id = -1, +}; + +static struct omap_lcd_config omap3_beagle_lcd_config __initdata = { + .ctrl_name = "internal", +}; + +static struct regulator_consumer_supply beagle_vmmc1_supply = { + .supply = "vmmc", +}; + +static struct regulator_consumer_supply beagle_vsim_supply = { + .supply = "vmmc_aux", +}; + static struct gpio_led gpio_leds[]; static int beagle_twl_gpio_setup(struct device *dev, @@ -128,6 +148,10 @@ static int beagle_twl_gpio_setup(struct device *dev, mmc[0].gpio_cd = gpio + 0; twl4030_mmc_init(mmc); + /* link regulators to MMC adapters */ + beagle_vmmc1_supply.dev = mmc[0].dev; + beagle_vsim_supply.dev = mmc[0].dev; + /* REVISIT: need ehci-omap hooks for external VBUS * power switch and overcurrent detect */ @@ -156,12 +180,85 @@ static struct twl4030_gpio_platform_data beagle_gpio_data = { .setup = beagle_twl_gpio_setup, }; +static struct regulator_consumer_supply beagle_vdac_supply = { + .supply = "vdac", + .dev = &omap3_beagle_lcd_device.dev, +}; + +static struct regulator_consumer_supply beagle_vdvi_supply = { + .supply = "vdvi", + .dev = &omap3_beagle_lcd_device.dev, +}; + +/* VMMC1 for MMC1 pins CMD, CLK, DAT0..DAT3 (20 mA, plus card == max 220 mA) */ +static struct regulator_init_data beagle_vmmc1 = { + .constraints = { + .min_uV = 1850000, + .max_uV = 3150000, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE + | REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = 1, + .consumer_supplies = &beagle_vmmc1_supply, +}; + +/* VSIM for MMC1 pins DAT4..DAT7 (2 mA, plus card == max 50 mA) */ +static struct regulator_init_data beagle_vsim = { + .constraints = { + .min_uV = 1800000, + .max_uV = 3000000, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE + | REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = 1, + .consumer_supplies = &beagle_vsim_supply, +}; + +/* VDAC for DSS driving S-Video (8 mA unloaded, max 65 mA) */ +static struct regulator_init_data beagle_vdac = { + .constraints = { + .min_uV = 1800000, + .max_uV = 1800000, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = 1, + .consumer_supplies = &beagle_vdac_supply, +}; + +/* VPLL2 for digital video outputs */ +static struct regulator_init_data beagle_vpll2 = { + .constraints = { + .name = "VDVI", + .min_uV = 1800000, + .max_uV = 1800000, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = 1, + .consumer_supplies = &beagle_vdvi_supply, +}; + static struct twl4030_platform_data beagle_twldata = { .irq_base = TWL4030_IRQ_BASE, .irq_end = TWL4030_IRQ_END, /* platform_data for children goes here */ .gpio = &beagle_gpio_data, + .vmmc1 = &beagle_vmmc1, + .vsim = &beagle_vsim, + .vdac = &beagle_vdac, + .vpll2 = &beagle_vpll2, }; static struct i2c_board_info __initdata beagle_i2c_boardinfo[] = { @@ -185,7 +282,7 @@ static int __init omap3_beagle_i2c_init(void) static void __init omap3_beagle_init_irq(void) { - omap2_init_common_hw(NULL); + omap2_init_common_hw(mt46h32m32lf6_sdrc_params); omap_init_irq(); #ifdef CONFIG_OMAP_32K_TIMER omap2_gp_clockevent_set_gptimer(12); @@ -193,15 +290,6 @@ static void __init omap3_beagle_init_irq(void) omap_gpio_init(); } -static struct platform_device omap3_beagle_lcd_device = { - .name = "omap3beagle_lcd", - .id = -1, -}; - -static struct omap_lcd_config omap3_beagle_lcd_config __initdata = { - .ctrl_name = "internal", -}; - static struct gpio_led gpio_leds[] = { { .name = "beagleboard::usr0", diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c new file mode 100644 index 000000000000..d3cc145814d0 --- /dev/null +++ b/arch/arm/mach-omap2/board-omap3evm.c @@ -0,0 +1,329 @@ +/* + * linux/arch/arm/mach-omap2/board-omap3evm.c + * + * Copyright (C) 2008 Texas Instruments + * + * Modified from mach-omap2/board-3430sdp.c + * + * Initial code: Syed Mohammed Khasim + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "sdram-micron-mt46h32m32lf-6.h" +#include "mmc-twl4030.h" + +#define OMAP3_EVM_TS_GPIO 175 + +#define OMAP3EVM_ETHR_START 0x2c000000 +#define OMAP3EVM_ETHR_SIZE 1024 +#define OMAP3EVM_ETHR_GPIO_IRQ 176 +#define OMAP3EVM_SMC911X_CS 5 + +static struct resource omap3evm_smc911x_resources[] = { + [0] = { + .start = OMAP3EVM_ETHR_START, + .end = (OMAP3EVM_ETHR_START + OMAP3EVM_ETHR_SIZE - 1), + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = OMAP_GPIO_IRQ(OMAP3EVM_ETHR_GPIO_IRQ), + .end = OMAP_GPIO_IRQ(OMAP3EVM_ETHR_GPIO_IRQ), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device omap3evm_smc911x_device = { + .name = "smc911x", + .id = -1, + .num_resources = ARRAY_SIZE(omap3evm_smc911x_resources), + .resource = &omap3evm_smc911x_resources[0], +}; + +static inline void __init omap3evm_init_smc911x(void) +{ + int eth_cs; + struct clk *l3ck; + unsigned int rate; + + eth_cs = OMAP3EVM_SMC911X_CS; + + l3ck = clk_get(NULL, "l3_ck"); + if (IS_ERR(l3ck)) + rate = 100000000; + else + rate = clk_get_rate(l3ck); + + if (gpio_request(OMAP3EVM_ETHR_GPIO_IRQ, "SMC911x irq") < 0) { + printk(KERN_ERR "Failed to request GPIO%d for smc911x IRQ\n", + OMAP3EVM_ETHR_GPIO_IRQ); + return; + } + + gpio_direction_input(OMAP3EVM_ETHR_GPIO_IRQ); +} + +static struct omap_uart_config omap3_evm_uart_config __initdata = { + .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)), +}; + +static struct twl4030_hsmmc_info mmc[] = { + { + .mmc = 1, + .wires = 4, + .gpio_cd = -EINVAL, + .gpio_wp = 63, + }, + {} /* Terminator */ +}; + +static struct gpio_led gpio_leds[] = { + { + .name = "omap3evm::ledb", + /* normally not visible (board underside) */ + .default_trigger = "default-on", + .gpio = -EINVAL, /* gets replaced */ + .active_low = true, + }, +}; + +static struct gpio_led_platform_data gpio_led_info = { + .leds = gpio_leds, + .num_leds = ARRAY_SIZE(gpio_leds), +}; + +static struct platform_device leds_gpio = { + .name = "leds-gpio", + .id = -1, + .dev = { + .platform_data = &gpio_led_info, + }, +}; + + +static int omap3evm_twl_gpio_setup(struct device *dev, + unsigned gpio, unsigned ngpio) +{ + /* gpio + 0 is "mmc0_cd" (input/IRQ) */ + omap_cfg_reg(L8_34XX_GPIO63); + mmc[0].gpio_cd = gpio + 0; + twl4030_mmc_init(mmc); + + /* + * Most GPIOs are for USB OTG. Some are mostly sent to + * the P2 connector; notably LEDA for the LCD backlight. + */ + + /* TWL4030_GPIO_MAX + 1 == ledB (out, active low LED) */ + gpio_leds[2].gpio = gpio + TWL4030_GPIO_MAX + 1; + + platform_device_register(&leds_gpio); + + return 0; +} + +static struct twl4030_gpio_platform_data omap3evm_gpio_data = { + .gpio_base = OMAP_MAX_GPIO_LINES, + .irq_base = TWL4030_GPIO_IRQ_BASE, + .irq_end = TWL4030_GPIO_IRQ_END, + .use_leds = true, + .setup = omap3evm_twl_gpio_setup, +}; + +static struct twl4030_usb_data omap3evm_usb_data = { + .usb_mode = T2_USB_MODE_ULPI, +}; + +static int omap3evm_keymap[] = { + KEY(0, 0, KEY_LEFT), + KEY(0, 1, KEY_RIGHT), + KEY(0, 2, KEY_A), + KEY(0, 3, KEY_B), + KEY(1, 0, KEY_DOWN), + KEY(1, 1, KEY_UP), + KEY(1, 2, KEY_E), + KEY(1, 3, KEY_F), + KEY(2, 0, KEY_ENTER), + KEY(2, 1, KEY_I), + KEY(2, 2, KEY_J), + KEY(2, 3, KEY_K), + KEY(3, 0, KEY_M), + KEY(3, 1, KEY_N), + KEY(3, 2, KEY_O), + KEY(3, 3, KEY_P) +}; + +static struct twl4030_keypad_data omap3evm_kp_data = { + .rows = 4, + .cols = 4, + .keymap = omap3evm_keymap, + .keymapsize = ARRAY_SIZE(omap3evm_keymap), + .rep = 1, +}; + +static struct twl4030_madc_platform_data omap3evm_madc_data = { + .irq_line = 1, +}; + +static struct twl4030_platform_data omap3evm_twldata = { + .irq_base = TWL4030_IRQ_BASE, + .irq_end = TWL4030_IRQ_END, + + /* platform_data for children goes here */ + .keypad = &omap3evm_kp_data, + .madc = &omap3evm_madc_data, + .usb = &omap3evm_usb_data, + .gpio = &omap3evm_gpio_data, +}; + +static struct i2c_board_info __initdata omap3evm_i2c_boardinfo[] = { + { + I2C_BOARD_INFO("twl4030", 0x48), + .flags = I2C_CLIENT_WAKE, + .irq = INT_34XX_SYS_NIRQ, + .platform_data = &omap3evm_twldata, + }, +}; + +static int __init omap3_evm_i2c_init(void) +{ + omap_register_i2c_bus(1, 2600, omap3evm_i2c_boardinfo, + ARRAY_SIZE(omap3evm_i2c_boardinfo)); + omap_register_i2c_bus(2, 400, NULL, 0); + omap_register_i2c_bus(3, 400, NULL, 0); + return 0; +} + +static struct platform_device omap3_evm_lcd_device = { + .name = "omap3evm_lcd", + .id = -1, +}; + +static struct omap_lcd_config omap3_evm_lcd_config __initdata = { + .ctrl_name = "internal", +}; + +static void ads7846_dev_init(void) +{ + if (gpio_request(OMAP3_EVM_TS_GPIO, "ADS7846 pendown") < 0) + printk(KERN_ERR "can't get ads7846 pen down GPIO\n"); + + gpio_direction_input(OMAP3_EVM_TS_GPIO); + + omap_set_gpio_debounce(OMAP3_EVM_TS_GPIO, 1); + omap_set_gpio_debounce_time(OMAP3_EVM_TS_GPIO, 0xa); +} + +static int ads7846_get_pendown_state(void) +{ + return !gpio_get_value(OMAP3_EVM_TS_GPIO); +} + +struct ads7846_platform_data ads7846_config = { + .x_max = 0x0fff, + .y_max = 0x0fff, + .x_plate_ohms = 180, + .pressure_max = 255, + .debounce_max = 10, + .debounce_tol = 3, + .debounce_rep = 1, + .get_pendown_state = ads7846_get_pendown_state, + .keep_vref_on = 1, + .settle_delay_usecs = 150, +}; + +static struct omap2_mcspi_device_config ads7846_mcspi_config = { + .turbo_mode = 0, + .single_channel = 1, /* 0: slave, 1: master */ +}; + +struct spi_board_info omap3evm_spi_board_info[] = { + [0] = { + .modalias = "ads7846", + .bus_num = 1, + .chip_select = 0, + .max_speed_hz = 1500000, + .controller_data = &ads7846_mcspi_config, + .irq = OMAP_GPIO_IRQ(OMAP3_EVM_TS_GPIO), + .platform_data = &ads7846_config, + }, +}; + +static void __init omap3_evm_init_irq(void) +{ + omap2_init_common_hw(mt46h32m32lf6_sdrc_params); + omap_init_irq(); + omap_gpio_init(); + omap3evm_init_smc911x(); +} + +static struct omap_board_config_kernel omap3_evm_config[] __initdata = { + { OMAP_TAG_UART, &omap3_evm_uart_config }, + { OMAP_TAG_LCD, &omap3_evm_lcd_config }, +}; + +static struct platform_device *omap3_evm_devices[] __initdata = { + &omap3_evm_lcd_device, + &omap3evm_smc911x_device, +}; + +static void __init omap3_evm_init(void) +{ + omap3_evm_i2c_init(); + + platform_add_devices(omap3_evm_devices, ARRAY_SIZE(omap3_evm_devices)); + omap_board_config = omap3_evm_config; + omap_board_config_size = ARRAY_SIZE(omap3_evm_config); + + spi_register_board_info(omap3evm_spi_board_info, + ARRAY_SIZE(omap3evm_spi_board_info)); + + omap_serial_init(); + usb_musb_init(); + ads7846_dev_init(); +} + +static void __init omap3_evm_map_io(void) +{ + omap2_set_globals_343x(); + omap2_map_common_io(); +} + +MACHINE_START(OMAP3EVM, "OMAP3 EVM") + /* Maintainer: Syed Mohammed Khasim - Texas Instruments */ + .phys_io = 0x48000000, + .io_pg_offst = ((0xd8000000) >> 18) & 0xfffc, + .boot_params = 0x80000100, + .map_io = omap3_evm_map_io, + .init_irq = omap3_evm_init_irq, + .init_machine = omap3_evm_init, + .timer = &omap_timer, +MACHINE_END diff --git a/arch/arm/mach-omap2/board-omap3pandora.c b/arch/arm/mach-omap2/board-omap3pandora.c index 402f09c6cf10..e32aa23ce962 100644 --- a/arch/arm/mach-omap2/board-omap3pandora.c +++ b/arch/arm/mach-omap2/board-omap3pandora.c @@ -23,7 +23,11 @@ #include #include +#include #include +#include +#include +#include #include #include @@ -35,11 +39,154 @@ #include #include #include +#include +#include "sdram-micron-mt46h32m32lf-6.h" #include "mmc-twl4030.h" #define OMAP3_PANDORA_TS_GPIO 94 +/* hardware debounce: (value + 1) * 31us */ +#define GPIO_DEBOUNCE_TIME 127 + +static struct gpio_led pandora_gpio_leds[] = { + { + .name = "pandora::sd1", + .default_trigger = "mmc0", + .gpio = 128, + }, { + .name = "pandora::sd2", + .default_trigger = "mmc1", + .gpio = 129, + }, { + .name = "pandora::bluetooth", + .gpio = 158, + }, { + .name = "pandora::wifi", + .gpio = 159, + }, +}; + +static struct gpio_led_platform_data pandora_gpio_led_data = { + .leds = pandora_gpio_leds, + .num_leds = ARRAY_SIZE(pandora_gpio_leds), +}; + +static struct platform_device pandora_leds_gpio = { + .name = "leds-gpio", + .id = -1, + .dev = { + .platform_data = &pandora_gpio_led_data, + }, +}; + +#define GPIO_BUTTON(gpio_num, ev_type, ev_code, act_low, descr) \ +{ \ + .gpio = gpio_num, \ + .type = ev_type, \ + .code = ev_code, \ + .active_low = act_low, \ + .desc = "btn " descr, \ +} + +#define GPIO_BUTTON_LOW(gpio_num, event_code, description) \ + GPIO_BUTTON(gpio_num, EV_KEY, event_code, 1, description) + +static struct gpio_keys_button pandora_gpio_keys[] = { + GPIO_BUTTON_LOW(110, KEY_UP, "up"), + GPIO_BUTTON_LOW(103, KEY_DOWN, "down"), + GPIO_BUTTON_LOW(96, KEY_LEFT, "left"), + GPIO_BUTTON_LOW(98, KEY_RIGHT, "right"), + GPIO_BUTTON_LOW(111, BTN_A, "a"), + GPIO_BUTTON_LOW(106, BTN_B, "b"), + GPIO_BUTTON_LOW(109, BTN_X, "x"), + GPIO_BUTTON_LOW(101, BTN_Y, "y"), + GPIO_BUTTON_LOW(102, BTN_TL, "l"), + GPIO_BUTTON_LOW(97, BTN_TL2, "l2"), + GPIO_BUTTON_LOW(105, BTN_TR, "r"), + GPIO_BUTTON_LOW(107, BTN_TR2, "r2"), + GPIO_BUTTON_LOW(104, KEY_LEFTCTRL, "ctrl"), + GPIO_BUTTON_LOW(99, KEY_MENU, "menu"), + GPIO_BUTTON_LOW(176, KEY_COFFEE, "hold"), + GPIO_BUTTON(100, EV_KEY, KEY_LEFTALT, 0, "alt"), + GPIO_BUTTON(108, EV_SW, SW_LID, 1, "lid"), +}; + +static struct gpio_keys_platform_data pandora_gpio_key_info = { + .buttons = pandora_gpio_keys, + .nbuttons = ARRAY_SIZE(pandora_gpio_keys), +}; + +static struct platform_device pandora_keys_gpio = { + .name = "gpio-keys", + .id = -1, + .dev = { + .platform_data = &pandora_gpio_key_info, + }, +}; + +static void __init pandora_keys_gpio_init(void) +{ + /* set debounce time for GPIO banks 4 and 6 */ + omap_set_gpio_debounce_time(32 * 3, GPIO_DEBOUNCE_TIME); + omap_set_gpio_debounce_time(32 * 5, GPIO_DEBOUNCE_TIME); +} + +static int pandora_keypad_map[] = { + /* col, row, code */ + KEY(0, 0, KEY_9), + KEY(0, 1, KEY_0), + KEY(0, 2, KEY_BACKSPACE), + KEY(0, 3, KEY_O), + KEY(0, 4, KEY_P), + KEY(0, 5, KEY_K), + KEY(0, 6, KEY_L), + KEY(0, 7, KEY_ENTER), + KEY(1, 0, KEY_8), + KEY(1, 1, KEY_7), + KEY(1, 2, KEY_6), + KEY(1, 3, KEY_5), + KEY(1, 4, KEY_4), + KEY(1, 5, KEY_3), + KEY(1, 6, KEY_2), + KEY(1, 7, KEY_1), + KEY(2, 0, KEY_I), + KEY(2, 1, KEY_U), + KEY(2, 2, KEY_Y), + KEY(2, 3, KEY_T), + KEY(2, 4, KEY_R), + KEY(2, 5, KEY_E), + KEY(2, 6, KEY_W), + KEY(2, 7, KEY_Q), + KEY(3, 0, KEY_J), + KEY(3, 1, KEY_H), + KEY(3, 2, KEY_G), + KEY(3, 3, KEY_F), + KEY(3, 4, KEY_D), + KEY(3, 5, KEY_S), + KEY(3, 6, KEY_A), + KEY(3, 7, KEY_LEFTSHIFT), + KEY(4, 0, KEY_N), + KEY(4, 1, KEY_B), + KEY(4, 2, KEY_V), + KEY(4, 3, KEY_C), + KEY(4, 4, KEY_X), + KEY(4, 5, KEY_Z), + KEY(4, 6, KEY_DOT), + KEY(4, 7, KEY_COMMA), + KEY(5, 0, KEY_M), + KEY(5, 1, KEY_SPACE), + KEY(5, 2, KEY_FN), +}; + +static struct twl4030_keypad_data pandora_kp_data = { + .rows = 8, + .cols = 6, + .keymap = pandora_keypad_map, + .keymapsize = ARRAY_SIZE(pandora_keypad_map), + .rep = 1, +}; + static struct twl4030_hsmmc_info omap3pandora_mmc[] = { { .mmc = 1, @@ -69,6 +216,14 @@ static struct omap_uart_config omap3pandora_uart_config __initdata = { .enabled_uarts = (1 << 2), /* UART3 */ }; +static struct regulator_consumer_supply pandora_vmmc1_supply = { + .supply = "vmmc", +}; + +static struct regulator_consumer_supply pandora_vmmc2_supply = { + .supply = "vmmc", +}; + static int omap3pandora_twl_gpio_setup(struct device *dev, unsigned gpio, unsigned ngpio) { @@ -77,6 +232,10 @@ static int omap3pandora_twl_gpio_setup(struct device *dev, omap3pandora_mmc[1].gpio_cd = gpio + 1; twl4030_mmc_init(omap3pandora_mmc); + /* link regulators to MMC adapters */ + pandora_vmmc1_supply.dev = omap3pandora_mmc[0].dev; + pandora_vmmc2_supply.dev = omap3pandora_mmc[1].dev; + return 0; } @@ -87,6 +246,36 @@ static struct twl4030_gpio_platform_data omap3pandora_gpio_data = { .setup = omap3pandora_twl_gpio_setup, }; +/* VMMC1 for MMC1 pins CMD, CLK, DAT0..DAT3 (20 mA, plus card == max 220 mA) */ +static struct regulator_init_data pandora_vmmc1 = { + .constraints = { + .min_uV = 1850000, + .max_uV = 3150000, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE + | REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = 1, + .consumer_supplies = &pandora_vmmc1_supply, +}; + +/* VMMC2 for MMC2 pins CMD, CLK, DAT0..DAT3 (max 100 mA) */ +static struct regulator_init_data pandora_vmmc2 = { + .constraints = { + .min_uV = 1850000, + .max_uV = 3150000, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE + | REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = 1, + .consumer_supplies = &pandora_vmmc2_supply, +}; + static struct twl4030_usb_data omap3pandora_usb_data = { .usb_mode = T2_USB_MODE_ULPI, }; @@ -96,6 +285,9 @@ static struct twl4030_platform_data omap3pandora_twldata = { .irq_end = TWL4030_IRQ_END, .gpio = &omap3pandora_gpio_data, .usb = &omap3pandora_usb_data, + .vmmc1 = &pandora_vmmc1, + .vmmc2 = &pandora_vmmc2, + .keypad = &pandora_kp_data, }; static struct i2c_board_info __initdata omap3pandora_i2c_boardinfo[] = { @@ -118,7 +310,7 @@ static int __init omap3pandora_i2c_init(void) static void __init omap3pandora_init_irq(void) { - omap2_init_common_hw(NULL); + omap2_init_common_hw(mt46h32m32lf6_sdrc_params); omap_init_irq(); omap_gpio_init(); } @@ -188,6 +380,8 @@ static struct omap_board_config_kernel omap3pandora_config[] __initdata = { static struct platform_device *omap3pandora_devices[] __initdata = { &omap3pandora_lcd_device, + &pandora_leds_gpio, + &pandora_keys_gpio, }; static void __init omap3pandora_init(void) @@ -201,6 +395,7 @@ static void __init omap3pandora_init(void) spi_register_board_info(omap3pandora_spi_board_info, ARRAY_SIZE(omap3pandora_spi_board_info)); omap3pandora_ads7846_init(); + pandora_keys_gpio_init(); usb_musb_init(); } diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c index b1f23bea863f..dff5528fbfb5 100644 --- a/arch/arm/mach-omap2/board-overo.c +++ b/arch/arm/mach-omap2/board-overo.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -45,6 +46,7 @@ #include #include +#include "sdram-micron-mt46h32m32lf-6.h" #include "mmc-twl4030.h" #define OVERO_GPIO_BT_XGATE 15 @@ -271,21 +273,76 @@ static struct omap_uart_config overo_uart_config __initdata = { .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)), }; +static struct twl4030_hsmmc_info mmc[] = { + { + .mmc = 1, + .wires = 4, + .gpio_cd = -EINVAL, + .gpio_wp = -EINVAL, + }, + { + .mmc = 2, + .wires = 4, + .gpio_cd = -EINVAL, + .gpio_wp = -EINVAL, + .transceiver = true, + .ocr_mask = 0x00100000, /* 3.3V */ + }, + {} /* Terminator */ +}; + +static struct regulator_consumer_supply overo_vmmc1_supply = { + .supply = "vmmc", +}; + +static int overo_twl_gpio_setup(struct device *dev, + unsigned gpio, unsigned ngpio) +{ + twl4030_mmc_init(mmc); + + overo_vmmc1_supply.dev = mmc[0].dev; + + return 0; +} + static struct twl4030_gpio_platform_data overo_gpio_data = { .gpio_base = OMAP_MAX_GPIO_LINES, .irq_base = TWL4030_GPIO_IRQ_BASE, .irq_end = TWL4030_GPIO_IRQ_END, + .setup = overo_twl_gpio_setup, }; +static struct twl4030_usb_data overo_usb_data = { + .usb_mode = T2_USB_MODE_ULPI, +}; + +static struct regulator_init_data overo_vmmc1 = { + .constraints = { + .min_uV = 1850000, + .max_uV = 3150000, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE + | REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = 1, + .consumer_supplies = &overo_vmmc1_supply, +}; + +/* mmc2 (WLAN) and Bluetooth don't use twl4030 regulators */ + static struct twl4030_platform_data overo_twldata = { .irq_base = TWL4030_IRQ_BASE, .irq_end = TWL4030_IRQ_END, .gpio = &overo_gpio_data, + .usb = &overo_usb_data, + .vmmc1 = &overo_vmmc1, }; static struct i2c_board_info __initdata overo_i2c_boardinfo[] = { { - I2C_BOARD_INFO("twl4030", 0x48), + I2C_BOARD_INFO("tps65950", 0x48), .flags = I2C_CLIENT_WAKE, .irq = INT_34XX_SYS_NIRQ, .platform_data = &overo_twldata, @@ -303,7 +360,7 @@ static int __init overo_i2c_init(void) static void __init overo_init_irq(void) { - omap2_init_common_hw(NULL); + omap2_init_common_hw(mt46h32m32lf6_sdrc_params); omap_init_irq(); omap_gpio_init(); } @@ -326,23 +383,6 @@ static struct platform_device *overo_devices[] __initdata = { &overo_lcd_device, }; -static struct twl4030_hsmmc_info mmc[] __initdata = { - { - .mmc = 1, - .wires = 4, - .gpio_cd = -EINVAL, - .gpio_wp = -EINVAL, - }, - { - .mmc = 2, - .wires = 4, - .gpio_cd = -EINVAL, - .gpio_wp = -EINVAL, - .transceiver = true, - }, - {} /* Terminator */ -}; - static void __init overo_init(void) { overo_i2c_init(); @@ -350,7 +390,6 @@ static void __init overo_init(void) omap_board_config = overo_config; omap_board_config_size = ARRAY_SIZE(overo_config); omap_serial_init(); - twl4030_mmc_init(mmc); overo_flash_init(); usb_musb_init(); overo_ads7846_init(); diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c index a7381729645c..da93b86234ed 100644 --- a/arch/arm/mach-omap2/board-rx51-peripherals.c +++ b/arch/arm/mach-omap2/board-rx51-peripherals.c @@ -27,30 +27,13 @@ #include #include #include +#include +#include #include "mmc-twl4030.h" - -#define SMC91X_CS 1 -#define SMC91X_GPIO_IRQ 54 -#define SMC91X_GPIO_RESET 164 -#define SMC91X_GPIO_PWRDWN 86 - -static struct resource rx51_smc91x_resources[] = { - [0] = { - .flags = IORESOURCE_MEM, - }, - [1] = { - .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE, - }, -}; - -static struct platform_device rx51_smc91x_device = { - .name = "smc91x", - .id = -1, - .num_resources = ARRAY_SIZE(rx51_smc91x_resources), - .resource = rx51_smc91x_resources, -}; +#define SYSTEM_REV_B_USES_VAUX3 0x1699 +#define SYSTEM_REV_S_USES_VAUX3 0x8 static int rx51_keymap[] = { KEY(0, 0, KEY_Q), @@ -107,98 +90,6 @@ static struct twl4030_keypad_data rx51_kp_data = { .rep = 1, }; -static struct platform_device *rx51_peripherals_devices[] = { - &rx51_smc91x_device, -}; - -/* - * Timings are taken from smsc-lan91c96-ms.pdf - */ -static int smc91x_init_gpmc(int cs) -{ - struct gpmc_timings t; - const int t2_r = 45; /* t2 in Figure 12.10 */ - const int t2_w = 30; /* t2 in Figure 12.11 */ - const int t3 = 15; /* t3 in Figure 12.10 */ - const int t5_r = 0; /* t5 in Figure 12.10 */ - const int t6_r = 45; /* t6 in Figure 12.10 */ - const int t6_w = 0; /* t6 in Figure 12.11 */ - const int t7_w = 15; /* t7 in Figure 12.11 */ - const int t15 = 12; /* t15 in Figure 12.2 */ - const int t20 = 185; /* t20 in Figure 12.2 */ - - memset(&t, 0, sizeof(t)); - - t.cs_on = t15; - t.cs_rd_off = t3 + t2_r + t5_r; /* Figure 12.10 */ - t.cs_wr_off = t3 + t2_w + t6_w; /* Figure 12.11 */ - t.adv_on = t3; /* Figure 12.10 */ - t.adv_rd_off = t3 + t2_r; /* Figure 12.10 */ - t.adv_wr_off = t3 + t2_w; /* Figure 12.11 */ - t.oe_off = t3 + t2_r + t5_r; /* Figure 12.10 */ - t.oe_on = t.oe_off - t6_r; /* Figure 12.10 */ - t.we_off = t3 + t2_w + t6_w; /* Figure 12.11 */ - t.we_on = t.we_off - t7_w; /* Figure 12.11 */ - t.rd_cycle = t20; /* Figure 12.2 */ - t.wr_cycle = t20; /* Figure 12.4 */ - t.access = t3 + t2_r + t5_r; /* Figure 12.10 */ - t.wr_access = t3 + t2_w + t6_w; /* Figure 12.11 */ - - gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, GPMC_CONFIG1_DEVICESIZE_16); - - return gpmc_cs_set_timings(cs, &t); -} - -static void __init rx51_init_smc91x(void) -{ - unsigned long cs_mem_base; - int ret; - - omap_cfg_reg(U8_34XX_GPIO54_DOWN); - omap_cfg_reg(G25_34XX_GPIO86_OUT); - omap_cfg_reg(H19_34XX_GPIO164_OUT); - - if (gpmc_cs_request(SMC91X_CS, SZ_16M, &cs_mem_base) < 0) { - printk(KERN_ERR "Failed to request GPMC mem for smc91x\n"); - return; - } - - rx51_smc91x_resources[0].start = cs_mem_base + 0x300; - rx51_smc91x_resources[0].end = cs_mem_base + 0x30f; - - smc91x_init_gpmc(SMC91X_CS); - - if (gpio_request(SMC91X_GPIO_IRQ, "SMC91X irq") < 0) - goto free1; - - gpio_direction_input(SMC91X_GPIO_IRQ); - rx51_smc91x_resources[1].start = gpio_to_irq(SMC91X_GPIO_IRQ); - - ret = gpio_request(SMC91X_GPIO_PWRDWN, "SMC91X powerdown"); - if (ret) - goto free2; - gpio_direction_output(SMC91X_GPIO_PWRDWN, 0); - - ret = gpio_request(SMC91X_GPIO_RESET, "SMC91X reset"); - if (ret) - goto free3; - gpio_direction_output(SMC91X_GPIO_RESET, 0); - gpio_set_value(SMC91X_GPIO_RESET, 1); - msleep(100); - gpio_set_value(SMC91X_GPIO_RESET, 0); - - return; - -free3: - gpio_free(SMC91X_GPIO_PWRDWN); -free2: - gpio_free(SMC91X_GPIO_IRQ); -free1: - gpmc_cs_free(SMC91X_CS); - - printk(KERN_ERR "Could not initialize smc91x\n"); -} - static struct twl4030_madc_platform_data rx51_madc_data = { .irq_line = 1, }; @@ -259,7 +150,7 @@ static struct regulator_init_data rx51_vaux2 = { }; /* VAUX3 - adds more power to VIO_18 rail */ -static struct regulator_init_data rx51_vaux3 = { +static struct regulator_init_data rx51_vaux3_cam = { .constraints = { .name = "VCAM_DIG_18", .min_uV = 1800000, @@ -272,6 +163,22 @@ static struct regulator_init_data rx51_vaux3 = { }, }; +static struct regulator_init_data rx51_vaux3_mmc = { + .constraints = { + .name = "VMMC2_30", + .min_uV = 2800000, + .max_uV = 3000000, + .apply_uV = true, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE + | REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = 1, + .consumer_supplies = &rx51_vmmc2_supply, +}; + static struct regulator_init_data rx51_vaux4 = { .constraints = { .name = "VCAM_ANA_28", @@ -382,10 +289,8 @@ static struct twl4030_platform_data rx51_twldata = { .vaux1 = &rx51_vaux1, .vaux2 = &rx51_vaux2, - .vaux3 = &rx51_vaux3, .vaux4 = &rx51_vaux4, .vmmc1 = &rx51_vmmc1, - .vmmc2 = &rx51_vmmc2, .vsim = &rx51_vsim, .vdac = &rx51_vdac, }; @@ -401,6 +306,13 @@ static struct i2c_board_info __initdata rx51_peripherals_i2c_board_info_1[] = { static int __init rx51_i2c_init(void) { + if ((system_rev >= SYSTEM_REV_S_USES_VAUX3 && system_rev < 0x100) || + system_rev >= SYSTEM_REV_B_USES_VAUX3) + rx51_twldata.vaux3 = &rx51_vaux3_mmc; + else { + rx51_twldata.vaux3 = &rx51_vaux3_cam; + rx51_twldata.vmmc2 = &rx51_vmmc2; + } omap_register_i2c_bus(1, 2600, rx51_peripherals_i2c_board_info_1, ARRAY_SIZE(rx51_peripherals_i2c_board_info_1)); omap_register_i2c_bus(2, 100, NULL, 0); @@ -408,12 +320,94 @@ static int __init rx51_i2c_init(void) return 0; } +#if defined(CONFIG_MTD_ONENAND_OMAP2) || \ + defined(CONFIG_MTD_ONENAND_OMAP2_MODULE) + +static struct mtd_partition onenand_partitions[] = { + { + .name = "bootloader", + .offset = 0, + .size = 0x20000, + .mask_flags = MTD_WRITEABLE, /* Force read-only */ + }, + { + .name = "config", + .offset = MTDPART_OFS_APPEND, + .size = 0x60000, + }, + { + .name = "log", + .offset = MTDPART_OFS_APPEND, + .size = 0x40000, + }, + { + .name = "kernel", + .offset = MTDPART_OFS_APPEND, + .size = 0x200000, + }, + { + .name = "initfs", + .offset = MTDPART_OFS_APPEND, + .size = 0x200000, + }, + { + .name = "rootfs", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL, + }, +}; + +static struct omap_onenand_platform_data board_onenand_data = { + .cs = 0, + .gpio_irq = 65, + .parts = onenand_partitions, + .nr_parts = ARRAY_SIZE(onenand_partitions), +}; + +static void __init board_onenand_init(void) +{ + gpmc_onenand_init(&board_onenand_data); +} + +#else + +static inline void board_onenand_init(void) +{ +} + +#endif + +#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE) + +static struct omap_smc91x_platform_data board_smc91x_data = { + .cs = 1, + .gpio_irq = 54, + .gpio_pwrdwn = 86, + .gpio_reset = 164, + .flags = GPMC_TIMINGS_SMC91C96 | IORESOURCE_IRQ_HIGHLEVEL, +}; + +static void __init board_smc91x_init(void) +{ + omap_cfg_reg(U8_34XX_GPIO54_DOWN); + omap_cfg_reg(G25_34XX_GPIO86_OUT); + omap_cfg_reg(H19_34XX_GPIO164_OUT); + + gpmc_smc91x_init(&board_smc91x_data); +} + +#else + +static inline void board_smc91x_init(void) +{ +} + +#endif void __init rx51_peripherals_init(void) { - platform_add_devices(rx51_peripherals_devices, - ARRAY_SIZE(rx51_peripherals_devices)); rx51_i2c_init(); - rx51_init_smc91x(); + board_onenand_init(); + board_smc91x_init(); } diff --git a/arch/arm/mach-omap2/board-zoom-debugboard.c b/arch/arm/mach-omap2/board-zoom-debugboard.c new file mode 100644 index 000000000000..bac5c4321ff7 --- /dev/null +++ b/arch/arm/mach-omap2/board-zoom-debugboard.c @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2009 Texas Instruments Inc. + * Mikkel Christensen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include + +#include + +#define ZOOM2_SMSC911X_CS 7 +#define ZOOM2_SMSC911X_GPIO 158 +#define ZOOM2_QUADUART_CS 3 +#define ZOOM2_QUADUART_GPIO 102 +#define QUART_CLK 1843200 +#define DEBUG_BASE 0x08000000 +#define ZOOM2_ETHR_START DEBUG_BASE + +static struct resource zoom2_smsc911x_resources[] = { + [0] = { + .start = ZOOM2_ETHR_START, + .end = ZOOM2_ETHR_START + SZ_4K, + .flags = IORESOURCE_MEM, + }, + [1] = { + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL, + }, +}; + +static struct smsc911x_platform_config zoom2_smsc911x_config = { + .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW, + .irq_type = SMSC911X_IRQ_TYPE_OPEN_DRAIN, + .flags = SMSC911X_USE_32BIT, + .phy_interface = PHY_INTERFACE_MODE_MII, +}; + +static struct platform_device zoom2_smsc911x_device = { + .name = "smsc911x", + .id = -1, + .num_resources = ARRAY_SIZE(zoom2_smsc911x_resources), + .resource = zoom2_smsc911x_resources, + .dev = { + .platform_data = &zoom2_smsc911x_config, + }, +}; + +static inline void __init zoom2_init_smsc911x(void) +{ + int eth_cs; + unsigned long cs_mem_base; + int eth_gpio = 0; + + eth_cs = ZOOM2_SMSC911X_CS; + + if (gpmc_cs_request(eth_cs, SZ_16M, &cs_mem_base) < 0) { + printk(KERN_ERR "Failed to request GPMC mem for smsc911x\n"); + return; + } + + zoom2_smsc911x_resources[0].start = cs_mem_base + 0x0; + zoom2_smsc911x_resources[0].end = cs_mem_base + 0xff; + + eth_gpio = ZOOM2_SMSC911X_GPIO; + + zoom2_smsc911x_resources[1].start = OMAP_GPIO_IRQ(eth_gpio); + + if (gpio_request(eth_gpio, "smsc911x irq") < 0) { + printk(KERN_ERR "Failed to request GPIO%d for smsc911x IRQ\n", + eth_gpio); + return; + } + gpio_direction_input(eth_gpio); +} + +static struct plat_serial8250_port serial_platform_data[] = { + { + .mapbase = 0x10000000, + .irq = OMAP_GPIO_IRQ(102), + .flags = UPF_BOOT_AUTOCONF|UPF_IOREMAP|UPF_SHARE_IRQ, + .iotype = UPIO_MEM, + .regshift = 1, + .uartclk = QUART_CLK, + }, { + .flags = 0 + } +}; + +static struct platform_device zoom2_debugboard_serial_device = { + .name = "serial8250", + .id = PLAT8250_DEV_PLATFORM1, + .dev = { + .platform_data = serial_platform_data, + }, +}; + +static inline void __init zoom2_init_quaduart(void) +{ + int quart_cs; + unsigned long cs_mem_base; + int quart_gpio = 0; + + quart_cs = ZOOM2_QUADUART_CS; + + if (gpmc_cs_request(quart_cs, SZ_1M, &cs_mem_base) < 0) { + printk(KERN_ERR "Failed to request GPMC mem" + "for Quad UART(TL16CP754C)\n"); + return; + } + + quart_gpio = ZOOM2_QUADUART_GPIO; + + if (gpio_request(quart_gpio, "TL16CP754C GPIO") < 0) { + printk(KERN_ERR "Failed to request GPIO%d for TL16CP754C\n", + quart_gpio); + return; + } + gpio_direction_input(quart_gpio); +} + +static inline int omap_zoom2_debugboard_detect(void) +{ + int debug_board_detect = 0; + + debug_board_detect = ZOOM2_SMSC911X_GPIO; + + if (gpio_request(debug_board_detect, "Zoom2 debug board detect") < 0) { + printk(KERN_ERR "Failed to request GPIO%d for Zoom2 debug" + "board detect\n", debug_board_detect); + return 0; + } + gpio_direction_input(debug_board_detect); + + if (!gpio_get_value(debug_board_detect)) { + gpio_free(debug_board_detect); + return 0; + } + return 1; +} + +static struct platform_device *zoom2_devices[] __initdata = { + &zoom2_smsc911x_device, + &zoom2_debugboard_serial_device, +}; + +int __init omap_zoom2_debugboard_init(void) +{ + if (!omap_zoom2_debugboard_detect()) + return 0; + + zoom2_init_smsc911x(); + zoom2_init_quaduart(); + return platform_add_devices(zoom2_devices, ARRAY_SIZE(zoom2_devices)); +} diff --git a/arch/arm/mach-omap2/board-zoom2.c b/arch/arm/mach-omap2/board-zoom2.c new file mode 100644 index 000000000000..bcc0f7632dea --- /dev/null +++ b/arch/arm/mach-omap2/board-zoom2.c @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2009 Texas Instruments Inc. + * Mikkel Christensen + * + * Modified from mach-omap2/board-ldp.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "mmc-twl4030.h" + +static void __init omap_zoom2_init_irq(void) +{ + omap2_init_common_hw(NULL); + omap_init_irq(); + omap_gpio_init(); +} + +static struct omap_uart_config zoom2_uart_config __initdata = { + .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)), +}; + +static struct omap_board_config_kernel zoom2_config[] __initdata = { + { OMAP_TAG_UART, &zoom2_uart_config }, +}; + +static struct twl4030_gpio_platform_data zoom2_gpio_data = { + .gpio_base = OMAP_MAX_GPIO_LINES, + .irq_base = TWL4030_GPIO_IRQ_BASE, + .irq_end = TWL4030_GPIO_IRQ_END, +}; + +static struct twl4030_platform_data zoom2_twldata = { + .irq_base = TWL4030_IRQ_BASE, + .irq_end = TWL4030_IRQ_END, + + /* platform_data for children goes here */ + .gpio = &zoom2_gpio_data, +}; + +static struct i2c_board_info __initdata zoom2_i2c_boardinfo[] = { + { + I2C_BOARD_INFO("twl4030", 0x48), + .flags = I2C_CLIENT_WAKE, + .irq = INT_34XX_SYS_NIRQ, + .platform_data = &zoom2_twldata, + }, +}; + +static int __init omap_i2c_init(void) +{ + omap_register_i2c_bus(1, 2600, zoom2_i2c_boardinfo, + ARRAY_SIZE(zoom2_i2c_boardinfo)); + omap_register_i2c_bus(2, 400, NULL, 0); + omap_register_i2c_bus(3, 400, NULL, 0); + return 0; +} + +static struct twl4030_hsmmc_info mmc[] __initdata = { + { + .mmc = 1, + .wires = 4, + .gpio_cd = -EINVAL, + .gpio_wp = -EINVAL, + }, + {} /* Terminator */ +}; + +extern int __init omap_zoom2_debugboard_init(void); + +static void __init omap_zoom2_init(void) +{ + omap_i2c_init(); + omap_board_config = zoom2_config; + omap_board_config_size = ARRAY_SIZE(zoom2_config); + omap_serial_init(); + omap_zoom2_debugboard_init(); + twl4030_mmc_init(mmc); + usb_musb_init(); +} + +static void __init omap_zoom2_map_io(void) +{ + omap2_set_globals_343x(); + omap2_map_common_io(); +} + +MACHINE_START(OMAP_ZOOM2, "OMAP Zoom2 board") + .phys_io = 0x48000000, + .io_pg_offst = ((0xd8000000) >> 18) & 0xfffc, + .boot_params = 0x80000100, + .map_io = omap_zoom2_map_io, + .init_irq = omap_zoom2_init_irq, + .init_machine = omap_zoom2_init, + .timer = &omap_timer, +MACHINE_END diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c index 4247a1534411..b0665f161c03 100644 --- a/arch/arm/mach-omap2/clock.c +++ b/arch/arm/mach-omap2/clock.c @@ -91,9 +91,9 @@ static void _omap2xxx_clk_commit(struct clk *clk) return; prm_write_mod_reg(OMAP24XX_VALID_CONFIG, OMAP24XX_GR_MOD, - OMAP24XX_PRCM_CLKCFG_CTRL_OFFSET); + OMAP2_PRCM_CLKCFG_CTRL_OFFSET); /* OCP barrier */ - prm_read_mod_reg(OMAP24XX_GR_MOD, OMAP24XX_PRCM_CLKCFG_CTRL_OFFSET); + prm_read_mod_reg(OMAP24XX_GR_MOD, OMAP2_PRCM_CLKCFG_CTRL_OFFSET); } /* @@ -302,7 +302,7 @@ int omap2_wait_clock_ready(void __iomem *reg, u32 mask, const char *name) udelay(1); } - if (i < MAX_CLOCK_ENABLE_WAIT) + if (i <= MAX_CLOCK_ENABLE_WAIT) pr_debug("Clock %s stable after %d loops\n", name, i); else printk(KERN_ERR "Clock %s didn't enable in %d tries\n", @@ -547,8 +547,8 @@ u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate, const struct clksel_rate *clkr; u32 last_div = 0; - printk(KERN_INFO "clock: clksel_round_rate_div: %s target_rate %ld\n", - clk->name, target_rate); + pr_debug("clock: clksel_round_rate_div: %s target_rate %ld\n", + clk->name, target_rate); *new_div = 1; @@ -562,7 +562,7 @@ u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate, /* Sanity check */ if (clkr->div <= last_div) - printk(KERN_ERR "clock: clksel_rate table not sorted " + pr_err("clock: clksel_rate table not sorted " "for clock %s", clk->name); last_div = clkr->div; @@ -574,7 +574,7 @@ u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate, } if (!clkr->div) { - printk(KERN_ERR "clock: Could not find divisor for target " + pr_err("clock: Could not find divisor for target " "rate %ld for clock %s parent %s\n", target_rate, clk->name, clk->parent->name); return ~0; @@ -582,8 +582,8 @@ u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate, *new_div = clkr->div; - printk(KERN_INFO "clock: new_div = %d, new_rate = %ld\n", *new_div, - (clk->parent->rate / clkr->div)); + pr_debug("clock: new_div = %d, new_rate = %ld\n", *new_div, + (clk->parent->rate / clkr->div)); return (clk->parent->rate / clkr->div); } @@ -1035,7 +1035,7 @@ void omap2_clk_disable_unused(struct clk *clk) if ((regval32 & (1 << clk->enable_bit)) == v) return; - printk(KERN_INFO "Disabling unused clock \"%s\"\n", clk->name); + printk(KERN_DEBUG "Disabling unused clock \"%s\"\n", clk->name); if (cpu_is_omap34xx()) { omap2_clk_enable(clk); omap2_clk_disable(clk); diff --git a/arch/arm/mach-omap2/clock24xx.c b/arch/arm/mach-omap2/clock24xx.c index e4cef333e291..44de0271fc2f 100644 --- a/arch/arm/mach-omap2/clock24xx.c +++ b/arch/arm/mach-omap2/clock24xx.c @@ -233,6 +233,8 @@ static struct prcm_config *curr_prcm_set; static struct clk *vclk; static struct clk *sclk; +static void __iomem *prcm_clksrc_ctrl; + /*------------------------------------------------------------------------- * Omap24xx specific clock functions *-------------------------------------------------------------------------*/ @@ -269,10 +271,9 @@ static int omap2_enable_osc_ck(struct clk *clk) { u32 pcc; - pcc = __raw_readl(OMAP24XX_PRCM_CLKSRC_CTRL); + pcc = __raw_readl(prcm_clksrc_ctrl); - __raw_writel(pcc & ~OMAP_AUTOEXTCLKMODE_MASK, - OMAP24XX_PRCM_CLKSRC_CTRL); + __raw_writel(pcc & ~OMAP_AUTOEXTCLKMODE_MASK, prcm_clksrc_ctrl); return 0; } @@ -281,10 +282,9 @@ static void omap2_disable_osc_ck(struct clk *clk) { u32 pcc; - pcc = __raw_readl(OMAP24XX_PRCM_CLKSRC_CTRL); + pcc = __raw_readl(prcm_clksrc_ctrl); - __raw_writel(pcc | OMAP_AUTOEXTCLKMODE_MASK, - OMAP24XX_PRCM_CLKSRC_CTRL); + __raw_writel(pcc | OMAP_AUTOEXTCLKMODE_MASK, prcm_clksrc_ctrl); } static const struct clkops clkops_oscck = { @@ -654,7 +654,7 @@ static u32 omap2_get_sysclkdiv(void) { u32 div; - div = __raw_readl(OMAP24XX_PRCM_CLKSRC_CTRL); + div = __raw_readl(prcm_clksrc_ctrl); div &= OMAP_SYSCLKDIV_MASK; div >>= OMAP_SYSCLKDIV_SHIFT; @@ -714,15 +714,18 @@ int __init omap2_clk_init(void) struct omap_clk *c; u32 clkrate; - if (cpu_is_omap242x()) + if (cpu_is_omap242x()) { + prcm_clksrc_ctrl = OMAP2420_PRCM_CLKSRC_CTRL; cpu_mask = RATE_IN_242X; - else if (cpu_is_omap2430()) + } else if (cpu_is_omap2430()) { + prcm_clksrc_ctrl = OMAP2430_PRCM_CLKSRC_CTRL; cpu_mask = RATE_IN_243X; + } clk_init(&omap2_clk_functions); for (c = omap24xx_clks; c < omap24xx_clks + ARRAY_SIZE(omap24xx_clks); c++) - clk_init_one(c->lk.clk); + clk_preinit(c->lk.clk); osc_ck.rate = omap2_osc_clk_recalc(&osc_ck); propagate_rate(&osc_ck); diff --git a/arch/arm/mach-omap2/clock24xx.h b/arch/arm/mach-omap2/clock24xx.h index 88c5acb40fcf..458f00cdcbea 100644 --- a/arch/arm/mach-omap2/clock24xx.h +++ b/arch/arm/mach-omap2/clock24xx.h @@ -24,6 +24,17 @@ #include "cm-regbits-24xx.h" #include "sdrc.h" +/* REVISIT: These should be set dynamically for CONFIG_MULTI_OMAP2 */ +#ifdef CONFIG_ARCH_OMAP2420 +#define OMAP_CM_REGADDR OMAP2420_CM_REGADDR +#define OMAP24XX_PRCM_CLKOUT_CTRL OMAP2420_PRCM_CLKOUT_CTRL +#define OMAP24XX_PRCM_CLKEMUL_CTRL OMAP2420_PRCM_CLKEMUL_CTRL +#else +#define OMAP_CM_REGADDR OMAP2430_CM_REGADDR +#define OMAP24XX_PRCM_CLKOUT_CTRL OMAP2430_PRCM_CLKOUT_CTRL +#define OMAP24XX_PRCM_CLKEMUL_CTRL OMAP2430_PRCM_CLKEMUL_CTRL +#endif + static unsigned long omap2_table_mpu_recalc(struct clk *clk); static int omap2_select_table_rate(struct clk *clk, unsigned long rate); static long omap2_round_to_table_rate(struct clk *clk, unsigned long rate); diff --git a/arch/arm/mach-omap2/clock34xx.c b/arch/arm/mach-omap2/clock34xx.c index ba05aa42bd8e..045da923e75b 100644 --- a/arch/arm/mach-omap2/clock34xx.c +++ b/arch/arm/mach-omap2/clock34xx.c @@ -129,6 +129,9 @@ static struct omap_clk omap34xx_clks[] = { CLK(NULL, "sgx_fck", &sgx_fck, CK_3430ES2), CLK(NULL, "sgx_ick", &sgx_ick, CK_3430ES2), CLK(NULL, "d2d_26m_fck", &d2d_26m_fck, CK_3430ES1), + CLK(NULL, "modem_fck", &modem_fck, CK_343X), + CLK(NULL, "sad2d_ick", &sad2d_ick, CK_343X), + CLK(NULL, "mad2d_ick", &mad2d_ick, CK_343X), CLK(NULL, "gpt10_fck", &gpt10_fck, CK_343X), CLK(NULL, "gpt11_fck", &gpt11_fck, CK_343X), CLK(NULL, "cpefuse_fck", &cpefuse_fck, CK_3430ES2), @@ -281,6 +284,22 @@ static struct omap_clk omap34xx_clks[] = { #define MAX_DPLL_WAIT_TRIES 1000000 +#define MIN_SDRC_DLL_LOCK_FREQ 83000000 + +#define CYCLES_PER_MHZ 1000000 + +/* Scale factor for fixed-point arith in omap3_core_dpll_m2_set_rate() */ +#define SDRC_MPURATE_SCALE 8 + +/* 2^SDRC_MPURATE_BASE_SHIFT: MPU MHz that SDRC_MPURATE_LOOPS is defined for */ +#define SDRC_MPURATE_BASE_SHIFT 9 + +/* + * SDRC_MPURATE_LOOPS: Number of MPU loops to execute at + * 2^MPURATE_BASE_SHIFT MHz for SDRC to stabilize + */ +#define SDRC_MPURATE_LOOPS 96 + /** * omap3_dpll_recalc - recalculate DPLL rate * @clk: DPLL struct clk @@ -703,7 +722,9 @@ static int omap3_dpll4_set_rate(struct clk *clk, unsigned long rate) static int omap3_core_dpll_m2_set_rate(struct clk *clk, unsigned long rate) { u32 new_div = 0; - unsigned long validrate, sdrcrate; + u32 unlock_dll = 0; + u32 c; + unsigned long validrate, sdrcrate, mpurate; struct omap_sdrc_params *sp; if (!clk || !rate) @@ -712,34 +733,44 @@ static int omap3_core_dpll_m2_set_rate(struct clk *clk, unsigned long rate) if (clk != &dpll3_m2_ck) return -EINVAL; - if (rate == clk->rate) - return 0; - validrate = omap2_clksel_round_rate_div(clk, rate, &new_div); if (validrate != rate) return -EINVAL; sdrcrate = sdrc_ick.rate; if (rate > clk->rate) - sdrcrate <<= ((rate / clk->rate) - 1); + sdrcrate <<= ((rate / clk->rate) >> 1); else - sdrcrate >>= ((clk->rate / rate) - 1); + sdrcrate >>= ((clk->rate / rate) >> 1); sp = omap2_sdrc_get_params(sdrcrate); if (!sp) return -EINVAL; - pr_info("clock: changing CORE DPLL rate from %lu to %lu\n", clk->rate, - validrate); - pr_info("clock: SDRC timing params used: %08x %08x %08x\n", - sp->rfr_ctrl, sp->actim_ctrla, sp->actim_ctrlb); + if (sdrcrate < MIN_SDRC_DLL_LOCK_FREQ) { + pr_debug("clock: will unlock SDRC DLL\n"); + unlock_dll = 1; + } - /* REVISIT: SRAM code doesn't support other M2 divisors yet */ - WARN_ON(new_div != 1 && new_div != 2); + /* + * XXX This only needs to be done when the CPU frequency changes + */ + mpurate = arm_fck.rate / CYCLES_PER_MHZ; + c = (mpurate << SDRC_MPURATE_SCALE) >> SDRC_MPURATE_BASE_SHIFT; + c += 1; /* for safety */ + c *= SDRC_MPURATE_LOOPS; + c >>= SDRC_MPURATE_SCALE; + if (c == 0) + c = 1; + + pr_debug("clock: changing CORE DPLL rate from %lu to %lu\n", clk->rate, + validrate); + pr_debug("clock: SDRC timing params used: %08x %08x %08x\n", + sp->rfr_ctrl, sp->actim_ctrla, sp->actim_ctrlb); - /* REVISIT: Add SDRC_MR changing to this code also */ omap3_configure_core_dpll(sp->rfr_ctrl, sp->actim_ctrla, - sp->actim_ctrlb, new_div); + sp->actim_ctrlb, new_div, unlock_dll, c, + sp->mr, rate > clk->rate); return 0; } @@ -956,7 +987,7 @@ int __init omap2_clk_init(void) clk_init(&omap2_clk_functions); for (c = omap34xx_clks; c < omap34xx_clks + ARRAY_SIZE(omap34xx_clks); c++) - clk_init_one(c->lk.clk); + clk_preinit(c->lk.clk); for (c = omap34xx_clks; c < omap34xx_clks + ARRAY_SIZE(omap34xx_clks); c++) if (c->cpu & cpu_clkflg) { diff --git a/arch/arm/mach-omap2/clock34xx.h b/arch/arm/mach-omap2/clock34xx.h index 017a30e9aa1d..e433aec4efdd 100644 --- a/arch/arm/mach-omap2/clock34xx.h +++ b/arch/arm/mach-omap2/clock34xx.h @@ -27,6 +27,8 @@ #include "prm.h" #include "prm-regbits-34xx.h" +#define OMAP_CM_REGADDR OMAP34XX_CM_REGADDR + static unsigned long omap3_dpll_recalc(struct clk *clk); static unsigned long omap3_clkoutx2_recalc(struct clk *clk); static void omap3_dpll_allow_idle(struct clk *clk); @@ -1228,6 +1230,37 @@ static struct clk d2d_26m_fck = { .recalc = &followparent_recalc, }; +static struct clk modem_fck = { + .name = "modem_fck", + .ops = &clkops_omap2_dflt_wait, + .parent = &sys_ck, + .init = &omap2_init_clk_clkdm, + .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), + .enable_bit = OMAP3430_EN_MODEM_SHIFT, + .clkdm_name = "d2d_clkdm", + .recalc = &followparent_recalc, +}; + +static struct clk sad2d_ick = { + .name = "sad2d_ick", + .ops = &clkops_omap2_dflt_wait, + .parent = &l3_ick, + .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1), + .enable_bit = OMAP3430_EN_SAD2D_SHIFT, + .clkdm_name = "d2d_clkdm", + .recalc = &followparent_recalc, +}; + +static struct clk mad2d_ick = { + .name = "mad2d_ick", + .ops = &clkops_omap2_dflt_wait, + .parent = &l3_ick, + .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN3), + .enable_bit = OMAP3430_EN_MAD2D_SHIFT, + .clkdm_name = "d2d_clkdm", + .recalc = &followparent_recalc, +}; + static const struct clksel omap343x_gpt_clksel[] = { { .parent = &omap_32k_fck, .rates = gpt_32k_rates }, { .parent = &sys_ck, .rates = gpt_sys_rates }, @@ -1945,8 +1978,6 @@ static struct clk usb_l4_ick = { .recalc = &omap2_clksel_recalc, }; -/* XXX MDM_INTC_ICK, SAD2D_ICK ?? */ - /* SECURITY_L4_ICK2 based clocks */ static struct clk security_l4_ick2 = { diff --git a/arch/arm/mach-omap2/clockdomains.h b/arch/arm/mach-omap2/clockdomains.h index 281d5da19188..fe319ae4ca0a 100644 --- a/arch/arm/mach-omap2/clockdomains.h +++ b/arch/arm/mach-omap2/clockdomains.h @@ -195,7 +195,7 @@ static struct clockdomain sgx_clkdm = { static struct clockdomain d2d_clkdm = { .name = "d2d_clkdm", .pwrdm = { .name = "core_pwrdm" }, - .flags = CLKDM_CAN_HWSUP, + .flags = CLKDM_CAN_HWSUP_SWSUP, .clktrctrl_mask = OMAP3430ES1_CLKTRCTRL_D2D_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), }; diff --git a/arch/arm/mach-omap2/cm-regbits-34xx.h b/arch/arm/mach-omap2/cm-regbits-34xx.h index 6f3f5a36aae6..6923deb98a28 100644 --- a/arch/arm/mach-omap2/cm-regbits-34xx.h +++ b/arch/arm/mach-omap2/cm-regbits-34xx.h @@ -145,6 +145,8 @@ #define OMAP3430_CLKACTIVITY_MPU_MASK (1 << 0) /* CM_FCLKEN1_CORE specific bits */ +#define OMAP3430_EN_MODEM (1 << 31) +#define OMAP3430_EN_MODEM_SHIFT 31 /* CM_ICLKEN1_CORE specific bits */ #define OMAP3430_EN_ICR (1 << 29) @@ -161,6 +163,8 @@ #define OMAP3430_EN_MAILBOXES_SHIFT 7 #define OMAP3430_EN_OMAPCTRL (1 << 6) #define OMAP3430_EN_OMAPCTRL_SHIFT 6 +#define OMAP3430_EN_SAD2D (1 << 3) +#define OMAP3430_EN_SAD2D_SHIFT 3 #define OMAP3430_EN_SDRC (1 << 1) #define OMAP3430_EN_SDRC_SHIFT 1 @@ -176,6 +180,10 @@ #define OMAP3430_EN_DES1 (1 << 0) #define OMAP3430_EN_DES1_SHIFT 0 +/* CM_ICLKEN3_CORE */ +#define OMAP3430_EN_MAD2D_SHIFT 3 +#define OMAP3430_EN_MAD2D (1 << 3) + /* CM_FCLKEN3_CORE specific bits */ #define OMAP3430ES2_EN_TS_SHIFT 1 #define OMAP3430ES2_EN_TS_MASK (1 << 1) @@ -231,6 +239,8 @@ #define OMAP3430ES2_ST_CPEFUSE_MASK (1 << 0) /* CM_AUTOIDLE1_CORE */ +#define OMAP3430_AUTO_MODEM (1 << 31) +#define OMAP3430_AUTO_MODEM_SHIFT 31 #define OMAP3430ES2_AUTO_MMC3 (1 << 30) #define OMAP3430ES2_AUTO_MMC3_SHIFT 30 #define OMAP3430ES2_AUTO_ICR (1 << 29) @@ -287,6 +297,8 @@ #define OMAP3430_AUTO_HSOTGUSB_SHIFT 4 #define OMAP3430ES1_AUTO_D2D (1 << 3) #define OMAP3430ES1_AUTO_D2D_SHIFT 3 +#define OMAP3430_AUTO_SAD2D (1 << 3) +#define OMAP3430_AUTO_SAD2D_SHIFT 3 #define OMAP3430_AUTO_SSI (1 << 0) #define OMAP3430_AUTO_SSI_SHIFT 0 @@ -308,6 +320,8 @@ #define OMAP3430ES2_AUTO_USBTLL (1 << 2) #define OMAP3430ES2_AUTO_USBTLL_SHIFT 2 #define OMAP3430ES2_AUTO_USBTLL_MASK (1 << 2) +#define OMAP3430_AUTO_MAD2D_SHIFT 3 +#define OMAP3430_AUTO_MAD2D (1 << 3) /* CM_CLKSEL_CORE */ #define OMAP3430_CLKSEL_SSI_SHIFT 8 diff --git a/arch/arm/mach-omap2/cm.h b/arch/arm/mach-omap2/cm.h index 65fdf78c91e1..1d3c93bf86d3 100644 --- a/arch/arm/mach-omap2/cm.h +++ b/arch/arm/mach-omap2/cm.h @@ -16,17 +16,12 @@ #include "prcm-common.h" -#ifndef __ASSEMBLER__ -#define OMAP_CM_REGADDR(module, reg) \ - IO_ADDRESS(OMAP2_CM_BASE + (module) + (reg)) -#else #define OMAP2420_CM_REGADDR(module, reg) \ IO_ADDRESS(OMAP2420_CM_BASE + (module) + (reg)) #define OMAP2430_CM_REGADDR(module, reg) \ IO_ADDRESS(OMAP2430_CM_BASE + (module) + (reg)) #define OMAP34XX_CM_REGADDR(module, reg) \ IO_ADDRESS(OMAP3430_CM_BASE + (module) + (reg)) -#endif /* * Architecture-specific global CM registers @@ -38,6 +33,7 @@ #define OMAP3430_CM_SYSCONFIG OMAP_CM_REGADDR(OCP_MOD, 0x0010) #define OMAP3430_CM_POLCTRL OMAP_CM_REGADDR(OCP_MOD, 0x009c) +#define OMAP3_CM_CLKOUT_CTRL_OFFSET 0x0070 #define OMAP3430_CM_CLKOUT_CTRL OMAP_CM_REGADDR(OMAP3430_CCR_MOD, 0x0070) /* diff --git a/arch/arm/mach-omap2/gpmc-onenand.c b/arch/arm/mach-omap2/gpmc-onenand.c new file mode 100644 index 000000000000..2fd22f9c5f0e --- /dev/null +++ b/arch/arm/mach-omap2/gpmc-onenand.c @@ -0,0 +1,330 @@ +/* + * linux/arch/arm/mach-omap2/gpmc-onenand.c + * + * Copyright (C) 2006 - 2009 Nokia Corporation + * Contacts: Juha Yrjola + * Tony Lindgren + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include + +#include + +#include +#include +#include + +static struct omap_onenand_platform_data *gpmc_onenand_data; + +static struct platform_device gpmc_onenand_device = { + .name = "omap2-onenand", + .id = -1, +}; + +static int omap2_onenand_set_async_mode(int cs, void __iomem *onenand_base) +{ + struct gpmc_timings t; + + const int t_cer = 15; + const int t_avdp = 12; + const int t_aavdh = 7; + const int t_ce = 76; + const int t_aa = 76; + const int t_oe = 20; + const int t_cez = 20; /* max of t_cez, t_oez */ + const int t_ds = 30; + const int t_wpl = 40; + const int t_wph = 30; + + memset(&t, 0, sizeof(t)); + t.sync_clk = 0; + t.cs_on = 0; + t.adv_on = 0; + + /* Read */ + t.adv_rd_off = gpmc_round_ns_to_ticks(max_t(int, t_avdp, t_cer)); + t.oe_on = t.adv_rd_off + gpmc_round_ns_to_ticks(t_aavdh); + t.access = t.adv_on + gpmc_round_ns_to_ticks(t_aa); + t.access = max_t(int, t.access, t.cs_on + gpmc_round_ns_to_ticks(t_ce)); + t.access = max_t(int, t.access, t.oe_on + gpmc_round_ns_to_ticks(t_oe)); + t.oe_off = t.access + gpmc_round_ns_to_ticks(1); + t.cs_rd_off = t.oe_off; + t.rd_cycle = t.cs_rd_off + gpmc_round_ns_to_ticks(t_cez); + + /* Write */ + t.adv_wr_off = t.adv_rd_off; + t.we_on = t.oe_on; + if (cpu_is_omap34xx()) { + t.wr_data_mux_bus = t.we_on; + t.wr_access = t.we_on + gpmc_round_ns_to_ticks(t_ds); + } + t.we_off = t.we_on + gpmc_round_ns_to_ticks(t_wpl); + t.cs_wr_off = t.we_off + gpmc_round_ns_to_ticks(t_wph); + t.wr_cycle = t.cs_wr_off + gpmc_round_ns_to_ticks(t_cez); + + /* Configure GPMC for asynchronous read */ + gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, + GPMC_CONFIG1_DEVICESIZE_16 | + GPMC_CONFIG1_MUXADDDATA); + + return gpmc_cs_set_timings(cs, &t); +} + +static void set_onenand_cfg(void __iomem *onenand_base, int latency, + int sync_read, int sync_write, int hf) +{ + u32 reg; + + reg = readw(onenand_base + ONENAND_REG_SYS_CFG1); + reg &= ~((0x7 << ONENAND_SYS_CFG1_BRL_SHIFT) | (0x7 << 9)); + reg |= (latency << ONENAND_SYS_CFG1_BRL_SHIFT) | + ONENAND_SYS_CFG1_BL_16; + if (sync_read) + reg |= ONENAND_SYS_CFG1_SYNC_READ; + else + reg &= ~ONENAND_SYS_CFG1_SYNC_READ; + if (sync_write) + reg |= ONENAND_SYS_CFG1_SYNC_WRITE; + else + reg &= ~ONENAND_SYS_CFG1_SYNC_WRITE; + if (hf) + reg |= ONENAND_SYS_CFG1_HF; + else + reg &= ~ONENAND_SYS_CFG1_HF; + writew(reg, onenand_base + ONENAND_REG_SYS_CFG1); +} + +static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg, + void __iomem *onenand_base, + int freq) +{ + struct gpmc_timings t; + const int t_cer = 15; + const int t_avdp = 12; + const int t_cez = 20; /* max of t_cez, t_oez */ + const int t_ds = 30; + const int t_wpl = 40; + const int t_wph = 30; + int min_gpmc_clk_period, t_ces, t_avds, t_avdh, t_ach, t_aavdh, t_rdyo; + int tick_ns, div, fclk_offset_ns, fclk_offset, gpmc_clk_ns, latency; + int first_time = 0, hf = 0, sync_read = 0, sync_write = 0; + int err, ticks_cez; + int cs = cfg->cs; + u32 reg; + + if (cfg->flags & ONENAND_SYNC_READ) { + sync_read = 1; + } else if (cfg->flags & ONENAND_SYNC_READWRITE) { + sync_read = 1; + sync_write = 1; + } + + if (!freq) { + /* Very first call freq is not known */ + err = omap2_onenand_set_async_mode(cs, onenand_base); + if (err) + return err; + reg = readw(onenand_base + ONENAND_REG_VERSION_ID); + switch ((reg >> 4) & 0xf) { + case 0: + freq = 40; + break; + case 1: + freq = 54; + break; + case 2: + freq = 66; + break; + case 3: + freq = 83; + break; + case 4: + freq = 104; + break; + default: + freq = 54; + break; + } + first_time = 1; + } + + switch (freq) { + case 83: + min_gpmc_clk_period = 12; /* 83 MHz */ + t_ces = 5; + t_avds = 4; + t_avdh = 2; + t_ach = 6; + t_aavdh = 6; + t_rdyo = 9; + break; + case 66: + min_gpmc_clk_period = 15; /* 66 MHz */ + t_ces = 6; + t_avds = 5; + t_avdh = 2; + t_ach = 6; + t_aavdh = 6; + t_rdyo = 11; + break; + default: + min_gpmc_clk_period = 18; /* 54 MHz */ + t_ces = 7; + t_avds = 7; + t_avdh = 7; + t_ach = 9; + t_aavdh = 7; + t_rdyo = 15; + sync_write = 0; + break; + } + + tick_ns = gpmc_ticks_to_ns(1); + div = gpmc_cs_calc_divider(cs, min_gpmc_clk_period); + gpmc_clk_ns = gpmc_ticks_to_ns(div); + if (gpmc_clk_ns < 15) /* >66Mhz */ + hf = 1; + if (hf) + latency = 6; + else if (gpmc_clk_ns >= 25) /* 40 MHz*/ + latency = 3; + else + latency = 4; + + if (first_time) + set_onenand_cfg(onenand_base, latency, + sync_read, sync_write, hf); + + if (div == 1) { + reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG2); + reg |= (1 << 7); + gpmc_cs_write_reg(cs, GPMC_CS_CONFIG2, reg); + reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG3); + reg |= (1 << 7); + gpmc_cs_write_reg(cs, GPMC_CS_CONFIG3, reg); + reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG4); + reg |= (1 << 7); + reg |= (1 << 23); + gpmc_cs_write_reg(cs, GPMC_CS_CONFIG4, reg); + } else { + reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG2); + reg &= ~(1 << 7); + gpmc_cs_write_reg(cs, GPMC_CS_CONFIG2, reg); + reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG3); + reg &= ~(1 << 7); + gpmc_cs_write_reg(cs, GPMC_CS_CONFIG3, reg); + reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG4); + reg &= ~(1 << 7); + reg &= ~(1 << 23); + gpmc_cs_write_reg(cs, GPMC_CS_CONFIG4, reg); + } + + /* Set synchronous read timings */ + memset(&t, 0, sizeof(t)); + t.sync_clk = min_gpmc_clk_period; + t.cs_on = 0; + t.adv_on = 0; + fclk_offset_ns = gpmc_round_ns_to_ticks(max_t(int, t_ces, t_avds)); + fclk_offset = gpmc_ns_to_ticks(fclk_offset_ns); + t.page_burst_access = gpmc_clk_ns; + + /* Read */ + t.adv_rd_off = gpmc_ticks_to_ns(fclk_offset + gpmc_ns_to_ticks(t_avdh)); + t.oe_on = gpmc_ticks_to_ns(fclk_offset + gpmc_ns_to_ticks(t_ach)); + t.access = gpmc_ticks_to_ns(fclk_offset + (latency + 1) * div); + t.oe_off = t.access + gpmc_round_ns_to_ticks(1); + t.cs_rd_off = t.oe_off; + ticks_cez = ((gpmc_ns_to_ticks(t_cez) + div - 1) / div) * div; + t.rd_cycle = gpmc_ticks_to_ns(fclk_offset + (latency + 1) * div + + ticks_cez); + + /* Write */ + if (sync_write) { + t.adv_wr_off = t.adv_rd_off; + t.we_on = 0; + t.we_off = t.cs_rd_off; + t.cs_wr_off = t.cs_rd_off; + t.wr_cycle = t.rd_cycle; + if (cpu_is_omap34xx()) { + t.wr_data_mux_bus = gpmc_ticks_to_ns(fclk_offset + + gpmc_ns_to_ticks(min_gpmc_clk_period + + t_rdyo)); + t.wr_access = t.access; + } + } else { + t.adv_wr_off = gpmc_round_ns_to_ticks(max_t(int, + t_avdp, t_cer)); + t.we_on = t.adv_wr_off + gpmc_round_ns_to_ticks(t_aavdh); + t.we_off = t.we_on + gpmc_round_ns_to_ticks(t_wpl); + t.cs_wr_off = t.we_off + gpmc_round_ns_to_ticks(t_wph); + t.wr_cycle = t.cs_wr_off + gpmc_round_ns_to_ticks(t_cez); + if (cpu_is_omap34xx()) { + t.wr_data_mux_bus = t.we_on; + t.wr_access = t.we_on + gpmc_round_ns_to_ticks(t_ds); + } + } + + /* Configure GPMC for synchronous read */ + gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, + GPMC_CONFIG1_WRAPBURST_SUPP | + GPMC_CONFIG1_READMULTIPLE_SUPP | + (sync_read ? GPMC_CONFIG1_READTYPE_SYNC : 0) | + (sync_write ? GPMC_CONFIG1_WRITEMULTIPLE_SUPP : 0) | + (sync_write ? GPMC_CONFIG1_WRITETYPE_SYNC : 0) | + GPMC_CONFIG1_CLKACTIVATIONTIME(fclk_offset) | + GPMC_CONFIG1_PAGE_LEN(2) | + (cpu_is_omap34xx() ? 0 : + (GPMC_CONFIG1_WAIT_READ_MON | + GPMC_CONFIG1_WAIT_PIN_SEL(0))) | + GPMC_CONFIG1_DEVICESIZE_16 | + GPMC_CONFIG1_DEVICETYPE_NOR | + GPMC_CONFIG1_MUXADDDATA); + + err = gpmc_cs_set_timings(cs, &t); + if (err) + return err; + + set_onenand_cfg(onenand_base, latency, sync_read, sync_write, hf); + + return 0; +} + +static int gpmc_onenand_setup(void __iomem *onenand_base, int freq) +{ + struct device *dev = &gpmc_onenand_device.dev; + + /* Set sync timings in GPMC */ + if (omap2_onenand_set_sync_mode(gpmc_onenand_data, onenand_base, + freq) < 0) { + dev_err(dev, "Unable to set synchronous mode\n"); + return -EINVAL; + } + + return 0; +} + +void __init gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data) +{ + gpmc_onenand_data = _onenand_data; + gpmc_onenand_data->onenand_setup = gpmc_onenand_setup; + gpmc_onenand_device.dev.platform_data = gpmc_onenand_data; + + if (cpu_is_omap24xx() && + (gpmc_onenand_data->flags & ONENAND_SYNC_READWRITE)) { + printk(KERN_ERR "Onenand using only SYNC_READ on 24xx\n"); + gpmc_onenand_data->flags &= ~ONENAND_SYNC_READWRITE; + gpmc_onenand_data->flags |= ONENAND_SYNC_READ; + } + + if (platform_device_register(&gpmc_onenand_device) < 0) { + printk(KERN_ERR "Unable to register OneNAND device\n"); + return; + } +} diff --git a/arch/arm/mach-omap2/gpmc-smc91x.c b/arch/arm/mach-omap2/gpmc-smc91x.c new file mode 100644 index 000000000000..df99d31d8b64 --- /dev/null +++ b/arch/arm/mach-omap2/gpmc-smc91x.c @@ -0,0 +1,189 @@ +/* + * linux/arch/arm/mach-omap2/gpmc-smc91x.c + * + * Copyright (C) 2009 Nokia Corporation + * Contact: Tony Lindgren + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +static struct omap_smc91x_platform_data *gpmc_cfg; + +static struct resource gpmc_smc91x_resources[] = { + [0] = { + .flags = IORESOURCE_MEM, + }, + [1] = { + .flags = IORESOURCE_IRQ, + }, +}; + +static struct smc91x_platdata gpmc_smc91x_info = { + .flags = SMC91X_USE_16BIT | SMC91X_NOWAIT | SMC91X_IO_SHIFT_0, +}; + +static struct platform_device gpmc_smc91x_device = { + .name = "smc91x", + .id = -1, + .num_resources = ARRAY_SIZE(gpmc_smc91x_resources), + .resource = gpmc_smc91x_resources, + .dev = { + .platform_data = &gpmc_smc91x_info, + }, +}; + +/* + * Set the gpmc timings for smc91c96. The timings are taken + * from the data sheet available at: + * http://www.smsc.com/main/catalog/lan91c96.html + * REVISIT: Level shifters can add at least to the access latency. + */ +static int smc91c96_gpmc_retime(void) +{ + struct gpmc_timings t; + const int t3 = 10; /* Figure 12.2 read and 12.4 write */ + const int t4_r = 20; /* Figure 12.2 read */ + const int t4_w = 5; /* Figure 12.4 write */ + const int t5 = 25; /* Figure 12.2 read */ + const int t6 = 15; /* Figure 12.2 read */ + const int t7 = 5; /* Figure 12.4 write */ + const int t8 = 5; /* Figure 12.4 write */ + const int t20 = 185; /* Figure 12.2 read and 12.4 write */ + u32 l; + + memset(&t, 0, sizeof(t)); + + /* Read timings */ + t.cs_on = 0; + t.adv_on = t.cs_on; + t.oe_on = t.adv_on + t3; + t.access = t.oe_on + t5; + t.oe_off = t.access; + t.adv_rd_off = t.oe_off + max(t4_r, t6); + t.cs_rd_off = t.oe_off; + t.rd_cycle = t20 - t.oe_on; + + /* Write timings */ + t.we_on = t.adv_on + t3; + + if (cpu_is_omap34xx() && (gpmc_cfg->flags & GPMC_MUX_ADD_DATA)) { + t.wr_data_mux_bus = t.we_on; + t.we_off = t.wr_data_mux_bus + t7; + } else + t.we_off = t.we_on + t7; + if (cpu_is_omap34xx()) + t.wr_access = t.we_off; + t.adv_wr_off = t.we_off + max(t4_w, t8); + t.cs_wr_off = t.we_off + t4_w; + t.wr_cycle = t20 - t.we_on; + + l = GPMC_CONFIG1_DEVICESIZE_16; + if (gpmc_cfg->flags & GPMC_MUX_ADD_DATA) + l |= GPMC_CONFIG1_MUXADDDATA; + if (gpmc_cfg->flags & GPMC_READ_MON) + l |= GPMC_CONFIG1_WAIT_READ_MON; + if (gpmc_cfg->flags & GPMC_WRITE_MON) + l |= GPMC_CONFIG1_WAIT_WRITE_MON; + if (gpmc_cfg->wait_pin) + l |= GPMC_CONFIG1_WAIT_PIN_SEL(gpmc_cfg->wait_pin); + gpmc_cs_write_reg(gpmc_cfg->cs, GPMC_CS_CONFIG1, l); + + /* + * FIXME: Calculate the address and data bus muxed timings. + * Note that at least adv_rd_off needs to be changed according + * to omap3430 TRM Figure 11-11. Are the sdp boards using the + * FPGA in between smc91x and omap as the timings are different + * from above? + */ + if (gpmc_cfg->flags & GPMC_MUX_ADD_DATA) + return 0; + + return gpmc_cs_set_timings(gpmc_cfg->cs, &t); +} + +/* + * Initialize smc91x device connected to the GPMC. Note that we + * assume that pin multiplexing is done in the board-*.c file, + * or in the bootloader. + */ +void __init gpmc_smc91x_init(struct omap_smc91x_platform_data *board_data) +{ + unsigned long cs_mem_base; + int ret; + + gpmc_cfg = board_data; + + if (gpmc_cfg->flags & GPMC_TIMINGS_SMC91C96) + gpmc_cfg->retime = smc91c96_gpmc_retime; + + if (gpmc_cs_request(gpmc_cfg->cs, SZ_16M, &cs_mem_base) < 0) { + printk(KERN_ERR "Failed to request GPMC mem for smc91x\n"); + return; + } + + gpmc_smc91x_resources[0].start = cs_mem_base + 0x300; + gpmc_smc91x_resources[0].end = cs_mem_base + 0x30f; + gpmc_smc91x_resources[1].flags |= (gpmc_cfg->flags & IRQF_TRIGGER_MASK); + + if (gpmc_cfg->retime) { + ret = gpmc_cfg->retime(); + if (ret != 0) + goto free1; + } + + if (gpio_request(gpmc_cfg->gpio_irq, "SMC91X irq") < 0) + goto free1; + + gpio_direction_input(gpmc_cfg->gpio_irq); + gpmc_smc91x_resources[1].start = gpio_to_irq(gpmc_cfg->gpio_irq); + + if (gpmc_cfg->gpio_pwrdwn) { + ret = gpio_request(gpmc_cfg->gpio_pwrdwn, "SMC91X powerdown"); + if (ret) + goto free2; + gpio_direction_output(gpmc_cfg->gpio_pwrdwn, 0); + } + + if (gpmc_cfg->gpio_reset) { + ret = gpio_request(gpmc_cfg->gpio_reset, "SMC91X reset"); + if (ret) + goto free3; + + gpio_direction_output(gpmc_cfg->gpio_reset, 0); + gpio_set_value(gpmc_cfg->gpio_reset, 1); + msleep(100); + gpio_set_value(gpmc_cfg->gpio_reset, 0); + } + + if (platform_device_register(&gpmc_smc91x_device) < 0) { + printk(KERN_ERR "Unable to register smc91x device\n"); + gpio_free(gpmc_cfg->gpio_reset); + goto free3; + } + + return; + +free3: + if (gpmc_cfg->gpio_pwrdwn) + gpio_free(gpmc_cfg->gpio_pwrdwn); +free2: + gpio_free(gpmc_cfg->gpio_irq); +free1: + gpmc_cs_free(gpmc_cfg->cs); + + printk(KERN_ERR "Could not initialize smc91x\n"); +} diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index 2249049c1d5a..f91934b2b092 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -5,6 +5,9 @@ * * Author: Juha Yrjola * + * Copyright (C) 2009 Texas Instruments + * Added OMAP4 support - Santosh Shilimkar + * * 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. @@ -424,6 +427,9 @@ void __init gpmc_init(void) } else if (cpu_is_omap34xx()) { ck = "gpmc_fck"; l = OMAP34XX_GPMC_BASE; + } else if (cpu_is_omap44xx()) { + ck = "gpmc_fck"; + l = OMAP44XX_GPMC_BASE; } gpmc_l3_clk = clk_get(NULL, ck); diff --git a/arch/arm/mach-omap2/id.c b/arch/arm/mach-omap2/id.c index 34b5914e0f8b..458990e20c60 100644 --- a/arch/arm/mach-omap2/id.c +++ b/arch/arm/mach-omap2/id.c @@ -6,6 +6,9 @@ * Copyright (C) 2005 Nokia Corporation * Written by Tony Lindgren * + * Copyright (C) 2009 Texas Instruments + * Added OMAP4 support - Santosh Shilimkar + * * 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. @@ -200,7 +203,10 @@ void __init omap2_check_revision(void) omap24xx_check_revision(); else if (cpu_is_omap34xx()) omap34xx_check_revision(); - else + else if (cpu_is_omap44xx()) { + printk(KERN_INFO "FIXME: CPU revision = OMAP4430\n"); + return; + } else pr_err("OMAP revision unknown, please fix!\n"); /* diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c index 916fcd3a2328..3a86b0f66031 100644 --- a/arch/arm/mach-omap2/io.c +++ b/arch/arm/mach-omap2/io.c @@ -4,12 +4,14 @@ * OMAP2 I/O mapping code * * Copyright (C) 2005 Nokia Corporation - * Copyright (C) 2007 Texas Instruments + * Copyright (C) 2007-2009 Texas Instruments * * Author: * Juha Yrjola * Syed Khasim * + * Added OMAP4 support - Santosh Shilimkar + * * 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. @@ -19,6 +21,7 @@ #include #include #include +#include #include @@ -30,6 +33,7 @@ #include #include +#ifndef CONFIG_ARCH_OMAP4 /* FIXME: Remove this once clkdev is ready */ #include "clock.h" #include @@ -38,7 +42,7 @@ #include #include "clockdomains.h" - +#endif /* * The machine specific code may provide the extra mapping besides the * default mapping provided here. @@ -166,6 +170,46 @@ static struct map_desc omap34xx_io_desc[] __initdata = { }, }; #endif +#ifdef CONFIG_ARCH_OMAP4 +static struct map_desc omap44xx_io_desc[] __initdata = { + { + .virtual = L3_44XX_VIRT, + .pfn = __phys_to_pfn(L3_44XX_PHYS), + .length = L3_44XX_SIZE, + .type = MT_DEVICE, + }, + { + .virtual = L4_44XX_VIRT, + .pfn = __phys_to_pfn(L4_44XX_PHYS), + .length = L4_44XX_SIZE, + .type = MT_DEVICE, + }, + { + .virtual = L4_WK_44XX_VIRT, + .pfn = __phys_to_pfn(L4_WK_44XX_PHYS), + .length = L4_WK_44XX_SIZE, + .type = MT_DEVICE, + }, + { + .virtual = OMAP44XX_GPMC_VIRT, + .pfn = __phys_to_pfn(OMAP44XX_GPMC_PHYS), + .length = OMAP44XX_GPMC_SIZE, + .type = MT_DEVICE, + }, + { + .virtual = L4_PER_44XX_VIRT, + .pfn = __phys_to_pfn(L4_PER_44XX_PHYS), + .length = L4_PER_44XX_SIZE, + .type = MT_DEVICE, + }, + { + .virtual = L4_EMU_44XX_VIRT, + .pfn = __phys_to_pfn(L4_EMU_44XX_PHYS), + .length = L4_EMU_44XX_SIZE, + .type = MT_DEVICE, + }, +}; +#endif void __init omap2_map_common_io(void) { @@ -183,6 +227,9 @@ void __init omap2_map_common_io(void) iotable_init(omap34xx_io_desc, ARRAY_SIZE(omap34xx_io_desc)); #endif +#if defined(CONFIG_ARCH_OMAP4) + iotable_init(omap44xx_io_desc, ARRAY_SIZE(omap44xx_io_desc)); +#endif /* Normally devicemaps_init() would flush caches and tlb after * mdesc->map_io(), but we must also do it here because of the CPU * revision check below. @@ -195,12 +242,49 @@ void __init omap2_map_common_io(void) omapfb_reserve_sdram(); } +/* + * omap2_init_reprogram_sdrc - reprogram SDRC timing parameters + * + * Sets the CORE DPLL3 M2 divider to the same value that it's at + * currently. This has the effect of setting the SDRC SDRAM AC timing + * registers to the values currently defined by the kernel. Currently + * only defined for OMAP3; will return 0 if called on OMAP2. Returns + * -EINVAL if the dpll3_m2_ck cannot be found, 0 if called on OMAP2, + * or passes along the return value of clk_set_rate(). + */ +static int __init _omap2_init_reprogram_sdrc(void) +{ + struct clk *dpll3_m2_ck; + int v = -EINVAL; + long rate; + + if (!cpu_is_omap34xx()) + return 0; + + dpll3_m2_ck = clk_get(NULL, "dpll3_m2_ck"); + if (!dpll3_m2_ck) + return -EINVAL; + + rate = clk_get_rate(dpll3_m2_ck); + pr_info("Reprogramming SDRC clock to %ld Hz\n", rate); + v = clk_set_rate(dpll3_m2_ck, rate); + if (v) + pr_err("dpll3_m2_clk rate change failed: %d\n", v); + + clk_put(dpll3_m2_ck); + + return v; +} + void __init omap2_init_common_hw(struct omap_sdrc_params *sp) { omap2_mux_init(); +#ifndef CONFIG_ARCH_OMAP4 /* FIXME: Remove this once the clkdev is ready */ pwrdm_init(powerdomains_omap); clkdm_init(clockdomains_omap, clkdm_pwrdm_autodeps); omap2_clk_init(); omap2_sdrc_init(sp); + _omap2_init_reprogram_sdrc(); +#endif gpmc_init(); } diff --git a/arch/arm/mach-omap2/iommu2.c b/arch/arm/mach-omap2/iommu2.c new file mode 100644 index 000000000000..015f22a53ead --- /dev/null +++ b/arch/arm/mach-omap2/iommu2.c @@ -0,0 +1,323 @@ +/* + * omap iommu: omap2/3 architecture specific functions + * + * Copyright (C) 2008-2009 Nokia Corporation + * + * Written by Hiroshi DOYU , + * Paul Mundt and Toshihiro Kobayashi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include + +#include + +/* + * omap2 architecture specific register bit definitions + */ +#define IOMMU_ARCH_VERSION 0x00000011 + +/* SYSCONF */ +#define MMU_SYS_IDLE_SHIFT 3 +#define MMU_SYS_IDLE_FORCE (0 << MMU_SYS_IDLE_SHIFT) +#define MMU_SYS_IDLE_NONE (1 << MMU_SYS_IDLE_SHIFT) +#define MMU_SYS_IDLE_SMART (2 << MMU_SYS_IDLE_SHIFT) +#define MMU_SYS_IDLE_MASK (3 << MMU_SYS_IDLE_SHIFT) + +#define MMU_SYS_SOFTRESET (1 << 1) +#define MMU_SYS_AUTOIDLE 1 + +/* SYSSTATUS */ +#define MMU_SYS_RESETDONE 1 + +/* IRQSTATUS & IRQENABLE */ +#define MMU_IRQ_MULTIHITFAULT (1 << 4) +#define MMU_IRQ_TABLEWALKFAULT (1 << 3) +#define MMU_IRQ_EMUMISS (1 << 2) +#define MMU_IRQ_TRANSLATIONFAULT (1 << 1) +#define MMU_IRQ_TLBMISS (1 << 0) +#define MMU_IRQ_MASK \ + (MMU_IRQ_MULTIHITFAULT | MMU_IRQ_TABLEWALKFAULT | MMU_IRQ_EMUMISS | \ + MMU_IRQ_TRANSLATIONFAULT) + +/* MMU_CNTL */ +#define MMU_CNTL_SHIFT 1 +#define MMU_CNTL_MASK (7 << MMU_CNTL_SHIFT) +#define MMU_CNTL_EML_TLB (1 << 3) +#define MMU_CNTL_TWL_EN (1 << 2) +#define MMU_CNTL_MMU_EN (1 << 1) + +#define get_cam_va_mask(pgsz) \ + (((pgsz) == MMU_CAM_PGSZ_16M) ? 0xff000000 : \ + ((pgsz) == MMU_CAM_PGSZ_1M) ? 0xfff00000 : \ + ((pgsz) == MMU_CAM_PGSZ_64K) ? 0xffff0000 : \ + ((pgsz) == MMU_CAM_PGSZ_4K) ? 0xfffff000 : 0) + +static int omap2_iommu_enable(struct iommu *obj) +{ + u32 l, pa; + unsigned long timeout; + + if (!obj->iopgd || !IS_ALIGNED((u32)obj->iopgd, SZ_16K)) + return -EINVAL; + + pa = virt_to_phys(obj->iopgd); + if (!IS_ALIGNED(pa, SZ_16K)) + return -EINVAL; + + iommu_write_reg(obj, MMU_SYS_SOFTRESET, MMU_SYSCONFIG); + + timeout = jiffies + msecs_to_jiffies(20); + do { + l = iommu_read_reg(obj, MMU_SYSSTATUS); + if (l & MMU_SYS_RESETDONE) + break; + } while (time_after(jiffies, timeout)); + + if (!(l & MMU_SYS_RESETDONE)) { + dev_err(obj->dev, "can't take mmu out of reset\n"); + return -ENODEV; + } + + l = iommu_read_reg(obj, MMU_REVISION); + dev_info(obj->dev, "%s: version %d.%d\n", obj->name, + (l >> 4) & 0xf, l & 0xf); + + l = iommu_read_reg(obj, MMU_SYSCONFIG); + l &= ~MMU_SYS_IDLE_MASK; + l |= (MMU_SYS_IDLE_SMART | MMU_SYS_AUTOIDLE); + iommu_write_reg(obj, l, MMU_SYSCONFIG); + + iommu_write_reg(obj, MMU_IRQ_MASK, MMU_IRQENABLE); + iommu_write_reg(obj, pa, MMU_TTB); + + l = iommu_read_reg(obj, MMU_CNTL); + l &= ~MMU_CNTL_MASK; + l |= (MMU_CNTL_MMU_EN | MMU_CNTL_TWL_EN); + iommu_write_reg(obj, l, MMU_CNTL); + + return 0; +} + +static void omap2_iommu_disable(struct iommu *obj) +{ + u32 l = iommu_read_reg(obj, MMU_CNTL); + + l &= ~MMU_CNTL_MASK; + iommu_write_reg(obj, l, MMU_CNTL); + iommu_write_reg(obj, MMU_SYS_IDLE_FORCE, MMU_SYSCONFIG); + + dev_dbg(obj->dev, "%s is shutting down\n", obj->name); +} + +static u32 omap2_iommu_fault_isr(struct iommu *obj, u32 *ra) +{ + int i; + u32 stat, da; + const char *err_msg[] = { + "tlb miss", + "translation fault", + "emulation miss", + "table walk fault", + "multi hit fault", + }; + + stat = iommu_read_reg(obj, MMU_IRQSTATUS); + stat &= MMU_IRQ_MASK; + if (!stat) + return 0; + + da = iommu_read_reg(obj, MMU_FAULT_AD); + *ra = da; + + dev_err(obj->dev, "%s:\tda:%08x ", __func__, da); + + for (i = 0; i < ARRAY_SIZE(err_msg); i++) { + if (stat & (1 << i)) + printk("%s ", err_msg[i]); + } + printk("\n"); + + iommu_write_reg(obj, stat, MMU_IRQSTATUS); + return stat; +} + +static void omap2_tlb_read_cr(struct iommu *obj, struct cr_regs *cr) +{ + cr->cam = iommu_read_reg(obj, MMU_READ_CAM); + cr->ram = iommu_read_reg(obj, MMU_READ_RAM); +} + +static void omap2_tlb_load_cr(struct iommu *obj, struct cr_regs *cr) +{ + iommu_write_reg(obj, cr->cam | MMU_CAM_V, MMU_CAM); + iommu_write_reg(obj, cr->ram, MMU_RAM); +} + +static u32 omap2_cr_to_virt(struct cr_regs *cr) +{ + u32 page_size = cr->cam & MMU_CAM_PGSZ_MASK; + u32 mask = get_cam_va_mask(cr->cam & page_size); + + return cr->cam & mask; +} + +static struct cr_regs *omap2_alloc_cr(struct iommu *obj, struct iotlb_entry *e) +{ + struct cr_regs *cr; + + if (e->da & ~(get_cam_va_mask(e->pgsz))) { + dev_err(obj->dev, "%s:\twrong alignment: %08x\n", __func__, + e->da); + return ERR_PTR(-EINVAL); + } + + cr = kmalloc(sizeof(*cr), GFP_KERNEL); + if (!cr) + return ERR_PTR(-ENOMEM); + + cr->cam = (e->da & MMU_CAM_VATAG_MASK) | e->prsvd | e->pgsz; + cr->ram = e->pa | e->endian | e->elsz | e->mixed; + + return cr; +} + +static inline int omap2_cr_valid(struct cr_regs *cr) +{ + return cr->cam & MMU_CAM_V; +} + +static u32 omap2_get_pte_attr(struct iotlb_entry *e) +{ + u32 attr; + + attr = e->mixed << 5; + attr |= e->endian; + attr |= e->elsz >> 3; + attr <<= ((e->pgsz & MMU_CAM_PGSZ_4K) ? 0 : 6); + + return attr; +} + +static ssize_t omap2_dump_cr(struct iommu *obj, struct cr_regs *cr, char *buf) +{ + char *p = buf; + + /* FIXME: Need more detail analysis of cam/ram */ + p += sprintf(p, "%08x %08x\n", cr->cam, cr->ram); + + return p - buf; +} + +#define pr_reg(name) \ + p += sprintf(p, "%20s: %08x\n", \ + __stringify(name), iommu_read_reg(obj, MMU_##name)); + +static ssize_t omap2_iommu_dump_ctx(struct iommu *obj, char *buf) +{ + char *p = buf; + + pr_reg(REVISION); + pr_reg(SYSCONFIG); + pr_reg(SYSSTATUS); + pr_reg(IRQSTATUS); + pr_reg(IRQENABLE); + pr_reg(WALKING_ST); + pr_reg(CNTL); + pr_reg(FAULT_AD); + pr_reg(TTB); + pr_reg(LOCK); + pr_reg(LD_TLB); + pr_reg(CAM); + pr_reg(RAM); + pr_reg(GFLUSH); + pr_reg(FLUSH_ENTRY); + pr_reg(READ_CAM); + pr_reg(READ_RAM); + pr_reg(EMU_FAULT_AD); + + return p - buf; +} + +static void omap2_iommu_save_ctx(struct iommu *obj) +{ + int i; + u32 *p = obj->ctx; + + for (i = 0; i < (MMU_REG_SIZE / sizeof(u32)); i++) { + p[i] = iommu_read_reg(obj, i * sizeof(u32)); + dev_dbg(obj->dev, "%s\t[%02d] %08x\n", __func__, i, p[i]); + } + + BUG_ON(p[0] != IOMMU_ARCH_VERSION); +} + +static void omap2_iommu_restore_ctx(struct iommu *obj) +{ + int i; + u32 *p = obj->ctx; + + for (i = 0; i < (MMU_REG_SIZE / sizeof(u32)); i++) { + iommu_write_reg(obj, p[i], i * sizeof(u32)); + dev_dbg(obj->dev, "%s\t[%02d] %08x\n", __func__, i, p[i]); + } + + BUG_ON(p[0] != IOMMU_ARCH_VERSION); +} + +static void omap2_cr_to_e(struct cr_regs *cr, struct iotlb_entry *e) +{ + e->da = cr->cam & MMU_CAM_VATAG_MASK; + e->pa = cr->ram & MMU_RAM_PADDR_MASK; + e->valid = cr->cam & MMU_CAM_V; + e->pgsz = cr->cam & MMU_CAM_PGSZ_MASK; + e->endian = cr->ram & MMU_RAM_ENDIAN_MASK; + e->elsz = cr->ram & MMU_RAM_ELSZ_MASK; + e->mixed = cr->ram & MMU_RAM_MIXED; +} + +static const struct iommu_functions omap2_iommu_ops = { + .version = IOMMU_ARCH_VERSION, + + .enable = omap2_iommu_enable, + .disable = omap2_iommu_disable, + .fault_isr = omap2_iommu_fault_isr, + + .tlb_read_cr = omap2_tlb_read_cr, + .tlb_load_cr = omap2_tlb_load_cr, + + .cr_to_e = omap2_cr_to_e, + .cr_to_virt = omap2_cr_to_virt, + .alloc_cr = omap2_alloc_cr, + .cr_valid = omap2_cr_valid, + .dump_cr = omap2_dump_cr, + + .get_pte_attr = omap2_get_pte_attr, + + .save_ctx = omap2_iommu_save_ctx, + .restore_ctx = omap2_iommu_restore_ctx, + .dump_ctx = omap2_iommu_dump_ctx, +}; + +static int __init omap2_iommu_init(void) +{ + return install_iommu_arch(&omap2_iommu_ops); +} +module_init(omap2_iommu_init); + +static void __exit omap2_iommu_exit(void) +{ + uninstall_iommu_arch(&omap2_iommu_ops); +} +module_exit(omap2_iommu_exit); + +MODULE_AUTHOR("Hiroshi DOYU, Paul Mundt and Toshihiro Kobayashi"); +MODULE_DESCRIPTION("omap iommu: omap2/3 architecture specific functions"); +MODULE_LICENSE("GPL v2"); diff --git a/arch/arm/mach-omap2/irq.c b/arch/arm/mach-omap2/irq.c index 998c5c45587e..b82863887f10 100644 --- a/arch/arm/mach-omap2/irq.c +++ b/arch/arm/mach-omap2/irq.c @@ -28,7 +28,6 @@ #define INTC_MIR_CLEAR0 0x0088 #define INTC_MIR_SET0 0x008c #define INTC_PENDING_IRQ0 0x0098 - /* Number of IRQ state bits in each MIR register */ #define IRQ_BITS_PER_REG 32 @@ -134,7 +133,6 @@ static struct irq_chip omap_irq_chip = { .ack = omap_mask_ack_irq, .mask = omap_mask_irq, .unmask = omap_unmask_irq, - .disable = omap_mask_irq, }; static void __init omap_irq_bank_init_one(struct omap_irq_bank *bank) @@ -157,6 +155,22 @@ static void __init omap_irq_bank_init_one(struct omap_irq_bank *bank) intc_bank_write_reg(1 << 0, bank, INTC_SYSCONFIG); } +int omap_irq_pending(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(irq_banks); i++) { + struct omap_irq_bank *bank = irq_banks + i; + int irq; + + for (irq = 0; irq < bank->nr_irqs; irq += 32) + if (intc_bank_read_reg(bank, INTC_PENDING_IRQ0 + + ((irq >> 5) << 5))) + return 1; + } + return 0; +} + void __init omap_init_irq(void) { unsigned long nr_of_irqs = 0; diff --git a/arch/arm/mach-omap2/mmc-twl4030.c b/arch/arm/mach-omap2/mmc-twl4030.c index dc40b3e72206..9756a878fd90 100644 --- a/arch/arm/mach-omap2/mmc-twl4030.c +++ b/arch/arm/mach-omap2/mmc-twl4030.c @@ -16,8 +16,8 @@ #include #include #include -#include -#include +#include +#include #include #include @@ -26,32 +26,10 @@ #include "mmc-twl4030.h" -#if defined(CONFIG_TWL4030_CORE) && \ + +#if defined(CONFIG_REGULATOR) && \ (defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE)) -#define LDO_CLR 0x00 -#define VSEL_S2_CLR 0x40 - -#define VMMC1_DEV_GRP 0x27 -#define VMMC1_CLR 0x00 -#define VMMC1_315V 0x03 -#define VMMC1_300V 0x02 -#define VMMC1_285V 0x01 -#define VMMC1_185V 0x00 -#define VMMC1_DEDICATED 0x2A - -#define VMMC2_DEV_GRP 0x2B -#define VMMC2_CLR 0x40 -#define VMMC2_315V 0x0c -#define VMMC2_300V 0x0b -#define VMMC2_285V 0x0a -#define VMMC2_280V 0x09 -#define VMMC2_260V 0x08 -#define VMMC2_185V 0x06 -#define VMMC2_DEDICATED 0x2E - -#define VMMC_DEV_GRP_P1 0x20 - static u16 control_pbias_offset; static u16 control_devconf1_offset; @@ -59,19 +37,16 @@ static u16 control_devconf1_offset; static struct twl_mmc_controller { struct omap_mmc_platform_data *mmc; - u8 twl_vmmc_dev_grp; - u8 twl_mmc_dedicated; - char name[HSMMC_NAME_LEN + 1]; -} hsmmc[OMAP34XX_NR_MMC] = { - { - .twl_vmmc_dev_grp = VMMC1_DEV_GRP, - .twl_mmc_dedicated = VMMC1_DEDICATED, - }, - { - .twl_vmmc_dev_grp = VMMC2_DEV_GRP, - .twl_mmc_dedicated = VMMC2_DEDICATED, - }, -}; + /* Vcc == configured supply + * Vcc_alt == optional + * - MMC1, supply for DAT4..DAT7 + * - MMC2/MMC2, external level shifter voltage supply, for + * chip (SDIO, eMMC, etc) or transceiver (MMC2 only) + */ + struct regulator *vcc; + struct regulator *vcc_aux; + char name[HSMMC_NAME_LEN + 1]; +} hsmmc[OMAP34XX_NR_MMC]; static int twl_mmc_card_detect(int irq) { @@ -117,16 +92,60 @@ static int twl_mmc_late_init(struct device *dev) int ret = 0; int i; - ret = gpio_request(mmc->slots[0].switch_pin, "mmc_cd"); - if (ret) - goto done; - ret = gpio_direction_input(mmc->slots[0].switch_pin); - if (ret) - goto err; + /* MMC/SD/SDIO doesn't require a card detect switch */ + if (gpio_is_valid(mmc->slots[0].switch_pin)) { + ret = gpio_request(mmc->slots[0].switch_pin, "mmc_cd"); + if (ret) + goto done; + ret = gpio_direction_input(mmc->slots[0].switch_pin); + if (ret) + goto err; + } + /* require at least main regulator */ for (i = 0; i < ARRAY_SIZE(hsmmc); i++) { if (hsmmc[i].name == mmc->slots[0].name) { + struct regulator *reg; + hsmmc[i].mmc = mmc; + + reg = regulator_get(dev, "vmmc"); + if (IS_ERR(reg)) { + dev_dbg(dev, "vmmc regulator missing\n"); + /* HACK: until fixed.c regulator is usable, + * we don't require a main regulator + * for MMC2 or MMC3 + */ + if (i != 0) + break; + ret = PTR_ERR(reg); + goto err; + } + hsmmc[i].vcc = reg; + mmc->slots[0].ocr_mask = mmc_regulator_get_ocrmask(reg); + + /* allow an aux regulator */ + reg = regulator_get(dev, "vmmc_aux"); + hsmmc[i].vcc_aux = IS_ERR(reg) ? NULL : reg; + + /* UGLY HACK: workaround regulator framework bugs. + * When the bootloader leaves a supply active, it's + * initialized with zero usecount ... and we can't + * disable it without first enabling it. Until the + * framework is fixed, we need a workaround like this + * (which is safe for MMC, but not in general). + */ + if (regulator_is_enabled(hsmmc[i].vcc) > 0) { + regulator_enable(hsmmc[i].vcc); + regulator_disable(hsmmc[i].vcc); + } + if (hsmmc[i].vcc_aux) { + if (regulator_is_enabled(reg) > 0) { + regulator_enable(reg); + regulator_disable(reg); + } + } + break; } } @@ -173,96 +192,6 @@ static int twl_mmc_resume(struct device *dev, int slot) #define twl_mmc_resume NULL #endif -/* - * Sets the MMC voltage in twl4030 - */ - -#define MMC1_OCR (MMC_VDD_165_195 \ - |MMC_VDD_28_29|MMC_VDD_29_30|MMC_VDD_30_31|MMC_VDD_31_32) -#define MMC2_OCR (MMC_VDD_165_195 \ - |MMC_VDD_25_26|MMC_VDD_26_27|MMC_VDD_27_28 \ - |MMC_VDD_28_29|MMC_VDD_29_30|MMC_VDD_30_31|MMC_VDD_31_32) - -static int twl_mmc_set_voltage(struct twl_mmc_controller *c, int vdd) -{ - int ret; - u8 vmmc = 0, dev_grp_val; - - if (!vdd) - goto doit; - - if (c->twl_vmmc_dev_grp == VMMC1_DEV_GRP) { - /* VMMC1: max 220 mA. And for 8-bit mode, - * VSIM: max 50 mA - */ - switch (1 << vdd) { - case MMC_VDD_165_195: - vmmc = VMMC1_185V; - /* and VSIM_180V */ - break; - case MMC_VDD_28_29: - vmmc = VMMC1_285V; - /* and VSIM_280V */ - break; - case MMC_VDD_29_30: - case MMC_VDD_30_31: - vmmc = VMMC1_300V; - /* and VSIM_300V */ - break; - case MMC_VDD_31_32: - vmmc = VMMC1_315V; - /* error if VSIM needed */ - break; - default: - return -EINVAL; - } - } else if (c->twl_vmmc_dev_grp == VMMC2_DEV_GRP) { - /* VMMC2: max 100 mA */ - switch (1 << vdd) { - case MMC_VDD_165_195: - vmmc = VMMC2_185V; - break; - case MMC_VDD_25_26: - case MMC_VDD_26_27: - vmmc = VMMC2_260V; - break; - case MMC_VDD_27_28: - vmmc = VMMC2_280V; - break; - case MMC_VDD_28_29: - vmmc = VMMC2_285V; - break; - case MMC_VDD_29_30: - case MMC_VDD_30_31: - vmmc = VMMC2_300V; - break; - case MMC_VDD_31_32: - vmmc = VMMC2_315V; - break; - default: - return -EINVAL; - } - } else { - return -EINVAL; - } - -doit: - if (vdd) - dev_grp_val = VMMC_DEV_GRP_P1; /* Power up */ - else - dev_grp_val = LDO_CLR; /* Power down */ - - ret = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, - dev_grp_val, c->twl_vmmc_dev_grp); - if (ret || !vdd) - return ret; - - ret = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, - vmmc, c->twl_mmc_dedicated); - - return ret; -} - static int twl_mmc1_set_power(struct device *dev, int slot, int power_on, int vdd) { @@ -273,11 +202,13 @@ static int twl_mmc1_set_power(struct device *dev, int slot, int power_on, /* * Assume we power both OMAP VMMC1 (for CMD, CLK, DAT0..3) and the - * card using the same TWL VMMC1 supply (hsmmc[0]); OMAP has both + * card with Vcc regulator (from twl4030 or whatever). OMAP has both * 1.8V and 3.0V modes, controlled by the PBIAS register. * * In 8-bit modes, OMAP VMMC1A (for DAT4..7) needs a supply, which * is most naturally TWL VSIM; those pins also use PBIAS. + * + * FIXME handle VMMC1A as needed ... */ if (power_on) { if (cpu_is_omap2430()) { @@ -300,7 +231,7 @@ static int twl_mmc1_set_power(struct device *dev, int slot, int power_on, reg &= ~OMAP2_PBIASLITEPWRDNZ0; omap_ctrl_writel(reg, control_pbias_offset); - ret = twl_mmc_set_voltage(c, vdd); + ret = mmc_regulator_set_ocr(c->vcc, vdd); /* 100ms delay required for PBIAS configuration */ msleep(100); @@ -316,7 +247,7 @@ static int twl_mmc1_set_power(struct device *dev, int slot, int power_on, reg &= ~OMAP2_PBIASLITEPWRDNZ0; omap_ctrl_writel(reg, control_pbias_offset); - ret = twl_mmc_set_voltage(c, 0); + ret = mmc_regulator_set_ocr(c->vcc, 0); /* 100ms delay required for PBIAS configuration */ msleep(100); @@ -329,19 +260,33 @@ static int twl_mmc1_set_power(struct device *dev, int slot, int power_on, return ret; } -static int twl_mmc2_set_power(struct device *dev, int slot, int power_on, int vdd) +static int twl_mmc23_set_power(struct device *dev, int slot, int power_on, int vdd) { - int ret; + int ret = 0; struct twl_mmc_controller *c = &hsmmc[1]; struct omap_mmc_platform_data *mmc = dev->platform_data; + /* If we don't see a Vcc regulator, assume it's a fixed + * voltage always-on regulator. + */ + if (!c->vcc) + return 0; + /* - * Assume TWL VMMC2 (hsmmc[1]) is used only to power the card ... OMAP + * Assume Vcc regulator is used only to power the card ... OMAP * VDDS is used to power the pins, optionally with a transceiver to * support cards using voltages other than VDDS (1.8V nominal). When a * transceiver is used, DAT3..7 are muxed as transceiver control pins. + * + * In some cases this regulator won't support enable/disable; + * e.g. it's a fixed rail for a WLAN chip. + * + * In other cases vcc_aux switches interface power. Example, for + * eMMC cards it represents VccQ. Sometimes transceivers or SDIO + * chips/cards need an interface voltage rail too. */ if (power_on) { + /* only MMC2 supports a CLKIN */ if (mmc->slots[0].internal_clock) { u32 reg; @@ -349,24 +294,23 @@ static int twl_mmc2_set_power(struct device *dev, int slot, int power_on, int vd reg |= OMAP2_MMCSDIO2ADPCLKISEL; omap_ctrl_writel(reg, control_devconf1_offset); } - ret = twl_mmc_set_voltage(c, vdd); + ret = mmc_regulator_set_ocr(c->vcc, vdd); + /* enable interface voltage rail, if needed */ + if (ret == 0 && c->vcc_aux) { + ret = regulator_enable(c->vcc_aux); + if (ret < 0) + ret = mmc_regulator_set_ocr(c->vcc, 0); + } } else { - ret = twl_mmc_set_voltage(c, 0); + if (c->vcc_aux && (ret = regulator_is_enabled(c->vcc_aux)) > 0) + ret = regulator_disable(c->vcc_aux); + if (ret == 0) + ret = mmc_regulator_set_ocr(c->vcc, 0); } return ret; } -static int twl_mmc3_set_power(struct device *dev, int slot, int power_on, - int vdd) -{ - /* - * Assume MMC3 has self-powered device connected, for example on-board - * chip with external power source. - */ - return 0; -} - static struct omap_mmc_platform_data *hsmmc_data[OMAP34XX_NR_MMC] __initdata; void __init twl4030_mmc_init(struct twl4030_hsmmc_info *controllers) @@ -412,10 +356,10 @@ void __init twl4030_mmc_init(struct twl4030_hsmmc_info *controllers) mmc->slots[0].wires = c->wires; mmc->slots[0].internal_clock = !c->ext_clock; mmc->dma_mask = 0xffffffff; + mmc->init = twl_mmc_late_init; - /* note: twl4030 card detect GPIOs normally switch VMMCx ... */ + /* note: twl4030 card detect GPIOs can disable VMMCx ... */ if (gpio_is_valid(c->gpio_cd)) { - mmc->init = twl_mmc_late_init; mmc->cleanup = twl_mmc_cleanup; mmc->suspend = twl_mmc_suspend; mmc->resume = twl_mmc_resume; @@ -439,26 +383,28 @@ void __init twl4030_mmc_init(struct twl4030_hsmmc_info *controllers) } else mmc->slots[0].gpio_wp = -EINVAL; - /* NOTE: we assume OMAP's MMC1 and MMC2 use - * the TWL4030's VMMC1 and VMMC2, respectively; - * and that MMC3 device has it's own power source. + /* NOTE: MMC slots should have a Vcc regulator set up. + * This may be from a TWL4030-family chip, another + * controllable regulator, or a fixed supply. + * + * temporary HACK: ocr_mask instead of fixed supply */ + mmc->slots[0].ocr_mask = c->ocr_mask; switch (c->mmc) { case 1: + /* on-chip level shifting via PBIAS0/PBIAS1 */ mmc->slots[0].set_power = twl_mmc1_set_power; - mmc->slots[0].ocr_mask = MMC1_OCR; break; case 2: - mmc->slots[0].set_power = twl_mmc2_set_power; - if (c->transceiver) - mmc->slots[0].ocr_mask = MMC2_OCR; - else - mmc->slots[0].ocr_mask = MMC_VDD_165_195; - break; + if (c->ext_clock) + c->transceiver = 1; + if (c->transceiver && c->wires > 4) + c->wires = 4; + /* FALLTHROUGH */ case 3: - mmc->slots[0].set_power = twl_mmc3_set_power; - mmc->slots[0].ocr_mask = MMC_VDD_165_195; + /* off-chip level shifting, or none */ + mmc->slots[0].set_power = twl_mmc23_set_power; break; default: pr_err("MMC%d configuration not supported!\n", c->mmc); diff --git a/arch/arm/mach-omap2/mmc-twl4030.h b/arch/arm/mach-omap2/mmc-twl4030.h index ea59e8624290..3807c45c9a6c 100644 --- a/arch/arm/mach-omap2/mmc-twl4030.h +++ b/arch/arm/mach-omap2/mmc-twl4030.h @@ -16,9 +16,10 @@ struct twl4030_hsmmc_info { int gpio_wp; /* or -EINVAL */ char *name; /* or NULL for default */ struct device *dev; /* returned: pointer to mmc adapter */ + int ocr_mask; /* temporary HACK */ }; -#if defined(CONFIG_TWL4030_CORE) && \ +#if defined(CONFIG_REGULATOR) && \ (defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE) || \ defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE)) diff --git a/arch/arm/mach-omap2/omap-headsmp.S b/arch/arm/mach-omap2/omap-headsmp.S new file mode 100644 index 000000000000..4afadba09477 --- /dev/null +++ b/arch/arm/mach-omap2/omap-headsmp.S @@ -0,0 +1,46 @@ +/* + * Secondary CPU startup routine source file. + * + * Copyright (C) 2009 Texas Instruments, Inc. + * + * Author: + * Santosh Shilimkar + * + * Interface functions needed for the SMP. This file is based on arm + * realview smp platform. + * Copyright (c) 2003 ARM Limited. + * + * This program is free software,you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include + +/* Physical address needed since MMU not enabled yet on secondary core */ +#define OMAP4_AUX_CORE_BOOT1_PA 0x48281804 + + __INIT + +/* + * OMAP4 specific entry point for secondary CPU to jump from ROM + * code. This routine also provides a holding flag into which + * secondary core is held until we're ready for it to initialise. + * The primary core will update the this flag using a hardware + * register AuxCoreBoot1. + */ +ENTRY(omap_secondary_startup) + mrc p15, 0, r0, c0, c0, 5 + and r0, r0, #0x0f +hold: ldr r1, =OMAP4_AUX_CORE_BOOT1_PA @ read from AuxCoreBoot1 + ldr r2, [r1] + cmp r2, r0 + bne hold + + /* + * we've been released from the cpu_release,secondary_stack + * should now contain the SVC stack for this core + */ + b secondary_startup + diff --git a/arch/arm/mach-omap2/omap-smp.c b/arch/arm/mach-omap2/omap-smp.c new file mode 100644 index 000000000000..8fe8d230f21b --- /dev/null +++ b/arch/arm/mach-omap2/omap-smp.c @@ -0,0 +1,178 @@ +/* + * OMAP4 SMP source file. It contains platform specific fucntions + * needed for the linux smp kernel. + * + * Copyright (C) 2009 Texas Instruments, Inc. + * + * Author: + * Santosh Shilimkar + * + * Platform file needed for the OMAP4 SMP. This file is based on arm + * realview smp platform. + * * Copyright (c) 2002 ARM Limited. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include + +#include +#include +#include + +/* Registers used for communicating startup information */ +#define OMAP4_AUXCOREBOOT_REG0 (OMAP44XX_VA_WKUPGEN_BASE + 0x800) +#define OMAP4_AUXCOREBOOT_REG1 (OMAP44XX_VA_WKUPGEN_BASE + 0x804) + +/* SCU base address */ +static void __iomem *scu_base = OMAP44XX_VA_SCU_BASE; + +/* + * Use SCU config register to count number of cores + */ +static inline unsigned int get_core_count(void) +{ + if (scu_base) + return scu_get_core_count(scu_base); + return 1; +} + +static DEFINE_SPINLOCK(boot_lock); + +void __cpuinit platform_secondary_init(unsigned int cpu) +{ + trace_hardirqs_off(); + + /* + * If any interrupts are already enabled for the primary + * core (e.g. timer irq), then they will not have been enabled + * for us: do so + */ + + gic_cpu_init(0, IO_ADDRESS(OMAP44XX_GIC_CPU_BASE)); + + /* + * Synchronise with the boot thread. + */ + spin_lock(&boot_lock); + spin_unlock(&boot_lock); +} + +int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) +{ + unsigned long timeout; + + /* + * Set synchronisation state between this boot processor + * and the secondary one + */ + spin_lock(&boot_lock); + + /* + * Update the AuxCoreBoot1 with boot state for secondary core. + * omap_secondary_startup() routine will hold the secondary core till + * the AuxCoreBoot1 register is updated with cpu state + * A barrier is added to ensure that write buffer is drained + */ + __raw_writel(cpu, OMAP4_AUXCOREBOOT_REG1); + smp_wmb(); + + timeout = jiffies + (1 * HZ); + while (time_before(jiffies, timeout)) + ; + + /* + * Now the secondary core is starting up let it run its + * calibrations, then wait for it to finish + */ + spin_unlock(&boot_lock); + + return 0; +} + +static void __init wakeup_secondary(void) +{ + /* + * Write the address of secondary startup routine into the + * AuxCoreBoot0 where ROM code will jump and start executing + * on secondary core once out of WFE + * A barrier is added to ensure that write buffer is drained + */ + __raw_writel(virt_to_phys(omap_secondary_startup), \ + OMAP4_AUXCOREBOOT_REG0); + smp_wmb(); + + /* + * Send a 'sev' to wake the secondary core from WFE. + */ + set_event(); + mb(); +} + +/* + * Initialise the CPU possible map early - this describes the CPUs + * which may be present or become present in the system. + */ +void __init smp_init_cpus(void) +{ + unsigned int i, ncores = get_core_count(); + + for (i = 0; i < ncores; i++) + set_cpu_possible(i, true); +} + +void __init smp_prepare_cpus(unsigned int max_cpus) +{ + unsigned int ncores = get_core_count(); + unsigned int cpu = smp_processor_id(); + int i; + + /* sanity check */ + if (ncores == 0) { + printk(KERN_ERR + "OMAP4: strange core count of 0? Default to 1\n"); + ncores = 1; + } + + if (ncores > NR_CPUS) { + printk(KERN_WARNING + "OMAP4: no. of cores (%d) greater than configured " + "maximum of %d - clipping\n", + ncores, NR_CPUS); + ncores = NR_CPUS; + } + smp_store_cpu_info(cpu); + + /* + * are we trying to boot more cores than exist? + */ + if (max_cpus > ncores) + max_cpus = ncores; + + /* + * Initialise the present map, which describes the set of CPUs + * actually populated at the present time. + */ + for (i = 0; i < max_cpus; i++) + set_cpu_present(i, true); + + if (max_cpus > 1) { + /* + * Enable the local timer or broadcast device for the + * boot CPU, but only if we have more than one CPU. + */ + percpu_timer_setup(); + + /* + * Initialise the SCU and wake up the secondary core using + * wakeup_secondary(). + */ + scu_enable(scu_base); + wakeup_secondary(); + } +} diff --git a/arch/arm/mach-omap2/omap3-iommu.c b/arch/arm/mach-omap2/omap3-iommu.c new file mode 100644 index 000000000000..194189c746c2 --- /dev/null +++ b/arch/arm/mach-omap2/omap3-iommu.c @@ -0,0 +1,105 @@ +/* + * omap iommu: omap3 device registration + * + * Copyright (C) 2008-2009 Nokia Corporation + * + * Written by Hiroshi DOYU + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include + +#include + +#define OMAP3_MMU1_BASE 0x480bd400 +#define OMAP3_MMU2_BASE 0x5d000000 +#define OMAP3_MMU1_IRQ 24 +#define OMAP3_MMU2_IRQ 28 + + +static unsigned long iommu_base[] __initdata = { + OMAP3_MMU1_BASE, + OMAP3_MMU2_BASE, +}; + +static int iommu_irq[] __initdata = { + OMAP3_MMU1_IRQ, + OMAP3_MMU2_IRQ, +}; + +static const struct iommu_platform_data omap3_iommu_pdata[] __initconst = { + { + .name = "isp", + .nr_tlb_entries = 8, + .clk_name = "cam_ick", + }, +#if defined(CONFIG_MPU_BRIDGE_IOMMU) + { + .name = "iva2", + .nr_tlb_entries = 32, + .clk_name = "iva2_ck", + }, +#endif +}; +#define NR_IOMMU_DEVICES ARRAY_SIZE(omap3_iommu_pdata) + +static struct platform_device *omap3_iommu_pdev[NR_IOMMU_DEVICES]; + +static int __init omap3_iommu_init(void) +{ + int i, err; + + for (i = 0; i < NR_IOMMU_DEVICES; i++) { + struct platform_device *pdev; + struct resource res[2]; + + pdev = platform_device_alloc("omap-iommu", i); + if (!pdev) { + err = -ENOMEM; + goto err_out; + } + + memset(res, 0, sizeof(res)); + res[0].start = iommu_base[i]; + res[0].end = iommu_base[i] + MMU_REG_SIZE - 1; + res[0].flags = IORESOURCE_MEM; + res[1].start = res[1].end = iommu_irq[i]; + res[1].flags = IORESOURCE_IRQ; + + err = platform_device_add_resources(pdev, res, + ARRAY_SIZE(res)); + if (err) + goto err_out; + err = platform_device_add_data(pdev, &omap3_iommu_pdata[i], + sizeof(omap3_iommu_pdata[0])); + if (err) + goto err_out; + err = platform_device_add(pdev); + if (err) + goto err_out; + omap3_iommu_pdev[i] = pdev; + } + return 0; + +err_out: + while (i--) + platform_device_put(omap3_iommu_pdev[i]); + return err; +} +module_init(omap3_iommu_init); + +static void __exit omap3_iommu_exit(void) +{ + int i; + + for (i = 0; i < NR_IOMMU_DEVICES; i++) + platform_device_unregister(omap3_iommu_pdev[i]); +} +module_exit(omap3_iommu_exit); + +MODULE_AUTHOR("Hiroshi DOYU"); +MODULE_DESCRIPTION("omap iommu: omap3 device registration"); +MODULE_LICENSE("GPL v2"); diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c new file mode 100644 index 000000000000..6cc375a275be --- /dev/null +++ b/arch/arm/mach-omap2/pm-debug.c @@ -0,0 +1,152 @@ +/* + * OMAP Power Management debug routines + * + * Copyright (C) 2005 Texas Instruments, Inc. + * Copyright (C) 2006-2008 Nokia Corporation + * + * Written by: + * Richard Woodruff + * Tony Lindgren + * Juha Yrjola + * Amit Kucheria + * Igor Stoppa + * Jouni Hogander + * + * Based on pm.c for omap2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include "prm.h" +#include "cm.h" +#include "pm.h" + +int omap2_pm_debug; + +#define DUMP_PRM_MOD_REG(mod, reg) \ + regs[reg_count].name = #mod "." #reg; \ + regs[reg_count++].val = prm_read_mod_reg(mod, reg) +#define DUMP_CM_MOD_REG(mod, reg) \ + regs[reg_count].name = #mod "." #reg; \ + regs[reg_count++].val = cm_read_mod_reg(mod, reg) +#define DUMP_PRM_REG(reg) \ + regs[reg_count].name = #reg; \ + regs[reg_count++].val = __raw_readl(reg) +#define DUMP_CM_REG(reg) \ + regs[reg_count].name = #reg; \ + regs[reg_count++].val = __raw_readl(reg) +#define DUMP_INTC_REG(reg, off) \ + regs[reg_count].name = #reg; \ + regs[reg_count++].val = __raw_readl(IO_ADDRESS(0x480fe000 + (off))) + +void omap2_pm_dump(int mode, int resume, unsigned int us) +{ + struct reg { + const char *name; + u32 val; + } regs[32]; + int reg_count = 0, i; + const char *s1 = NULL, *s2 = NULL; + + if (!resume) { +#if 0 + /* MPU */ + DUMP_PRM_MOD_REG(OCP_MOD, OMAP2_PRM_IRQENABLE_MPU_OFFSET); + DUMP_CM_MOD_REG(MPU_MOD, CM_CLKSTCTRL); + DUMP_PRM_MOD_REG(MPU_MOD, PM_PWSTCTRL); + DUMP_PRM_MOD_REG(MPU_MOD, PM_PWSTST); + DUMP_PRM_MOD_REG(MPU_MOD, PM_WKDEP); +#endif +#if 0 + /* INTC */ + DUMP_INTC_REG(INTC_MIR0, 0x0084); + DUMP_INTC_REG(INTC_MIR1, 0x00a4); + DUMP_INTC_REG(INTC_MIR2, 0x00c4); +#endif +#if 0 + DUMP_CM_MOD_REG(CORE_MOD, CM_FCLKEN1); + if (cpu_is_omap24xx()) { + DUMP_CM_MOD_REG(CORE_MOD, OMAP24XX_CM_FCLKEN2); + DUMP_PRM_MOD_REG(OMAP24XX_GR_MOD, + OMAP2_PRCM_CLKEMUL_CTRL_OFFSET); + DUMP_PRM_MOD_REG(OMAP24XX_GR_MOD, + OMAP2_PRCM_CLKSRC_CTRL_OFFSET); + } + DUMP_CM_MOD_REG(WKUP_MOD, CM_FCLKEN); + DUMP_CM_MOD_REG(CORE_MOD, CM_ICLKEN1); + DUMP_CM_MOD_REG(CORE_MOD, CM_ICLKEN2); + DUMP_CM_MOD_REG(WKUP_MOD, CM_ICLKEN); + DUMP_CM_MOD_REG(PLL_MOD, CM_CLKEN); + DUMP_CM_MOD_REG(PLL_MOD, CM_AUTOIDLE); + DUMP_PRM_MOD_REG(CORE_MOD, PM_PWSTST); +#endif +#if 0 + /* DSP */ + if (cpu_is_omap24xx()) { + DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_FCLKEN); + DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_ICLKEN); + DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_IDLEST); + DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_AUTOIDLE); + DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_CLKSEL); + DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_CLKSTCTRL); + DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, RM_RSTCTRL); + DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, RM_RSTST); + DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, PM_PWSTCTRL); + DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, PM_PWSTST); + } +#endif + } else { + DUMP_PRM_MOD_REG(CORE_MOD, PM_WKST1); + if (cpu_is_omap24xx()) + DUMP_PRM_MOD_REG(CORE_MOD, OMAP24XX_PM_WKST2); + DUMP_PRM_MOD_REG(WKUP_MOD, PM_WKST); + DUMP_PRM_MOD_REG(OCP_MOD, OMAP2_PRCM_IRQSTATUS_MPU_OFFSET); +#if 1 + DUMP_INTC_REG(INTC_PENDING_IRQ0, 0x0098); + DUMP_INTC_REG(INTC_PENDING_IRQ1, 0x00b8); + DUMP_INTC_REG(INTC_PENDING_IRQ2, 0x00d8); +#endif + } + + switch (mode) { + case 0: + s1 = "full"; + s2 = "retention"; + break; + case 1: + s1 = "MPU"; + s2 = "retention"; + break; + case 2: + s1 = "MPU"; + s2 = "idle"; + break; + } + + if (!resume) +#ifdef CONFIG_NO_HZ + printk(KERN_INFO + "--- Going to %s %s (next timer after %u ms)\n", s1, s2, + jiffies_to_msecs(get_next_timer_interrupt(jiffies) - + jiffies)); +#else + printk(KERN_INFO "--- Going to %s %s\n", s1, s2); +#endif + else + printk(KERN_INFO "--- Woke up (slept for %u.%03u ms)\n", + us / 1000, us % 1000); + + for (i = 0; i < reg_count; i++) + printk(KERN_INFO "%-20s: 0x%08x\n", regs[i].name, regs[i].val); +} diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c deleted file mode 100644 index ea8ceaed09cb..000000000000 --- a/arch/arm/mach-omap2/pm.c +++ /dev/null @@ -1,111 +0,0 @@ -/* - * linux/arch/arm/mach-omap2/pm.c - * - * OMAP2 Power Management Routines - * - * Copyright (C) 2006 Nokia Corporation - * Tony Lindgren - * - * Copyright (C) 2005 Texas Instruments, Inc. - * Richard Woodruff - * - * Based on pm.c for omap1 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include - -static struct clk *vclk; -static void (*omap2_sram_idle)(void); -static void (*omap2_sram_suspend)(int dllctrl, int cpu_rev); -static void (*saved_idle)(void); - -extern void __init pmdomain_init(void); -extern void pmdomain_set_autoidle(void); - -static unsigned int omap24xx_sleep_save[OMAP24XX_SLEEP_SAVE_SIZE]; - -void omap2_pm_idle(void) -{ - local_irq_disable(); - local_fiq_disable(); - if (need_resched()) { - local_fiq_enable(); - local_irq_enable(); - return; - } - - omap2_sram_idle(); - local_fiq_enable(); - local_irq_enable(); -} - -static int omap2_pm_prepare(void) -{ - /* We cannot sleep in idle until we have resumed */ - saved_idle = pm_idle; - pm_idle = NULL; - return 0; -} - -static int omap2_pm_suspend(void) -{ - return 0; -} - -static int omap2_pm_enter(suspend_state_t state) -{ - int ret = 0; - - switch (state) - { - case PM_SUSPEND_STANDBY: - case PM_SUSPEND_MEM: - ret = omap2_pm_suspend(); - break; - default: - ret = -EINVAL; - } - - return ret; -} - -static void omap2_pm_finish(void) -{ - pm_idle = saved_idle; -} - -static struct platform_suspend_ops omap_pm_ops = { - .prepare = omap2_pm_prepare, - .enter = omap2_pm_enter, - .finish = omap2_pm_finish, - .valid = suspend_valid_only_mem, -}; - -static int __init omap2_pm_init(void) -{ - return 0; -} - -__initcall(omap2_pm_init); diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h new file mode 100644 index 000000000000..f7b3baf76678 --- /dev/null +++ b/arch/arm/mach-omap2/pm.h @@ -0,0 +1,38 @@ +/* + * OMAP2/3 Power Management Routines + * + * Copyright (C) 2008 Nokia Corporation + * Jouni Hogander + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ARCH_ARM_MACH_OMAP2_PM_H +#define __ARCH_ARM_MACH_OMAP2_PM_H + +extern int omap2_pm_init(void); +extern int omap3_pm_init(void); + +#ifdef CONFIG_PM_DEBUG +extern void omap2_pm_dump(int mode, int resume, unsigned int us); +extern int omap2_pm_debug; +#else +#define omap2_pm_dump(mode, resume, us) do {} while (0); +#define omap2_pm_debug 0 +#endif /* CONFIG_PM_DEBUG */ + +extern void omap24xx_idle_loop_suspend(void); + +extern void omap24xx_cpu_suspend(u32 dll_ctrl, void __iomem *sdrc_dlla_ctrl, + void __iomem *sdrc_power); +extern void omap34xx_cpu_suspend(u32 *addr, int save_state); +extern void save_secure_ram_context(u32 *addr); + +extern unsigned int omap24xx_idle_loop_suspend_sz; +extern unsigned int omap34xx_suspend_sz; +extern unsigned int save_secure_ram_context_sz; +extern unsigned int omap24xx_cpu_suspend_sz; +extern unsigned int omap34xx_cpu_suspend_sz; + +#endif diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c new file mode 100644 index 000000000000..db1025562fb0 --- /dev/null +++ b/arch/arm/mach-omap2/pm24xx.c @@ -0,0 +1,549 @@ +/* + * OMAP2 Power Management Routines + * + * Copyright (C) 2005 Texas Instruments, Inc. + * Copyright (C) 2006-2008 Nokia Corporation + * + * Written by: + * Richard Woodruff + * Tony Lindgren + * Juha Yrjola + * Amit Kucheria + * Igor Stoppa + * + * Based on pm.c for omap1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "prm.h" +#include "prm-regbits-24xx.h" +#include "cm.h" +#include "cm-regbits-24xx.h" +#include "sdrc.h" +#include "pm.h" + +#include +#include + +static void (*omap2_sram_idle)(void); +static void (*omap2_sram_suspend)(u32 dllctrl, void __iomem *sdrc_dlla_ctrl, + void __iomem *sdrc_power); + +static struct powerdomain *mpu_pwrdm; +static struct powerdomain *core_pwrdm; + +static struct clockdomain *dsp_clkdm; +static struct clockdomain *gfx_clkdm; + +static struct clk *osc_ck, *emul_ck; + +static int omap2_fclks_active(void) +{ + u32 f1, f2; + + f1 = cm_read_mod_reg(CORE_MOD, CM_FCLKEN1); + f2 = cm_read_mod_reg(CORE_MOD, OMAP24XX_CM_FCLKEN2); + + /* Ignore UART clocks. These are handled by UART core (serial.c) */ + f1 &= ~(OMAP24XX_EN_UART1 | OMAP24XX_EN_UART2); + f2 &= ~OMAP24XX_EN_UART3; + + if (f1 | f2) + return 1; + return 0; +} + +static void omap2_enter_full_retention(void) +{ + u32 l; + struct timespec ts_preidle, ts_postidle, ts_idle; + + /* There is 1 reference hold for all children of the oscillator + * clock, the following will remove it. If no one else uses the + * oscillator itself it will be disabled if/when we enter retention + * mode. + */ + clk_disable(osc_ck); + + /* Clear old wake-up events */ + /* REVISIT: These write to reserved bits? */ + prm_write_mod_reg(0xffffffff, CORE_MOD, PM_WKST1); + prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP24XX_PM_WKST2); + prm_write_mod_reg(0xffffffff, WKUP_MOD, PM_WKST); + + /* + * Set MPU powerdomain's next power state to RETENTION; + * preserve logic state during retention + */ + pwrdm_set_logic_retst(mpu_pwrdm, PWRDM_POWER_RET); + pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_RET); + + /* Workaround to kill USB */ + l = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0) | OMAP24XX_USBSTANDBYCTRL; + omap_ctrl_writel(l, OMAP2_CONTROL_DEVCONF0); + + omap2_gpio_prepare_for_retention(); + + if (omap2_pm_debug) { + omap2_pm_dump(0, 0, 0); + getnstimeofday(&ts_preidle); + } + + /* One last check for pending IRQs to avoid extra latency due + * to sleeping unnecessarily. */ + if (omap_irq_pending()) + goto no_sleep; + + omap_uart_prepare_idle(0); + omap_uart_prepare_idle(1); + omap_uart_prepare_idle(2); + + /* Jump to SRAM suspend code */ + omap2_sram_suspend(sdrc_read_reg(SDRC_DLLA_CTRL), + OMAP_SDRC_REGADDR(SDRC_DLLA_CTRL), + OMAP_SDRC_REGADDR(SDRC_POWER)); + + omap_uart_resume_idle(2); + omap_uart_resume_idle(1); + omap_uart_resume_idle(0); + +no_sleep: + if (omap2_pm_debug) { + unsigned long long tmp; + + getnstimeofday(&ts_postidle); + ts_idle = timespec_sub(ts_postidle, ts_preidle); + tmp = timespec_to_ns(&ts_idle) * NSEC_PER_USEC; + omap2_pm_dump(0, 1, tmp); + } + omap2_gpio_resume_after_retention(); + + clk_enable(osc_ck); + + /* clear CORE wake-up events */ + prm_write_mod_reg(0xffffffff, CORE_MOD, PM_WKST1); + prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP24XX_PM_WKST2); + + /* wakeup domain events - bit 1: GPT1, bit5 GPIO */ + prm_clear_mod_reg_bits(0x4 | 0x1, WKUP_MOD, PM_WKST); + + /* MPU domain wake events */ + l = prm_read_mod_reg(OCP_MOD, OMAP2_PRCM_IRQSTATUS_MPU_OFFSET); + if (l & 0x01) + prm_write_mod_reg(0x01, OCP_MOD, + OMAP2_PRCM_IRQSTATUS_MPU_OFFSET); + if (l & 0x20) + prm_write_mod_reg(0x20, OCP_MOD, + OMAP2_PRCM_IRQSTATUS_MPU_OFFSET); + + /* Mask future PRCM-to-MPU interrupts */ + prm_write_mod_reg(0x0, OCP_MOD, OMAP2_PRCM_IRQSTATUS_MPU_OFFSET); +} + +static int omap2_i2c_active(void) +{ + u32 l; + + l = cm_read_mod_reg(CORE_MOD, CM_FCLKEN1); + return l & (OMAP2420_EN_I2C2 | OMAP2420_EN_I2C1); +} + +static int sti_console_enabled; + +static int omap2_allow_mpu_retention(void) +{ + u32 l; + + /* Check for MMC, UART2, UART1, McSPI2, McSPI1 and DSS1. */ + l = cm_read_mod_reg(CORE_MOD, CM_FCLKEN1); + if (l & (OMAP2420_EN_MMC | OMAP24XX_EN_UART2 | + OMAP24XX_EN_UART1 | OMAP24XX_EN_MCSPI2 | + OMAP24XX_EN_MCSPI1 | OMAP24XX_EN_DSS1)) + return 0; + /* Check for UART3. */ + l = cm_read_mod_reg(CORE_MOD, OMAP24XX_CM_FCLKEN2); + if (l & OMAP24XX_EN_UART3) + return 0; + if (sti_console_enabled) + return 0; + + return 1; +} + +static void omap2_enter_mpu_retention(void) +{ + int only_idle = 0; + struct timespec ts_preidle, ts_postidle, ts_idle; + + /* Putting MPU into the WFI state while a transfer is active + * seems to cause the I2C block to timeout. Why? Good question. */ + if (omap2_i2c_active()) + return; + + /* The peripherals seem not to be able to wake up the MPU when + * it is in retention mode. */ + if (omap2_allow_mpu_retention()) { + /* REVISIT: These write to reserved bits? */ + prm_write_mod_reg(0xffffffff, CORE_MOD, PM_WKST1); + prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP24XX_PM_WKST2); + prm_write_mod_reg(0xffffffff, WKUP_MOD, PM_WKST); + + /* Try to enter MPU retention */ + prm_write_mod_reg((0x01 << OMAP_POWERSTATE_SHIFT) | + OMAP_LOGICRETSTATE, + MPU_MOD, PM_PWSTCTRL); + } else { + /* Block MPU retention */ + + prm_write_mod_reg(OMAP_LOGICRETSTATE, MPU_MOD, PM_PWSTCTRL); + only_idle = 1; + } + + if (omap2_pm_debug) { + omap2_pm_dump(only_idle ? 2 : 1, 0, 0); + getnstimeofday(&ts_preidle); + } + + omap2_sram_idle(); + + if (omap2_pm_debug) { + unsigned long long tmp; + + getnstimeofday(&ts_postidle); + ts_idle = timespec_sub(ts_postidle, ts_preidle); + tmp = timespec_to_ns(&ts_idle) * NSEC_PER_USEC; + omap2_pm_dump(only_idle ? 2 : 1, 1, tmp); + } +} + +static int omap2_can_sleep(void) +{ + if (omap2_fclks_active()) + return 0; + if (osc_ck->usecount > 1) + return 0; + if (omap_dma_running()) + return 0; + + return 1; +} + +static void omap2_pm_idle(void) +{ + local_irq_disable(); + local_fiq_disable(); + + if (!omap2_can_sleep()) { + if (omap_irq_pending()) + goto out; + omap2_enter_mpu_retention(); + goto out; + } + + if (omap_irq_pending()) + goto out; + + omap2_enter_full_retention(); + +out: + local_fiq_enable(); + local_irq_enable(); +} + +static int omap2_pm_prepare(void) +{ + /* We cannot sleep in idle until we have resumed */ + disable_hlt(); + return 0; +} + +static int omap2_pm_suspend(void) +{ + u32 wken_wkup, mir1; + + wken_wkup = prm_read_mod_reg(WKUP_MOD, PM_WKEN); + prm_write_mod_reg(wken_wkup & ~OMAP24XX_EN_GPT1, WKUP_MOD, PM_WKEN); + + /* Mask GPT1 */ + mir1 = omap_readl(0x480fe0a4); + omap_writel(1 << 5, 0x480fe0ac); + + omap_uart_prepare_suspend(); + omap2_enter_full_retention(); + + omap_writel(mir1, 0x480fe0a4); + prm_write_mod_reg(wken_wkup, WKUP_MOD, PM_WKEN); + + return 0; +} + +static int omap2_pm_enter(suspend_state_t state) +{ + int ret = 0; + + switch (state) { + case PM_SUSPEND_STANDBY: + case PM_SUSPEND_MEM: + ret = omap2_pm_suspend(); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static void omap2_pm_finish(void) +{ + enable_hlt(); +} + +static struct platform_suspend_ops omap_pm_ops = { + .prepare = omap2_pm_prepare, + .enter = omap2_pm_enter, + .finish = omap2_pm_finish, + .valid = suspend_valid_only_mem, +}; + +static int _pm_clkdm_enable_hwsup(struct clockdomain *clkdm) +{ + omap2_clkdm_allow_idle(clkdm); + return 0; +} + +static void __init prcm_setup_regs(void) +{ + int i, num_mem_banks; + struct powerdomain *pwrdm; + + /* Enable autoidle */ + prm_write_mod_reg(OMAP24XX_AUTOIDLE, OCP_MOD, + OMAP2_PRCM_SYSCONFIG_OFFSET); + + /* Set all domain wakeup dependencies */ + prm_write_mod_reg(OMAP_EN_WKUP_MASK, MPU_MOD, PM_WKDEP); + prm_write_mod_reg(0, OMAP24XX_DSP_MOD, PM_WKDEP); + prm_write_mod_reg(0, GFX_MOD, PM_WKDEP); + prm_write_mod_reg(0, CORE_MOD, PM_WKDEP); + if (cpu_is_omap2430()) + prm_write_mod_reg(0, OMAP2430_MDM_MOD, PM_WKDEP); + + /* + * Set CORE powerdomain memory banks to retain their contents + * during RETENTION + */ + num_mem_banks = pwrdm_get_mem_bank_count(core_pwrdm); + for (i = 0; i < num_mem_banks; i++) + pwrdm_set_mem_retst(core_pwrdm, i, PWRDM_POWER_RET); + + /* Set CORE powerdomain's next power state to RETENTION */ + pwrdm_set_next_pwrst(core_pwrdm, PWRDM_POWER_RET); + + /* + * Set MPU powerdomain's next power state to RETENTION; + * preserve logic state during retention + */ + pwrdm_set_logic_retst(mpu_pwrdm, PWRDM_POWER_RET); + pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_RET); + + /* Force-power down DSP, GFX powerdomains */ + + pwrdm = clkdm_get_pwrdm(dsp_clkdm); + pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_OFF); + omap2_clkdm_sleep(dsp_clkdm); + + pwrdm = clkdm_get_pwrdm(gfx_clkdm); + pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_OFF); + omap2_clkdm_sleep(gfx_clkdm); + + /* Enable clockdomain hardware-supervised control for all clkdms */ + clkdm_for_each(_pm_clkdm_enable_hwsup); + + /* Enable clock autoidle for all domains */ + cm_write_mod_reg(OMAP24XX_AUTO_CAM | + OMAP24XX_AUTO_MAILBOXES | + OMAP24XX_AUTO_WDT4 | + OMAP2420_AUTO_WDT3 | + OMAP24XX_AUTO_MSPRO | + OMAP2420_AUTO_MMC | + OMAP24XX_AUTO_FAC | + OMAP2420_AUTO_EAC | + OMAP24XX_AUTO_HDQ | + OMAP24XX_AUTO_UART2 | + OMAP24XX_AUTO_UART1 | + OMAP24XX_AUTO_I2C2 | + OMAP24XX_AUTO_I2C1 | + OMAP24XX_AUTO_MCSPI2 | + OMAP24XX_AUTO_MCSPI1 | + OMAP24XX_AUTO_MCBSP2 | + OMAP24XX_AUTO_MCBSP1 | + OMAP24XX_AUTO_GPT12 | + OMAP24XX_AUTO_GPT11 | + OMAP24XX_AUTO_GPT10 | + OMAP24XX_AUTO_GPT9 | + OMAP24XX_AUTO_GPT8 | + OMAP24XX_AUTO_GPT7 | + OMAP24XX_AUTO_GPT6 | + OMAP24XX_AUTO_GPT5 | + OMAP24XX_AUTO_GPT4 | + OMAP24XX_AUTO_GPT3 | + OMAP24XX_AUTO_GPT2 | + OMAP2420_AUTO_VLYNQ | + OMAP24XX_AUTO_DSS, + CORE_MOD, CM_AUTOIDLE1); + cm_write_mod_reg(OMAP24XX_AUTO_UART3 | + OMAP24XX_AUTO_SSI | + OMAP24XX_AUTO_USB, + CORE_MOD, CM_AUTOIDLE2); + cm_write_mod_reg(OMAP24XX_AUTO_SDRC | + OMAP24XX_AUTO_GPMC | + OMAP24XX_AUTO_SDMA, + CORE_MOD, CM_AUTOIDLE3); + cm_write_mod_reg(OMAP24XX_AUTO_PKA | + OMAP24XX_AUTO_AES | + OMAP24XX_AUTO_RNG | + OMAP24XX_AUTO_SHA | + OMAP24XX_AUTO_DES, + CORE_MOD, OMAP24XX_CM_AUTOIDLE4); + + cm_write_mod_reg(OMAP2420_AUTO_DSP_IPI, OMAP24XX_DSP_MOD, CM_AUTOIDLE); + + /* Put DPLL and both APLLs into autoidle mode */ + cm_write_mod_reg((0x03 << OMAP24XX_AUTO_DPLL_SHIFT) | + (0x03 << OMAP24XX_AUTO_96M_SHIFT) | + (0x03 << OMAP24XX_AUTO_54M_SHIFT), + PLL_MOD, CM_AUTOIDLE); + + cm_write_mod_reg(OMAP24XX_AUTO_OMAPCTRL | + OMAP24XX_AUTO_WDT1 | + OMAP24XX_AUTO_MPU_WDT | + OMAP24XX_AUTO_GPIOS | + OMAP24XX_AUTO_32KSYNC | + OMAP24XX_AUTO_GPT1, + WKUP_MOD, CM_AUTOIDLE); + + /* REVISIT: Configure number of 32 kHz clock cycles for sys_clk + * stabilisation */ + prm_write_mod_reg(15 << OMAP_SETUP_TIME_SHIFT, OMAP24XX_GR_MOD, + OMAP2_PRCM_CLKSSETUP_OFFSET); + + /* Configure automatic voltage transition */ + prm_write_mod_reg(2 << OMAP_SETUP_TIME_SHIFT, OMAP24XX_GR_MOD, + OMAP2_PRCM_VOLTSETUP_OFFSET); + prm_write_mod_reg(OMAP24XX_AUTO_EXTVOLT | + (0x1 << OMAP24XX_SETOFF_LEVEL_SHIFT) | + OMAP24XX_MEMRETCTRL | + (0x1 << OMAP24XX_SETRET_LEVEL_SHIFT) | + (0x0 << OMAP24XX_VOLT_LEVEL_SHIFT), + OMAP24XX_GR_MOD, OMAP2_PRCM_VOLTCTRL_OFFSET); + + /* Enable wake-up events */ + prm_write_mod_reg(OMAP24XX_EN_GPIOS | OMAP24XX_EN_GPT1, + WKUP_MOD, PM_WKEN); +} + +int __init omap2_pm_init(void) +{ + u32 l; + + if (!cpu_is_omap24xx()) + return -ENODEV; + + printk(KERN_INFO "Power Management for OMAP2 initializing\n"); + l = prm_read_mod_reg(OCP_MOD, OMAP2_PRCM_REVISION_OFFSET); + printk(KERN_INFO "PRCM revision %d.%d\n", (l >> 4) & 0x0f, l & 0x0f); + + /* Look up important powerdomains, clockdomains */ + + mpu_pwrdm = pwrdm_lookup("mpu_pwrdm"); + if (!mpu_pwrdm) + pr_err("PM: mpu_pwrdm not found\n"); + + core_pwrdm = pwrdm_lookup("core_pwrdm"); + if (!core_pwrdm) + pr_err("PM: core_pwrdm not found\n"); + + dsp_clkdm = clkdm_lookup("dsp_clkdm"); + if (!dsp_clkdm) + pr_err("PM: mpu_clkdm not found\n"); + + gfx_clkdm = clkdm_lookup("gfx_clkdm"); + if (!gfx_clkdm) + pr_err("PM: gfx_clkdm not found\n"); + + + osc_ck = clk_get(NULL, "osc_ck"); + if (IS_ERR(osc_ck)) { + printk(KERN_ERR "could not get osc_ck\n"); + return -ENODEV; + } + + if (cpu_is_omap242x()) { + emul_ck = clk_get(NULL, "emul_ck"); + if (IS_ERR(emul_ck)) { + printk(KERN_ERR "could not get emul_ck\n"); + clk_put(osc_ck); + return -ENODEV; + } + } + + prcm_setup_regs(); + + /* Hack to prevent MPU retention when STI console is enabled. */ + { + const struct omap_sti_console_config *sti; + + sti = omap_get_config(OMAP_TAG_STI_CONSOLE, + struct omap_sti_console_config); + if (sti != NULL && sti->enable) + sti_console_enabled = 1; + } + + /* + * We copy the assembler sleep/wakeup routines to SRAM. + * These routines need to be in SRAM as that's the only + * memory the MPU can see when it wakes up. + */ + if (cpu_is_omap24xx()) { + omap2_sram_idle = omap_sram_push(omap24xx_idle_loop_suspend, + omap24xx_idle_loop_suspend_sz); + + omap2_sram_suspend = omap_sram_push(omap24xx_cpu_suspend, + omap24xx_cpu_suspend_sz); + } + + suspend_set_ops(&omap_pm_ops); + pm_idle = omap2_pm_idle; + + return 0; +} + +late_initcall(omap2_pm_init); diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c new file mode 100644 index 000000000000..841d4c5ed8be --- /dev/null +++ b/arch/arm/mach-omap2/pm34xx.c @@ -0,0 +1,710 @@ +/* + * OMAP3 Power Management Routines + * + * Copyright (C) 2006-2008 Nokia Corporation + * Tony Lindgren + * Jouni Hogander + * + * Copyright (C) 2005 Texas Instruments, Inc. + * Richard Woodruff + * + * Based on pm.c for omap1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "cm.h" +#include "cm-regbits-34xx.h" +#include "prm-regbits-34xx.h" + +#include "prm.h" +#include "pm.h" + +struct power_state { + struct powerdomain *pwrdm; + u32 next_state; + u32 saved_state; + struct list_head node; +}; + +static LIST_HEAD(pwrst_list); + +static void (*_omap_sram_idle)(u32 *addr, int save_state); + +static struct powerdomain *mpu_pwrdm; + +/* PRCM Interrupt Handler for wakeups */ +static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id) +{ + u32 wkst, irqstatus_mpu; + u32 fclk, iclk; + + /* WKUP */ + wkst = prm_read_mod_reg(WKUP_MOD, PM_WKST); + if (wkst) { + iclk = cm_read_mod_reg(WKUP_MOD, CM_ICLKEN); + fclk = cm_read_mod_reg(WKUP_MOD, CM_FCLKEN); + cm_set_mod_reg_bits(wkst, WKUP_MOD, CM_ICLKEN); + cm_set_mod_reg_bits(wkst, WKUP_MOD, CM_FCLKEN); + prm_write_mod_reg(wkst, WKUP_MOD, PM_WKST); + while (prm_read_mod_reg(WKUP_MOD, PM_WKST)) + cpu_relax(); + cm_write_mod_reg(iclk, WKUP_MOD, CM_ICLKEN); + cm_write_mod_reg(fclk, WKUP_MOD, CM_FCLKEN); + } + + /* CORE */ + wkst = prm_read_mod_reg(CORE_MOD, PM_WKST1); + if (wkst) { + iclk = cm_read_mod_reg(CORE_MOD, CM_ICLKEN1); + fclk = cm_read_mod_reg(CORE_MOD, CM_FCLKEN1); + cm_set_mod_reg_bits(wkst, CORE_MOD, CM_ICLKEN1); + cm_set_mod_reg_bits(wkst, CORE_MOD, CM_FCLKEN1); + prm_write_mod_reg(wkst, CORE_MOD, PM_WKST1); + while (prm_read_mod_reg(CORE_MOD, PM_WKST1)) + cpu_relax(); + cm_write_mod_reg(iclk, CORE_MOD, CM_ICLKEN1); + cm_write_mod_reg(fclk, CORE_MOD, CM_FCLKEN1); + } + wkst = prm_read_mod_reg(CORE_MOD, OMAP3430ES2_PM_WKST3); + if (wkst) { + iclk = cm_read_mod_reg(CORE_MOD, CM_ICLKEN3); + fclk = cm_read_mod_reg(CORE_MOD, OMAP3430ES2_CM_FCLKEN3); + cm_set_mod_reg_bits(wkst, CORE_MOD, CM_ICLKEN3); + cm_set_mod_reg_bits(wkst, CORE_MOD, OMAP3430ES2_CM_FCLKEN3); + prm_write_mod_reg(wkst, CORE_MOD, OMAP3430ES2_PM_WKST3); + while (prm_read_mod_reg(CORE_MOD, OMAP3430ES2_PM_WKST3)) + cpu_relax(); + cm_write_mod_reg(iclk, CORE_MOD, CM_ICLKEN3); + cm_write_mod_reg(fclk, CORE_MOD, OMAP3430ES2_CM_FCLKEN3); + } + + /* PER */ + wkst = prm_read_mod_reg(OMAP3430_PER_MOD, PM_WKST); + if (wkst) { + iclk = cm_read_mod_reg(OMAP3430_PER_MOD, CM_ICLKEN); + fclk = cm_read_mod_reg(OMAP3430_PER_MOD, CM_FCLKEN); + cm_set_mod_reg_bits(wkst, OMAP3430_PER_MOD, CM_ICLKEN); + cm_set_mod_reg_bits(wkst, OMAP3430_PER_MOD, CM_FCLKEN); + prm_write_mod_reg(wkst, OMAP3430_PER_MOD, PM_WKST); + while (prm_read_mod_reg(OMAP3430_PER_MOD, PM_WKST)) + cpu_relax(); + cm_write_mod_reg(iclk, OMAP3430_PER_MOD, CM_ICLKEN); + cm_write_mod_reg(fclk, OMAP3430_PER_MOD, CM_FCLKEN); + } + + if (omap_rev() > OMAP3430_REV_ES1_0) { + /* USBHOST */ + wkst = prm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, PM_WKST); + if (wkst) { + iclk = cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, + CM_ICLKEN); + fclk = cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, + CM_FCLKEN); + cm_set_mod_reg_bits(wkst, OMAP3430ES2_USBHOST_MOD, + CM_ICLKEN); + cm_set_mod_reg_bits(wkst, OMAP3430ES2_USBHOST_MOD, + CM_FCLKEN); + prm_write_mod_reg(wkst, OMAP3430ES2_USBHOST_MOD, + PM_WKST); + while (prm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, + PM_WKST)) + cpu_relax(); + cm_write_mod_reg(iclk, OMAP3430ES2_USBHOST_MOD, + CM_ICLKEN); + cm_write_mod_reg(fclk, OMAP3430ES2_USBHOST_MOD, + CM_FCLKEN); + } + } + + irqstatus_mpu = prm_read_mod_reg(OCP_MOD, + OMAP3_PRM_IRQSTATUS_MPU_OFFSET); + prm_write_mod_reg(irqstatus_mpu, OCP_MOD, + OMAP3_PRM_IRQSTATUS_MPU_OFFSET); + + while (prm_read_mod_reg(OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET)) + cpu_relax(); + + return IRQ_HANDLED; +} + +static void omap_sram_idle(void) +{ + /* Variable to tell what needs to be saved and restored + * in omap_sram_idle*/ + /* save_state = 0 => Nothing to save and restored */ + /* save_state = 1 => Only L1 and logic lost */ + /* save_state = 2 => Only L2 lost */ + /* save_state = 3 => L1, L2 and logic lost */ + int save_state = 0, mpu_next_state; + + if (!_omap_sram_idle) + return; + + mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm); + switch (mpu_next_state) { + case PWRDM_POWER_RET: + /* No need to save context */ + save_state = 0; + break; + default: + /* Invalid state */ + printk(KERN_ERR "Invalid mpu state in sram_idle\n"); + return; + } + omap2_gpio_prepare_for_retention(); + omap_uart_prepare_idle(0); + omap_uart_prepare_idle(1); + omap_uart_prepare_idle(2); + + _omap_sram_idle(NULL, save_state); + cpu_init(); + + omap_uart_resume_idle(2); + omap_uart_resume_idle(1); + omap_uart_resume_idle(0); + omap2_gpio_resume_after_retention(); +} + +/* + * Check if functional clocks are enabled before entering + * sleep. This function could be behind CONFIG_PM_DEBUG + * when all drivers are configuring their sysconfig registers + * properly and using their clocks properly. + */ +static int omap3_fclks_active(void) +{ + u32 fck_core1 = 0, fck_core3 = 0, fck_sgx = 0, fck_dss = 0, + fck_cam = 0, fck_per = 0, fck_usbhost = 0; + + fck_core1 = cm_read_mod_reg(CORE_MOD, + CM_FCLKEN1); + if (omap_rev() > OMAP3430_REV_ES1_0) { + fck_core3 = cm_read_mod_reg(CORE_MOD, + OMAP3430ES2_CM_FCLKEN3); + fck_sgx = cm_read_mod_reg(OMAP3430ES2_SGX_MOD, + CM_FCLKEN); + fck_usbhost = cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, + CM_FCLKEN); + } else + fck_sgx = cm_read_mod_reg(GFX_MOD, + OMAP3430ES2_CM_FCLKEN3); + fck_dss = cm_read_mod_reg(OMAP3430_DSS_MOD, + CM_FCLKEN); + fck_cam = cm_read_mod_reg(OMAP3430_CAM_MOD, + CM_FCLKEN); + fck_per = cm_read_mod_reg(OMAP3430_PER_MOD, + CM_FCLKEN); + + /* Ignore UART clocks. These are handled by UART core (serial.c) */ + fck_core1 &= ~(OMAP3430_EN_UART1 | OMAP3430_EN_UART2); + fck_per &= ~OMAP3430_EN_UART3; + + if (fck_core1 | fck_core3 | fck_sgx | fck_dss | + fck_cam | fck_per | fck_usbhost) + return 1; + return 0; +} + +static int omap3_can_sleep(void) +{ + if (!omap_uart_can_sleep()) + return 0; + if (omap3_fclks_active()) + return 0; + return 1; +} + +/* This sets pwrdm state (other than mpu & core. Currently only ON & + * RET are supported. Function is assuming that clkdm doesn't have + * hw_sup mode enabled. */ +static int set_pwrdm_state(struct powerdomain *pwrdm, u32 state) +{ + u32 cur_state; + int sleep_switch = 0; + int ret = 0; + + if (pwrdm == NULL || IS_ERR(pwrdm)) + return -EINVAL; + + while (!(pwrdm->pwrsts & (1 << state))) { + if (state == PWRDM_POWER_OFF) + return ret; + state--; + } + + cur_state = pwrdm_read_next_pwrst(pwrdm); + if (cur_state == state) + return ret; + + if (pwrdm_read_pwrst(pwrdm) < PWRDM_POWER_ON) { + omap2_clkdm_wakeup(pwrdm->pwrdm_clkdms[0]); + sleep_switch = 1; + pwrdm_wait_transition(pwrdm); + } + + ret = pwrdm_set_next_pwrst(pwrdm, state); + if (ret) { + printk(KERN_ERR "Unable to set state of powerdomain: %s\n", + pwrdm->name); + goto err; + } + + if (sleep_switch) { + omap2_clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]); + pwrdm_wait_transition(pwrdm); + } + +err: + return ret; +} + +static void omap3_pm_idle(void) +{ + local_irq_disable(); + local_fiq_disable(); + + if (!omap3_can_sleep()) + goto out; + + if (omap_irq_pending()) + goto out; + + omap_sram_idle(); + +out: + local_fiq_enable(); + local_irq_enable(); +} + +static int omap3_pm_prepare(void) +{ + disable_hlt(); + return 0; +} + +static int omap3_pm_suspend(void) +{ + struct power_state *pwrst; + int state, ret = 0; + + /* Read current next_pwrsts */ + list_for_each_entry(pwrst, &pwrst_list, node) + pwrst->saved_state = pwrdm_read_next_pwrst(pwrst->pwrdm); + /* Set ones wanted by suspend */ + list_for_each_entry(pwrst, &pwrst_list, node) { + if (set_pwrdm_state(pwrst->pwrdm, pwrst->next_state)) + goto restore; + if (pwrdm_clear_all_prev_pwrst(pwrst->pwrdm)) + goto restore; + } + + omap_uart_prepare_suspend(); + omap_sram_idle(); + +restore: + /* Restore next_pwrsts */ + list_for_each_entry(pwrst, &pwrst_list, node) { + set_pwrdm_state(pwrst->pwrdm, pwrst->saved_state); + state = pwrdm_read_prev_pwrst(pwrst->pwrdm); + if (state > pwrst->next_state) { + printk(KERN_INFO "Powerdomain (%s) didn't enter " + "target state %d\n", + pwrst->pwrdm->name, pwrst->next_state); + ret = -1; + } + } + if (ret) + printk(KERN_ERR "Could not enter target state in pm_suspend\n"); + else + printk(KERN_INFO "Successfully put all powerdomains " + "to target state\n"); + + return ret; +} + +static int omap3_pm_enter(suspend_state_t state) +{ + int ret = 0; + + switch (state) { + case PM_SUSPEND_STANDBY: + case PM_SUSPEND_MEM: + ret = omap3_pm_suspend(); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static void omap3_pm_finish(void) +{ + enable_hlt(); +} + +static struct platform_suspend_ops omap_pm_ops = { + .prepare = omap3_pm_prepare, + .enter = omap3_pm_enter, + .finish = omap3_pm_finish, + .valid = suspend_valid_only_mem, +}; + + +/** + * omap3_iva_idle(): ensure IVA is in idle so it can be put into + * retention + * + * In cases where IVA2 is activated by bootcode, it may prevent + * full-chip retention or off-mode because it is not idle. This + * function forces the IVA2 into idle state so it can go + * into retention/off and thus allow full-chip retention/off. + * + **/ +static void __init omap3_iva_idle(void) +{ + /* ensure IVA2 clock is disabled */ + cm_write_mod_reg(0, OMAP3430_IVA2_MOD, CM_FCLKEN); + + /* if no clock activity, nothing else to do */ + if (!(cm_read_mod_reg(OMAP3430_IVA2_MOD, OMAP3430_CM_CLKSTST) & + OMAP3430_CLKACTIVITY_IVA2_MASK)) + return; + + /* Reset IVA2 */ + prm_write_mod_reg(OMAP3430_RST1_IVA2 | + OMAP3430_RST2_IVA2 | + OMAP3430_RST3_IVA2, + OMAP3430_IVA2_MOD, RM_RSTCTRL); + + /* Enable IVA2 clock */ + cm_write_mod_reg(OMAP3430_CM_FCLKEN_IVA2_EN_IVA2, + OMAP3430_IVA2_MOD, CM_FCLKEN); + + /* Set IVA2 boot mode to 'idle' */ + omap_ctrl_writel(OMAP3_IVA2_BOOTMOD_IDLE, + OMAP343X_CONTROL_IVA2_BOOTMOD); + + /* Un-reset IVA2 */ + prm_write_mod_reg(0, OMAP3430_IVA2_MOD, RM_RSTCTRL); + + /* Disable IVA2 clock */ + cm_write_mod_reg(0, OMAP3430_IVA2_MOD, CM_FCLKEN); + + /* Reset IVA2 */ + prm_write_mod_reg(OMAP3430_RST1_IVA2 | + OMAP3430_RST2_IVA2 | + OMAP3430_RST3_IVA2, + OMAP3430_IVA2_MOD, RM_RSTCTRL); +} + +static void __init omap3_d2d_idle(void) +{ + u16 mask, padconf; + + /* In a stand alone OMAP3430 where there is not a stacked + * modem for the D2D Idle Ack and D2D MStandby must be pulled + * high. S CONTROL_PADCONF_SAD2D_IDLEACK and + * CONTROL_PADCONF_SAD2D_MSTDBY to have a pull up. */ + mask = (1 << 4) | (1 << 3); /* pull-up, enabled */ + padconf = omap_ctrl_readw(OMAP3_PADCONF_SAD2D_MSTANDBY); + padconf |= mask; + omap_ctrl_writew(padconf, OMAP3_PADCONF_SAD2D_MSTANDBY); + + padconf = omap_ctrl_readw(OMAP3_PADCONF_SAD2D_IDLEACK); + padconf |= mask; + omap_ctrl_writew(padconf, OMAP3_PADCONF_SAD2D_IDLEACK); + + /* reset modem */ + prm_write_mod_reg(OMAP3430_RM_RSTCTRL_CORE_MODEM_SW_RSTPWRON | + OMAP3430_RM_RSTCTRL_CORE_MODEM_SW_RST, + CORE_MOD, RM_RSTCTRL); + prm_write_mod_reg(0, CORE_MOD, RM_RSTCTRL); +} + +static void __init prcm_setup_regs(void) +{ + /* XXX Reset all wkdeps. This should be done when initializing + * powerdomains */ + prm_write_mod_reg(0, OMAP3430_IVA2_MOD, PM_WKDEP); + prm_write_mod_reg(0, MPU_MOD, PM_WKDEP); + prm_write_mod_reg(0, OMAP3430_DSS_MOD, PM_WKDEP); + prm_write_mod_reg(0, OMAP3430_NEON_MOD, PM_WKDEP); + prm_write_mod_reg(0, OMAP3430_CAM_MOD, PM_WKDEP); + prm_write_mod_reg(0, OMAP3430_PER_MOD, PM_WKDEP); + if (omap_rev() > OMAP3430_REV_ES1_0) { + prm_write_mod_reg(0, OMAP3430ES2_SGX_MOD, PM_WKDEP); + prm_write_mod_reg(0, OMAP3430ES2_USBHOST_MOD, PM_WKDEP); + } else + prm_write_mod_reg(0, GFX_MOD, PM_WKDEP); + + /* + * Enable interface clock autoidle for all modules. + * Note that in the long run this should be done by clockfw + */ + cm_write_mod_reg( + OMAP3430_AUTO_MODEM | + OMAP3430ES2_AUTO_MMC3 | + OMAP3430ES2_AUTO_ICR | + OMAP3430_AUTO_AES2 | + OMAP3430_AUTO_SHA12 | + OMAP3430_AUTO_DES2 | + OMAP3430_AUTO_MMC2 | + OMAP3430_AUTO_MMC1 | + OMAP3430_AUTO_MSPRO | + OMAP3430_AUTO_HDQ | + OMAP3430_AUTO_MCSPI4 | + OMAP3430_AUTO_MCSPI3 | + OMAP3430_AUTO_MCSPI2 | + OMAP3430_AUTO_MCSPI1 | + OMAP3430_AUTO_I2C3 | + OMAP3430_AUTO_I2C2 | + OMAP3430_AUTO_I2C1 | + OMAP3430_AUTO_UART2 | + OMAP3430_AUTO_UART1 | + OMAP3430_AUTO_GPT11 | + OMAP3430_AUTO_GPT10 | + OMAP3430_AUTO_MCBSP5 | + OMAP3430_AUTO_MCBSP1 | + OMAP3430ES1_AUTO_FAC | /* This is es1 only */ + OMAP3430_AUTO_MAILBOXES | + OMAP3430_AUTO_OMAPCTRL | + OMAP3430ES1_AUTO_FSHOSTUSB | + OMAP3430_AUTO_HSOTGUSB | + OMAP3430_AUTO_SAD2D | + OMAP3430_AUTO_SSI, + CORE_MOD, CM_AUTOIDLE1); + + cm_write_mod_reg( + OMAP3430_AUTO_PKA | + OMAP3430_AUTO_AES1 | + OMAP3430_AUTO_RNG | + OMAP3430_AUTO_SHA11 | + OMAP3430_AUTO_DES1, + CORE_MOD, CM_AUTOIDLE2); + + if (omap_rev() > OMAP3430_REV_ES1_0) { + cm_write_mod_reg( + OMAP3430_AUTO_MAD2D | + OMAP3430ES2_AUTO_USBTLL, + CORE_MOD, CM_AUTOIDLE3); + } + + cm_write_mod_reg( + OMAP3430_AUTO_WDT2 | + OMAP3430_AUTO_WDT1 | + OMAP3430_AUTO_GPIO1 | + OMAP3430_AUTO_32KSYNC | + OMAP3430_AUTO_GPT12 | + OMAP3430_AUTO_GPT1 , + WKUP_MOD, CM_AUTOIDLE); + + cm_write_mod_reg( + OMAP3430_AUTO_DSS, + OMAP3430_DSS_MOD, + CM_AUTOIDLE); + + cm_write_mod_reg( + OMAP3430_AUTO_CAM, + OMAP3430_CAM_MOD, + CM_AUTOIDLE); + + cm_write_mod_reg( + OMAP3430_AUTO_GPIO6 | + OMAP3430_AUTO_GPIO5 | + OMAP3430_AUTO_GPIO4 | + OMAP3430_AUTO_GPIO3 | + OMAP3430_AUTO_GPIO2 | + OMAP3430_AUTO_WDT3 | + OMAP3430_AUTO_UART3 | + OMAP3430_AUTO_GPT9 | + OMAP3430_AUTO_GPT8 | + OMAP3430_AUTO_GPT7 | + OMAP3430_AUTO_GPT6 | + OMAP3430_AUTO_GPT5 | + OMAP3430_AUTO_GPT4 | + OMAP3430_AUTO_GPT3 | + OMAP3430_AUTO_GPT2 | + OMAP3430_AUTO_MCBSP4 | + OMAP3430_AUTO_MCBSP3 | + OMAP3430_AUTO_MCBSP2, + OMAP3430_PER_MOD, + CM_AUTOIDLE); + + if (omap_rev() > OMAP3430_REV_ES1_0) { + cm_write_mod_reg( + OMAP3430ES2_AUTO_USBHOST, + OMAP3430ES2_USBHOST_MOD, + CM_AUTOIDLE); + } + + /* + * Set all plls to autoidle. This is needed until autoidle is + * enabled by clockfw + */ + cm_write_mod_reg(1 << OMAP3430_AUTO_IVA2_DPLL_SHIFT, + OMAP3430_IVA2_MOD, CM_AUTOIDLE2); + cm_write_mod_reg(1 << OMAP3430_AUTO_MPU_DPLL_SHIFT, + MPU_MOD, + CM_AUTOIDLE2); + cm_write_mod_reg((1 << OMAP3430_AUTO_PERIPH_DPLL_SHIFT) | + (1 << OMAP3430_AUTO_CORE_DPLL_SHIFT), + PLL_MOD, + CM_AUTOIDLE); + cm_write_mod_reg(1 << OMAP3430ES2_AUTO_PERIPH2_DPLL_SHIFT, + PLL_MOD, + CM_AUTOIDLE2); + + /* + * Enable control of expternal oscillator through + * sys_clkreq. In the long run clock framework should + * take care of this. + */ + prm_rmw_mod_reg_bits(OMAP_AUTOEXTCLKMODE_MASK, + 1 << OMAP_AUTOEXTCLKMODE_SHIFT, + OMAP3430_GR_MOD, + OMAP3_PRM_CLKSRC_CTRL_OFFSET); + + /* setup wakup source */ + prm_write_mod_reg(OMAP3430_EN_IO | OMAP3430_EN_GPIO1 | + OMAP3430_EN_GPT1 | OMAP3430_EN_GPT12, + WKUP_MOD, PM_WKEN); + /* No need to write EN_IO, that is always enabled */ + prm_write_mod_reg(OMAP3430_EN_GPIO1 | OMAP3430_EN_GPT1 | + OMAP3430_EN_GPT12, + WKUP_MOD, OMAP3430_PM_MPUGRPSEL); + /* For some reason IO doesn't generate wakeup event even if + * it is selected to mpu wakeup goup */ + prm_write_mod_reg(OMAP3430_IO_EN | OMAP3430_WKUP_EN, + OCP_MOD, OMAP3_PRM_IRQENABLE_MPU_OFFSET); + + /* Don't attach IVA interrupts */ + prm_write_mod_reg(0, WKUP_MOD, OMAP3430_PM_IVAGRPSEL); + prm_write_mod_reg(0, CORE_MOD, OMAP3430_PM_IVAGRPSEL1); + prm_write_mod_reg(0, CORE_MOD, OMAP3430ES2_PM_IVAGRPSEL3); + prm_write_mod_reg(0, OMAP3430_PER_MOD, OMAP3430_PM_IVAGRPSEL); + + /* Clear any pending 'reset' flags */ + prm_write_mod_reg(0xffffffff, MPU_MOD, RM_RSTST); + prm_write_mod_reg(0xffffffff, CORE_MOD, RM_RSTST); + prm_write_mod_reg(0xffffffff, OMAP3430_PER_MOD, RM_RSTST); + prm_write_mod_reg(0xffffffff, OMAP3430_EMU_MOD, RM_RSTST); + prm_write_mod_reg(0xffffffff, OMAP3430_NEON_MOD, RM_RSTST); + prm_write_mod_reg(0xffffffff, OMAP3430_DSS_MOD, RM_RSTST); + prm_write_mod_reg(0xffffffff, OMAP3430ES2_USBHOST_MOD, RM_RSTST); + + /* Clear any pending PRCM interrupts */ + prm_write_mod_reg(0, OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET); + + omap3_iva_idle(); + omap3_d2d_idle(); +} + +static int __init pwrdms_setup(struct powerdomain *pwrdm) +{ + struct power_state *pwrst; + + if (!pwrdm->pwrsts) + return 0; + + pwrst = kmalloc(sizeof(struct power_state), GFP_KERNEL); + if (!pwrst) + return -ENOMEM; + pwrst->pwrdm = pwrdm; + pwrst->next_state = PWRDM_POWER_RET; + list_add(&pwrst->node, &pwrst_list); + + if (pwrdm_has_hdwr_sar(pwrdm)) + pwrdm_enable_hdwr_sar(pwrdm); + + return set_pwrdm_state(pwrst->pwrdm, pwrst->next_state); +} + +/* + * Enable hw supervised mode for all clockdomains if it's + * supported. Initiate sleep transition for other clockdomains, if + * they are not used + */ +static int __init clkdms_setup(struct clockdomain *clkdm) +{ + if (clkdm->flags & CLKDM_CAN_ENABLE_AUTO) + omap2_clkdm_allow_idle(clkdm); + else if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP && + atomic_read(&clkdm->usecount) == 0) + omap2_clkdm_sleep(clkdm); + return 0; +} + +int __init omap3_pm_init(void) +{ + struct power_state *pwrst, *tmp; + int ret; + + if (!cpu_is_omap34xx()) + return -ENODEV; + + printk(KERN_ERR "Power Management for TI OMAP3.\n"); + + /* XXX prcm_setup_regs needs to be before enabling hw + * supervised mode for powerdomains */ + prcm_setup_regs(); + + ret = request_irq(INT_34XX_PRCM_MPU_IRQ, + (irq_handler_t)prcm_interrupt_handler, + IRQF_DISABLED, "prcm", NULL); + if (ret) { + printk(KERN_ERR "request_irq failed to register for 0x%x\n", + INT_34XX_PRCM_MPU_IRQ); + goto err1; + } + + ret = pwrdm_for_each(pwrdms_setup); + if (ret) { + printk(KERN_ERR "Failed to setup powerdomains\n"); + goto err2; + } + + (void) clkdm_for_each(clkdms_setup); + + mpu_pwrdm = pwrdm_lookup("mpu_pwrdm"); + if (mpu_pwrdm == NULL) { + printk(KERN_ERR "Failed to get mpu_pwrdm\n"); + goto err2; + } + + _omap_sram_idle = omap_sram_push(omap34xx_cpu_suspend, + omap34xx_cpu_suspend_sz); + + suspend_set_ops(&omap_pm_ops); + + pm_idle = omap3_pm_idle; + +err1: + return ret; +err2: + free_irq(INT_34XX_PRCM_MPU_IRQ, NULL); + list_for_each_entry_safe(pwrst, tmp, &pwrst_list, node) { + list_del(&pwrst->node); + kfree(pwrst); + } + return ret; +} + +late_initcall(omap3_pm_init); diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index 73e2971b1757..983f1cb676be 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c @@ -1099,7 +1099,7 @@ int pwrdm_wait_transition(struct powerdomain *pwrdm) (c++ < PWRDM_TRANSITION_BAILOUT)) udelay(1); - if (c >= PWRDM_TRANSITION_BAILOUT) { + if (c > PWRDM_TRANSITION_BAILOUT) { printk(KERN_ERR "powerdomain: waited too long for " "powerdomain %s to complete transition\n", pwrdm->name); return -EAGAIN; diff --git a/arch/arm/mach-omap2/prcm-common.h b/arch/arm/mach-omap2/prcm-common.h index 812d50ee495d..cb1ae84e0925 100644 --- a/arch/arm/mach-omap2/prcm-common.h +++ b/arch/arm/mach-omap2/prcm-common.h @@ -276,6 +276,8 @@ /* CM_FCLKEN_WKUP, CM_ICLKEN_WKUP, PM_WKEN_WKUP shared bits */ #define OMAP3430_EN_GPIO1 (1 << 3) #define OMAP3430_EN_GPIO1_SHIFT 3 +#define OMAP3430_EN_GPT12 (1 << 1) +#define OMAP3430_EN_GPT12_SHIFT 1 #define OMAP3430_EN_GPT1 (1 << 0) #define OMAP3430_EN_GPT1_SHIFT 0 diff --git a/arch/arm/mach-omap2/prm.h b/arch/arm/mach-omap2/prm.h index 826d326b8062..9937e2814696 100644 --- a/arch/arm/mach-omap2/prm.h +++ b/arch/arm/mach-omap2/prm.h @@ -16,17 +16,12 @@ #include "prcm-common.h" -#ifndef __ASSEMBLER__ -#define OMAP_PRM_REGADDR(module, reg) \ - IO_ADDRESS(OMAP2_PRM_BASE + (module) + (reg)) -#else #define OMAP2420_PRM_REGADDR(module, reg) \ IO_ADDRESS(OMAP2420_PRM_BASE + (module) + (reg)) #define OMAP2430_PRM_REGADDR(module, reg) \ IO_ADDRESS(OMAP2430_PRM_BASE + (module) + (reg)) #define OMAP34XX_PRM_REGADDR(module, reg) \ IO_ADDRESS(OMAP3430_PRM_BASE + (module) + (reg)) -#endif /* * Architecture-specific global PRM registers @@ -38,80 +33,132 @@ * */ -/* Global 24xx registers in GR_MOD (Same as OCP_MOD for 24xx) */ -#define OMAP24XX_PRCM_VOLTCTRL_OFFSET 0x0050 -#define OMAP24XX_PRCM_CLKCFG_CTRL_OFFSET 0x0080 +#define OMAP2_PRCM_REVISION_OFFSET 0x0000 +#define OMAP2420_PRCM_REVISION OMAP2420_PRM_REGADDR(OCP_MOD, 0x0000) +#define OMAP2_PRCM_SYSCONFIG_OFFSET 0x0010 +#define OMAP2420_PRCM_SYSCONFIG OMAP2420_PRM_REGADDR(OCP_MOD, 0x0010) -/* 242x GR_MOD registers, use these only for assembly code */ -#define OMAP242X_PRCM_VOLTCTRL OMAP2420_PRM_REGADDR(OMAP24XX_GR_MOD, \ - OMAP24XX_PRCM_VOLTCTRL_OFFSET) -#define OMAP242X_PRCM_CLKCFG_CTRL OMAP2420_PRM_REGADDR(OMAP24XX_GR_MOD, \ - OMAP24XX_PRCM_CLKCFG_CTRL_OFFSET) +#define OMAP2_PRCM_IRQSTATUS_MPU_OFFSET 0x0018 +#define OMAP2420_PRCM_IRQSTATUS_MPU OMAP2420_PRM_REGADDR(OCP_MOD, 0x0018) +#define OMAP2_PRCM_IRQENABLE_MPU_OFFSET 0x001c +#define OMAP2420_PRCM_IRQENABLE_MPU OMAP2420_PRM_REGADDR(OCP_MOD, 0x001c) -/* 243x GR_MOD registers, use these only for assembly code */ -#define OMAP243X_PRCM_VOLTCTRL OMAP2430_PRM_REGADDR(OMAP24XX_GR_MOD, \ - OMAP24XX_PRCM_VOLTCTRL_OFFSET) -#define OMAP243X_PRCM_CLKCFG_CTRL OMAP2430_PRM_REGADDR(OMAP24XX_GR_MOD, \ - OMAP24XX_PRCM_CLKCFG_CTRL_OFFSET) +#define OMAP2_PRCM_VOLTCTRL_OFFSET 0x0050 +#define OMAP2420_PRCM_VOLTCTRL OMAP2420_PRM_REGADDR(OCP_MOD, 0x0050) +#define OMAP2_PRCM_VOLTST_OFFSET 0x0054 +#define OMAP2420_PRCM_VOLTST OMAP2420_PRM_REGADDR(OCP_MOD, 0x0054) +#define OMAP2_PRCM_CLKSRC_CTRL_OFFSET 0x0060 +#define OMAP2420_PRCM_CLKSRC_CTRL OMAP2420_PRM_REGADDR(OCP_MOD, 0x0060) +#define OMAP2_PRCM_CLKOUT_CTRL_OFFSET 0x0070 +#define OMAP2420_PRCM_CLKOUT_CTRL OMAP2420_PRM_REGADDR(OCP_MOD, 0x0070) +#define OMAP2_PRCM_CLKEMUL_CTRL_OFFSET 0x0078 +#define OMAP2420_PRCM_CLKEMUL_CTRL OMAP2420_PRM_REGADDR(OCP_MOD, 0x0078) +#define OMAP2_PRCM_CLKCFG_CTRL_OFFSET 0x0080 +#define OMAP2420_PRCM_CLKCFG_CTRL OMAP2420_PRM_REGADDR(OCP_MOD, 0x0080) +#define OMAP2_PRCM_CLKCFG_STATUS_OFFSET 0x0084 +#define OMAP2420_PRCM_CLKCFG_STATUS OMAP2420_PRM_REGADDR(OCP_MOD, 0x0084) +#define OMAP2_PRCM_VOLTSETUP_OFFSET 0x0090 +#define OMAP2420_PRCM_VOLTSETUP OMAP2420_PRM_REGADDR(OCP_MOD, 0x0090) +#define OMAP2_PRCM_CLKSSETUP_OFFSET 0x0094 +#define OMAP2420_PRCM_CLKSSETUP OMAP2420_PRM_REGADDR(OCP_MOD, 0x0094) +#define OMAP2_PRCM_POLCTRL_OFFSET 0x0098 +#define OMAP2420_PRCM_POLCTRL OMAP2420_PRM_REGADDR(OCP_MOD, 0x0098) -/* These will disappear */ -#define OMAP24XX_PRCM_REVISION OMAP_PRM_REGADDR(OCP_MOD, 0x0000) -#define OMAP24XX_PRCM_SYSCONFIG OMAP_PRM_REGADDR(OCP_MOD, 0x0010) +#define OMAP2430_PRCM_REVISION OMAP2430_PRM_REGADDR(OCP_MOD, 0x0000) +#define OMAP2430_PRCM_SYSCONFIG OMAP2430_PRM_REGADDR(OCP_MOD, 0x0010) -#define OMAP24XX_PRCM_IRQSTATUS_MPU OMAP_PRM_REGADDR(OCP_MOD, 0x0018) -#define OMAP24XX_PRCM_IRQENABLE_MPU OMAP_PRM_REGADDR(OCP_MOD, 0x001c) +#define OMAP2430_PRCM_IRQSTATUS_MPU OMAP2430_PRM_REGADDR(OCP_MOD, 0x0018) +#define OMAP2430_PRCM_IRQENABLE_MPU OMAP2430_PRM_REGADDR(OCP_MOD, 0x001c) -#define OMAP24XX_PRCM_VOLTST OMAP_PRM_REGADDR(OCP_MOD, 0x0054) -#define OMAP24XX_PRCM_CLKSRC_CTRL OMAP_PRM_REGADDR(OCP_MOD, 0x0060) -#define OMAP24XX_PRCM_CLKOUT_CTRL OMAP_PRM_REGADDR(OCP_MOD, 0x0070) -#define OMAP24XX_PRCM_CLKEMUL_CTRL OMAP_PRM_REGADDR(OCP_MOD, 0x0078) -#define OMAP24XX_PRCM_CLKCFG_CTRL OMAP_PRM_REGADDR(OCP_MOD, 0x0080) -#define OMAP24XX_PRCM_CLKCFG_STATUS OMAP_PRM_REGADDR(OCP_MOD, 0x0084) -#define OMAP24XX_PRCM_VOLTSETUP OMAP_PRM_REGADDR(OCP_MOD, 0x0090) -#define OMAP24XX_PRCM_CLKSSETUP OMAP_PRM_REGADDR(OCP_MOD, 0x0094) -#define OMAP24XX_PRCM_POLCTRL OMAP_PRM_REGADDR(OCP_MOD, 0x0098) +#define OMAP2430_PRCM_VOLTCTRL OMAP2430_PRM_REGADDR(OCP_MOD, 0x0050) +#define OMAP2430_PRCM_VOLTST OMAP2430_PRM_REGADDR(OCP_MOD, 0x0054) +#define OMAP2430_PRCM_CLKSRC_CTRL OMAP2430_PRM_REGADDR(OCP_MOD, 0x0060) +#define OMAP2430_PRCM_CLKOUT_CTRL OMAP2430_PRM_REGADDR(OCP_MOD, 0x0070) +#define OMAP2430_PRCM_CLKEMUL_CTRL OMAP2430_PRM_REGADDR(OCP_MOD, 0x0078) +#define OMAP2430_PRCM_CLKCFG_CTRL OMAP2430_PRM_REGADDR(OCP_MOD, 0x0080) +#define OMAP2430_PRCM_CLKCFG_STATUS OMAP2430_PRM_REGADDR(OCP_MOD, 0x0084) +#define OMAP2430_PRCM_VOLTSETUP OMAP2430_PRM_REGADDR(OCP_MOD, 0x0090) +#define OMAP2430_PRCM_CLKSSETUP OMAP2430_PRM_REGADDR(OCP_MOD, 0x0094) +#define OMAP2430_PRCM_POLCTRL OMAP2430_PRM_REGADDR(OCP_MOD, 0x0098) -#define OMAP3430_PRM_REVISION OMAP_PRM_REGADDR(OCP_MOD, 0x0004) -#define OMAP3430_PRM_SYSCONFIG OMAP_PRM_REGADDR(OCP_MOD, 0x0014) +#define OMAP3_PRM_REVISION_OFFSET 0x0004 +#define OMAP3430_PRM_REVISION OMAP34XX_PRM_REGADDR(OCP_MOD, 0x0004) +#define OMAP3_PRM_SYSCONFIG_OFFSET 0x0014 +#define OMAP3430_PRM_SYSCONFIG OMAP34XX_PRM_REGADDR(OCP_MOD, 0x0014) -#define OMAP3430_PRM_IRQSTATUS_MPU OMAP_PRM_REGADDR(OCP_MOD, 0x0018) -#define OMAP3430_PRM_IRQENABLE_MPU OMAP_PRM_REGADDR(OCP_MOD, 0x001c) +#define OMAP3_PRM_IRQSTATUS_MPU_OFFSET 0x0018 +#define OMAP3430_PRM_IRQSTATUS_MPU OMAP34XX_PRM_REGADDR(OCP_MOD, 0x0018) +#define OMAP3_PRM_IRQENABLE_MPU_OFFSET 0x001c +#define OMAP3430_PRM_IRQENABLE_MPU OMAP34XX_PRM_REGADDR(OCP_MOD, 0x001c) -#define OMAP3430_PRM_VC_SMPS_SA OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0020) -#define OMAP3430_PRM_VC_SMPS_VOL_RA OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0024) -#define OMAP3430_PRM_VC_SMPS_CMD_RA OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0028) -#define OMAP3430_PRM_VC_CMD_VAL_0 OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x002c) -#define OMAP3430_PRM_VC_CMD_VAL_1 OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0030) -#define OMAP3430_PRM_VC_CH_CONF OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0034) -#define OMAP3430_PRM_VC_I2C_CFG OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0038) -#define OMAP3430_PRM_VC_BYPASS_VAL OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x003c) -#define OMAP3430_PRM_RSTCTRL OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0050) -#define OMAP3430_PRM_RSTTIME OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0054) -#define OMAP3430_PRM_RSTST OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0058) -#define OMAP3430_PRM_VOLTCTRL OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0060) -#define OMAP3430_PRM_SRAM_PCHARGE OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0064) -#define OMAP3430_PRM_CLKSRC_CTRL OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0070) -#define OMAP3430_PRM_VOLTSETUP1 OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0090) -#define OMAP3430_PRM_VOLTOFFSET OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0094) -#define OMAP3430_PRM_CLKSETUP OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0098) -#define OMAP3430_PRM_POLCTRL OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x009c) -#define OMAP3430_PRM_VOLTSETUP2 OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00a0) -#define OMAP3430_PRM_VP1_CONFIG OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00b0) -#define OMAP3430_PRM_VP1_VSTEPMIN OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00b4) -#define OMAP3430_PRM_VP1_VSTEPMAX OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00b8) -#define OMAP3430_PRM_VP1_VLIMITTO OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00bc) -#define OMAP3430_PRM_VP1_VOLTAGE OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00c0) -#define OMAP3430_PRM_VP1_STATUS OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00c4) -#define OMAP3430_PRM_VP2_CONFIG OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00d0) -#define OMAP3430_PRM_VP2_VSTEPMIN OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00d4) -#define OMAP3430_PRM_VP2_VSTEPMAX OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00d8) -#define OMAP3430_PRM_VP2_VLIMITTO OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00dc) -#define OMAP3430_PRM_VP2_VOLTAGE OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00e0) -#define OMAP3430_PRM_VP2_STATUS OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00e4) +#define OMAP3_PRM_VC_SMPS_SA_OFFSET 0x0020 +#define OMAP3430_PRM_VC_SMPS_SA OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0020) +#define OMAP3_PRM_VC_SMPS_VOL_RA_OFFSET 0x0024 +#define OMAP3430_PRM_VC_SMPS_VOL_RA OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0024) +#define OMAP3_PRM_VC_SMPS_CMD_RA_OFFSET 0x0028 +#define OMAP3430_PRM_VC_SMPS_CMD_RA OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0028) +#define OMAP3_PRM_VC_CMD_VAL_0_OFFSET 0x002c +#define OMAP3430_PRM_VC_CMD_VAL_0 OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x002c) +#define OMAP3_PRM_VC_CMD_VAL_1_OFFSET 0x0030 +#define OMAP3430_PRM_VC_CMD_VAL_1 OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0030) +#define OMAP3_PRM_VC_CH_CONF_OFFSET 0x0034 +#define OMAP3430_PRM_VC_CH_CONF OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0034) +#define OMAP3_PRM_VC_I2C_CFG_OFFSET 0x0038 +#define OMAP3430_PRM_VC_I2C_CFG OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0038) +#define OMAP3_PRM_VC_BYPASS_VAL_OFFSET 0x003c +#define OMAP3430_PRM_VC_BYPASS_VAL OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x003c) +#define OMAP3_PRM_RSTCTRL_OFFSET 0x0050 +#define OMAP3430_PRM_RSTCTRL OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0050) +#define OMAP3_PRM_RSTTIME_OFFSET 0x0054 +#define OMAP3430_PRM_RSTTIME OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0054) +#define OMAP3_PRM_RSTST_OFFSET 0x0058 +#define OMAP3430_PRM_RSTST OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0058) +#define OMAP3_PRM_VOLTCTRL_OFFSET 0x0060 +#define OMAP3430_PRM_VOLTCTRL OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0060) +#define OMAP3_PRM_SRAM_PCHARGE_OFFSET 0x0064 +#define OMAP3430_PRM_SRAM_PCHARGE OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0064) +#define OMAP3_PRM_CLKSRC_CTRL_OFFSET 0x0070 +#define OMAP3430_PRM_CLKSRC_CTRL OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0070) +#define OMAP3_PRM_VOLTSETUP1_OFFSET 0x0090 +#define OMAP3430_PRM_VOLTSETUP1 OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0090) +#define OMAP3_PRM_VOLTOFFSET_OFFSET 0x0094 +#define OMAP3430_PRM_VOLTOFFSET OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0094) +#define OMAP3_PRM_CLKSETUP_OFFSET 0x0098 +#define OMAP3430_PRM_CLKSETUP OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0098) +#define OMAP3_PRM_POLCTRL_OFFSET 0x009c +#define OMAP3430_PRM_POLCTRL OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x009c) +#define OMAP3_PRM_VOLTSETUP2_OFFSET 0x00a0 +#define OMAP3430_PRM_VOLTSETUP2 OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00a0) +#define OMAP3_PRM_VP1_CONFIG_OFFSET 0x00b0 +#define OMAP3430_PRM_VP1_CONFIG OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00b0) +#define OMAP3_PRM_VP1_VSTEPMIN_OFFSET 0x00b4 +#define OMAP3430_PRM_VP1_VSTEPMIN OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00b4) +#define OMAP3_PRM_VP1_VSTEPMAX_OFFSET 0x00b8 +#define OMAP3430_PRM_VP1_VSTEPMAX OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00b8) +#define OMAP3_PRM_VP1_VLIMITTO_OFFSET 0x00bc +#define OMAP3430_PRM_VP1_VLIMITTO OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00bc) +#define OMAP3_PRM_VP1_VOLTAGE_OFFSET 0x00c0 +#define OMAP3430_PRM_VP1_VOLTAGE OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00c0) +#define OMAP3_PRM_VP1_STATUS_OFFSET 0x00c4 +#define OMAP3430_PRM_VP1_STATUS OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00c4) +#define OMAP3_PRM_VP2_CONFIG_OFFSET 0x00d0 +#define OMAP3430_PRM_VP2_CONFIG OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00d0) +#define OMAP3_PRM_VP2_VSTEPMIN_OFFSET 0x00d4 +#define OMAP3430_PRM_VP2_VSTEPMIN OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00d4) +#define OMAP3_PRM_VP2_VSTEPMAX_OFFSET 0x00d8 +#define OMAP3430_PRM_VP2_VSTEPMAX OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00d8) +#define OMAP3_PRM_VP2_VLIMITTO_OFFSET 0x00dc +#define OMAP3430_PRM_VP2_VLIMITTO OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00dc) +#define OMAP3_PRM_VP2_VOLTAGE_OFFSET 0x00e0 +#define OMAP3430_PRM_VP2_VOLTAGE OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00e0) +#define OMAP3_PRM_VP2_STATUS_OFFSET 0x00e4 +#define OMAP3430_PRM_VP2_STATUS OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00e4) -#define OMAP3430_PRM_CLKSEL OMAP_PRM_REGADDR(OMAP3430_CCR_MOD, 0x0040) -#define OMAP3430_PRM_CLKOUT_CTRL OMAP_PRM_REGADDR(OMAP3430_CCR_MOD, 0x0070) +#define OMAP3_PRM_CLKSEL_OFFSET 0x0040 +#define OMAP3430_PRM_CLKSEL OMAP34XX_PRM_REGADDR(OMAP3430_CCR_MOD, 0x0040) +#define OMAP3_PRM_CLKOUT_CTRL_OFFSET 0x0070 +#define OMAP3430_PRM_CLKOUT_CTRL OMAP34XX_PRM_REGADDR(OMAP3430_CCR_MOD, 0x0070) /* * Module specific PRM registers from PRM_BASE + domain offset @@ -156,9 +203,11 @@ #define OMAP3430_PM_MPUGRPSEL 0x00a4 #define OMAP3430_PM_MPUGRPSEL1 OMAP3430_PM_MPUGRPSEL +#define OMAP3430ES2_PM_MPUGRPSEL3 0x00f8 #define OMAP3430_PM_IVAGRPSEL 0x00a8 #define OMAP3430_PM_IVAGRPSEL1 OMAP3430_PM_IVAGRPSEL +#define OMAP3430ES2_PM_IVAGRPSEL3 0x00f4 #define OMAP3430_PM_PREPWSTST 0x00e8 diff --git a/arch/arm/mach-omap2/sdram-micron-mt46h32m32lf-6.h b/arch/arm/mach-omap2/sdram-micron-mt46h32m32lf-6.h new file mode 100644 index 000000000000..02e1c2d4705f --- /dev/null +++ b/arch/arm/mach-omap2/sdram-micron-mt46h32m32lf-6.h @@ -0,0 +1,55 @@ +/* + * SDRC register values for the Micron MT46H32M32LF-6 + * + * Copyright (C) 2008 Texas Instruments, Inc. + * Copyright (C) 2008-2009 Nokia Corporation + * + * Paul Walmsley + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef ARCH_ARM_MACH_OMAP2_SDRAM_MICRON_MT46H32M32LF +#define ARCH_ARM_MACH_OMAP2_SDRAM_MICRON_MT46H32M32LF + +#include + +/* Micron MT46H32M32LF-6 */ +/* XXX Using ARE = 0x1 (no autorefresh burst) -- can this be changed? */ +static struct omap_sdrc_params mt46h32m32lf6_sdrc_params[] = { + [0] = { + .rate = 166000000, + .actim_ctrla = 0x9a9db4c6, + .actim_ctrlb = 0x00011217, + .rfr_ctrl = 0x0004dc01, + .mr = 0x00000032, + }, + [1] = { + .rate = 165941176, + .actim_ctrla = 0x9a9db4c6, + .actim_ctrlb = 0x00011217, + .rfr_ctrl = 0x0004dc01, + .mr = 0x00000032, + }, + [2] = { + .rate = 83000000, + .actim_ctrla = 0x51512283, + .actim_ctrlb = 0x0001120c, + .rfr_ctrl = 0x00025501, + .mr = 0x00000032, + }, + [3] = { + .rate = 82970588, + .actim_ctrla = 0x51512283, + .actim_ctrlb = 0x0001120c, + .rfr_ctrl = 0x00025501, + .mr = 0x00000032, + }, + [4] = { + .rate = 0 + }, +}; + +#endif diff --git a/arch/arm/mach-omap2/sdram-qimonda-hyb18m512160af-6.h b/arch/arm/mach-omap2/sdram-qimonda-hyb18m512160af-6.h new file mode 100644 index 000000000000..3751d293cb1f --- /dev/null +++ b/arch/arm/mach-omap2/sdram-qimonda-hyb18m512160af-6.h @@ -0,0 +1,54 @@ +/* + * SDRC register values for the Qimonda HYB18M512160AF-6 + * + * Copyright (C) 2008-2009 Texas Instruments, Inc. + * Copyright (C) 2008-2009 Nokia Corporation + * + * Paul Walmsley + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef ARCH_ARM_MACH_OMAP2_SDRAM_QIMONDA_HYB18M512160AF6 +#define ARCH_ARM_MACH_OMAP2_SDRAM_QIMONDA_HYB18M512160AF6 + +#include + +/* Qimonda HYB18M512160AF-6 */ +static struct omap_sdrc_params hyb18m512160af6_sdrc_params[] = { + [0] = { + .rate = 166000000, + .actim_ctrla = 0x629db4c6, + .actim_ctrlb = 0x00012214, + .rfr_ctrl = 0x0004dc01, + .mr = 0x00000032, + }, + [1] = { + .rate = 165941176, + .actim_ctrla = 0x629db4c6, + .actim_ctrlb = 0x00012214, + .rfr_ctrl = 0x0004dc01, + .mr = 0x00000032, + }, + [2] = { + .rate = 83000000, + .actim_ctrla = 0x31512283, + .actim_ctrlb = 0x0001220a, + .rfr_ctrl = 0x00025501, + .mr = 0x00000022, + }, + [3] = { + .rate = 82970588, + .actim_ctrla = 0x31512283, + .actim_ctrlb = 0x0001220a, + .rfr_ctrl = 0x00025501, + .mr = 0x00000022, + }, + [4] = { + .rate = 0 + }, +}; + +#endif diff --git a/arch/arm/mach-omap2/sdrc.c b/arch/arm/mach-omap2/sdrc.c index 2a30060cb4b7..2045441e8385 100644 --- a/arch/arm/mach-omap2/sdrc.c +++ b/arch/arm/mach-omap2/sdrc.c @@ -37,6 +37,10 @@ static struct omap_sdrc_params *sdrc_init_params; void __iomem *omap2_sdrc_base; void __iomem *omap2_sms_base; +/* SDRC_POWER register bits */ +#define SDRC_POWER_EXTCLKDIS_SHIFT 3 +#define SDRC_POWER_PWDENA_SHIFT 2 +#define SDRC_POWER_PAGEPOLICY_SHIFT 0 /** * omap2_sdrc_get_params - return SDRC register values for a given clock rate @@ -56,9 +60,12 @@ struct omap_sdrc_params *omap2_sdrc_get_params(unsigned long r) { struct omap_sdrc_params *sp; + if (!sdrc_init_params) + return NULL; + sp = sdrc_init_params; - while (sp->rate != r) + while (sp->rate && sp->rate != r) sp++; if (!sp->rate) @@ -74,7 +81,14 @@ void __init omap2_set_globals_sdrc(struct omap_globals *omap2_globals) omap2_sms_base = omap2_globals->sms; } -/* turn on smart idle modes for SDRAM scheduler and controller */ +/** + * omap2_sdrc_init - initialize SMS, SDRC devices on boot + * @sp: pointer to a null-terminated list of struct omap_sdrc_params + * + * Turn on smart idle modes for SDRAM scheduler and controller. + * Program a known-good configuration for the SDRC to deal with buggy + * bootloaders. + */ void __init omap2_sdrc_init(struct omap_sdrc_params *sp) { u32 l; @@ -90,4 +104,10 @@ void __init omap2_sdrc_init(struct omap_sdrc_params *sp) sdrc_write_reg(l, SDRC_SYSCONFIG); sdrc_init_params = sp; + + /* XXX Enable SRFRONIDLEREQ here also? */ + l = (1 << SDRC_POWER_EXTCLKDIS_SHIFT) | + (1 << SDRC_POWER_PWDENA_SHIFT) | + (1 << SDRC_POWER_PAGEPOLICY_SHIFT); + sdrc_write_reg(l, SDRC_POWER); } diff --git a/arch/arm/mach-omap2/sdrc2xxx.c b/arch/arm/mach-omap2/sdrc2xxx.c index 0afdad5ae9fb..feaec7eaf6bd 100644 --- a/arch/arm/mach-omap2/sdrc2xxx.c +++ b/arch/arm/mach-omap2/sdrc2xxx.c @@ -99,7 +99,10 @@ u32 omap2xxx_sdrc_reprogram(u32 level, u32 force) m_type = omap2xxx_sdrc_get_type(); local_irq_save(flags); - __raw_writel(0xffff, OMAP24XX_PRCM_VOLTSETUP); + if (cpu_is_omap2420()) + __raw_writel(0xffff, OMAP2420_PRCM_VOLTSETUP); + else + __raw_writel(0xffff, OMAP2430_PRCM_VOLTSETUP); omap2_sram_reprogram_sdrc(level, dll_ctrl, m_type); curr_perf_level = level; local_irq_restore(flags); diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c index 4dcf39c285b9..b094c15bfe47 100644 --- a/arch/arm/mach-omap2/serial.c +++ b/arch/arm/mach-omap2/serial.c @@ -6,8 +6,13 @@ * Copyright (C) 2005-2008 Nokia Corporation * Author: Paul Mundt * + * Major rework for PM support by Kevin Hilman + * * Based off of arch/arm/mach-omap/omap1/serial.c * + * Copyright (C) 2009 Texas Instruments + * Added OMAP4 support - Santosh Shilimkar #include +#include +#include -static struct clk *uart_ick[OMAP_MAX_NR_PORTS]; -static struct clk *uart_fck[OMAP_MAX_NR_PORTS]; +#include "prm.h" +#include "pm.h" +#include "prm-regbits-34xx.h" + +#define UART_OMAP_WER 0x17 /* Wake-up enable register */ + +#define DEFAULT_TIMEOUT (5 * HZ) + +struct omap_uart_state { + int num; + int can_sleep; + struct timer_list timer; + u32 timeout; + + void __iomem *wk_st; + void __iomem *wk_en; + u32 wk_mask; + u32 padconf; + + struct clk *ick; + struct clk *fck; + int clocked; + + struct plat_serial8250_port *p; + struct list_head node; + +#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM) + int context_valid; + + /* Registers to be saved/restored for OFF-mode */ + u16 dll; + u16 dlh; + u16 ier; + u16 sysc; + u16 scr; + u16 wer; +#endif +}; + +static struct omap_uart_state omap_uart[OMAP_MAX_NR_PORTS]; +static LIST_HEAD(uart_list); static struct plat_serial8250_port serial_platform_data[] = { { @@ -74,33 +120,369 @@ static inline void serial_write_reg(struct plat_serial8250_port *p, int offset, * properly. Note that the TX watermark initialization may not be needed * once the 8250.c watermark handling code is merged. */ -static inline void __init omap_serial_reset(struct plat_serial8250_port *p) +static inline void __init omap_uart_reset(struct omap_uart_state *uart) { + struct plat_serial8250_port *p = uart->p; + serial_write_reg(p, UART_OMAP_MDR1, 0x07); serial_write_reg(p, UART_OMAP_SCR, 0x08); serial_write_reg(p, UART_OMAP_MDR1, 0x00); serial_write_reg(p, UART_OMAP_SYSC, (0x02 << 3) | (1 << 2) | (1 << 0)); } -void omap_serial_enable_clocks(int enable) +#if defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP3) + +static int enable_off_mode; /* to be removed by full off-mode patches */ + +static void omap_uart_save_context(struct omap_uart_state *uart) { - int i; - for (i = 0; i < OMAP_MAX_NR_PORTS; i++) { - if (uart_ick[i] && uart_fck[i]) { - if (enable) { - clk_enable(uart_ick[i]); - clk_enable(uart_fck[i]); - } else { - clk_disable(uart_ick[i]); - clk_disable(uart_fck[i]); - } + u16 lcr = 0; + struct plat_serial8250_port *p = uart->p; + + if (!enable_off_mode) + return; + + lcr = serial_read_reg(p, UART_LCR); + serial_write_reg(p, UART_LCR, 0xBF); + uart->dll = serial_read_reg(p, UART_DLL); + uart->dlh = serial_read_reg(p, UART_DLM); + serial_write_reg(p, UART_LCR, lcr); + uart->ier = serial_read_reg(p, UART_IER); + uart->sysc = serial_read_reg(p, UART_OMAP_SYSC); + uart->scr = serial_read_reg(p, UART_OMAP_SCR); + uart->wer = serial_read_reg(p, UART_OMAP_WER); + + uart->context_valid = 1; +} + +static void omap_uart_restore_context(struct omap_uart_state *uart) +{ + u16 efr = 0; + struct plat_serial8250_port *p = uart->p; + + if (!enable_off_mode) + return; + + if (!uart->context_valid) + return; + + uart->context_valid = 0; + + serial_write_reg(p, UART_OMAP_MDR1, 0x7); + serial_write_reg(p, UART_LCR, 0xBF); /* Config B mode */ + efr = serial_read_reg(p, UART_EFR); + serial_write_reg(p, UART_EFR, UART_EFR_ECB); + serial_write_reg(p, UART_LCR, 0x0); /* Operational mode */ + serial_write_reg(p, UART_IER, 0x0); + serial_write_reg(p, UART_LCR, 0xBF); /* Config B mode */ + serial_write_reg(p, UART_DLL, uart->dll); + serial_write_reg(p, UART_DLM, uart->dlh); + serial_write_reg(p, UART_LCR, 0x0); /* Operational mode */ + serial_write_reg(p, UART_IER, uart->ier); + serial_write_reg(p, UART_FCR, 0xA1); + serial_write_reg(p, UART_LCR, 0xBF); /* Config B mode */ + serial_write_reg(p, UART_EFR, efr); + serial_write_reg(p, UART_LCR, UART_LCR_WLEN8); + serial_write_reg(p, UART_OMAP_SCR, uart->scr); + serial_write_reg(p, UART_OMAP_WER, uart->wer); + serial_write_reg(p, UART_OMAP_SYSC, uart->sysc); + serial_write_reg(p, UART_OMAP_MDR1, 0x00); /* UART 16x mode */ +} +#else +static inline void omap_uart_save_context(struct omap_uart_state *uart) {} +static inline void omap_uart_restore_context(struct omap_uart_state *uart) {} +#endif /* CONFIG_PM && CONFIG_ARCH_OMAP3 */ + +static inline void omap_uart_enable_clocks(struct omap_uart_state *uart) +{ + if (uart->clocked) + return; + + clk_enable(uart->ick); + clk_enable(uart->fck); + uart->clocked = 1; + omap_uart_restore_context(uart); +} + +#ifdef CONFIG_PM + +static inline void omap_uart_disable_clocks(struct omap_uart_state *uart) +{ + if (!uart->clocked) + return; + + omap_uart_save_context(uart); + uart->clocked = 0; + clk_disable(uart->ick); + clk_disable(uart->fck); +} + +static void omap_uart_smart_idle_enable(struct omap_uart_state *uart, + int enable) +{ + struct plat_serial8250_port *p = uart->p; + u16 sysc; + + sysc = serial_read_reg(p, UART_OMAP_SYSC) & 0x7; + if (enable) + sysc |= 0x2 << 3; + else + sysc |= 0x1 << 3; + + serial_write_reg(p, UART_OMAP_SYSC, sysc); +} + +static void omap_uart_block_sleep(struct omap_uart_state *uart) +{ + omap_uart_enable_clocks(uart); + + omap_uart_smart_idle_enable(uart, 0); + uart->can_sleep = 0; + if (uart->timeout) + mod_timer(&uart->timer, jiffies + uart->timeout); + else + del_timer(&uart->timer); +} + +static void omap_uart_allow_sleep(struct omap_uart_state *uart) +{ + if (!uart->clocked) + return; + + omap_uart_smart_idle_enable(uart, 1); + uart->can_sleep = 1; + del_timer(&uart->timer); +} + +static void omap_uart_idle_timer(unsigned long data) +{ + struct omap_uart_state *uart = (struct omap_uart_state *)data; + + omap_uart_allow_sleep(uart); +} + +void omap_uart_prepare_idle(int num) +{ + struct omap_uart_state *uart; + + list_for_each_entry(uart, &uart_list, node) { + if (num == uart->num && uart->can_sleep) { + omap_uart_disable_clocks(uart); + return; } } } +void omap_uart_resume_idle(int num) +{ + struct omap_uart_state *uart; + + list_for_each_entry(uart, &uart_list, node) { + if (num == uart->num) { + omap_uart_enable_clocks(uart); + + /* Check for IO pad wakeup */ + if (cpu_is_omap34xx() && uart->padconf) { + u16 p = omap_ctrl_readw(uart->padconf); + + if (p & OMAP3_PADCONF_WAKEUPEVENT0) + omap_uart_block_sleep(uart); + } + + /* Check for normal UART wakeup */ + if (__raw_readl(uart->wk_st) & uart->wk_mask) + omap_uart_block_sleep(uart); + + return; + } + } +} + +void omap_uart_prepare_suspend(void) +{ + struct omap_uart_state *uart; + + list_for_each_entry(uart, &uart_list, node) { + omap_uart_allow_sleep(uart); + } +} + +int omap_uart_can_sleep(void) +{ + struct omap_uart_state *uart; + int can_sleep = 1; + + list_for_each_entry(uart, &uart_list, node) { + if (!uart->clocked) + continue; + + if (!uart->can_sleep) { + can_sleep = 0; + continue; + } + + /* This UART can now safely sleep. */ + omap_uart_allow_sleep(uart); + } + + return can_sleep; +} + +/** + * omap_uart_interrupt() + * + * This handler is used only to detect that *any* UART interrupt has + * occurred. It does _nothing_ to handle the interrupt. Rather, + * any UART interrupt will trigger the inactivity timer so the + * UART will not idle or sleep for its timeout period. + * + **/ +static irqreturn_t omap_uart_interrupt(int irq, void *dev_id) +{ + struct omap_uart_state *uart = dev_id; + + omap_uart_block_sleep(uart); + + return IRQ_NONE; +} + +static u32 sleep_timeout = DEFAULT_TIMEOUT; + +static void omap_uart_idle_init(struct omap_uart_state *uart) +{ + u32 v; + struct plat_serial8250_port *p = uart->p; + int ret; + + uart->can_sleep = 0; + uart->timeout = sleep_timeout; + setup_timer(&uart->timer, omap_uart_idle_timer, + (unsigned long) uart); + mod_timer(&uart->timer, jiffies + uart->timeout); + omap_uart_smart_idle_enable(uart, 0); + + if (cpu_is_omap34xx()) { + u32 mod = (uart->num == 2) ? OMAP3430_PER_MOD : CORE_MOD; + u32 wk_mask = 0; + u32 padconf = 0; + + uart->wk_en = OMAP34XX_PRM_REGADDR(mod, PM_WKEN1); + uart->wk_st = OMAP34XX_PRM_REGADDR(mod, PM_WKST1); + switch (uart->num) { + case 0: + wk_mask = OMAP3430_ST_UART1_MASK; + padconf = 0x182; + break; + case 1: + wk_mask = OMAP3430_ST_UART2_MASK; + padconf = 0x17a; + break; + case 2: + wk_mask = OMAP3430_ST_UART3_MASK; + padconf = 0x19e; + break; + } + uart->wk_mask = wk_mask; + uart->padconf = padconf; + } else if (cpu_is_omap24xx()) { + u32 wk_mask = 0; + + if (cpu_is_omap2430()) { + uart->wk_en = OMAP2430_PRM_REGADDR(CORE_MOD, PM_WKEN1); + uart->wk_st = OMAP2430_PRM_REGADDR(CORE_MOD, PM_WKST1); + } else if (cpu_is_omap2420()) { + uart->wk_en = OMAP2420_PRM_REGADDR(CORE_MOD, PM_WKEN1); + uart->wk_st = OMAP2420_PRM_REGADDR(CORE_MOD, PM_WKST1); + } + switch (uart->num) { + case 0: + wk_mask = OMAP24XX_ST_UART1_MASK; + break; + case 1: + wk_mask = OMAP24XX_ST_UART2_MASK; + break; + case 2: + wk_mask = OMAP24XX_ST_UART3_MASK; + break; + } + uart->wk_mask = wk_mask; + } else { + uart->wk_en = 0; + uart->wk_st = 0; + uart->wk_mask = 0; + uart->padconf = 0; + } + + /* Set wake-enable bit */ + if (uart->wk_en && uart->wk_mask) { + v = __raw_readl(uart->wk_en); + v |= uart->wk_mask; + __raw_writel(v, uart->wk_en); + } + + /* Ensure IOPAD wake-enables are set */ + if (cpu_is_omap34xx() && uart->padconf) { + u16 v; + + v = omap_ctrl_readw(uart->padconf); + v |= OMAP3_PADCONF_WAKEUPENABLE0; + omap_ctrl_writew(v, uart->padconf); + } + + p->flags |= UPF_SHARE_IRQ; + ret = request_irq(p->irq, omap_uart_interrupt, IRQF_SHARED, + "serial idle", (void *)uart); + WARN_ON(ret); +} + +static ssize_t sleep_timeout_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + return sprintf(buf, "%u\n", sleep_timeout / HZ); +} + +static ssize_t sleep_timeout_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t n) +{ + struct omap_uart_state *uart; + unsigned int value; + + if (sscanf(buf, "%u", &value) != 1) { + printk(KERN_ERR "sleep_timeout_store: Invalid value\n"); + return -EINVAL; + } + sleep_timeout = value * HZ; + list_for_each_entry(uart, &uart_list, node) { + uart->timeout = sleep_timeout; + if (uart->timeout) + mod_timer(&uart->timer, jiffies + uart->timeout); + else + /* A zero value means disable timeout feature */ + omap_uart_block_sleep(uart); + } + return n; +} + +static struct kobj_attribute sleep_timeout_attr = + __ATTR(sleep_timeout, 0644, sleep_timeout_show, sleep_timeout_store); + +#else +static inline void omap_uart_idle_init(struct omap_uart_state *uart) {} +#endif /* CONFIG_PM */ + +static struct platform_device serial_device = { + .name = "serial8250", + .id = PLAT8250_DEV_PLATFORM, + .dev = { + .platform_data = serial_platform_data, + }, +}; + void __init omap_serial_init(void) { - int i; + int i, err; const struct omap_uart_config *info; char name[16]; @@ -114,9 +496,14 @@ void __init omap_serial_init(void) if (info == NULL) return; + if (cpu_is_omap44xx()) { + for (i = 0; i < OMAP_MAX_NR_PORTS; i++) + serial_platform_data[i].irq += 32; + } for (i = 0; i < OMAP_MAX_NR_PORTS; i++) { struct plat_serial8250_port *p = serial_platform_data + i; + struct omap_uart_state *uart = &omap_uart[i]; if (!(info->enabled_uarts & (1 << i))) { p->membase = NULL; @@ -125,35 +512,39 @@ void __init omap_serial_init(void) } sprintf(name, "uart%d_ick", i+1); - uart_ick[i] = clk_get(NULL, name); - if (IS_ERR(uart_ick[i])) { + uart->ick = clk_get(NULL, name); + if (IS_ERR(uart->ick)) { printk(KERN_ERR "Could not get uart%d_ick\n", i+1); - uart_ick[i] = NULL; - } else - clk_enable(uart_ick[i]); + uart->ick = NULL; + } sprintf(name, "uart%d_fck", i+1); - uart_fck[i] = clk_get(NULL, name); - if (IS_ERR(uart_fck[i])) { + uart->fck = clk_get(NULL, name); + if (IS_ERR(uart->fck)) { printk(KERN_ERR "Could not get uart%d_fck\n", i+1); - uart_fck[i] = NULL; - } else - clk_enable(uart_fck[i]); + uart->fck = NULL; + } - omap_serial_reset(p); + if (!uart->ick || !uart->fck) + continue; + + uart->num = i; + p->private_data = uart; + uart->p = p; + list_add(&uart->node, &uart_list); + + omap_uart_enable_clocks(uart); + omap_uart_reset(uart); + omap_uart_idle_init(uart); } + + err = platform_device_register(&serial_device); + +#ifdef CONFIG_PM + if (!err) + err = sysfs_create_file(&serial_device.dev.kobj, + &sleep_timeout_attr.attr); +#endif + } -static struct platform_device serial_device = { - .name = "serial8250", - .id = PLAT8250_DEV_PLATFORM, - .dev = { - .platform_data = serial_platform_data, - }, -}; - -static int __init omap_init(void) -{ - return platform_device_register(&serial_device); -} -arch_initcall(omap_init); diff --git a/arch/arm/mach-omap2/sleep24xx.S b/arch/arm/mach-omap2/sleep24xx.S index bf9e96105e11..130aadbfa083 100644 --- a/arch/arm/mach-omap2/sleep24xx.S +++ b/arch/arm/mach-omap2/sleep24xx.S @@ -28,7 +28,6 @@ #include #include #include -#include #include diff --git a/arch/arm/mach-omap2/sleep34xx.S b/arch/arm/mach-omap2/sleep34xx.S new file mode 100644 index 000000000000..e5e2553e79a6 --- /dev/null +++ b/arch/arm/mach-omap2/sleep34xx.S @@ -0,0 +1,436 @@ +/* + * linux/arch/arm/mach-omap2/sleep.S + * + * (C) Copyright 2007 + * Texas Instruments + * Karthik Dasu + * + * (C) Copyright 2004 + * Texas Instruments, + * Richard Woodruff + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR /PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#include +#include +#include +#include + +#include "prm.h" +#include "sdrc.h" + +#define PM_PREPWSTST_CORE_V OMAP34XX_PRM_REGADDR(CORE_MOD, \ + OMAP3430_PM_PREPWSTST) +#define PM_PREPWSTST_MPU_V OMAP34XX_PRM_REGADDR(MPU_MOD, \ + OMAP3430_PM_PREPWSTST) +#define PM_PWSTCTRL_MPU_P OMAP34XX_PRM_REGADDR(MPU_MOD, PM_PWSTCTRL) +#define SCRATCHPAD_MEM_OFFS 0x310 /* Move this as correct place is + * available */ +#define SCRATCHPAD_BASE_P OMAP343X_CTRL_REGADDR(\ + OMAP343X_CONTROL_MEM_WKUP +\ + SCRATCHPAD_MEM_OFFS) +#define SDRC_POWER_V OMAP34XX_SDRC_REGADDR(SDRC_POWER) + + .text +/* Function call to get the restore pointer for resume from OFF */ +ENTRY(get_restore_pointer) + stmfd sp!, {lr} @ save registers on stack + adr r0, restore + ldmfd sp!, {pc} @ restore regs and return +ENTRY(get_restore_pointer_sz) + .word . - get_restore_pointer_sz +/* + * Forces OMAP into idle state + * + * omap34xx_suspend() - This bit of code just executes the WFI + * for normal idles. + * + * Note: This code get's copied to internal SRAM at boot. When the OMAP + * wakes up it continues execution at the point it went to sleep. + */ +ENTRY(omap34xx_cpu_suspend) + stmfd sp!, {r0-r12, lr} @ save registers on stack +loop: + /*b loop*/ @Enable to debug by stepping through code + /* r0 contains restore pointer in sdram */ + /* r1 contains information about saving context */ + ldr r4, sdrc_power @ read the SDRC_POWER register + ldr r5, [r4] @ read the contents of SDRC_POWER + orr r5, r5, #0x40 @ enable self refresh on idle req + str r5, [r4] @ write back to SDRC_POWER register + + cmp r1, #0x0 + /* If context save is required, do that and execute wfi */ + bne save_context_wfi + /* Data memory barrier and Data sync barrier */ + mov r1, #0 + mcr p15, 0, r1, c7, c10, 4 + mcr p15, 0, r1, c7, c10, 5 + + wfi @ wait for interrupt + + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + bl i_dll_wait + + ldmfd sp!, {r0-r12, pc} @ restore regs and return +restore: + /* b restore*/ @ Enable to debug restore code + /* Check what was the reason for mpu reset and store the reason in r9*/ + /* 1 - Only L1 and logic lost */ + /* 2 - Only L2 lost - In this case, we wont be here */ + /* 3 - Both L1 and L2 lost */ + ldr r1, pm_pwstctrl_mpu + ldr r2, [r1] + and r2, r2, #0x3 + cmp r2, #0x0 @ Check if target power state was OFF or RET + moveq r9, #0x3 @ MPU OFF => L1 and L2 lost + movne r9, #0x1 @ Only L1 and L2 lost => avoid L2 invalidation + bne logic_l1_restore + /* Execute smi to invalidate L2 cache */ + mov r12, #0x1 @ set up to invalide L2 +smi: .word 0xE1600070 @ Call SMI monitor (smieq) +logic_l1_restore: + mov r1, #0 + /* Invalidate all instruction caches to PoU + * and flush branch target cache */ + mcr p15, 0, r1, c7, c5, 0 + + ldr r4, scratchpad_base + ldr r3, [r4,#0xBC] + ldmia r3!, {r4-r6} + mov sp, r4 + msr spsr_cxsf, r5 + mov lr, r6 + + ldmia r3!, {r4-r9} + /* Coprocessor access Control Register */ + mcr p15, 0, r4, c1, c0, 2 + + /* TTBR0 */ + MCR p15, 0, r5, c2, c0, 0 + /* TTBR1 */ + MCR p15, 0, r6, c2, c0, 1 + /* Translation table base control register */ + MCR p15, 0, r7, c2, c0, 2 + /*domain access Control Register */ + MCR p15, 0, r8, c3, c0, 0 + /* data fault status Register */ + MCR p15, 0, r9, c5, c0, 0 + + ldmia r3!,{r4-r8} + /* instruction fault status Register */ + MCR p15, 0, r4, c5, c0, 1 + /*Data Auxiliary Fault Status Register */ + MCR p15, 0, r5, c5, c1, 0 + /*Instruction Auxiliary Fault Status Register*/ + MCR p15, 0, r6, c5, c1, 1 + /*Data Fault Address Register */ + MCR p15, 0, r7, c6, c0, 0 + /*Instruction Fault Address Register*/ + MCR p15, 0, r8, c6, c0, 2 + ldmia r3!,{r4-r7} + + /* user r/w thread and process ID */ + MCR p15, 0, r4, c13, c0, 2 + /* user ro thread and process ID */ + MCR p15, 0, r5, c13, c0, 3 + /*Privileged only thread and process ID */ + MCR p15, 0, r6, c13, c0, 4 + /* cache size selection */ + MCR p15, 2, r7, c0, c0, 0 + ldmia r3!,{r4-r8} + /* Data TLB lockdown registers */ + MCR p15, 0, r4, c10, c0, 0 + /* Instruction TLB lockdown registers */ + MCR p15, 0, r5, c10, c0, 1 + /* Secure or Nonsecure Vector Base Address */ + MCR p15, 0, r6, c12, c0, 0 + /* FCSE PID */ + MCR p15, 0, r7, c13, c0, 0 + /* Context PID */ + MCR p15, 0, r8, c13, c0, 1 + + ldmia r3!,{r4-r5} + /* primary memory remap register */ + MCR p15, 0, r4, c10, c2, 0 + /*normal memory remap register */ + MCR p15, 0, r5, c10, c2, 1 + + /* Restore cpsr */ + ldmia r3!,{r4} /*load CPSR from SDRAM*/ + msr cpsr, r4 /*store cpsr */ + + /* Enabling MMU here */ + mrc p15, 0, r7, c2, c0, 2 /* Read TTBRControl */ + /* Extract N (0:2) bits and decide whether to use TTBR0 or TTBR1*/ + and r7, #0x7 + cmp r7, #0x0 + beq usettbr0 +ttbr_error: + /* More work needs to be done to support N[0:2] value other than 0 + * So looping here so that the error can be detected + */ + b ttbr_error +usettbr0: + mrc p15, 0, r2, c2, c0, 0 + ldr r5, ttbrbit_mask + and r2, r5 + mov r4, pc + ldr r5, table_index_mask + and r4, r5 /* r4 = 31 to 20 bits of pc */ + /* Extract the value to be written to table entry */ + ldr r1, table_entry + add r1, r1, r4 /* r1 has value to be written to table entry*/ + /* Getting the address of table entry to modify */ + lsr r4, #18 + add r2, r4 /* r2 has the location which needs to be modified */ + /* Storing previous entry of location being modified */ + ldr r5, scratchpad_base + ldr r4, [r2] + str r4, [r5, #0xC0] + /* Modify the table entry */ + str r1, [r2] + /* Storing address of entry being modified + * - will be restored after enabling MMU */ + ldr r5, scratchpad_base + str r2, [r5, #0xC4] + + mov r0, #0 + mcr p15, 0, r0, c7, c5, 4 @ Flush prefetch buffer + mcr p15, 0, r0, c7, c5, 6 @ Invalidate branch predictor array + mcr p15, 0, r0, c8, c5, 0 @ Invalidate instruction TLB + mcr p15, 0, r0, c8, c6, 0 @ Invalidate data TLB + /* Restore control register but dont enable caches here*/ + /* Caches will be enabled after restoring MMU table entry */ + ldmia r3!, {r4} + /* Store previous value of control register in scratchpad */ + str r4, [r5, #0xC8] + ldr r2, cache_pred_disable_mask + and r4, r2 + mcr p15, 0, r4, c1, c0, 0 + + ldmfd sp!, {r0-r12, pc} @ restore regs and return +save_context_wfi: + /*b save_context_wfi*/ @ enable to debug save code + mov r8, r0 /* Store SDRAM address in r8 */ + /* Check what that target sleep state is:stored in r1*/ + /* 1 - Only L1 and logic lost */ + /* 2 - Only L2 lost */ + /* 3 - Both L1 and L2 lost */ + cmp r1, #0x2 /* Only L2 lost */ + beq clean_l2 + cmp r1, #0x1 /* L2 retained */ + /* r9 stores whether to clean L2 or not*/ + moveq r9, #0x0 /* Dont Clean L2 */ + movne r9, #0x1 /* Clean L2 */ +l1_logic_lost: + /* Store sp and spsr to SDRAM */ + mov r4, sp + mrs r5, spsr + mov r6, lr + stmia r8!, {r4-r6} + /* Save all ARM registers */ + /* Coprocessor access control register */ + mrc p15, 0, r6, c1, c0, 2 + stmia r8!, {r6} + /* TTBR0, TTBR1 and Translation table base control */ + mrc p15, 0, r4, c2, c0, 0 + mrc p15, 0, r5, c2, c0, 1 + mrc p15, 0, r6, c2, c0, 2 + stmia r8!, {r4-r6} + /* Domain access control register, data fault status register, + and instruction fault status register */ + mrc p15, 0, r4, c3, c0, 0 + mrc p15, 0, r5, c5, c0, 0 + mrc p15, 0, r6, c5, c0, 1 + stmia r8!, {r4-r6} + /* Data aux fault status register, instruction aux fault status, + datat fault address register and instruction fault address register*/ + mrc p15, 0, r4, c5, c1, 0 + mrc p15, 0, r5, c5, c1, 1 + mrc p15, 0, r6, c6, c0, 0 + mrc p15, 0, r7, c6, c0, 2 + stmia r8!, {r4-r7} + /* user r/w thread and process ID, user r/o thread and process ID, + priv only thread and process ID, cache size selection */ + mrc p15, 0, r4, c13, c0, 2 + mrc p15, 0, r5, c13, c0, 3 + mrc p15, 0, r6, c13, c0, 4 + mrc p15, 2, r7, c0, c0, 0 + stmia r8!, {r4-r7} + /* Data TLB lockdown, instruction TLB lockdown registers */ + mrc p15, 0, r5, c10, c0, 0 + mrc p15, 0, r6, c10, c0, 1 + stmia r8!, {r5-r6} + /* Secure or non secure vector base address, FCSE PID, Context PID*/ + mrc p15, 0, r4, c12, c0, 0 + mrc p15, 0, r5, c13, c0, 0 + mrc p15, 0, r6, c13, c0, 1 + stmia r8!, {r4-r6} + /* Primary remap, normal remap registers */ + mrc p15, 0, r4, c10, c2, 0 + mrc p15, 0, r5, c10, c2, 1 + stmia r8!,{r4-r5} + + /* Store current cpsr*/ + mrs r2, cpsr + stmia r8!, {r2} + + mrc p15, 0, r4, c1, c0, 0 + /* save control register */ + stmia r8!, {r4} +clean_caches: + /* Clean Data or unified cache to POU*/ + /* How to invalidate only L1 cache???? - #FIX_ME# */ + /* mcr p15, 0, r11, c7, c11, 1 */ + cmp r9, #1 /* Check whether L2 inval is required or not*/ + bne skip_l2_inval +clean_l2: + /* read clidr */ + mrc p15, 1, r0, c0, c0, 1 + /* extract loc from clidr */ + ands r3, r0, #0x7000000 + /* left align loc bit field */ + mov r3, r3, lsr #23 + /* if loc is 0, then no need to clean */ + beq finished + /* start clean at cache level 0 */ + mov r10, #0 +loop1: + /* work out 3x current cache level */ + add r2, r10, r10, lsr #1 + /* extract cache type bits from clidr*/ + mov r1, r0, lsr r2 + /* mask of the bits for current cache only */ + and r1, r1, #7 + /* see what cache we have at this level */ + cmp r1, #2 + /* skip if no cache, or just i-cache */ + blt skip + /* select current cache level in cssr */ + mcr p15, 2, r10, c0, c0, 0 + /* isb to sych the new cssr&csidr */ + isb + /* read the new csidr */ + mrc p15, 1, r1, c0, c0, 0 + /* extract the length of the cache lines */ + and r2, r1, #7 + /* add 4 (line length offset) */ + add r2, r2, #4 + ldr r4, assoc_mask + /* find maximum number on the way size */ + ands r4, r4, r1, lsr #3 + /* find bit position of way size increment */ + clz r5, r4 + ldr r7, numset_mask + /* extract max number of the index size*/ + ands r7, r7, r1, lsr #13 +loop2: + mov r9, r4 + /* create working copy of max way size*/ +loop3: + /* factor way and cache number into r11 */ + orr r11, r10, r9, lsl r5 + /* factor index number into r11 */ + orr r11, r11, r7, lsl r2 + /*clean & invalidate by set/way */ + mcr p15, 0, r11, c7, c10, 2 + /* decrement the way*/ + subs r9, r9, #1 + bge loop3 + /*decrement the index */ + subs r7, r7, #1 + bge loop2 +skip: + add r10, r10, #2 + /* increment cache number */ + cmp r3, r10 + bgt loop1 +finished: + /*swith back to cache level 0 */ + mov r10, #0 + /* select current cache level in cssr */ + mcr p15, 2, r10, c0, c0, 0 + isb +skip_l2_inval: + /* Data memory barrier and Data sync barrier */ + mov r1, #0 + mcr p15, 0, r1, c7, c10, 4 + mcr p15, 0, r1, c7, c10, 5 + + wfi @ wait for interrupt + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + bl i_dll_wait + /* restore regs and return */ + ldmfd sp!, {r0-r12, pc} + +i_dll_wait: + ldr r4, clk_stabilize_delay + +i_dll_delay: + subs r4, r4, #0x1 + bne i_dll_delay + ldr r4, sdrc_power + ldr r5, [r4] + bic r5, r5, #0x40 + str r5, [r4] + bx lr +pm_prepwstst_core: + .word PM_PREPWSTST_CORE_V +pm_prepwstst_mpu: + .word PM_PREPWSTST_MPU_V +pm_pwstctrl_mpu: + .word PM_PWSTCTRL_MPU_P +scratchpad_base: + .word SCRATCHPAD_BASE_P +sdrc_power: + .word SDRC_POWER_V +context_mem: + .word 0x803E3E14 +clk_stabilize_delay: + .word 0x000001FF +assoc_mask: + .word 0x3ff +numset_mask: + .word 0x7fff +ttbrbit_mask: + .word 0xFFFFC000 +table_index_mask: + .word 0xFFF00000 +table_entry: + .word 0x00000C02 +cache_pred_disable_mask: + .word 0xFFFFE7FB +ENTRY(omap34xx_cpu_suspend_sz) + .word . - omap34xx_cpu_suspend diff --git a/arch/arm/mach-omap2/sram242x.S b/arch/arm/mach-omap2/sram242x.S index af4bd3490227..bb299851116d 100644 --- a/arch/arm/mach-omap2/sram242x.S +++ b/arch/arm/mach-omap2/sram242x.S @@ -124,11 +124,11 @@ omap242x_sdi_cm_clksel2_pll: omap242x_sdi_sdrc_dlla_ctrl: .word OMAP242X_SDRC_REGADDR(SDRC_DLLA_CTRL) omap242x_sdi_prcm_voltctrl: - .word OMAP242X_PRCM_VOLTCTRL + .word OMAP2420_PRCM_VOLTCTRL prcm_mask_val: .word 0xFFFF3FFC omap242x_sdi_timer_32ksynct_cr: - .word IO_ADDRESS(OMAP2_32KSYNCT_BASE + 0x010) + .word IO_ADDRESS(OMAP2420_32KSYNCT_BASE + 0x010) ENTRY(omap242x_sram_ddr_init_sz) .word . - omap242x_sram_ddr_init @@ -220,11 +220,11 @@ omap242x_srs_sdrc_dlla_ctrl: omap242x_srs_sdrc_rfr_ctrl: .word OMAP242X_SDRC_REGADDR(SDRC_RFR_CTRL_0) omap242x_srs_prcm_voltctrl: - .word OMAP242X_PRCM_VOLTCTRL + .word OMAP2420_PRCM_VOLTCTRL ddr_prcm_mask_val: .word 0xFFFF3FFC omap242x_srs_timer_32ksynct: - .word IO_ADDRESS(OMAP2_32KSYNCT_BASE + 0x010) + .word IO_ADDRESS(OMAP2420_32KSYNCT_BASE + 0x010) ENTRY(omap242x_sram_reprogram_sdrc_sz) .word . - omap242x_sram_reprogram_sdrc @@ -305,7 +305,7 @@ wait_dll_lock: ldmfd sp!, {r0-r12, pc} @ restore regs and return omap242x_ssp_set_config: - .word OMAP242X_PRCM_CLKCFG_CTRL + .word OMAP2420_PRCM_CLKCFG_CTRL omap242x_ssp_pll_ctl: .word OMAP2420_CM_REGADDR(PLL_MOD, CM_CLKEN) omap242x_ssp_pll_stat: diff --git a/arch/arm/mach-omap2/sram243x.S b/arch/arm/mach-omap2/sram243x.S index 84363e269e8c..9955abcaeb31 100644 --- a/arch/arm/mach-omap2/sram243x.S +++ b/arch/arm/mach-omap2/sram243x.S @@ -124,11 +124,11 @@ omap243x_sdi_cm_clksel2_pll: omap243x_sdi_sdrc_dlla_ctrl: .word OMAP243X_SDRC_REGADDR(SDRC_DLLA_CTRL) omap243x_sdi_prcm_voltctrl: - .word OMAP243X_PRCM_VOLTCTRL + .word OMAP2430_PRCM_VOLTCTRL prcm_mask_val: .word 0xFFFF3FFC omap243x_sdi_timer_32ksynct_cr: - .word IO_ADDRESS(OMAP2_32KSYNCT_BASE + 0x010) + .word IO_ADDRESS(OMAP2430_32KSYNCT_BASE + 0x010) ENTRY(omap243x_sram_ddr_init_sz) .word . - omap243x_sram_ddr_init @@ -220,11 +220,11 @@ omap243x_srs_sdrc_dlla_ctrl: omap243x_srs_sdrc_rfr_ctrl: .word OMAP243X_SDRC_REGADDR(SDRC_RFR_CTRL_0) omap243x_srs_prcm_voltctrl: - .word OMAP243X_PRCM_VOLTCTRL + .word OMAP2430_PRCM_VOLTCTRL ddr_prcm_mask_val: .word 0xFFFF3FFC omap243x_srs_timer_32ksynct: - .word IO_ADDRESS(OMAP2_32KSYNCT_BASE + 0x010) + .word IO_ADDRESS(OMAP2430_32KSYNCT_BASE + 0x010) ENTRY(omap243x_sram_reprogram_sdrc_sz) .word . - omap243x_sram_reprogram_sdrc @@ -305,7 +305,7 @@ wait_dll_lock: ldmfd sp!, {r0-r12, pc} @ restore regs and return omap243x_ssp_set_config: - .word OMAP243X_PRCM_CLKCFG_CTRL + .word OMAP2430_PRCM_CLKCFG_CTRL omap243x_ssp_pll_ctl: .word OMAP2430_CM_REGADDR(PLL_MOD, CM_CLKEN) omap243x_ssp_pll_stat: diff --git a/arch/arm/mach-omap2/sram34xx.S b/arch/arm/mach-omap2/sram34xx.S index 2c7146136342..f41f8d96ddba 100644 --- a/arch/arm/mach-omap2/sram34xx.S +++ b/arch/arm/mach-omap2/sram34xx.S @@ -3,13 +3,12 @@ * * Omap3 specific functions that need to be run in internal SRAM * - * (C) Copyright 2007 - * Texas Instruments Inc. - * Rajendra Nayak + * Copyright (C) 2004, 2007, 2008 Texas Instruments, Inc. + * Copyright (C) 2008 Nokia Corporation * - * (C) Copyright 2004 - * Texas Instruments, + * Rajendra Nayak * Richard Woodruff + * Paul Walmsley * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -37,121 +36,166 @@ .text +/* r4 parameters */ +#define SDRC_NO_UNLOCK_DLL 0x0 +#define SDRC_UNLOCK_DLL 0x1 + +/* SDRC_DLLA_CTRL bit settings */ +#define FIXEDDELAY_SHIFT 24 +#define FIXEDDELAY_MASK (0xff << FIXEDDELAY_SHIFT) +#define DLLIDLE_MASK 0x4 + /* - * Change frequency of core dpll - * r0 = sdrc_rfr_ctrl r1 = sdrc_actim_ctrla r2 = sdrc_actim_ctrlb r3 = M2 + * SDRC_DLLA_CTRL default values: TI hardware team indicates that + * FIXEDDELAY should be initialized to 0xf. This apparently was + * empirically determined during process testing, so no derivation + * was provided. + */ +#define FIXEDDELAY_DEFAULT (0x0f << FIXEDDELAY_SHIFT) + +/* SDRC_DLLA_STATUS bit settings */ +#define LOCKSTATUS_MASK 0x4 + +/* SDRC_POWER bit settings */ +#define SRFRONIDLEREQ_MASK 0x40 +#define PWDENA_MASK 0x4 + +/* CM_IDLEST1_CORE bit settings */ +#define ST_SDRC_MASK 0x2 + +/* CM_ICLKEN1_CORE bit settings */ +#define EN_SDRC_MASK 0x2 + +/* CM_CLKSEL1_PLL bit settings */ +#define CORE_DPLL_CLKOUT_DIV_SHIFT 0x1b + +/* + * omap3_sram_configure_core_dpll - change DPLL3 M2 divider + * r0 = new SDRC_RFR_CTRL register contents + * r1 = new SDRC_ACTIM_CTRLA register contents + * r2 = new SDRC_ACTIM_CTRLB register contents + * r3 = new M2 divider setting (only 1 and 2 supported right now) + * r4 = unlock SDRC DLL? (1 = yes, 0 = no). Only unlock DLL for + * SDRC rates < 83MHz + * r5 = number of MPU cycles to wait for SDRC to stabilize after + * reprogramming the SDRC when switching to a slower MPU speed + * r6 = new SDRC_MR_0 register value + * r7 = increasing SDRC rate? (1 = yes, 0 = no) + * */ ENTRY(omap3_sram_configure_core_dpll) stmfd sp!, {r1-r12, lr} @ store regs to stack - cmp r3, #0x2 - blne configure_sdrc - cmp r3, #0x2 + ldr r4, [sp, #52] @ pull extra args off the stack + ldr r5, [sp, #56] @ load extra args from the stack + ldr r6, [sp, #60] @ load extra args from the stack + ldr r7, [sp, #64] @ load extra args from the stack + dsb @ flush buffered writes to interconnect + cmp r7, #1 @ if increasing SDRC clk rate, + bleq configure_sdrc @ program the SDRC regs early (for RFR) + cmp r4, #SDRC_UNLOCK_DLL @ set the intended DLL state + bleq unlock_dll blne lock_dll - cmp r3, #0x1 - blne unlock_dll - bl sdram_in_selfrefresh @ put the SDRAM in self refresh - bl configure_core_dpll - bl enable_sdrc - cmp r3, #0x1 - blne wait_dll_unlock - cmp r3, #0x2 + bl sdram_in_selfrefresh @ put SDRAM in self refresh, idle SDRC + bl configure_core_dpll @ change the DPLL3 M2 divider + bl enable_sdrc @ take SDRC out of idle + cmp r4, #SDRC_UNLOCK_DLL @ wait for DLL status to change + bleq wait_dll_unlock blne wait_dll_lock - cmp r3, #0x1 - blne configure_sdrc + cmp r7, #1 @ if increasing SDRC clk rate, + beq return_to_sdram @ return to SDRAM code, otherwise, + bl configure_sdrc @ reprogram SDRC regs now + mov r12, r5 + bl wait_clk_stable @ wait for SDRC to stabilize +return_to_sdram: + isb @ prevent speculative exec past here mov r0, #0 @ return value ldmfd sp!, {r1-r12, pc} @ restore regs and return unlock_dll: - ldr r4, omap3_sdrc_dlla_ctrl - ldr r5, [r4] - orr r5, r5, #0x4 - str r5, [r4] + ldr r11, omap3_sdrc_dlla_ctrl + ldr r12, [r11] + and r12, r12, #FIXEDDELAY_MASK + orr r12, r12, #FIXEDDELAY_DEFAULT + orr r12, r12, #DLLIDLE_MASK + str r12, [r11] @ (no OCP barrier needed) bx lr lock_dll: - ldr r4, omap3_sdrc_dlla_ctrl - ldr r5, [r4] - bic r5, r5, #0x4 - str r5, [r4] + ldr r11, omap3_sdrc_dlla_ctrl + ldr r12, [r11] + bic r12, r12, #DLLIDLE_MASK + str r12, [r11] @ (no OCP barrier needed) bx lr sdram_in_selfrefresh: - mov r5, #0x0 @ Move 0 to R5 - mcr p15, 0, r5, c7, c10, 5 @ memory barrier - ldr r4, omap3_sdrc_power @ read the SDRC_POWER register - ldr r5, [r4] @ read the contents of SDRC_POWER - orr r5, r5, #0x40 @ enable self refresh on idle req - str r5, [r4] @ write back to SDRC_POWER register - ldr r4, omap3_cm_iclken1_core @ read the CM_ICLKEN1_CORE reg - ldr r5, [r4] - bic r5, r5, #0x2 @ disable iclk bit for SRDC - str r5, [r4] + ldr r11, omap3_sdrc_power @ read the SDRC_POWER register + ldr r12, [r11] @ read the contents of SDRC_POWER + mov r9, r12 @ keep a copy of SDRC_POWER bits + orr r12, r12, #SRFRONIDLEREQ_MASK @ enable self refresh on idle + bic r12, r12, #PWDENA_MASK @ clear PWDENA + str r12, [r11] @ write back to SDRC_POWER register + ldr r12, [r11] @ posted-write barrier for SDRC +idle_sdrc: + ldr r11, omap3_cm_iclken1_core @ read the CM_ICLKEN1_CORE reg + ldr r12, [r11] + bic r12, r12, #EN_SDRC_MASK @ disable iclk bit for SDRC + str r12, [r11] wait_sdrc_idle: - ldr r4, omap3_cm_idlest1_core - ldr r5, [r4] - and r5, r5, #0x2 @ check for SDRC idle - cmp r5, #2 + ldr r11, omap3_cm_idlest1_core + ldr r12, [r11] + and r12, r12, #ST_SDRC_MASK @ check for SDRC idle + cmp r12, #ST_SDRC_MASK bne wait_sdrc_idle bx lr configure_core_dpll: - ldr r4, omap3_cm_clksel1_pll - ldr r5, [r4] - ldr r6, core_m2_mask_val @ modify m2 for core dpll - and r5, r5, r6 - orr r5, r5, r3, lsl #0x1B @ r3 contains the M2 val - str r5, [r4] - mov r5, #0x800 @ wait for the clock to stabilise - cmp r3, #2 - bne wait_clk_stable + ldr r11, omap3_cm_clksel1_pll + ldr r12, [r11] + ldr r10, core_m2_mask_val @ modify m2 for core dpll + and r12, r12, r10 + orr r12, r12, r3, lsl #CORE_DPLL_CLKOUT_DIV_SHIFT + str r12, [r11] + ldr r12, [r11] @ posted-write barrier for CM bx lr wait_clk_stable: - subs r5, r5, #1 + subs r12, r12, #1 bne wait_clk_stable - nop - nop - nop - nop - nop - nop - nop - nop - nop - nop bx lr enable_sdrc: - ldr r4, omap3_cm_iclken1_core - ldr r5, [r4] - orr r5, r5, #0x2 @ enable iclk bit for SDRC - str r5, [r4] + ldr r11, omap3_cm_iclken1_core + ldr r12, [r11] + orr r12, r12, #EN_SDRC_MASK @ enable iclk bit for SDRC + str r12, [r11] wait_sdrc_idle1: - ldr r4, omap3_cm_idlest1_core - ldr r5, [r4] - and r5, r5, #0x2 - cmp r5, #0 + ldr r11, omap3_cm_idlest1_core + ldr r12, [r11] + and r12, r12, #ST_SDRC_MASK + cmp r12, #0 bne wait_sdrc_idle1 - ldr r4, omap3_sdrc_power - ldr r5, [r4] - bic r5, r5, #0x40 - str r5, [r4] +restore_sdrc_power_val: + ldr r11, omap3_sdrc_power + str r9, [r11] @ restore SDRC_POWER, no barrier needed bx lr wait_dll_lock: - ldr r4, omap3_sdrc_dlla_status - ldr r5, [r4] - and r5, r5, #0x4 - cmp r5, #0x4 + ldr r11, omap3_sdrc_dlla_status + ldr r12, [r11] + and r12, r12, #LOCKSTATUS_MASK + cmp r12, #LOCKSTATUS_MASK bne wait_dll_lock bx lr wait_dll_unlock: - ldr r4, omap3_sdrc_dlla_status - ldr r5, [r4] - and r5, r5, #0x4 - cmp r5, #0x0 + ldr r11, omap3_sdrc_dlla_status + ldr r12, [r11] + and r12, r12, #LOCKSTATUS_MASK + cmp r12, #0x0 bne wait_dll_unlock bx lr configure_sdrc: - ldr r4, omap3_sdrc_rfr_ctrl - str r0, [r4] - ldr r4, omap3_sdrc_actim_ctrla - str r1, [r4] - ldr r4, omap3_sdrc_actim_ctrlb - str r2, [r4] + ldr r11, omap3_sdrc_rfr_ctrl + str r0, [r11] + ldr r11, omap3_sdrc_actim_ctrla + str r1, [r11] + ldr r11, omap3_sdrc_actim_ctrlb + str r2, [r11] + ldr r11, omap3_sdrc_mr_0 + str r6, [r11] + ldr r6, [r11] @ posted-write barrier for SDRC bx lr omap3_sdrc_power: @@ -168,6 +212,8 @@ omap3_sdrc_actim_ctrla: .word OMAP34XX_SDRC_REGADDR(SDRC_ACTIM_CTRL_A_0) omap3_sdrc_actim_ctrlb: .word OMAP34XX_SDRC_REGADDR(SDRC_ACTIM_CTRL_B_0) +omap3_sdrc_mr_0: + .word OMAP34XX_SDRC_REGADDR(SDRC_MR_0) omap3_sdrc_dlla_status: .word OMAP34XX_SDRC_REGADDR(SDRC_DLLA_STATUS) omap3_sdrc_dlla_ctrl: diff --git a/arch/arm/mach-omap2/timer-gp.c b/arch/arm/mach-omap2/timer-gp.c index f36aba12090e..97eeeebcb066 100644 --- a/arch/arm/mach-omap2/timer-gp.c +++ b/arch/arm/mach-omap2/timer-gp.c @@ -17,9 +17,10 @@ * * Some parts based off of TI's 24xx code: * - * Copyright (C) 2004 Texas Instruments, Inc. + * Copyright (C) 2004-2009 Texas Instruments, Inc. * * Roughly modelled after the OMAP1 MPU timer code. + * Added OMAP4 support - Santosh Shilimkar * * 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 @@ -37,6 +38,7 @@ #include #include +#include /* MAX_GPTIMER_ID: number of GPTIMERs on the chip */ #define MAX_GPTIMER_ID 12 @@ -82,7 +84,8 @@ static void omap2_gp_timer_set_mode(enum clock_event_mode mode, case CLOCK_EVT_MODE_PERIODIC: period = clk_get_rate(omap_dm_timer_get_fclk(gptimer)) / HZ; period -= 1; - + if (cpu_is_omap44xx()) + period = 0xff; /* FIXME: */ omap_dm_timer_set_load_start(gptimer, 1, 0xffffffff - period); break; case CLOCK_EVT_MODE_ONESHOT: @@ -145,6 +148,9 @@ static void __init omap2_gp_clockevent_init(void) "timer-gp: omap_dm_timer_set_source() failed\n"); tick_rate = clk_get_rate(omap_dm_timer_get_fclk(gptimer)); + if (cpu_is_omap44xx()) + /* Assuming 32kHz clk is driving GPT1 */ + tick_rate = 32768; /* FIXME: */ pr_info("OMAP clockevent source: GPTIMER%d at %u Hz\n", gptimer_id, tick_rate); @@ -224,6 +230,9 @@ static void __init omap2_gp_clocksource_init(void) static void __init omap2_gp_timer_init(void) { +#ifdef CONFIG_LOCAL_TIMERS + twd_base = IO_ADDRESS(OMAP44XX_LOCAL_TWD_BASE); +#endif omap_dm_timer_init(); omap2_gp_clockevent_init(); diff --git a/arch/arm/mach-omap2/timer-mpu.c b/arch/arm/mach-omap2/timer-mpu.c new file mode 100644 index 000000000000..c1a650a9910f --- /dev/null +++ b/arch/arm/mach-omap2/timer-mpu.c @@ -0,0 +1,34 @@ +/* + * The MPU local timer source file. In OMAP4, both cortex-a9 cores have + * own timer in it's MPU domain. These timers will be driving the + * linux kernel SMP tick framework when active. These timers are not + * part of the wake up domain. + * + * Copyright (C) 2009 Texas Instruments, Inc. + * + * Author: + * Santosh Shilimkar + * + * This file is based on arm realview smp platform file. + * Copyright (C) 2002 ARM Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include + +/* + * Setup the local clock events for a CPU. + */ +void __cpuinit local_timer_setup(struct clock_event_device *evt) +{ + evt->irq = INT_44XX_LOCALTIMER_IRQ; + twd_timer_setup(evt); +} + diff --git a/arch/arm/mach-omap2/usb-musb.c b/arch/arm/mach-omap2/usb-musb.c index 34a56a136efd..d85296dc896c 100644 --- a/arch/arm/mach-omap2/usb-musb.c +++ b/arch/arm/mach-omap2/usb-musb.c @@ -28,10 +28,20 @@ #include #include -#include #include #include +#define OTG_SYSCONFIG (OMAP34XX_HSUSB_OTG_BASE + 0x404) + +static void __init usb_musb_pm_init(void) +{ + /* Ensure force-idle mode for OTG controller */ + if (cpu_is_omap34xx()) + omap_writel(0, OTG_SYSCONFIG); +} + +#ifdef CONFIG_USB_MUSB_SOC + static struct resource musb_resources[] = { [0] = { /* start and end set dynamically */ .flags = IORESOURCE_MEM, @@ -184,4 +194,13 @@ void __init usb_musb_init(void) printk(KERN_ERR "Unable to register HS-USB (MUSB) device\n"); return; } + + usb_musb_pm_init(); } + +#else +void __init usb_musb_init(void) +{ + usb_musb_pm_init(); +} +#endif /* CONFIG_USB_MUSB_SOC */ diff --git a/arch/arm/mach-orion5x/addr-map.c b/arch/arm/mach-orion5x/addr-map.c index c14d12137276..d78731edebb6 100644 --- a/arch/arm/mach-orion5x/addr-map.c +++ b/arch/arm/mach-orion5x/addr-map.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include "common.h" @@ -44,6 +45,7 @@ #define TARGET_DEV_BUS 1 #define TARGET_PCI 3 #define TARGET_PCIE 4 +#define TARGET_SRAM 9 #define ATTR_PCIE_MEM 0x59 #define ATTR_PCIE_IO 0x51 #define ATTR_PCIE_WA 0x79 @@ -53,6 +55,7 @@ #define ATTR_DEV_CS1 0x1d #define ATTR_DEV_CS2 0x1b #define ATTR_DEV_BOOT 0xf +#define ATTR_SRAM 0x0 /* * Helpers to get DDR bank info @@ -87,13 +90,13 @@ static int __init orion5x_cpu_win_can_remap(int win) return 0; } -static void __init setup_cpu_win(int win, u32 base, u32 size, +static int __init setup_cpu_win(int win, u32 base, u32 size, u8 target, u8 attr, int remap) { if (win >= 8) { printk(KERN_ERR "setup_cpu_win: trying to allocate " "window %d\n", win); - return; + return -ENOSPC; } writel(base & 0xffff0000, CPU_WIN_BASE(win)); @@ -107,6 +110,7 @@ static void __init setup_cpu_win(int win, u32 base, u32 size, writel(remap & 0xffff0000, CPU_WIN_REMAP_LO(win)); writel(0, CPU_WIN_REMAP_HI(win)); } + return 0; } void __init orion5x_setup_cpu_mbus_bridge(void) @@ -193,3 +197,9 @@ void __init orion5x_setup_pcie_wa_win(u32 base, u32 size) setup_cpu_win(win_alloc_count++, base, size, TARGET_PCIE, ATTR_PCIE_WA, -1); } + +int __init orion5x_setup_sram_win(void) +{ + return setup_cpu_win(win_alloc_count++, ORION5X_SRAM_PHYS_BASE, + ORION5X_SRAM_SIZE, TARGET_SRAM, ATTR_SRAM, -1); +} diff --git a/arch/arm/mach-orion5x/common.c b/arch/arm/mach-orion5x/common.c index b1c7778d9f96..f87fa1253803 100644 --- a/arch/arm/mach-orion5x/common.c +++ b/arch/arm/mach-orion5x/common.c @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include #include "common.h" @@ -536,16 +536,52 @@ void __init orion5x_xor_init(void) platform_device_register(&orion5x_xor1_channel); } +static struct resource orion5x_crypto_res[] = { + { + .name = "regs", + .start = ORION5X_CRYPTO_PHYS_BASE, + .end = ORION5X_CRYPTO_PHYS_BASE + 0xffff, + .flags = IORESOURCE_MEM, + }, { + .name = "sram", + .start = ORION5X_SRAM_PHYS_BASE, + .end = ORION5X_SRAM_PHYS_BASE + SZ_8K - 1, + .flags = IORESOURCE_MEM, + }, { + .name = "crypto interrupt", + .start = IRQ_ORION5X_CESA, + .end = IRQ_ORION5X_CESA, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device orion5x_crypto_device = { + .name = "mv_crypto", + .id = -1, + .num_resources = ARRAY_SIZE(orion5x_crypto_res), + .resource = orion5x_crypto_res, +}; + +static int __init orion5x_crypto_init(void) +{ + int ret; + + ret = orion5x_setup_sram_win(); + if (ret) + return ret; + + return platform_device_register(&orion5x_crypto_device); +} /***************************************************************************** * Watchdog ****************************************************************************/ -static struct orion5x_wdt_platform_data orion5x_wdt_data = { +static struct orion_wdt_platform_data orion5x_wdt_data = { .tclk = 0, }; static struct platform_device orion5x_wdt_device = { - .name = "orion5x_wdt", + .name = "orion_wdt", .id = -1, .dev = { .platform_data = &orion5x_wdt_data, @@ -660,6 +696,14 @@ void __init orion5x_init(void) disable_hlt(); } + /* + * The 5082/5181l/5182/6082/6082l/6183 have crypto + * while 5180n/5181/5281 don't have crypto. + */ + if ((dev == MV88F5181_DEV_ID && rev >= MV88F5181L_REV_A0) || + dev == MV88F5182_DEV_ID || dev == MV88F6183_DEV_ID) + orion5x_crypto_init(); + /* * Register watchdog driver */ diff --git a/arch/arm/mach-orion5x/common.h b/arch/arm/mach-orion5x/common.h index 798b9a5e3da9..8f004503c96d 100644 --- a/arch/arm/mach-orion5x/common.h +++ b/arch/arm/mach-orion5x/common.h @@ -26,6 +26,7 @@ void orion5x_setup_dev0_win(u32 base, u32 size); void orion5x_setup_dev1_win(u32 base, u32 size); void orion5x_setup_dev2_win(u32 base, u32 size); void orion5x_setup_pcie_wa_win(u32 base, u32 size); +int orion5x_setup_sram_win(void); void orion5x_ehci0_init(void); void orion5x_ehci1_init(void); diff --git a/arch/arm/mach-orion5x/include/mach/bridge-regs.h b/arch/arm/mach-orion5x/include/mach/bridge-regs.h index be896e59d3e7..5c9744cd8ef6 100644 --- a/arch/arm/mach-orion5x/include/mach/bridge-regs.h +++ b/arch/arm/mach-orion5x/include/mach/bridge-regs.h @@ -17,8 +17,8 @@ #define CPU_CTRL (ORION5X_BRIDGE_VIRT_BASE | 0x104) -#define CPU_RESET_MASK (ORION5X_BRIDGE_VIRT_BASE | 0x108) -#define WDT_RESET 0x0002 +#define RSTOUTn_MASK (ORION5X_BRIDGE_VIRT_BASE | 0x108) +#define WDT_RESET_OUT_EN 0x0002 #define CPU_SOFT_RESET (ORION5X_BRIDGE_VIRT_BASE | 0x10c) diff --git a/arch/arm/mach-orion5x/include/mach/orion5x.h b/arch/arm/mach-orion5x/include/mach/orion5x.h index 377a773ae53f..2d8766570531 100644 --- a/arch/arm/mach-orion5x/include/mach/orion5x.h +++ b/arch/arm/mach-orion5x/include/mach/orion5x.h @@ -24,6 +24,7 @@ * f1000000 on-chip peripheral registers * f2000000 PCIe I/O space * f2100000 PCI I/O space + * f2200000 SRAM dedicated for the crypto unit * f4000000 device bus mappings (boot) * fa000000 device bus mappings (cs0) * fa800000 device bus mappings (cs2) @@ -49,6 +50,9 @@ #define ORION5X_PCI_IO_BUS_BASE 0x00100000 #define ORION5X_PCI_IO_SIZE SZ_1M +#define ORION5X_SRAM_PHYS_BASE (0xf2200000) +#define ORION5X_SRAM_SIZE SZ_8K + /* Relevant only for Orion-1/Orion-NAS */ #define ORION5X_PCIE_WA_PHYS_BASE 0xf0000000 #define ORION5X_PCIE_WA_VIRT_BASE 0xfe000000 @@ -94,6 +98,8 @@ #define ORION5X_SATA_PHYS_BASE (ORION5X_REGS_PHYS_BASE | 0x80000) #define ORION5X_SATA_VIRT_BASE (ORION5X_REGS_VIRT_BASE | 0x80000) +#define ORION5X_CRYPTO_PHYS_BASE (ORION5X_REGS_PHYS_BASE | 0x90000) + #define ORION5X_USB1_PHYS_BASE (ORION5X_REGS_PHYS_BASE | 0xa0000) #define ORION5X_USB1_VIRT_BASE (ORION5X_REGS_VIRT_BASE | 0xa0000) diff --git a/arch/arm/mach-orion5x/include/mach/system.h b/arch/arm/mach-orion5x/include/mach/system.h index e912490fff23..60e734c10458 100644 --- a/arch/arm/mach-orion5x/include/mach/system.h +++ b/arch/arm/mach-orion5x/include/mach/system.h @@ -23,7 +23,7 @@ static inline void arch_reset(char mode, const char *cmd) /* * Enable and issue soft reset */ - orion5x_setbits(CPU_RESET_MASK, (1 << 2)); + orion5x_setbits(RSTOUTn_MASK, (1 << 2)); orion5x_setbits(CPU_SOFT_RESET, 1); } diff --git a/arch/arm/mach-orion5x/mpp.c b/arch/arm/mach-orion5x/mpp.c index e23a3f91d6c6..bc4c3b9aaf83 100644 --- a/arch/arm/mach-orion5x/mpp.c +++ b/arch/arm/mach-orion5x/mpp.c @@ -124,6 +124,9 @@ void __init orion5x_mpp_conf(struct orion5x_mpp_mode *mode) u32 mpp_8_15_ctrl = readl(MPP_8_15_CTRL); u32 mpp_16_19_ctrl = readl(MPP_16_19_CTRL); + /* Initialize gpiolib. */ + orion_gpio_init(); + while (mode->mpp >= 0) { u32 *reg; int num_type; diff --git a/arch/arm/mach-orion5x/mss2-setup.c b/arch/arm/mach-orion5x/mss2-setup.c index 41e6d5033d54..61c086b66723 100644 --- a/arch/arm/mach-orion5x/mss2-setup.c +++ b/arch/arm/mach-orion5x/mss2-setup.c @@ -181,9 +181,9 @@ static void mss2_power_off(void) /* * Enable and issue soft reset */ - reg = readl(CPU_RESET_MASK); + reg = readl(RSTOUTn_MASK); reg |= 1 << 2; - writel(reg, CPU_RESET_MASK); + writel(reg, RSTOUTn_MASK); reg = readl(CPU_SOFT_RESET); reg |= 1; diff --git a/arch/arm/mach-orion5x/ts78xx-fpga.h b/arch/arm/mach-orion5x/ts78xx-fpga.h index 0f9cdf458952..37b3d4875291 100644 --- a/arch/arm/mach-orion5x/ts78xx-fpga.h +++ b/arch/arm/mach-orion5x/ts78xx-fpga.h @@ -25,6 +25,7 @@ struct fpga_devices { /* Technologic Systems */ struct fpga_device ts_rtc; struct fpga_device ts_nand; + struct fpga_device ts_rng; }; struct ts78xx_fpga_data { diff --git a/arch/arm/mach-orion5x/ts78xx-setup.c b/arch/arm/mach-orion5x/ts78xx-setup.c index 9a6b397f972d..5041d1bc26b1 100644 --- a/arch/arm/mach-orion5x/ts78xx-setup.c +++ b/arch/arm/mach-orion5x/ts78xx-setup.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -269,6 +270,50 @@ static void ts78xx_ts_nand_unload(void) platform_device_del(&ts78xx_ts_nand_device); } +/***************************************************************************** + * HW RNG + ****************************************************************************/ +#define TS_RNG_DATA (TS78XX_FPGA_REGS_PHYS_BASE | 0x044) + +static struct resource ts78xx_ts_rng_resource = { + .flags = IORESOURCE_MEM, + .start = TS_RNG_DATA, + .end = TS_RNG_DATA + 4 - 1, +}; + +static struct timeriomem_rng_data ts78xx_ts_rng_data = { + .period = 1000000, /* one second */ +}; + +static struct platform_device ts78xx_ts_rng_device = { + .name = "timeriomem_rng", + .id = -1, + .dev = { + .platform_data = &ts78xx_ts_rng_data, + }, + .resource = &ts78xx_ts_rng_resource, + .num_resources = 1, +}; + +static int ts78xx_ts_rng_load(void) +{ + int rc; + + if (ts78xx_fpga.supports.ts_rng.init == 0) { + rc = platform_device_register(&ts78xx_ts_rng_device); + if (!rc) + ts78xx_fpga.supports.ts_rng.init = 1; + } else + rc = platform_device_add(&ts78xx_ts_rng_device); + + return rc; +}; + +static void ts78xx_ts_rng_unload(void) +{ + platform_device_del(&ts78xx_ts_rng_device); +} + /***************************************************************************** * FPGA 'hotplug' support code ****************************************************************************/ @@ -276,6 +321,7 @@ static void ts78xx_fpga_devices_zero_init(void) { ts78xx_fpga.supports.ts_rtc.init = 0; ts78xx_fpga.supports.ts_nand.init = 0; + ts78xx_fpga.supports.ts_rng.init = 0; } static void ts78xx_fpga_supports(void) @@ -289,10 +335,12 @@ static void ts78xx_fpga_supports(void) case TS7800_REV_5: ts78xx_fpga.supports.ts_rtc.present = 1; ts78xx_fpga.supports.ts_nand.present = 1; + ts78xx_fpga.supports.ts_rng.present = 1; break; default: ts78xx_fpga.supports.ts_rtc.present = 0; ts78xx_fpga.supports.ts_nand.present = 0; + ts78xx_fpga.supports.ts_rng.present = 0; } } @@ -316,6 +364,14 @@ static int ts78xx_fpga_load_devices(void) } ret |= tmp; } + if (ts78xx_fpga.supports.ts_rng.present == 1) { + tmp = ts78xx_ts_rng_load(); + if (tmp) { + printk(KERN_INFO "TS-78xx: RNG not registered\n"); + ts78xx_fpga.supports.ts_rng.present = 0; + } + ret |= tmp; + } return ret; } @@ -328,6 +384,8 @@ static int ts78xx_fpga_unload_devices(void) ts78xx_ts_rtc_unload(); if (ts78xx_fpga.supports.ts_nand.present == 1) ts78xx_ts_nand_unload(); + if (ts78xx_fpga.supports.ts_rng.present == 1) + ts78xx_ts_rng_unload(); return ret; } diff --git a/arch/arm/mach-orion5x/wnr854t-setup.c b/arch/arm/mach-orion5x/wnr854t-setup.c index 7ddc22c2bb54..69208217b220 100644 --- a/arch/arm/mach-orion5x/wnr854t-setup.c +++ b/arch/arm/mach-orion5x/wnr854t-setup.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -97,6 +98,20 @@ static struct mv643xx_eth_platform_data wnr854t_eth_data = { .duplex = DUPLEX_FULL, }; +static struct dsa_chip_data wnr854t_switch_chip_data = { + .port_names[0] = "lan3", + .port_names[1] = "lan4", + .port_names[2] = "wan", + .port_names[3] = "cpu", + .port_names[5] = "lan1", + .port_names[7] = "lan2", +}; + +static struct dsa_platform_data wnr854t_switch_plat_data = { + .nr_chips = 1, + .chip = &wnr854t_switch_chip_data, +}; + static void __init wnr854t_init(void) { /* @@ -110,6 +125,7 @@ static void __init wnr854t_init(void) * Configure peripherals. */ orion5x_eth_init(&wnr854t_eth_data); + orion5x_eth_switch_init(&wnr854t_switch_plat_data, NO_IRQ); orion5x_uart0_init(); orion5x_setup_dev_boot_win(WNR854T_NOR_BOOT_BASE, diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig index 17d3fbd368a3..89c992b8f75b 100644 --- a/arch/arm/mach-pxa/Kconfig +++ b/arch/arm/mach-pxa/Kconfig @@ -51,6 +51,12 @@ config MACH_INTELMOTE2 select IWMMXT select PXA_HAVE_BOARD_IRQS +config MACH_STARGATE2 + bool "Intel Stargate 2 Platform" + select PXA27x + select IWMMXT + select PXA_HAVE_BOARD_IRQS + config ARCH_LUBBOCK bool "Intel DBPXA250 Development Platform" select PXA25x @@ -88,6 +94,10 @@ config PXA_SHARPSL SL-C3000 (Spitz), SL-C3100 (Borzoi) or SL-C6000x (Tosa) handheld computer. +config SHARPSL_PM + bool + select APM_EMULATION + config CORGI_SSP_DEPRECATED bool select PXA_SSP @@ -280,6 +290,7 @@ config MACH_ZYLONITE select PXA3xx select PXA_SSP select HAVE_PWM + select PXA_HAVE_BOARD_IRQS config MACH_LITTLETON bool "PXA3xx Form Factor Platform (aka Littleton)" @@ -308,6 +319,14 @@ config MACH_CM_X300 select PXA3xx select CPU_PXA300 +config MACH_H4700 + bool "HP iPAQ hx4700" + select PXA27x + select IWMMXT + select PXA_SSP + select HAVE_PWM + select PXA_HAVE_BOARD_IRQS + config MACH_MAGICIAN bool "Enable HTC Magician Support" select PXA27x @@ -382,6 +401,16 @@ config MACH_PALMZ72 Say Y here if you intend to run this kernel on Palm Zire 72 handheld computer. +config MACH_TREO680 + bool "Palm Treo 680" + default y + depends on ARCH_PXA_PALM + select PXA27x + select IWMMXT + help + Say Y here if you intend to run this kernel on Palm Treo 680 + smartphone. + config MACH_PALMLD bool "Palm LifeDrive" default y @@ -505,12 +534,6 @@ config PXA_SSP help Enable support for PXA2xx SSP ports -config PXA_PWM - tristate - default BACKLIGHT_PWM - help - Enable support for PXA2xx/PXA3xx PWM controllers - config TOSA_BT tristate "Control the state of built-in bluetooth chip on Sharp SL-6000" depends on MACH_TOSA diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile index 682dbf4e14b0..d4c6122a342f 100644 --- a/arch/arm/mach-pxa/Makefile +++ b/arch/arm/mach-pxa/Makefile @@ -15,7 +15,6 @@ endif # Generic drivers that other drivers may depend upon obj-$(CONFIG_PXA_SSP) += ssp.o -obj-$(CONFIG_PXA_PWM) += pwm.o # SoC-specific code obj-$(CONFIG_PXA25x) += mfp-pxa2xx.o pxa2xx.o pxa25x.o @@ -47,6 +46,7 @@ obj-$(CONFIG_MACH_PCM027) += pcm027.o obj-$(CONFIG_MACH_PCM990_BASEBOARD) += pcm990-baseboard.o obj-$(CONFIG_MACH_TOSA) += tosa.o obj-$(CONFIG_MACH_EM_X270) += em-x270.o +obj-$(CONFIG_MACH_H4700) += hx4700.o obj-$(CONFIG_MACH_MAGICIAN) += magician.o obj-$(CONFIG_MACH_HIMALAYA) += himalaya.o obj-$(CONFIG_MACH_MIOA701) += mioa701.o mioa701_bootresume.o @@ -62,6 +62,7 @@ obj-$(CONFIG_MACH_PALMT5) += palmt5.o obj-$(CONFIG_MACH_PALMTX) += palmtx.o obj-$(CONFIG_MACH_PALMLD) += palmld.o obj-$(CONFIG_MACH_PALMZ72) += palmz72.o +obj-$(CONFIG_MACH_TREO680) += treo680.o obj-$(CONFIG_ARCH_VIPER) += viper.o ifeq ($(CONFIG_MACH_ZYLONITE),y) @@ -78,6 +79,7 @@ obj-$(CONFIG_MACH_CM_X300) += cm-x300.o obj-$(CONFIG_PXA_EZX) += ezx.o obj-$(CONFIG_MACH_INTELMOTE2) += imote2.o +obj-$(CONFIG_MACH_STARGATE2) += stargate2.o obj-$(CONFIG_MACH_CSB726) += csb726.o obj-$(CONFIG_CSB726_CSB701) += csb701.o diff --git a/arch/arm/mach-pxa/clock.c b/arch/arm/mach-pxa/clock.c index db52d2c4791d..49ae38292310 100644 --- a/arch/arm/mach-pxa/clock.c +++ b/arch/arm/mach-pxa/clock.c @@ -86,20 +86,3 @@ void clks_register(struct clk_lookup *clks, size_t num) for (i = 0; i < num; i++) clkdev_add(&clks[i]); } - -int clk_add_alias(const char *alias, const char *alias_dev_name, char *id, - struct device *dev) -{ - struct clk *r = clk_get(dev, id); - struct clk_lookup *l; - - if (!r) - return -ENODEV; - - l = clkdev_alloc(r, alias, alias_dev_name); - clk_put(r); - if (!l) - return -ENODEV; - clkdev_add(l); - return 0; -} diff --git a/arch/arm/mach-pxa/cm-x270.c b/arch/arm/mach-pxa/cm-x270.c index 34576ba5f5fd..1d2cec25391d 100644 --- a/arch/arm/mach-pxa/cm-x270.c +++ b/arch/arm/mach-pxa/cm-x270.c @@ -335,6 +335,10 @@ void __init cmx270_init(void) { pxa2xx_mfp_config(ARRAY_AND_SIZE(cmx270_pin_config)); +#ifdef CONFIG_PM + pxa27x_set_pwrmode(PWRMODE_DEEPSLEEP); +#endif + cmx270_init_rtc(); cmx270_init_mmc(); cmx270_init_ohci(); diff --git a/arch/arm/mach-pxa/cm-x300.c b/arch/arm/mach-pxa/cm-x300.c index a9f48b1cb54a..465da26591bd 100644 --- a/arch/arm/mach-pxa/cm-x300.c +++ b/arch/arm/mach-pxa/cm-x300.c @@ -21,18 +21,20 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include #include -#include +#include #include #include @@ -46,6 +48,11 @@ #define CM_X300_MMC2_IRQ IRQ_GPIO(GPIO82_MMC2_IRQ) +#define GPIO95_RTC_CS (95) +#define GPIO96_RTC_WR (96) +#define GPIO97_RTC_RD (97) +#define GPIO98_RTC_IO (98) + static mfp_cfg_t cm_x300_mfp_cfg[] __initdata = { /* LCD */ GPIO54_LCD_LDD_0, @@ -135,6 +142,12 @@ static mfp_cfg_t cm_x300_mfp_cfg[] __initdata = { GPIO85_GPIO, /* MMC WP */ GPIO99_GPIO, /* Ethernet IRQ */ + /* RTC GPIOs */ + GPIO95_GPIO, /* RTC CS */ + GPIO96_GPIO, /* RTC WR */ + GPIO97_GPIO, /* RTC RD */ + GPIO98_GPIO, /* RTC IO */ + /* Standard I2C */ GPIO21_I2C_SCL, GPIO22_I2C_SDA, @@ -265,6 +278,7 @@ static struct mtd_partition cm_x300_nand_partitions[] = { static struct pxa3xx_nand_platform_data cm_x300_nand_info = { .enable_arbiter = 1, + .keep_config = 1, .parts = cm_x300_nand_partitions, .nr_parts = ARRAY_SIZE(cm_x300_nand_partitions), }; @@ -441,6 +455,31 @@ static void __init cm_x300_init_i2c(void) static inline void cm_x300_init_i2c(void) {} #endif +#if defined(CONFIG_RTC_DRV_V3020) || defined(CONFIG_RTC_DRV_V3020_MODULE) +struct v3020_platform_data cm_x300_v3020_pdata = { + .use_gpio = 1, + .gpio_cs = GPIO95_RTC_CS, + .gpio_wr = GPIO96_RTC_WR, + .gpio_rd = GPIO97_RTC_RD, + .gpio_io = GPIO98_RTC_IO, +}; + +static struct platform_device cm_x300_rtc_device = { + .name = "v3020", + .id = -1, + .dev = { + .platform_data = &cm_x300_v3020_pdata, + } +}; + +static void __init cm_x300_init_rtc(void) +{ + platform_device_register(&cm_x300_rtc_device); +} +#else +static inline void cm_x300_init_rtc(void) {} +#endif + static void __init cm_x300_init(void) { /* board-processor specific GPIO initialization */ @@ -453,6 +492,19 @@ static void __init cm_x300_init(void) cm_x300_init_nand(); cm_x300_init_leds(); cm_x300_init_i2c(); + cm_x300_init_rtc(); +} + +static void __init cm_x300_fixup(struct machine_desc *mdesc, struct tag *tags, + char **cmdline, struct meminfo *mi) +{ + mi->nr_banks = 2; + mi->bank[0].start = 0xa0000000; + mi->bank[0].node = 0; + mi->bank[0].size = (64*1024*1024); + mi->bank[1].start = 0xc0000000; + mi->bank[1].node = 0; + mi->bank[1].size = (64*1024*1024); } MACHINE_START(CM_X300, "CM-X300 module") @@ -463,4 +515,5 @@ MACHINE_START(CM_X300, "CM-X300 module") .init_irq = pxa3xx_init_irq, .timer = &pxa_timer, .init_machine = cm_x300_init, + .fixup = cm_x300_fixup, MACHINE_END diff --git a/arch/arm/mach-pxa/corgi.c b/arch/arm/mach-pxa/corgi.c index 930e364ccde9..5363e1aea3fb 100644 --- a/arch/arm/mach-pxa/corgi.c +++ b/arch/arm/mach-pxa/corgi.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -42,7 +43,7 @@ #include #include -#include +#include #include #include #include @@ -445,13 +446,8 @@ static struct ads7846_platform_data corgi_ads7846_info = { .wait_for_sync = corgi_wait_for_hsync, }; -static void corgi_ads7846_cs(u32 command) -{ - gpio_set_value(CORGI_GPIO_ADS7846_CS, !(command == PXA2XX_CS_ASSERT)); -} - static struct pxa2xx_spi_chip corgi_ads7846_chip = { - .cs_control = corgi_ads7846_cs, + .gpio_cs = CORGI_GPIO_ADS7846_CS, }; static void corgi_bl_kick_battery(void) @@ -475,22 +471,12 @@ static struct corgi_lcd_platform_data corgi_lcdcon_info = { .kick_battery = corgi_bl_kick_battery, }; -static void corgi_lcdcon_cs(u32 command) -{ - gpio_set_value(CORGI_GPIO_LCDCON_CS, !(command == PXA2XX_CS_ASSERT)); -} - static struct pxa2xx_spi_chip corgi_lcdcon_chip = { - .cs_control = corgi_lcdcon_cs, + .gpio_cs = CORGI_GPIO_LCDCON_CS, }; -static void corgi_max1111_cs(u32 command) -{ - gpio_set_value(CORGI_GPIO_MAX1111_CS, !(command == PXA2XX_CS_ASSERT)); -} - static struct pxa2xx_spi_chip corgi_max1111_chip = { - .cs_control = corgi_max1111_cs, + .gpio_cs = CORGI_GPIO_MAX1111_CS, }; static struct spi_board_info corgi_spi_devices[] = { @@ -520,32 +506,8 @@ static struct spi_board_info corgi_spi_devices[] = { static void __init corgi_init_spi(void) { - int err; - - err = gpio_request(CORGI_GPIO_ADS7846_CS, "ADS7846_CS"); - if (err) - return; - - err = gpio_request(CORGI_GPIO_LCDCON_CS, "LCDCON_CS"); - if (err) - goto err_free_1; - - err = gpio_request(CORGI_GPIO_MAX1111_CS, "MAX1111_CS"); - if (err) - goto err_free_2; - - gpio_direction_output(CORGI_GPIO_ADS7846_CS, 1); - gpio_direction_output(CORGI_GPIO_LCDCON_CS, 1); - gpio_direction_output(CORGI_GPIO_MAX1111_CS, 1); - pxa2xx_set_spi_info(1, &corgi_spi_info); spi_register_board_info(ARRAY_AND_SIZE(corgi_spi_devices)); - return; - -err_free_2: - gpio_free(CORGI_GPIO_LCDCON_CS); -err_free_1: - gpio_free(CORGI_GPIO_ADS7846_CS); } #else static inline void corgi_init_spi(void) {} @@ -639,6 +601,10 @@ static struct platform_device *devices[] __initdata = { &sharpsl_rom_device, }; +static struct i2c_board_info __initdata corgi_i2c_devices[] = { + { I2C_BOARD_INFO("wm8731", 0x1b) }, +}; + static void corgi_poweroff(void) { if (!machine_is_corgi()) @@ -673,6 +639,7 @@ static void __init corgi_init(void) pxa_set_mci_info(&corgi_mci_platform_data); pxa_set_ficp_info(&corgi_ficp_platform_data); pxa_set_i2c_info(NULL); + i2c_register_board_info(0, ARRAY_AND_SIZE(corgi_i2c_devices)); platform_scoop_config = &corgi_pcmcia_config; diff --git a/arch/arm/mach-pxa/corgi_pm.c b/arch/arm/mach-pxa/corgi_pm.c index 7f04b3a761d1..a093282fe4db 100644 --- a/arch/arm/mach-pxa/corgi_pm.c +++ b/arch/arm/mach-pxa/corgi_pm.c @@ -41,7 +41,6 @@ static void corgi_charger_init(void) pxa_gpio_mode(CORGI_GPIO_CHRG_ON | GPIO_OUT); pxa_gpio_mode(CORGI_GPIO_CHRG_UKN | GPIO_OUT); pxa_gpio_mode(CORGI_GPIO_KEY_INT | GPIO_IN); - sharpsl_pm_pxa_init(); } static void corgi_measure_temp(int on) @@ -191,7 +190,7 @@ unsigned long corgipm_read_devdata(int type) static struct sharpsl_charger_machinfo corgi_pm_machinfo = { .init = corgi_charger_init, - .exit = sharpsl_pm_pxa_remove, + .exit = NULL, .gpio_batlock = CORGI_GPIO_BAT_COVER, .gpio_acin = CORGI_GPIO_AC_IN, .gpio_batfull = CORGI_GPIO_CHRG_FULL, diff --git a/arch/arm/mach-pxa/cpufreq-pxa2xx.c b/arch/arm/mach-pxa/cpufreq-pxa2xx.c index 083a1d851d49..3a8ee2272add 100644 --- a/arch/arm/mach-pxa/cpufreq-pxa2xx.c +++ b/arch/arm/mach-pxa/cpufreq-pxa2xx.c @@ -36,6 +36,8 @@ #include #include #include +#include +#include #include @@ -47,6 +49,8 @@ MODULE_PARM_DESC(freq_debug, "Set the debug messages to on=1/off=0"); #define freq_debug 0 #endif +static struct regulator *vcc_core; + static unsigned int pxa27x_maxfreq; module_param(pxa27x_maxfreq, uint, 0); MODULE_PARM_DESC(pxa27x_maxfreq, "Set the pxa27x maxfreq in MHz" @@ -58,6 +62,8 @@ typedef struct { unsigned int cccr; unsigned int div2; unsigned int cclkcfg; + int vmin; + int vmax; } pxa_freqs_t; /* Define the refresh period in mSec for the SDRAM and the number of rows */ @@ -82,24 +88,24 @@ static unsigned int sdram_rows; static pxa_freqs_t pxa255_run_freqs[] = { - /* CPU MEMBUS CCCR DIV2 CCLKCFG run turbo PXbus SDRAM */ - { 99500, 99500, 0x121, 1, CCLKCFG}, /* 99, 99, 50, 50 */ - {132700, 132700, 0x123, 1, CCLKCFG}, /* 133, 133, 66, 66 */ - {199100, 99500, 0x141, 0, CCLKCFG}, /* 199, 199, 99, 99 */ - {265400, 132700, 0x143, 1, CCLKCFG}, /* 265, 265, 133, 66 */ - {331800, 165900, 0x145, 1, CCLKCFG}, /* 331, 331, 166, 83 */ - {398100, 99500, 0x161, 0, CCLKCFG}, /* 398, 398, 196, 99 */ + /* CPU MEMBUS CCCR DIV2 CCLKCFG run turbo PXbus SDRAM */ + { 99500, 99500, 0x121, 1, CCLKCFG, -1, -1}, /* 99, 99, 50, 50 */ + {132700, 132700, 0x123, 1, CCLKCFG, -1, -1}, /* 133, 133, 66, 66 */ + {199100, 99500, 0x141, 0, CCLKCFG, -1, -1}, /* 199, 199, 99, 99 */ + {265400, 132700, 0x143, 1, CCLKCFG, -1, -1}, /* 265, 265, 133, 66 */ + {331800, 165900, 0x145, 1, CCLKCFG, -1, -1}, /* 331, 331, 166, 83 */ + {398100, 99500, 0x161, 0, CCLKCFG, -1, -1}, /* 398, 398, 196, 99 */ }; /* Use the turbo mode frequencies for the CPUFREQ_POLICY_POWERSAVE policy */ static pxa_freqs_t pxa255_turbo_freqs[] = { /* CPU MEMBUS CCCR DIV2 CCLKCFG run turbo PXbus SDRAM */ - { 99500, 99500, 0x121, 1, CCLKCFG}, /* 99, 99, 50, 50 */ - {199100, 99500, 0x221, 0, CCLKCFG}, /* 99, 199, 50, 99 */ - {298500, 99500, 0x321, 0, CCLKCFG}, /* 99, 287, 50, 99 */ - {298600, 99500, 0x1c1, 0, CCLKCFG}, /* 199, 287, 99, 99 */ - {398100, 99500, 0x241, 0, CCLKCFG}, /* 199, 398, 99, 99 */ + { 99500, 99500, 0x121, 1, CCLKCFG, -1, -1}, /* 99, 99, 50, 50 */ + {199100, 99500, 0x221, 0, CCLKCFG, -1, -1}, /* 99, 199, 50, 99 */ + {298500, 99500, 0x321, 0, CCLKCFG, -1, -1}, /* 99, 287, 50, 99 */ + {298600, 99500, 0x1c1, 0, CCLKCFG, -1, -1}, /* 199, 287, 99, 99 */ + {398100, 99500, 0x241, 0, CCLKCFG, -1, -1}, /* 199, 398, 99, 99 */ }; #define NUM_PXA25x_RUN_FREQS ARRAY_SIZE(pxa255_run_freqs) @@ -148,13 +154,13 @@ MODULE_PARM_DESC(pxa255_turbo_table, "Selects the frequency table (0 = run table ((T) ? CCLKCFG_TURBO : 0)) static pxa_freqs_t pxa27x_freqs[] = { - {104000, 104000, PXA27x_CCCR(1, 8, 2), 0, CCLKCFG2(1, 0, 1)}, - {156000, 104000, PXA27x_CCCR(1, 8, 6), 0, CCLKCFG2(1, 1, 1)}, - {208000, 208000, PXA27x_CCCR(0, 16, 2), 1, CCLKCFG2(0, 0, 1)}, - {312000, 208000, PXA27x_CCCR(1, 16, 3), 1, CCLKCFG2(1, 0, 1)}, - {416000, 208000, PXA27x_CCCR(1, 16, 4), 1, CCLKCFG2(1, 0, 1)}, - {520000, 208000, PXA27x_CCCR(1, 16, 5), 1, CCLKCFG2(1, 0, 1)}, - {624000, 208000, PXA27x_CCCR(1, 16, 6), 1, CCLKCFG2(1, 0, 1)} + {104000, 104000, PXA27x_CCCR(1, 8, 2), 0, CCLKCFG2(1, 0, 1), 900000, 1705000 }, + {156000, 104000, PXA27x_CCCR(1, 8, 6), 0, CCLKCFG2(1, 1, 1), 1000000, 1705000 }, + {208000, 208000, PXA27x_CCCR(0, 16, 2), 1, CCLKCFG2(0, 0, 1), 1180000, 1705000 }, + {312000, 208000, PXA27x_CCCR(1, 16, 3), 1, CCLKCFG2(1, 0, 1), 1250000, 1705000 }, + {416000, 208000, PXA27x_CCCR(1, 16, 4), 1, CCLKCFG2(1, 0, 1), 1350000, 1705000 }, + {520000, 208000, PXA27x_CCCR(1, 16, 5), 1, CCLKCFG2(1, 0, 1), 1450000, 1705000 }, + {624000, 208000, PXA27x_CCCR(1, 16, 6), 1, CCLKCFG2(1, 0, 1), 1550000, 1705000 } }; #define NUM_PXA27x_FREQS ARRAY_SIZE(pxa27x_freqs) @@ -163,6 +169,47 @@ static struct cpufreq_frequency_table extern unsigned get_clk_frequency_khz(int info); +#ifdef CONFIG_REGULATOR + +static int pxa_cpufreq_change_voltage(pxa_freqs_t *pxa_freq) +{ + int ret = 0; + int vmin, vmax; + + if (!cpu_is_pxa27x()) + return 0; + + vmin = pxa_freq->vmin; + vmax = pxa_freq->vmax; + if ((vmin == -1) || (vmax == -1)) + return 0; + + ret = regulator_set_voltage(vcc_core, vmin, vmax); + if (ret) + pr_err("cpufreq: Failed to set vcc_core in [%dmV..%dmV]\n", + vmin, vmax); + return ret; +} + +static __init void pxa_cpufreq_init_voltages(void) +{ + vcc_core = regulator_get(NULL, "vcc_core"); + if (IS_ERR(vcc_core)) { + pr_info("cpufreq: Didn't find vcc_core regulator\n"); + vcc_core = NULL; + } else { + pr_info("cpufreq: Found vcc_core regulator\n"); + } +} +#else +static int pxa_cpufreq_change_voltage(pxa_freqs_t *pxa_freq) +{ + return 0; +} + +static __init void pxa_cpufreq_init_voltages(void) { } +#endif + static void find_freq_tables(struct cpufreq_frequency_table **freq_table, pxa_freqs_t **pxa_freqs) { @@ -251,6 +298,7 @@ static int pxa_set_target(struct cpufreq_policy *policy, unsigned long flags; unsigned int new_freq_cpu, new_freq_mem; unsigned int unused, preset_mdrefr, postset_mdrefr, cclkcfg; + int ret = 0; /* Get the current policy */ find_freq_tables(&pxa_freqs_table, &pxa_freq_settings); @@ -273,6 +321,10 @@ static int pxa_set_target(struct cpufreq_policy *policy, freqs.new / 1000, (pxa_freq_settings[idx].div2) ? (new_freq_mem / 2000) : (new_freq_mem / 1000)); + if (vcc_core && freqs.new > freqs.old) + ret = pxa_cpufreq_change_voltage(&pxa_freq_settings[idx]); + if (ret) + return ret; /* * Tell everyone what we're about to do... * you should add a notify client with any platform specific @@ -335,6 +387,18 @@ static int pxa_set_target(struct cpufreq_policy *policy, */ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + /* + * Even if voltage setting fails, we don't report it, as the frequency + * change succeeded. The voltage reduction is not a critical failure, + * only power savings will suffer from this. + * + * Note: if the voltage change fails, and a return value is returned, a + * bug is triggered (seems a deadlock). Should anybody find out where, + * the "return 0" should become a "return ret". + */ + if (vcc_core && freqs.new < freqs.old) + ret = pxa_cpufreq_change_voltage(&pxa_freq_settings[idx]); + return 0; } @@ -349,6 +413,8 @@ static __init int pxa_cpufreq_init(struct cpufreq_policy *policy) if (cpu_is_pxa27x()) pxa27x_guess_max_freq(); + pxa_cpufreq_init_voltages(); + init_sdram_rows(); /* set default policy and cpuinfo */ diff --git a/arch/arm/mach-pxa/csb726.c b/arch/arm/mach-pxa/csb726.c index 2b289f83a61a..7d3e1b46e550 100644 --- a/arch/arm/mach-pxa/csb726.c +++ b/arch/arm/mach-pxa/csb726.c @@ -16,15 +16,17 @@ #include #include #include +#include #include #include #include #include -#include +#include #include #include #include +#include #include "generic.h" #include "devices.h" @@ -275,15 +277,26 @@ static struct resource csb726_lan_resources[] = { { .start = CSB726_IRQ_LAN, .end = CSB726_IRQ_LAN, - .flags = IORESOURCE_IRQ, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE, }, }; +struct smsc911x_platform_config csb726_lan_config = { + .irq_type = SMSC911X_IRQ_POLARITY_ACTIVE_LOW, + .irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL, + .flags = SMSC911X_USE_32BIT, + .phy_interface = PHY_INTERFACE_MODE_MII, +}; + + static struct platform_device csb726_lan = { - .name = "smc911x", + .name = "smsc911x", .id = -1, .num_resources = ARRAY_SIZE(csb726_lan_resources), .resource = csb726_lan_resources, + .dev = { + .platform_data = &csb726_lan_config, + }, }; static struct platform_device *devices[] __initdata = { @@ -303,6 +316,7 @@ static void __init csb726_init(void) pxa27x_set_i2c_power_info(NULL); pxa_set_mci_info(&csb726_mci); pxa_set_ohci_info(&csb726_ohci_platform_data); + pxa_set_ac97_info(NULL); platform_add_devices(devices, ARRAY_SIZE(devices)); } diff --git a/arch/arm/mach-pxa/devices.c b/arch/arm/mach-pxa/devices.c index 29970f703f3c..ecc08f360b68 100644 --- a/arch/arm/mach-pxa/devices.c +++ b/arch/arm/mach-pxa/devices.c @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include #include @@ -290,7 +290,7 @@ static struct resource pxa3xx_resources_i2c_power[] = { }; struct platform_device pxa3xx_device_i2c_power = { - .name = "pxa2xx-i2c", + .name = "pxa3xx-pwri2c", .id = 1, .resource = pxa3xx_resources_i2c_power, .num_resources = ARRAY_SIZE(pxa3xx_resources_i2c_power), diff --git a/arch/arm/mach-pxa/em-x270.c b/arch/arm/mach-pxa/em-x270.c index bc0f73fbd4ca..63b10d9bb1d3 100644 --- a/arch/arm/mach-pxa/em-x270.c +++ b/arch/arm/mach-pxa/em-x270.c @@ -28,6 +28,9 @@ #include #include #include +#include +#include +#include #include @@ -41,7 +44,7 @@ #include #include #include -#include +#include #include #include @@ -52,23 +55,31 @@ #define GPIO13_MMC_CD (13) #define GPIO95_MMC_WP (95) #define GPIO56_NAND_RB (56) +#define GPIO93_CAM_RESET (93) +#define GPIO16_USB_HUB_RESET (16) /* eXeda specific GPIOs */ #define GPIO114_MMC_CD (114) #define GPIO20_NAND_RB (20) #define GPIO38_SD_PWEN (38) +#define GPIO37_WLAN_RST (37) +#define GPIO95_TOUCHPAD_INT (95) +#define GPIO130_CAM_RESET (130) +#define GPIO10_USB_HUB_RESET (10) /* common GPIOs */ #define GPIO11_NAND_CS (11) -#define GPIO93_CAM_RESET (93) #define GPIO41_ETHIRQ (41) #define EM_X270_ETHIRQ IRQ_GPIO(GPIO41_ETHIRQ) #define GPIO115_WLAN_PWEN (115) #define GPIO19_WLAN_STRAP (19) +#define GPIO9_USB_VBUS_EN (9) static int mmc_cd; static int nand_rb; static int dm9000_flags; +static int cam_reset; +static int usb_hub_reset; static unsigned long common_pin_config[] = { /* AC'97 */ @@ -180,7 +191,6 @@ static unsigned long common_pin_config[] = { /* power controls */ GPIO20_GPIO | MFP_LPM_DRIVE_LOW, /* GPRS_PWEN */ - GPIO93_GPIO | MFP_LPM_DRIVE_LOW, /* Camera reset */ GPIO115_GPIO | MFP_LPM_DRIVE_LOW, /* WLAN_PWEN */ /* NAND controls */ @@ -191,14 +201,18 @@ static unsigned long common_pin_config[] = { }; static unsigned long em_x270_pin_config[] = { - GPIO13_GPIO, /* MMC card detect */ - GPIO56_GPIO, /* NAND Ready/Busy */ - GPIO95_GPIO, /* MMC Write protect */ + GPIO13_GPIO, /* MMC card detect */ + GPIO16_GPIO, /* USB hub reset */ + GPIO56_GPIO, /* NAND Ready/Busy */ + GPIO93_GPIO | MFP_LPM_DRIVE_LOW, /* Camera reset */ + GPIO95_GPIO, /* MMC Write protect */ }; static unsigned long exeda_pin_config[] = { + GPIO10_GPIO, /* USB hub reset */ GPIO20_GPIO, /* NAND Ready/Busy */ GPIO38_GPIO | MFP_LPM_DRIVE_LOW, /* SD slot power */ + GPIO95_GPIO, /* touchpad IRQ */ GPIO114_GPIO, /* MMC card detect */ }; @@ -464,18 +478,79 @@ static inline void em_x270_init_nor(void) {} /* PXA27x OHCI controller setup */ #if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) +static struct regulator *em_x270_usb_ldo; + +static int em_x270_usb_hub_init(void) +{ + int err; + + em_x270_usb_ldo = regulator_get(NULL, "vcc usb"); + if (IS_ERR(em_x270_usb_ldo)) + return PTR_ERR(em_x270_usb_ldo); + + err = gpio_request(GPIO9_USB_VBUS_EN, "vbus en"); + if (err) + goto err_free_usb_ldo; + + err = gpio_request(usb_hub_reset, "hub rst"); + if (err) + goto err_free_vbus_gpio; + + /* USB Hub power-on and reset */ + gpio_direction_output(usb_hub_reset, 0); + regulator_enable(em_x270_usb_ldo); + gpio_set_value(usb_hub_reset, 1); + gpio_set_value(usb_hub_reset, 0); + regulator_disable(em_x270_usb_ldo); + regulator_enable(em_x270_usb_ldo); + gpio_set_value(usb_hub_reset, 1); + + /* enable VBUS */ + gpio_direction_output(GPIO9_USB_VBUS_EN, 1); + + return 0; + +err_free_vbus_gpio: + gpio_free(GPIO9_USB_VBUS_EN); +err_free_usb_ldo: + regulator_put(em_x270_usb_ldo); + + return err; +} + static int em_x270_ohci_init(struct device *dev) { + int err; + + /* we don't want to entirely disable USB if the HUB init failed */ + err = em_x270_usb_hub_init(); + if (err) + pr_err("USB Hub initialization failed: %d\n", err); + /* enable port 2 transiever */ UP2OCR = UP2OCR_HXS | UP2OCR_HXOE; return 0; } +static void em_x270_ohci_exit(struct device *dev) +{ + gpio_free(usb_hub_reset); + gpio_free(GPIO9_USB_VBUS_EN); + + if (!IS_ERR(em_x270_usb_ldo)) { + if (regulator_is_enabled(em_x270_usb_ldo)) + regulator_disable(em_x270_usb_ldo); + + regulator_put(em_x270_usb_ldo); + } +} + static struct pxaohci_platform_data em_x270_ohci_platform_data = { .port_mode = PMM_PERPORT_MODE, .flags = ENABLE_PORT1 | ENABLE_PORT2 | POWER_CONTROL_LOW, .init = em_x270_ohci_init, + .exit = em_x270_ohci_exit, }; static void __init em_x270_init_ohci(void) @@ -661,6 +736,7 @@ static struct pxa2xx_spi_chip em_x270_libertas_chip = { .rx_threshold = 1, .tx_threshold = 1, .timeout = 1000, + .gpio_cs = 14, }; static unsigned long em_x270_libertas_pin_config[] = { @@ -677,33 +753,58 @@ static int em_x270_libertas_setup(struct spi_device *spi) if (err) return err; + err = gpio_request(GPIO19_WLAN_STRAP, "WLAN STRAP"); + if (err) + goto err_free_pwen; + + if (machine_is_exeda()) { + err = gpio_request(GPIO37_WLAN_RST, "WLAN RST"); + if (err) + goto err_free_strap; + + gpio_direction_output(GPIO37_WLAN_RST, 1); + msleep(100); + } + gpio_direction_output(GPIO19_WLAN_STRAP, 1); - mdelay(100); + msleep(100); pxa2xx_mfp_config(ARRAY_AND_SIZE(em_x270_libertas_pin_config)); gpio_direction_output(GPIO115_WLAN_PWEN, 0); - mdelay(100); + msleep(100); gpio_set_value(GPIO115_WLAN_PWEN, 1); - mdelay(100); + msleep(100); spi->bits_per_word = 16; spi_setup(spi); return 0; + +err_free_strap: + gpio_free(GPIO19_WLAN_STRAP); +err_free_pwen: + gpio_free(GPIO115_WLAN_PWEN); + + return err; } static int em_x270_libertas_teardown(struct spi_device *spi) { gpio_set_value(GPIO115_WLAN_PWEN, 0); gpio_free(GPIO115_WLAN_PWEN); + gpio_free(GPIO19_WLAN_STRAP); + + if (machine_is_exeda()) { + gpio_set_value(GPIO37_WLAN_RST, 0); + gpio_free(GPIO37_WLAN_RST); + } return 0; } struct libertas_spi_platform_data em_x270_libertas_pdata = { .use_dummy_writes = 1, - .gpio_cs = 14, .setup = em_x270_libertas_setup, .teardown = em_x270_libertas_teardown, }; @@ -738,10 +839,14 @@ static void __init em_x270_init_spi(void) static inline void em_x270_init_spi(void) {} #endif -#if defined(CONFIG_SND_PXA2XX_AC97) || defined(CONFIG_SND_PXA2XX_AC97_MODULE) +#if defined(CONFIG_SND_PXA2XX_LIB_AC97) +static pxa2xx_audio_ops_t em_x270_ac97_info = { + .reset_gpio = 113, +}; + static void __init em_x270_init_ac97(void) { - pxa_set_ac97_info(NULL); + pxa_set_ac97_info(&em_x270_ac97_info); } #else static inline void em_x270_init_ac97(void) {} @@ -863,26 +968,26 @@ static int em_x270_sensor_init(struct device *dev) { int ret; - ret = gpio_request(GPIO93_CAM_RESET, "camera reset"); + ret = gpio_request(cam_reset, "camera reset"); if (ret) return ret; - gpio_direction_output(GPIO93_CAM_RESET, 0); + gpio_direction_output(cam_reset, 0); em_x270_camera_ldo = regulator_get(NULL, "vcc cam"); if (em_x270_camera_ldo == NULL) { - gpio_free(GPIO93_CAM_RESET); + gpio_free(cam_reset); return -ENODEV; } ret = regulator_enable(em_x270_camera_ldo); if (ret) { regulator_put(em_x270_camera_ldo); - gpio_free(GPIO93_CAM_RESET); + gpio_free(cam_reset); return ret; } - gpio_set_value(GPIO93_CAM_RESET, 1); + gpio_set_value(cam_reset, 1); return 0; } @@ -902,7 +1007,7 @@ static int em_x270_sensor_power(struct device *dev, int on) if (on == is_on) return 0; - gpio_set_value(GPIO93_CAM_RESET, !on); + gpio_set_value(cam_reset, !on); if (on) ret = regulator_enable(em_x270_camera_ldo); @@ -912,7 +1017,7 @@ static int em_x270_sensor_power(struct device *dev, int on) if (ret) return ret; - gpio_set_value(GPIO93_CAM_RESET, on); + gpio_set_value(cam_reset, on); return 0; } @@ -929,13 +1034,8 @@ static struct i2c_board_info em_x270_i2c_cam_info[] = { }, }; -static struct i2c_pxa_platform_data em_x270_i2c_info = { - .fast_mode = 1, -}; - static void __init em_x270_init_camera(void) { - pxa_set_i2c_info(&em_x270_i2c_info); i2c_register_board_info(0, ARRAY_AND_SIZE(em_x270_i2c_cam_info)); pxa_set_camera_info(&em_x270_camera_platform_data); } @@ -943,6 +1043,52 @@ static void __init em_x270_init_camera(void) static inline void em_x270_init_camera(void) {} #endif +static struct regulator_bulk_data em_x270_gps_consumer_supply = { + .supply = "vcc gps", +}; + +static struct regulator_userspace_consumer_data em_x270_gps_consumer_data = { + .name = "vcc gps", + .num_supplies = 1, + .supplies = &em_x270_gps_consumer_supply, +}; + +static struct platform_device em_x270_gps_userspace_consumer = { + .name = "reg-userspace-consumer", + .id = 0, + .dev = { + .platform_data = &em_x270_gps_consumer_data, + }, +}; + +static struct regulator_bulk_data em_x270_gprs_consumer_supply = { + .supply = "vcc gprs", +}; + +static struct regulator_userspace_consumer_data em_x270_gprs_consumer_data = { + .name = "vcc gprs", + .num_supplies = 1, + .supplies = &em_x270_gprs_consumer_supply +}; + +static struct platform_device em_x270_gprs_userspace_consumer = { + .name = "reg-userspace-consumer", + .id = 1, + .dev = { + .platform_data = &em_x270_gprs_consumer_data, + } +}; + +static struct platform_device *em_x270_userspace_consumers[] = { + &em_x270_gps_userspace_consumer, + &em_x270_gprs_userspace_consumer, +}; + +static void __init em_x270_userspace_consumers_init(void) +{ + platform_add_devices(ARRAY_AND_SIZE(em_x270_userspace_consumers)); +} + /* DA9030 related initializations */ #define REGULATOR_CONSUMER(_name, _dev, _supply) \ static struct regulator_consumer_supply _name##_consumers[] = { \ @@ -952,11 +1098,11 @@ static inline void em_x270_init_camera(void) {} }, \ } -REGULATOR_CONSUMER(ldo3, NULL, "vcc gps"); +REGULATOR_CONSUMER(ldo3, &em_x270_gps_userspace_consumer.dev, "vcc gps"); REGULATOR_CONSUMER(ldo5, NULL, "vcc cam"); REGULATOR_CONSUMER(ldo10, &pxa_device_mci.dev, "vcc sdio"); REGULATOR_CONSUMER(ldo12, NULL, "vcc usb"); -REGULATOR_CONSUMER(ldo19, NULL, "vcc gprs"); +REGULATOR_CONSUMER(ldo19, &em_x270_gprs_userspace_consumer.dev, "vcc gprs"); #define REGULATOR_INIT(_ldo, _min_uV, _max_uV, _ops_mask) \ static struct regulator_init_data _ldo##_data = { \ @@ -967,6 +1113,7 @@ REGULATOR_CONSUMER(ldo19, NULL, "vcc gprs"); .enabled = 0, \ }, \ .valid_ops_mask = _ops_mask, \ + .apply_uV = 1, \ }, \ .num_consumer_supplies = ARRAY_SIZE(_ldo##_consumers), \ .consumer_supplies = _ldo##_consumers, \ @@ -985,7 +1132,7 @@ struct led_info em_x270_led_info = { }; struct power_supply_info em_x270_psy_info = { - .name = "LP555597P6H-FPS", + .name = "battery", .technology = POWER_SUPPLY_TECHNOLOGY_LIPO, .voltage_max_design = 4200000, .voltage_min_design = 3000000, @@ -1069,6 +1216,29 @@ static void __init em_x270_init_da9030(void) i2c_register_board_info(1, &em_x270_i2c_pmic_info, 1); } +static struct pca953x_platform_data exeda_gpio_ext_pdata = { + .gpio_base = 128, +}; + +static struct i2c_board_info exeda_i2c_info[] = { + { + I2C_BOARD_INFO("pca9555", 0x21), + .platform_data = &exeda_gpio_ext_pdata, + }, +}; + +static struct i2c_pxa_platform_data em_x270_i2c_info = { + .fast_mode = 1, +}; + +static void __init em_x270_init_i2c(void) +{ + pxa_set_i2c_info(&em_x270_i2c_info); + + if (machine_is_exeda()) + i2c_register_board_info(0, ARRAY_AND_SIZE(exeda_i2c_info)); +} + static void __init em_x270_module_init(void) { pr_info("%s\n", __func__); @@ -1077,6 +1247,8 @@ static void __init em_x270_module_init(void) mmc_cd = GPIO13_MMC_CD; nand_rb = GPIO56_NAND_RB; dm9000_flags = DM9000_PLATF_32BITONLY; + cam_reset = GPIO93_CAM_RESET; + usb_hub_reset = GPIO16_USB_HUB_RESET; } static void __init em_x270_exeda_init(void) @@ -1087,12 +1259,18 @@ static void __init em_x270_exeda_init(void) mmc_cd = GPIO114_MMC_CD; nand_rb = GPIO20_NAND_RB; dm9000_flags = DM9000_PLATF_16BITONLY; + cam_reset = GPIO130_CAM_RESET; + usb_hub_reset = GPIO10_USB_HUB_RESET; } static void __init em_x270_init(void) { pxa2xx_mfp_config(ARRAY_AND_SIZE(common_pin_config)); +#ifdef CONFIG_PM + pxa27x_set_pwrmode(PWRMODE_DEEPSLEEP); +#endif + if (machine_is_em_x270()) em_x270_module_init(); else if (machine_is_exeda()) @@ -1111,8 +1289,10 @@ static void __init em_x270_init(void) em_x270_init_keypad(); em_x270_init_gpio_keys(); em_x270_init_ac97(); - em_x270_init_camera(); em_x270_init_spi(); + em_x270_init_i2c(); + em_x270_init_camera(); + em_x270_userspace_consumers_init(); } MACHINE_START(EM_X270, "Compulab EM-X270") diff --git a/arch/arm/mach-pxa/ezx.c b/arch/arm/mach-pxa/ezx.c index 7db966dc29ce..588b265e5755 100644 --- a/arch/arm/mach-pxa/ezx.c +++ b/arch/arm/mach-pxa/ezx.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -25,13 +26,19 @@ #include #include #include -#include +#include #include #include #include "devices.h" #include "generic.h" +#define GPIO12_A780_FLIP_LID 12 +#define GPIO15_A1200_FLIP_LID 15 +#define GPIO15_A910_FLIP_LID 15 +#define GPIO12_E680_LOCK_SWITCH 12 +#define GPIO15_E6_LOCK_SWITCH 15 + static struct platform_pwm_backlight_data ezx_backlight_data = { .pwm_id = 0, .max_brightness = 1023, @@ -88,7 +95,7 @@ static struct pxafb_mach_info ezx_fb_info_2 = { .lcd_conn = LCD_COLOR_TFT_18BPP, }; -static struct platform_device *devices[] __initdata = { +static struct platform_device *ezx_devices[] __initdata = { &ezx_backlight_device, }; @@ -651,6 +658,35 @@ static struct pxa27x_keypad_platform_data e2_keypad_platform_data = { #endif /* CONFIG_MACH_EZX_E2 */ #ifdef CONFIG_MACH_EZX_A780 +/* gpio_keys */ +static struct gpio_keys_button a780_buttons[] = { + [0] = { + .code = SW_LID, + .gpio = GPIO12_A780_FLIP_LID, + .active_low = 0, + .desc = "A780 flip lid", + .type = EV_SW, + .wakeup = 1, + }, +}; + +static struct gpio_keys_platform_data a780_gpio_keys_platform_data = { + .buttons = a780_buttons, + .nbuttons = ARRAY_SIZE(a780_buttons), +}; + +static struct platform_device a780_gpio_keys = { + .name = "gpio-keys", + .id = -1, + .dev = { + .platform_data = &a780_gpio_keys_platform_data, + }, +}; + +static struct platform_device *a780_devices[] __initdata = { + &a780_gpio_keys, +}; + static void __init a780_init(void) { pxa2xx_mfp_config(ARRAY_AND_SIZE(ezx_pin_config)); @@ -663,7 +699,8 @@ static void __init a780_init(void) pxa_set_keypad_info(&a780_keypad_platform_data); - platform_add_devices(devices, ARRAY_SIZE(devices)); + platform_add_devices(ARRAY_AND_SIZE(ezx_devices)); + platform_add_devices(ARRAY_AND_SIZE(a780_devices)); } MACHINE_START(EZX_A780, "Motorola EZX A780") @@ -678,10 +715,39 @@ MACHINE_END #endif #ifdef CONFIG_MACH_EZX_E680 +/* gpio_keys */ +static struct gpio_keys_button e680_buttons[] = { + [0] = { + .code = KEY_SCREENLOCK, + .gpio = GPIO12_E680_LOCK_SWITCH, + .active_low = 0, + .desc = "E680 lock switch", + .type = EV_KEY, + .wakeup = 1, + }, +}; + +static struct gpio_keys_platform_data e680_gpio_keys_platform_data = { + .buttons = e680_buttons, + .nbuttons = ARRAY_SIZE(e680_buttons), +}; + +static struct platform_device e680_gpio_keys = { + .name = "gpio-keys", + .id = -1, + .dev = { + .platform_data = &e680_gpio_keys_platform_data, + }, +}; + static struct i2c_board_info __initdata e680_i2c_board_info[] = { { I2C_BOARD_INFO("tea5767", 0x81) }, }; +static struct platform_device *e680_devices[] __initdata = { + &e680_gpio_keys, +}; + static void __init e680_init(void) { pxa2xx_mfp_config(ARRAY_AND_SIZE(ezx_pin_config)); @@ -695,7 +761,8 @@ static void __init e680_init(void) pxa_set_keypad_info(&e680_keypad_platform_data); - platform_add_devices(devices, ARRAY_SIZE(devices)); + platform_add_devices(ARRAY_AND_SIZE(ezx_devices)); + platform_add_devices(ARRAY_AND_SIZE(e680_devices)); } MACHINE_START(EZX_E680, "Motorola EZX E680") @@ -710,10 +777,39 @@ MACHINE_END #endif #ifdef CONFIG_MACH_EZX_A1200 +/* gpio_keys */ +static struct gpio_keys_button a1200_buttons[] = { + [0] = { + .code = SW_LID, + .gpio = GPIO15_A1200_FLIP_LID, + .active_low = 0, + .desc = "A1200 flip lid", + .type = EV_SW, + .wakeup = 1, + }, +}; + +static struct gpio_keys_platform_data a1200_gpio_keys_platform_data = { + .buttons = a1200_buttons, + .nbuttons = ARRAY_SIZE(a1200_buttons), +}; + +static struct platform_device a1200_gpio_keys = { + .name = "gpio-keys", + .id = -1, + .dev = { + .platform_data = &a1200_gpio_keys_platform_data, + }, +}; + static struct i2c_board_info __initdata a1200_i2c_board_info[] = { { I2C_BOARD_INFO("tea5767", 0x81) }, }; +static struct platform_device *a1200_devices[] __initdata = { + &a1200_gpio_keys, +}; + static void __init a1200_init(void) { pxa2xx_mfp_config(ARRAY_AND_SIZE(ezx_pin_config)); @@ -727,7 +823,8 @@ static void __init a1200_init(void) pxa_set_keypad_info(&a1200_keypad_platform_data); - platform_add_devices(devices, ARRAY_SIZE(devices)); + platform_add_devices(ARRAY_AND_SIZE(ezx_devices)); + platform_add_devices(ARRAY_AND_SIZE(a1200_devices)); } MACHINE_START(EZX_A1200, "Motorola EZX A1200") @@ -742,6 +839,35 @@ MACHINE_END #endif #ifdef CONFIG_MACH_EZX_A910 +/* gpio_keys */ +static struct gpio_keys_button a910_buttons[] = { + [0] = { + .code = SW_LID, + .gpio = GPIO15_A910_FLIP_LID, + .active_low = 0, + .desc = "A910 flip lid", + .type = EV_SW, + .wakeup = 1, + }, +}; + +static struct gpio_keys_platform_data a910_gpio_keys_platform_data = { + .buttons = a910_buttons, + .nbuttons = ARRAY_SIZE(a910_buttons), +}; + +static struct platform_device a910_gpio_keys = { + .name = "gpio-keys", + .id = -1, + .dev = { + .platform_data = &a910_gpio_keys_platform_data, + }, +}; + +static struct platform_device *a910_devices[] __initdata = { + &a910_gpio_keys, +}; + static void __init a910_init(void) { pxa2xx_mfp_config(ARRAY_AND_SIZE(ezx_pin_config)); @@ -754,7 +880,8 @@ static void __init a910_init(void) pxa_set_keypad_info(&a910_keypad_platform_data); - platform_add_devices(devices, ARRAY_SIZE(devices)); + platform_add_devices(ARRAY_AND_SIZE(ezx_devices)); + platform_add_devices(ARRAY_AND_SIZE(a910_devices)); } MACHINE_START(EZX_A910, "Motorola EZX A910") @@ -769,10 +896,39 @@ MACHINE_END #endif #ifdef CONFIG_MACH_EZX_E6 +/* gpio_keys */ +static struct gpio_keys_button e6_buttons[] = { + [0] = { + .code = KEY_SCREENLOCK, + .gpio = GPIO15_E6_LOCK_SWITCH, + .active_low = 0, + .desc = "E6 lock switch", + .type = EV_KEY, + .wakeup = 1, + }, +}; + +static struct gpio_keys_platform_data e6_gpio_keys_platform_data = { + .buttons = e6_buttons, + .nbuttons = ARRAY_SIZE(e6_buttons), +}; + +static struct platform_device e6_gpio_keys = { + .name = "gpio-keys", + .id = -1, + .dev = { + .platform_data = &e6_gpio_keys_platform_data, + }, +}; + static struct i2c_board_info __initdata e6_i2c_board_info[] = { { I2C_BOARD_INFO("tea5767", 0x81) }, }; +static struct platform_device *e6_devices[] __initdata = { + &e6_gpio_keys, +}; + static void __init e6_init(void) { pxa2xx_mfp_config(ARRAY_AND_SIZE(ezx_pin_config)); @@ -786,7 +942,8 @@ static void __init e6_init(void) pxa_set_keypad_info(&e6_keypad_platform_data); - platform_add_devices(devices, ARRAY_SIZE(devices)); + platform_add_devices(ARRAY_AND_SIZE(ezx_devices)); + platform_add_devices(ARRAY_AND_SIZE(e6_devices)); } MACHINE_START(EZX_E6, "Motorola EZX E6") @@ -805,6 +962,9 @@ static struct i2c_board_info __initdata e2_i2c_board_info[] = { { I2C_BOARD_INFO("tea5767", 0x81) }, }; +static struct platform_device *e2_devices[] __initdata = { +}; + static void __init e2_init(void) { pxa2xx_mfp_config(ARRAY_AND_SIZE(ezx_pin_config)); @@ -818,7 +978,8 @@ static void __init e2_init(void) pxa_set_keypad_info(&e2_keypad_platform_data); - platform_add_devices(devices, ARRAY_SIZE(devices)); + platform_add_devices(ARRAY_AND_SIZE(ezx_devices)); + platform_add_devices(ARRAY_AND_SIZE(e2_devices)); } MACHINE_START(EZX_E2, "Motorola EZX E2") diff --git a/arch/arm/mach-pxa/hx4700.c b/arch/arm/mach-pxa/hx4700.c new file mode 100644 index 000000000000..81359d574f88 --- /dev/null +++ b/arch/arm/mach-pxa/hx4700.c @@ -0,0 +1,892 @@ +/* + * Support for HP iPAQ hx4700 PDAs. + * + * Copyright (c) 2008-2009 Philipp Zabel + * + * Based on code: + * Copyright (c) 2004 Hewlett-Packard Company. + * Copyright (c) 2005 SDG Systems, LLC + * Copyright (c) 2006 Anton Vorontsov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include : + * 8c011060: 02 d1 mov.l 8c01106c ,r1 + * 8c011062: 22 4f sts.l pr,@-r15 + * 8c011064: 02 c7 mova 8c011070 ,r0 + * 8c011066: 2b 41 jmp @r1 + * 8c011068: 2a 40 lds r0,pr + * 8c01106a: 09 00 nop + * 8c01106c: 68 24 .word 0x2468 <--- ip + * 8c01106e: 1d 8c .word 0x8c1d + * 8c011070: 26 4f lds.l @r15+,pr <--- ip + MCOUNT_INSN_SIZE + * + * We write 0x8c011070 to 0x8c01106c so that on entry to a() we branch + * past the _mcount call and continue executing code like normal. + */ +static unsigned char *ftrace_nop_replace(unsigned long ip) { + __raw_writel(ip + MCOUNT_INSN_SIZE, ftrace_nop); return ftrace_nop; } -static int is_sh_nop(unsigned char *ip) -{ - return strncmp(ip, ftrace_nop, sizeof(ftrace_nop)); -} - -unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr) +static unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr) { /* Place the address in the memory table. */ - if (addr == CALLER_ADDR) - __raw_writel(addr + MCOUNT_INSN_OFFSET, ftrace_replaced_code); - else - __raw_writel(addr, ftrace_replaced_code); + __raw_writel(addr, ftrace_replaced_code); /* * No locking needed, this must be called via kstop_machine @@ -51,7 +58,7 @@ unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr) return ftrace_replaced_code; } -int ftrace_modify_code(unsigned long ip, unsigned char *old_code, +static int ftrace_modify_code(unsigned long ip, unsigned char *old_code, unsigned char *new_code) { unsigned char replaced[MCOUNT_INSN_SIZE]; @@ -66,13 +73,6 @@ int ftrace_modify_code(unsigned long ip, unsigned char *old_code, * kstop_machine, or before SMP starts. */ - /* - * If we're trying to nop out a call to a function, we instead - * place a call to the address after the memory table. - */ - if (is_sh_nop(new_code) == 0) - __raw_writel(ip + MCOUNT_INSN_SIZE, (unsigned long)new_code); - /* read the text we want to modify */ if (probe_kernel_read(replaced, (void *)ip, MCOUNT_INSN_SIZE)) return -EFAULT; @@ -92,13 +92,13 @@ int ftrace_modify_code(unsigned long ip, unsigned char *old_code, int ftrace_update_ftrace_func(ftrace_func_t func) { - unsigned long ip = (unsigned long)(&ftrace_call); + unsigned long ip = (unsigned long)(&ftrace_call) + MCOUNT_INSN_OFFSET; unsigned char old[MCOUNT_INSN_SIZE], *new; - memcpy(old, (unsigned char *)(ip + MCOUNT_INSN_OFFSET), MCOUNT_INSN_SIZE); + memcpy(old, (unsigned char *)ip, MCOUNT_INSN_SIZE); new = ftrace_call_replace(ip, (unsigned long)func); - return ftrace_modify_code(ip + MCOUNT_INSN_OFFSET, old, new); + return ftrace_modify_code(ip, old, new); } int ftrace_make_nop(struct module *mod, @@ -108,7 +108,7 @@ int ftrace_make_nop(struct module *mod, unsigned long ip = rec->ip; old = ftrace_call_replace(ip, addr); - new = ftrace_nop_replace(); + new = ftrace_nop_replace(ip); return ftrace_modify_code(rec->ip, old, new); } @@ -118,7 +118,7 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) unsigned char *new, *old; unsigned long ip = rec->ip; - old = ftrace_nop_replace(); + old = ftrace_nop_replace(ip); new = ftrace_call_replace(ip, addr); return ftrace_modify_code(rec->ip, old, new); diff --git a/arch/sh/kernel/idle.c b/arch/sh/kernel/idle.c index f35ed0348850..27ff2dc093c7 100644 --- a/arch/sh/kernel/idle.c +++ b/arch/sh/kernel/idle.c @@ -1,7 +1,7 @@ /* * The idle loop for all SuperH platforms. * - * Copyright (C) 2002 - 2008 Paul Mundt + * Copyright (C) 2002 - 2009 Paul Mundt * * 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 @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -79,3 +80,23 @@ void cpu_idle(void) check_pgt_cache(); } } + +static void do_nothing(void *unused) +{ +} + +/* + * cpu_idle_wait - Used to ensure that all the CPUs discard old value of + * pm_idle and update to new pm_idle value. Required while changing pm_idle + * handler on SMP systems. + * + * Caller must have changed pm_idle to the new value before the call. Old + * pm_idle value will not be used by any CPU after the return of this function. + */ +void cpu_idle_wait(void) +{ + smp_mb(); + /* kick all the CPUs so that they exit out of pm_idle */ + smp_call_function(do_nothing, NULL, 1); +} +EXPORT_SYMBOL_GPL(cpu_idle_wait); diff --git a/arch/sh/kernel/init_task.c b/arch/sh/kernel/init_task.c index 80c35ff71d56..1719957c0a69 100644 --- a/arch/sh/kernel/init_task.c +++ b/arch/sh/kernel/init_task.c @@ -10,9 +10,6 @@ static struct signal_struct init_signals = INIT_SIGNALS(init_signals); static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); struct pt_regs fake_swapper_regs; -struct mm_struct init_mm = INIT_MM(init_mm); -EXPORT_SYMBOL(init_mm); - /* * Initial thread structure. * diff --git a/arch/sh/kernel/io.c b/arch/sh/kernel/io.c index 29cf4588fc05..4f85fffaa557 100644 --- a/arch/sh/kernel/io.c +++ b/arch/sh/kernel/io.c @@ -12,6 +12,7 @@ * for more details. */ #include +#include #include #include diff --git a/arch/sh/kernel/io_trapped.c b/arch/sh/kernel/io_trapped.c index c22853b059ef..77dfecb64373 100644 --- a/arch/sh/kernel/io_trapped.c +++ b/arch/sh/kernel/io_trapped.c @@ -267,7 +267,7 @@ static struct mem_access trapped_io_access = { int handle_trapped_io(struct pt_regs *regs, unsigned long address) { mm_segment_t oldfs; - opcode_t instruction; + insn_size_t instruction; int tmp; if (!lookup_tiop(address)) diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c index 3f1372eb0091..3d09062f4682 100644 --- a/arch/sh/kernel/irq.c +++ b/arch/sh/kernel/irq.c @@ -31,39 +31,64 @@ void ack_bad_irq(unsigned int irq) } #if defined(CONFIG_PROC_FS) +/* + * /proc/interrupts printing: + */ +static int show_other_interrupts(struct seq_file *p, int prec) +{ + seq_printf(p, "%*s: %10u\n", prec, "ERR", atomic_read(&irq_err_count)); + return 0; +} + int show_interrupts(struct seq_file *p, void *v) { - int i = *(loff_t *) v, j; - struct irqaction * action; - unsigned long flags; + unsigned long flags, any_count = 0; + int i = *(loff_t *)v, j, prec; + struct irqaction *action; + struct irq_desc *desc; + + if (i > nr_irqs) + return 0; + + for (prec = 3, j = 1000; prec < 10 && j <= nr_irqs; ++prec) + j *= 10; + + if (i == nr_irqs) + return show_other_interrupts(p, prec); if (i == 0) { - seq_puts(p, " "); + seq_printf(p, "%*s", prec + 8, ""); for_each_online_cpu(j) - seq_printf(p, "CPU%d ",j); + seq_printf(p, "CPU%-8d", j); seq_putc(p, '\n'); } - if (i < sh_mv.mv_nr_irqs) { - spin_lock_irqsave(&irq_desc[i].lock, flags); - action = irq_desc[i].action; - if (!action) - goto unlock; - seq_printf(p, "%3d: ",i); - for_each_online_cpu(j) - seq_printf(p, "%10u ", kstat_irqs_cpu(i, j)); - seq_printf(p, " %14s", irq_desc[i].chip->name); - seq_printf(p, "-%-8s", irq_desc[i].name); + desc = irq_to_desc(i); + if (!desc) + return 0; + + spin_lock_irqsave(&desc->lock, flags); + for_each_online_cpu(j) + any_count |= kstat_irqs_cpu(i, j); + action = desc->action; + if (!action && !any_count) + goto out; + + seq_printf(p, "%*d: ", prec, i); + for_each_online_cpu(j) + seq_printf(p, "%10u ", kstat_irqs_cpu(i, j)); + seq_printf(p, " %14s", desc->chip->name); + seq_printf(p, "-%-8s", desc->name); + + if (action) { seq_printf(p, " %s", action->name); - - for (action=action->next; action; action = action->next) + while ((action = action->next) != NULL) seq_printf(p, ", %s", action->name); - seq_putc(p, '\n'); -unlock: - spin_unlock_irqrestore(&irq_desc[i].lock, flags); - } else if (i == sh_mv.mv_nr_irqs) - seq_printf(p, "Err: %10u\n", atomic_read(&irq_err_count)); + } + seq_putc(p, '\n'); +out: + spin_unlock_irqrestore(&desc->lock, flags); return 0; } #endif @@ -254,3 +279,11 @@ void __init init_IRQ(void) irq_ctx_init(smp_processor_id()); } + +#ifdef CONFIG_SPARSE_IRQ +int __init arch_probe_nr_irqs(void) +{ + nr_irqs = sh_mv.mv_nr_irqs; + return 0; +} +#endif diff --git a/arch/sh/kernel/kgdb.c b/arch/sh/kernel/kgdb.c index 7c747e7d71b8..305aad742aec 100644 --- a/arch/sh/kernel/kgdb.c +++ b/arch/sh/kernel/kgdb.c @@ -47,7 +47,7 @@ char in_nmi = 0; /* Set during NMI to prevent re-entry */ /* Calculate the new address for after a step */ static short *get_step_address(struct pt_regs *linux_regs) { - opcode_t op = __raw_readw(linux_regs->pc); + insn_size_t op = __raw_readw(linux_regs->pc); long addr; /* BT */ @@ -134,7 +134,7 @@ static short *get_step_address(struct pt_regs *linux_regs) */ static unsigned long stepped_address; -static opcode_t stepped_opcode; +static insn_size_t stepped_opcode; static void do_single_step(struct pt_regs *linux_regs) { diff --git a/arch/sh/kernel/timers/timer-broadcast.c b/arch/sh/kernel/localtimer.c similarity index 100% rename from arch/sh/kernel/timers/timer-broadcast.c rename to arch/sh/kernel/localtimer.c diff --git a/arch/sh/kernel/machvec.c b/arch/sh/kernel/machvec.c index c1ea41e5812a..548f6607fd0f 100644 --- a/arch/sh/kernel/machvec.c +++ b/arch/sh/kernel/machvec.c @@ -129,6 +129,7 @@ void __init sh_mv_setup(void) mv_set(ioport_map); mv_set(ioport_unmap); mv_set(irq_demux); + mv_set(mode_pins); if (!sh_mv.mv_nr_irqs) sh_mv.mv_nr_irqs = NR_IRQS; diff --git a/arch/sh/kernel/module.c b/arch/sh/kernel/module.c index c43081039dd5..c2efdcde266f 100644 --- a/arch/sh/kernel/module.c +++ b/arch/sh/kernel/module.c @@ -46,8 +46,6 @@ void *module_alloc(unsigned long size) void module_free(struct module *mod, void *module_region) { vfree(module_region); - /* FIXME: If module_region == mod->init_region, trim exception - table entries. */ } /* We don't need anything special. */ @@ -90,7 +88,7 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, * SHmedia, the LSB of the symbol needs to be asserted * for the CPU to be in SHmedia mode when it starts executing * the branch target. */ - relocation |= (sym->st_other & 4); + relocation |= !!(sym->st_other & 4); #endif switch (ELF32_R_TYPE(rel[i].r_info)) { diff --git a/arch/sh/kernel/process_32.c b/arch/sh/kernel/process_32.c index 6d94725d22f2..92d7740faab1 100644 --- a/arch/sh/kernel/process_32.c +++ b/arch/sh/kernel/process_32.c @@ -119,8 +119,6 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) pid = do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); - trace_mark(kernel_arch_kthread_create, "pid %d fn %p", pid, fn); - return pid; } @@ -251,7 +249,8 @@ static void ubc_set_tracing(int asid, unsigned long pc) if (current_cpu_data.type == CPU_SH7729 || current_cpu_data.type == CPU_SH7710 || - current_cpu_data.type == CPU_SH7712) { + current_cpu_data.type == CPU_SH7712 || + current_cpu_data.type == CPU_SH7203){ ctrl_outw(BBR_INST | BBR_READ | BBR_CPU, UBC_BBRA); ctrl_outl(BRCR_PCBA | BRCR_PCTE, UBC_BRCR); } else { @@ -366,11 +365,6 @@ asmlinkage int sys_execve(char __user *ufilename, char __user * __user *uargv, goto out; error = do_execve(filename, uargv, uenvp, regs); - if (error == 0) { - task_lock(current); - current->ptrace &= ~PT_DTRACE; - task_unlock(current); - } putname(filename); out: return error; @@ -407,6 +401,7 @@ asmlinkage void break_point_trap(void) #else ctrl_outw(0, UBC_BBRA); ctrl_outw(0, UBC_BBRB); + ctrl_outl(0, UBC_BRCR); #endif current->thread.ubc_pc = 0; ubc_usercnt -= 1; diff --git a/arch/sh/kernel/process_64.c b/arch/sh/kernel/process_64.c index 96be839040f8..24de74214940 100644 --- a/arch/sh/kernel/process_64.c +++ b/arch/sh/kernel/process_64.c @@ -323,7 +323,6 @@ ATTRIB_NORET void kernel_thread_helper(void *arg, int (*fn)(void *)) int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) { struct pt_regs regs; - int pid; memset(®s, 0, sizeof(regs)); regs.regs[2] = (unsigned long)arg; @@ -333,12 +332,8 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) regs.sr = (1 << 30); /* Ok, create the new process.. */ - pid = do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, + return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); - - trace_mark(kernel_arch_kthread_create, "pid %d fn %p", pid, fn); - - return pid; } /* @@ -529,11 +524,6 @@ asmlinkage int sys_execve(char *ufilename, char **uargv, (char __user * __user *)uargv, (char __user * __user *)uenvp, pregs); - if (error == 0) { - task_lock(current); - current->ptrace &= ~PT_DTRACE; - task_unlock(current); - } putname(filename); out: return error; diff --git a/arch/sh/kernel/ptrace_32.c b/arch/sh/kernel/ptrace_32.c index f7b22dd83b0c..3392e835a374 100644 --- a/arch/sh/kernel/ptrace_32.c +++ b/arch/sh/kernel/ptrace_32.c @@ -334,6 +334,14 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) [(addr - (long)&dummy->fpu) >> 2]; } else if (addr == (long) &dummy->u_fpvalid) tmp = !!tsk_used_math(child); + else if (addr == PT_TEXT_ADDR) + tmp = child->mm->start_code; + else if (addr == PT_DATA_ADDR) + tmp = child->mm->start_data; + else if (addr == PT_TEXT_END_ADDR) + tmp = child->mm->end_code; + else if (addr == PT_TEXT_LEN) + tmp = child->mm->end_code - child->mm->start_code; else tmp = 0; ret = put_user(tmp, datap); diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c index 04a6004fccc4..dd38338553ef 100644 --- a/arch/sh/kernel/setup.c +++ b/arch/sh/kernel/setup.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -155,7 +156,7 @@ static void __init reserve_crashkernel(void) &crash_size, &crash_base); if (ret == 0 && crash_size) { if (crash_base <= 0) { - vp = alloc_bootmem_nopanic(crash_size); + vp = alloc_bootmem_nopanic(crash_size); if (!vp) { printk(KERN_INFO "crashkernel allocation " "failed\n"); @@ -184,7 +185,6 @@ static inline void __init reserve_crashkernel(void) {} #endif -#ifndef CONFIG_GENERIC_CALIBRATE_DELAY void __cpuinit calibrate_delay(void) { struct clk *clk = clk_get(NULL, "cpu_clk"); @@ -200,7 +200,6 @@ void __cpuinit calibrate_delay(void) (loops_per_jiffy/(5000/HZ)) % 100, loops_per_jiffy); } -#endif void __init __add_active_range(unsigned int nid, unsigned long start_pfn, unsigned long end_pfn) @@ -328,6 +327,10 @@ static int __init parse_elfcorehdr(char *arg) early_param("elfcorehdr", parse_elfcorehdr); #endif +void __init __attribute__ ((weak)) plat_early_device_setup(void) +{ +} + void __init setup_arch(char **cmdline_p) { enable_mmu(); @@ -381,6 +384,8 @@ void __init setup_arch(char **cmdline_p) parse_early_param(); + plat_early_device_setup(); + sh_mv_setup(); /* @@ -415,6 +420,18 @@ void __init setup_arch(char **cmdline_p) #endif } +/* processor boot mode configuration */ +int generic_mode_pins(void) +{ + pr_warning("generic_mode_pins(): missing mode pin configuration\n"); + return 0; +} + +int test_mode_pin(int pin) +{ + return sh_mv.mv_mode_pins() & pin; +} + static const char *cpu_name[] = { [CPU_SH7201] = "SH7201", [CPU_SH7203] = "SH7203", [CPU_SH7263] = "SH7263", @@ -435,7 +452,8 @@ static const char *cpu_name[] = { [CPU_SH7722] = "SH7722", [CPU_SHX3] = "SH-X3", [CPU_SH5_101] = "SH5-101", [CPU_SH5_103] = "SH5-103", [CPU_MXG] = "MX-G", [CPU_SH7723] = "SH7723", - [CPU_SH7366] = "SH7366", [CPU_SH_NONE] = "Unknown" + [CPU_SH7366] = "SH7366", [CPU_SH7724] = "SH7724", + [CPU_SH_NONE] = "Unknown" }; const char *get_cpu_subtype(struct sh_cpuinfo *c) diff --git a/arch/sh/kernel/sh_ksyms_32.c b/arch/sh/kernel/sh_ksyms_32.c index 528de2955c81..fcc5de31f83b 100644 --- a/arch/sh/kernel/sh_ksyms_32.c +++ b/arch/sh/kernel/sh_ksyms_32.c @@ -19,14 +19,10 @@ #include extern int dump_fpu(struct pt_regs *, elf_fpregset_t *); -extern struct hw_interrupt_type no_irq_type; /* platform dependent support */ EXPORT_SYMBOL(dump_fpu); EXPORT_SYMBOL(kernel_thread); -EXPORT_SYMBOL(irq_desc); -EXPORT_SYMBOL(no_irq_type); - EXPORT_SYMBOL(strlen); /* PCI exports */ @@ -41,11 +37,6 @@ EXPORT_SYMBOL(memcpy); EXPORT_SYMBOL(memset); EXPORT_SYMBOL(memmove); EXPORT_SYMBOL(__copy_user); - -#ifdef CONFIG_MMU -EXPORT_SYMBOL(get_vm_area); -#endif - EXPORT_SYMBOL(__udelay); EXPORT_SYMBOL(__ndelay); EXPORT_SYMBOL(__const_udelay); diff --git a/arch/sh/kernel/sh_ksyms_64.c b/arch/sh/kernel/sh_ksyms_64.c index 0d74d6b8774e..f5bd156ea504 100644 --- a/arch/sh/kernel/sh_ksyms_64.c +++ b/arch/sh/kernel/sh_ksyms_64.c @@ -38,13 +38,6 @@ EXPORT_SYMBOL(clear_user_page); EXPORT_SYMBOL(flush_dcache_page); #endif -/* Networking helper routines. */ -EXPORT_SYMBOL(csum_partial); -EXPORT_SYMBOL(csum_partial_copy_nocheck); -#ifdef CONFIG_IPV6 -EXPORT_SYMBOL(csum_ipv6_magic); -#endif - #ifdef CONFIG_VT EXPORT_SYMBOL(screen_info); #endif @@ -76,5 +69,7 @@ EXPORT_SYMBOL(strcpy); #define DECLARE_EXPORT(name) extern void name(void);EXPORT_SYMBOL(name) DECLARE_EXPORT(__sdivsi3); +DECLARE_EXPORT(__sdivsi3_1); +DECLARE_EXPORT(__sdivsi3_2); DECLARE_EXPORT(__udivsi3); DECLARE_EXPORT(__div_table); diff --git a/arch/sh/kernel/signal_32.c b/arch/sh/kernel/signal_32.c index 17784e19ae34..b5afbec1db59 100644 --- a/arch/sh/kernel/signal_32.c +++ b/arch/sh/kernel/signal_32.c @@ -332,8 +332,8 @@ get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size) /* These symbols are defined with the addresses in the vsyscall page. See vsyscall-trapa.S. */ -extern void __user __kernel_sigreturn; -extern void __user __kernel_rt_sigreturn; +extern void __kernel_sigreturn(void); +extern void __kernel_rt_sigreturn(void); static int setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs *regs) diff --git a/arch/sh/kernel/smp.c b/arch/sh/kernel/smp.c index 8f4027412614..442d8d47a41e 100644 --- a/arch/sh/kernel/smp.c +++ b/arch/sh/kernel/smp.c @@ -47,7 +47,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus) plat_prepare_cpus(max_cpus); #ifndef CONFIG_HOTPLUG_CPU - cpu_present_map = cpu_possible_map; + init_cpu_present(&cpu_possible_map); #endif } @@ -58,8 +58,8 @@ void __devinit smp_prepare_boot_cpu(void) __cpu_number_map[0] = cpu; __cpu_logical_map[0] = cpu; - cpu_set(cpu, cpu_online_map); - cpu_set(cpu, cpu_possible_map); + set_cpu_online(cpu, true); + set_cpu_possible(cpu, true); } asmlinkage void __cpuinit start_secondary(void) @@ -171,11 +171,11 @@ void smp_send_stop(void) smp_call_function(stop_this_cpu, 0, 0); } -void arch_send_call_function_ipi(cpumask_t mask) +void arch_send_call_function_ipi_mask(const struct cpumask *mask) { int cpu; - for_each_cpu_mask(cpu, mask) + for_each_cpu(cpu, mask) plat_send_ipi(cpu, SMP_MSG_FUNCTION); } diff --git a/arch/sh/kernel/sys_sh.c b/arch/sh/kernel/sys_sh.c index e3a7e36639ef..90d00e47264d 100644 --- a/arch/sh/kernel/sys_sh.c +++ b/arch/sh/kernel/sys_sh.c @@ -88,8 +88,6 @@ asmlinkage int sys_ipc(uint call, int first, int second, version = call >> 16; /* hack for backward compatibility */ call &= 0xffff; - trace_mark(kernel_arch_ipc_call, "call %u first %d", call, first); - if (call <= SEMTIMEDOP) switch (call) { case SEMOP: diff --git a/arch/sh/kernel/syscalls_32.S b/arch/sh/kernel/syscalls_32.S index 05202edd8e21..f9e21fa2f592 100644 --- a/arch/sh/kernel/syscalls_32.S +++ b/arch/sh/kernel/syscalls_32.S @@ -350,4 +350,6 @@ ENTRY(sys_call_table) .long sys_pipe2 .long sys_inotify_init1 .long sys_preadv - .long sys_writev + .long sys_pwritev + .long sys_rt_tgsigqueueinfo /* 335 */ + .long sys_perf_counter_open diff --git a/arch/sh/kernel/syscalls_64.S b/arch/sh/kernel/syscalls_64.S index a083609f9284..bf420b616ae0 100644 --- a/arch/sh/kernel/syscalls_64.S +++ b/arch/sh/kernel/syscalls_64.S @@ -389,3 +389,5 @@ sys_call_table: .long sys_inotify_init1 /* 360 */ .long sys_preadv .long sys_pwritev + .long sys_rt_tgsigqueueinfo + .long sys_perf_counter_open diff --git a/arch/sh/kernel/time.c b/arch/sh/kernel/time.c new file mode 100644 index 000000000000..9b352a1e3fb4 --- /dev/null +++ b/arch/sh/kernel/time.c @@ -0,0 +1,120 @@ +/* + * arch/sh/kernel/time.c + * + * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka + * Copyright (C) 2000 Philipp Rumpf + * Copyright (C) 2002 - 2009 Paul Mundt + * Copyright (C) 2002 M. R. Brown + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Dummy RTC ops */ +static void null_rtc_get_time(struct timespec *tv) +{ + tv->tv_sec = mktime(2000, 1, 1, 0, 0, 0); + tv->tv_nsec = 0; +} + +static int null_rtc_set_time(const time_t secs) +{ + return 0; +} + +void (*rtc_sh_get_time)(struct timespec *) = null_rtc_get_time; +int (*rtc_sh_set_time)(const time_t) = null_rtc_set_time; + +#ifdef CONFIG_GENERIC_CMOS_UPDATE +unsigned long read_persistent_clock(void) +{ + struct timespec tv; + rtc_sh_get_time(&tv); + return tv.tv_sec; +} + +int update_persistent_clock(struct timespec now) +{ + return rtc_sh_set_time(now.tv_sec); +} +#endif + +unsigned int get_rtc_time(struct rtc_time *tm) +{ + if (rtc_sh_get_time != null_rtc_get_time) { + struct timespec tv; + + rtc_sh_get_time(&tv); + rtc_time_to_tm(tv.tv_sec, tm); + } + + return RTC_24H; +} +EXPORT_SYMBOL(get_rtc_time); + +int set_rtc_time(struct rtc_time *tm) +{ + unsigned long secs; + + rtc_tm_to_time(tm, &secs); + return rtc_sh_set_time(secs); +} +EXPORT_SYMBOL(set_rtc_time); + +static int __init rtc_generic_init(void) +{ + struct platform_device *pdev; + + if (rtc_sh_get_time == null_rtc_get_time) + return -ENODEV; + + pdev = platform_device_register_simple("rtc-generic", -1, NULL, 0); + if (IS_ERR(pdev)) + return PTR_ERR(pdev); + + return 0; +} +module_init(rtc_generic_init); + +void (*board_time_init)(void); + +void __init time_init(void) +{ + if (board_time_init) + board_time_init(); + + clk_init(); + + rtc_sh_get_time(&xtime); + set_normalized_timespec(&wall_to_monotonic, + -xtime.tv_sec, -xtime.tv_nsec); + +#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST + local_timer_setup(smp_processor_id()); +#endif + + /* + * Make sure all compiled-in early timers register themselves. + * + * Run probe() for two "earlytimer" devices, these will be the + * clockevents and clocksource devices respectively. In the event + * that only a clockevents device is available, we -ENODEV on the + * clocksource and the jiffies clocksource is used transparently + * instead. No error handling is necessary here. + */ + early_platform_driver_register_all("earlytimer"); + early_platform_driver_probe("earlytimer", 2, 0); +} diff --git a/arch/sh/kernel/time_32.c b/arch/sh/kernel/time_32.c deleted file mode 100644 index 1700d2465f6c..000000000000 --- a/arch/sh/kernel/time_32.c +++ /dev/null @@ -1,240 +0,0 @@ -/* - * arch/sh/kernel/time_32.c - * - * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka - * Copyright (C) 2000 Philipp Rumpf - * Copyright (C) 2002 - 2008 Paul Mundt - * Copyright (C) 2002 M. R. Brown - * - * Some code taken from i386 version. - * Copyright (C) 1991, 1992, 1995 Linus Torvalds - */ -#include -#include -#include -#include -#include -#include -#include -#include /* for rtc_lock */ -#include -#include -#include -#include -#include - -struct sys_timer *sys_timer; - -/* Move this somewhere more sensible.. */ -DEFINE_SPINLOCK(rtc_lock); -EXPORT_SYMBOL(rtc_lock); - -/* Dummy RTC ops */ -static void null_rtc_get_time(struct timespec *tv) -{ - tv->tv_sec = mktime(2000, 1, 1, 0, 0, 0); - tv->tv_nsec = 0; -} - -static int null_rtc_set_time(const time_t secs) -{ - return 0; -} - -void (*rtc_sh_get_time)(struct timespec *) = null_rtc_get_time; -int (*rtc_sh_set_time)(const time_t) = null_rtc_set_time; - -#ifndef CONFIG_GENERIC_TIME -void do_gettimeofday(struct timeval *tv) -{ - unsigned long flags; - unsigned long seq; - unsigned long usec, sec; - - do { - /* - * Turn off IRQs when grabbing xtime_lock, so that - * the sys_timer get_offset code doesn't have to handle it. - */ - seq = read_seqbegin_irqsave(&xtime_lock, flags); - usec = get_timer_offset(); - sec = xtime.tv_sec; - usec += xtime.tv_nsec / NSEC_PER_USEC; - } while (read_seqretry_irqrestore(&xtime_lock, seq, flags)); - - while (usec >= 1000000) { - usec -= 1000000; - sec++; - } - - tv->tv_sec = sec; - tv->tv_usec = usec; -} -EXPORT_SYMBOL(do_gettimeofday); - -int do_settimeofday(struct timespec *tv) -{ - time_t wtm_sec, sec = tv->tv_sec; - long wtm_nsec, nsec = tv->tv_nsec; - - if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) - return -EINVAL; - - write_seqlock_irq(&xtime_lock); - /* - * This is revolting. We need to set "xtime" correctly. However, the - * value in this location is the value at the most recent update of - * wall time. Discover what correction gettimeofday() would have - * made, and then undo it! - */ - nsec -= get_timer_offset() * NSEC_PER_USEC; - - wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec); - wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec); - - set_normalized_timespec(&xtime, sec, nsec); - set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec); - - ntp_clear(); - write_sequnlock_irq(&xtime_lock); - clock_was_set(); - - return 0; -} -EXPORT_SYMBOL(do_settimeofday); -#endif /* !CONFIG_GENERIC_TIME */ - -/* last time the RTC clock got updated */ -static long last_rtc_update; - -/* - * handle_timer_tick() needs to keep up the real-time clock, - * as well as call the "do_timer()" routine every clocktick - */ -void handle_timer_tick(void) -{ - if (current->pid) - profile_tick(CPU_PROFILING); - - /* - * Here we are in the timer irq handler. We just have irqs locally - * disabled but we don't know if the timer_bh is running on the other - * CPU. We need to avoid to SMP race with it. NOTE: we don' t need - * the irq version of write_lock because as just said we have irq - * locally disabled. -arca - */ - write_seqlock(&xtime_lock); - do_timer(1); - - /* - * If we have an externally synchronized Linux clock, then update - * RTC clock accordingly every ~11 minutes. Set_rtc_mmss() has to be - * called as close as possible to 500 ms before the new second starts. - */ - if (ntp_synced() && - xtime.tv_sec > last_rtc_update + 660 && - (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 && - (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) { - if (rtc_sh_set_time(xtime.tv_sec) == 0) - last_rtc_update = xtime.tv_sec; - else - /* do it again in 60s */ - last_rtc_update = xtime.tv_sec - 600; - } - write_sequnlock(&xtime_lock); - -#ifndef CONFIG_SMP - update_process_times(user_mode(get_irq_regs())); -#endif -} - -#ifdef CONFIG_PM -int timer_suspend(struct sys_device *dev, pm_message_t state) -{ - struct sys_timer *sys_timer = container_of(dev, struct sys_timer, dev); - - sys_timer->ops->stop(); - - return 0; -} - -int timer_resume(struct sys_device *dev) -{ - struct sys_timer *sys_timer = container_of(dev, struct sys_timer, dev); - - sys_timer->ops->start(); - - return 0; -} -#else -#define timer_suspend NULL -#define timer_resume NULL -#endif - -static struct sysdev_class timer_sysclass = { - .name = "timer", - .suspend = timer_suspend, - .resume = timer_resume, -}; - -static int __init timer_init_sysfs(void) -{ - int ret; - - if (!sys_timer) - return 0; - - ret = sysdev_class_register(&timer_sysclass); - if (ret != 0) - return ret; - - sys_timer->dev.cls = &timer_sysclass; - return sysdev_register(&sys_timer->dev); -} -device_initcall(timer_init_sysfs); - -void (*board_time_init)(void); - -struct clocksource clocksource_sh = { - .name = "SuperH", -}; - -#ifdef CONFIG_GENERIC_TIME -unsigned long long sched_clock(void) -{ - unsigned long long cycles; - - /* jiffies based sched_clock if no clocksource is installed */ - if (!clocksource_sh.rating) - return (unsigned long long)jiffies * (NSEC_PER_SEC / HZ); - - cycles = clocksource_sh.read(&clocksource_sh); - return cyc2ns(&clocksource_sh, cycles); -} -#endif - -void __init time_init(void) -{ - if (board_time_init) - board_time_init(); - - clk_init(); - - rtc_sh_get_time(&xtime); - set_normalized_timespec(&wall_to_monotonic, - -xtime.tv_sec, -xtime.tv_nsec); - -#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST - local_timer_setup(smp_processor_id()); -#endif - - /* - * Find the timer to use as the system timer, it will be - * initialized for us. - */ - sys_timer = get_sys_timer(); - if (unlikely(!sys_timer)) - panic("System timer missing.\n"); - - printk(KERN_INFO "Using %s for system timer\n", sys_timer->name); -} diff --git a/arch/sh/kernel/time_64.c b/arch/sh/kernel/time_64.c deleted file mode 100644 index 988c77c37231..000000000000 --- a/arch/sh/kernel/time_64.c +++ /dev/null @@ -1,363 +0,0 @@ -/* - * arch/sh/kernel/time_64.c - * - * Copyright (C) 2000, 2001 Paolo Alberelli - * Copyright (C) 2003 - 2007 Paul Mundt - * Copyright (C) 2003 Richard Curnow - * - * Original TMU/RTC code taken from sh version. - * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka - * Some code taken from i386 version. - * Copyright (C) 1991, 1992, 1995 Linus Torvalds - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* required by inline __asm__ stmt. */ -#include -#include -#include -#include -#include -#include - -#define TMU_TOCR_INIT 0x00 -#define TMU0_TCR_INIT 0x0020 -#define TMU_TSTR_INIT 1 -#define TMU_TSTR_OFF 0 - -/* Real Time Clock */ -#define RTC_BLOCK_OFF 0x01040000 -#define RTC_BASE PHYS_PERIPHERAL_BLOCK + RTC_BLOCK_OFF -#define RTC_RCR1_CIE 0x10 /* Carry Interrupt Enable */ -#define RTC_RCR1 (rtc_base + 0x38) - -/* Time Management Unit */ -#define TMU_BLOCK_OFF 0x01020000 -#define TMU_BASE PHYS_PERIPHERAL_BLOCK + TMU_BLOCK_OFF -#define TMU0_BASE tmu_base + 0x8 + (0xc * 0x0) -#define TMU1_BASE tmu_base + 0x8 + (0xc * 0x1) -#define TMU2_BASE tmu_base + 0x8 + (0xc * 0x2) - -#define TMU_TOCR tmu_base+0x0 /* Byte access */ -#define TMU_TSTR tmu_base+0x4 /* Byte access */ - -#define TMU0_TCOR TMU0_BASE+0x0 /* Long access */ -#define TMU0_TCNT TMU0_BASE+0x4 /* Long access */ -#define TMU0_TCR TMU0_BASE+0x8 /* Word access */ - -#define TICK_SIZE (tick_nsec / 1000) - -static unsigned long tmu_base, rtc_base; -unsigned long cprc_base; - -/* Variables to allow interpolation of time of day to resolution better than a - * jiffy. */ - -/* This is effectively protected by xtime_lock */ -static unsigned long ctc_last_interrupt; -static unsigned long long usecs_per_jiffy = 1000000/HZ; /* Approximation */ - -#define CTC_JIFFY_SCALE_SHIFT 40 - -/* 2**CTC_JIFFY_SCALE_SHIFT / ctc_ticks_per_jiffy */ -static unsigned long long scaled_recip_ctc_ticks_per_jiffy; - -/* Estimate number of microseconds that have elapsed since the last timer tick, - by scaling the delta that has occurred in the CTC register. - - WARNING WARNING WARNING : This algorithm relies on the CTC decrementing at - the CPU clock rate. If the CPU sleeps, the CTC stops counting. Bear this - in mind if enabling SLEEP_WORKS in process.c. In that case, this algorithm - probably needs to use TMU.TCNT0 instead. This will work even if the CPU is - sleeping, though will be coarser. - - FIXME : What if usecs_per_tick is moving around too much, e.g. if an adjtime - is running or if the freq or tick arguments of adjtimex are modified after - we have calibrated the scaling factor? This will result in either a jump at - the end of a tick period, or a wrap backwards at the start of the next one, - if the application is reading the time of day often enough. I think we - ought to do better than this. For this reason, usecs_per_jiffy is left - separated out in the calculation below. This allows some future hook into - the adjtime-related stuff in kernel/timer.c to remove this hazard. - -*/ - -static unsigned long usecs_since_tick(void) -{ - unsigned long long current_ctc; - long ctc_ticks_since_interrupt; - unsigned long long ull_ctc_ticks_since_interrupt; - unsigned long result; - - unsigned long long mul1_out; - unsigned long long mul1_out_high; - unsigned long long mul2_out_low, mul2_out_high; - - /* Read CTC register */ - asm ("getcon cr62, %0" : "=r" (current_ctc)); - /* Note, the CTC counts down on each CPU clock, not up. - Note(2), use long type to get correct wraparound arithmetic when - the counter crosses zero. */ - ctc_ticks_since_interrupt = (long) ctc_last_interrupt - (long) current_ctc; - ull_ctc_ticks_since_interrupt = (unsigned long long) ctc_ticks_since_interrupt; - - /* Inline assembly to do 32x32x32->64 multiplier */ - asm volatile ("mulu.l %1, %2, %0" : - "=r" (mul1_out) : - "r" (ull_ctc_ticks_since_interrupt), "r" (usecs_per_jiffy)); - - mul1_out_high = mul1_out >> 32; - - asm volatile ("mulu.l %1, %2, %0" : - "=r" (mul2_out_low) : - "r" (mul1_out), "r" (scaled_recip_ctc_ticks_per_jiffy)); - -#if 1 - asm volatile ("mulu.l %1, %2, %0" : - "=r" (mul2_out_high) : - "r" (mul1_out_high), "r" (scaled_recip_ctc_ticks_per_jiffy)); -#endif - - result = (unsigned long) (((mul2_out_high << 32) + mul2_out_low) >> CTC_JIFFY_SCALE_SHIFT); - - return result; -} - -void do_gettimeofday(struct timeval *tv) -{ - unsigned long flags; - unsigned long seq; - unsigned long usec, sec; - - do { - seq = read_seqbegin_irqsave(&xtime_lock, flags); - usec = usecs_since_tick(); - sec = xtime.tv_sec; - usec += xtime.tv_nsec / 1000; - } while (read_seqretry_irqrestore(&xtime_lock, seq, flags)); - - while (usec >= 1000000) { - usec -= 1000000; - sec++; - } - - tv->tv_sec = sec; - tv->tv_usec = usec; -} -EXPORT_SYMBOL(do_gettimeofday); - -int do_settimeofday(struct timespec *tv) -{ - time_t wtm_sec, sec = tv->tv_sec; - long wtm_nsec, nsec = tv->tv_nsec; - - if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) - return -EINVAL; - - write_seqlock_irq(&xtime_lock); - /* - * This is revolting. We need to set "xtime" correctly. However, the - * value in this location is the value at the most recent update of - * wall time. Discover what correction gettimeofday() would have - * made, and then undo it! - */ - nsec -= 1000 * usecs_since_tick(); - - wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec); - wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec); - - set_normalized_timespec(&xtime, sec, nsec); - set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec); - - ntp_clear(); - write_sequnlock_irq(&xtime_lock); - clock_was_set(); - - return 0; -} -EXPORT_SYMBOL(do_settimeofday); - -/* Dummy RTC ops */ -static void null_rtc_get_time(struct timespec *tv) -{ - tv->tv_sec = mktime(2000, 1, 1, 0, 0, 0); - tv->tv_nsec = 0; -} - -static int null_rtc_set_time(const time_t secs) -{ - return 0; -} - -void (*rtc_sh_get_time)(struct timespec *) = null_rtc_get_time; -int (*rtc_sh_set_time)(const time_t) = null_rtc_set_time; - -/* last time the RTC clock got updated */ -static long last_rtc_update; - -/* - * timer_interrupt() needs to keep up the real-time clock, - * as well as call the "do_timer()" routine every clocktick - */ -static inline void do_timer_interrupt(void) -{ - unsigned long long current_ctc; - - if (current->pid) - profile_tick(CPU_PROFILING); - - /* - * Here we are in the timer irq handler. We just have irqs locally - * disabled but we don't know if the timer_bh is running on the other - * CPU. We need to avoid to SMP race with it. NOTE: we don' t need - * the irq version of write_lock because as just said we have irq - * locally disabled. -arca - */ - write_seqlock(&xtime_lock); - asm ("getcon cr62, %0" : "=r" (current_ctc)); - ctc_last_interrupt = (unsigned long) current_ctc; - - do_timer(1); - - /* - * If we have an externally synchronized Linux clock, then update - * RTC clock accordingly every ~11 minutes. Set_rtc_mmss() has to be - * called as close as possible to 500 ms before the new second starts. - */ - if (ntp_synced() && - xtime.tv_sec > last_rtc_update + 660 && - (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 && - (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) { - if (rtc_sh_set_time(xtime.tv_sec) == 0) - last_rtc_update = xtime.tv_sec; - else - /* do it again in 60 s */ - last_rtc_update = xtime.tv_sec - 600; - } - write_sequnlock(&xtime_lock); - -#ifndef CONFIG_SMP - update_process_times(user_mode(get_irq_regs())); -#endif -} - -/* - * This is the same as the above, except we _also_ save the current - * Time Stamp Counter value at the time of the timer interrupt, so that - * we later on can estimate the time of day more exactly. - */ -static irqreturn_t timer_interrupt(int irq, void *dev_id) -{ - unsigned long timer_status; - - /* Clear UNF bit */ - timer_status = ctrl_inw(TMU0_TCR); - timer_status &= ~0x100; - ctrl_outw(timer_status, TMU0_TCR); - - do_timer_interrupt(); - - return IRQ_HANDLED; -} - -static struct irqaction irq0 = { - .handler = timer_interrupt, - .flags = IRQF_DISABLED, - .name = "timer", -}; - -void __init time_init(void) -{ - unsigned long interval; - struct clk *clk; - - tmu_base = onchip_remap(TMU_BASE, 1024, "TMU"); - if (!tmu_base) { - panic("Unable to remap TMU\n"); - } - - rtc_base = onchip_remap(RTC_BASE, 1024, "RTC"); - if (!rtc_base) { - panic("Unable to remap RTC\n"); - } - - clk = clk_get(NULL, "cpu_clk"); - scaled_recip_ctc_ticks_per_jiffy = ((1ULL << CTC_JIFFY_SCALE_SHIFT) / - (unsigned long long)(clk_get_rate(clk) / HZ)); - - rtc_sh_get_time(&xtime); - - setup_irq(TIMER_IRQ, &irq0); - - clk = clk_get(NULL, "module_clk"); - interval = (clk_get_rate(clk)/(HZ*4)); - - printk("Interval = %ld\n", interval); - - /* Start TMU0 */ - ctrl_outb(TMU_TSTR_OFF, TMU_TSTR); - ctrl_outb(TMU_TOCR_INIT, TMU_TOCR); - ctrl_outw(TMU0_TCR_INIT, TMU0_TCR); - ctrl_outl(interval, TMU0_TCOR); - ctrl_outl(interval, TMU0_TCNT); - ctrl_outb(TMU_TSTR_INIT, TMU_TSTR); -} - -static struct resource rtc_resources[] = { - [0] = { - /* RTC base, filled in by rtc_init */ - .flags = IORESOURCE_IO, - }, - [1] = { - /* Period IRQ */ - .start = IRQ_PRI, - .flags = IORESOURCE_IRQ, - }, - [2] = { - /* Carry IRQ */ - .start = IRQ_CUI, - .flags = IORESOURCE_IRQ, - }, - [3] = { - /* Alarm IRQ */ - .start = IRQ_ATI, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct platform_device rtc_device = { - .name = "sh-rtc", - .id = -1, - .num_resources = ARRAY_SIZE(rtc_resources), - .resource = rtc_resources, -}; - -static int __init rtc_init(void) -{ - rtc_resources[0].start = rtc_base; - rtc_resources[0].end = rtc_resources[0].start + 0x58 - 1; - - return platform_device_register(&rtc_device); -} -device_initcall(rtc_init); diff --git a/arch/sh/kernel/timers/Makefile b/arch/sh/kernel/timers/Makefile deleted file mode 100644 index 0b7f8577193f..000000000000 --- a/arch/sh/kernel/timers/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# -# Makefile for the various Linux/SuperH timers -# - -obj-y := timer.o - -obj-$(CONFIG_SH_TMU) += timer-tmu.o -obj-$(CONFIG_SH_MTU2) += timer-mtu2.o -obj-$(CONFIG_SH_CMT) += timer-cmt.o - -obj-$(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) += timer-broadcast.o diff --git a/arch/sh/kernel/timers/timer-cmt.c b/arch/sh/kernel/timers/timer-cmt.c deleted file mode 100644 index 9aa348658ae3..000000000000 --- a/arch/sh/kernel/timers/timer-cmt.c +++ /dev/null @@ -1,188 +0,0 @@ -/* - * arch/sh/kernel/timers/timer-cmt.c - CMT Timer Support - * - * Copyright (C) 2005 Yoshinori Sato - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(CONFIG_CPU_SUBTYPE_SH7619) -#define CMT_CMSTR 0xf84a0070 -#define CMT_CMCSR_0 0xf84a0072 -#define CMT_CMCNT_0 0xf84a0074 -#define CMT_CMCOR_0 0xf84a0076 -#define CMT_CMCSR_1 0xf84a0078 -#define CMT_CMCNT_1 0xf84a007a -#define CMT_CMCOR_1 0xf84a007c - -#define STBCR3 0xf80a0000 -#define cmt_clock_enable() do { ctrl_outb(ctrl_inb(STBCR3) & ~0x10, STBCR3); } while(0) -#define CMT_CMCSR_INIT 0x0040 -#define CMT_CMCSR_CALIB 0x0000 -#elif defined(CONFIG_CPU_SUBTYPE_SH7203) || \ - defined(CONFIG_CPU_SUBTYPE_SH7206) || \ - defined(CONFIG_CPU_SUBTYPE_SH7263) -#define CMT_CMSTR 0xfffec000 -#define CMT_CMCSR_0 0xfffec002 -#define CMT_CMCNT_0 0xfffec004 -#define CMT_CMCOR_0 0xfffec006 - -#define STBCR4 0xfffe040c -#define cmt_clock_enable() do { ctrl_outb(ctrl_inb(STBCR4) & ~0x04, STBCR4); } while(0) -#define CMT_CMCSR_INIT 0x0040 -#define CMT_CMCSR_CALIB 0x0000 -#else -#error "Unknown CPU SUBTYPE" -#endif - -static unsigned long cmt_timer_get_offset(void) -{ - int count; - static unsigned short count_p = 0xffff; /* for the first call after boot */ - static unsigned long jiffies_p = 0; - - /* - * cache volatile jiffies temporarily; we have IRQs turned off. - */ - unsigned long jiffies_t; - - /* timer count may underflow right here */ - count = ctrl_inw(CMT_CMCOR_0); - count -= ctrl_inw(CMT_CMCNT_0); - - jiffies_t = jiffies; - - /* - * avoiding timer inconsistencies (they are rare, but they happen)... - * there is one kind of problem that must be avoided here: - * 1. the timer counter underflows - */ - - if (jiffies_t == jiffies_p) { - if (count > count_p) { - /* the nutcase */ - if (ctrl_inw(CMT_CMCSR_0) & 0x80) { /* Check CMF bit */ - count -= LATCH; - } else { - printk("%s (): hardware timer problem?\n", - __func__); - } - } - } else - jiffies_p = jiffies_t; - - count_p = count; - - count = ((LATCH-1) - count) * TICK_SIZE; - count = (count + LATCH/2) / LATCH; - - return count; -} - -static irqreturn_t cmt_timer_interrupt(int irq, void *dev_id) -{ - unsigned long timer_status; - - /* Clear CMF bit */ - timer_status = ctrl_inw(CMT_CMCSR_0); - timer_status &= ~0x80; - ctrl_outw(timer_status, CMT_CMCSR_0); - - handle_timer_tick(); - - return IRQ_HANDLED; -} - -static struct irqaction cmt_irq = { - .name = "timer", - .handler = cmt_timer_interrupt, - .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, -}; - -static void cmt_clk_init(struct clk *clk) -{ - u8 divisor = CMT_CMCSR_INIT & 0x3; - ctrl_inw(CMT_CMCSR_0); - ctrl_outw(CMT_CMCSR_INIT, CMT_CMCSR_0); - clk->parent = clk_get(NULL, "module_clk"); - clk->rate = clk->parent->rate / (8 << (divisor << 1)); -} - -static void cmt_clk_recalc(struct clk *clk) -{ - u8 divisor = ctrl_inw(CMT_CMCSR_0) & 0x3; - clk->rate = clk->parent->rate / (8 << (divisor << 1)); -} - -static struct clk_ops cmt_clk_ops = { - .init = cmt_clk_init, - .recalc = cmt_clk_recalc, -}; - -static struct clk cmt0_clk = { - .name = "cmt0_clk", - .ops = &cmt_clk_ops, -}; - -static int cmt_timer_start(void) -{ - ctrl_outw(ctrl_inw(CMT_CMSTR) | 0x01, CMT_CMSTR); - return 0; -} - -static int cmt_timer_stop(void) -{ - ctrl_outw(ctrl_inw(CMT_CMSTR) & ~0x01, CMT_CMSTR); - return 0; -} - -static int cmt_timer_init(void) -{ - unsigned long interval; - - cmt_clock_enable(); - - setup_irq(CONFIG_SH_TIMER_IRQ, &cmt_irq); - - cmt0_clk.parent = clk_get(NULL, "module_clk"); - - cmt_timer_stop(); - - interval = cmt0_clk.parent->rate / 8 / HZ; - printk(KERN_INFO "Interval = %ld\n", interval); - - ctrl_outw(interval, CMT_CMCOR_0); - - clk_register(&cmt0_clk); - clk_enable(&cmt0_clk); - - cmt_timer_start(); - - return 0; -} - -static struct sys_timer_ops cmt_timer_ops = { - .init = cmt_timer_init, - .start = cmt_timer_start, - .stop = cmt_timer_stop, -#ifndef CONFIG_GENERIC_TIME - .get_offset = cmt_timer_get_offset, -#endif -}; - -struct sys_timer cmt_timer = { - .name = "cmt", - .ops = &cmt_timer_ops, -}; diff --git a/arch/sh/kernel/timers/timer-mtu2.c b/arch/sh/kernel/timers/timer-mtu2.c deleted file mode 100644 index 9b0ef0126479..000000000000 --- a/arch/sh/kernel/timers/timer-mtu2.c +++ /dev/null @@ -1,202 +0,0 @@ -/* - * arch/sh/kernel/timers/timer-mtu2.c - MTU2 Timer Support - * - * Copyright (C) 2005 Paul Mundt - * - * Based off of arch/sh/kernel/timers/timer-tmu.c - * - * 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 -#include -#include -#include -#include -#include -#include -#include - -/* - * We use channel 1 for our lowly system timer. Channel 2 would be the other - * likely candidate, but we leave it alone as it has higher divisors that - * would be of more use to other more interesting applications. - * - * TODO: Presently we only implement a 16-bit single-channel system timer. - * However, we can implement channel cascade if we go the overflow route and - * get away with using 2 MTU2 channels as a 32-bit timer. - */ -#define MTU2_TSTR 0xfffe4280 -#define MTU2_TCR_1 0xfffe4380 -#define MTU2_TMDR_1 0xfffe4381 -#define MTU2_TIOR_1 0xfffe4382 -#define MTU2_TIER_1 0xfffe4384 -#define MTU2_TSR_1 0xfffe4385 -#define MTU2_TCNT_1 0xfffe4386 /* 16-bit counter */ - -#if defined(CONFIG_CPU_SUBTYPE_SH7201) || \ - defined(CONFIG_CPU_SUBTYPE_SH7203) -#define MTU2_TGRA_1 0xfffe4388 -#else -#define MTU2_TGRA_1 0xfffe438a -#endif - -#define STBCR3 0xfffe0408 - -#define MTU2_TSTR_CST1 (1 << 1) /* Counter Start 1 */ - -#define MTU2_TSR_TGFA (1 << 0) /* GRA compare match */ - -#define MTU2_TIER_TGIEA (1 << 0) /* GRA compare match interrupt enable */ - -#define MTU2_TCR_INIT 0x22 - -#define MTU2_TCR_CALIB 0x00 - -static unsigned long mtu2_timer_get_offset(void) -{ - int count; - static int count_p = 0x7fff; /* for the first call after boot */ - static unsigned long jiffies_p = 0; - - /* - * cache volatile jiffies temporarily; we have IRQs turned off. - */ - unsigned long jiffies_t; - - /* timer count may underflow right here */ - count = ctrl_inw(MTU2_TCNT_1); /* read the latched count */ - - jiffies_t = jiffies; - - /* - * avoiding timer inconsistencies (they are rare, but they happen)... - * there is one kind of problem that must be avoided here: - * 1. the timer counter underflows - */ - - if (jiffies_t == jiffies_p) { - if (count > count_p) { - if (ctrl_inb(MTU2_TSR_1) & MTU2_TSR_TGFA) { - count -= LATCH; - } else { - printk("%s (): hardware timer problem?\n", - __func__); - } - } - } else - jiffies_p = jiffies_t; - - count_p = count; - - count = ((LATCH-1) - count) * TICK_SIZE; - count = (count + LATCH/2) / LATCH; - - return count; -} - -static irqreturn_t mtu2_timer_interrupt(int irq, void *dev_id) -{ - unsigned long timer_status; - - /* Clear TGFA bit */ - timer_status = ctrl_inb(MTU2_TSR_1); - timer_status &= ~MTU2_TSR_TGFA; - ctrl_outb(timer_status, MTU2_TSR_1); - - /* Do timer tick */ - handle_timer_tick(); - - return IRQ_HANDLED; -} - -static struct irqaction mtu2_irq = { - .name = "timer", - .handler = mtu2_timer_interrupt, - .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, -}; - -static unsigned int divisors[] = { 1, 4, 16, 64, 1, 1, 256 }; - -static void mtu2_clk_init(struct clk *clk) -{ - u8 idx = MTU2_TCR_INIT & 0x7; - - clk->rate = clk->parent->rate / divisors[idx]; - /* Start TCNT counting */ - ctrl_outb(ctrl_inb(MTU2_TSTR) | MTU2_TSTR_CST1, MTU2_TSTR); - -} - -static void mtu2_clk_recalc(struct clk *clk) -{ - u8 idx = ctrl_inb(MTU2_TCR_1) & 0x7; - clk->rate = clk->parent->rate / divisors[idx]; -} - -static struct clk_ops mtu2_clk_ops = { - .init = mtu2_clk_init, - .recalc = mtu2_clk_recalc, -}; - -static struct clk mtu2_clk1 = { - .name = "mtu2_clk1", - .ops = &mtu2_clk_ops, -}; - -static int mtu2_timer_start(void) -{ - ctrl_outb(ctrl_inb(MTU2_TSTR) | MTU2_TSTR_CST1, MTU2_TSTR); - return 0; -} - -static int mtu2_timer_stop(void) -{ - ctrl_outb(ctrl_inb(MTU2_TSTR) & ~MTU2_TSTR_CST1, MTU2_TSTR); - return 0; -} - -static int mtu2_timer_init(void) -{ - unsigned long interval; - - setup_irq(CONFIG_SH_TIMER_IRQ, &mtu2_irq); - - mtu2_clk1.parent = clk_get(NULL, "module_clk"); - - ctrl_outb(ctrl_inb(STBCR3) & (~0x20), STBCR3); - - /* Normal operation */ - ctrl_outb(0, MTU2_TMDR_1); - ctrl_outb(MTU2_TCR_INIT, MTU2_TCR_1); - ctrl_outb(0x01, MTU2_TIOR_1); - - /* Enable underflow interrupt */ - ctrl_outb(ctrl_inb(MTU2_TIER_1) | MTU2_TIER_TGIEA, MTU2_TIER_1); - - interval = CONFIG_SH_PCLK_FREQ / 16 / HZ; - printk(KERN_INFO "Interval = %ld\n", interval); - - ctrl_outw(interval, MTU2_TGRA_1); - ctrl_outw(0, MTU2_TCNT_1); - - clk_register(&mtu2_clk1); - clk_enable(&mtu2_clk1); - - return 0; -} - -struct sys_timer_ops mtu2_timer_ops = { - .init = mtu2_timer_init, - .start = mtu2_timer_start, - .stop = mtu2_timer_stop, -#ifndef CONFIG_GENERIC_TIME - .get_offset = mtu2_timer_get_offset, -#endif -}; - -struct sys_timer mtu2_timer = { - .name = "mtu2", - .ops = &mtu2_timer_ops, -}; diff --git a/arch/sh/kernel/timers/timer-tmu.c b/arch/sh/kernel/timers/timer-tmu.c deleted file mode 100644 index fe8d8930ccb6..000000000000 --- a/arch/sh/kernel/timers/timer-tmu.c +++ /dev/null @@ -1,297 +0,0 @@ -/* - * arch/sh/kernel/timers/timer-tmu.c - TMU Timer Support - * - * Copyright (C) 2005 - 2007 Paul Mundt - * - * TMU handling code hacked out of arch/sh/kernel/time.c - * - * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka - * Copyright (C) 2000 Philipp Rumpf - * Copyright (C) 2002, 2003, 2004 Paul Mundt - * Copyright (C) 2002 M. R. Brown - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define TMU_TOCR_INIT 0x00 -#define TMU_TCR_INIT 0x0020 - -#define TMU0 (0) -#define TMU1 (1) - -static inline void _tmu_start(int tmu_num) -{ - ctrl_outb(ctrl_inb(TMU_012_TSTR) | (0x1<mode == CLOCK_EVT_MODE_PERIODIC); - _tmu_set_irq(TMU0,1); - return 0; -} - -static void tmu_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) -{ - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - ctrl_outl(tmu_latest_interval[TMU0], TMU0_TCOR); - break; - case CLOCK_EVT_MODE_ONESHOT: - ctrl_outl(0, TMU0_TCOR); - break; - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_RESUME: - break; - } -} - -static struct clock_event_device tmu0_clockevent = { - .name = "tmu0", - .shift = 32, - .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, - .set_mode = tmu_set_mode, - .set_next_event = tmu_set_next_event, -}; - -static irqreturn_t tmu_timer_interrupt(int irq, void *dummy) -{ - struct clock_event_device *evt = &tmu0_clockevent; - _tmu_clear_status(TMU0); - _tmu_set_irq(TMU0,tmu0_clockevent.mode != CLOCK_EVT_MODE_ONESHOT); - - switch (tmu0_clockevent.mode) { - case CLOCK_EVT_MODE_ONESHOT: - case CLOCK_EVT_MODE_PERIODIC: - evt->event_handler(evt); - break; - default: - break; - } - - return IRQ_HANDLED; -} - -static struct irqaction tmu0_irq = { - .name = "periodic/oneshot timer", - .handler = tmu_timer_interrupt, - .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, -}; - -static void __init tmu_clk_init(struct clk *clk) -{ - u8 divisor = TMU_TCR_INIT & 0x7; - int tmu_num = clk->name[3]-'0'; - ctrl_outw(TMU_TCR_INIT, TMU0_TCR+(tmu_num*0xC)); - clk->rate = clk_get_rate(clk->parent) / (4 << (divisor << 1)); -} - -static void tmu_clk_recalc(struct clk *clk) -{ - int tmu_num = clk->name[3]-'0'; - unsigned long prev_rate = clk_get_rate(clk); - unsigned long flags; - u8 divisor = ctrl_inw(TMU0_TCR+tmu_num*0xC) & 0x7; - clk->rate = clk_get_rate(clk->parent) / (4 << (divisor << 1)); - - if(prev_rate==clk_get_rate(clk)) - return; - - if(tmu_num) - return; /* No more work on TMU1 */ - - local_irq_save(flags); - tmus_are_scaled = (prev_rate > clk->rate); - - _tmu_stop(TMU0); - - tmu0_clockevent.mult = div_sc(clk->rate, NSEC_PER_SEC, - tmu0_clockevent.shift); - tmu0_clockevent.max_delta_ns = - clockevent_delta2ns(-1, &tmu0_clockevent); - tmu0_clockevent.min_delta_ns = - clockevent_delta2ns(1, &tmu0_clockevent); - - if (tmus_are_scaled) - tmu_latest_interval[TMU0] >>= 1; - else - tmu_latest_interval[TMU0] <<= 1; - - tmu_timer_set_interval(TMU0, - tmu_latest_interval[TMU0], - tmu0_clockevent.mode == CLOCK_EVT_MODE_PERIODIC); - - _tmu_start(TMU0); - - local_irq_restore(flags); -} - -static struct clk_ops tmu_clk_ops = { - .init = tmu_clk_init, - .recalc = tmu_clk_recalc, -}; - -static struct clk tmu0_clk = { - .name = "tmu0_clk", - .ops = &tmu_clk_ops, -}; - -static struct clk tmu1_clk = { - .name = "tmu1_clk", - .ops = &tmu_clk_ops, -}; - -static int tmu_timer_init(void) -{ - unsigned long interval; - unsigned long frequency; - - setup_irq(CONFIG_SH_TIMER_IRQ, &tmu0_irq); - - tmu0_clk.parent = clk_get(NULL, "module_clk"); - tmu1_clk.parent = clk_get(NULL, "module_clk"); - - tmu_timer_stop(); - -#if !defined(CONFIG_CPU_SUBTYPE_SH7720) && \ - !defined(CONFIG_CPU_SUBTYPE_SH7721) && \ - !defined(CONFIG_CPU_SUBTYPE_SH7760) && \ - !defined(CONFIG_CPU_SUBTYPE_SH7785) && \ - !defined(CONFIG_CPU_SUBTYPE_SH7786) && \ - !defined(CONFIG_CPU_SUBTYPE_SHX3) - ctrl_outb(TMU_TOCR_INIT, TMU_TOCR); -#endif - - clk_register(&tmu0_clk); - clk_register(&tmu1_clk); - clk_enable(&tmu0_clk); - clk_enable(&tmu1_clk); - - frequency = clk_get_rate(&tmu0_clk); - interval = (frequency + HZ / 2) / HZ; - - tmu_timer_set_interval(TMU0,interval, 1); - tmu_timer_set_interval(TMU1,~0,1); - - _tmu_start(TMU1); - - clocksource_sh.rating = 200; - clocksource_sh.mask = CLOCKSOURCE_MASK(32); - clocksource_sh.read = tmu_timer_read; - clocksource_sh.shift = 10; - clocksource_sh.mult = clocksource_hz2mult(clk_get_rate(&tmu1_clk), - clocksource_sh.shift); - clocksource_sh.flags = CLOCK_SOURCE_IS_CONTINUOUS; - clocksource_register(&clocksource_sh); - - tmu0_clockevent.mult = div_sc(frequency, NSEC_PER_SEC, - tmu0_clockevent.shift); - tmu0_clockevent.max_delta_ns = - clockevent_delta2ns(-1, &tmu0_clockevent); - tmu0_clockevent.min_delta_ns = - clockevent_delta2ns(1, &tmu0_clockevent); - - tmu0_clockevent.cpumask = cpumask_of(0); - tmu0_clockevent.rating = 100; - - clockevents_register_device(&tmu0_clockevent); - - return 0; -} - -static struct sys_timer_ops tmu_timer_ops = { - .init = tmu_timer_init, - .start = tmu_timer_start, - .stop = tmu_timer_stop, -}; - -struct sys_timer tmu_timer = { - .name = "tmu", - .ops = &tmu_timer_ops, -}; diff --git a/arch/sh/kernel/timers/timer.c b/arch/sh/kernel/timers/timer.c deleted file mode 100644 index 4e7e747d1b69..000000000000 --- a/arch/sh/kernel/timers/timer.c +++ /dev/null @@ -1,55 +0,0 @@ -/* - * arch/sh/kernel/timers/timer.c - Common timer code - * - * Copyright (C) 2005 Paul Mundt - * - * 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 -#include -#include -#include -#include - -static struct sys_timer *sys_timers[] = { -#ifdef CONFIG_SH_TMU - &tmu_timer, -#endif -#ifdef CONFIG_SH_MTU2 - &mtu2_timer, -#endif -#ifdef CONFIG_SH_CMT - &cmt_timer, -#endif - NULL, -}; - -static char timer_override[10]; -static int __init timer_setup(char *str) -{ - if (str) - strlcpy(timer_override, str, sizeof(timer_override)); - return 1; -} -__setup("timer=", timer_setup); - -struct sys_timer *get_sys_timer(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(sys_timers); i++) { - struct sys_timer *t = sys_timers[i]; - - if (unlikely(!t)) - break; - if (unlikely(timer_override[0])) - if ((strcmp(timer_override, t->name) != 0)) - continue; - if (likely(t->ops->init() == 0)) - return t; - } - - return NULL; -} diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c index 438f1ebcc453..b3e0067db358 100644 --- a/arch/sh/kernel/traps.c +++ b/arch/sh/kernel/traps.c @@ -22,11 +22,11 @@ static void handle_BUG(struct pt_regs *regs) int is_valid_bugaddr(unsigned long addr) { - unsigned short opcode; + insn_size_t opcode; if (addr < PAGE_OFFSET) return 0; - if (probe_kernel_address((u16 *)addr, opcode)) + if (probe_kernel_address((insn_size_t *)addr, opcode)) return 0; return opcode == TRAPA_BUG_OPCODE; @@ -66,9 +66,10 @@ BUILD_TRAP_HANDLER(bug) #ifdef CONFIG_BUG if (__kernel_text_address(instruction_pointer(regs))) { - opcode_t insn = *(opcode_t *)instruction_pointer(regs); + insn_size_t insn = *(insn_size_t *)instruction_pointer(regs); if (insn == TRAPA_BUG_OPCODE) handle_BUG(regs); + return; } #endif diff --git a/arch/sh/kernel/traps_32.c b/arch/sh/kernel/traps_32.c index 30ca9c51e52d..2b772776fcda 100644 --- a/arch/sh/kernel/traps_32.c +++ b/arch/sh/kernel/traps_32.c @@ -34,6 +34,7 @@ # define TRAP_ILLEGAL_SLOT_INST 6 # define TRAP_ADDRESS_ERROR 9 # ifdef CONFIG_CPU_SH2A +# define TRAP_UBC 12 # define TRAP_FPU_ERROR 13 # define TRAP_DIVZERO_ERROR 17 # define TRAP_DIVOVF_ERROR 18 @@ -176,7 +177,7 @@ static struct mem_access user_mem_access = { * (if that instruction is in a branch delay slot) * - return 0 if emulation okay, -EFAULT on existential error */ -static int handle_unaligned_ins(opcode_t instruction, struct pt_regs *regs, +static int handle_unaligned_ins(insn_size_t instruction, struct pt_regs *regs, struct mem_access *ma) { int ret, index, count; @@ -321,10 +322,10 @@ static int handle_unaligned_ins(opcode_t instruction, struct pt_regs *regs, * - fetches the instruction from PC+2 */ static inline int handle_delayslot(struct pt_regs *regs, - opcode_t old_instruction, + insn_size_t old_instruction, struct mem_access *ma) { - opcode_t instruction; + insn_size_t instruction; void __user *addr = (void __user *)(regs->pc + instruction_size(old_instruction)); @@ -364,7 +365,7 @@ static inline int handle_delayslot(struct pt_regs *regs, static int handle_unaligned_notify_count = 10; -int handle_unaligned_access(opcode_t instruction, struct pt_regs *regs, +int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs, struct mem_access *ma) { u_int rm; @@ -522,7 +523,7 @@ asmlinkage void do_address_error(struct pt_regs *regs, unsigned long error_code = 0; mm_segment_t oldfs; siginfo_t info; - opcode_t instruction; + insn_size_t instruction; int tmp; /* Intentional ifdef */ @@ -849,6 +850,10 @@ void __init trap_init(void) #endif #endif +#ifdef TRAP_UBC + set_exception_table_vec(TRAP_UBC, break_point_trap); +#endif + /* Setup VBR for boot cpu */ per_cpu_trap_init(); } diff --git a/arch/sh/kernel/traps_64.c b/arch/sh/kernel/traps_64.c index a85831cbf18b..267e5ebbb475 100644 --- a/arch/sh/kernel/traps_64.c +++ b/arch/sh/kernel/traps_64.c @@ -370,7 +370,6 @@ static int generate_and_check_address(struct pt_regs *regs, return -1; } -#if defined(CONFIG_SH64_USER_MISALIGNED_FIXUP) /* Check accessible. For misaligned access in the kernel, assume the address is always accessible (and if not, just fault when the load/store gets done.) */ @@ -380,18 +379,13 @@ static int generate_and_check_address(struct pt_regs *regs, } /* Do access_ok check later - it depends on whether it's a load or a store. */ } -#endif *address = addr; return 0; } -/* Default value as for sh */ -#if defined(CONFIG_SH64_USER_MISALIGNED_FIXUP) static int user_mode_unaligned_fixup_count = 10; static int user_mode_unaligned_fixup_enable = 1; -#endif - static int kernel_mode_unaligned_fixup_count = 32; static void misaligned_kernel_word_load(__u64 address, int do_sign_extend, __u64 *result) @@ -440,7 +434,6 @@ static int misaligned_load(struct pt_regs *regs, } destreg = (opcode >> 4) & 0x3f; -#if defined(CONFIG_SH64_USER_MISALIGNED_FIXUP) if (user_mode(regs)) { __u64 buffer; @@ -470,9 +463,7 @@ static int misaligned_load(struct pt_regs *regs, width_shift, (unsigned long) regs->pc); break; } - } else -#endif - { + } else { /* kernel mode - we can take short cuts since if we fault, it's a genuine bug */ __u64 lo, hi; @@ -519,7 +510,6 @@ static int misaligned_store(struct pt_regs *regs, } srcreg = (opcode >> 4) & 0x3f; -#if defined(CONFIG_SH64_USER_MISALIGNED_FIXUP) if (user_mode(regs)) { __u64 buffer; @@ -546,9 +536,7 @@ static int misaligned_store(struct pt_regs *regs, if (__copy_user((void *)(int)address, &buffer, (1 << width_shift)) > 0) { return -1; /* fault */ } - } else -#endif - { + } else { /* kernel mode - we can take short cuts since if we fault, it's a genuine bug */ __u64 val = regs->regs[srcreg]; @@ -576,7 +564,6 @@ static int misaligned_store(struct pt_regs *regs, } -#if defined(CONFIG_SH64_USER_MISALIGNED_FIXUP) /* Never need to fix up misaligned FPU accesses within the kernel since that's a real error. */ static int misaligned_fpu_load(struct pt_regs *regs, @@ -727,7 +714,6 @@ static int misaligned_fpu_store(struct pt_regs *regs, return -1; } } -#endif static int misaligned_fixup(struct pt_regs *regs) { @@ -735,12 +721,8 @@ static int misaligned_fixup(struct pt_regs *regs) int error; int major, minor; -#if !defined(CONFIG_SH64_USER_MISALIGNED_FIXUP) - /* Never fixup user mode misaligned accesses without this option enabled. */ - return -1; -#else - if (!user_mode_unaligned_fixup_enable) return -1; -#endif + if (!user_mode_unaligned_fixup_enable) + return -1; error = read_opcode(regs->pc, &opcode, user_mode(regs)); if (error < 0) { @@ -749,15 +731,12 @@ static int misaligned_fixup(struct pt_regs *regs) major = (opcode >> 26) & 0x3f; minor = (opcode >> 16) & 0xf; -#if defined(CONFIG_SH64_USER_MISALIGNED_FIXUP) if (user_mode(regs) && (user_mode_unaligned_fixup_count > 0)) { --user_mode_unaligned_fixup_count; /* Only do 'count' worth of these reports, to remove a potential DoS against syslog */ printk("Fixing up unaligned userspace access in \"%s\" pid=%d pc=0x%08x ins=0x%08lx\n", current->comm, task_pid_nr(current), (__u32)regs->pc, opcode); - } else -#endif - if (!user_mode(regs) && (kernel_mode_unaligned_fixup_count > 0)) { + } else if (!user_mode(regs) && (kernel_mode_unaligned_fixup_count > 0)) { --kernel_mode_unaligned_fixup_count; if (in_interrupt()) { printk("Fixing up unaligned kernelspace access in interrupt pc=0x%08x ins=0x%08lx\n", @@ -830,7 +809,6 @@ static int misaligned_fixup(struct pt_regs *regs) } break; -#if defined(CONFIG_SH64_USER_MISALIGNED_FIXUP) case (0x94>>2): /* FLD.S */ error = misaligned_fpu_load(regs, opcode, 1, 2, 0); break; @@ -881,7 +859,6 @@ static int misaligned_fixup(struct pt_regs *regs) break; } break; -#endif default: /* Fault */ @@ -907,7 +884,6 @@ static ctl_table unaligned_table[] = { .mode = 0644, .proc_handler = &proc_dointvec }, -#if defined(CONFIG_SH64_USER_MISALIGNED_FIXUP) { .ctl_name = CTL_UNNUMBERED, .procname = "user_reports", @@ -923,7 +899,6 @@ static ctl_table unaligned_table[] = { .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec}, -#endif {} }; diff --git a/arch/sh/kernel/vmlinux.lds.S b/arch/sh/kernel/vmlinux.lds.S index d7d4991f32af..f53c76acaede 100644 --- a/arch/sh/kernel/vmlinux.lds.S +++ b/arch/sh/kernel/vmlinux.lds.S @@ -1,5 +1,178 @@ -#ifdef CONFIG_SUPERH32 -# include "vmlinux_32.lds.S" +/* + * ld script to make SuperH Linux kernel + * Written by Niibe Yutaka and Paul Mundt + */ +#ifdef CONFIG_SUPERH64 +#define LOAD_OFFSET CONFIG_PAGE_OFFSET +OUTPUT_ARCH(sh:sh5) #else -# include "vmlinux_64.lds.S" +#define LOAD_OFFSET 0 +OUTPUT_ARCH(sh) #endif + +#include +#include +#include + +ENTRY(_start) +SECTIONS +{ +#ifdef CONFIG_PMB_FIXED + . = CONFIG_PAGE_OFFSET + (CONFIG_MEMORY_START & 0x1fffffff) + + CONFIG_ZERO_PAGE_OFFSET; +#elif defined(CONFIG_32BIT) + . = CONFIG_PAGE_OFFSET + CONFIG_ZERO_PAGE_OFFSET; +#else + . = CONFIG_PAGE_OFFSET + CONFIG_MEMORY_START + CONFIG_ZERO_PAGE_OFFSET; +#endif + + _text = .; /* Text and read-only data */ + + .empty_zero_page : AT(ADDR(.empty_zero_page) - LOAD_OFFSET) { + *(.empty_zero_page) + } = 0 + + .text : AT(ADDR(.text) - LOAD_OFFSET) { + HEAD_TEXT + TEXT_TEXT + +#ifdef CONFIG_SUPERH64 + *(.text64) + *(.text..SHmedia32) +#endif + + SCHED_TEXT + LOCK_TEXT + KPROBES_TEXT + IRQENTRY_TEXT + *(.fixup) + *(.gnu.warning) + _etext = .; /* End of text section */ + } = 0x0009 + + . = ALIGN(16); /* Exception table */ + __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { + __start___ex_table = .; + *(__ex_table) + __stop___ex_table = .; + } + + NOTES + RO_DATA(PAGE_SIZE) + + /* + * Code which must be executed uncached and the associated data + */ + . = ALIGN(PAGE_SIZE); + .uncached : AT(ADDR(.uncached) - LOAD_OFFSET) { + __uncached_start = .; + *(.uncached.text) + *(.uncached.data) + __uncached_end = .; + } + + . = ALIGN(THREAD_SIZE); + .data : AT(ADDR(.data) - LOAD_OFFSET) { /* Data */ + *(.data.init_task) + + . = ALIGN(L1_CACHE_BYTES); + *(.data.cacheline_aligned) + + . = ALIGN(L1_CACHE_BYTES); + *(.data.read_mostly) + + . = ALIGN(PAGE_SIZE); + *(.data.page_aligned) + + __nosave_begin = .; + *(.data.nosave) + . = ALIGN(PAGE_SIZE); + __nosave_end = .; + + DATA_DATA + CONSTRUCTORS + } + + _edata = .; /* End of data section */ + + . = ALIGN(PAGE_SIZE); /* Init code and data */ + .init.text : AT(ADDR(.init.text) - LOAD_OFFSET) { + __init_begin = .; + _sinittext = .; + INIT_TEXT + _einittext = .; + } + + .init.data : AT(ADDR(.init.data) - LOAD_OFFSET) { INIT_DATA } + + . = ALIGN(16); + .init.setup : AT(ADDR(.init.setup) - LOAD_OFFSET) { + __setup_start = .; + *(.init.setup) + __setup_end = .; + } + + .initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) { + __initcall_start = .; + INITCALLS + __initcall_end = .; + } + + .con_initcall.init : AT(ADDR(.con_initcall.init) - LOAD_OFFSET) { + __con_initcall_start = .; + *(.con_initcall.init) + __con_initcall_end = .; + } + + SECURITY_INIT + +#ifdef CONFIG_BLK_DEV_INITRD + . = ALIGN(PAGE_SIZE); + .init.ramfs : AT(ADDR(.init.ramfs) - LOAD_OFFSET) { + __initramfs_start = .; + *(.init.ramfs) + __initramfs_end = .; + } +#endif + + . = ALIGN(4); + .machvec.init : AT(ADDR(.machvec.init) - LOAD_OFFSET) { + __machvec_start = .; + *(.machvec.init) + __machvec_end = .; + } + + PERCPU(PAGE_SIZE) + + /* + * .exit.text is discarded at runtime, not link time, to deal with + * references from __bug_table + */ + .exit.text : AT(ADDR(.exit.text) - LOAD_OFFSET) { EXIT_TEXT } + .exit.data : AT(ADDR(.exit.data) - LOAD_OFFSET) { EXIT_DATA } + + . = ALIGN(PAGE_SIZE); + .bss : AT(ADDR(.bss) - LOAD_OFFSET) { + __init_end = .; + __bss_start = .; /* BSS */ + *(.bss.page_aligned) + *(.bss) + *(COMMON) + . = ALIGN(4); + _ebss = .; /* uClinux MTD sucks */ + _end = . ; + } + + /* + * When something in the kernel is NOT compiled as a module, the + * module cleanup code and data are put into these segments. Both + * can then be thrown away, as cleanup code is never called unless + * it's a module. + */ + /DISCARD/ : { + *(.exitcall.exit) + } + + STABS_DEBUG + DWARF_DEBUG +} diff --git a/arch/sh/kernel/vmlinux_32.lds.S b/arch/sh/kernel/vmlinux_32.lds.S deleted file mode 100644 index dd9b2ee1312d..000000000000 --- a/arch/sh/kernel/vmlinux_32.lds.S +++ /dev/null @@ -1,154 +0,0 @@ -/* - * ld script to make SuperH Linux kernel - * Written by Niibe Yutaka - */ -#include -#include -#include - -#ifdef CONFIG_CPU_LITTLE_ENDIAN -OUTPUT_FORMAT("elf32-sh-linux", "elf32-sh-linux", "elf32-sh-linux") -#else -OUTPUT_FORMAT("elf32-shbig-linux", "elf32-shbig-linux", "elf32-shbig-linux") -#endif -OUTPUT_ARCH(sh) -ENTRY(_start) -SECTIONS -{ -#ifdef CONFIG_PMB_FIXED - . = CONFIG_PAGE_OFFSET + (CONFIG_MEMORY_START & 0x1fffffff) + - CONFIG_ZERO_PAGE_OFFSET; -#elif defined(CONFIG_32BIT) - . = CONFIG_PAGE_OFFSET + CONFIG_ZERO_PAGE_OFFSET; -#else - . = CONFIG_PAGE_OFFSET + CONFIG_MEMORY_START + CONFIG_ZERO_PAGE_OFFSET; -#endif - - _text = .; /* Text and read-only data */ - - .empty_zero_page : { - *(.empty_zero_page) - } = 0 - - .text : { - HEAD_TEXT - TEXT_TEXT - SCHED_TEXT - LOCK_TEXT - KPROBES_TEXT - *(.fixup) - *(.gnu.warning) - } = 0x0009 - - . = ALIGN(16); /* Exception table */ - __start___ex_table = .; - __ex_table : { *(__ex_table) } - __stop___ex_table = .; - - _etext = .; /* End of text section */ - - NOTES - RO_DATA(PAGE_SIZE) - - /* - * Code which must be executed uncached and the associated data - */ - . = ALIGN(PAGE_SIZE); - __uncached_start = .; - .uncached.text : { *(.uncached.text) } - .uncached.data : { *(.uncached.data) } - __uncached_end = .; - - . = ALIGN(THREAD_SIZE); - .data : { /* Data */ - *(.data.init_task) - - . = ALIGN(L1_CACHE_BYTES); - *(.data.cacheline_aligned) - - . = ALIGN(L1_CACHE_BYTES); - *(.data.read_mostly) - - . = ALIGN(PAGE_SIZE); - *(.data.page_aligned) - - __nosave_begin = .; - *(.data.nosave) - . = ALIGN(PAGE_SIZE); - __nosave_end = .; - - DATA_DATA - CONSTRUCTORS - } - - _edata = .; /* End of data section */ - - . = ALIGN(PAGE_SIZE); /* Init code and data */ - __init_begin = .; - _sinittext = .; - .init.text : { INIT_TEXT } - _einittext = .; - .init.data : { INIT_DATA } - - . = ALIGN(16); - __setup_start = .; - .init.setup : { *(.init.setup) } - __setup_end = .; - - __initcall_start = .; - .initcall.init : { - INITCALLS - } - __initcall_end = .; - __con_initcall_start = .; - .con_initcall.init : { *(.con_initcall.init) } - __con_initcall_end = .; - - SECURITY_INIT - -#ifdef CONFIG_BLK_DEV_INITRD - . = ALIGN(PAGE_SIZE); - __initramfs_start = .; - .init.ramfs : { *(.init.ramfs) } - __initramfs_end = .; -#endif - - . = ALIGN(4); - __machvec_start = .; - .machvec.init : { *(.machvec.init) } - __machvec_end = .; - - PERCPU(PAGE_SIZE) - - /* - * .exit.text is discarded at runtime, not link time, to deal with - * references from __bug_table - */ - .exit.text : { EXIT_TEXT } - .exit.data : { EXIT_DATA } - - . = ALIGN(PAGE_SIZE); - .bss : { - __init_end = .; - __bss_start = .; /* BSS */ - *(.bss.page_aligned) - *(.bss) - *(COMMON) - . = ALIGN(4); - _ebss = .; /* uClinux MTD sucks */ - _end = . ; - } - - /* - * When something in the kernel is NOT compiled as a module, the - * module cleanup code and data are put into these segments. Both - * can then be thrown away, as cleanup code is never called unless - * it's a module. - */ - /DISCARD/ : { - *(.exitcall.exit) - } - - STABS_DEBUG - DWARF_DEBUG -} diff --git a/arch/sh/kernel/vmlinux_64.lds.S b/arch/sh/kernel/vmlinux_64.lds.S deleted file mode 100644 index 69664460c688..000000000000 --- a/arch/sh/kernel/vmlinux_64.lds.S +++ /dev/null @@ -1,163 +0,0 @@ -/* - * ld script to make SH64 Linux kernel - * - * Copyright (C) 2000, 2001 Paolo Alberelli - * - * benedict.gaster@superh.com: 2nd May 2002 - * Add definition of empty_zero_page to be the first page of kernel image. - * - * benedict.gaster@superh.com: 3rd May 2002 - * Added support for ramdisk, removing statically linked romfs at the - * same time. - * - * lethal@linux-sh.org: 9th May 2003 - * Kill off GLOBAL_NAME() usage and other CDC-isms. - * - * lethal@linux-sh.org: 19th May 2003 - * Remove support for ancient toolchains. - * - * 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 -#include -#include - -#define LOAD_OFFSET CONFIG_PAGE_OFFSET -#include - -OUTPUT_ARCH(sh:sh5) - -#define C_PHYS(x) AT (ADDR(x) - LOAD_OFFSET) - -ENTRY(__start) -SECTIONS -{ - . = CONFIG_PAGE_OFFSET + CONFIG_MEMORY_START + PAGE_SIZE; - _text = .; /* Text and read-only data */ - - .empty_zero_page : C_PHYS(.empty_zero_page) { - *(.empty_zero_page) - } = 0 - - .text : C_PHYS(.text) { - HEAD_TEXT - TEXT_TEXT - *(.text64) - *(.text..SHmedia32) - SCHED_TEXT - LOCK_TEXT - KPROBES_TEXT - *(.fixup) - *(.gnu.warning) -#ifdef CONFIG_CPU_LITTLE_ENDIAN - } = 0x6ff0fff0 -#else - } = 0xf0fff06f -#endif - - /* We likely want __ex_table to be Cache Line aligned */ - . = ALIGN(L1_CACHE_BYTES); /* Exception table */ - __start___ex_table = .; - __ex_table : C_PHYS(__ex_table) { *(__ex_table) } - __stop___ex_table = .; - - _etext = .; /* End of text section */ - - NOTES - RO_DATA(PAGE_SIZE) - - . = ALIGN(THREAD_SIZE); - .data : C_PHYS(.data) { /* Data */ - *(.data.init_task) - - . = ALIGN(L1_CACHE_BYTES); - *(.data.cacheline_aligned) - - . = ALIGN(L1_CACHE_BYTES); - *(.data.read_mostly) - - . = ALIGN(PAGE_SIZE); - *(.data.page_aligned) - - __nosave_begin = .; - *(.data.nosave) - . = ALIGN(PAGE_SIZE); - __nosave_end = .; - - DATA_DATA - CONSTRUCTORS - } - - _edata = .; /* End of data section */ - - . = ALIGN(PAGE_SIZE); /* Init code and data */ - __init_begin = .; - _sinittext = .; - .init.text : C_PHYS(.init.text) { INIT_TEXT } - _einittext = .; - .init.data : C_PHYS(.init.data) { INIT_DATA } - . = ALIGN(L1_CACHE_BYTES); /* Better if Cache Line aligned */ - __setup_start = .; - .init.setup : C_PHYS(.init.setup) { *(.init.setup) } - __setup_end = .; - __initcall_start = .; - .initcall.init : C_PHYS(.initcall.init) { - INITCALLS - } - __initcall_end = .; - __con_initcall_start = .; - .con_initcall.init : C_PHYS(.con_initcall.init) { - *(.con_initcall.init) - } - __con_initcall_end = .; - - SECURITY_INIT - -#ifdef CONFIG_BLK_DEV_INITRD - . = ALIGN(PAGE_SIZE); - __initramfs_start = .; - .init.ramfs : C_PHYS(.init.ramfs) { *(.init.ramfs) } - __initramfs_end = .; -#endif - - . = ALIGN(8); - __machvec_start = .; - .machvec.init : C_PHYS(.machvec.init) { *(.machvec.init) } - __machvec_end = .; - - PERCPU(PAGE_SIZE) - - /* - * .exit.text is discarded at runtime, not link time, to deal with - * references from __bug_table - */ - .exit.text : C_PHYS(.exit.text) { EXIT_TEXT } - .exit.data : C_PHYS(.exit.data) { EXIT_DATA } - - . = ALIGN(PAGE_SIZE); - .bss : C_PHYS(.bss) { - __init_end = .; - __bss_start = .; /* BSS */ - *(.bss.page_aligned) - *(.bss) - *(COMMON) - . = ALIGN(4); - _ebss = .; /* uClinux MTD sucks */ - _end = . ; - } - - /* - * When something in the kernel is NOT compiled as a module, the - * module cleanup code and data are put into these segments. Both - * can then be thrown away, as cleanup code is never called unless - * it's a module. - */ - /DISCARD/ : { - *(.exitcall.exit) - } - - STABS_DEBUG - DWARF_DEBUG -} diff --git a/arch/sh/lib64/.gitignore b/arch/sh/lib64/.gitignore deleted file mode 100644 index 3508c2cb23c4..000000000000 --- a/arch/sh/lib64/.gitignore +++ /dev/null @@ -1 +0,0 @@ -syscalltab.h diff --git a/arch/sh/lib64/Makefile b/arch/sh/lib64/Makefile index 4bacb9e83478..334bb2da36ea 100644 --- a/arch/sh/lib64/Makefile +++ b/arch/sh/lib64/Makefile @@ -10,7 +10,7 @@ # # Panic should really be compiled as PIC -lib-y := udelay.o c-checksum.o dbg.o panic.o memcpy.o memset.o \ +lib-y := udelay.o dbg.o panic.o memcpy.o memset.o \ copy_user_memcpy.o copy_page.o clear_page.o strcpy.o strlen.o # Extracted from libgcc diff --git a/arch/sh/lib64/c-checksum.c b/arch/sh/lib64/c-checksum.c deleted file mode 100644 index 73c0877e3a29..000000000000 --- a/arch/sh/lib64/c-checksum.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * arch/sh/lib64/c-checksum.c - * - * This file contains network checksum routines that are better done - * in an architecture-specific manner due to speed.. - */ -#include -#include -#include -#include -#include -#include - -static inline unsigned short from64to16(unsigned long long x) -{ - /* add up 32-bit words for 33 bits */ - x = (x & 0xffffffff) + (x >> 32); - /* add up 16-bit and 17-bit words for 17+c bits */ - x = (x & 0xffff) + (x >> 16); - /* add up 16-bit and 2-bit for 16+c bit */ - x = (x & 0xffff) + (x >> 16); - /* add up carry.. */ - x = (x & 0xffff) + (x >> 16); - return x; -} - -static inline unsigned short foldto16(unsigned long x) -{ - /* add up 16-bit for 17 bits */ - x = (x & 0xffff) + (x >> 16); - /* add up carry.. */ - x = (x & 0xffff) + (x >> 16); - return x; -} - -static inline unsigned short myfoldto16(unsigned long long x) -{ - /* Fold down to 32-bits so we don't lose in the typedef-less - network stack. */ - /* 64 to 33 */ - x = (x & 0xffffffff) + (x >> 32); - /* 33 to 32 */ - x = (x & 0xffffffff) + (x >> 32); - - /* add up 16-bit for 17 bits */ - x = (x & 0xffff) + (x >> 16); - /* add up carry.. */ - x = (x & 0xffff) + (x >> 16); - return x; -} - -#define odd(x) ((x)&1) -#define U16(x) ntohs(x) - -static unsigned long do_csum(const unsigned char *buff, int len) -{ - int odd, count; - unsigned long result = 0; - - pr_debug("do_csum buff %p, len %d (0x%x)\n", buff, len, len); -#ifdef DEBUG - for (i = 0; i < len; i++) { - if ((i % 26) == 0) - printk("\n"); - printk("%02X ", buff[i]); - } -#endif - - if (len <= 0) - goto out; - - odd = 1 & (unsigned long) buff; - if (odd) { - result = *buff << 8; - len--; - buff++; - } - count = len >> 1; /* nr of 16-bit words.. */ - if (count) { - if (2 & (unsigned long) buff) { - result += *(unsigned short *) buff; - count--; - len -= 2; - buff += 2; - } - count >>= 1; /* nr of 32-bit words.. */ - if (count) { - unsigned long carry = 0; - do { - unsigned long w = *(unsigned long *) buff; - buff += 4; - count--; - result += carry; - result += w; - carry = (w > result); - } while (count); - result += carry; - result = (result & 0xffff) + (result >> 16); - } - if (len & 2) { - result += *(unsigned short *) buff; - buff += 2; - } - } - if (len & 1) - result += *buff; - result = foldto16(result); - if (odd) - result = ((result >> 8) & 0xff) | ((result & 0xff) << 8); - - pr_debug("\nCHECKSUM is 0x%lx\n", result); - - out: - return result; -} - -/* computes the checksum of a memory block at buff, length len, - and adds in "sum" (32-bit) */ -__wsum csum_partial(const void *buff, int len, __wsum sum) -{ - unsigned long long result = do_csum(buff, len); - - /* add in old sum, and carry.. */ - result += (__force u32)sum; - /* 32+c bits -> 32 bits */ - result = (result & 0xffffffff) + (result >> 32); - - pr_debug("csum_partial, buff %p len %d sum 0x%x result=0x%016Lx\n", - buff, len, sum, result); - - return (__force __wsum)result; -} - -/* Copy while checksumming, otherwise like csum_partial. */ -__wsum -csum_partial_copy_nocheck(const void *src, void *dst, int len, __wsum sum) -{ - sum = csum_partial(src, len, sum); - memcpy(dst, src, len); - - return sum; -} - -/* Copy from userspace and compute checksum. If we catch an exception - then zero the rest of the buffer. */ -__wsum -csum_partial_copy_from_user(const void __user *src, void *dst, int len, - __wsum sum, int *err_ptr) -{ - int missing; - - pr_debug - ("csum_partial_copy_from_user src %p, dest %p, len %d, sum %08x, err_ptr %p\n", - src, dst, len, sum, err_ptr); - missing = copy_from_user(dst, src, len); - pr_debug(" access_ok %d\n", __access_ok((unsigned long) src, len)); - pr_debug(" missing %d\n", missing); - if (missing) { - memset(dst + len - missing, 0, missing); - *err_ptr = -EFAULT; - } - - return csum_partial(dst, len, sum); -} - -/* Copy to userspace and compute checksum. */ -__wsum -csum_partial_copy_to_user(const unsigned char *src, unsigned char *dst, int len, - __wsum sum, int *err_ptr) -{ - sum = csum_partial(src, len, sum); - - if (copy_to_user(dst, src, len)) - *err_ptr = -EFAULT; - - return sum; -} - -/* - * This is a version of ip_compute_csum() optimized for IP headers, - * which always checksum on 4 octet boundaries. - */ -__sum16 ip_fast_csum(const void *iph, unsigned int ihl) -{ - pr_debug("ip_fast_csum %p,%d\n", iph, ihl); - - return (__force __sum16)~do_csum(iph, ihl * 4); -} - -__wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr, - unsigned short len, - unsigned short proto, __wsum sum) -{ - unsigned long long result; - - pr_debug("ntohs(0x%x)=0x%x\n", 0xdead, ntohs(0xdead)); - pr_debug("htons(0x%x)=0x%x\n", 0xdead, htons(0xdead)); - - result = (__force u64) saddr + (__force u64) daddr + - (__force u64) sum + ((len + proto) << 8); - - /* Fold down to 32-bits so we don't lose in the typedef-less - network stack. */ - /* 64 to 33 */ - result = (result & 0xffffffff) + (result >> 32); - /* 33 to 32 */ - result = (result & 0xffffffff) + (result >> 32); - - pr_debug("%s saddr %x daddr %x len %x proto %x sum %x result %08Lx\n", - __func__, saddr, daddr, len, proto, sum, result); - - return (__wsum)result; -} -EXPORT_SYMBOL(csum_tcpudp_nofold); diff --git a/arch/sh/lib64/dbg.c b/arch/sh/lib64/dbg.c index 2fb8eaf6de60..6152a6a6d9c6 100644 --- a/arch/sh/lib64/dbg.c +++ b/arch/sh/lib64/dbg.c @@ -135,140 +135,6 @@ void print_itlb(void) (" =============================================================\n"); } -/* ======================================================================= */ - -#ifdef CONFIG_POOR_MANS_STRACE - -#include "syscalltab.h" - -struct ring_node { - int evt; - int ret_addr; - int event; - int tra; - int pid; - unsigned long sp; - unsigned long pc; -}; - -static struct ring_node event_ring[16]; -static int event_ptr = 0; - -struct stored_syscall_data { - int pid; - int syscall_number; -}; - -#define N_STORED_SYSCALLS 16 - -static struct stored_syscall_data stored_syscalls[N_STORED_SYSCALLS]; -static int syscall_next=0; -static int syscall_next_print=0; - -void evt_debug(int evt, int ret_addr, int event, int tra, struct pt_regs *regs) -{ - int syscallno = tra & 0xff; - unsigned long sp; - unsigned long stack_bottom; - int pid; - struct ring_node *rr; - - pid = current->pid; - stack_bottom = (unsigned long) task_stack_page(current); - asm volatile("ori r15, 0, %0" : "=r" (sp)); - rr = event_ring + event_ptr; - rr->evt = evt; - rr->ret_addr = ret_addr; - rr->event = event; - rr->tra = tra; - rr->pid = pid; - rr->sp = sp; - rr->pc = regs->pc; - - if (sp < stack_bottom + 3092) { - int i, j; - printk("evt_debug : stack underflow report\n"); - for (j=0, i = event_ptr; j<16; j++) { - rr = event_ring + i; - printk("evt=%08x event=%08x tra=%08x pid=%5d sp=%08lx pc=%08lx\n", - rr->evt, rr->event, rr->tra, rr->pid, rr->sp, rr->pc); - i--; - i &= 15; - } - panic("STACK UNDERFLOW\n"); - } - - event_ptr = (event_ptr + 1) & 15; - - if ((event == 2) && (evt == 0x160)) { - if (syscallno < NUM_SYSCALL_INFO_ENTRIES) { - /* Store the syscall information to print later. We - * can't print this now - currently we're running with - * SR.BL=1, so we can't take a tlbmiss (which could occur - * in the console drivers under printk). - * - * Just overwrite old entries on ring overflow - this - * is only for last-hope debugging. */ - stored_syscalls[syscall_next].pid = current->pid; - stored_syscalls[syscall_next].syscall_number = syscallno; - syscall_next++; - syscall_next &= (N_STORED_SYSCALLS - 1); - } - } -} - -static void drain_syscalls(void) { - while (syscall_next_print != syscall_next) { - printk("Task %d: %s()\n", - stored_syscalls[syscall_next_print].pid, - syscall_info_table[stored_syscalls[syscall_next_print].syscall_number].name); - syscall_next_print++; - syscall_next_print &= (N_STORED_SYSCALLS - 1); - } -} - -void evt_debug2(unsigned int ret) -{ - drain_syscalls(); - printk("Task %d: syscall returns %08x\n", current->pid, ret); -} - -void evt_debug_ret_from_irq(struct pt_regs *regs) -{ - int pid; - struct ring_node *rr; - - pid = current->pid; - rr = event_ring + event_ptr; - rr->evt = 0xffff; - rr->ret_addr = 0; - rr->event = 0; - rr->tra = 0; - rr->pid = pid; - rr->pc = regs->pc; - event_ptr = (event_ptr + 1) & 15; -} - -void evt_debug_ret_from_exc(struct pt_regs *regs) -{ - int pid; - struct ring_node *rr; - - pid = current->pid; - rr = event_ring + event_ptr; - rr->evt = 0xfffe; - rr->ret_addr = 0; - rr->event = 0; - rr->tra = 0; - rr->pid = pid; - rr->pc = regs->pc; - event_ptr = (event_ptr + 1) & 15; -} - -#endif /* CONFIG_POOR_MANS_STRACE */ - -/* ======================================================================= */ - void show_excp_regs(char *from, int trapnr, int signr, struct pt_regs *regs) { @@ -380,51 +246,3 @@ void show_excp_regs(char *from, int trapnr, int signr, struct pt_regs *regs) print_dtlb(); print_itlb(); } - -/* ======================================================================= */ - -/* -** Depending on scan the MMU, Data or Instruction side -** looking for a valid mapping matching Eaddr & asid. -** Return -1 if not found or the TLB id entry otherwise. -** Note: it works only for 4k pages! -*/ -static unsigned long -lookup_mmu_side(unsigned long base, unsigned long Eaddr, unsigned long asid) -{ - regType_t pteH; - unsigned long epn; - int count; - - epn = Eaddr & 0xfffff000; - - for (count = 0; count < MAX_TLBs; count++, base += TLB_STEP) { - pteH = getConfigReg(base); - if (GET_VALID(pteH)) - if ((unsigned long) GET_EPN(pteH) == epn) - if ((unsigned long) GET_ASID(pteH) == asid) - break; - } - return ((unsigned long) ((count < MAX_TLBs) ? base : -1)); -} - -unsigned long lookup_dtlb(unsigned long Eaddr) -{ - unsigned long asid = get_asid(); - return (lookup_mmu_side((u64) DTLB_BASE, Eaddr, asid)); -} - -unsigned long lookup_itlb(unsigned long Eaddr) -{ - unsigned long asid = get_asid(); - return (lookup_mmu_side((u64) ITLB_BASE, Eaddr, asid)); -} - -void print_page(struct page *page) -{ - printk(" page[%p] -> index 0x%lx, count 0x%x, flags 0x%lx\n", - page, page->index, page_count(page), page->flags); - printk(" address_space = %p, pages =%ld\n", page->mapping, - page->mapping->nrpages); - -} diff --git a/arch/sh/lib64/panic.c b/arch/sh/lib64/panic.c index da32ba7b5fcc..38c954e04f6a 100644 --- a/arch/sh/lib64/panic.c +++ b/arch/sh/lib64/panic.c @@ -6,53 +6,10 @@ * for more details. */ -#include -#include -#include - -/* THIS IS A PHYSICAL ADDRESS */ -#define HDSP2534_ADDR (0x04002100) - -#ifdef CONFIG_SH_CAYMAN - -static void poor_mans_delay(void) -{ - int i; - for (i = 0; i < 2500000; i++) { - } /* poor man's delay */ -} - -static void show_value(unsigned long x) -{ - int i; - unsigned nibble; - for (i = 0; i < 8; i++) { - nibble = ((x >> (i * 4)) & 0xf); - - ctrl_outb(nibble + ((nibble > 9) ? 55 : 48), - HDSP2534_ADDR + 0xe0 + ((7 - i) << 2)); - } -} - -#endif - void panic_handler(unsigned long panicPC, unsigned long panicSSR, unsigned long panicEXPEVT) { -#ifdef CONFIG_SH_CAYMAN - while (1) { - /* This piece of code displays the PC on the LED display */ - show_value(panicPC); - poor_mans_delay(); - show_value(panicSSR); - poor_mans_delay(); - show_value(panicEXPEVT); - poor_mans_delay(); - } -#endif - /* Never return from the panic handler */ for (;;) ; - } diff --git a/arch/sh/lib64/sdivsi3.S b/arch/sh/lib64/sdivsi3.S index 6a800c6a4904..1963bbd42288 100644 --- a/arch/sh/lib64/sdivsi3.S +++ b/arch/sh/lib64/sdivsi3.S @@ -1,4 +1,6 @@ .global __sdivsi3 + .global __sdivsi3_1 + .global __sdivsi3_2 .section .text..SHmedia32,"ax" .align 2 @@ -6,13 +8,15 @@ /* clobbered: r1,r18,r19,r20,r21,r25,tr0 */ /* result in r0 */ __sdivsi3: +__sdivsi3_1: ptb __div_table,tr0 + gettr tr0,r20 +__sdivsi3_2: nsb r5, r1 shlld r5, r1, r25 /* normalize; [-2 ..1, 1..2) in s2.62 */ shari r25, 58, r21 /* extract 5(6) bit index (s2.4 with hole -1..1) */ /* bubble */ - gettr tr0,r20 ldx.ub r20, r21, r19 /* u0.8 */ shari r25, 32, r25 /* normalize to s2.30 */ shlli r21, 1, r21 diff --git a/arch/sh/lib64/udelay.c b/arch/sh/lib64/udelay.c index d76bd801194f..f215b063da70 100644 --- a/arch/sh/lib64/udelay.c +++ b/arch/sh/lib64/udelay.c @@ -33,7 +33,7 @@ void __delay(unsigned long loops) :"0"(loops)); } -inline void __const_udelay(unsigned long xloops) +void __const_udelay(unsigned long xloops) { __delay(xloops * (HZ * cpu_data[raw_smp_processor_id()].loops_per_jiffy)); } diff --git a/arch/sh/mm/Kconfig b/arch/sh/mm/Kconfig index d4079cab2d58..2795618e4f07 100644 --- a/arch/sh/mm/Kconfig +++ b/arch/sh/mm/Kconfig @@ -21,6 +21,29 @@ config PAGE_OFFSET default "0x20000000" if MMU && SUPERH64 default "0x00000000" +config FORCE_MAX_ZONEORDER + int "Maximum zone order" + range 9 64 if PAGE_SIZE_16KB + default "9" if PAGE_SIZE_16KB + range 7 64 if PAGE_SIZE_64KB + default "7" if PAGE_SIZE_64KB + range 11 64 + default "14" if !MMU + default "11" + help + The kernel memory allocator divides physically contiguous memory + blocks into "zones", where each zone is a power of two number of + pages. This option selects the largest power of two that the kernel + keeps in the memory allocator. If you need to allocate very large + blocks of physically contiguous memory, then you may need to + increase this value. + + This config option is actually maximum order plus one. For example, + a value of 11 means that the largest free memory block is 2^10 pages. + + The page size is not necessarily 4KB. Keep this in mind when + choosing a value for this option. + config MEMORY_START hex "Physical memory start address" default "0x08000000" @@ -201,14 +224,6 @@ config PAGE_SIZE_64KB endchoice -config ENTRY_OFFSET - hex - default "0x00001000" if PAGE_SIZE_4KB - default "0x00002000" if PAGE_SIZE_8KB - default "0x00004000" if PAGE_SIZE_16KB - default "0x00010000" if PAGE_SIZE_64KB - default "0x00000000" - choice prompt "HugeTLB page size" depends on HUGETLB_PAGE && (CPU_SH4 || CPU_SH5) && MMU diff --git a/arch/sh/mm/cache-sh5.c b/arch/sh/mm/cache-sh5.c index 9e277ec7d536..86762092508c 100644 --- a/arch/sh/mm/cache-sh5.c +++ b/arch/sh/mm/cache-sh5.c @@ -60,7 +60,7 @@ static inline void sh64_teardown_dtlb_cache_slot(void) static inline void sh64_icache_inv_all(void) { unsigned long long addr, flag, data; - unsigned int flags; + unsigned long flags; addr = ICCR0; flag = ICCR0_ICI; @@ -172,7 +172,7 @@ static void sh64_icache_inv_user_page_range(struct mm_struct *mm, unsigned long eaddr; unsigned long after_last_page_start; unsigned long mm_asid, current_asid; - unsigned long long flags = 0ULL; + unsigned long flags = 0; mm_asid = cpu_asid(smp_processor_id(), mm); current_asid = get_asid(); @@ -236,7 +236,7 @@ static void sh64_icache_inv_user_small_range(struct mm_struct *mm, unsigned long long eaddr = start; unsigned long long eaddr_end = start + len; unsigned long current_asid, mm_asid; - unsigned long long flags; + unsigned long flags; unsigned long long epage_start; /* @@ -342,7 +342,7 @@ static void inline sh64_dcache_purge_sets(int sets_to_purge_base, int n_sets) * alloco is a NOP if the cache is write-through. */ if (test_bit(SH_CACHE_MODE_WT, &(cpu_data->dcache.flags))) - ctrl_inb(eaddr); + __raw_readb((unsigned long)eaddr); } } diff --git a/arch/sh/mm/fault_32.c b/arch/sh/mm/fault_32.c index 31a33ebdef6f..cc8ddbdf3d7a 100644 --- a/arch/sh/mm/fault_32.c +++ b/arch/sh/mm/fault_32.c @@ -133,7 +133,7 @@ good_area: * the fault. */ survive: - fault = handle_mm_fault(mm, vma, address, writeaccess); + fault = handle_mm_fault(mm, vma, address, writeaccess ? FAULT_FLAG_WRITE : 0); if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; @@ -249,9 +249,6 @@ static inline int notify_page_fault(struct pt_regs *regs, int trap) { int ret = 0; - trace_mark(kernel_arch_trap_entry, "trap_id %d ip #p%ld", - trap >> 5, instruction_pointer(regs)); - #ifdef CONFIG_KPROBES if (!user_mode(regs)) { preempt_disable(); @@ -327,6 +324,5 @@ asmlinkage int __kprobes __do_page_fault(struct pt_regs *regs, ret = 0; out: - trace_mark(kernel_arch_trap_exit, MARK_NOARGS); return ret; } diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c index 3edf297c829b..fe532aeaa16d 100644 --- a/arch/sh/mm/init.c +++ b/arch/sh/mm/init.c @@ -70,7 +70,7 @@ static void set_pte_phys(unsigned long addr, unsigned long phys, pgprot_t prot) } set_pte(pte, pfn_pte(phys >> PAGE_SHIFT, prot)); - flush_tlb_one(get_asid(), addr); + local_flush_tlb_one(get_asid(), addr); } /* @@ -177,14 +177,11 @@ void __init paging_init(void) free_area_init_nodes(max_zone_pfns); -#ifdef CONFIG_SUPERH32 /* Set up the uncached fixmap */ set_fixmap_nocache(FIX_UNCACHED, __pa(&__uncached_start)); -#endif } static struct kcore_list kcore_mem, kcore_vmalloc; -int after_bootmem = 0; void __init mem_init(void) { @@ -217,8 +214,6 @@ void __init mem_init(void) memset(empty_zero_page, 0, PAGE_SIZE); __flush_wback_region(empty_zero_page, PAGE_SIZE); - after_bootmem = 1; - codesize = (unsigned long) &_etext - (unsigned long) &_text; datasize = (unsigned long) &_edata - (unsigned long) &_etext; initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin; diff --git a/arch/sh/mm/ioremap_32.c b/arch/sh/mm/ioremap_32.c index 60cc486d2c2c..da2f4186f2cd 100644 --- a/arch/sh/mm/ioremap_32.c +++ b/arch/sh/mm/ioremap_32.c @@ -46,17 +46,15 @@ void __iomem *__ioremap(unsigned long phys_addr, unsigned long size, return NULL; /* - * If we're on an SH7751 or SH7780 PCI controller, PCI memory is - * mapped at the end of the address space (typically 0xfd000000) - * in a non-translatable area, so mapping through page tables for - * this area is not only pointless, but also fundamentally - * broken. Just return the physical address instead. + * If we're in the fixed PCI memory range, mapping through page + * tables is not only pointless, but also fundamentally broken. + * Just return the physical address instead. * * For boards that map a small PCI memory aperture somewhere in * P1/P2 space, ioremap() will already do the right thing, * and we'll never get this far. */ - if (is_pci_memaddr(phys_addr) && is_pci_memaddr(last_addr)) + if (is_pci_memory_fixed_range(phys_addr, size)) return (void __iomem *)phys_addr; #if !defined(CONFIG_PMB_FIXED) @@ -121,7 +119,9 @@ void __iounmap(void __iomem *addr) unsigned long seg = PXSEG(vaddr); struct vm_struct *p; - if (seg < P3SEG || vaddr >= P3_ADDR_MAX || is_pci_memaddr(vaddr)) + if (seg < P3SEG || vaddr >= P3_ADDR_MAX) + return; + if (is_pci_memory_fixed_range(vaddr, 0)) return; #ifdef CONFIG_PMB diff --git a/arch/sh/mm/ioremap_64.c b/arch/sh/mm/ioremap_64.c index 31e1bb5effbe..828c8597219d 100644 --- a/arch/sh/mm/ioremap_64.c +++ b/arch/sh/mm/ioremap_64.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -27,88 +28,17 @@ #include #include -static void shmedia_mapioaddr(unsigned long, unsigned long); -static unsigned long shmedia_ioremap(struct resource *, u32, int); - -/* - * Generic mapping function (not visible outside): - */ - -/* - * Remap an arbitrary physical address space into the kernel virtual - * address space. Needed when the kernel wants to access high addresses - * directly. - * - * NOTE! We need to allow non-page-aligned mappings too: we will obviously - * have to convert them into an offset in a page-aligned mapping, but the - * caller shouldn't need to know that small detail. - */ -void *__ioremap(unsigned long phys_addr, unsigned long size, - unsigned long flags) -{ - void * addr; - struct vm_struct * area; - unsigned long offset, last_addr; - pgprot_t pgprot; - - /* Don't allow wraparound or zero size */ - last_addr = phys_addr + size - 1; - if (!size || last_addr < phys_addr) - return NULL; - - pgprot = __pgprot(_PAGE_PRESENT | _PAGE_READ | - _PAGE_WRITE | _PAGE_DIRTY | - _PAGE_ACCESSED | _PAGE_SHARED | flags); - - /* - * Mappings have to be page-aligned - */ - offset = phys_addr & ~PAGE_MASK; - phys_addr &= PAGE_MASK; - size = PAGE_ALIGN(last_addr + 1) - phys_addr; - - /* - * Ok, go for it.. - */ - area = get_vm_area(size, VM_IOREMAP); - if (!area) - return NULL; - pr_debug("Get vm_area returns %p addr %p\n", area, area->addr); - area->phys_addr = phys_addr; - addr = area->addr; - if (ioremap_page_range((unsigned long)addr, (unsigned long)addr + size, - phys_addr, pgprot)) { - vunmap(addr); - return NULL; - } - return (void *) (offset + (char *)addr); -} -EXPORT_SYMBOL(__ioremap); - -void __iounmap(void *addr) -{ - struct vm_struct *area; - - vfree((void *) (PAGE_MASK & (unsigned long) addr)); - area = remove_vm_area((void *) (PAGE_MASK & (unsigned long) addr)); - if (!area) { - printk(KERN_ERR "iounmap: bad address %p\n", addr); - return; - } - - kfree(area); -} -EXPORT_SYMBOL(__iounmap); - static struct resource shmedia_iomap = { .name = "shmedia_iomap", .start = IOBASE_VADDR + PAGE_SIZE, .end = IOBASE_END - 1, }; -static void shmedia_mapioaddr(unsigned long pa, unsigned long va); +static void shmedia_mapioaddr(unsigned long pa, unsigned long va, + unsigned long flags); static void shmedia_unmapioaddr(unsigned long vaddr); -static unsigned long shmedia_ioremap(struct resource *res, u32 pa, int sz); +static void __iomem *shmedia_ioremap(struct resource *res, u32 pa, + int sz, unsigned long flags); /* * We have the same problem as the SPARC, so lets have the same comment: @@ -130,18 +60,18 @@ static struct xresource xresv[XNRES]; static struct xresource *xres_alloc(void) { - struct xresource *xrp; - int n; + struct xresource *xrp; + int n; - xrp = xresv; - for (n = 0; n < XNRES; n++) { - if (xrp->xflag == 0) { - xrp->xflag = 1; - return xrp; - } - xrp++; - } - return NULL; + xrp = xresv; + for (n = 0; n < XNRES; n++) { + if (xrp->xflag == 0) { + xrp->xflag = 1; + return xrp; + } + xrp++; + } + return NULL; } static void xres_free(struct xresource *xrp) @@ -161,76 +91,71 @@ static struct resource *shmedia_find_resource(struct resource *root, return NULL; } -static unsigned long shmedia_alloc_io(unsigned long phys, unsigned long size, - const char *name) +static void __iomem *shmedia_alloc_io(unsigned long phys, unsigned long size, + const char *name, unsigned long flags) { - static int printed_full = 0; - struct xresource *xres; - struct resource *res; - char *tack; - int tlen; + static int printed_full; + struct xresource *xres; + struct resource *res; + char *tack; + int tlen; - if (name == NULL) name = "???"; + if (name == NULL) + name = "???"; - if ((xres = xres_alloc()) != 0) { - tack = xres->xname; - res = &xres->xres; - } else { - if (!printed_full) { - printk("%s: done with statics, switching to kmalloc\n", - __func__); - printed_full = 1; - } - tlen = strlen(name); - tack = kmalloc(sizeof (struct resource) + tlen + 1, GFP_KERNEL); - if (!tack) - return -ENOMEM; - memset(tack, 0, sizeof(struct resource)); - res = (struct resource *) tack; - tack += sizeof (struct resource); - } + xres = xres_alloc(); + if (xres != 0) { + tack = xres->xname; + res = &xres->xres; + } else { + if (!printed_full) { + printk(KERN_NOTICE "%s: done with statics, " + "switching to kmalloc\n", __func__); + printed_full = 1; + } + tlen = strlen(name); + tack = kmalloc(sizeof(struct resource) + tlen + 1, GFP_KERNEL); + if (!tack) + return NULL; + memset(tack, 0, sizeof(struct resource)); + res = (struct resource *) tack; + tack += sizeof(struct resource); + } - strncpy(tack, name, XNMLN); - tack[XNMLN] = 0; - res->name = tack; + strncpy(tack, name, XNMLN); + tack[XNMLN] = 0; + res->name = tack; - return shmedia_ioremap(res, phys, size); + return shmedia_ioremap(res, phys, size, flags); } -static unsigned long shmedia_ioremap(struct resource *res, u32 pa, int sz) +static void __iomem *shmedia_ioremap(struct resource *res, u32 pa, int sz, + unsigned long flags) { - unsigned long offset = ((unsigned long) pa) & (~PAGE_MASK); + unsigned long offset = ((unsigned long) pa) & (~PAGE_MASK); unsigned long round_sz = (offset + sz + PAGE_SIZE-1) & PAGE_MASK; - unsigned long va; - unsigned int psz; + unsigned long va; + unsigned int psz; - if (allocate_resource(&shmedia_iomap, res, round_sz, + if (allocate_resource(&shmedia_iomap, res, round_sz, shmedia_iomap.start, shmedia_iomap.end, PAGE_SIZE, NULL, NULL) != 0) { - panic("alloc_io_res(%s): cannot occupy\n", - (res->name != NULL)? res->name: "???"); - } + panic("alloc_io_res(%s): cannot occupy\n", + (res->name != NULL) ? res->name : "???"); + } - va = res->start; - pa &= PAGE_MASK; + va = res->start; + pa &= PAGE_MASK; psz = (res->end - res->start + (PAGE_SIZE - 1)) / PAGE_SIZE; - /* log at boot time ... */ - printk("mapioaddr: %6s [%2d page%s] va 0x%08lx pa 0x%08x\n", - ((res->name != NULL) ? res->name : "???"), - psz, psz == 1 ? " " : "s", va, pa); + for (psz = res->end - res->start + 1; psz != 0; psz -= PAGE_SIZE) { + shmedia_mapioaddr(pa, va, flags); + va += PAGE_SIZE; + pa += PAGE_SIZE; + } - for (psz = res->end - res->start + 1; psz != 0; psz -= PAGE_SIZE) { - shmedia_mapioaddr(pa, va); - va += PAGE_SIZE; - pa += PAGE_SIZE; - } - - res->start += offset; - res->end = res->start + sz - 1; /* not strictly necessary.. */ - - return res->start; + return (void __iomem *)(unsigned long)(res->start + offset); } static void shmedia_free_io(struct resource *res) @@ -249,14 +174,12 @@ static void shmedia_free_io(struct resource *res) static __init_refok void *sh64_get_page(void) { - extern int after_bootmem; void *page; - if (after_bootmem) { - page = (void *)get_zeroed_page(GFP_ATOMIC); - } else { + if (slab_is_available()) + page = (void *)get_zeroed_page(GFP_KERNEL); + else page = alloc_bootmem_pages(PAGE_SIZE); - } if (!page || ((unsigned long)page & ~PAGE_MASK)) panic("sh64_get_page: Out of memory already?\n"); @@ -264,17 +187,20 @@ static __init_refok void *sh64_get_page(void) return page; } -static void shmedia_mapioaddr(unsigned long pa, unsigned long va) +static void shmedia_mapioaddr(unsigned long pa, unsigned long va, + unsigned long flags) { pgd_t *pgdp; pud_t *pudp; pmd_t *pmdp; pte_t *ptep, pte; pgprot_t prot; - unsigned long flags = 1; /* 1 = CB0-1 device */ pr_debug("shmedia_mapiopage pa %08lx va %08lx\n", pa, va); + if (!flags) + flags = 1; /* 1 = CB0-1 device */ + pgdp = pgd_offset_k(va); if (pgd_none(*pgdp) || !pgd_present(*pgdp)) { pudp = (pud_t *)sh64_get_page(); @@ -288,7 +214,7 @@ static void shmedia_mapioaddr(unsigned long pa, unsigned long va) } pmdp = pmd_offset(pudp, va); - if (pmd_none(*pmdp) || !pmd_present(*pmdp) ) { + if (pmd_none(*pmdp) || !pmd_present(*pmdp)) { ptep = (pte_t *)sh64_get_page(); set_pmd(pmdp, __pmd((unsigned long)ptep + _PAGE_TABLE)); } @@ -336,17 +262,19 @@ static void shmedia_unmapioaddr(unsigned long vaddr) pte_clear(&init_mm, vaddr, ptep); } -unsigned long onchip_remap(unsigned long phys, unsigned long size, const char *name) +void __iomem *__ioremap(unsigned long offset, unsigned long size, + unsigned long flags) { - if (size < PAGE_SIZE) - size = PAGE_SIZE; + char name[14]; - return shmedia_alloc_io(phys, size, name); + sprintf(name, "phys_%08x", (u32)offset); + return shmedia_alloc_io(offset, size, name, flags); } -EXPORT_SYMBOL(onchip_remap); +EXPORT_SYMBOL(__ioremap); -void onchip_unmap(unsigned long vaddr) +void __iounmap(void __iomem *virtual) { + unsigned long vaddr = (unsigned long)virtual & PAGE_MASK; struct resource *res; unsigned int psz; @@ -357,10 +285,7 @@ void onchip_unmap(unsigned long vaddr) return; } - psz = (res->end - res->start + (PAGE_SIZE - 1)) / PAGE_SIZE; - - printk(KERN_DEBUG "unmapioaddr: %6s [%2d page%s] freed\n", - res->name, psz, psz == 1 ? " " : "s"); + psz = (res->end - res->start + (PAGE_SIZE - 1)) / PAGE_SIZE; shmedia_free_io(res); @@ -371,9 +296,8 @@ void onchip_unmap(unsigned long vaddr) kfree(res); } } -EXPORT_SYMBOL(onchip_unmap); +EXPORT_SYMBOL(__iounmap); -#ifdef CONFIG_PROC_FS static int ioremap_proc_info(char *buf, char **start, off_t fpos, int length, int *eof, void *data) @@ -385,7 +309,10 @@ ioremap_proc_info(char *buf, char **start, off_t fpos, int length, int *eof, for (r = ((struct resource *)data)->child; r != NULL; r = r->sibling) { if (p + 32 >= e) /* Better than nothing */ break; - if ((nm = r->name) == 0) nm = "???"; + nm = r->name; + if (nm == NULL) + nm = "???"; + p += sprintf(p, "%08lx-%08lx: %s\n", (unsigned long)r->start, (unsigned long)r->end, nm); @@ -393,14 +320,11 @@ ioremap_proc_info(char *buf, char **start, off_t fpos, int length, int *eof, return p-buf; } -#endif /* CONFIG_PROC_FS */ static int __init register_proc_onchip(void) { -#ifdef CONFIG_PROC_FS - create_proc_read_entry("io_map",0,0, ioremap_proc_info, &shmedia_iomap); -#endif + create_proc_read_entry("io_map", 0, 0, ioremap_proc_info, + &shmedia_iomap); return 0; } - -__initcall(register_proc_onchip); +late_initcall(register_proc_onchip); diff --git a/arch/sh/mm/mmap.c b/arch/sh/mm/mmap.c index 931f4d003fa0..1b5fdfb4e0c2 100644 --- a/arch/sh/mm/mmap.c +++ b/arch/sh/mm/mmap.c @@ -1,7 +1,7 @@ /* * arch/sh/mm/mmap.c * - * Copyright (C) 2008 Paul Mundt + * Copyright (C) 2008 - 2009 Paul Mundt * * 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 @@ -21,9 +21,26 @@ EXPORT_SYMBOL(shm_align_mask); /* * To avoid cache aliases, we map the shared page with same color. */ -#define COLOUR_ALIGN(addr, pgoff) \ - ((((addr) + shm_align_mask) & ~shm_align_mask) + \ - (((pgoff) << PAGE_SHIFT) & shm_align_mask)) +static inline unsigned long COLOUR_ALIGN(unsigned long addr, + unsigned long pgoff) +{ + unsigned long base = (addr + shm_align_mask) & ~shm_align_mask; + unsigned long off = (pgoff << PAGE_SHIFT) & shm_align_mask; + + return base + off; +} + +static inline unsigned long COLOUR_ALIGN_DOWN(unsigned long addr, + unsigned long pgoff) +{ + unsigned long base = addr & ~shm_align_mask; + unsigned long off = (pgoff << PAGE_SHIFT) & shm_align_mask; + + if (base + off <= addr) + return base + off; + + return base - off; +} unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags) @@ -103,6 +120,117 @@ full_search: addr = COLOUR_ALIGN(addr, pgoff); } } + +unsigned long +arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, + const unsigned long len, const unsigned long pgoff, + const unsigned long flags) +{ + struct vm_area_struct *vma; + struct mm_struct *mm = current->mm; + unsigned long addr = addr0; + int do_colour_align; + + if (flags & MAP_FIXED) { + /* We do not accept a shared mapping if it would violate + * cache aliasing constraints. + */ + if ((flags & MAP_SHARED) && + ((addr - (pgoff << PAGE_SHIFT)) & shm_align_mask)) + return -EINVAL; + return addr; + } + + if (unlikely(len > TASK_SIZE)) + return -ENOMEM; + + do_colour_align = 0; + if (filp || (flags & MAP_SHARED)) + do_colour_align = 1; + + /* requesting a specific address */ + if (addr) { + if (do_colour_align) + addr = COLOUR_ALIGN(addr, pgoff); + else + addr = PAGE_ALIGN(addr); + + vma = find_vma(mm, addr); + if (TASK_SIZE - len >= addr && + (!vma || addr + len <= vma->vm_start)) + return addr; + } + + /* check if free_area_cache is useful for us */ + if (len <= mm->cached_hole_size) { + mm->cached_hole_size = 0; + mm->free_area_cache = mm->mmap_base; + } + + /* either no address requested or can't fit in requested address hole */ + addr = mm->free_area_cache; + if (do_colour_align) { + unsigned long base = COLOUR_ALIGN_DOWN(addr-len, pgoff); + + addr = base + len; + } + + /* make sure it can fit in the remaining address space */ + if (likely(addr > len)) { + vma = find_vma(mm, addr-len); + if (!vma || addr <= vma->vm_start) { + /* remember the address as a hint for next time */ + return (mm->free_area_cache = addr-len); + } + } + + if (unlikely(mm->mmap_base < len)) + goto bottomup; + + addr = mm->mmap_base-len; + if (do_colour_align) + addr = COLOUR_ALIGN_DOWN(addr, pgoff); + + do { + /* + * Lookup failure means no vma is above this address, + * else if new region fits below vma->vm_start, + * return with success: + */ + vma = find_vma(mm, addr); + if (likely(!vma || addr+len <= vma->vm_start)) { + /* remember the address as a hint for next time */ + return (mm->free_area_cache = addr); + } + + /* remember the largest hole we saw so far */ + if (addr + mm->cached_hole_size < vma->vm_start) + mm->cached_hole_size = vma->vm_start - addr; + + /* try just below the current vma->vm_start */ + addr = vma->vm_start-len; + if (do_colour_align) + addr = COLOUR_ALIGN_DOWN(addr, pgoff); + } while (likely(len < vma->vm_start)); + +bottomup: + /* + * A failed mmap() very likely causes application failure, + * so fall back to the bottom-up function here. This scenario + * can happen with large stack limits and large mmap() + * allocations. + */ + mm->cached_hole_size = ~0UL; + mm->free_area_cache = TASK_UNMAPPED_BASE; + addr = arch_get_unmapped_area(filp, addr0, len, pgoff, flags); + /* + * Restore the topdown base: + */ + mm->free_area_cache = mm->mmap_base; + mm->cached_hole_size = ~0UL; + + return addr; +} #endif /* CONFIG_MMU */ /* diff --git a/arch/sh/mm/tlbflush_64.c b/arch/sh/mm/tlbflush_64.c index 7876997ba19a..fcbb6e135cef 100644 --- a/arch/sh/mm/tlbflush_64.c +++ b/arch/sh/mm/tlbflush_64.c @@ -187,7 +187,7 @@ good_area: * the fault. */ survive: - fault = handle_mm_fault(mm, vma, address, writeaccess); + fault = handle_mm_fault(mm, vma, address, writeaccess ? FAULT_FLAG_WRITE : 0); if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; diff --git a/arch/sh/oprofile/common.c b/arch/sh/oprofile/common.c index 1b9d4304b3bf..44f4e31c6d63 100644 --- a/arch/sh/oprofile/common.c +++ b/arch/sh/oprofile/common.c @@ -109,6 +109,7 @@ int __init oprofile_arch_init(struct oprofile_operations *ops) case CPU_SH7785: case CPU_SH7786: case CPU_SH7723: + case CPU_SH7724: case CPU_SHX3: lmodel = &op_model_sh4a_ops; break; diff --git a/arch/sh/tools/mach-types b/arch/sh/tools/mach-types index 8477b5d884fd..fec3a53b8650 100644 --- a/arch/sh/tools/mach-types +++ b/arch/sh/tools/mach-types @@ -23,6 +23,7 @@ HD64461 HD64461 7619SE SH_7619_SOLUTION_ENGINE 7721SE SH_7721_SOLUTION_ENGINE 7722SE SH_7722_SOLUTION_ENGINE +7724SE SH_7724_SOLUTION_ENGINE 7751SE SH_7751_SOLUTION_ENGINE 7780SE SH_7780_SOLUTION_ENGINE 7751SYSTEMH SH_7751_SYSTEMH diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index cc12cd48bbc5..3f8b6a92eabd 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -37,6 +37,8 @@ config SPARC64 select HAVE_KPROBES select HAVE_LMB select HAVE_SYSCALL_WRAPPERS + select HAVE_DYNAMIC_FTRACE + select HAVE_FTRACE_MCOUNT_RECORD select USE_GENERIC_SMP_HELPERS if SMP select RTC_DRV_CMOS select RTC_DRV_BQ4802 @@ -93,6 +95,9 @@ config AUDIT_ARCH config HAVE_SETUP_PER_CPU_AREA def_bool y if SPARC64 +config HAVE_DYNAMIC_PER_CPU_AREA + def_bool y if SPARC64 + config GENERIC_HARDIRQS_NO__DO_IRQ bool def_bool y if SPARC64 diff --git a/arch/sparc/configs/sparc64_defconfig b/arch/sparc/configs/sparc64_defconfig index b5d63bd8716e..0123a4c596ce 100644 --- a/arch/sparc/configs/sparc64_defconfig +++ b/arch/sparc/configs/sparc64_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.30-rc2 -# Fri Apr 17 02:03:07 2009 +# Linux kernel version: 2.6.30 +# Tue Jun 16 04:59:36 2009 # CONFIG_64BIT=y CONFIG_SPARC=y @@ -19,6 +19,7 @@ CONFIG_LOCKDEP_SUPPORT=y CONFIG_HAVE_LATENCYTOP_SUPPORT=y CONFIG_AUDIT_ARCH=y CONFIG_HAVE_SETUP_PER_CPU_AREA=y +CONFIG_HAVE_DYNAMIC_PER_CPU_AREA=y CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y CONFIG_MMU=y CONFIG_ARCH_NO_VIRT_TO_BUS=y @@ -82,7 +83,6 @@ CONFIG_SYSCTL_SYSCALL=y CONFIG_KALLSYMS=y # CONFIG_KALLSYMS_ALL is not set # CONFIG_KALLSYMS_EXTRA_PASS is not set -# CONFIG_STRIP_ASM_SYMS is not set CONFIG_HOTPLUG=y CONFIG_PRINTK=y CONFIG_BUG=y @@ -95,16 +95,21 @@ CONFIG_TIMERFD=y CONFIG_EVENTFD=y CONFIG_SHMEM=y CONFIG_AIO=y + +# +# Performance Counters +# CONFIG_VM_EVENT_COUNTERS=y CONFIG_PCI_QUIRKS=y CONFIG_SLUB_DEBUG=y +# CONFIG_STRIP_ASM_SYMS is not set # CONFIG_COMPAT_BRK is not set # CONFIG_SLAB is not set CONFIG_SLUB=y # CONFIG_SLOB is not set CONFIG_PROFILING=y CONFIG_TRACEPOINTS=y -# CONFIG_MARKERS is not set +CONFIG_MARKERS=y CONFIG_OPROFILE=m CONFIG_HAVE_OPROFILE=y CONFIG_KPROBES=y @@ -202,6 +207,7 @@ CONFIG_NR_QUICK=1 CONFIG_UNEVICTABLE_LRU=y CONFIG_HAVE_MLOCK=y CONFIG_HAVE_MLOCKED_PAGE_BIT=y +CONFIG_DEFAULT_MMAP_MIN_ADDR=8192 CONFIG_SCHED_SMT=y CONFIG_SCHED_MC=y # CONFIG_PREEMPT_NONE is not set @@ -321,6 +327,7 @@ CONFIG_VLAN_8021Q=m # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set # CONFIG_PHONET is not set +# CONFIG_IEEE802154 is not set # CONFIG_NET_SCHED is not set # CONFIG_DCB is not set @@ -340,7 +347,11 @@ CONFIG_WIRELESS=y CONFIG_WIRELESS_OLD_REGULATORY=y # CONFIG_WIRELESS_EXT is not set # CONFIG_LIB80211 is not set -# CONFIG_MAC80211 is not set + +# +# CFG80211 needs to be enabled for MAC80211 +# +CONFIG_MAC80211_DEFAULT_PS_VALUE=0 # CONFIG_WIMAX is not set # CONFIG_RFKILL is not set # CONFIG_NET_9P is not set @@ -364,6 +375,7 @@ CONFIG_EXTRA_FIRMWARE="" CONFIG_CONNECTOR=m # CONFIG_MTD is not set CONFIG_OF_DEVICE=y +CONFIG_OF_MDIO=m # CONFIG_PARPORT is not set CONFIG_BLK_DEV=y # CONFIG_BLK_DEV_FD is not set @@ -399,6 +411,7 @@ CONFIG_MISC_DEVICES=y # CONFIG_EEPROM_AT24 is not set # CONFIG_EEPROM_LEGACY is not set # CONFIG_EEPROM_93CX6 is not set +# CONFIG_CB710_CORE is not set CONFIG_HAVE_IDE=y CONFIG_IDE=y @@ -477,10 +490,6 @@ CONFIG_BLK_DEV_SR=m CONFIG_BLK_DEV_SR_VENDOR=y CONFIG_CHR_DEV_SG=m # CONFIG_CHR_DEV_SCH is not set - -# -# Some SCSI devices (e.g. CD jukebox) support multiple LUNs -# CONFIG_SCSI_MULTI_LUN=y CONFIG_SCSI_CONSTANTS=y # CONFIG_SCSI_LOGGING is not set @@ -499,6 +508,7 @@ CONFIG_SCSI_FC_ATTRS=y CONFIG_SCSI_LOWLEVEL=y # CONFIG_ISCSI_TCP is not set # CONFIG_SCSI_CXGB3_ISCSI is not set +# CONFIG_SCSI_BNX2_ISCSI is not set # CONFIG_BLK_DEV_3W_XXXX_RAID is not set # CONFIG_SCSI_3W_9XXX is not set # CONFIG_SCSI_ACARD is not set @@ -507,6 +517,7 @@ CONFIG_SCSI_LOWLEVEL=y # CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_AIC79XX is not set # CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_MVSAS is not set # CONFIG_SCSI_ARCMSR is not set # CONFIG_MEGARAID_NEWGEN is not set # CONFIG_MEGARAID_LEGACY is not set @@ -521,7 +532,6 @@ CONFIG_SCSI_LOWLEVEL=y # CONFIG_SCSI_IPS is not set # CONFIG_SCSI_INITIO is not set # CONFIG_SCSI_INIA100 is not set -# CONFIG_SCSI_MVSAS is not set # CONFIG_SCSI_STEX is not set # CONFIG_SCSI_SYM53C8XX_2 is not set # CONFIG_SCSI_QLOGIC_1280 is not set @@ -569,7 +579,6 @@ CONFIG_DM_ZERO=m # CONFIG_IEEE1394 is not set # CONFIG_I2O is not set CONFIG_NETDEVICES=y -CONFIG_COMPAT_NET_DEV_OPS=y # CONFIG_DUMMY is not set # CONFIG_BONDING is not set # CONFIG_MACVLAN is not set @@ -635,6 +644,7 @@ CONFIG_NET_PCI=y # CONFIG_SMSC9420 is not set # CONFIG_SUNDANCE is not set # CONFIG_TLAN is not set +# CONFIG_KS8842 is not set # CONFIG_VIA_RHINE is not set # CONFIG_SC92031 is not set # CONFIG_ATL2 is not set @@ -1127,6 +1137,11 @@ CONFIG_SND_VERBOSE_PROCFS=y # CONFIG_SND_VERBOSE_PRINTK is not set # CONFIG_SND_DEBUG is not set CONFIG_SND_VMASTER=y +CONFIG_SND_RAWMIDI_SEQ=m +# CONFIG_SND_OPL3_LIB_SEQ is not set +# CONFIG_SND_OPL4_LIB_SEQ is not set +# CONFIG_SND_SBAWE_SEQ is not set +# CONFIG_SND_EMU10K1_SEQ is not set CONFIG_SND_MPU401_UART=m CONFIG_SND_AC97_CODEC=m CONFIG_SND_DRIVERS=y @@ -1153,6 +1168,7 @@ CONFIG_SND_ALI5451=m # CONFIG_SND_OXYGEN is not set # CONFIG_SND_CS4281 is not set # CONFIG_SND_CS46XX is not set +# CONFIG_SND_CTXFI is not set # CONFIG_SND_DARLA20 is not set # CONFIG_SND_GINA20 is not set # CONFIG_SND_LAYLA20 is not set @@ -1183,6 +1199,7 @@ CONFIG_SND_ALI5451=m # CONFIG_SND_INTEL8X0 is not set # CONFIG_SND_INTEL8X0M is not set # CONFIG_SND_KORG1212 is not set +# CONFIG_SND_LX6464ES is not set # CONFIG_SND_MAESTRO3 is not set # CONFIG_SND_MIXART is not set # CONFIG_SND_NM256 is not set @@ -1229,6 +1246,7 @@ CONFIG_HID_BELKIN=y CONFIG_HID_CHERRY=y CONFIG_HID_CHICONY=y CONFIG_HID_CYPRESS=y +CONFIG_HID_DRAGONRISE=y # CONFIG_DRAGONRISE_FF is not set CONFIG_HID_EZKEY=y CONFIG_HID_KYE=y @@ -1246,9 +1264,14 @@ CONFIG_HID_PETALYNX=y CONFIG_HID_SAMSUNG=y CONFIG_HID_SONY=y CONFIG_HID_SUNPLUS=y +CONFIG_HID_GREENASIA=y # CONFIG_GREENASIA_FF is not set +CONFIG_HID_SMARTJOYPLUS=y +# CONFIG_SMARTJOYPLUS_FF is not set CONFIG_HID_TOPSEED=y +CONFIG_HID_THRUSTMASTER=y # CONFIG_THRUSTMASTER_FF is not set +CONFIG_HID_ZEROPLUS=y # CONFIG_ZEROPLUS_FF is not set CONFIG_USB_SUPPORT=y CONFIG_USB_ARCH_HAS_HCD=y @@ -1462,6 +1485,7 @@ CONFIG_FILE_LOCKING=y # CONFIG_GFS2_FS is not set # CONFIG_OCFS2_FS is not set # CONFIG_BTRFS_FS is not set +CONFIG_FSNOTIFY=y CONFIG_DNOTIFY=y CONFIG_INOTIFY=y CONFIG_INOTIFY_USER=y @@ -1636,25 +1660,28 @@ CONFIG_SYSCTL_SYSCALL_CHECK=y # CONFIG_DEBUG_PAGEALLOC is not set CONFIG_NOP_TRACER=y CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y CONFIG_RING_BUFFER=y +CONFIG_EVENT_TRACING=y +CONFIG_CONTEXT_SWITCH_TRACER=y CONFIG_TRACING=y +CONFIG_GENERIC_TRACER=y CONFIG_TRACING_SUPPORT=y - -# -# Tracers -# +CONFIG_FTRACE=y # CONFIG_FUNCTION_TRACER is not set # CONFIG_IRQSOFF_TRACER is not set # CONFIG_SCHED_TRACER is not set -# CONFIG_CONTEXT_SWITCH_TRACER is not set -# CONFIG_EVENT_TRACER is not set # CONFIG_BOOT_TRACER is not set -# CONFIG_TRACE_BRANCH_PROFILING is not set +CONFIG_BRANCH_PROFILE_NONE=y +# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set +# CONFIG_PROFILE_ALL_BRANCHES is not set # CONFIG_STACK_TRACER is not set # CONFIG_KMEMTRACE is not set # CONFIG_WORKQUEUE_TRACER is not set CONFIG_BLK_DEV_IO_TRACE=y # CONFIG_FTRACE_STARTUP_TEST is not set +# CONFIG_RING_BUFFER_BENCHMARK is not set # CONFIG_DYNAMIC_DEBUG is not set # CONFIG_SAMPLES is not set CONFIG_HAVE_ARCH_KGDB=y diff --git a/arch/sparc/include/asm/atomic_32.h b/arch/sparc/include/asm/atomic_32.h index bb91b1248cd1..f0d343c3b956 100644 --- a/arch/sparc/include/asm/atomic_32.h +++ b/arch/sparc/include/asm/atomic_32.h @@ -161,5 +161,5 @@ static inline int __atomic24_sub(int i, atomic24_t *v) #endif /* !(__KERNEL__) */ -#include +#include #endif /* !(__ARCH_SPARC_ATOMIC__) */ diff --git a/arch/sparc/include/asm/atomic_64.h b/arch/sparc/include/asm/atomic_64.h index a0a706492696..f2e48009989e 100644 --- a/arch/sparc/include/asm/atomic_64.h +++ b/arch/sparc/include/asm/atomic_64.h @@ -114,5 +114,5 @@ static inline int atomic64_add_unless(atomic64_t *v, long a, long u) #define smp_mb__before_atomic_inc() barrier() #define smp_mb__after_atomic_inc() barrier() -#include +#include #endif /* !(__ARCH_SPARC64_ATOMIC__) */ diff --git a/arch/sparc/include/asm/bitsperlong.h b/arch/sparc/include/asm/bitsperlong.h new file mode 100644 index 000000000000..40dcaa3aaa56 --- /dev/null +++ b/arch/sparc/include/asm/bitsperlong.h @@ -0,0 +1,13 @@ +#ifndef __ASM_ALPHA_BITSPERLONG_H +#define __ASM_ALPHA_BITSPERLONG_H + +#if defined(__sparc__) && defined(__arch64__) +#define __BITS_PER_LONG 64 +#else +#define __BITS_PER_LONG 32 +#endif + +#include + +#endif /* __ASM_ALPHA_BITSPERLONG_H */ + diff --git a/arch/sparc/include/asm/cpudata_64.h b/arch/sparc/include/asm/cpudata_64.h index a11b89ee9ef8..926397d345ff 100644 --- a/arch/sparc/include/asm/cpudata_64.h +++ b/arch/sparc/include/asm/cpudata_64.h @@ -6,9 +6,6 @@ #ifndef _SPARC64_CPUDATA_H #define _SPARC64_CPUDATA_H -#include -#include - #ifndef __ASSEMBLY__ #include @@ -38,202 +35,10 @@ DECLARE_PER_CPU(cpuinfo_sparc, __cpu_data); #define cpu_data(__cpu) per_cpu(__cpu_data, (__cpu)) #define local_cpu_data() __get_cpu_var(__cpu_data) -/* Trap handling code needs to get at a few critical values upon - * trap entry and to process TSB misses. These cannot be in the - * per_cpu() area as we really need to lock them into the TLB and - * thus make them part of the main kernel image. As a result we - * try to make this as small as possible. - * - * This is padded out and aligned to 64-bytes to avoid false sharing - * on SMP. - */ - -/* If you modify the size of this structure, please update - * TRAP_BLOCK_SZ_SHIFT below. - */ -struct thread_info; -struct trap_per_cpu { -/* D-cache line 1: Basic thread information, cpu and device mondo queues */ - struct thread_info *thread; - unsigned long pgd_paddr; - unsigned long cpu_mondo_pa; - unsigned long dev_mondo_pa; - -/* D-cache line 2: Error Mondo Queue and kernel buffer pointers */ - unsigned long resum_mondo_pa; - unsigned long resum_kernel_buf_pa; - unsigned long nonresum_mondo_pa; - unsigned long nonresum_kernel_buf_pa; - -/* Dcache lines 3, 4, 5, and 6: Hypervisor Fault Status */ - struct hv_fault_status fault_info; - -/* Dcache line 7: Physical addresses of CPU send mondo block and CPU list. */ - unsigned long cpu_mondo_block_pa; - unsigned long cpu_list_pa; - unsigned long tsb_huge; - unsigned long tsb_huge_temp; - -/* Dcache line 8: IRQ work list, and keep trap_block a power-of-2 in size. */ - unsigned long irq_worklist_pa; - unsigned int cpu_mondo_qmask; - unsigned int dev_mondo_qmask; - unsigned int resum_qmask; - unsigned int nonresum_qmask; - void *hdesc; -} __attribute__((aligned(64))); -extern struct trap_per_cpu trap_block[NR_CPUS]; -extern void init_cur_cpu_trap(struct thread_info *); -extern void setup_tba(void); -extern int ncpus_probed; extern const struct seq_operations cpuinfo_op; -extern unsigned long real_hard_smp_processor_id(void); - -struct cpuid_patch_entry { - unsigned int addr; - unsigned int cheetah_safari[4]; - unsigned int cheetah_jbus[4]; - unsigned int starfire[4]; - unsigned int sun4v[4]; -}; -extern struct cpuid_patch_entry __cpuid_patch, __cpuid_patch_end; - -struct sun4v_1insn_patch_entry { - unsigned int addr; - unsigned int insn; -}; -extern struct sun4v_1insn_patch_entry __sun4v_1insn_patch, - __sun4v_1insn_patch_end; - -struct sun4v_2insn_patch_entry { - unsigned int addr; - unsigned int insns[2]; -}; -extern struct sun4v_2insn_patch_entry __sun4v_2insn_patch, - __sun4v_2insn_patch_end; - #endif /* !(__ASSEMBLY__) */ -#define TRAP_PER_CPU_THREAD 0x00 -#define TRAP_PER_CPU_PGD_PADDR 0x08 -#define TRAP_PER_CPU_CPU_MONDO_PA 0x10 -#define TRAP_PER_CPU_DEV_MONDO_PA 0x18 -#define TRAP_PER_CPU_RESUM_MONDO_PA 0x20 -#define TRAP_PER_CPU_RESUM_KBUF_PA 0x28 -#define TRAP_PER_CPU_NONRESUM_MONDO_PA 0x30 -#define TRAP_PER_CPU_NONRESUM_KBUF_PA 0x38 -#define TRAP_PER_CPU_FAULT_INFO 0x40 -#define TRAP_PER_CPU_CPU_MONDO_BLOCK_PA 0xc0 -#define TRAP_PER_CPU_CPU_LIST_PA 0xc8 -#define TRAP_PER_CPU_TSB_HUGE 0xd0 -#define TRAP_PER_CPU_TSB_HUGE_TEMP 0xd8 -#define TRAP_PER_CPU_IRQ_WORKLIST_PA 0xe0 -#define TRAP_PER_CPU_CPU_MONDO_QMASK 0xe8 -#define TRAP_PER_CPU_DEV_MONDO_QMASK 0xec -#define TRAP_PER_CPU_RESUM_QMASK 0xf0 -#define TRAP_PER_CPU_NONRESUM_QMASK 0xf4 - -#define TRAP_BLOCK_SZ_SHIFT 8 - -#include - -#define __GET_CPUID(REG) \ - /* Spitfire implementation (default). */ \ -661: ldxa [%g0] ASI_UPA_CONFIG, REG; \ - srlx REG, 17, REG; \ - and REG, 0x1f, REG; \ - nop; \ - .section .cpuid_patch, "ax"; \ - /* Instruction location. */ \ - .word 661b; \ - /* Cheetah Safari implementation. */ \ - ldxa [%g0] ASI_SAFARI_CONFIG, REG; \ - srlx REG, 17, REG; \ - and REG, 0x3ff, REG; \ - nop; \ - /* Cheetah JBUS implementation. */ \ - ldxa [%g0] ASI_JBUS_CONFIG, REG; \ - srlx REG, 17, REG; \ - and REG, 0x1f, REG; \ - nop; \ - /* Starfire implementation. */ \ - sethi %hi(0x1fff40000d0 >> 9), REG; \ - sllx REG, 9, REG; \ - or REG, 0xd0, REG; \ - lduwa [REG] ASI_PHYS_BYPASS_EC_E, REG;\ - /* sun4v implementation. */ \ - mov SCRATCHPAD_CPUID, REG; \ - ldxa [REG] ASI_SCRATCHPAD, REG; \ - nop; \ - nop; \ - .previous; - -#ifdef CONFIG_SMP - -#define TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \ - __GET_CPUID(TMP) \ - sethi %hi(trap_block), DEST; \ - sllx TMP, TRAP_BLOCK_SZ_SHIFT, TMP; \ - or DEST, %lo(trap_block), DEST; \ - add DEST, TMP, DEST; \ - -/* Clobbers TMP, current address space PGD phys address into DEST. */ -#define TRAP_LOAD_PGD_PHYS(DEST, TMP) \ - TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \ - ldx [DEST + TRAP_PER_CPU_PGD_PADDR], DEST; - -/* Clobbers TMP, loads local processor's IRQ work area into DEST. */ -#define TRAP_LOAD_IRQ_WORK_PA(DEST, TMP) \ - TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \ - add DEST, TRAP_PER_CPU_IRQ_WORKLIST_PA, DEST; - -/* Clobbers TMP, loads DEST with current thread info pointer. */ -#define TRAP_LOAD_THREAD_REG(DEST, TMP) \ - TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \ - ldx [DEST + TRAP_PER_CPU_THREAD], DEST; - -/* Given the current thread info pointer in THR, load the per-cpu - * area base of the current processor into DEST. REG1, REG2, and REG3 are - * clobbered. - * - * You absolutely cannot use DEST as a temporary in this code. The - * reason is that traps can happen during execution, and return from - * trap will load the fully resolved DEST per-cpu base. This can corrupt - * the calculations done by the macro mid-stream. - */ -#define LOAD_PER_CPU_BASE(DEST, THR, REG1, REG2, REG3) \ - lduh [THR + TI_CPU], REG1; \ - sethi %hi(__per_cpu_shift), REG3; \ - sethi %hi(__per_cpu_base), REG2; \ - ldx [REG3 + %lo(__per_cpu_shift)], REG3; \ - ldx [REG2 + %lo(__per_cpu_base)], REG2; \ - sllx REG1, REG3, REG3; \ - add REG3, REG2, DEST; - -#else - -#define TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \ - sethi %hi(trap_block), DEST; \ - or DEST, %lo(trap_block), DEST; \ - -/* Uniprocessor versions, we know the cpuid is zero. */ -#define TRAP_LOAD_PGD_PHYS(DEST, TMP) \ - TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \ - ldx [DEST + TRAP_PER_CPU_PGD_PADDR], DEST; - -/* Clobbers TMP, loads local processor's IRQ work area into DEST. */ -#define TRAP_LOAD_IRQ_WORK_PA(DEST, TMP) \ - TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \ - add DEST, TRAP_PER_CPU_IRQ_WORKLIST_PA, DEST; - -#define TRAP_LOAD_THREAD_REG(DEST, TMP) \ - TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \ - ldx [DEST + TRAP_PER_CPU_THREAD], DEST; - -/* No per-cpu areas on uniprocessor, so no need to load DEST. */ -#define LOAD_PER_CPU_BASE(DEST, THR, REG1, REG2, REG3) - -#endif /* !(CONFIG_SMP) */ +#include #endif /* _SPARC64_CPUDATA_H */ diff --git a/arch/sparc/include/asm/dma-mapping.h b/arch/sparc/include/asm/dma-mapping.h index 0f4150e26619..204e4bf64438 100644 --- a/arch/sparc/include/asm/dma-mapping.h +++ b/arch/sparc/include/asm/dma-mapping.h @@ -1,8 +1,166 @@ #ifndef ___ASM_SPARC_DMA_MAPPING_H #define ___ASM_SPARC_DMA_MAPPING_H -#if defined(__sparc__) && defined(__arch64__) -#include -#else -#include -#endif + +#include +#include + +#define DMA_ERROR_CODE (~(dma_addr_t)0x0) + +extern int dma_supported(struct device *dev, u64 mask); +extern int dma_set_mask(struct device *dev, u64 dma_mask); + +#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) +#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) +#define dma_is_consistent(d, h) (1) + +struct dma_ops { + void *(*alloc_coherent)(struct device *dev, size_t size, + dma_addr_t *dma_handle, gfp_t flag); + void (*free_coherent)(struct device *dev, size_t size, + void *cpu_addr, dma_addr_t dma_handle); + dma_addr_t (*map_page)(struct device *dev, struct page *page, + unsigned long offset, size_t size, + enum dma_data_direction direction); + void (*unmap_page)(struct device *dev, dma_addr_t dma_addr, + size_t size, + enum dma_data_direction direction); + int (*map_sg)(struct device *dev, struct scatterlist *sg, int nents, + enum dma_data_direction direction); + void (*unmap_sg)(struct device *dev, struct scatterlist *sg, + int nhwentries, + enum dma_data_direction direction); + void (*sync_single_for_cpu)(struct device *dev, + dma_addr_t dma_handle, size_t size, + enum dma_data_direction direction); + void (*sync_single_for_device)(struct device *dev, + dma_addr_t dma_handle, size_t size, + enum dma_data_direction direction); + void (*sync_sg_for_cpu)(struct device *dev, struct scatterlist *sg, + int nelems, + enum dma_data_direction direction); + void (*sync_sg_for_device)(struct device *dev, + struct scatterlist *sg, int nents, + enum dma_data_direction dir); +}; +extern const struct dma_ops *dma_ops; + +static inline void *dma_alloc_coherent(struct device *dev, size_t size, + dma_addr_t *dma_handle, gfp_t flag) +{ + return dma_ops->alloc_coherent(dev, size, dma_handle, flag); +} + +static inline void dma_free_coherent(struct device *dev, size_t size, + void *cpu_addr, dma_addr_t dma_handle) +{ + dma_ops->free_coherent(dev, size, cpu_addr, dma_handle); +} + +static inline dma_addr_t dma_map_single(struct device *dev, void *cpu_addr, + size_t size, + enum dma_data_direction direction) +{ + return dma_ops->map_page(dev, virt_to_page(cpu_addr), + (unsigned long)cpu_addr & ~PAGE_MASK, size, + direction); +} + +static inline void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, + size_t size, + enum dma_data_direction direction) +{ + dma_ops->unmap_page(dev, dma_addr, size, direction); +} + +static inline dma_addr_t dma_map_page(struct device *dev, struct page *page, + unsigned long offset, size_t size, + enum dma_data_direction direction) +{ + return dma_ops->map_page(dev, page, offset, size, direction); +} + +static inline void dma_unmap_page(struct device *dev, dma_addr_t dma_address, + size_t size, + enum dma_data_direction direction) +{ + dma_ops->unmap_page(dev, dma_address, size, direction); +} + +static inline int dma_map_sg(struct device *dev, struct scatterlist *sg, + int nents, enum dma_data_direction direction) +{ + return dma_ops->map_sg(dev, sg, nents, direction); +} + +static inline void dma_unmap_sg(struct device *dev, struct scatterlist *sg, + int nents, enum dma_data_direction direction) +{ + dma_ops->unmap_sg(dev, sg, nents, direction); +} + +static inline void dma_sync_single_for_cpu(struct device *dev, + dma_addr_t dma_handle, size_t size, + enum dma_data_direction direction) +{ + dma_ops->sync_single_for_cpu(dev, dma_handle, size, direction); +} + +static inline void dma_sync_single_for_device(struct device *dev, + dma_addr_t dma_handle, + size_t size, + enum dma_data_direction direction) +{ + if (dma_ops->sync_single_for_device) + dma_ops->sync_single_for_device(dev, dma_handle, size, + direction); +} + +static inline void dma_sync_sg_for_cpu(struct device *dev, + struct scatterlist *sg, int nelems, + enum dma_data_direction direction) +{ + dma_ops->sync_sg_for_cpu(dev, sg, nelems, direction); +} + +static inline void dma_sync_sg_for_device(struct device *dev, + struct scatterlist *sg, int nelems, + enum dma_data_direction direction) +{ + if (dma_ops->sync_sg_for_device) + dma_ops->sync_sg_for_device(dev, sg, nelems, direction); +} + +static inline void dma_sync_single_range_for_cpu(struct device *dev, + dma_addr_t dma_handle, + unsigned long offset, + size_t size, + enum dma_data_direction dir) +{ + dma_sync_single_for_cpu(dev, dma_handle+offset, size, dir); +} + +static inline void dma_sync_single_range_for_device(struct device *dev, + dma_addr_t dma_handle, + unsigned long offset, + size_t size, + enum dma_data_direction dir) +{ + dma_sync_single_for_device(dev, dma_handle+offset, size, dir); +} + + +static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) +{ + return (dma_addr == DMA_ERROR_CODE); +} + +static inline int dma_get_cache_alignment(void) +{ + /* + * no easy way to get cache size on all processors, so return + * the maximum possible, to be safe + */ + return (1 << INTERNODE_CACHE_SHIFT); +} + #endif diff --git a/arch/sparc/include/asm/dma-mapping_32.h b/arch/sparc/include/asm/dma-mapping_32.h deleted file mode 100644 index 8a57ea0573e6..000000000000 --- a/arch/sparc/include/asm/dma-mapping_32.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef _ASM_SPARC_DMA_MAPPING_H -#define _ASM_SPARC_DMA_MAPPING_H - -#include - -struct device; -struct scatterlist; -struct page; - -#define DMA_ERROR_CODE (~(dma_addr_t)0x0) - -extern int dma_supported(struct device *dev, u64 mask); -extern int dma_set_mask(struct device *dev, u64 dma_mask); -extern void *dma_alloc_coherent(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t flag); -extern void dma_free_coherent(struct device *dev, size_t size, - void *cpu_addr, dma_addr_t dma_handle); -extern dma_addr_t dma_map_single(struct device *dev, void *cpu_addr, - size_t size, - enum dma_data_direction direction); -extern void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, - size_t size, - enum dma_data_direction direction); -extern dma_addr_t dma_map_page(struct device *dev, struct page *page, - unsigned long offset, size_t size, - enum dma_data_direction direction); -extern void dma_unmap_page(struct device *dev, dma_addr_t dma_address, - size_t size, enum dma_data_direction direction); -extern int dma_map_sg(struct device *dev, struct scatterlist *sg, - int nents, enum dma_data_direction direction); -extern void dma_unmap_sg(struct device *dev, struct scatterlist *sg, - int nents, enum dma_data_direction direction); -extern void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, - size_t size, - enum dma_data_direction direction); -extern void dma_sync_single_for_device(struct device *dev, - dma_addr_t dma_handle, - size_t size, - enum dma_data_direction direction); -extern void dma_sync_single_range_for_cpu(struct device *dev, - dma_addr_t dma_handle, - unsigned long offset, - size_t size, - enum dma_data_direction direction); -extern void dma_sync_single_range_for_device(struct device *dev, - dma_addr_t dma_handle, - unsigned long offset, size_t size, - enum dma_data_direction direction); -extern void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, - int nelems, enum dma_data_direction direction); -extern void dma_sync_sg_for_device(struct device *dev, - struct scatterlist *sg, int nelems, - enum dma_data_direction direction); -extern int dma_mapping_error(struct device *dev, dma_addr_t dma_addr); -extern int dma_get_cache_alignment(void); - -#define dma_alloc_noncoherent dma_alloc_coherent -#define dma_free_noncoherent dma_free_coherent - -#endif /* _ASM_SPARC_DMA_MAPPING_H */ diff --git a/arch/sparc/include/asm/dma-mapping_64.h b/arch/sparc/include/asm/dma-mapping_64.h deleted file mode 100644 index bfa64f9702d5..000000000000 --- a/arch/sparc/include/asm/dma-mapping_64.h +++ /dev/null @@ -1,154 +0,0 @@ -#ifndef _ASM_SPARC64_DMA_MAPPING_H -#define _ASM_SPARC64_DMA_MAPPING_H - -#include -#include - -#define DMA_ERROR_CODE (~(dma_addr_t)0x0) - -struct dma_ops { - void *(*alloc_coherent)(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t flag); - void (*free_coherent)(struct device *dev, size_t size, - void *cpu_addr, dma_addr_t dma_handle); - dma_addr_t (*map_single)(struct device *dev, void *cpu_addr, - size_t size, - enum dma_data_direction direction); - void (*unmap_single)(struct device *dev, dma_addr_t dma_addr, - size_t size, - enum dma_data_direction direction); - int (*map_sg)(struct device *dev, struct scatterlist *sg, int nents, - enum dma_data_direction direction); - void (*unmap_sg)(struct device *dev, struct scatterlist *sg, - int nhwentries, - enum dma_data_direction direction); - void (*sync_single_for_cpu)(struct device *dev, - dma_addr_t dma_handle, size_t size, - enum dma_data_direction direction); - void (*sync_sg_for_cpu)(struct device *dev, struct scatterlist *sg, - int nelems, - enum dma_data_direction direction); -}; -extern const struct dma_ops *dma_ops; - -extern int dma_supported(struct device *dev, u64 mask); -extern int dma_set_mask(struct device *dev, u64 dma_mask); - -static inline void *dma_alloc_coherent(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t flag) -{ - return dma_ops->alloc_coherent(dev, size, dma_handle, flag); -} - -static inline void dma_free_coherent(struct device *dev, size_t size, - void *cpu_addr, dma_addr_t dma_handle) -{ - dma_ops->free_coherent(dev, size, cpu_addr, dma_handle); -} - -static inline dma_addr_t dma_map_single(struct device *dev, void *cpu_addr, - size_t size, - enum dma_data_direction direction) -{ - return dma_ops->map_single(dev, cpu_addr, size, direction); -} - -static inline void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, - size_t size, - enum dma_data_direction direction) -{ - dma_ops->unmap_single(dev, dma_addr, size, direction); -} - -static inline dma_addr_t dma_map_page(struct device *dev, struct page *page, - unsigned long offset, size_t size, - enum dma_data_direction direction) -{ - return dma_ops->map_single(dev, page_address(page) + offset, - size, direction); -} - -static inline void dma_unmap_page(struct device *dev, dma_addr_t dma_address, - size_t size, - enum dma_data_direction direction) -{ - dma_ops->unmap_single(dev, dma_address, size, direction); -} - -static inline int dma_map_sg(struct device *dev, struct scatterlist *sg, - int nents, enum dma_data_direction direction) -{ - return dma_ops->map_sg(dev, sg, nents, direction); -} - -static inline void dma_unmap_sg(struct device *dev, struct scatterlist *sg, - int nents, enum dma_data_direction direction) -{ - dma_ops->unmap_sg(dev, sg, nents, direction); -} - -static inline void dma_sync_single_for_cpu(struct device *dev, - dma_addr_t dma_handle, size_t size, - enum dma_data_direction direction) -{ - dma_ops->sync_single_for_cpu(dev, dma_handle, size, direction); -} - -static inline void dma_sync_single_for_device(struct device *dev, - dma_addr_t dma_handle, - size_t size, - enum dma_data_direction direction) -{ - /* No flushing needed to sync cpu writes to the device. */ -} - -static inline void dma_sync_single_range_for_cpu(struct device *dev, - dma_addr_t dma_handle, - unsigned long offset, - size_t size, - enum dma_data_direction direction) -{ - dma_sync_single_for_cpu(dev, dma_handle+offset, size, direction); -} - -static inline void dma_sync_single_range_for_device(struct device *dev, - dma_addr_t dma_handle, - unsigned long offset, - size_t size, - enum dma_data_direction direction) -{ - /* No flushing needed to sync cpu writes to the device. */ -} - - -static inline void dma_sync_sg_for_cpu(struct device *dev, - struct scatterlist *sg, int nelems, - enum dma_data_direction direction) -{ - dma_ops->sync_sg_for_cpu(dev, sg, nelems, direction); -} - -static inline void dma_sync_sg_for_device(struct device *dev, - struct scatterlist *sg, int nelems, - enum dma_data_direction direction) -{ - /* No flushing needed to sync cpu writes to the device. */ -} - -static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) -{ - return (dma_addr == DMA_ERROR_CODE); -} - -static inline int dma_get_cache_alignment(void) -{ - /* no easy way to get cache size on all processors, so return - * the maximum possible, to be safe */ - return (1 << INTERNODE_CACHE_SHIFT); -} - -#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) -#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) -#define dma_is_consistent(d, h) (1) - -#endif /* _ASM_SPARC64_DMA_MAPPING_H */ diff --git a/arch/sparc/include/asm/errno.h b/arch/sparc/include/asm/errno.h index a9ef172977de..4e2bc490d714 100644 --- a/arch/sparc/include/asm/errno.h +++ b/arch/sparc/include/asm/errno.h @@ -110,4 +110,6 @@ #define EOWNERDEAD 132 /* Owner died */ #define ENOTRECOVERABLE 133 /* State not recoverable */ +#define ERFKILL 134 /* Operation not possible due to RF-kill */ + #endif diff --git a/arch/sparc/include/asm/ftrace.h b/arch/sparc/include/asm/ftrace.h index d27716cd38c1..b0f18e9893db 100644 --- a/arch/sparc/include/asm/ftrace.h +++ b/arch/sparc/include/asm/ftrace.h @@ -11,4 +11,15 @@ extern void _mcount(void); #endif +#ifdef CONFIG_DYNAMIC_FTRACE +/* reloction of mcount call site is the same as the address */ +static inline unsigned long ftrace_call_adjust(unsigned long addr) +{ + return addr; +} + +struct dyn_arch_ftrace { +}; +#endif /* CONFIG_DYNAMIC_FTRACE */ + #endif /* _ASM_SPARC64_FTRACE */ diff --git a/arch/sparc/include/asm/kmap_types.h b/arch/sparc/include/asm/kmap_types.h index 602f5e034f7a..aad21745fbb9 100644 --- a/arch/sparc/include/asm/kmap_types.h +++ b/arch/sparc/include/asm/kmap_types.h @@ -5,21 +5,6 @@ * is actually used on sparc. -DaveM */ -enum km_type { - KM_BOUNCE_READ, - KM_SKB_SUNRPC_DATA, - KM_SKB_DATA_SOFTIRQ, - KM_USER0, - KM_USER1, - KM_BIO_SRC_IRQ, - KM_BIO_DST_IRQ, - KM_PTE0, - KM_PTE1, - KM_IRQ0, - KM_IRQ1, - KM_SOFTIRQ0, - KM_SOFTIRQ1, - KM_TYPE_NR -}; +#include #endif diff --git a/arch/sparc/include/asm/mdesc.h b/arch/sparc/include/asm/mdesc.h index 1acc7272e537..9faa046713fb 100644 --- a/arch/sparc/include/asm/mdesc.h +++ b/arch/sparc/include/asm/mdesc.h @@ -71,7 +71,8 @@ struct mdesc_notifier_client { extern void mdesc_register_notifier(struct mdesc_notifier_client *client); -extern void mdesc_fill_in_cpu_data(cpumask_t mask); +extern void mdesc_fill_in_cpu_data(cpumask_t *mask); +extern void mdesc_populate_present_mask(cpumask_t *mask); extern void sun4v_mdesc_init(void); diff --git a/arch/sparc/include/asm/mman.h b/arch/sparc/include/asm/mman.h index fdfbbf0a4736..988192e8e956 100644 --- a/arch/sparc/include/asm/mman.h +++ b/arch/sparc/include/asm/mman.h @@ -1,7 +1,7 @@ #ifndef __SPARC_MMAN_H__ #define __SPARC_MMAN_H__ -#include +#include /* SunOS'ified... */ diff --git a/arch/sparc/include/asm/page_32.h b/arch/sparc/include/asm/page_32.h index d1806edc0958..f72080bdda94 100644 --- a/arch/sparc/include/asm/page_32.h +++ b/arch/sparc/include/asm/page_32.h @@ -152,6 +152,6 @@ extern unsigned long pfn_base; VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) #include -#include +#include #endif /* _SPARC_PAGE_H */ diff --git a/arch/sparc/include/asm/page_64.h b/arch/sparc/include/asm/page_64.h index 4274ed13ddb2..f0d09b401036 100644 --- a/arch/sparc/include/asm/page_64.h +++ b/arch/sparc/include/asm/page_64.h @@ -132,6 +132,6 @@ typedef struct page *pgtable_t; #define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \ VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) -#include +#include #endif /* _SPARC64_PAGE_H */ diff --git a/arch/sparc/include/asm/pci_64.h b/arch/sparc/include/asm/pci_64.h index 4f79a54948f6..7a1e3566e59c 100644 --- a/arch/sparc/include/asm/pci_64.h +++ b/arch/sparc/include/asm/pci_64.h @@ -191,8 +191,6 @@ extern void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res, struct pci_bus_region *region); -extern struct resource *pcibios_select_root(struct pci_dev *, struct resource *); - static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel) { return PCI_IRQ_NONE; diff --git a/arch/sparc/include/asm/percpu_64.h b/arch/sparc/include/asm/percpu_64.h index bee64593023e..007aafb4ae97 100644 --- a/arch/sparc/include/asm/percpu_64.h +++ b/arch/sparc/include/asm/percpu_64.h @@ -7,20 +7,16 @@ register unsigned long __local_per_cpu_offset asm("g5"); #ifdef CONFIG_SMP -extern void real_setup_per_cpu_areas(void); +#include -extern unsigned long __per_cpu_base; -extern unsigned long __per_cpu_shift; #define __per_cpu_offset(__cpu) \ - (__per_cpu_base + ((unsigned long)(__cpu) << __per_cpu_shift)) + (trap_block[(__cpu)].__per_cpu_base) #define per_cpu_offset(x) (__per_cpu_offset(x)) #define __my_cpu_offset __local_per_cpu_offset #else /* ! SMP */ -#define real_setup_per_cpu_areas() do { } while (0) - #endif /* SMP */ #include diff --git a/arch/sparc/include/asm/prom.h b/arch/sparc/include/asm/prom.h index 900d44714f8d..be8d7aaeb60d 100644 --- a/arch/sparc/include/asm/prom.h +++ b/arch/sparc/include/asm/prom.h @@ -86,6 +86,8 @@ extern int of_node_to_nid(struct device_node *dp); #endif extern void prom_build_devicetree(void); +extern void of_populate_present_mask(void); +extern void of_fill_in_cpu_data(void); /* Dummy ref counting routines - to be implemented later */ static inline struct device_node *of_node_get(struct device_node *node) diff --git a/arch/sparc/include/asm/signal.h b/arch/sparc/include/asm/signal.h index cba45206b7f2..e49b828a2471 100644 --- a/arch/sparc/include/asm/signal.h +++ b/arch/sparc/include/asm/signal.h @@ -176,7 +176,7 @@ struct sigstack { #define SA_STATIC_ALLOC 0x8000 #endif -#include +#include struct __new_sigaction { __sighandler_t sa_handler; diff --git a/arch/sparc/include/asm/thread_info_64.h b/arch/sparc/include/asm/thread_info_64.h index 639ac805448a..65865726b283 100644 --- a/arch/sparc/include/asm/thread_info_64.h +++ b/arch/sparc/include/asm/thread_info_64.h @@ -102,8 +102,8 @@ struct thread_info { #define TI_KERN_CNTD1 0x00000488 #define TI_PCR 0x00000490 #define TI_RESTART_BLOCK 0x00000498 -#define TI_KUNA_REGS 0x000004c0 -#define TI_KUNA_INSN 0x000004c8 +#define TI_KUNA_REGS 0x000004c8 +#define TI_KUNA_INSN 0x000004d0 #define TI_FPREGS 0x00000500 /* We embed this in the uppermost byte of thread_info->flags */ diff --git a/arch/sparc/include/asm/trap_block.h b/arch/sparc/include/asm/trap_block.h new file mode 100644 index 000000000000..7e26b2db6211 --- /dev/null +++ b/arch/sparc/include/asm/trap_block.h @@ -0,0 +1,207 @@ +#ifndef _SPARC_TRAP_BLOCK_H +#define _SPARC_TRAP_BLOCK_H + +#include +#include + +#ifndef __ASSEMBLY__ + +/* Trap handling code needs to get at a few critical values upon + * trap entry and to process TSB misses. These cannot be in the + * per_cpu() area as we really need to lock them into the TLB and + * thus make them part of the main kernel image. As a result we + * try to make this as small as possible. + * + * This is padded out and aligned to 64-bytes to avoid false sharing + * on SMP. + */ + +/* If you modify the size of this structure, please update + * TRAP_BLOCK_SZ_SHIFT below. + */ +struct thread_info; +struct trap_per_cpu { +/* D-cache line 1: Basic thread information, cpu and device mondo queues */ + struct thread_info *thread; + unsigned long pgd_paddr; + unsigned long cpu_mondo_pa; + unsigned long dev_mondo_pa; + +/* D-cache line 2: Error Mondo Queue and kernel buffer pointers */ + unsigned long resum_mondo_pa; + unsigned long resum_kernel_buf_pa; + unsigned long nonresum_mondo_pa; + unsigned long nonresum_kernel_buf_pa; + +/* Dcache lines 3, 4, 5, and 6: Hypervisor Fault Status */ + struct hv_fault_status fault_info; + +/* Dcache line 7: Physical addresses of CPU send mondo block and CPU list. */ + unsigned long cpu_mondo_block_pa; + unsigned long cpu_list_pa; + unsigned long tsb_huge; + unsigned long tsb_huge_temp; + +/* Dcache line 8: IRQ work list, and keep trap_block a power-of-2 in size. */ + unsigned long irq_worklist_pa; + unsigned int cpu_mondo_qmask; + unsigned int dev_mondo_qmask; + unsigned int resum_qmask; + unsigned int nonresum_qmask; + unsigned long __per_cpu_base; +} __attribute__((aligned(64))); +extern struct trap_per_cpu trap_block[NR_CPUS]; +extern void init_cur_cpu_trap(struct thread_info *); +extern void setup_tba(void); +extern int ncpus_probed; + +extern unsigned long real_hard_smp_processor_id(void); + +struct cpuid_patch_entry { + unsigned int addr; + unsigned int cheetah_safari[4]; + unsigned int cheetah_jbus[4]; + unsigned int starfire[4]; + unsigned int sun4v[4]; +}; +extern struct cpuid_patch_entry __cpuid_patch, __cpuid_patch_end; + +struct sun4v_1insn_patch_entry { + unsigned int addr; + unsigned int insn; +}; +extern struct sun4v_1insn_patch_entry __sun4v_1insn_patch, + __sun4v_1insn_patch_end; + +struct sun4v_2insn_patch_entry { + unsigned int addr; + unsigned int insns[2]; +}; +extern struct sun4v_2insn_patch_entry __sun4v_2insn_patch, + __sun4v_2insn_patch_end; + + +#endif /* !(__ASSEMBLY__) */ + +#define TRAP_PER_CPU_THREAD 0x00 +#define TRAP_PER_CPU_PGD_PADDR 0x08 +#define TRAP_PER_CPU_CPU_MONDO_PA 0x10 +#define TRAP_PER_CPU_DEV_MONDO_PA 0x18 +#define TRAP_PER_CPU_RESUM_MONDO_PA 0x20 +#define TRAP_PER_CPU_RESUM_KBUF_PA 0x28 +#define TRAP_PER_CPU_NONRESUM_MONDO_PA 0x30 +#define TRAP_PER_CPU_NONRESUM_KBUF_PA 0x38 +#define TRAP_PER_CPU_FAULT_INFO 0x40 +#define TRAP_PER_CPU_CPU_MONDO_BLOCK_PA 0xc0 +#define TRAP_PER_CPU_CPU_LIST_PA 0xc8 +#define TRAP_PER_CPU_TSB_HUGE 0xd0 +#define TRAP_PER_CPU_TSB_HUGE_TEMP 0xd8 +#define TRAP_PER_CPU_IRQ_WORKLIST_PA 0xe0 +#define TRAP_PER_CPU_CPU_MONDO_QMASK 0xe8 +#define TRAP_PER_CPU_DEV_MONDO_QMASK 0xec +#define TRAP_PER_CPU_RESUM_QMASK 0xf0 +#define TRAP_PER_CPU_NONRESUM_QMASK 0xf4 +#define TRAP_PER_CPU_PER_CPU_BASE 0xf8 + +#define TRAP_BLOCK_SZ_SHIFT 8 + +#include + +#define __GET_CPUID(REG) \ + /* Spitfire implementation (default). */ \ +661: ldxa [%g0] ASI_UPA_CONFIG, REG; \ + srlx REG, 17, REG; \ + and REG, 0x1f, REG; \ + nop; \ + .section .cpuid_patch, "ax"; \ + /* Instruction location. */ \ + .word 661b; \ + /* Cheetah Safari implementation. */ \ + ldxa [%g0] ASI_SAFARI_CONFIG, REG; \ + srlx REG, 17, REG; \ + and REG, 0x3ff, REG; \ + nop; \ + /* Cheetah JBUS implementation. */ \ + ldxa [%g0] ASI_JBUS_CONFIG, REG; \ + srlx REG, 17, REG; \ + and REG, 0x1f, REG; \ + nop; \ + /* Starfire implementation. */ \ + sethi %hi(0x1fff40000d0 >> 9), REG; \ + sllx REG, 9, REG; \ + or REG, 0xd0, REG; \ + lduwa [REG] ASI_PHYS_BYPASS_EC_E, REG;\ + /* sun4v implementation. */ \ + mov SCRATCHPAD_CPUID, REG; \ + ldxa [REG] ASI_SCRATCHPAD, REG; \ + nop; \ + nop; \ + .previous; + +#ifdef CONFIG_SMP + +#define TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \ + __GET_CPUID(TMP) \ + sethi %hi(trap_block), DEST; \ + sllx TMP, TRAP_BLOCK_SZ_SHIFT, TMP; \ + or DEST, %lo(trap_block), DEST; \ + add DEST, TMP, DEST; \ + +/* Clobbers TMP, current address space PGD phys address into DEST. */ +#define TRAP_LOAD_PGD_PHYS(DEST, TMP) \ + TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \ + ldx [DEST + TRAP_PER_CPU_PGD_PADDR], DEST; + +/* Clobbers TMP, loads local processor's IRQ work area into DEST. */ +#define TRAP_LOAD_IRQ_WORK_PA(DEST, TMP) \ + TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \ + add DEST, TRAP_PER_CPU_IRQ_WORKLIST_PA, DEST; + +/* Clobbers TMP, loads DEST with current thread info pointer. */ +#define TRAP_LOAD_THREAD_REG(DEST, TMP) \ + TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \ + ldx [DEST + TRAP_PER_CPU_THREAD], DEST; + +/* Given the current thread info pointer in THR, load the per-cpu + * area base of the current processor into DEST. REG1, REG2, and REG3 are + * clobbered. + * + * You absolutely cannot use DEST as a temporary in this code. The + * reason is that traps can happen during execution, and return from + * trap will load the fully resolved DEST per-cpu base. This can corrupt + * the calculations done by the macro mid-stream. + */ +#define LOAD_PER_CPU_BASE(DEST, THR, REG1, REG2, REG3) \ + lduh [THR + TI_CPU], REG1; \ + sethi %hi(trap_block), REG2; \ + sllx REG1, TRAP_BLOCK_SZ_SHIFT, REG1; \ + or REG2, %lo(trap_block), REG2; \ + add REG2, REG1, REG2; \ + ldx [REG2 + TRAP_PER_CPU_PER_CPU_BASE], DEST; + +#else + +#define TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \ + sethi %hi(trap_block), DEST; \ + or DEST, %lo(trap_block), DEST; \ + +/* Uniprocessor versions, we know the cpuid is zero. */ +#define TRAP_LOAD_PGD_PHYS(DEST, TMP) \ + TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \ + ldx [DEST + TRAP_PER_CPU_PGD_PADDR], DEST; + +/* Clobbers TMP, loads local processor's IRQ work area into DEST. */ +#define TRAP_LOAD_IRQ_WORK_PA(DEST, TMP) \ + TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \ + add DEST, TRAP_PER_CPU_IRQ_WORKLIST_PA, DEST; + +#define TRAP_LOAD_THREAD_REG(DEST, TMP) \ + TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \ + ldx [DEST + TRAP_PER_CPU_THREAD], DEST; + +/* No per-cpu areas on uniprocessor, so no need to load DEST. */ +#define LOAD_PER_CPU_BASE(DEST, THR, REG1, REG2, REG3) + +#endif /* !(CONFIG_SMP) */ + +#endif /* _SPARC_TRAP_BLOCK_H */ diff --git a/arch/sparc/include/asm/types.h b/arch/sparc/include/asm/types.h index 2237118825d0..de671d73baed 100644 --- a/arch/sparc/include/asm/types.h +++ b/arch/sparc/include/asm/types.h @@ -21,8 +21,6 @@ typedef unsigned short umode_t; #ifdef __KERNEL__ -#define BITS_PER_LONG 64 - #ifndef __ASSEMBLY__ /* Dma addresses come in generic and 64-bit flavours. */ @@ -46,8 +44,6 @@ typedef unsigned short umode_t; #ifdef __KERNEL__ -#define BITS_PER_LONG 32 - #ifndef __ASSEMBLY__ typedef u32 dma_addr_t; diff --git a/arch/sparc/include/asm/uaccess_32.h b/arch/sparc/include/asm/uaccess_32.h index 47d5619d43fa..8303ac481034 100644 --- a/arch/sparc/include/asm/uaccess_32.h +++ b/arch/sparc/include/asm/uaccess_32.h @@ -17,6 +17,9 @@ #ifndef __ASSEMBLY__ +#define ARCH_HAS_SORT_EXTABLE +#define ARCH_HAS_SEARCH_EXTABLE + /* Sparc is not segmented, however we need to be able to fool access_ok() * when doing system calls from kernel mode legitimately. * diff --git a/arch/sparc/include/asm/uaccess_64.h b/arch/sparc/include/asm/uaccess_64.h index c64e767a3e4b..a38c03238918 100644 --- a/arch/sparc/include/asm/uaccess_64.h +++ b/arch/sparc/include/asm/uaccess_64.h @@ -12,7 +12,7 @@ #include #include #include -#include +#include #endif #ifndef __ASSEMBLY__ diff --git a/arch/sparc/include/asm/unistd.h b/arch/sparc/include/asm/unistd.h index b8eb71ef3163..b2c406de7d4f 100644 --- a/arch/sparc/include/asm/unistd.h +++ b/arch/sparc/include/asm/unistd.h @@ -394,8 +394,9 @@ #define __NR_accept4 323 #define __NR_preadv 324 #define __NR_pwritev 325 +#define __NR_rt_tgsigqueueinfo 326 -#define NR_SYSCALLS 326 +#define NR_SYSCALLS 327 #ifdef __32bit_syscall_numbers__ /* Sparc 32-bit only has the "setresuid32", "getresuid32" variants, diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile index 54742e58831c..475ce4696acd 100644 --- a/arch/sparc/kernel/Makefile +++ b/arch/sparc/kernel/Makefile @@ -37,6 +37,7 @@ obj-y += una_asm_$(BITS).o obj-$(CONFIG_SPARC32) += muldiv.o obj-y += prom_common.o obj-y += prom_$(BITS).o +obj-y += of_device_common.o obj-y += of_device_$(BITS).o obj-$(CONFIG_SPARC64) += prom_irqtrans.o @@ -54,6 +55,7 @@ obj-$(CONFIG_SPARC64) += sstate.o obj-$(CONFIG_SPARC64) += mdesc.o obj-$(CONFIG_SPARC64) += pcr.o obj-$(CONFIG_SPARC64) += nmi.o +obj-$(CONFIG_SPARC64_SMP) += cpumap.o # sparc32 do not use GENERIC_HARDIRQS but uses the generic devres implementation obj-$(CONFIG_SPARC32) += devres.o diff --git a/arch/sparc/kernel/cpumap.c b/arch/sparc/kernel/cpumap.c new file mode 100644 index 000000000000..7430ed080b23 --- /dev/null +++ b/arch/sparc/kernel/cpumap.c @@ -0,0 +1,431 @@ +/* cpumap.c: used for optimizing CPU assignment + * + * Copyright (C) 2009 Hong H. Pham + */ + +#include +#include +#include +#include +#include +#include +#include "cpumap.h" + + +enum { + CPUINFO_LVL_ROOT = 0, + CPUINFO_LVL_NODE, + CPUINFO_LVL_CORE, + CPUINFO_LVL_PROC, + CPUINFO_LVL_MAX, +}; + +enum { + ROVER_NO_OP = 0, + /* Increment rover every time level is visited */ + ROVER_INC_ON_VISIT = 1 << 0, + /* Increment parent's rover every time rover wraps around */ + ROVER_INC_PARENT_ON_LOOP = 1 << 1, +}; + +struct cpuinfo_node { + int id; + int level; + int num_cpus; /* Number of CPUs in this hierarchy */ + int parent_index; + int child_start; /* Array index of the first child node */ + int child_end; /* Array index of the last child node */ + int rover; /* Child node iterator */ +}; + +struct cpuinfo_level { + int start_index; /* Index of first node of a level in a cpuinfo tree */ + int end_index; /* Index of last node of a level in a cpuinfo tree */ + int num_nodes; /* Number of nodes in a level in a cpuinfo tree */ +}; + +struct cpuinfo_tree { + int total_nodes; + + /* Offsets into nodes[] for each level of the tree */ + struct cpuinfo_level level[CPUINFO_LVL_MAX]; + struct cpuinfo_node nodes[0]; +}; + + +static struct cpuinfo_tree *cpuinfo_tree; + +static u16 cpu_distribution_map[NR_CPUS]; +static DEFINE_SPINLOCK(cpu_map_lock); + + +/* Niagara optimized cpuinfo tree traversal. */ +static const int niagara_iterate_method[] = { + [CPUINFO_LVL_ROOT] = ROVER_NO_OP, + + /* Strands (or virtual CPUs) within a core may not run concurrently + * on the Niagara, as instruction pipeline(s) are shared. Distribute + * work to strands in different cores first for better concurrency. + * Go to next NUMA node when all cores are used. + */ + [CPUINFO_LVL_NODE] = ROVER_INC_ON_VISIT|ROVER_INC_PARENT_ON_LOOP, + + /* Strands are grouped together by proc_id in cpuinfo_sparc, i.e. + * a proc_id represents an instruction pipeline. Distribute work to + * strands in different proc_id groups if the core has multiple + * instruction pipelines (e.g. the Niagara 2/2+ has two). + */ + [CPUINFO_LVL_CORE] = ROVER_INC_ON_VISIT, + + /* Pick the next strand in the proc_id group. */ + [CPUINFO_LVL_PROC] = ROVER_INC_ON_VISIT, +}; + +/* Generic cpuinfo tree traversal. Distribute work round robin across NUMA + * nodes. + */ +static const int generic_iterate_method[] = { + [CPUINFO_LVL_ROOT] = ROVER_INC_ON_VISIT, + [CPUINFO_LVL_NODE] = ROVER_NO_OP, + [CPUINFO_LVL_CORE] = ROVER_INC_PARENT_ON_LOOP, + [CPUINFO_LVL_PROC] = ROVER_INC_ON_VISIT|ROVER_INC_PARENT_ON_LOOP, +}; + + +static int cpuinfo_id(int cpu, int level) +{ + int id; + + switch (level) { + case CPUINFO_LVL_ROOT: + id = 0; + break; + case CPUINFO_LVL_NODE: + id = cpu_to_node(cpu); + break; + case CPUINFO_LVL_CORE: + id = cpu_data(cpu).core_id; + break; + case CPUINFO_LVL_PROC: + id = cpu_data(cpu).proc_id; + break; + default: + id = -EINVAL; + } + return id; +} + +/* + * Enumerate the CPU information in __cpu_data to determine the start index, + * end index, and number of nodes for each level in the cpuinfo tree. The + * total number of cpuinfo nodes required to build the tree is returned. + */ +static int enumerate_cpuinfo_nodes(struct cpuinfo_level *tree_level) +{ + int prev_id[CPUINFO_LVL_MAX]; + int i, n, num_nodes; + + for (i = CPUINFO_LVL_ROOT; i < CPUINFO_LVL_MAX; i++) { + struct cpuinfo_level *lv = &tree_level[i]; + + prev_id[i] = -1; + lv->start_index = lv->end_index = lv->num_nodes = 0; + } + + num_nodes = 1; /* Include the root node */ + + for (i = 0; i < num_possible_cpus(); i++) { + if (!cpu_online(i)) + continue; + + n = cpuinfo_id(i, CPUINFO_LVL_NODE); + if (n > prev_id[CPUINFO_LVL_NODE]) { + tree_level[CPUINFO_LVL_NODE].num_nodes++; + prev_id[CPUINFO_LVL_NODE] = n; + num_nodes++; + } + n = cpuinfo_id(i, CPUINFO_LVL_CORE); + if (n > prev_id[CPUINFO_LVL_CORE]) { + tree_level[CPUINFO_LVL_CORE].num_nodes++; + prev_id[CPUINFO_LVL_CORE] = n; + num_nodes++; + } + n = cpuinfo_id(i, CPUINFO_LVL_PROC); + if (n > prev_id[CPUINFO_LVL_PROC]) { + tree_level[CPUINFO_LVL_PROC].num_nodes++; + prev_id[CPUINFO_LVL_PROC] = n; + num_nodes++; + } + } + + tree_level[CPUINFO_LVL_ROOT].num_nodes = 1; + + n = tree_level[CPUINFO_LVL_NODE].num_nodes; + tree_level[CPUINFO_LVL_NODE].start_index = 1; + tree_level[CPUINFO_LVL_NODE].end_index = n; + + n++; + tree_level[CPUINFO_LVL_CORE].start_index = n; + n += tree_level[CPUINFO_LVL_CORE].num_nodes; + tree_level[CPUINFO_LVL_CORE].end_index = n - 1; + + tree_level[CPUINFO_LVL_PROC].start_index = n; + n += tree_level[CPUINFO_LVL_PROC].num_nodes; + tree_level[CPUINFO_LVL_PROC].end_index = n - 1; + + return num_nodes; +} + +/* Build a tree representation of the CPU hierarchy using the per CPU + * information in __cpu_data. Entries in __cpu_data[0..NR_CPUS] are + * assumed to be sorted in ascending order based on node, core_id, and + * proc_id (in order of significance). + */ +static struct cpuinfo_tree *build_cpuinfo_tree(void) +{ + struct cpuinfo_tree *new_tree; + struct cpuinfo_node *node; + struct cpuinfo_level tmp_level[CPUINFO_LVL_MAX]; + int num_cpus[CPUINFO_LVL_MAX]; + int level_rover[CPUINFO_LVL_MAX]; + int prev_id[CPUINFO_LVL_MAX]; + int n, id, cpu, prev_cpu, last_cpu, level; + + n = enumerate_cpuinfo_nodes(tmp_level); + + new_tree = kzalloc(sizeof(struct cpuinfo_tree) + + (sizeof(struct cpuinfo_node) * n), GFP_ATOMIC); + if (!new_tree) + return NULL; + + new_tree->total_nodes = n; + memcpy(&new_tree->level, tmp_level, sizeof(tmp_level)); + + prev_cpu = cpu = first_cpu(cpu_online_map); + + /* Initialize all levels in the tree with the first CPU */ + for (level = CPUINFO_LVL_PROC; level >= CPUINFO_LVL_ROOT; level--) { + n = new_tree->level[level].start_index; + + level_rover[level] = n; + node = &new_tree->nodes[n]; + + id = cpuinfo_id(cpu, level); + if (unlikely(id < 0)) { + kfree(new_tree); + return NULL; + } + node->id = id; + node->level = level; + node->num_cpus = 1; + + node->parent_index = (level > CPUINFO_LVL_ROOT) + ? new_tree->level[level - 1].start_index : -1; + + node->child_start = node->child_end = node->rover = + (level == CPUINFO_LVL_PROC) + ? cpu : new_tree->level[level + 1].start_index; + + prev_id[level] = node->id; + num_cpus[level] = 1; + } + + for (last_cpu = (num_possible_cpus() - 1); last_cpu >= 0; last_cpu--) { + if (cpu_online(last_cpu)) + break; + } + + while (++cpu <= last_cpu) { + if (!cpu_online(cpu)) + continue; + + for (level = CPUINFO_LVL_PROC; level >= CPUINFO_LVL_ROOT; + level--) { + id = cpuinfo_id(cpu, level); + if (unlikely(id < 0)) { + kfree(new_tree); + return NULL; + } + + if ((id != prev_id[level]) || (cpu == last_cpu)) { + prev_id[level] = id; + node = &new_tree->nodes[level_rover[level]]; + node->num_cpus = num_cpus[level]; + num_cpus[level] = 1; + + if (cpu == last_cpu) + node->num_cpus++; + + /* Connect tree node to parent */ + if (level == CPUINFO_LVL_ROOT) + node->parent_index = -1; + else + node->parent_index = + level_rover[level - 1]; + + if (level == CPUINFO_LVL_PROC) { + node->child_end = + (cpu == last_cpu) ? cpu : prev_cpu; + } else { + node->child_end = + level_rover[level + 1] - 1; + } + + /* Initialize the next node in the same level */ + n = ++level_rover[level]; + if (n <= new_tree->level[level].end_index) { + node = &new_tree->nodes[n]; + node->id = id; + node->level = level; + + /* Connect node to child */ + node->child_start = node->child_end = + node->rover = + (level == CPUINFO_LVL_PROC) + ? cpu : level_rover[level + 1]; + } + } else + num_cpus[level]++; + } + prev_cpu = cpu; + } + + return new_tree; +} + +static void increment_rover(struct cpuinfo_tree *t, int node_index, + int root_index, const int *rover_inc_table) +{ + struct cpuinfo_node *node = &t->nodes[node_index]; + int top_level, level; + + top_level = t->nodes[root_index].level; + for (level = node->level; level >= top_level; level--) { + node->rover++; + if (node->rover <= node->child_end) + return; + + node->rover = node->child_start; + /* If parent's rover does not need to be adjusted, stop here. */ + if ((level == top_level) || + !(rover_inc_table[level] & ROVER_INC_PARENT_ON_LOOP)) + return; + + node = &t->nodes[node->parent_index]; + } +} + +static int iterate_cpu(struct cpuinfo_tree *t, unsigned int root_index) +{ + const int *rover_inc_table; + int level, new_index, index = root_index; + + switch (sun4v_chip_type) { + case SUN4V_CHIP_NIAGARA1: + case SUN4V_CHIP_NIAGARA2: + rover_inc_table = niagara_iterate_method; + break; + default: + rover_inc_table = generic_iterate_method; + } + + for (level = t->nodes[root_index].level; level < CPUINFO_LVL_MAX; + level++) { + new_index = t->nodes[index].rover; + if (rover_inc_table[level] & ROVER_INC_ON_VISIT) + increment_rover(t, index, root_index, rover_inc_table); + + index = new_index; + } + return index; +} + +static void _cpu_map_rebuild(void) +{ + int i; + + if (cpuinfo_tree) { + kfree(cpuinfo_tree); + cpuinfo_tree = NULL; + } + + cpuinfo_tree = build_cpuinfo_tree(); + if (!cpuinfo_tree) + return; + + /* Build CPU distribution map that spans all online CPUs. No need + * to check if the CPU is online, as that is done when the cpuinfo + * tree is being built. + */ + for (i = 0; i < cpuinfo_tree->nodes[0].num_cpus; i++) + cpu_distribution_map[i] = iterate_cpu(cpuinfo_tree, 0); +} + +/* Fallback if the cpuinfo tree could not be built. CPU mapping is linear + * round robin. + */ +static int simple_map_to_cpu(unsigned int index) +{ + int i, end, cpu_rover; + + cpu_rover = 0; + end = index % num_online_cpus(); + for (i = 0; i < num_possible_cpus(); i++) { + if (cpu_online(cpu_rover)) { + if (cpu_rover >= end) + return cpu_rover; + + cpu_rover++; + } + } + + /* Impossible, since num_online_cpus() <= num_possible_cpus() */ + return first_cpu(cpu_online_map); +} + +static int _map_to_cpu(unsigned int index) +{ + struct cpuinfo_node *root_node; + + if (unlikely(!cpuinfo_tree)) { + _cpu_map_rebuild(); + if (!cpuinfo_tree) + return simple_map_to_cpu(index); + } + + root_node = &cpuinfo_tree->nodes[0]; +#ifdef CONFIG_HOTPLUG_CPU + if (unlikely(root_node->num_cpus != num_online_cpus())) { + _cpu_map_rebuild(); + if (!cpuinfo_tree) + return simple_map_to_cpu(index); + } +#endif + return cpu_distribution_map[index % root_node->num_cpus]; +} + +int map_to_cpu(unsigned int index) +{ + int mapped_cpu; + unsigned long flag; + + spin_lock_irqsave(&cpu_map_lock, flag); + mapped_cpu = _map_to_cpu(index); + +#ifdef CONFIG_HOTPLUG_CPU + while (unlikely(!cpu_online(mapped_cpu))) + mapped_cpu = _map_to_cpu(index); +#endif + spin_unlock_irqrestore(&cpu_map_lock, flag); + return mapped_cpu; +} +EXPORT_SYMBOL(map_to_cpu); + +void cpu_map_rebuild(void) +{ + unsigned long flag; + + spin_lock_irqsave(&cpu_map_lock, flag); + _cpu_map_rebuild(); + spin_unlock_irqrestore(&cpu_map_lock, flag); +} diff --git a/arch/sparc/kernel/cpumap.h b/arch/sparc/kernel/cpumap.h new file mode 100644 index 000000000000..e639880ab864 --- /dev/null +++ b/arch/sparc/kernel/cpumap.h @@ -0,0 +1,16 @@ +#ifndef _CPUMAP_H +#define _CPUMAP_H + +#ifdef CONFIG_SMP +extern void cpu_map_rebuild(void); +extern int map_to_cpu(unsigned int index); +#define cpu_map_init() cpu_map_rebuild() +#else +#define cpu_map_init() do {} while (0) +static inline int map_to_cpu(unsigned int index) +{ + return raw_smp_processor_id(); +} +#endif + +#endif diff --git a/arch/sparc/kernel/dma.c b/arch/sparc/kernel/dma.c index ebc8403b035e..524c32f97c55 100644 --- a/arch/sparc/kernel/dma.c +++ b/arch/sparc/kernel/dma.c @@ -35,8 +35,8 @@ int dma_set_mask(struct device *dev, u64 dma_mask) } EXPORT_SYMBOL(dma_set_mask); -void *dma_alloc_coherent(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t flag) +static void *dma32_alloc_coherent(struct device *dev, size_t size, + dma_addr_t *dma_handle, gfp_t flag) { #ifdef CONFIG_PCI if (dev->bus == &pci_bus_type) @@ -44,10 +44,9 @@ void *dma_alloc_coherent(struct device *dev, size_t size, #endif return sbus_alloc_consistent(dev, size, dma_handle); } -EXPORT_SYMBOL(dma_alloc_coherent); -void dma_free_coherent(struct device *dev, size_t size, - void *cpu_addr, dma_addr_t dma_handle) +static void dma32_free_coherent(struct device *dev, size_t size, + void *cpu_addr, dma_addr_t dma_handle) { #ifdef CONFIG_PCI if (dev->bus == &pci_bus_type) { @@ -58,38 +57,10 @@ void dma_free_coherent(struct device *dev, size_t size, #endif sbus_free_consistent(dev, size, cpu_addr, dma_handle); } -EXPORT_SYMBOL(dma_free_coherent); -dma_addr_t dma_map_single(struct device *dev, void *cpu_addr, - size_t size, enum dma_data_direction direction) -{ -#ifdef CONFIG_PCI - if (dev->bus == &pci_bus_type) - return pci_map_single(to_pci_dev(dev), cpu_addr, - size, (int)direction); -#endif - return sbus_map_single(dev, cpu_addr, size, (int)direction); -} -EXPORT_SYMBOL(dma_map_single); - -void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, - size_t size, - enum dma_data_direction direction) -{ -#ifdef CONFIG_PCI - if (dev->bus == &pci_bus_type) { - pci_unmap_single(to_pci_dev(dev), dma_addr, - size, (int)direction); - return; - } -#endif - sbus_unmap_single(dev, dma_addr, size, (int)direction); -} -EXPORT_SYMBOL(dma_unmap_single); - -dma_addr_t dma_map_page(struct device *dev, struct page *page, - unsigned long offset, size_t size, - enum dma_data_direction direction) +static dma_addr_t dma32_map_page(struct device *dev, struct page *page, + unsigned long offset, size_t size, + enum dma_data_direction direction) { #ifdef CONFIG_PCI if (dev->bus == &pci_bus_type) @@ -99,10 +70,9 @@ dma_addr_t dma_map_page(struct device *dev, struct page *page, return sbus_map_single(dev, page_address(page) + offset, size, (int)direction); } -EXPORT_SYMBOL(dma_map_page); -void dma_unmap_page(struct device *dev, dma_addr_t dma_address, - size_t size, enum dma_data_direction direction) +static void dma32_unmap_page(struct device *dev, dma_addr_t dma_address, + size_t size, enum dma_data_direction direction) { #ifdef CONFIG_PCI if (dev->bus == &pci_bus_type) { @@ -113,10 +83,9 @@ void dma_unmap_page(struct device *dev, dma_addr_t dma_address, #endif sbus_unmap_single(dev, dma_address, size, (int)direction); } -EXPORT_SYMBOL(dma_unmap_page); -int dma_map_sg(struct device *dev, struct scatterlist *sg, - int nents, enum dma_data_direction direction) +static int dma32_map_sg(struct device *dev, struct scatterlist *sg, + int nents, enum dma_data_direction direction) { #ifdef CONFIG_PCI if (dev->bus == &pci_bus_type) @@ -124,10 +93,9 @@ int dma_map_sg(struct device *dev, struct scatterlist *sg, #endif return sbus_map_sg(dev, sg, nents, direction); } -EXPORT_SYMBOL(dma_map_sg); -void dma_unmap_sg(struct device *dev, struct scatterlist *sg, - int nents, enum dma_data_direction direction) +void dma32_unmap_sg(struct device *dev, struct scatterlist *sg, + int nents, enum dma_data_direction direction) { #ifdef CONFIG_PCI if (dev->bus == &pci_bus_type) { @@ -137,10 +105,10 @@ void dma_unmap_sg(struct device *dev, struct scatterlist *sg, #endif sbus_unmap_sg(dev, sg, nents, (int)direction); } -EXPORT_SYMBOL(dma_unmap_sg); -void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, - size_t size, enum dma_data_direction direction) +static void dma32_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, + size_t size, + enum dma_data_direction direction) { #ifdef CONFIG_PCI if (dev->bus == &pci_bus_type) { @@ -151,10 +119,10 @@ void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, #endif sbus_dma_sync_single_for_cpu(dev, dma_handle, size, (int) direction); } -EXPORT_SYMBOL(dma_sync_single_for_cpu); -void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, - size_t size, enum dma_data_direction direction) +static void dma32_sync_single_for_device(struct device *dev, + dma_addr_t dma_handle, size_t size, + enum dma_data_direction direction) { #ifdef CONFIG_PCI if (dev->bus == &pci_bus_type) { @@ -165,28 +133,9 @@ void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, #endif sbus_dma_sync_single_for_device(dev, dma_handle, size, (int) direction); } -EXPORT_SYMBOL(dma_sync_single_for_device); -void dma_sync_single_range_for_cpu(struct device *dev, - dma_addr_t dma_handle, - unsigned long offset, - size_t size, - enum dma_data_direction direction) -{ - dma_sync_single_for_cpu(dev, dma_handle+offset, size, direction); -} -EXPORT_SYMBOL(dma_sync_single_range_for_cpu); - -void dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle, - unsigned long offset, size_t size, - enum dma_data_direction direction) -{ - dma_sync_single_for_device(dev, dma_handle+offset, size, direction); -} -EXPORT_SYMBOL(dma_sync_single_range_for_device); - -void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, - int nelems, enum dma_data_direction direction) +static void dma32_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, + int nelems, enum dma_data_direction direction) { #ifdef CONFIG_PCI if (dev->bus == &pci_bus_type) { @@ -197,11 +146,10 @@ void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, #endif BUG(); } -EXPORT_SYMBOL(dma_sync_sg_for_cpu); -void dma_sync_sg_for_device(struct device *dev, - struct scatterlist *sg, int nelems, - enum dma_data_direction direction) +static void dma32_sync_sg_for_device(struct device *dev, + struct scatterlist *sg, int nelems, + enum dma_data_direction direction) { #ifdef CONFIG_PCI if (dev->bus == &pci_bus_type) { @@ -212,16 +160,19 @@ void dma_sync_sg_for_device(struct device *dev, #endif BUG(); } -EXPORT_SYMBOL(dma_sync_sg_for_device); -int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) -{ - return (dma_addr == DMA_ERROR_CODE); -} -EXPORT_SYMBOL(dma_mapping_error); +static const struct dma_ops dma32_dma_ops = { + .alloc_coherent = dma32_alloc_coherent, + .free_coherent = dma32_free_coherent, + .map_page = dma32_map_page, + .unmap_page = dma32_unmap_page, + .map_sg = dma32_map_sg, + .unmap_sg = dma32_unmap_sg, + .sync_single_for_cpu = dma32_sync_single_for_cpu, + .sync_single_for_device = dma32_sync_single_for_device, + .sync_sg_for_cpu = dma32_sync_sg_for_cpu, + .sync_sg_for_device = dma32_sync_sg_for_device, +}; -int dma_get_cache_alignment(void) -{ - return 32; -} -EXPORT_SYMBOL(dma_get_cache_alignment); +const struct dma_ops *dma_ops = &dma32_dma_ops; +EXPORT_SYMBOL(dma_ops); diff --git a/arch/sparc/kernel/ds.c b/arch/sparc/kernel/ds.c index 90350f838f05..4a700f4b79ce 100644 --- a/arch/sparc/kernel/ds.c +++ b/arch/sparc/kernel/ds.c @@ -544,7 +544,8 @@ static int __cpuinit dr_cpu_configure(struct ds_info *dp, resp_len, ncpus, mask, DR_CPU_STAT_CONFIGURED); - mdesc_fill_in_cpu_data(*mask); + mdesc_populate_present_mask(mask); + mdesc_fill_in_cpu_data(mask); for_each_cpu_mask(cpu, *mask) { int err; diff --git a/arch/sparc/kernel/ftrace.c b/arch/sparc/kernel/ftrace.c index d0218e73f982..d3b1a3076569 100644 --- a/arch/sparc/kernel/ftrace.c +++ b/arch/sparc/kernel/ftrace.c @@ -7,14 +7,10 @@ #include +#ifdef CONFIG_DYNAMIC_FTRACE static const u32 ftrace_nop = 0x01000000; -unsigned char *ftrace_nop_replace(void) -{ - return (char *)&ftrace_nop; -} - -unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr) +static u32 ftrace_call_replace(unsigned long ip, unsigned long addr) { static u32 call; s32 off; @@ -22,15 +18,11 @@ unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr) off = ((s32)addr - (s32)ip); call = 0x40000000 | ((u32)off >> 2); - return (unsigned char *) &call; + return call; } -int -ftrace_modify_code(unsigned long ip, unsigned char *old_code, - unsigned char *new_code) +static int ftrace_modify_code(unsigned long ip, u32 old, u32 new) { - u32 old = *(u32 *)old_code; - u32 new = *(u32 *)new_code; u32 replaced; int faulted; @@ -59,18 +51,43 @@ ftrace_modify_code(unsigned long ip, unsigned char *old_code, return faulted; } +int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, unsigned long addr) +{ + unsigned long ip = rec->ip; + u32 old, new; + + old = ftrace_call_replace(ip, addr); + new = ftrace_nop; + return ftrace_modify_code(ip, old, new); +} + +int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) +{ + unsigned long ip = rec->ip; + u32 old, new; + + old = ftrace_nop; + new = ftrace_call_replace(ip, addr); + return ftrace_modify_code(ip, old, new); +} + int ftrace_update_ftrace_func(ftrace_func_t func) { unsigned long ip = (unsigned long)(&ftrace_call); - unsigned char old[MCOUNT_INSN_SIZE], *new; + u32 old, new; - memcpy(old, &ftrace_call, MCOUNT_INSN_SIZE); + old = *(u32 *) &ftrace_call; new = ftrace_call_replace(ip, (unsigned long)func); return ftrace_modify_code(ip, old, new); } int __init ftrace_dyn_arch_init(void *data) { - ftrace_mcount_set(data); + unsigned long *p = data; + + *p = 0; + return 0; } +#endif + diff --git a/arch/sparc/kernel/head_64.S b/arch/sparc/kernel/head_64.S index 91bf4c7f79b9..f8f21050448b 100644 --- a/arch/sparc/kernel/head_64.S +++ b/arch/sparc/kernel/head_64.S @@ -641,28 +641,6 @@ tlb_fixup_done: /* Not reached... */ 1: - /* If we boot on a non-zero cpu, all of the per-cpu - * variable references we make before setting up the - * per-cpu areas will use a bogus offset. Put a - * compensating factor into __per_cpu_base to handle - * this cleanly. - * - * What the per-cpu code calculates is: - * - * __per_cpu_base + (cpu << __per_cpu_shift) - * - * These two variables are zero initially, so to - * make it all cancel out to zero we need to put - * "0 - (cpu << 0)" into __per_cpu_base so that the - * above formula evaluates to zero. - * - * We cannot even perform a printk() until this stuff - * is setup as that calls cpu_clock() which uses - * per-cpu variables. - */ - sub %g0, %o0, %o1 - sethi %hi(__per_cpu_base), %o2 - stx %o1, [%o2 + %lo(__per_cpu_base)] #else mov 0, %o0 #endif diff --git a/arch/sparc/kernel/init_task.c b/arch/sparc/kernel/init_task.c index f28cb8278e98..28125c5b3d3c 100644 --- a/arch/sparc/kernel/init_task.c +++ b/arch/sparc/kernel/init_task.c @@ -10,10 +10,7 @@ static struct signal_struct init_signals = INIT_SIGNALS(init_signals); static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); -struct mm_struct init_mm = INIT_MM(init_mm); struct task_struct init_task = INIT_TASK(init_task); - -EXPORT_SYMBOL(init_mm); EXPORT_SYMBOL(init_task); /* .text section in head.S is aligned at 8k boundary and this gets linked diff --git a/arch/sparc/kernel/iommu.c b/arch/sparc/kernel/iommu.c index d8900e1d5aad..0aeaefe696b9 100644 --- a/arch/sparc/kernel/iommu.c +++ b/arch/sparc/kernel/iommu.c @@ -351,8 +351,9 @@ static void dma_4u_free_coherent(struct device *dev, size_t size, free_pages((unsigned long)cpu, order); } -static dma_addr_t dma_4u_map_single(struct device *dev, void *ptr, size_t sz, - enum dma_data_direction direction) +static dma_addr_t dma_4u_map_page(struct device *dev, struct page *page, + unsigned long offset, size_t sz, + enum dma_data_direction direction) { struct iommu *iommu; struct strbuf *strbuf; @@ -368,7 +369,7 @@ static dma_addr_t dma_4u_map_single(struct device *dev, void *ptr, size_t sz, if (unlikely(direction == DMA_NONE)) goto bad_no_ctx; - oaddr = (unsigned long)ptr; + oaddr = (unsigned long)(page_address(page) + offset); npages = IO_PAGE_ALIGN(oaddr + sz) - (oaddr & IO_PAGE_MASK); npages >>= IO_PAGE_SHIFT; @@ -472,8 +473,8 @@ do_flush_sync: vaddr, ctx, npages); } -static void dma_4u_unmap_single(struct device *dev, dma_addr_t bus_addr, - size_t sz, enum dma_data_direction direction) +static void dma_4u_unmap_page(struct device *dev, dma_addr_t bus_addr, + size_t sz, enum dma_data_direction direction) { struct iommu *iommu; struct strbuf *strbuf; @@ -824,8 +825,8 @@ static void dma_4u_sync_sg_for_cpu(struct device *dev, static const struct dma_ops sun4u_dma_ops = { .alloc_coherent = dma_4u_alloc_coherent, .free_coherent = dma_4u_free_coherent, - .map_single = dma_4u_map_single, - .unmap_single = dma_4u_unmap_single, + .map_page = dma_4u_map_page, + .unmap_page = dma_4u_unmap_page, .map_sg = dma_4u_map_sg, .unmap_sg = dma_4u_unmap_sg, .sync_single_for_cpu = dma_4u_sync_single_for_cpu, diff --git a/arch/sparc/kernel/irq_64.c b/arch/sparc/kernel/irq_64.c index 5deabe921a47..bd075054942b 100644 --- a/arch/sparc/kernel/irq_64.c +++ b/arch/sparc/kernel/irq_64.c @@ -45,6 +45,7 @@ #include #include "entry.h" +#include "cpumap.h" #define NUM_IVECS (IMAP_INR + 1) @@ -256,35 +257,13 @@ static int irq_choose_cpu(unsigned int virt_irq) int cpuid; cpumask_copy(&mask, irq_desc[virt_irq].affinity); - if (cpus_equal(mask, CPU_MASK_ALL)) { - static int irq_rover; - static DEFINE_SPINLOCK(irq_rover_lock); - unsigned long flags; - - /* Round-robin distribution... */ - do_round_robin: - spin_lock_irqsave(&irq_rover_lock, flags); - - while (!cpu_online(irq_rover)) { - if (++irq_rover >= nr_cpu_ids) - irq_rover = 0; - } - cpuid = irq_rover; - do { - if (++irq_rover >= nr_cpu_ids) - irq_rover = 0; - } while (!cpu_online(irq_rover)); - - spin_unlock_irqrestore(&irq_rover_lock, flags); + if (cpus_equal(mask, cpu_online_map)) { + cpuid = map_to_cpu(virt_irq); } else { cpumask_t tmp; cpus_and(tmp, cpu_online_map, mask); - - if (cpus_empty(tmp)) - goto do_round_robin; - - cpuid = first_cpu(tmp); + cpuid = cpus_empty(tmp) ? map_to_cpu(virt_irq) : first_cpu(tmp); } return cpuid; @@ -318,10 +297,12 @@ static void sun4u_irq_enable(unsigned int virt_irq) } } -static void sun4u_set_affinity(unsigned int virt_irq, +static int sun4u_set_affinity(unsigned int virt_irq, const struct cpumask *mask) { sun4u_irq_enable(virt_irq); + + return 0; } /* Don't do anything. The desc->status check for IRQ_DISABLED in @@ -377,7 +358,7 @@ static void sun4v_irq_enable(unsigned int virt_irq) ino, err); } -static void sun4v_set_affinity(unsigned int virt_irq, +static int sun4v_set_affinity(unsigned int virt_irq, const struct cpumask *mask) { unsigned int ino = virt_irq_table[virt_irq].dev_ino; @@ -388,6 +369,8 @@ static void sun4v_set_affinity(unsigned int virt_irq, if (err != HV_EOK) printk(KERN_ERR "sun4v_intr_settarget(%x,%lu): " "err(%d)\n", ino, cpuid, err); + + return 0; } static void sun4v_irq_disable(unsigned int virt_irq) @@ -445,7 +428,7 @@ static void sun4v_virq_enable(unsigned int virt_irq) dev_handle, dev_ino, err); } -static void sun4v_virt_set_affinity(unsigned int virt_irq, +static int sun4v_virt_set_affinity(unsigned int virt_irq, const struct cpumask *mask) { unsigned long cpuid, dev_handle, dev_ino; @@ -461,6 +444,8 @@ static void sun4v_virt_set_affinity(unsigned int virt_irq, printk(KERN_ERR "sun4v_vintr_set_target(%lx,%lx,%lu): " "err(%d)\n", dev_handle, dev_ino, cpuid, err); + + return 0; } static void sun4v_virq_disable(unsigned int virt_irq) diff --git a/arch/sparc/kernel/mdesc.c b/arch/sparc/kernel/mdesc.c index f0e6ed23a468..938da19dc065 100644 --- a/arch/sparc/kernel/mdesc.c +++ b/arch/sparc/kernel/mdesc.c @@ -574,7 +574,7 @@ static void __init report_platform_properties(void) mdesc_release(hp); } -static void __devinit fill_in_one_cache(cpuinfo_sparc *c, +static void __cpuinit fill_in_one_cache(cpuinfo_sparc *c, struct mdesc_handle *hp, u64 mp) { @@ -619,8 +619,7 @@ static void __devinit fill_in_one_cache(cpuinfo_sparc *c, } } -static void __devinit mark_core_ids(struct mdesc_handle *hp, u64 mp, - int core_id) +static void __cpuinit mark_core_ids(struct mdesc_handle *hp, u64 mp, int core_id) { u64 a; @@ -653,7 +652,7 @@ static void __devinit mark_core_ids(struct mdesc_handle *hp, u64 mp, } } -static void __devinit set_core_ids(struct mdesc_handle *hp) +static void __cpuinit set_core_ids(struct mdesc_handle *hp) { int idx; u64 mp; @@ -678,8 +677,7 @@ static void __devinit set_core_ids(struct mdesc_handle *hp) } } -static void __devinit mark_proc_ids(struct mdesc_handle *hp, u64 mp, - int proc_id) +static void __cpuinit mark_proc_ids(struct mdesc_handle *hp, u64 mp, int proc_id) { u64 a; @@ -698,8 +696,7 @@ static void __devinit mark_proc_ids(struct mdesc_handle *hp, u64 mp, } } -static void __devinit __set_proc_ids(struct mdesc_handle *hp, - const char *exec_unit_name) +static void __cpuinit __set_proc_ids(struct mdesc_handle *hp, const char *exec_unit_name) { int idx; u64 mp; @@ -720,13 +717,13 @@ static void __devinit __set_proc_ids(struct mdesc_handle *hp, } } -static void __devinit set_proc_ids(struct mdesc_handle *hp) +static void __cpuinit set_proc_ids(struct mdesc_handle *hp) { __set_proc_ids(hp, "exec_unit"); __set_proc_ids(hp, "exec-unit"); } -static void __devinit get_one_mondo_bits(const u64 *p, unsigned int *mask, +static void __cpuinit get_one_mondo_bits(const u64 *p, unsigned int *mask, unsigned char def) { u64 val; @@ -745,7 +742,7 @@ use_default: *mask = ((1U << def) * 64U) - 1U; } -static void __devinit get_mondo_data(struct mdesc_handle *hp, u64 mp, +static void __cpuinit get_mondo_data(struct mdesc_handle *hp, u64 mp, struct trap_per_cpu *tb) { const u64 *val; @@ -763,23 +760,15 @@ static void __devinit get_mondo_data(struct mdesc_handle *hp, u64 mp, get_one_mondo_bits(val, &tb->nonresum_qmask, 2); } -void __cpuinit mdesc_fill_in_cpu_data(cpumask_t mask) +static void * __cpuinit mdesc_iterate_over_cpus(void *(*func)(struct mdesc_handle *, u64, int, void *), void *arg, cpumask_t *mask) { struct mdesc_handle *hp = mdesc_grab(); + void *ret = NULL; u64 mp; - ncpus_probed = 0; mdesc_for_each_node_by_name(hp, mp, "cpu") { const u64 *id = mdesc_get_property(hp, mp, "id", NULL); - const u64 *cfreq = mdesc_get_property(hp, mp, "clock-frequency", NULL); - struct trap_per_cpu *tb; - cpuinfo_sparc *c; - int cpuid; - u64 a; - - ncpus_probed++; - - cpuid = *id; + int cpuid = *id; #ifdef CONFIG_SMP if (cpuid >= NR_CPUS) { @@ -788,62 +777,104 @@ void __cpuinit mdesc_fill_in_cpu_data(cpumask_t mask) cpuid, NR_CPUS); continue; } - if (!cpu_isset(cpuid, mask)) + if (!cpu_isset(cpuid, *mask)) continue; -#else - /* On uniprocessor we only want the values for the - * real physical cpu the kernel booted onto, however - * cpu_data() only has one entry at index 0. - */ - if (cpuid != real_hard_smp_processor_id()) - continue; - cpuid = 0; #endif - c = &cpu_data(cpuid); - c->clock_tick = *cfreq; + ret = func(hp, mp, cpuid, arg); + if (ret) + goto out; + } +out: + mdesc_release(hp); + return ret; +} - tb = &trap_block[cpuid]; - get_mondo_data(hp, mp, tb); +static void * __cpuinit record_one_cpu(struct mdesc_handle *hp, u64 mp, int cpuid, void *arg) +{ + ncpus_probed++; +#ifdef CONFIG_SMP + set_cpu_present(cpuid, true); +#endif + return NULL; +} - mdesc_for_each_arc(a, hp, mp, MDESC_ARC_TYPE_FWD) { - u64 j, t = mdesc_arc_target(hp, a); - const char *t_name; +void __cpuinit mdesc_populate_present_mask(cpumask_t *mask) +{ + if (tlb_type != hypervisor) + return; - t_name = mdesc_node_name(hp, t); - if (!strcmp(t_name, "cache")) { - fill_in_one_cache(c, hp, t); - continue; - } + ncpus_probed = 0; + mdesc_iterate_over_cpus(record_one_cpu, NULL, mask); +} - mdesc_for_each_arc(j, hp, t, MDESC_ARC_TYPE_FWD) { - u64 n = mdesc_arc_target(hp, j); - const char *n_name; +static void * __cpuinit fill_in_one_cpu(struct mdesc_handle *hp, u64 mp, int cpuid, void *arg) +{ + const u64 *cfreq = mdesc_get_property(hp, mp, "clock-frequency", NULL); + struct trap_per_cpu *tb; + cpuinfo_sparc *c; + u64 a; - n_name = mdesc_node_name(hp, n); - if (!strcmp(n_name, "cache")) - fill_in_one_cache(c, hp, n); - } +#ifndef CONFIG_SMP + /* On uniprocessor we only want the values for the + * real physical cpu the kernel booted onto, however + * cpu_data() only has one entry at index 0. + */ + if (cpuid != real_hard_smp_processor_id()) + return NULL; + cpuid = 0; +#endif + + c = &cpu_data(cpuid); + c->clock_tick = *cfreq; + + tb = &trap_block[cpuid]; + get_mondo_data(hp, mp, tb); + + mdesc_for_each_arc(a, hp, mp, MDESC_ARC_TYPE_FWD) { + u64 j, t = mdesc_arc_target(hp, a); + const char *t_name; + + t_name = mdesc_node_name(hp, t); + if (!strcmp(t_name, "cache")) { + fill_in_one_cache(c, hp, t); + continue; } -#ifdef CONFIG_SMP - cpu_set(cpuid, cpu_present_map); -#endif + mdesc_for_each_arc(j, hp, t, MDESC_ARC_TYPE_FWD) { + u64 n = mdesc_arc_target(hp, j); + const char *n_name; - c->core_id = 0; - c->proc_id = -1; + n_name = mdesc_node_name(hp, n); + if (!strcmp(n_name, "cache")) + fill_in_one_cache(c, hp, n); + } } + c->core_id = 0; + c->proc_id = -1; + + return NULL; +} + +void __cpuinit mdesc_fill_in_cpu_data(cpumask_t *mask) +{ + struct mdesc_handle *hp; + + mdesc_iterate_over_cpus(fill_in_one_cpu, NULL, mask); + #ifdef CONFIG_SMP sparc64_multi_core = 1; #endif + hp = mdesc_grab(); + set_core_ids(hp); set_proc_ids(hp); - smp_fill_in_sib_core_maps(); - mdesc_release(hp); + + smp_fill_in_sib_core_maps(); } static ssize_t mdesc_read(struct file *file, char __user *buf, @@ -887,7 +918,6 @@ void __init sun4v_mdesc_init(void) { struct mdesc_handle *hp; unsigned long len, real_len, status; - cpumask_t mask; (void) sun4v_mach_desc(0UL, 0UL, &len); @@ -911,7 +941,4 @@ void __init sun4v_mdesc_init(void) cur_mdesc = hp; report_platform_properties(); - - cpus_setall(mask); - mdesc_fill_in_cpu_data(mask); } diff --git a/arch/sparc/kernel/module.c b/arch/sparc/kernel/module.c index 90273765e81f..0ee642f63234 100644 --- a/arch/sparc/kernel/module.c +++ b/arch/sparc/kernel/module.c @@ -75,8 +75,6 @@ void *module_alloc(unsigned long size) void module_free(struct module *mod, void *module_region) { vfree(module_region); - /* FIXME: If module_region == mod->init_region, trim exception - table entries. */ } /* Make generic code ignore STT_REGISTER dummy undefined symbols. */ diff --git a/arch/sparc/kernel/of_device_32.c b/arch/sparc/kernel/of_device_32.c index c8f14c1dc521..90396702ea2c 100644 --- a/arch/sparc/kernel/of_device_32.c +++ b/arch/sparc/kernel/of_device_32.c @@ -6,159 +6,11 @@ #include #include #include +#include #include #include -static int node_match(struct device *dev, void *data) -{ - struct of_device *op = to_of_device(dev); - struct device_node *dp = data; - - return (op->node == dp); -} - -struct of_device *of_find_device_by_node(struct device_node *dp) -{ - struct device *dev = bus_find_device(&of_platform_bus_type, NULL, - dp, node_match); - - if (dev) - return to_of_device(dev); - - return NULL; -} -EXPORT_SYMBOL(of_find_device_by_node); - -unsigned int irq_of_parse_and_map(struct device_node *node, int index) -{ - struct of_device *op = of_find_device_by_node(node); - - if (!op || index >= op->num_irqs) - return 0; - - return op->irqs[index]; -} -EXPORT_SYMBOL(irq_of_parse_and_map); - -/* Take the archdata values for IOMMU, STC, and HOSTDATA found in - * BUS and propagate to all child of_device objects. - */ -void of_propagate_archdata(struct of_device *bus) -{ - struct dev_archdata *bus_sd = &bus->dev.archdata; - struct device_node *bus_dp = bus->node; - struct device_node *dp; - - for (dp = bus_dp->child; dp; dp = dp->sibling) { - struct of_device *op = of_find_device_by_node(dp); - - op->dev.archdata.iommu = bus_sd->iommu; - op->dev.archdata.stc = bus_sd->stc; - op->dev.archdata.host_controller = bus_sd->host_controller; - op->dev.archdata.numa_node = bus_sd->numa_node; - - if (dp->child) - of_propagate_archdata(op); - } -} - -struct bus_type of_platform_bus_type; -EXPORT_SYMBOL(of_platform_bus_type); - -static inline u64 of_read_addr(const u32 *cell, int size) -{ - u64 r = 0; - while (size--) - r = (r << 32) | *(cell++); - return r; -} - -static void __init get_cells(struct device_node *dp, - int *addrc, int *sizec) -{ - if (addrc) - *addrc = of_n_addr_cells(dp); - if (sizec) - *sizec = of_n_size_cells(dp); -} - -/* Max address size we deal with */ -#define OF_MAX_ADDR_CELLS 4 - -struct of_bus { - const char *name; - const char *addr_prop_name; - int (*match)(struct device_node *parent); - void (*count_cells)(struct device_node *child, - int *addrc, int *sizec); - int (*map)(u32 *addr, const u32 *range, - int na, int ns, int pna); - unsigned long (*get_flags)(const u32 *addr, unsigned long); -}; - -/* - * Default translator (generic bus) - */ - -static void of_bus_default_count_cells(struct device_node *dev, - int *addrc, int *sizec) -{ - get_cells(dev, addrc, sizec); -} - -/* Make sure the least significant 64-bits are in-range. Even - * for 3 or 4 cell values it is a good enough approximation. - */ -static int of_out_of_range(const u32 *addr, const u32 *base, - const u32 *size, int na, int ns) -{ - u64 a = of_read_addr(addr, na); - u64 b = of_read_addr(base, na); - - if (a < b) - return 1; - - b += of_read_addr(size, ns); - if (a >= b) - return 1; - - return 0; -} - -static int of_bus_default_map(u32 *addr, const u32 *range, - int na, int ns, int pna) -{ - u32 result[OF_MAX_ADDR_CELLS]; - int i; - - if (ns > 2) { - printk("of_device: Cannot handle size cells (%d) > 2.", ns); - return -EINVAL; - } - - if (of_out_of_range(addr, range, range + na + pna, na, ns)) - return -EINVAL; - - /* Start with the parent range base. */ - memcpy(result, range + na, pna * 4); - - /* Add in the child address offset. */ - for (i = 0; i < na; i++) - result[pna - 1 - i] += - (addr[na - 1 - i] - - range[na - 1 - i]); - - memcpy(addr, result, pna * 4); - - return 0; -} - -static unsigned long of_bus_default_get_flags(const u32 *addr, unsigned long flags) -{ - if (flags) - return flags; - return IORESOURCE_MEM; -} +#include "of_device_common.h" /* * PCI bus specific translator @@ -240,47 +92,6 @@ static unsigned long of_bus_pci_get_flags(const u32 *addr, unsigned long flags) return flags; } -/* - * SBUS bus specific translator - */ - -static int of_bus_sbus_match(struct device_node *np) -{ - struct device_node *dp = np; - - while (dp) { - if (!strcmp(dp->name, "sbus") || - !strcmp(dp->name, "sbi")) - return 1; - - /* Have a look at use_1to1_mapping(). We're trying - * to match SBUS if that's the top-level bus and we - * don't have some intervening real bus that provides - * ranges based translations. - */ - if (of_find_property(dp, "ranges", NULL) != NULL) - break; - - dp = dp->parent; - } - - return 0; -} - -static void of_bus_sbus_count_cells(struct device_node *child, - int *addrc, int *sizec) -{ - if (addrc) - *addrc = 2; - if (sizec) - *sizec = 1; -} - -static int of_bus_sbus_map(u32 *addr, const u32 *range, int na, int ns, int pna) -{ - return of_bus_default_map(addr, range, na, ns, pna); -} - static unsigned long of_bus_sbus_get_flags(const u32 *addr, unsigned long flags) { return IORESOURCE_MEM; @@ -307,7 +118,7 @@ static struct of_bus of_busses[] = { .addr_prop_name = "reg", .match = of_bus_sbus_match, .count_cells = of_bus_sbus_count_cells, - .map = of_bus_sbus_map, + .map = of_bus_default_map, .get_flags = of_bus_sbus_get_flags, }, /* Default */ diff --git a/arch/sparc/kernel/of_device_64.c b/arch/sparc/kernel/of_device_64.c index 5ac287ac03de..881947e59e95 100644 --- a/arch/sparc/kernel/of_device_64.c +++ b/arch/sparc/kernel/of_device_64.c @@ -10,6 +10,8 @@ #include #include +#include "of_device_common.h" + void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name) { unsigned long ret = res->start + offset; @@ -35,156 +37,6 @@ void of_iounmap(struct resource *res, void __iomem *base, unsigned long size) } EXPORT_SYMBOL(of_iounmap); -static int node_match(struct device *dev, void *data) -{ - struct of_device *op = to_of_device(dev); - struct device_node *dp = data; - - return (op->node == dp); -} - -struct of_device *of_find_device_by_node(struct device_node *dp) -{ - struct device *dev = bus_find_device(&of_platform_bus_type, NULL, - dp, node_match); - - if (dev) - return to_of_device(dev); - - return NULL; -} -EXPORT_SYMBOL(of_find_device_by_node); - -unsigned int irq_of_parse_and_map(struct device_node *node, int index) -{ - struct of_device *op = of_find_device_by_node(node); - - if (!op || index >= op->num_irqs) - return 0; - - return op->irqs[index]; -} -EXPORT_SYMBOL(irq_of_parse_and_map); - -/* Take the archdata values for IOMMU, STC, and HOSTDATA found in - * BUS and propagate to all child of_device objects. - */ -void of_propagate_archdata(struct of_device *bus) -{ - struct dev_archdata *bus_sd = &bus->dev.archdata; - struct device_node *bus_dp = bus->node; - struct device_node *dp; - - for (dp = bus_dp->child; dp; dp = dp->sibling) { - struct of_device *op = of_find_device_by_node(dp); - - op->dev.archdata.iommu = bus_sd->iommu; - op->dev.archdata.stc = bus_sd->stc; - op->dev.archdata.host_controller = bus_sd->host_controller; - op->dev.archdata.numa_node = bus_sd->numa_node; - - if (dp->child) - of_propagate_archdata(op); - } -} - -struct bus_type of_platform_bus_type; -EXPORT_SYMBOL(of_platform_bus_type); - -static inline u64 of_read_addr(const u32 *cell, int size) -{ - u64 r = 0; - while (size--) - r = (r << 32) | *(cell++); - return r; -} - -static void get_cells(struct device_node *dp, int *addrc, int *sizec) -{ - if (addrc) - *addrc = of_n_addr_cells(dp); - if (sizec) - *sizec = of_n_size_cells(dp); -} - -/* Max address size we deal with */ -#define OF_MAX_ADDR_CELLS 4 - -struct of_bus { - const char *name; - const char *addr_prop_name; - int (*match)(struct device_node *parent); - void (*count_cells)(struct device_node *child, - int *addrc, int *sizec); - int (*map)(u32 *addr, const u32 *range, - int na, int ns, int pna); - unsigned long (*get_flags)(const u32 *addr, unsigned long); -}; - -/* - * Default translator (generic bus) - */ - -static void of_bus_default_count_cells(struct device_node *dev, - int *addrc, int *sizec) -{ - get_cells(dev, addrc, sizec); -} - -/* Make sure the least significant 64-bits are in-range. Even - * for 3 or 4 cell values it is a good enough approximation. - */ -static int of_out_of_range(const u32 *addr, const u32 *base, - const u32 *size, int na, int ns) -{ - u64 a = of_read_addr(addr, na); - u64 b = of_read_addr(base, na); - - if (a < b) - return 1; - - b += of_read_addr(size, ns); - if (a >= b) - return 1; - - return 0; -} - -static int of_bus_default_map(u32 *addr, const u32 *range, - int na, int ns, int pna) -{ - u32 result[OF_MAX_ADDR_CELLS]; - int i; - - if (ns > 2) { - printk("of_device: Cannot handle size cells (%d) > 2.", ns); - return -EINVAL; - } - - if (of_out_of_range(addr, range, range + na + pna, na, ns)) - return -EINVAL; - - /* Start with the parent range base. */ - memcpy(result, range + na, pna * 4); - - /* Add in the child address offset. */ - for (i = 0; i < na; i++) - result[pna - 1 - i] += - (addr[na - 1 - i] - - range[na - 1 - i]); - - memcpy(addr, result, pna * 4); - - return 0; -} - -static unsigned long of_bus_default_get_flags(const u32 *addr, unsigned long flags) -{ - if (flags) - return flags; - return IORESOURCE_MEM; -} - /* * PCI bus specific translator */ @@ -294,42 +146,6 @@ static unsigned long of_bus_pci_get_flags(const u32 *addr, unsigned long flags) return flags; } -/* - * SBUS bus specific translator - */ - -static int of_bus_sbus_match(struct device_node *np) -{ - struct device_node *dp = np; - - while (dp) { - if (!strcmp(dp->name, "sbus") || - !strcmp(dp->name, "sbi")) - return 1; - - /* Have a look at use_1to1_mapping(). We're trying - * to match SBUS if that's the top-level bus and we - * don't have some intervening real bus that provides - * ranges based translations. - */ - if (of_find_property(dp, "ranges", NULL) != NULL) - break; - - dp = dp->parent; - } - - return 0; -} - -static void of_bus_sbus_count_cells(struct device_node *child, - int *addrc, int *sizec) -{ - if (addrc) - *addrc = 2; - if (sizec) - *sizec = 1; -} - /* * FHC/Central bus specific translator. * diff --git a/arch/sparc/kernel/of_device_common.c b/arch/sparc/kernel/of_device_common.c new file mode 100644 index 000000000000..cb8eb799bb6c --- /dev/null +++ b/arch/sparc/kernel/of_device_common.c @@ -0,0 +1,174 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "of_device_common.h" + +static int node_match(struct device *dev, void *data) +{ + struct of_device *op = to_of_device(dev); + struct device_node *dp = data; + + return (op->node == dp); +} + +struct of_device *of_find_device_by_node(struct device_node *dp) +{ + struct device *dev = bus_find_device(&of_platform_bus_type, NULL, + dp, node_match); + + if (dev) + return to_of_device(dev); + + return NULL; +} +EXPORT_SYMBOL(of_find_device_by_node); + +unsigned int irq_of_parse_and_map(struct device_node *node, int index) +{ + struct of_device *op = of_find_device_by_node(node); + + if (!op || index >= op->num_irqs) + return 0; + + return op->irqs[index]; +} +EXPORT_SYMBOL(irq_of_parse_and_map); + +/* Take the archdata values for IOMMU, STC, and HOSTDATA found in + * BUS and propagate to all child of_device objects. + */ +void of_propagate_archdata(struct of_device *bus) +{ + struct dev_archdata *bus_sd = &bus->dev.archdata; + struct device_node *bus_dp = bus->node; + struct device_node *dp; + + for (dp = bus_dp->child; dp; dp = dp->sibling) { + struct of_device *op = of_find_device_by_node(dp); + + op->dev.archdata.iommu = bus_sd->iommu; + op->dev.archdata.stc = bus_sd->stc; + op->dev.archdata.host_controller = bus_sd->host_controller; + op->dev.archdata.numa_node = bus_sd->numa_node; + + if (dp->child) + of_propagate_archdata(op); + } +} + +struct bus_type of_platform_bus_type; +EXPORT_SYMBOL(of_platform_bus_type); + +static void get_cells(struct device_node *dp, int *addrc, int *sizec) +{ + if (addrc) + *addrc = of_n_addr_cells(dp); + if (sizec) + *sizec = of_n_size_cells(dp); +} + +/* + * Default translator (generic bus) + */ + +void of_bus_default_count_cells(struct device_node *dev, int *addrc, int *sizec) +{ + get_cells(dev, addrc, sizec); +} + +/* Make sure the least significant 64-bits are in-range. Even + * for 3 or 4 cell values it is a good enough approximation. + */ +int of_out_of_range(const u32 *addr, const u32 *base, + const u32 *size, int na, int ns) +{ + u64 a = of_read_addr(addr, na); + u64 b = of_read_addr(base, na); + + if (a < b) + return 1; + + b += of_read_addr(size, ns); + if (a >= b) + return 1; + + return 0; +} + +int of_bus_default_map(u32 *addr, const u32 *range, int na, int ns, int pna) +{ + u32 result[OF_MAX_ADDR_CELLS]; + int i; + + if (ns > 2) { + printk("of_device: Cannot handle size cells (%d) > 2.", ns); + return -EINVAL; + } + + if (of_out_of_range(addr, range, range + na + pna, na, ns)) + return -EINVAL; + + /* Start with the parent range base. */ + memcpy(result, range + na, pna * 4); + + /* Add in the child address offset. */ + for (i = 0; i < na; i++) + result[pna - 1 - i] += + (addr[na - 1 - i] - + range[na - 1 - i]); + + memcpy(addr, result, pna * 4); + + return 0; +} + +unsigned long of_bus_default_get_flags(const u32 *addr, unsigned long flags) +{ + if (flags) + return flags; + return IORESOURCE_MEM; +} + +/* + * SBUS bus specific translator + */ + +int of_bus_sbus_match(struct device_node *np) +{ + struct device_node *dp = np; + + while (dp) { + if (!strcmp(dp->name, "sbus") || + !strcmp(dp->name, "sbi")) + return 1; + + /* Have a look at use_1to1_mapping(). We're trying + * to match SBUS if that's the top-level bus and we + * don't have some intervening real bus that provides + * ranges based translations. + */ + if (of_find_property(dp, "ranges", NULL) != NULL) + break; + + dp = dp->parent; + } + + return 0; +} + +void of_bus_sbus_count_cells(struct device_node *child, int *addrc, int *sizec) +{ + if (addrc) + *addrc = 2; + if (sizec) + *sizec = 1; +} diff --git a/arch/sparc/kernel/of_device_common.h b/arch/sparc/kernel/of_device_common.h new file mode 100644 index 000000000000..cdfd23992841 --- /dev/null +++ b/arch/sparc/kernel/of_device_common.h @@ -0,0 +1,36 @@ +#ifndef _OF_DEVICE_COMMON_H +#define _OF_DEVICE_COMMON_H + +static inline u64 of_read_addr(const u32 *cell, int size) +{ + u64 r = 0; + while (size--) + r = (r << 32) | *(cell++); + return r; +} + +void of_bus_default_count_cells(struct device_node *dev, int *addrc, + int *sizec); +int of_out_of_range(const u32 *addr, const u32 *base, + const u32 *size, int na, int ns); +int of_bus_default_map(u32 *addr, const u32 *range, int na, int ns, int pna); +unsigned long of_bus_default_get_flags(const u32 *addr, unsigned long flags); + +int of_bus_sbus_match(struct device_node *np); +void of_bus_sbus_count_cells(struct device_node *child, int *addrc, int *sizec); + +/* Max address size we deal with */ +#define OF_MAX_ADDR_CELLS 4 + +struct of_bus { + const char *name; + const char *addr_prop_name; + int (*match)(struct device_node *parent); + void (*count_cells)(struct device_node *child, + int *addrc, int *sizec); + int (*map)(u32 *addr, const u32 *range, + int na, int ns, int pna); + unsigned long (*get_flags)(const u32 *addr, unsigned long); +}; + +#endif /* _OF_DEVICE_COMMON_H */ diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c index 4638fba799e4..57859ad23547 100644 --- a/arch/sparc/kernel/pci.c +++ b/arch/sparc/kernel/pci.c @@ -711,19 +711,6 @@ void __devinit pcibios_fixup_bus(struct pci_bus *pbus) pbus->resource[1] = &pbm->mem_space; } -struct resource *pcibios_select_root(struct pci_dev *pdev, struct resource *r) -{ - struct pci_pbm_info *pbm = pdev->bus->sysdata; - struct resource *root = NULL; - - if (r->flags & IORESOURCE_IO) - root = &pbm->io_space; - if (r->flags & IORESOURCE_MEM) - root = &pbm->mem_space; - - return root; -} - void pcibios_update_irq(struct pci_dev *pdev, int irq) { } diff --git a/arch/sparc/kernel/pci_sun4v.c b/arch/sparc/kernel/pci_sun4v.c index 5db5ebed35da..2485eaa23101 100644 --- a/arch/sparc/kernel/pci_sun4v.c +++ b/arch/sparc/kernel/pci_sun4v.c @@ -230,8 +230,9 @@ static void dma_4v_free_coherent(struct device *dev, size_t size, void *cpu, free_pages((unsigned long)cpu, order); } -static dma_addr_t dma_4v_map_single(struct device *dev, void *ptr, size_t sz, - enum dma_data_direction direction) +static dma_addr_t dma_4v_map_page(struct device *dev, struct page *page, + unsigned long offset, size_t sz, + enum dma_data_direction direction) { struct iommu *iommu; unsigned long flags, npages, oaddr; @@ -245,7 +246,7 @@ static dma_addr_t dma_4v_map_single(struct device *dev, void *ptr, size_t sz, if (unlikely(direction == DMA_NONE)) goto bad; - oaddr = (unsigned long)ptr; + oaddr = (unsigned long)(page_address(page) + offset); npages = IO_PAGE_ALIGN(oaddr + sz) - (oaddr & IO_PAGE_MASK); npages >>= IO_PAGE_SHIFT; @@ -294,8 +295,8 @@ iommu_map_fail: return DMA_ERROR_CODE; } -static void dma_4v_unmap_single(struct device *dev, dma_addr_t bus_addr, - size_t sz, enum dma_data_direction direction) +static void dma_4v_unmap_page(struct device *dev, dma_addr_t bus_addr, + size_t sz, enum dma_data_direction direction) { struct pci_pbm_info *pbm; struct iommu *iommu; @@ -537,8 +538,8 @@ static void dma_4v_sync_sg_for_cpu(struct device *dev, static const struct dma_ops sun4v_dma_ops = { .alloc_coherent = dma_4v_alloc_coherent, .free_coherent = dma_4v_free_coherent, - .map_single = dma_4v_map_single, - .unmap_single = dma_4v_unmap_single, + .map_page = dma_4v_map_page, + .unmap_page = dma_4v_unmap_page, .map_sg = dma_4v_map_sg, .unmap_sg = dma_4v_unmap_sg, .sync_single_for_cpu = dma_4v_sync_single_for_cpu, diff --git a/arch/sparc/kernel/prom.h b/arch/sparc/kernel/prom.h index bb0f0fda6cab..453397fe5e14 100644 --- a/arch/sparc/kernel/prom.h +++ b/arch/sparc/kernel/prom.h @@ -22,7 +22,6 @@ static inline int is_root_node(const struct device_node *dp) extern char *build_path_component(struct device_node *dp); extern void of_console_init(void); -extern void of_fill_in_cpu_data(void); extern unsigned int prom_early_allocated; diff --git a/arch/sparc/kernel/prom_64.c b/arch/sparc/kernel/prom_64.c index ca55c7012f77..fb06ac2bd38f 100644 --- a/arch/sparc/kernel/prom_64.c +++ b/arch/sparc/kernel/prom_64.c @@ -374,75 +374,26 @@ static const char *get_mid_prop(void) return (tlb_type == spitfire ? "upa-portid" : "portid"); } -struct device_node *of_find_node_by_cpuid(int cpuid) -{ - struct device_node *dp; - const char *mid_prop = get_mid_prop(); - - for_each_node_by_type(dp, "cpu") { - int id = of_getintprop_default(dp, mid_prop, -1); - const char *this_mid_prop = mid_prop; - - if (id < 0) { - this_mid_prop = "cpuid"; - id = of_getintprop_default(dp, this_mid_prop, -1); - } - - if (id < 0) { - prom_printf("OF: Serious problem, cpu lacks " - "%s property", this_mid_prop); - prom_halt(); - } - if (cpuid == id) - return dp; - } - return NULL; -} - -void __init of_fill_in_cpu_data(void) +static void *of_iterate_over_cpus(void *(*func)(struct device_node *, int, int), int arg) { struct device_node *dp; const char *mid_prop; - if (tlb_type == hypervisor) - return; - mid_prop = get_mid_prop(); - ncpus_probed = 0; for_each_node_by_type(dp, "cpu") { int cpuid = of_getintprop_default(dp, mid_prop, -1); const char *this_mid_prop = mid_prop; - struct device_node *portid_parent; - int portid = -1; + void *ret; - portid_parent = NULL; if (cpuid < 0) { this_mid_prop = "cpuid"; cpuid = of_getintprop_default(dp, this_mid_prop, -1); - if (cpuid >= 0) { - int limit = 2; - - portid_parent = dp; - while (limit--) { - portid_parent = portid_parent->parent; - if (!portid_parent) - break; - portid = of_getintprop_default(portid_parent, - "portid", -1); - if (portid >= 0) - break; - } - } } - if (cpuid < 0) { prom_printf("OF: Serious problem, cpu lacks " "%s property", this_mid_prop); prom_halt(); } - - ncpus_probed++; - #ifdef CONFIG_SMP if (cpuid >= NR_CPUS) { printk(KERN_WARNING "Ignoring CPU %d which is " @@ -450,79 +401,142 @@ void __init of_fill_in_cpu_data(void) cpuid, NR_CPUS); continue; } -#else - /* On uniprocessor we only want the values for the - * real physical cpu the kernel booted onto, however - * cpu_data() only has one entry at index 0. - */ - if (cpuid != real_hard_smp_processor_id()) - continue; - cpuid = 0; #endif + ret = func(dp, cpuid, arg); + if (ret) + return ret; + } + return NULL; +} - cpu_data(cpuid).clock_tick = - of_getintprop_default(dp, "clock-frequency", 0); +static void *check_cpu_node(struct device_node *dp, int cpuid, int id) +{ + if (id == cpuid) + return dp; + return NULL; +} - if (portid_parent) { - cpu_data(cpuid).dcache_size = - of_getintprop_default(dp, "l1-dcache-size", - 16 * 1024); - cpu_data(cpuid).dcache_line_size = - of_getintprop_default(dp, "l1-dcache-line-size", - 32); - cpu_data(cpuid).icache_size = - of_getintprop_default(dp, "l1-icache-size", - 8 * 1024); - cpu_data(cpuid).icache_line_size = - of_getintprop_default(dp, "l1-icache-line-size", - 32); - cpu_data(cpuid).ecache_size = - of_getintprop_default(dp, "l2-cache-size", 0); - cpu_data(cpuid).ecache_line_size = - of_getintprop_default(dp, "l2-cache-line-size", 0); - if (!cpu_data(cpuid).ecache_size || - !cpu_data(cpuid).ecache_line_size) { - cpu_data(cpuid).ecache_size = - of_getintprop_default(portid_parent, - "l2-cache-size", - (4 * 1024 * 1024)); - cpu_data(cpuid).ecache_line_size = - of_getintprop_default(portid_parent, - "l2-cache-line-size", 64); - } +struct device_node *of_find_node_by_cpuid(int cpuid) +{ + return of_iterate_over_cpus(check_cpu_node, cpuid); +} - cpu_data(cpuid).core_id = portid + 1; - cpu_data(cpuid).proc_id = portid; +static void *record_one_cpu(struct device_node *dp, int cpuid, int arg) +{ + ncpus_probed++; #ifdef CONFIG_SMP - sparc64_multi_core = 1; + set_cpu_present(cpuid, true); + set_cpu_possible(cpuid, true); #endif - } else { - cpu_data(cpuid).dcache_size = - of_getintprop_default(dp, "dcache-size", 16 * 1024); - cpu_data(cpuid).dcache_line_size = - of_getintprop_default(dp, "dcache-line-size", 32); + return NULL; +} - cpu_data(cpuid).icache_size = - of_getintprop_default(dp, "icache-size", 16 * 1024); - cpu_data(cpuid).icache_line_size = - of_getintprop_default(dp, "icache-line-size", 32); +void __init of_populate_present_mask(void) +{ + if (tlb_type == hypervisor) + return; + ncpus_probed = 0; + of_iterate_over_cpus(record_one_cpu, 0); +} + +static void *fill_in_one_cpu(struct device_node *dp, int cpuid, int arg) +{ + struct device_node *portid_parent = NULL; + int portid = -1; + + if (of_find_property(dp, "cpuid", NULL)) { + int limit = 2; + + portid_parent = dp; + while (limit--) { + portid_parent = portid_parent->parent; + if (!portid_parent) + break; + portid = of_getintprop_default(portid_parent, + "portid", -1); + if (portid >= 0) + break; + } + } + +#ifndef CONFIG_SMP + /* On uniprocessor we only want the values for the + * real physical cpu the kernel booted onto, however + * cpu_data() only has one entry at index 0. + */ + if (cpuid != real_hard_smp_processor_id()) + return NULL; + cpuid = 0; +#endif + + cpu_data(cpuid).clock_tick = + of_getintprop_default(dp, "clock-frequency", 0); + + if (portid_parent) { + cpu_data(cpuid).dcache_size = + of_getintprop_default(dp, "l1-dcache-size", + 16 * 1024); + cpu_data(cpuid).dcache_line_size = + of_getintprop_default(dp, "l1-dcache-line-size", + 32); + cpu_data(cpuid).icache_size = + of_getintprop_default(dp, "l1-icache-size", + 8 * 1024); + cpu_data(cpuid).icache_line_size = + of_getintprop_default(dp, "l1-icache-line-size", + 32); + cpu_data(cpuid).ecache_size = + of_getintprop_default(dp, "l2-cache-size", 0); + cpu_data(cpuid).ecache_line_size = + of_getintprop_default(dp, "l2-cache-line-size", 0); + if (!cpu_data(cpuid).ecache_size || + !cpu_data(cpuid).ecache_line_size) { cpu_data(cpuid).ecache_size = - of_getintprop_default(dp, "ecache-size", + of_getintprop_default(portid_parent, + "l2-cache-size", (4 * 1024 * 1024)); cpu_data(cpuid).ecache_line_size = - of_getintprop_default(dp, "ecache-line-size", 64); - - cpu_data(cpuid).core_id = 0; - cpu_data(cpuid).proc_id = -1; + of_getintprop_default(portid_parent, + "l2-cache-line-size", 64); } + cpu_data(cpuid).core_id = portid + 1; + cpu_data(cpuid).proc_id = portid; #ifdef CONFIG_SMP - set_cpu_present(cpuid, true); - set_cpu_possible(cpuid, true); + sparc64_multi_core = 1; #endif + } else { + cpu_data(cpuid).dcache_size = + of_getintprop_default(dp, "dcache-size", 16 * 1024); + cpu_data(cpuid).dcache_line_size = + of_getintprop_default(dp, "dcache-line-size", 32); + + cpu_data(cpuid).icache_size = + of_getintprop_default(dp, "icache-size", 16 * 1024); + cpu_data(cpuid).icache_line_size = + of_getintprop_default(dp, "icache-line-size", 32); + + cpu_data(cpuid).ecache_size = + of_getintprop_default(dp, "ecache-size", + (4 * 1024 * 1024)); + cpu_data(cpuid).ecache_line_size = + of_getintprop_default(dp, "ecache-line-size", 64); + + cpu_data(cpuid).core_id = 0; + cpu_data(cpuid).proc_id = -1; } + return NULL; +} + +void __init of_fill_in_cpu_data(void) +{ + if (tlb_type == hypervisor) + return; + + of_iterate_over_cpus(fill_in_one_cpu, 0); + smp_fill_in_sib_core_maps(); } diff --git a/arch/sparc/kernel/prom_common.c b/arch/sparc/kernel/prom_common.c index ff7b591c8946..0fb5789d43c8 100644 --- a/arch/sparc/kernel/prom_common.c +++ b/arch/sparc/kernel/prom_common.c @@ -313,6 +313,4 @@ void __init prom_build_devicetree(void) printk("PROM: Built device tree with %u bytes of memory.\n", prom_early_allocated); - - of_fill_in_cpu_data(); } diff --git a/arch/sparc/kernel/smp_64.c b/arch/sparc/kernel/smp_64.c index f7642e5a94db..fa44eaf8d897 100644 --- a/arch/sparc/kernel/smp_64.c +++ b/arch/sparc/kernel/smp_64.c @@ -20,7 +20,8 @@ #include #include #include -#include +#include +#include #include #include @@ -47,6 +48,8 @@ #include #include +#include "cpumap.h" + int sparc64_multi_core __read_mostly; DEFINE_PER_CPU(cpumask_t, cpu_sibling_map) = CPU_MASK_NONE; @@ -278,7 +281,7 @@ static unsigned long kimage_addr_to_ra(void *p) return kern_base + (val - KERNBASE); } -static void __cpuinit ldom_startcpu_cpuid(unsigned int cpu, unsigned long thread_reg) +static void __cpuinit ldom_startcpu_cpuid(unsigned int cpu, unsigned long thread_reg, void **descrp) { extern unsigned long sparc64_ttable_tl0; extern unsigned long kern_locked_tte_data; @@ -298,12 +301,12 @@ static void __cpuinit ldom_startcpu_cpuid(unsigned int cpu, unsigned long thread "hvtramp_descr.\n"); return; } + *descrp = hdesc; hdesc->cpu = cpu; hdesc->num_mappings = num_kernel_image_mappings; tb = &trap_block[cpu]; - tb->hdesc = hdesc; hdesc->fault_info_va = (unsigned long) &tb->fault_info; hdesc->fault_info_pa = kimage_addr_to_ra(&tb->fault_info); @@ -341,12 +344,12 @@ static struct thread_info *cpu_new_thread = NULL; static int __cpuinit smp_boot_one_cpu(unsigned int cpu) { - struct trap_per_cpu *tb = &trap_block[cpu]; unsigned long entry = (unsigned long)(&sparc64_cpu_startup); unsigned long cookie = (unsigned long)(&cpu_new_thread); struct task_struct *p; + void *descr = NULL; int timeout, ret; p = fork_idle(cpu); @@ -359,7 +362,8 @@ static int __cpuinit smp_boot_one_cpu(unsigned int cpu) #if defined(CONFIG_SUN_LDOMS) && defined(CONFIG_HOTPLUG_CPU) if (ldom_domaining_enabled) ldom_startcpu_cpuid(cpu, - (unsigned long) cpu_new_thread); + (unsigned long) cpu_new_thread, + &descr); else #endif prom_startcpu_cpuid(cpu, entry, cookie); @@ -383,10 +387,7 @@ static int __cpuinit smp_boot_one_cpu(unsigned int cpu) } cpu_new_thread = NULL; - if (tb->hdesc) { - kfree(tb->hdesc); - tb->hdesc = NULL; - } + kfree(descr); return ret; } @@ -1315,6 +1316,8 @@ int __cpu_disable(void) cpu_clear(cpu, cpu_online_map); ipi_call_unlock(); + cpu_map_rebuild(); + return 0; } @@ -1373,36 +1376,171 @@ void smp_send_stop(void) { } -unsigned long __per_cpu_base __read_mostly; -unsigned long __per_cpu_shift __read_mostly; - -EXPORT_SYMBOL(__per_cpu_base); -EXPORT_SYMBOL(__per_cpu_shift); - -void __init real_setup_per_cpu_areas(void) +/** + * pcpu_alloc_bootmem - NUMA friendly alloc_bootmem wrapper for percpu + * @cpu: cpu to allocate for + * @size: size allocation in bytes + * @align: alignment + * + * Allocate @size bytes aligned at @align for cpu @cpu. This wrapper + * does the right thing for NUMA regardless of the current + * configuration. + * + * RETURNS: + * Pointer to the allocated area on success, NULL on failure. + */ +static void * __init pcpu_alloc_bootmem(unsigned int cpu, unsigned long size, + unsigned long align) { - unsigned long paddr, goal, size, i; - char *ptr; + const unsigned long goal = __pa(MAX_DMA_ADDRESS); +#ifdef CONFIG_NEED_MULTIPLE_NODES + int node = cpu_to_node(cpu); + void *ptr; - /* Copy section for each CPU (we discard the original) */ - goal = PERCPU_ENOUGH_ROOM; + if (!node_online(node) || !NODE_DATA(node)) { + ptr = __alloc_bootmem(size, align, goal); + pr_info("cpu %d has no node %d or node-local memory\n", + cpu, node); + pr_debug("per cpu data for cpu%d %lu bytes at %016lx\n", + cpu, size, __pa(ptr)); + } else { + ptr = __alloc_bootmem_node(NODE_DATA(node), + size, align, goal); + pr_debug("per cpu data for cpu%d %lu bytes on node%d at " + "%016lx\n", cpu, size, node, __pa(ptr)); + } + return ptr; +#else + return __alloc_bootmem(size, align, goal); +#endif +} - __per_cpu_shift = PAGE_SHIFT; - for (size = PAGE_SIZE; size < goal; size <<= 1UL) - __per_cpu_shift++; +static size_t pcpur_size __initdata; +static void **pcpur_ptrs __initdata; - paddr = lmb_alloc(size * NR_CPUS, PAGE_SIZE); - if (!paddr) { - prom_printf("Cannot allocate per-cpu memory.\n"); - prom_halt(); +static struct page * __init pcpur_get_page(unsigned int cpu, int pageno) +{ + size_t off = (size_t)pageno << PAGE_SHIFT; + + if (off >= pcpur_size) + return NULL; + + return virt_to_page(pcpur_ptrs[cpu] + off); +} + +#define PCPU_CHUNK_SIZE (4UL * 1024UL * 1024UL) + +static void __init pcpu_map_range(unsigned long start, unsigned long end, + struct page *page) +{ + unsigned long pfn = page_to_pfn(page); + unsigned long pte_base; + + BUG_ON((pfn< end) + this_end = end; + + while (start < this_end) { + unsigned long paddr = pfn << PAGE_SHIFT; + + pte_val(*pte) = (paddr | pte_base); + + start += PAGE_SIZE; + pte++; + pfn++; + } + } +} + +void __init setup_per_cpu_areas(void) +{ + size_t dyn_size, static_size = __per_cpu_end - __per_cpu_start; + static struct vm_struct vm; + unsigned long delta, cpu; + size_t pcpu_unit_size; + size_t ptrs_size; + + pcpur_size = PFN_ALIGN(static_size + PERCPU_MODULE_RESERVE + + PERCPU_DYNAMIC_RESERVE); + dyn_size = pcpur_size - static_size - PERCPU_MODULE_RESERVE; + + + ptrs_size = PFN_ALIGN(num_possible_cpus() * sizeof(pcpur_ptrs[0])); + pcpur_ptrs = alloc_bootmem(ptrs_size); + + for_each_possible_cpu(cpu) { + pcpur_ptrs[cpu] = pcpu_alloc_bootmem(cpu, PCPU_CHUNK_SIZE, + PCPU_CHUNK_SIZE); + + free_bootmem(__pa(pcpur_ptrs[cpu] + pcpur_size), + PCPU_CHUNK_SIZE - pcpur_size); + + memcpy(pcpur_ptrs[cpu], __per_cpu_load, static_size); } - ptr = __va(paddr); - __per_cpu_base = ptr - __per_cpu_start; + /* allocate address and map */ + vm.flags = VM_ALLOC; + vm.size = num_possible_cpus() * PCPU_CHUNK_SIZE; + vm_area_register_early(&vm, PCPU_CHUNK_SIZE); - for (i = 0; i < NR_CPUS; i++, ptr += size) - memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start); + for_each_possible_cpu(cpu) { + unsigned long start = (unsigned long) vm.addr; + unsigned long end; + + start += cpu * PCPU_CHUNK_SIZE; + end = start + PCPU_CHUNK_SIZE; + pcpu_map_range(start, end, virt_to_page(pcpur_ptrs[cpu])); + } + + pcpu_unit_size = pcpu_setup_first_chunk(pcpur_get_page, static_size, + PERCPU_MODULE_RESERVE, dyn_size, + PCPU_CHUNK_SIZE, vm.addr, NULL); + + free_bootmem(__pa(pcpur_ptrs), ptrs_size); + + delta = (unsigned long)pcpu_base_addr - (unsigned long)__per_cpu_start; + for_each_possible_cpu(cpu) { + __per_cpu_offset(cpu) = delta + cpu * pcpu_unit_size; + } /* Setup %g5 for the boot cpu. */ __local_per_cpu_offset = __per_cpu_offset(smp_processor_id()); + + of_fill_in_cpu_data(); + if (tlb_type == hypervisor) + mdesc_fill_in_cpu_data(cpu_all_mask); } diff --git a/arch/sparc/kernel/systbls_32.S b/arch/sparc/kernel/systbls_32.S index 00ec3b15f38c..690901657291 100644 --- a/arch/sparc/kernel/systbls_32.S +++ b/arch/sparc/kernel/systbls_32.S @@ -81,4 +81,6 @@ sys_call_table: /*305*/ .long sys_set_mempolicy, sys_kexec_load, sys_move_pages, sys_getcpu, sys_epoll_pwait /*310*/ .long sys_utimensat, sys_signalfd, sys_timerfd_create, sys_eventfd, sys_fallocate /*315*/ .long sys_timerfd_settime, sys_timerfd_gettime, sys_signalfd4, sys_eventfd2, sys_epoll_create1 -/*320*/ .long sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, sys_preadv, sys_pwritev +/*320*/ .long sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, sys_preadv +/*325*/ .long sys_pwritev, sys_rt_tgsigqueueinfo + diff --git a/arch/sparc/kernel/systbls_64.S b/arch/sparc/kernel/systbls_64.S index 82b5bf85b9d2..6b3ee88e253c 100644 --- a/arch/sparc/kernel/systbls_64.S +++ b/arch/sparc/kernel/systbls_64.S @@ -82,7 +82,8 @@ sys_call_table32: .word compat_sys_set_mempolicy, compat_sys_kexec_load, compat_sys_move_pages, sys_getcpu, compat_sys_epoll_pwait /*310*/ .word compat_sys_utimensat, compat_sys_signalfd, sys_timerfd_create, sys_eventfd, compat_sys_fallocate .word compat_sys_timerfd_settime, compat_sys_timerfd_gettime, compat_sys_signalfd4, sys_eventfd2, sys_epoll_create1 -/*320*/ .word sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, compat_sys_preadv, compat_sys_pwritev +/*320*/ .word sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, compat_sys_preadv + .word compat_sys_pwritev, compat_sys_rt_tgsigqueueinfo #endif /* CONFIG_COMPAT */ @@ -156,4 +157,5 @@ sys_call_table: .word sys_set_mempolicy, sys_kexec_load, sys_move_pages, sys_getcpu, sys_epoll_pwait /*310*/ .word sys_utimensat, sys_signalfd, sys_timerfd_create, sys_eventfd, sys_fallocate .word sys_timerfd_settime, sys_timerfd_gettime, sys_signalfd4, sys_eventfd2, sys_epoll_create1 -/*320*/ .word sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, sys_preadv, sys_pwritev +/*320*/ .word sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, sys_preadv + .word sys_pwritev, sys_rt_tgsigqueueinfo diff --git a/arch/sparc/kernel/traps_64.c b/arch/sparc/kernel/traps_64.c index d809c4ebb48f..10f7bb9fc140 100644 --- a/arch/sparc/kernel/traps_64.c +++ b/arch/sparc/kernel/traps_64.c @@ -2509,6 +2509,7 @@ void do_getpsr(struct pt_regs *regs) } struct trap_per_cpu trap_block[NR_CPUS]; +EXPORT_SYMBOL(trap_block); /* This can get invoked before sched_init() so play it super safe * and use hard_smp_processor_id(). @@ -2530,84 +2531,97 @@ extern void tsb_config_offsets_are_bolixed_dave(void); void __init trap_init(void) { /* Compile time sanity check. */ - if (TI_TASK != offsetof(struct thread_info, task) || - TI_FLAGS != offsetof(struct thread_info, flags) || - TI_CPU != offsetof(struct thread_info, cpu) || - TI_FPSAVED != offsetof(struct thread_info, fpsaved) || - TI_KSP != offsetof(struct thread_info, ksp) || - TI_FAULT_ADDR != offsetof(struct thread_info, fault_address) || - TI_KREGS != offsetof(struct thread_info, kregs) || - TI_UTRAPS != offsetof(struct thread_info, utraps) || - TI_EXEC_DOMAIN != offsetof(struct thread_info, exec_domain) || - TI_REG_WINDOW != offsetof(struct thread_info, reg_window) || - TI_RWIN_SPTRS != offsetof(struct thread_info, rwbuf_stkptrs) || - TI_GSR != offsetof(struct thread_info, gsr) || - TI_XFSR != offsetof(struct thread_info, xfsr) || - TI_USER_CNTD0 != offsetof(struct thread_info, user_cntd0) || - TI_USER_CNTD1 != offsetof(struct thread_info, user_cntd1) || - TI_KERN_CNTD0 != offsetof(struct thread_info, kernel_cntd0) || - TI_KERN_CNTD1 != offsetof(struct thread_info, kernel_cntd1) || - TI_PCR != offsetof(struct thread_info, pcr_reg) || - TI_PRE_COUNT != offsetof(struct thread_info, preempt_count) || - TI_NEW_CHILD != offsetof(struct thread_info, new_child) || - TI_SYS_NOERROR != offsetof(struct thread_info, syscall_noerror) || - TI_RESTART_BLOCK != offsetof(struct thread_info, restart_block) || - TI_KUNA_REGS != offsetof(struct thread_info, kern_una_regs) || - TI_KUNA_INSN != offsetof(struct thread_info, kern_una_insn) || - TI_FPREGS != offsetof(struct thread_info, fpregs) || - (TI_FPREGS & (64 - 1))) - thread_info_offsets_are_bolixed_dave(); + BUILD_BUG_ON(TI_TASK != offsetof(struct thread_info, task) || + TI_FLAGS != offsetof(struct thread_info, flags) || + TI_CPU != offsetof(struct thread_info, cpu) || + TI_FPSAVED != offsetof(struct thread_info, fpsaved) || + TI_KSP != offsetof(struct thread_info, ksp) || + TI_FAULT_ADDR != offsetof(struct thread_info, + fault_address) || + TI_KREGS != offsetof(struct thread_info, kregs) || + TI_UTRAPS != offsetof(struct thread_info, utraps) || + TI_EXEC_DOMAIN != offsetof(struct thread_info, + exec_domain) || + TI_REG_WINDOW != offsetof(struct thread_info, + reg_window) || + TI_RWIN_SPTRS != offsetof(struct thread_info, + rwbuf_stkptrs) || + TI_GSR != offsetof(struct thread_info, gsr) || + TI_XFSR != offsetof(struct thread_info, xfsr) || + TI_USER_CNTD0 != offsetof(struct thread_info, + user_cntd0) || + TI_USER_CNTD1 != offsetof(struct thread_info, + user_cntd1) || + TI_KERN_CNTD0 != offsetof(struct thread_info, + kernel_cntd0) || + TI_KERN_CNTD1 != offsetof(struct thread_info, + kernel_cntd1) || + TI_PCR != offsetof(struct thread_info, pcr_reg) || + TI_PRE_COUNT != offsetof(struct thread_info, + preempt_count) || + TI_NEW_CHILD != offsetof(struct thread_info, new_child) || + TI_SYS_NOERROR != offsetof(struct thread_info, + syscall_noerror) || + TI_RESTART_BLOCK != offsetof(struct thread_info, + restart_block) || + TI_KUNA_REGS != offsetof(struct thread_info, + kern_una_regs) || + TI_KUNA_INSN != offsetof(struct thread_info, + kern_una_insn) || + TI_FPREGS != offsetof(struct thread_info, fpregs) || + (TI_FPREGS & (64 - 1))); - if (TRAP_PER_CPU_THREAD != offsetof(struct trap_per_cpu, thread) || - (TRAP_PER_CPU_PGD_PADDR != - offsetof(struct trap_per_cpu, pgd_paddr)) || - (TRAP_PER_CPU_CPU_MONDO_PA != - offsetof(struct trap_per_cpu, cpu_mondo_pa)) || - (TRAP_PER_CPU_DEV_MONDO_PA != - offsetof(struct trap_per_cpu, dev_mondo_pa)) || - (TRAP_PER_CPU_RESUM_MONDO_PA != - offsetof(struct trap_per_cpu, resum_mondo_pa)) || - (TRAP_PER_CPU_RESUM_KBUF_PA != - offsetof(struct trap_per_cpu, resum_kernel_buf_pa)) || - (TRAP_PER_CPU_NONRESUM_MONDO_PA != - offsetof(struct trap_per_cpu, nonresum_mondo_pa)) || - (TRAP_PER_CPU_NONRESUM_KBUF_PA != - offsetof(struct trap_per_cpu, nonresum_kernel_buf_pa)) || - (TRAP_PER_CPU_FAULT_INFO != - offsetof(struct trap_per_cpu, fault_info)) || - (TRAP_PER_CPU_CPU_MONDO_BLOCK_PA != - offsetof(struct trap_per_cpu, cpu_mondo_block_pa)) || - (TRAP_PER_CPU_CPU_LIST_PA != - offsetof(struct trap_per_cpu, cpu_list_pa)) || - (TRAP_PER_CPU_TSB_HUGE != - offsetof(struct trap_per_cpu, tsb_huge)) || - (TRAP_PER_CPU_TSB_HUGE_TEMP != - offsetof(struct trap_per_cpu, tsb_huge_temp)) || - (TRAP_PER_CPU_IRQ_WORKLIST_PA != - offsetof(struct trap_per_cpu, irq_worklist_pa)) || - (TRAP_PER_CPU_CPU_MONDO_QMASK != - offsetof(struct trap_per_cpu, cpu_mondo_qmask)) || - (TRAP_PER_CPU_DEV_MONDO_QMASK != - offsetof(struct trap_per_cpu, dev_mondo_qmask)) || - (TRAP_PER_CPU_RESUM_QMASK != - offsetof(struct trap_per_cpu, resum_qmask)) || - (TRAP_PER_CPU_NONRESUM_QMASK != - offsetof(struct trap_per_cpu, nonresum_qmask))) - trap_per_cpu_offsets_are_bolixed_dave(); + BUILD_BUG_ON(TRAP_PER_CPU_THREAD != offsetof(struct trap_per_cpu, + thread) || + (TRAP_PER_CPU_PGD_PADDR != + offsetof(struct trap_per_cpu, pgd_paddr)) || + (TRAP_PER_CPU_CPU_MONDO_PA != + offsetof(struct trap_per_cpu, cpu_mondo_pa)) || + (TRAP_PER_CPU_DEV_MONDO_PA != + offsetof(struct trap_per_cpu, dev_mondo_pa)) || + (TRAP_PER_CPU_RESUM_MONDO_PA != + offsetof(struct trap_per_cpu, resum_mondo_pa)) || + (TRAP_PER_CPU_RESUM_KBUF_PA != + offsetof(struct trap_per_cpu, resum_kernel_buf_pa)) || + (TRAP_PER_CPU_NONRESUM_MONDO_PA != + offsetof(struct trap_per_cpu, nonresum_mondo_pa)) || + (TRAP_PER_CPU_NONRESUM_KBUF_PA != + offsetof(struct trap_per_cpu, nonresum_kernel_buf_pa)) || + (TRAP_PER_CPU_FAULT_INFO != + offsetof(struct trap_per_cpu, fault_info)) || + (TRAP_PER_CPU_CPU_MONDO_BLOCK_PA != + offsetof(struct trap_per_cpu, cpu_mondo_block_pa)) || + (TRAP_PER_CPU_CPU_LIST_PA != + offsetof(struct trap_per_cpu, cpu_list_pa)) || + (TRAP_PER_CPU_TSB_HUGE != + offsetof(struct trap_per_cpu, tsb_huge)) || + (TRAP_PER_CPU_TSB_HUGE_TEMP != + offsetof(struct trap_per_cpu, tsb_huge_temp)) || + (TRAP_PER_CPU_IRQ_WORKLIST_PA != + offsetof(struct trap_per_cpu, irq_worklist_pa)) || + (TRAP_PER_CPU_CPU_MONDO_QMASK != + offsetof(struct trap_per_cpu, cpu_mondo_qmask)) || + (TRAP_PER_CPU_DEV_MONDO_QMASK != + offsetof(struct trap_per_cpu, dev_mondo_qmask)) || + (TRAP_PER_CPU_RESUM_QMASK != + offsetof(struct trap_per_cpu, resum_qmask)) || + (TRAP_PER_CPU_NONRESUM_QMASK != + offsetof(struct trap_per_cpu, nonresum_qmask)) || + (TRAP_PER_CPU_PER_CPU_BASE != + offsetof(struct trap_per_cpu, __per_cpu_base))); - if ((TSB_CONFIG_TSB != - offsetof(struct tsb_config, tsb)) || - (TSB_CONFIG_RSS_LIMIT != - offsetof(struct tsb_config, tsb_rss_limit)) || - (TSB_CONFIG_NENTRIES != - offsetof(struct tsb_config, tsb_nentries)) || - (TSB_CONFIG_REG_VAL != - offsetof(struct tsb_config, tsb_reg_val)) || - (TSB_CONFIG_MAP_VADDR != - offsetof(struct tsb_config, tsb_map_vaddr)) || - (TSB_CONFIG_MAP_PTE != - offsetof(struct tsb_config, tsb_map_pte))) - tsb_config_offsets_are_bolixed_dave(); + BUILD_BUG_ON((TSB_CONFIG_TSB != + offsetof(struct tsb_config, tsb)) || + (TSB_CONFIG_RSS_LIMIT != + offsetof(struct tsb_config, tsb_rss_limit)) || + (TSB_CONFIG_NENTRIES != + offsetof(struct tsb_config, tsb_nentries)) || + (TSB_CONFIG_REG_VAL != + offsetof(struct tsb_config, tsb_reg_val)) || + (TSB_CONFIG_MAP_VADDR != + offsetof(struct tsb_config, tsb_map_vaddr)) || + (TSB_CONFIG_MAP_PTE != + offsetof(struct tsb_config, tsb_map_pte))); /* Attach to the address space of init_task. On SMP we * do this in smp.c:smp_callin for other cpus. diff --git a/arch/sparc/mm/extable.c b/arch/sparc/mm/extable.c index 16cc28935e39..a61c349448e1 100644 --- a/arch/sparc/mm/extable.c +++ b/arch/sparc/mm/extable.c @@ -28,6 +28,10 @@ search_extable(const struct exception_table_entry *start, * word 3: last insn address + 4 bytes * word 4: fixup code address * + * Deleted entries are encoded as: + * word 1: unused + * word 2: -1 + * * See asm/uaccess.h for more details. */ @@ -39,6 +43,10 @@ search_extable(const struct exception_table_entry *start, continue; } + /* A deleted entry; see trim_init_extable */ + if (walk->fixup == -1) + continue; + if (walk->insn == value) return walk; } @@ -57,6 +65,27 @@ search_extable(const struct exception_table_entry *start, return NULL; } +#ifdef CONFIG_MODULES +/* We could memmove them around; easier to mark the trimmed ones. */ +void trim_init_extable(struct module *m) +{ + unsigned int i; + bool range; + + for (i = 0; i < m->num_exentries; i += range ? 2 : 1) { + range = m->extable[i].fixup == 0; + + if (within_module_init(m->extable[i].insn, m)) { + m->extable[i].fixup = -1; + if (range) + m->extable[i+1].fixup = -1; + } + if (range) + i++; + } +} +#endif /* CONFIG_MODULES */ + /* Special extable search, which handles ranges. Returns fixup */ unsigned long search_extables_range(unsigned long addr, unsigned long *g2) { diff --git a/arch/sparc/mm/fault_32.c b/arch/sparc/mm/fault_32.c index 12e447fc8542..a5e30c642ee3 100644 --- a/arch/sparc/mm/fault_32.c +++ b/arch/sparc/mm/fault_32.c @@ -241,7 +241,7 @@ good_area: * make sure we exit gracefully rather than endlessly redo * the fault. */ - fault = handle_mm_fault(mm, vma, address, write); + fault = handle_mm_fault(mm, vma, address, write ? FAULT_FLAG_WRITE : 0); if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; @@ -484,7 +484,7 @@ good_area: if(!(vma->vm_flags & (VM_READ | VM_EXEC))) goto bad_area; } - switch (handle_mm_fault(mm, vma, address, write)) { + switch (handle_mm_fault(mm, vma, address, write ? FAULT_FLAG_WRITE : 0)) { case VM_FAULT_SIGBUS: case VM_FAULT_OOM: goto do_sigbus; diff --git a/arch/sparc/mm/fault_64.c b/arch/sparc/mm/fault_64.c index 4ab8993b0863..e5620b27c8bf 100644 --- a/arch/sparc/mm/fault_64.c +++ b/arch/sparc/mm/fault_64.c @@ -398,7 +398,7 @@ good_area: goto bad_area; } - fault = handle_mm_fault(mm, vma, address, (fault_code & FAULT_CODE_WRITE)); + fault = handle_mm_fault(mm, vma, address, (fault_code & FAULT_CODE_WRITE) ? FAULT_FLAG_WRITE : 0); if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; diff --git a/arch/sparc/mm/init_32.c b/arch/sparc/mm/init_32.c index cbb282dab5a7..26bb3919ff1f 100644 --- a/arch/sparc/mm/init_32.c +++ b/arch/sparc/mm/init_32.c @@ -358,6 +358,7 @@ void __init paging_init(void) protection_map[15] = PAGE_SHARED; btfixup(); prom_build_devicetree(); + of_fill_in_cpu_data(); device_scan(); } diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c index f26a352c08a0..ed6be6ba2f4e 100644 --- a/arch/sparc/mm/init_64.c +++ b/arch/sparc/mm/init_64.c @@ -1679,11 +1679,6 @@ pgd_t swapper_pg_dir[2048]; static void sun4u_pgprot_init(void); static void sun4v_pgprot_init(void); -/* Dummy function */ -void __init setup_per_cpu_areas(void) -{ -} - void __init paging_init(void) { unsigned long end_pfn, shift, phys_base; @@ -1799,16 +1794,19 @@ void __init paging_init(void) if (tlb_type == hypervisor) sun4v_ktsb_register(); - /* We must setup the per-cpu areas before we pull in the - * PROM and the MDESC. The code there fills in cpu and - * other information into per-cpu data structures. - */ - real_setup_per_cpu_areas(); - prom_build_devicetree(); + of_populate_present_mask(); +#ifndef CONFIG_SMP + of_fill_in_cpu_data(); +#endif - if (tlb_type == hypervisor) + if (tlb_type == hypervisor) { sun4v_mdesc_init(); + mdesc_populate_present_mask(cpu_all_mask); +#ifndef CONFIG_SMP + mdesc_fill_in_cpu_data(cpu_all_mask); +#endif + } /* Once the OF device tree and MDESC have been setup, we know * the list of possible cpus. Therefore we can allocate the diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c index 06c9a7d98206..ade4eb373bdd 100644 --- a/arch/sparc/mm/srmmu.c +++ b/arch/sparc/mm/srmmu.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -349,7 +350,7 @@ static void srmmu_free_nocache(unsigned long vaddr, int size) vaddr, srmmu_nocache_end); BUG(); } - if (size & (size-1)) { + if (!is_power_of_2(size)) { printk("Size 0x%x is not a power of 2\n", size); BUG(); } diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c index 434ba121e3c5..3b44b47c7e1d 100644 --- a/arch/um/drivers/net_kern.c +++ b/arch/um/drivers/net_kern.c @@ -360,7 +360,7 @@ static struct platform_driver uml_net_driver = { static void net_device_release(struct device *dev) { - struct uml_net *device = dev->driver_data; + struct uml_net *device = dev_get_drvdata(dev); struct net_device *netdev = device->dev; struct uml_net_private *lp = netdev_priv(netdev); @@ -440,7 +440,7 @@ static void eth_configure(int n, void *init, char *mac, device->pdev.id = n; device->pdev.name = DRIVER_NAME; device->pdev.dev.release = net_device_release; - device->pdev.dev.driver_data = device; + dev_set_drvdata(&device->pdev.dev, device); if (platform_device_register(&device->pdev)) goto out_free_netdev; SET_NETDEV_DEV(dev,&device->pdev.dev); diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index f934225fd8ef..8f05d4d9da12 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c @@ -451,23 +451,6 @@ static void do_ubd_request(struct request_queue * q); /* Only changed by ubd_init, which is an initcall. */ static int thread_fd = -1; - -static void ubd_end_request(struct request *req, int bytes, int error) -{ - blk_end_request(req, error, bytes); -} - -/* Callable only from interrupt context - otherwise you need to do - * spin_lock_irq()/spin_lock_irqsave() */ -static inline void ubd_finish(struct request *req, int bytes) -{ - if(bytes < 0){ - ubd_end_request(req, 0, -EIO); - return; - } - ubd_end_request(req, bytes, 0); -} - static LIST_HEAD(restart); /* XXX - move this inside ubd_intr. */ @@ -475,7 +458,6 @@ static LIST_HEAD(restart); static void ubd_handler(void) { struct io_thread_req *req; - struct request *rq; struct ubd *ubd; struct list_head *list, *next_ele; unsigned long flags; @@ -492,10 +474,7 @@ static void ubd_handler(void) return; } - rq = req->req; - rq->nr_sectors -= req->length >> 9; - if(rq->nr_sectors == 0) - ubd_finish(rq, rq->hard_nr_sectors << 9); + blk_end_request(req->req, 0, req->length); kfree(req); } reactivate_fd(thread_fd, UBD_IRQ); @@ -799,7 +778,7 @@ static int ubd_open_dev(struct ubd *ubd_dev) static void ubd_device_release(struct device *dev) { - struct ubd *ubd_dev = dev->driver_data; + struct ubd *ubd_dev = dev_get_drvdata(dev); blk_cleanup_queue(ubd_dev->queue); *ubd_dev = ((struct ubd) DEFAULT_UBD); @@ -828,7 +807,7 @@ static int ubd_disk_register(int major, u64 size, int unit, ubd_devs[unit].pdev.id = unit; ubd_devs[unit].pdev.name = DRIVER_NAME; ubd_devs[unit].pdev.dev.release = ubd_device_release; - ubd_devs[unit].pdev.dev.driver_data = &ubd_devs[unit]; + dev_set_drvdata(&ubd_devs[unit].pdev.dev, &ubd_devs[unit]); platform_device_register(&ubd_devs[unit].pdev); disk->driverfs_dev = &ubd_devs[unit].pdev.dev; } @@ -1243,27 +1222,26 @@ static void do_ubd_request(struct request_queue *q) { struct io_thread_req *io_req; struct request *req; - int n, last_sectors; + sector_t sector; + int n; while(1){ struct ubd *dev = q->queuedata; if(dev->end_sg == 0){ - struct request *req = elv_next_request(q); + struct request *req = blk_fetch_request(q); if(req == NULL) return; dev->request = req; - blkdev_dequeue_request(req); dev->start_sg = 0; dev->end_sg = blk_rq_map_sg(q, req, dev->sg); } req = dev->request; - last_sectors = 0; + sector = blk_rq_pos(req); while(dev->start_sg < dev->end_sg){ struct scatterlist *sg = &dev->sg[dev->start_sg]; - req->sector += last_sectors; io_req = kmalloc(sizeof(struct io_thread_req), GFP_ATOMIC); if(io_req == NULL){ @@ -1272,10 +1250,10 @@ static void do_ubd_request(struct request_queue *q) return; } prepare_request(req, io_req, - (unsigned long long) req->sector << 9, + (unsigned long long)sector << 9, sg->offset, sg->length, sg_page(sg)); - last_sectors = sg->length >> 9; + sector += sg->length >> 9; n = os_write_file(thread_fd, &io_req, sizeof(struct io_thread_req *)); if(n != sizeof(struct io_thread_req *)){ diff --git a/arch/um/include/asm/page.h b/arch/um/include/asm/page.h index 55f28a0bae6d..4cc9b6cf480a 100644 --- a/arch/um/include/asm/page.h +++ b/arch/um/include/asm/page.h @@ -116,7 +116,7 @@ extern unsigned long uml_physmem; #define virt_addr_valid(v) pfn_valid(phys_to_pfn(__pa(v))) #include -#include +#include #endif /* __ASSEMBLY__ */ #endif /* __UM_PAGE_H */ diff --git a/arch/um/include/asm/pgtable.h b/arch/um/include/asm/pgtable.h index 58da2480a7f4..9ce3f165111a 100644 --- a/arch/um/include/asm/pgtable.h +++ b/arch/um/include/asm/pgtable.h @@ -53,16 +53,21 @@ extern unsigned long end_iomem; #else # define VMALLOC_END (FIXADDR_START-2*PAGE_SIZE) #endif +#define MODULES_VADDR VMALLOC_START +#define MODULES_END VMALLOC_END +#define MODULES_LEN (MODULES_VADDR - MODULES_END) #define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY) #define _KERNPG_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY) #define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY) - +#define __PAGE_KERNEL_EXEC \ + (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED) #define PAGE_NONE __pgprot(_PAGE_PROTNONE | _PAGE_ACCESSED) #define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED) #define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED) #define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED) #define PAGE_KERNEL __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED) +#define PAGE_KERNEL_EXEC __pgprot(__PAGE_KERNEL_EXEC) /* * The i386 can't do page protection for execute, and considers that the same diff --git a/arch/um/include/asm/suspend.h b/arch/um/include/asm/suspend.h deleted file mode 100644 index f4e8e007f468..000000000000 --- a/arch/um/include/asm/suspend.h +++ /dev/null @@ -1,4 +0,0 @@ -#ifndef __UM_SUSPEND_H -#define __UM_SUSPEND_H - -#endif diff --git a/arch/um/include/shared/init.h b/arch/um/include/shared/init.h index 37dd097c16c0..b3906f860a87 100644 --- a/arch/um/include/shared/init.h +++ b/arch/um/include/shared/init.h @@ -27,7 +27,7 @@ * sign followed by value, e.g.: * * static int init_variable __initdata = 0; - * static char linux_logo[] __initdata = { 0x32, 0x36, ... }; + * static const char linux_logo[] __initconst = { 0x32, 0x36, ... }; * * Don't forget to initialize data not at file scope, i.e. within a function, * as gcc otherwise puts the data into the bss section and not into the init diff --git a/arch/um/include/shared/net_user.h b/arch/um/include/shared/net_user.h index 63bee158cd8e..3dabbe128e40 100644 --- a/arch/um/include/shared/net_user.h +++ b/arch/um/include/shared/net_user.h @@ -8,7 +8,7 @@ #define ETH_ADDR_LEN (6) #define ETH_HEADER_ETHERTAP (16) -#define ETH_HEADER_OTHER (14) +#define ETH_HEADER_OTHER (26) /* 14 for ethernet + VLAN + MPLS for crazy people */ #define ETH_MAX_PACKET (1500) #define UML_NET_VERSION (4) diff --git a/arch/um/kernel/init_task.c b/arch/um/kernel/init_task.c index 806d381947bf..b25121b537d8 100644 --- a/arch/um/kernel/init_task.c +++ b/arch/um/kernel/init_task.c @@ -10,11 +10,8 @@ #include "linux/mqueue.h" #include "asm/uaccess.h" -struct mm_struct init_mm = INIT_MM(init_mm); static struct signal_struct init_signals = INIT_SIGNALS(init_signals); static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); -EXPORT_SYMBOL(init_mm); - /* * Initial task structure. * diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c index 336b61569072..454cdb43e351 100644 --- a/arch/um/kernel/irq.c +++ b/arch/um/kernel/irq.c @@ -358,7 +358,7 @@ EXPORT_SYMBOL(um_request_irq); EXPORT_SYMBOL(reactivate_fd); /* - * hw_interrupt_type must define (startup || enable) && + * irq_chip must define (startup || enable) && * (shutdown || disable) && end */ static void dummy(unsigned int irq) @@ -366,7 +366,7 @@ static void dummy(unsigned int irq) } /* This is used for everything else than the timer. */ -static struct hw_interrupt_type normal_irq_type = { +static struct irq_chip normal_irq_type = { .typename = "SIGIO", .release = free_irq_by_irq_and_dev, .disable = dummy, @@ -375,7 +375,7 @@ static struct hw_interrupt_type normal_irq_type = { .end = dummy }; -static struct hw_interrupt_type SIGVTALRM_irq_type = { +static struct irq_chip SIGVTALRM_irq_type = { .typename = "SIGVTALRM", .release = free_irq_by_irq_and_dev, .shutdown = dummy, /* never called */ diff --git a/arch/um/kernel/trap.c b/arch/um/kernel/trap.c index 7384d8accfe7..637c6505dc00 100644 --- a/arch/um/kernel/trap.c +++ b/arch/um/kernel/trap.c @@ -65,7 +65,7 @@ good_area: do { int fault; - fault = handle_mm_fault(mm, vma, address, is_write); + fault = handle_mm_fault(mm, vma, address, is_write ? FAULT_FLAG_WRITE : 0); if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) { goto out_of_memory; diff --git a/arch/um/sys-i386/Makefile b/arch/um/sys-i386/Makefile index 598b5c1903af..1b549bca4645 100644 --- a/arch/um/sys-i386/Makefile +++ b/arch/um/sys-i386/Makefile @@ -8,7 +8,7 @@ obj-y = bug.o bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \ subarch-obj-y = lib/semaphore_32.o lib/string_32.o subarch-obj-$(CONFIG_HIGHMEM) += mm/highmem_32.o -subarch-obj-$(CONFIG_MODULES) += kernel/module_32.o +subarch-obj-$(CONFIG_MODULES) += kernel/module.o USER_OBJS := bugs.o ptrace_user.o fault.o diff --git a/arch/um/sys-i386/stub.S b/arch/um/sys-i386/stub.S index c41b04bf5fa0..54a36ec20cb7 100644 --- a/arch/um/sys-i386/stub.S +++ b/arch/um/sys-i386/stub.S @@ -1,7 +1,7 @@ #include "as-layout.h" .globl syscall_stub -.section .__syscall_stub, "x" +.section .__syscall_stub, "ax" .globl batch_syscall_stub batch_syscall_stub: diff --git a/arch/um/sys-x86_64/Makefile b/arch/um/sys-x86_64/Makefile index c8b4cce9cfe1..2201e9c20e4a 100644 --- a/arch/um/sys-x86_64/Makefile +++ b/arch/um/sys-x86_64/Makefile @@ -8,10 +8,8 @@ obj-y = bug.o bugs.o delay.o fault.o ldt.o mem.o ptrace.o ptrace_user.o \ setjmp.o signal.o stub.o stub_segv.o syscalls.o syscall_table.o \ sysrq.o ksyms.o tls.o -obj-$(CONFIG_MODULES) += um_module.o - subarch-obj-y = lib/csum-partial_64.o lib/memcpy_64.o lib/thunk_64.o -subarch-obj-$(CONFIG_MODULES) += kernel/module_64.o +subarch-obj-$(CONFIG_MODULES) += kernel/module.o ldt-y = ../sys-i386/ldt.o diff --git a/arch/um/sys-x86_64/asm/elf.h b/arch/um/sys-x86_64/asm/elf.h index 6e8a9195e952..04b9e87c8dad 100644 --- a/arch/um/sys-x86_64/asm/elf.h +++ b/arch/um/sys-x86_64/asm/elf.h @@ -66,28 +66,28 @@ typedef struct user_i387_struct elf_fpregset_t; PT_REGS_R15(regs) = 0; \ } while (0) -#define ELF_CORE_COPY_REGS(pr_reg, regs) \ - (pr_reg)[0] = (regs)->regs.gp[0]; \ - (pr_reg)[1] = (regs)->regs.gp[1]; \ - (pr_reg)[2] = (regs)->regs.gp[2]; \ - (pr_reg)[3] = (regs)->regs.gp[3]; \ - (pr_reg)[4] = (regs)->regs.gp[4]; \ - (pr_reg)[5] = (regs)->regs.gp[5]; \ - (pr_reg)[6] = (regs)->regs.gp[6]; \ - (pr_reg)[7] = (regs)->regs.gp[7]; \ - (pr_reg)[8] = (regs)->regs.gp[8]; \ - (pr_reg)[9] = (regs)->regs.gp[9]; \ - (pr_reg)[10] = (regs)->regs.gp[10]; \ - (pr_reg)[11] = (regs)->regs.gp[11]; \ - (pr_reg)[12] = (regs)->regs.gp[12]; \ - (pr_reg)[13] = (regs)->regs.gp[13]; \ - (pr_reg)[14] = (regs)->regs.gp[14]; \ - (pr_reg)[15] = (regs)->regs.gp[15]; \ - (pr_reg)[16] = (regs)->regs.gp[16]; \ - (pr_reg)[17] = (regs)->regs.gp[17]; \ - (pr_reg)[18] = (regs)->regs.gp[18]; \ - (pr_reg)[19] = (regs)->regs.gp[19]; \ - (pr_reg)[20] = (regs)->regs.gp[20]; \ +#define ELF_CORE_COPY_REGS(pr_reg, _regs) \ + (pr_reg)[0] = (_regs)->regs.gp[0]; \ + (pr_reg)[1] = (_regs)->regs.gp[1]; \ + (pr_reg)[2] = (_regs)->regs.gp[2]; \ + (pr_reg)[3] = (_regs)->regs.gp[3]; \ + (pr_reg)[4] = (_regs)->regs.gp[4]; \ + (pr_reg)[5] = (_regs)->regs.gp[5]; \ + (pr_reg)[6] = (_regs)->regs.gp[6]; \ + (pr_reg)[7] = (_regs)->regs.gp[7]; \ + (pr_reg)[8] = (_regs)->regs.gp[8]; \ + (pr_reg)[9] = (_regs)->regs.gp[9]; \ + (pr_reg)[10] = (_regs)->regs.gp[10]; \ + (pr_reg)[11] = (_regs)->regs.gp[11]; \ + (pr_reg)[12] = (_regs)->regs.gp[12]; \ + (pr_reg)[13] = (_regs)->regs.gp[13]; \ + (pr_reg)[14] = (_regs)->regs.gp[14]; \ + (pr_reg)[15] = (_regs)->regs.gp[15]; \ + (pr_reg)[16] = (_regs)->regs.gp[16]; \ + (pr_reg)[17] = (_regs)->regs.gp[17]; \ + (pr_reg)[18] = (_regs)->regs.gp[18]; \ + (pr_reg)[19] = (_regs)->regs.gp[19]; \ + (pr_reg)[20] = (_regs)->regs.gp[20]; \ (pr_reg)[21] = current->thread.arch.fs; \ (pr_reg)[22] = 0; \ (pr_reg)[23] = 0; \ diff --git a/arch/um/sys-x86_64/stub.S b/arch/um/sys-x86_64/stub.S index 6d9edf9fabce..20e4a96a6dcb 100644 --- a/arch/um/sys-x86_64/stub.S +++ b/arch/um/sys-x86_64/stub.S @@ -1,7 +1,7 @@ #include "as-layout.h" .globl syscall_stub -.section .__syscall_stub, "x" +.section .__syscall_stub, "ax" syscall_stub: syscall /* We don't have 64-bit constants, so this constructs the address diff --git a/arch/um/sys-x86_64/um_module.c b/arch/um/sys-x86_64/um_module.c deleted file mode 100644 index 3dead392a415..000000000000 --- a/arch/um/sys-x86_64/um_module.c +++ /dev/null @@ -1,21 +0,0 @@ -#include -#include - -/* Copied from i386 arch/i386/kernel/module.c */ -void *module_alloc(unsigned long size) -{ - if (size == 0) - return NULL; - return vmalloc_exec(size); -} - -/* Free memory returned from module_alloc */ -void module_free(struct module *mod, void *module_region) -{ - vfree(module_region); - /* - * FIXME: If module_region == mod->init_region, trim exception - * table entries. - */ -} - diff --git a/arch/x86/Kbuild b/arch/x86/Kbuild new file mode 100644 index 000000000000..ad8ec356fb36 --- /dev/null +++ b/arch/x86/Kbuild @@ -0,0 +1,16 @@ + +obj-$(CONFIG_KVM) += kvm/ + +# Xen paravirtualization support +obj-$(CONFIG_XEN) += xen/ + +# lguest paravirtualization support +obj-$(CONFIG_LGUEST_GUEST) += lguest/ + +obj-y += kernel/ +obj-y += mm/ + +obj-y += crypto/ +obj-y += vdso/ +obj-$(CONFIG_IA32_EMULATION) += ia32/ + diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index a6efe0a2e9ae..d1430ef6b4f9 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -28,11 +28,13 @@ config X86 select HAVE_KPROBES select ARCH_WANT_OPTIONAL_GPIOLIB select ARCH_WANT_FRAME_POINTERS + select HAVE_DMA_ATTRS select HAVE_KRETPROBES select HAVE_FTRACE_MCOUNT_RECORD select HAVE_DYNAMIC_FTRACE select HAVE_FUNCTION_TRACER select HAVE_FUNCTION_GRAPH_TRACER + select HAVE_FUNCTION_GRAPH_FP_TEST select HAVE_FUNCTION_TRACE_MCOUNT_TEST select HAVE_FTRACE_NMI_ENTER if DYNAMIC_FTRACE select HAVE_FTRACE_SYSCALLS @@ -46,6 +48,12 @@ config X86 select HAVE_KERNEL_GZIP select HAVE_KERNEL_BZIP2 select HAVE_KERNEL_LZMA + select HAVE_ARCH_KMEMCHECK + +config OUTPUT_FORMAT + string + default "elf32-i386" if X86_32 + default "elf64-x86-64" if X86_64 config ARCH_DEFCONFIG string @@ -274,15 +282,9 @@ config SPARSE_IRQ If you don't know what to do here, say N. -config NUMA_MIGRATE_IRQ_DESC - bool "Move irq desc when changing irq smp_affinity" +config NUMA_IRQ_DESC + def_bool y depends on SPARSE_IRQ && NUMA - depends on BROKEN - default n - ---help--- - This enables moving irq_desc to cpu/node that irq will use handled. - - If you don't know what to do here, say N. config X86_MPPARSE bool "Enable MPS table" if ACPI @@ -355,7 +357,7 @@ config X86_UV depends on X86_64 depends on X86_EXTENDED_PLATFORM depends on NUMA - select X86_X2APIC + depends on X86_X2APIC ---help--- This option is needed in order to support SGI Ultraviolet systems. If you don't have one of these, you should say N here. @@ -740,6 +742,7 @@ config X86_UP_IOAPIC config X86_LOCAL_APIC def_bool y depends on X86_64 || SMP || X86_32_NON_STANDARD || X86_UP_APIC + select HAVE_PERF_COUNTERS if (!M386 && !M486) config X86_IO_APIC def_bool y @@ -789,10 +792,26 @@ config X86_MCE to disable it. MCE support simply ignores non-MCE processors like the 386 and 486, so nearly everyone can say Y here. +config X86_OLD_MCE + depends on X86_32 && X86_MCE + bool "Use legacy machine check code (will go away)" + default n + select X86_ANCIENT_MCE + ---help--- + Use the old i386 machine check code. This is merely intended for + testing in a transition period. Try this if you run into any machine + check related software problems, but report the problem to + linux-kernel. When in doubt say no. + +config X86_NEW_MCE + depends on X86_MCE + bool + default y if (!X86_OLD_MCE && X86_32) || X86_64 + config X86_MCE_INTEL def_bool y prompt "Intel MCE features" - depends on X86_64 && X86_MCE && X86_LOCAL_APIC + depends on X86_NEW_MCE && X86_LOCAL_APIC ---help--- Additional support for intel specific MCE features such as the thermal monitor. @@ -800,19 +819,36 @@ config X86_MCE_INTEL config X86_MCE_AMD def_bool y prompt "AMD MCE features" - depends on X86_64 && X86_MCE && X86_LOCAL_APIC + depends on X86_NEW_MCE && X86_LOCAL_APIC ---help--- Additional support for AMD specific MCE features such as the DRAM Error Threshold. +config X86_ANCIENT_MCE + def_bool n + depends on X86_32 + prompt "Support for old Pentium 5 / WinChip machine checks" + ---help--- + Include support for machine check handling on old Pentium 5 or WinChip + systems. These typically need to be enabled explicitely on the command + line. + config X86_MCE_THRESHOLD depends on X86_MCE_AMD || X86_MCE_INTEL bool default y +config X86_MCE_INJECT + depends on X86_NEW_MCE + tristate "Machine check injector support" + ---help--- + Provide support for injecting machine checks for testing purposes. + If you don't know what a machine check is and you don't do kernel + QA it is safe to say n. + config X86_MCE_NONFATAL tristate "Check for non-fatal errors on AMD Athlon/Duron / Intel Pentium 4" - depends on X86_32 && X86_MCE + depends on X86_OLD_MCE ---help--- Enabling this feature starts a timer that triggers every 5 seconds which will look at the machine check registers to see if anything happened. @@ -825,11 +861,15 @@ config X86_MCE_NONFATAL config X86_MCE_P4THERMAL bool "check for P4 thermal throttling interrupt." - depends on X86_32 && X86_MCE && (X86_UP_APIC || SMP) + depends on X86_OLD_MCE && X86_MCE && (X86_UP_APIC || SMP) ---help--- Enabling this feature will cause a message to be printed when the P4 enters thermal throttling. +config X86_THERMAL_VECTOR + def_bool y + depends on X86_MCE_P4THERMAL || X86_MCE_INTEL + config VM86 bool "Enable VM86 support" if EMBEDDED default y @@ -1466,9 +1506,7 @@ config KEXEC_JUMP config PHYSICAL_START hex "Physical address where the kernel is loaded" if (EMBEDDED || CRASH_DUMP) - default "0x1000000" if X86_NUMAQ - default "0x200000" if X86_64 - default "0x100000" + default "0x1000000" ---help--- This gives the physical address where the kernel is loaded. @@ -1487,15 +1525,15 @@ config PHYSICAL_START to be specifically compiled to run from a specific memory area (normally a reserved region) and this option comes handy. - So if you are using bzImage for capturing the crash dump, leave - the value here unchanged to 0x100000 and set CONFIG_RELOCATABLE=y. - Otherwise if you plan to use vmlinux for capturing the crash dump - change this value to start of the reserved region (Typically 16MB - 0x1000000). In other words, it can be set based on the "X" value as - specified in the "crashkernel=YM@XM" command line boot parameter - passed to the panic-ed kernel. Typically this parameter is set as - crashkernel=64M@16M. Please take a look at - Documentation/kdump/kdump.txt for more details about crash dumps. + So if you are using bzImage for capturing the crash dump, + leave the value here unchanged to 0x1000000 and set + CONFIG_RELOCATABLE=y. Otherwise if you plan to use vmlinux + for capturing the crash dump change this value to start of + the reserved region. In other words, it can be set based on + the "X" value as specified in the "crashkernel=YM@XM" + command line boot parameter passed to the panic-ed + kernel. Please take a look at Documentation/kdump/kdump.txt + for more details about crash dumps. Usage of bzImage for capturing the crash dump is recommended as one does not have to build two kernels. Same kernel can be used @@ -1508,8 +1546,8 @@ config PHYSICAL_START Don't change this unless you know what you are doing. config RELOCATABLE - bool "Build a relocatable kernel (EXPERIMENTAL)" - depends on EXPERIMENTAL + bool "Build a relocatable kernel" + default y ---help--- This builds a kernel image that retains relocation information so it can be loaded someplace besides the default 1MB. @@ -1524,12 +1562,16 @@ config RELOCATABLE it has been loaded at and the compile time physical address (CONFIG_PHYSICAL_START) is ignored. +# Relocation on x86-32 needs some additional build support +config X86_NEED_RELOCS + def_bool y + depends on X86_32 && RELOCATABLE + config PHYSICAL_ALIGN hex prompt "Alignment value to which kernel should be aligned" if X86_32 - default "0x100000" if X86_32 - default "0x200000" if X86_64 - range 0x2000 0x400000 + default "0x1000000" + range 0x2000 0x1000000 ---help--- This value puts the alignment restrictions on physical address where kernel is loaded and run from. Kernel is compiled for an diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug index d8359e73317f..d105f29bb6bb 100644 --- a/arch/x86/Kconfig.debug +++ b/arch/x86/Kconfig.debug @@ -159,14 +159,30 @@ config IOMMU_DEBUG options. See Documentation/x86_64/boot-options.txt for more details. +config IOMMU_STRESS + bool "Enable IOMMU stress-test mode" + ---help--- + This option disables various optimizations in IOMMU related + code to do real stress testing of the IOMMU code. This option + will cause a performance drop and should only be enabled for + testing. + config IOMMU_LEAK bool "IOMMU leak tracing" - depends on DEBUG_KERNEL - depends on IOMMU_DEBUG + depends on IOMMU_DEBUG && DMA_API_DEBUG ---help--- Add a simple leak tracer to the IOMMU code. This is useful when you are debugging a buggy device driver that leaks IOMMU mappings. +config X86_DS_SELFTEST + bool "DS selftest" + default y + depends on DEBUG_KERNEL + depends on X86_DS + ---help--- + Perform Debug Store selftests at boot time. + If in doubt, say "N". + config HAVE_MMIOTRACE_SUPPORT def_bool y diff --git a/arch/x86/Makefile b/arch/x86/Makefile index 8c86b72afdc2..1b68659c41b4 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -7,8 +7,6 @@ else KBUILD_DEFCONFIG := $(ARCH)_defconfig endif -core-$(CONFIG_KVM) += arch/x86/kvm/ - # BITS is used as extension for files which are available in a 32 bit # and a 64 bit version to simplify shared Makefiles. # e.g.: obj-y += foo_$(BITS).o @@ -83,6 +81,11 @@ ifdef CONFIG_CC_STACKPROTECTOR endif endif +# Don't unroll struct assignments with kmemcheck enabled +ifeq ($(CONFIG_KMEMCHECK),y) + KBUILD_CFLAGS += $(call cc-option,-fno-builtin-memcpy) +endif + # Stackpointer is addressed different for 32 bit and 64 bit x86 sp-$(CONFIG_X86_32) := esp sp-$(CONFIG_X86_64) := rsp @@ -118,21 +121,8 @@ head-y += arch/x86/kernel/init_task.o libs-y += arch/x86/lib/ -# Sub architecture files that needs linking first -core-y += $(fcore-y) - -# Xen paravirtualization support -core-$(CONFIG_XEN) += arch/x86/xen/ - -# lguest paravirtualization support -core-$(CONFIG_LGUEST_GUEST) += arch/x86/lguest/ - -core-y += arch/x86/kernel/ -core-y += arch/x86/mm/ - -core-y += arch/x86/crypto/ -core-y += arch/x86/vdso/ -core-$(CONFIG_IA32_EMULATION) += arch/x86/ia32/ +# See arch/x86/Kbuild for content of core part of the kernel +core-y += arch/x86/ # drivers-y are linked after core-y drivers-$(CONFIG_MATH_EMULATION) += arch/x86/math-emu/ diff --git a/arch/x86/boot/.gitignore b/arch/x86/boot/.gitignore index 172cf8a98bdd..851fe936d242 100644 --- a/arch/x86/boot/.gitignore +++ b/arch/x86/boot/.gitignore @@ -3,6 +3,8 @@ bzImage cpustr.h mkcpustr offsets.h +voffset.h +zoffset.h setup setup.bin setup.elf diff --git a/arch/x86/boot/Makefile b/arch/x86/boot/Makefile index 6633b6e7505a..ec749c2bfdd7 100644 --- a/arch/x86/boot/Makefile +++ b/arch/x86/boot/Makefile @@ -26,9 +26,10 @@ targets := vmlinux.bin setup.bin setup.elf bzImage targets += fdimage fdimage144 fdimage288 image.iso mtools.conf subdir- := compressed -setup-y += a20.o cmdline.o copy.o cpu.o cpucheck.o edd.o +setup-y += a20.o bioscall.o cmdline.o copy.o cpu.o cpucheck.o edd.o setup-y += header.o main.o mca.o memory.o pm.o pmjump.o -setup-y += printf.o string.o tty.o video.o video-mode.o version.o +setup-y += printf.o regs.o string.o tty.o video.o video-mode.o +setup-y += version.o setup-$(CONFIG_X86_APM_BOOT) += apm.o # The link order of the video-*.o modules can matter. In particular, @@ -69,6 +70,7 @@ KBUILD_CFLAGS := $(LINUXINCLUDE) -g -Os -D_SETUP -D__KERNEL__ \ $(call cc-option, -mpreferred-stack-boundary=2) KBUILD_CFLAGS += $(call cc-option, -m32) KBUILD_AFLAGS := $(KBUILD_CFLAGS) -D__ASSEMBLY__ +GCOV_PROFILE := n $(obj)/bzImage: asflags-y := $(SVGA_MODE) @@ -86,19 +88,27 @@ $(obj)/vmlinux.bin: $(obj)/compressed/vmlinux FORCE SETUP_OBJS = $(addprefix $(obj)/,$(setup-y)) -sed-offsets := -e 's/^00*/0/' \ - -e 's/^\([0-9a-fA-F]*\) . \(input_data\|input_data_end\)$$/\#define \2 0x\1/p' +sed-voffset := -e 's/^\([0-9a-fA-F]*\) . \(_text\|_end\)$$/\#define VO_\2 0x\1/p' -quiet_cmd_offsets = OFFSETS $@ - cmd_offsets = $(NM) $< | sed -n $(sed-offsets) > $@ +quiet_cmd_voffset = VOFFSET $@ + cmd_voffset = $(NM) $< | sed -n $(sed-voffset) > $@ -$(obj)/offsets.h: $(obj)/compressed/vmlinux FORCE - $(call if_changed,offsets) +targets += voffset.h +$(obj)/voffset.h: vmlinux FORCE + $(call if_changed,voffset) + +sed-zoffset := -e 's/^\([0-9a-fA-F]*\) . \(startup_32\|input_data\|_end\|z_.*\)$$/\#define ZO_\2 0x\1/p' + +quiet_cmd_zoffset = ZOFFSET $@ + cmd_zoffset = $(NM) $< | sed -n $(sed-zoffset) > $@ + +targets += zoffset.h +$(obj)/zoffset.h: $(obj)/compressed/vmlinux FORCE + $(call if_changed,zoffset) -targets += offsets.h AFLAGS_header.o += -I$(obj) -$(obj)/header.o: $(obj)/offsets.h +$(obj)/header.o: $(obj)/voffset.h $(obj)/zoffset.h LDFLAGS_setup.elf := -T $(obj)/setup.elf: $(src)/setup.ld $(SETUP_OBJS) FORCE diff --git a/arch/x86/boot/a20.c b/arch/x86/boot/a20.c index 7c19ce8c2442..64a31a6d751a 100644 --- a/arch/x86/boot/a20.c +++ b/arch/x86/boot/a20.c @@ -2,7 +2,7 @@ * * Copyright (C) 1991, 1992 Linus Torvalds * Copyright 2007-2008 rPath, Inc. - All Rights Reserved - * Copyright 2009 Intel Corporation + * Copyright 2009 Intel Corporation; author H. Peter Anvin * * This file is part of the Linux kernel, and is made available under * the terms of the GNU General Public License version 2. @@ -90,8 +90,11 @@ static int a20_test_long(void) static void enable_a20_bios(void) { - asm volatile("pushfl; int $0x15; popfl" - : : "a" ((u16)0x2401)); + struct biosregs ireg; + + initregs(&ireg); + ireg.ax = 0x2401; + intcall(0x15, &ireg, NULL); } static void enable_a20_kbc(void) diff --git a/arch/x86/boot/apm.c b/arch/x86/boot/apm.c index 7aa6033001f9..ee274834ea8b 100644 --- a/arch/x86/boot/apm.c +++ b/arch/x86/boot/apm.c @@ -2,6 +2,7 @@ * * Copyright (C) 1991, 1992 Linus Torvalds * Copyright 2007 rPath, Inc. - All Rights Reserved + * Copyright 2009 Intel Corporation; author H. Peter Anvin * * Original APM BIOS checking by Stephen Rothwell, May 1994 * (sfr@canb.auug.org.au) @@ -19,75 +20,56 @@ int query_apm_bios(void) { - u16 ax, bx, cx, dx, di; - u32 ebx, esi; - u8 err; + struct biosregs ireg, oreg; /* APM BIOS installation check */ - ax = 0x5300; - bx = cx = 0; - asm volatile("pushl %%ebp ; int $0x15 ; popl %%ebp ; setc %0" - : "=d" (err), "+a" (ax), "+b" (bx), "+c" (cx) - : : "esi", "edi"); + initregs(&ireg); + ireg.ah = 0x53; + intcall(0x15, &ireg, &oreg); - if (err) + if (oreg.flags & X86_EFLAGS_CF) return -1; /* No APM BIOS */ - if (bx != 0x504d) /* "PM" signature */ + if (oreg.bx != 0x504d) /* "PM" signature */ return -1; - if (!(cx & 0x02)) /* 32 bits supported? */ + if (!(oreg.cx & 0x02)) /* 32 bits supported? */ return -1; /* Disconnect first, just in case */ - ax = 0x5304; - bx = 0; - asm volatile("pushl %%ebp ; int $0x15 ; popl %%ebp" - : "+a" (ax), "+b" (bx) - : : "ecx", "edx", "esi", "edi"); - - /* Paranoia */ - ebx = esi = 0; - cx = dx = di = 0; + ireg.al = 0x04; + intcall(0x15, &ireg, NULL); /* 32-bit connect */ - asm volatile("pushl %%ebp ; int $0x15 ; popl %%ebp ; setc %6" - : "=a" (ax), "+b" (ebx), "+c" (cx), "+d" (dx), - "+S" (esi), "+D" (di), "=m" (err) - : "a" (0x5303)); + ireg.al = 0x03; + intcall(0x15, &ireg, &oreg); - boot_params.apm_bios_info.cseg = ax; - boot_params.apm_bios_info.offset = ebx; - boot_params.apm_bios_info.cseg_16 = cx; - boot_params.apm_bios_info.dseg = dx; - boot_params.apm_bios_info.cseg_len = (u16)esi; - boot_params.apm_bios_info.cseg_16_len = esi >> 16; - boot_params.apm_bios_info.dseg_len = di; + boot_params.apm_bios_info.cseg = oreg.ax; + boot_params.apm_bios_info.offset = oreg.ebx; + boot_params.apm_bios_info.cseg_16 = oreg.cx; + boot_params.apm_bios_info.dseg = oreg.dx; + boot_params.apm_bios_info.cseg_len = oreg.si; + boot_params.apm_bios_info.cseg_16_len = oreg.hsi; + boot_params.apm_bios_info.dseg_len = oreg.di; - if (err) + if (oreg.flags & X86_EFLAGS_CF) return -1; /* Redo the installation check as the 32-bit connect; some BIOSes return different flags this way... */ - ax = 0x5300; - bx = cx = 0; - asm volatile("pushl %%ebp ; int $0x15 ; popl %%ebp ; setc %0" - : "=d" (err), "+a" (ax), "+b" (bx), "+c" (cx) - : : "esi", "edi"); + ireg.al = 0x00; + intcall(0x15, &ireg, &oreg); - if (err || bx != 0x504d) { + if ((oreg.eflags & X86_EFLAGS_CF) || oreg.bx != 0x504d) { /* Failure with 32-bit connect, try to disconect and ignore */ - ax = 0x5304; - bx = 0; - asm volatile("pushl %%ebp ; int $0x15 ; popl %%ebp" - : "+a" (ax), "+b" (bx) - : : "ecx", "edx", "esi", "edi"); + ireg.al = 0x04; + intcall(0x15, &ireg, NULL); return -1; } - boot_params.apm_bios_info.version = ax; - boot_params.apm_bios_info.flags = cx; + boot_params.apm_bios_info.version = oreg.ax; + boot_params.apm_bios_info.flags = oreg.cx; return 0; } diff --git a/arch/x86/boot/bioscall.S b/arch/x86/boot/bioscall.S new file mode 100644 index 000000000000..1dfbf64e52a2 --- /dev/null +++ b/arch/x86/boot/bioscall.S @@ -0,0 +1,82 @@ +/* ----------------------------------------------------------------------- + * + * Copyright 2009 Intel Corporation; author H. Peter Anvin + * + * This file is part of the Linux kernel, and is made available under + * the terms of the GNU General Public License version 2 or (at your + * option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * "Glove box" for BIOS calls. Avoids the constant problems with BIOSes + * touching registers they shouldn't be. + */ + + .code16gcc + .text + .globl intcall + .type intcall, @function +intcall: + /* Self-modify the INT instruction. Ugly, but works. */ + cmpb %al, 3f + je 1f + movb %al, 3f + jmp 1f /* Synchronize pipeline */ +1: + /* Save state */ + pushfl + pushw %fs + pushw %gs + pushal + + /* Copy input state to stack frame */ + subw $44, %sp + movw %dx, %si + movw %sp, %di + movw $11, %cx + rep; movsd + + /* Pop full state from the stack */ + popal + popw %gs + popw %fs + popw %es + popw %ds + popfl + + /* Actual INT */ + .byte 0xcd /* INT opcode */ +3: .byte 0 + + /* Push full state to the stack */ + pushfl + pushw %ds + pushw %es + pushw %fs + pushw %gs + pushal + + /* Re-establish C environment invariants */ + cld + movzwl %sp, %esp + movw %cs, %ax + movw %ax, %ds + movw %ax, %es + + /* Copy output state from stack frame */ + movw 68(%esp), %di /* Original %cx == 3rd argument */ + andw %di, %di + jz 4f + movw %sp, %si + movw $11, %cx + rep; movsd +4: addw $44, %sp + + /* Restore state and return */ + popal + popw %gs + popw %fs + popfl + retl + .size intcall, .-intcall diff --git a/arch/x86/boot/boot.h b/arch/x86/boot/boot.h index 7b2692e897e5..98239d2658f2 100644 --- a/arch/x86/boot/boot.h +++ b/arch/x86/boot/boot.h @@ -2,6 +2,7 @@ * * Copyright (C) 1991, 1992 Linus Torvalds * Copyright 2007 rPath, Inc. - All Rights Reserved + * Copyright 2009 Intel Corporation; author H. Peter Anvin * * This file is part of the Linux kernel, and is made available under * the terms of the GNU General Public License version 2. @@ -26,6 +27,7 @@ #include #include "bitops.h" #include +#include /* Useful macros */ #define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)])) @@ -241,6 +243,49 @@ int enable_a20(void); /* apm.c */ int query_apm_bios(void); +/* bioscall.c */ +struct biosregs { + union { + struct { + u32 edi; + u32 esi; + u32 ebp; + u32 _esp; + u32 ebx; + u32 edx; + u32 ecx; + u32 eax; + u32 _fsgs; + u32 _dses; + u32 eflags; + }; + struct { + u16 di, hdi; + u16 si, hsi; + u16 bp, hbp; + u16 _sp, _hsp; + u16 bx, hbx; + u16 dx, hdx; + u16 cx, hcx; + u16 ax, hax; + u16 gs, fs; + u16 es, ds; + u16 flags, hflags; + }; + struct { + u8 dil, dih, edi2, edi3; + u8 sil, sih, esi2, esi3; + u8 bpl, bph, ebp2, ebp3; + u8 _spl, _sph, _esp2, _esp3; + u8 bl, bh, ebx2, ebx3; + u8 dl, dh, edx2, edx3; + u8 cl, ch, ecx2, ecx3; + u8 al, ah, eax2, eax3; + }; + }; +}; +void intcall(u8 int_no, const struct biosregs *ireg, struct biosregs *oreg); + /* cmdline.c */ int cmdline_find_option(const char *option, char *buffer, int bufsize); int cmdline_find_option_bool(const char *option); @@ -279,6 +324,9 @@ int sprintf(char *buf, const char *fmt, ...); int vsprintf(char *buf, const char *fmt, va_list args); int printf(const char *fmt, ...); +/* regs.c */ +void initregs(struct biosregs *regs); + /* string.c */ int strcmp(const char *str1, const char *str2); size_t strnlen(const char *s, size_t maxlen); diff --git a/arch/x86/boot/compressed/.gitignore b/arch/x86/boot/compressed/.gitignore index 63eff3b04d01..4a46fab7162e 100644 --- a/arch/x86/boot/compressed/.gitignore +++ b/arch/x86/boot/compressed/.gitignore @@ -1,3 +1,6 @@ relocs vmlinux.bin.all vmlinux.relocs +vmlinux.lds +mkpiggy +piggy.S diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile index 65551c9f8571..e2ff504b4ddc 100644 --- a/arch/x86/boot/compressed/Makefile +++ b/arch/x86/boot/compressed/Makefile @@ -15,11 +15,14 @@ KBUILD_CFLAGS += $(call cc-option,-ffreestanding) KBUILD_CFLAGS += $(call cc-option,-fno-stack-protector) KBUILD_AFLAGS := $(KBUILD_CFLAGS) -D__ASSEMBLY__ +GCOV_PROFILE := n LDFLAGS := -m elf_$(UTS_MACHINE) LDFLAGS_vmlinux := -T -$(obj)/vmlinux: $(src)/vmlinux_$(BITS).lds $(obj)/head_$(BITS).o $(obj)/misc.o $(obj)/piggy.o FORCE +hostprogs-y := mkpiggy + +$(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/head_$(BITS).o $(obj)/misc.o $(obj)/piggy.o FORCE $(call if_changed,ld) @: @@ -29,7 +32,7 @@ $(obj)/vmlinux.bin: vmlinux FORCE targets += vmlinux.bin.all vmlinux.relocs relocs -hostprogs-$(CONFIG_X86_32) += relocs +hostprogs-$(CONFIG_X86_NEED_RELOCS) += relocs quiet_cmd_relocs = RELOCS $@ cmd_relocs = $(obj)/relocs $< > $@;$(obj)/relocs --abs-relocs $< @@ -37,46 +40,22 @@ $(obj)/vmlinux.relocs: vmlinux $(obj)/relocs FORCE $(call if_changed,relocs) vmlinux.bin.all-y := $(obj)/vmlinux.bin -vmlinux.bin.all-$(CONFIG_RELOCATABLE) += $(obj)/vmlinux.relocs -quiet_cmd_relocbin = BUILD $@ - cmd_relocbin = cat $(filter-out FORCE,$^) > $@ -$(obj)/vmlinux.bin.all: $(vmlinux.bin.all-y) FORCE - $(call if_changed,relocbin) +vmlinux.bin.all-$(CONFIG_X86_NEED_RELOCS) += $(obj)/vmlinux.relocs -ifeq ($(CONFIG_X86_32),y) - -ifdef CONFIG_RELOCATABLE -$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin.all FORCE +$(obj)/vmlinux.bin.gz: $(vmlinux.bin.all-y) FORCE $(call if_changed,gzip) -$(obj)/vmlinux.bin.bz2: $(obj)/vmlinux.bin.all FORCE +$(obj)/vmlinux.bin.bz2: $(vmlinux.bin.all-y) FORCE $(call if_changed,bzip2) -$(obj)/vmlinux.bin.lzma: $(obj)/vmlinux.bin.all FORCE - $(call if_changed,lzma) -else -$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE - $(call if_changed,gzip) -$(obj)/vmlinux.bin.bz2: $(obj)/vmlinux.bin FORCE - $(call if_changed,bzip2) -$(obj)/vmlinux.bin.lzma: $(obj)/vmlinux.bin FORCE - $(call if_changed,lzma) -endif -LDFLAGS_piggy.o := -r --format binary --oformat elf32-i386 -T - -else - -$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE - $(call if_changed,gzip) -$(obj)/vmlinux.bin.bz2: $(obj)/vmlinux.bin FORCE - $(call if_changed,bzip2) -$(obj)/vmlinux.bin.lzma: $(obj)/vmlinux.bin FORCE +$(obj)/vmlinux.bin.lzma: $(vmlinux.bin.all-y) FORCE $(call if_changed,lzma) -LDFLAGS_piggy.o := -r --format binary --oformat elf64-x86-64 -T -endif +suffix-$(CONFIG_KERNEL_GZIP) := gz +suffix-$(CONFIG_KERNEL_BZIP2) := bz2 +suffix-$(CONFIG_KERNEL_LZMA) := lzma -suffix_$(CONFIG_KERNEL_GZIP) = gz -suffix_$(CONFIG_KERNEL_BZIP2) = bz2 -suffix_$(CONFIG_KERNEL_LZMA) = lzma +quiet_cmd_mkpiggy = MKPIGGY $@ + cmd_mkpiggy = $(obj)/mkpiggy $< > $@ || ( rm -f $@ ; false ) -$(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.$(suffix_y) FORCE - $(call if_changed,ld) +targets += piggy.S +$(obj)/piggy.S: $(obj)/vmlinux.bin.$(suffix-y) $(obj)/mkpiggy FORCE + $(call if_changed,mkpiggy) diff --git a/arch/x86/boot/compressed/head_32.S b/arch/x86/boot/compressed/head_32.S index 3a8a866fb2e2..75e4f001e706 100644 --- a/arch/x86/boot/compressed/head_32.S +++ b/arch/x86/boot/compressed/head_32.S @@ -12,16 +12,16 @@ * the page directory. [According to comments etc elsewhere on a compressed * kernel it will end up at 0x1000 + 1Mb I hope so as I assume this. - AC] * - * Page 0 is deliberately kept safe, since System Management Mode code in + * Page 0 is deliberately kept safe, since System Management Mode code in * laptops may need to access the BIOS data stored there. This is also - * useful for future device drivers that either access the BIOS via VM86 + * useful for future device drivers that either access the BIOS via VM86 * mode. */ /* * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996 */ -.text + .text #include #include @@ -29,161 +29,151 @@ #include #include -.section ".text.head","ax",@progbits + .section ".text.head","ax",@progbits ENTRY(startup_32) cld - /* test KEEP_SEGMENTS flag to see if the bootloader is asking - * us to not reload segments */ - testb $(1<<6), BP_loadflags(%esi) - jnz 1f + /* + * Test KEEP_SEGMENTS flag to see if the bootloader is asking + * us to not reload segments + */ + testb $(1<<6), BP_loadflags(%esi) + jnz 1f cli - movl $(__BOOT_DS),%eax - movl %eax,%ds - movl %eax,%es - movl %eax,%fs - movl %eax,%gs - movl %eax,%ss + movl $__BOOT_DS, %eax + movl %eax, %ds + movl %eax, %es + movl %eax, %fs + movl %eax, %gs + movl %eax, %ss 1: -/* Calculate the delta between where we were compiled to run +/* + * Calculate the delta between where we were compiled to run * at and where we were actually loaded at. This can only be done * with a short local call on x86. Nothing else will tell us what * address we are running at. The reserved chunk of the real-mode * data at 0x1e4 (defined as a scratch field) are used as the stack * for this calculation. Only 4 bytes are needed. */ - leal (0x1e4+4)(%esi), %esp - call 1f -1: popl %ebp - subl $1b, %ebp + leal (BP_scratch+4)(%esi), %esp + call 1f +1: popl %ebp + subl $1b, %ebp -/* %ebp contains the address we are loaded at by the boot loader and %ebx +/* + * %ebp contains the address we are loaded at by the boot loader and %ebx * contains the address where we should move the kernel image temporarily * for safe in-place decompression. */ #ifdef CONFIG_RELOCATABLE - movl %ebp, %ebx - addl $(CONFIG_PHYSICAL_ALIGN - 1), %ebx - andl $(~(CONFIG_PHYSICAL_ALIGN - 1)), %ebx + movl %ebp, %ebx + movl BP_kernel_alignment(%esi), %eax + decl %eax + addl %eax, %ebx + notl %eax + andl %eax, %ebx #else - movl $LOAD_PHYSICAL_ADDR, %ebx + movl $LOAD_PHYSICAL_ADDR, %ebx #endif - /* Replace the compressed data size with the uncompressed size */ - subl input_len(%ebp), %ebx - movl output_len(%ebp), %eax - addl %eax, %ebx - /* Add 8 bytes for every 32K input block */ - shrl $12, %eax - addl %eax, %ebx - /* Add 32K + 18 bytes of extra slack */ - addl $(32768 + 18), %ebx - /* Align on a 4K boundary */ - addl $4095, %ebx - andl $~4095, %ebx + /* Target address to relocate to for decompression */ + addl $z_extract_offset, %ebx -/* Copy the compressed kernel to the end of our buffer + /* Set up the stack */ + leal boot_stack_end(%ebx), %esp + + /* Zero EFLAGS */ + pushl $0 + popfl + +/* + * Copy the compressed kernel to the end of our buffer * where decompression in place becomes safe. */ - pushl %esi - leal _end(%ebp), %esi - leal _end(%ebx), %edi - movl $(_end - startup_32), %ecx + pushl %esi + leal (_bss-4)(%ebp), %esi + leal (_bss-4)(%ebx), %edi + movl $(_bss - startup_32), %ecx + shrl $2, %ecx std - rep - movsb + rep movsl cld - popl %esi - -/* Compute the kernel start address. - */ -#ifdef CONFIG_RELOCATABLE - addl $(CONFIG_PHYSICAL_ALIGN - 1), %ebp - andl $(~(CONFIG_PHYSICAL_ALIGN - 1)), %ebp -#else - movl $LOAD_PHYSICAL_ADDR, %ebp -#endif + popl %esi /* * Jump to the relocated address. */ - leal relocated(%ebx), %eax - jmp *%eax + leal relocated(%ebx), %eax + jmp *%eax ENDPROC(startup_32) -.section ".text" + .text relocated: /* - * Clear BSS + * Clear BSS (stack is currently empty) */ - xorl %eax,%eax - leal _edata(%ebx),%edi - leal _end(%ebx), %ecx - subl %edi,%ecx - cld - rep - stosb - -/* - * Setup the stack for the decompressor - */ - leal boot_stack_end(%ebx), %esp + xorl %eax, %eax + leal _bss(%ebx), %edi + leal _ebss(%ebx), %ecx + subl %edi, %ecx + shrl $2, %ecx + rep stosl /* * Do the decompression, and jump to the new kernel.. */ - movl output_len(%ebx), %eax - pushl %eax - # push arguments for decompress_kernel: - pushl %ebp # output address - movl input_len(%ebx), %eax - pushl %eax # input_len - leal input_data(%ebx), %eax - pushl %eax # input_data - leal boot_heap(%ebx), %eax - pushl %eax # heap area - pushl %esi # real mode pointer - call decompress_kernel - addl $20, %esp - popl %ecx + leal z_extract_offset_negative(%ebx), %ebp + /* push arguments for decompress_kernel: */ + pushl %ebp /* output address */ + pushl $z_input_len /* input_len */ + leal input_data(%ebx), %eax + pushl %eax /* input_data */ + leal boot_heap(%ebx), %eax + pushl %eax /* heap area */ + pushl %esi /* real mode pointer */ + call decompress_kernel + addl $20, %esp #if CONFIG_RELOCATABLE -/* Find the address of the relocations. +/* + * Find the address of the relocations. */ - movl %ebp, %edi - addl %ecx, %edi + leal z_output_len(%ebp), %edi -/* Calculate the delta between where vmlinux was compiled to run +/* + * Calculate the delta between where vmlinux was compiled to run * and where it was actually loaded. */ - movl %ebp, %ebx - subl $LOAD_PHYSICAL_ADDR, %ebx - jz 2f /* Nothing to be done if loaded at compiled addr. */ + movl %ebp, %ebx + subl $LOAD_PHYSICAL_ADDR, %ebx + jz 2f /* Nothing to be done if loaded at compiled addr. */ /* * Process relocations. */ -1: subl $4, %edi - movl 0(%edi), %ecx - testl %ecx, %ecx - jz 2f - addl %ebx, -__PAGE_OFFSET(%ebx, %ecx) - jmp 1b +1: subl $4, %edi + movl (%edi), %ecx + testl %ecx, %ecx + jz 2f + addl %ebx, -__PAGE_OFFSET(%ebx, %ecx) + jmp 1b 2: #endif /* * Jump to the decompressed kernel. */ - xorl %ebx,%ebx - jmp *%ebp + xorl %ebx, %ebx + jmp *%ebp -.bss -/* Stack and heap for uncompression */ -.balign 4 +/* + * Stack and heap for uncompression + */ + .bss + .balign 4 boot_heap: .fill BOOT_HEAP_SIZE, 1, 0 boot_stack: diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S index ed4a82948002..f62c284db9eb 100644 --- a/arch/x86/boot/compressed/head_64.S +++ b/arch/x86/boot/compressed/head_64.S @@ -21,8 +21,8 @@ /* * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996 */ -.code32 -.text + .code32 + .text #include #include @@ -33,12 +33,14 @@ #include #include -.section ".text.head" + .section ".text.head" .code32 ENTRY(startup_32) cld - /* test KEEP_SEGMENTS flag to see if the bootloader is asking - * us to not reload segments */ + /* + * Test KEEP_SEGMENTS flag to see if the bootloader is asking + * us to not reload segments + */ testb $(1<<6), BP_loadflags(%esi) jnz 1f @@ -49,14 +51,15 @@ ENTRY(startup_32) movl %eax, %ss 1: -/* Calculate the delta between where we were compiled to run +/* + * Calculate the delta between where we were compiled to run * at and where we were actually loaded at. This can only be done * with a short local call on x86. Nothing else will tell us what * address we are running at. The reserved chunk of the real-mode * data at 0x1e4 (defined as a scratch field) are used as the stack * for this calculation. Only 4 bytes are needed. */ - leal (0x1e4+4)(%esi), %esp + leal (BP_scratch+4)(%esi), %esp call 1f 1: popl %ebp subl $1b, %ebp @@ -70,32 +73,28 @@ ENTRY(startup_32) testl %eax, %eax jnz no_longmode -/* Compute the delta between where we were compiled to run at +/* + * Compute the delta between where we were compiled to run at * and where the code will actually run at. - */ -/* %ebp contains the address we are loaded at by the boot loader and %ebx + * + * %ebp contains the address we are loaded at by the boot loader and %ebx * contains the address where we should move the kernel image temporarily * for safe in-place decompression. */ #ifdef CONFIG_RELOCATABLE movl %ebp, %ebx - addl $(PMD_PAGE_SIZE -1), %ebx - andl $PMD_PAGE_MASK, %ebx + movl BP_kernel_alignment(%esi), %eax + decl %eax + addl %eax, %ebx + notl %eax + andl %eax, %ebx #else - movl $CONFIG_PHYSICAL_START, %ebx + movl $LOAD_PHYSICAL_ADDR, %ebx #endif - /* Replace the compressed data size with the uncompressed size */ - subl input_len(%ebp), %ebx - movl output_len(%ebp), %eax - addl %eax, %ebx - /* Add 8 bytes for every 32K input block */ - shrl $12, %eax - addl %eax, %ebx - /* Add 32K + 18 bytes of extra slack and align on a 4K boundary */ - addl $(32768 + 18 + 4095), %ebx - andl $~4095, %ebx + /* Target address to relocate to for decompression */ + addl $z_extract_offset, %ebx /* * Prepare for entering 64 bit mode @@ -114,7 +113,7 @@ ENTRY(startup_32) /* * Build early 4G boot pagetable */ - /* Initialize Page tables to 0*/ + /* Initialize Page tables to 0 */ leal pgtable(%ebx), %edi xorl %eax, %eax movl $((4096*6)/4), %ecx @@ -155,7 +154,8 @@ ENTRY(startup_32) btsl $_EFER_LME, %eax wrmsr - /* Setup for the jump to 64bit mode + /* + * Setup for the jump to 64bit mode * * When the jump is performend we will be in long mode but * in 32bit compatibility mode with EFER.LME = 1, CS.L = 0, CS.D = 1 @@ -184,7 +184,8 @@ no_longmode: #include "../../kernel/verify_cpu_64.S" - /* Be careful here startup_64 needs to be at a predictable + /* + * Be careful here startup_64 needs to be at a predictable * address so I can export it in an ELF header. Bootloaders * should look at the ELF header to find this address, as * it may change in the future. @@ -192,7 +193,8 @@ no_longmode: .code64 .org 0x200 ENTRY(startup_64) - /* We come here either from startup_32 or directly from a + /* + * We come here either from startup_32 or directly from a * 64bit bootloader. If we come here from a bootloader we depend on * an identity mapped page table being provied that maps our * entire text+data+bss and hopefully all of memory. @@ -209,50 +211,54 @@ ENTRY(startup_64) movl $0x20, %eax ltr %ax - /* Compute the decompressed kernel start address. It is where + /* + * Compute the decompressed kernel start address. It is where * we were loaded at aligned to a 2M boundary. %rbp contains the * decompressed kernel start address. * * If it is a relocatable kernel then decompress and run the kernel * from load address aligned to 2MB addr, otherwise decompress and - * run the kernel from CONFIG_PHYSICAL_START + * run the kernel from LOAD_PHYSICAL_ADDR + * + * We cannot rely on the calculation done in 32-bit mode, since we + * may have been invoked via the 64-bit entry point. */ /* Start with the delta to where the kernel will run at. */ #ifdef CONFIG_RELOCATABLE leaq startup_32(%rip) /* - $startup_32 */, %rbp - addq $(PMD_PAGE_SIZE - 1), %rbp - andq $PMD_PAGE_MASK, %rbp - movq %rbp, %rbx + movl BP_kernel_alignment(%rsi), %eax + decl %eax + addq %rax, %rbp + notq %rax + andq %rax, %rbp #else - movq $CONFIG_PHYSICAL_START, %rbp - movq %rbp, %rbx + movq $LOAD_PHYSICAL_ADDR, %rbp #endif - /* Replace the compressed data size with the uncompressed size */ - movl input_len(%rip), %eax - subq %rax, %rbx - movl output_len(%rip), %eax - addq %rax, %rbx - /* Add 8 bytes for every 32K input block */ - shrq $12, %rax - addq %rax, %rbx - /* Add 32K + 18 bytes of extra slack and align on a 4K boundary */ - addq $(32768 + 18 + 4095), %rbx - andq $~4095, %rbx + /* Target address to relocate to for decompression */ + leaq z_extract_offset(%rbp), %rbx -/* Copy the compressed kernel to the end of our buffer + /* Set up the stack */ + leaq boot_stack_end(%rbx), %rsp + + /* Zero EFLAGS */ + pushq $0 + popfq + +/* + * Copy the compressed kernel to the end of our buffer * where decompression in place becomes safe. */ - leaq _end_before_pgt(%rip), %r8 - leaq _end_before_pgt(%rbx), %r9 - movq $_end_before_pgt /* - $startup_32 */, %rcx -1: subq $8, %r8 - subq $8, %r9 - movq 0(%r8), %rax - movq %rax, 0(%r9) - subq $8, %rcx - jnz 1b + pushq %rsi + leaq (_bss-8)(%rip), %rsi + leaq (_bss-8)(%rbx), %rdi + movq $_bss /* - $startup_32 */, %rcx + shrq $3, %rcx + std + rep movsq + cld + popq %rsi /* * Jump to the relocated address. @@ -260,37 +266,28 @@ ENTRY(startup_64) leaq relocated(%rbx), %rax jmp *%rax -.section ".text" + .text relocated: /* - * Clear BSS + * Clear BSS (stack is currently empty) */ - xorq %rax, %rax - leaq _edata(%rbx), %rdi - leaq _end_before_pgt(%rbx), %rcx + xorl %eax, %eax + leaq _bss(%rip), %rdi + leaq _ebss(%rip), %rcx subq %rdi, %rcx - cld - rep - stosb - - /* Setup the stack */ - leaq boot_stack_end(%rip), %rsp - - /* zero EFLAGS after setting rsp */ - pushq $0 - popfq + shrq $3, %rcx + rep stosq /* * Do the decompression, and jump to the new kernel.. */ - pushq %rsi # Save the real mode argument - movq %rsi, %rdi # real mode address - leaq boot_heap(%rip), %rsi # malloc area for uncompression - leaq input_data(%rip), %rdx # input_data - movl input_len(%rip), %eax - movq %rax, %rcx # input_len - movq %rbp, %r8 # output + pushq %rsi /* Save the real mode argument */ + movq %rsi, %rdi /* real mode address */ + leaq boot_heap(%rip), %rsi /* malloc area for uncompression */ + leaq input_data(%rip), %rdx /* input_data */ + movl $z_input_len, %ecx /* input_len */ + movq %rbp, %r8 /* output target address */ call decompress_kernel popq %rsi @@ -311,11 +308,21 @@ gdt: .quad 0x0000000000000000 /* TS continued */ gdt_end: -.bss -/* Stack and heap for uncompression */ -.balign 4 +/* + * Stack and heap for uncompression + */ + .bss + .balign 4 boot_heap: .fill BOOT_HEAP_SIZE, 1, 0 boot_stack: .fill BOOT_STACK_SIZE, 1, 0 boot_stack_end: + +/* + * Space for page tables (not in .bss so not zeroed) + */ + .section ".pgtable","a",@nobits + .balign 4096 +pgtable: + .fill 6*4096, 1, 0 diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c index e45be73684ff..842b2a36174a 100644 --- a/arch/x86/boot/compressed/misc.c +++ b/arch/x86/boot/compressed/misc.c @@ -325,20 +325,18 @@ asmlinkage void decompress_kernel(void *rmode, memptr heap, free_mem_ptr = heap; /* Heap */ free_mem_end_ptr = heap + BOOT_HEAP_SIZE; + if ((unsigned long)output & (MIN_KERNEL_ALIGN - 1)) + error("Destination address inappropriately aligned"); #ifdef CONFIG_X86_64 - if ((unsigned long)output & (__KERNEL_ALIGN - 1)) - error("Destination address not 2M aligned"); - if ((unsigned long)output >= 0xffffffffffUL) + if (heap > 0x3fffffffffffUL) error("Destination address too large"); #else - if ((u32)output & (CONFIG_PHYSICAL_ALIGN - 1)) - error("Destination address not CONFIG_PHYSICAL_ALIGN aligned"); if (heap > ((-__PAGE_OFFSET-(512<<20)-1) & 0x7fffffff)) error("Destination address too large"); -#ifndef CONFIG_RELOCATABLE - if ((u32)output != LOAD_PHYSICAL_ADDR) - error("Wrong destination address"); #endif +#ifndef CONFIG_RELOCATABLE + if ((unsigned long)output != LOAD_PHYSICAL_ADDR) + error("Wrong destination address"); #endif if (!quiet) diff --git a/arch/x86/boot/compressed/mkpiggy.c b/arch/x86/boot/compressed/mkpiggy.c new file mode 100644 index 000000000000..bcbd36c41432 --- /dev/null +++ b/arch/x86/boot/compressed/mkpiggy.c @@ -0,0 +1,97 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright (C) 2009 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License 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. + * + * H. Peter Anvin + * + * ----------------------------------------------------------------------- */ + +/* + * Compute the desired load offset from a compressed program; outputs + * a small assembly wrapper with the appropriate symbols defined. + */ + +#include +#include +#include +#include + +static uint32_t getle32(const void *p) +{ + const uint8_t *cp = p; + + return (uint32_t)cp[0] + ((uint32_t)cp[1] << 8) + + ((uint32_t)cp[2] << 16) + ((uint32_t)cp[3] << 24); +} + +int main(int argc, char *argv[]) +{ + uint32_t olen; + long ilen; + unsigned long offs; + FILE *f; + + if (argc < 2) { + fprintf(stderr, "Usage: %s compressed_file\n", argv[0]); + return 1; + } + + /* Get the information for the compressed kernel image first */ + + f = fopen(argv[1], "r"); + if (!f) { + perror(argv[1]); + return 1; + } + + + if (fseek(f, -4L, SEEK_END)) { + perror(argv[1]); + } + fread(&olen, sizeof olen, 1, f); + ilen = ftell(f); + olen = getle32(&olen); + fclose(f); + + /* + * Now we have the input (compressed) and output (uncompressed) + * sizes, compute the necessary decompression offset... + */ + + offs = (olen > ilen) ? olen - ilen : 0; + offs += olen >> 12; /* Add 8 bytes for each 32K block */ + offs += 32*1024 + 18; /* Add 32K + 18 bytes slack */ + offs = (offs+4095) & ~4095; /* Round to a 4K boundary */ + + printf(".section \".rodata.compressed\",\"a\",@progbits\n"); + printf(".globl z_input_len\n"); + printf("z_input_len = %lu\n", ilen); + printf(".globl z_output_len\n"); + printf("z_output_len = %lu\n", (unsigned long)olen); + printf(".globl z_extract_offset\n"); + printf("z_extract_offset = 0x%lx\n", offs); + /* z_extract_offset_negative allows simplification of head_32.S */ + printf(".globl z_extract_offset_negative\n"); + printf("z_extract_offset_negative = -0x%lx\n", offs); + + printf(".globl input_data, input_data_end\n"); + printf("input_data:\n"); + printf(".incbin \"%s\"\n", argv[1]); + printf("input_data_end:\n"); + + return 0; +} diff --git a/arch/x86/boot/compressed/vmlinux_64.lds b/arch/x86/boot/compressed/vmlinux.lds.S similarity index 57% rename from arch/x86/boot/compressed/vmlinux_64.lds rename to arch/x86/boot/compressed/vmlinux.lds.S index bef1ac891bce..cc353e1b3ffd 100644 --- a/arch/x86/boot/compressed/vmlinux_64.lds +++ b/arch/x86/boot/compressed/vmlinux.lds.S @@ -1,6 +1,17 @@ -OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") +OUTPUT_FORMAT(CONFIG_OUTPUT_FORMAT, CONFIG_OUTPUT_FORMAT, CONFIG_OUTPUT_FORMAT) + +#undef i386 + +#include + +#ifdef CONFIG_X86_64 OUTPUT_ARCH(i386:x86-64) ENTRY(startup_64) +#else +OUTPUT_ARCH(i386) +ENTRY(startup_32) +#endif + SECTIONS { /* Be careful parts of head_64.S assume startup_32 is at @@ -33,16 +44,22 @@ SECTIONS *(.data.*) _edata = . ; } + . = ALIGN(CONFIG_X86_L1_CACHE_BYTES); .bss : { _bss = . ; *(.bss) *(.bss.*) *(COMMON) - . = ALIGN(8); - _end_before_pgt = . ; - . = ALIGN(4096); - pgtable = . ; - . = . + 4096 * 6; + . = ALIGN(8); /* For convenience during zeroing */ _ebss = .; } +#ifdef CONFIG_X86_64 + . = ALIGN(PAGE_SIZE); + .pgtable : { + _pgtable = . ; + *(.pgtable) + _epgtable = . ; + } +#endif + _end = .; } diff --git a/arch/x86/boot/compressed/vmlinux.scr b/arch/x86/boot/compressed/vmlinux.scr deleted file mode 100644 index f02382ae5c48..000000000000 --- a/arch/x86/boot/compressed/vmlinux.scr +++ /dev/null @@ -1,10 +0,0 @@ -SECTIONS -{ - .rodata.compressed : { - input_len = .; - LONG(input_data_end - input_data) input_data = .; - *(.data) - output_len = . - 4; - input_data_end = .; - } -} diff --git a/arch/x86/boot/compressed/vmlinux_32.lds b/arch/x86/boot/compressed/vmlinux_32.lds deleted file mode 100644 index bb3c48379c40..000000000000 --- a/arch/x86/boot/compressed/vmlinux_32.lds +++ /dev/null @@ -1,43 +0,0 @@ -OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") -OUTPUT_ARCH(i386) -ENTRY(startup_32) -SECTIONS -{ - /* Be careful parts of head_32.S assume startup_32 is at - * address 0. - */ - . = 0; - .text.head : { - _head = . ; - *(.text.head) - _ehead = . ; - } - .rodata.compressed : { - *(.rodata.compressed) - } - .text : { - _text = .; /* Text */ - *(.text) - *(.text.*) - _etext = . ; - } - .rodata : { - _rodata = . ; - *(.rodata) /* read-only data */ - *(.rodata.*) - _erodata = . ; - } - .data : { - _data = . ; - *(.data) - *(.data.*) - _edata = . ; - } - .bss : { - _bss = . ; - *(.bss) - *(.bss.*) - *(COMMON) - _end = . ; - } -} diff --git a/arch/x86/boot/edd.c b/arch/x86/boot/edd.c index 1aae8f3e5ca1..c501a5b466f8 100644 --- a/arch/x86/boot/edd.c +++ b/arch/x86/boot/edd.c @@ -2,6 +2,7 @@ * * Copyright (C) 1991, 1992 Linus Torvalds * Copyright 2007 rPath, Inc. - All Rights Reserved + * Copyright 2009 Intel Corporation; author H. Peter Anvin * * This file is part of the Linux kernel, and is made available under * the terms of the GNU General Public License version 2. @@ -22,17 +23,17 @@ */ static int read_mbr(u8 devno, void *buf) { - u16 ax, bx, cx, dx; + struct biosregs ireg, oreg; - ax = 0x0201; /* Legacy Read, one sector */ - cx = 0x0001; /* Sector 0-0-1 */ - dx = devno; - bx = (size_t)buf; - asm volatile("pushfl; stc; int $0x13; setc %%al; popfl" - : "+a" (ax), "+c" (cx), "+d" (dx), "+b" (bx) - : : "esi", "edi", "memory"); + initregs(&ireg); + ireg.ax = 0x0201; /* Legacy Read, one sector */ + ireg.cx = 0x0001; /* Sector 0-0-1 */ + ireg.dl = devno; + ireg.bx = (size_t)buf; - return -(u8)ax; /* 0 or -1 */ + intcall(0x13, &ireg, &oreg); + + return -(oreg.eflags & X86_EFLAGS_CF); /* 0 or -1 */ } static u32 read_mbr_sig(u8 devno, struct edd_info *ei, u32 *mbrsig) @@ -72,56 +73,46 @@ static u32 read_mbr_sig(u8 devno, struct edd_info *ei, u32 *mbrsig) static int get_edd_info(u8 devno, struct edd_info *ei) { - u16 ax, bx, cx, dx, di; + struct biosregs ireg, oreg; memset(ei, 0, sizeof *ei); /* Check Extensions Present */ - ax = 0x4100; - bx = EDDMAGIC1; - dx = devno; - asm("pushfl; stc; int $0x13; setc %%al; popfl" - : "+a" (ax), "+b" (bx), "=c" (cx), "+d" (dx) - : : "esi", "edi"); + initregs(&ireg); + ireg.ah = 0x41; + ireg.bx = EDDMAGIC1; + ireg.dl = devno; + intcall(0x13, &ireg, &oreg); - if ((u8)ax) + if (oreg.eflags & X86_EFLAGS_CF) return -1; /* No extended information */ - if (bx != EDDMAGIC2) + if (oreg.bx != EDDMAGIC2) return -1; ei->device = devno; - ei->version = ax >> 8; /* EDD version number */ - ei->interface_support = cx; /* EDD functionality subsets */ + ei->version = oreg.ah; /* EDD version number */ + ei->interface_support = oreg.cx; /* EDD functionality subsets */ /* Extended Get Device Parameters */ ei->params.length = sizeof(ei->params); - ax = 0x4800; - dx = devno; - asm("pushfl; int $0x13; popfl" - : "+a" (ax), "+d" (dx), "=m" (ei->params) - : "S" (&ei->params) - : "ebx", "ecx", "edi"); + ireg.ah = 0x48; + ireg.si = (size_t)&ei->params; + intcall(0x13, &ireg, &oreg); /* Get legacy CHS parameters */ /* Ralf Brown recommends setting ES:DI to 0:0 */ - ax = 0x0800; - dx = devno; - di = 0; - asm("pushw %%es; " - "movw %%di,%%es; " - "pushfl; stc; int $0x13; setc %%al; popfl; " - "popw %%es" - : "+a" (ax), "=b" (bx), "=c" (cx), "+d" (dx), "+D" (di) - : : "esi"); + ireg.ah = 0x08; + ireg.es = 0; + intcall(0x13, &ireg, &oreg); - if ((u8)ax == 0) { - ei->legacy_max_cylinder = (cx >> 8) + ((cx & 0xc0) << 2); - ei->legacy_max_head = dx >> 8; - ei->legacy_sectors_per_track = cx & 0x3f; + if (!(oreg.eflags & X86_EFLAGS_CF)) { + ei->legacy_max_cylinder = oreg.ch + ((oreg.cl & 0xc0) << 2); + ei->legacy_max_head = oreg.dh; + ei->legacy_sectors_per_track = oreg.cl & 0x3f; } return 0; diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S index 5d84d1c74e4c..b31cc54b4641 100644 --- a/arch/x86/boot/header.S +++ b/arch/x86/boot/header.S @@ -22,7 +22,8 @@ #include #include #include "boot.h" -#include "offsets.h" +#include "voffset.h" +#include "zoffset.h" BOOTSEG = 0x07C0 /* original address of boot-sector */ SYSSEG = 0x1000 /* historical load address >> 4 */ @@ -115,7 +116,7 @@ _start: # Part 2 of the header, from the old setup.S .ascii "HdrS" # header signature - .word 0x0209 # header version number (>= 0x0105) + .word 0x020a # header version number (>= 0x0105) # or else old loadlin-1.5 will fail) .globl realmode_swtch realmode_swtch: .word 0, 0 # default_switch, SETUPSEG @@ -168,7 +169,11 @@ heap_end_ptr: .word _end+STACK_SIZE-512 # end of setup code can be used by setup # for local heap purposes. -pad1: .word 0 +ext_loader_ver: + .byte 0 # Extended boot loader version +ext_loader_type: + .byte 0 # Extended boot loader type + cmd_line_ptr: .long 0 # (Header version 0x0202 or later) # If nonzero, a 32-bit pointer # to the kernel command line. @@ -200,7 +205,7 @@ relocatable_kernel: .byte 1 #else relocatable_kernel: .byte 0 #endif -pad2: .byte 0 +min_alignment: .byte MIN_KERNEL_ALIGN_LG2 # minimum alignment pad3: .word 0 cmdline_size: .long COMMAND_LINE_SIZE-1 #length of the command line, @@ -212,16 +217,27 @@ hardware_subarch: .long 0 # subarchitecture, added with 2.07 hardware_subarch_data: .quad 0 -payload_offset: .long input_data -payload_length: .long input_data_end-input_data +payload_offset: .long ZO_input_data +payload_length: .long ZO_z_input_len setup_data: .quad 0 # 64-bit physical pointer to # single linked list of # struct setup_data +pref_address: .quad LOAD_PHYSICAL_ADDR # preferred load addr + +#define ZO_INIT_SIZE (ZO__end - ZO_startup_32 + ZO_z_extract_offset) +#define VO_INIT_SIZE (VO__end - VO__text) +#if ZO_INIT_SIZE > VO_INIT_SIZE +#define INIT_SIZE ZO_INIT_SIZE +#else +#define INIT_SIZE VO_INIT_SIZE +#endif +init_size: .long INIT_SIZE # kernel initialization size + # End of setup header ##################################################### - .section ".inittext", "ax" + .section ".entrytext", "ax" start_of_setup: #ifdef SAFE_RESET_DISK_CONTROLLER # Reset the disk controller. diff --git a/arch/x86/boot/main.c b/arch/x86/boot/main.c index 58f0415d3ae0..140172b895bd 100644 --- a/arch/x86/boot/main.c +++ b/arch/x86/boot/main.c @@ -2,6 +2,7 @@ * * Copyright (C) 1991, 1992 Linus Torvalds * Copyright 2007 rPath, Inc. - All Rights Reserved + * Copyright 2009 Intel Corporation; author H. Peter Anvin * * This file is part of the Linux kernel, and is made available under * the terms of the GNU General Public License version 2. @@ -61,11 +62,10 @@ static void copy_boot_params(void) */ static void keyboard_set_repeat(void) { - u16 ax = 0x0305; - u16 bx = 0; - asm volatile("int $0x16" - : "+a" (ax), "+b" (bx) - : : "ecx", "edx", "esi", "edi"); + struct biosregs ireg; + initregs(&ireg); + ireg.ax = 0x0305; + intcall(0x16, &ireg, NULL); } /* @@ -73,18 +73,22 @@ static void keyboard_set_repeat(void) */ static void query_ist(void) { + struct biosregs ireg, oreg; + /* Some older BIOSes apparently crash on this call, so filter it from machines too old to have SpeedStep at all. */ if (cpu.level < 6) return; - asm("int $0x15" - : "=a" (boot_params.ist_info.signature), - "=b" (boot_params.ist_info.command), - "=c" (boot_params.ist_info.event), - "=d" (boot_params.ist_info.perf_level) - : "a" (0x0000e980), /* IST Support */ - "d" (0x47534943)); /* Request value */ + initregs(&ireg); + ireg.ax = 0xe980; /* IST Support */ + ireg.edx = 0x47534943; /* Request value */ + intcall(0x15, &ireg, &oreg); + + boot_params.ist_info.signature = oreg.eax; + boot_params.ist_info.command = oreg.ebx; + boot_params.ist_info.event = oreg.ecx; + boot_params.ist_info.perf_level = oreg.edx; } /* @@ -93,13 +97,12 @@ static void query_ist(void) static void set_bios_mode(void) { #ifdef CONFIG_X86_64 - u32 eax, ebx; + struct biosregs ireg; - eax = 0xec00; - ebx = 2; - asm volatile("int $0x15" - : "+a" (eax), "+b" (ebx) - : : "ecx", "edx", "esi", "edi"); + initregs(&ireg); + ireg.ax = 0xec00; + ireg.bx = 2; + intcall(0x15, &ireg, NULL); #endif } diff --git a/arch/x86/boot/mca.c b/arch/x86/boot/mca.c index 911eaae5d696..a95a531148ef 100644 --- a/arch/x86/boot/mca.c +++ b/arch/x86/boot/mca.c @@ -2,6 +2,7 @@ * * Copyright (C) 1991, 1992 Linus Torvalds * Copyright 2007 rPath, Inc. - All Rights Reserved + * Copyright 2009 Intel Corporation; author H. Peter Anvin * * This file is part of the Linux kernel, and is made available under * the terms of the GNU General Public License version 2. @@ -16,26 +17,22 @@ int query_mca(void) { - u8 err; - u16 es, bx, len; + struct biosregs ireg, oreg; + u16 len; - asm("pushw %%es ; " - "int $0x15 ; " - "setc %0 ; " - "movw %%es, %1 ; " - "popw %%es" - : "=acd" (err), "=acdSD" (es), "=b" (bx) - : "a" (0xc000)); + initregs(&ireg); + ireg.ah = 0xc0; + intcall(0x15, &ireg, &oreg); - if (err) + if (oreg.eflags & X86_EFLAGS_CF) return -1; /* No MCA present */ - set_fs(es); - len = rdfs16(bx); + set_fs(oreg.es); + len = rdfs16(oreg.bx); if (len > sizeof(boot_params.sys_desc_table)) len = sizeof(boot_params.sys_desc_table); - copy_from_fs(&boot_params.sys_desc_table, bx, len); + copy_from_fs(&boot_params.sys_desc_table, oreg.bx, len); return 0; } diff --git a/arch/x86/boot/memory.c b/arch/x86/boot/memory.c index 74b3d2ba84e9..cae3feb1035e 100644 --- a/arch/x86/boot/memory.c +++ b/arch/x86/boot/memory.c @@ -20,12 +20,16 @@ static int detect_memory_e820(void) { int count = 0; - u32 next = 0; - u32 size, id, edi; - u8 err; + struct biosregs ireg, oreg; struct e820entry *desc = boot_params.e820_map; static struct e820entry buf; /* static so it is zeroed */ + initregs(&ireg); + ireg.ax = 0xe820; + ireg.cx = sizeof buf; + ireg.edx = SMAP; + ireg.di = (size_t)&buf; + /* * Note: at least one BIOS is known which assumes that the * buffer pointed to by one e820 call is the same one as @@ -41,22 +45,13 @@ static int detect_memory_e820(void) */ do { - size = sizeof buf; - - /* Important: %edx and %esi are clobbered by some BIOSes, - so they must be either used for the error output - or explicitly marked clobbered. Given that, assume there - is something out there clobbering %ebp and %edi, too. */ - asm("pushl %%ebp; int $0x15; popl %%ebp; setc %0" - : "=d" (err), "+b" (next), "=a" (id), "+c" (size), - "=D" (edi), "+m" (buf) - : "D" (&buf), "d" (SMAP), "a" (0xe820) - : "esi"); + intcall(0x15, &ireg, &oreg); + ireg.ebx = oreg.ebx; /* for next iteration... */ /* BIOSes which terminate the chain with CF = 1 as opposed to %ebx = 0 don't always report the SMAP signature on the final, failing, probe. */ - if (err) + if (oreg.eflags & X86_EFLAGS_CF) break; /* Some BIOSes stop returning SMAP in the middle of @@ -64,60 +59,64 @@ static int detect_memory_e820(void) screwed up the map at that point, we might have a partial map, the full map, or complete garbage, so just return failure. */ - if (id != SMAP) { + if (oreg.eax != SMAP) { count = 0; break; } *desc++ = buf; count++; - } while (next && count < ARRAY_SIZE(boot_params.e820_map)); + } while (ireg.ebx && count < ARRAY_SIZE(boot_params.e820_map)); return boot_params.e820_entries = count; } static int detect_memory_e801(void) { - u16 ax, bx, cx, dx; - u8 err; + struct biosregs ireg, oreg; - bx = cx = dx = 0; - ax = 0xe801; - asm("stc; int $0x15; setc %0" - : "=m" (err), "+a" (ax), "+b" (bx), "+c" (cx), "+d" (dx)); + initregs(&ireg); + ireg.ax = 0xe801; + intcall(0x15, &ireg, &oreg); - if (err) + if (oreg.eflags & X86_EFLAGS_CF) return -1; /* Do we really need to do this? */ - if (cx || dx) { - ax = cx; - bx = dx; + if (oreg.cx || oreg.dx) { + oreg.ax = oreg.cx; + oreg.bx = oreg.dx; } - if (ax > 15*1024) + if (oreg.ax > 15*1024) { return -1; /* Bogus! */ - - /* This ignores memory above 16MB if we have a memory hole - there. If someone actually finds a machine with a memory - hole at 16MB and no support for 0E820h they should probably - generate a fake e820 map. */ - boot_params.alt_mem_k = (ax == 15*1024) ? (dx << 6)+ax : ax; + } else if (oreg.ax == 15*1024) { + boot_params.alt_mem_k = (oreg.dx << 6) + oreg.ax; + } else { + /* + * This ignores memory above 16MB if we have a memory + * hole there. If someone actually finds a machine + * with a memory hole at 16MB and no support for + * 0E820h they should probably generate a fake e820 + * map. + */ + boot_params.alt_mem_k = oreg.ax; + } return 0; } static int detect_memory_88(void) { - u16 ax; - u8 err; + struct biosregs ireg, oreg; - ax = 0x8800; - asm("stc; int $0x15; setc %0" : "=bcdm" (err), "+a" (ax)); + initregs(&ireg); + ireg.ah = 0x88; + intcall(0x15, &ireg, &oreg); - boot_params.screen_info.ext_mem_k = ax; + boot_params.screen_info.ext_mem_k = oreg.ax; - return -err; + return -(oreg.eflags & X86_EFLAGS_CF); /* 0 or -1 */ } int detect_memory(void) diff --git a/arch/x86/boot/regs.c b/arch/x86/boot/regs.c new file mode 100644 index 000000000000..958019b1cfa5 --- /dev/null +++ b/arch/x86/boot/regs.c @@ -0,0 +1,29 @@ +/* ----------------------------------------------------------------------- + * + * Copyright 2009 Intel Corporation; author H. Peter Anvin + * + * This file is part of the Linux kernel, and is made available under + * the terms of the GNU General Public License version 2 or (at your + * option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * Simple helper function for initializing a register set. + * + * Note that this sets EFLAGS_CF in the input register set; this + * makes it easier to catch functions which do nothing but don't + * explicitly set CF. + */ + +#include "boot.h" + +void initregs(struct biosregs *reg) +{ + memset(reg, 0, sizeof *reg); + reg->eflags |= X86_EFLAGS_CF; + reg->ds = ds(); + reg->es = ds(); + reg->fs = fs(); + reg->gs = gs(); +} diff --git a/arch/x86/boot/setup.ld b/arch/x86/boot/setup.ld index bb8dc2de7969..0f6ec455a2b1 100644 --- a/arch/x86/boot/setup.ld +++ b/arch/x86/boot/setup.ld @@ -15,8 +15,11 @@ SECTIONS . = 497; .header : { *(.header) } + .entrytext : { *(.entrytext) } .inittext : { *(.inittext) } .initdata : { *(.initdata) } + __end_init = .; + .text : { *(.text) } .text32 : { *(.text32) } @@ -52,4 +55,7 @@ SECTIONS . = ASSERT(_end <= 0x8000, "Setup too big!"); . = ASSERT(hdr == 0x1f1, "The setup header has the wrong offset!"); + /* Necessary for the very-old-loader check to work... */ + . = ASSERT(__end_init <= 5*512, "init sections too big!"); + } diff --git a/arch/x86/boot/tty.c b/arch/x86/boot/tty.c index 7e8e8b25f5f6..01ec69c901c7 100644 --- a/arch/x86/boot/tty.c +++ b/arch/x86/boot/tty.c @@ -2,6 +2,7 @@ * * Copyright (C) 1991, 1992 Linus Torvalds * Copyright 2007 rPath, Inc. - All Rights Reserved + * Copyright 2009 Intel Corporation; author H. Peter Anvin * * This file is part of the Linux kernel, and is made available under * the terms of the GNU General Public License version 2. @@ -22,24 +23,23 @@ void __attribute__((section(".inittext"))) putchar(int ch) { - unsigned char c = ch; + struct biosregs ireg; - if (c == '\n') + if (ch == '\n') putchar('\r'); /* \n -> \r\n */ - /* int $0x10 is known to have bugs involving touching registers - it shouldn't. Be extra conservative... */ - asm volatile("pushal; pushw %%ds; int $0x10; popw %%ds; popal" - : : "b" (0x0007), "c" (0x0001), "a" (0x0e00|ch)); + initregs(&ireg); + ireg.bx = 0x0007; + ireg.cx = 0x0001; + ireg.ah = 0x0e; + ireg.al = ch; + intcall(0x10, &ireg, NULL); } void __attribute__((section(".inittext"))) puts(const char *str) { - int n = 0; - while (*str) { + while (*str) putchar(*str++); - n++; - } } /* @@ -49,14 +49,13 @@ void __attribute__((section(".inittext"))) puts(const char *str) static u8 gettime(void) { - u16 ax = 0x0200; - u16 cx, dx; + struct biosregs ireg, oreg; - asm volatile("int $0x1a" - : "+a" (ax), "=c" (cx), "=d" (dx) - : : "ebx", "esi", "edi"); + initregs(&ireg); + ireg.ah = 0x02; + intcall(0x1a, &ireg, &oreg); - return dx >> 8; + return oreg.dh; } /* @@ -64,19 +63,24 @@ static u8 gettime(void) */ int getchar(void) { - u16 ax = 0; - asm volatile("int $0x16" : "+a" (ax)); + struct biosregs ireg, oreg; - return ax & 0xff; + initregs(&ireg); + /* ireg.ah = 0x00; */ + intcall(0x16, &ireg, &oreg); + + return oreg.al; } static int kbd_pending(void) { - u8 pending; - asm volatile("int $0x16; setnz %0" - : "=qm" (pending) - : "a" (0x0100)); - return pending; + struct biosregs ireg, oreg; + + initregs(&ireg); + ireg.ah = 0x01; + intcall(0x16, &ireg, &oreg); + + return !(oreg.eflags & X86_EFLAGS_ZF); } void kbd_flush(void) diff --git a/arch/x86/boot/video-bios.c b/arch/x86/boot/video-bios.c index 3fa979c9c363..d660be492363 100644 --- a/arch/x86/boot/video-bios.c +++ b/arch/x86/boot/video-bios.c @@ -2,6 +2,7 @@ * * Copyright (C) 1991, 1992 Linus Torvalds * Copyright 2007 rPath, Inc. - All Rights Reserved + * Copyright 2009 Intel Corporation; author H. Peter Anvin * * This file is part of the Linux kernel, and is made available under * the terms of the GNU General Public License version 2. @@ -29,21 +30,21 @@ static int bios_set_mode(struct mode_info *mi) static int set_bios_mode(u8 mode) { - u16 ax; + struct biosregs ireg, oreg; u8 new_mode; - ax = mode; /* AH=0x00 Set Video Mode */ - asm volatile(INT10 - : "+a" (ax) - : : "ebx", "ecx", "edx", "esi", "edi"); + initregs(&ireg); + ireg.al = mode; /* AH=0x00 Set Video Mode */ + intcall(0x10, &ireg, NULL); - ax = 0x0f00; /* Get Current Video Mode */ - asm volatile(INT10 - : "+a" (ax) - : : "ebx", "ecx", "edx", "esi", "edi"); + + ireg.ah = 0x0f; /* Get Current Video Mode */ + intcall(0x10, &ireg, &oreg); do_restore = 1; /* Assume video contents were lost */ - new_mode = ax & 0x7f; /* Not all BIOSes are clean with the top bit */ + + /* Not all BIOSes are clean with the top bit */ + new_mode = ireg.al & 0x7f; if (new_mode == mode) return 0; /* Mode change OK */ @@ -53,10 +54,8 @@ static int set_bios_mode(u8 mode) /* Mode setting failed, but we didn't end up where we started. That's bad. Try to revert to the original video mode. */ - ax = boot_params.screen_info.orig_video_mode; - asm volatile(INT10 - : "+a" (ax) - : : "ebx", "ecx", "edx", "esi", "edi"); + ireg.ax = boot_params.screen_info.orig_video_mode; + intcall(0x10, &ireg, NULL); } #endif return -1; diff --git a/arch/x86/boot/video-vesa.c b/arch/x86/boot/video-vesa.c index 4a58c8ce3f69..c700147d6ffb 100644 --- a/arch/x86/boot/video-vesa.c +++ b/arch/x86/boot/video-vesa.c @@ -2,6 +2,7 @@ * * Copyright (C) 1991, 1992 Linus Torvalds * Copyright 2007 rPath, Inc. - All Rights Reserved + * Copyright 2009 Intel Corporation; author H. Peter Anvin * * This file is part of the Linux kernel, and is made available under * the terms of the GNU General Public License version 2. @@ -31,7 +32,7 @@ static inline void vesa_store_mode_params_graphics(void) {} static int vesa_probe(void) { #if defined(CONFIG_VIDEO_VESA) || defined(CONFIG_FIRMWARE_EDID) - u16 ax, cx, di; + struct biosregs ireg, oreg; u16 mode; addr_t mode_ptr; struct mode_info *mi; @@ -39,13 +40,12 @@ static int vesa_probe(void) video_vesa.modes = GET_HEAP(struct mode_info, 0); - ax = 0x4f00; - di = (size_t)&vginfo; - asm(INT10 - : "+a" (ax), "+D" (di), "=m" (vginfo) - : : "ebx", "ecx", "edx", "esi"); + initregs(&ireg); + ireg.ax = 0x4f00; + ireg.di = (size_t)&vginfo; + intcall(0x10, &ireg, &oreg); - if (ax != 0x004f || + if (ireg.ax != 0x004f || vginfo.signature != VESA_MAGIC || vginfo.version < 0x0102) return 0; /* Not present */ @@ -65,14 +65,12 @@ static int vesa_probe(void) memset(&vminfo, 0, sizeof vminfo); /* Just in case... */ - ax = 0x4f01; - cx = mode; - di = (size_t)&vminfo; - asm(INT10 - : "+a" (ax), "+c" (cx), "+D" (di), "=m" (vminfo) - : : "ebx", "edx", "esi"); + ireg.ax = 0x4f01; + ireg.cx = mode; + ireg.di = (size_t)&vminfo; + intcall(0x10, &ireg, &oreg); - if (ax != 0x004f) + if (ireg.ax != 0x004f) continue; if ((vminfo.mode_attr & 0x15) == 0x05) { @@ -111,20 +109,19 @@ static int vesa_probe(void) static int vesa_set_mode(struct mode_info *mode) { - u16 ax, bx, cx, di; + struct biosregs ireg, oreg; int is_graphic; u16 vesa_mode = mode->mode - VIDEO_FIRST_VESA; memset(&vminfo, 0, sizeof vminfo); /* Just in case... */ - ax = 0x4f01; - cx = vesa_mode; - di = (size_t)&vminfo; - asm(INT10 - : "+a" (ax), "+c" (cx), "+D" (di), "=m" (vminfo) - : : "ebx", "edx", "esi"); + initregs(&ireg); + ireg.ax = 0x4f01; + ireg.cx = vesa_mode; + ireg.di = (size_t)&vminfo; + intcall(0x10, &ireg, &oreg); - if (ax != 0x004f) + if (oreg.ax != 0x004f) return -1; if ((vminfo.mode_attr & 0x15) == 0x05) { @@ -141,14 +138,12 @@ static int vesa_set_mode(struct mode_info *mode) } - ax = 0x4f02; - bx = vesa_mode; - di = 0; - asm volatile(INT10 - : "+a" (ax), "+b" (bx), "+D" (di) - : : "ecx", "edx", "esi"); + initregs(&ireg); + ireg.ax = 0x4f02; + ireg.bx = vesa_mode; + intcall(0x10, &ireg, &oreg); - if (ax != 0x004f) + if (oreg.ax != 0x004f) return -1; graphic_mode = is_graphic; @@ -171,50 +166,45 @@ static int vesa_set_mode(struct mode_info *mode) /* Switch DAC to 8-bit mode */ static void vesa_dac_set_8bits(void) { + struct biosregs ireg, oreg; u8 dac_size = 6; /* If possible, switch the DAC to 8-bit mode */ if (vginfo.capabilities & 1) { - u16 ax, bx; - - ax = 0x4f08; - bx = 0x0800; - asm volatile(INT10 - : "+a" (ax), "+b" (bx) - : : "ecx", "edx", "esi", "edi"); - - if (ax == 0x004f) - dac_size = bx >> 8; + initregs(&ireg); + ireg.ax = 0x4f08; + ireg.bh = 0x08; + intcall(0x10, &ireg, &oreg); + if (oreg.ax == 0x004f) + dac_size = oreg.bh; } /* Set the color sizes to the DAC size, and offsets to 0 */ - boot_params.screen_info.red_size = dac_size; + boot_params.screen_info.red_size = dac_size; boot_params.screen_info.green_size = dac_size; - boot_params.screen_info.blue_size = dac_size; - boot_params.screen_info.rsvd_size = dac_size; + boot_params.screen_info.blue_size = dac_size; + boot_params.screen_info.rsvd_size = dac_size; - boot_params.screen_info.red_pos = 0; - boot_params.screen_info.green_pos = 0; - boot_params.screen_info.blue_pos = 0; - boot_params.screen_info.rsvd_pos = 0; + boot_params.screen_info.red_pos = 0; + boot_params.screen_info.green_pos = 0; + boot_params.screen_info.blue_pos = 0; + boot_params.screen_info.rsvd_pos = 0; } /* Save the VESA protected mode info */ static void vesa_store_pm_info(void) { - u16 ax, bx, di, es; + struct biosregs ireg, oreg; - ax = 0x4f0a; - bx = di = 0; - asm("pushw %%es; "INT10"; movw %%es,%0; popw %%es" - : "=d" (es), "+a" (ax), "+b" (bx), "+D" (di) - : : "ecx", "esi"); + initregs(&ireg); + ireg.ax = 0x4f0a; + intcall(0x10, &ireg, &oreg); - if (ax != 0x004f) + if (oreg.ax != 0x004f) return; - boot_params.screen_info.vesapm_seg = es; - boot_params.screen_info.vesapm_off = di; + boot_params.screen_info.vesapm_seg = oreg.es; + boot_params.screen_info.vesapm_off = oreg.di; } /* @@ -252,7 +242,7 @@ static void vesa_store_mode_params_graphics(void) void vesa_store_edid(void) { #ifdef CONFIG_FIRMWARE_EDID - u16 ax, bx, cx, dx, di; + struct biosregs ireg, oreg; /* Apparently used as a nonsense token... */ memset(&boot_params.edid_info, 0x13, sizeof boot_params.edid_info); @@ -260,33 +250,26 @@ void vesa_store_edid(void) if (vginfo.version < 0x0200) return; /* EDID requires VBE 2.0+ */ - ax = 0x4f15; /* VBE DDC */ - bx = 0x0000; /* Report DDC capabilities */ - cx = 0; /* Controller 0 */ - di = 0; /* ES:DI must be 0 by spec */ + initregs(&ireg); + ireg.ax = 0x4f15; /* VBE DDC */ + /* ireg.bx = 0x0000; */ /* Report DDC capabilities */ + /* ireg.cx = 0; */ /* Controller 0 */ + ireg.es = 0; /* ES:DI must be 0 by spec */ + intcall(0x10, &ireg, &oreg); - /* Note: The VBE DDC spec is different from the main VESA spec; - we genuinely have to assume all registers are destroyed here. */ - - asm("pushw %%es; movw %2,%%es; "INT10"; popw %%es" - : "+a" (ax), "+b" (bx), "+c" (cx), "+D" (di) - : : "esi", "edx"); - - if (ax != 0x004f) + if (oreg.ax != 0x004f) return; /* No EDID */ /* BH = time in seconds to transfer EDD information */ /* BL = DDC level supported */ - ax = 0x4f15; /* VBE DDC */ - bx = 0x0001; /* Read EDID */ - cx = 0; /* Controller 0 */ - dx = 0; /* EDID block number */ - di =(size_t) &boot_params.edid_info; /* (ES:)Pointer to block */ - asm(INT10 - : "+a" (ax), "+b" (bx), "+d" (dx), "=m" (boot_params.edid_info), - "+c" (cx), "+D" (di) - : : "esi"); + ireg.ax = 0x4f15; /* VBE DDC */ + ireg.bx = 0x0001; /* Read EDID */ + /* ireg.cx = 0; */ /* Controller 0 */ + /* ireg.dx = 0; */ /* EDID block number */ + ireg.es = ds(); + ireg.di =(size_t)&boot_params.edid_info; /* (ES:)Pointer to block */ + intcall(0x10, &ireg, &oreg); #endif /* CONFIG_FIRMWARE_EDID */ } diff --git a/arch/x86/boot/video-vga.c b/arch/x86/boot/video-vga.c index 9e0587a37768..8f8d827e254d 100644 --- a/arch/x86/boot/video-vga.c +++ b/arch/x86/boot/video-vga.c @@ -2,6 +2,7 @@ * * Copyright (C) 1991, 1992 Linus Torvalds * Copyright 2007 rPath, Inc. - All Rights Reserved + * Copyright 2009 Intel Corporation; author H. Peter Anvin * * This file is part of the Linux kernel, and is made available under * the terms of the GNU General Public License version 2. @@ -39,30 +40,30 @@ static __videocard video_vga; /* Set basic 80x25 mode */ static u8 vga_set_basic_mode(void) { + struct biosregs ireg, oreg; u16 ax; u8 rows; u8 mode; + initregs(&ireg); + #ifdef CONFIG_VIDEO_400_HACK if (adapter >= ADAPTER_VGA) { - asm volatile(INT10 - : : "a" (0x1202), "b" (0x0030) - : "ecx", "edx", "esi", "edi"); + ireg.ax = 0x1202; + ireg.bx = 0x0030; + intcall(0x10, &ireg, NULL); } #endif ax = 0x0f00; - asm volatile(INT10 - : "+a" (ax) - : : "ebx", "ecx", "edx", "esi", "edi"); - - mode = (u8)ax; + intcall(0x10, &ireg, &oreg); + mode = oreg.al; set_fs(0); rows = rdfs8(0x484); /* rows minus one */ #ifndef CONFIG_VIDEO_400_HACK - if ((ax == 0x5003 || ax == 0x5007) && + if ((oreg.ax == 0x5003 || oreg.ax == 0x5007) && (rows == 0 || rows == 24)) return mode; #endif @@ -71,10 +72,8 @@ static u8 vga_set_basic_mode(void) mode = 3; /* Set the mode */ - ax = mode; - asm volatile(INT10 - : "+a" (ax) - : : "ebx", "ecx", "edx", "esi", "edi"); + ireg.ax = mode; /* AH=0: set mode */ + intcall(0x10, &ireg, NULL); do_restore = 1; return mode; } @@ -82,43 +81,69 @@ static u8 vga_set_basic_mode(void) static void vga_set_8font(void) { /* Set 8x8 font - 80x43 on EGA, 80x50 on VGA */ + struct biosregs ireg; + + initregs(&ireg); /* Set 8x8 font */ - asm volatile(INT10 : : "a" (0x1112), "b" (0)); + ireg.ax = 0x1112; + /* ireg.bl = 0; */ + intcall(0x10, &ireg, NULL); /* Use alternate print screen */ - asm volatile(INT10 : : "a" (0x1200), "b" (0x20)); + ireg.ax = 0x1200; + ireg.bl = 0x20; + intcall(0x10, &ireg, NULL); /* Turn off cursor emulation */ - asm volatile(INT10 : : "a" (0x1201), "b" (0x34)); + ireg.ax = 0x1201; + ireg.bl = 0x34; + intcall(0x10, &ireg, NULL); /* Cursor is scan lines 6-7 */ - asm volatile(INT10 : : "a" (0x0100), "c" (0x0607)); + ireg.ax = 0x0100; + ireg.cx = 0x0607; + intcall(0x10, &ireg, NULL); } static void vga_set_14font(void) { /* Set 9x14 font - 80x28 on VGA */ + struct biosregs ireg; + + initregs(&ireg); /* Set 9x14 font */ - asm volatile(INT10 : : "a" (0x1111), "b" (0)); + ireg.ax = 0x1111; + /* ireg.bl = 0; */ + intcall(0x10, &ireg, NULL); /* Turn off cursor emulation */ - asm volatile(INT10 : : "a" (0x1201), "b" (0x34)); + ireg.ax = 0x1201; + ireg.bl = 0x34; + intcall(0x10, &ireg, NULL); /* Cursor is scan lines 11-12 */ - asm volatile(INT10 : : "a" (0x0100), "c" (0x0b0c)); + ireg.ax = 0x0100; + ireg.cx = 0x0b0c; + intcall(0x10, &ireg, NULL); } static void vga_set_80x43(void) { /* Set 80x43 mode on VGA (not EGA) */ + struct biosregs ireg; + + initregs(&ireg); /* Set 350 scans */ - asm volatile(INT10 : : "a" (0x1201), "b" (0x30)); + ireg.ax = 0x1201; + ireg.bl = 0x30; + intcall(0x10, &ireg, NULL); /* Reset video mode */ - asm volatile(INT10 : : "a" (0x0003)); + ireg.ax = 0x0003; + intcall(0x10, &ireg, NULL); vga_set_8font(); } @@ -225,8 +250,6 @@ static int vga_set_mode(struct mode_info *mode) */ static int vga_probe(void) { - u16 ega_bx; - static const char *card_name[] = { "CGA/MDA/HGC", "EGA", "VGA" }; @@ -240,26 +263,26 @@ static int vga_probe(void) sizeof(ega_modes)/sizeof(struct mode_info), sizeof(vga_modes)/sizeof(struct mode_info), }; - u8 vga_flag; - asm(INT10 - : "=b" (ega_bx) - : "a" (0x1200), "b" (0x10) /* Check EGA/VGA */ - : "ecx", "edx", "esi", "edi"); + struct biosregs ireg, oreg; + + initregs(&ireg); + + ireg.ax = 0x1200; + ireg.bl = 0x10; /* Check EGA/VGA */ + intcall(0x10, &ireg, &oreg); #ifndef _WAKEUP - boot_params.screen_info.orig_video_ega_bx = ega_bx; + boot_params.screen_info.orig_video_ega_bx = oreg.bx; #endif /* If we have MDA/CGA/HGC then BL will be unchanged at 0x10 */ - if ((u8)ega_bx != 0x10) { + if (oreg.bl != 0x10) { /* EGA/VGA */ - asm(INT10 - : "=a" (vga_flag) - : "a" (0x1a00) - : "ebx", "ecx", "edx", "esi", "edi"); + ireg.ax = 0x1a00; + intcall(0x10, &ireg, &oreg); - if (vga_flag == 0x1a) { + if (oreg.al == 0x1a) { adapter = ADAPTER_VGA; #ifndef _WAKEUP boot_params.screen_info.orig_video_isVGA = 1; diff --git a/arch/x86/boot/video.c b/arch/x86/boot/video.c index 3bef2c1febe9..bad728b76fc2 100644 --- a/arch/x86/boot/video.c +++ b/arch/x86/boot/video.c @@ -2,6 +2,7 @@ * * Copyright (C) 1991, 1992 Linus Torvalds * Copyright 2007 rPath, Inc. - All Rights Reserved + * Copyright 2009 Intel Corporation; author H. Peter Anvin * * This file is part of the Linux kernel, and is made available under * the terms of the GNU General Public License version 2. @@ -18,33 +19,29 @@ static void store_cursor_position(void) { - u16 curpos; - u16 ax, bx; + struct biosregs ireg, oreg; - ax = 0x0300; - bx = 0; - asm(INT10 - : "=d" (curpos), "+a" (ax), "+b" (bx) - : : "ecx", "esi", "edi"); + initregs(&ireg); + ireg.ah = 0x03; + intcall(0x10, &ireg, &oreg); - boot_params.screen_info.orig_x = curpos; - boot_params.screen_info.orig_y = curpos >> 8; + boot_params.screen_info.orig_x = oreg.dl; + boot_params.screen_info.orig_y = oreg.dh; } static void store_video_mode(void) { - u16 ax, page; + struct biosregs ireg, oreg; /* N.B.: the saving of the video page here is a bit silly, since we pretty much assume page 0 everywhere. */ - ax = 0x0f00; - asm(INT10 - : "+a" (ax), "=b" (page) - : : "ecx", "edx", "esi", "edi"); + initregs(&ireg); + ireg.ah = 0x0f; + intcall(0x10, &ireg, &oreg); /* Not all BIOSes are clean with respect to the top bit */ - boot_params.screen_info.orig_video_mode = ax & 0x7f; - boot_params.screen_info.orig_video_page = page >> 8; + boot_params.screen_info.orig_video_mode = oreg.al & 0x7f; + boot_params.screen_info.orig_video_page = oreg.bh; } /* @@ -257,7 +254,7 @@ static void restore_screen(void) int y; addr_t dst = 0; u16 *src = saved.data; - u16 ax, bx, dx; + struct biosregs ireg; if (graphic_mode) return; /* Can't restore onto a graphic mode */ @@ -296,12 +293,11 @@ static void restore_screen(void) } /* Restore cursor position */ - ax = 0x0200; /* Set cursor position */ - bx = 0; /* Page number (<< 8) */ - dx = (saved.cury << 8)+saved.curx; - asm volatile(INT10 - : "+a" (ax), "+b" (bx), "+d" (dx) - : : "ecx", "esi", "edi"); + initregs(&ireg); + ireg.ah = 0x02; /* Set cursor position */ + ireg.dh = saved.cury; + ireg.dl = saved.curx; + intcall(0x10, &ireg, NULL); } #else #define save_screen() ((void)0) diff --git a/arch/x86/boot/video.h b/arch/x86/boot/video.h index ee63f5d14461..5bb174a997fc 100644 --- a/arch/x86/boot/video.h +++ b/arch/x86/boot/video.h @@ -112,20 +112,6 @@ extern int force_x, force_y; /* Don't query the BIOS for cols/rows */ extern int do_restore; /* Restore screen contents */ extern int graphic_mode; /* Graphics mode with linear frame buffer */ -/* - * int $0x10 is notorious for touching registers it shouldn't. - * gcc doesn't like %ebp being clobbered, so define it as a push/pop - * sequence here. - * - * A number of systems, including the original PC can clobber %bp in - * certain circumstances, like when scrolling. There exists at least - * one Trident video card which could clobber DS under a set of - * circumstances that we are unlikely to encounter (scrolling when - * using an extended graphics mode of more than 800x600 pixels), but - * it's cheap insurance to deal with that here. - */ -#define INT10 "pushl %%ebp; pushw %%ds; int $0x10; popw %%ds; popl %%ebp" - /* Accessing VGA indexed registers */ static inline u8 in_idx(u16 port, u8 index) { diff --git a/arch/x86/configs/i386_defconfig b/arch/x86/configs/i386_defconfig index 235b81d0f6f2..edb992ebef92 100644 --- a/arch/x86/configs/i386_defconfig +++ b/arch/x86/configs/i386_defconfig @@ -1,12 +1,13 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.29-rc4 -# Tue Feb 24 15:50:58 2009 +# Linux kernel version: 2.6.30-rc2 +# Mon May 11 16:21:55 2009 # # CONFIG_64BIT is not set CONFIG_X86_32=y # CONFIG_X86_64 is not set CONFIG_X86=y +CONFIG_OUTPUT_FORMAT="elf32-i386" CONFIG_ARCH_DEFCONFIG="arch/x86/configs/i386_defconfig" CONFIG_GENERIC_TIME=y CONFIG_GENERIC_CMOS_UPDATE=y @@ -33,6 +34,7 @@ CONFIG_ARCH_HAS_CPU_RELAX=y CONFIG_ARCH_HAS_DEFAULT_IDLE=y CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y CONFIG_HAVE_SETUP_PER_CPU_AREA=y +CONFIG_HAVE_DYNAMIC_PER_CPU_AREA=y # CONFIG_HAVE_CPUMASK_OF_CPU_MAP is not set CONFIG_ARCH_HIBERNATION_POSSIBLE=y CONFIG_ARCH_SUSPEND_POSSIBLE=y @@ -40,15 +42,16 @@ CONFIG_ARCH_SUSPEND_POSSIBLE=y CONFIG_ARCH_POPULATES_NODE_MAP=y # CONFIG_AUDIT_ARCH is not set CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING=y +CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y CONFIG_GENERIC_IRQ_PROBE=y CONFIG_GENERIC_PENDING_IRQ=y -CONFIG_X86_SMP=y CONFIG_USE_GENERIC_SMP_HELPERS=y CONFIG_X86_32_SMP=y CONFIG_X86_HT=y -CONFIG_X86_BIOS_REBOOT=y CONFIG_X86_TRAMPOLINE=y +CONFIG_X86_32_LAZY_GS=y CONFIG_KTIME_SCALAR=y CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" @@ -60,10 +63,17 @@ CONFIG_LOCK_KERNEL=y CONFIG_INIT_ENV_ARG_LIMIT=32 CONFIG_LOCALVERSION="" # CONFIG_LOCALVERSION_AUTO is not set +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_BZIP2=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_KERNEL_GZIP=y +# CONFIG_KERNEL_BZIP2 is not set +# CONFIG_KERNEL_LZMA is not set CONFIG_SWAP=y CONFIG_SYSVIPC=y CONFIG_SYSVIPC_SYSCTL=y CONFIG_POSIX_MQUEUE=y +CONFIG_POSIX_MQUEUE_SYSCTL=y CONFIG_BSD_PROCESS_ACCT=y # CONFIG_BSD_PROCESS_ACCT_V3 is not set CONFIG_TASKSTATS=y @@ -113,23 +123,26 @@ CONFIG_PID_NS=y CONFIG_NET_NS=y CONFIG_BLK_DEV_INITRD=y CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +CONFIG_RD_BZIP2=y +CONFIG_RD_LZMA=y CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y # CONFIG_EMBEDDED is not set CONFIG_UID16=y CONFIG_SYSCTL_SYSCALL=y CONFIG_KALLSYMS=y CONFIG_KALLSYMS_ALL=y CONFIG_KALLSYMS_EXTRA_PASS=y +# CONFIG_STRIP_ASM_SYMS is not set CONFIG_HOTPLUG=y CONFIG_PRINTK=y CONFIG_BUG=y CONFIG_ELF_CORE=y CONFIG_PCSPKR_PLATFORM=y -# CONFIG_COMPAT_BRK is not set CONFIG_BASE_FULL=y CONFIG_FUTEX=y -CONFIG_ANON_INODES=y CONFIG_EPOLL=y CONFIG_SIGNALFD=y CONFIG_TIMERFD=y @@ -139,6 +152,7 @@ CONFIG_AIO=y CONFIG_VM_EVENT_COUNTERS=y CONFIG_PCI_QUIRKS=y CONFIG_SLUB_DEBUG=y +# CONFIG_COMPAT_BRK is not set # CONFIG_SLAB is not set CONFIG_SLUB=y # CONFIG_SLOB is not set @@ -154,6 +168,8 @@ CONFIG_HAVE_IOREMAP_PROT=y CONFIG_HAVE_KPROBES=y CONFIG_HAVE_KRETPROBES=y CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_DMA_API_DEBUG=y +# CONFIG_SLOW_WORK is not set CONFIG_HAVE_GENERIC_DMA_COHERENT=y CONFIG_SLABINFO=y CONFIG_RT_MUTEXES=y @@ -167,7 +183,6 @@ CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_STOP_MACHINE=y CONFIG_BLOCK=y # CONFIG_LBD is not set -CONFIG_BLK_DEV_IO_TRACE=y CONFIG_BLK_DEV_BSG=y # CONFIG_BLK_DEV_INTEGRITY is not set @@ -194,12 +209,12 @@ CONFIG_HIGH_RES_TIMERS=y CONFIG_GENERIC_CLOCKEVENTS_BUILD=y CONFIG_SMP=y CONFIG_SPARSE_IRQ=y -CONFIG_X86_FIND_SMP_CONFIG=y CONFIG_X86_MPPARSE=y +# CONFIG_X86_BIGSMP is not set +CONFIG_X86_EXTENDED_PLATFORM=y # CONFIG_X86_ELAN is not set -# CONFIG_X86_GENERICARCH is not set -# CONFIG_X86_VSMP is not set # CONFIG_X86_RDC321X is not set +# CONFIG_X86_32_NON_STANDARD is not set CONFIG_SCHED_OMIT_FRAME_POINTER=y # CONFIG_PARAVIRT_GUEST is not set # CONFIG_MEMTEST is not set @@ -230,8 +245,10 @@ CONFIG_M686=y # CONFIG_GENERIC_CPU is not set CONFIG_X86_GENERIC=y CONFIG_X86_CPU=y +CONFIG_X86_L1_CACHE_BYTES=64 +CONFIG_X86_INTERNODE_CACHE_BYTES=64 CONFIG_X86_CMPXCHG=y -CONFIG_X86_L1_CACHE_SHIFT=7 +CONFIG_X86_L1_CACHE_SHIFT=5 CONFIG_X86_XADD=y # CONFIG_X86_PPRO_FENCE is not set CONFIG_X86_WP_WORKS_OK=y @@ -247,7 +264,7 @@ CONFIG_X86_DEBUGCTLMSR=y CONFIG_CPU_SUP_INTEL=y CONFIG_CPU_SUP_CYRIX_32=y CONFIG_CPU_SUP_AMD=y -CONFIG_CPU_SUP_CENTAUR_32=y +CONFIG_CPU_SUP_CENTAUR=y CONFIG_CPU_SUP_TRANSMETA_32=y CONFIG_CPU_SUP_UMC_32=y CONFIG_X86_DS=y @@ -279,6 +296,7 @@ CONFIG_MICROCODE_AMD=y CONFIG_MICROCODE_OLD_INTERFACE=y CONFIG_X86_MSR=y CONFIG_X86_CPUID=y +# CONFIG_X86_CPU_DEBUG is not set # CONFIG_NOHIGHMEM is not set CONFIG_HIGHMEM4G=y # CONFIG_HIGHMEM64G is not set @@ -302,6 +320,8 @@ CONFIG_ZONE_DMA_FLAG=1 CONFIG_BOUNCE=y CONFIG_VIRT_TO_BUS=y CONFIG_UNEVICTABLE_LRU=y +CONFIG_HAVE_MLOCK=y +CONFIG_HAVE_MLOCKED_PAGE_BIT=y CONFIG_HIGHPTE=y CONFIG_X86_CHECK_BIOS_CORRUPTION=y CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK=y @@ -312,6 +332,7 @@ CONFIG_MTRR=y CONFIG_X86_PAT=y CONFIG_EFI=y CONFIG_SECCOMP=y +# CONFIG_CC_STACKPROTECTOR is not set # CONFIG_HZ_100 is not set # CONFIG_HZ_250 is not set # CONFIG_HZ_300 is not set @@ -322,8 +343,9 @@ CONFIG_KEXEC=y CONFIG_CRASH_DUMP=y # CONFIG_KEXEC_JUMP is not set CONFIG_PHYSICAL_START=0x1000000 -# CONFIG_RELOCATABLE is not set -CONFIG_PHYSICAL_ALIGN=0x200000 +CONFIG_RELOCATABLE=y +CONFIG_X86_NEED_RELOCS=y +CONFIG_PHYSICAL_ALIGN=0x1000000 CONFIG_HOTPLUG_CPU=y # CONFIG_COMPAT_VDSO is not set # CONFIG_CMDLINE_BOOL is not set @@ -363,7 +385,6 @@ CONFIG_ACPI_THERMAL=y CONFIG_ACPI_BLACKLIST_YEAR=0 # CONFIG_ACPI_DEBUG is not set # CONFIG_ACPI_PCI_SLOT is not set -CONFIG_ACPI_SYSTEM=y CONFIG_X86_PM_TIMER=y CONFIG_ACPI_CONTAINER=y # CONFIG_ACPI_SBS is not set @@ -425,6 +446,7 @@ CONFIG_PCI_BIOS=y CONFIG_PCI_DIRECT=y CONFIG_PCI_MMCONFIG=y CONFIG_PCI_DOMAINS=y +# CONFIG_DMAR is not set CONFIG_PCIEPORTBUS=y # CONFIG_HOTPLUG_PCI_PCIE is not set CONFIG_PCIEAER=y @@ -435,6 +457,7 @@ CONFIG_PCI_MSI=y # CONFIG_PCI_DEBUG is not set # CONFIG_PCI_STUB is not set CONFIG_HT_IRQ=y +# CONFIG_PCI_IOV is not set CONFIG_ISA_DMA_API=y # CONFIG_ISA is not set # CONFIG_MCA is not set @@ -481,7 +504,6 @@ CONFIG_NET=y # # Networking options # -CONFIG_COMPAT_NET_DEV_OPS=y CONFIG_PACKET=y CONFIG_PACKET_MMAP=y CONFIG_UNIX=y @@ -639,6 +661,7 @@ CONFIG_LLC=y # CONFIG_LAPB is not set # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set +# CONFIG_PHONET is not set CONFIG_NET_SCHED=y # @@ -696,6 +719,7 @@ CONFIG_NET_SCH_FIFO=y # # CONFIG_NET_PKTGEN is not set # CONFIG_NET_TCPPROBE is not set +# CONFIG_NET_DROP_MONITOR is not set CONFIG_HAMRADIO=y # @@ -706,12 +730,10 @@ CONFIG_HAMRADIO=y # CONFIG_IRDA is not set # CONFIG_BT is not set # CONFIG_AF_RXRPC is not set -# CONFIG_PHONET is not set CONFIG_FIB_RULES=y CONFIG_WIRELESS=y CONFIG_CFG80211=y # CONFIG_CFG80211_REG_DEBUG is not set -CONFIG_NL80211=y CONFIG_WIRELESS_OLD_REGULATORY=y CONFIG_WIRELESS_EXT=y CONFIG_WIRELESS_EXT_SYSFS=y @@ -789,6 +811,7 @@ CONFIG_MISC_DEVICES=y # CONFIG_ICS932S401 is not set # CONFIG_ENCLOSURE_SERVICES is not set # CONFIG_HP_ILO is not set +# CONFIG_ISL29003 is not set # CONFIG_C2PORT is not set # @@ -842,6 +865,7 @@ CONFIG_SCSI_SPI_ATTRS=y # CONFIG_SCSI_LOWLEVEL is not set # CONFIG_SCSI_LOWLEVEL_PCMCIA is not set # CONFIG_SCSI_DH is not set +# CONFIG_SCSI_OSD_INITIATOR is not set CONFIG_ATA=y # CONFIG_ATA_NONSTANDARD is not set CONFIG_ATA_ACPI=y @@ -940,6 +964,7 @@ CONFIG_DM_ZERO=y CONFIG_MACINTOSH_DRIVERS=y CONFIG_MAC_EMUMOUSEBTN=y CONFIG_NETDEVICES=y +CONFIG_COMPAT_NET_DEV_OPS=y # CONFIG_IFB is not set # CONFIG_DUMMY is not set # CONFIG_BONDING is not set @@ -977,6 +1002,8 @@ CONFIG_MII=y CONFIG_NET_VENDOR_3COM=y # CONFIG_VORTEX is not set # CONFIG_TYPHOON is not set +# CONFIG_ETHOC is not set +# CONFIG_DNET is not set CONFIG_NET_TULIP=y # CONFIG_DE2104X is not set # CONFIG_TULIP is not set @@ -1026,6 +1053,7 @@ CONFIG_E1000=y CONFIG_E1000E=y # CONFIG_IP1000 is not set # CONFIG_IGB is not set +# CONFIG_IGBVF is not set # CONFIG_NS83820 is not set # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set @@ -1040,6 +1068,7 @@ CONFIG_BNX2=y # CONFIG_QLA3XXX is not set # CONFIG_ATL1 is not set # CONFIG_ATL1E is not set +# CONFIG_ATL1C is not set # CONFIG_JME is not set CONFIG_NETDEV_10000=y # CONFIG_CHELSIO_T1 is not set @@ -1049,6 +1078,7 @@ CONFIG_CHELSIO_T3_DEPENDS=y # CONFIG_IXGBE is not set # CONFIG_IXGB is not set # CONFIG_S2IO is not set +# CONFIG_VXGE is not set # CONFIG_MYRI10GE is not set # CONFIG_NETXEN_NIC is not set # CONFIG_NIU is not set @@ -1058,6 +1088,7 @@ CONFIG_CHELSIO_T3_DEPENDS=y # CONFIG_BNX2X is not set # CONFIG_QLGE is not set # CONFIG_SFC is not set +# CONFIG_BE2NET is not set CONFIG_TR=y # CONFIG_IBMOL is not set # CONFIG_IBMLS is not set @@ -1073,8 +1104,8 @@ CONFIG_WLAN_80211=y # CONFIG_LIBERTAS is not set # CONFIG_LIBERTAS_THINFIRM is not set # CONFIG_AIRO is not set -# CONFIG_HERMES is not set # CONFIG_ATMEL is not set +# CONFIG_AT76C50X_USB is not set # CONFIG_AIRO_CS is not set # CONFIG_PCMCIA_WL3501 is not set # CONFIG_PRISM54 is not set @@ -1084,21 +1115,21 @@ CONFIG_WLAN_80211=y # CONFIG_RTL8187 is not set # CONFIG_ADM8211 is not set # CONFIG_MAC80211_HWSIM is not set +# CONFIG_MWL8K is not set # CONFIG_P54_COMMON is not set CONFIG_ATH5K=y # CONFIG_ATH5K_DEBUG is not set # CONFIG_ATH9K is not set +# CONFIG_AR9170_USB is not set # CONFIG_IPW2100 is not set # CONFIG_IPW2200 is not set -# CONFIG_IWLCORE is not set -# CONFIG_IWLWIFI_LEDS is not set -# CONFIG_IWLAGN is not set -# CONFIG_IWL3945 is not set +# CONFIG_IWLWIFI is not set # CONFIG_HOSTAP is not set # CONFIG_B43 is not set # CONFIG_B43LEGACY is not set # CONFIG_ZD1211RW is not set # CONFIG_RT2X00 is not set +# CONFIG_HERMES is not set # # Enable WiMAX (Networking options) to see the WiMAX drivers @@ -1209,6 +1240,8 @@ CONFIG_INPUT_TABLET=y # CONFIG_TABLET_USB_KBTAB is not set # CONFIG_TABLET_USB_WACOM is not set CONFIG_INPUT_TOUCHSCREEN=y +# CONFIG_TOUCHSCREEN_AD7879_I2C is not set +# CONFIG_TOUCHSCREEN_AD7879 is not set # CONFIG_TOUCHSCREEN_FUJITSU is not set # CONFIG_TOUCHSCREEN_GUNZE is not set # CONFIG_TOUCHSCREEN_ELO is not set @@ -1303,6 +1336,7 @@ CONFIG_UNIX98_PTYS=y # CONFIG_LEGACY_PTYS is not set # CONFIG_IPMI_HANDLER is not set CONFIG_HW_RANDOM=y +# CONFIG_HW_RANDOM_TIMERIOMEM is not set CONFIG_HW_RANDOM_INTEL=y CONFIG_HW_RANDOM_AMD=y CONFIG_HW_RANDOM_GEODE=y @@ -1390,7 +1424,6 @@ CONFIG_I2C_I801=y # CONFIG_SENSORS_PCF8574 is not set # CONFIG_PCF8575 is not set # CONFIG_SENSORS_PCA9539 is not set -# CONFIG_SENSORS_PCF8591 is not set # CONFIG_SENSORS_MAX6875 is not set # CONFIG_SENSORS_TSL2550 is not set # CONFIG_I2C_DEBUG_CORE is not set @@ -1424,6 +1457,7 @@ CONFIG_HWMON=y # CONFIG_SENSORS_ADT7475 is not set # CONFIG_SENSORS_K8TEMP is not set # CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_ATK0110 is not set # CONFIG_SENSORS_ATXP1 is not set # CONFIG_SENSORS_DS1621 is not set # CONFIG_SENSORS_I5K_AMB is not set @@ -1433,6 +1467,7 @@ CONFIG_HWMON=y # CONFIG_SENSORS_FSCHER is not set # CONFIG_SENSORS_FSCPOS is not set # CONFIG_SENSORS_FSCHMD is not set +# CONFIG_SENSORS_G760A is not set # CONFIG_SENSORS_GL518SM is not set # CONFIG_SENSORS_GL520SM is not set # CONFIG_SENSORS_CORETEMP is not set @@ -1448,11 +1483,14 @@ CONFIG_HWMON=y # CONFIG_SENSORS_LM90 is not set # CONFIG_SENSORS_LM92 is not set # CONFIG_SENSORS_LM93 is not set +# CONFIG_SENSORS_LTC4215 is not set # CONFIG_SENSORS_LTC4245 is not set +# CONFIG_SENSORS_LM95241 is not set # CONFIG_SENSORS_MAX1619 is not set # CONFIG_SENSORS_MAX6650 is not set # CONFIG_SENSORS_PC87360 is not set # CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_PCF8591 is not set # CONFIG_SENSORS_SIS5595 is not set # CONFIG_SENSORS_DME1737 is not set # CONFIG_SENSORS_SMSC47M1 is not set @@ -1643,7 +1681,6 @@ CONFIG_FB_EFI=y # CONFIG_FB_3DFX is not set # CONFIG_FB_VOODOO1 is not set # CONFIG_FB_VT8623 is not set -# CONFIG_FB_CYBLA is not set # CONFIG_FB_TRIDENT is not set # CONFIG_FB_ARK is not set # CONFIG_FB_PM3 is not set @@ -1652,6 +1689,7 @@ CONFIG_FB_EFI=y # CONFIG_FB_VIRTUAL is not set # CONFIG_FB_METRONOME is not set # CONFIG_FB_MB862XX is not set +# CONFIG_FB_BROADSHEET is not set CONFIG_BACKLIGHT_LCD_SUPPORT=y # CONFIG_LCD_CLASS_DEVICE is not set CONFIG_BACKLIGHT_CLASS_DEVICE=y @@ -1738,6 +1776,8 @@ CONFIG_SND_PCI=y # CONFIG_SND_INDIGO is not set # CONFIG_SND_INDIGOIO is not set # CONFIG_SND_INDIGODJ is not set +# CONFIG_SND_INDIGOIOX is not set +# CONFIG_SND_INDIGODJX is not set # CONFIG_SND_EMU10K1 is not set # CONFIG_SND_EMU10K1X is not set # CONFIG_SND_ENS1370 is not set @@ -1811,15 +1851,17 @@ CONFIG_USB_HIDDEV=y # # Special HID drivers # -CONFIG_HID_COMPAT=y CONFIG_HID_A4TECH=y CONFIG_HID_APPLE=y CONFIG_HID_BELKIN=y CONFIG_HID_CHERRY=y CONFIG_HID_CHICONY=y CONFIG_HID_CYPRESS=y +# CONFIG_DRAGONRISE_FF is not set CONFIG_HID_EZKEY=y +CONFIG_HID_KYE=y CONFIG_HID_GYRATION=y +CONFIG_HID_KENSINGTON=y CONFIG_HID_LOGITECH=y CONFIG_LOGITECH_FF=y # CONFIG_LOGIRUMBLEPAD2_FF is not set @@ -1885,11 +1927,11 @@ CONFIG_USB_PRINTER=y # CONFIG_USB_TMC is not set # -# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may also be needed; +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may # # -# see USB_STORAGE Help for more information +# also be needed; see USB_STORAGE Help for more info # CONFIG_USB_STORAGE=y # CONFIG_USB_STORAGE_DEBUG is not set @@ -1931,7 +1973,6 @@ CONFIG_USB_LIBUSUAL=y # CONFIG_USB_LED is not set # CONFIG_USB_CYPRESS_CY7C63 is not set # CONFIG_USB_CYTHERM is not set -# CONFIG_USB_PHIDGET is not set # CONFIG_USB_IDMOUSE is not set # CONFIG_USB_FTDI_ELAN is not set # CONFIG_USB_APPLEDISPLAY is not set @@ -1947,6 +1988,7 @@ CONFIG_USB_LIBUSUAL=y # # OTG and related infrastructure # +# CONFIG_NOP_USB_XCEIV is not set # CONFIG_UWB is not set # CONFIG_MMC is not set # CONFIG_MEMSTICK is not set @@ -1958,8 +2000,10 @@ CONFIG_LEDS_CLASS=y # # CONFIG_LEDS_ALIX2 is not set # CONFIG_LEDS_PCA9532 is not set +# CONFIG_LEDS_LP5521 is not set # CONFIG_LEDS_CLEVO_MAIL is not set # CONFIG_LEDS_PCA955X is not set +# CONFIG_LEDS_BD2802 is not set # # LED Triggers @@ -1969,6 +2013,10 @@ CONFIG_LEDS_TRIGGERS=y # CONFIG_LEDS_TRIGGER_HEARTBEAT is not set # CONFIG_LEDS_TRIGGER_BACKLIGHT is not set # CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set + +# +# iptables trigger is under Netfilter config (LED target) +# # CONFIG_ACCESSIBILITY is not set # CONFIG_INFINIBAND is not set CONFIG_EDAC=y @@ -2037,6 +2085,7 @@ CONFIG_DMADEVICES=y # DMA Devices # # CONFIG_INTEL_IOATDMA is not set +# CONFIG_AUXDISPLAY is not set # CONFIG_UIO is not set # CONFIG_STAGING is not set CONFIG_X86_PLATFORM_DEVICES=y @@ -2071,6 +2120,7 @@ CONFIG_DMIID=y # # CONFIG_EXT2_FS is not set CONFIG_EXT3_FS=y +# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set CONFIG_EXT3_FS_XATTR=y CONFIG_EXT3_FS_POSIX_ACL=y CONFIG_EXT3_FS_SECURITY=y @@ -2100,6 +2150,11 @@ CONFIG_AUTOFS4_FS=y # CONFIG_FUSE_FS is not set CONFIG_GENERIC_ACL=y +# +# Caches +# +# CONFIG_FSCACHE is not set + # # CD-ROM/DVD Filesystems # @@ -2151,6 +2206,7 @@ CONFIG_MISC_FILESYSTEMS=y # CONFIG_ROMFS_FS is not set # CONFIG_SYSV_FS is not set # CONFIG_UFS_FS is not set +# CONFIG_NILFS2_FS is not set CONFIG_NETWORK_FILESYSTEMS=y CONFIG_NFS_FS=y CONFIG_NFS_V3=y @@ -2164,7 +2220,6 @@ CONFIG_NFS_ACL_SUPPORT=y CONFIG_NFS_COMMON=y CONFIG_SUNRPC=y CONFIG_SUNRPC_GSS=y -# CONFIG_SUNRPC_REGISTER_V4 is not set CONFIG_RPCSEC_GSS_KRB5=y # CONFIG_RPCSEC_GSS_SPKM3 is not set # CONFIG_SMB_FS is not set @@ -2251,6 +2306,7 @@ CONFIG_DEBUG_FS=y CONFIG_DEBUG_KERNEL=y # CONFIG_DEBUG_SHIRQ is not set # CONFIG_DETECT_SOFTLOCKUP is not set +# CONFIG_DETECT_HUNG_TASK is not set # CONFIG_SCHED_DEBUG is not set CONFIG_SCHEDSTATS=y CONFIG_TIMER_STATS=y @@ -2266,6 +2322,7 @@ CONFIG_TIMER_STATS=y # CONFIG_LOCK_STAT is not set # CONFIG_DEBUG_SPINLOCK_SLEEP is not set # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +CONFIG_STACKTRACE=y # CONFIG_DEBUG_KOBJECT is not set # CONFIG_DEBUG_HIGHMEM is not set CONFIG_DEBUG_BUGVERBOSE=y @@ -2289,13 +2346,19 @@ CONFIG_FRAME_POINTER=y # CONFIG_FAULT_INJECTION is not set # CONFIG_LATENCYTOP is not set CONFIG_SYSCTL_SYSCALL_CHECK=y +# CONFIG_DEBUG_PAGEALLOC is not set CONFIG_USER_STACKTRACE_SUPPORT=y +CONFIG_NOP_TRACER=y CONFIG_HAVE_FUNCTION_TRACER=y CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y CONFIG_HAVE_DYNAMIC_FTRACE=y CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y CONFIG_HAVE_HW_BRANCH_TRACER=y +CONFIG_HAVE_FTRACE_SYSCALLS=y +CONFIG_RING_BUFFER=y +CONFIG_TRACING=y +CONFIG_TRACING_SUPPORT=y # # Tracers @@ -2305,13 +2368,21 @@ CONFIG_HAVE_HW_BRANCH_TRACER=y # CONFIG_SYSPROF_TRACER is not set # CONFIG_SCHED_TRACER is not set # CONFIG_CONTEXT_SWITCH_TRACER is not set +# CONFIG_EVENT_TRACER is not set +# CONFIG_FTRACE_SYSCALLS is not set # CONFIG_BOOT_TRACER is not set # CONFIG_TRACE_BRANCH_PROFILING is not set # CONFIG_POWER_TRACER is not set # CONFIG_STACK_TRACER is not set # CONFIG_HW_BRANCH_TRACER is not set +# CONFIG_KMEMTRACE is not set +# CONFIG_WORKQUEUE_TRACER is not set +CONFIG_BLK_DEV_IO_TRACE=y +# CONFIG_FTRACE_STARTUP_TEST is not set +# CONFIG_MMIOTRACE is not set CONFIG_PROVIDE_OHCI1394_DMA_INIT=y -# CONFIG_DYNAMIC_PRINTK_DEBUG is not set +# CONFIG_DYNAMIC_DEBUG is not set +# CONFIG_DMA_API_DEBUG is not set # CONFIG_SAMPLES is not set CONFIG_HAVE_ARCH_KGDB=y # CONFIG_KGDB is not set @@ -2321,7 +2392,6 @@ CONFIG_EARLY_PRINTK=y CONFIG_EARLY_PRINTK_DBGP=y CONFIG_DEBUG_STACKOVERFLOW=y CONFIG_DEBUG_STACK_USAGE=y -# CONFIG_DEBUG_PAGEALLOC is not set # CONFIG_DEBUG_PER_CPU_MAPS is not set # CONFIG_X86_PTDUMP is not set CONFIG_DEBUG_RODATA=y @@ -2329,7 +2399,7 @@ CONFIG_DEBUG_RODATA=y CONFIG_DEBUG_NX_TEST=m # CONFIG_4KSTACKS is not set CONFIG_DOUBLEFAULT=y -# CONFIG_MMIOTRACE is not set +CONFIG_HAVE_MMIOTRACE_SUPPORT=y CONFIG_IO_DELAY_TYPE_0X80=0 CONFIG_IO_DELAY_TYPE_0XED=1 CONFIG_IO_DELAY_TYPE_UDELAY=2 @@ -2365,6 +2435,8 @@ CONFIG_SECURITY_SELINUX_AVC_STATS=y CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1 # CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX is not set # CONFIG_SECURITY_SMACK is not set +# CONFIG_SECURITY_TOMOYO is not set +# CONFIG_IMA is not set CONFIG_CRYPTO=y # @@ -2380,10 +2452,12 @@ CONFIG_CRYPTO_BLKCIPHER2=y CONFIG_CRYPTO_HASH=y CONFIG_CRYPTO_HASH2=y CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_PCOMP=y CONFIG_CRYPTO_MANAGER=y CONFIG_CRYPTO_MANAGER2=y # CONFIG_CRYPTO_GF128MUL is not set # CONFIG_CRYPTO_NULL is not set +CONFIG_CRYPTO_WORKQUEUE=y # CONFIG_CRYPTO_CRYPTD is not set CONFIG_CRYPTO_AUTHENC=y # CONFIG_CRYPTO_TEST is not set @@ -2456,6 +2530,7 @@ CONFIG_CRYPTO_DES=y # Compression # # CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_ZLIB is not set # CONFIG_CRYPTO_LZO is not set # @@ -2467,11 +2542,13 @@ CONFIG_CRYPTO_HW=y # CONFIG_CRYPTO_DEV_GEODE is not set # CONFIG_CRYPTO_DEV_HIFN_795X is not set CONFIG_HAVE_KVM=y +CONFIG_HAVE_KVM_IRQCHIP=y CONFIG_VIRTUALIZATION=y # CONFIG_KVM is not set # CONFIG_LGUEST is not set # CONFIG_VIRTIO_PCI is not set # CONFIG_VIRTIO_BALLOON is not set +CONFIG_BINARY_PRINTF=y # # Library routines @@ -2489,7 +2566,10 @@ CONFIG_CRC32=y # CONFIG_LIBCRC32C is not set CONFIG_AUDIT_GENERIC=y CONFIG_ZLIB_INFLATE=y -CONFIG_PLIST=y +CONFIG_DECOMPRESS_GZIP=y +CONFIG_DECOMPRESS_BZIP2=y +CONFIG_DECOMPRESS_LZMA=y CONFIG_HAS_IOMEM=y CONFIG_HAS_IOPORT=y CONFIG_HAS_DMA=y +CONFIG_NLATTR=y diff --git a/arch/x86/configs/x86_64_defconfig b/arch/x86/configs/x86_64_defconfig index 9fe5d212ab4c..cee1dd2e69b2 100644 --- a/arch/x86/configs/x86_64_defconfig +++ b/arch/x86/configs/x86_64_defconfig @@ -1,12 +1,13 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.29-rc4 -# Tue Feb 24 15:44:16 2009 +# Linux kernel version: 2.6.30-rc2 +# Mon May 11 16:22:00 2009 # CONFIG_64BIT=y # CONFIG_X86_32 is not set CONFIG_X86_64=y CONFIG_X86=y +CONFIG_OUTPUT_FORMAT="elf64-x86-64" CONFIG_ARCH_DEFCONFIG="arch/x86/configs/x86_64_defconfig" CONFIG_GENERIC_TIME=y CONFIG_GENERIC_CMOS_UPDATE=y @@ -34,6 +35,7 @@ CONFIG_ARCH_HAS_CPU_RELAX=y CONFIG_ARCH_HAS_DEFAULT_IDLE=y CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y CONFIG_HAVE_SETUP_PER_CPU_AREA=y +CONFIG_HAVE_DYNAMIC_PER_CPU_AREA=y CONFIG_HAVE_CPUMASK_OF_CPU_MAP=y CONFIG_ARCH_HIBERNATION_POSSIBLE=y CONFIG_ARCH_SUSPEND_POSSIBLE=y @@ -41,14 +43,14 @@ CONFIG_ZONE_DMA32=y CONFIG_ARCH_POPULATES_NODE_MAP=y CONFIG_AUDIT_ARCH=y CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING=y +CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y CONFIG_GENERIC_IRQ_PROBE=y CONFIG_GENERIC_PENDING_IRQ=y -CONFIG_X86_SMP=y CONFIG_USE_GENERIC_SMP_HELPERS=y CONFIG_X86_64_SMP=y CONFIG_X86_HT=y -CONFIG_X86_BIOS_REBOOT=y CONFIG_X86_TRAMPOLINE=y # CONFIG_KTIME_SCALAR is not set CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" @@ -61,10 +63,17 @@ CONFIG_LOCK_KERNEL=y CONFIG_INIT_ENV_ARG_LIMIT=32 CONFIG_LOCALVERSION="" # CONFIG_LOCALVERSION_AUTO is not set +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_BZIP2=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_KERNEL_GZIP=y +# CONFIG_KERNEL_BZIP2 is not set +# CONFIG_KERNEL_LZMA is not set CONFIG_SWAP=y CONFIG_SYSVIPC=y CONFIG_SYSVIPC_SYSCTL=y CONFIG_POSIX_MQUEUE=y +CONFIG_POSIX_MQUEUE_SYSCTL=y CONFIG_BSD_PROCESS_ACCT=y # CONFIG_BSD_PROCESS_ACCT_V3 is not set CONFIG_TASKSTATS=y @@ -114,23 +123,26 @@ CONFIG_PID_NS=y CONFIG_NET_NS=y CONFIG_BLK_DEV_INITRD=y CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +CONFIG_RD_BZIP2=y +CONFIG_RD_LZMA=y CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y # CONFIG_EMBEDDED is not set CONFIG_UID16=y CONFIG_SYSCTL_SYSCALL=y CONFIG_KALLSYMS=y CONFIG_KALLSYMS_ALL=y CONFIG_KALLSYMS_EXTRA_PASS=y +# CONFIG_STRIP_ASM_SYMS is not set CONFIG_HOTPLUG=y CONFIG_PRINTK=y CONFIG_BUG=y CONFIG_ELF_CORE=y CONFIG_PCSPKR_PLATFORM=y -# CONFIG_COMPAT_BRK is not set CONFIG_BASE_FULL=y CONFIG_FUTEX=y -CONFIG_ANON_INODES=y CONFIG_EPOLL=y CONFIG_SIGNALFD=y CONFIG_TIMERFD=y @@ -140,6 +152,7 @@ CONFIG_AIO=y CONFIG_VM_EVENT_COUNTERS=y CONFIG_PCI_QUIRKS=y CONFIG_SLUB_DEBUG=y +# CONFIG_COMPAT_BRK is not set # CONFIG_SLAB is not set CONFIG_SLUB=y # CONFIG_SLOB is not set @@ -155,6 +168,8 @@ CONFIG_HAVE_IOREMAP_PROT=y CONFIG_HAVE_KPROBES=y CONFIG_HAVE_KRETPROBES=y CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_DMA_API_DEBUG=y +# CONFIG_SLOW_WORK is not set # CONFIG_HAVE_GENERIC_DMA_COHERENT is not set CONFIG_SLABINFO=y CONFIG_RT_MUTEXES=y @@ -167,7 +182,6 @@ CONFIG_MODULE_FORCE_UNLOAD=y # CONFIG_MODULE_SRCVERSION_ALL is not set CONFIG_STOP_MACHINE=y CONFIG_BLOCK=y -CONFIG_BLK_DEV_IO_TRACE=y CONFIG_BLK_DEV_BSG=y # CONFIG_BLK_DEV_INTEGRITY is not set CONFIG_BLOCK_COMPAT=y @@ -195,12 +209,10 @@ CONFIG_HIGH_RES_TIMERS=y CONFIG_GENERIC_CLOCKEVENTS_BUILD=y CONFIG_SMP=y CONFIG_SPARSE_IRQ=y -# CONFIG_NUMA_MIGRATE_IRQ_DESC is not set -CONFIG_X86_FIND_SMP_CONFIG=y CONFIG_X86_MPPARSE=y -# CONFIG_X86_ELAN is not set -# CONFIG_X86_GENERICARCH is not set +CONFIG_X86_EXTENDED_PLATFORM=y # CONFIG_X86_VSMP is not set +# CONFIG_X86_UV is not set CONFIG_SCHED_OMIT_FRAME_POINTER=y # CONFIG_PARAVIRT_GUEST is not set # CONFIG_MEMTEST is not set @@ -230,10 +242,10 @@ CONFIG_SCHED_OMIT_FRAME_POINTER=y # CONFIG_MCORE2 is not set CONFIG_GENERIC_CPU=y CONFIG_X86_CPU=y -CONFIG_X86_L1_CACHE_BYTES=128 -CONFIG_X86_INTERNODE_CACHE_BYTES=128 +CONFIG_X86_L1_CACHE_BYTES=64 +CONFIG_X86_INTERNODE_CACHE_BYTES=64 CONFIG_X86_CMPXCHG=y -CONFIG_X86_L1_CACHE_SHIFT=7 +CONFIG_X86_L1_CACHE_SHIFT=6 CONFIG_X86_WP_WORKS_OK=y CONFIG_X86_TSC=y CONFIG_X86_CMPXCHG64=y @@ -242,7 +254,7 @@ CONFIG_X86_MINIMUM_CPU_FAMILY=64 CONFIG_X86_DEBUGCTLMSR=y CONFIG_CPU_SUP_INTEL=y CONFIG_CPU_SUP_AMD=y -CONFIG_CPU_SUP_CENTAUR_64=y +CONFIG_CPU_SUP_CENTAUR=y CONFIG_X86_DS=y CONFIG_X86_PTRACE_BTS=y CONFIG_HPET_TIMER=y @@ -269,6 +281,7 @@ CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS=y CONFIG_X86_MCE=y CONFIG_X86_MCE_INTEL=y CONFIG_X86_MCE_AMD=y +CONFIG_X86_MCE_THRESHOLD=y # CONFIG_I8K is not set CONFIG_MICROCODE=y CONFIG_MICROCODE_INTEL=y @@ -276,6 +289,7 @@ CONFIG_MICROCODE_AMD=y CONFIG_MICROCODE_OLD_INTERFACE=y CONFIG_X86_MSR=y CONFIG_X86_CPUID=y +# CONFIG_X86_CPU_DEBUG is not set CONFIG_ARCH_PHYS_ADDR_T_64BIT=y CONFIG_DIRECT_GBPAGES=y CONFIG_NUMA=y @@ -309,6 +323,8 @@ CONFIG_ZONE_DMA_FLAG=1 CONFIG_BOUNCE=y CONFIG_VIRT_TO_BUS=y CONFIG_UNEVICTABLE_LRU=y +CONFIG_HAVE_MLOCK=y +CONFIG_HAVE_MLOCKED_PAGE_BIT=y CONFIG_X86_CHECK_BIOS_CORRUPTION=y CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK=y CONFIG_X86_RESERVE_LOW_64K=y @@ -317,6 +333,7 @@ CONFIG_MTRR=y CONFIG_X86_PAT=y CONFIG_EFI=y CONFIG_SECCOMP=y +# CONFIG_CC_STACKPROTECTOR is not set # CONFIG_HZ_100 is not set # CONFIG_HZ_250 is not set # CONFIG_HZ_300 is not set @@ -325,9 +342,10 @@ CONFIG_HZ=1000 CONFIG_SCHED_HRTICK=y CONFIG_KEXEC=y CONFIG_CRASH_DUMP=y +# CONFIG_KEXEC_JUMP is not set CONFIG_PHYSICAL_START=0x1000000 -# CONFIG_RELOCATABLE is not set -CONFIG_PHYSICAL_ALIGN=0x200000 +CONFIG_RELOCATABLE=y +CONFIG_PHYSICAL_ALIGN=0x1000000 CONFIG_HOTPLUG_CPU=y # CONFIG_COMPAT_VDSO is not set # CONFIG_CMDLINE_BOOL is not set @@ -370,7 +388,6 @@ CONFIG_ACPI_NUMA=y CONFIG_ACPI_BLACKLIST_YEAR=0 # CONFIG_ACPI_DEBUG is not set # CONFIG_ACPI_PCI_SLOT is not set -CONFIG_ACPI_SYSTEM=y CONFIG_X86_PM_TIMER=y CONFIG_ACPI_CONTAINER=y # CONFIG_ACPI_SBS is not set @@ -436,6 +453,7 @@ CONFIG_PCI_MSI=y # CONFIG_PCI_DEBUG is not set # CONFIG_PCI_STUB is not set CONFIG_HT_IRQ=y +# CONFIG_PCI_IOV is not set CONFIG_ISA_DMA_API=y CONFIG_K8_NB=y CONFIG_PCCARD=y @@ -481,7 +499,6 @@ CONFIG_NET=y # # Networking options # -CONFIG_COMPAT_NET_DEV_OPS=y CONFIG_PACKET=y CONFIG_PACKET_MMAP=y CONFIG_UNIX=y @@ -639,6 +656,7 @@ CONFIG_LLC=y # CONFIG_LAPB is not set # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set +# CONFIG_PHONET is not set CONFIG_NET_SCHED=y # @@ -696,6 +714,7 @@ CONFIG_NET_SCH_FIFO=y # # CONFIG_NET_PKTGEN is not set # CONFIG_NET_TCPPROBE is not set +# CONFIG_NET_DROP_MONITOR is not set CONFIG_HAMRADIO=y # @@ -706,12 +725,10 @@ CONFIG_HAMRADIO=y # CONFIG_IRDA is not set # CONFIG_BT is not set # CONFIG_AF_RXRPC is not set -# CONFIG_PHONET is not set CONFIG_FIB_RULES=y CONFIG_WIRELESS=y CONFIG_CFG80211=y # CONFIG_CFG80211_REG_DEBUG is not set -CONFIG_NL80211=y CONFIG_WIRELESS_OLD_REGULATORY=y CONFIG_WIRELESS_EXT=y CONFIG_WIRELESS_EXT_SYSFS=y @@ -788,9 +805,8 @@ CONFIG_MISC_DEVICES=y # CONFIG_TIFM_CORE is not set # CONFIG_ICS932S401 is not set # CONFIG_ENCLOSURE_SERVICES is not set -# CONFIG_SGI_XP is not set # CONFIG_HP_ILO is not set -# CONFIG_SGI_GRU is not set +# CONFIG_ISL29003 is not set # CONFIG_C2PORT is not set # @@ -844,6 +860,7 @@ CONFIG_SCSI_SPI_ATTRS=y # CONFIG_SCSI_LOWLEVEL is not set # CONFIG_SCSI_LOWLEVEL_PCMCIA is not set # CONFIG_SCSI_DH is not set +# CONFIG_SCSI_OSD_INITIATOR is not set CONFIG_ATA=y # CONFIG_ATA_NONSTANDARD is not set CONFIG_ATA_ACPI=y @@ -940,6 +957,7 @@ CONFIG_DM_ZERO=y CONFIG_MACINTOSH_DRIVERS=y CONFIG_MAC_EMUMOUSEBTN=y CONFIG_NETDEVICES=y +CONFIG_COMPAT_NET_DEV_OPS=y # CONFIG_IFB is not set # CONFIG_DUMMY is not set # CONFIG_BONDING is not set @@ -977,6 +995,8 @@ CONFIG_MII=y CONFIG_NET_VENDOR_3COM=y # CONFIG_VORTEX is not set # CONFIG_TYPHOON is not set +# CONFIG_ETHOC is not set +# CONFIG_DNET is not set CONFIG_NET_TULIP=y # CONFIG_DE2104X is not set # CONFIG_TULIP is not set @@ -1026,6 +1046,7 @@ CONFIG_E1000=y # CONFIG_E1000E is not set # CONFIG_IP1000 is not set # CONFIG_IGB is not set +# CONFIG_IGBVF is not set # CONFIG_NS83820 is not set # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set @@ -1040,6 +1061,7 @@ CONFIG_TIGON3=y # CONFIG_QLA3XXX is not set # CONFIG_ATL1 is not set # CONFIG_ATL1E is not set +# CONFIG_ATL1C is not set # CONFIG_JME is not set CONFIG_NETDEV_10000=y # CONFIG_CHELSIO_T1 is not set @@ -1049,6 +1071,7 @@ CONFIG_CHELSIO_T3_DEPENDS=y # CONFIG_IXGBE is not set # CONFIG_IXGB is not set # CONFIG_S2IO is not set +# CONFIG_VXGE is not set # CONFIG_MYRI10GE is not set # CONFIG_NETXEN_NIC is not set # CONFIG_NIU is not set @@ -1058,6 +1081,7 @@ CONFIG_CHELSIO_T3_DEPENDS=y # CONFIG_BNX2X is not set # CONFIG_QLGE is not set # CONFIG_SFC is not set +# CONFIG_BE2NET is not set CONFIG_TR=y # CONFIG_IBMOL is not set # CONFIG_3C359 is not set @@ -1072,8 +1096,8 @@ CONFIG_WLAN_80211=y # CONFIG_LIBERTAS is not set # CONFIG_LIBERTAS_THINFIRM is not set # CONFIG_AIRO is not set -# CONFIG_HERMES is not set # CONFIG_ATMEL is not set +# CONFIG_AT76C50X_USB is not set # CONFIG_AIRO_CS is not set # CONFIG_PCMCIA_WL3501 is not set # CONFIG_PRISM54 is not set @@ -1083,21 +1107,21 @@ CONFIG_WLAN_80211=y # CONFIG_RTL8187 is not set # CONFIG_ADM8211 is not set # CONFIG_MAC80211_HWSIM is not set +# CONFIG_MWL8K is not set # CONFIG_P54_COMMON is not set CONFIG_ATH5K=y # CONFIG_ATH5K_DEBUG is not set # CONFIG_ATH9K is not set +# CONFIG_AR9170_USB is not set # CONFIG_IPW2100 is not set # CONFIG_IPW2200 is not set -# CONFIG_IWLCORE is not set -# CONFIG_IWLWIFI_LEDS is not set -# CONFIG_IWLAGN is not set -# CONFIG_IWL3945 is not set +# CONFIG_IWLWIFI is not set # CONFIG_HOSTAP is not set # CONFIG_B43 is not set # CONFIG_B43LEGACY is not set # CONFIG_ZD1211RW is not set # CONFIG_RT2X00 is not set +# CONFIG_HERMES is not set # # Enable WiMAX (Networking options) to see the WiMAX drivers @@ -1208,6 +1232,8 @@ CONFIG_INPUT_TABLET=y # CONFIG_TABLET_USB_KBTAB is not set # CONFIG_TABLET_USB_WACOM is not set CONFIG_INPUT_TOUCHSCREEN=y +# CONFIG_TOUCHSCREEN_AD7879_I2C is not set +# CONFIG_TOUCHSCREEN_AD7879 is not set # CONFIG_TOUCHSCREEN_FUJITSU is not set # CONFIG_TOUCHSCREEN_GUNZE is not set # CONFIG_TOUCHSCREEN_ELO is not set @@ -1301,6 +1327,7 @@ CONFIG_UNIX98_PTYS=y # CONFIG_LEGACY_PTYS is not set # CONFIG_IPMI_HANDLER is not set CONFIG_HW_RANDOM=y +# CONFIG_HW_RANDOM_TIMERIOMEM is not set # CONFIG_HW_RANDOM_INTEL is not set # CONFIG_HW_RANDOM_AMD is not set CONFIG_NVRAM=y @@ -1382,7 +1409,6 @@ CONFIG_I2C_I801=y # CONFIG_SENSORS_PCF8574 is not set # CONFIG_PCF8575 is not set # CONFIG_SENSORS_PCA9539 is not set -# CONFIG_SENSORS_PCF8591 is not set # CONFIG_SENSORS_MAX6875 is not set # CONFIG_SENSORS_TSL2550 is not set # CONFIG_I2C_DEBUG_CORE is not set @@ -1416,6 +1442,7 @@ CONFIG_HWMON=y # CONFIG_SENSORS_ADT7475 is not set # CONFIG_SENSORS_K8TEMP is not set # CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_ATK0110 is not set # CONFIG_SENSORS_ATXP1 is not set # CONFIG_SENSORS_DS1621 is not set # CONFIG_SENSORS_I5K_AMB is not set @@ -1425,6 +1452,7 @@ CONFIG_HWMON=y # CONFIG_SENSORS_FSCHER is not set # CONFIG_SENSORS_FSCPOS is not set # CONFIG_SENSORS_FSCHMD is not set +# CONFIG_SENSORS_G760A is not set # CONFIG_SENSORS_GL518SM is not set # CONFIG_SENSORS_GL520SM is not set # CONFIG_SENSORS_CORETEMP is not set @@ -1440,11 +1468,14 @@ CONFIG_HWMON=y # CONFIG_SENSORS_LM90 is not set # CONFIG_SENSORS_LM92 is not set # CONFIG_SENSORS_LM93 is not set +# CONFIG_SENSORS_LTC4215 is not set # CONFIG_SENSORS_LTC4245 is not set +# CONFIG_SENSORS_LM95241 is not set # CONFIG_SENSORS_MAX1619 is not set # CONFIG_SENSORS_MAX6650 is not set # CONFIG_SENSORS_PC87360 is not set # CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_PCF8591 is not set # CONFIG_SENSORS_SIS5595 is not set # CONFIG_SENSORS_DME1737 is not set # CONFIG_SENSORS_SMSC47M1 is not set @@ -1635,6 +1666,7 @@ CONFIG_FB_EFI=y # CONFIG_FB_VIRTUAL is not set # CONFIG_FB_METRONOME is not set # CONFIG_FB_MB862XX is not set +# CONFIG_FB_BROADSHEET is not set CONFIG_BACKLIGHT_LCD_SUPPORT=y # CONFIG_LCD_CLASS_DEVICE is not set CONFIG_BACKLIGHT_CLASS_DEVICE=y @@ -1720,6 +1752,8 @@ CONFIG_SND_PCI=y # CONFIG_SND_INDIGO is not set # CONFIG_SND_INDIGOIO is not set # CONFIG_SND_INDIGODJ is not set +# CONFIG_SND_INDIGOIOX is not set +# CONFIG_SND_INDIGODJX is not set # CONFIG_SND_EMU10K1 is not set # CONFIG_SND_EMU10K1X is not set # CONFIG_SND_ENS1370 is not set @@ -1792,15 +1826,17 @@ CONFIG_USB_HIDDEV=y # # Special HID drivers # -CONFIG_HID_COMPAT=y CONFIG_HID_A4TECH=y CONFIG_HID_APPLE=y CONFIG_HID_BELKIN=y CONFIG_HID_CHERRY=y CONFIG_HID_CHICONY=y CONFIG_HID_CYPRESS=y +# CONFIG_DRAGONRISE_FF is not set CONFIG_HID_EZKEY=y +CONFIG_HID_KYE=y CONFIG_HID_GYRATION=y +CONFIG_HID_KENSINGTON=y CONFIG_HID_LOGITECH=y CONFIG_LOGITECH_FF=y # CONFIG_LOGIRUMBLEPAD2_FF is not set @@ -1866,11 +1902,11 @@ CONFIG_USB_PRINTER=y # CONFIG_USB_TMC is not set # -# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may also be needed; +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may # # -# see USB_STORAGE Help for more information +# also be needed; see USB_STORAGE Help for more info # CONFIG_USB_STORAGE=y # CONFIG_USB_STORAGE_DEBUG is not set @@ -1912,7 +1948,6 @@ CONFIG_USB_LIBUSUAL=y # CONFIG_USB_LED is not set # CONFIG_USB_CYPRESS_CY7C63 is not set # CONFIG_USB_CYTHERM is not set -# CONFIG_USB_PHIDGET is not set # CONFIG_USB_IDMOUSE is not set # CONFIG_USB_FTDI_ELAN is not set # CONFIG_USB_APPLEDISPLAY is not set @@ -1928,6 +1963,7 @@ CONFIG_USB_LIBUSUAL=y # # OTG and related infrastructure # +# CONFIG_NOP_USB_XCEIV is not set # CONFIG_UWB is not set # CONFIG_MMC is not set # CONFIG_MEMSTICK is not set @@ -1939,8 +1975,10 @@ CONFIG_LEDS_CLASS=y # # CONFIG_LEDS_ALIX2 is not set # CONFIG_LEDS_PCA9532 is not set +# CONFIG_LEDS_LP5521 is not set # CONFIG_LEDS_CLEVO_MAIL is not set # CONFIG_LEDS_PCA955X is not set +# CONFIG_LEDS_BD2802 is not set # # LED Triggers @@ -1950,6 +1988,10 @@ CONFIG_LEDS_TRIGGERS=y # CONFIG_LEDS_TRIGGER_HEARTBEAT is not set # CONFIG_LEDS_TRIGGER_BACKLIGHT is not set # CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set + +# +# iptables trigger is under Netfilter config (LED target) +# # CONFIG_ACCESSIBILITY is not set # CONFIG_INFINIBAND is not set CONFIG_EDAC=y @@ -2018,6 +2060,7 @@ CONFIG_DMADEVICES=y # DMA Devices # # CONFIG_INTEL_IOATDMA is not set +# CONFIG_AUXDISPLAY is not set # CONFIG_UIO is not set # CONFIG_STAGING is not set CONFIG_X86_PLATFORM_DEVICES=y @@ -2051,6 +2094,7 @@ CONFIG_DMIID=y # # CONFIG_EXT2_FS is not set CONFIG_EXT3_FS=y +# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set CONFIG_EXT3_FS_XATTR=y CONFIG_EXT3_FS_POSIX_ACL=y CONFIG_EXT3_FS_SECURITY=y @@ -2081,6 +2125,11 @@ CONFIG_AUTOFS4_FS=y # CONFIG_FUSE_FS is not set CONFIG_GENERIC_ACL=y +# +# Caches +# +# CONFIG_FSCACHE is not set + # # CD-ROM/DVD Filesystems # @@ -2132,6 +2181,7 @@ CONFIG_MISC_FILESYSTEMS=y # CONFIG_ROMFS_FS is not set # CONFIG_SYSV_FS is not set # CONFIG_UFS_FS is not set +# CONFIG_NILFS2_FS is not set CONFIG_NETWORK_FILESYSTEMS=y CONFIG_NFS_FS=y CONFIG_NFS_V3=y @@ -2145,7 +2195,6 @@ CONFIG_NFS_ACL_SUPPORT=y CONFIG_NFS_COMMON=y CONFIG_SUNRPC=y CONFIG_SUNRPC_GSS=y -# CONFIG_SUNRPC_REGISTER_V4 is not set CONFIG_RPCSEC_GSS_KRB5=y # CONFIG_RPCSEC_GSS_SPKM3 is not set # CONFIG_SMB_FS is not set @@ -2232,6 +2281,7 @@ CONFIG_DEBUG_FS=y CONFIG_DEBUG_KERNEL=y # CONFIG_DEBUG_SHIRQ is not set # CONFIG_DETECT_SOFTLOCKUP is not set +# CONFIG_DETECT_HUNG_TASK is not set # CONFIG_SCHED_DEBUG is not set CONFIG_SCHEDSTATS=y CONFIG_TIMER_STATS=y @@ -2247,6 +2297,7 @@ CONFIG_TIMER_STATS=y # CONFIG_LOCK_STAT is not set # CONFIG_DEBUG_SPINLOCK_SLEEP is not set # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +CONFIG_STACKTRACE=y # CONFIG_DEBUG_KOBJECT is not set CONFIG_DEBUG_BUGVERBOSE=y # CONFIG_DEBUG_INFO is not set @@ -2269,13 +2320,19 @@ CONFIG_FRAME_POINTER=y # CONFIG_FAULT_INJECTION is not set # CONFIG_LATENCYTOP is not set CONFIG_SYSCTL_SYSCALL_CHECK=y +# CONFIG_DEBUG_PAGEALLOC is not set CONFIG_USER_STACKTRACE_SUPPORT=y +CONFIG_NOP_TRACER=y CONFIG_HAVE_FUNCTION_TRACER=y CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y CONFIG_HAVE_DYNAMIC_FTRACE=y CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y CONFIG_HAVE_HW_BRANCH_TRACER=y +CONFIG_HAVE_FTRACE_SYSCALLS=y +CONFIG_RING_BUFFER=y +CONFIG_TRACING=y +CONFIG_TRACING_SUPPORT=y # # Tracers @@ -2285,13 +2342,21 @@ CONFIG_HAVE_HW_BRANCH_TRACER=y # CONFIG_SYSPROF_TRACER is not set # CONFIG_SCHED_TRACER is not set # CONFIG_CONTEXT_SWITCH_TRACER is not set +# CONFIG_EVENT_TRACER is not set +# CONFIG_FTRACE_SYSCALLS is not set # CONFIG_BOOT_TRACER is not set # CONFIG_TRACE_BRANCH_PROFILING is not set # CONFIG_POWER_TRACER is not set # CONFIG_STACK_TRACER is not set # CONFIG_HW_BRANCH_TRACER is not set +# CONFIG_KMEMTRACE is not set +# CONFIG_WORKQUEUE_TRACER is not set +CONFIG_BLK_DEV_IO_TRACE=y +# CONFIG_FTRACE_STARTUP_TEST is not set +# CONFIG_MMIOTRACE is not set CONFIG_PROVIDE_OHCI1394_DMA_INIT=y -# CONFIG_DYNAMIC_PRINTK_DEBUG is not set +# CONFIG_DYNAMIC_DEBUG is not set +# CONFIG_DMA_API_DEBUG is not set # CONFIG_SAMPLES is not set CONFIG_HAVE_ARCH_KGDB=y # CONFIG_KGDB is not set @@ -2301,14 +2366,13 @@ CONFIG_EARLY_PRINTK=y CONFIG_EARLY_PRINTK_DBGP=y CONFIG_DEBUG_STACKOVERFLOW=y CONFIG_DEBUG_STACK_USAGE=y -# CONFIG_DEBUG_PAGEALLOC is not set # CONFIG_DEBUG_PER_CPU_MAPS is not set # CONFIG_X86_PTDUMP is not set CONFIG_DEBUG_RODATA=y # CONFIG_DEBUG_RODATA_TEST is not set CONFIG_DEBUG_NX_TEST=m # CONFIG_IOMMU_DEBUG is not set -# CONFIG_MMIOTRACE is not set +CONFIG_HAVE_MMIOTRACE_SUPPORT=y CONFIG_IO_DELAY_TYPE_0X80=0 CONFIG_IO_DELAY_TYPE_0XED=1 CONFIG_IO_DELAY_TYPE_UDELAY=2 @@ -2344,6 +2408,8 @@ CONFIG_SECURITY_SELINUX_AVC_STATS=y CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1 # CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX is not set # CONFIG_SECURITY_SMACK is not set +# CONFIG_SECURITY_TOMOYO is not set +# CONFIG_IMA is not set CONFIG_CRYPTO=y # @@ -2359,10 +2425,12 @@ CONFIG_CRYPTO_BLKCIPHER2=y CONFIG_CRYPTO_HASH=y CONFIG_CRYPTO_HASH2=y CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_PCOMP=y CONFIG_CRYPTO_MANAGER=y CONFIG_CRYPTO_MANAGER2=y # CONFIG_CRYPTO_GF128MUL is not set # CONFIG_CRYPTO_NULL is not set +CONFIG_CRYPTO_WORKQUEUE=y # CONFIG_CRYPTO_CRYPTD is not set CONFIG_CRYPTO_AUTHENC=y # CONFIG_CRYPTO_TEST is not set @@ -2414,6 +2482,7 @@ CONFIG_CRYPTO_SHA1=y # CONFIG_CRYPTO_AES=y # CONFIG_CRYPTO_AES_X86_64 is not set +# CONFIG_CRYPTO_AES_NI_INTEL is not set # CONFIG_CRYPTO_ANUBIS is not set CONFIG_CRYPTO_ARC4=y # CONFIG_CRYPTO_BLOWFISH is not set @@ -2435,6 +2504,7 @@ CONFIG_CRYPTO_DES=y # Compression # # CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_ZLIB is not set # CONFIG_CRYPTO_LZO is not set # @@ -2444,10 +2514,12 @@ CONFIG_CRYPTO_DES=y CONFIG_CRYPTO_HW=y # CONFIG_CRYPTO_DEV_HIFN_795X is not set CONFIG_HAVE_KVM=y +CONFIG_HAVE_KVM_IRQCHIP=y CONFIG_VIRTUALIZATION=y # CONFIG_KVM is not set # CONFIG_VIRTIO_PCI is not set # CONFIG_VIRTIO_BALLOON is not set +CONFIG_BINARY_PRINTF=y # # Library routines @@ -2464,7 +2536,10 @@ CONFIG_CRC32=y # CONFIG_CRC7 is not set # CONFIG_LIBCRC32C is not set CONFIG_ZLIB_INFLATE=y -CONFIG_PLIST=y +CONFIG_DECOMPRESS_GZIP=y +CONFIG_DECOMPRESS_BZIP2=y +CONFIG_DECOMPRESS_LZMA=y CONFIG_HAS_IOMEM=y CONFIG_HAS_IOPORT=y CONFIG_HAS_DMA=y +CONFIG_NLATTR=y diff --git a/arch/x86/crypto/Makefile b/arch/x86/crypto/Makefile index ebe7deedd5b4..cfb0010fa940 100644 --- a/arch/x86/crypto/Makefile +++ b/arch/x86/crypto/Makefile @@ -2,6 +2,8 @@ # Arch-specific CryptoAPI modules. # +obj-$(CONFIG_CRYPTO_FPU) += fpu.o + obj-$(CONFIG_CRYPTO_AES_586) += aes-i586.o obj-$(CONFIG_CRYPTO_TWOFISH_586) += twofish-i586.o obj-$(CONFIG_CRYPTO_SALSA20_586) += salsa20-i586.o diff --git a/arch/x86/crypto/aesni-intel_asm.S b/arch/x86/crypto/aesni-intel_asm.S index caba99601703..eb0566e83319 100644 --- a/arch/x86/crypto/aesni-intel_asm.S +++ b/arch/x86/crypto/aesni-intel_asm.S @@ -845,7 +845,7 @@ ENTRY(aesni_cbc_enc) */ ENTRY(aesni_cbc_dec) cmp $16, LEN - jb .Lcbc_dec_ret + jb .Lcbc_dec_just_ret mov 480(KEYP), KLEN add $240, KEYP movups (IVP), IV @@ -891,6 +891,7 @@ ENTRY(aesni_cbc_dec) add $16, OUTP cmp $16, LEN jge .Lcbc_dec_loop1 - movups IV, (IVP) .Lcbc_dec_ret: + movups IV, (IVP) +.Lcbc_dec_just_ret: ret diff --git a/arch/x86/crypto/aesni-intel_glue.c b/arch/x86/crypto/aesni-intel_glue.c index 02af0af65497..c580c5ec1cad 100644 --- a/arch/x86/crypto/aesni-intel_glue.c +++ b/arch/x86/crypto/aesni-intel_glue.c @@ -21,6 +21,22 @@ #include #include +#if defined(CONFIG_CRYPTO_CTR) || defined(CONFIG_CRYPTO_CTR_MODULE) +#define HAS_CTR +#endif + +#if defined(CONFIG_CRYPTO_LRW) || defined(CONFIG_CRYPTO_LRW_MODULE) +#define HAS_LRW +#endif + +#if defined(CONFIG_CRYPTO_PCBC) || defined(CONFIG_CRYPTO_PCBC_MODULE) +#define HAS_PCBC +#endif + +#if defined(CONFIG_CRYPTO_XTS) || defined(CONFIG_CRYPTO_XTS_MODULE) +#define HAS_XTS +#endif + struct async_aes_ctx { struct cryptd_ablkcipher *cryptd_tfm; }; @@ -137,6 +153,41 @@ static struct crypto_alg aesni_alg = { } }; +static void __aes_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) +{ + struct crypto_aes_ctx *ctx = aes_ctx(crypto_tfm_ctx(tfm)); + + aesni_enc(ctx, dst, src); +} + +static void __aes_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) +{ + struct crypto_aes_ctx *ctx = aes_ctx(crypto_tfm_ctx(tfm)); + + aesni_dec(ctx, dst, src); +} + +static struct crypto_alg __aesni_alg = { + .cra_name = "__aes-aesni", + .cra_driver_name = "__driver-aes-aesni", + .cra_priority = 0, + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct crypto_aes_ctx)+AESNI_ALIGN-1, + .cra_alignmask = 0, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(__aesni_alg.cra_list), + .cra_u = { + .cipher = { + .cia_min_keysize = AES_MIN_KEY_SIZE, + .cia_max_keysize = AES_MAX_KEY_SIZE, + .cia_setkey = aes_set_key, + .cia_encrypt = __aes_encrypt, + .cia_decrypt = __aes_decrypt + } + } +}; + static int ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes) @@ -147,6 +198,7 @@ static int ecb_encrypt(struct blkcipher_desc *desc, blkcipher_walk_init(&walk, dst, src, nbytes); err = blkcipher_walk_virt(desc, &walk); + desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; kernel_fpu_begin(); while ((nbytes = walk.nbytes)) { @@ -170,6 +222,7 @@ static int ecb_decrypt(struct blkcipher_desc *desc, blkcipher_walk_init(&walk, dst, src, nbytes); err = blkcipher_walk_virt(desc, &walk); + desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; kernel_fpu_begin(); while ((nbytes = walk.nbytes)) { @@ -215,6 +268,7 @@ static int cbc_encrypt(struct blkcipher_desc *desc, blkcipher_walk_init(&walk, dst, src, nbytes); err = blkcipher_walk_virt(desc, &walk); + desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; kernel_fpu_begin(); while ((nbytes = walk.nbytes)) { @@ -238,6 +292,7 @@ static int cbc_decrypt(struct blkcipher_desc *desc, blkcipher_walk_init(&walk, dst, src, nbytes); err = blkcipher_walk_virt(desc, &walk); + desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; kernel_fpu_begin(); while ((nbytes = walk.nbytes)) { @@ -277,8 +332,16 @@ static int ablk_set_key(struct crypto_ablkcipher *tfm, const u8 *key, unsigned int key_len) { struct async_aes_ctx *ctx = crypto_ablkcipher_ctx(tfm); + struct crypto_ablkcipher *child = &ctx->cryptd_tfm->base; + int err; - return crypto_ablkcipher_setkey(&ctx->cryptd_tfm->base, key, key_len); + crypto_ablkcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK); + crypto_ablkcipher_set_flags(child, crypto_ablkcipher_get_flags(tfm) + & CRYPTO_TFM_REQ_MASK); + err = crypto_ablkcipher_setkey(child, key, key_len); + crypto_ablkcipher_set_flags(tfm, crypto_ablkcipher_get_flags(child) + & CRYPTO_TFM_RES_MASK); + return err; } static int ablk_encrypt(struct ablkcipher_request *req) @@ -411,6 +474,163 @@ static struct crypto_alg ablk_cbc_alg = { }, }; +#ifdef HAS_CTR +static int ablk_ctr_init(struct crypto_tfm *tfm) +{ + struct cryptd_ablkcipher *cryptd_tfm; + + cryptd_tfm = cryptd_alloc_ablkcipher("fpu(ctr(__driver-aes-aesni))", + 0, 0); + if (IS_ERR(cryptd_tfm)) + return PTR_ERR(cryptd_tfm); + ablk_init_common(tfm, cryptd_tfm); + return 0; +} + +static struct crypto_alg ablk_ctr_alg = { + .cra_name = "ctr(aes)", + .cra_driver_name = "ctr-aes-aesni", + .cra_priority = 400, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC, + .cra_blocksize = 1, + .cra_ctxsize = sizeof(struct async_aes_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(ablk_ctr_alg.cra_list), + .cra_init = ablk_ctr_init, + .cra_exit = ablk_exit, + .cra_u = { + .ablkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + .setkey = ablk_set_key, + .encrypt = ablk_encrypt, + .decrypt = ablk_decrypt, + .geniv = "chainiv", + }, + }, +}; +#endif + +#ifdef HAS_LRW +static int ablk_lrw_init(struct crypto_tfm *tfm) +{ + struct cryptd_ablkcipher *cryptd_tfm; + + cryptd_tfm = cryptd_alloc_ablkcipher("fpu(lrw(__driver-aes-aesni))", + 0, 0); + if (IS_ERR(cryptd_tfm)) + return PTR_ERR(cryptd_tfm); + ablk_init_common(tfm, cryptd_tfm); + return 0; +} + +static struct crypto_alg ablk_lrw_alg = { + .cra_name = "lrw(aes)", + .cra_driver_name = "lrw-aes-aesni", + .cra_priority = 400, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct async_aes_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(ablk_lrw_alg.cra_list), + .cra_init = ablk_lrw_init, + .cra_exit = ablk_exit, + .cra_u = { + .ablkcipher = { + .min_keysize = AES_MIN_KEY_SIZE + AES_BLOCK_SIZE, + .max_keysize = AES_MAX_KEY_SIZE + AES_BLOCK_SIZE, + .ivsize = AES_BLOCK_SIZE, + .setkey = ablk_set_key, + .encrypt = ablk_encrypt, + .decrypt = ablk_decrypt, + }, + }, +}; +#endif + +#ifdef HAS_PCBC +static int ablk_pcbc_init(struct crypto_tfm *tfm) +{ + struct cryptd_ablkcipher *cryptd_tfm; + + cryptd_tfm = cryptd_alloc_ablkcipher("fpu(pcbc(__driver-aes-aesni))", + 0, 0); + if (IS_ERR(cryptd_tfm)) + return PTR_ERR(cryptd_tfm); + ablk_init_common(tfm, cryptd_tfm); + return 0; +} + +static struct crypto_alg ablk_pcbc_alg = { + .cra_name = "pcbc(aes)", + .cra_driver_name = "pcbc-aes-aesni", + .cra_priority = 400, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct async_aes_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(ablk_pcbc_alg.cra_list), + .cra_init = ablk_pcbc_init, + .cra_exit = ablk_exit, + .cra_u = { + .ablkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + .setkey = ablk_set_key, + .encrypt = ablk_encrypt, + .decrypt = ablk_decrypt, + }, + }, +}; +#endif + +#ifdef HAS_XTS +static int ablk_xts_init(struct crypto_tfm *tfm) +{ + struct cryptd_ablkcipher *cryptd_tfm; + + cryptd_tfm = cryptd_alloc_ablkcipher("fpu(xts(__driver-aes-aesni))", + 0, 0); + if (IS_ERR(cryptd_tfm)) + return PTR_ERR(cryptd_tfm); + ablk_init_common(tfm, cryptd_tfm); + return 0; +} + +static struct crypto_alg ablk_xts_alg = { + .cra_name = "xts(aes)", + .cra_driver_name = "xts-aes-aesni", + .cra_priority = 400, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct async_aes_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(ablk_xts_alg.cra_list), + .cra_init = ablk_xts_init, + .cra_exit = ablk_exit, + .cra_u = { + .ablkcipher = { + .min_keysize = 2 * AES_MIN_KEY_SIZE, + .max_keysize = 2 * AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + .setkey = ablk_set_key, + .encrypt = ablk_encrypt, + .decrypt = ablk_decrypt, + }, + }, +}; +#endif + static int __init aesni_init(void) { int err; @@ -421,6 +641,8 @@ static int __init aesni_init(void) } if ((err = crypto_register_alg(&aesni_alg))) goto aes_err; + if ((err = crypto_register_alg(&__aesni_alg))) + goto __aes_err; if ((err = crypto_register_alg(&blk_ecb_alg))) goto blk_ecb_err; if ((err = crypto_register_alg(&blk_cbc_alg))) @@ -429,9 +651,41 @@ static int __init aesni_init(void) goto ablk_ecb_err; if ((err = crypto_register_alg(&ablk_cbc_alg))) goto ablk_cbc_err; +#ifdef HAS_CTR + if ((err = crypto_register_alg(&ablk_ctr_alg))) + goto ablk_ctr_err; +#endif +#ifdef HAS_LRW + if ((err = crypto_register_alg(&ablk_lrw_alg))) + goto ablk_lrw_err; +#endif +#ifdef HAS_PCBC + if ((err = crypto_register_alg(&ablk_pcbc_alg))) + goto ablk_pcbc_err; +#endif +#ifdef HAS_XTS + if ((err = crypto_register_alg(&ablk_xts_alg))) + goto ablk_xts_err; +#endif return err; +#ifdef HAS_XTS +ablk_xts_err: +#endif +#ifdef HAS_PCBC + crypto_unregister_alg(&ablk_pcbc_alg); +ablk_pcbc_err: +#endif +#ifdef HAS_LRW + crypto_unregister_alg(&ablk_lrw_alg); +ablk_lrw_err: +#endif +#ifdef HAS_CTR + crypto_unregister_alg(&ablk_ctr_alg); +ablk_ctr_err: +#endif + crypto_unregister_alg(&ablk_cbc_alg); ablk_cbc_err: crypto_unregister_alg(&ablk_ecb_alg); ablk_ecb_err: @@ -439,6 +693,8 @@ ablk_ecb_err: blk_cbc_err: crypto_unregister_alg(&blk_ecb_alg); blk_ecb_err: + crypto_unregister_alg(&__aesni_alg); +__aes_err: crypto_unregister_alg(&aesni_alg); aes_err: return err; @@ -446,10 +702,23 @@ aes_err: static void __exit aesni_exit(void) { +#ifdef HAS_XTS + crypto_unregister_alg(&ablk_xts_alg); +#endif +#ifdef HAS_PCBC + crypto_unregister_alg(&ablk_pcbc_alg); +#endif +#ifdef HAS_LRW + crypto_unregister_alg(&ablk_lrw_alg); +#endif +#ifdef HAS_CTR + crypto_unregister_alg(&ablk_ctr_alg); +#endif crypto_unregister_alg(&ablk_cbc_alg); crypto_unregister_alg(&ablk_ecb_alg); crypto_unregister_alg(&blk_cbc_alg); crypto_unregister_alg(&blk_ecb_alg); + crypto_unregister_alg(&__aesni_alg); crypto_unregister_alg(&aesni_alg); } diff --git a/arch/x86/crypto/fpu.c b/arch/x86/crypto/fpu.c new file mode 100644 index 000000000000..daef6cd2b45d --- /dev/null +++ b/arch/x86/crypto/fpu.c @@ -0,0 +1,166 @@ +/* + * FPU: Wrapper for blkcipher touching fpu + * + * Copyright (c) Intel Corp. + * Author: Huang Ying + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ + +#include +#include +#include +#include +#include +#include + +struct crypto_fpu_ctx { + struct crypto_blkcipher *child; +}; + +static int crypto_fpu_setkey(struct crypto_tfm *parent, const u8 *key, + unsigned int keylen) +{ + struct crypto_fpu_ctx *ctx = crypto_tfm_ctx(parent); + struct crypto_blkcipher *child = ctx->child; + int err; + + crypto_blkcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK); + crypto_blkcipher_set_flags(child, crypto_tfm_get_flags(parent) & + CRYPTO_TFM_REQ_MASK); + err = crypto_blkcipher_setkey(child, key, keylen); + crypto_tfm_set_flags(parent, crypto_blkcipher_get_flags(child) & + CRYPTO_TFM_RES_MASK); + return err; +} + +static int crypto_fpu_encrypt(struct blkcipher_desc *desc_in, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + int err; + struct crypto_fpu_ctx *ctx = crypto_blkcipher_ctx(desc_in->tfm); + struct crypto_blkcipher *child = ctx->child; + struct blkcipher_desc desc = { + .tfm = child, + .info = desc_in->info, + .flags = desc_in->flags & ~CRYPTO_TFM_REQ_MAY_SLEEP, + }; + + kernel_fpu_begin(); + err = crypto_blkcipher_crt(desc.tfm)->encrypt(&desc, dst, src, nbytes); + kernel_fpu_end(); + return err; +} + +static int crypto_fpu_decrypt(struct blkcipher_desc *desc_in, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + int err; + struct crypto_fpu_ctx *ctx = crypto_blkcipher_ctx(desc_in->tfm); + struct crypto_blkcipher *child = ctx->child; + struct blkcipher_desc desc = { + .tfm = child, + .info = desc_in->info, + .flags = desc_in->flags & ~CRYPTO_TFM_REQ_MAY_SLEEP, + }; + + kernel_fpu_begin(); + err = crypto_blkcipher_crt(desc.tfm)->decrypt(&desc, dst, src, nbytes); + kernel_fpu_end(); + return err; +} + +static int crypto_fpu_init_tfm(struct crypto_tfm *tfm) +{ + struct crypto_instance *inst = crypto_tfm_alg_instance(tfm); + struct crypto_spawn *spawn = crypto_instance_ctx(inst); + struct crypto_fpu_ctx *ctx = crypto_tfm_ctx(tfm); + struct crypto_blkcipher *cipher; + + cipher = crypto_spawn_blkcipher(spawn); + if (IS_ERR(cipher)) + return PTR_ERR(cipher); + + ctx->child = cipher; + return 0; +} + +static void crypto_fpu_exit_tfm(struct crypto_tfm *tfm) +{ + struct crypto_fpu_ctx *ctx = crypto_tfm_ctx(tfm); + crypto_free_blkcipher(ctx->child); +} + +static struct crypto_instance *crypto_fpu_alloc(struct rtattr **tb) +{ + struct crypto_instance *inst; + struct crypto_alg *alg; + int err; + + err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_BLKCIPHER); + if (err) + return ERR_PTR(err); + + alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_BLKCIPHER, + CRYPTO_ALG_TYPE_MASK); + if (IS_ERR(alg)) + return ERR_CAST(alg); + + inst = crypto_alloc_instance("fpu", alg); + if (IS_ERR(inst)) + goto out_put_alg; + + inst->alg.cra_flags = alg->cra_flags; + inst->alg.cra_priority = alg->cra_priority; + inst->alg.cra_blocksize = alg->cra_blocksize; + inst->alg.cra_alignmask = alg->cra_alignmask; + inst->alg.cra_type = alg->cra_type; + inst->alg.cra_blkcipher.ivsize = alg->cra_blkcipher.ivsize; + inst->alg.cra_blkcipher.min_keysize = alg->cra_blkcipher.min_keysize; + inst->alg.cra_blkcipher.max_keysize = alg->cra_blkcipher.max_keysize; + inst->alg.cra_ctxsize = sizeof(struct crypto_fpu_ctx); + inst->alg.cra_init = crypto_fpu_init_tfm; + inst->alg.cra_exit = crypto_fpu_exit_tfm; + inst->alg.cra_blkcipher.setkey = crypto_fpu_setkey; + inst->alg.cra_blkcipher.encrypt = crypto_fpu_encrypt; + inst->alg.cra_blkcipher.decrypt = crypto_fpu_decrypt; + +out_put_alg: + crypto_mod_put(alg); + return inst; +} + +static void crypto_fpu_free(struct crypto_instance *inst) +{ + crypto_drop_spawn(crypto_instance_ctx(inst)); + kfree(inst); +} + +static struct crypto_template crypto_fpu_tmpl = { + .name = "fpu", + .alloc = crypto_fpu_alloc, + .free = crypto_fpu_free, + .module = THIS_MODULE, +}; + +static int __init crypto_fpu_module_init(void) +{ + return crypto_register_template(&crypto_fpu_tmpl); +} + +static void __exit crypto_fpu_module_exit(void) +{ + crypto_unregister_template(&crypto_fpu_tmpl); +} + +module_init(crypto_fpu_module_init); +module_exit(crypto_fpu_module_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("FPU block cipher wrapper"); diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S index a505202086e8..e590261ba059 100644 --- a/arch/x86/ia32/ia32entry.S +++ b/arch/x86/ia32/ia32entry.S @@ -825,9 +825,11 @@ ia32_sys_call_table: .quad compat_sys_signalfd4 .quad sys_eventfd2 .quad sys_epoll_create1 - .quad sys_dup3 /* 330 */ + .quad sys_dup3 /* 330 */ .quad sys_pipe2 .quad sys_inotify_init1 .quad compat_sys_preadv .quad compat_sys_pwritev + .quad compat_sys_rt_tgsigqueueinfo /* 335 */ + .quad sys_perf_counter_open ia32_syscall_end: diff --git a/arch/x86/include/asm/acpi.h b/arch/x86/include/asm/acpi.h index 4518dc500903..20d1465a2ab0 100644 --- a/arch/x86/include/asm/acpi.h +++ b/arch/x86/include/asm/acpi.h @@ -144,6 +144,7 @@ static inline unsigned int acpi_processor_cstate_check(unsigned int max_cstate) #else /* !CONFIG_ACPI */ +#define acpi_disabled 1 #define acpi_lapic 0 #define acpi_ioapic 0 static inline void acpi_noirq_set(void) { } diff --git a/arch/x86/include/asm/alternative.h b/arch/x86/include/asm/alternative.h index f6aa18eadf71..1a37bcdc8606 100644 --- a/arch/x86/include/asm/alternative.h +++ b/arch/x86/include/asm/alternative.h @@ -3,6 +3,7 @@ #include #include +#include #include /* @@ -74,6 +75,22 @@ static inline void alternatives_smp_switch(int smp) {} const unsigned char *const *find_nop_table(void); +/* alternative assembly primitive: */ +#define ALTERNATIVE(oldinstr, newinstr, feature) \ + \ + "661:\n\t" oldinstr "\n662:\n" \ + ".section .altinstructions,\"a\"\n" \ + _ASM_ALIGN "\n" \ + _ASM_PTR "661b\n" /* label */ \ + _ASM_PTR "663f\n" /* new instruction */ \ + " .byte " __stringify(feature) "\n" /* feature bit */ \ + " .byte 662b-661b\n" /* sourcelen */ \ + " .byte 664f-663f\n" /* replacementlen */ \ + ".previous\n" \ + ".section .altinstr_replacement, \"ax\"\n" \ + "663:\n\t" newinstr "\n664:\n" /* replacement */ \ + ".previous" + /* * Alternative instructions for different CPU types or capabilities. * @@ -87,18 +104,7 @@ const unsigned char *const *find_nop_table(void); * without volatile and memory clobber. */ #define alternative(oldinstr, newinstr, feature) \ - asm volatile ("661:\n\t" oldinstr "\n662:\n" \ - ".section .altinstructions,\"a\"\n" \ - _ASM_ALIGN "\n" \ - _ASM_PTR "661b\n" /* label */ \ - _ASM_PTR "663f\n" /* new instruction */ \ - " .byte %c0\n" /* feature bit */ \ - " .byte 662b-661b\n" /* sourcelen */ \ - " .byte 664f-663f\n" /* replacementlen */ \ - ".previous\n" \ - ".section .altinstr_replacement,\"ax\"\n" \ - "663:\n\t" newinstr "\n664:\n" /* replacement */ \ - ".previous" :: "i" (feature) : "memory") + asm volatile (ALTERNATIVE(oldinstr, newinstr, feature) : : : "memory") /* * Alternative inline assembly with input. @@ -109,35 +115,16 @@ const unsigned char *const *find_nop_table(void); * Best is to use constraints that are fixed size (like (%1) ... "r") * If you use variable sized constraints like "m" or "g" in the * replacement make sure to pad to the worst case length. + * Leaving an unused argument 0 to keep API compatibility. */ #define alternative_input(oldinstr, newinstr, feature, input...) \ - asm volatile ("661:\n\t" oldinstr "\n662:\n" \ - ".section .altinstructions,\"a\"\n" \ - _ASM_ALIGN "\n" \ - _ASM_PTR "661b\n" /* label */ \ - _ASM_PTR "663f\n" /* new instruction */ \ - " .byte %c0\n" /* feature bit */ \ - " .byte 662b-661b\n" /* sourcelen */ \ - " .byte 664f-663f\n" /* replacementlen */ \ - ".previous\n" \ - ".section .altinstr_replacement,\"ax\"\n" \ - "663:\n\t" newinstr "\n664:\n" /* replacement */ \ - ".previous" :: "i" (feature), ##input) + asm volatile (ALTERNATIVE(oldinstr, newinstr, feature) \ + : : "i" (0), ## input) /* Like alternative_input, but with a single output argument */ #define alternative_io(oldinstr, newinstr, feature, output, input...) \ - asm volatile ("661:\n\t" oldinstr "\n662:\n" \ - ".section .altinstructions,\"a\"\n" \ - _ASM_ALIGN "\n" \ - _ASM_PTR "661b\n" /* label */ \ - _ASM_PTR "663f\n" /* new instruction */ \ - " .byte %c[feat]\n" /* feature bit */ \ - " .byte 662b-661b\n" /* sourcelen */ \ - " .byte 664f-663f\n" /* replacementlen */ \ - ".previous\n" \ - ".section .altinstr_replacement,\"ax\"\n" \ - "663:\n\t" newinstr "\n664:\n" /* replacement */ \ - ".previous" : output : [feat] "i" (feature), ##input) + asm volatile (ALTERNATIVE(oldinstr, newinstr, feature) \ + : output : "i" (0), ## input) /* * use this macro(s) if you need more than one output parameter diff --git a/arch/x86/include/asm/amd_iommu.h b/arch/x86/include/asm/amd_iommu.h index f712344329bc..bdf96f119f06 100644 --- a/arch/x86/include/asm/amd_iommu.h +++ b/arch/x86/include/asm/amd_iommu.h @@ -27,9 +27,13 @@ extern int amd_iommu_init(void); extern int amd_iommu_init_dma_ops(void); extern void amd_iommu_detect(void); extern irqreturn_t amd_iommu_int_handler(int irq, void *data); +extern void amd_iommu_flush_all_domains(void); +extern void amd_iommu_flush_all_devices(void); +extern void amd_iommu_shutdown(void); #else static inline int amd_iommu_init(void) { return -ENODEV; } static inline void amd_iommu_detect(void) { } +static inline void amd_iommu_shutdown(void) { } #endif #endif /* _ASM_X86_AMD_IOMMU_H */ diff --git a/arch/x86/include/asm/amd_iommu_types.h b/arch/x86/include/asm/amd_iommu_types.h index 95c8cd9d22b5..0c878caaa0a2 100644 --- a/arch/x86/include/asm/amd_iommu_types.h +++ b/arch/x86/include/asm/amd_iommu_types.h @@ -194,6 +194,27 @@ #define PD_DMA_OPS_MASK (1UL << 0) /* domain used for dma_ops */ #define PD_DEFAULT_MASK (1UL << 1) /* domain is a default dma_ops domain for an IOMMU */ +extern bool amd_iommu_dump; +#define DUMP_printk(format, arg...) \ + do { \ + if (amd_iommu_dump) \ + printk(KERN_INFO "AMD IOMMU: " format, ## arg); \ + } while(0); + +/* + * Make iterating over all IOMMUs easier + */ +#define for_each_iommu(iommu) \ + list_for_each_entry((iommu), &amd_iommu_list, list) +#define for_each_iommu_safe(iommu, next) \ + list_for_each_entry_safe((iommu), (next), &amd_iommu_list, list) + +#define APERTURE_RANGE_SHIFT 27 /* 128 MB */ +#define APERTURE_RANGE_SIZE (1ULL << APERTURE_RANGE_SHIFT) +#define APERTURE_RANGE_PAGES (APERTURE_RANGE_SIZE >> PAGE_SHIFT) +#define APERTURE_MAX_RANGES 32 /* allows 4GB of DMA address space */ +#define APERTURE_RANGE_INDEX(a) ((a) >> APERTURE_RANGE_SHIFT) +#define APERTURE_PAGE_INDEX(a) (((a) >> 21) & 0x3fULL) /* * This structure contains generic data for IOMMU protection domains @@ -209,6 +230,26 @@ struct protection_domain { void *priv; /* private data */ }; +/* + * For dynamic growth the aperture size is split into ranges of 128MB of + * DMA address space each. This struct represents one such range. + */ +struct aperture_range { + + /* 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[64]; + + unsigned long offset; +}; + /* * Data container for a dma_ops specific protection domain */ @@ -222,18 +263,10 @@ struct dma_ops_domain { unsigned long aperture_size; /* address we start to search for free addresses */ - unsigned long next_bit; + unsigned long next_address; - /* 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; + /* address space relevant data */ + struct aperture_range *aperture[APERTURE_MAX_RANGES]; /* This will be set to true when TLB needs to be flushed */ bool need_flush; diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h index 42f2f8377422..bb7d47925847 100644 --- a/arch/x86/include/asm/apic.h +++ b/arch/x86/include/asm/apic.h @@ -107,8 +107,7 @@ extern u32 native_safe_apic_wait_icr_idle(void); extern void native_apic_icr_write(u32 low, u32 id); extern u64 native_apic_icr_read(void); -#define EIM_8BIT_APIC_ID 0 -#define EIM_32BIT_APIC_ID 1 +extern int x2apic_mode; #ifdef CONFIG_X86_X2APIC /* @@ -166,10 +165,9 @@ static inline u64 native_x2apic_icr_read(void) return val; } -extern int x2apic, x2apic_phys; +extern int x2apic_phys; extern void check_x2apic(void); extern void enable_x2apic(void); -extern void enable_IR_x2apic(void); extern void x2apic_icr_write(u32 low, u32 id); static inline int x2apic_enabled(void) { @@ -183,6 +181,8 @@ static inline int x2apic_enabled(void) return 1; return 0; } + +#define x2apic_supported() (cpu_has_x2apic) #else static inline void check_x2apic(void) { @@ -190,28 +190,20 @@ static inline void check_x2apic(void) static inline void enable_x2apic(void) { } -static inline void enable_IR_x2apic(void) -{ -} static inline int x2apic_enabled(void) { return 0; } -#define x2apic 0 - +#define x2apic_preenabled 0 +#define x2apic_supported() 0 #endif +extern void enable_IR_x2apic(void); + extern int get_physical_broadcast(void); -#ifdef CONFIG_X86_X2APIC -static inline void ack_x2APIC_irq(void) -{ - /* Docs say use 0 for future compatibility */ - native_apic_msr_write(APIC_EOI, 0); -} -#endif - +extern void apic_disable(void); extern int lapic_get_maxlvt(void); extern void clear_local_APIC(void); extern void connect_bsp_APIC(void); @@ -252,7 +244,7 @@ static inline void lapic_shutdown(void) { } #define local_apic_timer_c2_ok 1 static inline void init_apic_mappings(void) { } static inline void disable_local_APIC(void) { } - +static inline void apic_disable(void) { } #endif /* !CONFIG_X86_LOCAL_APIC */ #ifdef CONFIG_X86_64 @@ -410,7 +402,7 @@ static inline unsigned default_get_apic_id(unsigned long x) { unsigned int ver = GET_APIC_VERSION(apic_read(APIC_LVR)); - if (APIC_XAPIC(ver)) + if (APIC_XAPIC(ver) || boot_cpu_has(X86_FEATURE_EXTD_APICID)) return (x >> 24) & 0xFF; else return (x >> 24) & 0x0F; @@ -478,6 +470,9 @@ static inline unsigned int read_apic_id(void) extern void default_setup_apic_routing(void); #ifdef CONFIG_X86_32 + +extern struct apic apic_default; + /* * Set up the logical destination ID. * diff --git a/arch/x86/include/asm/apicdef.h b/arch/x86/include/asm/apicdef.h index bc9514fb3b13..7ddb36ab933b 100644 --- a/arch/x86/include/asm/apicdef.h +++ b/arch/x86/include/asm/apicdef.h @@ -22,6 +22,7 @@ # define APIC_INTEGRATED(x) (1) #endif #define APIC_XAPIC(x) ((x) >= 0x14) +#define APIC_EXT_SPACE(x) ((x) & 0x80000000) #define APIC_TASKPRI 0x80 #define APIC_TPRI_MASK 0xFFu #define APIC_ARBPRI 0x90 @@ -116,7 +117,9 @@ #define APIC_TDR_DIV_32 0x8 #define APIC_TDR_DIV_64 0x9 #define APIC_TDR_DIV_128 0xA -#define APIC_EILVT0 0x500 +#define APIC_EFEAT 0x400 +#define APIC_ECTRL 0x410 +#define APIC_EILVTn(n) (0x500 + 0x10 * n) #define APIC_EILVT_NR_AMD_K8 1 /* # of extended interrupts */ #define APIC_EILVT_NR_AMD_10H 4 #define APIC_EILVT_LVTOFF(x) (((x) >> 4) & 0xF) @@ -125,9 +128,6 @@ #define APIC_EILVT_MSG_NMI 0x4 #define APIC_EILVT_MSG_EXT 0x7 #define APIC_EILVT_MASKED (1 << 16) -#define APIC_EILVT1 0x510 -#define APIC_EILVT2 0x520 -#define APIC_EILVT3 0x530 #define APIC_BASE (fix_to_virt(FIX_APIC_BASE)) #define APIC_BASE_MSR 0x800 diff --git a/arch/x86/include/asm/atomic_32.h b/arch/x86/include/asm/atomic_32.h index 85b46fba4229..2503d4e64c2a 100644 --- a/arch/x86/include/asm/atomic_32.h +++ b/arch/x86/include/asm/atomic_32.h @@ -247,5 +247,240 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u) #define smp_mb__before_atomic_inc() barrier() #define smp_mb__after_atomic_inc() barrier() -#include +/* An 64bit atomic type */ + +typedef struct { + unsigned long long counter; +} atomic64_t; + +#define ATOMIC64_INIT(val) { (val) } + +/** + * atomic64_read - read atomic64 variable + * @ptr: pointer of type atomic64_t + * + * Atomically reads the value of @v. + * Doesn't imply a read memory barrier. + */ +#define __atomic64_read(ptr) ((ptr)->counter) + +static inline unsigned long long +cmpxchg8b(unsigned long long *ptr, unsigned long long old, unsigned long long new) +{ + asm volatile( + + LOCK_PREFIX "cmpxchg8b (%[ptr])\n" + + : "=A" (old) + + : [ptr] "D" (ptr), + "A" (old), + "b" (ll_low(new)), + "c" (ll_high(new)) + + : "memory"); + + return old; +} + +static inline unsigned long long +atomic64_cmpxchg(atomic64_t *ptr, unsigned long long old_val, + unsigned long long new_val) +{ + return cmpxchg8b(&ptr->counter, old_val, new_val); +} + +/** + * atomic64_xchg - xchg atomic64 variable + * @ptr: pointer to type atomic64_t + * @new_val: value to assign + * + * Atomically xchgs the value of @ptr to @new_val and returns + * the old value. + */ + +static inline unsigned long long +atomic64_xchg(atomic64_t *ptr, unsigned long long new_val) +{ + unsigned long long old_val; + + do { + old_val = atomic_read(ptr); + } while (atomic64_cmpxchg(ptr, old_val, new_val) != old_val); + + return old_val; +} + +/** + * atomic64_set - set atomic64 variable + * @ptr: pointer to type atomic64_t + * @new_val: value to assign + * + * Atomically sets the value of @ptr to @new_val. + */ +static inline void atomic64_set(atomic64_t *ptr, unsigned long long new_val) +{ + atomic64_xchg(ptr, new_val); +} + +/** + * atomic64_read - read atomic64 variable + * @ptr: pointer to type atomic64_t + * + * Atomically reads the value of @ptr and returns it. + */ +static inline unsigned long long atomic64_read(atomic64_t *ptr) +{ + unsigned long long curr_val; + + do { + curr_val = __atomic64_read(ptr); + } while (atomic64_cmpxchg(ptr, curr_val, curr_val) != curr_val); + + return curr_val; +} + +/** + * atomic64_add_return - add and return + * @delta: integer value to add + * @ptr: pointer to type atomic64_t + * + * Atomically adds @delta to @ptr and returns @delta + *@ptr + */ +static inline unsigned long long +atomic64_add_return(unsigned long long delta, atomic64_t *ptr) +{ + unsigned long long old_val, new_val; + + do { + old_val = atomic_read(ptr); + new_val = old_val + delta; + + } while (atomic64_cmpxchg(ptr, old_val, new_val) != old_val); + + return new_val; +} + +static inline long atomic64_sub_return(unsigned long long delta, atomic64_t *ptr) +{ + return atomic64_add_return(-delta, ptr); +} + +static inline long atomic64_inc_return(atomic64_t *ptr) +{ + return atomic64_add_return(1, ptr); +} + +static inline long atomic64_dec_return(atomic64_t *ptr) +{ + return atomic64_sub_return(1, ptr); +} + +/** + * atomic64_add - add integer to atomic64 variable + * @delta: integer value to add + * @ptr: pointer to type atomic64_t + * + * Atomically adds @delta to @ptr. + */ +static inline void atomic64_add(unsigned long long delta, atomic64_t *ptr) +{ + atomic64_add_return(delta, ptr); +} + +/** + * atomic64_sub - subtract the atomic64 variable + * @delta: integer value to subtract + * @ptr: pointer to type atomic64_t + * + * Atomically subtracts @delta from @ptr. + */ +static inline void atomic64_sub(unsigned long long delta, atomic64_t *ptr) +{ + atomic64_add(-delta, ptr); +} + +/** + * atomic64_sub_and_test - subtract value from variable and test result + * @delta: integer value to subtract + * @ptr: pointer to type atomic64_t + * + * Atomically subtracts @delta from @ptr and returns + * true if the result is zero, or false for all + * other cases. + */ +static inline int +atomic64_sub_and_test(unsigned long long delta, atomic64_t *ptr) +{ + unsigned long long old_val = atomic64_sub_return(delta, ptr); + + return old_val == 0; +} + +/** + * atomic64_inc - increment atomic64 variable + * @ptr: pointer to type atomic64_t + * + * Atomically increments @ptr by 1. + */ +static inline void atomic64_inc(atomic64_t *ptr) +{ + atomic64_add(1, ptr); +} + +/** + * atomic64_dec - decrement atomic64 variable + * @ptr: pointer to type atomic64_t + * + * Atomically decrements @ptr by 1. + */ +static inline void atomic64_dec(atomic64_t *ptr) +{ + atomic64_sub(1, ptr); +} + +/** + * atomic64_dec_and_test - decrement and test + * @ptr: pointer to type atomic64_t + * + * Atomically decrements @ptr by 1 and + * returns true if the result is 0, or false for all other + * cases. + */ +static inline int atomic64_dec_and_test(atomic64_t *ptr) +{ + return atomic64_sub_and_test(1, ptr); +} + +/** + * atomic64_inc_and_test - increment and test + * @ptr: pointer to type atomic64_t + * + * Atomically increments @ptr by 1 + * and returns true if the result is zero, or false for all + * other cases. + */ +static inline int atomic64_inc_and_test(atomic64_t *ptr) +{ + return atomic64_sub_and_test(-1, ptr); +} + +/** + * atomic64_add_negative - add and test if negative + * @delta: integer value to add + * @ptr: pointer to type atomic64_t + * + * Atomically adds @delta to @ptr and returns true + * if the result is negative, or false when + * result is greater than or equal to zero. + */ +static inline int +atomic64_add_negative(unsigned long long delta, atomic64_t *ptr) +{ + long long old_val = atomic64_add_return(delta, ptr); + + return old_val < 0; +} + +#include #endif /* _ASM_X86_ATOMIC_32_H */ diff --git a/arch/x86/include/asm/atomic_64.h b/arch/x86/include/asm/atomic_64.h index 8c21731984da..0d6360220007 100644 --- a/arch/x86/include/asm/atomic_64.h +++ b/arch/x86/include/asm/atomic_64.h @@ -455,5 +455,5 @@ static inline void atomic_or_long(unsigned long *v1, unsigned long v2) #define smp_mb__before_atomic_inc() barrier() #define smp_mb__after_atomic_inc() barrier() -#include +#include #endif /* _ASM_X86_ATOMIC_64_H */ diff --git a/arch/x86/include/asm/bitsperlong.h b/arch/x86/include/asm/bitsperlong.h new file mode 100644 index 000000000000..b0ae1c4dc791 --- /dev/null +++ b/arch/x86/include/asm/bitsperlong.h @@ -0,0 +1,13 @@ +#ifndef __ASM_X86_BITSPERLONG_H +#define __ASM_X86_BITSPERLONG_H + +#ifdef __x86_64__ +# define __BITS_PER_LONG 64 +#else +# define __BITS_PER_LONG 32 +#endif + +#include + +#endif /* __ASM_X86_BITSPERLONG_H */ + diff --git a/arch/x86/include/asm/boot.h b/arch/x86/include/asm/boot.h index 6ba23dd9fc92..418e632d4a80 100644 --- a/arch/x86/include/asm/boot.h +++ b/arch/x86/include/asm/boot.h @@ -8,11 +8,26 @@ #ifdef __KERNEL__ +#include + /* Physical address where kernel should be loaded. */ #define LOAD_PHYSICAL_ADDR ((CONFIG_PHYSICAL_START \ + (CONFIG_PHYSICAL_ALIGN - 1)) \ & ~(CONFIG_PHYSICAL_ALIGN - 1)) +/* Minimum kernel alignment, as a power of two */ +#ifdef CONFIG_x86_64 +#define MIN_KERNEL_ALIGN_LG2 PMD_SHIFT +#else +#define MIN_KERNEL_ALIGN_LG2 (PAGE_SHIFT+1) +#endif +#define MIN_KERNEL_ALIGN (_AC(1, UL) << MIN_KERNEL_ALIGN_LG2) + +#if (CONFIG_PHYSICAL_ALIGN & (CONFIG_PHYSICAL_ALIGN-1)) || \ + (CONFIG_PHYSICAL_ALIGN < (_AC(1, UL) << MIN_KERNEL_ALIGN_LG2)) +#error "Invalid value for CONFIG_PHYSICAL_ALIGN" +#endif + #ifdef CONFIG_KERNEL_BZIP2 #define BOOT_HEAP_SIZE 0x400000 #else /* !CONFIG_KERNEL_BZIP2 */ diff --git a/arch/x86/include/asm/bootparam.h b/arch/x86/include/asm/bootparam.h index 433adaebf9b6..1724e8de317c 100644 --- a/arch/x86/include/asm/bootparam.h +++ b/arch/x86/include/asm/bootparam.h @@ -50,7 +50,8 @@ struct setup_header { __u32 ramdisk_size; __u32 bootsect_kludge; __u16 heap_end_ptr; - __u16 _pad1; + __u8 ext_loader_ver; + __u8 ext_loader_type; __u32 cmd_line_ptr; __u32 initrd_addr_max; __u32 kernel_alignment; diff --git a/arch/x86/include/asm/cpu_debug.h b/arch/x86/include/asm/cpu_debug.h index 222802029fa6..d96c1ee3a95c 100644 --- a/arch/x86/include/asm/cpu_debug.h +++ b/arch/x86/include/asm/cpu_debug.h @@ -86,105 +86,7 @@ enum cpu_file_bit { CPU_VALUE_BIT, /* value */ }; -#define CPU_FILE_VALUE (1 << CPU_VALUE_BIT) - -/* - * DisplayFamily_DisplayModel Processor Families/Processor Number Series - * -------------------------- ------------------------------------------ - * 05_01, 05_02, 05_04 Pentium, Pentium with MMX - * - * 06_01 Pentium Pro - * 06_03, 06_05 Pentium II Xeon, Pentium II - * 06_07, 06_08, 06_0A, 06_0B Pentium III Xeon, Pentum III - * - * 06_09, 060D Pentium M - * - * 06_0E Core Duo, Core Solo - * - * 06_0F Xeon 3000, 3200, 5100, 5300, 7300 series, - * Core 2 Quad, Core 2 Extreme, Core 2 Duo, - * Pentium dual-core - * 06_17 Xeon 5200, 5400 series, Core 2 Quad Q9650 - * - * 06_1C Atom - * - * 0F_00, 0F_01, 0F_02 Xeon, Xeon MP, Pentium 4 - * 0F_03, 0F_04 Xeon, Xeon MP, Pentium 4, Pentium D - * - * 0F_06 Xeon 7100, 5000 Series, Xeon MP, - * Pentium 4, Pentium D - */ - -/* Register processors bits */ -enum cpu_processor_bit { - CPU_NONE, -/* Intel */ - CPU_INTEL_PENTIUM_BIT, - CPU_INTEL_P6_BIT, - CPU_INTEL_PENTIUM_M_BIT, - CPU_INTEL_CORE_BIT, - CPU_INTEL_CORE2_BIT, - CPU_INTEL_ATOM_BIT, - CPU_INTEL_XEON_P4_BIT, - CPU_INTEL_XEON_MP_BIT, -/* AMD */ - CPU_AMD_K6_BIT, - CPU_AMD_K7_BIT, - CPU_AMD_K8_BIT, - CPU_AMD_0F_BIT, - CPU_AMD_10_BIT, - CPU_AMD_11_BIT, -}; - -#define CPU_INTEL_PENTIUM (1 << CPU_INTEL_PENTIUM_BIT) -#define CPU_INTEL_P6 (1 << CPU_INTEL_P6_BIT) -#define CPU_INTEL_PENTIUM_M (1 << CPU_INTEL_PENTIUM_M_BIT) -#define CPU_INTEL_CORE (1 << CPU_INTEL_CORE_BIT) -#define CPU_INTEL_CORE2 (1 << CPU_INTEL_CORE2_BIT) -#define CPU_INTEL_ATOM (1 << CPU_INTEL_ATOM_BIT) -#define CPU_INTEL_XEON_P4 (1 << CPU_INTEL_XEON_P4_BIT) -#define CPU_INTEL_XEON_MP (1 << CPU_INTEL_XEON_MP_BIT) - -#define CPU_INTEL_PX (CPU_INTEL_P6 | CPU_INTEL_PENTIUM_M) -#define CPU_INTEL_COREX (CPU_INTEL_CORE | CPU_INTEL_CORE2) -#define CPU_INTEL_XEON (CPU_INTEL_XEON_P4 | CPU_INTEL_XEON_MP) -#define CPU_CO_AT (CPU_INTEL_CORE | CPU_INTEL_ATOM) -#define CPU_C2_AT (CPU_INTEL_CORE2 | CPU_INTEL_ATOM) -#define CPU_CX_AT (CPU_INTEL_COREX | CPU_INTEL_ATOM) -#define CPU_CX_XE (CPU_INTEL_COREX | CPU_INTEL_XEON) -#define CPU_P6_XE (CPU_INTEL_P6 | CPU_INTEL_XEON) -#define CPU_PM_CO_AT (CPU_INTEL_PENTIUM_M | CPU_CO_AT) -#define CPU_C2_AT_XE (CPU_C2_AT | CPU_INTEL_XEON) -#define CPU_CX_AT_XE (CPU_CX_AT | CPU_INTEL_XEON) -#define CPU_P6_CX_AT (CPU_INTEL_P6 | CPU_CX_AT) -#define CPU_P6_CX_XE (CPU_P6_XE | CPU_INTEL_COREX) -#define CPU_P6_CX_AT_XE (CPU_INTEL_P6 | CPU_CX_AT_XE) -#define CPU_PM_CX_AT_XE (CPU_INTEL_PENTIUM_M | CPU_CX_AT_XE) -#define CPU_PM_CX_AT (CPU_INTEL_PENTIUM_M | CPU_CX_AT) -#define CPU_PM_CX_XE (CPU_INTEL_PENTIUM_M | CPU_CX_XE) -#define CPU_PX_CX_AT (CPU_INTEL_PX | CPU_CX_AT) -#define CPU_PX_CX_AT_XE (CPU_INTEL_PX | CPU_CX_AT_XE) - -/* Select all supported Intel CPUs */ -#define CPU_INTEL_ALL (CPU_INTEL_PENTIUM | CPU_PX_CX_AT_XE) - -#define CPU_AMD_K6 (1 << CPU_AMD_K6_BIT) -#define CPU_AMD_K7 (1 << CPU_AMD_K7_BIT) -#define CPU_AMD_K8 (1 << CPU_AMD_K8_BIT) -#define CPU_AMD_0F (1 << CPU_AMD_0F_BIT) -#define CPU_AMD_10 (1 << CPU_AMD_10_BIT) -#define CPU_AMD_11 (1 << CPU_AMD_11_BIT) - -#define CPU_K10_PLUS (CPU_AMD_10 | CPU_AMD_11) -#define CPU_K0F_PLUS (CPU_AMD_0F | CPU_K10_PLUS) -#define CPU_K8_PLUS (CPU_AMD_K8 | CPU_K0F_PLUS) -#define CPU_K7_PLUS (CPU_AMD_K7 | CPU_K8_PLUS) - -/* Select all supported AMD CPUs */ -#define CPU_AMD_ALL (CPU_AMD_K6 | CPU_K7_PLUS) - -/* Select all supported CPUs */ -#define CPU_ALL (CPU_INTEL_ALL | CPU_AMD_ALL) +#define CPU_FILE_VALUE (1 << CPU_VALUE_BIT) #define MAX_CPU_FILES 512 @@ -220,7 +122,6 @@ struct cpu_debug_range { unsigned min; /* Register range min */ unsigned max; /* Register range max */ unsigned flag; /* Supported flags */ - unsigned model; /* Supported models */ }; #endif /* _ASM_X86_CPU_DEBUG_H */ diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h index bb83b1c397aa..4a28d22d4793 100644 --- a/arch/x86/include/asm/cpufeature.h +++ b/arch/x86/include/asm/cpufeature.h @@ -22,7 +22,7 @@ #define X86_FEATURE_TSC (0*32+ 4) /* Time Stamp Counter */ #define X86_FEATURE_MSR (0*32+ 5) /* Model-Specific Registers */ #define X86_FEATURE_PAE (0*32+ 6) /* Physical Address Extensions */ -#define X86_FEATURE_MCE (0*32+ 7) /* Machine Check Architecture */ +#define X86_FEATURE_MCE (0*32+ 7) /* Machine Check Exception */ #define X86_FEATURE_CX8 (0*32+ 8) /* CMPXCHG8 instruction */ #define X86_FEATURE_APIC (0*32+ 9) /* Onboard APIC */ #define X86_FEATURE_SEP (0*32+11) /* SYSENTER/SYSEXIT */ @@ -94,6 +94,7 @@ #define X86_FEATURE_TSC_RELIABLE (3*32+23) /* TSC is known to be reliable */ #define X86_FEATURE_NONSTOP_TSC (3*32+24) /* TSC does not stop in C states */ #define X86_FEATURE_CLFLUSH_MONITOR (3*32+25) /* "" clflush reqd with monitor */ +#define X86_FEATURE_EXTD_APICID (3*32+26) /* has extended APICID (8 bits) */ /* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */ #define X86_FEATURE_XMM3 (4*32+ 0) /* "pni" SSE-3 */ @@ -115,6 +116,8 @@ #define X86_FEATURE_XMM4_1 (4*32+19) /* "sse4_1" SSE-4.1 */ #define X86_FEATURE_XMM4_2 (4*32+20) /* "sse4_2" SSE-4.2 */ #define X86_FEATURE_X2APIC (4*32+21) /* x2APIC */ +#define X86_FEATURE_MOVBE (4*32+22) /* MOVBE instruction */ +#define X86_FEATURE_POPCNT (4*32+23) /* POPCNT instruction */ #define X86_FEATURE_AES (4*32+25) /* AES instructions */ #define X86_FEATURE_XSAVE (4*32+26) /* XSAVE/XRSTOR/XSETBV/XGETBV */ #define X86_FEATURE_OSXSAVE (4*32+27) /* "" XSAVE enabled in the OS */ @@ -192,11 +195,11 @@ extern const char * const x86_power_flags[32]; #define clear_cpu_cap(c, bit) clear_bit(bit, (unsigned long *)((c)->x86_capability)) #define setup_clear_cpu_cap(bit) do { \ clear_cpu_cap(&boot_cpu_data, bit); \ - set_bit(bit, (unsigned long *)cleared_cpu_caps); \ + set_bit(bit, (unsigned long *)cpu_caps_cleared); \ } while (0) #define setup_force_cpu_cap(bit) do { \ set_cpu_cap(&boot_cpu_data, bit); \ - clear_bit(bit, (unsigned long *)cleared_cpu_caps); \ + set_bit(bit, (unsigned long *)cpu_caps_set); \ } while (0) #define cpu_has_fpu boot_cpu_has(X86_FEATURE_FPU) diff --git a/arch/x86/include/asm/desc.h b/arch/x86/include/asm/desc.h index c45f415ce315..c993e9e0fed4 100644 --- a/arch/x86/include/asm/desc.h +++ b/arch/x86/include/asm/desc.h @@ -1,7 +1,6 @@ #ifndef _ASM_X86_DESC_H #define _ASM_X86_DESC_H -#ifndef __ASSEMBLY__ #include #include #include @@ -380,29 +379,4 @@ static inline void set_system_intr_gate_ist(int n, void *addr, unsigned ist) _set_gate(n, GATE_INTERRUPT, addr, 0x3, ist, __KERNEL_CS); } -#else -/* - * GET_DESC_BASE reads the descriptor base of the specified segment. - * - * Args: - * idx - descriptor index - * gdt - GDT pointer - * base - 32bit register to which the base will be written - * lo_w - lo word of the "base" register - * lo_b - lo byte of the "base" register - * hi_b - hi byte of the low word of the "base" register - * - * Example: - * GET_DESC_BASE(GDT_ENTRY_ESPFIX_SS, %ebx, %eax, %ax, %al, %ah) - * Will read the base address of GDT_ENTRY_ESPFIX_SS and put it into %eax. - */ -#define GET_DESC_BASE(idx, gdt, base, lo_w, lo_b, hi_b) \ - movb idx * 8 + 4(gdt), lo_b; \ - movb idx * 8 + 7(gdt), hi_b; \ - shll $16, base; \ - movw idx * 8 + 2(gdt), lo_w; - - -#endif /* __ASSEMBLY__ */ - #endif /* _ASM_X86_DESC_H */ diff --git a/arch/x86/include/asm/dma-mapping.h b/arch/x86/include/asm/dma-mapping.h index f82fdc412c64..1c3f9435f1c9 100644 --- a/arch/x86/include/asm/dma-mapping.h +++ b/arch/x86/include/asm/dma-mapping.h @@ -6,6 +6,7 @@ * Documentation/DMA-API.txt for documentation. */ +#include #include #include #include @@ -32,6 +33,8 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev) #endif } +#include + /* Make sure we keep the same behaviour */ static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) { @@ -52,171 +55,6 @@ extern int dma_set_mask(struct device *dev, u64 mask); extern void *dma_generic_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_addr, gfp_t flag); -static inline dma_addr_t -dma_map_single(struct device *hwdev, void *ptr, size_t size, - enum dma_data_direction dir) -{ - struct dma_map_ops *ops = get_dma_ops(hwdev); - dma_addr_t addr; - - BUG_ON(!valid_dma_direction(dir)); - addr = ops->map_page(hwdev, virt_to_page(ptr), - (unsigned long)ptr & ~PAGE_MASK, size, - dir, NULL); - debug_dma_map_page(hwdev, virt_to_page(ptr), - (unsigned long)ptr & ~PAGE_MASK, size, - dir, addr, true); - return addr; -} - -static inline void -dma_unmap_single(struct device *dev, dma_addr_t addr, size_t size, - enum dma_data_direction dir) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - - BUG_ON(!valid_dma_direction(dir)); - if (ops->unmap_page) - ops->unmap_page(dev, addr, size, dir, NULL); - debug_dma_unmap_page(dev, addr, size, dir, true); -} - -static inline int -dma_map_sg(struct device *hwdev, struct scatterlist *sg, - int nents, enum dma_data_direction dir) -{ - struct dma_map_ops *ops = get_dma_ops(hwdev); - int ents; - - BUG_ON(!valid_dma_direction(dir)); - ents = ops->map_sg(hwdev, sg, nents, dir, NULL); - debug_dma_map_sg(hwdev, sg, nents, ents, dir); - - return ents; -} - -static inline void -dma_unmap_sg(struct device *hwdev, struct scatterlist *sg, int nents, - enum dma_data_direction dir) -{ - struct dma_map_ops *ops = get_dma_ops(hwdev); - - BUG_ON(!valid_dma_direction(dir)); - debug_dma_unmap_sg(hwdev, sg, nents, dir); - if (ops->unmap_sg) - ops->unmap_sg(hwdev, sg, nents, dir, NULL); -} - -static inline void -dma_sync_single_for_cpu(struct device *hwdev, dma_addr_t dma_handle, - size_t size, enum dma_data_direction dir) -{ - struct dma_map_ops *ops = get_dma_ops(hwdev); - - BUG_ON(!valid_dma_direction(dir)); - if (ops->sync_single_for_cpu) - ops->sync_single_for_cpu(hwdev, dma_handle, size, dir); - debug_dma_sync_single_for_cpu(hwdev, dma_handle, size, dir); - flush_write_buffers(); -} - -static inline void -dma_sync_single_for_device(struct device *hwdev, dma_addr_t dma_handle, - size_t size, enum dma_data_direction dir) -{ - struct dma_map_ops *ops = get_dma_ops(hwdev); - - BUG_ON(!valid_dma_direction(dir)); - if (ops->sync_single_for_device) - ops->sync_single_for_device(hwdev, dma_handle, size, dir); - debug_dma_sync_single_for_device(hwdev, dma_handle, size, dir); - flush_write_buffers(); -} - -static inline void -dma_sync_single_range_for_cpu(struct device *hwdev, dma_addr_t dma_handle, - unsigned long offset, size_t size, - enum dma_data_direction dir) -{ - struct dma_map_ops *ops = get_dma_ops(hwdev); - - BUG_ON(!valid_dma_direction(dir)); - if (ops->sync_single_range_for_cpu) - ops->sync_single_range_for_cpu(hwdev, dma_handle, offset, - size, dir); - debug_dma_sync_single_range_for_cpu(hwdev, dma_handle, - offset, size, dir); - flush_write_buffers(); -} - -static inline void -dma_sync_single_range_for_device(struct device *hwdev, dma_addr_t dma_handle, - unsigned long offset, size_t size, - enum dma_data_direction dir) -{ - struct dma_map_ops *ops = get_dma_ops(hwdev); - - BUG_ON(!valid_dma_direction(dir)); - if (ops->sync_single_range_for_device) - ops->sync_single_range_for_device(hwdev, dma_handle, - offset, size, dir); - debug_dma_sync_single_range_for_device(hwdev, dma_handle, - offset, size, dir); - flush_write_buffers(); -} - -static inline void -dma_sync_sg_for_cpu(struct device *hwdev, struct scatterlist *sg, - int nelems, enum dma_data_direction dir) -{ - struct dma_map_ops *ops = get_dma_ops(hwdev); - - BUG_ON(!valid_dma_direction(dir)); - if (ops->sync_sg_for_cpu) - ops->sync_sg_for_cpu(hwdev, sg, nelems, dir); - debug_dma_sync_sg_for_cpu(hwdev, sg, nelems, dir); - flush_write_buffers(); -} - -static inline void -dma_sync_sg_for_device(struct device *hwdev, struct scatterlist *sg, - int nelems, enum dma_data_direction dir) -{ - struct dma_map_ops *ops = get_dma_ops(hwdev); - - BUG_ON(!valid_dma_direction(dir)); - if (ops->sync_sg_for_device) - ops->sync_sg_for_device(hwdev, sg, nelems, dir); - debug_dma_sync_sg_for_device(hwdev, sg, nelems, dir); - - flush_write_buffers(); -} - -static inline dma_addr_t dma_map_page(struct device *dev, struct page *page, - size_t offset, size_t size, - enum dma_data_direction dir) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - dma_addr_t addr; - - BUG_ON(!valid_dma_direction(dir)); - addr = ops->map_page(dev, page, offset, size, dir, NULL); - debug_dma_map_page(dev, page, offset, size, dir, addr, false); - - return addr; -} - -static inline void dma_unmap_page(struct device *dev, dma_addr_t addr, - size_t size, enum dma_data_direction dir) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - - BUG_ON(!valid_dma_direction(dir)); - if (ops->unmap_page) - ops->unmap_page(dev, addr, size, dir, NULL); - debug_dma_unmap_page(dev, addr, size, dir, false); -} - static inline void dma_cache_sync(struct device *dev, void *vaddr, size_t size, enum dma_data_direction dir) diff --git a/arch/x86/include/asm/ds.h b/arch/x86/include/asm/ds.h index a8f672ba100c..70dac199b093 100644 --- a/arch/x86/include/asm/ds.h +++ b/arch/x86/include/asm/ds.h @@ -15,8 +15,8 @@ * - buffer allocation (memory accounting) * * - * Copyright (C) 2007-2008 Intel Corporation. - * Markus Metzger , 2007-2008 + * Copyright (C) 2007-2009 Intel Corporation. + * Markus Metzger , 2007-2009 */ #ifndef _ASM_X86_DS_H @@ -83,8 +83,10 @@ enum ds_feature { * The interrupt threshold is independent from the overflow callback * to allow users to use their own overflow interrupt handling mechanism. * - * task: the task to request recording for; - * NULL for per-cpu recording on the current cpu + * The function might sleep. + * + * task: the task to request recording for + * cpu: the cpu to request recording for * base: the base pointer for the (non-pageable) buffer; * size: the size of the provided buffer in bytes * ovfl: pointer to a function to be called on buffer overflow; @@ -93,19 +95,28 @@ enum ds_feature { * -1 if no interrupt threshold is requested. * flags: a bit-mask of the above flags */ -extern struct bts_tracer *ds_request_bts(struct task_struct *task, - void *base, size_t size, - bts_ovfl_callback_t ovfl, - size_t th, unsigned int flags); -extern struct pebs_tracer *ds_request_pebs(struct task_struct *task, - void *base, size_t size, - pebs_ovfl_callback_t ovfl, - size_t th, unsigned int flags); +extern struct bts_tracer *ds_request_bts_task(struct task_struct *task, + void *base, size_t size, + bts_ovfl_callback_t ovfl, + size_t th, unsigned int flags); +extern struct bts_tracer *ds_request_bts_cpu(int cpu, void *base, size_t size, + bts_ovfl_callback_t ovfl, + size_t th, unsigned int flags); +extern struct pebs_tracer *ds_request_pebs_task(struct task_struct *task, + void *base, size_t size, + pebs_ovfl_callback_t ovfl, + size_t th, unsigned int flags); +extern struct pebs_tracer *ds_request_pebs_cpu(int cpu, + void *base, size_t size, + pebs_ovfl_callback_t ovfl, + size_t th, unsigned int flags); /* * Release BTS or PEBS resources * Suspend and resume BTS or PEBS tracing * + * Must be called with irq's enabled. + * * tracer: the tracer handle returned from ds_request_~() */ extern void ds_release_bts(struct bts_tracer *tracer); @@ -115,6 +126,28 @@ extern void ds_release_pebs(struct pebs_tracer *tracer); extern void ds_suspend_pebs(struct pebs_tracer *tracer); extern void ds_resume_pebs(struct pebs_tracer *tracer); +/* + * Release BTS or PEBS resources + * Suspend and resume BTS or PEBS tracing + * + * Cpu tracers must call this on the traced cpu. + * Task tracers must call ds_release_~_noirq() for themselves. + * + * May be called with irq's disabled. + * + * Returns 0 if successful; + * -EPERM if the cpu tracer does not trace the current cpu. + * -EPERM if the task tracer does not trace itself. + * + * tracer: the tracer handle returned from ds_request_~() + */ +extern int ds_release_bts_noirq(struct bts_tracer *tracer); +extern int ds_suspend_bts_noirq(struct bts_tracer *tracer); +extern int ds_resume_bts_noirq(struct bts_tracer *tracer); +extern int ds_release_pebs_noirq(struct pebs_tracer *tracer); +extern int ds_suspend_pebs_noirq(struct pebs_tracer *tracer); +extern int ds_resume_pebs_noirq(struct pebs_tracer *tracer); + /* * The raw DS buffer state as it is used for BTS and PEBS recording. @@ -170,9 +203,9 @@ struct bts_struct { } lbr; /* BTS_TASK_ARRIVES or BTS_TASK_DEPARTS */ struct { - __u64 jiffies; + __u64 clock; pid_t pid; - } timestamp; + } event; } variant; }; @@ -201,8 +234,12 @@ struct bts_trace { struct pebs_trace { struct ds_trace ds; - /* the PEBS reset value */ - unsigned long long reset_value; + /* the number of valid counters in the below array */ + unsigned int counters; + +#define MAX_PEBS_COUNTERS 4 + /* the counter reset value */ + unsigned long long counter_reset[MAX_PEBS_COUNTERS]; }; @@ -237,9 +274,11 @@ extern int ds_reset_pebs(struct pebs_tracer *tracer); * Returns 0 on success; -Eerrno on error * * tracer: the tracer handle returned from ds_request_pebs() + * counter: the index of the counter * value: the new counter reset value */ -extern int ds_set_pebs_reset(struct pebs_tracer *tracer, u64 value); +extern int ds_set_pebs_reset(struct pebs_tracer *tracer, + unsigned int counter, u64 value); /* * Initialization @@ -252,21 +291,12 @@ extern void __cpuinit ds_init_intel(struct cpuinfo_x86 *); */ extern void ds_switch_to(struct task_struct *prev, struct task_struct *next); -/* - * Task clone/init and cleanup work - */ -extern void ds_copy_thread(struct task_struct *tsk, struct task_struct *father); -extern void ds_exit_thread(struct task_struct *tsk); - #else /* CONFIG_X86_DS */ struct cpuinfo_x86; static inline void __cpuinit ds_init_intel(struct cpuinfo_x86 *ignored) {} static inline void ds_switch_to(struct task_struct *prev, struct task_struct *next) {} -static inline void ds_copy_thread(struct task_struct *tsk, - struct task_struct *father) {} -static inline void ds_exit_thread(struct task_struct *tsk) {} #endif /* CONFIG_X86_DS */ #endif /* _ASM_X86_DS_H */ diff --git a/arch/x86/include/asm/entry_arch.h b/arch/x86/include/asm/entry_arch.h index c2e6bedaf258..ff8cbfa07851 100644 --- a/arch/x86/include/asm/entry_arch.h +++ b/arch/x86/include/asm/entry_arch.h @@ -14,6 +14,7 @@ BUILD_INTERRUPT(reschedule_interrupt,RESCHEDULE_VECTOR) BUILD_INTERRUPT(call_function_interrupt,CALL_FUNCTION_VECTOR) BUILD_INTERRUPT(call_function_single_interrupt,CALL_FUNCTION_SINGLE_VECTOR) BUILD_INTERRUPT(irq_move_cleanup_interrupt,IRQ_MOVE_CLEANUP_VECTOR) +BUILD_INTERRUPT(reboot_interrupt,REBOOT_VECTOR) BUILD_INTERRUPT3(invalidate_interrupt0,INVALIDATE_TLB_VECTOR_START+0, smp_invalidate_interrupt) @@ -49,11 +50,19 @@ BUILD_INTERRUPT(error_interrupt,ERROR_APIC_VECTOR) BUILD_INTERRUPT(spurious_interrupt,SPURIOUS_APIC_VECTOR) #ifdef CONFIG_PERF_COUNTERS -BUILD_INTERRUPT(perf_counter_interrupt, LOCAL_PERF_VECTOR) +BUILD_INTERRUPT(perf_pending_interrupt, LOCAL_PENDING_VECTOR) #endif -#ifdef CONFIG_X86_MCE_P4THERMAL +#ifdef CONFIG_X86_THERMAL_VECTOR BUILD_INTERRUPT(thermal_interrupt,THERMAL_APIC_VECTOR) #endif +#ifdef CONFIG_X86_MCE_THRESHOLD +BUILD_INTERRUPT(threshold_interrupt,THRESHOLD_APIC_VECTOR) +#endif + +#ifdef CONFIG_X86_NEW_MCE +BUILD_INTERRUPT(mce_self_interrupt,MCE_SELF_VECTOR) +#endif + #endif diff --git a/arch/x86/include/asm/hardirq.h b/arch/x86/include/asm/hardirq.h index 37555e52f980..82e3e8f01043 100644 --- a/arch/x86/include/asm/hardirq.h +++ b/arch/x86/include/asm/hardirq.h @@ -13,6 +13,8 @@ typedef struct { unsigned int irq_spurious_count; #endif unsigned int generic_irqs; /* arch dependent */ + unsigned int apic_perf_irqs; + unsigned int apic_pending_irqs; #ifdef CONFIG_SMP unsigned int irq_resched_count; unsigned int irq_call_count; @@ -20,7 +22,7 @@ typedef struct { #endif #ifdef CONFIG_X86_MCE unsigned int irq_thermal_count; -# ifdef CONFIG_X86_64 +# ifdef CONFIG_X86_MCE_THRESHOLD unsigned int irq_threshold_count; # endif #endif diff --git a/arch/x86/include/asm/hw_irq.h b/arch/x86/include/asm/hw_irq.h index b762ea49bd70..ba180d93b08c 100644 --- a/arch/x86/include/asm/hw_irq.h +++ b/arch/x86/include/asm/hw_irq.h @@ -29,9 +29,12 @@ extern void apic_timer_interrupt(void); extern void generic_interrupt(void); extern void error_interrupt(void); +extern void perf_pending_interrupt(void); + extern void spurious_interrupt(void); extern void thermal_interrupt(void); extern void reschedule_interrupt(void); +extern void mce_self_interrupt(void); extern void invalidate_interrupt(void); extern void invalidate_interrupt0(void); @@ -44,6 +47,7 @@ extern void invalidate_interrupt6(void); extern void invalidate_interrupt7(void); extern void irq_move_cleanup_interrupt(void); +extern void reboot_interrupt(void); extern void threshold_interrupt(void); extern void call_function_interrupt(void); @@ -63,7 +67,26 @@ extern unsigned long io_apic_irqs; extern void init_VISWS_APIC_irqs(void); extern void setup_IO_APIC(void); extern void disable_IO_APIC(void); -extern int IO_APIC_get_PCI_irq_vector(int bus, int slot, int fn); + +struct io_apic_irq_attr { + int ioapic; + int ioapic_pin; + int trigger; + int polarity; +}; + +static inline void set_io_apic_irq_attr(struct io_apic_irq_attr *irq_attr, + int ioapic, int ioapic_pin, + int trigger, int polarity) +{ + irq_attr->ioapic = ioapic; + irq_attr->ioapic_pin = ioapic_pin; + irq_attr->trigger = trigger; + irq_attr->polarity = polarity; +} + +extern int IO_APIC_get_PCI_irq_vector(int bus, int devfn, int pin, + struct io_apic_irq_attr *irq_attr); extern void setup_ioapic_dest(void); extern void enable_IO_APIC(void); @@ -78,7 +101,11 @@ extern void eisa_set_level_irq(unsigned int irq); /* SMP */ extern void smp_apic_timer_interrupt(struct pt_regs *); extern void smp_spurious_interrupt(struct pt_regs *); +extern void smp_generic_interrupt(struct pt_regs *); extern void smp_error_interrupt(struct pt_regs *); +#ifdef CONFIG_X86_IO_APIC +extern asmlinkage void smp_irq_move_cleanup_interrupt(void); +#endif #ifdef CONFIG_SMP extern void smp_reschedule_interrupt(struct pt_regs *); extern void smp_call_function_interrupt(struct pt_regs *); diff --git a/arch/x86/include/asm/i387.h b/arch/x86/include/asm/i387.h index 71c9e5183982..175adf58dd4f 100644 --- a/arch/x86/include/asm/i387.h +++ b/arch/x86/include/asm/i387.h @@ -67,7 +67,7 @@ static inline int fxrstor_checking(struct i387_fxsave_struct *fx) ".previous\n" _ASM_EXTABLE(1b, 3b) : [err] "=r" (err) -#if 0 /* See comment in __save_init_fpu() below. */ +#if 0 /* See comment in fxsave() below. */ : [fx] "r" (fx), "m" (*fx), "0" (0)); #else : [fx] "cdaSDb" (fx), "m" (*fx), "0" (0)); @@ -75,14 +75,6 @@ static inline int fxrstor_checking(struct i387_fxsave_struct *fx) return err; } -static inline int restore_fpu_checking(struct task_struct *tsk) -{ - if (task_thread_info(tsk)->status & TS_XSAVE) - return xrstor_checking(&tsk->thread.xstate->xsave); - else - return fxrstor_checking(&tsk->thread.xstate->fxsave); -} - /* AMD CPUs don't save/restore FDP/FIP/FOP unless an exception is pending. Clear the x87 state here by setting it to fixed values. The kernel data segment can be sometimes 0 and sometimes @@ -120,7 +112,7 @@ static inline int fxsave_user(struct i387_fxsave_struct __user *fx) ".previous\n" _ASM_EXTABLE(1b, 3b) : [err] "=r" (err), "=m" (*fx) -#if 0 /* See comment in __fxsave_clear() below. */ +#if 0 /* See comment in fxsave() below. */ : [fx] "r" (fx), "0" (0)); #else : [fx] "cdaSDb" (fx), "0" (0)); @@ -185,12 +177,9 @@ static inline void tolerant_fwait(void) asm volatile("fnclex ; fwait"); } -static inline void restore_fpu(struct task_struct *tsk) +/* perform fxrstor iff the processor has extended states, otherwise frstor */ +static inline int fxrstor_checking(struct i387_fxsave_struct *fx) { - if (task_thread_info(tsk)->status & TS_XSAVE) { - xrstor_checking(&tsk->thread.xstate->xsave); - return; - } /* * The "nop" is needed to make the instructions the same * length. @@ -199,7 +188,9 @@ static inline void restore_fpu(struct task_struct *tsk) "nop ; frstor %1", "fxrstor %1", X86_FEATURE_FXSR, - "m" (tsk->thread.xstate->fxsave)); + "m" (*fx)); + + return 0; } /* We need a safe address that is cheap to find and that is already @@ -262,6 +253,14 @@ end: #endif /* CONFIG_X86_64 */ +static inline int restore_fpu_checking(struct task_struct *tsk) +{ + if (task_thread_info(tsk)->status & TS_XSAVE) + return xrstor_checking(&tsk->thread.xstate->xsave); + else + return fxrstor_checking(&tsk->thread.xstate->fxsave); +} + /* * Signal frame handlers... */ @@ -305,18 +304,18 @@ static inline void kernel_fpu_end(void) /* * Some instructions like VIA's padlock instructions generate a spurious * DNA fault but don't modify SSE registers. And these instructions - * get used from interrupt context aswell. To prevent these kernel instructions - * in interrupt context interact wrongly with other user/kernel fpu usage, we + * get used from interrupt context as well. To prevent these kernel instructions + * in interrupt context interacting wrongly with other user/kernel fpu usage, we * should use them only in the context of irq_ts_save/restore() */ static inline int irq_ts_save(void) { /* - * If we are in process context, we are ok to take a spurious DNA fault. - * Otherwise, doing clts() in process context require pre-emption to - * be disabled or some heavy lifting like kernel_fpu_begin() + * If in process context and not atomic, we can take a spurious DNA fault. + * Otherwise, doing clts() in process context requires disabling preemption + * or some heavy lifting like kernel_fpu_begin() */ - if (!in_interrupt()) + if (!in_atomic()) return 0; if (read_cr0() & X86_CR0_TS) { diff --git a/arch/x86/include/asm/i8259.h b/arch/x86/include/asm/i8259.h index 1a99e6c092af..58d7091eeb1f 100644 --- a/arch/x86/include/asm/i8259.h +++ b/arch/x86/include/asm/i8259.h @@ -60,8 +60,4 @@ extern struct irq_chip i8259A_chip; extern void mask_8259A(void); extern void unmask_8259A(void); -#ifdef CONFIG_X86_32 -extern void init_ISA_irqs(void); -#endif - #endif /* _ASM_X86_I8259_H */ diff --git a/arch/x86/include/asm/intel_arch_perfmon.h b/arch/x86/include/asm/intel_arch_perfmon.h deleted file mode 100644 index fa0fd068bc2e..000000000000 --- a/arch/x86/include/asm/intel_arch_perfmon.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef _ASM_X86_INTEL_ARCH_PERFMON_H -#define _ASM_X86_INTEL_ARCH_PERFMON_H - -#define MSR_ARCH_PERFMON_PERFCTR0 0xc1 -#define MSR_ARCH_PERFMON_PERFCTR1 0xc2 - -#define MSR_ARCH_PERFMON_EVENTSEL0 0x186 -#define MSR_ARCH_PERFMON_EVENTSEL1 0x187 - -#define ARCH_PERFMON_EVENTSEL0_ENABLE (1 << 22) -#define ARCH_PERFMON_EVENTSEL_INT (1 << 20) -#define ARCH_PERFMON_EVENTSEL_OS (1 << 17) -#define ARCH_PERFMON_EVENTSEL_USR (1 << 16) - -#define ARCH_PERFMON_UNHALTED_CORE_CYCLES_SEL (0x3c) -#define ARCH_PERFMON_UNHALTED_CORE_CYCLES_UMASK (0x00 << 8) -#define ARCH_PERFMON_UNHALTED_CORE_CYCLES_INDEX (0) -#define ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT \ - (1 << (ARCH_PERFMON_UNHALTED_CORE_CYCLES_INDEX)) - -union cpuid10_eax { - struct { - unsigned int version_id:8; - unsigned int num_counters:8; - unsigned int bit_width:8; - unsigned int mask_length:8; - } split; - unsigned int full; -}; - -#endif /* _ASM_X86_INTEL_ARCH_PERFMON_H */ diff --git a/arch/x86/include/asm/io_apic.h b/arch/x86/include/asm/io_apic.h index 9d826e436010..daf866ed0612 100644 --- a/arch/x86/include/asm/io_apic.h +++ b/arch/x86/include/asm/io_apic.h @@ -154,22 +154,19 @@ extern int timer_through_8259; extern int io_apic_get_unique_id(int ioapic, int apic_id); extern int io_apic_get_version(int ioapic); extern int io_apic_get_redir_entries(int ioapic); -extern int io_apic_set_pci_routing(int ioapic, int pin, int irq, - int edge_level, int active_high_low); #endif /* CONFIG_ACPI */ +struct io_apic_irq_attr; +extern int io_apic_set_pci_routing(struct device *dev, int irq, + struct io_apic_irq_attr *irq_attr); extern int (*ioapic_renumber_irq)(int ioapic, int irq); extern void ioapic_init_mappings(void); -#ifdef CONFIG_X86_64 extern struct IO_APIC_route_entry **alloc_ioapic_entries(void); extern void free_ioapic_entries(struct IO_APIC_route_entry **ioapic_entries); extern int save_IO_APIC_setup(struct IO_APIC_route_entry **ioapic_entries); extern void mask_IO_APIC_setup(struct IO_APIC_route_entry **ioapic_entries); extern int restore_IO_APIC_setup(struct IO_APIC_route_entry **ioapic_entries); -extern void reinit_intr_remapped_IO_APIC(int intr_remapping, - struct IO_APIC_route_entry **ioapic_entries); -#endif extern void probe_nr_irqs_gsi(void); diff --git a/arch/x86/include/asm/iomap.h b/arch/x86/include/asm/iomap.h index 86af26091d6c..0e9fe1d9d971 100644 --- a/arch/x86/include/asm/iomap.h +++ b/arch/x86/include/asm/iomap.h @@ -1,3 +1,6 @@ +#ifndef _ASM_X86_IOMAP_H +#define _ASM_X86_IOMAP_H + /* * Copyright © 2008 Ingo Molnar * @@ -31,3 +34,5 @@ iomap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t prot); void iounmap_atomic(void *kvaddr, enum km_type type); + +#endif /* _ASM_X86_IOMAP_H */ diff --git a/arch/x86/include/asm/iommu.h b/arch/x86/include/asm/iommu.h index af326a2975b5..fd6d21bbee6c 100644 --- a/arch/x86/include/asm/iommu.h +++ b/arch/x86/include/asm/iommu.h @@ -6,6 +6,7 @@ extern void no_iommu_init(void); extern struct dma_map_ops nommu_dma_ops; extern int force_iommu, no_iommu; extern int iommu_detected; +extern int iommu_pass_through; /* 10 seconds */ #define DMAR_OPERATION_TIMEOUT ((cycles_t) tsc_khz*10*1000) diff --git a/arch/x86/include/asm/irq_remapping.h b/arch/x86/include/asm/irq_remapping.h index 0396760fccb8..f275e2244505 100644 --- a/arch/x86/include/asm/irq_remapping.h +++ b/arch/x86/include/asm/irq_remapping.h @@ -1,6 +1,6 @@ #ifndef _ASM_X86_IRQ_REMAPPING_H #define _ASM_X86_IRQ_REMAPPING_H -#define IRTE_DEST(dest) ((x2apic) ? dest : dest << 8) +#define IRTE_DEST(dest) ((x2apic_mode) ? dest : dest << 8) #endif /* _ASM_X86_IRQ_REMAPPING_H */ diff --git a/arch/x86/include/asm/irq_vectors.h b/arch/x86/include/asm/irq_vectors.h index 3cbd79bbb47c..5b21f0ec3df2 100644 --- a/arch/x86/include/asm/irq_vectors.h +++ b/arch/x86/include/asm/irq_vectors.h @@ -25,6 +25,7 @@ */ #define NMI_VECTOR 0x02 +#define MCE_VECTOR 0x12 /* * IDT vectors usable for external interrupt sources start @@ -34,6 +35,7 @@ #ifdef CONFIG_X86_32 # define SYSCALL_VECTOR 0x80 +# define IA32_SYSCALL_VECTOR 0x80 #else # define IA32_SYSCALL_VECTOR 0x80 #endif @@ -86,13 +88,8 @@ #define CALL_FUNCTION_VECTOR 0xfc #define CALL_FUNCTION_SINGLE_VECTOR 0xfb #define THERMAL_APIC_VECTOR 0xfa - -#ifdef CONFIG_X86_32 -/* 0xf8 - 0xf9 : free */ -#else -# define THRESHOLD_APIC_VECTOR 0xf9 -# define UV_BAU_MESSAGE 0xf8 -#endif +#define THRESHOLD_APIC_VECTOR 0xf9 +#define REBOOT_VECTOR 0xf8 /* f0-f7 used for spreading out TLB flushes: */ #define INVALIDATE_TLB_VECTOR_END 0xf7 @@ -106,16 +103,23 @@ */ #define LOCAL_TIMER_VECTOR 0xef -/* - * Performance monitoring interrupt vector: - */ -#define LOCAL_PERF_VECTOR 0xee - /* * Generic system vector for platform specific use */ #define GENERIC_INTERRUPT_VECTOR 0xed +/* + * Performance monitoring pending work vector: + */ +#define LOCAL_PENDING_VECTOR 0xec + +#define UV_BAU_MESSAGE 0xec + +/* + * Self IPI vector for machine checks + */ +#define MCE_SELF_VECTOR 0xeb + /* * First APIC vector available to drivers: (vectors 0x30-0xee) we * start at 0x31(0x41) to spread out vectors evenly between priority diff --git a/arch/x86/include/asm/k8.h b/arch/x86/include/asm/k8.h index 54c8cc53b24d..c2d1f3b58e5f 100644 --- a/arch/x86/include/asm/k8.h +++ b/arch/x86/include/asm/k8.h @@ -12,4 +12,17 @@ extern int cache_k8_northbridges(void); extern void k8_flush_garts(void); extern int k8_scan_nodes(unsigned long start, unsigned long end); +#ifdef CONFIG_K8_NB +static inline struct pci_dev *node_to_k8_nb_misc(int node) +{ + return (node < num_k8_northbridges) ? k8_northbridges[node] : NULL; +} +#else +static inline struct pci_dev *node_to_k8_nb_misc(int node) +{ + return NULL; +} +#endif + + #endif /* _ASM_X86_K8_H */ diff --git a/arch/x86/include/asm/kmap_types.h b/arch/x86/include/asm/kmap_types.h index 5759c165a5cf..9e00a731a7fb 100644 --- a/arch/x86/include/asm/kmap_types.h +++ b/arch/x86/include/asm/kmap_types.h @@ -2,28 +2,11 @@ #define _ASM_X86_KMAP_TYPES_H #if defined(CONFIG_X86_32) && defined(CONFIG_DEBUG_HIGHMEM) -# define D(n) __KM_FENCE_##n , -#else -# define D(n) +#define __WITH_KM_FENCE #endif -enum km_type { -D(0) KM_BOUNCE_READ, -D(1) KM_SKB_SUNRPC_DATA, -D(2) KM_SKB_DATA_SOFTIRQ, -D(3) KM_USER0, -D(4) KM_USER1, -D(5) KM_BIO_SRC_IRQ, -D(6) KM_BIO_DST_IRQ, -D(7) KM_PTE0, -D(8) KM_PTE1, -D(9) KM_IRQ0, -D(10) KM_IRQ1, -D(11) KM_SOFTIRQ0, -D(12) KM_SOFTIRQ1, -D(13) KM_TYPE_NR -}; +#include -#undef D +#undef __WITH_KM_FENCE #endif /* _ASM_X86_KMAP_TYPES_H */ diff --git a/arch/x86/include/asm/kmemcheck.h b/arch/x86/include/asm/kmemcheck.h new file mode 100644 index 000000000000..ed01518f297e --- /dev/null +++ b/arch/x86/include/asm/kmemcheck.h @@ -0,0 +1,42 @@ +#ifndef ASM_X86_KMEMCHECK_H +#define ASM_X86_KMEMCHECK_H + +#include +#include + +#ifdef CONFIG_KMEMCHECK +bool kmemcheck_active(struct pt_regs *regs); + +void kmemcheck_show(struct pt_regs *regs); +void kmemcheck_hide(struct pt_regs *regs); + +bool kmemcheck_fault(struct pt_regs *regs, + unsigned long address, unsigned long error_code); +bool kmemcheck_trap(struct pt_regs *regs); +#else +static inline bool kmemcheck_active(struct pt_regs *regs) +{ + return false; +} + +static inline void kmemcheck_show(struct pt_regs *regs) +{ +} + +static inline void kmemcheck_hide(struct pt_regs *regs) +{ +} + +static inline bool kmemcheck_fault(struct pt_regs *regs, + unsigned long address, unsigned long error_code) +{ + return false; +} + +static inline bool kmemcheck_trap(struct pt_regs *regs) +{ + return false; +} +#endif /* CONFIG_KMEMCHECK */ + +#endif diff --git a/arch/x86/include/asm/kvm.h b/arch/x86/include/asm/kvm.h index dc3f6cf11704..125be8b19568 100644 --- a/arch/x86/include/asm/kvm.h +++ b/arch/x86/include/asm/kvm.h @@ -16,6 +16,7 @@ #define __KVM_HAVE_MSI #define __KVM_HAVE_USER_NMI #define __KVM_HAVE_GUEST_DEBUG +#define __KVM_HAVE_MSIX /* Architectural interrupt line count. */ #define KVM_NR_INTERRUPTS 256 diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index f0faf58044ff..eabdc1cfab5c 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -185,6 +185,7 @@ union kvm_mmu_page_role { unsigned access:3; unsigned invalid:1; unsigned cr4_pge:1; + unsigned nxe:1; }; }; @@ -212,7 +213,6 @@ struct kvm_mmu_page { int multimapped; /* More than one parent_pte? */ int root_count; /* Currently serving as active root */ bool unsync; - bool global; unsigned int unsync_children; union { u64 *parent_pte; /* !multimapped */ @@ -261,13 +261,11 @@ struct kvm_mmu { union kvm_mmu_page_role base_role; u64 *pae_root; + u64 rsvd_bits_mask[2][4]; }; struct kvm_vcpu_arch { u64 host_tsc; - int interrupt_window_open; - unsigned long irq_summary; /* bit vector: 1 per word in irq_pending */ - DECLARE_BITMAP(irq_pending, KVM_NR_INTERRUPTS); /* * rip and regs accesses must go through * kvm_{register,rip}_{read,write} functions. @@ -286,6 +284,7 @@ struct kvm_vcpu_arch { u64 shadow_efer; u64 apic_base; struct kvm_lapic *apic; /* kernel irqchip context */ + int32_t apic_arb_prio; int mp_state; int sipi_vector; u64 ia32_misc_enable_msr; @@ -320,6 +319,8 @@ struct kvm_vcpu_arch { struct kvm_pio_request pio; void *pio_data; + u8 event_exit_inst_len; + struct kvm_queued_exception { bool pending; bool has_error_code; @@ -329,11 +330,12 @@ struct kvm_vcpu_arch { struct kvm_queued_interrupt { bool pending; + bool soft; u8 nr; } interrupt; struct { - int active; + int vm86_active; u8 save_iopl; struct kvm_save_segment { u16 selector; @@ -356,9 +358,9 @@ struct kvm_vcpu_arch { unsigned int time_offset; struct page *time_page; + bool singlestep; /* guest is single stepped by KVM */ bool nmi_pending; bool nmi_injected; - bool nmi_window_open; struct mtrr_state_type mtrr_state; u32 pat; @@ -392,15 +394,14 @@ struct kvm_arch{ */ struct list_head active_mmu_pages; struct list_head assigned_dev_head; - struct list_head oos_global_pages; struct iommu_domain *iommu_domain; + int iommu_flags; struct kvm_pic *vpic; struct kvm_ioapic *vioapic; struct kvm_pit *vpit; struct hlist_head irq_ack_notifier_list; int vapics_in_nmi_mode; - int round_robin_prev_vcpu; unsigned int tss_addr; struct page *apic_access_page; @@ -423,7 +424,6 @@ struct kvm_vm_stat { u32 mmu_recycled; u32 mmu_cache_miss; u32 mmu_unsync; - u32 mmu_unsync_global; u32 remote_tlb_flush; u32 lpages; }; @@ -443,7 +443,6 @@ struct kvm_vcpu_stat { u32 halt_exits; u32 halt_wakeup; u32 request_irq_exits; - u32 request_nmi_exits; u32 irq_exits; u32 host_state_reload; u32 efer_reload; @@ -511,20 +510,22 @@ struct kvm_x86_ops { void (*run)(struct kvm_vcpu *vcpu, struct kvm_run *run); int (*handle_exit)(struct kvm_run *run, struct kvm_vcpu *vcpu); void (*skip_emulated_instruction)(struct kvm_vcpu *vcpu); + void (*set_interrupt_shadow)(struct kvm_vcpu *vcpu, int mask); + u32 (*get_interrupt_shadow)(struct kvm_vcpu *vcpu, int mask); void (*patch_hypercall)(struct kvm_vcpu *vcpu, unsigned char *hypercall_addr); - int (*get_irq)(struct kvm_vcpu *vcpu); - void (*set_irq)(struct kvm_vcpu *vcpu, int vec); + void (*set_irq)(struct kvm_vcpu *vcpu); + void (*set_nmi)(struct kvm_vcpu *vcpu); void (*queue_exception)(struct kvm_vcpu *vcpu, unsigned nr, bool has_error_code, u32 error_code); - bool (*exception_injected)(struct kvm_vcpu *vcpu); - void (*inject_pending_irq)(struct kvm_vcpu *vcpu); - void (*inject_pending_vectors)(struct kvm_vcpu *vcpu, - struct kvm_run *run); - + int (*interrupt_allowed)(struct kvm_vcpu *vcpu); + int (*nmi_allowed)(struct kvm_vcpu *vcpu); + void (*enable_nmi_window)(struct kvm_vcpu *vcpu); + void (*enable_irq_window)(struct kvm_vcpu *vcpu); + void (*update_cr8_intercept)(struct kvm_vcpu *vcpu, int tpr, int irr); int (*set_tss_addr)(struct kvm *kvm, unsigned int addr); int (*get_tdp_level)(void); - int (*get_mt_mask_shift)(void); + u64 (*get_mt_mask)(struct kvm_vcpu *vcpu, gfn_t gfn, bool is_mmio); }; extern struct kvm_x86_ops *kvm_x86_ops; @@ -538,7 +539,7 @@ int kvm_mmu_setup(struct kvm_vcpu *vcpu); void kvm_mmu_set_nonpresent_ptes(u64 trap_pte, u64 notrap_pte); void kvm_mmu_set_base_ptes(u64 base_pte); void kvm_mmu_set_mask_ptes(u64 user_mask, u64 accessed_mask, - u64 dirty_mask, u64 nx_mask, u64 x_mask, u64 mt_mask); + u64 dirty_mask, u64 nx_mask, u64 x_mask); int kvm_mmu_reset_context(struct kvm_vcpu *vcpu); void kvm_mmu_slot_remove_write_access(struct kvm *kvm, int slot); @@ -552,6 +553,7 @@ int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa, const void *val, int bytes); int kvm_pv_mmu_op(struct kvm_vcpu *vcpu, unsigned long bytes, gpa_t addr, unsigned long *ret); +u8 kvm_get_guest_memory_type(struct kvm_vcpu *vcpu, gfn_t gfn); extern bool tdp_enabled; @@ -563,6 +565,7 @@ enum emulation_result { #define EMULTYPE_NO_DECODE (1 << 0) #define EMULTYPE_TRAP_UD (1 << 1) +#define EMULTYPE_SKIP (1 << 2) int emulate_instruction(struct kvm_vcpu *vcpu, struct kvm_run *run, unsigned long cr2, u16 error_code, int emulation_type); void kvm_report_emulation_failure(struct kvm_vcpu *cvpu, const char *context); @@ -638,7 +641,6 @@ void __kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu); int kvm_mmu_load(struct kvm_vcpu *vcpu); void kvm_mmu_unload(struct kvm_vcpu *vcpu); void kvm_mmu_sync_roots(struct kvm_vcpu *vcpu); -void kvm_mmu_sync_global(struct kvm_vcpu *vcpu); int kvm_emulate_hypercall(struct kvm_vcpu *vcpu); @@ -769,6 +771,8 @@ enum { #define HF_GIF_MASK (1 << 0) #define HF_HIF_MASK (1 << 1) #define HF_VINTR_MASK (1 << 2) +#define HF_NMI_MASK (1 << 3) +#define HF_IRET_MASK (1 << 4) /* * Hardware virtualization extension instructions may fault if a @@ -791,5 +795,6 @@ asmlinkage void kvm_handle_fault_on_reboot(void); #define KVM_ARCH_WANT_MMU_NOTIFIER int kvm_unmap_hva(struct kvm *kvm, unsigned long hva); int kvm_age_hva(struct kvm *kvm, unsigned long hva); +int cpuid_maxphyaddr(struct kvm_vcpu *vcpu); #endif /* _ASM_X86_KVM_HOST_H */ diff --git a/arch/x86/include/asm/kvm_x86_emulate.h b/arch/x86/include/asm/kvm_x86_emulate.h index 6a159732881a..b7ed2c423116 100644 --- a/arch/x86/include/asm/kvm_x86_emulate.h +++ b/arch/x86/include/asm/kvm_x86_emulate.h @@ -143,6 +143,9 @@ struct decode_cache { struct fetch_cache fetch; }; +#define X86_SHADOW_INT_MOV_SS 1 +#define X86_SHADOW_INT_STI 2 + struct x86_emulate_ctxt { /* Register state before/after emulation. */ struct kvm_vcpu *vcpu; @@ -152,6 +155,9 @@ struct x86_emulate_ctxt { int mode; u32 cs_base; + /* interruptibility state, as a result of execution of STI or MOV SS */ + int interruptibility; + /* decode cache */ struct decode_cache decode; }; diff --git a/arch/x86/include/asm/lguest.h b/arch/x86/include/asm/lguest.h index 1caf57628b9c..313389cd50d2 100644 --- a/arch/x86/include/asm/lguest.h +++ b/arch/x86/include/asm/lguest.h @@ -17,8 +17,13 @@ /* Pages for switcher itself, then two pages per cpu */ #define TOTAL_SWITCHER_PAGES (SHARED_SWITCHER_PAGES + 2 * nr_cpu_ids) -/* We map at -4M for ease of mapping into the guest (one PTE page). */ +/* We map at -4M (-2M when PAE is activated) for ease of mapping + * into the guest (one PTE page). */ +#ifdef CONFIG_X86_PAE +#define SWITCHER_ADDR 0xFFE00000 +#else #define SWITCHER_ADDR 0xFFC00000 +#endif /* Found in switcher.S */ extern unsigned long default_idt_entries[]; diff --git a/arch/x86/include/asm/lguest_hcall.h b/arch/x86/include/asm/lguest_hcall.h index faae1996487b..d31c4a684078 100644 --- a/arch/x86/include/asm/lguest_hcall.h +++ b/arch/x86/include/asm/lguest_hcall.h @@ -12,11 +12,13 @@ #define LHCALL_TS 8 #define LHCALL_SET_CLOCKEVENT 9 #define LHCALL_HALT 10 +#define LHCALL_SET_PMD 13 #define LHCALL_SET_PTE 14 -#define LHCALL_SET_PMD 15 +#define LHCALL_SET_PGD 15 #define LHCALL_LOAD_TLS 16 #define LHCALL_NOTIFY 17 #define LHCALL_LOAD_GDT_ENTRY 18 +#define LHCALL_SEND_INTERRUPTS 19 #define LGUEST_TRAP_ENTRY 0x1F @@ -32,10 +34,10 @@ * operations? There are two ways: the direct way is to make a "hypercall", * to make requests of the Host Itself. * - * We use the KVM hypercall mechanism. Eighteen hypercalls are + * We use the KVM hypercall mechanism. Seventeen hypercalls are * available: the hypercall number is put in the %eax register, and the - * arguments (when required) are placed in %ebx, %ecx and %edx. If a return - * value makes sense, it's returned in %eax. + * arguments (when required) are placed in %ebx, %ecx, %edx and %esi. + * If a return value makes sense, it's returned in %eax. * * Grossly invalid calls result in Sudden Death at the hands of the vengeful * Host, rather than returning failure. This reflects Winston Churchill's @@ -47,8 +49,9 @@ #define LHCALL_RING_SIZE 64 struct hcall_args { - /* These map directly onto eax, ebx, ecx, edx in struct lguest_regs */ - unsigned long arg0, arg1, arg2, arg3; + /* These map directly onto eax, ebx, ecx, edx and esi + * in struct lguest_regs */ + unsigned long arg0, arg1, arg2, arg3, arg4; }; #endif /* !__ASSEMBLY__ */ diff --git a/arch/x86/include/asm/mce.h b/arch/x86/include/asm/mce.h index 4f8c199584e7..5cdd8d100ec9 100644 --- a/arch/x86/include/asm/mce.h +++ b/arch/x86/include/asm/mce.h @@ -1,8 +1,6 @@ #ifndef _ASM_X86_MCE_H #define _ASM_X86_MCE_H -#ifdef __x86_64__ - #include #include @@ -10,21 +8,35 @@ * Machine Check support for x86 */ -#define MCG_CTL_P (1UL<<8) /* MCG_CAP register available */ -#define MCG_EXT_P (1ULL<<9) /* Extended registers available */ -#define MCG_CMCI_P (1ULL<<10) /* CMCI supported */ +#define MCG_BANKCNT_MASK 0xff /* Number of Banks */ +#define MCG_CTL_P (1ULL<<8) /* MCG_CAP register available */ +#define MCG_EXT_P (1ULL<<9) /* Extended registers available */ +#define MCG_CMCI_P (1ULL<<10) /* CMCI supported */ +#define MCG_EXT_CNT_MASK 0xff0000 /* Number of Extended registers */ +#define MCG_EXT_CNT_SHIFT 16 +#define MCG_EXT_CNT(c) (((c) & MCG_EXT_CNT_MASK) >> MCG_EXT_CNT_SHIFT) +#define MCG_SER_P (1ULL<<24) /* MCA recovery/new status bits */ -#define MCG_STATUS_RIPV (1UL<<0) /* restart ip valid */ -#define MCG_STATUS_EIPV (1UL<<1) /* ip points to correct instruction */ -#define MCG_STATUS_MCIP (1UL<<2) /* machine check in progress */ +#define MCG_STATUS_RIPV (1ULL<<0) /* restart ip valid */ +#define MCG_STATUS_EIPV (1ULL<<1) /* ip points to correct instruction */ +#define MCG_STATUS_MCIP (1ULL<<2) /* machine check in progress */ -#define MCI_STATUS_VAL (1UL<<63) /* valid error */ -#define MCI_STATUS_OVER (1UL<<62) /* previous errors lost */ -#define MCI_STATUS_UC (1UL<<61) /* uncorrected error */ -#define MCI_STATUS_EN (1UL<<60) /* error enabled */ -#define MCI_STATUS_MISCV (1UL<<59) /* misc error reg. valid */ -#define MCI_STATUS_ADDRV (1UL<<58) /* addr reg. valid */ -#define MCI_STATUS_PCC (1UL<<57) /* processor context corrupt */ +#define MCI_STATUS_VAL (1ULL<<63) /* valid error */ +#define MCI_STATUS_OVER (1ULL<<62) /* previous errors lost */ +#define MCI_STATUS_UC (1ULL<<61) /* uncorrected error */ +#define MCI_STATUS_EN (1ULL<<60) /* error enabled */ +#define MCI_STATUS_MISCV (1ULL<<59) /* misc error reg. valid */ +#define MCI_STATUS_ADDRV (1ULL<<58) /* addr reg. valid */ +#define MCI_STATUS_PCC (1ULL<<57) /* processor context corrupt */ +#define MCI_STATUS_S (1ULL<<56) /* Signaled machine check */ +#define MCI_STATUS_AR (1ULL<<55) /* Action required */ + +/* MISC register defines */ +#define MCM_ADDR_SEGOFF 0 /* segment offset */ +#define MCM_ADDR_LINEAR 1 /* linear address */ +#define MCM_ADDR_PHYS 2 /* physical address */ +#define MCM_ADDR_MEM 3 /* memory address */ +#define MCM_ADDR_GENERIC 7 /* generic */ /* Fields are zero when not available */ struct mce { @@ -34,13 +46,19 @@ struct mce { __u64 mcgstatus; __u64 ip; __u64 tsc; /* cpu time stamp counter */ - __u64 res1; /* for future extension */ - __u64 res2; /* dito. */ + __u64 time; /* wall time_t when error was detected */ + __u8 cpuvendor; /* cpu vendor as encoded in system.h */ + __u8 pad1; + __u16 pad2; + __u32 cpuid; /* CPUID 1 EAX */ __u8 cs; /* code segment */ __u8 bank; /* machine check bank */ - __u8 cpu; /* cpu that raised the error */ + __u8 cpu; /* cpu number; obsolete; use extcpu now */ __u8 finished; /* entry is valid */ - __u32 pad; + __u32 extcpu; /* linux cpu number that detected the error */ + __u32 socketid; /* CPU socket ID */ + __u32 apicid; /* CPU initial apic ID */ + __u64 mcgcap; /* MCGCAP MSR: machine check capabilities of CPU */ }; /* @@ -57,7 +75,7 @@ struct mce_log { unsigned len; /* = MCE_LOG_LEN */ unsigned next; unsigned flags; - unsigned pad0; + unsigned recordlen; /* length of struct mce */ struct mce entry[MCE_LOG_LEN]; }; @@ -82,20 +100,41 @@ struct mce_log { #define K8_MCE_THRESHOLD_BANK_5 (MCE_THRESHOLD_BASE + 5 * 9) #define K8_MCE_THRESHOLD_DRAM_ECC (MCE_THRESHOLD_BANK_4 + 0) -#endif /* __x86_64__ */ - #ifdef __KERNEL__ -#ifdef CONFIG_X86_32 -extern int mce_disabled; -#else /* CONFIG_X86_32 */ - +#include +#include #include +extern int mce_disabled; +extern int mce_p5_enabled; + +#ifdef CONFIG_X86_MCE +void mcheck_init(struct cpuinfo_x86 *c); +#else +static inline void mcheck_init(struct cpuinfo_x86 *c) {} +#endif + +#ifdef CONFIG_X86_OLD_MCE +extern int nr_mce_banks; +void amd_mcheck_init(struct cpuinfo_x86 *c); +void intel_p4_mcheck_init(struct cpuinfo_x86 *c); +void intel_p6_mcheck_init(struct cpuinfo_x86 *c); +#endif + +#ifdef CONFIG_X86_ANCIENT_MCE +void intel_p5_mcheck_init(struct cpuinfo_x86 *c); +void winchip_mcheck_init(struct cpuinfo_x86 *c); +static inline void enable_p5_mce(void) { mce_p5_enabled = 1; } +#else +static inline void intel_p5_mcheck_init(struct cpuinfo_x86 *c) {} +static inline void winchip_mcheck_init(struct cpuinfo_x86 *c) {} +static inline void enable_p5_mce(void) {} +#endif + void mce_setup(struct mce *m); void mce_log(struct mce *m); -DECLARE_PER_CPU(struct sys_device, device_mce); -extern void (*threshold_cpu_callback)(unsigned long action, unsigned int cpu); +DECLARE_PER_CPU(struct sys_device, mce_dev); /* * To support more than 128 would need to escape the predefined @@ -104,6 +143,8 @@ extern void (*threshold_cpu_callback)(unsigned long action, unsigned int cpu); #define MAX_NR_BANKS (MCE_EXTENDED_BANK - 1) #ifdef CONFIG_X86_MCE_INTEL +extern int mce_cmci_disabled; +extern int mce_ignore_ce; void mce_intel_feature_init(struct cpuinfo_x86 *c); void cmci_clear(void); void cmci_reenable(void); @@ -123,14 +164,13 @@ void mce_amd_feature_init(struct cpuinfo_x86 *c); static inline void mce_amd_feature_init(struct cpuinfo_x86 *c) { } #endif -extern int mce_available(struct cpuinfo_x86 *c); +int mce_available(struct cpuinfo_x86 *c); -void mce_log_therm_throt_event(__u64 status); +DECLARE_PER_CPU(unsigned, mce_exception_count); +DECLARE_PER_CPU(unsigned, mce_poll_count); extern atomic_t mce_entry; -extern void do_machine_check(struct pt_regs *, long); - typedef DECLARE_BITMAP(mce_banks_t, MAX_NR_BANKS); DECLARE_PER_CPU(mce_banks_t, mce_poll_banks); @@ -139,19 +179,40 @@ enum mcp_flags { MCP_UC = (1 << 1), /* log uncorrected errors */ MCP_DONTLOG = (1 << 2), /* only clear, don't log */ }; -extern void machine_check_poll(enum mcp_flags flags, mce_banks_t *b); +void machine_check_poll(enum mcp_flags flags, mce_banks_t *b); -extern int mce_notify_user(void); +int mce_notify_irq(void); +void mce_notify_process(void); -#endif /* !CONFIG_X86_32 */ +DECLARE_PER_CPU(struct mce, injectm); +extern struct file_operations mce_chrdev_ops; -#ifdef CONFIG_X86_MCE -extern void mcheck_init(struct cpuinfo_x86 *c); -#else -#define mcheck_init(c) do { } while (0) -#endif +/* + * Exception handler + */ + +/* Call the installed machine check handler for this CPU setup. */ +extern void (*machine_check_vector)(struct pt_regs *, long error_code); +void do_machine_check(struct pt_regs *, long); + +/* + * Threshold handler + */ extern void (*mce_threshold_vector)(void); +extern void (*threshold_cpu_callback)(unsigned long action, unsigned int cpu); + +/* + * Thermal handler + */ + +void intel_init_thermal(struct cpuinfo_x86 *c); + +#ifdef CONFIG_X86_NEW_MCE +void mce_log_therm_throt_event(__u64 status); +#else +static inline void mce_log_therm_throt_event(__u64 status) {} +#endif #endif /* __KERNEL__ */ #endif /* _ASM_X86_MCE_H */ diff --git a/arch/x86/include/asm/microcode.h b/arch/x86/include/asm/microcode.h index c882664716c1..ef51b501e22a 100644 --- a/arch/x86/include/asm/microcode.h +++ b/arch/x86/include/asm/microcode.h @@ -9,20 +9,31 @@ struct cpu_signature { struct device; +enum ucode_state { UCODE_ERROR, UCODE_OK, UCODE_NFOUND }; + struct microcode_ops { - int (*request_microcode_user) (int cpu, const void __user *buf, size_t size); - int (*request_microcode_fw) (int cpu, struct device *device); + enum ucode_state (*request_microcode_user) (int cpu, + const void __user *buf, size_t size); - void (*apply_microcode) (int cpu); + enum ucode_state (*request_microcode_fw) (int cpu, + struct device *device); - int (*collect_cpu_info) (int cpu, struct cpu_signature *csig); void (*microcode_fini_cpu) (int cpu); + + /* + * The generic 'microcode_core' part guarantees that + * the callbacks below run on a target cpu when they + * are being called. + * See also the "Synchronization" section in microcode_core.c. + */ + int (*apply_microcode) (int cpu); + int (*collect_cpu_info) (int cpu, struct cpu_signature *csig); }; struct ucode_cpu_info { - struct cpu_signature cpu_sig; - int valid; - void *mc; + struct cpu_signature cpu_sig; + int valid; + void *mc; }; extern struct ucode_cpu_info ucode_cpu_info[]; diff --git a/arch/x86/include/asm/mman.h b/arch/x86/include/asm/mman.h index 90bc4108a4fd..751af2550ed9 100644 --- a/arch/x86/include/asm/mman.h +++ b/arch/x86/include/asm/mman.h @@ -1,7 +1,7 @@ #ifndef _ASM_X86_MMAN_H #define _ASM_X86_MMAN_H -#include +#include #define MAP_32BIT 0x40 /* only give out 32bit addresses */ diff --git a/arch/x86/include/asm/mpspec.h b/arch/x86/include/asm/mpspec.h index 642fc7fc8cdc..e2a1bb6d71ea 100644 --- a/arch/x86/include/asm/mpspec.h +++ b/arch/x86/include/asm/mpspec.h @@ -61,9 +61,11 @@ extern void get_smp_config(void); #ifdef CONFIG_X86_MPPARSE extern void find_smp_config(void); extern void early_reserve_e820_mpc_new(void); +extern int enable_update_mptable; #else static inline void find_smp_config(void) { } static inline void early_reserve_e820_mpc_new(void) { } +#define enable_update_mptable 0 #endif void __cpuinit generic_processor_info(int apicid, int version); @@ -72,20 +74,13 @@ extern void mp_register_ioapic(int id, u32 address, u32 gsi_base); extern void mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger, u32 gsi); extern void mp_config_acpi_legacy_irqs(void); -extern int mp_register_gsi(u32 gsi, int edge_level, int active_high_low); +struct device; +extern int mp_register_gsi(struct device *dev, u32 gsi, int edge_level, + int active_high_low); extern int acpi_probe_gsi(void); #ifdef CONFIG_X86_IO_APIC -extern int mp_config_acpi_gsi(unsigned char number, unsigned int devfn, u8 pin, - u32 gsi, int triggering, int polarity); extern int mp_find_ioapic(int gsi); extern int mp_find_ioapic_pin(int ioapic, int gsi); -#else -static inline int -mp_config_acpi_gsi(unsigned char number, unsigned int devfn, u8 pin, - u32 gsi, int triggering, int polarity) -{ - return 0; -} #endif #else /* !CONFIG_ACPI: */ static inline int acpi_probe_gsi(void) diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index ec41fc16c167..1692fb5050e3 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h @@ -121,7 +121,6 @@ #define MSR_K8_TOP_MEM1 0xc001001a #define MSR_K8_TOP_MEM2 0xc001001d #define MSR_K8_SYSCFG 0xc0010010 -#define MSR_K8_HWCR 0xc0010015 #define MSR_K8_INT_PENDING_MSG 0xc0010055 /* C1E active bits in int pending message */ #define K8_INTP_C1E_ACTIVE_MASK 0x18000000 @@ -208,7 +207,14 @@ #define MSR_IA32_THERM_CONTROL 0x0000019a #define MSR_IA32_THERM_INTERRUPT 0x0000019b + +#define THERM_INT_LOW_ENABLE (1 << 0) +#define THERM_INT_HIGH_ENABLE (1 << 1) + #define MSR_IA32_THERM_STATUS 0x0000019c + +#define THERM_STATUS_PROCHOT (1 << 0) + #define MSR_IA32_MISC_ENABLE 0x000001a0 /* MISC_ENABLE bits: architectural */ diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h index 638bf6241807..48ad9d29484a 100644 --- a/arch/x86/include/asm/msr.h +++ b/arch/x86/include/asm/msr.h @@ -3,15 +3,23 @@ #include -#ifndef __ASSEMBLY__ -# include -#endif - #ifdef __KERNEL__ #ifndef __ASSEMBLY__ +#include #include #include +#include + +struct msr { + union { + struct { + u32 l; + u32 h; + }; + u64 q; + }; +}; static inline unsigned long long native_read_tscp(unsigned int *aux) { @@ -216,6 +224,8 @@ do { \ #ifdef CONFIG_SMP int rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h); int wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h); +void rdmsr_on_cpus(const cpumask_t *mask, u32 msr_no, struct msr *msrs); +void wrmsr_on_cpus(const cpumask_t *mask, u32 msr_no, struct msr *msrs); int rdmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h); int wrmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h); #else /* CONFIG_SMP */ @@ -229,6 +239,16 @@ static inline int wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h) wrmsr(msr_no, l, h); return 0; } +static inline void rdmsr_on_cpus(const cpumask_t *m, u32 msr_no, + struct msr *msrs) +{ + rdmsr_on_cpu(0, msr_no, &(msrs[0].l), &(msrs[0].h)); +} +static inline void wrmsr_on_cpus(const cpumask_t *m, u32 msr_no, + struct msr *msrs) +{ + wrmsr_on_cpu(0, msr_no, msrs[0].l, msrs[0].h); +} static inline int rdmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h) { @@ -241,6 +261,4 @@ static inline int wrmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h) #endif /* CONFIG_SMP */ #endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */ - - #endif /* _ASM_X86_MSR_H */ diff --git a/arch/x86/include/asm/nmi.h b/arch/x86/include/asm/nmi.h index c45a0a568dff..c97264409934 100644 --- a/arch/x86/include/asm/nmi.h +++ b/arch/x86/include/asm/nmi.h @@ -64,7 +64,7 @@ static inline int nmi_watchdog_active(void) * but since they are power of two we could use a * cheaper way --cvg */ - return nmi_watchdog & 0x3; + return nmi_watchdog & (NMI_LOCAL_APIC | NMI_IO_APIC); } #endif diff --git a/arch/x86/include/asm/numa_64.h b/arch/x86/include/asm/numa_64.h index 064ed6df4cbe..c4ae822e415f 100644 --- a/arch/x86/include/asm/numa_64.h +++ b/arch/x86/include/asm/numa_64.h @@ -17,9 +17,6 @@ extern int compute_hash_shift(struct bootnode *nodes, int numblks, extern void numa_init_array(void); extern int numa_off; -extern void srat_reserve_add_area(int nodeid); -extern int hotadd_percent; - extern s16 apicid_to_node[MAX_LOCAL_APIC]; extern unsigned long numa_free_all_bootmem(void); @@ -27,6 +24,13 @@ extern void setup_node_bootmem(int nodeid, unsigned long start, unsigned long end); #ifdef CONFIG_NUMA +/* + * Too small node sizes may confuse the VM badly. Usually they + * result from BIOS bugs. So dont recognize nodes as standalone + * NUMA entities that have less than this amount of RAM listed: + */ +#define NODE_MIN_SIZE (4*1024*1024) + extern void __init init_cpu_to_node(void); extern void __cpuinit numa_set_node(int cpu, int node); extern void __cpuinit numa_clear_node(int cpu); diff --git a/arch/x86/include/asm/page.h b/arch/x86/include/asm/page.h index 89ed9d70b0aa..625c3f0e741a 100644 --- a/arch/x86/include/asm/page.h +++ b/arch/x86/include/asm/page.h @@ -56,7 +56,7 @@ extern bool __virt_addr_valid(unsigned long kaddr); #endif /* __ASSEMBLY__ */ #include -#include +#include #define __HAVE_ARCH_GATE_AREA 1 diff --git a/arch/x86/include/asm/page_32_types.h b/arch/x86/include/asm/page_32_types.h index 0f915ae649a7..6f1b7331313f 100644 --- a/arch/x86/include/asm/page_32_types.h +++ b/arch/x86/include/asm/page_32_types.h @@ -54,10 +54,6 @@ extern unsigned int __VMALLOC_RESERVE; extern int sysctl_legacy_va_layout; extern void find_low_pfn_range(void); -extern unsigned long init_memory_mapping(unsigned long start, - unsigned long end); -extern void initmem_init(unsigned long, unsigned long); -extern void free_initmem(void); extern void setup_bootmem_allocator(void); #endif /* !__ASSEMBLY__ */ diff --git a/arch/x86/include/asm/page_64_types.h b/arch/x86/include/asm/page_64_types.h index d38c91b70248..7639dbf5d223 100644 --- a/arch/x86/include/asm/page_64_types.h +++ b/arch/x86/include/asm/page_64_types.h @@ -32,24 +32,16 @@ */ #define __PAGE_OFFSET _AC(0xffff880000000000, UL) -#define __PHYSICAL_START CONFIG_PHYSICAL_START -#define __KERNEL_ALIGN 0x200000 - -/* - * Make sure kernel is aligned to 2MB address. Catching it at compile - * time is better. Change your config file and compile the kernel - * for a 2MB aligned address (CONFIG_PHYSICAL_START) - */ -#if (CONFIG_PHYSICAL_START % __KERNEL_ALIGN) != 0 -#error "CONFIG_PHYSICAL_START must be a multiple of 2MB" -#endif +#define __PHYSICAL_START ((CONFIG_PHYSICAL_START + \ + (CONFIG_PHYSICAL_ALIGN - 1)) & \ + ~(CONFIG_PHYSICAL_ALIGN - 1)) #define __START_KERNEL (__START_KERNEL_map + __PHYSICAL_START) #define __START_KERNEL_map _AC(0xffffffff80000000, UL) -/* See Documentation/x86_64/mm.txt for a description of the memory map. */ +/* See Documentation/x86/x86_64/mm.txt for a description of the memory map. */ #define __PHYSICAL_MASK_SHIFT 46 -#define __VIRTUAL_MASK_SHIFT 48 +#define __VIRTUAL_MASK_SHIFT 47 /* * Kernel image size is limited to 512 MB (see level2_kernel_pgt in @@ -71,12 +63,6 @@ extern unsigned long __phys_addr(unsigned long); #define vmemmap ((struct page *)VMEMMAP_START) -extern unsigned long init_memory_mapping(unsigned long start, - unsigned long end); - -extern void initmem_init(unsigned long start_pfn, unsigned long end_pfn); -extern void free_initmem(void); - extern void init_extra_mapping_uc(unsigned long phys, unsigned long size); extern void init_extra_mapping_wb(unsigned long phys, unsigned long size); diff --git a/arch/x86/include/asm/page_types.h b/arch/x86/include/asm/page_types.h index 826ad37006ab..6473f5ccff85 100644 --- a/arch/x86/include/asm/page_types.h +++ b/arch/x86/include/asm/page_types.h @@ -46,6 +46,12 @@ extern int devmem_is_allowed(unsigned long pagenr); extern unsigned long max_low_pfn_mapped; extern unsigned long max_pfn_mapped; +extern unsigned long init_memory_mapping(unsigned long start, + unsigned long end); + +extern void initmem_init(unsigned long start_pfn, unsigned long end_pfn); +extern void free_initmem(void); + #endif /* !__ASSEMBLY__ */ #endif /* _ASM_X86_PAGE_DEFS_H */ diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h index a53da004e08e..4fb37c8a0832 100644 --- a/arch/x86/include/asm/paravirt.h +++ b/arch/x86/include/asm/paravirt.h @@ -56,6 +56,7 @@ struct desc_ptr; struct tss_struct; struct mm_struct; struct desc_struct; +struct task_struct; /* * Wrapper type for pointers to code which uses the non-standard @@ -203,7 +204,8 @@ struct pv_cpu_ops { void (*swapgs)(void); - struct pv_lazy_ops lazy_mode; + void (*start_context_switch)(struct task_struct *prev); + void (*end_context_switch)(struct task_struct *next); }; struct pv_irq_ops { @@ -1399,25 +1401,23 @@ enum paravirt_lazy_mode { }; enum paravirt_lazy_mode paravirt_get_lazy_mode(void); -void paravirt_enter_lazy_cpu(void); -void paravirt_leave_lazy_cpu(void); +void paravirt_start_context_switch(struct task_struct *prev); +void paravirt_end_context_switch(struct task_struct *next); + void paravirt_enter_lazy_mmu(void); void paravirt_leave_lazy_mmu(void); -void paravirt_leave_lazy(enum paravirt_lazy_mode mode); -#define __HAVE_ARCH_ENTER_LAZY_CPU_MODE -static inline void arch_enter_lazy_cpu_mode(void) +#define __HAVE_ARCH_START_CONTEXT_SWITCH +static inline void arch_start_context_switch(struct task_struct *prev) { - PVOP_VCALL0(pv_cpu_ops.lazy_mode.enter); + PVOP_VCALL1(pv_cpu_ops.start_context_switch, prev); } -static inline void arch_leave_lazy_cpu_mode(void) +static inline void arch_end_context_switch(struct task_struct *next) { - PVOP_VCALL0(pv_cpu_ops.lazy_mode.leave); + PVOP_VCALL1(pv_cpu_ops.end_context_switch, next); } -void arch_flush_lazy_cpu_mode(void); - #define __HAVE_ARCH_ENTER_LAZY_MMU_MODE static inline void arch_enter_lazy_mmu_mode(void) { diff --git a/arch/x86/include/asm/pci.h b/arch/x86/include/asm/pci.h index b51a1e8b0baf..927958d13c19 100644 --- a/arch/x86/include/asm/pci.h +++ b/arch/x86/include/asm/pci.h @@ -130,6 +130,7 @@ extern void pci_iommu_alloc(void); /* generic pci stuff */ #include +#define PCIBIOS_MAX_MEM_32 0xffffffff #ifdef CONFIG_NUMA /* Returns the node based on pci bus */ diff --git a/arch/x86/include/asm/pci_x86.h b/arch/x86/include/asm/pci_x86.h index e60fd3e14bdf..b399988eee3a 100644 --- a/arch/x86/include/asm/pci_x86.h +++ b/arch/x86/include/asm/pci_x86.h @@ -121,6 +121,9 @@ extern int __init pcibios_init(void); extern int __init pci_mmcfg_arch_init(void); extern void __init pci_mmcfg_arch_free(void); +extern struct acpi_mcfg_allocation *pci_mmcfg_config; +extern int pci_mmcfg_config_num; + /* * AMD Fam10h CPUs are buggy, and cannot access MMIO config space * on their northbrige except through the * %eax register. As such, you MUST diff --git a/arch/x86/include/asm/perf_counter.h b/arch/x86/include/asm/perf_counter.h new file mode 100644 index 000000000000..5fb33e160ea0 --- /dev/null +++ b/arch/x86/include/asm/perf_counter.h @@ -0,0 +1,95 @@ +#ifndef _ASM_X86_PERF_COUNTER_H +#define _ASM_X86_PERF_COUNTER_H + +/* + * Performance counter hw details: + */ + +#define X86_PMC_MAX_GENERIC 8 +#define X86_PMC_MAX_FIXED 3 + +#define X86_PMC_IDX_GENERIC 0 +#define X86_PMC_IDX_FIXED 32 +#define X86_PMC_IDX_MAX 64 + +#define MSR_ARCH_PERFMON_PERFCTR0 0xc1 +#define MSR_ARCH_PERFMON_PERFCTR1 0xc2 + +#define MSR_ARCH_PERFMON_EVENTSEL0 0x186 +#define MSR_ARCH_PERFMON_EVENTSEL1 0x187 + +#define ARCH_PERFMON_EVENTSEL0_ENABLE (1 << 22) +#define ARCH_PERFMON_EVENTSEL_INT (1 << 20) +#define ARCH_PERFMON_EVENTSEL_OS (1 << 17) +#define ARCH_PERFMON_EVENTSEL_USR (1 << 16) + +/* + * Includes eventsel and unit mask as well: + */ +#define ARCH_PERFMON_EVENT_MASK 0xffff + +#define ARCH_PERFMON_UNHALTED_CORE_CYCLES_SEL 0x3c +#define ARCH_PERFMON_UNHALTED_CORE_CYCLES_UMASK (0x00 << 8) +#define ARCH_PERFMON_UNHALTED_CORE_CYCLES_INDEX 0 +#define ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT \ + (1 << (ARCH_PERFMON_UNHALTED_CORE_CYCLES_INDEX)) + +#define ARCH_PERFMON_BRANCH_MISSES_RETIRED 6 + +/* + * Intel "Architectural Performance Monitoring" CPUID + * detection/enumeration details: + */ +union cpuid10_eax { + struct { + unsigned int version_id:8; + unsigned int num_counters:8; + unsigned int bit_width:8; + unsigned int mask_length:8; + } split; + unsigned int full; +}; + +union cpuid10_edx { + struct { + unsigned int num_counters_fixed:4; + unsigned int reserved:28; + } split; + unsigned int full; +}; + + +/* + * Fixed-purpose performance counters: + */ + +/* + * All 3 fixed-mode PMCs are configured via this single MSR: + */ +#define MSR_ARCH_PERFMON_FIXED_CTR_CTRL 0x38d + +/* + * The counts are available in three separate MSRs: + */ + +/* Instr_Retired.Any: */ +#define MSR_ARCH_PERFMON_FIXED_CTR0 0x309 +#define X86_PMC_IDX_FIXED_INSTRUCTIONS (X86_PMC_IDX_FIXED + 0) + +/* CPU_CLK_Unhalted.Core: */ +#define MSR_ARCH_PERFMON_FIXED_CTR1 0x30a +#define X86_PMC_IDX_FIXED_CPU_CYCLES (X86_PMC_IDX_FIXED + 1) + +/* CPU_CLK_Unhalted.Ref: */ +#define MSR_ARCH_PERFMON_FIXED_CTR2 0x30b +#define X86_PMC_IDX_FIXED_BUS_CYCLES (X86_PMC_IDX_FIXED + 2) + +#ifdef CONFIG_PERF_COUNTERS +extern void init_hw_perf_counters(void); +extern void perf_counters_lapic_init(void); +#else +static inline void init_hw_perf_counters(void) { } +static inline void perf_counters_lapic_init(void) { } +#endif + +#endif /* _ASM_X86_PERF_COUNTER_H */ diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h index 29d96d168bc0..3cc06e3fceb8 100644 --- a/arch/x86/include/asm/pgtable.h +++ b/arch/x86/include/asm/pgtable.h @@ -81,6 +81,8 @@ static inline void __init paravirt_pagetable_setup_done(pgd_t *base) #define pte_val(x) native_pte_val(x) #define __pte(x) native_make_pte(x) +#define arch_end_context_switch(prev) do {} while(0) + #endif /* CONFIG_PARAVIRT */ /* @@ -315,6 +317,11 @@ static inline int pte_present(pte_t a) return pte_flags(a) & (_PAGE_PRESENT | _PAGE_PROTNONE); } +static inline int pte_hidden(pte_t pte) +{ + return pte_flags(pte) & _PAGE_HIDDEN; +} + static inline int pmd_present(pmd_t pmd) { return pmd_flags(pmd) & _PAGE_PRESENT; @@ -503,6 +510,8 @@ static inline int pgd_none(pgd_t pgd) #ifndef __ASSEMBLY__ +extern int direct_gbpages; + /* local pte updates need not use xchg for locking */ static inline pte_t native_local_ptep_get_and_clear(pte_t *ptep) { diff --git a/arch/x86/include/asm/pgtable_32.h b/arch/x86/include/asm/pgtable_32.h index 31bd120cf2a2..01fd9461d323 100644 --- a/arch/x86/include/asm/pgtable_32.h +++ b/arch/x86/include/asm/pgtable_32.h @@ -49,13 +49,17 @@ extern void set_pmd_pfn(unsigned long, unsigned long, pgprot_t); #endif #if defined(CONFIG_HIGHPTE) +#define __KM_PTE \ + (in_nmi() ? KM_NMI_PTE : \ + in_irq() ? KM_IRQ_PTE : \ + KM_PTE0) #define pte_offset_map(dir, address) \ - ((pte_t *)kmap_atomic_pte(pmd_page(*(dir)), KM_PTE0) + \ + ((pte_t *)kmap_atomic_pte(pmd_page(*(dir)), __KM_PTE) + \ pte_index((address))) #define pte_offset_map_nested(dir, address) \ ((pte_t *)kmap_atomic_pte(pmd_page(*(dir)), KM_PTE1) + \ pte_index((address))) -#define pte_unmap(pte) kunmap_atomic((pte), KM_PTE0) +#define pte_unmap(pte) kunmap_atomic((pte), __KM_PTE) #define pte_unmap_nested(pte) kunmap_atomic((pte), KM_PTE1) #else #define pte_offset_map(dir, address) \ diff --git a/arch/x86/include/asm/pgtable_32_types.h b/arch/x86/include/asm/pgtable_32_types.h index 2733fad45f98..5e67c1532314 100644 --- a/arch/x86/include/asm/pgtable_32_types.h +++ b/arch/x86/include/asm/pgtable_32_types.h @@ -46,6 +46,10 @@ extern bool __vmalloc_start_set; /* set once high_memory is set */ # define VMALLOC_END (FIXADDR_START - 2 * PAGE_SIZE) #endif +#define MODULES_VADDR VMALLOC_START +#define MODULES_END VMALLOC_END +#define MODULES_LEN (MODULES_VADDR - MODULES_END) + #define MAXMEM (VMALLOC_END - PAGE_OFFSET - __VMALLOC_RESERVE) #endif /* _ASM_X86_PGTABLE_32_DEFS_H */ diff --git a/arch/x86/include/asm/pgtable_64.h b/arch/x86/include/asm/pgtable_64.h index 6b87bc6d5018..c57a30117149 100644 --- a/arch/x86/include/asm/pgtable_64.h +++ b/arch/x86/include/asm/pgtable_64.h @@ -25,10 +25,6 @@ extern pgd_t init_level4_pgt[]; extern void paging_init(void); -#endif /* !__ASSEMBLY__ */ - -#ifndef __ASSEMBLY__ - #define pte_ERROR(e) \ printk("%s:%d: bad pte %p(%016lx).\n", \ __FILE__, __LINE__, &(e), pte_val(e)) @@ -135,8 +131,6 @@ static inline int pgd_large(pgd_t pgd) { return 0; } #define update_mmu_cache(vma, address, pte) do { } while (0) -extern int direct_gbpages; - /* Encode and de-code a swap entry */ #if _PAGE_BIT_FILE < _PAGE_BIT_PROTNONE #define SWP_TYPE_BITS (_PAGE_BIT_FILE - _PAGE_BIT_PRESENT - 1) @@ -171,10 +165,7 @@ extern void cleanup_highmap(void); /* fs/proc/kcore.c */ #define kc_vaddr_to_offset(v) ((v) & __VIRTUAL_MASK) -#define kc_offset_to_vaddr(o) \ - (((o) & (1UL << (__VIRTUAL_MASK_SHIFT - 1))) \ - ? ((o) | ~__VIRTUAL_MASK) \ - : (o)) +#define kc_offset_to_vaddr(o) ((o) | ~__VIRTUAL_MASK) #define __HAVE_ARCH_PTE_SAME #endif /* !__ASSEMBLY__ */ diff --git a/arch/x86/include/asm/pgtable_64_types.h b/arch/x86/include/asm/pgtable_64_types.h index fbf42b8e0383..766ea16fbbbd 100644 --- a/arch/x86/include/asm/pgtable_64_types.h +++ b/arch/x86/include/asm/pgtable_64_types.h @@ -51,11 +51,11 @@ typedef struct { pteval_t pte; } pte_t; #define PGDIR_SIZE (_AC(1, UL) << PGDIR_SHIFT) #define PGDIR_MASK (~(PGDIR_SIZE - 1)) - +/* See Documentation/x86/x86_64/mm.txt for a description of the memory map. */ #define MAXMEM _AC(__AC(1, UL) << MAX_PHYSMEM_BITS, UL) -#define VMALLOC_START _AC(0xffffc20000000000, UL) -#define VMALLOC_END _AC(0xffffe1ffffffffff, UL) -#define VMEMMAP_START _AC(0xffffe20000000000, UL) +#define VMALLOC_START _AC(0xffffc90000000000, UL) +#define VMALLOC_END _AC(0xffffe8ffffffffff, UL) +#define VMEMMAP_START _AC(0xffffea0000000000, UL) #define MODULES_VADDR _AC(0xffffffffa0000000, UL) #define MODULES_END _AC(0xffffffffff000000, UL) #define MODULES_LEN (MODULES_END - MODULES_VADDR) diff --git a/arch/x86/include/asm/pgtable_types.h b/arch/x86/include/asm/pgtable_types.h index b8238dc8786d..54cb697f4900 100644 --- a/arch/x86/include/asm/pgtable_types.h +++ b/arch/x86/include/asm/pgtable_types.h @@ -18,7 +18,7 @@ #define _PAGE_BIT_GLOBAL 8 /* Global TLB entry PPro+ */ #define _PAGE_BIT_UNUSED1 9 /* available for programmer */ #define _PAGE_BIT_IOMAP 10 /* flag used to indicate IO mapping */ -#define _PAGE_BIT_UNUSED3 11 +#define _PAGE_BIT_HIDDEN 11 /* hidden by kmemcheck */ #define _PAGE_BIT_PAT_LARGE 12 /* On 2MB or 1GB pages */ #define _PAGE_BIT_SPECIAL _PAGE_BIT_UNUSED1 #define _PAGE_BIT_CPA_TEST _PAGE_BIT_UNUSED1 @@ -41,13 +41,18 @@ #define _PAGE_GLOBAL (_AT(pteval_t, 1) << _PAGE_BIT_GLOBAL) #define _PAGE_UNUSED1 (_AT(pteval_t, 1) << _PAGE_BIT_UNUSED1) #define _PAGE_IOMAP (_AT(pteval_t, 1) << _PAGE_BIT_IOMAP) -#define _PAGE_UNUSED3 (_AT(pteval_t, 1) << _PAGE_BIT_UNUSED3) #define _PAGE_PAT (_AT(pteval_t, 1) << _PAGE_BIT_PAT) #define _PAGE_PAT_LARGE (_AT(pteval_t, 1) << _PAGE_BIT_PAT_LARGE) #define _PAGE_SPECIAL (_AT(pteval_t, 1) << _PAGE_BIT_SPECIAL) #define _PAGE_CPA_TEST (_AT(pteval_t, 1) << _PAGE_BIT_CPA_TEST) #define __HAVE_ARCH_PTE_SPECIAL +#ifdef CONFIG_KMEMCHECK +#define _PAGE_HIDDEN (_AT(pteval_t, 1) << _PAGE_BIT_HIDDEN) +#else +#define _PAGE_HIDDEN (_AT(pteval_t, 0)) +#endif + #if defined(CONFIG_X86_64) || defined(CONFIG_X86_PAE) #define _PAGE_NX (_AT(pteval_t, 1) << _PAGE_BIT_NX) #else @@ -273,7 +278,6 @@ typedef struct page *pgtable_t; extern pteval_t __supported_pte_mask; extern int nx_enabled; -extern void set_nx(void); #define pgprot_writecombine pgprot_writecombine extern pgprot_t pgprot_writecombine(pgprot_t prot); diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index c2cceae709c8..c7768269b1cf 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -135,7 +135,8 @@ extern struct cpuinfo_x86 boot_cpu_data; extern struct cpuinfo_x86 new_cpu_data; extern struct tss_struct doublefault_tss; -extern __u32 cleared_cpu_caps[NCAPINTS]; +extern __u32 cpu_caps_cleared[NCAPINTS]; +extern __u32 cpu_caps_set[NCAPINTS]; #ifdef CONFIG_SMP DECLARE_PER_CPU_SHARED_ALIGNED(struct cpuinfo_x86, cpu_info); @@ -409,9 +410,6 @@ DECLARE_PER_CPU(unsigned long, stack_canary); extern unsigned int xstate_size; extern void free_thread_xstate(struct task_struct *); extern struct kmem_cache *task_xstate_cachep; -extern void init_scattered_cpuid_features(struct cpuinfo_x86 *c); -extern unsigned int init_intel_cacheinfo(struct cpuinfo_x86 *c); -extern unsigned short num_cache_leaves; struct thread_struct { /* Cached TLS descriptors: */ @@ -427,8 +425,12 @@ struct thread_struct { unsigned short fsindex; unsigned short gsindex; #endif +#ifdef CONFIG_X86_32 unsigned long ip; +#endif +#ifdef CONFIG_X86_64 unsigned long fs; +#endif unsigned long gs; /* Hardware debugging registers: */ unsigned long debugreg0; @@ -460,14 +462,8 @@ struct thread_struct { unsigned io_bitmap_max; /* MSR_IA32_DEBUGCTLMSR value to switch in if TIF_DEBUGCTLMSR is set. */ unsigned long debugctlmsr; -#ifdef CONFIG_X86_DS -/* Debug Store context; see include/asm-x86/ds.h; goes into MSR_IA32_DS_AREA */ + /* Debug Store context; see asm/ds.h */ struct ds_context *ds_ctx; -#endif /* CONFIG_X86_DS */ -#ifdef CONFIG_X86_PTRACE_BTS -/* the signal to send on a bts buffer overflow */ - unsigned int bts_ovfl_signal; -#endif /* CONFIG_X86_PTRACE_BTS */ }; static inline unsigned long native_get_debugreg(int regno) @@ -795,6 +791,21 @@ static inline unsigned long get_debugctlmsr(void) return debugctlmsr; } +static inline unsigned long get_debugctlmsr_on_cpu(int cpu) +{ + u64 debugctlmsr = 0; + u32 val1, val2; + +#ifndef CONFIG_X86_DEBUGCTLMSR + if (boot_cpu_data.x86 < 6) + return 0; +#endif + rdmsr_on_cpu(cpu, MSR_IA32_DEBUGCTLMSR, &val1, &val2); + debugctlmsr = val1 | ((u64)val2 << 32); + + return debugctlmsr; +} + static inline void update_debugctlmsr(unsigned long debugctlmsr) { #ifndef CONFIG_X86_DEBUGCTLMSR @@ -804,6 +815,18 @@ static inline void update_debugctlmsr(unsigned long debugctlmsr) wrmsrl(MSR_IA32_DEBUGCTLMSR, debugctlmsr); } +static inline void update_debugctlmsr_on_cpu(int cpu, + unsigned long debugctlmsr) +{ +#ifndef CONFIG_X86_DEBUGCTLMSR + if (boot_cpu_data.x86 < 6) + return; +#endif + wrmsr_on_cpu(cpu, MSR_IA32_DEBUGCTLMSR, + (u32)((u64)debugctlmsr), + (u32)((u64)debugctlmsr >> 32)); +} + /* * from system description table in BIOS. Mostly for MCA use, but * others may find it useful: @@ -814,6 +837,7 @@ extern unsigned int BIOS_revision; /* Boot loader type from the setup header: */ extern int bootloader_type; +extern int bootloader_version; extern char ignore_fpu_irq; @@ -874,7 +898,6 @@ static inline void spin_lock_prefetch(const void *x) .vm86_info = NULL, \ .sysenter_cs = __KERNEL_CS, \ .io_bitmap_ptr = NULL, \ - .fs = __KERNEL_PERCPU, \ } /* diff --git a/arch/x86/include/asm/ptrace.h b/arch/x86/include/asm/ptrace.h index 624f133943ed..0f0d908349aa 100644 --- a/arch/x86/include/asm/ptrace.h +++ b/arch/x86/include/asm/ptrace.h @@ -236,12 +236,11 @@ extern int do_get_thread_area(struct task_struct *p, int idx, extern int do_set_thread_area(struct task_struct *p, int idx, struct user_desc __user *info, int can_allocate); -extern void x86_ptrace_untrace(struct task_struct *); -extern void x86_ptrace_fork(struct task_struct *child, - unsigned long clone_flags); +#ifdef CONFIG_X86_PTRACE_BTS +extern void ptrace_bts_untrace(struct task_struct *tsk); -#define arch_ptrace_untrace(tsk) x86_ptrace_untrace(tsk) -#define arch_ptrace_fork(child, flags) x86_ptrace_fork(child, flags) +#define arch_ptrace_untrace(tsk) ptrace_bts_untrace(tsk) +#endif /* CONFIG_X86_PTRACE_BTS */ #endif /* __KERNEL__ */ diff --git a/arch/x86/include/asm/required-features.h b/arch/x86/include/asm/required-features.h index a4737dddfd58..64cf2d24fad1 100644 --- a/arch/x86/include/asm/required-features.h +++ b/arch/x86/include/asm/required-features.h @@ -48,9 +48,15 @@ #endif #ifdef CONFIG_X86_64 +#ifdef CONFIG_PARAVIRT +/* Paravirtualized systems may not have PSE or PGE available */ #define NEED_PSE 0 -#define NEED_MSR (1<<(X86_FEATURE_MSR & 31)) #define NEED_PGE 0 +#else +#define NEED_PSE (1<<(X86_FEATURE_PSE) & 31) +#define NEED_PGE (1<<(X86_FEATURE_PGE) & 31) +#endif +#define NEED_MSR (1<<(X86_FEATURE_MSR & 31)) #define NEED_FXSR (1<<(X86_FEATURE_FXSR & 31)) #define NEED_XMM (1<<(X86_FEATURE_XMM & 31)) #define NEED_XMM2 (1<<(X86_FEATURE_XMM2 & 31)) diff --git a/arch/x86/include/asm/setup.h b/arch/x86/include/asm/setup.h index bdc2ada05ae0..4093d1ed6db2 100644 --- a/arch/x86/include/asm/setup.h +++ b/arch/x86/include/asm/setup.h @@ -33,7 +33,6 @@ struct x86_quirks { int (*setup_ioapic_ids)(void); }; -extern void x86_quirk_pre_intr_init(void); extern void x86_quirk_intr_init(void); extern void x86_quirk_trap_init(void); diff --git a/arch/x86/include/asm/signal.h b/arch/x86/include/asm/signal.h index 7761a5d554bb..598457cbd0f8 100644 --- a/arch/x86/include/asm/signal.h +++ b/arch/x86/include/asm/signal.h @@ -117,7 +117,7 @@ typedef unsigned long sigset_t; #define MINSIGSTKSZ 2048 #define SIGSTKSZ 8192 -#include +#include #ifndef __ASSEMBLY__ diff --git a/arch/x86/include/asm/smp.h b/arch/x86/include/asm/smp.h index 19e0d88b966d..6a84ed166aec 100644 --- a/arch/x86/include/asm/smp.h +++ b/arch/x86/include/asm/smp.h @@ -180,7 +180,7 @@ extern int safe_smp_processor_id(void); static inline int logical_smp_processor_id(void) { /* we don't want to mark this access volatile - bad code generation */ - return GET_APIC_LOGICAL_ID(*(u32 *)(APIC_BASE + APIC_LDR)); + return GET_APIC_LOGICAL_ID(apic_read(APIC_LDR)); } #endif diff --git a/arch/x86/include/asm/sparsemem.h b/arch/x86/include/asm/sparsemem.h index e3cc3c063ec5..4517d6b93188 100644 --- a/arch/x86/include/asm/sparsemem.h +++ b/arch/x86/include/asm/sparsemem.h @@ -27,7 +27,7 @@ #else /* CONFIG_X86_32 */ # define SECTION_SIZE_BITS 27 /* matt - 128 is convenient right now */ # define MAX_PHYSADDR_BITS 44 -# define MAX_PHYSMEM_BITS 44 /* Can be max 45 bits */ +# define MAX_PHYSMEM_BITS 46 #endif #endif /* CONFIG_SPARSEMEM */ diff --git a/arch/x86/include/asm/string_32.h b/arch/x86/include/asm/string_32.h index 0e0e3ba827f7..c86f452256de 100644 --- a/arch/x86/include/asm/string_32.h +++ b/arch/x86/include/asm/string_32.h @@ -177,10 +177,18 @@ static inline void *__memcpy3d(void *to, const void *from, size_t len) * No 3D Now! */ +#ifndef CONFIG_KMEMCHECK #define memcpy(t, f, n) \ (__builtin_constant_p((n)) \ ? __constant_memcpy((t), (f), (n)) \ : __memcpy((t), (f), (n))) +#else +/* + * kmemcheck becomes very happy if we use the REP instructions unconditionally, + * because it means that we know both memory operands in advance. + */ +#define memcpy(t, f, n) __memcpy((t), (f), (n)) +#endif #endif diff --git a/arch/x86/include/asm/string_64.h b/arch/x86/include/asm/string_64.h index 2afe164bf1e6..19e2c468fc2c 100644 --- a/arch/x86/include/asm/string_64.h +++ b/arch/x86/include/asm/string_64.h @@ -27,6 +27,7 @@ static __always_inline void *__inline_memcpy(void *to, const void *from, size_t function. */ #define __HAVE_ARCH_MEMCPY 1 +#ifndef CONFIG_KMEMCHECK #if (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) || __GNUC__ > 4 extern void *memcpy(void *to, const void *from, size_t len); #else @@ -42,6 +43,13 @@ extern void *__memcpy(void *to, const void *from, size_t len); __ret; \ }) #endif +#else +/* + * kmemcheck becomes very happy if we use the REP instructions unconditionally, + * because it means that we know both memory operands in advance. + */ +#define memcpy(dst, src, len) __inline_memcpy((dst), (src), (len)) +#endif #define __HAVE_ARCH_MEMSET void *memset(void *s, int c, size_t n); diff --git a/arch/x86/include/asm/svm.h b/arch/x86/include/asm/svm.h index 82ada75f3ebf..85574b7c1bc1 100644 --- a/arch/x86/include/asm/svm.h +++ b/arch/x86/include/asm/svm.h @@ -225,6 +225,7 @@ struct __attribute__ ((__packed__)) vmcb { #define SVM_EVTINJ_VALID_ERR (1 << 11) #define SVM_EXITINTINFO_VEC_MASK SVM_EVTINJ_VEC_MASK +#define SVM_EXITINTINFO_TYPE_MASK SVM_EVTINJ_TYPE_MASK #define SVM_EXITINTINFO_TYPE_INTR SVM_EVTINJ_TYPE_INTR #define SVM_EXITINTINFO_TYPE_NMI SVM_EVTINJ_TYPE_NMI diff --git a/arch/x86/include/asm/syscalls.h b/arch/x86/include/asm/syscalls.h index 7043408f6904..372b76edd63f 100644 --- a/arch/x86/include/asm/syscalls.h +++ b/arch/x86/include/asm/syscalls.h @@ -1,7 +1,7 @@ /* * syscalls.h - Linux syscall interfaces (arch-specific) * - * Copyright (c) 2008 Jaswinder Singh + * Copyright (c) 2008 Jaswinder Singh Rajput * * This file is released under the GPLv2. * See the file COPYING for more details. @@ -12,50 +12,55 @@ #include #include -#include #include +#include /* Common in X86_32 and X86_64 */ /* kernel/ioport.c */ asmlinkage long sys_ioperm(unsigned long, unsigned long, int); +/* kernel/process.c */ +int sys_fork(struct pt_regs *); +int sys_vfork(struct pt_regs *); + /* kernel/ldt.c */ asmlinkage int sys_modify_ldt(int, void __user *, unsigned long); +/* kernel/signal.c */ +long sys_rt_sigreturn(struct pt_regs *); + /* kernel/tls.c */ asmlinkage int sys_set_thread_area(struct user_desc __user *); asmlinkage int sys_get_thread_area(struct user_desc __user *); /* X86_32 only */ #ifdef CONFIG_X86_32 +/* kernel/ioport.c */ +long sys_iopl(struct pt_regs *); + /* kernel/process_32.c */ -int sys_fork(struct pt_regs *); int sys_clone(struct pt_regs *); -int sys_vfork(struct pt_regs *); int sys_execve(struct pt_regs *); -/* kernel/signal_32.c */ +/* kernel/signal.c */ asmlinkage int sys_sigsuspend(int, int, old_sigset_t); asmlinkage int sys_sigaction(int, const struct old_sigaction __user *, struct old_sigaction __user *); int sys_sigaltstack(struct pt_regs *); unsigned long sys_sigreturn(struct pt_regs *); -long sys_rt_sigreturn(struct pt_regs *); - -/* kernel/ioport.c */ -long sys_iopl(struct pt_regs *); /* kernel/sys_i386_32.c */ +struct mmap_arg_struct; +struct sel_arg_struct; +struct oldold_utsname; +struct old_utsname; + asmlinkage long sys_mmap2(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long); -struct mmap_arg_struct; asmlinkage int old_mmap(struct mmap_arg_struct __user *); -struct sel_arg_struct; asmlinkage int old_select(struct sel_arg_struct __user *); asmlinkage int sys_ipc(uint, int, int, int, void __user *, long); -struct old_utsname; asmlinkage int sys_uname(struct old_utsname __user *); -struct oldold_utsname; asmlinkage int sys_olduname(struct oldold_utsname __user *); /* kernel/vm86_32.c */ @@ -65,29 +70,27 @@ int sys_vm86(struct pt_regs *); #else /* CONFIG_X86_32 */ /* X86_64 only */ +/* kernel/ioport.c */ +asmlinkage long sys_iopl(unsigned int, struct pt_regs *); + /* kernel/process_64.c */ -asmlinkage long sys_fork(struct pt_regs *); asmlinkage long sys_clone(unsigned long, unsigned long, void __user *, void __user *, struct pt_regs *); -asmlinkage long sys_vfork(struct pt_regs *); asmlinkage long sys_execve(char __user *, char __user * __user *, char __user * __user *, struct pt_regs *); long sys_arch_prctl(int, unsigned long); -/* kernel/ioport.c */ -asmlinkage long sys_iopl(unsigned int, struct pt_regs *); - -/* kernel/signal_64.c */ +/* kernel/signal.c */ asmlinkage long sys_sigaltstack(const stack_t __user *, stack_t __user *, struct pt_regs *); -long sys_rt_sigreturn(struct pt_regs *); /* kernel/sys_x86_64.c */ +struct new_utsname; + asmlinkage long sys_mmap(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long); -struct new_utsname; asmlinkage long sys_uname(struct new_utsname __user *); #endif /* CONFIG_X86_32 */ diff --git a/arch/x86/include/asm/termios.h b/arch/x86/include/asm/termios.h index f72956331c49..c4ee8056baca 100644 --- a/arch/x86/include/asm/termios.h +++ b/arch/x86/include/asm/termios.h @@ -67,6 +67,7 @@ static inline int user_termio_to_kernel_termios(struct ktermios *termios, SET_LOW_TERMIOS_BITS(termios, termio, c_oflag); SET_LOW_TERMIOS_BITS(termios, termio, c_cflag); SET_LOW_TERMIOS_BITS(termios, termio, c_lflag); + get_user(termios->c_line, &termio->c_line); return copy_from_user(termios->c_cc, termio->c_cc, NCC); } diff --git a/arch/x86/include/asm/therm_throt.h b/arch/x86/include/asm/therm_throt.h deleted file mode 100644 index c62349ee7860..000000000000 --- a/arch/x86/include/asm/therm_throt.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef _ASM_X86_THERM_THROT_H -#define _ASM_X86_THERM_THROT_H - -#include - -extern atomic_t therm_throt_en; -int therm_throt_process(int curr); - -#endif /* _ASM_X86_THERM_THROT_H */ diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h index 8820a73ae090..b0783520988b 100644 --- a/arch/x86/include/asm/thread_info.h +++ b/arch/x86/include/asm/thread_info.h @@ -94,7 +94,8 @@ struct thread_info { #define TIF_FORCED_TF 24 /* true if TF in eflags artificially */ #define TIF_DEBUGCTLMSR 25 /* uses thread_struct.debugctlmsr */ #define TIF_DS_AREA_MSR 26 /* uses thread_struct.ds_area_msr */ -#define TIF_SYSCALL_FTRACE 27 /* for ftrace syscall instrumentation */ +#define TIF_LAZY_MMU_UPDATES 27 /* task is updating the mmu lazily */ +#define TIF_SYSCALL_FTRACE 28 /* for ftrace syscall instrumentation */ #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) @@ -116,6 +117,7 @@ struct thread_info { #define _TIF_FORCED_TF (1 << TIF_FORCED_TF) #define _TIF_DEBUGCTLMSR (1 << TIF_DEBUGCTLMSR) #define _TIF_DS_AREA_MSR (1 << TIF_DS_AREA_MSR) +#define _TIF_LAZY_MMU_UPDATES (1 << TIF_LAZY_MMU_UPDATES) #define _TIF_SYSCALL_FTRACE (1 << TIF_SYSCALL_FTRACE) /* work to do in syscall_trace_enter() */ @@ -152,9 +154,9 @@ struct thread_info { /* thread information allocation */ #ifdef CONFIG_DEBUG_STACK_USAGE -#define THREAD_FLAGS (GFP_KERNEL | __GFP_ZERO) +#define THREAD_FLAGS (GFP_KERNEL | __GFP_NOTRACK | __GFP_ZERO) #else -#define THREAD_FLAGS GFP_KERNEL +#define THREAD_FLAGS (GFP_KERNEL | __GFP_NOTRACK) #endif #define __HAVE_ARCH_THREAD_INFO_ALLOCATOR diff --git a/arch/x86/include/asm/timer.h b/arch/x86/include/asm/timer.h index bd37ed444a21..20ca9c4d4686 100644 --- a/arch/x86/include/asm/timer.h +++ b/arch/x86/include/asm/timer.h @@ -45,12 +45,16 @@ extern int no_timer_check; */ DECLARE_PER_CPU(unsigned long, cyc2ns); +DECLARE_PER_CPU(unsigned long long, cyc2ns_offset); #define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen */ static inline unsigned long long __cycles_2_ns(unsigned long long cyc) { - return cyc * per_cpu(cyc2ns, smp_processor_id()) >> CYC2NS_SCALE_FACTOR; + int cpu = smp_processor_id(); + unsigned long long ns = per_cpu(cyc2ns_offset, cpu); + ns += cyc * per_cpu(cyc2ns, cpu) >> CYC2NS_SCALE_FACTOR; + return ns; } static inline unsigned long long cycles_2_ns(unsigned long long cyc) diff --git a/arch/x86/include/asm/timex.h b/arch/x86/include/asm/timex.h index b5c9d45c981f..1375cfc93960 100644 --- a/arch/x86/include/asm/timex.h +++ b/arch/x86/include/asm/timex.h @@ -4,9 +4,7 @@ #include #include -/* The PIT ticks at this frequency (in HZ): */ -#define PIT_TICK_RATE 1193182 - +/* Assume we use the PIT time source for the clock tick */ #define CLOCK_TICK_RATE PIT_TICK_RATE #define ARCH_HAS_READ_CURRENT_TIMER diff --git a/arch/x86/include/asm/tlbflush.h b/arch/x86/include/asm/tlbflush.h index 16a5c84b0329..7f3eba08e7de 100644 --- a/arch/x86/include/asm/tlbflush.h +++ b/arch/x86/include/asm/tlbflush.h @@ -17,7 +17,7 @@ static inline void __native_flush_tlb(void) { - write_cr3(read_cr3()); + native_write_cr3(native_read_cr3()); } static inline void __native_flush_tlb_global(void) @@ -32,11 +32,11 @@ static inline void __native_flush_tlb_global(void) */ raw_local_irq_save(flags); - cr4 = read_cr4(); + cr4 = native_read_cr4(); /* clear PGE */ - write_cr4(cr4 & ~X86_CR4_PGE); + native_write_cr4(cr4 & ~X86_CR4_PGE); /* write old PGE again and flush TLBs */ - write_cr4(cr4); + native_write_cr4(cr4); raw_local_irq_restore(flags); } @@ -172,6 +172,6 @@ static inline void flush_tlb_kernel_range(unsigned long start, flush_tlb_all(); } -extern void zap_low_mappings(void); +extern void zap_low_mappings(bool early); #endif /* _ASM_X86_TLBFLUSH_H */ diff --git a/arch/x86/include/asm/topology.h b/arch/x86/include/asm/topology.h index f44b49abca49..066ef590d7e0 100644 --- a/arch/x86/include/asm/topology.h +++ b/arch/x86/include/asm/topology.h @@ -203,7 +203,8 @@ struct pci_bus; void x86_pci_root_bus_res_quirks(struct pci_bus *b); #ifdef CONFIG_SMP -#define mc_capable() (cpumask_weight(cpu_core_mask(0)) != nr_cpu_ids) +#define mc_capable() ((boot_cpu_data.x86_max_cores > 1) && \ + (cpumask_weight(cpu_core_mask(0)) != nr_cpu_ids)) #define smt_capable() (smp_num_siblings > 1) #endif diff --git a/arch/x86/include/asm/traps.h b/arch/x86/include/asm/traps.h index 0d5342515b86..bfd74c032fca 100644 --- a/arch/x86/include/asm/traps.h +++ b/arch/x86/include/asm/traps.h @@ -2,6 +2,7 @@ #define _ASM_X86_TRAPS_H #include +#include /* TRAP_TRACE, ... */ #ifdef CONFIG_X86_32 #define dotraplinkage @@ -13,6 +14,9 @@ asmlinkage void divide_error(void); asmlinkage void debug(void); asmlinkage void nmi(void); asmlinkage void int3(void); +asmlinkage void xen_debug(void); +asmlinkage void xen_int3(void); +asmlinkage void xen_stack_segment(void); asmlinkage void overflow(void); asmlinkage void bounds(void); asmlinkage void invalid_op(void); @@ -74,7 +78,6 @@ static inline int get_si_code(unsigned long condition) } extern int panic_on_unrecovered_nmi; -extern int kstack_depth_to_print; void math_error(void __user *); void math_emulate(struct math_emu_info *); diff --git a/arch/x86/include/asm/types.h b/arch/x86/include/asm/types.h index e6f736320077..09b97745772f 100644 --- a/arch/x86/include/asm/types.h +++ b/arch/x86/include/asm/types.h @@ -14,12 +14,6 @@ typedef unsigned short umode_t; */ #ifdef __KERNEL__ -#ifdef CONFIG_X86_32 -# define BITS_PER_LONG 32 -#else -# define BITS_PER_LONG 64 -#endif - #ifndef __ASSEMBLY__ typedef u64 dma64_addr_t; diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h index b685ece89d5c..20e6a795e160 100644 --- a/arch/x86/include/asm/uaccess.h +++ b/arch/x86/include/asm/uaccess.h @@ -25,7 +25,7 @@ #define MAKE_MM_SEG(s) ((mm_segment_t) { (s) }) #define KERNEL_DS MAKE_MM_SEG(-1UL) -#define USER_DS MAKE_MM_SEG(PAGE_OFFSET) +#define USER_DS MAKE_MM_SEG(TASK_SIZE_MAX) #define get_ds() (KERNEL_DS) #define get_fs() (current_thread_info()->addr_limit) diff --git a/arch/x86/include/asm/unistd_32.h b/arch/x86/include/asm/unistd_32.h index 6e72d74cf8dc..732a30706153 100644 --- a/arch/x86/include/asm/unistd_32.h +++ b/arch/x86/include/asm/unistd_32.h @@ -340,6 +340,8 @@ #define __NR_inotify_init1 332 #define __NR_preadv 333 #define __NR_pwritev 334 +#define __NR_rt_tgsigqueueinfo 335 +#define __NR_perf_counter_open 336 #ifdef __KERNEL__ diff --git a/arch/x86/include/asm/unistd_64.h b/arch/x86/include/asm/unistd_64.h index f81829462325..900e1617e672 100644 --- a/arch/x86/include/asm/unistd_64.h +++ b/arch/x86/include/asm/unistd_64.h @@ -657,7 +657,10 @@ __SYSCALL(__NR_inotify_init1, sys_inotify_init1) __SYSCALL(__NR_preadv, sys_preadv) #define __NR_pwritev 296 __SYSCALL(__NR_pwritev, sys_pwritev) - +#define __NR_rt_tgsigqueueinfo 297 +__SYSCALL(__NR_rt_tgsigqueueinfo, sys_rt_tgsigqueueinfo) +#define __NR_perf_counter_open 298 +__SYSCALL(__NR_perf_counter_open, sys_perf_counter_open) #ifndef __NO_STUBS #define __ARCH_WANT_OLD_READDIR diff --git a/arch/x86/include/asm/uv/uv_bau.h b/arch/x86/include/asm/uv/uv_bau.h index 9b0e61bf7a88..bddd44f2f0ab 100644 --- a/arch/x86/include/asm/uv/uv_bau.h +++ b/arch/x86/include/asm/uv/uv_bau.h @@ -37,7 +37,7 @@ #define UV_CPUS_PER_ACT_STATUS 32 #define UV_ACT_STATUS_MASK 0x3 #define UV_ACT_STATUS_SIZE 2 -#define UV_ACTIVATION_DESCRIPTOR_SIZE 32 +#define UV_ADP_SIZE 32 #define UV_DISTRIBUTION_SIZE 256 #define UV_SW_ACK_NPENDING 8 #define UV_NET_ENDPOINT_INTD 0x38 diff --git a/arch/x86/include/asm/uv/uv_hub.h b/arch/x86/include/asm/uv/uv_hub.h index d3a98ea1062e..341070f7ad5c 100644 --- a/arch/x86/include/asm/uv/uv_hub.h +++ b/arch/x86/include/asm/uv/uv_hub.h @@ -133,6 +133,7 @@ struct uv_scir_s { struct uv_hub_info_s { unsigned long global_mmr_base; unsigned long gpa_mask; + unsigned int gnode_extra; unsigned long gnode_upper; unsigned long lowmem_remap_top; unsigned long lowmem_remap_base; @@ -159,7 +160,8 @@ DECLARE_PER_CPU(struct uv_hub_info_s, __uv_hub_info); * p - PNODE (local part of nsids, right shifted 1) */ #define UV_NASID_TO_PNODE(n) (((n) >> 1) & uv_hub_info->pnode_mask) -#define UV_PNODE_TO_NASID(p) (((p) << 1) | uv_hub_info->gnode_upper) +#define UV_PNODE_TO_GNODE(p) ((p) |uv_hub_info->gnode_extra) +#define UV_PNODE_TO_NASID(p) (UV_PNODE_TO_GNODE(p) << 1) #define UV_LOCAL_MMR_BASE 0xf4000000UL #define UV_GLOBAL_MMR32_BASE 0xf8000000UL @@ -173,7 +175,7 @@ DECLARE_PER_CPU(struct uv_hub_info_s, __uv_hub_info); #define UV_GLOBAL_MMR32_PNODE_BITS(p) ((p) << (UV_GLOBAL_MMR32_PNODE_SHIFT)) #define UV_GLOBAL_MMR64_PNODE_BITS(p) \ - ((unsigned long)(p) << UV_GLOBAL_MMR64_PNODE_SHIFT) + ((unsigned long)(UV_PNODE_TO_GNODE(p)) << UV_GLOBAL_MMR64_PNODE_SHIFT) #define UV_APIC_PNODE_SHIFT 6 diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h index 498f944010b9..11be5ad2e0e9 100644 --- a/arch/x86/include/asm/vmx.h +++ b/arch/x86/include/asm/vmx.h @@ -247,6 +247,7 @@ enum vmcs_field { #define EXIT_REASON_MSR_READ 31 #define EXIT_REASON_MSR_WRITE 32 #define EXIT_REASON_MWAIT_INSTRUCTION 36 +#define EXIT_REASON_MCE_DURING_VMENTRY 41 #define EXIT_REASON_TPR_BELOW_THRESHOLD 43 #define EXIT_REASON_APIC_ACCESS 44 #define EXIT_REASON_EPT_VIOLATION 48 diff --git a/arch/x86/include/asm/xor.h b/arch/x86/include/asm/xor.h index 11b3bb86e17b..7fcf6f3dbcc3 100644 --- a/arch/x86/include/asm/xor.h +++ b/arch/x86/include/asm/xor.h @@ -1,5 +1,10 @@ +#ifdef CONFIG_KMEMCHECK +/* kmemcheck doesn't handle MMX/SSE/SSE2 instructions */ +# include +#else #ifdef CONFIG_X86_32 # include "xor_32.h" #else # include "xor_64.h" #endif +#endif diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 88d1bfc847d3..6c327b852e23 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -24,11 +24,13 @@ CFLAGS_vsyscall_64.o := $(PROFILING) -g0 $(nostackp) CFLAGS_hpet.o := $(nostackp) CFLAGS_tsc.o := $(nostackp) CFLAGS_paravirt.o := $(nostackp) +GCOV_PROFILE_vsyscall_64.o := n +GCOV_PROFILE_hpet.o := n obj-y := process_$(BITS).o signal.o entry_$(BITS).o obj-y += traps.o irq.o irq_$(BITS).o dumpstack_$(BITS).o obj-y += time_$(BITS).o ioport.o ldt.o dumpstack.o -obj-y += setup.o i8259.o irqinit_$(BITS).o +obj-y += setup.o i8259.o irqinit.o obj-$(CONFIG_X86_VISWS) += visws_quirks.o obj-$(CONFIG_X86_32) += probe_roms_32.o obj-$(CONFIG_X86_32) += sys_i386_32.o i386_ksyms_32.o @@ -44,6 +46,7 @@ obj-y += process.o obj-y += i387.o xsave.o obj-y += ptrace.o obj-$(CONFIG_X86_DS) += ds.o +obj-$(CONFIG_X86_DS_SELFTEST) += ds_selftest.o obj-$(CONFIG_X86_32) += tls.o obj-$(CONFIG_IA32_EMULATION) += tls.o obj-y += step.o @@ -72,7 +75,7 @@ obj-$(CONFIG_KEXEC) += machine_kexec_$(BITS).o obj-$(CONFIG_KEXEC) += relocate_kernel_$(BITS).o crash.o obj-$(CONFIG_CRASH_DUMP) += crash_dump_$(BITS).o obj-$(CONFIG_KPROBES) += kprobes.o -obj-$(CONFIG_MODULES) += module_$(BITS).o +obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_EFI) += efi.o efi_$(BITS).o efi_stub_$(BITS).o obj-$(CONFIG_DOUBLEFAULT) += doublefault_32.o obj-$(CONFIG_KGDB) += kgdb.o diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index 723989d7f802..6b8ca3a0285d 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -43,11 +44,7 @@ static int __initdata acpi_force = 0; u32 acpi_rsdt_forced; -#ifdef CONFIG_ACPI -int acpi_disabled = 0; -#else -int acpi_disabled = 1; -#endif +int acpi_disabled; EXPORT_SYMBOL(acpi_disabled); #ifdef CONFIG_X86_64 @@ -121,72 +118,6 @@ void __init __acpi_unmap_table(char *map, unsigned long size) early_iounmap(map, size); } -#ifdef CONFIG_PCI_MMCONFIG - -static int acpi_mcfg_64bit_base_addr __initdata = FALSE; - -/* The physical address of the MMCONFIG aperture. Set from ACPI tables. */ -struct acpi_mcfg_allocation *pci_mmcfg_config; -int pci_mmcfg_config_num; - -static int __init acpi_mcfg_oem_check(struct acpi_table_mcfg *mcfg) -{ - if (!strcmp(mcfg->header.oem_id, "SGI")) - acpi_mcfg_64bit_base_addr = TRUE; - - return 0; -} - -int __init acpi_parse_mcfg(struct acpi_table_header *header) -{ - struct acpi_table_mcfg *mcfg; - unsigned long i; - int config_size; - - if (!header) - return -EINVAL; - - mcfg = (struct acpi_table_mcfg *)header; - - /* how many config structures do we have */ - pci_mmcfg_config_num = 0; - i = header->length - sizeof(struct acpi_table_mcfg); - while (i >= sizeof(struct acpi_mcfg_allocation)) { - ++pci_mmcfg_config_num; - i -= sizeof(struct acpi_mcfg_allocation); - }; - if (pci_mmcfg_config_num == 0) { - printk(KERN_ERR PREFIX "MMCONFIG has no entries\n"); - return -ENODEV; - } - - config_size = pci_mmcfg_config_num * sizeof(*pci_mmcfg_config); - pci_mmcfg_config = kmalloc(config_size, GFP_KERNEL); - if (!pci_mmcfg_config) { - printk(KERN_WARNING PREFIX - "No memory for MCFG config tables\n"); - return -ENOMEM; - } - - memcpy(pci_mmcfg_config, &mcfg[1], config_size); - - acpi_mcfg_oem_check(mcfg); - - for (i = 0; i < pci_mmcfg_config_num; ++i) { - if ((pci_mmcfg_config[i].address > 0xFFFFFFFF) && - !acpi_mcfg_64bit_base_addr) { - printk(KERN_ERR PREFIX - "MMCONFIG not in low 4GB of memory\n"); - kfree(pci_mmcfg_config); - pci_mmcfg_config_num = 0; - return -ENODEV; - } - } - - return 0; -} -#endif /* CONFIG_PCI_MMCONFIG */ - #ifdef CONFIG_X86_LOCAL_APIC static int __init acpi_parse_madt(struct acpi_table_header *table) { @@ -522,7 +453,7 @@ int acpi_gsi_to_irq(u32 gsi, unsigned int *irq) * success: return IRQ number (>=0) * failure: return < 0 */ -int acpi_register_gsi(u32 gsi, int triggering, int polarity) +int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity) { unsigned int irq; unsigned int plat_gsi = gsi; @@ -532,14 +463,14 @@ int acpi_register_gsi(u32 gsi, int triggering, int polarity) * Make sure all (legacy) PCI IRQs are set as level-triggered. */ if (acpi_irq_model == ACPI_IRQ_MODEL_PIC) { - if (triggering == ACPI_LEVEL_SENSITIVE) + if (trigger == ACPI_LEVEL_SENSITIVE) eisa_set_level_irq(gsi); } #endif #ifdef CONFIG_X86_IO_APIC if (acpi_irq_model == ACPI_IRQ_MODEL_IOAPIC) { - plat_gsi = mp_register_gsi(gsi, triggering, polarity); + plat_gsi = mp_register_gsi(dev, gsi, trigger, polarity); } #endif acpi_gsi_to_irq(plat_gsi, &irq); @@ -903,10 +834,8 @@ extern int es7000_plat; #endif static struct { - int apic_id; int gsi_base; int gsi_end; - DECLARE_BITMAP(pin_programmed, MP_MAX_IOAPIC_PIN + 1); } mp_ioapic_routing[MAX_IO_APICS]; int mp_find_ioapic(int gsi) @@ -986,16 +915,12 @@ void __init mp_register_ioapic(int id, u32 address, u32 gsi_base) set_fixmap_nocache(FIX_IO_APIC_BASE_0 + idx, address); mp_ioapics[idx].apicid = uniq_ioapic_id(id); -#ifdef CONFIG_X86_32 mp_ioapics[idx].apicver = io_apic_get_version(idx); -#else - mp_ioapics[idx].apicver = 0; -#endif + /* * Build basic GSI lookup table to facilitate gsi->io_apic lookups * and to prevent reprogramming of IOAPIC pins (PCI GSIs). */ - mp_ioapic_routing[idx].apic_id = mp_ioapics[idx].apicid; mp_ioapic_routing[idx].gsi_base = gsi_base; mp_ioapic_routing[idx].gsi_end = gsi_base + io_apic_get_redir_entries(idx); @@ -1158,26 +1083,52 @@ void __init mp_config_acpi_legacy_irqs(void) } } -int mp_register_gsi(u32 gsi, int triggering, int polarity) +static int mp_config_acpi_gsi(struct device *dev, u32 gsi, int trigger, + int polarity) +{ +#ifdef CONFIG_X86_MPPARSE + struct mpc_intsrc mp_irq; + struct pci_dev *pdev; + unsigned char number; + unsigned int devfn; + int ioapic; + u8 pin; + + if (!acpi_ioapic) + return 0; + if (!dev) + return 0; + if (dev->bus != &pci_bus_type) + return 0; + + pdev = to_pci_dev(dev); + number = pdev->bus->number; + devfn = pdev->devfn; + pin = pdev->pin; + /* print the entry should happen on mptable identically */ + mp_irq.type = MP_INTSRC; + mp_irq.irqtype = mp_INT; + mp_irq.irqflag = (trigger == ACPI_EDGE_SENSITIVE ? 4 : 0x0c) | + (polarity == ACPI_ACTIVE_HIGH ? 1 : 3); + mp_irq.srcbus = number; + mp_irq.srcbusirq = (((devfn >> 3) & 0x1f) << 2) | ((pin - 1) & 3); + ioapic = mp_find_ioapic(gsi); + mp_irq.dstapic = mp_ioapics[ioapic].apicid; + mp_irq.dstirq = mp_find_ioapic_pin(ioapic, gsi); + + save_mp_irq(&mp_irq); +#endif + return 0; +} + +int mp_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity) { int ioapic; int ioapic_pin; -#ifdef CONFIG_X86_32 -#define MAX_GSI_NUM 4096 -#define IRQ_COMPRESSION_START 64 - - static int pci_irq = IRQ_COMPRESSION_START; - /* - * Mapping between Global System Interrupts, which - * represent all possible interrupts, and IRQs - * assigned to actual devices. - */ - static int gsi_to_irq[MAX_GSI_NUM]; -#else + struct io_apic_irq_attr irq_attr; if (acpi_irq_model != ACPI_IRQ_MODEL_IOAPIC) return gsi; -#endif /* Don't set up the ACPI SCI because it's already set up */ if (acpi_gbl_FADT.sci_interrupt == gsi) @@ -1196,95 +1147,24 @@ int mp_register_gsi(u32 gsi, int triggering, int polarity) gsi = ioapic_renumber_irq(ioapic, gsi); #endif - /* - * Avoid pin reprogramming. PRTs typically include entries - * with redundant pin->gsi mappings (but unique PCI devices); - * we only program the IOAPIC on the first. - */ if (ioapic_pin > MP_MAX_IOAPIC_PIN) { printk(KERN_ERR "Invalid reference to IOAPIC pin " - "%d-%d\n", mp_ioapic_routing[ioapic].apic_id, + "%d-%d\n", mp_ioapics[ioapic].apicid, ioapic_pin); return gsi; } - if (test_bit(ioapic_pin, mp_ioapic_routing[ioapic].pin_programmed)) { - pr_debug("Pin %d-%d already programmed\n", - mp_ioapic_routing[ioapic].apic_id, ioapic_pin); -#ifdef CONFIG_X86_32 - return (gsi < IRQ_COMPRESSION_START ? gsi : gsi_to_irq[gsi]); -#else - return gsi; -#endif - } - set_bit(ioapic_pin, mp_ioapic_routing[ioapic].pin_programmed); -#ifdef CONFIG_X86_32 - /* - * For GSI >= 64, use IRQ compression - */ - if ((gsi >= IRQ_COMPRESSION_START) - && (triggering == ACPI_LEVEL_SENSITIVE)) { - /* - * For PCI devices assign IRQs in order, avoiding gaps - * due to unused I/O APIC pins. - */ - int irq = gsi; - if (gsi < MAX_GSI_NUM) { - /* - * Retain the VIA chipset work-around (gsi > 15), but - * avoid a problem where the 8254 timer (IRQ0) is setup - * via an override (so it's not on pin 0 of the ioapic), - * and at the same time, the pin 0 interrupt is a PCI - * type. The gsi > 15 test could cause these two pins - * to be shared as IRQ0, and they are not shareable. - * So test for this condition, and if necessary, avoid - * the pin collision. - */ - gsi = pci_irq++; - /* - * Don't assign IRQ used by ACPI SCI - */ - if (gsi == acpi_gbl_FADT.sci_interrupt) - gsi = pci_irq++; - gsi_to_irq[irq] = gsi; - } else { - printk(KERN_ERR "GSI %u is too high\n", gsi); - return gsi; - } - } -#endif - io_apic_set_pci_routing(ioapic, ioapic_pin, gsi, - triggering == ACPI_EDGE_SENSITIVE ? 0 : 1, - polarity == ACPI_ACTIVE_HIGH ? 0 : 1); + if (enable_update_mptable) + mp_config_acpi_gsi(dev, gsi, trigger, polarity); + + set_io_apic_irq_attr(&irq_attr, ioapic, ioapic_pin, + trigger == ACPI_EDGE_SENSITIVE ? 0 : 1, + polarity == ACPI_ACTIVE_HIGH ? 0 : 1); + io_apic_set_pci_routing(dev, gsi, &irq_attr); + return gsi; } -int mp_config_acpi_gsi(unsigned char number, unsigned int devfn, u8 pin, - u32 gsi, int triggering, int polarity) -{ -#ifdef CONFIG_X86_MPPARSE - struct mpc_intsrc mp_irq; - int ioapic; - - if (!acpi_ioapic) - return 0; - - /* print the entry should happen on mptable identically */ - mp_irq.type = MP_INTSRC; - mp_irq.irqtype = mp_INT; - mp_irq.irqflag = (triggering == ACPI_EDGE_SENSITIVE ? 4 : 0x0c) | - (polarity == ACPI_ACTIVE_HIGH ? 1 : 3); - mp_irq.srcbus = number; - mp_irq.srcbusirq = (((devfn >> 3) & 0x1f) << 2) | ((pin - 1) & 3); - ioapic = mp_find_ioapic(gsi); - mp_irq.dstapic = mp_ioapic_routing[ioapic].apic_id; - mp_irq.dstirq = mp_find_ioapic_pin(ioapic, gsi); - - save_mp_irq(&mp_irq); -#endif - return 0; -} - /* * Parse IOAPIC related entries in MADT * returns 0 on success, < 0 on error @@ -1567,14 +1447,6 @@ static struct dmi_system_id __initdata acpi_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Workstation W8000"), }, }, - { - .callback = force_acpi_ht, - .ident = "ASUS P4B266", - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), - DMI_MATCH(DMI_BOARD_NAME, "P4B266"), - }, - }, { .callback = force_acpi_ht, .ident = "ASUS P2B-DS", diff --git a/arch/x86/kernel/acpi/cstate.c b/arch/x86/kernel/acpi/cstate.c index bbbe4bbb6f34..8c44c232efcb 100644 --- a/arch/x86/kernel/acpi/cstate.c +++ b/arch/x86/kernel/acpi/cstate.c @@ -34,12 +34,22 @@ void acpi_processor_power_init_bm_check(struct acpi_processor_flags *flags, flags->bm_check = 1; else if (c->x86_vendor == X86_VENDOR_INTEL) { /* - * Today all CPUs that support C3 share cache. - * TBD: This needs to look at cache shared map, once - * multi-core detection patch makes to the base. + * Today all MP CPUs that support C3 share cache. + * And caches should not be flushed by software while + * entering C3 type state. */ flags->bm_check = 1; } + + /* + * On all recent Intel platforms, ARB_DISABLE is a nop. + * So, set bm_control to zero to indicate that ARB_DISABLE + * is not required while entering C3 type state on + * P4, Core and beyond CPUs + */ + if (c->x86_vendor == X86_VENDOR_INTEL && + (c->x86 > 0x6 || (c->x86 == 6 && c->x86_model >= 14))) + flags->bm_control = 0; } EXPORT_SYMBOL(acpi_processor_power_init_bm_check); diff --git a/arch/x86/kernel/acpi/processor.c b/arch/x86/kernel/acpi/processor.c index 7c074eec39fb..d296f4a195c9 100644 --- a/arch/x86/kernel/acpi/processor.c +++ b/arch/x86/kernel/acpi/processor.c @@ -72,6 +72,7 @@ static void init_intel_pdc(struct acpi_processor *pr, struct cpuinfo_x86 *c) return; } + /* Initialize _PDC data based on the CPU vendor */ void arch_acpi_processor_init_pdc(struct acpi_processor *pr) { @@ -85,3 +86,15 @@ void arch_acpi_processor_init_pdc(struct acpi_processor *pr) } EXPORT_SYMBOL(arch_acpi_processor_init_pdc); + +void arch_acpi_processor_cleanup_pdc(struct acpi_processor *pr) +{ + if (pr->pdc) { + kfree(pr->pdc->pointer->buffer.pointer); + kfree(pr->pdc->pointer); + kfree(pr->pdc); + pr->pdc = NULL; + } +} + +EXPORT_SYMBOL(arch_acpi_processor_cleanup_pdc); diff --git a/arch/x86/kernel/acpi/realmode/Makefile b/arch/x86/kernel/acpi/realmode/Makefile index 1c31cc0e9def..6a564ac67ef5 100644 --- a/arch/x86/kernel/acpi/realmode/Makefile +++ b/arch/x86/kernel/acpi/realmode/Makefile @@ -9,7 +9,7 @@ always := wakeup.bin targets := wakeup.elf wakeup.lds -wakeup-y += wakeup.o wakemain.o video-mode.o copy.o +wakeup-y += wakeup.o wakemain.o video-mode.o copy.o bioscall.o regs.o # The link order of the video-*.o modules can matter. In particular, # video-vga.o *must* be listed first, followed by video-vesa.o. @@ -42,6 +42,7 @@ KBUILD_CFLAGS := $(LINUXINCLUDE) -g -Os -D_SETUP -D_WAKEUP -D__KERNEL__ \ $(call cc-option, -mpreferred-stack-boundary=2) KBUILD_CFLAGS += $(call cc-option, -m32) KBUILD_AFLAGS := $(KBUILD_CFLAGS) -D__ASSEMBLY__ +GCOV_PROFILE := n WAKEUP_OBJS = $(addprefix $(obj)/,$(wakeup-y)) diff --git a/arch/x86/kernel/acpi/realmode/bioscall.S b/arch/x86/kernel/acpi/realmode/bioscall.S new file mode 100644 index 000000000000..f51eb0bb56ce --- /dev/null +++ b/arch/x86/kernel/acpi/realmode/bioscall.S @@ -0,0 +1 @@ +#include "../../../boot/bioscall.S" diff --git a/arch/x86/kernel/acpi/realmode/regs.c b/arch/x86/kernel/acpi/realmode/regs.c new file mode 100644 index 000000000000..6206033ba202 --- /dev/null +++ b/arch/x86/kernel/acpi/realmode/regs.c @@ -0,0 +1 @@ +#include "../../../boot/regs.c" diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c index 7c243a2c5115..ca93638ba430 100644 --- a/arch/x86/kernel/acpi/sleep.c +++ b/arch/x86/kernel/acpi/sleep.c @@ -104,7 +104,7 @@ int acpi_save_state_mem(void) initial_gs = per_cpu_offset(smp_processor_id()); #endif initial_code = (unsigned long)wakeup_long64; - saved_magic = 0x123456789abcdef0; + saved_magic = 0x123456789abcdef0L; #endif /* CONFIG_64BIT */ return 0; diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index a97db99dad52..9372f0406ad4 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -55,7 +55,16 @@ struct iommu_cmd { static int dma_ops_unity_map(struct dma_ops_domain *dma_dom, struct unity_map_entry *e); static struct dma_ops_domain *find_protection_domain(u16 devid); +static u64* alloc_pte(struct protection_domain *dom, + unsigned long address, u64 + **pte_page, gfp_t gfp); +static void dma_ops_reserve_addresses(struct dma_ops_domain *dom, + unsigned long start_page, + unsigned int pages); +#ifndef BUS_NOTIFY_UNBOUND_DRIVER +#define BUS_NOTIFY_UNBOUND_DRIVER 0x0005 +#endif #ifdef CONFIG_AMD_IOMMU_STATS @@ -213,7 +222,7 @@ irqreturn_t amd_iommu_int_handler(int irq, void *data) { struct amd_iommu *iommu; - list_for_each_entry(iommu, &amd_iommu_list, list) + for_each_iommu(iommu) iommu_poll_events(iommu); return IRQ_HANDLED; @@ -425,6 +434,16 @@ static void iommu_flush_tlb(struct amd_iommu *iommu, u16 domid) iommu_queue_inv_iommu_pages(iommu, address, domid, 0, 1); } +/* Flush the whole IO/TLB for a given protection domain - including PDE */ +static void iommu_flush_tlb_pde(struct amd_iommu *iommu, u16 domid) +{ + u64 address = CMD_INV_IOMMU_ALL_PAGES_ADDRESS; + + INC_STATS_COUNTER(domain_flush_single); + + iommu_queue_inv_iommu_pages(iommu, address, domid, 1, 1); +} + /* * This function is used to flush the IO/TLB for a given protection domain * on every IOMMU in the system @@ -440,7 +459,7 @@ static void iommu_flush_domain(u16 domid) __iommu_build_inv_iommu_pages(&cmd, CMD_INV_IOMMU_ALL_PAGES_ADDRESS, domid, 1, 1); - list_for_each_entry(iommu, &amd_iommu_list, list) { + for_each_iommu(iommu) { spin_lock_irqsave(&iommu->lock, flags); __iommu_queue_command(iommu, &cmd); __iommu_completion_wait(iommu); @@ -449,6 +468,35 @@ static void iommu_flush_domain(u16 domid) } } +void amd_iommu_flush_all_domains(void) +{ + int i; + + for (i = 1; i < MAX_DOMAIN_ID; ++i) { + if (!test_bit(i, amd_iommu_pd_alloc_bitmap)) + continue; + iommu_flush_domain(i); + } +} + +void amd_iommu_flush_all_devices(void) +{ + struct amd_iommu *iommu; + int i; + + for (i = 0; i <= amd_iommu_last_bdf; ++i) { + if (amd_iommu_pd_table[i] == NULL) + continue; + + iommu = amd_iommu_rlookup_table[i]; + if (!iommu) + continue; + + iommu_queue_inv_dev_entry(iommu, i); + iommu_completion_wait(iommu); + } +} + /**************************************************************************** * * The functions below are used the create the page table mappings for @@ -468,7 +516,7 @@ static int iommu_map_page(struct protection_domain *dom, unsigned long phys_addr, int prot) { - u64 __pte, *pte, *page; + u64 __pte, *pte; bus_addr = PAGE_ALIGN(bus_addr); phys_addr = PAGE_ALIGN(phys_addr); @@ -477,27 +525,7 @@ static int iommu_map_page(struct protection_domain *dom, if (bus_addr > IOMMU_MAP_SIZE_L3 || !(prot & IOMMU_PROT_MASK)) return -EINVAL; - pte = &dom->pt_root[IOMMU_PTE_L2_INDEX(bus_addr)]; - - if (!IOMMU_PTE_PRESENT(*pte)) { - page = (u64 *)get_zeroed_page(GFP_KERNEL); - if (!page) - return -ENOMEM; - *pte = IOMMU_L2_PDE(virt_to_phys(page)); - } - - pte = IOMMU_PTE_PAGE(*pte); - pte = &pte[IOMMU_PTE_L1_INDEX(bus_addr)]; - - if (!IOMMU_PTE_PRESENT(*pte)) { - page = (u64 *)get_zeroed_page(GFP_KERNEL); - if (!page) - return -ENOMEM; - *pte = IOMMU_L1_PDE(virt_to_phys(page)); - } - - pte = IOMMU_PTE_PAGE(*pte); - pte = &pte[IOMMU_PTE_L0_INDEX(bus_addr)]; + pte = alloc_pte(dom, bus_addr, NULL, GFP_KERNEL); if (IOMMU_PTE_PRESENT(*pte)) return -EBUSY; @@ -595,7 +623,8 @@ static int dma_ops_unity_map(struct dma_ops_domain *dma_dom, * as allocated in the aperture */ if (addr < dma_dom->aperture_size) - __set_bit(addr >> PAGE_SHIFT, dma_dom->bitmap); + __set_bit(addr >> PAGE_SHIFT, + dma_dom->aperture[0]->bitmap); } return 0; @@ -632,42 +661,191 @@ static int init_unity_mappings_for_device(struct dma_ops_domain *dma_dom, ****************************************************************************/ /* - * The address allocator core function. + * The address allocator core functions. * * called with domain->lock held */ + +/* + * This function checks if there is a PTE for a given dma address. If + * there is one, it returns the pointer to it. + */ +static u64* fetch_pte(struct protection_domain *domain, + unsigned long address) +{ + u64 *pte; + + pte = &domain->pt_root[IOMMU_PTE_L2_INDEX(address)]; + + if (!IOMMU_PTE_PRESENT(*pte)) + return NULL; + + pte = IOMMU_PTE_PAGE(*pte); + pte = &pte[IOMMU_PTE_L1_INDEX(address)]; + + if (!IOMMU_PTE_PRESENT(*pte)) + return NULL; + + pte = IOMMU_PTE_PAGE(*pte); + pte = &pte[IOMMU_PTE_L0_INDEX(address)]; + + return pte; +} + +/* + * This function is used to add a new aperture range to an existing + * aperture in case of dma_ops domain allocation or address allocation + * failure. + */ +static int alloc_new_range(struct amd_iommu *iommu, + struct dma_ops_domain *dma_dom, + bool populate, gfp_t gfp) +{ + int index = dma_dom->aperture_size >> APERTURE_RANGE_SHIFT; + int i; + +#ifdef CONFIG_IOMMU_STRESS + populate = false; +#endif + + if (index >= APERTURE_MAX_RANGES) + return -ENOMEM; + + dma_dom->aperture[index] = kzalloc(sizeof(struct aperture_range), gfp); + if (!dma_dom->aperture[index]) + return -ENOMEM; + + dma_dom->aperture[index]->bitmap = (void *)get_zeroed_page(gfp); + if (!dma_dom->aperture[index]->bitmap) + goto out_free; + + dma_dom->aperture[index]->offset = dma_dom->aperture_size; + + if (populate) { + unsigned long address = dma_dom->aperture_size; + int i, num_ptes = APERTURE_RANGE_PAGES / 512; + u64 *pte, *pte_page; + + for (i = 0; i < num_ptes; ++i) { + pte = alloc_pte(&dma_dom->domain, address, + &pte_page, gfp); + if (!pte) + goto out_free; + + dma_dom->aperture[index]->pte_pages[i] = pte_page; + + address += APERTURE_RANGE_SIZE / 64; + } + } + + dma_dom->aperture_size += APERTURE_RANGE_SIZE; + + /* Intialize the exclusion range if necessary */ + if (iommu->exclusion_start && + iommu->exclusion_start >= dma_dom->aperture[index]->offset && + iommu->exclusion_start < dma_dom->aperture_size) { + unsigned long startpage = iommu->exclusion_start >> PAGE_SHIFT; + int pages = iommu_num_pages(iommu->exclusion_start, + iommu->exclusion_length, + PAGE_SIZE); + dma_ops_reserve_addresses(dma_dom, startpage, pages); + } + + /* + * Check for areas already mapped as present in the new aperture + * range and mark those pages as reserved in the allocator. Such + * mappings may already exist as a result of requested unity + * mappings for devices. + */ + for (i = dma_dom->aperture[index]->offset; + i < dma_dom->aperture_size; + i += PAGE_SIZE) { + u64 *pte = fetch_pte(&dma_dom->domain, i); + if (!pte || !IOMMU_PTE_PRESENT(*pte)) + continue; + + dma_ops_reserve_addresses(dma_dom, i << PAGE_SHIFT, 1); + } + + return 0; + +out_free: + free_page((unsigned long)dma_dom->aperture[index]->bitmap); + + kfree(dma_dom->aperture[index]); + dma_dom->aperture[index] = NULL; + + return -ENOMEM; +} + +static unsigned long dma_ops_area_alloc(struct device *dev, + struct dma_ops_domain *dom, + unsigned int pages, + unsigned long align_mask, + u64 dma_mask, + unsigned long start) +{ + unsigned long next_bit = dom->next_address % APERTURE_RANGE_SIZE; + int max_index = dom->aperture_size >> APERTURE_RANGE_SHIFT; + int i = start >> APERTURE_RANGE_SHIFT; + unsigned long boundary_size; + unsigned long address = -1; + unsigned long limit; + + next_bit >>= PAGE_SHIFT; + + boundary_size = ALIGN(dma_get_seg_boundary(dev) + 1, + PAGE_SIZE) >> PAGE_SHIFT; + + for (;i < max_index; ++i) { + unsigned long offset = dom->aperture[i]->offset >> PAGE_SHIFT; + + if (dom->aperture[i]->offset >= dma_mask) + break; + + limit = iommu_device_max_index(APERTURE_RANGE_PAGES, offset, + dma_mask >> PAGE_SHIFT); + + address = iommu_area_alloc(dom->aperture[i]->bitmap, + limit, next_bit, pages, 0, + boundary_size, align_mask); + if (address != -1) { + address = dom->aperture[i]->offset + + (address << PAGE_SHIFT); + dom->next_address = address + (pages << PAGE_SHIFT); + break; + } + + next_bit = 0; + } + + return address; +} + static unsigned long dma_ops_alloc_addresses(struct device *dev, struct dma_ops_domain *dom, unsigned int pages, unsigned long align_mask, u64 dma_mask) { - unsigned long limit; unsigned long address; - unsigned long boundary_size; - boundary_size = ALIGN(dma_get_seg_boundary(dev) + 1, - PAGE_SIZE) >> PAGE_SHIFT; - limit = iommu_device_max_index(dom->aperture_size >> PAGE_SHIFT, 0, - dma_mask >> PAGE_SHIFT); +#ifdef CONFIG_IOMMU_STRESS + dom->next_address = 0; + dom->need_flush = true; +#endif - if (dom->next_bit >= limit) { - dom->next_bit = 0; - dom->need_flush = true; - } + address = dma_ops_area_alloc(dev, dom, pages, align_mask, + dma_mask, dom->next_address); - address = iommu_area_alloc(dom->bitmap, limit, dom->next_bit, pages, - 0 , boundary_size, align_mask); if (address == -1) { - address = iommu_area_alloc(dom->bitmap, limit, 0, pages, - 0, boundary_size, align_mask); + dom->next_address = 0; + address = dma_ops_area_alloc(dev, dom, pages, align_mask, + dma_mask, 0); dom->need_flush = true; } - if (likely(address != -1)) { - dom->next_bit = address + pages; - address <<= PAGE_SHIFT; - } else + if (unlikely(address == -1)) address = bad_dma_address; WARN_ON((address + (PAGE_SIZE*pages)) > dom->aperture_size); @@ -684,11 +862,23 @@ static void dma_ops_free_addresses(struct dma_ops_domain *dom, unsigned long address, unsigned int pages) { - address >>= PAGE_SHIFT; - iommu_area_free(dom->bitmap, address, pages); + unsigned i = address >> APERTURE_RANGE_SHIFT; + struct aperture_range *range = dom->aperture[i]; - if (address >= dom->next_bit) + BUG_ON(i >= APERTURE_MAX_RANGES || range == NULL); + +#ifdef CONFIG_IOMMU_STRESS + if (i < 4) + return; +#endif + + if (address >= dom->next_address) dom->need_flush = true; + + address = (address % APERTURE_RANGE_SIZE) >> PAGE_SHIFT; + + iommu_area_free(range->bitmap, address, pages); + } /**************************************************************************** @@ -736,12 +926,16 @@ static void dma_ops_reserve_addresses(struct dma_ops_domain *dom, unsigned long start_page, unsigned int pages) { - unsigned int last_page = dom->aperture_size >> PAGE_SHIFT; + unsigned int i, last_page = dom->aperture_size >> PAGE_SHIFT; if (start_page + pages > last_page) pages = last_page - start_page; - iommu_area_reserve(dom->bitmap, start_page, pages); + for (i = start_page; i < start_page + pages; ++i) { + int index = i / APERTURE_RANGE_PAGES; + int page = i % APERTURE_RANGE_PAGES; + __set_bit(page, dom->aperture[index]->bitmap); + } } static void free_pagetable(struct protection_domain *domain) @@ -780,14 +974,19 @@ static void free_pagetable(struct protection_domain *domain) */ static void dma_ops_domain_free(struct dma_ops_domain *dom) { + int i; + if (!dom) return; free_pagetable(&dom->domain); - kfree(dom->pte_pages); - - kfree(dom->bitmap); + for (i = 0; i < APERTURE_MAX_RANGES; ++i) { + if (!dom->aperture[i]) + continue; + free_page((unsigned long)dom->aperture[i]->bitmap); + kfree(dom->aperture[i]); + } kfree(dom); } @@ -797,19 +996,9 @@ static void dma_ops_domain_free(struct dma_ops_domain *dom) * 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) +static struct dma_ops_domain *dma_ops_domain_alloc(struct amd_iommu *iommu) { struct dma_ops_domain *dma_dom; - unsigned i, num_pte_pages; - u64 *l2_pde; - u64 address; - - /* - * Currently the DMA aperture must be between 32 MB and 1GB in size - */ - if ((order < 25) || (order > 30)) - return NULL; dma_dom = kzalloc(sizeof(struct dma_ops_domain), GFP_KERNEL); if (!dma_dom) @@ -826,55 +1015,20 @@ static struct dma_ops_domain *dma_ops_domain_alloc(struct amd_iommu *iommu, dma_dom->domain.priv = dma_dom; if (!dma_dom->domain.pt_root) goto free_dma_dom; - dma_dom->aperture_size = (1ULL << order); - dma_dom->bitmap = kzalloc(dma_dom->aperture_size / (PAGE_SIZE * 8), - GFP_KERNEL); - if (!dma_dom->bitmap) - goto free_dma_dom; - /* - * mark the first page as allocated so we never return 0 as - * a valid dma-address. So we can use 0 as error value - */ - dma_dom->bitmap[0] = 1; - dma_dom->next_bit = 0; dma_dom->need_flush = false; dma_dom->target_dev = 0xffff; - /* 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; - int pages = iommu_num_pages(iommu->exclusion_start, - iommu->exclusion_length, - PAGE_SIZE); - dma_ops_reserve_addresses(dma_dom, startpage, pages); - } + if (alloc_new_range(iommu, dma_dom, true, GFP_KERNEL)) + goto free_dma_dom; /* - * 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. + * mark the first page as allocated so we never return 0 as + * a valid dma-address. So we can use 0 as error value */ - num_pte_pages = dma_dom->aperture_size / (PAGE_SIZE * 512); - dma_dom->pte_pages = kzalloc(num_pte_pages * sizeof(void *), - GFP_KERNEL); - if (!dma_dom->pte_pages) - goto free_dma_dom; + dma_dom->aperture[0]->bitmap[0] = 1; + dma_dom->next_address = 0; - l2_pde = (u64 *)get_zeroed_page(GFP_KERNEL); - if (l2_pde == NULL) - goto free_dma_dom; - - dma_dom->domain.pt_root[0] = IOMMU_L2_PDE(virt_to_phys(l2_pde)); - - for (i = 0; i < num_pte_pages; ++i) { - dma_dom->pte_pages[i] = (u64 *)get_zeroed_page(GFP_KERNEL); - if (!dma_dom->pte_pages[i]) - goto free_dma_dom; - address = virt_to_phys(dma_dom->pte_pages[i]); - l2_pde[i] = IOMMU_L1_PDE(address); - } return dma_dom; @@ -934,7 +1088,13 @@ static void attach_device(struct amd_iommu *iommu, amd_iommu_pd_table[devid] = domain; write_unlock_irqrestore(&amd_iommu_devtable_lock, flags); + /* + * We might boot into a crash-kernel here. The crashed kernel + * left the caches in the IOMMU dirty. So we have to flush + * here to evict all dirty stuff. + */ iommu_queue_inv_dev_entry(iommu, devid); + iommu_flush_tlb_pde(iommu, domain->id); } /* @@ -983,7 +1143,6 @@ static int device_change_notifier(struct notifier_block *nb, struct protection_domain *domain; struct dma_ops_domain *dma_domain; struct amd_iommu *iommu; - int order = amd_iommu_aperture_order; unsigned long flags; if (devid > amd_iommu_last_bdf) @@ -1002,17 +1161,7 @@ static int device_change_notifier(struct notifier_block *nb, "to a non-dma-ops domain\n", dev_name(dev)); switch (action) { - case BUS_NOTIFY_BOUND_DRIVER: - if (domain) - goto out; - dma_domain = find_protection_domain(devid); - if (!dma_domain) - dma_domain = iommu->default_dom; - attach_device(iommu, &dma_domain->domain, devid); - printk(KERN_INFO "AMD IOMMU: Using protection domain %d for " - "device %s\n", dma_domain->domain.id, dev_name(dev)); - break; - case BUS_NOTIFY_UNBIND_DRIVER: + case BUS_NOTIFY_UNBOUND_DRIVER: if (!domain) goto out; detach_device(domain, devid); @@ -1022,7 +1171,7 @@ static int device_change_notifier(struct notifier_block *nb, dma_domain = find_protection_domain(devid); if (dma_domain) goto out; - dma_domain = dma_ops_domain_alloc(iommu, order); + dma_domain = dma_ops_domain_alloc(iommu); if (!dma_domain) goto out; dma_domain->target_dev = devid; @@ -1133,8 +1282,8 @@ static int get_device_resources(struct device *dev, dma_dom = (*iommu)->default_dom; *domain = &dma_dom->domain; attach_device(*iommu, *domain, *bdf); - printk(KERN_INFO "AMD IOMMU: Using protection domain %d for " - "device %s\n", (*domain)->id, dev_name(dev)); + DUMP_printk("Using protection domain %d for device %s\n", + (*domain)->id, dev_name(dev)); } if (domain_for_device(_bdf) == NULL) @@ -1143,6 +1292,66 @@ static int get_device_resources(struct device *dev, return 1; } +/* + * If the pte_page is not yet allocated this function is called + */ +static u64* alloc_pte(struct protection_domain *dom, + unsigned long address, u64 **pte_page, gfp_t gfp) +{ + u64 *pte, *page; + + pte = &dom->pt_root[IOMMU_PTE_L2_INDEX(address)]; + + if (!IOMMU_PTE_PRESENT(*pte)) { + page = (u64 *)get_zeroed_page(gfp); + if (!page) + return NULL; + *pte = IOMMU_L2_PDE(virt_to_phys(page)); + } + + pte = IOMMU_PTE_PAGE(*pte); + pte = &pte[IOMMU_PTE_L1_INDEX(address)]; + + if (!IOMMU_PTE_PRESENT(*pte)) { + page = (u64 *)get_zeroed_page(gfp); + if (!page) + return NULL; + *pte = IOMMU_L1_PDE(virt_to_phys(page)); + } + + pte = IOMMU_PTE_PAGE(*pte); + + if (pte_page) + *pte_page = pte; + + pte = &pte[IOMMU_PTE_L0_INDEX(address)]; + + return pte; +} + +/* + * This function fetches the PTE for a given address in the aperture + */ +static u64* dma_ops_get_pte(struct dma_ops_domain *dom, + unsigned long address) +{ + struct aperture_range *aperture; + u64 *pte, *pte_page; + + aperture = dom->aperture[APERTURE_RANGE_INDEX(address)]; + if (!aperture) + return NULL; + + pte = aperture->pte_pages[APERTURE_PAGE_INDEX(address)]; + if (!pte) { + pte = alloc_pte(&dom->domain, address, &pte_page, GFP_ATOMIC); + aperture->pte_pages[APERTURE_PAGE_INDEX(address)] = pte_page; + } else + pte += IOMMU_PTE_L0_INDEX(address); + + return pte; +} + /* * 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. @@ -1159,8 +1368,9 @@ static dma_addr_t dma_ops_domain_map(struct amd_iommu *iommu, paddr &= PAGE_MASK; - pte = dom->pte_pages[IOMMU_PTE_L1_INDEX(address)]; - pte += IOMMU_PTE_L0_INDEX(address); + pte = dma_ops_get_pte(dom, address); + if (!pte) + return bad_dma_address; __pte = paddr | IOMMU_PTE_P | IOMMU_PTE_FC; @@ -1185,14 +1395,20 @@ static void dma_ops_domain_unmap(struct amd_iommu *iommu, struct dma_ops_domain *dom, unsigned long address) { + struct aperture_range *aperture; u64 *pte; if (address >= dom->aperture_size) return; - WARN_ON(address & ~PAGE_MASK || address >= dom->aperture_size); + aperture = dom->aperture[APERTURE_RANGE_INDEX(address)]; + if (!aperture) + return; + + pte = aperture->pte_pages[APERTURE_PAGE_INDEX(address)]; + if (!pte) + return; - pte = dom->pte_pages[IOMMU_PTE_L1_INDEX(address)]; pte += IOMMU_PTE_L0_INDEX(address); WARN_ON(!*pte); @@ -1216,7 +1432,7 @@ static dma_addr_t __map_single(struct device *dev, u64 dma_mask) { dma_addr_t offset = paddr & ~PAGE_MASK; - dma_addr_t address, start; + dma_addr_t address, start, ret; unsigned int pages; unsigned long align_mask = 0; int i; @@ -1232,14 +1448,33 @@ static dma_addr_t __map_single(struct device *dev, if (align) align_mask = (1UL << get_order(size)) - 1; +retry: address = dma_ops_alloc_addresses(dev, dma_dom, pages, align_mask, dma_mask); - if (unlikely(address == bad_dma_address)) - goto out; + if (unlikely(address == bad_dma_address)) { + /* + * setting next_address here will let the address + * allocator only scan the new allocated range in the + * first run. This is a small optimization. + */ + dma_dom->next_address = dma_dom->aperture_size; + + if (alloc_new_range(iommu, dma_dom, false, GFP_ATOMIC)) + goto out; + + /* + * aperture was sucessfully enlarged by 128 MB, try + * allocation again + */ + goto retry; + } start = address; for (i = 0; i < pages; ++i) { - dma_ops_domain_map(iommu, dma_dom, start, paddr, dir); + ret = dma_ops_domain_map(iommu, dma_dom, start, paddr, dir); + if (ret == bad_dma_address) + goto out_unmap; + paddr += PAGE_SIZE; start += PAGE_SIZE; } @@ -1255,6 +1490,17 @@ static dma_addr_t __map_single(struct device *dev, out: return address; + +out_unmap: + + for (--i; i >= 0; --i) { + start -= PAGE_SIZE; + dma_ops_domain_unmap(iommu, dma_dom, start); + } + + dma_ops_free_addresses(dma_dom, address, pages); + + return bad_dma_address; } /* @@ -1537,8 +1783,10 @@ static void *alloc_coherent(struct device *dev, size_t size, *dma_addr = __map_single(dev, iommu, domain->priv, paddr, size, DMA_BIDIRECTIONAL, true, dma_mask); - if (*dma_addr == bad_dma_address) + if (*dma_addr == bad_dma_address) { + spin_unlock_irqrestore(&domain->lock, flags); goto out_free; + } iommu_completion_wait(iommu); @@ -1625,7 +1873,6 @@ static void prealloc_protection_domains(void) struct pci_dev *dev = NULL; struct dma_ops_domain *dma_dom; struct amd_iommu *iommu; - int order = amd_iommu_aperture_order; u16 devid; while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { @@ -1638,7 +1885,7 @@ static void prealloc_protection_domains(void) iommu = amd_iommu_rlookup_table[devid]; if (!iommu) continue; - dma_dom = dma_ops_domain_alloc(iommu, order); + dma_dom = dma_ops_domain_alloc(iommu); if (!dma_dom) continue; init_unity_mappings_for_device(dma_dom, devid); @@ -1664,7 +1911,6 @@ static struct dma_map_ops amd_iommu_dma_ops = { int __init amd_iommu_init_dma_ops(void) { struct amd_iommu *iommu; - int order = amd_iommu_aperture_order; int ret; /* @@ -1672,8 +1918,8 @@ int __init amd_iommu_init_dma_ops(void) * 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); + for_each_iommu(iommu) { + iommu->default_dom = dma_ops_domain_alloc(iommu); if (iommu->default_dom == NULL) return -ENOMEM; iommu->default_dom->domain.flags |= PD_DEFAULT_MASK; @@ -1710,7 +1956,7 @@ int __init amd_iommu_init_dma_ops(void) free_domains: - list_for_each_entry(iommu, &amd_iommu_list, list) { + for_each_iommu(iommu) { if (iommu->default_dom) dma_ops_domain_free(iommu->default_dom); } @@ -1842,7 +2088,7 @@ static int amd_iommu_attach_device(struct iommu_domain *dom, old_domain = domain_for_device(devid); if (old_domain) - return -EBUSY; + detach_device(old_domain, devid); attach_device(iommu, domain, devid); diff --git a/arch/x86/kernel/amd_iommu_init.c b/arch/x86/kernel/amd_iommu_init.c index 8c0be0902dac..10b2accd12ea 100644 --- a/arch/x86/kernel/amd_iommu_init.c +++ b/arch/x86/kernel/amd_iommu_init.c @@ -115,15 +115,21 @@ struct ivmd_header { u64 range_length; } __attribute__((packed)); +bool amd_iommu_dump; + static int __initdata amd_iommu_detected; 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 */ +#ifdef CONFIG_IOMMU_STRESS +bool amd_iommu_isolate = false; +#else bool amd_iommu_isolate = true; /* if true, device isolation is enabled */ +#endif + bool amd_iommu_unmap_flush; /* if true, flush on every unmap */ LIST_HEAD(amd_iommu_list); /* list of all AMD IOMMUs in the @@ -175,7 +181,7 @@ static inline void update_last_devid(u16 devid) static inline unsigned long tbl_size(int entry_size) { unsigned shift = PAGE_SHIFT + - get_order(amd_iommu_last_bdf * entry_size); + get_order(((int)amd_iommu_last_bdf + 1) * entry_size); return 1UL << shift; } @@ -193,7 +199,7 @@ static inline unsigned long tbl_size(int entry_size) * 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) +static void iommu_set_exclusion_range(struct amd_iommu *iommu) { u64 start = iommu->exclusion_start & PAGE_MASK; u64 limit = (start + iommu->exclusion_length) & PAGE_MASK; @@ -225,7 +231,7 @@ static void __init iommu_set_device_table(struct amd_iommu *iommu) } /* Generic functions to enable/disable certain features of the IOMMU. */ -static void __init iommu_feature_enable(struct amd_iommu *iommu, u8 bit) +static void iommu_feature_enable(struct amd_iommu *iommu, u8 bit) { u32 ctrl; @@ -244,7 +250,7 @@ static void __init iommu_feature_disable(struct amd_iommu *iommu, u8 bit) } /* Function to enable the hardware */ -static void __init iommu_enable(struct amd_iommu *iommu) +static void iommu_enable(struct amd_iommu *iommu) { printk(KERN_INFO "AMD IOMMU: Enabling IOMMU at %s cap 0x%hx\n", dev_name(&iommu->dev->dev), iommu->cap_ptr); @@ -252,11 +258,17 @@ static void __init iommu_enable(struct amd_iommu *iommu) iommu_feature_enable(iommu, CONTROL_IOMMU_EN); } -/* Function to enable IOMMU event logging and event interrupts */ -static void __init iommu_enable_event_logging(struct amd_iommu *iommu) +static void iommu_disable(struct amd_iommu *iommu) { - iommu_feature_enable(iommu, CONTROL_EVT_LOG_EN); - iommu_feature_enable(iommu, CONTROL_EVT_INT_EN); + /* Disable command buffer */ + iommu_feature_disable(iommu, CONTROL_CMDBUF_EN); + + /* Disable event logging and event interrupts */ + iommu_feature_disable(iommu, CONTROL_EVT_INT_EN); + iommu_feature_disable(iommu, CONTROL_EVT_LOG_EN); + + /* Disable IOMMU hardware itself */ + iommu_feature_disable(iommu, CONTROL_IOMMU_EN); } /* @@ -413,25 +425,36 @@ static u8 * __init alloc_command_buffer(struct amd_iommu *iommu) { u8 *cmd_buf = (u8 *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, get_order(CMD_BUFFER_SIZE)); - u64 entry; if (cmd_buf == NULL) return NULL; iommu->cmd_buf_size = CMD_BUFFER_SIZE; - entry = (u64)virt_to_phys(cmd_buf); + return cmd_buf; +} + +/* + * This function writes the command buffer address to the hardware and + * enables it. + */ +static void iommu_enable_command_buffer(struct amd_iommu *iommu) +{ + u64 entry; + + BUG_ON(iommu->cmd_buf == NULL); + + entry = (u64)virt_to_phys(iommu->cmd_buf); entry |= MMIO_CMD_SIZE_512; + memcpy_toio(iommu->mmio_base + MMIO_CMD_BUF_OFFSET, - &entry, sizeof(entry)); + &entry, sizeof(entry)); /* set head and tail to zero manually */ writel(0x00, iommu->mmio_base + MMIO_CMD_HEAD_OFFSET); writel(0x00, iommu->mmio_base + MMIO_CMD_TAIL_OFFSET); iommu_feature_enable(iommu, CONTROL_CMDBUF_EN); - - return cmd_buf; } static void __init free_command_buffer(struct amd_iommu *iommu) @@ -443,20 +466,31 @@ static void __init free_command_buffer(struct amd_iommu *iommu) /* allocates the memory where the IOMMU will log its events to */ static u8 * __init alloc_event_buffer(struct amd_iommu *iommu) { - u64 entry; iommu->evt_buf = (u8 *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, get_order(EVT_BUFFER_SIZE)); if (iommu->evt_buf == NULL) return NULL; + return iommu->evt_buf; +} + +static void iommu_enable_event_buffer(struct amd_iommu *iommu) +{ + u64 entry; + + BUG_ON(iommu->evt_buf == NULL); + entry = (u64)virt_to_phys(iommu->evt_buf) | EVT_LEN_MASK; + memcpy_toio(iommu->mmio_base + MMIO_EVT_BUF_OFFSET, &entry, sizeof(entry)); - iommu->evt_buf_size = EVT_BUFFER_SIZE; + /* set head and tail to zero manually */ + writel(0x00, iommu->mmio_base + MMIO_EVT_HEAD_OFFSET); + writel(0x00, iommu->mmio_base + MMIO_EVT_TAIL_OFFSET); - return iommu->evt_buf; + iommu_feature_enable(iommu, CONTROL_EVT_LOG_EN); } static void __init free_event_buffer(struct amd_iommu *iommu) @@ -596,32 +630,83 @@ static void __init init_iommu_from_acpi(struct amd_iommu *iommu, p += sizeof(struct ivhd_header); end += h->length; + while (p < end) { e = (struct ivhd_entry *)p; switch (e->type) { case IVHD_DEV_ALL: + + DUMP_printk(" DEV_ALL\t\t\t first devid: %02x:%02x.%x" + " last device %02x:%02x.%x flags: %02x\n", + PCI_BUS(iommu->first_device), + PCI_SLOT(iommu->first_device), + PCI_FUNC(iommu->first_device), + PCI_BUS(iommu->last_device), + PCI_SLOT(iommu->last_device), + PCI_FUNC(iommu->last_device), + e->flags); + for (dev_i = iommu->first_device; dev_i <= iommu->last_device; ++dev_i) set_dev_entry_from_acpi(iommu, dev_i, e->flags, 0); break; case IVHD_DEV_SELECT: + + DUMP_printk(" DEV_SELECT\t\t\t devid: %02x:%02x.%x " + "flags: %02x\n", + PCI_BUS(e->devid), + PCI_SLOT(e->devid), + PCI_FUNC(e->devid), + e->flags); + devid = e->devid; set_dev_entry_from_acpi(iommu, devid, e->flags, 0); break; case IVHD_DEV_SELECT_RANGE_START: + + DUMP_printk(" DEV_SELECT_RANGE_START\t " + "devid: %02x:%02x.%x flags: %02x\n", + PCI_BUS(e->devid), + PCI_SLOT(e->devid), + PCI_FUNC(e->devid), + e->flags); + devid_start = e->devid; flags = e->flags; ext_flags = 0; alias = false; break; case IVHD_DEV_ALIAS: + + DUMP_printk(" DEV_ALIAS\t\t\t devid: %02x:%02x.%x " + "flags: %02x devid_to: %02x:%02x.%x\n", + PCI_BUS(e->devid), + PCI_SLOT(e->devid), + PCI_FUNC(e->devid), + e->flags, + PCI_BUS(e->ext >> 8), + PCI_SLOT(e->ext >> 8), + PCI_FUNC(e->ext >> 8)); + devid = e->devid; devid_to = e->ext >> 8; - set_dev_entry_from_acpi(iommu, devid, e->flags, 0); + set_dev_entry_from_acpi(iommu, devid_to, e->flags, 0); amd_iommu_alias_table[devid] = devid_to; break; case IVHD_DEV_ALIAS_RANGE: + + DUMP_printk(" DEV_ALIAS_RANGE\t\t " + "devid: %02x:%02x.%x flags: %02x " + "devid_to: %02x:%02x.%x\n", + PCI_BUS(e->devid), + PCI_SLOT(e->devid), + PCI_FUNC(e->devid), + e->flags, + PCI_BUS(e->ext >> 8), + PCI_SLOT(e->ext >> 8), + PCI_FUNC(e->ext >> 8)); + devid_start = e->devid; flags = e->flags; devid_to = e->ext >> 8; @@ -629,17 +714,39 @@ static void __init init_iommu_from_acpi(struct amd_iommu *iommu, alias = true; break; case IVHD_DEV_EXT_SELECT: + + DUMP_printk(" DEV_EXT_SELECT\t\t devid: %02x:%02x.%x " + "flags: %02x ext: %08x\n", + PCI_BUS(e->devid), + PCI_SLOT(e->devid), + PCI_FUNC(e->devid), + e->flags, e->ext); + devid = e->devid; set_dev_entry_from_acpi(iommu, devid, e->flags, e->ext); break; case IVHD_DEV_EXT_SELECT_RANGE: + + DUMP_printk(" DEV_EXT_SELECT_RANGE\t devid: " + "%02x:%02x.%x flags: %02x ext: %08x\n", + PCI_BUS(e->devid), + PCI_SLOT(e->devid), + PCI_FUNC(e->devid), + e->flags, e->ext); + devid_start = e->devid; flags = e->flags; ext_flags = e->ext; alias = false; break; case IVHD_DEV_RANGE_END: + + DUMP_printk(" DEV_RANGE_END\t\t devid: %02x:%02x.%x\n", + PCI_BUS(e->devid), + PCI_SLOT(e->devid), + PCI_FUNC(e->devid)); + devid = e->devid; for (dev_i = devid_start; dev_i <= devid; ++dev_i) { if (alias) @@ -679,7 +786,7 @@ static void __init free_iommu_all(void) { struct amd_iommu *iommu, *next; - list_for_each_entry_safe(iommu, next, &amd_iommu_list, list) { + for_each_iommu_safe(iommu, next) { list_del(&iommu->list); free_iommu_one(iommu); kfree(iommu); @@ -710,7 +817,6 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h) if (!iommu->mmio_base) return -ENOMEM; - iommu_set_device_table(iommu); iommu->cmd_buf = alloc_command_buffer(iommu); if (!iommu->cmd_buf) return -ENOMEM; @@ -746,6 +852,15 @@ static int __init init_iommu_all(struct acpi_table_header *table) h = (struct ivhd_header *)p; switch (*p) { case ACPI_IVHD_TYPE: + + DUMP_printk("IOMMU: device: %02x:%02x.%01x cap: %04x " + "seg: %d flags: %01x info %04x\n", + PCI_BUS(h->devid), PCI_SLOT(h->devid), + PCI_FUNC(h->devid), h->cap_ptr, + h->pci_seg, h->flags, h->info); + DUMP_printk(" mmio-addr: %016llx\n", + h->mmio_phys); + iommu = kzalloc(sizeof(struct amd_iommu), GFP_KERNEL); if (iommu == NULL) return -ENOMEM; @@ -773,56 +888,9 @@ static int __init init_iommu_all(struct acpi_table_header *table) * ****************************************************************************/ -static int __init iommu_setup_msix(struct amd_iommu *iommu) -{ - struct amd_iommu *curr; - struct msix_entry entries[32]; /* only 32 supported by AMD IOMMU */ - int nvec = 0, i; - - list_for_each_entry(curr, &amd_iommu_list, list) { - if (curr->dev == iommu->dev) { - entries[nvec].entry = curr->evt_msi_num; - entries[nvec].vector = 0; - curr->int_enabled = true; - nvec++; - } - } - - if (pci_enable_msix(iommu->dev, entries, nvec)) { - pci_disable_msix(iommu->dev); - return 1; - } - - for (i = 0; i < nvec; ++i) { - int r = request_irq(entries->vector, amd_iommu_int_handler, - IRQF_SAMPLE_RANDOM, - "AMD IOMMU", - NULL); - if (r) - goto out_free; - } - - return 0; - -out_free: - for (i -= 1; i >= 0; --i) - free_irq(entries->vector, NULL); - - pci_disable_msix(iommu->dev); - - return 1; -} - static int __init iommu_setup_msi(struct amd_iommu *iommu) { int r; - struct amd_iommu *curr; - - list_for_each_entry(curr, &amd_iommu_list, list) { - if (curr->dev == iommu->dev) - curr->int_enabled = true; - } - if (pci_enable_msi(iommu->dev)) return 1; @@ -837,17 +905,18 @@ static int __init iommu_setup_msi(struct amd_iommu *iommu) return 1; } + iommu->int_enabled = true; + iommu_feature_enable(iommu, CONTROL_EVT_INT_EN); + return 0; } -static int __init iommu_init_msi(struct amd_iommu *iommu) +static int iommu_init_msi(struct amd_iommu *iommu) { if (iommu->int_enabled) return 0; - if (pci_find_capability(iommu->dev, PCI_CAP_ID_MSIX)) - return iommu_setup_msix(iommu); - else if (pci_find_capability(iommu->dev, PCI_CAP_ID_MSI)) + if (pci_find_capability(iommu->dev, PCI_CAP_ID_MSI)) return iommu_setup_msi(iommu); return 1; @@ -899,6 +968,7 @@ static int __init init_exclusion_range(struct ivmd_header *m) static int __init init_unity_map_range(struct ivmd_header *m) { struct unity_map_entry *e = 0; + char *s; e = kzalloc(sizeof(*e), GFP_KERNEL); if (e == NULL) @@ -906,14 +976,19 @@ static int __init init_unity_map_range(struct ivmd_header *m) switch (m->type) { default: + kfree(e); + return 0; case ACPI_IVMD_TYPE: + s = "IVMD_TYPEi\t\t\t"; e->devid_start = e->devid_end = m->devid; break; case ACPI_IVMD_TYPE_ALL: + s = "IVMD_TYPE_ALL\t\t"; e->devid_start = 0; e->devid_end = amd_iommu_last_bdf; break; case ACPI_IVMD_TYPE_RANGE: + s = "IVMD_TYPE_RANGE\t\t"; e->devid_start = m->devid; e->devid_end = m->aux; break; @@ -922,6 +997,13 @@ static int __init init_unity_map_range(struct ivmd_header *m) e->address_end = e->address_start + PAGE_ALIGN(m->range_length); e->prot = m->flags >> 1; + DUMP_printk("%s devid_start: %02x:%02x.%x devid_end: %02x:%02x.%x" + " range_start: %016llx range_end: %016llx flags: %x\n", s, + PCI_BUS(e->devid_start), PCI_SLOT(e->devid_start), + PCI_FUNC(e->devid_start), PCI_BUS(e->devid_end), + PCI_SLOT(e->devid_end), PCI_FUNC(e->devid_end), + e->address_start, e->address_end, m->flags); + list_add_tail(&e->list, &amd_iommu_unity_map); return 0; @@ -967,18 +1049,29 @@ static void init_device_table(void) * This function finally enables all IOMMUs found in the system after * they have been initialized */ -static void __init enable_iommus(void) +static void enable_iommus(void) { struct amd_iommu *iommu; - list_for_each_entry(iommu, &amd_iommu_list, list) { + for_each_iommu(iommu) { + iommu_disable(iommu); + iommu_set_device_table(iommu); + iommu_enable_command_buffer(iommu); + iommu_enable_event_buffer(iommu); iommu_set_exclusion_range(iommu); iommu_init_msi(iommu); - iommu_enable_event_logging(iommu); iommu_enable(iommu); } } +static void disable_iommus(void) +{ + struct amd_iommu *iommu; + + for_each_iommu(iommu) + iommu_disable(iommu); +} + /* * Suspend/Resume support * disable suspend until real resume implemented @@ -986,12 +1079,25 @@ static void __init enable_iommus(void) static int amd_iommu_resume(struct sys_device *dev) { + /* re-load the hardware */ + enable_iommus(); + + /* + * we have to flush after the IOMMUs are enabled because a + * disabled IOMMU will never execute the commands we send + */ + amd_iommu_flush_all_devices(); + amd_iommu_flush_all_domains(); + return 0; } static int amd_iommu_suspend(struct sys_device *dev, pm_message_t state) { - return -EINVAL; + /* disable IOMMUs to go out of the way for BIOS */ + disable_iommus(); + + return 0; } static struct sysdev_class amd_iommu_sysdev_class = { @@ -1137,9 +1243,6 @@ int __init amd_iommu_init(void) enable_iommus(); - printk(KERN_INFO "AMD IOMMU: aperture size is %d MB\n", - (1 << (amd_iommu_aperture_order-20))); - printk(KERN_INFO "AMD IOMMU: device isolation "); if (amd_iommu_isolate) printk("enabled\n"); @@ -1177,6 +1280,11 @@ free: goto out; } +void amd_iommu_shutdown(void) +{ + disable_iommus(); +} + /**************************************************************************** * * Early detect code. This code runs at IOMMU detection time in the DMA @@ -1211,6 +1319,13 @@ void __init amd_iommu_detect(void) * ****************************************************************************/ +static int __init parse_amd_iommu_dump(char *str) +{ + amd_iommu_dump = true; + + return 1; +} + static int __init parse_amd_iommu_options(char *str) { for (; *str; ++str) { @@ -1225,15 +1340,5 @@ static int __init parse_amd_iommu_options(char *str) return 1; } -static int __init parse_amd_iommu_size_options(char *str) -{ - unsigned order = PAGE_SHIFT + get_order(memparse(str, &str)); - - if ((order > 24) && (order < 31)) - amd_iommu_aperture_order = order; - - return 1; -} - +__setup("amd_iommu_dump", parse_amd_iommu_dump); __setup("amd_iommu=", parse_amd_iommu_options); -__setup("amd_iommu_size=", parse_amd_iommu_size_options); diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index f2870920f246..8c7c042ecad1 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -14,6 +14,7 @@ * Mikael Pettersson : PM converted to driver model. */ +#include #include #include #include @@ -34,6 +35,7 @@ #include #include +#include #include #include #include @@ -98,6 +100,29 @@ early_param("lapic", parse_lapic); /* Local APIC was disabled by the BIOS and enabled by the kernel */ static int enabled_via_apicbase; +/* + * Handle interrupt mode configuration register (IMCR). + * This register controls whether the interrupt signals + * that reach the BSP come from the master PIC or from the + * local APIC. Before entering Symmetric I/O Mode, either + * the BIOS or the operating system must switch out of + * PIC Mode by changing the IMCR. + */ +static inline void imcr_pic_to_apic(void) +{ + /* select IMCR register */ + outb(0x70, 0x22); + /* NMI and 8259 INTR go through APIC */ + outb(0x01, 0x23); +} + +static inline void imcr_apic_to_pic(void) +{ + /* select IMCR register */ + outb(0x70, 0x22); + /* NMI and 8259 INTR go directly to BSP */ + outb(0x00, 0x23); +} #endif #ifdef CONFIG_X86_64 @@ -111,13 +136,19 @@ static __init int setup_apicpmtimer(char *s) __setup("apicpmtimer", setup_apicpmtimer); #endif +int x2apic_mode; #ifdef CONFIG_X86_X2APIC -int x2apic; /* x2apic enabled before OS handover */ static int x2apic_preenabled; static int disable_x2apic; static __init int setup_nox2apic(char *str) { + if (x2apic_enabled()) { + pr_warning("Bios already enabled x2apic, " + "can't enforce nox2apic"); + return 0; + } + disable_x2apic = 1; setup_clear_cpu_cap(X86_FEATURE_X2APIC); return 0; @@ -209,6 +240,31 @@ static int modern_apic(void) return lapic_get_version() >= 0x14; } +/* + * bare function to substitute write operation + * and it's _that_ fast :) + */ +static void native_apic_write_dummy(u32 reg, u32 v) +{ + WARN_ON_ONCE((cpu_has_apic || !disable_apic)); +} + +static u32 native_apic_read_dummy(u32 reg) +{ + WARN_ON_ONCE((cpu_has_apic && !disable_apic)); + return 0; +} + +/* + * right after this call apic->write/read doesn't do anything + * note that there is no restore operation it works one way + */ +void apic_disable(void) +{ + apic->read = native_apic_read_dummy; + apic->write = native_apic_write_dummy; +} + void native_apic_wait_icr_idle(void) { while (apic_read(APIC_ICR) & APIC_ICR_BUSY) @@ -348,7 +404,7 @@ static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen) static void setup_APIC_eilvt(u8 lvt_off, u8 vector, u8 msg_type, u8 mask) { - unsigned long reg = (lvt_off << 4) + APIC_EILVT0; + unsigned long reg = (lvt_off << 4) + APIC_EILVTn(0); unsigned int v = (mask << 16) | (msg_type << 8) | vector; apic_write(reg, v); @@ -815,7 +871,7 @@ void clear_local_APIC(void) u32 v; /* APIC hasn't been mapped yet */ - if (!x2apic && !apic_phys) + if (!x2apic_mode && !apic_phys) return; maxlvt = lapic_get_maxlvt(); @@ -843,7 +899,7 @@ void clear_local_APIC(void) } /* lets not touch this if we didn't frob it */ -#if defined(CONFIG_X86_MCE_P4THERMAL) || defined(CONFIG_X86_MCE_INTEL) +#ifdef CONFIG_X86_THERMAL_VECTOR if (maxlvt >= 5) { v = apic_read(APIC_LVTTHMR); apic_write(APIC_LVTTHMR, v | APIC_LVT_MASKED); @@ -1133,6 +1189,7 @@ void __cpuinit setup_local_APIC(void) apic_write(APIC_ESR, 0); } #endif + perf_counters_lapic_init(); preempt_disable(); @@ -1287,7 +1344,7 @@ void check_x2apic(void) { if (x2apic_enabled()) { pr_info("x2apic enabled by BIOS, switching to x2apic ops\n"); - x2apic_preenabled = x2apic = 1; + x2apic_preenabled = x2apic_mode = 1; } } @@ -1295,7 +1352,7 @@ void enable_x2apic(void) { int msr, msr2; - if (!x2apic) + if (!x2apic_mode) return; rdmsr(MSR_IA32_APICBASE, msr, msr2); @@ -1304,6 +1361,7 @@ void enable_x2apic(void) wrmsr(MSR_IA32_APICBASE, msr | X2APIC_ENABLE, 0); } } +#endif /* CONFIG_X86_X2APIC */ void __init enable_IR_x2apic(void) { @@ -1312,32 +1370,21 @@ void __init enable_IR_x2apic(void) unsigned long flags; struct IO_APIC_route_entry **ioapic_entries = NULL; - if (!cpu_has_x2apic) - return; - - if (!x2apic_preenabled && disable_x2apic) { - pr_info("Skipped enabling x2apic and Interrupt-remapping " - "because of nox2apic\n"); - return; - } - - if (x2apic_preenabled && disable_x2apic) - panic("Bios already enabled x2apic, can't enforce nox2apic"); - - if (!x2apic_preenabled && skip_ioapic_setup) { - pr_info("Skipped enabling x2apic and Interrupt-remapping " - "because of skipping io-apic setup\n"); - return; - } - ret = dmar_table_init(); if (ret) { - pr_info("dmar_table_init() failed with %d:\n", ret); + pr_debug("dmar_table_init() failed with %d:\n", ret); + goto ir_failed; + } - if (x2apic_preenabled) - panic("x2apic enabled by bios. But IR enabling failed"); - else - pr_info("Not enabling x2apic,Intr-remapping\n"); + if (!intr_remapping_supported()) { + pr_debug("intr-remapping not supported\n"); + goto ir_failed; + } + + + if (!x2apic_preenabled && skip_ioapic_setup) { + pr_info("Skipped enabling intr-remap because of skipping " + "io-apic setup\n"); return; } @@ -1357,19 +1404,16 @@ void __init enable_IR_x2apic(void) mask_IO_APIC_setup(ioapic_entries); mask_8259A(); - ret = enable_intr_remapping(EIM_32BIT_APIC_ID); - - if (ret && x2apic_preenabled) { - local_irq_restore(flags); - panic("x2apic enabled by bios. But IR enabling failed"); - } - + ret = enable_intr_remapping(x2apic_supported()); if (ret) goto end_restore; - if (!x2apic) { - x2apic = 1; + pr_info("Enabled Interrupt-remapping\n"); + + if (x2apic_supported() && !x2apic_mode) { + x2apic_mode = 1; enable_x2apic(); + pr_info("Enabled x2apic\n"); } end_restore: @@ -1378,37 +1422,34 @@ end_restore: * IR enabling failed */ restore_IO_APIC_setup(ioapic_entries); - else - reinit_intr_remapped_IO_APIC(x2apic_preenabled, ioapic_entries); unmask_8259A(); local_irq_restore(flags); end: - if (!ret) { - if (!x2apic_preenabled) - pr_info("Enabled x2apic and interrupt-remapping\n"); - else - pr_info("Enabled Interrupt-remapping\n"); - } else - pr_err("Failed to enable Interrupt-remapping and x2apic\n"); if (ioapic_entries) free_ioapic_entries(ioapic_entries); + + if (!ret) + return; + +ir_failed: + if (x2apic_preenabled) + panic("x2apic enabled by bios. But IR enabling failed"); + else if (cpu_has_x2apic) + pr_info("Not enabling x2apic,Intr-remapping\n"); #else if (!cpu_has_x2apic) return; if (x2apic_preenabled) panic("x2apic enabled prior OS handover," - " enable CONFIG_INTR_REMAP"); - - pr_info("Enable CONFIG_INTR_REMAP for enabling intr-remapping " - " and x2apic\n"); + " enable CONFIG_X86_X2APIC, CONFIG_INTR_REMAP"); #endif return; } -#endif /* CONFIG_X86_X2APIC */ + #ifdef CONFIG_X86_64 /* @@ -1425,7 +1466,6 @@ static int __init detect_init_APIC(void) } mp_lapic_addr = APIC_DEFAULT_PHYS_BASE; - boot_cpu_physical_apicid = 0; return 0; } #else @@ -1539,32 +1579,49 @@ void __init early_init_lapic_mapping(void) */ void __init init_apic_mappings(void) { - if (x2apic) { + unsigned int new_apicid; + + if (x2apic_mode) { boot_cpu_physical_apicid = read_apic_id(); return; } - /* - * If no local APIC can be found then set up a fake all - * zeroes page to simulate the local APIC and another - * one for the IO-APIC. - */ + /* If no local APIC can be found return early */ if (!smp_found_config && detect_init_APIC()) { - apic_phys = (unsigned long) alloc_bootmem_pages(PAGE_SIZE); - apic_phys = __pa(apic_phys); - } else + /* lets NOP'ify apic operations */ + pr_info("APIC: disable apic facility\n"); + apic_disable(); + } else { apic_phys = mp_lapic_addr; - set_fixmap_nocache(FIX_APIC_BASE, apic_phys); - apic_printk(APIC_VERBOSE, "mapped APIC to %08lx (%08lx)\n", - APIC_BASE, apic_phys); + /* + * acpi lapic path already maps that address in + * acpi_register_lapic_address() + */ + if (!acpi_lapic) + set_fixmap_nocache(FIX_APIC_BASE, apic_phys); + + apic_printk(APIC_VERBOSE, "mapped APIC to %08lx (%08lx)\n", + APIC_BASE, apic_phys); + } /* * Fetch the APIC ID of the BSP in case we have a * default configuration (or the MP table is broken). */ - if (boot_cpu_physical_apicid == -1U) - boot_cpu_physical_apicid = read_apic_id(); + new_apicid = read_apic_id(); + if (boot_cpu_physical_apicid != new_apicid) { + boot_cpu_physical_apicid = new_apicid; + /* + * yeah -- we lie about apic_version + * in case if apic was disabled via boot option + * but it's not a problem for SMP compiled kernel + * since smp_sanity_check is prepared for such a case + * and disable smp mode + */ + apic_version[new_apicid] = + GET_APIC_VERSION(apic_read(APIC_LVR)); + } } /* @@ -1733,8 +1790,7 @@ void __init connect_bsp_APIC(void) */ apic_printk(APIC_VERBOSE, "leaving PIC mode, " "enabling APIC mode.\n"); - outb(0x70, 0x22); - outb(0x01, 0x23); + imcr_pic_to_apic(); } #endif if (apic->enable_apic_mode) @@ -1762,8 +1818,7 @@ void disconnect_bsp_APIC(int virt_wire_setup) */ apic_printk(APIC_VERBOSE, "disabling APIC mode, " "entering PIC mode.\n"); - outb(0x70, 0x22); - outb(0x00, 0x23); + imcr_apic_to_pic(); return; } #endif @@ -1962,17 +2017,17 @@ static int lapic_suspend(struct sys_device *dev, pm_message_t state) apic_pm_state.apic_lvterr = apic_read(APIC_LVTERR); apic_pm_state.apic_tmict = apic_read(APIC_TMICT); apic_pm_state.apic_tdcr = apic_read(APIC_TDCR); -#if defined(CONFIG_X86_MCE_P4THERMAL) || defined(CONFIG_X86_MCE_INTEL) +#ifdef CONFIG_X86_THERMAL_VECTOR if (maxlvt >= 5) apic_pm_state.apic_thmr = apic_read(APIC_LVTTHMR); #endif local_irq_save(flags); disable_local_APIC(); -#ifdef CONFIG_INTR_REMAP + if (intr_remapping_enabled) disable_intr_remapping(); -#endif + local_irq_restore(flags); return 0; } @@ -1982,42 +2037,34 @@ static int lapic_resume(struct sys_device *dev) unsigned int l, h; unsigned long flags; int maxlvt; - -#ifdef CONFIG_INTR_REMAP - int ret; + int ret = 0; struct IO_APIC_route_entry **ioapic_entries = NULL; if (!apic_pm_state.active) return 0; local_irq_save(flags); - if (x2apic) { + if (intr_remapping_enabled) { ioapic_entries = alloc_ioapic_entries(); if (!ioapic_entries) { WARN(1, "Alloc ioapic_entries in lapic resume failed."); - return -ENOMEM; + ret = -ENOMEM; + goto restore; } ret = save_IO_APIC_setup(ioapic_entries); if (ret) { WARN(1, "Saving IO-APIC state failed: %d\n", ret); free_ioapic_entries(ioapic_entries); - return ret; + goto restore; } mask_IO_APIC_setup(ioapic_entries); mask_8259A(); - enable_x2apic(); } -#else - if (!apic_pm_state.active) - return 0; - local_irq_save(flags); - if (x2apic) + if (x2apic_mode) enable_x2apic(); -#endif - else { /* * Make sure the APICBASE points to the right address @@ -2055,21 +2102,16 @@ static int lapic_resume(struct sys_device *dev) apic_write(APIC_ESR, 0); apic_read(APIC_ESR); -#ifdef CONFIG_INTR_REMAP - if (intr_remapping_enabled) - reenable_intr_remapping(EIM_32BIT_APIC_ID); - - if (x2apic) { + if (intr_remapping_enabled) { + reenable_intr_remapping(x2apic_mode); unmask_8259A(); restore_IO_APIC_setup(ioapic_entries); free_ioapic_entries(ioapic_entries); } -#endif - +restore: local_irq_restore(flags); - - return 0; + return ret; } /* @@ -2117,31 +2159,14 @@ static void apic_pm_activate(void) { } #endif /* CONFIG_PM */ #ifdef CONFIG_X86_64 -/* - * apic_is_clustered_box() -- Check if we can expect good TSC - * - * Thus far, the major user of this is IBM's Summit2 series: - * - * Clustered boxes may have unsynced TSC problems if they are - * multi-chassis. Use available data to take a good guess. - * If in doubt, go HPET. - */ -__cpuinit int apic_is_clustered_box(void) + +static int __cpuinit apic_cluster_num(void) { int i, clusters, zeros; unsigned id; u16 *bios_cpu_apicid; DECLARE_BITMAP(clustermap, NUM_APIC_CLUSTERS); - /* - * there is not this kind of box with AMD CPU yet. - * Some AMD box with quadcore cpu and 8 sockets apicid - * will be [4, 0x23] or [8, 0x27] could be thought to - * vsmp box still need checking... - */ - if ((boot_cpu_data.x86_vendor == X86_VENDOR_AMD) && !is_vsmp_box()) - return 0; - bios_cpu_apicid = early_per_cpu_ptr(x86_bios_cpu_apicid); bitmap_zero(clustermap, NUM_APIC_CLUSTERS); @@ -2177,18 +2202,67 @@ __cpuinit int apic_is_clustered_box(void) ++zeros; } - /* ScaleMP vSMPowered boxes have one cluster per board and TSCs are - * not guaranteed to be synced between boards - */ - if (is_vsmp_box() && clusters > 1) + return clusters; +} + +static int __cpuinitdata multi_checked; +static int __cpuinitdata multi; + +static int __cpuinit set_multi(const struct dmi_system_id *d) +{ + if (multi) + return 0; + pr_info("APIC: %s detected, Multi Chassis\n", d->ident); + multi = 1; + return 0; +} + +static const __cpuinitconst struct dmi_system_id multi_dmi_table[] = { + { + .callback = set_multi, + .ident = "IBM System Summit2", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "IBM"), + DMI_MATCH(DMI_PRODUCT_NAME, "Summit2"), + }, + }, + {} +}; + +static void __cpuinit dmi_check_multi(void) +{ + if (multi_checked) + return; + + dmi_check_system(multi_dmi_table); + multi_checked = 1; +} + +/* + * apic_is_clustered_box() -- Check if we can expect good TSC + * + * Thus far, the major user of this is IBM's Summit2 series: + * Clustered boxes may have unsynced TSC problems if they are + * multi-chassis. + * Use DMI to check them + */ +__cpuinit int apic_is_clustered_box(void) +{ + dmi_check_multi(); + if (multi) return 1; + if (!is_vsmp_box()) + return 0; + /* - * If clusters > 2, then should be multi-chassis. - * May have to revisit this when multi-core + hyperthreaded CPUs come - * out, but AFAIK this will work even for them. + * ScaleMP vSMPowered boxes have one cluster per board and TSCs are + * not guaranteed to be synced between boards */ - return (clusters > 2); + if (apic_cluster_num() > 1) + return 1; + + return 0; } #endif diff --git a/arch/x86/kernel/apic/apic_flat_64.c b/arch/x86/kernel/apic/apic_flat_64.c index 306e5e88fb6f..d0c99abc26c3 100644 --- a/arch/x86/kernel/apic/apic_flat_64.c +++ b/arch/x86/kernel/apic/apic_flat_64.c @@ -161,7 +161,7 @@ static int flat_apic_id_registered(void) static int flat_phys_pkg_id(int initial_apic_id, int index_msb) { - return hard_smp_processor_id() >> index_msb; + return initial_apic_id >> index_msb; } struct apic apic_flat = { @@ -235,7 +235,7 @@ static int physflat_acpi_madt_oem_check(char *oem_id, char *oem_table_id) * regardless of how many processors are present (x86_64 ES7000 * is an example). */ - if (acpi_gbl_FADT.header.revision > FADT2_REVISION_ID && + if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID && (acpi_gbl_FADT.flags & ACPI_FADT_APIC_PHYSICAL)) { printk(KERN_DEBUG "system APIC only can use physical flat"); return 1; diff --git a/arch/x86/kernel/apic/es7000_32.c b/arch/x86/kernel/apic/es7000_32.c index 302947775575..69328ac8de9c 100644 --- a/arch/x86/kernel/apic/es7000_32.c +++ b/arch/x86/kernel/apic/es7000_32.c @@ -145,7 +145,7 @@ es7000_rename_gsi(int ioapic, int gsi) return gsi; } -static int wakeup_secondary_cpu_via_mip(int cpu, unsigned long eip) +static int __cpuinit wakeup_secondary_cpu_via_mip(int cpu, unsigned long eip) { unsigned long vect = 0, psaival = 0; diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 30da617d18e4..4d0216fcb36c 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -59,6 +59,7 @@ #include #include #include +#include #include #include @@ -129,12 +130,9 @@ struct irq_pin_list { struct irq_pin_list *next; }; -static struct irq_pin_list *get_one_free_irq_2_pin(int cpu) +static struct irq_pin_list *get_one_free_irq_2_pin(int node) { struct irq_pin_list *pin; - int node; - - node = cpu_to_node(cpu); pin = kzalloc_node(sizeof(*pin), GFP_ATOMIC, node); @@ -148,9 +146,6 @@ struct irq_cfg { unsigned move_cleanup_count; u8 vector; u8 move_in_progress : 1; -#ifdef CONFIG_NUMA_MIGRATE_IRQ_DESC - u8 move_desc_pending : 1; -#endif }; /* irq_cfg is indexed by the sum of all RTEs in all I/O APICs. */ @@ -182,16 +177,18 @@ int __init arch_early_irq_init(void) struct irq_cfg *cfg; struct irq_desc *desc; int count; + int node; int i; cfg = irq_cfgx; count = ARRAY_SIZE(irq_cfgx); + node= cpu_to_node(boot_cpu_id); for (i = 0; i < count; i++) { desc = irq_to_desc(i); desc->chip_data = &cfg[i]; - alloc_bootmem_cpumask_var(&cfg[i].domain); - alloc_bootmem_cpumask_var(&cfg[i].old_domain); + zalloc_cpumask_var_node(&cfg[i].domain, GFP_NOWAIT, node); + zalloc_cpumask_var_node(&cfg[i].old_domain, GFP_NOWAIT, node); if (i < NR_IRQS_LEGACY) cpumask_setall(cfg[i].domain); } @@ -212,12 +209,9 @@ static struct irq_cfg *irq_cfg(unsigned int irq) return cfg; } -static struct irq_cfg *get_one_free_irq_cfg(int cpu) +static struct irq_cfg *get_one_free_irq_cfg(int node) { struct irq_cfg *cfg; - int node; - - node = cpu_to_node(cpu); cfg = kzalloc_node(sizeof(*cfg), GFP_ATOMIC, node); if (cfg) { @@ -238,13 +232,13 @@ static struct irq_cfg *get_one_free_irq_cfg(int cpu) return cfg; } -int arch_init_chip_data(struct irq_desc *desc, int cpu) +int arch_init_chip_data(struct irq_desc *desc, int node) { struct irq_cfg *cfg; cfg = desc->chip_data; if (!cfg) { - desc->chip_data = get_one_free_irq_cfg(cpu); + desc->chip_data = get_one_free_irq_cfg(node); if (!desc->chip_data) { printk(KERN_ERR "can not alloc irq_cfg\n"); BUG_ON(1); @@ -254,10 +248,9 @@ int arch_init_chip_data(struct irq_desc *desc, int cpu) return 0; } -#ifdef CONFIG_NUMA_MIGRATE_IRQ_DESC - +/* for move_irq_desc */ static void -init_copy_irq_2_pin(struct irq_cfg *old_cfg, struct irq_cfg *cfg, int cpu) +init_copy_irq_2_pin(struct irq_cfg *old_cfg, struct irq_cfg *cfg, int node) { struct irq_pin_list *old_entry, *head, *tail, *entry; @@ -266,7 +259,7 @@ init_copy_irq_2_pin(struct irq_cfg *old_cfg, struct irq_cfg *cfg, int cpu) if (!old_entry) return; - entry = get_one_free_irq_2_pin(cpu); + entry = get_one_free_irq_2_pin(node); if (!entry) return; @@ -276,7 +269,7 @@ init_copy_irq_2_pin(struct irq_cfg *old_cfg, struct irq_cfg *cfg, int cpu) tail = entry; old_entry = old_entry->next; while (old_entry) { - entry = get_one_free_irq_2_pin(cpu); + entry = get_one_free_irq_2_pin(node); if (!entry) { entry = head; while (entry) { @@ -316,12 +309,12 @@ static void free_irq_2_pin(struct irq_cfg *old_cfg, struct irq_cfg *cfg) } void arch_init_copy_chip_data(struct irq_desc *old_desc, - struct irq_desc *desc, int cpu) + struct irq_desc *desc, int node) { struct irq_cfg *cfg; struct irq_cfg *old_cfg; - cfg = get_one_free_irq_cfg(cpu); + cfg = get_one_free_irq_cfg(node); if (!cfg) return; @@ -332,7 +325,7 @@ void arch_init_copy_chip_data(struct irq_desc *old_desc, memcpy(cfg, old_cfg, sizeof(struct irq_cfg)); - init_copy_irq_2_pin(old_cfg, cfg, cpu); + init_copy_irq_2_pin(old_cfg, cfg, node); } static void free_irq_cfg(struct irq_cfg *old_cfg) @@ -356,19 +349,7 @@ void arch_free_chip_data(struct irq_desc *old_desc, struct irq_desc *desc) old_desc->chip_data = NULL; } } - -static void -set_extra_move_desc(struct irq_desc *desc, const struct cpumask *mask) -{ - struct irq_cfg *cfg = desc->chip_data; - - if (!cfg->move_in_progress) { - /* it means that domain is not changed */ - if (!cpumask_intersects(desc->affinity, mask)) - cfg->move_desc_pending = 1; - } -} -#endif +/* end for move_irq_desc */ #else static struct irq_cfg *irq_cfg(unsigned int irq) @@ -378,13 +359,6 @@ static struct irq_cfg *irq_cfg(unsigned int irq) #endif -#ifndef CONFIG_NUMA_MIGRATE_IRQ_DESC -static inline void -set_extra_move_desc(struct irq_desc *desc, const struct cpumask *mask) -{ -} -#endif - struct io_apic { unsigned int index; unsigned int unused[3]; @@ -488,7 +462,8 @@ static struct IO_APIC_route_entry ioapic_read_entry(int apic, int pin) static void __ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e) { - union entry_union eu; + union entry_union eu = {{0, 0}}; + eu.entry = e; io_apic_write(apic, 0x11 + 2*pin, eu.w2); io_apic_write(apic, 0x10 + 2*pin, eu.w1); @@ -518,132 +493,18 @@ static void ioapic_mask_entry(int apic, int pin) spin_unlock_irqrestore(&ioapic_lock, flags); } -#ifdef CONFIG_SMP -static void send_cleanup_vector(struct irq_cfg *cfg) -{ - cpumask_var_t cleanup_mask; - - if (unlikely(!alloc_cpumask_var(&cleanup_mask, GFP_ATOMIC))) { - unsigned int i; - cfg->move_cleanup_count = 0; - for_each_cpu_and(i, cfg->old_domain, cpu_online_mask) - cfg->move_cleanup_count++; - for_each_cpu_and(i, cfg->old_domain, cpu_online_mask) - apic->send_IPI_mask(cpumask_of(i), IRQ_MOVE_CLEANUP_VECTOR); - } else { - cpumask_and(cleanup_mask, cfg->old_domain, cpu_online_mask); - cfg->move_cleanup_count = cpumask_weight(cleanup_mask); - apic->send_IPI_mask(cleanup_mask, IRQ_MOVE_CLEANUP_VECTOR); - free_cpumask_var(cleanup_mask); - } - cfg->move_in_progress = 0; -} - -static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, struct irq_cfg *cfg) -{ - int apic, pin; - struct irq_pin_list *entry; - u8 vector = cfg->vector; - - entry = cfg->irq_2_pin; - for (;;) { - unsigned int reg; - - if (!entry) - break; - - apic = entry->apic; - pin = entry->pin; - /* - * With interrupt-remapping, destination information comes - * from interrupt-remapping table entry. - */ - if (!irq_remapped(irq)) - io_apic_write(apic, 0x11 + pin*2, dest); - reg = io_apic_read(apic, 0x10 + pin*2); - reg &= ~IO_APIC_REDIR_VECTOR_MASK; - reg |= vector; - io_apic_modify(apic, 0x10 + pin*2, reg); - if (!entry->next) - break; - entry = entry->next; - } -} - -static int -assign_irq_vector(int irq, struct irq_cfg *cfg, const struct cpumask *mask); - -/* - * Either sets desc->affinity to a valid value, and returns - * ->cpu_mask_to_apicid of that, or returns BAD_APICID and - * leaves desc->affinity untouched. - */ -static unsigned int -set_desc_affinity(struct irq_desc *desc, const struct cpumask *mask) -{ - struct irq_cfg *cfg; - unsigned int irq; - - if (!cpumask_intersects(mask, cpu_online_mask)) - return BAD_APICID; - - irq = desc->irq; - cfg = desc->chip_data; - if (assign_irq_vector(irq, cfg, mask)) - return BAD_APICID; - - /* check that before desc->addinity get updated */ - set_extra_move_desc(desc, mask); - - cpumask_copy(desc->affinity, mask); - - return apic->cpu_mask_to_apicid_and(desc->affinity, cfg->domain); -} - -static void -set_ioapic_affinity_irq_desc(struct irq_desc *desc, const struct cpumask *mask) -{ - struct irq_cfg *cfg; - unsigned long flags; - unsigned int dest; - unsigned int irq; - - irq = desc->irq; - cfg = desc->chip_data; - - spin_lock_irqsave(&ioapic_lock, flags); - dest = set_desc_affinity(desc, mask); - if (dest != BAD_APICID) { - /* Only the high 8 bits are valid. */ - dest = SET_APIC_LOGICAL_ID(dest); - __target_IO_APIC_irq(irq, dest, cfg); - } - spin_unlock_irqrestore(&ioapic_lock, flags); -} - -static void -set_ioapic_affinity_irq(unsigned int irq, const struct cpumask *mask) -{ - struct irq_desc *desc; - - desc = irq_to_desc(irq); - - set_ioapic_affinity_irq_desc(desc, mask); -} -#endif /* CONFIG_SMP */ - /* * The common case is 1:1 IRQ<->pin mappings. Sometimes there are * shared ISA-space IRQs, so we have to support them. We are super * fast in the common case, and fast for shared ISA-space IRQs. */ -static void add_pin_to_irq_cpu(struct irq_cfg *cfg, int cpu, int apic, int pin) +static void add_pin_to_irq_node(struct irq_cfg *cfg, int node, int apic, int pin) { struct irq_pin_list *entry; entry = cfg->irq_2_pin; if (!entry) { - entry = get_one_free_irq_2_pin(cpu); + entry = get_one_free_irq_2_pin(node); if (!entry) { printk(KERN_ERR "can not alloc irq_2_pin to add %d - %d\n", apic, pin); @@ -663,7 +524,7 @@ static void add_pin_to_irq_cpu(struct irq_cfg *cfg, int cpu, int apic, int pin) entry = entry->next; } - entry->next = get_one_free_irq_2_pin(cpu); + entry->next = get_one_free_irq_2_pin(node); entry = entry->next; entry->apic = apic; entry->pin = pin; @@ -672,7 +533,7 @@ static void add_pin_to_irq_cpu(struct irq_cfg *cfg, int cpu, int apic, int pin) /* * Reroute an IRQ to a different pin. */ -static void __init replace_pin_at_irq_cpu(struct irq_cfg *cfg, int cpu, +static void __init replace_pin_at_irq_node(struct irq_cfg *cfg, int node, int oldapic, int oldpin, int newapic, int newpin) { @@ -692,7 +553,7 @@ static void __init replace_pin_at_irq_cpu(struct irq_cfg *cfg, int cpu, /* why? call replace before add? */ if (!replaced) - add_pin_to_irq_cpu(cfg, cpu, newapic, newpin); + add_pin_to_irq_node(cfg, node, newapic, newpin); } static inline void io_apic_modify_irq(struct irq_cfg *cfg, @@ -850,7 +711,6 @@ static int __init ioapic_pirq_setup(char *str) __setup("pirq=", ioapic_pirq_setup); #endif /* CONFIG_X86_32 */ -#ifdef CONFIG_INTR_REMAP struct IO_APIC_route_entry **alloc_ioapic_entries(void) { int apic; @@ -948,20 +808,6 @@ int restore_IO_APIC_setup(struct IO_APIC_route_entry **ioapic_entries) return 0; } -void reinit_intr_remapped_IO_APIC(int intr_remapping, - struct IO_APIC_route_entry **ioapic_entries) - -{ - /* - * for now plain restore of previous settings. - * TBD: In the case of OS enabling interrupt-remapping, - * IO-APIC RTE's need to be setup to point to interrupt-remapping - * table entries. for now, do a plain restore, and wait for - * the setup_IO_APIC_irqs() to do proper initialization. - */ - restore_IO_APIC_setup(ioapic_entries); -} - void free_ioapic_entries(struct IO_APIC_route_entry **ioapic_entries) { int apic; @@ -971,7 +817,6 @@ void free_ioapic_entries(struct IO_APIC_route_entry **ioapic_entries) kfree(ioapic_entries); } -#endif /* * Find the IRQ entry number of a certain pin. @@ -1032,54 +877,6 @@ static int __init find_isa_irq_apic(int irq, int type) return -1; } -/* - * Find a specific PCI IRQ entry. - * Not an __init, possibly needed by modules - */ -static int pin_2_irq(int idx, int apic, int pin); - -int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin) -{ - int apic, i, best_guess = -1; - - apic_printk(APIC_DEBUG, "querying PCI -> IRQ mapping bus:%d, slot:%d, pin:%d.\n", - bus, slot, pin); - if (test_bit(bus, mp_bus_not_pci)) { - apic_printk(APIC_VERBOSE, "PCI BIOS passed nonexistent PCI bus %d!\n", bus); - return -1; - } - for (i = 0; i < mp_irq_entries; i++) { - int lbus = mp_irqs[i].srcbus; - - for (apic = 0; apic < nr_ioapics; apic++) - if (mp_ioapics[apic].apicid == mp_irqs[i].dstapic || - mp_irqs[i].dstapic == MP_APIC_ALL) - break; - - if (!test_bit(lbus, mp_bus_not_pci) && - !mp_irqs[i].irqtype && - (bus == lbus) && - (slot == ((mp_irqs[i].srcbusirq >> 2) & 0x1f))) { - int irq = pin_2_irq(i, apic, mp_irqs[i].dstirq); - - if (!(apic || IO_APIC_IRQ(irq))) - continue; - - if (pin == (mp_irqs[i].srcbusirq & 3)) - return irq; - /* - * Use the first all-but-pin matching entry as a - * best-guess fuzzy result for broken mptables. - */ - if (best_guess < 0) - best_guess = irq; - } - } - return best_guess; -} - -EXPORT_SYMBOL(IO_APIC_get_PCI_irq_vector); - #if defined(CONFIG_EISA) || defined(CONFIG_MCA) /* * EISA Edge/Level control register, ELCR @@ -1298,6 +1095,64 @@ static int pin_2_irq(int idx, int apic, int pin) return irq; } +/* + * Find a specific PCI IRQ entry. + * Not an __init, possibly needed by modules + */ +int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin, + struct io_apic_irq_attr *irq_attr) +{ + int apic, i, best_guess = -1; + + apic_printk(APIC_DEBUG, + "querying PCI -> IRQ mapping bus:%d, slot:%d, pin:%d.\n", + bus, slot, pin); + if (test_bit(bus, mp_bus_not_pci)) { + apic_printk(APIC_VERBOSE, + "PCI BIOS passed nonexistent PCI bus %d!\n", bus); + return -1; + } + for (i = 0; i < mp_irq_entries; i++) { + int lbus = mp_irqs[i].srcbus; + + for (apic = 0; apic < nr_ioapics; apic++) + if (mp_ioapics[apic].apicid == mp_irqs[i].dstapic || + mp_irqs[i].dstapic == MP_APIC_ALL) + break; + + if (!test_bit(lbus, mp_bus_not_pci) && + !mp_irqs[i].irqtype && + (bus == lbus) && + (slot == ((mp_irqs[i].srcbusirq >> 2) & 0x1f))) { + int irq = pin_2_irq(i, apic, mp_irqs[i].dstirq); + + if (!(apic || IO_APIC_IRQ(irq))) + continue; + + if (pin == (mp_irqs[i].srcbusirq & 3)) { + set_io_apic_irq_attr(irq_attr, apic, + mp_irqs[i].dstirq, + irq_trigger(i), + irq_polarity(i)); + return irq; + } + /* + * Use the first all-but-pin matching entry as a + * best-guess fuzzy result for broken mptables. + */ + if (best_guess < 0) { + set_io_apic_irq_attr(irq_attr, apic, + mp_irqs[i].dstirq, + irq_trigger(i), + irq_polarity(i)); + best_guess = irq; + } + } + } + return best_guess; +} +EXPORT_SYMBOL(IO_APIC_get_PCI_irq_vector); + void lock_vector_lock(void) { /* Used to the online set of cpus does not change @@ -1559,6 +1414,9 @@ int setup_ioapic_entry(int apic_id, int irq, irte.vector = vector; irte.dest_id = IRTE_DEST(destination); + /* Set source-id of interrupt request */ + set_ioapic_sid(&irte, apic_id); + modify_irte(irq, &irte); ir_entry->index2 = (index >> 15) & 0x1; @@ -1628,58 +1486,70 @@ static void setup_IO_APIC_irq(int apic_id, int pin, unsigned int irq, struct irq ioapic_write_entry(apic_id, pin, entry); } +static struct { + DECLARE_BITMAP(pin_programmed, MP_MAX_IOAPIC_PIN + 1); +} mp_ioapic_routing[MAX_IO_APICS]; + static void __init setup_IO_APIC_irqs(void) { - int apic_id, pin, idx, irq; + int apic_id = 0, pin, idx, irq; int notcon = 0; struct irq_desc *desc; struct irq_cfg *cfg; - int cpu = boot_cpu_id; + int node = cpu_to_node(boot_cpu_id); apic_printk(APIC_VERBOSE, KERN_DEBUG "init IO_APIC IRQs\n"); - for (apic_id = 0; apic_id < nr_ioapics; apic_id++) { - for (pin = 0; pin < nr_ioapic_registers[apic_id]; pin++) { +#ifdef CONFIG_ACPI + if (!acpi_disabled && acpi_ioapic) { + apic_id = mp_find_ioapic(0); + if (apic_id < 0) + apic_id = 0; + } +#endif - idx = find_irq_entry(apic_id, pin, mp_INT); - if (idx == -1) { - if (!notcon) { - notcon = 1; - apic_printk(APIC_VERBOSE, - KERN_DEBUG " %d-%d", - mp_ioapics[apic_id].apicid, pin); - } else - apic_printk(APIC_VERBOSE, " %d-%d", - mp_ioapics[apic_id].apicid, pin); - continue; - } - if (notcon) { + for (pin = 0; pin < nr_ioapic_registers[apic_id]; pin++) { + idx = find_irq_entry(apic_id, pin, mp_INT); + if (idx == -1) { + if (!notcon) { + notcon = 1; apic_printk(APIC_VERBOSE, - " (apicid-pin) not connected\n"); - notcon = 0; - } - - irq = pin_2_irq(idx, apic_id, pin); - - /* - * Skip the timer IRQ if there's a quirk handler - * installed and if it returns 1: - */ - if (apic->multi_timer_check && - apic->multi_timer_check(apic_id, irq)) - continue; - - desc = irq_to_desc_alloc_cpu(irq, cpu); - if (!desc) { - printk(KERN_INFO "can not get irq_desc for %d\n", irq); - continue; - } - cfg = desc->chip_data; - add_pin_to_irq_cpu(cfg, cpu, apic_id, pin); - - setup_IO_APIC_irq(apic_id, pin, irq, desc, - irq_trigger(idx), irq_polarity(idx)); + KERN_DEBUG " %d-%d", + mp_ioapics[apic_id].apicid, pin); + } else + apic_printk(APIC_VERBOSE, " %d-%d", + mp_ioapics[apic_id].apicid, pin); + continue; } + if (notcon) { + apic_printk(APIC_VERBOSE, + " (apicid-pin) not connected\n"); + notcon = 0; + } + + irq = pin_2_irq(idx, apic_id, pin); + + /* + * Skip the timer IRQ if there's a quirk handler + * installed and if it returns 1: + */ + if (apic->multi_timer_check && + apic->multi_timer_check(apic_id, irq)) + continue; + + desc = irq_to_desc_alloc_node(irq, node); + if (!desc) { + printk(KERN_INFO "can not get irq_desc for %d\n", irq); + continue; + } + cfg = desc->chip_data; + add_pin_to_irq_node(cfg, node, apic_id, pin); + /* + * don't mark it in pin_programmed, so later acpi could + * set it correctly when irq < 16 + */ + setup_IO_APIC_irq(apic_id, pin, irq, desc, + irq_trigger(idx), irq_polarity(idx)); } if (notcon) @@ -1869,7 +1739,7 @@ __apicdebuginit(void) print_APIC_bitfield(int base) __apicdebuginit(void) print_local_APIC(void *dummy) { - unsigned int v, ver, maxlvt; + unsigned int i, v, ver, maxlvt; u64 icr; if (apic_verbosity == APIC_QUIET) @@ -1957,6 +1827,18 @@ __apicdebuginit(void) print_local_APIC(void *dummy) printk(KERN_DEBUG "... APIC TMCCT: %08x\n", v); v = apic_read(APIC_TDCR); printk(KERN_DEBUG "... APIC TDCR: %08x\n", v); + + if (boot_cpu_has(X86_FEATURE_EXTAPIC)) { + v = apic_read(APIC_EFEAT); + maxlvt = (v >> 16) & 0xff; + printk(KERN_DEBUG "... APIC EFEAT: %08x\n", v); + v = apic_read(APIC_ECTRL); + printk(KERN_DEBUG "... APIC ECTRL: %08x\n", v); + for (i = 0; i < maxlvt; i++) { + v = apic_read(APIC_EILVTn(i)); + printk(KERN_DEBUG "... APIC EILVT%d: %08x\n", i, v); + } + } printk("\n"); } @@ -2005,6 +1887,11 @@ __apicdebuginit(void) print_PIC(void) __apicdebuginit(int) print_all_ICs(void) { print_PIC(); + + /* don't print out if apic is not there */ + if (!cpu_has_apic || disable_apic) + return 0; + print_all_local_APICs(); print_IO_APIC(); @@ -2120,7 +2007,9 @@ void disable_IO_APIC(void) /* * Use virtual wire A mode when interrupt remapping is enabled. */ - disconnect_bsp_APIC(!intr_remapping_enabled && ioapic_i8259.pin != -1); + if (cpu_has_apic) + disconnect_bsp_APIC(!intr_remapping_enabled && + ioapic_i8259.pin != -1); } #ifdef CONFIG_X86_32 @@ -2360,6 +2249,118 @@ static int ioapic_retrigger_irq(unsigned int irq) */ #ifdef CONFIG_SMP +static void send_cleanup_vector(struct irq_cfg *cfg) +{ + cpumask_var_t cleanup_mask; + + if (unlikely(!alloc_cpumask_var(&cleanup_mask, GFP_ATOMIC))) { + unsigned int i; + cfg->move_cleanup_count = 0; + for_each_cpu_and(i, cfg->old_domain, cpu_online_mask) + cfg->move_cleanup_count++; + for_each_cpu_and(i, cfg->old_domain, cpu_online_mask) + apic->send_IPI_mask(cpumask_of(i), IRQ_MOVE_CLEANUP_VECTOR); + } else { + cpumask_and(cleanup_mask, cfg->old_domain, cpu_online_mask); + cfg->move_cleanup_count = cpumask_weight(cleanup_mask); + apic->send_IPI_mask(cleanup_mask, IRQ_MOVE_CLEANUP_VECTOR); + free_cpumask_var(cleanup_mask); + } + cfg->move_in_progress = 0; +} + +static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, struct irq_cfg *cfg) +{ + int apic, pin; + struct irq_pin_list *entry; + u8 vector = cfg->vector; + + entry = cfg->irq_2_pin; + for (;;) { + unsigned int reg; + + if (!entry) + break; + + apic = entry->apic; + pin = entry->pin; + /* + * With interrupt-remapping, destination information comes + * from interrupt-remapping table entry. + */ + if (!irq_remapped(irq)) + io_apic_write(apic, 0x11 + pin*2, dest); + reg = io_apic_read(apic, 0x10 + pin*2); + reg &= ~IO_APIC_REDIR_VECTOR_MASK; + reg |= vector; + io_apic_modify(apic, 0x10 + pin*2, reg); + if (!entry->next) + break; + entry = entry->next; + } +} + +static int +assign_irq_vector(int irq, struct irq_cfg *cfg, const struct cpumask *mask); + +/* + * Either sets desc->affinity to a valid value, and returns + * ->cpu_mask_to_apicid of that, or returns BAD_APICID and + * leaves desc->affinity untouched. + */ +static unsigned int +set_desc_affinity(struct irq_desc *desc, const struct cpumask *mask) +{ + struct irq_cfg *cfg; + unsigned int irq; + + if (!cpumask_intersects(mask, cpu_online_mask)) + return BAD_APICID; + + irq = desc->irq; + cfg = desc->chip_data; + if (assign_irq_vector(irq, cfg, mask)) + return BAD_APICID; + + cpumask_copy(desc->affinity, mask); + + return apic->cpu_mask_to_apicid_and(desc->affinity, cfg->domain); +} + +static int +set_ioapic_affinity_irq_desc(struct irq_desc *desc, const struct cpumask *mask) +{ + struct irq_cfg *cfg; + unsigned long flags; + unsigned int dest; + unsigned int irq; + int ret = -1; + + irq = desc->irq; + cfg = desc->chip_data; + + spin_lock_irqsave(&ioapic_lock, flags); + dest = set_desc_affinity(desc, mask); + if (dest != BAD_APICID) { + /* Only the high 8 bits are valid. */ + dest = SET_APIC_LOGICAL_ID(dest); + __target_IO_APIC_irq(irq, dest, cfg); + ret = 0; + } + spin_unlock_irqrestore(&ioapic_lock, flags); + + return ret; +} + +static int +set_ioapic_affinity_irq(unsigned int irq, const struct cpumask *mask) +{ + struct irq_desc *desc; + + desc = irq_to_desc(irq); + + return set_ioapic_affinity_irq_desc(desc, mask); +} #ifdef CONFIG_INTR_REMAP @@ -2374,26 +2375,25 @@ static int ioapic_retrigger_irq(unsigned int irq) * Real vector that is used for interrupting cpu will be coming from * the interrupt-remapping table entry. */ -static void +static int migrate_ioapic_irq_desc(struct irq_desc *desc, const struct cpumask *mask) { struct irq_cfg *cfg; struct irte irte; unsigned int dest; unsigned int irq; + int ret = -1; if (!cpumask_intersects(mask, cpu_online_mask)) - return; + return ret; irq = desc->irq; if (get_irte(irq, &irte)) - return; + return ret; cfg = desc->chip_data; if (assign_irq_vector(irq, cfg, mask)) - return; - - set_extra_move_desc(desc, mask); + return ret; dest = apic->cpu_mask_to_apicid_and(cfg->domain, mask); @@ -2409,27 +2409,30 @@ migrate_ioapic_irq_desc(struct irq_desc *desc, const struct cpumask *mask) send_cleanup_vector(cfg); cpumask_copy(desc->affinity, mask); + + return 0; } /* * Migrates the IRQ destination in the process context. */ -static void set_ir_ioapic_affinity_irq_desc(struct irq_desc *desc, +static int set_ir_ioapic_affinity_irq_desc(struct irq_desc *desc, const struct cpumask *mask) { - migrate_ioapic_irq_desc(desc, mask); + return migrate_ioapic_irq_desc(desc, mask); } -static void set_ir_ioapic_affinity_irq(unsigned int irq, +static int set_ir_ioapic_affinity_irq(unsigned int irq, const struct cpumask *mask) { struct irq_desc *desc = irq_to_desc(irq); - set_ir_ioapic_affinity_irq_desc(desc, mask); + return set_ir_ioapic_affinity_irq_desc(desc, mask); } #else -static inline void set_ir_ioapic_affinity_irq_desc(struct irq_desc *desc, +static inline int set_ir_ioapic_affinity_irq_desc(struct irq_desc *desc, const struct cpumask *mask) { + return 0; } #endif @@ -2491,86 +2494,19 @@ static void irq_complete_move(struct irq_desc **descp) struct irq_cfg *cfg = desc->chip_data; unsigned vector, me; - if (likely(!cfg->move_in_progress)) { -#ifdef CONFIG_NUMA_MIGRATE_IRQ_DESC - if (likely(!cfg->move_desc_pending)) - return; - - /* domain has not changed, but affinity did */ - me = smp_processor_id(); - if (cpumask_test_cpu(me, desc->affinity)) { - *descp = desc = move_irq_desc(desc, me); - /* get the new one */ - cfg = desc->chip_data; - cfg->move_desc_pending = 0; - } -#endif + if (likely(!cfg->move_in_progress)) return; - } vector = ~get_irq_regs()->orig_ax; me = smp_processor_id(); - if (vector == cfg->vector && cpumask_test_cpu(me, cfg->domain)) { -#ifdef CONFIG_NUMA_MIGRATE_IRQ_DESC - *descp = desc = move_irq_desc(desc, me); - /* get the new one */ - cfg = desc->chip_data; -#endif + if (vector == cfg->vector && cpumask_test_cpu(me, cfg->domain)) send_cleanup_vector(cfg); - } } #else static inline void irq_complete_move(struct irq_desc **descp) {} #endif -static void __eoi_ioapic_irq(unsigned int irq, struct irq_cfg *cfg) -{ - int apic, pin; - struct irq_pin_list *entry; - - entry = cfg->irq_2_pin; - for (;;) { - - if (!entry) - break; - - apic = entry->apic; - pin = entry->pin; - io_apic_eoi(apic, pin); - entry = entry->next; - } -} - -static void -eoi_ioapic_irq(struct irq_desc *desc) -{ - struct irq_cfg *cfg; - unsigned long flags; - unsigned int irq; - - irq = desc->irq; - cfg = desc->chip_data; - - spin_lock_irqsave(&ioapic_lock, flags); - __eoi_ioapic_irq(irq, cfg); - spin_unlock_irqrestore(&ioapic_lock, flags); -} - -#ifdef CONFIG_X86_X2APIC -static void ack_x2apic_level(unsigned int irq) -{ - struct irq_desc *desc = irq_to_desc(irq); - ack_x2APIC_irq(); - eoi_ioapic_irq(desc); -} - -static void ack_x2apic_edge(unsigned int irq) -{ - ack_x2APIC_irq(); -} -#endif - static void ack_apic_edge(unsigned int irq) { struct irq_desc *desc = irq_to_desc(irq); @@ -2634,9 +2570,6 @@ static void ack_apic_level(unsigned int irq) */ ack_APIC_irq(); - if (irq_remapped(irq)) - eoi_ioapic_irq(desc); - /* Now we can move and renable the irq */ if (unlikely(do_unmask_irq)) { /* Only migrate the irq if the ack has been received. @@ -2683,22 +2616,50 @@ static void ack_apic_level(unsigned int irq) } #ifdef CONFIG_INTR_REMAP +static void __eoi_ioapic_irq(unsigned int irq, struct irq_cfg *cfg) +{ + int apic, pin; + struct irq_pin_list *entry; + + entry = cfg->irq_2_pin; + for (;;) { + + if (!entry) + break; + + apic = entry->apic; + pin = entry->pin; + io_apic_eoi(apic, pin); + entry = entry->next; + } +} + +static void +eoi_ioapic_irq(struct irq_desc *desc) +{ + struct irq_cfg *cfg; + unsigned long flags; + unsigned int irq; + + irq = desc->irq; + cfg = desc->chip_data; + + spin_lock_irqsave(&ioapic_lock, flags); + __eoi_ioapic_irq(irq, cfg); + spin_unlock_irqrestore(&ioapic_lock, flags); +} + static void ir_ack_apic_edge(unsigned int irq) { -#ifdef CONFIG_X86_X2APIC - if (x2apic_enabled()) - return ack_x2apic_edge(irq); -#endif - return ack_apic_edge(irq); + ack_APIC_irq(); } static void ir_ack_apic_level(unsigned int irq) { -#ifdef CONFIG_X86_X2APIC - if (x2apic_enabled()) - return ack_x2apic_level(irq); -#endif - return ack_apic_level(irq); + struct irq_desc *desc = irq_to_desc(irq); + + ack_APIC_irq(); + eoi_ioapic_irq(desc); } #endif /* CONFIG_INTR_REMAP */ @@ -2903,7 +2864,7 @@ static inline void __init check_timer(void) { struct irq_desc *desc = irq_to_desc(0); struct irq_cfg *cfg = desc->chip_data; - int cpu = boot_cpu_id; + int node = cpu_to_node(boot_cpu_id); int apic1, pin1, apic2, pin2; unsigned long flags; int no_pin1 = 0; @@ -2969,7 +2930,7 @@ static inline void __init check_timer(void) * Ok, does IRQ0 through the IOAPIC work? */ if (no_pin1) { - add_pin_to_irq_cpu(cfg, cpu, apic1, pin1); + add_pin_to_irq_node(cfg, node, apic1, pin1); setup_timer_IRQ0_pin(apic1, pin1, cfg->vector); } else { /* for edge trigger, setup_IO_APIC_irq already @@ -3006,7 +2967,7 @@ static inline void __init check_timer(void) /* * legacy devices should be connected to IO APIC #0 */ - replace_pin_at_irq_cpu(cfg, cpu, apic1, pin1, apic2, pin2); + replace_pin_at_irq_node(cfg, node, apic1, pin1, apic2, pin2); setup_timer_IRQ0_pin(apic2, pin2, cfg->vector); enable_8259A_irq(0); if (timer_irq_works()) { @@ -3218,14 +3179,13 @@ static int nr_irqs_gsi = NR_IRQS_LEGACY; /* * Dynamic irq allocate and deallocation */ -unsigned int create_irq_nr(unsigned int irq_want) +unsigned int create_irq_nr(unsigned int irq_want, int node) { /* Allocate an unused irq */ unsigned int irq; unsigned int new; unsigned long flags; struct irq_cfg *cfg_new = NULL; - int cpu = boot_cpu_id; struct irq_desc *desc_new = NULL; irq = 0; @@ -3234,7 +3194,7 @@ unsigned int create_irq_nr(unsigned int irq_want) spin_lock_irqsave(&vector_lock, flags); for (new = irq_want; new < nr_irqs; new++) { - desc_new = irq_to_desc_alloc_cpu(new, cpu); + desc_new = irq_to_desc_alloc_node(new, node); if (!desc_new) { printk(KERN_INFO "can not get irq_desc for %d\n", new); continue; @@ -3243,6 +3203,9 @@ unsigned int create_irq_nr(unsigned int irq_want) if (cfg_new->vector != 0) continue; + + desc_new = move_irq_desc(desc_new, node); + if (__assign_irq_vector(new, cfg_new, apic->target_cpus()) == 0) irq = new; break; @@ -3260,11 +3223,12 @@ unsigned int create_irq_nr(unsigned int irq_want) int create_irq(void) { + int node = cpu_to_node(boot_cpu_id); unsigned int irq_want; int irq; irq_want = nr_irqs_gsi; - irq = create_irq_nr(irq_want); + irq = create_irq_nr(irq_want, node); if (irq == 0) irq = -1; @@ -3329,6 +3293,9 @@ static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_ms irte.vector = cfg->vector; irte.dest_id = IRTE_DEST(dest); + /* Set source-id of interrupt request */ + set_msi_sid(&irte, pdev); + modify_irte(irq, &irte); msg->address_hi = MSI_ADDR_BASE_HI; @@ -3366,7 +3333,7 @@ static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_ms } #ifdef CONFIG_SMP -static void set_msi_irq_affinity(unsigned int irq, const struct cpumask *mask) +static int set_msi_irq_affinity(unsigned int irq, const struct cpumask *mask) { struct irq_desc *desc = irq_to_desc(irq); struct irq_cfg *cfg; @@ -3375,7 +3342,7 @@ static void set_msi_irq_affinity(unsigned int irq, const struct cpumask *mask) dest = set_desc_affinity(desc, mask); if (dest == BAD_APICID) - return; + return -1; cfg = desc->chip_data; @@ -3387,13 +3354,15 @@ static void set_msi_irq_affinity(unsigned int irq, const struct cpumask *mask) msg.address_lo |= MSI_ADDR_DEST_ID(dest); write_msi_msg_desc(desc, &msg); + + return 0; } #ifdef CONFIG_INTR_REMAP /* * Migrate the MSI irq to another cpumask. This migration is * done in the process context using interrupt-remapping hardware. */ -static void +static int ir_set_msi_irq_affinity(unsigned int irq, const struct cpumask *mask) { struct irq_desc *desc = irq_to_desc(irq); @@ -3402,11 +3371,11 @@ ir_set_msi_irq_affinity(unsigned int irq, const struct cpumask *mask) struct irte irte; if (get_irte(irq, &irte)) - return; + return -1; dest = set_desc_affinity(desc, mask); if (dest == BAD_APICID) - return; + return -1; irte.vector = cfg->vector; irte.dest_id = IRTE_DEST(dest); @@ -3423,6 +3392,8 @@ ir_set_msi_irq_affinity(unsigned int irq, const struct cpumask *mask) */ if (cfg->move_in_progress) send_cleanup_vector(cfg); + + return 0; } #endif @@ -3518,15 +3489,17 @@ int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) unsigned int irq_want; struct intel_iommu *iommu = NULL; int index = 0; + int node; /* x86 doesn't support multiple MSI yet */ if (type == PCI_CAP_ID_MSI && nvec > 1) return 1; + node = dev_to_node(&dev->dev); irq_want = nr_irqs_gsi; sub_handle = 0; list_for_each_entry(msidesc, &dev->msi_list, list) { - irq = create_irq_nr(irq_want); + irq = create_irq_nr(irq_want, node); if (irq == 0) return -1; irq_want = irq + 1; @@ -3576,7 +3549,7 @@ void arch_teardown_msi_irq(unsigned int irq) #if defined (CONFIG_DMAR) || defined (CONFIG_INTR_REMAP) #ifdef CONFIG_SMP -static void dmar_msi_set_affinity(unsigned int irq, const struct cpumask *mask) +static int dmar_msi_set_affinity(unsigned int irq, const struct cpumask *mask) { struct irq_desc *desc = irq_to_desc(irq); struct irq_cfg *cfg; @@ -3585,7 +3558,7 @@ static void dmar_msi_set_affinity(unsigned int irq, const struct cpumask *mask) dest = set_desc_affinity(desc, mask); if (dest == BAD_APICID) - return; + return -1; cfg = desc->chip_data; @@ -3597,11 +3570,13 @@ static void dmar_msi_set_affinity(unsigned int irq, const struct cpumask *mask) msg.address_lo |= MSI_ADDR_DEST_ID(dest); dmar_msi_write(irq, &msg); + + return 0; } #endif /* CONFIG_SMP */ -struct irq_chip dmar_msi_type = { +static struct irq_chip dmar_msi_type = { .name = "DMAR_MSI", .unmask = dmar_msi_unmask, .mask = dmar_msi_mask, @@ -3630,7 +3605,7 @@ int arch_setup_dmar_msi(unsigned int irq) #ifdef CONFIG_HPET_TIMER #ifdef CONFIG_SMP -static void hpet_msi_set_affinity(unsigned int irq, const struct cpumask *mask) +static int hpet_msi_set_affinity(unsigned int irq, const struct cpumask *mask) { struct irq_desc *desc = irq_to_desc(irq); struct irq_cfg *cfg; @@ -3639,7 +3614,7 @@ static void hpet_msi_set_affinity(unsigned int irq, const struct cpumask *mask) dest = set_desc_affinity(desc, mask); if (dest == BAD_APICID) - return; + return -1; cfg = desc->chip_data; @@ -3651,6 +3626,8 @@ static void hpet_msi_set_affinity(unsigned int irq, const struct cpumask *mask) msg.address_lo |= MSI_ADDR_DEST_ID(dest); hpet_msi_write(irq, &msg); + + return 0; } #endif /* CONFIG_SMP */ @@ -3707,7 +3684,7 @@ static void target_ht_irq(unsigned int irq, unsigned int dest, u8 vector) write_ht_irq_msg(irq, &msg); } -static void set_ht_irq_affinity(unsigned int irq, const struct cpumask *mask) +static int set_ht_irq_affinity(unsigned int irq, const struct cpumask *mask) { struct irq_desc *desc = irq_to_desc(irq); struct irq_cfg *cfg; @@ -3715,11 +3692,13 @@ static void set_ht_irq_affinity(unsigned int irq, const struct cpumask *mask) dest = set_desc_affinity(desc, mask); if (dest == BAD_APICID) - return; + return -1; cfg = desc->chip_data; target_ht_irq(irq, dest, cfg->vector); + + return 0; } #endif @@ -3794,6 +3773,8 @@ int arch_enable_uv_irq(char *irq_name, unsigned int irq, int cpu, int mmr_blade, unsigned long flags; int err; + BUILD_BUG_ON(sizeof(struct uv_IO_APIC_route_entry) != sizeof(unsigned long)); + cfg = irq_cfg(irq); err = assign_irq_vector(irq, cfg, eligible_cpu); @@ -3807,15 +3788,13 @@ int arch_enable_uv_irq(char *irq_name, unsigned int irq, int cpu, int mmr_blade, mmr_value = 0; entry = (struct uv_IO_APIC_route_entry *)&mmr_value; - BUG_ON(sizeof(struct uv_IO_APIC_route_entry) != sizeof(unsigned long)); - - entry->vector = cfg->vector; - entry->delivery_mode = apic->irq_delivery_mode; - entry->dest_mode = apic->irq_dest_mode; - entry->polarity = 0; - entry->trigger = 0; - entry->mask = 0; - entry->dest = apic->cpu_mask_to_apicid(eligible_cpu); + entry->vector = cfg->vector; + entry->delivery_mode = apic->irq_delivery_mode; + entry->dest_mode = apic->irq_dest_mode; + entry->polarity = 0; + entry->trigger = 0; + entry->mask = 0; + entry->dest = apic->cpu_mask_to_apicid(eligible_cpu); mmr_pnode = uv_blade_to_pnode(mmr_blade); uv_write_global_mmr64(mmr_pnode, mmr_offset, mmr_value); @@ -3833,10 +3812,10 @@ void arch_disable_uv_irq(int mmr_blade, unsigned long mmr_offset) struct uv_IO_APIC_route_entry *entry; int mmr_pnode; + BUILD_BUG_ON(sizeof(struct uv_IO_APIC_route_entry) != sizeof(unsigned long)); + mmr_value = 0; entry = (struct uv_IO_APIC_route_entry *)&mmr_value; - BUG_ON(sizeof(struct uv_IO_APIC_route_entry) != sizeof(unsigned long)); - entry->mask = 1; mmr_pnode = uv_blade_to_pnode(mmr_blade); @@ -3900,6 +3879,71 @@ int __init arch_probe_nr_irqs(void) } #endif +static int __io_apic_set_pci_routing(struct device *dev, int irq, + struct io_apic_irq_attr *irq_attr) +{ + struct irq_desc *desc; + struct irq_cfg *cfg; + int node; + int ioapic, pin; + int trigger, polarity; + + ioapic = irq_attr->ioapic; + if (!IO_APIC_IRQ(irq)) { + apic_printk(APIC_QUIET,KERN_ERR "IOAPIC[%d]: Invalid reference to IRQ 0\n", + ioapic); + return -EINVAL; + } + + if (dev) + node = dev_to_node(dev); + else + node = cpu_to_node(boot_cpu_id); + + desc = irq_to_desc_alloc_node(irq, node); + if (!desc) { + printk(KERN_INFO "can not get irq_desc %d\n", irq); + return 0; + } + + pin = irq_attr->ioapic_pin; + trigger = irq_attr->trigger; + polarity = irq_attr->polarity; + + /* + * IRQs < 16 are already in the irq_2_pin[] map + */ + if (irq >= NR_IRQS_LEGACY) { + cfg = desc->chip_data; + add_pin_to_irq_node(cfg, node, ioapic, pin); + } + + setup_IO_APIC_irq(ioapic, pin, irq, desc, trigger, polarity); + + return 0; +} + +int io_apic_set_pci_routing(struct device *dev, int irq, + struct io_apic_irq_attr *irq_attr) +{ + int ioapic, pin; + /* + * Avoid pin reprogramming. PRTs typically include entries + * with redundant pin->gsi mappings (but unique PCI devices); + * we only program the IOAPIC on the first. + */ + ioapic = irq_attr->ioapic; + pin = irq_attr->ioapic_pin; + if (test_bit(pin, mp_ioapic_routing[ioapic].pin_programmed)) { + pr_debug("Pin %d-%d already programmed\n", + mp_ioapics[ioapic].apicid, pin); + return 0; + } + set_bit(pin, mp_ioapic_routing[ioapic].pin_programmed); + + return __io_apic_set_pci_routing(dev, irq, irq_attr); +} + /* -------------------------------------------------------------------------- ACPI-based IOAPIC Configuration -------------------------------------------------------------------------- */ @@ -3980,6 +4024,7 @@ int __init io_apic_get_unique_id(int ioapic, int apic_id) return apic_id; } +#endif int __init io_apic_get_version(int ioapic) { @@ -3992,39 +4037,6 @@ int __init io_apic_get_version(int ioapic) return reg_01.bits.version; } -#endif - -int io_apic_set_pci_routing (int ioapic, int pin, int irq, int triggering, int polarity) -{ - struct irq_desc *desc; - struct irq_cfg *cfg; - int cpu = boot_cpu_id; - - if (!IO_APIC_IRQ(irq)) { - apic_printk(APIC_QUIET,KERN_ERR "IOAPIC[%d]: Invalid reference to IRQ 0\n", - ioapic); - return -EINVAL; - } - - desc = irq_to_desc_alloc_cpu(irq, cpu); - if (!desc) { - printk(KERN_INFO "can not get irq_desc %d\n", irq); - return 0; - } - - /* - * IRQs < 16 are already in the irq_2_pin[] map - */ - if (irq >= NR_IRQS_LEGACY) { - cfg = desc->chip_data; - add_pin_to_irq_cpu(cfg, cpu, ioapic, pin); - } - - setup_IO_APIC_irq(ioapic, pin, irq, desc, triggering, polarity); - - return 0; -} - int acpi_get_override_irq(int bus_irq, int *trigger, int *polarity) { @@ -4055,51 +4067,44 @@ int acpi_get_override_irq(int bus_irq, int *trigger, int *polarity) #ifdef CONFIG_SMP void __init setup_ioapic_dest(void) { - int pin, ioapic, irq, irq_entry; + int pin, ioapic = 0, irq, irq_entry; struct irq_desc *desc; - struct irq_cfg *cfg; const struct cpumask *mask; if (skip_ioapic_setup == 1) return; - for (ioapic = 0; ioapic < nr_ioapics; ioapic++) { - for (pin = 0; pin < nr_ioapic_registers[ioapic]; pin++) { - irq_entry = find_irq_entry(ioapic, pin, mp_INT); - if (irq_entry == -1) - continue; - irq = pin_2_irq(irq_entry, ioapic, pin); - - /* setup_IO_APIC_irqs could fail to get vector for some device - * when you have too many devices, because at that time only boot - * cpu is online. - */ - desc = irq_to_desc(irq); - cfg = desc->chip_data; - if (!cfg->vector) { - setup_IO_APIC_irq(ioapic, pin, irq, desc, - irq_trigger(irq_entry), - irq_polarity(irq_entry)); - continue; - - } - - /* - * Honour affinities which have been set in early boot - */ - if (desc->status & - (IRQ_NO_BALANCING | IRQ_AFFINITY_SET)) - mask = desc->affinity; - else - mask = apic->target_cpus(); - - if (intr_remapping_enabled) - set_ir_ioapic_affinity_irq_desc(desc, mask); - else - set_ioapic_affinity_irq_desc(desc, mask); - } - +#ifdef CONFIG_ACPI + if (!acpi_disabled && acpi_ioapic) { + ioapic = mp_find_ioapic(0); + if (ioapic < 0) + ioapic = 0; } +#endif + + for (pin = 0; pin < nr_ioapic_registers[ioapic]; pin++) { + irq_entry = find_irq_entry(ioapic, pin, mp_INT); + if (irq_entry == -1) + continue; + irq = pin_2_irq(irq_entry, ioapic, pin); + + desc = irq_to_desc(irq); + + /* + * Honour affinities which have been set in early boot + */ + if (desc->status & + (IRQ_NO_BALANCING | IRQ_AFFINITY_SET)) + mask = desc->affinity; + else + mask = apic->target_cpus(); + + if (intr_remapping_enabled) + set_ir_ioapic_affinity_irq_desc(desc, mask); + else + set_ioapic_affinity_irq_desc(desc, mask); + } + } #endif diff --git a/arch/x86/kernel/apic/nmi.c b/arch/x86/kernel/apic/nmi.c index ce4fbfa315a1..b3025b43b63a 100644 --- a/arch/x86/kernel/apic/nmi.c +++ b/arch/x86/kernel/apic/nmi.c @@ -66,7 +66,7 @@ static inline unsigned int get_nmi_count(int cpu) static inline int mce_in_progress(void) { -#if defined(CONFIG_X86_64) && defined(CONFIG_X86_MCE) +#if defined(CONFIG_X86_NEW_MCE) return atomic_read(&mce_entry) > 0; #endif return 0; @@ -104,7 +104,7 @@ static __init void nmi_cpu_busy(void *data) } #endif -static void report_broken_nmi(int cpu, int *prev_nmi_count) +static void report_broken_nmi(int cpu, unsigned int *prev_nmi_count) { printk(KERN_CONT "\n"); diff --git a/arch/x86/kernel/apic/probe_32.c b/arch/x86/kernel/apic/probe_32.c index 01eda2ac65e4..0c0182cc947d 100644 --- a/arch/x86/kernel/apic/probe_32.c +++ b/arch/x86/kernel/apic/probe_32.c @@ -20,23 +20,12 @@ #include #include -#include -#include -#include -#include -#include -#include -#include #include -#include #include -#include -#include #include #include #include -#include #ifdef CONFIG_HOTPLUG_CPU #define DEFAULT_SEND_IPI (1) @@ -160,7 +149,6 @@ extern struct apic apic_summit; extern struct apic apic_bigsmp; extern struct apic apic_es7000; extern struct apic apic_es7000_cluster; -extern struct apic apic_default; struct apic *apic = &apic_default; EXPORT_SYMBOL_GPL(apic); diff --git a/arch/x86/kernel/apic/probe_64.c b/arch/x86/kernel/apic/probe_64.c index 1783652bb0e5..bc3e880f9b82 100644 --- a/arch/x86/kernel/apic/probe_64.c +++ b/arch/x86/kernel/apic/probe_64.c @@ -50,7 +50,7 @@ static struct apic *apic_probe[] __initdata = { void __init default_setup_apic_routing(void) { #ifdef CONFIG_X86_X2APIC - if (x2apic && (apic != &apic_x2apic_phys && + if (x2apic_mode && (apic != &apic_x2apic_phys && #ifdef CONFIG_X86_UV apic != &apic_x2apic_uv_x && #endif diff --git a/arch/x86/kernel/apic/summit_32.c b/arch/x86/kernel/apic/summit_32.c index 9cfe1f415d81..eafdfbd1ea95 100644 --- a/arch/x86/kernel/apic/summit_32.c +++ b/arch/x86/kernel/apic/summit_32.c @@ -44,7 +44,6 @@ #include #include #include -#include #include #include @@ -173,13 +172,6 @@ static inline int is_WPEG(struct rio_detail *rio){ rio->type == LookOutAWPEG || rio->type == LookOutBWPEG); } - -/* In clustered mode, the high nibble of APIC ID is a cluster number. - * The low nibble is a 4-bit bitmap. */ -#define XAPIC_DEST_CPUS_SHIFT 4 -#define XAPIC_DEST_CPUS_MASK ((1u << XAPIC_DEST_CPUS_SHIFT) - 1) -#define XAPIC_DEST_CLUSTER_MASK (XAPIC_DEST_CPUS_MASK << XAPIC_DEST_CPUS_SHIFT) - #define SUMMIT_APIC_DFR_VALUE (APIC_DFR_CLUSTER) static const struct cpumask *summit_target_cpus(void) diff --git a/arch/x86/kernel/apic/x2apic_cluster.c b/arch/x86/kernel/apic/x2apic_cluster.c index 4a903e2f0d17..8e4cbb255c38 100644 --- a/arch/x86/kernel/apic/x2apic_cluster.c +++ b/arch/x86/kernel/apic/x2apic_cluster.c @@ -10,7 +10,7 @@ #include #include -DEFINE_PER_CPU(u32, x86_cpu_to_logical_apicid); +static DEFINE_PER_CPU(u32, x86_cpu_to_logical_apicid); static int x2apic_acpi_madt_oem_check(char *oem_id, char *oem_table_id) { diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c index 2bda69352976..096d19aea2f7 100644 --- a/arch/x86/kernel/apic/x2apic_uv_x.c +++ b/arch/x86/kernel/apic/x2apic_uv_x.c @@ -105,7 +105,7 @@ static void uv_vector_allocation_domain(int cpu, struct cpumask *retmask) cpumask_set_cpu(cpu, retmask); } -static int uv_wakeup_secondary(int phys_apicid, unsigned long start_rip) +static int __cpuinit uv_wakeup_secondary(int phys_apicid, unsigned long start_rip) { #ifdef CONFIG_SMP unsigned long val; @@ -463,7 +463,7 @@ static void uv_heartbeat(unsigned long ignored) uv_set_scir_bits(bits); /* enable next timer period */ - mod_timer(timer, jiffies + SCIR_CPU_HB_INTERVAL); + mod_timer_pinned(timer, jiffies + SCIR_CPU_HB_INTERVAL); } static void __cpuinit uv_heartbeat_enable(int cpu) @@ -562,7 +562,7 @@ void __init uv_system_init(void) union uvh_node_id_u node_id; unsigned long gnode_upper, lowmem_redir_base, lowmem_redir_size; int bytes, nid, cpu, lcpu, pnode, blade, i, j, m_val, n_val; - int max_pnode = 0; + int gnode_extra, max_pnode = 0; unsigned long mmr_base, present, paddr; unsigned short pnode_mask; @@ -574,6 +574,13 @@ void __init uv_system_init(void) mmr_base = uv_read_local_mmr(UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR) & ~UV_MMR_ENABLE; + pnode_mask = (1 << n_val) - 1; + node_id.v = uv_read_local_mmr(UVH_NODE_ID); + gnode_extra = (node_id.s.node_id & ~((1 << n_val) - 1)) >> 1; + gnode_upper = ((unsigned long)gnode_extra << m_val); + printk(KERN_DEBUG "UV: N %d, M %d, gnode_upper 0x%lx, gnode_extra 0x%x\n", + n_val, m_val, gnode_upper, gnode_extra); + printk(KERN_DEBUG "UV: global MMR base 0x%lx\n", mmr_base); for(i = 0; i < UVH_NODE_PRESENT_TABLE_DEPTH; i++) @@ -583,15 +590,18 @@ void __init uv_system_init(void) bytes = sizeof(struct uv_blade_info) * uv_num_possible_blades(); uv_blade_info = kmalloc(bytes, GFP_KERNEL); + BUG_ON(!uv_blade_info); get_lowmem_redirect(&lowmem_redir_base, &lowmem_redir_size); bytes = sizeof(uv_node_to_blade[0]) * num_possible_nodes(); uv_node_to_blade = kmalloc(bytes, GFP_KERNEL); + BUG_ON(!uv_node_to_blade); memset(uv_node_to_blade, 255, bytes); bytes = sizeof(uv_cpu_to_blade[0]) * num_possible_cpus(); uv_cpu_to_blade = kmalloc(bytes, GFP_KERNEL); + BUG_ON(!uv_cpu_to_blade); memset(uv_cpu_to_blade, 255, bytes); blade = 0; @@ -607,11 +617,6 @@ void __init uv_system_init(void) } } - pnode_mask = (1 << n_val) - 1; - node_id.v = uv_read_local_mmr(UVH_NODE_ID); - gnode_upper = (((unsigned long)node_id.s.node_id) & - ~((1 << n_val) - 1)) << m_val; - uv_bios_init(); uv_bios_get_sn_info(0, &uv_type, &sn_partition_id, &sn_coherency_id, &sn_region_size); @@ -634,6 +639,7 @@ void __init uv_system_init(void) uv_cpu_hub_info(cpu)->pnode_mask = pnode_mask; uv_cpu_hub_info(cpu)->gpa_mask = (1 << (m_val + n_val)) - 1; uv_cpu_hub_info(cpu)->gnode_upper = gnode_upper; + uv_cpu_hub_info(cpu)->gnode_extra = gnode_extra; uv_cpu_hub_info(cpu)->global_mmr_base = mmr_base; uv_cpu_hub_info(cpu)->coherency_domain_number = sn_coherency_id; uv_cpu_hub_info(cpu)->scir.offset = SCIR_LOCAL_MMR_BASE + lcpu; diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c index 49e0939bac42..79302e9a33a4 100644 --- a/arch/x86/kernel/apm_32.c +++ b/arch/x86/kernel/apm_32.c @@ -1233,9 +1233,9 @@ static int suspend(int vetoable) int err; struct apm_user *as; - device_suspend(PMSG_SUSPEND); + dpm_suspend_start(PMSG_SUSPEND); - device_power_down(PMSG_SUSPEND); + dpm_suspend_noirq(PMSG_SUSPEND); local_irq_disable(); sysdev_suspend(PMSG_SUSPEND); @@ -1259,9 +1259,9 @@ static int suspend(int vetoable) sysdev_resume(); local_irq_enable(); - device_power_up(PMSG_RESUME); + dpm_resume_noirq(PMSG_RESUME); - device_resume(PMSG_RESUME); + dpm_resume_end(PMSG_RESUME); queue_event(APM_NORMAL_RESUME, NULL); spin_lock(&user_list_lock); for (as = user_list; as != NULL; as = as->next) { @@ -1277,7 +1277,7 @@ static void standby(void) { int err; - device_power_down(PMSG_SUSPEND); + dpm_suspend_noirq(PMSG_SUSPEND); local_irq_disable(); sysdev_suspend(PMSG_SUSPEND); @@ -1291,7 +1291,7 @@ static void standby(void) sysdev_resume(); local_irq_enable(); - device_power_up(PMSG_RESUME); + dpm_resume_noirq(PMSG_RESUME); } static apm_event_t get_event(void) @@ -1376,7 +1376,7 @@ static void check_events(void) ignore_bounce = 1; if ((event != APM_NORMAL_RESUME) || (ignore_normal_resume == 0)) { - device_resume(PMSG_RESUME); + dpm_resume_end(PMSG_RESUME); queue_event(event, NULL); } ignore_normal_resume = 0; diff --git a/arch/x86/kernel/asm-offsets_32.c b/arch/x86/kernel/asm-offsets_32.c index 5a6aa1c1162f..dfdbf6403895 100644 --- a/arch/x86/kernel/asm-offsets_32.c +++ b/arch/x86/kernel/asm-offsets_32.c @@ -126,6 +126,7 @@ void foo(void) #if defined(CONFIG_LGUEST) || defined(CONFIG_LGUEST_GUEST) || defined(CONFIG_LGUEST_MODULE) BLANK(); OFFSET(LGUEST_DATA_irq_enabled, lguest_data, irq_enabled); + OFFSET(LGUEST_DATA_irq_pending, lguest_data, irq_pending); OFFSET(LGUEST_DATA_pgdir, lguest_data, pgdir); BLANK(); @@ -146,4 +147,5 @@ void foo(void) OFFSET(BP_loadflags, boot_params, hdr.loadflags); OFFSET(BP_hardware_subarch, boot_params, hdr.hardware_subarch); OFFSET(BP_version, boot_params, hdr.version); + OFFSET(BP_kernel_alignment, boot_params, hdr.kernel_alignment); } diff --git a/arch/x86/kernel/asm-offsets_64.c b/arch/x86/kernel/asm-offsets_64.c index e72f062fb4b5..898ecc47e129 100644 --- a/arch/x86/kernel/asm-offsets_64.c +++ b/arch/x86/kernel/asm-offsets_64.c @@ -125,6 +125,7 @@ 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); + OFFSET(BP_kernel_alignment, boot_params, hdr.kernel_alignment); BLANK(); DEFINE(PAGE_SIZE_asm, PAGE_SIZE); diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile index 4e242f9a06e4..3efcb2b96a15 100644 --- a/arch/x86/kernel/cpu/Makefile +++ b/arch/x86/kernel/cpu/Makefile @@ -1,5 +1,5 @@ # -# Makefile for x86-compatible CPU details and quirks +# Makefile for x86-compatible CPU details, features and quirks # # Don't trace early stages of a secondary CPU boot @@ -23,11 +23,13 @@ obj-$(CONFIG_CPU_SUP_CENTAUR) += centaur.o obj-$(CONFIG_CPU_SUP_TRANSMETA_32) += transmeta.o obj-$(CONFIG_CPU_SUP_UMC_32) += umc.o -obj-$(CONFIG_X86_MCE) += mcheck/ -obj-$(CONFIG_MTRR) += mtrr/ -obj-$(CONFIG_CPU_FREQ) += cpufreq/ +obj-$(CONFIG_PERF_COUNTERS) += perf_counter.o -obj-$(CONFIG_X86_LOCAL_APIC) += perfctr-watchdog.o +obj-$(CONFIG_X86_MCE) += mcheck/ +obj-$(CONFIG_MTRR) += mtrr/ +obj-$(CONFIG_CPU_FREQ) += cpufreq/ + +obj-$(CONFIG_X86_LOCAL_APIC) += perfctr-watchdog.o quiet_cmd_mkcapflags = MKCAP $@ cmd_mkcapflags = $(PERL) $(srctree)/$(src)/mkcapflags.pl $< $@ diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 7e4a459daa64..e5b27d8f1b47 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -6,6 +6,7 @@ #include #include #include +#include #ifdef CONFIG_X86_64 # include @@ -272,7 +273,7 @@ static void __cpuinit srat_detect_node(struct cpuinfo_x86 *c) #if defined(CONFIG_NUMA) && defined(CONFIG_X86_64) int cpu = smp_processor_id(); int node; - unsigned apicid = hard_smp_processor_id(); + unsigned apicid = cpu_has_apic ? hard_smp_processor_id() : c->apicid; node = c->phys_proc_id; if (apicid_to_node[apicid] != NUMA_NO_NODE) @@ -351,6 +352,15 @@ static void __cpuinit early_init_amd(struct cpuinfo_x86 *c) (c->x86_model == 8 && c->x86_mask >= 8)) set_cpu_cap(c, X86_FEATURE_K6_MTRR); #endif +#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_PCI) + /* check CPU config space for extended APIC ID */ + if (c->x86 >= 0xf) { + unsigned int val; + val = read_pci_config(0, 24, 0, 0x68); + if ((val & ((1 << 17) | (1 << 18))) == ((1 << 17) | (1 << 18))) + set_cpu_cap(c, X86_FEATURE_EXTD_APICID); + } +#endif } static void __cpuinit init_amd(struct cpuinfo_x86 *c) diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 77848d9fca68..6b26d4deada0 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -107,7 +108,7 @@ DEFINE_PER_CPU_PAGE_ALIGNED(struct gdt_page, gdt_page) = { .gdt = { /* data */ [GDT_ENTRY_APMBIOS_BASE+2] = { { { 0x0000ffff, 0x00409200 } } }, - [GDT_ENTRY_ESPFIX_SS] = { { { 0x00000000, 0x00c09200 } } }, + [GDT_ENTRY_ESPFIX_SS] = { { { 0x0000ffff, 0x00cf9200 } } }, [GDT_ENTRY_PERCPU] = { { { 0x0000ffff, 0x00cf9200 } } }, GDT_STACK_CANARY_INIT #endif @@ -299,7 +300,8 @@ static const char *__cpuinit table_lookup_model(struct cpuinfo_x86 *c) return NULL; /* Not found */ } -__u32 cleared_cpu_caps[NCAPINTS] __cpuinitdata; +__u32 cpu_caps_cleared[NCAPINTS] __cpuinitdata; +__u32 cpu_caps_set[NCAPINTS] __cpuinitdata; void load_percpu_segment(int cpu) { @@ -485,7 +487,6 @@ out: static void __cpuinit get_cpu_vendor(struct cpuinfo_x86 *c) { char *v = c->x86_vendor_id; - static int printed; int i; for (i = 0; i < X86_VENDOR_NUM; i++) { @@ -502,13 +503,9 @@ static void __cpuinit get_cpu_vendor(struct cpuinfo_x86 *c) } } - if (!printed) { - printed++; - printk(KERN_ERR - "CPU: vendor_id '%s' unknown, using generic init.\n", v); - - printk(KERN_ERR "CPU: Your system may be unstable.\n"); - } + printk_once(KERN_ERR + "CPU: vendor_id '%s' unknown, using generic init.\n" \ + "CPU: Your system may be unstable.\n", v); c->x86_vendor = X86_VENDOR_UNKNOWN; this_cpu = &default_cpu; @@ -768,6 +765,12 @@ static void __cpuinit identify_cpu(struct cpuinfo_x86 *c) if (this_cpu->c_identify) this_cpu->c_identify(c); + /* Clear/Set all flags overriden by options, after probe */ + for (i = 0; i < NCAPINTS; i++) { + c->x86_capability[i] &= ~cpu_caps_cleared[i]; + c->x86_capability[i] |= cpu_caps_set[i]; + } + #ifdef CONFIG_X86_64 c->apicid = apic->phys_pkg_id(c->initial_apicid, 0); #endif @@ -813,6 +816,16 @@ static void __cpuinit identify_cpu(struct cpuinfo_x86 *c) #endif init_hypervisor(c); + + /* + * Clear/Set all flags overriden by options, need do it + * before following smp all cpus cap AND. + */ + for (i = 0; i < NCAPINTS; i++) { + c->x86_capability[i] &= ~cpu_caps_cleared[i]; + c->x86_capability[i] |= cpu_caps_set[i]; + } + /* * On SMP, boot_cpu_data holds the common feature set between * all CPUs; so make sure that we indicate which features are @@ -825,10 +838,6 @@ static void __cpuinit identify_cpu(struct cpuinfo_x86 *c) boot_cpu_data.x86_capability[i] &= c->x86_capability[i]; } - /* Clear all flags overriden by options */ - for (i = 0; i < NCAPINTS; i++) - c->x86_capability[i] &= ~cleared_cpu_caps[i]; - #ifdef CONFIG_X86_MCE /* Init Machine Check Exception if available. */ mcheck_init(c); @@ -839,6 +848,9 @@ static void __cpuinit identify_cpu(struct cpuinfo_x86 *c) #if defined(CONFIG_NUMA) && defined(CONFIG_X86_64) numa_add_cpu(smp_processor_id()); #endif + + /* Cap the iomem address space to what is addressable on all CPUs */ + iomem_resource.end &= (1ULL << c->x86_phys_bits) - 1; } #ifdef CONFIG_X86_64 @@ -861,6 +873,7 @@ void __init identify_boot_cpu(void) #else vgetcpu_set_mode(); #endif + init_hw_perf_counters(); } void __cpuinit identify_secondary_cpu(struct cpuinfo_x86 *c) diff --git a/arch/x86/kernel/cpu/cpu_debug.c b/arch/x86/kernel/cpu/cpu_debug.c index 46e29ab96c6a..6b2a52dd0403 100644 --- a/arch/x86/kernel/cpu/cpu_debug.c +++ b/arch/x86/kernel/cpu/cpu_debug.c @@ -32,9 +32,7 @@ static DEFINE_PER_CPU(struct cpu_cpuX_base, cpu_arr[CPU_REG_ALL_BIT]); static DEFINE_PER_CPU(struct cpu_private *, priv_arr[MAX_CPU_FILES]); -static DEFINE_PER_CPU(unsigned, cpu_modelflag); static DEFINE_PER_CPU(int, cpu_priv_count); -static DEFINE_PER_CPU(unsigned, cpu_model); static DEFINE_MUTEX(cpu_debug_lock); @@ -80,302 +78,102 @@ static struct cpu_file_base cpu_file[] = { { "value", CPU_REG_ALL, 1 }, }; -/* Intel Registers Range */ -static struct cpu_debug_range cpu_intel_range[] = { - { 0x00000000, 0x00000001, CPU_MC, CPU_INTEL_ALL }, - { 0x00000006, 0x00000007, CPU_MONITOR, CPU_CX_AT_XE }, - { 0x00000010, 0x00000010, CPU_TIME, CPU_INTEL_ALL }, - { 0x00000011, 0x00000013, CPU_PMC, CPU_INTEL_PENTIUM }, - { 0x00000017, 0x00000017, CPU_PLATFORM, CPU_PX_CX_AT_XE }, - { 0x0000001B, 0x0000001B, CPU_APIC, CPU_P6_CX_AT_XE }, +/* CPU Registers Range */ +static struct cpu_debug_range cpu_reg_range[] = { + { 0x00000000, 0x00000001, CPU_MC, }, + { 0x00000006, 0x00000007, CPU_MONITOR, }, + { 0x00000010, 0x00000010, CPU_TIME, }, + { 0x00000011, 0x00000013, CPU_PMC, }, + { 0x00000017, 0x00000017, CPU_PLATFORM, }, + { 0x0000001B, 0x0000001B, CPU_APIC, }, + { 0x0000002A, 0x0000002B, CPU_POWERON, }, + { 0x0000002C, 0x0000002C, CPU_FREQ, }, + { 0x0000003A, 0x0000003A, CPU_CONTROL, }, + { 0x00000040, 0x00000047, CPU_LBRANCH, }, + { 0x00000060, 0x00000067, CPU_LBRANCH, }, + { 0x00000079, 0x00000079, CPU_BIOS, }, + { 0x00000088, 0x0000008A, CPU_CACHE, }, + { 0x0000008B, 0x0000008B, CPU_BIOS, }, + { 0x0000009B, 0x0000009B, CPU_MONITOR, }, + { 0x000000C1, 0x000000C4, CPU_PMC, }, + { 0x000000CD, 0x000000CD, CPU_FREQ, }, + { 0x000000E7, 0x000000E8, CPU_PERF, }, + { 0x000000FE, 0x000000FE, CPU_MTRR, }, - { 0x0000002A, 0x0000002A, CPU_POWERON, CPU_PX_CX_AT_XE }, - { 0x0000002B, 0x0000002B, CPU_POWERON, CPU_INTEL_XEON }, - { 0x0000002C, 0x0000002C, CPU_FREQ, CPU_INTEL_XEON }, - { 0x0000003A, 0x0000003A, CPU_CONTROL, CPU_CX_AT_XE }, + { 0x00000116, 0x0000011E, CPU_CACHE, }, + { 0x00000174, 0x00000176, CPU_SYSENTER, }, + { 0x00000179, 0x0000017B, CPU_MC, }, + { 0x00000186, 0x00000189, CPU_PMC, }, + { 0x00000198, 0x00000199, CPU_PERF, }, + { 0x0000019A, 0x0000019A, CPU_TIME, }, + { 0x0000019B, 0x0000019D, CPU_THERM, }, + { 0x000001A0, 0x000001A0, CPU_MISC, }, + { 0x000001C9, 0x000001C9, CPU_LBRANCH, }, + { 0x000001D7, 0x000001D8, CPU_LBRANCH, }, + { 0x000001D9, 0x000001D9, CPU_DEBUG, }, + { 0x000001DA, 0x000001E0, CPU_LBRANCH, }, - { 0x00000040, 0x00000043, CPU_LBRANCH, CPU_PM_CX_AT_XE }, - { 0x00000044, 0x00000047, CPU_LBRANCH, CPU_PM_CO_AT }, - { 0x00000060, 0x00000063, CPU_LBRANCH, CPU_C2_AT }, - { 0x00000064, 0x00000067, CPU_LBRANCH, CPU_INTEL_ATOM }, + { 0x00000200, 0x0000020F, CPU_MTRR, }, + { 0x00000250, 0x00000250, CPU_MTRR, }, + { 0x00000258, 0x00000259, CPU_MTRR, }, + { 0x00000268, 0x0000026F, CPU_MTRR, }, + { 0x00000277, 0x00000277, CPU_PAT, }, + { 0x000002FF, 0x000002FF, CPU_MTRR, }, - { 0x00000079, 0x00000079, CPU_BIOS, CPU_P6_CX_AT_XE }, - { 0x00000088, 0x0000008A, CPU_CACHE, CPU_INTEL_P6 }, - { 0x0000008B, 0x0000008B, CPU_BIOS, CPU_P6_CX_AT_XE }, - { 0x0000009B, 0x0000009B, CPU_MONITOR, CPU_INTEL_XEON }, + { 0x00000300, 0x00000311, CPU_PMC, }, + { 0x00000345, 0x00000345, CPU_PMC, }, + { 0x00000360, 0x00000371, CPU_PMC, }, + { 0x0000038D, 0x00000390, CPU_PMC, }, + { 0x000003A0, 0x000003BE, CPU_PMC, }, + { 0x000003C0, 0x000003CD, CPU_PMC, }, + { 0x000003E0, 0x000003E1, CPU_PMC, }, + { 0x000003F0, 0x000003F2, CPU_PMC, }, - { 0x000000C1, 0x000000C2, CPU_PMC, CPU_P6_CX_AT }, - { 0x000000CD, 0x000000CD, CPU_FREQ, CPU_CX_AT }, - { 0x000000E7, 0x000000E8, CPU_PERF, CPU_CX_AT }, - { 0x000000FE, 0x000000FE, CPU_MTRR, CPU_P6_CX_XE }, + { 0x00000400, 0x00000417, CPU_MC, }, + { 0x00000480, 0x0000048B, CPU_VMX, }, - { 0x00000116, 0x00000116, CPU_CACHE, CPU_INTEL_P6 }, - { 0x00000118, 0x00000118, CPU_CACHE, CPU_INTEL_P6 }, - { 0x00000119, 0x00000119, CPU_CACHE, CPU_INTEL_PX }, - { 0x0000011A, 0x0000011B, CPU_CACHE, CPU_INTEL_P6 }, - { 0x0000011E, 0x0000011E, CPU_CACHE, CPU_PX_CX_AT }, + { 0x00000600, 0x00000600, CPU_DEBUG, }, + { 0x00000680, 0x0000068F, CPU_LBRANCH, }, + { 0x000006C0, 0x000006CF, CPU_LBRANCH, }, - { 0x00000174, 0x00000176, CPU_SYSENTER, CPU_P6_CX_AT_XE }, - { 0x00000179, 0x0000017A, CPU_MC, CPU_PX_CX_AT_XE }, - { 0x0000017B, 0x0000017B, CPU_MC, CPU_P6_XE }, - { 0x00000186, 0x00000187, CPU_PMC, CPU_P6_CX_AT }, - { 0x00000198, 0x00000199, CPU_PERF, CPU_PM_CX_AT_XE }, - { 0x0000019A, 0x0000019A, CPU_TIME, CPU_PM_CX_AT_XE }, - { 0x0000019B, 0x0000019D, CPU_THERM, CPU_PM_CX_AT_XE }, - { 0x000001A0, 0x000001A0, CPU_MISC, CPU_PM_CX_AT_XE }, + { 0x000107CC, 0x000107D3, CPU_PMC, }, - { 0x000001C9, 0x000001C9, CPU_LBRANCH, CPU_PM_CX_AT }, - { 0x000001D7, 0x000001D8, CPU_LBRANCH, CPU_INTEL_XEON }, - { 0x000001D9, 0x000001D9, CPU_DEBUG, CPU_CX_AT_XE }, - { 0x000001DA, 0x000001DA, CPU_LBRANCH, CPU_INTEL_XEON }, - { 0x000001DB, 0x000001DB, CPU_LBRANCH, CPU_P6_XE }, - { 0x000001DC, 0x000001DC, CPU_LBRANCH, CPU_INTEL_P6 }, - { 0x000001DD, 0x000001DE, CPU_LBRANCH, CPU_PX_CX_AT_XE }, - { 0x000001E0, 0x000001E0, CPU_LBRANCH, CPU_INTEL_P6 }, + { 0xC0000080, 0xC0000080, CPU_FEATURES, }, + { 0xC0000081, 0xC0000084, CPU_CALL, }, + { 0xC0000100, 0xC0000102, CPU_BASE, }, + { 0xC0000103, 0xC0000103, CPU_TIME, }, - { 0x00000200, 0x0000020F, CPU_MTRR, CPU_P6_CX_XE }, - { 0x00000250, 0x00000250, CPU_MTRR, CPU_P6_CX_XE }, - { 0x00000258, 0x00000259, CPU_MTRR, CPU_P6_CX_XE }, - { 0x00000268, 0x0000026F, CPU_MTRR, CPU_P6_CX_XE }, - { 0x00000277, 0x00000277, CPU_PAT, CPU_C2_AT_XE }, - { 0x000002FF, 0x000002FF, CPU_MTRR, CPU_P6_CX_XE }, - - { 0x00000300, 0x00000308, CPU_PMC, CPU_INTEL_XEON }, - { 0x00000309, 0x0000030B, CPU_PMC, CPU_C2_AT_XE }, - { 0x0000030C, 0x00000311, CPU_PMC, CPU_INTEL_XEON }, - { 0x00000345, 0x00000345, CPU_PMC, CPU_C2_AT }, - { 0x00000360, 0x00000371, CPU_PMC, CPU_INTEL_XEON }, - { 0x0000038D, 0x00000390, CPU_PMC, CPU_C2_AT }, - { 0x000003A0, 0x000003BE, CPU_PMC, CPU_INTEL_XEON }, - { 0x000003C0, 0x000003CD, CPU_PMC, CPU_INTEL_XEON }, - { 0x000003E0, 0x000003E1, CPU_PMC, CPU_INTEL_XEON }, - { 0x000003F0, 0x000003F0, CPU_PMC, CPU_INTEL_XEON }, - { 0x000003F1, 0x000003F1, CPU_PMC, CPU_C2_AT_XE }, - { 0x000003F2, 0x000003F2, CPU_PMC, CPU_INTEL_XEON }, - - { 0x00000400, 0x00000402, CPU_MC, CPU_PM_CX_AT_XE }, - { 0x00000403, 0x00000403, CPU_MC, CPU_INTEL_XEON }, - { 0x00000404, 0x00000406, CPU_MC, CPU_PM_CX_AT_XE }, - { 0x00000407, 0x00000407, CPU_MC, CPU_INTEL_XEON }, - { 0x00000408, 0x0000040A, CPU_MC, CPU_PM_CX_AT_XE }, - { 0x0000040B, 0x0000040B, CPU_MC, CPU_INTEL_XEON }, - { 0x0000040C, 0x0000040E, CPU_MC, CPU_PM_CX_XE }, - { 0x0000040F, 0x0000040F, CPU_MC, CPU_INTEL_XEON }, - { 0x00000410, 0x00000412, CPU_MC, CPU_PM_CX_AT_XE }, - { 0x00000413, 0x00000417, CPU_MC, CPU_CX_AT_XE }, - { 0x00000480, 0x0000048B, CPU_VMX, CPU_CX_AT_XE }, - - { 0x00000600, 0x00000600, CPU_DEBUG, CPU_PM_CX_AT_XE }, - { 0x00000680, 0x0000068F, CPU_LBRANCH, CPU_INTEL_XEON }, - { 0x000006C0, 0x000006CF, CPU_LBRANCH, CPU_INTEL_XEON }, - - { 0x000107CC, 0x000107D3, CPU_PMC, CPU_INTEL_XEON_MP }, - - { 0xC0000080, 0xC0000080, CPU_FEATURES, CPU_INTEL_XEON }, - { 0xC0000081, 0xC0000082, CPU_CALL, CPU_INTEL_XEON }, - { 0xC0000084, 0xC0000084, CPU_CALL, CPU_INTEL_XEON }, - { 0xC0000100, 0xC0000102, CPU_BASE, CPU_INTEL_XEON }, + { 0xC0010000, 0xC0010007, CPU_PMC, }, + { 0xC0010010, 0xC0010010, CPU_CONF, }, + { 0xC0010015, 0xC0010015, CPU_CONF, }, + { 0xC0010016, 0xC001001A, CPU_MTRR, }, + { 0xC001001D, 0xC001001D, CPU_MTRR, }, + { 0xC001001F, 0xC001001F, CPU_CONF, }, + { 0xC0010030, 0xC0010035, CPU_BIOS, }, + { 0xC0010044, 0xC0010048, CPU_MC, }, + { 0xC0010050, 0xC0010056, CPU_SMM, }, + { 0xC0010058, 0xC0010058, CPU_CONF, }, + { 0xC0010060, 0xC0010060, CPU_CACHE, }, + { 0xC0010061, 0xC0010068, CPU_SMM, }, + { 0xC0010069, 0xC001006B, CPU_SMM, }, + { 0xC0010070, 0xC0010071, CPU_SMM, }, + { 0xC0010111, 0xC0010113, CPU_SMM, }, + { 0xC0010114, 0xC0010118, CPU_SVM, }, + { 0xC0010140, 0xC0010141, CPU_OSVM, }, + { 0xC0011022, 0xC0011023, CPU_CONF, }, }; -/* AMD Registers Range */ -static struct cpu_debug_range cpu_amd_range[] = { - { 0x00000000, 0x00000001, CPU_MC, CPU_K10_PLUS, }, - { 0x00000010, 0x00000010, CPU_TIME, CPU_K8_PLUS, }, - { 0x0000001B, 0x0000001B, CPU_APIC, CPU_K8_PLUS, }, - { 0x0000002A, 0x0000002A, CPU_POWERON, CPU_K7_PLUS }, - { 0x0000008B, 0x0000008B, CPU_VER, CPU_K8_PLUS }, - { 0x000000FE, 0x000000FE, CPU_MTRR, CPU_K8_PLUS, }, - - { 0x00000174, 0x00000176, CPU_SYSENTER, CPU_K8_PLUS, }, - { 0x00000179, 0x0000017B, CPU_MC, CPU_K8_PLUS, }, - { 0x000001D9, 0x000001D9, CPU_DEBUG, CPU_K8_PLUS, }, - { 0x000001DB, 0x000001DE, CPU_LBRANCH, CPU_K8_PLUS, }, - - { 0x00000200, 0x0000020F, CPU_MTRR, CPU_K8_PLUS, }, - { 0x00000250, 0x00000250, CPU_MTRR, CPU_K8_PLUS, }, - { 0x00000258, 0x00000259, CPU_MTRR, CPU_K8_PLUS, }, - { 0x00000268, 0x0000026F, CPU_MTRR, CPU_K8_PLUS, }, - { 0x00000277, 0x00000277, CPU_PAT, CPU_K8_PLUS, }, - { 0x000002FF, 0x000002FF, CPU_MTRR, CPU_K8_PLUS, }, - - { 0x00000400, 0x00000413, CPU_MC, CPU_K8_PLUS, }, - - { 0xC0000080, 0xC0000080, CPU_FEATURES, CPU_AMD_ALL, }, - { 0xC0000081, 0xC0000084, CPU_CALL, CPU_K8_PLUS, }, - { 0xC0000100, 0xC0000102, CPU_BASE, CPU_K8_PLUS, }, - { 0xC0000103, 0xC0000103, CPU_TIME, CPU_K10_PLUS, }, - - { 0xC0010000, 0xC0010007, CPU_PMC, CPU_K8_PLUS, }, - { 0xC0010010, 0xC0010010, CPU_CONF, CPU_K7_PLUS, }, - { 0xC0010015, 0xC0010015, CPU_CONF, CPU_K7_PLUS, }, - { 0xC0010016, 0xC001001A, CPU_MTRR, CPU_K8_PLUS, }, - { 0xC001001D, 0xC001001D, CPU_MTRR, CPU_K8_PLUS, }, - { 0xC001001F, 0xC001001F, CPU_CONF, CPU_K8_PLUS, }, - { 0xC0010030, 0xC0010035, CPU_BIOS, CPU_K8_PLUS, }, - { 0xC0010044, 0xC0010048, CPU_MC, CPU_K8_PLUS, }, - { 0xC0010050, 0xC0010056, CPU_SMM, CPU_K0F_PLUS, }, - { 0xC0010058, 0xC0010058, CPU_CONF, CPU_K10_PLUS, }, - { 0xC0010060, 0xC0010060, CPU_CACHE, CPU_AMD_11, }, - { 0xC0010061, 0xC0010068, CPU_SMM, CPU_K10_PLUS, }, - { 0xC0010069, 0xC001006B, CPU_SMM, CPU_AMD_11, }, - { 0xC0010070, 0xC0010071, CPU_SMM, CPU_K10_PLUS, }, - { 0xC0010111, 0xC0010113, CPU_SMM, CPU_K8_PLUS, }, - { 0xC0010114, 0xC0010118, CPU_SVM, CPU_K10_PLUS, }, - { 0xC0010140, 0xC0010141, CPU_OSVM, CPU_K10_PLUS, }, - { 0xC0011022, 0xC0011023, CPU_CONF, CPU_K10_PLUS, }, -}; - - -/* Intel */ -static int get_intel_modelflag(unsigned model) -{ - int flag; - - switch (model) { - case 0x0501: - case 0x0502: - case 0x0504: - flag = CPU_INTEL_PENTIUM; - break; - case 0x0601: - case 0x0603: - case 0x0605: - case 0x0607: - case 0x0608: - case 0x060A: - case 0x060B: - flag = CPU_INTEL_P6; - break; - case 0x0609: - case 0x060D: - flag = CPU_INTEL_PENTIUM_M; - break; - case 0x060E: - flag = CPU_INTEL_CORE; - break; - case 0x060F: - case 0x0617: - flag = CPU_INTEL_CORE2; - break; - case 0x061C: - flag = CPU_INTEL_ATOM; - break; - case 0x0F00: - case 0x0F01: - case 0x0F02: - case 0x0F03: - case 0x0F04: - flag = CPU_INTEL_XEON_P4; - break; - case 0x0F06: - flag = CPU_INTEL_XEON_MP; - break; - default: - flag = CPU_NONE; - break; - } - - return flag; -} - -/* AMD */ -static int get_amd_modelflag(unsigned model) -{ - int flag; - - switch (model >> 8) { - case 0x6: - flag = CPU_AMD_K6; - break; - case 0x7: - flag = CPU_AMD_K7; - break; - case 0x8: - flag = CPU_AMD_K8; - break; - case 0xf: - flag = CPU_AMD_0F; - break; - case 0x10: - flag = CPU_AMD_10; - break; - case 0x11: - flag = CPU_AMD_11; - break; - default: - flag = CPU_NONE; - break; - } - - return flag; -} - -static int get_cpu_modelflag(unsigned cpu) -{ - int flag; - - flag = per_cpu(cpu_model, cpu); - - switch (flag >> 16) { - case X86_VENDOR_INTEL: - flag = get_intel_modelflag(flag); - break; - case X86_VENDOR_AMD: - flag = get_amd_modelflag(flag & 0xffff); - break; - default: - flag = CPU_NONE; - break; - } - - return flag; -} - -static int get_cpu_range_count(unsigned cpu) -{ - int index; - - switch (per_cpu(cpu_model, cpu) >> 16) { - case X86_VENDOR_INTEL: - index = ARRAY_SIZE(cpu_intel_range); - break; - case X86_VENDOR_AMD: - index = ARRAY_SIZE(cpu_amd_range); - break; - default: - index = 0; - break; - } - - return index; -} - static int is_typeflag_valid(unsigned cpu, unsigned flag) { - unsigned vendor, modelflag; - int i, index; + int i; /* Standard Registers should be always valid */ if (flag >= CPU_TSS) return 1; - modelflag = per_cpu(cpu_modelflag, cpu); - vendor = per_cpu(cpu_model, cpu) >> 16; - index = get_cpu_range_count(cpu); - - for (i = 0; i < index; i++) { - switch (vendor) { - case X86_VENDOR_INTEL: - if ((cpu_intel_range[i].model & modelflag) && - (cpu_intel_range[i].flag & flag)) - return 1; - break; - case X86_VENDOR_AMD: - if ((cpu_amd_range[i].model & modelflag) && - (cpu_amd_range[i].flag & flag)) - return 1; - break; - } + for (i = 0; i < ARRAY_SIZE(cpu_reg_range); i++) { + if (cpu_reg_range[i].flag == flag) + return 1; } /* Invalid */ @@ -385,26 +183,11 @@ static int is_typeflag_valid(unsigned cpu, unsigned flag) static unsigned get_cpu_range(unsigned cpu, unsigned *min, unsigned *max, int index, unsigned flag) { - unsigned modelflag; - - modelflag = per_cpu(cpu_modelflag, cpu); - *max = 0; - switch (per_cpu(cpu_model, cpu) >> 16) { - case X86_VENDOR_INTEL: - if ((cpu_intel_range[index].model & modelflag) && - (cpu_intel_range[index].flag & flag)) { - *min = cpu_intel_range[index].min; - *max = cpu_intel_range[index].max; - } - break; - case X86_VENDOR_AMD: - if ((cpu_amd_range[index].model & modelflag) && - (cpu_amd_range[index].flag & flag)) { - *min = cpu_amd_range[index].min; - *max = cpu_amd_range[index].max; - } - break; - } + if (cpu_reg_range[index].flag == flag) { + *min = cpu_reg_range[index].min; + *max = cpu_reg_range[index].max; + } else + *max = 0; return *max; } @@ -434,7 +217,7 @@ static void print_msr(struct seq_file *seq, unsigned cpu, unsigned flag) unsigned msr, msr_min, msr_max; struct cpu_private *priv; u32 low, high; - int i, range; + int i; if (seq) { priv = seq->private; @@ -446,9 +229,7 @@ static void print_msr(struct seq_file *seq, unsigned cpu, unsigned flag) } } - range = get_cpu_range_count(cpu); - - for (i = 0; i < range; i++) { + for (i = 0; i < ARRAY_SIZE(cpu_reg_range); i++) { if (!get_cpu_range(cpu, &msr_min, &msr_max, i, flag)) continue; @@ -588,8 +369,20 @@ static void print_apic(void *arg) seq_printf(seq, " TMICT\t\t: %08x\n", apic_read(APIC_TMICT)); seq_printf(seq, " TMCCT\t\t: %08x\n", apic_read(APIC_TMCCT)); seq_printf(seq, " TDCR\t\t: %08x\n", apic_read(APIC_TDCR)); -#endif /* CONFIG_X86_LOCAL_APIC */ + if (boot_cpu_has(X86_FEATURE_EXTAPIC)) { + unsigned int i, v, maxeilvt; + v = apic_read(APIC_EFEAT); + maxeilvt = (v >> 16) & 0xff; + seq_printf(seq, " EFEAT\t\t: %08x\n", v); + seq_printf(seq, " ECTRL\t\t: %08x\n", apic_read(APIC_ECTRL)); + + for (i = 0; i < maxeilvt; i++) { + v = apic_read(APIC_EILVTn(i)); + seq_printf(seq, " EILVT%d\t\t: %08x\n", i, v); + } + } +#endif /* CONFIG_X86_LOCAL_APIC */ seq_printf(seq, "\n MSR\t:\n"); } @@ -788,13 +581,11 @@ static int cpu_init_msr(unsigned cpu, unsigned type, struct dentry *dentry) { struct dentry *cpu_dentry = NULL; unsigned reg, reg_min, reg_max; - int i, range, err = 0; + int i, err = 0; char reg_dir[12]; u32 low, high; - range = get_cpu_range_count(cpu); - - for (i = 0; i < range; i++) { + for (i = 0; i < ARRAY_SIZE(cpu_reg_range); i++) { if (!get_cpu_range(cpu, ®_min, ®_max, i, cpu_base[type].flag)) continue; @@ -850,10 +641,6 @@ static int cpu_init_cpu(void) cpui = &cpu_data(cpu); if (!cpu_has(cpui, X86_FEATURE_MSR)) continue; - per_cpu(cpu_model, cpu) = ((cpui->x86_vendor << 16) | - (cpui->x86 << 8) | - (cpui->x86_model)); - per_cpu(cpu_modelflag, cpu) = get_cpu_modelflag(cpu); sprintf(cpu_dir, "cpu%d", cpu); cpu_dentry = debugfs_create_dir(cpu_dir, cpu_debugfs_dir); diff --git a/arch/x86/kernel/cpu/cpufreq/Kconfig b/arch/x86/kernel/cpu/cpufreq/Kconfig index 52c839875478..f138c6c389b9 100644 --- a/arch/x86/kernel/cpu/cpufreq/Kconfig +++ b/arch/x86/kernel/cpu/cpufreq/Kconfig @@ -220,11 +220,14 @@ config X86_LONGHAUL If in doubt, say N. config X86_E_POWERSAVER - tristate "VIA C7 Enhanced PowerSaver" + tristate "VIA C7 Enhanced PowerSaver (DANGEROUS)" select CPU_FREQ_TABLE - depends on X86_32 + depends on X86_32 && EXPERIMENTAL help - This adds the CPUFreq driver for VIA C7 processors. + This adds the CPUFreq driver for VIA C7 processors. However, this driver + does not have any safeguards to prevent operating the CPU out of spec + and is thus considered dangerous. Please use the regular ACPI cpufreq + driver, enabled by CONFIG_X86_ACPI_CPUFREQ. If in doubt, say N. diff --git a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c index 752e8c6b2c7e..ae9b503220ca 100644 --- a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c +++ b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c @@ -90,11 +90,7 @@ static int check_est_cpu(unsigned int cpuid) { struct cpuinfo_x86 *cpu = &cpu_data(cpuid); - if (cpu->x86_vendor != X86_VENDOR_INTEL || - !cpu_has(cpu, X86_FEATURE_EST)) - return 0; - - return 1; + return cpu_has(cpu, X86_FEATURE_EST); } static unsigned extract_io(u32 value, struct acpi_cpufreq_data *data) diff --git a/arch/x86/kernel/cpu/cpufreq/powernow-k8.c b/arch/x86/kernel/cpu/cpufreq/powernow-k8.c index cf52215d9eb1..81cbe64ed6b4 100644 --- a/arch/x86/kernel/cpu/cpufreq/powernow-k8.c +++ b/arch/x86/kernel/cpu/cpufreq/powernow-k8.c @@ -1,3 +1,4 @@ + /* * (c) 2003-2006 Advanced Micro Devices, Inc. * Your use of this code is subject to the terms and conditions of the @@ -117,20 +118,17 @@ static int query_current_values_with_pending_wait(struct powernow_k8_data *data) u32 i = 0; if (cpu_family == CPU_HW_PSTATE) { - if (data->currpstate == HW_PSTATE_INVALID) { - /* read (initial) hw pstate if not yet set */ - rdmsr(MSR_PSTATE_STATUS, lo, hi); - i = lo & HW_PSTATE_MASK; + rdmsr(MSR_PSTATE_STATUS, lo, hi); + i = lo & HW_PSTATE_MASK; + data->currpstate = i; + + /* + * a workaround for family 11h erratum 311 might cause + * an "out-of-range Pstate if the core is in Pstate-0 + */ + if ((boot_cpu_data.x86 == 0x11) && (i >= data->numps)) + data->currpstate = HW_PSTATE_0; - /* - * a workaround for family 11h erratum 311 might cause - * an "out-of-range Pstate if the core is in Pstate-0 - */ - if (i >= data->numps) - data->currpstate = HW_PSTATE_0; - else - data->currpstate = i; - } return 0; } do { @@ -510,41 +508,34 @@ static int core_voltage_post_transition(struct powernow_k8_data *data, return 0; } -static int check_supported_cpu(unsigned int cpu) +static void check_supported_cpu(void *_rc) { - cpumask_t oldmask; u32 eax, ebx, ecx, edx; - unsigned int rc = 0; + int *rc = _rc; - oldmask = current->cpus_allowed; - set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu)); - - if (smp_processor_id() != cpu) { - printk(KERN_ERR PFX "limiting to cpu %u failed\n", cpu); - goto out; - } + *rc = -ENODEV; if (current_cpu_data.x86_vendor != X86_VENDOR_AMD) - goto out; + return; eax = cpuid_eax(CPUID_PROCESSOR_SIGNATURE); if (((eax & CPUID_XFAM) != CPUID_XFAM_K8) && ((eax & CPUID_XFAM) < CPUID_XFAM_10H)) - goto out; + return; if ((eax & CPUID_XFAM) == CPUID_XFAM_K8) { if (((eax & CPUID_USE_XFAM_XMOD) != CPUID_USE_XFAM_XMOD) || ((eax & CPUID_XMOD) > CPUID_XMOD_REV_MASK)) { printk(KERN_INFO PFX "Processor cpuid %x not supported\n", eax); - goto out; + return; } eax = cpuid_eax(CPUID_GET_MAX_CAPABILITIES); if (eax < CPUID_FREQ_VOLT_CAPABILITIES) { printk(KERN_INFO PFX "No frequency change capabilities detected\n"); - goto out; + return; } cpuid(CPUID_FREQ_VOLT_CAPABILITIES, &eax, &ebx, &ecx, &edx); @@ -552,21 +543,17 @@ static int check_supported_cpu(unsigned int cpu) != P_STATE_TRANSITION_CAPABLE) { printk(KERN_INFO PFX "Power state transitions not supported\n"); - goto out; + return; } } else { /* must be a HW Pstate capable processor */ cpuid(CPUID_FREQ_VOLT_CAPABILITIES, &eax, &ebx, &ecx, &edx); if ((edx & USE_HW_PSTATE) == USE_HW_PSTATE) cpu_family = CPU_HW_PSTATE; else - goto out; + return; } - rc = 1; - -out: - set_cpus_allowed_ptr(current, &oldmask); - return rc; + *rc = 0; } static int check_pst_table(struct powernow_k8_data *data, struct pst_s *pst, @@ -823,13 +810,14 @@ static void powernow_k8_acpi_pst_values(struct powernow_k8_data *data, if (!data->acpi_data.state_count || (cpu_family == CPU_HW_PSTATE)) return; - control = data->acpi_data.states[index].control; data->irt = (control - >> IRT_SHIFT) & IRT_MASK; data->rvo = (control >> - RVO_SHIFT) & RVO_MASK; data->exttype = (control - >> EXT_TYPE_SHIFT) & EXT_TYPE_MASK; - data->plllock = (control >> PLL_L_SHIFT) & PLL_L_MASK; data->vidmvs = 1 - << ((control >> MVS_SHIFT) & MVS_MASK); data->vstable = - (control >> VST_SHIFT) & VST_MASK; } + control = data->acpi_data.states[index].control; + data->irt = (control >> IRT_SHIFT) & IRT_MASK; + data->rvo = (control >> RVO_SHIFT) & RVO_MASK; + data->exttype = (control >> EXT_TYPE_SHIFT) & EXT_TYPE_MASK; + data->plllock = (control >> PLL_L_SHIFT) & PLL_L_MASK; + data->vidmvs = 1 << ((control >> MVS_SHIFT) & MVS_MASK); + data->vstable = (control >> VST_SHIFT) & VST_MASK; +} static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data) { @@ -1046,6 +1034,19 @@ static int get_transition_latency(struct powernow_k8_data *data) if (cur_latency > max_latency) max_latency = cur_latency; } + if (max_latency == 0) { + /* + * Fam 11h always returns 0 as transition latency. + * This is intended and means "very fast". While cpufreq core + * and governors currently can handle that gracefully, better + * set it to 1 to avoid problems in the future. + * For all others it's a BIOS bug. + */ + if (!boot_cpu_data.x86 == 0x11) + printk(KERN_ERR FW_WARN PFX "Invalid zero transition " + "latency\n"); + max_latency = 1; + } /* value in usecs, needs to be in nanoseconds */ return 1000 * max_latency; } @@ -1093,7 +1094,7 @@ static int transition_frequency_fidvid(struct powernow_k8_data *data, freqs.old = find_khz_freq_from_fid(data->currfid); freqs.new = find_khz_freq_from_fid(fid); - for_each_cpu_mask_nr(i, *(data->available_cores)) { + for_each_cpu(i, data->available_cores) { freqs.cpu = i; cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); } @@ -1101,7 +1102,7 @@ static int transition_frequency_fidvid(struct powernow_k8_data *data, res = transition_fid_vid(data, fid, vid); freqs.new = find_khz_freq_from_fid(data->currfid); - for_each_cpu_mask_nr(i, *(data->available_cores)) { + for_each_cpu(i, data->available_cores) { freqs.cpu = i; cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); } @@ -1126,7 +1127,7 @@ static int transition_frequency_pstate(struct powernow_k8_data *data, data->currpstate); freqs.new = find_khz_freq_from_pstate(data->powernow_table, pstate); - for_each_cpu_mask_nr(i, *(data->available_cores)) { + for_each_cpu(i, data->available_cores) { freqs.cpu = i; cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); } @@ -1134,7 +1135,7 @@ static int transition_frequency_pstate(struct powernow_k8_data *data, res = transition_pstate(data, pstate); freqs.new = find_khz_freq_from_pstate(data->powernow_table, pstate); - for_each_cpu_mask_nr(i, *(data->available_cores)) { + for_each_cpu(i, data->available_cores) { freqs.cpu = i; cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); } @@ -1235,21 +1236,47 @@ static int powernowk8_verify(struct cpufreq_policy *pol) return cpufreq_frequency_table_verify(pol, data->powernow_table); } -static const char ACPI_PSS_BIOS_BUG_MSG[] = - KERN_ERR FW_BUG PFX "No compatible ACPI _PSS objects found.\n" - KERN_ERR FW_BUG PFX "Try again with latest BIOS.\n"; +struct init_on_cpu { + struct powernow_k8_data *data; + int rc; +}; + +static void __cpuinit powernowk8_cpu_init_on_cpu(void *_init_on_cpu) +{ + struct init_on_cpu *init_on_cpu = _init_on_cpu; + + if (pending_bit_stuck()) { + printk(KERN_ERR PFX "failing init, change pending bit set\n"); + init_on_cpu->rc = -ENODEV; + return; + } + + if (query_current_values_with_pending_wait(init_on_cpu->data)) { + init_on_cpu->rc = -ENODEV; + return; + } + + if (cpu_family == CPU_OPTERON) + fidvid_msr_init(); + + init_on_cpu->rc = 0; +} /* per CPU init entry point to the driver */ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol) { + static const char ACPI_PSS_BIOS_BUG_MSG[] = + KERN_ERR FW_BUG PFX "No compatible ACPI _PSS objects found.\n" + KERN_ERR FW_BUG PFX "Try again with latest BIOS.\n"; struct powernow_k8_data *data; - cpumask_t oldmask; + struct init_on_cpu init_on_cpu; int rc; if (!cpu_online(pol->cpu)) return -ENODEV; - if (!check_supported_cpu(pol->cpu)) + smp_call_function_single(pol->cpu, check_supported_cpu, &rc, 1); + if (rc) return -ENODEV; data = kzalloc(sizeof(struct powernow_k8_data), GFP_KERNEL); @@ -1289,27 +1316,12 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol) pol->cpuinfo.transition_latency = get_transition_latency(data); /* only run on specific CPU from here on */ - oldmask = current->cpus_allowed; - set_cpus_allowed_ptr(current, &cpumask_of_cpu(pol->cpu)); - - if (smp_processor_id() != pol->cpu) { - printk(KERN_ERR PFX "limiting to cpu %u failed\n", pol->cpu); - goto err_out_unmask; - } - - if (pending_bit_stuck()) { - printk(KERN_ERR PFX "failing init, change pending bit set\n"); - goto err_out_unmask; - } - - if (query_current_values_with_pending_wait(data)) - goto err_out_unmask; - - if (cpu_family == CPU_OPTERON) - fidvid_msr_init(); - - /* run on any CPU again */ - set_cpus_allowed_ptr(current, &oldmask); + init_on_cpu.data = data; + smp_call_function_single(data->cpu, powernowk8_cpu_init_on_cpu, + &init_on_cpu, 1); + rc = init_on_cpu.rc; + if (rc != 0) + goto err_out_exit_acpi; if (cpu_family == CPU_HW_PSTATE) cpumask_copy(pol->cpus, cpumask_of(pol->cpu)); @@ -1346,8 +1358,7 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol) return 0; -err_out_unmask: - set_cpus_allowed_ptr(current, &oldmask); +err_out_exit_acpi: powernow_k8_cpu_exit_acpi(data); err_out: @@ -1372,28 +1383,25 @@ static int __devexit powernowk8_cpu_exit(struct cpufreq_policy *pol) return 0; } +static void query_values_on_cpu(void *_err) +{ + int *err = _err; + struct powernow_k8_data *data = __get_cpu_var(powernow_data); + + *err = query_current_values_with_pending_wait(data); +} + static unsigned int powernowk8_get(unsigned int cpu) { - struct powernow_k8_data *data; - cpumask_t oldmask = current->cpus_allowed; + struct powernow_k8_data *data = per_cpu(powernow_data, cpu); unsigned int khz = 0; - unsigned int first; - - first = cpumask_first(cpu_core_mask(cpu)); - data = per_cpu(powernow_data, first); + int err; if (!data) return -EINVAL; - set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu)); - if (smp_processor_id() != cpu) { - printk(KERN_ERR PFX - "limiting to CPU %d failed in powernowk8_get\n", cpu); - set_cpus_allowed_ptr(current, &oldmask); - return 0; - } - - if (query_current_values_with_pending_wait(data)) + smp_call_function_single(cpu, query_values_on_cpu, &err, true); + if (err) goto out; if (cpu_family == CPU_HW_PSTATE) @@ -1404,7 +1412,6 @@ static unsigned int powernowk8_get(unsigned int cpu) out: - set_cpus_allowed_ptr(current, &oldmask); return khz; } @@ -1430,7 +1437,9 @@ static int __cpuinit powernowk8_init(void) unsigned int i, supported_cpus = 0; for_each_online_cpu(i) { - if (check_supported_cpu(i)) + int rc; + smp_call_function_single(i, check_supported_cpu, &rc, 1); + if (rc == 0) supported_cpus++; } diff --git a/arch/x86/kernel/cpu/cpufreq/powernow-k8.h b/arch/x86/kernel/cpu/cpufreq/powernow-k8.h index 6c6698feade1..c9c1190b5e1f 100644 --- a/arch/x86/kernel/cpu/cpufreq/powernow-k8.h +++ b/arch/x86/kernel/cpu/cpufreq/powernow-k8.h @@ -223,14 +223,3 @@ static void powernow_k8_acpi_pst_values(struct powernow_k8_data *data, unsigned static int fill_powernow_table_pstate(struct powernow_k8_data *data, struct cpufreq_frequency_table *powernow_table); static int fill_powernow_table_fidvid(struct powernow_k8_data *data, struct cpufreq_frequency_table *powernow_table); - -#ifdef CONFIG_SMP -static inline void define_siblings(int cpu, cpumask_t cpu_sharedcore_mask[]) -{ -} -#else -static inline void define_siblings(int cpu, cpumask_t cpu_sharedcore_mask[]) -{ - cpu_set(0, cpu_sharedcore_mask[0]); -} -#endif diff --git a/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c b/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c index 55c831ed71ce..8d672ef162ce 100644 --- a/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c +++ b/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c @@ -323,14 +323,8 @@ static unsigned int get_cur_freq(unsigned int cpu) { unsigned l, h; unsigned clock_freq; - cpumask_t saved_mask; - saved_mask = current->cpus_allowed; - set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu)); - if (smp_processor_id() != cpu) - return 0; - - rdmsr(MSR_IA32_PERF_STATUS, l, h); + rdmsr_on_cpu(cpu, MSR_IA32_PERF_STATUS, &l, &h); clock_freq = extract_clock(l, cpu, 0); if (unlikely(clock_freq == 0)) { @@ -340,11 +334,9 @@ static unsigned int get_cur_freq(unsigned int cpu) * P-state transition (like TM2). Get the last freq set * in PERF_CTL. */ - rdmsr(MSR_IA32_PERF_CTL, l, h); + rdmsr_on_cpu(cpu, MSR_IA32_PERF_CTL, &l, &h); clock_freq = extract_clock(l, cpu, 1); } - - set_cpus_allowed_ptr(current, &saved_mask); return clock_freq; } @@ -467,15 +459,10 @@ static int centrino_target (struct cpufreq_policy *policy, struct cpufreq_freqs freqs; int retval = 0; unsigned int j, k, first_cpu, tmp; - cpumask_var_t saved_mask, covered_cpus; + cpumask_var_t covered_cpus; - if (unlikely(!alloc_cpumask_var(&saved_mask, GFP_KERNEL))) + if (unlikely(!zalloc_cpumask_var(&covered_cpus, GFP_KERNEL))) return -ENOMEM; - if (unlikely(!zalloc_cpumask_var(&covered_cpus, GFP_KERNEL))) { - free_cpumask_var(saved_mask); - return -ENOMEM; - } - cpumask_copy(saved_mask, ¤t->cpus_allowed); if (unlikely(per_cpu(centrino_model, cpu) == NULL)) { retval = -ENODEV; @@ -493,7 +480,7 @@ static int centrino_target (struct cpufreq_policy *policy, first_cpu = 1; for_each_cpu(j, policy->cpus) { - const struct cpumask *mask; + int good_cpu; /* cpufreq holds the hotplug lock, so we are safe here */ if (!cpu_online(j)) @@ -504,32 +491,30 @@ static int centrino_target (struct cpufreq_policy *policy, * Make sure we are running on CPU that wants to change freq */ if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) - mask = policy->cpus; + good_cpu = cpumask_any_and(policy->cpus, + cpu_online_mask); else - mask = cpumask_of(j); + good_cpu = j; - set_cpus_allowed_ptr(current, mask); - preempt_disable(); - if (unlikely(!cpu_isset(smp_processor_id(), *mask))) { + if (good_cpu >= nr_cpu_ids) { dprintk("couldn't limit to CPUs in this domain\n"); retval = -EAGAIN; if (first_cpu) { /* We haven't started the transition yet. */ - goto migrate_end; + goto out; } - preempt_enable(); break; } msr = per_cpu(centrino_model, cpu)->op_points[newstate].index; if (first_cpu) { - rdmsr(MSR_IA32_PERF_CTL, oldmsr, h); + rdmsr_on_cpu(good_cpu, MSR_IA32_PERF_CTL, &oldmsr, &h); if (msr == (oldmsr & 0xffff)) { dprintk("no change needed - msr was and needs " "to be %x\n", oldmsr); retval = 0; - goto migrate_end; + goto out; } freqs.old = extract_clock(oldmsr, cpu, 0); @@ -553,14 +538,11 @@ static int centrino_target (struct cpufreq_policy *policy, oldmsr |= msr; } - wrmsr(MSR_IA32_PERF_CTL, oldmsr, h); - if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) { - preempt_enable(); + wrmsr_on_cpu(good_cpu, MSR_IA32_PERF_CTL, oldmsr, h); + if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) break; - } - cpu_set(j, *covered_cpus); - preempt_enable(); + cpumask_set_cpu(j, covered_cpus); } for_each_cpu(k, policy->cpus) { @@ -578,10 +560,8 @@ static int centrino_target (struct cpufreq_policy *policy, * Best effort undo.. */ - for_each_cpu_mask_nr(j, *covered_cpus) { - set_cpus_allowed_ptr(current, &cpumask_of_cpu(j)); - wrmsr(MSR_IA32_PERF_CTL, oldmsr, h); - } + for_each_cpu(j, covered_cpus) + wrmsr_on_cpu(j, MSR_IA32_PERF_CTL, oldmsr, h); tmp = freqs.new; freqs.new = freqs.old; @@ -593,15 +573,9 @@ static int centrino_target (struct cpufreq_policy *policy, cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); } } - set_cpus_allowed_ptr(current, saved_mask); retval = 0; - goto out; -migrate_end: - preempt_enable(); - set_cpus_allowed_ptr(current, saved_mask); out: - free_cpumask_var(saved_mask); free_cpumask_var(covered_cpus); return retval; } diff --git a/arch/x86/kernel/cpu/cpufreq/speedstep-ich.c b/arch/x86/kernel/cpu/cpufreq/speedstep-ich.c index 016c1a4fa3fc..6911e91fb4f6 100644 --- a/arch/x86/kernel/cpu/cpufreq/speedstep-ich.c +++ b/arch/x86/kernel/cpu/cpufreq/speedstep-ich.c @@ -89,7 +89,8 @@ static int speedstep_find_register(void) * speedstep_set_state - set the SpeedStep state * @state: new processor frequency state (SPEEDSTEP_LOW or SPEEDSTEP_HIGH) * - * Tries to change the SpeedStep state. + * Tries to change the SpeedStep state. Can be called from + * smp_call_function_single. */ static void speedstep_set_state(unsigned int state) { @@ -143,6 +144,11 @@ static void speedstep_set_state(unsigned int state) return; } +/* Wrapper for smp_call_function_single. */ +static void _speedstep_set_state(void *_state) +{ + speedstep_set_state(*(unsigned int *)_state); +} /** * speedstep_activate - activate SpeedStep control in the chipset @@ -226,22 +232,28 @@ static unsigned int speedstep_detect_chipset(void) return 0; } -static unsigned int _speedstep_get(const struct cpumask *cpus) -{ +struct get_freq_data { unsigned int speed; - cpumask_t cpus_allowed; + unsigned int processor; +}; - cpus_allowed = current->cpus_allowed; - set_cpus_allowed_ptr(current, cpus); - speed = speedstep_get_frequency(speedstep_processor); - set_cpus_allowed_ptr(current, &cpus_allowed); - dprintk("detected %u kHz as current frequency\n", speed); - return speed; +static void get_freq_data(void *_data) +{ + struct get_freq_data *data = _data; + + data->speed = speedstep_get_frequency(data->processor); } static unsigned int speedstep_get(unsigned int cpu) { - return _speedstep_get(cpumask_of(cpu)); + struct get_freq_data data = { .processor = cpu }; + + /* You're supposed to ensure CPU is online. */ + if (smp_call_function_single(cpu, get_freq_data, &data, 1) != 0) + BUG(); + + dprintk("detected %u kHz as current frequency\n", data.speed); + return data.speed; } /** @@ -257,16 +269,16 @@ static int speedstep_target(struct cpufreq_policy *policy, unsigned int target_freq, unsigned int relation) { - unsigned int newstate = 0; + unsigned int newstate = 0, policy_cpu; struct cpufreq_freqs freqs; - cpumask_t cpus_allowed; int i; if (cpufreq_frequency_table_target(policy, &speedstep_freqs[0], target_freq, relation, &newstate)) return -EINVAL; - freqs.old = _speedstep_get(policy->cpus); + policy_cpu = cpumask_any_and(policy->cpus, cpu_online_mask); + freqs.old = speedstep_get(policy_cpu); freqs.new = speedstep_freqs[newstate].frequency; freqs.cpu = policy->cpu; @@ -276,20 +288,13 @@ static int speedstep_target(struct cpufreq_policy *policy, if (freqs.old == freqs.new) return 0; - cpus_allowed = current->cpus_allowed; - for_each_cpu(i, policy->cpus) { freqs.cpu = i; cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); } - /* switch to physical CPU where state is to be changed */ - set_cpus_allowed_ptr(current, policy->cpus); - - speedstep_set_state(newstate); - - /* allow to be run on all CPUs */ - set_cpus_allowed_ptr(current, &cpus_allowed); + smp_call_function_single(policy_cpu, _speedstep_set_state, &newstate, + true); for_each_cpu(i, policy->cpus) { freqs.cpu = i; @@ -312,33 +317,43 @@ static int speedstep_verify(struct cpufreq_policy *policy) return cpufreq_frequency_table_verify(policy, &speedstep_freqs[0]); } +struct get_freqs { + struct cpufreq_policy *policy; + int ret; +}; + +static void get_freqs_on_cpu(void *_get_freqs) +{ + struct get_freqs *get_freqs = _get_freqs; + + get_freqs->ret = + speedstep_get_freqs(speedstep_processor, + &speedstep_freqs[SPEEDSTEP_LOW].frequency, + &speedstep_freqs[SPEEDSTEP_HIGH].frequency, + &get_freqs->policy->cpuinfo.transition_latency, + &speedstep_set_state); +} static int speedstep_cpu_init(struct cpufreq_policy *policy) { - int result = 0; - unsigned int speed; - cpumask_t cpus_allowed; + int result; + unsigned int policy_cpu, speed; + struct get_freqs gf; /* only run on CPU to be set, or on its sibling */ #ifdef CONFIG_SMP cpumask_copy(policy->cpus, cpu_sibling_mask(policy->cpu)); #endif - - cpus_allowed = current->cpus_allowed; - set_cpus_allowed_ptr(current, policy->cpus); + policy_cpu = cpumask_any_and(policy->cpus, cpu_online_mask); /* detect low and high frequency and transition latency */ - result = speedstep_get_freqs(speedstep_processor, - &speedstep_freqs[SPEEDSTEP_LOW].frequency, - &speedstep_freqs[SPEEDSTEP_HIGH].frequency, - &policy->cpuinfo.transition_latency, - &speedstep_set_state); - set_cpus_allowed_ptr(current, &cpus_allowed); - if (result) - return result; + gf.policy = policy; + smp_call_function_single(policy_cpu, get_freqs_on_cpu, &gf, 1); + if (gf.ret) + return gf.ret; /* get current speed setting */ - speed = _speedstep_get(policy->cpus); + speed = speedstep_get(policy_cpu); if (!speed) return -EIO; diff --git a/arch/x86/kernel/cpu/cpufreq/speedstep-lib.c b/arch/x86/kernel/cpu/cpufreq/speedstep-lib.c index 2e3c6862657b..f4c290b8482f 100644 --- a/arch/x86/kernel/cpu/cpufreq/speedstep-lib.c +++ b/arch/x86/kernel/cpu/cpufreq/speedstep-lib.c @@ -226,6 +226,7 @@ static unsigned int pentium4_get_frequency(void) } +/* Warning: may get called from smp_call_function_single. */ unsigned int speedstep_get_frequency(unsigned int processor) { switch (processor) { diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c index 7437fa133c02..3260ab044996 100644 --- a/arch/x86/kernel/cpu/intel.c +++ b/arch/x86/kernel/cpu/intel.c @@ -86,6 +86,29 @@ static void __cpuinit early_init_intel(struct cpuinfo_x86 *c) */ if (c->x86 == 6 && c->x86_model < 15) clear_cpu_cap(c, X86_FEATURE_PAT); + +#ifdef CONFIG_KMEMCHECK + /* + * P4s have a "fast strings" feature which causes single- + * stepping REP instructions to only generate a #DB on + * cache-line boundaries. + * + * Ingo Molnar reported a Pentium D (model 6) and a Xeon + * (model 2) with the same problem. + */ + if (c->x86 == 15) { + u64 misc_enable; + + rdmsrl(MSR_IA32_MISC_ENABLE, misc_enable); + + if (misc_enable & MSR_IA32_MISC_ENABLE_FAST_STRING) { + printk(KERN_INFO "kmemcheck: Disabling fast string operations\n"); + + misc_enable &= ~MSR_IA32_MISC_ENABLE_FAST_STRING; + wrmsrl(MSR_IA32_MISC_ENABLE, misc_enable); + } + } +#endif } #ifdef CONFIG_X86_32 @@ -229,12 +252,12 @@ static void __cpuinit intel_workarounds(struct cpuinfo_x86 *c) } #endif -static void __cpuinit srat_detect_node(void) +static void __cpuinit srat_detect_node(struct cpuinfo_x86 *c) { #if defined(CONFIG_NUMA) && defined(CONFIG_X86_64) unsigned node; int cpu = smp_processor_id(); - int apicid = hard_smp_processor_id(); + int apicid = cpu_has_apic ? hard_smp_processor_id() : c->apicid; /* Don't do the funky fallback heuristics the AMD version employs for now. */ @@ -400,7 +423,7 @@ static void __cpuinit init_intel(struct cpuinfo_x86 *c) } /* Work around errata */ - srat_detect_node(); + srat_detect_node(c); if (cpu_has(c, X86_FEATURE_VMX)) detect_vmx_virtcap(c); diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c index 483eda96e102..789efe217e1a 100644 --- a/arch/x86/kernel/cpu/intel_cacheinfo.c +++ b/arch/x86/kernel/cpu/intel_cacheinfo.c @@ -17,6 +17,7 @@ #include #include +#include #define LVL_1_INST 1 #define LVL_1_DATA 2 @@ -159,14 +160,6 @@ struct _cpuid4_info_regs { unsigned long can_disable; }; -#if defined(CONFIG_PCI) && defined(CONFIG_SYSFS) -static struct pci_device_id k8_nb_id[] = { - { PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x1103) }, - { PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x1203) }, - {} -}; -#endif - unsigned short num_cache_leaves; /* AMD doesn't have CPUID4. Emulate it here to report the same @@ -207,10 +200,17 @@ union l3_cache { }; static const unsigned short __cpuinitconst assocs[] = { - [1] = 1, [2] = 2, [4] = 4, [6] = 8, - [8] = 16, [0xa] = 32, [0xb] = 48, + [1] = 1, + [2] = 2, + [4] = 4, + [6] = 8, + [8] = 16, + [0xa] = 32, + [0xb] = 48, [0xc] = 64, - [0xf] = 0xffff // ?? + [0xd] = 96, + [0xe] = 128, + [0xf] = 0xffff /* fully associative - no way to show this currently */ }; static const unsigned char __cpuinitconst levels[] = { 1, 1, 2, 3 }; @@ -271,7 +271,8 @@ amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax, eax->split.type = types[leaf]; eax->split.level = levels[leaf]; if (leaf == 3) - eax->split.num_threads_sharing = current_cpu_data.x86_max_cores - 1; + eax->split.num_threads_sharing = + current_cpu_data.x86_max_cores - 1; else eax->split.num_threads_sharing = 0; eax->split.num_cores_on_die = current_cpu_data.x86_max_cores - 1; @@ -291,6 +292,14 @@ amd_check_l3_disable(int index, struct _cpuid4_info_regs *this_leaf) { if (index < 3) return; + + if (boot_cpu_data.x86 == 0x11) + return; + + /* see erratum #382 */ + if ((boot_cpu_data.x86 == 0x10) && (boot_cpu_data.x86_model < 0x8)) + return; + this_leaf->can_disable = 1; } @@ -696,98 +705,76 @@ static ssize_t show_type(struct _cpuid4_info *this_leaf, char *buf) #define to_object(k) container_of(k, struct _index_kobject, kobj) #define to_attr(a) container_of(a, struct _cache_attr, attr) -#ifdef CONFIG_PCI -static struct pci_dev *get_k8_northbridge(int node) +static ssize_t show_cache_disable(struct _cpuid4_info *this_leaf, char *buf, + unsigned int index) { - struct pci_dev *dev = NULL; - int i; - - for (i = 0; i <= node; i++) { - do { - dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev); - if (!dev) - break; - } while (!pci_match_id(&k8_nb_id[0], dev)); - if (!dev) - break; - } - return dev; -} -#else -static struct pci_dev *get_k8_northbridge(int node) -{ - return NULL; -} -#endif - -static ssize_t show_cache_disable(struct _cpuid4_info *this_leaf, char *buf) -{ - const struct cpumask *mask = to_cpumask(this_leaf->shared_cpu_map); - int node = cpu_to_node(cpumask_first(mask)); - struct pci_dev *dev = NULL; - ssize_t ret = 0; - int i; + int cpu = cpumask_first(to_cpumask(this_leaf->shared_cpu_map)); + int node = cpu_to_node(cpu); + struct pci_dev *dev = node_to_k8_nb_misc(node); + unsigned int reg = 0; if (!this_leaf->can_disable) - return sprintf(buf, "Feature not enabled\n"); - - dev = get_k8_northbridge(node); - if (!dev) { - printk(KERN_ERR "Attempting AMD northbridge operation on a system with no northbridge\n"); return -EINVAL; - } - for (i = 0; i < 2; i++) { - unsigned int reg; + if (!dev) + return -EINVAL; - pci_read_config_dword(dev, 0x1BC + i * 4, ®); - - ret += sprintf(buf, "%sEntry: %d\n", buf, i); - ret += sprintf(buf, "%sReads: %s\tNew Entries: %s\n", - buf, - reg & 0x80000000 ? "Disabled" : "Allowed", - reg & 0x40000000 ? "Disabled" : "Allowed"); - ret += sprintf(buf, "%sSubCache: %x\tIndex: %x\n", - buf, (reg & 0x30000) >> 16, reg & 0xfff); - } - return ret; + pci_read_config_dword(dev, 0x1BC + index * 4, ®); + return sprintf(buf, "%x\n", reg); } -static ssize_t -store_cache_disable(struct _cpuid4_info *this_leaf, const char *buf, - size_t count) +#define SHOW_CACHE_DISABLE(index) \ +static ssize_t \ +show_cache_disable_##index(struct _cpuid4_info *this_leaf, char *buf) \ +{ \ + return show_cache_disable(this_leaf, buf, index); \ +} +SHOW_CACHE_DISABLE(0) +SHOW_CACHE_DISABLE(1) + +static ssize_t store_cache_disable(struct _cpuid4_info *this_leaf, + const char *buf, size_t count, unsigned int index) { - const struct cpumask *mask = to_cpumask(this_leaf->shared_cpu_map); - int node = cpu_to_node(cpumask_first(mask)); - struct pci_dev *dev = NULL; - unsigned int ret, index, val; + int cpu = cpumask_first(to_cpumask(this_leaf->shared_cpu_map)); + int node = cpu_to_node(cpu); + struct pci_dev *dev = node_to_k8_nb_misc(node); + unsigned long val = 0; + unsigned int scrubber = 0; if (!this_leaf->can_disable) - return 0; - - if (strlen(buf) > 15) return -EINVAL; - ret = sscanf(buf, "%x %x", &index, &val); - if (ret != 2) + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (!dev) return -EINVAL; - if (index > 1) + + if (strict_strtoul(buf, 10, &val) < 0) return -EINVAL; val |= 0xc0000000; - dev = get_k8_northbridge(node); - if (!dev) { - printk(KERN_ERR "Attempting AMD northbridge operation on a system with no northbridge\n"); - return -EINVAL; - } + + pci_read_config_dword(dev, 0x58, &scrubber); + scrubber &= ~0x1f000000; + pci_write_config_dword(dev, 0x58, scrubber); pci_write_config_dword(dev, 0x1BC + index * 4, val & ~0x40000000); wbinvd(); pci_write_config_dword(dev, 0x1BC + index * 4, val); - - return 1; + return count; } +#define STORE_CACHE_DISABLE(index) \ +static ssize_t \ +store_cache_disable_##index(struct _cpuid4_info *this_leaf, \ + const char *buf, size_t count) \ +{ \ + return store_cache_disable(this_leaf, buf, count, index); \ +} +STORE_CACHE_DISABLE(0) +STORE_CACHE_DISABLE(1) + struct _cache_attr { struct attribute attr; ssize_t (*show)(struct _cpuid4_info *, char *); @@ -808,7 +795,10 @@ define_one_ro(size); define_one_ro(shared_cpu_map); define_one_ro(shared_cpu_list); -static struct _cache_attr cache_disable = __ATTR(cache_disable, 0644, show_cache_disable, store_cache_disable); +static struct _cache_attr cache_disable_0 = __ATTR(cache_disable_0, 0644, + show_cache_disable_0, store_cache_disable_0); +static struct _cache_attr cache_disable_1 = __ATTR(cache_disable_1, 0644, + show_cache_disable_1, store_cache_disable_1); static struct attribute * default_attrs[] = { &type.attr, @@ -820,7 +810,8 @@ static struct attribute * default_attrs[] = { &size.attr, &shared_cpu_map.attr, &shared_cpu_list.attr, - &cache_disable.attr, + &cache_disable_0.attr, + &cache_disable_1.attr, NULL }; diff --git a/arch/x86/kernel/cpu/mcheck/Makefile b/arch/x86/kernel/cpu/mcheck/Makefile index b2f89829bbe8..188a1ca5ad2b 100644 --- a/arch/x86/kernel/cpu/mcheck/Makefile +++ b/arch/x86/kernel/cpu/mcheck/Makefile @@ -1,7 +1,12 @@ -obj-y = mce_$(BITS).o therm_throt.o +obj-y = mce.o -obj-$(CONFIG_X86_32) += k7.o p4.o p5.o p6.o winchip.o -obj-$(CONFIG_X86_MCE_INTEL) += mce_intel_64.o -obj-$(CONFIG_X86_MCE_AMD) += mce_amd_64.o +obj-$(CONFIG_X86_NEW_MCE) += mce-severity.o +obj-$(CONFIG_X86_OLD_MCE) += k7.o p4.o p6.o +obj-$(CONFIG_X86_ANCIENT_MCE) += winchip.o p5.o +obj-$(CONFIG_X86_MCE_INTEL) += mce_intel.o +obj-$(CONFIG_X86_MCE_AMD) += mce_amd.o obj-$(CONFIG_X86_MCE_NONFATAL) += non-fatal.o obj-$(CONFIG_X86_MCE_THRESHOLD) += threshold.o +obj-$(CONFIG_X86_MCE_INJECT) += mce-inject.o + +obj-$(CONFIG_X86_THERMAL_VECTOR) += therm_throt.o diff --git a/arch/x86/kernel/cpu/mcheck/k7.c b/arch/x86/kernel/cpu/mcheck/k7.c index dd3af6e7b39a..b945d5dbc609 100644 --- a/arch/x86/kernel/cpu/mcheck/k7.c +++ b/arch/x86/kernel/cpu/mcheck/k7.c @@ -2,25 +2,23 @@ * Athlon specific Machine Check Exception Reporting * (C) Copyright 2002 Dave Jones */ - -#include -#include -#include #include +#include +#include +#include #include #include #include +#include #include -#include "mce.h" - -/* Machine Check Handler For AMD Athlon/Duron */ +/* Machine Check Handler For AMD Athlon/Duron: */ static void k7_machine_check(struct pt_regs *regs, long error_code) { - int recover = 1; u32 alow, ahigh, high, low; u32 mcgstl, mcgsth; + int recover = 1; int i; rdmsr(MSR_IA32_MCG_STATUS, mcgstl, mcgsth); @@ -32,15 +30,19 @@ static void k7_machine_check(struct pt_regs *regs, long error_code) for (i = 1; i < nr_mce_banks; i++) { rdmsr(MSR_IA32_MC0_STATUS+i*4, low, high); - if (high&(1<<31)) { + if (high & (1<<31)) { char misc[20]; char addr[24]; - misc[0] = addr[0] = '\0'; + + misc[0] = '\0'; + addr[0] = '\0'; + if (high & (1<<29)) recover |= 1; if (high & (1<<25)) recover |= 2; high &= ~(1<<31); + if (high & (1<<27)) { rdmsr(MSR_IA32_MC0_MISC+i*4, alow, ahigh); snprintf(misc, 20, "[%08x%08x]", ahigh, alow); @@ -49,27 +51,31 @@ static void k7_machine_check(struct pt_regs *regs, long error_code) rdmsr(MSR_IA32_MC0_ADDR+i*4, alow, ahigh); snprintf(addr, 24, " at %08x%08x", ahigh, alow); } + printk(KERN_EMERG "CPU %d: Bank %d: %08x%08x%s%s\n", smp_processor_id(), i, high, low, misc, addr); - /* Clear it */ + + /* Clear it: */ wrmsr(MSR_IA32_MC0_STATUS+i*4, 0UL, 0UL); - /* Serialize */ + /* Serialize: */ wmb(); add_taint(TAINT_MACHINE_CHECK); } } - if (recover&2) + if (recover & 2) panic("CPU context corrupt"); - if (recover&1) + if (recover & 1) panic("Unable to continue"); + printk(KERN_EMERG "Attempting to continue.\n"); + mcgstl &= ~(1<<2); wrmsr(MSR_IA32_MCG_STATUS, mcgstl, mcgsth); } -/* AMD K7 machine check is Intel like */ +/* AMD K7 machine check is Intel like: */ void amd_mcheck_init(struct cpuinfo_x86 *c) { u32 l, h; @@ -79,21 +85,26 @@ void amd_mcheck_init(struct cpuinfo_x86 *c) return; machine_check_vector = k7_machine_check; + /* Make sure the vector pointer is visible before we enable MCEs: */ wmb(); printk(KERN_INFO "Intel machine check architecture supported.\n"); + rdmsr(MSR_IA32_MCG_CAP, l, h); if (l & (1<<8)) /* Control register present ? */ wrmsr(MSR_IA32_MCG_CTL, 0xffffffff, 0xffffffff); nr_mce_banks = l & 0xff; - /* Clear status for MC index 0 separately, we don't touch CTL, - * as some K7 Athlons cause spurious MCEs when its enabled. */ + /* + * Clear status for MC index 0 separately, we don't touch CTL, + * as some K7 Athlons cause spurious MCEs when its enabled: + */ if (boot_cpu_data.x86 == 6) { wrmsr(MSR_IA32_MC0_STATUS, 0x0, 0x0); i = 1; } else i = 0; + for (; i < nr_mce_banks; i++) { wrmsr(MSR_IA32_MC0_CTL+4*i, 0xffffffff, 0xffffffff); wrmsr(MSR_IA32_MC0_STATUS+4*i, 0x0, 0x0); diff --git a/arch/x86/kernel/cpu/mcheck/mce-inject.c b/arch/x86/kernel/cpu/mcheck/mce-inject.c new file mode 100644 index 000000000000..a3a235a53f09 --- /dev/null +++ b/arch/x86/kernel/cpu/mcheck/mce-inject.c @@ -0,0 +1,127 @@ +/* + * Machine check injection support. + * Copyright 2008 Intel 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; version 2 + * of the License. + * + * Authors: + * Andi Kleen + * Ying Huang + */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* Update fake mce registers on current CPU. */ +static void inject_mce(struct mce *m) +{ + struct mce *i = &per_cpu(injectm, m->extcpu); + + /* Make sure noone reads partially written injectm */ + i->finished = 0; + mb(); + m->finished = 0; + /* First set the fields after finished */ + i->extcpu = m->extcpu; + mb(); + /* Now write record in order, finished last (except above) */ + memcpy(i, m, sizeof(struct mce)); + /* Finally activate it */ + mb(); + i->finished = 1; +} + +struct delayed_mce { + struct timer_list timer; + struct mce m; +}; + +/* Inject mce on current CPU */ +static void raise_mce(unsigned long data) +{ + struct delayed_mce *dm = (struct delayed_mce *)data; + struct mce *m = &dm->m; + int cpu = m->extcpu; + + inject_mce(m); + if (m->status & MCI_STATUS_UC) { + struct pt_regs regs; + memset(®s, 0, sizeof(struct pt_regs)); + regs.ip = m->ip; + regs.cs = m->cs; + printk(KERN_INFO "Triggering MCE exception on CPU %d\n", cpu); + do_machine_check(®s, 0); + printk(KERN_INFO "MCE exception done on CPU %d\n", cpu); + } else { + mce_banks_t b; + memset(&b, 0xff, sizeof(mce_banks_t)); + printk(KERN_INFO "Starting machine check poll CPU %d\n", cpu); + machine_check_poll(0, &b); + mce_notify_irq(); + printk(KERN_INFO "Finished machine check poll on CPU %d\n", + cpu); + } + kfree(dm); +} + +/* Error injection interface */ +static ssize_t mce_write(struct file *filp, const char __user *ubuf, + size_t usize, loff_t *off) +{ + struct delayed_mce *dm; + struct mce m; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + /* + * There are some cases where real MSR reads could slip + * through. + */ + if (!boot_cpu_has(X86_FEATURE_MCE) || !boot_cpu_has(X86_FEATURE_MCA)) + return -EIO; + + if ((unsigned long)usize > sizeof(struct mce)) + usize = sizeof(struct mce); + if (copy_from_user(&m, ubuf, usize)) + return -EFAULT; + + if (m.extcpu >= num_possible_cpus() || !cpu_online(m.extcpu)) + return -EINVAL; + + dm = kmalloc(sizeof(struct delayed_mce), GFP_KERNEL); + if (!dm) + return -ENOMEM; + + /* + * Need to give user space some time to set everything up, + * so do it a jiffie or two later everywhere. + * Should we use a hrtimer here for better synchronization? + */ + memcpy(&dm->m, &m, sizeof(struct mce)); + setup_timer(&dm->timer, raise_mce, (unsigned long)dm); + dm->timer.expires = jiffies + 2; + add_timer_on(&dm->timer, m.extcpu); + return usize; +} + +static int inject_init(void) +{ + printk(KERN_INFO "Machine check injector initialized\n"); + mce_chrdev_ops.write = mce_write; + return 0; +} + +module_init(inject_init); +/* + * Cannot tolerate unloading currently because we cannot + * guarantee all openers of mce_chrdev will get a reference to us. + */ +MODULE_LICENSE("GPL"); diff --git a/arch/x86/kernel/cpu/mcheck/mce-internal.h b/arch/x86/kernel/cpu/mcheck/mce-internal.h new file mode 100644 index 000000000000..54dcb8ff12e5 --- /dev/null +++ b/arch/x86/kernel/cpu/mcheck/mce-internal.h @@ -0,0 +1,15 @@ +#include + +enum severity_level { + MCE_NO_SEVERITY, + MCE_KEEP_SEVERITY, + MCE_SOME_SEVERITY, + MCE_AO_SEVERITY, + MCE_UC_SEVERITY, + MCE_AR_SEVERITY, + MCE_PANIC_SEVERITY, +}; + +int mce_severity(struct mce *a, int tolerant, char **msg); + +extern int mce_ser; diff --git a/arch/x86/kernel/cpu/mcheck/mce-severity.c b/arch/x86/kernel/cpu/mcheck/mce-severity.c new file mode 100644 index 000000000000..ff0807f97056 --- /dev/null +++ b/arch/x86/kernel/cpu/mcheck/mce-severity.c @@ -0,0 +1,218 @@ +/* + * MCE grading rules. + * Copyright 2008, 2009 Intel Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; version 2 + * of the License. + * + * Author: Andi Kleen + */ +#include +#include +#include +#include +#include + +#include "mce-internal.h" + +/* + * Grade an mce by severity. In general the most severe ones are processed + * first. Since there are quite a lot of combinations test the bits in a + * table-driven way. The rules are simply processed in order, first + * match wins. + * + * Note this is only used for machine check exceptions, the corrected + * errors use much simpler rules. The exceptions still check for the corrected + * errors, but only to leave them alone for the CMCI handler (except for + * panic situations) + */ + +enum context { IN_KERNEL = 1, IN_USER = 2 }; +enum ser { SER_REQUIRED = 1, NO_SER = 2 }; + +static struct severity { + u64 mask; + u64 result; + unsigned char sev; + unsigned char mcgmask; + unsigned char mcgres; + unsigned char ser; + unsigned char context; + unsigned char covered; + char *msg; +} severities[] = { +#define KERNEL .context = IN_KERNEL +#define USER .context = IN_USER +#define SER .ser = SER_REQUIRED +#define NOSER .ser = NO_SER +#define SEV(s) .sev = MCE_ ## s ## _SEVERITY +#define BITCLR(x, s, m, r...) { .mask = x, .result = 0, SEV(s), .msg = m, ## r } +#define BITSET(x, s, m, r...) { .mask = x, .result = x, SEV(s), .msg = m, ## r } +#define MCGMASK(x, res, s, m, r...) \ + { .mcgmask = x, .mcgres = res, SEV(s), .msg = m, ## r } +#define MASK(x, y, s, m, r...) \ + { .mask = x, .result = y, SEV(s), .msg = m, ## r } +#define MCI_UC_S (MCI_STATUS_UC|MCI_STATUS_S) +#define MCI_UC_SAR (MCI_STATUS_UC|MCI_STATUS_S|MCI_STATUS_AR) +#define MCACOD 0xffff + + BITCLR(MCI_STATUS_VAL, NO, "Invalid"), + BITCLR(MCI_STATUS_EN, NO, "Not enabled"), + BITSET(MCI_STATUS_PCC, PANIC, "Processor context corrupt"), + /* When MCIP is not set something is very confused */ + MCGMASK(MCG_STATUS_MCIP, 0, PANIC, "MCIP not set in MCA handler"), + /* Neither return not error IP -- no chance to recover -> PANIC */ + MCGMASK(MCG_STATUS_RIPV|MCG_STATUS_EIPV, 0, PANIC, + "Neither restart nor error IP"), + MCGMASK(MCG_STATUS_RIPV, 0, PANIC, "In kernel and no restart IP", + KERNEL), + BITCLR(MCI_STATUS_UC, KEEP, "Corrected error", NOSER), + MASK(MCI_STATUS_OVER|MCI_STATUS_UC|MCI_STATUS_EN, MCI_STATUS_UC, SOME, + "Spurious not enabled", SER), + + /* ignore OVER for UCNA */ + MASK(MCI_UC_SAR, MCI_STATUS_UC, KEEP, + "Uncorrected no action required", SER), + MASK(MCI_STATUS_OVER|MCI_UC_SAR, MCI_STATUS_UC|MCI_STATUS_AR, PANIC, + "Illegal combination (UCNA with AR=1)", SER), + MASK(MCI_STATUS_S, 0, KEEP, "Non signalled machine check", SER), + + /* AR add known MCACODs here */ + MASK(MCI_STATUS_OVER|MCI_UC_SAR, MCI_STATUS_OVER|MCI_UC_SAR, PANIC, + "Action required with lost events", SER), + MASK(MCI_STATUS_OVER|MCI_UC_SAR|MCACOD, MCI_UC_SAR, PANIC, + "Action required; unknown MCACOD", SER), + + /* known AO MCACODs: */ + MASK(MCI_UC_SAR|MCI_STATUS_OVER|0xfff0, MCI_UC_S|0xc0, AO, + "Action optional: memory scrubbing error", SER), + MASK(MCI_UC_SAR|MCI_STATUS_OVER|MCACOD, MCI_UC_S|0x17a, AO, + "Action optional: last level cache writeback error", SER), + + MASK(MCI_STATUS_OVER|MCI_UC_SAR, MCI_UC_S, SOME, + "Action optional unknown MCACOD", SER), + MASK(MCI_STATUS_OVER|MCI_UC_SAR, MCI_UC_S|MCI_STATUS_OVER, SOME, + "Action optional with lost events", SER), + BITSET(MCI_STATUS_UC|MCI_STATUS_OVER, PANIC, "Overflowed uncorrected"), + BITSET(MCI_STATUS_UC, UC, "Uncorrected"), + BITSET(0, SOME, "No match") /* always matches. keep at end */ +}; + +/* + * If the EIPV bit is set, it means the saved IP is the + * instruction which caused the MCE. + */ +static int error_context(struct mce *m) +{ + if (m->mcgstatus & MCG_STATUS_EIPV) + return (m->ip && (m->cs & 3) == 3) ? IN_USER : IN_KERNEL; + /* Unknown, assume kernel */ + return IN_KERNEL; +} + +int mce_severity(struct mce *a, int tolerant, char **msg) +{ + enum context ctx = error_context(a); + struct severity *s; + + for (s = severities;; s++) { + if ((a->status & s->mask) != s->result) + continue; + if ((a->mcgstatus & s->mcgmask) != s->mcgres) + continue; + if (s->ser == SER_REQUIRED && !mce_ser) + continue; + if (s->ser == NO_SER && mce_ser) + continue; + if (s->context && ctx != s->context) + continue; + if (msg) + *msg = s->msg; + s->covered = 1; + if (s->sev >= MCE_UC_SEVERITY && ctx == IN_KERNEL) { + if (panic_on_oops || tolerant < 1) + return MCE_PANIC_SEVERITY; + } + return s->sev; + } +} + +static void *s_start(struct seq_file *f, loff_t *pos) +{ + if (*pos >= ARRAY_SIZE(severities)) + return NULL; + return &severities[*pos]; +} + +static void *s_next(struct seq_file *f, void *data, loff_t *pos) +{ + if (++(*pos) >= ARRAY_SIZE(severities)) + return NULL; + return &severities[*pos]; +} + +static void s_stop(struct seq_file *f, void *data) +{ +} + +static int s_show(struct seq_file *f, void *data) +{ + struct severity *ser = data; + seq_printf(f, "%d\t%s\n", ser->covered, ser->msg); + return 0; +} + +static const struct seq_operations severities_seq_ops = { + .start = s_start, + .next = s_next, + .stop = s_stop, + .show = s_show, +}; + +static int severities_coverage_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &severities_seq_ops); +} + +static ssize_t severities_coverage_write(struct file *file, + const char __user *ubuf, + size_t count, loff_t *ppos) +{ + int i; + for (i = 0; i < ARRAY_SIZE(severities); i++) + severities[i].covered = 0; + return count; +} + +static const struct file_operations severities_coverage_fops = { + .open = severities_coverage_open, + .release = seq_release, + .read = seq_read, + .write = severities_coverage_write, +}; + +static int __init severities_debugfs_init(void) +{ + struct dentry *dmce = NULL, *fseverities_coverage = NULL; + + dmce = debugfs_create_dir("mce", NULL); + if (dmce == NULL) + goto err_out; + fseverities_coverage = debugfs_create_file("severities-coverage", + 0444, dmce, NULL, + &severities_coverage_fops); + if (fseverities_coverage == NULL) + goto err_out; + + return 0; + +err_out: + if (fseverities_coverage) + debugfs_remove(fseverities_coverage); + if (dmce) + debugfs_remove(dmce); + return -ENOMEM; +} +late_initcall(severities_debugfs_init); diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c new file mode 100644 index 000000000000..284d1de968bc --- /dev/null +++ b/arch/x86/kernel/cpu/mcheck/mce.c @@ -0,0 +1,2049 @@ +/* + * Machine check handler. + * + * K8 parts Copyright 2002,2003 Andi Kleen, SuSE Labs. + * Rest from unknown author(s). + * 2004 Andi Kleen. Rewrote most of it. + * Copyright 2008 Intel Corporation + * Author: Andi Kleen + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "mce-internal.h" + +/* Handle unconfigured int18 (should never happen) */ +static void unexpected_machine_check(struct pt_regs *regs, long error_code) +{ + printk(KERN_ERR "CPU#%d: Unexpected int18 (Machine Check).\n", + smp_processor_id()); +} + +/* Call the installed machine check handler for this CPU setup. */ +void (*machine_check_vector)(struct pt_regs *, long error_code) = + unexpected_machine_check; + +int mce_disabled __read_mostly; + +#ifdef CONFIG_X86_NEW_MCE + +#define MISC_MCELOG_MINOR 227 + +#define SPINUNIT 100 /* 100ns */ + +atomic_t mce_entry; + +DEFINE_PER_CPU(unsigned, mce_exception_count); + +/* + * Tolerant levels: + * 0: always panic on uncorrected errors, log corrected errors + * 1: panic or SIGBUS on uncorrected errors, log corrected errors + * 2: SIGBUS or log uncorrected errors (if possible), log corrected errors + * 3: never panic or SIGBUS, log all errors (for testing only) + */ +static int tolerant __read_mostly = 1; +static int banks __read_mostly; +static u64 *bank __read_mostly; +static int rip_msr __read_mostly; +static int mce_bootlog __read_mostly = -1; +static int monarch_timeout __read_mostly = -1; +static int mce_panic_timeout __read_mostly; +static int mce_dont_log_ce __read_mostly; +int mce_cmci_disabled __read_mostly; +int mce_ignore_ce __read_mostly; +int mce_ser __read_mostly; + +/* User mode helper program triggered by machine check event */ +static unsigned long mce_need_notify; +static char mce_helper[128]; +static char *mce_helper_argv[2] = { mce_helper, NULL }; + +static unsigned long dont_init_banks; + +static DECLARE_WAIT_QUEUE_HEAD(mce_wait); +static DEFINE_PER_CPU(struct mce, mces_seen); +static int cpu_missing; + + +/* MCA banks polled by the period polling timer for corrected events */ +DEFINE_PER_CPU(mce_banks_t, mce_poll_banks) = { + [0 ... BITS_TO_LONGS(MAX_NR_BANKS)-1] = ~0UL +}; + +static inline int skip_bank_init(int i) +{ + return i < BITS_PER_LONG && test_bit(i, &dont_init_banks); +} + +static DEFINE_PER_CPU(struct work_struct, mce_work); + +/* Do initial initialization of a struct mce */ +void mce_setup(struct mce *m) +{ + memset(m, 0, sizeof(struct mce)); + m->cpu = m->extcpu = smp_processor_id(); + rdtscll(m->tsc); + /* We hope get_seconds stays lockless */ + m->time = get_seconds(); + m->cpuvendor = boot_cpu_data.x86_vendor; + m->cpuid = cpuid_eax(1); +#ifdef CONFIG_SMP + m->socketid = cpu_data(m->extcpu).phys_proc_id; +#endif + m->apicid = cpu_data(m->extcpu).initial_apicid; + rdmsrl(MSR_IA32_MCG_CAP, m->mcgcap); +} + +DEFINE_PER_CPU(struct mce, injectm); +EXPORT_PER_CPU_SYMBOL_GPL(injectm); + +/* + * Lockless MCE logging infrastructure. + * This avoids deadlocks on printk locks without having to break locks. Also + * separate MCEs from kernel messages to avoid bogus bug reports. + */ + +static struct mce_log mcelog = { + .signature = MCE_LOG_SIGNATURE, + .len = MCE_LOG_LEN, + .recordlen = sizeof(struct mce), +}; + +void mce_log(struct mce *mce) +{ + unsigned next, entry; + + mce->finished = 0; + wmb(); + for (;;) { + entry = rcu_dereference(mcelog.next); + for (;;) { + /* + * When the buffer fills up discard new entries. + * Assume that the earlier errors are the more + * interesting ones: + */ + if (entry >= MCE_LOG_LEN) { + set_bit(MCE_OVERFLOW, + (unsigned long *)&mcelog.flags); + return; + } + /* Old left over entry. Skip: */ + if (mcelog.entry[entry].finished) { + entry++; + continue; + } + break; + } + smp_rmb(); + next = entry + 1; + if (cmpxchg(&mcelog.next, entry, next) == entry) + break; + } + memcpy(mcelog.entry + entry, mce, sizeof(struct mce)); + wmb(); + mcelog.entry[entry].finished = 1; + wmb(); + + mce->finished = 1; + set_bit(0, &mce_need_notify); +} + +static void print_mce(struct mce *m) +{ + printk(KERN_EMERG + "CPU %d: Machine Check Exception: %16Lx Bank %d: %016Lx\n", + m->extcpu, m->mcgstatus, m->bank, m->status); + if (m->ip) { + printk(KERN_EMERG "RIP%s %02x:<%016Lx> ", + !(m->mcgstatus & MCG_STATUS_EIPV) ? " !INEXACT!" : "", + m->cs, m->ip); + if (m->cs == __KERNEL_CS) + print_symbol("{%s}", m->ip); + printk("\n"); + } + printk(KERN_EMERG "TSC %llx ", m->tsc); + if (m->addr) + printk("ADDR %llx ", m->addr); + if (m->misc) + printk("MISC %llx ", m->misc); + printk("\n"); + printk(KERN_EMERG "PROCESSOR %u:%x TIME %llu SOCKET %u APIC %x\n", + m->cpuvendor, m->cpuid, m->time, m->socketid, + m->apicid); +} + +static void print_mce_head(void) +{ + printk(KERN_EMERG "\n" KERN_EMERG "HARDWARE ERROR\n"); +} + +static void print_mce_tail(void) +{ + printk(KERN_EMERG "This is not a software problem!\n" + KERN_EMERG "Run through mcelog --ascii to decode and contact your hardware vendor\n"); +} + +#define PANIC_TIMEOUT 5 /* 5 seconds */ + +static atomic_t mce_paniced; + +/* Panic in progress. Enable interrupts and wait for final IPI */ +static void wait_for_panic(void) +{ + long timeout = PANIC_TIMEOUT*USEC_PER_SEC; + preempt_disable(); + local_irq_enable(); + while (timeout-- > 0) + udelay(1); + if (panic_timeout == 0) + panic_timeout = mce_panic_timeout; + panic("Panicing machine check CPU died"); +} + +static void mce_panic(char *msg, struct mce *final, char *exp) +{ + int i; + + /* + * Make sure only one CPU runs in machine check panic + */ + if (atomic_add_return(1, &mce_paniced) > 1) + wait_for_panic(); + barrier(); + + bust_spinlocks(1); + console_verbose(); + print_mce_head(); + /* First print corrected ones that are still unlogged */ + for (i = 0; i < MCE_LOG_LEN; i++) { + struct mce *m = &mcelog.entry[i]; + if (!(m->status & MCI_STATUS_VAL)) + continue; + if (!(m->status & MCI_STATUS_UC)) + print_mce(m); + } + /* Now print uncorrected but with the final one last */ + for (i = 0; i < MCE_LOG_LEN; i++) { + struct mce *m = &mcelog.entry[i]; + if (!(m->status & MCI_STATUS_VAL)) + continue; + if (!(m->status & MCI_STATUS_UC)) + continue; + if (!final || memcmp(m, final, sizeof(struct mce))) + print_mce(m); + } + if (final) + print_mce(final); + if (cpu_missing) + printk(KERN_EMERG "Some CPUs didn't answer in synchronization\n"); + print_mce_tail(); + if (exp) + printk(KERN_EMERG "Machine check: %s\n", exp); + if (panic_timeout == 0) + panic_timeout = mce_panic_timeout; + panic(msg); +} + +/* Support code for software error injection */ + +static int msr_to_offset(u32 msr) +{ + unsigned bank = __get_cpu_var(injectm.bank); + if (msr == rip_msr) + return offsetof(struct mce, ip); + if (msr == MSR_IA32_MC0_STATUS + bank*4) + return offsetof(struct mce, status); + if (msr == MSR_IA32_MC0_ADDR + bank*4) + return offsetof(struct mce, addr); + if (msr == MSR_IA32_MC0_MISC + bank*4) + return offsetof(struct mce, misc); + if (msr == MSR_IA32_MCG_STATUS) + return offsetof(struct mce, mcgstatus); + return -1; +} + +/* MSR access wrappers used for error injection */ +static u64 mce_rdmsrl(u32 msr) +{ + u64 v; + if (__get_cpu_var(injectm).finished) { + int offset = msr_to_offset(msr); + if (offset < 0) + return 0; + return *(u64 *)((char *)&__get_cpu_var(injectm) + offset); + } + rdmsrl(msr, v); + return v; +} + +static void mce_wrmsrl(u32 msr, u64 v) +{ + if (__get_cpu_var(injectm).finished) { + int offset = msr_to_offset(msr); + if (offset >= 0) + *(u64 *)((char *)&__get_cpu_var(injectm) + offset) = v; + return; + } + wrmsrl(msr, v); +} + +/* + * Simple lockless ring to communicate PFNs from the exception handler with the + * process context work function. This is vastly simplified because there's + * only a single reader and a single writer. + */ +#define MCE_RING_SIZE 16 /* we use one entry less */ + +struct mce_ring { + unsigned short start; + unsigned short end; + unsigned long ring[MCE_RING_SIZE]; +}; +static DEFINE_PER_CPU(struct mce_ring, mce_ring); + +/* Runs with CPU affinity in workqueue */ +static int mce_ring_empty(void) +{ + struct mce_ring *r = &__get_cpu_var(mce_ring); + + return r->start == r->end; +} + +static int mce_ring_get(unsigned long *pfn) +{ + struct mce_ring *r; + int ret = 0; + + *pfn = 0; + get_cpu(); + r = &__get_cpu_var(mce_ring); + if (r->start == r->end) + goto out; + *pfn = r->ring[r->start]; + r->start = (r->start + 1) % MCE_RING_SIZE; + ret = 1; +out: + put_cpu(); + return ret; +} + +/* Always runs in MCE context with preempt off */ +static int mce_ring_add(unsigned long pfn) +{ + struct mce_ring *r = &__get_cpu_var(mce_ring); + unsigned next; + + next = (r->end + 1) % MCE_RING_SIZE; + if (next == r->start) + return -1; + r->ring[r->end] = pfn; + wmb(); + r->end = next; + return 0; +} + +int mce_available(struct cpuinfo_x86 *c) +{ + if (mce_disabled) + return 0; + return cpu_has(c, X86_FEATURE_MCE) && cpu_has(c, X86_FEATURE_MCA); +} + +static void mce_schedule_work(void) +{ + if (!mce_ring_empty()) { + struct work_struct *work = &__get_cpu_var(mce_work); + if (!work_pending(work)) + schedule_work(work); + } +} + +/* + * Get the address of the instruction at the time of the machine check + * error. + */ +static inline void mce_get_rip(struct mce *m, struct pt_regs *regs) +{ + + if (regs && (m->mcgstatus & (MCG_STATUS_RIPV|MCG_STATUS_EIPV))) { + m->ip = regs->ip; + m->cs = regs->cs; + } else { + m->ip = 0; + m->cs = 0; + } + if (rip_msr) + m->ip = mce_rdmsrl(rip_msr); +} + +#ifdef CONFIG_X86_LOCAL_APIC +/* + * Called after interrupts have been reenabled again + * when a MCE happened during an interrupts off region + * in the kernel. + */ +asmlinkage void smp_mce_self_interrupt(struct pt_regs *regs) +{ + ack_APIC_irq(); + exit_idle(); + irq_enter(); + mce_notify_irq(); + mce_schedule_work(); + irq_exit(); +} +#endif + +static void mce_report_event(struct pt_regs *regs) +{ + if (regs->flags & (X86_VM_MASK|X86_EFLAGS_IF)) { + mce_notify_irq(); + /* + * Triggering the work queue here is just an insurance + * policy in case the syscall exit notify handler + * doesn't run soon enough or ends up running on the + * wrong CPU (can happen when audit sleeps) + */ + mce_schedule_work(); + return; + } + +#ifdef CONFIG_X86_LOCAL_APIC + /* + * Without APIC do not notify. The event will be picked + * up eventually. + */ + if (!cpu_has_apic) + return; + + /* + * When interrupts are disabled we cannot use + * kernel services safely. Trigger an self interrupt + * through the APIC to instead do the notification + * after interrupts are reenabled again. + */ + apic->send_IPI_self(MCE_SELF_VECTOR); + + /* + * Wait for idle afterwards again so that we don't leave the + * APIC in a non idle state because the normal APIC writes + * cannot exclude us. + */ + apic_wait_icr_idle(); +#endif +} + +DEFINE_PER_CPU(unsigned, mce_poll_count); + +/* + * Poll for corrected events or events that happened before reset. + * Those are just logged through /dev/mcelog. + * + * This is executed in standard interrupt context. + * + * Note: spec recommends to panic for fatal unsignalled + * errors here. However this would be quite problematic -- + * we would need to reimplement the Monarch handling and + * it would mess up the exclusion between exception handler + * and poll hander -- * so we skip this for now. + * These cases should not happen anyways, or only when the CPU + * is already totally * confused. In this case it's likely it will + * not fully execute the machine check handler either. + */ +void machine_check_poll(enum mcp_flags flags, mce_banks_t *b) +{ + struct mce m; + int i; + + __get_cpu_var(mce_poll_count)++; + + mce_setup(&m); + + m.mcgstatus = mce_rdmsrl(MSR_IA32_MCG_STATUS); + for (i = 0; i < banks; i++) { + if (!bank[i] || !test_bit(i, *b)) + continue; + + m.misc = 0; + m.addr = 0; + m.bank = i; + m.tsc = 0; + + barrier(); + m.status = mce_rdmsrl(MSR_IA32_MC0_STATUS + i*4); + if (!(m.status & MCI_STATUS_VAL)) + continue; + + /* + * Uncorrected or signalled events are handled by the exception + * handler when it is enabled, so don't process those here. + * + * TBD do the same check for MCI_STATUS_EN here? + */ + if (!(flags & MCP_UC) && + (m.status & (mce_ser ? MCI_STATUS_S : MCI_STATUS_UC))) + continue; + + if (m.status & MCI_STATUS_MISCV) + m.misc = mce_rdmsrl(MSR_IA32_MC0_MISC + i*4); + if (m.status & MCI_STATUS_ADDRV) + m.addr = mce_rdmsrl(MSR_IA32_MC0_ADDR + i*4); + + if (!(flags & MCP_TIMESTAMP)) + m.tsc = 0; + /* + * Don't get the IP here because it's unlikely to + * have anything to do with the actual error location. + */ + if (!(flags & MCP_DONTLOG) && !mce_dont_log_ce) { + mce_log(&m); + add_taint(TAINT_MACHINE_CHECK); + } + + /* + * Clear state for this bank. + */ + mce_wrmsrl(MSR_IA32_MC0_STATUS+4*i, 0); + } + + /* + * Don't clear MCG_STATUS here because it's only defined for + * exceptions. + */ + + sync_core(); +} +EXPORT_SYMBOL_GPL(machine_check_poll); + +/* + * Do a quick check if any of the events requires a panic. + * This decides if we keep the events around or clear them. + */ +static int mce_no_way_out(struct mce *m, char **msg) +{ + int i; + + for (i = 0; i < banks; i++) { + m->status = mce_rdmsrl(MSR_IA32_MC0_STATUS + i*4); + if (mce_severity(m, tolerant, msg) >= MCE_PANIC_SEVERITY) + return 1; + } + return 0; +} + +/* + * Variable to establish order between CPUs while scanning. + * Each CPU spins initially until executing is equal its number. + */ +static atomic_t mce_executing; + +/* + * Defines order of CPUs on entry. First CPU becomes Monarch. + */ +static atomic_t mce_callin; + +/* + * Check if a timeout waiting for other CPUs happened. + */ +static int mce_timed_out(u64 *t) +{ + /* + * The others already did panic for some reason. + * Bail out like in a timeout. + * rmb() to tell the compiler that system_state + * might have been modified by someone else. + */ + rmb(); + if (atomic_read(&mce_paniced)) + wait_for_panic(); + if (!monarch_timeout) + goto out; + if ((s64)*t < SPINUNIT) { + /* CHECKME: Make panic default for 1 too? */ + if (tolerant < 1) + mce_panic("Timeout synchronizing machine check over CPUs", + NULL, NULL); + cpu_missing = 1; + return 1; + } + *t -= SPINUNIT; +out: + touch_nmi_watchdog(); + return 0; +} + +/* + * The Monarch's reign. The Monarch is the CPU who entered + * the machine check handler first. It waits for the others to + * raise the exception too and then grades them. When any + * error is fatal panic. Only then let the others continue. + * + * The other CPUs entering the MCE handler will be controlled by the + * Monarch. They are called Subjects. + * + * This way we prevent any potential data corruption in a unrecoverable case + * and also makes sure always all CPU's errors are examined. + * + * Also this detects the case of an machine check event coming from outer + * space (not detected by any CPUs) In this case some external agent wants + * us to shut down, so panic too. + * + * The other CPUs might still decide to panic if the handler happens + * in a unrecoverable place, but in this case the system is in a semi-stable + * state and won't corrupt anything by itself. It's ok to let the others + * continue for a bit first. + * + * All the spin loops have timeouts; when a timeout happens a CPU + * typically elects itself to be Monarch. + */ +static void mce_reign(void) +{ + int cpu; + struct mce *m = NULL; + int global_worst = 0; + char *msg = NULL; + char *nmsg = NULL; + + /* + * This CPU is the Monarch and the other CPUs have run + * through their handlers. + * Grade the severity of the errors of all the CPUs. + */ + for_each_possible_cpu(cpu) { + int severity = mce_severity(&per_cpu(mces_seen, cpu), tolerant, + &nmsg); + if (severity > global_worst) { + msg = nmsg; + global_worst = severity; + m = &per_cpu(mces_seen, cpu); + } + } + + /* + * Cannot recover? Panic here then. + * This dumps all the mces in the log buffer and stops the + * other CPUs. + */ + if (m && global_worst >= MCE_PANIC_SEVERITY && tolerant < 3) + mce_panic("Fatal Machine check", m, msg); + + /* + * For UC somewhere we let the CPU who detects it handle it. + * Also must let continue the others, otherwise the handling + * CPU could deadlock on a lock. + */ + + /* + * No machine check event found. Must be some external + * source or one CPU is hung. Panic. + */ + if (!m && tolerant < 3) + mce_panic("Machine check from unknown source", NULL, NULL); + + /* + * Now clear all the mces_seen so that they don't reappear on + * the next mce. + */ + for_each_possible_cpu(cpu) + memset(&per_cpu(mces_seen, cpu), 0, sizeof(struct mce)); +} + +static atomic_t global_nwo; + +/* + * Start of Monarch synchronization. This waits until all CPUs have + * entered the exception handler and then determines if any of them + * saw a fatal event that requires panic. Then it executes them + * in the entry order. + * TBD double check parallel CPU hotunplug + */ +static int mce_start(int *no_way_out) +{ + int order; + int cpus = num_online_cpus(); + u64 timeout = (u64)monarch_timeout * NSEC_PER_USEC; + + if (!timeout) + return -1; + + atomic_add(*no_way_out, &global_nwo); + /* + * global_nwo should be updated before mce_callin + */ + smp_wmb(); + order = atomic_add_return(1, &mce_callin); + + /* + * Wait for everyone. + */ + while (atomic_read(&mce_callin) != cpus) { + if (mce_timed_out(&timeout)) { + atomic_set(&global_nwo, 0); + return -1; + } + ndelay(SPINUNIT); + } + + /* + * mce_callin should be read before global_nwo + */ + smp_rmb(); + + if (order == 1) { + /* + * Monarch: Starts executing now, the others wait. + */ + atomic_set(&mce_executing, 1); + } else { + /* + * Subject: Now start the scanning loop one by one in + * the original callin order. + * This way when there are any shared banks it will be + * only seen by one CPU before cleared, avoiding duplicates. + */ + while (atomic_read(&mce_executing) < order) { + if (mce_timed_out(&timeout)) { + atomic_set(&global_nwo, 0); + return -1; + } + ndelay(SPINUNIT); + } + } + + /* + * Cache the global no_way_out state. + */ + *no_way_out = atomic_read(&global_nwo); + + return order; +} + +/* + * Synchronize between CPUs after main scanning loop. + * This invokes the bulk of the Monarch processing. + */ +static int mce_end(int order) +{ + int ret = -1; + u64 timeout = (u64)monarch_timeout * NSEC_PER_USEC; + + if (!timeout) + goto reset; + if (order < 0) + goto reset; + + /* + * Allow others to run. + */ + atomic_inc(&mce_executing); + + if (order == 1) { + /* CHECKME: Can this race with a parallel hotplug? */ + int cpus = num_online_cpus(); + + /* + * Monarch: Wait for everyone to go through their scanning + * loops. + */ + while (atomic_read(&mce_executing) <= cpus) { + if (mce_timed_out(&timeout)) + goto reset; + ndelay(SPINUNIT); + } + + mce_reign(); + barrier(); + ret = 0; + } else { + /* + * Subject: Wait for Monarch to finish. + */ + while (atomic_read(&mce_executing) != 0) { + if (mce_timed_out(&timeout)) + goto reset; + ndelay(SPINUNIT); + } + + /* + * Don't reset anything. That's done by the Monarch. + */ + return 0; + } + + /* + * Reset all global state. + */ +reset: + atomic_set(&global_nwo, 0); + atomic_set(&mce_callin, 0); + barrier(); + + /* + * Let others run again. + */ + atomic_set(&mce_executing, 0); + return ret; +} + +/* + * Check if the address reported by the CPU is in a format we can parse. + * It would be possible to add code for most other cases, but all would + * be somewhat complicated (e.g. segment offset would require an instruction + * parser). So only support physical addresses upto page granuality for now. + */ +static int mce_usable_address(struct mce *m) +{ + if (!(m->status & MCI_STATUS_MISCV) || !(m->status & MCI_STATUS_ADDRV)) + return 0; + if ((m->misc & 0x3f) > PAGE_SHIFT) + return 0; + if (((m->misc >> 6) & 7) != MCM_ADDR_PHYS) + return 0; + return 1; +} + +static void mce_clear_state(unsigned long *toclear) +{ + int i; + + for (i = 0; i < banks; i++) { + if (test_bit(i, toclear)) + mce_wrmsrl(MSR_IA32_MC0_STATUS+4*i, 0); + } +} + +/* + * The actual machine check handler. This only handles real + * exceptions when something got corrupted coming in through int 18. + * + * This is executed in NMI context not subject to normal locking rules. This + * implies that most kernel services cannot be safely used. Don't even + * think about putting a printk in there! + * + * On Intel systems this is entered on all CPUs in parallel through + * MCE broadcast. However some CPUs might be broken beyond repair, + * so be always careful when synchronizing with others. + */ +void do_machine_check(struct pt_regs *regs, long error_code) +{ + struct mce m, *final; + int i; + int worst = 0; + int severity; + /* + * Establish sequential order between the CPUs entering the machine + * check handler. + */ + int order; + /* + * If no_way_out gets set, there is no safe way to recover from this + * MCE. If tolerant is cranked up, we'll try anyway. + */ + int no_way_out = 0; + /* + * If kill_it gets set, there might be a way to recover from this + * error. + */ + int kill_it = 0; + DECLARE_BITMAP(toclear, MAX_NR_BANKS); + char *msg = "Unknown"; + + atomic_inc(&mce_entry); + + __get_cpu_var(mce_exception_count)++; + + if (notify_die(DIE_NMI, "machine check", regs, error_code, + 18, SIGKILL) == NOTIFY_STOP) + goto out; + if (!banks) + goto out; + + mce_setup(&m); + + m.mcgstatus = mce_rdmsrl(MSR_IA32_MCG_STATUS); + no_way_out = mce_no_way_out(&m, &msg); + + final = &__get_cpu_var(mces_seen); + *final = m; + + barrier(); + + /* + * When no restart IP must always kill or panic. + */ + if (!(m.mcgstatus & MCG_STATUS_RIPV)) + kill_it = 1; + + /* + * Go through all the banks in exclusion of the other CPUs. + * This way we don't report duplicated events on shared banks + * because the first one to see it will clear it. + */ + order = mce_start(&no_way_out); + for (i = 0; i < banks; i++) { + __clear_bit(i, toclear); + if (!bank[i]) + continue; + + m.misc = 0; + m.addr = 0; + m.bank = i; + + m.status = mce_rdmsrl(MSR_IA32_MC0_STATUS + i*4); + if ((m.status & MCI_STATUS_VAL) == 0) + continue; + + /* + * Non uncorrected or non signaled errors are handled by + * machine_check_poll. Leave them alone, unless this panics. + */ + if (!(m.status & (mce_ser ? MCI_STATUS_S : MCI_STATUS_UC)) && + !no_way_out) + continue; + + /* + * Set taint even when machine check was not enabled. + */ + add_taint(TAINT_MACHINE_CHECK); + + severity = mce_severity(&m, tolerant, NULL); + + /* + * When machine check was for corrected handler don't touch, + * unless we're panicing. + */ + if (severity == MCE_KEEP_SEVERITY && !no_way_out) + continue; + __set_bit(i, toclear); + if (severity == MCE_NO_SEVERITY) { + /* + * Machine check event was not enabled. Clear, but + * ignore. + */ + continue; + } + + /* + * Kill on action required. + */ + if (severity == MCE_AR_SEVERITY) + kill_it = 1; + + if (m.status & MCI_STATUS_MISCV) + m.misc = mce_rdmsrl(MSR_IA32_MC0_MISC + i*4); + if (m.status & MCI_STATUS_ADDRV) + m.addr = mce_rdmsrl(MSR_IA32_MC0_ADDR + i*4); + + /* + * Action optional error. Queue address for later processing. + * When the ring overflows we just ignore the AO error. + * RED-PEN add some logging mechanism when + * usable_address or mce_add_ring fails. + * RED-PEN don't ignore overflow for tolerant == 0 + */ + if (severity == MCE_AO_SEVERITY && mce_usable_address(&m)) + mce_ring_add(m.addr >> PAGE_SHIFT); + + mce_get_rip(&m, regs); + mce_log(&m); + + if (severity > worst) { + *final = m; + worst = severity; + } + } + + if (!no_way_out) + mce_clear_state(toclear); + + /* + * Do most of the synchronization with other CPUs. + * When there's any problem use only local no_way_out state. + */ + if (mce_end(order) < 0) + no_way_out = worst >= MCE_PANIC_SEVERITY; + + /* + * If we have decided that we just CAN'T continue, and the user + * has not set tolerant to an insane level, give up and die. + * + * This is mainly used in the case when the system doesn't + * support MCE broadcasting or it has been disabled. + */ + if (no_way_out && tolerant < 3) + mce_panic("Fatal machine check on current CPU", final, msg); + + /* + * If the error seems to be unrecoverable, something should be + * done. Try to kill as little as possible. If we can kill just + * one task, do that. If the user has set the tolerance very + * high, don't try to do anything at all. + */ + + if (kill_it && tolerant < 3) + force_sig(SIGBUS, current); + + /* notify userspace ASAP */ + set_thread_flag(TIF_MCE_NOTIFY); + + if (worst > 0) + mce_report_event(regs); + mce_wrmsrl(MSR_IA32_MCG_STATUS, 0); +out: + atomic_dec(&mce_entry); + sync_core(); +} +EXPORT_SYMBOL_GPL(do_machine_check); + +/* dummy to break dependency. actual code is in mm/memory-failure.c */ +void __attribute__((weak)) memory_failure(unsigned long pfn, int vector) +{ + printk(KERN_ERR "Action optional memory failure at %lx ignored\n", pfn); +} + +/* + * Called after mce notification in process context. This code + * is allowed to sleep. Call the high level VM handler to process + * any corrupted pages. + * Assume that the work queue code only calls this one at a time + * per CPU. + * Note we don't disable preemption, so this code might run on the wrong + * CPU. In this case the event is picked up by the scheduled work queue. + * This is merely a fast path to expedite processing in some common + * cases. + */ +void mce_notify_process(void) +{ + unsigned long pfn; + mce_notify_irq(); + while (mce_ring_get(&pfn)) + memory_failure(pfn, MCE_VECTOR); +} + +static void mce_process_work(struct work_struct *dummy) +{ + mce_notify_process(); +} + +#ifdef CONFIG_X86_MCE_INTEL +/*** + * mce_log_therm_throt_event - Logs the thermal throttling event to mcelog + * @cpu: The CPU on which the event occurred. + * @status: Event status information + * + * This function should be called by the thermal interrupt after the + * event has been processed and the decision was made to log the event + * further. + * + * The status parameter will be saved to the 'status' field of 'struct mce' + * and historically has been the register value of the + * MSR_IA32_THERMAL_STATUS (Intel) msr. + */ +void mce_log_therm_throt_event(__u64 status) +{ + struct mce m; + + mce_setup(&m); + m.bank = MCE_THERMAL_BANK; + m.status = status; + mce_log(&m); +} +#endif /* CONFIG_X86_MCE_INTEL */ + +/* + * Periodic polling timer for "silent" machine check errors. If the + * poller finds an MCE, poll 2x faster. When the poller finds no more + * errors, poll 2x slower (up to check_interval seconds). + */ +static int check_interval = 5 * 60; /* 5 minutes */ + +static DEFINE_PER_CPU(int, next_interval); /* in jiffies */ +static DEFINE_PER_CPU(struct timer_list, mce_timer); + +static void mcheck_timer(unsigned long data) +{ + struct timer_list *t = &per_cpu(mce_timer, data); + int *n; + + WARN_ON(smp_processor_id() != data); + + if (mce_available(¤t_cpu_data)) { + machine_check_poll(MCP_TIMESTAMP, + &__get_cpu_var(mce_poll_banks)); + } + + /* + * Alert userspace if needed. If we logged an MCE, reduce the + * polling interval, otherwise increase the polling interval. + */ + n = &__get_cpu_var(next_interval); + if (mce_notify_irq()) + *n = max(*n/2, HZ/100); + else + *n = min(*n*2, (int)round_jiffies_relative(check_interval*HZ)); + + t->expires = jiffies + *n; + add_timer(t); +} + +static void mce_do_trigger(struct work_struct *work) +{ + call_usermodehelper(mce_helper, mce_helper_argv, NULL, UMH_NO_WAIT); +} + +static DECLARE_WORK(mce_trigger_work, mce_do_trigger); + +/* + * Notify the user(s) about new machine check events. + * Can be called from interrupt context, but not from machine check/NMI + * context. + */ +int mce_notify_irq(void) +{ + /* Not more than two messages every minute */ + static DEFINE_RATELIMIT_STATE(ratelimit, 60*HZ, 2); + + clear_thread_flag(TIF_MCE_NOTIFY); + + if (test_and_clear_bit(0, &mce_need_notify)) { + wake_up_interruptible(&mce_wait); + + /* + * There is no risk of missing notifications because + * work_pending is always cleared before the function is + * executed. + */ + if (mce_helper[0] && !work_pending(&mce_trigger_work)) + schedule_work(&mce_trigger_work); + + if (__ratelimit(&ratelimit)) + printk(KERN_INFO "Machine check events logged\n"); + + return 1; + } + return 0; +} +EXPORT_SYMBOL_GPL(mce_notify_irq); + +/* + * Initialize Machine Checks for a CPU. + */ +static int mce_cap_init(void) +{ + unsigned b; + u64 cap; + + rdmsrl(MSR_IA32_MCG_CAP, cap); + + b = cap & MCG_BANKCNT_MASK; + printk(KERN_INFO "mce: CPU supports %d MCE banks\n", b); + + if (b > MAX_NR_BANKS) { + printk(KERN_WARNING + "MCE: Using only %u machine check banks out of %u\n", + MAX_NR_BANKS, b); + b = MAX_NR_BANKS; + } + + /* Don't support asymmetric configurations today */ + WARN_ON(banks != 0 && b != banks); + banks = b; + if (!bank) { + bank = kmalloc(banks * sizeof(u64), GFP_KERNEL); + if (!bank) + return -ENOMEM; + memset(bank, 0xff, banks * sizeof(u64)); + } + + /* Use accurate RIP reporting if available. */ + if ((cap & MCG_EXT_P) && MCG_EXT_CNT(cap) >= 9) + rip_msr = MSR_IA32_MCG_EIP; + + if (cap & MCG_SER_P) + mce_ser = 1; + + return 0; +} + +static void mce_init(void) +{ + mce_banks_t all_banks; + u64 cap; + int i; + + /* + * Log the machine checks left over from the previous reset. + */ + bitmap_fill(all_banks, MAX_NR_BANKS); + machine_check_poll(MCP_UC|(!mce_bootlog ? MCP_DONTLOG : 0), &all_banks); + + set_in_cr4(X86_CR4_MCE); + + rdmsrl(MSR_IA32_MCG_CAP, cap); + if (cap & MCG_CTL_P) + wrmsr(MSR_IA32_MCG_CTL, 0xffffffff, 0xffffffff); + + for (i = 0; i < banks; i++) { + if (skip_bank_init(i)) + continue; + wrmsrl(MSR_IA32_MC0_CTL+4*i, bank[i]); + wrmsrl(MSR_IA32_MC0_STATUS+4*i, 0); + } +} + +/* Add per CPU specific workarounds here */ +static void mce_cpu_quirks(struct cpuinfo_x86 *c) +{ + /* This should be disabled by the BIOS, but isn't always */ + if (c->x86_vendor == X86_VENDOR_AMD) { + if (c->x86 == 15 && banks > 4) { + /* + * disable GART TBL walk error reporting, which + * trips off incorrectly with the IOMMU & 3ware + * & Cerberus: + */ + clear_bit(10, (unsigned long *)&bank[4]); + } + if (c->x86 <= 17 && mce_bootlog < 0) { + /* + * Lots of broken BIOS around that don't clear them + * by default and leave crap in there. Don't log: + */ + mce_bootlog = 0; + } + /* + * Various K7s with broken bank 0 around. Always disable + * by default. + */ + if (c->x86 == 6 && banks > 0) + bank[0] = 0; + } + + if (c->x86_vendor == X86_VENDOR_INTEL) { + /* + * SDM documents that on family 6 bank 0 should not be written + * because it aliases to another special BIOS controlled + * register. + * But it's not aliased anymore on model 0x1a+ + * Don't ignore bank 0 completely because there could be a + * valid event later, merely don't write CTL0. + */ + + if (c->x86 == 6 && c->x86_model < 0x1A) + __set_bit(0, &dont_init_banks); + + /* + * All newer Intel systems support MCE broadcasting. Enable + * synchronization with a one second timeout. + */ + if ((c->x86 > 6 || (c->x86 == 6 && c->x86_model >= 0xe)) && + monarch_timeout < 0) + monarch_timeout = USEC_PER_SEC; + } + if (monarch_timeout < 0) + monarch_timeout = 0; + if (mce_bootlog != 0) + mce_panic_timeout = 30; +} + +static void __cpuinit mce_ancient_init(struct cpuinfo_x86 *c) +{ + if (c->x86 != 5) + return; + switch (c->x86_vendor) { + case X86_VENDOR_INTEL: + intel_p5_mcheck_init(c); + break; + case X86_VENDOR_CENTAUR: + winchip_mcheck_init(c); + break; + } +} + +static void mce_cpu_features(struct cpuinfo_x86 *c) +{ + switch (c->x86_vendor) { + case X86_VENDOR_INTEL: + mce_intel_feature_init(c); + break; + case X86_VENDOR_AMD: + mce_amd_feature_init(c); + break; + default: + break; + } +} + +static void mce_init_timer(void) +{ + struct timer_list *t = &__get_cpu_var(mce_timer); + int *n = &__get_cpu_var(next_interval); + + if (mce_ignore_ce) + return; + + *n = check_interval * HZ; + if (!*n) + return; + setup_timer(t, mcheck_timer, smp_processor_id()); + t->expires = round_jiffies(jiffies + *n); + add_timer(t); +} + +/* + * Called for each booted CPU to set up machine checks. + * Must be called with preempt off: + */ +void __cpuinit mcheck_init(struct cpuinfo_x86 *c) +{ + if (mce_disabled) + return; + + mce_ancient_init(c); + + if (!mce_available(c)) + return; + + if (mce_cap_init() < 0) { + mce_disabled = 1; + return; + } + mce_cpu_quirks(c); + + machine_check_vector = do_machine_check; + + mce_init(); + mce_cpu_features(c); + mce_init_timer(); + INIT_WORK(&__get_cpu_var(mce_work), mce_process_work); +} + +/* + * Character device to read and clear the MCE log. + */ + +static DEFINE_SPINLOCK(mce_state_lock); +static int open_count; /* #times opened */ +static int open_exclu; /* already open exclusive? */ + +static int mce_open(struct inode *inode, struct file *file) +{ + spin_lock(&mce_state_lock); + + if (open_exclu || (open_count && (file->f_flags & O_EXCL))) { + spin_unlock(&mce_state_lock); + + return -EBUSY; + } + + if (file->f_flags & O_EXCL) + open_exclu = 1; + open_count++; + + spin_unlock(&mce_state_lock); + + return nonseekable_open(inode, file); +} + +static int mce_release(struct inode *inode, struct file *file) +{ + spin_lock(&mce_state_lock); + + open_count--; + open_exclu = 0; + + spin_unlock(&mce_state_lock); + + return 0; +} + +static void collect_tscs(void *data) +{ + unsigned long *cpu_tsc = (unsigned long *)data; + + rdtscll(cpu_tsc[smp_processor_id()]); +} + +static DEFINE_MUTEX(mce_read_mutex); + +static ssize_t mce_read(struct file *filp, char __user *ubuf, size_t usize, + loff_t *off) +{ + char __user *buf = ubuf; + unsigned long *cpu_tsc; + unsigned prev, next; + int i, err; + + cpu_tsc = kmalloc(nr_cpu_ids * sizeof(long), GFP_KERNEL); + if (!cpu_tsc) + return -ENOMEM; + + mutex_lock(&mce_read_mutex); + next = rcu_dereference(mcelog.next); + + /* Only supports full reads right now */ + if (*off != 0 || usize < MCE_LOG_LEN*sizeof(struct mce)) { + mutex_unlock(&mce_read_mutex); + kfree(cpu_tsc); + + return -EINVAL; + } + + err = 0; + prev = 0; + do { + for (i = prev; i < next; i++) { + unsigned long start = jiffies; + + while (!mcelog.entry[i].finished) { + if (time_after_eq(jiffies, start + 2)) { + memset(mcelog.entry + i, 0, + sizeof(struct mce)); + goto timeout; + } + cpu_relax(); + } + smp_rmb(); + err |= copy_to_user(buf, mcelog.entry + i, + sizeof(struct mce)); + buf += sizeof(struct mce); +timeout: + ; + } + + memset(mcelog.entry + prev, 0, + (next - prev) * sizeof(struct mce)); + prev = next; + next = cmpxchg(&mcelog.next, prev, 0); + } while (next != prev); + + synchronize_sched(); + + /* + * Collect entries that were still getting written before the + * synchronize. + */ + on_each_cpu(collect_tscs, cpu_tsc, 1); + + for (i = next; i < MCE_LOG_LEN; i++) { + if (mcelog.entry[i].finished && + mcelog.entry[i].tsc < cpu_tsc[mcelog.entry[i].cpu]) { + err |= copy_to_user(buf, mcelog.entry+i, + sizeof(struct mce)); + smp_rmb(); + buf += sizeof(struct mce); + memset(&mcelog.entry[i], 0, sizeof(struct mce)); + } + } + mutex_unlock(&mce_read_mutex); + kfree(cpu_tsc); + + return err ? -EFAULT : buf - ubuf; +} + +static unsigned int mce_poll(struct file *file, poll_table *wait) +{ + poll_wait(file, &mce_wait, wait); + if (rcu_dereference(mcelog.next)) + return POLLIN | POLLRDNORM; + return 0; +} + +static long mce_ioctl(struct file *f, unsigned int cmd, unsigned long arg) +{ + int __user *p = (int __user *)arg; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + switch (cmd) { + case MCE_GET_RECORD_LEN: + return put_user(sizeof(struct mce), p); + case MCE_GET_LOG_LEN: + return put_user(MCE_LOG_LEN, p); + case MCE_GETCLEAR_FLAGS: { + unsigned flags; + + do { + flags = mcelog.flags; + } while (cmpxchg(&mcelog.flags, flags, 0) != flags); + + return put_user(flags, p); + } + default: + return -ENOTTY; + } +} + +/* Modified in mce-inject.c, so not static or const */ +struct file_operations mce_chrdev_ops = { + .open = mce_open, + .release = mce_release, + .read = mce_read, + .poll = mce_poll, + .unlocked_ioctl = mce_ioctl, +}; +EXPORT_SYMBOL_GPL(mce_chrdev_ops); + +static struct miscdevice mce_log_device = { + MISC_MCELOG_MINOR, + "mcelog", + &mce_chrdev_ops, +}; + +/* + * mce=off Disables machine check + * mce=no_cmci Disables CMCI + * mce=dont_log_ce Clears corrected events silently, no log created for CEs. + * mce=ignore_ce Disables polling and CMCI, corrected events are not cleared. + * mce=TOLERANCELEVEL[,monarchtimeout] (number, see above) + * monarchtimeout is how long to wait for other CPUs on machine + * check, or 0 to not wait + * mce=bootlog Log MCEs from before booting. Disabled by default on AMD. + * mce=nobootlog Don't log MCEs from before booting. + */ +static int __init mcheck_enable(char *str) +{ + if (*str == 0) + enable_p5_mce(); + if (*str == '=') + str++; + if (!strcmp(str, "off")) + mce_disabled = 1; + else if (!strcmp(str, "no_cmci")) + mce_cmci_disabled = 1; + else if (!strcmp(str, "dont_log_ce")) + mce_dont_log_ce = 1; + else if (!strcmp(str, "ignore_ce")) + mce_ignore_ce = 1; + else if (!strcmp(str, "bootlog") || !strcmp(str, "nobootlog")) + mce_bootlog = (str[0] == 'b'); + else if (isdigit(str[0])) { + get_option(&str, &tolerant); + if (*str == ',') { + ++str; + get_option(&str, &monarch_timeout); + } + } else { + printk(KERN_INFO "mce argument %s ignored. Please use /sys\n", + str); + return 0; + } + return 1; +} +__setup("mce", mcheck_enable); + +/* + * Sysfs support + */ + +/* + * Disable machine checks on suspend and shutdown. We can't really handle + * them later. + */ +static int mce_disable(void) +{ + int i; + + for (i = 0; i < banks; i++) { + if (!skip_bank_init(i)) + wrmsrl(MSR_IA32_MC0_CTL + i*4, 0); + } + return 0; +} + +static int mce_suspend(struct sys_device *dev, pm_message_t state) +{ + return mce_disable(); +} + +static int mce_shutdown(struct sys_device *dev) +{ + return mce_disable(); +} + +/* + * On resume clear all MCE state. Don't want to see leftovers from the BIOS. + * Only one CPU is active at this time, the others get re-added later using + * CPU hotplug: + */ +static int mce_resume(struct sys_device *dev) +{ + mce_init(); + mce_cpu_features(¤t_cpu_data); + + return 0; +} + +static void mce_cpu_restart(void *data) +{ + del_timer_sync(&__get_cpu_var(mce_timer)); + if (!mce_available(¤t_cpu_data)) + return; + mce_init(); + mce_init_timer(); +} + +/* Reinit MCEs after user configuration changes */ +static void mce_restart(void) +{ + on_each_cpu(mce_cpu_restart, NULL, 1); +} + +/* Toggle features for corrected errors */ +static void mce_disable_ce(void *all) +{ + if (!mce_available(¤t_cpu_data)) + return; + if (all) + del_timer_sync(&__get_cpu_var(mce_timer)); + cmci_clear(); +} + +static void mce_enable_ce(void *all) +{ + if (!mce_available(¤t_cpu_data)) + return; + cmci_reenable(); + cmci_recheck(); + if (all) + mce_init_timer(); +} + +static struct sysdev_class mce_sysclass = { + .suspend = mce_suspend, + .shutdown = mce_shutdown, + .resume = mce_resume, + .name = "machinecheck", +}; + +DEFINE_PER_CPU(struct sys_device, mce_dev); + +__cpuinitdata +void (*threshold_cpu_callback)(unsigned long action, unsigned int cpu); + +static struct sysdev_attribute *bank_attrs; + +static ssize_t show_bank(struct sys_device *s, struct sysdev_attribute *attr, + char *buf) +{ + u64 b = bank[attr - bank_attrs]; + + return sprintf(buf, "%llx\n", b); +} + +static ssize_t set_bank(struct sys_device *s, struct sysdev_attribute *attr, + const char *buf, size_t size) +{ + u64 new; + + if (strict_strtoull(buf, 0, &new) < 0) + return -EINVAL; + + bank[attr - bank_attrs] = new; + mce_restart(); + + return size; +} + +static ssize_t +show_trigger(struct sys_device *s, struct sysdev_attribute *attr, char *buf) +{ + strcpy(buf, mce_helper); + strcat(buf, "\n"); + return strlen(mce_helper) + 1; +} + +static ssize_t set_trigger(struct sys_device *s, struct sysdev_attribute *attr, + const char *buf, size_t siz) +{ + char *p; + int len; + + strncpy(mce_helper, buf, sizeof(mce_helper)); + mce_helper[sizeof(mce_helper)-1] = 0; + len = strlen(mce_helper); + p = strchr(mce_helper, '\n'); + + if (*p) + *p = 0; + + return len; +} + +static ssize_t set_ignore_ce(struct sys_device *s, + struct sysdev_attribute *attr, + const char *buf, size_t size) +{ + u64 new; + + if (strict_strtoull(buf, 0, &new) < 0) + return -EINVAL; + + if (mce_ignore_ce ^ !!new) { + if (new) { + /* disable ce features */ + on_each_cpu(mce_disable_ce, (void *)1, 1); + mce_ignore_ce = 1; + } else { + /* enable ce features */ + mce_ignore_ce = 0; + on_each_cpu(mce_enable_ce, (void *)1, 1); + } + } + return size; +} + +static ssize_t set_cmci_disabled(struct sys_device *s, + struct sysdev_attribute *attr, + const char *buf, size_t size) +{ + u64 new; + + if (strict_strtoull(buf, 0, &new) < 0) + return -EINVAL; + + if (mce_cmci_disabled ^ !!new) { + if (new) { + /* disable cmci */ + on_each_cpu(mce_disable_ce, NULL, 1); + mce_cmci_disabled = 1; + } else { + /* enable cmci */ + mce_cmci_disabled = 0; + on_each_cpu(mce_enable_ce, NULL, 1); + } + } + return size; +} + +static ssize_t store_int_with_restart(struct sys_device *s, + struct sysdev_attribute *attr, + const char *buf, size_t size) +{ + ssize_t ret = sysdev_store_int(s, attr, buf, size); + mce_restart(); + return ret; +} + +static SYSDEV_ATTR(trigger, 0644, show_trigger, set_trigger); +static SYSDEV_INT_ATTR(tolerant, 0644, tolerant); +static SYSDEV_INT_ATTR(monarch_timeout, 0644, monarch_timeout); +static SYSDEV_INT_ATTR(dont_log_ce, 0644, mce_dont_log_ce); + +static struct sysdev_ext_attribute attr_check_interval = { + _SYSDEV_ATTR(check_interval, 0644, sysdev_show_int, + store_int_with_restart), + &check_interval +}; + +static struct sysdev_ext_attribute attr_ignore_ce = { + _SYSDEV_ATTR(ignore_ce, 0644, sysdev_show_int, set_ignore_ce), + &mce_ignore_ce +}; + +static struct sysdev_ext_attribute attr_cmci_disabled = { + _SYSDEV_ATTR(cmci_disabled, 0644, sysdev_show_int, set_cmci_disabled), + &mce_cmci_disabled +}; + +static struct sysdev_attribute *mce_attrs[] = { + &attr_tolerant.attr, + &attr_check_interval.attr, + &attr_trigger, + &attr_monarch_timeout.attr, + &attr_dont_log_ce.attr, + &attr_ignore_ce.attr, + &attr_cmci_disabled.attr, + NULL +}; + +static cpumask_var_t mce_dev_initialized; + +/* Per cpu sysdev init. All of the cpus still share the same ctrl bank: */ +static __cpuinit int mce_create_device(unsigned int cpu) +{ + int err; + int i, j; + + if (!mce_available(&boot_cpu_data)) + return -EIO; + + memset(&per_cpu(mce_dev, cpu).kobj, 0, sizeof(struct kobject)); + per_cpu(mce_dev, cpu).id = cpu; + per_cpu(mce_dev, cpu).cls = &mce_sysclass; + + err = sysdev_register(&per_cpu(mce_dev, cpu)); + if (err) + return err; + + for (i = 0; mce_attrs[i]; i++) { + err = sysdev_create_file(&per_cpu(mce_dev, cpu), mce_attrs[i]); + if (err) + goto error; + } + for (j = 0; j < banks; j++) { + err = sysdev_create_file(&per_cpu(mce_dev, cpu), + &bank_attrs[j]); + if (err) + goto error2; + } + cpumask_set_cpu(cpu, mce_dev_initialized); + + return 0; +error2: + while (--j >= 0) + sysdev_remove_file(&per_cpu(mce_dev, cpu), &bank_attrs[j]); +error: + while (--i >= 0) + sysdev_remove_file(&per_cpu(mce_dev, cpu), mce_attrs[i]); + + sysdev_unregister(&per_cpu(mce_dev, cpu)); + + return err; +} + +static __cpuinit void mce_remove_device(unsigned int cpu) +{ + int i; + + if (!cpumask_test_cpu(cpu, mce_dev_initialized)) + return; + + for (i = 0; mce_attrs[i]; i++) + sysdev_remove_file(&per_cpu(mce_dev, cpu), mce_attrs[i]); + + for (i = 0; i < banks; i++) + sysdev_remove_file(&per_cpu(mce_dev, cpu), &bank_attrs[i]); + + sysdev_unregister(&per_cpu(mce_dev, cpu)); + cpumask_clear_cpu(cpu, mce_dev_initialized); +} + +/* Make sure there are no machine checks on offlined CPUs. */ +static void mce_disable_cpu(void *h) +{ + unsigned long action = *(unsigned long *)h; + int i; + + if (!mce_available(¤t_cpu_data)) + return; + if (!(action & CPU_TASKS_FROZEN)) + cmci_clear(); + for (i = 0; i < banks; i++) { + if (!skip_bank_init(i)) + wrmsrl(MSR_IA32_MC0_CTL + i*4, 0); + } +} + +static void mce_reenable_cpu(void *h) +{ + unsigned long action = *(unsigned long *)h; + int i; + + if (!mce_available(¤t_cpu_data)) + return; + + if (!(action & CPU_TASKS_FROZEN)) + cmci_reenable(); + for (i = 0; i < banks; i++) { + if (!skip_bank_init(i)) + wrmsrl(MSR_IA32_MC0_CTL + i*4, bank[i]); + } +} + +/* Get notified when a cpu comes on/off. Be hotplug friendly. */ +static int __cpuinit +mce_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) +{ + unsigned int cpu = (unsigned long)hcpu; + struct timer_list *t = &per_cpu(mce_timer, cpu); + + switch (action) { + case CPU_ONLINE: + case CPU_ONLINE_FROZEN: + mce_create_device(cpu); + if (threshold_cpu_callback) + threshold_cpu_callback(action, cpu); + break; + case CPU_DEAD: + case CPU_DEAD_FROZEN: + if (threshold_cpu_callback) + threshold_cpu_callback(action, cpu); + mce_remove_device(cpu); + break; + case CPU_DOWN_PREPARE: + case CPU_DOWN_PREPARE_FROZEN: + del_timer_sync(t); + smp_call_function_single(cpu, mce_disable_cpu, &action, 1); + break; + case CPU_DOWN_FAILED: + case CPU_DOWN_FAILED_FROZEN: + t->expires = round_jiffies(jiffies + + __get_cpu_var(next_interval)); + add_timer_on(t, cpu); + smp_call_function_single(cpu, mce_reenable_cpu, &action, 1); + break; + case CPU_POST_DEAD: + /* intentionally ignoring frozen here */ + cmci_rediscover(cpu); + break; + } + return NOTIFY_OK; +} + +static struct notifier_block mce_cpu_notifier __cpuinitdata = { + .notifier_call = mce_cpu_callback, +}; + +static __init int mce_init_banks(void) +{ + int i; + + bank_attrs = kzalloc(sizeof(struct sysdev_attribute) * banks, + GFP_KERNEL); + if (!bank_attrs) + return -ENOMEM; + + for (i = 0; i < banks; i++) { + struct sysdev_attribute *a = &bank_attrs[i]; + + a->attr.name = kasprintf(GFP_KERNEL, "bank%d", i); + if (!a->attr.name) + goto nomem; + + a->attr.mode = 0644; + a->show = show_bank; + a->store = set_bank; + } + return 0; + +nomem: + while (--i >= 0) + kfree(bank_attrs[i].attr.name); + kfree(bank_attrs); + bank_attrs = NULL; + + return -ENOMEM; +} + +static __init int mce_init_device(void) +{ + int err; + int i = 0; + + if (!mce_available(&boot_cpu_data)) + return -EIO; + + zalloc_cpumask_var(&mce_dev_initialized, GFP_KERNEL); + + err = mce_init_banks(); + if (err) + return err; + + err = sysdev_class_register(&mce_sysclass); + if (err) + return err; + + for_each_online_cpu(i) { + err = mce_create_device(i); + if (err) + return err; + } + + register_hotcpu_notifier(&mce_cpu_notifier); + misc_register(&mce_log_device); + + return err; +} + +device_initcall(mce_init_device); + +#else /* CONFIG_X86_OLD_MCE: */ + +int nr_mce_banks; +EXPORT_SYMBOL_GPL(nr_mce_banks); /* non-fatal.o */ + +/* This has to be run for each processor */ +void mcheck_init(struct cpuinfo_x86 *c) +{ + if (mce_disabled) + return; + + switch (c->x86_vendor) { + case X86_VENDOR_AMD: + amd_mcheck_init(c); + break; + + case X86_VENDOR_INTEL: + if (c->x86 == 5) + intel_p5_mcheck_init(c); + if (c->x86 == 6) + intel_p6_mcheck_init(c); + if (c->x86 == 15) + intel_p4_mcheck_init(c); + break; + + case X86_VENDOR_CENTAUR: + if (c->x86 == 5) + winchip_mcheck_init(c); + break; + + default: + break; + } + printk(KERN_INFO "mce: CPU supports %d MCE banks\n", nr_mce_banks); +} + +static int __init mcheck_enable(char *str) +{ + mce_p5_enabled = 1; + return 1; +} +__setup("mce", mcheck_enable); + +#endif /* CONFIG_X86_OLD_MCE */ + +/* + * Old style boot options parsing. Only for compatibility. + */ +static int __init mcheck_disable(char *str) +{ + mce_disabled = 1; + return 1; +} +__setup("nomce", mcheck_disable); diff --git a/arch/x86/kernel/cpu/mcheck/mce.h b/arch/x86/kernel/cpu/mcheck/mce.h deleted file mode 100644 index ae9f628838f1..000000000000 --- a/arch/x86/kernel/cpu/mcheck/mce.h +++ /dev/null @@ -1,14 +0,0 @@ -#include -#include - -void amd_mcheck_init(struct cpuinfo_x86 *c); -void intel_p4_mcheck_init(struct cpuinfo_x86 *c); -void intel_p5_mcheck_init(struct cpuinfo_x86 *c); -void intel_p6_mcheck_init(struct cpuinfo_x86 *c); -void winchip_mcheck_init(struct cpuinfo_x86 *c); - -/* Call the installed machine check handler for this CPU setup. */ -extern void (*machine_check_vector)(struct pt_regs *, long error_code); - -extern int nr_mce_banks; - diff --git a/arch/x86/kernel/cpu/mcheck/mce_32.c b/arch/x86/kernel/cpu/mcheck/mce_32.c deleted file mode 100644 index 3552119b091d..000000000000 --- a/arch/x86/kernel/cpu/mcheck/mce_32.c +++ /dev/null @@ -1,76 +0,0 @@ -/* - * mce.c - x86 Machine Check Exception Reporting - * (c) 2002 Alan Cox , Dave Jones - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "mce.h" - -int mce_disabled; -int nr_mce_banks; - -EXPORT_SYMBOL_GPL(nr_mce_banks); /* non-fatal.o */ - -/* Handle unconfigured int18 (should never happen) */ -static void unexpected_machine_check(struct pt_regs *regs, long error_code) -{ - printk(KERN_ERR "CPU#%d: Unexpected int18 (Machine Check).\n", smp_processor_id()); -} - -/* Call the installed machine check handler for this CPU setup. */ -void (*machine_check_vector)(struct pt_regs *, long error_code) = unexpected_machine_check; - -/* This has to be run for each processor */ -void mcheck_init(struct cpuinfo_x86 *c) -{ - if (mce_disabled == 1) - return; - - switch (c->x86_vendor) { - case X86_VENDOR_AMD: - amd_mcheck_init(c); - break; - - case X86_VENDOR_INTEL: - if (c->x86 == 5) - intel_p5_mcheck_init(c); - if (c->x86 == 6) - intel_p6_mcheck_init(c); - if (c->x86 == 15) - intel_p4_mcheck_init(c); - break; - - case X86_VENDOR_CENTAUR: - if (c->x86 == 5) - winchip_mcheck_init(c); - break; - - default: - break; - } -} - -static int __init mcheck_disable(char *str) -{ - mce_disabled = 1; - return 1; -} - -static int __init mcheck_enable(char *str) -{ - mce_disabled = -1; - return 1; -} - -__setup("nomce", mcheck_disable); -__setup("mce", mcheck_enable); diff --git a/arch/x86/kernel/cpu/mcheck/mce_64.c b/arch/x86/kernel/cpu/mcheck/mce_64.c deleted file mode 100644 index 09dd1d414fc3..000000000000 --- a/arch/x86/kernel/cpu/mcheck/mce_64.c +++ /dev/null @@ -1,1187 +0,0 @@ -/* - * Machine check handler. - * K8 parts Copyright 2002,2003 Andi Kleen, SuSE Labs. - * Rest from unknown author(s). - * 2004 Andi Kleen. Rewrote most of it. - * Copyright 2008 Intel Corporation - * Author: Andi Kleen - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define MISC_MCELOG_MINOR 227 - -atomic_t mce_entry; - -static int mce_dont_init; - -/* - * Tolerant levels: - * 0: always panic on uncorrected errors, log corrected errors - * 1: panic or SIGBUS on uncorrected errors, log corrected errors - * 2: SIGBUS or log uncorrected errors (if possible), log corrected errors - * 3: never panic or SIGBUS, log all errors (for testing only) - */ -static int tolerant = 1; -static int banks; -static u64 *bank; -static unsigned long notify_user; -static int rip_msr; -static int mce_bootlog = -1; -static atomic_t mce_events; - -static char trigger[128]; -static char *trigger_argv[2] = { trigger, NULL }; - -static DECLARE_WAIT_QUEUE_HEAD(mce_wait); - -/* MCA banks polled by the period polling timer for corrected events */ -DEFINE_PER_CPU(mce_banks_t, mce_poll_banks) = { - [0 ... BITS_TO_LONGS(MAX_NR_BANKS)-1] = ~0UL -}; - -/* Do initial initialization of a struct mce */ -void mce_setup(struct mce *m) -{ - memset(m, 0, sizeof(struct mce)); - m->cpu = smp_processor_id(); - rdtscll(m->tsc); -} - -/* - * Lockless MCE logging infrastructure. - * This avoids deadlocks on printk locks without having to break locks. Also - * separate MCEs from kernel messages to avoid bogus bug reports. - */ - -static struct mce_log mcelog = { - MCE_LOG_SIGNATURE, - MCE_LOG_LEN, -}; - -void mce_log(struct mce *mce) -{ - unsigned next, entry; - atomic_inc(&mce_events); - mce->finished = 0; - wmb(); - for (;;) { - entry = rcu_dereference(mcelog.next); - for (;;) { - /* When the buffer fills up discard new entries. Assume - that the earlier errors are the more interesting. */ - if (entry >= MCE_LOG_LEN) { - set_bit(MCE_OVERFLOW, (unsigned long *)&mcelog.flags); - return; - } - /* Old left over entry. Skip. */ - if (mcelog.entry[entry].finished) { - entry++; - continue; - } - break; - } - smp_rmb(); - next = entry + 1; - if (cmpxchg(&mcelog.next, entry, next) == entry) - break; - } - memcpy(mcelog.entry + entry, mce, sizeof(struct mce)); - wmb(); - mcelog.entry[entry].finished = 1; - wmb(); - - set_bit(0, ¬ify_user); -} - -static void print_mce(struct mce *m) -{ - printk(KERN_EMERG "\n" - KERN_EMERG "HARDWARE ERROR\n" - KERN_EMERG - "CPU %d: Machine Check Exception: %16Lx Bank %d: %016Lx\n", - m->cpu, m->mcgstatus, m->bank, m->status); - if (m->ip) { - printk(KERN_EMERG "RIP%s %02x:<%016Lx> ", - !(m->mcgstatus & MCG_STATUS_EIPV) ? " !INEXACT!" : "", - m->cs, m->ip); - if (m->cs == __KERNEL_CS) - print_symbol("{%s}", m->ip); - printk("\n"); - } - printk(KERN_EMERG "TSC %llx ", m->tsc); - if (m->addr) - printk("ADDR %llx ", m->addr); - if (m->misc) - printk("MISC %llx ", m->misc); - printk("\n"); - printk(KERN_EMERG "This is not a software problem!\n"); - printk(KERN_EMERG "Run through mcelog --ascii to decode " - "and contact your hardware vendor\n"); -} - -static void mce_panic(char *msg, struct mce *backup, unsigned long start) -{ - int i; - - oops_begin(); - for (i = 0; i < MCE_LOG_LEN; i++) { - unsigned long tsc = mcelog.entry[i].tsc; - - if (time_before(tsc, start)) - continue; - print_mce(&mcelog.entry[i]); - if (backup && mcelog.entry[i].tsc == backup->tsc) - backup = NULL; - } - if (backup) - print_mce(backup); - panic(msg); -} - -int mce_available(struct cpuinfo_x86 *c) -{ - if (mce_dont_init) - return 0; - return cpu_has(c, X86_FEATURE_MCE) && cpu_has(c, X86_FEATURE_MCA); -} - -static inline void mce_get_rip(struct mce *m, struct pt_regs *regs) -{ - if (regs && (m->mcgstatus & MCG_STATUS_RIPV)) { - m->ip = regs->ip; - m->cs = regs->cs; - } else { - m->ip = 0; - m->cs = 0; - } - if (rip_msr) { - /* Assume the RIP in the MSR is exact. Is this true? */ - m->mcgstatus |= MCG_STATUS_EIPV; - rdmsrl(rip_msr, m->ip); - m->cs = 0; - } -} - -/* - * Poll for corrected events or events that happened before reset. - * Those are just logged through /dev/mcelog. - * - * This is executed in standard interrupt context. - */ -void machine_check_poll(enum mcp_flags flags, mce_banks_t *b) -{ - struct mce m; - int i; - - mce_setup(&m); - - rdmsrl(MSR_IA32_MCG_STATUS, m.mcgstatus); - for (i = 0; i < banks; i++) { - if (!bank[i] || !test_bit(i, *b)) - continue; - - m.misc = 0; - m.addr = 0; - m.bank = i; - m.tsc = 0; - - barrier(); - rdmsrl(MSR_IA32_MC0_STATUS + i*4, m.status); - if (!(m.status & MCI_STATUS_VAL)) - continue; - - /* - * Uncorrected events are handled by the exception handler - * when it is enabled. But when the exception is disabled log - * everything. - * - * TBD do the same check for MCI_STATUS_EN here? - */ - if ((m.status & MCI_STATUS_UC) && !(flags & MCP_UC)) - continue; - - if (m.status & MCI_STATUS_MISCV) - rdmsrl(MSR_IA32_MC0_MISC + i*4, m.misc); - if (m.status & MCI_STATUS_ADDRV) - rdmsrl(MSR_IA32_MC0_ADDR + i*4, m.addr); - - if (!(flags & MCP_TIMESTAMP)) - m.tsc = 0; - /* - * Don't get the IP here because it's unlikely to - * have anything to do with the actual error location. - */ - if (!(flags & MCP_DONTLOG)) { - mce_log(&m); - add_taint(TAINT_MACHINE_CHECK); - } - - /* - * Clear state for this bank. - */ - wrmsrl(MSR_IA32_MC0_STATUS+4*i, 0); - } - - /* - * Don't clear MCG_STATUS here because it's only defined for - * exceptions. - */ -} - -/* - * The actual machine check handler. This only handles real - * exceptions when something got corrupted coming in through int 18. - * - * This is executed in NMI context not subject to normal locking rules. This - * implies that most kernel services cannot be safely used. Don't even - * think about putting a printk in there! - */ -void do_machine_check(struct pt_regs * regs, long error_code) -{ - struct mce m, panicm; - u64 mcestart = 0; - int i; - int panicm_found = 0; - /* - * If no_way_out gets set, there is no safe way to recover from this - * MCE. If tolerant is cranked up, we'll try anyway. - */ - int no_way_out = 0; - /* - * If kill_it gets set, there might be a way to recover from this - * error. - */ - int kill_it = 0; - DECLARE_BITMAP(toclear, MAX_NR_BANKS); - - atomic_inc(&mce_entry); - - if (notify_die(DIE_NMI, "machine check", regs, error_code, - 18, SIGKILL) == NOTIFY_STOP) - goto out2; - if (!banks) - goto out2; - - mce_setup(&m); - - rdmsrl(MSR_IA32_MCG_STATUS, m.mcgstatus); - /* if the restart IP is not valid, we're done for */ - if (!(m.mcgstatus & MCG_STATUS_RIPV)) - no_way_out = 1; - - rdtscll(mcestart); - barrier(); - - for (i = 0; i < banks; i++) { - __clear_bit(i, toclear); - if (!bank[i]) - continue; - - m.misc = 0; - m.addr = 0; - m.bank = i; - - rdmsrl(MSR_IA32_MC0_STATUS + i*4, m.status); - if ((m.status & MCI_STATUS_VAL) == 0) - continue; - - /* - * Non uncorrected errors are handled by machine_check_poll - * Leave them alone. - */ - if ((m.status & MCI_STATUS_UC) == 0) - continue; - - /* - * Set taint even when machine check was not enabled. - */ - add_taint(TAINT_MACHINE_CHECK); - - __set_bit(i, toclear); - - if (m.status & MCI_STATUS_EN) { - /* if PCC was set, there's no way out */ - no_way_out |= !!(m.status & MCI_STATUS_PCC); - /* - * If this error was uncorrectable and there was - * an overflow, we're in trouble. If no overflow, - * we might get away with just killing a task. - */ - if (m.status & MCI_STATUS_UC) { - if (tolerant < 1 || m.status & MCI_STATUS_OVER) - no_way_out = 1; - kill_it = 1; - } - } else { - /* - * Machine check event was not enabled. Clear, but - * ignore. - */ - continue; - } - - if (m.status & MCI_STATUS_MISCV) - rdmsrl(MSR_IA32_MC0_MISC + i*4, m.misc); - if (m.status & MCI_STATUS_ADDRV) - rdmsrl(MSR_IA32_MC0_ADDR + i*4, m.addr); - - mce_get_rip(&m, regs); - mce_log(&m); - - /* Did this bank cause the exception? */ - /* Assume that the bank with uncorrectable errors did it, - and that there is only a single one. */ - if ((m.status & MCI_STATUS_UC) && (m.status & MCI_STATUS_EN)) { - panicm = m; - panicm_found = 1; - } - } - - /* If we didn't find an uncorrectable error, pick - the last one (shouldn't happen, just being safe). */ - if (!panicm_found) - panicm = m; - - /* - * If we have decided that we just CAN'T continue, and the user - * has not set tolerant to an insane level, give up and die. - */ - if (no_way_out && tolerant < 3) - mce_panic("Machine check", &panicm, mcestart); - - /* - * If the error seems to be unrecoverable, something should be - * done. Try to kill as little as possible. If we can kill just - * one task, do that. If the user has set the tolerance very - * high, don't try to do anything at all. - */ - if (kill_it && tolerant < 3) { - int user_space = 0; - - /* - * If the EIPV bit is set, it means the saved IP is the - * instruction which caused the MCE. - */ - if (m.mcgstatus & MCG_STATUS_EIPV) - user_space = panicm.ip && (panicm.cs & 3); - - /* - * If we know that the error was in user space, send a - * SIGBUS. Otherwise, panic if tolerance is low. - * - * force_sig() takes an awful lot of locks and has a slight - * risk of deadlocking. - */ - if (user_space) { - force_sig(SIGBUS, current); - } else if (panic_on_oops || tolerant < 2) { - mce_panic("Uncorrected machine check", - &panicm, mcestart); - } - } - - /* notify userspace ASAP */ - set_thread_flag(TIF_MCE_NOTIFY); - - /* the last thing we do is clear state */ - for (i = 0; i < banks; i++) { - if (test_bit(i, toclear)) - wrmsrl(MSR_IA32_MC0_STATUS+4*i, 0); - } - wrmsrl(MSR_IA32_MCG_STATUS, 0); - out2: - atomic_dec(&mce_entry); -} - -#ifdef CONFIG_X86_MCE_INTEL -/*** - * mce_log_therm_throt_event - Logs the thermal throttling event to mcelog - * @cpu: The CPU on which the event occurred. - * @status: Event status information - * - * This function should be called by the thermal interrupt after the - * event has been processed and the decision was made to log the event - * further. - * - * The status parameter will be saved to the 'status' field of 'struct mce' - * and historically has been the register value of the - * MSR_IA32_THERMAL_STATUS (Intel) msr. - */ -void mce_log_therm_throt_event(__u64 status) -{ - struct mce m; - - mce_setup(&m); - m.bank = MCE_THERMAL_BANK; - m.status = status; - mce_log(&m); -} -#endif /* CONFIG_X86_MCE_INTEL */ - -/* - * Periodic polling timer for "silent" machine check errors. If the - * poller finds an MCE, poll 2x faster. When the poller finds no more - * errors, poll 2x slower (up to check_interval seconds). - */ - -static int check_interval = 5 * 60; /* 5 minutes */ -static DEFINE_PER_CPU(int, next_interval); /* in jiffies */ -static void mcheck_timer(unsigned long); -static DEFINE_PER_CPU(struct timer_list, mce_timer); - -static void mcheck_timer(unsigned long data) -{ - struct timer_list *t = &per_cpu(mce_timer, data); - int *n; - - WARN_ON(smp_processor_id() != data); - - if (mce_available(¤t_cpu_data)) - machine_check_poll(MCP_TIMESTAMP, - &__get_cpu_var(mce_poll_banks)); - - /* - * Alert userspace if needed. If we logged an MCE, reduce the - * polling interval, otherwise increase the polling interval. - */ - n = &__get_cpu_var(next_interval); - if (mce_notify_user()) { - *n = max(*n/2, HZ/100); - } else { - *n = min(*n*2, (int)round_jiffies_relative(check_interval*HZ)); - } - - t->expires = jiffies + *n; - add_timer(t); -} - -static void mce_do_trigger(struct work_struct *work) -{ - call_usermodehelper(trigger, trigger_argv, NULL, UMH_NO_WAIT); -} - -static DECLARE_WORK(mce_trigger_work, mce_do_trigger); - -/* - * Notify the user(s) about new machine check events. - * Can be called from interrupt context, but not from machine check/NMI - * context. - */ -int mce_notify_user(void) -{ - /* Not more than two messages every minute */ - static DEFINE_RATELIMIT_STATE(ratelimit, 60*HZ, 2); - - clear_thread_flag(TIF_MCE_NOTIFY); - if (test_and_clear_bit(0, ¬ify_user)) { - wake_up_interruptible(&mce_wait); - - /* - * There is no risk of missing notifications because - * work_pending is always cleared before the function is - * executed. - */ - if (trigger[0] && !work_pending(&mce_trigger_work)) - schedule_work(&mce_trigger_work); - - if (__ratelimit(&ratelimit)) - printk(KERN_INFO "Machine check events logged\n"); - - return 1; - } - return 0; -} - -/* see if the idle task needs to notify userspace */ -static int -mce_idle_callback(struct notifier_block *nfb, unsigned long action, void *junk) -{ - /* IDLE_END should be safe - interrupts are back on */ - if (action == IDLE_END && test_thread_flag(TIF_MCE_NOTIFY)) - mce_notify_user(); - - return NOTIFY_OK; -} - -static struct notifier_block mce_idle_notifier = { - .notifier_call = mce_idle_callback, -}; - -static __init int periodic_mcheck_init(void) -{ - idle_notifier_register(&mce_idle_notifier); - return 0; -} -__initcall(periodic_mcheck_init); - -/* - * Initialize Machine Checks for a CPU. - */ -static int mce_cap_init(void) -{ - u64 cap; - unsigned b; - - rdmsrl(MSR_IA32_MCG_CAP, cap); - b = cap & 0xff; - if (b > MAX_NR_BANKS) { - printk(KERN_WARNING - "MCE: Using only %u machine check banks out of %u\n", - MAX_NR_BANKS, b); - b = MAX_NR_BANKS; - } - - /* Don't support asymmetric configurations today */ - WARN_ON(banks != 0 && b != banks); - banks = b; - if (!bank) { - bank = kmalloc(banks * sizeof(u64), GFP_KERNEL); - if (!bank) - return -ENOMEM; - memset(bank, 0xff, banks * sizeof(u64)); - } - - /* Use accurate RIP reporting if available. */ - if ((cap & (1<<9)) && ((cap >> 16) & 0xff) >= 9) - rip_msr = MSR_IA32_MCG_EIP; - - return 0; -} - -static void mce_init(void *dummy) -{ - u64 cap; - int i; - mce_banks_t all_banks; - - /* - * Log the machine checks left over from the previous reset. - */ - bitmap_fill(all_banks, MAX_NR_BANKS); - machine_check_poll(MCP_UC|(!mce_bootlog ? MCP_DONTLOG : 0), &all_banks); - - set_in_cr4(X86_CR4_MCE); - - rdmsrl(MSR_IA32_MCG_CAP, cap); - if (cap & MCG_CTL_P) - wrmsr(MSR_IA32_MCG_CTL, 0xffffffff, 0xffffffff); - - for (i = 0; i < banks; i++) { - wrmsrl(MSR_IA32_MC0_CTL+4*i, bank[i]); - wrmsrl(MSR_IA32_MC0_STATUS+4*i, 0); - } -} - -/* Add per CPU specific workarounds here */ -static void mce_cpu_quirks(struct cpuinfo_x86 *c) -{ - /* This should be disabled by the BIOS, but isn't always */ - if (c->x86_vendor == X86_VENDOR_AMD) { - if (c->x86 == 15 && banks > 4) - /* disable GART TBL walk error reporting, which trips off - incorrectly with the IOMMU & 3ware & Cerberus. */ - clear_bit(10, (unsigned long *)&bank[4]); - if(c->x86 <= 17 && mce_bootlog < 0) - /* Lots of broken BIOS around that don't clear them - by default and leave crap in there. Don't log. */ - mce_bootlog = 0; - } - -} - -static void mce_cpu_features(struct cpuinfo_x86 *c) -{ - switch (c->x86_vendor) { - case X86_VENDOR_INTEL: - mce_intel_feature_init(c); - break; - case X86_VENDOR_AMD: - mce_amd_feature_init(c); - break; - default: - break; - } -} - -static void mce_init_timer(void) -{ - struct timer_list *t = &__get_cpu_var(mce_timer); - int *n = &__get_cpu_var(next_interval); - - *n = check_interval * HZ; - if (!*n) - return; - setup_timer(t, mcheck_timer, smp_processor_id()); - t->expires = round_jiffies(jiffies + *n); - add_timer(t); -} - -/* - * Called for each booted CPU to set up machine checks. - * Must be called with preempt off. - */ -void __cpuinit mcheck_init(struct cpuinfo_x86 *c) -{ - if (!mce_available(c)) - return; - - if (mce_cap_init() < 0) { - mce_dont_init = 1; - return; - } - mce_cpu_quirks(c); - - mce_init(NULL); - mce_cpu_features(c); - mce_init_timer(); -} - -/* - * Character device to read and clear the MCE log. - */ - -static DEFINE_SPINLOCK(mce_state_lock); -static int open_count; /* #times opened */ -static int open_exclu; /* already open exclusive? */ - -static int mce_open(struct inode *inode, struct file *file) -{ - lock_kernel(); - spin_lock(&mce_state_lock); - - if (open_exclu || (open_count && (file->f_flags & O_EXCL))) { - spin_unlock(&mce_state_lock); - unlock_kernel(); - return -EBUSY; - } - - if (file->f_flags & O_EXCL) - open_exclu = 1; - open_count++; - - spin_unlock(&mce_state_lock); - unlock_kernel(); - - return nonseekable_open(inode, file); -} - -static int mce_release(struct inode *inode, struct file *file) -{ - spin_lock(&mce_state_lock); - - open_count--; - open_exclu = 0; - - spin_unlock(&mce_state_lock); - - return 0; -} - -static void collect_tscs(void *data) -{ - unsigned long *cpu_tsc = (unsigned long *)data; - - rdtscll(cpu_tsc[smp_processor_id()]); -} - -static ssize_t mce_read(struct file *filp, char __user *ubuf, size_t usize, - loff_t *off) -{ - unsigned long *cpu_tsc; - static DEFINE_MUTEX(mce_read_mutex); - unsigned prev, next; - char __user *buf = ubuf; - int i, err; - - cpu_tsc = kmalloc(nr_cpu_ids * sizeof(long), GFP_KERNEL); - if (!cpu_tsc) - return -ENOMEM; - - mutex_lock(&mce_read_mutex); - next = rcu_dereference(mcelog.next); - - /* Only supports full reads right now */ - if (*off != 0 || usize < MCE_LOG_LEN*sizeof(struct mce)) { - mutex_unlock(&mce_read_mutex); - kfree(cpu_tsc); - return -EINVAL; - } - - err = 0; - prev = 0; - do { - for (i = prev; i < next; i++) { - unsigned long start = jiffies; - - while (!mcelog.entry[i].finished) { - if (time_after_eq(jiffies, start + 2)) { - memset(mcelog.entry + i, 0, - sizeof(struct mce)); - goto timeout; - } - cpu_relax(); - } - smp_rmb(); - err |= copy_to_user(buf, mcelog.entry + i, - sizeof(struct mce)); - buf += sizeof(struct mce); -timeout: - ; - } - - memset(mcelog.entry + prev, 0, - (next - prev) * sizeof(struct mce)); - prev = next; - next = cmpxchg(&mcelog.next, prev, 0); - } while (next != prev); - - synchronize_sched(); - - /* - * Collect entries that were still getting written before the - * synchronize. - */ - on_each_cpu(collect_tscs, cpu_tsc, 1); - for (i = next; i < MCE_LOG_LEN; i++) { - if (mcelog.entry[i].finished && - mcelog.entry[i].tsc < cpu_tsc[mcelog.entry[i].cpu]) { - err |= copy_to_user(buf, mcelog.entry+i, - sizeof(struct mce)); - smp_rmb(); - buf += sizeof(struct mce); - memset(&mcelog.entry[i], 0, sizeof(struct mce)); - } - } - mutex_unlock(&mce_read_mutex); - kfree(cpu_tsc); - return err ? -EFAULT : buf - ubuf; -} - -static unsigned int mce_poll(struct file *file, poll_table *wait) -{ - poll_wait(file, &mce_wait, wait); - if (rcu_dereference(mcelog.next)) - return POLLIN | POLLRDNORM; - return 0; -} - -static long mce_ioctl(struct file *f, unsigned int cmd, unsigned long arg) -{ - int __user *p = (int __user *)arg; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - switch (cmd) { - case MCE_GET_RECORD_LEN: - return put_user(sizeof(struct mce), p); - case MCE_GET_LOG_LEN: - return put_user(MCE_LOG_LEN, p); - case MCE_GETCLEAR_FLAGS: { - unsigned flags; - - do { - flags = mcelog.flags; - } while (cmpxchg(&mcelog.flags, flags, 0) != flags); - return put_user(flags, p); - } - default: - return -ENOTTY; - } -} - -static const struct file_operations mce_chrdev_ops = { - .open = mce_open, - .release = mce_release, - .read = mce_read, - .poll = mce_poll, - .unlocked_ioctl = mce_ioctl, -}; - -static struct miscdevice mce_log_device = { - MISC_MCELOG_MINOR, - "mcelog", - &mce_chrdev_ops, -}; - -/* - * Old style boot options parsing. Only for compatibility. - */ -static int __init mcheck_disable(char *str) -{ - mce_dont_init = 1; - return 1; -} - -/* mce=off disables machine check. - mce=TOLERANCELEVEL (number, see above) - mce=bootlog Log MCEs from before booting. Disabled by default on AMD. - mce=nobootlog Don't log MCEs from before booting. */ -static int __init mcheck_enable(char *str) -{ - if (!strcmp(str, "off")) - mce_dont_init = 1; - else if (!strcmp(str, "bootlog") || !strcmp(str,"nobootlog")) - mce_bootlog = str[0] == 'b'; - else if (isdigit(str[0])) - get_option(&str, &tolerant); - else - printk("mce= argument %s ignored. Please use /sys", str); - return 1; -} - -__setup("nomce", mcheck_disable); -__setup("mce=", mcheck_enable); - -/* - * Sysfs support - */ - -/* - * Disable machine checks on suspend and shutdown. We can't really handle - * them later. - */ -static int mce_disable(void) -{ - int i; - - for (i = 0; i < banks; i++) - wrmsrl(MSR_IA32_MC0_CTL + i*4, 0); - return 0; -} - -static int mce_suspend(struct sys_device *dev, pm_message_t state) -{ - return mce_disable(); -} - -static int mce_shutdown(struct sys_device *dev) -{ - return mce_disable(); -} - -/* On resume clear all MCE state. Don't want to see leftovers from the BIOS. - Only one CPU is active at this time, the others get readded later using - CPU hotplug. */ -static int mce_resume(struct sys_device *dev) -{ - mce_init(NULL); - mce_cpu_features(¤t_cpu_data); - return 0; -} - -static void mce_cpu_restart(void *data) -{ - del_timer_sync(&__get_cpu_var(mce_timer)); - if (mce_available(¤t_cpu_data)) - mce_init(NULL); - mce_init_timer(); -} - -/* Reinit MCEs after user configuration changes */ -static void mce_restart(void) -{ - on_each_cpu(mce_cpu_restart, NULL, 1); -} - -static struct sysdev_class mce_sysclass = { - .suspend = mce_suspend, - .shutdown = mce_shutdown, - .resume = mce_resume, - .name = "machinecheck", -}; - -DEFINE_PER_CPU(struct sys_device, device_mce); -void (*threshold_cpu_callback)(unsigned long action, unsigned int cpu) __cpuinitdata; - -/* Why are there no generic functions for this? */ -#define ACCESSOR(name, var, start) \ - static ssize_t show_ ## name(struct sys_device *s, \ - struct sysdev_attribute *attr, \ - char *buf) { \ - return sprintf(buf, "%lx\n", (unsigned long)var); \ - } \ - static ssize_t set_ ## name(struct sys_device *s, \ - struct sysdev_attribute *attr, \ - const char *buf, size_t siz) { \ - char *end; \ - unsigned long new = simple_strtoul(buf, &end, 0); \ - if (end == buf) return -EINVAL; \ - var = new; \ - start; \ - return end-buf; \ - } \ - static SYSDEV_ATTR(name, 0644, show_ ## name, set_ ## name); - -static struct sysdev_attribute *bank_attrs; - -static ssize_t show_bank(struct sys_device *s, struct sysdev_attribute *attr, - char *buf) -{ - u64 b = bank[attr - bank_attrs]; - return sprintf(buf, "%llx\n", b); -} - -static ssize_t set_bank(struct sys_device *s, struct sysdev_attribute *attr, - const char *buf, size_t siz) -{ - char *end; - u64 new = simple_strtoull(buf, &end, 0); - if (end == buf) - return -EINVAL; - bank[attr - bank_attrs] = new; - mce_restart(); - return end-buf; -} - -static ssize_t show_trigger(struct sys_device *s, struct sysdev_attribute *attr, - char *buf) -{ - strcpy(buf, trigger); - strcat(buf, "\n"); - return strlen(trigger) + 1; -} - -static ssize_t set_trigger(struct sys_device *s, struct sysdev_attribute *attr, - const char *buf,size_t siz) -{ - char *p; - int len; - strncpy(trigger, buf, sizeof(trigger)); - trigger[sizeof(trigger)-1] = 0; - len = strlen(trigger); - p = strchr(trigger, '\n'); - if (*p) *p = 0; - return len; -} - -static SYSDEV_ATTR(trigger, 0644, show_trigger, set_trigger); -static SYSDEV_INT_ATTR(tolerant, 0644, tolerant); -ACCESSOR(check_interval,check_interval,mce_restart()) -static struct sysdev_attribute *mce_attributes[] = { - &attr_tolerant.attr, &attr_check_interval, &attr_trigger, - NULL -}; - -static cpumask_var_t mce_device_initialized; - -/* Per cpu sysdev init. All of the cpus still share the same ctl bank */ -static __cpuinit int mce_create_device(unsigned int cpu) -{ - int err; - int i; - - if (!mce_available(&boot_cpu_data)) - return -EIO; - - memset(&per_cpu(device_mce, cpu).kobj, 0, sizeof(struct kobject)); - per_cpu(device_mce,cpu).id = cpu; - per_cpu(device_mce,cpu).cls = &mce_sysclass; - - err = sysdev_register(&per_cpu(device_mce,cpu)); - if (err) - return err; - - for (i = 0; mce_attributes[i]; i++) { - err = sysdev_create_file(&per_cpu(device_mce,cpu), - mce_attributes[i]); - if (err) - goto error; - } - for (i = 0; i < banks; i++) { - err = sysdev_create_file(&per_cpu(device_mce, cpu), - &bank_attrs[i]); - if (err) - goto error2; - } - cpumask_set_cpu(cpu, mce_device_initialized); - - return 0; -error2: - while (--i >= 0) { - sysdev_remove_file(&per_cpu(device_mce, cpu), - &bank_attrs[i]); - } -error: - while (--i >= 0) { - sysdev_remove_file(&per_cpu(device_mce,cpu), - mce_attributes[i]); - } - sysdev_unregister(&per_cpu(device_mce,cpu)); - - return err; -} - -static __cpuinit void mce_remove_device(unsigned int cpu) -{ - int i; - - if (!cpumask_test_cpu(cpu, mce_device_initialized)) - return; - - for (i = 0; mce_attributes[i]; i++) - sysdev_remove_file(&per_cpu(device_mce,cpu), - mce_attributes[i]); - for (i = 0; i < banks; i++) - sysdev_remove_file(&per_cpu(device_mce, cpu), - &bank_attrs[i]); - sysdev_unregister(&per_cpu(device_mce,cpu)); - cpumask_clear_cpu(cpu, mce_device_initialized); -} - -/* Make sure there are no machine checks on offlined CPUs. */ -static void mce_disable_cpu(void *h) -{ - int i; - unsigned long action = *(unsigned long *)h; - - if (!mce_available(¤t_cpu_data)) - return; - if (!(action & CPU_TASKS_FROZEN)) - cmci_clear(); - for (i = 0; i < banks; i++) - wrmsrl(MSR_IA32_MC0_CTL + i*4, 0); -} - -static void mce_reenable_cpu(void *h) -{ - int i; - unsigned long action = *(unsigned long *)h; - - if (!mce_available(¤t_cpu_data)) - return; - if (!(action & CPU_TASKS_FROZEN)) - cmci_reenable(); - for (i = 0; i < banks; i++) - wrmsrl(MSR_IA32_MC0_CTL + i*4, bank[i]); -} - -/* Get notified when a cpu comes on/off. Be hotplug friendly. */ -static int __cpuinit mce_cpu_callback(struct notifier_block *nfb, - unsigned long action, void *hcpu) -{ - unsigned int cpu = (unsigned long)hcpu; - struct timer_list *t = &per_cpu(mce_timer, cpu); - - switch (action) { - case CPU_ONLINE: - case CPU_ONLINE_FROZEN: - mce_create_device(cpu); - if (threshold_cpu_callback) - threshold_cpu_callback(action, cpu); - break; - case CPU_DEAD: - case CPU_DEAD_FROZEN: - if (threshold_cpu_callback) - threshold_cpu_callback(action, cpu); - mce_remove_device(cpu); - break; - case CPU_DOWN_PREPARE: - case CPU_DOWN_PREPARE_FROZEN: - del_timer_sync(t); - smp_call_function_single(cpu, mce_disable_cpu, &action, 1); - break; - case CPU_DOWN_FAILED: - case CPU_DOWN_FAILED_FROZEN: - t->expires = round_jiffies(jiffies + - __get_cpu_var(next_interval)); - add_timer_on(t, cpu); - smp_call_function_single(cpu, mce_reenable_cpu, &action, 1); - break; - case CPU_POST_DEAD: - /* intentionally ignoring frozen here */ - cmci_rediscover(cpu); - break; - } - return NOTIFY_OK; -} - -static struct notifier_block mce_cpu_notifier __cpuinitdata = { - .notifier_call = mce_cpu_callback, -}; - -static __init int mce_init_banks(void) -{ - int i; - - bank_attrs = kzalloc(sizeof(struct sysdev_attribute) * banks, - GFP_KERNEL); - if (!bank_attrs) - return -ENOMEM; - - for (i = 0; i < banks; i++) { - struct sysdev_attribute *a = &bank_attrs[i]; - a->attr.name = kasprintf(GFP_KERNEL, "bank%d", i); - if (!a->attr.name) - goto nomem; - a->attr.mode = 0644; - a->show = show_bank; - a->store = set_bank; - } - return 0; - -nomem: - while (--i >= 0) - kfree(bank_attrs[i].attr.name); - kfree(bank_attrs); - bank_attrs = NULL; - return -ENOMEM; -} - -static __init int mce_init_device(void) -{ - int err; - int i = 0; - - if (!mce_available(&boot_cpu_data)) - return -EIO; - - zalloc_cpumask_var(&mce_device_initialized, GFP_KERNEL); - - err = mce_init_banks(); - if (err) - return err; - - err = sysdev_class_register(&mce_sysclass); - if (err) - return err; - - for_each_online_cpu(i) { - err = mce_create_device(i); - if (err) - return err; - } - - register_hotcpu_notifier(&mce_cpu_notifier); - misc_register(&mce_log_device); - return err; -} - -device_initcall(mce_init_device); diff --git a/arch/x86/kernel/cpu/mcheck/mce_amd_64.c b/arch/x86/kernel/cpu/mcheck/mce_amd.c similarity index 82% rename from arch/x86/kernel/cpu/mcheck/mce_amd_64.c rename to arch/x86/kernel/cpu/mcheck/mce_amd.c index 56dde9c4bc96..ddae21620bda 100644 --- a/arch/x86/kernel/cpu/mcheck/mce_amd_64.c +++ b/arch/x86/kernel/cpu/mcheck/mce_amd.c @@ -13,22 +13,22 @@ * * All MC4_MISCi registers are shared between multi-cores */ - -#include -#include -#include #include -#include #include -#include -#include +#include +#include #include +#include +#include #include +#include +#include +#include + #include +#include #include #include -#include -#include #define PFX "mce_threshold: " #define VERSION "version 1.1.1" @@ -48,26 +48,26 @@ #define MCG_XBLK_ADDR 0xC0000400 struct threshold_block { - unsigned int block; - unsigned int bank; - unsigned int cpu; - u32 address; - u16 interrupt_enable; - u16 threshold_limit; - struct kobject kobj; - struct list_head miscj; + unsigned int block; + unsigned int bank; + unsigned int cpu; + u32 address; + u16 interrupt_enable; + u16 threshold_limit; + struct kobject kobj; + struct list_head miscj; }; /* defaults used early on boot */ static struct threshold_block threshold_defaults = { - .interrupt_enable = 0, - .threshold_limit = THRESHOLD_MAX, + .interrupt_enable = 0, + .threshold_limit = THRESHOLD_MAX, }; struct threshold_bank { - struct kobject *kobj; - struct threshold_block *blocks; - cpumask_var_t cpus; + struct kobject *kobj; + struct threshold_block *blocks; + cpumask_var_t cpus; }; static DEFINE_PER_CPU(struct threshold_bank *, threshold_banks[NR_BANKS]); @@ -86,9 +86,9 @@ static void amd_threshold_interrupt(void); */ struct thresh_restart { - struct threshold_block *b; - int reset; - u16 old_limit; + struct threshold_block *b; + int reset; + u16 old_limit; }; /* must be called with correct cpu affinity */ @@ -110,6 +110,7 @@ static void threshold_restart_bank(void *_tr) } else if (tr->old_limit) { /* change limit w/o reset */ int new_count = (mci_misc_hi & THRESHOLD_MAX) + (tr->old_limit - tr->b->threshold_limit); + mci_misc_hi = (mci_misc_hi & ~MASK_ERR_COUNT_HI) | (new_count & THRESHOLD_MAX); } @@ -125,11 +126,11 @@ static void threshold_restart_bank(void *_tr) /* cpu init entry point, called from mce.c with preempt off */ void mce_amd_feature_init(struct cpuinfo_x86 *c) { - unsigned int bank, block; unsigned int cpu = smp_processor_id(); - u8 lvt_off; u32 low = 0, high = 0, address = 0; + unsigned int bank, block; struct thresh_restart tr; + u8 lvt_off; for (bank = 0; bank < NR_BANKS; ++bank) { for (block = 0; block < NR_BLOCKS; ++block) { @@ -140,8 +141,7 @@ void mce_amd_feature_init(struct cpuinfo_x86 *c) if (!address) break; address += MCG_XBLK_ADDR; - } - else + } else ++address; if (rdmsr_safe(address, &low, &high)) @@ -193,9 +193,9 @@ void mce_amd_feature_init(struct cpuinfo_x86 *c) */ static void amd_threshold_interrupt(void) { + u32 low = 0, high = 0, address = 0; unsigned int bank, block; struct mce m; - u32 low = 0, high = 0, address = 0; mce_setup(&m); @@ -204,16 +204,16 @@ static void amd_threshold_interrupt(void) if (!(per_cpu(bank_map, m.cpu) & (1 << bank))) continue; for (block = 0; block < NR_BLOCKS; ++block) { - if (block == 0) + if (block == 0) { address = MSR_IA32_MC0_MISC + bank * 4; - else if (block == 1) { + } else if (block == 1) { address = (low & MASK_BLKPTR_LO) >> 21; if (!address) break; address += MCG_XBLK_ADDR; - } - else + } else { ++address; + } if (rdmsr_safe(address, &low, &high)) break; @@ -229,8 +229,10 @@ static void amd_threshold_interrupt(void) (high & MASK_LOCKED_HI)) continue; - /* Log the machine check that caused the threshold - event. */ + /* + * Log the machine check that caused the threshold + * event. + */ machine_check_poll(MCP_TIMESTAMP, &__get_cpu_var(mce_poll_banks)); @@ -254,48 +256,52 @@ static void amd_threshold_interrupt(void) struct threshold_attr { struct attribute attr; - ssize_t(*show) (struct threshold_block *, char *); - ssize_t(*store) (struct threshold_block *, const char *, size_t count); + ssize_t (*show) (struct threshold_block *, char *); + ssize_t (*store) (struct threshold_block *, const char *, size_t count); }; -#define SHOW_FIELDS(name) \ -static ssize_t show_ ## name(struct threshold_block * b, char *buf) \ -{ \ - return sprintf(buf, "%lx\n", (unsigned long) b->name); \ +#define SHOW_FIELDS(name) \ +static ssize_t show_ ## name(struct threshold_block *b, char *buf) \ +{ \ + return sprintf(buf, "%lx\n", (unsigned long) b->name); \ } SHOW_FIELDS(interrupt_enable) SHOW_FIELDS(threshold_limit) -static ssize_t store_interrupt_enable(struct threshold_block *b, - const char *buf, size_t count) +static ssize_t +store_interrupt_enable(struct threshold_block *b, const char *buf, size_t size) { - char *end; struct thresh_restart tr; - unsigned long new = simple_strtoul(buf, &end, 0); - if (end == buf) + unsigned long new; + + if (strict_strtoul(buf, 0, &new) < 0) return -EINVAL; + b->interrupt_enable = !!new; - tr.b = b; - tr.reset = 0; - tr.old_limit = 0; + tr.b = b; + tr.reset = 0; + tr.old_limit = 0; + smp_call_function_single(b->cpu, threshold_restart_bank, &tr, 1); - return end - buf; + return size; } -static ssize_t store_threshold_limit(struct threshold_block *b, - const char *buf, size_t count) +static ssize_t +store_threshold_limit(struct threshold_block *b, const char *buf, size_t size) { - char *end; struct thresh_restart tr; - unsigned long new = simple_strtoul(buf, &end, 0); - if (end == buf) + unsigned long new; + + if (strict_strtoul(buf, 0, &new) < 0) return -EINVAL; + if (new > THRESHOLD_MAX) new = THRESHOLD_MAX; if (new < 1) new = 1; + tr.old_limit = b->threshold_limit; b->threshold_limit = new; tr.b = b; @@ -303,12 +309,12 @@ static ssize_t store_threshold_limit(struct threshold_block *b, smp_call_function_single(b->cpu, threshold_restart_bank, &tr, 1); - return end - buf; + return size; } struct threshold_block_cross_cpu { - struct threshold_block *tb; - long retval; + struct threshold_block *tb; + long retval; }; static void local_error_count_handler(void *_tbcc) @@ -338,16 +344,13 @@ static ssize_t store_error_count(struct threshold_block *b, return 1; } -#define THRESHOLD_ATTR(_name,_mode,_show,_store) { \ - .attr = {.name = __stringify(_name), .mode = _mode }, \ - .show = _show, \ - .store = _store, \ +#define RW_ATTR(val) \ +static struct threshold_attr val = { \ + .attr = {.name = __stringify(val), .mode = 0644 }, \ + .show = show_## val, \ + .store = store_## val, \ }; -#define RW_ATTR(name) \ -static struct threshold_attr name = \ - THRESHOLD_ATTR(name, 0644, show_## name, store_## name) - RW_ATTR(interrupt_enable); RW_ATTR(threshold_limit); RW_ATTR(error_count); @@ -359,15 +362,17 @@ static struct attribute *default_attrs[] = { NULL }; -#define to_block(k) container_of(k, struct threshold_block, kobj) -#define to_attr(a) container_of(a, struct threshold_attr, attr) +#define to_block(k) container_of(k, struct threshold_block, kobj) +#define to_attr(a) container_of(a, struct threshold_attr, attr) static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf) { struct threshold_block *b = to_block(kobj); struct threshold_attr *a = to_attr(attr); ssize_t ret; + ret = a->show ? a->show(b, buf) : -EIO; + return ret; } @@ -377,18 +382,20 @@ static ssize_t store(struct kobject *kobj, struct attribute *attr, struct threshold_block *b = to_block(kobj); struct threshold_attr *a = to_attr(attr); ssize_t ret; + ret = a->store ? a->store(b, buf, count) : -EIO; + return ret; } static struct sysfs_ops threshold_ops = { - .show = show, - .store = store, + .show = show, + .store = store, }; static struct kobj_type threshold_ktype = { - .sysfs_ops = &threshold_ops, - .default_attrs = default_attrs, + .sysfs_ops = &threshold_ops, + .default_attrs = default_attrs, }; static __cpuinit int allocate_threshold_blocks(unsigned int cpu, @@ -396,9 +403,9 @@ static __cpuinit int allocate_threshold_blocks(unsigned int cpu, unsigned int block, u32 address) { - int err; - u32 low, high; struct threshold_block *b = NULL; + u32 low, high; + int err; if ((bank >= NR_BANKS) || (block >= NR_BLOCKS)) return 0; @@ -421,20 +428,21 @@ static __cpuinit int allocate_threshold_blocks(unsigned int cpu, if (!b) return -ENOMEM; - b->block = block; - b->bank = bank; - b->cpu = cpu; - b->address = address; - b->interrupt_enable = 0; - b->threshold_limit = THRESHOLD_MAX; + b->block = block; + b->bank = bank; + b->cpu = cpu; + b->address = address; + b->interrupt_enable = 0; + b->threshold_limit = THRESHOLD_MAX; INIT_LIST_HEAD(&b->miscj); - if (per_cpu(threshold_banks, cpu)[bank]->blocks) + if (per_cpu(threshold_banks, cpu)[bank]->blocks) { list_add(&b->miscj, &per_cpu(threshold_banks, cpu)[bank]->blocks->miscj); - else + } else { per_cpu(threshold_banks, cpu)[bank]->blocks = b; + } err = kobject_init_and_add(&b->kobj, &threshold_ktype, per_cpu(threshold_banks, cpu)[bank]->kobj, @@ -447,8 +455,9 @@ recurse: if (!address) return 0; address += MCG_XBLK_ADDR; - } else + } else { ++address; + } err = allocate_threshold_blocks(cpu, bank, ++block, address); if (err) @@ -500,13 +509,14 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank) if (!b) goto out; - err = sysfs_create_link(&per_cpu(device_mce, cpu).kobj, + err = sysfs_create_link(&per_cpu(mce_dev, cpu).kobj, b->kobj, name); if (err) goto out; cpumask_copy(b->cpus, cpu_core_mask(cpu)); per_cpu(threshold_banks, cpu)[bank] = b; + goto out; } #endif @@ -522,7 +532,7 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank) goto out; } - b->kobj = kobject_create_and_add(name, &per_cpu(device_mce, cpu).kobj); + b->kobj = kobject_create_and_add(name, &per_cpu(mce_dev, cpu).kobj); if (!b->kobj) goto out_free; @@ -542,7 +552,7 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank) if (i == cpu) continue; - err = sysfs_create_link(&per_cpu(device_mce, i).kobj, + err = sysfs_create_link(&per_cpu(mce_dev, i).kobj, b->kobj, name); if (err) goto out; @@ -605,15 +615,13 @@ static void deallocate_threshold_block(unsigned int cpu, static void threshold_remove_bank(unsigned int cpu, int bank) { - int i = 0; struct threshold_bank *b; char name[32]; + int i = 0; b = per_cpu(threshold_banks, cpu)[bank]; - if (!b) return; - if (!b->blocks) goto free_out; @@ -622,8 +630,9 @@ static void threshold_remove_bank(unsigned int cpu, int bank) #ifdef CONFIG_SMP /* sibling symlink */ if (shared_bank[bank] && b->blocks->cpu != cpu) { - sysfs_remove_link(&per_cpu(device_mce, cpu).kobj, name); + sysfs_remove_link(&per_cpu(mce_dev, cpu).kobj, name); per_cpu(threshold_banks, cpu)[bank] = NULL; + return; } #endif @@ -633,7 +642,7 @@ static void threshold_remove_bank(unsigned int cpu, int bank) if (i == cpu) continue; - sysfs_remove_link(&per_cpu(device_mce, i).kobj, name); + sysfs_remove_link(&per_cpu(mce_dev, i).kobj, name); per_cpu(threshold_banks, i)[bank] = NULL; } @@ -659,12 +668,9 @@ static void threshold_remove_device(unsigned int cpu) } /* get notified when a cpu comes on/off */ -static void __cpuinit amd_64_threshold_cpu_callback(unsigned long action, - unsigned int cpu) +static void __cpuinit +amd_64_threshold_cpu_callback(unsigned long action, unsigned int cpu) { - if (cpu >= NR_CPUS) - return; - switch (action) { case CPU_ONLINE: case CPU_ONLINE_FROZEN: @@ -686,11 +692,12 @@ static __init int threshold_init_device(void) /* to hit CPUs online before the notifier is up */ for_each_online_cpu(lcpu) { int err = threshold_create_device(lcpu); + if (err) return err; } threshold_cpu_callback = amd_64_threshold_cpu_callback; + return 0; } - device_initcall(threshold_init_device); diff --git a/arch/x86/kernel/cpu/mcheck/mce_intel_64.c b/arch/x86/kernel/cpu/mcheck/mce_intel.c similarity index 74% rename from arch/x86/kernel/cpu/mcheck/mce_intel_64.c rename to arch/x86/kernel/cpu/mcheck/mce_intel.c index cef3ee30744b..e1acec0f7a32 100644 --- a/arch/x86/kernel/cpu/mcheck/mce_intel_64.c +++ b/arch/x86/kernel/cpu/mcheck/mce_intel.c @@ -8,85 +8,10 @@ #include #include #include -#include #include +#include #include #include -#include -#include -#include -#include - -asmlinkage void smp_thermal_interrupt(void) -{ - __u64 msr_val; - - ack_APIC_irq(); - - exit_idle(); - irq_enter(); - - rdmsrl(MSR_IA32_THERM_STATUS, msr_val); - if (therm_throt_process(msr_val & 1)) - mce_log_therm_throt_event(msr_val); - - inc_irq_stat(irq_thermal_count); - irq_exit(); -} - -static void intel_init_thermal(struct cpuinfo_x86 *c) -{ - u32 l, h; - int tm2 = 0; - unsigned int cpu = smp_processor_id(); - - if (!cpu_has(c, X86_FEATURE_ACPI)) - return; - - if (!cpu_has(c, X86_FEATURE_ACC)) - return; - - /* first check if TM1 is already enabled by the BIOS, in which - * case there might be some SMM goo which handles it, so we can't even - * put a handler since it might be delivered via SMI already. - */ - rdmsr(MSR_IA32_MISC_ENABLE, l, h); - h = apic_read(APIC_LVTTHMR); - if ((l & MSR_IA32_MISC_ENABLE_TM1) && (h & APIC_DM_SMI)) { - printk(KERN_DEBUG - "CPU%d: Thermal monitoring handled by SMI\n", cpu); - return; - } - - if (cpu_has(c, X86_FEATURE_TM2) && (l & MSR_IA32_MISC_ENABLE_TM2)) - tm2 = 1; - - if (h & APIC_VECTOR_MASK) { - printk(KERN_DEBUG - "CPU%d: Thermal LVT vector (%#x) already " - "installed\n", cpu, (h & APIC_VECTOR_MASK)); - return; - } - - h = THERMAL_APIC_VECTOR; - h |= (APIC_DM_FIXED | APIC_LVT_MASKED); - apic_write(APIC_LVTTHMR, h); - - rdmsr(MSR_IA32_THERM_INTERRUPT, l, h); - wrmsr(MSR_IA32_THERM_INTERRUPT, l | 0x03, h); - - rdmsr(MSR_IA32_MISC_ENABLE, l, h); - wrmsr(MSR_IA32_MISC_ENABLE, l | MSR_IA32_MISC_ENABLE_TM1, h); - - l = apic_read(APIC_LVTTHMR); - apic_write(APIC_LVTTHMR, l & ~APIC_LVT_MASKED); - printk(KERN_INFO "CPU%d: Thermal monitoring enabled (%s)\n", - cpu, tm2 ? "TM2" : "TM1"); - - /* enable thermal throttle processing */ - atomic_set(&therm_throt_en, 1); - return; -} /* * Support for Intel Correct Machine Check Interrupts. This allows @@ -109,6 +34,9 @@ static int cmci_supported(int *banks) { u64 cap; + if (mce_cmci_disabled || mce_ignore_ce) + return 0; + /* * Vendor check is not strictly needed, but the initial * initialization is vendor keyed and this @@ -132,7 +60,7 @@ static int cmci_supported(int *banks) static void intel_threshold_interrupt(void) { machine_check_poll(MCP_TIMESTAMP, &__get_cpu_var(mce_banks_owned)); - mce_notify_user(); + mce_notify_irq(); } static void print_update(char *type, int *hdr, int num) @@ -248,7 +176,7 @@ void cmci_rediscover(int dying) return; cpumask_copy(old, ¤t->cpus_allowed); - for_each_online_cpu (cpu) { + for_each_online_cpu(cpu) { if (cpu == dying) continue; if (set_cpus_allowed_ptr(current, cpumask_of(cpu))) diff --git a/arch/x86/kernel/cpu/mcheck/non-fatal.c b/arch/x86/kernel/cpu/mcheck/non-fatal.c index a74af128efc9..f5f2d6f71fb6 100644 --- a/arch/x86/kernel/cpu/mcheck/non-fatal.c +++ b/arch/x86/kernel/cpu/mcheck/non-fatal.c @@ -6,25 +6,23 @@ * This file contains routines to check for non-fatal MCEs every 15s * */ - -#include -#include -#include -#include -#include #include -#include +#include +#include +#include #include +#include +#include +#include #include #include +#include #include -#include "mce.h" +static int firstbank; -static int firstbank; - -#define MCE_RATE 15*HZ /* timer rate is 15s */ +#define MCE_RATE (15*HZ) /* timer rate is 15s */ static void mce_checkregs(void *info) { @@ -34,23 +32,24 @@ static void mce_checkregs(void *info) for (i = firstbank; i < nr_mce_banks; i++) { rdmsr(MSR_IA32_MC0_STATUS+i*4, low, high); - if (high & (1<<31)) { - printk(KERN_INFO "MCE: The hardware reports a non " - "fatal, correctable incident occurred on " - "CPU %d.\n", + if (!(high & (1<<31))) + continue; + + printk(KERN_INFO "MCE: The hardware reports a non fatal, " + "correctable incident occurred on CPU %d.\n", smp_processor_id()); - printk(KERN_INFO "Bank %d: %08x%08x\n", i, high, low); - /* - * Scrub the error so we don't pick it up in MCE_RATE - * seconds time. - */ - wrmsr(MSR_IA32_MC0_STATUS+i*4, 0UL, 0UL); + printk(KERN_INFO "Bank %d: %08x%08x\n", i, high, low); - /* Serialize */ - wmb(); - add_taint(TAINT_MACHINE_CHECK); - } + /* + * Scrub the error so we don't pick it up in MCE_RATE + * seconds time: + */ + wrmsr(MSR_IA32_MC0_STATUS+i*4, 0UL, 0UL); + + /* Serialize: */ + wmb(); + add_taint(TAINT_MACHINE_CHECK); } } @@ -77,16 +76,17 @@ static int __init init_nonfatal_mce_checker(void) /* Some Athlons misbehave when we frob bank 0 */ if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD && - boot_cpu_data.x86 == 6) - firstbank = 1; + boot_cpu_data.x86 == 6) + firstbank = 1; else - firstbank = 0; + firstbank = 0; /* * Check for non-fatal errors every MCE_RATE s */ schedule_delayed_work(&mce_work, round_jiffies_relative(MCE_RATE)); printk(KERN_INFO "Machine check exception polling timer started.\n"); + return 0; } module_init(init_nonfatal_mce_checker); diff --git a/arch/x86/kernel/cpu/mcheck/p4.c b/arch/x86/kernel/cpu/mcheck/p4.c index f53bdcbaf382..4482aea9aa2e 100644 --- a/arch/x86/kernel/cpu/mcheck/p4.c +++ b/arch/x86/kernel/cpu/mcheck/p4.c @@ -1,21 +1,14 @@ /* * P4 specific Machine Check Exception Reporting */ - -#include -#include #include -#include +#include +#include #include #include -#include +#include #include -#include - -#include - -#include "mce.h" /* as supported by the P4/Xeon family */ struct intel_mce_extended_msrs { @@ -34,98 +27,8 @@ struct intel_mce_extended_msrs { static int mce_num_extended_msrs; - -#ifdef CONFIG_X86_MCE_P4THERMAL -static void unexpected_thermal_interrupt(struct pt_regs *regs) -{ - printk(KERN_ERR "CPU%d: Unexpected LVT TMR interrupt!\n", - smp_processor_id()); - add_taint(TAINT_MACHINE_CHECK); -} - -/* P4/Xeon Thermal transition interrupt handler */ -static void intel_thermal_interrupt(struct pt_regs *regs) -{ - __u64 msr_val; - - ack_APIC_irq(); - - rdmsrl(MSR_IA32_THERM_STATUS, msr_val); - therm_throt_process(msr_val & 0x1); -} - -/* Thermal interrupt handler for this CPU setup */ -static void (*vendor_thermal_interrupt)(struct pt_regs *regs) = unexpected_thermal_interrupt; - -void smp_thermal_interrupt(struct pt_regs *regs) -{ - irq_enter(); - vendor_thermal_interrupt(regs); - __get_cpu_var(irq_stat).irq_thermal_count++; - irq_exit(); -} - -/* P4/Xeon Thermal regulation detect and init */ -static void intel_init_thermal(struct cpuinfo_x86 *c) -{ - u32 l, h; - unsigned int cpu = smp_processor_id(); - - /* Thermal monitoring */ - if (!cpu_has(c, X86_FEATURE_ACPI)) - return; /* -ENODEV */ - - /* Clock modulation */ - if (!cpu_has(c, X86_FEATURE_ACC)) - return; /* -ENODEV */ - - /* first check if its enabled already, in which case there might - * be some SMM goo which handles it, so we can't even put a handler - * since it might be delivered via SMI already -zwanem. - */ - rdmsr(MSR_IA32_MISC_ENABLE, l, h); - h = apic_read(APIC_LVTTHMR); - if ((l & MSR_IA32_MISC_ENABLE_TM1) && (h & APIC_DM_SMI)) { - printk(KERN_DEBUG "CPU%d: Thermal monitoring handled by SMI\n", - cpu); - return; /* -EBUSY */ - } - - /* check whether a vector already exists, temporarily masked? */ - if (h & APIC_VECTOR_MASK) { - printk(KERN_DEBUG "CPU%d: Thermal LVT vector (%#x) already " - "installed\n", - cpu, (h & APIC_VECTOR_MASK)); - return; /* -EBUSY */ - } - - /* The temperature transition interrupt handler setup */ - h = THERMAL_APIC_VECTOR; /* our delivery vector */ - h |= (APIC_DM_FIXED | APIC_LVT_MASKED); /* we'll mask till we're ready */ - apic_write(APIC_LVTTHMR, h); - - rdmsr(MSR_IA32_THERM_INTERRUPT, l, h); - wrmsr(MSR_IA32_THERM_INTERRUPT, l | 0x03 , h); - - /* ok we're good to go... */ - vendor_thermal_interrupt = intel_thermal_interrupt; - - rdmsr(MSR_IA32_MISC_ENABLE, l, h); - wrmsr(MSR_IA32_MISC_ENABLE, l | MSR_IA32_MISC_ENABLE_TM1, h); - - l = apic_read(APIC_LVTTHMR); - apic_write(APIC_LVTTHMR, l & ~APIC_LVT_MASKED); - printk(KERN_INFO "CPU%d: Thermal monitoring enabled\n", cpu); - - /* enable thermal throttle processing */ - atomic_set(&therm_throt_en, 1); - return; -} -#endif /* CONFIG_X86_MCE_P4THERMAL */ - - /* P4/Xeon Extended MCE MSR retrieval, return 0 if unsupported */ -static inline void intel_get_extended_msrs(struct intel_mce_extended_msrs *r) +static void intel_get_extended_msrs(struct intel_mce_extended_msrs *r) { u32 h; @@ -143,9 +46,9 @@ static inline void intel_get_extended_msrs(struct intel_mce_extended_msrs *r) static void intel_machine_check(struct pt_regs *regs, long error_code) { - int recover = 1; u32 alow, ahigh, high, low; u32 mcgstl, mcgsth; + int recover = 1; int i; rdmsr(MSR_IA32_MCG_STATUS, mcgstl, mcgsth); @@ -157,7 +60,9 @@ static void intel_machine_check(struct pt_regs *regs, long error_code) if (mce_num_extended_msrs > 0) { struct intel_mce_extended_msrs dbg; + intel_get_extended_msrs(&dbg); + printk(KERN_DEBUG "CPU %d: EIP: %08x EFLAGS: %08x\n" "\teax: %08x ebx: %08x ecx: %08x edx: %08x\n" "\tesi: %08x edi: %08x ebp: %08x esp: %08x\n", @@ -171,6 +76,7 @@ static void intel_machine_check(struct pt_regs *regs, long error_code) if (high & (1<<31)) { char misc[20]; char addr[24]; + misc[0] = addr[0] = '\0'; if (high & (1<<29)) recover |= 1; @@ -196,6 +102,7 @@ static void intel_machine_check(struct pt_regs *regs, long error_code) panic("Unable to continue"); printk(KERN_EMERG "Attempting to continue.\n"); + /* * Do not clear the MSR_IA32_MCi_STATUS if the error is not * recoverable/continuable.This will allow BIOS to look at the MSRs @@ -217,7 +124,6 @@ static void intel_machine_check(struct pt_regs *regs, long error_code) wrmsr(MSR_IA32_MCG_STATUS, mcgstl, mcgsth); } - void intel_p4_mcheck_init(struct cpuinfo_x86 *c) { u32 l, h; diff --git a/arch/x86/kernel/cpu/mcheck/p5.c b/arch/x86/kernel/cpu/mcheck/p5.c index c9f77ea69edc..5c0e6533d9bc 100644 --- a/arch/x86/kernel/cpu/mcheck/p5.c +++ b/arch/x86/kernel/cpu/mcheck/p5.c @@ -2,52 +2,67 @@ * P5 specific Machine Check Exception Reporting * (C) Copyright 2002 Alan Cox */ - -#include -#include -#include #include +#include +#include +#include #include #include #include +#include #include -#include "mce.h" +/* By default disabled */ +int mce_p5_enabled __read_mostly; -/* Machine check handler for Pentium class Intel */ +/* Machine check handler for Pentium class Intel CPUs: */ static void pentium_machine_check(struct pt_regs *regs, long error_code) { u32 loaddr, hi, lotype; + rdmsr(MSR_IA32_P5_MC_ADDR, loaddr, hi); rdmsr(MSR_IA32_P5_MC_TYPE, lotype, hi); - printk(KERN_EMERG "CPU#%d: Machine Check Exception: 0x%8X (type 0x%8X).\n", smp_processor_id(), loaddr, lotype); - if (lotype&(1<<5)) - printk(KERN_EMERG "CPU#%d: Possible thermal failure (CPU on fire ?).\n", smp_processor_id()); + + printk(KERN_EMERG + "CPU#%d: Machine Check Exception: 0x%8X (type 0x%8X).\n", + smp_processor_id(), loaddr, lotype); + + if (lotype & (1<<5)) { + printk(KERN_EMERG + "CPU#%d: Possible thermal failure (CPU on fire ?).\n", + smp_processor_id()); + } + add_taint(TAINT_MACHINE_CHECK); } -/* Set up machine check reporting for processors with Intel style MCE */ +/* Set up machine check reporting for processors with Intel style MCE: */ void intel_p5_mcheck_init(struct cpuinfo_x86 *c) { u32 l, h; - /*Check for MCE support */ + /* Default P5 to off as its often misconnected: */ + if (!mce_p5_enabled) + return; + + /* Check for MCE support: */ if (!cpu_has(c, X86_FEATURE_MCE)) return; - /* Default P5 to off as its often misconnected */ - if (mce_disabled != -1) - return; machine_check_vector = pentium_machine_check; + /* Make sure the vector pointer is visible before we enable MCEs: */ wmb(); - /* Read registers before enabling */ + /* Read registers before enabling: */ rdmsr(MSR_IA32_P5_MC_ADDR, l, h); rdmsr(MSR_IA32_P5_MC_TYPE, l, h); - printk(KERN_INFO "Intel old style machine check architecture supported.\n"); + printk(KERN_INFO + "Intel old style machine check architecture supported.\n"); - /* Enable MCE */ + /* Enable MCE: */ set_in_cr4(X86_CR4_MCE); - printk(KERN_INFO "Intel old style machine check reporting enabled on CPU#%d.\n", smp_processor_id()); + printk(KERN_INFO + "Intel old style machine check reporting enabled on CPU#%d.\n", + smp_processor_id()); } diff --git a/arch/x86/kernel/cpu/mcheck/p6.c b/arch/x86/kernel/cpu/mcheck/p6.c index 2ac52d7b434b..01e4f8178183 100644 --- a/arch/x86/kernel/cpu/mcheck/p6.c +++ b/arch/x86/kernel/cpu/mcheck/p6.c @@ -2,25 +2,23 @@ * P6 specific Machine Check Exception Reporting * (C) Copyright 2002 Alan Cox */ - -#include -#include -#include #include +#include +#include +#include #include #include #include +#include #include -#include "mce.h" - /* Machine Check Handler For PII/PIII */ static void intel_machine_check(struct pt_regs *regs, long error_code) { - int recover = 1; u32 alow, ahigh, high, low; u32 mcgstl, mcgsth; + int recover = 1; int i; rdmsr(MSR_IA32_MCG_STATUS, mcgstl, mcgsth); @@ -35,12 +33,16 @@ static void intel_machine_check(struct pt_regs *regs, long error_code) if (high & (1<<31)) { char misc[20]; char addr[24]; - misc[0] = addr[0] = '\0'; + + misc[0] = '\0'; + addr[0] = '\0'; + if (high & (1<<29)) recover |= 1; if (high & (1<<25)) recover |= 2; high &= ~(1<<31); + if (high & (1<<27)) { rdmsr(MSR_IA32_MC0_MISC+i*4, alow, ahigh); snprintf(misc, 20, "[%08x%08x]", ahigh, alow); @@ -49,6 +51,7 @@ static void intel_machine_check(struct pt_regs *regs, long error_code) rdmsr(MSR_IA32_MC0_ADDR+i*4, alow, ahigh); snprintf(addr, 24, " at %08x%08x", ahigh, alow); } + printk(KERN_EMERG "CPU %d: Bank %d: %08x%08x%s%s\n", smp_processor_id(), i, high, low, misc, addr); } @@ -63,16 +66,17 @@ static void intel_machine_check(struct pt_regs *regs, long error_code) /* * Do not clear the MSR_IA32_MCi_STATUS if the error is not * recoverable/continuable.This will allow BIOS to look at the MSRs - * for errors if the OS could not log the error. + * for errors if the OS could not log the error: */ for (i = 0; i < nr_mce_banks; i++) { unsigned int msr; + msr = MSR_IA32_MC0_STATUS+i*4; rdmsr(msr, low, high); if (high & (1<<31)) { - /* Clear it */ + /* Clear it: */ wrmsr(msr, 0UL, 0UL); - /* Serialize */ + /* Serialize: */ wmb(); add_taint(TAINT_MACHINE_CHECK); } @@ -81,7 +85,7 @@ static void intel_machine_check(struct pt_regs *regs, long error_code) wrmsr(MSR_IA32_MCG_STATUS, mcgstl, mcgsth); } -/* Set up machine check reporting for processors with Intel style MCE */ +/* Set up machine check reporting for processors with Intel style MCE: */ void intel_p6_mcheck_init(struct cpuinfo_x86 *c) { u32 l, h; @@ -97,6 +101,7 @@ void intel_p6_mcheck_init(struct cpuinfo_x86 *c) /* Ok machine check is available */ machine_check_vector = intel_machine_check; + /* Make sure the vector pointer is visible before we enable MCEs: */ wmb(); printk(KERN_INFO "Intel machine check architecture supported.\n"); diff --git a/arch/x86/kernel/cpu/mcheck/therm_throt.c b/arch/x86/kernel/cpu/mcheck/therm_throt.c index d5ae2243f0b9..bff8dd191dd5 100644 --- a/arch/x86/kernel/cpu/mcheck/therm_throt.c +++ b/arch/x86/kernel/cpu/mcheck/therm_throt.c @@ -1,7 +1,7 @@ /* - * * Thermal throttle event support code (such as syslog messaging and rate * limiting) that was factored out from x86_64 (mce_intel.c) and i386 (p4.c). + * * This allows consistent reporting of CPU thermal throttle events. * * Maintains a counter in /sys that keeps track of the number of thermal @@ -13,43 +13,53 @@ * Credits: Adapted from Zwane Mwaikambo's original code in mce_intel.c. * Inspired by Ross Biro's and Al Borchers' counter code. */ - -#include -#include -#include -#include +#include #include #include -#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include /* How long to wait between reporting thermal events */ -#define CHECK_INTERVAL (300 * HZ) +#define CHECK_INTERVAL (300 * HZ) static DEFINE_PER_CPU(__u64, next_check) = INITIAL_JIFFIES; static DEFINE_PER_CPU(unsigned long, thermal_throttle_count); -atomic_t therm_throt_en = ATOMIC_INIT(0); + +static atomic_t therm_throt_en = ATOMIC_INIT(0); #ifdef CONFIG_SYSFS -#define define_therm_throt_sysdev_one_ro(_name) \ - static SYSDEV_ATTR(_name, 0444, therm_throt_sysdev_show_##_name, NULL) +#define define_therm_throt_sysdev_one_ro(_name) \ + static SYSDEV_ATTR(_name, 0444, therm_throt_sysdev_show_##_name, NULL) -#define define_therm_throt_sysdev_show_func(name) \ -static ssize_t therm_throt_sysdev_show_##name(struct sys_device *dev, \ - struct sysdev_attribute *attr, \ - char *buf) \ -{ \ - unsigned int cpu = dev->id; \ - ssize_t ret; \ - \ - preempt_disable(); /* CPU hotplug */ \ - if (cpu_online(cpu)) \ - ret = sprintf(buf, "%lu\n", \ - per_cpu(thermal_throttle_##name, cpu)); \ - else \ - ret = 0; \ - preempt_enable(); \ - \ - return ret; \ +#define define_therm_throt_sysdev_show_func(name) \ +static ssize_t therm_throt_sysdev_show_##name(struct sys_device *dev, \ + struct sysdev_attribute *attr, \ + char *buf) \ +{ \ + unsigned int cpu = dev->id; \ + ssize_t ret; \ + \ + preempt_disable(); /* CPU hotplug */ \ + if (cpu_online(cpu)) \ + ret = sprintf(buf, "%lu\n", \ + per_cpu(thermal_throttle_##name, cpu)); \ + else \ + ret = 0; \ + preempt_enable(); \ + \ + return ret; \ } define_therm_throt_sysdev_show_func(count); @@ -61,8 +71,8 @@ static struct attribute *thermal_throttle_attrs[] = { }; static struct attribute_group thermal_throttle_attr_group = { - .attrs = thermal_throttle_attrs, - .name = "thermal_throttle" + .attrs = thermal_throttle_attrs, + .name = "thermal_throttle" }; #endif /* CONFIG_SYSFS */ @@ -82,7 +92,7 @@ static struct attribute_group thermal_throttle_attr_group = { * 1 : Event should be logged further, and a message has been * printed to the syslog. */ -int therm_throt_process(int curr) +static int therm_throt_process(int curr) { unsigned int cpu = smp_processor_id(); __u64 tmp_jiffs = get_jiffies_64(); @@ -110,10 +120,11 @@ int therm_throt_process(int curr) } #ifdef CONFIG_SYSFS -/* Add/Remove thermal_throttle interface for CPU device */ +/* Add/Remove thermal_throttle interface for CPU device: */ static __cpuinit int thermal_throttle_add_dev(struct sys_device *sys_dev) { - return sysfs_create_group(&sys_dev->kobj, &thermal_throttle_attr_group); + return sysfs_create_group(&sys_dev->kobj, + &thermal_throttle_attr_group); } static __cpuinit void thermal_throttle_remove_dev(struct sys_device *sys_dev) @@ -121,19 +132,21 @@ static __cpuinit void thermal_throttle_remove_dev(struct sys_device *sys_dev) sysfs_remove_group(&sys_dev->kobj, &thermal_throttle_attr_group); } -/* Mutex protecting device creation against CPU hotplug */ +/* Mutex protecting device creation against CPU hotplug: */ static DEFINE_MUTEX(therm_cpu_lock); /* Get notified when a cpu comes on/off. Be hotplug friendly. */ -static __cpuinit int thermal_throttle_cpu_callback(struct notifier_block *nfb, - unsigned long action, - void *hcpu) +static __cpuinit int +thermal_throttle_cpu_callback(struct notifier_block *nfb, + unsigned long action, + void *hcpu) { unsigned int cpu = (unsigned long)hcpu; struct sys_device *sys_dev; int err = 0; sys_dev = get_cpu_sysdev(cpu); + switch (action) { case CPU_UP_PREPARE: case CPU_UP_PREPARE_FROZEN: @@ -183,6 +196,94 @@ static __init int thermal_throttle_init_device(void) return 0; } - device_initcall(thermal_throttle_init_device); + #endif /* CONFIG_SYSFS */ + +/* Thermal transition interrupt handler */ +static void intel_thermal_interrupt(void) +{ + __u64 msr_val; + + rdmsrl(MSR_IA32_THERM_STATUS, msr_val); + if (therm_throt_process(msr_val & THERM_STATUS_PROCHOT)) + mce_log_therm_throt_event(msr_val); +} + +static void unexpected_thermal_interrupt(void) +{ + printk(KERN_ERR "CPU%d: Unexpected LVT TMR interrupt!\n", + smp_processor_id()); + add_taint(TAINT_MACHINE_CHECK); +} + +static void (*smp_thermal_vector)(void) = unexpected_thermal_interrupt; + +asmlinkage void smp_thermal_interrupt(struct pt_regs *regs) +{ + exit_idle(); + irq_enter(); + inc_irq_stat(irq_thermal_count); + smp_thermal_vector(); + irq_exit(); + /* Ack only at the end to avoid potential reentry */ + ack_APIC_irq(); +} + +void intel_init_thermal(struct cpuinfo_x86 *c) +{ + unsigned int cpu = smp_processor_id(); + int tm2 = 0; + u32 l, h; + + /* Thermal monitoring depends on ACPI and clock modulation*/ + if (!cpu_has(c, X86_FEATURE_ACPI) || !cpu_has(c, X86_FEATURE_ACC)) + return; + + /* + * First check if its enabled already, in which case there might + * be some SMM goo which handles it, so we can't even put a handler + * since it might be delivered via SMI already: + */ + rdmsr(MSR_IA32_MISC_ENABLE, l, h); + h = apic_read(APIC_LVTTHMR); + if ((l & MSR_IA32_MISC_ENABLE_TM1) && (h & APIC_DM_SMI)) { + printk(KERN_DEBUG + "CPU%d: Thermal monitoring handled by SMI\n", cpu); + return; + } + + if (cpu_has(c, X86_FEATURE_TM2) && (l & MSR_IA32_MISC_ENABLE_TM2)) + tm2 = 1; + + /* Check whether a vector already exists */ + if (h & APIC_VECTOR_MASK) { + printk(KERN_DEBUG + "CPU%d: Thermal LVT vector (%#x) already installed\n", + cpu, (h & APIC_VECTOR_MASK)); + return; + } + + /* We'll mask the thermal vector in the lapic till we're ready: */ + h = THERMAL_APIC_VECTOR | APIC_DM_FIXED | APIC_LVT_MASKED; + apic_write(APIC_LVTTHMR, h); + + rdmsr(MSR_IA32_THERM_INTERRUPT, l, h); + wrmsr(MSR_IA32_THERM_INTERRUPT, + l | (THERM_INT_LOW_ENABLE | THERM_INT_HIGH_ENABLE), h); + + smp_thermal_vector = intel_thermal_interrupt; + + rdmsr(MSR_IA32_MISC_ENABLE, l, h); + wrmsr(MSR_IA32_MISC_ENABLE, l | MSR_IA32_MISC_ENABLE_TM1, h); + + /* Unmask the thermal vector: */ + l = apic_read(APIC_LVTTHMR); + apic_write(APIC_LVTTHMR, l & ~APIC_LVT_MASKED); + + printk(KERN_INFO "CPU%d: Thermal monitoring enabled (%s)\n", + cpu, tm2 ? "TM2" : "TM1"); + + /* enable thermal throttle processing */ + atomic_set(&therm_throt_en, 1); +} diff --git a/arch/x86/kernel/cpu/mcheck/threshold.c b/arch/x86/kernel/cpu/mcheck/threshold.c index 23ee9e730f78..d746df2909c9 100644 --- a/arch/x86/kernel/cpu/mcheck/threshold.c +++ b/arch/x86/kernel/cpu/mcheck/threshold.c @@ -17,7 +17,7 @@ static void default_threshold_interrupt(void) void (*mce_threshold_vector)(void) = default_threshold_interrupt; -asmlinkage void mce_threshold_interrupt(void) +asmlinkage void smp_threshold_interrupt(void) { exit_idle(); irq_enter(); diff --git a/arch/x86/kernel/cpu/mcheck/winchip.c b/arch/x86/kernel/cpu/mcheck/winchip.c index 2a043d89811d..54060f565974 100644 --- a/arch/x86/kernel/cpu/mcheck/winchip.c +++ b/arch/x86/kernel/cpu/mcheck/winchip.c @@ -2,19 +2,17 @@ * IDT Winchip specific Machine Check Exception Reporting * (C) Copyright 2002 Alan Cox */ - -#include -#include -#include #include +#include +#include +#include #include #include +#include #include -#include "mce.h" - -/* Machine check handler for WinChip C6 */ +/* Machine check handler for WinChip C6: */ static void winchip_machine_check(struct pt_regs *regs, long error_code) { printk(KERN_EMERG "CPU0: Machine Check Exception.\n"); @@ -25,12 +23,18 @@ static void winchip_machine_check(struct pt_regs *regs, long error_code) void winchip_mcheck_init(struct cpuinfo_x86 *c) { u32 lo, hi; + machine_check_vector = winchip_machine_check; + /* Make sure the vector pointer is visible before we enable MCEs: */ wmb(); + rdmsr(MSR_IDT_FCR1, lo, hi); lo |= (1<<2); /* Enable EIERRINT (int 18 MCE) */ lo &= ~(1<<4); /* Enable MCE */ wrmsr(MSR_IDT_FCR1, lo, hi); + set_in_cr4(X86_CR4_MCE); - printk(KERN_INFO "Winchip machine check reporting enabled on CPU#0.\n"); + + printk(KERN_INFO + "Winchip machine check reporting enabled on CPU#0.\n"); } diff --git a/arch/x86/kernel/cpu/mtrr/cleanup.c b/arch/x86/kernel/cpu/mtrr/cleanup.c index ce0fe4b5c04f..1d584a18a50d 100644 --- a/arch/x86/kernel/cpu/mtrr/cleanup.c +++ b/arch/x86/kernel/cpu/mtrr/cleanup.c @@ -808,7 +808,7 @@ int __init mtrr_cleanup(unsigned address_bits) if (!is_cpu(INTEL) || enable_mtrr_cleanup < 1) return 0; - rdmsr(MTRRdefType_MSR, def, dummy); + rdmsr(MSR_MTRRdefType, def, dummy); def &= 0xff; if (def != MTRR_TYPE_UNCACHABLE) return 0; @@ -1003,7 +1003,7 @@ int __init mtrr_trim_uncached_memory(unsigned long end_pfn) */ if (!is_cpu(INTEL) || disable_mtrr_trim) return 0; - rdmsr(MTRRdefType_MSR, def, dummy); + rdmsr(MSR_MTRRdefType, def, dummy); def &= 0xff; if (def != MTRR_TYPE_UNCACHABLE) return 0; diff --git a/arch/x86/kernel/cpu/mtrr/generic.c b/arch/x86/kernel/cpu/mtrr/generic.c index d21d4fb161f7..0543f69f0b27 100644 --- a/arch/x86/kernel/cpu/mtrr/generic.c +++ b/arch/x86/kernel/cpu/mtrr/generic.c @@ -20,9 +20,9 @@ struct fixed_range_block { }; static struct fixed_range_block fixed_range_blocks[] = { - { MTRRfix64K_00000_MSR, 1 }, /* one 64k MTRR */ - { MTRRfix16K_80000_MSR, 2 }, /* two 16k MTRRs */ - { MTRRfix4K_C0000_MSR, 8 }, /* eight 4k MTRRs */ + { MSR_MTRRfix64K_00000, 1 }, /* one 64k MTRR */ + { MSR_MTRRfix16K_80000, 2 }, /* two 16k MTRRs */ + { MSR_MTRRfix4K_C0000, 8 }, /* eight 4k MTRRs */ {} }; @@ -194,12 +194,12 @@ get_fixed_ranges(mtrr_type * frs) k8_check_syscfg_dram_mod_en(); - rdmsr(MTRRfix64K_00000_MSR, p[0], p[1]); + rdmsr(MSR_MTRRfix64K_00000, p[0], p[1]); for (i = 0; i < 2; i++) - rdmsr(MTRRfix16K_80000_MSR + i, p[2 + i * 2], p[3 + i * 2]); + rdmsr(MSR_MTRRfix16K_80000 + i, p[2 + i * 2], p[3 + i * 2]); for (i = 0; i < 8; i++) - rdmsr(MTRRfix4K_C0000_MSR + i, p[6 + i * 2], p[7 + i * 2]); + rdmsr(MSR_MTRRfix4K_C0000 + i, p[6 + i * 2], p[7 + i * 2]); } void mtrr_save_fixed_ranges(void *info) @@ -310,7 +310,7 @@ void __init get_mtrr_state(void) vrs = mtrr_state.var_ranges; - rdmsr(MTRRcap_MSR, lo, dummy); + rdmsr(MSR_MTRRcap, lo, dummy); mtrr_state.have_fixed = (lo >> 8) & 1; for (i = 0; i < num_var_ranges; i++) @@ -318,7 +318,7 @@ void __init get_mtrr_state(void) if (mtrr_state.have_fixed) get_fixed_ranges(mtrr_state.fixed_ranges); - rdmsr(MTRRdefType_MSR, lo, dummy); + rdmsr(MSR_MTRRdefType, lo, dummy); mtrr_state.def_type = (lo & 0xff); mtrr_state.enabled = (lo & 0xc00) >> 10; @@ -583,10 +583,10 @@ static void prepare_set(void) __acquires(set_atomicity_lock) __flush_tlb(); /* Save MTRR state */ - rdmsr(MTRRdefType_MSR, deftype_lo, deftype_hi); + rdmsr(MSR_MTRRdefType, deftype_lo, deftype_hi); /* Disable MTRRs, and set the default type to uncached */ - mtrr_wrmsr(MTRRdefType_MSR, deftype_lo & ~0xcff, deftype_hi); + mtrr_wrmsr(MSR_MTRRdefType, deftype_lo & ~0xcff, deftype_hi); } static void post_set(void) __releases(set_atomicity_lock) @@ -595,7 +595,7 @@ static void post_set(void) __releases(set_atomicity_lock) __flush_tlb(); /* Intel (P6) standard MTRRs */ - mtrr_wrmsr(MTRRdefType_MSR, deftype_lo, deftype_hi); + mtrr_wrmsr(MSR_MTRRdefType, deftype_lo, deftype_hi); /* Enable caches */ write_cr0(read_cr0() & 0xbfffffff); @@ -707,7 +707,7 @@ int generic_validate_add_page(unsigned long base, unsigned long size, unsigned i static int generic_have_wrcomb(void) { unsigned long config, dummy; - rdmsr(MTRRcap_MSR, config, dummy); + rdmsr(MSR_MTRRcap, config, dummy); return (config & (1 << 10)); } diff --git a/arch/x86/kernel/cpu/mtrr/main.c b/arch/x86/kernel/cpu/mtrr/main.c index 03cda01f57c7..8fc248b5aeaf 100644 --- a/arch/x86/kernel/cpu/mtrr/main.c +++ b/arch/x86/kernel/cpu/mtrr/main.c @@ -104,7 +104,7 @@ static void __init set_num_var_ranges(void) unsigned long config = 0, dummy; if (use_intel()) { - rdmsr(MTRRcap_MSR, config, dummy); + rdmsr(MSR_MTRRcap, config, dummy); } else if (is_cpu(AMD)) config = 2; else if (is_cpu(CYRIX) || is_cpu(CENTAUR)) diff --git a/arch/x86/kernel/cpu/mtrr/mtrr.h b/arch/x86/kernel/cpu/mtrr/mtrr.h index 77f67f7b347a..7538b767f206 100644 --- a/arch/x86/kernel/cpu/mtrr/mtrr.h +++ b/arch/x86/kernel/cpu/mtrr/mtrr.h @@ -5,21 +5,6 @@ #include #include -#define MTRRcap_MSR 0x0fe -#define MTRRdefType_MSR 0x2ff - -#define MTRRfix64K_00000_MSR 0x250 -#define MTRRfix16K_80000_MSR 0x258 -#define MTRRfix16K_A0000_MSR 0x259 -#define MTRRfix4K_C0000_MSR 0x268 -#define MTRRfix4K_C8000_MSR 0x269 -#define MTRRfix4K_D0000_MSR 0x26a -#define MTRRfix4K_D8000_MSR 0x26b -#define MTRRfix4K_E0000_MSR 0x26c -#define MTRRfix4K_E8000_MSR 0x26d -#define MTRRfix4K_F0000_MSR 0x26e -#define MTRRfix4K_F8000_MSR 0x26f - #define MTRR_CHANGE_MASK_FIXED 0x01 #define MTRR_CHANGE_MASK_VARIABLE 0x02 #define MTRR_CHANGE_MASK_DEFTYPE 0x04 diff --git a/arch/x86/kernel/cpu/mtrr/state.c b/arch/x86/kernel/cpu/mtrr/state.c index 7f7e2753685b..1f5fb1588d1f 100644 --- a/arch/x86/kernel/cpu/mtrr/state.c +++ b/arch/x86/kernel/cpu/mtrr/state.c @@ -35,7 +35,7 @@ void set_mtrr_prepare_save(struct set_mtrr_context *ctxt) if (use_intel()) /* Save MTRR state */ - rdmsr(MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi); + rdmsr(MSR_MTRRdefType, ctxt->deftype_lo, ctxt->deftype_hi); else /* Cyrix ARRs - everything else were excluded at the top */ ctxt->ccr3 = getCx86(CX86_CCR3); @@ -46,7 +46,7 @@ void set_mtrr_cache_disable(struct set_mtrr_context *ctxt) { if (use_intel()) /* Disable MTRRs, and set the default type to uncached */ - mtrr_wrmsr(MTRRdefType_MSR, ctxt->deftype_lo & 0xf300UL, + mtrr_wrmsr(MSR_MTRRdefType, ctxt->deftype_lo & 0xf300UL, ctxt->deftype_hi); else if (is_cpu(CYRIX)) /* Cyrix ARRs - everything else were excluded at the top */ @@ -64,7 +64,7 @@ void set_mtrr_done(struct set_mtrr_context *ctxt) /* Restore MTRRdefType */ if (use_intel()) /* Intel (P6) standard MTRRs */ - mtrr_wrmsr(MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi); + mtrr_wrmsr(MSR_MTRRdefType, ctxt->deftype_lo, ctxt->deftype_hi); else /* Cyrix ARRs - everything else was excluded at the top */ setCx86(CX86_CCR3, ctxt->ccr3); diff --git a/arch/x86/kernel/cpu/perf_counter.c b/arch/x86/kernel/cpu/perf_counter.c new file mode 100644 index 000000000000..76dfef23f789 --- /dev/null +++ b/arch/x86/kernel/cpu/perf_counter.c @@ -0,0 +1,1721 @@ +/* + * Performance counter x86 architecture code + * + * Copyright (C) 2008 Thomas Gleixner + * Copyright (C) 2008-2009 Red Hat, Inc., Ingo Molnar + * Copyright (C) 2009 Jaswinder Singh Rajput + * Copyright (C) 2009 Advanced Micro Devices, Inc., Robert Richter + * Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra + * + * For licencing details see kernel-base/COPYING + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +static u64 perf_counter_mask __read_mostly; + +struct cpu_hw_counters { + struct perf_counter *counters[X86_PMC_IDX_MAX]; + unsigned long used_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)]; + unsigned long active_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)]; + unsigned long interrupts; + int enabled; +}; + +/* + * struct x86_pmu - generic x86 pmu + */ +struct x86_pmu { + const char *name; + int version; + int (*handle_irq)(struct pt_regs *); + void (*disable_all)(void); + void (*enable_all)(void); + void (*enable)(struct hw_perf_counter *, int); + void (*disable)(struct hw_perf_counter *, int); + unsigned eventsel; + unsigned perfctr; + u64 (*event_map)(int); + u64 (*raw_event)(u64); + int max_events; + int num_counters; + int num_counters_fixed; + int counter_bits; + u64 counter_mask; + u64 max_period; + u64 intel_ctrl; +}; + +static struct x86_pmu x86_pmu __read_mostly; + +static DEFINE_PER_CPU(struct cpu_hw_counters, cpu_hw_counters) = { + .enabled = 1, +}; + +/* + * Intel PerfMon v3. Used on Core2 and later. + */ +static const u64 intel_perfmon_event_map[] = +{ + [PERF_COUNT_HW_CPU_CYCLES] = 0x003c, + [PERF_COUNT_HW_INSTRUCTIONS] = 0x00c0, + [PERF_COUNT_HW_CACHE_REFERENCES] = 0x4f2e, + [PERF_COUNT_HW_CACHE_MISSES] = 0x412e, + [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x00c4, + [PERF_COUNT_HW_BRANCH_MISSES] = 0x00c5, + [PERF_COUNT_HW_BUS_CYCLES] = 0x013c, +}; + +static u64 intel_pmu_event_map(int event) +{ + return intel_perfmon_event_map[event]; +} + +/* + * Generalized hw caching related event table, filled + * in on a per model basis. A value of 0 means + * 'not supported', -1 means 'event makes no sense on + * this CPU', any other value means the raw event + * ID. + */ + +#define C(x) PERF_COUNT_HW_CACHE_##x + +static u64 __read_mostly hw_cache_event_ids + [PERF_COUNT_HW_CACHE_MAX] + [PERF_COUNT_HW_CACHE_OP_MAX] + [PERF_COUNT_HW_CACHE_RESULT_MAX]; + +static const u64 nehalem_hw_cache_event_ids + [PERF_COUNT_HW_CACHE_MAX] + [PERF_COUNT_HW_CACHE_OP_MAX] + [PERF_COUNT_HW_CACHE_RESULT_MAX] = +{ + [ C(L1D) ] = { + [ C(OP_READ) ] = { + [ C(RESULT_ACCESS) ] = 0x0f40, /* L1D_CACHE_LD.MESI */ + [ C(RESULT_MISS) ] = 0x0140, /* L1D_CACHE_LD.I_STATE */ + }, + [ C(OP_WRITE) ] = { + [ C(RESULT_ACCESS) ] = 0x0f41, /* L1D_CACHE_ST.MESI */ + [ C(RESULT_MISS) ] = 0x0141, /* L1D_CACHE_ST.I_STATE */ + }, + [ C(OP_PREFETCH) ] = { + [ C(RESULT_ACCESS) ] = 0x014e, /* L1D_PREFETCH.REQUESTS */ + [ C(RESULT_MISS) ] = 0x024e, /* L1D_PREFETCH.MISS */ + }, + }, + [ C(L1I ) ] = { + [ C(OP_READ) ] = { + [ C(RESULT_ACCESS) ] = 0x0380, /* L1I.READS */ + [ C(RESULT_MISS) ] = 0x0280, /* L1I.MISSES */ + }, + [ C(OP_WRITE) ] = { + [ C(RESULT_ACCESS) ] = -1, + [ C(RESULT_MISS) ] = -1, + }, + [ C(OP_PREFETCH) ] = { + [ C(RESULT_ACCESS) ] = 0x0, + [ C(RESULT_MISS) ] = 0x0, + }, + }, + [ C(LL ) ] = { + [ C(OP_READ) ] = { + [ C(RESULT_ACCESS) ] = 0x0324, /* L2_RQSTS.LOADS */ + [ C(RESULT_MISS) ] = 0x0224, /* L2_RQSTS.LD_MISS */ + }, + [ C(OP_WRITE) ] = { + [ C(RESULT_ACCESS) ] = 0x0c24, /* L2_RQSTS.RFOS */ + [ C(RESULT_MISS) ] = 0x0824, /* L2_RQSTS.RFO_MISS */ + }, + [ C(OP_PREFETCH) ] = { + [ C(RESULT_ACCESS) ] = 0x4f2e, /* LLC Reference */ + [ C(RESULT_MISS) ] = 0x412e, /* LLC Misses */ + }, + }, + [ C(DTLB) ] = { + [ C(OP_READ) ] = { + [ C(RESULT_ACCESS) ] = 0x0f40, /* L1D_CACHE_LD.MESI (alias) */ + [ C(RESULT_MISS) ] = 0x0108, /* DTLB_LOAD_MISSES.ANY */ + }, + [ C(OP_WRITE) ] = { + [ C(RESULT_ACCESS) ] = 0x0f41, /* L1D_CACHE_ST.MESI (alias) */ + [ C(RESULT_MISS) ] = 0x010c, /* MEM_STORE_RETIRED.DTLB_MISS */ + }, + [ C(OP_PREFETCH) ] = { + [ C(RESULT_ACCESS) ] = 0x0, + [ C(RESULT_MISS) ] = 0x0, + }, + }, + [ C(ITLB) ] = { + [ C(OP_READ) ] = { + [ C(RESULT_ACCESS) ] = 0x01c0, /* INST_RETIRED.ANY_P */ + [ C(RESULT_MISS) ] = 0x20c8, /* ITLB_MISS_RETIRED */ + }, + [ C(OP_WRITE) ] = { + [ C(RESULT_ACCESS) ] = -1, + [ C(RESULT_MISS) ] = -1, + }, + [ C(OP_PREFETCH) ] = { + [ C(RESULT_ACCESS) ] = -1, + [ C(RESULT_MISS) ] = -1, + }, + }, + [ C(BPU ) ] = { + [ C(OP_READ) ] = { + [ C(RESULT_ACCESS) ] = 0x00c4, /* BR_INST_RETIRED.ALL_BRANCHES */ + [ C(RESULT_MISS) ] = 0x03e8, /* BPU_CLEARS.ANY */ + }, + [ C(OP_WRITE) ] = { + [ C(RESULT_ACCESS) ] = -1, + [ C(RESULT_MISS) ] = -1, + }, + [ C(OP_PREFETCH) ] = { + [ C(RESULT_ACCESS) ] = -1, + [ C(RESULT_MISS) ] = -1, + }, + }, +}; + +static const u64 core2_hw_cache_event_ids + [PERF_COUNT_HW_CACHE_MAX] + [PERF_COUNT_HW_CACHE_OP_MAX] + [PERF_COUNT_HW_CACHE_RESULT_MAX] = +{ + [ C(L1D) ] = { + [ C(OP_READ) ] = { + [ C(RESULT_ACCESS) ] = 0x0f40, /* L1D_CACHE_LD.MESI */ + [ C(RESULT_MISS) ] = 0x0140, /* L1D_CACHE_LD.I_STATE */ + }, + [ C(OP_WRITE) ] = { + [ C(RESULT_ACCESS) ] = 0x0f41, /* L1D_CACHE_ST.MESI */ + [ C(RESULT_MISS) ] = 0x0141, /* L1D_CACHE_ST.I_STATE */ + }, + [ C(OP_PREFETCH) ] = { + [ C(RESULT_ACCESS) ] = 0x104e, /* L1D_PREFETCH.REQUESTS */ + [ C(RESULT_MISS) ] = 0, + }, + }, + [ C(L1I ) ] = { + [ C(OP_READ) ] = { + [ C(RESULT_ACCESS) ] = 0x0080, /* L1I.READS */ + [ C(RESULT_MISS) ] = 0x0081, /* L1I.MISSES */ + }, + [ C(OP_WRITE) ] = { + [ C(RESULT_ACCESS) ] = -1, + [ C(RESULT_MISS) ] = -1, + }, + [ C(OP_PREFETCH) ] = { + [ C(RESULT_ACCESS) ] = 0, + [ C(RESULT_MISS) ] = 0, + }, + }, + [ C(LL ) ] = { + [ C(OP_READ) ] = { + [ C(RESULT_ACCESS) ] = 0x4f29, /* L2_LD.MESI */ + [ C(RESULT_MISS) ] = 0x4129, /* L2_LD.ISTATE */ + }, + [ C(OP_WRITE) ] = { + [ C(RESULT_ACCESS) ] = 0x4f2A, /* L2_ST.MESI */ + [ C(RESULT_MISS) ] = 0x412A, /* L2_ST.ISTATE */ + }, + [ C(OP_PREFETCH) ] = { + [ C(RESULT_ACCESS) ] = 0, + [ C(RESULT_MISS) ] = 0, + }, + }, + [ C(DTLB) ] = { + [ C(OP_READ) ] = { + [ C(RESULT_ACCESS) ] = 0x0f40, /* L1D_CACHE_LD.MESI (alias) */ + [ C(RESULT_MISS) ] = 0x0208, /* DTLB_MISSES.MISS_LD */ + }, + [ C(OP_WRITE) ] = { + [ C(RESULT_ACCESS) ] = 0x0f41, /* L1D_CACHE_ST.MESI (alias) */ + [ C(RESULT_MISS) ] = 0x0808, /* DTLB_MISSES.MISS_ST */ + }, + [ C(OP_PREFETCH) ] = { + [ C(RESULT_ACCESS) ] = 0, + [ C(RESULT_MISS) ] = 0, + }, + }, + [ C(ITLB) ] = { + [ C(OP_READ) ] = { + [ C(RESULT_ACCESS) ] = 0x00c0, /* INST_RETIRED.ANY_P */ + [ C(RESULT_MISS) ] = 0x1282, /* ITLBMISSES */ + }, + [ C(OP_WRITE) ] = { + [ C(RESULT_ACCESS) ] = -1, + [ C(RESULT_MISS) ] = -1, + }, + [ C(OP_PREFETCH) ] = { + [ C(RESULT_ACCESS) ] = -1, + [ C(RESULT_MISS) ] = -1, + }, + }, + [ C(BPU ) ] = { + [ C(OP_READ) ] = { + [ C(RESULT_ACCESS) ] = 0x00c4, /* BR_INST_RETIRED.ANY */ + [ C(RESULT_MISS) ] = 0x00c5, /* BP_INST_RETIRED.MISPRED */ + }, + [ C(OP_WRITE) ] = { + [ C(RESULT_ACCESS) ] = -1, + [ C(RESULT_MISS) ] = -1, + }, + [ C(OP_PREFETCH) ] = { + [ C(RESULT_ACCESS) ] = -1, + [ C(RESULT_MISS) ] = -1, + }, + }, +}; + +static const u64 atom_hw_cache_event_ids + [PERF_COUNT_HW_CACHE_MAX] + [PERF_COUNT_HW_CACHE_OP_MAX] + [PERF_COUNT_HW_CACHE_RESULT_MAX] = +{ + [ C(L1D) ] = { + [ C(OP_READ) ] = { + [ C(RESULT_ACCESS) ] = 0x2140, /* L1D_CACHE.LD */ + [ C(RESULT_MISS) ] = 0, + }, + [ C(OP_WRITE) ] = { + [ C(RESULT_ACCESS) ] = 0x2240, /* L1D_CACHE.ST */ + [ C(RESULT_MISS) ] = 0, + }, + [ C(OP_PREFETCH) ] = { + [ C(RESULT_ACCESS) ] = 0x0, + [ C(RESULT_MISS) ] = 0, + }, + }, + [ C(L1I ) ] = { + [ C(OP_READ) ] = { + [ C(RESULT_ACCESS) ] = 0x0380, /* L1I.READS */ + [ C(RESULT_MISS) ] = 0x0280, /* L1I.MISSES */ + }, + [ C(OP_WRITE) ] = { + [ C(RESULT_ACCESS) ] = -1, + [ C(RESULT_MISS) ] = -1, + }, + [ C(OP_PREFETCH) ] = { + [ C(RESULT_ACCESS) ] = 0, + [ C(RESULT_MISS) ] = 0, + }, + }, + [ C(LL ) ] = { + [ C(OP_READ) ] = { + [ C(RESULT_ACCESS) ] = 0x4f29, /* L2_LD.MESI */ + [ C(RESULT_MISS) ] = 0x4129, /* L2_LD.ISTATE */ + }, + [ C(OP_WRITE) ] = { + [ C(RESULT_ACCESS) ] = 0x4f2A, /* L2_ST.MESI */ + [ C(RESULT_MISS) ] = 0x412A, /* L2_ST.ISTATE */ + }, + [ C(OP_PREFETCH) ] = { + [ C(RESULT_ACCESS) ] = 0, + [ C(RESULT_MISS) ] = 0, + }, + }, + [ C(DTLB) ] = { + [ C(OP_READ) ] = { + [ C(RESULT_ACCESS) ] = 0x2140, /* L1D_CACHE_LD.MESI (alias) */ + [ C(RESULT_MISS) ] = 0x0508, /* DTLB_MISSES.MISS_LD */ + }, + [ C(OP_WRITE) ] = { + [ C(RESULT_ACCESS) ] = 0x2240, /* L1D_CACHE_ST.MESI (alias) */ + [ C(RESULT_MISS) ] = 0x0608, /* DTLB_MISSES.MISS_ST */ + }, + [ C(OP_PREFETCH) ] = { + [ C(RESULT_ACCESS) ] = 0, + [ C(RESULT_MISS) ] = 0, + }, + }, + [ C(ITLB) ] = { + [ C(OP_READ) ] = { + [ C(RESULT_ACCESS) ] = 0x00c0, /* INST_RETIRED.ANY_P */ + [ C(RESULT_MISS) ] = 0x0282, /* ITLB.MISSES */ + }, + [ C(OP_WRITE) ] = { + [ C(RESULT_ACCESS) ] = -1, + [ C(RESULT_MISS) ] = -1, + }, + [ C(OP_PREFETCH) ] = { + [ C(RESULT_ACCESS) ] = -1, + [ C(RESULT_MISS) ] = -1, + }, + }, + [ C(BPU ) ] = { + [ C(OP_READ) ] = { + [ C(RESULT_ACCESS) ] = 0x00c4, /* BR_INST_RETIRED.ANY */ + [ C(RESULT_MISS) ] = 0x00c5, /* BP_INST_RETIRED.MISPRED */ + }, + [ C(OP_WRITE) ] = { + [ C(RESULT_ACCESS) ] = -1, + [ C(RESULT_MISS) ] = -1, + }, + [ C(OP_PREFETCH) ] = { + [ C(RESULT_ACCESS) ] = -1, + [ C(RESULT_MISS) ] = -1, + }, + }, +}; + +static u64 intel_pmu_raw_event(u64 event) +{ +#define CORE_EVNTSEL_EVENT_MASK 0x000000FFULL +#define CORE_EVNTSEL_UNIT_MASK 0x0000FF00ULL +#define CORE_EVNTSEL_EDGE_MASK 0x00040000ULL +#define CORE_EVNTSEL_INV_MASK 0x00800000ULL +#define CORE_EVNTSEL_COUNTER_MASK 0xFF000000ULL + +#define CORE_EVNTSEL_MASK \ + (CORE_EVNTSEL_EVENT_MASK | \ + CORE_EVNTSEL_UNIT_MASK | \ + CORE_EVNTSEL_EDGE_MASK | \ + CORE_EVNTSEL_INV_MASK | \ + CORE_EVNTSEL_COUNTER_MASK) + + return event & CORE_EVNTSEL_MASK; +} + +static const u64 amd_hw_cache_event_ids + [PERF_COUNT_HW_CACHE_MAX] + [PERF_COUNT_HW_CACHE_OP_MAX] + [PERF_COUNT_HW_CACHE_RESULT_MAX] = +{ + [ C(L1D) ] = { + [ C(OP_READ) ] = { + [ C(RESULT_ACCESS) ] = 0x0040, /* Data Cache Accesses */ + [ C(RESULT_MISS) ] = 0x0041, /* Data Cache Misses */ + }, + [ C(OP_WRITE) ] = { + [ C(RESULT_ACCESS) ] = 0x0042, /* Data Cache Refills from L2 */ + [ C(RESULT_MISS) ] = 0, + }, + [ C(OP_PREFETCH) ] = { + [ C(RESULT_ACCESS) ] = 0x0267, /* Data Prefetcher :attempts */ + [ C(RESULT_MISS) ] = 0x0167, /* Data Prefetcher :cancelled */ + }, + }, + [ C(L1I ) ] = { + [ C(OP_READ) ] = { + [ C(RESULT_ACCESS) ] = 0x0080, /* Instruction cache fetches */ + [ C(RESULT_MISS) ] = 0x0081, /* Instruction cache misses */ + }, + [ C(OP_WRITE) ] = { + [ C(RESULT_ACCESS) ] = -1, + [ C(RESULT_MISS) ] = -1, + }, + [ C(OP_PREFETCH) ] = { + [ C(RESULT_ACCESS) ] = 0x014B, /* Prefetch Instructions :Load */ + [ C(RESULT_MISS) ] = 0, + }, + }, + [ C(LL ) ] = { + [ C(OP_READ) ] = { + [ C(RESULT_ACCESS) ] = 0x037D, /* Requests to L2 Cache :IC+DC */ + [ C(RESULT_MISS) ] = 0x037E, /* L2 Cache Misses : IC+DC */ + }, + [ C(OP_WRITE) ] = { + [ C(RESULT_ACCESS) ] = 0x017F, /* L2 Fill/Writeback */ + [ C(RESULT_MISS) ] = 0, + }, + [ C(OP_PREFETCH) ] = { + [ C(RESULT_ACCESS) ] = 0, + [ C(RESULT_MISS) ] = 0, + }, + }, + [ C(DTLB) ] = { + [ C(OP_READ) ] = { + [ C(RESULT_ACCESS) ] = 0x0040, /* Data Cache Accesses */ + [ C(RESULT_MISS) ] = 0x0046, /* L1 DTLB and L2 DLTB Miss */ + }, + [ C(OP_WRITE) ] = { + [ C(RESULT_ACCESS) ] = 0, + [ C(RESULT_MISS) ] = 0, + }, + [ C(OP_PREFETCH) ] = { + [ C(RESULT_ACCESS) ] = 0, + [ C(RESULT_MISS) ] = 0, + }, + }, + [ C(ITLB) ] = { + [ C(OP_READ) ] = { + [ C(RESULT_ACCESS) ] = 0x0080, /* Instruction fecthes */ + [ C(RESULT_MISS) ] = 0x0085, /* Instr. fetch ITLB misses */ + }, + [ C(OP_WRITE) ] = { + [ C(RESULT_ACCESS) ] = -1, + [ C(RESULT_MISS) ] = -1, + }, + [ C(OP_PREFETCH) ] = { + [ C(RESULT_ACCESS) ] = -1, + [ C(RESULT_MISS) ] = -1, + }, + }, + [ C(BPU ) ] = { + [ C(OP_READ) ] = { + [ C(RESULT_ACCESS) ] = 0x00c2, /* Retired Branch Instr. */ + [ C(RESULT_MISS) ] = 0x00c3, /* Retired Mispredicted BI */ + }, + [ C(OP_WRITE) ] = { + [ C(RESULT_ACCESS) ] = -1, + [ C(RESULT_MISS) ] = -1, + }, + [ C(OP_PREFETCH) ] = { + [ C(RESULT_ACCESS) ] = -1, + [ C(RESULT_MISS) ] = -1, + }, + }, +}; + +/* + * AMD Performance Monitor K7 and later. + */ +static const u64 amd_perfmon_event_map[] = +{ + [PERF_COUNT_HW_CPU_CYCLES] = 0x0076, + [PERF_COUNT_HW_INSTRUCTIONS] = 0x00c0, + [PERF_COUNT_HW_CACHE_REFERENCES] = 0x0080, + [PERF_COUNT_HW_CACHE_MISSES] = 0x0081, + [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x00c4, + [PERF_COUNT_HW_BRANCH_MISSES] = 0x00c5, +}; + +static u64 amd_pmu_event_map(int event) +{ + return amd_perfmon_event_map[event]; +} + +static u64 amd_pmu_raw_event(u64 event) +{ +#define K7_EVNTSEL_EVENT_MASK 0x7000000FFULL +#define K7_EVNTSEL_UNIT_MASK 0x00000FF00ULL +#define K7_EVNTSEL_EDGE_MASK 0x000040000ULL +#define K7_EVNTSEL_INV_MASK 0x000800000ULL +#define K7_EVNTSEL_COUNTER_MASK 0x0FF000000ULL + +#define K7_EVNTSEL_MASK \ + (K7_EVNTSEL_EVENT_MASK | \ + K7_EVNTSEL_UNIT_MASK | \ + K7_EVNTSEL_EDGE_MASK | \ + K7_EVNTSEL_INV_MASK | \ + K7_EVNTSEL_COUNTER_MASK) + + return event & K7_EVNTSEL_MASK; +} + +/* + * Propagate counter elapsed time into the generic counter. + * Can only be executed on the CPU where the counter is active. + * Returns the delta events processed. + */ +static u64 +x86_perf_counter_update(struct perf_counter *counter, + struct hw_perf_counter *hwc, int idx) +{ + int shift = 64 - x86_pmu.counter_bits; + u64 prev_raw_count, new_raw_count; + s64 delta; + + /* + * Careful: an NMI might modify the previous counter value. + * + * Our tactic to handle this is to first atomically read and + * exchange a new raw count - then add that new-prev delta + * count to the generic counter atomically: + */ +again: + prev_raw_count = atomic64_read(&hwc->prev_count); + rdmsrl(hwc->counter_base + idx, new_raw_count); + + if (atomic64_cmpxchg(&hwc->prev_count, prev_raw_count, + new_raw_count) != prev_raw_count) + goto again; + + /* + * Now we have the new raw value and have updated the prev + * timestamp already. We can now calculate the elapsed delta + * (counter-)time and add that to the generic counter. + * + * Careful, not all hw sign-extends above the physical width + * of the count. + */ + delta = (new_raw_count << shift) - (prev_raw_count << shift); + delta >>= shift; + + atomic64_add(delta, &counter->count); + atomic64_sub(delta, &hwc->period_left); + + return new_raw_count; +} + +static atomic_t active_counters; +static DEFINE_MUTEX(pmc_reserve_mutex); + +static bool reserve_pmc_hardware(void) +{ + int i; + + if (nmi_watchdog == NMI_LOCAL_APIC) + disable_lapic_nmi_watchdog(); + + for (i = 0; i < x86_pmu.num_counters; i++) { + if (!reserve_perfctr_nmi(x86_pmu.perfctr + i)) + goto perfctr_fail; + } + + for (i = 0; i < x86_pmu.num_counters; i++) { + if (!reserve_evntsel_nmi(x86_pmu.eventsel + i)) + goto eventsel_fail; + } + + return true; + +eventsel_fail: + for (i--; i >= 0; i--) + release_evntsel_nmi(x86_pmu.eventsel + i); + + i = x86_pmu.num_counters; + +perfctr_fail: + for (i--; i >= 0; i--) + release_perfctr_nmi(x86_pmu.perfctr + i); + + if (nmi_watchdog == NMI_LOCAL_APIC) + enable_lapic_nmi_watchdog(); + + return false; +} + +static void release_pmc_hardware(void) +{ + int i; + + for (i = 0; i < x86_pmu.num_counters; i++) { + release_perfctr_nmi(x86_pmu.perfctr + i); + release_evntsel_nmi(x86_pmu.eventsel + i); + } + + if (nmi_watchdog == NMI_LOCAL_APIC) + enable_lapic_nmi_watchdog(); +} + +static void hw_perf_counter_destroy(struct perf_counter *counter) +{ + if (atomic_dec_and_mutex_lock(&active_counters, &pmc_reserve_mutex)) { + release_pmc_hardware(); + mutex_unlock(&pmc_reserve_mutex); + } +} + +static inline int x86_pmu_initialized(void) +{ + return x86_pmu.handle_irq != NULL; +} + +static inline int +set_ext_hw_attr(struct hw_perf_counter *hwc, struct perf_counter_attr *attr) +{ + unsigned int cache_type, cache_op, cache_result; + u64 config, val; + + config = attr->config; + + cache_type = (config >> 0) & 0xff; + if (cache_type >= PERF_COUNT_HW_CACHE_MAX) + return -EINVAL; + + cache_op = (config >> 8) & 0xff; + if (cache_op >= PERF_COUNT_HW_CACHE_OP_MAX) + return -EINVAL; + + cache_result = (config >> 16) & 0xff; + if (cache_result >= PERF_COUNT_HW_CACHE_RESULT_MAX) + return -EINVAL; + + val = hw_cache_event_ids[cache_type][cache_op][cache_result]; + + if (val == 0) + return -ENOENT; + + if (val == -1) + return -EINVAL; + + hwc->config |= val; + + return 0; +} + +/* + * Setup the hardware configuration for a given attr_type + */ +static int __hw_perf_counter_init(struct perf_counter *counter) +{ + struct perf_counter_attr *attr = &counter->attr; + struct hw_perf_counter *hwc = &counter->hw; + int err; + + if (!x86_pmu_initialized()) + return -ENODEV; + + err = 0; + if (!atomic_inc_not_zero(&active_counters)) { + mutex_lock(&pmc_reserve_mutex); + if (atomic_read(&active_counters) == 0 && !reserve_pmc_hardware()) + err = -EBUSY; + else + atomic_inc(&active_counters); + mutex_unlock(&pmc_reserve_mutex); + } + if (err) + return err; + + /* + * Generate PMC IRQs: + * (keep 'enabled' bit clear for now) + */ + hwc->config = ARCH_PERFMON_EVENTSEL_INT; + + /* + * Count user and OS events unless requested not to. + */ + if (!attr->exclude_user) + hwc->config |= ARCH_PERFMON_EVENTSEL_USR; + if (!attr->exclude_kernel) + hwc->config |= ARCH_PERFMON_EVENTSEL_OS; + + if (!hwc->sample_period) { + hwc->sample_period = x86_pmu.max_period; + hwc->last_period = hwc->sample_period; + atomic64_set(&hwc->period_left, hwc->sample_period); + } + + counter->destroy = hw_perf_counter_destroy; + + /* + * Raw event type provide the config in the event structure + */ + if (attr->type == PERF_TYPE_RAW) { + hwc->config |= x86_pmu.raw_event(attr->config); + return 0; + } + + if (attr->type == PERF_TYPE_HW_CACHE) + return set_ext_hw_attr(hwc, attr); + + if (attr->config >= x86_pmu.max_events) + return -EINVAL; + /* + * The generic map: + */ + hwc->config |= x86_pmu.event_map(attr->config); + + return 0; +} + +static void intel_pmu_disable_all(void) +{ + wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, 0); +} + +static void amd_pmu_disable_all(void) +{ + struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters); + int idx; + + if (!cpuc->enabled) + return; + + cpuc->enabled = 0; + /* + * ensure we write the disable before we start disabling the + * counters proper, so that amd_pmu_enable_counter() does the + * right thing. + */ + barrier(); + + for (idx = 0; idx < x86_pmu.num_counters; idx++) { + u64 val; + + if (!test_bit(idx, cpuc->active_mask)) + continue; + rdmsrl(MSR_K7_EVNTSEL0 + idx, val); + if (!(val & ARCH_PERFMON_EVENTSEL0_ENABLE)) + continue; + val &= ~ARCH_PERFMON_EVENTSEL0_ENABLE; + wrmsrl(MSR_K7_EVNTSEL0 + idx, val); + } +} + +void hw_perf_disable(void) +{ + if (!x86_pmu_initialized()) + return; + return x86_pmu.disable_all(); +} + +static void intel_pmu_enable_all(void) +{ + wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, x86_pmu.intel_ctrl); +} + +static void amd_pmu_enable_all(void) +{ + struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters); + int idx; + + if (cpuc->enabled) + return; + + cpuc->enabled = 1; + barrier(); + + for (idx = 0; idx < x86_pmu.num_counters; idx++) { + u64 val; + + if (!test_bit(idx, cpuc->active_mask)) + continue; + rdmsrl(MSR_K7_EVNTSEL0 + idx, val); + if (val & ARCH_PERFMON_EVENTSEL0_ENABLE) + continue; + val |= ARCH_PERFMON_EVENTSEL0_ENABLE; + wrmsrl(MSR_K7_EVNTSEL0 + idx, val); + } +} + +void hw_perf_enable(void) +{ + if (!x86_pmu_initialized()) + return; + x86_pmu.enable_all(); +} + +static inline u64 intel_pmu_get_status(void) +{ + u64 status; + + rdmsrl(MSR_CORE_PERF_GLOBAL_STATUS, status); + + return status; +} + +static inline void intel_pmu_ack_status(u64 ack) +{ + wrmsrl(MSR_CORE_PERF_GLOBAL_OVF_CTRL, ack); +} + +static inline void x86_pmu_enable_counter(struct hw_perf_counter *hwc, int idx) +{ + int err; + err = checking_wrmsrl(hwc->config_base + idx, + hwc->config | ARCH_PERFMON_EVENTSEL0_ENABLE); +} + +static inline void x86_pmu_disable_counter(struct hw_perf_counter *hwc, int idx) +{ + int err; + err = checking_wrmsrl(hwc->config_base + idx, + hwc->config); +} + +static inline void +intel_pmu_disable_fixed(struct hw_perf_counter *hwc, int __idx) +{ + int idx = __idx - X86_PMC_IDX_FIXED; + u64 ctrl_val, mask; + int err; + + mask = 0xfULL << (idx * 4); + + rdmsrl(hwc->config_base, ctrl_val); + ctrl_val &= ~mask; + err = checking_wrmsrl(hwc->config_base, ctrl_val); +} + +static inline void +intel_pmu_disable_counter(struct hw_perf_counter *hwc, int idx) +{ + if (unlikely(hwc->config_base == MSR_ARCH_PERFMON_FIXED_CTR_CTRL)) { + intel_pmu_disable_fixed(hwc, idx); + return; + } + + x86_pmu_disable_counter(hwc, idx); +} + +static inline void +amd_pmu_disable_counter(struct hw_perf_counter *hwc, int idx) +{ + x86_pmu_disable_counter(hwc, idx); +} + +static DEFINE_PER_CPU(u64, prev_left[X86_PMC_IDX_MAX]); + +/* + * Set the next IRQ period, based on the hwc->period_left value. + * To be called with the counter disabled in hw: + */ +static int +x86_perf_counter_set_period(struct perf_counter *counter, + struct hw_perf_counter *hwc, int idx) +{ + s64 left = atomic64_read(&hwc->period_left); + s64 period = hwc->sample_period; + int err, ret = 0; + + /* + * If we are way outside a reasoable range then just skip forward: + */ + if (unlikely(left <= -period)) { + left = period; + atomic64_set(&hwc->period_left, left); + hwc->last_period = period; + ret = 1; + } + + if (unlikely(left <= 0)) { + left += period; + atomic64_set(&hwc->period_left, left); + hwc->last_period = period; + ret = 1; + } + /* + * Quirk: certain CPUs dont like it if just 1 event is left: + */ + if (unlikely(left < 2)) + left = 2; + + if (left > x86_pmu.max_period) + left = x86_pmu.max_period; + + per_cpu(prev_left[idx], smp_processor_id()) = left; + + /* + * The hw counter starts counting from this counter offset, + * mark it to be able to extra future deltas: + */ + atomic64_set(&hwc->prev_count, (u64)-left); + + err = checking_wrmsrl(hwc->counter_base + idx, + (u64)(-left) & x86_pmu.counter_mask); + + return ret; +} + +static inline void +intel_pmu_enable_fixed(struct hw_perf_counter *hwc, int __idx) +{ + int idx = __idx - X86_PMC_IDX_FIXED; + u64 ctrl_val, bits, mask; + int err; + + /* + * Enable IRQ generation (0x8), + * and enable ring-3 counting (0x2) and ring-0 counting (0x1) + * if requested: + */ + bits = 0x8ULL; + if (hwc->config & ARCH_PERFMON_EVENTSEL_USR) + bits |= 0x2; + if (hwc->config & ARCH_PERFMON_EVENTSEL_OS) + bits |= 0x1; + bits <<= (idx * 4); + mask = 0xfULL << (idx * 4); + + rdmsrl(hwc->config_base, ctrl_val); + ctrl_val &= ~mask; + ctrl_val |= bits; + err = checking_wrmsrl(hwc->config_base, ctrl_val); +} + +static void intel_pmu_enable_counter(struct hw_perf_counter *hwc, int idx) +{ + if (unlikely(hwc->config_base == MSR_ARCH_PERFMON_FIXED_CTR_CTRL)) { + intel_pmu_enable_fixed(hwc, idx); + return; + } + + x86_pmu_enable_counter(hwc, idx); +} + +static void amd_pmu_enable_counter(struct hw_perf_counter *hwc, int idx) +{ + struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters); + + if (cpuc->enabled) + x86_pmu_enable_counter(hwc, idx); + else + x86_pmu_disable_counter(hwc, idx); +} + +static int +fixed_mode_idx(struct perf_counter *counter, struct hw_perf_counter *hwc) +{ + unsigned int event; + + if (!x86_pmu.num_counters_fixed) + return -1; + + /* + * Quirk, IA32_FIXED_CTRs do not work on current Atom processors: + */ + if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL && + boot_cpu_data.x86_model == 28) + return -1; + + event = hwc->config & ARCH_PERFMON_EVENT_MASK; + + if (unlikely(event == x86_pmu.event_map(PERF_COUNT_HW_INSTRUCTIONS))) + return X86_PMC_IDX_FIXED_INSTRUCTIONS; + if (unlikely(event == x86_pmu.event_map(PERF_COUNT_HW_CPU_CYCLES))) + return X86_PMC_IDX_FIXED_CPU_CYCLES; + if (unlikely(event == x86_pmu.event_map(PERF_COUNT_HW_BUS_CYCLES))) + return X86_PMC_IDX_FIXED_BUS_CYCLES; + + return -1; +} + +/* + * Find a PMC slot for the freshly enabled / scheduled in counter: + */ +static int x86_pmu_enable(struct perf_counter *counter) +{ + struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters); + struct hw_perf_counter *hwc = &counter->hw; + int idx; + + idx = fixed_mode_idx(counter, hwc); + if (idx >= 0) { + /* + * Try to get the fixed counter, if that is already taken + * then try to get a generic counter: + */ + if (test_and_set_bit(idx, cpuc->used_mask)) + goto try_generic; + + hwc->config_base = MSR_ARCH_PERFMON_FIXED_CTR_CTRL; + /* + * We set it so that counter_base + idx in wrmsr/rdmsr maps to + * MSR_ARCH_PERFMON_FIXED_CTR0 ... CTR2: + */ + hwc->counter_base = + MSR_ARCH_PERFMON_FIXED_CTR0 - X86_PMC_IDX_FIXED; + hwc->idx = idx; + } else { + idx = hwc->idx; + /* Try to get the previous generic counter again */ + if (test_and_set_bit(idx, cpuc->used_mask)) { +try_generic: + idx = find_first_zero_bit(cpuc->used_mask, + x86_pmu.num_counters); + if (idx == x86_pmu.num_counters) + return -EAGAIN; + + set_bit(idx, cpuc->used_mask); + hwc->idx = idx; + } + hwc->config_base = x86_pmu.eventsel; + hwc->counter_base = x86_pmu.perfctr; + } + + perf_counters_lapic_init(); + + x86_pmu.disable(hwc, idx); + + cpuc->counters[idx] = counter; + set_bit(idx, cpuc->active_mask); + + x86_perf_counter_set_period(counter, hwc, idx); + x86_pmu.enable(hwc, idx); + + return 0; +} + +static void x86_pmu_unthrottle(struct perf_counter *counter) +{ + struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters); + struct hw_perf_counter *hwc = &counter->hw; + + if (WARN_ON_ONCE(hwc->idx >= X86_PMC_IDX_MAX || + cpuc->counters[hwc->idx] != counter)) + return; + + x86_pmu.enable(hwc, hwc->idx); +} + +void perf_counter_print_debug(void) +{ + u64 ctrl, status, overflow, pmc_ctrl, pmc_count, prev_left, fixed; + struct cpu_hw_counters *cpuc; + unsigned long flags; + int cpu, idx; + + if (!x86_pmu.num_counters) + return; + + local_irq_save(flags); + + cpu = smp_processor_id(); + cpuc = &per_cpu(cpu_hw_counters, cpu); + + if (x86_pmu.version >= 2) { + rdmsrl(MSR_CORE_PERF_GLOBAL_CTRL, ctrl); + rdmsrl(MSR_CORE_PERF_GLOBAL_STATUS, status); + rdmsrl(MSR_CORE_PERF_GLOBAL_OVF_CTRL, overflow); + rdmsrl(MSR_ARCH_PERFMON_FIXED_CTR_CTRL, fixed); + + pr_info("\n"); + pr_info("CPU#%d: ctrl: %016llx\n", cpu, ctrl); + pr_info("CPU#%d: status: %016llx\n", cpu, status); + pr_info("CPU#%d: overflow: %016llx\n", cpu, overflow); + pr_info("CPU#%d: fixed: %016llx\n", cpu, fixed); + } + pr_info("CPU#%d: used: %016llx\n", cpu, *(u64 *)cpuc->used_mask); + + for (idx = 0; idx < x86_pmu.num_counters; idx++) { + rdmsrl(x86_pmu.eventsel + idx, pmc_ctrl); + rdmsrl(x86_pmu.perfctr + idx, pmc_count); + + prev_left = per_cpu(prev_left[idx], cpu); + + pr_info("CPU#%d: gen-PMC%d ctrl: %016llx\n", + cpu, idx, pmc_ctrl); + pr_info("CPU#%d: gen-PMC%d count: %016llx\n", + cpu, idx, pmc_count); + pr_info("CPU#%d: gen-PMC%d left: %016llx\n", + cpu, idx, prev_left); + } + for (idx = 0; idx < x86_pmu.num_counters_fixed; idx++) { + rdmsrl(MSR_ARCH_PERFMON_FIXED_CTR0 + idx, pmc_count); + + pr_info("CPU#%d: fixed-PMC%d count: %016llx\n", + cpu, idx, pmc_count); + } + local_irq_restore(flags); +} + +static void x86_pmu_disable(struct perf_counter *counter) +{ + struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters); + struct hw_perf_counter *hwc = &counter->hw; + int idx = hwc->idx; + + /* + * Must be done before we disable, otherwise the nmi handler + * could reenable again: + */ + clear_bit(idx, cpuc->active_mask); + x86_pmu.disable(hwc, idx); + + /* + * Make sure the cleared pointer becomes visible before we + * (potentially) free the counter: + */ + barrier(); + + /* + * Drain the remaining delta count out of a counter + * that we are disabling: + */ + x86_perf_counter_update(counter, hwc, idx); + cpuc->counters[idx] = NULL; + clear_bit(idx, cpuc->used_mask); +} + +/* + * Save and restart an expired counter. Called by NMI contexts, + * so it has to be careful about preempting normal counter ops: + */ +static int intel_pmu_save_and_restart(struct perf_counter *counter) +{ + struct hw_perf_counter *hwc = &counter->hw; + int idx = hwc->idx; + int ret; + + x86_perf_counter_update(counter, hwc, idx); + ret = x86_perf_counter_set_period(counter, hwc, idx); + + if (counter->state == PERF_COUNTER_STATE_ACTIVE) + intel_pmu_enable_counter(hwc, idx); + + return ret; +} + +static void intel_pmu_reset(void) +{ + unsigned long flags; + int idx; + + if (!x86_pmu.num_counters) + return; + + local_irq_save(flags); + + printk("clearing PMU state on CPU#%d\n", smp_processor_id()); + + for (idx = 0; idx < x86_pmu.num_counters; idx++) { + checking_wrmsrl(x86_pmu.eventsel + idx, 0ull); + checking_wrmsrl(x86_pmu.perfctr + idx, 0ull); + } + for (idx = 0; idx < x86_pmu.num_counters_fixed; idx++) { + checking_wrmsrl(MSR_ARCH_PERFMON_FIXED_CTR0 + idx, 0ull); + } + + local_irq_restore(flags); +} + + +/* + * This handler is triggered by the local APIC, so the APIC IRQ handling + * rules apply: + */ +static int intel_pmu_handle_irq(struct pt_regs *regs) +{ + struct perf_sample_data data; + struct cpu_hw_counters *cpuc; + int bit, cpu, loops; + u64 ack, status; + + data.regs = regs; + data.addr = 0; + + cpu = smp_processor_id(); + cpuc = &per_cpu(cpu_hw_counters, cpu); + + perf_disable(); + status = intel_pmu_get_status(); + if (!status) { + perf_enable(); + return 0; + } + + loops = 0; +again: + if (++loops > 100) { + WARN_ONCE(1, "perfcounters: irq loop stuck!\n"); + perf_counter_print_debug(); + intel_pmu_reset(); + perf_enable(); + return 1; + } + + inc_irq_stat(apic_perf_irqs); + ack = status; + for_each_bit(bit, (unsigned long *)&status, X86_PMC_IDX_MAX) { + struct perf_counter *counter = cpuc->counters[bit]; + + clear_bit(bit, (unsigned long *) &status); + if (!test_bit(bit, cpuc->active_mask)) + continue; + + if (!intel_pmu_save_and_restart(counter)) + continue; + + data.period = counter->hw.last_period; + + if (perf_counter_overflow(counter, 1, &data)) + intel_pmu_disable_counter(&counter->hw, bit); + } + + intel_pmu_ack_status(ack); + + /* + * Repeat if there is more work to be done: + */ + status = intel_pmu_get_status(); + if (status) + goto again; + + perf_enable(); + + return 1; +} + +static int amd_pmu_handle_irq(struct pt_regs *regs) +{ + struct perf_sample_data data; + struct cpu_hw_counters *cpuc; + struct perf_counter *counter; + struct hw_perf_counter *hwc; + int cpu, idx, handled = 0; + u64 val; + + data.regs = regs; + data.addr = 0; + + cpu = smp_processor_id(); + cpuc = &per_cpu(cpu_hw_counters, cpu); + + for (idx = 0; idx < x86_pmu.num_counters; idx++) { + if (!test_bit(idx, cpuc->active_mask)) + continue; + + counter = cpuc->counters[idx]; + hwc = &counter->hw; + + val = x86_perf_counter_update(counter, hwc, idx); + if (val & (1ULL << (x86_pmu.counter_bits - 1))) + continue; + + /* + * counter overflow + */ + handled = 1; + data.period = counter->hw.last_period; + + if (!x86_perf_counter_set_period(counter, hwc, idx)) + continue; + + if (perf_counter_overflow(counter, 1, &data)) + amd_pmu_disable_counter(hwc, idx); + } + + if (handled) + inc_irq_stat(apic_perf_irqs); + + return handled; +} + +void smp_perf_pending_interrupt(struct pt_regs *regs) +{ + irq_enter(); + ack_APIC_irq(); + inc_irq_stat(apic_pending_irqs); + perf_counter_do_pending(); + irq_exit(); +} + +void set_perf_counter_pending(void) +{ + apic->send_IPI_self(LOCAL_PENDING_VECTOR); +} + +void perf_counters_lapic_init(void) +{ + if (!x86_pmu_initialized()) + return; + + /* + * Always use NMI for PMU + */ + apic_write(APIC_LVTPC, APIC_DM_NMI); +} + +static int __kprobes +perf_counter_nmi_handler(struct notifier_block *self, + unsigned long cmd, void *__args) +{ + struct die_args *args = __args; + struct pt_regs *regs; + + if (!atomic_read(&active_counters)) + return NOTIFY_DONE; + + switch (cmd) { + case DIE_NMI: + case DIE_NMI_IPI: + break; + + default: + return NOTIFY_DONE; + } + + regs = args->regs; + + apic_write(APIC_LVTPC, APIC_DM_NMI); + /* + * Can't rely on the handled return value to say it was our NMI, two + * counters could trigger 'simultaneously' raising two back-to-back NMIs. + * + * If the first NMI handles both, the latter will be empty and daze + * the CPU. + */ + x86_pmu.handle_irq(regs); + + return NOTIFY_STOP; +} + +static __read_mostly struct notifier_block perf_counter_nmi_notifier = { + .notifier_call = perf_counter_nmi_handler, + .next = NULL, + .priority = 1 +}; + +static struct x86_pmu intel_pmu = { + .name = "Intel", + .handle_irq = intel_pmu_handle_irq, + .disable_all = intel_pmu_disable_all, + .enable_all = intel_pmu_enable_all, + .enable = intel_pmu_enable_counter, + .disable = intel_pmu_disable_counter, + .eventsel = MSR_ARCH_PERFMON_EVENTSEL0, + .perfctr = MSR_ARCH_PERFMON_PERFCTR0, + .event_map = intel_pmu_event_map, + .raw_event = intel_pmu_raw_event, + .max_events = ARRAY_SIZE(intel_perfmon_event_map), + /* + * Intel PMCs cannot be accessed sanely above 32 bit width, + * so we install an artificial 1<<31 period regardless of + * the generic counter period: + */ + .max_period = (1ULL << 31) - 1, +}; + +static struct x86_pmu amd_pmu = { + .name = "AMD", + .handle_irq = amd_pmu_handle_irq, + .disable_all = amd_pmu_disable_all, + .enable_all = amd_pmu_enable_all, + .enable = amd_pmu_enable_counter, + .disable = amd_pmu_disable_counter, + .eventsel = MSR_K7_EVNTSEL0, + .perfctr = MSR_K7_PERFCTR0, + .event_map = amd_pmu_event_map, + .raw_event = amd_pmu_raw_event, + .max_events = ARRAY_SIZE(amd_perfmon_event_map), + .num_counters = 4, + .counter_bits = 48, + .counter_mask = (1ULL << 48) - 1, + /* use highest bit to detect overflow */ + .max_period = (1ULL << 47) - 1, +}; + +static int intel_pmu_init(void) +{ + union cpuid10_edx edx; + union cpuid10_eax eax; + unsigned int unused; + unsigned int ebx; + int version; + + if (!cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) + return -ENODEV; + + /* + * Check whether the Architectural PerfMon supports + * Branch Misses Retired Event or not. + */ + cpuid(10, &eax.full, &ebx, &unused, &edx.full); + if (eax.split.mask_length <= ARCH_PERFMON_BRANCH_MISSES_RETIRED) + return -ENODEV; + + version = eax.split.version_id; + if (version < 2) + return -ENODEV; + + x86_pmu = intel_pmu; + x86_pmu.version = version; + x86_pmu.num_counters = eax.split.num_counters; + x86_pmu.counter_bits = eax.split.bit_width; + x86_pmu.counter_mask = (1ULL << eax.split.bit_width) - 1; + + /* + * Quirk: v2 perfmon does not report fixed-purpose counters, so + * assume at least 3 counters: + */ + x86_pmu.num_counters_fixed = max((int)edx.split.num_counters_fixed, 3); + + rdmsrl(MSR_CORE_PERF_GLOBAL_CTRL, x86_pmu.intel_ctrl); + + /* + * Install the hw-cache-events table: + */ + switch (boot_cpu_data.x86_model) { + case 15: /* original 65 nm celeron/pentium/core2/xeon, "Merom"/"Conroe" */ + case 22: /* single-core 65 nm celeron/core2solo "Merom-L"/"Conroe-L" */ + case 23: /* current 45 nm celeron/core2/xeon "Penryn"/"Wolfdale" */ + case 29: /* six-core 45 nm xeon "Dunnington" */ + memcpy(hw_cache_event_ids, core2_hw_cache_event_ids, + sizeof(hw_cache_event_ids)); + + pr_cont("Core2 events, "); + break; + default: + case 26: + memcpy(hw_cache_event_ids, nehalem_hw_cache_event_ids, + sizeof(hw_cache_event_ids)); + + pr_cont("Nehalem/Corei7 events, "); + break; + case 28: + memcpy(hw_cache_event_ids, atom_hw_cache_event_ids, + sizeof(hw_cache_event_ids)); + + pr_cont("Atom events, "); + break; + } + return 0; +} + +static int amd_pmu_init(void) +{ + /* Performance-monitoring supported from K7 and later: */ + if (boot_cpu_data.x86 < 6) + return -ENODEV; + + x86_pmu = amd_pmu; + + /* Events are common for all AMDs */ + memcpy(hw_cache_event_ids, amd_hw_cache_event_ids, + sizeof(hw_cache_event_ids)); + + return 0; +} + +void __init init_hw_perf_counters(void) +{ + int err; + + pr_info("Performance Counters: "); + + switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_INTEL: + err = intel_pmu_init(); + break; + case X86_VENDOR_AMD: + err = amd_pmu_init(); + break; + default: + return; + } + if (err != 0) { + pr_cont("no PMU driver, software counters only.\n"); + return; + } + + pr_cont("%s PMU driver.\n", x86_pmu.name); + + if (x86_pmu.num_counters > X86_PMC_MAX_GENERIC) { + x86_pmu.num_counters = X86_PMC_MAX_GENERIC; + WARN(1, KERN_ERR "hw perf counters %d > max(%d), clipping!", + x86_pmu.num_counters, X86_PMC_MAX_GENERIC); + } + perf_counter_mask = (1 << x86_pmu.num_counters) - 1; + perf_max_counters = x86_pmu.num_counters; + + if (x86_pmu.num_counters_fixed > X86_PMC_MAX_FIXED) { + x86_pmu.num_counters_fixed = X86_PMC_MAX_FIXED; + WARN(1, KERN_ERR "hw perf counters fixed %d > max(%d), clipping!", + x86_pmu.num_counters_fixed, X86_PMC_MAX_FIXED); + } + + perf_counter_mask |= + ((1LL << x86_pmu.num_counters_fixed)-1) << X86_PMC_IDX_FIXED; + + perf_counters_lapic_init(); + register_die_notifier(&perf_counter_nmi_notifier); + + pr_info("... version: %d\n", x86_pmu.version); + pr_info("... bit width: %d\n", x86_pmu.counter_bits); + pr_info("... generic counters: %d\n", x86_pmu.num_counters); + pr_info("... value mask: %016Lx\n", x86_pmu.counter_mask); + pr_info("... max period: %016Lx\n", x86_pmu.max_period); + pr_info("... fixed-purpose counters: %d\n", x86_pmu.num_counters_fixed); + pr_info("... counter mask: %016Lx\n", perf_counter_mask); +} + +static inline void x86_pmu_read(struct perf_counter *counter) +{ + x86_perf_counter_update(counter, &counter->hw, counter->hw.idx); +} + +static const struct pmu pmu = { + .enable = x86_pmu_enable, + .disable = x86_pmu_disable, + .read = x86_pmu_read, + .unthrottle = x86_pmu_unthrottle, +}; + +const struct pmu *hw_perf_counter_init(struct perf_counter *counter) +{ + int err; + + err = __hw_perf_counter_init(counter); + if (err) + return ERR_PTR(err); + + return &pmu; +} + +/* + * callchain support + */ + +static inline +void callchain_store(struct perf_callchain_entry *entry, u64 ip) +{ + if (entry->nr < PERF_MAX_STACK_DEPTH) + entry->ip[entry->nr++] = ip; +} + +static DEFINE_PER_CPU(struct perf_callchain_entry, irq_entry); +static DEFINE_PER_CPU(struct perf_callchain_entry, nmi_entry); + + +static void +backtrace_warning_symbol(void *data, char *msg, unsigned long symbol) +{ + /* Ignore warnings */ +} + +static void backtrace_warning(void *data, char *msg) +{ + /* Ignore warnings */ +} + +static int backtrace_stack(void *data, char *name) +{ + /* Process all stacks: */ + return 0; +} + +static void backtrace_address(void *data, unsigned long addr, int reliable) +{ + struct perf_callchain_entry *entry = data; + + if (reliable) + callchain_store(entry, addr); +} + +static const struct stacktrace_ops backtrace_ops = { + .warning = backtrace_warning, + .warning_symbol = backtrace_warning_symbol, + .stack = backtrace_stack, + .address = backtrace_address, +}; + +#include "../dumpstack.h" + +static void +perf_callchain_kernel(struct pt_regs *regs, struct perf_callchain_entry *entry) +{ + callchain_store(entry, PERF_CONTEXT_KERNEL); + callchain_store(entry, regs->ip); + + dump_trace(NULL, regs, NULL, 0, &backtrace_ops, entry); +} + +/* + * best effort, GUP based copy_from_user() that assumes IRQ or NMI context + */ +static unsigned long +copy_from_user_nmi(void *to, const void __user *from, unsigned long n) +{ + unsigned long offset, addr = (unsigned long)from; + int type = in_nmi() ? KM_NMI : KM_IRQ0; + unsigned long size, len = 0; + struct page *page; + void *map; + int ret; + + do { + ret = __get_user_pages_fast(addr, 1, 0, &page); + if (!ret) + break; + + offset = addr & (PAGE_SIZE - 1); + size = min(PAGE_SIZE - offset, n - len); + + map = kmap_atomic(page, type); + memcpy(to, map+offset, size); + kunmap_atomic(map, type); + put_page(page); + + len += size; + to += size; + addr += size; + + } while (len < n); + + return len; +} + +static int copy_stack_frame(const void __user *fp, struct stack_frame *frame) +{ + unsigned long bytes; + + bytes = copy_from_user_nmi(frame, fp, sizeof(*frame)); + + return bytes == sizeof(*frame); +} + +static void +perf_callchain_user(struct pt_regs *regs, struct perf_callchain_entry *entry) +{ + struct stack_frame frame; + const void __user *fp; + + if (!user_mode(regs)) + regs = task_pt_regs(current); + + fp = (void __user *)regs->bp; + + callchain_store(entry, PERF_CONTEXT_USER); + callchain_store(entry, regs->ip); + + while (entry->nr < PERF_MAX_STACK_DEPTH) { + frame.next_frame = NULL; + frame.return_address = 0; + + if (!copy_stack_frame(fp, &frame)) + break; + + if ((unsigned long)fp < regs->sp) + break; + + callchain_store(entry, frame.return_address); + fp = frame.next_frame; + } +} + +static void +perf_do_callchain(struct pt_regs *regs, struct perf_callchain_entry *entry) +{ + int is_user; + + if (!regs) + return; + + is_user = user_mode(regs); + + if (!current || current->pid == 0) + return; + + if (is_user && current->state != TASK_RUNNING) + return; + + if (!is_user) + perf_callchain_kernel(regs, entry); + + if (current->mm) + perf_callchain_user(regs, entry); +} + +struct perf_callchain_entry *perf_callchain(struct pt_regs *regs) +{ + struct perf_callchain_entry *entry; + + if (in_nmi()) + entry = &__get_cpu_var(nmi_entry); + else + entry = &__get_cpu_var(irq_entry); + + entry->nr = 0; + + perf_do_callchain(regs, entry); + + return entry; +} diff --git a/arch/x86/kernel/cpu/perfctr-watchdog.c b/arch/x86/kernel/cpu/perfctr-watchdog.c index f6c70a164e32..5c481f6205bf 100644 --- a/arch/x86/kernel/cpu/perfctr-watchdog.c +++ b/arch/x86/kernel/cpu/perfctr-watchdog.c @@ -19,8 +19,8 @@ #include #include -#include -#include +#include +#include struct nmi_watchdog_ctlblk { unsigned int cccr_msr; @@ -716,11 +716,15 @@ static void probe_nmi_watchdog(void) wd_ops = &k7_wd_ops; break; case X86_VENDOR_INTEL: - /* - * Work around Core Duo (Yonah) errata AE49 where perfctr1 - * doesn't have a working enable bit. + /* Work around where perfctr1 doesn't have a working enable + * bit as described in the following errata: + * AE49 Core Duo and Intel Core Solo 65 nm + * AN49 Intel Pentium Dual-Core + * AF49 Dual-Core Intel Xeon Processor LV */ - if (boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model == 14) { + if ((boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model == 14) || + ((boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model == 15 && + boot_cpu_data.x86_mask == 4))) { intel_arch_wd_ops.perfctr = MSR_ARCH_PERFMON_PERFCTR0; intel_arch_wd_ops.evntsel = MSR_ARCH_PERFMON_EVENTSEL0; } diff --git a/arch/x86/kernel/cpuid.c b/arch/x86/kernel/cpuid.c index 2ac1f0c2beb3..b07af8861244 100644 --- a/arch/x86/kernel/cpuid.c +++ b/arch/x86/kernel/cpuid.c @@ -182,6 +182,11 @@ static struct notifier_block __refdata cpuid_class_cpu_notifier = .notifier_call = cpuid_class_cpu_callback, }; +static char *cpuid_nodename(struct device *dev) +{ + return kasprintf(GFP_KERNEL, "cpu/%u/cpuid", MINOR(dev->devt)); +} + static int __init cpuid_init(void) { int i, err = 0; @@ -198,6 +203,7 @@ static int __init cpuid_init(void) err = PTR_ERR(cpuid_class); goto out_chrdev; } + cpuid_class->nodename = cpuid_nodename; for_each_online_cpu(i) { err = cpuid_device_create(i); if (err != 0) diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c index ff958248e61d..5e409dc298a4 100644 --- a/arch/x86/kernel/crash.c +++ b/arch/x86/kernel/crash.c @@ -27,6 +27,7 @@ #include #include #include +#include #if defined(CONFIG_SMP) && defined(CONFIG_X86_LOCAL_APIC) @@ -103,5 +104,10 @@ void native_machine_crash_shutdown(struct pt_regs *regs) #ifdef CONFIG_HPET_TIMER hpet_disable(); #endif + +#ifdef CONFIG_X86_64 + pci_iommu_shutdown(); +#endif + crash_save_cpu(regs, safe_smp_processor_id()); } diff --git a/arch/x86/kernel/ds.c b/arch/x86/kernel/ds.c index 87b67e3a765a..48bfe1386038 100644 --- a/arch/x86/kernel/ds.c +++ b/arch/x86/kernel/ds.c @@ -19,45 +19,61 @@ * Markus Metzger , 2007-2009 */ +#include +#include +#include +#include +#include +#include +#include #include -#include -#include -#include -#include -#include -#include - +#include "ds_selftest.h" /* - * The configuration for a particular DS hardware implementation. + * The configuration for a particular DS hardware implementation: */ struct ds_configuration { - /* the name of the configuration */ - const char *name; - /* the size of one pointer-typed field in the DS structure and - in the BTS and PEBS buffers in bytes; - this covers the first 8 DS fields related to buffer management. */ - unsigned char sizeof_field; - /* the size of a BTS/PEBS record in bytes */ - unsigned char sizeof_rec[2]; - /* a series of bit-masks to control various features indexed - * by enum ds_feature */ - unsigned long ctl[dsf_ctl_max]; + /* The name of the configuration: */ + const char *name; + + /* The size of pointer-typed fields in DS, BTS, and PEBS: */ + unsigned char sizeof_ptr_field; + + /* The size of a BTS/PEBS record in bytes: */ + unsigned char sizeof_rec[2]; + + /* The number of pebs counter reset values in the DS structure. */ + unsigned char nr_counter_reset; + + /* Control bit-masks indexed by enum ds_feature: */ + unsigned long ctl[dsf_ctl_max]; }; -static DEFINE_PER_CPU(struct ds_configuration, ds_cfg_array); +static struct ds_configuration ds_cfg __read_mostly; -#define ds_cfg per_cpu(ds_cfg_array, smp_processor_id()) -#define MAX_SIZEOF_DS (12 * 8) /* maximal size of a DS configuration */ -#define MAX_SIZEOF_BTS (3 * 8) /* maximal size of a BTS record */ -#define DS_ALIGNMENT (1 << 3) /* BTS and PEBS buffer alignment */ +/* Maximal size of a DS configuration: */ +#define MAX_SIZEOF_DS 0x80 -#define BTS_CONTROL \ - (ds_cfg.ctl[dsf_bts] | ds_cfg.ctl[dsf_bts_kernel] | ds_cfg.ctl[dsf_bts_user] |\ - ds_cfg.ctl[dsf_bts_overflow]) +/* Maximal size of a BTS record: */ +#define MAX_SIZEOF_BTS (3 * 8) +/* BTS and PEBS buffer alignment: */ +#define DS_ALIGNMENT (1 << 3) + +/* Number of buffer pointers in DS: */ +#define NUM_DS_PTR_FIELDS 8 + +/* Size of a pebs reset value in DS: */ +#define PEBS_RESET_FIELD_SIZE 8 + +/* Mask of control bits in the DS MSR register: */ +#define BTS_CONTROL \ + ( ds_cfg.ctl[dsf_bts] | \ + ds_cfg.ctl[dsf_bts_kernel] | \ + ds_cfg.ctl[dsf_bts_user] | \ + ds_cfg.ctl[dsf_bts_overflow] ) /* * A BTS or PEBS tracer. @@ -66,29 +82,36 @@ static DEFINE_PER_CPU(struct ds_configuration, ds_cfg_array); * to identify tracers. */ struct ds_tracer { - /* the DS context (partially) owned by this tracer */ - struct ds_context *context; - /* the buffer provided on ds_request() and its size in bytes */ - void *buffer; - size_t size; + /* The DS context (partially) owned by this tracer. */ + struct ds_context *context; + /* The buffer provided on ds_request() and its size in bytes. */ + void *buffer; + size_t size; }; struct bts_tracer { - /* the common DS part */ - struct ds_tracer ds; - /* the trace including the DS configuration */ - struct bts_trace trace; - /* buffer overflow notification function */ - bts_ovfl_callback_t ovfl; + /* The common DS part: */ + struct ds_tracer ds; + + /* The trace including the DS configuration: */ + struct bts_trace trace; + + /* Buffer overflow notification function: */ + bts_ovfl_callback_t ovfl; + + /* Active flags affecting trace collection. */ + unsigned int flags; }; struct pebs_tracer { - /* the common DS part */ - struct ds_tracer ds; - /* the trace including the DS configuration */ - struct pebs_trace trace; - /* buffer overflow notification function */ - pebs_ovfl_callback_t ovfl; + /* The common DS part: */ + struct ds_tracer ds; + + /* The trace including the DS configuration: */ + struct pebs_trace trace; + + /* Buffer overflow notification function: */ + pebs_ovfl_callback_t ovfl; }; /* @@ -97,6 +120,7 @@ struct pebs_tracer { * * The DS configuration consists of the following fields; different * architetures vary in the size of those fields. + * * - double-word aligned base linear address of the BTS buffer * - write pointer into the BTS buffer * - end linear address of the BTS buffer (one byte beyond the end of @@ -135,21 +159,22 @@ enum ds_field { }; enum ds_qualifier { - ds_bts = 0, + ds_bts = 0, ds_pebs }; -static inline unsigned long ds_get(const unsigned char *base, - enum ds_qualifier qual, enum ds_field field) +static inline unsigned long +ds_get(const unsigned char *base, enum ds_qualifier qual, enum ds_field field) { - base += (ds_cfg.sizeof_field * (field + (4 * qual))); + base += (ds_cfg.sizeof_ptr_field * (field + (4 * qual))); return *(unsigned long *)base; } -static inline void ds_set(unsigned char *base, enum ds_qualifier qual, - enum ds_field field, unsigned long value) +static inline void +ds_set(unsigned char *base, enum ds_qualifier qual, enum ds_field field, + unsigned long value) { - base += (ds_cfg.sizeof_field * (field + (4 * qual))); + base += (ds_cfg.sizeof_ptr_field * (field + (4 * qual))); (*(unsigned long *)base) = value; } @@ -159,7 +184,6 @@ static inline void ds_set(unsigned char *base, enum ds_qualifier qual, */ static DEFINE_SPINLOCK(ds_lock); - /* * We either support (system-wide) per-cpu or per-thread allocation. * We distinguish the two based on the task_struct pointer, where a @@ -178,12 +202,28 @@ static DEFINE_SPINLOCK(ds_lock); */ static atomic_t tracers = ATOMIC_INIT(0); -static inline void get_tracer(struct task_struct *task) +static inline int get_tracer(struct task_struct *task) { - if (task) + int error; + + spin_lock_irq(&ds_lock); + + if (task) { + error = -EPERM; + if (atomic_read(&tracers) < 0) + goto out; atomic_inc(&tracers); - else + } else { + error = -EPERM; + if (atomic_read(&tracers) > 0) + goto out; atomic_dec(&tracers); + } + + error = 0; +out: + spin_unlock_irq(&ds_lock); + return error; } static inline void put_tracer(struct task_struct *task) @@ -194,14 +234,6 @@ static inline void put_tracer(struct task_struct *task) atomic_inc(&tracers); } -static inline int check_tracer(struct task_struct *task) -{ - return task ? - (atomic_read(&tracers) >= 0) : - (atomic_read(&tracers) <= 0); -} - - /* * The DS context is either attached to a thread or to a cpu: * - in the former case, the thread_struct contains a pointer to the @@ -213,61 +245,58 @@ static inline int check_tracer(struct task_struct *task) * deallocated when the last user puts the context. */ struct ds_context { - /* pointer to the DS configuration; goes into MSR_IA32_DS_AREA */ - unsigned char ds[MAX_SIZEOF_DS]; - /* the owner of the BTS and PEBS configuration, respectively */ - struct bts_tracer *bts_master; - struct pebs_tracer *pebs_master; - /* use count */ - unsigned long count; - /* a pointer to the context location inside the thread_struct - * or the per_cpu context array */ - struct ds_context **this; - /* a pointer to the task owning this context, or NULL, if the - * context is owned by a cpu */ - struct task_struct *task; + /* The DS configuration; goes into MSR_IA32_DS_AREA: */ + unsigned char ds[MAX_SIZEOF_DS]; + + /* The owner of the BTS and PEBS configuration, respectively: */ + struct bts_tracer *bts_master; + struct pebs_tracer *pebs_master; + + /* Use count: */ + unsigned long count; + + /* Pointer to the context pointer field: */ + struct ds_context **this; + + /* The traced task; NULL for cpu tracing: */ + struct task_struct *task; + + /* The traced cpu; only valid if task is NULL: */ + int cpu; }; -static DEFINE_PER_CPU(struct ds_context *, system_context_array); - -#define system_context per_cpu(system_context_array, smp_processor_id()) +static DEFINE_PER_CPU(struct ds_context *, cpu_context); -static inline struct ds_context *ds_get_context(struct task_struct *task) +static struct ds_context *ds_get_context(struct task_struct *task, int cpu) { struct ds_context **p_context = - (task ? &task->thread.ds_ctx : &system_context); + (task ? &task->thread.ds_ctx : &per_cpu(cpu_context, cpu)); struct ds_context *context = NULL; struct ds_context *new_context = NULL; - unsigned long irq; /* Chances are small that we already have a context. */ new_context = kzalloc(sizeof(*new_context), GFP_KERNEL); if (!new_context) return NULL; - spin_lock_irqsave(&ds_lock, irq); + spin_lock_irq(&ds_lock); context = *p_context; - if (!context) { + if (likely(!context)) { context = new_context; context->this = p_context; context->task = task; + context->cpu = cpu; context->count = 0; - if (task) - set_tsk_thread_flag(task, TIF_DS_AREA_MSR); - - if (!task || (task == current)) - wrmsrl(MSR_IA32_DS_AREA, (unsigned long)context->ds); - *p_context = context; } context->count++; - spin_unlock_irqrestore(&ds_lock, irq); + spin_unlock_irq(&ds_lock); if (context != new_context) kfree(new_context); @@ -275,8 +304,9 @@ static inline struct ds_context *ds_get_context(struct task_struct *task) return context; } -static inline void ds_put_context(struct ds_context *context) +static void ds_put_context(struct ds_context *context) { + struct task_struct *task; unsigned long irq; if (!context) @@ -291,17 +321,55 @@ static inline void ds_put_context(struct ds_context *context) *(context->this) = NULL; - if (context->task) - clear_tsk_thread_flag(context->task, TIF_DS_AREA_MSR); + task = context->task; - if (!context->task || (context->task == current)) - wrmsrl(MSR_IA32_DS_AREA, 0); + if (task) + clear_tsk_thread_flag(task, TIF_DS_AREA_MSR); + + /* + * We leave the (now dangling) pointer to the DS configuration in + * the DS_AREA msr. This is as good or as bad as replacing it with + * NULL - the hardware would crash if we enabled tracing. + * + * This saves us some problems with having to write an msr on a + * different cpu while preventing others from doing the same for the + * next context for that same cpu. + */ spin_unlock_irqrestore(&ds_lock, irq); + /* The context might still be in use for context switching. */ + if (task && (task != current)) + wait_task_context_switch(task); + kfree(context); } +static void ds_install_ds_area(struct ds_context *context) +{ + unsigned long ds; + + ds = (unsigned long)context->ds; + + /* + * There is a race between the bts master and the pebs master. + * + * The thread/cpu access is synchronized via get/put_cpu() for + * task tracing and via wrmsr_on_cpu for cpu tracing. + * + * If bts and pebs are collected for the same task or same cpu, + * the same confiuration is written twice. + */ + if (context->task) { + get_cpu(); + if (context->task == current) + wrmsrl(MSR_IA32_DS_AREA, ds); + set_tsk_thread_flag(context->task, TIF_DS_AREA_MSR); + put_cpu(); + } else + wrmsr_on_cpu(context->cpu, MSR_IA32_DS_AREA, + (u32)((u64)ds), (u32)((u64)ds >> 32)); +} /* * Call the tracer's callback on a buffer overflow. @@ -332,9 +400,9 @@ static void ds_overflow(struct ds_context *context, enum ds_qualifier qual) * The remainder of any partially written record is zeroed out. * * context: the DS context - * qual: the buffer type - * record: the data to write - * size: the size of the data + * qual: the buffer type + * record: the data to write + * size: the size of the data */ static int ds_write(struct ds_context *context, enum ds_qualifier qual, const void *record, size_t size) @@ -349,14 +417,14 @@ static int ds_write(struct ds_context *context, enum ds_qualifier qual, unsigned long write_size, adj_write_size; /* - * write as much as possible without producing an + * Write as much as possible without producing an * overflow interrupt. * - * interrupt_threshold must either be + * Interrupt_threshold must either be * - bigger than absolute_maximum or * - point to a record between buffer_base and absolute_maximum * - * index points to a valid record. + * Index points to a valid record. */ base = ds_get(context->ds, qual, ds_buffer_base); index = ds_get(context->ds, qual, ds_index); @@ -365,8 +433,10 @@ static int ds_write(struct ds_context *context, enum ds_qualifier qual, write_end = min(end, int_th); - /* if we are already beyond the interrupt threshold, - * we fill the entire buffer */ + /* + * If we are already beyond the interrupt threshold, + * we fill the entire buffer. + */ if (write_end <= index) write_end = end; @@ -383,7 +453,7 @@ static int ds_write(struct ds_context *context, enum ds_qualifier qual, adj_write_size = write_size / ds_cfg.sizeof_rec[qual]; adj_write_size *= ds_cfg.sizeof_rec[qual]; - /* zero out trailing bytes */ + /* Zero out trailing bytes. */ memset((char *)index + write_size, 0, adj_write_size - write_size); index += adj_write_size; @@ -410,7 +480,7 @@ static int ds_write(struct ds_context *context, enum ds_qualifier qual, * Later architectures use 64bit pointers throughout, whereas earlier * architectures use 32bit pointers in 32bit mode. * - * We compute the base address for the first 8 fields based on: + * We compute the base address for the fields based on: * - the field size stored in the DS configuration * - the relative field position * @@ -431,23 +501,23 @@ enum bts_field { bts_to, bts_flags, - bts_qual = bts_from, - bts_jiffies = bts_to, - bts_pid = bts_flags, + bts_qual = bts_from, + bts_clock = bts_to, + bts_pid = bts_flags, - bts_qual_mask = (bts_qual_max - 1), - bts_escape = ((unsigned long)-1 & ~bts_qual_mask) + bts_qual_mask = (bts_qual_max - 1), + bts_escape = ((unsigned long)-1 & ~bts_qual_mask) }; static inline unsigned long bts_get(const char *base, enum bts_field field) { - base += (ds_cfg.sizeof_field * field); + base += (ds_cfg.sizeof_ptr_field * field); return *(unsigned long *)base; } static inline void bts_set(char *base, enum bts_field field, unsigned long val) { - base += (ds_cfg.sizeof_field * field);; + base += (ds_cfg.sizeof_ptr_field * field);; (*(unsigned long *)base) = val; } @@ -463,8 +533,8 @@ static inline void bts_set(char *base, enum bts_field field, unsigned long val) * * return: bytes read/written on success; -Eerrno, otherwise */ -static int bts_read(struct bts_tracer *tracer, const void *at, - struct bts_struct *out) +static int +bts_read(struct bts_tracer *tracer, const void *at, struct bts_struct *out) { if (!tracer) return -EINVAL; @@ -478,8 +548,8 @@ static int bts_read(struct bts_tracer *tracer, const void *at, memset(out, 0, sizeof(*out)); if ((bts_get(at, bts_qual) & ~bts_qual_mask) == bts_escape) { out->qualifier = (bts_get(at, bts_qual) & bts_qual_mask); - out->variant.timestamp.jiffies = bts_get(at, bts_jiffies); - out->variant.timestamp.pid = bts_get(at, bts_pid); + out->variant.event.clock = bts_get(at, bts_clock); + out->variant.event.pid = bts_get(at, bts_pid); } else { out->qualifier = bts_branch; out->variant.lbr.from = bts_get(at, bts_from); @@ -516,8 +586,8 @@ static int bts_write(struct bts_tracer *tracer, const struct bts_struct *in) case bts_task_arrives: case bts_task_departs: bts_set(raw, bts_qual, (bts_escape | in->qualifier)); - bts_set(raw, bts_jiffies, in->variant.timestamp.jiffies); - bts_set(raw, bts_pid, in->variant.timestamp.pid); + bts_set(raw, bts_clock, in->variant.event.clock); + bts_set(raw, bts_pid, in->variant.event.pid); break; default: return -EINVAL; @@ -555,7 +625,8 @@ static void ds_init_ds_trace(struct ds_trace *trace, enum ds_qualifier qual, unsigned int flags) { unsigned long buffer, adj; - /* adjust the buffer address and size to meet alignment + /* + * Adjust the buffer address and size to meet alignment * constraints: * - buffer is double-word aligned * - size is multiple of record size @@ -577,9 +648,11 @@ static void ds_init_ds_trace(struct ds_trace *trace, enum ds_qualifier qual, trace->begin = (void *)buffer; trace->top = trace->begin; trace->end = (void *)(buffer + size); - /* The value for 'no threshold' is -1, which will set the + /* + * The value for 'no threshold' is -1, which will set the * threshold outside of the buffer, just like we want it. */ + ith *= ds_cfg.sizeof_rec[qual]; trace->ith = (void *)(buffer + size - ith); trace->flags = flags; @@ -588,18 +661,27 @@ static void ds_init_ds_trace(struct ds_trace *trace, enum ds_qualifier qual, static int ds_request(struct ds_tracer *tracer, struct ds_trace *trace, enum ds_qualifier qual, struct task_struct *task, - void *base, size_t size, size_t th, unsigned int flags) + int cpu, void *base, size_t size, size_t th) { struct ds_context *context; int error; + size_t req_size; + + error = -EOPNOTSUPP; + if (!ds_cfg.sizeof_rec[qual]) + goto out; error = -EINVAL; if (!base) goto out; - /* we require some space to do alignment adjustments below */ + req_size = ds_cfg.sizeof_rec[qual]; + /* We might need space for alignment adjustments. */ + if (!IS_ALIGNED((unsigned long)base, DS_ALIGNMENT)) + req_size += DS_ALIGNMENT; + error = -EINVAL; - if (size < (DS_ALIGNMENT + ds_cfg.sizeof_rec[qual])) + if (size < req_size) goto out; if (th != (size_t)-1) { @@ -614,182 +696,318 @@ static int ds_request(struct ds_tracer *tracer, struct ds_trace *trace, tracer->size = size; error = -ENOMEM; - context = ds_get_context(task); + context = ds_get_context(task, cpu); if (!context) goto out; tracer->context = context; - ds_init_ds_trace(trace, qual, base, size, th, flags); + /* + * Defer any tracer-specific initialization work for the context until + * context ownership has been clarified. + */ error = 0; out: return error; } -struct bts_tracer *ds_request_bts(struct task_struct *task, - void *base, size_t size, - bts_ovfl_callback_t ovfl, size_t th, - unsigned int flags) +static struct bts_tracer *ds_request_bts(struct task_struct *task, int cpu, + void *base, size_t size, + bts_ovfl_callback_t ovfl, size_t th, + unsigned int flags) { struct bts_tracer *tracer; - unsigned long irq; int error; - error = -EOPNOTSUPP; - if (!ds_cfg.ctl[dsf_bts]) - goto out; - - /* buffer overflow notification is not yet implemented */ + /* Buffer overflow notification is not yet implemented. */ error = -EOPNOTSUPP; if (ovfl) goto out; + error = get_tracer(task); + if (error < 0) + goto out; + error = -ENOMEM; tracer = kzalloc(sizeof(*tracer), GFP_KERNEL); if (!tracer) - goto out; + goto out_put_tracer; tracer->ovfl = ovfl; + /* Do some more error checking and acquire a tracing context. */ error = ds_request(&tracer->ds, &tracer->trace.ds, - ds_bts, task, base, size, th, flags); + ds_bts, task, cpu, base, size, th); if (error < 0) goto out_tracer; - - spin_lock_irqsave(&ds_lock, irq); - - error = -EPERM; - if (!check_tracer(task)) - goto out_unlock; - get_tracer(task); + /* Claim the bts part of the tracing context we acquired above. */ + spin_lock_irq(&ds_lock); error = -EPERM; if (tracer->ds.context->bts_master) - goto out_put_tracer; + goto out_unlock; tracer->ds.context->bts_master = tracer; - spin_unlock_irqrestore(&ds_lock, irq); + spin_unlock_irq(&ds_lock); + /* + * Now that we own the bts part of the context, let's complete the + * initialization for that part. + */ + ds_init_ds_trace(&tracer->trace.ds, ds_bts, base, size, th, flags); + ds_write_config(tracer->ds.context, &tracer->trace.ds, ds_bts); + ds_install_ds_area(tracer->ds.context); tracer->trace.read = bts_read; tracer->trace.write = bts_write; - ds_write_config(tracer->ds.context, &tracer->trace.ds, ds_bts); + /* Start tracing. */ ds_resume_bts(tracer); return tracer; - out_put_tracer: - put_tracer(task); out_unlock: - spin_unlock_irqrestore(&ds_lock, irq); + spin_unlock_irq(&ds_lock); ds_put_context(tracer->ds.context); out_tracer: kfree(tracer); + out_put_tracer: + put_tracer(task); out: return ERR_PTR(error); } -struct pebs_tracer *ds_request_pebs(struct task_struct *task, - void *base, size_t size, - pebs_ovfl_callback_t ovfl, size_t th, - unsigned int flags) +struct bts_tracer *ds_request_bts_task(struct task_struct *task, + void *base, size_t size, + bts_ovfl_callback_t ovfl, + size_t th, unsigned int flags) +{ + return ds_request_bts(task, 0, base, size, ovfl, th, flags); +} + +struct bts_tracer *ds_request_bts_cpu(int cpu, void *base, size_t size, + bts_ovfl_callback_t ovfl, + size_t th, unsigned int flags) +{ + return ds_request_bts(NULL, cpu, base, size, ovfl, th, flags); +} + +static struct pebs_tracer *ds_request_pebs(struct task_struct *task, int cpu, + void *base, size_t size, + pebs_ovfl_callback_t ovfl, size_t th, + unsigned int flags) { struct pebs_tracer *tracer; - unsigned long irq; int error; - /* buffer overflow notification is not yet implemented */ + /* Buffer overflow notification is not yet implemented. */ error = -EOPNOTSUPP; if (ovfl) goto out; + error = get_tracer(task); + if (error < 0) + goto out; + error = -ENOMEM; tracer = kzalloc(sizeof(*tracer), GFP_KERNEL); if (!tracer) - goto out; + goto out_put_tracer; tracer->ovfl = ovfl; + /* Do some more error checking and acquire a tracing context. */ error = ds_request(&tracer->ds, &tracer->trace.ds, - ds_pebs, task, base, size, th, flags); + ds_pebs, task, cpu, base, size, th); if (error < 0) goto out_tracer; - spin_lock_irqsave(&ds_lock, irq); - - error = -EPERM; - if (!check_tracer(task)) - goto out_unlock; - get_tracer(task); + /* Claim the pebs part of the tracing context we acquired above. */ + spin_lock_irq(&ds_lock); error = -EPERM; if (tracer->ds.context->pebs_master) - goto out_put_tracer; + goto out_unlock; tracer->ds.context->pebs_master = tracer; - spin_unlock_irqrestore(&ds_lock, irq); + spin_unlock_irq(&ds_lock); + /* + * Now that we own the pebs part of the context, let's complete the + * initialization for that part. + */ + ds_init_ds_trace(&tracer->trace.ds, ds_pebs, base, size, th, flags); ds_write_config(tracer->ds.context, &tracer->trace.ds, ds_pebs); + ds_install_ds_area(tracer->ds.context); + + /* Start tracing. */ ds_resume_pebs(tracer); return tracer; - out_put_tracer: - put_tracer(task); out_unlock: - spin_unlock_irqrestore(&ds_lock, irq); + spin_unlock_irq(&ds_lock); ds_put_context(tracer->ds.context); out_tracer: kfree(tracer); + out_put_tracer: + put_tracer(task); out: return ERR_PTR(error); } -void ds_release_bts(struct bts_tracer *tracer) +struct pebs_tracer *ds_request_pebs_task(struct task_struct *task, + void *base, size_t size, + pebs_ovfl_callback_t ovfl, + size_t th, unsigned int flags) { - if (!tracer) - return; + return ds_request_pebs(task, 0, base, size, ovfl, th, flags); +} - ds_suspend_bts(tracer); +struct pebs_tracer *ds_request_pebs_cpu(int cpu, void *base, size_t size, + pebs_ovfl_callback_t ovfl, + size_t th, unsigned int flags) +{ + return ds_request_pebs(NULL, cpu, base, size, ovfl, th, flags); +} + +static void ds_free_bts(struct bts_tracer *tracer) +{ + struct task_struct *task; + + task = tracer->ds.context->task; WARN_ON_ONCE(tracer->ds.context->bts_master != tracer); tracer->ds.context->bts_master = NULL; - put_tracer(tracer->ds.context->task); + /* Make sure tracing stopped and the tracer is not in use. */ + if (task && (task != current)) + wait_task_context_switch(task); + ds_put_context(tracer->ds.context); + put_tracer(task); kfree(tracer); } +void ds_release_bts(struct bts_tracer *tracer) +{ + might_sleep(); + + if (!tracer) + return; + + ds_suspend_bts(tracer); + ds_free_bts(tracer); +} + +int ds_release_bts_noirq(struct bts_tracer *tracer) +{ + struct task_struct *task; + unsigned long irq; + int error; + + if (!tracer) + return 0; + + task = tracer->ds.context->task; + + local_irq_save(irq); + + error = -EPERM; + if (!task && + (tracer->ds.context->cpu != smp_processor_id())) + goto out; + + error = -EPERM; + if (task && (task != current)) + goto out; + + ds_suspend_bts_noirq(tracer); + ds_free_bts(tracer); + + error = 0; + out: + local_irq_restore(irq); + return error; +} + +static void update_task_debugctlmsr(struct task_struct *task, + unsigned long debugctlmsr) +{ + task->thread.debugctlmsr = debugctlmsr; + + get_cpu(); + if (task == current) + update_debugctlmsr(debugctlmsr); + put_cpu(); +} + void ds_suspend_bts(struct bts_tracer *tracer) { struct task_struct *task; + unsigned long debugctlmsr; + int cpu; if (!tracer) return; + tracer->flags = 0; + task = tracer->ds.context->task; + cpu = tracer->ds.context->cpu; - if (!task || (task == current)) - update_debugctlmsr(get_debugctlmsr() & ~BTS_CONTROL); + WARN_ON(!task && irqs_disabled()); - if (task) { - task->thread.debugctlmsr &= ~BTS_CONTROL; + debugctlmsr = (task ? + task->thread.debugctlmsr : + get_debugctlmsr_on_cpu(cpu)); + debugctlmsr &= ~BTS_CONTROL; - if (!task->thread.debugctlmsr) - clear_tsk_thread_flag(task, TIF_DEBUGCTLMSR); - } + if (task) + update_task_debugctlmsr(task, debugctlmsr); + else + update_debugctlmsr_on_cpu(cpu, debugctlmsr); } -void ds_resume_bts(struct bts_tracer *tracer) +int ds_suspend_bts_noirq(struct bts_tracer *tracer) { struct task_struct *task; - unsigned long control; + unsigned long debugctlmsr, irq; + int cpu, error = 0; if (!tracer) - return; + return 0; + + tracer->flags = 0; task = tracer->ds.context->task; + cpu = tracer->ds.context->cpu; + + local_irq_save(irq); + + error = -EPERM; + if (!task && (cpu != smp_processor_id())) + goto out; + + debugctlmsr = (task ? + task->thread.debugctlmsr : + get_debugctlmsr()); + debugctlmsr &= ~BTS_CONTROL; + + if (task) + update_task_debugctlmsr(task, debugctlmsr); + else + update_debugctlmsr(debugctlmsr); + + error = 0; + out: + local_irq_restore(irq); + return error; +} + +static unsigned long ds_bts_control(struct bts_tracer *tracer) +{ + unsigned long control; control = ds_cfg.ctl[dsf_bts]; if (!(tracer->trace.ds.flags & BTS_KERNEL)) @@ -797,41 +1015,149 @@ void ds_resume_bts(struct bts_tracer *tracer) if (!(tracer->trace.ds.flags & BTS_USER)) control |= ds_cfg.ctl[dsf_bts_user]; - if (task) { - task->thread.debugctlmsr |= control; - set_tsk_thread_flag(task, TIF_DEBUGCTLMSR); - } - - if (!task || (task == current)) - update_debugctlmsr(get_debugctlmsr() | control); + return control; } -void ds_release_pebs(struct pebs_tracer *tracer) +void ds_resume_bts(struct bts_tracer *tracer) { + struct task_struct *task; + unsigned long debugctlmsr; + int cpu; + if (!tracer) return; - ds_suspend_pebs(tracer); + tracer->flags = tracer->trace.ds.flags; + + task = tracer->ds.context->task; + cpu = tracer->ds.context->cpu; + + WARN_ON(!task && irqs_disabled()); + + debugctlmsr = (task ? + task->thread.debugctlmsr : + get_debugctlmsr_on_cpu(cpu)); + debugctlmsr |= ds_bts_control(tracer); + + if (task) + update_task_debugctlmsr(task, debugctlmsr); + else + update_debugctlmsr_on_cpu(cpu, debugctlmsr); +} + +int ds_resume_bts_noirq(struct bts_tracer *tracer) +{ + struct task_struct *task; + unsigned long debugctlmsr, irq; + int cpu, error = 0; + + if (!tracer) + return 0; + + tracer->flags = tracer->trace.ds.flags; + + task = tracer->ds.context->task; + cpu = tracer->ds.context->cpu; + + local_irq_save(irq); + + error = -EPERM; + if (!task && (cpu != smp_processor_id())) + goto out; + + debugctlmsr = (task ? + task->thread.debugctlmsr : + get_debugctlmsr()); + debugctlmsr |= ds_bts_control(tracer); + + if (task) + update_task_debugctlmsr(task, debugctlmsr); + else + update_debugctlmsr(debugctlmsr); + + error = 0; + out: + local_irq_restore(irq); + return error; +} + +static void ds_free_pebs(struct pebs_tracer *tracer) +{ + struct task_struct *task; + + task = tracer->ds.context->task; WARN_ON_ONCE(tracer->ds.context->pebs_master != tracer); tracer->ds.context->pebs_master = NULL; - put_tracer(tracer->ds.context->task); ds_put_context(tracer->ds.context); + put_tracer(task); kfree(tracer); } +void ds_release_pebs(struct pebs_tracer *tracer) +{ + might_sleep(); + + if (!tracer) + return; + + ds_suspend_pebs(tracer); + ds_free_pebs(tracer); +} + +int ds_release_pebs_noirq(struct pebs_tracer *tracer) +{ + struct task_struct *task; + unsigned long irq; + int error; + + if (!tracer) + return 0; + + task = tracer->ds.context->task; + + local_irq_save(irq); + + error = -EPERM; + if (!task && + (tracer->ds.context->cpu != smp_processor_id())) + goto out; + + error = -EPERM; + if (task && (task != current)) + goto out; + + ds_suspend_pebs_noirq(tracer); + ds_free_pebs(tracer); + + error = 0; + out: + local_irq_restore(irq); + return error; +} + void ds_suspend_pebs(struct pebs_tracer *tracer) { } +int ds_suspend_pebs_noirq(struct pebs_tracer *tracer) +{ + return 0; +} + void ds_resume_pebs(struct pebs_tracer *tracer) { } +int ds_resume_pebs_noirq(struct pebs_tracer *tracer) +{ + return 0; +} + const struct bts_trace *ds_read_bts(struct bts_tracer *tracer) { if (!tracer) @@ -847,8 +1173,12 @@ const struct pebs_trace *ds_read_pebs(struct pebs_tracer *tracer) return NULL; ds_read_config(tracer->ds.context, &tracer->trace.ds, ds_pebs); - tracer->trace.reset_value = - *(u64 *)(tracer->ds.context->ds + (ds_cfg.sizeof_field * 8)); + + tracer->trace.counters = ds_cfg.nr_counter_reset; + memcpy(tracer->trace.counter_reset, + tracer->ds.context->ds + + (NUM_DS_PTR_FIELDS * ds_cfg.sizeof_ptr_field), + ds_cfg.nr_counter_reset * PEBS_RESET_FIELD_SIZE); return &tracer->trace; } @@ -873,18 +1203,24 @@ int ds_reset_pebs(struct pebs_tracer *tracer) tracer->trace.ds.top = tracer->trace.ds.begin; - ds_set(tracer->ds.context->ds, ds_bts, ds_index, + ds_set(tracer->ds.context->ds, ds_pebs, ds_index, (unsigned long)tracer->trace.ds.top); return 0; } -int ds_set_pebs_reset(struct pebs_tracer *tracer, u64 value) +int ds_set_pebs_reset(struct pebs_tracer *tracer, + unsigned int counter, u64 value) { if (!tracer) return -EINVAL; - *(u64 *)(tracer->ds.context->ds + (ds_cfg.sizeof_field * 8)) = value; + if (ds_cfg.nr_counter_reset < counter) + return -EINVAL; + + *(u64 *)(tracer->ds.context->ds + + (NUM_DS_PTR_FIELDS * ds_cfg.sizeof_ptr_field) + + (counter * PEBS_RESET_FIELD_SIZE)) = value; return 0; } @@ -894,73 +1230,117 @@ static const struct ds_configuration ds_cfg_netburst = { .ctl[dsf_bts] = (1 << 2) | (1 << 3), .ctl[dsf_bts_kernel] = (1 << 5), .ctl[dsf_bts_user] = (1 << 6), - - .sizeof_field = sizeof(long), - .sizeof_rec[ds_bts] = sizeof(long) * 3, -#ifdef __i386__ - .sizeof_rec[ds_pebs] = sizeof(long) * 10, -#else - .sizeof_rec[ds_pebs] = sizeof(long) * 18, -#endif + .nr_counter_reset = 1, }; static const struct ds_configuration ds_cfg_pentium_m = { .name = "Pentium M", .ctl[dsf_bts] = (1 << 6) | (1 << 7), - - .sizeof_field = sizeof(long), - .sizeof_rec[ds_bts] = sizeof(long) * 3, -#ifdef __i386__ - .sizeof_rec[ds_pebs] = sizeof(long) * 10, -#else - .sizeof_rec[ds_pebs] = sizeof(long) * 18, -#endif + .nr_counter_reset = 1, }; static const struct ds_configuration ds_cfg_core2_atom = { .name = "Core 2/Atom", .ctl[dsf_bts] = (1 << 6) | (1 << 7), .ctl[dsf_bts_kernel] = (1 << 9), .ctl[dsf_bts_user] = (1 << 10), - - .sizeof_field = 8, - .sizeof_rec[ds_bts] = 8 * 3, - .sizeof_rec[ds_pebs] = 8 * 18, + .nr_counter_reset = 1, +}; +static const struct ds_configuration ds_cfg_core_i7 = { + .name = "Core i7", + .ctl[dsf_bts] = (1 << 6) | (1 << 7), + .ctl[dsf_bts_kernel] = (1 << 9), + .ctl[dsf_bts_user] = (1 << 10), + .nr_counter_reset = 4, }; static void -ds_configure(const struct ds_configuration *cfg) +ds_configure(const struct ds_configuration *cfg, + struct cpuinfo_x86 *cpu) { + unsigned long nr_pebs_fields = 0; + + printk(KERN_INFO "[ds] using %s configuration\n", cfg->name); + +#ifdef __i386__ + nr_pebs_fields = 10; +#else + nr_pebs_fields = 18; +#endif + + /* + * Starting with version 2, architectural performance + * monitoring supports a format specifier. + */ + if ((cpuid_eax(0xa) & 0xff) > 1) { + unsigned long perf_capabilities, format; + + rdmsrl(MSR_IA32_PERF_CAPABILITIES, perf_capabilities); + + format = (perf_capabilities >> 8) & 0xf; + + switch (format) { + case 0: + nr_pebs_fields = 18; + break; + case 1: + nr_pebs_fields = 22; + break; + default: + printk(KERN_INFO + "[ds] unknown PEBS format: %lu\n", format); + nr_pebs_fields = 0; + break; + } + } + memset(&ds_cfg, 0, sizeof(ds_cfg)); ds_cfg = *cfg; - printk(KERN_INFO "[ds] using %s configuration\n", ds_cfg.name); + ds_cfg.sizeof_ptr_field = + (cpu_has(cpu, X86_FEATURE_DTES64) ? 8 : 4); - if (!cpu_has_bts) { - ds_cfg.ctl[dsf_bts] = 0; + ds_cfg.sizeof_rec[ds_bts] = ds_cfg.sizeof_ptr_field * 3; + ds_cfg.sizeof_rec[ds_pebs] = ds_cfg.sizeof_ptr_field * nr_pebs_fields; + + if (!cpu_has(cpu, X86_FEATURE_BTS)) { + ds_cfg.sizeof_rec[ds_bts] = 0; printk(KERN_INFO "[ds] bts not available\n"); } - if (!cpu_has_pebs) + if (!cpu_has(cpu, X86_FEATURE_PEBS)) { + ds_cfg.sizeof_rec[ds_pebs] = 0; printk(KERN_INFO "[ds] pebs not available\n"); + } - WARN_ON_ONCE(MAX_SIZEOF_DS < (12 * ds_cfg.sizeof_field)); + printk(KERN_INFO "[ds] sizes: address: %u bit, ", + 8 * ds_cfg.sizeof_ptr_field); + printk("bts/pebs record: %u/%u bytes\n", + ds_cfg.sizeof_rec[ds_bts], ds_cfg.sizeof_rec[ds_pebs]); + + WARN_ON_ONCE(MAX_PEBS_COUNTERS < ds_cfg.nr_counter_reset); } void __cpuinit ds_init_intel(struct cpuinfo_x86 *c) { + /* Only configure the first cpu. Others are identical. */ + if (ds_cfg.name) + return; + switch (c->x86) { case 0x6: switch (c->x86_model) { case 0x9: case 0xd: /* Pentium M */ - ds_configure(&ds_cfg_pentium_m); + ds_configure(&ds_cfg_pentium_m, c); break; case 0xf: case 0x17: /* Core2 */ case 0x1c: /* Atom */ - ds_configure(&ds_cfg_core2_atom); + ds_configure(&ds_cfg_core2_atom, c); + break; + case 0x1a: /* Core i7 */ + ds_configure(&ds_cfg_core_i7, c); break; - case 0x1a: /* i7 */ default: - /* sorry, don't know about them */ + /* Sorry, don't know about them. */ break; } break; @@ -969,64 +1349,89 @@ void __cpuinit ds_init_intel(struct cpuinfo_x86 *c) case 0x0: case 0x1: case 0x2: /* Netburst */ - ds_configure(&ds_cfg_netburst); + ds_configure(&ds_cfg_netburst, c); break; default: - /* sorry, don't know about them */ + /* Sorry, don't know about them. */ break; } break; default: - /* sorry, don't know about them */ + /* Sorry, don't know about them. */ break; } } +static inline void ds_take_timestamp(struct ds_context *context, + enum bts_qualifier qualifier, + struct task_struct *task) +{ + struct bts_tracer *tracer = context->bts_master; + struct bts_struct ts; + + /* Prevent compilers from reading the tracer pointer twice. */ + barrier(); + + if (!tracer || !(tracer->flags & BTS_TIMESTAMPS)) + return; + + memset(&ts, 0, sizeof(ts)); + ts.qualifier = qualifier; + ts.variant.event.clock = trace_clock_global(); + ts.variant.event.pid = task->pid; + + bts_write(tracer, &ts); +} + /* * Change the DS configuration from tracing prev to tracing next. */ void ds_switch_to(struct task_struct *prev, struct task_struct *next) { - struct ds_context *prev_ctx = prev->thread.ds_ctx; - struct ds_context *next_ctx = next->thread.ds_ctx; + struct ds_context *prev_ctx = prev->thread.ds_ctx; + struct ds_context *next_ctx = next->thread.ds_ctx; + unsigned long debugctlmsr = next->thread.debugctlmsr; + + /* Make sure all data is read before we start. */ + barrier(); if (prev_ctx) { update_debugctlmsr(0); - if (prev_ctx->bts_master && - (prev_ctx->bts_master->trace.ds.flags & BTS_TIMESTAMPS)) { - struct bts_struct ts = { - .qualifier = bts_task_departs, - .variant.timestamp.jiffies = jiffies_64, - .variant.timestamp.pid = prev->pid - }; - bts_write(prev_ctx->bts_master, &ts); - } + ds_take_timestamp(prev_ctx, bts_task_departs, prev); } if (next_ctx) { - if (next_ctx->bts_master && - (next_ctx->bts_master->trace.ds.flags & BTS_TIMESTAMPS)) { - struct bts_struct ts = { - .qualifier = bts_task_arrives, - .variant.timestamp.jiffies = jiffies_64, - .variant.timestamp.pid = next->pid - }; - bts_write(next_ctx->bts_master, &ts); - } + ds_take_timestamp(next_ctx, bts_task_arrives, next); wrmsrl(MSR_IA32_DS_AREA, (unsigned long)next_ctx->ds); } - update_debugctlmsr(next->thread.debugctlmsr); + update_debugctlmsr(debugctlmsr); } -void ds_copy_thread(struct task_struct *tsk, struct task_struct *father) +static __init int ds_selftest(void) { - clear_tsk_thread_flag(tsk, TIF_DS_AREA_MSR); - tsk->thread.ds_ctx = NULL; -} + if (ds_cfg.sizeof_rec[ds_bts]) { + int error; -void ds_exit_thread(struct task_struct *tsk) -{ + error = ds_selftest_bts(); + if (error) { + WARN(1, "[ds] selftest failed. disabling bts.\n"); + ds_cfg.sizeof_rec[ds_bts] = 0; + } + } + + if (ds_cfg.sizeof_rec[ds_pebs]) { + int error; + + error = ds_selftest_pebs(); + if (error) { + WARN(1, "[ds] selftest failed. disabling pebs.\n"); + ds_cfg.sizeof_rec[ds_pebs] = 0; + } + } + + return 0; } +device_initcall(ds_selftest); diff --git a/arch/x86/kernel/ds_selftest.c b/arch/x86/kernel/ds_selftest.c new file mode 100644 index 000000000000..6bc7c199ab99 --- /dev/null +++ b/arch/x86/kernel/ds_selftest.c @@ -0,0 +1,408 @@ +/* + * Debug Store support - selftest + * + * + * Copyright (C) 2009 Intel Corporation. + * Markus Metzger , 2009 + */ + +#include "ds_selftest.h" + +#include +#include +#include +#include + +#include + + +#define BUFFER_SIZE 521 /* Intentionally chose an odd size. */ +#define SMALL_BUFFER_SIZE 24 /* A single bts entry. */ + +struct ds_selftest_bts_conf { + struct bts_tracer *tracer; + int error; + int (*suspend)(struct bts_tracer *); + int (*resume)(struct bts_tracer *); +}; + +static int ds_selftest_bts_consistency(const struct bts_trace *trace) +{ + int error = 0; + + if (!trace) { + printk(KERN_CONT "failed to access trace..."); + /* Bail out. Other tests are pointless. */ + return -1; + } + + if (!trace->read) { + printk(KERN_CONT "bts read not available..."); + error = -1; + } + + /* Do some sanity checks on the trace configuration. */ + if (!trace->ds.n) { + printk(KERN_CONT "empty bts buffer..."); + error = -1; + } + if (!trace->ds.size) { + printk(KERN_CONT "bad bts trace setup..."); + error = -1; + } + if (trace->ds.end != + (char *)trace->ds.begin + (trace->ds.n * trace->ds.size)) { + printk(KERN_CONT "bad bts buffer setup..."); + error = -1; + } + /* + * We allow top in [begin; end], since its not clear when the + * overflow adjustment happens: after the increment or before the + * write. + */ + if ((trace->ds.top < trace->ds.begin) || + (trace->ds.end < trace->ds.top)) { + printk(KERN_CONT "bts top out of bounds..."); + error = -1; + } + + return error; +} + +static int ds_selftest_bts_read(struct bts_tracer *tracer, + const struct bts_trace *trace, + const void *from, const void *to) +{ + const unsigned char *at; + + /* + * Check a few things which do not belong to this test. + * They should be covered by other tests. + */ + if (!trace) + return -1; + + if (!trace->read) + return -1; + + if (to < from) + return -1; + + if (from < trace->ds.begin) + return -1; + + if (trace->ds.end < to) + return -1; + + if (!trace->ds.size) + return -1; + + /* Now to the test itself. */ + for (at = from; (void *)at < to; at += trace->ds.size) { + struct bts_struct bts; + unsigned long index; + int error; + + if (((void *)at - trace->ds.begin) % trace->ds.size) { + printk(KERN_CONT + "read from non-integer index..."); + return -1; + } + index = ((void *)at - trace->ds.begin) / trace->ds.size; + + memset(&bts, 0, sizeof(bts)); + error = trace->read(tracer, at, &bts); + if (error < 0) { + printk(KERN_CONT + "error reading bts trace at [%lu] (0x%p)...", + index, at); + return error; + } + + switch (bts.qualifier) { + case BTS_BRANCH: + break; + default: + printk(KERN_CONT + "unexpected bts entry %llu at [%lu] (0x%p)...", + bts.qualifier, index, at); + return -1; + } + } + + return 0; +} + +static void ds_selftest_bts_cpu(void *arg) +{ + struct ds_selftest_bts_conf *conf = arg; + const struct bts_trace *trace; + void *top; + + if (IS_ERR(conf->tracer)) { + conf->error = PTR_ERR(conf->tracer); + conf->tracer = NULL; + + printk(KERN_CONT + "initialization failed (err: %d)...", conf->error); + return; + } + + /* We should meanwhile have enough trace. */ + conf->error = conf->suspend(conf->tracer); + if (conf->error < 0) + return; + + /* Let's see if we can access the trace. */ + trace = ds_read_bts(conf->tracer); + + conf->error = ds_selftest_bts_consistency(trace); + if (conf->error < 0) + return; + + /* If everything went well, we should have a few trace entries. */ + if (trace->ds.top == trace->ds.begin) { + /* + * It is possible but highly unlikely that we got a + * buffer overflow and end up at exactly the same + * position we started from. + * Let's issue a warning, but continue. + */ + printk(KERN_CONT "no trace/overflow..."); + } + + /* Let's try to read the trace we collected. */ + conf->error = + ds_selftest_bts_read(conf->tracer, trace, + trace->ds.begin, trace->ds.top); + if (conf->error < 0) + return; + + /* + * Let's read the trace again. + * Since we suspended tracing, we should get the same result. + */ + top = trace->ds.top; + + trace = ds_read_bts(conf->tracer); + conf->error = ds_selftest_bts_consistency(trace); + if (conf->error < 0) + return; + + if (top != trace->ds.top) { + printk(KERN_CONT "suspend not working..."); + conf->error = -1; + return; + } + + /* Let's collect some more trace - see if resume is working. */ + conf->error = conf->resume(conf->tracer); + if (conf->error < 0) + return; + + conf->error = conf->suspend(conf->tracer); + if (conf->error < 0) + return; + + trace = ds_read_bts(conf->tracer); + + conf->error = ds_selftest_bts_consistency(trace); + if (conf->error < 0) + return; + + if (trace->ds.top == top) { + /* + * It is possible but highly unlikely that we got a + * buffer overflow and end up at exactly the same + * position we started from. + * Let's issue a warning and check the full trace. + */ + printk(KERN_CONT + "no resume progress/overflow..."); + + conf->error = + ds_selftest_bts_read(conf->tracer, trace, + trace->ds.begin, trace->ds.end); + } else if (trace->ds.top < top) { + /* + * We had a buffer overflow - the entire buffer should + * contain trace records. + */ + conf->error = + ds_selftest_bts_read(conf->tracer, trace, + trace->ds.begin, trace->ds.end); + } else { + /* + * It is quite likely that the buffer did not overflow. + * Let's just check the delta trace. + */ + conf->error = + ds_selftest_bts_read(conf->tracer, trace, top, + trace->ds.top); + } + if (conf->error < 0) + return; + + conf->error = 0; +} + +static int ds_suspend_bts_wrap(struct bts_tracer *tracer) +{ + ds_suspend_bts(tracer); + return 0; +} + +static int ds_resume_bts_wrap(struct bts_tracer *tracer) +{ + ds_resume_bts(tracer); + return 0; +} + +static void ds_release_bts_noirq_wrap(void *tracer) +{ + (void)ds_release_bts_noirq(tracer); +} + +static int ds_selftest_bts_bad_release_noirq(int cpu, + struct bts_tracer *tracer) +{ + int error = -EPERM; + + /* Try to release the tracer on the wrong cpu. */ + get_cpu(); + if (cpu != smp_processor_id()) { + error = ds_release_bts_noirq(tracer); + if (error != -EPERM) + printk(KERN_CONT "release on wrong cpu..."); + } + put_cpu(); + + return error ? 0 : -1; +} + +static int ds_selftest_bts_bad_request_cpu(int cpu, void *buffer) +{ + struct bts_tracer *tracer; + int error; + + /* Try to request cpu tracing while task tracing is active. */ + tracer = ds_request_bts_cpu(cpu, buffer, BUFFER_SIZE, NULL, + (size_t)-1, BTS_KERNEL); + error = PTR_ERR(tracer); + if (!IS_ERR(tracer)) { + ds_release_bts(tracer); + error = 0; + } + + if (error != -EPERM) + printk(KERN_CONT "cpu/task tracing overlap..."); + + return error ? 0 : -1; +} + +static int ds_selftest_bts_bad_request_task(void *buffer) +{ + struct bts_tracer *tracer; + int error; + + /* Try to request cpu tracing while task tracing is active. */ + tracer = ds_request_bts_task(current, buffer, BUFFER_SIZE, NULL, + (size_t)-1, BTS_KERNEL); + error = PTR_ERR(tracer); + if (!IS_ERR(tracer)) { + error = 0; + ds_release_bts(tracer); + } + + if (error != -EPERM) + printk(KERN_CONT "task/cpu tracing overlap..."); + + return error ? 0 : -1; +} + +int ds_selftest_bts(void) +{ + struct ds_selftest_bts_conf conf; + unsigned char buffer[BUFFER_SIZE], *small_buffer; + unsigned long irq; + int cpu; + + printk(KERN_INFO "[ds] bts selftest..."); + conf.error = 0; + + small_buffer = (unsigned char *)ALIGN((unsigned long)buffer, 8) + 8; + + get_online_cpus(); + for_each_online_cpu(cpu) { + conf.suspend = ds_suspend_bts_wrap; + conf.resume = ds_resume_bts_wrap; + conf.tracer = + ds_request_bts_cpu(cpu, buffer, BUFFER_SIZE, + NULL, (size_t)-1, BTS_KERNEL); + ds_selftest_bts_cpu(&conf); + if (conf.error >= 0) + conf.error = ds_selftest_bts_bad_request_task(buffer); + ds_release_bts(conf.tracer); + if (conf.error < 0) + goto out; + + conf.suspend = ds_suspend_bts_noirq; + conf.resume = ds_resume_bts_noirq; + conf.tracer = + ds_request_bts_cpu(cpu, buffer, BUFFER_SIZE, + NULL, (size_t)-1, BTS_KERNEL); + smp_call_function_single(cpu, ds_selftest_bts_cpu, &conf, 1); + if (conf.error >= 0) { + conf.error = + ds_selftest_bts_bad_release_noirq(cpu, + conf.tracer); + /* We must not release the tracer twice. */ + if (conf.error < 0) + conf.tracer = NULL; + } + if (conf.error >= 0) + conf.error = ds_selftest_bts_bad_request_task(buffer); + smp_call_function_single(cpu, ds_release_bts_noirq_wrap, + conf.tracer, 1); + if (conf.error < 0) + goto out; + } + + conf.suspend = ds_suspend_bts_wrap; + conf.resume = ds_resume_bts_wrap; + conf.tracer = + ds_request_bts_task(current, buffer, BUFFER_SIZE, + NULL, (size_t)-1, BTS_KERNEL); + ds_selftest_bts_cpu(&conf); + if (conf.error >= 0) + conf.error = ds_selftest_bts_bad_request_cpu(0, buffer); + ds_release_bts(conf.tracer); + if (conf.error < 0) + goto out; + + conf.suspend = ds_suspend_bts_noirq; + conf.resume = ds_resume_bts_noirq; + conf.tracer = + ds_request_bts_task(current, small_buffer, SMALL_BUFFER_SIZE, + NULL, (size_t)-1, BTS_KERNEL); + local_irq_save(irq); + ds_selftest_bts_cpu(&conf); + if (conf.error >= 0) + conf.error = ds_selftest_bts_bad_request_cpu(0, buffer); + ds_release_bts_noirq(conf.tracer); + local_irq_restore(irq); + if (conf.error < 0) + goto out; + + conf.error = 0; + out: + put_online_cpus(); + printk(KERN_CONT "%s.\n", (conf.error ? "failed" : "passed")); + + return conf.error; +} + +int ds_selftest_pebs(void) +{ + return 0; +} diff --git a/arch/x86/kernel/ds_selftest.h b/arch/x86/kernel/ds_selftest.h new file mode 100644 index 000000000000..2ba8745c6663 --- /dev/null +++ b/arch/x86/kernel/ds_selftest.h @@ -0,0 +1,15 @@ +/* + * Debug Store support - selftest + * + * + * Copyright (C) 2009 Intel Corporation. + * Markus Metzger , 2009 + */ + +#ifdef CONFIG_X86_DS_SELFTEST +extern int ds_selftest_bts(void); +extern int ds_selftest_pebs(void); +#else +static inline int ds_selftest_bts(void) { return 0; } +static inline int ds_selftest_pebs(void) { return 0; } +#endif diff --git a/arch/x86/kernel/dumpstack.h b/arch/x86/kernel/dumpstack.h index da87590b8698..81086c227ab7 100644 --- a/arch/x86/kernel/dumpstack.h +++ b/arch/x86/kernel/dumpstack.h @@ -29,7 +29,6 @@ show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, unsigned long *sp, unsigned long bp, char *log_lvl); extern unsigned int code_bytes; -extern int kstack_depth_to_print; /* The form of the top of the frame on the stack */ struct stack_frame { diff --git a/arch/x86/kernel/e820.c b/arch/x86/kernel/e820.c index 006281302925..7271fa33d791 100644 --- a/arch/x86/kernel/e820.c +++ b/arch/x86/kernel/e820.c @@ -617,7 +617,7 @@ __init int e820_search_gap(unsigned long *gapstart, unsigned long *gapsize, */ __init void e820_setup_gap(void) { - unsigned long gapstart, gapsize, round; + unsigned long gapstart, gapsize; int found; gapstart = 0x10000000; @@ -635,14 +635,9 @@ __init void e820_setup_gap(void) #endif /* - * See how much we want to round up: start off with - * rounding to the next 1MB area. + * e820_reserve_resources_late protect stolen RAM already */ - round = 0x100000; - while ((gapsize >> 4) > round) - round += round; - /* Fun with two's complement */ - pci_mem_start = (gapstart + round) & -round; + pci_mem_start = gapstart; printk(KERN_INFO "Allocating PCI resources starting at %lx (gap: %lx:%lx)\n", @@ -1371,6 +1366,23 @@ void __init e820_reserve_resources(void) } } +/* How much should we pad RAM ending depending on where it is? */ +static unsigned long ram_alignment(resource_size_t pos) +{ + unsigned long mb = pos >> 20; + + /* To 64kB in the first megabyte */ + if (!mb) + return 64*1024; + + /* To 1MB in the first 16MB */ + if (mb < 16) + return 1024*1024; + + /* To 32MB for anything above that */ + return 32*1024*1024; +} + void __init e820_reserve_resources_late(void) { int i; @@ -1382,6 +1394,24 @@ void __init e820_reserve_resources_late(void) insert_resource_expand_to_fit(&iomem_resource, res); res++; } + + /* + * Try to bump up RAM regions to reasonable boundaries to + * avoid stolen RAM: + */ + for (i = 0; i < e820.nr_map; i++) { + struct e820entry *entry = &e820_saved.map[i]; + resource_size_t start, end; + + if (entry->type != E820_RAM) + continue; + start = entry->addr + entry->size; + end = round_up(start, ram_alignment(start)); + if (start == end) + continue; + reserve_region_with_split(&iomem_resource, start, + end - 1, "RAM buffer"); + } } char *__init default_machine_specific_memory_setup(void) diff --git a/arch/x86/kernel/early-quirks.c b/arch/x86/kernel/early-quirks.c index 76b8cd953dee..ebdb85cf2686 100644 --- a/arch/x86/kernel/early-quirks.c +++ b/arch/x86/kernel/early-quirks.c @@ -96,6 +96,7 @@ static void __init nvidia_bugs(int num, int slot, int func) } +#if defined(CONFIG_ACPI) && defined(CONFIG_X86_IO_APIC) #if defined(CONFIG_ACPI) && defined(CONFIG_X86_IO_APIC) static u32 __init ati_ixp4x0_rev(int num, int slot, int func) { @@ -114,6 +115,7 @@ static u32 __init ati_ixp4x0_rev(int num, int slot, int func) d &= 0xff; return d; } +#endif static void __init ati_bugs(int num, int slot, int func) { diff --git a/arch/x86/kernel/efi.c b/arch/x86/kernel/efi.c index 1736acc4d7aa..96f7ac0bbf01 100644 --- a/arch/x86/kernel/efi.c +++ b/arch/x86/kernel/efi.c @@ -240,10 +240,35 @@ static void __init do_add_efi_memmap(void) unsigned long long size = md->num_pages << EFI_PAGE_SHIFT; int e820_type; - if (md->attribute & EFI_MEMORY_WB) - e820_type = E820_RAM; - else + switch (md->type) { + case EFI_LOADER_CODE: + case EFI_LOADER_DATA: + case EFI_BOOT_SERVICES_CODE: + case EFI_BOOT_SERVICES_DATA: + case EFI_CONVENTIONAL_MEMORY: + if (md->attribute & EFI_MEMORY_WB) + e820_type = E820_RAM; + else + e820_type = E820_RESERVED; + break; + case EFI_ACPI_RECLAIM_MEMORY: + e820_type = E820_ACPI; + break; + case EFI_ACPI_MEMORY_NVS: + e820_type = E820_NVS; + break; + case EFI_UNUSABLE_MEMORY: + e820_type = E820_UNUSABLE; + break; + default: + /* + * EFI_RESERVED_TYPE EFI_RUNTIME_SERVICES_CODE + * EFI_RUNTIME_SERVICES_DATA EFI_MEMORY_MAPPED_IO + * EFI_MEMORY_MAPPED_IO_PORT_SPACE EFI_PAL_CODE + */ e820_type = E820_RESERVED; + break; + } e820_add_region(start, size, e820_type); } sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map); diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S index c929add475c9..c097e7d607c6 100644 --- a/arch/x86/kernel/entry_32.S +++ b/arch/x86/kernel/entry_32.S @@ -48,7 +48,6 @@ #include #include #include -#include #include #include #include @@ -84,7 +83,7 @@ #define preempt_stop(clobbers) DISABLE_INTERRUPTS(clobbers); TRACE_IRQS_OFF #else #define preempt_stop(clobbers) -#define resume_kernel restore_nocheck +#define resume_kernel restore_all #endif .macro TRACE_IRQS_IRET @@ -372,7 +371,7 @@ END(ret_from_exception) ENTRY(resume_kernel) DISABLE_INTERRUPTS(CLBR_ANY) cmpl $0,TI_preempt_count(%ebp) # non-zero preempt_count ? - jnz restore_nocheck + jnz restore_all need_resched: movl TI_flags(%ebp), %ecx # need_resched set ? testb $_TIF_NEED_RESCHED, %cl @@ -540,6 +539,8 @@ syscall_exit: jne syscall_exit_work restore_all: + TRACE_IRQS_IRET +restore_all_notrace: movl PT_EFLAGS(%esp), %eax # mix EFLAGS, SS and CS # Warning: PT_OLDSS(%esp) contains the wrong/random values if we # are returning to the kernel. @@ -551,8 +552,6 @@ restore_all: CFI_REMEMBER_STATE je ldt_ss # returning to user-space with LDT SS restore_nocheck: - TRACE_IRQS_IRET -restore_nocheck_notrace: RESTORE_REGS 4 # skip orig_eax/error_code CFI_ADJUST_CFA_OFFSET -4 irq_return: @@ -588,22 +587,34 @@ ldt_ss: jne restore_nocheck #endif - /* If returning to userspace with 16bit stack, - * try to fix the higher word of ESP, as the CPU - * won't restore it. - * This is an "official" bug of all the x86-compatible - * CPUs, which we can try to work around to make - * dosemu and wine happy. */ - movl PT_OLDESP(%esp), %eax - movl %esp, %edx - call patch_espfix_desc +/* + * Setup and switch to ESPFIX stack + * + * We're returning to userspace with a 16 bit stack. The CPU will not + * restore the high word of ESP for us on executing iret... This is an + * "official" bug of all the x86-compatible CPUs, which we can work + * around to make dosemu and wine happy. We do this by preloading the + * high word of ESP with the high word of the userspace ESP while + * compensating for the offset by changing to the ESPFIX segment with + * a base address that matches for the difference. + */ + mov %esp, %edx /* load kernel esp */ + mov PT_OLDESP(%esp), %eax /* load userspace esp */ + mov %dx, %ax /* eax: new kernel esp */ + sub %eax, %edx /* offset (low word is 0) */ + PER_CPU(gdt_page, %ebx) + shr $16, %edx + mov %dl, GDT_ENTRY_ESPFIX_SS * 8 + 4(%ebx) /* bits 16..23 */ + mov %dh, GDT_ENTRY_ESPFIX_SS * 8 + 7(%ebx) /* bits 24..31 */ pushl $__ESPFIX_SS CFI_ADJUST_CFA_OFFSET 4 - pushl %eax + push %eax /* new kernel esp */ CFI_ADJUST_CFA_OFFSET 4 + /* Disable interrupts, but do not irqtrace this section: we + * will soon execute iret and the tracer was already set to + * the irqstate after the iret */ DISABLE_INTERRUPTS(CLBR_EAX) - TRACE_IRQS_OFF - lss (%esp), %esp + lss (%esp), %esp /* switch to espfix segment */ CFI_ADJUST_CFA_OFFSET -8 jmp restore_nocheck CFI_ENDPROC @@ -716,15 +727,24 @@ PTREGSCALL(vm86) PTREGSCALL(vm86old) .macro FIXUP_ESPFIX_STACK - /* since we are on a wrong stack, we cant make it a C code :( */ +/* + * Switch back for ESPFIX stack to the normal zerobased stack + * + * We can't call C functions using the ESPFIX stack. This code reads + * the high word of the segment base from the GDT and swiches to the + * normal stack and adjusts ESP with the matching offset. + */ + /* fixup the stack */ PER_CPU(gdt_page, %ebx) - GET_DESC_BASE(GDT_ENTRY_ESPFIX_SS, %ebx, %eax, %ax, %al, %ah) - addl %esp, %eax + mov GDT_ENTRY_ESPFIX_SS * 8 + 4(%ebx), %al /* bits 16..23 */ + mov GDT_ENTRY_ESPFIX_SS * 8 + 7(%ebx), %ah /* bits 24..31 */ + shl $16, %eax + addl %esp, %eax /* the adjusted stack pointer */ pushl $__KERNEL_DS CFI_ADJUST_CFA_OFFSET 4 pushl %eax CFI_ADJUST_CFA_OFFSET 4 - lss (%esp), %esp + lss (%esp), %esp /* switch to the normal stack segment */ CFI_ADJUST_CFA_OFFSET -8 .endm .macro UNWIND_ESPFIX_STACK @@ -1154,6 +1174,7 @@ ENTRY(ftrace_graph_caller) pushl %edx movl 0xc(%esp), %edx lea 0x4(%ebp), %eax + movl (%ebp), %ecx subl $MCOUNT_INSN_SIZE, %edx call prepare_ftrace_return popl %edx @@ -1168,6 +1189,7 @@ return_to_handler: pushl %eax pushl %ecx pushl %edx + movl %ebp, %eax call ftrace_return_to_handler movl %eax, 0xc(%esp) popl %edx @@ -1329,7 +1351,7 @@ nmi_stack_correct: xorl %edx,%edx # zero error code movl %esp,%eax # pt_regs pointer call do_nmi - jmp restore_nocheck_notrace + jmp restore_all_notrace CFI_ENDPROC nmi_stack_fixup: diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S index 38946c6e8433..c251be745107 100644 --- a/arch/x86/kernel/entry_64.S +++ b/arch/x86/kernel/entry_64.S @@ -135,6 +135,7 @@ ENTRY(ftrace_graph_caller) leaq 8(%rbp), %rdi movq 0x38(%rsp), %rsi + movq (%rbp), %rdx subq $MCOUNT_INSN_SIZE, %rsi call prepare_ftrace_return @@ -147,27 +148,15 @@ END(ftrace_graph_caller) GLOBAL(return_to_handler) subq $80, %rsp + /* Save the return values */ movq %rax, (%rsp) - movq %rcx, 8(%rsp) - movq %rdx, 16(%rsp) - movq %rsi, 24(%rsp) - movq %rdi, 32(%rsp) - movq %r8, 40(%rsp) - movq %r9, 48(%rsp) - movq %r10, 56(%rsp) - movq %r11, 64(%rsp) + movq %rdx, 8(%rsp) + movq %rbp, %rdi call ftrace_return_to_handler movq %rax, 72(%rsp) - movq 64(%rsp), %r11 - movq 56(%rsp), %r10 - movq 48(%rsp), %r9 - movq 40(%rsp), %r8 - movq 32(%rsp), %rdi - movq 24(%rsp), %rsi - movq 16(%rsp), %rdx - movq 8(%rsp), %rcx + movq 8(%rsp), %rdx movq (%rsp), %rax addq $72, %rsp retq @@ -976,6 +965,8 @@ END(\sym) #ifdef CONFIG_SMP apicinterrupt IRQ_MOVE_CLEANUP_VECTOR \ irq_move_cleanup_interrupt smp_irq_move_cleanup_interrupt +apicinterrupt REBOOT_VECTOR \ + reboot_interrupt smp_reboot_interrupt #endif #ifdef CONFIG_X86_UV @@ -1007,10 +998,15 @@ apicinterrupt INVALIDATE_TLB_VECTOR_START+7 \ #endif apicinterrupt THRESHOLD_APIC_VECTOR \ - threshold_interrupt mce_threshold_interrupt + threshold_interrupt smp_threshold_interrupt apicinterrupt THERMAL_APIC_VECTOR \ thermal_interrupt smp_thermal_interrupt +#ifdef CONFIG_X86_MCE +apicinterrupt MCE_SELF_VECTOR \ + mce_self_interrupt smp_mce_self_interrupt +#endif + #ifdef CONFIG_SMP apicinterrupt CALL_FUNCTION_SINGLE_VECTOR \ call_function_single_interrupt smp_call_function_single_interrupt @@ -1025,6 +1021,11 @@ apicinterrupt ERROR_APIC_VECTOR \ apicinterrupt SPURIOUS_APIC_VECTOR \ spurious_interrupt smp_spurious_interrupt +#ifdef CONFIG_PERF_COUNTERS +apicinterrupt LOCAL_PENDING_VECTOR \ + perf_pending_interrupt smp_perf_pending_interrupt +#endif + /* * Exception entry points. */ @@ -1379,10 +1380,15 @@ END(xen_failsafe_callback) paranoidzeroentry_ist debug do_debug DEBUG_STACK paranoidzeroentry_ist int3 do_int3 DEBUG_STACK paranoiderrorentry stack_segment do_stack_segment +#ifdef CONFIG_XEN +zeroentry xen_debug do_debug +zeroentry xen_int3 do_int3 +errorentry xen_stack_segment do_stack_segment +#endif errorentry general_protection do_general_protection errorentry page_fault do_page_fault #ifdef CONFIG_X86_MCE -paranoidzeroentry machine_check do_machine_check +paranoidzeroentry machine_check *machine_check_vector(%rip) #endif /* diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c index b79c5533c421..d94e1ea3b9fe 100644 --- a/arch/x86/kernel/ftrace.c +++ b/arch/x86/kernel/ftrace.c @@ -408,7 +408,8 @@ int ftrace_disable_ftrace_graph_caller(void) * Hook the return address and push it in the stack of return addrs * in current thread info. */ -void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr) +void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, + unsigned long frame_pointer) { unsigned long old; int faulted; @@ -453,7 +454,8 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr) return; } - if (ftrace_push_return_trace(old, self_addr, &trace.depth) == -EBUSY) { + if (ftrace_push_return_trace(old, self_addr, &trace.depth, + frame_pointer) == -EBUSY) { *parent = old; return; } diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S index 30683883e0cd..8663afb56535 100644 --- a/arch/x86/kernel/head_32.S +++ b/arch/x86/kernel/head_32.S @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -608,13 +607,6 @@ ignore_int: ENTRY(initial_code) .long i386_start_kernel -.section .text -/* - * Real beginning of normal "text" segment - */ -ENTRY(stext) -ENTRY(_stext) - /* * BSS section */ diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S index 54b29bb24e71..fa54f78e2a05 100644 --- a/arch/x86/kernel/head_64.S +++ b/arch/x86/kernel/head_64.S @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c index 81408b93f887..dedc2bddf7a5 100644 --- a/arch/x86/kernel/hpet.c +++ b/arch/x86/kernel/hpet.c @@ -510,7 +510,8 @@ static int hpet_setup_irq(struct hpet_dev *dev) { if (request_irq(dev->irq, hpet_interrupt_handler, - IRQF_DISABLED|IRQF_NOBALANCING, dev->name, dev)) + IRQF_TIMER | IRQF_DISABLED | IRQF_NOBALANCING, + dev->name, dev)) return -1; disable_irq(dev->irq); diff --git a/arch/x86/kernel/i8253.c b/arch/x86/kernel/i8253.c index c2e0bb0890d4..5cf36c053ac4 100644 --- a/arch/x86/kernel/i8253.c +++ b/arch/x86/kernel/i8253.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/x86/kernel/init_task.c b/arch/x86/kernel/init_task.c index df3bf269beab..270ff83efc11 100644 --- a/arch/x86/kernel/init_task.c +++ b/arch/x86/kernel/init_task.c @@ -12,7 +12,6 @@ static struct signal_struct init_signals = INIT_SIGNALS(init_signals); static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); -struct mm_struct init_mm = INIT_MM(init_mm); /* * Initial thread structure. diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c index c3fe010d74c8..b0cdde6932f5 100644 --- a/arch/x86/kernel/irq.c +++ b/arch/x86/kernel/irq.c @@ -12,6 +12,8 @@ #include #include #include +#include +#include atomic_t irq_err_count; @@ -24,9 +26,9 @@ void (*generic_interrupt_extension)(void) = NULL; */ void ack_bad_irq(unsigned int irq) { - printk(KERN_ERR "unexpected IRQ trap at vector %02x\n", irq); + if (printk_ratelimit()) + pr_err("unexpected IRQ trap at vector %02x\n", irq); -#ifdef CONFIG_X86_LOCAL_APIC /* * Currently unexpected vectors happen only on SMP and APIC. * We _must_ ack these because every local APIC has only N @@ -36,9 +38,7 @@ void ack_bad_irq(unsigned int irq) * completely. * But only ack when the APIC is enabled -AK */ - if (cpu_has_apic) - ack_APIC_irq(); -#endif + ack_APIC_irq(); } #define irq_stats(x) (&per_cpu(irq_stat, x)) @@ -63,6 +63,14 @@ static int show_other_interrupts(struct seq_file *p, int prec) for_each_online_cpu(j) seq_printf(p, "%10u ", irq_stats(j)->irq_spurious_count); seq_printf(p, " Spurious interrupts\n"); + seq_printf(p, "%*s: ", prec, "CNT"); + for_each_online_cpu(j) + seq_printf(p, "%10u ", irq_stats(j)->apic_perf_irqs); + seq_printf(p, " Performance counter interrupts\n"); + seq_printf(p, "%*s: ", prec, "PND"); + for_each_online_cpu(j) + seq_printf(p, "%10u ", irq_stats(j)->apic_pending_irqs); + seq_printf(p, " Performance pending work\n"); #endif if (generic_interrupt_extension) { seq_printf(p, "%*s: ", prec, "PLT"); @@ -89,12 +97,22 @@ static int show_other_interrupts(struct seq_file *p, int prec) for_each_online_cpu(j) seq_printf(p, "%10u ", irq_stats(j)->irq_thermal_count); seq_printf(p, " Thermal event interrupts\n"); -# ifdef CONFIG_X86_64 +# ifdef CONFIG_X86_MCE_THRESHOLD seq_printf(p, "%*s: ", prec, "THR"); for_each_online_cpu(j) seq_printf(p, "%10u ", irq_stats(j)->irq_threshold_count); seq_printf(p, " Threshold APIC interrupts\n"); # endif +#endif +#ifdef CONFIG_X86_NEW_MCE + seq_printf(p, "%*s: ", prec, "MCE"); + for_each_online_cpu(j) + seq_printf(p, "%10u ", per_cpu(mce_exception_count, j)); + seq_printf(p, " Machine check exceptions\n"); + seq_printf(p, "%*s: ", prec, "MCP"); + for_each_online_cpu(j) + seq_printf(p, "%10u ", per_cpu(mce_poll_count, j)); + seq_printf(p, " Machine check polls\n"); #endif seq_printf(p, "%*s: %10u\n", prec, "ERR", atomic_read(&irq_err_count)); #if defined(CONFIG_X86_IO_APIC) @@ -166,6 +184,8 @@ u64 arch_irq_stat_cpu(unsigned int cpu) #ifdef CONFIG_X86_LOCAL_APIC sum += irq_stats(cpu)->apic_timer_irqs; sum += irq_stats(cpu)->irq_spurious_count; + sum += irq_stats(cpu)->apic_perf_irqs; + sum += irq_stats(cpu)->apic_pending_irqs; #endif if (generic_interrupt_extension) sum += irq_stats(cpu)->generic_irqs; @@ -176,9 +196,13 @@ u64 arch_irq_stat_cpu(unsigned int cpu) #endif #ifdef CONFIG_X86_MCE sum += irq_stats(cpu)->irq_thermal_count; -# ifdef CONFIG_X86_64 +# ifdef CONFIG_X86_MCE_THRESHOLD sum += irq_stats(cpu)->irq_threshold_count; +# endif #endif +#ifdef CONFIG_X86_NEW_MCE + sum += per_cpu(mce_exception_count, cpu); + sum += per_cpu(mce_poll_count, cpu); #endif return sum; } @@ -213,14 +237,11 @@ unsigned int __irq_entry do_IRQ(struct pt_regs *regs) irq = __get_cpu_var(vector_irq)[vector]; if (!handle_irq(irq, regs)) { -#ifdef CONFIG_X86_64 - if (!disable_apic) - ack_APIC_irq(); -#endif + ack_APIC_irq(); if (printk_ratelimit()) - printk(KERN_EMERG "%s: %d.%d No irq handler for vector (irq %d)\n", - __func__, smp_processor_id(), vector, irq); + pr_emerg("%s: %d.%d No irq handler for vector (irq %d)\n", + __func__, smp_processor_id(), vector, irq); } irq_exit(); diff --git a/arch/x86/kernel/irqinit_32.c b/arch/x86/kernel/irqinit.c similarity index 67% rename from arch/x86/kernel/irqinit_32.c rename to arch/x86/kernel/irqinit.c index 368b0a8836f9..696f0e475c2d 100644 --- a/arch/x86/kernel/irqinit_32.c +++ b/arch/x86/kernel/irqinit.c @@ -1,20 +1,25 @@ +#include #include #include #include #include #include +#include #include #include +#include #include #include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -22,7 +27,23 @@ #include #include +/* + * ISA PIC or low IO-APIC triggered (INTA-cycle or APIC) interrupts: + * (these are usually mapped to vectors 0x30-0x3f) + */ +/* + * The IO-APIC gives us many more interrupt sources. Most of these + * are unused but an SMP system is supposed to have enough memory ... + * sometimes (mostly wrt. hw bugs) we get corrupted vectors all + * across the spectrum, so we really want to be prepared to get all + * of these. Plus, more powerful systems might have more than 64 + * IO-APIC registers. + * + * (these are usually mapped into the 0x30-0xff vector range) + */ + +#ifdef CONFIG_X86_32 /* * Note that on a 486, we don't want to do a SIGFPE on an irq13 * as the irq is unreliable, and exception 16 works correctly @@ -52,30 +73,7 @@ static struct irqaction fpu_irq = { .handler = math_error_irq, .name = "fpu", }; - -void __init init_ISA_irqs(void) -{ - int i; - -#ifdef CONFIG_X86_LOCAL_APIC - init_bsp_APIC(); #endif - init_8259A(0); - - /* - * 16 old-style INTA-cycle interrupts: - */ - for (i = 0; i < NR_IRQS_LEGACY; i++) { - struct irq_desc *desc = irq_to_desc(i); - - desc->status = IRQ_DISABLED; - desc->action = NULL; - desc->depth = 1; - - set_irq_chip_and_handler_name(i, &i8259A_chip, - handle_level_irq, "XT"); - } -} /* * IRQ2 is cascade interrupt to second interrupt controller @@ -118,29 +116,37 @@ int vector_used_by_percpu_irq(unsigned int vector) return 0; } -/* Overridden in paravirt.c */ -void init_IRQ(void) __attribute__((weak, alias("native_init_IRQ"))); - -void __init native_init_IRQ(void) +static void __init init_ISA_irqs(void) { int i; - /* Execute any quirks before the call gates are initialised: */ - x86_quirk_pre_intr_init(); +#if defined(CONFIG_X86_64) || defined(CONFIG_X86_LOCAL_APIC) + init_bsp_APIC(); +#endif + init_8259A(0); /* - * Cover the whole vector space, no vector can escape - * us. (some of these will be overridden and become - * 'special' SMP interrupts) + * 16 old-style INTA-cycle interrupts: */ - for (i = FIRST_EXTERNAL_VECTOR; i < NR_VECTORS; i++) { - /* SYSCALL_VECTOR was reserved in trap_init. */ - if (i != SYSCALL_VECTOR) - set_intr_gate(i, interrupt[i-FIRST_EXTERNAL_VECTOR]); + for (i = 0; i < NR_IRQS_LEGACY; i++) { + struct irq_desc *desc = irq_to_desc(i); + + desc->status = IRQ_DISABLED; + desc->action = NULL; + desc->depth = 1; + + set_irq_chip_and_handler_name(i, &i8259A_chip, + handle_level_irq, "XT"); } +} +/* Overridden in paravirt.c */ +void init_IRQ(void) __attribute__((weak, alias("native_init_IRQ"))); -#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_SMP) +static void __init smp_intr_init(void) +{ +#ifdef CONFIG_SMP +#if defined(CONFIG_X86_64) || defined(CONFIG_X86_LOCAL_APIC) /* * The reschedule interrupt is a CPU-to-CPU reschedule-helper * IPI, driven by wakeup. @@ -160,16 +166,35 @@ void __init native_init_IRQ(void) /* IPI for generic function call */ alloc_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt); - /* IPI for single call function */ + /* IPI for generic single function call */ alloc_intr_gate(CALL_FUNCTION_SINGLE_VECTOR, - call_function_single_interrupt); + call_function_single_interrupt); /* Low priority IPI to cleanup after moving an irq */ set_intr_gate(IRQ_MOVE_CLEANUP_VECTOR, irq_move_cleanup_interrupt); set_bit(IRQ_MOVE_CLEANUP_VECTOR, used_vectors); + + /* IPI used for rebooting/stopping */ + alloc_intr_gate(REBOOT_VECTOR, reboot_interrupt); +#endif +#endif /* CONFIG_SMP */ +} + +static void __init apic_intr_init(void) +{ + smp_intr_init(); + +#ifdef CONFIG_X86_THERMAL_VECTOR + alloc_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt); +#endif +#ifdef CONFIG_X86_THRESHOLD + alloc_intr_gate(THRESHOLD_APIC_VECTOR, threshold_interrupt); +#endif +#if defined(CONFIG_X86_NEW_MCE) && defined(CONFIG_X86_LOCAL_APIC) + alloc_intr_gate(MCE_SELF_VECTOR, mce_self_interrupt); #endif -#ifdef CONFIG_X86_LOCAL_APIC +#if defined(CONFIG_X86_64) || defined(CONFIG_X86_LOCAL_APIC) /* self generated IPI for local APIC timer */ alloc_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt); @@ -179,16 +204,59 @@ void __init native_init_IRQ(void) /* IPI vectors for APIC spurious and error interrupts */ alloc_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt); alloc_intr_gate(ERROR_APIC_VECTOR, error_interrupt); -#endif -#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86_MCE_P4THERMAL) - /* thermal monitor LVT interrupt */ - alloc_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt); + /* Performance monitoring interrupts: */ +# ifdef CONFIG_PERF_COUNTERS + alloc_intr_gate(LOCAL_PENDING_VECTOR, perf_pending_interrupt); +# endif + #endif +} + +/** + * x86_quirk_pre_intr_init - initialisation prior to setting up interrupt vectors + * + * Description: + * Perform any necessary interrupt initialisation prior to setting up + * the "ordinary" interrupt call gates. For legacy reasons, the ISA + * interrupts should be initialised here if the machine emulates a PC + * in any way. + **/ +static void __init x86_quirk_pre_intr_init(void) +{ +#ifdef CONFIG_X86_32 + if (x86_quirks->arch_pre_intr_init) { + if (x86_quirks->arch_pre_intr_init()) + return; + } +#endif + init_ISA_irqs(); +} + +void __init native_init_IRQ(void) +{ + int i; + + /* Execute any quirks before the call gates are initialised: */ + x86_quirk_pre_intr_init(); + + apic_intr_init(); + + /* + * Cover the whole vector space, no vector can escape + * us. (some of these will be overridden and become + * 'special' SMP interrupts) + */ + for (i = FIRST_EXTERNAL_VECTOR; i < NR_VECTORS; i++) { + /* IA32_SYSCALL_VECTOR could be used in trap_init already. */ + if (!test_bit(i, used_vectors)) + set_intr_gate(i, interrupt[i-FIRST_EXTERNAL_VECTOR]); + } if (!acpi_ioapic) setup_irq(2, &irq2); +#ifdef CONFIG_X86_32 /* * Call quirks after call gates are initialised (usually add in * the architecture specific gates): @@ -203,4 +271,5 @@ void __init native_init_IRQ(void) setup_irq(FPU_IRQ, &fpu_irq); irq_ctx_init(smp_processor_id()); +#endif } diff --git a/arch/x86/kernel/irqinit_64.c b/arch/x86/kernel/irqinit_64.c deleted file mode 100644 index 8cd10537fd46..000000000000 --- a/arch/x86/kernel/irqinit_64.c +++ /dev/null @@ -1,177 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -/* - * ISA PIC or low IO-APIC triggered (INTA-cycle or APIC) interrupts: - * (these are usually mapped to vectors 0x30-0x3f) - */ - -/* - * The IO-APIC gives us many more interrupt sources. Most of these - * are unused but an SMP system is supposed to have enough memory ... - * sometimes (mostly wrt. hw bugs) we get corrupted vectors all - * across the spectrum, so we really want to be prepared to get all - * of these. Plus, more powerful systems might have more than 64 - * IO-APIC registers. - * - * (these are usually mapped into the 0x30-0xff vector range) - */ - -/* - * IRQ2 is cascade interrupt to second interrupt controller - */ - -static struct irqaction irq2 = { - .handler = no_action, - .name = "cascade", -}; -DEFINE_PER_CPU(vector_irq_t, vector_irq) = { - [0 ... IRQ0_VECTOR - 1] = -1, - [IRQ0_VECTOR] = 0, - [IRQ1_VECTOR] = 1, - [IRQ2_VECTOR] = 2, - [IRQ3_VECTOR] = 3, - [IRQ4_VECTOR] = 4, - [IRQ5_VECTOR] = 5, - [IRQ6_VECTOR] = 6, - [IRQ7_VECTOR] = 7, - [IRQ8_VECTOR] = 8, - [IRQ9_VECTOR] = 9, - [IRQ10_VECTOR] = 10, - [IRQ11_VECTOR] = 11, - [IRQ12_VECTOR] = 12, - [IRQ13_VECTOR] = 13, - [IRQ14_VECTOR] = 14, - [IRQ15_VECTOR] = 15, - [IRQ15_VECTOR + 1 ... NR_VECTORS - 1] = -1 -}; - -int vector_used_by_percpu_irq(unsigned int vector) -{ - int cpu; - - for_each_online_cpu(cpu) { - if (per_cpu(vector_irq, cpu)[vector] != -1) - return 1; - } - - return 0; -} - -static void __init init_ISA_irqs(void) -{ - int i; - - init_bsp_APIC(); - init_8259A(0); - - for (i = 0; i < NR_IRQS_LEGACY; i++) { - struct irq_desc *desc = irq_to_desc(i); - - desc->status = IRQ_DISABLED; - desc->action = NULL; - desc->depth = 1; - - /* - * 16 old-style INTA-cycle interrupts: - */ - set_irq_chip_and_handler_name(i, &i8259A_chip, - handle_level_irq, "XT"); - } -} - -void init_IRQ(void) __attribute__((weak, alias("native_init_IRQ"))); - -static void __init smp_intr_init(void) -{ -#ifdef CONFIG_SMP - /* - * The reschedule interrupt is a CPU-to-CPU reschedule-helper - * IPI, driven by wakeup. - */ - alloc_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt); - - /* IPIs for invalidation */ - alloc_intr_gate(INVALIDATE_TLB_VECTOR_START+0, invalidate_interrupt0); - alloc_intr_gate(INVALIDATE_TLB_VECTOR_START+1, invalidate_interrupt1); - alloc_intr_gate(INVALIDATE_TLB_VECTOR_START+2, invalidate_interrupt2); - alloc_intr_gate(INVALIDATE_TLB_VECTOR_START+3, invalidate_interrupt3); - alloc_intr_gate(INVALIDATE_TLB_VECTOR_START+4, invalidate_interrupt4); - alloc_intr_gate(INVALIDATE_TLB_VECTOR_START+5, invalidate_interrupt5); - alloc_intr_gate(INVALIDATE_TLB_VECTOR_START+6, invalidate_interrupt6); - alloc_intr_gate(INVALIDATE_TLB_VECTOR_START+7, invalidate_interrupt7); - - /* IPI for generic function call */ - alloc_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt); - - /* IPI for generic single function call */ - alloc_intr_gate(CALL_FUNCTION_SINGLE_VECTOR, - call_function_single_interrupt); - - /* Low priority IPI to cleanup after moving an irq */ - set_intr_gate(IRQ_MOVE_CLEANUP_VECTOR, irq_move_cleanup_interrupt); - set_bit(IRQ_MOVE_CLEANUP_VECTOR, used_vectors); -#endif -} - -static void __init apic_intr_init(void) -{ - smp_intr_init(); - - alloc_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt); - alloc_intr_gate(THRESHOLD_APIC_VECTOR, threshold_interrupt); - - /* self generated IPI for local APIC timer */ - alloc_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt); - - /* generic IPI for platform specific use */ - alloc_intr_gate(GENERIC_INTERRUPT_VECTOR, generic_interrupt); - - /* IPI vectors for APIC spurious and error interrupts */ - alloc_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt); - alloc_intr_gate(ERROR_APIC_VECTOR, error_interrupt); -} - -void __init native_init_IRQ(void) -{ - int i; - - init_ISA_irqs(); - /* - * Cover the whole vector space, no vector can escape - * us. (some of these will be overridden and become - * 'special' SMP interrupts) - */ - for (i = 0; i < (NR_VECTORS - FIRST_EXTERNAL_VECTOR); i++) { - int vector = FIRST_EXTERNAL_VECTOR + i; - if (vector != IA32_SYSCALL_VECTOR) - set_intr_gate(vector, interrupt[i]); - } - - apic_intr_init(); - - if (!acpi_ioapic) - setup_irq(2, &irq2); -} diff --git a/arch/x86/kernel/kgdb.c b/arch/x86/kernel/kgdb.c index b1f4dffb919e..8d82a77a3f3b 100644 --- a/arch/x86/kernel/kgdb.c +++ b/arch/x86/kernel/kgdb.c @@ -142,7 +142,7 @@ void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) gdb_regs32[GDB_PS] = *(unsigned long *)(p->thread.sp + 8); gdb_regs32[GDB_CS] = __KERNEL_CS; gdb_regs32[GDB_SS] = __KERNEL_DS; - gdb_regs[GDB_PC] = p->thread.ip; + gdb_regs[GDB_PC] = 0; gdb_regs[GDB_R8] = 0; gdb_regs[GDB_R9] = 0; gdb_regs[GDB_R10] = 0; diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c index 33019ddb56b4..a78ecad0c900 100644 --- a/arch/x86/kernel/kvm.c +++ b/arch/x86/kernel/kvm.c @@ -27,6 +27,7 @@ #include #include #include +#include #define MMU_QUEUE_SIZE 1024 @@ -195,7 +196,7 @@ static void kvm_leave_lazy_mmu(void) struct kvm_para_state *state = kvm_para_state(); mmu_queue_flush(state); - paravirt_leave_lazy(paravirt_get_lazy_mode()); + paravirt_leave_lazy_mmu(); state->mode = paravirt_get_lazy_mode(); } @@ -230,6 +231,9 @@ static void paravirt_ops_setup(void) pv_mmu_ops.lazy_mode.enter = kvm_enter_lazy_mmu; pv_mmu_ops.lazy_mode.leave = kvm_leave_lazy_mmu; } +#ifdef CONFIG_X86_IO_APIC + no_timer_check = 1; +#endif } void __init kvm_guest_init(void) diff --git a/arch/x86/kernel/microcode_amd.c b/arch/x86/kernel/microcode_amd.c index 453b5795a5c6..366baa179913 100644 --- a/arch/x86/kernel/microcode_amd.c +++ b/arch/x86/kernel/microcode_amd.c @@ -13,25 +13,13 @@ * Licensed under the terms of the GNU General Public * License version 2. See file COPYING for details. */ -#include -#include -#include #include -#include -#include #include #include #include #include #include -#include -#include -#include -#include -#include #include -#include -#include #include #include @@ -79,9 +67,6 @@ struct microcode_amd { #define UCODE_CONTAINER_SECTION_HDR 8 #define UCODE_CONTAINER_HEADER_SIZE 12 -/* serialize access to the physical write */ -static DEFINE_SPINLOCK(microcode_update_lock); - static struct equiv_cpu_entry *equiv_cpu_table; static int collect_cpu_info_amd(int cpu, struct cpu_signature *csig) @@ -144,9 +129,8 @@ static int get_matching_microcode(int cpu, void *mc, int rev) return 1; } -static void apply_microcode_amd(int cpu) +static int apply_microcode_amd(int cpu) { - unsigned long flags; u32 rev, dummy; int cpu_num = raw_smp_processor_id(); struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num; @@ -156,25 +140,25 @@ static void apply_microcode_amd(int cpu) BUG_ON(cpu_num != cpu); if (mc_amd == NULL) - return; + return 0; - spin_lock_irqsave(µcode_update_lock, flags); wrmsrl(MSR_AMD64_PATCH_LOADER, (u64)(long)&mc_amd->hdr.data_code); /* get patch id after patching */ rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy); - spin_unlock_irqrestore(µcode_update_lock, flags); /* check current patch id and patch's id for match */ if (rev != mc_amd->hdr.patch_id) { printk(KERN_ERR "microcode: CPU%d: update failed " "(for patch_level=0x%x)\n", cpu, mc_amd->hdr.patch_id); - return; + return -1; } printk(KERN_INFO "microcode: CPU%d: updated (new patch_level=0x%x)\n", cpu, rev); uci->cpu_sig.rev = rev; + + return 0; } static int get_ucode_data(void *to, const u8 *from, size_t n) @@ -257,13 +241,12 @@ static int install_equiv_cpu_table(const u8 *buf) static void free_equiv_cpu_table(void) { - if (equiv_cpu_table) { - vfree(equiv_cpu_table); - equiv_cpu_table = NULL; - } + vfree(equiv_cpu_table); + equiv_cpu_table = NULL; } -static int generic_load_microcode(int cpu, const u8 *data, size_t size) +static enum ucode_state +generic_load_microcode(int cpu, const u8 *data, size_t size) { struct ucode_cpu_info *uci = ucode_cpu_info + cpu; const u8 *ucode_ptr = data; @@ -272,12 +255,13 @@ static int generic_load_microcode(int cpu, const u8 *data, size_t size) int new_rev = uci->cpu_sig.rev; unsigned int leftover; unsigned long offset; + enum ucode_state state = UCODE_OK; offset = install_equiv_cpu_table(ucode_ptr); if (!offset) { printk(KERN_ERR "microcode: failed to create " "equivalent cpu table\n"); - return -EINVAL; + return UCODE_ERROR; } ucode_ptr += offset; @@ -293,8 +277,7 @@ static int generic_load_microcode(int cpu, const u8 *data, size_t size) mc_header = (struct microcode_header_amd *)mc; if (get_matching_microcode(cpu, mc, new_rev)) { - if (new_mc) - vfree(new_mc); + vfree(new_mc); new_rev = mc_header->patch_id; new_mc = mc; } else @@ -306,34 +289,32 @@ static int generic_load_microcode(int cpu, const u8 *data, size_t size) if (new_mc) { if (!leftover) { - if (uci->mc) - vfree(uci->mc); + vfree(uci->mc); uci->mc = new_mc; pr_debug("microcode: CPU%d found a matching microcode " "update with version 0x%x (current=0x%x)\n", cpu, new_rev, uci->cpu_sig.rev); - } else + } else { vfree(new_mc); - } + state = UCODE_ERROR; + } + } else + state = UCODE_NFOUND; free_equiv_cpu_table(); - return (int)leftover; + return state; } -static int request_microcode_fw(int cpu, struct device *device) +static enum ucode_state request_microcode_fw(int cpu, struct device *device) { const char *fw_name = "amd-ucode/microcode_amd.bin"; const struct firmware *firmware; - int ret; + enum ucode_state ret; - /* We should bind the task to the CPU */ - BUG_ON(cpu != raw_smp_processor_id()); - - ret = request_firmware(&firmware, fw_name, device); - if (ret) { + if (request_firmware(&firmware, fw_name, device)) { printk(KERN_ERR "microcode: failed to load file %s\n", fw_name); - return ret; + return UCODE_NFOUND; } ret = generic_load_microcode(cpu, firmware->data, firmware->size); @@ -343,11 +324,12 @@ static int request_microcode_fw(int cpu, struct device *device) return ret; } -static int request_microcode_user(int cpu, const void __user *buf, size_t size) +static enum ucode_state +request_microcode_user(int cpu, const void __user *buf, size_t size) { printk(KERN_INFO "microcode: AMD microcode update via " "/dev/cpu/microcode not supported\n"); - return -1; + return UCODE_ERROR; } static void microcode_fini_cpu_amd(int cpu) diff --git a/arch/x86/kernel/microcode_core.c b/arch/x86/kernel/microcode_core.c index 98c470c069d1..9371448290ac 100644 --- a/arch/x86/kernel/microcode_core.c +++ b/arch/x86/kernel/microcode_core.c @@ -71,27 +71,18 @@ * Thanks to Stuart Swales for pointing out this bug. */ #include -#include #include -#include +#include #include -#include -#include -#include -#include #include #include #include -#include -#include -#include #include #include #include #include #include -#include MODULE_DESCRIPTION("Microcode Update Driver"); MODULE_AUTHOR("Tigran Aivazian "); @@ -101,36 +92,110 @@ MODULE_LICENSE("GPL"); static struct microcode_ops *microcode_ops; -/* no concurrent ->write()s are allowed on /dev/cpu/microcode */ +/* + * Synchronization. + * + * All non cpu-hotplug-callback call sites use: + * + * - microcode_mutex to synchronize with each other; + * - get/put_online_cpus() to synchronize with + * the cpu-hotplug-callback call sites. + * + * We guarantee that only a single cpu is being + * updated at any particular moment of time. + */ static DEFINE_MUTEX(microcode_mutex); struct ucode_cpu_info ucode_cpu_info[NR_CPUS]; EXPORT_SYMBOL_GPL(ucode_cpu_info); +/* + * Operations that are run on a target cpu: + */ + +struct cpu_info_ctx { + struct cpu_signature *cpu_sig; + int err; +}; + +static void collect_cpu_info_local(void *arg) +{ + struct cpu_info_ctx *ctx = arg; + + ctx->err = microcode_ops->collect_cpu_info(smp_processor_id(), + ctx->cpu_sig); +} + +static int collect_cpu_info_on_target(int cpu, struct cpu_signature *cpu_sig) +{ + struct cpu_info_ctx ctx = { .cpu_sig = cpu_sig, .err = 0 }; + int ret; + + ret = smp_call_function_single(cpu, collect_cpu_info_local, &ctx, 1); + if (!ret) + ret = ctx.err; + + return ret; +} + +static int collect_cpu_info(int cpu) +{ + struct ucode_cpu_info *uci = ucode_cpu_info + cpu; + int ret; + + memset(uci, 0, sizeof(*uci)); + + ret = collect_cpu_info_on_target(cpu, &uci->cpu_sig); + if (!ret) + uci->valid = 1; + + return ret; +} + +struct apply_microcode_ctx { + int err; +}; + +static void apply_microcode_local(void *arg) +{ + struct apply_microcode_ctx *ctx = arg; + + ctx->err = microcode_ops->apply_microcode(smp_processor_id()); +} + +static int apply_microcode_on_target(int cpu) +{ + struct apply_microcode_ctx ctx = { .err = 0 }; + int ret; + + ret = smp_call_function_single(cpu, apply_microcode_local, &ctx, 1); + if (!ret) + ret = ctx.err; + + return ret; +} + #ifdef CONFIG_MICROCODE_OLD_INTERFACE static int do_microcode_update(const void __user *buf, size_t size) { - cpumask_t old; int error = 0; int cpu; - old = current->cpus_allowed; - for_each_online_cpu(cpu) { struct ucode_cpu_info *uci = ucode_cpu_info + cpu; + enum ucode_state ustate; if (!uci->valid) continue; - set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu)); - error = microcode_ops->request_microcode_user(cpu, buf, size); - if (error < 0) - goto out; - if (!error) - microcode_ops->apply_microcode(cpu); + ustate = microcode_ops->request_microcode_user(cpu, buf, size); + if (ustate == UCODE_ERROR) { + error = -1; + break; + } else if (ustate == UCODE_OK) + apply_microcode_on_target(cpu); } -out: - set_cpus_allowed_ptr(current, &old); + return error; } @@ -143,19 +208,17 @@ static int microcode_open(struct inode *unused1, struct file *unused2) static ssize_t microcode_write(struct file *file, const char __user *buf, size_t len, loff_t *ppos) { - ssize_t ret; + ssize_t ret = -EINVAL; if ((len >> PAGE_SHIFT) > num_physpages) { - printk(KERN_ERR "microcode: too much data (max %ld pages)\n", - num_physpages); - return -EINVAL; + pr_err("microcode: too much data (max %ld pages)\n", num_physpages); + return ret; } get_online_cpus(); mutex_lock(µcode_mutex); - ret = do_microcode_update(buf, len); - if (!ret) + if (do_microcode_update(buf, len) == 0) ret = (ssize_t)len; mutex_unlock(µcode_mutex); @@ -165,15 +228,16 @@ static ssize_t microcode_write(struct file *file, const char __user *buf, } static const struct file_operations microcode_fops = { - .owner = THIS_MODULE, - .write = microcode_write, - .open = microcode_open, + .owner = THIS_MODULE, + .write = microcode_write, + .open = microcode_open, }; static struct miscdevice microcode_dev = { - .minor = MICROCODE_MINOR, - .name = "microcode", - .fops = µcode_fops, + .minor = MICROCODE_MINOR, + .name = "microcode", + .devnode = "cpu/microcode", + .fops = µcode_fops, }; static int __init microcode_dev_init(void) @@ -182,9 +246,7 @@ static int __init microcode_dev_init(void) error = misc_register(µcode_dev); if (error) { - printk(KERN_ERR - "microcode: can't misc_register on minor=%d\n", - MICROCODE_MINOR); + pr_err("microcode: can't misc_register on minor=%d\n", MICROCODE_MINOR); return error; } @@ -205,42 +267,51 @@ MODULE_ALIAS_MISCDEV(MICROCODE_MINOR); /* fake device for request_firmware */ static struct platform_device *microcode_pdev; -static long reload_for_cpu(void *unused) +static int reload_for_cpu(int cpu) { - struct ucode_cpu_info *uci = ucode_cpu_info + smp_processor_id(); + struct ucode_cpu_info *uci = ucode_cpu_info + cpu; int err = 0; mutex_lock(µcode_mutex); if (uci->valid) { - err = microcode_ops->request_microcode_fw(smp_processor_id(), - µcode_pdev->dev); - if (!err) - microcode_ops->apply_microcode(smp_processor_id()); + enum ucode_state ustate; + + ustate = microcode_ops->request_microcode_fw(cpu, µcode_pdev->dev); + if (ustate == UCODE_OK) + apply_microcode_on_target(cpu); + else + if (ustate == UCODE_ERROR) + err = -EINVAL; } mutex_unlock(µcode_mutex); + return err; } static ssize_t reload_store(struct sys_device *dev, struct sysdev_attribute *attr, - const char *buf, size_t sz) + const char *buf, size_t size) { - char *end; - unsigned long val = simple_strtoul(buf, &end, 0); - int err = 0; + unsigned long val; int cpu = dev->id; + int ret = 0; + char *end; + val = simple_strtoul(buf, &end, 0); if (end == buf) return -EINVAL; + if (val == 1) { get_online_cpus(); if (cpu_online(cpu)) - err = work_on_cpu(cpu, reload_for_cpu, NULL); + ret = reload_for_cpu(cpu); put_online_cpus(); } - if (err) - return err; - return sz; + + if (!ret) + ret = size; + + return ret; } static ssize_t version_show(struct sys_device *dev, @@ -271,11 +342,11 @@ static struct attribute *mc_default_attrs[] = { }; static struct attribute_group mc_attr_group = { - .attrs = mc_default_attrs, - .name = "microcode", + .attrs = mc_default_attrs, + .name = "microcode", }; -static void __microcode_fini_cpu(int cpu) +static void microcode_fini_cpu(int cpu) { struct ucode_cpu_info *uci = ucode_cpu_info + cpu; @@ -283,103 +354,68 @@ static void __microcode_fini_cpu(int cpu) uci->valid = 0; } -static void microcode_fini_cpu(int cpu) -{ - mutex_lock(µcode_mutex); - __microcode_fini_cpu(cpu); - mutex_unlock(µcode_mutex); -} - -static void collect_cpu_info(int cpu) +static enum ucode_state microcode_resume_cpu(int cpu) { struct ucode_cpu_info *uci = ucode_cpu_info + cpu; - memset(uci, 0, sizeof(*uci)); - if (!microcode_ops->collect_cpu_info(cpu, &uci->cpu_sig)) - uci->valid = 1; -} - -static int microcode_resume_cpu(int cpu) -{ - struct ucode_cpu_info *uci = ucode_cpu_info + cpu; - struct cpu_signature nsig; - - pr_debug("microcode: CPU%d resumed\n", cpu); - if (!uci->mc) - return 1; + return UCODE_NFOUND; - /* - * Let's verify that the 'cached' ucode does belong - * to this cpu (a bit of paranoia): - */ - if (microcode_ops->collect_cpu_info(cpu, &nsig)) { - __microcode_fini_cpu(cpu); - printk(KERN_ERR "failed to collect_cpu_info for resuming cpu #%d\n", - cpu); - return -1; - } + pr_debug("microcode: CPU%d updated upon resume\n", cpu); + apply_microcode_on_target(cpu); - if ((nsig.sig != uci->cpu_sig.sig) || (nsig.pf != uci->cpu_sig.pf)) { - __microcode_fini_cpu(cpu); - printk(KERN_ERR "cached ucode doesn't match the resuming cpu #%d\n", - cpu); - /* Should we look for a new ucode here? */ - return 1; - } - - return 0; + return UCODE_OK; } -static long microcode_update_cpu(void *unused) +static enum ucode_state microcode_init_cpu(int cpu) { - struct ucode_cpu_info *uci = ucode_cpu_info + smp_processor_id(); - int err = 0; + enum ucode_state ustate; - /* - * Check if the system resume is in progress (uci->valid != NULL), - * otherwise just request a firmware: - */ - if (uci->valid) { - err = microcode_resume_cpu(smp_processor_id()); - } else { - collect_cpu_info(smp_processor_id()); - if (uci->valid && system_state == SYSTEM_RUNNING) - err = microcode_ops->request_microcode_fw( - smp_processor_id(), - µcode_pdev->dev); + if (collect_cpu_info(cpu)) + return UCODE_ERROR; + + /* --dimm. Trigger a delayed update? */ + if (system_state != SYSTEM_RUNNING) + return UCODE_NFOUND; + + ustate = microcode_ops->request_microcode_fw(cpu, µcode_pdev->dev); + + if (ustate == UCODE_OK) { + pr_debug("microcode: CPU%d updated upon init\n", cpu); + apply_microcode_on_target(cpu); } - if (!err) - microcode_ops->apply_microcode(smp_processor_id()); - return err; + + return ustate; } -static int microcode_init_cpu(int cpu) +static enum ucode_state microcode_update_cpu(int cpu) { - int err; - mutex_lock(µcode_mutex); - err = work_on_cpu(cpu, microcode_update_cpu, NULL); - mutex_unlock(µcode_mutex); + struct ucode_cpu_info *uci = ucode_cpu_info + cpu; + enum ucode_state ustate; - return err; + if (uci->valid) + ustate = microcode_resume_cpu(cpu); + else + ustate = microcode_init_cpu(cpu); + + return ustate; } static int mc_sysdev_add(struct sys_device *sys_dev) { int err, cpu = sys_dev->id; - struct ucode_cpu_info *uci = ucode_cpu_info + cpu; if (!cpu_online(cpu)) return 0; pr_debug("microcode: CPU%d added\n", cpu); - memset(uci, 0, sizeof(*uci)); err = sysfs_create_group(&sys_dev->kobj, &mc_attr_group); if (err) return err; - err = microcode_init_cpu(cpu); + if (microcode_init_cpu(cpu) == UCODE_ERROR) + err = -EINVAL; return err; } @@ -400,19 +436,30 @@ static int mc_sysdev_remove(struct sys_device *sys_dev) static int mc_sysdev_resume(struct sys_device *dev) { int cpu = dev->id; + struct ucode_cpu_info *uci = ucode_cpu_info + cpu; if (!cpu_online(cpu)) return 0; - /* only CPU 0 will apply ucode here */ - microcode_update_cpu(NULL); + /* + * All non-bootup cpus are still disabled, + * so only CPU 0 will apply ucode here. + * + * Moreover, there can be no concurrent + * updates from any other places at this point. + */ + WARN_ON(cpu != 0); + + if (uci->valid && uci->mc) + microcode_ops->apply_microcode(cpu); + return 0; } static struct sysdev_driver mc_sysdev_driver = { - .add = mc_sysdev_add, - .remove = mc_sysdev_remove, - .resume = mc_sysdev_resume, + .add = mc_sysdev_add, + .remove = mc_sysdev_remove, + .resume = mc_sysdev_resume, }; static __cpuinit int @@ -425,15 +472,12 @@ mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu) switch (action) { case CPU_ONLINE: case CPU_ONLINE_FROZEN: - if (microcode_init_cpu(cpu)) - printk(KERN_ERR "microcode: failed to init CPU%d\n", - cpu); + microcode_update_cpu(cpu); case CPU_DOWN_FAILED: case CPU_DOWN_FAILED_FROZEN: pr_debug("microcode: CPU%d added\n", cpu); if (sysfs_create_group(&sys_dev->kobj, &mc_attr_group)) - printk(KERN_ERR "microcode: Failed to create the sysfs " - "group for CPU%d\n", cpu); + pr_err("microcode: Failed to create group for CPU%d\n", cpu); break; case CPU_DOWN_PREPARE: case CPU_DOWN_PREPARE_FROZEN: @@ -465,13 +509,10 @@ static int __init microcode_init(void) microcode_ops = init_amd_microcode(); if (!microcode_ops) { - printk(KERN_ERR "microcode: no support for this CPU vendor\n"); + pr_err("microcode: no support for this CPU vendor\n"); return -ENODEV; } - error = microcode_dev_init(); - if (error) - return error; microcode_pdev = platform_device_register_simple("microcode", -1, NULL, 0); if (IS_ERR(microcode_pdev)) { @@ -480,23 +521,31 @@ static int __init microcode_init(void) } get_online_cpus(); + mutex_lock(µcode_mutex); + error = sysdev_driver_register(&cpu_sysdev_class, &mc_sysdev_driver); + + mutex_unlock(µcode_mutex); put_online_cpus(); + if (error) { - microcode_dev_exit(); platform_device_unregister(microcode_pdev); return error; } + error = microcode_dev_init(); + if (error) + return error; + register_hotcpu_notifier(&mc_cpu_notifier); - printk(KERN_INFO - "Microcode Update Driver: v" MICROCODE_VERSION + pr_info("Microcode Update Driver: v" MICROCODE_VERSION " ," " Peter Oruba\n"); return 0; } +module_init(microcode_init); static void __exit microcode_exit(void) { @@ -505,16 +554,17 @@ static void __exit microcode_exit(void) unregister_hotcpu_notifier(&mc_cpu_notifier); get_online_cpus(); + mutex_lock(µcode_mutex); + sysdev_driver_unregister(&cpu_sysdev_class, &mc_sysdev_driver); + + mutex_unlock(µcode_mutex); put_online_cpus(); platform_device_unregister(microcode_pdev); microcode_ops = NULL; - printk(KERN_INFO - "Microcode Update Driver: v" MICROCODE_VERSION " removed.\n"); + pr_info("Microcode Update Driver: v" MICROCODE_VERSION " removed.\n"); } - -module_init(microcode_init); module_exit(microcode_exit); diff --git a/arch/x86/kernel/microcode_intel.c b/arch/x86/kernel/microcode_intel.c index 149b9ec7c1ab..0d334ddd0a96 100644 --- a/arch/x86/kernel/microcode_intel.c +++ b/arch/x86/kernel/microcode_intel.c @@ -70,24 +70,11 @@ * Fix sigmatch() macro to handle old CPUs with pf == 0. * Thanks to Stuart Swales for pointing out this bug. */ -#include -#include -#include #include -#include -#include -#include #include -#include #include #include -#include -#include -#include -#include -#include -#include -#include +#include #include #include @@ -150,13 +137,9 @@ struct extended_sigtable { #define exttable_size(et) ((et)->count * EXT_SIGNATURE_SIZE + EXT_HEADER_SIZE) -/* serialize access to the physical write to MSR 0x79 */ -static DEFINE_SPINLOCK(microcode_update_lock); - static int collect_cpu_info(int cpu_num, struct cpu_signature *csig) { struct cpuinfo_x86 *c = &cpu_data(cpu_num); - unsigned long flags; unsigned int val[2]; memset(csig, 0, sizeof(*csig)); @@ -176,18 +159,14 @@ static int collect_cpu_info(int cpu_num, struct cpu_signature *csig) csig->pf = 1 << ((val[1] >> 18) & 7); } - /* serialize access to the physical write to MSR 0x79 */ - spin_lock_irqsave(µcode_update_lock, flags); - wrmsr(MSR_IA32_UCODE_REV, 0, 0); /* see notes above for revision 1.07. Apparent chip bug */ sync_core(); /* get the current revision from MSR 0x8B */ rdmsr(MSR_IA32_UCODE_REV, val[0], csig->rev); - spin_unlock_irqrestore(µcode_update_lock, flags); - pr_debug("microcode: collect_cpu_info : sig=0x%x, pf=0x%x, rev=0x%x\n", - csig->sig, csig->pf, csig->rev); + printk(KERN_INFO "microcode: CPU%d sig=0x%x, pf=0x%x, revision=0x%x\n", + cpu_num, csig->sig, csig->pf, csig->rev); return 0; } @@ -318,11 +297,10 @@ get_matching_microcode(struct cpu_signature *cpu_sig, void *mc, int rev) return 0; } -static void apply_microcode(int cpu) +static int apply_microcode(int cpu) { struct microcode_intel *mc_intel; struct ucode_cpu_info *uci; - unsigned long flags; unsigned int val[2]; int cpu_num; @@ -334,10 +312,7 @@ static void apply_microcode(int cpu) BUG_ON(cpu_num != cpu); if (mc_intel == NULL) - return; - - /* serialize access to the physical write to MSR 0x79 */ - spin_lock_irqsave(µcode_update_lock, flags); + return 0; /* write microcode via MSR 0x79 */ wrmsr(MSR_IA32_UCODE_WRITE, @@ -351,30 +326,32 @@ static void apply_microcode(int cpu) /* get the current revision from MSR 0x8B */ rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]); - spin_unlock_irqrestore(µcode_update_lock, flags); if (val[1] != mc_intel->hdr.rev) { - printk(KERN_ERR "microcode: CPU%d update from revision " - "0x%x to 0x%x failed\n", - cpu_num, uci->cpu_sig.rev, val[1]); - return; + printk(KERN_ERR "microcode: CPU%d update " + "to revision 0x%x failed\n", + cpu_num, mc_intel->hdr.rev); + return -1; } - printk(KERN_INFO "microcode: CPU%d updated from revision " - "0x%x to 0x%x, date = %04x-%02x-%02x \n", - cpu_num, uci->cpu_sig.rev, val[1], + printk(KERN_INFO "microcode: CPU%d updated to revision " + "0x%x, date = %04x-%02x-%02x \n", + cpu_num, val[1], mc_intel->hdr.date & 0xffff, mc_intel->hdr.date >> 24, (mc_intel->hdr.date >> 16) & 0xff); uci->cpu_sig.rev = val[1]; + + return 0; } -static int generic_load_microcode(int cpu, void *data, size_t size, - int (*get_ucode_data)(void *, const void *, size_t)) +static enum ucode_state generic_load_microcode(int cpu, void *data, size_t size, + int (*get_ucode_data)(void *, const void *, size_t)) { struct ucode_cpu_info *uci = ucode_cpu_info + cpu; u8 *ucode_ptr = data, *new_mc = NULL, *mc; int new_rev = uci->cpu_sig.rev; unsigned int leftover = size; + enum ucode_state state = UCODE_OK; while (leftover) { struct microcode_header_intel mc_header; @@ -412,11 +389,15 @@ static int generic_load_microcode(int cpu, void *data, size_t size, leftover -= mc_size; } - if (!new_mc) - goto out; - if (leftover) { - vfree(new_mc); + if (new_mc) + vfree(new_mc); + state = UCODE_ERROR; + goto out; + } + + if (!new_mc) { + state = UCODE_NFOUND; goto out; } @@ -427,9 +408,8 @@ static int generic_load_microcode(int cpu, void *data, size_t size, pr_debug("microcode: CPU%d found a matching microcode update with" " version 0x%x (current=0x%x)\n", cpu, new_rev, uci->cpu_sig.rev); - - out: - return (int)leftover; +out: + return state; } static int get_ucode_fw(void *to, const void *from, size_t n) @@ -438,21 +418,19 @@ static int get_ucode_fw(void *to, const void *from, size_t n) return 0; } -static int request_microcode_fw(int cpu, struct device *device) +static enum ucode_state request_microcode_fw(int cpu, struct device *device) { char name[30]; struct cpuinfo_x86 *c = &cpu_data(cpu); const struct firmware *firmware; - int ret; + enum ucode_state ret; - /* We should bind the task to the CPU */ - BUG_ON(cpu != raw_smp_processor_id()); sprintf(name, "intel-ucode/%02x-%02x-%02x", c->x86, c->x86_model, c->x86_mask); - ret = request_firmware(&firmware, name, device); - if (ret) { + + if (request_firmware(&firmware, name, device)) { pr_debug("microcode: data file %s load failed\n", name); - return ret; + return UCODE_NFOUND; } ret = generic_load_microcode(cpu, (void *)firmware->data, @@ -468,11 +446,9 @@ static int get_ucode_user(void *to, const void *from, size_t n) return copy_from_user(to, from, n); } -static int request_microcode_user(int cpu, const void __user *buf, size_t size) +static enum ucode_state +request_microcode_user(int cpu, const void __user *buf, size_t size) { - /* We should bind the task to the CPU */ - BUG_ON(cpu != raw_smp_processor_id()); - return generic_load_microcode(cpu, (void *)buf, size, &get_ucode_user); } diff --git a/arch/x86/kernel/module_64.c b/arch/x86/kernel/module.c similarity index 74% rename from arch/x86/kernel/module_64.c rename to arch/x86/kernel/module.c index c23880b90b5c..89f386f044e4 100644 --- a/arch/x86/kernel/module_64.c +++ b/arch/x86/kernel/module.c @@ -1,6 +1,5 @@ -/* Kernel module help for x86-64 +/* Kernel module help for x86. Copyright (C) 2001 Rusty Russell. - Copyright (C) 2002,2003 Andi Kleen, SuSE Labs. 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 @@ -22,23 +21,18 @@ #include #include #include -#include -#include #include +#include #include #include #include +#if 0 +#define DEBUGP printk +#else #define DEBUGP(fmt...) - -#ifndef CONFIG_UML -void module_free(struct module *mod, void *module_region) -{ - vfree(module_region); - /* FIXME: If module_region == mod->init_region, trim exception - table entries. */ -} +#endif void *module_alloc(unsigned long size) { @@ -54,9 +48,15 @@ void *module_alloc(unsigned long size) if (!area) return NULL; - return __vmalloc_area(area, GFP_KERNEL, PAGE_KERNEL_EXEC); + return __vmalloc_area(area, GFP_KERNEL | __GFP_HIGHMEM, + PAGE_KERNEL_EXEC); +} + +/* Free memory returned from module_alloc */ +void module_free(struct module *mod, void *module_region) +{ + vfree(module_region); } -#endif /* We don't need anything special. */ int module_frob_arch_sections(Elf_Ehdr *hdr, @@ -67,6 +67,58 @@ int module_frob_arch_sections(Elf_Ehdr *hdr, return 0; } +#ifdef CONFIG_X86_32 +int apply_relocate(Elf32_Shdr *sechdrs, + const char *strtab, + unsigned int symindex, + unsigned int relsec, + struct module *me) +{ + unsigned int i; + Elf32_Rel *rel = (void *)sechdrs[relsec].sh_addr; + Elf32_Sym *sym; + uint32_t *location; + + DEBUGP("Applying relocate section %u to %u\n", relsec, + sechdrs[relsec].sh_info); + for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { + /* This is where to make the change */ + location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr + + rel[i].r_offset; + /* This is the symbol it is referring to. Note that all + undefined symbols have been resolved. */ + sym = (Elf32_Sym *)sechdrs[symindex].sh_addr + + ELF32_R_SYM(rel[i].r_info); + + switch (ELF32_R_TYPE(rel[i].r_info)) { + case R_386_32: + /* We add the value into the location given */ + *location += sym->st_value; + break; + case R_386_PC32: + /* Add the value, subtract its postition */ + *location += sym->st_value - (uint32_t)location; + break; + default: + printk(KERN_ERR "module %s: Unknown relocation: %u\n", + me->name, ELF32_R_TYPE(rel[i].r_info)); + return -ENOEXEC; + } + } + return 0; +} + +int apply_relocate_add(Elf32_Shdr *sechdrs, + const char *strtab, + unsigned int symindex, + unsigned int relsec, + struct module *me) +{ + printk(KERN_ERR "module %s: ADD RELOCATION unsupported\n", + me->name); + return -ENOEXEC; +} +#else /*X86_64*/ int apply_relocate_add(Elf64_Shdr *sechdrs, const char *strtab, unsigned int symindex, @@ -147,6 +199,8 @@ int apply_relocate(Elf_Shdr *sechdrs, return -ENOSYS; } +#endif + int module_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, struct module *me) diff --git a/arch/x86/kernel/module_32.c b/arch/x86/kernel/module_32.c deleted file mode 100644 index 0edd819050e7..000000000000 --- a/arch/x86/kernel/module_32.c +++ /dev/null @@ -1,152 +0,0 @@ -/* Kernel module help for i386. - Copyright (C) 2001 Rusty Russell. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ -#include -#include -#include -#include -#include -#include -#include - -#if 0 -#define DEBUGP printk -#else -#define DEBUGP(fmt...) -#endif - -void *module_alloc(unsigned long size) -{ - if (size == 0) - return NULL; - return vmalloc_exec(size); -} - - -/* Free memory returned from module_alloc */ -void module_free(struct module *mod, void *module_region) -{ - vfree(module_region); - /* FIXME: If module_region == mod->init_region, trim exception - table entries. */ -} - -/* We don't need anything special. */ -int module_frob_arch_sections(Elf_Ehdr *hdr, - Elf_Shdr *sechdrs, - char *secstrings, - struct module *mod) -{ - return 0; -} - -int apply_relocate(Elf32_Shdr *sechdrs, - const char *strtab, - unsigned int symindex, - unsigned int relsec, - struct module *me) -{ - unsigned int i; - Elf32_Rel *rel = (void *)sechdrs[relsec].sh_addr; - Elf32_Sym *sym; - uint32_t *location; - - DEBUGP("Applying relocate section %u to %u\n", relsec, - sechdrs[relsec].sh_info); - for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { - /* This is where to make the change */ - location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr - + rel[i].r_offset; - /* This is the symbol it is referring to. Note that all - undefined symbols have been resolved. */ - sym = (Elf32_Sym *)sechdrs[symindex].sh_addr - + ELF32_R_SYM(rel[i].r_info); - - switch (ELF32_R_TYPE(rel[i].r_info)) { - case R_386_32: - /* We add the value into the location given */ - *location += sym->st_value; - break; - case R_386_PC32: - /* Add the value, subtract its postition */ - *location += sym->st_value - (uint32_t)location; - break; - default: - printk(KERN_ERR "module %s: Unknown relocation: %u\n", - me->name, ELF32_R_TYPE(rel[i].r_info)); - return -ENOEXEC; - } - } - return 0; -} - -int apply_relocate_add(Elf32_Shdr *sechdrs, - const char *strtab, - unsigned int symindex, - unsigned int relsec, - struct module *me) -{ - printk(KERN_ERR "module %s: ADD RELOCATION unsupported\n", - me->name); - return -ENOEXEC; -} - -int module_finalize(const Elf_Ehdr *hdr, - const Elf_Shdr *sechdrs, - struct module *me) -{ - 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++) { - if (!strcmp(".text", secstrings + s->sh_name)) - text = s; - if (!strcmp(".altinstructions", secstrings + s->sh_name)) - alt = s; - if (!strcmp(".smp_locks", secstrings + s->sh_name)) - locks = s; - if (!strcmp(".parainstructions", secstrings + s->sh_name)) - para = s; - } - - if (alt) { - /* patch .altinstructions */ - void *aseg = (void *)alt->sh_addr; - apply_alternatives(aseg, aseg + alt->sh_size); - } - if (locks && text) { - void *lseg = (void *)locks->sh_addr; - void *tseg = (void *)text->sh_addr; - alternatives_smp_module_add(me, me->name, - lseg, lseg + locks->sh_size, - 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); -} - -void module_arch_cleanup(struct module *mod) -{ - alternatives_smp_module_del(mod); - module_bug_cleanup(mod); -} diff --git a/arch/x86/kernel/mpparse.c b/arch/x86/kernel/mpparse.c index 70fd7e414c15..651c93b28862 100644 --- a/arch/x86/kernel/mpparse.c +++ b/arch/x86/kernel/mpparse.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -870,24 +871,17 @@ static inline void __init check_irq_src(struct mpc_intsrc *m, int *nr_m_spare) {} #endif /* CONFIG_X86_IO_APIC */ -static int check_slot(unsigned long mpc_new_phys, unsigned long mpc_new_length, - int count) +static int +check_slot(unsigned long mpc_new_phys, unsigned long mpc_new_length, int count) { - if (!mpc_new_phys) { - pr_info("No spare slots, try to append...take your risk, " - "new mpc_length %x\n", count); - } else { - if (count <= mpc_new_length) - pr_info("No spare slots, try to append..., " - "new mpc_length %x\n", count); - else { - pr_err("mpc_new_length %lx is too small\n", - mpc_new_length); - return -1; - } + int ret = 0; + + if (!mpc_new_phys || count <= mpc_new_length) { + WARN(1, "update_mptable: No spare slots (length: %x)\n", count); + return -1; } - return 0; + return ret; } static int __init replace_intsrc_all(struct mpc_table *mpc, @@ -946,7 +940,7 @@ static int __init replace_intsrc_all(struct mpc_table *mpc, } else { struct mpc_intsrc *m = (struct mpc_intsrc *)mpt; count += sizeof(struct mpc_intsrc); - if (!check_slot(mpc_new_phys, mpc_new_length, count)) + if (check_slot(mpc_new_phys, mpc_new_length, count) < 0) goto out; assign_to_mpc_intsrc(&mp_irqs[i], m); mpc->length = count; @@ -963,11 +957,14 @@ out: return 0; } -static int __initdata enable_update_mptable; +int enable_update_mptable; static int __init update_mptable_setup(char *str) { enable_update_mptable = 1; +#ifdef CONFIG_PCI + pci_routeirq = 1; +#endif return 0; } early_param("update_mptable", update_mptable_setup); @@ -980,6 +977,9 @@ static int __initdata alloc_mptable; static int __init parse_alloc_mptable_opt(char *p) { enable_update_mptable = 1; +#ifdef CONFIG_PCI + pci_routeirq = 1; +#endif alloc_mptable = 1; if (!p) return 0; diff --git a/arch/x86/kernel/msr.c b/arch/x86/kernel/msr.c index 3cf3413ec626..98fd6cd4e3a4 100644 --- a/arch/x86/kernel/msr.c +++ b/arch/x86/kernel/msr.c @@ -196,6 +196,11 @@ static struct notifier_block __refdata msr_class_cpu_notifier = { .notifier_call = msr_class_cpu_callback, }; +static char *msr_nodename(struct device *dev) +{ + return kasprintf(GFP_KERNEL, "cpu/%u/msr", MINOR(dev->devt)); +} + static int __init msr_init(void) { int i, err = 0; @@ -212,6 +217,7 @@ static int __init msr_init(void) err = PTR_ERR(msr_class); goto out_chrdev; } + msr_class->nodename = msr_nodename; for_each_online_cpu(i) { err = msr_device_create(i); if (err != 0) diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c index 9faf43bea336..70ec9b951d76 100644 --- a/arch/x86/kernel/paravirt.c +++ b/arch/x86/kernel/paravirt.c @@ -248,18 +248,16 @@ static DEFINE_PER_CPU(enum paravirt_lazy_mode, paravirt_lazy_mode) = PARAVIRT_LA static inline void enter_lazy(enum paravirt_lazy_mode mode) { - BUG_ON(__get_cpu_var(paravirt_lazy_mode) != PARAVIRT_LAZY_NONE); - BUG_ON(preemptible()); + BUG_ON(percpu_read(paravirt_lazy_mode) != PARAVIRT_LAZY_NONE); - __get_cpu_var(paravirt_lazy_mode) = mode; + percpu_write(paravirt_lazy_mode, mode); } -void paravirt_leave_lazy(enum paravirt_lazy_mode mode) +static void leave_lazy(enum paravirt_lazy_mode mode) { - BUG_ON(__get_cpu_var(paravirt_lazy_mode) != mode); - BUG_ON(preemptible()); + BUG_ON(percpu_read(paravirt_lazy_mode) != mode); - __get_cpu_var(paravirt_lazy_mode) = PARAVIRT_LAZY_NONE; + percpu_write(paravirt_lazy_mode, PARAVIRT_LAZY_NONE); } void paravirt_enter_lazy_mmu(void) @@ -269,22 +267,36 @@ void paravirt_enter_lazy_mmu(void) void paravirt_leave_lazy_mmu(void) { - paravirt_leave_lazy(PARAVIRT_LAZY_MMU); + leave_lazy(PARAVIRT_LAZY_MMU); } -void paravirt_enter_lazy_cpu(void) +void paravirt_start_context_switch(struct task_struct *prev) { + BUG_ON(preemptible()); + + if (percpu_read(paravirt_lazy_mode) == PARAVIRT_LAZY_MMU) { + arch_leave_lazy_mmu_mode(); + set_ti_thread_flag(task_thread_info(prev), TIF_LAZY_MMU_UPDATES); + } enter_lazy(PARAVIRT_LAZY_CPU); } -void paravirt_leave_lazy_cpu(void) +void paravirt_end_context_switch(struct task_struct *next) { - paravirt_leave_lazy(PARAVIRT_LAZY_CPU); + BUG_ON(preemptible()); + + leave_lazy(PARAVIRT_LAZY_CPU); + + if (test_and_clear_ti_thread_flag(task_thread_info(next), TIF_LAZY_MMU_UPDATES)) + arch_enter_lazy_mmu_mode(); } enum paravirt_lazy_mode paravirt_get_lazy_mode(void) { - return __get_cpu_var(paravirt_lazy_mode); + if (in_interrupt()) + return PARAVIRT_LAZY_NONE; + + return percpu_read(paravirt_lazy_mode); } void arch_flush_lazy_mmu_mode(void) @@ -292,7 +304,6 @@ void arch_flush_lazy_mmu_mode(void) preempt_disable(); if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU) { - WARN_ON(preempt_count() == 1); arch_leave_lazy_mmu_mode(); arch_enter_lazy_mmu_mode(); } @@ -300,19 +311,6 @@ void arch_flush_lazy_mmu_mode(void) preempt_enable(); } -void arch_flush_lazy_cpu_mode(void) -{ - preempt_disable(); - - if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_CPU) { - WARN_ON(preempt_count() == 1); - arch_leave_lazy_cpu_mode(); - arch_enter_lazy_cpu_mode(); - } - - preempt_enable(); -} - struct pv_info pv_info = { .name = "bare hardware", .paravirt_enabled = 0, @@ -404,10 +402,8 @@ struct pv_cpu_ops pv_cpu_ops = { .set_iopl_mask = native_set_iopl_mask, .io_delay = native_io_delay, - .lazy_mode = { - .enter = paravirt_nop, - .leave = paravirt_nop, - }, + .start_context_switch = paravirt_nop, + .end_context_switch = paravirt_nop, }; struct pv_apic_ops pv_apic_ops = { diff --git a/arch/x86/kernel/pci-calgary_64.c b/arch/x86/kernel/pci-calgary_64.c index 755c21e906f3..971a3bec47a8 100644 --- a/arch/x86/kernel/pci-calgary_64.c +++ b/arch/x86/kernel/pci-calgary_64.c @@ -186,37 +186,6 @@ static struct cal_chipset_ops calioc2_chip_ops = { static struct calgary_bus_info bus_info[MAX_PHB_BUS_NUM] = { { NULL, 0, 0 }, }; -/* enable this to stress test the chip's TCE cache */ -#ifdef CONFIG_IOMMU_DEBUG -static int debugging = 1; - -static inline unsigned long verify_bit_range(unsigned long* bitmap, - int expected, unsigned long start, unsigned long end) -{ - unsigned long idx = start; - - BUG_ON(start >= end); - - while (idx < end) { - if (!!test_bit(idx, bitmap) != expected) - return idx; - ++idx; - } - - /* all bits have the expected value */ - return ~0UL; -} -#else /* debugging is disabled */ -static int debugging; - -static inline unsigned long verify_bit_range(unsigned long* bitmap, - int expected, unsigned long start, unsigned long end) -{ - return ~0UL; -} - -#endif /* CONFIG_IOMMU_DEBUG */ - static inline int translation_enabled(struct iommu_table *tbl) { /* only PHBs with translation enabled have an IOMMU table */ @@ -228,7 +197,6 @@ static void iommu_range_reserve(struct iommu_table *tbl, { unsigned long index; unsigned long end; - unsigned long badbit; unsigned long flags; index = start_addr >> PAGE_SHIFT; @@ -243,14 +211,6 @@ static void iommu_range_reserve(struct iommu_table *tbl, spin_lock_irqsave(&tbl->it_lock, flags); - badbit = verify_bit_range(tbl->it_map, 0, index, end); - if (badbit != ~0UL) { - if (printk_ratelimit()) - printk(KERN_ERR "Calgary: entry already allocated at " - "0x%lx tbl %p dma 0x%lx npages %u\n", - badbit, tbl, start_addr, npages); - } - iommu_area_reserve(tbl->it_map, index, npages); spin_unlock_irqrestore(&tbl->it_lock, flags); @@ -326,7 +286,6 @@ static void iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr, unsigned int npages) { unsigned long entry; - unsigned long badbit; unsigned long badend; unsigned long flags; @@ -346,14 +305,6 @@ static void iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr, spin_lock_irqsave(&tbl->it_lock, flags); - badbit = verify_bit_range(tbl->it_map, 1, entry, entry + npages); - if (badbit != ~0UL) { - if (printk_ratelimit()) - printk(KERN_ERR "Calgary: bit is off at 0x%lx " - "tbl %p dma 0x%Lx entry 0x%lx npages %u\n", - badbit, tbl, dma_addr, entry, npages); - } - iommu_area_free(tbl->it_map, entry, npages); spin_unlock_irqrestore(&tbl->it_lock, flags); @@ -1488,9 +1439,8 @@ void __init detect_calgary(void) iommu_detected = 1; calgary_detected = 1; printk(KERN_INFO "PCI-DMA: Calgary IOMMU detected.\n"); - printk(KERN_INFO "PCI-DMA: Calgary TCE table spec is %d, " - "CONFIG_IOMMU_DEBUG is %s.\n", specified_table_size, - debugging ? "enabled" : "disabled"); + printk(KERN_INFO "PCI-DMA: Calgary TCE table spec is %d\n", + specified_table_size); /* swiotlb for devices that aren't behind the Calgary. */ if (max_pfn > MAX_DMA32_PFN) diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c index 745579bc8256..47630479b067 100644 --- a/arch/x86/kernel/pci-dma.c +++ b/arch/x86/kernel/pci-dma.c @@ -32,6 +32,8 @@ int no_iommu __read_mostly; /* Set this to 1 if there is a HW IOMMU in the system */ int iommu_detected __read_mostly = 0; +int iommu_pass_through; + dma_addr_t bad_dma_address __read_mostly = 0; EXPORT_SYMBOL(bad_dma_address); @@ -209,6 +211,10 @@ static __init int iommu_setup(char *p) #ifdef CONFIG_SWIOTLB if (!strncmp(p, "soft", 4)) swiotlb = 1; + if (!strncmp(p, "pt", 2)) { + iommu_pass_through = 1; + return 1; + } #endif gart_parse_options(p); @@ -290,6 +296,8 @@ static int __init pci_iommu_init(void) void pci_iommu_shutdown(void) { gart_iommu_shutdown(); + + amd_iommu_shutdown(); } /* Must execute after PCI subsystem */ fs_initcall(pci_iommu_init); diff --git a/arch/x86/kernel/pci-gart_64.c b/arch/x86/kernel/pci-gart_64.c index b284b58c035c..cfd9f9063896 100644 --- a/arch/x86/kernel/pci-gart_64.c +++ b/arch/x86/kernel/pci-gart_64.c @@ -144,48 +144,21 @@ static void flush_gart(void) } #ifdef CONFIG_IOMMU_LEAK - -#define SET_LEAK(x) \ - do { \ - if (iommu_leak_tab) \ - iommu_leak_tab[x] = __builtin_return_address(0);\ - } while (0) - -#define CLEAR_LEAK(x) \ - do { \ - if (iommu_leak_tab) \ - iommu_leak_tab[x] = NULL; \ - } while (0) - /* Debugging aid for drivers that don't free their IOMMU tables */ -static void **iommu_leak_tab; static int leak_trace; static int iommu_leak_pages = 20; static void dump_leak(void) { - int i; static int dump; - if (dump || !iommu_leak_tab) + if (dump) return; dump = 1; - show_stack(NULL, NULL); - /* Very crude. dump some from the end of the table too */ - printk(KERN_DEBUG "Dumping %d pages from end of IOMMU:\n", - iommu_leak_pages); - for (i = 0; i < iommu_leak_pages; i += 2) { - printk(KERN_DEBUG "%lu: ", iommu_pages-i); - printk_address((unsigned long) iommu_leak_tab[iommu_pages-i], - 0); - printk(KERN_CONT "%c", (i+1)%2 == 0 ? '\n' : ' '); - } - printk(KERN_DEBUG "\n"); + show_stack(NULL, NULL); + debug_dma_dump_mappings(NULL); } -#else -# define SET_LEAK(x) -# define CLEAR_LEAK(x) #endif static void iommu_full(struct device *dev, size_t size, int dir) @@ -248,7 +221,6 @@ static dma_addr_t dma_map_area(struct device *dev, dma_addr_t phys_mem, for (i = 0; i < npages; i++) { iommu_gatt_base[iommu_page + i] = GPTE_ENCODE(phys_mem); - SET_LEAK(iommu_page + i); phys_mem += PAGE_SIZE; } return iommu_bus_base + iommu_page*PAGE_SIZE + (phys_mem & ~PAGE_MASK); @@ -294,7 +266,6 @@ static void gart_unmap_page(struct device *dev, dma_addr_t dma_addr, npages = iommu_num_pages(dma_addr, size, PAGE_SIZE); for (i = 0; i < npages; i++) { iommu_gatt_base[iommu_page + i] = gart_unmapped_entry; - CLEAR_LEAK(iommu_page + i); } free_iommu(iommu_page, npages); } @@ -377,7 +348,6 @@ static int __dma_map_cont(struct device *dev, struct scatterlist *start, pages = iommu_num_pages(s->offset, s->length, PAGE_SIZE); while (pages--) { iommu_gatt_base[iommu_page] = GPTE_ENCODE(addr); - SET_LEAK(iommu_page); addr += PAGE_SIZE; iommu_page++; } @@ -688,8 +658,6 @@ static __init int init_k8_gatt(struct agp_kern_info *info) agp_gatt_table = gatt; - enable_gart_translations(); - error = sysdev_class_register(&gart_sysdev_class); if (!error) error = sysdev_register(&device_gart); @@ -801,11 +769,12 @@ void __init gart_iommu_init(void) #ifdef CONFIG_IOMMU_LEAK if (leak_trace) { - iommu_leak_tab = (void *)__get_free_pages(GFP_KERNEL|__GFP_ZERO, - get_order(iommu_pages*sizeof(void *))); - if (!iommu_leak_tab) + int ret; + + ret = dma_debug_resize_entries(iommu_pages); + if (ret) printk(KERN_DEBUG - "PCI-DMA: Cannot allocate leak trace area\n"); + "PCI-DMA: Cannot trace all the entries\n"); } #endif @@ -845,6 +814,14 @@ void __init gart_iommu_init(void) * the pages as Not-Present: */ wbinvd(); + + /* + * Now all caches are flushed and we can safely enable + * GART hardware. Doing it early leaves the possibility + * of stale cache entries that can lead to GART PTE + * errors. + */ + enable_gart_translations(); /* * Try to workaround a bug (thanks to BenH): diff --git a/arch/x86/kernel/pci-swiotlb.c b/arch/x86/kernel/pci-swiotlb.c index 221a3853e268..6af96ee44200 100644 --- a/arch/x86/kernel/pci-swiotlb.c +++ b/arch/x86/kernel/pci-swiotlb.c @@ -28,7 +28,7 @@ dma_addr_t swiotlb_phys_to_bus(struct device *hwdev, phys_addr_t paddr) return paddr; } -phys_addr_t swiotlb_bus_to_phys(dma_addr_t baddr) +phys_addr_t swiotlb_bus_to_phys(struct device *hwdev, dma_addr_t baddr) { return baddr; } @@ -71,7 +71,8 @@ void __init pci_swiotlb_init(void) { /* don't initialize swiotlb if iommu=off (no_iommu=1) */ #ifdef CONFIG_X86_64 - if (!iommu_detected && !no_iommu && max_pfn > MAX_DMA32_PFN) + if ((!iommu_detected && !no_iommu && max_pfn > MAX_DMA32_PFN) || + iommu_pass_through) swiotlb = 1; #endif if (swiotlb_force) diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index ca989158e847..994dd6a4a2a0 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -8,12 +8,15 @@ #include #include #include +#include #include #include #include +#include #include #include #include +#include unsigned long idle_halt; EXPORT_SYMBOL(idle_halt); @@ -45,6 +48,8 @@ void free_thread_xstate(struct task_struct *tsk) kmem_cache_free(task_xstate_cachep, tsk->thread.xstate); tsk->thread.xstate = NULL; } + + WARN(tsk->thread.ds_ctx, "leaking DS context\n"); } void free_thread_info(struct thread_info *ti) @@ -58,7 +63,7 @@ void arch_task_cache_init(void) task_xstate_cachep = kmem_cache_create("task_xstate", xstate_size, __alignof__(union thread_xstate), - SLAB_PANIC, NULL); + SLAB_PANIC | SLAB_NOTRACK, NULL); } /* @@ -83,8 +88,6 @@ void exit_thread(void) put_cpu(); kfree(bp); } - - ds_exit_thread(current); } void flush_thread(void) @@ -613,3 +616,16 @@ static int __init idle_setup(char *str) } early_param("idle", idle_setup); +unsigned long arch_align_stack(unsigned long sp) +{ + if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space) + sp -= get_random_int() % 8192; + return sp & ~0xf; +} + +unsigned long arch_randomize_brk(struct mm_struct *mm) +{ + unsigned long range_end = mm->brk + 0x02000000; + return randomize_range(mm->brk, range_end, 0) ? : mm->brk; +} + diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c index 76f8f84043a2..59f4524984af 100644 --- a/arch/x86/kernel/process_32.c +++ b/arch/x86/kernel/process_32.c @@ -9,8 +9,6 @@ * This file handles the architecture-dependent parts of process handling.. */ -#include - #include #include #include @@ -33,7 +31,6 @@ #include #include #include -#include #include #include #include @@ -290,7 +287,8 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, p->thread.io_bitmap_max = 0; } - ds_copy_thread(p, current); + clear_tsk_thread_flag(p, TIF_DS_AREA_MSR); + p->thread.ds_ctx = NULL; clear_tsk_thread_flag(p, TIF_DEBUGCTLMSR); p->thread.debugctlmsr = 0; @@ -407,7 +405,7 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) * done before math_state_restore, so the TS bit is up * to date. */ - arch_leave_lazy_cpu_mode(); + arch_end_context_switch(next_p); /* If the task has used fpu the last 5 timeslices, just do a full * restore of the math state immediately to avoid the trap; the @@ -497,15 +495,3 @@ unsigned long get_wchan(struct task_struct *p) return 0; } -unsigned long arch_align_stack(unsigned long sp) -{ - if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space) - sp -= get_random_int() % 8192; - return sp & ~0xf; -} - -unsigned long arch_randomize_brk(struct mm_struct *mm) -{ - unsigned long range_end = mm->brk + 0x02000000; - return randomize_range(mm->brk, range_end, 0) ? : mm->brk; -} diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index b751a41392b1..ebefb5407b9d 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c @@ -14,8 +14,6 @@ * This file handles the architecture-dependent parts of process handling.. */ -#include - #include #include #include @@ -32,7 +30,6 @@ #include #include #include -#include #include #include #include @@ -335,7 +332,8 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, goto out; } - ds_copy_thread(p, me); + clear_tsk_thread_flag(p, TIF_DS_AREA_MSR); + p->thread.ds_ctx = NULL; clear_tsk_thread_flag(p, TIF_DEBUGCTLMSR); p->thread.debugctlmsr = 0; @@ -428,7 +426,7 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) * done before math_state_restore, so the TS bit is up * to date. */ - arch_leave_lazy_cpu_mode(); + arch_end_context_switch(next_p); /* * Switch FS and GS. @@ -660,15 +658,3 @@ long sys_arch_prctl(int code, unsigned long addr) return do_arch_prctl(current, code, addr); } -unsigned long arch_align_stack(unsigned long sp) -{ - if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space) - sp -= get_random_int() % 8192; - return sp & ~0xf; -} - -unsigned long arch_randomize_brk(struct mm_struct *mm) -{ - unsigned long range_end = mm->brk + 0x02000000; - return randomize_range(mm->brk, range_end, 0) ? : mm->brk; -} diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index 23b7c8f017e2..09ecbde91c13 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -578,17 +579,130 @@ static int ioperm_get(struct task_struct *target, } #ifdef CONFIG_X86_PTRACE_BTS +/* + * A branch trace store context. + * + * Contexts may only be installed by ptrace_bts_config() and only for + * ptraced tasks. + * + * Contexts are destroyed when the tracee is detached from the tracer. + * The actual destruction work requires interrupts enabled, so the + * work is deferred and will be scheduled during __ptrace_unlink(). + * + * Contexts hold an additional task_struct reference on the traced + * task, as well as a reference on the tracer's mm. + * + * Ptrace already holds a task_struct for the duration of ptrace operations, + * but since destruction is deferred, it may be executed after both + * tracer and tracee exited. + */ +struct bts_context { + /* The branch trace handle. */ + struct bts_tracer *tracer; + + /* The buffer used to store the branch trace and its size. */ + void *buffer; + unsigned int size; + + /* The mm that paid for the above buffer. */ + struct mm_struct *mm; + + /* The task this context belongs to. */ + struct task_struct *task; + + /* The signal to send on a bts buffer overflow. */ + unsigned int bts_ovfl_signal; + + /* The work struct to destroy a context. */ + struct work_struct work; +}; + +static int alloc_bts_buffer(struct bts_context *context, unsigned int size) +{ + void *buffer = NULL; + int err = -ENOMEM; + + err = account_locked_memory(current->mm, current->signal->rlim, size); + if (err < 0) + return err; + + buffer = kzalloc(size, GFP_KERNEL); + if (!buffer) + goto out_refund; + + context->buffer = buffer; + context->size = size; + context->mm = get_task_mm(current); + + return 0; + + out_refund: + refund_locked_memory(current->mm, size); + return err; +} + +static inline void free_bts_buffer(struct bts_context *context) +{ + if (!context->buffer) + return; + + kfree(context->buffer); + context->buffer = NULL; + + refund_locked_memory(context->mm, context->size); + context->size = 0; + + mmput(context->mm); + context->mm = NULL; +} + +static void free_bts_context_work(struct work_struct *w) +{ + struct bts_context *context; + + context = container_of(w, struct bts_context, work); + + ds_release_bts(context->tracer); + put_task_struct(context->task); + free_bts_buffer(context); + kfree(context); +} + +static inline void free_bts_context(struct bts_context *context) +{ + INIT_WORK(&context->work, free_bts_context_work); + schedule_work(&context->work); +} + +static inline struct bts_context *alloc_bts_context(struct task_struct *task) +{ + struct bts_context *context = kzalloc(sizeof(*context), GFP_KERNEL); + if (context) { + context->task = task; + task->bts = context; + + get_task_struct(task); + } + + return context; +} + static int ptrace_bts_read_record(struct task_struct *child, size_t index, struct bts_struct __user *out) { + struct bts_context *context; const struct bts_trace *trace; struct bts_struct bts; const unsigned char *at; int error; - trace = ds_read_bts(child->bts); + context = child->bts; + if (!context) + return -ESRCH; + + trace = ds_read_bts(context->tracer); if (!trace) - return -EPERM; + return -ESRCH; at = trace->ds.top - ((index + 1) * trace->ds.size); if ((void *)at < trace->ds.begin) @@ -597,7 +711,7 @@ static int ptrace_bts_read_record(struct task_struct *child, size_t index, if (!trace->read) return -EOPNOTSUPP; - error = trace->read(child->bts, at, &bts); + error = trace->read(context->tracer, at, &bts); if (error < 0) return error; @@ -611,13 +725,18 @@ static int ptrace_bts_drain(struct task_struct *child, long size, struct bts_struct __user *out) { + struct bts_context *context; const struct bts_trace *trace; const unsigned char *at; int error, drained = 0; - trace = ds_read_bts(child->bts); + context = child->bts; + if (!context) + return -ESRCH; + + trace = ds_read_bts(context->tracer); if (!trace) - return -EPERM; + return -ESRCH; if (!trace->read) return -EOPNOTSUPP; @@ -628,9 +747,8 @@ static int ptrace_bts_drain(struct task_struct *child, for (at = trace->ds.begin; (void *)at < trace->ds.top; out++, drained++, at += trace->ds.size) { struct bts_struct bts; - int error; - error = trace->read(child->bts, at, &bts); + error = trace->read(context->tracer, at, &bts); if (error < 0) return error; @@ -640,35 +758,18 @@ static int ptrace_bts_drain(struct task_struct *child, memset(trace->ds.begin, 0, trace->ds.n * trace->ds.size); - error = ds_reset_bts(child->bts); + error = ds_reset_bts(context->tracer); if (error < 0) return error; return drained; } -static int ptrace_bts_allocate_buffer(struct task_struct *child, size_t size) -{ - child->bts_buffer = alloc_locked_buffer(size); - if (!child->bts_buffer) - return -ENOMEM; - - child->bts_size = size; - - return 0; -} - -static void ptrace_bts_free_buffer(struct task_struct *child) -{ - free_locked_buffer(child->bts_buffer, child->bts_size); - child->bts_buffer = NULL; - child->bts_size = 0; -} - static int ptrace_bts_config(struct task_struct *child, long cfg_size, const struct ptrace_bts_config __user *ucfg) { + struct bts_context *context; struct ptrace_bts_config cfg; unsigned int flags = 0; @@ -678,28 +779,33 @@ static int ptrace_bts_config(struct task_struct *child, if (copy_from_user(&cfg, ucfg, sizeof(cfg))) return -EFAULT; - if (child->bts) { - ds_release_bts(child->bts); - child->bts = NULL; - } + context = child->bts; + if (!context) + context = alloc_bts_context(child); + if (!context) + return -ENOMEM; if (cfg.flags & PTRACE_BTS_O_SIGNAL) { if (!cfg.signal) return -EINVAL; - child->thread.bts_ovfl_signal = cfg.signal; return -EOPNOTSUPP; + context->bts_ovfl_signal = cfg.signal; } - if ((cfg.flags & PTRACE_BTS_O_ALLOC) && - (cfg.size != child->bts_size)) { - int error; + ds_release_bts(context->tracer); + context->tracer = NULL; - ptrace_bts_free_buffer(child); + if ((cfg.flags & PTRACE_BTS_O_ALLOC) && (cfg.size != context->size)) { + int err; - error = ptrace_bts_allocate_buffer(child, cfg.size); - if (error < 0) - return error; + free_bts_buffer(context); + if (!cfg.size) + return 0; + + err = alloc_bts_buffer(context, cfg.size); + if (err < 0) + return err; } if (cfg.flags & PTRACE_BTS_O_TRACE) @@ -708,15 +814,14 @@ static int ptrace_bts_config(struct task_struct *child, if (cfg.flags & PTRACE_BTS_O_SCHED) flags |= BTS_TIMESTAMPS; - child->bts = ds_request_bts(child, child->bts_buffer, child->bts_size, - /* ovfl = */ NULL, /* th = */ (size_t)-1, - flags); - if (IS_ERR(child->bts)) { - int error = PTR_ERR(child->bts); - - ptrace_bts_free_buffer(child); - child->bts = NULL; + context->tracer = + ds_request_bts_task(child, context->buffer, context->size, + NULL, (size_t)-1, flags); + if (unlikely(IS_ERR(context->tracer))) { + int error = PTR_ERR(context->tracer); + free_bts_buffer(context); + context->tracer = NULL; return error; } @@ -727,20 +832,25 @@ static int ptrace_bts_status(struct task_struct *child, long cfg_size, struct ptrace_bts_config __user *ucfg) { + struct bts_context *context; const struct bts_trace *trace; struct ptrace_bts_config cfg; + context = child->bts; + if (!context) + return -ESRCH; + if (cfg_size < sizeof(cfg)) return -EIO; - trace = ds_read_bts(child->bts); + trace = ds_read_bts(context->tracer); if (!trace) - return -EPERM; + return -ESRCH; memset(&cfg, 0, sizeof(cfg)); - cfg.size = trace->ds.end - trace->ds.begin; - cfg.signal = child->thread.bts_ovfl_signal; - cfg.bts_size = sizeof(struct bts_struct); + cfg.size = trace->ds.end - trace->ds.begin; + cfg.signal = context->bts_ovfl_signal; + cfg.bts_size = sizeof(struct bts_struct); if (cfg.signal) cfg.flags |= PTRACE_BTS_O_SIGNAL; @@ -759,80 +869,51 @@ static int ptrace_bts_status(struct task_struct *child, static int ptrace_bts_clear(struct task_struct *child) { + struct bts_context *context; const struct bts_trace *trace; - trace = ds_read_bts(child->bts); + context = child->bts; + if (!context) + return -ESRCH; + + trace = ds_read_bts(context->tracer); if (!trace) - return -EPERM; + return -ESRCH; memset(trace->ds.begin, 0, trace->ds.n * trace->ds.size); - return ds_reset_bts(child->bts); + return ds_reset_bts(context->tracer); } static int ptrace_bts_size(struct task_struct *child) { + struct bts_context *context; const struct bts_trace *trace; - trace = ds_read_bts(child->bts); + context = child->bts; + if (!context) + return -ESRCH; + + trace = ds_read_bts(context->tracer); if (!trace) - return -EPERM; + return -ESRCH; return (trace->ds.top - trace->ds.begin) / trace->ds.size; } -static void ptrace_bts_fork(struct task_struct *tsk) -{ - tsk->bts = NULL; - tsk->bts_buffer = NULL; - tsk->bts_size = 0; - tsk->thread.bts_ovfl_signal = 0; -} - -static void ptrace_bts_untrace(struct task_struct *child) +/* + * Called from __ptrace_unlink() after the child has been moved back + * to its original parent. + */ +void ptrace_bts_untrace(struct task_struct *child) { if (unlikely(child->bts)) { - ds_release_bts(child->bts); + free_bts_context(child->bts); child->bts = NULL; - - /* We cannot update total_vm and locked_vm since - child's mm is already gone. But we can reclaim the - memory. */ - kfree(child->bts_buffer); - child->bts_buffer = NULL; - child->bts_size = 0; } } - -static void ptrace_bts_detach(struct task_struct *child) -{ - /* - * Ptrace_detach() races with ptrace_untrace() in case - * the child dies and is reaped by another thread. - * - * We only do the memory accounting at this point and - * leave the buffer deallocation and the bts tracer - * release to ptrace_bts_untrace() which will be called - * later on with tasklist_lock held. - */ - release_locked_buffer(child->bts_buffer, child->bts_size); -} -#else -static inline void ptrace_bts_fork(struct task_struct *tsk) {} -static inline void ptrace_bts_detach(struct task_struct *child) {} -static inline void ptrace_bts_untrace(struct task_struct *child) {} #endif /* CONFIG_X86_PTRACE_BTS */ -void x86_ptrace_fork(struct task_struct *child, unsigned long clone_flags) -{ - ptrace_bts_fork(child); -} - -void x86_ptrace_untrace(struct task_struct *child) -{ - ptrace_bts_untrace(child); -} - /* * Called by kernel/ptrace.c when detaching.. * @@ -844,7 +925,6 @@ void ptrace_disable(struct task_struct *child) #ifdef TIF_SYSCALL_EMU clear_tsk_thread_flag(child, TIF_SYSCALL_EMU); #endif - ptrace_bts_detach(child); } #if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION diff --git a/arch/x86/kernel/quirks.c b/arch/x86/kernel/quirks.c index 7563b31b4f03..af71d06624bf 100644 --- a/arch/x86/kernel/quirks.c +++ b/arch/x86/kernel/quirks.c @@ -491,5 +491,42 @@ void force_hpet_resume(void) break; } } - +#endif + +#if defined(CONFIG_PCI) && defined(CONFIG_NUMA) +/* Set correct numa_node information for AMD NB functions */ +static void __init quirk_amd_nb_node(struct pci_dev *dev) +{ + struct pci_dev *nb_ht; + unsigned int devfn; + u32 val; + + devfn = PCI_DEVFN(PCI_SLOT(dev->devfn), 0); + nb_ht = pci_get_slot(dev->bus, devfn); + if (!nb_ht) + return; + + pci_read_config_dword(nb_ht, 0x60, &val); + set_dev_node(&dev->dev, val & 7); + pci_dev_put(dev); +} + +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB, + quirk_amd_nb_node); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB_ADDRMAP, + quirk_amd_nb_node); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB_MEMCTL, + quirk_amd_nb_node); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB_MISC, + quirk_amd_nb_node); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_10H_NB_HT, + quirk_amd_nb_node); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_10H_NB_MAP, + quirk_amd_nb_node); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_10H_NB_DRAM, + quirk_amd_nb_node); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_10H_NB_MISC, + quirk_amd_nb_node); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_10H_NB_LINK, + quirk_amd_nb_node); #endif diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index 667188e0b5a0..d2d1ce8170f0 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c @@ -192,6 +192,15 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = { DMI_MATCH(DMI_BOARD_NAME, "0KP561"), }, }, + { /* Handle problems with rebooting on Dell Optiplex 360 with 0T656F */ + .callback = set_bios_reboot, + .ident = "Dell OptiPlex 360", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 360"), + DMI_MATCH(DMI_BOARD_NAME, "0T656F"), + }, + }, { /* Handle problems with rebooting on Dell 2400's */ .callback = set_bios_reboot, .ident = "Dell PowerEdge 2400", diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index b4158439bf63..be5ae80f897f 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -112,6 +112,14 @@ #define ARCH_SETUP #endif +/* + * end_pfn only includes RAM, while max_pfn_mapped includes all e820 entries. + * The direct mapping extends to max_pfn_mapped, so that we can directly access + * apertures, ACPI and other tables without having to play with fixmaps. + */ +unsigned long max_low_pfn_mapped; +unsigned long max_pfn_mapped; + RESERVE_BRK(dmi_alloc, 65536); unsigned int boot_cpu_id __read_mostly; @@ -214,8 +222,8 @@ unsigned long mmu_cr4_features; unsigned long mmu_cr4_features = X86_CR4_PAE; #endif -/* Boot loader ID as an integer, for the benefit of proc_dointvec */ -int bootloader_type; +/* Boot loader ID and version as integers, for the benefit of proc_dointvec */ +int bootloader_type, bootloader_version; /* * Setup options @@ -293,15 +301,13 @@ static void __init reserve_brk(void) #ifdef CONFIG_BLK_DEV_INITRD -#ifdef CONFIG_X86_32 - #define MAX_MAP_CHUNK (NR_FIX_BTMAPS << PAGE_SHIFT) static void __init relocate_initrd(void) { u64 ramdisk_image = boot_params.hdr.ramdisk_image; u64 ramdisk_size = boot_params.hdr.ramdisk_size; - u64 end_of_lowmem = max_low_pfn << PAGE_SHIFT; + u64 end_of_lowmem = max_low_pfn_mapped << PAGE_SHIFT; u64 ramdisk_here; unsigned long slop, clen, mapaddr; char *p, *q; @@ -357,14 +363,13 @@ static void __init relocate_initrd(void) ramdisk_image, ramdisk_image + ramdisk_size - 1, ramdisk_here, ramdisk_here + ramdisk_size - 1); } -#endif static void __init reserve_initrd(void) { u64 ramdisk_image = boot_params.hdr.ramdisk_image; u64 ramdisk_size = boot_params.hdr.ramdisk_size; u64 ramdisk_end = ramdisk_image + ramdisk_size; - u64 end_of_lowmem = max_low_pfn << PAGE_SHIFT; + u64 end_of_lowmem = max_low_pfn_mapped << PAGE_SHIFT; if (!boot_params.hdr.type_of_loader || !ramdisk_image || !ramdisk_size) @@ -394,14 +399,8 @@ static void __init reserve_initrd(void) return; } -#ifdef CONFIG_X86_32 relocate_initrd(); -#else - printk(KERN_ERR "initrd extends beyond end of memory " - "(0x%08llx > 0x%08llx)\ndisabling initrd\n", - ramdisk_end, end_of_lowmem); - initrd_start = 0; -#endif + free_early(ramdisk_image, ramdisk_end); } #else @@ -706,6 +705,12 @@ void __init setup_arch(char **cmdline_p) #endif saved_video_mode = boot_params.hdr.vid_mode; bootloader_type = boot_params.hdr.type_of_loader; + if ((bootloader_type >> 4) == 0xe) { + bootloader_type &= 0xf; + bootloader_type |= (boot_params.hdr.ext_loader_type+0x10) << 4; + } + bootloader_version = bootloader_type & 0xf; + bootloader_version |= boot_params.hdr.ext_loader_ver << 4; #ifdef CONFIG_BLK_DEV_RAM rd_image_start = boot_params.hdr.ram_size & RAMDISK_IMAGE_START_MASK; @@ -854,12 +859,16 @@ void __init setup_arch(char **cmdline_p) max_low_pfn = max_pfn; high_memory = (void *)__va(max_pfn * PAGE_SIZE - 1) + 1; + max_pfn_mapped = KERNEL_IMAGE_SIZE >> PAGE_SHIFT; #endif #ifdef CONFIG_X86_CHECK_BIOS_CORRUPTION setup_bios_corruption_check(); #endif + printk(KERN_DEBUG "initial memory mapped : 0 - %08lx\n", + max_pfn_mapped<arch_pre_intr_init) { - if (x86_quirks->arch_pre_intr_init()) - return; - } - init_ISA_irqs(); -} - /** * x86_quirk_intr_init - post gate setup interrupt initialisation * diff --git a/arch/x86/kernel/setup_percpu.c b/arch/x86/kernel/setup_percpu.c index 8f0e13be36b3..9c3f0823e6aa 100644 --- a/arch/x86/kernel/setup_percpu.c +++ b/arch/x86/kernel/setup_percpu.c @@ -425,6 +425,14 @@ void __init setup_per_cpu_areas(void) early_per_cpu_ptr(x86_cpu_to_node_map) = NULL; #endif +#if defined(CONFIG_X86_64) && defined(CONFIG_NUMA) + /* + * make sure boot cpu node_number is right, when boot cpu is on the + * node that doesn't have mem installed + */ + per_cpu(node_number, boot_cpu_id) = cpu_to_node(boot_cpu_id); +#endif + /* Setup node to cpumask map */ setup_node_to_cpumask_map(); diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index 14425166b8e3..4c578751e94e 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c @@ -6,7 +6,6 @@ * 2000-06-20 Pentium III FXSR, SSE support by Gareth Hughes * 2000-2002 x86-64 support by Andi Kleen */ - #include #include #include @@ -25,11 +24,11 @@ #include #include #include +#include #ifdef CONFIG_X86_64 #include #include -#include #endif /* CONFIG_X86_64 */ #include @@ -857,10 +856,10 @@ static void do_signal(struct pt_regs *regs) void do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags) { -#if defined(CONFIG_X86_64) && defined(CONFIG_X86_MCE) +#ifdef CONFIG_X86_NEW_MCE /* notify userspace of pending MCEs */ if (thread_info_flags & _TIF_MCE_NOTIFY) - mce_notify_user(); + mce_notify_process(); #endif /* CONFIG_X86_64 && CONFIG_X86_MCE */ /* deal with pending signal delivery */ diff --git a/arch/x86/kernel/smp.c b/arch/x86/kernel/smp.c index 13f33ea8ccaa..ec1de97600e7 100644 --- a/arch/x86/kernel/smp.c +++ b/arch/x86/kernel/smp.c @@ -150,14 +150,40 @@ void native_send_call_func_ipi(const struct cpumask *mask) * this function calls the 'stop' function on all other CPUs in the system. */ +asmlinkage void smp_reboot_interrupt(void) +{ + ack_APIC_irq(); + irq_enter(); + stop_this_cpu(NULL); + irq_exit(); +} + static void native_smp_send_stop(void) { unsigned long flags; + unsigned long wait; if (reboot_force) return; - smp_call_function(stop_this_cpu, NULL, 0); + /* + * Use an own vector here because smp_call_function + * does lots of things not suitable in a panic situation. + * On most systems we could also use an NMI here, + * but there are a few systems around where NMI + * is problematic so stay with an non NMI for now + * (this implies we cannot stop CPUs spinning with irq off + * currently) + */ + if (num_online_cpus() > 1) { + apic->send_IPI_allbutself(REBOOT_VECTOR); + + /* Don't wait longer than a second */ + wait = USEC_PER_SEC; + while (num_online_cpus() > 1 && wait--) + udelay(1); + } + local_irq_save(flags); disable_local_APIC(); local_irq_restore(flags); @@ -172,6 +198,9 @@ void smp_reschedule_interrupt(struct pt_regs *regs) { ack_APIC_irq(); inc_irq_stat(irq_resched_count); + /* + * KVM uses this interrupt to force a cpu out of guest mode + */ } void smp_call_function_interrupt(struct pt_regs *regs) @@ -193,19 +222,19 @@ void smp_call_function_single_interrupt(struct pt_regs *regs) } struct smp_ops smp_ops = { - .smp_prepare_boot_cpu = native_smp_prepare_boot_cpu, - .smp_prepare_cpus = native_smp_prepare_cpus, - .smp_cpus_done = native_smp_cpus_done, + .smp_prepare_boot_cpu = native_smp_prepare_boot_cpu, + .smp_prepare_cpus = native_smp_prepare_cpus, + .smp_cpus_done = native_smp_cpus_done, - .smp_send_stop = native_smp_send_stop, - .smp_send_reschedule = native_smp_send_reschedule, + .smp_send_stop = native_smp_send_stop, + .smp_send_reschedule = native_smp_send_reschedule, - .cpu_up = native_cpu_up, - .cpu_die = native_cpu_die, - .cpu_disable = native_cpu_disable, - .play_dead = native_play_dead, + .cpu_up = native_cpu_up, + .cpu_die = native_cpu_die, + .cpu_disable = native_cpu_disable, + .play_dead = native_play_dead, - .send_call_func_ipi = native_send_call_func_ipi, + .send_call_func_ipi = native_send_call_func_ipi, .send_call_func_single_ipi = native_send_call_func_single_ipi, }; EXPORT_SYMBOL_GPL(smp_ops); diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index 58d24ef917d8..2fecda69ee64 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -504,7 +504,7 @@ void __inquire_remote_apic(int apicid) * INIT, INIT, STARTUP sequence will reset the chip hard for us, and this * won't ... remember to clear down the APIC, etc later. */ -int __devinit +int __cpuinit wakeup_secondary_cpu_via_nmi(int logical_apicid, unsigned long start_eip) { unsigned long send_status, accept_status = 0; @@ -538,7 +538,7 @@ wakeup_secondary_cpu_via_nmi(int logical_apicid, unsigned long start_eip) return (send_status | accept_status); } -int __devinit +static int __cpuinit wakeup_secondary_cpu_via_init(int phys_apicid, unsigned long start_eip) { unsigned long send_status, accept_status = 0; @@ -822,10 +822,12 @@ do_rest: /* mark "stuck" area as not stuck */ *((volatile unsigned long *)trampoline_base) = 0; - /* - * Cleanup possible dangling ends... - */ - smpboot_restore_warm_reset_vector(); + if (get_uv_system_type() != UV_NON_UNIQUE_APIC) { + /* + * Cleanup possible dangling ends... + */ + smpboot_restore_warm_reset_vector(); + } return boot_error; } @@ -871,7 +873,7 @@ int __cpuinit native_cpu_up(unsigned int cpu) err = do_boot_cpu(apicid, cpu); - zap_low_mappings(); + zap_low_mappings(false); low_mappings = 0; #else err = do_boot_cpu(apicid, cpu); @@ -990,10 +992,12 @@ static int __init smp_sanity_check(unsigned max_cpus) */ if (APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid]) && !cpu_has_apic) { - printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n", - boot_cpu_physical_apicid); - printk(KERN_ERR "... forcing use of dummy APIC emulation." + if (!disable_apic) { + pr_err("BIOS bug, local APIC #%d not detected!...\n", + boot_cpu_physical_apicid); + pr_err("... forcing use of dummy APIC emulation." "(tell your hw vendor)\n"); + } smpboot_clear_io_apic(); arch_disable_smp_support(); return -1; diff --git a/arch/x86/kernel/stacktrace.c b/arch/x86/kernel/stacktrace.c index f7bddc2e37d1..c3eb207181fe 100644 --- a/arch/x86/kernel/stacktrace.c +++ b/arch/x86/kernel/stacktrace.c @@ -20,7 +20,7 @@ save_stack_warning_symbol(void *data, char *msg, unsigned long symbol) static int save_stack_stack(void *data, char *name) { - return -1; + return 0; } static void save_stack_address(void *data, unsigned long addr, int reliable) @@ -77,6 +77,13 @@ void save_stack_trace(struct stack_trace *trace) } EXPORT_SYMBOL_GPL(save_stack_trace); +void save_stack_trace_bp(struct stack_trace *trace, unsigned long bp) +{ + dump_trace(current, NULL, NULL, bp, &save_stack_ops, trace); + if (trace->nr_entries < trace->max_entries) + trace->entries[trace->nr_entries++] = ULONG_MAX; +} + void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) { dump_trace(tsk, NULL, NULL, 0, &save_stack_ops_nosched, trace); diff --git a/arch/x86/kernel/syscall_table_32.S b/arch/x86/kernel/syscall_table_32.S index ff5c8736b491..d51321ddafda 100644 --- a/arch/x86/kernel/syscall_table_32.S +++ b/arch/x86/kernel/syscall_table_32.S @@ -334,3 +334,5 @@ ENTRY(sys_call_table) .long sys_inotify_init1 .long sys_preadv .long sys_pwritev + .long sys_rt_tgsigqueueinfo /* 335 */ + .long sys_perf_counter_open diff --git a/arch/x86/kernel/tlb_uv.c b/arch/x86/kernel/tlb_uv.c index 8c7b03b0cfcb..124d40c575df 100644 --- a/arch/x86/kernel/tlb_uv.c +++ b/arch/x86/kernel/tlb_uv.c @@ -715,7 +715,12 @@ uv_activation_descriptor_init(int node, int pnode) struct bau_desc *adp; struct bau_desc *ad2; - adp = (struct bau_desc *)kmalloc_node(16384, GFP_KERNEL, node); + /* + * each bau_desc is 64 bytes; there are 8 (UV_ITEMS_PER_DESCRIPTOR) + * per cpu; and up to 32 (UV_ADP_SIZE) cpu's per blade + */ + adp = (struct bau_desc *)kmalloc_node(sizeof(struct bau_desc)* + UV_ADP_SIZE*UV_ITEMS_PER_DESCRIPTOR, GFP_KERNEL, node); BUG_ON(!adp); pa = uv_gpa(adp); /* need the real nasid*/ @@ -729,7 +734,13 @@ uv_activation_descriptor_init(int node, int pnode) (n << UV_DESC_BASE_PNODE_SHIFT | m)); } - for (i = 0, ad2 = adp; i < UV_ACTIVATION_DESCRIPTOR_SIZE; i++, ad2++) { + /* + * initializing all 8 (UV_ITEMS_PER_DESCRIPTOR) descriptors for each + * cpu even though we only use the first one; one descriptor can + * describe a broadcast to 256 nodes. + */ + for (i = 0, ad2 = adp; i < (UV_ADP_SIZE*UV_ITEMS_PER_DESCRIPTOR); + i++, ad2++) { memset(ad2, 0, sizeof(struct bau_desc)); ad2->header.sw_ack_flag = 1; /* diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index a1d288327ff0..a0f48f5671c0 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -45,6 +45,7 @@ #include #endif +#include #include #include #include @@ -53,6 +54,7 @@ #include #include #include +#include #include @@ -64,8 +66,6 @@ #include #include -#include "cpu/mcheck/mce.h" - asmlinkage int system_call(void); /* Do we ignore FPU interrupts ? */ @@ -534,6 +534,10 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code) get_debugreg(condition, 6); + /* Catch kmemcheck conditions first of all! */ + if (condition & DR_STEP && kmemcheck_trap(regs)) + return; + /* * The processor cleared BTF, so don't mark that we need it set. */ @@ -798,15 +802,15 @@ unsigned long patch_espfix_desc(unsigned long uesp, unsigned long kesp) return new_kesp; } -#else +#endif + asmlinkage void __attribute__((weak)) smp_thermal_interrupt(void) { } -asmlinkage void __attribute__((weak)) mce_threshold_interrupt(void) +asmlinkage void __attribute__((weak)) smp_threshold_interrupt(void) { } -#endif /* * 'math_state_restore()' saves the current math information in the @@ -839,9 +843,6 @@ asmlinkage void math_state_restore(void) } clts(); /* Allow maths ops (or we recurse) */ -#ifdef CONFIG_X86_32 - restore_fpu(tsk); -#else /* * Paranoid restore. send a SIGSEGV if we fail to restore the state. */ @@ -850,7 +851,7 @@ asmlinkage void math_state_restore(void) force_sig(SIGSEGV, tsk); return; } -#endif + thread->status |= TS_USEDFPU; /* So we fnsave on switch_to() */ tsk->fpu_counter++; } @@ -945,8 +946,13 @@ void __init trap_init(void) #endif set_intr_gate(19, &simd_coprocessor_error); + /* Reserve all the builtin and the syscall vector: */ + for (i = 0; i < FIRST_EXTERNAL_VECTOR; i++) + set_bit(i, used_vectors); + #ifdef CONFIG_IA32_EMULATION set_system_intr_gate(IA32_SYSCALL_VECTOR, ia32_syscall); + set_bit(IA32_SYSCALL_VECTOR, used_vectors); #endif #ifdef CONFIG_X86_32 @@ -963,17 +969,9 @@ void __init trap_init(void) } set_system_trap_gate(SYSCALL_VECTOR, &system_call); -#endif - - /* Reserve all the builtin and the syscall vector: */ - for (i = 0; i < FIRST_EXTERNAL_VECTOR; i++) - set_bit(i, used_vectors); - -#ifdef CONFIG_X86_64 - set_bit(IA32_SYSCALL_VECTOR, used_vectors); -#else set_bit(SYSCALL_VECTOR, used_vectors); #endif + /* * Should be a barrier for any external CPU state: */ diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index d57de05dc430..6e1a368d21d4 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -384,13 +385,13 @@ unsigned long native_calibrate_tsc(void) { u64 tsc1, tsc2, delta, ref1, ref2; unsigned long tsc_pit_min = ULONG_MAX, tsc_ref_min = ULONG_MAX; - unsigned long flags, latch, ms, fast_calibrate, tsc_khz; + unsigned long flags, latch, ms, fast_calibrate, hv_tsc_khz; int hpet = is_hpet_enabled(), i, loopmin; - tsc_khz = get_hypervisor_tsc_freq(); - if (tsc_khz) { + hv_tsc_khz = get_hypervisor_tsc_freq(); + if (hv_tsc_khz) { printk(KERN_INFO "TSC: Frequency read from the hypervisor\n"); - return tsc_khz; + return hv_tsc_khz; } local_irq_save(flags); @@ -589,22 +590,26 @@ EXPORT_SYMBOL(recalibrate_cpu_khz); */ DEFINE_PER_CPU(unsigned long, cyc2ns); +DEFINE_PER_CPU(unsigned long long, cyc2ns_offset); static void set_cyc2ns_scale(unsigned long cpu_khz, int cpu) { - unsigned long long tsc_now, ns_now; + unsigned long long tsc_now, ns_now, *offset; unsigned long flags, *scale; local_irq_save(flags); sched_clock_idle_sleep_event(); scale = &per_cpu(cyc2ns, cpu); + offset = &per_cpu(cyc2ns_offset, cpu); rdtscll(tsc_now); ns_now = __cycles_2_ns(tsc_now); - if (cpu_khz) + if (cpu_khz) { *scale = (NSEC_PER_MSEC << CYC2NS_SCALE_FACTOR)/cpu_khz; + *offset = ns_now - (tsc_now * *scale >> CYC2NS_SCALE_FACTOR); + } sched_clock_idle_wakeup_event(0); local_irq_restore(flags); @@ -631,17 +636,15 @@ static int time_cpufreq_notifier(struct notifier_block *nb, unsigned long val, void *data) { struct cpufreq_freqs *freq = data; - unsigned long *lpj, dummy; + unsigned long *lpj; if (cpu_has(&cpu_data(freq->cpu), X86_FEATURE_CONSTANT_TSC)) return 0; - lpj = &dummy; - if (!(freq->flags & CPUFREQ_CONST_LOOPS)) -#ifdef CONFIG_SMP - lpj = &cpu_data(freq->cpu).loops_per_jiffy; -#else lpj = &boot_cpu_data.loops_per_jiffy; +#ifdef CONFIG_SMP + if (!(freq->flags & CPUFREQ_CONST_LOOPS)) + lpj = &cpu_data(freq->cpu).loops_per_jiffy; #endif if (!ref_freq) { @@ -710,7 +713,16 @@ static cycle_t read_tsc(struct clocksource *cs) #ifdef CONFIG_X86_64 static cycle_t __vsyscall_fn vread_tsc(void) { - cycle_t ret = (cycle_t)vget_cycles(); + cycle_t ret; + + /* + * Surround the RDTSC by barriers, to make sure it's not + * speculated to outside the seqlock critical section and + * does not cause time warps: + */ + rdtsc_barrier(); + ret = (cycle_t)vget_cycles(); + rdtsc_barrier(); return ret >= __vsyscall_gtod_data.clock.cycle_last ? ret : __vsyscall_gtod_data.clock.cycle_last; diff --git a/arch/x86/kernel/tsc_sync.c b/arch/x86/kernel/tsc_sync.c index bf36328f6ef9..027b5b498993 100644 --- a/arch/x86/kernel/tsc_sync.c +++ b/arch/x86/kernel/tsc_sync.c @@ -34,6 +34,7 @@ static __cpuinitdata atomic_t stop_count; * of a critical section, to be able to prove TSC time-warps: */ static __cpuinitdata raw_spinlock_t sync_lock = __RAW_SPIN_LOCK_UNLOCKED; + static __cpuinitdata cycles_t last_tsc; static __cpuinitdata cycles_t max_warp; static __cpuinitdata int nr_warps; @@ -113,13 +114,12 @@ void __cpuinit check_tsc_sync_source(int cpu) return; if (boot_cpu_has(X86_FEATURE_TSC_RELIABLE)) { - printk(KERN_INFO - "Skipping synchronization checks as TSC is reliable.\n"); + pr_info("Skipping synchronization checks as TSC is reliable.\n"); return; } - printk(KERN_INFO "checking TSC synchronization [CPU#%d -> CPU#%d]:", - smp_processor_id(), cpu); + pr_info("checking TSC synchronization [CPU#%d -> CPU#%d]:", + smp_processor_id(), cpu); /* * Reset it - in case this is a second bootup: @@ -143,8 +143,8 @@ void __cpuinit check_tsc_sync_source(int cpu) if (nr_warps) { printk("\n"); - printk(KERN_WARNING "Measured %Ld cycles TSC warp between CPUs," - " turning off TSC clock.\n", max_warp); + pr_warning("Measured %Ld cycles TSC warp between CPUs, " + "turning off TSC clock.\n", max_warp); mark_tsc_unstable("check_tsc_sync_source failed"); } else { printk(" passed.\n"); @@ -195,5 +195,3 @@ void __cpuinit check_tsc_sync_target(void) while (atomic_read(&stop_count) != cpus) cpu_relax(); } -#undef NR_LOOPS - diff --git a/arch/x86/kernel/vm86_32.c b/arch/x86/kernel/vm86_32.c index d7ac84e7fc1c..9c4e62539058 100644 --- a/arch/x86/kernel/vm86_32.c +++ b/arch/x86/kernel/vm86_32.c @@ -287,10 +287,9 @@ static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk info->regs.pt.ds = 0; info->regs.pt.es = 0; info->regs.pt.fs = 0; - -/* we are clearing gs later just before "jmp resume_userspace", - * because it is not saved/restored. - */ +#ifndef CONFIG_X86_32_LAZY_GS + info->regs.pt.gs = 0; +#endif /* * The flags register is also special: we cannot trust that the user @@ -318,9 +317,9 @@ static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk } /* - * Save old state, set default return value (%ax) to 0 + * Save old state, set default return value (%ax) to 0 (VM86_SIGNAL) */ - info->regs32->ax = 0; + info->regs32->ax = VM86_SIGNAL; tsk->thread.saved_sp0 = tsk->thread.sp0; tsk->thread.saved_fs = info->regs32->fs; tsk->thread.saved_gs = get_user_gs(info->regs32); @@ -343,7 +342,9 @@ static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk __asm__ __volatile__( "movl %0,%%esp\n\t" "movl %1,%%ebp\n\t" +#ifdef CONFIG_X86_32_LAZY_GS "mov %2, %%gs\n\t" +#endif "jmp resume_userspace" : /* no outputs */ :"r" (&info->regs), "r" (task_thread_info(tsk)), "r" (0)); diff --git a/arch/x86/kernel/vmi_32.c b/arch/x86/kernel/vmi_32.c index 95deb9f2211e..b263423fbe2a 100644 --- a/arch/x86/kernel/vmi_32.c +++ b/arch/x86/kernel/vmi_32.c @@ -462,22 +462,28 @@ vmi_startup_ipi_hook(int phys_apicid, unsigned long start_eip, } #endif -static void vmi_enter_lazy_cpu(void) +static void vmi_start_context_switch(struct task_struct *prev) { - paravirt_enter_lazy_cpu(); + paravirt_start_context_switch(prev); vmi_ops.set_lazy_mode(2); } +static void vmi_end_context_switch(struct task_struct *next) +{ + vmi_ops.set_lazy_mode(0); + paravirt_end_context_switch(next); +} + static void vmi_enter_lazy_mmu(void) { paravirt_enter_lazy_mmu(); vmi_ops.set_lazy_mode(1); } -static void vmi_leave_lazy(void) +static void vmi_leave_lazy_mmu(void) { - paravirt_leave_lazy(paravirt_get_lazy_mode()); vmi_ops.set_lazy_mode(0); + paravirt_leave_lazy_mmu(); } static inline int __init check_vmi_rom(struct vrom_header *rom) @@ -711,14 +717,14 @@ static inline int __init activate_vmi(void) para_fill(pv_cpu_ops.set_iopl_mask, SetIOPLMask); para_fill(pv_cpu_ops.io_delay, IODelay); - para_wrap(pv_cpu_ops.lazy_mode.enter, vmi_enter_lazy_cpu, + para_wrap(pv_cpu_ops.start_context_switch, vmi_start_context_switch, set_lazy_mode, SetLazyMode); - para_wrap(pv_cpu_ops.lazy_mode.leave, vmi_leave_lazy, + para_wrap(pv_cpu_ops.end_context_switch, vmi_end_context_switch, set_lazy_mode, SetLazyMode); para_wrap(pv_mmu_ops.lazy_mode.enter, vmi_enter_lazy_mmu, set_lazy_mode, SetLazyMode); - para_wrap(pv_mmu_ops.lazy_mode.leave, vmi_leave_lazy, + para_wrap(pv_mmu_ops.lazy_mode.leave, vmi_leave_lazy_mmu, set_lazy_mode, SetLazyMode); /* user and kernel flush are just handled with different flags to FlushTLB */ diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S index 849ee611f013..367e87882041 100644 --- a/arch/x86/kernel/vmlinux.lds.S +++ b/arch/x86/kernel/vmlinux.lds.S @@ -1,5 +1,433 @@ +/* + * ld script for the x86 kernel + * + * Historic 32-bit version written by Martin Mares + * + * Modernisation, unification and other changes and fixes: + * Copyright (C) 2007-2009 Sam Ravnborg + * + * + * Don't define absolute symbols until and unless you know that symbol + * value is should remain constant even if kernel image is relocated + * at run time. Absolute symbols are not relocated. If symbol value should + * change if kernel is relocated, make the symbol section relative and + * put it inside the section definition. + */ + #ifdef CONFIG_X86_32 -# include "vmlinux_32.lds.S" +#define LOAD_OFFSET __PAGE_OFFSET #else -# include "vmlinux_64.lds.S" +#define LOAD_OFFSET __START_KERNEL_map #endif + +#include +#include +#include +#include +#include +#include + +#undef i386 /* in case the preprocessor is a 32bit one */ + +OUTPUT_FORMAT(CONFIG_OUTPUT_FORMAT, CONFIG_OUTPUT_FORMAT, CONFIG_OUTPUT_FORMAT) + +#ifdef CONFIG_X86_32 +OUTPUT_ARCH(i386) +ENTRY(phys_startup_32) +jiffies = jiffies_64; +#else +OUTPUT_ARCH(i386:x86-64) +ENTRY(phys_startup_64) +jiffies_64 = jiffies; +#endif + +PHDRS { + text PT_LOAD FLAGS(5); /* R_E */ + data PT_LOAD FLAGS(7); /* RWE */ +#ifdef CONFIG_X86_64 + user PT_LOAD FLAGS(7); /* RWE */ + data.init PT_LOAD FLAGS(7); /* RWE */ +#ifdef CONFIG_SMP + percpu PT_LOAD FLAGS(7); /* RWE */ +#endif + data.init2 PT_LOAD FLAGS(7); /* RWE */ +#endif + note PT_NOTE FLAGS(0); /* ___ */ +} + +SECTIONS +{ +#ifdef CONFIG_X86_32 + . = LOAD_OFFSET + LOAD_PHYSICAL_ADDR; + phys_startup_32 = startup_32 - LOAD_OFFSET; +#else + . = __START_KERNEL; + phys_startup_64 = startup_64 - LOAD_OFFSET; +#endif + + /* Text and read-only data */ + + /* bootstrapping code */ + .text.head : AT(ADDR(.text.head) - LOAD_OFFSET) { + _text = .; + *(.text.head) + } :text = 0x9090 + + /* The rest of the text */ + .text : AT(ADDR(.text) - LOAD_OFFSET) { +#ifdef CONFIG_X86_32 + /* not really needed, already page aligned */ + . = ALIGN(PAGE_SIZE); + *(.text.page_aligned) +#endif + . = ALIGN(8); + _stext = .; + TEXT_TEXT + SCHED_TEXT + LOCK_TEXT + KPROBES_TEXT + IRQENTRY_TEXT + *(.fixup) + *(.gnu.warning) + /* End of text section */ + _etext = .; + } :text = 0x9090 + + NOTES :text :note + + /* Exception table */ + . = ALIGN(16); + __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { + __start___ex_table = .; + *(__ex_table) + __stop___ex_table = .; + } :text = 0x9090 + + RODATA + + /* Data */ + . = ALIGN(PAGE_SIZE); + .data : AT(ADDR(.data) - LOAD_OFFSET) { + /* Start of data section */ + _sdata = .; + DATA_DATA + CONSTRUCTORS + +#ifdef CONFIG_X86_64 + /* End of data section */ + _edata = .; +#endif + } :data + +#ifdef CONFIG_X86_32 + /* 32 bit has nosave before _edata */ + . = ALIGN(PAGE_SIZE); + .data_nosave : AT(ADDR(.data_nosave) - LOAD_OFFSET) { + __nosave_begin = .; + *(.data.nosave) + . = ALIGN(PAGE_SIZE); + __nosave_end = .; + } +#endif + + . = ALIGN(PAGE_SIZE); + .data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET) { + *(.data.page_aligned) + *(.data.idt) + } + +#ifdef CONFIG_X86_32 + . = ALIGN(32); +#else + . = ALIGN(PAGE_SIZE); + . = ALIGN(CONFIG_X86_L1_CACHE_BYTES); +#endif + .data.cacheline_aligned : + AT(ADDR(.data.cacheline_aligned) - LOAD_OFFSET) { + *(.data.cacheline_aligned) + } + + /* rarely changed data like cpu maps */ +#ifdef CONFIG_X86_32 + . = ALIGN(32); +#else + . = ALIGN(CONFIG_X86_INTERNODE_CACHE_BYTES); +#endif + .data.read_mostly : AT(ADDR(.data.read_mostly) - LOAD_OFFSET) { + *(.data.read_mostly) + +#ifdef CONFIG_X86_32 + /* End of data section */ + _edata = .; +#endif + } + +#ifdef CONFIG_X86_64 + +#define VSYSCALL_ADDR (-10*1024*1024) +#define VSYSCALL_PHYS_ADDR ((LOADADDR(.data.read_mostly) + \ + SIZEOF(.data.read_mostly) + 4095) & ~(4095)) +#define VSYSCALL_VIRT_ADDR ((ADDR(.data.read_mostly) + \ + SIZEOF(.data.read_mostly) + 4095) & ~(4095)) + +#define VLOAD_OFFSET (VSYSCALL_ADDR - VSYSCALL_PHYS_ADDR) +#define VLOAD(x) (ADDR(x) - VLOAD_OFFSET) + +#define VVIRT_OFFSET (VSYSCALL_ADDR - VSYSCALL_VIRT_ADDR) +#define VVIRT(x) (ADDR(x) - VVIRT_OFFSET) + + . = VSYSCALL_ADDR; + .vsyscall_0 : AT(VSYSCALL_PHYS_ADDR) { + *(.vsyscall_0) + } :user + + __vsyscall_0 = VSYSCALL_VIRT_ADDR; + + . = ALIGN(CONFIG_X86_L1_CACHE_BYTES); + .vsyscall_fn : AT(VLOAD(.vsyscall_fn)) { + *(.vsyscall_fn) + } + + . = ALIGN(CONFIG_X86_L1_CACHE_BYTES); + .vsyscall_gtod_data : AT(VLOAD(.vsyscall_gtod_data)) { + *(.vsyscall_gtod_data) + } + + vsyscall_gtod_data = VVIRT(.vsyscall_gtod_data); + .vsyscall_clock : AT(VLOAD(.vsyscall_clock)) { + *(.vsyscall_clock) + } + vsyscall_clock = VVIRT(.vsyscall_clock); + + + .vsyscall_1 ADDR(.vsyscall_0) + 1024: AT(VLOAD(.vsyscall_1)) { + *(.vsyscall_1) + } + .vsyscall_2 ADDR(.vsyscall_0) + 2048: AT(VLOAD(.vsyscall_2)) { + *(.vsyscall_2) + } + + .vgetcpu_mode : AT(VLOAD(.vgetcpu_mode)) { + *(.vgetcpu_mode) + } + vgetcpu_mode = VVIRT(.vgetcpu_mode); + + . = ALIGN(CONFIG_X86_L1_CACHE_BYTES); + .jiffies : AT(VLOAD(.jiffies)) { + *(.jiffies) + } + jiffies = VVIRT(.jiffies); + + .vsyscall_3 ADDR(.vsyscall_0) + 3072: AT(VLOAD(.vsyscall_3)) { + *(.vsyscall_3) + } + + . = VSYSCALL_VIRT_ADDR + PAGE_SIZE; + +#undef VSYSCALL_ADDR +#undef VSYSCALL_PHYS_ADDR +#undef VSYSCALL_VIRT_ADDR +#undef VLOAD_OFFSET +#undef VLOAD +#undef VVIRT_OFFSET +#undef VVIRT + +#endif /* CONFIG_X86_64 */ + + /* init_task */ + . = ALIGN(THREAD_SIZE); + .data.init_task : AT(ADDR(.data.init_task) - LOAD_OFFSET) { + *(.data.init_task) + } +#ifdef CONFIG_X86_64 + :data.init +#endif + + /* + * smp_locks might be freed after init + * start/end must be page aligned + */ + . = ALIGN(PAGE_SIZE); + .smp_locks : AT(ADDR(.smp_locks) - LOAD_OFFSET) { + __smp_locks = .; + *(.smp_locks) + __smp_locks_end = .; + . = ALIGN(PAGE_SIZE); + } + + /* Init code and data - will be freed after init */ + . = ALIGN(PAGE_SIZE); + .init.text : AT(ADDR(.init.text) - LOAD_OFFSET) { + __init_begin = .; /* paired with __init_end */ + _sinittext = .; + INIT_TEXT + _einittext = .; + } + + .init.data : AT(ADDR(.init.data) - LOAD_OFFSET) { + INIT_DATA + } + + . = ALIGN(16); + .init.setup : AT(ADDR(.init.setup) - LOAD_OFFSET) { + __setup_start = .; + *(.init.setup) + __setup_end = .; + } + .initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) { + __initcall_start = .; + INITCALLS + __initcall_end = .; + } + + .con_initcall.init : AT(ADDR(.con_initcall.init) - LOAD_OFFSET) { + __con_initcall_start = .; + *(.con_initcall.init) + __con_initcall_end = .; + } + + .x86_cpu_dev.init : AT(ADDR(.x86_cpu_dev.init) - LOAD_OFFSET) { + __x86_cpu_dev_start = .; + *(.x86_cpu_dev.init) + __x86_cpu_dev_end = .; + } + + SECURITY_INIT + + . = ALIGN(8); + .parainstructions : AT(ADDR(.parainstructions) - LOAD_OFFSET) { + __parainstructions = .; + *(.parainstructions) + __parainstructions_end = .; + } + + . = ALIGN(8); + .altinstructions : AT(ADDR(.altinstructions) - LOAD_OFFSET) { + __alt_instructions = .; + *(.altinstructions) + __alt_instructions_end = .; + } + + .altinstr_replacement : AT(ADDR(.altinstr_replacement) - LOAD_OFFSET) { + *(.altinstr_replacement) + } + + /* + * .exit.text is discard at runtime, not link time, to deal with + * references from .altinstructions and .eh_frame + */ + .exit.text : AT(ADDR(.exit.text) - LOAD_OFFSET) { + EXIT_TEXT + } + + .exit.data : AT(ADDR(.exit.data) - LOAD_OFFSET) { + EXIT_DATA + } + +#ifdef CONFIG_BLK_DEV_INITRD + . = ALIGN(PAGE_SIZE); + .init.ramfs : AT(ADDR(.init.ramfs) - LOAD_OFFSET) { + __initramfs_start = .; + *(.init.ramfs) + __initramfs_end = .; + } +#endif + +#if defined(CONFIG_X86_64) && defined(CONFIG_SMP) + /* + * percpu offsets are zero-based on SMP. PERCPU_VADDR() changes the + * output PHDR, so the next output section - __data_nosave - should + * start another section data.init2. Also, pda should be at the head of + * percpu area. Preallocate it and define the percpu offset symbol + * so that it can be accessed as a percpu variable. + */ + . = ALIGN(PAGE_SIZE); + PERCPU_VADDR(0, :percpu) +#else + PERCPU(PAGE_SIZE) +#endif + + . = ALIGN(PAGE_SIZE); + + /* freed after init ends here */ + .init.end : AT(ADDR(.init.end) - LOAD_OFFSET) { + __init_end = .; + } + +#ifdef CONFIG_X86_64 + .data_nosave : AT(ADDR(.data_nosave) - LOAD_OFFSET) { + . = ALIGN(PAGE_SIZE); + __nosave_begin = .; + *(.data.nosave) + . = ALIGN(PAGE_SIZE); + __nosave_end = .; + } :data.init2 + /* use another section data.init2, see PERCPU_VADDR() above */ +#endif + + /* BSS */ + . = ALIGN(PAGE_SIZE); + .bss : AT(ADDR(.bss) - LOAD_OFFSET) { + __bss_start = .; + *(.bss.page_aligned) + *(.bss) + . = ALIGN(4); + __bss_stop = .; + } + + . = ALIGN(PAGE_SIZE); + .brk : AT(ADDR(.brk) - LOAD_OFFSET) { + __brk_base = .; + . += 64 * 1024; /* 64k alignment slop space */ + *(.brk_reservation) /* areas brk users have reserved */ + __brk_limit = .; + } + + .end : AT(ADDR(.end) - LOAD_OFFSET) { + _end = .; + } + + /* Sections to be discarded */ + /DISCARD/ : { + *(.exitcall.exit) + *(.eh_frame) + *(.discard) + } + + STABS_DEBUG + DWARF_DEBUG +} + + +#ifdef CONFIG_X86_32 +ASSERT((_end - LOAD_OFFSET <= KERNEL_IMAGE_SIZE), + "kernel image bigger than KERNEL_IMAGE_SIZE") +#else +/* + * Per-cpu symbols which need to be offset from __per_cpu_load + * for the boot processor. + */ +#define INIT_PER_CPU(x) init_per_cpu__##x = per_cpu__##x + __per_cpu_load +INIT_PER_CPU(gdt_page); +INIT_PER_CPU(irq_stack_union); + +/* + * Build-time check on the image size: + */ +ASSERT((_end - _text <= KERNEL_IMAGE_SIZE), + "kernel image bigger than KERNEL_IMAGE_SIZE") + +#ifdef CONFIG_SMP +ASSERT((per_cpu__irq_stack_union == 0), + "irq_stack_union is not at start of per-cpu area"); +#endif + +#endif /* CONFIG_X86_32 */ + +#ifdef CONFIG_KEXEC +#include + +ASSERT(kexec_control_code_size <= KEXEC_CONTROL_CODE_MAX_SIZE, + "kexec control code size is too big") +#endif + diff --git a/arch/x86/kernel/vmlinux_32.lds.S b/arch/x86/kernel/vmlinux_32.lds.S deleted file mode 100644 index 62ad500d55f3..000000000000 --- a/arch/x86/kernel/vmlinux_32.lds.S +++ /dev/null @@ -1,229 +0,0 @@ -/* ld script to make i386 Linux kernel - * Written by Martin Mares ; - * - * Don't define absolute symbols until and unless you know that symbol - * value is should remain constant even if kernel image is relocated - * at run time. Absolute symbols are not relocated. If symbol value should - * change if kernel is relocated, make the symbol section relative and - * put it inside the section definition. - */ - -#define LOAD_OFFSET __PAGE_OFFSET - -#include -#include -#include -#include -#include - -OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") -OUTPUT_ARCH(i386) -ENTRY(phys_startup_32) -jiffies = jiffies_64; - -PHDRS { - text PT_LOAD FLAGS(5); /* R_E */ - data PT_LOAD FLAGS(7); /* RWE */ - note PT_NOTE FLAGS(0); /* ___ */ -} -SECTIONS -{ - . = LOAD_OFFSET + LOAD_PHYSICAL_ADDR; - phys_startup_32 = startup_32 - LOAD_OFFSET; - - .text.head : AT(ADDR(.text.head) - LOAD_OFFSET) { - _text = .; /* Text and read-only data */ - *(.text.head) - } :text = 0x9090 - - /* read-only */ - .text : AT(ADDR(.text) - LOAD_OFFSET) { - . = ALIGN(PAGE_SIZE); /* not really needed, already page aligned */ - *(.text.page_aligned) - TEXT_TEXT - SCHED_TEXT - LOCK_TEXT - KPROBES_TEXT - IRQENTRY_TEXT - *(.fixup) - *(.gnu.warning) - _etext = .; /* End of text section */ - } :text = 0x9090 - - NOTES :text :note - - . = ALIGN(16); /* Exception table */ - __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { - __start___ex_table = .; - *(__ex_table) - __stop___ex_table = .; - } :text = 0x9090 - - RODATA - - /* writeable */ - . = ALIGN(PAGE_SIZE); - .data : AT(ADDR(.data) - LOAD_OFFSET) { /* Data */ - DATA_DATA - CONSTRUCTORS - } :data - - . = ALIGN(PAGE_SIZE); - .data_nosave : AT(ADDR(.data_nosave) - LOAD_OFFSET) { - __nosave_begin = .; - *(.data.nosave) - . = ALIGN(PAGE_SIZE); - __nosave_end = .; - } - - . = ALIGN(PAGE_SIZE); - .data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET) { - *(.data.page_aligned) - *(.data.idt) - } - - . = ALIGN(32); - .data.cacheline_aligned : AT(ADDR(.data.cacheline_aligned) - LOAD_OFFSET) { - *(.data.cacheline_aligned) - } - - /* rarely changed data like cpu maps */ - . = ALIGN(32); - .data.read_mostly : AT(ADDR(.data.read_mostly) - LOAD_OFFSET) { - *(.data.read_mostly) - _edata = .; /* End of data section */ - } - - . = ALIGN(THREAD_SIZE); /* init_task */ - .data.init_task : AT(ADDR(.data.init_task) - LOAD_OFFSET) { - *(.data.init_task) - } - - /* might get freed after init */ - . = ALIGN(PAGE_SIZE); - .smp_locks : AT(ADDR(.smp_locks) - LOAD_OFFSET) { - __smp_locks = .; - *(.smp_locks) - __smp_locks_end = .; - } - /* will be freed after init - * Following ALIGN() is required to make sure no other data falls on the - * same page where __smp_alt_end is pointing as that page might be freed - * after boot. Always make sure that ALIGN() directive is present after - * the section which contains __smp_alt_end. - */ - . = ALIGN(PAGE_SIZE); - - /* will be freed after init */ - . = ALIGN(PAGE_SIZE); /* Init code and data */ - .init.text : AT(ADDR(.init.text) - LOAD_OFFSET) { - __init_begin = .; - _sinittext = .; - INIT_TEXT - _einittext = .; - } - .init.data : AT(ADDR(.init.data) - LOAD_OFFSET) { - INIT_DATA - } - . = ALIGN(16); - .init.setup : AT(ADDR(.init.setup) - LOAD_OFFSET) { - __setup_start = .; - *(.init.setup) - __setup_end = .; - } - .initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) { - __initcall_start = .; - INITCALLS - __initcall_end = .; - } - .con_initcall.init : AT(ADDR(.con_initcall.init) - LOAD_OFFSET) { - __con_initcall_start = .; - *(.con_initcall.init) - __con_initcall_end = .; - } - .x86_cpu_dev.init : AT(ADDR(.x86_cpu_dev.init) - LOAD_OFFSET) { - __x86_cpu_dev_start = .; - *(.x86_cpu_dev.init) - __x86_cpu_dev_end = .; - } - SECURITY_INIT - . = ALIGN(4); - .altinstructions : AT(ADDR(.altinstructions) - LOAD_OFFSET) { - __alt_instructions = .; - *(.altinstructions) - __alt_instructions_end = .; - } - .altinstr_replacement : AT(ADDR(.altinstr_replacement) - LOAD_OFFSET) { - *(.altinstr_replacement) - } - . = ALIGN(4); - .parainstructions : AT(ADDR(.parainstructions) - LOAD_OFFSET) { - __parainstructions = .; - *(.parainstructions) - __parainstructions_end = .; - } - /* .exit.text is discard at runtime, not link time, to deal with references - from .altinstructions and .eh_frame */ - .exit.text : AT(ADDR(.exit.text) - LOAD_OFFSET) { - EXIT_TEXT - } - .exit.data : AT(ADDR(.exit.data) - LOAD_OFFSET) { - EXIT_DATA - } -#if defined(CONFIG_BLK_DEV_INITRD) - . = ALIGN(PAGE_SIZE); - .init.ramfs : AT(ADDR(.init.ramfs) - LOAD_OFFSET) { - __initramfs_start = .; - *(.init.ramfs) - __initramfs_end = .; - } -#endif - PERCPU(PAGE_SIZE) - . = ALIGN(PAGE_SIZE); - /* freed after init ends here */ - - .bss : AT(ADDR(.bss) - LOAD_OFFSET) { - __init_end = .; - __bss_start = .; /* BSS */ - *(.bss.page_aligned) - *(.bss) - . = ALIGN(4); - __bss_stop = .; - } - - .brk : AT(ADDR(.brk) - LOAD_OFFSET) { - . = ALIGN(PAGE_SIZE); - __brk_base = . ; - . += 64 * 1024 ; /* 64k alignment slop space */ - *(.brk_reservation) /* areas brk users have reserved */ - __brk_limit = . ; - } - - .end : AT(ADDR(.end) - LOAD_OFFSET) { - _end = . ; - } - - /* Sections to be discarded */ - /DISCARD/ : { - *(.exitcall.exit) - *(.discard) - } - - STABS_DEBUG - - DWARF_DEBUG -} - -/* - * Build-time check on the image size: - */ -ASSERT((_end - LOAD_OFFSET <= KERNEL_IMAGE_SIZE), - "kernel image bigger than KERNEL_IMAGE_SIZE") - -#ifdef CONFIG_KEXEC -/* Link time checks */ -#include - -ASSERT(kexec_control_code_size <= KEXEC_CONTROL_CODE_MAX_SIZE, - "kexec control code size is too big") -#endif diff --git a/arch/x86/kernel/vmlinux_64.lds.S b/arch/x86/kernel/vmlinux_64.lds.S deleted file mode 100644 index c8742507b030..000000000000 --- a/arch/x86/kernel/vmlinux_64.lds.S +++ /dev/null @@ -1,298 +0,0 @@ -/* ld script to make x86-64 Linux kernel - * Written by Martin Mares ; - */ - -#define LOAD_OFFSET __START_KERNEL_map - -#include -#include -#include - -#undef i386 /* in case the preprocessor is a 32bit one */ - -OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") -OUTPUT_ARCH(i386:x86-64) -ENTRY(phys_startup_64) -jiffies_64 = jiffies; -PHDRS { - text PT_LOAD FLAGS(5); /* R_E */ - data PT_LOAD FLAGS(7); /* RWE */ - user PT_LOAD FLAGS(7); /* RWE */ - data.init PT_LOAD FLAGS(7); /* RWE */ -#ifdef CONFIG_SMP - percpu PT_LOAD FLAGS(7); /* RWE */ -#endif - data.init2 PT_LOAD FLAGS(7); /* RWE */ - note PT_NOTE FLAGS(0); /* ___ */ -} -SECTIONS -{ - . = __START_KERNEL; - phys_startup_64 = startup_64 - LOAD_OFFSET; - .text : AT(ADDR(.text) - LOAD_OFFSET) { - _text = .; /* Text and read-only data */ - /* First the code that has to be first for bootstrapping */ - *(.text.head) - _stext = .; - /* Then the rest */ - TEXT_TEXT - SCHED_TEXT - LOCK_TEXT - KPROBES_TEXT - IRQENTRY_TEXT - *(.fixup) - *(.gnu.warning) - _etext = .; /* End of text section */ - } :text = 0x9090 - - NOTES :text :note - - . = ALIGN(16); /* Exception table */ - __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { - __start___ex_table = .; - *(__ex_table) - __stop___ex_table = .; - } :text = 0x9090 - - RODATA - - . = ALIGN(PAGE_SIZE); /* Align data segment to page size boundary */ - /* Data */ - .data : AT(ADDR(.data) - LOAD_OFFSET) { - DATA_DATA - CONSTRUCTORS - _edata = .; /* End of data section */ - } :data - - - .data.cacheline_aligned : AT(ADDR(.data.cacheline_aligned) - LOAD_OFFSET) { - . = ALIGN(PAGE_SIZE); - . = ALIGN(CONFIG_X86_L1_CACHE_BYTES); - *(.data.cacheline_aligned) - } - . = ALIGN(CONFIG_X86_INTERNODE_CACHE_BYTES); - .data.read_mostly : AT(ADDR(.data.read_mostly) - LOAD_OFFSET) { - *(.data.read_mostly) - } - -#define VSYSCALL_ADDR (-10*1024*1024) -#define VSYSCALL_PHYS_ADDR ((LOADADDR(.data.read_mostly) + SIZEOF(.data.read_mostly) + 4095) & ~(4095)) -#define VSYSCALL_VIRT_ADDR ((ADDR(.data.read_mostly) + SIZEOF(.data.read_mostly) + 4095) & ~(4095)) - -#define VLOAD_OFFSET (VSYSCALL_ADDR - VSYSCALL_PHYS_ADDR) -#define VLOAD(x) (ADDR(x) - VLOAD_OFFSET) - -#define VVIRT_OFFSET (VSYSCALL_ADDR - VSYSCALL_VIRT_ADDR) -#define VVIRT(x) (ADDR(x) - VVIRT_OFFSET) - - . = VSYSCALL_ADDR; - .vsyscall_0 : AT(VSYSCALL_PHYS_ADDR) { *(.vsyscall_0) } :user - __vsyscall_0 = VSYSCALL_VIRT_ADDR; - - . = ALIGN(CONFIG_X86_L1_CACHE_BYTES); - .vsyscall_fn : AT(VLOAD(.vsyscall_fn)) { *(.vsyscall_fn) } - . = ALIGN(CONFIG_X86_L1_CACHE_BYTES); - .vsyscall_gtod_data : AT(VLOAD(.vsyscall_gtod_data)) - { *(.vsyscall_gtod_data) } - vsyscall_gtod_data = VVIRT(.vsyscall_gtod_data); - .vsyscall_clock : AT(VLOAD(.vsyscall_clock)) - { *(.vsyscall_clock) } - vsyscall_clock = VVIRT(.vsyscall_clock); - - - .vsyscall_1 ADDR(.vsyscall_0) + 1024: AT(VLOAD(.vsyscall_1)) - { *(.vsyscall_1) } - .vsyscall_2 ADDR(.vsyscall_0) + 2048: AT(VLOAD(.vsyscall_2)) - { *(.vsyscall_2) } - - .vgetcpu_mode : AT(VLOAD(.vgetcpu_mode)) { *(.vgetcpu_mode) } - vgetcpu_mode = VVIRT(.vgetcpu_mode); - - . = ALIGN(CONFIG_X86_L1_CACHE_BYTES); - .jiffies : AT(VLOAD(.jiffies)) { *(.jiffies) } - jiffies = VVIRT(.jiffies); - - .vsyscall_3 ADDR(.vsyscall_0) + 3072: AT(VLOAD(.vsyscall_3)) - { *(.vsyscall_3) } - - . = VSYSCALL_VIRT_ADDR + PAGE_SIZE; - -#undef VSYSCALL_ADDR -#undef VSYSCALL_PHYS_ADDR -#undef VSYSCALL_VIRT_ADDR -#undef VLOAD_OFFSET -#undef VLOAD -#undef VVIRT_OFFSET -#undef VVIRT - - .data.init_task : AT(ADDR(.data.init_task) - LOAD_OFFSET) { - . = ALIGN(THREAD_SIZE); /* init_task */ - *(.data.init_task) - }:data.init - - .data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET) { - . = ALIGN(PAGE_SIZE); - *(.data.page_aligned) - } - - .smp_locks : AT(ADDR(.smp_locks) - LOAD_OFFSET) { - /* might get freed after init */ - . = ALIGN(PAGE_SIZE); - __smp_alt_begin = .; - __smp_locks = .; - *(.smp_locks) - __smp_locks_end = .; - . = ALIGN(PAGE_SIZE); - __smp_alt_end = .; - } - - . = ALIGN(PAGE_SIZE); /* Init code and data */ - __init_begin = .; /* paired with __init_end */ - .init.text : AT(ADDR(.init.text) - LOAD_OFFSET) { - _sinittext = .; - INIT_TEXT - _einittext = .; - } - .init.data : AT(ADDR(.init.data) - LOAD_OFFSET) { - __initdata_begin = .; - INIT_DATA - __initdata_end = .; - } - - .init.setup : AT(ADDR(.init.setup) - LOAD_OFFSET) { - . = ALIGN(16); - __setup_start = .; - *(.init.setup) - __setup_end = .; - } - .initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) { - __initcall_start = .; - INITCALLS - __initcall_end = .; - } - .con_initcall.init : AT(ADDR(.con_initcall.init) - LOAD_OFFSET) { - __con_initcall_start = .; - *(.con_initcall.init) - __con_initcall_end = .; - } - .x86_cpu_dev.init : AT(ADDR(.x86_cpu_dev.init) - LOAD_OFFSET) { - __x86_cpu_dev_start = .; - *(.x86_cpu_dev.init) - __x86_cpu_dev_end = .; - } - SECURITY_INIT - - . = ALIGN(8); - .parainstructions : AT(ADDR(.parainstructions) - LOAD_OFFSET) { - __parainstructions = .; - *(.parainstructions) - __parainstructions_end = .; - } - - .altinstructions : AT(ADDR(.altinstructions) - LOAD_OFFSET) { - . = ALIGN(8); - __alt_instructions = .; - *(.altinstructions) - __alt_instructions_end = .; - } - .altinstr_replacement : AT(ADDR(.altinstr_replacement) - LOAD_OFFSET) { - *(.altinstr_replacement) - } - /* .exit.text is discard at runtime, not link time, to deal with references - from .altinstructions and .eh_frame */ - .exit.text : AT(ADDR(.exit.text) - LOAD_OFFSET) { - EXIT_TEXT - } - .exit.data : AT(ADDR(.exit.data) - LOAD_OFFSET) { - EXIT_DATA - } - -#ifdef CONFIG_BLK_DEV_INITRD - . = ALIGN(PAGE_SIZE); - .init.ramfs : AT(ADDR(.init.ramfs) - LOAD_OFFSET) { - __initramfs_start = .; - *(.init.ramfs) - __initramfs_end = .; - } -#endif - -#ifdef CONFIG_SMP - /* - * percpu offsets are zero-based on SMP. PERCPU_VADDR() changes the - * output PHDR, so the next output section - __data_nosave - should - * start another section data.init2. Also, pda should be at the head of - * percpu area. Preallocate it and define the percpu offset symbol - * so that it can be accessed as a percpu variable. - */ - . = ALIGN(PAGE_SIZE); - PERCPU_VADDR(0, :percpu) -#else - PERCPU(PAGE_SIZE) -#endif - - . = ALIGN(PAGE_SIZE); - __init_end = .; - - .data_nosave : AT(ADDR(.data_nosave) - LOAD_OFFSET) { - . = ALIGN(PAGE_SIZE); - __nosave_begin = .; - *(.data.nosave) - . = ALIGN(PAGE_SIZE); - __nosave_end = .; - } :data.init2 /* use another section data.init2, see PERCPU_VADDR() above */ - - .bss : AT(ADDR(.bss) - LOAD_OFFSET) { - . = ALIGN(PAGE_SIZE); - __bss_start = .; /* BSS */ - *(.bss.page_aligned) - *(.bss) - __bss_stop = .; - } - - .brk : AT(ADDR(.brk) - LOAD_OFFSET) { - . = ALIGN(PAGE_SIZE); - __brk_base = . ; - . += 64 * 1024 ; /* 64k alignment slop space */ - *(.brk_reservation) /* areas brk users have reserved */ - __brk_limit = . ; - } - - _end = . ; - - /* Sections to be discarded */ - /DISCARD/ : { - *(.exitcall.exit) - *(.eh_frame) - *(.discard) - } - - STABS_DEBUG - - DWARF_DEBUG -} - - /* - * Per-cpu symbols which need to be offset from __per_cpu_load - * for the boot processor. - */ -#define INIT_PER_CPU(x) init_per_cpu__##x = per_cpu__##x + __per_cpu_load -INIT_PER_CPU(gdt_page); -INIT_PER_CPU(irq_stack_union); - -/* - * Build-time check on the image size: - */ -ASSERT((_end - _text <= KERNEL_IMAGE_SIZE), - "kernel image bigger than KERNEL_IMAGE_SIZE") - -#ifdef CONFIG_SMP -ASSERT((per_cpu__irq_stack_union == 0), - "irq_stack_union is not at start of per-cpu area"); -#endif - -#ifdef CONFIG_KEXEC -#include - -ASSERT(kexec_control_code_size <= KEXEC_CONTROL_CODE_MAX_SIZE, - "kexec control code size is too big") -#endif diff --git a/arch/x86/kernel/vsyscall_64.c b/arch/x86/kernel/vsyscall_64.c index 44153afc9067..25ee06a80aad 100644 --- a/arch/x86/kernel/vsyscall_64.c +++ b/arch/x86/kernel/vsyscall_64.c @@ -132,15 +132,7 @@ static __always_inline void do_vgettimeofday(struct timeval * tv) return; } - /* - * Surround the RDTSC by barriers, to make sure it's not - * speculated to outside the seqlock critical section and - * does not cause time warps: - */ - rdtsc_barrier(); now = vread(); - rdtsc_barrier(); - base = __vsyscall_gtod_data.clock.cycle_last; mask = __vsyscall_gtod_data.clock.mask; mult = __vsyscall_gtod_data.clock.mult; diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig index a58504ea78cc..8600a09e0c6c 100644 --- a/arch/x86/kvm/Kconfig +++ b/arch/x86/kvm/Kconfig @@ -50,6 +50,9 @@ config KVM_INTEL Provides support for KVM on Intel processors equipped with the VT extensions. + To compile this as a module, choose M here: the module + will be called kvm-intel. + config KVM_AMD tristate "KVM for AMD processors support" depends on KVM @@ -57,6 +60,9 @@ config KVM_AMD Provides support for KVM on AMD processors equipped with the AMD-V (SVM) extensions. + To compile this as a module, choose M here: the module + will be called kvm-amd. + config KVM_TRACE bool "KVM trace support" depends on KVM && SYSFS diff --git a/arch/x86/kvm/Makefile b/arch/x86/kvm/Makefile index d3ec292f00f2..b43c4efafe80 100644 --- a/arch/x86/kvm/Makefile +++ b/arch/x86/kvm/Makefile @@ -14,7 +14,7 @@ endif EXTRA_CFLAGS += -Ivirt/kvm -Iarch/x86/kvm kvm-objs := $(common-objs) x86.o mmu.o x86_emulate.o i8259.o irq.o lapic.o \ - i8254.o + i8254.o timer.o obj-$(CONFIG_KVM) += kvm.o kvm-intel-objs = vmx.o obj-$(CONFIG_KVM_INTEL) += kvm-intel.o diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c index c13bb92d3157..4d6f0d293ee2 100644 --- a/arch/x86/kvm/i8254.c +++ b/arch/x86/kvm/i8254.c @@ -98,6 +98,37 @@ static int pit_get_gate(struct kvm *kvm, int channel) return kvm->arch.vpit->pit_state.channels[channel].gate; } +static s64 __kpit_elapsed(struct kvm *kvm) +{ + s64 elapsed; + ktime_t remaining; + struct kvm_kpit_state *ps = &kvm->arch.vpit->pit_state; + + /* + * The Counter does not stop when it reaches zero. In + * Modes 0, 1, 4, and 5 the Counter ``wraps around'' to + * the highest count, either FFFF hex for binary counting + * or 9999 for BCD counting, and continues counting. + * Modes 2 and 3 are periodic; the Counter reloads + * itself with the initial count and continues counting + * from there. + */ + remaining = hrtimer_expires_remaining(&ps->pit_timer.timer); + elapsed = ps->pit_timer.period - ktime_to_ns(remaining); + elapsed = mod_64(elapsed, ps->pit_timer.period); + + return elapsed; +} + +static s64 kpit_elapsed(struct kvm *kvm, struct kvm_kpit_channel_state *c, + int channel) +{ + if (channel == 0) + return __kpit_elapsed(kvm); + + return ktime_to_ns(ktime_sub(ktime_get(), c->count_load_time)); +} + static int pit_get_count(struct kvm *kvm, int channel) { struct kvm_kpit_channel_state *c = @@ -107,7 +138,7 @@ static int pit_get_count(struct kvm *kvm, int channel) WARN_ON(!mutex_is_locked(&kvm->arch.vpit->pit_state.lock)); - t = ktime_to_ns(ktime_sub(ktime_get(), c->count_load_time)); + t = kpit_elapsed(kvm, c, channel); d = muldiv64(t, KVM_PIT_FREQ, NSEC_PER_SEC); switch (c->mode) { @@ -137,7 +168,7 @@ static int pit_get_out(struct kvm *kvm, int channel) WARN_ON(!mutex_is_locked(&kvm->arch.vpit->pit_state.lock)); - t = ktime_to_ns(ktime_sub(ktime_get(), c->count_load_time)); + t = kpit_elapsed(kvm, c, channel); d = muldiv64(t, KVM_PIT_FREQ, NSEC_PER_SEC); switch (c->mode) { @@ -193,28 +224,6 @@ static void pit_latch_status(struct kvm *kvm, int channel) } } -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; - - if (!atomic_inc_and_test(&pt->pending)) - set_bit(KVM_REQ_PENDING_TIMER, &vcpu0->requests); - - if (!pt->reinject) - atomic_set(&pt->pending, 1); - - if (vcpu0 && waitqueue_active(&vcpu0->wq)) - wake_up_interruptible(&vcpu0->wq); - - hrtimer_add_expires_ns(&pt->timer, pt->period); - pt->scheduled = hrtimer_get_expires_ns(&pt->timer); - if (pt->period) - ps->channels[0].count_load_time = ktime_get(); - - return (pt->period == 0 ? 0 : 1); -} - int pit_has_pending_timer(struct kvm_vcpu *vcpu) { struct kvm_pit *pit = vcpu->kvm->arch.vpit; @@ -235,21 +244,6 @@ static void kvm_pit_ack_irq(struct kvm_irq_ack_notifier *kian) spin_unlock(&ps->inject_lock); } -static enum hrtimer_restart pit_timer_fn(struct hrtimer *data) -{ - struct kvm_kpit_state *ps; - int restart_timer = 0; - - ps = container_of(data, struct kvm_kpit_state, pit_timer.timer); - - restart_timer = __pit_timer_fn(ps); - - if (restart_timer) - return HRTIMER_RESTART; - else - return HRTIMER_NORESTART; -} - void __kvm_migrate_pit_timer(struct kvm_vcpu *vcpu) { struct kvm_pit *pit = vcpu->kvm->arch.vpit; @@ -263,15 +257,26 @@ void __kvm_migrate_pit_timer(struct kvm_vcpu *vcpu) hrtimer_start_expires(timer, HRTIMER_MODE_ABS); } -static void destroy_pit_timer(struct kvm_kpit_timer *pt) +static void destroy_pit_timer(struct kvm_timer *pt) { pr_debug("pit: execute del timer!\n"); hrtimer_cancel(&pt->timer); } +static bool kpit_is_periodic(struct kvm_timer *ktimer) +{ + struct kvm_kpit_state *ps = container_of(ktimer, struct kvm_kpit_state, + pit_timer); + return ps->is_periodic; +} + +static struct kvm_timer_ops kpit_ops = { + .is_periodic = kpit_is_periodic, +}; + static void create_pit_timer(struct kvm_kpit_state *ps, u32 val, int is_period) { - struct kvm_kpit_timer *pt = &ps->pit_timer; + struct kvm_timer *pt = &ps->pit_timer; s64 interval; interval = muldiv64(val, NSEC_PER_SEC, KVM_PIT_FREQ); @@ -280,8 +285,14 @@ static void create_pit_timer(struct kvm_kpit_state *ps, u32 val, int is_period) /* TODO The new value only affected after the retriggered */ hrtimer_cancel(&pt->timer); - pt->period = (is_period == 0) ? 0 : interval; - pt->timer.function = pit_timer_fn; + pt->period = interval; + ps->is_periodic = is_period; + + pt->timer.function = kvm_timer_fn; + pt->t_ops = &kpit_ops; + pt->kvm = ps->pit->kvm; + pt->vcpu_id = 0; + atomic_set(&pt->pending, 0); ps->irq_ack = 1; @@ -298,23 +309,23 @@ static void pit_load_count(struct kvm *kvm, int channel, u32 val) pr_debug("pit: load_count val is %d, channel is %d\n", val, channel); /* - * Though spec said the state of 8254 is undefined after power-up, - * seems some tricky OS like Windows XP depends on IRQ0 interrupt - * when booting up. - * So here setting initialize rate for it, and not a specific number + * The largest possible initial count is 0; this is equivalent + * to 216 for binary counting and 104 for BCD counting. */ if (val == 0) val = 0x10000; - ps->channels[channel].count_load_time = ktime_get(); ps->channels[channel].count = val; - if (channel != 0) + if (channel != 0) { + ps->channels[channel].count_load_time = ktime_get(); return; + } /* Two types of timer * mode 1 is one shot, mode 2 is period, otherwise del timer */ switch (ps->channels[0].mode) { + case 0: case 1: /* FIXME: enhance mode 4 precision */ case 4: diff --git a/arch/x86/kvm/i8254.h b/arch/x86/kvm/i8254.h index 6acbe4b505d5..bbd863ff60b7 100644 --- a/arch/x86/kvm/i8254.h +++ b/arch/x86/kvm/i8254.h @@ -3,15 +3,6 @@ #include "iodev.h" -struct kvm_kpit_timer { - struct hrtimer timer; - int irq; - s64 period; /* unit: ns */ - s64 scheduled; - atomic_t pending; - bool reinject; -}; - struct kvm_kpit_channel_state { u32 count; /* can be 65536 */ u16 latched_count; @@ -30,7 +21,8 @@ struct kvm_kpit_channel_state { struct kvm_kpit_state { struct kvm_kpit_channel_state channels[3]; - struct kvm_kpit_timer pit_timer; + struct kvm_timer pit_timer; + bool is_periodic; u32 speaker_data_on; struct mutex lock; struct kvm_pit *pit; diff --git a/arch/x86/kvm/irq.c b/arch/x86/kvm/irq.c index cf17ed52f6fb..96dfbb6ad2a9 100644 --- a/arch/x86/kvm/irq.c +++ b/arch/x86/kvm/irq.c @@ -24,6 +24,7 @@ #include "irq.h" #include "i8254.h" +#include "x86.h" /* * check if there are pending timer events @@ -48,6 +49,9 @@ int kvm_cpu_has_interrupt(struct kvm_vcpu *v) { struct kvm_pic *s; + if (!irqchip_in_kernel(v->kvm)) + return v->arch.interrupt.pending; + if (kvm_apic_has_interrupt(v) == -1) { /* LAPIC */ if (kvm_apic_accept_pic_intr(v)) { s = pic_irqchip(v->kvm); /* PIC */ @@ -67,6 +71,9 @@ int kvm_cpu_get_interrupt(struct kvm_vcpu *v) struct kvm_pic *s; int vector; + if (!irqchip_in_kernel(v->kvm)) + return v->arch.interrupt.nr; + vector = kvm_get_apic_interrupt(v); /* APIC */ if (vector == -1) { if (kvm_apic_accept_pic_intr(v)) { diff --git a/arch/x86/kvm/kvm_timer.h b/arch/x86/kvm/kvm_timer.h new file mode 100644 index 000000000000..26bd6ba74e1c --- /dev/null +++ b/arch/x86/kvm/kvm_timer.h @@ -0,0 +1,18 @@ + +struct kvm_timer { + struct hrtimer timer; + s64 period; /* unit: ns */ + atomic_t pending; /* accumulated triggered timers */ + bool reinject; + struct kvm_timer_ops *t_ops; + struct kvm *kvm; + int vcpu_id; +}; + +struct kvm_timer_ops { + bool (*is_periodic)(struct kvm_timer *); +}; + + +enum hrtimer_restart kvm_timer_fn(struct hrtimer *data); + diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index f0b67f2cdd69..ae99d83f81a3 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -196,20 +196,15 @@ int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu) } EXPORT_SYMBOL_GPL(kvm_lapic_find_highest_irr); -int kvm_apic_set_irq(struct kvm_vcpu *vcpu, u8 vec, u8 trig) +static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, + int vector, int level, int trig_mode); + +int kvm_apic_set_irq(struct kvm_vcpu *vcpu, struct kvm_lapic_irq *irq) { struct kvm_lapic *apic = vcpu->arch.apic; - if (!apic_test_and_set_irr(vec, apic)) { - /* a new pending irq is set in IRR */ - if (trig) - apic_set_vector(vec, apic->regs + APIC_TMR); - else - apic_clear_vector(vec, apic->regs + APIC_TMR); - kvm_vcpu_kick(apic->vcpu); - return 1; - } - return 0; + return __apic_accept_irq(apic, irq->delivery_mode, irq->vector, + irq->level, irq->trig_mode); } static inline int apic_find_highest_isr(struct kvm_lapic *apic) @@ -250,7 +245,7 @@ static void apic_set_tpr(struct kvm_lapic *apic, u32 tpr) int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest) { - return kvm_apic_id(apic) == dest; + return dest == 0xff || kvm_apic_id(apic) == dest; } int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda) @@ -279,37 +274,34 @@ int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda) return result; } -static int apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source, +int kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source, int short_hand, int dest, int dest_mode) { int result = 0; struct kvm_lapic *target = vcpu->arch.apic; apic_debug("target %p, source %p, dest 0x%x, " - "dest_mode 0x%x, short_hand 0x%x", + "dest_mode 0x%x, short_hand 0x%x\n", target, source, dest, dest_mode, short_hand); ASSERT(!target); switch (short_hand) { case APIC_DEST_NOSHORT: - if (dest_mode == 0) { + if (dest_mode == 0) /* Physical mode. */ - if ((dest == 0xFF) || (dest == kvm_apic_id(target))) - result = 1; - } else + result = kvm_apic_match_physical_addr(target, dest); + else /* Logical mode. */ result = kvm_apic_match_logical_addr(target, dest); break; case APIC_DEST_SELF: - if (target == source) - result = 1; + result = (target == source); break; case APIC_DEST_ALLINC: result = 1; break; case APIC_DEST_ALLBUT: - if (target != source) - result = 1; + result = (target != source); break; default: printk(KERN_WARNING "Bad dest shorthand value %x\n", @@ -327,20 +319,22 @@ static int apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source, static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, int vector, int level, int trig_mode) { - int orig_irr, result = 0; + int result = 0; struct kvm_vcpu *vcpu = apic->vcpu; switch (delivery_mode) { - case APIC_DM_FIXED: case APIC_DM_LOWEST: + vcpu->arch.apic_arb_prio++; + case APIC_DM_FIXED: /* FIXME add logic for vcpu on reset */ if (unlikely(!apic_enabled(apic))) break; - orig_irr = apic_test_and_set_irr(vector, apic); - if (orig_irr && trig_mode) { - apic_debug("level trig mode repeatedly for vector %d", - vector); + result = !apic_test_and_set_irr(vector, apic); + if (!result) { + if (trig_mode) + apic_debug("level trig mode repeatedly for " + "vector %d", vector); break; } @@ -349,10 +343,7 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, apic_set_vector(vector, apic->regs + APIC_TMR); } else apic_clear_vector(vector, apic->regs + APIC_TMR); - kvm_vcpu_kick(vcpu); - - result = (orig_irr == 0); break; case APIC_DM_REMRD: @@ -364,12 +355,14 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, break; case APIC_DM_NMI: + result = 1; kvm_inject_nmi(vcpu); kvm_vcpu_kick(vcpu); break; case APIC_DM_INIT: if (level) { + result = 1; if (vcpu->arch.mp_state == KVM_MP_STATE_RUNNABLE) printk(KERN_DEBUG "INIT on a runnable vcpu %d\n", @@ -386,6 +379,7 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, apic_debug("SIPI to vcpu %d vector 0x%02x\n", vcpu->vcpu_id, vector); if (vcpu->arch.mp_state == KVM_MP_STATE_INIT_RECEIVED) { + result = 1; vcpu->arch.sipi_vector = vector; vcpu->arch.mp_state = KVM_MP_STATE_SIPI_RECEIVED; kvm_vcpu_kick(vcpu); @@ -408,43 +402,9 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, return result; } -static struct kvm_lapic *kvm_apic_round_robin(struct kvm *kvm, u8 vector, - unsigned long bitmap) +int kvm_apic_compare_prio(struct kvm_vcpu *vcpu1, struct kvm_vcpu *vcpu2) { - int last; - int next; - struct kvm_lapic *apic = NULL; - - last = kvm->arch.round_robin_prev_vcpu; - next = last; - - do { - if (++next == KVM_MAX_VCPUS) - next = 0; - if (kvm->vcpus[next] == NULL || !test_bit(next, &bitmap)) - continue; - apic = kvm->vcpus[next]->arch.apic; - if (apic && apic_enabled(apic)) - break; - apic = NULL; - } while (next != last); - kvm->arch.round_robin_prev_vcpu = next; - - if (!apic) - printk(KERN_DEBUG "vcpu not ready for apic_round_robin\n"); - - return apic; -} - -struct kvm_vcpu *kvm_get_lowest_prio_vcpu(struct kvm *kvm, u8 vector, - unsigned long bitmap) -{ - struct kvm_lapic *apic; - - apic = kvm_apic_round_robin(kvm, vector, bitmap); - if (apic) - return apic->vcpu; - return NULL; + return vcpu1->arch.apic_arb_prio - vcpu2->arch.apic_arb_prio; } static void apic_set_eoi(struct kvm_lapic *apic) @@ -472,47 +432,24 @@ static void apic_send_ipi(struct kvm_lapic *apic) { u32 icr_low = apic_get_reg(apic, APIC_ICR); u32 icr_high = apic_get_reg(apic, APIC_ICR2); + struct kvm_lapic_irq irq; - unsigned int dest = GET_APIC_DEST_FIELD(icr_high); - unsigned int short_hand = icr_low & APIC_SHORT_MASK; - unsigned int trig_mode = icr_low & APIC_INT_LEVELTRIG; - unsigned int level = icr_low & APIC_INT_ASSERT; - unsigned int dest_mode = icr_low & APIC_DEST_MASK; - unsigned int delivery_mode = icr_low & APIC_MODE_MASK; - unsigned int vector = icr_low & APIC_VECTOR_MASK; - - struct kvm_vcpu *target; - struct kvm_vcpu *vcpu; - unsigned long lpr_map = 0; - int i; + irq.vector = icr_low & APIC_VECTOR_MASK; + irq.delivery_mode = icr_low & APIC_MODE_MASK; + irq.dest_mode = icr_low & APIC_DEST_MASK; + irq.level = icr_low & APIC_INT_ASSERT; + irq.trig_mode = icr_low & APIC_INT_LEVELTRIG; + irq.shorthand = icr_low & APIC_SHORT_MASK; + irq.dest_id = GET_APIC_DEST_FIELD(icr_high); apic_debug("icr_high 0x%x, icr_low 0x%x, " "short_hand 0x%x, dest 0x%x, trig_mode 0x%x, level 0x%x, " "dest_mode 0x%x, delivery_mode 0x%x, vector 0x%x\n", - icr_high, icr_low, short_hand, dest, - trig_mode, level, dest_mode, delivery_mode, vector); + icr_high, icr_low, irq.shorthand, irq.dest_id, + irq.trig_mode, irq.level, irq.dest_mode, irq.delivery_mode, + irq.vector); - for (i = 0; i < KVM_MAX_VCPUS; i++) { - vcpu = apic->vcpu->kvm->vcpus[i]; - if (!vcpu) - continue; - - if (vcpu->arch.apic && - apic_match_dest(vcpu, apic, short_hand, dest, dest_mode)) { - if (delivery_mode == APIC_DM_LOWEST) - set_bit(vcpu->vcpu_id, &lpr_map); - else - __apic_accept_irq(vcpu->arch.apic, delivery_mode, - vector, level, trig_mode); - } - } - - if (delivery_mode == APIC_DM_LOWEST) { - target = kvm_get_lowest_prio_vcpu(vcpu->kvm, vector, lpr_map); - if (target != NULL) - __apic_accept_irq(target->arch.apic, delivery_mode, - vector, level, trig_mode); - } + kvm_irq_delivery_to_apic(apic->vcpu->kvm, apic, &irq); } static u32 apic_get_tmcct(struct kvm_lapic *apic) @@ -527,12 +464,13 @@ static u32 apic_get_tmcct(struct kvm_lapic *apic) if (apic_get_reg(apic, APIC_TMICT) == 0) return 0; - remaining = hrtimer_expires_remaining(&apic->timer.dev); + remaining = hrtimer_expires_remaining(&apic->lapic_timer.timer); if (ktime_to_ns(remaining) < 0) remaining = ktime_set(0, 0); - ns = mod_64(ktime_to_ns(remaining), apic->timer.period); - tmcct = div64_u64(ns, (APIC_BUS_CYCLE_NS * apic->timer.divide_count)); + ns = mod_64(ktime_to_ns(remaining), apic->lapic_timer.period); + tmcct = div64_u64(ns, + (APIC_BUS_CYCLE_NS * apic->divide_count)); return tmcct; } @@ -619,25 +557,25 @@ static void update_divide_count(struct kvm_lapic *apic) tdcr = apic_get_reg(apic, APIC_TDCR); tmp1 = tdcr & 0xf; tmp2 = ((tmp1 & 0x3) | ((tmp1 & 0x8) >> 1)) + 1; - apic->timer.divide_count = 0x1 << (tmp2 & 0x7); + apic->divide_count = 0x1 << (tmp2 & 0x7); apic_debug("timer divide count is 0x%x\n", - apic->timer.divide_count); + apic->divide_count); } static void start_apic_timer(struct kvm_lapic *apic) { - ktime_t now = apic->timer.dev.base->get_time(); + ktime_t now = apic->lapic_timer.timer.base->get_time(); - apic->timer.period = apic_get_reg(apic, APIC_TMICT) * - APIC_BUS_CYCLE_NS * apic->timer.divide_count; - atomic_set(&apic->timer.pending, 0); + apic->lapic_timer.period = apic_get_reg(apic, APIC_TMICT) * + APIC_BUS_CYCLE_NS * apic->divide_count; + atomic_set(&apic->lapic_timer.pending, 0); - if (!apic->timer.period) + if (!apic->lapic_timer.period) return; - hrtimer_start(&apic->timer.dev, - ktime_add_ns(now, apic->timer.period), + hrtimer_start(&apic->lapic_timer.timer, + ktime_add_ns(now, apic->lapic_timer.period), HRTIMER_MODE_ABS); apic_debug("%s: bus cycle is %" PRId64 "ns, now 0x%016" @@ -646,9 +584,9 @@ static void start_apic_timer(struct kvm_lapic *apic) "expire @ 0x%016" PRIx64 ".\n", __func__, APIC_BUS_CYCLE_NS, ktime_to_ns(now), apic_get_reg(apic, APIC_TMICT), - apic->timer.period, + apic->lapic_timer.period, ktime_to_ns(ktime_add_ns(now, - apic->timer.period))); + apic->lapic_timer.period))); } static void apic_manage_nmi_watchdog(struct kvm_lapic *apic, u32 lvt0_val) @@ -730,7 +668,7 @@ static void apic_mmio_write(struct kvm_io_device *this, apic_set_reg(apic, APIC_LVTT + 0x10 * i, lvt_val | APIC_LVT_MASKED); } - atomic_set(&apic->timer.pending, 0); + atomic_set(&apic->lapic_timer.pending, 0); } break; @@ -762,7 +700,7 @@ static void apic_mmio_write(struct kvm_io_device *this, break; case APIC_TMICT: - hrtimer_cancel(&apic->timer.dev); + hrtimer_cancel(&apic->lapic_timer.timer); apic_set_reg(apic, APIC_TMICT, val); start_apic_timer(apic); return; @@ -802,7 +740,7 @@ void kvm_free_lapic(struct kvm_vcpu *vcpu) if (!vcpu->arch.apic) return; - hrtimer_cancel(&vcpu->arch.apic->timer.dev); + hrtimer_cancel(&vcpu->arch.apic->lapic_timer.timer); if (vcpu->arch.apic->regs_page) __free_page(vcpu->arch.apic->regs_page); @@ -880,7 +818,7 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu) ASSERT(apic != NULL); /* Stop the timer in case it's a reset to an active apic */ - hrtimer_cancel(&apic->timer.dev); + hrtimer_cancel(&apic->lapic_timer.timer); apic_set_reg(apic, APIC_ID, vcpu->vcpu_id << 24); apic_set_reg(apic, APIC_LVR, APIC_VERSION); @@ -905,11 +843,13 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu) apic_set_reg(apic, APIC_TMR + 0x10 * i, 0); } update_divide_count(apic); - atomic_set(&apic->timer.pending, 0); + atomic_set(&apic->lapic_timer.pending, 0); if (vcpu->vcpu_id == 0) vcpu->arch.apic_base |= MSR_IA32_APICBASE_BSP; apic_update_ppr(apic); + vcpu->arch.apic_arb_prio = 0; + apic_debug(KERN_INFO "%s: vcpu=%p, id=%d, base_msr=" "0x%016" PRIx64 ", base_address=0x%0lx.\n", __func__, vcpu, kvm_apic_id(apic), @@ -917,16 +857,14 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu) } EXPORT_SYMBOL_GPL(kvm_lapic_reset); +bool kvm_apic_present(struct kvm_vcpu *vcpu) +{ + return vcpu->arch.apic && apic_hw_enabled(vcpu->arch.apic); +} + int kvm_lapic_enabled(struct kvm_vcpu *vcpu) { - struct kvm_lapic *apic = vcpu->arch.apic; - int ret = 0; - - if (!apic) - return 0; - ret = apic_enabled(apic); - - return ret; + return kvm_apic_present(vcpu) && apic_sw_enabled(vcpu->arch.apic); } EXPORT_SYMBOL_GPL(kvm_lapic_enabled); @@ -936,22 +874,11 @@ EXPORT_SYMBOL_GPL(kvm_lapic_enabled); *---------------------------------------------------------------------- */ -/* TODO: make sure __apic_timer_fn runs in current pCPU */ -static int __apic_timer_fn(struct kvm_lapic *apic) +static bool lapic_is_periodic(struct kvm_timer *ktimer) { - int result = 0; - wait_queue_head_t *q = &apic->vcpu->wq; - - if(!atomic_inc_and_test(&apic->timer.pending)) - set_bit(KVM_REQ_PENDING_TIMER, &apic->vcpu->requests); - if (waitqueue_active(q)) - wake_up_interruptible(q); - - if (apic_lvtt_period(apic)) { - result = 1; - hrtimer_add_expires_ns(&apic->timer.dev, apic->timer.period); - } - return result; + struct kvm_lapic *apic = container_of(ktimer, struct kvm_lapic, + lapic_timer); + return apic_lvtt_period(apic); } int apic_has_pending_timer(struct kvm_vcpu *vcpu) @@ -959,7 +886,7 @@ int apic_has_pending_timer(struct kvm_vcpu *vcpu) struct kvm_lapic *lapic = vcpu->arch.apic; if (lapic && apic_enabled(lapic) && apic_lvt_enabled(lapic, APIC_LVTT)) - return atomic_read(&lapic->timer.pending); + return atomic_read(&lapic->lapic_timer.pending); return 0; } @@ -986,20 +913,9 @@ void kvm_apic_nmi_wd_deliver(struct kvm_vcpu *vcpu) kvm_apic_local_deliver(apic, APIC_LVT0); } -static enum hrtimer_restart apic_timer_fn(struct hrtimer *data) -{ - struct kvm_lapic *apic; - int restart_timer = 0; - - apic = container_of(data, struct kvm_lapic, timer.dev); - - restart_timer = __apic_timer_fn(apic); - - if (restart_timer) - return HRTIMER_RESTART; - else - return HRTIMER_NORESTART; -} +static struct kvm_timer_ops lapic_timer_ops = { + .is_periodic = lapic_is_periodic, +}; int kvm_create_lapic(struct kvm_vcpu *vcpu) { @@ -1024,8 +940,13 @@ int kvm_create_lapic(struct kvm_vcpu *vcpu) memset(apic->regs, 0, PAGE_SIZE); apic->vcpu = vcpu; - hrtimer_init(&apic->timer.dev, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); - apic->timer.dev.function = apic_timer_fn; + hrtimer_init(&apic->lapic_timer.timer, CLOCK_MONOTONIC, + HRTIMER_MODE_ABS); + apic->lapic_timer.timer.function = kvm_timer_fn; + apic->lapic_timer.t_ops = &lapic_timer_ops; + apic->lapic_timer.kvm = vcpu->kvm; + apic->lapic_timer.vcpu_id = vcpu->vcpu_id; + apic->base_address = APIC_DEFAULT_PHYS_BASE; vcpu->arch.apic_base = APIC_DEFAULT_PHYS_BASE; @@ -1078,9 +999,9 @@ void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu) { struct kvm_lapic *apic = vcpu->arch.apic; - if (apic && atomic_read(&apic->timer.pending) > 0) { + if (apic && atomic_read(&apic->lapic_timer.pending) > 0) { if (kvm_apic_local_deliver(apic, APIC_LVTT)) - atomic_dec(&apic->timer.pending); + atomic_dec(&apic->lapic_timer.pending); } } @@ -1106,7 +1027,7 @@ void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu) MSR_IA32_APICBASE_BASE; apic_set_reg(apic, APIC_LVR, APIC_VERSION); apic_update_ppr(apic); - hrtimer_cancel(&apic->timer.dev); + hrtimer_cancel(&apic->lapic_timer.timer); update_divide_count(apic); start_apic_timer(apic); } @@ -1119,7 +1040,7 @@ void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu) if (!apic) return; - timer = &apic->timer.dev; + timer = &apic->lapic_timer.timer; if (hrtimer_cancel(timer)) hrtimer_start_expires(timer, HRTIMER_MODE_ABS); } diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h index 45ab6ee71209..a587f8349c46 100644 --- a/arch/x86/kvm/lapic.h +++ b/arch/x86/kvm/lapic.h @@ -2,18 +2,15 @@ #define __KVM_X86_LAPIC_H #include "iodev.h" +#include "kvm_timer.h" #include struct kvm_lapic { unsigned long base_address; struct kvm_io_device dev; - struct { - atomic_t pending; - s64 period; /* unit: ns */ - u32 divide_count; - struct hrtimer dev; - } timer; + struct kvm_timer lapic_timer; + u32 divide_count; struct kvm_vcpu *vcpu; struct page *regs_page; void *regs; @@ -34,12 +31,13 @@ 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); -int kvm_apic_set_irq(struct kvm_vcpu *vcpu, u8 vec, u8 trig); +int kvm_apic_set_irq(struct kvm_vcpu *vcpu, struct kvm_lapic_irq *irq); u64 kvm_get_apic_base(struct kvm_vcpu *vcpu); void kvm_set_apic_base(struct kvm_vcpu *vcpu, u64 data); void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu); int kvm_lapic_enabled(struct kvm_vcpu *vcpu); +bool kvm_apic_present(struct kvm_vcpu *vcpu); int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu); void kvm_lapic_set_vapic_addr(struct kvm_vcpu *vcpu, gpa_t vapic_addr); diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 32cf11e5728a..5c3d6e81a7dc 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -126,6 +126,7 @@ module_param(oos_shadow, bool, 0644); #define PFERR_PRESENT_MASK (1U << 0) #define PFERR_WRITE_MASK (1U << 1) #define PFERR_USER_MASK (1U << 2) +#define PFERR_RSVD_MASK (1U << 3) #define PFERR_FETCH_MASK (1U << 4) #define PT_DIRECTORY_LEVEL 2 @@ -177,7 +178,11 @@ static u64 __read_mostly shadow_x_mask; /* mutual exclusive with nx_mask */ static u64 __read_mostly shadow_user_mask; static u64 __read_mostly shadow_accessed_mask; static u64 __read_mostly shadow_dirty_mask; -static u64 __read_mostly shadow_mt_mask; + +static inline u64 rsvd_bits(int s, int e) +{ + return ((1ULL << (e - s + 1)) - 1) << s; +} void kvm_mmu_set_nonpresent_ptes(u64 trap_pte, u64 notrap_pte) { @@ -193,14 +198,13 @@ void kvm_mmu_set_base_ptes(u64 base_pte) EXPORT_SYMBOL_GPL(kvm_mmu_set_base_ptes); void kvm_mmu_set_mask_ptes(u64 user_mask, u64 accessed_mask, - u64 dirty_mask, u64 nx_mask, u64 x_mask, u64 mt_mask) + u64 dirty_mask, u64 nx_mask, u64 x_mask) { shadow_user_mask = user_mask; shadow_accessed_mask = accessed_mask; shadow_dirty_mask = dirty_mask; shadow_nx_mask = nx_mask; shadow_x_mask = x_mask; - shadow_mt_mask = mt_mask; } EXPORT_SYMBOL_GPL(kvm_mmu_set_mask_ptes); @@ -219,11 +223,6 @@ static int is_nx(struct kvm_vcpu *vcpu) return vcpu->arch.shadow_efer & EFER_NX; } -static int is_present_pte(unsigned long pte) -{ - return pte & PT_PRESENT_MASK; -} - static int is_shadow_present_pte(u64 pte) { return pte != shadow_trap_nonpresent_pte @@ -1074,18 +1073,10 @@ static struct kvm_mmu_page *kvm_mmu_lookup_page(struct kvm *kvm, gfn_t gfn) return NULL; } -static void kvm_unlink_unsync_global(struct kvm *kvm, struct kvm_mmu_page *sp) -{ - list_del(&sp->oos_link); - --kvm->stat.mmu_unsync_global; -} - static void kvm_unlink_unsync_page(struct kvm *kvm, struct kvm_mmu_page *sp) { WARN_ON(!sp->unsync); sp->unsync = 0; - if (sp->global) - kvm_unlink_unsync_global(kvm, sp); --kvm->stat.mmu_unsync; } @@ -1248,7 +1239,6 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu, pgprintk("%s: adding gfn %lx role %x\n", __func__, gfn, role.word); sp->gfn = gfn; sp->role = role; - sp->global = 0; hlist_add_head(&sp->hash_link, bucket); if (!direct) { if (rmap_write_protect(vcpu->kvm, gfn)) @@ -1616,7 +1606,7 @@ static int get_mtrr_type(struct mtrr_state_type *mtrr_state, return mtrr_state->def_type; } -static u8 get_memory_type(struct kvm_vcpu *vcpu, gfn_t gfn) +u8 kvm_get_guest_memory_type(struct kvm_vcpu *vcpu, gfn_t gfn) { u8 mtrr; @@ -1626,6 +1616,7 @@ static u8 get_memory_type(struct kvm_vcpu *vcpu, gfn_t gfn) mtrr = MTRR_TYPE_WRBACK; return mtrr; } +EXPORT_SYMBOL_GPL(kvm_get_guest_memory_type); static int kvm_unsync_page(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp) { @@ -1646,11 +1637,7 @@ static int kvm_unsync_page(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp) ++vcpu->kvm->stat.mmu_unsync; sp->unsync = 1; - if (sp->global) { - list_add(&sp->oos_link, &vcpu->kvm->arch.oos_global_pages); - ++vcpu->kvm->stat.mmu_unsync_global; - } else - kvm_mmu_mark_parents_unsync(vcpu, sp); + kvm_mmu_mark_parents_unsync(vcpu, sp); mmu_convert_notrap(sp); return 0; @@ -1677,21 +1664,11 @@ static int mmu_need_write_protect(struct kvm_vcpu *vcpu, gfn_t gfn, static int set_spte(struct kvm_vcpu *vcpu, u64 *shadow_pte, unsigned pte_access, int user_fault, int write_fault, int dirty, int largepage, - int global, gfn_t gfn, pfn_t pfn, bool speculative, + gfn_t gfn, pfn_t pfn, bool speculative, bool can_unsync) { u64 spte; int ret = 0; - u64 mt_mask = shadow_mt_mask; - struct kvm_mmu_page *sp = page_header(__pa(shadow_pte)); - - if (!global && sp->global) { - sp->global = 0; - if (sp->unsync) { - kvm_unlink_unsync_global(vcpu->kvm, sp); - kvm_mmu_mark_parents_unsync(vcpu, sp); - } - } /* * We don't set the accessed bit, since we sometimes want to see @@ -1711,16 +1688,9 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *shadow_pte, spte |= shadow_user_mask; if (largepage) spte |= PT_PAGE_SIZE_MASK; - if (mt_mask) { - if (!kvm_is_mmio_pfn(pfn)) { - mt_mask = get_memory_type(vcpu, gfn) << - kvm_x86_ops->get_mt_mask_shift(); - mt_mask |= VMX_EPT_IGMT_BIT; - } else - mt_mask = MTRR_TYPE_UNCACHABLE << - kvm_x86_ops->get_mt_mask_shift(); - spte |= mt_mask; - } + if (tdp_enabled) + spte |= kvm_x86_ops->get_mt_mask(vcpu, gfn, + kvm_is_mmio_pfn(pfn)); spte |= (u64)pfn << PAGE_SHIFT; @@ -1765,8 +1735,8 @@ set_pte: static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *shadow_pte, unsigned pt_access, unsigned pte_access, int user_fault, int write_fault, int dirty, - int *ptwrite, int largepage, int global, - gfn_t gfn, pfn_t pfn, bool speculative) + int *ptwrite, int largepage, gfn_t gfn, + pfn_t pfn, bool speculative) { int was_rmapped = 0; int was_writeble = is_writeble_pte(*shadow_pte); @@ -1795,7 +1765,7 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *shadow_pte, was_rmapped = 1; } if (set_spte(vcpu, shadow_pte, pte_access, user_fault, write_fault, - dirty, largepage, global, gfn, pfn, speculative, true)) { + dirty, largepage, gfn, pfn, speculative, true)) { if (write_fault) *ptwrite = 1; kvm_x86_ops->tlb_flush(vcpu); @@ -1843,7 +1813,7 @@ static int __direct_map(struct kvm_vcpu *vcpu, gpa_t v, int write, || (largepage && iterator.level == PT_DIRECTORY_LEVEL)) { mmu_set_spte(vcpu, iterator.sptep, ACC_ALL, ACC_ALL, 0, write, 1, &pt_write, - largepage, 0, gfn, pfn, false); + largepage, gfn, pfn, false); ++vcpu->stat.pf_fixed; break; } @@ -1942,7 +1912,19 @@ static void mmu_free_roots(struct kvm_vcpu *vcpu) vcpu->arch.mmu.root_hpa = INVALID_PAGE; } -static void mmu_alloc_roots(struct kvm_vcpu *vcpu) +static int mmu_check_root(struct kvm_vcpu *vcpu, gfn_t root_gfn) +{ + int ret = 0; + + if (!kvm_is_visible_gfn(vcpu->kvm, root_gfn)) { + set_bit(KVM_REQ_TRIPLE_FAULT, &vcpu->requests); + ret = 1; + } + + return ret; +} + +static int mmu_alloc_roots(struct kvm_vcpu *vcpu) { int i; gfn_t root_gfn; @@ -1957,13 +1939,15 @@ static void mmu_alloc_roots(struct kvm_vcpu *vcpu) ASSERT(!VALID_PAGE(root)); if (tdp_enabled) direct = 1; + if (mmu_check_root(vcpu, root_gfn)) + return 1; sp = kvm_mmu_get_page(vcpu, root_gfn, 0, PT64_ROOT_LEVEL, direct, ACC_ALL, NULL); root = __pa(sp->spt); ++sp->root_count; vcpu->arch.mmu.root_hpa = root; - return; + return 0; } direct = !is_paging(vcpu); if (tdp_enabled) @@ -1980,6 +1964,8 @@ static void mmu_alloc_roots(struct kvm_vcpu *vcpu) root_gfn = vcpu->arch.pdptrs[i] >> PAGE_SHIFT; } else if (vcpu->arch.mmu.root_level == 0) root_gfn = 0; + if (mmu_check_root(vcpu, root_gfn)) + return 1; sp = kvm_mmu_get_page(vcpu, root_gfn, i << 30, PT32_ROOT_LEVEL, direct, ACC_ALL, NULL); @@ -1988,6 +1974,7 @@ static void mmu_alloc_roots(struct kvm_vcpu *vcpu) vcpu->arch.mmu.pae_root[i] = root | PT_PRESENT_MASK; } vcpu->arch.mmu.root_hpa = __pa(vcpu->arch.mmu.pae_root); + return 0; } static void mmu_sync_roots(struct kvm_vcpu *vcpu) @@ -2006,7 +1993,7 @@ static void mmu_sync_roots(struct kvm_vcpu *vcpu) for (i = 0; i < 4; ++i) { hpa_t root = vcpu->arch.mmu.pae_root[i]; - if (root) { + if (root && VALID_PAGE(root)) { root &= PT64_BASE_ADDR_MASK; sp = page_header(root); mmu_sync_children(vcpu, sp); @@ -2014,15 +2001,6 @@ static void mmu_sync_roots(struct kvm_vcpu *vcpu) } } -static void mmu_sync_global(struct kvm_vcpu *vcpu) -{ - struct kvm *kvm = vcpu->kvm; - struct kvm_mmu_page *sp, *n; - - list_for_each_entry_safe(sp, n, &kvm->arch.oos_global_pages, oos_link) - kvm_sync_page(vcpu, sp); -} - void kvm_mmu_sync_roots(struct kvm_vcpu *vcpu) { spin_lock(&vcpu->kvm->mmu_lock); @@ -2030,13 +2008,6 @@ void kvm_mmu_sync_roots(struct kvm_vcpu *vcpu) spin_unlock(&vcpu->kvm->mmu_lock); } -void kvm_mmu_sync_global(struct kvm_vcpu *vcpu) -{ - spin_lock(&vcpu->kvm->mmu_lock); - mmu_sync_global(vcpu); - spin_unlock(&vcpu->kvm->mmu_lock); -} - static gpa_t nonpaging_gva_to_gpa(struct kvm_vcpu *vcpu, gva_t vaddr) { return vaddr; @@ -2151,6 +2122,14 @@ static void paging_free(struct kvm_vcpu *vcpu) nonpaging_free(vcpu); } +static bool is_rsvd_bits_set(struct kvm_vcpu *vcpu, u64 gpte, int level) +{ + int bit7; + + bit7 = (gpte >> 7) & 1; + return (gpte & vcpu->arch.mmu.rsvd_bits_mask[bit7][level-1]) != 0; +} + #define PTTYPE 64 #include "paging_tmpl.h" #undef PTTYPE @@ -2159,6 +2138,59 @@ static void paging_free(struct kvm_vcpu *vcpu) #include "paging_tmpl.h" #undef PTTYPE +static void reset_rsvds_bits_mask(struct kvm_vcpu *vcpu, int level) +{ + struct kvm_mmu *context = &vcpu->arch.mmu; + int maxphyaddr = cpuid_maxphyaddr(vcpu); + u64 exb_bit_rsvd = 0; + + if (!is_nx(vcpu)) + exb_bit_rsvd = rsvd_bits(63, 63); + switch (level) { + case PT32_ROOT_LEVEL: + /* no rsvd bits for 2 level 4K page table entries */ + context->rsvd_bits_mask[0][1] = 0; + context->rsvd_bits_mask[0][0] = 0; + if (is_cpuid_PSE36()) + /* 36bits PSE 4MB page */ + context->rsvd_bits_mask[1][1] = rsvd_bits(17, 21); + else + /* 32 bits PSE 4MB page */ + context->rsvd_bits_mask[1][1] = rsvd_bits(13, 21); + context->rsvd_bits_mask[1][0] = ~0ull; + break; + case PT32E_ROOT_LEVEL: + context->rsvd_bits_mask[0][2] = + rsvd_bits(maxphyaddr, 63) | + rsvd_bits(7, 8) | rsvd_bits(1, 2); /* PDPTE */ + context->rsvd_bits_mask[0][1] = exb_bit_rsvd | + rsvd_bits(maxphyaddr, 62); /* PDE */ + context->rsvd_bits_mask[0][0] = exb_bit_rsvd | + rsvd_bits(maxphyaddr, 62); /* PTE */ + context->rsvd_bits_mask[1][1] = exb_bit_rsvd | + rsvd_bits(maxphyaddr, 62) | + rsvd_bits(13, 20); /* large page */ + context->rsvd_bits_mask[1][0] = ~0ull; + break; + case PT64_ROOT_LEVEL: + context->rsvd_bits_mask[0][3] = exb_bit_rsvd | + rsvd_bits(maxphyaddr, 51) | rsvd_bits(7, 8); + context->rsvd_bits_mask[0][2] = exb_bit_rsvd | + rsvd_bits(maxphyaddr, 51) | rsvd_bits(7, 8); + context->rsvd_bits_mask[0][1] = exb_bit_rsvd | + rsvd_bits(maxphyaddr, 51); + context->rsvd_bits_mask[0][0] = exb_bit_rsvd | + rsvd_bits(maxphyaddr, 51); + context->rsvd_bits_mask[1][3] = context->rsvd_bits_mask[0][3]; + context->rsvd_bits_mask[1][2] = context->rsvd_bits_mask[0][2]; + context->rsvd_bits_mask[1][1] = exb_bit_rsvd | + rsvd_bits(maxphyaddr, 51) | + rsvd_bits(13, 20); /* large page */ + context->rsvd_bits_mask[1][0] = ~0ull; + break; + } +} + static int paging64_init_context_common(struct kvm_vcpu *vcpu, int level) { struct kvm_mmu *context = &vcpu->arch.mmu; @@ -2179,6 +2211,7 @@ static int paging64_init_context_common(struct kvm_vcpu *vcpu, int level) static int paging64_init_context(struct kvm_vcpu *vcpu) { + reset_rsvds_bits_mask(vcpu, PT64_ROOT_LEVEL); return paging64_init_context_common(vcpu, PT64_ROOT_LEVEL); } @@ -2186,6 +2219,7 @@ static int paging32_init_context(struct kvm_vcpu *vcpu) { struct kvm_mmu *context = &vcpu->arch.mmu; + reset_rsvds_bits_mask(vcpu, PT32_ROOT_LEVEL); context->new_cr3 = paging_new_cr3; context->page_fault = paging32_page_fault; context->gva_to_gpa = paging32_gva_to_gpa; @@ -2201,6 +2235,7 @@ static int paging32_init_context(struct kvm_vcpu *vcpu) static int paging32E_init_context(struct kvm_vcpu *vcpu) { + reset_rsvds_bits_mask(vcpu, PT32E_ROOT_LEVEL); return paging64_init_context_common(vcpu, PT32E_ROOT_LEVEL); } @@ -2221,12 +2256,15 @@ static int init_kvm_tdp_mmu(struct kvm_vcpu *vcpu) context->gva_to_gpa = nonpaging_gva_to_gpa; context->root_level = 0; } else if (is_long_mode(vcpu)) { + reset_rsvds_bits_mask(vcpu, PT64_ROOT_LEVEL); context->gva_to_gpa = paging64_gva_to_gpa; context->root_level = PT64_ROOT_LEVEL; } else if (is_pae(vcpu)) { + reset_rsvds_bits_mask(vcpu, PT32E_ROOT_LEVEL); context->gva_to_gpa = paging64_gva_to_gpa; context->root_level = PT32E_ROOT_LEVEL; } else { + reset_rsvds_bits_mask(vcpu, PT32_ROOT_LEVEL); context->gva_to_gpa = paging32_gva_to_gpa; context->root_level = PT32_ROOT_LEVEL; } @@ -2290,9 +2328,11 @@ int kvm_mmu_load(struct kvm_vcpu *vcpu) goto out; spin_lock(&vcpu->kvm->mmu_lock); kvm_mmu_free_some_pages(vcpu); - mmu_alloc_roots(vcpu); + r = mmu_alloc_roots(vcpu); mmu_sync_roots(vcpu); spin_unlock(&vcpu->kvm->mmu_lock); + if (r) + goto out; kvm_x86_ops->set_cr3(vcpu, vcpu->arch.mmu.root_hpa); kvm_mmu_flush_tlb(vcpu); out: @@ -2638,14 +2678,6 @@ EXPORT_SYMBOL_GPL(kvm_disable_tdp); static void free_mmu_pages(struct kvm_vcpu *vcpu) { - struct kvm_mmu_page *sp; - - while (!list_empty(&vcpu->kvm->arch.active_mmu_pages)) { - sp = container_of(vcpu->kvm->arch.active_mmu_pages.next, - struct kvm_mmu_page, link); - kvm_mmu_zap_page(vcpu->kvm, sp); - cond_resched(); - } free_page((unsigned long)vcpu->arch.mmu.pae_root); } @@ -2710,7 +2742,6 @@ void kvm_mmu_slot_remove_write_access(struct kvm *kvm, int slot) { struct kvm_mmu_page *sp; - spin_lock(&kvm->mmu_lock); list_for_each_entry(sp, &kvm->arch.active_mmu_pages, link) { int i; u64 *pt; @@ -2725,7 +2756,6 @@ void kvm_mmu_slot_remove_write_access(struct kvm *kvm, int slot) pt[i] &= ~PT_WRITABLE_MASK; } kvm_flush_remote_tlbs(kvm); - spin_unlock(&kvm->mmu_lock); } void kvm_mmu_zap_all(struct kvm *kvm) @@ -3007,11 +3037,13 @@ static void audit_mappings_page(struct kvm_vcpu *vcpu, u64 page_pte, " in nonleaf level: levels %d gva %lx" " level %d pte %llx\n", audit_msg, vcpu->arch.mmu.root_level, va, level, ent); - - audit_mappings_page(vcpu, ent, va, level - 1); + else + audit_mappings_page(vcpu, ent, va, level - 1); } else { gpa_t gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, va); - hpa_t hpa = (hpa_t)gpa_to_pfn(vcpu, gpa) << PAGE_SHIFT; + gfn_t gfn = gpa >> PAGE_SHIFT; + pfn_t pfn = gfn_to_pfn(vcpu->kvm, gfn); + hpa_t hpa = (hpa_t)pfn << PAGE_SHIFT; if (is_shadow_present_pte(ent) && (ent & PT64_BASE_ADDR_MASK) != hpa) diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h index eaab2145f62b..3494a2fb136e 100644 --- a/arch/x86/kvm/mmu.h +++ b/arch/x86/kvm/mmu.h @@ -75,4 +75,9 @@ static inline int is_paging(struct kvm_vcpu *vcpu) return vcpu->arch.cr0 & X86_CR0_PG; } +static inline int is_present_pte(unsigned long pte) +{ + return pte & PT_PRESENT_MASK; +} + #endif diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h index 6bd70206c561..258e4591e1ca 100644 --- a/arch/x86/kvm/paging_tmpl.h +++ b/arch/x86/kvm/paging_tmpl.h @@ -123,6 +123,7 @@ static int FNAME(walk_addr)(struct guest_walker *walker, gfn_t table_gfn; unsigned index, pt_access, pte_access; gpa_t pte_gpa; + int rsvd_fault = 0; pgprintk("%s: addr %lx\n", __func__, addr); walk: @@ -157,6 +158,10 @@ walk: if (!is_present_pte(pte)) goto not_present; + rsvd_fault = is_rsvd_bits_set(vcpu, pte, walker->level); + if (rsvd_fault) + goto access_error; + if (write_fault && !is_writeble_pte(pte)) if (user_fault || is_write_protection(vcpu)) goto access_error; @@ -209,7 +214,6 @@ walk: if (ret) goto walk; pte |= PT_DIRTY_MASK; - kvm_mmu_pte_write(vcpu, pte_gpa, (u8 *)&pte, sizeof(pte), 0); walker->ptes[walker->level - 1] = pte; } @@ -233,6 +237,8 @@ err: walker->error_code |= PFERR_USER_MASK; if (fetch_fault) walker->error_code |= PFERR_FETCH_MASK; + if (rsvd_fault) + walker->error_code |= PFERR_RSVD_MASK; return 0; } @@ -262,8 +268,7 @@ static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *page, kvm_get_pfn(pfn); mmu_set_spte(vcpu, spte, page->role.access, pte_access, 0, 0, gpte & PT_DIRTY_MASK, NULL, largepage, - gpte & PT_GLOBAL_MASK, gpte_to_gfn(gpte), - pfn, true); + gpte_to_gfn(gpte), pfn, true); } /* @@ -297,7 +302,6 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr, user_fault, write_fault, gw->ptes[gw->level-1] & PT_DIRTY_MASK, ptwrite, largepage, - gw->ptes[gw->level-1] & PT_GLOBAL_MASK, gw->gfn, pfn, false); break; } @@ -380,7 +384,7 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, return r; /* - * Look up the shadow pte for the faulting address. + * Look up the guest pte for the faulting address. */ r = FNAME(walk_addr)(&walker, vcpu, addr, write_fault, user_fault, fetch_fault); @@ -586,7 +590,7 @@ static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp) nr_present++; pte_access = sp->role.access & FNAME(gpte_access)(vcpu, gpte); set_spte(vcpu, &sp->spt[i], pte_access, 0, 0, - is_dirty_pte(gpte), 0, gpte & PT_GLOBAL_MASK, gfn, + is_dirty_pte(gpte), 0, gfn, spte_to_pfn(sp->spt[i]), true, false); } diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 1f8510c51d6e..71510e07e69e 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -19,6 +19,7 @@ #include "irq.h" #include "mmu.h" #include "kvm_cache_regs.h" +#include "x86.h" #include #include @@ -69,7 +70,6 @@ module_param(npt, int, S_IRUGO); static int nested = 0; module_param(nested, int, S_IRUGO); -static void kvm_reput_irq(struct vcpu_svm *svm); static void svm_flush_tlb(struct kvm_vcpu *vcpu); static int nested_svm_exit_handled(struct vcpu_svm *svm, bool kvm_override); @@ -132,24 +132,6 @@ static inline u32 svm_has(u32 feat) return svm_features & feat; } -static inline u8 pop_irq(struct kvm_vcpu *vcpu) -{ - int word_index = __ffs(vcpu->arch.irq_summary); - int bit_index = __ffs(vcpu->arch.irq_pending[word_index]); - int irq = word_index * BITS_PER_LONG + bit_index; - - clear_bit(bit_index, &vcpu->arch.irq_pending[word_index]); - if (!vcpu->arch.irq_pending[word_index]) - clear_bit(word_index, &vcpu->arch.irq_summary); - return irq; -} - -static inline void push_irq(struct kvm_vcpu *vcpu, u8 irq) -{ - set_bit(irq, vcpu->arch.irq_pending); - set_bit(irq / BITS_PER_LONG, &vcpu->arch.irq_summary); -} - static inline void clgi(void) { asm volatile (__ex(SVM_CLGI)); @@ -214,25 +196,41 @@ static void svm_queue_exception(struct kvm_vcpu *vcpu, unsigned nr, svm->vmcb->control.event_inj_err = error_code; } -static bool svm_exception_injected(struct kvm_vcpu *vcpu) -{ - struct vcpu_svm *svm = to_svm(vcpu); - - return !(svm->vmcb->control.exit_int_info & SVM_EXITINTINFO_VALID); -} - static int is_external_interrupt(u32 info) { info &= SVM_EVTINJ_TYPE_MASK | SVM_EVTINJ_VALID; return info == (SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_INTR); } +static u32 svm_get_interrupt_shadow(struct kvm_vcpu *vcpu, int mask) +{ + struct vcpu_svm *svm = to_svm(vcpu); + u32 ret = 0; + + if (svm->vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK) + ret |= X86_SHADOW_INT_STI | X86_SHADOW_INT_MOV_SS; + return ret & mask; +} + +static void svm_set_interrupt_shadow(struct kvm_vcpu *vcpu, int mask) +{ + struct vcpu_svm *svm = to_svm(vcpu); + + if (mask == 0) + svm->vmcb->control.int_state &= ~SVM_INTERRUPT_SHADOW_MASK; + else + svm->vmcb->control.int_state |= SVM_INTERRUPT_SHADOW_MASK; + +} + static void skip_emulated_instruction(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm = to_svm(vcpu); if (!svm->next_rip) { - printk(KERN_DEBUG "%s: NOP\n", __func__); + if (emulate_instruction(vcpu, vcpu->run, 0, 0, EMULTYPE_SKIP) != + EMULATE_DONE) + printk(KERN_DEBUG "%s: NOP\n", __func__); return; } if (svm->next_rip - kvm_rip_read(vcpu) > MAX_INST_SIZE) @@ -240,9 +238,7 @@ static void skip_emulated_instruction(struct kvm_vcpu *vcpu) __func__, kvm_rip_read(vcpu), svm->next_rip); kvm_rip_write(vcpu, svm->next_rip); - svm->vmcb->control.int_state &= ~SVM_INTERRUPT_SHADOW_MASK; - - vcpu->arch.interrupt_window_open = (svm->vcpu.arch.hflags & HF_GIF_MASK); + svm_set_interrupt_shadow(vcpu, 0); } static int has_svm(void) @@ -830,6 +826,15 @@ static void svm_get_segment(struct kvm_vcpu *vcpu, if (!var->unusable) var->type |= 0x1; break; + case VCPU_SREG_SS: + /* On AMD CPUs sometimes the DB bit in the segment + * descriptor is left as 1, although the whole segment has + * been made unusable. Clear it here to pass an Intel VMX + * entry check when cross vendor migrating. + */ + if (var->unusable) + var->db = 0; + break; } } @@ -960,15 +965,16 @@ static void svm_set_segment(struct kvm_vcpu *vcpu, } -static int svm_guest_debug(struct kvm_vcpu *vcpu, struct kvm_guest_debug *dbg) +static void update_db_intercept(struct kvm_vcpu *vcpu) { - int old_debug = vcpu->guest_debug; struct vcpu_svm *svm = to_svm(vcpu); - vcpu->guest_debug = dbg->control; - svm->vmcb->control.intercept_exceptions &= ~((1 << DB_VECTOR) | (1 << BP_VECTOR)); + + if (vcpu->arch.singlestep) + svm->vmcb->control.intercept_exceptions |= (1 << DB_VECTOR); + if (vcpu->guest_debug & KVM_GUESTDBG_ENABLE) { if (vcpu->guest_debug & (KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_USE_HW_BP)) @@ -979,6 +985,16 @@ static int svm_guest_debug(struct kvm_vcpu *vcpu, struct kvm_guest_debug *dbg) 1 << BP_VECTOR; } else vcpu->guest_debug = 0; +} + +static int svm_guest_debug(struct kvm_vcpu *vcpu, struct kvm_guest_debug *dbg) +{ + int old_debug = vcpu->guest_debug; + struct vcpu_svm *svm = to_svm(vcpu); + + vcpu->guest_debug = dbg->control; + + update_db_intercept(vcpu); if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP) svm->vmcb->save.dr7 = dbg->arch.debugreg[7]; @@ -993,16 +1009,6 @@ static int svm_guest_debug(struct kvm_vcpu *vcpu, struct kvm_guest_debug *dbg) return 0; } -static int svm_get_irq(struct kvm_vcpu *vcpu) -{ - struct vcpu_svm *svm = to_svm(vcpu); - u32 exit_int_info = svm->vmcb->control.exit_int_info; - - if (is_external_interrupt(exit_int_info)) - return exit_int_info & SVM_EVTINJ_VEC_MASK; - return -1; -} - static void load_host_msrs(struct kvm_vcpu *vcpu) { #ifdef CONFIG_X86_64 @@ -1107,17 +1113,8 @@ static void svm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long value, static int pf_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) { - u32 exit_int_info = svm->vmcb->control.exit_int_info; - struct kvm *kvm = svm->vcpu.kvm; u64 fault_address; u32 error_code; - bool event_injection = false; - - if (!irqchip_in_kernel(kvm) && - is_external_interrupt(exit_int_info)) { - event_injection = true; - push_irq(&svm->vcpu, exit_int_info & SVM_EVTINJ_VEC_MASK); - } fault_address = svm->vmcb->control.exit_info_2; error_code = svm->vmcb->control.exit_info_1; @@ -1137,23 +1134,40 @@ static int pf_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) */ if (npt_enabled) svm_flush_tlb(&svm->vcpu); - - if (!npt_enabled && event_injection) - kvm_mmu_unprotect_page_virt(&svm->vcpu, fault_address); + else { + if (kvm_event_needs_reinjection(&svm->vcpu)) + kvm_mmu_unprotect_page_virt(&svm->vcpu, fault_address); + } return kvm_mmu_page_fault(&svm->vcpu, fault_address, error_code); } static int db_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) { if (!(svm->vcpu.guest_debug & - (KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_USE_HW_BP))) { + (KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_USE_HW_BP)) && + !svm->vcpu.arch.singlestep) { kvm_queue_exception(&svm->vcpu, DB_VECTOR); return 1; } - kvm_run->exit_reason = KVM_EXIT_DEBUG; - kvm_run->debug.arch.pc = svm->vmcb->save.cs.base + svm->vmcb->save.rip; - kvm_run->debug.arch.exception = DB_VECTOR; - return 0; + + if (svm->vcpu.arch.singlestep) { + svm->vcpu.arch.singlestep = false; + if (!(svm->vcpu.guest_debug & KVM_GUESTDBG_SINGLESTEP)) + svm->vmcb->save.rflags &= + ~(X86_EFLAGS_TF | X86_EFLAGS_RF); + update_db_intercept(&svm->vcpu); + } + + if (svm->vcpu.guest_debug & + (KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_USE_HW_BP)){ + kvm_run->exit_reason = KVM_EXIT_DEBUG; + kvm_run->debug.arch.pc = + svm->vmcb->save.cs.base + svm->vmcb->save.rip; + kvm_run->debug.arch.exception = DB_VECTOR; + return 0; + } + + return 1; } static int bp_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) @@ -1842,17 +1856,51 @@ static int task_switch_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) { u16 tss_selector; + int reason; + int int_type = svm->vmcb->control.exit_int_info & + SVM_EXITINTINFO_TYPE_MASK; + int int_vec = svm->vmcb->control.exit_int_info & SVM_EVTINJ_VEC_MASK; + uint32_t type = + svm->vmcb->control.exit_int_info & SVM_EXITINTINFO_TYPE_MASK; + uint32_t idt_v = + svm->vmcb->control.exit_int_info & SVM_EXITINTINFO_VALID; tss_selector = (u16)svm->vmcb->control.exit_info_1; + if (svm->vmcb->control.exit_info_2 & (1ULL << SVM_EXITINFOSHIFT_TS_REASON_IRET)) - return kvm_task_switch(&svm->vcpu, tss_selector, - TASK_SWITCH_IRET); - if (svm->vmcb->control.exit_info_2 & - (1ULL << SVM_EXITINFOSHIFT_TS_REASON_JMP)) - return kvm_task_switch(&svm->vcpu, tss_selector, - TASK_SWITCH_JMP); - return kvm_task_switch(&svm->vcpu, tss_selector, TASK_SWITCH_CALL); + reason = TASK_SWITCH_IRET; + else if (svm->vmcb->control.exit_info_2 & + (1ULL << SVM_EXITINFOSHIFT_TS_REASON_JMP)) + reason = TASK_SWITCH_JMP; + else if (idt_v) + reason = TASK_SWITCH_GATE; + else + reason = TASK_SWITCH_CALL; + + if (reason == TASK_SWITCH_GATE) { + switch (type) { + case SVM_EXITINTINFO_TYPE_NMI: + svm->vcpu.arch.nmi_injected = false; + break; + case SVM_EXITINTINFO_TYPE_EXEPT: + kvm_clear_exception_queue(&svm->vcpu); + break; + case SVM_EXITINTINFO_TYPE_INTR: + kvm_clear_interrupt_queue(&svm->vcpu); + break; + default: + break; + } + } + + if (reason != TASK_SWITCH_GATE || + int_type == SVM_EXITINTINFO_TYPE_SOFT || + (int_type == SVM_EXITINTINFO_TYPE_EXEPT && + (int_vec == OF_VECTOR || int_vec == BP_VECTOR))) + skip_emulated_instruction(&svm->vcpu); + + return kvm_task_switch(&svm->vcpu, tss_selector, reason); } static int cpuid_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) @@ -1862,6 +1910,14 @@ static int cpuid_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) return 1; } +static int iret_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) +{ + ++svm->vcpu.stat.nmi_window_exits; + svm->vmcb->control.intercept &= ~(1UL << INTERCEPT_IRET); + svm->vcpu.arch.hflags |= HF_IRET_MASK; + return 1; +} + static int invlpg_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) { if (emulate_instruction(&svm->vcpu, kvm_run, 0, 0, 0) != EMULATE_DONE) @@ -1879,8 +1935,14 @@ static int emulate_on_interception(struct vcpu_svm *svm, static int cr8_write_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) { + u8 cr8_prev = kvm_get_cr8(&svm->vcpu); + /* instruction emulation calls kvm_set_cr8() */ emulate_instruction(&svm->vcpu, NULL, 0, 0, 0); - if (irqchip_in_kernel(svm->vcpu.kvm)) + if (irqchip_in_kernel(svm->vcpu.kvm)) { + svm->vmcb->control.intercept_cr_write &= ~INTERCEPT_CR8_MASK; + return 1; + } + if (cr8_prev <= kvm_get_cr8(&svm->vcpu)) return 1; kvm_run->exit_reason = KVM_EXIT_SET_TPR; return 0; @@ -2090,8 +2152,9 @@ static int interrupt_window_interception(struct vcpu_svm *svm, * If the user space waits to inject interrupts, exit as soon as * possible */ - if (kvm_run->request_interrupt_window && - !svm->vcpu.arch.irq_summary) { + if (!irqchip_in_kernel(svm->vcpu.kvm) && + kvm_run->request_interrupt_window && + !kvm_cpu_has_interrupt(&svm->vcpu)) { ++svm->vcpu.stat.irq_window_exits; kvm_run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN; return 0; @@ -2134,6 +2197,7 @@ static int (*svm_exit_handlers[])(struct vcpu_svm *svm, [SVM_EXIT_VINTR] = interrupt_window_interception, /* [SVM_EXIT_CR0_SEL_WRITE] = emulate_on_interception, */ [SVM_EXIT_CPUID] = cpuid_interception, + [SVM_EXIT_IRET] = iret_interception, [SVM_EXIT_INVD] = emulate_on_interception, [SVM_EXIT_HLT] = halt_interception, [SVM_EXIT_INVLPG] = invlpg_interception, @@ -2194,7 +2258,6 @@ static int handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) } } - kvm_reput_irq(svm); if (svm->vmcb->control.exit_code == SVM_EXIT_ERR) { kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY; @@ -2205,7 +2268,7 @@ static int handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) if (is_external_interrupt(svm->vmcb->control.exit_int_info) && exit_code != SVM_EXIT_EXCP_BASE + PF_VECTOR && - exit_code != SVM_EXIT_NPF) + exit_code != SVM_EXIT_NPF && exit_code != SVM_EXIT_TASK_SWITCH) printk(KERN_ERR "%s: unexpected exit_ini_info 0x%x " "exit_code 0x%x\n", __func__, svm->vmcb->control.exit_int_info, @@ -2242,6 +2305,15 @@ static void pre_svm_run(struct vcpu_svm *svm) new_asid(svm, svm_data); } +static void svm_inject_nmi(struct kvm_vcpu *vcpu) +{ + struct vcpu_svm *svm = to_svm(vcpu); + + svm->vmcb->control.event_inj = SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_NMI; + vcpu->arch.hflags |= HF_NMI_MASK; + svm->vmcb->control.intercept |= (1UL << INTERCEPT_IRET); + ++vcpu->stat.nmi_injections; +} static inline void svm_inject_irq(struct vcpu_svm *svm, int irq) { @@ -2257,134 +2329,71 @@ static inline void svm_inject_irq(struct vcpu_svm *svm, int irq) ((/*control->int_vector >> 4*/ 0xf) << V_INTR_PRIO_SHIFT); } -static void svm_set_irq(struct kvm_vcpu *vcpu, int irq) +static void svm_queue_irq(struct kvm_vcpu *vcpu, unsigned nr) +{ + struct vcpu_svm *svm = to_svm(vcpu); + + svm->vmcb->control.event_inj = nr | + SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_INTR; +} + +static void svm_set_irq(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm = to_svm(vcpu); nested_svm_intr(svm); - svm_inject_irq(svm, irq); + svm_queue_irq(vcpu, vcpu->arch.interrupt.nr); } -static void update_cr8_intercept(struct kvm_vcpu *vcpu) +static void update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr) +{ + struct vcpu_svm *svm = to_svm(vcpu); + + if (irr == -1) + return; + + if (tpr >= irr) + svm->vmcb->control.intercept_cr_write |= INTERCEPT_CR8_MASK; +} + +static int svm_nmi_allowed(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm = to_svm(vcpu); struct vmcb *vmcb = svm->vmcb; - int max_irr, tpr; - - if (!irqchip_in_kernel(vcpu->kvm) || vcpu->arch.apic->vapic_addr) - return; - - vmcb->control.intercept_cr_write &= ~INTERCEPT_CR8_MASK; - - max_irr = kvm_lapic_find_highest_irr(vcpu); - if (max_irr == -1) - return; - - tpr = kvm_lapic_get_cr8(vcpu) << 4; - - if (tpr >= (max_irr & 0xf0)) - vmcb->control.intercept_cr_write |= INTERCEPT_CR8_MASK; + return !(vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK) && + !(svm->vcpu.arch.hflags & HF_NMI_MASK); } -static void svm_intr_assist(struct kvm_vcpu *vcpu) +static int svm_interrupt_allowed(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm = to_svm(vcpu); struct vmcb *vmcb = svm->vmcb; - int intr_vector = -1; - - if ((vmcb->control.exit_int_info & SVM_EVTINJ_VALID) && - ((vmcb->control.exit_int_info & SVM_EVTINJ_TYPE_MASK) == 0)) { - intr_vector = vmcb->control.exit_int_info & - SVM_EVTINJ_VEC_MASK; - vmcb->control.exit_int_info = 0; - svm_inject_irq(svm, intr_vector); - goto out; - } - - if (vmcb->control.int_ctl & V_IRQ_MASK) - goto out; - - if (!kvm_cpu_has_interrupt(vcpu)) - goto out; - - if (nested_svm_intr(svm)) - goto out; - - if (!(svm->vcpu.arch.hflags & HF_GIF_MASK)) - goto out; - - if (!(vmcb->save.rflags & X86_EFLAGS_IF) || - (vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK) || - (vmcb->control.event_inj & SVM_EVTINJ_VALID)) { - /* unable to deliver irq, set pending irq */ - svm_set_vintr(svm); - svm_inject_irq(svm, 0x0); - goto out; - } - /* Okay, we can deliver the interrupt: grab it and update PIC state. */ - intr_vector = kvm_cpu_get_interrupt(vcpu); - svm_inject_irq(svm, intr_vector); -out: - update_cr8_intercept(vcpu); + return (vmcb->save.rflags & X86_EFLAGS_IF) && + !(vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK) && + (svm->vcpu.arch.hflags & HF_GIF_MASK); } -static void kvm_reput_irq(struct vcpu_svm *svm) +static void enable_irq_window(struct kvm_vcpu *vcpu) { - struct vmcb_control_area *control = &svm->vmcb->control; - - if ((control->int_ctl & V_IRQ_MASK) - && !irqchip_in_kernel(svm->vcpu.kvm)) { - control->int_ctl &= ~V_IRQ_MASK; - push_irq(&svm->vcpu, control->int_vector); - } - - svm->vcpu.arch.interrupt_window_open = - !(control->int_state & SVM_INTERRUPT_SHADOW_MASK) && - (svm->vcpu.arch.hflags & HF_GIF_MASK); + svm_set_vintr(to_svm(vcpu)); + svm_inject_irq(to_svm(vcpu), 0x0); } -static void svm_do_inject_vector(struct vcpu_svm *svm) -{ - struct kvm_vcpu *vcpu = &svm->vcpu; - int word_index = __ffs(vcpu->arch.irq_summary); - int bit_index = __ffs(vcpu->arch.irq_pending[word_index]); - int irq = word_index * BITS_PER_LONG + bit_index; - - clear_bit(bit_index, &vcpu->arch.irq_pending[word_index]); - if (!vcpu->arch.irq_pending[word_index]) - clear_bit(word_index, &vcpu->arch.irq_summary); - svm_inject_irq(svm, irq); -} - -static void do_interrupt_requests(struct kvm_vcpu *vcpu, - struct kvm_run *kvm_run) +static void enable_nmi_window(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm = to_svm(vcpu); - struct vmcb_control_area *control = &svm->vmcb->control; - if (nested_svm_intr(svm)) - return; + if ((svm->vcpu.arch.hflags & (HF_NMI_MASK | HF_IRET_MASK)) + == HF_NMI_MASK) + return; /* IRET will cause a vm exit */ - svm->vcpu.arch.interrupt_window_open = - (!(control->int_state & SVM_INTERRUPT_SHADOW_MASK) && - (svm->vmcb->save.rflags & X86_EFLAGS_IF) && - (svm->vcpu.arch.hflags & HF_GIF_MASK)); - - if (svm->vcpu.arch.interrupt_window_open && svm->vcpu.arch.irq_summary) - /* - * If interrupts enabled, and not blocked by sti or mov ss. Good. - */ - svm_do_inject_vector(svm); - - /* - * Interrupts blocked. Wait for unblock. - */ - if (!svm->vcpu.arch.interrupt_window_open && - (svm->vcpu.arch.irq_summary || kvm_run->request_interrupt_window)) - svm_set_vintr(svm); - else - svm_clear_vintr(svm); + /* Something prevents NMI from been injected. Single step over + possible problem (IRET or exception injection or interrupt + shadow) */ + vcpu->arch.singlestep = true; + svm->vmcb->save.rflags |= (X86_EFLAGS_TF | X86_EFLAGS_RF); + update_db_intercept(vcpu); } static int svm_set_tss_addr(struct kvm *kvm, unsigned int addr) @@ -2407,7 +2416,7 @@ static inline void sync_cr8_to_lapic(struct kvm_vcpu *vcpu) if (!(svm->vmcb->control.intercept_cr_write & INTERCEPT_CR8_MASK)) { int cr8 = svm->vmcb->control.int_ctl & V_TPR_MASK; - kvm_lapic_set_tpr(vcpu, cr8); + kvm_set_cr8(vcpu, cr8); } } @@ -2416,14 +2425,54 @@ static inline void sync_lapic_to_cr8(struct kvm_vcpu *vcpu) struct vcpu_svm *svm = to_svm(vcpu); u64 cr8; - if (!irqchip_in_kernel(vcpu->kvm)) - return; - cr8 = kvm_get_cr8(vcpu); svm->vmcb->control.int_ctl &= ~V_TPR_MASK; svm->vmcb->control.int_ctl |= cr8 & V_TPR_MASK; } +static void svm_complete_interrupts(struct vcpu_svm *svm) +{ + u8 vector; + int type; + u32 exitintinfo = svm->vmcb->control.exit_int_info; + + if (svm->vcpu.arch.hflags & HF_IRET_MASK) + svm->vcpu.arch.hflags &= ~(HF_NMI_MASK | HF_IRET_MASK); + + svm->vcpu.arch.nmi_injected = false; + kvm_clear_exception_queue(&svm->vcpu); + kvm_clear_interrupt_queue(&svm->vcpu); + + if (!(exitintinfo & SVM_EXITINTINFO_VALID)) + return; + + vector = exitintinfo & SVM_EXITINTINFO_VEC_MASK; + type = exitintinfo & SVM_EXITINTINFO_TYPE_MASK; + + switch (type) { + case SVM_EXITINTINFO_TYPE_NMI: + svm->vcpu.arch.nmi_injected = true; + break; + case SVM_EXITINTINFO_TYPE_EXEPT: + /* In case of software exception do not reinject an exception + vector, but re-execute and instruction instead */ + if (kvm_exception_is_soft(vector)) + break; + if (exitintinfo & SVM_EXITINTINFO_VALID_ERR) { + u32 err = svm->vmcb->control.exit_int_info_err; + kvm_queue_exception_e(&svm->vcpu, vector, err); + + } else + kvm_queue_exception(&svm->vcpu, vector); + break; + case SVM_EXITINTINFO_TYPE_INTR: + kvm_queue_interrupt(&svm->vcpu, vector, false); + break; + default: + break; + } +} + #ifdef CONFIG_X86_64 #define R "r" #else @@ -2552,6 +2601,8 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) sync_cr8_to_lapic(vcpu); svm->next_rip = 0; + + svm_complete_interrupts(svm); } #undef R @@ -2617,7 +2668,7 @@ static int get_npt_level(void) #endif } -static int svm_get_mt_mask_shift(void) +static u64 svm_get_mt_mask(struct kvm_vcpu *vcpu, gfn_t gfn, bool is_mmio) { return 0; } @@ -2667,17 +2718,21 @@ static struct kvm_x86_ops svm_x86_ops = { .run = svm_vcpu_run, .handle_exit = handle_exit, .skip_emulated_instruction = skip_emulated_instruction, + .set_interrupt_shadow = svm_set_interrupt_shadow, + .get_interrupt_shadow = svm_get_interrupt_shadow, .patch_hypercall = svm_patch_hypercall, - .get_irq = svm_get_irq, .set_irq = svm_set_irq, + .set_nmi = svm_inject_nmi, .queue_exception = svm_queue_exception, - .exception_injected = svm_exception_injected, - .inject_pending_irq = svm_intr_assist, - .inject_pending_vectors = do_interrupt_requests, + .interrupt_allowed = svm_interrupt_allowed, + .nmi_allowed = svm_nmi_allowed, + .enable_nmi_window = enable_nmi_window, + .enable_irq_window = enable_irq_window, + .update_cr8_intercept = update_cr8_intercept, .set_tss_addr = svm_set_tss_addr, .get_tdp_level = get_npt_level, - .get_mt_mask_shift = svm_get_mt_mask_shift, + .get_mt_mask = svm_get_mt_mask, }; static int __init svm_init(void) diff --git a/arch/x86/kvm/timer.c b/arch/x86/kvm/timer.c new file mode 100644 index 000000000000..86dbac072d0c --- /dev/null +++ b/arch/x86/kvm/timer.c @@ -0,0 +1,46 @@ +#include +#include +#include +#include +#include "kvm_timer.h" + +static int __kvm_timer_fn(struct kvm_vcpu *vcpu, struct kvm_timer *ktimer) +{ + int restart_timer = 0; + wait_queue_head_t *q = &vcpu->wq; + + /* FIXME: this code should not know anything about vcpus */ + if (!atomic_inc_and_test(&ktimer->pending)) + set_bit(KVM_REQ_PENDING_TIMER, &vcpu->requests); + + if (!ktimer->reinject) + atomic_set(&ktimer->pending, 1); + + if (waitqueue_active(q)) + wake_up_interruptible(q); + + if (ktimer->t_ops->is_periodic(ktimer)) { + hrtimer_add_expires_ns(&ktimer->timer, ktimer->period); + restart_timer = 1; + } + + return restart_timer; +} + +enum hrtimer_restart kvm_timer_fn(struct hrtimer *data) +{ + int restart_timer; + struct kvm_vcpu *vcpu; + struct kvm_timer *ktimer = container_of(data, struct kvm_timer, timer); + + vcpu = ktimer->kvm->vcpus[ktimer->vcpu_id]; + if (!vcpu) + return HRTIMER_NORESTART; + + restart_timer = __kvm_timer_fn(vcpu, ktimer); + if (restart_timer) + return HRTIMER_RESTART; + else + return HRTIMER_NORESTART; +} + diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index bb481330716f..e770bf349ec4 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -32,26 +32,27 @@ #include #include #include +#include #define __ex(x) __kvm_handle_fault_on_reboot(x) MODULE_AUTHOR("Qumranet"); MODULE_LICENSE("GPL"); -static int bypass_guest_pf = 1; -module_param(bypass_guest_pf, bool, 0); +static int __read_mostly bypass_guest_pf = 1; +module_param(bypass_guest_pf, bool, S_IRUGO); -static int enable_vpid = 1; -module_param(enable_vpid, bool, 0); +static int __read_mostly enable_vpid = 1; +module_param_named(vpid, enable_vpid, bool, 0444); -static int flexpriority_enabled = 1; -module_param(flexpriority_enabled, bool, 0); +static int __read_mostly flexpriority_enabled = 1; +module_param_named(flexpriority, flexpriority_enabled, bool, S_IRUGO); -static int enable_ept = 1; -module_param(enable_ept, bool, 0); +static int __read_mostly enable_ept = 1; +module_param_named(ept, enable_ept, bool, S_IRUGO); -static int emulate_invalid_guest_state = 0; -module_param(emulate_invalid_guest_state, bool, 0); +static int __read_mostly emulate_invalid_guest_state = 0; +module_param(emulate_invalid_guest_state, bool, S_IRUGO); struct vmcs { u32 revision_id; @@ -97,6 +98,7 @@ struct vcpu_vmx { int soft_vnmi_blocked; ktime_t entry_time; s64 vnmi_blocked_time; + u32 exit_reason; }; static inline struct vcpu_vmx *to_vmx(struct kvm_vcpu *vcpu) @@ -111,9 +113,10 @@ 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; -static struct page *vmx_msr_bitmap; +static unsigned long *vmx_io_bitmap_a; +static unsigned long *vmx_io_bitmap_b; +static unsigned long *vmx_msr_bitmap_legacy; +static unsigned long *vmx_msr_bitmap_longmode; static DECLARE_BITMAP(vmx_vpid_bitmap, VMX_NR_VPIDS); static DEFINE_SPINLOCK(vmx_vpid_lock); @@ -213,70 +216,78 @@ static inline int is_external_interrupt(u32 intr_info) == (INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK); } +static inline int is_machine_check(u32 intr_info) +{ + return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK | + INTR_INFO_VALID_MASK)) == + (INTR_TYPE_HARD_EXCEPTION | MC_VECTOR | INTR_INFO_VALID_MASK); +} + static inline int cpu_has_vmx_msr_bitmap(void) { - return (vmcs_config.cpu_based_exec_ctrl & CPU_BASED_USE_MSR_BITMAPS); + return vmcs_config.cpu_based_exec_ctrl & CPU_BASED_USE_MSR_BITMAPS; } static inline int cpu_has_vmx_tpr_shadow(void) { - return (vmcs_config.cpu_based_exec_ctrl & CPU_BASED_TPR_SHADOW); + return vmcs_config.cpu_based_exec_ctrl & CPU_BASED_TPR_SHADOW; } static inline int vm_need_tpr_shadow(struct kvm *kvm) { - return ((cpu_has_vmx_tpr_shadow()) && (irqchip_in_kernel(kvm))); + return (cpu_has_vmx_tpr_shadow()) && (irqchip_in_kernel(kvm)); } static inline int cpu_has_secondary_exec_ctrls(void) { - return (vmcs_config.cpu_based_exec_ctrl & - CPU_BASED_ACTIVATE_SECONDARY_CONTROLS); + return vmcs_config.cpu_based_exec_ctrl & + CPU_BASED_ACTIVATE_SECONDARY_CONTROLS; } static inline bool cpu_has_vmx_virtualize_apic_accesses(void) { - return flexpriority_enabled - && (vmcs_config.cpu_based_2nd_exec_ctrl & - SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES); + return vmcs_config.cpu_based_2nd_exec_ctrl & + SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES; +} + +static inline bool cpu_has_vmx_flexpriority(void) +{ + return cpu_has_vmx_tpr_shadow() && + cpu_has_vmx_virtualize_apic_accesses(); } static inline int cpu_has_vmx_invept_individual_addr(void) { - return (!!(vmx_capability.ept & VMX_EPT_EXTENT_INDIVIDUAL_BIT)); + return !!(vmx_capability.ept & VMX_EPT_EXTENT_INDIVIDUAL_BIT); } static inline int cpu_has_vmx_invept_context(void) { - return (!!(vmx_capability.ept & VMX_EPT_EXTENT_CONTEXT_BIT)); + return !!(vmx_capability.ept & VMX_EPT_EXTENT_CONTEXT_BIT); } static inline int cpu_has_vmx_invept_global(void) { - return (!!(vmx_capability.ept & VMX_EPT_EXTENT_GLOBAL_BIT)); + return !!(vmx_capability.ept & VMX_EPT_EXTENT_GLOBAL_BIT); } static inline int cpu_has_vmx_ept(void) { - return (vmcs_config.cpu_based_2nd_exec_ctrl & - SECONDARY_EXEC_ENABLE_EPT); -} - -static inline int vm_need_ept(void) -{ - return (cpu_has_vmx_ept() && enable_ept); + return vmcs_config.cpu_based_2nd_exec_ctrl & + SECONDARY_EXEC_ENABLE_EPT; } static inline int vm_need_virtualize_apic_accesses(struct kvm *kvm) { - return ((cpu_has_vmx_virtualize_apic_accesses()) && - (irqchip_in_kernel(kvm))); + return flexpriority_enabled && + (cpu_has_vmx_virtualize_apic_accesses()) && + (irqchip_in_kernel(kvm)); } static inline int cpu_has_vmx_vpid(void) { - return (vmcs_config.cpu_based_2nd_exec_ctrl & - SECONDARY_EXEC_ENABLE_VPID); + return vmcs_config.cpu_based_2nd_exec_ctrl & + SECONDARY_EXEC_ENABLE_VPID; } static inline int cpu_has_virtual_nmis(void) @@ -284,6 +295,11 @@ static inline int cpu_has_virtual_nmis(void) return vmcs_config.pin_based_exec_ctrl & PIN_BASED_VIRTUAL_NMIS; } +static inline bool report_flexpriority(void) +{ + return flexpriority_enabled; +} + static int __find_msr_index(struct vcpu_vmx *vmx, u32 msr) { int i; @@ -381,7 +397,7 @@ static inline void ept_sync_global(void) static inline void ept_sync_context(u64 eptp) { - if (vm_need_ept()) { + if (enable_ept) { if (cpu_has_vmx_invept_context()) __invept(VMX_EPT_EXTENT_CONTEXT, eptp, 0); else @@ -391,7 +407,7 @@ static inline void ept_sync_context(u64 eptp) static inline void ept_sync_individual_addr(u64 eptp, gpa_t gpa) { - if (vm_need_ept()) { + if (enable_ept) { if (cpu_has_vmx_invept_individual_addr()) __invept(VMX_EPT_EXTENT_INDIVIDUAL_ADDR, eptp, gpa); @@ -478,7 +494,7 @@ static void update_exception_bitmap(struct kvm_vcpu *vcpu) { u32 eb; - eb = (1u << PF_VECTOR) | (1u << UD_VECTOR); + eb = (1u << PF_VECTOR) | (1u << UD_VECTOR) | (1u << MC_VECTOR); if (!vcpu->fpu_active) eb |= 1u << NM_VECTOR; if (vcpu->guest_debug & KVM_GUESTDBG_ENABLE) { @@ -488,9 +504,9 @@ static void update_exception_bitmap(struct kvm_vcpu *vcpu) if (vcpu->guest_debug & KVM_GUESTDBG_USE_SW_BP) eb |= 1u << BP_VECTOR; } - if (vcpu->arch.rmode.active) + if (vcpu->arch.rmode.vm86_active) eb = ~0; - if (vm_need_ept()) + if (enable_ept) eb &= ~(1u << PF_VECTOR); /* bypass_guest_pf = 0 */ vmcs_write32(EXCEPTION_BITMAP, eb); } @@ -724,29 +740,50 @@ static unsigned long vmx_get_rflags(struct kvm_vcpu *vcpu) static void vmx_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags) { - if (vcpu->arch.rmode.active) + if (vcpu->arch.rmode.vm86_active) rflags |= X86_EFLAGS_IOPL | X86_EFLAGS_VM; vmcs_writel(GUEST_RFLAGS, rflags); } +static u32 vmx_get_interrupt_shadow(struct kvm_vcpu *vcpu, int mask) +{ + u32 interruptibility = vmcs_read32(GUEST_INTERRUPTIBILITY_INFO); + int ret = 0; + + if (interruptibility & GUEST_INTR_STATE_STI) + ret |= X86_SHADOW_INT_STI; + if (interruptibility & GUEST_INTR_STATE_MOV_SS) + ret |= X86_SHADOW_INT_MOV_SS; + + return ret & mask; +} + +static void vmx_set_interrupt_shadow(struct kvm_vcpu *vcpu, int mask) +{ + u32 interruptibility_old = vmcs_read32(GUEST_INTERRUPTIBILITY_INFO); + u32 interruptibility = interruptibility_old; + + interruptibility &= ~(GUEST_INTR_STATE_STI | GUEST_INTR_STATE_MOV_SS); + + if (mask & X86_SHADOW_INT_MOV_SS) + interruptibility |= GUEST_INTR_STATE_MOV_SS; + if (mask & X86_SHADOW_INT_STI) + interruptibility |= GUEST_INTR_STATE_STI; + + if ((interruptibility != interruptibility_old)) + vmcs_write32(GUEST_INTERRUPTIBILITY_INFO, interruptibility); +} + static void skip_emulated_instruction(struct kvm_vcpu *vcpu) { unsigned long rip; - u32 interruptibility; rip = kvm_rip_read(vcpu); rip += vmcs_read32(VM_EXIT_INSTRUCTION_LEN); kvm_rip_write(vcpu, rip); - /* - * We emulated an instruction, so temporary interrupt blocking - * should be removed, if set. - */ - interruptibility = vmcs_read32(GUEST_INTERRUPTIBILITY_INFO); - if (interruptibility & 3) - vmcs_write32(GUEST_INTERRUPTIBILITY_INFO, - interruptibility & ~3); - vcpu->arch.interrupt_window_open = 1; + /* skipping an emulated instruction also counts */ + vmx_set_interrupt_shadow(vcpu, 0); } static void vmx_queue_exception(struct kvm_vcpu *vcpu, unsigned nr, @@ -760,7 +797,7 @@ static void vmx_queue_exception(struct kvm_vcpu *vcpu, unsigned nr, intr_info |= INTR_INFO_DELIVER_CODE_MASK; } - if (vcpu->arch.rmode.active) { + if (vcpu->arch.rmode.vm86_active) { vmx->rmode.irq.pending = true; vmx->rmode.irq.vector = nr; vmx->rmode.irq.rip = kvm_rip_read(vcpu); @@ -773,8 +810,9 @@ static void vmx_queue_exception(struct kvm_vcpu *vcpu, unsigned nr, return; } - if (nr == BP_VECTOR || nr == OF_VECTOR) { - vmcs_write32(VM_ENTRY_INSTRUCTION_LEN, 1); + if (kvm_exception_is_soft(nr)) { + vmcs_write32(VM_ENTRY_INSTRUCTION_LEN, + vmx->vcpu.arch.event_exit_inst_len); intr_info |= INTR_TYPE_SOFT_EXCEPTION; } else intr_info |= INTR_TYPE_HARD_EXCEPTION; @@ -782,11 +820,6 @@ static void vmx_queue_exception(struct kvm_vcpu *vcpu, unsigned nr, vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, intr_info); } -static bool vmx_exception_injected(struct kvm_vcpu *vcpu) -{ - return false; -} - /* * Swap MSR entry in host/guest MSR entry array. */ @@ -812,6 +845,7 @@ static void move_msr_up(struct vcpu_vmx *vmx, int from, int to) static void setup_msrs(struct vcpu_vmx *vmx) { int save_nmsrs; + unsigned long *msr_bitmap; vmx_load_host_state(vmx); save_nmsrs = 0; @@ -847,6 +881,15 @@ static void setup_msrs(struct vcpu_vmx *vmx) __find_msr_index(vmx, MSR_KERNEL_GS_BASE); #endif vmx->msr_offset_efer = __find_msr_index(vmx, MSR_EFER); + + if (cpu_has_vmx_msr_bitmap()) { + if (is_long_mode(&vmx->vcpu)) + msr_bitmap = vmx_msr_bitmap_longmode; + else + msr_bitmap = vmx_msr_bitmap_legacy; + + vmcs_write64(MSR_BITMAP, __pa(msr_bitmap)); + } } /* @@ -1034,13 +1077,6 @@ static int set_guest_debug(struct kvm_vcpu *vcpu, struct kvm_guest_debug *dbg) return 0; } -static int vmx_get_irq(struct kvm_vcpu *vcpu) -{ - if (!vcpu->arch.interrupt.pending) - return -1; - return vcpu->arch.interrupt.nr; -} - static __init int cpu_has_kvm_support(void) { return cpu_has_vmx(); @@ -1241,7 +1277,7 @@ static struct vmcs *alloc_vmcs_cpu(int cpu) struct page *pages; struct vmcs *vmcs; - pages = alloc_pages_node(node, GFP_KERNEL, vmcs_config.order); + pages = alloc_pages_exact_node(node, GFP_KERNEL, vmcs_config.order); if (!pages) return NULL; vmcs = page_address(pages); @@ -1294,6 +1330,18 @@ static __init int hardware_setup(void) if (boot_cpu_has(X86_FEATURE_NX)) kvm_enable_efer_bits(EFER_NX); + if (!cpu_has_vmx_vpid()) + enable_vpid = 0; + + if (!cpu_has_vmx_ept()) + enable_ept = 0; + + if (!cpu_has_vmx_flexpriority()) + flexpriority_enabled = 0; + + if (!cpu_has_vmx_tpr_shadow()) + kvm_x86_ops->update_cr8_intercept = NULL; + return alloc_kvm_area(); } @@ -1324,7 +1372,7 @@ static void enter_pmode(struct kvm_vcpu *vcpu) struct vcpu_vmx *vmx = to_vmx(vcpu); vmx->emulation_required = 1; - vcpu->arch.rmode.active = 0; + vcpu->arch.rmode.vm86_active = 0; vmcs_writel(GUEST_TR_BASE, vcpu->arch.rmode.tr.base); vmcs_write32(GUEST_TR_LIMIT, vcpu->arch.rmode.tr.limit); @@ -1386,7 +1434,7 @@ static void enter_rmode(struct kvm_vcpu *vcpu) struct vcpu_vmx *vmx = to_vmx(vcpu); vmx->emulation_required = 1; - vcpu->arch.rmode.active = 1; + vcpu->arch.rmode.vm86_active = 1; vcpu->arch.rmode.tr.base = vmcs_readl(GUEST_TR_BASE); vmcs_writel(GUEST_TR_BASE, rmode_tss_base(vcpu->kvm)); @@ -1485,7 +1533,7 @@ 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()) + if (enable_ept) ept_sync_context(construct_eptp(vcpu->arch.mmu.root_hpa)); } @@ -1555,10 +1603,10 @@ static void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) vmx_fpu_deactivate(vcpu); - if (vcpu->arch.rmode.active && (cr0 & X86_CR0_PE)) + if (vcpu->arch.rmode.vm86_active && (cr0 & X86_CR0_PE)) enter_pmode(vcpu); - if (!vcpu->arch.rmode.active && !(cr0 & X86_CR0_PE)) + if (!vcpu->arch.rmode.vm86_active && !(cr0 & X86_CR0_PE)) enter_rmode(vcpu); #ifdef CONFIG_X86_64 @@ -1570,7 +1618,7 @@ static void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) } #endif - if (vm_need_ept()) + if (enable_ept) ept_update_paging_mode_cr0(&hw_cr0, cr0, vcpu); vmcs_writel(CR0_READ_SHADOW, cr0); @@ -1599,7 +1647,7 @@ static void vmx_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3) u64 eptp; guest_cr3 = cr3; - if (vm_need_ept()) { + if (enable_ept) { eptp = construct_eptp(cr3); vmcs_write64(EPT_POINTER, eptp); ept_sync_context(eptp); @@ -1616,11 +1664,11 @@ static void vmx_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3) static void vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) { - unsigned long hw_cr4 = cr4 | (vcpu->arch.rmode.active ? + unsigned long hw_cr4 = cr4 | (vcpu->arch.rmode.vm86_active ? KVM_RMODE_VM_CR4_ALWAYS_ON : KVM_PMODE_VM_CR4_ALWAYS_ON); vcpu->arch.cr4 = cr4; - if (vm_need_ept()) + if (enable_ept) ept_update_paging_mode_cr4(&hw_cr4, vcpu); vmcs_writel(CR4_READ_SHADOW, cr4); @@ -1699,7 +1747,7 @@ static void vmx_set_segment(struct kvm_vcpu *vcpu, struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg]; u32 ar; - if (vcpu->arch.rmode.active && seg == VCPU_SREG_TR) { + if (vcpu->arch.rmode.vm86_active && seg == VCPU_SREG_TR) { vcpu->arch.rmode.tr.selector = var->selector; vcpu->arch.rmode.tr.base = var->base; vcpu->arch.rmode.tr.limit = var->limit; @@ -1709,7 +1757,7 @@ static void vmx_set_segment(struct kvm_vcpu *vcpu, vmcs_writel(sf->base, var->base); vmcs_write32(sf->limit, var->limit); vmcs_write16(sf->selector, var->selector); - if (vcpu->arch.rmode.active && var->s) { + if (vcpu->arch.rmode.vm86_active && var->s) { /* * Hack real-mode segments into vm86 compatibility. */ @@ -1982,7 +2030,7 @@ static int init_rmode_identity_map(struct kvm *kvm) pfn_t identity_map_pfn; u32 tmp; - if (!vm_need_ept()) + if (!enable_ept) return 1; if (unlikely(!kvm->arch.ept_identity_pagetable)) { printk(KERN_ERR "EPT: identity-mapping pagetable " @@ -2071,7 +2119,7 @@ static void allocate_vpid(struct vcpu_vmx *vmx) int vpid; vmx->vpid = 0; - if (!enable_vpid || !cpu_has_vmx_vpid()) + if (!enable_vpid) return; spin_lock(&vmx_vpid_lock); vpid = find_first_zero_bit(vmx_vpid_bitmap, VMX_NR_VPIDS); @@ -2082,9 +2130,9 @@ static void allocate_vpid(struct vcpu_vmx *vmx) spin_unlock(&vmx_vpid_lock); } -static void vmx_disable_intercept_for_msr(struct page *msr_bitmap, u32 msr) +static void __vmx_disable_intercept_for_msr(unsigned long *msr_bitmap, u32 msr) { - void *va; + int f = sizeof(unsigned long); if (!cpu_has_vmx_msr_bitmap()) return; @@ -2094,16 +2142,21 @@ static void vmx_disable_intercept_for_msr(struct page *msr_bitmap, u32 msr) * have the write-low and read-high bitmap offsets the wrong way round. * We can control MSRs 0x00000000-0x00001fff and 0xc0000000-0xc0001fff. */ - va = kmap(msr_bitmap); if (msr <= 0x1fff) { - __clear_bit(msr, va + 0x000); /* read-low */ - __clear_bit(msr, va + 0x800); /* write-low */ + __clear_bit(msr, msr_bitmap + 0x000 / f); /* read-low */ + __clear_bit(msr, msr_bitmap + 0x800 / f); /* write-low */ } else if ((msr >= 0xc0000000) && (msr <= 0xc0001fff)) { msr &= 0x1fff; - __clear_bit(msr, va + 0x400); /* read-high */ - __clear_bit(msr, va + 0xc00); /* write-high */ + __clear_bit(msr, msr_bitmap + 0x400 / f); /* read-high */ + __clear_bit(msr, msr_bitmap + 0xc00 / f); /* write-high */ } - kunmap(msr_bitmap); +} + +static void vmx_disable_intercept_for_msr(u32 msr, bool longmode_only) +{ + if (!longmode_only) + __vmx_disable_intercept_for_msr(vmx_msr_bitmap_legacy, msr); + __vmx_disable_intercept_for_msr(vmx_msr_bitmap_longmode, msr); } /* @@ -2121,11 +2174,11 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx) u32 exec_control; /* I/O */ - vmcs_write64(IO_BITMAP_A, page_to_phys(vmx_io_bitmap_a)); - vmcs_write64(IO_BITMAP_B, page_to_phys(vmx_io_bitmap_b)); + vmcs_write64(IO_BITMAP_A, __pa(vmx_io_bitmap_a)); + vmcs_write64(IO_BITMAP_B, __pa(vmx_io_bitmap_b)); if (cpu_has_vmx_msr_bitmap()) - vmcs_write64(MSR_BITMAP, page_to_phys(vmx_msr_bitmap)); + vmcs_write64(MSR_BITMAP, __pa(vmx_msr_bitmap_legacy)); vmcs_write64(VMCS_LINK_POINTER, -1ull); /* 22.3.1.5 */ @@ -2141,7 +2194,7 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx) CPU_BASED_CR8_LOAD_EXITING; #endif } - if (!vm_need_ept()) + if (!enable_ept) exec_control |= CPU_BASED_CR3_STORE_EXITING | CPU_BASED_CR3_LOAD_EXITING | CPU_BASED_INVLPG_EXITING; @@ -2154,7 +2207,7 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx) ~SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES; if (vmx->vpid == 0) exec_control &= ~SECONDARY_EXEC_ENABLE_VPID; - if (!vm_need_ept()) + if (!enable_ept) exec_control &= ~SECONDARY_EXEC_ENABLE_EPT; vmcs_write32(SECONDARY_VM_EXEC_CONTROL, exec_control); } @@ -2273,7 +2326,7 @@ static int vmx_vcpu_reset(struct kvm_vcpu *vcpu) goto out; } - vmx->vcpu.arch.rmode.active = 0; + vmx->vcpu.arch.rmode.vm86_active = 0; vmx->soft_vnmi_blocked = 0; @@ -2402,14 +2455,16 @@ static void enable_nmi_window(struct kvm_vcpu *vcpu) vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control); } -static void vmx_inject_irq(struct kvm_vcpu *vcpu, int irq) +static void vmx_inject_irq(struct kvm_vcpu *vcpu) { struct vcpu_vmx *vmx = to_vmx(vcpu); + uint32_t intr; + int irq = vcpu->arch.interrupt.nr; KVMTRACE_1D(INJ_VIRQ, vcpu, (u32)irq, handler); ++vcpu->stat.irq_injections; - if (vcpu->arch.rmode.active) { + if (vcpu->arch.rmode.vm86_active) { vmx->rmode.irq.pending = true; vmx->rmode.irq.vector = irq; vmx->rmode.irq.rip = kvm_rip_read(vcpu); @@ -2419,8 +2474,14 @@ static void vmx_inject_irq(struct kvm_vcpu *vcpu, int irq) kvm_rip_write(vcpu, vmx->rmode.irq.rip - 1); return; } - vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, - irq | INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK); + intr = irq | INTR_INFO_VALID_MASK; + if (vcpu->arch.interrupt.soft) { + intr |= INTR_TYPE_SOFT_INTR; + vmcs_write32(VM_ENTRY_INSTRUCTION_LEN, + vmx->vcpu.arch.event_exit_inst_len); + } else + intr |= INTR_TYPE_EXT_INTR; + vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, intr); } static void vmx_inject_nmi(struct kvm_vcpu *vcpu) @@ -2441,7 +2502,7 @@ static void vmx_inject_nmi(struct kvm_vcpu *vcpu) } ++vcpu->stat.nmi_injections; - if (vcpu->arch.rmode.active) { + if (vcpu->arch.rmode.vm86_active) { vmx->rmode.irq.pending = true; vmx->rmode.irq.vector = NMI_VECTOR; vmx->rmode.irq.rip = kvm_rip_read(vcpu); @@ -2456,76 +2517,21 @@ static void vmx_inject_nmi(struct kvm_vcpu *vcpu) INTR_TYPE_NMI_INTR | INTR_INFO_VALID_MASK | NMI_VECTOR); } -static void vmx_update_window_states(struct kvm_vcpu *vcpu) +static int vmx_nmi_allowed(struct kvm_vcpu *vcpu) { - u32 guest_intr = vmcs_read32(GUEST_INTERRUPTIBILITY_INFO); - - vcpu->arch.nmi_window_open = - !(guest_intr & (GUEST_INTR_STATE_STI | - GUEST_INTR_STATE_MOV_SS | - GUEST_INTR_STATE_NMI)); if (!cpu_has_virtual_nmis() && to_vmx(vcpu)->soft_vnmi_blocked) - vcpu->arch.nmi_window_open = 0; + return 0; - vcpu->arch.interrupt_window_open = - ((vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) && - !(guest_intr & (GUEST_INTR_STATE_STI | - GUEST_INTR_STATE_MOV_SS))); + return !(vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & + (GUEST_INTR_STATE_STI | GUEST_INTR_STATE_MOV_SS | + GUEST_INTR_STATE_NMI)); } -static void kvm_do_inject_irq(struct kvm_vcpu *vcpu) +static int vmx_interrupt_allowed(struct kvm_vcpu *vcpu) { - int word_index = __ffs(vcpu->arch.irq_summary); - int bit_index = __ffs(vcpu->arch.irq_pending[word_index]); - int irq = word_index * BITS_PER_LONG + bit_index; - - clear_bit(bit_index, &vcpu->arch.irq_pending[word_index]); - if (!vcpu->arch.irq_pending[word_index]) - clear_bit(word_index, &vcpu->arch.irq_summary); - kvm_queue_interrupt(vcpu, irq); -} - -static void do_interrupt_requests(struct kvm_vcpu *vcpu, - struct kvm_run *kvm_run) -{ - vmx_update_window_states(vcpu); - - if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) - vmcs_clear_bits(GUEST_INTERRUPTIBILITY_INFO, - GUEST_INTR_STATE_STI | - GUEST_INTR_STATE_MOV_SS); - - if (vcpu->arch.nmi_pending && !vcpu->arch.nmi_injected) { - if (vcpu->arch.interrupt.pending) { - enable_nmi_window(vcpu); - } else if (vcpu->arch.nmi_window_open) { - vcpu->arch.nmi_pending = false; - vcpu->arch.nmi_injected = true; - } else { - enable_nmi_window(vcpu); - return; - } - } - if (vcpu->arch.nmi_injected) { - vmx_inject_nmi(vcpu); - if (vcpu->arch.nmi_pending) - enable_nmi_window(vcpu); - else if (vcpu->arch.irq_summary - || kvm_run->request_interrupt_window) - enable_irq_window(vcpu); - return; - } - - if (vcpu->arch.interrupt_window_open) { - if (vcpu->arch.irq_summary && !vcpu->arch.interrupt.pending) - kvm_do_inject_irq(vcpu); - - if (vcpu->arch.interrupt.pending) - vmx_inject_irq(vcpu, vcpu->arch.interrupt.nr); - } - if (!vcpu->arch.interrupt_window_open && - (vcpu->arch.irq_summary || kvm_run->request_interrupt_window)) - enable_irq_window(vcpu); + return (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) && + !(vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & + (GUEST_INTR_STATE_STI | GUEST_INTR_STATE_MOV_SS)); } static int vmx_set_tss_addr(struct kvm *kvm, unsigned int addr) @@ -2585,6 +2591,31 @@ static int handle_rmode_exception(struct kvm_vcpu *vcpu, return 0; } +/* + * Trigger machine check on the host. We assume all the MSRs are already set up + * by the CPU and that we still run on the same CPU as the MCE occurred on. + * We pass a fake environment to the machine check handler because we want + * the guest to be always treated like user space, no matter what context + * it used internally. + */ +static void kvm_machine_check(void) +{ +#if defined(CONFIG_X86_MCE) && defined(CONFIG_X86_64) + struct pt_regs regs = { + .cs = 3, /* Fake ring 3 no matter what the guest ran on */ + .flags = X86_EFLAGS_IF, + }; + + do_machine_check(®s, 0); +#endif +} + +static int handle_machine_check(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +{ + /* already handled by vcpu_run */ + return 1; +} + static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) { struct vcpu_vmx *vmx = to_vmx(vcpu); @@ -2596,17 +2627,14 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) vect_info = vmx->idt_vectoring_info; intr_info = vmcs_read32(VM_EXIT_INTR_INFO); + if (is_machine_check(intr_info)) + return handle_machine_check(vcpu, kvm_run); + if ((vect_info & VECTORING_INFO_VALID_MASK) && !is_page_fault(intr_info)) printk(KERN_ERR "%s: unexpected, vectoring info 0x%x " "intr info 0x%x\n", __func__, vect_info, intr_info); - if (!irqchip_in_kernel(vcpu->kvm) && is_external_interrupt(vect_info)) { - int irq = vect_info & VECTORING_INFO_VECTOR_MASK; - set_bit(irq, vcpu->arch.irq_pending); - set_bit(irq / BITS_PER_LONG, &vcpu->arch.irq_summary); - } - if ((intr_info & INTR_INFO_INTR_TYPE_MASK) == INTR_TYPE_NMI_INTR) return 1; /* already handled by vmx_vcpu_run() */ @@ -2628,17 +2656,17 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) error_code = vmcs_read32(VM_EXIT_INTR_ERROR_CODE); if (is_page_fault(intr_info)) { /* EPT won't cause page fault directly */ - if (vm_need_ept()) + if (enable_ept) BUG(); cr2 = vmcs_readl(EXIT_QUALIFICATION); KVMTRACE_3D(PAGE_FAULT, vcpu, error_code, (u32)cr2, (u32)((u64)cr2 >> 32), handler); - if (vcpu->arch.interrupt.pending || vcpu->arch.exception.pending) + if (kvm_event_needs_reinjection(vcpu)) kvm_mmu_unprotect_page_virt(vcpu, cr2); return kvm_mmu_page_fault(vcpu, cr2, error_code); } - if (vcpu->arch.rmode.active && + if (vcpu->arch.rmode.vm86_active && handle_rmode_exception(vcpu, intr_info & INTR_INFO_VECTOR_MASK, error_code)) { if (vcpu->arch.halt_request) { @@ -2753,13 +2781,18 @@ static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) kvm_set_cr4(vcpu, kvm_register_read(vcpu, reg)); skip_emulated_instruction(vcpu); return 1; - case 8: - kvm_set_cr8(vcpu, kvm_register_read(vcpu, reg)); - skip_emulated_instruction(vcpu); - if (irqchip_in_kernel(vcpu->kvm)) - return 1; - kvm_run->exit_reason = KVM_EXIT_SET_TPR; - return 0; + case 8: { + u8 cr8_prev = kvm_get_cr8(vcpu); + u8 cr8 = kvm_register_read(vcpu, reg); + kvm_set_cr8(vcpu, cr8); + skip_emulated_instruction(vcpu); + if (irqchip_in_kernel(vcpu->kvm)) + return 1; + if (cr8_prev <= cr8) + return 1; + kvm_run->exit_reason = KVM_EXIT_SET_TPR; + return 0; + } }; break; case 2: /* clts */ @@ -2957,8 +2990,9 @@ static int handle_interrupt_window(struct kvm_vcpu *vcpu, * If the user space waits to inject interrupts, exit as soon as * possible */ - if (kvm_run->request_interrupt_window && - !vcpu->arch.irq_summary) { + if (!irqchip_in_kernel(vcpu->kvm) && + kvm_run->request_interrupt_window && + !kvm_cpu_has_interrupt(vcpu)) { kvm_run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN; return 0; } @@ -2980,7 +3014,7 @@ static int handle_vmcall(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) static int handle_invlpg(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) { - u64 exit_qualification = vmcs_read64(EXIT_QUALIFICATION); + unsigned long exit_qualification = vmcs_readl(EXIT_QUALIFICATION); kvm_mmu_invlpg(vcpu, exit_qualification); skip_emulated_instruction(vcpu); @@ -2996,11 +3030,11 @@ static int handle_wbinvd(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) static int handle_apic_access(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) { - u64 exit_qualification; + unsigned long exit_qualification; enum emulation_result er; unsigned long offset; - exit_qualification = vmcs_read64(EXIT_QUALIFICATION); + exit_qualification = vmcs_readl(EXIT_QUALIFICATION); offset = exit_qualification & 0xffful; er = emulate_instruction(vcpu, kvm_run, 0, 0, 0); @@ -3019,22 +3053,41 @@ static int handle_task_switch(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) struct vcpu_vmx *vmx = to_vmx(vcpu); unsigned long exit_qualification; u16 tss_selector; - int reason; + int reason, type, idt_v; + + idt_v = (vmx->idt_vectoring_info & VECTORING_INFO_VALID_MASK); + type = (vmx->idt_vectoring_info & VECTORING_INFO_TYPE_MASK); exit_qualification = vmcs_readl(EXIT_QUALIFICATION); reason = (u32)exit_qualification >> 30; - if (reason == TASK_SWITCH_GATE && vmx->vcpu.arch.nmi_injected && - (vmx->idt_vectoring_info & VECTORING_INFO_VALID_MASK) && - (vmx->idt_vectoring_info & VECTORING_INFO_TYPE_MASK) - == INTR_TYPE_NMI_INTR) { - vcpu->arch.nmi_injected = false; - if (cpu_has_virtual_nmis()) - vmcs_set_bits(GUEST_INTERRUPTIBILITY_INFO, - GUEST_INTR_STATE_NMI); + if (reason == TASK_SWITCH_GATE && idt_v) { + switch (type) { + case INTR_TYPE_NMI_INTR: + vcpu->arch.nmi_injected = false; + if (cpu_has_virtual_nmis()) + vmcs_set_bits(GUEST_INTERRUPTIBILITY_INFO, + GUEST_INTR_STATE_NMI); + break; + case INTR_TYPE_EXT_INTR: + case INTR_TYPE_SOFT_INTR: + kvm_clear_interrupt_queue(vcpu); + break; + case INTR_TYPE_HARD_EXCEPTION: + case INTR_TYPE_SOFT_EXCEPTION: + kvm_clear_exception_queue(vcpu); + break; + default: + break; + } } tss_selector = exit_qualification; + if (!idt_v || (type != INTR_TYPE_HARD_EXCEPTION && + type != INTR_TYPE_EXT_INTR && + type != INTR_TYPE_NMI_INTR)) + skip_emulated_instruction(vcpu); + if (!kvm_task_switch(vcpu, tss_selector, reason)) return 0; @@ -3051,11 +3104,11 @@ static int handle_task_switch(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) static int handle_ept_violation(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) { - u64 exit_qualification; + unsigned long exit_qualification; gpa_t gpa; int gla_validity; - exit_qualification = vmcs_read64(EXIT_QUALIFICATION); + exit_qualification = vmcs_readl(EXIT_QUALIFICATION); if (exit_qualification & (1 << 6)) { printk(KERN_ERR "EPT: GPA exceeds GAW!\n"); @@ -3067,7 +3120,7 @@ static int handle_ept_violation(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) printk(KERN_ERR "EPT: Handling EPT violation failed!\n"); printk(KERN_ERR "EPT: GPA: 0x%lx, GVA: 0x%lx\n", (long unsigned int)vmcs_read64(GUEST_PHYSICAL_ADDRESS), - (long unsigned int)vmcs_read64(GUEST_LINEAR_ADDRESS)); + vmcs_readl(GUEST_LINEAR_ADDRESS)); printk(KERN_ERR "EPT: Exit qualification is 0x%lx\n", (long unsigned int)exit_qualification); kvm_run->exit_reason = KVM_EXIT_UNKNOWN; @@ -3150,6 +3203,7 @@ static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu, [EXIT_REASON_WBINVD] = handle_wbinvd, [EXIT_REASON_TASK_SWITCH] = handle_task_switch, [EXIT_REASON_EPT_VIOLATION] = handle_ept_violation, + [EXIT_REASON_MCE_DURING_VMENTRY] = handle_machine_check, }; static const int kvm_vmx_max_exit_handlers = @@ -3159,10 +3213,10 @@ static const int kvm_vmx_max_exit_handlers = * The guest has exited. See if we can fix it or if we need userspace * assistance. */ -static int kvm_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) +static int vmx_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) { - u32 exit_reason = vmcs_read32(VM_EXIT_REASON); struct vcpu_vmx *vmx = to_vmx(vcpu); + u32 exit_reason = vmx->exit_reason; u32 vectoring_info = vmx->idt_vectoring_info; KVMTRACE_3D(VMEXIT, vcpu, exit_reason, (u32)kvm_rip_read(vcpu), @@ -3178,7 +3232,7 @@ static int kvm_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) /* Access CR3 don't cause VMExit in paging mode, so we need * to sync with guest real CR3. */ - if (vm_need_ept() && is_paging(vcpu)) { + if (enable_ept && is_paging(vcpu)) { vcpu->arch.cr3 = vmcs_readl(GUEST_CR3); ept_load_pdptrs(vcpu); } @@ -3199,9 +3253,8 @@ static int kvm_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) __func__, vectoring_info, exit_reason); if (unlikely(!cpu_has_virtual_nmis() && vmx->soft_vnmi_blocked)) { - if (vcpu->arch.interrupt_window_open) { + if (vmx_interrupt_allowed(vcpu)) { vmx->soft_vnmi_blocked = 0; - vcpu->arch.nmi_window_open = 1; } else if (vmx->vnmi_blocked_time > 1000000000LL && vcpu->arch.nmi_pending) { /* @@ -3214,7 +3267,6 @@ static int kvm_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) "state on VCPU %d after 1 s timeout\n", __func__, vcpu->vcpu_id); vmx->soft_vnmi_blocked = 0; - vmx->vcpu.arch.nmi_window_open = 1; } } @@ -3228,122 +3280,107 @@ static int kvm_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) return 0; } -static void update_tpr_threshold(struct kvm_vcpu *vcpu) +static void update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr) { - int max_irr, tpr; - - if (!vm_need_tpr_shadow(vcpu->kvm)) - return; - - if (!kvm_lapic_enabled(vcpu) || - ((max_irr = kvm_lapic_find_highest_irr(vcpu)) == -1)) { + if (irr == -1 || tpr < irr) { vmcs_write32(TPR_THRESHOLD, 0); return; } - tpr = (kvm_lapic_get_cr8(vcpu) & 0x0f) << 4; - vmcs_write32(TPR_THRESHOLD, (max_irr > tpr) ? tpr >> 4 : max_irr >> 4); + vmcs_write32(TPR_THRESHOLD, irr); } static void vmx_complete_interrupts(struct vcpu_vmx *vmx) { u32 exit_intr_info; - u32 idt_vectoring_info; + u32 idt_vectoring_info = vmx->idt_vectoring_info; bool unblock_nmi; u8 vector; int type; bool idtv_info_valid; - u32 error; exit_intr_info = vmcs_read32(VM_EXIT_INTR_INFO); + + vmx->exit_reason = vmcs_read32(VM_EXIT_REASON); + + /* Handle machine checks before interrupts are enabled */ + if ((vmx->exit_reason == EXIT_REASON_MCE_DURING_VMENTRY) + || (vmx->exit_reason == EXIT_REASON_EXCEPTION_NMI + && is_machine_check(exit_intr_info))) + kvm_machine_check(); + + /* We need to handle NMIs before interrupts are enabled */ + if ((exit_intr_info & INTR_INFO_INTR_TYPE_MASK) == INTR_TYPE_NMI_INTR && + (exit_intr_info & INTR_INFO_VALID_MASK)) { + KVMTRACE_0D(NMI, &vmx->vcpu, handler); + asm("int $2"); + } + + idtv_info_valid = idt_vectoring_info & VECTORING_INFO_VALID_MASK; + if (cpu_has_virtual_nmis()) { unblock_nmi = (exit_intr_info & INTR_INFO_UNBLOCK_NMI) != 0; vector = exit_intr_info & INTR_INFO_VECTOR_MASK; /* - * SDM 3: 25.7.1.2 + * SDM 3: 27.7.1.2 (September 2008) * Re-set bit "block by NMI" before VM entry if vmexit caused by * a guest IRET fault. + * SDM 3: 23.2.2 (September 2008) + * Bit 12 is undefined in any of the following cases: + * If the VM exit sets the valid bit in the IDT-vectoring + * information field. + * If the VM exit is due to a double fault. */ - if (unblock_nmi && vector != DF_VECTOR) + if ((exit_intr_info & INTR_INFO_VALID_MASK) && unblock_nmi && + vector != DF_VECTOR && !idtv_info_valid) vmcs_set_bits(GUEST_INTERRUPTIBILITY_INFO, GUEST_INTR_STATE_NMI); } else if (unlikely(vmx->soft_vnmi_blocked)) vmx->vnmi_blocked_time += ktime_to_ns(ktime_sub(ktime_get(), vmx->entry_time)); - idt_vectoring_info = vmx->idt_vectoring_info; - idtv_info_valid = idt_vectoring_info & VECTORING_INFO_VALID_MASK; + vmx->vcpu.arch.nmi_injected = false; + kvm_clear_exception_queue(&vmx->vcpu); + kvm_clear_interrupt_queue(&vmx->vcpu); + + if (!idtv_info_valid) + return; + vector = idt_vectoring_info & VECTORING_INFO_VECTOR_MASK; type = idt_vectoring_info & VECTORING_INFO_TYPE_MASK; - if (vmx->vcpu.arch.nmi_injected) { + + switch (type) { + case INTR_TYPE_NMI_INTR: + vmx->vcpu.arch.nmi_injected = true; /* - * SDM 3: 25.7.1.2 - * Clear bit "block by NMI" before VM entry if a NMI delivery - * faulted. + * SDM 3: 27.7.1.2 (September 2008) + * Clear bit "block by NMI" before VM entry if a NMI + * delivery faulted. */ - if (idtv_info_valid && type == INTR_TYPE_NMI_INTR) - vmcs_clear_bits(GUEST_INTERRUPTIBILITY_INFO, - GUEST_INTR_STATE_NMI); - else - vmx->vcpu.arch.nmi_injected = false; - } - kvm_clear_exception_queue(&vmx->vcpu); - if (idtv_info_valid && (type == INTR_TYPE_HARD_EXCEPTION || - type == INTR_TYPE_SOFT_EXCEPTION)) { + vmcs_clear_bits(GUEST_INTERRUPTIBILITY_INFO, + GUEST_INTR_STATE_NMI); + break; + case INTR_TYPE_SOFT_EXCEPTION: + vmx->vcpu.arch.event_exit_inst_len = + vmcs_read32(VM_EXIT_INSTRUCTION_LEN); + /* fall through */ + case INTR_TYPE_HARD_EXCEPTION: if (idt_vectoring_info & VECTORING_INFO_DELIVER_CODE_MASK) { - error = vmcs_read32(IDT_VECTORING_ERROR_CODE); - kvm_queue_exception_e(&vmx->vcpu, vector, error); + u32 err = vmcs_read32(IDT_VECTORING_ERROR_CODE); + kvm_queue_exception_e(&vmx->vcpu, vector, err); } else kvm_queue_exception(&vmx->vcpu, vector); - vmx->idt_vectoring_info = 0; - } - kvm_clear_interrupt_queue(&vmx->vcpu); - if (idtv_info_valid && type == INTR_TYPE_EXT_INTR) { - kvm_queue_interrupt(&vmx->vcpu, vector); - vmx->idt_vectoring_info = 0; - } -} - -static void vmx_intr_assist(struct kvm_vcpu *vcpu) -{ - update_tpr_threshold(vcpu); - - vmx_update_window_states(vcpu); - - if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) - vmcs_clear_bits(GUEST_INTERRUPTIBILITY_INFO, - GUEST_INTR_STATE_STI | - GUEST_INTR_STATE_MOV_SS); - - if (vcpu->arch.nmi_pending && !vcpu->arch.nmi_injected) { - if (vcpu->arch.interrupt.pending) { - enable_nmi_window(vcpu); - } else if (vcpu->arch.nmi_window_open) { - vcpu->arch.nmi_pending = false; - vcpu->arch.nmi_injected = true; - } else { - enable_nmi_window(vcpu); - return; - } - } - if (vcpu->arch.nmi_injected) { - vmx_inject_nmi(vcpu); - if (vcpu->arch.nmi_pending) - enable_nmi_window(vcpu); - else if (kvm_cpu_has_interrupt(vcpu)) - enable_irq_window(vcpu); - return; - } - if (!vcpu->arch.interrupt.pending && kvm_cpu_has_interrupt(vcpu)) { - if (vcpu->arch.interrupt_window_open) - kvm_queue_interrupt(vcpu, kvm_cpu_get_interrupt(vcpu)); - else - enable_irq_window(vcpu); - } - if (vcpu->arch.interrupt.pending) { - vmx_inject_irq(vcpu, vcpu->arch.interrupt.nr); - if (kvm_cpu_has_interrupt(vcpu)) - enable_irq_window(vcpu); + break; + case INTR_TYPE_SOFT_INTR: + vmx->vcpu.arch.event_exit_inst_len = + vmcs_read32(VM_EXIT_INSTRUCTION_LEN); + /* fall through */ + case INTR_TYPE_EXT_INTR: + kvm_queue_interrupt(&vmx->vcpu, vector, + type == INTR_TYPE_SOFT_INTR); + break; + default: + break; } } @@ -3381,7 +3418,6 @@ static void fixup_rmode_irq(struct vcpu_vmx *vmx) static void vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) { struct vcpu_vmx *vmx = to_vmx(vcpu); - u32 intr_info; /* Record the guest's net vcpu time for enforced NMI injections. */ if (unlikely(!cpu_has_virtual_nmis() && vmx->soft_vnmi_blocked)) @@ -3505,20 +3541,9 @@ static void vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) if (vmx->rmode.irq.pending) fixup_rmode_irq(vmx); - vmx_update_window_states(vcpu); - asm("mov %0, %%ds; mov %0, %%es" : : "r"(__USER_DS)); vmx->launched = 1; - 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) == INTR_TYPE_NMI_INTR && - (intr_info & INTR_INFO_VALID_MASK)) { - KVMTRACE_0D(NMI, vcpu, handler); - asm("int $2"); - } - vmx_complete_interrupts(vmx); } @@ -3593,7 +3618,7 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id) if (alloc_apic_access_page(kvm) != 0) goto free_vmcs; - if (vm_need_ept()) + if (enable_ept) if (alloc_identity_pagetable(kvm) != 0) goto free_vmcs; @@ -3631,9 +3656,32 @@ static int get_ept_level(void) return VMX_EPT_DEFAULT_GAW + 1; } -static int vmx_get_mt_mask_shift(void) +static u64 vmx_get_mt_mask(struct kvm_vcpu *vcpu, gfn_t gfn, bool is_mmio) { - return VMX_EPT_MT_EPTE_SHIFT; + u64 ret; + + /* For VT-d and EPT combination + * 1. MMIO: always map as UC + * 2. EPT with VT-d: + * a. VT-d without snooping control feature: can't guarantee the + * result, try to trust guest. + * b. VT-d with snooping control feature: snooping control feature of + * VT-d engine can guarantee the cache correctness. Just set it + * to WB to keep consistent with host. So the same as item 3. + * 3. EPT without VT-d: always map as WB and set IGMT=1 to keep + * consistent with host MTRR + */ + if (is_mmio) + ret = MTRR_TYPE_UNCACHABLE << VMX_EPT_MT_EPTE_SHIFT; + else if (vcpu->kvm->arch.iommu_domain && + !(vcpu->kvm->arch.iommu_flags & KVM_IOMMU_CACHE_COHERENCY)) + ret = kvm_get_guest_memory_type(vcpu, gfn) << + VMX_EPT_MT_EPTE_SHIFT; + else + ret = (MTRR_TYPE_WRBACK << VMX_EPT_MT_EPTE_SHIFT) + | VMX_EPT_IGMT_BIT; + + return ret; } static struct kvm_x86_ops vmx_x86_ops = { @@ -3644,7 +3692,7 @@ static struct kvm_x86_ops vmx_x86_ops = { .check_processor_compatibility = vmx_check_processor_compat, .hardware_enable = hardware_enable, .hardware_disable = hardware_disable, - .cpu_has_accelerated_tpr = cpu_has_vmx_virtualize_apic_accesses, + .cpu_has_accelerated_tpr = report_flexpriority, .vcpu_create = vmx_create_vcpu, .vcpu_free = vmx_free_vcpu, @@ -3678,78 +3726,82 @@ static struct kvm_x86_ops vmx_x86_ops = { .tlb_flush = vmx_flush_tlb, .run = vmx_vcpu_run, - .handle_exit = kvm_handle_exit, + .handle_exit = vmx_handle_exit, .skip_emulated_instruction = skip_emulated_instruction, + .set_interrupt_shadow = vmx_set_interrupt_shadow, + .get_interrupt_shadow = vmx_get_interrupt_shadow, .patch_hypercall = vmx_patch_hypercall, - .get_irq = vmx_get_irq, .set_irq = vmx_inject_irq, + .set_nmi = vmx_inject_nmi, .queue_exception = vmx_queue_exception, - .exception_injected = vmx_exception_injected, - .inject_pending_irq = vmx_intr_assist, - .inject_pending_vectors = do_interrupt_requests, + .interrupt_allowed = vmx_interrupt_allowed, + .nmi_allowed = vmx_nmi_allowed, + .enable_nmi_window = enable_nmi_window, + .enable_irq_window = enable_irq_window, + .update_cr8_intercept = update_cr8_intercept, .set_tss_addr = vmx_set_tss_addr, .get_tdp_level = get_ept_level, - .get_mt_mask_shift = vmx_get_mt_mask_shift, + .get_mt_mask = vmx_get_mt_mask, }; static int __init vmx_init(void) { - void *va; int r; - vmx_io_bitmap_a = alloc_page(GFP_KERNEL | __GFP_HIGHMEM); + vmx_io_bitmap_a = (unsigned long *)__get_free_page(GFP_KERNEL); if (!vmx_io_bitmap_a) return -ENOMEM; - vmx_io_bitmap_b = alloc_page(GFP_KERNEL | __GFP_HIGHMEM); + vmx_io_bitmap_b = (unsigned long *)__get_free_page(GFP_KERNEL); if (!vmx_io_bitmap_b) { r = -ENOMEM; goto out; } - vmx_msr_bitmap = alloc_page(GFP_KERNEL | __GFP_HIGHMEM); - if (!vmx_msr_bitmap) { + vmx_msr_bitmap_legacy = (unsigned long *)__get_free_page(GFP_KERNEL); + if (!vmx_msr_bitmap_legacy) { r = -ENOMEM; goto out1; } + vmx_msr_bitmap_longmode = (unsigned long *)__get_free_page(GFP_KERNEL); + if (!vmx_msr_bitmap_longmode) { + r = -ENOMEM; + goto out2; + } + /* * Allow direct access to the PC debug port (it is often used for I/O * delays, but the vmexits simply slow things down). */ - va = kmap(vmx_io_bitmap_a); - memset(va, 0xff, PAGE_SIZE); - clear_bit(0x80, va); - kunmap(vmx_io_bitmap_a); + memset(vmx_io_bitmap_a, 0xff, PAGE_SIZE); + clear_bit(0x80, vmx_io_bitmap_a); - va = kmap(vmx_io_bitmap_b); - memset(va, 0xff, PAGE_SIZE); - kunmap(vmx_io_bitmap_b); + memset(vmx_io_bitmap_b, 0xff, PAGE_SIZE); - va = kmap(vmx_msr_bitmap); - memset(va, 0xff, PAGE_SIZE); - kunmap(vmx_msr_bitmap); + memset(vmx_msr_bitmap_legacy, 0xff, PAGE_SIZE); + memset(vmx_msr_bitmap_longmode, 0xff, PAGE_SIZE); set_bit(0, vmx_vpid_bitmap); /* 0 is reserved for host */ r = kvm_init(&vmx_x86_ops, sizeof(struct vcpu_vmx), THIS_MODULE); if (r) - goto out2; + goto out3; - vmx_disable_intercept_for_msr(vmx_msr_bitmap, MSR_FS_BASE); - vmx_disable_intercept_for_msr(vmx_msr_bitmap, MSR_GS_BASE); - vmx_disable_intercept_for_msr(vmx_msr_bitmap, MSR_IA32_SYSENTER_CS); - vmx_disable_intercept_for_msr(vmx_msr_bitmap, MSR_IA32_SYSENTER_ESP); - vmx_disable_intercept_for_msr(vmx_msr_bitmap, MSR_IA32_SYSENTER_EIP); + vmx_disable_intercept_for_msr(MSR_FS_BASE, false); + vmx_disable_intercept_for_msr(MSR_GS_BASE, false); + vmx_disable_intercept_for_msr(MSR_KERNEL_GS_BASE, true); + vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_CS, false); + vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_ESP, false); + vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_EIP, false); - if (vm_need_ept()) { + if (enable_ept) { bypass_guest_pf = 0; kvm_mmu_set_base_ptes(VMX_EPT_READABLE_MASK | VMX_EPT_WRITABLE_MASK); kvm_mmu_set_mask_ptes(0ull, 0ull, 0ull, 0ull, - VMX_EPT_EXECUTABLE_MASK, - VMX_EPT_DEFAULT_MT << VMX_EPT_MT_EPTE_SHIFT); + VMX_EPT_EXECUTABLE_MASK); kvm_enable_tdp(); } else kvm_disable_tdp(); @@ -3761,20 +3813,23 @@ static int __init vmx_init(void) return 0; +out3: + free_page((unsigned long)vmx_msr_bitmap_longmode); out2: - __free_page(vmx_msr_bitmap); + free_page((unsigned long)vmx_msr_bitmap_legacy); out1: - __free_page(vmx_io_bitmap_b); + free_page((unsigned long)vmx_io_bitmap_b); out: - __free_page(vmx_io_bitmap_a); + free_page((unsigned long)vmx_io_bitmap_a); return r; } static void __exit vmx_exit(void) { - __free_page(vmx_msr_bitmap); - __free_page(vmx_io_bitmap_b); - __free_page(vmx_io_bitmap_a); + free_page((unsigned long)vmx_msr_bitmap_legacy); + free_page((unsigned long)vmx_msr_bitmap_longmode); + free_page((unsigned long)vmx_io_bitmap_b); + free_page((unsigned long)vmx_io_bitmap_a); kvm_exit(); } diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 3944e917e794..249540f98513 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -91,7 +91,6 @@ struct kvm_stats_debugfs_item debugfs_entries[] = { { "halt_wakeup", VCPU_STAT(halt_wakeup) }, { "hypercalls", VCPU_STAT(hypercalls) }, { "request_irq", VCPU_STAT(request_irq_exits) }, - { "request_nmi", VCPU_STAT(request_nmi_exits) }, { "irq_exits", VCPU_STAT(irq_exits) }, { "host_state_reload", VCPU_STAT(host_state_reload) }, { "efer_reload", VCPU_STAT(efer_reload) }, @@ -108,7 +107,6 @@ struct kvm_stats_debugfs_item debugfs_entries[] = { { "mmu_recycled", VM_STAT(mmu_recycled) }, { "mmu_cache_miss", VM_STAT(mmu_cache_miss) }, { "mmu_unsync", VM_STAT(mmu_unsync) }, - { "mmu_unsync_global", VM_STAT(mmu_unsync_global) }, { "remote_tlb_flush", VM_STAT(remote_tlb_flush) }, { "largepages", VM_STAT(lpages) }, { NULL } @@ -234,7 +232,8 @@ int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3) goto out; } for (i = 0; i < ARRAY_SIZE(pdpte); ++i) { - if ((pdpte[i] & 1) && (pdpte[i] & 0xfffffff0000001e6ull)) { + if (is_present_pte(pdpte[i]) && + (pdpte[i] & vcpu->arch.mmu.rsvd_bits_mask[0][2])) { ret = 0; goto out; } @@ -321,7 +320,6 @@ void kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) kvm_x86_ops->set_cr0(vcpu, cr0); vcpu->arch.cr0 = cr0; - kvm_mmu_sync_global(vcpu); kvm_mmu_reset_context(vcpu); return; } @@ -370,7 +368,6 @@ void kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) kvm_x86_ops->set_cr4(vcpu, cr4); vcpu->arch.cr4 = cr4; vcpu->arch.mmu.base_role.cr4_pge = (cr4 & X86_CR4_PGE) && !tdp_enabled; - kvm_mmu_sync_global(vcpu); kvm_mmu_reset_context(vcpu); } EXPORT_SYMBOL_GPL(kvm_set_cr4); @@ -523,6 +520,9 @@ static void set_efer(struct kvm_vcpu *vcpu, u64 efer) efer |= vcpu->arch.shadow_efer & EFER_LMA; vcpu->arch.shadow_efer = efer; + + vcpu->arch.mmu.base_role.nxe = (efer & EFER_NX) && !tdp_enabled; + kvm_mmu_reset_context(vcpu); } void kvm_enable_efer_bits(u64 mask) @@ -630,14 +630,17 @@ static void kvm_write_guest_time(struct kvm_vcpu *v) unsigned long flags; struct kvm_vcpu_arch *vcpu = &v->arch; void *shared_kaddr; + unsigned long this_tsc_khz; if ((!vcpu->time_page)) return; - if (unlikely(vcpu->hv_clock_tsc_khz != __get_cpu_var(cpu_tsc_khz))) { - kvm_set_time_scale(__get_cpu_var(cpu_tsc_khz), &vcpu->hv_clock); - vcpu->hv_clock_tsc_khz = __get_cpu_var(cpu_tsc_khz); + this_tsc_khz = get_cpu_var(cpu_tsc_khz); + if (unlikely(vcpu->hv_clock_tsc_khz != this_tsc_khz)) { + kvm_set_time_scale(this_tsc_khz, &vcpu->hv_clock); + vcpu->hv_clock_tsc_khz = this_tsc_khz; } + put_cpu_var(cpu_tsc_khz); /* Keep irq disabled to prevent changes to the clock */ local_irq_save(flags); @@ -893,6 +896,8 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata) case MSR_IA32_LASTINTFROMIP: case MSR_IA32_LASTINTTOIP: case MSR_VM_HSAVE_PA: + case MSR_P6_EVNTSEL0: + case MSR_P6_EVNTSEL1: data = 0; break; case MSR_MTRRcap: @@ -1024,6 +1029,7 @@ int kvm_dev_ioctl_check_extension(long ext) case KVM_CAP_SYNC_MMU: case KVM_CAP_REINJECT_CONTROL: case KVM_CAP_IRQ_INJECT_STATUS: + case KVM_CAP_ASSIGN_DEV_IRQ: r = 1; break; case KVM_CAP_COALESCED_MMIO: @@ -1241,41 +1247,53 @@ static void do_cpuid_1_ent(struct kvm_cpuid_entry2 *entry, u32 function, entry->flags = 0; } +#define F(x) bit(X86_FEATURE_##x) + static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function, u32 index, int *nent, int maxnent) { - const u32 kvm_supported_word0_x86_features = bit(X86_FEATURE_FPU) | - bit(X86_FEATURE_VME) | bit(X86_FEATURE_DE) | - bit(X86_FEATURE_PSE) | bit(X86_FEATURE_TSC) | - bit(X86_FEATURE_MSR) | bit(X86_FEATURE_PAE) | - bit(X86_FEATURE_CX8) | bit(X86_FEATURE_APIC) | - bit(X86_FEATURE_SEP) | bit(X86_FEATURE_PGE) | - bit(X86_FEATURE_CMOV) | bit(X86_FEATURE_PSE36) | - bit(X86_FEATURE_CLFLSH) | bit(X86_FEATURE_MMX) | - bit(X86_FEATURE_FXSR) | bit(X86_FEATURE_XMM) | - bit(X86_FEATURE_XMM2) | bit(X86_FEATURE_SELFSNOOP); - const u32 kvm_supported_word1_x86_features = bit(X86_FEATURE_FPU) | - bit(X86_FEATURE_VME) | bit(X86_FEATURE_DE) | - bit(X86_FEATURE_PSE) | bit(X86_FEATURE_TSC) | - bit(X86_FEATURE_MSR) | bit(X86_FEATURE_PAE) | - bit(X86_FEATURE_CX8) | bit(X86_FEATURE_APIC) | - bit(X86_FEATURE_PGE) | - bit(X86_FEATURE_CMOV) | bit(X86_FEATURE_PSE36) | - bit(X86_FEATURE_MMX) | bit(X86_FEATURE_FXSR) | - bit(X86_FEATURE_SYSCALL) | - (is_efer_nx() ? bit(X86_FEATURE_NX) : 0) | + unsigned f_nx = is_efer_nx() ? F(NX) : 0; #ifdef CONFIG_X86_64 - bit(X86_FEATURE_LM) | + unsigned f_lm = F(LM); +#else + unsigned f_lm = 0; #endif - bit(X86_FEATURE_FXSR_OPT) | - bit(X86_FEATURE_MMXEXT) | - bit(X86_FEATURE_3DNOWEXT) | - bit(X86_FEATURE_3DNOW); - const u32 kvm_supported_word3_x86_features = - bit(X86_FEATURE_XMM3) | bit(X86_FEATURE_CX16); + + /* cpuid 1.edx */ + const u32 kvm_supported_word0_x86_features = + F(FPU) | F(VME) | F(DE) | F(PSE) | + F(TSC) | F(MSR) | F(PAE) | F(MCE) | + F(CX8) | F(APIC) | 0 /* Reserved */ | F(SEP) | + F(MTRR) | F(PGE) | F(MCA) | F(CMOV) | + F(PAT) | F(PSE36) | 0 /* PSN */ | F(CLFLSH) | + 0 /* Reserved, DS, ACPI */ | F(MMX) | + F(FXSR) | F(XMM) | F(XMM2) | F(SELFSNOOP) | + 0 /* HTT, TM, Reserved, PBE */; + /* cpuid 0x80000001.edx */ + const u32 kvm_supported_word1_x86_features = + F(FPU) | F(VME) | F(DE) | F(PSE) | + F(TSC) | F(MSR) | F(PAE) | F(MCE) | + F(CX8) | F(APIC) | 0 /* Reserved */ | F(SYSCALL) | + F(MTRR) | F(PGE) | F(MCA) | F(CMOV) | + F(PAT) | F(PSE36) | 0 /* Reserved */ | + f_nx | 0 /* Reserved */ | F(MMXEXT) | F(MMX) | + F(FXSR) | F(FXSR_OPT) | 0 /* GBPAGES */ | 0 /* RDTSCP */ | + 0 /* Reserved */ | f_lm | F(3DNOWEXT) | F(3DNOW); + /* cpuid 1.ecx */ + const u32 kvm_supported_word4_x86_features = + F(XMM3) | 0 /* Reserved, DTES64, MONITOR */ | + 0 /* DS-CPL, VMX, SMX, EST */ | + 0 /* TM2 */ | F(SSSE3) | 0 /* CNXT-ID */ | 0 /* Reserved */ | + 0 /* Reserved */ | F(CX16) | 0 /* xTPR Update, PDCM */ | + 0 /* Reserved, DCA */ | F(XMM4_1) | + F(XMM4_2) | 0 /* x2APIC */ | F(MOVBE) | F(POPCNT) | + 0 /* Reserved, XSAVE, OSXSAVE */; + /* cpuid 0x80000001.ecx */ const u32 kvm_supported_word6_x86_features = - bit(X86_FEATURE_LAHF_LM) | bit(X86_FEATURE_CMP_LEGACY) | - bit(X86_FEATURE_SVM); + F(LAHF_LM) | F(CMP_LEGACY) | F(SVM) | 0 /* ExtApicSpace */ | + F(CR8_LEGACY) | F(ABM) | F(SSE4A) | F(MISALIGNSSE) | + F(3DNOWPREFETCH) | 0 /* OSVW */ | 0 /* IBS */ | F(SSE5) | + 0 /* SKINIT */ | 0 /* WDT */; /* all calls to cpuid_count() should be made on the same cpu */ get_cpu(); @@ -1288,7 +1306,7 @@ static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function, break; case 1: entry->edx &= kvm_supported_word0_x86_features; - entry->ecx &= kvm_supported_word3_x86_features; + entry->ecx &= kvm_supported_word4_x86_features; break; /* function 2 entries are STATEFUL. That is, repeated cpuid commands * may return different values. This forces us to get_cpu() before @@ -1350,6 +1368,8 @@ static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function, put_cpu(); } +#undef F + static int kvm_dev_ioctl_get_supported_cpuid(struct kvm_cpuid2 *cpuid, struct kvm_cpuid_entry2 __user *entries) { @@ -1421,8 +1441,7 @@ static int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, return -ENXIO; vcpu_load(vcpu); - set_bit(irq->irq, vcpu->arch.irq_pending); - set_bit(irq->irq / BITS_PER_LONG, &vcpu->arch.irq_summary); + kvm_queue_interrupt(vcpu, irq->irq, false); vcpu_put(vcpu); @@ -1584,8 +1603,7 @@ long kvm_arch_vcpu_ioctl(struct file *filp, r = -EINVAL; } out: - if (lapic) - kfree(lapic); + kfree(lapic); return r; } @@ -1606,10 +1624,12 @@ static int kvm_vm_ioctl_set_nr_mmu_pages(struct kvm *kvm, return -EINVAL; down_write(&kvm->slots_lock); + spin_lock(&kvm->mmu_lock); kvm_mmu_change_mmu_pages(kvm, kvm_nr_mmu_pages); kvm->arch.n_requested_mmu_pages = kvm_nr_mmu_pages; + spin_unlock(&kvm->mmu_lock); up_write(&kvm->slots_lock); return 0; } @@ -1785,7 +1805,9 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, /* If nothing is dirty, don't bother messing with page tables. */ if (is_dirty) { + spin_lock(&kvm->mmu_lock); kvm_mmu_slot_remove_write_access(kvm, log->slot); + spin_unlock(&kvm->mmu_lock); kvm_flush_remote_tlbs(kvm); memslot = &kvm->memslots[log->slot]; n = ALIGN(memslot->npages, BITS_PER_LONG) / 8; @@ -2360,7 +2382,7 @@ int emulate_instruction(struct kvm_vcpu *vcpu, u16 error_code, int emulation_type) { - int r; + int r, shadow_mask; struct decode_cache *c; kvm_clear_exception_queue(vcpu); @@ -2408,7 +2430,16 @@ int emulate_instruction(struct kvm_vcpu *vcpu, } } + if (emulation_type & EMULTYPE_SKIP) { + kvm_rip_write(vcpu, vcpu->arch.emulate_ctxt.decode.eip); + return EMULATE_DONE; + } + r = x86_emulate_insn(&vcpu->arch.emulate_ctxt, &emulate_ops); + shadow_mask = vcpu->arch.emulate_ctxt.interruptibility; + + if (r == 0) + kvm_x86_ops->set_interrupt_shadow(vcpu, shadow_mask); if (vcpu->arch.pio.string) return EMULATE_DO_MMIO; @@ -2761,7 +2792,7 @@ int kvm_arch_init(void *opaque) kvm_mmu_set_nonpresent_ptes(0ull, 0ull); kvm_mmu_set_base_ptes(PT_PRESENT_MASK); kvm_mmu_set_mask_ptes(PT_USER_MASK, PT_ACCESSED_MASK, - PT_DIRTY_MASK, PT64_NX_MASK, 0, 0); + PT_DIRTY_MASK, PT64_NX_MASK, 0); for_each_possible_cpu(cpu) per_cpu(cpu_tsc_khz, cpu) = tsc_khz; @@ -3012,6 +3043,16 @@ struct kvm_cpuid_entry2 *kvm_find_cpuid_entry(struct kvm_vcpu *vcpu, return best; } +int cpuid_maxphyaddr(struct kvm_vcpu *vcpu) +{ + struct kvm_cpuid_entry2 *best; + + best = kvm_find_cpuid_entry(vcpu, 0x80000008, 0); + if (best) + return best->eax & 0xff; + return 36; +} + void kvm_emulate_cpuid(struct kvm_vcpu *vcpu) { u32 function, index; @@ -3048,10 +3089,9 @@ EXPORT_SYMBOL_GPL(kvm_emulate_cpuid); static int dm_request_for_irq_injection(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) { - return (!vcpu->arch.irq_summary && + return (!irqchip_in_kernel(vcpu->kvm) && !kvm_cpu_has_interrupt(vcpu) && kvm_run->request_interrupt_window && - vcpu->arch.interrupt_window_open && - (kvm_x86_ops->get_rflags(vcpu) & X86_EFLAGS_IF)); + kvm_arch_interrupt_allowed(vcpu)); } static void post_kvm_run_save(struct kvm_vcpu *vcpu, @@ -3064,8 +3104,9 @@ static void post_kvm_run_save(struct kvm_vcpu *vcpu, kvm_run->ready_for_interrupt_injection = 1; else kvm_run->ready_for_interrupt_injection = - (vcpu->arch.interrupt_window_open && - vcpu->arch.irq_summary == 0); + kvm_arch_interrupt_allowed(vcpu) && + !kvm_cpu_has_interrupt(vcpu) && + !kvm_event_needs_reinjection(vcpu); } static void vapic_enter(struct kvm_vcpu *vcpu) @@ -3094,9 +3135,63 @@ static void vapic_exit(struct kvm_vcpu *vcpu) up_read(&vcpu->kvm->slots_lock); } +static void update_cr8_intercept(struct kvm_vcpu *vcpu) +{ + int max_irr, tpr; + + if (!kvm_x86_ops->update_cr8_intercept) + return; + + if (!vcpu->arch.apic->vapic_addr) + max_irr = kvm_lapic_find_highest_irr(vcpu); + else + max_irr = -1; + + if (max_irr != -1) + max_irr >>= 4; + + tpr = kvm_lapic_get_cr8(vcpu); + + kvm_x86_ops->update_cr8_intercept(vcpu, tpr, max_irr); +} + +static void inject_pending_irq(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +{ + if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) + kvm_x86_ops->set_interrupt_shadow(vcpu, 0); + + /* try to reinject previous events if any */ + if (vcpu->arch.nmi_injected) { + kvm_x86_ops->set_nmi(vcpu); + return; + } + + if (vcpu->arch.interrupt.pending) { + kvm_x86_ops->set_irq(vcpu); + return; + } + + /* try to inject new event if pending */ + if (vcpu->arch.nmi_pending) { + if (kvm_x86_ops->nmi_allowed(vcpu)) { + vcpu->arch.nmi_pending = false; + vcpu->arch.nmi_injected = true; + kvm_x86_ops->set_nmi(vcpu); + } + } else if (kvm_cpu_has_interrupt(vcpu)) { + if (kvm_x86_ops->interrupt_allowed(vcpu)) { + kvm_queue_interrupt(vcpu, kvm_cpu_get_interrupt(vcpu), + false); + kvm_x86_ops->set_irq(vcpu); + } + } +} + static int vcpu_enter_guest(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) { int r; + bool req_int_win = !irqchip_in_kernel(vcpu->kvm) && + kvm_run->request_interrupt_window; if (vcpu->requests) if (test_and_clear_bit(KVM_REQ_MMU_RELOAD, &vcpu->requests)) @@ -3128,9 +3223,6 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) } } - clear_bit(KVM_REQ_PENDING_TIMER, &vcpu->requests); - kvm_inject_pending_timer_irqs(vcpu); - preempt_disable(); kvm_x86_ops->prepare_guest_switch(vcpu); @@ -3138,6 +3230,9 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) local_irq_disable(); + clear_bit(KVM_REQ_KICK, &vcpu->requests); + smp_mb__after_clear_bit(); + if (vcpu->requests || need_resched() || signal_pending(current)) { local_irq_enable(); preempt_enable(); @@ -3145,21 +3240,21 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) goto out; } - vcpu->guest_mode = 1; - /* - * Make sure that guest_mode assignment won't happen after - * testing the pending IRQ vector bitmap. - */ - smp_wmb(); - if (vcpu->arch.exception.pending) __queue_exception(vcpu); - else if (irqchip_in_kernel(vcpu->kvm)) - kvm_x86_ops->inject_pending_irq(vcpu); else - kvm_x86_ops->inject_pending_vectors(vcpu, kvm_run); + inject_pending_irq(vcpu, kvm_run); - kvm_lapic_sync_to_vapic(vcpu); + /* enable NMI/IRQ window open exits if needed */ + if (vcpu->arch.nmi_pending) + kvm_x86_ops->enable_nmi_window(vcpu); + else if (kvm_cpu_has_interrupt(vcpu) || req_int_win) + kvm_x86_ops->enable_irq_window(vcpu); + + if (kvm_lapic_enabled(vcpu)) { + update_cr8_intercept(vcpu); + kvm_lapic_sync_to_vapic(vcpu); + } up_read(&vcpu->kvm->slots_lock); @@ -3193,7 +3288,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) set_debugreg(vcpu->arch.host_dr6, 6); set_debugreg(vcpu->arch.host_dr7, 7); - vcpu->guest_mode = 0; + set_bit(KVM_REQ_KICK, &vcpu->requests); local_irq_enable(); ++vcpu->stat.exits; @@ -3220,8 +3315,6 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) profile_hit(KVM_PROFILING, (void *)rip); } - if (vcpu->arch.exception.pending && kvm_x86_ops->exception_injected(vcpu)) - vcpu->arch.exception.pending = false; kvm_lapic_sync_from_vapic(vcpu); @@ -3230,6 +3323,7 @@ out: return r; } + static int __vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) { int r; @@ -3256,29 +3350,42 @@ static int __vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) kvm_vcpu_block(vcpu); down_read(&vcpu->kvm->slots_lock); if (test_and_clear_bit(KVM_REQ_UNHALT, &vcpu->requests)) - if (vcpu->arch.mp_state == KVM_MP_STATE_HALTED) + { + switch(vcpu->arch.mp_state) { + case KVM_MP_STATE_HALTED: vcpu->arch.mp_state = - KVM_MP_STATE_RUNNABLE; - if (vcpu->arch.mp_state != KVM_MP_STATE_RUNNABLE) - r = -EINTR; + KVM_MP_STATE_RUNNABLE; + case KVM_MP_STATE_RUNNABLE: + break; + case KVM_MP_STATE_SIPI_RECEIVED: + default: + r = -EINTR; + break; + } + } } - if (r > 0) { - if (dm_request_for_irq_injection(vcpu, kvm_run)) { - r = -EINTR; - kvm_run->exit_reason = KVM_EXIT_INTR; - ++vcpu->stat.request_irq_exits; - } - if (signal_pending(current)) { - r = -EINTR; - kvm_run->exit_reason = KVM_EXIT_INTR; - ++vcpu->stat.signal_exits; - } - if (need_resched()) { - up_read(&vcpu->kvm->slots_lock); - kvm_resched(vcpu); - down_read(&vcpu->kvm->slots_lock); - } + if (r <= 0) + break; + + clear_bit(KVM_REQ_PENDING_TIMER, &vcpu->requests); + if (kvm_cpu_has_pending_timer(vcpu)) + kvm_inject_pending_timer_irqs(vcpu); + + if (dm_request_for_irq_injection(vcpu, kvm_run)) { + r = -EINTR; + kvm_run->exit_reason = KVM_EXIT_INTR; + ++vcpu->stat.request_irq_exits; + } + if (signal_pending(current)) { + r = -EINTR; + kvm_run->exit_reason = KVM_EXIT_INTR; + ++vcpu->stat.signal_exits; + } + if (need_resched()) { + up_read(&vcpu->kvm->slots_lock); + kvm_resched(vcpu); + down_read(&vcpu->kvm->slots_lock); } } @@ -3442,7 +3549,6 @@ int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs) { struct descriptor_table dt; - int pending_vec; vcpu_load(vcpu); @@ -3472,16 +3578,11 @@ int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu, sregs->efer = vcpu->arch.shadow_efer; sregs->apic_base = kvm_get_apic_base(vcpu); - if (irqchip_in_kernel(vcpu->kvm)) { - memset(sregs->interrupt_bitmap, 0, - sizeof sregs->interrupt_bitmap); - pending_vec = kvm_x86_ops->get_irq(vcpu); - if (pending_vec >= 0) - set_bit(pending_vec, - (unsigned long *)sregs->interrupt_bitmap); - } else - memcpy(sregs->interrupt_bitmap, vcpu->arch.irq_pending, - sizeof sregs->interrupt_bitmap); + memset(sregs->interrupt_bitmap, 0, sizeof sregs->interrupt_bitmap); + + if (vcpu->arch.interrupt.pending && !vcpu->arch.interrupt.soft) + set_bit(vcpu->arch.interrupt.nr, + (unsigned long *)sregs->interrupt_bitmap); vcpu_put(vcpu); @@ -3688,7 +3789,6 @@ static void save_state_to_tss32(struct kvm_vcpu *vcpu, tss->fs = get_segment_selector(vcpu, VCPU_SREG_FS); tss->gs = get_segment_selector(vcpu, VCPU_SREG_GS); tss->ldt_selector = get_segment_selector(vcpu, VCPU_SREG_LDTR); - tss->prev_task_link = get_segment_selector(vcpu, VCPU_SREG_TR); } static int load_state_from_tss32(struct kvm_vcpu *vcpu, @@ -3785,8 +3885,8 @@ static int load_state_from_tss16(struct kvm_vcpu *vcpu, } static int kvm_task_switch_16(struct kvm_vcpu *vcpu, u16 tss_selector, - u32 old_tss_base, - struct desc_struct *nseg_desc) + u16 old_tss_sel, u32 old_tss_base, + struct desc_struct *nseg_desc) { struct tss_segment_16 tss_segment_16; int ret = 0; @@ -3805,6 +3905,16 @@ static int kvm_task_switch_16(struct kvm_vcpu *vcpu, u16 tss_selector, &tss_segment_16, sizeof tss_segment_16)) goto out; + if (old_tss_sel != 0xffff) { + tss_segment_16.prev_task_link = old_tss_sel; + + if (kvm_write_guest(vcpu->kvm, + get_tss_base_addr(vcpu, nseg_desc), + &tss_segment_16.prev_task_link, + sizeof tss_segment_16.prev_task_link)) + goto out; + } + if (load_state_from_tss16(vcpu, &tss_segment_16)) goto out; @@ -3814,7 +3924,7 @@ out: } static int kvm_task_switch_32(struct kvm_vcpu *vcpu, u16 tss_selector, - u32 old_tss_base, + u16 old_tss_sel, u32 old_tss_base, struct desc_struct *nseg_desc) { struct tss_segment_32 tss_segment_32; @@ -3834,6 +3944,16 @@ static int kvm_task_switch_32(struct kvm_vcpu *vcpu, u16 tss_selector, &tss_segment_32, sizeof tss_segment_32)) goto out; + if (old_tss_sel != 0xffff) { + tss_segment_32.prev_task_link = old_tss_sel; + + if (kvm_write_guest(vcpu->kvm, + get_tss_base_addr(vcpu, nseg_desc), + &tss_segment_32.prev_task_link, + sizeof tss_segment_32.prev_task_link)) + goto out; + } + if (load_state_from_tss32(vcpu, &tss_segment_32)) goto out; @@ -3887,14 +4007,22 @@ int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason) kvm_x86_ops->set_rflags(vcpu, eflags & ~X86_EFLAGS_NT); } - kvm_x86_ops->skip_emulated_instruction(vcpu); + /* set back link to prev task only if NT bit is set in eflags + note that old_tss_sel is not used afetr this point */ + if (reason != TASK_SWITCH_CALL && reason != TASK_SWITCH_GATE) + old_tss_sel = 0xffff; + + /* set back link to prev task only if NT bit is set in eflags + note that old_tss_sel is not used afetr this point */ + if (reason != TASK_SWITCH_CALL && reason != TASK_SWITCH_GATE) + old_tss_sel = 0xffff; if (nseg_desc.type & 8) - ret = kvm_task_switch_32(vcpu, tss_selector, old_tss_base, - &nseg_desc); + ret = kvm_task_switch_32(vcpu, tss_selector, old_tss_sel, + old_tss_base, &nseg_desc); else - ret = kvm_task_switch_16(vcpu, tss_selector, old_tss_base, - &nseg_desc); + ret = kvm_task_switch_16(vcpu, tss_selector, old_tss_sel, + old_tss_base, &nseg_desc); if (reason == TASK_SWITCH_CALL || reason == TASK_SWITCH_GATE) { u32 eflags = kvm_x86_ops->get_rflags(vcpu); @@ -3920,7 +4048,7 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs) { int mmu_reset_needed = 0; - int i, pending_vec, max_bits; + int pending_vec, max_bits; struct descriptor_table dt; vcpu_load(vcpu); @@ -3934,7 +4062,13 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, vcpu->arch.cr2 = sregs->cr2; mmu_reset_needed |= vcpu->arch.cr3 != sregs->cr3; - vcpu->arch.cr3 = sregs->cr3; + + down_read(&vcpu->kvm->slots_lock); + if (gfn_to_memslot(vcpu->kvm, sregs->cr3 >> PAGE_SHIFT)) + vcpu->arch.cr3 = sregs->cr3; + else + set_bit(KVM_REQ_TRIPLE_FAULT, &vcpu->requests); + up_read(&vcpu->kvm->slots_lock); kvm_set_cr8(vcpu, sregs->cr8); @@ -3956,25 +4090,14 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, if (mmu_reset_needed) kvm_mmu_reset_context(vcpu); - if (!irqchip_in_kernel(vcpu->kvm)) { - memcpy(vcpu->arch.irq_pending, sregs->interrupt_bitmap, - sizeof vcpu->arch.irq_pending); - vcpu->arch.irq_summary = 0; - for (i = 0; i < ARRAY_SIZE(vcpu->arch.irq_pending); ++i) - if (vcpu->arch.irq_pending[i]) - __set_bit(i, &vcpu->arch.irq_summary); - } else { - max_bits = (sizeof sregs->interrupt_bitmap) << 3; - pending_vec = find_first_bit( - (const unsigned long *)sregs->interrupt_bitmap, - max_bits); - /* Only pending external irq is handled here */ - if (pending_vec < max_bits) { - kvm_x86_ops->set_irq(vcpu, pending_vec); - pr_debug("Set back pending irq %d\n", - pending_vec); - } - kvm_pic_clear_isr_ack(vcpu->kvm); + max_bits = (sizeof sregs->interrupt_bitmap) << 3; + pending_vec = find_first_bit( + (const unsigned long *)sregs->interrupt_bitmap, max_bits); + if (pending_vec < max_bits) { + kvm_queue_interrupt(vcpu, pending_vec, false); + pr_debug("Set back pending irq %d\n", pending_vec); + if (irqchip_in_kernel(vcpu->kvm)) + kvm_pic_clear_isr_ack(vcpu->kvm); } kvm_set_segment(vcpu, &sregs->cs, VCPU_SREG_CS); @@ -4308,7 +4431,6 @@ struct kvm *kvm_arch_create_vm(void) return ERR_PTR(-ENOMEM); INIT_LIST_HEAD(&kvm->arch.active_mmu_pages); - INIT_LIST_HEAD(&kvm->arch.oos_global_pages); INIT_LIST_HEAD(&kvm->arch.assigned_dev_head); /* Reserve bit 0 of irq_sources_bitmap for userspace irq source */ @@ -4411,12 +4533,14 @@ int kvm_arch_set_memory_region(struct kvm *kvm, } } + spin_lock(&kvm->mmu_lock); if (!kvm->arch.n_requested_mmu_pages) { unsigned int nr_mmu_pages = kvm_mmu_calculate_mmu_pages(kvm); kvm_mmu_change_mmu_pages(kvm, nr_mmu_pages); } kvm_mmu_slot_remove_write_access(kvm, mem->slot); + spin_unlock(&kvm->mmu_lock); kvm_flush_remote_tlbs(kvm); return 0; @@ -4425,6 +4549,7 @@ int kvm_arch_set_memory_region(struct kvm *kvm, void kvm_arch_flush_shadow(struct kvm *kvm) { kvm_mmu_zap_all(kvm); + kvm_reload_remote_mmus(kvm); } int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu) @@ -4434,28 +4559,24 @@ int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu) || vcpu->arch.nmi_pending; } -static void vcpu_kick_intr(void *info) -{ -#ifdef DEBUG - struct kvm_vcpu *vcpu = (struct kvm_vcpu *)info; - printk(KERN_DEBUG "vcpu_kick_intr %p \n", vcpu); -#endif -} - void kvm_vcpu_kick(struct kvm_vcpu *vcpu) { - int ipi_pcpu = vcpu->cpu; - int cpu = get_cpu(); + int me; + int cpu = vcpu->cpu; if (waitqueue_active(&vcpu->wq)) { wake_up_interruptible(&vcpu->wq); ++vcpu->stat.halt_wakeup; } - /* - * We may be called synchronously with irqs disabled in guest mode, - * So need not to call smp_call_function_single() in that case. - */ - if (vcpu->guest_mode && vcpu->cpu != cpu) - smp_call_function_single(ipi_pcpu, vcpu_kick_intr, vcpu, 0); + + me = get_cpu(); + if (cpu != me && (unsigned)cpu < nr_cpu_ids && cpu_online(cpu)) + if (!test_and_set_bit(KVM_REQ_KICK, &vcpu->requests)) + smp_send_reschedule(cpu); put_cpu(); } + +int kvm_arch_interrupt_allowed(struct kvm_vcpu *vcpu) +{ + return kvm_x86_ops->interrupt_allowed(vcpu); +} diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h index 6a4be78a7384..4c8e10af78e8 100644 --- a/arch/x86/kvm/x86.h +++ b/arch/x86/kvm/x86.h @@ -8,9 +8,11 @@ static inline void kvm_clear_exception_queue(struct kvm_vcpu *vcpu) vcpu->arch.exception.pending = false; } -static inline void kvm_queue_interrupt(struct kvm_vcpu *vcpu, u8 vector) +static inline void kvm_queue_interrupt(struct kvm_vcpu *vcpu, u8 vector, + bool soft) { vcpu->arch.interrupt.pending = true; + vcpu->arch.interrupt.soft = soft; vcpu->arch.interrupt.nr = vector; } @@ -19,4 +21,14 @@ static inline void kvm_clear_interrupt_queue(struct kvm_vcpu *vcpu) vcpu->arch.interrupt.pending = false; } +static inline bool kvm_event_needs_reinjection(struct kvm_vcpu *vcpu) +{ + return vcpu->arch.exception.pending || vcpu->arch.interrupt.pending || + vcpu->arch.nmi_injected; +} + +static inline bool kvm_exception_is_soft(unsigned int nr) +{ + return (nr == BP_VECTOR) || (nr == OF_VECTOR); +} #endif diff --git a/arch/x86/kvm/x86_emulate.c b/arch/x86/kvm/x86_emulate.c index ca91749d2083..c1b6c232e02b 100644 --- a/arch/x86/kvm/x86_emulate.c +++ b/arch/x86/kvm/x86_emulate.c @@ -59,13 +59,14 @@ #define SrcImm (5<<4) /* Immediate operand. */ #define SrcImmByte (6<<4) /* 8-bit sign-extended immediate operand. */ #define SrcOne (7<<4) /* Implied '1' */ -#define SrcMask (7<<4) +#define SrcImmUByte (8<<4) /* 8-bit unsigned immediate operand. */ +#define SrcMask (0xf<<4) /* Generic ModRM decode. */ -#define ModRM (1<<7) +#define ModRM (1<<8) /* Destination is only written; never read. */ -#define Mov (1<<8) -#define BitOp (1<<9) -#define MemAbs (1<<10) /* Memory operand is absolute displacement */ +#define Mov (1<<9) +#define BitOp (1<<10) +#define MemAbs (1<<11) /* Memory operand is absolute displacement */ #define String (1<<12) /* String instruction (rep capable) */ #define Stack (1<<13) /* Stack instruction (push/pop) */ #define Group (1<<14) /* Bits 3:5 of modrm byte extend opcode */ @@ -76,6 +77,7 @@ #define Src2CL (1<<29) #define Src2ImmByte (2<<29) #define Src2One (3<<29) +#define Src2Imm16 (4<<29) #define Src2Mask (7<<29) enum { @@ -135,11 +137,11 @@ static u32 opcode_table[256] = { SrcNone | ByteOp | ImplicitOps, SrcNone | ImplicitOps, /* insb, insw/insd */ SrcNone | ByteOp | ImplicitOps, SrcNone | ImplicitOps, /* outsb, outsw/outsd */ /* 0x70 - 0x77 */ - ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, - ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, + SrcImmByte, SrcImmByte, SrcImmByte, SrcImmByte, + SrcImmByte, SrcImmByte, SrcImmByte, SrcImmByte, /* 0x78 - 0x7F */ - ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, - ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, + SrcImmByte, SrcImmByte, SrcImmByte, SrcImmByte, + SrcImmByte, SrcImmByte, SrcImmByte, SrcImmByte, /* 0x80 - 0x87 */ Group | Group1_80, Group | Group1_81, Group | Group1_82, Group | Group1_83, @@ -153,7 +155,8 @@ static u32 opcode_table[256] = { /* 0x90 - 0x97 */ DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, /* 0x98 - 0x9F */ - 0, 0, 0, 0, ImplicitOps | Stack, ImplicitOps | Stack, 0, 0, + 0, 0, SrcImm | Src2Imm16, 0, + ImplicitOps | Stack, ImplicitOps | Stack, 0, 0, /* 0xA0 - 0xA7 */ ByteOp | DstReg | SrcMem | Mov | MemAbs, DstReg | SrcMem | Mov | MemAbs, ByteOp | DstMem | SrcReg | Mov | MemAbs, DstMem | SrcReg | Mov | MemAbs, @@ -178,7 +181,8 @@ static u32 opcode_table[256] = { 0, ImplicitOps | Stack, 0, 0, ByteOp | DstMem | SrcImm | ModRM | Mov, DstMem | SrcImm | ModRM | Mov, /* 0xC8 - 0xCF */ - 0, 0, 0, ImplicitOps | Stack, 0, 0, 0, 0, + 0, 0, 0, ImplicitOps | Stack, + ImplicitOps, SrcImmByte, ImplicitOps, ImplicitOps, /* 0xD0 - 0xD7 */ ByteOp | DstMem | SrcImplicit | ModRM, DstMem | SrcImplicit | ModRM, ByteOp | DstMem | SrcImplicit | ModRM, DstMem | SrcImplicit | ModRM, @@ -187,11 +191,11 @@ static u32 opcode_table[256] = { 0, 0, 0, 0, 0, 0, 0, 0, /* 0xE0 - 0xE7 */ 0, 0, 0, 0, - SrcNone | ByteOp | ImplicitOps, SrcNone | ImplicitOps, - SrcNone | ByteOp | ImplicitOps, SrcNone | ImplicitOps, + ByteOp | SrcImmUByte, SrcImmUByte, + ByteOp | SrcImmUByte, SrcImmUByte, /* 0xE8 - 0xEF */ - ImplicitOps | Stack, SrcImm | ImplicitOps, - ImplicitOps, SrcImmByte | ImplicitOps, + SrcImm | Stack, SrcImm | ImplicitOps, + SrcImm | Src2Imm16, SrcImmByte | ImplicitOps, SrcNone | ByteOp | ImplicitOps, SrcNone | ImplicitOps, SrcNone | ByteOp | ImplicitOps, SrcNone | ImplicitOps, /* 0xF0 - 0xF7 */ @@ -230,10 +234,8 @@ static u32 twobyte_table[256] = { /* 0x70 - 0x7F */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 - 0x8F */ - ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, - ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, - ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, - ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, + SrcImm, SrcImm, SrcImm, SrcImm, SrcImm, SrcImm, SrcImm, SrcImm, + SrcImm, SrcImm, SrcImm, SrcImm, SrcImm, SrcImm, SrcImm, SrcImm, /* 0x90 - 0x9F */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xA0 - 0xA7 */ @@ -1044,10 +1046,14 @@ done_prefixes: } break; case SrcImmByte: + case SrcImmUByte: c->src.type = OP_IMM; c->src.ptr = (unsigned long *)c->eip; c->src.bytes = 1; - c->src.val = insn_fetch(s8, 1, c->eip); + if ((c->d & SrcMask) == SrcImmByte) + c->src.val = insn_fetch(s8, 1, c->eip); + else + c->src.val = insn_fetch(u8, 1, c->eip); break; case SrcOne: c->src.bytes = 1; @@ -1072,6 +1078,12 @@ done_prefixes: c->src2.bytes = 1; c->src2.val = insn_fetch(u8, 1, c->eip); break; + case Src2Imm16: + c->src2.type = OP_IMM; + c->src2.ptr = (unsigned long *)c->eip; + c->src2.bytes = 2; + c->src2.val = insn_fetch(u16, 2, c->eip); + break; case Src2One: c->src2.bytes = 1; c->src2.val = 1; @@ -1349,6 +1361,20 @@ static inline int writeback(struct x86_emulate_ctxt *ctxt, return 0; } +void toggle_interruptibility(struct x86_emulate_ctxt *ctxt, u32 mask) +{ + u32 int_shadow = kvm_x86_ops->get_interrupt_shadow(ctxt->vcpu, mask); + /* + * an sti; sti; sequence only disable interrupts for the first + * instruction. So, if the last instruction, be it emulated or + * not, left the system with the INT_STI flag enabled, it + * means that the last instruction is an sti. We should not + * leave the flag on in this case. The same goes for mov ss + */ + if (!(int_shadow & mask)) + ctxt->interruptibility = mask; +} + int x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) { @@ -1360,6 +1386,8 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) int io_dir_in; int rc = 0; + ctxt->interruptibility = 0; + /* Shadow copy of register state. Committed on successful emulation. * NOTE: we can copy them from vcpu as x86_decode_insn() doesn't * modify them. @@ -1531,13 +1559,10 @@ special_insn: return -1; } return 0; - case 0x70 ... 0x7f: /* jcc (short) */ { - int rel = insn_fetch(s8, 1, c->eip); - + case 0x70 ... 0x7f: /* jcc (short) */ if (test_cc(c->b, ctxt->eflags)) - jmp_rel(c, rel); + jmp_rel(c, c->src.val); break; - } case 0x80 ... 0x83: /* Grp1 */ switch (c->modrm_reg) { case 0: @@ -1609,6 +1634,9 @@ special_insn: int err; sel = c->src.val; + if (c->modrm_reg == VCPU_SREG_SS) + toggle_interruptibility(ctxt, X86_SHADOW_INT_MOV_SS); + if (c->modrm_reg <= 5) { type_bits = (c->modrm_reg == 1) ? 9 : 1; err = kvm_load_segment_descriptor(ctxt->vcpu, sel, @@ -1769,59 +1797,32 @@ special_insn: break; case 0xe4: /* inb */ case 0xe5: /* in */ - port = insn_fetch(u8, 1, c->eip); + port = c->src.val; io_dir_in = 1; goto do_io; case 0xe6: /* outb */ case 0xe7: /* out */ - port = insn_fetch(u8, 1, c->eip); + port = c->src.val; io_dir_in = 0; goto do_io; case 0xe8: /* call (near) */ { - long int rel; - switch (c->op_bytes) { - case 2: - rel = insn_fetch(s16, 2, c->eip); - break; - case 4: - rel = insn_fetch(s32, 4, c->eip); - break; - default: - DPRINTF("Call: Invalid op_bytes\n"); - goto cannot_emulate; - } + long int rel = c->src.val; c->src.val = (unsigned long) c->eip; jmp_rel(c, rel); - c->op_bytes = c->ad_bytes; emulate_push(ctxt); break; } case 0xe9: /* jmp rel */ 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) { + case 0xea: /* jmp far */ + if (kvm_load_segment_descriptor(ctxt->vcpu, c->src2.val, 9, + VCPU_SREG_CS) < 0) { DPRINTF("jmp far: Failed to load CS descriptor\n"); goto cannot_emulate; } - c->eip = eip; + c->eip = c->src.val; break; - } case 0xeb: jmp: /* jmp rel short */ jmp_rel(c, c->src.val); @@ -1865,6 +1866,7 @@ special_insn: c->dst.type = OP_NONE; /* Disable writeback. */ break; case 0xfb: /* sti */ + toggle_interruptibility(ctxt, X86_SHADOW_INT_STI); ctxt->eflags |= X86_EFLAGS_IF; c->dst.type = OP_NONE; /* Disable writeback. */ break; @@ -2039,28 +2041,11 @@ twobyte_insn: if (!test_cc(c->b, ctxt->eflags)) c->dst.type = OP_NONE; /* no writeback */ break; - case 0x80 ... 0x8f: /* jnz rel, etc*/ { - long int rel; - - switch (c->op_bytes) { - case 2: - rel = insn_fetch(s16, 2, c->eip); - break; - case 4: - rel = insn_fetch(s32, 4, c->eip); - break; - case 8: - rel = insn_fetch(s64, 8, c->eip); - break; - default: - DPRINTF("jnz: Invalid op_bytes\n"); - goto cannot_emulate; - } + case 0x80 ... 0x8f: /* jnz rel, etc*/ if (test_cc(c->b, ctxt->eflags)) - jmp_rel(c, rel); + jmp_rel(c, c->src.val); c->dst.type = OP_NONE; break; - } case 0xa3: bt: /* bt */ c->dst.type = OP_NONE; diff --git a/arch/x86/lguest/Kconfig b/arch/x86/lguest/Kconfig index 8dab8f7844d3..38718041efc3 100644 --- a/arch/x86/lguest/Kconfig +++ b/arch/x86/lguest/Kconfig @@ -2,7 +2,6 @@ config LGUEST_GUEST bool "Lguest guest support" select PARAVIRT depends on X86_32 - depends on !X86_PAE select VIRTIO select VIRTIO_RING select VIRTIO_CONSOLE diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c index 33a93b417396..7bc65f0f62c4 100644 --- a/arch/x86/lguest/boot.c +++ b/arch/x86/lguest/boot.c @@ -87,7 +87,7 @@ struct lguest_data lguest_data = { /*G:037 async_hcall() is pretty simple: I'm quite proud of it really. We have a * ring buffer of stored hypercalls which the Host will run though next time we - * do a normal hypercall. Each entry in the ring has 4 slots for the hypercall + * do a normal hypercall. Each entry in the ring has 5 slots for the hypercall * arguments, and a "hcall_status" word which is 0 if the call is ready to go, * and 255 once the Host has finished with it. * @@ -96,7 +96,8 @@ struct lguest_data lguest_data = { * effect of causing the Host to run all the stored calls in the ring buffer * which empties it for next time! */ static void async_hcall(unsigned long call, unsigned long arg1, - unsigned long arg2, unsigned long arg3) + unsigned long arg2, unsigned long arg3, + unsigned long arg4) { /* Note: This code assumes we're uniprocessor. */ static unsigned int next_call; @@ -108,12 +109,13 @@ static void async_hcall(unsigned long call, unsigned long arg1, local_irq_save(flags); if (lguest_data.hcall_status[next_call] != 0xFF) { /* Table full, so do normal hcall which will flush table. */ - kvm_hypercall3(call, arg1, arg2, arg3); + kvm_hypercall4(call, arg1, arg2, arg3, arg4); } else { lguest_data.hcalls[next_call].arg0 = call; lguest_data.hcalls[next_call].arg1 = arg1; lguest_data.hcalls[next_call].arg2 = arg2; lguest_data.hcalls[next_call].arg3 = arg3; + lguest_data.hcalls[next_call].arg4 = arg4; /* Arguments must all be written before we mark it to go */ wmb(); lguest_data.hcall_status[next_call] = 0; @@ -141,7 +143,7 @@ static void lazy_hcall1(unsigned long call, if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE) kvm_hypercall1(call, arg1); else - async_hcall(call, arg1, 0, 0); + async_hcall(call, arg1, 0, 0, 0); } static void lazy_hcall2(unsigned long call, @@ -151,7 +153,7 @@ static void lazy_hcall2(unsigned long call, if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE) kvm_hypercall2(call, arg1, arg2); else - async_hcall(call, arg1, arg2, 0); + async_hcall(call, arg1, arg2, 0, 0); } static void lazy_hcall3(unsigned long call, @@ -162,18 +164,38 @@ static void lazy_hcall3(unsigned long call, if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE) kvm_hypercall3(call, arg1, arg2, arg3); else - async_hcall(call, arg1, arg2, arg3); + async_hcall(call, arg1, arg2, arg3, 0); } +#ifdef CONFIG_X86_PAE +static void lazy_hcall4(unsigned long call, + unsigned long arg1, + unsigned long arg2, + unsigned long arg3, + unsigned long arg4) +{ + if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE) + kvm_hypercall4(call, arg1, arg2, arg3, arg4); + else + async_hcall(call, arg1, arg2, arg3, arg4); +} +#endif + /* When lazy mode is turned off reset the per-cpu lazy mode variable and then * issue the do-nothing hypercall to flush any stored calls. */ -static void lguest_leave_lazy_mode(void) +static void lguest_leave_lazy_mmu_mode(void) { - paravirt_leave_lazy(paravirt_get_lazy_mode()); kvm_hypercall0(LHCALL_FLUSH_ASYNC); + paravirt_leave_lazy_mmu(); } -/*G:033 +static void lguest_end_context_switch(struct task_struct *next) +{ + kvm_hypercall0(LHCALL_FLUSH_ASYNC); + paravirt_end_context_switch(next); +} + +/*G:032 * After that diversion we return to our first native-instruction * replacements: four functions for interrupt control. * @@ -193,30 +215,28 @@ static unsigned long save_fl(void) { return lguest_data.irq_enabled; } -PV_CALLEE_SAVE_REGS_THUNK(save_fl); - -/* restore_flags() just sets the flags back to the value given. */ -static void restore_fl(unsigned long flags) -{ - lguest_data.irq_enabled = flags; -} -PV_CALLEE_SAVE_REGS_THUNK(restore_fl); /* Interrupts go off... */ static void irq_disable(void) { lguest_data.irq_enabled = 0; } + +/* Let's pause a moment. Remember how I said these are called so often? + * Jeremy Fitzhardinge optimized them so hard early in 2009 that he had to + * break some rules. In particular, these functions are assumed to save their + * own registers if they need to: normal C functions assume they can trash the + * eax register. To use normal C functions, we use + * PV_CALLEE_SAVE_REGS_THUNK(), which pushes %eax onto the stack, calls the + * C function, then restores it. */ +PV_CALLEE_SAVE_REGS_THUNK(save_fl); PV_CALLEE_SAVE_REGS_THUNK(irq_disable); - -/* Interrupts go on... */ -static void irq_enable(void) -{ - lguest_data.irq_enabled = X86_EFLAGS_IF; -} -PV_CALLEE_SAVE_REGS_THUNK(irq_enable); - /*:*/ + +/* These are in i386_head.S */ +extern void lg_irq_enable(void); +extern void lg_restore_fl(unsigned long flags); + /*M:003 Note that we don't check for outstanding interrupts when we re-enable * them (or when we unmask an interrupt). This seems to work for the moment, * since interrupts are rare and we'll just get the interrupt on the next timer @@ -362,8 +382,8 @@ static void lguest_cpuid(unsigned int *ax, unsigned int *bx, case 1: /* Basic feature request. */ /* We only allow kernel to see SSE3, CMPXCHG16B and SSSE3 */ *cx &= 0x00002201; - /* SSE, SSE2, FXSR, MMX, CMOV, CMPXCHG8B, TSC, FPU. */ - *dx &= 0x07808111; + /* SSE, SSE2, FXSR, MMX, CMOV, CMPXCHG8B, TSC, FPU, PAE. */ + *dx &= 0x07808151; /* The Host can do a nice optimization if it knows that the * kernel mappings (addresses above 0xC0000000 or whatever * PAGE_OFFSET is set to) haven't changed. But Linux calls @@ -382,6 +402,11 @@ static void lguest_cpuid(unsigned int *ax, unsigned int *bx, if (*ax > 0x80000008) *ax = 0x80000008; break; + case 0x80000001: + /* Here we should fix nx cap depending on host. */ + /* For this version of PAE, we just clear NX bit. */ + *dx &= ~(1 << 20); + break; } } @@ -515,25 +540,52 @@ static void lguest_write_cr4(unsigned long val) static void lguest_pte_update(struct mm_struct *mm, unsigned long addr, pte_t *ptep) { +#ifdef CONFIG_X86_PAE + lazy_hcall4(LHCALL_SET_PTE, __pa(mm->pgd), addr, + ptep->pte_low, ptep->pte_high); +#else lazy_hcall3(LHCALL_SET_PTE, __pa(mm->pgd), addr, ptep->pte_low); +#endif } static void lguest_set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pteval) { - *ptep = pteval; + native_set_pte(ptep, pteval); lguest_pte_update(mm, addr, ptep); } -/* The Guest calls this to set a top-level entry. Again, we set the entry then - * tell the Host which top-level page we changed, and the index of the entry we - * changed. */ +/* The Guest calls lguest_set_pud to set a top-level entry and lguest_set_pmd + * to set a middle-level entry when PAE is activated. + * Again, we set the entry then tell the Host which page we changed, + * and the index of the entry we changed. */ +#ifdef CONFIG_X86_PAE +static void lguest_set_pud(pud_t *pudp, pud_t pudval) +{ + native_set_pud(pudp, pudval); + + /* 32 bytes aligned pdpt address and the index. */ + lazy_hcall2(LHCALL_SET_PGD, __pa(pudp) & 0xFFFFFFE0, + (__pa(pudp) & 0x1F) / sizeof(pud_t)); +} + static void lguest_set_pmd(pmd_t *pmdp, pmd_t pmdval) { - *pmdp = pmdval; + native_set_pmd(pmdp, pmdval); lazy_hcall2(LHCALL_SET_PMD, __pa(pmdp) & PAGE_MASK, - (__pa(pmdp) & (PAGE_SIZE - 1)) / 4); + (__pa(pmdp) & (PAGE_SIZE - 1)) / sizeof(pmd_t)); } +#else + +/* The Guest calls lguest_set_pmd to set a top-level entry when PAE is not + * activated. */ +static void lguest_set_pmd(pmd_t *pmdp, pmd_t pmdval) +{ + native_set_pmd(pmdp, pmdval); + lazy_hcall2(LHCALL_SET_PGD, __pa(pmdp) & PAGE_MASK, + (__pa(pmdp) & (PAGE_SIZE - 1)) / sizeof(pmd_t)); +} +#endif /* There are a couple of legacy places where the kernel sets a PTE, but we * don't know the top level any more. This is useless for us, since we don't @@ -546,11 +598,31 @@ static void lguest_set_pmd(pmd_t *pmdp, pmd_t pmdval) * which brings boot back to 0.25 seconds. */ static void lguest_set_pte(pte_t *ptep, pte_t pteval) { - *ptep = pteval; + native_set_pte(ptep, pteval); if (cr3_changed) lazy_hcall1(LHCALL_FLUSH_TLB, 1); } +#ifdef CONFIG_X86_PAE +static void lguest_set_pte_atomic(pte_t *ptep, pte_t pte) +{ + native_set_pte_atomic(ptep, pte); + if (cr3_changed) + lazy_hcall1(LHCALL_FLUSH_TLB, 1); +} + +void lguest_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) +{ + native_pte_clear(mm, addr, ptep); + lguest_pte_update(mm, addr, ptep); +} + +void lguest_pmd_clear(pmd_t *pmdp) +{ + lguest_set_pmd(pmdp, __pmd(0)); +} +#endif + /* Unfortunately for Lguest, the pv_mmu_ops for page tables were based on * native page table operations. On native hardware you can set a new page * table entry whenever you want, but if you want to remove one you have to do @@ -622,13 +694,12 @@ static void __init lguest_init_IRQ(void) { unsigned int i; - for (i = 0; i < LGUEST_IRQS; i++) { - int vector = FIRST_EXTERNAL_VECTOR + i; + for (i = FIRST_EXTERNAL_VECTOR; i < NR_VECTORS; i++) { /* Some systems map "vectors" to interrupts weirdly. Lguest has * a straightforward 1 to 1 mapping, so force that here. */ - __get_cpu_var(vector_irq)[vector] = i; - if (vector != SYSCALL_VECTOR) - set_intr_gate(vector, interrupt[i]); + __get_cpu_var(vector_irq)[i] = i - FIRST_EXTERNAL_VECTOR; + if (i != SYSCALL_VECTOR) + set_intr_gate(i, interrupt[i - FIRST_EXTERNAL_VECTOR]); } /* This call is required to set up for 4k stacks, where we have * separate stacks for hard and soft interrupts. */ @@ -637,7 +708,7 @@ static void __init lguest_init_IRQ(void) void lguest_setup_irq(unsigned int irq) { - irq_to_desc_alloc_cpu(irq, 0); + irq_to_desc_alloc_node(irq, 0); set_irq_chip_and_handler_name(irq, &lguest_irq_controller, handle_level_irq, "level"); } @@ -967,10 +1038,10 @@ static void lguest_restart(char *reason) * * Our current solution is to allow the paravirt back end to optionally patch * over the indirect calls to replace them with something more efficient. We - * patch the four most commonly called functions: disable interrupts, enable - * interrupts, restore interrupts and save interrupts. We usually have 6 or 10 - * bytes to patch into: the Guest versions of these operations are small enough - * that we can fit comfortably. + * patch two of the simplest of the most commonly called functions: disable + * interrupts and save interrupts. We usually have 6 or 10 bytes to patch + * into: the Guest versions of these operations are small enough that we can + * fit comfortably. * * First we need assembly templates of each of the patchable Guest operations, * and these are in i386_head.S. */ @@ -981,8 +1052,6 @@ static const struct lguest_insns const char *start, *end; } lguest_insns[] = { [PARAVIRT_PATCH(pv_irq_ops.irq_disable)] = { lgstart_cli, lgend_cli }, - [PARAVIRT_PATCH(pv_irq_ops.irq_enable)] = { lgstart_sti, lgend_sti }, - [PARAVIRT_PATCH(pv_irq_ops.restore_fl)] = { lgstart_popf, lgend_popf }, [PARAVIRT_PATCH(pv_irq_ops.save_fl)] = { lgstart_pushf, lgend_pushf }, }; @@ -1020,6 +1089,7 @@ __init void lguest_init(void) pv_info.name = "lguest"; pv_info.paravirt_enabled = 1; pv_info.kernel_rpl = 1; + pv_info.shared_kernel_pmd = 1; /* We set up all the lguest overrides for sensitive operations. These * are detailed with the operations themselves. */ @@ -1027,9 +1097,9 @@ __init void lguest_init(void) /* interrupt-related operations */ pv_irq_ops.init_IRQ = lguest_init_IRQ; pv_irq_ops.save_fl = PV_CALLEE_SAVE(save_fl); - pv_irq_ops.restore_fl = PV_CALLEE_SAVE(restore_fl); + pv_irq_ops.restore_fl = __PV_IS_CALLEE_SAVE(lg_restore_fl); pv_irq_ops.irq_disable = PV_CALLEE_SAVE(irq_disable); - pv_irq_ops.irq_enable = PV_CALLEE_SAVE(irq_enable); + pv_irq_ops.irq_enable = __PV_IS_CALLEE_SAVE(lg_irq_enable); pv_irq_ops.safe_halt = lguest_safe_halt; /* init-time operations */ @@ -1054,8 +1124,8 @@ __init void lguest_init(void) pv_cpu_ops.write_gdt_entry = lguest_write_gdt_entry; pv_cpu_ops.write_idt_entry = lguest_write_idt_entry; pv_cpu_ops.wbinvd = lguest_wbinvd; - pv_cpu_ops.lazy_mode.enter = paravirt_enter_lazy_cpu; - pv_cpu_ops.lazy_mode.leave = lguest_leave_lazy_mode; + pv_cpu_ops.start_context_switch = paravirt_start_context_switch; + pv_cpu_ops.end_context_switch = lguest_end_context_switch; /* pagetable management */ pv_mmu_ops.write_cr3 = lguest_write_cr3; @@ -1065,10 +1135,16 @@ __init void lguest_init(void) pv_mmu_ops.set_pte = lguest_set_pte; pv_mmu_ops.set_pte_at = lguest_set_pte_at; pv_mmu_ops.set_pmd = lguest_set_pmd; +#ifdef CONFIG_X86_PAE + pv_mmu_ops.set_pte_atomic = lguest_set_pte_atomic; + pv_mmu_ops.pte_clear = lguest_pte_clear; + pv_mmu_ops.pmd_clear = lguest_pmd_clear; + pv_mmu_ops.set_pud = lguest_set_pud; +#endif pv_mmu_ops.read_cr2 = lguest_read_cr2; pv_mmu_ops.read_cr3 = lguest_read_cr3; pv_mmu_ops.lazy_mode.enter = paravirt_enter_lazy_mmu; - pv_mmu_ops.lazy_mode.leave = lguest_leave_lazy_mode; + pv_mmu_ops.lazy_mode.leave = lguest_leave_lazy_mmu_mode; pv_mmu_ops.pte_update = lguest_pte_update; pv_mmu_ops.pte_update_defer = lguest_pte_update; diff --git a/arch/x86/lguest/i386_head.S b/arch/x86/lguest/i386_head.S index f79541989471..a9c8cfe61cd4 100644 --- a/arch/x86/lguest/i386_head.S +++ b/arch/x86/lguest/i386_head.S @@ -46,10 +46,64 @@ ENTRY(lguest_entry) .globl lgstart_##name; .globl lgend_##name LGUEST_PATCH(cli, movl $0, lguest_data+LGUEST_DATA_irq_enabled) -LGUEST_PATCH(sti, movl $X86_EFLAGS_IF, lguest_data+LGUEST_DATA_irq_enabled) -LGUEST_PATCH(popf, movl %eax, lguest_data+LGUEST_DATA_irq_enabled) LGUEST_PATCH(pushf, movl lguest_data+LGUEST_DATA_irq_enabled, %eax) -/*:*/ + +/*G:033 But using those wrappers is inefficient (we'll see why that doesn't + * matter for save_fl and irq_disable later). If we write our routines + * carefully in assembler, we can avoid clobbering any registers and avoid + * jumping through the wrapper functions. + * + * I skipped over our first piece of assembler, but this one is worth studying + * in a bit more detail so I'll describe in easy stages. First, the routine + * to enable interrupts: */ +ENTRY(lg_irq_enable) + /* The reverse of irq_disable, this sets lguest_data.irq_enabled to + * X86_EFLAGS_IF (ie. "Interrupts enabled"). */ + movl $X86_EFLAGS_IF, lguest_data+LGUEST_DATA_irq_enabled + /* But now we need to check if the Host wants to know: there might have + * been interrupts waiting to be delivered, in which case it will have + * set lguest_data.irq_pending to X86_EFLAGS_IF. If it's not zero, we + * jump to send_interrupts, otherwise we're done. */ + testl $0, lguest_data+LGUEST_DATA_irq_pending + jnz send_interrupts + /* One cool thing about x86 is that you can do many things without using + * a register. In this case, the normal path hasn't needed to save or + * restore any registers at all! */ + ret +send_interrupts: + /* OK, now we need a register: eax is used for the hypercall number, + * which is LHCALL_SEND_INTERRUPTS. + * + * We used not to bother with this pending detection at all, which was + * much simpler. Sooner or later the Host would realize it had to + * send us an interrupt. But that turns out to make performance 7 + * times worse on a simple tcp benchmark. So now we do this the hard + * way. */ + pushl %eax + movl $LHCALL_SEND_INTERRUPTS, %eax + /* This is a vmcall instruction (same thing that KVM uses). Older + * assembler versions might not know the "vmcall" instruction, so we + * create one manually here. */ + .byte 0x0f,0x01,0xc1 /* KVM_HYPERCALL */ + popl %eax + ret + +/* Finally, the "popf" or "restore flags" routine. The %eax register holds the + * flags (in practice, either X86_EFLAGS_IF or 0): if it's X86_EFLAGS_IF we're + * enabling interrupts again, if it's 0 we're leaving them off. */ +ENTRY(lg_restore_fl) + /* This is just "lguest_data.irq_enabled = flags;" */ + movl %eax, lguest_data+LGUEST_DATA_irq_enabled + /* Now, if the %eax value has enabled interrupts and + * lguest_data.irq_pending is set, we want to tell the Host so it can + * deliver any outstanding interrupts. Fortunately, both values will + * be X86_EFLAGS_IF (ie. 512) in that case, and the "testl" + * instruction will AND them together for us. If both are set, we + * jump to send_interrupts. */ + testl lguest_data+LGUEST_DATA_irq_pending, %eax + jnz send_interrupts + /* Again, the normal path has used no extra registers. Clever, huh? */ + ret /* These demark the EIP range where host should never deliver interrupts. */ .global lguest_noirq_start diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index 55e11aa6d66c..f9d35632666b 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -2,7 +2,7 @@ # Makefile for x86 specific library files. # -obj-$(CONFIG_SMP) := msr-on-cpu.o +obj-$(CONFIG_SMP) := msr.o lib-y := delay.o lib-y += thunk_$(BITS).o diff --git a/arch/x86/lib/msr-on-cpu.c b/arch/x86/lib/msr-on-cpu.c deleted file mode 100644 index 321cf720dbb6..000000000000 --- a/arch/x86/lib/msr-on-cpu.c +++ /dev/null @@ -1,97 +0,0 @@ -#include -#include -#include -#include - -struct msr_info { - u32 msr_no; - u32 l, h; - int err; -}; - -static void __rdmsr_on_cpu(void *info) -{ - struct msr_info *rv = info; - - rdmsr(rv->msr_no, rv->l, rv->h); -} - -static void __wrmsr_on_cpu(void *info) -{ - struct msr_info *rv = info; - - wrmsr(rv->msr_no, rv->l, rv->h); -} - -int rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h) -{ - int err; - struct msr_info rv; - - rv.msr_no = msr_no; - err = smp_call_function_single(cpu, __rdmsr_on_cpu, &rv, 1); - *l = rv.l; - *h = rv.h; - - return err; -} - -int wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h) -{ - int err; - struct msr_info rv; - - rv.msr_no = msr_no; - rv.l = l; - rv.h = h; - err = smp_call_function_single(cpu, __wrmsr_on_cpu, &rv, 1); - - return err; -} - -/* These "safe" variants are slower and should be used when the target MSR - may not actually exist. */ -static void __rdmsr_safe_on_cpu(void *info) -{ - struct msr_info *rv = info; - - rv->err = rdmsr_safe(rv->msr_no, &rv->l, &rv->h); -} - -static void __wrmsr_safe_on_cpu(void *info) -{ - struct msr_info *rv = info; - - rv->err = wrmsr_safe(rv->msr_no, rv->l, rv->h); -} - -int rdmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h) -{ - int err; - struct msr_info rv; - - rv.msr_no = msr_no; - err = smp_call_function_single(cpu, __rdmsr_safe_on_cpu, &rv, 1); - *l = rv.l; - *h = rv.h; - - return err ? err : rv.err; -} - -int wrmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h) -{ - int err; - struct msr_info rv; - - rv.msr_no = msr_no; - rv.l = l; - rv.h = h; - err = smp_call_function_single(cpu, __wrmsr_safe_on_cpu, &rv, 1); - - return err ? err : rv.err; -} - -EXPORT_SYMBOL(rdmsr_on_cpu); -EXPORT_SYMBOL(wrmsr_on_cpu); -EXPORT_SYMBOL(rdmsr_safe_on_cpu); -EXPORT_SYMBOL(wrmsr_safe_on_cpu); diff --git a/arch/x86/lib/msr.c b/arch/x86/lib/msr.c new file mode 100644 index 000000000000..1440b9c0547e --- /dev/null +++ b/arch/x86/lib/msr.c @@ -0,0 +1,183 @@ +#include +#include +#include +#include + +struct msr_info { + u32 msr_no; + struct msr reg; + struct msr *msrs; + int off; + int err; +}; + +static void __rdmsr_on_cpu(void *info) +{ + struct msr_info *rv = info; + struct msr *reg; + int this_cpu = raw_smp_processor_id(); + + if (rv->msrs) + reg = &rv->msrs[this_cpu - rv->off]; + else + reg = &rv->reg; + + rdmsr(rv->msr_no, reg->l, reg->h); +} + +static void __wrmsr_on_cpu(void *info) +{ + struct msr_info *rv = info; + struct msr *reg; + int this_cpu = raw_smp_processor_id(); + + if (rv->msrs) + reg = &rv->msrs[this_cpu - rv->off]; + else + reg = &rv->reg; + + wrmsr(rv->msr_no, reg->l, reg->h); +} + +int rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h) +{ + int err; + struct msr_info rv; + + memset(&rv, 0, sizeof(rv)); + + rv.msr_no = msr_no; + err = smp_call_function_single(cpu, __rdmsr_on_cpu, &rv, 1); + *l = rv.reg.l; + *h = rv.reg.h; + + return err; +} +EXPORT_SYMBOL(rdmsr_on_cpu); + +int wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h) +{ + int err; + struct msr_info rv; + + memset(&rv, 0, sizeof(rv)); + + rv.msr_no = msr_no; + rv.reg.l = l; + rv.reg.h = h; + err = smp_call_function_single(cpu, __wrmsr_on_cpu, &rv, 1); + + return err; +} +EXPORT_SYMBOL(wrmsr_on_cpu); + +/* rdmsr on a bunch of CPUs + * + * @mask: which CPUs + * @msr_no: which MSR + * @msrs: array of MSR values + * + */ +void rdmsr_on_cpus(const cpumask_t *mask, u32 msr_no, struct msr *msrs) +{ + struct msr_info rv; + int this_cpu; + + memset(&rv, 0, sizeof(rv)); + + rv.off = cpumask_first(mask); + rv.msrs = msrs; + rv.msr_no = msr_no; + + preempt_disable(); + /* + * FIXME: handle the CPU we're executing on separately for now until + * smp_call_function_many has been fixed to not skip it. + */ + this_cpu = raw_smp_processor_id(); + smp_call_function_single(this_cpu, __rdmsr_on_cpu, &rv, 1); + + smp_call_function_many(mask, __rdmsr_on_cpu, &rv, 1); + preempt_enable(); +} +EXPORT_SYMBOL(rdmsr_on_cpus); + +/* + * wrmsr on a bunch of CPUs + * + * @mask: which CPUs + * @msr_no: which MSR + * @msrs: array of MSR values + * + */ +void wrmsr_on_cpus(const cpumask_t *mask, u32 msr_no, struct msr *msrs) +{ + struct msr_info rv; + int this_cpu; + + memset(&rv, 0, sizeof(rv)); + + rv.off = cpumask_first(mask); + rv.msrs = msrs; + rv.msr_no = msr_no; + + preempt_disable(); + /* + * FIXME: handle the CPU we're executing on separately for now until + * smp_call_function_many has been fixed to not skip it. + */ + this_cpu = raw_smp_processor_id(); + smp_call_function_single(this_cpu, __wrmsr_on_cpu, &rv, 1); + + smp_call_function_many(mask, __wrmsr_on_cpu, &rv, 1); + preempt_enable(); +} +EXPORT_SYMBOL(wrmsr_on_cpus); + +/* These "safe" variants are slower and should be used when the target MSR + may not actually exist. */ +static void __rdmsr_safe_on_cpu(void *info) +{ + struct msr_info *rv = info; + + rv->err = rdmsr_safe(rv->msr_no, &rv->reg.l, &rv->reg.h); +} + +static void __wrmsr_safe_on_cpu(void *info) +{ + struct msr_info *rv = info; + + rv->err = wrmsr_safe(rv->msr_no, rv->reg.l, rv->reg.h); +} + +int rdmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h) +{ + int err; + struct msr_info rv; + + memset(&rv, 0, sizeof(rv)); + + rv.msr_no = msr_no; + err = smp_call_function_single(cpu, __rdmsr_safe_on_cpu, &rv, 1); + *l = rv.reg.l; + *h = rv.reg.h; + + return err ? err : rv.err; +} +EXPORT_SYMBOL(rdmsr_safe_on_cpu); + +int wrmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h) +{ + int err; + struct msr_info rv; + + memset(&rv, 0, sizeof(rv)); + + rv.msr_no = msr_no; + rv.reg.l = l; + rv.reg.h = h; + err = smp_call_function_single(cpu, __wrmsr_safe_on_cpu, &rv, 1); + + return err ? err : rv.err; +} +EXPORT_SYMBOL(wrmsr_safe_on_cpu); diff --git a/arch/x86/lib/usercopy_64.c b/arch/x86/lib/usercopy_64.c index ec13cb5f17ed..b7c2849ffb66 100644 --- a/arch/x86/lib/usercopy_64.c +++ b/arch/x86/lib/usercopy_64.c @@ -127,7 +127,7 @@ EXPORT_SYMBOL(__strnlen_user); long strnlen_user(const char __user *s, long n) { - if (!access_ok(VERIFY_READ, s, n)) + if (!access_ok(VERIFY_READ, s, 1)) return 0; return __strnlen_user(s, n); } diff --git a/arch/x86/mm/Makefile b/arch/x86/mm/Makefile index fdd30d08ab52..eefdeee8a871 100644 --- a/arch/x86/mm/Makefile +++ b/arch/x86/mm/Makefile @@ -10,6 +10,8 @@ obj-$(CONFIG_X86_PTDUMP) += dump_pagetables.o obj-$(CONFIG_HIGHMEM) += highmem_32.o +obj-$(CONFIG_KMEMCHECK) += kmemcheck/ + obj-$(CONFIG_MMIOTRACE) += mmiotrace.o mmiotrace-y := kmmio.o pf_in.o mmio-mod.o obj-$(CONFIG_MMIOTRACE_TEST) += testmmiotrace.o diff --git a/arch/x86/mm/dump_pagetables.c b/arch/x86/mm/dump_pagetables.c index e7277cbcfb40..a725b7f760ae 100644 --- a/arch/x86/mm/dump_pagetables.c +++ b/arch/x86/mm/dump_pagetables.c @@ -161,13 +161,14 @@ static void note_page(struct seq_file *m, struct pg_state *st, st->current_address >= st->marker[1].start_address) { const char *unit = units; unsigned long delta; + int width = sizeof(unsigned long) * 2; /* * Now print the actual finished series */ - seq_printf(m, "0x%p-0x%p ", - (void *)st->start_address, - (void *)st->current_address); + seq_printf(m, "0x%0*lx-0x%0*lx ", + width, st->start_address, + width, st->current_address); delta = (st->current_address - st->start_address) >> 10; while (!(delta & 1023) && unit[1]) { diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index a03b7279efa0..78a5fff857be 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c @@ -3,40 +3,18 @@ * Copyright (C) 2001, 2002 Andi Kleen, SuSE Labs. * Copyright (C) 2008-2009, Red Hat Inc., Ingo Molnar */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include /* STACK_END_MAGIC */ +#include /* test_thread_flag(), ... */ +#include /* oops_begin/end, ... */ +#include /* search_exception_table */ +#include /* max_low_pfn */ +#include /* __kprobes, ... */ +#include /* kmmio_handler, ... */ +#include /* perf_swcounter_event */ -#include - -#include -#include -#include -#include -#include -#include -#include +#include /* dotraplinkage, ... */ +#include /* pgd_*(), ... */ +#include /* kmemcheck_*(), ... */ /* * Page fault error code bits: @@ -225,12 +203,10 @@ static inline pmd_t *vmalloc_sync_one(pgd_t *pgd, unsigned long address) if (!pmd_present(*pmd_k)) return NULL; - if (!pmd_present(*pmd)) { + if (!pmd_present(*pmd)) set_pmd(pmd, *pmd_k); - arch_flush_lazy_mmu_mode(); - } else { + else BUG_ON(pmd_page(*pmd) != pmd_page(*pmd_k)); - } return pmd_k; } @@ -538,8 +514,6 @@ bad: static int is_errata93(struct pt_regs *regs, unsigned long address) { #ifdef CONFIG_X86_64 - static int once; - if (address != regs->ip) return 0; @@ -549,10 +523,7 @@ static int is_errata93(struct pt_regs *regs, unsigned long address) address |= 0xffffffffUL << 32; if ((address >= (u64)_stext && address <= (u64)_etext) || (address >= MODULES_VADDR && address <= MODULES_END)) { - if (!once) { - printk(errata93_warning); - once = 1; - } + printk_once(errata93_warning); regs->ip = address; return 1; } @@ -981,11 +952,17 @@ do_page_fault(struct pt_regs *regs, unsigned long error_code) tsk = current; mm = tsk->mm; - prefetchw(&mm->mmap_sem); - /* Get the faulting address: */ address = read_cr2(); + /* + * Detect and handle instructions that would cause a page fault for + * both a tracked kernel page and a userspace page. + */ + if (kmemcheck_active(regs)) + kmemcheck_hide(regs); + prefetchw(&mm->mmap_sem); + if (unlikely(kmmio_fault(regs, address))) return; @@ -1003,9 +980,13 @@ do_page_fault(struct pt_regs *regs, unsigned long error_code) * protection error (error_code & 9) == 0. */ if (unlikely(fault_in_kernel_space(address))) { - if (!(error_code & (PF_RSVD|PF_USER|PF_PROT)) && - vmalloc_fault(address) >= 0) - return; + if (!(error_code & (PF_RSVD | PF_USER | PF_PROT))) { + if (vmalloc_fault(address) >= 0) + return; + + if (kmemcheck_fault(regs, address, error_code)) + return; + } /* Can handle a stale RO->RW TLB: */ if (spurious_fault(error_code, address)) @@ -1044,6 +1025,8 @@ do_page_fault(struct pt_regs *regs, unsigned long error_code) if (unlikely(error_code & PF_RSVD)) pgtable_bad(regs, error_code, address); + perf_swcounter_event(PERF_COUNT_SW_PAGE_FAULTS, 1, 0, regs, address); + /* * If we're in an interrupt, have no user context or are running * in an atomic region then we must not take the fault: @@ -1130,17 +1113,22 @@ good_area: * make sure we exit gracefully rather than endlessly redo * the fault: */ - fault = handle_mm_fault(mm, vma, address, write); + fault = handle_mm_fault(mm, vma, address, write ? FAULT_FLAG_WRITE : 0); if (unlikely(fault & VM_FAULT_ERROR)) { mm_fault_error(regs, error_code, address, fault); return; } - if (fault & VM_FAULT_MAJOR) + if (fault & VM_FAULT_MAJOR) { tsk->maj_flt++; - else + perf_swcounter_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, 0, + regs, address); + } else { tsk->min_flt++; + perf_swcounter_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, 0, + regs, address); + } check_v8086_mode(regs, address, tsk); diff --git a/arch/x86/mm/gup.c b/arch/x86/mm/gup.c index 6340cef6798a..71da1bca13cb 100644 --- a/arch/x86/mm/gup.c +++ b/arch/x86/mm/gup.c @@ -14,7 +14,7 @@ static inline pte_t gup_get_pte(pte_t *ptep) { #ifndef CONFIG_X86_PAE - return *ptep; + return ACCESS_ONCE(*ptep); #else /* * With get_user_pages_fast, we walk down the pagetables without taking @@ -219,6 +219,62 @@ static int gup_pud_range(pgd_t pgd, unsigned long addr, unsigned long end, return 1; } +/* + * Like get_user_pages_fast() except its IRQ-safe in that it won't fall + * back to the regular GUP. + */ +int __get_user_pages_fast(unsigned long start, int nr_pages, int write, + struct page **pages) +{ + struct mm_struct *mm = current->mm; + unsigned long addr, len, end; + unsigned long next; + unsigned long flags; + pgd_t *pgdp; + int nr = 0; + + start &= PAGE_MASK; + addr = start; + len = (unsigned long) nr_pages << PAGE_SHIFT; + end = start + len; + if (unlikely(!access_ok(write ? VERIFY_WRITE : VERIFY_READ, + (void __user *)start, len))) + return 0; + + /* + * XXX: batch / limit 'nr', to avoid large irq off latency + * needs some instrumenting to determine the common sizes used by + * important workloads (eg. DB2), and whether limiting the batch size + * will decrease performance. + * + * It seems like we're in the clear for the moment. Direct-IO is + * the main guy that batches up lots of get_user_pages, and even + * they are limited to 64-at-a-time which is not so many. + */ + /* + * This doesn't prevent pagetable teardown, but does prevent + * the pagetables and pages from being freed on x86. + * + * So long as we atomically load page table pointers versus teardown + * (which we do on x86, with the above PAE exception), we can follow the + * address down to the the page and take a ref on it. + */ + local_irq_save(flags); + pgdp = pgd_offset(mm, addr); + do { + pgd_t pgd = *pgdp; + + next = pgd_addr_end(addr, end); + if (pgd_none(pgd)) + break; + if (!gup_pud_range(pgd, addr, next, write, pages, &nr)) + break; + } while (pgdp++, addr = next, addr != end); + local_irq_restore(flags); + + return nr; +} + /** * get_user_pages_fast() - pin user pages in memory * @start: starting user address @@ -247,11 +303,16 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write, start &= PAGE_MASK; addr = start; len = (unsigned long) nr_pages << PAGE_SHIFT; + end = start + len; - if (unlikely(!access_ok(write ? VERIFY_WRITE : VERIFY_READ, - (void __user *)start, len))) + if (end < start) goto slow_irqon; +#ifdef CONFIG_X86_64 + if (end >> __VIRTUAL_MASK_SHIFT) + goto slow_irqon; +#endif + /* * XXX: batch / limit 'nr', to avoid large irq off latency * needs some instrumenting to determine the common sizes used by diff --git a/arch/x86/mm/highmem_32.c b/arch/x86/mm/highmem_32.c index 8126e8d1a2a4..58f621e81919 100644 --- a/arch/x86/mm/highmem_32.c +++ b/arch/x86/mm/highmem_32.c @@ -44,7 +44,6 @@ void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot) vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); BUG_ON(!pte_none(*(kmap_pte-idx))); set_pte(kmap_pte-idx, mk_pte(page, prot)); - arch_flush_lazy_mmu_mode(); return (void *)vaddr; } @@ -74,7 +73,6 @@ void kunmap_atomic(void *kvaddr, enum km_type type) #endif } - arch_flush_lazy_mmu_mode(); pagefault_enable(); } diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c index ae4f7b5d7104..f53b57e4086f 100644 --- a/arch/x86/mm/init.c +++ b/arch/x86/mm/init.c @@ -1,3 +1,4 @@ +#include #include #include @@ -10,6 +11,9 @@ #include #include #include +#include + +DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); unsigned long __initdata e820_table_start; unsigned long __meminitdata e820_table_end; @@ -23,6 +27,69 @@ int direct_gbpages #endif ; +int nx_enabled; + +#if defined(CONFIG_X86_64) || defined(CONFIG_X86_PAE) +static int disable_nx __cpuinitdata; + +/* + * noexec = on|off + * + * Control non-executable mappings for processes. + * + * on Enable + * off Disable + */ +static int __init noexec_setup(char *str) +{ + if (!str) + return -EINVAL; + if (!strncmp(str, "on", 2)) { + __supported_pte_mask |= _PAGE_NX; + disable_nx = 0; + } else if (!strncmp(str, "off", 3)) { + disable_nx = 1; + __supported_pte_mask &= ~_PAGE_NX; + } + return 0; +} +early_param("noexec", noexec_setup); +#endif + +#ifdef CONFIG_X86_PAE +static void __init set_nx(void) +{ + unsigned int v[4], l, h; + + if (cpu_has_pae && (cpuid_eax(0x80000000) > 0x80000001)) { + cpuid(0x80000001, &v[0], &v[1], &v[2], &v[3]); + + if ((v[3] & (1 << 20)) && !disable_nx) { + rdmsr(MSR_EFER, l, h); + l |= EFER_NX; + wrmsr(MSR_EFER, l, h); + nx_enabled = 1; + __supported_pte_mask |= _PAGE_NX; + } + } +} +#else +static inline void set_nx(void) +{ +} +#endif + +#ifdef CONFIG_X86_64 +void __cpuinit check_efer(void) +{ + unsigned long efer; + + rdmsrl(MSR_EFER, efer); + if (!(efer & EFER_NX) || disable_nx) + __supported_pte_mask &= ~_PAGE_NX; +} +#endif + static void __init find_early_table_space(unsigned long end, int use_pse, int use_gbpages) { @@ -66,12 +133,11 @@ static void __init find_early_table_space(unsigned long end, int use_pse, */ #ifdef CONFIG_X86_32 start = 0x7000; +#else + start = 0x8000; +#endif e820_table_start = find_e820_area(start, max_pfn_mapped< #include #include +#include #include -unsigned long max_low_pfn_mapped; -unsigned long max_pfn_mapped; - -DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); unsigned long highstart_pfn, highend_pfn; static noinline int do_test_wp_bit(void); @@ -114,7 +111,7 @@ static pte_t * __init one_page_table_init(pmd_t *pmd) pte_t *page_table = NULL; if (after_bootmem) { -#ifdef CONFIG_DEBUG_PAGEALLOC +#if defined(CONFIG_DEBUG_PAGEALLOC) || defined(CONFIG_KMEMCHECK) page_table = (pte_t *) alloc_bootmem_pages(PAGE_SIZE); #endif if (!page_table) @@ -567,7 +564,7 @@ static inline void save_pg_dir(void) } #endif /* !CONFIG_ACPI_SLEEP */ -void zap_low_mappings(void) +void zap_low_mappings(bool early) { int i; @@ -584,64 +581,16 @@ void zap_low_mappings(void) set_pgd(swapper_pg_dir+i, __pgd(0)); #endif } - flush_tlb_all(); -} -int nx_enabled; + if (early) + __flush_tlb(); + else + flush_tlb_all(); +} pteval_t __supported_pte_mask __read_mostly = ~(_PAGE_NX | _PAGE_GLOBAL | _PAGE_IOMAP); EXPORT_SYMBOL_GPL(__supported_pte_mask); -#ifdef CONFIG_X86_PAE - -static int disable_nx __initdata; - -/* - * noexec = on|off - * - * Control non executable mappings. - * - * on Enable - * off Disable - */ -static int __init noexec_setup(char *str) -{ - if (!str || !strcmp(str, "on")) { - if (cpu_has_nx) { - __supported_pte_mask |= _PAGE_NX; - disable_nx = 0; - } - } else { - if (!strcmp(str, "off")) { - disable_nx = 1; - __supported_pte_mask &= ~_PAGE_NX; - } else { - return -EINVAL; - } - } - - return 0; -} -early_param("noexec", noexec_setup); - -void __init set_nx(void) -{ - unsigned int v[4], l, h; - - if (cpu_has_pae && (cpuid_eax(0x80000000) > 0x80000001)) { - cpuid(0x80000001, &v[0], &v[1], &v[2], &v[3]); - - if ((v[3] & (1 << 20)) && !disable_nx) { - rdmsr(MSR_EFER, l, h); - l |= EFER_NX; - wrmsr(MSR_EFER, l, h); - nx_enabled = 1; - __supported_pte_mask |= _PAGE_NX; - } - } -} -#endif - /* user-defined highmem size */ static unsigned int highmem_pages = -1; @@ -761,15 +710,15 @@ void __init initmem_init(unsigned long start_pfn, highstart_pfn = highend_pfn = max_pfn; if (max_pfn > max_low_pfn) highstart_pfn = max_low_pfn; - memory_present(0, 0, highend_pfn); e820_register_active_regions(0, 0, highend_pfn); + sparse_memory_present_with_active_regions(0); printk(KERN_NOTICE "%ldMB HIGHMEM available.\n", pages_to_mb(highend_pfn - highstart_pfn)); num_physpages = highend_pfn; high_memory = (void *) __va(highstart_pfn * PAGE_SIZE - 1) + 1; #else - memory_present(0, 0, max_low_pfn); e820_register_active_regions(0, 0, max_low_pfn); + sparse_memory_present_with_active_regions(0); num_physpages = max_low_pfn; high_memory = (void *) __va(max_low_pfn * PAGE_SIZE - 1) + 1; #endif @@ -1011,7 +960,7 @@ void __init mem_init(void) test_wp_bit(); save_pg_dir(); - zap_low_mappings(); + zap_low_mappings(true); } #ifdef CONFIG_MEMORY_HOTPLUG diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index 1753e8020df6..c4378f4fd4a5 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c @@ -50,18 +50,8 @@ #include #include -/* - * end_pfn only includes RAM, while max_pfn_mapped includes all e820 entries. - * The direct mapping extends to max_pfn_mapped, so that we can directly access - * apertures, ACPI and other tables without having to play with fixmaps. - */ -unsigned long max_low_pfn_mapped; -unsigned long max_pfn_mapped; - static unsigned long dma_reserve __initdata; -DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); - static int __init parse_direct_gbpages_off(char *arg) { direct_gbpages = 0; @@ -85,39 +75,6 @@ early_param("gbpages", parse_direct_gbpages_on); pteval_t __supported_pte_mask __read_mostly = ~_PAGE_IOMAP; EXPORT_SYMBOL_GPL(__supported_pte_mask); -static int disable_nx __cpuinitdata; - -/* - * noexec=on|off - * Control non-executable mappings for 64-bit processes. - * - * on Enable (default) - * off Disable - */ -static int __init nonx_setup(char *str) -{ - if (!str) - return -EINVAL; - if (!strncmp(str, "on", 2)) { - __supported_pte_mask |= _PAGE_NX; - disable_nx = 0; - } else if (!strncmp(str, "off", 3)) { - disable_nx = 1; - __supported_pte_mask &= ~_PAGE_NX; - } - return 0; -} -early_param("noexec", nonx_setup); - -void __cpuinit check_efer(void) -{ - unsigned long efer; - - rdmsrl(MSR_EFER, efer); - if (!(efer & EFER_NX) || disable_nx) - __supported_pte_mask &= ~_PAGE_NX; -} - int force_personality32; /* @@ -147,7 +104,7 @@ static __ref void *spp_getpage(void) void *ptr; if (after_bootmem) - ptr = (void *) get_zeroed_page(GFP_ATOMIC); + ptr = (void *) get_zeroed_page(GFP_ATOMIC | __GFP_NOTRACK); else ptr = alloc_bootmem_pages(PAGE_SIZE); @@ -324,7 +281,7 @@ static __ref void *alloc_low_page(unsigned long *phys) void *adr; if (after_bootmem) { - adr = (void *)get_zeroed_page(GFP_ATOMIC); + adr = (void *)get_zeroed_page(GFP_ATOMIC | __GFP_NOTRACK); *phys = __pa(adr); return adr; @@ -570,7 +527,7 @@ phys_pud_update(pgd_t *pgd, unsigned long addr, unsigned long end, return phys_pud_init(pud, addr, end, page_size_mask); } -unsigned long __init +unsigned long __meminit kernel_physical_mapping_init(unsigned long start, unsigned long end, unsigned long page_size_mask) @@ -628,6 +585,7 @@ void __init initmem_init(unsigned long start_pfn, unsigned long end_pfn) early_res_to_bootmem(0, end_pfn< +#include +#include +#include +#include +#include +#include +#include + +#include "error.h" +#include "shadow.h" + +enum kmemcheck_error_type { + KMEMCHECK_ERROR_INVALID_ACCESS, + KMEMCHECK_ERROR_BUG, +}; + +#define SHADOW_COPY_SIZE (1 << CONFIG_KMEMCHECK_SHADOW_COPY_SHIFT) + +struct kmemcheck_error { + enum kmemcheck_error_type type; + + union { + /* KMEMCHECK_ERROR_INVALID_ACCESS */ + struct { + /* Kind of access that caused the error */ + enum kmemcheck_shadow state; + /* Address and size of the erroneous read */ + unsigned long address; + unsigned int size; + }; + }; + + struct pt_regs regs; + struct stack_trace trace; + unsigned long trace_entries[32]; + + /* We compress it to a char. */ + unsigned char shadow_copy[SHADOW_COPY_SIZE]; + unsigned char memory_copy[SHADOW_COPY_SIZE]; +}; + +/* + * Create a ring queue of errors to output. We can't call printk() directly + * from the kmemcheck traps, since this may call the console drivers and + * result in a recursive fault. + */ +static struct kmemcheck_error error_fifo[CONFIG_KMEMCHECK_QUEUE_SIZE]; +static unsigned int error_count; +static unsigned int error_rd; +static unsigned int error_wr; +static unsigned int error_missed_count; + +static struct kmemcheck_error *error_next_wr(void) +{ + struct kmemcheck_error *e; + + if (error_count == ARRAY_SIZE(error_fifo)) { + ++error_missed_count; + return NULL; + } + + e = &error_fifo[error_wr]; + if (++error_wr == ARRAY_SIZE(error_fifo)) + error_wr = 0; + ++error_count; + return e; +} + +static struct kmemcheck_error *error_next_rd(void) +{ + struct kmemcheck_error *e; + + if (error_count == 0) + return NULL; + + e = &error_fifo[error_rd]; + if (++error_rd == ARRAY_SIZE(error_fifo)) + error_rd = 0; + --error_count; + return e; +} + +void kmemcheck_error_recall(void) +{ + static const char *desc[] = { + [KMEMCHECK_SHADOW_UNALLOCATED] = "unallocated", + [KMEMCHECK_SHADOW_UNINITIALIZED] = "uninitialized", + [KMEMCHECK_SHADOW_INITIALIZED] = "initialized", + [KMEMCHECK_SHADOW_FREED] = "freed", + }; + + static const char short_desc[] = { + [KMEMCHECK_SHADOW_UNALLOCATED] = 'a', + [KMEMCHECK_SHADOW_UNINITIALIZED] = 'u', + [KMEMCHECK_SHADOW_INITIALIZED] = 'i', + [KMEMCHECK_SHADOW_FREED] = 'f', + }; + + struct kmemcheck_error *e; + unsigned int i; + + e = error_next_rd(); + if (!e) + return; + + switch (e->type) { + case KMEMCHECK_ERROR_INVALID_ACCESS: + printk(KERN_ERR "WARNING: kmemcheck: Caught %d-bit read " + "from %s memory (%p)\n", + 8 * e->size, e->state < ARRAY_SIZE(desc) ? + desc[e->state] : "(invalid shadow state)", + (void *) e->address); + + printk(KERN_INFO); + for (i = 0; i < SHADOW_COPY_SIZE; ++i) + printk("%02x", e->memory_copy[i]); + printk("\n"); + + printk(KERN_INFO); + for (i = 0; i < SHADOW_COPY_SIZE; ++i) { + if (e->shadow_copy[i] < ARRAY_SIZE(short_desc)) + printk(" %c", short_desc[e->shadow_copy[i]]); + else + printk(" ?"); + } + printk("\n"); + printk(KERN_INFO "%*c\n", 2 + 2 + * (int) (e->address & (SHADOW_COPY_SIZE - 1)), '^'); + break; + case KMEMCHECK_ERROR_BUG: + printk(KERN_EMERG "ERROR: kmemcheck: Fatal error\n"); + break; + } + + __show_regs(&e->regs, 1); + print_stack_trace(&e->trace, 0); +} + +static void do_wakeup(unsigned long data) +{ + while (error_count > 0) + kmemcheck_error_recall(); + + if (error_missed_count > 0) { + printk(KERN_WARNING "kmemcheck: Lost %d error reports because " + "the queue was too small\n", error_missed_count); + error_missed_count = 0; + } +} + +static DECLARE_TASKLET(kmemcheck_tasklet, &do_wakeup, 0); + +/* + * Save the context of an error report. + */ +void kmemcheck_error_save(enum kmemcheck_shadow state, + unsigned long address, unsigned int size, struct pt_regs *regs) +{ + static unsigned long prev_ip; + + struct kmemcheck_error *e; + void *shadow_copy; + void *memory_copy; + + /* Don't report several adjacent errors from the same EIP. */ + if (regs->ip == prev_ip) + return; + prev_ip = regs->ip; + + e = error_next_wr(); + if (!e) + return; + + e->type = KMEMCHECK_ERROR_INVALID_ACCESS; + + e->state = state; + e->address = address; + e->size = size; + + /* Save regs */ + memcpy(&e->regs, regs, sizeof(*regs)); + + /* Save stack trace */ + e->trace.nr_entries = 0; + e->trace.entries = e->trace_entries; + e->trace.max_entries = ARRAY_SIZE(e->trace_entries); + e->trace.skip = 0; + save_stack_trace_bp(&e->trace, regs->bp); + + /* Round address down to nearest 16 bytes */ + shadow_copy = kmemcheck_shadow_lookup(address + & ~(SHADOW_COPY_SIZE - 1)); + BUG_ON(!shadow_copy); + + memcpy(e->shadow_copy, shadow_copy, SHADOW_COPY_SIZE); + + kmemcheck_show_addr(address); + memory_copy = (void *) (address & ~(SHADOW_COPY_SIZE - 1)); + memcpy(e->memory_copy, memory_copy, SHADOW_COPY_SIZE); + kmemcheck_hide_addr(address); + + tasklet_hi_schedule_first(&kmemcheck_tasklet); +} + +/* + * Save the context of a kmemcheck bug. + */ +void kmemcheck_error_save_bug(struct pt_regs *regs) +{ + struct kmemcheck_error *e; + + e = error_next_wr(); + if (!e) + return; + + e->type = KMEMCHECK_ERROR_BUG; + + memcpy(&e->regs, regs, sizeof(*regs)); + + e->trace.nr_entries = 0; + e->trace.entries = e->trace_entries; + e->trace.max_entries = ARRAY_SIZE(e->trace_entries); + e->trace.skip = 1; + save_stack_trace(&e->trace); + + tasklet_hi_schedule_first(&kmemcheck_tasklet); +} diff --git a/arch/x86/mm/kmemcheck/error.h b/arch/x86/mm/kmemcheck/error.h new file mode 100644 index 000000000000..0efc2e8d0a20 --- /dev/null +++ b/arch/x86/mm/kmemcheck/error.h @@ -0,0 +1,15 @@ +#ifndef ARCH__X86__MM__KMEMCHECK__ERROR_H +#define ARCH__X86__MM__KMEMCHECK__ERROR_H + +#include + +#include "shadow.h" + +void kmemcheck_error_save(enum kmemcheck_shadow state, + unsigned long address, unsigned int size, struct pt_regs *regs); + +void kmemcheck_error_save_bug(struct pt_regs *regs); + +void kmemcheck_error_recall(void); + +#endif diff --git a/arch/x86/mm/kmemcheck/kmemcheck.c b/arch/x86/mm/kmemcheck/kmemcheck.c new file mode 100644 index 000000000000..2c55ed098654 --- /dev/null +++ b/arch/x86/mm/kmemcheck/kmemcheck.c @@ -0,0 +1,640 @@ +/** + * kmemcheck - a heavyweight memory checker for the linux kernel + * Copyright (C) 2007, 2008 Vegard Nossum + * (With a lot of help from Ingo Molnar and Pekka Enberg.) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License (version 2) as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "error.h" +#include "opcode.h" +#include "pte.h" +#include "selftest.h" +#include "shadow.h" + + +#ifdef CONFIG_KMEMCHECK_DISABLED_BY_DEFAULT +# define KMEMCHECK_ENABLED 0 +#endif + +#ifdef CONFIG_KMEMCHECK_ENABLED_BY_DEFAULT +# define KMEMCHECK_ENABLED 1 +#endif + +#ifdef CONFIG_KMEMCHECK_ONESHOT_BY_DEFAULT +# define KMEMCHECK_ENABLED 2 +#endif + +int kmemcheck_enabled = KMEMCHECK_ENABLED; + +int __init kmemcheck_init(void) +{ +#ifdef CONFIG_SMP + /* + * Limit SMP to use a single CPU. We rely on the fact that this code + * runs before SMP is set up. + */ + if (setup_max_cpus > 1) { + printk(KERN_INFO + "kmemcheck: Limiting number of CPUs to 1.\n"); + setup_max_cpus = 1; + } +#endif + + if (!kmemcheck_selftest()) { + printk(KERN_INFO "kmemcheck: self-tests failed; disabling\n"); + kmemcheck_enabled = 0; + return -EINVAL; + } + + printk(KERN_INFO "kmemcheck: Initialized\n"); + return 0; +} + +early_initcall(kmemcheck_init); + +/* + * We need to parse the kmemcheck= option before any memory is allocated. + */ +static int __init param_kmemcheck(char *str) +{ + if (!str) + return -EINVAL; + + sscanf(str, "%d", &kmemcheck_enabled); + return 0; +} + +early_param("kmemcheck", param_kmemcheck); + +int kmemcheck_show_addr(unsigned long address) +{ + pte_t *pte; + + pte = kmemcheck_pte_lookup(address); + if (!pte) + return 0; + + set_pte(pte, __pte(pte_val(*pte) | _PAGE_PRESENT)); + __flush_tlb_one(address); + return 1; +} + +int kmemcheck_hide_addr(unsigned long address) +{ + pte_t *pte; + + pte = kmemcheck_pte_lookup(address); + if (!pte) + return 0; + + set_pte(pte, __pte(pte_val(*pte) & ~_PAGE_PRESENT)); + __flush_tlb_one(address); + return 1; +} + +struct kmemcheck_context { + bool busy; + int balance; + + /* + * There can be at most two memory operands to an instruction, but + * each address can cross a page boundary -- so we may need up to + * four addresses that must be hidden/revealed for each fault. + */ + unsigned long addr[4]; + unsigned long n_addrs; + unsigned long flags; + + /* Data size of the instruction that caused a fault. */ + unsigned int size; +}; + +static DEFINE_PER_CPU(struct kmemcheck_context, kmemcheck_context); + +bool kmemcheck_active(struct pt_regs *regs) +{ + struct kmemcheck_context *data = &__get_cpu_var(kmemcheck_context); + + return data->balance > 0; +} + +/* Save an address that needs to be shown/hidden */ +static void kmemcheck_save_addr(unsigned long addr) +{ + struct kmemcheck_context *data = &__get_cpu_var(kmemcheck_context); + + BUG_ON(data->n_addrs >= ARRAY_SIZE(data->addr)); + data->addr[data->n_addrs++] = addr; +} + +static unsigned int kmemcheck_show_all(void) +{ + struct kmemcheck_context *data = &__get_cpu_var(kmemcheck_context); + unsigned int i; + unsigned int n; + + n = 0; + for (i = 0; i < data->n_addrs; ++i) + n += kmemcheck_show_addr(data->addr[i]); + + return n; +} + +static unsigned int kmemcheck_hide_all(void) +{ + struct kmemcheck_context *data = &__get_cpu_var(kmemcheck_context); + unsigned int i; + unsigned int n; + + n = 0; + for (i = 0; i < data->n_addrs; ++i) + n += kmemcheck_hide_addr(data->addr[i]); + + return n; +} + +/* + * Called from the #PF handler. + */ +void kmemcheck_show(struct pt_regs *regs) +{ + struct kmemcheck_context *data = &__get_cpu_var(kmemcheck_context); + + BUG_ON(!irqs_disabled()); + + if (unlikely(data->balance != 0)) { + kmemcheck_show_all(); + kmemcheck_error_save_bug(regs); + data->balance = 0; + return; + } + + /* + * None of the addresses actually belonged to kmemcheck. Note that + * this is not an error. + */ + if (kmemcheck_show_all() == 0) + return; + + ++data->balance; + + /* + * The IF needs to be cleared as well, so that the faulting + * instruction can run "uninterrupted". Otherwise, we might take + * an interrupt and start executing that before we've had a chance + * to hide the page again. + * + * NOTE: In the rare case of multiple faults, we must not override + * the original flags: + */ + if (!(regs->flags & X86_EFLAGS_TF)) + data->flags = regs->flags; + + regs->flags |= X86_EFLAGS_TF; + regs->flags &= ~X86_EFLAGS_IF; +} + +/* + * Called from the #DB handler. + */ +void kmemcheck_hide(struct pt_regs *regs) +{ + struct kmemcheck_context *data = &__get_cpu_var(kmemcheck_context); + int n; + + BUG_ON(!irqs_disabled()); + + if (data->balance == 0) + return; + + if (unlikely(data->balance != 1)) { + kmemcheck_show_all(); + kmemcheck_error_save_bug(regs); + data->n_addrs = 0; + data->balance = 0; + + if (!(data->flags & X86_EFLAGS_TF)) + regs->flags &= ~X86_EFLAGS_TF; + if (data->flags & X86_EFLAGS_IF) + regs->flags |= X86_EFLAGS_IF; + return; + } + + if (kmemcheck_enabled) + n = kmemcheck_hide_all(); + else + n = kmemcheck_show_all(); + + if (n == 0) + return; + + --data->balance; + + data->n_addrs = 0; + + if (!(data->flags & X86_EFLAGS_TF)) + regs->flags &= ~X86_EFLAGS_TF; + if (data->flags & X86_EFLAGS_IF) + regs->flags |= X86_EFLAGS_IF; +} + +void kmemcheck_show_pages(struct page *p, unsigned int n) +{ + unsigned int i; + + for (i = 0; i < n; ++i) { + unsigned long address; + pte_t *pte; + unsigned int level; + + address = (unsigned long) page_address(&p[i]); + pte = lookup_address(address, &level); + BUG_ON(!pte); + BUG_ON(level != PG_LEVEL_4K); + + set_pte(pte, __pte(pte_val(*pte) | _PAGE_PRESENT)); + set_pte(pte, __pte(pte_val(*pte) & ~_PAGE_HIDDEN)); + __flush_tlb_one(address); + } +} + +bool kmemcheck_page_is_tracked(struct page *p) +{ + /* This will also check the "hidden" flag of the PTE. */ + return kmemcheck_pte_lookup((unsigned long) page_address(p)); +} + +void kmemcheck_hide_pages(struct page *p, unsigned int n) +{ + unsigned int i; + + for (i = 0; i < n; ++i) { + unsigned long address; + pte_t *pte; + unsigned int level; + + address = (unsigned long) page_address(&p[i]); + pte = lookup_address(address, &level); + BUG_ON(!pte); + BUG_ON(level != PG_LEVEL_4K); + + set_pte(pte, __pte(pte_val(*pte) & ~_PAGE_PRESENT)); + set_pte(pte, __pte(pte_val(*pte) | _PAGE_HIDDEN)); + __flush_tlb_one(address); + } +} + +/* Access may NOT cross page boundary */ +static void kmemcheck_read_strict(struct pt_regs *regs, + unsigned long addr, unsigned int size) +{ + void *shadow; + enum kmemcheck_shadow status; + + shadow = kmemcheck_shadow_lookup(addr); + if (!shadow) + return; + + kmemcheck_save_addr(addr); + status = kmemcheck_shadow_test(shadow, size); + if (status == KMEMCHECK_SHADOW_INITIALIZED) + return; + + if (kmemcheck_enabled) + kmemcheck_error_save(status, addr, size, regs); + + if (kmemcheck_enabled == 2) + kmemcheck_enabled = 0; + + /* Don't warn about it again. */ + kmemcheck_shadow_set(shadow, size); +} + +/* Access may cross page boundary */ +static void kmemcheck_read(struct pt_regs *regs, + unsigned long addr, unsigned int size) +{ + unsigned long page = addr & PAGE_MASK; + unsigned long next_addr = addr + size - 1; + unsigned long next_page = next_addr & PAGE_MASK; + + if (likely(page == next_page)) { + kmemcheck_read_strict(regs, addr, size); + return; + } + + /* + * What we do is basically to split the access across the + * two pages and handle each part separately. Yes, this means + * that we may now see reads that are 3 + 5 bytes, for + * example (and if both are uninitialized, there will be two + * reports), but it makes the code a lot simpler. + */ + kmemcheck_read_strict(regs, addr, next_page - addr); + kmemcheck_read_strict(regs, next_page, next_addr - next_page); +} + +static void kmemcheck_write_strict(struct pt_regs *regs, + unsigned long addr, unsigned int size) +{ + void *shadow; + + shadow = kmemcheck_shadow_lookup(addr); + if (!shadow) + return; + + kmemcheck_save_addr(addr); + kmemcheck_shadow_set(shadow, size); +} + +static void kmemcheck_write(struct pt_regs *regs, + unsigned long addr, unsigned int size) +{ + unsigned long page = addr & PAGE_MASK; + unsigned long next_addr = addr + size - 1; + unsigned long next_page = next_addr & PAGE_MASK; + + if (likely(page == next_page)) { + kmemcheck_write_strict(regs, addr, size); + return; + } + + /* See comment in kmemcheck_read(). */ + kmemcheck_write_strict(regs, addr, next_page - addr); + kmemcheck_write_strict(regs, next_page, next_addr - next_page); +} + +/* + * Copying is hard. We have two addresses, each of which may be split across + * a page (and each page will have different shadow addresses). + */ +static void kmemcheck_copy(struct pt_regs *regs, + unsigned long src_addr, unsigned long dst_addr, unsigned int size) +{ + uint8_t shadow[8]; + enum kmemcheck_shadow status; + + unsigned long page; + unsigned long next_addr; + unsigned long next_page; + + uint8_t *x; + unsigned int i; + unsigned int n; + + BUG_ON(size > sizeof(shadow)); + + page = src_addr & PAGE_MASK; + next_addr = src_addr + size - 1; + next_page = next_addr & PAGE_MASK; + + if (likely(page == next_page)) { + /* Same page */ + x = kmemcheck_shadow_lookup(src_addr); + if (x) { + kmemcheck_save_addr(src_addr); + for (i = 0; i < size; ++i) + shadow[i] = x[i]; + } else { + for (i = 0; i < size; ++i) + shadow[i] = KMEMCHECK_SHADOW_INITIALIZED; + } + } else { + n = next_page - src_addr; + BUG_ON(n > sizeof(shadow)); + + /* First page */ + x = kmemcheck_shadow_lookup(src_addr); + if (x) { + kmemcheck_save_addr(src_addr); + for (i = 0; i < n; ++i) + shadow[i] = x[i]; + } else { + /* Not tracked */ + for (i = 0; i < n; ++i) + shadow[i] = KMEMCHECK_SHADOW_INITIALIZED; + } + + /* Second page */ + x = kmemcheck_shadow_lookup(next_page); + if (x) { + kmemcheck_save_addr(next_page); + for (i = n; i < size; ++i) + shadow[i] = x[i - n]; + } else { + /* Not tracked */ + for (i = n; i < size; ++i) + shadow[i] = KMEMCHECK_SHADOW_INITIALIZED; + } + } + + page = dst_addr & PAGE_MASK; + next_addr = dst_addr + size - 1; + next_page = next_addr & PAGE_MASK; + + if (likely(page == next_page)) { + /* Same page */ + x = kmemcheck_shadow_lookup(dst_addr); + if (x) { + kmemcheck_save_addr(dst_addr); + for (i = 0; i < size; ++i) { + x[i] = shadow[i]; + shadow[i] = KMEMCHECK_SHADOW_INITIALIZED; + } + } + } else { + n = next_page - dst_addr; + BUG_ON(n > sizeof(shadow)); + + /* First page */ + x = kmemcheck_shadow_lookup(dst_addr); + if (x) { + kmemcheck_save_addr(dst_addr); + for (i = 0; i < n; ++i) { + x[i] = shadow[i]; + shadow[i] = KMEMCHECK_SHADOW_INITIALIZED; + } + } + + /* Second page */ + x = kmemcheck_shadow_lookup(next_page); + if (x) { + kmemcheck_save_addr(next_page); + for (i = n; i < size; ++i) { + x[i - n] = shadow[i]; + shadow[i] = KMEMCHECK_SHADOW_INITIALIZED; + } + } + } + + status = kmemcheck_shadow_test(shadow, size); + if (status == KMEMCHECK_SHADOW_INITIALIZED) + return; + + if (kmemcheck_enabled) + kmemcheck_error_save(status, src_addr, size, regs); + + if (kmemcheck_enabled == 2) + kmemcheck_enabled = 0; +} + +enum kmemcheck_method { + KMEMCHECK_READ, + KMEMCHECK_WRITE, +}; + +static void kmemcheck_access(struct pt_regs *regs, + unsigned long fallback_address, enum kmemcheck_method fallback_method) +{ + const uint8_t *insn; + const uint8_t *insn_primary; + unsigned int size; + + struct kmemcheck_context *data = &__get_cpu_var(kmemcheck_context); + + /* Recursive fault -- ouch. */ + if (data->busy) { + kmemcheck_show_addr(fallback_address); + kmemcheck_error_save_bug(regs); + return; + } + + data->busy = true; + + insn = (const uint8_t *) regs->ip; + insn_primary = kmemcheck_opcode_get_primary(insn); + + kmemcheck_opcode_decode(insn, &size); + + switch (insn_primary[0]) { +#ifdef CONFIG_KMEMCHECK_BITOPS_OK + /* AND, OR, XOR */ + /* + * Unfortunately, these instructions have to be excluded from + * our regular checking since they access only some (and not + * all) bits. This clears out "bogus" bitfield-access warnings. + */ + case 0x80: + case 0x81: + case 0x82: + case 0x83: + switch ((insn_primary[1] >> 3) & 7) { + /* OR */ + case 1: + /* AND */ + case 4: + /* XOR */ + case 6: + kmemcheck_write(regs, fallback_address, size); + goto out; + + /* ADD */ + case 0: + /* ADC */ + case 2: + /* SBB */ + case 3: + /* SUB */ + case 5: + /* CMP */ + case 7: + break; + } + break; +#endif + + /* MOVS, MOVSB, MOVSW, MOVSD */ + case 0xa4: + case 0xa5: + /* + * These instructions are special because they take two + * addresses, but we only get one page fault. + */ + kmemcheck_copy(regs, regs->si, regs->di, size); + goto out; + + /* CMPS, CMPSB, CMPSW, CMPSD */ + case 0xa6: + case 0xa7: + kmemcheck_read(regs, regs->si, size); + kmemcheck_read(regs, regs->di, size); + goto out; + } + + /* + * If the opcode isn't special in any way, we use the data from the + * page fault handler to determine the address and type of memory + * access. + */ + switch (fallback_method) { + case KMEMCHECK_READ: + kmemcheck_read(regs, fallback_address, size); + goto out; + case KMEMCHECK_WRITE: + kmemcheck_write(regs, fallback_address, size); + goto out; + } + +out: + data->busy = false; +} + +bool kmemcheck_fault(struct pt_regs *regs, unsigned long address, + unsigned long error_code) +{ + pte_t *pte; + + /* + * XXX: Is it safe to assume that memory accesses from virtual 86 + * mode or non-kernel code segments will _never_ access kernel + * memory (e.g. tracked pages)? For now, we need this to avoid + * invoking kmemcheck for PnP BIOS calls. + */ + if (regs->flags & X86_VM_MASK) + return false; + if (regs->cs != __KERNEL_CS) + return false; + + pte = kmemcheck_pte_lookup(address); + if (!pte) + return false; + + if (error_code & 2) + kmemcheck_access(regs, address, KMEMCHECK_WRITE); + else + kmemcheck_access(regs, address, KMEMCHECK_READ); + + kmemcheck_show(regs); + return true; +} + +bool kmemcheck_trap(struct pt_regs *regs) +{ + if (!kmemcheck_active(regs)) + return false; + + /* We're done. */ + kmemcheck_hide(regs); + return true; +} diff --git a/arch/x86/mm/kmemcheck/opcode.c b/arch/x86/mm/kmemcheck/opcode.c new file mode 100644 index 000000000000..63c19e27aa6f --- /dev/null +++ b/arch/x86/mm/kmemcheck/opcode.c @@ -0,0 +1,106 @@ +#include + +#include "opcode.h" + +static bool opcode_is_prefix(uint8_t b) +{ + return + /* Group 1 */ + b == 0xf0 || b == 0xf2 || b == 0xf3 + /* Group 2 */ + || b == 0x2e || b == 0x36 || b == 0x3e || b == 0x26 + || b == 0x64 || b == 0x65 || b == 0x2e || b == 0x3e + /* Group 3 */ + || b == 0x66 + /* Group 4 */ + || b == 0x67; +} + +#ifdef CONFIG_X86_64 +static bool opcode_is_rex_prefix(uint8_t b) +{ + return (b & 0xf0) == 0x40; +} +#else +static bool opcode_is_rex_prefix(uint8_t b) +{ + return false; +} +#endif + +#define REX_W (1 << 3) + +/* + * This is a VERY crude opcode decoder. We only need to find the size of the + * load/store that caused our #PF and this should work for all the opcodes + * that we care about. Moreover, the ones who invented this instruction set + * should be shot. + */ +void kmemcheck_opcode_decode(const uint8_t *op, unsigned int *size) +{ + /* Default operand size */ + int operand_size_override = 4; + + /* prefixes */ + for (; opcode_is_prefix(*op); ++op) { + if (*op == 0x66) + operand_size_override = 2; + } + + /* REX prefix */ + if (opcode_is_rex_prefix(*op)) { + uint8_t rex = *op; + + ++op; + if (rex & REX_W) { + switch (*op) { + case 0x63: + *size = 4; + return; + case 0x0f: + ++op; + + switch (*op) { + case 0xb6: + case 0xbe: + *size = 1; + return; + case 0xb7: + case 0xbf: + *size = 2; + return; + } + + break; + } + + *size = 8; + return; + } + } + + /* escape opcode */ + if (*op == 0x0f) { + ++op; + + /* + * This is move with zero-extend and sign-extend, respectively; + * we don't have to think about 0xb6/0xbe, because this is + * already handled in the conditional below. + */ + if (*op == 0xb7 || *op == 0xbf) + operand_size_override = 2; + } + + *size = (*op & 1) ? operand_size_override : 1; +} + +const uint8_t *kmemcheck_opcode_get_primary(const uint8_t *op) +{ + /* skip prefixes */ + while (opcode_is_prefix(*op)) + ++op; + if (opcode_is_rex_prefix(*op)) + ++op; + return op; +} diff --git a/arch/x86/mm/kmemcheck/opcode.h b/arch/x86/mm/kmemcheck/opcode.h new file mode 100644 index 000000000000..6956aad66b5b --- /dev/null +++ b/arch/x86/mm/kmemcheck/opcode.h @@ -0,0 +1,9 @@ +#ifndef ARCH__X86__MM__KMEMCHECK__OPCODE_H +#define ARCH__X86__MM__KMEMCHECK__OPCODE_H + +#include + +void kmemcheck_opcode_decode(const uint8_t *op, unsigned int *size); +const uint8_t *kmemcheck_opcode_get_primary(const uint8_t *op); + +#endif diff --git a/arch/x86/mm/kmemcheck/pte.c b/arch/x86/mm/kmemcheck/pte.c new file mode 100644 index 000000000000..4ead26eeaf96 --- /dev/null +++ b/arch/x86/mm/kmemcheck/pte.c @@ -0,0 +1,22 @@ +#include + +#include + +#include "pte.h" + +pte_t *kmemcheck_pte_lookup(unsigned long address) +{ + pte_t *pte; + unsigned int level; + + pte = lookup_address(address, &level); + if (!pte) + return NULL; + if (level != PG_LEVEL_4K) + return NULL; + if (!pte_hidden(*pte)) + return NULL; + + return pte; +} + diff --git a/arch/x86/mm/kmemcheck/pte.h b/arch/x86/mm/kmemcheck/pte.h new file mode 100644 index 000000000000..9f5966456492 --- /dev/null +++ b/arch/x86/mm/kmemcheck/pte.h @@ -0,0 +1,10 @@ +#ifndef ARCH__X86__MM__KMEMCHECK__PTE_H +#define ARCH__X86__MM__KMEMCHECK__PTE_H + +#include + +#include + +pte_t *kmemcheck_pte_lookup(unsigned long address); + +#endif diff --git a/arch/x86/mm/kmemcheck/selftest.c b/arch/x86/mm/kmemcheck/selftest.c new file mode 100644 index 000000000000..036efbea8b28 --- /dev/null +++ b/arch/x86/mm/kmemcheck/selftest.c @@ -0,0 +1,69 @@ +#include + +#include "opcode.h" +#include "selftest.h" + +struct selftest_opcode { + unsigned int expected_size; + const uint8_t *insn; + const char *desc; +}; + +static const struct selftest_opcode selftest_opcodes[] = { + /* REP MOVS */ + {1, "\xf3\xa4", "rep movsb , "}, + {4, "\xf3\xa5", "rep movsl , "}, + + /* MOVZX / MOVZXD */ + {1, "\x66\x0f\xb6\x51\xf8", "movzwq , "}, + {1, "\x0f\xb6\x51\xf8", "movzwq , "}, + + /* MOVSX / MOVSXD */ + {1, "\x66\x0f\xbe\x51\xf8", "movswq , "}, + {1, "\x0f\xbe\x51\xf8", "movswq , "}, + +#ifdef CONFIG_X86_64 + /* MOVZX / MOVZXD */ + {1, "\x49\x0f\xb6\x51\xf8", "movzbq , "}, + {2, "\x49\x0f\xb7\x51\xf8", "movzbq , "}, + + /* MOVSX / MOVSXD */ + {1, "\x49\x0f\xbe\x51\xf8", "movsbq , "}, + {2, "\x49\x0f\xbf\x51\xf8", "movsbq , "}, + {4, "\x49\x63\x51\xf8", "movslq , "}, +#endif +}; + +static bool selftest_opcode_one(const struct selftest_opcode *op) +{ + unsigned size; + + kmemcheck_opcode_decode(op->insn, &size); + + if (size == op->expected_size) + return true; + + printk(KERN_WARNING "kmemcheck: opcode %s: expected size %d, got %d\n", + op->desc, op->expected_size, size); + return false; +} + +static bool selftest_opcodes_all(void) +{ + bool pass = true; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(selftest_opcodes); ++i) + pass = pass && selftest_opcode_one(&selftest_opcodes[i]); + + return pass; +} + +bool kmemcheck_selftest(void) +{ + bool pass = true; + + pass = pass && selftest_opcodes_all(); + + return pass; +} diff --git a/arch/x86/mm/kmemcheck/selftest.h b/arch/x86/mm/kmemcheck/selftest.h new file mode 100644 index 000000000000..8fed4fe11f95 --- /dev/null +++ b/arch/x86/mm/kmemcheck/selftest.h @@ -0,0 +1,6 @@ +#ifndef ARCH_X86_MM_KMEMCHECK_SELFTEST_H +#define ARCH_X86_MM_KMEMCHECK_SELFTEST_H + +bool kmemcheck_selftest(void); + +#endif diff --git a/arch/x86/mm/kmemcheck/shadow.c b/arch/x86/mm/kmemcheck/shadow.c new file mode 100644 index 000000000000..e773b6bd0079 --- /dev/null +++ b/arch/x86/mm/kmemcheck/shadow.c @@ -0,0 +1,162 @@ +#include +#include +#include +#include + +#include +#include + +#include "pte.h" +#include "shadow.h" + +/* + * Return the shadow address for the given address. Returns NULL if the + * address is not tracked. + * + * We need to be extremely careful not to follow any invalid pointers, + * because this function can be called for *any* possible address. + */ +void *kmemcheck_shadow_lookup(unsigned long address) +{ + pte_t *pte; + struct page *page; + + if (!virt_addr_valid(address)) + return NULL; + + pte = kmemcheck_pte_lookup(address); + if (!pte) + return NULL; + + page = virt_to_page(address); + if (!page->shadow) + return NULL; + return page->shadow + (address & (PAGE_SIZE - 1)); +} + +static void mark_shadow(void *address, unsigned int n, + enum kmemcheck_shadow status) +{ + unsigned long addr = (unsigned long) address; + unsigned long last_addr = addr + n - 1; + unsigned long page = addr & PAGE_MASK; + unsigned long last_page = last_addr & PAGE_MASK; + unsigned int first_n; + void *shadow; + + /* If the memory range crosses a page boundary, stop there. */ + if (page == last_page) + first_n = n; + else + first_n = page + PAGE_SIZE - addr; + + shadow = kmemcheck_shadow_lookup(addr); + if (shadow) + memset(shadow, status, first_n); + + addr += first_n; + n -= first_n; + + /* Do full-page memset()s. */ + while (n >= PAGE_SIZE) { + shadow = kmemcheck_shadow_lookup(addr); + if (shadow) + memset(shadow, status, PAGE_SIZE); + + addr += PAGE_SIZE; + n -= PAGE_SIZE; + } + + /* Do the remaining page, if any. */ + if (n > 0) { + shadow = kmemcheck_shadow_lookup(addr); + if (shadow) + memset(shadow, status, n); + } +} + +void kmemcheck_mark_unallocated(void *address, unsigned int n) +{ + mark_shadow(address, n, KMEMCHECK_SHADOW_UNALLOCATED); +} + +void kmemcheck_mark_uninitialized(void *address, unsigned int n) +{ + mark_shadow(address, n, KMEMCHECK_SHADOW_UNINITIALIZED); +} + +/* + * Fill the shadow memory of the given address such that the memory at that + * address is marked as being initialized. + */ +void kmemcheck_mark_initialized(void *address, unsigned int n) +{ + mark_shadow(address, n, KMEMCHECK_SHADOW_INITIALIZED); +} +EXPORT_SYMBOL_GPL(kmemcheck_mark_initialized); + +void kmemcheck_mark_freed(void *address, unsigned int n) +{ + mark_shadow(address, n, KMEMCHECK_SHADOW_FREED); +} + +void kmemcheck_mark_unallocated_pages(struct page *p, unsigned int n) +{ + unsigned int i; + + for (i = 0; i < n; ++i) + kmemcheck_mark_unallocated(page_address(&p[i]), PAGE_SIZE); +} + +void kmemcheck_mark_uninitialized_pages(struct page *p, unsigned int n) +{ + unsigned int i; + + for (i = 0; i < n; ++i) + kmemcheck_mark_uninitialized(page_address(&p[i]), PAGE_SIZE); +} + +void kmemcheck_mark_initialized_pages(struct page *p, unsigned int n) +{ + unsigned int i; + + for (i = 0; i < n; ++i) + kmemcheck_mark_initialized(page_address(&p[i]), PAGE_SIZE); +} + +enum kmemcheck_shadow kmemcheck_shadow_test(void *shadow, unsigned int size) +{ + uint8_t *x; + unsigned int i; + + x = shadow; + +#ifdef CONFIG_KMEMCHECK_PARTIAL_OK + /* + * Make sure _some_ bytes are initialized. Gcc frequently generates + * code to access neighboring bytes. + */ + for (i = 0; i < size; ++i) { + if (x[i] == KMEMCHECK_SHADOW_INITIALIZED) + return x[i]; + } +#else + /* All bytes must be initialized. */ + for (i = 0; i < size; ++i) { + if (x[i] != KMEMCHECK_SHADOW_INITIALIZED) + return x[i]; + } +#endif + + return x[0]; +} + +void kmemcheck_shadow_set(void *shadow, unsigned int size) +{ + uint8_t *x; + unsigned int i; + + x = shadow; + for (i = 0; i < size; ++i) + x[i] = KMEMCHECK_SHADOW_INITIALIZED; +} diff --git a/arch/x86/mm/kmemcheck/shadow.h b/arch/x86/mm/kmemcheck/shadow.h new file mode 100644 index 000000000000..af46d9ab9d86 --- /dev/null +++ b/arch/x86/mm/kmemcheck/shadow.h @@ -0,0 +1,16 @@ +#ifndef ARCH__X86__MM__KMEMCHECK__SHADOW_H +#define ARCH__X86__MM__KMEMCHECK__SHADOW_H + +enum kmemcheck_shadow { + KMEMCHECK_SHADOW_UNALLOCATED, + KMEMCHECK_SHADOW_UNINITIALIZED, + KMEMCHECK_SHADOW_INITIALIZED, + KMEMCHECK_SHADOW_FREED, +}; + +void *kmemcheck_shadow_lookup(unsigned long address); + +enum kmemcheck_shadow kmemcheck_shadow_test(void *shadow, unsigned int size); +void kmemcheck_shadow_set(void *shadow, unsigned int size); + +#endif diff --git a/arch/x86/mm/kmmio.c b/arch/x86/mm/kmmio.c index 50dc802a1c46..16ccbd77917f 100644 --- a/arch/x86/mm/kmmio.c +++ b/arch/x86/mm/kmmio.c @@ -32,7 +32,7 @@ struct kmmio_fault_page { struct list_head list; struct kmmio_fault_page *release_next; unsigned long page; /* location of the fault page */ - bool old_presence; /* page presence prior to arming */ + pteval_t old_presence; /* page presence prior to arming */ bool armed; /* @@ -97,60 +97,62 @@ static struct kmmio_probe *get_kmmio_probe(unsigned long addr) static struct kmmio_fault_page *get_kmmio_fault_page(unsigned long page) { struct list_head *head; - struct kmmio_fault_page *p; + struct kmmio_fault_page *f; page &= PAGE_MASK; head = kmmio_page_list(page); - list_for_each_entry_rcu(p, head, list) { - if (p->page == page) - return p; + list_for_each_entry_rcu(f, head, list) { + if (f->page == page) + return f; } return NULL; } -static void set_pmd_presence(pmd_t *pmd, bool present, bool *old) +static void clear_pmd_presence(pmd_t *pmd, bool clear, pmdval_t *old) { pmdval_t v = pmd_val(*pmd); - *old = !!(v & _PAGE_PRESENT); - v &= ~_PAGE_PRESENT; - if (present) - v |= _PAGE_PRESENT; + if (clear) { + *old = v & _PAGE_PRESENT; + v &= ~_PAGE_PRESENT; + } else /* presume this has been called with clear==true previously */ + v |= *old; set_pmd(pmd, __pmd(v)); } -static void set_pte_presence(pte_t *pte, bool present, bool *old) +static void clear_pte_presence(pte_t *pte, bool clear, pteval_t *old) { pteval_t v = pte_val(*pte); - *old = !!(v & _PAGE_PRESENT); - v &= ~_PAGE_PRESENT; - if (present) - v |= _PAGE_PRESENT; + if (clear) { + *old = v & _PAGE_PRESENT; + v &= ~_PAGE_PRESENT; + } else /* presume this has been called with clear==true previously */ + v |= *old; set_pte_atomic(pte, __pte(v)); } -static int set_page_presence(unsigned long addr, bool present, bool *old) +static int clear_page_presence(struct kmmio_fault_page *f, bool clear) { unsigned int level; - pte_t *pte = lookup_address(addr, &level); + pte_t *pte = lookup_address(f->page, &level); if (!pte) { - pr_err("kmmio: no pte for page 0x%08lx\n", addr); + pr_err("kmmio: no pte for page 0x%08lx\n", f->page); return -1; } switch (level) { case PG_LEVEL_2M: - set_pmd_presence((pmd_t *)pte, present, old); + clear_pmd_presence((pmd_t *)pte, clear, &f->old_presence); break; case PG_LEVEL_4K: - set_pte_presence(pte, present, old); + clear_pte_presence(pte, clear, &f->old_presence); break; default: pr_err("kmmio: unexpected page level 0x%x.\n", level); return -1; } - __flush_tlb_one(addr); + __flush_tlb_one(f->page); return 0; } @@ -171,9 +173,9 @@ static int arm_kmmio_fault_page(struct kmmio_fault_page *f) WARN_ONCE(f->armed, KERN_ERR "kmmio page already armed.\n"); if (f->armed) { pr_warning("kmmio double-arm: page 0x%08lx, ref %d, old %d\n", - f->page, f->count, f->old_presence); + f->page, f->count, !!f->old_presence); } - ret = set_page_presence(f->page, false, &f->old_presence); + ret = clear_page_presence(f, true); WARN_ONCE(ret < 0, KERN_ERR "kmmio arming 0x%08lx failed.\n", f->page); f->armed = true; return ret; @@ -182,8 +184,7 @@ static int arm_kmmio_fault_page(struct kmmio_fault_page *f) /** Restore the given page to saved presence state. */ static void disarm_kmmio_fault_page(struct kmmio_fault_page *f) { - bool tmp; - int ret = set_page_presence(f->page, f->old_presence, &tmp); + int ret = clear_page_presence(f, false); WARN_ONCE(ret < 0, KERN_ERR "kmmio disarming 0x%08lx failed.\n", f->page); f->armed = false; @@ -310,7 +311,12 @@ static int post_kmmio_handler(unsigned long condition, struct pt_regs *regs) struct kmmio_context *ctx = &get_cpu_var(kmmio_ctx); if (!ctx->active) { - pr_debug("kmmio: spurious debug trap on CPU %d.\n", + /* + * debug traps without an active context are due to either + * something external causing them (f.e. using a debugger while + * mmio tracing enabled), or erroneous behaviour + */ + pr_warning("kmmio: unexpected debug trap on CPU %d.\n", smp_processor_id()); goto out; } @@ -439,12 +445,12 @@ static void rcu_free_kmmio_fault_pages(struct rcu_head *head) head, struct kmmio_delayed_release, rcu); - struct kmmio_fault_page *p = dr->release_list; - while (p) { - struct kmmio_fault_page *next = p->release_next; - BUG_ON(p->count); - kfree(p); - p = next; + struct kmmio_fault_page *f = dr->release_list; + while (f) { + struct kmmio_fault_page *next = f->release_next; + BUG_ON(f->count); + kfree(f); + f = next; } kfree(dr); } @@ -453,19 +459,19 @@ static void remove_kmmio_fault_pages(struct rcu_head *head) { struct kmmio_delayed_release *dr = container_of(head, struct kmmio_delayed_release, rcu); - struct kmmio_fault_page *p = dr->release_list; + struct kmmio_fault_page *f = dr->release_list; struct kmmio_fault_page **prevp = &dr->release_list; unsigned long flags; spin_lock_irqsave(&kmmio_lock, flags); - while (p) { - if (!p->count) { - list_del_rcu(&p->list); - prevp = &p->release_next; + while (f) { + if (!f->count) { + list_del_rcu(&f->list); + prevp = &f->release_next; } else { - *prevp = p->release_next; + *prevp = f->release_next; } - p = p->release_next; + f = f->release_next; } spin_unlock_irqrestore(&kmmio_lock, flags); @@ -528,8 +534,8 @@ void unregister_kmmio_probe(struct kmmio_probe *p) } EXPORT_SYMBOL(unregister_kmmio_probe); -static int kmmio_die_notifier(struct notifier_block *nb, unsigned long val, - void *args) +static int +kmmio_die_notifier(struct notifier_block *nb, unsigned long val, void *args) { struct die_args *arg = args; @@ -544,11 +550,23 @@ static struct notifier_block nb_die = { .notifier_call = kmmio_die_notifier }; -static int __init init_kmmio(void) +int kmmio_init(void) { int i; + for (i = 0; i < KMMIO_PAGE_TABLE_SIZE; i++) INIT_LIST_HEAD(&kmmio_page_table[i]); + return register_die_notifier(&nb_die); } -fs_initcall(init_kmmio); /* should be before device_initcall() */ + +void kmmio_cleanup(void) +{ + int i; + + unregister_die_notifier(&nb_die); + for (i = 0; i < KMMIO_PAGE_TABLE_SIZE; i++) { + WARN_ONCE(!list_empty(&kmmio_page_table[i]), + KERN_ERR "kmmio_page_table not empty at cleanup, any further tracing will leak memory.\n"); + } +} diff --git a/arch/x86/mm/memtest.c b/arch/x86/mm/memtest.c index 605c8be06217..18d244f70205 100644 --- a/arch/x86/mm/memtest.c +++ b/arch/x86/mm/memtest.c @@ -40,23 +40,22 @@ static void __init reserve_bad_mem(u64 pattern, u64 start_bad, u64 end_bad) static void __init memtest(u64 pattern, u64 start_phys, u64 size) { - u64 i, count; - u64 *start; + u64 *p, *start, *end; u64 start_bad, last_bad; u64 start_phys_aligned; - size_t incr; + const size_t incr = sizeof(pattern); - incr = sizeof(pattern); start_phys_aligned = ALIGN(start_phys, incr); - count = (size - (start_phys_aligned - start_phys))/incr; start = __va(start_phys_aligned); + end = start + (size - (start_phys_aligned - start_phys)) / incr; start_bad = 0; last_bad = 0; - for (i = 0; i < count; i++) - start[i] = pattern; - for (i = 0; i < count; i++, start++, start_phys_aligned += incr) { - if (*start == pattern) + for (p = start; p < end; p++) + *p = pattern; + + for (p = start; p < end; p++, start_phys_aligned += incr) { + if (*p == pattern) continue; if (start_phys_aligned == last_bad + incr) { last_bad += incr; diff --git a/arch/x86/mm/mmio-mod.c b/arch/x86/mm/mmio-mod.c index c9342ed8b402..132772a8ec57 100644 --- a/arch/x86/mm/mmio-mod.c +++ b/arch/x86/mm/mmio-mod.c @@ -451,6 +451,7 @@ void enable_mmiotrace(void) if (nommiotrace) pr_info(NAME "MMIO tracing disabled.\n"); + kmmio_init(); enter_uniprocessor(); spin_lock_irq(&trace_lock); atomic_inc(&mmiotrace_enabled); @@ -473,6 +474,7 @@ void disable_mmiotrace(void) clear_trace_list(); /* guarantees: no more kmmio callbacks */ leave_uniprocessor(); + kmmio_cleanup(); pr_info(NAME "disabled.\n"); out: mutex_unlock(&mmiotrace_mutex); diff --git a/arch/x86/mm/numa_64.c b/arch/x86/mm/numa_64.c index 2d05a12029dc..459913beac71 100644 --- a/arch/x86/mm/numa_64.c +++ b/arch/x86/mm/numa_64.c @@ -179,18 +179,25 @@ static void * __init early_node_mem(int nodeid, unsigned long start, } /* Initialize bootmem allocator for a node */ -void __init setup_node_bootmem(int nodeid, unsigned long start, - unsigned long end) +void __init +setup_node_bootmem(int nodeid, unsigned long start, unsigned long end) { unsigned long start_pfn, last_pfn, bootmap_pages, bootmap_size; + const int pgdat_size = roundup(sizeof(pg_data_t), PAGE_SIZE); unsigned long bootmap_start, nodedata_phys; void *bootmap; - const int pgdat_size = roundup(sizeof(pg_data_t), PAGE_SIZE); int nid; if (!end) return; + /* + * Don't confuse VM with a node that doesn't have the + * minimum amount of memory: + */ + if (end && (end - start) < NODE_MIN_SIZE) + return; + start = roundup(start, ZONE_ALIGN); printk(KERN_INFO "Bootmem setup node %d %016lx-%016lx\n", nodeid, @@ -272,9 +279,6 @@ void __init setup_node_bootmem(int nodeid, unsigned long start, reserve_bootmem_node(NODE_DATA(nodeid), bootmap_start, bootmap_pages<> PAGE_SHIFT; unsigned long e_pfn = end >> PAGE_SHIFT; - int ret = 0, changed = 0; + int changed = 0; struct bootnode *nd = &nodes_add[node]; /* I had some trouble with strange memory hotadd regions breaking @@ -210,7 +197,7 @@ reserve_hotadd(int node, unsigned long start, unsigned long end) mistakes */ if ((signed long)(end - start) < NODE_MIN_SIZE) { printk(KERN_ERR "SRAT: Hotplug area too small\n"); - return -1; + return; } /* This check might be a bit too strict, but I'm keeping it for now. */ @@ -218,12 +205,7 @@ reserve_hotadd(int node, unsigned long start, unsigned long end) printk(KERN_ERR "SRAT: Hotplug area %lu -> %lu has existing memory\n", s_pfn, e_pfn); - return -1; - } - - if (!hotadd_enough_memory(&nodes_add[node])) { - printk(KERN_ERR "SRAT: Hotplug area too large\n"); - return -1; + return; } /* Looks good */ @@ -245,11 +227,9 @@ reserve_hotadd(int node, unsigned long start, unsigned long end) printk(KERN_ERR "SRAT: Hotplug zone not continuous. Partly ignored\n"); } - ret = update_end_of_memory(nd->end); - if (changed) - printk(KERN_INFO "SRAT: hot plug zone found %Lx - %Lx\n", nd->start, nd->end); - return ret; + printk(KERN_INFO "SRAT: hot plug zone found %Lx - %Lx\n", + nd->start, nd->end); } /* Callback for parsing of the Proximity Domain <-> Memory Area mappings */ @@ -310,13 +290,10 @@ acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma) start, end); e820_register_active_regions(node, start >> PAGE_SHIFT, end >> PAGE_SHIFT); - push_node_boundaries(node, nd->start >> PAGE_SHIFT, - nd->end >> PAGE_SHIFT); - if ((ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) && - (reserve_hotadd(node, start, end) < 0)) { - /* Ignore hotadd region. Undo damage */ - printk(KERN_NOTICE "SRAT: Hotplug region ignored\n"); + if (ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) { + update_nodes_add(node, start, end); + /* restore nodes[node] */ *nd = oldnode; if ((nd->start | nd->end) == 0) node_clear(node, nodes_parsed); @@ -345,9 +322,9 @@ static int __init nodes_cover_memory(const struct bootnode *nodes) pxmram = 0; } - e820ram = max_pfn - absent_pages_in_range(0, max_pfn); - /* We seem to lose 3 pages somewhere. Allow a bit of slack. */ - if ((long)(e820ram - pxmram) >= 1*1024*1024) { + e820ram = max_pfn - (e820_hole_size(0, max_pfn<>PAGE_SHIFT); + /* We seem to lose 3 pages somewhere. Allow 1M of slack. */ + if ((long)(e820ram - pxmram) >= (1<<(20 - PAGE_SHIFT))) { printk(KERN_ERR "SRAT: PXMs only cover %luMB of your %luMB e820 RAM. Not used.\n", (pxmram << PAGE_SHIFT) >> 20, @@ -357,17 +334,6 @@ static int __init nodes_cover_memory(const struct bootnode *nodes) return 1; } -static void __init unparse_node(int node) -{ - int i; - node_clear(node, nodes_parsed); - node_clear(node, cpu_nodes_parsed); - for (i = 0; i < MAX_LOCAL_APIC; i++) { - if (apicid_to_node[i] == node) - apicid_to_node[i] = NUMA_NO_NODE; - } -} - void __init acpi_numa_arch_fixup(void) {} /* Use the information discovered above to actually set up the nodes. */ @@ -379,18 +345,8 @@ int __init acpi_scan_nodes(unsigned long start, unsigned long end) return -1; /* First clean up the node list */ - for (i = 0; i < MAX_NUMNODES; i++) { + for (i = 0; i < MAX_NUMNODES; i++) cutoff_node(i, start, end); - /* - * don't confuse VM with a node that doesn't have the - * minimum memory. - */ - if (nodes[i].end && - (nodes[i].end - nodes[i].start) < NODE_MIN_SIZE) { - unparse_node(i); - node_set_offline(i); - } - } if (!nodes_cover_memory(nodes)) { bad_srat(); @@ -423,7 +379,7 @@ int __init acpi_scan_nodes(unsigned long start, unsigned long end) if (node == NUMA_NO_NODE) continue; - if (!node_isset(node, node_possible_map)) + if (!node_online(node)) numa_clear_node(i); } numa_init_array(); @@ -510,26 +466,6 @@ static int null_slit_node_compare(int a, int b) } #endif /* CONFIG_NUMA_EMU */ -void __init srat_reserve_add_area(int nodeid) -{ - if (found_add_area && nodes_add[nodeid].end) { - u64 total_mb; - - printk(KERN_INFO "SRAT: Reserving hot-add memory space " - "for node %d at %Lx-%Lx\n", - nodeid, nodes_add[nodeid].start, nodes_add[nodeid].end); - total_mb = (nodes_add[nodeid].end - nodes_add[nodeid].start) - >> PAGE_SHIFT; - total_mb *= sizeof(struct page); - total_mb >>= 20; - printk(KERN_INFO "SRAT: This will cost you %Lu MB of " - "pre-allocated memory.\n", (unsigned long long)total_mb); - reserve_bootmem_node(NODE_DATA(nodeid), nodes_add[nodeid].start, - nodes_add[nodeid].end - nodes_add[nodeid].start, - BOOTMEM_DEFAULT); - } -} - int __node_distance(int a, int b) { int index; diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index 202864ad49a7..b07dd8d0b321 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -40,8 +40,9 @@ static int profile_exceptions_notify(struct notifier_block *self, switch (val) { case DIE_NMI: - if (model->check_ctrs(args->regs, &per_cpu(cpu_msrs, cpu))) - ret = NOTIFY_STOP; + case DIE_NMI_IPI: + model->check_ctrs(args->regs, &per_cpu(cpu_msrs, cpu)); + ret = NOTIFY_STOP; break; default: break; @@ -134,7 +135,7 @@ static void nmi_cpu_setup(void *dummy) static struct notifier_block profile_exceptions_nb = { .notifier_call = profile_exceptions_notify, .next = NULL, - .priority = 0 + .priority = 2 }; static int nmi_setup(void) @@ -356,14 +357,11 @@ static void exit_sysfs(void) #define exit_sysfs() do { } while (0) #endif /* CONFIG_PM */ -static int p4force; -module_param(p4force, int, 0); - static int __init p4_init(char **cpu_type) { __u8 cpu_model = boot_cpu_data.x86_model; - if (!p4force && (cpu_model > 6 || cpu_model == 5)) + if (cpu_model > 6 || cpu_model == 5) return 0; #ifndef CONFIG_SMP @@ -389,10 +387,25 @@ static int __init p4_init(char **cpu_type) return 0; } +static int force_arch_perfmon; +static int force_cpu_type(const char *str, struct kernel_param *kp) +{ + if (!strcmp(str, "archperfmon")) { + force_arch_perfmon = 1; + printk(KERN_INFO "oprofile: forcing architectural perfmon\n"); + } + + return 0; +} +module_param_call(cpu_type, force_cpu_type, NULL, NULL, 0); + static int __init ppro_init(char **cpu_type) { __u8 cpu_model = boot_cpu_data.x86_model; + if (force_arch_perfmon && cpu_has_arch_perfmon) + return 0; + switch (cpu_model) { case 0 ... 2: *cpu_type = "i386/ppro"; @@ -414,6 +427,13 @@ static int __init ppro_init(char **cpu_type) case 15: case 23: *cpu_type = "i386/core_2"; break; + case 26: + arch_perfmon_setup_counters(); + *cpu_type = "i386/core_i7"; + break; + case 28: + *cpu_type = "i386/atom"; + break; default: /* Unknown */ return 0; diff --git a/arch/x86/oprofile/op_model_ppro.c b/arch/x86/oprofile/op_model_ppro.c index 10131fbdaada..4da7230b3d17 100644 --- a/arch/x86/oprofile/op_model_ppro.c +++ b/arch/x86/oprofile/op_model_ppro.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include "op_x86_model.h" #include "op_counter.h" @@ -136,6 +136,13 @@ static int ppro_check_ctrs(struct pt_regs * const regs, u64 val; int i; + /* + * This can happen if perf counters are in use when + * we steal the die notifier NMI. + */ + if (unlikely(!reset_value)) + goto out; + for (i = 0 ; i < num_counters; ++i) { if (!reset_value[i]) continue; @@ -146,6 +153,7 @@ static int ppro_check_ctrs(struct pt_regs * const regs, } } +out: /* Only P6 based Pentium M need to re-unmask the apic vector but it * doesn't hurt other P6 variant */ apic_write(APIC_LVTPC, apic_read(APIC_LVTPC) & ~APIC_LVT_MASKED); diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c index c0ecf250fe51..b26626dc517c 100644 --- a/arch/x86/pci/acpi.c +++ b/arch/x86/pci/acpi.c @@ -38,15 +38,26 @@ count_resource(struct acpi_resource *acpi_res, void *data) struct acpi_resource_address64 addr; acpi_status status; - if (info->res_num >= PCI_BUS_NUM_RESOURCES) - return AE_OK; - status = resource_to_addr(acpi_res, &addr); if (ACPI_SUCCESS(status)) info->res_num++; return AE_OK; } +static int +bus_has_transparent_bridge(struct pci_bus *bus) +{ + struct pci_dev *dev; + + list_for_each_entry(dev, &bus->devices, bus_list) { + u16 class = dev->class >> 8; + + if (class == PCI_CLASS_BRIDGE_PCI && dev->transparent) + return true; + } + return false; +} + static acpi_status setup_resource(struct acpi_resource *acpi_res, void *data) { @@ -56,9 +67,7 @@ setup_resource(struct acpi_resource *acpi_res, void *data) acpi_status status; unsigned long flags; struct resource *root; - - if (info->res_num >= PCI_BUS_NUM_RESOURCES) - return AE_OK; + int max_root_bus_resources = PCI_BUS_NUM_RESOURCES; status = resource_to_addr(acpi_res, &addr); if (!ACPI_SUCCESS(status)) @@ -82,6 +91,18 @@ setup_resource(struct acpi_resource *acpi_res, void *data) res->end = res->start + addr.address_length - 1; res->child = NULL; + if (bus_has_transparent_bridge(info->bus)) + max_root_bus_resources -= 3; + if (info->res_num >= max_root_bus_resources) { + printk(KERN_WARNING "PCI: Failed to allocate 0x%lx-0x%lx " + "from %s for %s due to _CRS returning more than " + "%d resource descriptors\n", (unsigned long) res->start, + (unsigned long) res->end, root->name, info->name, + max_root_bus_resources); + info->res_num++; + return AE_OK; + } + if (insert_resource(root, res)) { printk(KERN_ERR "PCI: Failed to allocate 0x%lx-0x%lx " "from %s for %s\n", (unsigned long) res->start, diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c index a85bef20a3b9..0fb56db16d18 100644 --- a/arch/x86/pci/i386.c +++ b/arch/x86/pci/i386.c @@ -116,7 +116,7 @@ static void __init pcibios_allocate_bus_resources(struct list_head *bus_list) struct pci_bus *bus; struct pci_dev *dev; int idx; - struct resource *r, *pr; + struct resource *r; /* Depth-First Search on bus tree */ list_for_each_entry(bus, bus_list, node) { @@ -126,9 +126,8 @@ static void __init pcibios_allocate_bus_resources(struct list_head *bus_list) r = &dev->resource[idx]; if (!r->flags) continue; - pr = pci_find_parent_resource(dev, r); - if (!r->start || !pr || - request_resource(pr, r) < 0) { + if (!r->start || + pci_claim_resource(dev, idx) < 0) { dev_info(&dev->dev, "BAR %d: can't allocate resource\n", idx); /* * Something is wrong with the region. @@ -149,7 +148,7 @@ static void __init pcibios_allocate_resources(int pass) struct pci_dev *dev = NULL; int idx, disabled; u16 command; - struct resource *r, *pr; + struct resource *r; for_each_pci_dev(dev) { pci_read_config_word(dev, PCI_COMMAND, &command); @@ -168,8 +167,7 @@ static void __init pcibios_allocate_resources(int pass) (unsigned long long) r->start, (unsigned long long) r->end, r->flags, disabled, pass); - pr = pci_find_parent_resource(dev, r); - if (!pr || request_resource(pr, r) < 0) { + if (pci_claim_resource(dev, idx) < 0) { dev_info(&dev->dev, "BAR %d: can't allocate resource\n", idx); /* We'll assign a new address later */ r->end -= r->start; @@ -197,7 +195,7 @@ static void __init pcibios_allocate_resources(int pass) static int __init pcibios_assign_resources(void) { struct pci_dev *dev = NULL; - struct resource *r, *pr; + struct resource *r; if (!(pci_probe & PCI_ASSIGN_ROMS)) { /* @@ -209,8 +207,7 @@ static int __init pcibios_assign_resources(void) r = &dev->resource[PCI_ROM_RESOURCE]; if (!r->flags || !r->start) continue; - pr = pci_find_parent_resource(dev, r); - if (!pr || request_resource(pr, r) < 0) { + if (pci_claim_resource(dev, PCI_ROM_RESOURCE) < 0) { r->end -= r->start; r->start = 0; } diff --git a/arch/x86/pci/irq.c b/arch/x86/pci/irq.c index fecbce6e7d7c..0696d506c4ad 100644 --- a/arch/x86/pci/irq.c +++ b/arch/x86/pci/irq.c @@ -889,6 +889,9 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign) return 0; } + if (io_apic_assign_pci_irqs) + return 0; + /* Find IRQ routing entry */ if (!pirq_table) @@ -1039,56 +1042,15 @@ static void __init pcibios_fixup_irqs(void) pirq_penalty[dev->irq]++; } + if (io_apic_assign_pci_irqs) + return; + dev = NULL; while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); if (!pin) continue; -#ifdef CONFIG_X86_IO_APIC - /* - * Recalculate IRQ numbers if we use the I/O APIC. - */ - if (io_apic_assign_pci_irqs) { - int irq; - - /* - * interrupt pins are numbered starting from 1 - */ - irq = IO_APIC_get_PCI_irq_vector(dev->bus->number, - PCI_SLOT(dev->devfn), pin - 1); - /* - * Busses behind bridges are typically not listed in the - * MP-table. In this case we have to look up the IRQ - * based on the parent bus, parent slot, and pin number. - * The SMP code detects such bridged busses itself so we - * should get into this branch reliably. - */ - if (irq < 0 && dev->bus->parent) { - /* go back to the bridge */ - struct pci_dev *bridge = dev->bus->self; - int bus; - - pin = pci_swizzle_interrupt_pin(dev, pin); - bus = bridge->bus->number; - irq = IO_APIC_get_PCI_irq_vector(bus, - PCI_SLOT(bridge->devfn), pin - 1); - if (irq >= 0) - dev_warn(&dev->dev, - "using bridge %s INT %c to " - "get IRQ %d\n", - pci_name(bridge), - 'A' + pin - 1, irq); - } - if (irq >= 0) { - dev_info(&dev->dev, - "PCI->APIC IRQ transform: INT %c " - "-> IRQ %d\n", - 'A' + pin - 1, irq); - dev->irq = irq; - } - } -#endif /* * Still no IRQ? Try to lookup one... */ @@ -1183,6 +1145,19 @@ int __init pcibios_irq_init(void) pcibios_enable_irq = pirq_enable_irq; pcibios_fixup_irqs(); + + if (io_apic_assign_pci_irqs && pci_routeirq) { + struct pci_dev *dev = NULL; + /* + * PCI IRQ routing is set up by pci_enable_device(), but we + * also do it here in case there are still broken drivers that + * don't use pci_enable_device(). + */ + printk(KERN_INFO "PCI: Routing PCI interrupts for all devices because \"pci=routeirq\" specified\n"); + for_each_pci_dev(dev) + pirq_enable_irq(dev); + } + return 0; } @@ -1213,16 +1188,23 @@ void pcibios_penalize_isa_irq(int irq, int active) static int pirq_enable_irq(struct pci_dev *dev) { u8 pin; - struct pci_dev *temp_dev; pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); - if (pin && !pcibios_lookup_irq(dev, 1) && !dev->irq) { + if (pin && !pcibios_lookup_irq(dev, 1)) { char *msg = ""; - if (io_apic_assign_pci_irqs) { - int irq; + if (!io_apic_assign_pci_irqs && dev->irq) + return 0; - irq = IO_APIC_get_PCI_irq_vector(dev->bus->number, PCI_SLOT(dev->devfn), pin - 1); + if (io_apic_assign_pci_irqs) { +#ifdef CONFIG_X86_IO_APIC + struct pci_dev *temp_dev; + int irq; + struct io_apic_irq_attr irq_attr; + + irq = IO_APIC_get_PCI_irq_vector(dev->bus->number, + PCI_SLOT(dev->devfn), + pin - 1, &irq_attr); /* * Busses behind bridges are typically not listed in the MP-table. * In this case we have to look up the IRQ based on the parent bus, @@ -1235,7 +1217,8 @@ static int pirq_enable_irq(struct pci_dev *dev) pin = pci_swizzle_interrupt_pin(dev, pin); irq = IO_APIC_get_PCI_irq_vector(bridge->bus->number, - PCI_SLOT(bridge->devfn), pin - 1); + PCI_SLOT(bridge->devfn), + pin - 1, &irq_attr); if (irq >= 0) dev_warn(&dev->dev, "using bridge %s " "INT %c to get IRQ %d\n", @@ -1245,12 +1228,15 @@ static int pirq_enable_irq(struct pci_dev *dev) } dev = temp_dev; if (irq >= 0) { + io_apic_set_pci_routing(&dev->dev, irq, + &irq_attr); + dev->irq = irq; dev_info(&dev->dev, "PCI->APIC IRQ transform: " "INT %c -> IRQ %d\n", 'A' + pin - 1, irq); - dev->irq = irq; return 0; } else msg = "; probably buggy MP table"; +#endif } else if (pci_probe & PCI_BIOS_IRQ_SCAN) msg = ""; else diff --git a/arch/x86/pci/mmconfig-shared.c b/arch/x86/pci/mmconfig-shared.c index 8766b0e216c5..712443ec6d43 100644 --- a/arch/x86/pci/mmconfig-shared.c +++ b/arch/x86/pci/mmconfig-shared.c @@ -523,6 +523,69 @@ reject: static int __initdata known_bridge; +static int acpi_mcfg_64bit_base_addr __initdata = FALSE; + +/* The physical address of the MMCONFIG aperture. Set from ACPI tables. */ +struct acpi_mcfg_allocation *pci_mmcfg_config; +int pci_mmcfg_config_num; + +static int __init acpi_mcfg_oem_check(struct acpi_table_mcfg *mcfg) +{ + if (!strcmp(mcfg->header.oem_id, "SGI")) + acpi_mcfg_64bit_base_addr = TRUE; + + return 0; +} + +static int __init pci_parse_mcfg(struct acpi_table_header *header) +{ + struct acpi_table_mcfg *mcfg; + unsigned long i; + int config_size; + + if (!header) + return -EINVAL; + + mcfg = (struct acpi_table_mcfg *)header; + + /* how many config structures do we have */ + pci_mmcfg_config_num = 0; + i = header->length - sizeof(struct acpi_table_mcfg); + while (i >= sizeof(struct acpi_mcfg_allocation)) { + ++pci_mmcfg_config_num; + i -= sizeof(struct acpi_mcfg_allocation); + }; + if (pci_mmcfg_config_num == 0) { + printk(KERN_ERR PREFIX "MMCONFIG has no entries\n"); + return -ENODEV; + } + + config_size = pci_mmcfg_config_num * sizeof(*pci_mmcfg_config); + pci_mmcfg_config = kmalloc(config_size, GFP_KERNEL); + if (!pci_mmcfg_config) { + printk(KERN_WARNING PREFIX + "No memory for MCFG config tables\n"); + return -ENOMEM; + } + + memcpy(pci_mmcfg_config, &mcfg[1], config_size); + + acpi_mcfg_oem_check(mcfg); + + for (i = 0; i < pci_mmcfg_config_num; ++i) { + if ((pci_mmcfg_config[i].address > 0xFFFFFFFF) && + !acpi_mcfg_64bit_base_addr) { + printk(KERN_ERR PREFIX + "MMCONFIG not in low 4GB of memory\n"); + kfree(pci_mmcfg_config); + pci_mmcfg_config_num = 0; + return -ENODEV; + } + } + + return 0; +} + static void __init __pci_mmcfg_init(int early) { /* MMCONFIG disabled */ @@ -543,7 +606,7 @@ static void __init __pci_mmcfg_init(int early) } if (!known_bridge) - acpi_table_parse(ACPI_SIG_MCFG, acpi_parse_mcfg); + acpi_table_parse(ACPI_SIG_MCFG, pci_parse_mcfg); pci_mmcfg_reject_broken(early); diff --git a/arch/x86/power/Makefile b/arch/x86/power/Makefile index 58b32db33125..de2abbd07544 100644 --- a/arch/x86/power/Makefile +++ b/arch/x86/power/Makefile @@ -3,5 +3,5 @@ nostackp := $(call cc-option, -fno-stack-protector) CFLAGS_cpu_$(BITS).o := $(nostackp) -obj-$(CONFIG_PM_SLEEP) += cpu_$(BITS).o +obj-$(CONFIG_PM_SLEEP) += cpu.o obj-$(CONFIG_HIBERNATION) += hibernate_$(BITS).o hibernate_asm_$(BITS).o diff --git a/arch/x86/power/cpu_64.c b/arch/x86/power/cpu.c similarity index 62% rename from arch/x86/power/cpu_64.c rename to arch/x86/power/cpu.c index 5343540f2607..d277ef1eea51 100644 --- a/arch/x86/power/cpu_64.c +++ b/arch/x86/power/cpu.c @@ -1,5 +1,5 @@ /* - * Suspend and hibernation support for x86-64 + * Suspend support specific for i386/x86-64. * * Distribute under GPLv2 * @@ -8,18 +8,28 @@ * Copyright (c) 2001 Patrick Mochel */ -#include #include -#include -#include +#include + #include +#include #include +#include +#include #include #include -static void fix_processor_context(void); +#ifdef CONFIG_X86_32 +static struct saved_context saved_context; +unsigned long saved_context_ebx; +unsigned long saved_context_esp, saved_context_ebp; +unsigned long saved_context_esi, saved_context_edi; +unsigned long saved_context_eflags; +#else +/* CONFIG_X86_64 */ struct saved_context saved_context; +#endif /** * __save_processor_state - save CPU registers before creating a @@ -38,19 +48,35 @@ struct saved_context saved_context; */ static void __save_processor_state(struct saved_context *ctxt) { +#ifdef CONFIG_X86_32 + mtrr_save_fixed_ranges(NULL); +#endif kernel_fpu_begin(); /* * descriptor tables */ +#ifdef CONFIG_X86_32 + store_gdt(&ctxt->gdt); + store_idt(&ctxt->idt); +#else +/* CONFIG_X86_64 */ store_gdt((struct desc_ptr *)&ctxt->gdt_limit); store_idt((struct desc_ptr *)&ctxt->idt_limit); +#endif store_tr(ctxt->tr); /* XMM0..XMM15 should be handled by kernel_fpu_begin(). */ /* * segment registers */ +#ifdef CONFIG_X86_32 + savesegment(es, ctxt->es); + savesegment(fs, ctxt->fs); + savesegment(gs, ctxt->gs); + savesegment(ss, ctxt->ss); +#else +/* CONFIG_X86_64 */ asm volatile ("movw %%ds, %0" : "=m" (ctxt->ds)); asm volatile ("movw %%es, %0" : "=m" (ctxt->es)); asm volatile ("movw %%fs, %0" : "=m" (ctxt->fs)); @@ -62,30 +88,87 @@ static void __save_processor_state(struct saved_context *ctxt) rdmsrl(MSR_KERNEL_GS_BASE, ctxt->gs_kernel_base); mtrr_save_fixed_ranges(NULL); + rdmsrl(MSR_EFER, ctxt->efer); +#endif + /* * control registers */ - rdmsrl(MSR_EFER, ctxt->efer); ctxt->cr0 = read_cr0(); ctxt->cr2 = read_cr2(); ctxt->cr3 = read_cr3(); +#ifdef CONFIG_X86_32 + ctxt->cr4 = read_cr4_safe(); +#else +/* CONFIG_X86_64 */ ctxt->cr4 = read_cr4(); ctxt->cr8 = read_cr8(); +#endif } +/* Needed by apm.c */ void save_processor_state(void) { __save_processor_state(&saved_context); } +#ifdef CONFIG_X86_32 +EXPORT_SYMBOL(save_processor_state); +#endif static void do_fpu_end(void) { /* - * Restore FPU regs if necessary + * Restore FPU regs if necessary. */ kernel_fpu_end(); } +static void fix_processor_context(void) +{ + int cpu = smp_processor_id(); + struct tss_struct *t = &per_cpu(init_tss, cpu); + + set_tss_desc(cpu, t); /* + * This just modifies memory; should not be + * necessary. But... This is necessary, because + * 386 hardware has concept of busy TSS or some + * similar stupidity. + */ + +#ifdef CONFIG_X86_64 + get_cpu_gdt_table(cpu)[GDT_ENTRY_TSS].type = 9; + + syscall_init(); /* This sets MSR_*STAR and related */ +#endif + load_TR_desc(); /* This does ltr */ + load_LDT(¤t->active_mm->context); /* This does lldt */ + + /* + * Now maybe reload the debug registers + */ + if (current->thread.debugreg7) { +#ifdef CONFIG_X86_32 + set_debugreg(current->thread.debugreg0, 0); + set_debugreg(current->thread.debugreg1, 1); + set_debugreg(current->thread.debugreg2, 2); + set_debugreg(current->thread.debugreg3, 3); + /* no 4 and 5 */ + set_debugreg(current->thread.debugreg6, 6); + set_debugreg(current->thread.debugreg7, 7); +#else + /* CONFIG_X86_64 */ + loaddebug(¤t->thread, 0); + loaddebug(¤t->thread, 1); + loaddebug(¤t->thread, 2); + loaddebug(¤t->thread, 3); + /* no 4 and 5 */ + loaddebug(¤t->thread, 6); + loaddebug(¤t->thread, 7); +#endif + } + +} + /** * __restore_processor_state - restore the contents of CPU registers saved * by __save_processor_state() @@ -96,9 +179,16 @@ static void __restore_processor_state(struct saved_context *ctxt) /* * control registers */ + /* cr4 was introduced in the Pentium CPU */ +#ifdef CONFIG_X86_32 + if (ctxt->cr4) + write_cr4(ctxt->cr4); +#else +/* CONFIG X86_64 */ wrmsrl(MSR_EFER, ctxt->efer); write_cr8(ctxt->cr8); write_cr4(ctxt->cr4); +#endif write_cr3(ctxt->cr3); write_cr2(ctxt->cr2); write_cr0(ctxt->cr0); @@ -107,13 +197,31 @@ static void __restore_processor_state(struct saved_context *ctxt) * now restore the descriptor tables to their proper values * ltr is done i fix_processor_context(). */ +#ifdef CONFIG_X86_32 + load_gdt(&ctxt->gdt); + load_idt(&ctxt->idt); +#else +/* CONFIG_X86_64 */ load_gdt((const struct desc_ptr *)&ctxt->gdt_limit); load_idt((const struct desc_ptr *)&ctxt->idt_limit); - +#endif /* * segment registers */ +#ifdef CONFIG_X86_32 + loadsegment(es, ctxt->es); + loadsegment(fs, ctxt->fs); + loadsegment(gs, ctxt->gs); + loadsegment(ss, ctxt->ss); + + /* + * sysenter MSRs + */ + if (boot_cpu_has(X86_FEATURE_SEP)) + enable_sep_cpu(); +#else +/* CONFIG_X86_64 */ asm volatile ("movw %0, %%ds" :: "r" (ctxt->ds)); asm volatile ("movw %0, %%es" :: "r" (ctxt->es)); asm volatile ("movw %0, %%fs" :: "r" (ctxt->fs)); @@ -123,6 +231,7 @@ static void __restore_processor_state(struct saved_context *ctxt) wrmsrl(MSR_FS_BASE, ctxt->fs_base); wrmsrl(MSR_GS_BASE, ctxt->gs_base); wrmsrl(MSR_KERNEL_GS_BASE, ctxt->gs_kernel_base); +#endif /* * restore XCR0 for xsave capable cpu's. @@ -134,41 +243,17 @@ static void __restore_processor_state(struct saved_context *ctxt) do_fpu_end(); mtrr_ap_init(); + +#ifdef CONFIG_X86_32 + mcheck_init(&boot_cpu_data); +#endif } +/* Needed by apm.c */ void restore_processor_state(void) { __restore_processor_state(&saved_context); } - -static void fix_processor_context(void) -{ - int cpu = smp_processor_id(); - struct tss_struct *t = &per_cpu(init_tss, cpu); - - /* - * This just modifies memory; should not be necessary. But... This - * is necessary, because 386 hardware has concept of busy TSS or some - * similar stupidity. - */ - set_tss_desc(cpu, t); - - get_cpu_gdt_table(cpu)[GDT_ENTRY_TSS].type = 9; - - syscall_init(); /* This sets MSR_*STAR and related */ - load_TR_desc(); /* This does ltr */ - load_LDT(¤t->active_mm->context); /* This does lldt */ - - /* - * Now maybe reload the debug registers - */ - if (current->thread.debugreg7){ - loaddebug(¤t->thread, 0); - loaddebug(¤t->thread, 1); - loaddebug(¤t->thread, 2); - loaddebug(¤t->thread, 3); - /* no 4 and 5 */ - loaddebug(¤t->thread, 6); - loaddebug(¤t->thread, 7); - } -} +#ifdef CONFIG_X86_32 +EXPORT_SYMBOL(restore_processor_state); +#endif diff --git a/arch/x86/power/cpu_32.c b/arch/x86/power/cpu_32.c deleted file mode 100644 index ce702c5b3a2c..000000000000 --- a/arch/x86/power/cpu_32.c +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Suspend support specific for i386. - * - * Distribute under GPLv2 - * - * Copyright (c) 2002 Pavel Machek - * Copyright (c) 2001 Patrick Mochel - */ - -#include -#include -#include -#include -#include -#include - -static struct saved_context saved_context; - -unsigned long saved_context_ebx; -unsigned long saved_context_esp, saved_context_ebp; -unsigned long saved_context_esi, saved_context_edi; -unsigned long saved_context_eflags; - -static void __save_processor_state(struct saved_context *ctxt) -{ - mtrr_save_fixed_ranges(NULL); - kernel_fpu_begin(); - - /* - * descriptor tables - */ - store_gdt(&ctxt->gdt); - store_idt(&ctxt->idt); - store_tr(ctxt->tr); - - /* - * segment registers - */ - savesegment(es, ctxt->es); - savesegment(fs, ctxt->fs); - savesegment(gs, ctxt->gs); - savesegment(ss, ctxt->ss); - - /* - * control registers - */ - ctxt->cr0 = read_cr0(); - ctxt->cr2 = read_cr2(); - ctxt->cr3 = read_cr3(); - ctxt->cr4 = read_cr4_safe(); -} - -/* Needed by apm.c */ -void save_processor_state(void) -{ - __save_processor_state(&saved_context); -} -EXPORT_SYMBOL(save_processor_state); - -static void do_fpu_end(void) -{ - /* - * Restore FPU regs if necessary. - */ - kernel_fpu_end(); -} - -static void fix_processor_context(void) -{ - int cpu = smp_processor_id(); - struct tss_struct *t = &per_cpu(init_tss, cpu); - - set_tss_desc(cpu, t); /* - * This just modifies memory; should not be - * necessary. But... This is necessary, because - * 386 hardware has concept of busy TSS or some - * similar stupidity. - */ - - load_TR_desc(); /* This does ltr */ - load_LDT(¤t->active_mm->context); /* This does lldt */ - - /* - * Now maybe reload the debug registers - */ - if (current->thread.debugreg7) { - set_debugreg(current->thread.debugreg0, 0); - set_debugreg(current->thread.debugreg1, 1); - set_debugreg(current->thread.debugreg2, 2); - set_debugreg(current->thread.debugreg3, 3); - /* no 4 and 5 */ - set_debugreg(current->thread.debugreg6, 6); - set_debugreg(current->thread.debugreg7, 7); - } - -} - -static void __restore_processor_state(struct saved_context *ctxt) -{ - /* - * control registers - */ - /* cr4 was introduced in the Pentium CPU */ - if (ctxt->cr4) - write_cr4(ctxt->cr4); - write_cr3(ctxt->cr3); - write_cr2(ctxt->cr2); - write_cr0(ctxt->cr0); - - /* - * now restore the descriptor tables to their proper values - * ltr is done i fix_processor_context(). - */ - load_gdt(&ctxt->gdt); - load_idt(&ctxt->idt); - - /* - * segment registers - */ - loadsegment(es, ctxt->es); - loadsegment(fs, ctxt->fs); - loadsegment(gs, ctxt->gs); - loadsegment(ss, ctxt->ss); - - /* - * sysenter MSRs - */ - if (boot_cpu_has(X86_FEATURE_SEP)) - enable_sep_cpu(); - - /* - * restore XCR0 for xsave capable cpu's. - */ - if (cpu_has_xsave) - xsetbv(XCR_XFEATURE_ENABLED_MASK, pcntxt_mask); - - fix_processor_context(); - do_fpu_end(); - mtrr_ap_init(); - mcheck_init(&boot_cpu_data); -} - -/* Needed by apm.c */ -void restore_processor_state(void) -{ - __restore_processor_state(&saved_context); -} -EXPORT_SYMBOL(restore_processor_state); diff --git a/arch/x86/vdso/Makefile b/arch/x86/vdso/Makefile index 16a9020c8f11..88112b49f02c 100644 --- a/arch/x86/vdso/Makefile +++ b/arch/x86/vdso/Makefile @@ -123,6 +123,7 @@ quiet_cmd_vdso = VDSO $@ -Wl,-T,$(filter %.lds,$^) $(filter %.o,$^) VDSO_LDFLAGS = -fPIC -shared $(call ld-option, -Wl$(comma)--hash-style=sysv) +GCOV_PROFILE := n # # Install the unstripped copy of vdso*.so listed in $(vdso-install-y). diff --git a/arch/x86/vdso/vdso32-setup.c b/arch/x86/vdso/vdso32-setup.c index 1241f118ab56..58bc00f68b12 100644 --- a/arch/x86/vdso/vdso32-setup.c +++ b/arch/x86/vdso/vdso32-setup.c @@ -338,6 +338,8 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) } } + current->mm->context.vdso = (void *)addr; + if (compat_uses_vma || !compat) { /* * MAYWRITE to allow gdb to COW and set breakpoints @@ -358,11 +360,13 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) goto up_fail; } - current->mm->context.vdso = (void *)addr; current_thread_info()->sysenter_return = VDSO32_SYMBOL(addr, SYSENTER_RETURN); up_fail: + if (ret) + current->mm->context.vdso = NULL; + up_write(&mm->mmap_sem); return ret; diff --git a/arch/x86/vdso/vma.c b/arch/x86/vdso/vma.c index 7133cdf9098b..21e1aeb9f3ea 100644 --- a/arch/x86/vdso/vma.c +++ b/arch/x86/vdso/vma.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -115,15 +116,18 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) goto up_fail; } + current->mm->context.vdso = (void *)addr; + ret = install_special_mapping(mm, addr, vdso_size, VM_READ|VM_EXEC| VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC| VM_ALWAYSDUMP, vdso_pages); - if (ret) + if (ret) { + current->mm->context.vdso = NULL; goto up_fail; + } - current->mm->context.vdso = (void *)addr; up_fail: up_write(&mm->mmap_sem); return ret; diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index f09e8c36ee80..0a1700a2be9c 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -44,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -240,10 +242,10 @@ static unsigned long xen_get_debugreg(int reg) return HYPERVISOR_get_debugreg(reg); } -void xen_leave_lazy(void) +static void xen_end_context_switch(struct task_struct *next) { - paravirt_leave_lazy(paravirt_get_lazy_mode()); xen_mc_flush(); + paravirt_end_context_switch(next); } static unsigned long xen_store_tr(void) @@ -428,11 +430,44 @@ static void xen_write_ldt_entry(struct desc_struct *dt, int entrynum, static int cvt_gate_to_trap(int vector, const gate_desc *val, struct trap_info *info) { + unsigned long addr; + if (val->type != GATE_TRAP && val->type != GATE_INTERRUPT) return 0; info->vector = vector; - info->address = gate_offset(*val); + + addr = gate_offset(*val); +#ifdef CONFIG_X86_64 + /* + * Look for known traps using IST, and substitute them + * appropriately. The debugger ones are the only ones we care + * about. Xen will handle faults like double_fault and + * machine_check, so we should never see them. Warn if + * there's an unexpected IST-using fault handler. + */ + if (addr == (unsigned long)debug) + addr = (unsigned long)xen_debug; + else if (addr == (unsigned long)int3) + addr = (unsigned long)xen_int3; + else if (addr == (unsigned long)stack_segment) + addr = (unsigned long)xen_stack_segment; + else if (addr == (unsigned long)double_fault || + addr == (unsigned long)nmi) { + /* Don't need to handle these */ + return 0; +#ifdef CONFIG_X86_MCE + } else if (addr == (unsigned long)machine_check) { + return 0; +#endif + } else { + /* Some other trap using IST? */ + if (WARN_ON(val->ist != 0)) + return 0; + } +#endif /* CONFIG_X86_64 */ + info->address = addr; + info->cs = gate_segment(*val); info->flags = val->dpl; /* interrupt gates clear IF */ @@ -623,10 +658,26 @@ static void xen_clts(void) xen_mc_issue(PARAVIRT_LAZY_CPU); } +static DEFINE_PER_CPU(unsigned long, xen_cr0_value); + +static unsigned long xen_read_cr0(void) +{ + unsigned long cr0 = percpu_read(xen_cr0_value); + + if (unlikely(cr0 == 0)) { + cr0 = native_read_cr0(); + percpu_write(xen_cr0_value, cr0); + } + + return cr0; +} + static void xen_write_cr0(unsigned long cr0) { struct multicall_space mcs; + percpu_write(xen_cr0_value, cr0); + /* Only pay attention to cr0.TS; everything else is ignored. */ mcs = xen_mc_entry(0); @@ -812,7 +863,7 @@ static const struct pv_cpu_ops xen_cpu_ops __initdata = { .clts = xen_clts, - .read_cr0 = native_read_cr0, + .read_cr0 = xen_read_cr0, .write_cr0 = xen_write_cr0, .read_cr4 = native_read_cr4, @@ -860,10 +911,8 @@ static const struct pv_cpu_ops xen_cpu_ops __initdata = { /* 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, - }, + .start_context_switch = paravirt_start_context_switch, + .end_context_switch = xen_end_context_switch, }; static const struct pv_apic_ops xen_apic_ops __initdata = { diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c index fba55b1a4021..4ceb28581652 100644 --- a/arch/x86/xen/mmu.c +++ b/arch/x86/xen/mmu.c @@ -452,10 +452,6 @@ void set_pte_mfn(unsigned long vaddr, unsigned long mfn, pgprot_t flags) void xen_set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pteval) { - /* updates to init_mm may be done without lock */ - if (mm == &init_mm) - preempt_disable(); - ADD_STATS(set_pte_at, 1); // ADD_STATS(set_pte_at_pinned, xen_page_pinned(ptep)); ADD_STATS(set_pte_at_current, mm == current->mm); @@ -476,9 +472,7 @@ void xen_set_pte_at(struct mm_struct *mm, unsigned long addr, } xen_set_pte(ptep, pteval); -out: - if (mm == &init_mm) - preempt_enable(); +out: return; } pte_t xen_ptep_modify_prot_start(struct mm_struct *mm, @@ -1152,10 +1146,8 @@ static void drop_other_mm_ref(void *info) /* If this cpu still has a stale cr3 reference, then make sure it has been flushed. */ - if (percpu_read(xen_current_cr3) == __pa(mm->pgd)) { + if (percpu_read(xen_current_cr3) == __pa(mm->pgd)) load_cr3(swapper_pg_dir); - arch_flush_lazy_cpu_mode(); - } } static void xen_drop_mm_ref(struct mm_struct *mm) @@ -1168,7 +1160,6 @@ static void xen_drop_mm_ref(struct mm_struct *mm) load_cr3(swapper_pg_dir); else leave_mm(smp_processor_id()); - arch_flush_lazy_cpu_mode(); } /* Get the "official" set of cpus referring to our pagetable. */ @@ -1876,6 +1867,14 @@ __init void xen_post_allocator_init(void) xen_mark_init_mm_pinned(); } +static void xen_leave_lazy_mmu(void) +{ + preempt_disable(); + xen_mc_flush(); + paravirt_leave_lazy_mmu(); + preempt_enable(); +} + const struct pv_mmu_ops xen_mmu_ops __initdata = { .pagetable_setup_start = xen_pagetable_setup_start, .pagetable_setup_done = xen_pagetable_setup_done, @@ -1949,7 +1948,7 @@ const struct pv_mmu_ops xen_mmu_ops __initdata = { .lazy_mode = { .enter = paravirt_enter_lazy_mmu, - .leave = xen_leave_lazy, + .leave = xen_leave_lazy_mmu, }, .set_fixmap = xen_set_fixmap, diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c index 15c6c68db6a2..ad0047f47cd4 100644 --- a/arch/x86/xen/setup.c +++ b/arch/x86/xen/setup.c @@ -61,9 +61,9 @@ char * __init xen_memory_setup(void) * - xen_start_info * See comment above "struct start_info" in */ - e820_add_region(__pa(xen_start_info->mfn_list), - xen_start_info->pt_base - xen_start_info->mfn_list, - E820_RESERVED); + reserve_early(__pa(xen_start_info->mfn_list), + __pa(xen_start_info->pt_base), + "XEN START INFO"); sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map); diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h index ca6596b05d53..22494fd4c9b5 100644 --- a/arch/x86/xen/xen-ops.h +++ b/arch/x86/xen/xen-ops.h @@ -30,7 +30,6 @@ pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd, unsigned long max_pfn); void xen_ident_map_ISA(void); void xen_reserve_top(void); -void xen_leave_lazy(void); void xen_post_allocator_init(void); char * __init xen_memory_setup(void); diff --git a/arch/xtensa/configs/s6105_defconfig b/arch/xtensa/configs/s6105_defconfig index 768bee006037..bb84fbc9921f 100644 --- a/arch/xtensa/configs/s6105_defconfig +++ b/arch/xtensa/configs/s6105_defconfig @@ -263,7 +263,54 @@ CONFIG_HAVE_IDE=y # CONFIG_SCSI_NETLINK is not set # CONFIG_ATA is not set # CONFIG_MD is not set -# CONFIG_NETDEVICES is not set +CONFIG_NETDEVICES=y +# 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_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_MARVELL_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_VITESSE_PHY is not set +CONFIG_SMSC_PHY=y +# CONFIG_BROADCOM_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_FIXED_PHY is not set +# CONFIG_MDIO_BITBANG is not set +# CONFIG_NET_ETHERNET is not set +CONFIG_NETDEV_1000=y +CONFIG_S6GMAC=y +# CONFIG_NETDEV_10000 is not set + +# +# Wireless LAN +# +# CONFIG_WLAN_PRE80211 is not set +# CONFIG_WLAN_80211 is not set +# CONFIG_IWLWIFI_LEDS is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +# CONFIG_WAN is not set +# CONFIG_PPP is not set +# CONFIG_SLIP 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 @@ -304,8 +351,6 @@ CONFIG_UNIX98_PTYS=y # CONFIG_LEGACY_PTYS is not set # CONFIG_IPMI_HANDLER is not set # CONFIG_HW_RANDOM is not set -# CONFIG_RTC is not set -# CONFIG_GEN_RTC is not set # CONFIG_R3964 is not set # CONFIG_RAW_DRIVER is not set # CONFIG_TCG_TPM is not set @@ -387,7 +432,59 @@ CONFIG_SSB_POSSIBLE=y # CONFIG_MEMSTICK is not set # CONFIG_NEW_LEDS is not set # CONFIG_ACCESSIBILITY is not set -# CONFIG_RTC_CLASS is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +# CONFIG_RTC_INTF_SYSFS is not set +# CONFIG_RTC_INTF_PROC is not set +# CONFIG_RTC_INTF_DEV is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +CONFIG_RTC_DRV_M41T80=y +# CONFIG_RTC_DRV_M41T80_WDT is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8581 is not set + +# +# SPI RTC drivers +# + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_V3020 is not set + +# +# on-CPU RTC drivers +# # CONFIG_DMADEVICES is not set # CONFIG_UIO is not set # CONFIG_STAGING is not set diff --git a/arch/xtensa/include/asm/atomic.h b/arch/xtensa/include/asm/atomic.h index 67ad67bed8c1..22d6dde42619 100644 --- a/arch/xtensa/include/asm/atomic.h +++ b/arch/xtensa/include/asm/atomic.h @@ -292,7 +292,7 @@ static inline void atomic_set_mask(unsigned int mask, atomic_t *v) #define smp_mb__before_atomic_inc() barrier() #define smp_mb__after_atomic_inc() barrier() -#include +#include #endif /* __KERNEL__ */ #endif /* _XTENSA_ATOMIC_H */ diff --git a/arch/xtensa/include/asm/bitsperlong.h b/arch/xtensa/include/asm/bitsperlong.h new file mode 100644 index 000000000000..6dc0bb0c13b2 --- /dev/null +++ b/arch/xtensa/include/asm/bitsperlong.h @@ -0,0 +1 @@ +#include diff --git a/arch/xtensa/include/asm/cacheflush.h b/arch/xtensa/include/asm/cacheflush.h index 8fc1c0c8de07..b7b8fbe47c77 100644 --- a/arch/xtensa/include/asm/cacheflush.h +++ b/arch/xtensa/include/asm/cacheflush.h @@ -155,5 +155,100 @@ extern void copy_from_user_page(struct vm_area_struct*, struct page*, #endif +#define XTENSA_CACHEBLK_LOG2 29 +#define XTENSA_CACHEBLK_SIZE (1 << XTENSA_CACHEBLK_LOG2) +#define XTENSA_CACHEBLK_MASK (7 << XTENSA_CACHEBLK_LOG2) + +#if XCHAL_HAVE_CACHEATTR +static inline u32 xtensa_get_cacheattr(void) +{ + u32 r; + asm volatile(" rsr %0, CACHEATTR" : "=a"(r)); + return r; +} + +static inline u32 xtensa_get_dtlb1(u32 addr) +{ + u32 r = addr & XTENSA_CACHEBLK_MASK; + return r | ((xtensa_get_cacheattr() >> (r >> (XTENSA_CACHEBLK_LOG2-2))) + & 0xF); +} +#else +static inline u32 xtensa_get_dtlb1(u32 addr) +{ + u32 r; + asm volatile(" rdtlb1 %0, %1" : "=a"(r) : "a"(addr)); + asm volatile(" dsync"); + return r; +} + +static inline u32 xtensa_get_cacheattr(void) +{ + u32 r = 0; + u32 a = 0; + do { + a -= XTENSA_CACHEBLK_SIZE; + r = (r << 4) | (xtensa_get_dtlb1(a) & 0xF); + } while (a); + return r; +} +#endif + +static inline int xtensa_need_flush_dma_source(u32 addr) +{ + return (xtensa_get_dtlb1(addr) & ((1 << XCHAL_CA_BITS) - 1)) >= 4; +} + +static inline int xtensa_need_invalidate_dma_destination(u32 addr) +{ + return (xtensa_get_dtlb1(addr) & ((1 << XCHAL_CA_BITS) - 1)) != 2; +} + +static inline void flush_dcache_unaligned(u32 addr, u32 size) +{ + u32 cnt; + if (size) { + cnt = (size + ((XCHAL_DCACHE_LINESIZE - 1) & addr) + + XCHAL_DCACHE_LINESIZE - 1) / XCHAL_DCACHE_LINESIZE; + while (cnt--) { + asm volatile(" dhwb %0, 0" : : "a"(addr)); + addr += XCHAL_DCACHE_LINESIZE; + } + asm volatile(" dsync"); + } +} + +static inline void invalidate_dcache_unaligned(u32 addr, u32 size) +{ + int cnt; + if (size) { + asm volatile(" dhwbi %0, 0 ;" : : "a"(addr)); + cnt = (size + ((XCHAL_DCACHE_LINESIZE - 1) & addr) + - XCHAL_DCACHE_LINESIZE - 1) / XCHAL_DCACHE_LINESIZE; + while (cnt-- > 0) { + asm volatile(" dhi %0, %1" : : "a"(addr), + "n"(XCHAL_DCACHE_LINESIZE)); + addr += XCHAL_DCACHE_LINESIZE; + } + asm volatile(" dhwbi %0, %1" : : "a"(addr), + "n"(XCHAL_DCACHE_LINESIZE)); + asm volatile(" dsync"); + } +} + +static inline void flush_invalidate_dcache_unaligned(u32 addr, u32 size) +{ + u32 cnt; + if (size) { + cnt = (size + ((XCHAL_DCACHE_LINESIZE - 1) & addr) + + XCHAL_DCACHE_LINESIZE - 1) / XCHAL_DCACHE_LINESIZE; + while (cnt--) { + asm volatile(" dhwbi %0, 0" : : "a"(addr)); + addr += XCHAL_DCACHE_LINESIZE; + } + asm volatile(" dsync"); + } +} + #endif /* __KERNEL__ */ #endif /* _XTENSA_CACHEFLUSH_H */ diff --git a/arch/xtensa/include/asm/gpio.h b/arch/xtensa/include/asm/gpio.h index 0763b0763960..a8c9fc46c790 100644 --- a/arch/xtensa/include/asm/gpio.h +++ b/arch/xtensa/include/asm/gpio.h @@ -38,14 +38,14 @@ static inline int gpio_cansleep(unsigned int gpio) return __gpio_cansleep(gpio); } +static inline int gpio_to_irq(unsigned int gpio) +{ + return __gpio_to_irq(gpio); +} + /* * Not implemented, yet. */ -static inline int gpio_to_irq(unsigned int gpio) -{ - return -ENOSYS; -} - static inline int irq_to_gpio(unsigned int irq) { return -EINVAL; diff --git a/arch/xtensa/include/asm/irq.h b/arch/xtensa/include/asm/irq.h index dfac82dc52ad..4c0ccc9c4f4c 100644 --- a/arch/xtensa/include/asm/irq.h +++ b/arch/xtensa/include/asm/irq.h @@ -11,6 +11,7 @@ #ifndef _XTENSA_IRQ_H #define _XTENSA_IRQ_H +#include #include #include @@ -21,11 +22,20 @@ static inline void variant_irq_enable(unsigned int irq) { } static inline void variant_irq_disable(unsigned int irq) { } #endif +#ifndef VARIANT_NR_IRQS +# define VARIANT_NR_IRQS 0 +#endif #ifndef PLATFORM_NR_IRQS # define PLATFORM_NR_IRQS 0 #endif #define XTENSA_NR_IRQS XCHAL_NUM_INTERRUPTS -#define NR_IRQS (XTENSA_NR_IRQS + PLATFORM_NR_IRQS) +#define NR_IRQS (XTENSA_NR_IRQS + VARIANT_NR_IRQS + PLATFORM_NR_IRQS) + +#if VARIANT_NR_IRQS == 0 +static inline void variant_init_irq(void) { } +#else +void variant_init_irq(void) __init; +#endif static __inline__ int irq_canonicalize(int irq) { diff --git a/arch/xtensa/include/asm/kmap_types.h b/arch/xtensa/include/asm/kmap_types.h index 9e822d2e3bce..11c687e527f1 100644 --- a/arch/xtensa/include/asm/kmap_types.h +++ b/arch/xtensa/include/asm/kmap_types.h @@ -1,31 +1,6 @@ -/* - * include/asm-xtensa/kmap_types.h - * - * 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) 2001 - 2005 Tensilica Inc. - */ - #ifndef _XTENSA_KMAP_TYPES_H #define _XTENSA_KMAP_TYPES_H -enum km_type { - KM_BOUNCE_READ, - KM_SKB_SUNRPC_DATA, - KM_SKB_DATA_SOFTIRQ, - KM_USER0, - KM_USER1, - KM_BIO_SRC_IRQ, - KM_BIO_DST_IRQ, - KM_PTE0, - KM_PTE1, - KM_IRQ0, - KM_IRQ1, - KM_SOFTIRQ0, - KM_SOFTIRQ1, - KM_TYPE_NR -}; +#include #endif /* _XTENSA_KMAP_TYPES_H */ diff --git a/arch/xtensa/include/asm/page.h b/arch/xtensa/include/asm/page.h index 17e0c5383b10..161bb89e98c8 100644 --- a/arch/xtensa/include/asm/page.h +++ b/arch/xtensa/include/asm/page.h @@ -129,7 +129,7 @@ static inline __attribute_const__ int get_order(unsigned long size) #else -# include +# include #endif diff --git a/arch/xtensa/kernel/init_task.c b/arch/xtensa/kernel/init_task.c index e07f5c9fcd35..c4302f0e4ba0 100644 --- a/arch/xtensa/kernel/init_task.c +++ b/arch/xtensa/kernel/init_task.c @@ -23,10 +23,6 @@ static struct signal_struct init_signals = INIT_SIGNALS(init_signals); static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); -struct mm_struct init_mm = INIT_MM(init_mm); - -EXPORT_SYMBOL(init_mm); - union thread_union init_thread_union __attribute__((__section__(".data.init_task"))) = { INIT_THREAD_INFO(init_task) }; diff --git a/arch/xtensa/kernel/irq.c b/arch/xtensa/kernel/irq.c index a36c85edd045..a1badb32fcda 100644 --- a/arch/xtensa/kernel/irq.c +++ b/arch/xtensa/kernel/irq.c @@ -197,4 +197,6 @@ void __init init_IRQ(void) } cached_irq_mask = 0; + + variant_init_irq(); } diff --git a/arch/xtensa/kernel/module.c b/arch/xtensa/kernel/module.c index 3981a466c779..c1accea8cb56 100644 --- a/arch/xtensa/kernel/module.c +++ b/arch/xtensa/kernel/module.c @@ -34,8 +34,6 @@ void *module_alloc(unsigned long size) void module_free(struct module *mod, void *module_region) { vfree(module_region); - /* FIXME: If module_region == mod->init_region, trim exception - table entries. */ } int module_frob_arch_sections(Elf32_Ehdr *hdr, diff --git a/arch/xtensa/kernel/process.c b/arch/xtensa/kernel/process.c index 031f36685710..e1a04a346e75 100644 --- a/arch/xtensa/kernel/process.c +++ b/arch/xtensa/kernel/process.c @@ -331,11 +331,6 @@ long xtensa_execve(char __user *name, char __user * __user *argv, if (IS_ERR(filename)) goto out; error = do_execve(filename, argv, envp, regs); - if (error == 0) { - task_lock(current); - current->ptrace &= ~PT_DTRACE; - task_unlock(current); - } putname(filename); out: return error; diff --git a/arch/xtensa/mm/fault.c b/arch/xtensa/mm/fault.c index bdd860d93f72..bc0733359a88 100644 --- a/arch/xtensa/mm/fault.c +++ b/arch/xtensa/mm/fault.c @@ -106,7 +106,7 @@ good_area: * the fault. */ survive: - fault = handle_mm_fault(mm, vma, address, is_write); + fault = handle_mm_fault(mm, vma, address, is_write ? FAULT_FLAG_WRITE : 0); if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; diff --git a/arch/xtensa/platforms/s6105/device.c b/arch/xtensa/platforms/s6105/device.c index 78b08be5a92d..65333ffefb07 100644 --- a/arch/xtensa/platforms/s6105/device.c +++ b/arch/xtensa/platforms/s6105/device.c @@ -5,14 +5,27 @@ */ #include +#include #include +#include +#include #include #include #include #include +#include +#include + +#define GPIO3_INTNUM 3 #define UART_INTNUM 4 +#define GMAC_INTNUM 5 + +static const signed char gpio3_irq_mappings[] = { + S6_INTC_GPIO(3), + -1 +}; static const signed char uart_irq_mappings[] = { S6_INTC_UART(0), @@ -20,8 +33,18 @@ static const signed char uart_irq_mappings[] = { -1, }; +static const signed char gmac_irq_mappings[] = { + S6_INTC_GMAC_STAT, + S6_INTC_GMAC_ERR, + S6_INTC_DMA_HOSTTERMCNT(0), + S6_INTC_DMA_HOSTTERMCNT(1), + -1 +}; + const signed char *platform_irq_mappings[NR_IRQS] = { + [GPIO3_INTNUM] = gpio3_irq_mappings, [UART_INTNUM] = uart_irq_mappings, + [GMAC_INTNUM] = gmac_irq_mappings, }; static struct plat_serial8250_port serial_platform_data[] = { @@ -46,6 +69,66 @@ static struct plat_serial8250_port serial_platform_data[] = { { }, }; +static struct resource s6_gmac_resource[] = { + { + .name = "mem", + .start = (resource_size_t)S6_REG_GMAC, + .end = (resource_size_t)S6_REG_GMAC + 0x10000 - 1, + .flags = IORESOURCE_MEM, + }, + { + .name = "dma", + .start = (resource_size_t) + DMA_CHNL(S6_REG_HIFDMA, S6_HIFDMA_GMACTX), + .end = (resource_size_t) + DMA_CHNL(S6_REG_HIFDMA, S6_HIFDMA_GMACTX) + 0x100 - 1, + .flags = IORESOURCE_DMA, + }, + { + .name = "dma", + .start = (resource_size_t) + DMA_CHNL(S6_REG_HIFDMA, S6_HIFDMA_GMACRX), + .end = (resource_size_t) + DMA_CHNL(S6_REG_HIFDMA, S6_HIFDMA_GMACRX) + 0x100 - 1, + .flags = IORESOURCE_DMA, + }, + { + .name = "io", + .start = (resource_size_t)S6_MEM_GMAC, + .end = (resource_size_t)S6_MEM_GMAC + 0x2000000 - 1, + .flags = IORESOURCE_IO, + }, + { + .name = "irq", + .start = (resource_size_t)GMAC_INTNUM, + .flags = IORESOURCE_IRQ, + }, + { + .name = "irq", + .start = (resource_size_t)PHY_POLL, + .flags = IORESOURCE_IRQ, + }, +}; + +static int __init prepare_phy_irq(int pin) +{ + int irq; + if (gpio_request(pin, "s6gmac_phy") < 0) + goto fail; + if (gpio_direction_input(pin) < 0) + goto free; + irq = gpio_to_irq(pin); + if (irq < 0) + goto free; + if (set_irq_type(irq, IRQ_TYPE_LEVEL_LOW) < 0) + goto free; + return irq; +free: + gpio_free(pin); +fail: + return PHY_POLL; +} + static struct platform_device platform_devices[] = { { .name = "serial8250", @@ -54,12 +137,23 @@ static struct platform_device platform_devices[] = { .platform_data = serial_platform_data, }, }, + { + .name = "s6gmac", + .id = 0, + .resource = s6_gmac_resource, + .num_resources = ARRAY_SIZE(s6_gmac_resource), + }, + { + I2C_BOARD_INFO("m41t62", S6I2C_ADDR_M41T62), + }, }; static int __init device_init(void) { int i; + s6_gmac_resource[5].start = prepare_phy_irq(GPIO_PHY_IRQ); + for (i = 0; i < ARRAY_SIZE(platform_devices); i++) platform_device_register(&platform_devices[i]); return 0; diff --git a/arch/xtensa/platforms/s6105/setup.c b/arch/xtensa/platforms/s6105/setup.c index 855ddeadc43d..86ce730f7913 100644 --- a/arch/xtensa/platforms/s6105/setup.c +++ b/arch/xtensa/platforms/s6105/setup.c @@ -35,12 +35,21 @@ void __init platform_setup(char **cmdline) { unsigned long reg; + reg = readl(S6_REG_GREG1 + S6_GREG1_PLLSEL); + reg &= ~(S6_GREG1_PLLSEL_GMAC_MASK << S6_GREG1_PLLSEL_GMAC | + S6_GREG1_PLLSEL_GMII_MASK << S6_GREG1_PLLSEL_GMII); + reg |= S6_GREG1_PLLSEL_GMAC_125MHZ << S6_GREG1_PLLSEL_GMAC | + S6_GREG1_PLLSEL_GMII_125MHZ << S6_GREG1_PLLSEL_GMII; + writel(reg, S6_REG_GREG1 + S6_GREG1_PLLSEL); + reg = readl(S6_REG_GREG1 + S6_GREG1_CLKGATE); reg &= ~(1 << S6_GREG1_BLOCK_SB); + reg &= ~(1 << S6_GREG1_BLOCK_GMAC); writel(reg, S6_REG_GREG1 + S6_GREG1_CLKGATE); reg = readl(S6_REG_GREG1 + S6_GREG1_BLOCKENA); reg |= 1 << S6_GREG1_BLOCK_SB; + reg |= 1 << S6_GREG1_BLOCK_GMAC; writel(reg, S6_REG_GREG1 + S6_GREG1_BLOCKENA); printk(KERN_NOTICE "S6105 on Stretch S6000 - " @@ -49,7 +58,7 @@ void __init platform_setup(char **cmdline) void __init platform_init(bp_tag_t *first) { - s6_gpio_init(); + s6_gpio_init(0); gpio_request(GPIO_LED1_NGREEN, "led1_green"); gpio_request(GPIO_LED1_RED, "led1_red"); gpio_direction_output(GPIO_LED1_NGREEN, 1); diff --git a/arch/xtensa/variants/s6000/Makefile b/arch/xtensa/variants/s6000/Makefile index d83f3805130c..3e7ef0a0c498 100644 --- a/arch/xtensa/variants/s6000/Makefile +++ b/arch/xtensa/variants/s6000/Makefile @@ -1,4 +1,4 @@ # s6000 Makefile -obj-y += irq.o gpio.o +obj-y += irq.o gpio.o dmac.o obj-$(CONFIG_XTENSA_CALIBRATE_CCOUNT) += delay.o diff --git a/arch/xtensa/variants/s6000/dmac.c b/arch/xtensa/variants/s6000/dmac.c new file mode 100644 index 000000000000..dc7f7c573518 --- /dev/null +++ b/arch/xtensa/variants/s6000/dmac.c @@ -0,0 +1,173 @@ +/* + * Authors: Oskar Schirmer + * Daniel Gloeckner + * (c) 2008 emlix GmbH http://www.emlix.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 +#include +#include +#include +#include +#include +#include + +/* DMA engine lookup */ + +struct s6dmac_ctrl s6dmac_ctrl[S6_DMAC_NB]; + + +/* DMA control, per engine */ + +void s6dmac_put_fifo_cache(u32 dmac, int chan, u32 src, u32 dst, u32 size) +{ + if (xtensa_need_flush_dma_source(src)) { + u32 base = src; + u32 span = size; + u32 chunk = readl(DMA_CHNL(dmac, chan) + S6_DMA_CMONCHUNK); + if (chunk && (size > chunk)) { + s32 skip = + readl(DMA_CHNL(dmac, chan) + S6_DMA_SRCSKIP); + u32 gaps = (size+chunk-1)/chunk - 1; + if (skip >= 0) { + span += gaps * skip; + } else if (-skip > chunk) { + s32 decr = gaps * (chunk + skip); + base += decr; + span = chunk - decr; + } else { + span = max(span + gaps * skip, + (chunk + skip) * gaps - skip); + } + } + flush_dcache_unaligned(base, span); + } + if (xtensa_need_invalidate_dma_destination(dst)) { + u32 base = dst; + u32 span = size; + u32 chunk = readl(DMA_CHNL(dmac, chan) + S6_DMA_CMONCHUNK); + if (chunk && (size > chunk)) { + s32 skip = + readl(DMA_CHNL(dmac, chan) + S6_DMA_DSTSKIP); + u32 gaps = (size+chunk-1)/chunk - 1; + if (skip >= 0) { + span += gaps * skip; + } else if (-skip > chunk) { + s32 decr = gaps * (chunk + skip); + base += decr; + span = chunk - decr; + } else { + span = max(span + gaps * skip, + (chunk + skip) * gaps - skip); + } + } + invalidate_dcache_unaligned(base, span); + } + s6dmac_put_fifo(dmac, chan, src, dst, size); +} + +void s6dmac_disable_error_irqs(u32 dmac, u32 mask) +{ + unsigned long flags; + spinlock_t *spinl = &s6dmac_ctrl[_dmac_addr_index(dmac)].lock; + spin_lock_irqsave(spinl, flags); + _s6dmac_disable_error_irqs(dmac, mask); + spin_unlock_irqrestore(spinl, flags); +} + +u32 s6dmac_int_sources(u32 dmac, u32 channel) +{ + u32 mask, ret, tmp; + mask = 1 << channel; + + tmp = readl(dmac + S6_DMA_TERMCNTIRQSTAT); + tmp &= mask; + writel(tmp, dmac + S6_DMA_TERMCNTIRQCLR); + ret = tmp >> channel; + + tmp = readl(dmac + S6_DMA_PENDCNTIRQSTAT); + tmp &= mask; + writel(tmp, dmac + S6_DMA_PENDCNTIRQCLR); + ret |= (tmp >> channel) << 1; + + tmp = readl(dmac + S6_DMA_LOWWMRKIRQSTAT); + tmp &= mask; + writel(tmp, dmac + S6_DMA_LOWWMRKIRQCLR); + ret |= (tmp >> channel) << 2; + + tmp = readl(dmac + S6_DMA_INTRAW0); + tmp &= (mask << S6_DMA_INT0_OVER) | (mask << S6_DMA_INT0_UNDER); + writel(tmp, dmac + S6_DMA_INTCLEAR0); + + if (tmp & (mask << S6_DMA_INT0_UNDER)) + ret |= 1 << 3; + if (tmp & (mask << S6_DMA_INT0_OVER)) + ret |= 1 << 4; + + tmp = readl(dmac + S6_DMA_MASTERERRINFO); + mask <<= S6_DMA_INT1_CHANNEL; + if (((tmp >> S6_DMA_MASTERERR_CHAN(0)) & S6_DMA_MASTERERR_CHAN_MASK) + == channel) + mask |= 1 << S6_DMA_INT1_MASTER; + if (((tmp >> S6_DMA_MASTERERR_CHAN(1)) & S6_DMA_MASTERERR_CHAN_MASK) + == channel) + mask |= 1 << (S6_DMA_INT1_MASTER + 1); + if (((tmp >> S6_DMA_MASTERERR_CHAN(2)) & S6_DMA_MASTERERR_CHAN_MASK) + == channel) + mask |= 1 << (S6_DMA_INT1_MASTER + 2); + + tmp = readl(dmac + S6_DMA_INTRAW1) & mask; + writel(tmp, dmac + S6_DMA_INTCLEAR1); + ret |= ((tmp >> channel) & 1) << 5; + ret |= ((tmp >> S6_DMA_INT1_MASTER) & S6_DMA_INT1_MASTER_MASK) << 6; + + return ret; +} + +void s6dmac_release_chan(u32 dmac, int chan) +{ + if (chan >= 0) + s6dmac_disable_chan(dmac, chan); +} + + +/* global init */ + +static inline void __init dmac_init(u32 dmac, u8 chan_nb) +{ + s6dmac_ctrl[S6_DMAC_INDEX(dmac)].dmac = dmac; + spin_lock_init(&s6dmac_ctrl[S6_DMAC_INDEX(dmac)].lock); + s6dmac_ctrl[S6_DMAC_INDEX(dmac)].chan_nb = chan_nb; + writel(S6_DMA_INT1_MASTER_MASK << S6_DMA_INT1_MASTER, + dmac + S6_DMA_INTCLEAR1); +} + +static inline void __init dmac_master(u32 dmac, + u32 m0start, u32 m0end, u32 m1start, u32 m1end) +{ + writel(m0start, dmac + S6_DMA_MASTER0START); + writel(m0end - 1, dmac + S6_DMA_MASTER0END); + writel(m1start, dmac + S6_DMA_MASTER1START); + writel(m1end - 1, dmac + S6_DMA_MASTER1END); +} + +static void __init s6_dmac_init(void) +{ + dmac_init(S6_REG_LMSDMA, S6_LMSDMA_NB); + dmac_master(S6_REG_LMSDMA, + S6_MEM_DDR, S6_MEM_PCIE_APER, S6_MEM_EFI, S6_MEM_GMAC); + dmac_init(S6_REG_NIDMA, S6_NIDMA_NB); + dmac_init(S6_REG_DPDMA, S6_DPDMA_NB); + dmac_master(S6_REG_DPDMA, + S6_MEM_DDR, S6_MEM_PCIE_APER, S6_REG_DP, S6_REG_DPDMA); + dmac_init(S6_REG_HIFDMA, S6_HIFDMA_NB); + dmac_master(S6_REG_HIFDMA, + S6_MEM_GMAC, S6_MEM_PCIE_CFG, S6_MEM_PCIE_APER, S6_MEM_AUX); +} + +arch_initcall(s6_dmac_init); diff --git a/arch/xtensa/variants/s6000/gpio.c b/arch/xtensa/variants/s6000/gpio.c index 79317fdcf14c..380a70fff756 100644 --- a/arch/xtensa/variants/s6000/gpio.c +++ b/arch/xtensa/variants/s6000/gpio.c @@ -4,15 +4,20 @@ * Copyright (c) 2009 emlix GmbH * Authors: Oskar Schirmer * Johannes Weiner + * Daniel Gloeckner */ +#include #include #include #include #include +#include #include #include +#define IRQ_BASE XTENSA_NR_IRQS + #define S6_GPIO_DATA 0x000 #define S6_GPIO_IS 0x404 #define S6_GPIO_IBE 0x408 @@ -52,19 +57,175 @@ static void set(struct gpio_chip *chip, unsigned int off, int val) writeb(val ? ~0 : 0, S6_REG_GPIO + S6_GPIO_DATA + S6_GPIO_OFFSET(off)); } +static int to_irq(struct gpio_chip *chip, unsigned offset) +{ + if (offset < 8) + return offset + IRQ_BASE; + return -EINVAL; +} + static struct gpio_chip gpiochip = { .owner = THIS_MODULE, .direction_input = direction_input, .get = get, .direction_output = direction_output, .set = set, + .to_irq = to_irq, .base = 0, .ngpio = 24, .can_sleep = 0, /* no blocking io needed */ .exported = 0, /* no exporting to userspace */ }; -int s6_gpio_init(void) +int s6_gpio_init(u32 afsel) { + writeb(afsel, S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_AFSEL); + writeb(afsel >> 8, S6_REG_GPIO + S6_GPIO_BANK(1) + S6_GPIO_AFSEL); + writeb(afsel >> 16, S6_REG_GPIO + S6_GPIO_BANK(2) + S6_GPIO_AFSEL); return gpiochip_add(&gpiochip); } + +static void ack(unsigned int irq) +{ + writeb(1 << (irq - IRQ_BASE), S6_REG_GPIO + S6_GPIO_IC); +} + +static void mask(unsigned int irq) +{ + u8 r = readb(S6_REG_GPIO + S6_GPIO_IE); + r &= ~(1 << (irq - IRQ_BASE)); + writeb(r, S6_REG_GPIO + S6_GPIO_IE); +} + +static void unmask(unsigned int irq) +{ + u8 m = readb(S6_REG_GPIO + S6_GPIO_IE); + m |= 1 << (irq - IRQ_BASE); + writeb(m, S6_REG_GPIO + S6_GPIO_IE); +} + +static int set_type(unsigned int irq, unsigned int type) +{ + const u8 m = 1 << (irq - IRQ_BASE); + irq_flow_handler_t handler; + struct irq_desc *desc; + u8 reg; + + if (type == IRQ_TYPE_PROBE) { + if ((readb(S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_AFSEL) & m) + || (readb(S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_IE) & m) + || readb(S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_DIR + + S6_GPIO_MASK(irq - IRQ_BASE))) + return 0; + type = IRQ_TYPE_EDGE_BOTH; + } + + reg = readb(S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_IS); + if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) { + reg |= m; + handler = handle_level_irq; + } else { + reg &= ~m; + handler = handle_edge_irq; + } + writeb(reg, S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_IS); + desc = irq_to_desc(irq); + desc->handle_irq = handler; + + reg = readb(S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_IEV); + if (type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_EDGE_RISING)) + reg |= m; + else + reg &= ~m; + writeb(reg, S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_IEV); + + reg = readb(S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_IBE); + if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) + reg |= m; + else + reg &= ~m; + writeb(reg, S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_IBE); + return 0; +} + +static struct irq_chip gpioirqs = { + .name = "GPIO", + .ack = ack, + .mask = mask, + .unmask = unmask, + .set_type = set_type, +}; + +static u8 demux_masks[4]; + +static void demux_irqs(unsigned int irq, struct irq_desc *desc) +{ + u8 *mask = get_irq_desc_data(desc); + u8 pending; + int cirq; + + desc->chip->mask(irq); + desc->chip->ack(irq); + pending = readb(S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_MIS) & *mask; + cirq = IRQ_BASE - 1; + while (pending) { + int n = ffs(pending); + cirq += n; + pending >>= n; + generic_handle_irq(cirq); + } + desc->chip->unmask(irq); +} + +extern const signed char *platform_irq_mappings[XTENSA_NR_IRQS]; + +void __init variant_init_irq(void) +{ + int irq, n; + writeb(0, S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_IE); + for (irq = n = 0; irq < XTENSA_NR_IRQS; irq++) { + const signed char *mapping = platform_irq_mappings[irq]; + int alone = 1; + u8 mask; + if (!mapping) + continue; + for(mask = 0; *mapping != -1; mapping++) + switch (*mapping) { + case S6_INTC_GPIO(0): + mask |= 1 << 0; + break; + case S6_INTC_GPIO(1): + mask |= 1 << 1; + break; + case S6_INTC_GPIO(2): + mask |= 1 << 2; + break; + case S6_INTC_GPIO(3): + mask |= 0x1f << 3; + break; + default: + alone = 0; + } + if (mask) { + int cirq, i; + if (!alone) { + printk(KERN_ERR "chained irq chips can't share" + " parent irq %i\n", irq); + continue; + } + demux_masks[n] = mask; + cirq = IRQ_BASE - 1; + do { + i = ffs(mask); + cirq += i; + mask >>= i; + set_irq_chip(cirq, &gpioirqs); + set_irq_type(irq, IRQ_TYPE_LEVEL_LOW); + } while (mask); + set_irq_data(irq, demux_masks + n); + set_irq_chained_handler(irq, demux_irqs); + if (++n == ARRAY_SIZE(demux_masks)) + break; + } + } +} diff --git a/arch/xtensa/variants/s6000/include/variant/dmac.h b/arch/xtensa/variants/s6000/include/variant/dmac.h new file mode 100644 index 000000000000..89ab9484fb71 --- /dev/null +++ b/arch/xtensa/variants/s6000/include/variant/dmac.h @@ -0,0 +1,387 @@ +/* + * include/asm-xtensa/variant-s6000/dmac.h + * + * 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) 2006 Tensilica Inc. + * Copyright (C) 2008 Emlix GmbH + * Authors: Fabian Godehardt + * Oskar Schirmer + * Daniel Gloeckner + */ + +#ifndef __ASM_XTENSA_S6000_DMAC_H +#define __ASM_XTENSA_S6000_DMAC_H +#include +#include + +/* DMA global */ + +#define S6_DMA_INTSTAT0 0x000 +#define S6_DMA_INTSTAT1 0x004 +#define S6_DMA_INTENABLE0 0x008 +#define S6_DMA_INTENABLE1 0x00C +#define S6_DMA_INTRAW0 0x010 +#define S6_DMA_INTRAW1 0x014 +#define S6_DMA_INTCLEAR0 0x018 +#define S6_DMA_INTCLEAR1 0x01C +#define S6_DMA_INTSET0 0x020 +#define S6_DMA_INTSET1 0x024 +#define S6_DMA_INT0_UNDER 0 +#define S6_DMA_INT0_OVER 16 +#define S6_DMA_INT1_CHANNEL 0 +#define S6_DMA_INT1_MASTER 16 +#define S6_DMA_INT1_MASTER_MASK 7 +#define S6_DMA_TERMCNTIRQSTAT 0x028 +#define S6_DMA_TERMCNTIRQCLR 0x02C +#define S6_DMA_TERMCNTIRQSET 0x030 +#define S6_DMA_PENDCNTIRQSTAT 0x034 +#define S6_DMA_PENDCNTIRQCLR 0x038 +#define S6_DMA_PENDCNTIRQSET 0x03C +#define S6_DMA_LOWWMRKIRQSTAT 0x040 +#define S6_DMA_LOWWMRKIRQCLR 0x044 +#define S6_DMA_LOWWMRKIRQSET 0x048 +#define S6_DMA_MASTERERRINFO 0x04C +#define S6_DMA_MASTERERR_CHAN(n) (4*(n)) +#define S6_DMA_MASTERERR_CHAN_MASK 0xF +#define S6_DMA_DESCRFIFO0 0x050 +#define S6_DMA_DESCRFIFO1 0x054 +#define S6_DMA_DESCRFIFO2 0x058 +#define S6_DMA_DESCRFIFO2_AUTODISABLE 24 +#define S6_DMA_DESCRFIFO3 0x05C +#define S6_DMA_MASTER0START 0x060 +#define S6_DMA_MASTER0END 0x064 +#define S6_DMA_MASTER1START 0x068 +#define S6_DMA_MASTER1END 0x06C +#define S6_DMA_NEXTFREE 0x070 +#define S6_DMA_NEXTFREE_CHAN 0 +#define S6_DMA_NEXTFREE_CHAN_MASK 0x1F +#define S6_DMA_NEXTFREE_ENA 16 +#define S6_DMA_NEXTFREE_ENA_MASK ((1 << 16) - 1) +#define S6_DMA_DPORTCTRLGRP(p) ((p) * 4 + 0x074) +#define S6_DMA_DPORTCTRLGRP_FRAMEREP 0 +#define S6_DMA_DPORTCTRLGRP_NRCHANS 1 +#define S6_DMA_DPORTCTRLGRP_NRCHANS_1 0 +#define S6_DMA_DPORTCTRLGRP_NRCHANS_3 1 +#define S6_DMA_DPORTCTRLGRP_NRCHANS_4 2 +#define S6_DMA_DPORTCTRLGRP_NRCHANS_2 3 +#define S6_DMA_DPORTCTRLGRP_ENA 31 + + +/* DMA per channel */ + +#define DMA_CHNL(dmac, n) ((dmac) + 0x1000 + (n) * 0x100) +#define DMA_INDEX_CHNL(addr) (((addr) >> 8) & 0xF) +#define DMA_MASK_DMAC(addr) ((addr) & 0xFFFF0000) +#define S6_DMA_CHNCTRL 0x000 +#define S6_DMA_CHNCTRL_ENABLE 0 +#define S6_DMA_CHNCTRL_PAUSE 1 +#define S6_DMA_CHNCTRL_PRIO 2 +#define S6_DMA_CHNCTRL_PRIO_MASK 3 +#define S6_DMA_CHNCTRL_PERIPHXFER 4 +#define S6_DMA_CHNCTRL_PERIPHENA 5 +#define S6_DMA_CHNCTRL_SRCINC 6 +#define S6_DMA_CHNCTRL_DSTINC 7 +#define S6_DMA_CHNCTRL_BURSTLOG 8 +#define S6_DMA_CHNCTRL_BURSTLOG_MASK 7 +#define S6_DMA_CHNCTRL_DESCFIFODEPTH 12 +#define S6_DMA_CHNCTRL_DESCFIFODEPTH_MASK 0x1F +#define S6_DMA_CHNCTRL_DESCFIFOFULL 17 +#define S6_DMA_CHNCTRL_BWCONSEL 18 +#define S6_DMA_CHNCTRL_BWCONENA 19 +#define S6_DMA_CHNCTRL_PENDGCNTSTAT 20 +#define S6_DMA_CHNCTRL_PENDGCNTSTAT_MASK 0x3F +#define S6_DMA_CHNCTRL_LOWWMARK 26 +#define S6_DMA_CHNCTRL_LOWWMARK_MASK 0xF +#define S6_DMA_CHNCTRL_TSTAMP 30 +#define S6_DMA_TERMCNTNB 0x004 +#define S6_DMA_TERMCNTNB_MASK 0xFFFF +#define S6_DMA_TERMCNTTMO 0x008 +#define S6_DMA_TERMCNTSTAT 0x00C +#define S6_DMA_TERMCNTSTAT_MASK 0xFF +#define S6_DMA_CMONCHUNK 0x010 +#define S6_DMA_SRCSKIP 0x014 +#define S6_DMA_DSTSKIP 0x018 +#define S6_DMA_CUR_SRC 0x024 +#define S6_DMA_CUR_DST 0x028 +#define S6_DMA_TIMESTAMP 0x030 + +/* DMA channel lists */ + +#define S6_DPDMA_CHAN(stream, channel) (4 * (stream) + (channel)) +#define S6_DPDMA_NB 16 + +#define S6_HIFDMA_GMACTX 0 +#define S6_HIFDMA_GMACRX 1 +#define S6_HIFDMA_I2S0 2 +#define S6_HIFDMA_I2S1 3 +#define S6_HIFDMA_EGIB 4 +#define S6_HIFDMA_PCITX 5 +#define S6_HIFDMA_PCIRX 6 +#define S6_HIFDMA_NB 7 + +#define S6_NIDMA_NB 4 + +#define S6_LMSDMA_NB 12 + +/* controller access */ + +#define S6_DMAC_NB 4 +#define S6_DMAC_INDEX(dmac) (((unsigned)(dmac) >> 18) % S6_DMAC_NB) + +struct s6dmac_ctrl { + u32 dmac; + spinlock_t lock; + u8 chan_nb; +}; + +extern struct s6dmac_ctrl s6dmac_ctrl[S6_DMAC_NB]; + + +/* DMA control, per channel */ + +static inline int s6dmac_fifo_full(u32 dmac, int chan) +{ + return (readl(DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL) + & (1 << S6_DMA_CHNCTRL_DESCFIFOFULL)) && 1; +} + +static inline int s6dmac_termcnt_irq(u32 dmac, int chan) +{ + u32 m = 1 << chan; + int r = (readl(dmac + S6_DMA_TERMCNTIRQSTAT) & m) && 1; + if (r) + writel(m, dmac + S6_DMA_TERMCNTIRQCLR); + return r; +} + +static inline int s6dmac_pendcnt_irq(u32 dmac, int chan) +{ + u32 m = 1 << chan; + int r = (readl(dmac + S6_DMA_PENDCNTIRQSTAT) & m) && 1; + if (r) + writel(m, dmac + S6_DMA_PENDCNTIRQCLR); + return r; +} + +static inline int s6dmac_lowwmark_irq(u32 dmac, int chan) +{ + int r = (readl(dmac + S6_DMA_LOWWMRKIRQSTAT) & (1 << chan)) ? 1 : 0; + if (r) + writel(1 << chan, dmac + S6_DMA_LOWWMRKIRQCLR); + return r; +} + +static inline u32 s6dmac_pending_count(u32 dmac, int chan) +{ + return (readl(DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL) + >> S6_DMA_CHNCTRL_PENDGCNTSTAT) + & S6_DMA_CHNCTRL_PENDGCNTSTAT_MASK; +} + +static inline void s6dmac_set_terminal_count(u32 dmac, int chan, u32 n) +{ + n &= S6_DMA_TERMCNTNB_MASK; + n |= readl(DMA_CHNL(dmac, chan) + S6_DMA_TERMCNTNB) + & ~S6_DMA_TERMCNTNB_MASK; + writel(n, DMA_CHNL(dmac, chan) + S6_DMA_TERMCNTNB); +} + +static inline u32 s6dmac_get_terminal_count(u32 dmac, int chan) +{ + return (readl(DMA_CHNL(dmac, chan) + S6_DMA_TERMCNTNB)) + & S6_DMA_TERMCNTNB_MASK; +} + +static inline u32 s6dmac_timestamp(u32 dmac, int chan) +{ + return readl(DMA_CHNL(dmac, chan) + S6_DMA_TIMESTAMP); +} + +static inline u32 s6dmac_cur_src(u32 dmac, int chan) +{ + return readl(DMA_CHNL(dmac, chan) + S6_DMA_CUR_SRC); +} + +static inline u32 s6dmac_cur_dst(u32 dmac, int chan) +{ + return readl(DMA_CHNL(dmac, chan) + S6_DMA_CUR_DST); +} + +static inline void s6dmac_disable_chan(u32 dmac, int chan) +{ + u32 ctrl; + writel(readl(DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL) + & ~(1 << S6_DMA_CHNCTRL_ENABLE), + DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL); + do + ctrl = readl(DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL); + while (ctrl & (1 << S6_DMA_CHNCTRL_ENABLE)); +} + +static inline void s6dmac_set_stride_skip(u32 dmac, int chan, + int comchunk, /* 0: disable scatter/gather */ + int srcskip, int dstskip) +{ + writel(comchunk, DMA_CHNL(dmac, chan) + S6_DMA_CMONCHUNK); + writel(srcskip, DMA_CHNL(dmac, chan) + S6_DMA_SRCSKIP); + writel(dstskip, DMA_CHNL(dmac, chan) + S6_DMA_DSTSKIP); +} + +static inline void s6dmac_enable_chan(u32 dmac, int chan, + int prio, /* 0 (highest) .. 3 (lowest) */ + int periphxfer, /* <0: disable p.req.line, 0..1: mode */ + int srcinc, int dstinc, /* 0: dont increment src/dst address */ + int comchunk, /* 0: disable scatter/gather */ + int srcskip, int dstskip, + int burstsize, /* 4 for I2S, 7 for everything else */ + int bandwidthconserve, /* <0: disable, 0..1: select */ + int lowwmark, /* 0..15 */ + int timestamp, /* 0: disable timestamp */ + int enable) /* 0: disable for now */ +{ + writel(1, DMA_CHNL(dmac, chan) + S6_DMA_TERMCNTNB); + writel(0, DMA_CHNL(dmac, chan) + S6_DMA_TERMCNTTMO); + writel(lowwmark << S6_DMA_CHNCTRL_LOWWMARK, + DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL); + s6dmac_set_stride_skip(dmac, chan, comchunk, srcskip, dstskip); + writel(((enable ? 1 : 0) << S6_DMA_CHNCTRL_ENABLE) | + (prio << S6_DMA_CHNCTRL_PRIO) | + (((periphxfer > 0) ? 1 : 0) << S6_DMA_CHNCTRL_PERIPHXFER) | + (((periphxfer < 0) ? 0 : 1) << S6_DMA_CHNCTRL_PERIPHENA) | + ((srcinc ? 1 : 0) << S6_DMA_CHNCTRL_SRCINC) | + ((dstinc ? 1 : 0) << S6_DMA_CHNCTRL_DSTINC) | + (burstsize << S6_DMA_CHNCTRL_BURSTLOG) | + (((bandwidthconserve > 0) ? 1 : 0) << S6_DMA_CHNCTRL_BWCONSEL) | + (((bandwidthconserve < 0) ? 0 : 1) << S6_DMA_CHNCTRL_BWCONENA) | + (lowwmark << S6_DMA_CHNCTRL_LOWWMARK) | + ((timestamp ? 1 : 0) << S6_DMA_CHNCTRL_TSTAMP), + DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL); +} + + +/* DMA control, per engine */ + +static inline unsigned _dmac_addr_index(u32 dmac) +{ + unsigned i = S6_DMAC_INDEX(dmac); + if (s6dmac_ctrl[i].dmac != dmac) + BUG(); + return i; +} + +static inline void _s6dmac_disable_error_irqs(u32 dmac, u32 mask) +{ + writel(mask, dmac + S6_DMA_TERMCNTIRQCLR); + writel(mask, dmac + S6_DMA_PENDCNTIRQCLR); + writel(mask, dmac + S6_DMA_LOWWMRKIRQCLR); + writel(readl(dmac + S6_DMA_INTENABLE0) + & ~((mask << S6_DMA_INT0_UNDER) | (mask << S6_DMA_INT0_OVER)), + dmac + S6_DMA_INTENABLE0); + writel(readl(dmac + S6_DMA_INTENABLE1) & ~(mask << S6_DMA_INT1_CHANNEL), + dmac + S6_DMA_INTENABLE1); + writel((mask << S6_DMA_INT0_UNDER) | (mask << S6_DMA_INT0_OVER), + dmac + S6_DMA_INTCLEAR0); + writel(mask << S6_DMA_INT1_CHANNEL, dmac + S6_DMA_INTCLEAR1); +} + +/* + * request channel from specified engine + * with chan<0, accept any channel + * further parameters see s6dmac_enable_chan + * returns < 0 upon error, channel nb otherwise + */ +static inline int s6dmac_request_chan(u32 dmac, int chan, + int prio, + int periphxfer, + int srcinc, int dstinc, + int comchunk, + int srcskip, int dstskip, + int burstsize, + int bandwidthconserve, + int lowwmark, + int timestamp, + int enable) +{ + int r = chan; + unsigned long flags; + spinlock_t *spinl = &s6dmac_ctrl[_dmac_addr_index(dmac)].lock; + spin_lock_irqsave(spinl, flags); + if (r < 0) { + r = (readl(dmac + S6_DMA_NEXTFREE) >> S6_DMA_NEXTFREE_CHAN) + & S6_DMA_NEXTFREE_CHAN_MASK; + } + if (r >= s6dmac_ctrl[_dmac_addr_index(dmac)].chan_nb) { + if (chan < 0) + r = -EBUSY; + else + r = -ENXIO; + } else if (((readl(dmac + S6_DMA_NEXTFREE) >> S6_DMA_NEXTFREE_ENA) + >> r) & 1) { + r = -EBUSY; + } else { + s6dmac_enable_chan(dmac, r, prio, periphxfer, + srcinc, dstinc, comchunk, srcskip, dstskip, burstsize, + bandwidthconserve, lowwmark, timestamp, enable); + } + spin_unlock_irqrestore(spinl, flags); + return r; +} + +static inline void s6dmac_put_fifo(u32 dmac, int chan, + u32 src, u32 dst, u32 size) +{ + unsigned long flags; + spinlock_t *spinl = &s6dmac_ctrl[_dmac_addr_index(dmac)].lock; + spin_lock_irqsave(spinl, flags); + writel(src, dmac + S6_DMA_DESCRFIFO0); + writel(dst, dmac + S6_DMA_DESCRFIFO1); + writel(size, dmac + S6_DMA_DESCRFIFO2); + writel(chan, dmac + S6_DMA_DESCRFIFO3); + spin_unlock_irqrestore(spinl, flags); +} + +static inline u32 s6dmac_channel_enabled(u32 dmac, int chan) +{ + return readl(DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL) & + (1 << S6_DMA_CHNCTRL_ENABLE); +} + +/* + * group 1-4 data port channels + * with port=0..3, nrch=1-4 channels, + * frrep=0/1 (dis- or enable frame repeat) + */ +static inline void s6dmac_dp_setup_group(u32 dmac, int port, + int nrch, int frrep) +{ + const static u8 mask[4] = {0, 3, 1, 2}; + BUG_ON(dmac != S6_REG_DPDMA); + if ((port < 0) || (port > 3) || (nrch < 1) || (nrch > 4)) + return; + writel((mask[nrch - 1] << S6_DMA_DPORTCTRLGRP_NRCHANS) + | ((frrep ? 1 : 0) << S6_DMA_DPORTCTRLGRP_FRAMEREP), + dmac + S6_DMA_DPORTCTRLGRP(port)); +} + +static inline void s6dmac_dp_switch_group(u32 dmac, int port, int enable) +{ + u32 tmp; + BUG_ON(dmac != S6_REG_DPDMA); + tmp = readl(dmac + S6_DMA_DPORTCTRLGRP(port)); + if (enable) + tmp |= (1 << S6_DMA_DPORTCTRLGRP_ENA); + else + tmp &= ~(1 << S6_DMA_DPORTCTRLGRP_ENA); + writel(tmp, dmac + S6_DMA_DPORTCTRLGRP(port)); +} + +extern void s6dmac_put_fifo_cache(u32 dmac, int chan, + u32 src, u32 dst, u32 size); +extern void s6dmac_disable_error_irqs(u32 dmac, u32 mask); +extern u32 s6dmac_int_sources(u32 dmac, u32 channel); +extern void s6dmac_release_chan(u32 dmac, int chan); + +#endif /* __ASM_XTENSA_S6000_DMAC_H */ diff --git a/arch/xtensa/variants/s6000/include/variant/gpio.h b/arch/xtensa/variants/s6000/include/variant/gpio.h index 8327f62167eb..8484ab0df461 100644 --- a/arch/xtensa/variants/s6000/include/variant/gpio.h +++ b/arch/xtensa/variants/s6000/include/variant/gpio.h @@ -1,6 +1,6 @@ #ifndef _XTENSA_VARIANT_S6000_GPIO_H #define _XTENSA_VARIANT_S6000_GPIO_H -extern int s6_gpio_init(void); +extern int s6_gpio_init(u32 afsel); #endif /* _XTENSA_VARIANT_S6000_GPIO_H */ diff --git a/arch/xtensa/variants/s6000/include/variant/irq.h b/arch/xtensa/variants/s6000/include/variant/irq.h index fa031cb0acc4..97d6fc48deff 100644 --- a/arch/xtensa/variants/s6000/include/variant/irq.h +++ b/arch/xtensa/variants/s6000/include/variant/irq.h @@ -1,9 +1,9 @@ -#ifndef __XTENSA_S6000_IRQ_H -#define __XTENSA_S6000_IRQ_H +#ifndef _XTENSA_S6000_IRQ_H +#define _XTENSA_S6000_IRQ_H #define NO_IRQ (-1) +#define VARIANT_NR_IRQS 8 /* GPIO interrupts */ extern void variant_irq_enable(unsigned int irq); -extern void variant_irq_disable(unsigned int irq); #endif /* __XTENSA_S6000_IRQ_H */ diff --git a/block/Kconfig b/block/Kconfig index e7d12782bcfb..95a86adc33a1 100644 --- a/block/Kconfig +++ b/block/Kconfig @@ -23,9 +23,10 @@ menuconfig BLOCK if BLOCK -config LBD - bool "Support for large block devices and files" +config LBDAF + bool "Support for large (2TB+) block devices and files" depends on !64BIT + default y help Enable block devices or files of size 2TB and larger. @@ -38,11 +39,13 @@ config LBD The ext4 filesystem requires that this feature be enabled in order to support filesystems that have the huge_file feature - enabled. Otherwise, it will refuse to mount any filesystems - that use the huge_file feature, which is enabled by default - by mke2fs.ext4. The GFS2 filesystem also requires this feature. + enabled. Otherwise, it will refuse to mount in the read-write + mode any filesystems that use the huge_file feature, which is + enabled by default by mke2fs.ext4. - If unsure, say N. + The GFS2 filesystem also requires this feature. + + If unsure, say Y. config BLK_DEV_BSG bool "Block layer SG support v4 (EXPERIMENTAL)" diff --git a/block/as-iosched.c b/block/as-iosched.c index c48fa670d221..7a12cf6ee1d3 100644 --- a/block/as-iosched.c +++ b/block/as-iosched.c @@ -306,8 +306,8 @@ as_choose_req(struct as_data *ad, struct request *rq1, struct request *rq2) data_dir = rq_is_sync(rq1); last = ad->last_sector[data_dir]; - s1 = rq1->sector; - s2 = rq2->sector; + s1 = blk_rq_pos(rq1); + s2 = blk_rq_pos(rq2); BUG_ON(data_dir != rq_is_sync(rq2)); @@ -566,13 +566,15 @@ static void as_update_iohist(struct as_data *ad, struct as_io_context *aic, as_update_thinktime(ad, aic, thinktime); /* Calculate read -> read seek distance */ - if (aic->last_request_pos < rq->sector) - seek_dist = rq->sector - aic->last_request_pos; + if (aic->last_request_pos < blk_rq_pos(rq)) + seek_dist = blk_rq_pos(rq) - + aic->last_request_pos; else - seek_dist = aic->last_request_pos - rq->sector; + seek_dist = aic->last_request_pos - + blk_rq_pos(rq); as_update_seekdist(ad, aic, seek_dist); } - aic->last_request_pos = rq->sector + rq->nr_sectors; + aic->last_request_pos = blk_rq_pos(rq) + blk_rq_sectors(rq); set_bit(AS_TASK_IOSTARTED, &aic->state); spin_unlock(&aic->lock); } @@ -587,7 +589,7 @@ static int as_close_req(struct as_data *ad, struct as_io_context *aic, { unsigned long delay; /* jiffies */ sector_t last = ad->last_sector[ad->batch_data_dir]; - sector_t next = rq->sector; + sector_t next = blk_rq_pos(rq); sector_t delta; /* acceptable close offset (in sectors) */ sector_t s; @@ -981,7 +983,7 @@ static void as_move_to_dispatch(struct as_data *ad, struct request *rq) * This has to be set in order to be correctly updated by * as_find_next_rq */ - ad->last_sector[data_dir] = rq->sector + rq->nr_sectors; + ad->last_sector[data_dir] = blk_rq_pos(rq) + blk_rq_sectors(rq); if (data_dir == BLK_RW_SYNC) { struct io_context *ioc = RQ_IOC(rq); @@ -1312,12 +1314,8 @@ static void as_merged_requests(struct request_queue *q, struct request *req, static void as_work_handler(struct work_struct *work) { struct as_data *ad = container_of(work, struct as_data, antic_work); - struct request_queue *q = ad->q; - unsigned long flags; - spin_lock_irqsave(q->queue_lock, flags); - blk_start_queueing(q); - spin_unlock_irqrestore(q->queue_lock, flags); + blk_run_queue(ad->q); } static int as_may_queue(struct request_queue *q, int rw) diff --git a/block/blk-barrier.c b/block/blk-barrier.c index 20b4111fa050..30022b4e2f63 100644 --- a/block/blk-barrier.c +++ b/block/blk-barrier.c @@ -106,10 +106,7 @@ bool blk_ordered_complete_seq(struct request_queue *q, unsigned seq, int error) */ q->ordseq = 0; rq = q->orig_bar_rq; - - if (__blk_end_request(rq, q->orderr, blk_rq_bytes(rq))) - BUG(); - + __blk_end_request_all(rq, q->orderr); return true; } @@ -166,7 +163,7 @@ static inline bool start_ordered(struct request_queue *q, struct request **rqp) * For an empty barrier, there's no actual BAR request, which * in turn makes POSTFLUSH unnecessary. Mask them off. */ - if (!rq->hard_nr_sectors) { + if (!blk_rq_sectors(rq)) { q->ordered &= ~(QUEUE_ORDERED_DO_BAR | QUEUE_ORDERED_DO_POSTFLUSH); /* @@ -183,7 +180,7 @@ static inline bool start_ordered(struct request_queue *q, struct request **rqp) } /* stash away the original request */ - elv_dequeue_request(q, rq); + blk_dequeue_request(rq); q->orig_bar_rq = rq; rq = NULL; @@ -221,7 +218,7 @@ static inline bool start_ordered(struct request_queue *q, struct request **rqp) } else skip |= QUEUE_ORDSEQ_PREFLUSH; - if ((q->ordered & QUEUE_ORDERED_BY_DRAIN) && q->in_flight) + if ((q->ordered & QUEUE_ORDERED_BY_DRAIN) && queue_in_flight(q)) rq = NULL; else skip |= QUEUE_ORDSEQ_DRAIN; @@ -251,10 +248,8 @@ bool blk_do_ordered(struct request_queue *q, struct request **rqp) * Queue ordering not supported. Terminate * with prejudice. */ - elv_dequeue_request(q, rq); - if (__blk_end_request(rq, -EOPNOTSUPP, - blk_rq_bytes(rq))) - BUG(); + blk_dequeue_request(rq); + __blk_end_request_all(rq, -EOPNOTSUPP); *rqp = NULL; return false; } @@ -329,7 +324,7 @@ int blkdev_issue_flush(struct block_device *bdev, sector_t *error_sector) /* * The driver must store the error location in ->bi_sector, if * it supports it. For non-stacked drivers, this should be copied - * from rq->sector. + * from blk_rq_pos(rq). */ if (error_sector) *error_sector = bio->bi_sector; @@ -393,10 +388,10 @@ int blkdev_issue_discard(struct block_device *bdev, bio->bi_sector = sector; - if (nr_sects > q->max_hw_sectors) { - bio->bi_size = q->max_hw_sectors << 9; - nr_sects -= q->max_hw_sectors; - sector += q->max_hw_sectors; + if (nr_sects > queue_max_hw_sectors(q)) { + bio->bi_size = queue_max_hw_sectors(q) << 9; + nr_sects -= queue_max_hw_sectors(q); + sector += queue_max_hw_sectors(q); } else { bio->bi_size = nr_sects << 9; nr_sects = 0; diff --git a/block/blk-core.c b/block/blk-core.c index c89883be8737..b06cf5c2a829 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -26,24 +26,15 @@ #include #include #include -#include #include -#include + +#define CREATE_TRACE_POINTS +#include #include "blk.h" -DEFINE_TRACE(block_plug); -DEFINE_TRACE(block_unplug_io); -DEFINE_TRACE(block_unplug_timer); -DEFINE_TRACE(block_getrq); -DEFINE_TRACE(block_sleeprq); -DEFINE_TRACE(block_rq_requeue); -DEFINE_TRACE(block_bio_backmerge); -DEFINE_TRACE(block_bio_frontmerge); -DEFINE_TRACE(block_bio_queue); -DEFINE_TRACE(block_rq_complete); -DEFINE_TRACE(block_remap); /* Also used in drivers/md/dm.c */ EXPORT_TRACEPOINT_SYMBOL_GPL(block_remap); +EXPORT_TRACEPOINT_SYMBOL_GPL(block_bio_complete); static int __make_request(struct request_queue *q, struct bio *bio); @@ -68,11 +59,11 @@ static void drive_stat_acct(struct request *rq, int new_io) int rw = rq_data_dir(rq); int cpu; - if (!blk_fs_request(rq) || !blk_do_io_stat(rq)) + if (!blk_do_io_stat(rq)) return; cpu = part_stat_lock(); - part = disk_map_sector_rcu(rq->rq_disk, rq->sector); + part = disk_map_sector_rcu(rq->rq_disk, blk_rq_pos(rq)); if (!new_io) part_stat_inc(cpu, part, merges[rw]); @@ -127,13 +118,14 @@ void blk_rq_init(struct request_queue *q, struct request *rq) INIT_LIST_HEAD(&rq->timeout_list); rq->cpu = -1; rq->q = q; - rq->sector = rq->hard_sector = (sector_t) -1; + rq->__sector = (sector_t) -1; INIT_HLIST_NODE(&rq->hash); RB_CLEAR_NODE(&rq->rb_node); rq->cmd = rq->__cmd; rq->cmd_len = BLK_MAX_CDB; rq->tag = -1; rq->ref_count = 1; + rq->start_time = jiffies; } EXPORT_SYMBOL(blk_rq_init); @@ -184,14 +176,11 @@ void blk_dump_rq_flags(struct request *rq, char *msg) rq->rq_disk ? rq->rq_disk->disk_name : "?", rq->cmd_type, rq->cmd_flags); - printk(KERN_INFO " sector %llu, nr/cnr %lu/%u\n", - (unsigned long long)rq->sector, - rq->nr_sectors, - rq->current_nr_sectors); - printk(KERN_INFO " bio %p, biotail %p, buffer %p, data %p, len %u\n", - rq->bio, rq->biotail, - rq->buffer, rq->data, - rq->data_len); + printk(KERN_INFO " sector %llu, nr/cnr %u/%u\n", + (unsigned long long)blk_rq_pos(rq), + blk_rq_sectors(rq), blk_rq_cur_sectors(rq)); + printk(KERN_INFO " bio %p, biotail %p, buffer %p, len %u\n", + rq->bio, rq->biotail, rq->buffer, blk_rq_bytes(rq)); if (blk_pc_request(rq)) { printk(KERN_INFO " cdb: "); @@ -333,24 +322,6 @@ void blk_unplug(struct request_queue *q) } EXPORT_SYMBOL(blk_unplug); -static void blk_invoke_request_fn(struct request_queue *q) -{ - if (unlikely(blk_queue_stopped(q))) - return; - - /* - * one level of recursion is ok and is much faster than kicking - * the unplug handling - */ - if (!queue_flag_test_and_set(QUEUE_FLAG_REENTER, q)) { - q->request_fn(q); - queue_flag_clear(QUEUE_FLAG_REENTER, q); - } else { - queue_flag_set(QUEUE_FLAG_PLUGGED, q); - kblockd_schedule_work(q, &q->unplug_work); - } -} - /** * blk_start_queue - restart a previously stopped queue * @q: The &struct request_queue in question @@ -365,7 +336,7 @@ void blk_start_queue(struct request_queue *q) WARN_ON(!irqs_disabled()); queue_flag_clear(QUEUE_FLAG_STOPPED, q); - blk_invoke_request_fn(q); + __blk_run_queue(q); } EXPORT_SYMBOL(blk_start_queue); @@ -425,12 +396,23 @@ void __blk_run_queue(struct request_queue *q) { blk_remove_plug(q); + if (unlikely(blk_queue_stopped(q))) + return; + + if (elv_queue_empty(q)) + return; + /* * Only recurse once to avoid overrunning the stack, let the unplug * handling reinvoke the handler shortly if we already got there. */ - if (!elv_queue_empty(q)) - blk_invoke_request_fn(q); + if (!queue_flag_test_and_set(QUEUE_FLAG_REENTER, q)) { + q->request_fn(q); + queue_flag_clear(QUEUE_FLAG_REENTER, q); + } else { + queue_flag_set(QUEUE_FLAG_PLUGGED, q); + kblockd_schedule_work(q, &q->unplug_work); + } } EXPORT_SYMBOL(__blk_run_queue); @@ -440,9 +422,7 @@ EXPORT_SYMBOL(__blk_run_queue); * * Description: * Invoke request handling on this queue, if it has pending work to do. - * May be used to restart queueing when a request has completed. Also - * See @blk_start_queueing. - * + * May be used to restart queueing when a request has completed. */ void blk_run_queue(struct request_queue *q) { @@ -517,6 +497,11 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id) q->backing_dev_info.unplug_io_fn = blk_backing_dev_unplug; q->backing_dev_info.unplug_io_data = q; + q->backing_dev_info.ra_pages = + (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE; + q->backing_dev_info.state = 0; + q->backing_dev_info.capabilities = BDI_CAP_MAP_COPY; + err = bdi_init(&q->backing_dev_info); if (err) { kmem_cache_free(blk_requestq_cachep, q); @@ -902,26 +887,59 @@ struct request *blk_get_request(struct request_queue *q, int rw, gfp_t gfp_mask) EXPORT_SYMBOL(blk_get_request); /** - * blk_start_queueing - initiate dispatch of requests to device - * @q: request queue to kick into gear + * blk_make_request - given a bio, allocate a corresponding struct request. + * @q: target request queue + * @bio: The bio describing the memory mappings that will be submitted for IO. + * It may be a chained-bio properly constructed by block/bio layer. + * @gfp_mask: gfp flags to be used for memory allocation * - * This is basically a helper to remove the need to know whether a queue - * is plugged or not if someone just wants to initiate dispatch of requests - * for this queue. Should be used to start queueing on a device outside - * of ->request_fn() context. Also see @blk_run_queue. + * blk_make_request is the parallel of generic_make_request for BLOCK_PC + * type commands. Where the struct request needs to be farther initialized by + * the caller. It is passed a &struct bio, which describes the memory info of + * the I/O transfer. * - * The queue lock must be held with interrupts disabled. + * The caller of blk_make_request must make sure that bi_io_vec + * are set to describe the memory buffers. That bio_data_dir() will return + * the needed direction of the request. (And all bio's in the passed bio-chain + * are properly set accordingly) + * + * If called under none-sleepable conditions, mapped bio buffers must not + * need bouncing, by calling the appropriate masked or flagged allocator, + * suitable for the target device. Otherwise the call to blk_queue_bounce will + * BUG. + * + * WARNING: When allocating/cloning a bio-chain, careful consideration should be + * given to how you allocate bios. In particular, you cannot use __GFP_WAIT for + * anything but the first bio in the chain. Otherwise you risk waiting for IO + * completion of a bio that hasn't been submitted yet, thus resulting in a + * deadlock. Alternatively bios should be allocated using bio_kmalloc() instead + * of bio_alloc(), as that avoids the mempool deadlock. + * If possible a big IO should be split into smaller parts when allocation + * fails. Partial allocation should not be an error, or you risk a live-lock. */ -void blk_start_queueing(struct request_queue *q) +struct request *blk_make_request(struct request_queue *q, struct bio *bio, + gfp_t gfp_mask) { - if (!blk_queue_plugged(q)) { - if (unlikely(blk_queue_stopped(q))) - return; - q->request_fn(q); - } else - __generic_unplug_device(q); + struct request *rq = blk_get_request(q, bio_data_dir(bio), gfp_mask); + + if (unlikely(!rq)) + return ERR_PTR(-ENOMEM); + + for_each_bio(bio) { + struct bio *bounce_bio = bio; + int ret; + + blk_queue_bounce(q, &bounce_bio); + ret = blk_rq_append_bio(q, rq, bounce_bio); + if (unlikely(ret)) { + blk_put_request(rq); + return ERR_PTR(ret); + } + } + + return rq; } -EXPORT_SYMBOL(blk_start_queueing); +EXPORT_SYMBOL(blk_make_request); /** * blk_requeue_request - put a request back on queue @@ -942,6 +960,8 @@ void blk_requeue_request(struct request_queue *q, struct request *rq) if (blk_rq_tagged(rq)) blk_queue_end_tag(q, rq); + BUG_ON(blk_queued_rq(rq)); + elv_requeue_request(q, rq); } EXPORT_SYMBOL(blk_requeue_request); @@ -977,7 +997,6 @@ void blk_insert_request(struct request_queue *q, struct request *rq, * barrier */ rq->cmd_type = REQ_TYPE_SPECIAL; - rq->cmd_flags |= REQ_SOFTBARRIER; rq->special = data; @@ -991,7 +1010,7 @@ void blk_insert_request(struct request_queue *q, struct request *rq, drive_stat_acct(rq, 1); __elv_add_request(q, rq, where, 0); - blk_start_queueing(q); + __blk_run_queue(q); spin_unlock_irqrestore(q->queue_lock, flags); } EXPORT_SYMBOL(blk_insert_request); @@ -1113,16 +1132,13 @@ void init_request_from_bio(struct request *req, struct bio *bio) if (bio_failfast_driver(bio)) req->cmd_flags |= REQ_FAILFAST_DRIVER; - /* - * REQ_BARRIER implies no merging, but lets make it explicit - */ if (unlikely(bio_discard(bio))) { req->cmd_flags |= REQ_DISCARD; if (bio_barrier(bio)) req->cmd_flags |= REQ_SOFTBARRIER; req->q->prepare_discard_fn(req->q, req); } else if (unlikely(bio_barrier(bio))) - req->cmd_flags |= (REQ_HARDBARRIER | REQ_NOMERGE); + req->cmd_flags |= REQ_HARDBARRIER; if (bio_sync(bio)) req->cmd_flags |= REQ_RW_SYNC; @@ -1132,9 +1148,8 @@ void init_request_from_bio(struct request *req, struct bio *bio) req->cmd_flags |= REQ_NOIDLE; req->errors = 0; - req->hard_sector = req->sector = bio->bi_sector; + req->__sector = bio->bi_sector; req->ioprio = bio_prio(bio); - req->start_time = jiffies; blk_rq_bio_prep(req->q, req, bio); } @@ -1150,14 +1165,13 @@ static inline bool queue_should_plug(struct request_queue *q) static int __make_request(struct request_queue *q, struct bio *bio) { struct request *req; - int el_ret, nr_sectors; + int el_ret; + unsigned int bytes = bio->bi_size; const unsigned short prio = bio_prio(bio); const int sync = bio_sync(bio); const int unplug = bio_unplug(bio); int rw_flags; - nr_sectors = bio_sectors(bio); - /* * low level driver can indicate that it wants pages above a * certain limit bounced to low memory (ie for highmem, or even @@ -1182,7 +1196,7 @@ static int __make_request(struct request_queue *q, struct bio *bio) req->biotail->bi_next = bio; req->biotail = bio; - req->nr_sectors = req->hard_nr_sectors += nr_sectors; + req->__data_len += bytes; req->ioprio = ioprio_best(req->ioprio, prio); if (!blk_rq_cpu_valid(req)) req->cpu = bio->bi_comp_cpu; @@ -1208,10 +1222,8 @@ static int __make_request(struct request_queue *q, struct bio *bio) * not touch req->buffer either... */ req->buffer = bio_data(bio); - req->current_nr_sectors = bio_cur_sectors(bio); - req->hard_cur_sectors = req->current_nr_sectors; - req->sector = req->hard_sector = bio->bi_sector; - req->nr_sectors = req->hard_nr_sectors += nr_sectors; + req->__sector = bio->bi_sector; + req->__data_len += bytes; req->ioprio = ioprio_best(req->ioprio, prio); if (!blk_rq_cpu_valid(req)) req->cpu = bio->bi_comp_cpu; @@ -1277,7 +1289,7 @@ static inline void blk_partition_remap(struct bio *bio) bio->bi_bdev = bdev->bd_contains; trace_block_remap(bdev_get_queue(bio->bi_bdev), bio, - bdev->bd_dev, bio->bi_sector, + bdev->bd_dev, bio->bi_sector - p->start_sect); } } @@ -1422,11 +1434,11 @@ static inline void __generic_make_request(struct bio *bio) goto end_io; } - if (unlikely(nr_sectors > q->max_hw_sectors)) { + if (unlikely(nr_sectors > queue_max_hw_sectors(q))) { printk(KERN_ERR "bio too big device %s (%u > %u)\n", - bdevname(bio->bi_bdev, b), - bio_sectors(bio), - q->max_hw_sectors); + bdevname(bio->bi_bdev, b), + bio_sectors(bio), + queue_max_hw_sectors(q)); goto end_io; } @@ -1446,8 +1458,7 @@ static inline void __generic_make_request(struct bio *bio) goto end_io; if (old_sector != -1) - trace_block_remap(q, bio, old_dev, bio->bi_sector, - old_sector); + trace_block_remap(q, bio, old_dev, old_sector); trace_block_bio_queue(q, bio); @@ -1593,8 +1604,8 @@ EXPORT_SYMBOL(submit_bio); */ int blk_rq_check_limits(struct request_queue *q, struct request *rq) { - if (rq->nr_sectors > q->max_sectors || - rq->data_len > q->max_hw_sectors << 9) { + if (blk_rq_sectors(rq) > queue_max_sectors(q) || + blk_rq_bytes(rq) > queue_max_hw_sectors(q) << 9) { printk(KERN_ERR "%s: over max size limit.\n", __func__); return -EIO; } @@ -1606,8 +1617,8 @@ int blk_rq_check_limits(struct request_queue *q, struct request *rq) * limitation. */ blk_recalc_rq_segments(rq); - if (rq->nr_phys_segments > q->max_phys_segments || - rq->nr_phys_segments > q->max_hw_segments) { + if (rq->nr_phys_segments > queue_max_phys_segments(q) || + rq->nr_phys_segments > queue_max_hw_segments(q)) { printk(KERN_ERR "%s: over max segments limit.\n", __func__); return -EIO; } @@ -1651,40 +1662,15 @@ int blk_insert_cloned_request(struct request_queue *q, struct request *rq) } EXPORT_SYMBOL_GPL(blk_insert_cloned_request); -/** - * blkdev_dequeue_request - dequeue request and start timeout timer - * @req: request to dequeue - * - * Dequeue @req and start timeout timer on it. This hands off the - * request to the driver. - * - * Block internal functions which don't want to start timer should - * call elv_dequeue_request(). - */ -void blkdev_dequeue_request(struct request *req) -{ - elv_dequeue_request(req->q, req); - - /* - * We are now handing the request to the hardware, add the - * timeout handler. - */ - blk_add_timer(req); -} -EXPORT_SYMBOL(blkdev_dequeue_request); - static void blk_account_io_completion(struct request *req, unsigned int bytes) { - if (!blk_do_io_stat(req)) - return; - - if (blk_fs_request(req)) { + if (blk_do_io_stat(req)) { const int rw = rq_data_dir(req); struct hd_struct *part; int cpu; cpu = part_stat_lock(); - part = disk_map_sector_rcu(req->rq_disk, req->sector); + part = disk_map_sector_rcu(req->rq_disk, blk_rq_pos(req)); part_stat_add(cpu, part, sectors[rw], bytes >> 9); part_stat_unlock(); } @@ -1692,22 +1678,19 @@ static void blk_account_io_completion(struct request *req, unsigned int bytes) static void blk_account_io_done(struct request *req) { - if (!blk_do_io_stat(req)) - return; - /* * Account IO completion. bar_rq isn't accounted as a normal * IO on queueing nor completion. Accounting the containing * request is enough. */ - if (blk_fs_request(req) && req != &req->q->bar_rq) { + if (blk_do_io_stat(req) && req != &req->q->bar_rq) { unsigned long duration = jiffies - req->start_time; const int rw = rq_data_dir(req); struct hd_struct *part; int cpu; cpu = part_stat_lock(); - part = disk_map_sector_rcu(req->rq_disk, req->sector); + part = disk_map_sector_rcu(req->rq_disk, blk_rq_pos(req)); part_stat_inc(cpu, part, ios[rw]); part_stat_add(cpu, part, ticks[rw], duration); @@ -1719,38 +1702,226 @@ static void blk_account_io_done(struct request *req) } /** - * __end_that_request_first - end I/O on a request - * @req: the request being processed - * @error: %0 for success, < %0 for error - * @nr_bytes: number of bytes to complete + * blk_peek_request - peek at the top of a request queue + * @q: request queue to peek at * * Description: - * Ends I/O on a number of bytes attached to @req, and sets it up - * for the next range of segments (if any) in the cluster. + * Return the request at the top of @q. The returned request + * should be started using blk_start_request() before LLD starts + * processing it. * * Return: - * %0 - we are done with this request, call end_that_request_last() - * %1 - still buffers pending for this request + * Pointer to the request at the top of @q if available. Null + * otherwise. + * + * Context: + * queue_lock must be held. + */ +struct request *blk_peek_request(struct request_queue *q) +{ + struct request *rq; + int ret; + + while ((rq = __elv_next_request(q)) != NULL) { + if (!(rq->cmd_flags & REQ_STARTED)) { + /* + * This is the first time the device driver + * sees this request (possibly after + * requeueing). Notify IO scheduler. + */ + if (blk_sorted_rq(rq)) + elv_activate_rq(q, rq); + + /* + * just mark as started even if we don't start + * it, a request that has been delayed should + * not be passed by new incoming requests + */ + rq->cmd_flags |= REQ_STARTED; + trace_block_rq_issue(q, rq); + } + + if (!q->boundary_rq || q->boundary_rq == rq) { + q->end_sector = rq_end_sector(rq); + q->boundary_rq = NULL; + } + + if (rq->cmd_flags & REQ_DONTPREP) + break; + + if (q->dma_drain_size && blk_rq_bytes(rq)) { + /* + * make sure space for the drain appears we + * know we can do this because max_hw_segments + * has been adjusted to be one fewer than the + * device can handle + */ + rq->nr_phys_segments++; + } + + if (!q->prep_rq_fn) + break; + + ret = q->prep_rq_fn(q, rq); + if (ret == BLKPREP_OK) { + break; + } else if (ret == BLKPREP_DEFER) { + /* + * the request may have been (partially) prepped. + * we need to keep this request in the front to + * avoid resource deadlock. REQ_STARTED will + * prevent other fs requests from passing this one. + */ + if (q->dma_drain_size && blk_rq_bytes(rq) && + !(rq->cmd_flags & REQ_DONTPREP)) { + /* + * remove the space for the drain we added + * so that we don't add it again + */ + --rq->nr_phys_segments; + } + + rq = NULL; + break; + } else if (ret == BLKPREP_KILL) { + rq->cmd_flags |= REQ_QUIET; + /* + * Mark this request as started so we don't trigger + * any debug logic in the end I/O path. + */ + blk_start_request(rq); + __blk_end_request_all(rq, -EIO); + } else { + printk(KERN_ERR "%s: bad return=%d\n", __func__, ret); + break; + } + } + + return rq; +} +EXPORT_SYMBOL(blk_peek_request); + +void blk_dequeue_request(struct request *rq) +{ + struct request_queue *q = rq->q; + + BUG_ON(list_empty(&rq->queuelist)); + BUG_ON(ELV_ON_HASH(rq)); + + list_del_init(&rq->queuelist); + + /* + * the time frame between a request being removed from the lists + * and to it is freed is accounted as io that is in progress at + * the driver side. + */ + if (blk_account_rq(rq)) + q->in_flight[rq_is_sync(rq)]++; +} + +/** + * blk_start_request - start request processing on the driver + * @req: request to dequeue + * + * Description: + * Dequeue @req and start timeout timer on it. This hands off the + * request to the driver. + * + * Block internal functions which don't want to start timer should + * call blk_dequeue_request(). + * + * Context: + * queue_lock must be held. + */ +void blk_start_request(struct request *req) +{ + blk_dequeue_request(req); + + /* + * We are now handing the request to the hardware, initialize + * resid_len to full count and add the timeout handler. + */ + req->resid_len = blk_rq_bytes(req); + if (unlikely(blk_bidi_rq(req))) + req->next_rq->resid_len = blk_rq_bytes(req->next_rq); + + blk_add_timer(req); +} +EXPORT_SYMBOL(blk_start_request); + +/** + * blk_fetch_request - fetch a request from a request queue + * @q: request queue to fetch a request from + * + * Description: + * Return the request at the top of @q. The request is started on + * return and LLD can start processing it immediately. + * + * Return: + * Pointer to the request at the top of @q if available. Null + * otherwise. + * + * Context: + * queue_lock must be held. + */ +struct request *blk_fetch_request(struct request_queue *q) +{ + struct request *rq; + + rq = blk_peek_request(q); + if (rq) + blk_start_request(rq); + return rq; +} +EXPORT_SYMBOL(blk_fetch_request); + +/** + * blk_update_request - Special helper function for request stacking drivers + * @req: the request being processed + * @error: %0 for success, < %0 for error + * @nr_bytes: number of bytes to complete @req + * + * Description: + * Ends I/O on a number of bytes attached to @req, but doesn't complete + * the request structure even if @req doesn't have leftover. + * If @req has leftover, sets it up for the next range of segments. + * + * This special helper function is only for request stacking drivers + * (e.g. request-based dm) so that they can handle partial completion. + * Actual device drivers should use blk_end_request instead. + * + * Passing the result of blk_rq_bytes() as @nr_bytes guarantees + * %false return from this function. + * + * Return: + * %false - this request doesn't have any more data + * %true - this request has more data **/ -static int __end_that_request_first(struct request *req, int error, - int nr_bytes) +bool blk_update_request(struct request *req, int error, unsigned int nr_bytes) { int total_bytes, bio_nbytes, next_idx = 0; struct bio *bio; + if (!req->bio) + return false; + trace_block_rq_complete(req->q, req); /* - * for a REQ_TYPE_BLOCK_PC request, we want to carry any eventual - * sense key with us all the way through + * For fs requests, rq is just carrier of independent bio's + * and each partial completion should be handled separately. + * Reset per-request error on each partial completion. + * + * TODO: tj: This is too subtle. It would be better to let + * low level drivers do what they see fit. */ - if (!blk_pc_request(req)) + if (blk_fs_request(req)) req->errors = 0; if (error && (blk_fs_request(req) && !(req->cmd_flags & REQ_QUIET))) { printk(KERN_ERR "end_request: I/O error, dev %s, sector %llu\n", req->rq_disk ? req->rq_disk->disk_name : "?", - (unsigned long long)req->sector); + (unsigned long long)blk_rq_pos(req)); } blk_account_io_completion(req, nr_bytes); @@ -1810,8 +1981,15 @@ static int __end_that_request_first(struct request *req, int error, /* * completely done */ - if (!req->bio) - return 0; + if (!req->bio) { + /* + * Reset counters so that the request stacking driver + * can find how many bytes remain in the request + * later. + */ + req->__data_len = 0; + return false; + } /* * if the request wasn't completed, update state @@ -1823,21 +2001,55 @@ static int __end_that_request_first(struct request *req, int error, bio_iovec(bio)->bv_len -= nr_bytes; } - blk_recalc_rq_sectors(req, total_bytes >> 9); + req->__data_len -= total_bytes; + req->buffer = bio_data(req->bio); + + /* update sector only for requests with clear definition of sector */ + if (blk_fs_request(req) || blk_discard_rq(req)) + req->__sector += total_bytes >> 9; + + /* + * If total number of sectors is less than the first segment + * size, something has gone terribly wrong. + */ + if (blk_rq_bytes(req) < blk_rq_cur_bytes(req)) { + printk(KERN_ERR "blk: request botched\n"); + req->__data_len = blk_rq_cur_bytes(req); + } + + /* recalculate the number of segments */ blk_recalc_rq_segments(req); - return 1; + + return true; +} +EXPORT_SYMBOL_GPL(blk_update_request); + +static bool blk_update_bidi_request(struct request *rq, int error, + unsigned int nr_bytes, + unsigned int bidi_bytes) +{ + if (blk_update_request(rq, error, nr_bytes)) + return true; + + /* Bidi request must be completed as a whole */ + if (unlikely(blk_bidi_rq(rq)) && + blk_update_request(rq->next_rq, error, bidi_bytes)) + return true; + + add_disk_randomness(rq->rq_disk); + + return false; } /* * queue lock must be held */ -static void end_that_request_last(struct request *req, int error) +static void blk_finish_request(struct request *req, int error) { if (blk_rq_tagged(req)) blk_queue_end_tag(req->q, req); - if (blk_queued_rq(req)) - elv_dequeue_request(req->q, req); + BUG_ON(blk_queued_rq(req)); if (unlikely(laptop_mode) && blk_fs_request(req)) laptop_io_completion(); @@ -1857,117 +2069,62 @@ static void end_that_request_last(struct request *req, int error) } /** - * blk_rq_bytes - Returns bytes left to complete in the entire request - * @rq: the request being processed - **/ -unsigned int blk_rq_bytes(struct request *rq) -{ - if (blk_fs_request(rq)) - return rq->hard_nr_sectors << 9; - - return rq->data_len; -} -EXPORT_SYMBOL_GPL(blk_rq_bytes); - -/** - * blk_rq_cur_bytes - Returns bytes left to complete in the current segment - * @rq: the request being processed - **/ -unsigned int blk_rq_cur_bytes(struct request *rq) -{ - if (blk_fs_request(rq)) - return rq->current_nr_sectors << 9; - - if (rq->bio) - return rq->bio->bi_size; - - return rq->data_len; -} -EXPORT_SYMBOL_GPL(blk_rq_cur_bytes); - -/** - * end_request - end I/O on the current segment of the request - * @req: the request being processed - * @uptodate: error value or %0/%1 uptodate flag - * - * Description: - * Ends I/O on the current segment of a request. If that is the only - * remaining segment, the request is also completed and freed. - * - * This is a remnant of how older block drivers handled I/O completions. - * Modern drivers typically end I/O on the full request in one go, unless - * they have a residual value to account for. For that case this function - * isn't really useful, unless the residual just happens to be the - * full current segment. In other words, don't use this function in new - * code. Use blk_end_request() or __blk_end_request() to end a request. - **/ -void end_request(struct request *req, int uptodate) -{ - int error = 0; - - if (uptodate <= 0) - error = uptodate ? uptodate : -EIO; - - __blk_end_request(req, error, req->hard_cur_sectors << 9); -} -EXPORT_SYMBOL(end_request); - -static int end_that_request_data(struct request *rq, int error, - unsigned int nr_bytes, unsigned int bidi_bytes) -{ - if (rq->bio) { - if (__end_that_request_first(rq, error, nr_bytes)) - return 1; - - /* Bidi request must be completed as a whole */ - if (blk_bidi_rq(rq) && - __end_that_request_first(rq->next_rq, error, bidi_bytes)) - return 1; - } - - return 0; -} - -/** - * blk_end_io - Generic end_io function to complete a request. - * @rq: the request being processed - * @error: %0 for success, < %0 for error - * @nr_bytes: number of bytes to complete @rq - * @bidi_bytes: number of bytes to complete @rq->next_rq - * @drv_callback: function called between completion of bios in the request - * and completion of the request. - * If the callback returns non %0, this helper returns without - * completion of the request. + * blk_end_bidi_request - Complete a bidi request + * @rq: the request to complete + * @error: %0 for success, < %0 for error + * @nr_bytes: number of bytes to complete @rq + * @bidi_bytes: number of bytes to complete @rq->next_rq * * Description: * Ends I/O on a number of bytes attached to @rq and @rq->next_rq. - * If @rq has leftover, sets it up for the next range of segments. + * Drivers that supports bidi can safely call this member for any + * type of request, bidi or uni. In the later case @bidi_bytes is + * just ignored. * * Return: - * %0 - we are done with this request - * %1 - this request is not freed yet, it still has pending buffers. + * %false - we are done with this request + * %true - still buffers pending for this request **/ -static int blk_end_io(struct request *rq, int error, unsigned int nr_bytes, - unsigned int bidi_bytes, - int (drv_callback)(struct request *)) +static bool blk_end_bidi_request(struct request *rq, int error, + unsigned int nr_bytes, unsigned int bidi_bytes) { struct request_queue *q = rq->q; - unsigned long flags = 0UL; + unsigned long flags; - if (end_that_request_data(rq, error, nr_bytes, bidi_bytes)) - return 1; - - /* Special feature for tricky drivers */ - if (drv_callback && drv_callback(rq)) - return 1; - - add_disk_randomness(rq->rq_disk); + if (blk_update_bidi_request(rq, error, nr_bytes, bidi_bytes)) + return true; spin_lock_irqsave(q->queue_lock, flags); - end_that_request_last(rq, error); + blk_finish_request(rq, error); spin_unlock_irqrestore(q->queue_lock, flags); - return 0; + return false; +} + +/** + * __blk_end_bidi_request - Complete a bidi request with queue lock held + * @rq: the request to complete + * @error: %0 for success, < %0 for error + * @nr_bytes: number of bytes to complete @rq + * @bidi_bytes: number of bytes to complete @rq->next_rq + * + * Description: + * Identical to blk_end_bidi_request() except that queue lock is + * assumed to be locked on entry and remains so on return. + * + * Return: + * %false - we are done with this request + * %true - still buffers pending for this request + **/ +static bool __blk_end_bidi_request(struct request *rq, int error, + unsigned int nr_bytes, unsigned int bidi_bytes) +{ + if (blk_update_bidi_request(rq, error, nr_bytes, bidi_bytes)) + return true; + + blk_finish_request(rq, error); + + return false; } /** @@ -1981,15 +2138,54 @@ static int blk_end_io(struct request *rq, int error, unsigned int nr_bytes, * If @rq has leftover, sets it up for the next range of segments. * * Return: - * %0 - we are done with this request - * %1 - still buffers pending for this request + * %false - we are done with this request + * %true - still buffers pending for this request **/ -int blk_end_request(struct request *rq, int error, unsigned int nr_bytes) +bool blk_end_request(struct request *rq, int error, unsigned int nr_bytes) { - return blk_end_io(rq, error, nr_bytes, 0, NULL); + return blk_end_bidi_request(rq, error, nr_bytes, 0); } EXPORT_SYMBOL_GPL(blk_end_request); +/** + * blk_end_request_all - Helper function for drives to finish the request. + * @rq: the request to finish + * @error: %0 for success, < %0 for error + * + * Description: + * Completely finish @rq. + */ +void blk_end_request_all(struct request *rq, int error) +{ + bool pending; + unsigned int bidi_bytes = 0; + + if (unlikely(blk_bidi_rq(rq))) + bidi_bytes = blk_rq_bytes(rq->next_rq); + + pending = blk_end_bidi_request(rq, error, blk_rq_bytes(rq), bidi_bytes); + BUG_ON(pending); +} +EXPORT_SYMBOL_GPL(blk_end_request_all); + +/** + * blk_end_request_cur - Helper function to finish the current request chunk. + * @rq: the request to finish the current chunk for + * @error: %0 for success, < %0 for error + * + * Description: + * Complete the current consecutively mapped chunk from @rq. + * + * Return: + * %false - we are done with this request + * %true - still buffers pending for this request + */ +bool blk_end_request_cur(struct request *rq, int error) +{ + return blk_end_request(rq, error, blk_rq_cur_bytes(rq)); +} +EXPORT_SYMBOL_GPL(blk_end_request_cur); + /** * __blk_end_request - Helper function for drivers to complete the request. * @rq: the request being processed @@ -2000,105 +2196,54 @@ EXPORT_SYMBOL_GPL(blk_end_request); * Must be called with queue lock held unlike blk_end_request(). * * Return: - * %0 - we are done with this request - * %1 - still buffers pending for this request + * %false - we are done with this request + * %true - still buffers pending for this request **/ -int __blk_end_request(struct request *rq, int error, unsigned int nr_bytes) +bool __blk_end_request(struct request *rq, int error, unsigned int nr_bytes) { - if (rq->bio && __end_that_request_first(rq, error, nr_bytes)) - return 1; - - add_disk_randomness(rq->rq_disk); - - end_that_request_last(rq, error); - - return 0; + return __blk_end_bidi_request(rq, error, nr_bytes, 0); } EXPORT_SYMBOL_GPL(__blk_end_request); /** - * blk_end_bidi_request - Helper function for drivers to complete bidi request. - * @rq: the bidi request being processed - * @error: %0 for success, < %0 for error - * @nr_bytes: number of bytes to complete @rq - * @bidi_bytes: number of bytes to complete @rq->next_rq + * __blk_end_request_all - Helper function for drives to finish the request. + * @rq: the request to finish + * @error: %0 for success, < %0 for error * * Description: - * Ends I/O on a number of bytes attached to @rq and @rq->next_rq. - * - * Return: - * %0 - we are done with this request - * %1 - still buffers pending for this request - **/ -int blk_end_bidi_request(struct request *rq, int error, unsigned int nr_bytes, - unsigned int bidi_bytes) -{ - return blk_end_io(rq, error, nr_bytes, bidi_bytes, NULL); -} -EXPORT_SYMBOL_GPL(blk_end_bidi_request); - -/** - * blk_update_request - Special helper function for request stacking drivers - * @rq: the request being processed - * @error: %0 for success, < %0 for error - * @nr_bytes: number of bytes to complete @rq - * - * Description: - * Ends I/O on a number of bytes attached to @rq, but doesn't complete - * the request structure even if @rq doesn't have leftover. - * If @rq has leftover, sets it up for the next range of segments. - * - * This special helper function is only for request stacking drivers - * (e.g. request-based dm) so that they can handle partial completion. - * Actual device drivers should use blk_end_request instead. + * Completely finish @rq. Must be called with queue lock held. */ -void blk_update_request(struct request *rq, int error, unsigned int nr_bytes) +void __blk_end_request_all(struct request *rq, int error) { - if (!end_that_request_data(rq, error, nr_bytes, 0)) { - /* - * These members are not updated in end_that_request_data() - * when all bios are completed. - * Update them so that the request stacking driver can find - * how many bytes remain in the request later. - */ - rq->nr_sectors = rq->hard_nr_sectors = 0; - rq->current_nr_sectors = rq->hard_cur_sectors = 0; - } + bool pending; + unsigned int bidi_bytes = 0; + + if (unlikely(blk_bidi_rq(rq))) + bidi_bytes = blk_rq_bytes(rq->next_rq); + + pending = __blk_end_bidi_request(rq, error, blk_rq_bytes(rq), bidi_bytes); + BUG_ON(pending); } -EXPORT_SYMBOL_GPL(blk_update_request); +EXPORT_SYMBOL_GPL(__blk_end_request_all); /** - * blk_end_request_callback - Special helper function for tricky drivers - * @rq: the request being processed - * @error: %0 for success, < %0 for error - * @nr_bytes: number of bytes to complete - * @drv_callback: function called between completion of bios in the request - * and completion of the request. - * If the callback returns non %0, this helper returns without - * completion of the request. + * __blk_end_request_cur - Helper function to finish the current request chunk. + * @rq: the request to finish the current chunk for + * @error: %0 for success, < %0 for error * * Description: - * Ends I/O on a number of bytes attached to @rq. - * If @rq has leftover, sets it up for the next range of segments. - * - * This special helper function is used only for existing tricky drivers. - * (e.g. cdrom_newpc_intr() of ide-cd) - * This interface will be removed when such drivers are rewritten. - * Don't use this interface in other places anymore. + * Complete the current consecutively mapped chunk from @rq. Must + * be called with queue lock held. * * Return: - * %0 - we are done with this request - * %1 - this request is not freed yet. - * this request still has pending buffers or - * the driver doesn't want to finish this request yet. - **/ -int blk_end_request_callback(struct request *rq, int error, - unsigned int nr_bytes, - int (drv_callback)(struct request *)) + * %false - we are done with this request + * %true - still buffers pending for this request + */ +bool __blk_end_request_cur(struct request *rq, int error) { - return blk_end_io(rq, error, nr_bytes, 0, drv_callback); + return __blk_end_request(rq, error, blk_rq_cur_bytes(rq)); } -EXPORT_SYMBOL_GPL(blk_end_request_callback); +EXPORT_SYMBOL_GPL(__blk_end_request_cur); void blk_rq_bio_prep(struct request_queue *q, struct request *rq, struct bio *bio) @@ -2111,11 +2256,7 @@ void blk_rq_bio_prep(struct request_queue *q, struct request *rq, rq->nr_phys_segments = bio_phys_segments(q, bio); rq->buffer = bio_data(bio); } - rq->current_nr_sectors = bio_cur_sectors(bio); - rq->hard_cur_sectors = rq->current_nr_sectors; - rq->hard_nr_sectors = rq->nr_sectors = bio_sectors(bio); - rq->data_len = bio->bi_size; - + rq->__data_len = bio->bi_size; rq->bio = rq->biotail = bio; if (bio->bi_bdev) @@ -2150,6 +2291,106 @@ int blk_lld_busy(struct request_queue *q) } EXPORT_SYMBOL_GPL(blk_lld_busy); +/** + * blk_rq_unprep_clone - Helper function to free all bios in a cloned request + * @rq: the clone request to be cleaned up + * + * Description: + * Free all bios in @rq for a cloned request. + */ +void blk_rq_unprep_clone(struct request *rq) +{ + struct bio *bio; + + while ((bio = rq->bio) != NULL) { + rq->bio = bio->bi_next; + + bio_put(bio); + } +} +EXPORT_SYMBOL_GPL(blk_rq_unprep_clone); + +/* + * Copy attributes of the original request to the clone request. + * The actual data parts (e.g. ->cmd, ->buffer, ->sense) are not copied. + */ +static void __blk_rq_prep_clone(struct request *dst, struct request *src) +{ + dst->cpu = src->cpu; + dst->cmd_flags = (rq_data_dir(src) | REQ_NOMERGE); + dst->cmd_type = src->cmd_type; + dst->__sector = blk_rq_pos(src); + dst->__data_len = blk_rq_bytes(src); + dst->nr_phys_segments = src->nr_phys_segments; + dst->ioprio = src->ioprio; + dst->extra_len = src->extra_len; +} + +/** + * blk_rq_prep_clone - Helper function to setup clone request + * @rq: the request to be setup + * @rq_src: original request to be cloned + * @bs: bio_set that bios for clone are allocated from + * @gfp_mask: memory allocation mask for bio + * @bio_ctr: setup function to be called for each clone bio. + * Returns %0 for success, non %0 for failure. + * @data: private data to be passed to @bio_ctr + * + * Description: + * Clones bios in @rq_src to @rq, and copies attributes of @rq_src to @rq. + * The actual data parts of @rq_src (e.g. ->cmd, ->buffer, ->sense) + * are not copied, and copying such parts is the caller's responsibility. + * Also, pages which the original bios are pointing to are not copied + * and the cloned bios just point same pages. + * So cloned bios must be completed before original bios, which means + * the caller must complete @rq before @rq_src. + */ +int blk_rq_prep_clone(struct request *rq, struct request *rq_src, + struct bio_set *bs, gfp_t gfp_mask, + int (*bio_ctr)(struct bio *, struct bio *, void *), + void *data) +{ + struct bio *bio, *bio_src; + + if (!bs) + bs = fs_bio_set; + + blk_rq_init(NULL, rq); + + __rq_for_each_bio(bio_src, rq_src) { + bio = bio_alloc_bioset(gfp_mask, bio_src->bi_max_vecs, bs); + if (!bio) + goto free_and_out; + + __bio_clone(bio, bio_src); + + if (bio_integrity(bio_src) && + bio_integrity_clone(bio, bio_src, gfp_mask)) + goto free_and_out; + + if (bio_ctr && bio_ctr(bio, bio_src, data)) + goto free_and_out; + + if (rq->bio) { + rq->biotail->bi_next = bio; + rq->biotail = bio; + } else + rq->bio = rq->biotail = bio; + } + + __blk_rq_prep_clone(rq, rq_src); + + return 0; + +free_and_out: + if (bio) + bio_free(bio, bs); + blk_rq_unprep_clone(rq); + + return -ENOMEM; +} +EXPORT_SYMBOL_GPL(blk_rq_prep_clone); + int kblockd_schedule_work(struct request_queue *q, struct work_struct *work) { return queue_work(kblockd_workqueue, work); @@ -2158,6 +2399,9 @@ EXPORT_SYMBOL(kblockd_schedule_work); int __init blk_dev_init(void) { + BUILD_BUG_ON(__REQ_NR_BITS > 8 * + sizeof(((struct request *)0)->cmd_flags)); + kblockd_workqueue = create_workqueue("kblockd"); if (!kblockd_workqueue) panic("Failed to create kblockd\n"); diff --git a/block/blk-exec.c b/block/blk-exec.c index 6af716d1e54e..49557e91f0da 100644 --- a/block/blk-exec.c +++ b/block/blk-exec.c @@ -51,7 +51,6 @@ void blk_execute_rq_nowait(struct request_queue *q, struct gendisk *bd_disk, int where = at_head ? ELEVATOR_INSERT_FRONT : ELEVATOR_INSERT_BACK; rq->rq_disk = bd_disk; - rq->cmd_flags |= REQ_NOMERGE; rq->end_io = done; WARN_ON(irqs_disabled()); spin_lock_irq(q->queue_lock); diff --git a/block/blk-integrity.c b/block/blk-integrity.c index 91fa8e06b6a5..73e28d355688 100644 --- a/block/blk-integrity.c +++ b/block/blk-integrity.c @@ -340,7 +340,7 @@ int blk_integrity_register(struct gendisk *disk, struct blk_integrity *template) kobject_uevent(&bi->kobj, KOBJ_ADD); bi->flags |= INTEGRITY_FLAG_READ | INTEGRITY_FLAG_WRITE; - bi->sector_size = disk->queue->hardsect_size; + bi->sector_size = queue_logical_block_size(disk->queue); disk->integrity = bi; } else bi = disk->integrity; diff --git a/block/blk-ioc.c b/block/blk-ioc.c index 012f065ac8e2..d4ed6000147d 100644 --- a/block/blk-ioc.c +++ b/block/blk-ioc.c @@ -35,9 +35,9 @@ int put_io_context(struct io_context *ioc) if (ioc == NULL) return 1; - BUG_ON(atomic_read(&ioc->refcount) == 0); + BUG_ON(atomic_long_read(&ioc->refcount) == 0); - if (atomic_dec_and_test(&ioc->refcount)) { + if (atomic_long_dec_and_test(&ioc->refcount)) { rcu_read_lock(); if (ioc->aic && ioc->aic->dtor) ioc->aic->dtor(ioc->aic); @@ -90,7 +90,7 @@ struct io_context *alloc_io_context(gfp_t gfp_flags, int node) ret = kmem_cache_alloc_node(iocontext_cachep, gfp_flags, node); if (ret) { - atomic_set(&ret->refcount, 1); + atomic_long_set(&ret->refcount, 1); atomic_set(&ret->nr_tasks, 1); spin_lock_init(&ret->lock); ret->ioprio_changed = 0; @@ -151,7 +151,7 @@ struct io_context *get_io_context(gfp_t gfp_flags, int node) ret = current_io_context(gfp_flags, node); if (unlikely(!ret)) break; - } while (!atomic_inc_not_zero(&ret->refcount)); + } while (!atomic_long_inc_not_zero(&ret->refcount)); return ret; } @@ -163,8 +163,8 @@ void copy_io_context(struct io_context **pdst, struct io_context **psrc) struct io_context *dst = *pdst; if (src) { - BUG_ON(atomic_read(&src->refcount) == 0); - atomic_inc(&src->refcount); + BUG_ON(atomic_long_read(&src->refcount) == 0); + atomic_long_inc(&src->refcount); put_io_context(dst); *pdst = src; } diff --git a/block/blk-map.c b/block/blk-map.c index f103729b462f..9083cf0180cc 100644 --- a/block/blk-map.c +++ b/block/blk-map.c @@ -20,11 +20,10 @@ int blk_rq_append_bio(struct request_queue *q, struct request *rq, rq->biotail->bi_next = bio; rq->biotail = bio; - rq->data_len += bio->bi_size; + rq->__data_len += bio->bi_size; } return 0; } -EXPORT_SYMBOL(blk_rq_append_bio); static int __blk_rq_unmap_user(struct bio *bio) { @@ -116,7 +115,7 @@ int blk_rq_map_user(struct request_queue *q, struct request *rq, struct bio *bio = NULL; int ret; - if (len > (q->max_hw_sectors << 9)) + if (len > (queue_max_hw_sectors(q) << 9)) return -EINVAL; if (!len) return -EINVAL; @@ -156,7 +155,7 @@ int blk_rq_map_user(struct request_queue *q, struct request *rq, if (!bio_flagged(bio, BIO_USER_MAPPED)) rq->cmd_flags |= REQ_COPY_USER; - rq->buffer = rq->data = NULL; + rq->buffer = NULL; return 0; unmap_rq: blk_rq_unmap_user(bio); @@ -235,7 +234,7 @@ int blk_rq_map_user_iov(struct request_queue *q, struct request *rq, blk_queue_bounce(q, &bio); bio_get(bio); blk_rq_bio_prep(q, rq, bio); - rq->buffer = rq->data = NULL; + rq->buffer = NULL; return 0; } EXPORT_SYMBOL(blk_rq_map_user_iov); @@ -282,7 +281,8 @@ EXPORT_SYMBOL(blk_rq_unmap_user); * * Description: * Data will be mapped directly if possible. Otherwise a bounce - * buffer is used. + * buffer is used. Can be called multple times to append multple + * buffers. */ int blk_rq_map_kern(struct request_queue *q, struct request *rq, void *kbuf, unsigned int len, gfp_t gfp_mask) @@ -290,8 +290,9 @@ int blk_rq_map_kern(struct request_queue *q, struct request *rq, void *kbuf, int reading = rq_data_dir(rq) == READ; int do_copy = 0; struct bio *bio; + int ret; - if (len > (q->max_hw_sectors << 9)) + if (len > (queue_max_hw_sectors(q) << 9)) return -EINVAL; if (!len || !kbuf) return -EINVAL; @@ -311,9 +312,15 @@ int blk_rq_map_kern(struct request_queue *q, struct request *rq, void *kbuf, if (do_copy) rq->cmd_flags |= REQ_COPY_USER; - blk_rq_bio_prep(q, rq, bio); + ret = blk_rq_append_bio(q, rq, bio); + if (unlikely(ret)) { + /* request is too big */ + bio_put(bio); + return ret; + } + blk_queue_bounce(q, &rq->bio); - rq->buffer = rq->data = NULL; + rq->buffer = NULL; return 0; } EXPORT_SYMBOL(blk_rq_map_kern); diff --git a/block/blk-merge.c b/block/blk-merge.c index 23d2a6fe34a3..39ce64432ba6 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -9,35 +9,6 @@ #include "blk.h" -void blk_recalc_rq_sectors(struct request *rq, int nsect) -{ - if (blk_fs_request(rq) || blk_discard_rq(rq)) { - rq->hard_sector += nsect; - rq->hard_nr_sectors -= nsect; - - /* - * Move the I/O submission pointers ahead if required. - */ - if ((rq->nr_sectors >= rq->hard_nr_sectors) && - (rq->sector <= rq->hard_sector)) { - rq->sector = rq->hard_sector; - rq->nr_sectors = rq->hard_nr_sectors; - rq->hard_cur_sectors = bio_cur_sectors(rq->bio); - rq->current_nr_sectors = rq->hard_cur_sectors; - rq->buffer = bio_data(rq->bio); - } - - /* - * if total number of sectors is less than the first segment - * size, something has gone terribly wrong - */ - if (rq->nr_sectors < rq->current_nr_sectors) { - printk(KERN_ERR "blk: request botched\n"); - rq->nr_sectors = rq->current_nr_sectors; - } - } -} - static unsigned int __blk_recalc_rq_segments(struct request_queue *q, struct bio *bio) { @@ -61,11 +32,12 @@ static unsigned int __blk_recalc_rq_segments(struct request_queue *q, * never considered part of another segment, since that * might change with the bounce page. */ - high = page_to_pfn(bv->bv_page) > q->bounce_pfn; + high = page_to_pfn(bv->bv_page) > queue_bounce_pfn(q); if (high || highprv) goto new_segment; if (cluster) { - if (seg_size + bv->bv_len > q->max_segment_size) + if (seg_size + bv->bv_len + > queue_max_segment_size(q)) goto new_segment; if (!BIOVEC_PHYS_MERGEABLE(bvprv, bv)) goto new_segment; @@ -120,7 +92,7 @@ static int blk_phys_contig_segment(struct request_queue *q, struct bio *bio, return 0; if (bio->bi_seg_back_size + nxt->bi_seg_front_size > - q->max_segment_size) + queue_max_segment_size(q)) return 0; if (!bio_has_data(bio)) @@ -163,7 +135,7 @@ int blk_rq_map_sg(struct request_queue *q, struct request *rq, int nbytes = bvec->bv_len; if (bvprv && cluster) { - if (sg->length + nbytes > q->max_segment_size) + if (sg->length + nbytes > queue_max_segment_size(q)) goto new_segment; if (!BIOVEC_PHYS_MERGEABLE(bvprv, bvec)) @@ -199,8 +171,9 @@ new_segment: if (unlikely(rq->cmd_flags & REQ_COPY_USER) && - (rq->data_len & q->dma_pad_mask)) { - unsigned int pad_len = (q->dma_pad_mask & ~rq->data_len) + 1; + (blk_rq_bytes(rq) & q->dma_pad_mask)) { + unsigned int pad_len = + (q->dma_pad_mask & ~blk_rq_bytes(rq)) + 1; sg->length += pad_len; rq->extra_len += pad_len; @@ -233,8 +206,8 @@ static inline int ll_new_hw_segment(struct request_queue *q, { int nr_phys_segs = bio_phys_segments(q, bio); - if (req->nr_phys_segments + nr_phys_segs > q->max_hw_segments - || req->nr_phys_segments + nr_phys_segs > q->max_phys_segments) { + if (req->nr_phys_segments + nr_phys_segs > queue_max_hw_segments(q) || + req->nr_phys_segments + nr_phys_segs > queue_max_phys_segments(q)) { req->cmd_flags |= REQ_NOMERGE; if (req == q->last_merge) q->last_merge = NULL; @@ -255,11 +228,11 @@ int ll_back_merge_fn(struct request_queue *q, struct request *req, unsigned short max_sectors; if (unlikely(blk_pc_request(req))) - max_sectors = q->max_hw_sectors; + max_sectors = queue_max_hw_sectors(q); else - max_sectors = q->max_sectors; + max_sectors = queue_max_sectors(q); - if (req->nr_sectors + bio_sectors(bio) > max_sectors) { + if (blk_rq_sectors(req) + bio_sectors(bio) > max_sectors) { req->cmd_flags |= REQ_NOMERGE; if (req == q->last_merge) q->last_merge = NULL; @@ -279,12 +252,12 @@ int ll_front_merge_fn(struct request_queue *q, struct request *req, unsigned short max_sectors; if (unlikely(blk_pc_request(req))) - max_sectors = q->max_hw_sectors; + max_sectors = queue_max_hw_sectors(q); else - max_sectors = q->max_sectors; + max_sectors = queue_max_sectors(q); - if (req->nr_sectors + bio_sectors(bio) > max_sectors) { + if (blk_rq_sectors(req) + bio_sectors(bio) > max_sectors) { req->cmd_flags |= REQ_NOMERGE; if (req == q->last_merge) q->last_merge = NULL; @@ -315,7 +288,7 @@ static int ll_merge_requests_fn(struct request_queue *q, struct request *req, /* * Will it become too large? */ - if ((req->nr_sectors + next->nr_sectors) > q->max_sectors) + if ((blk_rq_sectors(req) + blk_rq_sectors(next)) > queue_max_sectors(q)) return 0; total_phys_segments = req->nr_phys_segments + next->nr_phys_segments; @@ -327,10 +300,10 @@ static int ll_merge_requests_fn(struct request_queue *q, struct request *req, total_phys_segments--; } - if (total_phys_segments > q->max_phys_segments) + if (total_phys_segments > queue_max_phys_segments(q)) return 0; - if (total_phys_segments > q->max_hw_segments) + if (total_phys_segments > queue_max_hw_segments(q)) return 0; /* Merge is OK... */ @@ -345,7 +318,7 @@ static void blk_account_io_merge(struct request *req) int cpu; cpu = part_stat_lock(); - part = disk_map_sector_rcu(req->rq_disk, req->sector); + part = disk_map_sector_rcu(req->rq_disk, blk_rq_pos(req)); part_round_stats(cpu, part); part_dec_in_flight(part); @@ -366,7 +339,7 @@ static int attempt_merge(struct request_queue *q, struct request *req, /* * not contiguous */ - if (req->sector + req->nr_sectors != next->sector) + if (blk_rq_pos(req) + blk_rq_sectors(req) != blk_rq_pos(next)) return 0; if (rq_data_dir(req) != rq_data_dir(next) @@ -398,7 +371,7 @@ static int attempt_merge(struct request_queue *q, struct request *req, req->biotail->bi_next = next->bio; req->biotail = next->biotail; - req->nr_sectors = req->hard_nr_sectors += next->hard_nr_sectors; + req->__data_len += blk_rq_bytes(next); elv_merge_requests(q, req, next); diff --git a/block/blk-settings.c b/block/blk-settings.c index 57af728d94bb..bd582a7f5310 100644 --- a/block/blk-settings.c +++ b/block/blk-settings.c @@ -95,6 +95,31 @@ void blk_queue_lld_busy(struct request_queue *q, lld_busy_fn *fn) } EXPORT_SYMBOL_GPL(blk_queue_lld_busy); +/** + * blk_set_default_limits - reset limits to default values + * @lim: the queue_limits structure to reset + * + * Description: + * Returns a queue_limit struct to its default state. Can be used by + * stacking drivers like DM that stage table swaps and reuse an + * existing device queue. + */ +void blk_set_default_limits(struct queue_limits *lim) +{ + lim->max_phys_segments = MAX_PHYS_SEGMENTS; + lim->max_hw_segments = MAX_HW_SEGMENTS; + lim->seg_boundary_mask = BLK_SEG_BOUNDARY_MASK; + lim->max_segment_size = MAX_SEGMENT_SIZE; + lim->max_sectors = lim->max_hw_sectors = SAFE_MAX_SECTORS; + lim->logical_block_size = lim->physical_block_size = lim->io_min = 512; + lim->bounce_pfn = (unsigned long)(BLK_BOUNCE_ANY >> PAGE_SHIFT); + lim->alignment_offset = 0; + lim->io_opt = 0; + lim->misaligned = 0; + lim->no_cluster = 0; +} +EXPORT_SYMBOL(blk_set_default_limits); + /** * blk_queue_make_request - define an alternate make_request function for a device * @q: the request queue for the device to be affected @@ -123,18 +148,8 @@ void blk_queue_make_request(struct request_queue *q, make_request_fn *mfn) * set defaults */ q->nr_requests = BLKDEV_MAX_RQ; - blk_queue_max_phys_segments(q, MAX_PHYS_SEGMENTS); - blk_queue_max_hw_segments(q, MAX_HW_SEGMENTS); - blk_queue_segment_boundary(q, BLK_SEG_BOUNDARY_MASK); - blk_queue_max_segment_size(q, MAX_SEGMENT_SIZE); q->make_request_fn = mfn; - q->backing_dev_info.ra_pages = - (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE; - q->backing_dev_info.state = 0; - q->backing_dev_info.capabilities = BDI_CAP_MAP_COPY; - blk_queue_max_sectors(q, SAFE_MAX_SECTORS); - blk_queue_hardsect_size(q, 512); blk_queue_dma_alignment(q, 511); blk_queue_congestion_threshold(q); q->nr_batching = BLK_BATCH_REQ; @@ -147,6 +162,8 @@ void blk_queue_make_request(struct request_queue *q, make_request_fn *mfn) q->unplug_timer.function = blk_unplug_timeout; q->unplug_timer.data = (unsigned long)q; + blk_set_default_limits(&q->limits); + /* * by default assume old behaviour and bounce for any highmem page */ @@ -179,16 +196,16 @@ void blk_queue_bounce_limit(struct request_queue *q, u64 dma_mask) */ if (b_pfn < (min_t(u64, 0xffffffffUL, BLK_BOUNCE_HIGH) >> PAGE_SHIFT)) dma = 1; - q->bounce_pfn = max_low_pfn; + q->limits.bounce_pfn = max_low_pfn; #else if (b_pfn < blk_max_low_pfn) dma = 1; - q->bounce_pfn = b_pfn; + q->limits.bounce_pfn = b_pfn; #endif if (dma) { init_emergency_isa_pool(); q->bounce_gfp = GFP_NOIO | GFP_DMA; - q->bounce_pfn = b_pfn; + q->limits.bounce_pfn = b_pfn; } } EXPORT_SYMBOL(blk_queue_bounce_limit); @@ -211,14 +228,23 @@ void blk_queue_max_sectors(struct request_queue *q, unsigned int max_sectors) } if (BLK_DEF_MAX_SECTORS > max_sectors) - q->max_hw_sectors = q->max_sectors = max_sectors; + q->limits.max_hw_sectors = q->limits.max_sectors = max_sectors; else { - q->max_sectors = BLK_DEF_MAX_SECTORS; - q->max_hw_sectors = max_sectors; + q->limits.max_sectors = BLK_DEF_MAX_SECTORS; + q->limits.max_hw_sectors = max_sectors; } } EXPORT_SYMBOL(blk_queue_max_sectors); +void blk_queue_max_hw_sectors(struct request_queue *q, unsigned int max_sectors) +{ + if (BLK_DEF_MAX_SECTORS > max_sectors) + q->limits.max_hw_sectors = BLK_DEF_MAX_SECTORS; + else + q->limits.max_hw_sectors = max_sectors; +} +EXPORT_SYMBOL(blk_queue_max_hw_sectors); + /** * blk_queue_max_phys_segments - set max phys segments for a request for this queue * @q: the request queue for the device @@ -238,7 +264,7 @@ void blk_queue_max_phys_segments(struct request_queue *q, __func__, max_segments); } - q->max_phys_segments = max_segments; + q->limits.max_phys_segments = max_segments; } EXPORT_SYMBOL(blk_queue_max_phys_segments); @@ -262,7 +288,7 @@ void blk_queue_max_hw_segments(struct request_queue *q, __func__, max_segments); } - q->max_hw_segments = max_segments; + q->limits.max_hw_segments = max_segments; } EXPORT_SYMBOL(blk_queue_max_hw_segments); @@ -283,26 +309,110 @@ void blk_queue_max_segment_size(struct request_queue *q, unsigned int max_size) __func__, max_size); } - q->max_segment_size = max_size; + q->limits.max_segment_size = max_size; } EXPORT_SYMBOL(blk_queue_max_segment_size); /** - * blk_queue_hardsect_size - set hardware sector size for the queue + * blk_queue_logical_block_size - set logical block size for the queue * @q: the request queue for the device - * @size: the hardware sector size, in bytes + * @size: the logical block size, in bytes * * Description: - * This should typically be set to the lowest possible sector size - * that the hardware can operate on (possible without reverting to - * even internal read-modify-write operations). Usually the default - * of 512 covers most hardware. + * This should be set to the lowest possible block size that the + * storage device can address. The default of 512 covers most + * hardware. **/ -void blk_queue_hardsect_size(struct request_queue *q, unsigned short size) +void blk_queue_logical_block_size(struct request_queue *q, unsigned short size) { - q->hardsect_size = size; + q->limits.logical_block_size = size; + + if (q->limits.physical_block_size < size) + q->limits.physical_block_size = size; + + if (q->limits.io_min < q->limits.physical_block_size) + q->limits.io_min = q->limits.physical_block_size; } -EXPORT_SYMBOL(blk_queue_hardsect_size); +EXPORT_SYMBOL(blk_queue_logical_block_size); + +/** + * blk_queue_physical_block_size - set physical block size for the queue + * @q: the request queue for the device + * @size: the physical block size, in bytes + * + * Description: + * This should be set to the lowest possible sector size that the + * hardware can operate on without reverting to read-modify-write + * operations. + */ +void blk_queue_physical_block_size(struct request_queue *q, unsigned short size) +{ + q->limits.physical_block_size = size; + + if (q->limits.physical_block_size < q->limits.logical_block_size) + q->limits.physical_block_size = q->limits.logical_block_size; + + if (q->limits.io_min < q->limits.physical_block_size) + q->limits.io_min = q->limits.physical_block_size; +} +EXPORT_SYMBOL(blk_queue_physical_block_size); + +/** + * blk_queue_alignment_offset - set physical block alignment offset + * @q: the request queue for the device + * @offset: alignment offset in bytes + * + * Description: + * Some devices are naturally misaligned to compensate for things like + * the legacy DOS partition table 63-sector offset. Low-level drivers + * should call this function for devices whose first sector is not + * naturally aligned. + */ +void blk_queue_alignment_offset(struct request_queue *q, unsigned int offset) +{ + q->limits.alignment_offset = + offset & (q->limits.physical_block_size - 1); + q->limits.misaligned = 0; +} +EXPORT_SYMBOL(blk_queue_alignment_offset); + +/** + * blk_queue_io_min - set minimum request size for the queue + * @q: the request queue for the device + * @min: smallest I/O size in bytes + * + * Description: + * Some devices have an internal block size bigger than the reported + * hardware sector size. This function can be used to signal the + * smallest I/O the device can perform without incurring a performance + * penalty. + */ +void blk_queue_io_min(struct request_queue *q, unsigned int min) +{ + q->limits.io_min = min; + + if (q->limits.io_min < q->limits.logical_block_size) + q->limits.io_min = q->limits.logical_block_size; + + if (q->limits.io_min < q->limits.physical_block_size) + q->limits.io_min = q->limits.physical_block_size; +} +EXPORT_SYMBOL(blk_queue_io_min); + +/** + * blk_queue_io_opt - set optimal request size for the queue + * @q: the request queue for the device + * @opt: optimal request size in bytes + * + * Description: + * Drivers can call this function to set the preferred I/O request + * size for devices that report such a value. + */ +void blk_queue_io_opt(struct request_queue *q, unsigned int opt) +{ + q->limits.io_opt = opt; +} +EXPORT_SYMBOL(blk_queue_io_opt); /* * Returns the minimum that is _not_ zero, unless both are zero. @@ -317,14 +427,27 @@ EXPORT_SYMBOL(blk_queue_hardsect_size); void blk_queue_stack_limits(struct request_queue *t, struct request_queue *b) { /* zero is "infinity" */ - t->max_sectors = min_not_zero(t->max_sectors, b->max_sectors); - t->max_hw_sectors = min_not_zero(t->max_hw_sectors, b->max_hw_sectors); - t->seg_boundary_mask = min_not_zero(t->seg_boundary_mask, b->seg_boundary_mask); + t->limits.max_sectors = min_not_zero(queue_max_sectors(t), + queue_max_sectors(b)); + + t->limits.max_hw_sectors = min_not_zero(queue_max_hw_sectors(t), + queue_max_hw_sectors(b)); + + t->limits.seg_boundary_mask = min_not_zero(queue_segment_boundary(t), + queue_segment_boundary(b)); + + t->limits.max_phys_segments = min_not_zero(queue_max_phys_segments(t), + queue_max_phys_segments(b)); + + t->limits.max_hw_segments = min_not_zero(queue_max_hw_segments(t), + queue_max_hw_segments(b)); + + t->limits.max_segment_size = min_not_zero(queue_max_segment_size(t), + queue_max_segment_size(b)); + + t->limits.logical_block_size = max(queue_logical_block_size(t), + queue_logical_block_size(b)); - t->max_phys_segments = min_not_zero(t->max_phys_segments, b->max_phys_segments); - t->max_hw_segments = min_not_zero(t->max_hw_segments, b->max_hw_segments); - t->max_segment_size = min_not_zero(t->max_segment_size, b->max_segment_size); - t->hardsect_size = max(t->hardsect_size, b->hardsect_size); if (!t->queue_lock) WARN_ON_ONCE(1); else if (!test_bit(QUEUE_FLAG_CLUSTER, &b->queue_flags)) { @@ -336,6 +459,109 @@ void blk_queue_stack_limits(struct request_queue *t, struct request_queue *b) } EXPORT_SYMBOL(blk_queue_stack_limits); +/** + * blk_stack_limits - adjust queue_limits for stacked devices + * @t: the stacking driver limits (top) + * @b: the underlying queue limits (bottom) + * @offset: offset to beginning of data within component device + * + * Description: + * Merges two queue_limit structs. Returns 0 if alignment didn't + * change. Returns -1 if adding the bottom device caused + * misalignment. + */ +int blk_stack_limits(struct queue_limits *t, struct queue_limits *b, + sector_t offset) +{ + t->max_sectors = min_not_zero(t->max_sectors, b->max_sectors); + t->max_hw_sectors = min_not_zero(t->max_hw_sectors, b->max_hw_sectors); + t->bounce_pfn = min_not_zero(t->bounce_pfn, b->bounce_pfn); + + t->seg_boundary_mask = min_not_zero(t->seg_boundary_mask, + b->seg_boundary_mask); + + t->max_phys_segments = min_not_zero(t->max_phys_segments, + b->max_phys_segments); + + t->max_hw_segments = min_not_zero(t->max_hw_segments, + b->max_hw_segments); + + t->max_segment_size = min_not_zero(t->max_segment_size, + b->max_segment_size); + + t->logical_block_size = max(t->logical_block_size, + b->logical_block_size); + + t->physical_block_size = max(t->physical_block_size, + b->physical_block_size); + + t->io_min = max(t->io_min, b->io_min); + t->no_cluster |= b->no_cluster; + + /* Bottom device offset aligned? */ + if (offset && + (offset & (b->physical_block_size - 1)) != b->alignment_offset) { + t->misaligned = 1; + return -1; + } + + /* If top has no alignment offset, inherit from bottom */ + if (!t->alignment_offset) + t->alignment_offset = + b->alignment_offset & (b->physical_block_size - 1); + + /* Top device aligned on logical block boundary? */ + if (t->alignment_offset & (t->logical_block_size - 1)) { + t->misaligned = 1; + return -1; + } + + return 0; +} +EXPORT_SYMBOL(blk_stack_limits); + +/** + * disk_stack_limits - adjust queue limits for stacked drivers + * @disk: MD/DM gendisk (top) + * @bdev: the underlying block device (bottom) + * @offset: offset to beginning of data within component device + * + * Description: + * Merges the limits for two queues. Returns 0 if alignment + * didn't change. Returns -1 if adding the bottom device caused + * misalignment. + */ +void disk_stack_limits(struct gendisk *disk, struct block_device *bdev, + sector_t offset) +{ + struct request_queue *t = disk->queue; + struct request_queue *b = bdev_get_queue(bdev); + + offset += get_start_sect(bdev) << 9; + + if (blk_stack_limits(&t->limits, &b->limits, offset) < 0) { + char top[BDEVNAME_SIZE], bottom[BDEVNAME_SIZE]; + + disk_name(disk, 0, top); + bdevname(bdev, bottom); + + printk(KERN_NOTICE "%s: Warning: Device %s is misaligned\n", + top, bottom); + } + + if (!t->queue_lock) + WARN_ON_ONCE(1); + else if (!test_bit(QUEUE_FLAG_CLUSTER, &b->queue_flags)) { + unsigned long flags; + + spin_lock_irqsave(t->queue_lock, flags); + if (!test_bit(QUEUE_FLAG_CLUSTER, &b->queue_flags)) + queue_flag_clear(QUEUE_FLAG_CLUSTER, t); + spin_unlock_irqrestore(t->queue_lock, flags); + } +} +EXPORT_SYMBOL(disk_stack_limits); + /** * blk_queue_dma_pad - set pad mask * @q: the request queue for the device @@ -396,11 +622,11 @@ int blk_queue_dma_drain(struct request_queue *q, dma_drain_needed_fn *dma_drain_needed, void *buf, unsigned int size) { - if (q->max_hw_segments < 2 || q->max_phys_segments < 2) + if (queue_max_hw_segments(q) < 2 || queue_max_phys_segments(q) < 2) return -EINVAL; /* make room for appending the drain */ - --q->max_hw_segments; - --q->max_phys_segments; + blk_queue_max_hw_segments(q, queue_max_hw_segments(q) - 1); + blk_queue_max_phys_segments(q, queue_max_phys_segments(q) - 1); q->dma_drain_needed = dma_drain_needed; q->dma_drain_buffer = buf; q->dma_drain_size = size; @@ -422,7 +648,7 @@ void blk_queue_segment_boundary(struct request_queue *q, unsigned long mask) __func__, mask); } - q->seg_boundary_mask = mask; + q->limits.seg_boundary_mask = mask; } EXPORT_SYMBOL(blk_queue_segment_boundary); diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c index 3ff9bba3379a..b1cd04087d6a 100644 --- a/block/blk-sysfs.c +++ b/block/blk-sysfs.c @@ -95,21 +95,36 @@ queue_ra_store(struct request_queue *q, const char *page, size_t count) static ssize_t queue_max_sectors_show(struct request_queue *q, char *page) { - int max_sectors_kb = q->max_sectors >> 1; + int max_sectors_kb = queue_max_sectors(q) >> 1; return queue_var_show(max_sectors_kb, (page)); } -static ssize_t queue_hw_sector_size_show(struct request_queue *q, char *page) +static ssize_t queue_logical_block_size_show(struct request_queue *q, char *page) { - return queue_var_show(q->hardsect_size, page); + return queue_var_show(queue_logical_block_size(q), page); +} + +static ssize_t queue_physical_block_size_show(struct request_queue *q, char *page) +{ + return queue_var_show(queue_physical_block_size(q), page); +} + +static ssize_t queue_io_min_show(struct request_queue *q, char *page) +{ + return queue_var_show(queue_io_min(q), page); +} + +static ssize_t queue_io_opt_show(struct request_queue *q, char *page) +{ + return queue_var_show(queue_io_opt(q), page); } static ssize_t queue_max_sectors_store(struct request_queue *q, const char *page, size_t count) { unsigned long max_sectors_kb, - max_hw_sectors_kb = q->max_hw_sectors >> 1, + max_hw_sectors_kb = queue_max_hw_sectors(q) >> 1, page_kb = 1 << (PAGE_CACHE_SHIFT - 10); ssize_t ret = queue_var_store(&max_sectors_kb, page, count); @@ -117,7 +132,7 @@ queue_max_sectors_store(struct request_queue *q, const char *page, size_t count) return -EINVAL; spin_lock_irq(q->queue_lock); - q->max_sectors = max_sectors_kb << 1; + blk_queue_max_sectors(q, max_sectors_kb << 1); spin_unlock_irq(q->queue_lock); return ret; @@ -125,7 +140,7 @@ queue_max_sectors_store(struct request_queue *q, const char *page, size_t count) static ssize_t queue_max_hw_sectors_show(struct request_queue *q, char *page) { - int max_hw_sectors_kb = q->max_hw_sectors >> 1; + int max_hw_sectors_kb = queue_max_hw_sectors(q) >> 1; return queue_var_show(max_hw_sectors_kb, (page)); } @@ -249,7 +264,27 @@ static struct queue_sysfs_entry queue_iosched_entry = { static struct queue_sysfs_entry queue_hw_sector_size_entry = { .attr = {.name = "hw_sector_size", .mode = S_IRUGO }, - .show = queue_hw_sector_size_show, + .show = queue_logical_block_size_show, +}; + +static struct queue_sysfs_entry queue_logical_block_size_entry = { + .attr = {.name = "logical_block_size", .mode = S_IRUGO }, + .show = queue_logical_block_size_show, +}; + +static struct queue_sysfs_entry queue_physical_block_size_entry = { + .attr = {.name = "physical_block_size", .mode = S_IRUGO }, + .show = queue_physical_block_size_show, +}; + +static struct queue_sysfs_entry queue_io_min_entry = { + .attr = {.name = "minimum_io_size", .mode = S_IRUGO }, + .show = queue_io_min_show, +}; + +static struct queue_sysfs_entry queue_io_opt_entry = { + .attr = {.name = "optimal_io_size", .mode = S_IRUGO }, + .show = queue_io_opt_show, }; static struct queue_sysfs_entry queue_nonrot_entry = { @@ -283,6 +318,10 @@ static struct attribute *default_attrs[] = { &queue_max_sectors_entry.attr, &queue_iosched_entry.attr, &queue_hw_sector_size_entry.attr, + &queue_logical_block_size_entry.attr, + &queue_physical_block_size_entry.attr, + &queue_io_min_entry.attr, + &queue_io_opt_entry.attr, &queue_nonrot_entry.attr, &queue_nomerges_entry.attr, &queue_rq_affinity_entry.attr, @@ -383,22 +422,26 @@ struct kobj_type blk_queue_ktype = { int blk_register_queue(struct gendisk *disk) { int ret; + struct device *dev = disk_to_dev(disk); struct request_queue *q = disk->queue; if (WARN_ON(!q)) return -ENXIO; - if (!q->request_fn) - return 0; + ret = blk_trace_init_sysfs(dev); + if (ret) + return ret; - ret = kobject_add(&q->kobj, kobject_get(&disk_to_dev(disk)->kobj), - "%s", "queue"); + ret = kobject_add(&q->kobj, kobject_get(&dev->kobj), "%s", "queue"); if (ret < 0) return ret; kobject_uevent(&q->kobj, KOBJ_ADD); + if (!q->request_fn) + return 0; + ret = elv_register_queue(q); if (ret) { kobject_uevent(&q->kobj, KOBJ_REMOVE); diff --git a/block/blk-tag.c b/block/blk-tag.c index 3c518e3303ae..2e5cfeb59333 100644 --- a/block/blk-tag.c +++ b/block/blk-tag.c @@ -336,7 +336,7 @@ EXPORT_SYMBOL(blk_queue_end_tag); int blk_queue_start_tag(struct request_queue *q, struct request *rq) { struct blk_queue_tag *bqt = q->queue_tags; - unsigned max_depth, offset; + unsigned max_depth; int tag; if (unlikely((rq->cmd_flags & REQ_QUEUED))) { @@ -355,13 +355,16 @@ int blk_queue_start_tag(struct request_queue *q, struct request *rq) * to starve sync IO on behalf of flooding async IO. */ max_depth = bqt->max_depth; - if (rq_is_sync(rq)) - offset = 0; - else - offset = max_depth >> 2; + if (!rq_is_sync(rq) && max_depth > 1) { + max_depth -= 2; + if (!max_depth) + max_depth = 1; + if (q->in_flight[0] > max_depth) + return 1; + } do { - tag = find_next_zero_bit(bqt->tag_map, max_depth, offset); + tag = find_first_zero_bit(bqt->tag_map, max_depth); if (tag >= max_depth) return 1; @@ -374,7 +377,7 @@ int blk_queue_start_tag(struct request_queue *q, struct request *rq) rq->cmd_flags |= REQ_QUEUED; rq->tag = tag; bqt->tag_index[tag] = rq; - blkdev_dequeue_request(rq); + blk_start_request(rq); list_add(&rq->queuelist, &q->tag_busy_list); return 0; } diff --git a/block/blk-timeout.c b/block/blk-timeout.c index 1ec0d503cacd..1ba7e0aca878 100644 --- a/block/blk-timeout.c +++ b/block/blk-timeout.c @@ -122,10 +122,8 @@ void blk_rq_timed_out_timer(unsigned long data) if (blk_mark_rq_complete(rq)) continue; blk_rq_timed_out(rq); - } else { - if (!next || time_after(next, rq->deadline)) - next = rq->deadline; - } + } else if (!next || time_after(next, rq->deadline)) + next = rq->deadline; } /* @@ -176,16 +174,14 @@ void blk_add_timer(struct request *req) BUG_ON(!list_empty(&req->timeout_list)); BUG_ON(test_bit(REQ_ATOM_COMPLETE, &req->atomic_flags)); - if (req->timeout) - req->deadline = jiffies + req->timeout; - else { - req->deadline = jiffies + q->rq_timeout; - /* - * Some LLDs, like scsi, peek at the timeout to prevent - * a command from being retried forever. - */ + /* + * Some LLDs, like scsi, peek at the timeout to prevent a + * command from being retried forever. + */ + if (!req->timeout) req->timeout = q->rq_timeout; - } + + req->deadline = jiffies + req->timeout; list_add_tail(&req->timeout_list, &q->timeout_list); /* diff --git a/block/blk.h b/block/blk.h index 79c85f7c9ff5..3fae6add5430 100644 --- a/block/blk.h +++ b/block/blk.h @@ -13,6 +13,9 @@ extern struct kobj_type blk_queue_ktype; void init_request_from_bio(struct request *req, struct bio *bio); void blk_rq_bio_prep(struct request_queue *q, struct request *rq, struct bio *bio); +int blk_rq_append_bio(struct request_queue *q, struct request *rq, + struct bio *bio); +void blk_dequeue_request(struct request *rq); void __blk_queue_free_tags(struct request_queue *q); void blk_unplug_work(struct work_struct *work); @@ -43,6 +46,43 @@ static inline void blk_clear_rq_complete(struct request *rq) clear_bit(REQ_ATOM_COMPLETE, &rq->atomic_flags); } +/* + * Internal elevator interface + */ +#define ELV_ON_HASH(rq) (!hlist_unhashed(&(rq)->hash)) + +static inline struct request *__elv_next_request(struct request_queue *q) +{ + struct request *rq; + + while (1) { + while (!list_empty(&q->queue_head)) { + rq = list_entry_rq(q->queue_head.next); + if (blk_do_ordered(q, &rq)) + return rq; + } + + if (!q->elevator->ops->elevator_dispatch_fn(q, 0)) + return NULL; + } +} + +static inline void elv_activate_rq(struct request_queue *q, struct request *rq) +{ + struct elevator_queue *e = q->elevator; + + if (e->ops->elevator_activate_req_fn) + e->ops->elevator_activate_req_fn(q, rq); +} + +static inline void elv_deactivate_rq(struct request_queue *q, struct request *rq) +{ + struct elevator_queue *e = q->elevator; + + if (e->ops->elevator_deactivate_req_fn) + e->ops->elevator_deactivate_req_fn(q, rq); +} + #ifdef CONFIG_FAIL_IO_TIMEOUT int blk_should_fake_timeout(struct request_queue *); ssize_t part_timeout_show(struct device *, struct device_attribute *, char *); @@ -64,7 +104,6 @@ int ll_front_merge_fn(struct request_queue *q, struct request *req, int attempt_back_merge(struct request_queue *q, struct request *rq); int attempt_front_merge(struct request_queue *q, struct request *rq); void blk_recalc_rq_segments(struct request *rq); -void blk_recalc_rq_sectors(struct request *rq, int nsect); void blk_queue_congestion_threshold(struct request_queue *q); @@ -112,9 +151,17 @@ static inline int blk_cpu_to_group(int cpu) #endif } +/* + * Contribute to IO statistics IFF: + * + * a) it's attached to a gendisk, and + * b) the queue had IO stats enabled when this request was started, and + * c) it's a file system request or a discard request + */ static inline int blk_do_io_stat(struct request *rq) { - return rq->rq_disk && blk_rq_io_stat(rq); + return rq->rq_disk && blk_rq_io_stat(rq) && + (blk_fs_request(rq) || blk_discard_rq(rq)); } #endif diff --git a/block/bsg.c b/block/bsg.c index dd81be455e00..e7d475254248 100644 --- a/block/bsg.c +++ b/block/bsg.c @@ -315,7 +315,6 @@ out: blk_put_request(rq); if (next_rq) { blk_rq_unmap_user(next_rq->bio); - next_rq->bio = NULL; blk_put_request(next_rq); } return ERR_PTR(ret); @@ -446,15 +445,14 @@ static int blk_complete_sgv4_hdr_rq(struct request *rq, struct sg_io_v4 *hdr, } if (rq->next_rq) { - hdr->dout_resid = rq->data_len; - hdr->din_resid = rq->next_rq->data_len; + hdr->dout_resid = rq->resid_len; + hdr->din_resid = rq->next_rq->resid_len; blk_rq_unmap_user(bidi_bio); - rq->next_rq->bio = NULL; blk_put_request(rq->next_rq); } else if (rq_data_dir(rq) == READ) - hdr->din_resid = rq->data_len; + hdr->din_resid = rq->resid_len; else - hdr->dout_resid = rq->data_len; + hdr->dout_resid = rq->resid_len; /* * If the request generated a negative error number, return it @@ -468,7 +466,6 @@ static int blk_complete_sgv4_hdr_rq(struct request *rq, struct sg_io_v4 *hdr, blk_rq_unmap_user(bio); if (rq->cmd != rq->__cmd) kfree(rq->cmd); - rq->bio = NULL; blk_put_request(rq); return ret; @@ -1065,6 +1062,11 @@ EXPORT_SYMBOL_GPL(bsg_register_queue); static struct cdev bsg_cdev; +static char *bsg_nodename(struct device *dev) +{ + return kasprintf(GFP_KERNEL, "bsg/%s", dev_name(dev)); +} + static int __init bsg_init(void) { int ret, i; @@ -1085,6 +1087,7 @@ static int __init bsg_init(void) ret = PTR_ERR(bsg_class); goto destroy_kmemcache; } + bsg_class->nodename = bsg_nodename; ret = alloc_chrdev_region(&devid, 0, BSG_MAX_DEVS, "bsg"); if (ret) diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index a55a9bd75bd1..833ec18eaa63 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -122,7 +122,6 @@ struct cfq_data { struct cfq_queue *async_idle_cfqq; sector_t last_position; - unsigned long last_end_request; /* * tunables, see top of file @@ -349,8 +348,8 @@ cfq_choose_req(struct cfq_data *cfqd, struct request *rq1, struct request *rq2) else if (rq_is_meta(rq2) && !rq_is_meta(rq1)) return rq2; - s1 = rq1->sector; - s2 = rq2->sector; + s1 = blk_rq_pos(rq1); + s2 = blk_rq_pos(rq2); last = cfqd->last_position; @@ -579,9 +578,9 @@ cfq_prio_tree_lookup(struct cfq_data *cfqd, struct rb_root *root, * Sort strictly based on sector. Smallest to the left, * largest to the right. */ - if (sector > cfqq->next_rq->sector) + if (sector > blk_rq_pos(cfqq->next_rq)) n = &(*p)->rb_right; - else if (sector < cfqq->next_rq->sector) + else if (sector < blk_rq_pos(cfqq->next_rq)) n = &(*p)->rb_left; else break; @@ -611,8 +610,8 @@ static void cfq_prio_tree_add(struct cfq_data *cfqd, struct cfq_queue *cfqq) return; cfqq->p_root = &cfqd->prio_trees[cfqq->org_ioprio]; - __cfqq = cfq_prio_tree_lookup(cfqd, cfqq->p_root, cfqq->next_rq->sector, - &parent, &p); + __cfqq = cfq_prio_tree_lookup(cfqd, cfqq->p_root, + blk_rq_pos(cfqq->next_rq), &parent, &p); if (!__cfqq) { rb_link_node(&cfqq->p_node, parent, p); rb_insert_color(&cfqq->p_node, cfqq->p_root); @@ -760,7 +759,7 @@ static void cfq_activate_request(struct request_queue *q, struct request *rq) cfq_log_cfqq(cfqd, RQ_CFQQ(rq), "activate rq, drv=%d", cfqd->rq_in_driver); - cfqd->last_position = rq->hard_sector + rq->hard_nr_sectors; + cfqd->last_position = blk_rq_pos(rq) + blk_rq_sectors(rq); } static void cfq_deactivate_request(struct request_queue *q, struct request *rq) @@ -949,10 +948,10 @@ static struct cfq_queue *cfq_set_active_queue(struct cfq_data *cfqd, static inline sector_t cfq_dist_from_last(struct cfq_data *cfqd, struct request *rq) { - if (rq->sector >= cfqd->last_position) - return rq->sector - cfqd->last_position; + if (blk_rq_pos(rq) >= cfqd->last_position) + return blk_rq_pos(rq) - cfqd->last_position; else - return cfqd->last_position - rq->sector; + return cfqd->last_position - blk_rq_pos(rq); } #define CIC_SEEK_THR 8 * 1024 @@ -996,7 +995,7 @@ static struct cfq_queue *cfqq_close(struct cfq_data *cfqd, if (cfq_rq_close(cfqd, __cfqq->next_rq)) return __cfqq; - if (__cfqq->next_rq->sector < sector) + if (blk_rq_pos(__cfqq->next_rq) < sector) node = rb_next(&__cfqq->p_node); else node = rb_prev(&__cfqq->p_node); @@ -1253,7 +1252,7 @@ static int cfq_forced_dispatch(struct cfq_data *cfqd) BUG_ON(cfqd->busy_queues); - cfq_log(cfqd, "forced_dispatch=%d\n", dispatched); + cfq_log(cfqd, "forced_dispatch=%d", dispatched); return dispatched; } @@ -1282,7 +1281,7 @@ static void cfq_dispatch_request(struct cfq_data *cfqd, struct cfq_queue *cfqq) if (!cfqd->active_cic) { struct cfq_io_context *cic = RQ_CIC(rq); - atomic_inc(&cic->ioc->refcount); + atomic_long_inc(&cic->ioc->refcount); cfqd->active_cic = cic; } } @@ -1918,10 +1917,10 @@ cfq_update_io_seektime(struct cfq_data *cfqd, struct cfq_io_context *cic, if (!cic->last_request_pos) sdist = 0; - else if (cic->last_request_pos < rq->sector) - sdist = rq->sector - cic->last_request_pos; + else if (cic->last_request_pos < blk_rq_pos(rq)) + sdist = blk_rq_pos(rq) - cic->last_request_pos; else - sdist = cic->last_request_pos - rq->sector; + sdist = cic->last_request_pos - blk_rq_pos(rq); /* * Don't allow the seek distance to get too large from the @@ -2071,7 +2070,7 @@ cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq, cfq_update_io_seektime(cfqd, cic, rq); cfq_update_idle_window(cfqd, cfqq, cic); - cic->last_request_pos = rq->sector + rq->nr_sectors; + cic->last_request_pos = blk_rq_pos(rq) + blk_rq_sectors(rq); if (cfqq == cfqd->active_queue) { /* @@ -2088,7 +2087,7 @@ cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq, if (blk_rq_bytes(rq) > PAGE_CACHE_SIZE || cfqd->busy_queues > 1) { del_timer(&cfqd->idle_slice_timer); - blk_start_queueing(cfqd->queue); + __blk_run_queue(cfqd->queue); } cfq_mark_cfqq_must_dispatch(cfqq); } @@ -2100,7 +2099,7 @@ cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq, * this new queue is RT and the current one is BE */ cfq_preempt_queue(cfqd, cfqq); - blk_start_queueing(cfqd->queue); + __blk_run_queue(cfqd->queue); } } @@ -2164,9 +2163,6 @@ static void cfq_completed_request(struct request_queue *q, struct request *rq) if (cfq_cfqq_sync(cfqq)) cfqd->sync_flight--; - if (!cfq_class_idle(cfqq)) - cfqd->last_end_request = now; - if (sync) RQ_CIC(rq)->last_end_request = now; @@ -2345,7 +2341,7 @@ static void cfq_kick_queue(struct work_struct *work) struct request_queue *q = cfqd->queue; spin_lock_irq(q->queue_lock); - blk_start_queueing(q); + __blk_run_queue(cfqd->queue); spin_unlock_irq(q->queue_lock); } @@ -2479,7 +2475,6 @@ static void *cfq_init_queue(struct request_queue *q) INIT_WORK(&cfqd->unplug_work, cfq_kick_queue); - cfqd->last_end_request = jiffies; cfqd->cfq_quantum = cfq_quantum; cfqd->cfq_fifo_expire[0] = cfq_fifo_expire[0]; cfqd->cfq_fifo_expire[1] = cfq_fifo_expire[1]; diff --git a/block/compat_ioctl.c b/block/compat_ioctl.c index f87615dea46b..7865a34e0faa 100644 --- a/block/compat_ioctl.c +++ b/block/compat_ioctl.c @@ -568,7 +568,7 @@ static int compat_blk_trace_setup(struct block_device *bdev, char __user *arg) memcpy(&buts.name, &cbuts.name, 32); mutex_lock(&bdev->bd_mutex); - ret = do_blk_trace_setup(q, b, bdev->bd_dev, &buts); + ret = do_blk_trace_setup(q, b, bdev->bd_dev, bdev, &buts); mutex_unlock(&bdev->bd_mutex); if (ret) return ret; @@ -763,10 +763,10 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg) case BLKBSZGET_32: /* get the logical block size (cf. BLKSSZGET) */ return compat_put_int(arg, block_size(bdev)); case BLKSSZGET: /* get block device hardware sector size */ - return compat_put_int(arg, bdev_hardsect_size(bdev)); + return compat_put_int(arg, bdev_logical_block_size(bdev)); case BLKSECTGET: return compat_put_ushort(arg, - bdev_get_queue(bdev)->max_sectors); + queue_max_sectors(bdev_get_queue(bdev))); case BLKRASET: /* compatible, but no compat_ptr (!) */ case BLKFRASET: if (!capable(CAP_SYS_ADMIN)) diff --git a/block/deadline-iosched.c b/block/deadline-iosched.c index c4d991d4adef..b547cbca7b23 100644 --- a/block/deadline-iosched.c +++ b/block/deadline-iosched.c @@ -138,7 +138,7 @@ deadline_merge(struct request_queue *q, struct request **req, struct bio *bio) __rq = elv_rb_find(&dd->sort_list[bio_data_dir(bio)], sector); if (__rq) { - BUG_ON(sector != __rq->sector); + BUG_ON(sector != blk_rq_pos(__rq)); if (elv_rq_merge_ok(__rq, bio)) { ret = ELEVATOR_FRONT_MERGE; diff --git a/block/elevator.c b/block/elevator.c index 7073a9072577..ca861927ba41 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -33,17 +33,16 @@ #include #include #include -#include #include #include +#include + #include "blk.h" static DEFINE_SPINLOCK(elv_list_lock); static LIST_HEAD(elv_list); -DEFINE_TRACE(block_rq_abort); - /* * Merge hash stuff. */ @@ -52,11 +51,7 @@ static const int elv_hash_shift = 6; #define ELV_HASH_FN(sec) \ (hash_long(ELV_HASH_BLOCK((sec)), elv_hash_shift)) #define ELV_HASH_ENTRIES (1 << elv_hash_shift) -#define rq_hash_key(rq) ((rq)->sector + (rq)->nr_sectors) -#define ELV_ON_HASH(rq) (!hlist_unhashed(&(rq)->hash)) - -DEFINE_TRACE(block_rq_insert); -DEFINE_TRACE(block_rq_issue); +#define rq_hash_key(rq) (blk_rq_pos(rq) + blk_rq_sectors(rq)) /* * Query io scheduler to see if the current process issuing bio may be @@ -120,9 +115,9 @@ static inline int elv_try_merge(struct request *__rq, struct bio *bio) * we can merge and sequence is ok, check if it's possible */ if (elv_rq_merge_ok(__rq, bio)) { - if (__rq->sector + __rq->nr_sectors == bio->bi_sector) + if (blk_rq_pos(__rq) + blk_rq_sectors(__rq) == bio->bi_sector) ret = ELEVATOR_BACK_MERGE; - else if (__rq->sector - bio_sectors(bio) == bio->bi_sector) + else if (blk_rq_pos(__rq) - bio_sectors(bio) == bio->bi_sector) ret = ELEVATOR_FRONT_MERGE; } @@ -310,22 +305,6 @@ void elevator_exit(struct elevator_queue *e) } EXPORT_SYMBOL(elevator_exit); -static void elv_activate_rq(struct request_queue *q, struct request *rq) -{ - struct elevator_queue *e = q->elevator; - - if (e->ops->elevator_activate_req_fn) - e->ops->elevator_activate_req_fn(q, rq); -} - -static void elv_deactivate_rq(struct request_queue *q, struct request *rq) -{ - struct elevator_queue *e = q->elevator; - - if (e->ops->elevator_deactivate_req_fn) - e->ops->elevator_deactivate_req_fn(q, rq); -} - static inline void __elv_rqhash_del(struct request *rq) { hlist_del_init(&rq->hash); @@ -387,9 +366,9 @@ struct request *elv_rb_add(struct rb_root *root, struct request *rq) parent = *p; __rq = rb_entry(parent, struct request, rb_node); - if (rq->sector < __rq->sector) + if (blk_rq_pos(rq) < blk_rq_pos(__rq)) p = &(*p)->rb_left; - else if (rq->sector > __rq->sector) + else if (blk_rq_pos(rq) > blk_rq_pos(__rq)) p = &(*p)->rb_right; else return __rq; @@ -417,9 +396,9 @@ struct request *elv_rb_find(struct rb_root *root, sector_t sector) while (n) { rq = rb_entry(n, struct request, rb_node); - if (sector < rq->sector) + if (sector < blk_rq_pos(rq)) n = n->rb_left; - else if (sector > rq->sector) + else if (sector > blk_rq_pos(rq)) n = n->rb_right; else return rq; @@ -458,14 +437,14 @@ void elv_dispatch_sort(struct request_queue *q, struct request *rq) break; if (pos->cmd_flags & stop_flags) break; - if (rq->sector >= boundary) { - if (pos->sector < boundary) + if (blk_rq_pos(rq) >= boundary) { + if (blk_rq_pos(pos) < boundary) continue; } else { - if (pos->sector >= boundary) + if (blk_rq_pos(pos) >= boundary) break; } - if (rq->sector >= pos->sector) + if (blk_rq_pos(rq) >= blk_rq_pos(pos)) break; } @@ -563,7 +542,7 @@ void elv_requeue_request(struct request_queue *q, struct request *rq) * in_flight count again */ if (blk_account_rq(rq)) { - q->in_flight--; + q->in_flight[rq_is_sync(rq)]--; if (blk_sorted_rq(rq)) elv_deactivate_rq(q, rq); } @@ -592,6 +571,9 @@ void elv_drain_elevator(struct request_queue *q) */ void elv_quiesce_start(struct request_queue *q) { + if (!q->elevator) + return; + queue_flag_set(QUEUE_FLAG_ELVSWITCH, q); /* @@ -599,7 +581,7 @@ void elv_quiesce_start(struct request_queue *q) */ elv_drain_elevator(q); while (q->rq.elvpriv) { - blk_start_queueing(q); + __blk_run_queue(q); spin_unlock_irq(q->queue_lock); msleep(10); spin_lock_irq(q->queue_lock); @@ -643,8 +625,7 @@ void elv_insert(struct request_queue *q, struct request *rq, int where) * with anything. There's no point in delaying queue * processing. */ - blk_remove_plug(q); - blk_start_queueing(q); + __blk_run_queue(q); break; case ELEVATOR_INSERT_SORT: @@ -703,7 +684,7 @@ void elv_insert(struct request_queue *q, struct request *rq, int where) if (unplug_it && blk_queue_plugged(q)) { int nrq = q->rq.count[BLK_RW_SYNC] + q->rq.count[BLK_RW_ASYNC] - - q->in_flight; + - queue_in_flight(q); if (nrq >= q->unplug_thresh) __generic_unplug_device(q); @@ -759,117 +740,6 @@ void elv_add_request(struct request_queue *q, struct request *rq, int where, } EXPORT_SYMBOL(elv_add_request); -static inline struct request *__elv_next_request(struct request_queue *q) -{ - struct request *rq; - - while (1) { - while (!list_empty(&q->queue_head)) { - rq = list_entry_rq(q->queue_head.next); - if (blk_do_ordered(q, &rq)) - return rq; - } - - if (!q->elevator->ops->elevator_dispatch_fn(q, 0)) - return NULL; - } -} - -struct request *elv_next_request(struct request_queue *q) -{ - struct request *rq; - int ret; - - while ((rq = __elv_next_request(q)) != NULL) { - if (!(rq->cmd_flags & REQ_STARTED)) { - /* - * This is the first time the device driver - * sees this request (possibly after - * requeueing). Notify IO scheduler. - */ - if (blk_sorted_rq(rq)) - elv_activate_rq(q, rq); - - /* - * just mark as started even if we don't start - * it, a request that has been delayed should - * not be passed by new incoming requests - */ - rq->cmd_flags |= REQ_STARTED; - trace_block_rq_issue(q, rq); - } - - if (!q->boundary_rq || q->boundary_rq == rq) { - q->end_sector = rq_end_sector(rq); - q->boundary_rq = NULL; - } - - if (rq->cmd_flags & REQ_DONTPREP) - break; - - if (q->dma_drain_size && rq->data_len) { - /* - * make sure space for the drain appears we - * know we can do this because max_hw_segments - * has been adjusted to be one fewer than the - * device can handle - */ - rq->nr_phys_segments++; - } - - if (!q->prep_rq_fn) - break; - - ret = q->prep_rq_fn(q, rq); - if (ret == BLKPREP_OK) { - break; - } else if (ret == BLKPREP_DEFER) { - /* - * the request may have been (partially) prepped. - * we need to keep this request in the front to - * avoid resource deadlock. REQ_STARTED will - * prevent other fs requests from passing this one. - */ - if (q->dma_drain_size && rq->data_len && - !(rq->cmd_flags & REQ_DONTPREP)) { - /* - * remove the space for the drain we added - * so that we don't add it again - */ - --rq->nr_phys_segments; - } - - rq = NULL; - break; - } else if (ret == BLKPREP_KILL) { - rq->cmd_flags |= REQ_QUIET; - __blk_end_request(rq, -EIO, blk_rq_bytes(rq)); - } else { - printk(KERN_ERR "%s: bad return=%d\n", __func__, ret); - break; - } - } - - return rq; -} -EXPORT_SYMBOL(elv_next_request); - -void elv_dequeue_request(struct request_queue *q, struct request *rq) -{ - BUG_ON(list_empty(&rq->queuelist)); - BUG_ON(ELV_ON_HASH(rq)); - - list_del_init(&rq->queuelist); - - /* - * the time frame between a request being removed from the lists - * and to it is freed is accounted as io that is in progress at - * the driver side. - */ - if (blk_account_rq(rq)) - q->in_flight++; -} - int elv_queue_empty(struct request_queue *q) { struct elevator_queue *e = q->elevator; @@ -939,7 +809,12 @@ void elv_abort_queue(struct request_queue *q) rq = list_entry_rq(q->queue_head.next); rq->cmd_flags |= REQ_QUIET; trace_block_rq_abort(q, rq); - __blk_end_request(rq, -EIO, blk_rq_bytes(rq)); + /* + * Mark this request as started so we don't trigger + * any debug logic in the end I/O path. + */ + blk_start_request(rq); + __blk_end_request_all(rq, -EIO); } } EXPORT_SYMBOL(elv_abort_queue); @@ -952,7 +827,7 @@ void elv_completed_request(struct request_queue *q, struct request *rq) * request is released from the driver, io must be done */ if (blk_account_rq(rq)) { - q->in_flight--; + q->in_flight[rq_is_sync(rq)]--; if (blk_sorted_rq(rq) && e->ops->elevator_completed_req_fn) e->ops->elevator_completed_req_fn(q, rq); } @@ -967,11 +842,11 @@ void elv_completed_request(struct request_queue *q, struct request *rq) if (!list_empty(&q->queue_head)) next = list_entry_rq(q->queue_head.next); - if (!q->in_flight && + if (!queue_in_flight(q) && blk_ordered_cur_seq(q) == QUEUE_ORDSEQ_DRAIN && (!next || blk_ordered_req_seq(next) > QUEUE_ORDSEQ_DRAIN)) { blk_ordered_complete_seq(q, QUEUE_ORDSEQ_DRAIN, 0); - blk_start_queueing(q); + __blk_run_queue(q); } } } @@ -1179,6 +1054,9 @@ ssize_t elv_iosched_store(struct request_queue *q, const char *name, char elevator_name[ELV_NAME_MAX]; struct elevator_type *e; + if (!q->elevator) + return count; + strlcpy(elevator_name, name, sizeof(elevator_name)); strstrip(elevator_name); @@ -1202,10 +1080,15 @@ ssize_t elv_iosched_store(struct request_queue *q, const char *name, ssize_t elv_iosched_show(struct request_queue *q, char *name) { struct elevator_queue *e = q->elevator; - struct elevator_type *elv = e->elevator_type; + struct elevator_type *elv; struct elevator_type *__e; int len = 0; + if (!q->elevator) + return sprintf(name, "none\n"); + + elv = e->elevator_type; + spin_lock(&elv_list_lock); list_for_each_entry(__e, &elv_list, list) { if (!strcmp(elv->elevator_name, __e->elevator_name)) diff --git a/block/genhd.c b/block/genhd.c index 1a4916e01732..f4c64c2b303a 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -852,11 +852,21 @@ static ssize_t disk_capability_show(struct device *dev, return sprintf(buf, "%x\n", disk->flags); } +static ssize_t disk_alignment_offset_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct gendisk *disk = dev_to_disk(dev); + + return sprintf(buf, "%d\n", queue_alignment_offset(disk->queue)); +} + static DEVICE_ATTR(range, S_IRUGO, disk_range_show, NULL); static DEVICE_ATTR(ext_range, S_IRUGO, disk_ext_range_show, NULL); static DEVICE_ATTR(removable, S_IRUGO, disk_removable_show, NULL); static DEVICE_ATTR(ro, S_IRUGO, disk_ro_show, NULL); static DEVICE_ATTR(size, S_IRUGO, part_size_show, NULL); +static DEVICE_ATTR(alignment_offset, S_IRUGO, disk_alignment_offset_show, NULL); static DEVICE_ATTR(capability, S_IRUGO, disk_capability_show, NULL); static DEVICE_ATTR(stat, S_IRUGO, part_stat_show, NULL); #ifdef CONFIG_FAIL_MAKE_REQUEST @@ -875,6 +885,7 @@ static struct attribute *disk_attrs[] = { &dev_attr_removable.attr, &dev_attr_ro.attr, &dev_attr_size.attr, + &dev_attr_alignment_offset.attr, &dev_attr_capability.attr, &dev_attr_stat.attr, #ifdef CONFIG_FAIL_MAKE_REQUEST @@ -985,10 +996,20 @@ struct class block_class = { .name = "block", }; +static char *block_nodename(struct device *dev) +{ + struct gendisk *disk = dev_to_disk(dev); + + if (disk->nodename) + return disk->nodename(disk); + return NULL; +} + static struct device_type disk_type = { .name = "disk", .groups = disk_attr_groups, .release = disk_release, + .nodename = block_nodename, }; #ifdef CONFIG_PROC_FS diff --git a/block/ioctl.c b/block/ioctl.c index ad474d4bbcce..500e4c73cc52 100644 --- a/block/ioctl.c +++ b/block/ioctl.c @@ -152,10 +152,10 @@ static int blk_ioctl_discard(struct block_device *bdev, uint64_t start, bio->bi_private = &wait; bio->bi_sector = start; - if (len > q->max_hw_sectors) { - bio->bi_size = q->max_hw_sectors << 9; - len -= q->max_hw_sectors; - start += q->max_hw_sectors; + if (len > queue_max_hw_sectors(q)) { + bio->bi_size = queue_max_hw_sectors(q) << 9; + len -= queue_max_hw_sectors(q); + start += queue_max_hw_sectors(q); } else { bio->bi_size = len << 9; len = 0; @@ -311,9 +311,9 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd, case BLKBSZGET: /* get the logical block size (cf. BLKSSZGET) */ return put_int(arg, block_size(bdev)); case BLKSSZGET: /* get block device hardware sector size */ - return put_int(arg, bdev_hardsect_size(bdev)); + return put_int(arg, bdev_logical_block_size(bdev)); case BLKSECTGET: - return put_ushort(arg, bdev_get_queue(bdev)->max_sectors); + return put_ushort(arg, queue_max_sectors(bdev_get_queue(bdev))); case BLKRASET: case BLKFRASET: if(!capable(CAP_SYS_ADMIN)) diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c index 82a0ca2f6729..5f8e798ede4e 100644 --- a/block/scsi_ioctl.c +++ b/block/scsi_ioctl.c @@ -75,7 +75,7 @@ static int sg_set_timeout(struct request_queue *q, int __user *p) static int sg_get_reserved_size(struct request_queue *q, int __user *p) { - unsigned val = min(q->sg_reserved_size, q->max_sectors << 9); + unsigned val = min(q->sg_reserved_size, queue_max_sectors(q) << 9); return put_user(val, p); } @@ -89,8 +89,8 @@ static int sg_set_reserved_size(struct request_queue *q, int __user *p) if (size < 0) return -EINVAL; - if (size > (q->max_sectors << 9)) - size = q->max_sectors << 9; + if (size > (queue_max_sectors(q) << 9)) + size = queue_max_sectors(q) << 9; q->sg_reserved_size = size; return 0; @@ -230,7 +230,7 @@ static int blk_complete_sghdr_rq(struct request *rq, struct sg_io_hdr *hdr, hdr->info = 0; if (hdr->masked_status || hdr->host_status || hdr->driver_status) hdr->info |= SG_INFO_CHECK; - hdr->resid = rq->data_len; + hdr->resid = rq->resid_len; hdr->sb_len_wr = 0; if (rq->sense_len && hdr->sbp) { @@ -264,7 +264,7 @@ static int sg_io(struct request_queue *q, struct gendisk *bd_disk, if (hdr->cmd_len > BLK_MAX_CDB) return -EINVAL; - if (hdr->dxfer_len > (q->max_hw_sectors << 9)) + if (hdr->dxfer_len > (queue_max_hw_sectors(q) << 9)) return -EIO; if (hdr->dxfer_len) @@ -500,9 +500,6 @@ static int __blk_send_generic(struct request_queue *q, struct gendisk *bd_disk, rq = blk_get_request(q, WRITE, __GFP_WAIT); rq->cmd_type = REQ_TYPE_BLOCK_PC; - rq->data = NULL; - rq->data_len = 0; - rq->extra_len = 0; rq->timeout = BLK_DEFAULT_SG_TIMEOUT; rq->cmd[0] = cmd; rq->cmd[4] = data; diff --git a/crypto/Kconfig b/crypto/Kconfig index 74d0e622a515..4dfdd03e708f 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -241,6 +241,11 @@ config CRYPTO_XTS key size 256, 384 or 512 bits. This implementation currently can't handle a sectorsize which is not a multiple of 16 bytes. +config CRYPTO_FPU + tristate + select CRYPTO_BLKCIPHER + select CRYPTO_MANAGER + comment "Hash modes" config CRYPTO_HMAC @@ -486,6 +491,7 @@ config CRYPTO_AES_NI_INTEL select CRYPTO_AES_X86_64 select CRYPTO_CRYPTD select CRYPTO_ALGAPI + select CRYPTO_FPU help Use Intel AES-NI instructions for AES algorithm. @@ -505,6 +511,10 @@ config CRYPTO_AES_NI_INTEL See for more information. + In addition to AES cipher algorithm support, the + acceleration for some popular block cipher mode is supported + too, including ECB, CBC, CTR, LRW, PCBC, XTS. + config CRYPTO_ANUBIS tristate "Anubis cipher algorithm" select CRYPTO_ALGAPI diff --git a/crypto/algboss.c b/crypto/algboss.c index 6906f92aeac0..9908dd830c26 100644 --- a/crypto/algboss.c +++ b/crypto/algboss.c @@ -280,29 +280,13 @@ static struct notifier_block cryptomgr_notifier = { static int __init cryptomgr_init(void) { - int err; - - err = testmgr_init(); - if (err) - return err; - - err = crypto_register_notifier(&cryptomgr_notifier); - if (err) - goto free_testmgr; - - return 0; - -free_testmgr: - testmgr_exit(); - return err; + return crypto_register_notifier(&cryptomgr_notifier); } static void __exit cryptomgr_exit(void) { int err = crypto_unregister_notifier(&cryptomgr_notifier); BUG_ON(err); - - testmgr_exit(); } subsys_initcall(cryptomgr_init); diff --git a/crypto/api.c b/crypto/api.c index fd2545decb28..d5944f92b416 100644 --- a/crypto/api.c +++ b/crypto/api.c @@ -217,14 +217,11 @@ struct crypto_alg *crypto_larval_lookup(const char *name, u32 type, u32 mask) alg = crypto_alg_lookup(name, type, mask); if (!alg) { - char tmp[CRYPTO_MAX_ALG_NAME]; - - request_module(name); + request_module("%s", name); if (!((type ^ CRYPTO_ALG_NEED_FALLBACK) & mask & - CRYPTO_ALG_NEED_FALLBACK) && - snprintf(tmp, sizeof(tmp), "%s-all", name) < sizeof(tmp)) - request_module(tmp); + CRYPTO_ALG_NEED_FALLBACK)) + request_module("%s-all", name); alg = crypto_alg_lookup(name, type, mask); } @@ -580,20 +577,17 @@ EXPORT_SYMBOL_GPL(crypto_alloc_tfm); void crypto_destroy_tfm(void *mem, struct crypto_tfm *tfm) { struct crypto_alg *alg; - int size; if (unlikely(!mem)) return; alg = tfm->__crt_alg; - size = ksize(mem); if (!tfm->exit && alg->cra_exit) alg->cra_exit(tfm); crypto_exit_ops(tfm); crypto_mod_put(alg); - memset(mem, 0, size); - kfree(mem); + kzfree(mem); } EXPORT_SYMBOL_GPL(crypto_destroy_tfm); diff --git a/crypto/cryptd.c b/crypto/cryptd.c index d14b22658d7a..ae5fa99d5d36 100644 --- a/crypto/cryptd.c +++ b/crypto/cryptd.c @@ -586,20 +586,24 @@ struct cryptd_ablkcipher *cryptd_alloc_ablkcipher(const char *alg_name, u32 type, u32 mask) { char cryptd_alg_name[CRYPTO_MAX_ALG_NAME]; - struct crypto_ablkcipher *tfm; + struct crypto_tfm *tfm; if (snprintf(cryptd_alg_name, CRYPTO_MAX_ALG_NAME, "cryptd(%s)", alg_name) >= CRYPTO_MAX_ALG_NAME) return ERR_PTR(-EINVAL); - tfm = crypto_alloc_ablkcipher(cryptd_alg_name, type, mask); + type &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV); + type |= CRYPTO_ALG_TYPE_BLKCIPHER; + mask &= ~CRYPTO_ALG_TYPE_MASK; + mask |= (CRYPTO_ALG_GENIV | CRYPTO_ALG_TYPE_BLKCIPHER_MASK); + tfm = crypto_alloc_base(cryptd_alg_name, type, mask); if (IS_ERR(tfm)) return ERR_CAST(tfm); - if (crypto_ablkcipher_tfm(tfm)->__crt_alg->cra_module != THIS_MODULE) { - crypto_free_ablkcipher(tfm); + if (tfm->__crt_alg->cra_module != THIS_MODULE) { + crypto_free_tfm(tfm); return ERR_PTR(-EINVAL); } - return __cryptd_ablkcipher_cast(tfm); + return __cryptd_ablkcipher_cast(__crypto_ablkcipher_cast(tfm)); } EXPORT_SYMBOL_GPL(cryptd_alloc_ablkcipher); diff --git a/crypto/internal.h b/crypto/internal.h index fc76e1f37fc3..113579a82dff 100644 --- a/crypto/internal.h +++ b/crypto/internal.h @@ -121,9 +121,6 @@ int crypto_register_notifier(struct notifier_block *nb); int crypto_unregister_notifier(struct notifier_block *nb); int crypto_probing_notify(unsigned long val, void *v); -int __init testmgr_init(void); -void testmgr_exit(void); - static inline void crypto_alg_put(struct crypto_alg *alg) { if (atomic_dec_and_test(&alg->cra_refcnt) && alg->cra_destroy) diff --git a/crypto/pcompress.c b/crypto/pcompress.c index ca9a4af91efe..bcadc03726b7 100644 --- a/crypto/pcompress.c +++ b/crypto/pcompress.c @@ -26,6 +26,7 @@ #include #include +#include #include "internal.h" diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c index c3c9124209a1..d59ba5079d14 100644 --- a/crypto/tcrypt.c +++ b/crypto/tcrypt.c @@ -27,6 +27,7 @@ #include #include #include "tcrypt.h" +#include "internal.h" /* * Need slab memory for testing (size in number of pages). @@ -396,16 +397,16 @@ static void test_hash_speed(const char *algo, unsigned int sec, struct scatterlist sg[TVMEMSIZE]; struct crypto_hash *tfm; struct hash_desc desc; - char output[1024]; + static char output[1024]; int i; int ret; - printk("\ntesting speed of %s\n", algo); + printk(KERN_INFO "\ntesting speed of %s\n", algo); tfm = crypto_alloc_hash(algo, 0, CRYPTO_ALG_ASYNC); if (IS_ERR(tfm)) { - printk("failed to load transform for %s: %ld\n", algo, + printk(KERN_ERR "failed to load transform for %s: %ld\n", algo, PTR_ERR(tfm)); return; } @@ -414,7 +415,7 @@ static void test_hash_speed(const char *algo, unsigned int sec, desc.flags = 0; if (crypto_hash_digestsize(tfm) > sizeof(output)) { - printk("digestsize(%u) > outputbuffer(%zu)\n", + printk(KERN_ERR "digestsize(%u) > outputbuffer(%zu)\n", crypto_hash_digestsize(tfm), sizeof(output)); goto out; } @@ -427,12 +428,14 @@ static void test_hash_speed(const char *algo, unsigned int sec, for (i = 0; speed[i].blen != 0; i++) { if (speed[i].blen > TVMEMSIZE * PAGE_SIZE) { - printk("template (%u) too big for tvmem (%lu)\n", + printk(KERN_ERR + "template (%u) too big for tvmem (%lu)\n", speed[i].blen, TVMEMSIZE * PAGE_SIZE); goto out; } - printk("test%3u (%5u byte blocks,%5u bytes per update,%4u updates): ", + printk(KERN_INFO "test%3u " + "(%5u byte blocks,%5u bytes per update,%4u updates): ", i, speed[i].blen, speed[i].plen, speed[i].blen / speed[i].plen); if (sec) @@ -443,7 +446,7 @@ static void test_hash_speed(const char *algo, unsigned int sec, speed[i].plen, output); if (ret) { - printk("hashing failed ret=%d\n", ret); + printk(KERN_ERR "hashing failed ret=%d\n", ret); break; } } @@ -466,239 +469,255 @@ static void test_available(void) static inline int tcrypt_test(const char *alg) { - return alg_test(alg, alg, 0, 0); + int ret; + + ret = alg_test(alg, alg, 0, 0); + /* non-fips algs return -EINVAL in fips mode */ + if (fips_enabled && ret == -EINVAL) + ret = 0; + return ret; } -static void do_test(int m) +static int do_test(int m) { int i; + int ret = 0; switch (m) { case 0: for (i = 1; i < 200; i++) - do_test(i); + ret += do_test(i); break; case 1: - tcrypt_test("md5"); + ret += tcrypt_test("md5"); break; case 2: - tcrypt_test("sha1"); + ret += tcrypt_test("sha1"); break; case 3: - tcrypt_test("ecb(des)"); - tcrypt_test("cbc(des)"); + ret += tcrypt_test("ecb(des)"); + ret += tcrypt_test("cbc(des)"); break; case 4: - tcrypt_test("ecb(des3_ede)"); - tcrypt_test("cbc(des3_ede)"); + ret += tcrypt_test("ecb(des3_ede)"); + ret += tcrypt_test("cbc(des3_ede)"); break; case 5: - tcrypt_test("md4"); + ret += tcrypt_test("md4"); break; case 6: - tcrypt_test("sha256"); + ret += tcrypt_test("sha256"); break; case 7: - tcrypt_test("ecb(blowfish)"); - tcrypt_test("cbc(blowfish)"); + ret += tcrypt_test("ecb(blowfish)"); + ret += tcrypt_test("cbc(blowfish)"); break; case 8: - tcrypt_test("ecb(twofish)"); - tcrypt_test("cbc(twofish)"); + ret += tcrypt_test("ecb(twofish)"); + ret += tcrypt_test("cbc(twofish)"); break; case 9: - tcrypt_test("ecb(serpent)"); + ret += tcrypt_test("ecb(serpent)"); break; case 10: - tcrypt_test("ecb(aes)"); - tcrypt_test("cbc(aes)"); - tcrypt_test("lrw(aes)"); - tcrypt_test("xts(aes)"); - tcrypt_test("rfc3686(ctr(aes))"); + ret += tcrypt_test("ecb(aes)"); + ret += tcrypt_test("cbc(aes)"); + ret += tcrypt_test("lrw(aes)"); + ret += tcrypt_test("xts(aes)"); + ret += tcrypt_test("ctr(aes)"); + ret += tcrypt_test("rfc3686(ctr(aes))"); break; case 11: - tcrypt_test("sha384"); + ret += tcrypt_test("sha384"); break; case 12: - tcrypt_test("sha512"); + ret += tcrypt_test("sha512"); break; case 13: - tcrypt_test("deflate"); + ret += tcrypt_test("deflate"); break; case 14: - tcrypt_test("ecb(cast5)"); + ret += tcrypt_test("ecb(cast5)"); break; case 15: - tcrypt_test("ecb(cast6)"); + ret += tcrypt_test("ecb(cast6)"); break; case 16: - tcrypt_test("ecb(arc4)"); + ret += tcrypt_test("ecb(arc4)"); break; case 17: - tcrypt_test("michael_mic"); + ret += tcrypt_test("michael_mic"); break; case 18: - tcrypt_test("crc32c"); + ret += tcrypt_test("crc32c"); break; case 19: - tcrypt_test("ecb(tea)"); + ret += tcrypt_test("ecb(tea)"); break; case 20: - tcrypt_test("ecb(xtea)"); + ret += tcrypt_test("ecb(xtea)"); break; case 21: - tcrypt_test("ecb(khazad)"); + ret += tcrypt_test("ecb(khazad)"); break; case 22: - tcrypt_test("wp512"); + ret += tcrypt_test("wp512"); break; case 23: - tcrypt_test("wp384"); + ret += tcrypt_test("wp384"); break; case 24: - tcrypt_test("wp256"); + ret += tcrypt_test("wp256"); break; case 25: - tcrypt_test("ecb(tnepres)"); + ret += tcrypt_test("ecb(tnepres)"); break; case 26: - tcrypt_test("ecb(anubis)"); - tcrypt_test("cbc(anubis)"); + ret += tcrypt_test("ecb(anubis)"); + ret += tcrypt_test("cbc(anubis)"); break; case 27: - tcrypt_test("tgr192"); + ret += tcrypt_test("tgr192"); break; case 28: - tcrypt_test("tgr160"); + ret += tcrypt_test("tgr160"); break; case 29: - tcrypt_test("tgr128"); + ret += tcrypt_test("tgr128"); break; case 30: - tcrypt_test("ecb(xeta)"); + ret += tcrypt_test("ecb(xeta)"); break; case 31: - tcrypt_test("pcbc(fcrypt)"); + ret += tcrypt_test("pcbc(fcrypt)"); break; case 32: - tcrypt_test("ecb(camellia)"); - tcrypt_test("cbc(camellia)"); + ret += tcrypt_test("ecb(camellia)"); + ret += tcrypt_test("cbc(camellia)"); break; case 33: - tcrypt_test("sha224"); + ret += tcrypt_test("sha224"); break; case 34: - tcrypt_test("salsa20"); + ret += tcrypt_test("salsa20"); break; case 35: - tcrypt_test("gcm(aes)"); + ret += tcrypt_test("gcm(aes)"); break; case 36: - tcrypt_test("lzo"); + ret += tcrypt_test("lzo"); break; case 37: - tcrypt_test("ccm(aes)"); + ret += tcrypt_test("ccm(aes)"); break; case 38: - tcrypt_test("cts(cbc(aes))"); + ret += tcrypt_test("cts(cbc(aes))"); break; case 39: - tcrypt_test("rmd128"); + ret += tcrypt_test("rmd128"); break; case 40: - tcrypt_test("rmd160"); + ret += tcrypt_test("rmd160"); break; case 41: - tcrypt_test("rmd256"); + ret += tcrypt_test("rmd256"); break; case 42: - tcrypt_test("rmd320"); + ret += tcrypt_test("rmd320"); break; case 43: - tcrypt_test("ecb(seed)"); + ret += tcrypt_test("ecb(seed)"); break; case 44: - tcrypt_test("zlib"); + ret += tcrypt_test("zlib"); + break; + + case 45: + ret += tcrypt_test("rfc4309(ccm(aes))"); break; case 100: - tcrypt_test("hmac(md5)"); + ret += tcrypt_test("hmac(md5)"); break; case 101: - tcrypt_test("hmac(sha1)"); + ret += tcrypt_test("hmac(sha1)"); break; case 102: - tcrypt_test("hmac(sha256)"); + ret += tcrypt_test("hmac(sha256)"); break; case 103: - tcrypt_test("hmac(sha384)"); + ret += tcrypt_test("hmac(sha384)"); break; case 104: - tcrypt_test("hmac(sha512)"); + ret += tcrypt_test("hmac(sha512)"); break; case 105: - tcrypt_test("hmac(sha224)"); + ret += tcrypt_test("hmac(sha224)"); break; case 106: - tcrypt_test("xcbc(aes)"); + ret += tcrypt_test("xcbc(aes)"); break; case 107: - tcrypt_test("hmac(rmd128)"); + ret += tcrypt_test("hmac(rmd128)"); break; case 108: - tcrypt_test("hmac(rmd160)"); + ret += tcrypt_test("hmac(rmd160)"); + break; + + case 150: + ret += tcrypt_test("ansi_cprng"); break; case 200: @@ -862,6 +881,8 @@ static void do_test(int m) test_available(); break; } + + return ret; } static int __init tcrypt_mod_init(void) @@ -875,15 +896,21 @@ static int __init tcrypt_mod_init(void) goto err_free_tv; } - do_test(mode); + err = do_test(mode); + if (err) { + printk(KERN_ERR "tcrypt: one or more tests failed!\n"); + goto err_free_tv; + } - /* We intentionaly return -EAGAIN to prevent keeping - * the module. It does all its work from init() - * and doesn't offer any runtime functionality + /* We intentionaly return -EAGAIN to prevent keeping the module, + * unless we're running in fips mode. It does all its work from + * init() and doesn't offer any runtime functionality, but in + * the fips case, checking for a successful load is helpful. * => we don't need it in the memory, do we? * -- mludvig */ - err = -EAGAIN; + if (!fips_enabled) + err = -EAGAIN; err_free_tv: for (i = 0; i < TVMEMSIZE && tvmem[i]; i++) diff --git a/crypto/testmgr.c b/crypto/testmgr.c index b50c3c6b17a2..e9e9d84293b9 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "internal.h" #include "testmgr.h" @@ -84,10 +85,16 @@ struct hash_test_suite { unsigned int count; }; +struct cprng_test_suite { + struct cprng_testvec *vecs; + unsigned int count; +}; + struct alg_test_desc { const char *alg; int (*test)(const struct alg_test_desc *desc, const char *driver, u32 type, u32 mask); + int fips_allowed; /* set if alg is allowed in fips mode */ union { struct aead_test_suite aead; @@ -95,14 +102,12 @@ struct alg_test_desc { struct comp_test_suite comp; struct pcomp_test_suite pcomp; struct hash_test_suite hash; + struct cprng_test_suite cprng; } suite; }; static unsigned int IDX[8] = { IDX1, IDX2, IDX3, IDX4, IDX5, IDX6, IDX7, IDX8 }; -static char *xbuf[XBUFSIZE]; -static char *axbuf[XBUFSIZE]; - static void hexdump(unsigned char *buf, unsigned int len) { print_hex_dump(KERN_CONT, "", DUMP_PREFIX_OFFSET, @@ -121,6 +126,33 @@ static void tcrypt_complete(struct crypto_async_request *req, int err) complete(&res->completion); } +static int testmgr_alloc_buf(char *buf[XBUFSIZE]) +{ + int i; + + for (i = 0; i < XBUFSIZE; i++) { + buf[i] = (void *)__get_free_page(GFP_KERNEL); + if (!buf[i]) + goto err_free_buf; + } + + return 0; + +err_free_buf: + while (i-- > 0) + free_page((unsigned long)buf[i]); + + return -ENOMEM; +} + +static void testmgr_free_buf(char *buf[XBUFSIZE]) +{ + int i; + + for (i = 0; i < XBUFSIZE; i++) + free_page((unsigned long)buf[i]); +} + static int test_hash(struct crypto_ahash *tfm, struct hash_testvec *template, unsigned int tcount) { @@ -130,8 +162,12 @@ static int test_hash(struct crypto_ahash *tfm, struct hash_testvec *template, char result[64]; struct ahash_request *req; struct tcrypt_result tresult; - int ret; void *hash_buff; + char *xbuf[XBUFSIZE]; + int ret = -ENOMEM; + + if (testmgr_alloc_buf(xbuf)) + goto out_nobuf; init_completion(&tresult.completion); @@ -139,17 +175,25 @@ static int test_hash(struct crypto_ahash *tfm, struct hash_testvec *template, if (!req) { printk(KERN_ERR "alg: hash: Failed to allocate request for " "%s\n", algo); - ret = -ENOMEM; goto out_noreq; } ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, tcrypt_complete, &tresult); + j = 0; for (i = 0; i < tcount; i++) { + if (template[i].np) + continue; + + j++; memset(result, 0, 64); hash_buff = xbuf[0]; + ret = -EINVAL; + if (WARN_ON(template[i].psize > PAGE_SIZE)) + goto out; + memcpy(hash_buff, template[i].plaintext, template[i].psize); sg_init_one(&sg[0], hash_buff, template[i].psize); @@ -159,7 +203,7 @@ static int test_hash(struct crypto_ahash *tfm, struct hash_testvec *template, template[i].ksize); if (ret) { printk(KERN_ERR "alg: hash: setkey failed on " - "test %d for %s: ret=%d\n", i + 1, algo, + "test %d for %s: ret=%d\n", j, algo, -ret); goto out; } @@ -181,14 +225,14 @@ static int test_hash(struct crypto_ahash *tfm, struct hash_testvec *template, /* fall through */ default: printk(KERN_ERR "alg: hash: digest failed on test %d " - "for %s: ret=%d\n", i + 1, algo, -ret); + "for %s: ret=%d\n", j, algo, -ret); goto out; } if (memcmp(result, template[i].digest, crypto_ahash_digestsize(tfm))) { printk(KERN_ERR "alg: hash: Test %d failed for %s\n", - i + 1, algo); + j, algo); hexdump(result, crypto_ahash_digestsize(tfm)); ret = -EINVAL; goto out; @@ -203,7 +247,11 @@ static int test_hash(struct crypto_ahash *tfm, struct hash_testvec *template, temp = 0; sg_init_table(sg, template[i].np); + ret = -EINVAL; for (k = 0; k < template[i].np; k++) { + if (WARN_ON(offset_in_page(IDX[k]) + + template[i].tap[k] > PAGE_SIZE)) + goto out; sg_set_buf(&sg[k], memcpy(xbuf[IDX[k] >> PAGE_SHIFT] + offset_in_page(IDX[k]), @@ -265,6 +313,8 @@ static int test_hash(struct crypto_ahash *tfm, struct hash_testvec *template, out: ahash_request_free(req); out_noreq: + testmgr_free_buf(xbuf); +out_nobuf: return ret; } @@ -273,7 +323,7 @@ static int test_aead(struct crypto_aead *tfm, int enc, { const char *algo = crypto_tfm_alg_driver_name(crypto_aead_tfm(tfm)); unsigned int i, j, k, n, temp; - int ret = 0; + int ret = -ENOMEM; char *q; char *key; struct aead_request *req; @@ -285,6 +335,13 @@ static int test_aead(struct crypto_aead *tfm, int enc, void *input; void *assoc; char iv[MAX_IVLEN]; + char *xbuf[XBUFSIZE]; + char *axbuf[XBUFSIZE]; + + if (testmgr_alloc_buf(xbuf)) + goto out_noxbuf; + if (testmgr_alloc_buf(axbuf)) + goto out_noaxbuf; if (enc == ENCRYPT) e = "encryption"; @@ -297,7 +354,6 @@ static int test_aead(struct crypto_aead *tfm, int enc, if (!req) { printk(KERN_ERR "alg: aead: Failed to allocate request for " "%s\n", algo); - ret = -ENOMEM; goto out; } @@ -314,6 +370,11 @@ static int test_aead(struct crypto_aead *tfm, int enc, input = xbuf[0]; assoc = axbuf[0]; + ret = -EINVAL; + if (WARN_ON(template[i].ilen > PAGE_SIZE || + template[i].alen > PAGE_SIZE)) + goto out; + memcpy(input, template[i].input, template[i].ilen); memcpy(assoc, template[i].assoc, template[i].alen); if (template[i].iv) @@ -363,6 +424,16 @@ static int test_aead(struct crypto_aead *tfm, int enc, switch (ret) { case 0: + if (template[i].novrfy) { + /* verification was supposed to fail */ + printk(KERN_ERR "alg: aead: %s failed " + "on test %d for %s: ret was 0, " + "expected -EBADMSG\n", + e, j, algo); + /* so really, we got a bad message */ + ret = -EBADMSG; + goto out; + } break; case -EINPROGRESS: case -EBUSY: @@ -372,6 +443,10 @@ static int test_aead(struct crypto_aead *tfm, int enc, INIT_COMPLETION(result.completion); break; } + case -EBADMSG: + if (template[i].novrfy) + /* verification failure was expected */ + continue; /* fall through */ default: printk(KERN_ERR "alg: aead: %s failed on test " @@ -459,7 +534,11 @@ static int test_aead(struct crypto_aead *tfm, int enc, } sg_init_table(asg, template[i].anp); + ret = -EINVAL; for (k = 0, temp = 0; k < template[i].anp; k++) { + if (WARN_ON(offset_in_page(IDX[k]) + + template[i].atap[k] > PAGE_SIZE)) + goto out; sg_set_buf(&asg[k], memcpy(axbuf[IDX[k] >> PAGE_SHIFT] + offset_in_page(IDX[k]), @@ -481,6 +560,16 @@ static int test_aead(struct crypto_aead *tfm, int enc, switch (ret) { case 0: + if (template[i].novrfy) { + /* verification was supposed to fail */ + printk(KERN_ERR "alg: aead: %s failed " + "on chunk test %d for %s: ret " + "was 0, expected -EBADMSG\n", + e, j, algo); + /* so really, we got a bad message */ + ret = -EBADMSG; + goto out; + } break; case -EINPROGRESS: case -EBUSY: @@ -490,6 +579,10 @@ static int test_aead(struct crypto_aead *tfm, int enc, INIT_COMPLETION(result.completion); break; } + case -EBADMSG: + if (template[i].novrfy) + /* verification failure was expected */ + continue; /* fall through */ default: printk(KERN_ERR "alg: aead: %s failed on " @@ -546,6 +639,10 @@ static int test_aead(struct crypto_aead *tfm, int enc, out: aead_request_free(req); + testmgr_free_buf(axbuf); +out_noaxbuf: + testmgr_free_buf(xbuf); +out_noxbuf: return ret; } @@ -554,10 +651,14 @@ static int test_cipher(struct crypto_cipher *tfm, int enc, { const char *algo = crypto_tfm_alg_driver_name(crypto_cipher_tfm(tfm)); unsigned int i, j, k; - int ret; char *q; const char *e; void *data; + char *xbuf[XBUFSIZE]; + int ret = -ENOMEM; + + if (testmgr_alloc_buf(xbuf)) + goto out_nobuf; if (enc == ENCRYPT) e = "encryption"; @@ -571,6 +672,10 @@ static int test_cipher(struct crypto_cipher *tfm, int enc, j++; + ret = -EINVAL; + if (WARN_ON(template[i].ilen > PAGE_SIZE)) + goto out; + data = xbuf[0]; memcpy(data, template[i].input, template[i].ilen); @@ -611,6 +716,8 @@ static int test_cipher(struct crypto_cipher *tfm, int enc, ret = 0; out: + testmgr_free_buf(xbuf); +out_nobuf: return ret; } @@ -620,7 +727,6 @@ static int test_skcipher(struct crypto_ablkcipher *tfm, int enc, const char *algo = crypto_tfm_alg_driver_name(crypto_ablkcipher_tfm(tfm)); unsigned int i, j, k, n, temp; - int ret; char *q; struct ablkcipher_request *req; struct scatterlist sg[8]; @@ -628,6 +734,11 @@ static int test_skcipher(struct crypto_ablkcipher *tfm, int enc, struct tcrypt_result result; void *data; char iv[MAX_IVLEN]; + char *xbuf[XBUFSIZE]; + int ret = -ENOMEM; + + if (testmgr_alloc_buf(xbuf)) + goto out_nobuf; if (enc == ENCRYPT) e = "encryption"; @@ -640,7 +751,6 @@ static int test_skcipher(struct crypto_ablkcipher *tfm, int enc, if (!req) { printk(KERN_ERR "alg: skcipher: Failed to allocate request " "for %s\n", algo); - ret = -ENOMEM; goto out; } @@ -657,6 +767,10 @@ static int test_skcipher(struct crypto_ablkcipher *tfm, int enc, if (!(template[i].np)) { j++; + ret = -EINVAL; + if (WARN_ON(template[i].ilen > PAGE_SIZE)) + goto out; + data = xbuf[0]; memcpy(data, template[i].input, template[i].ilen); @@ -825,6 +939,8 @@ static int test_skcipher(struct crypto_ablkcipher *tfm, int enc, out: ablkcipher_request_free(req); + testmgr_free_buf(xbuf); +out_nobuf: return ret; } @@ -837,7 +953,8 @@ static int test_comp(struct crypto_comp *tfm, struct comp_testvec *ctemplate, int ret; for (i = 0; i < ctcount; i++) { - int ilen, dlen = COMP_BUF_SIZE; + int ilen; + unsigned int dlen = COMP_BUF_SIZE; memset(result, 0, sizeof (result)); @@ -869,7 +986,8 @@ static int test_comp(struct crypto_comp *tfm, struct comp_testvec *ctemplate, } for (i = 0; i < dtcount; i++) { - int ilen, dlen = COMP_BUF_SIZE; + int ilen; + unsigned int dlen = COMP_BUF_SIZE; memset(result, 0, sizeof (result)); @@ -914,24 +1032,25 @@ static int test_pcomp(struct crypto_pcomp *tfm, const char *algo = crypto_tfm_alg_driver_name(crypto_pcomp_tfm(tfm)); unsigned int i; char result[COMP_BUF_SIZE]; - int error; + int res; for (i = 0; i < ctcount; i++) { struct comp_request req; + unsigned int produced = 0; - error = crypto_compress_setup(tfm, ctemplate[i].params, - ctemplate[i].paramsize); - if (error) { + res = crypto_compress_setup(tfm, ctemplate[i].params, + ctemplate[i].paramsize); + if (res) { pr_err("alg: pcomp: compression setup failed on test " - "%d for %s: error=%d\n", i + 1, algo, error); - return error; + "%d for %s: error=%d\n", i + 1, algo, res); + return res; } - error = crypto_compress_init(tfm); - if (error) { + res = crypto_compress_init(tfm); + if (res) { pr_err("alg: pcomp: compression init failed on test " - "%d for %s: error=%d\n", i + 1, algo, error); - return error; + "%d for %s: error=%d\n", i + 1, algo, res); + return res; } memset(result, 0, sizeof(result)); @@ -941,32 +1060,37 @@ static int test_pcomp(struct crypto_pcomp *tfm, req.next_out = result; req.avail_out = ctemplate[i].outlen / 2; - error = crypto_compress_update(tfm, &req); - if (error && (error != -EAGAIN || req.avail_in)) { + res = crypto_compress_update(tfm, &req); + if (res < 0 && (res != -EAGAIN || req.avail_in)) { pr_err("alg: pcomp: compression update failed on test " - "%d for %s: error=%d\n", i + 1, algo, error); - return error; + "%d for %s: error=%d\n", i + 1, algo, res); + return res; } + if (res > 0) + produced += res; /* Add remaining input data */ req.avail_in += (ctemplate[i].inlen + 1) / 2; - error = crypto_compress_update(tfm, &req); - if (error && (error != -EAGAIN || req.avail_in)) { + res = crypto_compress_update(tfm, &req); + if (res < 0 && (res != -EAGAIN || req.avail_in)) { pr_err("alg: pcomp: compression update failed on test " - "%d for %s: error=%d\n", i + 1, algo, error); - return error; + "%d for %s: error=%d\n", i + 1, algo, res); + return res; } + if (res > 0) + produced += res; /* Provide remaining output space */ req.avail_out += COMP_BUF_SIZE - ctemplate[i].outlen / 2; - error = crypto_compress_final(tfm, &req); - if (error) { + res = crypto_compress_final(tfm, &req); + if (res < 0) { pr_err("alg: pcomp: compression final failed on test " - "%d for %s: error=%d\n", i + 1, algo, error); - return error; + "%d for %s: error=%d\n", i + 1, algo, res); + return res; } + produced += res; if (COMP_BUF_SIZE - req.avail_out != ctemplate[i].outlen) { pr_err("alg: comp: Compression test %d failed for %s: " @@ -976,6 +1100,13 @@ static int test_pcomp(struct crypto_pcomp *tfm, return -EINVAL; } + if (produced != ctemplate[i].outlen) { + pr_err("alg: comp: Compression test %d failed for %s: " + "returned len = %u (expected %d)\n", i + 1, + algo, produced, ctemplate[i].outlen); + return -EINVAL; + } + if (memcmp(result, ctemplate[i].output, ctemplate[i].outlen)) { pr_err("alg: pcomp: Compression test %d failed for " "%s\n", i + 1, algo); @@ -986,21 +1117,21 @@ static int test_pcomp(struct crypto_pcomp *tfm, for (i = 0; i < dtcount; i++) { struct comp_request req; + unsigned int produced = 0; - error = crypto_decompress_setup(tfm, dtemplate[i].params, - dtemplate[i].paramsize); - if (error) { + res = crypto_decompress_setup(tfm, dtemplate[i].params, + dtemplate[i].paramsize); + if (res) { pr_err("alg: pcomp: decompression setup failed on " - "test %d for %s: error=%d\n", i + 1, algo, - error); - return error; + "test %d for %s: error=%d\n", i + 1, algo, res); + return res; } - error = crypto_decompress_init(tfm); - if (error) { + res = crypto_decompress_init(tfm); + if (res) { pr_err("alg: pcomp: decompression init failed on test " - "%d for %s: error=%d\n", i + 1, algo, error); - return error; + "%d for %s: error=%d\n", i + 1, algo, res); + return res; } memset(result, 0, sizeof(result)); @@ -1010,35 +1141,38 @@ static int test_pcomp(struct crypto_pcomp *tfm, req.next_out = result; req.avail_out = dtemplate[i].outlen / 2; - error = crypto_decompress_update(tfm, &req); - if (error && (error != -EAGAIN || req.avail_in)) { + res = crypto_decompress_update(tfm, &req); + if (res < 0 && (res != -EAGAIN || req.avail_in)) { pr_err("alg: pcomp: decompression update failed on " - "test %d for %s: error=%d\n", i + 1, algo, - error); - return error; + "test %d for %s: error=%d\n", i + 1, algo, res); + return res; } + if (res > 0) + produced += res; /* Add remaining input data */ req.avail_in += (dtemplate[i].inlen + 1) / 2; - error = crypto_decompress_update(tfm, &req); - if (error && (error != -EAGAIN || req.avail_in)) { + res = crypto_decompress_update(tfm, &req); + if (res < 0 && (res != -EAGAIN || req.avail_in)) { pr_err("alg: pcomp: decompression update failed on " - "test %d for %s: error=%d\n", i + 1, algo, - error); - return error; + "test %d for %s: error=%d\n", i + 1, algo, res); + return res; } + if (res > 0) + produced += res; /* Provide remaining output space */ req.avail_out += COMP_BUF_SIZE - dtemplate[i].outlen / 2; - error = crypto_decompress_final(tfm, &req); - if (error && (error != -EAGAIN || req.avail_in)) { + res = crypto_decompress_final(tfm, &req); + if (res < 0 && (res != -EAGAIN || req.avail_in)) { pr_err("alg: pcomp: decompression final failed on " - "test %d for %s: error=%d\n", i + 1, algo, - error); - return error; + "test %d for %s: error=%d\n", i + 1, algo, res); + return res; } + if (res > 0) + produced += res; if (COMP_BUF_SIZE - req.avail_out != dtemplate[i].outlen) { pr_err("alg: comp: Decompression test %d failed for " @@ -1048,6 +1182,13 @@ static int test_pcomp(struct crypto_pcomp *tfm, return -EINVAL; } + if (produced != dtemplate[i].outlen) { + pr_err("alg: comp: Decompression test %d failed for " + "%s: returned len = %u (expected %d)\n", i + 1, + algo, produced, dtemplate[i].outlen); + return -EINVAL; + } + if (memcmp(result, dtemplate[i].output, dtemplate[i].outlen)) { pr_err("alg: pcomp: Decompression test %d failed for " "%s\n", i + 1, algo); @@ -1059,6 +1200,68 @@ static int test_pcomp(struct crypto_pcomp *tfm, return 0; } + +static int test_cprng(struct crypto_rng *tfm, struct cprng_testvec *template, + unsigned int tcount) +{ + const char *algo = crypto_tfm_alg_driver_name(crypto_rng_tfm(tfm)); + int err, i, j, seedsize; + u8 *seed; + char result[32]; + + seedsize = crypto_rng_seedsize(tfm); + + seed = kmalloc(seedsize, GFP_KERNEL); + if (!seed) { + printk(KERN_ERR "alg: cprng: Failed to allocate seed space " + "for %s\n", algo); + return -ENOMEM; + } + + for (i = 0; i < tcount; i++) { + memset(result, 0, 32); + + memcpy(seed, template[i].v, template[i].vlen); + memcpy(seed + template[i].vlen, template[i].key, + template[i].klen); + memcpy(seed + template[i].vlen + template[i].klen, + template[i].dt, template[i].dtlen); + + err = crypto_rng_reset(tfm, seed, seedsize); + if (err) { + printk(KERN_ERR "alg: cprng: Failed to reset rng " + "for %s\n", algo); + goto out; + } + + for (j = 0; j < template[i].loops; j++) { + err = crypto_rng_get_bytes(tfm, result, + template[i].rlen); + if (err != template[i].rlen) { + printk(KERN_ERR "alg: cprng: Failed to obtain " + "the correct amount of random data for " + "%s (requested %d, got %d)\n", algo, + template[i].rlen, err); + goto out; + } + } + + err = memcmp(result, template[i].result, + template[i].rlen); + if (err) { + printk(KERN_ERR "alg: cprng: Test %d failed for %s\n", + i, algo); + hexdump(result, template[i].rlen); + err = -EINVAL; + goto out; + } + } + +out: + kfree(seed); + return err; +} + static int alg_test_aead(const struct alg_test_desc *desc, const char *driver, u32 type, u32 mask) { @@ -1258,11 +1461,42 @@ out: return err; } +static int alg_test_cprng(const struct alg_test_desc *desc, const char *driver, + u32 type, u32 mask) +{ + struct crypto_rng *rng; + int err; + + rng = crypto_alloc_rng(driver, type, mask); + if (IS_ERR(rng)) { + printk(KERN_ERR "alg: cprng: Failed to load transform for %s: " + "%ld\n", driver, PTR_ERR(rng)); + return PTR_ERR(rng); + } + + err = test_cprng(rng, desc->suite.cprng.vecs, desc->suite.cprng.count); + + crypto_free_rng(rng); + + return err; +} + /* Please keep this list sorted by algorithm name. */ static const struct alg_test_desc alg_test_descs[] = { { + .alg = "ansi_cprng", + .test = alg_test_cprng, + .fips_allowed = 1, + .suite = { + .cprng = { + .vecs = ansi_cprng_aes_tv_template, + .count = ANSI_CPRNG_AES_TEST_VECTORS + } + } + }, { .alg = "cbc(aes)", .test = alg_test_skcipher, + .fips_allowed = 1, .suite = { .cipher = { .enc = { @@ -1338,6 +1572,7 @@ static const struct alg_test_desc alg_test_descs[] = { }, { .alg = "cbc(des3_ede)", .test = alg_test_skcipher, + .fips_allowed = 1, .suite = { .cipher = { .enc = { @@ -1368,6 +1603,7 @@ static const struct alg_test_desc alg_test_descs[] = { }, { .alg = "ccm(aes)", .test = alg_test_aead, + .fips_allowed = 1, .suite = { .aead = { .enc = { @@ -1383,12 +1619,29 @@ static const struct alg_test_desc alg_test_descs[] = { }, { .alg = "crc32c", .test = alg_test_crc32c, + .fips_allowed = 1, .suite = { .hash = { .vecs = crc32c_tv_template, .count = CRC32C_TEST_VECTORS } } + }, { + .alg = "ctr(aes)", + .test = alg_test_skcipher, + .fips_allowed = 1, + .suite = { + .cipher = { + .enc = { + .vecs = aes_ctr_enc_tv_template, + .count = AES_CTR_ENC_TEST_VECTORS + }, + .dec = { + .vecs = aes_ctr_dec_tv_template, + .count = AES_CTR_DEC_TEST_VECTORS + } + } + } }, { .alg = "cts(cbc(aes))", .test = alg_test_skcipher, @@ -1422,6 +1675,7 @@ static const struct alg_test_desc alg_test_descs[] = { }, { .alg = "ecb(aes)", .test = alg_test_skcipher, + .fips_allowed = 1, .suite = { .cipher = { .enc = { @@ -1527,6 +1781,7 @@ static const struct alg_test_desc alg_test_descs[] = { }, { .alg = "ecb(des)", .test = alg_test_skcipher, + .fips_allowed = 1, .suite = { .cipher = { .enc = { @@ -1542,6 +1797,7 @@ static const struct alg_test_desc alg_test_descs[] = { }, { .alg = "ecb(des3_ede)", .test = alg_test_skcipher, + .fips_allowed = 1, .suite = { .cipher = { .enc = { @@ -1677,6 +1933,7 @@ static const struct alg_test_desc alg_test_descs[] = { }, { .alg = "gcm(aes)", .test = alg_test_aead, + .fips_allowed = 1, .suite = { .aead = { .enc = { @@ -1719,6 +1976,7 @@ static const struct alg_test_desc alg_test_descs[] = { }, { .alg = "hmac(sha1)", .test = alg_test_hash, + .fips_allowed = 1, .suite = { .hash = { .vecs = hmac_sha1_tv_template, @@ -1728,6 +1986,7 @@ static const struct alg_test_desc alg_test_descs[] = { }, { .alg = "hmac(sha224)", .test = alg_test_hash, + .fips_allowed = 1, .suite = { .hash = { .vecs = hmac_sha224_tv_template, @@ -1737,6 +1996,7 @@ static const struct alg_test_desc alg_test_descs[] = { }, { .alg = "hmac(sha256)", .test = alg_test_hash, + .fips_allowed = 1, .suite = { .hash = { .vecs = hmac_sha256_tv_template, @@ -1746,6 +2006,7 @@ static const struct alg_test_desc alg_test_descs[] = { }, { .alg = "hmac(sha384)", .test = alg_test_hash, + .fips_allowed = 1, .suite = { .hash = { .vecs = hmac_sha384_tv_template, @@ -1755,6 +2016,7 @@ static const struct alg_test_desc alg_test_descs[] = { }, { .alg = "hmac(sha512)", .test = alg_test_hash, + .fips_allowed = 1, .suite = { .hash = { .vecs = hmac_sha512_tv_template, @@ -1836,15 +2098,32 @@ static const struct alg_test_desc alg_test_descs[] = { }, { .alg = "rfc3686(ctr(aes))", .test = alg_test_skcipher, + .fips_allowed = 1, .suite = { .cipher = { .enc = { - .vecs = aes_ctr_enc_tv_template, - .count = AES_CTR_ENC_TEST_VECTORS + .vecs = aes_ctr_rfc3686_enc_tv_template, + .count = AES_CTR_3686_ENC_TEST_VECTORS }, .dec = { - .vecs = aes_ctr_dec_tv_template, - .count = AES_CTR_DEC_TEST_VECTORS + .vecs = aes_ctr_rfc3686_dec_tv_template, + .count = AES_CTR_3686_DEC_TEST_VECTORS + } + } + } + }, { + .alg = "rfc4309(ccm(aes))", + .test = alg_test_aead, + .fips_allowed = 1, + .suite = { + .aead = { + .enc = { + .vecs = aes_ccm_rfc4309_enc_tv_template, + .count = AES_CCM_4309_ENC_TEST_VECTORS + }, + .dec = { + .vecs = aes_ccm_rfc4309_dec_tv_template, + .count = AES_CCM_4309_DEC_TEST_VECTORS } } } @@ -1898,6 +2177,7 @@ static const struct alg_test_desc alg_test_descs[] = { }, { .alg = "sha1", .test = alg_test_hash, + .fips_allowed = 1, .suite = { .hash = { .vecs = sha1_tv_template, @@ -1907,6 +2187,7 @@ static const struct alg_test_desc alg_test_descs[] = { }, { .alg = "sha224", .test = alg_test_hash, + .fips_allowed = 1, .suite = { .hash = { .vecs = sha224_tv_template, @@ -1916,6 +2197,7 @@ static const struct alg_test_desc alg_test_descs[] = { }, { .alg = "sha256", .test = alg_test_hash, + .fips_allowed = 1, .suite = { .hash = { .vecs = sha256_tv_template, @@ -1925,6 +2207,7 @@ static const struct alg_test_desc alg_test_descs[] = { }, { .alg = "sha384", .test = alg_test_hash, + .fips_allowed = 1, .suite = { .hash = { .vecs = sha384_tv_template, @@ -1934,6 +2217,7 @@ static const struct alg_test_desc alg_test_descs[] = { }, { .alg = "sha512", .test = alg_test_hash, + .fips_allowed = 1, .suite = { .hash = { .vecs = sha512_tv_template, @@ -2077,60 +2361,36 @@ int alg_test(const char *driver, const char *alg, u32 type, u32 mask) if (i < 0) goto notest; - return alg_test_cipher(alg_test_descs + i, driver, type, mask); + if (fips_enabled && !alg_test_descs[i].fips_allowed) + goto non_fips_alg; + + rc = alg_test_cipher(alg_test_descs + i, driver, type, mask); + goto test_done; } i = alg_find_test(alg); if (i < 0) goto notest; + if (fips_enabled && !alg_test_descs[i].fips_allowed) + goto non_fips_alg; + rc = alg_test_descs[i].test(alg_test_descs + i, driver, type, mask); +test_done: if (fips_enabled && rc) panic("%s: %s alg self test failed in fips mode!\n", driver, alg); + if (fips_enabled && !rc) + printk(KERN_INFO "alg: self-tests for %s (%s) passed\n", + driver, alg); + return rc; notest: printk(KERN_INFO "alg: No test for %s (%s)\n", alg, driver); return 0; +non_fips_alg: + return -EINVAL; } EXPORT_SYMBOL_GPL(alg_test); - -int __init testmgr_init(void) -{ - int i; - - for (i = 0; i < XBUFSIZE; i++) { - xbuf[i] = (void *)__get_free_page(GFP_KERNEL); - if (!xbuf[i]) - goto err_free_xbuf; - } - - for (i = 0; i < XBUFSIZE; i++) { - axbuf[i] = (void *)__get_free_page(GFP_KERNEL); - if (!axbuf[i]) - goto err_free_axbuf; - } - - return 0; - -err_free_axbuf: - for (i = 0; i < XBUFSIZE && axbuf[i]; i++) - free_page((unsigned long)axbuf[i]); -err_free_xbuf: - for (i = 0; i < XBUFSIZE && xbuf[i]; i++) - free_page((unsigned long)xbuf[i]); - - return -ENOMEM; -} - -void testmgr_exit(void) -{ - int i; - - for (i = 0; i < XBUFSIZE; i++) - free_page((unsigned long)axbuf[i]); - for (i = 0; i < XBUFSIZE; i++) - free_page((unsigned long)xbuf[i]); -} diff --git a/crypto/testmgr.h b/crypto/testmgr.h index 526f00a9c72f..69316228fc19 100644 --- a/crypto/testmgr.h +++ b/crypto/testmgr.h @@ -62,6 +62,7 @@ struct aead_testvec { int np; int anp; unsigned char fail; + unsigned char novrfy; /* ccm dec verification failure expected */ unsigned char wk; /* weak key flag */ unsigned char klen; unsigned short ilen; @@ -69,6 +70,18 @@ struct aead_testvec { unsigned short rlen; }; +struct cprng_testvec { + char *key; + char *dt; + char *v; + char *result; + unsigned char klen; + unsigned short dtlen; + unsigned short vlen; + unsigned short rlen; + unsigned short loops; +}; + static char zeroed_string[48]; /* @@ -2841,12 +2854,16 @@ static struct cipher_testvec cast6_dec_tv_template[] = { #define AES_LRW_DEC_TEST_VECTORS 8 #define AES_XTS_ENC_TEST_VECTORS 4 #define AES_XTS_DEC_TEST_VECTORS 4 -#define AES_CTR_ENC_TEST_VECTORS 7 -#define AES_CTR_DEC_TEST_VECTORS 6 +#define AES_CTR_ENC_TEST_VECTORS 3 +#define AES_CTR_DEC_TEST_VECTORS 3 +#define AES_CTR_3686_ENC_TEST_VECTORS 7 +#define AES_CTR_3686_DEC_TEST_VECTORS 6 #define AES_GCM_ENC_TEST_VECTORS 9 #define AES_GCM_DEC_TEST_VECTORS 8 #define AES_CCM_ENC_TEST_VECTORS 7 #define AES_CCM_DEC_TEST_VECTORS 7 +#define AES_CCM_4309_ENC_TEST_VECTORS 7 +#define AES_CCM_4309_DEC_TEST_VECTORS 10 static struct cipher_testvec aes_enc_tv_template[] = { { /* From FIPS-197 */ @@ -3983,6 +4000,164 @@ static struct cipher_testvec aes_xts_dec_tv_template[] = { static struct cipher_testvec aes_ctr_enc_tv_template[] = { + { /* From NIST Special Publication 800-38A, Appendix F.5 */ + .key = "\x2b\x7e\x15\x16\x28\xae\xd2\xa6" + "\xab\xf7\x15\x88\x09\xcf\x4f\x3c", + .klen = 16, + .iv = "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" + "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", + .input = "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96" + "\xe9\x3d\x7e\x11\x73\x93\x17\x2a" + "\xae\x2d\x8a\x57\x1e\x03\xac\x9c" + "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51" + "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11" + "\xe5\xfb\xc1\x19\x1a\x0a\x52\xef" + "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17" + "\xad\x2b\x41\x7b\xe6\x6c\x37\x10", + .ilen = 64, + .result = "\x87\x4d\x61\x91\xb6\x20\xe3\x26" + "\x1b\xef\x68\x64\x99\x0d\xb6\xce" + "\x98\x06\xf6\x6b\x79\x70\xfd\xff" + "\x86\x17\x18\x7b\xb9\xff\xfd\xff" + "\x5a\xe4\xdf\x3e\xdb\xd5\xd3\x5e" + "\x5b\x4f\x09\x02\x0d\xb0\x3e\xab" + "\x1e\x03\x1d\xda\x2f\xbe\x03\xd1" + "\x79\x21\x70\xa0\xf3\x00\x9c\xee", + .rlen = 64, + }, { + .key = "\x8e\x73\xb0\xf7\xda\x0e\x64\x52" + "\xc8\x10\xf3\x2b\x80\x90\x79\xe5" + "\x62\xf8\xea\xd2\x52\x2c\x6b\x7b", + .klen = 24, + .iv = "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" + "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", + .input = "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96" + "\xe9\x3d\x7e\x11\x73\x93\x17\x2a" + "\xae\x2d\x8a\x57\x1e\x03\xac\x9c" + "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51" + "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11" + "\xe5\xfb\xc1\x19\x1a\x0a\x52\xef" + "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17" + "\xad\x2b\x41\x7b\xe6\x6c\x37\x10", + .ilen = 64, + .result = "\x1a\xbc\x93\x24\x17\x52\x1c\xa2" + "\x4f\x2b\x04\x59\xfe\x7e\x6e\x0b" + "\x09\x03\x39\xec\x0a\xa6\xfa\xef" + "\xd5\xcc\xc2\xc6\xf4\xce\x8e\x94" + "\x1e\x36\xb2\x6b\xd1\xeb\xc6\x70" + "\xd1\xbd\x1d\x66\x56\x20\xab\xf7" + "\x4f\x78\xa7\xf6\xd2\x98\x09\x58" + "\x5a\x97\xda\xec\x58\xc6\xb0\x50", + .rlen = 64, + }, { + .key = "\x60\x3d\xeb\x10\x15\xca\x71\xbe" + "\x2b\x73\xae\xf0\x85\x7d\x77\x81" + "\x1f\x35\x2c\x07\x3b\x61\x08\xd7" + "\x2d\x98\x10\xa3\x09\x14\xdf\xf4", + .klen = 32, + .iv = "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" + "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", + .input = "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96" + "\xe9\x3d\x7e\x11\x73\x93\x17\x2a" + "\xae\x2d\x8a\x57\x1e\x03\xac\x9c" + "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51" + "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11" + "\xe5\xfb\xc1\x19\x1a\x0a\x52\xef" + "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17" + "\xad\x2b\x41\x7b\xe6\x6c\x37\x10", + .ilen = 64, + .result = "\x60\x1e\xc3\x13\x77\x57\x89\xa5" + "\xb7\xa7\xf5\x04\xbb\xf3\xd2\x28" + "\xf4\x43\xe3\xca\x4d\x62\xb5\x9a" + "\xca\x84\xe9\x90\xca\xca\xf5\xc5" + "\x2b\x09\x30\xda\xa2\x3d\xe9\x4c" + "\xe8\x70\x17\xba\x2d\x84\x98\x8d" + "\xdf\xc9\xc5\x8d\xb6\x7a\xad\xa6" + "\x13\xc2\xdd\x08\x45\x79\x41\xa6", + .rlen = 64, + } +}; + +static struct cipher_testvec aes_ctr_dec_tv_template[] = { + { /* From NIST Special Publication 800-38A, Appendix F.5 */ + .key = "\x2b\x7e\x15\x16\x28\xae\xd2\xa6" + "\xab\xf7\x15\x88\x09\xcf\x4f\x3c", + .klen = 16, + .iv = "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" + "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", + .input = "\x87\x4d\x61\x91\xb6\x20\xe3\x26" + "\x1b\xef\x68\x64\x99\x0d\xb6\xce" + "\x98\x06\xf6\x6b\x79\x70\xfd\xff" + "\x86\x17\x18\x7b\xb9\xff\xfd\xff" + "\x5a\xe4\xdf\x3e\xdb\xd5\xd3\x5e" + "\x5b\x4f\x09\x02\x0d\xb0\x3e\xab" + "\x1e\x03\x1d\xda\x2f\xbe\x03\xd1" + "\x79\x21\x70\xa0\xf3\x00\x9c\xee", + .ilen = 64, + .result = "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96" + "\xe9\x3d\x7e\x11\x73\x93\x17\x2a" + "\xae\x2d\x8a\x57\x1e\x03\xac\x9c" + "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51" + "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11" + "\xe5\xfb\xc1\x19\x1a\x0a\x52\xef" + "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17" + "\xad\x2b\x41\x7b\xe6\x6c\x37\x10", + .rlen = 64, + }, { + .key = "\x8e\x73\xb0\xf7\xda\x0e\x64\x52" + "\xc8\x10\xf3\x2b\x80\x90\x79\xe5" + "\x62\xf8\xea\xd2\x52\x2c\x6b\x7b", + .klen = 24, + .iv = "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" + "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", + .input = "\x1a\xbc\x93\x24\x17\x52\x1c\xa2" + "\x4f\x2b\x04\x59\xfe\x7e\x6e\x0b" + "\x09\x03\x39\xec\x0a\xa6\xfa\xef" + "\xd5\xcc\xc2\xc6\xf4\xce\x8e\x94" + "\x1e\x36\xb2\x6b\xd1\xeb\xc6\x70" + "\xd1\xbd\x1d\x66\x56\x20\xab\xf7" + "\x4f\x78\xa7\xf6\xd2\x98\x09\x58" + "\x5a\x97\xda\xec\x58\xc6\xb0\x50", + .ilen = 64, + .result = "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96" + "\xe9\x3d\x7e\x11\x73\x93\x17\x2a" + "\xae\x2d\x8a\x57\x1e\x03\xac\x9c" + "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51" + "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11" + "\xe5\xfb\xc1\x19\x1a\x0a\x52\xef" + "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17" + "\xad\x2b\x41\x7b\xe6\x6c\x37\x10", + .rlen = 64, + }, { + .key = "\x60\x3d\xeb\x10\x15\xca\x71\xbe" + "\x2b\x73\xae\xf0\x85\x7d\x77\x81" + "\x1f\x35\x2c\x07\x3b\x61\x08\xd7" + "\x2d\x98\x10\xa3\x09\x14\xdf\xf4", + .klen = 32, + .iv = "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" + "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", + .input = "\x60\x1e\xc3\x13\x77\x57\x89\xa5" + "\xb7\xa7\xf5\x04\xbb\xf3\xd2\x28" + "\xf4\x43\xe3\xca\x4d\x62\xb5\x9a" + "\xca\x84\xe9\x90\xca\xca\xf5\xc5" + "\x2b\x09\x30\xda\xa2\x3d\xe9\x4c" + "\xe8\x70\x17\xba\x2d\x84\x98\x8d" + "\xdf\xc9\xc5\x8d\xb6\x7a\xad\xa6" + "\x13\xc2\xdd\x08\x45\x79\x41\xa6", + .ilen = 64, + .result = "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96" + "\xe9\x3d\x7e\x11\x73\x93\x17\x2a" + "\xae\x2d\x8a\x57\x1e\x03\xac\x9c" + "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51" + "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11" + "\xe5\xfb\xc1\x19\x1a\x0a\x52\xef" + "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17" + "\xad\x2b\x41\x7b\xe6\x6c\x37\x10", + .rlen = 64, + } +}; + +static struct cipher_testvec aes_ctr_rfc3686_enc_tv_template[] = { { /* From RFC 3686 */ .key = "\xae\x68\x52\xf8\x12\x10\x67\xcc" "\x4b\xf7\xa5\x76\x55\x77\xf3\x9e" @@ -5114,7 +5289,7 @@ static struct cipher_testvec aes_ctr_enc_tv_template[] = { }, }; -static struct cipher_testvec aes_ctr_dec_tv_template[] = { +static struct cipher_testvec aes_ctr_rfc3686_dec_tv_template[] = { { /* From RFC 3686 */ .key = "\xae\x68\x52\xf8\x12\x10\x67\xcc" "\x4b\xf7\xa5\x76\x55\x77\xf3\x9e" @@ -5825,6 +6000,470 @@ static struct aead_testvec aes_ccm_dec_tv_template[] = { }, }; +/* + * rfc4309 refers to section 8 of rfc3610 for test vectors, but they all + * use a 13-byte nonce, we only support an 11-byte nonce. Similarly, all of + * Special Publication 800-38C's test vectors also use nonce lengths our + * implementation doesn't support. The following are taken from fips cavs + * fax files on hand at Red Hat. + * + * nb: actual key lengths are (klen - 3), the last 3 bytes are actually + * part of the nonce which combine w/the iv, but need to be input this way. + */ +static struct aead_testvec aes_ccm_rfc4309_enc_tv_template[] = { + { + .key = "\x83\xac\x54\x66\xc2\xeb\xe5\x05" + "\x2e\x01\xd1\xfc\x5d\x82\x66\x2e" + "\x96\xac\x59", + .klen = 19, + .iv = "\x30\x07\xa1\xe2\xa2\xc7\x55\x24", + .alen = 0, + .input = "\x19\xc8\x81\xf6\xe9\x86\xff\x93" + "\x0b\x78\x67\xe5\xbb\xb7\xfc\x6e" + "\x83\x77\xb3\xa6\x0c\x8c\x9f\x9c" + "\x35\x2e\xad\xe0\x62\xf9\x91\xa1", + .ilen = 32, + .result = "\xab\x6f\xe1\x69\x1d\x19\x99\xa8" + "\x92\xa0\xc4\x6f\x7e\xe2\x8b\xb1" + "\x70\xbb\x8c\xa6\x4c\x6e\x97\x8a" + "\x57\x2b\xbe\x5d\x98\xa6\xb1\x32" + "\xda\x24\xea\xd9\xa1\x39\x98\xfd" + "\xa4\xbe\xd9\xf2\x1a\x6d\x22\xa8", + .rlen = 48, + }, { + .key = "\x1e\x2c\x7e\x01\x41\x9a\xef\xc0" + "\x0d\x58\x96\x6e\x5c\xa2\x4b\xd3" + "\x4f\xa3\x19", + .klen = 19, + .iv = "\xd3\x01\x5a\xd8\x30\x60\x15\x56", + .assoc = "\xda\xe6\x28\x9c\x45\x2d\xfd\x63" + "\x5e\xda\x4c\xb6\xe6\xfc\xf9\xb7" + "\x0c\x56\xcb\xe4\xe0\x05\x7a\xe1" + "\x0a\x63\x09\x78\xbc\x2c\x55\xde", + .alen = 32, + .input = "\x87\xa3\x36\xfd\x96\xb3\x93\x78" + "\xa9\x28\x63\xba\x12\xa3\x14\x85" + "\x57\x1e\x06\xc9\x7b\x21\xef\x76" + "\x7f\x38\x7e\x8e\x29\xa4\x3e\x7e", + .ilen = 32, + .result = "\x8a\x1e\x11\xf0\x02\x6b\xe2\x19" + "\xfc\x70\xc4\x6d\x8e\xb7\x99\xab" + "\xc5\x4b\xa2\xac\xd3\xf3\x48\xff" + "\x3b\xb5\xce\x53\xef\xde\xbb\x02" + "\xa9\x86\x15\x6c\x13\xfe\xda\x0a" + "\x22\xb8\x29\x3d\xd8\x39\x9a\x23", + .rlen = 48, + }, { + .key = "\xf4\x6b\xc2\x75\x62\xfe\xb4\xe1" + "\xa3\xf0\xff\xdd\x4e\x4b\x12\x75" + "\x53\x14\x73\x66\x8d\x88\xf6\x80" + "\xa0\x20\x35", + .klen = 27, + .iv = "\x26\xf2\x21\x8d\x50\x20\xda\xe2", + .assoc = "\x5b\x9e\x13\x67\x02\x5e\xef\xc1" + "\x6c\xf9\xd7\x1e\x52\x8f\x7a\x47" + "\xe9\xd4\xcf\x20\x14\x6e\xf0\x2d" + "\xd8\x9e\x2b\x56\x10\x23\x56\xe7", + .alen = 32, + .ilen = 0, + .result = "\x36\xea\x7a\x70\x08\xdc\x6a\xbc" + "\xad\x0c\x7a\x63\xf6\x61\xfd\x9b", + .rlen = 16, + }, { + .key = "\x56\xdf\x5c\x8f\x26\x3f\x0e\x42" + "\xef\x7a\xd3\xce\xfc\x84\x60\x62" + "\xca\xb4\x40\xaf\x5f\xc9\xc9\x01" + "\xd6\x3c\x8c", + .klen = 27, + .iv = "\x86\x84\xb6\xcd\xef\x09\x2e\x94", + .assoc = "\x02\x65\x78\x3c\xe9\x21\x30\x91" + "\xb1\xb9\xda\x76\x9a\x78\x6d\x95" + "\xf2\x88\x32\xa3\xf2\x50\xcb\x4c" + "\xe3\x00\x73\x69\x84\x69\x87\x79", + .alen = 32, + .input = "\x9f\xd2\x02\x4b\x52\x49\x31\x3c" + "\x43\x69\x3a\x2d\x8e\x70\xad\x7e" + "\xe0\xe5\x46\x09\x80\x89\x13\xb2" + "\x8c\x8b\xd9\x3f\x86\xfb\xb5\x6b", + .ilen = 32, + .result = "\x39\xdf\x7c\x3c\x5a\x29\xb9\x62" + "\x5d\x51\xc2\x16\xd8\xbd\x06\x9f" + "\x9b\x6a\x09\x70\xc1\x51\x83\xc2" + "\x66\x88\x1d\x4f\x9a\xda\xe0\x1e" + "\xc7\x79\x11\x58\xe5\x6b\x20\x40" + "\x7a\xea\x46\x42\x8b\xe4\x6f\xe1", + .rlen = 48, + }, { + .key = "\xe0\x8d\x99\x71\x60\xd7\x97\x1a" + "\xbd\x01\x99\xd5\x8a\xdf\x71\x3a" + "\xd3\xdf\x24\x4b\x5e\x3d\x4b\x4e" + "\x30\x7a\xb9\xd8\x53\x0a\x5e\x2b" + "\x1e\x29\x91", + .klen = 35, + .iv = "\xad\x8e\xc1\x53\x0a\xcf\x2d\xbe", + .assoc = "\x19\xb6\x1f\x57\xc4\xf3\xf0\x8b" + "\x78\x2b\x94\x02\x29\x0f\x42\x27" + "\x6b\x75\xcb\x98\x34\x08\x7e\x79" + "\xe4\x3e\x49\x0d\x84\x8b\x22\x87", + .alen = 32, + .input = "\xe1\xd9\xd8\x13\xeb\x3a\x75\x3f" + "\x9d\xbd\x5f\x66\xbe\xdc\xbb\x66" + "\xbf\x17\x99\x62\x4a\x39\x27\x1f" + "\x1d\xdc\x24\xae\x19\x2f\x98\x4c", + .ilen = 32, + .result = "\x19\xb8\x61\x33\x45\x2b\x43\x96" + "\x6f\x51\xd0\x20\x30\x7d\x9b\xc6" + "\x26\x3d\xf8\xc9\x65\x16\xa8\x9f" + "\xf0\x62\x17\x34\xf2\x1e\x8d\x75" + "\x4e\x13\xcc\xc0\xc3\x2a\x54\x2d", + .rlen = 40, + }, { + .key = "\x7c\xc8\x18\x3b\x8d\x99\xe0\x7c" + "\x45\x41\xb8\xbd\x5c\xa7\xc2\x32" + "\x8a\xb8\x02\x59\xa4\xfe\xa9\x2c" + "\x09\x75\x9a\x9b\x3c\x9b\x27\x39" + "\xf9\xd9\x4e", + .klen = 35, + .iv = "\x63\xb5\x3d\x9d\x43\xf6\x1e\x50", + .assoc = "\x57\xf5\x6b\x8b\x57\x5c\x3d\x3b" + "\x13\x02\x01\x0c\x83\x4c\x96\x35" + "\x8e\xd6\x39\xcf\x7d\x14\x9b\x94" + "\xb0\x39\x36\xe6\x8f\x57\xe0\x13", + .alen = 32, + .input = "\x3b\x6c\x29\x36\xb6\xef\x07\xa6" + "\x83\x72\x07\x4f\xcf\xfa\x66\x89" + "\x5f\xca\xb1\xba\xd5\x8f\x2c\x27" + "\x30\xdb\x75\x09\x93\xd4\x65\xe4", + .ilen = 32, + .result = "\xb0\x88\x5a\x33\xaa\xe5\xc7\x1d" + "\x85\x23\xc7\xc6\x2f\xf4\x1e\x3d" + "\xcc\x63\x44\x25\x07\x78\x4f\x9e" + "\x96\xb8\x88\xeb\xbc\x48\x1f\x06" + "\x39\xaf\x39\xac\xd8\x4a\x80\x39" + "\x7b\x72\x8a\xf7", + .rlen = 44, + }, { + .key = "\xab\xd0\xe9\x33\x07\x26\xe5\x83" + "\x8c\x76\x95\xd4\xb6\xdc\xf3\x46" + "\xf9\x8f\xad\xe3\x02\x13\x83\x77" + "\x3f\xb0\xf1\xa1\xa1\x22\x0f\x2b" + "\x24\xa7\x8b", + .klen = 35, + .iv = "\x07\xcb\xcc\x0e\xe6\x33\xbf\xf5", + .assoc = "\xd4\xdb\x30\x1d\x03\xfe\xfd\x5f" + "\x87\xd4\x8c\xb6\xb6\xf1\x7a\x5d" + "\xab\x90\x65\x8d\x8e\xca\x4d\x4f" + "\x16\x0c\x40\x90\x4b\xc7\x36\x73", + .alen = 32, + .input = "\xf5\xc6\x7d\x48\xc1\xb7\xe6\x92" + "\x97\x5a\xca\xc4\xa9\x6d\xf9\x3d" + "\x6c\xde\xbc\xf1\x90\xea\x6a\xb2" + "\x35\x86\x36\xaf\x5c\xfe\x4b\x3a", + .ilen = 32, + .result = "\x83\x6f\x40\x87\x72\xcf\xc1\x13" + "\xef\xbb\x80\x21\x04\x6c\x58\x09" + "\x07\x1b\xfc\xdf\xc0\x3f\x5b\xc7" + "\xe0\x79\xa8\x6e\x71\x7c\x3f\xcf" + "\x5c\xda\xb2\x33\xe5\x13\xe2\x0d" + "\x74\xd1\xef\xb5\x0f\x3a\xb5\xf8", + .rlen = 48, + }, +}; + +static struct aead_testvec aes_ccm_rfc4309_dec_tv_template[] = { + { + .key = "\xab\x2f\x8a\x74\xb7\x1c\xd2\xb1" + "\xff\x80\x2e\x48\x7d\x82\xf8\xb9" + "\xc6\xfb\x7d", + .klen = 19, + .iv = "\x80\x0d\x13\xab\xd8\xa6\xb2\xd8", + .alen = 0, + .input = "\xd5\xe8\x93\x9f\xc7\x89\x2e\x2b", + .ilen = 8, + .result = "\x00", + .rlen = 0, + .novrfy = 1, + }, { + .key = "\xab\x2f\x8a\x74\xb7\x1c\xd2\xb1" + "\xff\x80\x2e\x48\x7d\x82\xf8\xb9" + "\xaf\x94\x87", + .klen = 19, + .iv = "\x78\x35\x82\x81\x7f\x88\x94\x68", + .alen = 0, + .input = "\x41\x3c\xb8\x87\x73\xcb\xf3\xf3", + .ilen = 8, + .result = "\x00", + .rlen = 0, + }, { + .key = "\x61\x0e\x8c\xae\xe3\x23\xb6\x38" + "\x76\x1c\xf6\x3a\x67\xa3\x9c\xd8" + "\xc6\xfb\x7d", + .klen = 19, + .iv = "\x80\x0d\x13\xab\xd8\xa6\xb2\xd8", + .assoc = "\xf3\x94\x87\x78\x35\x82\x81\x7f" + "\x88\x94\x68\xb1\x78\x6b\x2b\xd6" + "\x04\x1f\x4e\xed\x78\xd5\x33\x66" + "\xd8\x94\x99\x91\x81\x54\x62\x57", + .alen = 32, + .input = "\xf0\x7c\x29\x02\xae\x1c\x2f\x55" + "\xd0\xd1\x3d\x1a\xa3\x6d\xe4\x0a" + "\x86\xb0\x87\x6b\x62\x33\x8c\x34" + "\xce\xab\x57\xcc\x79\x0b\xe0\x6f" + "\x5c\x3e\x48\x1f\x6c\x46\xf7\x51" + "\x8b\x84\x83\x2a\xc1\x05\xb8\xc5", + .ilen = 48, + .result = "\x50\x82\x3e\x07\xe2\x1e\xb6\xfb" + "\x33\xe4\x73\xce\xd2\xfb\x95\x79" + "\xe8\xb4\xb5\x77\x11\x10\x62\x6f" + "\x6a\x82\xd1\x13\xec\xf5\xd0\x48", + .rlen = 32, + .novrfy = 1, + }, { + .key = "\x61\x0e\x8c\xae\xe3\x23\xb6\x38" + "\x76\x1c\xf6\x3a\x67\xa3\x9c\xd8" + "\x05\xe0\xc9", + .klen = 19, + .iv = "\x0f\xed\x34\xea\x97\xd4\x3b\xdf", + .assoc = "\x49\x5c\x50\x1f\x1d\x94\xcc\x81" + "\xba\xb7\xb6\x03\xaf\xa5\xc1\xa1" + "\xd8\x5c\x42\x68\xe0\x6c\xda\x89" + "\x05\xac\x56\xac\x1b\x2a\xd3\x86", + .alen = 32, + .input = "\x39\xbe\x7d\x15\x62\x77\xf3\x3c" + "\xad\x83\x52\x6d\x71\x03\x25\x1c" + "\xed\x81\x3a\x9a\x16\x7d\x19\x80" + "\x72\x04\x72\xd0\xf6\xff\x05\x0f" + "\xb7\x14\x30\x00\x32\x9e\xa0\xa6" + "\x9e\x5a\x18\xa1\xb8\xfe\xdb\xd3", + .ilen = 48, + .result = "\x75\x05\xbe\xc2\xd9\x1e\xde\x60" + "\x47\x3d\x8c\x7d\xbd\xb5\xd9\xb7" + "\xf2\xae\x61\x05\x8f\x82\x24\x3f" + "\x9c\x67\x91\xe1\x38\x4f\xe4\x0c", + .rlen = 32, + }, { + .key = "\x39\xbb\xa7\xbe\x59\x97\x9e\x73" + "\xa2\xbc\x6b\x98\xd7\x75\x7f\xe3" + "\xa4\x48\x93\x39\x26\x71\x4a\xc6" + "\xee\x49\x83", + .klen = 27, + .iv = "\xe9\xa9\xff\xe9\x57\xba\xfd\x9e", + .assoc = "\x44\xa6\x2c\x05\xe9\xe1\x43\xb1" + "\x58\x7c\xf2\x5c\x6d\x39\x0a\x64" + "\xa4\xf0\x13\x05\xd1\x77\x99\x67" + "\x11\xc4\xc6\xdb\x00\x56\x36\x61", + .alen = 32, + .input = "\x71\x99\xfa\xf4\x44\x12\x68\x9b", + .ilen = 8, + .result = "\x00", + .rlen = 0, + }, { + .key = "\x58\x5d\xa0\x96\x65\x1a\x04\xd7" + "\x96\xe5\xc5\x68\xaa\x95\x35\xe0" + "\x29\xa0\xba\x9e\x48\x78\xd1\xba" + "\xee\x49\x83", + .klen = 27, + .iv = "\xe9\xa9\xff\xe9\x57\xba\xfd\x9e", + .assoc = "\x44\xa6\x2c\x05\xe9\xe1\x43\xb1" + "\x58\x7c\xf2\x5c\x6d\x39\x0a\x64" + "\xa4\xf0\x13\x05\xd1\x77\x99\x67" + "\x11\xc4\xc6\xdb\x00\x56\x36\x61", + .alen = 32, + .input = "\xfb\xe5\x5d\x34\xbe\xe5\xe8\xe7" + "\x5a\xef\x2f\xbf\x1f\x7f\xd4\xb2" + "\x66\xca\x61\x1e\x96\x7a\x61\xb3" + "\x1c\x16\x45\x52\xba\x04\x9c\x9f" + "\xb1\xd2\x40\xbc\x52\x7c\x6f\xb1", + .ilen = 40, + .result = "\x85\x34\x66\x42\xc8\x92\x0f\x36" + "\x58\xe0\x6b\x91\x3c\x98\x5c\xbb" + "\x0a\x85\xcc\x02\xad\x7a\x96\xe9" + "\x65\x43\xa4\xc3\x0f\xdc\x55\x81", + .rlen = 32, + }, { + .key = "\x58\x5d\xa0\x96\x65\x1a\x04\xd7" + "\x96\xe5\xc5\x68\xaa\x95\x35\xe0" + "\x29\xa0\xba\x9e\x48\x78\xd1\xba" + "\xd1\xfc\x57", + .klen = 27, + .iv = "\x9c\xfe\xb8\x9c\xad\x71\xaa\x1f", + .assoc = "\x86\x67\xa5\xa9\x14\x5f\x0d\xc6" + "\xff\x14\xc7\x44\xbf\x6c\x3a\xc3" + "\xff\xb6\x81\xbd\xe2\xd5\x06\xc7" + "\x3c\xa1\x52\x13\x03\x8a\x23\x3a", + .alen = 32, + .input = "\x3f\x66\xb0\x9d\xe5\x4b\x38\x00" + "\xc6\x0e\x6e\xe5\xd6\x98\xa6\x37" + "\x8c\x26\x33\xc6\xb2\xa2\x17\xfa" + "\x64\x19\xc0\x30\xd7\xfc\x14\x6b" + "\xe3\x33\xc2\x04\xb0\x37\xbe\x3f" + "\xa9\xb4\x2d\x68\x03\xa3\x44\xef", + .ilen = 48, + .result = "\x02\x87\x4d\x28\x80\x6e\xb2\xed" + "\x99\x2a\xa8\xca\x04\x25\x45\x90" + "\x1d\xdd\x5a\xd9\xe4\xdb\x9c\x9c" + "\x49\xe9\x01\xfe\xa7\x80\x6d\x6b", + .rlen = 32, + .novrfy = 1, + }, { + .key = "\xa4\x4b\x54\x29\x0a\xb8\x6d\x01" + "\x5b\x80\x2a\xcf\x25\xc4\xb7\x5c" + "\x20\x2c\xad\x30\xc2\x2b\x41\xfb" + "\x0e\x85\xbc\x33\xad\x0f\x2b\xff" + "\xee\x49\x83", + .klen = 35, + .iv = "\xe9\xa9\xff\xe9\x57\xba\xfd\x9e", + .alen = 0, + .input = "\x1f\xb8\x8f\xa3\xdd\x54\x00\xf2", + .ilen = 8, + .result = "\x00", + .rlen = 0, + }, { + .key = "\x39\xbb\xa7\xbe\x59\x97\x9e\x73" + "\xa2\xbc\x6b\x98\xd7\x75\x7f\xe3" + "\xa4\x48\x93\x39\x26\x71\x4a\xc6" + "\xae\x8f\x11\x4c\xc2\x9c\x4a\xbb" + "\x85\x34\x66", + .klen = 35, + .iv = "\x42\xc8\x92\x0f\x36\x58\xe0\x6b", + .alen = 0, + .input = "\x48\x01\x5e\x02\x24\x04\x66\x47" + "\xa1\xea\x6f\xaf\xe8\xfc\xfb\xdd" + "\xa5\xa9\x87\x8d\x84\xee\x2e\x77" + "\xbb\x86\xb9\xf5\x5c\x6c\xff\xf6" + "\x72\xc3\x8e\xf7\x70\xb1\xb2\x07" + "\xbc\xa8\xa3\xbd\x83\x7c\x1d\x2a", + .ilen = 48, + .result = "\xdc\x56\xf2\x71\xb0\xb1\xa0\x6c" + "\xf0\x97\x3a\xfb\x6d\xe7\x32\x99" + "\x3e\xaf\x70\x5e\xb2\x4d\xea\x39" + "\x89\xd4\x75\x7a\x63\xb1\xda\x93", + .rlen = 32, + .novrfy = 1, + }, { + .key = "\x58\x5d\xa0\x96\x65\x1a\x04\xd7" + "\x96\xe5\xc5\x68\xaa\x95\x35\xe0" + "\x29\xa0\xba\x9e\x48\x78\xd1\xba" + "\x0d\x1a\x53\x3b\xb5\xe3\xf8\x8b" + "\xcf\x76\x3f", + .klen = 35, + .iv = "\xd9\x95\x75\x8f\x44\x89\x40\x7b", + .assoc = "\x8f\x86\x6c\x4d\x1d\xc5\x39\x88" + "\xc8\xf3\x5c\x52\x10\x63\x6f\x2b" + "\x8a\x2a\xc5\x6f\x30\x23\x58\x7b" + "\xfb\x36\x03\x11\xb4\xd9\xf2\xfe", + .alen = 32, + .input = "\x48\x58\xd6\xf3\xad\x63\x58\xbf" + "\xae\xc7\x5e\xae\x83\x8f\x7b\xe4" + "\x78\x5c\x4c\x67\x71\x89\x94\xbf" + "\x47\xf1\x63\x7e\x1c\x59\xbd\xc5" + "\x7f\x44\x0a\x0c\x01\x18\x07\x92" + "\xe1\xd3\x51\xce\x32\x6d\x0c\x5b", + .ilen = 48, + .result = "\xc2\x54\xc8\xde\x78\x87\x77\x40" + "\x49\x71\xe4\xb7\xe7\xcb\x76\x61" + "\x0a\x41\xb9\xe9\xc0\x76\x54\xab" + "\x04\x49\x3b\x19\x93\x57\x25\x5d", + .rlen = 32, + }, +}; + +/* + * ANSI X9.31 Continuous Pseudo-Random Number Generator (AES mode) + * test vectors, taken from Appendix B.2.9 and B.2.10: + * http://csrc.nist.gov/groups/STM/cavp/documents/rng/RNGVS.pdf + * Only AES-128 is supported at this time. + */ +#define ANSI_CPRNG_AES_TEST_VECTORS 6 + +static struct cprng_testvec ansi_cprng_aes_tv_template[] = { + { + .key = "\xf3\xb1\x66\x6d\x13\x60\x72\x42" + "\xed\x06\x1c\xab\xb8\xd4\x62\x02", + .klen = 16, + .dt = "\xe6\xb3\xbe\x78\x2a\x23\xfa\x62" + "\xd7\x1d\x4a\xfb\xb0\xe9\x22\xf9", + .dtlen = 16, + .v = "\x80\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .vlen = 16, + .result = "\x59\x53\x1e\xd1\x3b\xb0\xc0\x55" + "\x84\x79\x66\x85\xc1\x2f\x76\x41", + .rlen = 16, + .loops = 1, + }, { + .key = "\xf3\xb1\x66\x6d\x13\x60\x72\x42" + "\xed\x06\x1c\xab\xb8\xd4\x62\x02", + .klen = 16, + .dt = "\xe6\xb3\xbe\x78\x2a\x23\xfa\x62" + "\xd7\x1d\x4a\xfb\xb0\xe9\x22\xfa", + .dtlen = 16, + .v = "\xc0\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .vlen = 16, + .result = "\x7c\x22\x2c\xf4\xca\x8f\xa2\x4c" + "\x1c\x9c\xb6\x41\xa9\xf3\x22\x0d", + .rlen = 16, + .loops = 1, + }, { + .key = "\xf3\xb1\x66\x6d\x13\x60\x72\x42" + "\xed\x06\x1c\xab\xb8\xd4\x62\x02", + .klen = 16, + .dt = "\xe6\xb3\xbe\x78\x2a\x23\xfa\x62" + "\xd7\x1d\x4a\xfb\xb0\xe9\x22\xfb", + .dtlen = 16, + .v = "\xe0\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .vlen = 16, + .result = "\x8a\xaa\x00\x39\x66\x67\x5b\xe5" + "\x29\x14\x28\x81\xa9\x4d\x4e\xc7", + .rlen = 16, + .loops = 1, + }, { + .key = "\xf3\xb1\x66\x6d\x13\x60\x72\x42" + "\xed\x06\x1c\xab\xb8\xd4\x62\x02", + .klen = 16, + .dt = "\xe6\xb3\xbe\x78\x2a\x23\xfa\x62" + "\xd7\x1d\x4a\xfb\xb0\xe9\x22\xfc", + .dtlen = 16, + .v = "\xf0\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .vlen = 16, + .result = "\x88\xdd\xa4\x56\x30\x24\x23\xe5" + "\xf6\x9d\xa5\x7e\x7b\x95\xc7\x3a", + .rlen = 16, + .loops = 1, + }, { + .key = "\xf3\xb1\x66\x6d\x13\x60\x72\x42" + "\xed\x06\x1c\xab\xb8\xd4\x62\x02", + .klen = 16, + .dt = "\xe6\xb3\xbe\x78\x2a\x23\xfa\x62" + "\xd7\x1d\x4a\xfb\xb0\xe9\x22\xfd", + .dtlen = 16, + .v = "\xf8\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .vlen = 16, + .result = "\x05\x25\x92\x46\x61\x79\xd2\xcb" + "\x78\xc4\x0b\x14\x0a\x5a\x9a\xc8", + .rlen = 16, + .loops = 1, + }, { /* Monte Carlo Test */ + .key = "\x9f\x5b\x51\x20\x0b\xf3\x34\xb5" + "\xd8\x2b\xe8\xc3\x72\x55\xc8\x48", + .klen = 16, + .dt = "\x63\x76\xbb\xe5\x29\x02\xba\x3b" + "\x67\xc9\x25\xfa\x70\x1f\x11\xac", + .dtlen = 16, + .v = "\x57\x2c\x8e\x76\x87\x26\x47\x97" + "\x7e\x74\xfb\xdd\xc4\x95\x01\xd1", + .vlen = 16, + .result = "\x48\xe9\xbd\x0d\x06\xee\x18\xfb" + "\xe4\x57\x90\xd5\xc3\xfc\x9b\x73", + .rlen = 16, + .loops = 10000, + }, +}; + /* Cast5 test vectors from RFC 2144 */ #define CAST5_ENC_TEST_VECTORS 3 #define CAST5_DEC_TEST_VECTORS 3 diff --git a/crypto/xor.c b/crypto/xor.c index 996b6ee57d9e..fc5b836f3430 100644 --- a/crypto/xor.c +++ b/crypto/xor.c @@ -101,7 +101,12 @@ calibrate_xor_blocks(void) void *b1, *b2; struct xor_block_template *f, *fastest; - b1 = (void *) __get_free_pages(GFP_KERNEL, 2); + /* + * Note: Since the memory is not actually used for _anything_ but to + * test the XOR speed, we don't really want kmemcheck to warn about + * reading uninitialized bytes here. + */ + b1 = (void *) __get_free_pages(GFP_KERNEL | __GFP_NOTRACK, 2); if (!b1) { printk(KERN_WARNING "xor: Yikes! No memory available.\n"); return -ENOMEM; diff --git a/crypto/zlib.c b/crypto/zlib.c index 33609bab614e..c3015733c990 100644 --- a/crypto/zlib.c +++ b/crypto/zlib.c @@ -165,15 +165,15 @@ static int zlib_compress_update(struct crypto_pcomp *tfm, return -EINVAL; } + ret = req->avail_out - stream->avail_out; pr_debug("avail_in %u, avail_out %u (consumed %u, produced %u)\n", stream->avail_in, stream->avail_out, - req->avail_in - stream->avail_in, - req->avail_out - stream->avail_out); + req->avail_in - stream->avail_in, ret); req->next_in = stream->next_in; req->avail_in = stream->avail_in; req->next_out = stream->next_out; req->avail_out = stream->avail_out; - return 0; + return ret; } static int zlib_compress_final(struct crypto_pcomp *tfm, @@ -195,15 +195,15 @@ static int zlib_compress_final(struct crypto_pcomp *tfm, return -EINVAL; } + ret = req->avail_out - stream->avail_out; pr_debug("avail_in %u, avail_out %u (consumed %u, produced %u)\n", stream->avail_in, stream->avail_out, - req->avail_in - stream->avail_in, - req->avail_out - stream->avail_out); + req->avail_in - stream->avail_in, ret); req->next_in = stream->next_in; req->avail_in = stream->avail_in; req->next_out = stream->next_out; req->avail_out = stream->avail_out; - return 0; + return ret; } @@ -280,15 +280,15 @@ static int zlib_decompress_update(struct crypto_pcomp *tfm, return -EINVAL; } + ret = req->avail_out - stream->avail_out; pr_debug("avail_in %u, avail_out %u (consumed %u, produced %u)\n", stream->avail_in, stream->avail_out, - req->avail_in - stream->avail_in, - req->avail_out - stream->avail_out); + req->avail_in - stream->avail_in, ret); req->next_in = stream->next_in; req->avail_in = stream->avail_in; req->next_out = stream->next_out; req->avail_out = stream->avail_out; - return 0; + return ret; } static int zlib_decompress_final(struct crypto_pcomp *tfm, @@ -328,15 +328,15 @@ static int zlib_decompress_final(struct crypto_pcomp *tfm, return -EINVAL; } + ret = req->avail_out - stream->avail_out; pr_debug("avail_in %u, avail_out %u (consumed %u, produced %u)\n", stream->avail_in, stream->avail_out, - req->avail_in - stream->avail_in, - req->avail_out - stream->avail_out); + req->avail_in - stream->avail_in, ret); req->next_in = stream->next_in; req->avail_in = stream->avail_in; req->next_out = stream->next_out; req->avail_out = stream->avail_out; - return 0; + return ret; } diff --git a/drivers/Kconfig b/drivers/Kconfig index 00cf9553f740..48bbdbe43e69 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -52,6 +52,8 @@ source "drivers/i2c/Kconfig" source "drivers/spi/Kconfig" +source "drivers/pps/Kconfig" + source "drivers/gpio/Kconfig" source "drivers/w1/Kconfig" @@ -104,6 +106,8 @@ source "drivers/auxdisplay/Kconfig" source "drivers/uio/Kconfig" +source "drivers/vlynq/Kconfig" + source "drivers/xen/Kconfig" source "drivers/staging/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 1266ead6ace0..bc4205d2fc3c 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -72,6 +72,7 @@ obj-$(CONFIG_INPUT) += input/ obj-$(CONFIG_I2O) += message/ obj-$(CONFIG_RTC_LIB) += rtc/ obj-y += i2c/ media/ +obj-$(CONFIG_PPS) += pps/ obj-$(CONFIG_W1) += w1/ obj-$(CONFIG_POWER_SUPPLY) += power/ obj-$(CONFIG_HWMON) += hwmon/ @@ -105,5 +106,7 @@ obj-$(CONFIG_PPC_PS3) += ps3/ obj-$(CONFIG_OF) += of/ obj-$(CONFIG_SSB) += ssb/ obj-$(CONFIG_VIRTIO) += virtio/ +obj-$(CONFIG_VLYNQ) += vlynq/ obj-$(CONFIG_STAGING) += staging/ obj-y += platform/ +obj-y += ieee802154/ diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 431f8b439553..7ec7d88c5999 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -266,6 +266,7 @@ config ACPI_DEBUG_FUNC_TRACE config ACPI_PCI_SLOT tristate "PCI slot detection driver" + depends on SYSFS default n help This driver creates entries in /sys/bus/pci/slots/ for all PCI diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c index 88e42abf5d88..0df8fcb687d6 100644 --- a/drivers/acpi/ac.c +++ b/drivers/acpi/ac.c @@ -61,6 +61,7 @@ static int acpi_ac_open_fs(struct inode *inode, struct file *file); static int acpi_ac_add(struct acpi_device *device); static int acpi_ac_remove(struct acpi_device *device, int type); static int acpi_ac_resume(struct acpi_device *device); +static void acpi_ac_notify(struct acpi_device *device, u32 event); static const struct acpi_device_id ac_device_ids[] = { {"ACPI0003", 0}, @@ -72,10 +73,12 @@ static struct acpi_driver acpi_ac_driver = { .name = "ac", .class = ACPI_AC_CLASS, .ids = ac_device_ids, + .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS, .ops = { .add = acpi_ac_add, .remove = acpi_ac_remove, .resume = acpi_ac_resume, + .notify = acpi_ac_notify, }, }; @@ -220,16 +223,14 @@ static int acpi_ac_remove_fs(struct acpi_device *device) Driver Model -------------------------------------------------------------------------- */ -static void acpi_ac_notify(acpi_handle handle, u32 event, void *data) +static void acpi_ac_notify(struct acpi_device *device, u32 event) { - struct acpi_ac *ac = data; - struct acpi_device *device = NULL; + struct acpi_ac *ac = acpi_driver_data(device); if (!ac) return; - device = ac->device; switch (event) { default: ACPI_DEBUG_PRINT((ACPI_DB_INFO, @@ -253,7 +254,6 @@ static void acpi_ac_notify(acpi_handle handle, u32 event, void *data) static int acpi_ac_add(struct acpi_device *device) { int result = 0; - acpi_status status = AE_OK; struct acpi_ac *ac = NULL; @@ -286,13 +286,6 @@ static int acpi_ac_add(struct acpi_device *device) ac->charger.get_property = get_ac_property; power_supply_register(&ac->device->dev, &ac->charger); #endif - status = acpi_install_notify_handler(device->handle, - ACPI_ALL_NOTIFY, acpi_ac_notify, - ac); - if (ACPI_FAILURE(status)) { - result = -ENODEV; - goto end; - } printk(KERN_INFO PREFIX "%s [%s] (%s)\n", acpi_device_name(device), acpi_device_bid(device), @@ -328,7 +321,6 @@ static int acpi_ac_resume(struct acpi_device *device) static int acpi_ac_remove(struct acpi_device *device, int type) { - acpi_status status = AE_OK; struct acpi_ac *ac = NULL; @@ -337,8 +329,6 @@ static int acpi_ac_remove(struct acpi_device *device, int type) ac = acpi_driver_data(device); - status = acpi_remove_notify_handler(device->handle, - ACPI_ALL_NOTIFY, acpi_ac_notify); #ifdef CONFIG_ACPI_SYSFS_POWER if (ac->charger.dev) power_supply_unregister(&ac->charger); diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h index 07e20135f01b..0bba148a2c61 100644 --- a/drivers/acpi/acpica/acevents.h +++ b/drivers/acpi/acpica/acevents.h @@ -139,7 +139,7 @@ acpi_status acpi_ev_initialize_op_regions(void); acpi_status acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, u32 function, - acpi_physical_address address, + u32 region_offset, u32 bit_width, acpi_integer * value); acpi_status diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index 16e5210ae936..3d87362d17ed 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -362,9 +362,6 @@ extern u8 acpi_gbl_method_executing; extern u8 acpi_gbl_abort_method; extern u8 acpi_gbl_db_terminate_threads; -ACPI_EXTERN int optind; -ACPI_EXTERN char *optarg; - ACPI_EXTERN u8 acpi_gbl_db_opt_tables; ACPI_EXTERN u8 acpi_gbl_db_opt_stats; ACPI_EXTERN u8 acpi_gbl_db_opt_ini_methods; diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 2ec394a328e9..ee986edfa0da 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -205,6 +205,7 @@ struct acpi_namespace_node { #define ANOBJ_METHOD_LOCAL 0x08 /* Node is a method local */ #define ANOBJ_SUBTREE_HAS_INI 0x10 /* Used to optimize device initialization */ #define ANOBJ_EVALUATED 0x20 /* Set on first evaluation of node */ +#define ANOBJ_ALLOCATED_BUFFER 0x40 /* Method AML buffer is dynamic (install_method) */ #define ANOBJ_IS_EXTERNAL 0x08 /* i_aSL only: This object created via External() */ #define ANOBJ_METHOD_NO_RETVAL 0x10 /* i_aSL only: Method has no return value */ @@ -788,11 +789,14 @@ struct acpi_bit_register_info { /* For control registers, both ignored and reserved bits must be preserved */ /* - * The ACPI spec says to ignore PM1_CTL.SCI_EN (bit 0) - * but we need to be able to write ACPI_BITREG_SCI_ENABLE directly - * as a BIOS workaround on some machines. + * For PM1 control, the SCI enable bit (bit 0, SCI_EN) is defined by the + * ACPI specification to be a "preserved" bit - "OSPM always preserves this + * bit position", section 4.7.3.2.1. However, on some machines the OS must + * write a one to this bit after resume for the machine to work properly. + * To enable this, we no longer attempt to preserve this bit. No machines + * are known to fail if the bit is not preserved. (May 2009) */ -#define ACPI_PM1_CONTROL_IGNORED_BITS 0x0200 /* Bits 9 */ +#define ACPI_PM1_CONTROL_IGNORED_BITS 0x0200 /* Bit 9 */ #define ACPI_PM1_CONTROL_RESERVED_BITS 0xC1F8 /* Bits 14-15, 3-8 */ #define ACPI_PM1_CONTROL_PRESERVED_BITS \ (ACPI_PM1_CONTROL_IGNORED_BITS | ACPI_PM1_CONTROL_RESERVED_BITS) diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h index 46cb5b46d280..94cdc2b8cb93 100644 --- a/drivers/acpi/acpica/acnamesp.h +++ b/drivers/acpi/acpica/acnamesp.h @@ -99,10 +99,19 @@ acpi_ns_walk_namespace(acpi_object_type type, acpi_walk_callback user_function, void *context, void **return_value); -struct acpi_namespace_node *acpi_ns_get_next_node(acpi_object_type type, struct acpi_namespace_node - *parent, struct acpi_namespace_node +struct acpi_namespace_node *acpi_ns_get_next_node(struct acpi_namespace_node + *parent, + struct acpi_namespace_node *child); +struct acpi_namespace_node *acpi_ns_get_next_node_typed(acpi_object_type type, + struct + acpi_namespace_node + *parent, + struct + acpi_namespace_node + *child); + /* * nsparse - table parsing */ diff --git a/drivers/acpi/acpica/amlcode.h b/drivers/acpi/acpica/amlcode.h index ff851c5df698..067f967eb389 100644 --- a/drivers/acpi/acpica/amlcode.h +++ b/drivers/acpi/acpica/amlcode.h @@ -483,7 +483,7 @@ typedef enum { #define AML_METHOD_ARG_COUNT 0x07 #define AML_METHOD_SERIALIZED 0x08 -#define AML_METHOD_SYNCH_LEVEL 0xF0 +#define AML_METHOD_SYNC_LEVEL 0xF0 /* METHOD_FLAGS_ARG_COUNT is not used internally, define additional flags */ diff --git a/drivers/acpi/acpica/dsobject.c b/drivers/acpi/acpica/dsobject.c index dab3f48f0b42..02e6caad4a76 100644 --- a/drivers/acpi/acpica/dsobject.c +++ b/drivers/acpi/acpica/dsobject.c @@ -734,7 +734,8 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state, /* Local ID (0-7) is (AML opcode - base AML_LOCAL_OP) */ - obj_desc->reference.value = opcode - AML_LOCAL_OP; + obj_desc->reference.value = + ((u32)opcode) - AML_LOCAL_OP; obj_desc->reference.class = ACPI_REFCLASS_LOCAL; #ifndef ACPI_NO_METHOD_EXECUTION @@ -754,7 +755,7 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state, /* Arg ID (0-6) is (AML opcode - base AML_ARG_OP) */ - obj_desc->reference.value = opcode - AML_ARG_OP; + obj_desc->reference.value = ((u32)opcode) - AML_ARG_OP; obj_desc->reference.class = ACPI_REFCLASS_ARG; #ifndef ACPI_NO_METHOD_EXECUTION diff --git a/drivers/acpi/acpica/dsopcode.c b/drivers/acpi/acpica/dsopcode.c index b4c87b5053e6..584d766e6f12 100644 --- a/drivers/acpi/acpica/dsopcode.c +++ b/drivers/acpi/acpica/dsopcode.c @@ -1386,14 +1386,19 @@ acpi_ds_exec_end_control_op(struct acpi_walk_state * walk_state, case AML_BREAK_POINT_OP: - /* Call up to the OS service layer to handle this */ + /* + * Set the single-step flag. This will cause the debugger (if present) + * to break to the console within the AML debugger at the start of the + * next AML instruction. + */ + ACPI_DEBUGGER_EXEC(acpi_gbl_cm_single_step = TRUE); + ACPI_DEBUGGER_EXEC(acpi_os_printf + ("**break** Executed AML BreakPoint opcode\n")); - status = - acpi_os_signal(ACPI_SIGNAL_BREAKPOINT, - "Executed AML Breakpoint opcode"); - - /* If and when it returns, all done. */ + /* Call to the OSL in case OS wants a piece of the action */ + status = acpi_os_signal(ACPI_SIGNAL_BREAKPOINT, + "Executed AML Breakpoint opcode"); break; case AML_BREAK_OP: diff --git a/drivers/acpi/acpica/dswstate.c b/drivers/acpi/acpica/dswstate.c index 40f92bf7dce5..e46c821cf572 100644 --- a/drivers/acpi/acpica/dswstate.c +++ b/drivers/acpi/acpica/dswstate.c @@ -102,7 +102,7 @@ acpi_ds_result_pop(union acpi_operand_object **object, /* Return object of the top element and clean that top element result stack */ walk_state->result_count--; - index = walk_state->result_count % ACPI_RESULTS_FRAME_OBJ_NUM; + index = (u32)walk_state->result_count % ACPI_RESULTS_FRAME_OBJ_NUM; *object = state->results.obj_desc[index]; if (!*object) { @@ -186,7 +186,7 @@ acpi_ds_result_push(union acpi_operand_object * object, /* Assign the address of object to the top free element of result stack */ - index = walk_state->result_count % ACPI_RESULTS_FRAME_OBJ_NUM; + index = (u32)walk_state->result_count % ACPI_RESULTS_FRAME_OBJ_NUM; state->results.obj_desc[index] = object; walk_state->result_count++; diff --git a/drivers/acpi/acpica/evregion.c b/drivers/acpi/acpica/evregion.c index 538d63264555..98c7f9c62653 100644 --- a/drivers/acpi/acpica/evregion.c +++ b/drivers/acpi/acpica/evregion.c @@ -275,7 +275,7 @@ acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function) * * PARAMETERS: region_obj - Internal region object * Function - Read or Write operation - * Address - Where in the space to read or write + * region_offset - Where in the region to read or write * bit_width - Field width in bits (8, 16, 32, or 64) * Value - Pointer to in or out value, must be * full 64-bit acpi_integer @@ -290,7 +290,7 @@ acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function) acpi_status acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, u32 function, - acpi_physical_address address, + u32 region_offset, u32 bit_width, acpi_integer * value) { acpi_status status; @@ -396,7 +396,8 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, "Handler %p (@%p) Address %8.8X%8.8X [%s]\n", ®ion_obj->region.handler->address_space, handler, - ACPI_FORMAT_NATIVE_UINT(address), + ACPI_FORMAT_NATIVE_UINT(region_obj->region.address + + region_offset), acpi_ut_get_region_name(region_obj->region. space_id))); @@ -412,8 +413,9 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, /* Call the handler */ - status = handler(function, address, bit_width, value, - handler_desc->address_space.context, + status = handler(function, + (region_obj->region.address + region_offset), + bit_width, value, handler_desc->address_space.context, region_obj2->extra.region_context); if (ACPI_FAILURE(status)) { diff --git a/drivers/acpi/acpica/evxfevnt.c b/drivers/acpi/acpica/evxfevnt.c index d0a080747ec3..4721f58fe42c 100644 --- a/drivers/acpi/acpica/evxfevnt.c +++ b/drivers/acpi/acpica/evxfevnt.c @@ -51,7 +51,7 @@ ACPI_MODULE_NAME("evxfevnt") /* Local prototypes */ -acpi_status +static acpi_status acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info, struct acpi_gpe_block_info *gpe_block, void *context); @@ -785,7 +785,7 @@ ACPI_EXPORT_SYMBOL(acpi_get_gpe_device) * block device. NULL if the GPE is one of the FADT-defined GPEs. * ******************************************************************************/ -acpi_status +static acpi_status acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info, struct acpi_gpe_block_info *gpe_block, void *context) { diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c index 3deb20a126b2..277fd609611a 100644 --- a/drivers/acpi/acpica/exconfig.c +++ b/drivers/acpi/acpica/exconfig.c @@ -47,6 +47,7 @@ #include "acnamesp.h" #include "actables.h" #include "acdispat.h" +#include "acevents.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exconfig") @@ -57,6 +58,10 @@ acpi_ex_add_table(u32 table_index, struct acpi_namespace_node *parent_node, union acpi_operand_object **ddb_handle); +static acpi_status +acpi_ex_region_read(union acpi_operand_object *obj_desc, + u32 length, u8 *buffer); + /******************************************************************************* * * FUNCTION: acpi_ex_add_table @@ -91,6 +96,7 @@ acpi_ex_add_table(u32 table_index, /* Init the table handle */ + obj_desc->common.flags |= AOPOBJ_DATA_VALID; obj_desc->reference.class = ACPI_REFCLASS_TABLE; *ddb_handle = obj_desc; @@ -229,6 +235,8 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state, walk_state); if (ACPI_FAILURE(status)) { (void)acpi_ex_unload_table(ddb_handle); + + acpi_ut_remove_reference(ddb_handle); return_ACPI_STATUS(status); } } @@ -252,6 +260,47 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state, return_ACPI_STATUS(status); } +/******************************************************************************* + * + * FUNCTION: acpi_ex_region_read + * + * PARAMETERS: obj_desc - Region descriptor + * Length - Number of bytes to read + * Buffer - Pointer to where to put the data + * + * RETURN: Status + * + * DESCRIPTION: Read data from an operation region. The read starts from the + * beginning of the region. + * + ******************************************************************************/ + +static acpi_status +acpi_ex_region_read(union acpi_operand_object *obj_desc, u32 length, u8 *buffer) +{ + acpi_status status; + acpi_integer value; + u32 region_offset = 0; + u32 i; + + /* Bytewise reads */ + + for (i = 0; i < length; i++) { + status = acpi_ev_address_space_dispatch(obj_desc, ACPI_READ, + region_offset, 8, + &value); + if (ACPI_FAILURE(status)) { + return status; + } + + *buffer = (u8)value; + buffer++; + region_offset++; + } + + return AE_OK; +} + /******************************************************************************* * * FUNCTION: acpi_ex_load_op @@ -314,18 +363,23 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, } } - /* - * Map the table header and get the actual table length. The region - * length is not guaranteed to be the same as the table length. - */ - table = acpi_os_map_memory(obj_desc->region.address, - sizeof(struct acpi_table_header)); + /* Get the table header first so we can get the table length */ + + table = ACPI_ALLOCATE(sizeof(struct acpi_table_header)); if (!table) { return_ACPI_STATUS(AE_NO_MEMORY); } + status = + acpi_ex_region_read(obj_desc, + sizeof(struct acpi_table_header), + ACPI_CAST_PTR(u8, table)); length = table->length; - acpi_os_unmap_memory(table, sizeof(struct acpi_table_header)); + ACPI_FREE(table); + + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } /* Must have at least an ACPI table header */ @@ -334,10 +388,19 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, } /* - * The memory region is not guaranteed to remain stable and we must - * copy the table to a local buffer. For example, the memory region - * is corrupted after suspend on some machines. Dynamically loaded - * tables are usually small, so this overhead is minimal. + * The original implementation simply mapped the table, with no copy. + * However, the memory region is not guaranteed to remain stable and + * we must copy the table to a local buffer. For example, the memory + * region is corrupted after suspend on some machines. Dynamically + * loaded tables are usually small, so this overhead is minimal. + * + * The latest implementation (5/2009) does not use a mapping at all. + * We use the low-level operation region interface to read the table + * instead of the obvious optimization of using a direct mapping. + * This maintains a consistent use of operation regions across the + * entire subsystem. This is important if additional processing must + * be performed in the (possibly user-installed) operation region + * handler. For example, acpi_exec and ASLTS depend on this. */ /* Allocate a buffer for the table */ @@ -347,17 +410,16 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, return_ACPI_STATUS(AE_NO_MEMORY); } - /* Map the entire table and copy it */ + /* Read the entire table */ - table = acpi_os_map_memory(obj_desc->region.address, length); - if (!table) { + status = acpi_ex_region_read(obj_desc, length, + ACPI_CAST_PTR(u8, + table_desc.pointer)); + if (ACPI_FAILURE(status)) { ACPI_FREE(table_desc.pointer); - return_ACPI_STATUS(AE_NO_MEMORY); + return_ACPI_STATUS(status); } - ACPI_MEMCPY(table_desc.pointer, table, length); - acpi_os_unmap_memory(table, length); - table_desc.address = obj_desc->region.address; break; @@ -454,6 +516,10 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, return_ACPI_STATUS(status); } + /* Remove the reference by added by acpi_ex_store above */ + + acpi_ut_remove_reference(ddb_handle); + /* Invoke table handler if present */ if (acpi_gbl_table_handler) { @@ -495,13 +561,18 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle) /* * Validate the handle - * Although the handle is partially validated in acpi_ex_reconfiguration(), + * Although the handle is partially validated in acpi_ex_reconfiguration() * when it calls acpi_ex_resolve_operands(), the handle is more completely * validated here. + * + * Handle must be a valid operand object of type reference. Also, the + * ddb_handle must still be marked valid (table has not been previously + * unloaded) */ if ((!ddb_handle) || (ACPI_GET_DESCRIPTOR_TYPE(ddb_handle) != ACPI_DESC_TYPE_OPERAND) || - (ddb_handle->common.type != ACPI_TYPE_LOCAL_REFERENCE)) { + (ddb_handle->common.type != ACPI_TYPE_LOCAL_REFERENCE) || + (!(ddb_handle->common.flags & AOPOBJ_DATA_VALID))) { return_ACPI_STATUS(AE_BAD_PARAMETER); } @@ -509,6 +580,12 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle) table_index = table_desc->reference.value; + /* Ensure the table is still loaded */ + + if (!acpi_tb_is_table_loaded(table_index)) { + return_ACPI_STATUS(AE_NOT_EXIST); + } + /* Invoke table handler if present */ if (acpi_gbl_table_handler) { @@ -530,8 +607,10 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle) (void)acpi_tb_release_owner_id(table_index); acpi_tb_set_table_loaded_flag(table_index, FALSE); - /* Table unloaded, remove a reference to the ddb_handle object */ - - acpi_ut_remove_reference(ddb_handle); + /* + * Invalidate the handle. We do this because the handle may be stored + * in a named object and may not be actually deleted until much later. + */ + ddb_handle->common.flags &= ~AOPOBJ_DATA_VALID; return_ACPI_STATUS(AE_OK); } diff --git a/drivers/acpi/acpica/excreate.c b/drivers/acpi/acpica/excreate.c index a57ad2564ab0..02b25d233d99 100644 --- a/drivers/acpi/acpica/excreate.c +++ b/drivers/acpi/acpica/excreate.c @@ -502,7 +502,7 @@ acpi_ex_create_method(u8 * aml_start, * ACPI 2.0: sync_level = sync_level in method declaration */ obj_desc->method.sync_level = (u8) - ((method_flags & AML_METHOD_SYNCH_LEVEL) >> 4); + ((method_flags & AML_METHOD_SYNC_LEVEL) >> 4); } /* Attach the new object to the method Node */ diff --git a/drivers/acpi/acpica/exdump.c b/drivers/acpi/acpica/exdump.c index 89d141fdae0b..ec524614e708 100644 --- a/drivers/acpi/acpica/exdump.c +++ b/drivers/acpi/acpica/exdump.c @@ -120,9 +120,11 @@ static struct acpi_exdump_info acpi_ex_dump_event[2] = { {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(event.os_semaphore), "OsSemaphore"} }; -static struct acpi_exdump_info acpi_ex_dump_method[8] = { +static struct acpi_exdump_info acpi_ex_dump_method[9] = { {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_method), NULL}, - {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.param_count), "ParamCount"}, + {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.method_flags), "Method Flags"}, + {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.param_count), + "Parameter Count"}, {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.sync_level), "Sync Level"}, {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(method.mutex), "Mutex"}, {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.owner_id), "Owner Id"}, diff --git a/drivers/acpi/acpica/exfldio.c b/drivers/acpi/acpica/exfldio.c index 99cee61e655d..d4075b821021 100644 --- a/drivers/acpi/acpica/exfldio.c +++ b/drivers/acpi/acpica/exfldio.c @@ -222,7 +222,7 @@ acpi_ex_access_region(union acpi_operand_object *obj_desc, { acpi_status status; union acpi_operand_object *rgn_desc; - acpi_physical_address address; + u32 region_offset; ACPI_FUNCTION_TRACE(ex_access_region); @@ -243,7 +243,7 @@ acpi_ex_access_region(union acpi_operand_object *obj_desc, * 3) The current offset into the field */ rgn_desc = obj_desc->common_field.region_obj; - address = rgn_desc->region.address + + region_offset = obj_desc->common_field.base_byte_offset + field_datum_byte_offset; if ((function & ACPI_IO_MASK) == ACPI_READ) { @@ -260,16 +260,18 @@ acpi_ex_access_region(union acpi_operand_object *obj_desc, obj_desc->common_field.access_byte_width, obj_desc->common_field.base_byte_offset, field_datum_byte_offset, ACPI_CAST_PTR(void, - address))); + (rgn_desc-> + region. + address + + region_offset)))); /* Invoke the appropriate address_space/op_region handler */ - status = acpi_ev_address_space_dispatch(rgn_desc, function, - address, - ACPI_MUL_8(obj_desc-> - common_field. - access_byte_width), - value); + status = + acpi_ev_address_space_dispatch(rgn_desc, function, region_offset, + ACPI_MUL_8(obj_desc->common_field. + access_byte_width), + value); if (ACPI_FAILURE(status)) { if (status == AE_NOT_IMPLEMENTED) { diff --git a/drivers/acpi/acpica/exmutex.c b/drivers/acpi/acpica/exmutex.c index d301c1f363ef..2f0114202b05 100644 --- a/drivers/acpi/acpica/exmutex.c +++ b/drivers/acpi/acpica/exmutex.c @@ -83,6 +83,15 @@ void acpi_ex_unlink_mutex(union acpi_operand_object *obj_desc) if (obj_desc->mutex.prev) { (obj_desc->mutex.prev)->mutex.next = obj_desc->mutex.next; + + /* + * Migrate the previous sync level associated with this mutex to the + * previous mutex on the list so that it may be preserved. This handles + * the case where several mutexes have been acquired at the same level, + * but are not released in opposite order. + */ + (obj_desc->mutex.prev)->mutex.original_sync_level = + obj_desc->mutex.original_sync_level; } else { thread->acquired_mutex_list = obj_desc->mutex.next; } @@ -349,6 +358,7 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, struct acpi_walk_state *walk_state) { acpi_status status = AE_OK; + u8 previous_sync_level; ACPI_FUNCTION_TRACE(ex_release_mutex); @@ -373,11 +383,12 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, walk_state->thread->thread_id) && (obj_desc != acpi_gbl_global_lock_mutex)) { ACPI_ERROR((AE_INFO, - "Thread %lX cannot release Mutex [%4.4s] acquired by thread %lX", - (unsigned long)walk_state->thread->thread_id, + "Thread %p cannot release Mutex [%4.4s] acquired by thread %p", + ACPI_CAST_PTR(void, walk_state->thread->thread_id), acpi_ut_get_node_name(obj_desc->mutex.node), - (unsigned long)obj_desc->mutex.owner_thread-> - thread_id)); + ACPI_CAST_PTR(void, + obj_desc->mutex.owner_thread-> + thread_id))); return_ACPI_STATUS(AE_AML_NOT_OWNER); } @@ -391,10 +402,14 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, } /* - * The sync level of the mutex must be less than or equal to the current - * sync level + * The sync level of the mutex must be equal to the current sync level. In + * other words, the current level means that at least one mutex at that + * level is currently being held. Attempting to release a mutex of a + * different level can only mean that the mutex ordering rule is being + * violated. This behavior is clarified in ACPI 4.0 specification. */ - if (obj_desc->mutex.sync_level > walk_state->thread->current_sync_level) { + if (obj_desc->mutex.sync_level != + walk_state->thread->current_sync_level) { ACPI_ERROR((AE_INFO, "Cannot release Mutex [%4.4s], SyncLevel mismatch: mutex %d current %d", acpi_ut_get_node_name(obj_desc->mutex.node), @@ -403,14 +418,24 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, return_ACPI_STATUS(AE_AML_MUTEX_ORDER); } + /* + * Get the previous sync_level from the head of the acquired mutex list. + * This handles the case where several mutexes at the same level have been + * acquired, but are not released in reverse order. + */ + previous_sync_level = + walk_state->thread->acquired_mutex_list->mutex.original_sync_level; + status = acpi_ex_release_mutex_object(obj_desc); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } if (obj_desc->mutex.acquisition_depth == 0) { - /* Restore the original sync_level */ + /* Restore the previous sync_level */ - walk_state->thread->current_sync_level = - obj_desc->mutex.original_sync_level; + walk_state->thread->current_sync_level = previous_sync_level; } return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/exstore.c b/drivers/acpi/acpica/exstore.c index 90d606196c99..6efd07a4f779 100644 --- a/drivers/acpi/acpica/exstore.c +++ b/drivers/acpi/acpica/exstore.c @@ -193,10 +193,12 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc, case ACPI_REFCLASS_TABLE: + /* Case for ddb_handle */ + ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "Table Index 0x%X\n", source_desc->reference.value)); - break; + return; default: break; diff --git a/drivers/acpi/acpica/hwregs.c b/drivers/acpi/acpica/hwregs.c index 7b2fb602b5cb..23d5505cb1f7 100644 --- a/drivers/acpi/acpica/hwregs.c +++ b/drivers/acpi/acpica/hwregs.c @@ -81,9 +81,9 @@ acpi_status acpi_hw_clear_acpi_status(void) ACPI_FUNCTION_TRACE(hw_clear_acpi_status); - ACPI_DEBUG_PRINT((ACPI_DB_IO, "About to write %04X to %0llX\n", + ACPI_DEBUG_PRINT((ACPI_DB_IO, "About to write %04X to %8.8X%8.8X\n", ACPI_BITMASK_ALL_FIXED_STATUS, - acpi_gbl_xpm1a_status.address)); + ACPI_FORMAT_UINT64(acpi_gbl_xpm1a_status.address))); lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock); diff --git a/drivers/acpi/acpica/nsalloc.c b/drivers/acpi/acpica/nsalloc.c index aceb93111967..efc971ab7d65 100644 --- a/drivers/acpi/acpica/nsalloc.c +++ b/drivers/acpi/acpica/nsalloc.c @@ -334,9 +334,7 @@ void acpi_ns_delete_namespace_subtree(struct acpi_namespace_node *parent_node) /* Get the next node in this scope (NULL if none) */ - child_node = - acpi_ns_get_next_node(ACPI_TYPE_ANY, parent_node, - child_node); + child_node = acpi_ns_get_next_node(parent_node, child_node); if (child_node) { /* Found a child node - detach any attached object */ @@ -345,8 +343,7 @@ void acpi_ns_delete_namespace_subtree(struct acpi_namespace_node *parent_node) /* Check if this node has any children */ - if (acpi_ns_get_next_node - (ACPI_TYPE_ANY, child_node, NULL)) { + if (child_node->child) { /* * There is at least one child of this node, * visit the node @@ -432,9 +429,7 @@ void acpi_ns_delete_namespace_by_owner(acpi_owner_id owner_id) * Get the next child of this parent node. When child_node is NULL, * the first child of the parent is returned */ - child_node = - acpi_ns_get_next_node(ACPI_TYPE_ANY, parent_node, - child_node); + child_node = acpi_ns_get_next_node(parent_node, child_node); if (deletion_node) { acpi_ns_delete_children(deletion_node); @@ -452,8 +447,7 @@ void acpi_ns_delete_namespace_by_owner(acpi_owner_id owner_id) /* Check if this node has any children */ - if (acpi_ns_get_next_node - (ACPI_TYPE_ANY, child_node, NULL)) { + if (child_node->child) { /* * There is at least one child of this node, * visit the node diff --git a/drivers/acpi/acpica/nsnames.c b/drivers/acpi/acpica/nsnames.c index ae3dc10a7e81..af8e6bcee07e 100644 --- a/drivers/acpi/acpica/nsnames.c +++ b/drivers/acpi/acpica/nsnames.c @@ -149,7 +149,7 @@ char *acpi_ns_get_external_pathname(struct acpi_namespace_node *node) name_buffer = ACPI_ALLOCATE_ZEROED(size); if (!name_buffer) { - ACPI_ERROR((AE_INFO, "Allocation failure")); + ACPI_ERROR((AE_INFO, "Could not allocate %u bytes", (u32)size)); return_PTR(NULL); } diff --git a/drivers/acpi/acpica/nsobject.c b/drivers/acpi/acpica/nsobject.c index 3eb20bfda9d8..60f3af08d28c 100644 --- a/drivers/acpi/acpica/nsobject.c +++ b/drivers/acpi/acpica/nsobject.c @@ -213,6 +213,15 @@ void acpi_ns_detach_object(struct acpi_namespace_node *node) return_VOID; } + if (node->flags & ANOBJ_ALLOCATED_BUFFER) { + + /* Free the dynamic aml buffer */ + + if (obj_desc->common.type == ACPI_TYPE_METHOD) { + ACPI_FREE(obj_desc->method.aml_start); + } + } + /* Clear the entry in all cases */ node->object = NULL; diff --git a/drivers/acpi/acpica/nspredef.c b/drivers/acpi/acpica/nspredef.c index d9e8cbc6e679..7f8e066b12a3 100644 --- a/drivers/acpi/acpica/nspredef.c +++ b/drivers/acpi/acpica/nspredef.c @@ -144,7 +144,7 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node, pathname = acpi_ns_get_external_pathname(node); if (!pathname) { - pathname = ACPI_CAST_PTR(char, predefined->info.name); + return AE_OK; /* Could not get pathname, ignore */ } /* @@ -230,10 +230,7 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node, } exit: - if (pathname != predefined->info.name) { - ACPI_FREE(pathname); - } - + ACPI_FREE(pathname); return (status); } diff --git a/drivers/acpi/acpica/nssearch.c b/drivers/acpi/acpica/nssearch.c index f9b4f51bf8f2..7e865639a928 100644 --- a/drivers/acpi/acpica/nssearch.c +++ b/drivers/acpi/acpica/nssearch.c @@ -45,6 +45,10 @@ #include "accommon.h" #include "acnamesp.h" +#ifdef ACPI_ASL_COMPILER +#include "amlcode.h" +#endif + #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nssearch") diff --git a/drivers/acpi/acpica/nswalk.c b/drivers/acpi/acpica/nswalk.c index 83e3aa6d4b9b..35539df5c75d 100644 --- a/drivers/acpi/acpica/nswalk.c +++ b/drivers/acpi/acpica/nswalk.c @@ -52,6 +52,51 @@ ACPI_MODULE_NAME("nswalk") * * FUNCTION: acpi_ns_get_next_node * + * PARAMETERS: parent_node - Parent node whose children we are + * getting + * child_node - Previous child that was found. + * The NEXT child will be returned + * + * RETURN: struct acpi_namespace_node - Pointer to the NEXT child or NULL if + * none is found. + * + * DESCRIPTION: Return the next peer node within the namespace. If Handle + * is valid, Scope is ignored. Otherwise, the first node + * within Scope is returned. + * + ******************************************************************************/ +struct acpi_namespace_node *acpi_ns_get_next_node(struct acpi_namespace_node + *parent_node, + struct acpi_namespace_node + *child_node) +{ + ACPI_FUNCTION_ENTRY(); + + if (!child_node) { + + /* It's really the parent's _scope_ that we want */ + + return parent_node->child; + } + + /* + * Get the next node. + * + * If we are at the end of this peer list, return NULL + */ + if (child_node->flags & ANOBJ_END_OF_PEER_LIST) { + return NULL; + } + + /* Otherwise just return the next peer */ + + return child_node->peer; +} + +/******************************************************************************* + * + * FUNCTION: acpi_ns_get_next_node_typed + * * PARAMETERS: Type - Type of node to be searched for * parent_node - Parent node whose children we are * getting @@ -66,26 +111,21 @@ ACPI_MODULE_NAME("nswalk") * within Scope is returned. * ******************************************************************************/ -struct acpi_namespace_node *acpi_ns_get_next_node(acpi_object_type type, struct acpi_namespace_node - *parent_node, struct acpi_namespace_node - *child_node) + +struct acpi_namespace_node *acpi_ns_get_next_node_typed(acpi_object_type type, + struct + acpi_namespace_node + *parent_node, + struct + acpi_namespace_node + *child_node) { struct acpi_namespace_node *next_node = NULL; ACPI_FUNCTION_ENTRY(); - if (!child_node) { + next_node = acpi_ns_get_next_node(parent_node, child_node); - /* It's really the parent's _scope_ that we want */ - - next_node = parent_node->child; - } - - else { - /* Start search at the NEXT node */ - - next_node = acpi_ns_get_next_valid_node(child_node); - } /* If any type is OK, we are done */ @@ -186,9 +226,7 @@ acpi_ns_walk_namespace(acpi_object_type type, /* Get the next node in this scope. Null if not found */ status = AE_OK; - child_node = - acpi_ns_get_next_node(ACPI_TYPE_ANY, parent_node, - child_node); + child_node = acpi_ns_get_next_node(parent_node, child_node); if (child_node) { /* Found next child, get the type if we are not searching for ANY */ @@ -269,8 +307,7 @@ acpi_ns_walk_namespace(acpi_object_type type, * function has specified that the maximum depth has been reached. */ if ((level < max_depth) && (status != AE_CTRL_DEPTH)) { - if (acpi_ns_get_next_node - (ACPI_TYPE_ANY, child_node, NULL)) { + if (child_node->child) { /* There is at least one child of this node, visit it */ diff --git a/drivers/acpi/acpica/nsxfname.c b/drivers/acpi/acpica/nsxfname.c index 9589fea24997..f23593d6add4 100644 --- a/drivers/acpi/acpica/nsxfname.c +++ b/drivers/acpi/acpica/nsxfname.c @@ -45,6 +45,8 @@ #include #include "accommon.h" #include "acnamesp.h" +#include "acparser.h" +#include "amlcode.h" #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsxfname") @@ -358,3 +360,151 @@ acpi_get_object_info(acpi_handle handle, struct acpi_buffer * buffer) } ACPI_EXPORT_SYMBOL(acpi_get_object_info) + +/****************************************************************************** + * + * FUNCTION: acpi_install_method + * + * PARAMETERS: Buffer - An ACPI table containing one control method + * + * RETURN: Status + * + * DESCRIPTION: Install a control method into the namespace. If the method + * name already exists in the namespace, it is overwritten. The + * input buffer must contain a valid DSDT or SSDT containing a + * single control method. + * + ******************************************************************************/ +acpi_status acpi_install_method(u8 *buffer) +{ + struct acpi_table_header *table = + ACPI_CAST_PTR(struct acpi_table_header, buffer); + u8 *aml_buffer; + u8 *aml_start; + char *path; + struct acpi_namespace_node *node; + union acpi_operand_object *method_obj; + struct acpi_parse_state parser_state; + u32 aml_length; + u16 opcode; + u8 method_flags; + acpi_status status; + + /* Parameter validation */ + + if (!buffer) { + return AE_BAD_PARAMETER; + } + + /* Table must be a DSDT or SSDT */ + + if (!ACPI_COMPARE_NAME(table->signature, ACPI_SIG_DSDT) && + !ACPI_COMPARE_NAME(table->signature, ACPI_SIG_SSDT)) { + return AE_BAD_HEADER; + } + + /* First AML opcode in the table must be a control method */ + + parser_state.aml = buffer + sizeof(struct acpi_table_header); + opcode = acpi_ps_peek_opcode(&parser_state); + if (opcode != AML_METHOD_OP) { + return AE_BAD_PARAMETER; + } + + /* Extract method information from the raw AML */ + + parser_state.aml += acpi_ps_get_opcode_size(opcode); + parser_state.pkg_end = acpi_ps_get_next_package_end(&parser_state); + path = acpi_ps_get_next_namestring(&parser_state); + method_flags = *parser_state.aml++; + aml_start = parser_state.aml; + aml_length = ACPI_PTR_DIFF(parser_state.pkg_end, aml_start); + + /* + * Allocate resources up-front. We don't want to have to delete a new + * node from the namespace if we cannot allocate memory. + */ + aml_buffer = ACPI_ALLOCATE(aml_length); + if (!aml_buffer) { + return AE_NO_MEMORY; + } + + method_obj = acpi_ut_create_internal_object(ACPI_TYPE_METHOD); + if (!method_obj) { + ACPI_FREE(aml_buffer); + return AE_NO_MEMORY; + } + + /* Lock namespace for acpi_ns_lookup, we may be creating a new node */ + + status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE(status)) { + goto error_exit; + } + + /* The lookup either returns an existing node or creates a new one */ + + status = + acpi_ns_lookup(NULL, path, ACPI_TYPE_METHOD, ACPI_IMODE_LOAD_PASS1, + ACPI_NS_DONT_OPEN_SCOPE | ACPI_NS_ERROR_IF_FOUND, + NULL, &node); + + (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); + + if (ACPI_FAILURE(status)) { /* ns_lookup */ + if (status != AE_ALREADY_EXISTS) { + goto error_exit; + } + + /* Node existed previously, make sure it is a method node */ + + if (node->type != ACPI_TYPE_METHOD) { + status = AE_TYPE; + goto error_exit; + } + } + + /* Copy the method AML to the local buffer */ + + ACPI_MEMCPY(aml_buffer, aml_start, aml_length); + + /* Initialize the method object with the new method's information */ + + method_obj->method.aml_start = aml_buffer; + method_obj->method.aml_length = aml_length; + + method_obj->method.param_count = (u8) + (method_flags & AML_METHOD_ARG_COUNT); + + method_obj->method.method_flags = (u8) + (method_flags & ~AML_METHOD_ARG_COUNT); + + if (method_flags & AML_METHOD_SERIALIZED) { + method_obj->method.sync_level = (u8) + ((method_flags & AML_METHOD_SYNC_LEVEL) >> 4); + } + + /* + * Now that it is complete, we can attach the new method object to + * the method Node (detaches/deletes any existing object) + */ + status = acpi_ns_attach_object(node, method_obj, ACPI_TYPE_METHOD); + + /* + * Flag indicates AML buffer is dynamic, must be deleted later. + * Must be set only after attach above. + */ + node->flags |= ANOBJ_ALLOCATED_BUFFER; + + /* Remove local reference to the method object */ + + acpi_ut_remove_reference(method_obj); + return status; + +error_exit: + + ACPI_FREE(aml_buffer); + ACPI_FREE(method_obj); + return status; +} +ACPI_EXPORT_SYMBOL(acpi_install_method) diff --git a/drivers/acpi/acpica/nsxfobj.c b/drivers/acpi/acpica/nsxfobj.c index 1c7efc15225f..4071bad4458e 100644 --- a/drivers/acpi/acpica/nsxfobj.c +++ b/drivers/acpi/acpica/nsxfobj.c @@ -162,6 +162,7 @@ ACPI_EXPORT_SYMBOL(acpi_get_type) acpi_status acpi_get_parent(acpi_handle handle, acpi_handle * ret_handle) { struct acpi_namespace_node *node; + struct acpi_namespace_node *parent_node; acpi_status status; if (!ret_handle) { @@ -189,12 +190,12 @@ acpi_status acpi_get_parent(acpi_handle handle, acpi_handle * ret_handle) /* Get the parent entry */ - *ret_handle = - acpi_ns_convert_entry_to_handle(acpi_ns_get_parent_node(node)); + parent_node = acpi_ns_get_parent_node(node); + *ret_handle = acpi_ns_convert_entry_to_handle(parent_node); /* Return exception if parent is null */ - if (!acpi_ns_get_parent_node(node)) { + if (!parent_node) { status = AE_NULL_ENTRY; } @@ -268,7 +269,7 @@ acpi_get_next_object(acpi_object_type type, /* Internal function does the real work */ - node = acpi_ns_get_next_node(type, parent_node, child_node); + node = acpi_ns_get_next_node_typed(type, parent_node, child_node); if (!node) { status = AE_NOT_FOUND; goto unlock_and_exit; diff --git a/drivers/acpi/acpica/rscalc.c b/drivers/acpi/acpica/rscalc.c index 88b5a2c4814d..3c4dcc3d1069 100644 --- a/drivers/acpi/acpica/rscalc.c +++ b/drivers/acpi/acpica/rscalc.c @@ -547,7 +547,7 @@ acpi_rs_get_pci_routing_table_length(union acpi_operand_object *package_object, if (!package_element || (package_element->common.type != ACPI_TYPE_PACKAGE)) { - return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + return_ACPI_STATUS(AE_AML_OPERAND_TYPE); } /* @@ -593,9 +593,6 @@ acpi_rs_get_pci_routing_table_length(union acpi_operand_object *package_object, } else { temp_size_needed += acpi_ns_get_pathname_length((*sub_object_list)->reference.node); - if (!temp_size_needed) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } } } else { /* diff --git a/drivers/acpi/acpica/rsxface.c b/drivers/acpi/acpica/rsxface.c index 69a2aa5b5d83..395212bcd19b 100644 --- a/drivers/acpi/acpica/rsxface.c +++ b/drivers/acpi/acpica/rsxface.c @@ -338,13 +338,17 @@ acpi_resource_to_address64(struct acpi_resource *resource, switch (resource->type) { case ACPI_RESOURCE_TYPE_ADDRESS16: - address16 = (struct acpi_resource_address16 *)&resource->data; + address16 = + ACPI_CAST_PTR(struct acpi_resource_address16, + &resource->data); ACPI_COPY_ADDRESS(out, address16); break; case ACPI_RESOURCE_TYPE_ADDRESS32: - address32 = (struct acpi_resource_address32 *)&resource->data; + address32 = + ACPI_CAST_PTR(struct acpi_resource_address32, + &resource->data); ACPI_COPY_ADDRESS(out, address32); break; diff --git a/drivers/acpi/acpica/tbfadt.c b/drivers/acpi/acpica/tbfadt.c index 71e655d14cb0..82b02dcb942e 100644 --- a/drivers/acpi/acpica/tbfadt.c +++ b/drivers/acpi/acpica/tbfadt.c @@ -284,9 +284,9 @@ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length) if (length > sizeof(struct acpi_table_fadt)) { ACPI_WARNING((AE_INFO, "FADT (revision %u) is longer than ACPI 2.0 version, " - "truncating length 0x%X to 0x%zX", - table->revision, (unsigned)length, - sizeof(struct acpi_table_fadt))); + "truncating length 0x%X to 0x%X", + table->revision, length, + (u32)sizeof(struct acpi_table_fadt))); } /* Clear the entire local FADT */ @@ -441,7 +441,7 @@ static void acpi_tb_convert_fadt(void) &acpi_gbl_FADT, fadt_info_table [i].length), - address32); + (u64) address32); } } } @@ -469,7 +469,6 @@ static void acpi_tb_convert_fadt(void) static void acpi_tb_validate_fadt(void) { char *name; - u32 *address32; struct acpi_generic_address *address64; u8 length; u32 i; @@ -505,15 +504,12 @@ static void acpi_tb_validate_fadt(void) for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) { /* - * Generate pointers to the 32-bit and 64-bit addresses, get the - * register length (width), and the register name + * Generate pointer to the 64-bit address, get the register + * length (width) and the register name */ address64 = ACPI_ADD_PTR(struct acpi_generic_address, &acpi_gbl_FADT, fadt_info_table[i].address64); - address32 = - ACPI_ADD_PTR(u32, &acpi_gbl_FADT, - fadt_info_table[i].address32); length = *ACPI_ADD_PTR(u8, &acpi_gbl_FADT, fadt_info_table[i].length); diff --git a/drivers/acpi/acpica/tbinstal.c b/drivers/acpi/acpica/tbinstal.c index f865d5a096de..63e82329a9e8 100644 --- a/drivers/acpi/acpica/tbinstal.c +++ b/drivers/acpi/acpica/tbinstal.c @@ -472,7 +472,7 @@ acpi_status acpi_tb_delete_namespace_by_owner(u32 table_index) * lock may block, and also since the execution of a namespace walk * must be allowed to use the interpreter. */ - acpi_ut_release_mutex(ACPI_MTX_INTERPRETER); + (void)acpi_ut_release_mutex(ACPI_MTX_INTERPRETER); status = acpi_ut_acquire_write_lock(&acpi_gbl_namespace_rw_lock); acpi_ns_delete_namespace_by_owner(owner_id); diff --git a/drivers/acpi/acpica/utcopy.c b/drivers/acpi/acpica/utcopy.c index 919624f123d5..0f0c64bf8ac9 100644 --- a/drivers/acpi/acpica/utcopy.c +++ b/drivers/acpi/acpica/utcopy.c @@ -676,6 +676,7 @@ acpi_ut_copy_simple_object(union acpi_operand_object *source_desc, { u16 reference_count; union acpi_operand_object *next_object; + acpi_status status; /* Save fields from destination that we don't want to overwrite */ @@ -768,6 +769,28 @@ acpi_ut_copy_simple_object(union acpi_operand_object *source_desc, } break; + /* + * For Mutex and Event objects, we cannot simply copy the underlying + * OS object. We must create a new one. + */ + case ACPI_TYPE_MUTEX: + + status = acpi_os_create_mutex(&dest_desc->mutex.os_mutex); + if (ACPI_FAILURE(status)) { + return status; + } + break; + + case ACPI_TYPE_EVENT: + + status = acpi_os_create_semaphore(ACPI_NO_UNIT_LIMIT, 0, + &dest_desc->event. + os_semaphore); + if (ACPI_FAILURE(status)) { + return status; + } + break; + default: /* Nothing to do for other simple objects */ break; diff --git a/drivers/acpi/acpica/utdebug.c b/drivers/acpi/acpica/utdebug.c index 38821f53042c..527d729f6815 100644 --- a/drivers/acpi/acpica/utdebug.c +++ b/drivers/acpi/acpica/utdebug.c @@ -179,9 +179,9 @@ acpi_debug_print(u32 requested_debug_level, if (thread_id != acpi_gbl_prev_thread_id) { if (ACPI_LV_THREADS & acpi_dbg_level) { acpi_os_printf - ("\n**** Context Switch from TID %lX to TID %lX ****\n\n", - (unsigned long)acpi_gbl_prev_thread_id, - (unsigned long)thread_id); + ("\n**** Context Switch from TID %p to TID %p ****\n\n", + ACPI_CAST_PTR(void, acpi_gbl_prev_thread_id), + ACPI_CAST_PTR(void, thread_id)); } acpi_gbl_prev_thread_id = thread_id; @@ -194,7 +194,7 @@ acpi_debug_print(u32 requested_debug_level, acpi_os_printf("%8s-%04ld ", module_name, line_number); if (ACPI_LV_THREADS & acpi_dbg_level) { - acpi_os_printf("[%04lX] ", (unsigned long)thread_id); + acpi_os_printf("[%p] ", ACPI_CAST_PTR(void, thread_id)); } acpi_os_printf("[%02ld] %-22.22s: ", diff --git a/drivers/acpi/acpica/utdelete.c b/drivers/acpi/acpica/utdelete.c index a5ee23bc4f55..bc1710315088 100644 --- a/drivers/acpi/acpica/utdelete.c +++ b/drivers/acpi/acpica/utdelete.c @@ -75,6 +75,7 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object) union acpi_operand_object *handler_desc; union acpi_operand_object *second_desc; union acpi_operand_object *next_desc; + union acpi_operand_object **last_obj_ptr; ACPI_FUNCTION_TRACE_PTR(ut_delete_internal_obj, object); @@ -223,6 +224,26 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object) */ handler_desc = object->region.handler; if (handler_desc) { + next_desc = + handler_desc->address_space.region_list; + last_obj_ptr = + &handler_desc->address_space.region_list; + + /* Remove the region object from the handler's list */ + + while (next_desc) { + if (next_desc == object) { + *last_obj_ptr = + next_desc->region.next; + break; + } + + /* Walk the linked list of handler */ + + last_obj_ptr = &next_desc->region.next; + next_desc = next_desc->region.next; + } + if (handler_desc->address_space.handler_flags & ACPI_ADDR_HANDLER_DEFAULT_INSTALLED) { diff --git a/drivers/acpi/acpica/utmisc.c b/drivers/acpi/acpica/utmisc.c index 1c9e250caefb..fbe782348b0b 100644 --- a/drivers/acpi/acpica/utmisc.c +++ b/drivers/acpi/acpica/utmisc.c @@ -1033,11 +1033,12 @@ acpi_error(const char *module_name, u32 line_number, const char *format, ...) { va_list args; - acpi_os_printf("ACPI Error (%s-%04d): ", module_name, line_number); + acpi_os_printf("ACPI Error: "); va_start(args, format); acpi_os_vprintf(format, args); - acpi_os_printf(" [%X]\n", ACPI_CA_VERSION); + acpi_os_printf(" %8.8X %s-%u\n", ACPI_CA_VERSION, module_name, + line_number); va_end(args); } @@ -1047,12 +1048,12 @@ acpi_exception(const char *module_name, { va_list args; - acpi_os_printf("ACPI Exception (%s-%04d): %s, ", module_name, - line_number, acpi_format_exception(status)); + acpi_os_printf("ACPI Exception: %s, ", acpi_format_exception(status)); va_start(args, format); acpi_os_vprintf(format, args); - acpi_os_printf(" [%X]\n", ACPI_CA_VERSION); + acpi_os_printf(" %8.8X %s-%u\n", ACPI_CA_VERSION, module_name, + line_number); va_end(args); } @@ -1061,11 +1062,12 @@ acpi_warning(const char *module_name, u32 line_number, const char *format, ...) { va_list args; - acpi_os_printf("ACPI Warning (%s-%04d): ", module_name, line_number); + acpi_os_printf("ACPI Warning: "); va_start(args, format); acpi_os_vprintf(format, args); - acpi_os_printf(" [%X]\n", ACPI_CA_VERSION); + acpi_os_printf(" %8.8X %s-%u\n", ACPI_CA_VERSION, module_name, + line_number); va_end(args); } @@ -1074,10 +1076,6 @@ acpi_info(const char *module_name, u32 line_number, const char *format, ...) { va_list args; - /* - * Removed module_name, line_number, and acpica version, not needed - * for info output - */ acpi_os_printf("ACPI: "); va_start(args, format); diff --git a/drivers/acpi/acpica/utmutex.c b/drivers/acpi/acpica/utmutex.c index 26c93a748e64..80bb65154117 100644 --- a/drivers/acpi/acpica/utmutex.c +++ b/drivers/acpi/acpica/utmutex.c @@ -230,17 +230,18 @@ acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id) if (acpi_gbl_mutex_info[i].thread_id == this_thread_id) { if (i == mutex_id) { ACPI_ERROR((AE_INFO, - "Mutex [%s] already acquired by this thread [%X]", + "Mutex [%s] already acquired by this thread [%p]", acpi_ut_get_mutex_name (mutex_id), - this_thread_id)); + ACPI_CAST_PTR(void, + this_thread_id))); return (AE_ALREADY_ACQUIRED); } ACPI_ERROR((AE_INFO, - "Invalid acquire order: Thread %X owns [%s], wants [%s]", - this_thread_id, + "Invalid acquire order: Thread %p owns [%s], wants [%s]", + ACPI_CAST_PTR(void, this_thread_id), acpi_ut_get_mutex_name(i), acpi_ut_get_mutex_name(mutex_id))); @@ -251,24 +252,24 @@ acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id) #endif ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, - "Thread %lX attempting to acquire Mutex [%s]\n", - (unsigned long)this_thread_id, + "Thread %p attempting to acquire Mutex [%s]\n", + ACPI_CAST_PTR(void, this_thread_id), acpi_ut_get_mutex_name(mutex_id))); status = acpi_os_acquire_mutex(acpi_gbl_mutex_info[mutex_id].mutex, ACPI_WAIT_FOREVER); if (ACPI_SUCCESS(status)) { ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, - "Thread %lX acquired Mutex [%s]\n", - (unsigned long)this_thread_id, + "Thread %p acquired Mutex [%s]\n", + ACPI_CAST_PTR(void, this_thread_id), acpi_ut_get_mutex_name(mutex_id))); acpi_gbl_mutex_info[mutex_id].use_count++; acpi_gbl_mutex_info[mutex_id].thread_id = this_thread_id; } else { ACPI_EXCEPTION((AE_INFO, status, - "Thread %lX could not acquire Mutex [%X]", - (unsigned long)this_thread_id, mutex_id)); + "Thread %p could not acquire Mutex [%X]", + ACPI_CAST_PTR(void, this_thread_id), mutex_id)); } return (status); @@ -293,9 +294,8 @@ acpi_status acpi_ut_release_mutex(acpi_mutex_handle mutex_id) ACPI_FUNCTION_NAME(ut_release_mutex); this_thread_id = acpi_os_get_thread_id(); - ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, - "Thread %lX releasing Mutex [%s]\n", - (unsigned long)this_thread_id, + ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Thread %p releasing Mutex [%s]\n", + ACPI_CAST_PTR(void, this_thread_id), acpi_ut_get_mutex_name(mutex_id))); if (mutex_id > ACPI_MAX_MUTEX) { diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index b0de6312919a..58b4517ce712 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -796,13 +796,12 @@ static void acpi_battery_remove_fs(struct acpi_device *device) Driver Interface -------------------------------------------------------------------------- */ -static void acpi_battery_notify(acpi_handle handle, u32 event, void *data) +static void acpi_battery_notify(struct acpi_device *device, u32 event) { - struct acpi_battery *battery = data; - struct acpi_device *device; + struct acpi_battery *battery = acpi_driver_data(device); + if (!battery) return; - device = battery->device; acpi_battery_update(battery); acpi_bus_generate_proc_event(device, event, acpi_battery_present(battery)); @@ -819,7 +818,6 @@ static void acpi_battery_notify(acpi_handle handle, u32 event, void *data) static int acpi_battery_add(struct acpi_device *device) { int result = 0; - acpi_status status = 0; struct acpi_battery *battery = NULL; if (!device) return -EINVAL; @@ -834,22 +832,12 @@ static int acpi_battery_add(struct acpi_device *device) acpi_battery_update(battery); #ifdef CONFIG_ACPI_PROCFS_POWER result = acpi_battery_add_fs(device); - if (result) - goto end; #endif - status = acpi_install_notify_handler(device->handle, - ACPI_ALL_NOTIFY, - acpi_battery_notify, battery); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "Installing notify handler")); - result = -ENODEV; - goto end; - } - printk(KERN_INFO PREFIX "%s Slot [%s] (battery %s)\n", - ACPI_BATTERY_DEVICE_NAME, acpi_device_bid(device), - device->status.battery_present ? "present" : "absent"); - end: - if (result) { + if (!result) { + printk(KERN_INFO PREFIX "%s Slot [%s] (battery %s)\n", + ACPI_BATTERY_DEVICE_NAME, acpi_device_bid(device), + device->status.battery_present ? "present" : "absent"); + } else { #ifdef CONFIG_ACPI_PROCFS_POWER acpi_battery_remove_fs(device); #endif @@ -860,15 +848,11 @@ static int acpi_battery_add(struct acpi_device *device) static int acpi_battery_remove(struct acpi_device *device, int type) { - acpi_status status = 0; struct acpi_battery *battery = NULL; if (!device || !acpi_driver_data(device)) return -EINVAL; battery = acpi_driver_data(device); - status = acpi_remove_notify_handler(device->handle, - ACPI_ALL_NOTIFY, - acpi_battery_notify); #ifdef CONFIG_ACPI_PROCFS_POWER acpi_battery_remove_fs(device); #endif @@ -896,10 +880,12 @@ static struct acpi_driver acpi_battery_driver = { .name = "battery", .class = ACPI_BATTERY_CLASS, .ids = battery_device_ids, + .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS, .ops = { .add = acpi_battery_add, .resume = acpi_battery_resume, .remove = acpi_battery_remove, + .notify = acpi_battery_notify, }, }; diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c index 09c69806c1fc..f6baa77deefb 100644 --- a/drivers/acpi/blacklist.c +++ b/drivers/acpi/blacklist.c @@ -192,6 +192,22 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = { DMI_MATCH(DMI_PRODUCT_NAME, "ESPRIMO Mobile V5505"), }, }, + { + .callback = dmi_disable_osi_vista, + .ident = "Sony VGN-NS10J_S", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "VGN-NS10J_S"), + }, + }, + { + .callback = dmi_disable_osi_vista, + .ident = "Sony VGN-SR290J", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "Sony VGN-SR290J"), + }, + }, /* * BIOS invocation of _OSI(Linux) is almost always a BIOS bug. diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index ae862f1798dc..2876fc70c3a9 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -450,18 +450,16 @@ int acpi_bus_receive_event(struct acpi_bus_event *event) Notification Handling -------------------------------------------------------------------------- */ -static int -acpi_bus_check_device(struct acpi_device *device, int *status_changed) +static void acpi_bus_check_device(acpi_handle handle) { - acpi_status status = 0; + struct acpi_device *device; + acpi_status status; struct acpi_device_status old_status; - + if (acpi_bus_get_device(handle, &device)) + return; if (!device) - return -EINVAL; - - if (status_changed) - *status_changed = 0; + return; old_status = device->status; @@ -471,22 +469,15 @@ acpi_bus_check_device(struct acpi_device *device, int *status_changed) */ if (device->parent && !device->parent->status.present) { device->status = device->parent->status; - if (STRUCT_TO_INT(old_status) != STRUCT_TO_INT(device->status)) { - if (status_changed) - *status_changed = 1; - } - return 0; + return; } status = acpi_bus_get_status(device); if (ACPI_FAILURE(status)) - return -ENODEV; + return; if (STRUCT_TO_INT(old_status) == STRUCT_TO_INT(device->status)) - return 0; - - if (status_changed) - *status_changed = 1; + return; /* * Device Insertion/Removal @@ -498,33 +489,17 @@ acpi_bus_check_device(struct acpi_device *device, int *status_changed) ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device removal detected\n")); /* TBD: Handle device removal */ } - - return 0; } -static int acpi_bus_check_scope(struct acpi_device *device) +static void acpi_bus_check_scope(acpi_handle handle) { - int result = 0; - int status_changed = 0; - - - if (!device) - return -EINVAL; - /* Status Change? */ - result = acpi_bus_check_device(device, &status_changed); - if (result) - return result; - - if (!status_changed) - return 0; + acpi_bus_check_device(handle); /* * TBD: Enumerate child devices within this device's scope and * run acpi_bus_check_device()'s on them. */ - - return 0; } static BLOCKING_NOTIFIER_HEAD(acpi_bus_notify_list); @@ -547,22 +522,19 @@ EXPORT_SYMBOL_GPL(unregister_acpi_bus_notifier); */ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) { - int result = 0; struct acpi_device *device = NULL; + struct acpi_driver *driver; + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Notification %#02x to handle %p\n", + type, handle)); blocking_notifier_call_chain(&acpi_bus_notify_list, type, (void *)handle); - if (acpi_bus_get_device(handle, &device)) - return; - switch (type) { case ACPI_NOTIFY_BUS_CHECK: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Received BUS CHECK notification for device [%s]\n", - device->pnp.bus_id)); - result = acpi_bus_check_scope(device); + acpi_bus_check_scope(handle); /* * TBD: We'll need to outsource certain events to non-ACPI * drivers via the device manager (device.c). @@ -570,10 +542,7 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) break; case ACPI_NOTIFY_DEVICE_CHECK: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Received DEVICE CHECK notification for device [%s]\n", - device->pnp.bus_id)); - result = acpi_bus_check_device(device, NULL); + acpi_bus_check_device(handle); /* * TBD: We'll need to outsource certain events to non-ACPI * drivers via the device manager (device.c). @@ -581,44 +550,26 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) break; case ACPI_NOTIFY_DEVICE_WAKE: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Received DEVICE WAKE notification for device [%s]\n", - device->pnp.bus_id)); /* TBD */ break; case ACPI_NOTIFY_EJECT_REQUEST: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Received EJECT REQUEST notification for device [%s]\n", - device->pnp.bus_id)); /* TBD */ break; case ACPI_NOTIFY_DEVICE_CHECK_LIGHT: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Received DEVICE CHECK LIGHT notification for device [%s]\n", - device->pnp.bus_id)); /* TBD: Exactly what does 'light' mean? */ break; case ACPI_NOTIFY_FREQUENCY_MISMATCH: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Received FREQUENCY MISMATCH notification for device [%s]\n", - device->pnp.bus_id)); /* TBD */ break; case ACPI_NOTIFY_BUS_MODE_MISMATCH: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Received BUS MODE MISMATCH notification for device [%s]\n", - device->pnp.bus_id)); /* TBD */ break; case ACPI_NOTIFY_POWER_FAULT: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Received POWER FAULT notification for device [%s]\n", - device->pnp.bus_id)); /* TBD */ break; @@ -629,7 +580,13 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) break; } - return; + acpi_bus_get_device(handle, &device); + if (device) { + driver = device->driver; + if (driver && driver->ops.notify && + (driver->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS)) + driver->ops.notify(device, type); + } } /* -------------------------------------------------------------------------- diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 8bd2c2a6884d..a8a5c29958c8 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -140,46 +140,6 @@ struct device *acpi_get_physical_device(acpi_handle handle) EXPORT_SYMBOL(acpi_get_physical_device); -/* ToDo: When a PCI bridge is found, return the PCI device behind the bridge - * This should work in general, but did not on a Lenovo T61 for the - * graphics card. But this must be fixed when the PCI device is - * bound and the kernel device struct is attached to the acpi device - * Note: A success call will increase reference count by one - * Do call put_device(dev) on the returned device then - */ -struct device *acpi_get_physical_pci_device(acpi_handle handle) -{ - struct device *dev; - long long device_id; - acpi_status status; - - status = - acpi_evaluate_integer(handle, "_ADR", NULL, &device_id); - - if (ACPI_FAILURE(status)) - return NULL; - - /* We need to attempt to determine whether the _ADR refers to a - PCI device or not. There's no terribly good way to do this, - so the best we can hope for is to assume that there'll never - be a device in the host bridge */ - if (device_id >= 0x10000) { - /* It looks like a PCI device. Does it exist? */ - dev = acpi_get_physical_device(handle); - } else { - /* It doesn't look like a PCI device. Does its parent - exist? */ - acpi_handle phandle; - if (acpi_get_parent(handle, &phandle)) - return NULL; - dev = acpi_get_physical_device(phandle); - } - if (!dev) - return NULL; - return dev; -} -EXPORT_SYMBOL(acpi_get_physical_pci_device); - static int acpi_bind_one(struct device *dev, acpi_handle handle) { struct acpi_device *acpi_dev; diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index d916bea729f1..71670719d61a 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -79,6 +79,7 @@ static acpi_osd_handler acpi_irq_handler; static void *acpi_irq_context; static struct workqueue_struct *kacpid_wq; static struct workqueue_struct *kacpi_notify_wq; +static struct workqueue_struct *kacpi_hotplug_wq; struct acpi_res_list { resource_size_t start; @@ -192,8 +193,10 @@ acpi_status acpi_os_initialize1(void) { kacpid_wq = create_singlethread_workqueue("kacpid"); kacpi_notify_wq = create_singlethread_workqueue("kacpi_notify"); + kacpi_hotplug_wq = create_singlethread_workqueue("kacpi_hotplug"); BUG_ON(!kacpid_wq); BUG_ON(!kacpi_notify_wq); + BUG_ON(!kacpi_hotplug_wq); return AE_OK; } @@ -206,6 +209,7 @@ acpi_status acpi_os_terminate(void) destroy_workqueue(kacpid_wq); destroy_workqueue(kacpi_notify_wq); + destroy_workqueue(kacpi_hotplug_wq); return AE_OK; } @@ -716,6 +720,7 @@ static acpi_status __acpi_os_execute(acpi_execute_type type, acpi_status status = AE_OK; struct acpi_os_dpc *dpc; struct workqueue_struct *queue; + work_func_t func; int ret; ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Scheduling function [%p(%p)] for deferred execution.\n", @@ -740,15 +745,17 @@ static acpi_status __acpi_os_execute(acpi_execute_type type, dpc->function = function; dpc->context = context; - if (!hp) { - INIT_WORK(&dpc->work, acpi_os_execute_deferred); - queue = (type == OSL_NOTIFY_HANDLER) ? - kacpi_notify_wq : kacpid_wq; - ret = queue_work(queue, &dpc->work); - } else { - INIT_WORK(&dpc->work, acpi_os_execute_hp_deferred); - ret = schedule_work(&dpc->work); - } + /* + * We can't run hotplug code in keventd_wq/kacpid_wq/kacpid_notify_wq + * because the hotplug code may call driver .remove() functions, + * which invoke flush_scheduled_work/acpi_os_wait_events_complete + * to flush these workqueues. + */ + queue = hp ? kacpi_hotplug_wq : + (type == OSL_NOTIFY_HANDLER ? kacpi_notify_wq : kacpid_wq); + func = hp ? acpi_os_execute_hp_deferred : acpi_os_execute_deferred; + INIT_WORK(&dpc->work, func); + ret = queue_work(queue, &dpc->work); if (!ret) { printk(KERN_ERR PREFIX diff --git a/drivers/acpi/pci_bind.c b/drivers/acpi/pci_bind.c index bc46de3d967f..a5a77b78a723 100644 --- a/drivers/acpi/pci_bind.c +++ b/drivers/acpi/pci_bind.c @@ -24,12 +24,7 @@ */ #include -#include -#include #include -#include -#include -#include #include #include #include @@ -38,310 +33,76 @@ #define _COMPONENT ACPI_PCI_COMPONENT ACPI_MODULE_NAME("pci_bind"); -struct acpi_pci_data { - struct acpi_pci_id id; +static int acpi_pci_unbind(struct acpi_device *device) +{ + struct pci_dev *dev; + + dev = acpi_get_pci_dev(device->handle); + if (!dev || !dev->subordinate) + goto out; + + acpi_pci_irq_del_prt(dev->subordinate); + + device->ops.bind = NULL; + device->ops.unbind = NULL; + +out: + pci_dev_put(dev); + return 0; +} + +static int acpi_pci_bind(struct acpi_device *device) +{ + acpi_status status; + acpi_handle handle; struct pci_bus *bus; struct pci_dev *dev; -}; -static int acpi_pci_unbind(struct acpi_device *device); - -static void acpi_pci_data_handler(acpi_handle handle, u32 function, - void *context) -{ - - /* TBD: Anything we need to do here? */ - - return; -} - -/** - * acpi_get_pci_id - * ------------------ - * This function is used by the ACPI Interpreter (a.k.a. Core Subsystem) - * to resolve PCI information for ACPI-PCI devices defined in the namespace. - * This typically occurs when resolving PCI operation region information. - */ -acpi_status acpi_get_pci_id(acpi_handle handle, struct acpi_pci_id *id) -{ - int result = 0; - acpi_status status = AE_OK; - struct acpi_device *device = NULL; - struct acpi_pci_data *data = NULL; - - - if (!id) - return AE_BAD_PARAMETER; - - result = acpi_bus_get_device(handle, &device); - if (result) { - printk(KERN_ERR PREFIX - "Invalid ACPI Bus context for device %s\n", - acpi_device_bid(device)); - return AE_NOT_EXIST; - } - - status = acpi_get_data(handle, acpi_pci_data_handler, (void **)&data); - if (ACPI_FAILURE(status) || !data) { - ACPI_EXCEPTION((AE_INFO, status, - "Invalid ACPI-PCI context for device %s", - acpi_device_bid(device))); - return status; - } - - *id = data->id; + dev = acpi_get_pci_dev(device->handle); + if (!dev) + return 0; /* - id->segment = data->id.segment; - id->bus = data->id.bus; - id->device = data->id.device; - id->function = data->id.function; + * Install the 'bind' function to facilitate callbacks for + * children of the P2P bridge. */ - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Device %s has PCI address %04x:%02x:%02x.%d\n", - acpi_device_bid(device), id->segment, id->bus, - id->device, id->function)); - - return AE_OK; -} - -EXPORT_SYMBOL(acpi_get_pci_id); - -int acpi_pci_bind(struct acpi_device *device) -{ - int result = 0; - acpi_status status; - struct acpi_pci_data *data; - struct acpi_pci_data *pdata; - struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - acpi_handle handle; - - if (!device || !device->parent) - return -EINVAL; - - data = kzalloc(sizeof(struct acpi_pci_data), GFP_KERNEL); - if (!data) - return -ENOMEM; - - status = acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer); - if (ACPI_FAILURE(status)) { - kfree(data); - return -ENODEV; - } - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Binding PCI device [%s]...\n", - (char *)buffer.pointer)); - - /* - * Segment & Bus - * ------------- - * These are obtained via the parent device's ACPI-PCI context. - */ - status = acpi_get_data(device->parent->handle, acpi_pci_data_handler, - (void **)&pdata); - if (ACPI_FAILURE(status) || !pdata || !pdata->bus) { - ACPI_EXCEPTION((AE_INFO, status, - "Invalid ACPI-PCI context for parent device %s", - acpi_device_bid(device->parent))); - result = -ENODEV; - goto end; - } - data->id.segment = pdata->id.segment; - data->id.bus = pdata->bus->number; - - /* - * Device & Function - * ----------------- - * These are simply obtained from the device's _ADR method. Note - * that a value of zero is valid. - */ - data->id.device = device->pnp.bus_address >> 16; - data->id.function = device->pnp.bus_address & 0xFFFF; - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "...to %04x:%02x:%02x.%d\n", - data->id.segment, data->id.bus, data->id.device, - data->id.function)); - - /* - * TBD: Support slot devices (e.g. function=0xFFFF). - */ - - /* - * Locate PCI Device - * ----------------- - * Locate matching device in PCI namespace. If it doesn't exist - * this typically means that the device isn't currently inserted - * (e.g. docking station, port replicator, etc.). - */ - data->dev = pci_get_slot(pdata->bus, - PCI_DEVFN(data->id.device, data->id.function)); - if (!data->dev) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Device %04x:%02x:%02x.%d not present in PCI namespace\n", - data->id.segment, data->id.bus, - data->id.device, data->id.function)); - result = -ENODEV; - goto end; - } - if (!data->dev->bus) { - printk(KERN_ERR PREFIX - "Device %04x:%02x:%02x.%d has invalid 'bus' field\n", - data->id.segment, data->id.bus, - data->id.device, data->id.function); - result = -ENODEV; - goto end; - } - - /* - * PCI Bridge? - * ----------- - * If so, set the 'bus' field and install the 'bind' function to - * facilitate callbacks for all of its children. - */ - if (data->dev->subordinate) { + if (dev->subordinate) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device %04x:%02x:%02x.%d is a PCI bridge\n", - data->id.segment, data->id.bus, - data->id.device, data->id.function)); - data->bus = data->dev->subordinate; + pci_domain_nr(dev->bus), dev->bus->number, + PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn))); device->ops.bind = acpi_pci_bind; device->ops.unbind = acpi_pci_unbind; } /* - * Attach ACPI-PCI Context - * ----------------------- - * Thus binding the ACPI and PCI devices. - */ - status = acpi_attach_data(device->handle, acpi_pci_data_handler, data); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, - "Unable to attach ACPI-PCI context to device %s", - acpi_device_bid(device))); - result = -ENODEV; - goto end; - } - - /* - * PCI Routing Table - * ----------------- - * Evaluate and parse _PRT, if exists. This code is independent of - * PCI bridges (above) to allow parsing of _PRT objects within the - * scope of non-bridge devices. Note that _PRTs within the scope of - * a PCI bridge assume the bridge's subordinate bus number. + * Evaluate and parse _PRT, if exists. This code allows parsing of + * _PRT objects within the scope of non-bridge devices. Note that + * _PRTs within the scope of a PCI bridge assume the bridge's + * subordinate bus number. * * TBD: Can _PRTs exist within the scope of non-bridge PCI devices? */ status = acpi_get_handle(device->handle, METHOD_NAME__PRT, &handle); - if (ACPI_SUCCESS(status)) { - if (data->bus) /* PCI-PCI bridge */ - acpi_pci_irq_add_prt(device->handle, data->id.segment, - data->bus->number); - else /* non-bridge PCI device */ - acpi_pci_irq_add_prt(device->handle, data->id.segment, - data->id.bus); - } - - end: - kfree(buffer.pointer); - if (result) { - pci_dev_put(data->dev); - kfree(data); - } - return result; -} - -static int acpi_pci_unbind(struct acpi_device *device) -{ - int result = 0; - acpi_status status; - struct acpi_pci_data *data; - struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - - - if (!device || !device->parent) - return -EINVAL; - - status = acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer); if (ACPI_FAILURE(status)) - return -ENODEV; + goto out; - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Unbinding PCI device [%s]...\n", - (char *) buffer.pointer)); - kfree(buffer.pointer); + if (dev->subordinate) + bus = dev->subordinate; + else + bus = dev->bus; - status = - acpi_get_data(device->handle, acpi_pci_data_handler, - (void **)&data); - if (ACPI_FAILURE(status)) { - result = -ENODEV; - goto end; - } + acpi_pci_irq_add_prt(device->handle, bus); - status = acpi_detach_data(device->handle, acpi_pci_data_handler); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, - "Unable to detach data from device %s", - acpi_device_bid(device))); - result = -ENODEV; - goto end; - } - if (data->dev->subordinate) { - acpi_pci_irq_del_prt(data->id.segment, data->bus->number); - } - pci_dev_put(data->dev); - kfree(data); - - end: - return result; +out: + pci_dev_put(dev); + return 0; } -int -acpi_pci_bind_root(struct acpi_device *device, - struct acpi_pci_id *id, struct pci_bus *bus) +int acpi_pci_bind_root(struct acpi_device *device) { - int result = 0; - acpi_status status; - struct acpi_pci_data *data = NULL; - struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - - if (!device || !id || !bus) { - return -EINVAL; - } - - data = kzalloc(sizeof(struct acpi_pci_data), GFP_KERNEL); - if (!data) - return -ENOMEM; - - data->id = *id; - data->bus = bus; device->ops.bind = acpi_pci_bind; device->ops.unbind = acpi_pci_unbind; - status = acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer); - if (ACPI_FAILURE(status)) { - kfree (data); - return -ENODEV; - } - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Binding PCI root bridge [%s] to " - "%04x:%02x\n", (char *)buffer.pointer, - id->segment, id->bus)); - - status = acpi_attach_data(device->handle, acpi_pci_data_handler, data); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, - "Unable to attach ACPI-PCI context to device %s", - (char *)buffer.pointer)); - result = -ENODEV; - goto end; - } - - end: - kfree(buffer.pointer); - if (result != 0) - kfree(data); - - return result; + return 0; } diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index 51b9f8280f88..b794eb88ab90 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c @@ -182,7 +182,7 @@ static void do_prt_fixups(struct acpi_prt_entry *entry, } } -static int acpi_pci_irq_add_entry(acpi_handle handle, int segment, int bus, +static int acpi_pci_irq_add_entry(acpi_handle handle, struct pci_bus *bus, struct acpi_pci_routing_table *prt) { struct acpi_prt_entry *entry; @@ -196,8 +196,8 @@ static int acpi_pci_irq_add_entry(acpi_handle handle, int segment, int bus, * 1=INTA, 2=INTB. We use the PCI encoding throughout, so convert * it here. */ - entry->id.segment = segment; - entry->id.bus = bus; + entry->id.segment = pci_domain_nr(bus); + entry->id.bus = bus->number; entry->id.device = (prt->address >> 16) & 0xFFFF; entry->pin = prt->pin + 1; @@ -242,7 +242,7 @@ static int acpi_pci_irq_add_entry(acpi_handle handle, int segment, int bus, return 0; } -int acpi_pci_irq_add_prt(acpi_handle handle, int segment, int bus) +int acpi_pci_irq_add_prt(acpi_handle handle, struct pci_bus *bus) { acpi_status status; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; @@ -271,7 +271,7 @@ int acpi_pci_irq_add_prt(acpi_handle handle, int segment, int bus) entry = buffer.pointer; while (entry && (entry->length > 0)) { - acpi_pci_irq_add_entry(handle, segment, bus, entry); + acpi_pci_irq_add_entry(handle, bus, entry); entry = (struct acpi_pci_routing_table *) ((unsigned long)entry + entry->length); } @@ -280,16 +280,17 @@ int acpi_pci_irq_add_prt(acpi_handle handle, int segment, int bus) return 0; } -void acpi_pci_irq_del_prt(int segment, int bus) +void acpi_pci_irq_del_prt(struct pci_bus *bus) { struct acpi_prt_entry *entry, *tmp; printk(KERN_DEBUG "ACPI: Delete PCI Interrupt Routing Table for %04x:%02x\n", - segment, bus); + pci_domain_nr(bus), bus->number); spin_lock(&acpi_prt_lock); list_for_each_entry_safe(entry, tmp, &acpi_prt_list, list) { - if (segment == entry->id.segment && bus == entry->id.bus) { + if (pci_domain_nr(bus) == entry->id.segment + && bus->number == entry->id.bus) { list_del(&entry->list); kfree(entry); } @@ -401,7 +402,8 @@ int acpi_pci_irq_enable(struct pci_dev *dev) /* Interrupt Line values above 0xF are forbidden */ if (dev->irq > 0 && (dev->irq <= 0xF)) { printk(" - using IRQ %d\n", dev->irq); - acpi_register_gsi(dev->irq, ACPI_LEVEL_SENSITIVE, + acpi_register_gsi(&dev->dev, dev->irq, + ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW); return 0; } else { @@ -410,7 +412,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev) } } - rc = acpi_register_gsi(gsi, triggering, polarity); + rc = acpi_register_gsi(&dev->dev, gsi, triggering, polarity); if (rc < 0) { dev_warn(&dev->dev, "PCI INT %c: failed to register GSI\n", pin_name(pin)); diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 196f97d00956..8a5bf3b356fa 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -63,9 +63,10 @@ static struct acpi_driver acpi_pci_root_driver = { struct acpi_pci_root { struct list_head node; - struct acpi_device * device; - struct acpi_pci_id id; + struct acpi_device *device; struct pci_bus *bus; + u16 segment; + u8 bus_nr; u32 osc_support_set; /* _OSC state of support bits */ u32 osc_control_set; /* _OSC state of control bits */ @@ -82,7 +83,7 @@ static DEFINE_MUTEX(osc_lock); int acpi_pci_register_driver(struct acpi_pci_driver *driver) { int n = 0; - struct list_head *entry; + struct acpi_pci_root *root; struct acpi_pci_driver **pptr = &sub_driver; while (*pptr) @@ -92,9 +93,7 @@ int acpi_pci_register_driver(struct acpi_pci_driver *driver) if (!driver->add) return 0; - list_for_each(entry, &acpi_pci_roots) { - struct acpi_pci_root *root; - root = list_entry(entry, struct acpi_pci_root, node); + list_for_each_entry(root, &acpi_pci_roots, node) { driver->add(root->device->handle); n++; } @@ -106,7 +105,7 @@ EXPORT_SYMBOL(acpi_pci_register_driver); void acpi_pci_unregister_driver(struct acpi_pci_driver *driver) { - struct list_head *entry; + struct acpi_pci_root *root; struct acpi_pci_driver **pptr = &sub_driver; while (*pptr) { @@ -120,28 +119,48 @@ void acpi_pci_unregister_driver(struct acpi_pci_driver *driver) if (!driver->remove) return; - list_for_each(entry, &acpi_pci_roots) { - struct acpi_pci_root *root; - root = list_entry(entry, struct acpi_pci_root, node); + list_for_each_entry(root, &acpi_pci_roots, node) driver->remove(root->device->handle); - } } EXPORT_SYMBOL(acpi_pci_unregister_driver); acpi_handle acpi_get_pci_rootbridge_handle(unsigned int seg, unsigned int bus) { - struct acpi_pci_root *tmp; + struct acpi_pci_root *root; - list_for_each_entry(tmp, &acpi_pci_roots, node) { - if ((tmp->id.segment == (u16) seg) && (tmp->id.bus == (u16) bus)) - return tmp->device->handle; - } + list_for_each_entry(root, &acpi_pci_roots, node) + if ((root->segment == (u16) seg) && (root->bus_nr == (u16) bus)) + return root->device->handle; return NULL; } EXPORT_SYMBOL_GPL(acpi_get_pci_rootbridge_handle); +/** + * acpi_is_root_bridge - determine whether an ACPI CA node is a PCI root bridge + * @handle - the ACPI CA node in question. + * + * Note: we could make this API take a struct acpi_device * instead, but + * for now, it's more convenient to operate on an acpi_handle. + */ +int acpi_is_root_bridge(acpi_handle handle) +{ + int ret; + struct acpi_device *device; + + ret = acpi_bus_get_device(handle, &device); + if (ret) + return 0; + + ret = acpi_match_device_ids(device, root_device_ids); + if (ret) + return 0; + else + return 1; +} +EXPORT_SYMBOL_GPL(acpi_is_root_bridge); + static acpi_status get_root_bridge_busnr_callback(struct acpi_resource *resource, void *data) { @@ -161,19 +180,22 @@ get_root_bridge_busnr_callback(struct acpi_resource *resource, void *data) return AE_OK; } -static acpi_status try_get_root_bridge_busnr(acpi_handle handle, int *busnum) +static acpi_status try_get_root_bridge_busnr(acpi_handle handle, + unsigned long long *bus) { acpi_status status; + int busnum; - *busnum = -1; + busnum = -1; status = acpi_walk_resources(handle, METHOD_NAME__CRS, - get_root_bridge_busnr_callback, busnum); + get_root_bridge_busnr_callback, &busnum); if (ACPI_FAILURE(status)) return status; /* Check if we really get a bus number from _CRS */ - if (*busnum == -1) + if (busnum == -1) return AE_ERROR; + *bus = busnum; return AE_OK; } @@ -298,6 +320,7 @@ static acpi_status acpi_pci_osc_support(struct acpi_pci_root *root, u32 flags) static struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle) { struct acpi_pci_root *root; + list_for_each_entry(root, &acpi_pci_roots, node) { if (root->device->handle == handle) return root; @@ -305,6 +328,87 @@ static struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle) return NULL; } +struct acpi_handle_node { + struct list_head node; + acpi_handle handle; +}; + +/** + * acpi_get_pci_dev - convert ACPI CA handle to struct pci_dev + * @handle: the handle in question + * + * Given an ACPI CA handle, the desired PCI device is located in the + * list of PCI devices. + * + * If the device is found, its reference count is increased and this + * function returns a pointer to its data structure. The caller must + * decrement the reference count by calling pci_dev_put(). + * If no device is found, %NULL is returned. + */ +struct pci_dev *acpi_get_pci_dev(acpi_handle handle) +{ + int dev, fn; + unsigned long long adr; + acpi_status status; + acpi_handle phandle; + struct pci_bus *pbus; + struct pci_dev *pdev = NULL; + struct acpi_handle_node *node, *tmp; + struct acpi_pci_root *root; + LIST_HEAD(device_list); + + /* + * Walk up the ACPI CA namespace until we reach a PCI root bridge. + */ + phandle = handle; + while (!acpi_is_root_bridge(phandle)) { + node = kzalloc(sizeof(struct acpi_handle_node), GFP_KERNEL); + if (!node) + goto out; + + INIT_LIST_HEAD(&node->node); + node->handle = phandle; + list_add(&node->node, &device_list); + + status = acpi_get_parent(phandle, &phandle); + if (ACPI_FAILURE(status)) + goto out; + } + + root = acpi_pci_find_root(phandle); + if (!root) + goto out; + + pbus = root->bus; + + /* + * Now, walk back down the PCI device tree until we return to our + * original handle. Assumes that everything between the PCI root + * bridge and the device we're looking for must be a P2P bridge. + */ + list_for_each_entry(node, &device_list, node) { + acpi_handle hnd = node->handle; + status = acpi_evaluate_integer(hnd, "_ADR", NULL, &adr); + if (ACPI_FAILURE(status)) + goto out; + dev = (adr >> 16) & 0xffff; + fn = adr & 0xffff; + + pdev = pci_get_slot(pbus, PCI_DEVFN(dev, fn)); + if (hnd == handle) + break; + + pbus = pdev->subordinate; + pci_dev_put(pdev); + } +out: + list_for_each_entry_safe(node, tmp, &device_list, node) + kfree(node); + + return pdev; +} +EXPORT_SYMBOL_GPL(acpi_get_pci_dev); + /** * acpi_pci_osc_control_set - commit requested control to Firmware * @handle: acpi_handle for the target ACPI object @@ -363,31 +467,46 @@ EXPORT_SYMBOL(acpi_pci_osc_control_set); static int __devinit acpi_pci_root_add(struct acpi_device *device) { - int result = 0; - struct acpi_pci_root *root = NULL; - struct acpi_pci_root *tmp; - acpi_status status = AE_OK; - unsigned long long value = 0; - acpi_handle handle = NULL; + unsigned long long segment, bus; + acpi_status status; + int result; + struct acpi_pci_root *root; + acpi_handle handle; struct acpi_device *child; u32 flags, base_flags; + segment = 0; + status = acpi_evaluate_integer(device->handle, METHOD_NAME__SEG, NULL, + &segment); + if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { + printk(KERN_ERR PREFIX "can't evaluate _SEG\n"); + return -ENODEV; + } - if (!device) - return -EINVAL; + /* Check _CRS first, then _BBN. If no _BBN, default to zero. */ + bus = 0; + status = try_get_root_bridge_busnr(device->handle, &bus); + if (ACPI_FAILURE(status)) { + status = acpi_evaluate_integer(device->handle, METHOD_NAME__BBN, NULL, &bus); + if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { + printk(KERN_ERR PREFIX + "no bus number in _CRS and can't evaluate _BBN\n"); + return -ENODEV; + } + } root = kzalloc(sizeof(struct acpi_pci_root), GFP_KERNEL); if (!root) return -ENOMEM; - INIT_LIST_HEAD(&root->node); + INIT_LIST_HEAD(&root->node); root->device = device; + root->segment = segment & 0xFFFF; + root->bus_nr = bus & 0xFF; strcpy(acpi_device_name(device), ACPI_PCI_ROOT_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_PCI_ROOT_CLASS); device->driver_data = root; - device->ops.bind = acpi_pci_bind; - /* * All supported architectures that use ACPI have support for * PCI domains, so we indicate this in _OSC support capabilities. @@ -395,79 +514,6 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) flags = base_flags = OSC_PCI_SEGMENT_GROUPS_SUPPORT; acpi_pci_osc_support(root, flags); - /* - * Segment - * ------- - * Obtained via _SEG, if exists, otherwise assumed to be zero (0). - */ - status = acpi_evaluate_integer(device->handle, METHOD_NAME__SEG, NULL, - &value); - switch (status) { - case AE_OK: - root->id.segment = (u16) value; - break; - case AE_NOT_FOUND: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Assuming segment 0 (no _SEG)\n")); - root->id.segment = 0; - break; - default: - ACPI_EXCEPTION((AE_INFO, status, "Evaluating _SEG")); - result = -ENODEV; - goto end; - } - - /* - * Bus - * --- - * Obtained via _BBN, if exists, otherwise assumed to be zero (0). - */ - status = acpi_evaluate_integer(device->handle, METHOD_NAME__BBN, NULL, - &value); - switch (status) { - case AE_OK: - root->id.bus = (u16) value; - break; - case AE_NOT_FOUND: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Assuming bus 0 (no _BBN)\n")); - root->id.bus = 0; - break; - default: - ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BBN")); - result = -ENODEV; - goto end; - } - - /* Some systems have wrong _BBN */ - list_for_each_entry(tmp, &acpi_pci_roots, node) { - if ((tmp->id.segment == root->id.segment) - && (tmp->id.bus == root->id.bus)) { - int bus = 0; - acpi_status status; - - printk(KERN_ERR PREFIX - "Wrong _BBN value, reboot" - " and use option 'pci=noacpi'\n"); - - status = try_get_root_bridge_busnr(device->handle, &bus); - if (ACPI_FAILURE(status)) - break; - if (bus != root->id.bus) { - printk(KERN_INFO PREFIX - "PCI _CRS %d overrides _BBN 0\n", bus); - root->id.bus = bus; - } - break; - } - } - /* - * Device & Function - * ----------------- - * Obtained from _ADR (which has already been evaluated for us). - */ - root->id.device = device->pnp.bus_address >> 16; - root->id.function = device->pnp.bus_address & 0xFFFF; - /* * TBD: Need PCI interface for enumeration/configuration of roots. */ @@ -477,7 +523,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) printk(KERN_INFO PREFIX "%s [%s] (%04x:%02x)\n", acpi_device_name(device), acpi_device_bid(device), - root->id.segment, root->id.bus); + root->segment, root->bus_nr); /* * Scan the Root Bridge @@ -486,11 +532,11 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) * PCI namespace does not get created until this call is made (and * thus the root bridge's pci_dev does not exist). */ - root->bus = pci_acpi_scan_root(device, root->id.segment, root->id.bus); + root->bus = pci_acpi_scan_root(device, segment, bus); if (!root->bus) { printk(KERN_ERR PREFIX "Bus %04x:%02x not present in PCI namespace\n", - root->id.segment, root->id.bus); + root->segment, root->bus_nr); result = -ENODEV; goto end; } @@ -500,7 +546,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) * ----------------------- * Thus binding the ACPI and PCI devices. */ - result = acpi_pci_bind_root(device, &root->id, root->bus); + result = acpi_pci_bind_root(device); if (result) goto end; @@ -511,8 +557,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) */ status = acpi_get_handle(device->handle, METHOD_NAME__PRT, &handle); if (ACPI_SUCCESS(status)) - result = acpi_pci_irq_add_prt(device->handle, root->id.segment, - root->id.bus); + result = acpi_pci_irq_add_prt(device->handle, root->bus); /* * Scan and bind all _ADR-Based Devices @@ -531,42 +576,28 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) if (flags != base_flags) acpi_pci_osc_support(root, flags); - end: - if (result) { - if (!list_empty(&root->node)) - list_del(&root->node); - kfree(root); - } + return 0; +end: + if (!list_empty(&root->node)) + list_del(&root->node); + kfree(root); return result; } static int acpi_pci_root_start(struct acpi_device *device) { - struct acpi_pci_root *root; + struct acpi_pci_root *root = acpi_driver_data(device); - - list_for_each_entry(root, &acpi_pci_roots, node) { - if (root->device == device) { - pci_bus_add_devices(root->bus); - return 0; - } - } - return -ENODEV; + pci_bus_add_devices(root->bus); + return 0; } static int acpi_pci_root_remove(struct acpi_device *device, int type) { - struct acpi_pci_root *root = NULL; - - - if (!device || !acpi_driver_data(device)) - return -EINVAL; - - root = acpi_driver_data(device); + struct acpi_pci_root *root = acpi_driver_data(device); kfree(root); - return 0; } diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 56665a63bf19..d74365d4a6e7 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -194,7 +194,7 @@ static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state) static int acpi_power_on(acpi_handle handle, struct acpi_device *dev) { - int result = 0, state; + int result = 0; int found = 0; acpi_status status = AE_OK; struct acpi_power_resource *resource = NULL; @@ -236,18 +236,6 @@ static int acpi_power_on(acpi_handle handle, struct acpi_device *dev) if (ACPI_FAILURE(status)) return -ENODEV; - if (!acpi_power_nocheck) { - /* - * If acpi_power_nocheck is set, it is unnecessary to check - * the power state after power transition. - */ - result = acpi_power_get_state(resource->device->handle, - &state); - if (result) - return result; - if (state != ACPI_POWER_RESOURCE_STATE_ON) - return -ENOEXEC; - } /* Update the power resource's _device_ power state */ resource->device->power.state = ACPI_STATE_D0; @@ -258,7 +246,7 @@ static int acpi_power_on(acpi_handle handle, struct acpi_device *dev) static int acpi_power_off_device(acpi_handle handle, struct acpi_device *dev) { - int result = 0, state; + int result = 0; acpi_status status = AE_OK; struct acpi_power_resource *resource = NULL; struct list_head *node, *next; @@ -293,18 +281,6 @@ static int acpi_power_off_device(acpi_handle handle, struct acpi_device *dev) if (ACPI_FAILURE(status)) return -ENODEV; - if (!acpi_power_nocheck) { - /* - * If acpi_power_nocheck is set, it is unnecessary to check - * the power state after power transition. - */ - result = acpi_power_get_state(handle, &state); - if (result) - return result; - if (state != ACPI_POWER_RESOURCE_STATE_OFF) - return -ENOEXEC; - } - /* Update the power resource's _device_ power state */ resource->device->power.state = ACPI_STATE_D3; diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index 23f0fb84f1c1..84e0f3c07442 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -89,7 +89,7 @@ static int acpi_processor_handle_eject(struct acpi_processor *pr); static const struct acpi_device_id processor_device_ids[] = { {ACPI_PROCESSOR_OBJECT_HID, 0}, - {ACPI_PROCESSOR_HID, 0}, + {"ACPI0007", 0}, {"", 0}, }; MODULE_DEVICE_TABLE(acpi, processor_device_ids); @@ -596,7 +596,21 @@ static int acpi_processor_get_info(struct acpi_device *device) ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No bus mastering arbitration control\n")); - if (!strcmp(acpi_device_hid(device), ACPI_PROCESSOR_HID)) { + if (!strcmp(acpi_device_hid(device), ACPI_PROCESSOR_OBJECT_HID)) { + /* Declared with "Processor" statement; match ProcessorID */ + status = acpi_evaluate_object(pr->handle, NULL, NULL, &buffer); + if (ACPI_FAILURE(status)) { + printk(KERN_ERR PREFIX "Evaluating processor object\n"); + return -ENODEV; + } + + /* + * TBD: Synch processor ID (via LAPIC/LSAPIC structures) on SMP. + * >>> 'acpi_get_processor_id(acpi_id, &id)' in + * arch/xxx/acpi.c + */ + pr->acpi_id = object.processor.proc_id; + } else { /* * Declared with "Device" statement; match _UID. * Note that we don't handle string _UIDs yet. @@ -611,20 +625,6 @@ static int acpi_processor_get_info(struct acpi_device *device) } device_declaration = 1; pr->acpi_id = value; - } else { - /* Declared with "Processor" statement; match ProcessorID */ - status = acpi_evaluate_object(pr->handle, NULL, NULL, &buffer); - if (ACPI_FAILURE(status)) { - printk(KERN_ERR PREFIX "Evaluating processor object\n"); - return -ENODEV; - } - - /* - * TBD: Synch processor ID (via LAPIC/LSAPIC structures) on SMP. - * >>> 'acpi_get_processor_id(acpi_id, &id)' in - * arch/xxx/acpi.c - */ - pr->acpi_id = object.processor.proc_id; } cpu_index = get_cpu_id(pr->handle, device_declaration, pr->acpi_id); @@ -649,7 +649,16 @@ static int acpi_processor_get_info(struct acpi_device *device) return -ENODEV; } } - + /* + * On some boxes several processors use the same processor bus id. + * But they are located in different scope. For example: + * \_SB.SCK0.CPU0 + * \_SB.SCK1.CPU0 + * Rename the processor device bus id. And the new bus id will be + * generated as the following format: + * CPU+CPU ID. + */ + sprintf(acpi_device_bid(device), "CPU%X", pr->id); ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Processor [%d:%d]\n", pr->id, pr->acpi_id)); @@ -731,6 +740,8 @@ static int __cpuinit acpi_processor_start(struct acpi_device *device) /* _PDC call should be done before doing anything else (if reqd.). */ arch_acpi_processor_init_pdc(pr); acpi_processor_set_pdc(pr); + arch_acpi_processor_cleanup_pdc(pr); + #ifdef CONFIG_CPU_FREQ acpi_processor_ppc_has_changed(pr); #endif diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 10a2d913635a..0efa59e7e3af 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -139,7 +139,7 @@ static void acpi_safe_halt(void) * are affected too. We pick the most conservative approach: we assume * that the local APIC stops in both C2 and C3. */ -static void acpi_timer_check_state(int state, struct acpi_processor *pr, +static void lapic_timer_check_state(int state, struct acpi_processor *pr, struct acpi_processor_cx *cx) { struct acpi_processor_power *pwr = &pr->power; @@ -162,7 +162,7 @@ static void acpi_timer_check_state(int state, struct acpi_processor *pr, pr->power.timer_broadcast_on_state = state; } -static void acpi_propagate_timer_broadcast(struct acpi_processor *pr) +static void lapic_timer_propagate_broadcast(struct acpi_processor *pr) { unsigned long reason; @@ -173,7 +173,7 @@ static void acpi_propagate_timer_broadcast(struct acpi_processor *pr) } /* Power(C) State timer broadcast control */ -static void acpi_state_timer_broadcast(struct acpi_processor *pr, +static void lapic_timer_state_broadcast(struct acpi_processor *pr, struct acpi_processor_cx *cx, int broadcast) { @@ -190,10 +190,10 @@ static void acpi_state_timer_broadcast(struct acpi_processor *pr, #else -static void acpi_timer_check_state(int state, struct acpi_processor *pr, +static void lapic_timer_check_state(int state, struct acpi_processor *pr, struct acpi_processor_cx *cstate) { } -static void acpi_propagate_timer_broadcast(struct acpi_processor *pr) { } -static void acpi_state_timer_broadcast(struct acpi_processor *pr, +static void lapic_timer_propagate_broadcast(struct acpi_processor *pr) { } +static void lapic_timer_state_broadcast(struct acpi_processor *pr, struct acpi_processor_cx *cx, int broadcast) { @@ -515,7 +515,8 @@ static void acpi_processor_power_verify_c2(struct acpi_processor_cx *cx) static void acpi_processor_power_verify_c3(struct acpi_processor *pr, struct acpi_processor_cx *cx) { - static int bm_check_flag; + static int bm_check_flag = -1; + static int bm_control_flag = -1; if (!cx->address) @@ -545,12 +546,14 @@ static void acpi_processor_power_verify_c3(struct acpi_processor *pr, } /* All the logic here assumes flags.bm_check is same across all CPUs */ - if (!bm_check_flag) { + if (bm_check_flag == -1) { /* Determine whether bm_check is needed based on CPU */ acpi_processor_power_init_bm_check(&(pr->flags), pr->id); bm_check_flag = pr->flags.bm_check; + bm_control_flag = pr->flags.bm_control; } else { pr->flags.bm_check = bm_check_flag; + pr->flags.bm_control = bm_control_flag; } if (pr->flags.bm_check) { @@ -614,29 +617,25 @@ static int acpi_processor_power_verify(struct acpi_processor *pr) switch (cx->type) { case ACPI_STATE_C1: cx->valid = 1; - acpi_timer_check_state(i, pr, cx); break; case ACPI_STATE_C2: acpi_processor_power_verify_c2(cx); - if (cx->valid) - acpi_timer_check_state(i, pr, cx); break; case ACPI_STATE_C3: acpi_processor_power_verify_c3(pr, cx); - if (cx->valid) - acpi_timer_check_state(i, pr, cx); break; } - if (cx->valid) - tsc_check_state(cx->type); + if (!cx->valid) + continue; - if (cx->valid) - working++; + lapic_timer_check_state(i, pr, cx); + tsc_check_state(cx->type); + working++; } - acpi_propagate_timer_broadcast(pr); + lapic_timer_propagate_broadcast(pr); return (working); } @@ -839,7 +838,7 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev, return 0; } - acpi_state_timer_broadcast(pr, cx, 1); + lapic_timer_state_broadcast(pr, cx, 1); kt1 = ktime_get_real(); acpi_idle_do_entry(cx); kt2 = ktime_get_real(); @@ -847,7 +846,7 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev, local_irq_enable(); cx->usage++; - acpi_state_timer_broadcast(pr, cx, 0); + lapic_timer_state_broadcast(pr, cx, 0); return idle_time; } @@ -892,7 +891,7 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev, * Must be done before busmaster disable as we might need to * access HPET ! */ - acpi_state_timer_broadcast(pr, cx, 1); + lapic_timer_state_broadcast(pr, cx, 1); if (cx->type == ACPI_STATE_C3) ACPI_FLUSH_CPU_CACHE(); @@ -914,7 +913,7 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev, cx->usage++; - acpi_state_timer_broadcast(pr, cx, 0); + lapic_timer_state_broadcast(pr, cx, 0); cx->time += sleep_ticks; return idle_time; } @@ -981,7 +980,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, * Must be done before busmaster disable as we might need to * access HPET ! */ - acpi_state_timer_broadcast(pr, cx, 1); + lapic_timer_state_broadcast(pr, cx, 1); kt1 = ktime_get_real(); /* @@ -1026,7 +1025,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, cx->usage++; - acpi_state_timer_broadcast(pr, cx, 0); + lapic_timer_state_broadcast(pr, cx, 0); cx->time += sleep_ticks; return idle_time; } diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 8ff510b91d88..781435d7e369 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -95,7 +95,7 @@ acpi_device_modalias_show(struct device *dev, struct device_attribute *attr, cha } static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL); -static int acpi_bus_hot_remove_device(void *context) +static void acpi_bus_hot_remove_device(void *context) { struct acpi_device *device; acpi_handle handle = context; @@ -104,10 +104,10 @@ static int acpi_bus_hot_remove_device(void *context) acpi_status status = AE_OK; if (acpi_bus_get_device(handle, &device)) - return 0; + return; if (!device) - return 0; + return; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Hot-removing device %s...\n", dev_name(&device->dev))); @@ -115,7 +115,7 @@ static int acpi_bus_hot_remove_device(void *context) if (acpi_bus_trim(device, 1)) { printk(KERN_ERR PREFIX "Removing device failed\n"); - return -1; + return; } /* power off device */ @@ -142,9 +142,10 @@ static int acpi_bus_hot_remove_device(void *context) */ status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL); if (ACPI_FAILURE(status)) - return -ENODEV; + printk(KERN_WARNING PREFIX + "Eject device failed\n"); - return 0; + return; } static ssize_t @@ -155,7 +156,6 @@ acpi_eject_store(struct device *d, struct device_attribute *attr, acpi_status status; acpi_object_type type = 0; struct acpi_device *acpi_device = to_acpi_device(d); - struct task_struct *task; if ((!count) || (buf[0] != '1')) { return -EINVAL; @@ -172,11 +172,7 @@ acpi_eject_store(struct device *d, struct device_attribute *attr, goto err; } - /* remove the device in another thread to fix the deadlock issue */ - task = kthread_run(acpi_bus_hot_remove_device, - acpi_device->handle, "acpi_hot_remove_device"); - if (IS_ERR(task)) - ret = PTR_ERR(task); + acpi_os_hotplug_execute(acpi_bus_hot_remove_device, acpi_device->handle); err: return ret; } @@ -198,12 +194,12 @@ acpi_device_path_show(struct device *dev, struct device_attribute *attr, char *b int result; result = acpi_get_name(acpi_dev->handle, ACPI_FULL_PATHNAME, &path); - if(result) + if (result) goto end; result = sprintf(buf, "%s\n", (char*)path.pointer); kfree(path.pointer); - end: +end: return result; } static DEVICE_ATTR(path, 0444, acpi_device_path_show, NULL); @@ -217,21 +213,21 @@ static int acpi_device_setup_files(struct acpi_device *dev) /* * Devices gotten from FADT don't have a "path" attribute */ - if(dev->handle) { + if (dev->handle) { result = device_create_file(&dev->dev, &dev_attr_path); - if(result) + if (result) goto end; } - if(dev->flags.hardware_id) { + if (dev->flags.hardware_id) { result = device_create_file(&dev->dev, &dev_attr_hid); - if(result) + if (result) goto end; } - if (dev->flags.hardware_id || dev->flags.compatible_ids){ + if (dev->flags.hardware_id || dev->flags.compatible_ids) { result = device_create_file(&dev->dev, &dev_attr_modalias); - if(result) + if (result) goto end; } @@ -242,7 +238,7 @@ static int acpi_device_setup_files(struct acpi_device *dev) status = acpi_get_handle(dev->handle, "_EJ0", &temp); if (ACPI_SUCCESS(status)) result = device_create_file(&dev->dev, &dev_attr_eject); - end: +end: return result; } @@ -262,9 +258,9 @@ static void acpi_device_remove_files(struct acpi_device *dev) if (dev->flags.hardware_id || dev->flags.compatible_ids) device_remove_file(&dev->dev, &dev_attr_modalias); - if(dev->flags.hardware_id) + if (dev->flags.hardware_id) device_remove_file(&dev->dev, &dev_attr_hid); - if(dev->handle) + if (dev->handle) device_remove_file(&dev->dev, &dev_attr_path); } /* -------------------------------------------------------------------------- @@ -512,7 +508,7 @@ static int acpi_device_register(struct acpi_device *device, break; } } - if(!found) { + if (!found) { acpi_device_bus_id = new_bus_id; strcpy(acpi_device_bus_id->bus_id, device->flags.hardware_id ? device->pnp.hardware_id : "device"); acpi_device_bus_id->instance_no = 0; @@ -530,22 +526,21 @@ static int acpi_device_register(struct acpi_device *device, if (device->parent) device->dev.parent = &parent->dev; device->dev.bus = &acpi_bus_type; - device_initialize(&device->dev); device->dev.release = &acpi_device_release; - result = device_add(&device->dev); - if(result) { - dev_err(&device->dev, "Error adding device\n"); + result = device_register(&device->dev); + if (result) { + dev_err(&device->dev, "Error registering device\n"); goto end; } result = acpi_device_setup_files(device); - if(result) + if (result) printk(KERN_ERR PREFIX "Error creating sysfs interface for device %s\n", dev_name(&device->dev)); device->removal_type = ACPI_BUS_REMOVAL_NORMAL; return 0; - end: +end: mutex_lock(&acpi_device_lock); if (device->parent) list_del(&device->node); @@ -577,7 +572,7 @@ static void acpi_device_unregister(struct acpi_device *device, int type) * @device: the device to add and initialize * @driver: driver for the device * - * Used to initialize a device via its device driver. Called whenever a + * Used to initialize a device via its device driver. Called whenever a * driver is bound to a device. Invokes the driver's add() ops. */ static int @@ -585,7 +580,6 @@ acpi_bus_driver_init(struct acpi_device *device, struct acpi_driver *driver) { int result = 0; - if (!device || !driver) return -EINVAL; @@ -802,7 +796,7 @@ static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device) if (!acpi_match_device_ids(device, button_device_ids)) device->wakeup.flags.run_wake = 1; - end: +end: if (ACPI_FAILURE(status)) device->flags.wake_capable = 0; return 0; @@ -1070,7 +1064,7 @@ static void acpi_device_set_id(struct acpi_device *device, break; } - /* + /* * \_SB * ---- * Fix for the system root bus device -- the only root-level device. @@ -1320,7 +1314,7 @@ acpi_add_single_object(struct acpi_device **child, device->parent->ops.bind(device); } - end: +end: if (!result) *child = device; else { @@ -1464,7 +1458,6 @@ acpi_bus_add(struct acpi_device **child, return result; } - EXPORT_SYMBOL(acpi_bus_add); int acpi_bus_start(struct acpi_device *device) @@ -1484,7 +1477,6 @@ int acpi_bus_start(struct acpi_device *device) } return result; } - EXPORT_SYMBOL(acpi_bus_start); int acpi_bus_trim(struct acpi_device *start, int rmdevice) @@ -1542,7 +1534,6 @@ int acpi_bus_trim(struct acpi_device *start, int rmdevice) } EXPORT_SYMBOL_GPL(acpi_bus_trim); - static int acpi_bus_scan_fixed(struct acpi_device *root) { int result = 0; @@ -1610,6 +1601,6 @@ int __init acpi_scan_init(void) if (result) acpi_device_unregister(acpi_root, ACPI_BUS_REMOVAL_NORMAL); - Done: +Done: return result; } diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 1bdfb37377e3..8851315ce858 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -76,6 +76,7 @@ MODULE_LICENSE("GPL"); static int brightness_switch_enabled = 1; module_param(brightness_switch_enabled, bool, 0644); +static int register_count = 0; static int acpi_video_bus_add(struct acpi_device *device); static int acpi_video_bus_remove(struct acpi_device *device, int type); static int acpi_video_resume(struct acpi_device *device); @@ -586,6 +587,14 @@ static struct dmi_system_id video_dmi_table[] __initdata = { DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5315"), }, }, + { + .callback = video_set_bqc_offset, + .ident = "Acer Aspire 7720", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 7720"), + }, + }, {} }; @@ -976,6 +985,11 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) device->backlight->props.max_brightness = device->brightness->count-3; kfree(name); + result = sysfs_create_link(&device->backlight->dev.kobj, + &device->dev->dev.kobj, "device"); + if (result) + printk(KERN_ERR PREFIX "Create sysfs link\n"); + device->cdev = thermal_cooling_device_register("LCD", device->dev, &video_cooling_ops); if (IS_ERR(device->cdev)) @@ -1054,15 +1068,15 @@ static void acpi_video_bus_find_cap(struct acpi_video_bus *video) static int acpi_video_bus_check(struct acpi_video_bus *video) { acpi_status status = -ENOENT; - struct device *dev; + struct pci_dev *dev; if (!video) return -EINVAL; - dev = acpi_get_physical_pci_device(video->device->handle); + dev = acpi_get_pci_dev(video->device->handle); if (!dev) return -ENODEV; - put_device(dev); + pci_dev_put(dev); /* Since there is no HID, CID and so on for VGA driver, we have * to check well known required nodes. @@ -1990,6 +2004,7 @@ static int acpi_video_bus_put_one_device(struct acpi_video_device *device) status = acpi_remove_notify_handler(device->dev->handle, ACPI_DEVICE_NOTIFY, acpi_video_device_notify); + sysfs_remove_link(&device->backlight->dev.kobj, "device"); backlight_device_unregister(device->backlight); if (device->cdev) { sysfs_remove_link(&device->dev->dev.kobj, @@ -2318,6 +2333,13 @@ static int __init intel_opregion_present(void) int acpi_video_register(void) { int result = 0; + if (register_count) { + /* + * if the function of acpi_video_register is already called, + * don't register the acpi_vide_bus again and return no error. + */ + return 0; + } acpi_video_dir = proc_mkdir(ACPI_VIDEO_CLASS, acpi_root_dir); if (!acpi_video_dir) @@ -2329,10 +2351,35 @@ int acpi_video_register(void) return -ENODEV; } + /* + * When the acpi_video_bus is loaded successfully, increase + * the counter reference. + */ + register_count = 1; + return 0; } EXPORT_SYMBOL(acpi_video_register); +void acpi_video_unregister(void) +{ + if (!register_count) { + /* + * If the acpi video bus is already unloaded, don't + * unload it again and return directly. + */ + return; + } + acpi_bus_unregister_driver(&acpi_video_bus); + + remove_proc_entry(ACPI_VIDEO_CLASS, acpi_root_dir); + + register_count = 0; + + return; +} +EXPORT_SYMBOL(acpi_video_unregister); + /* * This is kind of nasty. Hardware using Intel chipsets may require * the video opregion code to be run first in order to initialise @@ -2350,16 +2397,12 @@ static int __init acpi_video_init(void) return acpi_video_register(); } -void acpi_video_exit(void) +static void __exit acpi_video_exit(void) { - - acpi_bus_unregister_driver(&acpi_video_bus); - - remove_proc_entry(ACPI_VIDEO_CLASS, acpi_root_dir); + acpi_video_unregister(); return; } -EXPORT_SYMBOL(acpi_video_exit); module_init(acpi_video_init); module_exit(acpi_video_exit); diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index 09737275e25f..7cd2b63435ea 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -10,7 +10,7 @@ * assinged * * After PCI devices are glued with ACPI devices - * acpi_get_physical_pci_device() can be called to identify ACPI graphics + * acpi_get_pci_dev() can be called to identify ACPI graphics * devices for which a real graphics card is plugged in * * Now acpi_video_get_capabilities() can be called to check which @@ -36,6 +36,7 @@ #include #include +#include ACPI_MODULE_NAME("video"); #define _COMPONENT ACPI_VIDEO_COMPONENT @@ -109,7 +110,7 @@ static acpi_status find_video(acpi_handle handle, u32 lvl, void *context, void **rv) { long *cap = context; - struct device *dev; + struct pci_dev *dev; struct acpi_device *acpi_dev; const struct acpi_device_id video_ids[] = { @@ -120,10 +121,10 @@ find_video(acpi_handle handle, u32 lvl, void *context, void **rv) return AE_OK; if (!acpi_match_device_ids(acpi_dev, video_ids)) { - dev = acpi_get_physical_pci_device(handle); + dev = acpi_get_pci_dev(handle); if (!dev) return AE_OK; - put_device(dev); + pci_dev_put(dev); *cap |= acpi_is_video_device(acpi_dev); } return AE_OK; diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 9120717c0701..b17c57f85032 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -535,6 +535,15 @@ config PATA_OPTIDMA If unsure, say N. +config PATA_PALMLD + tristate "Palm LifeDrive PATA support" + depends on MACH_PALMLD + help + This option enables support for Palm LifeDrive's internal ATA + port via the new ATA layer. + + If unsure, say N. + config PATA_PCMCIA tristate "PCMCIA PATA support" depends on PCMCIA @@ -670,6 +679,14 @@ config PATA_PLATFORM If unsure, say N. +config PATA_AT91 + tristate "PATA support for AT91SAM9260" + depends on ARM && ARCH_AT91 + help + This option enables support for IDE devices on the Atmel AT91SAM9260 SoC. + + If unsure, say N. + config PATA_OF_PLATFORM tristate "OpenFirmware platform device PATA support" depends on PATA_PLATFORM && PPC_OF diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index 7f1ecf99528c..38906f9bbb4e 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -50,6 +50,7 @@ obj-$(CONFIG_PATA_MPC52xx) += pata_mpc52xx.o obj-$(CONFIG_PATA_MARVELL) += pata_marvell.o obj-$(CONFIG_PATA_MPIIX) += pata_mpiix.o obj-$(CONFIG_PATA_OLDPIIX) += pata_oldpiix.o +obj-$(CONFIG_PATA_PALMLD) += pata_palmld.o obj-$(CONFIG_PATA_PCMCIA) += pata_pcmcia.o obj-$(CONFIG_PATA_PDC2027X) += pata_pdc2027x.o obj-$(CONFIG_PATA_PDC_OLD) += pata_pdc202xx_old.o @@ -71,6 +72,7 @@ obj-$(CONFIG_PATA_SCH) += pata_sch.o obj-$(CONFIG_PATA_BF54X) += pata_bf54x.o obj-$(CONFIG_PATA_OCTEON_CF) += pata_octeon_cf.o obj-$(CONFIG_PATA_PLATFORM) += pata_platform.o +obj-$(CONFIG_PATA_AT91) += pata_at91.o obj-$(CONFIG_PATA_OF_PLATFORM) += pata_of_platform.o obj-$(CONFIG_PATA_ICSIDE) += pata_icside.o # Should be last but two libata driver diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 6b91c26a4635..15a23031833f 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -77,8 +77,6 @@ static ssize_t ahci_led_store(struct ata_port *ap, const char *buf, size_t size); static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state, ssize_t size); -#define MAX_SLOTS 8 -#define MAX_RETRY 15 enum { AHCI_PCI_BAR = 5, @@ -231,6 +229,10 @@ enum { ICH_MAP = 0x90, /* ICH MAP register */ + /* em constants */ + EM_MAX_SLOTS = 8, + EM_MAX_RETRY = 5, + /* em_ctl bits */ EM_CTL_RST = (1 << 9), /* Reset */ EM_CTL_TM = (1 << 8), /* Transmit Message */ @@ -282,8 +284,8 @@ struct ahci_port_priv { unsigned int ncq_saw_dmas:1; unsigned int ncq_saw_sdb:1; u32 intr_mask; /* interrupts to enable */ - struct ahci_em_priv em_priv[MAX_SLOTS];/* enclosure management info - * per PM slot */ + /* enclosure management info per PM slot */ + struct ahci_em_priv em_priv[EM_MAX_SLOTS]; }; static int ahci_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val); @@ -313,7 +315,6 @@ static void ahci_error_handler(struct ata_port *ap); static void ahci_post_internal_cmd(struct ata_queued_cmd *qc); static int ahci_port_resume(struct ata_port *ap); static void ahci_dev_config(struct ata_device *dev); -static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl); static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag, u32 opts); #ifdef CONFIG_PM @@ -404,14 +405,14 @@ static struct ata_port_operations ahci_sb600_ops = { #define AHCI_HFLAGS(flags) .private_data = (void *)(flags) static const struct ata_port_info ahci_port_info[] = { - /* board_ahci */ + [board_ahci] = { .flags = AHCI_FLAG_COMMON, .pio_mask = ATA_PIO4, .udma_mask = ATA_UDMA6, .port_ops = &ahci_ops, }, - /* board_ahci_vt8251 */ + [board_ahci_vt8251] = { AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_PMP), .flags = AHCI_FLAG_COMMON, @@ -419,7 +420,7 @@ static const struct ata_port_info ahci_port_info[] = { .udma_mask = ATA_UDMA6, .port_ops = &ahci_vt8251_ops, }, - /* board_ahci_ign_iferr */ + [board_ahci_ign_iferr] = { AHCI_HFLAGS (AHCI_HFLAG_IGN_IRQ_IF_ERR), .flags = AHCI_FLAG_COMMON, @@ -427,17 +428,16 @@ static const struct ata_port_info ahci_port_info[] = { .udma_mask = ATA_UDMA6, .port_ops = &ahci_ops, }, - /* board_ahci_sb600 */ + [board_ahci_sb600] = { AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL | - AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_MSI | - AHCI_HFLAG_SECT255), + AHCI_HFLAG_NO_MSI | AHCI_HFLAG_SECT255), .flags = AHCI_FLAG_COMMON, .pio_mask = ATA_PIO4, .udma_mask = ATA_UDMA6, .port_ops = &ahci_sb600_ops, }, - /* board_ahci_mv */ + [board_ahci_mv] = { AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_MSI | AHCI_HFLAG_MV_PATA | AHCI_HFLAG_NO_PMP), @@ -447,7 +447,7 @@ static const struct ata_port_info ahci_port_info[] = { .udma_mask = ATA_UDMA6, .port_ops = &ahci_ops, }, - /* board_ahci_sb700, for SB700 and SB800 */ + [board_ahci_sb700] = /* for SB700 and SB800 */ { AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL), .flags = AHCI_FLAG_COMMON, @@ -455,7 +455,7 @@ static const struct ata_port_info ahci_port_info[] = { .udma_mask = ATA_UDMA6, .port_ops = &ahci_sb600_ops, }, - /* board_ahci_mcp65 */ + [board_ahci_mcp65] = { AHCI_HFLAGS (AHCI_HFLAG_YES_NCQ), .flags = AHCI_FLAG_COMMON, @@ -463,7 +463,7 @@ static const struct ata_port_info ahci_port_info[] = { .udma_mask = ATA_UDMA6, .port_ops = &ahci_ops, }, - /* board_ahci_nopmp */ + [board_ahci_nopmp] = { AHCI_HFLAGS (AHCI_HFLAG_NO_PMP), .flags = AHCI_FLAG_COMMON, @@ -1141,12 +1141,12 @@ static void ahci_start_port(struct ata_port *ap) emp = &pp->em_priv[link->pmp]; /* EM Transmit bit maybe busy during init */ - for (i = 0; i < MAX_RETRY; i++) { + for (i = 0; i < EM_MAX_RETRY; i++) { rc = ahci_transmit_led_message(ap, emp->led_state, 4); if (rc == -EBUSY) - udelay(100); + msleep(1); else break; } @@ -1340,7 +1340,7 @@ static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state, /* get the slot number from the message */ pmp = (state & EM_MSG_LED_PMP_SLOT) >> 8; - if (pmp < MAX_SLOTS) + if (pmp < EM_MAX_SLOTS) emp = &pp->em_priv[pmp]; else return -EINVAL; @@ -1408,7 +1408,7 @@ static ssize_t ahci_led_store(struct ata_port *ap, const char *buf, /* get the slot number from the message */ pmp = (state & EM_MSG_LED_PMP_SLOT) >> 8; - if (pmp < MAX_SLOTS) + if (pmp < EM_MAX_SLOTS) emp = &pp->em_priv[pmp]; else return -EINVAL; @@ -2584,6 +2584,51 @@ static void ahci_p5wdh_workaround(struct ata_host *host) } } +/* + * SB600 ahci controller on ASUS M2A-VM can't do 64bit DMA with older + * BIOS. The oldest version known to be broken is 0901 and working is + * 1501 which was released on 2007-10-26. Force 32bit DMA on anything + * older than 1501. Please read bko#9412 for more info. + */ +static bool ahci_asus_m2a_vm_32bit_only(struct pci_dev *pdev) +{ + static const struct dmi_system_id sysids[] = { + { + .ident = "ASUS M2A-VM", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, + "ASUSTeK Computer INC."), + DMI_MATCH(DMI_BOARD_NAME, "M2A-VM"), + }, + }, + { } + }; + const char *cutoff_mmdd = "10/26"; + const char *date; + int year; + + if (pdev->bus->number != 0 || pdev->devfn != PCI_DEVFN(0x12, 0) || + !dmi_check_system(sysids)) + return false; + + /* + * Argh.... both version and date are free form strings. + * Let's hope they're using the same date format across + * different versions. + */ + date = dmi_get_system_info(DMI_BIOS_DATE); + year = dmi_get_year(DMI_BIOS_DATE); + if (date && strlen(date) >= 10 && date[2] == '/' && date[5] == '/' && + (year > 2007 || + (year == 2007 && strncmp(date, cutoff_mmdd, 5) >= 0))) + return false; + + dev_printk(KERN_WARNING, &pdev->dev, "ASUS M2A-VM: BIOS too old, " + "forcing 32bit DMA, update BIOS\n"); + + return true; +} + static bool ahci_broken_system_poweroff(struct pci_dev *pdev) { static const struct dmi_system_id broken_systems[] = { @@ -2744,6 +2789,10 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (board_id == board_ahci_sb700 && pdev->revision >= 0x40) hpriv->flags &= ~AHCI_HFLAG_IGN_SERR_INTERNAL; + /* apply ASUS M2A_VM quirk */ + if (ahci_asus_m2a_vm_32bit_only(pdev)) + hpriv->flags |= AHCI_HFLAG_32BIT_ONLY; + if (!(hpriv->flags & AHCI_HFLAG_NO_MSI)) pci_enable_msi(pdev); diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 1aeb7082b0c4..d0a14cf2bd74 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -223,10 +223,8 @@ static const struct pci_device_id piix_pci_tbl[] = { /* ICH8 Mobile PATA Controller */ { 0x8086, 0x2850, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, - /* NOTE: The following PCI ids must be kept in sync with the - * list in drivers/pci/quirks.c. - */ - + /* SATA ports */ + /* 82801EB (ICH5) */ { 0x8086, 0x24d1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata }, /* 82801EB (ICH5) */ @@ -1509,8 +1507,8 @@ static int __devinit piix_init_one(struct pci_dev *pdev, dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); - /* no hotplugging support (FIXME) */ - if (!in_module_init) + /* no hotplugging support for later devices (FIXME) */ + if (!in_module_init && ent->driver_data >= ich5_sata) return -ENODEV; if (piix_broken_system_poweroff(pdev)) { @@ -1591,6 +1589,7 @@ static int __devinit piix_init_one(struct pci_dev *pdev, host->ports[1]->mwdma_mask = 0; host->ports[1]->udma_mask = 0; } + host->flags |= ATA_HOST_PARALLEL_SCAN; pci_set_master(pdev); return ata_pci_sff_activate_host(host, ata_sff_interrupt, &piix_sht); diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index 6273d98d00eb..ac176da1f94e 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -748,9 +748,9 @@ static int ata_acpi_run_tf(struct ata_device *dev, /** * ata_acpi_exec_tfs - get then write drive taskfile settings * @dev: target ATA device - * @nr_executed: out paramter for the number of executed commands + * @nr_executed: out parameter for the number of executed commands * - * Evaluate _GTF and excute returned taskfiles. + * Evaluate _GTF and execute returned taskfiles. * * LOCKING: * EH context. diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index c9242301cfa1..045a486a09ea 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -125,19 +125,19 @@ MODULE_PARM_DESC(force, "Force ATA configurations including cable type, link spe static int atapi_enabled = 1; module_param(atapi_enabled, int, 0444); -MODULE_PARM_DESC(atapi_enabled, "Enable discovery of ATAPI devices (0=off, 1=on)"); +MODULE_PARM_DESC(atapi_enabled, "Enable discovery of ATAPI devices (0=off, 1=on [default])"); static int atapi_dmadir = 0; module_param(atapi_dmadir, int, 0444); -MODULE_PARM_DESC(atapi_dmadir, "Enable ATAPI DMADIR bridge support (0=off, 1=on)"); +MODULE_PARM_DESC(atapi_dmadir, "Enable ATAPI DMADIR bridge support (0=off [default], 1=on)"); int atapi_passthru16 = 1; module_param(atapi_passthru16, int, 0444); -MODULE_PARM_DESC(atapi_passthru16, "Enable ATA_16 passthru for ATAPI devices; on by default (0=off, 1=on)"); +MODULE_PARM_DESC(atapi_passthru16, "Enable ATA_16 passthru for ATAPI devices (0=off, 1=on [default])"); int libata_fua = 0; module_param_named(fua, libata_fua, int, 0444); -MODULE_PARM_DESC(fua, "FUA support (0=off, 1=on)"); +MODULE_PARM_DESC(fua, "FUA support (0=off [default], 1=on)"); static int ata_ignore_hpa; module_param_named(ignore_hpa, ata_ignore_hpa, int, 0644); @@ -153,11 +153,11 @@ MODULE_PARM_DESC(ata_probe_timeout, "Set ATA probing timeout (seconds)"); int libata_noacpi = 0; module_param_named(noacpi, libata_noacpi, int, 0444); -MODULE_PARM_DESC(noacpi, "Disables the use of ACPI in probe/suspend/resume when set"); +MODULE_PARM_DESC(noacpi, "Disable the use of ACPI in probe/suspend/resume (0=off [default], 1=on)"); int libata_allow_tpm = 0; module_param_named(allow_tpm, libata_allow_tpm, int, 0444); -MODULE_PARM_DESC(allow_tpm, "Permit the use of TPM commands"); +MODULE_PARM_DESC(allow_tpm, "Permit the use of TPM commands (0=off [default], 1=on)"); MODULE_AUTHOR("Jeff Garzik"); MODULE_DESCRIPTION("Library module for ATA devices"); @@ -1993,11 +1993,17 @@ unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd) * Check if the current speed of the device requires IORDY. Used * by various controllers for chip configuration. */ - unsigned int ata_pio_need_iordy(const struct ata_device *adev) { - /* Controller doesn't support IORDY. Probably a pointless check - as the caller should know this */ + /* Don't set IORDY if we're preparing for reset. IORDY may + * lead to controller lock up on certain controllers if the + * port is not occupied. See bko#11703 for details. + */ + if (adev->link->ap->pflags & ATA_PFLAG_RESETTING) + return 0; + /* Controller doesn't support IORDY. Probably a pointless + * check as the caller should know this. + */ if (adev->link->ap->flags & ATA_FLAG_NO_IORDY) return 0; /* CF spec. r4.1 Table 22 says no iordy on PIO5 and PIO6. */ @@ -2020,7 +2026,6 @@ unsigned int ata_pio_need_iordy(const struct ata_device *adev) * Compute the highest mode possible if we are not using iordy. Return * -1 if no iordy mode is available. */ - static u32 ata_pio_mask_no_iordy(const struct ata_device *adev) { /* If we have no drive specific rule, then PIO 2 is non IORDY */ @@ -5031,7 +5036,6 @@ int ata_qc_complete_multiple(struct ata_port *ap, u32 qc_active) { int nr_done = 0; u32 done_mask; - int i; done_mask = ap->qc_active ^ qc_active; @@ -5041,16 +5045,16 @@ int ata_qc_complete_multiple(struct ata_port *ap, u32 qc_active) return -EINVAL; } - for (i = 0; i < ATA_MAX_QUEUE; i++) { + while (done_mask) { struct ata_queued_cmd *qc; + unsigned int tag = __ffs(done_mask); - if (!(done_mask & (1 << i))) - continue; - - if ((qc = ata_qc_from_tag(ap, i))) { + qc = ata_qc_from_tag(ap, tag); + if (qc) { ata_qc_complete(qc); nr_done++; } + done_mask &= ~(1 << tag); } return nr_done; diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 94919ad03df1..fa22f94ca415 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -2864,7 +2864,7 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link, /** * ata_set_mode - Program timings and issue SET FEATURES - XFER * @link: link on which timings will be programmed - * @r_failed_dev: out paramter for failed device + * @r_failed_dev: out parameter for failed device * * Set ATA device disk transfer mode (PIO3, UDMA6, etc.). If * ata_set_mode() fails, pointer to the failing device is diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 342316064e9f..d0dfeef55db5 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -1084,7 +1084,7 @@ static int atapi_drain_needed(struct request *rq) if (likely(!blk_pc_request(rq))) return 0; - if (!rq->data_len || (rq->cmd_flags & REQ_RW)) + if (!blk_rq_bytes(rq) || (rq->cmd_flags & REQ_RW)) return 0; return atapi_cmd_type(rq->cmd[0]) == ATAPI_MISC; diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index bb18415d3d63..bbbb1fab1755 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -727,17 +727,23 @@ unsigned int ata_sff_data_xfer(struct ata_device *dev, unsigned char *buf, else iowrite16_rep(data_addr, buf, words); - /* Transfer trailing 1 byte, if any. */ + /* Transfer trailing byte, if any. */ if (unlikely(buflen & 0x01)) { - __le16 align_buf[1] = { 0 }; - unsigned char *trailing_buf = buf + buflen - 1; + unsigned char pad[2]; + /* Point buf to the tail of buffer */ + buf += buflen - 1; + + /* + * Use io*16_rep() accessors here as well to avoid pointlessly + * swapping bytes to and fro on the big endian machines... + */ if (rw == READ) { - align_buf[0] = cpu_to_le16(ioread16(data_addr)); - memcpy(trailing_buf, align_buf, 1); + ioread16_rep(data_addr, pad, 1); + *buf = pad[0]; } else { - memcpy(align_buf, trailing_buf, 1); - iowrite16(le16_to_cpu(align_buf[0]), data_addr); + pad[0] = *buf; + iowrite16_rep(data_addr, pad, 1); } words++; } diff --git a/drivers/ata/pata_at91.c b/drivers/ata/pata_at91.c new file mode 100644 index 000000000000..4b27617be26d --- /dev/null +++ b/drivers/ata/pata_at91.c @@ -0,0 +1,361 @@ +/* + * PATA driver for AT91SAM9260 Static Memory Controller + * with CompactFlash interface in True IDE mode + * + * Copyright (C) 2009 Matyukevich Sergey + * + * Based on: + * * generic platform driver by Paul Mundt: drivers/ata/pata_platform.c + * * pata_at32 driver by Kristoffer Nyborg Gregertsen + * * at91_ide driver by Stanislaw Gruszka + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +#define DRV_NAME "pata_at91" +#define DRV_VERSION "0.1" + +#define CF_IDE_OFFSET 0x00c00000 +#define CF_ALT_IDE_OFFSET 0x00e00000 +#define CF_IDE_RES_SIZE 0x08 + +struct at91_ide_info { + unsigned long mode; + unsigned int cs; + + void __iomem *ide_addr; + void __iomem *alt_addr; +}; + +const struct ata_timing initial_timing = + {XFER_PIO_0, 70, 290, 240, 600, 165, 150, 600, 0}; + +static unsigned int calc_mck_cycles(unsigned int ns, unsigned int mck_hz) +{ + unsigned long mul; + + /* + * cycles = x [nsec] * f [Hz] / 10^9 [ns in sec] = + * x * (f / 1_000_000_000) = + * x * ((f * 65536) / 1_000_000_000) / 65536 = + * x * (((f / 10_000) * 65536) / 100_000) / 65536 = + */ + + mul = (mck_hz / 10000) << 16; + mul /= 100000; + + return (ns * mul + 65536) >> 16; /* rounding */ +} + +static void set_smc_mode(struct at91_ide_info *info) +{ + at91_sys_write(AT91_SMC_MODE(info->cs), info->mode); + return; +} + +static void set_smc_timing(struct device *dev, + struct at91_ide_info *info, const struct ata_timing *ata) +{ + int read_cycle, write_cycle, active, recover; + int nrd_setup, nrd_pulse, nrd_recover; + int nwe_setup, nwe_pulse; + + int ncs_write_setup, ncs_write_pulse; + int ncs_read_setup, ncs_read_pulse; + + unsigned int mck_hz; + struct clk *mck; + + read_cycle = ata->cyc8b; + nrd_setup = ata->setup; + nrd_pulse = ata->act8b; + nrd_recover = ata->rec8b; + + mck = clk_get(NULL, "mck"); + BUG_ON(IS_ERR(mck)); + mck_hz = clk_get_rate(mck); + + read_cycle = calc_mck_cycles(read_cycle, mck_hz); + nrd_setup = calc_mck_cycles(nrd_setup, mck_hz); + nrd_pulse = calc_mck_cycles(nrd_pulse, mck_hz); + nrd_recover = calc_mck_cycles(nrd_recover, mck_hz); + + clk_put(mck); + + active = nrd_setup + nrd_pulse; + recover = read_cycle - active; + + /* Need at least two cycles recovery */ + if (recover < 2) + read_cycle = active + 2; + + /* (CS0, CS1, DIR, OE) <= (CFCE1, CFCE2, CFRNW, NCSX) timings */ + ncs_read_setup = 1; + ncs_read_pulse = read_cycle - 2; + + /* Write timings same as read timings */ + write_cycle = read_cycle; + nwe_setup = nrd_setup; + nwe_pulse = nrd_pulse; + ncs_write_setup = ncs_read_setup; + ncs_write_pulse = ncs_read_pulse; + + dev_dbg(dev, "ATA timings: nrd_setup = %d nrd_pulse = %d nrd_cycle = %d\n", + nrd_setup, nrd_pulse, read_cycle); + dev_dbg(dev, "ATA timings: nwe_setup = %d nwe_pulse = %d nwe_cycle = %d\n", + nwe_setup, nwe_pulse, write_cycle); + dev_dbg(dev, "ATA timings: ncs_read_setup = %d ncs_read_pulse = %d\n", + ncs_read_setup, ncs_read_pulse); + dev_dbg(dev, "ATA timings: ncs_write_setup = %d ncs_write_pulse = %d\n", + ncs_write_setup, ncs_write_pulse); + + at91_sys_write(AT91_SMC_SETUP(info->cs), + AT91_SMC_NWESETUP_(nwe_setup) | + AT91_SMC_NRDSETUP_(nrd_setup) | + AT91_SMC_NCS_WRSETUP_(ncs_write_setup) | + AT91_SMC_NCS_RDSETUP_(ncs_read_setup)); + + at91_sys_write(AT91_SMC_PULSE(info->cs), + AT91_SMC_NWEPULSE_(nwe_pulse) | + AT91_SMC_NRDPULSE_(nrd_pulse) | + AT91_SMC_NCS_WRPULSE_(ncs_write_pulse) | + AT91_SMC_NCS_RDPULSE_(ncs_read_pulse)); + + at91_sys_write(AT91_SMC_CYCLE(info->cs), + AT91_SMC_NWECYCLE_(write_cycle) | + AT91_SMC_NRDCYCLE_(read_cycle)); + + return; +} + +static void pata_at91_set_piomode(struct ata_port *ap, struct ata_device *adev) +{ + struct at91_ide_info *info = ap->host->private_data; + struct ata_timing timing; + int ret; + + /* Compute ATA timing and set it to SMC */ + ret = ata_timing_compute(adev, adev->pio_mode, &timing, 1000, 0); + if (ret) { + dev_warn(ap->dev, "Failed to compute ATA timing %d, \ + set PIO_0 timing\n", ret); + set_smc_timing(ap->dev, info, &initial_timing); + } else { + set_smc_timing(ap->dev, info, &timing); + } + + /* Setup SMC mode */ + set_smc_mode(info); + + return; +} + +static unsigned int pata_at91_data_xfer_noirq(struct ata_device *dev, + unsigned char *buf, unsigned int buflen, int rw) +{ + struct at91_ide_info *info = dev->link->ap->host->private_data; + unsigned int consumed; + unsigned long flags; + unsigned int mode; + + local_irq_save(flags); + mode = at91_sys_read(AT91_SMC_MODE(info->cs)); + + /* set 16bit mode before writing data */ + at91_sys_write(AT91_SMC_MODE(info->cs), + (mode & ~AT91_SMC_DBW) | AT91_SMC_DBW_16); + + consumed = ata_sff_data_xfer(dev, buf, buflen, rw); + + /* restore 8bit mode after data is written */ + at91_sys_write(AT91_SMC_MODE(info->cs), + (mode & ~AT91_SMC_DBW) | AT91_SMC_DBW_8); + + local_irq_restore(flags); + return consumed; +} + +static struct scsi_host_template pata_at91_sht = { + ATA_PIO_SHT(DRV_NAME), +}; + +static struct ata_port_operations pata_at91_port_ops = { + .inherits = &ata_sff_port_ops, + + .sff_data_xfer = pata_at91_data_xfer_noirq, + .set_piomode = pata_at91_set_piomode, + .cable_detect = ata_cable_40wire, + .port_start = ATA_OP_NULL, +}; + +static int __devinit pata_at91_probe(struct platform_device *pdev) +{ + struct at91_cf_data *board = pdev->dev.platform_data; + struct device *dev = &pdev->dev; + struct at91_ide_info *info; + struct resource *mem_res; + struct ata_host *host; + struct ata_port *ap; + int irq_flags = 0; + int irq = 0; + int ret; + + /* get platform resources: IO/CTL memories and irq/rst pins */ + + if (pdev->num_resources != 1) { + dev_err(&pdev->dev, "invalid number of resources\n"); + return -EINVAL; + } + + mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + if (!mem_res) { + dev_err(dev, "failed to get mem resource\n"); + return -EINVAL; + } + + irq = board->irq_pin; + + /* init ata host */ + + host = ata_host_alloc(dev, 1); + + if (!host) + return -ENOMEM; + + ap = host->ports[0]; + ap->ops = &pata_at91_port_ops; + ap->flags |= ATA_FLAG_SLAVE_POSS; + ap->pio_mask = ATA_PIO4; + + if (!irq) { + ap->flags |= ATA_FLAG_PIO_POLLING; + ata_port_desc(ap, "no IRQ, using PIO polling"); + } + + info = kzalloc(sizeof(*info), GFP_KERNEL); + + if (!info) { + dev_err(dev, "failed to allocate memory for private data\n"); + return -ENOMEM; + } + + info->cs = board->chipselect; + info->mode = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | + AT91_SMC_EXNWMODE_READY | AT91_SMC_BAT_SELECT | + AT91_SMC_DBW_8 | AT91_SMC_TDF_(0); + + info->ide_addr = devm_ioremap(dev, + mem_res->start + CF_IDE_OFFSET, CF_IDE_RES_SIZE); + + if (!info->ide_addr) { + dev_err(dev, "failed to map IO base\n"); + ret = -ENOMEM; + goto err_ide_ioremap; + } + + info->alt_addr = devm_ioremap(dev, + mem_res->start + CF_ALT_IDE_OFFSET, CF_IDE_RES_SIZE); + + if (!info->alt_addr) { + dev_err(dev, "failed to map CTL base\n"); + ret = -ENOMEM; + goto err_alt_ioremap; + } + + ap->ioaddr.cmd_addr = info->ide_addr; + ap->ioaddr.ctl_addr = info->alt_addr + 0x06; + ap->ioaddr.altstatus_addr = ap->ioaddr.ctl_addr; + + ata_sff_std_ports(&ap->ioaddr); + + ata_port_desc(ap, "mmio cmd 0x%llx ctl 0x%llx", + (unsigned long long)mem_res->start + CF_IDE_OFFSET, + (unsigned long long)mem_res->start + CF_ALT_IDE_OFFSET); + + host->private_data = info; + + return ata_host_activate(host, irq ? gpio_to_irq(irq) : 0, + irq ? ata_sff_interrupt : NULL, + irq_flags, &pata_at91_sht); + +err_alt_ioremap: + devm_iounmap(dev, info->ide_addr); + +err_ide_ioremap: + kfree(info); + + return ret; +} + +static int __devexit pata_at91_remove(struct platform_device *pdev) +{ + struct ata_host *host = dev_get_drvdata(&pdev->dev); + struct at91_ide_info *info = host->private_data; + struct device *dev = &pdev->dev; + + if (!host) + return 0; + + ata_host_detach(host); + + if (!info) + return 0; + + devm_iounmap(dev, info->ide_addr); + devm_iounmap(dev, info->alt_addr); + + kfree(info); + return 0; +} + +static struct platform_driver pata_at91_driver = { + .probe = pata_at91_probe, + .remove = __devexit_p(pata_at91_remove), + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init pata_at91_init(void) +{ + return platform_driver_register(&pata_at91_driver); +} + +static void __exit pata_at91_exit(void) +{ + platform_driver_unregister(&pata_at91_driver); +} + + +module_init(pata_at91_init); +module_exit(pata_at91_exit); + + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Driver for CF in True IDE mode on AT91SAM9260 SoC"); +MODULE_AUTHOR("Matyukevich Sergey"); +MODULE_VERSION(DRV_VERSION); + diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c index 68d27bc70d06..2bc2dbe30e8f 100644 --- a/drivers/ata/pata_mpc52xx.c +++ b/drivers/ata/pata_mpc52xx.c @@ -694,7 +694,7 @@ mpc52xx_ata_probe(struct of_device *op, const struct of_device_id *match) struct bcom_task *dmatsk = NULL; /* Get ipb frequency */ - ipb_freq = mpc52xx_find_ipb_freq(op->node); + ipb_freq = mpc5xxx_get_bus_frequency(op->node); if (!ipb_freq) { dev_err(&op->dev, "could not determine IPB bus frequency\n"); return -ENODEV; diff --git a/drivers/ata/pata_palmld.c b/drivers/ata/pata_palmld.c new file mode 100644 index 000000000000..11fb4ccc74b4 --- /dev/null +++ b/drivers/ata/pata_palmld.c @@ -0,0 +1,150 @@ +/* + * drivers/ata/pata_palmld.c + * + * Driver for IDE channel in Palm LifeDrive + * + * Based on research of: + * Alex Osborne + * + * Rewrite for mainline: + * Marek Vasut + * + * Rewritten version based on pata_ixp4xx_cf.c: + * ixp4xx PATA/Compact Flash driver + * Copyright (C) 2006-07 Tower Technologies + * Author: Alessandro Zummo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define DRV_NAME "pata_palmld" + +static struct scsi_host_template palmld_sht = { + ATA_PIO_SHT(DRV_NAME), +}; + +static struct ata_port_operations palmld_port_ops = { + .inherits = &ata_sff_port_ops, + .sff_data_xfer = ata_sff_data_xfer_noirq, + .cable_detect = ata_cable_40wire, +}; + +static __devinit int palmld_pata_probe(struct platform_device *pdev) +{ + struct ata_host *host; + struct ata_port *ap; + void __iomem *mem; + int ret; + + /* allocate host */ + host = ata_host_alloc(&pdev->dev, 1); + if (!host) + return -ENOMEM; + + /* remap drive's physical memory address */ + mem = devm_ioremap(&pdev->dev, PALMLD_IDE_PHYS, 0x1000); + if (!mem) + return -ENOMEM; + + /* request and activate power GPIO, IRQ GPIO */ + ret = gpio_request(GPIO_NR_PALMLD_IDE_PWEN, "HDD PWR"); + if (ret) + goto err1; + ret = gpio_direction_output(GPIO_NR_PALMLD_IDE_PWEN, 1); + if (ret) + goto err2; + + ret = gpio_request(GPIO_NR_PALMLD_IDE_RESET, "HDD RST"); + if (ret) + goto err2; + ret = gpio_direction_output(GPIO_NR_PALMLD_IDE_RESET, 0); + if (ret) + goto err3; + + /* reset the drive */ + gpio_set_value(GPIO_NR_PALMLD_IDE_RESET, 0); + msleep(30); + gpio_set_value(GPIO_NR_PALMLD_IDE_RESET, 1); + msleep(30); + + /* setup the ata port */ + ap = host->ports[0]; + ap->ops = &palmld_port_ops; + ap->pio_mask = ATA_PIO4; + ap->flags |= ATA_FLAG_MMIO | ATA_FLAG_NO_LEGACY | ATA_FLAG_PIO_POLLING; + + /* memory mapping voodoo */ + ap->ioaddr.cmd_addr = mem + 0x10; + ap->ioaddr.altstatus_addr = mem + 0xe; + ap->ioaddr.ctl_addr = mem + 0xe; + + /* start the port */ + ata_sff_std_ports(&ap->ioaddr); + + /* activate host */ + return ata_host_activate(host, 0, NULL, IRQF_TRIGGER_RISING, + &palmld_sht); + +err3: + gpio_free(GPIO_NR_PALMLD_IDE_RESET); +err2: + gpio_free(GPIO_NR_PALMLD_IDE_PWEN); +err1: + return ret; +} + +static __devexit int palmld_pata_remove(struct platform_device *dev) +{ + struct ata_host *host = platform_get_drvdata(dev); + + ata_host_detach(host); + + /* power down the HDD */ + gpio_set_value(GPIO_NR_PALMLD_IDE_PWEN, 0); + + gpio_free(GPIO_NR_PALMLD_IDE_RESET); + gpio_free(GPIO_NR_PALMLD_IDE_PWEN); + + return 0; +} + +static struct platform_driver palmld_pata_platform_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, + .probe = palmld_pata_probe, + .remove = __devexit_p(palmld_pata_remove), +}; + +static int __init palmld_pata_init(void) +{ + return platform_driver_register(&palmld_pata_platform_driver); +} + +static void __exit palmld_pata_exit(void) +{ + platform_driver_unregister(&palmld_pata_platform_driver); +} + +MODULE_AUTHOR("Marek Vasut "); +MODULE_DESCRIPTION("PalmLD PATA driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" DRV_NAME); + +module_init(palmld_pata_init); +module_exit(palmld_pata_exit); diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c index 36b8629203be..94eaa432c40a 100644 --- a/drivers/ata/sata_fsl.c +++ b/drivers/ata/sata_fsl.c @@ -1378,6 +1378,37 @@ static int sata_fsl_remove(struct of_device *ofdev) return 0; } +#ifdef CONFIG_PM +static int sata_fsl_suspend(struct of_device *op, pm_message_t state) +{ + struct ata_host *host = dev_get_drvdata(&op->dev); + return ata_host_suspend(host, state); +} + +static int sata_fsl_resume(struct of_device *op) +{ + struct ata_host *host = dev_get_drvdata(&op->dev); + struct sata_fsl_host_priv *host_priv = host->private_data; + int ret; + void __iomem *hcr_base = host_priv->hcr_base; + struct ata_port *ap = host->ports[0]; + struct sata_fsl_port_priv *pp = ap->private_data; + + ret = sata_fsl_init_controller(host); + if (ret) { + dev_printk(KERN_ERR, &op->dev, + "Error initialize hardware\n"); + return ret; + } + + /* Recovery the CHBA register in host controller cmd register set */ + iowrite32(pp->cmdslot_paddr & 0xffffffff, hcr_base + CHBA); + + ata_host_resume(host); + return 0; +} +#endif + static struct of_device_id fsl_sata_match[] = { { .compatible = "fsl,pq-sata", @@ -1392,6 +1423,10 @@ static struct of_platform_driver fsl_sata_driver = { .match_table = fsl_sata_match, .probe = sata_fsl_probe, .remove = sata_fsl_remove, +#ifdef CONFIG_PM + .suspend = sata_fsl_suspend, + .resume = sata_fsl_resume, +#endif }; static int __init sata_fsl_init(void) diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index 6cda12ba8122..b2d11f300c39 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -305,8 +305,8 @@ static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance); static int nv_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val); static int nv_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val); -static int nv_noclassify_hardreset(struct ata_link *link, unsigned int *class, - unsigned long deadline); +static int nv_hardreset(struct ata_link *link, unsigned int *class, + unsigned long deadline); static void nv_nf2_freeze(struct ata_port *ap); static void nv_nf2_thaw(struct ata_port *ap); static void nv_ck804_freeze(struct ata_port *ap); @@ -406,49 +406,82 @@ static struct scsi_host_template nv_swncq_sht = { .slave_configure = nv_swncq_slave_config, }; -static struct ata_port_operations nv_common_ops = { +/* + * NV SATA controllers have various different problems with hardreset + * protocol depending on the specific controller and device. + * + * GENERIC: + * + * bko11195 reports that link doesn't come online after hardreset on + * generic nv's and there have been several other similar reports on + * linux-ide. + * + * bko12351#c23 reports that warmplug on MCP61 doesn't work with + * softreset. + * + * NF2/3: + * + * bko3352 reports nf2/3 controllers can't determine device signature + * reliably after hardreset. The following thread reports detection + * failure on cold boot with the standard debouncing timing. + * + * http://thread.gmane.org/gmane.linux.ide/34098 + * + * bko12176 reports that hardreset fails to bring up the link during + * boot on nf2. + * + * CK804: + * + * For initial probing after boot and hot plugging, hardreset mostly + * works fine on CK804 but curiously, reprobing on the initial port + * by rescanning or rmmod/insmod fails to acquire the initial D2H Reg + * FIS in somewhat undeterministic way. + * + * SWNCQ: + * + * bko12351 reports that when SWNCQ is enabled, for hotplug to work, + * hardreset should be used and hardreset can't report proper + * signature, which suggests that mcp5x is closer to nf2 as long as + * reset quirkiness is concerned. + * + * bko12703 reports that boot probing fails for intel SSD with + * hardreset. Link fails to come online. Softreset works fine. + * + * The failures are varied but the following patterns seem true for + * all flavors. + * + * - Softreset during boot always works. + * + * - Hardreset during boot sometimes fails to bring up the link on + * certain comibnations and device signature acquisition is + * unreliable. + * + * - Hardreset is often necessary after hotplug. + * + * So, preferring softreset for boot probing and error handling (as + * hardreset might bring down the link) but using hardreset for + * post-boot probing should work around the above issues in most + * cases. Define nv_hardreset() which only kicks in for post-boot + * probing and use it for all variants. + */ +static struct ata_port_operations nv_generic_ops = { .inherits = &ata_bmdma_port_ops, .lost_interrupt = ATA_OP_NULL, .scr_read = nv_scr_read, .scr_write = nv_scr_write, + .hardreset = nv_hardreset, }; -/* OSDL bz11195 reports that link doesn't come online after hardreset - * on generic nv's and there have been several other similar reports - * on linux-ide. Disable hardreset for generic nv's. - */ -static struct ata_port_operations nv_generic_ops = { - .inherits = &nv_common_ops, - .hardreset = ATA_OP_NULL, -}; - -/* nf2 is ripe with hardreset related problems. - * - * kernel bz#3352 reports nf2/3 controllers can't determine device - * signature reliably. The following thread reports detection failure - * on cold boot with the standard debouncing timing. - * - * http://thread.gmane.org/gmane.linux.ide/34098 - * - * And bz#12176 reports that hardreset simply doesn't work on nf2. - * Give up on it and just don't do hardreset. - */ static struct ata_port_operations nv_nf2_ops = { .inherits = &nv_generic_ops, .freeze = nv_nf2_freeze, .thaw = nv_nf2_thaw, }; -/* For initial probing after boot and hot plugging, hardreset mostly - * works fine on CK804 but curiously, reprobing on the initial port by - * rescanning or rmmod/insmod fails to acquire the initial D2H Reg FIS - * in somewhat undeterministic way. Use noclassify hardreset. - */ static struct ata_port_operations nv_ck804_ops = { - .inherits = &nv_common_ops, + .inherits = &nv_generic_ops, .freeze = nv_ck804_freeze, .thaw = nv_ck804_thaw, - .hardreset = nv_noclassify_hardreset, .host_stop = nv_ck804_host_stop, }; @@ -476,19 +509,8 @@ static struct ata_port_operations nv_adma_ops = { .host_stop = nv_adma_host_stop, }; -/* Kernel bz#12351 reports that when SWNCQ is enabled, for hotplug to - * work, hardreset should be used and hardreset can't report proper - * signature, which suggests that mcp5x is closer to nf2 as long as - * reset quirkiness is concerned. Define separate ops for mcp5x with - * nv_noclassify_hardreset(). - */ -static struct ata_port_operations nv_mcp5x_ops = { - .inherits = &nv_common_ops, - .hardreset = nv_noclassify_hardreset, -}; - static struct ata_port_operations nv_swncq_ops = { - .inherits = &nv_mcp5x_ops, + .inherits = &nv_generic_ops, .qc_defer = ata_std_qc_defer, .qc_prep = nv_swncq_qc_prep, @@ -557,7 +579,7 @@ static const struct ata_port_info nv_port_info[] = { .pio_mask = NV_PIO_MASK, .mwdma_mask = NV_MWDMA_MASK, .udma_mask = NV_UDMA_MASK, - .port_ops = &nv_mcp5x_ops, + .port_ops = &nv_generic_ops, .private_data = NV_PI_PRIV(nv_generic_interrupt, &nv_sht), }, /* SWNCQ */ @@ -1559,15 +1581,24 @@ static int nv_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val) return 0; } -static int nv_noclassify_hardreset(struct ata_link *link, unsigned int *class, - unsigned long deadline) +static int nv_hardreset(struct ata_link *link, unsigned int *class, + unsigned long deadline) { - bool online; - int rc; + struct ata_eh_context *ehc = &link->eh_context; - rc = sata_link_hardreset(link, sata_deb_timing_hotplug, deadline, - &online, NULL); - return online ? -EAGAIN : rc; + /* Do hardreset iff it's post-boot probing, please read the + * comment above port ops for details. + */ + if (!(link->ap->pflags & ATA_PFLAG_LOADING) && + !ata_dev_enabled(link->device)) + sata_link_hardreset(link, sata_deb_timing_hotplug, deadline, + NULL, NULL); + else if (!(ehc->i.flags & ATA_EHI_QUIET)) + ata_link_printk(link, KERN_INFO, + "nv: skipping hardreset on occupied port\n"); + + /* device signature acquisition is unreliable */ + return -EAGAIN; } static void nv_nf2_freeze(struct ata_port *ap) diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index e67ce8e5caa5..030ec079b184 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c @@ -183,7 +183,7 @@ static struct scsi_host_template sil_sht = { }; static struct ata_port_operations sil_ops = { - .inherits = &ata_bmdma_port_ops, + .inherits = &ata_bmdma32_port_ops, .dev_config = sil_dev_config, .set_mode = sil_set_mode, .bmdma_setup = sil_bmdma_setup, diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c index eb05a3c82a9e..bbcf970068ad 100644 --- a/drivers/ata/sata_sx4.c +++ b/drivers/ata/sata_sx4.c @@ -193,6 +193,7 @@ enum { PDC_TIMER_MASK_INT, }; +#define ECC_ERASE_BUF_SZ (128 * 1024) struct pdc_port_priv { u8 dimm_buf[(ATA_PRD_SZ * ATA_MAX_PRD) + 512]; @@ -1280,7 +1281,6 @@ static unsigned int pdc20621_dimm_init(struct ata_host *host) { int speed, size, length; u32 addr, spd0, pci_status; - u32 tmp = 0; u32 time_period = 0; u32 tcount = 0; u32 ticks = 0; @@ -1395,14 +1395,17 @@ static unsigned int pdc20621_dimm_init(struct ata_host *host) pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS, PDC_DIMM_SPD_TYPE, &spd0); if (spd0 == 0x02) { + void *buf; VPRINTK("Start ECC initialization\n"); addr = 0; length = size * 1024 * 1024; + buf = kzalloc(ECC_ERASE_BUF_SZ, GFP_KERNEL); while (addr < length) { - pdc20621_put_to_dimm(host, (void *) &tmp, addr, - sizeof(u32)); - addr += sizeof(u32); + pdc20621_put_to_dimm(host, buf, addr, + ECC_ERASE_BUF_SZ); + addr += ECC_ERASE_BUF_SZ; } + kfree(buf); VPRINTK("Finish ECC initialization\n"); } return 0; diff --git a/drivers/base/bus.c b/drivers/base/bus.c index c6599618523e..4b04a15146d7 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -279,7 +279,7 @@ static struct device *next_device(struct klist_iter *i) * * NOTE: The device that returns a non-zero value is not retained * in any way, nor is its refcount incremented. If the caller needs - * to retain this data, it should do, and increment the reference + * to retain this data, it should do so, and increment the reference * count in the supplied callback. */ int bus_for_each_dev(struct bus_type *bus, struct device *start, diff --git a/drivers/base/core.c b/drivers/base/core.c index 1977d4beb89e..7ecb1938e590 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "base.h" #include "power/power.h" @@ -161,10 +162,18 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, struct device *dev = to_dev(kobj); int retval = 0; - /* add the major/minor if present */ + /* add device node properties if present */ if (MAJOR(dev->devt)) { + const char *tmp; + const char *name; + add_uevent_var(env, "MAJOR=%u", MAJOR(dev->devt)); add_uevent_var(env, "MINOR=%u", MINOR(dev->devt)); + name = device_get_nodename(dev, &tmp); + if (name) { + add_uevent_var(env, "DEVNAME=%s", name); + kfree(tmp); + } } if (dev->type && dev->type->name) @@ -874,7 +883,7 @@ int device_add(struct device *dev) * the name, and force the use of dev_name() */ if (dev->init_name) { - dev_set_name(dev, dev->init_name); + dev_set_name(dev, "%s", dev->init_name); dev->init_name = NULL; } @@ -1127,6 +1136,47 @@ static struct device *next_device(struct klist_iter *i) return dev; } +/** + * device_get_nodename - path of device node file + * @dev: device + * @tmp: possibly allocated string + * + * Return the relative path of a possible device node. + * Non-default names may need to allocate a memory to compose + * a name. This memory is returned in tmp and needs to be + * freed by the caller. + */ +const char *device_get_nodename(struct device *dev, const char **tmp) +{ + char *s; + + *tmp = NULL; + + /* the device type may provide a specific name */ + if (dev->type && dev->type->nodename) + *tmp = dev->type->nodename(dev); + if (*tmp) + return *tmp; + + /* the class may provide a specific name */ + if (dev->class && dev->class->nodename) + *tmp = dev->class->nodename(dev); + if (*tmp) + return *tmp; + + /* return name without allocation, tmp == NULL */ + if (strchr(dev_name(dev), '!') == NULL) + return dev_name(dev); + + /* replace '!' in the name with '/' */ + *tmp = kstrdup(dev_name(dev), GFP_KERNEL); + if (!*tmp) + return NULL; + while ((s = strchr(*tmp, '!'))) + s[0] = '/'; + return *tmp; +} + /** * device_for_each_child - device child iterator. * @parent: parent struct device. @@ -1271,7 +1321,7 @@ struct device *__root_device_register(const char *name, struct module *owner) if (!root) return ERR_PTR(err); - err = dev_set_name(&root->dev, name); + err = dev_set_name(&root->dev, "%s", name); if (err) { kfree(root); return ERR_PTR(err); @@ -1665,4 +1715,5 @@ void device_shutdown(void) kobject_put(sysfs_dev_char_kobj); kobject_put(sysfs_dev_block_kobj); kobject_put(dev_kobj); + async_synchronize_full(); } diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 742cbe6b042b..f0106875f01d 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -226,7 +226,7 @@ static int __device_attach(struct device_driver *drv, void *data) * pair is found, break out and return. * * Returns 1 if the device was bound to a driver; - * 0 if no matching device was found; + * 0 if no matching driver was found; * -ENODEV if the device is not registered. * * When called for a USB interface, @dev->parent->sem must be held. @@ -320,6 +320,10 @@ static void __device_release_driver(struct device *dev) devres_release_all(dev); dev->driver = NULL; klist_remove(&dev->p->knode_driver); + if (dev->bus) + blocking_notifier_call_chain(&dev->bus->p->bus_notifier, + BUS_NOTIFY_UNBOUND_DRIVER, + dev); } } diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index d3a59c688fe4..ddeb819c8f87 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -17,7 +17,7 @@ #include #include #include - +#include #include #include "base.h" @@ -40,12 +40,15 @@ static int loading_timeout = 60; /* In seconds */ static DEFINE_MUTEX(fw_lock); struct firmware_priv { - char fw_id[FIRMWARE_NAME_MAX]; + char *fw_id; struct completion completion; struct bin_attribute attr_data; struct firmware *fw; unsigned long status; - int alloc_size; + struct page **pages; + int nr_pages; + int page_array_size; + const char *vdata; struct timer_list timeout; }; @@ -122,6 +125,10 @@ static ssize_t firmware_loading_show(struct device *dev, return sprintf(buf, "%d\n", loading); } +/* Some architectures don't have PAGE_KERNEL_RO */ +#ifndef PAGE_KERNEL_RO +#define PAGE_KERNEL_RO PAGE_KERNEL +#endif /** * firmware_loading_store - set value in the 'loading' control file * @dev: device pointer @@ -141,6 +148,7 @@ static ssize_t firmware_loading_store(struct device *dev, { struct firmware_priv *fw_priv = dev_get_drvdata(dev); int loading = simple_strtol(buf, NULL, 10); + int i; switch (loading) { case 1: @@ -151,13 +159,30 @@ static ssize_t firmware_loading_store(struct device *dev, } vfree(fw_priv->fw->data); fw_priv->fw->data = NULL; + for (i = 0; i < fw_priv->nr_pages; i++) + __free_page(fw_priv->pages[i]); + kfree(fw_priv->pages); + fw_priv->pages = NULL; + fw_priv->page_array_size = 0; + fw_priv->nr_pages = 0; fw_priv->fw->size = 0; - fw_priv->alloc_size = 0; set_bit(FW_STATUS_LOADING, &fw_priv->status); mutex_unlock(&fw_lock); break; case 0: if (test_bit(FW_STATUS_LOADING, &fw_priv->status)) { + vfree(fw_priv->fw->data); + fw_priv->fw->data = vmap(fw_priv->pages, + fw_priv->nr_pages, + 0, PAGE_KERNEL_RO); + if (!fw_priv->fw->data) { + dev_err(dev, "%s: vmap() failed\n", __func__); + goto err; + } + /* Pages will be freed by vfree() */ + fw_priv->pages = NULL; + fw_priv->page_array_size = 0; + fw_priv->nr_pages = 0; complete(&fw_priv->completion); clear_bit(FW_STATUS_LOADING, &fw_priv->status); break; @@ -167,6 +192,7 @@ static ssize_t firmware_loading_store(struct device *dev, dev_err(dev, "%s: unexpected value (%d)\n", __func__, loading); /* fallthrough */ case -1: + err: fw_load_abort(fw_priv); break; } @@ -191,8 +217,28 @@ firmware_data_read(struct kobject *kobj, struct bin_attribute *bin_attr, ret_count = -ENODEV; goto out; } - ret_count = memory_read_from_buffer(buffer, count, &offset, - fw->data, fw->size); + if (offset > fw->size) + return 0; + if (count > fw->size - offset) + count = fw->size - offset; + + ret_count = count; + + while (count) { + void *page_data; + int page_nr = offset >> PAGE_SHIFT; + int page_ofs = offset & (PAGE_SIZE-1); + int page_cnt = min_t(size_t, PAGE_SIZE - page_ofs, count); + + page_data = kmap(fw_priv->pages[page_nr]); + + memcpy(buffer, page_data + page_ofs, page_cnt); + + kunmap(fw_priv->pages[page_nr]); + buffer += page_cnt; + offset += page_cnt; + count -= page_cnt; + } out: mutex_unlock(&fw_lock); return ret_count; @@ -201,27 +247,39 @@ out: static int fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size) { - u8 *new_data; - int new_size = fw_priv->alloc_size; + int pages_needed = ALIGN(min_size, PAGE_SIZE) >> PAGE_SHIFT; - if (min_size <= fw_priv->alloc_size) - return 0; + /* If the array of pages is too small, grow it... */ + if (fw_priv->page_array_size < pages_needed) { + int new_array_size = max(pages_needed, + fw_priv->page_array_size * 2); + struct page **new_pages; - new_size = ALIGN(min_size, PAGE_SIZE); - new_data = vmalloc(new_size); - if (!new_data) { - printk(KERN_ERR "%s: unable to alloc buffer\n", __func__); - /* Make sure that we don't keep incomplete data */ - fw_load_abort(fw_priv); - return -ENOMEM; + new_pages = kmalloc(new_array_size * sizeof(void *), + GFP_KERNEL); + if (!new_pages) { + fw_load_abort(fw_priv); + return -ENOMEM; + } + memcpy(new_pages, fw_priv->pages, + fw_priv->page_array_size * sizeof(void *)); + memset(&new_pages[fw_priv->page_array_size], 0, sizeof(void *) * + (new_array_size - fw_priv->page_array_size)); + kfree(fw_priv->pages); + fw_priv->pages = new_pages; + fw_priv->page_array_size = new_array_size; } - fw_priv->alloc_size = new_size; - if (fw_priv->fw->data) { - memcpy(new_data, fw_priv->fw->data, fw_priv->fw->size); - vfree(fw_priv->fw->data); + + while (fw_priv->nr_pages < pages_needed) { + fw_priv->pages[fw_priv->nr_pages] = + alloc_page(GFP_KERNEL | __GFP_HIGHMEM); + + if (!fw_priv->pages[fw_priv->nr_pages]) { + fw_load_abort(fw_priv); + return -ENOMEM; + } + fw_priv->nr_pages++; } - fw_priv->fw->data = new_data; - BUG_ON(min_size > fw_priv->alloc_size); return 0; } @@ -258,10 +316,25 @@ firmware_data_write(struct kobject *kobj, struct bin_attribute *bin_attr, if (retval) goto out; - memcpy((u8 *)fw->data + offset, buffer, count); - - fw->size = max_t(size_t, offset + count, fw->size); retval = count; + + while (count) { + void *page_data; + int page_nr = offset >> PAGE_SHIFT; + int page_ofs = offset & (PAGE_SIZE - 1); + int page_cnt = min_t(size_t, PAGE_SIZE - page_ofs, count); + + page_data = kmap(fw_priv->pages[page_nr]); + + memcpy(page_data + page_ofs, buffer, page_cnt); + + kunmap(fw_priv->pages[page_nr]); + buffer += page_cnt; + offset += page_cnt; + count -= page_cnt; + } + + fw->size = max_t(size_t, offset, fw->size); out: mutex_unlock(&fw_lock); return retval; @@ -277,9 +350,14 @@ static struct bin_attribute firmware_attr_data_tmpl = { static void fw_dev_release(struct device *dev) { struct firmware_priv *fw_priv = dev_get_drvdata(dev); + int i; + for (i = 0; i < fw_priv->nr_pages; i++) + __free_page(fw_priv->pages[i]); + kfree(fw_priv->pages); + kfree(fw_priv->fw_id); kfree(fw_priv); - kfree(dev); + put_device(dev); module_put(THIS_MODULE); } @@ -309,13 +387,19 @@ static int fw_register_device(struct device **dev_p, const char *fw_name, init_completion(&fw_priv->completion); fw_priv->attr_data = firmware_attr_data_tmpl; - strlcpy(fw_priv->fw_id, fw_name, FIRMWARE_NAME_MAX); + fw_priv->fw_id = kstrdup(fw_name, GFP_KERNEL); + if (!fw_priv->fw_id) { + dev_err(device, "%s: Firmware name allocation failed\n", + __func__); + retval = -ENOMEM; + goto error_kfree; + } fw_priv->timeout.function = firmware_class_timeout; fw_priv->timeout.data = (u_long) fw_priv; init_timer(&fw_priv->timeout); - dev_set_name(f_dev, dev_name(device)); + dev_set_name(f_dev, "%s", dev_name(device)); f_dev->parent = device; f_dev->class = &firmware_class; dev_set_drvdata(f_dev, fw_priv); @@ -323,14 +407,17 @@ static int fw_register_device(struct device **dev_p, const char *fw_name, retval = device_register(f_dev); if (retval) { dev_err(device, "%s: device_register failed\n", __func__); - goto error_kfree; + put_device(f_dev); + goto error_kfree_fw_id; } *dev_p = f_dev; return 0; +error_kfree_fw_id: + kfree(fw_priv->fw_id); error_kfree: - kfree(fw_priv); kfree(f_dev); + kfree(fw_priv); return retval; } @@ -538,8 +625,9 @@ request_firmware_work_func(void *arg) * @cont: function will be called asynchronously when the firmware * request is over. * - * Asynchronous variant of request_firmware() for contexts where - * it is not possible to sleep. + * Asynchronous variant of request_firmware() for user contexts where + * it is not possible to sleep for long time. It can't be called + * in atomic contexts. **/ int request_firmware_nowait( diff --git a/drivers/base/node.c b/drivers/base/node.c index 40b809742a1c..91d4087b4039 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c @@ -72,10 +72,8 @@ static ssize_t node_read_meminfo(struct sys_device * dev, "Node %d Inactive(anon): %8lu kB\n" "Node %d Active(file): %8lu kB\n" "Node %d Inactive(file): %8lu kB\n" -#ifdef CONFIG_UNEVICTABLE_LRU "Node %d Unevictable: %8lu kB\n" "Node %d Mlocked: %8lu kB\n" -#endif #ifdef CONFIG_HIGHMEM "Node %d HighTotal: %8lu kB\n" "Node %d HighFree: %8lu kB\n" @@ -105,10 +103,8 @@ static ssize_t node_read_meminfo(struct sys_device * dev, nid, K(node_page_state(nid, NR_INACTIVE_ANON)), nid, K(node_page_state(nid, NR_ACTIVE_FILE)), nid, K(node_page_state(nid, NR_INACTIVE_FILE)), -#ifdef CONFIG_UNEVICTABLE_LRU nid, K(node_page_state(nid, NR_UNEVICTABLE)), nid, K(node_page_state(nid, NR_MLOCK)), -#endif #ifdef CONFIG_HIGHMEM nid, K(i.totalhigh), nid, K(i.freehigh), diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 8b4708e06244..81cb01bfc356 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -69,7 +69,8 @@ EXPORT_SYMBOL_GPL(platform_get_irq); * @name: resource name */ struct resource *platform_get_resource_byname(struct platform_device *dev, - unsigned int type, char *name) + unsigned int type, + const char *name) { int i; @@ -88,7 +89,7 @@ EXPORT_SYMBOL_GPL(platform_get_resource_byname); * @dev: platform device * @name: IRQ name */ -int platform_get_irq_byname(struct platform_device *dev, char *name) +int platform_get_irq_byname(struct platform_device *dev, const char *name) { struct resource *r = platform_get_resource_byname(dev, IORESOURCE_IRQ, name); @@ -244,7 +245,7 @@ int platform_device_add(struct platform_device *pdev) if (pdev->id != -1) dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id); else - dev_set_name(&pdev->dev, pdev->name); + dev_set_name(&pdev->dev, "%s", pdev->name); for (i = 0; i < pdev->num_resources; i++) { struct resource *p, *r = &pdev->resource[i]; @@ -469,22 +470,6 @@ static void platform_drv_shutdown(struct device *_dev) drv->shutdown(dev); } -static int platform_drv_suspend(struct device *_dev, pm_message_t state) -{ - struct platform_driver *drv = to_platform_driver(_dev->driver); - struct platform_device *dev = to_platform_device(_dev); - - return drv->suspend(dev, state); -} - -static int platform_drv_resume(struct device *_dev) -{ - struct platform_driver *drv = to_platform_driver(_dev->driver); - struct platform_device *dev = to_platform_device(_dev); - - return drv->resume(dev); -} - /** * platform_driver_register * @drv: platform driver structure @@ -498,10 +483,10 @@ int platform_driver_register(struct platform_driver *drv) drv->driver.remove = platform_drv_remove; if (drv->shutdown) drv->driver.shutdown = platform_drv_shutdown; - if (drv->suspend) - drv->driver.suspend = platform_drv_suspend; - if (drv->resume) - drv->driver.resume = platform_drv_resume; + if (drv->suspend || drv->resume) + pr_warning("Platform driver '%s' needs updating - please use " + "dev_pm_ops\n", drv->driver.name); + return driver_register(&drv->driver); } EXPORT_SYMBOL_GPL(platform_driver_register); @@ -633,10 +618,12 @@ static int platform_match(struct device *dev, struct device_driver *drv) static int platform_legacy_suspend(struct device *dev, pm_message_t mesg) { + struct platform_driver *pdrv = to_platform_driver(dev->driver); + struct platform_device *pdev = to_platform_device(dev); int ret = 0; - if (dev->driver && dev->driver->suspend) - ret = dev->driver->suspend(dev, mesg); + if (dev->driver && pdrv->suspend) + ret = pdrv->suspend(pdev, mesg); return ret; } @@ -667,10 +654,12 @@ static int platform_legacy_resume_early(struct device *dev) static int platform_legacy_resume(struct device *dev) { + struct platform_driver *pdrv = to_platform_driver(dev->driver); + struct platform_device *pdev = to_platform_device(dev); int ret = 0; - if (dev->driver && dev->driver->resume) - ret = dev->driver->resume(dev); + if (dev->driver && pdrv->resume) + ret = pdrv->resume(pdev); return ret; } diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 3e4bc699bc0f..fae725458981 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -315,13 +315,13 @@ static void pm_dev_err(struct device *dev, pm_message_t state, char *info, /*------------------------- Resume routines -------------------------*/ /** - * resume_device_noirq - Power on one device (early resume). + * device_resume_noirq - Power on one device (early resume). * @dev: Device. * @state: PM transition of the system being carried out. * * Must be called with interrupts disabled. */ -static int resume_device_noirq(struct device *dev, pm_message_t state) +static int device_resume_noirq(struct device *dev, pm_message_t state) { int error = 0; @@ -334,9 +334,6 @@ static int resume_device_noirq(struct device *dev, pm_message_t state) if (dev->bus->pm) { pm_dev_dbg(dev, state, "EARLY "); error = pm_noirq_op(dev, dev->bus->pm, state); - } else if (dev->bus->resume_early) { - pm_dev_dbg(dev, state, "legacy EARLY "); - error = dev->bus->resume_early(dev); } End: TRACE_RESUME(error); @@ -344,16 +341,16 @@ static int resume_device_noirq(struct device *dev, pm_message_t state) } /** - * dpm_power_up - Power on all regular (non-sysdev) devices. + * dpm_resume_noirq - Power on all regular (non-sysdev) devices. * @state: PM transition of the system being carried out. * - * Execute the appropriate "noirq resume" callback for all devices marked - * as DPM_OFF_IRQ. + * Call the "noirq" resume handlers for all devices marked as + * DPM_OFF_IRQ and enable device drivers to receive interrupts. * * Must be called under dpm_list_mtx. Device drivers should not receive * interrupts while it's being executed. */ -static void dpm_power_up(pm_message_t state) +void dpm_resume_noirq(pm_message_t state) { struct device *dev; @@ -363,33 +360,21 @@ static void dpm_power_up(pm_message_t state) int error; dev->power.status = DPM_OFF; - error = resume_device_noirq(dev, state); + error = device_resume_noirq(dev, state); if (error) pm_dev_err(dev, state, " early", error); } mutex_unlock(&dpm_list_mtx); -} - -/** - * device_power_up - Turn on all devices that need special attention. - * @state: PM transition of the system being carried out. - * - * Call the "early" resume handlers and enable device drivers to receive - * interrupts. - */ -void device_power_up(pm_message_t state) -{ - dpm_power_up(state); resume_device_irqs(); } -EXPORT_SYMBOL_GPL(device_power_up); +EXPORT_SYMBOL_GPL(dpm_resume_noirq); /** - * resume_device - Restore state for one device. + * device_resume - Restore state for one device. * @dev: Device. * @state: PM transition of the system being carried out. */ -static int resume_device(struct device *dev, pm_message_t state) +static int device_resume(struct device *dev, pm_message_t state) { int error = 0; @@ -414,9 +399,6 @@ static int resume_device(struct device *dev, pm_message_t state) if (dev->type->pm) { pm_dev_dbg(dev, state, "type "); error = pm_op(dev, dev->type->pm, state); - } else if (dev->type->resume) { - pm_dev_dbg(dev, state, "legacy type "); - error = dev->type->resume(dev); } if (error) goto End; @@ -462,7 +444,7 @@ static void dpm_resume(pm_message_t state) dev->power.status = DPM_RESUMING; mutex_unlock(&dpm_list_mtx); - error = resume_device(dev, state); + error = device_resume(dev, state); mutex_lock(&dpm_list_mtx); if (error) @@ -480,11 +462,11 @@ static void dpm_resume(pm_message_t state) } /** - * complete_device - Complete a PM transition for given device + * device_complete - Complete a PM transition for given device * @dev: Device. * @state: PM transition of the system being carried out. */ -static void complete_device(struct device *dev, pm_message_t state) +static void device_complete(struct device *dev, pm_message_t state) { down(&dev->sem); @@ -527,7 +509,7 @@ static void dpm_complete(pm_message_t state) dev->power.status = DPM_ON; mutex_unlock(&dpm_list_mtx); - complete_device(dev, state); + device_complete(dev, state); mutex_lock(&dpm_list_mtx); } @@ -540,19 +522,19 @@ static void dpm_complete(pm_message_t state) } /** - * device_resume - Restore state of each device in system. + * dpm_resume_end - Restore state of each device in system. * @state: PM transition of the system being carried out. * * Resume all the devices, unlock them all, and allow new * devices to be registered once again. */ -void device_resume(pm_message_t state) +void dpm_resume_end(pm_message_t state) { might_sleep(); dpm_resume(state); dpm_complete(state); } -EXPORT_SYMBOL_GPL(device_resume); +EXPORT_SYMBOL_GPL(dpm_resume_end); /*------------------------- Suspend routines -------------------------*/ @@ -577,13 +559,13 @@ static pm_message_t resume_event(pm_message_t sleep_state) } /** - * suspend_device_noirq - Shut down one device (late suspend). + * device_suspend_noirq - Shut down one device (late suspend). * @dev: Device. * @state: PM transition of the system being carried out. * * This is called with interrupts off and only a single CPU running. */ -static int suspend_device_noirq(struct device *dev, pm_message_t state) +static int device_suspend_noirq(struct device *dev, pm_message_t state) { int error = 0; @@ -593,24 +575,20 @@ static int suspend_device_noirq(struct device *dev, pm_message_t state) if (dev->bus->pm) { pm_dev_dbg(dev, state, "LATE "); error = pm_noirq_op(dev, dev->bus->pm, state); - } else if (dev->bus->suspend_late) { - pm_dev_dbg(dev, state, "legacy LATE "); - error = dev->bus->suspend_late(dev, state); - suspend_report_result(dev->bus->suspend_late, error); } return error; } /** - * device_power_down - Shut down special devices. + * dpm_suspend_noirq - Power down all regular (non-sysdev) devices. * @state: PM transition of the system being carried out. * - * Prevent device drivers from receiving interrupts and call the "late" + * Prevent device drivers from receiving interrupts and call the "noirq" * suspend handlers. * * Must be called under dpm_list_mtx. */ -int device_power_down(pm_message_t state) +int dpm_suspend_noirq(pm_message_t state) { struct device *dev; int error = 0; @@ -618,7 +596,7 @@ int device_power_down(pm_message_t state) suspend_device_irqs(); mutex_lock(&dpm_list_mtx); list_for_each_entry_reverse(dev, &dpm_list, power.entry) { - error = suspend_device_noirq(dev, state); + error = device_suspend_noirq(dev, state); if (error) { pm_dev_err(dev, state, " late", error); break; @@ -627,17 +605,17 @@ int device_power_down(pm_message_t state) } mutex_unlock(&dpm_list_mtx); if (error) - device_power_up(resume_event(state)); + dpm_resume_noirq(resume_event(state)); return error; } -EXPORT_SYMBOL_GPL(device_power_down); +EXPORT_SYMBOL_GPL(dpm_suspend_noirq); /** - * suspend_device - Save state of one device. + * device_suspend - Save state of one device. * @dev: Device. * @state: PM transition of the system being carried out. */ -static int suspend_device(struct device *dev, pm_message_t state) +static int device_suspend(struct device *dev, pm_message_t state) { int error = 0; @@ -660,10 +638,6 @@ static int suspend_device(struct device *dev, pm_message_t state) if (dev->type->pm) { pm_dev_dbg(dev, state, "type "); error = pm_op(dev, dev->type->pm, state); - } else if (dev->type->suspend) { - pm_dev_dbg(dev, state, "legacy type "); - error = dev->type->suspend(dev, state); - suspend_report_result(dev->type->suspend, error); } if (error) goto End; @@ -704,7 +678,7 @@ static int dpm_suspend(pm_message_t state) get_device(dev); mutex_unlock(&dpm_list_mtx); - error = suspend_device(dev, state); + error = device_suspend(dev, state); mutex_lock(&dpm_list_mtx); if (error) { @@ -723,11 +697,11 @@ static int dpm_suspend(pm_message_t state) } /** - * prepare_device - Execute the ->prepare() callback(s) for given device. + * device_prepare - Execute the ->prepare() callback(s) for given device. * @dev: Device. * @state: PM transition of the system being carried out. */ -static int prepare_device(struct device *dev, pm_message_t state) +static int device_prepare(struct device *dev, pm_message_t state) { int error = 0; @@ -781,7 +755,7 @@ static int dpm_prepare(pm_message_t state) dev->power.status = DPM_PREPARING; mutex_unlock(&dpm_list_mtx); - error = prepare_device(dev, state); + error = device_prepare(dev, state); mutex_lock(&dpm_list_mtx); if (error) { @@ -807,12 +781,12 @@ static int dpm_prepare(pm_message_t state) } /** - * device_suspend - Save state and stop all devices in system. + * dpm_suspend_start - Save state and stop all devices in system. * @state: PM transition of the system being carried out. * * Prepare and suspend all devices. */ -int device_suspend(pm_message_t state) +int dpm_suspend_start(pm_message_t state) { int error; @@ -822,7 +796,7 @@ int device_suspend(pm_message_t state) error = dpm_suspend(state); return error; } -EXPORT_SYMBOL_GPL(device_suspend); +EXPORT_SYMBOL_GPL(dpm_suspend_start); void __suspend_report_result(const char *function, void *fn, int ret) { diff --git a/drivers/base/sys.c b/drivers/base/sys.c index 3236b434b964..79a9ae5238ac 100644 --- a/drivers/base/sys.c +++ b/drivers/base/sys.c @@ -131,6 +131,8 @@ static struct kset *system_kset; int sysdev_class_register(struct sysdev_class *cls) { + int retval; + pr_debug("Registering sysdev class '%s'\n", cls->name); INIT_LIST_HEAD(&cls->drivers); @@ -138,7 +140,11 @@ int sysdev_class_register(struct sysdev_class *cls) cls->kset.kobj.parent = &system_kset->kobj; cls->kset.kobj.ktype = &ktype_sysdev_class; cls->kset.kobj.kset = system_kset; - kobject_set_name(&cls->kset.kobj, cls->name); + + retval = kobject_set_name(&cls->kset.kobj, "%s", cls->name); + if (retval) + return retval; + return kset_register(&cls->kset); } @@ -343,11 +349,15 @@ static void __sysdev_resume(struct sys_device *dev) /* First, call the class-specific one */ if (cls->resume) cls->resume(dev); + WARN_ONCE(!irqs_disabled(), + "Interrupts enabled after %pF\n", cls->resume); /* Call auxillary drivers next. */ list_for_each_entry(drv, &cls->drivers, entry) { if (drv->resume) drv->resume(dev); + WARN_ONCE(!irqs_disabled(), + "Interrupts enabled after %pF\n", drv->resume); } } @@ -377,6 +387,9 @@ int sysdev_suspend(pm_message_t state) if (ret) return ret; + WARN_ONCE(!irqs_disabled(), + "Interrupts enabled while suspending system devices\n"); + pr_debug("Suspending System Devices\n"); list_for_each_entry_reverse(cls, &system_kset->list, kset.kobj.entry) { @@ -393,6 +406,9 @@ int sysdev_suspend(pm_message_t state) if (ret) goto aux_driver; } + WARN_ONCE(!irqs_disabled(), + "Interrupts enabled after %pF\n", + drv->suspend); } /* Now call the generic one */ @@ -400,6 +416,9 @@ int sysdev_suspend(pm_message_t state) ret = cls->suspend(sysdev, state); if (ret) goto cls_driver; + WARN_ONCE(!irqs_disabled(), + "Interrupts enabled after %pF\n", + cls->suspend); } } } @@ -452,6 +471,9 @@ int sysdev_resume(void) { struct sysdev_class *cls; + WARN_ONCE(!irqs_disabled(), + "Interrupts enabled while resuming system devices\n"); + pr_debug("Resuming System Devices\n"); list_for_each_entry(cls, &system_kset->list, kset.kobj.entry) { diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c index f22ed6cc69f2..668dc234b8e2 100644 --- a/drivers/block/DAC960.c +++ b/drivers/block/DAC960.c @@ -3321,7 +3321,7 @@ static int DAC960_process_queue(DAC960_Controller_T *Controller, struct request_ DAC960_Command_T *Command; while(1) { - Request = elv_next_request(req_q); + Request = blk_peek_request(req_q); if (!Request) return 1; @@ -3338,10 +3338,10 @@ static int DAC960_process_queue(DAC960_Controller_T *Controller, struct request_ } Command->Completion = Request->end_io_data; Command->LogicalDriveNumber = (long)Request->rq_disk->private_data; - Command->BlockNumber = Request->sector; - Command->BlockCount = Request->nr_sectors; + Command->BlockNumber = blk_rq_pos(Request); + Command->BlockCount = blk_rq_sectors(Request); Command->Request = Request; - blkdev_dequeue_request(Request); + blk_start_request(Request); Command->SegmentCount = blk_rq_map_sg(req_q, Command->Request, Command->cmd_sglist); /* pci_map_sg MAY change the value of SegCount */ @@ -3431,7 +3431,7 @@ static void DAC960_queue_partial_rw(DAC960_Command_T *Command) * successfully as possible. */ Command->SegmentCount = 1; - Command->BlockNumber = Request->sector; + Command->BlockNumber = blk_rq_pos(Request); Command->BlockCount = 1; DAC960_QueueReadWriteCommand(Command); return; diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index ddea8e485cc9..bb72ada9f074 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -112,7 +112,7 @@ config GDROM with up to 1 GB of data. This drive will also read standard CD ROM disks. Select this option to access any disks in your GD ROM drive. Most users will want to say "Y" here. - You can also build this as a module which will be called gdrom.ko + You can also build this as a module which will be called gdrom. source "drivers/block/paride/Kconfig" @@ -412,7 +412,7 @@ config ATA_OVER_ETH config MG_DISK tristate "mGine mflash, gflash support" - depends on ARM && ATA && GPIOLIB + depends on ARM && GPIOLIB help mGine mFlash(gFlash) block device driver @@ -438,7 +438,7 @@ source "drivers/s390/block/Kconfig" config XILINX_SYSACE tristate "Xilinx SystemACE support" - depends on 4xx + depends on 4xx || MICROBLAZE help Include support for the Xilinx SystemACE CompactFlash interface diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c index 8df436ff7068..9c6e5b0fe894 100644 --- a/drivers/block/amiflop.c +++ b/drivers/block/amiflop.c @@ -112,8 +112,6 @@ module_param(fd_def_df0, ulong, 0); MODULE_LICENSE("GPL"); static struct request_queue *floppy_queue; -#define QUEUE (floppy_queue) -#define CURRENT elv_next_request(floppy_queue) /* * Macros @@ -1335,64 +1333,60 @@ static int get_track(int drive, int track) static void redo_fd_request(void) { + struct request *rq; unsigned int cnt, block, track, sector; int drive; struct amiga_floppy_struct *floppy; char *data; unsigned long flags; + int err; - repeat: - if (!CURRENT) { +next_req: + rq = blk_fetch_request(floppy_queue); + if (!rq) { /* Nothing left to do */ return; } - floppy = CURRENT->rq_disk->private_data; + floppy = rq->rq_disk->private_data; drive = floppy - unit; +next_segment: /* Here someone could investigate to be more efficient */ - for (cnt = 0; cnt < CURRENT->current_nr_sectors; cnt++) { + for (cnt = 0, err = 0; cnt < blk_rq_cur_sectors(rq); cnt++) { #ifdef DEBUG printk("fd: sector %ld + %d requested for %s\n", - CURRENT->sector,cnt, - (rq_data_dir(CURRENT) == READ) ? "read" : "write"); + blk_rq_pos(rq), cnt, + (rq_data_dir(rq) == READ) ? "read" : "write"); #endif - block = CURRENT->sector + cnt; + block = blk_rq_pos(rq) + cnt; if ((int)block > floppy->blocks) { - end_request(CURRENT, 0); - goto repeat; + err = -EIO; + break; } track = block / (floppy->dtype->sects * floppy->type->sect_mult); sector = block % (floppy->dtype->sects * floppy->type->sect_mult); - data = CURRENT->buffer + 512 * cnt; + data = rq->buffer + 512 * cnt; #ifdef DEBUG printk("access to track %d, sector %d, with buffer at " "0x%08lx\n", track, sector, data); #endif - if ((rq_data_dir(CURRENT) != READ) && (rq_data_dir(CURRENT) != WRITE)) { - printk(KERN_WARNING "do_fd_request: unknown command\n"); - end_request(CURRENT, 0); - goto repeat; - } if (get_track(drive, track) == -1) { - end_request(CURRENT, 0); - goto repeat; + err = -EIO; + break; } - switch (rq_data_dir(CURRENT)) { - case READ: + if (rq_data_dir(rq) == READ) { memcpy(data, floppy->trackbuf + sector * 512, 512); - break; - - case WRITE: + } else { memcpy(floppy->trackbuf + sector * 512, data, 512); /* keep the drive spinning while writes are scheduled */ if (!fd_motor_on(drive)) { - end_request(CURRENT, 0); - goto repeat; + err = -EIO; + break; } /* * setup a callback to write the track buffer @@ -1404,14 +1398,12 @@ static void redo_fd_request(void) /* reset the timer */ mod_timer (flush_track_timer + drive, jiffies + 1); local_irq_restore(flags); - break; } } - CURRENT->nr_sectors -= CURRENT->current_nr_sectors; - CURRENT->sector += CURRENT->current_nr_sectors; - end_request(CURRENT, 1); - goto repeat; + if (__blk_end_request_cur(rq, err)) + goto next_segment; + goto next_req; } static void do_fd_request(struct request_queue * q) diff --git a/drivers/block/aoe/aoechr.c b/drivers/block/aoe/aoechr.c index 200efc4d2c1e..19888354188f 100644 --- a/drivers/block/aoe/aoechr.c +++ b/drivers/block/aoe/aoechr.c @@ -266,6 +266,11 @@ static const struct file_operations aoe_fops = { .owner = THIS_MODULE, }; +static char *aoe_nodename(struct device *dev) +{ + return kasprintf(GFP_KERNEL, "etherd/%s", dev_name(dev)); +} + int __init aoechr_init(void) { @@ -283,6 +288,8 @@ aoechr_init(void) unregister_chrdev(AOE_MAJOR, "aoechr"); return PTR_ERR(aoe_class); } + aoe_class->nodename = aoe_nodename; + for (i = 0; i < ARRAY_SIZE(chardevs); ++i) device_create(aoe_class, NULL, MKDEV(AOE_MAJOR, chardevs[i].minor), NULL, diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index 31693bc24444..965ece2c7e4d 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -34,13 +34,6 @@ new_skb(ulong len) skb_reset_mac_header(skb); skb_reset_network_header(skb); skb->protocol = __constant_htons(ETH_P_AOE); - skb->priority = 0; - skb->next = skb->prev = NULL; - - /* tell the network layer not to perform IP checksums - * or to get the NIC to do it - */ - skb->ip_summed = CHECKSUM_NONE; } return skb; } diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c index 4234c11c1e4c..f5e7180d7f47 100644 --- a/drivers/block/ataflop.c +++ b/drivers/block/ataflop.c @@ -79,9 +79,7 @@ #undef DEBUG static struct request_queue *floppy_queue; - -#define QUEUE (floppy_queue) -#define CURRENT elv_next_request(floppy_queue) +static struct request *fd_request; /* Disk types: DD, HD, ED */ static struct atari_disk_type { @@ -376,6 +374,12 @@ static DEFINE_TIMER(readtrack_timer, fd_readtrack_check, 0, 0); static DEFINE_TIMER(timeout_timer, fd_times_out, 0, 0); static DEFINE_TIMER(fd_timer, check_change, 0, 0); +static void fd_end_request_cur(int err) +{ + if (!__blk_end_request_cur(fd_request, err)) + fd_request = NULL; +} + static inline void start_motor_off_timer(void) { mod_timer(&motor_off_timer, jiffies + FD_MOTOR_OFF_DELAY); @@ -606,15 +610,15 @@ static void fd_error( void ) return; } - if (!CURRENT) + if (!fd_request) return; - CURRENT->errors++; - if (CURRENT->errors >= MAX_ERRORS) { + fd_request->errors++; + if (fd_request->errors >= MAX_ERRORS) { printk(KERN_ERR "fd%d: too many errors.\n", SelectedDrive ); - end_request(CURRENT, 0); + fd_end_request_cur(-EIO); } - else if (CURRENT->errors == RECALIBRATE_ERRORS) { + else if (fd_request->errors == RECALIBRATE_ERRORS) { printk(KERN_WARNING "fd%d: recalibrating\n", SelectedDrive ); if (SelectedDrive != -1) SUD.track = -1; @@ -725,16 +729,14 @@ static void do_fd_action( int drive ) if (IS_BUFFERED( drive, ReqSide, ReqTrack )) { if (ReqCmd == READ) { copy_buffer( SECTOR_BUFFER(ReqSector), ReqData ); - if (++ReqCnt < CURRENT->current_nr_sectors) { + if (++ReqCnt < blk_rq_cur_sectors(fd_request)) { /* read next sector */ setup_req_params( drive ); goto repeat; } else { /* all sectors finished */ - CURRENT->nr_sectors -= CURRENT->current_nr_sectors; - CURRENT->sector += CURRENT->current_nr_sectors; - end_request(CURRENT, 1); + fd_end_request_cur(0); redo_fd_request(); return; } @@ -1132,16 +1134,14 @@ static void fd_rwsec_done1(int status) } } - if (++ReqCnt < CURRENT->current_nr_sectors) { + if (++ReqCnt < blk_rq_cur_sectors(fd_request)) { /* read next sector */ setup_req_params( SelectedDrive ); do_fd_action( SelectedDrive ); } else { /* all sectors finished */ - CURRENT->nr_sectors -= CURRENT->current_nr_sectors; - CURRENT->sector += CURRENT->current_nr_sectors; - end_request(CURRENT, 1); + fd_end_request_cur(0); redo_fd_request(); } return; @@ -1382,7 +1382,7 @@ static void setup_req_params( int drive ) ReqData = ReqBuffer + 512 * ReqCnt; if (UseTrackbuffer) - read_track = (ReqCmd == READ && CURRENT->errors == 0); + read_track = (ReqCmd == READ && fd_request->errors == 0); else read_track = 0; @@ -1396,25 +1396,27 @@ static void redo_fd_request(void) int drive, type; struct atari_floppy_struct *floppy; - DPRINT(("redo_fd_request: CURRENT=%p dev=%s CURRENT->sector=%ld\n", - CURRENT, CURRENT ? CURRENT->rq_disk->disk_name : "", - CURRENT ? CURRENT->sector : 0 )); + DPRINT(("redo_fd_request: fd_request=%p dev=%s fd_request->sector=%ld\n", + fd_request, fd_request ? fd_request->rq_disk->disk_name : "", + fd_request ? blk_rq_pos(fd_request) : 0 )); IsFormatting = 0; repeat: + if (!fd_request) { + fd_request = blk_fetch_request(floppy_queue); + if (!fd_request) + goto the_end; + } - if (!CURRENT) - goto the_end; - - floppy = CURRENT->rq_disk->private_data; + floppy = fd_request->rq_disk->private_data; drive = floppy - unit; type = floppy->type; if (!UD.connected) { /* drive not connected */ printk(KERN_ERR "Unknown Device: fd%d\n", drive ); - end_request(CURRENT, 0); + fd_end_request_cur(-EIO); goto repeat; } @@ -1430,12 +1432,12 @@ repeat: /* user supplied disk type */ if (--type >= NUM_DISK_MINORS) { printk(KERN_WARNING "fd%d: invalid disk format", drive ); - end_request(CURRENT, 0); + fd_end_request_cur(-EIO); goto repeat; } if (minor2disktype[type].drive_types > DriveType) { printk(KERN_WARNING "fd%d: unsupported disk format", drive ); - end_request(CURRENT, 0); + fd_end_request_cur(-EIO); goto repeat; } type = minor2disktype[type].index; @@ -1444,8 +1446,8 @@ repeat: UD.autoprobe = 0; } - if (CURRENT->sector + 1 > UDT->blocks) { - end_request(CURRENT, 0); + if (blk_rq_pos(fd_request) + 1 > UDT->blocks) { + fd_end_request_cur(-EIO); goto repeat; } @@ -1453,9 +1455,9 @@ repeat: del_timer( &motor_off_timer ); ReqCnt = 0; - ReqCmd = rq_data_dir(CURRENT); - ReqBlock = CURRENT->sector; - ReqBuffer = CURRENT->buffer; + ReqCmd = rq_data_dir(fd_request); + ReqBlock = blk_rq_pos(fd_request); + ReqBuffer = fd_request->buffer; setup_req_params( drive ); do_fd_action( drive ); diff --git a/drivers/block/brd.c b/drivers/block/brd.c index 5f7e64ba87e5..4bf8705b3ace 100644 --- a/drivers/block/brd.c +++ b/drivers/block/brd.c @@ -407,12 +407,7 @@ static int __init ramdisk_size(char *str) rd_size = simple_strtol(str, NULL, 0); return 1; } -static int __init ramdisk_size2(char *str) -{ - return ramdisk_size(str); -} -__setup("ramdisk=", ramdisk_size); -__setup("ramdisk_size=", ramdisk_size2); +__setup("ramdisk_size=", ramdisk_size); #endif /* diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 4d4d5e0d3fa6..c7a527c08a09 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -38,7 +38,6 @@ #include #include #include -#include #include #include @@ -180,11 +179,13 @@ static void __devinit cciss_interrupt_mode(ctlr_info_t *, struct pci_dev *, __u32); static void start_io(ctlr_info_t *h); static int sendcmd(__u8 cmd, int ctlr, void *buff, size_t size, - unsigned int use_unit_num, unsigned int log_unit, __u8 page_code, unsigned char *scsi3addr, int cmd_type); static int sendcmd_withirq(__u8 cmd, int ctlr, void *buff, size_t size, - unsigned int use_unit_num, unsigned int log_unit, - __u8 page_code, int cmd_type); + __u8 page_code, unsigned char scsi3addr[], + int cmd_type); +static int sendcmd_withirq_core(ctlr_info_t *h, CommandList_struct *c, + int attempt_retry); +static int process_sendcmd_error(ctlr_info_t *h, CommandList_struct *c); static void fail_all_cmds(unsigned long ctlr); static int scan_thread(void *data); @@ -437,6 +438,194 @@ static void __devinit cciss_procinit(int i) } #endif /* CONFIG_PROC_FS */ +#define MAX_PRODUCT_NAME_LEN 19 + +#define to_hba(n) container_of(n, struct ctlr_info, dev) +#define to_drv(n) container_of(n, drive_info_struct, dev) + +static struct device_type cciss_host_type = { + .name = "cciss_host", +}; + +static ssize_t dev_show_unique_id(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + drive_info_struct *drv = to_drv(dev); + struct ctlr_info *h = to_hba(drv->dev.parent); + __u8 sn[16]; + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags); + if (h->busy_configuring) + ret = -EBUSY; + else + memcpy(sn, drv->serial_no, sizeof(sn)); + spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); + + if (ret) + return ret; + else + return snprintf(buf, 16 * 2 + 2, + "%02X%02X%02X%02X%02X%02X%02X%02X" + "%02X%02X%02X%02X%02X%02X%02X%02X\n", + sn[0], sn[1], sn[2], sn[3], + sn[4], sn[5], sn[6], sn[7], + sn[8], sn[9], sn[10], sn[11], + sn[12], sn[13], sn[14], sn[15]); +} +DEVICE_ATTR(unique_id, S_IRUGO, dev_show_unique_id, NULL); + +static ssize_t dev_show_vendor(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + drive_info_struct *drv = to_drv(dev); + struct ctlr_info *h = to_hba(drv->dev.parent); + char vendor[VENDOR_LEN + 1]; + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags); + if (h->busy_configuring) + ret = -EBUSY; + else + memcpy(vendor, drv->vendor, VENDOR_LEN + 1); + spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); + + if (ret) + return ret; + else + return snprintf(buf, sizeof(vendor) + 1, "%s\n", drv->vendor); +} +DEVICE_ATTR(vendor, S_IRUGO, dev_show_vendor, NULL); + +static ssize_t dev_show_model(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + drive_info_struct *drv = to_drv(dev); + struct ctlr_info *h = to_hba(drv->dev.parent); + char model[MODEL_LEN + 1]; + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags); + if (h->busy_configuring) + ret = -EBUSY; + else + memcpy(model, drv->model, MODEL_LEN + 1); + spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); + + if (ret) + return ret; + else + return snprintf(buf, sizeof(model) + 1, "%s\n", drv->model); +} +DEVICE_ATTR(model, S_IRUGO, dev_show_model, NULL); + +static ssize_t dev_show_rev(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + drive_info_struct *drv = to_drv(dev); + struct ctlr_info *h = to_hba(drv->dev.parent); + char rev[REV_LEN + 1]; + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags); + if (h->busy_configuring) + ret = -EBUSY; + else + memcpy(rev, drv->rev, REV_LEN + 1); + spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); + + if (ret) + return ret; + else + return snprintf(buf, sizeof(rev) + 1, "%s\n", drv->rev); +} +DEVICE_ATTR(rev, S_IRUGO, dev_show_rev, NULL); + +static struct attribute *cciss_dev_attrs[] = { + &dev_attr_unique_id.attr, + &dev_attr_model.attr, + &dev_attr_vendor.attr, + &dev_attr_rev.attr, + NULL +}; + +static struct attribute_group cciss_dev_attr_group = { + .attrs = cciss_dev_attrs, +}; + +static struct attribute_group *cciss_dev_attr_groups[] = { + &cciss_dev_attr_group, + NULL +}; + +static struct device_type cciss_dev_type = { + .name = "cciss_device", + .groups = cciss_dev_attr_groups, +}; + +static struct bus_type cciss_bus_type = { + .name = "cciss", +}; + + +/* + * Initialize sysfs entry for each controller. This sets up and registers + * the 'cciss#' directory for each individual controller under + * /sys/bus/pci/devices//. + */ +static int cciss_create_hba_sysfs_entry(struct ctlr_info *h) +{ + device_initialize(&h->dev); + h->dev.type = &cciss_host_type; + h->dev.bus = &cciss_bus_type; + dev_set_name(&h->dev, "%s", h->devname); + h->dev.parent = &h->pdev->dev; + + return device_add(&h->dev); +} + +/* + * Remove sysfs entries for an hba. + */ +static void cciss_destroy_hba_sysfs_entry(struct ctlr_info *h) +{ + device_del(&h->dev); +} + +/* + * Initialize sysfs for each logical drive. This sets up and registers + * the 'c#d#' directory for each individual logical drive under + * /sys/bus/pci/devices/dev); + drv->dev.type = &cciss_dev_type; + drv->dev.bus = &cciss_bus_type; + dev_set_name(&drv->dev, "c%dd%d", h->ctlr, drv_index); + drv->dev.parent = &h->dev; + return device_add(&drv->dev); +} + +/* + * Remove sysfs entries for a logical drive. + */ +static void cciss_destroy_ld_sysfs_entry(drive_info_struct *drv) +{ + device_del(&drv->dev); +} + /* * For operations that cannot sleep, a command block is allocated at init, * and managed by cmd_alloc() and cmd_free() using a simple bitmap to track @@ -1299,7 +1488,6 @@ static void cciss_softirq_done(struct request *rq) { CommandList_struct *cmd = rq->completion_data; ctlr_info_t *h = hba[cmd->ctlr]; - unsigned int nr_bytes; unsigned long flags; u64bit temp64; int i, ddir; @@ -1321,15 +1509,11 @@ static void cciss_softirq_done(struct request *rq) printk("Done with %p\n", rq); #endif /* CCISS_DEBUG */ - /* - * Store the full size and set the residual count for pc requests - */ - nr_bytes = blk_rq_bytes(rq); + /* set the residual count for pc requests */ if (blk_pc_request(rq)) - rq->data_len = cmd->err_info->ResidualCnt; + rq->resid_len = cmd->err_info->ResidualCnt; - if (blk_end_request(rq, (rq->errors == 0) ? 0 : -EIO, nr_bytes)) - BUG(); + blk_end_request_all(rq, (rq->errors == 0) ? 0 : -EIO); spin_lock_irqsave(&h->lock, flags); cmd_free(h, cmd, 1); @@ -1337,6 +1521,56 @@ static void cciss_softirq_done(struct request *rq) spin_unlock_irqrestore(&h->lock, flags); } +static void log_unit_to_scsi3addr(ctlr_info_t *h, unsigned char scsi3addr[], + uint32_t log_unit) +{ + log_unit = h->drv[log_unit].LunID & 0x03fff; + memset(&scsi3addr[4], 0, 4); + memcpy(&scsi3addr[0], &log_unit, 4); + scsi3addr[3] |= 0x40; +} + +/* This function gets the SCSI vendor, model, and revision of a logical drive + * via the inquiry page 0. Model, vendor, and rev are set to empty strings if + * they cannot be read. + */ +static void cciss_get_device_descr(int ctlr, int logvol, int withirq, + char *vendor, char *model, char *rev) +{ + int rc; + InquiryData_struct *inq_buf; + unsigned char scsi3addr[8]; + + *vendor = '\0'; + *model = '\0'; + *rev = '\0'; + + inq_buf = kzalloc(sizeof(InquiryData_struct), GFP_KERNEL); + if (!inq_buf) + return; + + log_unit_to_scsi3addr(hba[ctlr], scsi3addr, logvol); + if (withirq) + rc = sendcmd_withirq(CISS_INQUIRY, ctlr, inq_buf, + sizeof(InquiryData_struct), 0, + scsi3addr, TYPE_CMD); + else + rc = sendcmd(CISS_INQUIRY, ctlr, inq_buf, + sizeof(InquiryData_struct), 0, + scsi3addr, TYPE_CMD); + if (rc == IO_OK) { + memcpy(vendor, &inq_buf->data_byte[8], VENDOR_LEN); + vendor[VENDOR_LEN] = '\0'; + memcpy(model, &inq_buf->data_byte[16], MODEL_LEN); + model[MODEL_LEN] = '\0'; + memcpy(rev, &inq_buf->data_byte[32], REV_LEN); + rev[REV_LEN] = '\0'; + } + + kfree(inq_buf); + return; +} + /* This function gets the serial number of a logical drive via * inquiry page 0x83. Serial no. is 16 bytes. If the serial * number cannot be had, for whatever reason, 16 bytes of 0xff @@ -1348,6 +1582,7 @@ static void cciss_get_serial_no(int ctlr, int logvol, int withirq, #define PAGE_83_INQ_BYTES 64 int rc; unsigned char *buf; + unsigned char scsi3addr[8]; if (buflen > 16) buflen = 16; @@ -1356,12 +1591,13 @@ static void cciss_get_serial_no(int ctlr, int logvol, int withirq, if (!buf) return; memset(serial_no, 0, buflen); + log_unit_to_scsi3addr(hba[ctlr], scsi3addr, logvol); if (withirq) rc = sendcmd_withirq(CISS_INQUIRY, ctlr, buf, - PAGE_83_INQ_BYTES, 1, logvol, 0x83, TYPE_CMD); + PAGE_83_INQ_BYTES, 0x83, scsi3addr, TYPE_CMD); else rc = sendcmd(CISS_INQUIRY, ctlr, buf, - PAGE_83_INQ_BYTES, 1, logvol, 0x83, NULL, TYPE_CMD); + PAGE_83_INQ_BYTES, 0x83, scsi3addr, TYPE_CMD); if (rc == IO_OK) memcpy(serial_no, &buf[8], buflen); kfree(buf); @@ -1377,7 +1613,7 @@ static void cciss_add_disk(ctlr_info_t *h, struct gendisk *disk, disk->first_minor = drv_index << NWD_SHIFT; disk->fops = &cciss_fops; disk->private_data = &h->drv[drv_index]; - disk->driverfs_dev = &h->pdev->dev; + disk->driverfs_dev = &h->drv[drv_index].dev; /* Set up queue information */ blk_queue_bounce_limit(disk->queue, h->pdev->dma_mask); @@ -1394,8 +1630,8 @@ static void cciss_add_disk(ctlr_info_t *h, struct gendisk *disk, disk->queue->queuedata = h; - blk_queue_hardsect_size(disk->queue, - h->drv[drv_index].block_size); + blk_queue_logical_block_size(disk->queue, + h->drv[drv_index].block_size); /* Make sure all queue data is written out before */ /* setting h->drv[drv_index].queue, as setting this */ @@ -1468,6 +1704,8 @@ static void cciss_update_drive_info(int ctlr, int drv_index, int first_time) drvinfo->block_size = block_size; drvinfo->nr_blocks = total_size + 1; + cciss_get_device_descr(ctlr, drv_index, 1, drvinfo->vendor, + drvinfo->model, drvinfo->rev); cciss_get_serial_no(ctlr, drv_index, 1, drvinfo->serial_no, sizeof(drvinfo->serial_no)); @@ -1517,6 +1755,9 @@ static void cciss_update_drive_info(int ctlr, int drv_index, int first_time) h->drv[drv_index].cylinders = drvinfo->cylinders; h->drv[drv_index].raid_level = drvinfo->raid_level; memcpy(h->drv[drv_index].serial_no, drvinfo->serial_no, 16); + memcpy(h->drv[drv_index].vendor, drvinfo->vendor, VENDOR_LEN + 1); + memcpy(h->drv[drv_index].model, drvinfo->model, MODEL_LEN + 1); + memcpy(h->drv[drv_index].rev, drvinfo->rev, REV_LEN + 1); ++h->num_luns; disk = h->gendisk[drv_index]; @@ -1591,6 +1832,8 @@ static int cciss_add_gendisk(ctlr_info_t *h, __u32 lunid, int controller_node) } } h->drv[drv_index].LunID = lunid; + if (cciss_create_ld_sysfs_entry(h, &h->drv[drv_index], drv_index)) + goto err_free_disk; /* Don't need to mark this busy because nobody */ /* else knows about this disk yet to contend */ @@ -1598,6 +1841,11 @@ static int cciss_add_gendisk(ctlr_info_t *h, __u32 lunid, int controller_node) h->drv[drv_index].busy_configuring = 0; wmb(); return drv_index; + +err_free_disk: + put_disk(h->gendisk[drv_index]); + h->gendisk[drv_index] = NULL; + return -1; } /* This is for the special case of a controller which @@ -1668,8 +1916,8 @@ static int rebuild_lun_table(ctlr_info_t *h, int first_time) goto mem_msg; return_code = sendcmd_withirq(CISS_REPORT_LOG, ctlr, ld_buff, - sizeof(ReportLunData_struct), 0, - 0, 0, TYPE_CMD); + sizeof(ReportLunData_struct), + 0, CTLR_LUNID, TYPE_CMD); if (return_code == IO_OK) listlength = be32_to_cpu(*(__be32 *) ld_buff->LUNListLength); @@ -1718,6 +1966,7 @@ static int rebuild_lun_table(ctlr_info_t *h, int first_time) h->drv[i].busy_configuring = 1; spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); return_code = deregister_disk(h, i, 1); + cciss_destroy_ld_sysfs_entry(&h->drv[i]); h->drv[i].busy_configuring = 0; } } @@ -1877,11 +2126,9 @@ static int deregister_disk(ctlr_info_t *h, int drv_index, return 0; } -static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, size_t size, unsigned int use_unit_num, /* 0: address the controller, - 1: address logical volume log_unit, - 2: periph device address is scsi3addr */ - unsigned int log_unit, __u8 page_code, - unsigned char *scsi3addr, int cmd_type) +static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, + size_t size, __u8 page_code, unsigned char *scsi3addr, + int cmd_type) { ctlr_info_t *h = hba[ctlr]; u64bit buff_dma_handle; @@ -1897,27 +2144,12 @@ static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, size_ c->Header.SGTotal = 0; } c->Header.Tag.lower = c->busaddr; + memcpy(c->Header.LUN.LunAddrBytes, scsi3addr, 8); c->Request.Type.Type = cmd_type; if (cmd_type == TYPE_CMD) { switch (cmd) { case CISS_INQUIRY: - /* If the logical unit number is 0 then, this is going - to controller so It's a physical command - mode = 0 target = 0. So we have nothing to write. - otherwise, if use_unit_num == 1, - mode = 1(volume set addressing) target = LUNID - otherwise, if use_unit_num == 2, - mode = 0(periph dev addr) target = scsi3addr */ - if (use_unit_num == 1) { - c->Header.LUN.LogDev.VolId = - h->drv[log_unit].LunID; - c->Header.LUN.LogDev.Mode = 1; - } else if (use_unit_num == 2) { - memcpy(c->Header.LUN.LunAddrBytes, scsi3addr, - 8); - c->Header.LUN.LogDev.Mode = 0; - } /* are we trying to read a vital product page */ if (page_code != 0) { c->Request.CDB[1] = 0x01; @@ -1947,8 +2179,6 @@ static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, size_ break; case CCISS_READ_CAPACITY: - c->Header.LUN.LogDev.VolId = h->drv[log_unit].LunID; - c->Header.LUN.LogDev.Mode = 1; c->Request.CDBLen = 10; c->Request.Type.Attribute = ATTR_SIMPLE; c->Request.Type.Direction = XFER_READ; @@ -1956,8 +2186,6 @@ static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, size_ c->Request.CDB[0] = cmd; break; case CCISS_READ_CAPACITY_16: - c->Header.LUN.LogDev.VolId = h->drv[log_unit].LunID; - c->Header.LUN.LogDev.Mode = 1; c->Request.CDBLen = 16; c->Request.Type.Attribute = ATTR_SIMPLE; c->Request.Type.Direction = XFER_READ; @@ -1979,6 +2207,12 @@ static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, size_ c->Request.CDB[0] = BMIC_WRITE; c->Request.CDB[6] = BMIC_CACHE_FLUSH; break; + case TEST_UNIT_READY: + c->Request.CDBLen = 6; + c->Request.Type.Attribute = ATTR_SIMPLE; + c->Request.Type.Direction = XFER_NONE; + c->Request.Timeout = 0; + break; default: printk(KERN_WARNING "cciss%d: Unknown Command 0x%c\n", ctlr, cmd); @@ -1997,13 +2231,13 @@ static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, size_ memcpy(&c->Request.CDB[4], buff, 8); break; case 1: /* RESET message */ - c->Request.CDBLen = 12; + c->Request.CDBLen = 16; c->Request.Type.Attribute = ATTR_SIMPLE; - c->Request.Type.Direction = XFER_WRITE; + c->Request.Type.Direction = XFER_NONE; c->Request.Timeout = 0; memset(&c->Request.CDB[0], 0, sizeof(c->Request.CDB)); c->Request.CDB[0] = cmd; /* reset */ - c->Request.CDB[1] = 0x04; /* reset a LUN */ + c->Request.CDB[1] = 0x03; /* reset a target */ break; case 3: /* No-Op message */ c->Request.CDBLen = 1; @@ -2035,114 +2269,152 @@ static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, size_ return status; } -static int sendcmd_withirq(__u8 cmd, - int ctlr, - void *buff, - size_t size, - unsigned int use_unit_num, - unsigned int log_unit, __u8 page_code, int cmd_type) +static int check_target_status(ctlr_info_t *h, CommandList_struct *c) { - ctlr_info_t *h = hba[ctlr]; - CommandList_struct *c; + switch (c->err_info->ScsiStatus) { + case SAM_STAT_GOOD: + return IO_OK; + case SAM_STAT_CHECK_CONDITION: + switch (0xf & c->err_info->SenseInfo[2]) { + case 0: return IO_OK; /* no sense */ + case 1: return IO_OK; /* recovered error */ + default: + printk(KERN_WARNING "cciss%d: cmd 0x%02x " + "check condition, sense key = 0x%02x\n", + h->ctlr, c->Request.CDB[0], + c->err_info->SenseInfo[2]); + } + break; + default: + printk(KERN_WARNING "cciss%d: cmd 0x%02x" + "scsi status = 0x%02x\n", h->ctlr, + c->Request.CDB[0], c->err_info->ScsiStatus); + break; + } + return IO_ERROR; +} + +static int process_sendcmd_error(ctlr_info_t *h, CommandList_struct *c) +{ + int return_status = IO_OK; + + if (c->err_info->CommandStatus == CMD_SUCCESS) + return IO_OK; + + switch (c->err_info->CommandStatus) { + case CMD_TARGET_STATUS: + return_status = check_target_status(h, c); + break; + case CMD_DATA_UNDERRUN: + case CMD_DATA_OVERRUN: + /* expected for inquiry and report lun commands */ + break; + case CMD_INVALID: + printk(KERN_WARNING "cciss: cmd 0x%02x is " + "reported invalid\n", c->Request.CDB[0]); + return_status = IO_ERROR; + break; + case CMD_PROTOCOL_ERR: + printk(KERN_WARNING "cciss: cmd 0x%02x has " + "protocol error \n", c->Request.CDB[0]); + return_status = IO_ERROR; + break; + case CMD_HARDWARE_ERR: + printk(KERN_WARNING "cciss: cmd 0x%02x had " + " hardware error\n", c->Request.CDB[0]); + return_status = IO_ERROR; + break; + case CMD_CONNECTION_LOST: + printk(KERN_WARNING "cciss: cmd 0x%02x had " + "connection lost\n", c->Request.CDB[0]); + return_status = IO_ERROR; + break; + case CMD_ABORTED: + printk(KERN_WARNING "cciss: cmd 0x%02x was " + "aborted\n", c->Request.CDB[0]); + return_status = IO_ERROR; + break; + case CMD_ABORT_FAILED: + printk(KERN_WARNING "cciss: cmd 0x%02x reports " + "abort failed\n", c->Request.CDB[0]); + return_status = IO_ERROR; + break; + case CMD_UNSOLICITED_ABORT: + printk(KERN_WARNING + "cciss%d: unsolicited abort 0x%02x\n", h->ctlr, + c->Request.CDB[0]); + return_status = IO_NEEDS_RETRY; + break; + default: + printk(KERN_WARNING "cciss: cmd 0x%02x returned " + "unknown status %x\n", c->Request.CDB[0], + c->err_info->CommandStatus); + return_status = IO_ERROR; + } + return return_status; +} + +static int sendcmd_withirq_core(ctlr_info_t *h, CommandList_struct *c, + int attempt_retry) +{ + DECLARE_COMPLETION_ONSTACK(wait); u64bit buff_dma_handle; unsigned long flags; - int return_status; - DECLARE_COMPLETION_ONSTACK(wait); + int return_status = IO_OK; - if ((c = cmd_alloc(h, 0)) == NULL) - return -ENOMEM; - return_status = fill_cmd(c, cmd, ctlr, buff, size, use_unit_num, - log_unit, page_code, NULL, cmd_type); - if (return_status != IO_OK) { - cmd_free(h, c, 0); - return return_status; - } - resend_cmd2: +resend_cmd2: c->waiting = &wait; - /* Put the request on the tail of the queue and send it */ - spin_lock_irqsave(CCISS_LOCK(ctlr), flags); + spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags); addQ(&h->reqQ, c); h->Qdepth++; start_io(h); - spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags); + spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); wait_for_completion(&wait); - if (c->err_info->CommandStatus != 0) { /* an error has occurred */ - switch (c->err_info->CommandStatus) { - case CMD_TARGET_STATUS: - printk(KERN_WARNING "cciss: cmd %p has " - " completed with errors\n", c); - if (c->err_info->ScsiStatus) { - printk(KERN_WARNING "cciss: cmd %p " - "has SCSI Status = %x\n", - c, c->err_info->ScsiStatus); - } + if (c->err_info->CommandStatus == 0 || !attempt_retry) + goto command_done; - break; - case CMD_DATA_UNDERRUN: - case CMD_DATA_OVERRUN: - /* expected for inquire and report lun commands */ - break; - case CMD_INVALID: - printk(KERN_WARNING "cciss: Cmd %p is " - "reported invalid\n", c); - return_status = IO_ERROR; - break; - case CMD_PROTOCOL_ERR: - printk(KERN_WARNING "cciss: cmd %p has " - "protocol error \n", c); - return_status = IO_ERROR; - break; - case CMD_HARDWARE_ERR: - printk(KERN_WARNING "cciss: cmd %p had " - " hardware error\n", c); - return_status = IO_ERROR; - break; - case CMD_CONNECTION_LOST: - printk(KERN_WARNING "cciss: cmd %p had " - "connection lost\n", c); - return_status = IO_ERROR; - break; - case CMD_ABORTED: - printk(KERN_WARNING "cciss: cmd %p was " - "aborted\n", c); - return_status = IO_ERROR; - break; - case CMD_ABORT_FAILED: - printk(KERN_WARNING "cciss: cmd %p reports " - "abort failed\n", c); - return_status = IO_ERROR; - break; - case CMD_UNSOLICITED_ABORT: - printk(KERN_WARNING - "cciss%d: unsolicited abort %p\n", ctlr, c); - if (c->retry_count < MAX_CMD_RETRIES) { - printk(KERN_WARNING - "cciss%d: retrying %p\n", ctlr, c); - c->retry_count++; - /* erase the old error information */ - memset(c->err_info, 0, - sizeof(ErrorInfo_struct)); - return_status = IO_OK; - INIT_COMPLETION(wait); - goto resend_cmd2; - } - return_status = IO_ERROR; - break; - default: - printk(KERN_WARNING "cciss: cmd %p returned " - "unknown status %x\n", c, - c->err_info->CommandStatus); - return_status = IO_ERROR; - } + return_status = process_sendcmd_error(h, c); + + if (return_status == IO_NEEDS_RETRY && + c->retry_count < MAX_CMD_RETRIES) { + printk(KERN_WARNING "cciss%d: retrying 0x%02x\n", h->ctlr, + c->Request.CDB[0]); + c->retry_count++; + /* erase the old error information */ + memset(c->err_info, 0, sizeof(ErrorInfo_struct)); + return_status = IO_OK; + INIT_COMPLETION(wait); + goto resend_cmd2; } + +command_done: /* unlock the buffers from DMA */ buff_dma_handle.val32.lower = c->SG[0].Addr.lower; buff_dma_handle.val32.upper = c->SG[0].Addr.upper; pci_unmap_single(h->pdev, (dma_addr_t) buff_dma_handle.val, c->SG[0].Len, PCI_DMA_BIDIRECTIONAL); + return return_status; +} + +static int sendcmd_withirq(__u8 cmd, int ctlr, void *buff, size_t size, + __u8 page_code, unsigned char scsi3addr[], + int cmd_type) +{ + ctlr_info_t *h = hba[ctlr]; + CommandList_struct *c; + int return_status; + + c = cmd_alloc(h, 0); + if (!c) + return -ENOMEM; + return_status = fill_cmd(c, cmd, ctlr, buff, size, page_code, + scsi3addr, cmd_type); + if (return_status == IO_OK) + return_status = sendcmd_withirq_core(h, c, 1); + cmd_free(h, c, 0); return return_status; } @@ -2155,15 +2427,17 @@ static void cciss_geometry_inquiry(int ctlr, int logvol, { int return_code; unsigned long t; + unsigned char scsi3addr[8]; memset(inq_buff, 0, sizeof(InquiryData_struct)); + log_unit_to_scsi3addr(hba[ctlr], scsi3addr, logvol); if (withirq) return_code = sendcmd_withirq(CISS_INQUIRY, ctlr, - inq_buff, sizeof(*inq_buff), 1, - logvol, 0xC1, TYPE_CMD); + inq_buff, sizeof(*inq_buff), + 0xC1, scsi3addr, TYPE_CMD); else return_code = sendcmd(CISS_INQUIRY, ctlr, inq_buff, - sizeof(*inq_buff), 1, logvol, 0xC1, NULL, + sizeof(*inq_buff), 0xC1, scsi3addr, TYPE_CMD); if (return_code == IO_OK) { if (inq_buff->data_byte[8] == 0xFF) { @@ -2204,6 +2478,7 @@ cciss_read_capacity(int ctlr, int logvol, int withirq, sector_t *total_size, { ReadCapdata_struct *buf; int return_code; + unsigned char scsi3addr[8]; buf = kzalloc(sizeof(ReadCapdata_struct), GFP_KERNEL); if (!buf) { @@ -2211,14 +2486,15 @@ cciss_read_capacity(int ctlr, int logvol, int withirq, sector_t *total_size, return; } + log_unit_to_scsi3addr(hba[ctlr], scsi3addr, logvol); if (withirq) return_code = sendcmd_withirq(CCISS_READ_CAPACITY, ctlr, buf, sizeof(ReadCapdata_struct), - 1, logvol, 0, TYPE_CMD); + 0, scsi3addr, TYPE_CMD); else return_code = sendcmd(CCISS_READ_CAPACITY, ctlr, buf, sizeof(ReadCapdata_struct), - 1, logvol, 0, NULL, TYPE_CMD); + 0, scsi3addr, TYPE_CMD); if (return_code == IO_OK) { *total_size = be32_to_cpu(*(__be32 *) buf->total_size); *block_size = be32_to_cpu(*(__be32 *) buf->block_size); @@ -2238,6 +2514,7 @@ cciss_read_capacity_16(int ctlr, int logvol, int withirq, sector_t *total_size, { ReadCapdata_struct_16 *buf; int return_code; + unsigned char scsi3addr[8]; buf = kzalloc(sizeof(ReadCapdata_struct_16), GFP_KERNEL); if (!buf) { @@ -2245,15 +2522,16 @@ cciss_read_capacity_16(int ctlr, int logvol, int withirq, sector_t *total_size, return; } + log_unit_to_scsi3addr(hba[ctlr], scsi3addr, logvol); if (withirq) { return_code = sendcmd_withirq(CCISS_READ_CAPACITY_16, ctlr, buf, sizeof(ReadCapdata_struct_16), - 1, logvol, 0, TYPE_CMD); + 0, scsi3addr, TYPE_CMD); } else { return_code = sendcmd(CCISS_READ_CAPACITY_16, ctlr, buf, sizeof(ReadCapdata_struct_16), - 1, logvol, 0, NULL, TYPE_CMD); + 0, scsi3addr, TYPE_CMD); } if (return_code == IO_OK) { *total_size = be64_to_cpu(*(__be64 *) buf->total_size); @@ -2303,7 +2581,7 @@ static int cciss_revalidate(struct gendisk *disk) cciss_geometry_inquiry(h->ctlr, logvol, 1, total_size, block_size, inq_buff, drv); - blk_queue_hardsect_size(drv->queue, drv->block_size); + blk_queue_logical_block_size(drv->queue, drv->block_size); set_capacity(disk, drv->nr_blocks); kfree(inq_buff); @@ -2333,86 +2611,21 @@ static unsigned long pollcomplete(int ctlr) return 1; } -static int add_sendcmd_reject(__u8 cmd, int ctlr, unsigned long complete) -{ - /* We get in here if sendcmd() is polling for completions - and gets some command back that it wasn't expecting -- - something other than that which it just sent down. - Ordinarily, that shouldn't happen, but it can happen when - the scsi tape stuff gets into error handling mode, and - starts using sendcmd() to try to abort commands and - reset tape drives. In that case, sendcmd may pick up - completions of commands that were sent to logical drives - through the block i/o system, or cciss ioctls completing, etc. - In that case, we need to save those completions for later - processing by the interrupt handler. - */ - -#ifdef CONFIG_CISS_SCSI_TAPE - struct sendcmd_reject_list *srl = &hba[ctlr]->scsi_rejects; - - /* If it's not the scsi tape stuff doing error handling, (abort */ - /* or reset) then we don't expect anything weird. */ - if (cmd != CCISS_RESET_MSG && cmd != CCISS_ABORT_MSG) { -#endif - printk(KERN_WARNING "cciss cciss%d: SendCmd " - "Invalid command list address returned! (%lx)\n", - ctlr, complete); - /* not much we can do. */ -#ifdef CONFIG_CISS_SCSI_TAPE - return 1; - } - - /* We've sent down an abort or reset, but something else - has completed */ - if (srl->ncompletions >= (hba[ctlr]->nr_cmds + 2)) { - /* Uh oh. No room to save it for later... */ - printk(KERN_WARNING "cciss%d: Sendcmd: Invalid command addr, " - "reject list overflow, command lost!\n", ctlr); - return 1; - } - /* Save it for later */ - srl->complete[srl->ncompletions] = complete; - srl->ncompletions++; -#endif - return 0; -} - -/* - * Send a command to the controller, and wait for it to complete. - * Only used at init time. +/* Send command c to controller h and poll for it to complete. + * Turns interrupts off on the board. Used at driver init time + * and during SCSI error recovery. */ -static int sendcmd(__u8 cmd, int ctlr, void *buff, size_t size, unsigned int use_unit_num, /* 0: address the controller, - 1: address logical volume log_unit, - 2: periph device address is scsi3addr */ - unsigned int log_unit, - __u8 page_code, unsigned char *scsi3addr, int cmd_type) +static int sendcmd_core(ctlr_info_t *h, CommandList_struct *c) { - CommandList_struct *c; int i; unsigned long complete; - ctlr_info_t *info_p = hba[ctlr]; + int status = IO_ERROR; u64bit buff_dma_handle; - int status, done = 0; - if ((c = cmd_alloc(info_p, 1)) == NULL) { - printk(KERN_WARNING "cciss: unable to get memory"); - return IO_ERROR; - } - status = fill_cmd(c, cmd, ctlr, buff, size, use_unit_num, - log_unit, page_code, scsi3addr, cmd_type); - if (status != IO_OK) { - cmd_free(info_p, c, 1); - return status; - } - resend_cmd1: - /* - * Disable interrupt - */ -#ifdef CCISS_DEBUG - printk(KERN_DEBUG "cciss: turning intr off\n"); -#endif /* CCISS_DEBUG */ - info_p->access.set_intr_mask(info_p, CCISS_INTR_OFF); +resend_cmd1: + + /* Disable interrupt on the board. */ + h->access.set_intr_mask(h, CCISS_INTR_OFF); /* Make sure there is room in the command FIFO */ /* Actually it should be completely empty at this time */ @@ -2420,21 +2633,15 @@ static int sendcmd(__u8 cmd, int ctlr, void *buff, size_t size, unsigned int use /* tape side of the driver. */ for (i = 200000; i > 0; i--) { /* if fifo isn't full go */ - if (!(info_p->access.fifo_full(info_p))) { - + if (!(h->access.fifo_full(h))) break; - } udelay(10); printk(KERN_WARNING "cciss cciss%d: SendCmd FIFO full," - " waiting!\n", ctlr); + " waiting!\n", h->ctlr); } - /* - * Send the cmd - */ - info_p->access.submit_command(info_p, c); - done = 0; + h->access.submit_command(h, c); /* Send the cmd */ do { - complete = pollcomplete(ctlr); + complete = pollcomplete(h->ctlr); #ifdef CCISS_DEBUG printk(KERN_DEBUG "cciss: command completed\n"); @@ -2443,97 +2650,102 @@ static int sendcmd(__u8 cmd, int ctlr, void *buff, size_t size, unsigned int use if (complete == 1) { printk(KERN_WARNING "cciss cciss%d: SendCmd Timeout out, " - "No command list address returned!\n", ctlr); + "No command list address returned!\n", h->ctlr); status = IO_ERROR; - done = 1; break; } - /* This will need to change for direct lookup completions */ - if ((complete & CISS_ERROR_BIT) - && (complete & ~CISS_ERROR_BIT) == c->busaddr) { - /* if data overrun or underun on Report command - ignore it - */ - if (((c->Request.CDB[0] == CISS_REPORT_LOG) || - (c->Request.CDB[0] == CISS_REPORT_PHYS) || - (c->Request.CDB[0] == CISS_INQUIRY)) && - ((c->err_info->CommandStatus == - CMD_DATA_OVERRUN) || - (c->err_info->CommandStatus == CMD_DATA_UNDERRUN) - )) { - complete = c->busaddr; - } else { - if (c->err_info->CommandStatus == - CMD_UNSOLICITED_ABORT) { - printk(KERN_WARNING "cciss%d: " - "unsolicited abort %p\n", - ctlr, c); - if (c->retry_count < MAX_CMD_RETRIES) { - printk(KERN_WARNING - "cciss%d: retrying %p\n", - ctlr, c); - c->retry_count++; - /* erase the old error */ - /* information */ - memset(c->err_info, 0, - sizeof - (ErrorInfo_struct)); - goto resend_cmd1; - } else { - printk(KERN_WARNING - "cciss%d: retried %p too " - "many times\n", ctlr, c); - status = IO_ERROR; - goto cleanup1; - } - } else if (c->err_info->CommandStatus == - CMD_UNABORTABLE) { - printk(KERN_WARNING - "cciss%d: command could not be aborted.\n", - ctlr); - status = IO_ERROR; - goto cleanup1; - } - printk(KERN_WARNING "ciss ciss%d: sendcmd" - " Error %x \n", ctlr, - c->err_info->CommandStatus); - printk(KERN_WARNING "ciss ciss%d: sendcmd" - " offensive info\n" - " size %x\n num %x value %x\n", - ctlr, - c->err_info->MoreErrInfo.Invalid_Cmd. - offense_size, - c->err_info->MoreErrInfo.Invalid_Cmd. - offense_num, - c->err_info->MoreErrInfo.Invalid_Cmd. - offense_value); - status = IO_ERROR; - goto cleanup1; - } - } - /* This will need changing for direct lookup completions */ - if (complete != c->busaddr) { - if (add_sendcmd_reject(cmd, ctlr, complete) != 0) { - BUG(); /* we are pretty much hosed if we get here. */ - } + /* Make sure it's the command we're expecting. */ + if ((complete & ~CISS_ERROR_BIT) != c->busaddr) { + printk(KERN_WARNING "cciss%d: Unexpected command " + "completion.\n", h->ctlr); continue; - } else - done = 1; - } while (!done); + } + + /* It is our command. If no error, we're done. */ + if (!(complete & CISS_ERROR_BIT)) { + status = IO_OK; + break; + } + + /* There is an error... */ + + /* if data overrun or underun on Report command ignore it */ + if (((c->Request.CDB[0] == CISS_REPORT_LOG) || + (c->Request.CDB[0] == CISS_REPORT_PHYS) || + (c->Request.CDB[0] == CISS_INQUIRY)) && + ((c->err_info->CommandStatus == CMD_DATA_OVERRUN) || + (c->err_info->CommandStatus == CMD_DATA_UNDERRUN))) { + complete = c->busaddr; + status = IO_OK; + break; + } + + if (c->err_info->CommandStatus == CMD_UNSOLICITED_ABORT) { + printk(KERN_WARNING "cciss%d: unsolicited abort %p\n", + h->ctlr, c); + if (c->retry_count < MAX_CMD_RETRIES) { + printk(KERN_WARNING "cciss%d: retrying %p\n", + h->ctlr, c); + c->retry_count++; + /* erase the old error information */ + memset(c->err_info, 0, sizeof(c->err_info)); + goto resend_cmd1; + } + printk(KERN_WARNING "cciss%d: retried %p too many " + "times\n", h->ctlr, c); + status = IO_ERROR; + break; + } + + if (c->err_info->CommandStatus == CMD_UNABORTABLE) { + printk(KERN_WARNING "cciss%d: command could not be " + "aborted.\n", h->ctlr); + status = IO_ERROR; + break; + } + + if (c->err_info->CommandStatus == CMD_TARGET_STATUS) { + status = check_target_status(h, c); + break; + } + + printk(KERN_WARNING "cciss%d: sendcmd error\n", h->ctlr); + printk(KERN_WARNING "cmd = 0x%02x, CommandStatus = 0x%02x\n", + c->Request.CDB[0], c->err_info->CommandStatus); + status = IO_ERROR; + break; + + } while (1); - cleanup1: /* unlock the data buffer from DMA */ buff_dma_handle.val32.lower = c->SG[0].Addr.lower; buff_dma_handle.val32.upper = c->SG[0].Addr.upper; - pci_unmap_single(info_p->pdev, (dma_addr_t) buff_dma_handle.val, + pci_unmap_single(h->pdev, (dma_addr_t) buff_dma_handle.val, c->SG[0].Len, PCI_DMA_BIDIRECTIONAL); -#ifdef CONFIG_CISS_SCSI_TAPE - /* if we saved some commands for later, process them now. */ - if (info_p->scsi_rejects.ncompletions > 0) - do_cciss_intr(0, info_p); -#endif - cmd_free(info_p, c, 1); + return status; +} + +/* + * Send a command to the controller, and wait for it to complete. + * Used at init time, and during SCSI error recovery. + */ +static int sendcmd(__u8 cmd, int ctlr, void *buff, size_t size, + __u8 page_code, unsigned char *scsi3addr, int cmd_type) +{ + CommandList_struct *c; + int status; + + c = cmd_alloc(hba[ctlr], 1); + if (!c) { + printk(KERN_WARNING "cciss: unable to get memory"); + return IO_ERROR; + } + status = fill_cmd(c, cmd, ctlr, buff, size, page_code, + scsi3addr, cmd_type); + if (status == IO_OK) + status = sendcmd_core(hba[ctlr], c); + cmd_free(hba[ctlr], c, 1); return status; } @@ -2691,7 +2903,7 @@ static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd, printk(KERN_WARNING "cciss: cmd %p has" " completed with data underrun " "reported\n", cmd); - cmd->rq->data_len = cmd->err_info->ResidualCnt; + cmd->rq->resid_len = cmd->err_info->ResidualCnt; } break; case CMD_DATA_OVERRUN: @@ -2806,7 +3018,7 @@ static void do_cciss_request(struct request_queue *q) goto startio; queue: - creq = elv_next_request(q); + creq = blk_peek_request(q); if (!creq) goto startio; @@ -2815,7 +3027,7 @@ static void do_cciss_request(struct request_queue *q) if ((c = cmd_alloc(h, 1)) == NULL) goto full; - blkdev_dequeue_request(creq); + blk_start_request(creq); spin_unlock_irq(q->queue_lock); @@ -2840,10 +3052,10 @@ static void do_cciss_request(struct request_queue *q) c->Request.Timeout = 0; // Don't time out c->Request.CDB[0] = (rq_data_dir(creq) == READ) ? h->cciss_read : h->cciss_write; - start_blk = creq->sector; + start_blk = blk_rq_pos(creq); #ifdef CCISS_DEBUG - printk(KERN_DEBUG "ciss: sector =%d nr_sectors=%d\n", (int)creq->sector, - (int)creq->nr_sectors); + printk(KERN_DEBUG "ciss: sector =%d nr_sectors=%d\n", + (int)blk_rq_pos(creq), (int)blk_rq_sectors(creq)); #endif /* CCISS_DEBUG */ sg_init_table(tmp_sg, MAXSGENTRIES); @@ -2869,8 +3081,8 @@ static void do_cciss_request(struct request_queue *q) h->maxSG = seg; #ifdef CCISS_DEBUG - printk(KERN_DEBUG "cciss: Submitting %lu sectors in %d segments\n", - creq->nr_sectors, seg); + printk(KERN_DEBUG "cciss: Submitting %u sectors in %d segments\n", + blk_rq_sectors(creq), seg); #endif /* CCISS_DEBUG */ c->Header.SGList = c->Header.SGTotal = seg; @@ -2882,8 +3094,8 @@ static void do_cciss_request(struct request_queue *q) c->Request.CDB[4] = (start_blk >> 8) & 0xff; c->Request.CDB[5] = start_blk & 0xff; c->Request.CDB[6] = 0; // (sect >> 24) & 0xff; MSB - c->Request.CDB[7] = (creq->nr_sectors >> 8) & 0xff; - c->Request.CDB[8] = creq->nr_sectors & 0xff; + c->Request.CDB[7] = (blk_rq_sectors(creq) >> 8) & 0xff; + c->Request.CDB[8] = blk_rq_sectors(creq) & 0xff; c->Request.CDB[9] = c->Request.CDB[11] = c->Request.CDB[12] = 0; } else { u32 upper32 = upper_32_bits(start_blk); @@ -2898,10 +3110,10 @@ static void do_cciss_request(struct request_queue *q) c->Request.CDB[7]= (start_blk >> 16) & 0xff; c->Request.CDB[8]= (start_blk >> 8) & 0xff; c->Request.CDB[9]= start_blk & 0xff; - c->Request.CDB[10]= (creq->nr_sectors >> 24) & 0xff; - c->Request.CDB[11]= (creq->nr_sectors >> 16) & 0xff; - c->Request.CDB[12]= (creq->nr_sectors >> 8) & 0xff; - c->Request.CDB[13]= creq->nr_sectors & 0xff; + c->Request.CDB[10]= (blk_rq_sectors(creq) >> 24) & 0xff; + c->Request.CDB[11]= (blk_rq_sectors(creq) >> 16) & 0xff; + c->Request.CDB[12]= (blk_rq_sectors(creq) >> 8) & 0xff; + c->Request.CDB[13]= blk_rq_sectors(creq) & 0xff; c->Request.CDB[14] = c->Request.CDB[15] = 0; } } else if (blk_pc_request(creq)) { @@ -2931,44 +3143,18 @@ startio: static inline unsigned long get_next_completion(ctlr_info_t *h) { -#ifdef CONFIG_CISS_SCSI_TAPE - /* Any rejects from sendcmd() lying around? Process them first */ - if (h->scsi_rejects.ncompletions == 0) - return h->access.command_completed(h); - else { - struct sendcmd_reject_list *srl; - int n; - srl = &h->scsi_rejects; - n = --srl->ncompletions; - /* printk("cciss%d: processing saved reject\n", h->ctlr); */ - printk("p"); - return srl->complete[n]; - } -#else return h->access.command_completed(h); -#endif } static inline int interrupt_pending(ctlr_info_t *h) { -#ifdef CONFIG_CISS_SCSI_TAPE - return (h->access.intr_pending(h) - || (h->scsi_rejects.ncompletions > 0)); -#else return h->access.intr_pending(h); -#endif } static inline long interrupt_not_for_us(ctlr_info_t *h) { -#ifdef CONFIG_CISS_SCSI_TAPE - return (((h->access.intr_pending(h) == 0) || - (h->interrupts_enabled == 0)) - && (h->scsi_rejects.ncompletions == 0)); -#else return (((h->access.intr_pending(h) == 0) || (h->interrupts_enabled == 0))); -#endif } static irqreturn_t do_cciss_intr(int irq, void *dev_id) @@ -3723,12 +3909,15 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, INIT_HLIST_HEAD(&hba[i]->reqQ); if (cciss_pci_init(hba[i], pdev) != 0) - goto clean1; + goto clean0; sprintf(hba[i]->devname, "cciss%d", i); hba[i]->ctlr = i; hba[i]->pdev = pdev; + if (cciss_create_hba_sysfs_entry(hba[i])) + goto clean0; + /* configure PCI DMA stuff */ if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) dac = 1; @@ -3787,15 +3976,6 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, printk(KERN_ERR "cciss: out of memory"); goto clean4; } -#ifdef CONFIG_CISS_SCSI_TAPE - hba[i]->scsi_rejects.complete = - kmalloc(sizeof(hba[i]->scsi_rejects.complete[0]) * - (hba[i]->nr_cmds + 5), GFP_KERNEL); - if (hba[i]->scsi_rejects.complete == NULL) { - printk(KERN_ERR "cciss: out of memory"); - goto clean4; - } -#endif spin_lock_init(&hba[i]->lock); /* Initialize the pdev driver private data. @@ -3828,7 +4008,7 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, } return_code = sendcmd_withirq(CISS_INQUIRY, i, inq_buff, - sizeof(InquiryData_struct), 0, 0 , 0, TYPE_CMD); + sizeof(InquiryData_struct), 0, CTLR_LUNID, TYPE_CMD); if (return_code == IO_OK) { hba[i]->firm_ver[0] = inq_buff->data_byte[32]; hba[i]->firm_ver[1] = inq_buff->data_byte[33]; @@ -3855,9 +4035,6 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, clean4: kfree(inq_buff); -#ifdef CONFIG_CISS_SCSI_TAPE - kfree(hba[i]->scsi_rejects.complete); -#endif kfree(hba[i]->cmd_pool_bits); if (hba[i]->cmd_pool) pci_free_consistent(hba[i]->pdev, @@ -3872,6 +4049,8 @@ clean4: clean2: unregister_blkdev(hba[i]->major, hba[i]->devname); clean1: + cciss_destroy_hba_sysfs_entry(hba[i]); +clean0: hba[i]->busy_initializing = 0; /* cleanup any queues that may have been initialized */ for (j=0; j <= hba[i]->highest_lun; j++){ @@ -3907,8 +4086,8 @@ static void cciss_shutdown(struct pci_dev *pdev) /* sendcmd will turn off interrupt, and send the flush... * To write all data in the battery backed cache to disks */ memset(flush_buf, 0, 4); - return_code = sendcmd(CCISS_CACHE_FLUSH, i, flush_buf, 4, 0, 0, 0, NULL, - TYPE_CMD); + return_code = sendcmd(CCISS_CACHE_FLUSH, i, flush_buf, 4, 0, + CTLR_LUNID, TYPE_CMD); if (return_code == IO_OK) { printk(KERN_INFO "Completed flushing cache on controller %d\n", i); } else { @@ -3973,15 +4152,13 @@ static void __devexit cciss_remove_one(struct pci_dev *pdev) pci_free_consistent(hba[i]->pdev, hba[i]->nr_cmds * sizeof(ErrorInfo_struct), hba[i]->errinfo_pool, hba[i]->errinfo_pool_dhandle); kfree(hba[i]->cmd_pool_bits); -#ifdef CONFIG_CISS_SCSI_TAPE - kfree(hba[i]->scsi_rejects.complete); -#endif /* * Deliberately omit pci_disable_device(): it does something nasty to * Smart Array controllers that pci_enable_device does not undo */ pci_release_regions(pdev); pci_set_drvdata(pdev, NULL); + cciss_destroy_hba_sysfs_entry(hba[i]); free_hba(i); } @@ -3999,6 +4176,8 @@ static struct pci_driver cciss_pci_driver = { */ static int __init cciss_init(void) { + int err; + /* * The hardware requires that commands are aligned on a 64-bit * boundary. Given that we use pci_alloc_consistent() to allocate an @@ -4008,8 +4187,20 @@ static int __init cciss_init(void) printk(KERN_INFO DRIVER_NAME "\n"); + err = bus_register(&cciss_bus_type); + if (err) + return err; + /* Register for our PCI devices */ - return pci_register_driver(&cciss_pci_driver); + err = pci_register_driver(&cciss_pci_driver); + if (err) + goto err_bus_register; + + return 0; + +err_bus_register: + bus_unregister(&cciss_bus_type); + return err; } static void __exit cciss_cleanup(void) @@ -4026,6 +4217,7 @@ static void __exit cciss_cleanup(void) } } remove_proc_entry("driver/cciss", NULL); + bus_unregister(&cciss_bus_type); } static void fail_all_cmds(unsigned long ctlr) diff --git a/drivers/block/cciss.h b/drivers/block/cciss.h index 703e08038fb9..06a5db25b298 100644 --- a/drivers/block/cciss.h +++ b/drivers/block/cciss.h @@ -11,6 +11,11 @@ #define IO_OK 0 #define IO_ERROR 1 +#define IO_NEEDS_RETRY 3 + +#define VENDOR_LEN 8 +#define MODEL_LEN 16 +#define REV_LEN 4 struct ctlr_info; typedef struct ctlr_info ctlr_info_t; @@ -34,23 +39,20 @@ typedef struct _drive_info_struct int cylinders; int raid_level; /* set to -1 to indicate that * the drive is not in use/configured - */ - int busy_configuring; /*This is set when the drive is being removed - *to prevent it from being opened or it's queue - *from being started. - */ - __u8 serial_no[16]; /* from inquiry page 0x83, */ - /* not necc. null terminated. */ + */ + int busy_configuring; /* This is set when a drive is being removed + * to prevent it from being opened or it's + * queue from being started. + */ + struct device dev; + __u8 serial_no[16]; /* from inquiry page 0x83, + * not necc. null terminated. + */ + char vendor[VENDOR_LEN + 1]; /* SCSI vendor string */ + char model[MODEL_LEN + 1]; /* SCSI model string */ + char rev[REV_LEN + 1]; /* SCSI revision string */ } drive_info_struct; -#ifdef CONFIG_CISS_SCSI_TAPE - -struct sendcmd_reject_list { - int ncompletions; - unsigned long *complete; /* array of NR_CMDS tags */ -}; - -#endif struct ctlr_info { int ctlr; @@ -118,11 +120,11 @@ struct ctlr_info void *scsi_ctlr; /* ptr to structure containing scsi related stuff */ /* list of block side commands the scsi error handling sucked up */ /* and saved for later processing */ - struct sendcmd_reject_list scsi_rejects; #endif unsigned char alive; struct completion *rescan_wait; struct task_struct *cciss_scan_thread; + struct device dev; }; /* Defining the diffent access_menthods */ diff --git a/drivers/block/cciss_cmd.h b/drivers/block/cciss_cmd.h index 40b1b92dae7f..cd665b00c7c5 100644 --- a/drivers/block/cciss_cmd.h +++ b/drivers/block/cciss_cmd.h @@ -217,6 +217,8 @@ typedef union _LUNAddr_struct { LogDevAddr_struct LogDev; } LUNAddr_struct; +#define CTLR_LUNID "\0\0\0\0\0\0\0\0" + typedef struct _CommandListHeader_struct { BYTE ReplyQueue; BYTE SGList; diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c index a3fd87b41444..3315268b4ec7 100644 --- a/drivers/block/cciss_scsi.c +++ b/drivers/block/cciss_scsi.c @@ -44,20 +44,13 @@ #define CCISS_ABORT_MSG 0x00 #define CCISS_RESET_MSG 0x01 -/* some prototypes... */ -static int sendcmd( - __u8 cmd, - int ctlr, - void *buff, - size_t size, - unsigned int use_unit_num, /* 0: address the controller, - 1: address logical volume log_unit, - 2: address is in scsi3addr */ - unsigned int log_unit, - __u8 page_code, - unsigned char *scsi3addr, +static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, + size_t size, + __u8 page_code, unsigned char *scsi3addr, int cmd_type); +static CommandList_struct *cmd_alloc(ctlr_info_t *h, int get_from_pool); +static void cmd_free(ctlr_info_t *h, CommandList_struct *c, int got_from_pool); static int cciss_scsi_proc_info( struct Scsi_Host *sh, @@ -1575,6 +1568,75 @@ cciss_seq_tape_report(struct seq_file *seq, int ctlr) CPQ_TAPE_UNLOCK(ctlr, flags); } +static int wait_for_device_to_become_ready(ctlr_info_t *h, + unsigned char lunaddr[]) +{ + int rc; + int count = 0; + int waittime = HZ; + CommandList_struct *c; + + c = cmd_alloc(h, 1); + if (!c) { + printk(KERN_WARNING "cciss%d: out of memory in " + "wait_for_device_to_become_ready.\n", h->ctlr); + return IO_ERROR; + } + + /* Send test unit ready until device ready, or give up. */ + while (count < 20) { + + /* Wait for a bit. do this first, because if we send + * the TUR right away, the reset will just abort it. + */ + schedule_timeout_uninterruptible(waittime); + count++; + + /* Increase wait time with each try, up to a point. */ + if (waittime < (HZ * 30)) + waittime = waittime * 2; + + /* Send the Test Unit Ready */ + rc = fill_cmd(c, TEST_UNIT_READY, h->ctlr, NULL, 0, 0, + lunaddr, TYPE_CMD); + if (rc == 0) + rc = sendcmd_withirq_core(h, c, 0); + + (void) process_sendcmd_error(h, c); + + if (rc != 0) + goto retry_tur; + + if (c->err_info->CommandStatus == CMD_SUCCESS) + break; + + if (c->err_info->CommandStatus == CMD_TARGET_STATUS && + c->err_info->ScsiStatus == SAM_STAT_CHECK_CONDITION) { + if (c->err_info->SenseInfo[2] == NO_SENSE) + break; + if (c->err_info->SenseInfo[2] == UNIT_ATTENTION) { + unsigned char asc; + asc = c->err_info->SenseInfo[12]; + check_for_unit_attention(h, c); + if (asc == POWER_OR_RESET) + break; + } + } +retry_tur: + printk(KERN_WARNING "cciss%d: Waiting %d secs " + "for device to become ready.\n", + h->ctlr, waittime / HZ); + rc = 1; /* device not ready. */ + } + + if (rc) + printk("cciss%d: giving up on device.\n", h->ctlr); + else + printk(KERN_WARNING "cciss%d: device is ready.\n", h->ctlr); + + cmd_free(h, c, 1); + return rc; +} /* Need at least one of these error handlers to keep ../scsi/hosts.c from * complaining. Doing a host- or bus-reset can't do anything good here. @@ -1591,6 +1653,7 @@ static int cciss_eh_device_reset_handler(struct scsi_cmnd *scsicmd) { int rc; CommandList_struct *cmd_in_trouble; + unsigned char lunaddr[8]; ctlr_info_t **c; int ctlr; @@ -1600,19 +1663,15 @@ static int cciss_eh_device_reset_handler(struct scsi_cmnd *scsicmd) return FAILED; ctlr = (*c)->ctlr; printk(KERN_WARNING "cciss%d: resetting tape drive or medium changer.\n", ctlr); - /* find the command that's giving us trouble */ cmd_in_trouble = (CommandList_struct *) scsicmd->host_scribble; - if (cmd_in_trouble == NULL) { /* paranoia */ + if (cmd_in_trouble == NULL) /* paranoia */ return FAILED; - } + memcpy(lunaddr, &cmd_in_trouble->Header.LUN.LunAddrBytes[0], 8); /* send a reset to the SCSI LUN which the command was sent to */ - rc = sendcmd(CCISS_RESET_MSG, ctlr, NULL, 0, 2, 0, 0, - (unsigned char *) &cmd_in_trouble->Header.LUN.LunAddrBytes[0], + rc = sendcmd_withirq(CCISS_RESET_MSG, ctlr, NULL, 0, 0, lunaddr, TYPE_MSG); - /* sendcmd turned off interrupts on the board, turn 'em back on. */ - (*c)->access.set_intr_mask(*c, CCISS_INTR_ON); - if (rc == 0) + if (rc == 0 && wait_for_device_to_become_ready(*c, lunaddr) == 0) return SUCCESS; printk(KERN_WARNING "cciss%d: resetting device failed.\n", ctlr); return FAILED; @@ -1622,6 +1681,7 @@ static int cciss_eh_abort_handler(struct scsi_cmnd *scsicmd) { int rc; CommandList_struct *cmd_to_abort; + unsigned char lunaddr[8]; ctlr_info_t **c; int ctlr; @@ -1636,12 +1696,9 @@ static int cciss_eh_abort_handler(struct scsi_cmnd *scsicmd) cmd_to_abort = (CommandList_struct *) scsicmd->host_scribble; if (cmd_to_abort == NULL) /* paranoia */ return FAILED; - rc = sendcmd(CCISS_ABORT_MSG, ctlr, &cmd_to_abort->Header.Tag, - 0, 2, 0, 0, - (unsigned char *) &cmd_to_abort->Header.LUN.LunAddrBytes[0], - TYPE_MSG); - /* sendcmd turned off interrupts on the board, turn 'em back on. */ - (*c)->access.set_intr_mask(*c, CCISS_INTR_ON); + memcpy(lunaddr, &cmd_to_abort->Header.LUN.LunAddrBytes[0], 8); + rc = sendcmd_withirq(CCISS_ABORT_MSG, ctlr, &cmd_to_abort->Header.Tag, + 0, 0, lunaddr, TYPE_MSG); if (rc == 0) return SUCCESS; return FAILED; diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c index ca268ca11159..44fa2018f6b0 100644 --- a/drivers/block/cpqarray.c +++ b/drivers/block/cpqarray.c @@ -474,7 +474,7 @@ static int __init cpqarray_register_ctlr( int i, struct pci_dev *pdev) disk->fops = &ida_fops; if (j && !drv->nr_blks) continue; - blk_queue_hardsect_size(hba[i]->queue, drv->blk_size); + blk_queue_logical_block_size(hba[i]->queue, drv->blk_size); set_capacity(disk, drv->nr_blks); disk->queue = hba[i]->queue; disk->private_data = drv; @@ -903,7 +903,7 @@ static void do_ida_request(struct request_queue *q) goto startio; queue_next: - creq = elv_next_request(q); + creq = blk_peek_request(q); if (!creq) goto startio; @@ -912,17 +912,18 @@ queue_next: if ((c = cmd_alloc(h,1)) == NULL) goto startio; - blkdev_dequeue_request(creq); + blk_start_request(creq); c->ctlr = h->ctlr; c->hdr.unit = (drv_info_t *)(creq->rq_disk->private_data) - h->drv; c->hdr.size = sizeof(rblk_t) >> 2; c->size += sizeof(rblk_t); - c->req.hdr.blk = creq->sector; + c->req.hdr.blk = blk_rq_pos(creq); c->rq = creq; DBGPX( - printk("sector=%d, nr_sectors=%d\n", creq->sector, creq->nr_sectors); + printk("sector=%d, nr_sectors=%u\n", + blk_rq_pos(creq), blk_rq_sectors(creq)); ); sg_init_table(tmp_sg, SG_MAX); seg = blk_rq_map_sg(q, creq, tmp_sg); @@ -940,9 +941,9 @@ DBGPX( tmp_sg[i].offset, tmp_sg[i].length, dir); } -DBGPX( printk("Submitting %d sectors in %d segments\n", creq->nr_sectors, seg); ); +DBGPX( printk("Submitting %u sectors in %d segments\n", blk_rq_sectors(creq), seg); ); c->req.hdr.sg_cnt = seg; - c->req.hdr.blk_cnt = creq->nr_sectors; + c->req.hdr.blk_cnt = blk_rq_sectors(creq); c->req.hdr.cmd = (rq_data_dir(creq) == READ) ? IDA_READ : IDA_WRITE; c->type = CMD_RWREQ; @@ -1024,8 +1025,7 @@ static inline void complete_command(cmdlist_t *cmd, int timeout) cmd->req.sg[i].size, ddir); DBGPX(printk("Done with %p\n", rq);); - if (__blk_end_request(rq, error, blk_rq_bytes(rq))) - BUG(); + __blk_end_request_all(rq, error); } /* @@ -1546,7 +1546,7 @@ static int revalidate_allvol(ctlr_info_t *host) drv_info_t *drv = &host->drv[i]; if (i && !drv->nr_blks) continue; - blk_queue_hardsect_size(host->queue, drv->blk_size); + blk_queue_logical_block_size(host->queue, drv->blk_size); set_capacity(disk, drv->nr_blks); disk->queue = host->queue; disk->private_data = drv; diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 1300df6f1642..862b40c90181 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -931,7 +931,7 @@ static inline void unlock_fdc(void) del_timer(&fd_timeout); cont = NULL; clear_bit(0, &fdc_busy); - if (elv_next_request(floppy_queue)) + if (current_req || blk_peek_request(floppy_queue)) do_fd_request(floppy_queue); spin_unlock_irqrestore(&floppy_lock, flags); wake_up(&fdc_wait); @@ -2303,7 +2303,7 @@ static void floppy_end_request(struct request *req, int error) /* current_count_sectors can be zero if transfer failed */ if (error) - nr_sectors = req->current_nr_sectors; + nr_sectors = blk_rq_cur_sectors(req); if (__blk_end_request(req, error, nr_sectors << 9)) return; @@ -2332,7 +2332,7 @@ static void request_done(int uptodate) if (uptodate) { /* maintain values for invalidation on geometry * change */ - block = current_count_sectors + req->sector; + block = current_count_sectors + blk_rq_pos(req); INFBOUND(DRS->maxblock, block); if (block > _floppy->sect) DRS->maxtrack = 1; @@ -2346,10 +2346,10 @@ static void request_done(int uptodate) /* record write error information */ DRWE->write_errors++; if (DRWE->write_errors == 1) { - DRWE->first_error_sector = req->sector; + DRWE->first_error_sector = blk_rq_pos(req); DRWE->first_error_generation = DRS->generation; } - DRWE->last_error_sector = req->sector; + DRWE->last_error_sector = blk_rq_pos(req); DRWE->last_error_generation = DRS->generation; } spin_lock_irqsave(q->queue_lock, flags); @@ -2503,24 +2503,23 @@ static void copy_buffer(int ssize, int max_sector, int max_sector_2) max_sector = transfer_size(ssize, min(max_sector, max_sector_2), - current_req->nr_sectors); + blk_rq_sectors(current_req)); if (current_count_sectors <= 0 && CT(COMMAND) == FD_WRITE && - buffer_max > fsector_t + current_req->nr_sectors) + buffer_max > fsector_t + blk_rq_sectors(current_req)) current_count_sectors = min_t(int, buffer_max - fsector_t, - current_req->nr_sectors); + blk_rq_sectors(current_req)); remaining = current_count_sectors << 9; #ifdef FLOPPY_SANITY_CHECK - if ((remaining >> 9) > current_req->nr_sectors && - CT(COMMAND) == FD_WRITE) { + if (remaining > blk_rq_bytes(current_req) && CT(COMMAND) == FD_WRITE) { DPRINT("in copy buffer\n"); printk("current_count_sectors=%ld\n", current_count_sectors); printk("remaining=%d\n", remaining >> 9); - printk("current_req->nr_sectors=%ld\n", - current_req->nr_sectors); + printk("current_req->nr_sectors=%u\n", + blk_rq_sectors(current_req)); printk("current_req->current_nr_sectors=%u\n", - current_req->current_nr_sectors); + blk_rq_cur_sectors(current_req)); printk("max_sector=%d\n", max_sector); printk("ssize=%d\n", ssize); } @@ -2530,7 +2529,7 @@ static void copy_buffer(int ssize, int max_sector, int max_sector_2) dma_buffer = floppy_track_buffer + ((fsector_t - buffer_min) << 9); - size = current_req->current_nr_sectors << 9; + size = blk_rq_cur_bytes(current_req); rq_for_each_segment(bv, current_req, iter) { if (!remaining) @@ -2648,10 +2647,10 @@ static int make_raw_rw_request(void) max_sector = _floppy->sect * _floppy->head; - TRACK = (int)current_req->sector / max_sector; - fsector_t = (int)current_req->sector % max_sector; + TRACK = (int)blk_rq_pos(current_req) / max_sector; + fsector_t = (int)blk_rq_pos(current_req) % max_sector; if (_floppy->track && TRACK >= _floppy->track) { - if (current_req->current_nr_sectors & 1) { + if (blk_rq_cur_sectors(current_req) & 1) { current_count_sectors = 1; return 1; } else @@ -2669,7 +2668,7 @@ static int make_raw_rw_request(void) if (fsector_t >= max_sector) { current_count_sectors = min_t(int, _floppy->sect - fsector_t, - current_req->nr_sectors); + blk_rq_sectors(current_req)); return 1; } SIZECODE = 2; @@ -2720,7 +2719,7 @@ static int make_raw_rw_request(void) in_sector_offset = (fsector_t % _floppy->sect) % ssize; aligned_sector_t = fsector_t - in_sector_offset; - max_size = current_req->nr_sectors; + max_size = blk_rq_sectors(current_req); if ((raw_cmd->track == buffer_track) && (current_drive == buffer_drive) && (fsector_t >= buffer_min) && (fsector_t < buffer_max)) { @@ -2729,10 +2728,10 @@ static int make_raw_rw_request(void) copy_buffer(1, max_sector, buffer_max); return 1; } - } else if (in_sector_offset || current_req->nr_sectors < ssize) { + } else if (in_sector_offset || blk_rq_sectors(current_req) < ssize) { if (CT(COMMAND) == FD_WRITE) { - if (fsector_t + current_req->nr_sectors > ssize && - fsector_t + current_req->nr_sectors < ssize + ssize) + if (fsector_t + blk_rq_sectors(current_req) > ssize && + fsector_t + blk_rq_sectors(current_req) < ssize + ssize) max_size = ssize + ssize; else max_size = ssize; @@ -2776,7 +2775,7 @@ static int make_raw_rw_request(void) (indirect * 2 > direct * 3 && *errors < DP->max_errors.read_track && ((!probing || (DP->read_track & (1 << DRS->probed_format)))))) { - max_size = current_req->nr_sectors; + max_size = blk_rq_sectors(current_req); } else { raw_cmd->kernel_data = current_req->buffer; raw_cmd->length = current_count_sectors << 9; @@ -2801,7 +2800,7 @@ static int make_raw_rw_request(void) fsector_t > buffer_max || fsector_t < buffer_min || ((CT(COMMAND) == FD_READ || - (!in_sector_offset && current_req->nr_sectors >= ssize)) && + (!in_sector_offset && blk_rq_sectors(current_req) >= ssize)) && max_sector > 2 * max_buffer_sectors + buffer_min && max_size + fsector_t > 2 * max_buffer_sectors + buffer_min) /* not enough space */ @@ -2879,8 +2878,8 @@ static int make_raw_rw_request(void) printk("write\n"); return 0; } - } else if (raw_cmd->length > current_req->nr_sectors << 9 || - current_count_sectors > current_req->nr_sectors) { + } else if (raw_cmd->length > blk_rq_bytes(current_req) || + current_count_sectors > blk_rq_sectors(current_req)) { DPRINT("buffer overrun in direct transfer\n"); return 0; } else if (raw_cmd->length < current_count_sectors << 9) { @@ -2913,7 +2912,7 @@ static void redo_fd_request(void) struct request *req; spin_lock_irq(floppy_queue->queue_lock); - req = elv_next_request(floppy_queue); + req = blk_fetch_request(floppy_queue); spin_unlock_irq(floppy_queue->queue_lock); if (!req) { do_floppy = NULL; @@ -2990,8 +2989,9 @@ static void do_fd_request(struct request_queue * q) if (usage_count == 0) { printk("warning: usage count=0, current_req=%p exiting\n", current_req); - printk("sect=%ld type=%x flags=%x\n", (long)current_req->sector, - current_req->cmd_type, current_req->cmd_flags); + printk("sect=%ld type=%x flags=%x\n", + (long)blk_rq_pos(current_req), current_req->cmd_type, + current_req->cmd_flags); return; } if (test_bit(0, &fdc_busy)) { @@ -4148,6 +4148,24 @@ static void floppy_device_release(struct device *dev) { } +static int floppy_resume(struct platform_device *dev) +{ + int fdc; + + for (fdc = 0; fdc < N_FDC; fdc++) + if (FDCS->address != -1) + user_reset_fdc(-1, FD_RESET_ALWAYS, 0); + + return 0; +} + +static struct platform_driver floppy_driver = { + .resume = floppy_resume, + .driver = { + .name = "floppy", + }, +}; + static struct platform_device floppy_device[N_DRIVE]; static struct kobject *floppy_find(dev_t dev, int *part, void *data) @@ -4196,10 +4214,14 @@ static int __init floppy_init(void) if (err) goto out_put_disk; + err = platform_driver_register(&floppy_driver); + if (err) + goto out_unreg_blkdev; + floppy_queue = blk_init_queue(do_fd_request, &floppy_lock); if (!floppy_queue) { err = -ENOMEM; - goto out_unreg_blkdev; + goto out_unreg_driver; } blk_queue_max_sectors(floppy_queue, 64); @@ -4346,6 +4368,8 @@ out_flush_work: out_unreg_region: blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256); blk_cleanup_queue(floppy_queue); +out_unreg_driver: + platform_driver_unregister(&floppy_driver); out_unreg_blkdev: unregister_blkdev(FLOPPY_MAJOR, "fd"); out_put_disk: @@ -4566,6 +4590,7 @@ static void __exit floppy_module_exit(void) blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256); unregister_blkdev(FLOPPY_MAJOR, "fd"); + platform_driver_unregister(&floppy_driver); for (drive = 0; drive < N_DRIVE; drive++) { del_timer_sync(&motor_off_timer[drive]); diff --git a/drivers/block/hd.c b/drivers/block/hd.c index baaa9e486e50..f9d01608cbe2 100644 --- a/drivers/block/hd.c +++ b/drivers/block/hd.c @@ -98,10 +98,7 @@ static DEFINE_SPINLOCK(hd_lock); static struct request_queue *hd_queue; - -#define MAJOR_NR HD_MAJOR -#define QUEUE (hd_queue) -#define CURRENT elv_next_request(hd_queue) +static struct request *hd_req; #define TIMEOUT_VALUE (6*HZ) #define HD_DELAY 0 @@ -195,11 +192,24 @@ static void __init hd_setup(char *str, int *ints) NR_HD = hdind+1; } +static bool hd_end_request(int err, unsigned int bytes) +{ + if (__blk_end_request(hd_req, err, bytes)) + return true; + hd_req = NULL; + return false; +} + +static bool hd_end_request_cur(int err) +{ + return hd_end_request(err, blk_rq_cur_bytes(hd_req)); +} + static void dump_status(const char *msg, unsigned int stat) { char *name = "hd?"; - if (CURRENT) - name = CURRENT->rq_disk->disk_name; + if (hd_req) + name = hd_req->rq_disk->disk_name; #ifdef VERBOSE_ERRORS printk("%s: %s: status=0x%02x { ", name, msg, stat & 0xff); @@ -227,8 +237,8 @@ static void dump_status(const char *msg, unsigned int stat) if (hd_error & (BBD_ERR|ECC_ERR|ID_ERR|MARK_ERR)) { printk(", CHS=%d/%d/%d", (inb(HD_HCYL)<<8) + inb(HD_LCYL), inb(HD_CURRENT) & 0xf, inb(HD_SECTOR)); - if (CURRENT) - printk(", sector=%ld", CURRENT->sector); + if (hd_req) + printk(", sector=%ld", blk_rq_pos(hd_req)); } printk("\n"); } @@ -406,11 +416,12 @@ static void unexpected_hd_interrupt(void) */ static void bad_rw_intr(void) { - struct request *req = CURRENT; + struct request *req = hd_req; + if (req != NULL) { struct hd_i_struct *disk = req->rq_disk->private_data; if (++req->errors >= MAX_ERRORS || (hd_error & BBD_ERR)) { - end_request(req, 0); + hd_end_request_cur(-EIO); disk->special_op = disk->recalibrate = 1; } else if (req->errors % RESET_FREQ == 0) reset = 1; @@ -452,37 +463,30 @@ static void read_intr(void) bad_rw_intr(); hd_request(); return; + ok_to_read: - req = CURRENT; + req = hd_req; insw(HD_DATA, req->buffer, 256); - req->sector++; - req->buffer += 512; - req->errors = 0; - i = --req->nr_sectors; - --req->current_nr_sectors; #ifdef DEBUG - printk("%s: read: sector %ld, remaining = %ld, buffer=%p\n", - req->rq_disk->disk_name, req->sector, req->nr_sectors, - req->buffer+512); + printk("%s: read: sector %ld, remaining = %u, buffer=%p\n", + req->rq_disk->disk_name, blk_rq_pos(req) + 1, + blk_rq_sectors(req) - 1, req->buffer+512); #endif - if (req->current_nr_sectors <= 0) - end_request(req, 1); - if (i > 0) { + if (hd_end_request(0, 512)) { SET_HANDLER(&read_intr); return; } + (void) inb_p(HD_STATUS); #if (HD_DELAY > 0) last_req = read_timer(); #endif - if (elv_next_request(QUEUE)) - hd_request(); - return; + hd_request(); } static void write_intr(void) { - struct request *req = CURRENT; + struct request *req = hd_req; int i; int retries = 100000; @@ -492,30 +496,25 @@ static void write_intr(void) continue; if (!OK_STATUS(i)) break; - if ((req->nr_sectors <= 1) || (i & DRQ_STAT)) + if ((blk_rq_sectors(req) <= 1) || (i & DRQ_STAT)) goto ok_to_write; } while (--retries > 0); dump_status("write_intr", i); bad_rw_intr(); hd_request(); return; + ok_to_write: - req->sector++; - i = --req->nr_sectors; - --req->current_nr_sectors; - req->buffer += 512; - if (!i || (req->bio && req->current_nr_sectors <= 0)) - end_request(req, 1); - if (i > 0) { + if (hd_end_request(0, 512)) { SET_HANDLER(&write_intr); outsw(HD_DATA, req->buffer, 256); - } else { -#if (HD_DELAY > 0) - last_req = read_timer(); -#endif - hd_request(); + return; } - return; + +#if (HD_DELAY > 0) + last_req = read_timer(); +#endif + hd_request(); } static void recal_intr(void) @@ -537,18 +536,18 @@ static void hd_times_out(unsigned long dummy) do_hd = NULL; - if (!CURRENT) + if (!hd_req) return; spin_lock_irq(hd_queue->queue_lock); reset = 1; - name = CURRENT->rq_disk->disk_name; + name = hd_req->rq_disk->disk_name; printk("%s: timeout\n", name); - if (++CURRENT->errors >= MAX_ERRORS) { + if (++hd_req->errors >= MAX_ERRORS) { #ifdef DEBUG printk("%s: too many errors\n", name); #endif - end_request(CURRENT, 0); + hd_end_request_cur(-EIO); } hd_request(); spin_unlock_irq(hd_queue->queue_lock); @@ -563,7 +562,7 @@ static int do_special_op(struct hd_i_struct *disk, struct request *req) } if (disk->head > 16) { printk("%s: cannot handle device with more than 16 heads - giving up\n", req->rq_disk->disk_name); - end_request(req, 0); + hd_end_request_cur(-EIO); } disk->special_op = 0; return 1; @@ -590,24 +589,27 @@ static void hd_request(void) repeat: del_timer(&device_timer); - req = CURRENT; - if (!req) { - do_hd = NULL; - return; + if (!hd_req) { + hd_req = blk_fetch_request(hd_queue); + if (!hd_req) { + do_hd = NULL; + return; + } } + req = hd_req; if (reset) { reset_hd(); return; } disk = req->rq_disk->private_data; - block = req->sector; - nsect = req->nr_sectors; + block = blk_rq_pos(req); + nsect = blk_rq_sectors(req); if (block >= get_capacity(req->rq_disk) || ((block+nsect) > get_capacity(req->rq_disk))) { printk("%s: bad access: block=%d, count=%d\n", req->rq_disk->disk_name, block, nsect); - end_request(req, 0); + hd_end_request_cur(-EIO); goto repeat; } @@ -647,7 +649,7 @@ repeat: break; default: printk("unknown hd-command\n"); - end_request(req, 0); + hd_end_request_cur(-EIO); break; } } @@ -708,19 +710,19 @@ static int __init hd_init(void) { int drive; - if (register_blkdev(MAJOR_NR, "hd")) + if (register_blkdev(HD_MAJOR, "hd")) return -1; hd_queue = blk_init_queue(do_hd_request, &hd_lock); if (!hd_queue) { - unregister_blkdev(MAJOR_NR, "hd"); + unregister_blkdev(HD_MAJOR, "hd"); return -ENOMEM; } blk_queue_max_sectors(hd_queue, 255); init_timer(&device_timer); device_timer.function = hd_times_out; - blk_queue_hardsect_size(hd_queue, 512); + blk_queue_logical_block_size(hd_queue, 512); if (!NR_HD) { /* @@ -747,7 +749,7 @@ static int __init hd_init(void) struct hd_i_struct *p = &hd_info[drive]; if (!disk) goto Enomem; - disk->major = MAJOR_NR; + disk->major = HD_MAJOR; disk->first_minor = drive << 6; disk->fops = &hd_fops; sprintf(disk->disk_name, "hd%c", 'a'+drive); @@ -791,7 +793,7 @@ out1: NR_HD = 0; out: del_timer(&device_timer); - unregister_blkdev(MAJOR_NR, "hd"); + unregister_blkdev(HD_MAJOR, "hd"); blk_cleanup_queue(hd_queue); return -1; Enomem: diff --git a/drivers/block/loop.c b/drivers/block/loop.c index ddae80825899..801f4ab83302 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -511,11 +511,7 @@ out: */ static void loop_add_bio(struct loop_device *lo, struct bio *bio) { - if (lo->lo_biotail) { - lo->lo_biotail->bi_next = bio; - lo->lo_biotail = bio; - } else - lo->lo_bio = lo->lo_biotail = bio; + bio_list_add(&lo->lo_bio_list, bio); } /* @@ -523,16 +519,7 @@ static void loop_add_bio(struct loop_device *lo, struct bio *bio) */ static struct bio *loop_get_bio(struct loop_device *lo) { - struct bio *bio; - - if ((bio = lo->lo_bio)) { - if (bio == lo->lo_biotail) - lo->lo_biotail = NULL; - lo->lo_bio = bio->bi_next; - bio->bi_next = NULL; - } - - return bio; + return bio_list_pop(&lo->lo_bio_list); } static int loop_make_request(struct request_queue *q, struct bio *old_bio) @@ -609,12 +596,13 @@ static int loop_thread(void *data) set_user_nice(current, -20); - while (!kthread_should_stop() || lo->lo_bio) { + while (!kthread_should_stop() || !bio_list_empty(&lo->lo_bio_list)) { wait_event_interruptible(lo->lo_event, - lo->lo_bio || kthread_should_stop()); + !bio_list_empty(&lo->lo_bio_list) || + kthread_should_stop()); - if (!lo->lo_bio) + if (bio_list_empty(&lo->lo_bio_list)) continue; spin_lock_irq(&lo->lo_lock); bio = loop_get_bio(lo); @@ -721,10 +709,6 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev, if (!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode)) goto out_putf; - /* new backing store needs to support loop (eg splice_read) */ - if (!inode->i_fop->splice_read) - goto out_putf; - /* size of the new backing store needs to be the same */ if (get_loop_size(lo, file) != get_loop_size(lo, old_file)) goto out_putf; @@ -800,12 +784,7 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode, error = -EINVAL; if (S_ISREG(inode->i_mode) || S_ISBLK(inode->i_mode)) { const struct address_space_operations *aops = mapping->a_ops; - /* - * If we can't read - sorry. If we only can't write - well, - * it's going to be read-only. - */ - if (!file->f_op->splice_read) - goto out_putf; + if (aops->write_begin) lo_flags |= LO_FLAGS_USE_AOPS; if (!(lo_flags & LO_FLAGS_USE_AOPS) && !file->f_op->write) @@ -841,7 +820,7 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode, lo->old_gfp_mask = mapping_gfp_mask(mapping); mapping_set_gfp_mask(mapping, lo->old_gfp_mask & ~(__GFP_IO|__GFP_FS)); - lo->lo_bio = lo->lo_biotail = NULL; + bio_list_init(&lo->lo_bio_list); /* * set queue make_request_fn, and add limits based on lower level diff --git a/drivers/block/mg_disk.c b/drivers/block/mg_disk.c index f3898353d0a8..f703f5478246 100644 --- a/drivers/block/mg_disk.c +++ b/drivers/block/mg_disk.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include @@ -26,62 +26,185 @@ #define MG_RES_SEC (CONFIG_MG_DISK_RES << 1) +/* name for block device */ +#define MG_DISK_NAME "mgd" + +#define MG_DISK_MAJ 0 +#define MG_DISK_MAX_PART 16 +#define MG_SECTOR_SIZE 512 +#define MG_MAX_SECTS 256 + +/* Register offsets */ +#define MG_BUFF_OFFSET 0x8000 +#define MG_STORAGE_BUFFER_SIZE 0x200 +#define MG_REG_OFFSET 0xC000 +#define MG_REG_FEATURE (MG_REG_OFFSET + 2) /* write case */ +#define MG_REG_ERROR (MG_REG_OFFSET + 2) /* read case */ +#define MG_REG_SECT_CNT (MG_REG_OFFSET + 4) +#define MG_REG_SECT_NUM (MG_REG_OFFSET + 6) +#define MG_REG_CYL_LOW (MG_REG_OFFSET + 8) +#define MG_REG_CYL_HIGH (MG_REG_OFFSET + 0xA) +#define MG_REG_DRV_HEAD (MG_REG_OFFSET + 0xC) +#define MG_REG_COMMAND (MG_REG_OFFSET + 0xE) /* write case */ +#define MG_REG_STATUS (MG_REG_OFFSET + 0xE) /* read case */ +#define MG_REG_DRV_CTRL (MG_REG_OFFSET + 0x10) +#define MG_REG_BURST_CTRL (MG_REG_OFFSET + 0x12) + +/* handy status */ +#define MG_STAT_READY (ATA_DRDY | ATA_DSC) +#define MG_READY_OK(s) (((s) & (MG_STAT_READY | (ATA_BUSY | ATA_DF | \ + ATA_ERR))) == MG_STAT_READY) + +/* error code for others */ +#define MG_ERR_NONE 0 +#define MG_ERR_TIMEOUT 0x100 +#define MG_ERR_INIT_STAT 0x101 +#define MG_ERR_TRANSLATION 0x102 +#define MG_ERR_CTRL_RST 0x103 +#define MG_ERR_INV_STAT 0x104 +#define MG_ERR_RSTOUT 0x105 + +#define MG_MAX_ERRORS 6 /* Max read/write errors */ + +/* command */ +#define MG_CMD_RD 0x20 +#define MG_CMD_WR 0x30 +#define MG_CMD_SLEEP 0x99 +#define MG_CMD_WAKEUP 0xC3 +#define MG_CMD_ID 0xEC +#define MG_CMD_WR_CONF 0x3C +#define MG_CMD_RD_CONF 0x40 + +/* operation mode */ +#define MG_OP_CASCADE (1 << 0) +#define MG_OP_CASCADE_SYNC_RD (1 << 1) +#define MG_OP_CASCADE_SYNC_WR (1 << 2) +#define MG_OP_INTERLEAVE (1 << 3) + +/* synchronous */ +#define MG_BURST_LAT_4 (3 << 4) +#define MG_BURST_LAT_5 (4 << 4) +#define MG_BURST_LAT_6 (5 << 4) +#define MG_BURST_LAT_7 (6 << 4) +#define MG_BURST_LAT_8 (7 << 4) +#define MG_BURST_LEN_4 (1 << 1) +#define MG_BURST_LEN_8 (2 << 1) +#define MG_BURST_LEN_16 (3 << 1) +#define MG_BURST_LEN_32 (4 << 1) +#define MG_BURST_LEN_CONT (0 << 1) + +/* timeout value (unit: ms) */ +#define MG_TMAX_CONF_TO_CMD 1 +#define MG_TMAX_WAIT_RD_DRQ 10 +#define MG_TMAX_WAIT_WR_DRQ 500 +#define MG_TMAX_RST_TO_BUSY 10 +#define MG_TMAX_HDRST_TO_RDY 500 +#define MG_TMAX_SWRST_TO_RDY 500 +#define MG_TMAX_RSTOUT 3000 + +#define MG_DEV_MASK (MG_BOOT_DEV | MG_STORAGE_DEV | MG_STORAGE_DEV_SKIP_RST) + +/* main structure for mflash driver */ +struct mg_host { + struct device *dev; + + struct request_queue *breq; + struct request *req; + spinlock_t lock; + struct gendisk *gd; + + struct timer_list timer; + void (*mg_do_intr) (struct mg_host *); + + u16 id[ATA_ID_WORDS]; + + u16 cyls; + u16 heads; + u16 sectors; + u32 n_sectors; + u32 nres_sectors; + + void __iomem *dev_base; + unsigned int irq; + unsigned int rst; + unsigned int rstout; + + u32 major; + u32 error; +}; + +/* + * Debugging macro and defines + */ +#undef DO_MG_DEBUG +#ifdef DO_MG_DEBUG +# define MG_DBG(fmt, args...) \ + printk(KERN_DEBUG "%s:%d "fmt, __func__, __LINE__, ##args) +#else /* CONFIG_MG_DEBUG */ +# define MG_DBG(fmt, args...) do { } while (0) +#endif /* CONFIG_MG_DEBUG */ + static void mg_request(struct request_queue *); +static bool mg_end_request(struct mg_host *host, int err, unsigned int nr_bytes) +{ + if (__blk_end_request(host->req, err, nr_bytes)) + return true; + + host->req = NULL; + return false; +} + +static bool mg_end_request_cur(struct mg_host *host, int err) +{ + return mg_end_request(host, err, blk_rq_cur_bytes(host->req)); +} + static void mg_dump_status(const char *msg, unsigned int stat, struct mg_host *host) { char *name = MG_DISK_NAME; - struct request *req; - if (host->breq) { - req = elv_next_request(host->breq); - if (req) - name = req->rq_disk->disk_name; - } + if (host->req) + name = host->req->rq_disk->disk_name; printk(KERN_ERR "%s: %s: status=0x%02x { ", name, msg, stat & 0xff); - if (stat & MG_REG_STATUS_BIT_BUSY) + if (stat & ATA_BUSY) printk("Busy "); - if (stat & MG_REG_STATUS_BIT_READY) + if (stat & ATA_DRDY) printk("DriveReady "); - if (stat & MG_REG_STATUS_BIT_WRITE_FAULT) + if (stat & ATA_DF) printk("WriteFault "); - if (stat & MG_REG_STATUS_BIT_SEEK_DONE) + if (stat & ATA_DSC) printk("SeekComplete "); - if (stat & MG_REG_STATUS_BIT_DATA_REQ) + if (stat & ATA_DRQ) printk("DataRequest "); - if (stat & MG_REG_STATUS_BIT_CORRECTED_ERROR) + if (stat & ATA_CORR) printk("CorrectedError "); - if (stat & MG_REG_STATUS_BIT_ERROR) + if (stat & ATA_ERR) printk("Error "); printk("}\n"); - if ((stat & MG_REG_STATUS_BIT_ERROR) == 0) { + if ((stat & ATA_ERR) == 0) { host->error = 0; } else { host->error = inb((unsigned long)host->dev_base + MG_REG_ERROR); printk(KERN_ERR "%s: %s: error=0x%02x { ", name, msg, host->error & 0xff); - if (host->error & MG_REG_ERR_BBK) + if (host->error & ATA_BBK) printk("BadSector "); - if (host->error & MG_REG_ERR_UNC) + if (host->error & ATA_UNC) printk("UncorrectableError "); - if (host->error & MG_REG_ERR_IDNF) + if (host->error & ATA_IDNF) printk("SectorIdNotFound "); - if (host->error & MG_REG_ERR_ABRT) + if (host->error & ATA_ABORTED) printk("DriveStatusError "); - if (host->error & MG_REG_ERR_AMNF) + if (host->error & ATA_AMNF) printk("AddrMarkNotFound "); printk("}"); - if (host->error & - (MG_REG_ERR_BBK | MG_REG_ERR_UNC | - MG_REG_ERR_IDNF | MG_REG_ERR_AMNF)) { - if (host->breq) { - req = elv_next_request(host->breq); - if (req) - printk(", sector=%u", (u32)req->sector); - } - + if (host->error & (ATA_BBK | ATA_UNC | ATA_IDNF | ATA_AMNF)) { + if (host->req) + printk(", sector=%u", + (unsigned int)blk_rq_pos(host->req)); } printk("\n"); } @@ -100,12 +223,12 @@ static unsigned int mg_wait(struct mg_host *host, u32 expect, u32 msec) do { cur_jiffies = jiffies; - if (status & MG_REG_STATUS_BIT_BUSY) { - if (expect == MG_REG_STATUS_BIT_BUSY) + if (status & ATA_BUSY) { + if (expect == ATA_BUSY) break; } else { /* Check the error condition! */ - if (status & MG_REG_STATUS_BIT_ERROR) { + if (status & ATA_ERR) { mg_dump_status("mg_wait", status, host); break; } @@ -114,8 +237,8 @@ static unsigned int mg_wait(struct mg_host *host, u32 expect, u32 msec) if (MG_READY_OK(status)) break; - if (expect == MG_REG_STATUS_BIT_DATA_REQ) - if (status & MG_REG_STATUS_BIT_DATA_REQ) + if (expect == ATA_DRQ) + if (status & ATA_DRQ) break; } if (!msec) { @@ -173,6 +296,42 @@ static irqreturn_t mg_irq(int irq, void *dev_id) return IRQ_HANDLED; } +/* local copy of ata_id_string() */ +static void mg_id_string(const u16 *id, unsigned char *s, + unsigned int ofs, unsigned int len) +{ + unsigned int c; + + BUG_ON(len & 1); + + while (len > 0) { + c = id[ofs] >> 8; + *s = c; + s++; + + c = id[ofs] & 0xff; + *s = c; + s++; + + ofs++; + len -= 2; + } +} + +/* local copy of ata_id_c_string() */ +static void mg_id_c_string(const u16 *id, unsigned char *s, + unsigned int ofs, unsigned int len) +{ + unsigned char *p; + + mg_id_string(id, s, ofs, len - 1); + + p = s + strnlen(s, len - 1); + while (p > s && p[-1] == ' ') + p--; + *p = '\0'; +} + static int mg_get_disk_id(struct mg_host *host) { u32 i; @@ -184,12 +343,10 @@ static int mg_get_disk_id(struct mg_host *host) char serial[ATA_ID_SERNO_LEN + 1]; if (!prv_data->use_polling) - outb(MG_REG_CTRL_INTR_DISABLE, - (unsigned long)host->dev_base + - MG_REG_DRV_CTRL); + outb(ATA_NIEN, (unsigned long)host->dev_base + MG_REG_DRV_CTRL); outb(MG_CMD_ID, (unsigned long)host->dev_base + MG_REG_COMMAND); - err = mg_wait(host, MG_REG_STATUS_BIT_DATA_REQ, MG_TMAX_WAIT_RD_DRQ); + err = mg_wait(host, ATA_DRQ, MG_TMAX_WAIT_RD_DRQ); if (err) return err; @@ -219,9 +376,9 @@ static int mg_get_disk_id(struct mg_host *host) host->n_sectors -= host->nres_sectors; } - ata_id_c_string(id, fwrev, ATA_ID_FW_REV, sizeof(fwrev)); - ata_id_c_string(id, model, ATA_ID_PROD, sizeof(model)); - ata_id_c_string(id, serial, ATA_ID_SERNO, sizeof(serial)); + mg_id_c_string(id, fwrev, ATA_ID_FW_REV, sizeof(fwrev)); + mg_id_c_string(id, model, ATA_ID_PROD, sizeof(model)); + mg_id_c_string(id, serial, ATA_ID_SERNO, sizeof(serial)); printk(KERN_INFO "mg_disk: model: %s\n", model); printk(KERN_INFO "mg_disk: firm: %.8s\n", fwrev); printk(KERN_INFO "mg_disk: serial: %s\n", serial); @@ -229,8 +386,7 @@ static int mg_get_disk_id(struct mg_host *host) host->n_sectors, host->nres_sectors); if (!prv_data->use_polling) - outb(MG_REG_CTRL_INTR_ENABLE, (unsigned long)host->dev_base + - MG_REG_DRV_CTRL); + outb(0, (unsigned long)host->dev_base + MG_REG_DRV_CTRL); return err; } @@ -244,7 +400,7 @@ static int mg_disk_init(struct mg_host *host) /* hdd rst low */ gpio_set_value(host->rst, 0); - err = mg_wait(host, MG_REG_STATUS_BIT_BUSY, MG_TMAX_RST_TO_BUSY); + err = mg_wait(host, ATA_BUSY, MG_TMAX_RST_TO_BUSY); if (err) return err; @@ -255,17 +411,14 @@ static int mg_disk_init(struct mg_host *host) return err; /* soft reset on */ - outb(MG_REG_CTRL_RESET | - (prv_data->use_polling ? MG_REG_CTRL_INTR_DISABLE : - MG_REG_CTRL_INTR_ENABLE), + outb(ATA_SRST | (prv_data->use_polling ? ATA_NIEN : 0), (unsigned long)host->dev_base + MG_REG_DRV_CTRL); - err = mg_wait(host, MG_REG_STATUS_BIT_BUSY, MG_TMAX_RST_TO_BUSY); + err = mg_wait(host, ATA_BUSY, MG_TMAX_RST_TO_BUSY); if (err) return err; /* soft reset off */ - outb(prv_data->use_polling ? MG_REG_CTRL_INTR_DISABLE : - MG_REG_CTRL_INTR_ENABLE, + outb(prv_data->use_polling ? ATA_NIEN : 0, (unsigned long)host->dev_base + MG_REG_DRV_CTRL); err = mg_wait(host, MG_STAT_READY, MG_TMAX_SWRST_TO_RDY); if (err) @@ -281,11 +434,10 @@ static int mg_disk_init(struct mg_host *host) static void mg_bad_rw_intr(struct mg_host *host) { - struct request *req = elv_next_request(host->breq); - if (req != NULL) - if (++req->errors >= MG_MAX_ERRORS || - host->error == MG_ERR_TIMEOUT) - end_request(req, 0); + if (host->req) + if (++host->req->errors >= MG_MAX_ERRORS || + host->error == MG_ERR_TIMEOUT) + mg_end_request_cur(host, -EIO); } static unsigned int mg_out(struct mg_host *host, @@ -311,7 +463,7 @@ static unsigned int mg_out(struct mg_host *host, MG_REG_CYL_LOW); outb((u8)(sect_num >> 16), (unsigned long)host->dev_base + MG_REG_CYL_HIGH); - outb((u8)((sect_num >> 24) | MG_REG_HEAD_LBA_MODE), + outb((u8)((sect_num >> 24) | ATA_LBA | ATA_DEVICE_OBS), (unsigned long)host->dev_base + MG_REG_DRV_HEAD); outb(cmd, (unsigned long)host->dev_base + MG_REG_COMMAND); return MG_ERR_NONE; @@ -319,105 +471,77 @@ static unsigned int mg_out(struct mg_host *host, static void mg_read(struct request *req) { - u32 remains, j; + u32 j; struct mg_host *host = req->rq_disk->private_data; - remains = req->nr_sectors; - - if (mg_out(host, req->sector, req->nr_sectors, MG_CMD_RD, NULL) != - MG_ERR_NONE) + if (mg_out(host, blk_rq_pos(req), blk_rq_sectors(req), + MG_CMD_RD, NULL) != MG_ERR_NONE) mg_bad_rw_intr(host); MG_DBG("requested %d sects (from %ld), buffer=0x%p\n", - remains, req->sector, req->buffer); + blk_rq_sectors(req), blk_rq_pos(req), req->buffer); - while (remains) { - if (mg_wait(host, MG_REG_STATUS_BIT_DATA_REQ, - MG_TMAX_WAIT_RD_DRQ) != MG_ERR_NONE) { + do { + u16 *buff = (u16 *)req->buffer; + + if (mg_wait(host, ATA_DRQ, + MG_TMAX_WAIT_RD_DRQ) != MG_ERR_NONE) { mg_bad_rw_intr(host); return; } - for (j = 0; j < MG_SECTOR_SIZE >> 1; j++) { - *(u16 *)req->buffer = - inw((unsigned long)host->dev_base + - MG_BUFF_OFFSET + (j << 1)); - req->buffer += 2; - } - - req->sector++; - req->errors = 0; - remains = --req->nr_sectors; - --req->current_nr_sectors; - - if (req->current_nr_sectors <= 0) { - MG_DBG("remain : %d sects\n", remains); - end_request(req, 1); - if (remains > 0) - req = elv_next_request(host->breq); - } + for (j = 0; j < MG_SECTOR_SIZE >> 1; j++) + *buff++ = inw((unsigned long)host->dev_base + + MG_BUFF_OFFSET + (j << 1)); outb(MG_CMD_RD_CONF, (unsigned long)host->dev_base + MG_REG_COMMAND); - } + } while (mg_end_request(host, 0, MG_SECTOR_SIZE)); } static void mg_write(struct request *req) { - u32 remains, j; + u32 j; struct mg_host *host = req->rq_disk->private_data; - remains = req->nr_sectors; - - if (mg_out(host, req->sector, req->nr_sectors, MG_CMD_WR, NULL) != - MG_ERR_NONE) { + if (mg_out(host, blk_rq_pos(req), blk_rq_sectors(req), + MG_CMD_WR, NULL) != MG_ERR_NONE) { mg_bad_rw_intr(host); return; } - MG_DBG("requested %d sects (from %ld), buffer=0x%p\n", - remains, req->sector, req->buffer); - while (remains) { - if (mg_wait(host, MG_REG_STATUS_BIT_DATA_REQ, - MG_TMAX_WAIT_WR_DRQ) != MG_ERR_NONE) { + blk_rq_sectors(req), blk_rq_pos(req), req->buffer); + + do { + u16 *buff = (u16 *)req->buffer; + + if (mg_wait(host, ATA_DRQ, MG_TMAX_WAIT_WR_DRQ) != MG_ERR_NONE) { mg_bad_rw_intr(host); return; } - for (j = 0; j < MG_SECTOR_SIZE >> 1; j++) { - outw(*(u16 *)req->buffer, - (unsigned long)host->dev_base + - MG_BUFF_OFFSET + (j << 1)); - req->buffer += 2; - } - req->sector++; - remains = --req->nr_sectors; - --req->current_nr_sectors; - - if (req->current_nr_sectors <= 0) { - MG_DBG("remain : %d sects\n", remains); - end_request(req, 1); - if (remains > 0) - req = elv_next_request(host->breq); - } + for (j = 0; j < MG_SECTOR_SIZE >> 1; j++) + outw(*buff++, (unsigned long)host->dev_base + + MG_BUFF_OFFSET + (j << 1)); outb(MG_CMD_WR_CONF, (unsigned long)host->dev_base + MG_REG_COMMAND); - } + } while (mg_end_request(host, 0, MG_SECTOR_SIZE)); } static void mg_read_intr(struct mg_host *host) { + struct request *req = host->req; u32 i; - struct request *req; + u16 *buff; /* check status */ do { i = inb((unsigned long)host->dev_base + MG_REG_STATUS); - if (i & MG_REG_STATUS_BIT_BUSY) + if (i & ATA_BUSY) break; if (!MG_READY_OK(i)) break; - if (i & MG_REG_STATUS_BIT_DATA_REQ) + if (i & ATA_DRQ) goto ok_to_read; } while (0); mg_dump_status("mg_read_intr", i, host); @@ -427,60 +551,42 @@ static void mg_read_intr(struct mg_host *host) ok_to_read: /* get current segment of request */ - req = elv_next_request(host->breq); + buff = (u16 *)req->buffer; /* read 1 sector */ - for (i = 0; i < MG_SECTOR_SIZE >> 1; i++) { - *(u16 *)req->buffer = - inw((unsigned long)host->dev_base + MG_BUFF_OFFSET + - (i << 1)); - req->buffer += 2; - } + for (i = 0; i < MG_SECTOR_SIZE >> 1; i++) + *buff++ = inw((unsigned long)host->dev_base + MG_BUFF_OFFSET + + (i << 1)); - /* manipulate request */ MG_DBG("sector %ld, remaining=%ld, buffer=0x%p\n", - req->sector, req->nr_sectors - 1, req->buffer); - - req->sector++; - req->errors = 0; - i = --req->nr_sectors; - --req->current_nr_sectors; - - /* let know if current segment done */ - if (req->current_nr_sectors <= 0) - end_request(req, 1); - - /* set handler if read remains */ - if (i > 0) { - host->mg_do_intr = mg_read_intr; - mod_timer(&host->timer, jiffies + 3 * HZ); - } + blk_rq_pos(req), blk_rq_sectors(req) - 1, req->buffer); /* send read confirm */ outb(MG_CMD_RD_CONF, (unsigned long)host->dev_base + MG_REG_COMMAND); - /* goto next request */ - if (!i) + if (mg_end_request(host, 0, MG_SECTOR_SIZE)) { + /* set handler if read remains */ + host->mg_do_intr = mg_read_intr; + mod_timer(&host->timer, jiffies + 3 * HZ); + } else /* goto next request */ mg_request(host->breq); } static void mg_write_intr(struct mg_host *host) { + struct request *req = host->req; u32 i, j; u16 *buff; - struct request *req; - - /* get current segment of request */ - req = elv_next_request(host->breq); + bool rem; /* check status */ do { i = inb((unsigned long)host->dev_base + MG_REG_STATUS); - if (i & MG_REG_STATUS_BIT_BUSY) + if (i & ATA_BUSY) break; if (!MG_READY_OK(i)) break; - if ((req->nr_sectors <= 1) || (i & MG_REG_STATUS_BIT_DATA_REQ)) + if ((blk_rq_sectors(req) <= 1) || (i & ATA_DRQ)) goto ok_to_write; } while (0); mg_dump_status("mg_write_intr", i, host); @@ -489,18 +595,8 @@ static void mg_write_intr(struct mg_host *host) return; ok_to_write: - /* manipulate request */ - req->sector++; - i = --req->nr_sectors; - --req->current_nr_sectors; - req->buffer += MG_SECTOR_SIZE; - - /* let know if current segment or all done */ - if (!i || (req->bio && req->current_nr_sectors <= 0)) - end_request(req, 1); - - /* write 1 sector and set handler if remains */ - if (i > 0) { + if ((rem = mg_end_request(host, 0, MG_SECTOR_SIZE))) { + /* write 1 sector and set handler if remains */ buff = (u16 *)req->buffer; for (j = 0; j < MG_STORAGE_BUFFER_SIZE >> 1; j++) { outw(*buff, (unsigned long)host->dev_base + @@ -508,7 +604,7 @@ ok_to_write: buff++; } MG_DBG("sector %ld, remaining=%ld, buffer=0x%p\n", - req->sector, req->nr_sectors, req->buffer); + blk_rq_pos(req), blk_rq_sectors(req), req->buffer); host->mg_do_intr = mg_write_intr; mod_timer(&host->timer, jiffies + 3 * HZ); } @@ -516,7 +612,7 @@ ok_to_write: /* send write confirm */ outb(MG_CMD_WR_CONF, (unsigned long)host->dev_base + MG_REG_COMMAND); - if (!i) + if (!rem) mg_request(host->breq); } @@ -524,49 +620,45 @@ void mg_times_out(unsigned long data) { struct mg_host *host = (struct mg_host *)data; char *name; - struct request *req; spin_lock_irq(&host->lock); - req = elv_next_request(host->breq); - if (!req) + if (!host->req) goto out_unlock; host->mg_do_intr = NULL; - name = req->rq_disk->disk_name; + name = host->req->rq_disk->disk_name; printk(KERN_DEBUG "%s: timeout\n", name); host->error = MG_ERR_TIMEOUT; mg_bad_rw_intr(host); - mg_request(host->breq); out_unlock: + mg_request(host->breq); spin_unlock_irq(&host->lock); } static void mg_request_poll(struct request_queue *q) { - struct request *req; - struct mg_host *host; + struct mg_host *host = q->queuedata; - while ((req = elv_next_request(q)) != NULL) { - host = req->rq_disk->private_data; - if (blk_fs_request(req)) { - switch (rq_data_dir(req)) { - case READ: - mg_read(req); + while (1) { + if (!host->req) { + host->req = blk_fetch_request(q); + if (!host->req) break; - case WRITE: - mg_write(req); - break; - default: - printk(KERN_WARNING "%s:%d unknown command\n", - __func__, __LINE__); - end_request(req, 0); - break; - } } + + if (unlikely(!blk_fs_request(host->req))) { + mg_end_request_cur(host, -EIO); + continue; + } + + if (rq_data_dir(host->req) == READ) + mg_read(host->req); + else + mg_write(host->req); } } @@ -588,18 +680,15 @@ static unsigned int mg_issue_req(struct request *req, break; case WRITE: /* TODO : handler */ - outb(MG_REG_CTRL_INTR_DISABLE, - (unsigned long)host->dev_base + - MG_REG_DRV_CTRL); + outb(ATA_NIEN, (unsigned long)host->dev_base + MG_REG_DRV_CTRL); if (mg_out(host, sect_num, sect_cnt, MG_CMD_WR, &mg_write_intr) != MG_ERR_NONE) { mg_bad_rw_intr(host); return host->error; } del_timer(&host->timer); - mg_wait(host, MG_REG_STATUS_BIT_DATA_REQ, MG_TMAX_WAIT_WR_DRQ); - outb(MG_REG_CTRL_INTR_ENABLE, (unsigned long)host->dev_base + - MG_REG_DRV_CTRL); + mg_wait(host, ATA_DRQ, MG_TMAX_WAIT_WR_DRQ); + outb(0, (unsigned long)host->dev_base + MG_REG_DRV_CTRL); if (host->error) { mg_bad_rw_intr(host); return host->error; @@ -614,11 +703,6 @@ static unsigned int mg_issue_req(struct request *req, outb(MG_CMD_WR_CONF, (unsigned long)host->dev_base + MG_REG_COMMAND); break; - default: - printk(KERN_WARNING "%s:%d unknown command\n", - __func__, __LINE__); - end_request(req, 0); - break; } return MG_ERR_NONE; } @@ -626,16 +710,17 @@ static unsigned int mg_issue_req(struct request *req, /* This function also called from IRQ context */ static void mg_request(struct request_queue *q) { + struct mg_host *host = q->queuedata; struct request *req; - struct mg_host *host; u32 sect_num, sect_cnt; while (1) { - req = elv_next_request(q); - if (!req) - return; - - host = req->rq_disk->private_data; + if (!host->req) { + host->req = blk_fetch_request(q); + if (!host->req) + break; + } + req = host->req; /* check unwanted request call */ if (host->mg_do_intr) @@ -643,9 +728,9 @@ static void mg_request(struct request_queue *q) del_timer(&host->timer); - sect_num = req->sector; + sect_num = blk_rq_pos(req); /* deal whole segments */ - sect_cnt = req->nr_sectors; + sect_cnt = blk_rq_sectors(req); /* sanity check */ if (sect_num >= get_capacity(req->rq_disk) || @@ -655,12 +740,14 @@ static void mg_request(struct request_queue *q) "%s: bad access: sector=%d, count=%d\n", req->rq_disk->disk_name, sect_num, sect_cnt); - end_request(req, 0); + mg_end_request_cur(host, -EIO); continue; } - if (!blk_fs_request(req)) - return; + if (unlikely(!blk_fs_request(req))) { + mg_end_request_cur(host, -EIO); + continue; + } if (!mg_issue_req(req, host, sect_num, sect_cnt)) return; @@ -690,9 +777,7 @@ static int mg_suspend(struct platform_device *plat_dev, pm_message_t state) return -EIO; if (!prv_data->use_polling) - outb(MG_REG_CTRL_INTR_DISABLE, - (unsigned long)host->dev_base + - MG_REG_DRV_CTRL); + outb(ATA_NIEN, (unsigned long)host->dev_base + MG_REG_DRV_CTRL); outb(MG_CMD_SLEEP, (unsigned long)host->dev_base + MG_REG_COMMAND); /* wait until mflash deep sleep */ @@ -700,9 +785,7 @@ static int mg_suspend(struct platform_device *plat_dev, pm_message_t state) if (mg_wait(host, MG_STAT_READY, MG_TMAX_CONF_TO_CMD)) { if (!prv_data->use_polling) - outb(MG_REG_CTRL_INTR_ENABLE, - (unsigned long)host->dev_base + - MG_REG_DRV_CTRL); + outb(0, (unsigned long)host->dev_base + MG_REG_DRV_CTRL); return -EIO; } @@ -725,8 +808,7 @@ static int mg_resume(struct platform_device *plat_dev) return -EIO; if (!prv_data->use_polling) - outb(MG_REG_CTRL_INTR_ENABLE, (unsigned long)host->dev_base + - MG_REG_DRV_CTRL); + outb(0, (unsigned long)host->dev_base + MG_REG_DRV_CTRL); return 0; } @@ -877,6 +959,7 @@ static int mg_probe(struct platform_device *plat_dev) __func__, __LINE__); goto probe_err_5; } + host->breq->queuedata = host; /* mflash is random device, thanx for the noop */ elevator_exit(host->breq->elevator); @@ -887,7 +970,7 @@ static int mg_probe(struct platform_device *plat_dev) goto probe_err_6; } blk_queue_max_sectors(host->breq, MG_MAX_SECTS); - blk_queue_hardsect_size(host->breq, MG_SECTOR_SIZE); + blk_queue_logical_block_size(host->breq, MG_SECTOR_SIZE); init_timer(&host->timer); host->timer.function = mg_times_out; diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 4d6de4f15ccb..5d23ffad7c77 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -110,7 +110,7 @@ static void nbd_end_request(struct request *req) req, error ? "failed" : "done"); spin_lock_irqsave(q->queue_lock, flags); - __blk_end_request(req, error, req->nr_sectors << 9); + __blk_end_request_all(req, error); spin_unlock_irqrestore(q->queue_lock, flags); } @@ -231,19 +231,19 @@ static int nbd_send_req(struct nbd_device *lo, struct request *req) { int result, flags; struct nbd_request request; - unsigned long size = req->nr_sectors << 9; + unsigned long size = blk_rq_bytes(req); request.magic = htonl(NBD_REQUEST_MAGIC); request.type = htonl(nbd_cmd(req)); - request.from = cpu_to_be64((u64) req->sector << 9); + request.from = cpu_to_be64((u64)blk_rq_pos(req) << 9); request.len = htonl(size); memcpy(request.handle, &req, sizeof(req)); - dprintk(DBG_TX, "%s: request %p: sending control (%s@%llu,%luB)\n", + dprintk(DBG_TX, "%s: request %p: sending control (%s@%llu,%uB)\n", lo->disk->disk_name, req, nbdcmd_to_ascii(nbd_cmd(req)), - (unsigned long long)req->sector << 9, - req->nr_sectors << 9); + (unsigned long long)blk_rq_pos(req) << 9, + blk_rq_bytes(req)); result = sock_xmit(lo, 1, &request, sizeof(request), (nbd_cmd(req) == NBD_CMD_WRITE) ? MSG_MORE : 0); if (result <= 0) { @@ -533,11 +533,9 @@ static void do_nbd_request(struct request_queue *q) { struct request *req; - while ((req = elv_next_request(q)) != NULL) { + while ((req = blk_fetch_request(q)) != NULL) { struct nbd_device *lo; - blkdev_dequeue_request(req); - spin_unlock_irq(q->queue_lock); dprintk(DBG_BLKDEV, "%s: request %p: dequeued (flags=%x)\n", @@ -580,13 +578,6 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *lo, blk_rq_init(NULL, &sreq); sreq.cmd_type = REQ_TYPE_SPECIAL; nbd_cmd(&sreq) = NBD_CMD_DISC; - /* - * Set these to sane values in case server implementation - * fails to check the request type first and also to keep - * debugging output cleaner. - */ - sreq.sector = 0; - sreq.nr_sectors = 0; if (!lo->sock) return -EINVAL; nbd_send_req(lo, &sreq); diff --git a/drivers/block/paride/pcd.c b/drivers/block/paride/pcd.c index e91d4b4b014f..911dfd98d813 100644 --- a/drivers/block/paride/pcd.c +++ b/drivers/block/paride/pcd.c @@ -719,32 +719,37 @@ static void do_pcd_request(struct request_queue * q) if (pcd_busy) return; while (1) { - pcd_req = elv_next_request(q); - if (!pcd_req) - return; + if (!pcd_req) { + pcd_req = blk_fetch_request(q); + if (!pcd_req) + return; + } if (rq_data_dir(pcd_req) == READ) { struct pcd_unit *cd = pcd_req->rq_disk->private_data; if (cd != pcd_current) pcd_bufblk = -1; pcd_current = cd; - pcd_sector = pcd_req->sector; - pcd_count = pcd_req->current_nr_sectors; + pcd_sector = blk_rq_pos(pcd_req); + pcd_count = blk_rq_cur_sectors(pcd_req); pcd_buf = pcd_req->buffer; pcd_busy = 1; ps_set_intr(do_pcd_read, NULL, 0, nice); return; - } else - end_request(pcd_req, 0); + } else { + __blk_end_request_all(pcd_req, -EIO); + pcd_req = NULL; + } } } -static inline void next_request(int success) +static inline void next_request(int err) { unsigned long saved_flags; spin_lock_irqsave(&pcd_lock, saved_flags); - end_request(pcd_req, success); + if (!__blk_end_request_cur(pcd_req, err)) + pcd_req = NULL; pcd_busy = 0; do_pcd_request(pcd_queue); spin_unlock_irqrestore(&pcd_lock, saved_flags); @@ -781,7 +786,7 @@ static void pcd_start(void) if (pcd_command(pcd_current, rd_cmd, 2048, "read block")) { pcd_bufblk = -1; - next_request(0); + next_request(-EIO); return; } @@ -796,7 +801,7 @@ static void do_pcd_read(void) pcd_retries = 0; pcd_transfer(); if (!pcd_count) { - next_request(1); + next_request(0); return; } @@ -815,7 +820,7 @@ static void do_pcd_read_drq(void) return; } pcd_bufblk = -1; - next_request(0); + next_request(-EIO); return; } diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c index 9299455b0af6..bf5955b3d873 100644 --- a/drivers/block/paride/pd.c +++ b/drivers/block/paride/pd.c @@ -410,10 +410,12 @@ static void run_fsm(void) pd_claimed = 0; phase = NULL; spin_lock_irqsave(&pd_lock, saved_flags); - end_request(pd_req, res); - pd_req = elv_next_request(pd_queue); - if (!pd_req) - stop = 1; + if (!__blk_end_request_cur(pd_req, + res == Ok ? 0 : -EIO)) { + pd_req = blk_fetch_request(pd_queue); + if (!pd_req) + stop = 1; + } spin_unlock_irqrestore(&pd_lock, saved_flags); if (stop) return; @@ -443,11 +445,11 @@ static enum action do_pd_io_start(void) pd_cmd = rq_data_dir(pd_req); if (pd_cmd == READ || pd_cmd == WRITE) { - pd_block = pd_req->sector; - pd_count = pd_req->current_nr_sectors; + pd_block = blk_rq_pos(pd_req); + pd_count = blk_rq_cur_sectors(pd_req); if (pd_block + pd_count > get_capacity(pd_req->rq_disk)) return Fail; - pd_run = pd_req->nr_sectors; + pd_run = blk_rq_sectors(pd_req); pd_buf = pd_req->buffer; pd_retries = 0; if (pd_cmd == READ) @@ -477,8 +479,8 @@ static int pd_next_buf(void) if (pd_count) return 0; spin_lock_irqsave(&pd_lock, saved_flags); - end_request(pd_req, 1); - pd_count = pd_req->current_nr_sectors; + __blk_end_request_cur(pd_req, 0); + pd_count = blk_rq_cur_sectors(pd_req); pd_buf = pd_req->buffer; spin_unlock_irqrestore(&pd_lock, saved_flags); return 0; @@ -702,7 +704,7 @@ static void do_pd_request(struct request_queue * q) { if (pd_req) return; - pd_req = elv_next_request(q); + pd_req = blk_fetch_request(q); if (!pd_req) return; diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c index bef3b997ba3e..68a90834e993 100644 --- a/drivers/block/paride/pf.c +++ b/drivers/block/paride/pf.c @@ -750,12 +750,10 @@ static int pf_ready(void) static struct request_queue *pf_queue; -static void pf_end_request(int uptodate) +static void pf_end_request(int err) { - if (pf_req) { - end_request(pf_req, uptodate); + if (pf_req && !__blk_end_request_cur(pf_req, err)) pf_req = NULL; - } } static void do_pf_request(struct request_queue * q) @@ -763,17 +761,19 @@ static void do_pf_request(struct request_queue * q) if (pf_busy) return; repeat: - pf_req = elv_next_request(q); - if (!pf_req) - return; + if (!pf_req) { + pf_req = blk_fetch_request(q); + if (!pf_req) + return; + } pf_current = pf_req->rq_disk->private_data; - pf_block = pf_req->sector; - pf_run = pf_req->nr_sectors; - pf_count = pf_req->current_nr_sectors; + pf_block = blk_rq_pos(pf_req); + pf_run = blk_rq_sectors(pf_req); + pf_count = blk_rq_cur_sectors(pf_req); if (pf_block + pf_count > get_capacity(pf_req->rq_disk)) { - pf_end_request(0); + pf_end_request(-EIO); goto repeat; } @@ -788,7 +788,7 @@ repeat: pi_do_claimed(pf_current->pi, do_pf_write); else { pf_busy = 0; - pf_end_request(0); + pf_end_request(-EIO); goto repeat; } } @@ -805,23 +805,22 @@ static int pf_next_buf(void) return 1; if (!pf_count) { spin_lock_irqsave(&pf_spin_lock, saved_flags); - pf_end_request(1); - pf_req = elv_next_request(pf_queue); + pf_end_request(0); spin_unlock_irqrestore(&pf_spin_lock, saved_flags); if (!pf_req) return 1; - pf_count = pf_req->current_nr_sectors; + pf_count = blk_rq_cur_sectors(pf_req); pf_buf = pf_req->buffer; } return 0; } -static inline void next_request(int success) +static inline void next_request(int err) { unsigned long saved_flags; spin_lock_irqsave(&pf_spin_lock, saved_flags); - pf_end_request(success); + pf_end_request(err); pf_busy = 0; do_pf_request(pf_queue); spin_unlock_irqrestore(&pf_spin_lock, saved_flags); @@ -844,7 +843,7 @@ static void do_pf_read_start(void) pi_do_claimed(pf_current->pi, do_pf_read_start); return; } - next_request(0); + next_request(-EIO); return; } pf_mask = STAT_DRQ; @@ -863,7 +862,7 @@ static void do_pf_read_drq(void) pi_do_claimed(pf_current->pi, do_pf_read_start); return; } - next_request(0); + next_request(-EIO); return; } pi_read_block(pf_current->pi, pf_buf, 512); @@ -871,7 +870,7 @@ static void do_pf_read_drq(void) break; } pi_disconnect(pf_current->pi); - next_request(1); + next_request(0); } static void do_pf_write(void) @@ -890,7 +889,7 @@ static void do_pf_write_start(void) pi_do_claimed(pf_current->pi, do_pf_write_start); return; } - next_request(0); + next_request(-EIO); return; } @@ -903,7 +902,7 @@ static void do_pf_write_start(void) pi_do_claimed(pf_current->pi, do_pf_write_start); return; } - next_request(0); + next_request(-EIO); return; } pi_write_block(pf_current->pi, pf_buf, 512); @@ -923,11 +922,11 @@ static void do_pf_write_done(void) pi_do_claimed(pf_current->pi, do_pf_write_start); return; } - next_request(0); + next_request(-EIO); return; } pi_disconnect(pf_current->pi); - next_request(1); + next_request(0); } static int __init pf_init(void) diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index dc7a8c352da2..83650e00632d 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -430,7 +430,7 @@ static void pkt_sysfs_cleanup(void) /******************************************************************** entries in debugfs - /debugfs/pktcdvd[0-7]/ + /sys/kernel/debug/pktcdvd[0-7]/ info *******************************************************************/ @@ -991,13 +991,15 @@ static void pkt_iosched_process_queue(struct pktcdvd_device *pd) */ static int pkt_set_segment_merging(struct pktcdvd_device *pd, struct request_queue *q) { - if ((pd->settings.size << 9) / CD_FRAMESIZE <= q->max_phys_segments) { + if ((pd->settings.size << 9) / CD_FRAMESIZE + <= queue_max_phys_segments(q)) { /* * The cdrom device can handle one segment/frame */ clear_bit(PACKET_MERGE_SEGS, &pd->flags); return 0; - } else if ((pd->settings.size << 9) / PAGE_SIZE <= q->max_phys_segments) { + } else if ((pd->settings.size << 9) / PAGE_SIZE + <= queue_max_phys_segments(q)) { /* * We can handle this case at the expense of some extra memory * copies during write operations @@ -2657,7 +2659,7 @@ static void pkt_init_queue(struct pktcdvd_device *pd) struct request_queue *q = pd->disk->queue; blk_queue_make_request(q, pkt_make_request); - blk_queue_hardsect_size(q, CD_FRAMESIZE); + blk_queue_logical_block_size(q, CD_FRAMESIZE); blk_queue_max_sectors(q, PACKET_MAX_SECTORS); blk_queue_merge_bvec(q, pkt_merge_bvec); q->queuedata = pd; @@ -2853,6 +2855,11 @@ static struct block_device_operations pktcdvd_ops = { .media_changed = pkt_media_changed, }; +static char *pktcdvd_nodename(struct gendisk *gd) +{ + return kasprintf(GFP_KERNEL, "pktcdvd/%s", gd->disk_name); +} + /* * Set up mapping from pktcdvd device to CD-ROM device. */ @@ -2905,6 +2912,7 @@ static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev) disk->fops = &pktcdvd_ops; disk->flags = GENHD_FL_REMOVABLE; strcpy(disk->disk_name, pd->name); + disk->nodename = pktcdvd_nodename; disk->private_data = pd; disk->queue = blk_alloc_queue(GFP_KERNEL); if (!disk->queue) @@ -3060,6 +3068,7 @@ static const struct file_operations pkt_ctl_fops = { static struct miscdevice pkt_misc = { .minor = MISC_DYNAMIC_MINOR, .name = DRIVER_NAME, + .name = "pktcdvd/control", .fops = &pkt_ctl_fops }; diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c index bccc42bb9212..34cbb7f3efa8 100644 --- a/drivers/block/ps3disk.c +++ b/drivers/block/ps3disk.c @@ -120,7 +120,7 @@ static void ps3disk_scatter_gather(struct ps3_storage_device *dev, static int ps3disk_submit_request_sg(struct ps3_storage_device *dev, struct request *req) { - struct ps3disk_private *priv = dev->sbd.core.driver_data; + struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); int write = rq_data_dir(req), res; const char *op = write ? "write" : "read"; u64 start_sector, sectors; @@ -134,13 +134,12 @@ static int ps3disk_submit_request_sg(struct ps3_storage_device *dev, rq_for_each_segment(bv, req, iter) n++; dev_dbg(&dev->sbd.core, - "%s:%u: %s req has %u bvecs for %lu sectors %lu hard sectors\n", - __func__, __LINE__, op, n, req->nr_sectors, - req->hard_nr_sectors); + "%s:%u: %s req has %u bvecs for %u sectors\n", + __func__, __LINE__, op, n, blk_rq_sectors(req)); #endif - start_sector = req->sector * priv->blocking_factor; - sectors = req->nr_sectors * priv->blocking_factor; + start_sector = blk_rq_pos(req) * priv->blocking_factor; + sectors = blk_rq_sectors(req) * priv->blocking_factor; dev_dbg(&dev->sbd.core, "%s:%u: %s %llu sectors starting at %llu\n", __func__, __LINE__, op, sectors, start_sector); @@ -158,7 +157,7 @@ static int ps3disk_submit_request_sg(struct ps3_storage_device *dev, if (res) { dev_err(&dev->sbd.core, "%s:%u: %s failed %d\n", __func__, __LINE__, op, res); - end_request(req, 0); + __blk_end_request_all(req, -EIO); return 0; } @@ -169,7 +168,7 @@ static int ps3disk_submit_request_sg(struct ps3_storage_device *dev, static int ps3disk_submit_flush_request(struct ps3_storage_device *dev, struct request *req) { - struct ps3disk_private *priv = dev->sbd.core.driver_data; + struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); u64 res; dev_dbg(&dev->sbd.core, "%s:%u: flush request\n", __func__, __LINE__); @@ -180,7 +179,7 @@ static int ps3disk_submit_flush_request(struct ps3_storage_device *dev, if (res) { dev_err(&dev->sbd.core, "%s:%u: sync cache failed 0x%llx\n", __func__, __LINE__, res); - end_request(req, 0); + __blk_end_request_all(req, -EIO); return 0; } @@ -195,7 +194,7 @@ static void ps3disk_do_request(struct ps3_storage_device *dev, dev_dbg(&dev->sbd.core, "%s:%u\n", __func__, __LINE__); - while ((req = elv_next_request(q))) { + while ((req = blk_fetch_request(q))) { if (blk_fs_request(req)) { if (ps3disk_submit_request_sg(dev, req)) break; @@ -205,7 +204,7 @@ static void ps3disk_do_request(struct ps3_storage_device *dev, break; } else { blk_dump_rq_flags(req, DEVICE_NAME " bad request"); - end_request(req, 0); + __blk_end_request_all(req, -EIO); continue; } } @@ -214,7 +213,7 @@ static void ps3disk_do_request(struct ps3_storage_device *dev, static void ps3disk_request(struct request_queue *q) { struct ps3_storage_device *dev = q->queuedata; - struct ps3disk_private *priv = dev->sbd.core.driver_data; + struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); if (priv->req) { dev_dbg(&dev->sbd.core, "%s:%u busy\n", __func__, __LINE__); @@ -231,7 +230,6 @@ static irqreturn_t ps3disk_interrupt(int irq, void *data) struct request *req; int res, read, error; u64 tag, status; - unsigned long num_sectors; const char *op; res = lv1_storage_get_async_status(dev->sbd.dev_id, &tag, &status); @@ -247,7 +245,7 @@ static irqreturn_t ps3disk_interrupt(int irq, void *data) return IRQ_HANDLED; } - priv = dev->sbd.core.driver_data; + priv = ps3_system_bus_get_drvdata(&dev->sbd); req = priv->req; if (!req) { dev_dbg(&dev->sbd.core, @@ -261,11 +259,9 @@ static irqreturn_t ps3disk_interrupt(int irq, void *data) if (req->cmd_type == REQ_TYPE_LINUX_BLOCK && req->cmd[0] == REQ_LB_OP_FLUSH) { read = 0; - num_sectors = req->hard_cur_sectors; op = "flush"; } else { read = !rq_data_dir(req); - num_sectors = req->nr_sectors; op = read ? "read" : "write"; } if (status) { @@ -281,7 +277,7 @@ static irqreturn_t ps3disk_interrupt(int irq, void *data) } spin_lock(&priv->lock); - __blk_end_request(req, error, num_sectors << 9); + __blk_end_request_all(req, error); priv->req = NULL; ps3disk_do_request(dev, priv->queue); spin_unlock(&priv->lock); @@ -368,7 +364,7 @@ static void ata_id_c_string(const u16 *id, unsigned char *s, unsigned int ofs, static int ps3disk_identify(struct ps3_storage_device *dev) { - struct ps3disk_private *priv = dev->sbd.core.driver_data; + struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); struct lv1_ata_cmnd_block ata_cmnd; u16 *id = dev->bounce_buf; u64 res; @@ -449,7 +445,7 @@ static int __devinit ps3disk_probe(struct ps3_system_bus_device *_dev) goto fail; } - dev->sbd.core.driver_data = priv; + ps3_system_bus_set_drvdata(_dev, priv); spin_lock_init(&priv->lock); dev->bounce_size = BOUNCE_SIZE; @@ -481,7 +477,7 @@ static int __devinit ps3disk_probe(struct ps3_system_bus_device *_dev) blk_queue_max_sectors(queue, dev->bounce_size >> 9); blk_queue_segment_boundary(queue, -1UL); blk_queue_dma_alignment(queue, dev->blk_size-1); - blk_queue_hardsect_size(queue, dev->blk_size); + blk_queue_logical_block_size(queue, dev->blk_size); blk_queue_ordered(queue, QUEUE_ORDERED_DRAIN_FLUSH, ps3disk_prepare_flush); @@ -527,7 +523,7 @@ fail_free_bounce: kfree(dev->bounce_buf); fail_free_priv: kfree(priv); - dev->sbd.core.driver_data = NULL; + ps3_system_bus_set_drvdata(_dev, NULL); fail: mutex_lock(&ps3disk_mask_mutex); __clear_bit(devidx, &ps3disk_mask); @@ -538,7 +534,7 @@ fail: static int ps3disk_remove(struct ps3_system_bus_device *_dev) { struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core); - struct ps3disk_private *priv = dev->sbd.core.driver_data; + struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); mutex_lock(&ps3disk_mask_mutex); __clear_bit(MINOR(disk_devt(priv->gendisk)) / PS3DISK_MINORS, @@ -552,7 +548,7 @@ static int ps3disk_remove(struct ps3_system_bus_device *_dev) ps3stor_teardown(dev); kfree(dev->bounce_buf); kfree(priv); - dev->sbd.core.driver_data = NULL; + ps3_system_bus_set_drvdata(_dev, NULL); return 0; } diff --git a/drivers/block/ps3vram.c b/drivers/block/ps3vram.c index 8eddef373a91..095f97e60665 100644 --- a/drivers/block/ps3vram.c +++ b/drivers/block/ps3vram.c @@ -14,8 +14,10 @@ #include #include +#include #include #include +#include #define DEVICE_NAME "ps3vram" @@ -45,8 +47,6 @@ #define NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN 0x0000030c #define NV_MEMORY_TO_MEMORY_FORMAT_NOTIFY 0x00000104 -#define L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT 0x601 - #define CACHE_PAGE_PRESENT 1 #define CACHE_PAGE_DIRTY 2 @@ -72,8 +72,7 @@ struct ps3vram_priv { u64 memory_handle; u64 context_handle; u32 *ctrl; - u32 *reports; - u8 __iomem *ddr_base; + void *reports; u8 *xdr_buf; u32 *fifo_base; @@ -81,8 +80,8 @@ struct ps3vram_priv { struct ps3vram_cache cache; - /* Used to serialize cache/DMA operations */ - struct mutex lock; + spinlock_t lock; /* protecting list of bios */ + struct bio_list list; }; @@ -103,15 +102,15 @@ static char *size = "256M"; module_param(size, charp, 0); MODULE_PARM_DESC(size, "memory size"); -static u32 *ps3vram_get_notifier(u32 *reports, int notifier) +static u32 *ps3vram_get_notifier(void *reports, int notifier) { - return (void *)reports + DMA_NOTIFIER_OFFSET_BASE + + return reports + DMA_NOTIFIER_OFFSET_BASE + DMA_NOTIFIER_SIZE * notifier; } static void ps3vram_notifier_reset(struct ps3_system_bus_device *dev) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); u32 *notify = ps3vram_get_notifier(priv->reports, NOTIFIER); int i; @@ -122,7 +121,7 @@ static void ps3vram_notifier_reset(struct ps3_system_bus_device *dev) static int ps3vram_notifier_wait(struct ps3_system_bus_device *dev, unsigned int timeout_ms) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); u32 *notify = ps3vram_get_notifier(priv->reports, NOTIFIER); unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms); @@ -137,7 +136,7 @@ static int ps3vram_notifier_wait(struct ps3_system_bus_device *dev, static void ps3vram_init_ring(struct ps3_system_bus_device *dev) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); priv->ctrl[CTRL_PUT] = FIFO_BASE + FIFO_OFFSET; priv->ctrl[CTRL_GET] = FIFO_BASE + FIFO_OFFSET; @@ -146,7 +145,7 @@ static void ps3vram_init_ring(struct ps3_system_bus_device *dev) static int ps3vram_wait_ring(struct ps3_system_bus_device *dev, unsigned int timeout_ms) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms); do { @@ -175,7 +174,7 @@ static void ps3vram_begin_ring(struct ps3vram_priv *priv, u32 chan, u32 tag, static void ps3vram_rewind_ring(struct ps3_system_bus_device *dev) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); int status; ps3vram_out_ring(priv, 0x20000000 | (FIFO_BASE + FIFO_OFFSET)); @@ -183,20 +182,17 @@ static void ps3vram_rewind_ring(struct ps3_system_bus_device *dev) priv->ctrl[CTRL_PUT] = FIFO_BASE + FIFO_OFFSET; /* asking the HV for a blit will kick the FIFO */ - status = lv1_gpu_context_attribute(priv->context_handle, - L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT, 0, - 0, 0, 0); + status = lv1_gpu_fb_blit(priv->context_handle, 0, 0, 0, 0); if (status) - dev_err(&dev->core, - "%s: lv1_gpu_context_attribute failed %d\n", __func__, - status); + dev_err(&dev->core, "%s: lv1_gpu_fb_blit failed %d\n", + __func__, status); priv->fifo_ptr = priv->fifo_base; } static void ps3vram_fire_ring(struct ps3_system_bus_device *dev) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); int status; mutex_lock(&ps3_gpu_mutex); @@ -205,13 +201,10 @@ static void ps3vram_fire_ring(struct ps3_system_bus_device *dev) (priv->fifo_ptr - priv->fifo_base) * sizeof(u32); /* asking the HV for a blit will kick the FIFO */ - status = lv1_gpu_context_attribute(priv->context_handle, - L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT, 0, - 0, 0, 0); + status = lv1_gpu_fb_blit(priv->context_handle, 0, 0, 0, 0); if (status) - dev_err(&dev->core, - "%s: lv1_gpu_context_attribute failed %d\n", __func__, - status); + dev_err(&dev->core, "%s: lv1_gpu_fb_blit failed %d\n", + __func__, status); if ((priv->fifo_ptr - priv->fifo_base) * sizeof(u32) > FIFO_SIZE - 1024) { @@ -225,7 +218,7 @@ static void ps3vram_fire_ring(struct ps3_system_bus_device *dev) static void ps3vram_bind(struct ps3_system_bus_device *dev) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); ps3vram_begin_ring(priv, UPLOAD_SUBCH, 0, 1); ps3vram_out_ring(priv, 0x31337303); @@ -248,7 +241,7 @@ static int ps3vram_upload(struct ps3_system_bus_device *dev, unsigned int src_offset, unsigned int dst_offset, int len, int count) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); ps3vram_begin_ring(priv, UPLOAD_SUBCH, NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8); @@ -280,7 +273,7 @@ static int ps3vram_download(struct ps3_system_bus_device *dev, unsigned int src_offset, unsigned int dst_offset, int len, int count) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); ps3vram_begin_ring(priv, DOWNLOAD_SUBCH, NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8); @@ -310,7 +303,7 @@ static int ps3vram_download(struct ps3_system_bus_device *dev, static void ps3vram_cache_evict(struct ps3_system_bus_device *dev, int entry) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); struct ps3vram_cache *cache = &priv->cache; if (!(cache->tags[entry].flags & CACHE_PAGE_DIRTY)) @@ -332,7 +325,7 @@ static void ps3vram_cache_evict(struct ps3_system_bus_device *dev, int entry) static void ps3vram_cache_load(struct ps3_system_bus_device *dev, int entry, unsigned int address) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); struct ps3vram_cache *cache = &priv->cache; dev_dbg(&dev->core, "Fetching %d: 0x%08x\n", entry, address); @@ -352,7 +345,7 @@ static void ps3vram_cache_load(struct ps3_system_bus_device *dev, int entry, static void ps3vram_cache_flush(struct ps3_system_bus_device *dev) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); struct ps3vram_cache *cache = &priv->cache; int i; @@ -366,7 +359,7 @@ static void ps3vram_cache_flush(struct ps3_system_bus_device *dev) static unsigned int ps3vram_cache_match(struct ps3_system_bus_device *dev, loff_t address) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); struct ps3vram_cache *cache = &priv->cache; unsigned int base; unsigned int offset; @@ -400,7 +393,7 @@ static unsigned int ps3vram_cache_match(struct ps3_system_bus_device *dev, static int ps3vram_cache_init(struct ps3_system_bus_device *dev) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); priv->cache.page_count = CACHE_PAGE_COUNT; priv->cache.page_size = CACHE_PAGE_SIZE; @@ -419,7 +412,7 @@ static int ps3vram_cache_init(struct ps3_system_bus_device *dev) static void ps3vram_cache_cleanup(struct ps3_system_bus_device *dev) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); ps3vram_cache_flush(dev); kfree(priv->cache.tags); @@ -428,7 +421,7 @@ static void ps3vram_cache_cleanup(struct ps3_system_bus_device *dev) static int ps3vram_read(struct ps3_system_bus_device *dev, loff_t from, size_t len, size_t *retlen, u_char *buf) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); unsigned int cached, count; dev_dbg(&dev->core, "%s: from=0x%08x len=0x%zx\n", __func__, @@ -449,8 +442,6 @@ static int ps3vram_read(struct ps3_system_bus_device *dev, loff_t from, offset = (unsigned int) (from & (priv->cache.page_size - 1)); avail = priv->cache.page_size - offset; - mutex_lock(&priv->lock); - entry = ps3vram_cache_match(dev, from); cached = CACHE_OFFSET + entry * priv->cache.page_size + offset; @@ -462,8 +453,6 @@ static int ps3vram_read(struct ps3_system_bus_device *dev, loff_t from, avail = count; memcpy(buf, priv->xdr_buf + cached, avail); - mutex_unlock(&priv->lock); - buf += avail; count -= avail; from += avail; @@ -476,7 +465,7 @@ static int ps3vram_read(struct ps3_system_bus_device *dev, loff_t from, static int ps3vram_write(struct ps3_system_bus_device *dev, loff_t to, size_t len, size_t *retlen, const u_char *buf) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); unsigned int cached, count; if (to >= priv->size) @@ -494,8 +483,6 @@ static int ps3vram_write(struct ps3_system_bus_device *dev, loff_t to, offset = (unsigned int) (to & (priv->cache.page_size - 1)); avail = priv->cache.page_size - offset; - mutex_lock(&priv->lock); - entry = ps3vram_cache_match(dev, to); cached = CACHE_OFFSET + entry * priv->cache.page_size + offset; @@ -509,8 +496,6 @@ static int ps3vram_write(struct ps3_system_bus_device *dev, loff_t to, priv->cache.tags[entry].flags |= CACHE_PAGE_DIRTY; - mutex_unlock(&priv->lock); - buf += avail; count -= avail; to += avail; @@ -543,28 +528,26 @@ static const struct file_operations ps3vram_proc_fops = { static void __devinit ps3vram_proc_init(struct ps3_system_bus_device *dev) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); struct proc_dir_entry *pde; - pde = proc_create(DEVICE_NAME, 0444, NULL, &ps3vram_proc_fops); - if (!pde) { + pde = proc_create_data(DEVICE_NAME, 0444, NULL, &ps3vram_proc_fops, + priv); + if (!pde) dev_warn(&dev->core, "failed to create /proc entry\n"); - return; - } - pde->data = priv; } -static int ps3vram_make_request(struct request_queue *q, struct bio *bio) +static struct bio *ps3vram_do_bio(struct ps3_system_bus_device *dev, + struct bio *bio) { - struct ps3_system_bus_device *dev = q->queuedata; + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); int write = bio_data_dir(bio) == WRITE; const char *op = write ? "write" : "read"; loff_t offset = bio->bi_sector << 9; int error = 0; struct bio_vec *bvec; unsigned int i; - - dev_dbg(&dev->core, "%s\n", __func__); + struct bio *next; bio_for_each_segment(bvec, bio, i) { /* PS3 is ppc64, so we don't handle highmem */ @@ -585,6 +568,7 @@ static int ps3vram_make_request(struct request_queue *q, struct bio *bio) if (retlen != len) { dev_err(&dev->core, "Short %s\n", op); + error = -EIO; goto out; } @@ -594,7 +578,35 @@ static int ps3vram_make_request(struct request_queue *q, struct bio *bio) dev_dbg(&dev->core, "%s completed\n", op); out: + spin_lock_irq(&priv->lock); + bio_list_pop(&priv->list); + next = bio_list_peek(&priv->list); + spin_unlock_irq(&priv->lock); + bio_endio(bio, error); + return next; +} + +static int ps3vram_make_request(struct request_queue *q, struct bio *bio) +{ + struct ps3_system_bus_device *dev = q->queuedata; + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); + int busy; + + dev_dbg(&dev->core, "%s\n", __func__); + + spin_lock_irq(&priv->lock); + busy = !bio_list_empty(&priv->list); + bio_list_add(&priv->list, bio); + spin_unlock_irq(&priv->lock); + + if (busy) + return 0; + + do { + bio = ps3vram_do_bio(dev, bio); + } while (bio); + return 0; } @@ -604,8 +616,8 @@ static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev) int error, status; struct request_queue *queue; struct gendisk *gendisk; - u64 ddr_lpar, ctrl_lpar, info_lpar, reports_lpar, ddr_size, - reports_size; + u64 ddr_size, ddr_lpar, ctrl_lpar, info_lpar, reports_lpar, + reports_size, xdr_lpar; char *rest; priv = kzalloc(sizeof(*priv), GFP_KERNEL); @@ -614,10 +626,9 @@ static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev) goto fail; } - mutex_init(&priv->lock); - dev->core.driver_data = priv; - - priv = dev->core.driver_data; + spin_lock_init(&priv->lock); + bio_list_init(&priv->list); + ps3_system_bus_set_drvdata(dev, priv); /* Allocate XDR buffer (1MiB aligned) */ priv->xdr_buf = (void *)__get_free_pages(GFP_KERNEL, @@ -636,7 +647,7 @@ static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev) if (ps3_open_hv_device(dev)) { dev_err(&dev->core, "ps3_open_hv_device failed\n"); error = -EAGAIN; - goto out_close_gpu; + goto out_free_xdr_buf; } /* Request memory */ @@ -660,7 +671,7 @@ static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev) dev_err(&dev->core, "lv1_gpu_memory_allocate failed %d\n", status); error = -ENOMEM; - goto out_free_xdr_buf; + goto out_close_gpu; } /* Request context */ @@ -676,9 +687,11 @@ static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev) } /* Map XDR buffer to RSX */ + xdr_lpar = ps3_mm_phys_to_lpar(__pa(priv->xdr_buf)); status = lv1_gpu_context_iomap(priv->context_handle, XDR_IOIF, - ps3_mm_phys_to_lpar(__pa(priv->xdr_buf)), - XDR_BUF_SIZE, 0); + xdr_lpar, XDR_BUF_SIZE, + CBE_IOPTE_PP_W | CBE_IOPTE_PP_R | + CBE_IOPTE_M); if (status) { dev_err(&dev->core, "lv1_gpu_context_iomap failed %d\n", status); @@ -686,19 +699,11 @@ static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev) goto out_free_context; } - priv->ddr_base = ioremap_flags(ddr_lpar, ddr_size, _PAGE_NO_CACHE); - - if (!priv->ddr_base) { - dev_err(&dev->core, "ioremap DDR failed\n"); - error = -ENOMEM; - goto out_free_context; - } - priv->ctrl = ioremap(ctrl_lpar, 64 * 1024); if (!priv->ctrl) { dev_err(&dev->core, "ioremap CTRL failed\n"); error = -ENOMEM; - goto out_unmap_vram; + goto out_unmap_context; } priv->reports = ioremap(reports_lpar, reports_size); @@ -775,8 +780,9 @@ out_unmap_reports: iounmap(priv->reports); out_unmap_ctrl: iounmap(priv->ctrl); -out_unmap_vram: - iounmap(priv->ddr_base); +out_unmap_context: + lv1_gpu_context_iomap(priv->context_handle, XDR_IOIF, xdr_lpar, + XDR_BUF_SIZE, CBE_IOPTE_M); out_free_context: lv1_gpu_context_free(priv->context_handle); out_free_memory: @@ -787,14 +793,14 @@ out_free_xdr_buf: free_pages((unsigned long) priv->xdr_buf, get_order(XDR_BUF_SIZE)); fail_free_priv: kfree(priv); - dev->core.driver_data = NULL; + ps3_system_bus_set_drvdata(dev, NULL); fail: return error; } static int ps3vram_remove(struct ps3_system_bus_device *dev) { - struct ps3vram_priv *priv = dev->core.driver_data; + struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); del_gendisk(priv->gendisk); put_disk(priv->gendisk); @@ -803,13 +809,15 @@ static int ps3vram_remove(struct ps3_system_bus_device *dev) ps3vram_cache_cleanup(dev); iounmap(priv->reports); iounmap(priv->ctrl); - iounmap(priv->ddr_base); + lv1_gpu_context_iomap(priv->context_handle, XDR_IOIF, + ps3_mm_phys_to_lpar(__pa(priv->xdr_buf)), + XDR_BUF_SIZE, CBE_IOPTE_M); lv1_gpu_context_free(priv->context_handle); lv1_gpu_memory_free(priv->memory_handle); ps3_close_hv_device(dev); free_pages((unsigned long) priv->xdr_buf, get_order(XDR_BUF_SIZE)); kfree(priv); - dev->core.driver_data = NULL; + ps3_system_bus_set_drvdata(dev, NULL); return 0; } diff --git a/drivers/block/sunvdc.c b/drivers/block/sunvdc.c index 5861e33efe63..cbfd9c0aef03 100644 --- a/drivers/block/sunvdc.c +++ b/drivers/block/sunvdc.c @@ -212,11 +212,6 @@ static void vdc_end_special(struct vdc_port *port, struct vio_disk_desc *desc) vdc_finish(&port->vio, -err, WAITING_FOR_GEN_CMD); } -static void vdc_end_request(struct request *req, int error, int num_sectors) -{ - __blk_end_request(req, error, num_sectors << 9); -} - static void vdc_end_one(struct vdc_port *port, struct vio_dring_state *dr, unsigned int index) { @@ -239,7 +234,7 @@ static void vdc_end_one(struct vdc_port *port, struct vio_dring_state *dr, rqe->req = NULL; - vdc_end_request(req, (desc->status ? -EIO : 0), desc->size >> 9); + __blk_end_request(req, (desc->status ? -EIO : 0), desc->size); if (blk_queue_stopped(port->disk->queue)) blk_start_queue(port->disk->queue); @@ -421,7 +416,7 @@ static int __send_request(struct request *req) desc->slice = 0; } desc->status = ~0; - desc->offset = (req->sector << 9) / port->vdisk_block_size; + desc->offset = (blk_rq_pos(req) << 9) / port->vdisk_block_size; desc->size = len; desc->ncookies = err; @@ -446,14 +441,13 @@ out: static void do_vdc_request(struct request_queue *q) { while (1) { - struct request *req = elv_next_request(q); + struct request *req = blk_fetch_request(q); if (!req) break; - blkdev_dequeue_request(req); if (__send_request(req) < 0) - vdc_end_request(req, -EIO, req->hard_nr_sectors); + __blk_end_request_all(req, -EIO); } } diff --git a/drivers/block/swim.c b/drivers/block/swim.c index d22cc3856937..cf7877fb8a7d 100644 --- a/drivers/block/swim.c +++ b/drivers/block/swim.c @@ -514,7 +514,7 @@ static int floppy_read_sectors(struct floppy_state *fs, ret = swim_read_sector(fs, side, track, sector, buffer); if (try-- == 0) - return -1; + return -EIO; } while (ret != 512); buffer += ret; @@ -528,45 +528,31 @@ static void redo_fd_request(struct request_queue *q) struct request *req; struct floppy_state *fs; - while ((req = elv_next_request(q))) { + req = blk_fetch_request(q); + while (req) { + int err = -EIO; fs = req->rq_disk->private_data; - if (req->sector < 0 || req->sector >= fs->total_secs) { - end_request(req, 0); - continue; - } - if (req->current_nr_sectors == 0) { - end_request(req, 1); - continue; - } - if (!fs->disk_in) { - end_request(req, 0); - continue; - } - if (rq_data_dir(req) == WRITE) { - if (fs->write_protected) { - end_request(req, 0); - continue; - } - } + if (blk_rq_pos(req) >= fs->total_secs) + goto done; + if (!fs->disk_in) + goto done; + if (rq_data_dir(req) == WRITE && fs->write_protected) + goto done; + switch (rq_data_dir(req)) { case WRITE: /* NOT IMPLEMENTED */ - end_request(req, 0); break; case READ: - if (floppy_read_sectors(fs, req->sector, - req->current_nr_sectors, - req->buffer)) { - end_request(req, 0); - continue; - } - req->nr_sectors -= req->current_nr_sectors; - req->sector += req->current_nr_sectors; - req->buffer += req->current_nr_sectors * 512; - end_request(req, 1); + err = floppy_read_sectors(fs, blk_rq_pos(req), + blk_rq_cur_sectors(req), + req->buffer); break; } + done: + if (!__blk_end_request_cur(req, err)) + req = blk_fetch_request(q); } } diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c index 612965307ba0..80df93e3cdd0 100644 --- a/drivers/block/swim3.c +++ b/drivers/block/swim3.c @@ -251,6 +251,20 @@ static int floppy_release(struct gendisk *disk, fmode_t mode); static int floppy_check_change(struct gendisk *disk); static int floppy_revalidate(struct gendisk *disk); +static bool swim3_end_request(int err, unsigned int nr_bytes) +{ + if (__blk_end_request(fd_req, err, nr_bytes)) + return true; + + fd_req = NULL; + return false; +} + +static bool swim3_end_request_cur(int err) +{ + return swim3_end_request(err, blk_rq_cur_bytes(fd_req)); +} + static void swim3_select(struct floppy_state *fs, int sel) { struct swim3 __iomem *sw = fs->swim3; @@ -310,25 +324,27 @@ static void start_request(struct floppy_state *fs) wake_up(&fs->wait); return; } - while (fs->state == idle && (req = elv_next_request(swim3_queue))) { + while (fs->state == idle) { + if (!fd_req) { + fd_req = blk_fetch_request(swim3_queue); + if (!fd_req) + break; + } + req = fd_req; #if 0 - printk("do_fd_req: dev=%s cmd=%d sec=%ld nr_sec=%ld buf=%p\n", + printk("do_fd_req: dev=%s cmd=%d sec=%ld nr_sec=%u buf=%p\n", req->rq_disk->disk_name, req->cmd, - (long)req->sector, req->nr_sectors, req->buffer); - printk(" errors=%d current_nr_sectors=%ld\n", - req->errors, req->current_nr_sectors); + (long)blk_rq_pos(req), blk_rq_sectors(req), req->buffer); + printk(" errors=%d current_nr_sectors=%u\n", + req->errors, blk_rq_cur_sectors(req)); #endif - if (req->sector < 0 || req->sector >= fs->total_secs) { - end_request(req, 0); - continue; - } - if (req->current_nr_sectors == 0) { - end_request(req, 1); + if (blk_rq_pos(req) >= fs->total_secs) { + swim3_end_request_cur(-EIO); continue; } if (fs->ejected) { - end_request(req, 0); + swim3_end_request_cur(-EIO); continue; } @@ -336,18 +352,19 @@ static void start_request(struct floppy_state *fs) if (fs->write_prot < 0) fs->write_prot = swim3_readbit(fs, WRITE_PROT); if (fs->write_prot) { - end_request(req, 0); + swim3_end_request_cur(-EIO); continue; } } - /* Do not remove the cast. req->sector is now a sector_t and - * can be 64 bits, but it will never go past 32 bits for this - * driver anyway, so we can safely cast it down and not have - * to do a 64/32 division + /* Do not remove the cast. blk_rq_pos(req) is now a + * sector_t and can be 64 bits, but it will never go + * past 32 bits for this driver anyway, so we can + * safely cast it down and not have to do a 64/32 + * division */ - fs->req_cyl = ((long)req->sector) / fs->secpercyl; - x = ((long)req->sector) % fs->secpercyl; + fs->req_cyl = ((long)blk_rq_pos(req)) / fs->secpercyl; + x = ((long)blk_rq_pos(req)) % fs->secpercyl; fs->head = x / fs->secpertrack; fs->req_sector = x % fs->secpertrack + 1; fd_req = req; @@ -424,7 +441,7 @@ static inline void setup_transfer(struct floppy_state *fs) struct dbdma_cmd *cp = fs->dma_cmd; struct dbdma_regs __iomem *dr = fs->dma; - if (fd_req->current_nr_sectors <= 0) { + if (blk_rq_cur_sectors(fd_req) <= 0) { printk(KERN_ERR "swim3: transfer 0 sectors?\n"); return; } @@ -432,8 +449,8 @@ static inline void setup_transfer(struct floppy_state *fs) n = 1; else { n = fs->secpertrack - fs->req_sector + 1; - if (n > fd_req->current_nr_sectors) - n = fd_req->current_nr_sectors; + if (n > blk_rq_cur_sectors(fd_req)) + n = blk_rq_cur_sectors(fd_req); } fs->scount = n; swim3_select(fs, fs->head? READ_DATA_1: READ_DATA_0); @@ -508,7 +525,7 @@ static void act(struct floppy_state *fs) case do_transfer: if (fs->cur_cyl != fs->req_cyl) { if (fs->retries > 5) { - end_request(fd_req, 0); + swim3_end_request_cur(-EIO); fs->state = idle; return; } @@ -540,7 +557,7 @@ static void scan_timeout(unsigned long data) out_8(&sw->intr_enable, 0); fs->cur_cyl = -1; if (fs->retries > 5) { - end_request(fd_req, 0); + swim3_end_request_cur(-EIO); fs->state = idle; start_request(fs); } else { @@ -559,7 +576,7 @@ static void seek_timeout(unsigned long data) out_8(&sw->select, RELAX); out_8(&sw->intr_enable, 0); printk(KERN_ERR "swim3: seek timeout\n"); - end_request(fd_req, 0); + swim3_end_request_cur(-EIO); fs->state = idle; start_request(fs); } @@ -583,7 +600,7 @@ static void settle_timeout(unsigned long data) return; } printk(KERN_ERR "swim3: seek settle timeout\n"); - end_request(fd_req, 0); + swim3_end_request_cur(-EIO); fs->state = idle; start_request(fs); } @@ -593,8 +610,6 @@ static void xfer_timeout(unsigned long data) struct floppy_state *fs = (struct floppy_state *) data; struct swim3 __iomem *sw = fs->swim3; struct dbdma_regs __iomem *dr = fs->dma; - struct dbdma_cmd *cp = fs->dma_cmd; - unsigned long s; int n; fs->timeout_pending = 0; @@ -605,17 +620,10 @@ static void xfer_timeout(unsigned long data) out_8(&sw->intr_enable, 0); out_8(&sw->control_bic, WRITE_SECTORS | DO_ACTION); out_8(&sw->select, RELAX); - if (rq_data_dir(fd_req) == WRITE) - ++cp; - if (ld_le16(&cp->xfer_status) != 0) - s = fs->scount - ((ld_le16(&cp->res_count) + 511) >> 9); - else - s = 0; - fd_req->sector += s; - fd_req->current_nr_sectors -= s; printk(KERN_ERR "swim3: timeout %sing sector %ld\n", - (rq_data_dir(fd_req)==WRITE? "writ": "read"), (long)fd_req->sector); - end_request(fd_req, 0); + (rq_data_dir(fd_req)==WRITE? "writ": "read"), + (long)blk_rq_pos(fd_req)); + swim3_end_request_cur(-EIO); fs->state = idle; start_request(fs); } @@ -646,7 +654,7 @@ static irqreturn_t swim3_interrupt(int irq, void *dev_id) printk(KERN_ERR "swim3: seen sector but cyl=ff?\n"); fs->cur_cyl = -1; if (fs->retries > 5) { - end_request(fd_req, 0); + swim3_end_request_cur(-EIO); fs->state = idle; start_request(fs); } else { @@ -719,9 +727,7 @@ static irqreturn_t swim3_interrupt(int irq, void *dev_id) if (intr & ERROR_INTR) { n = fs->scount - 1 - resid / 512; if (n > 0) { - fd_req->sector += n; - fd_req->current_nr_sectors -= n; - fd_req->buffer += n * 512; + blk_update_request(fd_req, 0, n << 9); fs->req_sector += n; } if (fs->retries < 5) { @@ -730,8 +736,8 @@ static irqreturn_t swim3_interrupt(int irq, void *dev_id) } else { printk("swim3: error %sing block %ld (err=%x)\n", rq_data_dir(fd_req) == WRITE? "writ": "read", - (long)fd_req->sector, err); - end_request(fd_req, 0); + (long)blk_rq_pos(fd_req), err); + swim3_end_request_cur(-EIO); fs->state = idle; } } else { @@ -740,18 +746,12 @@ static irqreturn_t swim3_interrupt(int irq, void *dev_id) printk(KERN_ERR "swim3: fd dma: stat=%x resid=%d\n", stat, resid); printk(KERN_ERR " state=%d, dir=%x, intr=%x, err=%x\n", fs->state, rq_data_dir(fd_req), intr, err); - end_request(fd_req, 0); + swim3_end_request_cur(-EIO); fs->state = idle; start_request(fs); break; } - fd_req->sector += fs->scount; - fd_req->current_nr_sectors -= fs->scount; - fd_req->buffer += fs->scount * 512; - if (fd_req->current_nr_sectors <= 0) { - end_request(fd_req, 1); - fs->state = idle; - } else { + if (swim3_end_request(0, fs->scount << 9)) { fs->req_sector += fs->scount; if (fs->req_sector > fs->secpertrack) { fs->req_sector -= fs->secpertrack; @@ -761,7 +761,8 @@ static irqreturn_t swim3_interrupt(int irq, void *dev_id) } } act(fs); - } + } else + fs->state = idle; } if (fs->state == idle) start_request(fs); diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c index ff0448e4bf03..da403b6a7f43 100644 --- a/drivers/block/sx8.c +++ b/drivers/block/sx8.c @@ -749,8 +749,7 @@ static inline void carm_end_request_queued(struct carm_host *host, struct request *req = crq->rq; int rc; - rc = __blk_end_request(req, error, blk_rq_bytes(req)); - assert(rc == 0); + __blk_end_request_all(req, error); rc = carm_put_request(host, crq); assert(rc == 0); @@ -811,12 +810,10 @@ static void carm_oob_rq_fn(struct request_queue *q) while (1) { DPRINTK("get req\n"); - rq = elv_next_request(q); + rq = blk_fetch_request(q); if (!rq) break; - blkdev_dequeue_request(rq); - crq = rq->special; assert(crq != NULL); assert(crq->rq == rq); @@ -847,7 +844,7 @@ static void carm_rq_fn(struct request_queue *q) queue_one_request: VPRINTK("get req\n"); - rq = elv_next_request(q); + rq = blk_peek_request(q); if (!rq) return; @@ -858,7 +855,7 @@ queue_one_request: } crq->rq = rq; - blkdev_dequeue_request(rq); + blk_start_request(rq); if (rq_data_dir(rq) == WRITE) { writing = 1; @@ -904,10 +901,10 @@ queue_one_request: msg->sg_count = n_elem; msg->sg_type = SGT_32BIT; msg->handle = cpu_to_le32(TAG_ENCODE(crq->tag)); - msg->lba = cpu_to_le32(rq->sector & 0xffffffff); - tmp = (rq->sector >> 16) >> 16; + msg->lba = cpu_to_le32(blk_rq_pos(rq) & 0xffffffff); + tmp = (blk_rq_pos(rq) >> 16) >> 16; msg->lba_high = cpu_to_le16( (u16) tmp ); - msg->lba_count = cpu_to_le16(rq->nr_sectors); + msg->lba_count = cpu_to_le16(blk_rq_sectors(rq)); msg_size = sizeof(struct carm_msg_rw) - sizeof(msg->sg); for (i = 0; i < n_elem; i++) { diff --git a/drivers/block/ub.c b/drivers/block/ub.c index 689cd27ac890..cc54473b8e77 100644 --- a/drivers/block/ub.c +++ b/drivers/block/ub.c @@ -360,8 +360,7 @@ static void ub_cmd_build_block(struct ub_dev *sc, struct ub_lun *lun, static void ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun, struct ub_scsi_cmd *cmd, struct ub_request *urq); static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd); -static void ub_end_rq(struct request *rq, unsigned int status, - unsigned int cmd_len); +static void ub_end_rq(struct request *rq, unsigned int status); static int ub_rw_cmd_retry(struct ub_dev *sc, struct ub_lun *lun, struct ub_request *urq, struct ub_scsi_cmd *cmd); static int ub_submit_scsi(struct ub_dev *sc, struct ub_scsi_cmd *cmd); @@ -627,7 +626,7 @@ static void ub_request_fn(struct request_queue *q) struct ub_lun *lun = q->queuedata; struct request *rq; - while ((rq = elv_next_request(q)) != NULL) { + while ((rq = blk_peek_request(q)) != NULL) { if (ub_request_fn_1(lun, rq) != 0) { blk_stop_queue(q); break; @@ -643,14 +642,14 @@ static int ub_request_fn_1(struct ub_lun *lun, struct request *rq) int n_elem; if (atomic_read(&sc->poison)) { - blkdev_dequeue_request(rq); - ub_end_rq(rq, DID_NO_CONNECT << 16, blk_rq_bytes(rq)); + blk_start_request(rq); + ub_end_rq(rq, DID_NO_CONNECT << 16); return 0; } if (lun->changed && !blk_pc_request(rq)) { - blkdev_dequeue_request(rq); - ub_end_rq(rq, SAM_STAT_CHECK_CONDITION, blk_rq_bytes(rq)); + blk_start_request(rq); + ub_end_rq(rq, SAM_STAT_CHECK_CONDITION); return 0; } @@ -660,7 +659,7 @@ static int ub_request_fn_1(struct ub_lun *lun, struct request *rq) return -1; memset(cmd, 0, sizeof(struct ub_scsi_cmd)); - blkdev_dequeue_request(rq); + blk_start_request(rq); urq = &lun->urq; memset(urq, 0, sizeof(struct ub_request)); @@ -702,7 +701,7 @@ static int ub_request_fn_1(struct ub_lun *lun, struct request *rq) drop: ub_put_cmd(lun, cmd); - ub_end_rq(rq, DID_ERROR << 16, blk_rq_bytes(rq)); + ub_end_rq(rq, DID_ERROR << 16); return 0; } @@ -723,11 +722,11 @@ static void ub_cmd_build_block(struct ub_dev *sc, struct ub_lun *lun, /* * build the command * - * The call to blk_queue_hardsect_size() guarantees that request + * The call to blk_queue_logical_block_size() guarantees that request * is aligned, but it is given in terms of 512 byte units, always. */ - block = rq->sector >> lun->capacity.bshift; - nblks = rq->nr_sectors >> lun->capacity.bshift; + block = blk_rq_pos(rq) >> lun->capacity.bshift; + nblks = blk_rq_sectors(rq) >> lun->capacity.bshift; cmd->cdb[0] = (cmd->dir == UB_DIR_READ)? READ_10: WRITE_10; /* 10-byte uses 4 bytes of LBA: 2147483648KB, 2097152MB, 2048GB */ @@ -739,7 +738,7 @@ static void ub_cmd_build_block(struct ub_dev *sc, struct ub_lun *lun, cmd->cdb[8] = nblks; cmd->cdb_len = 10; - cmd->len = rq->nr_sectors * 512; + cmd->len = blk_rq_bytes(rq); } static void ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun, @@ -747,7 +746,7 @@ static void ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun, { struct request *rq = urq->rq; - if (rq->data_len == 0) { + if (blk_rq_bytes(rq) == 0) { cmd->dir = UB_DIR_NONE; } else { if (rq_data_dir(rq) == WRITE) @@ -762,7 +761,7 @@ static void ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun, memcpy(&cmd->cdb, rq->cmd, rq->cmd_len); cmd->cdb_len = rq->cmd_len; - cmd->len = rq->data_len; + cmd->len = blk_rq_bytes(rq); /* * To reapply this to every URB is not as incorrect as it looks. @@ -777,16 +776,15 @@ static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd) struct ub_request *urq = cmd->back; struct request *rq; unsigned int scsi_status; - unsigned int cmd_len; rq = urq->rq; if (cmd->error == 0) { if (blk_pc_request(rq)) { - if (cmd->act_len >= rq->data_len) - rq->data_len = 0; + if (cmd->act_len >= rq->resid_len) + rq->resid_len = 0; else - rq->data_len -= cmd->act_len; + rq->resid_len -= cmd->act_len; scsi_status = 0; } else { if (cmd->act_len != cmd->len) { @@ -818,17 +816,14 @@ static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd) urq->rq = NULL; - cmd_len = cmd->len; ub_put_cmd(lun, cmd); - ub_end_rq(rq, scsi_status, cmd_len); + ub_end_rq(rq, scsi_status); blk_start_queue(lun->disk->queue); } -static void ub_end_rq(struct request *rq, unsigned int scsi_status, - unsigned int cmd_len) +static void ub_end_rq(struct request *rq, unsigned int scsi_status) { int error; - long rqlen; if (scsi_status == 0) { error = 0; @@ -836,12 +831,7 @@ static void ub_end_rq(struct request *rq, unsigned int scsi_status, error = -EIO; rq->errors = scsi_status; } - rqlen = blk_rq_bytes(rq); /* Oddly enough, this is the residue. */ - if (__blk_end_request(rq, error, cmd_len)) { - printk(KERN_WARNING DRV_NAME - ": __blk_end_request blew, %s-cmd total %u rqlen %ld\n", - blk_pc_request(rq)? "pc": "fs", cmd_len, rqlen); - } + __blk_end_request_all(rq, error); } static int ub_rw_cmd_retry(struct ub_dev *sc, struct ub_lun *lun, @@ -1759,7 +1749,7 @@ static int ub_bd_revalidate(struct gendisk *disk) ub_revalidate(lun->udev, lun); /* XXX Support sector size switching like in sr.c */ - blk_queue_hardsect_size(disk->queue, lun->capacity.bsize); + blk_queue_logical_block_size(disk->queue, lun->capacity.bsize); set_capacity(disk, lun->capacity.nsec); // set_disk_ro(sdkp->disk, lun->readonly); @@ -2334,7 +2324,7 @@ static int ub_probe_lun(struct ub_dev *sc, int lnum) blk_queue_max_phys_segments(q, UB_MAX_REQ_SG); blk_queue_segment_boundary(q, 0xffffffff); /* Dubious. */ blk_queue_max_sectors(q, UB_MAX_SECTORS); - blk_queue_hardsect_size(q, lun->capacity.bsize); + blk_queue_logical_block_size(q, lun->capacity.bsize); lun->disk = disk; q->queuedata = lun; diff --git a/drivers/block/viodasd.c b/drivers/block/viodasd.c index ecccf65dce2f..390d69bb7c48 100644 --- a/drivers/block/viodasd.c +++ b/drivers/block/viodasd.c @@ -252,7 +252,7 @@ static int send_request(struct request *req) struct viodasd_device *d; unsigned long flags; - start = (u64)req->sector << 9; + start = (u64)blk_rq_pos(req) << 9; if (rq_data_dir(req) == READ) { direction = DMA_FROM_DEVICE; @@ -361,19 +361,17 @@ static void do_viodasd_request(struct request_queue *q) * back later. */ while (num_req_outstanding < VIOMAXREQ) { - req = elv_next_request(q); + req = blk_fetch_request(q); if (req == NULL) return; - /* dequeue the current request from the queue */ - blkdev_dequeue_request(req); /* check that request contains a valid command */ if (!blk_fs_request(req)) { - viodasd_end_request(req, -EIO, req->hard_nr_sectors); + viodasd_end_request(req, -EIO, blk_rq_sectors(req)); continue; } /* Try sending the request */ if (send_request(req) != 0) - viodasd_end_request(req, -EIO, req->hard_nr_sectors); + viodasd_end_request(req, -EIO, blk_rq_sectors(req)); } } @@ -590,7 +588,7 @@ static int viodasd_handle_read_write(struct vioblocklpevent *bevent) err = vio_lookup_rc(viodasd_err_table, bevent->sub_result); printk(VIOD_KERN_WARNING "read/write error %d:0x%04x (%s)\n", event->xRc, bevent->sub_result, err->msg); - num_sect = req->hard_nr_sectors; + num_sect = blk_rq_sectors(req); } qlock = req->q->queue_lock; spin_lock_irqsave(qlock, irq_flags); diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index 5d34764c8a87..43db3ea15b54 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -37,6 +37,7 @@ struct virtblk_req struct list_head list; struct request *req; struct virtio_blk_outhdr out_hdr; + struct virtio_scsi_inhdr in_hdr; u8 status; }; @@ -50,6 +51,7 @@ static void blk_done(struct virtqueue *vq) spin_lock_irqsave(&vblk->lock, flags); while ((vbr = vblk->vq->vq_ops->get_buf(vblk->vq, &len)) != NULL) { int error; + switch (vbr->status) { case VIRTIO_BLK_S_OK: error = 0; @@ -62,7 +64,13 @@ static void blk_done(struct virtqueue *vq) break; } - __blk_end_request(vbr->req, error, blk_rq_bytes(vbr->req)); + if (blk_pc_request(vbr->req)) { + vbr->req->resid_len = vbr->in_hdr.residual; + vbr->req->sense_len = vbr->in_hdr.sense_len; + vbr->req->errors = vbr->in_hdr.errors; + } + + __blk_end_request_all(vbr->req, error); list_del(&vbr->list); mempool_free(vbr, vblk->pool); } @@ -74,7 +82,7 @@ static void blk_done(struct virtqueue *vq) static bool do_req(struct request_queue *q, struct virtio_blk *vblk, struct request *req) { - unsigned long num, out, in; + unsigned long num, out = 0, in = 0; struct virtblk_req *vbr; vbr = mempool_alloc(vblk->pool, GFP_ATOMIC); @@ -85,7 +93,7 @@ static bool do_req(struct request_queue *q, struct virtio_blk *vblk, vbr->req = req; if (blk_fs_request(vbr->req)) { vbr->out_hdr.type = 0; - vbr->out_hdr.sector = vbr->req->sector; + vbr->out_hdr.sector = blk_rq_pos(vbr->req); vbr->out_hdr.ioprio = req_get_ioprio(vbr->req); } else if (blk_pc_request(vbr->req)) { vbr->out_hdr.type = VIRTIO_BLK_T_SCSI_CMD; @@ -99,18 +107,36 @@ static bool do_req(struct request_queue *q, struct virtio_blk *vblk, if (blk_barrier_rq(vbr->req)) vbr->out_hdr.type |= VIRTIO_BLK_T_BARRIER; - sg_set_buf(&vblk->sg[0], &vbr->out_hdr, sizeof(vbr->out_hdr)); - num = blk_rq_map_sg(q, vbr->req, vblk->sg+1); - sg_set_buf(&vblk->sg[num+1], &vbr->status, sizeof(vbr->status)); + sg_set_buf(&vblk->sg[out++], &vbr->out_hdr, sizeof(vbr->out_hdr)); - if (rq_data_dir(vbr->req) == WRITE) { - vbr->out_hdr.type |= VIRTIO_BLK_T_OUT; - out = 1 + num; - in = 1; - } else { - vbr->out_hdr.type |= VIRTIO_BLK_T_IN; - out = 1; - in = 1 + num; + /* + * If this is a packet command we need a couple of additional headers. + * Behind the normal outhdr we put a segment with the scsi command + * block, and before the normal inhdr we put the sense data and the + * inhdr with additional status information before the normal inhdr. + */ + if (blk_pc_request(vbr->req)) + sg_set_buf(&vblk->sg[out++], vbr->req->cmd, vbr->req->cmd_len); + + num = blk_rq_map_sg(q, vbr->req, vblk->sg + out); + + if (blk_pc_request(vbr->req)) { + sg_set_buf(&vblk->sg[num + out + in++], vbr->req->sense, 96); + sg_set_buf(&vblk->sg[num + out + in++], &vbr->in_hdr, + sizeof(vbr->in_hdr)); + } + + sg_set_buf(&vblk->sg[num + out + in++], &vbr->status, + sizeof(vbr->status)); + + if (num) { + if (rq_data_dir(vbr->req) == WRITE) { + vbr->out_hdr.type |= VIRTIO_BLK_T_OUT; + out += num; + } else { + vbr->out_hdr.type |= VIRTIO_BLK_T_IN; + in += num; + } } if (vblk->vq->vq_ops->add_buf(vblk->vq, vblk->sg, out, in, vbr)) { @@ -124,12 +150,11 @@ static bool do_req(struct request_queue *q, struct virtio_blk *vblk, static void do_virtblk_request(struct request_queue *q) { - struct virtio_blk *vblk = NULL; + struct virtio_blk *vblk = q->queuedata; struct request *req; unsigned int issued = 0; - while ((req = elv_next_request(q)) != NULL) { - vblk = req->rq_disk->private_data; + while ((req = blk_peek_request(q)) != NULL) { BUG_ON(req->nr_phys_segments + 2 > vblk->sg_elems); /* If this request fails, stop queue and wait for something to @@ -138,7 +163,7 @@ static void do_virtblk_request(struct request_queue *q) blk_stop_queue(q); break; } - blkdev_dequeue_request(req); + blk_start_request(req); issued++; } @@ -146,12 +171,51 @@ static void do_virtblk_request(struct request_queue *q) vblk->vq->vq_ops->kick(vblk->vq); } +/* return ATA identify data + */ +static int virtblk_identify(struct gendisk *disk, void *argp) +{ + struct virtio_blk *vblk = disk->private_data; + void *opaque; + int err = -ENOMEM; + + opaque = kmalloc(VIRTIO_BLK_ID_BYTES, GFP_KERNEL); + if (!opaque) + goto out; + + err = virtio_config_buf(vblk->vdev, VIRTIO_BLK_F_IDENTIFY, + offsetof(struct virtio_blk_config, identify), opaque, + VIRTIO_BLK_ID_BYTES); + + if (err) + goto out_kfree; + + if (copy_to_user(argp, opaque, VIRTIO_BLK_ID_BYTES)) + err = -EFAULT; + +out_kfree: + kfree(opaque); +out: + return err; +} + static int virtblk_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd, unsigned long data) { - return scsi_cmd_ioctl(bdev->bd_disk->queue, - bdev->bd_disk, mode, cmd, - (void __user *)data); + struct gendisk *disk = bdev->bd_disk; + struct virtio_blk *vblk = disk->private_data; + void __user *argp = (void __user *)data; + + if (cmd == HDIO_GET_IDENTITY) + return virtblk_identify(disk, argp); + + /* + * Only allow the generic SCSI ioctls if the host can support it. + */ + if (!virtio_has_feature(vblk->vdev, VIRTIO_BLK_F_SCSI)) + return -ENOIOCTLCMD; + + return scsi_cmd_ioctl(disk->queue, disk, mode, cmd, argp); } /* We provide getgeo only to please some old bootloader/partitioning tools */ @@ -190,7 +254,7 @@ static int index_to_minor(int index) return index << PART_BITS; } -static int virtblk_probe(struct virtio_device *vdev) +static int __devinit virtblk_probe(struct virtio_device *vdev) { struct virtio_blk *vblk; int err; @@ -224,7 +288,7 @@ static int virtblk_probe(struct virtio_device *vdev) sg_init_table(vblk->sg, vblk->sg_elems); /* We expect one virtqueue, for output. */ - vblk->vq = vdev->config->find_vq(vdev, 0, blk_done); + vblk->vq = virtio_find_single_vq(vdev, blk_done, "requests"); if (IS_ERR(vblk->vq)) { err = PTR_ERR(vblk->vq); goto out_free_vblk; @@ -249,6 +313,7 @@ static int virtblk_probe(struct virtio_device *vdev) goto out_put_disk; } + vblk->disk->queue->queuedata = vblk; queue_flag_set_unlocked(QUEUE_FLAG_VIRT, vblk->disk->queue); if (index < 26) { @@ -313,7 +378,7 @@ static int virtblk_probe(struct virtio_device *vdev) offsetof(struct virtio_blk_config, blk_size), &blk_size); if (!err) - blk_queue_hardsect_size(vblk->disk->queue, blk_size); + blk_queue_logical_block_size(vblk->disk->queue, blk_size); add_disk(vblk->disk); return 0; @@ -323,14 +388,14 @@ out_put_disk: out_mempool: mempool_destroy(vblk->pool); out_free_vq: - vdev->config->del_vq(vblk->vq); + vdev->config->del_vqs(vdev); out_free_vblk: kfree(vblk); out: return err; } -static void virtblk_remove(struct virtio_device *vdev) +static void __devexit virtblk_remove(struct virtio_device *vdev) { struct virtio_blk *vblk = vdev->priv; @@ -344,7 +409,7 @@ static void virtblk_remove(struct virtio_device *vdev) blk_cleanup_queue(vblk->disk->queue); put_disk(vblk->disk); mempool_destroy(vblk->pool); - vdev->config->del_vq(vblk->vq); + vdev->config->del_vqs(vdev); kfree(vblk); } @@ -356,6 +421,7 @@ static struct virtio_device_id id_table[] = { static unsigned int features[] = { VIRTIO_BLK_F_BARRIER, VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX, VIRTIO_BLK_F_GEOMETRY, VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE, + VIRTIO_BLK_F_SCSI, VIRTIO_BLK_F_IDENTIFY }; static struct virtio_driver virtio_blk = { diff --git a/drivers/block/xd.c b/drivers/block/xd.c index 64b496fce98b..ce2429219925 100644 --- a/drivers/block/xd.c +++ b/drivers/block/xd.c @@ -305,30 +305,25 @@ static void do_xd_request (struct request_queue * q) if (xdc_busy) return; - while ((req = elv_next_request(q)) != NULL) { - unsigned block = req->sector; - unsigned count = req->nr_sectors; - int rw = rq_data_dir(req); + req = blk_fetch_request(q); + while (req) { + unsigned block = blk_rq_pos(req); + unsigned count = blk_rq_cur_sectors(req); XD_INFO *disk = req->rq_disk->private_data; - int res = 0; + int res = -EIO; int retry; - if (!blk_fs_request(req)) { - end_request(req, 0); - continue; - } - if (block + count > get_capacity(req->rq_disk)) { - end_request(req, 0); - continue; - } - if (rw != READ && rw != WRITE) { - printk("do_xd_request: unknown request\n"); - end_request(req, 0); - continue; - } + if (!blk_fs_request(req)) + goto done; + if (block + count > get_capacity(req->rq_disk)) + goto done; for (retry = 0; (retry < XD_RETRIES) && !res; retry++) - res = xd_readwrite(rw, disk, req->buffer, block, count); - end_request(req, res); /* wrap up, 0 = fail, 1 = success */ + res = xd_readwrite(rq_data_dir(req), disk, req->buffer, + block, count); + done: + /* wrap up, 0 = success, -errno = fail */ + if (!__blk_end_request_cur(req, res)) + req = blk_fetch_request(q); } } @@ -418,7 +413,7 @@ static int xd_readwrite (u_char operation,XD_INFO *p,char *buffer,u_int block,u_ printk("xd%c: %s timeout, recalibrating drive\n",'a'+drive,(operation == READ ? "read" : "write")); xd_recalibrate(drive); spin_lock_irq(&xd_lock); - return (0); + return -EIO; case 2: if (sense[0] & 0x30) { printk("xd%c: %s - ",'a'+drive,(operation == READ ? "reading" : "writing")); @@ -439,7 +434,7 @@ static int xd_readwrite (u_char operation,XD_INFO *p,char *buffer,u_int block,u_ else printk(" - no valid disk address\n"); spin_lock_irq(&xd_lock); - return (0); + return -EIO; } if (xd_dma_buffer) for (i=0; i < (temp * 0x200); i++) @@ -448,7 +443,7 @@ static int xd_readwrite (u_char operation,XD_INFO *p,char *buffer,u_int block,u_ count -= temp, buffer += temp * 0x200, block += temp; } spin_lock_irq(&xd_lock); - return (1); + return 0; } /* xd_recalibrate: recalibrate a given drive and reset controller if necessary */ diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index a6cbf7b808e6..e53284767f7c 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -122,7 +122,7 @@ static DEFINE_SPINLOCK(blkif_io_lock); static int get_id_from_freelist(struct blkfront_info *info) { unsigned long free = info->shadow_free; - BUG_ON(free > BLK_RING_SIZE); + BUG_ON(free >= BLK_RING_SIZE); info->shadow_free = info->shadow[free].req.id; info->shadow[free].req.id = 0x0fffffee; /* debug */ return free; @@ -231,7 +231,7 @@ static int blkif_queue_request(struct request *req) info->shadow[id].request = (unsigned long)req; ring_req->id = id; - ring_req->sector_number = (blkif_sector_t)req->sector; + ring_req->sector_number = (blkif_sector_t)blk_rq_pos(req); ring_req->handle = info->handle; ring_req->operation = rq_data_dir(req) ? @@ -299,25 +299,25 @@ static void do_blkif_request(struct request_queue *rq) queued = 0; - while ((req = elv_next_request(rq)) != NULL) { + while ((req = blk_peek_request(rq)) != NULL) { info = req->rq_disk->private_data; - if (!blk_fs_request(req)) { - end_request(req, 0); - continue; - } if (RING_FULL(&info->ring)) goto wait; + blk_start_request(req); + + if (!blk_fs_request(req)) { + __blk_end_request_all(req, -EIO); + continue; + } + pr_debug("do_blk_req %p: cmd %p, sec %lx, " - "(%u/%li) buffer:%p [%s]\n", - req, req->cmd, (unsigned long)req->sector, - req->current_nr_sectors, - req->nr_sectors, req->buffer, - rq_data_dir(req) ? "write" : "read"); + "(%u/%u) buffer:%p [%s]\n", + req, req->cmd, (unsigned long)blk_rq_pos(req), + blk_rq_cur_sectors(req), blk_rq_sectors(req), + req->buffer, rq_data_dir(req) ? "write" : "read"); - - blkdev_dequeue_request(req); if (blkif_queue_request(req)) { blk_requeue_request(rq, req); wait: @@ -344,7 +344,7 @@ static int xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size) queue_flag_set_unlocked(QUEUE_FLAG_VIRT, rq); /* Hard sector size and max sectors impersonate the equiv. hardware. */ - blk_queue_hardsect_size(rq, sector_size); + blk_queue_logical_block_size(rq, sector_size); blk_queue_max_sectors(rq, 512); /* Each segment in a request is up to an aligned page in size. */ @@ -551,7 +551,6 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id) for (i = info->ring.rsp_cons; i != rp; i++) { unsigned long id; - int ret; bret = RING_GET_RESPONSE(&info->ring, i); id = bret->id; @@ -578,8 +577,7 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id) dev_dbg(&info->xbdev->dev, "Bad return from blkdev data " "request: %x\n", bret->status); - ret = __blk_end_request(req, error, blk_rq_bytes(req)); - BUG_ON(ret); + __blk_end_request_all(req, error); break; default: BUG(); @@ -755,12 +753,12 @@ static int blkfront_probe(struct xenbus_device *dev, /* Front end dir is a number, which is used as the id. */ info->handle = simple_strtoul(strrchr(dev->nodename, '/')+1, NULL, 0); - dev->dev.driver_data = info; + dev_set_drvdata(&dev->dev, info); err = talk_to_backend(dev, info); if (err) { kfree(info); - dev->dev.driver_data = NULL; + dev_set_drvdata(&dev->dev, NULL); return err; } @@ -845,7 +843,7 @@ static int blkif_recover(struct blkfront_info *info) */ static int blkfront_resume(struct xenbus_device *dev) { - struct blkfront_info *info = dev->dev.driver_data; + struct blkfront_info *info = dev_get_drvdata(&dev->dev); int err; dev_dbg(&dev->dev, "blkfront_resume: %s\n", dev->nodename); @@ -924,7 +922,7 @@ static void blkfront_connect(struct blkfront_info *info) */ static void blkfront_closing(struct xenbus_device *dev) { - struct blkfront_info *info = dev->dev.driver_data; + struct blkfront_info *info = dev_get_drvdata(&dev->dev); unsigned long flags; dev_dbg(&dev->dev, "blkfront_closing: %s removed\n", dev->nodename); @@ -959,7 +957,7 @@ static void blkfront_closing(struct xenbus_device *dev) static void backend_changed(struct xenbus_device *dev, enum xenbus_state backend_state) { - struct blkfront_info *info = dev->dev.driver_data; + struct blkfront_info *info = dev_get_drvdata(&dev->dev); struct block_device *bd; dev_dbg(&dev->dev, "blkfront:backend_changed.\n"); @@ -999,7 +997,7 @@ static void backend_changed(struct xenbus_device *dev, static int blkfront_remove(struct xenbus_device *dev) { - struct blkfront_info *info = dev->dev.driver_data; + struct blkfront_info *info = dev_get_drvdata(&dev->dev); dev_dbg(&dev->dev, "blkfront_remove: %s removed\n", dev->nodename); @@ -1012,7 +1010,7 @@ static int blkfront_remove(struct xenbus_device *dev) static int blkfront_is_ready(struct xenbus_device *dev) { - struct blkfront_info *info = dev->dev.driver_data; + struct blkfront_info *info = dev_get_drvdata(&dev->dev); return info->is_ready; } diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c index 4aecf5dc6a93..f08491a3a813 100644 --- a/drivers/block/xsysace.c +++ b/drivers/block/xsysace.c @@ -463,10 +463,11 @@ struct request *ace_get_next_request(struct request_queue * q) { struct request *req; - while ((req = elv_next_request(q)) != NULL) { + while ((req = blk_peek_request(q)) != NULL) { if (blk_fs_request(req)) break; - end_request(req, 0); + blk_start_request(req); + __blk_end_request_all(req, -EIO); } return req; } @@ -492,9 +493,13 @@ static void ace_fsm_dostate(struct ace_device *ace) set_capacity(ace->gd, 0); dev_info(ace->dev, "No CF in slot\n"); - /* Drop all pending requests */ - while ((req = elv_next_request(ace->queue)) != NULL) - end_request(req, 0); + /* Drop all in-flight and pending requests */ + if (ace->req) { + __blk_end_request_all(ace->req, -EIO); + ace->req = NULL; + } + while ((req = blk_fetch_request(ace->queue)) != NULL) + __blk_end_request_all(req, -EIO); /* Drop back to IDLE state and notify waiters */ ace->fsm_state = ACE_FSM_STATE_IDLE; @@ -642,19 +647,21 @@ static void ace_fsm_dostate(struct ace_device *ace) ace->fsm_state = ACE_FSM_STATE_IDLE; break; } + blk_start_request(req); /* Okay, it's a data request, set it up for transfer */ dev_dbg(ace->dev, - "request: sec=%llx hcnt=%lx, ccnt=%x, dir=%i\n", - (unsigned long long) req->sector, req->hard_nr_sectors, - req->current_nr_sectors, rq_data_dir(req)); + "request: sec=%llx hcnt=%x, ccnt=%x, dir=%i\n", + (unsigned long long)blk_rq_pos(req), + blk_rq_sectors(req), blk_rq_cur_sectors(req), + rq_data_dir(req)); ace->req = req; ace->data_ptr = req->buffer; - ace->data_count = req->current_nr_sectors * ACE_BUF_PER_SECTOR; - ace_out32(ace, ACE_MPULBA, req->sector & 0x0FFFFFFF); + ace->data_count = blk_rq_cur_sectors(req) * ACE_BUF_PER_SECTOR; + ace_out32(ace, ACE_MPULBA, blk_rq_pos(req) & 0x0FFFFFFF); - count = req->hard_nr_sectors; + count = blk_rq_sectors(req); if (rq_data_dir(req)) { /* Kick off write request */ dev_dbg(ace->dev, "write data\n"); @@ -688,7 +695,7 @@ static void ace_fsm_dostate(struct ace_device *ace) dev_dbg(ace->dev, "CFBSY set; t=%i iter=%i c=%i dc=%i irq=%i\n", ace->fsm_task, ace->fsm_iter_num, - ace->req->current_nr_sectors * 16, + blk_rq_cur_sectors(ace->req) * 16, ace->data_count, ace->in_irq); ace_fsm_yield(ace); /* need to poll CFBSY bit */ break; @@ -697,7 +704,7 @@ static void ace_fsm_dostate(struct ace_device *ace) dev_dbg(ace->dev, "DATABUF not set; t=%i iter=%i c=%i dc=%i irq=%i\n", ace->fsm_task, ace->fsm_iter_num, - ace->req->current_nr_sectors * 16, + blk_rq_cur_sectors(ace->req) * 16, ace->data_count, ace->in_irq); ace_fsm_yieldirq(ace); break; @@ -717,14 +724,13 @@ static void ace_fsm_dostate(struct ace_device *ace) } /* bio finished; is there another one? */ - if (__blk_end_request(ace->req, 0, - blk_rq_cur_bytes(ace->req))) { - /* dev_dbg(ace->dev, "next block; h=%li c=%i\n", - * ace->req->hard_nr_sectors, - * ace->req->current_nr_sectors); + if (__blk_end_request_cur(ace->req, 0)) { + /* dev_dbg(ace->dev, "next block; h=%u c=%u\n", + * blk_rq_sectors(ace->req), + * blk_rq_cur_sectors(ace->req)); */ ace->data_ptr = ace->req->buffer; - ace->data_count = ace->req->current_nr_sectors * 16; + ace->data_count = blk_rq_cur_sectors(ace->req) * 16; ace_fsm_yieldirq(ace); break; } @@ -978,7 +984,7 @@ static int __devinit ace_setup(struct ace_device *ace) ace->queue = blk_init_queue(ace_request, &ace->lock); if (ace->queue == NULL) goto err_blk_initq; - blk_queue_hardsect_size(ace->queue, 512); + blk_queue_logical_block_size(ace->queue, 512); /* * Allocate and initialize GD structure diff --git a/drivers/block/z2ram.c b/drivers/block/z2ram.c index 80754cdd3119..4575171e5beb 100644 --- a/drivers/block/z2ram.c +++ b/drivers/block/z2ram.c @@ -70,15 +70,18 @@ static struct gendisk *z2ram_gendisk; static void do_z2_request(struct request_queue *q) { struct request *req; - while ((req = elv_next_request(q)) != NULL) { - unsigned long start = req->sector << 9; - unsigned long len = req->current_nr_sectors << 9; + + req = blk_fetch_request(q); + while (req) { + unsigned long start = blk_rq_pos(req) << 9; + unsigned long len = blk_rq_cur_bytes(req); + int err = 0; if (start + len > z2ram_size) { printk( KERN_ERR DEVICE_NAME ": bad access: block=%lu, count=%u\n", - req->sector, req->current_nr_sectors); - end_request(req, 0); - continue; + blk_rq_pos(req), blk_rq_cur_sectors(req)); + err = -EIO; + goto done; } while (len) { unsigned long addr = start & Z2RAM_CHUNKMASK; @@ -93,7 +96,9 @@ static void do_z2_request(struct request_queue *q) start += size; len -= size; } - end_request(req, 1); + done: + if (!__blk_end_request_cur(req, err)) + req = blk_fetch_request(q); } } diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c index 901bdd95655f..2cc7b3266eaf 100644 --- a/drivers/bluetooth/dtl1_cs.c +++ b/drivers/bluetooth/dtl1_cs.c @@ -415,6 +415,8 @@ static int dtl1_hci_send_frame(struct sk_buff *skb) hdev->stat.sco_tx++; nsh.type = 0x83; break; + default: + return -EILSEQ; }; nsh.zero = 0; diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index af761dc434f6..4895f0e05322 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -277,8 +277,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.ops->flush_buffer) - tty->ldisc.ops->flush_buffer(tty); + if (tty->ldisc->ops->flush_buffer) + tty->ldisc->ops->flush_buffer(tty); tty_driver_flush_buffer(tty); return 0; @@ -463,7 +463,6 @@ static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file, clear_bit(HCI_UART_PROTO_SET, &hu->flags); return err; } - tty->low_latency = 1; } else return -EBUSY; break; diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c index 0bbefba6469c..1df9dda2e377 100644 --- a/drivers/bluetooth/hci_vhci.c +++ b/drivers/bluetooth/hci_vhci.c @@ -40,7 +40,7 @@ #include #include -#define VERSION "1.2" +#define VERSION "1.3" static int minor = MISC_DYNAMIC_MINOR; @@ -51,14 +51,8 @@ struct vhci_data { wait_queue_head_t read_wait; struct sk_buff_head readq; - - struct fasync_struct *fasync; }; -#define VHCI_FASYNC 0x0010 - -static struct miscdevice vhci_miscdev; - static int vhci_open_dev(struct hci_dev *hdev) { set_bit(HCI_RUNNING, &hdev->flags); @@ -105,9 +99,6 @@ static int vhci_send_frame(struct sk_buff *skb) memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1); skb_queue_tail(&data->readq, skb); - if (data->flags & VHCI_FASYNC) - kill_fasync(&data->fasync, SIGIO, POLL_IN); - wake_up_interruptible(&data->read_wait); return 0; @@ -179,41 +170,31 @@ static inline ssize_t vhci_put_user(struct vhci_data *data, static ssize_t vhci_read(struct file *file, char __user *buf, size_t count, loff_t *pos) { - DECLARE_WAITQUEUE(wait, current); struct vhci_data *data = file->private_data; struct sk_buff *skb; ssize_t ret = 0; - add_wait_queue(&data->read_wait, &wait); while (count) { - set_current_state(TASK_INTERRUPTIBLE); - skb = skb_dequeue(&data->readq); - if (!skb) { - if (file->f_flags & O_NONBLOCK) { - ret = -EAGAIN; - break; - } - - if (signal_pending(current)) { - ret = -ERESTARTSYS; - break; - } - - schedule(); - continue; + if (skb) { + ret = vhci_put_user(data, skb, buf, count); + if (ret < 0) + skb_queue_head(&data->readq, skb); + else + kfree_skb(skb); + break; } - if (access_ok(VERIFY_WRITE, buf, count)) - ret = vhci_put_user(data, skb, buf, count); - else - ret = -EFAULT; + if (file->f_flags & O_NONBLOCK) { + ret = -EAGAIN; + break; + } - kfree_skb(skb); - break; + ret = wait_event_interruptible(data->read_wait, + !skb_queue_empty(&data->readq)); + if (ret < 0) + break; } - set_current_state(TASK_RUNNING); - remove_wait_queue(&data->read_wait, &wait); return ret; } @@ -223,9 +204,6 @@ static ssize_t vhci_write(struct file *file, { struct vhci_data *data = file->private_data; - if (!access_ok(VERIFY_READ, buf, count)) - return -EFAULT; - return vhci_get_user(data, buf, count); } @@ -259,11 +237,9 @@ static int vhci_open(struct inode *inode, struct file *file) skb_queue_head_init(&data->readq); init_waitqueue_head(&data->read_wait); - lock_kernel(); hdev = hci_alloc_dev(); if (!hdev) { kfree(data); - unlock_kernel(); return -ENOMEM; } @@ -284,12 +260,10 @@ static int vhci_open(struct inode *inode, struct file *file) BT_ERR("Can't register HCI device"); kfree(data); hci_free_dev(hdev); - unlock_kernel(); return -EBUSY; } file->private_data = data; - unlock_kernel(); return nonseekable_open(inode, file); } @@ -310,48 +284,25 @@ static int vhci_release(struct inode *inode, struct file *file) return 0; } -static int vhci_fasync(int fd, struct file *file, int on) -{ - struct vhci_data *data = file->private_data; - int err = 0; - - lock_kernel(); - err = fasync_helper(fd, file, on, &data->fasync); - if (err < 0) - goto out; - - if (on) - data->flags |= VHCI_FASYNC; - else - data->flags &= ~VHCI_FASYNC; - -out: - unlock_kernel(); - return err; -} - static const struct file_operations vhci_fops = { - .owner = THIS_MODULE, .read = vhci_read, .write = vhci_write, .poll = vhci_poll, .ioctl = vhci_ioctl, .open = vhci_open, .release = vhci_release, - .fasync = vhci_fasync, }; static struct miscdevice vhci_miscdev= { - .name = "vhci", - .fops = &vhci_fops, + .name = "vhci", + .fops = &vhci_fops, + .minor = MISC_DYNAMIC_MINOR, }; static int __init vhci_init(void) { BT_INFO("Virtual HCI driver ver %s", VERSION); - vhci_miscdev.minor = minor; - if (misc_register(&vhci_miscdev) < 0) { BT_ERR("Can't register misc device with minor %d", minor); return -EIO; @@ -369,9 +320,6 @@ static void __exit vhci_exit(void) module_init(vhci_init); module_exit(vhci_exit); -module_param(minor, int, 0444); -MODULE_PARM_DESC(minor, "Miscellaneous minor device number"); - MODULE_AUTHOR("Marcel Holtmann "); MODULE_DESCRIPTION("Bluetooth virtual HCI driver ver " VERSION); MODULE_VERSION(VERSION); diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index cceace61ef28..71d1b9bab70b 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -2101,8 +2101,8 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf, nr = nframes; if (cdi->cdda_method == CDDA_BPC_SINGLE) nr = 1; - if (nr * CD_FRAMESIZE_RAW > (q->max_sectors << 9)) - nr = (q->max_sectors << 9) / CD_FRAMESIZE_RAW; + if (nr * CD_FRAMESIZE_RAW > (queue_max_sectors(q) << 9)) + nr = (queue_max_sectors(q) << 9) / CD_FRAMESIZE_RAW; len = nr * CD_FRAMESIZE_RAW; diff --git a/drivers/cdrom/gdrom.c b/drivers/cdrom/gdrom.c index 2eecb779437b..b5621f27c4be 100644 --- a/drivers/cdrom/gdrom.c +++ b/drivers/cdrom/gdrom.c @@ -584,8 +584,8 @@ static void gdrom_readdisk_dma(struct work_struct *work) list_for_each_safe(elem, next, &gdrom_deferred) { req = list_entry(elem, struct request, queuelist); spin_unlock(&gdrom_lock); - block = req->sector/GD_TO_BLK + GD_SESSION_OFFSET; - block_cnt = req->nr_sectors/GD_TO_BLK; + block = blk_rq_pos(req)/GD_TO_BLK + GD_SESSION_OFFSET; + block_cnt = blk_rq_sectors(req)/GD_TO_BLK; ctrl_outl(PHYSADDR(req->buffer), GDROM_DMA_STARTADDR_REG); ctrl_outl(block_cnt * GDROM_HARD_SECTOR, GDROM_DMA_LENGTH_REG); ctrl_outl(1, GDROM_DMA_DIRECTION_REG); @@ -632,39 +632,35 @@ static void gdrom_readdisk_dma(struct work_struct *work) * before handling ending the request */ spin_lock(&gdrom_lock); list_del_init(&req->queuelist); - __blk_end_request(req, err, blk_rq_bytes(req)); + __blk_end_request_all(req, err); } spin_unlock(&gdrom_lock); kfree(read_command); } -static void gdrom_request_handler_dma(struct request *req) -{ - /* dequeue, add to list of deferred work - * and then schedule workqueue */ - blkdev_dequeue_request(req); - list_add_tail(&req->queuelist, &gdrom_deferred); - schedule_work(&work); -} - static void gdrom_request(struct request_queue *rq) { struct request *req; - while ((req = elv_next_request(rq)) != NULL) { + while ((req = blk_fetch_request(rq)) != NULL) { if (!blk_fs_request(req)) { printk(KERN_DEBUG "GDROM: Non-fs request ignored\n"); - end_request(req, 0); + __blk_end_request_all(req, -EIO); + continue; } if (rq_data_dir(req) != READ) { printk(KERN_NOTICE "GDROM: Read only device -"); printk(" write request ignored\n"); - end_request(req, 0); + __blk_end_request_all(req, -EIO); + continue; } - if (req->nr_sectors) - gdrom_request_handler_dma(req); - else - end_request(req, 0); + + /* + * Add to list of deferred work and then schedule + * workqueue. + */ + list_add_tail(&req->queuelist, &gdrom_deferred); + schedule_work(&work); } } @@ -743,7 +739,7 @@ static void __devinit probe_gdrom_setupdisk(void) static int __devinit probe_gdrom_setupqueue(void) { - blk_queue_hardsect_size(gd.gdrom_rq, GDROM_HARD_SECTOR); + blk_queue_logical_block_size(gd.gdrom_rq, GDROM_HARD_SECTOR); /* using DMA so memory will need to be contiguous */ blk_queue_max_hw_segments(gd.gdrom_rq, 1); /* set a large max size to get most from DMA */ diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c index 9b1624e0ddeb..0fff646cc2f0 100644 --- a/drivers/cdrom/viocd.c +++ b/drivers/cdrom/viocd.c @@ -282,7 +282,7 @@ static int send_request(struct request *req) viopath_targetinst(viopath_hostLp), (u64)req, VIOVERSION << 16, ((u64)DEVICE_NR(diskinfo) << 48) | dmaaddr, - (u64)req->sector * 512, len, 0); + (u64)blk_rq_pos(req) * 512, len, 0); if (hvrc != HvLpEvent_Rc_Good) { printk(VIOCD_KERN_WARNING "hv error on op %d\n", (int)hvrc); return -1; @@ -291,36 +291,19 @@ static int send_request(struct request *req) return 0; } -static void viocd_end_request(struct request *req, int error) -{ - int nsectors = req->hard_nr_sectors; - - /* - * Make sure it's fully ended, and ensure that we process - * at least one sector. - */ - if (blk_pc_request(req)) - nsectors = (req->data_len + 511) >> 9; - if (!nsectors) - nsectors = 1; - - if (__blk_end_request(req, error, nsectors << 9)) - BUG(); -} - static int rwreq; static void do_viocd_request(struct request_queue *q) { struct request *req; - while ((rwreq == 0) && ((req = elv_next_request(q)) != NULL)) { + while ((rwreq == 0) && ((req = blk_fetch_request(q)) != NULL)) { if (!blk_fs_request(req)) - viocd_end_request(req, -EIO); + __blk_end_request_all(req, -EIO); else if (send_request(req) < 0) { printk(VIOCD_KERN_WARNING "unable to send message to OS/400!"); - viocd_end_request(req, -EIO); + __blk_end_request_all(req, -EIO); } else rwreq++; } @@ -486,8 +469,8 @@ static void vio_handle_cd_event(struct HvLpEvent *event) case viocdopen: if (event->xRc == 0) { di = &viocd_diskinfo[bevent->disk]; - blk_queue_hardsect_size(di->viocd_disk->queue, - bevent->block_size); + blk_queue_logical_block_size(di->viocd_disk->queue, + bevent->block_size); set_capacity(di->viocd_disk, bevent->media_size * bevent->block_size / 512); @@ -531,9 +514,9 @@ return_complete: "with rc %d:0x%04X: %s\n", req, event->xRc, bevent->sub_result, err->msg); - viocd_end_request(req, -EIO); + __blk_end_request_all(req, -EIO); } else - viocd_end_request(req, 0); + __blk_end_request_all(req, 0); /* restart handling of incoming requests */ spin_unlock_irqrestore(&viocd_reqlock, flags); diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 735bbe2be51a..0bd01f49cfd8 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -97,6 +97,19 @@ config DEVKMEM kind of kernel debugging operations. When in doubt, say "N". +config BFIN_JTAG_COMM + tristate "Blackfin JTAG Communication" + depends on BLACKFIN + help + Add support for emulating a TTY device over the Blackfin JTAG. + + To compile this driver as a module, choose M here: the + module will be called bfin_jtag_comm. + +config BFIN_JTAG_COMM_CONSOLE + bool "Console on Blackfin JTAG" + depends on BFIN_JTAG_COMM=y + config SERIAL_NONSTANDARD bool "Non-standard serial port support" depends on HAS_IOMEM @@ -679,7 +692,7 @@ config HVCS this driver. To compile this driver as a module, choose M here: the - module will be called hvcs.ko. Additionally, this module + module will be called hvcs. Additionally, this module will depend on arch specific APIs exported from hvcserver.ko which will also be compiled when this driver is built as a module. @@ -794,7 +807,7 @@ if RTC_LIB=n config RTC tristate "Enhanced Real Time Clock Support (legacy PC RTC driver)" depends on !PPC && !PARISC && !IA64 && !M68K && !SPARC && !FRV \ - && !ARM && !SUPERH && !S390 && !AVR32 + && !ARM && !SUPERH && !S390 && !AVR32 && !BLACKFIN ---help--- If you say Y here and create a character special file /dev/rtc with major number 10 and minor number 135 using mknod ("man mknod"), you @@ -893,7 +906,7 @@ config DTLK config XILINX_HWICAP tristate "Xilinx HWICAP Support" - depends on XILINX_VIRTEX + depends on XILINX_VIRTEX || MICROBLAZE help This option enables support for Xilinx Internal Configuration Access Port (ICAP) driver. The ICAP is used on Xilinx Virtex diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 9caf5b5ad1c0..189efcff08ce 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_LEGACY_PTYS) += pty.o obj-$(CONFIG_UNIX98_PTYS) += pty.o obj-y += misc.o obj-$(CONFIG_VT) += vt_ioctl.o vc_screen.o selection.o keyboard.o +obj-$(CONFIG_BFIN_JTAG_COMM) += bfin_jtag_comm.o obj-$(CONFIG_CONSOLE_TRANSLATIONS) += consolemap.o consolemap_deftbl.o obj-$(CONFIG_HW_CONSOLE) += vt.o defkeymap.o obj-$(CONFIG_AUDIT) += tty_audit.o diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h index 46f507531177..178e2e9e9f09 100644 --- a/drivers/char/agp/agp.h +++ b/drivers/char/agp/agp.h @@ -107,7 +107,7 @@ struct agp_bridge_driver { void (*agp_enable)(struct agp_bridge_data *, u32); void (*cleanup)(void); void (*tlb_flush)(struct agp_memory *); - unsigned long (*mask_memory)(struct agp_bridge_data *, unsigned long, int); + unsigned long (*mask_memory)(struct agp_bridge_data *, struct page *, int); void (*cache_flush)(void); int (*create_gatt_table)(struct agp_bridge_data *); int (*free_gatt_table)(struct agp_bridge_data *); @@ -115,9 +115,9 @@ struct agp_bridge_driver { int (*remove_memory)(struct agp_memory *, off_t, int); struct agp_memory *(*alloc_by_type) (size_t, int); void (*free_by_type)(struct agp_memory *); - void *(*agp_alloc_page)(struct agp_bridge_data *); + struct page *(*agp_alloc_page)(struct agp_bridge_data *); int (*agp_alloc_pages)(struct agp_bridge_data *, struct agp_memory *, size_t); - void (*agp_destroy_page)(void *, int flags); + void (*agp_destroy_page)(struct page *, int flags); void (*agp_destroy_pages)(struct agp_memory *); int (*agp_type_to_mask_type) (struct agp_bridge_data *, int); void (*chipset_flush)(struct agp_bridge_data *); @@ -278,10 +278,10 @@ int agp_generic_insert_memory(struct agp_memory *mem, off_t pg_start, int type); int agp_generic_remove_memory(struct agp_memory *mem, off_t pg_start, int type); struct agp_memory *agp_generic_alloc_by_type(size_t page_count, int type); void agp_generic_free_by_type(struct agp_memory *curr); -void *agp_generic_alloc_page(struct agp_bridge_data *bridge); +struct page *agp_generic_alloc_page(struct agp_bridge_data *bridge); int agp_generic_alloc_pages(struct agp_bridge_data *agp_bridge, struct agp_memory *memory, size_t page_count); -void agp_generic_destroy_page(void *addr, int flags); +void agp_generic_destroy_page(struct page *page, int flags); void agp_generic_destroy_pages(struct agp_memory *memory); void agp_free_key(int key); int agp_num_entries(void); @@ -291,7 +291,7 @@ int agp_3_5_enable(struct agp_bridge_data *bridge); void global_cache_flush(void); void get_agp_version(struct agp_bridge_data *bridge); unsigned long agp_generic_mask_memory(struct agp_bridge_data *bridge, - unsigned long addr, int type); + struct page *page, int type); int agp_generic_type_to_mask_type(struct agp_bridge_data *bridge, int type); struct agp_bridge_data *agp_generic_find_bridge(struct pci_dev *pdev); diff --git a/drivers/char/agp/ali-agp.c b/drivers/char/agp/ali-agp.c index dc8d1a90971f..201ef3ffd484 100644 --- a/drivers/char/agp/ali-agp.c +++ b/drivers/char/agp/ali-agp.c @@ -141,37 +141,37 @@ static void m1541_cache_flush(void) } } -static void *m1541_alloc_page(struct agp_bridge_data *bridge) +static struct page *m1541_alloc_page(struct agp_bridge_data *bridge) { - void *addr = agp_generic_alloc_page(agp_bridge); + struct page *page = agp_generic_alloc_page(agp_bridge); u32 temp; - if (!addr) + if (!page) return NULL; pci_read_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, &temp); pci_write_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, (((temp & ALI_CACHE_FLUSH_ADDR_MASK) | - virt_to_gart(addr)) | ALI_CACHE_FLUSH_EN )); - return addr; + phys_to_gart(page_to_phys(page))) | ALI_CACHE_FLUSH_EN )); + return page; } -static void ali_destroy_page(void * addr, int flags) +static void ali_destroy_page(struct page *page, int flags) { - if (addr) { + if (page) { if (flags & AGP_PAGE_DESTROY_UNMAP) { global_cache_flush(); /* is this really needed? --hch */ - agp_generic_destroy_page(addr, flags); + agp_generic_destroy_page(page, flags); } else - agp_generic_destroy_page(addr, flags); + agp_generic_destroy_page(page, flags); } } -static void m1541_destroy_page(void * addr, int flags) +static void m1541_destroy_page(struct page *page, int flags) { u32 temp; - if (addr == NULL) + if (page == NULL) return; if (flags & AGP_PAGE_DESTROY_UNMAP) { @@ -180,9 +180,9 @@ static void m1541_destroy_page(void * addr, int flags) pci_read_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, &temp); pci_write_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, (((temp & ALI_CACHE_FLUSH_ADDR_MASK) | - virt_to_gart(addr)) | ALI_CACHE_FLUSH_EN)); + phys_to_gart(page_to_phys(page))) | ALI_CACHE_FLUSH_EN)); } - agp_generic_destroy_page(addr, flags); + agp_generic_destroy_page(page, flags); } @@ -346,7 +346,7 @@ found: devs[j].chipset_name = "M1641"; break; case 0x43: - devs[j].chipset_name = "M????"; + devs[j].chipset_name = "M1621"; break; case 0x47: devs[j].chipset_name = "M1647"; diff --git a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c index 3f98254b911f..ba9bde71eaaf 100644 --- a/drivers/char/agp/amd-k7-agp.c +++ b/drivers/char/agp/amd-k7-agp.c @@ -325,7 +325,7 @@ static int amd_insert_memory(struct agp_memory *mem, off_t pg_start, int type) addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr; cur_gatt = GET_GATT(addr); writel(agp_generic_mask_memory(agp_bridge, - mem->memory[i], mem->type), cur_gatt+GET_GATT_OFF(addr)); + mem->pages[i], mem->type), cur_gatt+GET_GATT_OFF(addr)); readl(cur_gatt+GET_GATT_OFF(addr)); /* PCI Posting. */ } amd_irongate_tlbflush(mem); diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c index d765afda9c2a..3bf5dda90f4a 100644 --- a/drivers/char/agp/amd64-agp.c +++ b/drivers/char/agp/amd64-agp.c @@ -79,7 +79,7 @@ static int amd64_insert_memory(struct agp_memory *mem, off_t pg_start, int type) for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { tmp = agp_bridge->driver->mask_memory(agp_bridge, - mem->memory[i], mask_type); + mem->pages[i], mask_type); BUG_ON(tmp & 0xffffff0000000ffcULL); pte = (tmp & 0x000000ff00000000ULL) >> 28; diff --git a/drivers/char/agp/ati-agp.c b/drivers/char/agp/ati-agp.c index f1537eece07f..33656e144cc5 100644 --- a/drivers/char/agp/ati-agp.c +++ b/drivers/char/agp/ati-agp.c @@ -269,12 +269,17 @@ static int ati_insert_memory(struct agp_memory * mem, int i, j, num_entries; unsigned long __iomem *cur_gatt; unsigned long addr; + int mask_type; num_entries = A_SIZE_LVL2(agp_bridge->current_size)->num_entries; - if (type != 0 || mem->type != 0) + mask_type = agp_generic_type_to_mask_type(mem->bridge, type); + if (mask_type != 0 || type != mem->type) return -EINVAL; + if (mem->page_count == 0) + return 0; + if ((pg_start + mem->page_count) > num_entries) return -EINVAL; @@ -296,10 +301,11 @@ static int ati_insert_memory(struct agp_memory * mem, for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr; cur_gatt = GET_GATT(addr); - writel(agp_bridge->driver->mask_memory(agp_bridge, - mem->memory[i], mem->type), cur_gatt+GET_GATT_OFF(addr)); - readl(cur_gatt+GET_GATT_OFF(addr)); /* PCI Posting. */ + writel(agp_bridge->driver->mask_memory(agp_bridge, + mem->pages[i], mem->type), + cur_gatt+GET_GATT_OFF(addr)); } + readl(GET_GATT(agp_bridge->gart_bus_addr)); /* PCI posting */ agp_bridge->driver->tlb_flush(mem); return 0; } @@ -310,17 +316,22 @@ static int ati_remove_memory(struct agp_memory * mem, off_t pg_start, int i; unsigned long __iomem *cur_gatt; unsigned long addr; + int mask_type; - if (type != 0 || mem->type != 0) + mask_type = agp_generic_type_to_mask_type(mem->bridge, type); + if (mask_type != 0 || type != mem->type) return -EINVAL; + if (mem->page_count == 0) + return 0; + for (i = pg_start; i < (mem->page_count + pg_start); i++) { addr = (i * PAGE_SIZE) + agp_bridge->gart_bus_addr; cur_gatt = GET_GATT(addr); writel(agp_bridge->scratch_page, cur_gatt+GET_GATT_OFF(addr)); - readl(cur_gatt+GET_GATT_OFF(addr)); /* PCI Posting. */ } + readl(GET_GATT(agp_bridge->gart_bus_addr)); /* PCI posting */ agp_bridge->driver->tlb_flush(mem); return 0; } diff --git a/drivers/char/agp/backend.c b/drivers/char/agp/backend.c index 8c617ad7497f..cfa5a649dfe7 100644 --- a/drivers/char/agp/backend.c +++ b/drivers/char/agp/backend.c @@ -141,17 +141,17 @@ static int agp_backend_initialize(struct agp_bridge_data *bridge) bridge->version = &agp_current_version; if (bridge->driver->needs_scratch_page) { - void *addr = bridge->driver->agp_alloc_page(bridge); + struct page *page = bridge->driver->agp_alloc_page(bridge); - if (!addr) { + if (!page) { dev_err(&bridge->dev->dev, "can't get memory for scratch page\n"); return -ENOMEM; } - bridge->scratch_page_real = virt_to_gart(addr); + bridge->scratch_page_real = phys_to_gart(page_to_phys(page)); bridge->scratch_page = - bridge->driver->mask_memory(bridge, bridge->scratch_page_real, 0); + bridge->driver->mask_memory(bridge, page, 0); } size_value = bridge->driver->fetch_size(); diff --git a/drivers/char/agp/efficeon-agp.c b/drivers/char/agp/efficeon-agp.c index 453543a1f293..35d50f2861b6 100644 --- a/drivers/char/agp/efficeon-agp.c +++ b/drivers/char/agp/efficeon-agp.c @@ -65,8 +65,9 @@ static const struct gatt_mask efficeon_generic_masks[] = }; /* This function does the same thing as mask_memory() for this chipset... */ -static inline unsigned long efficeon_mask_memory(unsigned long addr) +static inline unsigned long efficeon_mask_memory(struct page *page) { + unsigned long addr = phys_to_gart(page_to_phys(page)); return addr | 0x00000001; } @@ -257,7 +258,7 @@ static int efficeon_insert_memory(struct agp_memory * mem, off_t pg_start, int t last_page = NULL; for (i = 0; i < count; i++) { int index = pg_start + i; - unsigned long insert = efficeon_mask_memory(mem->memory[i]); + unsigned long insert = efficeon_mask_memory(mem->pages[i]); page = (unsigned int *) efficeon_private.l1_table[index >> 10]; diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c index 2224b762b7fb..1e8b461b91f1 100644 --- a/drivers/char/agp/generic.c +++ b/drivers/char/agp/generic.c @@ -95,13 +95,13 @@ EXPORT_SYMBOL(agp_flush_chipset); void agp_alloc_page_array(size_t size, struct agp_memory *mem) { - mem->memory = NULL; + mem->pages = NULL; mem->vmalloc_flag = false; if (size <= 2*PAGE_SIZE) - mem->memory = kmalloc(size, GFP_KERNEL | __GFP_NORETRY); - if (mem->memory == NULL) { - mem->memory = vmalloc(size); + mem->pages = kmalloc(size, GFP_KERNEL | __GFP_NORETRY); + if (mem->pages == NULL) { + mem->pages = vmalloc(size); mem->vmalloc_flag = true; } } @@ -110,9 +110,9 @@ EXPORT_SYMBOL(agp_alloc_page_array); void agp_free_page_array(struct agp_memory *mem) { if (mem->vmalloc_flag) { - vfree(mem->memory); + vfree(mem->pages); } else { - kfree(mem->memory); + kfree(mem->pages); } } EXPORT_SYMBOL(agp_free_page_array); @@ -136,7 +136,7 @@ static struct agp_memory *agp_create_user_memory(unsigned long num_agp_pages) agp_alloc_page_array(alloc_size, new); - if (new->memory == NULL) { + if (new->pages == NULL) { agp_free_key(new->key); kfree(new); return NULL; @@ -162,7 +162,7 @@ struct agp_memory *agp_create_memory(int scratch_pages) agp_alloc_page_array(PAGE_SIZE * scratch_pages, new); - if (new->memory == NULL) { + if (new->pages == NULL) { agp_free_key(new->key); kfree(new); return NULL; @@ -206,15 +206,13 @@ void agp_free_memory(struct agp_memory *curr) } else { for (i = 0; i < curr->page_count; i++) { - curr->memory[i] = (unsigned long)gart_to_virt( - curr->memory[i]); curr->bridge->driver->agp_destroy_page( - (void *)curr->memory[i], + curr->pages[i], AGP_PAGE_DESTROY_UNMAP); } for (i = 0; i < curr->page_count; i++) { curr->bridge->driver->agp_destroy_page( - (void *)curr->memory[i], + curr->pages[i], AGP_PAGE_DESTROY_FREE); } } @@ -282,13 +280,13 @@ struct agp_memory *agp_allocate_memory(struct agp_bridge_data *bridge, } for (i = 0; i < page_count; i++) { - void *addr = bridge->driver->agp_alloc_page(bridge); + struct page *page = bridge->driver->agp_alloc_page(bridge); - if (addr == NULL) { + if (page == NULL) { agp_free_memory(new); return NULL; } - new->memory[i] = virt_to_gart(addr); + new->pages[i] = page; new->page_count++; } new->bridge = bridge; @@ -1134,7 +1132,7 @@ int agp_generic_insert_memory(struct agp_memory * mem, off_t pg_start, int type) } for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { - writel(bridge->driver->mask_memory(bridge, mem->memory[i], mask_type), + writel(bridge->driver->mask_memory(bridge, mem->pages[i], mask_type), bridge->gatt_table+j); } readl(bridge->gatt_table+j-1); /* PCI Posting. */ @@ -1204,7 +1202,7 @@ struct agp_memory *agp_generic_alloc_user(size_t page_count, int type) return NULL; for (i = 0; i < page_count; i++) - new->memory[i] = 0; + new->pages[i] = 0; new->page_count = 0; new->type = type; new->num_scratch_pages = pages; @@ -1237,23 +1235,20 @@ int agp_generic_alloc_pages(struct agp_bridge_data *bridge, struct agp_memory *m get_page(page); atomic_inc(&agp_bridge->current_memory_agp); - /* set_memory_array_uc() needs virtual address */ - mem->memory[i] = (unsigned long)page_address(page); + mem->pages[i] = page; mem->page_count++; } #ifdef CONFIG_X86 - set_memory_array_uc(mem->memory, num_pages); + set_pages_array_uc(mem->pages, num_pages); #endif ret = 0; out: - for (i = 0; i < mem->page_count; i++) - mem->memory[i] = virt_to_gart((void *)mem->memory[i]); return ret; } EXPORT_SYMBOL(agp_generic_alloc_pages); -void *agp_generic_alloc_page(struct agp_bridge_data *bridge) +struct page *agp_generic_alloc_page(struct agp_bridge_data *bridge) { struct page * page; @@ -1265,56 +1260,47 @@ void *agp_generic_alloc_page(struct agp_bridge_data *bridge) get_page(page); atomic_inc(&agp_bridge->current_memory_agp); - return page_address(page); + return page; } EXPORT_SYMBOL(agp_generic_alloc_page); void agp_generic_destroy_pages(struct agp_memory *mem) { int i; - void *addr; struct page *page; if (!mem) return; - for (i = 0; i < mem->page_count; i++) - mem->memory[i] = (unsigned long)gart_to_virt(mem->memory[i]); - #ifdef CONFIG_X86 - set_memory_array_wb(mem->memory, mem->page_count); + set_pages_array_wb(mem->pages, mem->page_count); #endif for (i = 0; i < mem->page_count; i++) { - addr = (void *)mem->memory[i]; - page = virt_to_page(addr); + page = mem->pages[i]; #ifndef CONFIG_X86 unmap_page_from_agp(page); #endif - put_page(page); - free_page((unsigned long)addr); + __free_page(page); atomic_dec(&agp_bridge->current_memory_agp); - mem->memory[i] = 0; + mem->pages[i] = NULL; } } EXPORT_SYMBOL(agp_generic_destroy_pages); -void agp_generic_destroy_page(void *addr, int flags) +void agp_generic_destroy_page(struct page *page, int flags) { - struct page *page; - - if (addr == NULL) + if (page == NULL) return; - page = virt_to_page(addr); if (flags & AGP_PAGE_DESTROY_UNMAP) unmap_page_from_agp(page); if (flags & AGP_PAGE_DESTROY_FREE) { put_page(page); - free_page((unsigned long)addr); + __free_page(page); atomic_dec(&agp_bridge->current_memory_agp); } } @@ -1361,8 +1347,9 @@ void global_cache_flush(void) EXPORT_SYMBOL(global_cache_flush); unsigned long agp_generic_mask_memory(struct agp_bridge_data *bridge, - unsigned long addr, int type) + struct page *page, int type) { + unsigned long addr = phys_to_gart(page_to_phys(page)); /* memory type is ignored in the generic routine */ if (bridge->driver->masks) return addr | bridge->driver->masks[0].mask; diff --git a/drivers/char/agp/hp-agp.c b/drivers/char/agp/hp-agp.c index 183ac3fe44fb..8f3d4c184914 100644 --- a/drivers/char/agp/hp-agp.c +++ b/drivers/char/agp/hp-agp.c @@ -361,13 +361,11 @@ hp_zx1_insert_memory (struct agp_memory *mem, off_t pg_start, int type) for (i = 0, j = io_pg_start; i < mem->page_count; i++) { unsigned long paddr; - paddr = mem->memory[i]; + paddr = page_to_phys(mem->pages[i]); for (k = 0; k < hp->io_pages_per_kpage; k++, j++, paddr += hp->io_page_size) { - hp->gatt[j] = - agp_bridge->driver->mask_memory(agp_bridge, - paddr, type); + hp->gatt[j] = HP_ZX1_PDIR_VALID_BIT | paddr; } } @@ -397,8 +395,9 @@ hp_zx1_remove_memory (struct agp_memory *mem, off_t pg_start, int type) static unsigned long hp_zx1_mask_memory (struct agp_bridge_data *bridge, - unsigned long addr, int type) + struct page *page, int type) { + unsigned long addr = phys_to_gart(page_to_phys(page)); return HP_ZX1_PDIR_VALID_BIT | addr; } @@ -518,8 +517,9 @@ zx1_gart_probe (acpi_handle obj, u32 depth, void *context, void **ret) if (hp_zx1_setup(sba_hpa + HP_ZX1_IOC_OFFSET, lba_hpa)) return AE_OK; - printk(KERN_INFO PFX "Detected HP ZX1 %s AGP chipset (ioc=%lx, lba=%lx)\n", - (char *) context, sba_hpa + HP_ZX1_IOC_OFFSET, lba_hpa); + printk(KERN_INFO PFX "Detected HP ZX1 %s AGP chipset " + "(ioc=%llx, lba=%llx)\n", (char *)context, + sba_hpa + HP_ZX1_IOC_OFFSET, lba_hpa); hp_zx1_gart_found = 1; return AE_CTRL_TERMINATE; /* we only support one bridge; quit looking */ diff --git a/drivers/char/agp/i460-agp.c b/drivers/char/agp/i460-agp.c index 10da687d131a..60cc35bb5db7 100644 --- a/drivers/char/agp/i460-agp.c +++ b/drivers/char/agp/i460-agp.c @@ -60,6 +60,9 @@ */ #define WR_FLUSH_GATT(index) RD_GATT(index) +static unsigned long i460_mask_memory (struct agp_bridge_data *bridge, + unsigned long addr, int type); + static struct { void *gatt; /* ioremap'd GATT area */ @@ -74,6 +77,7 @@ static struct { unsigned long *alloced_map; /* bitmap of kernel-pages in use */ int refcount; /* number of kernel pages using the large page */ u64 paddr; /* physical address of large page */ + struct page *page; /* page pointer */ } *lp_desc; } i460; @@ -294,7 +298,7 @@ static int i460_insert_memory_small_io_page (struct agp_memory *mem, void *temp; pr_debug("i460_insert_memory_small_io_page(mem=%p, pg_start=%ld, type=%d, paddr0=0x%lx)\n", - mem, pg_start, type, mem->memory[0]); + mem, pg_start, type, page_to_phys(mem->pages[0])); if (type >= AGP_USER_TYPES || mem->type >= AGP_USER_TYPES) return -EINVAL; @@ -321,10 +325,9 @@ static int i460_insert_memory_small_io_page (struct agp_memory *mem, io_page_size = 1UL << I460_IO_PAGE_SHIFT; for (i = 0, j = io_pg_start; i < mem->page_count; i++) { - paddr = mem->memory[i]; + paddr = phys_to_gart(page_to_phys(mem->pages[i])); for (k = 0; k < I460_IOPAGES_PER_KPAGE; k++, j++, paddr += io_page_size) - WR_GATT(j, agp_bridge->driver->mask_memory(agp_bridge, - paddr, mem->type)); + WR_GATT(j, i460_mask_memory(agp_bridge, paddr, mem->type)); } WR_FLUSH_GATT(j - 1); return 0; @@ -364,10 +367,9 @@ static int i460_alloc_large_page (struct lp_desc *lp) { unsigned long order = I460_IO_PAGE_SHIFT - PAGE_SHIFT; size_t map_size; - void *lpage; - lpage = (void *) __get_free_pages(GFP_KERNEL, order); - if (!lpage) { + lp->page = alloc_pages(GFP_KERNEL, order); + if (!lp->page) { printk(KERN_ERR PFX "Couldn't alloc 4M GART page...\n"); return -ENOMEM; } @@ -375,12 +377,12 @@ static int i460_alloc_large_page (struct lp_desc *lp) map_size = ((I460_KPAGES_PER_IOPAGE + BITS_PER_LONG - 1) & -BITS_PER_LONG)/8; lp->alloced_map = kzalloc(map_size, GFP_KERNEL); if (!lp->alloced_map) { - free_pages((unsigned long) lpage, order); + __free_pages(lp->page, order); printk(KERN_ERR PFX "Out of memory, we're in trouble...\n"); return -ENOMEM; } - lp->paddr = virt_to_gart(lpage); + lp->paddr = phys_to_gart(page_to_phys(lp->page)); lp->refcount = 0; atomic_add(I460_KPAGES_PER_IOPAGE, &agp_bridge->current_memory_agp); return 0; @@ -391,7 +393,7 @@ static void i460_free_large_page (struct lp_desc *lp) kfree(lp->alloced_map); lp->alloced_map = NULL; - free_pages((unsigned long) gart_to_virt(lp->paddr), I460_IO_PAGE_SHIFT - PAGE_SHIFT); + __free_pages(lp->page, I460_IO_PAGE_SHIFT - PAGE_SHIFT); atomic_sub(I460_KPAGES_PER_IOPAGE, &agp_bridge->current_memory_agp); } @@ -439,8 +441,8 @@ static int i460_insert_memory_large_io_page (struct agp_memory *mem, if (i460_alloc_large_page(lp) < 0) return -ENOMEM; pg = lp - i460.lp_desc; - WR_GATT(pg, agp_bridge->driver->mask_memory(agp_bridge, - lp->paddr, 0)); + WR_GATT(pg, i460_mask_memory(agp_bridge, + lp->paddr, 0)); WR_FLUSH_GATT(pg); } @@ -448,7 +450,7 @@ static int i460_insert_memory_large_io_page (struct agp_memory *mem, idx < ((lp == end) ? (end_offset + 1) : I460_KPAGES_PER_IOPAGE); idx++, i++) { - mem->memory[i] = lp->paddr + idx*PAGE_SIZE; + mem->pages[i] = lp->page; __set_bit(idx, lp->alloced_map); ++lp->refcount; } @@ -463,7 +465,7 @@ static int i460_remove_memory_large_io_page (struct agp_memory *mem, struct lp_desc *start, *end, *lp; void *temp; - temp = agp_bridge->driver->current_size; + temp = agp_bridge->current_size; num_entries = A_SIZE_8(temp)->num_entries; /* Figure out what pg_start means in terms of our large GART pages */ @@ -477,7 +479,7 @@ static int i460_remove_memory_large_io_page (struct agp_memory *mem, idx < ((lp == end) ? (end_offset + 1) : I460_KPAGES_PER_IOPAGE); idx++, i++) { - mem->memory[i] = 0; + mem->pages[i] = NULL; __clear_bit(idx, lp->alloced_map); --lp->refcount; } @@ -521,7 +523,7 @@ static int i460_remove_memory (struct agp_memory *mem, * Let's just hope nobody counts on the allocated AGP memory being there before bind time * (I don't think current drivers do)... */ -static void *i460_alloc_page (struct agp_bridge_data *bridge) +static struct page *i460_alloc_page (struct agp_bridge_data *bridge) { void *page; @@ -534,7 +536,7 @@ static void *i460_alloc_page (struct agp_bridge_data *bridge) return page; } -static void i460_destroy_page (void *page, int flags) +static void i460_destroy_page (struct page *page, int flags) { if (I460_IO_PAGE_SHIFT <= PAGE_SHIFT) { agp_generic_destroy_page(page, flags); @@ -544,13 +546,20 @@ static void i460_destroy_page (void *page, int flags) #endif /* I460_LARGE_IO_PAGES */ static unsigned long i460_mask_memory (struct agp_bridge_data *bridge, - unsigned long addr, int type) + unsigned long addr, int type) { /* Make sure the returned address is a valid GATT entry */ return bridge->driver->masks[0].mask | (((addr & ~((1 << I460_IO_PAGE_SHIFT) - 1)) & 0xfffff000) >> 12); } +static unsigned long i460_page_mask_memory(struct agp_bridge_data *bridge, + struct page *page, int type) +{ + unsigned long addr = phys_to_gart(page_to_phys(page)); + return i460_mask_memory(bridge, addr, type); +} + const struct agp_bridge_driver intel_i460_driver = { .owner = THIS_MODULE, .aperture_sizes = i460_sizes, @@ -560,7 +569,7 @@ const struct agp_bridge_driver intel_i460_driver = { .fetch_size = i460_fetch_size, .cleanup = i460_cleanup, .tlb_flush = i460_tlb_flush, - .mask_memory = i460_mask_memory, + .mask_memory = i460_page_mask_memory, .masks = i460_masks, .agp_enable = agp_generic_enable, .cache_flush = global_cache_flush, diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index 3686912427ba..8c9d50db5c3a 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -46,6 +46,10 @@ #define PCI_DEVICE_ID_INTEL_G45_IG 0x2E22 #define PCI_DEVICE_ID_INTEL_G41_HB 0x2E30 #define PCI_DEVICE_ID_INTEL_G41_IG 0x2E32 +#define PCI_DEVICE_ID_INTEL_IGDNG_D_HB 0x0040 +#define PCI_DEVICE_ID_INTEL_IGDNG_D_IG 0x0042 +#define PCI_DEVICE_ID_INTEL_IGDNG_M_HB 0x0044 +#define PCI_DEVICE_ID_INTEL_IGDNG_M_IG 0x0046 /* cover 915 and 945 variants */ #define IS_I915 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_E7221_HB || \ @@ -75,7 +79,9 @@ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q45_HB || \ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G45_HB || \ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_GM45_HB || \ - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G41_HB) + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G41_HB || \ + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IGDNG_D_HB || \ + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IGDNG_M_HB) extern int agp_memory_reserved; @@ -251,7 +257,7 @@ static void intel_i810_agp_enable(struct agp_bridge_data *bridge, u32 mode) } /* Exists to support ARGB cursors */ -static void *i8xx_alloc_pages(void) +static struct page *i8xx_alloc_pages(void) { struct page *page; @@ -266,17 +272,14 @@ static void *i8xx_alloc_pages(void) } get_page(page); atomic_inc(&agp_bridge->current_memory_agp); - return page_address(page); + return page; } -static void i8xx_destroy_pages(void *addr) +static void i8xx_destroy_pages(struct page *page) { - struct page *page; - - if (addr == NULL) + if (page == NULL) return; - page = virt_to_page(addr); set_pages_wb(page, 4); put_page(page); __free_pages(page, 2); @@ -340,7 +343,7 @@ static int intel_i810_insert_entries(struct agp_memory *mem, off_t pg_start, global_cache_flush(); for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { writel(agp_bridge->driver->mask_memory(agp_bridge, - mem->memory[i], + mem->pages[i], mask_type), intel_private.registers+I810_PTE_BASE+(j*4)); } @@ -383,37 +386,37 @@ static int intel_i810_remove_entries(struct agp_memory *mem, off_t pg_start, static struct agp_memory *alloc_agpphysmem_i8xx(size_t pg_count, int type) { struct agp_memory *new; - void *addr; + struct page *page; switch (pg_count) { - case 1: addr = agp_bridge->driver->agp_alloc_page(agp_bridge); + case 1: page = agp_bridge->driver->agp_alloc_page(agp_bridge); break; case 4: /* kludge to get 4 physical pages for ARGB cursor */ - addr = i8xx_alloc_pages(); + page = i8xx_alloc_pages(); break; default: return NULL; } - if (addr == NULL) + if (page == NULL) return NULL; new = agp_create_memory(pg_count); if (new == NULL) return NULL; - new->memory[0] = virt_to_gart(addr); + new->pages[0] = page; if (pg_count == 4) { /* kludge to get 4 physical pages for ARGB cursor */ - new->memory[1] = new->memory[0] + PAGE_SIZE; - new->memory[2] = new->memory[1] + PAGE_SIZE; - new->memory[3] = new->memory[2] + PAGE_SIZE; + new->pages[1] = new->pages[0] + 1; + new->pages[2] = new->pages[1] + 1; + new->pages[3] = new->pages[2] + 1; } new->page_count = pg_count; new->num_scratch_pages = pg_count; new->type = AGP_PHYS_MEMORY; - new->physical = new->memory[0]; + new->physical = page_to_phys(new->pages[0]); return new; } @@ -445,13 +448,11 @@ static void intel_i810_free_by_type(struct agp_memory *curr) agp_free_key(curr->key); if (curr->type == AGP_PHYS_MEMORY) { if (curr->page_count == 4) - i8xx_destroy_pages(gart_to_virt(curr->memory[0])); + i8xx_destroy_pages(curr->pages[0]); else { - void *va = gart_to_virt(curr->memory[0]); - - agp_bridge->driver->agp_destroy_page(va, + agp_bridge->driver->agp_destroy_page(curr->pages[0], AGP_PAGE_DESTROY_UNMAP); - agp_bridge->driver->agp_destroy_page(va, + agp_bridge->driver->agp_destroy_page(curr->pages[0], AGP_PAGE_DESTROY_FREE); } agp_free_page_array(curr); @@ -460,8 +461,9 @@ static void intel_i810_free_by_type(struct agp_memory *curr) } static unsigned long intel_i810_mask_memory(struct agp_bridge_data *bridge, - unsigned long addr, int type) + struct page *page, int type) { + unsigned long addr = phys_to_gart(page_to_phys(page)); /* Type checking must be done elsewhere */ return addr | bridge->driver->masks[type].mask; } @@ -849,7 +851,7 @@ static int intel_i830_insert_entries(struct agp_memory *mem, off_t pg_start, for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { writel(agp_bridge->driver->mask_memory(agp_bridge, - mem->memory[i], mask_type), + mem->pages[i], mask_type), intel_private.registers+I810_PTE_BASE+(j*4)); } readl(intel_private.registers+I810_PTE_BASE+((j-1)*4)); @@ -1079,7 +1081,7 @@ static int intel_i915_insert_entries(struct agp_memory *mem, off_t pg_start, for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { writel(agp_bridge->driver->mask_memory(agp_bridge, - mem->memory[i], mask_type), intel_private.gtt+j); + mem->pages[i], mask_type), intel_private.gtt+j); } readl(intel_private.gtt+j-1); @@ -1194,8 +1196,9 @@ static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge) * this conditional. */ static unsigned long intel_i965_mask_memory(struct agp_bridge_data *bridge, - unsigned long addr, int type) + struct page *page, int type) { + dma_addr_t addr = phys_to_gart(page_to_phys(page)); /* Shift high bits down */ addr |= (addr >> 28) & 0xf0; @@ -1211,6 +1214,8 @@ static void intel_i965_get_gtt_range(int *gtt_offset, int *gtt_size) case PCI_DEVICE_ID_INTEL_Q45_HB: case PCI_DEVICE_ID_INTEL_G45_HB: case PCI_DEVICE_ID_INTEL_G41_HB: + case PCI_DEVICE_ID_INTEL_IGDNG_D_HB: + case PCI_DEVICE_ID_INTEL_IGDNG_M_HB: *gtt_offset = *gtt_size = MB(2); break; default: @@ -2186,6 +2191,10 @@ static const struct intel_driver_description { "G45/G43", NULL, &intel_i965_driver }, { PCI_DEVICE_ID_INTEL_G41_HB, PCI_DEVICE_ID_INTEL_G41_IG, 0, "G41", NULL, &intel_i965_driver }, + { PCI_DEVICE_ID_INTEL_IGDNG_D_HB, PCI_DEVICE_ID_INTEL_IGDNG_D_IG, 0, + "IGDNG/D", NULL, &intel_i965_driver }, + { PCI_DEVICE_ID_INTEL_IGDNG_M_HB, PCI_DEVICE_ID_INTEL_IGDNG_M_IG, 0, + "IGDNG/M", NULL, &intel_i965_driver }, { 0, 0, 0, NULL, NULL, NULL } }; @@ -2387,6 +2396,8 @@ static struct pci_device_id agp_intel_pci_table[] = { ID(PCI_DEVICE_ID_INTEL_Q45_HB), ID(PCI_DEVICE_ID_INTEL_G45_HB), ID(PCI_DEVICE_ID_INTEL_G41_HB), + ID(PCI_DEVICE_ID_INTEL_IGDNG_D_HB), + ID(PCI_DEVICE_ID_INTEL_IGDNG_M_HB), { } }; diff --git a/drivers/char/agp/nvidia-agp.c b/drivers/char/agp/nvidia-agp.c index 16acee2de117..263d71dd441c 100644 --- a/drivers/char/agp/nvidia-agp.c +++ b/drivers/char/agp/nvidia-agp.c @@ -225,7 +225,7 @@ static int nvidia_insert_memory(struct agp_memory *mem, off_t pg_start, int type } for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { writel(agp_bridge->driver->mask_memory(agp_bridge, - mem->memory[i], mask_type), + mem->pages[i], mask_type), agp_bridge->gatt_table+nvidia_private.pg_offset+j); } diff --git a/drivers/char/agp/parisc-agp.c b/drivers/char/agp/parisc-agp.c index 699e3422ad93..f4bb43fb8016 100644 --- a/drivers/char/agp/parisc-agp.c +++ b/drivers/char/agp/parisc-agp.c @@ -31,6 +31,10 @@ #define AGP8X_MODE_BIT 3 #define AGP8X_MODE (1 << AGP8X_MODE_BIT) +static unsigned long +parisc_agp_mask_memory(struct agp_bridge_data *bridge, unsigned long addr, + int type); + static struct _parisc_agp_info { void __iomem *ioc_regs; void __iomem *lba_regs; @@ -149,12 +153,12 @@ parisc_agp_insert_memory(struct agp_memory *mem, off_t pg_start, int type) for (i = 0, j = io_pg_start; i < mem->page_count; i++) { unsigned long paddr; - paddr = mem->memory[i]; + paddr = page_to_phys(mem->pages[i]); for (k = 0; k < info->io_pages_per_kpage; k++, j++, paddr += info->io_page_size) { info->gatt[j] = - agp_bridge->driver->mask_memory(agp_bridge, + parisc_agp_mask_memory(agp_bridge, paddr, type); } } @@ -185,12 +189,20 @@ parisc_agp_remove_memory(struct agp_memory *mem, off_t pg_start, int type) } static unsigned long -parisc_agp_mask_memory(struct agp_bridge_data *bridge, - unsigned long addr, int type) +parisc_agp_mask_memory(struct agp_bridge_data *bridge, unsigned long addr, + int type) { return SBA_PDIR_VALID_BIT | addr; } +static unsigned long +parisc_agp_page_mask_memory(struct agp_bridge_data *bridge, struct page *page, + int type) +{ + unsigned long addr = phys_to_gart(page_to_phys(page)); + return SBA_PDIR_VALID_BIT | addr; +} + static void parisc_agp_enable(struct agp_bridge_data *bridge, u32 mode) { diff --git a/drivers/char/agp/sgi-agp.c b/drivers/char/agp/sgi-agp.c index b972d83bb1b2..d3ea2e4226b5 100644 --- a/drivers/char/agp/sgi-agp.c +++ b/drivers/char/agp/sgi-agp.c @@ -38,7 +38,7 @@ static struct aper_size_info_fixed sgi_tioca_sizes[] = { {0, 0, 0}, }; -static void *sgi_tioca_alloc_page(struct agp_bridge_data *bridge) +static struct page *sgi_tioca_alloc_page(struct agp_bridge_data *bridge) { struct page *page; int nid; @@ -52,7 +52,7 @@ static void *sgi_tioca_alloc_page(struct agp_bridge_data *bridge) get_page(page); atomic_inc(&agp_bridge->current_memory_agp); - return page_address(page); + return page; } /* @@ -71,8 +71,9 @@ static void sgi_tioca_tlbflush(struct agp_memory *mem) */ static unsigned long sgi_tioca_mask_memory(struct agp_bridge_data *bridge, - unsigned long addr, int type) + struct page *page, int type) { + unsigned long addr = phys_to_gart(page_to_phys(page)); return tioca_physpage_to_gart(addr); } @@ -189,7 +190,7 @@ static int sgi_tioca_insert_memory(struct agp_memory *mem, off_t pg_start, for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { table[j] = - bridge->driver->mask_memory(bridge, mem->memory[i], + bridge->driver->mask_memory(bridge, mem->pages[i], mem->type); } diff --git a/drivers/char/agp/sworks-agp.c b/drivers/char/agp/sworks-agp.c index 6224df8b7f0a..b964a2199329 100644 --- a/drivers/char/agp/sworks-agp.c +++ b/drivers/char/agp/sworks-agp.c @@ -349,7 +349,7 @@ static int serverworks_insert_memory(struct agp_memory *mem, for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr; cur_gatt = SVRWRKS_GET_GATT(addr); - writel(agp_bridge->driver->mask_memory(agp_bridge, mem->memory[i], mem->type), cur_gatt+GET_GATT_OFF(addr)); + writel(agp_bridge->driver->mask_memory(agp_bridge, mem->pages[i], mem->type), cur_gatt+GET_GATT_OFF(addr)); } serverworks_tlbflush(mem); return 0; diff --git a/drivers/char/agp/uninorth-agp.c b/drivers/char/agp/uninorth-agp.c index 03f95ec08f59..f192c3b9ad41 100644 --- a/drivers/char/agp/uninorth-agp.c +++ b/drivers/char/agp/uninorth-agp.c @@ -146,13 +146,20 @@ static int uninorth_insert_memory(struct agp_memory *mem, off_t pg_start, { int i, j, num_entries; void *temp; + int mask_type; temp = agp_bridge->current_size; num_entries = A_SIZE_32(temp)->num_entries; - if (type != 0 || mem->type != 0) + if (type != mem->type) + return -EINVAL; + + mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type); + if (mask_type != 0) { /* We know nothing of memory types */ return -EINVAL; + } + if ((pg_start + mem->page_count) > num_entries) return -EINVAL; @@ -166,9 +173,9 @@ static int uninorth_insert_memory(struct agp_memory *mem, off_t pg_start, for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { agp_bridge->gatt_table[j] = - cpu_to_le32((mem->memory[i] & 0xFFFFF000UL) | 0x1UL); - flush_dcache_range((unsigned long)__va(mem->memory[i]), - (unsigned long)__va(mem->memory[i])+0x1000); + cpu_to_le32((page_to_phys(mem->pages[i]) & 0xFFFFF000UL) | 0x1UL); + flush_dcache_range((unsigned long)__va(page_to_phys(mem->pages[i])), + (unsigned long)__va(page_to_phys(mem->pages[i]))+0x1000); } (void)in_le32((volatile u32*)&agp_bridge->gatt_table[pg_start]); mb(); @@ -184,13 +191,20 @@ static int u3_insert_memory(struct agp_memory *mem, off_t pg_start, int type) int i, num_entries; void *temp; u32 *gp; + int mask_type; temp = agp_bridge->current_size; num_entries = A_SIZE_32(temp)->num_entries; - if (type != 0 || mem->type != 0) + if (type != mem->type) + return -EINVAL; + + mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type); + if (mask_type != 0) { /* We know nothing of memory types */ return -EINVAL; + } + if ((pg_start + mem->page_count) > num_entries) return -EINVAL; @@ -205,9 +219,9 @@ static int u3_insert_memory(struct agp_memory *mem, off_t pg_start, int type) } for (i = 0; i < mem->page_count; i++) { - gp[i] = (mem->memory[i] >> PAGE_SHIFT) | 0x80000000UL; - flush_dcache_range((unsigned long)__va(mem->memory[i]), - (unsigned long)__va(mem->memory[i])+0x1000); + gp[i] = (page_to_phys(mem->pages[i]) >> PAGE_SHIFT) | 0x80000000UL; + flush_dcache_range((unsigned long)__va(page_to_phys(mem->pages[i])), + (unsigned long)__va(page_to_phys(mem->pages[i]))+0x1000); } mb(); flush_dcache_range((unsigned long)gp, (unsigned long) &gp[i]); diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c index fd3ebd1be570..72429b6b2fa8 100644 --- a/drivers/char/amiserial.c +++ b/drivers/char/amiserial.c @@ -779,7 +779,7 @@ static void change_speed(struct async_struct *info, info->IER |= UART_IER_MSI; } /* TBD: - * Does clearing IER_MSI imply that we should disbale the VBL interrupt ? + * Does clearing IER_MSI imply that we should disable the VBL interrupt ? */ /* diff --git a/drivers/char/bfin_jtag_comm.c b/drivers/char/bfin_jtag_comm.c new file mode 100644 index 000000000000..1d7c34c73b20 --- /dev/null +++ b/drivers/char/bfin_jtag_comm.c @@ -0,0 +1,365 @@ +/* + * TTY over Blackfin JTAG Communication + * + * Copyright 2008-2009 Analog Devices Inc. + * + * Enter bugs at http://blackfin.uclinux.org/ + * + * Licensed under the GPL-2 or later. + */ + +#define DRV_NAME "bfin-jtag-comm" +#define DEV_NAME "ttyBFJC" +#define pr_fmt(fmt) DRV_NAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define pr_init(fmt, args...) ({ static const __initconst char __fmt[] = fmt; printk(__fmt, ## args); }) + +/* See the Debug/Emulation chapter in the HRM */ +#define EMUDOF 0x00000001 /* EMUDAT_OUT full & valid */ +#define EMUDIF 0x00000002 /* EMUDAT_IN full & valid */ +#define EMUDOOVF 0x00000004 /* EMUDAT_OUT overflow */ +#define EMUDIOVF 0x00000008 /* EMUDAT_IN overflow */ + +static inline uint32_t bfin_write_emudat(uint32_t emudat) +{ + __asm__ __volatile__("emudat = %0;" : : "d"(emudat)); + return emudat; +} + +static inline uint32_t bfin_read_emudat(void) +{ + uint32_t emudat; + __asm__ __volatile__("%0 = emudat;" : "=d"(emudat)); + return emudat; +} + +static inline uint32_t bfin_write_emudat_chars(char a, char b, char c, char d) +{ + return bfin_write_emudat((a << 0) | (b << 8) | (c << 16) | (d << 24)); +} + +#define CIRC_SIZE 2048 /* see comment in tty_io.c:do_tty_write() */ +#define CIRC_MASK (CIRC_SIZE - 1) +#define circ_empty(circ) ((circ)->head == (circ)->tail) +#define circ_free(circ) CIRC_SPACE((circ)->head, (circ)->tail, CIRC_SIZE) +#define circ_cnt(circ) CIRC_CNT((circ)->head, (circ)->tail, CIRC_SIZE) +#define circ_byte(circ, idx) ((circ)->buf[(idx) & CIRC_MASK]) + +static struct tty_driver *bfin_jc_driver; +static struct task_struct *bfin_jc_kthread; +static struct tty_struct * volatile bfin_jc_tty; +static unsigned long bfin_jc_count; +static DEFINE_MUTEX(bfin_jc_tty_mutex); +static volatile struct circ_buf bfin_jc_write_buf; + +static int +bfin_jc_emudat_manager(void *arg) +{ + uint32_t inbound_len = 0, outbound_len = 0; + + while (!kthread_should_stop()) { + /* no one left to give data to, so sleep */ + if (bfin_jc_tty == NULL && circ_empty(&bfin_jc_write_buf)) { + pr_debug("waiting for readers\n"); + __set_current_state(TASK_UNINTERRUPTIBLE); + schedule(); + __set_current_state(TASK_RUNNING); + } + + /* no data available, so just chill */ + if (!(bfin_read_DBGSTAT() & EMUDIF) && circ_empty(&bfin_jc_write_buf)) { + pr_debug("waiting for data (in_len = %i) (circ: %i %i)\n", + inbound_len, bfin_jc_write_buf.tail, bfin_jc_write_buf.head); + if (inbound_len) + schedule(); + else + schedule_timeout_interruptible(HZ); + continue; + } + + /* if incoming data is ready, eat it */ + if (bfin_read_DBGSTAT() & EMUDIF) { + struct tty_struct *tty; + mutex_lock(&bfin_jc_tty_mutex); + tty = (struct tty_struct *)bfin_jc_tty; + if (tty != NULL) { + uint32_t emudat = bfin_read_emudat(); + if (inbound_len == 0) { + pr_debug("incoming length: 0x%08x\n", emudat); + inbound_len = emudat; + } else { + size_t num_chars = (4 <= inbound_len ? 4 : inbound_len); + pr_debug(" incoming data: 0x%08x (pushing %zu)\n", emudat, num_chars); + inbound_len -= num_chars; + tty_insert_flip_string(tty, (unsigned char *)&emudat, num_chars); + tty_flip_buffer_push(tty); + } + } + mutex_unlock(&bfin_jc_tty_mutex); + } + + /* if outgoing data is ready, post it */ + if (!(bfin_read_DBGSTAT() & EMUDOF) && !circ_empty(&bfin_jc_write_buf)) { + if (outbound_len == 0) { + outbound_len = circ_cnt(&bfin_jc_write_buf); + bfin_write_emudat(outbound_len); + pr_debug("outgoing length: 0x%08x\n", outbound_len); + } else { + struct tty_struct *tty; + int tail = bfin_jc_write_buf.tail; + size_t ate = (4 <= outbound_len ? 4 : outbound_len); + uint32_t emudat = + bfin_write_emudat_chars( + circ_byte(&bfin_jc_write_buf, tail + 0), + circ_byte(&bfin_jc_write_buf, tail + 1), + circ_byte(&bfin_jc_write_buf, tail + 2), + circ_byte(&bfin_jc_write_buf, tail + 3) + ); + bfin_jc_write_buf.tail += ate; + outbound_len -= ate; + mutex_lock(&bfin_jc_tty_mutex); + tty = (struct tty_struct *)bfin_jc_tty; + if (tty) + tty_wakeup(tty); + mutex_unlock(&bfin_jc_tty_mutex); + pr_debug(" outgoing data: 0x%08x (pushing %zu)\n", emudat, ate); + } + } + } + + __set_current_state(TASK_RUNNING); + return 0; +} + +static int +bfin_jc_open(struct tty_struct *tty, struct file *filp) +{ + mutex_lock(&bfin_jc_tty_mutex); + pr_debug("open %lu\n", bfin_jc_count); + ++bfin_jc_count; + bfin_jc_tty = tty; + wake_up_process(bfin_jc_kthread); + mutex_unlock(&bfin_jc_tty_mutex); + return 0; +} + +static void +bfin_jc_close(struct tty_struct *tty, struct file *filp) +{ + mutex_lock(&bfin_jc_tty_mutex); + pr_debug("close %lu\n", bfin_jc_count); + if (--bfin_jc_count == 0) + bfin_jc_tty = NULL; + wake_up_process(bfin_jc_kthread); + mutex_unlock(&bfin_jc_tty_mutex); +} + +/* XXX: we dont handle the put_char() case where we must handle count = 1 */ +static int +bfin_jc_circ_write(const unsigned char *buf, int count) +{ + int i; + count = min(count, circ_free(&bfin_jc_write_buf)); + pr_debug("going to write chunk of %i bytes\n", count); + for (i = 0; i < count; ++i) + circ_byte(&bfin_jc_write_buf, bfin_jc_write_buf.head + i) = buf[i]; + bfin_jc_write_buf.head += i; + return i; +} + +#ifndef CONFIG_BFIN_JTAG_COMM_CONSOLE +# define acquire_console_sem() +# define release_console_sem() +#endif +static int +bfin_jc_write(struct tty_struct *tty, const unsigned char *buf, int count) +{ + int i; + acquire_console_sem(); + i = bfin_jc_circ_write(buf, count); + release_console_sem(); + wake_up_process(bfin_jc_kthread); + return i; +} + +static void +bfin_jc_flush_chars(struct tty_struct *tty) +{ + wake_up_process(bfin_jc_kthread); +} + +static int +bfin_jc_write_room(struct tty_struct *tty) +{ + return circ_free(&bfin_jc_write_buf); +} + +static int +bfin_jc_chars_in_buffer(struct tty_struct *tty) +{ + return circ_cnt(&bfin_jc_write_buf); +} + +static void +bfin_jc_wait_until_sent(struct tty_struct *tty, int timeout) +{ + unsigned long expire = jiffies + timeout; + while (!circ_empty(&bfin_jc_write_buf)) { + if (signal_pending(current)) + break; + if (time_after(jiffies, expire)) + break; + } +} + +static struct tty_operations bfin_jc_ops = { + .open = bfin_jc_open, + .close = bfin_jc_close, + .write = bfin_jc_write, + /*.put_char = bfin_jc_put_char,*/ + .flush_chars = bfin_jc_flush_chars, + .write_room = bfin_jc_write_room, + .chars_in_buffer = bfin_jc_chars_in_buffer, + .wait_until_sent = bfin_jc_wait_until_sent, +}; + +static int __init bfin_jc_init(void) +{ + int ret; + + bfin_jc_kthread = kthread_create(bfin_jc_emudat_manager, NULL, DRV_NAME); + if (IS_ERR(bfin_jc_kthread)) + return PTR_ERR(bfin_jc_kthread); + + ret = -ENOMEM; + + bfin_jc_write_buf.head = bfin_jc_write_buf.tail = 0; + bfin_jc_write_buf.buf = kmalloc(CIRC_SIZE, GFP_KERNEL); + if (!bfin_jc_write_buf.buf) + goto err; + + bfin_jc_driver = alloc_tty_driver(1); + if (!bfin_jc_driver) + goto err; + + bfin_jc_driver->owner = THIS_MODULE; + bfin_jc_driver->driver_name = DRV_NAME; + bfin_jc_driver->name = DEV_NAME; + bfin_jc_driver->type = TTY_DRIVER_TYPE_SERIAL; + bfin_jc_driver->subtype = SERIAL_TYPE_NORMAL; + bfin_jc_driver->init_termios = tty_std_termios; + tty_set_operations(bfin_jc_driver, &bfin_jc_ops); + + ret = tty_register_driver(bfin_jc_driver); + if (ret) + goto err; + + pr_init(KERN_INFO DRV_NAME ": initialized\n"); + + return 0; + + err: + put_tty_driver(bfin_jc_driver); + kfree(bfin_jc_write_buf.buf); + kthread_stop(bfin_jc_kthread); + return ret; +} +module_init(bfin_jc_init); + +static void __exit bfin_jc_exit(void) +{ + kthread_stop(bfin_jc_kthread); + kfree(bfin_jc_write_buf.buf); + tty_unregister_driver(bfin_jc_driver); + put_tty_driver(bfin_jc_driver); +} +module_exit(bfin_jc_exit); + +#if defined(CONFIG_BFIN_JTAG_COMM_CONSOLE) || defined(CONFIG_EARLY_PRINTK) +static void +bfin_jc_straight_buffer_write(const char *buf, unsigned count) +{ + unsigned ate = 0; + while (bfin_read_DBGSTAT() & EMUDOF) + continue; + bfin_write_emudat(count); + while (ate < count) { + while (bfin_read_DBGSTAT() & EMUDOF) + continue; + bfin_write_emudat_chars(buf[ate], buf[ate+1], buf[ate+2], buf[ate+3]); + ate += 4; + } +} +#endif + +#ifdef CONFIG_BFIN_JTAG_COMM_CONSOLE +static void +bfin_jc_console_write(struct console *co, const char *buf, unsigned count) +{ + if (bfin_jc_kthread == NULL) + bfin_jc_straight_buffer_write(buf, count); + else + bfin_jc_circ_write(buf, count); +} + +static struct tty_driver * +bfin_jc_console_device(struct console *co, int *index) +{ + *index = co->index; + return bfin_jc_driver; +} + +static struct console bfin_jc_console = { + .name = DEV_NAME, + .write = bfin_jc_console_write, + .device = bfin_jc_console_device, + .flags = CON_ANYTIME | CON_PRINTBUFFER, + .index = -1, +}; + +static int __init bfin_jc_console_init(void) +{ + register_console(&bfin_jc_console); + return 0; +} +console_initcall(bfin_jc_console_init); +#endif + +#ifdef CONFIG_EARLY_PRINTK +static void __init +bfin_jc_early_write(struct console *co, const char *buf, unsigned int count) +{ + bfin_jc_straight_buffer_write(buf, count); +} + +static struct __initdata console bfin_jc_early_console = { + .name = "early_BFJC", + .write = bfin_jc_early_write, + .flags = CON_ANYTIME | CON_PRINTBUFFER, + .index = -1, +}; + +struct console * __init +bfin_jc_early_init(unsigned int port, unsigned int cflag) +{ + return &bfin_jc_early_console; +} +#endif + +MODULE_AUTHOR("Mike Frysinger "); +MODULE_DESCRIPTION("TTY over Blackfin JTAG Communication"); +MODULE_LICENSE("GPL"); diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index 1fdb9f657d8f..f3366d3f06cf 100644 --- a/drivers/char/cyclades.c +++ b/drivers/char/cyclades.c @@ -604,7 +604,6 @@ #define NR_PORTS 256 -#define ZE_V1_NPORTS 64 #define ZO_V1 0 #define ZO_V2 1 #define ZE_V1 2 @@ -663,18 +662,6 @@ static void cy_throttle(struct tty_struct *tty); static void cy_send_xchar(struct tty_struct *tty, char ch); -#define IS_CYC_Z(card) ((card).num_chips == (unsigned int)-1) - -#define Z_FPGA_CHECK(card) \ - ((readl(&((struct RUNTIME_9060 __iomem *) \ - ((card).ctl_addr))->init_ctrl) & (1<<17)) != 0) - -#define ISZLOADED(card) (((ZO_V1 == readl(&((struct RUNTIME_9060 __iomem *) \ - ((card).ctl_addr))->mail_box_0)) || \ - Z_FPGA_CHECK(card)) && \ - (ZFIRM_ID == readl(&((struct FIRM_ID __iomem *) \ - ((card).base_addr+ID_ADDRESS))->signature))) - #ifndef SERIAL_XMIT_SIZE #define SERIAL_XMIT_SIZE (min(PAGE_SIZE, 4096)) #endif @@ -687,8 +674,6 @@ static void cy_send_xchar(struct tty_struct *tty, char ch); #define DRIVER_VERSION 0x02010203 #define RAM_SIZE 0x80000 -#define Z_FPGA_LOADED(X) ((readl(&(X)->init_ctrl) & (1<<17)) != 0) - enum zblock_type { ZBLOCK_PRG = 0, ZBLOCK_FPGA = 1 @@ -883,6 +868,29 @@ static void cyz_rx_restart(unsigned long); static struct timer_list cyz_rx_full_timer[NR_PORTS]; #endif /* CONFIG_CYZ_INTR */ +static inline bool cy_is_Z(struct cyclades_card *card) +{ + return card->num_chips == (unsigned int)-1; +} + +static inline bool __cyz_fpga_loaded(struct RUNTIME_9060 __iomem *ctl_addr) +{ + return readl(&ctl_addr->init_ctrl) & (1 << 17); +} + +static inline bool cyz_fpga_loaded(struct cyclades_card *card) +{ + return __cyz_fpga_loaded(card->ctl_addr.p9060); +} + +static inline bool cyz_is_loaded(struct cyclades_card *card) +{ + struct FIRM_ID __iomem *fw_id = card->base_addr + ID_ADDRESS; + + return (card->hw_ver == ZO_V1 || cyz_fpga_loaded(card)) && + readl(&fw_id->signature) == ZFIRM_ID; +} + static inline int serial_paranoia_check(struct cyclades_port *info, char *name, const char *routine) { @@ -1395,19 +1403,15 @@ cyz_fetch_msg(struct cyclades_card *cinfo, unsigned long loc_doorbell; firm_id = cinfo->base_addr + ID_ADDRESS; - if (!ISZLOADED(*cinfo)) - return -1; zfw_ctrl = cinfo->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff); board_ctrl = &zfw_ctrl->board_ctrl; - loc_doorbell = readl(&((struct RUNTIME_9060 __iomem *) - (cinfo->ctl_addr))->loc_doorbell); + loc_doorbell = readl(&cinfo->ctl_addr.p9060->loc_doorbell); if (loc_doorbell) { *cmd = (char)(0xff & loc_doorbell); *channel = readl(&board_ctrl->fwcmd_channel); *param = (__u32) readl(&board_ctrl->fwcmd_param); - cy_writel(&((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))-> - loc_doorbell, 0xffffffff); + cy_writel(&cinfo->ctl_addr.p9060->loc_doorbell, 0xffffffff); return 1; } return 0; @@ -1424,15 +1428,14 @@ cyz_issue_cmd(struct cyclades_card *cinfo, unsigned int index; firm_id = cinfo->base_addr + ID_ADDRESS; - if (!ISZLOADED(*cinfo)) + if (!cyz_is_loaded(cinfo)) return -1; zfw_ctrl = cinfo->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff); board_ctrl = &zfw_ctrl->board_ctrl; index = 0; - pci_doorbell = - &((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))->pci_doorbell; + pci_doorbell = &cinfo->ctl_addr.p9060->pci_doorbell; while ((readl(pci_doorbell) & 0xff) != 0) { if (index++ == 1000) return (int)(readl(pci_doorbell) & 0xff); @@ -1624,10 +1627,8 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo) static struct BOARD_CTRL __iomem *board_ctrl; static struct CH_CTRL __iomem *ch_ctrl; static struct BUF_CTRL __iomem *buf_ctrl; - __u32 channel; + __u32 channel, param, fw_ver; __u8 cmd; - __u32 param; - __u32 hw_ver, fw_ver; int special_count; int delta_count; @@ -1635,8 +1636,6 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo) zfw_ctrl = cinfo->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff); board_ctrl = &zfw_ctrl->board_ctrl; fw_ver = readl(&board_ctrl->fw_version); - hw_ver = readl(&((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))-> - mail_box_0); while (cyz_fetch_msg(cinfo, &channel, &cmd, ¶m) == 1) { special_count = 0; @@ -1737,15 +1736,7 @@ static irqreturn_t cyz_interrupt(int irq, void *dev_id) { struct cyclades_card *cinfo = dev_id; - if (unlikely(cinfo == NULL)) { -#ifdef CY_DEBUG_INTERRUPTS - printk(KERN_DEBUG "cyz_interrupt: spurious interrupt %d\n", - irq); -#endif - return IRQ_NONE; /* spurious interrupt */ - } - - if (unlikely(!ISZLOADED(*cinfo))) { + if (unlikely(!cyz_is_loaded(cinfo))) { #ifdef CY_DEBUG_INTERRUPTS printk(KERN_DEBUG "cyz_interrupt: board not yet loaded " "(IRQ%d).\n", irq); @@ -1785,7 +1776,6 @@ static void cyz_poll(unsigned long arg) struct tty_struct *tty; struct FIRM_ID __iomem *firm_id; struct ZFW_CTRL __iomem *zfw_ctrl; - struct BOARD_CTRL __iomem *board_ctrl; struct BUF_CTRL __iomem *buf_ctrl; unsigned long expires = jiffies + HZ; unsigned int port, card; @@ -1793,19 +1783,17 @@ static void cyz_poll(unsigned long arg) for (card = 0; card < NR_CARDS; card++) { cinfo = &cy_card[card]; - if (!IS_CYC_Z(*cinfo)) + if (!cy_is_Z(cinfo)) continue; - if (!ISZLOADED(*cinfo)) + if (!cyz_is_loaded(cinfo)) continue; firm_id = cinfo->base_addr + ID_ADDRESS; zfw_ctrl = cinfo->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff); - board_ctrl = &(zfw_ctrl->board_ctrl); /* Skip first polling cycle to avoid racing conditions with the FW */ if (!cinfo->intr_enabled) { - cinfo->nports = (int)readl(&board_ctrl->n_channel); cinfo->intr_enabled = 1; continue; } @@ -1874,7 +1862,7 @@ static int startup(struct cyclades_port *info) set_line_char(info); - if (!IS_CYC_Z(*card)) { + if (!cy_is_Z(card)) { chip = channel >> 2; channel &= 0x03; index = card->bus_index; @@ -1931,7 +1919,7 @@ static int startup(struct cyclades_port *info) base_addr = card->base_addr; firm_id = base_addr + ID_ADDRESS; - if (!ISZLOADED(*card)) + if (!cyz_is_loaded(card)) return -ENODEV; zfw_ctrl = card->base_addr + @@ -2026,7 +2014,7 @@ static void start_xmit(struct cyclades_port *info) card = info->card; channel = info->line - card->first_line; - if (!IS_CYC_Z(*card)) { + if (!cy_is_Z(card)) { chip = channel >> 2; channel &= 0x03; index = card->bus_index; @@ -2070,7 +2058,7 @@ static void shutdown(struct cyclades_port *info) card = info->card; channel = info->line - card->first_line; - if (!IS_CYC_Z(*card)) { + if (!cy_is_Z(card)) { chip = channel >> 2; channel &= 0x03; index = card->bus_index; @@ -2126,7 +2114,7 @@ static void shutdown(struct cyclades_port *info) #endif firm_id = base_addr + ID_ADDRESS; - if (!ISZLOADED(*card)) + if (!cyz_is_loaded(card)) return; zfw_ctrl = card->base_addr + @@ -2233,7 +2221,7 @@ block_til_ready(struct tty_struct *tty, struct file *filp, #endif info->port.blocked_open++; - if (!IS_CYC_Z(*cinfo)) { + if (!cy_is_Z(cinfo)) { chip = channel >> 2; channel &= 0x03; index = cinfo->bus_index; @@ -2296,7 +2284,7 @@ block_til_ready(struct tty_struct *tty, struct file *filp, base_addr = cinfo->base_addr; firm_id = base_addr + ID_ADDRESS; - if (!ISZLOADED(*cinfo)) { + if (!cyz_is_loaded(cinfo)) { __set_current_state(TASK_RUNNING); remove_wait_queue(&info->port.open_wait, &wait); return -EINVAL; @@ -2397,16 +2385,14 @@ static int cy_open(struct tty_struct *tty, struct file *filp) treat it as absent from the system. This will make the user pay attention. */ - if (IS_CYC_Z(*info->card)) { + if (cy_is_Z(info->card)) { struct cyclades_card *cinfo = info->card; struct FIRM_ID __iomem *firm_id = cinfo->base_addr + ID_ADDRESS; - if (!ISZLOADED(*cinfo)) { - if (((ZE_V1 == readl(&((struct RUNTIME_9060 __iomem *) - (cinfo->ctl_addr))->mail_box_0)) && - Z_FPGA_CHECK(*cinfo)) && - (ZFIRM_HLT == readl( - &firm_id->signature))) { + if (!cyz_is_loaded(cinfo)) { + if (cinfo->hw_ver == ZE_V1 && cyz_fpga_loaded(cinfo) && + readl(&firm_id->signature) == + ZFIRM_HLT) { printk(KERN_ERR "cyc:Cyclades-Z Error: you " "need an external power supply for " "this number of ports.\nFirmware " @@ -2423,18 +2409,13 @@ static int cy_open(struct tty_struct *tty, struct file *filp) interrupts should be enabled as soon as the first open happens to one of its ports. */ if (!cinfo->intr_enabled) { - struct ZFW_CTRL __iomem *zfw_ctrl; - struct BOARD_CTRL __iomem *board_ctrl; - - zfw_ctrl = cinfo->base_addr + - (readl(&firm_id->zfwctrl_addr) & - 0xfffff); - - board_ctrl = &zfw_ctrl->board_ctrl; + u16 intr; /* Enable interrupts on the PLX chip */ - cy_writew(cinfo->ctl_addr + 0x68, - readw(cinfo->ctl_addr + 0x68) | 0x0900); + intr = readw(&cinfo->ctl_addr.p9060-> + intr_ctrl_stat) | 0x0900; + cy_writew(&cinfo->ctl_addr.p9060-> + intr_ctrl_stat, intr); /* Enable interrupts on the FW */ retval = cyz_issue_cmd(cinfo, 0, C_CM_IRQ_ENBL, 0L); @@ -2442,8 +2423,6 @@ static int cy_open(struct tty_struct *tty, struct file *filp) printk(KERN_ERR "cyc:IRQ enable retval " "was %x\n", retval); } - cinfo->nports = - (int)readl(&board_ctrl->n_channel); cinfo->intr_enabled = 1; } } @@ -2556,7 +2535,7 @@ static void cy_wait_until_sent(struct tty_struct *tty, int timeout) #endif card = info->card; channel = (info->line) - (card->first_line); - if (!IS_CYC_Z(*card)) { + if (!cy_is_Z(card)) { chip = channel >> 2; channel &= 0x03; index = card->bus_index; @@ -2601,7 +2580,7 @@ static void cy_flush_buffer(struct tty_struct *tty) info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; spin_unlock_irqrestore(&card->card_lock, flags); - if (IS_CYC_Z(*card)) { /* If it is a Z card, flush the on-board + if (cy_is_Z(card)) { /* If it is a Z card, flush the on-board buffers as well */ spin_lock_irqsave(&card->card_lock, flags); retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_TX, 0L); @@ -2682,7 +2661,7 @@ static void cy_close(struct tty_struct *tty, struct file *filp) spin_lock_irqsave(&card->card_lock, flags); - if (!IS_CYC_Z(*card)) { + if (!cy_is_Z(card)) { int channel = info->line - card->first_line; int index = card->bus_index; void __iomem *base_addr = card->base_addr + @@ -2902,7 +2881,7 @@ static int cy_chars_in_buffer(struct tty_struct *tty) channel = (info->line) - (card->first_line); #ifdef Z_EXT_CHARS_IN_BUFFER - if (!IS_CYC_Z(cy_card[card])) { + if (!cy_is_Z(card)) { #endif /* Z_EXT_CHARS_IN_BUFFER */ #ifdef CY_DEBUG_IO printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n", @@ -2984,7 +2963,6 @@ static void set_line_char(struct cyclades_port *info) void __iomem *base_addr; int chip, channel, index; unsigned cflag, iflag; - unsigned short chip_number; int baud, baud_rate = 0; int i; @@ -3013,9 +2991,8 @@ static void set_line_char(struct cyclades_port *info) card = info->card; channel = info->line - card->first_line; - chip_number = channel / 4; - if (!IS_CYC_Z(*card)) { + if (!cy_is_Z(card)) { index = card->bus_index; @@ -3233,21 +3210,17 @@ static void set_line_char(struct cyclades_port *info) } else { struct FIRM_ID __iomem *firm_id; struct ZFW_CTRL __iomem *zfw_ctrl; - struct BOARD_CTRL __iomem *board_ctrl; struct CH_CTRL __iomem *ch_ctrl; - struct BUF_CTRL __iomem *buf_ctrl; __u32 sw_flow; int retval; firm_id = card->base_addr + ID_ADDRESS; - if (!ISZLOADED(*card)) + if (!cyz_is_loaded(card)) return; zfw_ctrl = card->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff); - board_ctrl = &zfw_ctrl->board_ctrl; ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]); - buf_ctrl = &zfw_ctrl->buf_ctrl[channel]; /* baud rate */ baud = tty_get_baud_rate(info->port.tty); @@ -3457,7 +3430,7 @@ static int get_lsr_info(struct cyclades_port *info, unsigned int __user *value) card = info->card; channel = (info->line) - (card->first_line); - if (!IS_CYC_Z(*card)) { + if (!cy_is_Z(card)) { chip = channel >> 2; channel &= 0x03; index = card->bus_index; @@ -3497,7 +3470,7 @@ static int cy_tiocmget(struct tty_struct *tty, struct file *file) card = info->card; channel = info->line - card->first_line; - if (!IS_CYC_Z(*card)) { + if (!cy_is_Z(card)) { chip = channel >> 2; channel &= 0x03; index = card->bus_index; @@ -3523,7 +3496,7 @@ static int cy_tiocmget(struct tty_struct *tty, struct file *file) } else { base_addr = card->base_addr; firm_id = card->base_addr + ID_ADDRESS; - if (ISZLOADED(*card)) { + if (cyz_is_loaded(card)) { zfw_ctrl = card->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff); board_ctrl = &zfw_ctrl->board_ctrl; @@ -3566,7 +3539,7 @@ cy_tiocmset(struct tty_struct *tty, struct file *file, card = info->card; channel = (info->line) - (card->first_line); - if (!IS_CYC_Z(*card)) { + if (!cy_is_Z(card)) { chip = channel >> 2; channel &= 0x03; index = card->bus_index; @@ -3641,7 +3614,7 @@ cy_tiocmset(struct tty_struct *tty, struct file *file, base_addr = card->base_addr; firm_id = card->base_addr + ID_ADDRESS; - if (ISZLOADED(*card)) { + if (cyz_is_loaded(card)) { zfw_ctrl = card->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff); board_ctrl = &zfw_ctrl->board_ctrl; @@ -3713,7 +3686,7 @@ static int cy_break(struct tty_struct *tty, int break_state) card = info->card; spin_lock_irqsave(&card->card_lock, flags); - if (!IS_CYC_Z(*card)) { + if (!cy_is_Z(card)) { /* Let the transmit ISR take care of this (since it requires stuffing characters into the output stream). */ @@ -3782,7 +3755,7 @@ static int set_threshold(struct cyclades_port *info, unsigned long value) card = info->card; channel = info->line - card->first_line; - if (!IS_CYC_Z(*card)) { + if (!cy_is_Z(card)) { chip = channel >> 2; channel &= 0x03; index = card->bus_index; @@ -3810,7 +3783,7 @@ static int get_threshold(struct cyclades_port *info, card = info->card; channel = info->line - card->first_line; - if (!IS_CYC_Z(*card)) { + if (!cy_is_Z(card)) { chip = channel >> 2; channel &= 0x03; index = card->bus_index; @@ -3844,7 +3817,7 @@ static int set_timeout(struct cyclades_port *info, unsigned long value) card = info->card; channel = info->line - card->first_line; - if (!IS_CYC_Z(*card)) { + if (!cy_is_Z(card)) { chip = channel >> 2; channel &= 0x03; index = card->bus_index; @@ -3867,7 +3840,7 @@ static int get_timeout(struct cyclades_port *info, card = info->card; channel = info->line - card->first_line; - if (!IS_CYC_Z(*card)) { + if (!cy_is_Z(card)) { chip = channel >> 2; channel &= 0x03; index = card->bus_index; @@ -4121,7 +4094,7 @@ static void cy_send_xchar(struct tty_struct *tty, char ch) card = info->card; channel = info->line - card->first_line; - if (IS_CYC_Z(*card)) { + if (cy_is_Z(card)) { if (ch == STOP_CHAR(tty)) cyz_issue_cmd(card, channel, C_CM_SENDXOFF, 0L); else if (ch == START_CHAR(tty)) @@ -4154,7 +4127,7 @@ static void cy_throttle(struct tty_struct *tty) card = info->card; if (I_IXOFF(tty)) { - if (!IS_CYC_Z(*card)) + if (!cy_is_Z(card)) cy_send_xchar(tty, STOP_CHAR(tty)); else info->throttle = 1; @@ -4162,7 +4135,7 @@ static void cy_throttle(struct tty_struct *tty) if (tty->termios->c_cflag & CRTSCTS) { channel = info->line - card->first_line; - if (!IS_CYC_Z(*card)) { + if (!cy_is_Z(card)) { chip = channel >> 2; channel &= 0x03; index = card->bus_index; @@ -4219,7 +4192,7 @@ static void cy_unthrottle(struct tty_struct *tty) if (tty->termios->c_cflag & CRTSCTS) { card = info->card; channel = info->line - card->first_line; - if (!IS_CYC_Z(*card)) { + if (!cy_is_Z(card)) { chip = channel >> 2; channel &= 0x03; index = card->bus_index; @@ -4263,7 +4236,7 @@ static void cy_stop(struct tty_struct *tty) cinfo = info->card; channel = info->line - cinfo->first_line; - if (!IS_CYC_Z(*cinfo)) { + if (!cy_is_Z(cinfo)) { index = cinfo->bus_index; chip = channel >> 2; channel &= 0x03; @@ -4296,7 +4269,7 @@ static void cy_start(struct tty_struct *tty) cinfo = info->card; channel = info->line - cinfo->first_line; index = cinfo->bus_index; - if (!IS_CYC_Z(*cinfo)) { + if (!cy_is_Z(cinfo)) { chip = channel >> 2; channel &= 0x03; base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index); @@ -4347,33 +4320,20 @@ static void cy_hangup(struct tty_struct *tty) static int __devinit cy_init_card(struct cyclades_card *cinfo) { struct cyclades_port *info; - u32 uninitialized_var(mailbox); - unsigned int nports, port; + unsigned int port; unsigned short chip_number; - int uninitialized_var(index); spin_lock_init(&cinfo->card_lock); + cinfo->intr_enabled = 0; - if (IS_CYC_Z(*cinfo)) { /* Cyclades-Z */ - mailbox = readl(&((struct RUNTIME_9060 __iomem *) - cinfo->ctl_addr)->mail_box_0); - nports = (mailbox == ZE_V1) ? ZE_V1_NPORTS : 8; - cinfo->intr_enabled = 0; - cinfo->nports = 0; /* Will be correctly set later, after - Z FW is loaded */ - } else { - index = cinfo->bus_index; - nports = cinfo->nports = CyPORTS_PER_CHIP * cinfo->num_chips; - } - - cinfo->ports = kzalloc(sizeof(*cinfo->ports) * nports, GFP_KERNEL); + cinfo->ports = kcalloc(cinfo->nports, sizeof(*cinfo->ports), + GFP_KERNEL); if (cinfo->ports == NULL) { printk(KERN_ERR "Cyclades: cannot allocate ports\n"); - cinfo->nports = 0; return -ENOMEM; } - for (port = cinfo->first_line; port < cinfo->first_line + nports; + for (port = cinfo->first_line; port < cinfo->first_line + cinfo->nports; port++) { info = &cinfo->ports[port - cinfo->first_line]; tty_port_init(&info->port); @@ -4387,9 +4347,9 @@ static int __devinit cy_init_card(struct cyclades_card *cinfo) init_completion(&info->shutdown_wait); init_waitqueue_head(&info->delta_msr_wait); - if (IS_CYC_Z(*cinfo)) { + if (cy_is_Z(cinfo)) { info->type = PORT_STARTECH; - if (mailbox == ZO_V1) + if (cinfo->hw_ver == ZO_V1) info->xmit_fifo_size = CYZ_FIFO_SIZE; else info->xmit_fifo_size = 4 * CYZ_FIFO_SIZE; @@ -4398,6 +4358,7 @@ static int __devinit cy_init_card(struct cyclades_card *cinfo) cyz_rx_restart, (unsigned long)info); #endif } else { + int index = cinfo->bus_index; info->type = PORT_CIRRUS; info->xmit_fifo_size = CyMAX_CHAR_FIFO; info->cor1 = CyPARITY_NONE | Cy_1_STOP | Cy_8_BITS; @@ -4430,7 +4391,7 @@ static int __devinit cy_init_card(struct cyclades_card *cinfo) } #ifndef CONFIG_CYZ_INTR - if (IS_CYC_Z(*cinfo) && !timer_pending(&cyz_timerlist)) { + if (cy_is_Z(cinfo) && !timer_pending(&cyz_timerlist)) { mod_timer(&cyz_timerlist, jiffies + 1); #ifdef CY_PCI_DEBUG printk(KERN_DEBUG "Cyclades-Z polling initialized\n"); @@ -4621,11 +4582,12 @@ static int __init cy_detect_isa(void) /* set cy_card */ cy_card[j].base_addr = cy_isa_address; - cy_card[j].ctl_addr = NULL; + cy_card[j].ctl_addr.p9050 = NULL; cy_card[j].irq = (int)cy_isa_irq; cy_card[j].bus_index = 0; cy_card[j].first_line = cy_next_channel; - cy_card[j].num_chips = cy_isa_nchan / 4; + cy_card[j].num_chips = cy_isa_nchan / CyPORTS_PER_CHIP; + cy_card[j].nports = cy_isa_nchan; if (cy_init_card(&cy_card[j])) { cy_card[j].base_addr = NULL; free_irq(cy_isa_irq, &cy_card[j]); @@ -4781,7 +4743,7 @@ static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr, struct CUSTOM_REG __iomem *cust = base_addr; struct ZFW_CTRL __iomem *pt_zfwctrl; void __iomem *tmp; - u32 mailbox, status; + u32 mailbox, status, nchan; unsigned int i; int retval; @@ -4793,7 +4755,7 @@ static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr, /* Check whether the firmware is already loaded and running. If positive, skip this board */ - if (Z_FPGA_LOADED(ctl_addr) && readl(&fid->signature) == ZFIRM_ID) { + if (__cyz_fpga_loaded(ctl_addr) && readl(&fid->signature) == ZFIRM_ID) { u32 cntval = readl(base_addr + 0x190); udelay(100); @@ -4812,7 +4774,7 @@ static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr, mailbox = readl(&ctl_addr->mail_box_0); - if (mailbox == 0 || Z_FPGA_LOADED(ctl_addr)) { + if (mailbox == 0 || __cyz_fpga_loaded(ctl_addr)) { /* stops CPU and set window to beginning of RAM */ cy_writel(&ctl_addr->loc_addr_base, WIN_CREG); cy_writel(&cust->cpu_stop, 0); @@ -4828,7 +4790,7 @@ static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr, base_addr); if (retval) goto err_rel; - if (!Z_FPGA_LOADED(ctl_addr)) { + if (!__cyz_fpga_loaded(ctl_addr)) { dev_err(&pdev->dev, "fw upload successful, but fw is " "not loaded\n"); goto err_rel; @@ -4887,7 +4849,7 @@ static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr, "system before loading the new FW to the " "Cyclades-Z.\n"); - if (Z_FPGA_LOADED(ctl_addr)) + if (__cyz_fpga_loaded(ctl_addr)) plx_init(pdev, irq, ctl_addr); retval = -EIO; @@ -4902,16 +4864,16 @@ static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr, base_addr + ID_ADDRESS, readl(&fid->zfwctrl_addr), base_addr + readl(&fid->zfwctrl_addr)); + nchan = readl(&pt_zfwctrl->board_ctrl.n_channel); dev_info(&pdev->dev, "Cyclades-Z FW loaded: version = %x, ports = %u\n", - readl(&pt_zfwctrl->board_ctrl.fw_version), - readl(&pt_zfwctrl->board_ctrl.n_channel)); + readl(&pt_zfwctrl->board_ctrl.fw_version), nchan); - if (readl(&pt_zfwctrl->board_ctrl.n_channel) == 0) { + if (nchan == 0) { dev_warn(&pdev->dev, "no Cyclades-Z ports were found. Please " "check the connection between the Z host card and the " "serial expanders.\n"); - if (Z_FPGA_LOADED(ctl_addr)) + if (__cyz_fpga_loaded(ctl_addr)) plx_init(pdev, irq, ctl_addr); dev_info(&pdev->dev, "Null number of ports detected. Board " @@ -4932,9 +4894,7 @@ static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr, cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) | 0x00030800UL); - plx_init(pdev, irq, ctl_addr); - - return 0; + return nchan; err_rel: release_firmware(fw); err: @@ -4946,7 +4906,7 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev, { void __iomem *addr0 = NULL, *addr2 = NULL; char *card_name = NULL; - u32 mailbox; + u32 uninitialized_var(mailbox); unsigned int device_id, nchan = 0, card_no, i; unsigned char plx_ver; int retval, irq; @@ -5023,11 +4983,12 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev, } /* Disable interrupts on the PLX before resetting it */ - cy_writew(addr0 + 0x68, readw(addr0 + 0x68) & ~0x0900); + cy_writew(&ctl_addr->intr_ctrl_stat, + readw(&ctl_addr->intr_ctrl_stat) & ~0x0900); plx_init(pdev, irq, addr0); - mailbox = (u32)readl(&ctl_addr->mail_box_0); + mailbox = readl(&ctl_addr->mail_box_0); addr2 = ioremap_nocache(pci_resource_start(pdev, 2), mailbox == ZE_V1 ? CyPCI_Ze_win : CyPCI_Zwin); @@ -5038,12 +4999,8 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev, if (mailbox == ZE_V1) { card_name = "Cyclades-Ze"; - - readl(&ctl_addr->mail_box_0); - nchan = ZE_V1_NPORTS; } else { card_name = "Cyclades-8Zo"; - #ifdef CY_PCI_DEBUG if (mailbox == ZO_V1) { cy_writel(&ctl_addr->loc_addr_base, WIN_CREG); @@ -5065,15 +5022,12 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev, */ if ((mailbox == ZO_V1) || (mailbox == ZO_V2)) cy_writel(addr2 + ID_ADDRESS, 0L); - - retval = cyz_load_fw(pdev, addr2, addr0, irq); - if (retval) - goto err_unmap; - /* This must be a Cyclades-8Zo/PCI. The extendable - version will have a different device_id and will - be allocated its maximum number of ports. */ - nchan = 8; } + + retval = cyz_load_fw(pdev, addr2, addr0, irq); + if (retval <= 0) + goto err_unmap; + nchan = retval; } if ((cy_next_channel + nchan) > NR_PORTS) { @@ -5103,8 +5057,10 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev, dev_err(&pdev->dev, "could not allocate IRQ\n"); goto err_unmap; } - cy_card[card_no].num_chips = nchan / 4; + cy_card[card_no].num_chips = nchan / CyPORTS_PER_CHIP; } else { + cy_card[card_no].hw_ver = mailbox; + cy_card[card_no].num_chips = (unsigned int)-1; #ifdef CONFIG_CYZ_INTR /* allocate IRQ only if board has an IRQ */ if (irq != 0 && irq != 255) { @@ -5117,15 +5073,15 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev, } } #endif /* CONFIG_CYZ_INTR */ - cy_card[card_no].num_chips = (unsigned int)-1; } /* set cy_card */ cy_card[card_no].base_addr = addr2; - cy_card[card_no].ctl_addr = addr0; + cy_card[card_no].ctl_addr.p9050 = addr0; cy_card[card_no].irq = irq; cy_card[card_no].bus_index = 1; cy_card[card_no].first_line = cy_next_channel; + cy_card[card_no].nports = nchan; retval = cy_init_card(&cy_card[card_no]); if (retval) goto err_null; @@ -5138,17 +5094,20 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev, plx_ver = readb(addr2 + CyPLX_VER) & 0x0f; switch (plx_ver) { case PLX_9050: - cy_writeb(addr0 + 0x4c, 0x43); break; case PLX_9060: case PLX_9080: default: /* Old boards, use PLX_9060 */ - plx_init(pdev, irq, addr0); - cy_writew(addr0 + 0x68, readw(addr0 + 0x68) | 0x0900); + { + struct RUNTIME_9060 __iomem *ctl_addr = addr0; + plx_init(pdev, irq, ctl_addr); + cy_writew(&ctl_addr->intr_ctrl_stat, + readw(&ctl_addr->intr_ctrl_stat) | 0x0900); break; } + } } dev_info(&pdev->dev, "%s/PCI #%d found: %d channels starting from " @@ -5179,22 +5138,23 @@ static void __devexit cy_pci_remove(struct pci_dev *pdev) unsigned int i; /* non-Z with old PLX */ - if (!IS_CYC_Z(*cinfo) && (readb(cinfo->base_addr + CyPLX_VER) & 0x0f) == + if (!cy_is_Z(cinfo) && (readb(cinfo->base_addr + CyPLX_VER) & 0x0f) == PLX_9050) - cy_writeb(cinfo->ctl_addr + 0x4c, 0); + cy_writeb(cinfo->ctl_addr.p9050 + 0x4c, 0); else #ifndef CONFIG_CYZ_INTR - if (!IS_CYC_Z(*cinfo)) + if (!cy_is_Z(cinfo)) #endif - cy_writew(cinfo->ctl_addr + 0x68, - readw(cinfo->ctl_addr + 0x68) & ~0x0900); + cy_writew(&cinfo->ctl_addr.p9060->intr_ctrl_stat, + readw(&cinfo->ctl_addr.p9060->intr_ctrl_stat) & + ~0x0900); iounmap(cinfo->base_addr); - if (cinfo->ctl_addr) - iounmap(cinfo->ctl_addr); + if (cinfo->ctl_addr.p9050) + iounmap(cinfo->ctl_addr.p9050); if (cinfo->irq #ifndef CONFIG_CYZ_INTR - && !IS_CYC_Z(*cinfo) + && !cy_is_Z(cinfo) #endif /* CONFIG_CYZ_INTR */ ) free_irq(cinfo->irq, cinfo); @@ -5240,7 +5200,7 @@ static int cyclades_proc_show(struct seq_file *m, void *v) (cur_jifs - info->idle_stats.recv_idle)/ HZ, info->idle_stats.overruns, /* FIXME: double check locking */ - (long)info->port.tty->ldisc.ops->num); + (long)info->port.tty->ldisc->ops->num); else seq_printf(m, "%3d %8lu %10lu %8lu " "%10lu %8lu %9lu %6ld\n", @@ -5386,11 +5346,11 @@ static void __exit cy_cleanup_module(void) /* clear interrupt */ cy_writeb(card->base_addr + Cy_ClrIntr, 0); iounmap(card->base_addr); - if (card->ctl_addr) - iounmap(card->ctl_addr); + if (card->ctl_addr.p9050) + iounmap(card->ctl_addr.p9050); if (card->irq #ifndef CONFIG_CYZ_INTR - && !IS_CYC_Z(*card) + && !cy_is_Z(card) #endif /* CONFIG_CYZ_INTR */ ) free_irq(card->irq, card); diff --git a/drivers/char/dtlk.c b/drivers/char/dtlk.c index 6b900b297cc6..52e06589821d 100644 --- a/drivers/char/dtlk.c +++ b/drivers/char/dtlk.c @@ -571,7 +571,7 @@ static char dtlk_read_tts(void) portval = inb_p(dtlk_port_tts); } while ((portval & TTS_READABLE) == 0 && retries++ < DTLK_MAX_RETRIES); - if (retries == DTLK_MAX_RETRIES) + if (retries > DTLK_MAX_RETRIES) printk(KERN_ERR "dtlk_read_tts() timeout\n"); ch = inb_p(dtlk_port_tts); /* input from TTS port */ @@ -583,7 +583,7 @@ static char dtlk_read_tts(void) portval = inb_p(dtlk_port_tts); } while ((portval & TTS_READABLE) != 0 && retries++ < DTLK_MAX_RETRIES); - if (retries == DTLK_MAX_RETRIES) + if (retries > DTLK_MAX_RETRIES) printk(KERN_ERR "dtlk_read_tts() timeout\n"); TRACE_RET; @@ -640,7 +640,7 @@ static char dtlk_write_tts(char ch) while ((inb_p(dtlk_port_tts) & TTS_WRITABLE) == 0 && retries++ < DTLK_MAX_RETRIES) /* DT ready? */ ; - if (retries == DTLK_MAX_RETRIES) + if (retries > DTLK_MAX_RETRIES) printk(KERN_ERR "dtlk_write_tts() timeout\n"); outb_p(ch, dtlk_port_tts); /* output to TTS port */ diff --git a/drivers/char/epca.c b/drivers/char/epca.c index af7c13ca9493..abef1f7d84fe 100644 --- a/drivers/char/epca.c +++ b/drivers/char/epca.c @@ -745,7 +745,7 @@ static int epca_carrier_raised(struct tty_port *port) return 0; } -static void epca_raise_dtr_rts(struct tty_port *port) +static void epca_dtr_rts(struct tty_port *port, int onoff) { } @@ -925,7 +925,7 @@ static const struct tty_operations pc_ops = { static const struct tty_port_operations epca_port_ops = { .carrier_raised = epca_carrier_raised, - .raise_dtr_rts = epca_raise_dtr_rts, + .dtr_rts = epca_dtr_rts, }; static int info_open(struct tty_struct *tty, struct file *filp) @@ -1518,7 +1518,7 @@ static void doevent(int crd) if (event & MODEMCHG_IND) { /* A modem signal change has been indicated */ ch->imodem = mstat; - if (test_bit(ASYNC_CHECK_CD, &ch->port.flags)) { + if (test_bit(ASYNCB_CHECK_CD, &ch->port.flags)) { /* We are now receiving dcd */ if (mstat & ch->dcd) wake_up_interruptible(&ch->port.open_wait); @@ -1765,9 +1765,9 @@ static void epcaparam(struct tty_struct *tty, struct channel *ch) * that the driver will wait on carrier detect. */ if (ts->c_cflag & CLOCAL) - clear_bit(ASYNC_CHECK_CD, &ch->port.flags); + clear_bit(ASYNCB_CHECK_CD, &ch->port.flags); else - set_bit(ASYNC_CHECK_CD, &ch->port.flags); + set_bit(ASYNCB_CHECK_CD, &ch->port.flags); mval = ch->m_dtr | ch->m_rts; } /* End CBAUD not detected */ iflag = termios2digi_i(ch, ts->c_iflag); @@ -2114,8 +2114,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.ops->flush_buffer) - tty->ldisc.ops->flush_buffer(tty); + if (tty->ldisc->ops->flush_buffer) + tty->ldisc->ops->flush_buffer(tty); } unlock_kernel(); /* Fall Thru */ @@ -2244,7 +2244,8 @@ static void do_softint(struct work_struct *work) if (test_and_clear_bit(EPCA_EVENT_HANGUP, &ch->event)) { tty_hangup(tty); wake_up_interruptible(&ch->port.open_wait); - clear_bit(ASYNC_NORMAL_ACTIVE, &ch->port.flags); + clear_bit(ASYNCB_NORMAL_ACTIVE, + &ch->port.flags); } } tty_kref_put(tty); diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index 340ba4f9dc54..4a9f3492b921 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c @@ -224,7 +224,7 @@ static void hpet_timer_set_irq(struct hpet_dev *devp) break; } - gsi = acpi_register_gsi(irq, ACPI_LEVEL_SENSITIVE, + gsi = acpi_register_gsi(NULL, irq, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW); if (gsi > 0) break; @@ -939,7 +939,7 @@ static acpi_status hpet_resources(struct acpi_resource *res, void *data) irqp = &res->data.extended_irq; for (i = 0; i < irqp->interrupt_count; i++) { - irq = acpi_register_gsi(irqp->interrupts[i], + irq = acpi_register_gsi(NULL, irqp->interrupts[i], irqp->triggering, irqp->polarity); if (irq < 0) return AE_ERROR; diff --git a/drivers/char/hvc_iseries.c b/drivers/char/hvc_iseries.c index 449727b6166d..936d05bf37fa 100644 --- a/drivers/char/hvc_iseries.c +++ b/drivers/char/hvc_iseries.c @@ -241,7 +241,7 @@ static int __devexit hvc_vio_remove(struct vio_dev *vdev) static struct vio_driver hvc_vio_driver = { .id_table = hvc_driver_table, .probe = hvc_vio_probe, - .remove = hvc_vio_remove, + .remove = __devexit_p(hvc_vio_remove), .driver = { .name = hvc_driver_name, .owner = THIS_MODULE, diff --git a/drivers/char/hvc_iucv.c b/drivers/char/hvc_iucv.c index 54481a887769..86105efb4eb6 100644 --- a/drivers/char/hvc_iucv.c +++ b/drivers/char/hvc_iucv.c @@ -4,7 +4,7 @@ * This HVC device driver provides terminal access using * z/VM IUCV communication paths. * - * Copyright IBM Corp. 2008 + * Copyright IBM Corp. 2008, 2009 * * Author(s): Hendrik Brueckner */ @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -74,6 +75,7 @@ struct hvc_iucv_private { wait_queue_head_t sndbuf_waitq; /* wait for send completion */ struct list_head tty_outqueue; /* outgoing IUCV messages */ struct list_head tty_inqueue; /* incoming IUCV messages */ + struct device *dev; /* device structure */ }; struct iucv_tty_buffer { @@ -542,7 +544,68 @@ static void flush_sndbuf_sync(struct hvc_iucv_private *priv) if (sync_wait) wait_event_timeout(priv->sndbuf_waitq, - tty_outqueue_empty(priv), HZ); + tty_outqueue_empty(priv), HZ/10); +} + +/** + * hvc_iucv_hangup() - Sever IUCV path and schedule hvc tty hang up + * @priv: Pointer to hvc_iucv_private structure + * + * This routine severs an existing IUCV communication path and hangs + * up the underlying HVC terminal device. + * The hang-up occurs only if an IUCV communication path is established; + * otherwise there is no need to hang up the terminal device. + * + * The IUCV HVC hang-up is separated into two steps: + * 1. After the IUCV path has been severed, the iucv_state is set to + * IUCV_SEVERED. + * 2. Later, when the HVC thread calls hvc_iucv_get_chars(), the + * IUCV_SEVERED state causes the tty hang-up in the HVC layer. + * + * If the tty has not yet been opened, clean up the hvc_iucv_private + * structure to allow re-connects. + * If the tty has been opened, let get_chars() return -EPIPE to signal + * the HVC layer to hang up the tty and, if so, wake up the HVC thread + * to call get_chars()... + * + * Special notes on hanging up a HVC terminal instantiated as console: + * Hang-up: 1. do_tty_hangup() replaces file ops (= hung_up_tty_fops) + * 2. do_tty_hangup() calls tty->ops->close() for console_filp + * => no hangup notifier is called by HVC (default) + * 2. hvc_close() returns because of tty_hung_up_p(filp) + * => no delete notifier is called! + * Finally, the back-end is not being notified, thus, the tty session is + * kept active (TTY_OPEN) to be ready for re-connects. + * + * Locking: spin_lock(&priv->lock) w/o disabling bh + */ +static void hvc_iucv_hangup(struct hvc_iucv_private *priv) +{ + struct iucv_path *path; + + path = NULL; + spin_lock(&priv->lock); + if (priv->iucv_state == IUCV_CONNECTED) { + path = priv->path; + priv->path = NULL; + priv->iucv_state = IUCV_SEVERED; + if (priv->tty_state == TTY_CLOSED) + hvc_iucv_cleanup(priv); + else + /* console is special (see above) */ + if (priv->is_console) { + hvc_iucv_cleanup(priv); + priv->tty_state = TTY_OPENED; + } else + hvc_kick(); + } + spin_unlock(&priv->lock); + + /* finally sever path (outside of priv->lock due to lock ordering) */ + if (path) { + iucv_path_sever(path, NULL); + iucv_path_free(path); + } } /** @@ -735,11 +798,8 @@ out_path_handled: * @ipuser: User specified data for this path * (AF_IUCV: port/service name and originator port) * - * The function also severs the path (as required by the IUCV protocol) and - * sets the iucv state to IUCV_SEVERED for the associated struct - * hvc_iucv_private instance. Later, the IUCV_SEVERED state triggers a tty - * hangup (hvc_iucv_get_chars() / hvc_iucv_write()). - * If tty portion of the HVC is closed, clean up the outqueue. + * This function calls the hvc_iucv_hangup() function for the + * respective IUCV HVC terminal. * * Locking: struct hvc_iucv_private->lock */ @@ -747,33 +807,7 @@ static void hvc_iucv_path_severed(struct iucv_path *path, u8 ipuser[16]) { struct hvc_iucv_private *priv = path->private; - spin_lock(&priv->lock); - priv->iucv_state = IUCV_SEVERED; - - /* If the tty has not yet been opened, clean up the hvc_iucv_private - * structure to allow re-connects. - * This is also done for our console device because console hangups - * are handled specially and no notifier is called by HVC. - * The tty session is active (TTY_OPEN) and ready for re-connects... - * - * If it has been opened, let get_chars() return -EPIPE to signal the - * HVC layer to hang up the tty. - * If so, we need to wake up the HVC thread to call get_chars()... - */ - priv->path = NULL; - if (priv->tty_state == TTY_CLOSED) - hvc_iucv_cleanup(priv); - else - if (priv->is_console) { - hvc_iucv_cleanup(priv); - priv->tty_state = TTY_OPENED; - } else - hvc_kick(); - spin_unlock(&priv->lock); - - /* finally sever path (outside of priv->lock due to lock ordering) */ - iucv_path_sever(path, ipuser); - iucv_path_free(path); + hvc_iucv_hangup(priv); } /** @@ -853,6 +887,37 @@ static void hvc_iucv_msg_complete(struct iucv_path *path, destroy_tty_buffer_list(&list_remove); } +/** + * hvc_iucv_pm_freeze() - Freeze PM callback + * @dev: IUVC HVC terminal device + * + * Sever an established IUCV communication path and + * trigger a hang-up of the underlying HVC terminal. + */ +static int hvc_iucv_pm_freeze(struct device *dev) +{ + struct hvc_iucv_private *priv = dev_get_drvdata(dev); + + local_bh_disable(); + hvc_iucv_hangup(priv); + local_bh_enable(); + + return 0; +} + +/** + * hvc_iucv_pm_restore_thaw() - Thaw and restore PM callback + * @dev: IUVC HVC terminal device + * + * Wake up the HVC thread to trigger hang-up and respective + * HVC back-end notifier invocations. + */ +static int hvc_iucv_pm_restore_thaw(struct device *dev) +{ + hvc_kick(); + return 0; +} + /* HVC operations */ static struct hv_ops hvc_iucv_ops = { @@ -863,6 +928,20 @@ static struct hv_ops hvc_iucv_ops = { .notifier_hangup = hvc_iucv_notifier_hangup, }; +/* Suspend / resume device operations */ +static struct dev_pm_ops hvc_iucv_pm_ops = { + .freeze = hvc_iucv_pm_freeze, + .thaw = hvc_iucv_pm_restore_thaw, + .restore = hvc_iucv_pm_restore_thaw, +}; + +/* IUCV HVC device driver */ +static struct device_driver hvc_iucv_driver = { + .name = KMSG_COMPONENT, + .bus = &iucv_bus, + .pm = &hvc_iucv_pm_ops, +}; + /** * hvc_iucv_alloc() - Allocates a new struct hvc_iucv_private instance * @id: hvc_iucv_table index @@ -897,14 +976,12 @@ static int __init hvc_iucv_alloc(int id, unsigned int is_console) /* set console flag */ priv->is_console = is_console; - /* finally allocate hvc */ + /* allocate hvc device */ priv->hvc = hvc_alloc(HVC_IUCV_MAGIC + id, /* PAGE_SIZE */ HVC_IUCV_MAGIC + id, &hvc_iucv_ops, 256); if (IS_ERR(priv->hvc)) { rc = PTR_ERR(priv->hvc); - free_page((unsigned long) priv->sndbuf); - kfree(priv); - return rc; + goto out_error_hvc; } /* notify HVC thread instead of using polling */ @@ -915,8 +992,45 @@ static int __init hvc_iucv_alloc(int id, unsigned int is_console) memcpy(priv->srv_name, name, 8); ASCEBC(priv->srv_name, 8); + /* create and setup device */ + priv->dev = kzalloc(sizeof(*priv->dev), GFP_KERNEL); + if (!priv->dev) { + rc = -ENOMEM; + goto out_error_dev; + } + dev_set_name(priv->dev, "hvc_iucv%d", id); + dev_set_drvdata(priv->dev, priv); + priv->dev->bus = &iucv_bus; + priv->dev->parent = iucv_root; + priv->dev->driver = &hvc_iucv_driver; + priv->dev->release = (void (*)(struct device *)) kfree; + rc = device_register(priv->dev); + if (rc) { + kfree(priv->dev); + goto out_error_dev; + } + hvc_iucv_table[id] = priv; return 0; + +out_error_dev: + hvc_remove(priv->hvc); +out_error_hvc: + free_page((unsigned long) priv->sndbuf); + kfree(priv); + + return rc; +} + +/** + * hvc_iucv_destroy() - Destroy and free hvc_iucv_private instances + */ +static void __init hvc_iucv_destroy(struct hvc_iucv_private *priv) +{ + hvc_remove(priv->hvc); + device_unregister(priv->dev); + free_page((unsigned long) priv->sndbuf); + kfree(priv); } /** @@ -1109,6 +1223,11 @@ static int __init hvc_iucv_init(void) goto out_error; } + /* register IUCV HVC device driver */ + rc = driver_register(&hvc_iucv_driver); + if (rc) + goto out_error; + /* parse hvc_iucv_allow string and create z/VM user ID filter list */ if (hvc_iucv_filter_string) { rc = hvc_iucv_setup_filter(hvc_iucv_filter_string); @@ -1183,15 +1302,14 @@ out_error_iucv: iucv_unregister(&hvc_iucv_handler, 0); out_error_hvc: for (i = 0; i < hvc_iucv_devices; i++) - if (hvc_iucv_table[i]) { - if (hvc_iucv_table[i]->hvc) - hvc_remove(hvc_iucv_table[i]->hvc); - kfree(hvc_iucv_table[i]); - } + if (hvc_iucv_table[i]) + hvc_iucv_destroy(hvc_iucv_table[i]); out_error_memory: mempool_destroy(hvc_iucv_mempool); kmem_cache_destroy(hvc_iucv_buffer_cache); out_error: + if (hvc_iucv_filter) + kfree(hvc_iucv_filter); hvc_iucv_devices = 0; /* ensure that we do not provide any device */ return rc; } diff --git a/drivers/char/hvc_vio.c b/drivers/char/hvc_vio.c index bd62dc86b47d..c72b994652ac 100644 --- a/drivers/char/hvc_vio.c +++ b/drivers/char/hvc_vio.c @@ -113,7 +113,7 @@ static int __devexit hvc_vio_remove(struct vio_dev *vdev) static struct vio_driver hvc_vio_driver = { .id_table = hvc_driver_table, .probe = hvc_vio_probe, - .remove = hvc_vio_remove, + .remove = __devexit_p(hvc_vio_remove), .driver = { .name = hvc_driver_name, .owner = THIS_MODULE, diff --git a/drivers/char/hvcs.c b/drivers/char/hvcs.c index c76bccf5354d..266b858b8f85 100644 --- a/drivers/char/hvcs.c +++ b/drivers/char/hvcs.c @@ -347,7 +347,7 @@ static void __exit hvcs_module_exit(void); static inline struct hvcs_struct *from_vio_dev(struct vio_dev *viod) { - return viod->dev.driver_data; + return dev_get_drvdata(&viod->dev); } /* The sysfs interface for the driver and devices */ @@ -785,7 +785,7 @@ static int __devinit hvcs_probe( kref_init(&hvcsd->kref); hvcsd->vdev = dev; - dev->dev.driver_data = hvcsd; + dev_set_drvdata(&dev->dev, hvcsd); hvcsd->index = index; @@ -831,7 +831,7 @@ static int __devinit hvcs_probe( static int __devexit hvcs_remove(struct vio_dev *dev) { - struct hvcs_struct *hvcsd = dev->dev.driver_data; + struct hvcs_struct *hvcsd = dev_get_drvdata(&dev->dev); unsigned long flags; struct tty_struct *tty; @@ -868,7 +868,7 @@ static int __devexit hvcs_remove(struct vio_dev *dev) static struct vio_driver hvcs_vio_driver = { .id_table = hvcs_driver_table, .probe = hvcs_probe, - .remove = hvcs_remove, + .remove = __devexit_p(hvcs_remove), .driver = { .name = hvcs_driver_name, .owner = THIS_MODULE, diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index 5fab6470f4b2..ce66a70184f7 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -88,7 +88,7 @@ config HW_RANDOM_N2RNG config HW_RANDOM_VIA tristate "VIA HW Random Number Generator support" - depends on HW_RANDOM && X86_32 + depends on HW_RANDOM && X86 default HW_RANDOM ---help--- This driver provides kernel-side support for the Random Number @@ -148,3 +148,28 @@ config HW_RANDOM_VIRTIO To compile this driver as a module, choose M here: the module will be called virtio-rng. If unsure, say N. + +config HW_RANDOM_TX4939 + tristate "TX4939 Random Number Generator support" + depends on HW_RANDOM && SOC_TX4939 + default HW_RANDOM + ---help--- + This driver provides kernel-side support for the Random Number + Generator hardware found on TX4939 SoC. + + To compile this driver as a module, choose M here: the + module will be called tx4939-rng. + + If unsure, say Y. + +config HW_RANDOM_MXC_RNGA + tristate "Freescale i.MX RNGA Random Number Generator" + depends on HW_RANDOM && ARCH_HAS_RNGA + ---help--- + This driver provides kernel-side support for the Random Number + Generator hardware found on Freescale i.MX processors. + + To compile this driver as a module, choose M here: the + module will be called mxc-rnga. + + If unsure, say Y. diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile index e81d21a5f28f..676828ba8123 100644 --- a/drivers/char/hw_random/Makefile +++ b/drivers/char/hw_random/Makefile @@ -15,3 +15,5 @@ obj-$(CONFIG_HW_RANDOM_IXP4XX) += ixp4xx-rng.o obj-$(CONFIG_HW_RANDOM_OMAP) += omap-rng.o obj-$(CONFIG_HW_RANDOM_PASEMI) += pasemi-rng.o obj-$(CONFIG_HW_RANDOM_VIRTIO) += virtio-rng.o +obj-$(CONFIG_HW_RANDOM_TX4939) += tx4939-rng.o +obj-$(CONFIG_HW_RANDOM_MXC_RNGA) += mxc-rnga.o diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c index e5d583c84e4f..fc93e2fc7c71 100644 --- a/drivers/char/hw_random/core.c +++ b/drivers/char/hw_random/core.c @@ -153,6 +153,7 @@ static const struct file_operations rng_chrdev_ops = { static struct miscdevice rng_miscdev = { .minor = RNG_MISCDEV_MINOR, .name = RNG_MODULE_NAME, + .devnode = "hwrng", .fops = &rng_chrdev_ops, }; diff --git a/drivers/char/hw_random/mxc-rnga.c b/drivers/char/hw_random/mxc-rnga.c new file mode 100644 index 000000000000..187c6be80f43 --- /dev/null +++ b/drivers/char/hw_random/mxc-rnga.c @@ -0,0 +1,247 @@ +/* + * RNG driver for Freescale RNGA + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Author: Alan Carvalho de Assis + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + * + * This driver is based on other RNG drivers. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* RNGA Registers */ +#define RNGA_CONTROL 0x00 +#define RNGA_STATUS 0x04 +#define RNGA_ENTROPY 0x08 +#define RNGA_OUTPUT_FIFO 0x0c +#define RNGA_MODE 0x10 +#define RNGA_VERIFICATION_CONTROL 0x14 +#define RNGA_OSC_CONTROL_COUNTER 0x18 +#define RNGA_OSC1_COUNTER 0x1c +#define RNGA_OSC2_COUNTER 0x20 +#define RNGA_OSC_COUNTER_STATUS 0x24 + +/* RNGA Registers Range */ +#define RNG_ADDR_RANGE 0x28 + +/* RNGA Control Register */ +#define RNGA_CONTROL_SLEEP 0x00000010 +#define RNGA_CONTROL_CLEAR_INT 0x00000008 +#define RNGA_CONTROL_MASK_INTS 0x00000004 +#define RNGA_CONTROL_HIGH_ASSURANCE 0x00000002 +#define RNGA_CONTROL_GO 0x00000001 + +#define RNGA_STATUS_LEVEL_MASK 0x0000ff00 + +/* RNGA Status Register */ +#define RNGA_STATUS_OSC_DEAD 0x80000000 +#define RNGA_STATUS_SLEEP 0x00000010 +#define RNGA_STATUS_ERROR_INT 0x00000008 +#define RNGA_STATUS_FIFO_UNDERFLOW 0x00000004 +#define RNGA_STATUS_LAST_READ_STATUS 0x00000002 +#define RNGA_STATUS_SECURITY_VIOLATION 0x00000001 + +static struct platform_device *rng_dev; + +static int mxc_rnga_data_present(struct hwrng *rng) +{ + int level; + void __iomem *rng_base = (void __iomem *)rng->priv; + + /* how many random numbers is in FIFO? [0-16] */ + level = ((__raw_readl(rng_base + RNGA_STATUS) & + RNGA_STATUS_LEVEL_MASK) >> 8); + + return level > 0 ? 1 : 0; +} + +static int mxc_rnga_data_read(struct hwrng *rng, u32 * data) +{ + int err; + u32 ctrl; + void __iomem *rng_base = (void __iomem *)rng->priv; + + /* retrieve a random number from FIFO */ + *data = __raw_readl(rng_base + RNGA_OUTPUT_FIFO); + + /* some error while reading this random number? */ + err = __raw_readl(rng_base + RNGA_STATUS) & RNGA_STATUS_ERROR_INT; + + /* if error: clear error interrupt, but doesn't return random number */ + if (err) { + dev_dbg(&rng_dev->dev, "Error while reading random number!\n"); + ctrl = __raw_readl(rng_base + RNGA_CONTROL); + __raw_writel(ctrl | RNGA_CONTROL_CLEAR_INT, + rng_base + RNGA_CONTROL); + return 0; + } else + return 4; +} + +static int mxc_rnga_init(struct hwrng *rng) +{ + u32 ctrl, osc; + void __iomem *rng_base = (void __iomem *)rng->priv; + + /* wake up */ + ctrl = __raw_readl(rng_base + RNGA_CONTROL); + __raw_writel(ctrl & ~RNGA_CONTROL_SLEEP, rng_base + RNGA_CONTROL); + + /* verify if oscillator is working */ + osc = __raw_readl(rng_base + RNGA_STATUS); + if (osc & RNGA_STATUS_OSC_DEAD) { + dev_err(&rng_dev->dev, "RNGA Oscillator is dead!\n"); + return -ENODEV; + } + + /* go running */ + ctrl = __raw_readl(rng_base + RNGA_CONTROL); + __raw_writel(ctrl | RNGA_CONTROL_GO, rng_base + RNGA_CONTROL); + + return 0; +} + +static void mxc_rnga_cleanup(struct hwrng *rng) +{ + u32 ctrl; + void __iomem *rng_base = (void __iomem *)rng->priv; + + ctrl = __raw_readl(rng_base + RNGA_CONTROL); + + /* stop rnga */ + __raw_writel(ctrl & ~RNGA_CONTROL_GO, rng_base + RNGA_CONTROL); +} + +static struct hwrng mxc_rnga = { + .name = "mxc-rnga", + .init = mxc_rnga_init, + .cleanup = mxc_rnga_cleanup, + .data_present = mxc_rnga_data_present, + .data_read = mxc_rnga_data_read +}; + +static int __init mxc_rnga_probe(struct platform_device *pdev) +{ + int err = -ENODEV; + struct clk *clk; + struct resource *res, *mem; + void __iomem *rng_base = NULL; + + if (rng_dev) + return -EBUSY; + + clk = clk_get(&pdev->dev, "rng"); + if (IS_ERR(clk)) { + dev_err(&pdev->dev, "Could not get rng_clk!\n"); + err = PTR_ERR(clk); + goto out; + } + + clk_enable(clk); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + err = -ENOENT; + goto err_region; + } + + mem = request_mem_region(res->start, resource_size(res), pdev->name); + if (mem == NULL) { + err = -EBUSY; + goto err_region; + } + + rng_base = ioremap(res->start, resource_size(res)); + if (!rng_base) { + err = -ENOMEM; + goto err_ioremap; + } + + mxc_rnga.priv = (unsigned long)rng_base; + + err = hwrng_register(&mxc_rnga); + if (err) { + dev_err(&pdev->dev, "MXC RNGA registering failed (%d)\n", err); + goto err_register; + } + + rng_dev = pdev; + + dev_info(&pdev->dev, "MXC RNGA Registered.\n"); + + return 0; + +err_register: + iounmap(rng_base); + rng_base = NULL; + +err_ioremap: + release_mem_region(res->start, resource_size(res)); + +err_region: + clk_disable(clk); + clk_put(clk); + +out: + return err; +} + +static int __exit mxc_rnga_remove(struct platform_device *pdev) +{ + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + void __iomem *rng_base = (void __iomem *)mxc_rnga.priv; + struct clk *clk = clk_get(&pdev->dev, "rng"); + + hwrng_unregister(&mxc_rnga); + + iounmap(rng_base); + + release_mem_region(res->start, resource_size(res)); + + clk_disable(clk); + clk_put(clk); + + return 0; +} + +static struct platform_driver mxc_rnga_driver = { + .driver = { + .name = "mxc_rnga", + .owner = THIS_MODULE, + }, + .remove = __exit_p(mxc_rnga_remove), +}; + +static int __init mod_init(void) +{ + return platform_driver_probe(&mxc_rnga_driver, mxc_rnga_probe); +} + +static void __exit mod_exit(void) +{ + platform_driver_unregister(&mxc_rnga_driver); +} + +module_init(mod_init); +module_exit(mod_exit); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("H/W RNGA driver for i.MX"); +MODULE_LICENSE("GPL"); diff --git a/drivers/char/hw_random/omap-rng.c b/drivers/char/hw_random/omap-rng.c index 538313f9e7ac..00dd3de1be51 100644 --- a/drivers/char/hw_random/omap-rng.c +++ b/drivers/char/hw_random/omap-rng.c @@ -89,7 +89,7 @@ static struct hwrng omap_rng_ops = { .data_read = omap_rng_data_read, }; -static int __init omap_rng_probe(struct platform_device *pdev) +static int __devinit omap_rng_probe(struct platform_device *pdev) { struct resource *res, *mem; int ret; diff --git a/drivers/char/hw_random/timeriomem-rng.c b/drivers/char/hw_random/timeriomem-rng.c index dcd352ad0e7f..a94e930575f2 100644 --- a/drivers/char/hw_random/timeriomem-rng.c +++ b/drivers/char/hw_random/timeriomem-rng.c @@ -88,9 +88,9 @@ static struct hwrng timeriomem_rng_ops = { .priv = 0, }; -static int __init timeriomem_rng_probe(struct platform_device *pdev) +static int __devinit timeriomem_rng_probe(struct platform_device *pdev) { - struct resource *res, *mem; + struct resource *res; int ret; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -98,21 +98,12 @@ static int __init timeriomem_rng_probe(struct platform_device *pdev) if (!res) return -ENOENT; - mem = request_mem_region(res->start, res->end - res->start + 1, - pdev->name); - if (mem == NULL) - return -EBUSY; - - dev_set_drvdata(&pdev->dev, mem); - timeriomem_rng_data = pdev->dev.platform_data; timeriomem_rng_data->address = ioremap(res->start, res->end - res->start + 1); - if (!timeriomem_rng_data->address) { - ret = -ENOMEM; - goto err_ioremap; - } + if (!timeriomem_rng_data->address) + return -EIO; if (timeriomem_rng_data->period != 0 && usecs_to_jiffies(timeriomem_rng_data->period) > 0) { @@ -125,7 +116,7 @@ static int __init timeriomem_rng_probe(struct platform_device *pdev) ret = hwrng_register(&timeriomem_rng_ops); if (ret) - goto err_register; + goto failed; dev_info(&pdev->dev, "32bits from 0x%p @ %dus\n", timeriomem_rng_data->address, @@ -133,24 +124,19 @@ static int __init timeriomem_rng_probe(struct platform_device *pdev) return 0; -err_register: +failed: dev_err(&pdev->dev, "problem registering\n"); iounmap(timeriomem_rng_data->address); -err_ioremap: - release_resource(mem); return ret; } static int __devexit timeriomem_rng_remove(struct platform_device *pdev) { - struct resource *mem = dev_get_drvdata(&pdev->dev); - del_timer_sync(&timeriomem_rng_timer); hwrng_unregister(&timeriomem_rng_ops); iounmap(timeriomem_rng_data->address); - release_resource(mem); return 0; } diff --git a/drivers/char/hw_random/tx4939-rng.c b/drivers/char/hw_random/tx4939-rng.c new file mode 100644 index 000000000000..544d9085a8e8 --- /dev/null +++ b/drivers/char/hw_random/tx4939-rng.c @@ -0,0 +1,184 @@ +/* + * RNG driver for TX4939 Random Number Generators (RNG) + * + * Copyright (C) 2009 Atsushi Nemoto + * + * 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 +#include +#include +#include +#include +#include +#include + +#define TX4939_RNG_RCSR 0x00000000 +#define TX4939_RNG_ROR(n) (0x00000018 + (n) * 8) + +#define TX4939_RNG_RCSR_INTE 0x00000008 +#define TX4939_RNG_RCSR_RST 0x00000004 +#define TX4939_RNG_RCSR_FIN 0x00000002 +#define TX4939_RNG_RCSR_ST 0x00000001 + +struct tx4939_rng { + struct hwrng rng; + void __iomem *base; + u64 databuf[3]; + unsigned int data_avail; +}; + +static void rng_io_start(void) +{ +#ifndef CONFIG_64BIT + /* + * readq is reading a 64-bit register using a 64-bit load. On + * a 32-bit kernel however interrupts or any other processor + * exception would clobber the upper 32-bit of the processor + * register so interrupts need to be disabled. + */ + local_irq_disable(); +#endif +} + +static void rng_io_end(void) +{ +#ifndef CONFIG_64BIT + local_irq_enable(); +#endif +} + +static u64 read_rng(void __iomem *base, unsigned int offset) +{ + return ____raw_readq(base + offset); +} + +static void write_rng(u64 val, void __iomem *base, unsigned int offset) +{ + return ____raw_writeq(val, base + offset); +} + +static int tx4939_rng_data_present(struct hwrng *rng, int wait) +{ + struct tx4939_rng *rngdev = container_of(rng, struct tx4939_rng, rng); + int i; + + if (rngdev->data_avail) + return rngdev->data_avail; + for (i = 0; i < 20; i++) { + rng_io_start(); + if (!(read_rng(rngdev->base, TX4939_RNG_RCSR) + & TX4939_RNG_RCSR_ST)) { + rngdev->databuf[0] = + read_rng(rngdev->base, TX4939_RNG_ROR(0)); + rngdev->databuf[1] = + read_rng(rngdev->base, TX4939_RNG_ROR(1)); + rngdev->databuf[2] = + read_rng(rngdev->base, TX4939_RNG_ROR(2)); + rngdev->data_avail = + sizeof(rngdev->databuf) / sizeof(u32); + /* Start RNG */ + write_rng(TX4939_RNG_RCSR_ST, + rngdev->base, TX4939_RNG_RCSR); + wait = 0; + } + rng_io_end(); + if (!wait) + break; + /* 90 bus clock cycles by default for generation */ + ndelay(90 * 5); + } + return rngdev->data_avail; +} + +static int tx4939_rng_data_read(struct hwrng *rng, u32 *buffer) +{ + struct tx4939_rng *rngdev = container_of(rng, struct tx4939_rng, rng); + + rngdev->data_avail--; + *buffer = *((u32 *)&rngdev->databuf + rngdev->data_avail); + return sizeof(u32); +} + +static int __init tx4939_rng_probe(struct platform_device *dev) +{ + struct tx4939_rng *rngdev; + struct resource *r; + int i; + + r = platform_get_resource(dev, IORESOURCE_MEM, 0); + if (!r) + return -EBUSY; + rngdev = devm_kzalloc(&dev->dev, sizeof(*rngdev), GFP_KERNEL); + if (!rngdev) + return -ENOMEM; + if (!devm_request_mem_region(&dev->dev, r->start, resource_size(r), + dev_name(&dev->dev))) + return -EBUSY; + rngdev->base = devm_ioremap(&dev->dev, r->start, resource_size(r)); + if (!rngdev->base) + return -EBUSY; + + rngdev->rng.name = dev_name(&dev->dev); + rngdev->rng.data_present = tx4939_rng_data_present; + rngdev->rng.data_read = tx4939_rng_data_read; + + rng_io_start(); + /* Reset RNG */ + write_rng(TX4939_RNG_RCSR_RST, rngdev->base, TX4939_RNG_RCSR); + write_rng(0, rngdev->base, TX4939_RNG_RCSR); + /* Start RNG */ + write_rng(TX4939_RNG_RCSR_ST, rngdev->base, TX4939_RNG_RCSR); + rng_io_end(); + /* + * Drop first two results. From the datasheet: + * The quality of the random numbers generated immediately + * after reset can be insufficient. Therefore, do not use + * random numbers obtained from the first and second + * generations; use the ones from the third or subsequent + * generation. + */ + for (i = 0; i < 2; i++) { + rngdev->data_avail = 0; + if (!tx4939_rng_data_present(&rngdev->rng, 1)) + return -EIO; + } + + platform_set_drvdata(dev, rngdev); + return hwrng_register(&rngdev->rng); +} + +static int __exit tx4939_rng_remove(struct platform_device *dev) +{ + struct tx4939_rng *rngdev = platform_get_drvdata(dev); + + hwrng_unregister(&rngdev->rng); + platform_set_drvdata(dev, NULL); + return 0; +} + +static struct platform_driver tx4939_rng_driver = { + .driver = { + .name = "tx4939-rng", + .owner = THIS_MODULE, + }, + .remove = tx4939_rng_remove, +}; + +static int __init tx4939rng_init(void) +{ + return platform_driver_probe(&tx4939_rng_driver, tx4939_rng_probe); +} + +static void __exit tx4939rng_exit(void) +{ + platform_driver_unregister(&tx4939_rng_driver); +} + +module_init(tx4939rng_init); +module_exit(tx4939rng_exit); + +MODULE_DESCRIPTION("H/W Random Number Generator (RNG) driver for TX4939"); +MODULE_LICENSE("GPL"); diff --git a/drivers/char/hw_random/via-rng.c b/drivers/char/hw_random/via-rng.c index 4e9573c1d39e..794aacb715c1 100644 --- a/drivers/char/hw_random/via-rng.c +++ b/drivers/char/hw_random/via-rng.c @@ -132,6 +132,19 @@ static int via_rng_init(struct hwrng *rng) struct cpuinfo_x86 *c = &cpu_data(0); u32 lo, hi, old_lo; + /* VIA Nano CPUs don't have the MSR_VIA_RNG anymore. The RNG + * is always enabled if CPUID rng_en is set. There is no + * RNG configuration like it used to be the case in this + * register */ + if ((c->x86 == 6) && (c->x86_model >= 0x0f)) { + if (!cpu_has_xstore_enabled) { + printk(KERN_ERR PFX "can't enable hardware RNG " + "if XSTORE is not enabled\n"); + return -ENODEV; + } + return 0; + } + /* Control the RNG via MSR. Tread lightly and pay very close * close attention to values written, as the reserved fields * are documented to be "undefined and unpredictable"; but it @@ -205,5 +218,5 @@ static void __exit mod_exit(void) module_init(mod_init); module_exit(mod_exit); -MODULE_DESCRIPTION("H/W RNG driver for VIA chipsets"); +MODULE_DESCRIPTION("H/W RNG driver for VIA CPU with PadLock"); MODULE_LICENSE("GPL"); diff --git a/drivers/char/hw_random/virtio-rng.c b/drivers/char/hw_random/virtio-rng.c index 86e83f883139..32216b623248 100644 --- a/drivers/char/hw_random/virtio-rng.c +++ b/drivers/char/hw_random/virtio-rng.c @@ -35,13 +35,13 @@ static DECLARE_COMPLETION(have_data); static void random_recv_done(struct virtqueue *vq) { - int len; + unsigned int len; /* We can get spurious callbacks, e.g. shared IRQs + virtio_pci. */ if (!vq->vq_ops->get_buf(vq, &len)) return; - data_left = len / sizeof(random_data[0]); + data_left += len; complete(&have_data); } @@ -49,7 +49,7 @@ static void register_buffer(void) { struct scatterlist sg; - sg_init_one(&sg, random_data, RANDOM_DATA_SIZE); + sg_init_one(&sg, random_data+data_left, RANDOM_DATA_SIZE-data_left); /* There should always be room for one buffer. */ if (vq->vq_ops->add_buf(vq, &sg, 0, 1, random_data) != 0) BUG(); @@ -59,24 +59,32 @@ static void register_buffer(void) /* At least we don't udelay() in a loop like some other drivers. */ static int virtio_data_present(struct hwrng *rng, int wait) { - if (data_left) + if (data_left >= sizeof(u32)) return 1; +again: if (!wait) return 0; wait_for_completion(&have_data); + + /* Not enough? Re-register. */ + if (unlikely(data_left < sizeof(u32))) { + register_buffer(); + goto again; + } + return 1; } /* virtio_data_present() must have succeeded before this is called. */ static int virtio_data_read(struct hwrng *rng, u32 *data) { - BUG_ON(!data_left); + BUG_ON(data_left < sizeof(u32)); + data_left -= sizeof(u32); + *data = random_data[data_left / 4]; - *data = random_data[--data_left]; - - if (!data_left) { + if (data_left < sizeof(u32)) { init_completion(&have_data); register_buffer(); } @@ -94,13 +102,13 @@ static int virtrng_probe(struct virtio_device *vdev) int err; /* We expect a single virtqueue. */ - vq = vdev->config->find_vq(vdev, 0, random_recv_done); + vq = virtio_find_single_vq(vdev, random_recv_done, "input"); if (IS_ERR(vq)) return PTR_ERR(vq); err = hwrng_register(&virtio_hwrng); if (err) { - vdev->config->del_vq(vq); + vdev->config->del_vqs(vdev); return err; } @@ -112,7 +120,7 @@ static void virtrng_remove(struct virtio_device *vdev) { vdev->config->reset(vdev); hwrng_unregister(&virtio_hwrng); - vdev->config->del_vq(vq); + vdev->config->del_vqs(vdev); } static struct virtio_device_id id_table[] = { diff --git a/drivers/char/ip2/i2lib.c b/drivers/char/ip2/i2lib.c index 0061e18aff60..0d10b89218ed 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.ops->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.ops->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 afd9247cf082..517271c762e6 100644 --- a/drivers/char/ip2/ip2main.c +++ b/drivers/char/ip2/ip2main.c @@ -1315,8 +1315,8 @@ static inline void isig(int sig, struct tty_struct *tty, int flush) if (tty->pgrp) kill_pgrp(tty->pgrp, sig, 1); if (flush || !L_NOFLSH(tty)) { - if ( tty->ldisc.ops->flush_buffer ) - tty->ldisc.ops->flush_buffer(tty); + if ( tty->ldisc->ops->flush_buffer ) + tty->ldisc->ops->flush_buffer(tty); i2InputFlush( tty->driver_data ); } } diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 259644646b82..d2e698096ace 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -2375,14 +2375,14 @@ static int __devinit ipmi_of_probe(struct of_device *dev, info->io.addr_data, info->io.regsize, info->io.regspacing, info->irq); - dev->dev.driver_data = (void *) info; + dev_set_drvdata(&dev->dev, info); return try_smi_init(info); } static int __devexit ipmi_of_remove(struct of_device *dev) { - cleanup_one_si(dev->dev.driver_data); + cleanup_one_si(dev_get_drvdata(&dev->dev)); return 0; } diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c index a59eac584d16..4159292e35cf 100644 --- a/drivers/char/isicom.c +++ b/drivers/char/isicom.c @@ -329,7 +329,7 @@ static inline void drop_rts(struct isi_port *port) /* card->lock MUST NOT be held */ -static void isicom_raise_dtr_rts(struct tty_port *port) +static void isicom_dtr_rts(struct tty_port *port, int on) { struct isi_port *ip = container_of(port, struct isi_port, port); struct isi_board *card = ip->card; @@ -339,10 +339,17 @@ static void isicom_raise_dtr_rts(struct tty_port *port) if (!lock_card(card)) return; - outw(0x8000 | (channel << card->shift_count) | 0x02, base); - outw(0x0f04, base); - InterruptTheCard(base); - ip->status |= (ISI_DTR | ISI_RTS); + if (on) { + outw(0x8000 | (channel << card->shift_count) | 0x02, base); + outw(0x0f04, base); + InterruptTheCard(base); + ip->status |= (ISI_DTR | ISI_RTS); + } else { + outw(0x8000 | (channel << card->shift_count) | 0x02, base); + outw(0x0C04, base); + InterruptTheCard(base); + ip->status &= ~(ISI_DTR | ISI_RTS); + } unlock_card(card); } @@ -1339,7 +1346,7 @@ static const struct tty_operations isicom_ops = { static const struct tty_port_operations isicom_port_ops = { .carrier_raised = isicom_carrier_raised, - .raise_dtr_rts = isicom_raise_dtr_rts, + .dtr_rts = isicom_dtr_rts, }; static int __devinit reset_card(struct pci_dev *pdev, @@ -1586,7 +1593,7 @@ static unsigned int card_count; static int __devinit isicom_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { - unsigned int signature, index; + unsigned int uninitialized_var(signature), index; int retval = -EPERM; struct isi_board *board = NULL; diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c index fff19f7e29d2..0c999f5bb3db 100644 --- a/drivers/char/istallion.c +++ b/drivers/char/istallion.c @@ -1140,14 +1140,14 @@ static int stli_carrier_raised(struct tty_port *port) return (portp->sigs & TIOCM_CD) ? 1 : 0; } -static void stli_raise_dtr_rts(struct tty_port *port) +static void stli_dtr_rts(struct tty_port *port, int on) { struct stliport *portp = container_of(port, struct stliport, port); struct stlibrd *brdp = stli_brds[portp->brdnr]; - stli_mkasysigs(&portp->asig, 1, 1); + stli_mkasysigs(&portp->asig, on, on); if (stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig, sizeof(asysigs_t), 0) < 0) - printk(KERN_WARNING "istallion: dtr raise failed.\n"); + printk(KERN_WARNING "istallion: dtr set failed.\n"); } @@ -3785,7 +3785,7 @@ err: return retval; } -static void stli_pciremove(struct pci_dev *pdev) +static void __devexit stli_pciremove(struct pci_dev *pdev) { struct stlibrd *brdp = pci_get_drvdata(pdev); @@ -4417,7 +4417,7 @@ static const struct tty_operations stli_ops = { static const struct tty_port_operations stli_port_ops = { .carrier_raised = stli_carrier_raised, - .raise_dtr_rts = stli_raise_dtr_rts, + .dtr_rts = stli_dtr_rts, }; /*****************************************************************************/ diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index de26a978fbdd..737be953cc58 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -1123,8 +1123,6 @@ static int emulate_raw(struct vc_data *vc, unsigned int keycode, #define HW_RAW(dev) 0 -#warning "Cannot generate rawmode keyboard for your architecture yet." - static int emulate_raw(struct vc_data *vc, unsigned int keycode, unsigned char up_flag) { if (keycode > 127) diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 65e12bca657c..afa8813e737a 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -694,9 +694,8 @@ static ssize_t read_zero(struct file * file, char __user * buf, written += chunk - unwritten; if (unwritten) break; - /* Consider changing this to just 'signal_pending()' with lots of testing */ - if (fatal_signal_pending(current)) - return written ? written : -EINTR; + if (signal_pending(current)) + return written ? written : -ERESTARTSYS; buf += chunk; count -= chunk; cond_resched(); @@ -864,59 +863,58 @@ static const struct file_operations kmsg_fops = { .write = kmsg_write, }; -static int memory_open(struct inode * inode, struct file * filp) +static const struct { + unsigned int minor; + char *name; + umode_t mode; + const struct file_operations *fops; + struct backing_dev_info *dev_info; +} devlist[] = { /* list of minor devices */ + {1, "mem", S_IRUSR | S_IWUSR | S_IRGRP, &mem_fops, + &directly_mappable_cdev_bdi}, +#ifdef CONFIG_DEVKMEM + {2, "kmem", S_IRUSR | S_IWUSR | S_IRGRP, &kmem_fops, + &directly_mappable_cdev_bdi}, +#endif + {3, "null", S_IRUGO | S_IWUGO, &null_fops, NULL}, +#ifdef CONFIG_DEVPORT + {4, "port", S_IRUSR | S_IWUSR | S_IRGRP, &port_fops, NULL}, +#endif + {5, "zero", S_IRUGO | S_IWUGO, &zero_fops, &zero_bdi}, + {7, "full", S_IRUGO | S_IWUGO, &full_fops, NULL}, + {8, "random", S_IRUGO | S_IWUSR, &random_fops, NULL}, + {9, "urandom", S_IRUGO | S_IWUSR, &urandom_fops, NULL}, + {11,"kmsg", S_IRUGO | S_IWUSR, &kmsg_fops, NULL}, +#ifdef CONFIG_CRASH_DUMP + {12,"oldmem", S_IRUSR | S_IWUSR | S_IRGRP, &oldmem_fops, NULL}, +#endif +}; + +static int memory_open(struct inode *inode, struct file *filp) { int ret = 0; + int i; lock_kernel(); - switch (iminor(inode)) { - case 1: - filp->f_op = &mem_fops; - filp->f_mapping->backing_dev_info = - &directly_mappable_cdev_bdi; + + for (i = 0; i < ARRAY_SIZE(devlist); i++) { + if (devlist[i].minor == iminor(inode)) { + filp->f_op = devlist[i].fops; + if (devlist[i].dev_info) { + filp->f_mapping->backing_dev_info = + devlist[i].dev_info; + } + break; -#ifdef CONFIG_DEVKMEM - case 2: - filp->f_op = &kmem_fops; - filp->f_mapping->backing_dev_info = - &directly_mappable_cdev_bdi; - break; -#endif - case 3: - filp->f_op = &null_fops; - break; -#ifdef CONFIG_DEVPORT - case 4: - filp->f_op = &port_fops; - break; -#endif - case 5: - filp->f_mapping->backing_dev_info = &zero_bdi; - filp->f_op = &zero_fops; - break; - case 7: - filp->f_op = &full_fops; - break; - case 8: - filp->f_op = &random_fops; - break; - case 9: - filp->f_op = &urandom_fops; - break; - case 11: - filp->f_op = &kmsg_fops; - break; -#ifdef CONFIG_CRASH_DUMP - case 12: - filp->f_op = &oldmem_fops; - break; -#endif - default: - unlock_kernel(); - return -ENXIO; + } } - if (filp->f_op && filp->f_op->open) - ret = filp->f_op->open(inode,filp); + + if (i == ARRAY_SIZE(devlist)) + ret = -ENXIO; + else + if (filp->f_op && filp->f_op->open) + ret = filp->f_op->open(inode, filp); + unlock_kernel(); return ret; } @@ -925,30 +923,6 @@ static const struct file_operations memory_fops = { .open = memory_open, /* just a selector for the real open */ }; -static const struct { - unsigned int minor; - char *name; - umode_t mode; - const struct file_operations *fops; -} devlist[] = { /* list of minor devices */ - {1, "mem", S_IRUSR | S_IWUSR | S_IRGRP, &mem_fops}, -#ifdef CONFIG_DEVKMEM - {2, "kmem", S_IRUSR | S_IWUSR | S_IRGRP, &kmem_fops}, -#endif - {3, "null", S_IRUGO | S_IWUGO, &null_fops}, -#ifdef CONFIG_DEVPORT - {4, "port", S_IRUSR | S_IWUSR | S_IRGRP, &port_fops}, -#endif - {5, "zero", S_IRUGO | S_IWUGO, &zero_fops}, - {7, "full", S_IRUGO | S_IWUGO, &full_fops}, - {8, "random", S_IRUGO | S_IWUSR, &random_fops}, - {9, "urandom", S_IRUGO | S_IWUSR, &urandom_fops}, - {11,"kmsg", S_IRUGO | S_IWUSR, &kmsg_fops}, -#ifdef CONFIG_CRASH_DUMP - {12,"oldmem", S_IRUSR | S_IWUSR | S_IRGRP, &oldmem_fops}, -#endif -}; - static struct class *mem_class; static int __init chr_dev_init(void) diff --git a/drivers/char/misc.c b/drivers/char/misc.c index a5e0db9d7662..62c99fa59e2b 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c @@ -168,7 +168,6 @@ static const struct file_operations misc_fops = { .open = misc_open, }; - /** * misc_register - register a miscellaneous device * @misc: device structure @@ -217,8 +216,8 @@ int misc_register(struct miscdevice * misc) misc_minors[misc->minor >> 3] |= 1 << (misc->minor & 7); dev = MKDEV(MISC_MAJOR, misc->minor); - misc->this_device = device_create(misc_class, misc->parent, dev, NULL, - "%s", misc->name); + misc->this_device = device_create(misc_class, misc->parent, dev, + misc, "%s", misc->name); if (IS_ERR(misc->this_device)) { err = PTR_ERR(misc->this_device); goto out; @@ -264,6 +263,15 @@ int misc_deregister(struct miscdevice *misc) EXPORT_SYMBOL(misc_register); EXPORT_SYMBOL(misc_deregister); +static char *misc_nodename(struct device *dev) +{ + struct miscdevice *c = dev_get_drvdata(dev); + + if (c->devnode) + return kstrdup(c->devnode, GFP_KERNEL); + return NULL; +} + static int __init misc_init(void) { int err; @@ -279,6 +287,7 @@ static int __init misc_init(void) err = -EIO; if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) goto fail_printk; + misc_class->nodename = misc_nodename; return 0; fail_printk: diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c index 4a4cab73d0be..65b6ff2442c6 100644 --- a/drivers/char/moxa.c +++ b/drivers/char/moxa.c @@ -1184,6 +1184,11 @@ static int moxa_open(struct tty_struct *tty, struct file *filp) return -ENODEV; } + if (port % MAX_PORTS_PER_BOARD >= brd->numPorts) { + mutex_unlock(&moxa_openlock); + return -ENODEV; + } + ch = &brd->ports[port % MAX_PORTS_PER_BOARD]; ch->port.count++; tty->driver_data = ch; diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c index 13f8871e5b21..52d953eb30c3 100644 --- a/drivers/char/mxser.c +++ b/drivers/char/mxser.c @@ -547,14 +547,18 @@ static int mxser_carrier_raised(struct tty_port *port) return (inb(mp->ioaddr + UART_MSR) & UART_MSR_DCD)?1:0; } -static void mxser_raise_dtr_rts(struct tty_port *port) +static void mxser_dtr_rts(struct tty_port *port, int on) { struct mxser_port *mp = container_of(port, struct mxser_port, port); unsigned long flags; spin_lock_irqsave(&mp->slock, flags); - outb(inb(mp->ioaddr + UART_MCR) | - UART_MCR_DTR | UART_MCR_RTS, mp->ioaddr + UART_MCR); + if (on) + outb(inb(mp->ioaddr + UART_MCR) | + UART_MCR_DTR | UART_MCR_RTS, mp->ioaddr + UART_MCR); + else + outb(inb(mp->ioaddr + UART_MCR)&~(UART_MCR_DTR | UART_MCR_RTS), + mp->ioaddr + UART_MCR); spin_unlock_irqrestore(&mp->slock, flags); } @@ -1044,8 +1048,6 @@ static int mxser_open(struct tty_struct *tty, struct file *filp) if (retval) return retval; - /* unmark here for very high baud rate (ex. 921600 bps) used */ - tty->low_latency = 1; return 0; } @@ -2356,7 +2358,7 @@ static const struct tty_operations mxser_ops = { struct tty_port_operations mxser_port_ops = { .carrier_raised = mxser_carrier_raised, - .raise_dtr_rts = mxser_raise_dtr_rts, + .dtr_rts = mxser_dtr_rts, }; /* diff --git a/drivers/char/n_hdlc.c b/drivers/char/n_hdlc.c index bacb3e2872ae..1c43c8cdee25 100644 --- a/drivers/char/n_hdlc.c +++ b/drivers/char/n_hdlc.c @@ -10,7 +10,6 @@ * Paul Mackerras * * Original release 01/11/99 - * $Id: n_hdlc.c,v 4.8 2003/05/06 21:18:51 paulkf Exp $ * * This code is released under the GNU General Public License (GPL) * @@ -79,7 +78,6 @@ */ #define HDLC_MAGIC 0x239e -#define HDLC_VERSION "$Revision: 4.8 $" #include #include @@ -114,7 +112,7 @@ #define MAX_HDLC_FRAME_SIZE 65535 #define DEFAULT_RX_BUF_COUNT 10 #define MAX_RX_BUF_COUNT 60 -#define DEFAULT_TX_BUF_COUNT 1 +#define DEFAULT_TX_BUF_COUNT 3 struct n_hdlc_buf { struct n_hdlc_buf *link; @@ -199,6 +197,31 @@ 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 void flush_rx_queue(struct tty_struct *tty) +{ + struct n_hdlc *n_hdlc = tty2n_hdlc(tty); + struct n_hdlc_buf *buf; + + while ((buf = n_hdlc_buf_get(&n_hdlc->rx_buf_list))) + n_hdlc_buf_put(&n_hdlc->rx_free_buf_list, buf); +} + +static void flush_tx_queue(struct tty_struct *tty) +{ + struct n_hdlc *n_hdlc = tty2n_hdlc(tty); + struct n_hdlc_buf *buf; + unsigned long flags; + + while ((buf = n_hdlc_buf_get(&n_hdlc->tx_buf_list))) + n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, buf); + spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags); + if (n_hdlc->tbuf) { + n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, n_hdlc->tbuf); + n_hdlc->tbuf = NULL; + } + spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags); +} + static struct tty_ldisc_ops n_hdlc_ldisc = { .owner = THIS_MODULE, .magic = TTY_LDISC_MAGIC, @@ -211,6 +234,7 @@ static struct tty_ldisc_ops n_hdlc_ldisc = { .poll = n_hdlc_tty_poll, .receive_buf = n_hdlc_tty_receive, .write_wakeup = n_hdlc_tty_wakeup, + .flush_buffer = flush_rx_queue, }; /** @@ -341,10 +365,7 @@ static int n_hdlc_tty_open (struct tty_struct *tty) set_bit(TTY_NO_WRITE_SPLIT,&tty->flags); #endif - /* Flush any pending characters in the driver and discipline. */ - if (tty->ldisc.ops->flush_buffer) - tty->ldisc.ops->flush_buffer(tty); - + /* flush receive data from driver */ tty_driver_flush_buffer(tty); if (debuglevel >= DEBUG_LEVEL_INFO) @@ -763,6 +784,14 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file, error = put_user(count, (int __user *)arg); break; + case TCFLSH: + switch (arg) { + case TCIOFLUSH: + case TCOFLUSH: + flush_tx_queue(tty); + } + /* fall through to default */ + default: error = n_tty_ioctl_helper(tty, file, cmd, arg); break; @@ -919,8 +948,7 @@ static struct n_hdlc_buf* n_hdlc_buf_get(struct n_hdlc_buf_list *list) } /* end of n_hdlc_buf_get() */ static char hdlc_banner[] __initdata = - KERN_INFO "HDLC line discipline: version " HDLC_VERSION - ", maxframe=%u\n"; + KERN_INFO "HDLC line discipline maxframe=%u\n"; static char hdlc_register_ok[] __initdata = KERN_INFO "N_HDLC line discipline registered.\n"; static char hdlc_register_fail[] __initdata = diff --git a/drivers/char/n_r3964.c b/drivers/char/n_r3964.c index d2e93e343226..2e99158ebb8a 100644 --- a/drivers/char/n_r3964.c +++ b/drivers/char/n_r3964.c @@ -1062,7 +1062,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file, struct r3964_client_info *pClient; struct r3964_message *pMsg; struct r3964_client_message theMsg; - int count; + int ret; TRACE_L("read()"); @@ -1074,8 +1074,8 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file, if (pMsg == NULL) { /* no messages available. */ if (file->f_flags & O_NONBLOCK) { - unlock_kernel(); - return -EAGAIN; + ret = -EAGAIN; + goto unlock; } /* block until there is a message: */ wait_event_interruptible(pInfo->read_wait, @@ -1085,29 +1085,31 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file, /* If we still haven't got a message, we must have been signalled */ if (!pMsg) { - unlock_kernel(); - return -EINTR; + ret = -EINTR; + goto unlock; } /* deliver msg to client process: */ theMsg.msg_id = pMsg->msg_id; theMsg.arg = pMsg->arg; theMsg.error_code = pMsg->error_code; - count = sizeof(struct r3964_client_message); + ret = sizeof(struct r3964_client_message); kfree(pMsg); TRACE_M("r3964_read - msg kfree %p", pMsg); - if (copy_to_user(buf, &theMsg, count)) { - unlock_kernel(); - return -EFAULT; + if (copy_to_user(buf, &theMsg, ret)) { + ret = -EFAULT; + goto unlock; } - TRACE_PS("read - return %d", count); - return count; + TRACE_PS("read - return %d", ret); + goto unlock; } + ret = -EPERM; +unlock: unlock_kernel(); - return -EPERM; + return ret; } static ssize_t r3964_write(struct tty_struct *tty, struct file *file, diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c index f6f0e4ec2b51..94a5d5020abc 100644 --- a/drivers/char/n_tty.c +++ b/drivers/char/n_tty.c @@ -73,24 +73,6 @@ #define ECHO_OP_SET_CANON_COL 0x81 #define ECHO_OP_ERASE_TAB 0x82 -static inline unsigned char *alloc_buf(void) -{ - gfp_t prio = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL; - - if (PAGE_SIZE != N_TTY_BUF_SIZE) - return kmalloc(N_TTY_BUF_SIZE, prio); - else - return (unsigned char *)__get_free_page(prio); -} - -static inline void free_buf(unsigned char *buf) -{ - if (PAGE_SIZE != N_TTY_BUF_SIZE) - kfree(buf); - else - free_page((unsigned long) buf); -} - static inline int tty_put_user(struct tty_struct *tty, unsigned char x, unsigned char __user *ptr) { @@ -1558,11 +1540,11 @@ static void n_tty_close(struct tty_struct *tty) { n_tty_flush_buffer(tty); if (tty->read_buf) { - free_buf(tty->read_buf); + kfree(tty->read_buf); tty->read_buf = NULL; } if (tty->echo_buf) { - free_buf(tty->echo_buf); + kfree(tty->echo_buf); tty->echo_buf = NULL; } } @@ -1584,17 +1566,16 @@ static int n_tty_open(struct tty_struct *tty) /* These are ugly. Currently a malloc failure here can panic */ if (!tty->read_buf) { - tty->read_buf = alloc_buf(); + tty->read_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL); if (!tty->read_buf) return -ENOMEM; } if (!tty->echo_buf) { - tty->echo_buf = alloc_buf(); + tty->echo_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL); + if (!tty->echo_buf) return -ENOMEM; } - memset(tty->read_buf, 0, N_TTY_BUF_SIZE); - memset(tty->echo_buf, 0, N_TTY_BUF_SIZE); reset_buffer_flags(tty); tty->column = 0; n_tty_set_termios(tty, NULL); diff --git a/drivers/char/nozomi.c b/drivers/char/nozomi.c index d6102b644b55..574f1c79b6e6 100644 --- a/drivers/char/nozomi.c +++ b/drivers/char/nozomi.c @@ -1591,8 +1591,6 @@ static int ntty_open(struct tty_struct *tty, struct file *file) /* Enable interrupt downlink for channel */ if (port->port.count == 1) { - /* FIXME: is this needed now ? */ - tty->low_latency = 1; tty->driver_data = port; tty_port_tty_set(&port->port, tty); DBG1("open: %d", port->token_dl); diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c index dbb912574569..881934c068c8 100644 --- a/drivers/char/pcmcia/cm4000_cs.c +++ b/drivers/char/pcmcia/cm4000_cs.c @@ -1575,7 +1575,8 @@ static long cmm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) clear_bit(LOCK_IO, &dev->flags); wake_up_interruptible(&dev->ioq); - return 0; + rc = 0; + break; case CM_IOCSPTS: { struct ptsreq krnptsreq; diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 19d79fc54461..77b364889224 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -383,7 +383,7 @@ static void async_mode(MGSLPC_INFO *info); static void tx_timeout(unsigned long context); static int carrier_raised(struct tty_port *port); -static void raise_dtr_rts(struct tty_port *port); +static void dtr_rts(struct tty_port *port, int onoff); #if SYNCLINK_GENERIC_HDLC #define dev_to_port(D) (dev_to_hdlc(D)->priv) @@ -513,7 +513,7 @@ static void ldisc_receive_buf(struct tty_struct *tty, static const struct tty_port_operations mgslpc_port_ops = { .carrier_raised = carrier_raised, - .raise_dtr_rts = raise_dtr_rts + .dtr_rts = dtr_rts }; static int mgslpc_probe(struct pcmcia_device *link) @@ -2528,13 +2528,16 @@ static int carrier_raised(struct tty_port *port) return 0; } -static void raise_dtr_rts(struct tty_port *port) +static void dtr_rts(struct tty_port *port, int onoff) { MGSLPC_INFO *info = container_of(port, MGSLPC_INFO, port); unsigned long flags; spin_lock_irqsave(&info->lock,flags); - info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR; + if (onoff) + info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR; + else + info->serial_signals &= ~SerialSignal_RTS + SerialSignal_DTR; set_signals(info); spin_unlock_irqrestore(&info->lock,flags); } diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c index c84c34fb1231..432655bcb04c 100644 --- a/drivers/char/ppdev.c +++ b/drivers/char/ppdev.c @@ -114,8 +114,7 @@ static ssize_t pp_read (struct file * file, char __user * buf, size_t count, if (!(pp->flags & PP_CLAIMED)) { /* Don't have the port claimed */ - printk (KERN_DEBUG CHRDEV "%x: claim the port first\n", - minor); + pr_debug(CHRDEV "%x: claim the port first\n", minor); return -EINVAL; } @@ -198,8 +197,7 @@ static ssize_t pp_write (struct file * file, const char __user * buf, if (!(pp->flags & PP_CLAIMED)) { /* Don't have the port claimed */ - printk (KERN_DEBUG CHRDEV "%x: claim the port first\n", - minor); + pr_debug(CHRDEV "%x: claim the port first\n", minor); return -EINVAL; } @@ -313,7 +311,7 @@ static int register_device (int minor, struct pp_struct *pp) } pp->pdev = pdev; - printk (KERN_DEBUG "%s: registered pardevice\n", name); + pr_debug("%s: registered pardevice\n", name); return 0; } @@ -343,8 +341,7 @@ static int pp_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg) int ret; if (pp->flags & PP_CLAIMED) { - printk (KERN_DEBUG CHRDEV - "%x: you've already got it!\n", minor); + pr_debug(CHRDEV "%x: you've already got it!\n", minor); return -EINVAL; } @@ -379,7 +376,7 @@ static int pp_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } case PPEXCL: if (pp->pdev) { - printk (KERN_DEBUG CHRDEV "%x: too late for PPEXCL; " + pr_debug(CHRDEV "%x: too late for PPEXCL; " "already registered\n", minor); if (pp->flags & PP_EXCL) /* But it's not really an error. */ @@ -491,8 +488,7 @@ static int pp_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg) /* Everything else requires the port to be claimed, so check * that now. */ if ((pp->flags & PP_CLAIMED) == 0) { - printk (KERN_DEBUG CHRDEV "%x: claim the port first\n", - minor); + pr_debug(CHRDEV "%x: claim the port first\n", minor); return -EINVAL; } @@ -624,8 +620,7 @@ static int pp_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return 0; default: - printk (KERN_DEBUG CHRDEV "%x: What? (cmd=0x%x)\n", minor, - cmd); + pr_debug(CHRDEV "%x: What? (cmd=0x%x)\n", minor, cmd); return -EINVAL; } @@ -698,9 +693,8 @@ static int pp_release (struct inode * inode, struct file * file) } if (compat_negot) { parport_negotiate (pp->pdev->port, IEEE1284_MODE_COMPAT); - printk (KERN_DEBUG CHRDEV - "%x: negotiated back to compatibility mode because " - "user-space forgot\n", minor); + pr_debug(CHRDEV "%x: negotiated back to compatibility " + "mode because user-space forgot\n", minor); } if (pp->flags & PP_CLAIMED) { @@ -713,7 +707,7 @@ static int pp_release (struct inode * inode, struct file * file) info->phase = pp->saved_state.phase; parport_release (pp->pdev); if (compat_negot != 1) { - printk (KERN_DEBUG CHRDEV "%x: released pardevice " + pr_debug(CHRDEV "%x: released pardevice " "because user-space forgot\n", minor); } } @@ -723,8 +717,7 @@ static int pp_release (struct inode * inode, struct file * file) parport_unregister_device (pp->pdev); kfree (name); pp->pdev = NULL; - printk (KERN_DEBUG CHRDEV "%x: unregistered pardevice\n", - minor); + pr_debug(CHRDEV "%x: unregistered pardevice\n", minor); } kfree (pp); diff --git a/drivers/char/ps3flash.c b/drivers/char/ps3flash.c index afbe45676d71..f424d394a286 100644 --- a/drivers/char/ps3flash.c +++ b/drivers/char/ps3flash.c @@ -33,48 +33,64 @@ struct ps3flash_private { struct mutex mutex; /* Bounce buffer mutex */ + u64 chunk_sectors; + int tag; /* Start sector of buffer, -1 if invalid */ + bool dirty; }; static struct ps3_storage_device *ps3flash_dev; -static ssize_t ps3flash_read_write_sectors(struct ps3_storage_device *dev, - u64 lpar, u64 start_sector, - u64 sectors, int write) +static int ps3flash_read_write_sectors(struct ps3_storage_device *dev, + u64 start_sector, int write) { - u64 res = ps3stor_read_write_sectors(dev, lpar, start_sector, sectors, + struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); + u64 res = ps3stor_read_write_sectors(dev, dev->bounce_lpar, + start_sector, priv->chunk_sectors, write); if (res) { dev_err(&dev->sbd.core, "%s:%u: %s failed 0x%llx\n", __func__, __LINE__, write ? "write" : "read", res); return -EIO; } - return sectors; + return 0; } -static ssize_t ps3flash_read_sectors(struct ps3_storage_device *dev, - u64 start_sector, u64 sectors, - unsigned int sector_offset) +static int ps3flash_writeback(struct ps3_storage_device *dev) { - u64 max_sectors, lpar; + struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); + int res; - max_sectors = dev->bounce_size / dev->blk_size; - if (sectors > max_sectors) { - dev_dbg(&dev->sbd.core, "%s:%u Limiting sectors to %llu\n", - __func__, __LINE__, max_sectors); - sectors = max_sectors; - } + if (!priv->dirty || priv->tag < 0) + return 0; - lpar = dev->bounce_lpar + sector_offset * dev->blk_size; - return ps3flash_read_write_sectors(dev, lpar, start_sector, sectors, - 0); + res = ps3flash_read_write_sectors(dev, priv->tag, 1); + if (res) + return res; + + priv->dirty = false; + return 0; } -static ssize_t ps3flash_write_chunk(struct ps3_storage_device *dev, - u64 start_sector) +static int ps3flash_fetch(struct ps3_storage_device *dev, u64 start_sector) { - u64 sectors = dev->bounce_size / dev->blk_size; - return ps3flash_read_write_sectors(dev, dev->bounce_lpar, start_sector, - sectors, 1); + struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); + int res; + + if (start_sector == priv->tag) + return 0; + + res = ps3flash_writeback(dev); + if (res) + return res; + + priv->tag = -1; + + res = ps3flash_read_write_sectors(dev, start_sector, 0); + if (res) + return res; + + priv->tag = start_sector; + return 0; } static loff_t ps3flash_llseek(struct file *file, loff_t offset, int origin) @@ -104,18 +120,19 @@ out: return res; } -static ssize_t ps3flash_read(struct file *file, char __user *buf, size_t count, - loff_t *pos) +static ssize_t ps3flash_read(char __user *userbuf, void *kernelbuf, + size_t count, loff_t *pos) { struct ps3_storage_device *dev = ps3flash_dev; - struct ps3flash_private *priv = dev->sbd.core.driver_data; - u64 size, start_sector, end_sector, offset; - ssize_t sectors_read; + struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); + u64 size, sector, offset; + int res; size_t remaining, n; + const void *src; dev_dbg(&dev->sbd.core, - "%s:%u: Reading %zu bytes at position %lld to user 0x%p\n", - __func__, __LINE__, count, *pos, buf); + "%s:%u: Reading %zu bytes at position %lld to U0x%p/K0x%p\n", + __func__, __LINE__, count, *pos, userbuf, kernelbuf); size = dev->regions[dev->region_idx].size*dev->blk_size; if (*pos >= size || !count) @@ -128,156 +145,40 @@ static ssize_t ps3flash_read(struct file *file, char __user *buf, size_t count, count = size - *pos; } - start_sector = *pos / dev->blk_size; - offset = *pos % dev->blk_size; - end_sector = DIV_ROUND_UP(*pos + count, dev->blk_size); - - remaining = count; - do { - mutex_lock(&priv->mutex); - - sectors_read = ps3flash_read_sectors(dev, start_sector, - end_sector-start_sector, - 0); - if (sectors_read < 0) { - mutex_unlock(&priv->mutex); - goto fail; - } - - n = min_t(u64, remaining, sectors_read*dev->blk_size-offset); - dev_dbg(&dev->sbd.core, - "%s:%u: copy %lu bytes from 0x%p to user 0x%p\n", - __func__, __LINE__, n, dev->bounce_buf+offset, buf); - if (copy_to_user(buf, dev->bounce_buf+offset, n)) { - mutex_unlock(&priv->mutex); - sectors_read = -EFAULT; - goto fail; - } - - mutex_unlock(&priv->mutex); - - *pos += n; - buf += n; - remaining -= n; - start_sector += sectors_read; - offset = 0; - } while (remaining > 0); - - return count; - -fail: - return sectors_read; -} - -static ssize_t ps3flash_write(struct file *file, const char __user *buf, - size_t count, loff_t *pos) -{ - struct ps3_storage_device *dev = ps3flash_dev; - struct ps3flash_private *priv = dev->sbd.core.driver_data; - u64 size, chunk_sectors, start_write_sector, end_write_sector, - end_read_sector, start_read_sector, head, tail, offset; - ssize_t res; - size_t remaining, n; - unsigned int sec_off; - - dev_dbg(&dev->sbd.core, - "%s:%u: Writing %zu bytes at position %lld from user 0x%p\n", - __func__, __LINE__, count, *pos, buf); - - size = dev->regions[dev->region_idx].size*dev->blk_size; - if (*pos >= size || !count) - return 0; - - if (*pos + count > size) { - dev_dbg(&dev->sbd.core, - "%s:%u Truncating count from %zu to %llu\n", __func__, - __LINE__, count, size - *pos); - count = size - *pos; - } - - chunk_sectors = dev->bounce_size / dev->blk_size; - - start_write_sector = *pos / dev->bounce_size * chunk_sectors; + sector = *pos / dev->bounce_size * priv->chunk_sectors; offset = *pos % dev->bounce_size; - end_write_sector = DIV_ROUND_UP(*pos + count, dev->bounce_size) * - chunk_sectors; - - end_read_sector = DIV_ROUND_UP(*pos, dev->blk_size); - start_read_sector = (*pos + count) / dev->blk_size; - - /* - * As we have to write in 256 KiB chunks, while we can read in blk_size - * (usually 512 bytes) chunks, we perform the following steps: - * 1. Read from start_write_sector to end_read_sector ("head") - * 2. Read from start_read_sector to end_write_sector ("tail") - * 3. Copy data to buffer - * 4. Write from start_write_sector to end_write_sector - * All of this is complicated by using only one 256 KiB bounce buffer. - */ - - head = end_read_sector - start_write_sector; - tail = end_write_sector - start_read_sector; remaining = count; do { + n = min_t(u64, remaining, dev->bounce_size - offset); + src = dev->bounce_buf + offset; + mutex_lock(&priv->mutex); - if (end_read_sector >= start_read_sector) { - /* Merge head and tail */ - dev_dbg(&dev->sbd.core, - "Merged head and tail: %llu sectors at %llu\n", - chunk_sectors, start_write_sector); - res = ps3flash_read_sectors(dev, start_write_sector, - chunk_sectors, 0); - if (res < 0) - goto fail; - } else { - if (head) { - /* Read head */ - dev_dbg(&dev->sbd.core, - "head: %llu sectors at %llu\n", head, - start_write_sector); - res = ps3flash_read_sectors(dev, - start_write_sector, - head, 0); - if (res < 0) - goto fail; - } - if (start_read_sector < - start_write_sector+chunk_sectors) { - /* Read tail */ - dev_dbg(&dev->sbd.core, - "tail: %llu sectors at %llu\n", tail, - start_read_sector); - sec_off = start_read_sector-start_write_sector; - res = ps3flash_read_sectors(dev, - start_read_sector, - tail, sec_off); - if (res < 0) - goto fail; - } - } + res = ps3flash_fetch(dev, sector); + if (res) + goto fail; - n = min_t(u64, remaining, dev->bounce_size-offset); dev_dbg(&dev->sbd.core, - "%s:%u: copy %lu bytes from user 0x%p to 0x%p\n", - __func__, __LINE__, n, buf, dev->bounce_buf+offset); - if (copy_from_user(dev->bounce_buf+offset, buf, n)) { - res = -EFAULT; - goto fail; + "%s:%u: copy %lu bytes from 0x%p to U0x%p/K0x%p\n", + __func__, __LINE__, n, src, userbuf, kernelbuf); + if (userbuf) { + if (copy_to_user(userbuf, src, n)) { + res = -EFAULT; + goto fail; + } + userbuf += n; + } + if (kernelbuf) { + memcpy(kernelbuf, src, n); + kernelbuf += n; } - - res = ps3flash_write_chunk(dev, start_write_sector); - if (res < 0) - goto fail; mutex_unlock(&priv->mutex); *pos += n; - buf += n; remaining -= n; - start_write_sector += chunk_sectors; - head = 0; + sector += priv->chunk_sectors; offset = 0; } while (remaining > 0); @@ -288,6 +189,126 @@ fail: return res; } +static ssize_t ps3flash_write(const char __user *userbuf, + const void *kernelbuf, size_t count, loff_t *pos) +{ + struct ps3_storage_device *dev = ps3flash_dev; + struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); + u64 size, sector, offset; + int res = 0; + size_t remaining, n; + void *dst; + + dev_dbg(&dev->sbd.core, + "%s:%u: Writing %zu bytes at position %lld from U0x%p/K0x%p\n", + __func__, __LINE__, count, *pos, userbuf, kernelbuf); + + size = dev->regions[dev->region_idx].size*dev->blk_size; + if (*pos >= size || !count) + return 0; + + if (*pos + count > size) { + dev_dbg(&dev->sbd.core, + "%s:%u Truncating count from %zu to %llu\n", __func__, + __LINE__, count, size - *pos); + count = size - *pos; + } + + sector = *pos / dev->bounce_size * priv->chunk_sectors; + offset = *pos % dev->bounce_size; + + remaining = count; + do { + n = min_t(u64, remaining, dev->bounce_size - offset); + dst = dev->bounce_buf + offset; + + mutex_lock(&priv->mutex); + + if (n != dev->bounce_size) + res = ps3flash_fetch(dev, sector); + else if (sector != priv->tag) + res = ps3flash_writeback(dev); + if (res) + goto fail; + + dev_dbg(&dev->sbd.core, + "%s:%u: copy %lu bytes from U0x%p/K0x%p to 0x%p\n", + __func__, __LINE__, n, userbuf, kernelbuf, dst); + if (userbuf) { + if (copy_from_user(dst, userbuf, n)) { + res = -EFAULT; + goto fail; + } + userbuf += n; + } + if (kernelbuf) { + memcpy(dst, kernelbuf, n); + kernelbuf += n; + } + + priv->tag = sector; + priv->dirty = true; + + mutex_unlock(&priv->mutex); + + *pos += n; + remaining -= n; + sector += priv->chunk_sectors; + offset = 0; + } while (remaining > 0); + + return count; + +fail: + mutex_unlock(&priv->mutex); + return res; +} + +static ssize_t ps3flash_user_read(struct file *file, char __user *buf, + size_t count, loff_t *pos) +{ + return ps3flash_read(buf, NULL, count, pos); +} + +static ssize_t ps3flash_user_write(struct file *file, const char __user *buf, + size_t count, loff_t *pos) +{ + return ps3flash_write(buf, NULL, count, pos); +} + +static ssize_t ps3flash_kernel_read(void *buf, size_t count, loff_t pos) +{ + return ps3flash_read(NULL, buf, count, &pos); +} + +static ssize_t ps3flash_kernel_write(const void *buf, size_t count, + loff_t pos) +{ + ssize_t res; + int wb; + + res = ps3flash_write(NULL, buf, count, &pos); + if (res < 0) + return res; + + /* Make kernel writes synchronous */ + wb = ps3flash_writeback(ps3flash_dev); + if (wb) + return wb; + + return res; +} + +static int ps3flash_flush(struct file *file, fl_owner_t id) +{ + return ps3flash_writeback(ps3flash_dev); +} + +static int ps3flash_fsync(struct file *file, struct dentry *dentry, + int datasync) +{ + return ps3flash_writeback(ps3flash_dev); +} static irqreturn_t ps3flash_interrupt(int irq, void *data) { @@ -312,12 +333,18 @@ static irqreturn_t ps3flash_interrupt(int irq, void *data) return IRQ_HANDLED; } - static const struct file_operations ps3flash_fops = { .owner = THIS_MODULE, .llseek = ps3flash_llseek, - .read = ps3flash_read, - .write = ps3flash_write, + .read = ps3flash_user_read, + .write = ps3flash_user_write, + .flush = ps3flash_flush, + .fsync = ps3flash_fsync, +}; + +static const struct ps3_os_area_flash_ops ps3flash_kernel_ops = { + .read = ps3flash_kernel_read, + .write = ps3flash_kernel_write, }; static struct miscdevice ps3flash_misc = { @@ -366,11 +393,13 @@ static int __devinit ps3flash_probe(struct ps3_system_bus_device *_dev) goto fail; } - dev->sbd.core.driver_data = priv; + ps3_system_bus_set_drvdata(&dev->sbd, priv); mutex_init(&priv->mutex); + priv->tag = -1; dev->bounce_size = ps3flash_bounce_buffer.size; dev->bounce_buf = ps3flash_bounce_buffer.address; + priv->chunk_sectors = dev->bounce_size / dev->blk_size; error = ps3stor_setup(dev, ps3flash_interrupt); if (error) @@ -386,13 +415,15 @@ static int __devinit ps3flash_probe(struct ps3_system_bus_device *_dev) dev_info(&dev->sbd.core, "%s:%u: registered misc device %d\n", __func__, __LINE__, ps3flash_misc.minor); + + ps3_os_area_flash_register(&ps3flash_kernel_ops); return 0; fail_teardown: ps3stor_teardown(dev); fail_free_priv: kfree(priv); - dev->sbd.core.driver_data = NULL; + ps3_system_bus_set_drvdata(&dev->sbd, NULL); fail: ps3flash_dev = NULL; return error; @@ -402,10 +433,11 @@ static int ps3flash_remove(struct ps3_system_bus_device *_dev) { struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core); + ps3_os_area_flash_register(NULL); misc_deregister(&ps3flash_misc); ps3stor_teardown(dev); - kfree(dev->sbd.core.driver_data); - dev->sbd.core.driver_data = NULL; + kfree(ps3_system_bus_get_drvdata(&dev->sbd)); + ps3_system_bus_set_drvdata(&dev->sbd, NULL); ps3flash_dev = NULL; return 0; } diff --git a/drivers/char/pty.c b/drivers/char/pty.c index 31038a0052a2..daebe1ba43d4 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c @@ -30,7 +30,6 @@ #include -/* These are global because they are accessed in tty_io.c */ #ifdef CONFIG_UNIX98_PTYS static struct tty_driver *ptm_driver; static struct tty_driver *pts_driver; @@ -96,23 +95,34 @@ static void pty_unthrottle(struct tty_struct *tty) * a count. * * FIXME: Our pty_write method is called with our ldisc lock held but - * not our partners. We can't just take the other one blindly without - * risking deadlocks. + * not our partners. We can't just wait on the other one blindly without + * risking deadlocks. At some point when everything has settled down we need + * to look into making pty_write at least able to sleep over an ldisc change. + * + * The return on no ldisc is a bit counter intuitive but the logic works + * like this. During an ldisc change the other end will flush its buffers. We + * thus return the full length which is identical to the case where we had + * proper locking and happened to queue the bytes just before the flush during + * the ldisc change. */ static int pty_write(struct tty_struct *tty, const unsigned char *buf, int count) { struct tty_struct *to = tty->link; - int c; + struct tty_ldisc *ld; + int c = count; if (!to || tty->stopped) return 0; + ld = tty_ldisc_ref(to); - c = to->receive_room; - if (c > count) - c = count; - to->ldisc.ops->receive_buf(to, buf, NULL, c); - + if (ld) { + c = to->receive_room; + if (c > count) + c = count; + ld->ops->receive_buf(to, buf, NULL, c); + tty_ldisc_deref(ld); + } return c; } @@ -146,14 +156,23 @@ static int pty_write_room(struct tty_struct *tty) static int pty_chars_in_buffer(struct tty_struct *tty) { struct tty_struct *to = tty->link; - int count; + struct tty_ldisc *ld; + int count = 0; /* We should get the line discipline lock for "tty->link" */ - if (!to || !to->ldisc.ops->chars_in_buffer) + if (!to) + return 0; + /* We cannot take a sleeping reference here without deadlocking with + an ldisc change - but it doesn't really matter */ + ld = tty_ldisc_ref(to); + if (ld == NULL) return 0; /* The ldisc must report 0 if no characters available to be read */ - count = to->ldisc.ops->chars_in_buffer(to); + if (ld->ops->chars_in_buffer) + count = ld->ops->chars_in_buffer(to); + + tty_ldisc_deref(ld); if (tty->driver->subtype == PTY_TYPE_SLAVE) return count; @@ -183,12 +202,19 @@ static void pty_flush_buffer(struct tty_struct *tty) { struct tty_struct *to = tty->link; unsigned long flags; + struct tty_ldisc *ld; if (!to) return; + ld = tty_ldisc_ref(to); - if (to->ldisc.ops->flush_buffer) - to->ldisc.ops->flush_buffer(to); + /* The other end is changing discipline */ + if (!ld) + return; + + if (ld->ops->flush_buffer) + to->ldisc->ops->flush_buffer(to); + tty_ldisc_deref(ld); if (to->packet) { spin_lock_irqsave(&tty->ctrl_lock, flags); diff --git a/drivers/char/raw.c b/drivers/char/raw.c index 20d90e6a6e50..05f9d18b9361 100644 --- a/drivers/char/raw.c +++ b/drivers/char/raw.c @@ -71,7 +71,7 @@ static int raw_open(struct inode *inode, struct file *filp) err = bd_claim(bdev, raw_open); if (err) goto out1; - err = set_blocksize(bdev, bdev_hardsect_size(bdev)); + err = set_blocksize(bdev, bdev_logical_block_size(bdev)); if (err) goto out2; filp->f_flags |= O_DIRECT; @@ -261,6 +261,11 @@ static const struct file_operations raw_ctl_fops = { static struct cdev raw_cdev; +static char *raw_nodename(struct device *dev) +{ + return kasprintf(GFP_KERNEL, "raw/%s", dev_name(dev)); +} + static int __init raw_init(void) { dev_t dev = MKDEV(RAW_MAJOR, 0); @@ -284,6 +289,7 @@ static int __init raw_init(void) ret = PTR_ERR(raw_class); goto error_region; } + raw_class->nodename = raw_nodename; device_create(raw_class, NULL, MKDEV(RAW_MAJOR, 0), NULL, "rawctl"); return 0; diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c index f59fc5cea067..63d5b628477a 100644 --- a/drivers/char/rocket.c +++ b/drivers/char/rocket.c @@ -872,11 +872,16 @@ static int carrier_raised(struct tty_port *port) return (sGetChanStatusLo(&info->channel) & CD_ACT) ? 1 : 0; } -static void raise_dtr_rts(struct tty_port *port) +static void dtr_rts(struct tty_port *port, int on) { struct r_port *info = container_of(port, struct r_port, port); - sSetDTR(&info->channel); - sSetRTS(&info->channel); + if (on) { + sSetDTR(&info->channel); + sSetRTS(&info->channel); + } else { + sClrDTR(&info->channel); + sClrRTS(&info->channel); + } } /* @@ -934,7 +939,7 @@ static int rp_open(struct tty_struct *tty, struct file *filp) /* * Info->count is now 1; so it's safe to sleep now. */ - if (!test_bit(ASYNC_INITIALIZED, &port->flags)) { + if (!test_bit(ASYNCB_INITIALIZED, &port->flags)) { cp = &info->channel; sSetRxTrigger(cp, TRIG_1); if (sGetChanStatus(cp) & CD_ACT) @@ -958,7 +963,7 @@ static int rp_open(struct tty_struct *tty, struct file *filp) sEnRxFIFO(cp); sEnTransmit(cp); - set_bit(ASYNC_INITIALIZED, &info->port.flags); + set_bit(ASYNCB_INITIALIZED, &info->port.flags); /* * Set up the tty->alt_speed kludge @@ -1641,7 +1646,7 @@ static int rp_write(struct tty_struct *tty, /* Write remaining data into the port's xmit_buf */ while (1) { /* Hung up ? */ - if (!test_bit(ASYNC_NORMAL_ACTIVE, &info->port.flags)) + if (!test_bit(ASYNCB_NORMAL_ACTIVE, &info->port.flags)) goto end; c = min(count, XMIT_BUF_SIZE - info->xmit_cnt - 1); c = min(c, XMIT_BUF_SIZE - info->xmit_head); @@ -2250,7 +2255,7 @@ static const struct tty_operations rocket_ops = { static const struct tty_port_operations rocket_port_ops = { .carrier_raised = carrier_raised, - .raise_dtr_rts = raise_dtr_rts, + .dtr_rts = dtr_rts, }; /* diff --git a/drivers/char/selection.c b/drivers/char/selection.c index cb8ca5698963..f97b9e848064 100644 --- a/drivers/char/selection.c +++ b/drivers/char/selection.c @@ -327,7 +327,7 @@ int paste_selection(struct tty_struct *tty) } count = sel_buffer_lth - pasted; count = min(count, tty->receive_room); - tty->ldisc.ops->receive_buf(tty, sel_buffer + pasted, + tty->ldisc->ops->receive_buf(tty, sel_buffer + pasted, NULL, count); pasted += count; } diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c index 2ad813a801dc..53e504f41b20 100644 --- a/drivers/char/stallion.c +++ b/drivers/char/stallion.c @@ -772,11 +772,11 @@ static int stl_carrier_raised(struct tty_port *port) return (portp->sigs & TIOCM_CD) ? 1 : 0; } -static void stl_raise_dtr_rts(struct tty_port *port) +static void stl_dtr_rts(struct tty_port *port, int on) { struct stlport *portp = container_of(port, struct stlport, port); /* Takes brd_lock internally */ - stl_setsignals(portp, 1, 1); + stl_setsignals(portp, on, on); } /*****************************************************************************/ @@ -2547,7 +2547,7 @@ static const struct tty_operations stl_ops = { static const struct tty_port_operations stl_port_ops = { .carrier_raised = stl_carrier_raised, - .raise_dtr_rts = stl_raise_dtr_rts, + .dtr_rts = stl_dtr_rts, }; /*****************************************************************************/ diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c index afd0b26ca056..afded3a2379c 100644 --- a/drivers/char/synclink.c +++ b/drivers/char/synclink.c @@ -3247,13 +3247,16 @@ static int carrier_raised(struct tty_port *port) return (info->serial_signals & SerialSignal_DCD) ? 1 : 0; } -static void raise_dtr_rts(struct tty_port *port) +static void dtr_rts(struct tty_port *port, int on) { struct mgsl_struct *info = container_of(port, struct mgsl_struct, port); unsigned long flags; spin_lock_irqsave(&info->irq_spinlock,flags); - info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR; + if (on) + info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR; + else + info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR); usc_set_serial_signals(info); spin_unlock_irqrestore(&info->irq_spinlock,flags); } @@ -4258,7 +4261,7 @@ static void mgsl_add_device( struct mgsl_struct *info ) static const struct tty_port_operations mgsl_port_ops = { .carrier_raised = carrier_raised, - .raise_dtr_rts = raise_dtr_rts, + .dtr_rts = dtr_rts, }; diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c index 5e256494686a..a2e67e6df3a1 100644 --- a/drivers/char/synclink_gt.c +++ b/drivers/char/synclink_gt.c @@ -214,6 +214,7 @@ struct slgt_desc #define set_desc_next(a,b) (a).next = cpu_to_le32((unsigned int)(b)) #define set_desc_count(a,b)(a).count = cpu_to_le16((unsigned short)(b)) #define set_desc_eof(a,b) (a).status = cpu_to_le16((b) ? (le16_to_cpu((a).status) | BIT0) : (le16_to_cpu((a).status) & ~BIT0)) +#define set_desc_status(a, b) (a).status = cpu_to_le16((unsigned short)(b)) #define desc_count(a) (le16_to_cpu((a).count)) #define desc_status(a) (le16_to_cpu((a).status)) #define desc_complete(a) (le16_to_cpu((a).status) & BIT15) @@ -297,6 +298,7 @@ struct slgt_info { u32 max_frame_size; /* as set by device config */ unsigned int rbuf_fill_level; + unsigned int rx_pio; unsigned int if_mode; unsigned int base_clock; @@ -331,6 +333,8 @@ struct slgt_info { struct slgt_desc *rbufs; unsigned int rbuf_current; unsigned int rbuf_index; + unsigned int rbuf_fill_index; + unsigned short rbuf_fill_count; unsigned int tbuf_count; struct slgt_desc *tbufs; @@ -463,7 +467,6 @@ static unsigned int free_tbuf_count(struct slgt_info *info); static unsigned int tbuf_bytes(struct slgt_info *info); static void reset_tbufs(struct slgt_info *info); static void tdma_reset(struct slgt_info *info); -static void tdma_start(struct slgt_info *info); static void tx_load(struct slgt_info *info, const char *buf, unsigned int count); static void get_signals(struct slgt_info *info); @@ -791,6 +794,18 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios) } } +static void update_tx_timer(struct slgt_info *info) +{ + /* + * use worst case speed of 1200bps to calculate transmit timeout + * based on data in buffers (tbuf_bytes) and FIFO (128 bytes) + */ + if (info->params.mode == MGSL_MODE_HDLC) { + int timeout = (tbuf_bytes(info) * 7) + 1000; + mod_timer(&info->tx_timer, jiffies + msecs_to_jiffies(timeout)); + } +} + static int write(struct tty_struct *tty, const unsigned char *buf, int count) { @@ -834,8 +849,18 @@ start: spin_lock_irqsave(&info->lock,flags); if (!info->tx_active) tx_start(info); - else - tdma_start(info); + else if (!(rd_reg32(info, TDCSR) & BIT0)) { + /* transmit still active but transmit DMA stopped */ + unsigned int i = info->tbuf_current; + if (!i) + i = info->tbuf_count; + i--; + /* if DMA buf unsent must try later after tx idle */ + if (desc_count(info->tbufs[i])) + ret = 0; + } + if (ret > 0) + update_tx_timer(info); spin_unlock_irqrestore(&info->lock,flags); } @@ -1498,10 +1523,9 @@ static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev) /* save start time for transmit timeout detection */ dev->trans_start = jiffies; - /* start hardware transmitter if necessary */ spin_lock_irqsave(&info->lock,flags); - if (!info->tx_active) - tx_start(info); + tx_start(info); + update_tx_timer(info); spin_unlock_irqrestore(&info->lock,flags); return 0; @@ -2110,6 +2134,40 @@ static void ri_change(struct slgt_info *info, unsigned short status) info->pending_bh |= BH_STATUS; } +static void isr_rxdata(struct slgt_info *info) +{ + unsigned int count = info->rbuf_fill_count; + unsigned int i = info->rbuf_fill_index; + unsigned short reg; + + while (rd_reg16(info, SSR) & IRQ_RXDATA) { + reg = rd_reg16(info, RDR); + DBGISR(("isr_rxdata %s RDR=%04X\n", info->device_name, reg)); + if (desc_complete(info->rbufs[i])) { + /* all buffers full */ + rx_stop(info); + info->rx_restart = 1; + continue; + } + info->rbufs[i].buf[count++] = (unsigned char)reg; + /* async mode saves status byte to buffer for each data byte */ + if (info->params.mode == MGSL_MODE_ASYNC) + info->rbufs[i].buf[count++] = (unsigned char)(reg >> 8); + if (count == info->rbuf_fill_level || (reg & BIT10)) { + /* buffer full or end of frame */ + set_desc_count(info->rbufs[i], count); + set_desc_status(info->rbufs[i], BIT15 | (reg >> 8)); + info->rbuf_fill_count = count = 0; + if (++i == info->rbuf_count) + i = 0; + info->pending_bh |= BH_RECEIVE; + } + } + + info->rbuf_fill_index = i; + info->rbuf_fill_count = count; +} + static void isr_serial(struct slgt_info *info) { unsigned short status = rd_reg16(info, SSR); @@ -2125,6 +2183,8 @@ static void isr_serial(struct slgt_info *info) if (info->tx_count) isr_txeom(info, status); } + if (info->rx_pio && (status & IRQ_RXDATA)) + isr_rxdata(info); if ((status & IRQ_RXBREAK) && (status & RXBREAK)) { info->icount.brk++; /* process break detection if tty control allows */ @@ -2141,7 +2201,8 @@ static void isr_serial(struct slgt_info *info) } else { if (status & (IRQ_TXIDLE + IRQ_TXUNDER)) isr_txeom(info, status); - + if (info->rx_pio && (status & IRQ_RXDATA)) + isr_rxdata(info); if (status & IRQ_RXIDLE) { if (status & RXIDLE) info->icount.rxidle++; @@ -2642,6 +2703,10 @@ static int rx_enable(struct slgt_info *info, int enable) return -EINVAL; } info->rbuf_fill_level = rbuf_fill_level; + if (rbuf_fill_level < 128) + info->rx_pio = 1; /* PIO mode */ + else + info->rx_pio = 0; /* DMA mode */ rx_stop(info); /* restart receiver to use new fill level */ } @@ -3099,13 +3164,16 @@ static int carrier_raised(struct tty_port *port) return (info->signals & SerialSignal_DCD) ? 1 : 0; } -static void raise_dtr_rts(struct tty_port *port) +static void dtr_rts(struct tty_port *port, int on) { unsigned long flags; struct slgt_info *info = container_of(port, struct slgt_info, port); spin_lock_irqsave(&info->lock,flags); - info->signals |= SerialSignal_RTS + SerialSignal_DTR; + if (on) + info->signals |= SerialSignal_RTS + SerialSignal_DTR; + else + info->signals &= ~(SerialSignal_RTS + SerialSignal_DTR); set_signals(info); spin_unlock_irqrestore(&info->lock,flags); } @@ -3419,7 +3487,7 @@ static void add_device(struct slgt_info *info) static const struct tty_port_operations slgt_port_ops = { .carrier_raised = carrier_raised, - .raise_dtr_rts = raise_dtr_rts, + .dtr_rts = dtr_rts, }; /* @@ -3841,15 +3909,27 @@ static void rx_start(struct slgt_info *info) rdma_reset(info); reset_rbufs(info); - /* set 1st descriptor address */ - wr_reg32(info, RDDAR, info->rbufs[0].pdesc); - - if (info->params.mode != MGSL_MODE_ASYNC) { - /* enable rx DMA and DMA interrupt */ - wr_reg32(info, RDCSR, (BIT2 + BIT0)); + if (info->rx_pio) { + /* rx request when rx FIFO not empty */ + wr_reg16(info, SCR, (unsigned short)(rd_reg16(info, SCR) & ~BIT14)); + slgt_irq_on(info, IRQ_RXDATA); + if (info->params.mode == MGSL_MODE_ASYNC) { + /* enable saving of rx status */ + wr_reg32(info, RDCSR, BIT6); + } } else { - /* enable saving of rx status, rx DMA and DMA interrupt */ - wr_reg32(info, RDCSR, (BIT6 + BIT2 + BIT0)); + /* rx request when rx FIFO half full */ + wr_reg16(info, SCR, (unsigned short)(rd_reg16(info, SCR) | BIT14)); + /* set 1st descriptor address */ + wr_reg32(info, RDDAR, info->rbufs[0].pdesc); + + if (info->params.mode != MGSL_MODE_ASYNC) { + /* enable rx DMA and DMA interrupt */ + wr_reg32(info, RDCSR, (BIT2 + BIT0)); + } else { + /* enable saving of rx status, rx DMA and DMA interrupt */ + wr_reg32(info, RDCSR, (BIT6 + BIT2 + BIT0)); + } } slgt_irq_on(info, IRQ_RXOVER); @@ -3886,50 +3966,19 @@ static void tx_start(struct slgt_info *info) slgt_irq_on(info, IRQ_TXUNDER + IRQ_TXIDLE); /* clear tx idle and underrun status bits */ wr_reg16(info, SSR, (unsigned short)(IRQ_TXIDLE + IRQ_TXUNDER)); - if (info->params.mode == MGSL_MODE_HDLC) - mod_timer(&info->tx_timer, jiffies + - msecs_to_jiffies(5000)); } else { slgt_irq_off(info, IRQ_TXDATA); slgt_irq_on(info, IRQ_TXIDLE); /* clear tx idle status bit */ wr_reg16(info, SSR, IRQ_TXIDLE); } - tdma_start(info); + /* set 1st descriptor address and start DMA */ + wr_reg32(info, TDDAR, info->tbufs[info->tbuf_start].pdesc); + wr_reg32(info, TDCSR, BIT2 + BIT0); info->tx_active = true; } } -/* - * start transmit DMA if inactive and there are unsent buffers - */ -static void tdma_start(struct slgt_info *info) -{ - unsigned int i; - - if (rd_reg32(info, TDCSR) & BIT0) - return; - - /* transmit DMA inactive, check for unsent buffers */ - i = info->tbuf_start; - while (!desc_count(info->tbufs[i])) { - if (++i == info->tbuf_count) - i = 0; - if (i == info->tbuf_current) - return; - } - info->tbuf_start = i; - - /* there are unsent buffers, start transmit DMA */ - - /* reset needed if previous error condition */ - tdma_reset(info); - - /* set 1st descriptor address */ - wr_reg32(info, TDDAR, info->tbufs[info->tbuf_start].pdesc); - wr_reg32(info, TDCSR, BIT2 + BIT0); /* IRQ + DMA enable */ -} - static void tx_stop(struct slgt_info *info) { unsigned short val; @@ -4467,6 +4516,8 @@ static void free_rbufs(struct slgt_info *info, unsigned int i, unsigned int last static void reset_rbufs(struct slgt_info *info) { free_rbufs(info, 0, info->rbuf_count - 1); + info->rbuf_fill_index = 0; + info->rbuf_fill_count = 0; } /* @@ -4942,8 +4993,7 @@ static void tx_timeout(unsigned long context) info->icount.txtimeout++; } spin_lock_irqsave(&info->lock,flags); - info->tx_active = false; - info->tx_count = 0; + tx_stop(info); spin_unlock_irqrestore(&info->lock,flags); #if SYNCLINK_GENERIC_HDLC diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c index 26de60efe4b2..6f727e3c53ad 100644 --- a/drivers/char/synclinkmp.c +++ b/drivers/char/synclinkmp.c @@ -3277,13 +3277,16 @@ static int carrier_raised(struct tty_port *port) return (info->serial_signals & SerialSignal_DCD) ? 1 : 0; } -static void raise_dtr_rts(struct tty_port *port) +static void dtr_rts(struct tty_port *port, int on) { SLMP_INFO *info = container_of(port, SLMP_INFO, port); unsigned long flags; spin_lock_irqsave(&info->lock,flags); - info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR; + if (on) + info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR; + else + info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR); set_signals(info); spin_unlock_irqrestore(&info->lock,flags); } @@ -3746,7 +3749,7 @@ static void add_device(SLMP_INFO *info) static const struct tty_port_operations port_ops = { .carrier_raised = carrier_raised, - .raise_dtr_rts = raise_dtr_rts, + .dtr_rts = dtr_rts, }; /* Allocate and initialize a device instance structure diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c index d6a807f4077d..0db35857e4d8 100644 --- a/drivers/char/sysrq.c +++ b/drivers/char/sysrq.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -120,20 +121,17 @@ static struct sysrq_key_op sysrq_unraw_op = { #define sysrq_unraw_op (*(struct sysrq_key_op *)0) #endif /* CONFIG_VT */ -#ifdef CONFIG_KEXEC -static void sysrq_handle_crashdump(int key, struct tty_struct *tty) +static void sysrq_handle_crash(int key, struct tty_struct *tty) { - crash_kexec(get_irq_regs()); + char *killer = NULL; + *killer = 1; } static struct sysrq_key_op sysrq_crashdump_op = { - .handler = sysrq_handle_crashdump, - .help_msg = "Crashdump", - .action_msg = "Trigger a crashdump", + .handler = sysrq_handle_crash, + .help_msg = "Crash", + .action_msg = "Trigger a crash", .enable_mask = SYSRQ_ENABLE_DUMP, }; -#else -#define sysrq_crashdump_op (*(struct sysrq_key_op *)0) -#endif static void sysrq_handle_reboot(int key, struct tty_struct *tty) { @@ -243,6 +241,7 @@ static void sysrq_handle_showregs(int key, struct tty_struct *tty) struct pt_regs *regs = get_irq_regs(); if (regs) show_regs(regs); + perf_counter_print_debug(); } static struct sysrq_key_op sysrq_showregs_op = { .handler = sysrq_handle_showregs, diff --git a/drivers/char/tty_audit.c b/drivers/char/tty_audit.c index 55ba6f142883..ac16fbec72d0 100644 --- a/drivers/char/tty_audit.c +++ b/drivers/char/tty_audit.c @@ -29,10 +29,7 @@ static struct tty_audit_buf *tty_audit_buf_alloc(int major, int minor, buf = kmalloc(sizeof(*buf), GFP_KERNEL); if (!buf) goto err; - if (PAGE_SIZE != N_TTY_BUF_SIZE) - buf->data = kmalloc(N_TTY_BUF_SIZE, GFP_KERNEL); - else - buf->data = (unsigned char *)__get_free_page(GFP_KERNEL); + buf->data = kmalloc(N_TTY_BUF_SIZE, GFP_KERNEL); if (!buf->data) goto err_buf; atomic_set(&buf->count, 1); @@ -52,10 +49,7 @@ err: static void tty_audit_buf_free(struct tty_audit_buf *buf) { WARN_ON(buf->valid != 0); - if (PAGE_SIZE != N_TTY_BUF_SIZE) - kfree(buf->data); - else - free_page((unsigned long)buf->data); + kfree(buf->data); kfree(buf); } diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 66b99a2049e3..a3afa0c387cd 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -295,7 +295,7 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line) struct tty_driver *p, *res = NULL; int tty_line = 0; int len; - char *str; + char *str, *stp; for (str = name; *str; str++) if ((*str >= '0' && *str <= '9') || *str == ',') @@ -311,13 +311,14 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line) list_for_each_entry(p, &tty_drivers, tty_drivers) { if (strncmp(name, p->name, len) != 0) continue; - if (*str == ',') - str++; - if (*str == '\0') - str = NULL; + stp = str; + if (*stp == ',') + stp++; + if (*stp == '\0') + stp = NULL; if (tty_line >= 0 && tty_line <= p->num && p->ops && - p->ops->poll_init && !p->ops->poll_init(p, tty_line, str)) { + p->ops->poll_init && !p->ops->poll_init(p, tty_line, stp)) { res = tty_driver_kref_get(p); *line = tty_line; break; @@ -469,43 +470,6 @@ void tty_wakeup(struct tty_struct *tty) EXPORT_SYMBOL_GPL(tty_wakeup); -/** - * tty_ldisc_flush - flush line discipline queue - * @tty: tty - * - * Flush the line discipline queue (if any) for this tty. If there - * is no line discipline active this is a no-op. - */ - -void tty_ldisc_flush(struct tty_struct *tty) -{ - struct tty_ldisc *ld = tty_ldisc_ref(tty); - if (ld) { - if (ld->ops->flush_buffer) - ld->ops->flush_buffer(tty); - tty_ldisc_deref(ld); - } - tty_buffer_flush(tty); -} - -EXPORT_SYMBOL_GPL(tty_ldisc_flush); - -/** - * tty_reset_termios - reset terminal state - * @tty: tty to reset - * - * Restore a terminal to the driver default state - */ - -static void tty_reset_termios(struct tty_struct *tty) -{ - mutex_lock(&tty->termios_mutex); - *tty->termios = tty->driver->init_termios; - tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios); - tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios); - mutex_unlock(&tty->termios_mutex); -} - /** * do_tty_hangup - actual handler for hangup events * @work: tty device @@ -535,7 +499,6 @@ static void do_tty_hangup(struct work_struct *work) struct file *cons_filp = NULL; struct file *filp, *f = NULL; struct task_struct *p; - struct tty_ldisc *ld; int closecount = 0, n; unsigned long flags; int refs = 0; @@ -566,40 +529,8 @@ static void do_tty_hangup(struct work_struct *work) filp->f_op = &hung_up_tty_fops; } file_list_unlock(); - /* - * FIXME! What are the locking issues here? This may me overdoing - * things... This question is especially important now that we've - * removed the irqlock. - */ - ld = tty_ldisc_ref(tty); - if (ld != NULL) { - /* We may have no line discipline at this point */ - 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->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 - * ldisc completion and fix the driver call race - */ - wake_up_interruptible_poll(&tty->write_wait, POLLOUT); - wake_up_interruptible_poll(&tty->read_wait, POLLIN); - /* - * Shutdown the current line discipline, and reset it to - * N_TTY. - */ - if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) - tty_reset_termios(tty); - /* Defer ldisc switch */ - /* tty_deferred_ldisc_switch(N_TTY); - This should get done automatically when the port closes and - tty_release is called */ + tty_ldisc_hangup(tty); read_lock(&tasklist_lock); if (tty->session) { @@ -628,12 +559,15 @@ static void do_tty_hangup(struct work_struct *work) read_unlock(&tasklist_lock); spin_lock_irqsave(&tty->ctrl_lock, flags); - tty->flags = 0; + clear_bit(TTY_THROTTLED, &tty->flags); + clear_bit(TTY_PUSH, &tty->flags); + clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); put_pid(tty->session); put_pid(tty->pgrp); tty->session = NULL; tty->pgrp = NULL; tty->ctrl_status = 0; + set_bit(TTY_HUPPED, &tty->flags); spin_unlock_irqrestore(&tty->ctrl_lock, flags); /* Account for the p->signal references we killed */ @@ -659,10 +593,7 @@ static void do_tty_hangup(struct work_struct *work) * can't yet guarantee all that. */ set_bit(TTY_HUPPED, &tty->flags); - if (ld) { - tty_ldisc_enable(tty); - tty_ldisc_deref(ld); - } + tty_ldisc_enable(tty); unlock_kernel(); if (f) fput(f); @@ -1332,7 +1263,9 @@ static int tty_reopen(struct tty_struct *tty) tty->count++; tty->driver = driver; /* N.B. why do this every time?? */ + mutex_lock(&tty->ldisc_mutex); WARN_ON(!test_bit(TTY_LDISC, &tty->flags)); + mutex_unlock(&tty->ldisc_mutex); return 0; } @@ -2480,6 +2413,24 @@ static int tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int return tty->ops->tiocmset(tty, file, set, clear); } +struct tty_struct *tty_pair_get_tty(struct tty_struct *tty) +{ + if (tty->driver->type == TTY_DRIVER_TYPE_PTY && + tty->driver->subtype == PTY_TYPE_MASTER) + tty = tty->link; + return tty; +} +EXPORT_SYMBOL(tty_pair_get_tty); + +struct tty_struct *tty_pair_get_pty(struct tty_struct *tty) +{ + if (tty->driver->type == TTY_DRIVER_TYPE_PTY && + tty->driver->subtype == PTY_TYPE_MASTER) + return tty; + return tty->link; +} +EXPORT_SYMBOL(tty_pair_get_pty); + /* * Split this up, as gcc can choke on it otherwise.. */ @@ -2495,11 +2446,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) if (tty_paranoia_check(tty, inode, "tty_ioctl")) return -EINVAL; - real_tty = tty; - if (tty->driver->type == TTY_DRIVER_TYPE_PTY && - tty->driver->subtype == PTY_TYPE_MASTER) - real_tty = tty->link; - + real_tty = tty_pair_get_tty(tty); /* * Factor out some common prep work @@ -2555,7 +2502,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.ops->num, (int __user *)p); + return put_user(tty->ldisc->ops->num, (int __user *)p); case TIOCSETD: return tiocsetd(tty, p); /* @@ -2770,6 +2717,7 @@ void initialize_tty_struct(struct tty_struct *tty, tty->buf.head = tty->buf.tail = NULL; tty_buffer_init(tty); mutex_init(&tty->termios_mutex); + mutex_init(&tty->ldisc_mutex); init_waitqueue_head(&tty->write_wait); init_waitqueue_head(&tty->read_wait); INIT_WORK(&tty->hangup_work, do_tty_hangup); diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c index 6f4c7d0a53bf..b24f6c6a1ea3 100644 --- a/drivers/char/tty_ioctl.c +++ b/drivers/char/tty_ioctl.c @@ -97,14 +97,19 @@ EXPORT_SYMBOL(tty_driver_flush_buffer); * @tty: terminal * * Indicate that a tty should stop transmitting data down the stack. + * Takes the termios mutex to protect against parallel throttle/unthrottle + * and also to ensure the driver can consistently reference its own + * termios data at this point when implementing software flow control. */ void tty_throttle(struct tty_struct *tty) { + mutex_lock(&tty->termios_mutex); /* check TTY_THROTTLED first so it indicates our state */ if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) && tty->ops->throttle) tty->ops->throttle(tty); + mutex_unlock(&tty->termios_mutex); } EXPORT_SYMBOL(tty_throttle); @@ -113,13 +118,21 @@ EXPORT_SYMBOL(tty_throttle); * @tty: terminal * * Indicate that a tty may continue transmitting data down the stack. + * Takes the termios mutex to protect against parallel throttle/unthrottle + * and also to ensure the driver can consistently reference its own + * termios data at this point when implementing software flow control. + * + * Drivers should however remember that the stack can issue a throttle, + * then change flow control method, then unthrottle. */ void tty_unthrottle(struct tty_struct *tty) { + mutex_lock(&tty->termios_mutex); if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) && tty->ops->unthrottle) tty->ops->unthrottle(tty); + mutex_unlock(&tty->termios_mutex); } EXPORT_SYMBOL(tty_unthrottle); @@ -613,9 +626,25 @@ static int set_termios(struct tty_struct *tty, void __user *arg, int opt) return 0; } +static void copy_termios(struct tty_struct *tty, struct ktermios *kterm) +{ + mutex_lock(&tty->termios_mutex); + memcpy(kterm, tty->termios, sizeof(struct ktermios)); + mutex_unlock(&tty->termios_mutex); +} + +static void copy_termios_locked(struct tty_struct *tty, struct ktermios *kterm) +{ + mutex_lock(&tty->termios_mutex); + memcpy(kterm, tty->termios_locked, sizeof(struct ktermios)); + mutex_unlock(&tty->termios_mutex); +} + static int get_termio(struct tty_struct *tty, struct termio __user *termio) { - if (kernel_termios_to_user_termio(termio, tty->termios)) + struct ktermios kterm; + copy_termios(tty, &kterm); + if (kernel_termios_to_user_termio(termio, &kterm)) return -EFAULT; return 0; } @@ -917,6 +946,7 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file, struct tty_struct *real_tty; void __user *p = (void __user *)arg; int ret = 0; + struct ktermios kterm; if (tty->driver->type == TTY_DRIVER_TYPE_PTY && tty->driver->subtype == PTY_TYPE_MASTER) @@ -952,23 +982,20 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file, return set_termios(real_tty, p, TERMIOS_OLD); #ifndef TCGETS2 case TCGETS: - mutex_lock(&real_tty->termios_mutex); - if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios)) + copy_termios(real_tty, &kterm); + if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm)) ret = -EFAULT; - mutex_unlock(&real_tty->termios_mutex); return ret; #else case TCGETS: - mutex_lock(&real_tty->termios_mutex); - if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios)) + copy_termios(real_tty, &kterm); + if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm)) ret = -EFAULT; - mutex_unlock(&real_tty->termios_mutex); return ret; case TCGETS2: - mutex_lock(&real_tty->termios_mutex); - if (kernel_termios_to_user_termios((struct termios2 __user *)arg, real_tty->termios)) + copy_termios(real_tty, &kterm); + if (kernel_termios_to_user_termios((struct termios2 __user *)arg, &kterm)) ret = -EFAULT; - mutex_unlock(&real_tty->termios_mutex); return ret; case TCSETSF2: return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT); @@ -987,46 +1014,51 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file, return set_termios(real_tty, p, TERMIOS_TERMIO); #ifndef TCGETS2 case TIOCGLCKTRMIOS: - mutex_lock(&real_tty->termios_mutex); - if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios_locked)) + copy_termios_locked(real_tty, &kterm); + if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm)) ret = -EFAULT; - mutex_unlock(&real_tty->termios_mutex); return ret; case TIOCSLCKTRMIOS: if (!capable(CAP_SYS_ADMIN)) return -EPERM; - mutex_lock(&real_tty->termios_mutex); - if (user_termios_to_kernel_termios(real_tty->termios_locked, + copy_termios_locked(real_tty, &kterm); + if (user_termios_to_kernel_termios(&kterm, (struct termios __user *) arg)) - ret = -EFAULT; + return -EFAULT; + mutex_lock(&real_tty->termios_mutex); + memcpy(real_tty->termios_locked, &kterm, sizeof(struct ktermios)); mutex_unlock(&real_tty->termios_mutex); - return ret; + return 0; #else case TIOCGLCKTRMIOS: - mutex_lock(&real_tty->termios_mutex); - if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios_locked)) + copy_termios_locked(real_tty, &kterm); + if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm)) ret = -EFAULT; - mutex_unlock(&real_tty->termios_mutex); return ret; case TIOCSLCKTRMIOS: if (!capable(CAP_SYS_ADMIN)) - ret = -EPERM; - mutex_lock(&real_tty->termios_mutex); - if (user_termios_to_kernel_termios_1(real_tty->termios_locked, + return -EPERM; + copy_termios_locked(real_tty, &kterm); + if (user_termios_to_kernel_termios_1(&kterm, (struct termios __user *) arg)) - ret = -EFAULT; + return -EFAULT; + mutex_lock(&real_tty->termios_mutex); + memcpy(real_tty->termios_locked, &kterm, sizeof(struct ktermios)); mutex_unlock(&real_tty->termios_mutex); return ret; #endif #ifdef TCGETX - case TCGETX: + case TCGETX: { + struct termiox ktermx; if (real_tty->termiox == NULL) return -EINVAL; mutex_lock(&real_tty->termios_mutex); - if (copy_to_user(p, real_tty->termiox, sizeof(struct termiox))) - ret = -EFAULT; + memcpy(&ktermx, real_tty->termiox, sizeof(struct termiox)); mutex_unlock(&real_tty->termios_mutex); + if (copy_to_user(p, &ktermx, sizeof(struct termiox))) + ret = -EFAULT; return ret; + } case TCSETX: return set_termiox(real_tty, p, 0); case TCSETXW: @@ -1035,10 +1067,9 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file, return set_termiox(real_tty, p, TERMIOS_FLUSH); #endif case TIOCGSOFTCAR: - mutex_lock(&real_tty->termios_mutex); - ret = put_user(C_CLOCAL(real_tty) ? 1 : 0, + copy_termios(real_tty, &kterm); + ret = put_user((kterm.c_cflag & CLOCAL) ? 1 : 0, (int __user *)arg); - mutex_unlock(&real_tty->termios_mutex); return ret; case TIOCSSOFTCAR: if (get_user(arg, (unsigned int __user *) arg)) diff --git a/drivers/char/tty_ldisc.c b/drivers/char/tty_ldisc.c index f78f5b0127a8..a19e935847b0 100644 --- a/drivers/char/tty_ldisc.c +++ b/drivers/char/tty_ldisc.c @@ -115,19 +115,22 @@ 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 + * the line discipline refcounted or an error. */ -static int tty_ldisc_try_get(int disc, struct tty_ldisc *ld) +static struct tty_ldisc *tty_ldisc_try_get(int disc) { unsigned long flags; + struct tty_ldisc *ld; struct tty_ldisc_ops *ldops; int err = -EINVAL; - + + ld = kmalloc(sizeof(struct tty_ldisc), GFP_KERNEL); + if (ld == NULL) + return ERR_PTR(-ENOMEM); + spin_lock_irqsave(&tty_ldisc_lock, flags); ld->ops = NULL; ldops = tty_ldiscs[disc]; @@ -140,17 +143,21 @@ static int tty_ldisc_try_get(int disc, struct tty_ldisc *ld) /* lock it */ ldops->refcount++; ld->ops = ldops; + ld->refcount = 0; err = 0; } } spin_unlock_irqrestore(&tty_ldisc_lock, flags); - return err; + if (err) { + kfree(ld); + return ERR_PTR(err); + } + return ld; } /** * 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. @@ -161,52 +168,55 @@ static int tty_ldisc_try_get(int disc, struct tty_ldisc *ld) * takes tty_ldisc_lock to guard against ldisc races */ -static int tty_ldisc_get(int disc, struct tty_ldisc *ld) +static struct tty_ldisc *tty_ldisc_get(int disc) { - int err; + struct tty_ldisc *ld; if (disc < N_TTY || disc >= NR_LDISCS) - return -EINVAL; - err = tty_ldisc_try_get(disc, ld); - if (err < 0) { + return ERR_PTR(-EINVAL); + ld = tty_ldisc_try_get(disc); + if (IS_ERR(ld)) { request_module("tty-ldisc-%d", disc); - err = tty_ldisc_try_get(disc, ld); + ld = tty_ldisc_try_get(disc); } - return err; + return ld; } /** * tty_ldisc_put - drop ldisc reference - * @disc: ldisc number + * @ld: ldisc * * Drop a reference to a line discipline. Manage refcounts and - * module usage counts + * module usage counts. Free the ldisc once the recount hits zero. * * Locking: * takes tty_ldisc_lock to guard against ldisc races */ -static void tty_ldisc_put(struct tty_ldisc_ops *ld) +static void tty_ldisc_put(struct tty_ldisc *ld) { unsigned long flags; - int disc = ld->num; + int disc = ld->ops->num; + struct tty_ldisc_ops *ldo; BUG_ON(disc < N_TTY || disc >= NR_LDISCS); spin_lock_irqsave(&tty_ldisc_lock, flags); - ld = tty_ldiscs[disc]; - BUG_ON(ld->refcount == 0); - ld->refcount--; - module_put(ld->owner); + ldo = tty_ldiscs[disc]; + BUG_ON(ldo->refcount == 0); + ldo->refcount--; + module_put(ldo->owner); spin_unlock_irqrestore(&tty_ldisc_lock, flags); + WARN_ON(ld->refcount); + kfree(ld); } -static void * tty_ldiscs_seq_start(struct seq_file *m, loff_t *pos) +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) +static void *tty_ldiscs_seq_next(struct seq_file *m, void *v, loff_t *pos) { (*pos)++; return (*pos < NR_LDISCS) ? pos : NULL; @@ -219,12 +229,13 @@ 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) + struct tty_ldisc *ld; + + ld = tty_ldisc_try_get(i); + if (IS_ERR(ld)) return 0; - seq_printf(m, "%-10s %2d\n", ld.ops->name ? ld.ops->name : "???", i); - tty_ldisc_put(ld.ops); + seq_printf(m, "%-10s %2d\n", ld->ops->name ? ld->ops->name : "???", i); + tty_ldisc_put(ld); return 0; } @@ -254,7 +265,7 @@ const struct file_operations tty_ldiscs_proc_fops = { * @ld: line discipline * * Install an instance of a line discipline into a tty structure. The - * ldisc must have a reference count above zero to ensure it remains/ + * ldisc must have a reference count above zero to ensure it remains. * The tty instance refcount starts at zero. * * Locking: @@ -263,8 +274,7 @@ const struct file_operations tty_ldiscs_proc_fops = { static void tty_ldisc_assign(struct tty_struct *tty, struct tty_ldisc *ld) { - ld->refcount = 0; - tty->ldisc = *ld; + tty->ldisc = ld; } /** @@ -286,7 +296,7 @@ static int tty_ldisc_try(struct tty_struct *tty) int ret = 0; spin_lock_irqsave(&tty_ldisc_lock, flags); - ld = &tty->ldisc; + ld = tty->ldisc; if (test_bit(TTY_LDISC, &tty->flags)) { ld->refcount++; ret = 1; @@ -315,10 +325,9 @@ struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty) { /* wait_event is a macro */ wait_event(tty_ldisc_wait, tty_ldisc_try(tty)); - WARN_ON(tty->ldisc.refcount == 0); - return &tty->ldisc; + WARN_ON(tty->ldisc->refcount == 0); + return tty->ldisc; } - EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait); /** @@ -335,10 +344,9 @@ EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait); struct tty_ldisc *tty_ldisc_ref(struct tty_struct *tty) { if (tty_ldisc_try(tty)) - return &tty->ldisc; + return tty->ldisc; return NULL; } - EXPORT_SYMBOL_GPL(tty_ldisc_ref); /** @@ -366,7 +374,6 @@ void tty_ldisc_deref(struct tty_ldisc *ld) wake_up(&tty_ldisc_wait); spin_unlock_irqrestore(&tty_ldisc_lock, flags); } - EXPORT_SYMBOL_GPL(tty_ldisc_deref); /** @@ -388,6 +395,26 @@ void tty_ldisc_enable(struct tty_struct *tty) wake_up(&tty_ldisc_wait); } +/** + * tty_ldisc_flush - flush line discipline queue + * @tty: tty + * + * Flush the line discipline queue (if any) for this tty. If there + * is no line discipline active this is a no-op. + */ + +void tty_ldisc_flush(struct tty_struct *tty) +{ + struct tty_ldisc *ld = tty_ldisc_ref(tty); + if (ld) { + if (ld->ops->flush_buffer) + ld->ops->flush_buffer(tty); + tty_ldisc_deref(ld); + } + tty_buffer_flush(tty); +} +EXPORT_SYMBOL_GPL(tty_ldisc_flush); + /** * tty_set_termios_ldisc - set ldisc field * @tty: tty structure @@ -407,6 +434,39 @@ static void tty_set_termios_ldisc(struct tty_struct *tty, int num) mutex_unlock(&tty->termios_mutex); } +/** + * tty_ldisc_open - open a line discipline + * @tty: tty we are opening the ldisc on + * @ld: discipline to open + * + * A helper opening method. Also a convenient debugging and check + * point. + */ + +static int tty_ldisc_open(struct tty_struct *tty, struct tty_ldisc *ld) +{ + WARN_ON(test_and_set_bit(TTY_LDISC_OPEN, &tty->flags)); + if (ld->ops->open) + return ld->ops->open(tty); + return 0; +} + +/** + * tty_ldisc_close - close a line discipline + * @tty: tty we are opening the ldisc on + * @ld: discipline to close + * + * A helper close method. Also a convenient debugging and check + * point. + */ + +static void tty_ldisc_close(struct tty_struct *tty, struct tty_ldisc *ld) +{ + WARN_ON(!test_bit(TTY_LDISC_OPEN, &tty->flags)); + clear_bit(TTY_LDISC_OPEN, &tty->flags); + if (ld->ops->close) + ld->ops->close(tty); +} /** * tty_ldisc_restore - helper for tty ldisc change @@ -420,66 +480,136 @@ static void tty_set_termios_ldisc(struct tty_struct *tty, int num) static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old) { char buf[64]; - struct tty_ldisc new_ldisc; + struct tty_ldisc *new_ldisc; + int r; /* There is an outstanding reference here so this is safe */ - tty_ldisc_get(old->ops->num, old); + old = tty_ldisc_get(old->ops->num); + WARN_ON(IS_ERR(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); + if (tty_ldisc_open(tty, old) < 0) { + tty_ldisc_put(old); /* This driver is always present */ - if (tty_ldisc_get(N_TTY, &new_ldisc) < 0) + new_ldisc = tty_ldisc_get(N_TTY); + if (IS_ERR(new_ldisc)) panic("n_tty: get"); - tty_ldisc_assign(tty, &new_ldisc); + 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); - } + r = tty_ldisc_open(tty, new_ldisc); + if (r < 0) + panic("Couldn't open N_TTY ldisc for " + "%s --- error %d.", + tty_name(tty, buf), r); } } +/** + * tty_ldisc_halt - shut down the line discipline + * @tty: tty device + * + * Shut down the line discipline and work queue for this tty device. + * The TTY_LDISC flag being cleared ensures no further references can + * be obtained while the delayed work queue halt ensures that no more + * data is fed to the ldisc. + * + * In order to wait for any existing references to complete see + * tty_ldisc_wait_idle. + */ + +static int tty_ldisc_halt(struct tty_struct *tty) +{ + clear_bit(TTY_LDISC, &tty->flags); + return cancel_delayed_work(&tty->buf.work); +} + +/** + * tty_ldisc_wait_idle - wait for the ldisc to become idle + * @tty: tty to wait for + * + * Wait for the line discipline to become idle. The discipline must + * have been halted for this to guarantee it remains idle. + * + * tty_ldisc_lock protects the ref counts currently. + */ + +static int tty_ldisc_wait_idle(struct tty_struct *tty) +{ + unsigned long flags; + spin_lock_irqsave(&tty_ldisc_lock, flags); + while (tty->ldisc->refcount) { + spin_unlock_irqrestore(&tty_ldisc_lock, flags); + if (wait_event_timeout(tty_ldisc_wait, + tty->ldisc->refcount == 0, 5 * HZ) == 0) + return -EBUSY; + spin_lock_irqsave(&tty_ldisc_lock, flags); + } + spin_unlock_irqrestore(&tty_ldisc_lock, flags); + return 0; +} + /** * tty_set_ldisc - set line discipline * @tty: the terminal to set * @ldisc: the line discipline * * Set the discipline of a tty line. Must be called from a process - * context. + * context. The ldisc change logic has to protect itself against any + * overlapping ldisc change (including on the other end of pty pairs), + * the close of one side of a tty/pty pair, and eventually hangup. * - * Locking: takes tty_ldisc_lock. - * called functions take termios_mutex + * Locking: takes tty_ldisc_lock, termios_mutex */ int tty_set_ldisc(struct tty_struct *tty, int ldisc) { int retval; - struct tty_ldisc o_ldisc, new_ldisc; - int work; - unsigned long flags; + struct tty_ldisc *o_ldisc, *new_ldisc; + int work, o_work = 0; struct tty_struct *o_tty; -restart: - /* 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; + new_ldisc = tty_ldisc_get(ldisc); + if (IS_ERR(new_ldisc)) + return PTR_ERR(new_ldisc); + + /* + * We need to look at the tty locking here for pty/tty pairs + * when both sides try to change in parallel. + */ + + o_tty = tty->link; /* o_tty is the pty side or NULL */ + + + /* + * Check the no-op case + */ + + if (tty->ldisc->ops->num == ldisc) { + tty_ldisc_put(new_ldisc); + return 0; + } /* * Problem: What do we do if this blocks ? + * We could deadlock here */ tty_wait_until_sent(tty, 0); - if (tty->ldisc.ops->num == ldisc) { - tty_ldisc_put(new_ldisc.ops); - return 0; + mutex_lock(&tty->ldisc_mutex); + + /* + * We could be midstream of another ldisc change which has + * dropped the lock during processing. If so we need to wait. + */ + + while (test_bit(TTY_LDISC_CHANGING, &tty->flags)) { + mutex_unlock(&tty->ldisc_mutex); + wait_event(tty_ldisc_wait, + test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0); + mutex_lock(&tty->ldisc_mutex); } + set_bit(TTY_LDISC_CHANGING, &tty->flags); /* * No more input please, we are switching. The new ldisc @@ -489,8 +619,6 @@ restart: tty->receive_room = 0; o_ldisc = tty->ldisc; - o_tty = tty->link; - /* * Make sure we don't change while someone holds a * reference to the line discipline. The TTY_LDISC bit @@ -501,108 +629,183 @@ restart: * with a userspace app continually trying to use the tty in * parallel to the change and re-referencing the tty. */ - clear_bit(TTY_LDISC, &tty->flags); - if (o_tty) - clear_bit(TTY_LDISC, &o_tty->flags); - spin_lock_irqsave(&tty_ldisc_lock, flags); - if (tty->ldisc.refcount || (o_tty && o_tty->ldisc.refcount)) { - if (tty->ldisc.refcount) { - /* Free the new ldisc we grabbed. Must drop the lock - first. */ - spin_unlock_irqrestore(&tty_ldisc_lock, flags); - tty_ldisc_put(o_ldisc.ops); - /* - * There are several reasons we may be busy, including - * random momentary I/O traffic. We must therefore - * retry. We could distinguish between blocking ops - * and retries if we made tty_ldisc_wait() smarter. - * That is up for discussion. - */ - if (wait_event_interruptible(tty_ldisc_wait, tty->ldisc.refcount == 0) < 0) - return -ERESTARTSYS; - goto restart; - } - if (o_tty && o_tty->ldisc.refcount) { - spin_unlock_irqrestore(&tty_ldisc_lock, flags); - tty_ldisc_put(o_tty->ldisc.ops); - if (wait_event_interruptible(tty_ldisc_wait, o_tty->ldisc.refcount == 0) < 0) - return -ERESTARTSYS; - goto restart; - } - } - /* - * If the TTY_LDISC bit is set, then we are racing against - * another ldisc change - */ - if (test_bit(TTY_LDISC_CHANGING, &tty->flags)) { - struct tty_ldisc *ld; - spin_unlock_irqrestore(&tty_ldisc_lock, flags); - tty_ldisc_put(new_ldisc.ops); - ld = tty_ldisc_ref_wait(tty); - tty_ldisc_deref(ld); - goto restart; - } - /* - * This flag is used to avoid two parallel ldisc changes. Once - * open and close are fine grained locked this may work better - * as a mutex shared with the open/close/hup paths - */ - set_bit(TTY_LDISC_CHANGING, &tty->flags); + work = tty_ldisc_halt(tty); if (o_tty) - set_bit(TTY_LDISC_CHANGING, &o_tty->flags); - spin_unlock_irqrestore(&tty_ldisc_lock, flags); - + o_work = tty_ldisc_halt(o_tty); + /* - * From this point on we know nobody has an ldisc - * usage reference, nor can they obtain one until - * we say so later on. + * Wait for ->hangup_work and ->buf.work handlers to terminate. + * We must drop the mutex here in case a hangup is also in process. */ - work = cancel_delayed_work(&tty->buf.work); - /* - * Wait for ->hangup_work and ->buf.work handlers to terminate - * MUST NOT hold locks here. - */ + mutex_unlock(&tty->ldisc_mutex); + flush_scheduled_work(); + + /* Let any existing reference holders finish */ + retval = tty_ldisc_wait_idle(tty); + if (retval < 0) { + clear_bit(TTY_LDISC_CHANGING, &tty->flags); + tty_ldisc_put(new_ldisc); + return retval; + } + + mutex_lock(&tty->ldisc_mutex); + if (test_bit(TTY_HUPPED, &tty->flags)) { + /* We were raced by the hangup method. It will have stomped + the ldisc data and closed the ldisc down */ + clear_bit(TTY_LDISC_CHANGING, &tty->flags); + mutex_unlock(&tty->ldisc_mutex); + tty_ldisc_put(new_ldisc); + return -EIO; + } + /* Shutdown the current discipline. */ - if (o_ldisc.ops->close) - (o_ldisc.ops->close)(tty); + tty_ldisc_close(tty, o_ldisc); /* Now set up the new line discipline. */ - tty_ldisc_assign(tty, &new_ldisc); + tty_ldisc_assign(tty, new_ldisc); tty_set_termios_ldisc(tty, ldisc); - if (new_ldisc.ops->open) - retval = (new_ldisc.ops->open)(tty); + + retval = tty_ldisc_open(tty, new_ldisc); if (retval < 0) { - tty_ldisc_put(new_ldisc.ops); - tty_ldisc_restore(tty, &o_ldisc); + /* Back to the old one or N_TTY if we can't */ + tty_ldisc_put(new_ldisc); + 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.ops->num != o_ldisc.ops->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.ops); + tty_ldisc_put(o_ldisc); /* - * Allow ldisc referencing to occur as soon as the driver - * ldisc callback completes. + * Allow ldisc referencing to occur again */ tty_ldisc_enable(tty); if (o_tty) tty_ldisc_enable(o_tty); - /* Restart it in case no characters kick it off. Safe if + /* Restart the work queue in case no characters kick it off. Safe if already running */ if (work) schedule_delayed_work(&tty->buf.work, 1); + if (o_work) + schedule_delayed_work(&o_tty->buf.work, 1); + mutex_unlock(&tty->ldisc_mutex); return retval; } +/** + * tty_reset_termios - reset terminal state + * @tty: tty to reset + * + * Restore a terminal to the driver default state. + */ + +static void tty_reset_termios(struct tty_struct *tty) +{ + mutex_lock(&tty->termios_mutex); + *tty->termios = tty->driver->init_termios; + tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios); + tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios); + mutex_unlock(&tty->termios_mutex); +} + + +/** + * tty_ldisc_reinit - reinitialise the tty ldisc + * @tty: tty to reinit + * + * Switch the tty back to N_TTY line discipline and leave the + * ldisc state closed + */ + +static void tty_ldisc_reinit(struct tty_struct *tty) +{ + struct tty_ldisc *ld; + + tty_ldisc_close(tty, tty->ldisc); + tty_ldisc_put(tty->ldisc); + tty->ldisc = NULL; + /* + * Switch the line discipline back + */ + ld = tty_ldisc_get(N_TTY); + BUG_ON(IS_ERR(ld)); + tty_ldisc_assign(tty, ld); + tty_set_termios_ldisc(tty, N_TTY); +} + +/** + * tty_ldisc_hangup - hangup ldisc reset + * @tty: tty being hung up + * + * Some tty devices reset their termios when they receive a hangup + * event. In that situation we must also switch back to N_TTY properly + * before we reset the termios data. + * + * Locking: We can take the ldisc mutex as the rest of the code is + * careful to allow for this. + * + * In the pty pair case this occurs in the close() path of the + * tty itself so we must be careful about locking rules. + */ + +void tty_ldisc_hangup(struct tty_struct *tty) +{ + struct tty_ldisc *ld; + + /* + * FIXME! What are the locking issues here? This may me overdoing + * things... This question is especially important now that we've + * removed the irqlock. + */ + ld = tty_ldisc_ref(tty); + if (ld != NULL) { + /* We may have no line discipline at this point */ + 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->ops->write_wakeup) + ld->ops->write_wakeup(tty); + if (ld->ops->hangup) + ld->ops->hangup(tty); + tty_ldisc_deref(ld); + } + /* + * FIXME: Once we trust the LDISC code better we can wait here for + * ldisc completion and fix the driver call race + */ + wake_up_interruptible_poll(&tty->write_wait, POLLOUT); + wake_up_interruptible_poll(&tty->read_wait, POLLIN); + /* + * Shutdown the current line discipline, and reset it to + * N_TTY. + */ + if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) { + /* Avoid racing set_ldisc */ + mutex_lock(&tty->ldisc_mutex); + /* Switch back to N_TTY */ + tty_ldisc_halt(tty); + tty_ldisc_wait_idle(tty); + tty_ldisc_reinit(tty); + /* At this point we have a closed ldisc and we want to + reopen it. We could defer this to the next open but + it means auditing a lot of other paths so this is a FIXME */ + WARN_ON(tty_ldisc_open(tty, tty->ldisc)); + tty_ldisc_enable(tty); + mutex_unlock(&tty->ldisc_mutex); + tty_reset_termios(tty); + } +} /** * tty_ldisc_setup - open line discipline @@ -610,24 +813,23 @@ restart: * @o_tty: pair tty for pty/tty pairs * * Called during the initial open of a tty/pty pair in order to set up the - * line discplines and bind them to the tty. + * line disciplines and bind them to the tty. This has no locking issues + * as the device isn't yet active. */ int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty) { - struct tty_ldisc *ld = &tty->ldisc; + struct tty_ldisc *ld = tty->ldisc; int retval; - if (ld->ops->open) { - retval = (ld->ops->open)(tty); - if (retval) - return retval; - } - if (o_tty && o_tty->ldisc.ops->open) { - retval = (o_tty->ldisc.ops->open)(o_tty); + retval = tty_ldisc_open(tty, ld); + if (retval) + return retval; + + if (o_tty) { + retval = tty_ldisc_open(o_tty, o_tty->ldisc); if (retval) { - if (ld->ops->close) - (ld->ops->close)(tty); + tty_ldisc_close(tty, ld); return retval; } tty_ldisc_enable(o_tty); @@ -635,32 +837,25 @@ int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty) tty_ldisc_enable(tty); return 0; } - /** * tty_ldisc_release - release line discipline * @tty: tty being shut down * @o_tty: pair tty for pty/tty pairs * - * Called during the final close of a tty/pty pair in order to shut down the - * line discpline layer. + * Called during the final close of a tty/pty pair in order to shut down + * the line discpline layer. On exit the ldisc assigned is N_TTY and the + * ldisc has not been opened. */ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty) { - unsigned long flags; - struct tty_ldisc ld; /* * Prevent flush_to_ldisc() from rescheduling the work for later. Then * kill any delayed work. As this is the final close it does not * race with the set_ldisc code path. */ - clear_bit(TTY_LDISC, &tty->flags); - cancel_delayed_work(&tty->buf.work); - - /* - * Wait for ->hangup_work and ->buf.work handlers to terminate - */ + tty_ldisc_halt(tty); flush_scheduled_work(); /* @@ -668,38 +863,19 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty) * side waiters as the file is closing so user count on the file * side is zero. */ - spin_lock_irqsave(&tty_ldisc_lock, flags); - while (tty->ldisc.refcount) { - spin_unlock_irqrestore(&tty_ldisc_lock, flags); - wait_event(tty_ldisc_wait, tty->ldisc.refcount == 0); - spin_lock_irqsave(&tty_ldisc_lock, flags); - } - spin_unlock_irqrestore(&tty_ldisc_lock, flags); + + tty_ldisc_wait_idle(tty); + /* * Shutdown the current line discipline, and reset it to N_TTY. * * FIXME: this MUST get fixed for the new reflocking */ - if (tty->ldisc.ops->close) - (tty->ldisc.ops->close)(tty); - tty_ldisc_put(tty->ldisc.ops); - /* - * Switch the line discipline back - */ - 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.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); - } + tty_ldisc_reinit(tty); + /* This will need doing differently if we need to lock */ + if (o_tty) + tty_ldisc_release(o_tty, NULL); } /** @@ -712,10 +888,10 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty) void tty_ldisc_init(struct tty_struct *tty) { - struct tty_ldisc ld; - if (tty_ldisc_get(N_TTY, &ld) < 0) + struct tty_ldisc *ld = tty_ldisc_get(N_TTY); + if (IS_ERR(ld)) panic("n_tty: init_tty"); - tty_ldisc_assign(tty, &ld); + tty_ldisc_assign(tty, ld); } void tty_ldisc_begin(void) diff --git a/drivers/char/tty_port.c b/drivers/char/tty_port.c index 9b8004c72686..4e862a75f7ff 100644 --- a/drivers/char/tty_port.c +++ b/drivers/char/tty_port.c @@ -137,7 +137,7 @@ int tty_port_carrier_raised(struct tty_port *port) EXPORT_SYMBOL(tty_port_carrier_raised); /** - * tty_port_raise_dtr_rts - Riase DTR/RTS + * tty_port_raise_dtr_rts - Raise DTR/RTS * @port: tty port * * Wrapper for the DTR/RTS raise logic. For the moment this is used @@ -147,11 +147,27 @@ EXPORT_SYMBOL(tty_port_carrier_raised); void tty_port_raise_dtr_rts(struct tty_port *port) { - if (port->ops->raise_dtr_rts) - port->ops->raise_dtr_rts(port); + if (port->ops->dtr_rts) + port->ops->dtr_rts(port, 1); } EXPORT_SYMBOL(tty_port_raise_dtr_rts); +/** + * tty_port_lower_dtr_rts - Lower DTR/RTS + * @port: tty port + * + * Wrapper for the DTR/RTS raise logic. For the moment this is used + * to hide some internal details. This will eventually become entirely + * internal to the tty port. + */ + +void tty_port_lower_dtr_rts(struct tty_port *port) +{ + if (port->ops->dtr_rts) + port->ops->dtr_rts(port, 0); +} +EXPORT_SYMBOL(tty_port_lower_dtr_rts); + /** * tty_port_block_til_ready - Waiting logic for tty open * @port: the tty port being opened @@ -167,7 +183,7 @@ EXPORT_SYMBOL(tty_port_raise_dtr_rts); * - port flags and counts * * The passed tty_port must implement the carrier_raised method if it can - * do carrier detect and the raise_dtr_rts method if it supports software + * do carrier detect and the dtr_rts method if it supports software * management of these lines. Note that the dtr/rts raise is done each * iteration as a hangup may have previously dropped them while we wait. */ @@ -177,12 +193,13 @@ int tty_port_block_til_ready(struct tty_port *port, { int do_clocal = 0, retval; unsigned long flags; - DECLARE_WAITQUEUE(wait, current); + DEFINE_WAIT(wait); int cd; /* block if port is in the process of being closed */ if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) { - interruptible_sleep_on(&port->close_wait); + wait_event_interruptible(port->close_wait, + !(port->flags & ASYNC_CLOSING)); if (port->flags & ASYNC_HUP_NOTIFY) return -EAGAIN; else @@ -205,7 +222,6 @@ int tty_port_block_til_ready(struct tty_port *port, before the next open may complete */ retval = 0; - add_wait_queue(&port->open_wait, &wait); /* The port lock protects the port counts */ spin_lock_irqsave(&port->lock, flags); @@ -219,7 +235,7 @@ int tty_port_block_til_ready(struct tty_port *port, if (tty->termios->c_cflag & CBAUD) tty_port_raise_dtr_rts(port); - set_current_state(TASK_INTERRUPTIBLE); + prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE); /* Check for a hangup or uninitialised port. Return accordingly */ if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) { if (port->flags & ASYNC_HUP_NOTIFY) @@ -240,8 +256,7 @@ int tty_port_block_til_ready(struct tty_port *port, } schedule(); } - set_current_state(TASK_RUNNING); - remove_wait_queue(&port->open_wait, &wait); + finish_wait(&port->open_wait, &wait); /* Update counts. A parallel hangup will have set count to zero and we must not mess that up further */ @@ -292,6 +307,17 @@ int tty_port_close_start(struct tty_port *port, struct tty_struct *tty, struct f if (port->flags & ASYNC_INITIALIZED && port->closing_wait != ASYNC_CLOSING_WAIT_NONE) tty_wait_until_sent(tty, port->closing_wait); + if (port->drain_delay) { + unsigned int bps = tty_get_baud_rate(tty); + long timeout; + + if (bps > 1200) + timeout = max_t(long, (HZ * 10 * port->drain_delay) / bps, + HZ / 10); + else + timeout = 2 * HZ; + schedule_timeout_interruptible(timeout); + } return 1; } EXPORT_SYMBOL(tty_port_close_start); @@ -302,6 +328,9 @@ void tty_port_close_end(struct tty_port *port, struct tty_struct *tty) tty_ldisc_flush(tty); + if (tty->termios->c_cflag & HUPCL) + tty_port_lower_dtr_rts(port); + spin_lock_irqsave(&port->lock, flags); tty->closing = 0; diff --git a/drivers/char/viotape.c b/drivers/char/viotape.c index ffc9254f7e02..042c8149a6d1 100644 --- a/drivers/char/viotape.c +++ b/drivers/char/viotape.c @@ -867,7 +867,7 @@ static int viotape_probe(struct vio_dev *vdev, const struct vio_device_id *id) int j; struct device_node *node = vdev->dev.archdata.of_node; - if (i > VIOTAPE_MAX_TAPE) + if (i >= VIOTAPE_MAX_TAPE) return -ENODEV; if (!node) return -ENODEV; diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index ff6f5a4b58fb..c74dacfa6795 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -188,6 +188,9 @@ static void hvc_handle_input(struct virtqueue *vq) * Finally we put our input buffer in the input queue, ready to receive. */ static int __devinit virtcons_probe(struct virtio_device *dev) { + vq_callback_t *callbacks[] = { hvc_handle_input, NULL}; + const char *names[] = { "input", "output" }; + struct virtqueue *vqs[2]; int err; vdev = dev; @@ -199,20 +202,15 @@ static int __devinit virtcons_probe(struct virtio_device *dev) goto fail; } - /* Find the input queue. */ + /* Find the queues. */ /* FIXME: This is why we want to wean off hvc: we do nothing * when input comes in. */ - in_vq = vdev->config->find_vq(vdev, 0, hvc_handle_input); - if (IS_ERR(in_vq)) { - err = PTR_ERR(in_vq); + err = vdev->config->find_vqs(vdev, 2, vqs, callbacks, names); + if (err) goto free; - } - out_vq = vdev->config->find_vq(vdev, 1, NULL); - if (IS_ERR(out_vq)) { - err = PTR_ERR(out_vq); - goto free_in_vq; - } + in_vq = vqs[0]; + out_vq = vqs[1]; /* Start using the new console output. */ virtio_cons.get_chars = get_chars; @@ -233,17 +231,15 @@ static int __devinit virtcons_probe(struct virtio_device *dev) hvc = hvc_alloc(0, 0, &virtio_cons, PAGE_SIZE); if (IS_ERR(hvc)) { err = PTR_ERR(hvc); - goto free_out_vq; + goto free_vqs; } /* Register the input buffer the first time. */ add_inbuf(); return 0; -free_out_vq: - vdev->config->del_vq(out_vq); -free_in_vq: - vdev->config->del_vq(in_vq); +free_vqs: + vdev->config->del_vqs(vdev); free: kfree(inbuf); fail: diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 08151d4de489..d9113b4c76e3 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -95,7 +95,6 @@ #include #include #include -#include #include #include #include @@ -172,8 +171,9 @@ int do_poke_blanked_console; int console_blanked; static int vesa_blank_mode; /* 0:none 1:suspendV 2:suspendH 3:powerdown */ -static int blankinterval = 10*60*HZ; static int vesa_off_interval; +static int blankinterval = 10*60; +core_param(consoleblank, blankinterval, int, 0444); static DECLARE_WORK(console_work, console_callback); @@ -1486,7 +1486,7 @@ static void setterm_command(struct vc_data *vc) update_attr(vc); break; case 9: /* set blanking interval */ - blankinterval = ((vc->vc_par[1] < 60) ? vc->vc_par[1] : 60) * 60 * HZ; + blankinterval = ((vc->vc_par[1] < 60) ? vc->vc_par[1] : 60) * 60; poke_blanked_console(); break; case 10: /* set bell frequency in Hz */ @@ -2872,17 +2872,14 @@ static int __init con_init(void) if (blankinterval) { blank_state = blank_normal_wait; - mod_timer(&console_timer, jiffies + blankinterval); + mod_timer(&console_timer, jiffies + (blankinterval * HZ)); } - /* - * kmalloc is not running yet - we use the bootmem allocator. - */ for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) { - vc_cons[currcons].d = vc = alloc_bootmem(sizeof(struct vc_data)); + vc_cons[currcons].d = vc = kzalloc(sizeof(struct vc_data), GFP_NOWAIT); INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK); visual_init(vc, currcons, 1); - vc->vc_screenbuf = (unsigned short *)alloc_bootmem(vc->vc_screenbuf_size); + vc->vc_screenbuf = kzalloc(vc->vc_screenbuf_size, GFP_NOWAIT); vc->vc_kmalloced = 0; vc_init(vc, vc->vc_rows, vc->vc_cols, currcons || !vc->vc_sw->con_save_screen); @@ -3681,7 +3678,7 @@ void do_unblank_screen(int leaving_gfx) return; /* but leave console_blanked != 0 */ if (blankinterval) { - mod_timer(&console_timer, jiffies + blankinterval); + mod_timer(&console_timer, jiffies + (blankinterval * HZ)); blank_state = blank_normal_wait; } @@ -3715,7 +3712,7 @@ void unblank_screen(void) static void blank_screen_t(unsigned long dummy) { if (unlikely(!keventd_up())) { - mod_timer(&console_timer, jiffies + blankinterval); + mod_timer(&console_timer, jiffies + (blankinterval * HZ)); return; } blank_timer_expired = 1; @@ -3745,7 +3742,7 @@ void poke_blanked_console(void) if (console_blanked) unblank_screen(); else if (blankinterval) { - mod_timer(&console_timer, jiffies + blankinterval); + mod_timer(&console_timer, jiffies + (blankinterval * HZ)); blank_state = blank_normal_wait; } } diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c index e6ce632a393e..7539bed0f7e0 100644 --- a/drivers/char/vt_ioctl.c +++ b/drivers/char/vt_ioctl.c @@ -396,7 +396,8 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, kbd = kbd_table + console; switch (cmd) { case TIOCLINUX: - return tioclinux(tty, arg); + ret = tioclinux(tty, arg); + break; case KIOCSOUND: if (!perm) goto eperm; diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 1efb2879a94f..eef216f7f61d 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -3,3 +3,5 @@ obj-$(CONFIG_X86_CYCLONE_TIMER) += cyclone.o obj-$(CONFIG_X86_PM_TIMER) += acpi_pm.o obj-$(CONFIG_SCx200HR_TIMER) += scx200_hrt.o obj-$(CONFIG_SH_TIMER_CMT) += sh_cmt.o +obj-$(CONFIG_SH_TIMER_MTU2) += sh_mtu2.o +obj-$(CONFIG_SH_TIMER_TMU) += sh_tmu.o diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c index 40bd8c61c7d7..72a633a6ec98 100644 --- a/drivers/clocksource/acpi_pm.c +++ b/drivers/clocksource/acpi_pm.c @@ -18,6 +18,7 @@ #include #include +#include #include #include #include diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c index 1c92c39a53aa..2964f5f4a7ef 100644 --- a/drivers/clocksource/sh_cmt.c +++ b/drivers/clocksource/sh_cmt.c @@ -18,7 +18,6 @@ */ #include -#include #include #include #include @@ -29,7 +28,7 @@ #include #include #include -#include +#include struct sh_cmt_priv { void __iomem *mapbase; @@ -47,6 +46,7 @@ struct sh_cmt_priv { unsigned long rate; spinlock_t lock; struct clock_event_device ced; + struct clocksource cs; unsigned long total_cycles; }; @@ -59,7 +59,7 @@ static DEFINE_SPINLOCK(sh_cmt_lock); static inline unsigned long sh_cmt_read(struct sh_cmt_priv *p, int reg_nr) { - struct sh_cmt_config *cfg = p->pdev->dev.platform_data; + struct sh_timer_config *cfg = p->pdev->dev.platform_data; void __iomem *base = p->mapbase; unsigned long offs; @@ -83,7 +83,7 @@ static inline unsigned long sh_cmt_read(struct sh_cmt_priv *p, int reg_nr) static inline void sh_cmt_write(struct sh_cmt_priv *p, int reg_nr, unsigned long value) { - struct sh_cmt_config *cfg = p->pdev->dev.platform_data; + struct sh_timer_config *cfg = p->pdev->dev.platform_data; void __iomem *base = p->mapbase; unsigned long offs; @@ -110,23 +110,28 @@ static unsigned long sh_cmt_get_counter(struct sh_cmt_priv *p, int *has_wrapped) { unsigned long v1, v2, v3; + int o1, o2; + + o1 = sh_cmt_read(p, CMCSR) & p->overflow_bit; /* Make sure the timer value is stable. Stolen from acpi_pm.c */ do { + o2 = o1; v1 = sh_cmt_read(p, CMCNT); v2 = sh_cmt_read(p, CMCNT); v3 = sh_cmt_read(p, CMCNT); - } while (unlikely((v1 > v2 && v1 < v3) || (v2 > v3 && v2 < v1) - || (v3 > v1 && v3 < v2))); + o1 = sh_cmt_read(p, CMCSR) & p->overflow_bit; + } while (unlikely((o1 != o2) || (v1 > v2 && v1 < v3) + || (v2 > v3 && v2 < v1) || (v3 > v1 && v3 < v2))); - *has_wrapped = sh_cmt_read(p, CMCSR) & p->overflow_bit; + *has_wrapped = o1; return v2; } static void sh_cmt_start_stop_ch(struct sh_cmt_priv *p, int start) { - struct sh_cmt_config *cfg = p->pdev->dev.platform_data; + struct sh_timer_config *cfg = p->pdev->dev.platform_data; unsigned long flags, value; /* start stop register shared by multiple timer channels */ @@ -144,7 +149,7 @@ static void sh_cmt_start_stop_ch(struct sh_cmt_priv *p, int start) static int sh_cmt_enable(struct sh_cmt_priv *p, unsigned long *rate) { - struct sh_cmt_config *cfg = p->pdev->dev.platform_data; + struct sh_timer_config *cfg = p->pdev->dev.platform_data; int ret; /* enable clock */ @@ -153,16 +158,18 @@ static int sh_cmt_enable(struct sh_cmt_priv *p, unsigned long *rate) pr_err("sh_cmt: cannot enable clock \"%s\"\n", cfg->clk); return ret; } - *rate = clk_get_rate(p->clk) / 8; /* make sure channel is disabled */ sh_cmt_start_stop_ch(p, 0); /* configure channel, periodic mode and maximum timeout */ - if (p->width == 16) - sh_cmt_write(p, CMCSR, 0); - else + if (p->width == 16) { + *rate = clk_get_rate(p->clk) / 512; + sh_cmt_write(p, CMCSR, 0x43); + } else { + *rate = clk_get_rate(p->clk) / 8; sh_cmt_write(p, CMCSR, 0x01a4); + } sh_cmt_write(p, CMCOR, 0xffffffff); sh_cmt_write(p, CMCNT, 0); @@ -177,6 +184,9 @@ static void sh_cmt_disable(struct sh_cmt_priv *p) /* disable channel */ sh_cmt_start_stop_ch(p, 0); + /* disable interrupts in CMT block */ + sh_cmt_write(p, CMCSR, 0); + /* stop clock */ clk_disable(p->clk); } @@ -376,6 +386,68 @@ static void sh_cmt_stop(struct sh_cmt_priv *p, unsigned long flag) spin_unlock_irqrestore(&p->lock, flags); } +static struct sh_cmt_priv *cs_to_sh_cmt(struct clocksource *cs) +{ + return container_of(cs, struct sh_cmt_priv, cs); +} + +static cycle_t sh_cmt_clocksource_read(struct clocksource *cs) +{ + struct sh_cmt_priv *p = cs_to_sh_cmt(cs); + unsigned long flags, raw; + unsigned long value; + int has_wrapped; + + spin_lock_irqsave(&p->lock, flags); + value = p->total_cycles; + raw = sh_cmt_get_counter(p, &has_wrapped); + + if (unlikely(has_wrapped)) + raw += p->match_value; + spin_unlock_irqrestore(&p->lock, flags); + + return value + raw; +} + +static int sh_cmt_clocksource_enable(struct clocksource *cs) +{ + struct sh_cmt_priv *p = cs_to_sh_cmt(cs); + int ret; + + p->total_cycles = 0; + + ret = sh_cmt_start(p, FLAG_CLOCKSOURCE); + if (ret) + return ret; + + /* TODO: calculate good shift from rate and counter bit width */ + cs->shift = 0; + cs->mult = clocksource_hz2mult(p->rate, cs->shift); + return 0; +} + +static void sh_cmt_clocksource_disable(struct clocksource *cs) +{ + sh_cmt_stop(cs_to_sh_cmt(cs), FLAG_CLOCKSOURCE); +} + +static int sh_cmt_register_clocksource(struct sh_cmt_priv *p, + char *name, unsigned long rating) +{ + struct clocksource *cs = &p->cs; + + cs->name = name; + cs->rating = rating; + cs->read = sh_cmt_clocksource_read; + cs->enable = sh_cmt_clocksource_enable; + cs->disable = sh_cmt_clocksource_disable; + cs->mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8); + cs->flags = CLOCK_SOURCE_IS_CONTINUOUS; + pr_info("sh_cmt: %s used as clock source\n", cs->name); + clocksource_register(cs); + return 0; +} + static struct sh_cmt_priv *ced_to_sh_cmt(struct clock_event_device *ced) { return container_of(ced, struct sh_cmt_priv, ced); @@ -468,9 +540,9 @@ static void sh_cmt_register_clockevent(struct sh_cmt_priv *p, clockevents_register_device(ced); } -int sh_cmt_register(struct sh_cmt_priv *p, char *name, - unsigned long clockevent_rating, - unsigned long clocksource_rating) +static int sh_cmt_register(struct sh_cmt_priv *p, char *name, + unsigned long clockevent_rating, + unsigned long clocksource_rating) { if (p->width == (sizeof(p->max_match_value) * 8)) p->max_match_value = ~0; @@ -483,12 +555,15 @@ int sh_cmt_register(struct sh_cmt_priv *p, char *name, if (clockevent_rating) sh_cmt_register_clockevent(p, name, clockevent_rating); + if (clocksource_rating) + sh_cmt_register_clocksource(p, name, clocksource_rating); + return 0; } static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev) { - struct sh_cmt_config *cfg = pdev->dev.platform_data; + struct sh_timer_config *cfg = pdev->dev.platform_data; struct resource *res; int irq, ret; ret = -ENXIO; @@ -527,7 +602,6 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev) p->irqaction.handler = sh_cmt_interrupt; p->irqaction.dev_id = p; p->irqaction.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL; - p->irqaction.mask = CPU_MASK_NONE; ret = setup_irq(irq, &p->irqaction); if (ret) { pr_err("sh_cmt: failed to request irq %d\n", irq); @@ -545,7 +619,7 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev) if (resource_size(res) == 6) { p->width = 16; p->overflow_bit = 0x80; - p->clear_bits = ~0xc0; + p->clear_bits = ~0x80; } else { p->width = 32; p->overflow_bit = 0x8000; @@ -566,8 +640,14 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev) static int __devinit sh_cmt_probe(struct platform_device *pdev) { struct sh_cmt_priv *p = platform_get_drvdata(pdev); + struct sh_timer_config *cfg = pdev->dev.platform_data; int ret; + if (p) { + pr_info("sh_cmt: %s kept as earlytimer\n", cfg->name); + return 0; + } + p = kmalloc(sizeof(*p), GFP_KERNEL); if (p == NULL) { dev_err(&pdev->dev, "failed to allocate driver data\n"); @@ -577,7 +657,6 @@ static int __devinit sh_cmt_probe(struct platform_device *pdev) ret = sh_cmt_setup(p, pdev); if (ret) { kfree(p); - platform_set_drvdata(pdev, NULL); } return ret; @@ -606,6 +685,7 @@ static void __exit sh_cmt_exit(void) platform_driver_unregister(&sh_cmt_device_driver); } +early_platform_init("earlytimer", &sh_cmt_device_driver); module_init(sh_cmt_init); module_exit(sh_cmt_exit); diff --git a/drivers/clocksource/sh_mtu2.c b/drivers/clocksource/sh_mtu2.c new file mode 100644 index 000000000000..973e714d6051 --- /dev/null +++ b/drivers/clocksource/sh_mtu2.c @@ -0,0 +1,356 @@ +/* + * SuperH Timer Support - MTU2 + * + * Copyright (C) 2009 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 of the License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct sh_mtu2_priv { + void __iomem *mapbase; + struct clk *clk; + struct irqaction irqaction; + struct platform_device *pdev; + unsigned long rate; + unsigned long periodic; + struct clock_event_device ced; +}; + +static DEFINE_SPINLOCK(sh_mtu2_lock); + +#define TSTR -1 /* shared register */ +#define TCR 0 /* channel register */ +#define TMDR 1 /* channel register */ +#define TIOR 2 /* channel register */ +#define TIER 3 /* channel register */ +#define TSR 4 /* channel register */ +#define TCNT 5 /* channel register */ +#define TGR 6 /* channel register */ + +static unsigned long mtu2_reg_offs[] = { + [TCR] = 0, + [TMDR] = 1, + [TIOR] = 2, + [TIER] = 4, + [TSR] = 5, + [TCNT] = 6, + [TGR] = 8, +}; + +static inline unsigned long sh_mtu2_read(struct sh_mtu2_priv *p, int reg_nr) +{ + struct sh_timer_config *cfg = p->pdev->dev.platform_data; + void __iomem *base = p->mapbase; + unsigned long offs; + + if (reg_nr == TSTR) + return ioread8(base + cfg->channel_offset); + + offs = mtu2_reg_offs[reg_nr]; + + if ((reg_nr == TCNT) || (reg_nr == TGR)) + return ioread16(base + offs); + else + return ioread8(base + offs); +} + +static inline void sh_mtu2_write(struct sh_mtu2_priv *p, int reg_nr, + unsigned long value) +{ + struct sh_timer_config *cfg = p->pdev->dev.platform_data; + void __iomem *base = p->mapbase; + unsigned long offs; + + if (reg_nr == TSTR) { + iowrite8(value, base + cfg->channel_offset); + return; + } + + offs = mtu2_reg_offs[reg_nr]; + + if ((reg_nr == TCNT) || (reg_nr == TGR)) + iowrite16(value, base + offs); + else + iowrite8(value, base + offs); +} + +static void sh_mtu2_start_stop_ch(struct sh_mtu2_priv *p, int start) +{ + struct sh_timer_config *cfg = p->pdev->dev.platform_data; + unsigned long flags, value; + + /* start stop register shared by multiple timer channels */ + spin_lock_irqsave(&sh_mtu2_lock, flags); + value = sh_mtu2_read(p, TSTR); + + if (start) + value |= 1 << cfg->timer_bit; + else + value &= ~(1 << cfg->timer_bit); + + sh_mtu2_write(p, TSTR, value); + spin_unlock_irqrestore(&sh_mtu2_lock, flags); +} + +static int sh_mtu2_enable(struct sh_mtu2_priv *p) +{ + struct sh_timer_config *cfg = p->pdev->dev.platform_data; + int ret; + + /* enable clock */ + ret = clk_enable(p->clk); + if (ret) { + pr_err("sh_mtu2: cannot enable clock \"%s\"\n", cfg->clk); + return ret; + } + + /* make sure channel is disabled */ + sh_mtu2_start_stop_ch(p, 0); + + p->rate = clk_get_rate(p->clk) / 64; + p->periodic = (p->rate + HZ/2) / HZ; + + /* "Periodic Counter Operation" */ + sh_mtu2_write(p, TCR, 0x23); /* TGRA clear, divide clock by 64 */ + sh_mtu2_write(p, TIOR, 0); + sh_mtu2_write(p, TGR, p->periodic); + sh_mtu2_write(p, TCNT, 0); + sh_mtu2_write(p, TMDR, 0); + sh_mtu2_write(p, TIER, 0x01); + + /* enable channel */ + sh_mtu2_start_stop_ch(p, 1); + + return 0; +} + +static void sh_mtu2_disable(struct sh_mtu2_priv *p) +{ + /* disable channel */ + sh_mtu2_start_stop_ch(p, 0); + + /* stop clock */ + clk_disable(p->clk); +} + +static irqreturn_t sh_mtu2_interrupt(int irq, void *dev_id) +{ + struct sh_mtu2_priv *p = dev_id; + + /* acknowledge interrupt */ + sh_mtu2_read(p, TSR); + sh_mtu2_write(p, TSR, 0xfe); + + /* notify clockevent layer */ + p->ced.event_handler(&p->ced); + return IRQ_HANDLED; +} + +static struct sh_mtu2_priv *ced_to_sh_mtu2(struct clock_event_device *ced) +{ + return container_of(ced, struct sh_mtu2_priv, ced); +} + +static void sh_mtu2_clock_event_mode(enum clock_event_mode mode, + struct clock_event_device *ced) +{ + struct sh_mtu2_priv *p = ced_to_sh_mtu2(ced); + int disabled = 0; + + /* deal with old setting first */ + switch (ced->mode) { + case CLOCK_EVT_MODE_PERIODIC: + sh_mtu2_disable(p); + disabled = 1; + break; + default: + break; + } + + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + pr_info("sh_mtu2: %s used for periodic clock events\n", + ced->name); + sh_mtu2_enable(p); + break; + case CLOCK_EVT_MODE_UNUSED: + if (!disabled) + sh_mtu2_disable(p); + break; + case CLOCK_EVT_MODE_SHUTDOWN: + default: + break; + } +} + +static void sh_mtu2_register_clockevent(struct sh_mtu2_priv *p, + char *name, unsigned long rating) +{ + struct clock_event_device *ced = &p->ced; + int ret; + + memset(ced, 0, sizeof(*ced)); + + ced->name = name; + ced->features = CLOCK_EVT_FEAT_PERIODIC; + ced->rating = rating; + ced->cpumask = cpumask_of(0); + ced->set_mode = sh_mtu2_clock_event_mode; + + ret = setup_irq(p->irqaction.irq, &p->irqaction); + if (ret) { + pr_err("sh_mtu2: failed to request irq %d\n", + p->irqaction.irq); + return; + } + + pr_info("sh_mtu2: %s used for clock events\n", ced->name); + clockevents_register_device(ced); +} + +static int sh_mtu2_register(struct sh_mtu2_priv *p, char *name, + unsigned long clockevent_rating) +{ + if (clockevent_rating) + sh_mtu2_register_clockevent(p, name, clockevent_rating); + + return 0; +} + +static int sh_mtu2_setup(struct sh_mtu2_priv *p, struct platform_device *pdev) +{ + struct sh_timer_config *cfg = pdev->dev.platform_data; + struct resource *res; + int irq, ret; + ret = -ENXIO; + + memset(p, 0, sizeof(*p)); + p->pdev = pdev; + + if (!cfg) { + dev_err(&p->pdev->dev, "missing platform data\n"); + goto err0; + } + + platform_set_drvdata(pdev, p); + + res = platform_get_resource(p->pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&p->pdev->dev, "failed to get I/O memory\n"); + goto err0; + } + + irq = platform_get_irq(p->pdev, 0); + if (irq < 0) { + dev_err(&p->pdev->dev, "failed to get irq\n"); + goto err0; + } + + /* map memory, let mapbase point to our channel */ + p->mapbase = ioremap_nocache(res->start, resource_size(res)); + if (p->mapbase == NULL) { + pr_err("sh_mtu2: failed to remap I/O memory\n"); + goto err0; + } + + /* setup data for setup_irq() (too early for request_irq()) */ + p->irqaction.name = cfg->name; + p->irqaction.handler = sh_mtu2_interrupt; + p->irqaction.dev_id = p; + p->irqaction.irq = irq; + p->irqaction.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL; + + /* get hold of clock */ + p->clk = clk_get(&p->pdev->dev, cfg->clk); + if (IS_ERR(p->clk)) { + pr_err("sh_mtu2: cannot get clock \"%s\"\n", cfg->clk); + ret = PTR_ERR(p->clk); + goto err1; + } + + return sh_mtu2_register(p, cfg->name, cfg->clockevent_rating); + err1: + iounmap(p->mapbase); + err0: + return ret; +} + +static int __devinit sh_mtu2_probe(struct platform_device *pdev) +{ + struct sh_mtu2_priv *p = platform_get_drvdata(pdev); + struct sh_timer_config *cfg = pdev->dev.platform_data; + int ret; + + if (p) { + pr_info("sh_mtu2: %s kept as earlytimer\n", cfg->name); + return 0; + } + + p = kmalloc(sizeof(*p), GFP_KERNEL); + if (p == NULL) { + dev_err(&pdev->dev, "failed to allocate driver data\n"); + return -ENOMEM; + } + + ret = sh_mtu2_setup(p, pdev); + if (ret) { + kfree(p); + platform_set_drvdata(pdev, NULL); + } + return ret; +} + +static int __devexit sh_mtu2_remove(struct platform_device *pdev) +{ + return -EBUSY; /* cannot unregister clockevent */ +} + +static struct platform_driver sh_mtu2_device_driver = { + .probe = sh_mtu2_probe, + .remove = __devexit_p(sh_mtu2_remove), + .driver = { + .name = "sh_mtu2", + } +}; + +static int __init sh_mtu2_init(void) +{ + return platform_driver_register(&sh_mtu2_device_driver); +} + +static void __exit sh_mtu2_exit(void) +{ + platform_driver_unregister(&sh_mtu2_device_driver); +} + +early_platform_init("earlytimer", &sh_mtu2_device_driver); +module_init(sh_mtu2_init); +module_exit(sh_mtu2_exit); + +MODULE_AUTHOR("Magnus Damm"); +MODULE_DESCRIPTION("SuperH MTU2 Timer Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clocksource/sh_tmu.c b/drivers/clocksource/sh_tmu.c new file mode 100644 index 000000000000..9ffb05f4095d --- /dev/null +++ b/drivers/clocksource/sh_tmu.c @@ -0,0 +1,463 @@ +/* + * SuperH Timer Support - TMU + * + * Copyright (C) 2009 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 of the License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct sh_tmu_priv { + void __iomem *mapbase; + struct clk *clk; + struct irqaction irqaction; + struct platform_device *pdev; + unsigned long rate; + unsigned long periodic; + struct clock_event_device ced; + struct clocksource cs; +}; + +static DEFINE_SPINLOCK(sh_tmu_lock); + +#define TSTR -1 /* shared register */ +#define TCOR 0 /* channel register */ +#define TCNT 1 /* channel register */ +#define TCR 2 /* channel register */ + +static inline unsigned long sh_tmu_read(struct sh_tmu_priv *p, int reg_nr) +{ + struct sh_timer_config *cfg = p->pdev->dev.platform_data; + void __iomem *base = p->mapbase; + unsigned long offs; + + if (reg_nr == TSTR) + return ioread8(base - cfg->channel_offset); + + offs = reg_nr << 2; + + if (reg_nr == TCR) + return ioread16(base + offs); + else + return ioread32(base + offs); +} + +static inline void sh_tmu_write(struct sh_tmu_priv *p, int reg_nr, + unsigned long value) +{ + struct sh_timer_config *cfg = p->pdev->dev.platform_data; + void __iomem *base = p->mapbase; + unsigned long offs; + + if (reg_nr == TSTR) { + iowrite8(value, base - cfg->channel_offset); + return; + } + + offs = reg_nr << 2; + + if (reg_nr == TCR) + iowrite16(value, base + offs); + else + iowrite32(value, base + offs); +} + +static void sh_tmu_start_stop_ch(struct sh_tmu_priv *p, int start) +{ + struct sh_timer_config *cfg = p->pdev->dev.platform_data; + unsigned long flags, value; + + /* start stop register shared by multiple timer channels */ + spin_lock_irqsave(&sh_tmu_lock, flags); + value = sh_tmu_read(p, TSTR); + + if (start) + value |= 1 << cfg->timer_bit; + else + value &= ~(1 << cfg->timer_bit); + + sh_tmu_write(p, TSTR, value); + spin_unlock_irqrestore(&sh_tmu_lock, flags); +} + +static int sh_tmu_enable(struct sh_tmu_priv *p) +{ + struct sh_timer_config *cfg = p->pdev->dev.platform_data; + int ret; + + /* enable clock */ + ret = clk_enable(p->clk); + if (ret) { + pr_err("sh_tmu: cannot enable clock \"%s\"\n", cfg->clk); + return ret; + } + + /* make sure channel is disabled */ + sh_tmu_start_stop_ch(p, 0); + + /* maximum timeout */ + sh_tmu_write(p, TCOR, 0xffffffff); + sh_tmu_write(p, TCNT, 0xffffffff); + + /* configure channel to parent clock / 4, irq off */ + p->rate = clk_get_rate(p->clk) / 4; + sh_tmu_write(p, TCR, 0x0000); + + /* enable channel */ + sh_tmu_start_stop_ch(p, 1); + + return 0; +} + +static void sh_tmu_disable(struct sh_tmu_priv *p) +{ + /* disable channel */ + sh_tmu_start_stop_ch(p, 0); + + /* disable interrupts in TMU block */ + sh_tmu_write(p, TCR, 0x0000); + + /* stop clock */ + clk_disable(p->clk); +} + +static void sh_tmu_set_next(struct sh_tmu_priv *p, unsigned long delta, + int periodic) +{ + /* stop timer */ + sh_tmu_start_stop_ch(p, 0); + + /* acknowledge interrupt */ + sh_tmu_read(p, TCR); + + /* enable interrupt */ + sh_tmu_write(p, TCR, 0x0020); + + /* reload delta value in case of periodic timer */ + if (periodic) + sh_tmu_write(p, TCOR, delta); + else + sh_tmu_write(p, TCOR, 0); + + sh_tmu_write(p, TCNT, delta); + + /* start timer */ + sh_tmu_start_stop_ch(p, 1); +} + +static irqreturn_t sh_tmu_interrupt(int irq, void *dev_id) +{ + struct sh_tmu_priv *p = dev_id; + + /* disable or acknowledge interrupt */ + if (p->ced.mode == CLOCK_EVT_MODE_ONESHOT) + sh_tmu_write(p, TCR, 0x0000); + else + sh_tmu_write(p, TCR, 0x0020); + + /* notify clockevent layer */ + p->ced.event_handler(&p->ced); + return IRQ_HANDLED; +} + +static struct sh_tmu_priv *cs_to_sh_tmu(struct clocksource *cs) +{ + return container_of(cs, struct sh_tmu_priv, cs); +} + +static cycle_t sh_tmu_clocksource_read(struct clocksource *cs) +{ + struct sh_tmu_priv *p = cs_to_sh_tmu(cs); + + return sh_tmu_read(p, TCNT) ^ 0xffffffff; +} + +static int sh_tmu_clocksource_enable(struct clocksource *cs) +{ + struct sh_tmu_priv *p = cs_to_sh_tmu(cs); + int ret; + + ret = sh_tmu_enable(p); + if (ret) + return ret; + + /* TODO: calculate good shift from rate and counter bit width */ + cs->shift = 10; + cs->mult = clocksource_hz2mult(p->rate, cs->shift); + return 0; +} + +static void sh_tmu_clocksource_disable(struct clocksource *cs) +{ + sh_tmu_disable(cs_to_sh_tmu(cs)); +} + +static int sh_tmu_register_clocksource(struct sh_tmu_priv *p, + char *name, unsigned long rating) +{ + struct clocksource *cs = &p->cs; + + cs->name = name; + cs->rating = rating; + cs->read = sh_tmu_clocksource_read; + cs->enable = sh_tmu_clocksource_enable; + cs->disable = sh_tmu_clocksource_disable; + cs->mask = CLOCKSOURCE_MASK(32); + cs->flags = CLOCK_SOURCE_IS_CONTINUOUS; + pr_info("sh_tmu: %s used as clock source\n", cs->name); + clocksource_register(cs); + return 0; +} + +static struct sh_tmu_priv *ced_to_sh_tmu(struct clock_event_device *ced) +{ + return container_of(ced, struct sh_tmu_priv, ced); +} + +static void sh_tmu_clock_event_start(struct sh_tmu_priv *p, int periodic) +{ + struct clock_event_device *ced = &p->ced; + + sh_tmu_enable(p); + + /* TODO: calculate good shift from rate and counter bit width */ + + ced->shift = 32; + ced->mult = div_sc(p->rate, NSEC_PER_SEC, ced->shift); + ced->max_delta_ns = clockevent_delta2ns(0xffffffff, ced); + ced->min_delta_ns = 5000; + + if (periodic) { + p->periodic = (p->rate + HZ/2) / HZ; + sh_tmu_set_next(p, p->periodic, 1); + } +} + +static void sh_tmu_clock_event_mode(enum clock_event_mode mode, + struct clock_event_device *ced) +{ + struct sh_tmu_priv *p = ced_to_sh_tmu(ced); + int disabled = 0; + + /* deal with old setting first */ + switch (ced->mode) { + case CLOCK_EVT_MODE_PERIODIC: + case CLOCK_EVT_MODE_ONESHOT: + sh_tmu_disable(p); + disabled = 1; + break; + default: + break; + } + + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + pr_info("sh_tmu: %s used for periodic clock events\n", + ced->name); + sh_tmu_clock_event_start(p, 1); + break; + case CLOCK_EVT_MODE_ONESHOT: + pr_info("sh_tmu: %s used for oneshot clock events\n", + ced->name); + sh_tmu_clock_event_start(p, 0); + break; + case CLOCK_EVT_MODE_UNUSED: + if (!disabled) + sh_tmu_disable(p); + break; + case CLOCK_EVT_MODE_SHUTDOWN: + default: + break; + } +} + +static int sh_tmu_clock_event_next(unsigned long delta, + struct clock_event_device *ced) +{ + struct sh_tmu_priv *p = ced_to_sh_tmu(ced); + + BUG_ON(ced->mode != CLOCK_EVT_MODE_ONESHOT); + + /* program new delta value */ + sh_tmu_set_next(p, delta, 0); + return 0; +} + +static void sh_tmu_register_clockevent(struct sh_tmu_priv *p, + char *name, unsigned long rating) +{ + struct clock_event_device *ced = &p->ced; + int ret; + + memset(ced, 0, sizeof(*ced)); + + ced->name = name; + ced->features = CLOCK_EVT_FEAT_PERIODIC; + ced->features |= CLOCK_EVT_FEAT_ONESHOT; + ced->rating = rating; + ced->cpumask = cpumask_of(0); + ced->set_next_event = sh_tmu_clock_event_next; + ced->set_mode = sh_tmu_clock_event_mode; + + ret = setup_irq(p->irqaction.irq, &p->irqaction); + if (ret) { + pr_err("sh_tmu: failed to request irq %d\n", + p->irqaction.irq); + return; + } + + pr_info("sh_tmu: %s used for clock events\n", ced->name); + clockevents_register_device(ced); +} + +static int sh_tmu_register(struct sh_tmu_priv *p, char *name, + unsigned long clockevent_rating, + unsigned long clocksource_rating) +{ + if (clockevent_rating) + sh_tmu_register_clockevent(p, name, clockevent_rating); + else if (clocksource_rating) + sh_tmu_register_clocksource(p, name, clocksource_rating); + + return 0; +} + +static int sh_tmu_setup(struct sh_tmu_priv *p, struct platform_device *pdev) +{ + struct sh_timer_config *cfg = pdev->dev.platform_data; + struct resource *res; + int irq, ret; + ret = -ENXIO; + + memset(p, 0, sizeof(*p)); + p->pdev = pdev; + + if (!cfg) { + dev_err(&p->pdev->dev, "missing platform data\n"); + goto err0; + } + + platform_set_drvdata(pdev, p); + + res = platform_get_resource(p->pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&p->pdev->dev, "failed to get I/O memory\n"); + goto err0; + } + + irq = platform_get_irq(p->pdev, 0); + if (irq < 0) { + dev_err(&p->pdev->dev, "failed to get irq\n"); + goto err0; + } + + /* map memory, let mapbase point to our channel */ + p->mapbase = ioremap_nocache(res->start, resource_size(res)); + if (p->mapbase == NULL) { + pr_err("sh_tmu: failed to remap I/O memory\n"); + goto err0; + } + + /* setup data for setup_irq() (too early for request_irq()) */ + p->irqaction.name = cfg->name; + p->irqaction.handler = sh_tmu_interrupt; + p->irqaction.dev_id = p; + p->irqaction.irq = irq; + p->irqaction.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL; + + /* get hold of clock */ + p->clk = clk_get(&p->pdev->dev, cfg->clk); + if (IS_ERR(p->clk)) { + pr_err("sh_tmu: cannot get clock \"%s\"\n", cfg->clk); + ret = PTR_ERR(p->clk); + goto err1; + } + + return sh_tmu_register(p, cfg->name, + cfg->clockevent_rating, + cfg->clocksource_rating); + err1: + iounmap(p->mapbase); + err0: + return ret; +} + +static int __devinit sh_tmu_probe(struct platform_device *pdev) +{ + struct sh_tmu_priv *p = platform_get_drvdata(pdev); + struct sh_timer_config *cfg = pdev->dev.platform_data; + int ret; + + if (p) { + pr_info("sh_tmu: %s kept as earlytimer\n", cfg->name); + return 0; + } + + p = kmalloc(sizeof(*p), GFP_KERNEL); + if (p == NULL) { + dev_err(&pdev->dev, "failed to allocate driver data\n"); + return -ENOMEM; + } + + ret = sh_tmu_setup(p, pdev); + if (ret) { + kfree(p); + platform_set_drvdata(pdev, NULL); + } + return ret; +} + +static int __devexit sh_tmu_remove(struct platform_device *pdev) +{ + return -EBUSY; /* cannot unregister clockevent and clocksource */ +} + +static struct platform_driver sh_tmu_device_driver = { + .probe = sh_tmu_probe, + .remove = __devexit_p(sh_tmu_remove), + .driver = { + .name = "sh_tmu", + } +}; + +static int __init sh_tmu_init(void) +{ + return platform_driver_register(&sh_tmu_device_driver); +} + +static void __exit sh_tmu_exit(void) +{ + platform_driver_unregister(&sh_tmu_device_driver); +} + +early_platform_init("earlytimer", &sh_tmu_device_driver); +module_init(sh_tmu_init); +module_exit(sh_tmu_exit); + +MODULE_AUTHOR("Magnus Damm"); +MODULE_DESCRIPTION("SuperH TMU Timer Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/connector/Kconfig b/drivers/connector/Kconfig index 100bfd422066..6e6730f9dfd1 100644 --- a/drivers/connector/Kconfig +++ b/drivers/connector/Kconfig @@ -7,7 +7,7 @@ menuconfig CONNECTOR of the netlink socket protocol. Connector support can also be built as a module. If so, the module - will be called cn.ko. + will be called cn. if CONNECTOR diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c index 7a74d175287b..7fc58af748b4 100644 --- a/drivers/cpufreq/cpufreq_conservative.c +++ b/drivers/cpufreq/cpufreq_conservative.c @@ -42,27 +42,12 @@ * this governor will not work. * All times here are in uS. */ -static unsigned int def_sampling_rate; #define MIN_SAMPLING_RATE_RATIO (2) -/* for correct statistics, we need at least 10 ticks between each measure */ -#define MIN_STAT_SAMPLING_RATE \ - (MIN_SAMPLING_RATE_RATIO * jiffies_to_usecs(10)) -#define MIN_SAMPLING_RATE \ - (def_sampling_rate / MIN_SAMPLING_RATE_RATIO) -/* Above MIN_SAMPLING_RATE will vanish with its sysfs file soon - * Define the minimal settable sampling rate to the greater of: - * - "HW transition latency" * 100 (same as default sampling / 10) - * - MIN_STAT_SAMPLING_RATE - * To avoid that userspace shoots itself. -*/ -static unsigned int minimum_sampling_rate(void) -{ - return max(def_sampling_rate / 10, MIN_STAT_SAMPLING_RATE); -} -/* This will also vanish soon with removing sampling_rate_max */ -#define MAX_SAMPLING_RATE (500 * def_sampling_rate) +static unsigned int min_sampling_rate; + #define LATENCY_MULTIPLIER (1000) +#define MIN_LATENCY_MULTIPLIER (100) #define DEF_SAMPLING_DOWN_FACTOR (1) #define MAX_SAMPLING_DOWN_FACTOR (10) #define TRANSITION_LATENCY_LIMIT (10 * 1000 * 1000) @@ -182,27 +167,14 @@ static struct notifier_block dbs_cpufreq_notifier_block = { /************************** sysfs interface ************************/ static ssize_t show_sampling_rate_max(struct cpufreq_policy *policy, char *buf) { - static int print_once; - - if (!print_once) { - printk(KERN_INFO "CPUFREQ: conservative sampling_rate_max " - "sysfs file is deprecated - used by: %s\n", - current->comm); - print_once = 1; - } - return sprintf(buf, "%u\n", MAX_SAMPLING_RATE); + printk_once(KERN_INFO "CPUFREQ: conservative sampling_rate_max " + "sysfs file is deprecated - used by: %s\n", current->comm); + return sprintf(buf, "%u\n", -1U); } static ssize_t show_sampling_rate_min(struct cpufreq_policy *policy, char *buf) { - static int print_once; - - if (!print_once) { - printk(KERN_INFO "CPUFREQ: conservative sampling_rate_max " - "sysfs file is deprecated - used by: %s\n", current->comm); - print_once = 1; - } - return sprintf(buf, "%u\n", MIN_SAMPLING_RATE); + return sprintf(buf, "%u\n", min_sampling_rate); } #define define_one_ro(_name) \ @@ -254,7 +226,7 @@ static ssize_t store_sampling_rate(struct cpufreq_policy *unused, return -EINVAL; mutex_lock(&dbs_mutex); - dbs_tuners_ins.sampling_rate = max(input, minimum_sampling_rate()); + dbs_tuners_ins.sampling_rate = max(input, min_sampling_rate); mutex_unlock(&dbs_mutex); return count; @@ -601,11 +573,18 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy, if (latency == 0) latency = 1; - def_sampling_rate = - max(latency * LATENCY_MULTIPLIER, - MIN_STAT_SAMPLING_RATE); - - dbs_tuners_ins.sampling_rate = def_sampling_rate; + /* + * conservative does not implement micro like ondemand + * governor, thus we are bound to jiffes/HZ + */ + min_sampling_rate = + MIN_SAMPLING_RATE_RATIO * jiffies_to_usecs(10); + /* Bring kernel and HW constraints together */ + min_sampling_rate = max(min_sampling_rate, + MIN_LATENCY_MULTIPLIER * latency); + dbs_tuners_ins.sampling_rate = + max(min_sampling_rate, + latency * LATENCY_MULTIPLIER); cpufreq_register_notifier( &dbs_cpufreq_notifier_block, diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index e741c339df76..1911d1729353 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -32,6 +32,7 @@ #define DEF_FREQUENCY_UP_THRESHOLD (80) #define MICRO_FREQUENCY_DOWN_DIFFERENTIAL (3) #define MICRO_FREQUENCY_UP_THRESHOLD (95) +#define MICRO_FREQUENCY_MIN_SAMPLE_RATE (10000) #define MIN_FREQUENCY_UP_THRESHOLD (11) #define MAX_FREQUENCY_UP_THRESHOLD (100) @@ -45,27 +46,12 @@ * this governor will not work. * All times here are in uS. */ -static unsigned int def_sampling_rate; #define MIN_SAMPLING_RATE_RATIO (2) -/* for correct statistics, we need at least 10 ticks between each measure */ -#define MIN_STAT_SAMPLING_RATE \ - (MIN_SAMPLING_RATE_RATIO * jiffies_to_usecs(10)) -#define MIN_SAMPLING_RATE \ - (def_sampling_rate / MIN_SAMPLING_RATE_RATIO) -/* Above MIN_SAMPLING_RATE will vanish with its sysfs file soon - * Define the minimal settable sampling rate to the greater of: - * - "HW transition latency" * 100 (same as default sampling / 10) - * - MIN_STAT_SAMPLING_RATE - * To avoid that userspace shoots itself. -*/ -static unsigned int minimum_sampling_rate(void) -{ - return max(def_sampling_rate / 10, MIN_STAT_SAMPLING_RATE); -} -/* This will also vanish soon with removing sampling_rate_max */ -#define MAX_SAMPLING_RATE (500 * def_sampling_rate) +static unsigned int min_sampling_rate; + #define LATENCY_MULTIPLIER (1000) +#define MIN_LATENCY_MULTIPLIER (100) #define TRANSITION_LATENCY_LIMIT (10 * 1000 * 1000) static void do_dbs_timer(struct work_struct *work); @@ -219,28 +205,14 @@ static void ondemand_powersave_bias_init(void) /************************** sysfs interface ************************/ static ssize_t show_sampling_rate_max(struct cpufreq_policy *policy, char *buf) { - static int print_once; - - if (!print_once) { - printk(KERN_INFO "CPUFREQ: ondemand sampling_rate_max " - "sysfs file is deprecated - used by: %s\n", - current->comm); - print_once = 1; - } - return sprintf(buf, "%u\n", MAX_SAMPLING_RATE); + printk_once(KERN_INFO "CPUFREQ: ondemand sampling_rate_max " + "sysfs file is deprecated - used by: %s\n", current->comm); + return sprintf(buf, "%u\n", -1U); } static ssize_t show_sampling_rate_min(struct cpufreq_policy *policy, char *buf) { - static int print_once; - - if (!print_once) { - printk(KERN_INFO "CPUFREQ: ondemand sampling_rate_min " - "sysfs file is deprecated - used by: %s\n", - current->comm); - print_once = 1; - } - return sprintf(buf, "%u\n", MIN_SAMPLING_RATE); + return sprintf(buf, "%u\n", min_sampling_rate); } #define define_one_ro(_name) \ @@ -274,7 +246,7 @@ static ssize_t store_sampling_rate(struct cpufreq_policy *unused, mutex_unlock(&dbs_mutex); return -EINVAL; } - dbs_tuners_ins.sampling_rate = max(input, minimum_sampling_rate()); + dbs_tuners_ins.sampling_rate = max(input, min_sampling_rate); mutex_unlock(&dbs_mutex); return count; @@ -619,12 +591,12 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy, latency = policy->cpuinfo.transition_latency / 1000; if (latency == 0) latency = 1; - - def_sampling_rate = - max(latency * LATENCY_MULTIPLIER, - MIN_STAT_SAMPLING_RATE); - - dbs_tuners_ins.sampling_rate = def_sampling_rate; + /* Bring kernel and HW constraints together */ + min_sampling_rate = max(min_sampling_rate, + MIN_LATENCY_MULTIPLIER * latency); + dbs_tuners_ins.sampling_rate = + max(min_sampling_rate, + latency * LATENCY_MULTIPLIER); } dbs_timer_init(this_dbs_info); @@ -678,6 +650,16 @@ static int __init cpufreq_gov_dbs_init(void) dbs_tuners_ins.up_threshold = MICRO_FREQUENCY_UP_THRESHOLD; dbs_tuners_ins.down_differential = MICRO_FREQUENCY_DOWN_DIFFERENTIAL; + /* + * In no_hz/micro accounting case we set the minimum frequency + * not depending on HZ, but fixed (very low). The deferred + * timer might skip some samples if idle/sleeping as needed. + */ + min_sampling_rate = MICRO_FREQUENCY_MIN_SAMPLE_RATE; + } else { + /* For correct statistics, we need 10 ticks for each measure */ + min_sampling_rate = + MIN_SAMPLING_RATE_RATIO * jiffies_to_usecs(10); } kondemand_wq = create_workqueue("kondemand"); diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 01afd758072f..5b27692372bf 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -12,7 +12,7 @@ if CRYPTO_HW config CRYPTO_DEV_PADLOCK tristate "Support for VIA PadLock ACE" - depends on X86_32 && !UML + depends on X86 && !UML select CRYPTO_ALGAPI help Some VIA processors come with an integrated crypto engine @@ -34,7 +34,7 @@ config CRYPTO_DEV_PADLOCK_AES Available in VIA C3 and newer CPUs. If unsure say M. The compiled module will be - called padlock-aes.ko + called padlock-aes. config CRYPTO_DEV_PADLOCK_SHA tristate "PadLock driver for SHA1 and SHA256 algorithms" @@ -47,7 +47,7 @@ config CRYPTO_DEV_PADLOCK_SHA Available in VIA C7 and newer processors. If unsure say M. The compiled module will be - called padlock-sha.ko + called padlock-sha. config CRYPTO_DEV_GEODE tristate "Support for the Geode LX AES engine" @@ -79,7 +79,7 @@ config ZCRYPT_MONOLITHIC bool "Monolithic zcrypt module" depends on ZCRYPT="m" help - Select this option if you want to have a single module z90crypt.ko + Select this option if you want to have a single module z90crypt, that contains all parts of the crypto device driver (ap bus, request router and all the card drivers). diff --git a/drivers/crypto/hifn_795x.c b/drivers/crypto/hifn_795x.c index 2bef086fb342..5f753fc08730 100644 --- a/drivers/crypto/hifn_795x.c +++ b/drivers/crypto/hifn_795x.c @@ -2564,7 +2564,7 @@ static void hifn_tasklet_callback(unsigned long data) hifn_process_queue(dev); } -static int hifn_probe(struct pci_dev *pdev, const struct pci_device_id *id) +static int __devinit hifn_probe(struct pci_dev *pdev, const struct pci_device_id *id) { int err, i; struct hifn_device *dev; @@ -2696,7 +2696,7 @@ err_out_disable_pci_device: return err; } -static void hifn_remove(struct pci_dev *pdev) +static void __devexit hifn_remove(struct pci_dev *pdev) { int i; struct hifn_device *dev; @@ -2744,7 +2744,7 @@ static struct pci_driver hifn_pci_driver = { .remove = __devexit_p(hifn_remove), }; -static int __devinit hifn_init(void) +static int __init hifn_init(void) { unsigned int freq; int err; @@ -2789,7 +2789,7 @@ static int __devinit hifn_init(void) return 0; } -static void __devexit hifn_fini(void) +static void __exit hifn_fini(void) { pci_unregister_driver(&hifn_pci_driver); diff --git a/drivers/crypto/padlock-aes.c b/drivers/crypto/padlock-aes.c index 856b3cc25583..a9952b1236b0 100644 --- a/drivers/crypto/padlock-aes.c +++ b/drivers/crypto/padlock-aes.c @@ -18,9 +18,22 @@ #include #include #include +#include #include #include "padlock.h" +/* + * Number of data blocks actually fetched for each xcrypt insn. + * Processors with prefetch errata will fetch extra blocks. + */ +static unsigned int ecb_fetch_blocks = 2; +#define MAX_ECB_FETCH_BLOCKS (8) +#define ecb_fetch_bytes (ecb_fetch_blocks * AES_BLOCK_SIZE) + +static unsigned int cbc_fetch_blocks = 1; +#define MAX_CBC_FETCH_BLOCKS (4) +#define cbc_fetch_bytes (cbc_fetch_blocks * AES_BLOCK_SIZE) + /* Control word. */ struct cword { unsigned int __attribute__ ((__packed__)) @@ -154,7 +167,11 @@ static inline void padlock_reset_key(struct cword *cword) int cpu = raw_smp_processor_id(); if (cword != per_cpu(last_cword, cpu)) +#ifndef CONFIG_X86_64 asm volatile ("pushfl; popfl"); +#else + asm volatile ("pushfq; popfq"); +#endif } static inline void padlock_store_cword(struct cword *cword) @@ -168,64 +185,111 @@ static inline void padlock_store_cword(struct cword *cword) * should be used only inside the irq_ts_save/restore() context */ -static inline void padlock_xcrypt(const u8 *input, u8 *output, void *key, - struct cword *control_word) +static inline void rep_xcrypt_ecb(const u8 *input, u8 *output, void *key, + struct cword *control_word, int count) { asm volatile (".byte 0xf3,0x0f,0xa7,0xc8" /* rep xcryptecb */ : "+S"(input), "+D"(output) - : "d"(control_word), "b"(key), "c"(1)); + : "d"(control_word), "b"(key), "c"(count)); } -static void aes_crypt_copy(const u8 *in, u8 *out, u32 *key, struct cword *cword) +static inline u8 *rep_xcrypt_cbc(const u8 *input, u8 *output, void *key, + u8 *iv, struct cword *control_word, int count) { - u8 buf[AES_BLOCK_SIZE * 2 + PADLOCK_ALIGNMENT - 1]; + asm volatile (".byte 0xf3,0x0f,0xa7,0xd0" /* rep xcryptcbc */ + : "+S" (input), "+D" (output), "+a" (iv) + : "d" (control_word), "b" (key), "c" (count)); + return iv; +} + +static void ecb_crypt_copy(const u8 *in, u8 *out, u32 *key, + struct cword *cword, int count) +{ + /* + * Padlock prefetches extra data so we must provide mapped input buffers. + * Assume there are at least 16 bytes of stack already in use. + */ + u8 buf[AES_BLOCK_SIZE * (MAX_ECB_FETCH_BLOCKS - 1) + PADLOCK_ALIGNMENT - 1]; u8 *tmp = PTR_ALIGN(&buf[0], PADLOCK_ALIGNMENT); - memcpy(tmp, in, AES_BLOCK_SIZE); - padlock_xcrypt(tmp, out, key, cword); + memcpy(tmp, in, count * AES_BLOCK_SIZE); + rep_xcrypt_ecb(tmp, out, key, cword, count); } -static inline void aes_crypt(const u8 *in, u8 *out, u32 *key, - struct cword *cword) +static u8 *cbc_crypt_copy(const u8 *in, u8 *out, u32 *key, + u8 *iv, struct cword *cword, int count) { - /* padlock_xcrypt requires at least two blocks of data. */ - if (unlikely(!(((unsigned long)in ^ (PAGE_SIZE - AES_BLOCK_SIZE)) & - (PAGE_SIZE - 1)))) { - aes_crypt_copy(in, out, key, cword); + /* + * Padlock prefetches extra data so we must provide mapped input buffers. + * Assume there are at least 16 bytes of stack already in use. + */ + u8 buf[AES_BLOCK_SIZE * (MAX_CBC_FETCH_BLOCKS - 1) + PADLOCK_ALIGNMENT - 1]; + u8 *tmp = PTR_ALIGN(&buf[0], PADLOCK_ALIGNMENT); + + memcpy(tmp, in, count * AES_BLOCK_SIZE); + return rep_xcrypt_cbc(tmp, out, key, iv, cword, count); +} + +static inline void ecb_crypt(const u8 *in, u8 *out, u32 *key, + struct cword *cword, int count) +{ + /* Padlock in ECB mode fetches at least ecb_fetch_bytes of data. + * We could avoid some copying here but it's probably not worth it. + */ + if (unlikely(((unsigned long)in & PAGE_SIZE) + ecb_fetch_bytes > PAGE_SIZE)) { + ecb_crypt_copy(in, out, key, cword, count); return; } - padlock_xcrypt(in, out, key, cword); + rep_xcrypt_ecb(in, out, key, cword, count); +} + +static inline u8 *cbc_crypt(const u8 *in, u8 *out, u32 *key, + u8 *iv, struct cword *cword, int count) +{ + /* Padlock in CBC mode fetches at least cbc_fetch_bytes of data. */ + if (unlikely(((unsigned long)in & PAGE_SIZE) + cbc_fetch_bytes > PAGE_SIZE)) + return cbc_crypt_copy(in, out, key, iv, cword, count); + + return rep_xcrypt_cbc(in, out, key, iv, cword, count); } static inline void padlock_xcrypt_ecb(const u8 *input, u8 *output, void *key, void *control_word, u32 count) { - if (count == 1) { - aes_crypt(input, output, key, control_word); + u32 initial = count & (ecb_fetch_blocks - 1); + + if (count < ecb_fetch_blocks) { + ecb_crypt(input, output, key, control_word, count); return; } - asm volatile ("test $1, %%cl;" - "je 1f;" - "lea -1(%%ecx), %%eax;" - "mov $1, %%ecx;" - ".byte 0xf3,0x0f,0xa7,0xc8;" /* rep xcryptecb */ - "mov %%eax, %%ecx;" - "1:" - ".byte 0xf3,0x0f,0xa7,0xc8" /* rep xcryptecb */ + if (initial) + asm volatile (".byte 0xf3,0x0f,0xa7,0xc8" /* rep xcryptecb */ + : "+S"(input), "+D"(output) + : "d"(control_word), "b"(key), "c"(initial)); + + asm volatile (".byte 0xf3,0x0f,0xa7,0xc8" /* rep xcryptecb */ : "+S"(input), "+D"(output) - : "d"(control_word), "b"(key), "c"(count) - : "ax"); + : "d"(control_word), "b"(key), "c"(count - initial)); } static inline u8 *padlock_xcrypt_cbc(const u8 *input, u8 *output, void *key, u8 *iv, void *control_word, u32 count) { - /* rep xcryptcbc */ - asm volatile (".byte 0xf3,0x0f,0xa7,0xd0" + u32 initial = count & (cbc_fetch_blocks - 1); + + if (count < cbc_fetch_blocks) + return cbc_crypt(input, output, key, iv, control_word, count); + + if (initial) + asm volatile (".byte 0xf3,0x0f,0xa7,0xd0" /* rep xcryptcbc */ + : "+S" (input), "+D" (output), "+a" (iv) + : "d" (control_word), "b" (key), "c" (count)); + + asm volatile (".byte 0xf3,0x0f,0xa7,0xd0" /* rep xcryptcbc */ : "+S" (input), "+D" (output), "+a" (iv) - : "d" (control_word), "b" (key), "c" (count)); + : "d" (control_word), "b" (key), "c" (count-initial)); return iv; } @@ -236,7 +300,7 @@ static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) padlock_reset_key(&ctx->cword.encrypt); ts_state = irq_ts_save(); - aes_crypt(in, out, ctx->E, &ctx->cword.encrypt); + ecb_crypt(in, out, ctx->E, &ctx->cword.encrypt, 1); irq_ts_restore(ts_state); padlock_store_cword(&ctx->cword.encrypt); } @@ -248,7 +312,7 @@ static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) padlock_reset_key(&ctx->cword.encrypt); ts_state = irq_ts_save(); - aes_crypt(in, out, ctx->D, &ctx->cword.decrypt); + ecb_crypt(in, out, ctx->D, &ctx->cword.decrypt, 1); irq_ts_restore(ts_state); padlock_store_cword(&ctx->cword.encrypt); } @@ -441,6 +505,7 @@ static struct crypto_alg cbc_aes_alg = { static int __init padlock_init(void) { int ret; + struct cpuinfo_x86 *c = &cpu_data(0); if (!cpu_has_xcrypt) { printk(KERN_NOTICE PFX "VIA PadLock not detected.\n"); @@ -463,6 +528,12 @@ static int __init padlock_init(void) printk(KERN_NOTICE PFX "Using VIA PadLock ACE for AES algorithm.\n"); + if (c->x86 == 6 && c->x86_model == 15 && c->x86_mask == 2) { + ecb_fetch_blocks = MAX_ECB_FETCH_BLOCKS; + cbc_fetch_blocks = MAX_CBC_FETCH_BLOCKS; + printk(KERN_NOTICE PFX "VIA Nano stepping 2 detected: enabling workaround.\n"); + } + out: return ret; diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index a3918c16b3db..c70775fd3ce2 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -44,6 +44,8 @@ #include #include #include +#include +#include #include "talitos.h" @@ -339,7 +341,8 @@ static void flush_channel(struct device *dev, int ch, int error, int reset_ch) status = error; dma_unmap_single(dev, request->dma_desc, - sizeof(struct talitos_desc), DMA_BIDIRECTIONAL); + sizeof(struct talitos_desc), + DMA_BIDIRECTIONAL); /* copy entries so we can call callback outside lock */ saved_req.desc = request->desc; @@ -413,7 +416,8 @@ static struct talitos_desc *current_desc(struct device *dev, int ch) /* * user diagnostics; report root cause of error based on execution unit status */ -static void report_eu_error(struct device *dev, int ch, struct talitos_desc *desc) +static void report_eu_error(struct device *dev, int ch, + struct talitos_desc *desc) { struct talitos_private *priv = dev_get_drvdata(dev); int i; @@ -684,8 +688,8 @@ struct talitos_ctx { unsigned int authsize; }; -static int aead_authenc_setauthsize(struct crypto_aead *authenc, - unsigned int authsize) +static int aead_setauthsize(struct crypto_aead *authenc, + unsigned int authsize) { struct talitos_ctx *ctx = crypto_aead_ctx(authenc); @@ -694,8 +698,8 @@ static int aead_authenc_setauthsize(struct crypto_aead *authenc, return 0; } -static int aead_authenc_setkey(struct crypto_aead *authenc, - const u8 *key, unsigned int keylen) +static int aead_setkey(struct crypto_aead *authenc, + const u8 *key, unsigned int keylen) { struct talitos_ctx *ctx = crypto_aead_ctx(authenc); struct rtattr *rta = (void *)key; @@ -740,7 +744,7 @@ badkey: } /* - * ipsec_esp_edesc - s/w-extended ipsec_esp descriptor + * talitos_edesc - s/w-extended descriptor * @src_nents: number of segments in input scatterlist * @dst_nents: number of segments in output scatterlist * @dma_len: length of dma mapped link_tbl space @@ -752,17 +756,67 @@ badkey: * is greater than 1, an integrity check value is concatenated to the end * of link_tbl data */ -struct ipsec_esp_edesc { +struct talitos_edesc { int src_nents; int dst_nents; + int src_is_chained; + int dst_is_chained; int dma_len; dma_addr_t dma_link_tbl; struct talitos_desc desc; struct talitos_ptr link_tbl[0]; }; +static int talitos_map_sg(struct device *dev, struct scatterlist *sg, + unsigned int nents, enum dma_data_direction dir, + int chained) +{ + if (unlikely(chained)) + while (sg) { + dma_map_sg(dev, sg, 1, dir); + sg = scatterwalk_sg_next(sg); + } + else + dma_map_sg(dev, sg, nents, dir); + return nents; +} + +static void talitos_unmap_sg_chain(struct device *dev, struct scatterlist *sg, + enum dma_data_direction dir) +{ + while (sg) { + dma_unmap_sg(dev, sg, 1, dir); + sg = scatterwalk_sg_next(sg); + } +} + +static void talitos_sg_unmap(struct device *dev, + struct talitos_edesc *edesc, + struct scatterlist *src, + struct scatterlist *dst) +{ + unsigned int src_nents = edesc->src_nents ? : 1; + unsigned int dst_nents = edesc->dst_nents ? : 1; + + if (src != dst) { + if (edesc->src_is_chained) + talitos_unmap_sg_chain(dev, src, DMA_TO_DEVICE); + else + dma_unmap_sg(dev, src, src_nents, DMA_TO_DEVICE); + + if (edesc->dst_is_chained) + talitos_unmap_sg_chain(dev, dst, DMA_FROM_DEVICE); + else + dma_unmap_sg(dev, dst, dst_nents, DMA_FROM_DEVICE); + } else + if (edesc->src_is_chained) + talitos_unmap_sg_chain(dev, src, DMA_BIDIRECTIONAL); + else + dma_unmap_sg(dev, src, src_nents, DMA_BIDIRECTIONAL); +} + static void ipsec_esp_unmap(struct device *dev, - struct ipsec_esp_edesc *edesc, + struct talitos_edesc *edesc, struct aead_request *areq) { unmap_single_talitos_ptr(dev, &edesc->desc.ptr[6], DMA_FROM_DEVICE); @@ -772,15 +826,7 @@ static void ipsec_esp_unmap(struct device *dev, dma_unmap_sg(dev, areq->assoc, 1, DMA_TO_DEVICE); - if (areq->src != areq->dst) { - dma_unmap_sg(dev, areq->src, edesc->src_nents ? : 1, - DMA_TO_DEVICE); - dma_unmap_sg(dev, areq->dst, edesc->dst_nents ? : 1, - DMA_FROM_DEVICE); - } else { - dma_unmap_sg(dev, areq->src, edesc->src_nents ? : 1, - DMA_BIDIRECTIONAL); - } + talitos_sg_unmap(dev, edesc, areq->src, areq->dst); if (edesc->dma_len) dma_unmap_single(dev, edesc->dma_link_tbl, edesc->dma_len, @@ -795,13 +841,14 @@ static void ipsec_esp_encrypt_done(struct device *dev, int err) { struct aead_request *areq = context; - struct ipsec_esp_edesc *edesc = - container_of(desc, struct ipsec_esp_edesc, desc); struct crypto_aead *authenc = crypto_aead_reqtfm(areq); struct talitos_ctx *ctx = crypto_aead_ctx(authenc); + struct talitos_edesc *edesc; struct scatterlist *sg; void *icvdata; + edesc = container_of(desc, struct talitos_edesc, desc); + ipsec_esp_unmap(dev, edesc, areq); /* copy the generated ICV to dst */ @@ -819,17 +866,18 @@ static void ipsec_esp_encrypt_done(struct device *dev, } static void ipsec_esp_decrypt_swauth_done(struct device *dev, - struct talitos_desc *desc, void *context, - int err) + struct talitos_desc *desc, + void *context, int err) { struct aead_request *req = context; - struct ipsec_esp_edesc *edesc = - container_of(desc, struct ipsec_esp_edesc, desc); struct crypto_aead *authenc = crypto_aead_reqtfm(req); struct talitos_ctx *ctx = crypto_aead_ctx(authenc); + struct talitos_edesc *edesc; struct scatterlist *sg; void *icvdata; + edesc = container_of(desc, struct talitos_edesc, desc); + ipsec_esp_unmap(dev, edesc, req); if (!err) { @@ -851,20 +899,20 @@ static void ipsec_esp_decrypt_swauth_done(struct device *dev, } static void ipsec_esp_decrypt_hwauth_done(struct device *dev, - struct talitos_desc *desc, void *context, - int err) + struct talitos_desc *desc, + void *context, int err) { struct aead_request *req = context; - struct ipsec_esp_edesc *edesc = - container_of(desc, struct ipsec_esp_edesc, desc); + struct talitos_edesc *edesc; + + edesc = container_of(desc, struct talitos_edesc, desc); ipsec_esp_unmap(dev, edesc, req); /* check ICV auth status */ - if (!err) - if ((desc->hdr_lo & DESC_HDR_LO_ICCR1_MASK) != - DESC_HDR_LO_ICCR1_PASS) - err = -EBADMSG; + if (!err && ((desc->hdr_lo & DESC_HDR_LO_ICCR1_MASK) != + DESC_HDR_LO_ICCR1_PASS)) + err = -EBADMSG; kfree(edesc); @@ -886,7 +934,7 @@ static int sg_to_link_tbl(struct scatterlist *sg, int sg_count, link_tbl_ptr->j_extent = 0; link_tbl_ptr++; cryptlen -= sg_dma_len(sg); - sg = sg_next(sg); + sg = scatterwalk_sg_next(sg); } /* adjust (decrease) last one (or two) entry's len to cryptlen */ @@ -910,7 +958,7 @@ static int sg_to_link_tbl(struct scatterlist *sg, int sg_count, /* * fill in and submit ipsec_esp descriptor */ -static int ipsec_esp(struct ipsec_esp_edesc *edesc, struct aead_request *areq, +static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq, u8 *giv, u64 seq, void (*callback) (struct device *dev, struct talitos_desc *desc, @@ -952,32 +1000,31 @@ static int ipsec_esp(struct ipsec_esp_edesc *edesc, struct aead_request *areq, desc->ptr[4].len = cpu_to_be16(cryptlen); desc->ptr[4].j_extent = authsize; - if (areq->src == areq->dst) - sg_count = dma_map_sg(dev, areq->src, edesc->src_nents ? : 1, - DMA_BIDIRECTIONAL); - else - sg_count = dma_map_sg(dev, areq->src, edesc->src_nents ? : 1, - DMA_TO_DEVICE); + sg_count = talitos_map_sg(dev, areq->src, edesc->src_nents ? : 1, + (areq->src == areq->dst) ? DMA_BIDIRECTIONAL + : DMA_TO_DEVICE, + edesc->src_is_chained); if (sg_count == 1) { desc->ptr[4].ptr = cpu_to_be32(sg_dma_address(areq->src)); } else { sg_link_tbl_len = cryptlen; - if ((edesc->desc.hdr & DESC_HDR_MODE1_MDEU_CICV) && - (edesc->desc.hdr & DESC_HDR_MODE0_ENCRYPT) == 0) { + if (edesc->desc.hdr & DESC_HDR_MODE1_MDEU_CICV) sg_link_tbl_len = cryptlen + authsize; - } + sg_count = sg_to_link_tbl(areq->src, sg_count, sg_link_tbl_len, &edesc->link_tbl[0]); if (sg_count > 1) { desc->ptr[4].j_extent |= DESC_PTR_LNKTBL_JUMP; desc->ptr[4].ptr = cpu_to_be32(edesc->dma_link_tbl); - dma_sync_single_for_device(ctx->dev, edesc->dma_link_tbl, - edesc->dma_len, DMA_BIDIRECTIONAL); + dma_sync_single_for_device(dev, edesc->dma_link_tbl, + edesc->dma_len, + DMA_BIDIRECTIONAL); } else { /* Only one segment now, so no link tbl needed */ - desc->ptr[4].ptr = cpu_to_be32(sg_dma_address(areq->src)); + desc->ptr[4].ptr = cpu_to_be32(sg_dma_address(areq-> + src)); } } @@ -985,10 +1032,11 @@ static int ipsec_esp(struct ipsec_esp_edesc *edesc, struct aead_request *areq, desc->ptr[5].len = cpu_to_be16(cryptlen); desc->ptr[5].j_extent = authsize; - if (areq->src != areq->dst) { - sg_count = dma_map_sg(dev, areq->dst, edesc->dst_nents ? : 1, - DMA_FROM_DEVICE); - } + if (areq->src != areq->dst) + sg_count = talitos_map_sg(dev, areq->dst, + edesc->dst_nents ? : 1, + DMA_FROM_DEVICE, + edesc->dst_is_chained); if (sg_count == 1) { desc->ptr[5].ptr = cpu_to_be32(sg_dma_address(areq->dst)); @@ -1033,49 +1081,55 @@ static int ipsec_esp(struct ipsec_esp_edesc *edesc, struct aead_request *areq, return ret; } - /* * derive number of elements in scatterlist */ -static int sg_count(struct scatterlist *sg_list, int nbytes) +static int sg_count(struct scatterlist *sg_list, int nbytes, int *chained) { struct scatterlist *sg = sg_list; int sg_nents = 0; - while (nbytes) { + *chained = 0; + while (nbytes > 0) { sg_nents++; nbytes -= sg->length; - sg = sg_next(sg); + if (!sg_is_last(sg) && (sg + 1)->length == 0) + *chained = 1; + sg = scatterwalk_sg_next(sg); } return sg_nents; } /* - * allocate and map the ipsec_esp extended descriptor + * allocate and map the extended descriptor */ -static struct ipsec_esp_edesc *ipsec_esp_edesc_alloc(struct aead_request *areq, - int icv_stashing) +static struct talitos_edesc *talitos_edesc_alloc(struct device *dev, + struct scatterlist *src, + struct scatterlist *dst, + unsigned int cryptlen, + unsigned int authsize, + int icv_stashing, + u32 cryptoflags) { - struct crypto_aead *authenc = crypto_aead_reqtfm(areq); - struct talitos_ctx *ctx = crypto_aead_ctx(authenc); - struct ipsec_esp_edesc *edesc; + struct talitos_edesc *edesc; int src_nents, dst_nents, alloc_len, dma_len; - gfp_t flags = areq->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL : + int src_chained, dst_chained = 0; + gfp_t flags = cryptoflags & CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL : GFP_ATOMIC; - if (areq->cryptlen + ctx->authsize > TALITOS_MAX_DATA_LEN) { - dev_err(ctx->dev, "cryptlen exceeds h/w max limit\n"); + if (cryptlen + authsize > TALITOS_MAX_DATA_LEN) { + dev_err(dev, "length exceeds h/w max limit\n"); return ERR_PTR(-EINVAL); } - src_nents = sg_count(areq->src, areq->cryptlen + ctx->authsize); + src_nents = sg_count(src, cryptlen + authsize, &src_chained); src_nents = (src_nents == 1) ? 0 : src_nents; - if (areq->dst == areq->src) { + if (dst == src) { dst_nents = src_nents; } else { - dst_nents = sg_count(areq->dst, areq->cryptlen + ctx->authsize); + dst_nents = sg_count(dst, cryptlen + authsize, &dst_chained); dst_nents = (dst_nents == 1) ? 0 : dst_nents; } @@ -1084,39 +1138,52 @@ static struct ipsec_esp_edesc *ipsec_esp_edesc_alloc(struct aead_request *areq, * allowing for two separate entries for ICV and generated ICV (+ 2), * and the ICV data itself */ - alloc_len = sizeof(struct ipsec_esp_edesc); + alloc_len = sizeof(struct talitos_edesc); if (src_nents || dst_nents) { dma_len = (src_nents + dst_nents + 2) * - sizeof(struct talitos_ptr) + ctx->authsize; + sizeof(struct talitos_ptr) + authsize; alloc_len += dma_len; } else { dma_len = 0; - alloc_len += icv_stashing ? ctx->authsize : 0; + alloc_len += icv_stashing ? authsize : 0; } edesc = kmalloc(alloc_len, GFP_DMA | flags); if (!edesc) { - dev_err(ctx->dev, "could not allocate edescriptor\n"); + dev_err(dev, "could not allocate edescriptor\n"); return ERR_PTR(-ENOMEM); } edesc->src_nents = src_nents; edesc->dst_nents = dst_nents; + edesc->src_is_chained = src_chained; + edesc->dst_is_chained = dst_chained; edesc->dma_len = dma_len; - edesc->dma_link_tbl = dma_map_single(ctx->dev, &edesc->link_tbl[0], + edesc->dma_link_tbl = dma_map_single(dev, &edesc->link_tbl[0], edesc->dma_len, DMA_BIDIRECTIONAL); return edesc; } -static int aead_authenc_encrypt(struct aead_request *req) +static struct talitos_edesc *aead_edesc_alloc(struct aead_request *areq, + int icv_stashing) +{ + struct crypto_aead *authenc = crypto_aead_reqtfm(areq); + struct talitos_ctx *ctx = crypto_aead_ctx(authenc); + + return talitos_edesc_alloc(ctx->dev, areq->src, areq->dst, + areq->cryptlen, ctx->authsize, icv_stashing, + areq->base.flags); +} + +static int aead_encrypt(struct aead_request *req) { struct crypto_aead *authenc = crypto_aead_reqtfm(req); struct talitos_ctx *ctx = crypto_aead_ctx(authenc); - struct ipsec_esp_edesc *edesc; + struct talitos_edesc *edesc; /* allocate extended descriptor */ - edesc = ipsec_esp_edesc_alloc(req, 0); + edesc = aead_edesc_alloc(req, 0); if (IS_ERR(edesc)) return PTR_ERR(edesc); @@ -1126,70 +1193,67 @@ static int aead_authenc_encrypt(struct aead_request *req) return ipsec_esp(edesc, req, NULL, 0, ipsec_esp_encrypt_done); } - - -static int aead_authenc_decrypt(struct aead_request *req) +static int aead_decrypt(struct aead_request *req) { struct crypto_aead *authenc = crypto_aead_reqtfm(req); struct talitos_ctx *ctx = crypto_aead_ctx(authenc); unsigned int authsize = ctx->authsize; struct talitos_private *priv = dev_get_drvdata(ctx->dev); - struct ipsec_esp_edesc *edesc; + struct talitos_edesc *edesc; struct scatterlist *sg; void *icvdata; req->cryptlen -= authsize; /* allocate extended descriptor */ - edesc = ipsec_esp_edesc_alloc(req, 1); + edesc = aead_edesc_alloc(req, 1); if (IS_ERR(edesc)) return PTR_ERR(edesc); if ((priv->features & TALITOS_FTR_HW_AUTH_CHECK) && - (((!edesc->src_nents && !edesc->dst_nents) || - priv->features & TALITOS_FTR_SRC_LINK_TBL_LEN_INCLUDES_EXTENT))) { + ((!edesc->src_nents && !edesc->dst_nents) || + priv->features & TALITOS_FTR_SRC_LINK_TBL_LEN_INCLUDES_EXTENT)) { /* decrypt and check the ICV */ - edesc->desc.hdr = ctx->desc_hdr_template | DESC_HDR_DIR_INBOUND | + edesc->desc.hdr = ctx->desc_hdr_template | + DESC_HDR_DIR_INBOUND | DESC_HDR_MODE1_MDEU_CICV; /* reset integrity check result bits */ edesc->desc.hdr_lo = 0; - return ipsec_esp(edesc, req, NULL, 0, ipsec_esp_decrypt_hwauth_done); + return ipsec_esp(edesc, req, NULL, 0, + ipsec_esp_decrypt_hwauth_done); - } else { - - /* Have to check the ICV with software */ - - edesc->desc.hdr = ctx->desc_hdr_template | DESC_HDR_DIR_INBOUND; - - /* stash incoming ICV for later cmp with ICV generated by the h/w */ - if (edesc->dma_len) - icvdata = &edesc->link_tbl[edesc->src_nents + - edesc->dst_nents + 2]; - else - icvdata = &edesc->link_tbl[0]; - - sg = sg_last(req->src, edesc->src_nents ? : 1); - - memcpy(icvdata, (char *)sg_virt(sg) + sg->length - ctx->authsize, - ctx->authsize); - - return ipsec_esp(edesc, req, NULL, 0, ipsec_esp_decrypt_swauth_done); } + + /* Have to check the ICV with software */ + edesc->desc.hdr = ctx->desc_hdr_template | DESC_HDR_DIR_INBOUND; + + /* stash incoming ICV for later cmp with ICV generated by the h/w */ + if (edesc->dma_len) + icvdata = &edesc->link_tbl[edesc->src_nents + + edesc->dst_nents + 2]; + else + icvdata = &edesc->link_tbl[0]; + + sg = sg_last(req->src, edesc->src_nents ? : 1); + + memcpy(icvdata, (char *)sg_virt(sg) + sg->length - ctx->authsize, + ctx->authsize); + + return ipsec_esp(edesc, req, NULL, 0, ipsec_esp_decrypt_swauth_done); } -static int aead_authenc_givencrypt( - struct aead_givcrypt_request *req) +static int aead_givencrypt(struct aead_givcrypt_request *req) { struct aead_request *areq = &req->areq; struct crypto_aead *authenc = crypto_aead_reqtfm(areq); struct talitos_ctx *ctx = crypto_aead_ctx(authenc); - struct ipsec_esp_edesc *edesc; + struct talitos_edesc *edesc; /* allocate extended descriptor */ - edesc = ipsec_esp_edesc_alloc(areq, 0); + edesc = aead_edesc_alloc(areq, 0); if (IS_ERR(edesc)) return PTR_ERR(edesc); @@ -1204,31 +1268,228 @@ static int aead_authenc_givencrypt( ipsec_esp_encrypt_done); } +static int ablkcipher_setkey(struct crypto_ablkcipher *cipher, + const u8 *key, unsigned int keylen) +{ + struct talitos_ctx *ctx = crypto_ablkcipher_ctx(cipher); + struct ablkcipher_alg *alg = crypto_ablkcipher_alg(cipher); + + if (keylen > TALITOS_MAX_KEY_SIZE) + goto badkey; + + if (keylen < alg->min_keysize || keylen > alg->max_keysize) + goto badkey; + + memcpy(&ctx->key, key, keylen); + ctx->keylen = keylen; + + return 0; + +badkey: + crypto_ablkcipher_set_flags(cipher, CRYPTO_TFM_RES_BAD_KEY_LEN); + return -EINVAL; +} + +static void common_nonsnoop_unmap(struct device *dev, + struct talitos_edesc *edesc, + struct ablkcipher_request *areq) +{ + unmap_single_talitos_ptr(dev, &edesc->desc.ptr[5], DMA_FROM_DEVICE); + unmap_single_talitos_ptr(dev, &edesc->desc.ptr[2], DMA_TO_DEVICE); + unmap_single_talitos_ptr(dev, &edesc->desc.ptr[1], DMA_TO_DEVICE); + + talitos_sg_unmap(dev, edesc, areq->src, areq->dst); + + if (edesc->dma_len) + dma_unmap_single(dev, edesc->dma_link_tbl, edesc->dma_len, + DMA_BIDIRECTIONAL); +} + +static void ablkcipher_done(struct device *dev, + struct talitos_desc *desc, void *context, + int err) +{ + struct ablkcipher_request *areq = context; + struct talitos_edesc *edesc; + + edesc = container_of(desc, struct talitos_edesc, desc); + + common_nonsnoop_unmap(dev, edesc, areq); + + kfree(edesc); + + areq->base.complete(&areq->base, err); +} + +static int common_nonsnoop(struct talitos_edesc *edesc, + struct ablkcipher_request *areq, + u8 *giv, + void (*callback) (struct device *dev, + struct talitos_desc *desc, + void *context, int error)) +{ + struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(areq); + struct talitos_ctx *ctx = crypto_ablkcipher_ctx(cipher); + struct device *dev = ctx->dev; + struct talitos_desc *desc = &edesc->desc; + unsigned int cryptlen = areq->nbytes; + unsigned int ivsize; + int sg_count, ret; + + /* first DWORD empty */ + desc->ptr[0].len = 0; + desc->ptr[0].ptr = 0; + desc->ptr[0].j_extent = 0; + + /* cipher iv */ + ivsize = crypto_ablkcipher_ivsize(cipher); + map_single_talitos_ptr(dev, &desc->ptr[1], ivsize, giv ?: areq->info, 0, + DMA_TO_DEVICE); + + /* cipher key */ + map_single_talitos_ptr(dev, &desc->ptr[2], ctx->keylen, + (char *)&ctx->key, 0, DMA_TO_DEVICE); + + /* + * cipher in + */ + desc->ptr[3].len = cpu_to_be16(cryptlen); + desc->ptr[3].j_extent = 0; + + sg_count = talitos_map_sg(dev, areq->src, edesc->src_nents ? : 1, + (areq->src == areq->dst) ? DMA_BIDIRECTIONAL + : DMA_TO_DEVICE, + edesc->src_is_chained); + + if (sg_count == 1) { + desc->ptr[3].ptr = cpu_to_be32(sg_dma_address(areq->src)); + } else { + sg_count = sg_to_link_tbl(areq->src, sg_count, cryptlen, + &edesc->link_tbl[0]); + if (sg_count > 1) { + desc->ptr[3].j_extent |= DESC_PTR_LNKTBL_JUMP; + desc->ptr[3].ptr = cpu_to_be32(edesc->dma_link_tbl); + dma_sync_single_for_device(dev, edesc->dma_link_tbl, + edesc->dma_len, + DMA_BIDIRECTIONAL); + } else { + /* Only one segment now, so no link tbl needed */ + desc->ptr[3].ptr = cpu_to_be32(sg_dma_address(areq-> + src)); + } + } + + /* cipher out */ + desc->ptr[4].len = cpu_to_be16(cryptlen); + desc->ptr[4].j_extent = 0; + + if (areq->src != areq->dst) + sg_count = talitos_map_sg(dev, areq->dst, + edesc->dst_nents ? : 1, + DMA_FROM_DEVICE, + edesc->dst_is_chained); + + if (sg_count == 1) { + desc->ptr[4].ptr = cpu_to_be32(sg_dma_address(areq->dst)); + } else { + struct talitos_ptr *link_tbl_ptr = + &edesc->link_tbl[edesc->src_nents + 1]; + + desc->ptr[4].j_extent |= DESC_PTR_LNKTBL_JUMP; + desc->ptr[4].ptr = cpu_to_be32((struct talitos_ptr *) + edesc->dma_link_tbl + + edesc->src_nents + 1); + sg_count = sg_to_link_tbl(areq->dst, sg_count, cryptlen, + link_tbl_ptr); + dma_sync_single_for_device(ctx->dev, edesc->dma_link_tbl, + edesc->dma_len, DMA_BIDIRECTIONAL); + } + + /* iv out */ + map_single_talitos_ptr(dev, &desc->ptr[5], ivsize, ctx->iv, 0, + DMA_FROM_DEVICE); + + /* last DWORD empty */ + desc->ptr[6].len = 0; + desc->ptr[6].ptr = 0; + desc->ptr[6].j_extent = 0; + + ret = talitos_submit(dev, desc, callback, areq); + if (ret != -EINPROGRESS) { + common_nonsnoop_unmap(dev, edesc, areq); + kfree(edesc); + } + return ret; +} + +static struct talitos_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request * + areq) +{ + struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(areq); + struct talitos_ctx *ctx = crypto_ablkcipher_ctx(cipher); + + return talitos_edesc_alloc(ctx->dev, areq->src, areq->dst, areq->nbytes, + 0, 0, areq->base.flags); +} + +static int ablkcipher_encrypt(struct ablkcipher_request *areq) +{ + struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(areq); + struct talitos_ctx *ctx = crypto_ablkcipher_ctx(cipher); + struct talitos_edesc *edesc; + + /* allocate extended descriptor */ + edesc = ablkcipher_edesc_alloc(areq); + if (IS_ERR(edesc)) + return PTR_ERR(edesc); + + /* set encrypt */ + edesc->desc.hdr = ctx->desc_hdr_template | DESC_HDR_MODE0_ENCRYPT; + + return common_nonsnoop(edesc, areq, NULL, ablkcipher_done); +} + +static int ablkcipher_decrypt(struct ablkcipher_request *areq) +{ + struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(areq); + struct talitos_ctx *ctx = crypto_ablkcipher_ctx(cipher); + struct talitos_edesc *edesc; + + /* allocate extended descriptor */ + edesc = ablkcipher_edesc_alloc(areq); + if (IS_ERR(edesc)) + return PTR_ERR(edesc); + + edesc->desc.hdr = ctx->desc_hdr_template | DESC_HDR_DIR_INBOUND; + + return common_nonsnoop(edesc, areq, NULL, ablkcipher_done); +} + struct talitos_alg_template { - char name[CRYPTO_MAX_ALG_NAME]; - char driver_name[CRYPTO_MAX_ALG_NAME]; - unsigned int blocksize; - struct aead_alg aead; - struct device *dev; + struct crypto_alg alg; __be32 desc_hdr_template; }; static struct talitos_alg_template driver_algs[] = { - /* single-pass ipsec_esp descriptor */ + /* AEAD algorithms. These use a single-pass ipsec_esp descriptor */ { - .name = "authenc(hmac(sha1),cbc(aes))", - .driver_name = "authenc-hmac-sha1-cbc-aes-talitos", - .blocksize = AES_BLOCK_SIZE, - .aead = { - .setkey = aead_authenc_setkey, - .setauthsize = aead_authenc_setauthsize, - .encrypt = aead_authenc_encrypt, - .decrypt = aead_authenc_decrypt, - .givencrypt = aead_authenc_givencrypt, - .geniv = "", - .ivsize = AES_BLOCK_SIZE, - .maxauthsize = SHA1_DIGEST_SIZE, - }, + .alg = { + .cra_name = "authenc(hmac(sha1),cbc(aes))", + .cra_driver_name = "authenc-hmac-sha1-cbc-aes-talitos", + .cra_blocksize = AES_BLOCK_SIZE, + .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC, + .cra_type = &crypto_aead_type, + .cra_aead = { + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .givencrypt = aead_givencrypt, + .geniv = "", + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = SHA1_DIGEST_SIZE, + } + }, .desc_hdr_template = DESC_HDR_TYPE_IPSEC_ESP | DESC_HDR_SEL0_AESU | DESC_HDR_MODE0_AESU_CBC | @@ -1238,19 +1499,23 @@ static struct talitos_alg_template driver_algs[] = { DESC_HDR_MODE1_MDEU_SHA1_HMAC, }, { - .name = "authenc(hmac(sha1),cbc(des3_ede))", - .driver_name = "authenc-hmac-sha1-cbc-3des-talitos", - .blocksize = DES3_EDE_BLOCK_SIZE, - .aead = { - .setkey = aead_authenc_setkey, - .setauthsize = aead_authenc_setauthsize, - .encrypt = aead_authenc_encrypt, - .decrypt = aead_authenc_decrypt, - .givencrypt = aead_authenc_givencrypt, - .geniv = "", - .ivsize = DES3_EDE_BLOCK_SIZE, - .maxauthsize = SHA1_DIGEST_SIZE, - }, + .alg = { + .cra_name = "authenc(hmac(sha1),cbc(des3_ede))", + .cra_driver_name = "authenc-hmac-sha1-cbc-3des-talitos", + .cra_blocksize = DES3_EDE_BLOCK_SIZE, + .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC, + .cra_type = &crypto_aead_type, + .cra_aead = { + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .givencrypt = aead_givencrypt, + .geniv = "", + .ivsize = DES3_EDE_BLOCK_SIZE, + .maxauthsize = SHA1_DIGEST_SIZE, + } + }, .desc_hdr_template = DESC_HDR_TYPE_IPSEC_ESP | DESC_HDR_SEL0_DEU | DESC_HDR_MODE0_DEU_CBC | @@ -1261,19 +1526,23 @@ static struct talitos_alg_template driver_algs[] = { DESC_HDR_MODE1_MDEU_SHA1_HMAC, }, { - .name = "authenc(hmac(sha256),cbc(aes))", - .driver_name = "authenc-hmac-sha256-cbc-aes-talitos", - .blocksize = AES_BLOCK_SIZE, - .aead = { - .setkey = aead_authenc_setkey, - .setauthsize = aead_authenc_setauthsize, - .encrypt = aead_authenc_encrypt, - .decrypt = aead_authenc_decrypt, - .givencrypt = aead_authenc_givencrypt, - .geniv = "", - .ivsize = AES_BLOCK_SIZE, - .maxauthsize = SHA256_DIGEST_SIZE, - }, + .alg = { + .cra_name = "authenc(hmac(sha256),cbc(aes))", + .cra_driver_name = "authenc-hmac-sha256-cbc-aes-talitos", + .cra_blocksize = AES_BLOCK_SIZE, + .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC, + .cra_type = &crypto_aead_type, + .cra_aead = { + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .givencrypt = aead_givencrypt, + .geniv = "", + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = SHA256_DIGEST_SIZE, + } + }, .desc_hdr_template = DESC_HDR_TYPE_IPSEC_ESP | DESC_HDR_SEL0_AESU | DESC_HDR_MODE0_AESU_CBC | @@ -1283,19 +1552,23 @@ static struct talitos_alg_template driver_algs[] = { DESC_HDR_MODE1_MDEU_SHA256_HMAC, }, { - .name = "authenc(hmac(sha256),cbc(des3_ede))", - .driver_name = "authenc-hmac-sha256-cbc-3des-talitos", - .blocksize = DES3_EDE_BLOCK_SIZE, - .aead = { - .setkey = aead_authenc_setkey, - .setauthsize = aead_authenc_setauthsize, - .encrypt = aead_authenc_encrypt, - .decrypt = aead_authenc_decrypt, - .givencrypt = aead_authenc_givencrypt, - .geniv = "", - .ivsize = DES3_EDE_BLOCK_SIZE, - .maxauthsize = SHA256_DIGEST_SIZE, - }, + .alg = { + .cra_name = "authenc(hmac(sha256),cbc(des3_ede))", + .cra_driver_name = "authenc-hmac-sha256-cbc-3des-talitos", + .cra_blocksize = DES3_EDE_BLOCK_SIZE, + .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC, + .cra_type = &crypto_aead_type, + .cra_aead = { + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .givencrypt = aead_givencrypt, + .geniv = "", + .ivsize = DES3_EDE_BLOCK_SIZE, + .maxauthsize = SHA256_DIGEST_SIZE, + } + }, .desc_hdr_template = DESC_HDR_TYPE_IPSEC_ESP | DESC_HDR_SEL0_DEU | DESC_HDR_MODE0_DEU_CBC | @@ -1306,19 +1579,23 @@ static struct talitos_alg_template driver_algs[] = { DESC_HDR_MODE1_MDEU_SHA256_HMAC, }, { - .name = "authenc(hmac(md5),cbc(aes))", - .driver_name = "authenc-hmac-md5-cbc-aes-talitos", - .blocksize = AES_BLOCK_SIZE, - .aead = { - .setkey = aead_authenc_setkey, - .setauthsize = aead_authenc_setauthsize, - .encrypt = aead_authenc_encrypt, - .decrypt = aead_authenc_decrypt, - .givencrypt = aead_authenc_givencrypt, - .geniv = "", - .ivsize = AES_BLOCK_SIZE, - .maxauthsize = MD5_DIGEST_SIZE, - }, + .alg = { + .cra_name = "authenc(hmac(md5),cbc(aes))", + .cra_driver_name = "authenc-hmac-md5-cbc-aes-talitos", + .cra_blocksize = AES_BLOCK_SIZE, + .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC, + .cra_type = &crypto_aead_type, + .cra_aead = { + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .givencrypt = aead_givencrypt, + .geniv = "", + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = MD5_DIGEST_SIZE, + } + }, .desc_hdr_template = DESC_HDR_TYPE_IPSEC_ESP | DESC_HDR_SEL0_AESU | DESC_HDR_MODE0_AESU_CBC | @@ -1328,19 +1605,23 @@ static struct talitos_alg_template driver_algs[] = { DESC_HDR_MODE1_MDEU_MD5_HMAC, }, { - .name = "authenc(hmac(md5),cbc(des3_ede))", - .driver_name = "authenc-hmac-md5-cbc-3des-talitos", - .blocksize = DES3_EDE_BLOCK_SIZE, - .aead = { - .setkey = aead_authenc_setkey, - .setauthsize = aead_authenc_setauthsize, - .encrypt = aead_authenc_encrypt, - .decrypt = aead_authenc_decrypt, - .givencrypt = aead_authenc_givencrypt, - .geniv = "", - .ivsize = DES3_EDE_BLOCK_SIZE, - .maxauthsize = MD5_DIGEST_SIZE, - }, + .alg = { + .cra_name = "authenc(hmac(md5),cbc(des3_ede))", + .cra_driver_name = "authenc-hmac-md5-cbc-3des-talitos", + .cra_blocksize = DES3_EDE_BLOCK_SIZE, + .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC, + .cra_type = &crypto_aead_type, + .cra_aead = { + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .givencrypt = aead_givencrypt, + .geniv = "", + .ivsize = DES3_EDE_BLOCK_SIZE, + .maxauthsize = MD5_DIGEST_SIZE, + } + }, .desc_hdr_template = DESC_HDR_TYPE_IPSEC_ESP | DESC_HDR_SEL0_DEU | DESC_HDR_MODE0_DEU_CBC | @@ -1349,6 +1630,52 @@ static struct talitos_alg_template driver_algs[] = { DESC_HDR_MODE1_MDEU_INIT | DESC_HDR_MODE1_MDEU_PAD | DESC_HDR_MODE1_MDEU_MD5_HMAC, + }, + /* ABLKCIPHER algorithms. */ + { + .alg = { + .cra_name = "cbc(aes)", + .cra_driver_name = "cbc-aes-talitos", + .cra_blocksize = AES_BLOCK_SIZE, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_ASYNC, + .cra_type = &crypto_ablkcipher_type, + .cra_ablkcipher = { + .setkey = ablkcipher_setkey, + .encrypt = ablkcipher_encrypt, + .decrypt = ablkcipher_decrypt, + .geniv = "eseqiv", + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + } + }, + .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU | + DESC_HDR_SEL0_AESU | + DESC_HDR_MODE0_AESU_CBC, + }, + { + .alg = { + .cra_name = "cbc(des3_ede)", + .cra_driver_name = "cbc-3des-talitos", + .cra_blocksize = DES3_EDE_BLOCK_SIZE, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_ASYNC, + .cra_type = &crypto_ablkcipher_type, + .cra_ablkcipher = { + .setkey = ablkcipher_setkey, + .encrypt = ablkcipher_encrypt, + .decrypt = ablkcipher_decrypt, + .geniv = "eseqiv", + .min_keysize = DES3_EDE_KEY_SIZE, + .max_keysize = DES3_EDE_KEY_SIZE, + .ivsize = DES3_EDE_BLOCK_SIZE, + } + }, + .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU | + DESC_HDR_SEL0_DEU | + DESC_HDR_MODE0_DEU_CBC | + DESC_HDR_MODE0_DEU_3DES, } }; @@ -1362,12 +1689,14 @@ struct talitos_crypto_alg { static int talitos_cra_init(struct crypto_tfm *tfm) { struct crypto_alg *alg = tfm->__crt_alg; - struct talitos_crypto_alg *talitos_alg = - container_of(alg, struct talitos_crypto_alg, crypto_alg); + struct talitos_crypto_alg *talitos_alg; struct talitos_ctx *ctx = crypto_tfm_ctx(tfm); + talitos_alg = container_of(alg, struct talitos_crypto_alg, crypto_alg); + /* update context with ptr to dev */ ctx->dev = talitos_alg->dev; + /* copy descriptor header template value */ ctx->desc_hdr_template = talitos_alg->desc_hdr_template; @@ -1453,19 +1782,13 @@ static struct talitos_crypto_alg *talitos_alg_alloc(struct device *dev, return ERR_PTR(-ENOMEM); alg = &t_alg->crypto_alg; + *alg = template->alg; - snprintf(alg->cra_name, CRYPTO_MAX_ALG_NAME, "%s", template->name); - snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", - template->driver_name); alg->cra_module = THIS_MODULE; alg->cra_init = talitos_cra_init; alg->cra_priority = TALITOS_CRA_PRIORITY; - alg->cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC; - alg->cra_blocksize = template->blocksize; alg->cra_alignmask = 0; - alg->cra_type = &crypto_aead_type; alg->cra_ctxsize = sizeof(struct talitos_ctx); - alg->cra_u.aead = template->aead; t_alg->desc_hdr_template = template->desc_hdr_template; t_alg->dev = dev; diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index ddcd9793b25c..fe1f3717b1ff 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -50,6 +50,14 @@ config DW_DMAC Support the Synopsys DesignWare AHB DMA controller. This can be integrated in chips such as the Atmel AT32ap7000. +config AT_HDMAC + tristate "Atmel AHB DMA support" + depends on ARCH_AT91SAM9RL + select DMA_ENGINE + help + Support the Atmel AHB DMA controller. This can be integrated in + chips such as the Atmel AT91SAM9RL. + config FSL_DMA tristate "Freescale Elo and Elo Plus DMA support" depends on FSL_SOC @@ -85,6 +93,14 @@ config MX3_IPU_IRQS To avoid bloating the irq_desc[] array we allocate a sufficient number of IRQ slots and map them dynamically to specific sources. +config TXX9_DMAC + tristate "Toshiba TXx9 SoC DMA support" + depends on MACH_TX49XX || MACH_TX39XX + select DMA_ENGINE + help + Support the TXx9 SoC internal DMA controller. This can be + integrated in chips such as the Toshiba TX4927/38/39. + config DMA_ENGINE bool @@ -104,7 +120,7 @@ config NET_DMA config ASYNC_TX_DMA bool "Async_tx: Offload support for the async_tx api" - depends on DMA_ENGINE + depends on DMA_ENGINE && !HIGHMEM64G help This allows the async_tx api to take advantage of offload engines for memcpy, memset, xor, and raid6 p+q operations. If your platform has diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index a1cb2857bba6..8f115e93b4a1 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -6,4 +6,6 @@ obj-$(CONFIG_INTEL_IOP_ADMA) += iop-adma.o obj-$(CONFIG_FSL_DMA) += fsldma.o obj-$(CONFIG_MV_XOR) += mv_xor.o obj-$(CONFIG_DW_DMAC) += dw_dmac.o +obj-$(CONFIG_AT_HDMAC) += at_hdmac.o obj-$(CONFIG_MX3_IPU) += ipu/ +obj-$(CONFIG_TXX9_DMAC) += txx9dmac.o diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c new file mode 100644 index 000000000000..0aeb578a24e3 --- /dev/null +++ b/drivers/dma/at_hdmac.c @@ -0,0 +1,1215 @@ +/* + * Driver for the Atmel AHB DMA Controller (aka HDMA or DMAC on AT91 systems) + * + * Copyright (C) 2008 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * + * This supports the Atmel AHB DMA Controller, + * + * The driver has currently been tested with the Atmel AT91SAM9RL + * and AT91SAM9G45 series. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "at_hdmac_regs.h" + +/* + * Glossary + * -------- + * + * at_hdmac : Name of the ATmel AHB DMA Controller + * at_dma_ / atdma : ATmel DMA controller entity related + * atc_ / atchan : ATmel DMA Channel entity related + */ + +#define ATC_DEFAULT_CFG (ATC_FIFOCFG_HALFFIFO) +#define ATC_DEFAULT_CTRLA (0) +#define ATC_DEFAULT_CTRLB (ATC_SIF(0) \ + |ATC_DIF(1)) + +/* + * Initial number of descriptors to allocate for each channel. This could + * be increased during dma usage. + */ +static unsigned int init_nr_desc_per_channel = 64; +module_param(init_nr_desc_per_channel, uint, 0644); +MODULE_PARM_DESC(init_nr_desc_per_channel, + "initial descriptors per channel (default: 64)"); + + +/* prototypes */ +static dma_cookie_t atc_tx_submit(struct dma_async_tx_descriptor *tx); + + +/*----------------------------------------------------------------------*/ + +static struct at_desc *atc_first_active(struct at_dma_chan *atchan) +{ + return list_first_entry(&atchan->active_list, + struct at_desc, desc_node); +} + +static struct at_desc *atc_first_queued(struct at_dma_chan *atchan) +{ + return list_first_entry(&atchan->queue, + struct at_desc, desc_node); +} + +/** + * atc_alloc_descriptor - allocate and return an initilized descriptor + * @chan: the channel to allocate descriptors for + * @gfp_flags: GFP allocation flags + * + * Note: The ack-bit is positioned in the descriptor flag at creation time + * to make initial allocation more convenient. This bit will be cleared + * and control will be given to client at usage time (during + * preparation functions). + */ +static struct at_desc *atc_alloc_descriptor(struct dma_chan *chan, + gfp_t gfp_flags) +{ + struct at_desc *desc = NULL; + struct at_dma *atdma = to_at_dma(chan->device); + dma_addr_t phys; + + desc = dma_pool_alloc(atdma->dma_desc_pool, gfp_flags, &phys); + if (desc) { + memset(desc, 0, sizeof(struct at_desc)); + INIT_LIST_HEAD(&desc->tx_list); + dma_async_tx_descriptor_init(&desc->txd, chan); + /* txd.flags will be overwritten in prep functions */ + desc->txd.flags = DMA_CTRL_ACK; + desc->txd.tx_submit = atc_tx_submit; + desc->txd.phys = phys; + } + + return desc; +} + +/** + * atc_desc_get - get a unsused descriptor from free_list + * @atchan: channel we want a new descriptor for + */ +static struct at_desc *atc_desc_get(struct at_dma_chan *atchan) +{ + struct at_desc *desc, *_desc; + struct at_desc *ret = NULL; + unsigned int i = 0; + LIST_HEAD(tmp_list); + + spin_lock_bh(&atchan->lock); + list_for_each_entry_safe(desc, _desc, &atchan->free_list, desc_node) { + i++; + if (async_tx_test_ack(&desc->txd)) { + list_del(&desc->desc_node); + ret = desc; + break; + } + dev_dbg(chan2dev(&atchan->chan_common), + "desc %p not ACKed\n", desc); + } + spin_unlock_bh(&atchan->lock); + dev_vdbg(chan2dev(&atchan->chan_common), + "scanned %u descriptors on freelist\n", i); + + /* no more descriptor available in initial pool: create one more */ + if (!ret) { + ret = atc_alloc_descriptor(&atchan->chan_common, GFP_ATOMIC); + if (ret) { + spin_lock_bh(&atchan->lock); + atchan->descs_allocated++; + spin_unlock_bh(&atchan->lock); + } else { + dev_err(chan2dev(&atchan->chan_common), + "not enough descriptors available\n"); + } + } + + return ret; +} + +/** + * atc_desc_put - move a descriptor, including any children, to the free list + * @atchan: channel we work on + * @desc: descriptor, at the head of a chain, to move to free list + */ +static void atc_desc_put(struct at_dma_chan *atchan, struct at_desc *desc) +{ + if (desc) { + struct at_desc *child; + + spin_lock_bh(&atchan->lock); + list_for_each_entry(child, &desc->tx_list, desc_node) + dev_vdbg(chan2dev(&atchan->chan_common), + "moving child desc %p to freelist\n", + child); + list_splice_init(&desc->tx_list, &atchan->free_list); + dev_vdbg(chan2dev(&atchan->chan_common), + "moving desc %p to freelist\n", desc); + list_add(&desc->desc_node, &atchan->free_list); + spin_unlock_bh(&atchan->lock); + } +} + +/** + * atc_assign_cookie - compute and assign new cookie + * @atchan: channel we work on + * @desc: descriptor to asign cookie for + * + * Called with atchan->lock held and bh disabled + */ +static dma_cookie_t +atc_assign_cookie(struct at_dma_chan *atchan, struct at_desc *desc) +{ + dma_cookie_t cookie = atchan->chan_common.cookie; + + if (++cookie < 0) + cookie = 1; + + atchan->chan_common.cookie = cookie; + desc->txd.cookie = cookie; + + return cookie; +} + +/** + * atc_dostart - starts the DMA engine for real + * @atchan: the channel we want to start + * @first: first descriptor in the list we want to begin with + * + * Called with atchan->lock held and bh disabled + */ +static void atc_dostart(struct at_dma_chan *atchan, struct at_desc *first) +{ + struct at_dma *atdma = to_at_dma(atchan->chan_common.device); + + /* ASSERT: channel is idle */ + if (atc_chan_is_enabled(atchan)) { + dev_err(chan2dev(&atchan->chan_common), + "BUG: Attempted to start non-idle channel\n"); + dev_err(chan2dev(&atchan->chan_common), + " channel: s0x%x d0x%x ctrl0x%x:0x%x l0x%x\n", + channel_readl(atchan, SADDR), + channel_readl(atchan, DADDR), + channel_readl(atchan, CTRLA), + channel_readl(atchan, CTRLB), + channel_readl(atchan, DSCR)); + + /* The tasklet will hopefully advance the queue... */ + return; + } + + vdbg_dump_regs(atchan); + + /* clear any pending interrupt */ + while (dma_readl(atdma, EBCISR)) + cpu_relax(); + + channel_writel(atchan, SADDR, 0); + channel_writel(atchan, DADDR, 0); + channel_writel(atchan, CTRLA, 0); + channel_writel(atchan, CTRLB, 0); + channel_writel(atchan, DSCR, first->txd.phys); + dma_writel(atdma, CHER, atchan->mask); + + vdbg_dump_regs(atchan); +} + +/** + * atc_chain_complete - finish work for one transaction chain + * @atchan: channel we work on + * @desc: descriptor at the head of the chain we want do complete + * + * Called with atchan->lock held and bh disabled */ +static void +atc_chain_complete(struct at_dma_chan *atchan, struct at_desc *desc) +{ + dma_async_tx_callback callback; + void *param; + struct dma_async_tx_descriptor *txd = &desc->txd; + + dev_vdbg(chan2dev(&atchan->chan_common), + "descriptor %u complete\n", txd->cookie); + + atchan->completed_cookie = txd->cookie; + callback = txd->callback; + param = txd->callback_param; + + /* move children to free_list */ + list_splice_init(&desc->tx_list, &atchan->free_list); + /* move myself to free_list */ + list_move(&desc->desc_node, &atchan->free_list); + + /* unmap dma addresses */ + if (!atchan->chan_common.private) { + struct device *parent = chan2parent(&atchan->chan_common); + if (!(txd->flags & DMA_COMPL_SKIP_DEST_UNMAP)) { + if (txd->flags & DMA_COMPL_DEST_UNMAP_SINGLE) + dma_unmap_single(parent, + desc->lli.daddr, + desc->len, DMA_FROM_DEVICE); + else + dma_unmap_page(parent, + desc->lli.daddr, + desc->len, DMA_FROM_DEVICE); + } + if (!(txd->flags & DMA_COMPL_SKIP_SRC_UNMAP)) { + if (txd->flags & DMA_COMPL_SRC_UNMAP_SINGLE) + dma_unmap_single(parent, + desc->lli.saddr, + desc->len, DMA_TO_DEVICE); + else + dma_unmap_page(parent, + desc->lli.saddr, + desc->len, DMA_TO_DEVICE); + } + } + + /* + * The API requires that no submissions are done from a + * callback, so we don't need to drop the lock here + */ + if (callback) + callback(param); + + dma_run_dependencies(txd); +} + +/** + * atc_complete_all - finish work for all transactions + * @atchan: channel to complete transactions for + * + * Eventually submit queued descriptors if any + * + * Assume channel is idle while calling this function + * Called with atchan->lock held and bh disabled + */ +static void atc_complete_all(struct at_dma_chan *atchan) +{ + struct at_desc *desc, *_desc; + LIST_HEAD(list); + + dev_vdbg(chan2dev(&atchan->chan_common), "complete all\n"); + + BUG_ON(atc_chan_is_enabled(atchan)); + + /* + * Submit queued descriptors ASAP, i.e. before we go through + * the completed ones. + */ + if (!list_empty(&atchan->queue)) + atc_dostart(atchan, atc_first_queued(atchan)); + /* empty active_list now it is completed */ + list_splice_init(&atchan->active_list, &list); + /* empty queue list by moving descriptors (if any) to active_list */ + list_splice_init(&atchan->queue, &atchan->active_list); + + list_for_each_entry_safe(desc, _desc, &list, desc_node) + atc_chain_complete(atchan, desc); +} + +/** + * atc_cleanup_descriptors - cleanup up finished descriptors in active_list + * @atchan: channel to be cleaned up + * + * Called with atchan->lock held and bh disabled + */ +static void atc_cleanup_descriptors(struct at_dma_chan *atchan) +{ + struct at_desc *desc, *_desc; + struct at_desc *child; + + dev_vdbg(chan2dev(&atchan->chan_common), "cleanup descriptors\n"); + + list_for_each_entry_safe(desc, _desc, &atchan->active_list, desc_node) { + if (!(desc->lli.ctrla & ATC_DONE)) + /* This one is currently in progress */ + return; + + list_for_each_entry(child, &desc->tx_list, desc_node) + if (!(child->lli.ctrla & ATC_DONE)) + /* Currently in progress */ + return; + + /* + * No descriptors so far seem to be in progress, i.e. + * this chain must be done. + */ + atc_chain_complete(atchan, desc); + } +} + +/** + * atc_advance_work - at the end of a transaction, move forward + * @atchan: channel where the transaction ended + * + * Called with atchan->lock held and bh disabled + */ +static void atc_advance_work(struct at_dma_chan *atchan) +{ + dev_vdbg(chan2dev(&atchan->chan_common), "advance_work\n"); + + if (list_empty(&atchan->active_list) || + list_is_singular(&atchan->active_list)) { + atc_complete_all(atchan); + } else { + atc_chain_complete(atchan, atc_first_active(atchan)); + /* advance work */ + atc_dostart(atchan, atc_first_active(atchan)); + } +} + + +/** + * atc_handle_error - handle errors reported by DMA controller + * @atchan: channel where error occurs + * + * Called with atchan->lock held and bh disabled + */ +static void atc_handle_error(struct at_dma_chan *atchan) +{ + struct at_desc *bad_desc; + struct at_desc *child; + + /* + * The descriptor currently at the head of the active list is + * broked. Since we don't have any way to report errors, we'll + * just have to scream loudly and try to carry on. + */ + bad_desc = atc_first_active(atchan); + list_del_init(&bad_desc->desc_node); + + /* As we are stopped, take advantage to push queued descriptors + * in active_list */ + list_splice_init(&atchan->queue, atchan->active_list.prev); + + /* Try to restart the controller */ + if (!list_empty(&atchan->active_list)) + atc_dostart(atchan, atc_first_active(atchan)); + + /* + * KERN_CRITICAL may seem harsh, but since this only happens + * when someone submits a bad physical address in a + * descriptor, we should consider ourselves lucky that the + * controller flagged an error instead of scribbling over + * random memory locations. + */ + dev_crit(chan2dev(&atchan->chan_common), + "Bad descriptor submitted for DMA!\n"); + dev_crit(chan2dev(&atchan->chan_common), + " cookie: %d\n", bad_desc->txd.cookie); + atc_dump_lli(atchan, &bad_desc->lli); + list_for_each_entry(child, &bad_desc->tx_list, desc_node) + atc_dump_lli(atchan, &child->lli); + + /* Pretend the descriptor completed successfully */ + atc_chain_complete(atchan, bad_desc); +} + + +/*-- IRQ & Tasklet ---------------------------------------------------*/ + +static void atc_tasklet(unsigned long data) +{ + struct at_dma_chan *atchan = (struct at_dma_chan *)data; + + /* Channel cannot be enabled here */ + if (atc_chan_is_enabled(atchan)) { + dev_err(chan2dev(&atchan->chan_common), + "BUG: channel enabled in tasklet\n"); + return; + } + + spin_lock(&atchan->lock); + if (test_and_clear_bit(0, &atchan->error_status)) + atc_handle_error(atchan); + else + atc_advance_work(atchan); + + spin_unlock(&atchan->lock); +} + +static irqreturn_t at_dma_interrupt(int irq, void *dev_id) +{ + struct at_dma *atdma = (struct at_dma *)dev_id; + struct at_dma_chan *atchan; + int i; + u32 status, pending, imr; + int ret = IRQ_NONE; + + do { + imr = dma_readl(atdma, EBCIMR); + status = dma_readl(atdma, EBCISR); + pending = status & imr; + + if (!pending) + break; + + dev_vdbg(atdma->dma_common.dev, + "interrupt: status = 0x%08x, 0x%08x, 0x%08x\n", + status, imr, pending); + + for (i = 0; i < atdma->dma_common.chancnt; i++) { + atchan = &atdma->chan[i]; + if (pending & (AT_DMA_CBTC(i) | AT_DMA_ERR(i))) { + if (pending & AT_DMA_ERR(i)) { + /* Disable channel on AHB error */ + dma_writel(atdma, CHDR, atchan->mask); + /* Give information to tasklet */ + set_bit(0, &atchan->error_status); + } + tasklet_schedule(&atchan->tasklet); + ret = IRQ_HANDLED; + } + } + + } while (pending); + + return ret; +} + + +/*-- DMA Engine API --------------------------------------------------*/ + +/** + * atc_tx_submit - set the prepared descriptor(s) to be executed by the engine + * @desc: descriptor at the head of the transaction chain + * + * Queue chain if DMA engine is working already + * + * Cookie increment and adding to active_list or queue must be atomic + */ +static dma_cookie_t atc_tx_submit(struct dma_async_tx_descriptor *tx) +{ + struct at_desc *desc = txd_to_at_desc(tx); + struct at_dma_chan *atchan = to_at_dma_chan(tx->chan); + dma_cookie_t cookie; + + spin_lock_bh(&atchan->lock); + cookie = atc_assign_cookie(atchan, desc); + + if (list_empty(&atchan->active_list)) { + dev_vdbg(chan2dev(tx->chan), "tx_submit: started %u\n", + desc->txd.cookie); + atc_dostart(atchan, desc); + list_add_tail(&desc->desc_node, &atchan->active_list); + } else { + dev_vdbg(chan2dev(tx->chan), "tx_submit: queued %u\n", + desc->txd.cookie); + list_add_tail(&desc->desc_node, &atchan->queue); + } + + spin_unlock_bh(&atchan->lock); + + return cookie; +} + +/** + * atc_prep_dma_memcpy - prepare a memcpy operation + * @chan: the channel to prepare operation on + * @dest: operation virtual destination address + * @src: operation virtual source address + * @len: operation length + * @flags: tx descriptor status flags + */ +static struct dma_async_tx_descriptor * +atc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, + size_t len, unsigned long flags) +{ + struct at_dma_chan *atchan = to_at_dma_chan(chan); + struct at_desc *desc = NULL; + struct at_desc *first = NULL; + struct at_desc *prev = NULL; + size_t xfer_count; + size_t offset; + unsigned int src_width; + unsigned int dst_width; + u32 ctrla; + u32 ctrlb; + + dev_vdbg(chan2dev(chan), "prep_dma_memcpy: d0x%x s0x%x l0x%zx f0x%lx\n", + dest, src, len, flags); + + if (unlikely(!len)) { + dev_dbg(chan2dev(chan), "prep_dma_memcpy: length is zero!\n"); + return NULL; + } + + ctrla = ATC_DEFAULT_CTRLA; + ctrlb = ATC_DEFAULT_CTRLB + | ATC_SRC_ADDR_MODE_INCR + | ATC_DST_ADDR_MODE_INCR + | ATC_FC_MEM2MEM; + + /* + * We can be a lot more clever here, but this should take care + * of the most common optimization. + */ + if (!((src | dest | len) & 3)) { + ctrla |= ATC_SRC_WIDTH_WORD | ATC_DST_WIDTH_WORD; + src_width = dst_width = 2; + } else if (!((src | dest | len) & 1)) { + ctrla |= ATC_SRC_WIDTH_HALFWORD | ATC_DST_WIDTH_HALFWORD; + src_width = dst_width = 1; + } else { + ctrla |= ATC_SRC_WIDTH_BYTE | ATC_DST_WIDTH_BYTE; + src_width = dst_width = 0; + } + + for (offset = 0; offset < len; offset += xfer_count << src_width) { + xfer_count = min_t(size_t, (len - offset) >> src_width, + ATC_BTSIZE_MAX); + + desc = atc_desc_get(atchan); + if (!desc) + goto err_desc_get; + + desc->lli.saddr = src + offset; + desc->lli.daddr = dest + offset; + desc->lli.ctrla = ctrla | xfer_count; + desc->lli.ctrlb = ctrlb; + + desc->txd.cookie = 0; + async_tx_ack(&desc->txd); + + if (!first) { + first = desc; + } else { + /* inform the HW lli about chaining */ + prev->lli.dscr = desc->txd.phys; + /* insert the link descriptor to the LD ring */ + list_add_tail(&desc->desc_node, + &first->tx_list); + } + prev = desc; + } + + /* First descriptor of the chain embedds additional information */ + first->txd.cookie = -EBUSY; + first->len = len; + + /* set end-of-link to the last link descriptor of list*/ + set_desc_eol(desc); + + desc->txd.flags = flags; /* client is in control of this ack */ + + return &first->txd; + +err_desc_get: + atc_desc_put(atchan, first); + return NULL; +} + + +/** + * atc_prep_slave_sg - prepare descriptors for a DMA_SLAVE transaction + * @chan: DMA channel + * @sgl: scatterlist to transfer to/from + * @sg_len: number of entries in @scatterlist + * @direction: DMA direction + * @flags: tx descriptor status flags + */ +static struct dma_async_tx_descriptor * +atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, + unsigned int sg_len, enum dma_data_direction direction, + unsigned long flags) +{ + struct at_dma_chan *atchan = to_at_dma_chan(chan); + struct at_dma_slave *atslave = chan->private; + struct at_desc *first = NULL; + struct at_desc *prev = NULL; + u32 ctrla; + u32 ctrlb; + dma_addr_t reg; + unsigned int reg_width; + unsigned int mem_width; + unsigned int i; + struct scatterlist *sg; + size_t total_len = 0; + + dev_vdbg(chan2dev(chan), "prep_slave_sg: %s f0x%lx\n", + direction == DMA_TO_DEVICE ? "TO DEVICE" : "FROM DEVICE", + flags); + + if (unlikely(!atslave || !sg_len)) { + dev_dbg(chan2dev(chan), "prep_dma_memcpy: length is zero!\n"); + return NULL; + } + + reg_width = atslave->reg_width; + + ctrla = ATC_DEFAULT_CTRLA | atslave->ctrla; + ctrlb = ATC_DEFAULT_CTRLB | ATC_IEN; + + switch (direction) { + case DMA_TO_DEVICE: + ctrla |= ATC_DST_WIDTH(reg_width); + ctrlb |= ATC_DST_ADDR_MODE_FIXED + | ATC_SRC_ADDR_MODE_INCR + | ATC_FC_MEM2PER; + reg = atslave->tx_reg; + for_each_sg(sgl, sg, sg_len, i) { + struct at_desc *desc; + u32 len; + u32 mem; + + desc = atc_desc_get(atchan); + if (!desc) + goto err_desc_get; + + mem = sg_phys(sg); + len = sg_dma_len(sg); + mem_width = 2; + if (unlikely(mem & 3 || len & 3)) + mem_width = 0; + + desc->lli.saddr = mem; + desc->lli.daddr = reg; + desc->lli.ctrla = ctrla + | ATC_SRC_WIDTH(mem_width) + | len >> mem_width; + desc->lli.ctrlb = ctrlb; + + if (!first) { + first = desc; + } else { + /* inform the HW lli about chaining */ + prev->lli.dscr = desc->txd.phys; + /* insert the link descriptor to the LD ring */ + list_add_tail(&desc->desc_node, + &first->tx_list); + } + prev = desc; + total_len += len; + } + break; + case DMA_FROM_DEVICE: + ctrla |= ATC_SRC_WIDTH(reg_width); + ctrlb |= ATC_DST_ADDR_MODE_INCR + | ATC_SRC_ADDR_MODE_FIXED + | ATC_FC_PER2MEM; + + reg = atslave->rx_reg; + for_each_sg(sgl, sg, sg_len, i) { + struct at_desc *desc; + u32 len; + u32 mem; + + desc = atc_desc_get(atchan); + if (!desc) + goto err_desc_get; + + mem = sg_phys(sg); + len = sg_dma_len(sg); + mem_width = 2; + if (unlikely(mem & 3 || len & 3)) + mem_width = 0; + + desc->lli.saddr = reg; + desc->lli.daddr = mem; + desc->lli.ctrla = ctrla + | ATC_DST_WIDTH(mem_width) + | len >> mem_width; + desc->lli.ctrlb = ctrlb; + + if (!first) { + first = desc; + } else { + /* inform the HW lli about chaining */ + prev->lli.dscr = desc->txd.phys; + /* insert the link descriptor to the LD ring */ + list_add_tail(&desc->desc_node, + &first->tx_list); + } + prev = desc; + total_len += len; + } + break; + default: + return NULL; + } + + /* set end-of-link to the last link descriptor of list*/ + set_desc_eol(prev); + + /* First descriptor of the chain embedds additional information */ + first->txd.cookie = -EBUSY; + first->len = total_len; + + /* last link descriptor of list is responsible of flags */ + prev->txd.flags = flags; /* client is in control of this ack */ + + return &first->txd; + +err_desc_get: + dev_err(chan2dev(chan), "not enough descriptors available\n"); + atc_desc_put(atchan, first); + return NULL; +} + +static void atc_terminate_all(struct dma_chan *chan) +{ + struct at_dma_chan *atchan = to_at_dma_chan(chan); + struct at_dma *atdma = to_at_dma(chan->device); + struct at_desc *desc, *_desc; + LIST_HEAD(list); + + /* + * This is only called when something went wrong elsewhere, so + * we don't really care about the data. Just disable the + * channel. We still have to poll the channel enable bit due + * to AHB/HSB limitations. + */ + spin_lock_bh(&atchan->lock); + + dma_writel(atdma, CHDR, atchan->mask); + + /* confirm that this channel is disabled */ + while (dma_readl(atdma, CHSR) & atchan->mask) + cpu_relax(); + + /* active_list entries will end up before queued entries */ + list_splice_init(&atchan->queue, &list); + list_splice_init(&atchan->active_list, &list); + + spin_unlock_bh(&atchan->lock); + + /* Flush all pending and queued descriptors */ + list_for_each_entry_safe(desc, _desc, &list, desc_node) + atc_chain_complete(atchan, desc); +} + +/** + * atc_is_tx_complete - poll for transaction completion + * @chan: DMA channel + * @cookie: transaction identifier to check status of + * @done: if not %NULL, updated with last completed transaction + * @used: if not %NULL, updated with last used transaction + * + * If @done and @used are passed in, upon return they reflect the driver + * internal state and can be used with dma_async_is_complete() to check + * the status of multiple cookies without re-checking hardware state. + */ +static enum dma_status +atc_is_tx_complete(struct dma_chan *chan, + dma_cookie_t cookie, + dma_cookie_t *done, dma_cookie_t *used) +{ + struct at_dma_chan *atchan = to_at_dma_chan(chan); + dma_cookie_t last_used; + dma_cookie_t last_complete; + enum dma_status ret; + + dev_vdbg(chan2dev(chan), "is_tx_complete: %d (d%d, u%d)\n", + cookie, done ? *done : 0, used ? *used : 0); + + spin_lock_bh(atchan->lock); + + last_complete = atchan->completed_cookie; + last_used = chan->cookie; + + ret = dma_async_is_complete(cookie, last_complete, last_used); + if (ret != DMA_SUCCESS) { + atc_cleanup_descriptors(atchan); + + last_complete = atchan->completed_cookie; + last_used = chan->cookie; + + ret = dma_async_is_complete(cookie, last_complete, last_used); + } + + spin_unlock_bh(atchan->lock); + + if (done) + *done = last_complete; + if (used) + *used = last_used; + + return ret; +} + +/** + * atc_issue_pending - try to finish work + * @chan: target DMA channel + */ +static void atc_issue_pending(struct dma_chan *chan) +{ + struct at_dma_chan *atchan = to_at_dma_chan(chan); + + dev_vdbg(chan2dev(chan), "issue_pending\n"); + + if (!atc_chan_is_enabled(atchan)) { + spin_lock_bh(&atchan->lock); + atc_advance_work(atchan); + spin_unlock_bh(&atchan->lock); + } +} + +/** + * atc_alloc_chan_resources - allocate resources for DMA channel + * @chan: allocate descriptor resources for this channel + * @client: current client requesting the channel be ready for requests + * + * return - the number of allocated descriptors + */ +static int atc_alloc_chan_resources(struct dma_chan *chan) +{ + struct at_dma_chan *atchan = to_at_dma_chan(chan); + struct at_dma *atdma = to_at_dma(chan->device); + struct at_desc *desc; + struct at_dma_slave *atslave; + int i; + u32 cfg; + LIST_HEAD(tmp_list); + + dev_vdbg(chan2dev(chan), "alloc_chan_resources\n"); + + /* ASSERT: channel is idle */ + if (atc_chan_is_enabled(atchan)) { + dev_dbg(chan2dev(chan), "DMA channel not idle ?\n"); + return -EIO; + } + + cfg = ATC_DEFAULT_CFG; + + atslave = chan->private; + if (atslave) { + /* + * We need controller-specific data to set up slave + * transfers. + */ + BUG_ON(!atslave->dma_dev || atslave->dma_dev != atdma->dma_common.dev); + + /* if cfg configuration specified take it instad of default */ + if (atslave->cfg) + cfg = atslave->cfg; + } + + /* have we already been set up? + * reconfigure channel but no need to reallocate descriptors */ + if (!list_empty(&atchan->free_list)) + return atchan->descs_allocated; + + /* Allocate initial pool of descriptors */ + for (i = 0; i < init_nr_desc_per_channel; i++) { + desc = atc_alloc_descriptor(chan, GFP_KERNEL); + if (!desc) { + dev_err(atdma->dma_common.dev, + "Only %d initial descriptors\n", i); + break; + } + list_add_tail(&desc->desc_node, &tmp_list); + } + + spin_lock_bh(&atchan->lock); + atchan->descs_allocated = i; + list_splice(&tmp_list, &atchan->free_list); + atchan->completed_cookie = chan->cookie = 1; + spin_unlock_bh(&atchan->lock); + + /* channel parameters */ + channel_writel(atchan, CFG, cfg); + + dev_dbg(chan2dev(chan), + "alloc_chan_resources: allocated %d descriptors\n", + atchan->descs_allocated); + + return atchan->descs_allocated; +} + +/** + * atc_free_chan_resources - free all channel resources + * @chan: DMA channel + */ +static void atc_free_chan_resources(struct dma_chan *chan) +{ + struct at_dma_chan *atchan = to_at_dma_chan(chan); + struct at_dma *atdma = to_at_dma(chan->device); + struct at_desc *desc, *_desc; + LIST_HEAD(list); + + dev_dbg(chan2dev(chan), "free_chan_resources: (descs allocated=%u)\n", + atchan->descs_allocated); + + /* ASSERT: channel is idle */ + BUG_ON(!list_empty(&atchan->active_list)); + BUG_ON(!list_empty(&atchan->queue)); + BUG_ON(atc_chan_is_enabled(atchan)); + + list_for_each_entry_safe(desc, _desc, &atchan->free_list, desc_node) { + dev_vdbg(chan2dev(chan), " freeing descriptor %p\n", desc); + list_del(&desc->desc_node); + /* free link descriptor */ + dma_pool_free(atdma->dma_desc_pool, desc, desc->txd.phys); + } + list_splice_init(&atchan->free_list, &list); + atchan->descs_allocated = 0; + + dev_vdbg(chan2dev(chan), "free_chan_resources: done\n"); +} + + +/*-- Module Management -----------------------------------------------*/ + +/** + * at_dma_off - disable DMA controller + * @atdma: the Atmel HDAMC device + */ +static void at_dma_off(struct at_dma *atdma) +{ + dma_writel(atdma, EN, 0); + + /* disable all interrupts */ + dma_writel(atdma, EBCIDR, -1L); + + /* confirm that all channels are disabled */ + while (dma_readl(atdma, CHSR) & atdma->all_chan_mask) + cpu_relax(); +} + +static int __init at_dma_probe(struct platform_device *pdev) +{ + struct at_dma_platform_data *pdata; + struct resource *io; + struct at_dma *atdma; + size_t size; + int irq; + int err; + int i; + + /* get DMA Controller parameters from platform */ + pdata = pdev->dev.platform_data; + if (!pdata || pdata->nr_channels > AT_DMA_MAX_NR_CHANNELS) + return -EINVAL; + + io = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!io) + return -EINVAL; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + size = sizeof(struct at_dma); + size += pdata->nr_channels * sizeof(struct at_dma_chan); + atdma = kzalloc(size, GFP_KERNEL); + if (!atdma) + return -ENOMEM; + + /* discover transaction capabilites from the platform data */ + atdma->dma_common.cap_mask = pdata->cap_mask; + atdma->all_chan_mask = (1 << pdata->nr_channels) - 1; + + size = io->end - io->start + 1; + if (!request_mem_region(io->start, size, pdev->dev.driver->name)) { + err = -EBUSY; + goto err_kfree; + } + + atdma->regs = ioremap(io->start, size); + if (!atdma->regs) { + err = -ENOMEM; + goto err_release_r; + } + + atdma->clk = clk_get(&pdev->dev, "dma_clk"); + if (IS_ERR(atdma->clk)) { + err = PTR_ERR(atdma->clk); + goto err_clk; + } + clk_enable(atdma->clk); + + /* force dma off, just in case */ + at_dma_off(atdma); + + err = request_irq(irq, at_dma_interrupt, 0, "at_hdmac", atdma); + if (err) + goto err_irq; + + platform_set_drvdata(pdev, atdma); + + /* create a pool of consistent memory blocks for hardware descriptors */ + atdma->dma_desc_pool = dma_pool_create("at_hdmac_desc_pool", + &pdev->dev, sizeof(struct at_desc), + 4 /* word alignment */, 0); + if (!atdma->dma_desc_pool) { + dev_err(&pdev->dev, "No memory for descriptors dma pool\n"); + err = -ENOMEM; + goto err_pool_create; + } + + /* clear any pending interrupt */ + while (dma_readl(atdma, EBCISR)) + cpu_relax(); + + /* initialize channels related values */ + INIT_LIST_HEAD(&atdma->dma_common.channels); + for (i = 0; i < pdata->nr_channels; i++, atdma->dma_common.chancnt++) { + struct at_dma_chan *atchan = &atdma->chan[i]; + + atchan->chan_common.device = &atdma->dma_common; + atchan->chan_common.cookie = atchan->completed_cookie = 1; + atchan->chan_common.chan_id = i; + list_add_tail(&atchan->chan_common.device_node, + &atdma->dma_common.channels); + + atchan->ch_regs = atdma->regs + ch_regs(i); + spin_lock_init(&atchan->lock); + atchan->mask = 1 << i; + + INIT_LIST_HEAD(&atchan->active_list); + INIT_LIST_HEAD(&atchan->queue); + INIT_LIST_HEAD(&atchan->free_list); + + tasklet_init(&atchan->tasklet, atc_tasklet, + (unsigned long)atchan); + atc_enable_irq(atchan); + } + + /* set base routines */ + atdma->dma_common.device_alloc_chan_resources = atc_alloc_chan_resources; + atdma->dma_common.device_free_chan_resources = atc_free_chan_resources; + atdma->dma_common.device_is_tx_complete = atc_is_tx_complete; + atdma->dma_common.device_issue_pending = atc_issue_pending; + atdma->dma_common.dev = &pdev->dev; + + /* set prep routines based on capability */ + if (dma_has_cap(DMA_MEMCPY, atdma->dma_common.cap_mask)) + atdma->dma_common.device_prep_dma_memcpy = atc_prep_dma_memcpy; + + if (dma_has_cap(DMA_SLAVE, atdma->dma_common.cap_mask)) { + atdma->dma_common.device_prep_slave_sg = atc_prep_slave_sg; + atdma->dma_common.device_terminate_all = atc_terminate_all; + } + + dma_writel(atdma, EN, AT_DMA_ENABLE); + + dev_info(&pdev->dev, "Atmel AHB DMA Controller ( %s%s), %d channels\n", + dma_has_cap(DMA_MEMCPY, atdma->dma_common.cap_mask) ? "cpy " : "", + dma_has_cap(DMA_SLAVE, atdma->dma_common.cap_mask) ? "slave " : "", + atdma->dma_common.chancnt); + + dma_async_device_register(&atdma->dma_common); + + return 0; + +err_pool_create: + platform_set_drvdata(pdev, NULL); + free_irq(platform_get_irq(pdev, 0), atdma); +err_irq: + clk_disable(atdma->clk); + clk_put(atdma->clk); +err_clk: + iounmap(atdma->regs); + atdma->regs = NULL; +err_release_r: + release_mem_region(io->start, size); +err_kfree: + kfree(atdma); + return err; +} + +static int __exit at_dma_remove(struct platform_device *pdev) +{ + struct at_dma *atdma = platform_get_drvdata(pdev); + struct dma_chan *chan, *_chan; + struct resource *io; + + at_dma_off(atdma); + dma_async_device_unregister(&atdma->dma_common); + + dma_pool_destroy(atdma->dma_desc_pool); + platform_set_drvdata(pdev, NULL); + free_irq(platform_get_irq(pdev, 0), atdma); + + list_for_each_entry_safe(chan, _chan, &atdma->dma_common.channels, + device_node) { + struct at_dma_chan *atchan = to_at_dma_chan(chan); + + /* Disable interrupts */ + atc_disable_irq(atchan); + tasklet_disable(&atchan->tasklet); + + tasklet_kill(&atchan->tasklet); + list_del(&chan->device_node); + } + + clk_disable(atdma->clk); + clk_put(atdma->clk); + + iounmap(atdma->regs); + atdma->regs = NULL; + + io = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(io->start, io->end - io->start + 1); + + kfree(atdma); + + return 0; +} + +static void at_dma_shutdown(struct platform_device *pdev) +{ + struct at_dma *atdma = platform_get_drvdata(pdev); + + at_dma_off(platform_get_drvdata(pdev)); + clk_disable(atdma->clk); +} + +static int at_dma_suspend_late(struct platform_device *pdev, pm_message_t mesg) +{ + struct at_dma *atdma = platform_get_drvdata(pdev); + + at_dma_off(platform_get_drvdata(pdev)); + clk_disable(atdma->clk); + return 0; +} + +static int at_dma_resume_early(struct platform_device *pdev) +{ + struct at_dma *atdma = platform_get_drvdata(pdev); + + clk_enable(atdma->clk); + dma_writel(atdma, EN, AT_DMA_ENABLE); + return 0; + +} + +static struct platform_driver at_dma_driver = { + .remove = __exit_p(at_dma_remove), + .shutdown = at_dma_shutdown, + .suspend_late = at_dma_suspend_late, + .resume_early = at_dma_resume_early, + .driver = { + .name = "at_hdmac", + }, +}; + +static int __init at_dma_init(void) +{ + return platform_driver_probe(&at_dma_driver, at_dma_probe); +} +module_init(at_dma_init); + +static void __exit at_dma_exit(void) +{ + platform_driver_unregister(&at_dma_driver); +} +module_exit(at_dma_exit); + +MODULE_DESCRIPTION("Atmel AHB DMA Controller driver"); +MODULE_AUTHOR("Nicolas Ferre "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:at_hdmac"); diff --git a/drivers/dma/at_hdmac_regs.h b/drivers/dma/at_hdmac_regs.h new file mode 100644 index 000000000000..495457e3dc4b --- /dev/null +++ b/drivers/dma/at_hdmac_regs.h @@ -0,0 +1,354 @@ +/* + * Header file for the Atmel AHB DMA Controller driver + * + * Copyright (C) 2008 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ +#ifndef AT_HDMAC_REGS_H +#define AT_HDMAC_REGS_H + +#include + +#define AT_DMA_MAX_NR_CHANNELS 8 + + +#define AT_DMA_GCFG 0x00 /* Global Configuration Register */ +#define AT_DMA_IF_BIGEND(i) (0x1 << (i)) /* AHB-Lite Interface i in Big-endian mode */ +#define AT_DMA_ARB_CFG (0x1 << 4) /* Arbiter mode. */ +#define AT_DMA_ARB_CFG_FIXED (0x0 << 4) +#define AT_DMA_ARB_CFG_ROUND_ROBIN (0x1 << 4) + +#define AT_DMA_EN 0x04 /* Controller Enable Register */ +#define AT_DMA_ENABLE (0x1 << 0) + +#define AT_DMA_SREQ 0x08 /* Software Single Request Register */ +#define AT_DMA_SSREQ(x) (0x1 << ((x) << 1)) /* Request a source single transfer on channel x */ +#define AT_DMA_DSREQ(x) (0x1 << (1 + ((x) << 1))) /* Request a destination single transfer on channel x */ + +#define AT_DMA_CREQ 0x0C /* Software Chunk Transfer Request Register */ +#define AT_DMA_SCREQ(x) (0x1 << ((x) << 1)) /* Request a source chunk transfer on channel x */ +#define AT_DMA_DCREQ(x) (0x1 << (1 + ((x) << 1))) /* Request a destination chunk transfer on channel x */ + +#define AT_DMA_LAST 0x10 /* Software Last Transfer Flag Register */ +#define AT_DMA_SLAST(x) (0x1 << ((x) << 1)) /* This src rq is last tx of buffer on channel x */ +#define AT_DMA_DLAST(x) (0x1 << (1 + ((x) << 1))) /* This dst rq is last tx of buffer on channel x */ + +#define AT_DMA_SYNC 0x14 /* Request Synchronization Register */ +#define AT_DMA_SYR(h) (0x1 << (h)) /* Synchronize handshake line h */ + +/* Error, Chained Buffer transfer completed and Buffer transfer completed Interrupt registers */ +#define AT_DMA_EBCIER 0x18 /* Enable register */ +#define AT_DMA_EBCIDR 0x1C /* Disable register */ +#define AT_DMA_EBCIMR 0x20 /* Mask Register */ +#define AT_DMA_EBCISR 0x24 /* Status Register */ +#define AT_DMA_CBTC_OFFSET 8 +#define AT_DMA_ERR_OFFSET 16 +#define AT_DMA_BTC(x) (0x1 << (x)) +#define AT_DMA_CBTC(x) (0x1 << (AT_DMA_CBTC_OFFSET + (x))) +#define AT_DMA_ERR(x) (0x1 << (AT_DMA_ERR_OFFSET + (x))) + +#define AT_DMA_CHER 0x28 /* Channel Handler Enable Register */ +#define AT_DMA_ENA(x) (0x1 << (x)) +#define AT_DMA_SUSP(x) (0x1 << ( 8 + (x))) +#define AT_DMA_KEEP(x) (0x1 << (24 + (x))) + +#define AT_DMA_CHDR 0x2C /* Channel Handler Disable Register */ +#define AT_DMA_DIS(x) (0x1 << (x)) +#define AT_DMA_RES(x) (0x1 << ( 8 + (x))) + +#define AT_DMA_CHSR 0x30 /* Channel Handler Status Register */ +#define AT_DMA_EMPT(x) (0x1 << (16 + (x))) +#define AT_DMA_STAL(x) (0x1 << (24 + (x))) + + +#define AT_DMA_CH_REGS_BASE 0x3C /* Channel registers base address */ +#define ch_regs(x) (AT_DMA_CH_REGS_BASE + (x) * 0x28) /* Channel x base addr */ + +/* Hardware register offset for each channel */ +#define ATC_SADDR_OFFSET 0x00 /* Source Address Register */ +#define ATC_DADDR_OFFSET 0x04 /* Destination Address Register */ +#define ATC_DSCR_OFFSET 0x08 /* Descriptor Address Register */ +#define ATC_CTRLA_OFFSET 0x0C /* Control A Register */ +#define ATC_CTRLB_OFFSET 0x10 /* Control B Register */ +#define ATC_CFG_OFFSET 0x14 /* Configuration Register */ +#define ATC_SPIP_OFFSET 0x18 /* Src PIP Configuration Register */ +#define ATC_DPIP_OFFSET 0x1C /* Dst PIP Configuration Register */ + + +/* Bitfield definitions */ + +/* Bitfields in DSCR */ +#define ATC_DSCR_IF(i) (0x3 & (i)) /* Dsc feched via AHB-Lite Interface i */ + +/* Bitfields in CTRLA */ +#define ATC_BTSIZE_MAX 0xFFFFUL /* Maximum Buffer Transfer Size */ +#define ATC_BTSIZE(x) (ATC_BTSIZE_MAX & (x)) /* Buffer Transfer Size */ +/* Chunck Tranfer size definitions are in at_hdmac.h */ +#define ATC_SRC_WIDTH_MASK (0x3 << 24) /* Source Single Transfer Size */ +#define ATC_SRC_WIDTH(x) ((x) << 24) +#define ATC_SRC_WIDTH_BYTE (0x0 << 24) +#define ATC_SRC_WIDTH_HALFWORD (0x1 << 24) +#define ATC_SRC_WIDTH_WORD (0x2 << 24) +#define ATC_DST_WIDTH_MASK (0x3 << 28) /* Destination Single Transfer Size */ +#define ATC_DST_WIDTH(x) ((x) << 28) +#define ATC_DST_WIDTH_BYTE (0x0 << 28) +#define ATC_DST_WIDTH_HALFWORD (0x1 << 28) +#define ATC_DST_WIDTH_WORD (0x2 << 28) +#define ATC_DONE (0x1 << 31) /* Tx Done (only written back in descriptor) */ + +/* Bitfields in CTRLB */ +#define ATC_SIF(i) (0x3 & (i)) /* Src tx done via AHB-Lite Interface i */ +#define ATC_DIF(i) ((0x3 & (i)) << 4) /* Dst tx done via AHB-Lite Interface i */ +#define ATC_SRC_PIP (0x1 << 8) /* Source Picture-in-Picture enabled */ +#define ATC_DST_PIP (0x1 << 12) /* Destination Picture-in-Picture enabled */ +#define ATC_SRC_DSCR_DIS (0x1 << 16) /* Src Descriptor fetch disable */ +#define ATC_DST_DSCR_DIS (0x1 << 20) /* Dst Descriptor fetch disable */ +#define ATC_FC_MASK (0x7 << 21) /* Choose Flow Controller */ +#define ATC_FC_MEM2MEM (0x0 << 21) /* Mem-to-Mem (DMA) */ +#define ATC_FC_MEM2PER (0x1 << 21) /* Mem-to-Periph (DMA) */ +#define ATC_FC_PER2MEM (0x2 << 21) /* Periph-to-Mem (DMA) */ +#define ATC_FC_PER2PER (0x3 << 21) /* Periph-to-Periph (DMA) */ +#define ATC_FC_PER2MEM_PER (0x4 << 21) /* Periph-to-Mem (Peripheral) */ +#define ATC_FC_MEM2PER_PER (0x5 << 21) /* Mem-to-Periph (Peripheral) */ +#define ATC_FC_PER2PER_SRCPER (0x6 << 21) /* Periph-to-Periph (Src Peripheral) */ +#define ATC_FC_PER2PER_DSTPER (0x7 << 21) /* Periph-to-Periph (Dst Peripheral) */ +#define ATC_SRC_ADDR_MODE_MASK (0x3 << 24) +#define ATC_SRC_ADDR_MODE_INCR (0x0 << 24) /* Incrementing Mode */ +#define ATC_SRC_ADDR_MODE_DECR (0x1 << 24) /* Decrementing Mode */ +#define ATC_SRC_ADDR_MODE_FIXED (0x2 << 24) /* Fixed Mode */ +#define ATC_DST_ADDR_MODE_MASK (0x3 << 28) +#define ATC_DST_ADDR_MODE_INCR (0x0 << 28) /* Incrementing Mode */ +#define ATC_DST_ADDR_MODE_DECR (0x1 << 28) /* Decrementing Mode */ +#define ATC_DST_ADDR_MODE_FIXED (0x2 << 28) /* Fixed Mode */ +#define ATC_IEN (0x1 << 30) /* BTC interrupt enable (active low) */ +#define ATC_AUTO (0x1 << 31) /* Auto multiple buffer tx enable */ + +/* Bitfields in CFG */ +/* are in at_hdmac.h */ + +/* Bitfields in SPIP */ +#define ATC_SPIP_HOLE(x) (0xFFFFU & (x)) +#define ATC_SPIP_BOUNDARY(x) ((0x3FF & (x)) << 16) + +/* Bitfields in DPIP */ +#define ATC_DPIP_HOLE(x) (0xFFFFU & (x)) +#define ATC_DPIP_BOUNDARY(x) ((0x3FF & (x)) << 16) + + +/*-- descriptors -----------------------------------------------------*/ + +/* LLI == Linked List Item; aka DMA buffer descriptor */ +struct at_lli { + /* values that are not changed by hardware */ + dma_addr_t saddr; + dma_addr_t daddr; + /* value that may get written back: */ + u32 ctrla; + /* more values that are not changed by hardware */ + u32 ctrlb; + dma_addr_t dscr; /* chain to next lli */ +}; + +/** + * struct at_desc - software descriptor + * @at_lli: hardware lli structure + * @txd: support for the async_tx api + * @desc_node: node on the channed descriptors list + * @len: total transaction bytecount + */ +struct at_desc { + /* FIRST values the hardware uses */ + struct at_lli lli; + + /* THEN values for driver housekeeping */ + struct list_head tx_list; + struct dma_async_tx_descriptor txd; + struct list_head desc_node; + size_t len; +}; + +static inline struct at_desc * +txd_to_at_desc(struct dma_async_tx_descriptor *txd) +{ + return container_of(txd, struct at_desc, txd); +} + + +/*-- Channels --------------------------------------------------------*/ + +/** + * struct at_dma_chan - internal representation of an Atmel HDMAC channel + * @chan_common: common dmaengine channel object members + * @device: parent device + * @ch_regs: memory mapped register base + * @mask: channel index in a mask + * @error_status: transmit error status information from irq handler + * to tasklet (use atomic operations) + * @tasklet: bottom half to finish transaction work + * @lock: serializes enqueue/dequeue operations to descriptors lists + * @completed_cookie: identifier for the most recently completed operation + * @active_list: list of descriptors dmaengine is being running on + * @queue: list of descriptors ready to be submitted to engine + * @free_list: list of descriptors usable by the channel + * @descs_allocated: records the actual size of the descriptor pool + */ +struct at_dma_chan { + struct dma_chan chan_common; + struct at_dma *device; + void __iomem *ch_regs; + u8 mask; + unsigned long error_status; + struct tasklet_struct tasklet; + + spinlock_t lock; + + /* these other elements are all protected by lock */ + dma_cookie_t completed_cookie; + struct list_head active_list; + struct list_head queue; + struct list_head free_list; + unsigned int descs_allocated; +}; + +#define channel_readl(atchan, name) \ + __raw_readl((atchan)->ch_regs + ATC_##name##_OFFSET) + +#define channel_writel(atchan, name, val) \ + __raw_writel((val), (atchan)->ch_regs + ATC_##name##_OFFSET) + +static inline struct at_dma_chan *to_at_dma_chan(struct dma_chan *dchan) +{ + return container_of(dchan, struct at_dma_chan, chan_common); +} + + +/*-- Controller ------------------------------------------------------*/ + +/** + * struct at_dma - internal representation of an Atmel HDMA Controller + * @chan_common: common dmaengine dma_device object members + * @ch_regs: memory mapped register base + * @clk: dma controller clock + * @all_chan_mask: all channels availlable in a mask + * @dma_desc_pool: base of DMA descriptor region (DMA address) + * @chan: channels table to store at_dma_chan structures + */ +struct at_dma { + struct dma_device dma_common; + void __iomem *regs; + struct clk *clk; + + u8 all_chan_mask; + + struct dma_pool *dma_desc_pool; + /* AT THE END channels table */ + struct at_dma_chan chan[0]; +}; + +#define dma_readl(atdma, name) \ + __raw_readl((atdma)->regs + AT_DMA_##name) +#define dma_writel(atdma, name, val) \ + __raw_writel((val), (atdma)->regs + AT_DMA_##name) + +static inline struct at_dma *to_at_dma(struct dma_device *ddev) +{ + return container_of(ddev, struct at_dma, dma_common); +} + + +/*-- Helper functions ------------------------------------------------*/ + +static struct device *chan2dev(struct dma_chan *chan) +{ + return &chan->dev->device; +} +static struct device *chan2parent(struct dma_chan *chan) +{ + return chan->dev->device.parent; +} + +#if defined(VERBOSE_DEBUG) +static void vdbg_dump_regs(struct at_dma_chan *atchan) +{ + struct at_dma *atdma = to_at_dma(atchan->chan_common.device); + + dev_err(chan2dev(&atchan->chan_common), + " channel %d : imr = 0x%x, chsr = 0x%x\n", + atchan->chan_common.chan_id, + dma_readl(atdma, EBCIMR), + dma_readl(atdma, CHSR)); + + dev_err(chan2dev(&atchan->chan_common), + " channel: s0x%x d0x%x ctrl0x%x:0x%x cfg0x%x l0x%x\n", + channel_readl(atchan, SADDR), + channel_readl(atchan, DADDR), + channel_readl(atchan, CTRLA), + channel_readl(atchan, CTRLB), + channel_readl(atchan, CFG), + channel_readl(atchan, DSCR)); +} +#else +static void vdbg_dump_regs(struct at_dma_chan *atchan) {} +#endif + +static void atc_dump_lli(struct at_dma_chan *atchan, struct at_lli *lli) +{ + dev_printk(KERN_CRIT, chan2dev(&atchan->chan_common), + " desc: s0x%x d0x%x ctrl0x%x:0x%x l0x%x\n", + lli->saddr, lli->daddr, + lli->ctrla, lli->ctrlb, lli->dscr); +} + + +static void atc_setup_irq(struct at_dma_chan *atchan, int on) +{ + struct at_dma *atdma = to_at_dma(atchan->chan_common.device); + u32 ebci; + + /* enable interrupts on buffer chain completion & error */ + ebci = AT_DMA_CBTC(atchan->chan_common.chan_id) + | AT_DMA_ERR(atchan->chan_common.chan_id); + if (on) + dma_writel(atdma, EBCIER, ebci); + else + dma_writel(atdma, EBCIDR, ebci); +} + +static inline void atc_enable_irq(struct at_dma_chan *atchan) +{ + atc_setup_irq(atchan, 1); +} + +static inline void atc_disable_irq(struct at_dma_chan *atchan) +{ + atc_setup_irq(atchan, 0); +} + + +/** + * atc_chan_is_enabled - test if given channel is enabled + * @atchan: channel we want to test status + */ +static inline int atc_chan_is_enabled(struct at_dma_chan *atchan) +{ + struct at_dma *atdma = to_at_dma(atchan->chan_common.device); + + return !!(dma_readl(atdma, CHSR) & atchan->mask); +} + + +/** + * set_desc_eol - set end-of-link to descriptor so it will end transfer + * @desc: descriptor, signle or at the end of a chain, to end chain on + */ +static void set_desc_eol(struct at_desc *desc) +{ + desc->lli.ctrlb |= ATC_SRC_DSCR_DIS | ATC_DST_DSCR_DIS; + desc->lli.dscr = 0; +} + +#endif /* AT_HDMAC_REGS_H */ diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index d5bc628d207c..bd0b248de2cf 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -977,7 +977,6 @@ void dma_async_tx_descriptor_init(struct dma_async_tx_descriptor *tx, { tx->chan = chan; spin_lock_init(&tx->lock); - INIT_LIST_HEAD(&tx->tx_list); } EXPORT_SYMBOL(dma_async_tx_descriptor_init); diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index a3722a7384b5..a32a4cf7b1e0 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c @@ -38,6 +38,11 @@ module_param(max_channels, uint, S_IRUGO); MODULE_PARM_DESC(max_channels, "Maximum number of channels to use (default: all)"); +static unsigned int iterations; +module_param(iterations, uint, S_IRUGO); +MODULE_PARM_DESC(iterations, + "Iterations before stopping test (default: infinite)"); + static unsigned int xor_sources = 3; module_param(xor_sources, uint, S_IRUGO); MODULE_PARM_DESC(xor_sources, @@ -119,7 +124,7 @@ static void dmatest_init_srcs(u8 **bufs, unsigned int start, unsigned int len) buf[i] = PATTERN_SRC | (~i & PATTERN_COUNT_MASK); for ( ; i < start + len; i++) buf[i] = PATTERN_SRC | PATTERN_COPY - | (~i & PATTERN_COUNT_MASK);; + | (~i & PATTERN_COUNT_MASK); for ( ; i < test_buf_size; i++) buf[i] = PATTERN_SRC | (~i & PATTERN_COUNT_MASK); buf++; @@ -281,7 +286,8 @@ static int dmatest_func(void *data) flags = DMA_CTRL_ACK | DMA_COMPL_SKIP_DEST_UNMAP | DMA_PREP_INTERRUPT; - while (!kthread_should_stop()) { + while (!kthread_should_stop() + && !(iterations && total_tests >= iterations)) { struct dma_device *dev = chan->device; struct dma_async_tx_descriptor *tx = NULL; dma_addr_t dma_srcs[src_cnt]; @@ -450,6 +456,13 @@ err_srcbuf: err_srcs: pr_notice("%s: terminating after %u tests, %u failures (status %d)\n", thread_name, total_tests, failed_tests, ret); + + if (iterations > 0) + while (!kthread_should_stop()) { + DECLARE_WAIT_QUEUE_HEAD(wait_dmatest_exit); + interruptible_sleep_on(&wait_dmatest_exit); + } + return ret; } @@ -531,11 +544,11 @@ static int dmatest_add_channel(struct dma_chan *chan) if (dma_has_cap(DMA_MEMCPY, dma_dev->cap_mask)) { cnt = dmatest_add_threads(dtc, DMA_MEMCPY); - thread_count += cnt > 0 ?: 0; + thread_count += cnt > 0 ? cnt : 0; } if (dma_has_cap(DMA_XOR, dma_dev->cap_mask)) { cnt = dmatest_add_threads(dtc, DMA_XOR); - thread_count += cnt > 0 ?: 0; + thread_count += cnt > 0 ? cnt : 0; } if (dma_has_cap(DMA_PQ, dma_dev->cap_mask)) { cnt = dmatest_add_threads(dtc, DMA_PQ); diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c index 98c9a847bf51..8fb748280361 100644 --- a/drivers/dma/dw_dmac.c +++ b/drivers/dma/dw_dmac.c @@ -116,7 +116,7 @@ static void dwc_sync_desc_for_cpu(struct dw_dma_chan *dwc, struct dw_desc *desc) { struct dw_desc *child; - list_for_each_entry(child, &desc->txd.tx_list, desc_node) + list_for_each_entry(child, &desc->tx_list, desc_node) dma_sync_single_for_cpu(chan2parent(&dwc->chan), child->txd.phys, sizeof(child->lli), DMA_TO_DEVICE); @@ -137,11 +137,11 @@ static void dwc_desc_put(struct dw_dma_chan *dwc, struct dw_desc *desc) dwc_sync_desc_for_cpu(dwc, desc); spin_lock_bh(&dwc->lock); - list_for_each_entry(child, &desc->txd.tx_list, desc_node) + list_for_each_entry(child, &desc->tx_list, desc_node) dev_vdbg(chan2dev(&dwc->chan), "moving child desc %p to freelist\n", child); - list_splice_init(&desc->txd.tx_list, &dwc->free_list); + list_splice_init(&desc->tx_list, &dwc->free_list); dev_vdbg(chan2dev(&dwc->chan), "moving desc %p to freelist\n", desc); list_add(&desc->desc_node, &dwc->free_list); spin_unlock_bh(&dwc->lock); @@ -209,19 +209,28 @@ dwc_descriptor_complete(struct dw_dma_chan *dwc, struct dw_desc *desc) param = txd->callback_param; dwc_sync_desc_for_cpu(dwc, desc); - list_splice_init(&txd->tx_list, &dwc->free_list); + list_splice_init(&desc->tx_list, &dwc->free_list); list_move(&desc->desc_node, &dwc->free_list); - /* - * We use dma_unmap_page() regardless of how the buffers were - * mapped before they were submitted... - */ - if (!(txd->flags & DMA_COMPL_SKIP_DEST_UNMAP)) - dma_unmap_page(chan2parent(&dwc->chan), desc->lli.dar, - desc->len, DMA_FROM_DEVICE); - if (!(txd->flags & DMA_COMPL_SKIP_SRC_UNMAP)) - dma_unmap_page(chan2parent(&dwc->chan), desc->lli.sar, - desc->len, DMA_TO_DEVICE); + if (!dwc->chan.private) { + struct device *parent = chan2parent(&dwc->chan); + if (!(txd->flags & DMA_COMPL_SKIP_DEST_UNMAP)) { + if (txd->flags & DMA_COMPL_DEST_UNMAP_SINGLE) + dma_unmap_single(parent, desc->lli.dar, + desc->len, DMA_FROM_DEVICE); + else + dma_unmap_page(parent, desc->lli.dar, + desc->len, DMA_FROM_DEVICE); + } + if (!(txd->flags & DMA_COMPL_SKIP_SRC_UNMAP)) { + if (txd->flags & DMA_COMPL_SRC_UNMAP_SINGLE) + dma_unmap_single(parent, desc->lli.sar, + desc->len, DMA_TO_DEVICE); + else + dma_unmap_page(parent, desc->lli.sar, + desc->len, DMA_TO_DEVICE); + } + } /* * The API requires that no submissions are done from a @@ -289,7 +298,7 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc) /* This one is currently in progress */ return; - list_for_each_entry(child, &desc->txd.tx_list, desc_node) + list_for_each_entry(child, &desc->tx_list, desc_node) if (child->lli.llp == llp) /* Currently in progress */ return; @@ -356,7 +365,7 @@ static void dwc_handle_error(struct dw_dma *dw, struct dw_dma_chan *dwc) dev_printk(KERN_CRIT, chan2dev(&dwc->chan), " cookie: %d\n", bad_desc->txd.cookie); dwc_dump_lli(dwc, &bad_desc->lli); - list_for_each_entry(child, &bad_desc->txd.tx_list, desc_node) + list_for_each_entry(child, &bad_desc->tx_list, desc_node) dwc_dump_lli(dwc, &child->lli); /* Pretend the descriptor completed successfully */ @@ -608,7 +617,7 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, prev->txd.phys, sizeof(prev->lli), DMA_TO_DEVICE); list_add_tail(&desc->desc_node, - &first->txd.tx_list); + &first->tx_list); } prev = desc; } @@ -658,8 +667,6 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, reg_width = dws->reg_width; prev = first = NULL; - sg_len = dma_map_sg(chan2parent(chan), sgl, sg_len, direction); - switch (direction) { case DMA_TO_DEVICE: ctllo = (DWC_DEFAULT_CTLLO @@ -700,7 +707,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, sizeof(prev->lli), DMA_TO_DEVICE); list_add_tail(&desc->desc_node, - &first->txd.tx_list); + &first->tx_list); } prev = desc; total_len += len; @@ -746,7 +753,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, sizeof(prev->lli), DMA_TO_DEVICE); list_add_tail(&desc->desc_node, - &first->txd.tx_list); + &first->tx_list); } prev = desc; total_len += len; @@ -902,6 +909,7 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan) break; } + INIT_LIST_HEAD(&desc->tx_list); dma_async_tx_descriptor_init(&desc->txd, chan); desc->txd.tx_submit = dwc_tx_submit; desc->txd.flags = DMA_CTRL_ACK; diff --git a/drivers/dma/dw_dmac_regs.h b/drivers/dma/dw_dmac_regs.h index 13a580767031..d9a939f67f46 100644 --- a/drivers/dma/dw_dmac_regs.h +++ b/drivers/dma/dw_dmac_regs.h @@ -217,6 +217,7 @@ struct dw_desc { /* THEN values for driver housekeeping */ struct list_head desc_node; + struct list_head tx_list; struct dma_async_tx_descriptor txd; size_t len; }; diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c index f18d1bde0439..296f9e747fac 100644 --- a/drivers/dma/fsldma.c +++ b/drivers/dma/fsldma.c @@ -12,6 +12,11 @@ * also fit for MPC8560, MPC8555, MPC8548, MPC8641, and etc. * The support for MPC8349 DMA contorller is also added. * + * This driver instructs the DMA controller to issue the PCI Read Multiple + * command for PCI read operations, instead of using the default PCI Read Line + * command. Please be aware that this setting may result in read pre-fetching + * on some platforms. + * * This 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 @@ -29,6 +34,7 @@ #include #include +#include #include "fsldma.h" static void dma_init(struct fsl_dma_chan *fsl_chan) @@ -49,9 +55,10 @@ static void dma_init(struct fsl_dma_chan *fsl_chan) case FSL_DMA_IP_83XX: /* Set the channel to below modes: * EOTIE - End-of-transfer interrupt enable + * PRC_RM - PCI read multiple */ - DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr, FSL_DMA_MR_EOTIE, - 32); + DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr, FSL_DMA_MR_EOTIE + | FSL_DMA_MR_PRC_RM, 32); break; } @@ -136,15 +143,16 @@ static int dma_is_idle(struct fsl_dma_chan *fsl_chan) static void dma_start(struct fsl_dma_chan *fsl_chan) { - u32 mr_set = 0;; + u32 mr_set = 0; if (fsl_chan->feature & FSL_DMA_CHAN_PAUSE_EXT) { DMA_OUT(fsl_chan, &fsl_chan->reg_base->bcr, 0, 32); mr_set |= FSL_DMA_MR_EMP_EN; - } else + } else if ((fsl_chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_85XX) { DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr, DMA_IN(fsl_chan, &fsl_chan->reg_base->mr, 32) & ~FSL_DMA_MR_EMP_EN, 32); + } if (fsl_chan->feature & FSL_DMA_CHAN_START_EXT) mr_set |= FSL_DMA_MR_EMS_EN; @@ -272,29 +280,41 @@ static void fsl_chan_set_dest_loop_size(struct fsl_dma_chan *fsl_chan, int size) } } +/** + * fsl_chan_set_request_count - Set DMA Request Count for external control + * @fsl_chan : Freescale DMA channel + * @size : Number of bytes to transfer in a single request + * + * The Freescale DMA channel can be controlled by the external signal DREQ#. + * The DMA request count is how many bytes are allowed to transfer before + * pausing the channel, after which a new assertion of DREQ# resumes channel + * operation. + * + * A size of 0 disables external pause control. The maximum size is 1024. + */ +static void fsl_chan_set_request_count(struct fsl_dma_chan *fsl_chan, int size) +{ + BUG_ON(size > 1024); + DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr, + DMA_IN(fsl_chan, &fsl_chan->reg_base->mr, 32) + | ((__ilog2(size) << 24) & 0x0f000000), + 32); +} + /** * fsl_chan_toggle_ext_pause - Toggle channel external pause status * @fsl_chan : Freescale DMA channel - * @size : Pause control size, 0 for disable external pause control. - * The maximum is 1024. + * @enable : 0 is disabled, 1 is enabled. * - * The Freescale DMA channel can be controlled by the external - * signal DREQ#. The pause control size is how many bytes are allowed - * to transfer before pausing the channel, after which a new assertion - * of DREQ# resumes channel operation. + * The Freescale DMA channel can be controlled by the external signal DREQ#. + * The DMA Request Count feature should be used in addition to this feature + * to set the number of bytes to transfer before pausing the channel. */ -static void fsl_chan_toggle_ext_pause(struct fsl_dma_chan *fsl_chan, int size) +static void fsl_chan_toggle_ext_pause(struct fsl_dma_chan *fsl_chan, int enable) { - if (size > 1024) - return; - - if (size) { - DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr, - DMA_IN(fsl_chan, &fsl_chan->reg_base->mr, 32) - | ((__ilog2(size) << 24) & 0x0f000000), - 32); + if (enable) fsl_chan->feature |= FSL_DMA_CHAN_PAUSE_EXT; - } else + else fsl_chan->feature &= ~FSL_DMA_CHAN_PAUSE_EXT; } @@ -319,7 +339,8 @@ static void fsl_chan_toggle_ext_start(struct fsl_dma_chan *fsl_chan, int enable) static dma_cookie_t fsl_dma_tx_submit(struct dma_async_tx_descriptor *tx) { struct fsl_dma_chan *fsl_chan = to_fsl_chan(tx->chan); - struct fsl_desc_sw *desc; + struct fsl_desc_sw *desc = tx_to_fsl_desc(tx); + struct fsl_desc_sw *child; unsigned long flags; dma_cookie_t cookie; @@ -327,7 +348,7 @@ static dma_cookie_t fsl_dma_tx_submit(struct dma_async_tx_descriptor *tx) spin_lock_irqsave(&fsl_chan->desc_lock, flags); cookie = fsl_chan->common.cookie; - list_for_each_entry(desc, &tx->tx_list, node) { + list_for_each_entry(child, &desc->tx_list, node) { cookie++; if (cookie < 0) cookie = 1; @@ -336,8 +357,8 @@ static dma_cookie_t fsl_dma_tx_submit(struct dma_async_tx_descriptor *tx) } fsl_chan->common.cookie = cookie; - append_ld_queue(fsl_chan, tx_to_fsl_desc(tx)); - list_splice_init(&tx->tx_list, fsl_chan->ld_queue.prev); + append_ld_queue(fsl_chan, desc); + list_splice_init(&desc->tx_list, fsl_chan->ld_queue.prev); spin_unlock_irqrestore(&fsl_chan->desc_lock, flags); @@ -359,6 +380,7 @@ static struct fsl_desc_sw *fsl_dma_alloc_descriptor( desc_sw = dma_pool_alloc(fsl_chan->desc_pool, GFP_ATOMIC, &pdesc); if (desc_sw) { memset(desc_sw, 0, sizeof(struct fsl_desc_sw)); + INIT_LIST_HEAD(&desc_sw->tx_list); dma_async_tx_descriptor_init(&desc_sw->async_tx, &fsl_chan->common); desc_sw->async_tx.tx_submit = fsl_dma_tx_submit; @@ -448,7 +470,7 @@ fsl_dma_prep_interrupt(struct dma_chan *chan, unsigned long flags) new->async_tx.flags = flags; /* Insert the link descriptor to the LD ring */ - list_add_tail(&new->node, &new->async_tx.tx_list); + list_add_tail(&new->node, &new->tx_list); /* Set End-of-link to the last link descriptor of new list*/ set_ld_eol(fsl_chan, new); @@ -506,7 +528,7 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_memcpy( dma_dest += copy; /* Insert the link descriptor to the LD ring */ - list_add_tail(&new->node, &first->async_tx.tx_list); + list_add_tail(&new->node, &first->tx_list); } while (len); new->async_tx.flags = flags; /* client is in control of this ack */ @@ -521,7 +543,7 @@ fail: if (!first) return NULL; - list = &first->async_tx.tx_list; + list = &first->tx_list; list_for_each_entry_safe_reverse(new, prev, list, node) { list_del(&new->node); dma_pool_free(fsl_chan->desc_pool, new, new->async_tx.phys); @@ -530,6 +552,229 @@ fail: return NULL; } +/** + * fsl_dma_prep_slave_sg - prepare descriptors for a DMA_SLAVE transaction + * @chan: DMA channel + * @sgl: scatterlist to transfer to/from + * @sg_len: number of entries in @scatterlist + * @direction: DMA direction + * @flags: DMAEngine flags + * + * Prepare a set of descriptors for a DMA_SLAVE transaction. Following the + * DMA_SLAVE API, this gets the device-specific information from the + * chan->private variable. + */ +static struct dma_async_tx_descriptor *fsl_dma_prep_slave_sg( + struct dma_chan *chan, struct scatterlist *sgl, unsigned int sg_len, + enum dma_data_direction direction, unsigned long flags) +{ + struct fsl_dma_chan *fsl_chan; + struct fsl_desc_sw *first = NULL, *prev = NULL, *new = NULL; + struct fsl_dma_slave *slave; + struct list_head *tx_list; + size_t copy; + + int i; + struct scatterlist *sg; + size_t sg_used; + size_t hw_used; + struct fsl_dma_hw_addr *hw; + dma_addr_t dma_dst, dma_src; + + if (!chan) + return NULL; + + if (!chan->private) + return NULL; + + fsl_chan = to_fsl_chan(chan); + slave = chan->private; + + if (list_empty(&slave->addresses)) + return NULL; + + hw = list_first_entry(&slave->addresses, struct fsl_dma_hw_addr, entry); + hw_used = 0; + + /* + * Build the hardware transaction to copy from the scatterlist to + * the hardware, or from the hardware to the scatterlist + * + * If you are copying from the hardware to the scatterlist and it + * takes two hardware entries to fill an entire page, then both + * hardware entries will be coalesced into the same page + * + * If you are copying from the scatterlist to the hardware and a + * single page can fill two hardware entries, then the data will + * be read out of the page into the first hardware entry, and so on + */ + for_each_sg(sgl, sg, sg_len, i) { + sg_used = 0; + + /* Loop until the entire scatterlist entry is used */ + while (sg_used < sg_dma_len(sg)) { + + /* + * If we've used up the current hardware address/length + * pair, we need to load a new one + * + * This is done in a while loop so that descriptors with + * length == 0 will be skipped + */ + while (hw_used >= hw->length) { + + /* + * If the current hardware entry is the last + * entry in the list, we're finished + */ + if (list_is_last(&hw->entry, &slave->addresses)) + goto finished; + + /* Get the next hardware address/length pair */ + hw = list_entry(hw->entry.next, + struct fsl_dma_hw_addr, entry); + hw_used = 0; + } + + /* Allocate the link descriptor from DMA pool */ + new = fsl_dma_alloc_descriptor(fsl_chan); + if (!new) { + dev_err(fsl_chan->dev, "No free memory for " + "link descriptor\n"); + goto fail; + } +#ifdef FSL_DMA_LD_DEBUG + dev_dbg(fsl_chan->dev, "new link desc alloc %p\n", new); +#endif + + /* + * Calculate the maximum number of bytes to transfer, + * making sure it is less than the DMA controller limit + */ + copy = min_t(size_t, sg_dma_len(sg) - sg_used, + hw->length - hw_used); + copy = min_t(size_t, copy, FSL_DMA_BCR_MAX_CNT); + + /* + * DMA_FROM_DEVICE + * from the hardware to the scatterlist + * + * DMA_TO_DEVICE + * from the scatterlist to the hardware + */ + if (direction == DMA_FROM_DEVICE) { + dma_src = hw->address + hw_used; + dma_dst = sg_dma_address(sg) + sg_used; + } else { + dma_src = sg_dma_address(sg) + sg_used; + dma_dst = hw->address + hw_used; + } + + /* Fill in the descriptor */ + set_desc_cnt(fsl_chan, &new->hw, copy); + set_desc_src(fsl_chan, &new->hw, dma_src); + set_desc_dest(fsl_chan, &new->hw, dma_dst); + + /* + * If this is not the first descriptor, chain the + * current descriptor after the previous descriptor + */ + if (!first) { + first = new; + } else { + set_desc_next(fsl_chan, &prev->hw, + new->async_tx.phys); + } + + new->async_tx.cookie = 0; + async_tx_ack(&new->async_tx); + + prev = new; + sg_used += copy; + hw_used += copy; + + /* Insert the link descriptor into the LD ring */ + list_add_tail(&new->node, &first->tx_list); + } + } + +finished: + + /* All of the hardware address/length pairs had length == 0 */ + if (!first || !new) + return NULL; + + new->async_tx.flags = flags; + new->async_tx.cookie = -EBUSY; + + /* Set End-of-link to the last link descriptor of new list */ + set_ld_eol(fsl_chan, new); + + /* Enable extra controller features */ + if (fsl_chan->set_src_loop_size) + fsl_chan->set_src_loop_size(fsl_chan, slave->src_loop_size); + + if (fsl_chan->set_dest_loop_size) + fsl_chan->set_dest_loop_size(fsl_chan, slave->dst_loop_size); + + if (fsl_chan->toggle_ext_start) + fsl_chan->toggle_ext_start(fsl_chan, slave->external_start); + + if (fsl_chan->toggle_ext_pause) + fsl_chan->toggle_ext_pause(fsl_chan, slave->external_pause); + + if (fsl_chan->set_request_count) + fsl_chan->set_request_count(fsl_chan, slave->request_count); + + return &first->async_tx; + +fail: + /* If first was not set, then we failed to allocate the very first + * descriptor, and we're done */ + if (!first) + return NULL; + + /* + * First is set, so all of the descriptors we allocated have been added + * to first->tx_list, INCLUDING "first" itself. Therefore we + * must traverse the list backwards freeing each descriptor in turn + * + * We're re-using variables for the loop, oh well + */ + tx_list = &first->tx_list; + list_for_each_entry_safe_reverse(new, prev, tx_list, node) { + list_del_init(&new->node); + dma_pool_free(fsl_chan->desc_pool, new, new->async_tx.phys); + } + + return NULL; +} + +static void fsl_dma_device_terminate_all(struct dma_chan *chan) +{ + struct fsl_dma_chan *fsl_chan; + struct fsl_desc_sw *desc, *tmp; + unsigned long flags; + + if (!chan) + return; + + fsl_chan = to_fsl_chan(chan); + + /* Halt the DMA engine */ + dma_halt(fsl_chan); + + spin_lock_irqsave(&fsl_chan->desc_lock, flags); + + /* Remove and free all of the descriptors in the LD queue */ + list_for_each_entry_safe(desc, tmp, &fsl_chan->ld_queue, node) { + list_del(&desc->node); + dma_pool_free(fsl_chan->desc_pool, desc, desc->async_tx.phys); + } + + spin_unlock_irqrestore(&fsl_chan->desc_lock, flags); +} + /** * fsl_dma_update_completed_cookie - Update the completed cookie. * @fsl_chan : Freescale DMA channel @@ -871,11 +1116,12 @@ static int __devinit fsl_dma_chan_probe(struct fsl_dma_device *fdev, switch (new_fsl_chan->feature & FSL_DMA_IP_MASK) { case FSL_DMA_IP_85XX: - new_fsl_chan->toggle_ext_start = fsl_chan_toggle_ext_start; new_fsl_chan->toggle_ext_pause = fsl_chan_toggle_ext_pause; case FSL_DMA_IP_83XX: + new_fsl_chan->toggle_ext_start = fsl_chan_toggle_ext_start; new_fsl_chan->set_src_loop_size = fsl_chan_set_src_loop_size; new_fsl_chan->set_dest_loop_size = fsl_chan_set_dest_loop_size; + new_fsl_chan->set_request_count = fsl_chan_set_request_count; } spin_lock_init(&new_fsl_chan->desc_lock); @@ -955,12 +1201,15 @@ static int __devinit of_fsl_dma_probe(struct of_device *dev, dma_cap_set(DMA_MEMCPY, fdev->common.cap_mask); dma_cap_set(DMA_INTERRUPT, fdev->common.cap_mask); + dma_cap_set(DMA_SLAVE, fdev->common.cap_mask); fdev->common.device_alloc_chan_resources = fsl_dma_alloc_chan_resources; fdev->common.device_free_chan_resources = fsl_dma_free_chan_resources; fdev->common.device_prep_dma_interrupt = fsl_dma_prep_interrupt; fdev->common.device_prep_dma_memcpy = fsl_dma_prep_memcpy; fdev->common.device_is_tx_complete = fsl_dma_is_complete; fdev->common.device_issue_pending = fsl_dma_memcpy_issue_pending; + fdev->common.device_prep_slave_sg = fsl_dma_prep_slave_sg; + fdev->common.device_terminate_all = fsl_dma_device_terminate_all; fdev->common.dev = &dev->dev; fdev->irq = irq_of_parse_and_map(dev->node, 0); diff --git a/drivers/dma/fsldma.h b/drivers/dma/fsldma.h index 4f21a512d848..0df14cbb8ca3 100644 --- a/drivers/dma/fsldma.h +++ b/drivers/dma/fsldma.h @@ -38,6 +38,7 @@ /* Special MR definition for MPC8349 */ #define FSL_DMA_MR_EOTIE 0x00000080 +#define FSL_DMA_MR_PRC_RM 0x00000800 #define FSL_DMA_SR_CH 0x00000020 #define FSL_DMA_SR_PE 0x00000010 @@ -89,6 +90,7 @@ struct fsl_dma_ld_hw { struct fsl_desc_sw { struct fsl_dma_ld_hw hw; struct list_head node; + struct list_head tx_list; struct dma_async_tx_descriptor async_tx; struct list_head *ld; void *priv; @@ -142,10 +144,11 @@ struct fsl_dma_chan { struct tasklet_struct tasklet; u32 feature; - void (*toggle_ext_pause)(struct fsl_dma_chan *fsl_chan, int size); + void (*toggle_ext_pause)(struct fsl_dma_chan *fsl_chan, int enable); void (*toggle_ext_start)(struct fsl_dma_chan *fsl_chan, int enable); void (*set_src_loop_size)(struct fsl_dma_chan *fsl_chan, int size); void (*set_dest_loop_size)(struct fsl_dma_chan *fsl_chan, int size); + void (*set_request_count)(struct fsl_dma_chan *fsl_chan, int size); }; #define to_fsl_chan(chan) container_of(chan, struct fsl_dma_chan, common) diff --git a/drivers/dma/ioat/dma.c b/drivers/dma/ioat/dma.c index 32a757be75c1..c524d36d3c2e 100644 --- a/drivers/dma/ioat/dma.c +++ b/drivers/dma/ioat/dma.c @@ -251,12 +251,12 @@ static dma_cookie_t ioat1_tx_submit(struct dma_async_tx_descriptor *tx) dev_dbg(to_dev(&ioat->base), "%s: cookie: %d\n", __func__, cookie); /* write address into NextDescriptor field of last desc in chain */ - first = to_ioat_desc(tx->tx_list.next); + first = to_ioat_desc(desc->tx_list.next); chain_tail = to_ioat_desc(ioat->used_desc.prev); /* make descriptor updates globally visible before chaining */ wmb(); chain_tail->hw->next = first->txd.phys; - list_splice_tail_init(&tx->tx_list, &ioat->used_desc); + list_splice_tail_init(&desc->tx_list, &ioat->used_desc); dump_desc_dbg(ioat, chain_tail); dump_desc_dbg(ioat, first); @@ -298,6 +298,7 @@ ioat_dma_alloc_descriptor(struct ioat_dma_chan *ioat, gfp_t flags) memset(desc, 0, sizeof(*desc)); + INIT_LIST_HEAD(&desc_sw->tx_list); dma_async_tx_descriptor_init(&desc_sw->txd, &ioat->base.common); desc_sw->txd.tx_submit = ioat1_tx_submit; desc_sw->hw = desc; @@ -522,7 +523,7 @@ ioat1_dma_prep_memcpy(struct dma_chan *c, dma_addr_t dma_dest, desc->txd.flags = flags; desc->len = total_len; - list_splice(&chain, &desc->txd.tx_list); + list_splice(&chain, &desc->tx_list); hw->ctl_f.int_en = !!(flags & DMA_PREP_INTERRUPT); hw->ctl_f.compl_write = 1; hw->tx_cnt = tx_cnt; diff --git a/drivers/dma/ioat/dma.h b/drivers/dma/ioat/dma.h index 0e37e426c729..6a675a2a2d1c 100644 --- a/drivers/dma/ioat/dma.h +++ b/drivers/dma/ioat/dma.h @@ -171,7 +171,7 @@ ioat_is_complete(struct dma_chan *c, dma_cookie_t cookie, * struct ioat_desc_sw - wrapper around hardware descriptor * @hw: hardware DMA descriptor (for memcpy) * @node: this descriptor will either be on the free list, - * or attached to a transaction list (async_tx.tx_list) + * or attached to a transaction list (tx_list) * @txd: the generic software descriptor for all engines * @id: identifier for debug */ @@ -179,6 +179,7 @@ struct ioat_desc_sw { struct ioat_dma_descriptor *hw; struct list_head node; size_t len; + struct list_head tx_list; struct dma_async_tx_descriptor txd; #ifdef DEBUG int id; diff --git a/drivers/dma/ioat/dma_v2.c b/drivers/dma/ioat/dma_v2.c index 7bbbd83d12e6..5d6ac49e0d32 100644 --- a/drivers/dma/ioat/dma_v2.c +++ b/drivers/dma/ioat/dma_v2.c @@ -397,11 +397,12 @@ static struct ioat_ring_ent *ioat2_alloc_ring_ent(struct dma_chan *chan, gfp_t f return NULL; memset(hw, 0, sizeof(*hw)); - desc = kzalloc(sizeof(*desc), flags); + desc = kmem_cache_alloc(ioat2_cache, flags); if (!desc) { pci_pool_free(dma->dma_pool, hw, phys); return NULL; } + memset(desc, 0, sizeof(*desc)); dma_async_tx_descriptor_init(&desc->txd, chan); desc->txd.tx_submit = ioat2_tx_submit_unlock; @@ -416,7 +417,7 @@ static void ioat2_free_ring_ent(struct ioat_ring_ent *desc, struct dma_chan *cha dma = to_ioatdma_device(chan->device); pci_pool_free(dma->dma_pool, desc->hw, desc->txd.phys); - kfree(desc); + kmem_cache_free(ioat2_cache, desc); } static struct ioat_ring_ent **ioat2_alloc_ring(struct dma_chan *c, int order, gfp_t flags) diff --git a/drivers/dma/ioat/dma_v2.h b/drivers/dma/ioat/dma_v2.h index 246e646b1904..1d849ef74d5f 100644 --- a/drivers/dma/ioat/dma_v2.h +++ b/drivers/dma/ioat/dma_v2.h @@ -142,8 +142,8 @@ struct ioat_ring_ent { struct ioat_pq_update_descriptor *pqu; struct ioat_raw_descriptor *raw; }; - struct dma_async_tx_descriptor txd; size_t len; + struct dma_async_tx_descriptor txd; enum sum_check_flags *result; #ifdef DEBUG int id; @@ -186,4 +186,5 @@ void __ioat2_issue_pending(struct ioat2_dma_chan *ioat); void ioat2_cleanup_tasklet(unsigned long data); void ioat2_timer_event(unsigned long data); extern struct kobj_type ioat2_ktype; +extern struct kmem_cache *ioat2_cache; #endif /* IOATDMA_V2_H */ diff --git a/drivers/dma/ioat/pci.c b/drivers/dma/ioat/pci.c index b77d3a2864ad..c788fa266470 100644 --- a/drivers/dma/ioat/pci.c +++ b/drivers/dma/ioat/pci.c @@ -83,6 +83,8 @@ static int ioat_dca_enabled = 1; module_param(ioat_dca_enabled, int, 0644); MODULE_PARM_DESC(ioat_dca_enabled, "control support of dca service (default: 1)"); +struct kmem_cache *ioat2_cache; + #define DRV_NAME "ioatdma" static struct pci_driver ioat_pci_driver = { @@ -182,15 +184,27 @@ static void __devexit ioat_remove(struct pci_dev *pdev) static int __init ioat_init_module(void) { + int err; + pr_info("%s: Intel(R) QuickData Technology Driver %s\n", DRV_NAME, IOAT_DMA_VERSION); - return pci_register_driver(&ioat_pci_driver); + ioat2_cache = kmem_cache_create("ioat2", sizeof(struct ioat_ring_ent), + 0, SLAB_HWCACHE_ALIGN, NULL); + if (!ioat2_cache) + return -ENOMEM; + + err = pci_register_driver(&ioat_pci_driver); + if (err) + kmem_cache_destroy(ioat2_cache); + + return err; } module_init(ioat_init_module); static void __exit ioat_exit_module(void) { pci_unregister_driver(&ioat_pci_driver); + kmem_cache_destroy(ioat2_cache); } module_exit(ioat_exit_module); diff --git a/drivers/dma/iop-adma.c b/drivers/dma/iop-adma.c index 518f557ef857..645ca8d54ec4 100644 --- a/drivers/dma/iop-adma.c +++ b/drivers/dma/iop-adma.c @@ -421,7 +421,7 @@ retry: } alloc_tail->group_head = alloc_start; alloc_tail->async_tx.cookie = -EBUSY; - list_splice(&chain, &alloc_tail->async_tx.tx_list); + list_splice(&chain, &alloc_tail->tx_list); iop_chan->last_used = last_used; iop_desc_clear_next_desc(alloc_start); iop_desc_clear_next_desc(alloc_tail); @@ -480,7 +480,7 @@ iop_adma_tx_submit(struct dma_async_tx_descriptor *tx) old_chain_tail = list_entry(iop_chan->chain.prev, struct iop_adma_desc_slot, chain_node); - list_splice_init(&sw_desc->async_tx.tx_list, + list_splice_init(&sw_desc->tx_list, &old_chain_tail->chain_node); /* fix up the hardware chain */ @@ -547,6 +547,7 @@ static int iop_adma_alloc_chan_resources(struct dma_chan *chan) dma_async_tx_descriptor_init(&slot->async_tx, chan); slot->async_tx.tx_submit = iop_adma_tx_submit; + INIT_LIST_HEAD(&slot->tx_list); INIT_LIST_HEAD(&slot->chain_node); INIT_LIST_HEAD(&slot->slot_node); hw_desc = (char *) iop_chan->device->dma_desc_pool; @@ -1642,7 +1643,7 @@ static void iop_chan_start_null_memcpy(struct iop_adma_chan *iop_chan) if (sw_desc) { grp_start = sw_desc->group_head; - list_splice_init(&sw_desc->async_tx.tx_list, &iop_chan->chain); + list_splice_init(&sw_desc->tx_list, &iop_chan->chain); async_tx_ack(&sw_desc->async_tx); iop_desc_init_memcpy(grp_start, 0); iop_desc_set_byte_count(grp_start, iop_chan, 0); @@ -1698,7 +1699,7 @@ static void iop_chan_start_null_xor(struct iop_adma_chan *iop_chan) sw_desc = iop_adma_alloc_slots(iop_chan, slot_cnt, slots_per_op); if (sw_desc) { grp_start = sw_desc->group_head; - list_splice_init(&sw_desc->async_tx.tx_list, &iop_chan->chain); + list_splice_init(&sw_desc->tx_list, &iop_chan->chain); async_tx_ack(&sw_desc->async_tx); iop_desc_init_null_xor(grp_start, 2, 0); iop_desc_set_byte_count(grp_start, iop_chan, 0); diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c index ddab94f51224..466ab10c1ff1 100644 --- a/drivers/dma/mv_xor.c +++ b/drivers/dma/mv_xor.c @@ -517,7 +517,7 @@ retry: } alloc_tail->group_head = alloc_start; alloc_tail->async_tx.cookie = -EBUSY; - list_splice(&chain, &alloc_tail->async_tx.tx_list); + list_splice(&chain, &alloc_tail->tx_list); mv_chan->last_used = last_used; mv_desc_clear_next_desc(alloc_start); mv_desc_clear_next_desc(alloc_tail); @@ -565,14 +565,14 @@ mv_xor_tx_submit(struct dma_async_tx_descriptor *tx) cookie = mv_desc_assign_cookie(mv_chan, sw_desc); if (list_empty(&mv_chan->chain)) - list_splice_init(&sw_desc->async_tx.tx_list, &mv_chan->chain); + list_splice_init(&sw_desc->tx_list, &mv_chan->chain); else { new_hw_chain = 0; old_chain_tail = list_entry(mv_chan->chain.prev, struct mv_xor_desc_slot, chain_node); - list_splice_init(&grp_start->async_tx.tx_list, + list_splice_init(&grp_start->tx_list, &old_chain_tail->chain_node); if (!mv_can_chain(grp_start)) @@ -632,6 +632,7 @@ static int mv_xor_alloc_chan_resources(struct dma_chan *chan) slot->async_tx.tx_submit = mv_xor_tx_submit; INIT_LIST_HEAD(&slot->chain_node); INIT_LIST_HEAD(&slot->slot_node); + INIT_LIST_HEAD(&slot->tx_list); hw_desc = (char *) mv_chan->device->dma_desc_pool; slot->async_tx.phys = (dma_addr_t) &hw_desc[idx * MV_XOR_SLOT_SIZE]; @@ -1176,7 +1177,7 @@ static int __devinit mv_xor_probe(struct platform_device *pdev) if (dma_has_cap(DMA_MEMSET, dma_dev->cap_mask)) dma_dev->device_prep_dma_memset = mv_xor_prep_dma_memset; if (dma_has_cap(DMA_XOR, dma_dev->cap_mask)) { - dma_dev->max_xor = 8; ; + dma_dev->max_xor = 8; dma_dev->device_prep_dma_xor = mv_xor_prep_dma_xor; } diff --git a/drivers/dma/mv_xor.h b/drivers/dma/mv_xor.h index 06cafe1ef521..977b592e976b 100644 --- a/drivers/dma/mv_xor.h +++ b/drivers/dma/mv_xor.h @@ -126,9 +126,8 @@ struct mv_xor_chan { * @idx: pool index * @unmap_src_cnt: number of xor sources * @unmap_len: transaction bytecount + * @tx_list: list of slots that make up a multi-descriptor transaction * @async_tx: support for the async_tx api - * @group_list: list of slots that make up a multi-descriptor transaction - * for example transfer lengths larger than the supported hw max * @xor_check_result: result of zero sum * @crc32_result: result crc calculation */ @@ -145,6 +144,7 @@ struct mv_xor_desc_slot { u16 unmap_src_cnt; u32 value; size_t unmap_len; + struct list_head tx_list; struct dma_async_tx_descriptor async_tx; union { u32 *xor_check_result; diff --git a/drivers/dma/txx9dmac.c b/drivers/dma/txx9dmac.c new file mode 100644 index 000000000000..197c7bc37895 --- /dev/null +++ b/drivers/dma/txx9dmac.c @@ -0,0 +1,1356 @@ +/* + * Driver for the TXx9 SoC DMA Controller + * + * Copyright (C) 2009 Atsushi Nemoto + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "txx9dmac.h" + +static struct txx9dmac_chan *to_txx9dmac_chan(struct dma_chan *chan) +{ + return container_of(chan, struct txx9dmac_chan, chan); +} + +static struct txx9dmac_cregs __iomem *__dma_regs(const struct txx9dmac_chan *dc) +{ + return dc->ch_regs; +} + +static struct txx9dmac_cregs32 __iomem *__dma_regs32( + const struct txx9dmac_chan *dc) +{ + return dc->ch_regs; +} + +#define channel64_readq(dc, name) \ + __raw_readq(&(__dma_regs(dc)->name)) +#define channel64_writeq(dc, name, val) \ + __raw_writeq((val), &(__dma_regs(dc)->name)) +#define channel64_readl(dc, name) \ + __raw_readl(&(__dma_regs(dc)->name)) +#define channel64_writel(dc, name, val) \ + __raw_writel((val), &(__dma_regs(dc)->name)) + +#define channel32_readl(dc, name) \ + __raw_readl(&(__dma_regs32(dc)->name)) +#define channel32_writel(dc, name, val) \ + __raw_writel((val), &(__dma_regs32(dc)->name)) + +#define channel_readq(dc, name) channel64_readq(dc, name) +#define channel_writeq(dc, name, val) channel64_writeq(dc, name, val) +#define channel_readl(dc, name) \ + (is_dmac64(dc) ? \ + channel64_readl(dc, name) : channel32_readl(dc, name)) +#define channel_writel(dc, name, val) \ + (is_dmac64(dc) ? \ + channel64_writel(dc, name, val) : channel32_writel(dc, name, val)) + +static dma_addr_t channel64_read_CHAR(const struct txx9dmac_chan *dc) +{ + if (sizeof(__dma_regs(dc)->CHAR) == sizeof(u64)) + return channel64_readq(dc, CHAR); + else + return channel64_readl(dc, CHAR); +} + +static void channel64_write_CHAR(const struct txx9dmac_chan *dc, dma_addr_t val) +{ + if (sizeof(__dma_regs(dc)->CHAR) == sizeof(u64)) + channel64_writeq(dc, CHAR, val); + else + channel64_writel(dc, CHAR, val); +} + +static void channel64_clear_CHAR(const struct txx9dmac_chan *dc) +{ +#if defined(CONFIG_32BIT) && !defined(CONFIG_64BIT_PHYS_ADDR) + channel64_writel(dc, CHAR, 0); + channel64_writel(dc, __pad_CHAR, 0); +#else + channel64_writeq(dc, CHAR, 0); +#endif +} + +static dma_addr_t channel_read_CHAR(const struct txx9dmac_chan *dc) +{ + if (is_dmac64(dc)) + return channel64_read_CHAR(dc); + else + return channel32_readl(dc, CHAR); +} + +static void channel_write_CHAR(const struct txx9dmac_chan *dc, dma_addr_t val) +{ + if (is_dmac64(dc)) + channel64_write_CHAR(dc, val); + else + channel32_writel(dc, CHAR, val); +} + +static struct txx9dmac_regs __iomem *__txx9dmac_regs( + const struct txx9dmac_dev *ddev) +{ + return ddev->regs; +} + +static struct txx9dmac_regs32 __iomem *__txx9dmac_regs32( + const struct txx9dmac_dev *ddev) +{ + return ddev->regs; +} + +#define dma64_readl(ddev, name) \ + __raw_readl(&(__txx9dmac_regs(ddev)->name)) +#define dma64_writel(ddev, name, val) \ + __raw_writel((val), &(__txx9dmac_regs(ddev)->name)) + +#define dma32_readl(ddev, name) \ + __raw_readl(&(__txx9dmac_regs32(ddev)->name)) +#define dma32_writel(ddev, name, val) \ + __raw_writel((val), &(__txx9dmac_regs32(ddev)->name)) + +#define dma_readl(ddev, name) \ + (__is_dmac64(ddev) ? \ + dma64_readl(ddev, name) : dma32_readl(ddev, name)) +#define dma_writel(ddev, name, val) \ + (__is_dmac64(ddev) ? \ + dma64_writel(ddev, name, val) : dma32_writel(ddev, name, val)) + +static struct device *chan2dev(struct dma_chan *chan) +{ + return &chan->dev->device; +} +static struct device *chan2parent(struct dma_chan *chan) +{ + return chan->dev->device.parent; +} + +static struct txx9dmac_desc * +txd_to_txx9dmac_desc(struct dma_async_tx_descriptor *txd) +{ + return container_of(txd, struct txx9dmac_desc, txd); +} + +static dma_addr_t desc_read_CHAR(const struct txx9dmac_chan *dc, + const struct txx9dmac_desc *desc) +{ + return is_dmac64(dc) ? desc->hwdesc.CHAR : desc->hwdesc32.CHAR; +} + +static void desc_write_CHAR(const struct txx9dmac_chan *dc, + struct txx9dmac_desc *desc, dma_addr_t val) +{ + if (is_dmac64(dc)) + desc->hwdesc.CHAR = val; + else + desc->hwdesc32.CHAR = val; +} + +#define TXX9_DMA_MAX_COUNT 0x04000000 + +#define TXX9_DMA_INITIAL_DESC_COUNT 64 + +static struct txx9dmac_desc *txx9dmac_first_active(struct txx9dmac_chan *dc) +{ + return list_entry(dc->active_list.next, + struct txx9dmac_desc, desc_node); +} + +static struct txx9dmac_desc *txx9dmac_last_active(struct txx9dmac_chan *dc) +{ + return list_entry(dc->active_list.prev, + struct txx9dmac_desc, desc_node); +} + +static struct txx9dmac_desc *txx9dmac_first_queued(struct txx9dmac_chan *dc) +{ + return list_entry(dc->queue.next, struct txx9dmac_desc, desc_node); +} + +static struct txx9dmac_desc *txx9dmac_last_child(struct txx9dmac_desc *desc) +{ + if (!list_empty(&desc->tx_list)) + desc = list_entry(desc->tx_list.prev, typeof(*desc), desc_node); + return desc; +} + +static dma_cookie_t txx9dmac_tx_submit(struct dma_async_tx_descriptor *tx); + +static struct txx9dmac_desc *txx9dmac_desc_alloc(struct txx9dmac_chan *dc, + gfp_t flags) +{ + struct txx9dmac_dev *ddev = dc->ddev; + struct txx9dmac_desc *desc; + + desc = kzalloc(sizeof(*desc), flags); + if (!desc) + return NULL; + INIT_LIST_HEAD(&desc->tx_list); + dma_async_tx_descriptor_init(&desc->txd, &dc->chan); + desc->txd.tx_submit = txx9dmac_tx_submit; + /* txd.flags will be overwritten in prep funcs */ + desc->txd.flags = DMA_CTRL_ACK; + desc->txd.phys = dma_map_single(chan2parent(&dc->chan), &desc->hwdesc, + ddev->descsize, DMA_TO_DEVICE); + return desc; +} + +static struct txx9dmac_desc *txx9dmac_desc_get(struct txx9dmac_chan *dc) +{ + struct txx9dmac_desc *desc, *_desc; + struct txx9dmac_desc *ret = NULL; + unsigned int i = 0; + + spin_lock_bh(&dc->lock); + list_for_each_entry_safe(desc, _desc, &dc->free_list, desc_node) { + if (async_tx_test_ack(&desc->txd)) { + list_del(&desc->desc_node); + ret = desc; + break; + } + dev_dbg(chan2dev(&dc->chan), "desc %p not ACKed\n", desc); + i++; + } + spin_unlock_bh(&dc->lock); + + dev_vdbg(chan2dev(&dc->chan), "scanned %u descriptors on freelist\n", + i); + if (!ret) { + ret = txx9dmac_desc_alloc(dc, GFP_ATOMIC); + if (ret) { + spin_lock_bh(&dc->lock); + dc->descs_allocated++; + spin_unlock_bh(&dc->lock); + } else + dev_err(chan2dev(&dc->chan), + "not enough descriptors available\n"); + } + return ret; +} + +static void txx9dmac_sync_desc_for_cpu(struct txx9dmac_chan *dc, + struct txx9dmac_desc *desc) +{ + struct txx9dmac_dev *ddev = dc->ddev; + struct txx9dmac_desc *child; + + list_for_each_entry(child, &desc->tx_list, desc_node) + dma_sync_single_for_cpu(chan2parent(&dc->chan), + child->txd.phys, ddev->descsize, + DMA_TO_DEVICE); + dma_sync_single_for_cpu(chan2parent(&dc->chan), + desc->txd.phys, ddev->descsize, + DMA_TO_DEVICE); +} + +/* + * Move a descriptor, including any children, to the free list. + * `desc' must not be on any lists. + */ +static void txx9dmac_desc_put(struct txx9dmac_chan *dc, + struct txx9dmac_desc *desc) +{ + if (desc) { + struct txx9dmac_desc *child; + + txx9dmac_sync_desc_for_cpu(dc, desc); + + spin_lock_bh(&dc->lock); + list_for_each_entry(child, &desc->tx_list, desc_node) + dev_vdbg(chan2dev(&dc->chan), + "moving child desc %p to freelist\n", + child); + list_splice_init(&desc->tx_list, &dc->free_list); + dev_vdbg(chan2dev(&dc->chan), "moving desc %p to freelist\n", + desc); + list_add(&desc->desc_node, &dc->free_list); + spin_unlock_bh(&dc->lock); + } +} + +/* Called with dc->lock held and bh disabled */ +static dma_cookie_t +txx9dmac_assign_cookie(struct txx9dmac_chan *dc, struct txx9dmac_desc *desc) +{ + dma_cookie_t cookie = dc->chan.cookie; + + if (++cookie < 0) + cookie = 1; + + dc->chan.cookie = cookie; + desc->txd.cookie = cookie; + + return cookie; +} + +/*----------------------------------------------------------------------*/ + +static void txx9dmac_dump_regs(struct txx9dmac_chan *dc) +{ + if (is_dmac64(dc)) + dev_err(chan2dev(&dc->chan), + " CHAR: %#llx SAR: %#llx DAR: %#llx CNTR: %#x" + " SAIR: %#x DAIR: %#x CCR: %#x CSR: %#x\n", + (u64)channel64_read_CHAR(dc), + channel64_readq(dc, SAR), + channel64_readq(dc, DAR), + channel64_readl(dc, CNTR), + channel64_readl(dc, SAIR), + channel64_readl(dc, DAIR), + channel64_readl(dc, CCR), + channel64_readl(dc, CSR)); + else + dev_err(chan2dev(&dc->chan), + " CHAR: %#x SAR: %#x DAR: %#x CNTR: %#x" + " SAIR: %#x DAIR: %#x CCR: %#x CSR: %#x\n", + channel32_readl(dc, CHAR), + channel32_readl(dc, SAR), + channel32_readl(dc, DAR), + channel32_readl(dc, CNTR), + channel32_readl(dc, SAIR), + channel32_readl(dc, DAIR), + channel32_readl(dc, CCR), + channel32_readl(dc, CSR)); +} + +static void txx9dmac_reset_chan(struct txx9dmac_chan *dc) +{ + channel_writel(dc, CCR, TXX9_DMA_CCR_CHRST); + if (is_dmac64(dc)) { + channel64_clear_CHAR(dc); + channel_writeq(dc, SAR, 0); + channel_writeq(dc, DAR, 0); + } else { + channel_writel(dc, CHAR, 0); + channel_writel(dc, SAR, 0); + channel_writel(dc, DAR, 0); + } + channel_writel(dc, CNTR, 0); + channel_writel(dc, SAIR, 0); + channel_writel(dc, DAIR, 0); + channel_writel(dc, CCR, 0); + mmiowb(); +} + +/* Called with dc->lock held and bh disabled */ +static void txx9dmac_dostart(struct txx9dmac_chan *dc, + struct txx9dmac_desc *first) +{ + struct txx9dmac_slave *ds = dc->chan.private; + u32 sai, dai; + + dev_vdbg(chan2dev(&dc->chan), "dostart %u %p\n", + first->txd.cookie, first); + /* ASSERT: channel is idle */ + if (channel_readl(dc, CSR) & TXX9_DMA_CSR_XFACT) { + dev_err(chan2dev(&dc->chan), + "BUG: Attempted to start non-idle channel\n"); + txx9dmac_dump_regs(dc); + /* The tasklet will hopefully advance the queue... */ + return; + } + + if (is_dmac64(dc)) { + channel64_writel(dc, CNTR, 0); + channel64_writel(dc, CSR, 0xffffffff); + if (ds) { + if (ds->tx_reg) { + sai = ds->reg_width; + dai = 0; + } else { + sai = 0; + dai = ds->reg_width; + } + } else { + sai = 8; + dai = 8; + } + channel64_writel(dc, SAIR, sai); + channel64_writel(dc, DAIR, dai); + /* All 64-bit DMAC supports SMPCHN */ + channel64_writel(dc, CCR, dc->ccr); + /* Writing a non zero value to CHAR will assert XFACT */ + channel64_write_CHAR(dc, first->txd.phys); + } else { + channel32_writel(dc, CNTR, 0); + channel32_writel(dc, CSR, 0xffffffff); + if (ds) { + if (ds->tx_reg) { + sai = ds->reg_width; + dai = 0; + } else { + sai = 0; + dai = ds->reg_width; + } + } else { + sai = 4; + dai = 4; + } + channel32_writel(dc, SAIR, sai); + channel32_writel(dc, DAIR, dai); + if (txx9_dma_have_SMPCHN()) { + channel32_writel(dc, CCR, dc->ccr); + /* Writing a non zero value to CHAR will assert XFACT */ + channel32_writel(dc, CHAR, first->txd.phys); + } else { + channel32_writel(dc, CHAR, first->txd.phys); + channel32_writel(dc, CCR, dc->ccr); + } + } +} + +/*----------------------------------------------------------------------*/ + +static void +txx9dmac_descriptor_complete(struct txx9dmac_chan *dc, + struct txx9dmac_desc *desc) +{ + dma_async_tx_callback callback; + void *param; + struct dma_async_tx_descriptor *txd = &desc->txd; + struct txx9dmac_slave *ds = dc->chan.private; + + dev_vdbg(chan2dev(&dc->chan), "descriptor %u %p complete\n", + txd->cookie, desc); + + dc->completed = txd->cookie; + callback = txd->callback; + param = txd->callback_param; + + txx9dmac_sync_desc_for_cpu(dc, desc); + list_splice_init(&desc->tx_list, &dc->free_list); + list_move(&desc->desc_node, &dc->free_list); + + if (!ds) { + dma_addr_t dmaaddr; + if (!(txd->flags & DMA_COMPL_SKIP_DEST_UNMAP)) { + dmaaddr = is_dmac64(dc) ? + desc->hwdesc.DAR : desc->hwdesc32.DAR; + if (txd->flags & DMA_COMPL_DEST_UNMAP_SINGLE) + dma_unmap_single(chan2parent(&dc->chan), + dmaaddr, desc->len, DMA_FROM_DEVICE); + else + dma_unmap_page(chan2parent(&dc->chan), + dmaaddr, desc->len, DMA_FROM_DEVICE); + } + if (!(txd->flags & DMA_COMPL_SKIP_SRC_UNMAP)) { + dmaaddr = is_dmac64(dc) ? + desc->hwdesc.SAR : desc->hwdesc32.SAR; + if (txd->flags & DMA_COMPL_SRC_UNMAP_SINGLE) + dma_unmap_single(chan2parent(&dc->chan), + dmaaddr, desc->len, DMA_TO_DEVICE); + else + dma_unmap_page(chan2parent(&dc->chan), + dmaaddr, desc->len, DMA_TO_DEVICE); + } + } + + /* + * The API requires that no submissions are done from a + * callback, so we don't need to drop the lock here + */ + if (callback) + callback(param); + dma_run_dependencies(txd); +} + +static void txx9dmac_dequeue(struct txx9dmac_chan *dc, struct list_head *list) +{ + struct txx9dmac_dev *ddev = dc->ddev; + struct txx9dmac_desc *desc; + struct txx9dmac_desc *prev = NULL; + + BUG_ON(!list_empty(list)); + do { + desc = txx9dmac_first_queued(dc); + if (prev) { + desc_write_CHAR(dc, prev, desc->txd.phys); + dma_sync_single_for_device(chan2parent(&dc->chan), + prev->txd.phys, ddev->descsize, + DMA_TO_DEVICE); + } + prev = txx9dmac_last_child(desc); + list_move_tail(&desc->desc_node, list); + /* Make chain-completion interrupt happen */ + if ((desc->txd.flags & DMA_PREP_INTERRUPT) && + !txx9dmac_chan_INTENT(dc)) + break; + } while (!list_empty(&dc->queue)); +} + +static void txx9dmac_complete_all(struct txx9dmac_chan *dc) +{ + struct txx9dmac_desc *desc, *_desc; + LIST_HEAD(list); + + /* + * Submit queued descriptors ASAP, i.e. before we go through + * the completed ones. + */ + list_splice_init(&dc->active_list, &list); + if (!list_empty(&dc->queue)) { + txx9dmac_dequeue(dc, &dc->active_list); + txx9dmac_dostart(dc, txx9dmac_first_active(dc)); + } + + list_for_each_entry_safe(desc, _desc, &list, desc_node) + txx9dmac_descriptor_complete(dc, desc); +} + +static void txx9dmac_dump_desc(struct txx9dmac_chan *dc, + struct txx9dmac_hwdesc *desc) +{ + if (is_dmac64(dc)) { +#ifdef TXX9_DMA_USE_SIMPLE_CHAIN + dev_crit(chan2dev(&dc->chan), + " desc: ch%#llx s%#llx d%#llx c%#x\n", + (u64)desc->CHAR, desc->SAR, desc->DAR, desc->CNTR); +#else + dev_crit(chan2dev(&dc->chan), + " desc: ch%#llx s%#llx d%#llx c%#x" + " si%#x di%#x cc%#x cs%#x\n", + (u64)desc->CHAR, desc->SAR, desc->DAR, desc->CNTR, + desc->SAIR, desc->DAIR, desc->CCR, desc->CSR); +#endif + } else { + struct txx9dmac_hwdesc32 *d = (struct txx9dmac_hwdesc32 *)desc; +#ifdef TXX9_DMA_USE_SIMPLE_CHAIN + dev_crit(chan2dev(&dc->chan), + " desc: ch%#x s%#x d%#x c%#x\n", + d->CHAR, d->SAR, d->DAR, d->CNTR); +#else + dev_crit(chan2dev(&dc->chan), + " desc: ch%#x s%#x d%#x c%#x" + " si%#x di%#x cc%#x cs%#x\n", + d->CHAR, d->SAR, d->DAR, d->CNTR, + d->SAIR, d->DAIR, d->CCR, d->CSR); +#endif + } +} + +static void txx9dmac_handle_error(struct txx9dmac_chan *dc, u32 csr) +{ + struct txx9dmac_desc *bad_desc; + struct txx9dmac_desc *child; + u32 errors; + + /* + * The descriptor currently at the head of the active list is + * borked. Since we don't have any way to report errors, we'll + * just have to scream loudly and try to carry on. + */ + dev_crit(chan2dev(&dc->chan), "Abnormal Chain Completion\n"); + txx9dmac_dump_regs(dc); + + bad_desc = txx9dmac_first_active(dc); + list_del_init(&bad_desc->desc_node); + + /* Clear all error flags and try to restart the controller */ + errors = csr & (TXX9_DMA_CSR_ABCHC | + TXX9_DMA_CSR_CFERR | TXX9_DMA_CSR_CHERR | + TXX9_DMA_CSR_DESERR | TXX9_DMA_CSR_SORERR); + channel_writel(dc, CSR, errors); + + if (list_empty(&dc->active_list) && !list_empty(&dc->queue)) + txx9dmac_dequeue(dc, &dc->active_list); + if (!list_empty(&dc->active_list)) + txx9dmac_dostart(dc, txx9dmac_first_active(dc)); + + dev_crit(chan2dev(&dc->chan), + "Bad descriptor submitted for DMA! (cookie: %d)\n", + bad_desc->txd.cookie); + txx9dmac_dump_desc(dc, &bad_desc->hwdesc); + list_for_each_entry(child, &bad_desc->tx_list, desc_node) + txx9dmac_dump_desc(dc, &child->hwdesc); + /* Pretend the descriptor completed successfully */ + txx9dmac_descriptor_complete(dc, bad_desc); +} + +static void txx9dmac_scan_descriptors(struct txx9dmac_chan *dc) +{ + dma_addr_t chain; + struct txx9dmac_desc *desc, *_desc; + struct txx9dmac_desc *child; + u32 csr; + + if (is_dmac64(dc)) { + chain = channel64_read_CHAR(dc); + csr = channel64_readl(dc, CSR); + channel64_writel(dc, CSR, csr); + } else { + chain = channel32_readl(dc, CHAR); + csr = channel32_readl(dc, CSR); + channel32_writel(dc, CSR, csr); + } + /* For dynamic chain, we should look at XFACT instead of NCHNC */ + if (!(csr & (TXX9_DMA_CSR_XFACT | TXX9_DMA_CSR_ABCHC))) { + /* Everything we've submitted is done */ + txx9dmac_complete_all(dc); + return; + } + if (!(csr & TXX9_DMA_CSR_CHNEN)) + chain = 0; /* last descriptor of this chain */ + + dev_vdbg(chan2dev(&dc->chan), "scan_descriptors: char=%#llx\n", + (u64)chain); + + list_for_each_entry_safe(desc, _desc, &dc->active_list, desc_node) { + if (desc_read_CHAR(dc, desc) == chain) { + /* This one is currently in progress */ + if (csr & TXX9_DMA_CSR_ABCHC) + goto scan_done; + return; + } + + list_for_each_entry(child, &desc->tx_list, desc_node) + if (desc_read_CHAR(dc, child) == chain) { + /* Currently in progress */ + if (csr & TXX9_DMA_CSR_ABCHC) + goto scan_done; + return; + } + + /* + * No descriptors so far seem to be in progress, i.e. + * this one must be done. + */ + txx9dmac_descriptor_complete(dc, desc); + } +scan_done: + if (csr & TXX9_DMA_CSR_ABCHC) { + txx9dmac_handle_error(dc, csr); + return; + } + + dev_err(chan2dev(&dc->chan), + "BUG: All descriptors done, but channel not idle!\n"); + + /* Try to continue after resetting the channel... */ + txx9dmac_reset_chan(dc); + + if (!list_empty(&dc->queue)) { + txx9dmac_dequeue(dc, &dc->active_list); + txx9dmac_dostart(dc, txx9dmac_first_active(dc)); + } +} + +static void txx9dmac_chan_tasklet(unsigned long data) +{ + int irq; + u32 csr; + struct txx9dmac_chan *dc; + + dc = (struct txx9dmac_chan *)data; + csr = channel_readl(dc, CSR); + dev_vdbg(chan2dev(&dc->chan), "tasklet: status=%x\n", csr); + + spin_lock(&dc->lock); + if (csr & (TXX9_DMA_CSR_ABCHC | TXX9_DMA_CSR_NCHNC | + TXX9_DMA_CSR_NTRNFC)) + txx9dmac_scan_descriptors(dc); + spin_unlock(&dc->lock); + irq = dc->irq; + + enable_irq(irq); +} + +static irqreturn_t txx9dmac_chan_interrupt(int irq, void *dev_id) +{ + struct txx9dmac_chan *dc = dev_id; + + dev_vdbg(chan2dev(&dc->chan), "interrupt: status=%#x\n", + channel_readl(dc, CSR)); + + tasklet_schedule(&dc->tasklet); + /* + * Just disable the interrupts. We'll turn them back on in the + * softirq handler. + */ + disable_irq_nosync(irq); + + return IRQ_HANDLED; +} + +static void txx9dmac_tasklet(unsigned long data) +{ + int irq; + u32 csr; + struct txx9dmac_chan *dc; + + struct txx9dmac_dev *ddev = (struct txx9dmac_dev *)data; + u32 mcr; + int i; + + mcr = dma_readl(ddev, MCR); + dev_vdbg(ddev->chan[0]->dma.dev, "tasklet: mcr=%x\n", mcr); + for (i = 0; i < TXX9_DMA_MAX_NR_CHANNELS; i++) { + if ((mcr >> (24 + i)) & 0x11) { + dc = ddev->chan[i]; + csr = channel_readl(dc, CSR); + dev_vdbg(chan2dev(&dc->chan), "tasklet: status=%x\n", + csr); + spin_lock(&dc->lock); + if (csr & (TXX9_DMA_CSR_ABCHC | TXX9_DMA_CSR_NCHNC | + TXX9_DMA_CSR_NTRNFC)) + txx9dmac_scan_descriptors(dc); + spin_unlock(&dc->lock); + } + } + irq = ddev->irq; + + enable_irq(irq); +} + +static irqreturn_t txx9dmac_interrupt(int irq, void *dev_id) +{ + struct txx9dmac_dev *ddev = dev_id; + + dev_vdbg(ddev->chan[0]->dma.dev, "interrupt: status=%#x\n", + dma_readl(ddev, MCR)); + + tasklet_schedule(&ddev->tasklet); + /* + * Just disable the interrupts. We'll turn them back on in the + * softirq handler. + */ + disable_irq_nosync(irq); + + return IRQ_HANDLED; +} + +/*----------------------------------------------------------------------*/ + +static dma_cookie_t txx9dmac_tx_submit(struct dma_async_tx_descriptor *tx) +{ + struct txx9dmac_desc *desc = txd_to_txx9dmac_desc(tx); + struct txx9dmac_chan *dc = to_txx9dmac_chan(tx->chan); + dma_cookie_t cookie; + + spin_lock_bh(&dc->lock); + cookie = txx9dmac_assign_cookie(dc, desc); + + dev_vdbg(chan2dev(tx->chan), "tx_submit: queued %u %p\n", + desc->txd.cookie, desc); + + list_add_tail(&desc->desc_node, &dc->queue); + spin_unlock_bh(&dc->lock); + + return cookie; +} + +static struct dma_async_tx_descriptor * +txx9dmac_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, + size_t len, unsigned long flags) +{ + struct txx9dmac_chan *dc = to_txx9dmac_chan(chan); + struct txx9dmac_dev *ddev = dc->ddev; + struct txx9dmac_desc *desc; + struct txx9dmac_desc *first; + struct txx9dmac_desc *prev; + size_t xfer_count; + size_t offset; + + dev_vdbg(chan2dev(chan), "prep_dma_memcpy d%#llx s%#llx l%#zx f%#lx\n", + (u64)dest, (u64)src, len, flags); + + if (unlikely(!len)) { + dev_dbg(chan2dev(chan), "prep_dma_memcpy: length is zero!\n"); + return NULL; + } + + prev = first = NULL; + + for (offset = 0; offset < len; offset += xfer_count) { + xfer_count = min_t(size_t, len - offset, TXX9_DMA_MAX_COUNT); + /* + * Workaround for ERT-TX49H2-033, ERT-TX49H3-020, + * ERT-TX49H4-016 (slightly conservative) + */ + if (__is_dmac64(ddev)) { + if (xfer_count > 0x100 && + (xfer_count & 0xff) >= 0xfa && + (xfer_count & 0xff) <= 0xff) + xfer_count -= 0x20; + } else { + if (xfer_count > 0x80 && + (xfer_count & 0x7f) >= 0x7e && + (xfer_count & 0x7f) <= 0x7f) + xfer_count -= 0x20; + } + + desc = txx9dmac_desc_get(dc); + if (!desc) { + txx9dmac_desc_put(dc, first); + return NULL; + } + + if (__is_dmac64(ddev)) { + desc->hwdesc.SAR = src + offset; + desc->hwdesc.DAR = dest + offset; + desc->hwdesc.CNTR = xfer_count; + txx9dmac_desc_set_nosimple(ddev, desc, 8, 8, + dc->ccr | TXX9_DMA_CCR_XFACT); + } else { + desc->hwdesc32.SAR = src + offset; + desc->hwdesc32.DAR = dest + offset; + desc->hwdesc32.CNTR = xfer_count; + txx9dmac_desc_set_nosimple(ddev, desc, 4, 4, + dc->ccr | TXX9_DMA_CCR_XFACT); + } + + /* + * The descriptors on tx_list are not reachable from + * the dc->queue list or dc->active_list after a + * submit. If we put all descriptors on active_list, + * calling of callback on the completion will be more + * complex. + */ + if (!first) { + first = desc; + } else { + desc_write_CHAR(dc, prev, desc->txd.phys); + dma_sync_single_for_device(chan2parent(&dc->chan), + prev->txd.phys, ddev->descsize, + DMA_TO_DEVICE); + list_add_tail(&desc->desc_node, &first->tx_list); + } + prev = desc; + } + + /* Trigger interrupt after last block */ + if (flags & DMA_PREP_INTERRUPT) + txx9dmac_desc_set_INTENT(ddev, prev); + + desc_write_CHAR(dc, prev, 0); + dma_sync_single_for_device(chan2parent(&dc->chan), + prev->txd.phys, ddev->descsize, + DMA_TO_DEVICE); + + first->txd.flags = flags; + first->len = len; + + return &first->txd; +} + +static struct dma_async_tx_descriptor * +txx9dmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, + unsigned int sg_len, enum dma_data_direction direction, + unsigned long flags) +{ + struct txx9dmac_chan *dc = to_txx9dmac_chan(chan); + struct txx9dmac_dev *ddev = dc->ddev; + struct txx9dmac_slave *ds = chan->private; + struct txx9dmac_desc *prev; + struct txx9dmac_desc *first; + unsigned int i; + struct scatterlist *sg; + + dev_vdbg(chan2dev(chan), "prep_dma_slave\n"); + + BUG_ON(!ds || !ds->reg_width); + if (ds->tx_reg) + BUG_ON(direction != DMA_TO_DEVICE); + else + BUG_ON(direction != DMA_FROM_DEVICE); + if (unlikely(!sg_len)) + return NULL; + + prev = first = NULL; + + for_each_sg(sgl, sg, sg_len, i) { + struct txx9dmac_desc *desc; + dma_addr_t mem; + u32 sai, dai; + + desc = txx9dmac_desc_get(dc); + if (!desc) { + txx9dmac_desc_put(dc, first); + return NULL; + } + + mem = sg_dma_address(sg); + + if (__is_dmac64(ddev)) { + if (direction == DMA_TO_DEVICE) { + desc->hwdesc.SAR = mem; + desc->hwdesc.DAR = ds->tx_reg; + } else { + desc->hwdesc.SAR = ds->rx_reg; + desc->hwdesc.DAR = mem; + } + desc->hwdesc.CNTR = sg_dma_len(sg); + } else { + if (direction == DMA_TO_DEVICE) { + desc->hwdesc32.SAR = mem; + desc->hwdesc32.DAR = ds->tx_reg; + } else { + desc->hwdesc32.SAR = ds->rx_reg; + desc->hwdesc32.DAR = mem; + } + desc->hwdesc32.CNTR = sg_dma_len(sg); + } + if (direction == DMA_TO_DEVICE) { + sai = ds->reg_width; + dai = 0; + } else { + sai = 0; + dai = ds->reg_width; + } + txx9dmac_desc_set_nosimple(ddev, desc, sai, dai, + dc->ccr | TXX9_DMA_CCR_XFACT); + + if (!first) { + first = desc; + } else { + desc_write_CHAR(dc, prev, desc->txd.phys); + dma_sync_single_for_device(chan2parent(&dc->chan), + prev->txd.phys, + ddev->descsize, + DMA_TO_DEVICE); + list_add_tail(&desc->desc_node, &first->tx_list); + } + prev = desc; + } + + /* Trigger interrupt after last block */ + if (flags & DMA_PREP_INTERRUPT) + txx9dmac_desc_set_INTENT(ddev, prev); + + desc_write_CHAR(dc, prev, 0); + dma_sync_single_for_device(chan2parent(&dc->chan), + prev->txd.phys, ddev->descsize, + DMA_TO_DEVICE); + + first->txd.flags = flags; + first->len = 0; + + return &first->txd; +} + +static void txx9dmac_terminate_all(struct dma_chan *chan) +{ + struct txx9dmac_chan *dc = to_txx9dmac_chan(chan); + struct txx9dmac_desc *desc, *_desc; + LIST_HEAD(list); + + dev_vdbg(chan2dev(chan), "terminate_all\n"); + spin_lock_bh(&dc->lock); + + txx9dmac_reset_chan(dc); + + /* active_list entries will end up before queued entries */ + list_splice_init(&dc->queue, &list); + list_splice_init(&dc->active_list, &list); + + spin_unlock_bh(&dc->lock); + + /* Flush all pending and queued descriptors */ + list_for_each_entry_safe(desc, _desc, &list, desc_node) + txx9dmac_descriptor_complete(dc, desc); +} + +static enum dma_status +txx9dmac_is_tx_complete(struct dma_chan *chan, + dma_cookie_t cookie, + dma_cookie_t *done, dma_cookie_t *used) +{ + struct txx9dmac_chan *dc = to_txx9dmac_chan(chan); + dma_cookie_t last_used; + dma_cookie_t last_complete; + int ret; + + last_complete = dc->completed; + last_used = chan->cookie; + + ret = dma_async_is_complete(cookie, last_complete, last_used); + if (ret != DMA_SUCCESS) { + spin_lock_bh(&dc->lock); + txx9dmac_scan_descriptors(dc); + spin_unlock_bh(&dc->lock); + + last_complete = dc->completed; + last_used = chan->cookie; + + ret = dma_async_is_complete(cookie, last_complete, last_used); + } + + if (done) + *done = last_complete; + if (used) + *used = last_used; + + return ret; +} + +static void txx9dmac_chain_dynamic(struct txx9dmac_chan *dc, + struct txx9dmac_desc *prev) +{ + struct txx9dmac_dev *ddev = dc->ddev; + struct txx9dmac_desc *desc; + LIST_HEAD(list); + + prev = txx9dmac_last_child(prev); + txx9dmac_dequeue(dc, &list); + desc = list_entry(list.next, struct txx9dmac_desc, desc_node); + desc_write_CHAR(dc, prev, desc->txd.phys); + dma_sync_single_for_device(chan2parent(&dc->chan), + prev->txd.phys, ddev->descsize, + DMA_TO_DEVICE); + mmiowb(); + if (!(channel_readl(dc, CSR) & TXX9_DMA_CSR_CHNEN) && + channel_read_CHAR(dc) == prev->txd.phys) + /* Restart chain DMA */ + channel_write_CHAR(dc, desc->txd.phys); + list_splice_tail(&list, &dc->active_list); +} + +static void txx9dmac_issue_pending(struct dma_chan *chan) +{ + struct txx9dmac_chan *dc = to_txx9dmac_chan(chan); + + spin_lock_bh(&dc->lock); + + if (!list_empty(&dc->active_list)) + txx9dmac_scan_descriptors(dc); + if (!list_empty(&dc->queue)) { + if (list_empty(&dc->active_list)) { + txx9dmac_dequeue(dc, &dc->active_list); + txx9dmac_dostart(dc, txx9dmac_first_active(dc)); + } else if (txx9_dma_have_SMPCHN()) { + struct txx9dmac_desc *prev = txx9dmac_last_active(dc); + + if (!(prev->txd.flags & DMA_PREP_INTERRUPT) || + txx9dmac_chan_INTENT(dc)) + txx9dmac_chain_dynamic(dc, prev); + } + } + + spin_unlock_bh(&dc->lock); +} + +static int txx9dmac_alloc_chan_resources(struct dma_chan *chan) +{ + struct txx9dmac_chan *dc = to_txx9dmac_chan(chan); + struct txx9dmac_slave *ds = chan->private; + struct txx9dmac_desc *desc; + int i; + + dev_vdbg(chan2dev(chan), "alloc_chan_resources\n"); + + /* ASSERT: channel is idle */ + if (channel_readl(dc, CSR) & TXX9_DMA_CSR_XFACT) { + dev_dbg(chan2dev(chan), "DMA channel not idle?\n"); + return -EIO; + } + + dc->completed = chan->cookie = 1; + + dc->ccr = TXX9_DMA_CCR_IMMCHN | TXX9_DMA_CCR_INTENE | CCR_LE; + txx9dmac_chan_set_SMPCHN(dc); + if (!txx9_dma_have_SMPCHN() || (dc->ccr & TXX9_DMA_CCR_SMPCHN)) + dc->ccr |= TXX9_DMA_CCR_INTENC; + if (chan->device->device_prep_dma_memcpy) { + if (ds) + return -EINVAL; + dc->ccr |= TXX9_DMA_CCR_XFSZ_X8; + } else { + if (!ds || + (ds->tx_reg && ds->rx_reg) || (!ds->tx_reg && !ds->rx_reg)) + return -EINVAL; + dc->ccr |= TXX9_DMA_CCR_EXTRQ | + TXX9_DMA_CCR_XFSZ(__ffs(ds->reg_width)); + txx9dmac_chan_set_INTENT(dc); + } + + spin_lock_bh(&dc->lock); + i = dc->descs_allocated; + while (dc->descs_allocated < TXX9_DMA_INITIAL_DESC_COUNT) { + spin_unlock_bh(&dc->lock); + + desc = txx9dmac_desc_alloc(dc, GFP_KERNEL); + if (!desc) { + dev_info(chan2dev(chan), + "only allocated %d descriptors\n", i); + spin_lock_bh(&dc->lock); + break; + } + txx9dmac_desc_put(dc, desc); + + spin_lock_bh(&dc->lock); + i = ++dc->descs_allocated; + } + spin_unlock_bh(&dc->lock); + + dev_dbg(chan2dev(chan), + "alloc_chan_resources allocated %d descriptors\n", i); + + return i; +} + +static void txx9dmac_free_chan_resources(struct dma_chan *chan) +{ + struct txx9dmac_chan *dc = to_txx9dmac_chan(chan); + struct txx9dmac_dev *ddev = dc->ddev; + struct txx9dmac_desc *desc, *_desc; + LIST_HEAD(list); + + dev_dbg(chan2dev(chan), "free_chan_resources (descs allocated=%u)\n", + dc->descs_allocated); + + /* ASSERT: channel is idle */ + BUG_ON(!list_empty(&dc->active_list)); + BUG_ON(!list_empty(&dc->queue)); + BUG_ON(channel_readl(dc, CSR) & TXX9_DMA_CSR_XFACT); + + spin_lock_bh(&dc->lock); + list_splice_init(&dc->free_list, &list); + dc->descs_allocated = 0; + spin_unlock_bh(&dc->lock); + + list_for_each_entry_safe(desc, _desc, &list, desc_node) { + dev_vdbg(chan2dev(chan), " freeing descriptor %p\n", desc); + dma_unmap_single(chan2parent(chan), desc->txd.phys, + ddev->descsize, DMA_TO_DEVICE); + kfree(desc); + } + + dev_vdbg(chan2dev(chan), "free_chan_resources done\n"); +} + +/*----------------------------------------------------------------------*/ + +static void txx9dmac_off(struct txx9dmac_dev *ddev) +{ + dma_writel(ddev, MCR, 0); + mmiowb(); +} + +static int __init txx9dmac_chan_probe(struct platform_device *pdev) +{ + struct txx9dmac_chan_platform_data *cpdata = pdev->dev.platform_data; + struct platform_device *dmac_dev = cpdata->dmac_dev; + struct txx9dmac_platform_data *pdata = dmac_dev->dev.platform_data; + struct txx9dmac_chan *dc; + int err; + int ch = pdev->id % TXX9_DMA_MAX_NR_CHANNELS; + int irq; + + dc = devm_kzalloc(&pdev->dev, sizeof(*dc), GFP_KERNEL); + if (!dc) + return -ENOMEM; + + dc->dma.dev = &pdev->dev; + dc->dma.device_alloc_chan_resources = txx9dmac_alloc_chan_resources; + dc->dma.device_free_chan_resources = txx9dmac_free_chan_resources; + dc->dma.device_terminate_all = txx9dmac_terminate_all; + dc->dma.device_is_tx_complete = txx9dmac_is_tx_complete; + dc->dma.device_issue_pending = txx9dmac_issue_pending; + if (pdata && pdata->memcpy_chan == ch) { + dc->dma.device_prep_dma_memcpy = txx9dmac_prep_dma_memcpy; + dma_cap_set(DMA_MEMCPY, dc->dma.cap_mask); + } else { + dc->dma.device_prep_slave_sg = txx9dmac_prep_slave_sg; + dma_cap_set(DMA_SLAVE, dc->dma.cap_mask); + dma_cap_set(DMA_PRIVATE, dc->dma.cap_mask); + } + + INIT_LIST_HEAD(&dc->dma.channels); + dc->ddev = platform_get_drvdata(dmac_dev); + if (dc->ddev->irq < 0) { + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + tasklet_init(&dc->tasklet, txx9dmac_chan_tasklet, + (unsigned long)dc); + dc->irq = irq; + err = devm_request_irq(&pdev->dev, dc->irq, + txx9dmac_chan_interrupt, 0, dev_name(&pdev->dev), dc); + if (err) + return err; + } else + dc->irq = -1; + dc->ddev->chan[ch] = dc; + dc->chan.device = &dc->dma; + list_add_tail(&dc->chan.device_node, &dc->chan.device->channels); + dc->chan.cookie = dc->completed = 1; + + if (is_dmac64(dc)) + dc->ch_regs = &__txx9dmac_regs(dc->ddev)->CHAN[ch]; + else + dc->ch_regs = &__txx9dmac_regs32(dc->ddev)->CHAN[ch]; + spin_lock_init(&dc->lock); + + INIT_LIST_HEAD(&dc->active_list); + INIT_LIST_HEAD(&dc->queue); + INIT_LIST_HEAD(&dc->free_list); + + txx9dmac_reset_chan(dc); + + platform_set_drvdata(pdev, dc); + + err = dma_async_device_register(&dc->dma); + if (err) + return err; + dev_dbg(&pdev->dev, "TXx9 DMA Channel (dma%d%s%s)\n", + dc->dma.dev_id, + dma_has_cap(DMA_MEMCPY, dc->dma.cap_mask) ? " memcpy" : "", + dma_has_cap(DMA_SLAVE, dc->dma.cap_mask) ? " slave" : ""); + + return 0; +} + +static int __exit txx9dmac_chan_remove(struct platform_device *pdev) +{ + struct txx9dmac_chan *dc = platform_get_drvdata(pdev); + + dma_async_device_unregister(&dc->dma); + if (dc->irq >= 0) + tasklet_kill(&dc->tasklet); + dc->ddev->chan[pdev->id % TXX9_DMA_MAX_NR_CHANNELS] = NULL; + return 0; +} + +static int __init txx9dmac_probe(struct platform_device *pdev) +{ + struct txx9dmac_platform_data *pdata = pdev->dev.platform_data; + struct resource *io; + struct txx9dmac_dev *ddev; + u32 mcr; + int err; + + io = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!io) + return -EINVAL; + + ddev = devm_kzalloc(&pdev->dev, sizeof(*ddev), GFP_KERNEL); + if (!ddev) + return -ENOMEM; + + if (!devm_request_mem_region(&pdev->dev, io->start, resource_size(io), + dev_name(&pdev->dev))) + return -EBUSY; + + ddev->regs = devm_ioremap(&pdev->dev, io->start, resource_size(io)); + if (!ddev->regs) + return -ENOMEM; + ddev->have_64bit_regs = pdata->have_64bit_regs; + if (__is_dmac64(ddev)) + ddev->descsize = sizeof(struct txx9dmac_hwdesc); + else + ddev->descsize = sizeof(struct txx9dmac_hwdesc32); + + /* force dma off, just in case */ + txx9dmac_off(ddev); + + ddev->irq = platform_get_irq(pdev, 0); + if (ddev->irq >= 0) { + tasklet_init(&ddev->tasklet, txx9dmac_tasklet, + (unsigned long)ddev); + err = devm_request_irq(&pdev->dev, ddev->irq, + txx9dmac_interrupt, 0, dev_name(&pdev->dev), ddev); + if (err) + return err; + } + + mcr = TXX9_DMA_MCR_MSTEN | MCR_LE; + if (pdata && pdata->memcpy_chan >= 0) + mcr |= TXX9_DMA_MCR_FIFUM(pdata->memcpy_chan); + dma_writel(ddev, MCR, mcr); + + platform_set_drvdata(pdev, ddev); + return 0; +} + +static int __exit txx9dmac_remove(struct platform_device *pdev) +{ + struct txx9dmac_dev *ddev = platform_get_drvdata(pdev); + + txx9dmac_off(ddev); + if (ddev->irq >= 0) + tasklet_kill(&ddev->tasklet); + return 0; +} + +static void txx9dmac_shutdown(struct platform_device *pdev) +{ + struct txx9dmac_dev *ddev = platform_get_drvdata(pdev); + + txx9dmac_off(ddev); +} + +static int txx9dmac_suspend_late(struct platform_device *pdev, + pm_message_t mesg) +{ + struct txx9dmac_dev *ddev = platform_get_drvdata(pdev); + + txx9dmac_off(ddev); + return 0; +} + +static int txx9dmac_resume_early(struct platform_device *pdev) +{ + struct txx9dmac_dev *ddev = platform_get_drvdata(pdev); + struct txx9dmac_platform_data *pdata = pdev->dev.platform_data; + u32 mcr; + + mcr = TXX9_DMA_MCR_MSTEN | MCR_LE; + if (pdata && pdata->memcpy_chan >= 0) + mcr |= TXX9_DMA_MCR_FIFUM(pdata->memcpy_chan); + dma_writel(ddev, MCR, mcr); + return 0; + +} + +static struct platform_driver txx9dmac_chan_driver = { + .remove = __exit_p(txx9dmac_chan_remove), + .driver = { + .name = "txx9dmac-chan", + }, +}; + +static struct platform_driver txx9dmac_driver = { + .remove = __exit_p(txx9dmac_remove), + .shutdown = txx9dmac_shutdown, + .suspend_late = txx9dmac_suspend_late, + .resume_early = txx9dmac_resume_early, + .driver = { + .name = "txx9dmac", + }, +}; + +static int __init txx9dmac_init(void) +{ + int rc; + + rc = platform_driver_probe(&txx9dmac_driver, txx9dmac_probe); + if (!rc) { + rc = platform_driver_probe(&txx9dmac_chan_driver, + txx9dmac_chan_probe); + if (rc) + platform_driver_unregister(&txx9dmac_driver); + } + return rc; +} +module_init(txx9dmac_init); + +static void __exit txx9dmac_exit(void) +{ + platform_driver_unregister(&txx9dmac_chan_driver); + platform_driver_unregister(&txx9dmac_driver); +} +module_exit(txx9dmac_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("TXx9 DMA Controller driver"); +MODULE_AUTHOR("Atsushi Nemoto "); diff --git a/drivers/dma/txx9dmac.h b/drivers/dma/txx9dmac.h new file mode 100644 index 000000000000..365d42366b9f --- /dev/null +++ b/drivers/dma/txx9dmac.h @@ -0,0 +1,308 @@ +/* + * Driver for the TXx9 SoC DMA Controller + * + * Copyright (C) 2009 Atsushi Nemoto + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef TXX9DMAC_H +#define TXX9DMAC_H + +#include +#include + +/* + * Design Notes: + * + * This DMAC have four channels and one FIFO buffer. Each channel can + * be configured for memory-memory or device-memory transfer, but only + * one channel can do alignment-free memory-memory transfer at a time + * while the channel should occupy the FIFO buffer for effective + * transfers. + * + * Instead of dynamically assign the FIFO buffer to channels, I chose + * make one dedicated channel for memory-memory transfer. The + * dedicated channel is public. Other channels are private and used + * for slave transfer. Some devices in the SoC are wired to certain + * DMA channel. + */ + +#ifdef CONFIG_MACH_TX49XX +static inline bool txx9_dma_have_SMPCHN(void) +{ + return true; +} +#define TXX9_DMA_USE_SIMPLE_CHAIN +#else +static inline bool txx9_dma_have_SMPCHN(void) +{ + return false; +} +#endif + +#ifdef __LITTLE_ENDIAN +#ifdef CONFIG_MACH_TX49XX +#define CCR_LE TXX9_DMA_CCR_LE +#define MCR_LE 0 +#else +#define CCR_LE 0 +#define MCR_LE TXX9_DMA_MCR_LE +#endif +#else +#define CCR_LE 0 +#define MCR_LE 0 +#endif + +/* + * Redefine this macro to handle differences between 32- and 64-bit + * addressing, big vs. little endian, etc. + */ +#ifdef __BIG_ENDIAN +#define TXX9_DMA_REG32(name) u32 __pad_##name; u32 name +#else +#define TXX9_DMA_REG32(name) u32 name; u32 __pad_##name +#endif + +/* Hardware register definitions. */ +struct txx9dmac_cregs { +#if defined(CONFIG_32BIT) && !defined(CONFIG_64BIT_PHYS_ADDR) + TXX9_DMA_REG32(CHAR); /* Chain Address Register */ +#else + u64 CHAR; /* Chain Address Register */ +#endif + u64 SAR; /* Source Address Register */ + u64 DAR; /* Destination Address Register */ + TXX9_DMA_REG32(CNTR); /* Count Register */ + TXX9_DMA_REG32(SAIR); /* Source Address Increment Register */ + TXX9_DMA_REG32(DAIR); /* Destination Address Increment Register */ + TXX9_DMA_REG32(CCR); /* Channel Control Register */ + TXX9_DMA_REG32(CSR); /* Channel Status Register */ +}; +struct txx9dmac_cregs32 { + u32 CHAR; + u32 SAR; + u32 DAR; + u32 CNTR; + u32 SAIR; + u32 DAIR; + u32 CCR; + u32 CSR; +}; + +struct txx9dmac_regs { + /* per-channel registers */ + struct txx9dmac_cregs CHAN[TXX9_DMA_MAX_NR_CHANNELS]; + u64 __pad[9]; + u64 MFDR; /* Memory Fill Data Register */ + TXX9_DMA_REG32(MCR); /* Master Control Register */ +}; +struct txx9dmac_regs32 { + struct txx9dmac_cregs32 CHAN[TXX9_DMA_MAX_NR_CHANNELS]; + u32 __pad[9]; + u32 MFDR; + u32 MCR; +}; + +/* bits for MCR */ +#define TXX9_DMA_MCR_EIS(ch) (0x10000000<<(ch)) +#define TXX9_DMA_MCR_DIS(ch) (0x01000000<<(ch)) +#define TXX9_DMA_MCR_RSFIF 0x00000080 +#define TXX9_DMA_MCR_FIFUM(ch) (0x00000008<<(ch)) +#define TXX9_DMA_MCR_LE 0x00000004 +#define TXX9_DMA_MCR_RPRT 0x00000002 +#define TXX9_DMA_MCR_MSTEN 0x00000001 + +/* bits for CCRn */ +#define TXX9_DMA_CCR_IMMCHN 0x20000000 +#define TXX9_DMA_CCR_USEXFSZ 0x10000000 +#define TXX9_DMA_CCR_LE 0x08000000 +#define TXX9_DMA_CCR_DBINH 0x04000000 +#define TXX9_DMA_CCR_SBINH 0x02000000 +#define TXX9_DMA_CCR_CHRST 0x01000000 +#define TXX9_DMA_CCR_RVBYTE 0x00800000 +#define TXX9_DMA_CCR_ACKPOL 0x00400000 +#define TXX9_DMA_CCR_REQPL 0x00200000 +#define TXX9_DMA_CCR_EGREQ 0x00100000 +#define TXX9_DMA_CCR_CHDN 0x00080000 +#define TXX9_DMA_CCR_DNCTL 0x00060000 +#define TXX9_DMA_CCR_EXTRQ 0x00010000 +#define TXX9_DMA_CCR_INTRQD 0x0000e000 +#define TXX9_DMA_CCR_INTENE 0x00001000 +#define TXX9_DMA_CCR_INTENC 0x00000800 +#define TXX9_DMA_CCR_INTENT 0x00000400 +#define TXX9_DMA_CCR_CHNEN 0x00000200 +#define TXX9_DMA_CCR_XFACT 0x00000100 +#define TXX9_DMA_CCR_SMPCHN 0x00000020 +#define TXX9_DMA_CCR_XFSZ(order) (((order) << 2) & 0x0000001c) +#define TXX9_DMA_CCR_XFSZ_1 TXX9_DMA_CCR_XFSZ(0) +#define TXX9_DMA_CCR_XFSZ_2 TXX9_DMA_CCR_XFSZ(1) +#define TXX9_DMA_CCR_XFSZ_4 TXX9_DMA_CCR_XFSZ(2) +#define TXX9_DMA_CCR_XFSZ_8 TXX9_DMA_CCR_XFSZ(3) +#define TXX9_DMA_CCR_XFSZ_X4 TXX9_DMA_CCR_XFSZ(4) +#define TXX9_DMA_CCR_XFSZ_X8 TXX9_DMA_CCR_XFSZ(5) +#define TXX9_DMA_CCR_XFSZ_X16 TXX9_DMA_CCR_XFSZ(6) +#define TXX9_DMA_CCR_XFSZ_X32 TXX9_DMA_CCR_XFSZ(7) +#define TXX9_DMA_CCR_MEMIO 0x00000002 +#define TXX9_DMA_CCR_SNGAD 0x00000001 + +/* bits for CSRn */ +#define TXX9_DMA_CSR_CHNEN 0x00000400 +#define TXX9_DMA_CSR_STLXFER 0x00000200 +#define TXX9_DMA_CSR_XFACT 0x00000100 +#define TXX9_DMA_CSR_ABCHC 0x00000080 +#define TXX9_DMA_CSR_NCHNC 0x00000040 +#define TXX9_DMA_CSR_NTRNFC 0x00000020 +#define TXX9_DMA_CSR_EXTDN 0x00000010 +#define TXX9_DMA_CSR_CFERR 0x00000008 +#define TXX9_DMA_CSR_CHERR 0x00000004 +#define TXX9_DMA_CSR_DESERR 0x00000002 +#define TXX9_DMA_CSR_SORERR 0x00000001 + +struct txx9dmac_chan { + struct dma_chan chan; + struct dma_device dma; + struct txx9dmac_dev *ddev; + void __iomem *ch_regs; + struct tasklet_struct tasklet; + int irq; + u32 ccr; + + spinlock_t lock; + + /* these other elements are all protected by lock */ + dma_cookie_t completed; + struct list_head active_list; + struct list_head queue; + struct list_head free_list; + + unsigned int descs_allocated; +}; + +struct txx9dmac_dev { + void __iomem *regs; + struct tasklet_struct tasklet; + int irq; + struct txx9dmac_chan *chan[TXX9_DMA_MAX_NR_CHANNELS]; + bool have_64bit_regs; + unsigned int descsize; +}; + +static inline bool __is_dmac64(const struct txx9dmac_dev *ddev) +{ + return ddev->have_64bit_regs; +} + +static inline bool is_dmac64(const struct txx9dmac_chan *dc) +{ + return __is_dmac64(dc->ddev); +} + +#ifdef TXX9_DMA_USE_SIMPLE_CHAIN +/* Hardware descriptor definition. (for simple-chain) */ +struct txx9dmac_hwdesc { +#if defined(CONFIG_32BIT) && !defined(CONFIG_64BIT_PHYS_ADDR) + TXX9_DMA_REG32(CHAR); +#else + u64 CHAR; +#endif + u64 SAR; + u64 DAR; + TXX9_DMA_REG32(CNTR); +}; +struct txx9dmac_hwdesc32 { + u32 CHAR; + u32 SAR; + u32 DAR; + u32 CNTR; +}; +#else +#define txx9dmac_hwdesc txx9dmac_cregs +#define txx9dmac_hwdesc32 txx9dmac_cregs32 +#endif + +struct txx9dmac_desc { + /* FIRST values the hardware uses */ + union { + struct txx9dmac_hwdesc hwdesc; + struct txx9dmac_hwdesc32 hwdesc32; + }; + + /* THEN values for driver housekeeping */ + struct list_head desc_node ____cacheline_aligned; + struct list_head tx_list; + struct dma_async_tx_descriptor txd; + size_t len; +}; + +#ifdef TXX9_DMA_USE_SIMPLE_CHAIN + +static inline bool txx9dmac_chan_INTENT(struct txx9dmac_chan *dc) +{ + return (dc->ccr & TXX9_DMA_CCR_INTENT) != 0; +} + +static inline void txx9dmac_chan_set_INTENT(struct txx9dmac_chan *dc) +{ + dc->ccr |= TXX9_DMA_CCR_INTENT; +} + +static inline void txx9dmac_desc_set_INTENT(struct txx9dmac_dev *ddev, + struct txx9dmac_desc *desc) +{ +} + +static inline void txx9dmac_chan_set_SMPCHN(struct txx9dmac_chan *dc) +{ + dc->ccr |= TXX9_DMA_CCR_SMPCHN; +} + +static inline void txx9dmac_desc_set_nosimple(struct txx9dmac_dev *ddev, + struct txx9dmac_desc *desc, + u32 sair, u32 dair, u32 ccr) +{ +} + +#else /* TXX9_DMA_USE_SIMPLE_CHAIN */ + +static inline bool txx9dmac_chan_INTENT(struct txx9dmac_chan *dc) +{ + return true; +} + +static void txx9dmac_chan_set_INTENT(struct txx9dmac_chan *dc) +{ +} + +static inline void txx9dmac_desc_set_INTENT(struct txx9dmac_dev *ddev, + struct txx9dmac_desc *desc) +{ + if (__is_dmac64(ddev)) + desc->hwdesc.CCR |= TXX9_DMA_CCR_INTENT; + else + desc->hwdesc32.CCR |= TXX9_DMA_CCR_INTENT; +} + +static inline void txx9dmac_chan_set_SMPCHN(struct txx9dmac_chan *dc) +{ +} + +static inline void txx9dmac_desc_set_nosimple(struct txx9dmac_dev *ddev, + struct txx9dmac_desc *desc, + u32 sai, u32 dai, u32 ccr) +{ + if (__is_dmac64(ddev)) { + desc->hwdesc.SAIR = sai; + desc->hwdesc.DAIR = dai; + desc->hwdesc.CCR = ccr; + } else { + desc->hwdesc32.SAIR = sai; + desc->hwdesc32.DAIR = dai; + desc->hwdesc32.CCR = ccr; + } +} + +#endif /* TXX9_DMA_USE_SIMPLE_CHAIN */ + +#endif /* TXX9DMAC_H */ diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index 956982f8739b..4339b1a879cd 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -5,7 +5,7 @@ # menuconfig EDAC - bool "EDAC - error detection and reporting" + bool "EDAC (Error Detection And Correction) reporting" depends on HAS_IOMEM depends on X86 || PPC help @@ -49,7 +49,6 @@ config EDAC_DEBUG_VERBOSE config EDAC_MM_EDAC tristate "Main Memory EDAC (Error Detection And Correction) reporting" - default y help Some systems are able to detect and correct errors in main memory. EDAC can report statistics on memory error @@ -58,6 +57,31 @@ config EDAC_MM_EDAC occurred so that a particular failing memory module can be replaced. If unsure, select 'Y'. +config EDAC_AMD64 + tristate "AMD64 (Opteron, Athlon64) K8, F10h, F11h" + depends on EDAC_MM_EDAC && K8_NB && X86_64 && PCI + help + Support for error detection and correction on the AMD 64 + Families of Memory Controllers (K8, F10h and F11h) + +config EDAC_AMD64_ERROR_INJECTION + bool "Sysfs Error Injection facilities" + depends on EDAC_AMD64 + help + Recent Opterons (Family 10h and later) provide for Memory Error + Injection into the ECC detection circuits. The amd64_edac module + allows the operator/user to inject Uncorrectable and Correctable + errors into DRAM. + + When enabled, in each of the respective memory controller directories + (/sys/devices/system/edac/mc/mcX), there are 3 input files: + + - inject_section (0..3, 16-byte section of 64-byte cacheline), + - inject_word (0..8, 16-bit word of 16-byte section), + - inject_ecc_vector (hex ecc vector: select bits of inject word) + + In addition, there are two control files, inject_read and inject_write, + which trigger the DRAM ECC Read and Write respectively. config EDAC_AMD76X tristate "AMD 76x (760, 762, 768)" @@ -208,4 +232,13 @@ config EDAC_AMD8111 Note, add more Kconfig dependency if it's adopted on some machine other than Maple. +config EDAC_CPC925 + tristate "IBM CPC925 Memory Controller (PPC970FX)" + depends on EDAC_MM_EDAC && PPC64 + help + Support for error detection and correction on the + IBM CPC925 Bridge and Memory Controller, which is + a companion chip to the PowerPC 970 family of + processors. + endif # EDAC diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile index 59076819135d..98aa4a7db412 100644 --- a/drivers/edac/Makefile +++ b/drivers/edac/Makefile @@ -18,6 +18,7 @@ edac_core-objs += edac_pci.o edac_pci_sysfs.o endif obj-$(CONFIG_EDAC_AMD76X) += amd76x_edac.o +obj-$(CONFIG_EDAC_CPC925) += cpc925_edac.o obj-$(CONFIG_EDAC_I5000) += i5000_edac.o obj-$(CONFIG_EDAC_I5100) += i5100_edac.o obj-$(CONFIG_EDAC_I5400) += i5400_edac.o @@ -30,6 +31,13 @@ obj-$(CONFIG_EDAC_I3000) += i3000_edac.o obj-$(CONFIG_EDAC_X38) += x38_edac.o obj-$(CONFIG_EDAC_I82860) += i82860_edac.o obj-$(CONFIG_EDAC_R82600) += r82600_edac.o + +amd64_edac_mod-y := amd64_edac_err_types.o amd64_edac.o +amd64_edac_mod-$(CONFIG_EDAC_DEBUG) += amd64_edac_dbg.o +amd64_edac_mod-$(CONFIG_EDAC_AMD64_ERROR_INJECTION) += amd64_edac_inj.o + +obj-$(CONFIG_EDAC_AMD64) += amd64_edac_mod.o + obj-$(CONFIG_EDAC_PASEMI) += pasemi_edac.o obj-$(CONFIG_EDAC_MPC85XX) += mpc85xx_edac.o obj-$(CONFIG_EDAC_MV64X60) += mv64x60_edac.o diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c new file mode 100644 index 000000000000..c36bf40568cf --- /dev/null +++ b/drivers/edac/amd64_edac.c @@ -0,0 +1,3354 @@ +#include "amd64_edac.h" +#include + +static struct edac_pci_ctl_info *amd64_ctl_pci; + +static int report_gart_errors; +module_param(report_gart_errors, int, 0644); + +/* + * Set by command line parameter. If BIOS has enabled the ECC, this override is + * cleared to prevent re-enabling the hardware by this driver. + */ +static int ecc_enable_override; +module_param(ecc_enable_override, int, 0644); + +/* Lookup table for all possible MC control instances */ +struct amd64_pvt; +static struct mem_ctl_info *mci_lookup[MAX_NUMNODES]; +static struct amd64_pvt *pvt_lookup[MAX_NUMNODES]; + +/* + * Memory scrubber control interface. For K8, memory scrubbing is handled by + * hardware and can involve L2 cache, dcache as well as the main memory. With + * F10, this is extended to L3 cache scrubbing on CPU models sporting that + * functionality. + * + * This causes the "units" for the scrubbing speed to vary from 64 byte blocks + * (dram) over to cache lines. This is nasty, so we will use bandwidth in + * bytes/sec for the setting. + * + * Currently, we only do dram scrubbing. If the scrubbing is done in software on + * other archs, we might not have access to the caches directly. + */ + +/* + * scan the scrub rate mapping table for a close or matching bandwidth value to + * issue. If requested is too big, then use last maximum value found. + */ +static int amd64_search_set_scrub_rate(struct pci_dev *ctl, u32 new_bw, + u32 min_scrubrate) +{ + u32 scrubval; + int i; + + /* + * map the configured rate (new_bw) to a value specific to the AMD64 + * memory controller and apply to register. Search for the first + * bandwidth entry that is greater or equal than the setting requested + * and program that. If at last entry, turn off DRAM scrubbing. + */ + for (i = 0; i < ARRAY_SIZE(scrubrates); i++) { + /* + * skip scrub rates which aren't recommended + * (see F10 BKDG, F3x58) + */ + if (scrubrates[i].scrubval < min_scrubrate) + continue; + + if (scrubrates[i].bandwidth <= new_bw) + break; + + /* + * if no suitable bandwidth found, turn off DRAM scrubbing + * entirely by falling back to the last element in the + * scrubrates array. + */ + } + + scrubval = scrubrates[i].scrubval; + if (scrubval) + edac_printk(KERN_DEBUG, EDAC_MC, + "Setting scrub rate bandwidth: %u\n", + scrubrates[i].bandwidth); + else + edac_printk(KERN_DEBUG, EDAC_MC, "Turning scrubbing off.\n"); + + pci_write_bits32(ctl, K8_SCRCTRL, scrubval, 0x001F); + + return 0; +} + +static int amd64_set_scrub_rate(struct mem_ctl_info *mci, u32 *bandwidth) +{ + struct amd64_pvt *pvt = mci->pvt_info; + u32 min_scrubrate = 0x0; + + switch (boot_cpu_data.x86) { + case 0xf: + min_scrubrate = K8_MIN_SCRUB_RATE_BITS; + break; + case 0x10: + min_scrubrate = F10_MIN_SCRUB_RATE_BITS; + break; + case 0x11: + min_scrubrate = F11_MIN_SCRUB_RATE_BITS; + break; + + default: + amd64_printk(KERN_ERR, "Unsupported family!\n"); + break; + } + return amd64_search_set_scrub_rate(pvt->misc_f3_ctl, *bandwidth, + min_scrubrate); +} + +static int amd64_get_scrub_rate(struct mem_ctl_info *mci, u32 *bw) +{ + struct amd64_pvt *pvt = mci->pvt_info; + u32 scrubval = 0; + int status = -1, i, ret = 0; + + ret = pci_read_config_dword(pvt->misc_f3_ctl, K8_SCRCTRL, &scrubval); + if (ret) + debugf0("Reading K8_SCRCTRL failed\n"); + + scrubval = scrubval & 0x001F; + + edac_printk(KERN_DEBUG, EDAC_MC, + "pci-read, sdram scrub control value: %d \n", scrubval); + + for (i = 0; ARRAY_SIZE(scrubrates); i++) { + if (scrubrates[i].scrubval == scrubval) { + *bw = scrubrates[i].bandwidth; + status = 0; + break; + } + } + + return status; +} + +/* Map from a CSROW entry to the mask entry that operates on it */ +static inline u32 amd64_map_to_dcs_mask(struct amd64_pvt *pvt, int csrow) +{ + return csrow >> (pvt->num_dcsm >> 3); +} + +/* return the 'base' address the i'th CS entry of the 'dct' DRAM controller */ +static u32 amd64_get_dct_base(struct amd64_pvt *pvt, int dct, int csrow) +{ + if (dct == 0) + return pvt->dcsb0[csrow]; + else + return pvt->dcsb1[csrow]; +} + +/* + * Return the 'mask' address the i'th CS entry. This function is needed because + * there number of DCSM registers on Rev E and prior vs Rev F and later is + * different. + */ +static u32 amd64_get_dct_mask(struct amd64_pvt *pvt, int dct, int csrow) +{ + if (dct == 0) + return pvt->dcsm0[amd64_map_to_dcs_mask(pvt, csrow)]; + else + return pvt->dcsm1[amd64_map_to_dcs_mask(pvt, csrow)]; +} + + +/* + * In *base and *limit, pass back the full 40-bit base and limit physical + * addresses for the node given by node_id. This information is obtained from + * DRAM Base (section 3.4.4.1) and DRAM Limit (section 3.4.4.2) registers. The + * base and limit addresses are of type SysAddr, as defined at the start of + * section 3.4.4 (p. 70). They are the lowest and highest physical addresses + * in the address range they represent. + */ +static void amd64_get_base_and_limit(struct amd64_pvt *pvt, int node_id, + u64 *base, u64 *limit) +{ + *base = pvt->dram_base[node_id]; + *limit = pvt->dram_limit[node_id]; +} + +/* + * Return 1 if the SysAddr given by sys_addr matches the base/limit associated + * with node_id + */ +static int amd64_base_limit_match(struct amd64_pvt *pvt, + u64 sys_addr, int node_id) +{ + u64 base, limit, addr; + + amd64_get_base_and_limit(pvt, node_id, &base, &limit); + + /* The K8 treats this as a 40-bit value. However, bits 63-40 will be + * all ones if the most significant implemented address bit is 1. + * Here we discard bits 63-40. See section 3.4.2 of AMD publication + * 24592: AMD x86-64 Architecture Programmer's Manual Volume 1 + * Application Programming. + */ + addr = sys_addr & 0x000000ffffffffffull; + + return (addr >= base) && (addr <= limit); +} + +/* + * Attempt to map a SysAddr to a node. On success, return a pointer to the + * mem_ctl_info structure for the node that the SysAddr maps to. + * + * On failure, return NULL. + */ +static struct mem_ctl_info *find_mc_by_sys_addr(struct mem_ctl_info *mci, + u64 sys_addr) +{ + struct amd64_pvt *pvt; + int node_id; + u32 intlv_en, bits; + + /* + * Here we use the DRAM Base (section 3.4.4.1) and DRAM Limit (section + * 3.4.4.2) registers to map the SysAddr to a node ID. + */ + pvt = mci->pvt_info; + + /* + * The value of this field should be the same for all DRAM Base + * registers. Therefore we arbitrarily choose to read it from the + * register for node 0. + */ + intlv_en = pvt->dram_IntlvEn[0]; + + if (intlv_en == 0) { + for (node_id = 0; ; ) { + if (amd64_base_limit_match(pvt, sys_addr, node_id)) + break; + + if (++node_id >= DRAM_REG_COUNT) + goto err_no_match; + } + goto found; + } + + if (unlikely((intlv_en != (0x01 << 8)) && + (intlv_en != (0x03 << 8)) && + (intlv_en != (0x07 << 8)))) { + amd64_printk(KERN_WARNING, "junk value of 0x%x extracted from " + "IntlvEn field of DRAM Base Register for node 0: " + "This probably indicates a BIOS bug.\n", intlv_en); + return NULL; + } + + bits = (((u32) sys_addr) >> 12) & intlv_en; + + for (node_id = 0; ; ) { + if ((pvt->dram_limit[node_id] & intlv_en) == bits) + break; /* intlv_sel field matches */ + + if (++node_id >= DRAM_REG_COUNT) + goto err_no_match; + } + + /* sanity test for sys_addr */ + if (unlikely(!amd64_base_limit_match(pvt, sys_addr, node_id))) { + amd64_printk(KERN_WARNING, + "%s(): sys_addr 0x%lx falls outside base/limit " + "address range for node %d with node interleaving " + "enabled.\n", __func__, (unsigned long)sys_addr, + node_id); + return NULL; + } + +found: + return edac_mc_find(node_id); + +err_no_match: + debugf2("sys_addr 0x%lx doesn't match any node\n", + (unsigned long)sys_addr); + + return NULL; +} + +/* + * Extract the DRAM CS base address from selected csrow register. + */ +static u64 base_from_dct_base(struct amd64_pvt *pvt, int csrow) +{ + return ((u64) (amd64_get_dct_base(pvt, 0, csrow) & pvt->dcsb_base)) << + pvt->dcs_shift; +} + +/* + * Extract the mask from the dcsb0[csrow] entry in a CPU revision-specific way. + */ +static u64 mask_from_dct_mask(struct amd64_pvt *pvt, int csrow) +{ + u64 dcsm_bits, other_bits; + u64 mask; + + /* Extract bits from DRAM CS Mask. */ + dcsm_bits = amd64_get_dct_mask(pvt, 0, csrow) & pvt->dcsm_mask; + + other_bits = pvt->dcsm_mask; + other_bits = ~(other_bits << pvt->dcs_shift); + + /* + * The extracted bits from DCSM belong in the spaces represented by + * the cleared bits in other_bits. + */ + mask = (dcsm_bits << pvt->dcs_shift) | other_bits; + + return mask; +} + +/* + * @input_addr is an InputAddr associated with the node given by mci. Return the + * csrow that input_addr maps to, or -1 on failure (no csrow claims input_addr). + */ +static int input_addr_to_csrow(struct mem_ctl_info *mci, u64 input_addr) +{ + struct amd64_pvt *pvt; + int csrow; + u64 base, mask; + + pvt = mci->pvt_info; + + /* + * Here we use the DRAM CS Base and DRAM CS Mask registers. For each CS + * base/mask register pair, test the condition shown near the start of + * section 3.5.4 (p. 84, BKDG #26094, K8, revA-E). + */ + for (csrow = 0; csrow < CHIPSELECT_COUNT; csrow++) { + + /* This DRAM chip select is disabled on this node */ + if ((pvt->dcsb0[csrow] & K8_DCSB_CS_ENABLE) == 0) + continue; + + base = base_from_dct_base(pvt, csrow); + mask = ~mask_from_dct_mask(pvt, csrow); + + if ((input_addr & mask) == (base & mask)) { + debugf2("InputAddr 0x%lx matches csrow %d (node %d)\n", + (unsigned long)input_addr, csrow, + pvt->mc_node_id); + + return csrow; + } + } + + debugf2("no matching csrow for InputAddr 0x%lx (MC node %d)\n", + (unsigned long)input_addr, pvt->mc_node_id); + + return -1; +} + +/* + * Return the base value defined by the DRAM Base register for the node + * represented by mci. This function returns the full 40-bit value despite the + * fact that the register only stores bits 39-24 of the value. See section + * 3.4.4.1 (BKDG #26094, K8, revA-E) + */ +static inline u64 get_dram_base(struct mem_ctl_info *mci) +{ + struct amd64_pvt *pvt = mci->pvt_info; + + return pvt->dram_base[pvt->mc_node_id]; +} + +/* + * Obtain info from the DRAM Hole Address Register (section 3.4.8, pub #26094) + * for the node represented by mci. Info is passed back in *hole_base, + * *hole_offset, and *hole_size. Function returns 0 if info is valid or 1 if + * info is invalid. Info may be invalid for either of the following reasons: + * + * - The revision of the node is not E or greater. In this case, the DRAM Hole + * Address Register does not exist. + * + * - The DramHoleValid bit is cleared in the DRAM Hole Address Register, + * indicating that its contents are not valid. + * + * The values passed back in *hole_base, *hole_offset, and *hole_size are + * complete 32-bit values despite the fact that the bitfields in the DHAR + * only represent bits 31-24 of the base and offset values. + */ +int amd64_get_dram_hole_info(struct mem_ctl_info *mci, u64 *hole_base, + u64 *hole_offset, u64 *hole_size) +{ + struct amd64_pvt *pvt = mci->pvt_info; + u64 base; + + /* only revE and later have the DRAM Hole Address Register */ + if (boot_cpu_data.x86 == 0xf && pvt->ext_model < OPTERON_CPU_REV_E) { + debugf1(" revision %d for node %d does not support DHAR\n", + pvt->ext_model, pvt->mc_node_id); + return 1; + } + + /* only valid for Fam10h */ + if (boot_cpu_data.x86 == 0x10 && + (pvt->dhar & F10_DRAM_MEM_HOIST_VALID) == 0) { + debugf1(" Dram Memory Hoisting is DISABLED on this system\n"); + return 1; + } + + if ((pvt->dhar & DHAR_VALID) == 0) { + debugf1(" Dram Memory Hoisting is DISABLED on this node %d\n", + pvt->mc_node_id); + return 1; + } + + /* This node has Memory Hoisting */ + + /* +------------------+--------------------+--------------------+----- + * | memory | DRAM hole | relocated | + * | [0, (x - 1)] | [x, 0xffffffff] | addresses from | + * | | | DRAM hole | + * | | | [0x100000000, | + * | | | (0x100000000+ | + * | | | (0xffffffff-x))] | + * +------------------+--------------------+--------------------+----- + * + * Above is a diagram of physical memory showing the DRAM hole and the + * relocated addresses from the DRAM hole. As shown, the DRAM hole + * starts at address x (the base address) and extends through address + * 0xffffffff. The DRAM Hole Address Register (DHAR) relocates the + * addresses in the hole so that they start at 0x100000000. + */ + + base = dhar_base(pvt->dhar); + + *hole_base = base; + *hole_size = (0x1ull << 32) - base; + + if (boot_cpu_data.x86 > 0xf) + *hole_offset = f10_dhar_offset(pvt->dhar); + else + *hole_offset = k8_dhar_offset(pvt->dhar); + + debugf1(" DHAR info for node %d base 0x%lx offset 0x%lx size 0x%lx\n", + pvt->mc_node_id, (unsigned long)*hole_base, + (unsigned long)*hole_offset, (unsigned long)*hole_size); + + return 0; +} +EXPORT_SYMBOL_GPL(amd64_get_dram_hole_info); + +/* + * Return the DramAddr that the SysAddr given by @sys_addr maps to. It is + * assumed that sys_addr maps to the node given by mci. + * + * The first part of section 3.4.4 (p. 70) shows how the DRAM Base (section + * 3.4.4.1) and DRAM Limit (section 3.4.4.2) registers are used to translate a + * SysAddr to a DramAddr. If the DRAM Hole Address Register (DHAR) is enabled, + * then it is also involved in translating a SysAddr to a DramAddr. Sections + * 3.4.8 and 3.5.8.2 describe the DHAR and how it is used for memory hoisting. + * These parts of the documentation are unclear. I interpret them as follows: + * + * When node n receives a SysAddr, it processes the SysAddr as follows: + * + * 1. It extracts the DRAMBase and DRAMLimit values from the DRAM Base and DRAM + * Limit registers for node n. If the SysAddr is not within the range + * specified by the base and limit values, then node n ignores the Sysaddr + * (since it does not map to node n). Otherwise continue to step 2 below. + * + * 2. If the DramHoleValid bit of the DHAR for node n is clear, the DHAR is + * disabled so skip to step 3 below. Otherwise see if the SysAddr is within + * the range of relocated addresses (starting at 0x100000000) from the DRAM + * hole. If not, skip to step 3 below. Else get the value of the + * DramHoleOffset field from the DHAR. To obtain the DramAddr, subtract the + * offset defined by this value from the SysAddr. + * + * 3. Obtain the base address for node n from the DRAMBase field of the DRAM + * Base register for node n. To obtain the DramAddr, subtract the base + * address from the SysAddr, as shown near the start of section 3.4.4 (p.70). + */ +static u64 sys_addr_to_dram_addr(struct mem_ctl_info *mci, u64 sys_addr) +{ + u64 dram_base, hole_base, hole_offset, hole_size, dram_addr; + int ret = 0; + + dram_base = get_dram_base(mci); + + ret = amd64_get_dram_hole_info(mci, &hole_base, &hole_offset, + &hole_size); + if (!ret) { + if ((sys_addr >= (1ull << 32)) && + (sys_addr < ((1ull << 32) + hole_size))) { + /* use DHAR to translate SysAddr to DramAddr */ + dram_addr = sys_addr - hole_offset; + + debugf2("using DHAR to translate SysAddr 0x%lx to " + "DramAddr 0x%lx\n", + (unsigned long)sys_addr, + (unsigned long)dram_addr); + + return dram_addr; + } + } + + /* + * Translate the SysAddr to a DramAddr as shown near the start of + * section 3.4.4 (p. 70). Although sys_addr is a 64-bit value, the k8 + * only deals with 40-bit values. Therefore we discard bits 63-40 of + * sys_addr below. If bit 39 of sys_addr is 1 then the bits we + * discard are all 1s. Otherwise the bits we discard are all 0s. See + * section 3.4.2 of AMD publication 24592: AMD x86-64 Architecture + * Programmer's Manual Volume 1 Application Programming. + */ + dram_addr = (sys_addr & 0xffffffffffull) - dram_base; + + debugf2("using DRAM Base register to translate SysAddr 0x%lx to " + "DramAddr 0x%lx\n", (unsigned long)sys_addr, + (unsigned long)dram_addr); + return dram_addr; +} + +/* + * @intlv_en is the value of the IntlvEn field from a DRAM Base register + * (section 3.4.4.1). Return the number of bits from a SysAddr that are used + * for node interleaving. + */ +static int num_node_interleave_bits(unsigned intlv_en) +{ + static const int intlv_shift_table[] = { 0, 1, 0, 2, 0, 0, 0, 3 }; + int n; + + BUG_ON(intlv_en > 7); + n = intlv_shift_table[intlv_en]; + return n; +} + +/* Translate the DramAddr given by @dram_addr to an InputAddr. */ +static u64 dram_addr_to_input_addr(struct mem_ctl_info *mci, u64 dram_addr) +{ + struct amd64_pvt *pvt; + int intlv_shift; + u64 input_addr; + + pvt = mci->pvt_info; + + /* + * See the start of section 3.4.4 (p. 70, BKDG #26094, K8, revA-E) + * concerning translating a DramAddr to an InputAddr. + */ + intlv_shift = num_node_interleave_bits(pvt->dram_IntlvEn[0]); + input_addr = ((dram_addr >> intlv_shift) & 0xffffff000ull) + + (dram_addr & 0xfff); + + debugf2(" Intlv Shift=%d DramAddr=0x%lx maps to InputAddr=0x%lx\n", + intlv_shift, (unsigned long)dram_addr, + (unsigned long)input_addr); + + return input_addr; +} + +/* + * Translate the SysAddr represented by @sys_addr to an InputAddr. It is + * assumed that @sys_addr maps to the node given by mci. + */ +static u64 sys_addr_to_input_addr(struct mem_ctl_info *mci, u64 sys_addr) +{ + u64 input_addr; + + input_addr = + dram_addr_to_input_addr(mci, sys_addr_to_dram_addr(mci, sys_addr)); + + debugf2("SysAdddr 0x%lx translates to InputAddr 0x%lx\n", + (unsigned long)sys_addr, (unsigned long)input_addr); + + return input_addr; +} + + +/* + * @input_addr is an InputAddr associated with the node represented by mci. + * Translate @input_addr to a DramAddr and return the result. + */ +static u64 input_addr_to_dram_addr(struct mem_ctl_info *mci, u64 input_addr) +{ + struct amd64_pvt *pvt; + int node_id, intlv_shift; + u64 bits, dram_addr; + u32 intlv_sel; + + /* + * Near the start of section 3.4.4 (p. 70, BKDG #26094, K8, revA-E) + * shows how to translate a DramAddr to an InputAddr. Here we reverse + * this procedure. When translating from a DramAddr to an InputAddr, the + * bits used for node interleaving are discarded. Here we recover these + * bits from the IntlvSel field of the DRAM Limit register (section + * 3.4.4.2) for the node that input_addr is associated with. + */ + pvt = mci->pvt_info; + node_id = pvt->mc_node_id; + BUG_ON((node_id < 0) || (node_id > 7)); + + intlv_shift = num_node_interleave_bits(pvt->dram_IntlvEn[0]); + + if (intlv_shift == 0) { + debugf1(" InputAddr 0x%lx translates to DramAddr of " + "same value\n", (unsigned long)input_addr); + + return input_addr; + } + + bits = ((input_addr & 0xffffff000ull) << intlv_shift) + + (input_addr & 0xfff); + + intlv_sel = pvt->dram_IntlvSel[node_id] & ((1 << intlv_shift) - 1); + dram_addr = bits + (intlv_sel << 12); + + debugf1("InputAddr 0x%lx translates to DramAddr 0x%lx " + "(%d node interleave bits)\n", (unsigned long)input_addr, + (unsigned long)dram_addr, intlv_shift); + + return dram_addr; +} + +/* + * @dram_addr is a DramAddr that maps to the node represented by mci. Convert + * @dram_addr to a SysAddr. + */ +static u64 dram_addr_to_sys_addr(struct mem_ctl_info *mci, u64 dram_addr) +{ + struct amd64_pvt *pvt = mci->pvt_info; + u64 hole_base, hole_offset, hole_size, base, limit, sys_addr; + int ret = 0; + + ret = amd64_get_dram_hole_info(mci, &hole_base, &hole_offset, + &hole_size); + if (!ret) { + if ((dram_addr >= hole_base) && + (dram_addr < (hole_base + hole_size))) { + sys_addr = dram_addr + hole_offset; + + debugf1("using DHAR to translate DramAddr 0x%lx to " + "SysAddr 0x%lx\n", (unsigned long)dram_addr, + (unsigned long)sys_addr); + + return sys_addr; + } + } + + amd64_get_base_and_limit(pvt, pvt->mc_node_id, &base, &limit); + sys_addr = dram_addr + base; + + /* + * The sys_addr we have computed up to this point is a 40-bit value + * because the k8 deals with 40-bit values. However, the value we are + * supposed to return is a full 64-bit physical address. The AMD + * x86-64 architecture specifies that the most significant implemented + * address bit through bit 63 of a physical address must be either all + * 0s or all 1s. Therefore we sign-extend the 40-bit sys_addr to a + * 64-bit value below. See section 3.4.2 of AMD publication 24592: + * AMD x86-64 Architecture Programmer's Manual Volume 1 Application + * Programming. + */ + sys_addr |= ~((sys_addr & (1ull << 39)) - 1); + + debugf1(" Node %d, DramAddr 0x%lx to SysAddr 0x%lx\n", + pvt->mc_node_id, (unsigned long)dram_addr, + (unsigned long)sys_addr); + + return sys_addr; +} + +/* + * @input_addr is an InputAddr associated with the node given by mci. Translate + * @input_addr to a SysAddr. + */ +static inline u64 input_addr_to_sys_addr(struct mem_ctl_info *mci, + u64 input_addr) +{ + return dram_addr_to_sys_addr(mci, + input_addr_to_dram_addr(mci, input_addr)); +} + +/* + * Find the minimum and maximum InputAddr values that map to the given @csrow. + * Pass back these values in *input_addr_min and *input_addr_max. + */ +static void find_csrow_limits(struct mem_ctl_info *mci, int csrow, + u64 *input_addr_min, u64 *input_addr_max) +{ + struct amd64_pvt *pvt; + u64 base, mask; + + pvt = mci->pvt_info; + BUG_ON((csrow < 0) || (csrow >= CHIPSELECT_COUNT)); + + base = base_from_dct_base(pvt, csrow); + mask = mask_from_dct_mask(pvt, csrow); + + *input_addr_min = base & ~mask; + *input_addr_max = base | mask | pvt->dcs_mask_notused; +} + +/* + * Extract error address from MCA NB Address Low (section 3.6.4.5) and MCA NB + * Address High (section 3.6.4.6) register values and return the result. Address + * is located in the info structure (nbeah and nbeal), the encoding is device + * specific. + */ +static u64 extract_error_address(struct mem_ctl_info *mci, + struct amd64_error_info_regs *info) +{ + struct amd64_pvt *pvt = mci->pvt_info; + + return pvt->ops->get_error_address(mci, info); +} + + +/* Map the Error address to a PAGE and PAGE OFFSET. */ +static inline void error_address_to_page_and_offset(u64 error_address, + u32 *page, u32 *offset) +{ + *page = (u32) (error_address >> PAGE_SHIFT); + *offset = ((u32) error_address) & ~PAGE_MASK; +} + +/* + * @sys_addr is an error address (a SysAddr) extracted from the MCA NB Address + * Low (section 3.6.4.5) and MCA NB Address High (section 3.6.4.6) registers + * of a node that detected an ECC memory error. mci represents the node that + * the error address maps to (possibly different from the node that detected + * the error). Return the number of the csrow that sys_addr maps to, or -1 on + * error. + */ +static int sys_addr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr) +{ + int csrow; + + csrow = input_addr_to_csrow(mci, sys_addr_to_input_addr(mci, sys_addr)); + + if (csrow == -1) + amd64_mc_printk(mci, KERN_ERR, + "Failed to translate InputAddr to csrow for " + "address 0x%lx\n", (unsigned long)sys_addr); + return csrow; +} + +static int get_channel_from_ecc_syndrome(unsigned short syndrome); + +static void amd64_cpu_display_info(struct amd64_pvt *pvt) +{ + if (boot_cpu_data.x86 == 0x11) + edac_printk(KERN_DEBUG, EDAC_MC, "F11h CPU detected\n"); + else if (boot_cpu_data.x86 == 0x10) + edac_printk(KERN_DEBUG, EDAC_MC, "F10h CPU detected\n"); + else if (boot_cpu_data.x86 == 0xf) + edac_printk(KERN_DEBUG, EDAC_MC, "%s detected\n", + (pvt->ext_model >= OPTERON_CPU_REV_F) ? + "Rev F or later" : "Rev E or earlier"); + else + /* we'll hardly ever ever get here */ + edac_printk(KERN_ERR, EDAC_MC, "Unknown cpu!\n"); +} + +/* + * Determine if the DIMMs have ECC enabled. ECC is enabled ONLY if all the DIMMs + * are ECC capable. + */ +static enum edac_type amd64_determine_edac_cap(struct amd64_pvt *pvt) +{ + int bit; + enum dev_type edac_cap = EDAC_NONE; + + bit = (boot_cpu_data.x86 > 0xf || pvt->ext_model >= OPTERON_CPU_REV_F) + ? 19 + : 17; + + if (pvt->dclr0 >> BIT(bit)) + edac_cap = EDAC_FLAG_SECDED; + + return edac_cap; +} + + +static void f10_debug_display_dimm_sizes(int ctrl, struct amd64_pvt *pvt, + int ganged); + +/* Display and decode various NB registers for debug purposes. */ +static void amd64_dump_misc_regs(struct amd64_pvt *pvt) +{ + int ganged; + + debugf1(" nbcap:0x%8.08x DctDualCap=%s DualNode=%s 8-Node=%s\n", + pvt->nbcap, + (pvt->nbcap & K8_NBCAP_DCT_DUAL) ? "True" : "False", + (pvt->nbcap & K8_NBCAP_DUAL_NODE) ? "True" : "False", + (pvt->nbcap & K8_NBCAP_8_NODE) ? "True" : "False"); + debugf1(" ECC Capable=%s ChipKill Capable=%s\n", + (pvt->nbcap & K8_NBCAP_SECDED) ? "True" : "False", + (pvt->nbcap & K8_NBCAP_CHIPKILL) ? "True" : "False"); + debugf1(" DramCfg0-low=0x%08x DIMM-ECC=%s Parity=%s Width=%s\n", + pvt->dclr0, + (pvt->dclr0 & BIT(19)) ? "Enabled" : "Disabled", + (pvt->dclr0 & BIT(8)) ? "Enabled" : "Disabled", + (pvt->dclr0 & BIT(11)) ? "128b" : "64b"); + debugf1(" DIMM x4 Present: L0=%s L1=%s L2=%s L3=%s DIMM Type=%s\n", + (pvt->dclr0 & BIT(12)) ? "Y" : "N", + (pvt->dclr0 & BIT(13)) ? "Y" : "N", + (pvt->dclr0 & BIT(14)) ? "Y" : "N", + (pvt->dclr0 & BIT(15)) ? "Y" : "N", + (pvt->dclr0 & BIT(16)) ? "UN-Buffered" : "Buffered"); + + + debugf1(" online-spare: 0x%8.08x\n", pvt->online_spare); + + if (boot_cpu_data.x86 == 0xf) { + debugf1(" dhar: 0x%8.08x Base=0x%08x Offset=0x%08x\n", + pvt->dhar, dhar_base(pvt->dhar), + k8_dhar_offset(pvt->dhar)); + debugf1(" DramHoleValid=%s\n", + (pvt->dhar & DHAR_VALID) ? "True" : "False"); + + debugf1(" dbam-dkt: 0x%8.08x\n", pvt->dbam0); + + /* everything below this point is Fam10h and above */ + return; + + } else { + debugf1(" dhar: 0x%8.08x Base=0x%08x Offset=0x%08x\n", + pvt->dhar, dhar_base(pvt->dhar), + f10_dhar_offset(pvt->dhar)); + debugf1(" DramMemHoistValid=%s DramHoleValid=%s\n", + (pvt->dhar & F10_DRAM_MEM_HOIST_VALID) ? + "True" : "False", + (pvt->dhar & DHAR_VALID) ? + "True" : "False"); + } + + /* Only if NOT ganged does dcl1 have valid info */ + if (!dct_ganging_enabled(pvt)) { + debugf1(" DramCfg1-low=0x%08x DIMM-ECC=%s Parity=%s " + "Width=%s\n", pvt->dclr1, + (pvt->dclr1 & BIT(19)) ? "Enabled" : "Disabled", + (pvt->dclr1 & BIT(8)) ? "Enabled" : "Disabled", + (pvt->dclr1 & BIT(11)) ? "128b" : "64b"); + debugf1(" DIMM x4 Present: L0=%s L1=%s L2=%s L3=%s " + "DIMM Type=%s\n", + (pvt->dclr1 & BIT(12)) ? "Y" : "N", + (pvt->dclr1 & BIT(13)) ? "Y" : "N", + (pvt->dclr1 & BIT(14)) ? "Y" : "N", + (pvt->dclr1 & BIT(15)) ? "Y" : "N", + (pvt->dclr1 & BIT(16)) ? "UN-Buffered" : "Buffered"); + } + + /* + * Determine if ganged and then dump memory sizes for first controller, + * and if NOT ganged dump info for 2nd controller. + */ + ganged = dct_ganging_enabled(pvt); + + f10_debug_display_dimm_sizes(0, pvt, ganged); + + if (!ganged) + f10_debug_display_dimm_sizes(1, pvt, ganged); +} + +/* Read in both of DBAM registers */ +static void amd64_read_dbam_reg(struct amd64_pvt *pvt) +{ + int err = 0; + unsigned int reg; + + reg = DBAM0; + err = pci_read_config_dword(pvt->dram_f2_ctl, reg, &pvt->dbam0); + if (err) + goto err_reg; + + if (boot_cpu_data.x86 >= 0x10) { + reg = DBAM1; + err = pci_read_config_dword(pvt->dram_f2_ctl, reg, &pvt->dbam1); + + if (err) + goto err_reg; + } + +err_reg: + debugf0("Error reading F2x%03x.\n", reg); +} + +/* + * NOTE: CPU Revision Dependent code: Rev E and Rev F + * + * Set the DCSB and DCSM mask values depending on the CPU revision value. Also + * set the shift factor for the DCSB and DCSM values. + * + * ->dcs_mask_notused, RevE: + * + * To find the max InputAddr for the csrow, start with the base address and set + * all bits that are "don't care" bits in the test at the start of section + * 3.5.4 (p. 84). + * + * The "don't care" bits are all set bits in the mask and all bits in the gaps + * between bit ranges [35:25] and [19:13]. The value REV_E_DCS_NOTUSED_BITS + * represents bits [24:20] and [12:0], which are all bits in the above-mentioned + * gaps. + * + * ->dcs_mask_notused, RevF and later: + * + * To find the max InputAddr for the csrow, start with the base address and set + * all bits that are "don't care" bits in the test at the start of NPT section + * 4.5.4 (p. 87). + * + * The "don't care" bits are all set bits in the mask and all bits in the gaps + * between bit ranges [36:27] and [21:13]. + * + * The value REV_F_F1Xh_DCS_NOTUSED_BITS represents bits [26:22] and [12:0], + * which are all bits in the above-mentioned gaps. + */ +static void amd64_set_dct_base_and_mask(struct amd64_pvt *pvt) +{ + if (pvt->ext_model >= OPTERON_CPU_REV_F) { + pvt->dcsb_base = REV_F_F1Xh_DCSB_BASE_BITS; + pvt->dcsm_mask = REV_F_F1Xh_DCSM_MASK_BITS; + pvt->dcs_mask_notused = REV_F_F1Xh_DCS_NOTUSED_BITS; + pvt->dcs_shift = REV_F_F1Xh_DCS_SHIFT; + + switch (boot_cpu_data.x86) { + case 0xf: + pvt->num_dcsm = REV_F_DCSM_COUNT; + break; + + case 0x10: + pvt->num_dcsm = F10_DCSM_COUNT; + break; + + case 0x11: + pvt->num_dcsm = F11_DCSM_COUNT; + break; + + default: + amd64_printk(KERN_ERR, "Unsupported family!\n"); + break; + } + } else { + pvt->dcsb_base = REV_E_DCSB_BASE_BITS; + pvt->dcsm_mask = REV_E_DCSM_MASK_BITS; + pvt->dcs_mask_notused = REV_E_DCS_NOTUSED_BITS; + pvt->dcs_shift = REV_E_DCS_SHIFT; + pvt->num_dcsm = REV_E_DCSM_COUNT; + } +} + +/* + * Function 2 Offset F10_DCSB0; read in the DCS Base and DCS Mask hw registers + */ +static void amd64_read_dct_base_mask(struct amd64_pvt *pvt) +{ + int cs, reg, err = 0; + + amd64_set_dct_base_and_mask(pvt); + + for (cs = 0; cs < CHIPSELECT_COUNT; cs++) { + reg = K8_DCSB0 + (cs * 4); + err = pci_read_config_dword(pvt->dram_f2_ctl, reg, + &pvt->dcsb0[cs]); + if (unlikely(err)) + debugf0("Reading K8_DCSB0[%d] failed\n", cs); + else + debugf0(" DCSB0[%d]=0x%08x reg: F2x%x\n", + cs, pvt->dcsb0[cs], reg); + + /* If DCT are NOT ganged, then read in DCT1's base */ + if (boot_cpu_data.x86 >= 0x10 && !dct_ganging_enabled(pvt)) { + reg = F10_DCSB1 + (cs * 4); + err = pci_read_config_dword(pvt->dram_f2_ctl, reg, + &pvt->dcsb1[cs]); + if (unlikely(err)) + debugf0("Reading F10_DCSB1[%d] failed\n", cs); + else + debugf0(" DCSB1[%d]=0x%08x reg: F2x%x\n", + cs, pvt->dcsb1[cs], reg); + } else { + pvt->dcsb1[cs] = 0; + } + } + + for (cs = 0; cs < pvt->num_dcsm; cs++) { + reg = K8_DCSB0 + (cs * 4); + err = pci_read_config_dword(pvt->dram_f2_ctl, reg, + &pvt->dcsm0[cs]); + if (unlikely(err)) + debugf0("Reading K8_DCSM0 failed\n"); + else + debugf0(" DCSM0[%d]=0x%08x reg: F2x%x\n", + cs, pvt->dcsm0[cs], reg); + + /* If DCT are NOT ganged, then read in DCT1's mask */ + if (boot_cpu_data.x86 >= 0x10 && !dct_ganging_enabled(pvt)) { + reg = F10_DCSM1 + (cs * 4); + err = pci_read_config_dword(pvt->dram_f2_ctl, reg, + &pvt->dcsm1[cs]); + if (unlikely(err)) + debugf0("Reading F10_DCSM1[%d] failed\n", cs); + else + debugf0(" DCSM1[%d]=0x%08x reg: F2x%x\n", + cs, pvt->dcsm1[cs], reg); + } else + pvt->dcsm1[cs] = 0; + } +} + +static enum mem_type amd64_determine_memory_type(struct amd64_pvt *pvt) +{ + enum mem_type type; + + if (boot_cpu_data.x86 >= 0x10 || pvt->ext_model >= OPTERON_CPU_REV_F) { + /* Rev F and later */ + type = (pvt->dclr0 & BIT(16)) ? MEM_DDR2 : MEM_RDDR2; + } else { + /* Rev E and earlier */ + type = (pvt->dclr0 & BIT(18)) ? MEM_DDR : MEM_RDDR; + } + + debugf1(" Memory type is: %s\n", + (type == MEM_DDR2) ? "MEM_DDR2" : + (type == MEM_RDDR2) ? "MEM_RDDR2" : + (type == MEM_DDR) ? "MEM_DDR" : "MEM_RDDR"); + + return type; +} + +/* + * Read the DRAM Configuration Low register. It differs between CG, D & E revs + * and the later RevF memory controllers (DDR vs DDR2) + * + * Return: + * number of memory channels in operation + * Pass back: + * contents of the DCL0_LOW register + */ +static int k8_early_channel_count(struct amd64_pvt *pvt) +{ + int flag, err = 0; + + err = pci_read_config_dword(pvt->dram_f2_ctl, F10_DCLR_0, &pvt->dclr0); + if (err) + return err; + + if ((boot_cpu_data.x86_model >> 4) >= OPTERON_CPU_REV_F) { + /* RevF (NPT) and later */ + flag = pvt->dclr0 & F10_WIDTH_128; + } else { + /* RevE and earlier */ + flag = pvt->dclr0 & REVE_WIDTH_128; + } + + /* not used */ + pvt->dclr1 = 0; + + return (flag) ? 2 : 1; +} + +/* extract the ERROR ADDRESS for the K8 CPUs */ +static u64 k8_get_error_address(struct mem_ctl_info *mci, + struct amd64_error_info_regs *info) +{ + return (((u64) (info->nbeah & 0xff)) << 32) + + (info->nbeal & ~0x03); +} + +/* + * Read the Base and Limit registers for K8 based Memory controllers; extract + * fields from the 'raw' reg into separate data fields + * + * Isolates: BASE, LIMIT, IntlvEn, IntlvSel, RW_EN + */ +static void k8_read_dram_base_limit(struct amd64_pvt *pvt, int dram) +{ + u32 low; + u32 off = dram << 3; /* 8 bytes between DRAM entries */ + int err; + + err = pci_read_config_dword(pvt->addr_f1_ctl, + K8_DRAM_BASE_LOW + off, &low); + if (err) + debugf0("Reading K8_DRAM_BASE_LOW failed\n"); + + /* Extract parts into separate data entries */ + pvt->dram_base[dram] = ((u64) low & 0xFFFF0000) << 8; + pvt->dram_IntlvEn[dram] = (low >> 8) & 0x7; + pvt->dram_rw_en[dram] = (low & 0x3); + + err = pci_read_config_dword(pvt->addr_f1_ctl, + K8_DRAM_LIMIT_LOW + off, &low); + if (err) + debugf0("Reading K8_DRAM_LIMIT_LOW failed\n"); + + /* + * Extract parts into separate data entries. Limit is the HIGHEST memory + * location of the region, so lower 24 bits need to be all ones + */ + pvt->dram_limit[dram] = (((u64) low & 0xFFFF0000) << 8) | 0x00FFFFFF; + pvt->dram_IntlvSel[dram] = (low >> 8) & 0x7; + pvt->dram_DstNode[dram] = (low & 0x7); +} + +static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci, + struct amd64_error_info_regs *info, + u64 SystemAddress) +{ + struct mem_ctl_info *src_mci; + unsigned short syndrome; + int channel, csrow; + u32 page, offset; + + /* Extract the syndrome parts and form a 16-bit syndrome */ + syndrome = EXTRACT_HIGH_SYNDROME(info->nbsl) << 8; + syndrome |= EXTRACT_LOW_SYNDROME(info->nbsh); + + /* CHIPKILL enabled */ + if (info->nbcfg & K8_NBCFG_CHIPKILL) { + channel = get_channel_from_ecc_syndrome(syndrome); + if (channel < 0) { + /* + * Syndrome didn't map, so we don't know which of the + * 2 DIMMs is in error. So we need to ID 'both' of them + * as suspect. + */ + amd64_mc_printk(mci, KERN_WARNING, + "unknown syndrome 0x%x - possible error " + "reporting race\n", syndrome); + edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR); + return; + } + } else { + /* + * non-chipkill ecc mode + * + * The k8 documentation is unclear about how to determine the + * channel number when using non-chipkill memory. This method + * was obtained from email communication with someone at AMD. + * (Wish the email was placed in this comment - norsk) + */ + channel = ((SystemAddress & BIT(3)) != 0); + } + + /* + * Find out which node the error address belongs to. This may be + * different from the node that detected the error. + */ + src_mci = find_mc_by_sys_addr(mci, SystemAddress); + if (src_mci) { + amd64_mc_printk(mci, KERN_ERR, + "failed to map error address 0x%lx to a node\n", + (unsigned long)SystemAddress); + edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR); + return; + } + + /* Now map the SystemAddress to a CSROW */ + csrow = sys_addr_to_csrow(src_mci, SystemAddress); + if (csrow < 0) { + edac_mc_handle_ce_no_info(src_mci, EDAC_MOD_STR); + } else { + error_address_to_page_and_offset(SystemAddress, &page, &offset); + + edac_mc_handle_ce(src_mci, page, offset, syndrome, csrow, + channel, EDAC_MOD_STR); + } +} + +/* + * determrine the number of PAGES in for this DIMM's size based on its DRAM + * Address Mapping. + * + * First step is to calc the number of bits to shift a value of 1 left to + * indicate show many pages. Start with the DBAM value as the starting bits, + * then proceed to adjust those shift bits, based on CPU rev and the table. + * See BKDG on the DBAM + */ +static int k8_dbam_map_to_pages(struct amd64_pvt *pvt, int dram_map) +{ + int nr_pages; + + if (pvt->ext_model >= OPTERON_CPU_REV_F) { + nr_pages = 1 << (revf_quad_ddr2_shift[dram_map] - PAGE_SHIFT); + } else { + /* + * RevE and less section; this line is tricky. It collapses the + * table used by RevD and later to one that matches revisions CG + * and earlier. + */ + dram_map -= (pvt->ext_model >= OPTERON_CPU_REV_D) ? + (dram_map > 8 ? 4 : (dram_map > 5 ? + 3 : (dram_map > 2 ? 1 : 0))) : 0; + + /* 25 shift is 32MiB minimum DIMM size in RevE and prior */ + nr_pages = 1 << (dram_map + 25 - PAGE_SHIFT); + } + + return nr_pages; +} + +/* + * Get the number of DCT channels in use. + * + * Return: + * number of Memory Channels in operation + * Pass back: + * contents of the DCL0_LOW register + */ +static int f10_early_channel_count(struct amd64_pvt *pvt) +{ + int err = 0, channels = 0; + u32 dbam; + + err = pci_read_config_dword(pvt->dram_f2_ctl, F10_DCLR_0, &pvt->dclr0); + if (err) + goto err_reg; + + err = pci_read_config_dword(pvt->dram_f2_ctl, F10_DCLR_1, &pvt->dclr1); + if (err) + goto err_reg; + + /* If we are in 128 bit mode, then we are using 2 channels */ + if (pvt->dclr0 & F10_WIDTH_128) { + debugf0("Data WIDTH is 128 bits - 2 channels\n"); + channels = 2; + return channels; + } + + /* + * Need to check if in UN-ganged mode: In such, there are 2 channels, + * but they are NOT in 128 bit mode and thus the above 'dcl0' status bit + * will be OFF. + * + * Need to check DCT0[0] and DCT1[0] to see if only one of them has + * their CSEnable bit on. If so, then SINGLE DIMM case. + */ + debugf0("Data WIDTH is NOT 128 bits - need more decoding\n"); + + /* + * Check DRAM Bank Address Mapping values for each DIMM to see if there + * is more than just one DIMM present in unganged mode. Need to check + * both controllers since DIMMs can be placed in either one. + */ + channels = 0; + err = pci_read_config_dword(pvt->dram_f2_ctl, DBAM0, &dbam); + if (err) + goto err_reg; + + if (DBAM_DIMM(0, dbam) > 0) + channels++; + if (DBAM_DIMM(1, dbam) > 0) + channels++; + if (DBAM_DIMM(2, dbam) > 0) + channels++; + if (DBAM_DIMM(3, dbam) > 0) + channels++; + + /* If more than 2 DIMMs are present, then we have 2 channels */ + if (channels > 2) + channels = 2; + else if (channels == 0) { + /* No DIMMs on DCT0, so look at DCT1 */ + err = pci_read_config_dword(pvt->dram_f2_ctl, DBAM1, &dbam); + if (err) + goto err_reg; + + if (DBAM_DIMM(0, dbam) > 0) + channels++; + if (DBAM_DIMM(1, dbam) > 0) + channels++; + if (DBAM_DIMM(2, dbam) > 0) + channels++; + if (DBAM_DIMM(3, dbam) > 0) + channels++; + + if (channels > 2) + channels = 2; + } + + /* If we found ALL 0 values, then assume just ONE DIMM-ONE Channel */ + if (channels == 0) + channels = 1; + + debugf0("DIMM count= %d\n", channels); + + return channels; + +err_reg: + return -1; + +} + +static int f10_dbam_map_to_pages(struct amd64_pvt *pvt, int dram_map) +{ + return 1 << (revf_quad_ddr2_shift[dram_map] - PAGE_SHIFT); +} + +/* Enable extended configuration access via 0xCF8 feature */ +static void amd64_setup(struct amd64_pvt *pvt) +{ + u32 reg; + + pci_read_config_dword(pvt->misc_f3_ctl, F10_NB_CFG_HIGH, ®); + + pvt->flags.cf8_extcfg = !!(reg & F10_NB_CFG_LOW_ENABLE_EXT_CFG); + reg |= F10_NB_CFG_LOW_ENABLE_EXT_CFG; + pci_write_config_dword(pvt->misc_f3_ctl, F10_NB_CFG_HIGH, reg); +} + +/* Restore the extended configuration access via 0xCF8 feature */ +static void amd64_teardown(struct amd64_pvt *pvt) +{ + u32 reg; + + pci_read_config_dword(pvt->misc_f3_ctl, F10_NB_CFG_HIGH, ®); + + reg &= ~F10_NB_CFG_LOW_ENABLE_EXT_CFG; + if (pvt->flags.cf8_extcfg) + reg |= F10_NB_CFG_LOW_ENABLE_EXT_CFG; + pci_write_config_dword(pvt->misc_f3_ctl, F10_NB_CFG_HIGH, reg); +} + +static u64 f10_get_error_address(struct mem_ctl_info *mci, + struct amd64_error_info_regs *info) +{ + return (((u64) (info->nbeah & 0xffff)) << 32) + + (info->nbeal & ~0x01); +} + +/* + * Read the Base and Limit registers for F10 based Memory controllers. Extract + * fields from the 'raw' reg into separate data fields. + * + * Isolates: BASE, LIMIT, IntlvEn, IntlvSel, RW_EN. + */ +static void f10_read_dram_base_limit(struct amd64_pvt *pvt, int dram) +{ + u32 high_offset, low_offset, high_base, low_base, high_limit, low_limit; + + low_offset = K8_DRAM_BASE_LOW + (dram << 3); + high_offset = F10_DRAM_BASE_HIGH + (dram << 3); + + /* read the 'raw' DRAM BASE Address register */ + pci_read_config_dword(pvt->addr_f1_ctl, low_offset, &low_base); + + /* Read from the ECS data register */ + pci_read_config_dword(pvt->addr_f1_ctl, high_offset, &high_base); + + /* Extract parts into separate data entries */ + pvt->dram_rw_en[dram] = (low_base & 0x3); + + if (pvt->dram_rw_en[dram] == 0) + return; + + pvt->dram_IntlvEn[dram] = (low_base >> 8) & 0x7; + + pvt->dram_base[dram] = (((((u64) high_base & 0x000000FF) << 32) | + ((u64) low_base & 0xFFFF0000))) << 8; + + low_offset = K8_DRAM_LIMIT_LOW + (dram << 3); + high_offset = F10_DRAM_LIMIT_HIGH + (dram << 3); + + /* read the 'raw' LIMIT registers */ + pci_read_config_dword(pvt->addr_f1_ctl, low_offset, &low_limit); + + /* Read from the ECS data register for the HIGH portion */ + pci_read_config_dword(pvt->addr_f1_ctl, high_offset, &high_limit); + + debugf0(" HW Regs: BASE=0x%08x-%08x LIMIT= 0x%08x-%08x\n", + high_base, low_base, high_limit, low_limit); + + pvt->dram_DstNode[dram] = (low_limit & 0x7); + pvt->dram_IntlvSel[dram] = (low_limit >> 8) & 0x7; + + /* + * Extract address values and form a LIMIT address. Limit is the HIGHEST + * memory location of the region, so low 24 bits need to be all ones. + */ + low_limit |= 0x0000FFFF; + pvt->dram_limit[dram] = + ((((u64) high_limit << 32) + (u64) low_limit) << 8) | (0xFF); +} + +static void f10_read_dram_ctl_register(struct amd64_pvt *pvt) +{ + int err = 0; + + err = pci_read_config_dword(pvt->dram_f2_ctl, F10_DCTL_SEL_LOW, + &pvt->dram_ctl_select_low); + if (err) { + debugf0("Reading F10_DCTL_SEL_LOW failed\n"); + } else { + debugf0("DRAM_DCTL_SEL_LOW=0x%x DctSelBaseAddr=0x%x\n", + pvt->dram_ctl_select_low, dct_sel_baseaddr(pvt)); + + debugf0(" DRAM DCTs are=%s DRAM Is=%s DRAM-Ctl-" + "sel-hi-range=%s\n", + (dct_ganging_enabled(pvt) ? "GANGED" : "NOT GANGED"), + (dct_dram_enabled(pvt) ? "Enabled" : "Disabled"), + (dct_high_range_enabled(pvt) ? "Enabled" : "Disabled")); + + debugf0(" DctDatIntLv=%s MemCleared=%s DctSelIntLvAddr=0x%x\n", + (dct_data_intlv_enabled(pvt) ? "Enabled" : "Disabled"), + (dct_memory_cleared(pvt) ? "True " : "False "), + dct_sel_interleave_addr(pvt)); + } + + err = pci_read_config_dword(pvt->dram_f2_ctl, F10_DCTL_SEL_HIGH, + &pvt->dram_ctl_select_high); + if (err) + debugf0("Reading F10_DCTL_SEL_HIGH failed\n"); +} + +/* + * determine channel based on the interleaving mode: F10h BKDG, 2.8.9 Memory + * Interleaving Modes. + */ +static u32 f10_determine_channel(struct amd64_pvt *pvt, u64 sys_addr, + int hi_range_sel, u32 intlv_en) +{ + u32 cs, temp, dct_sel_high = (pvt->dram_ctl_select_low >> 1) & 1; + + if (dct_ganging_enabled(pvt)) + cs = 0; + else if (hi_range_sel) + cs = dct_sel_high; + else if (dct_interleave_enabled(pvt)) { + /* + * see F2x110[DctSelIntLvAddr] - channel interleave mode + */ + if (dct_sel_interleave_addr(pvt) == 0) + cs = sys_addr >> 6 & 1; + else if ((dct_sel_interleave_addr(pvt) >> 1) & 1) { + temp = hweight_long((u32) ((sys_addr >> 16) & 0x1F)) % 2; + + if (dct_sel_interleave_addr(pvt) & 1) + cs = (sys_addr >> 9 & 1) ^ temp; + else + cs = (sys_addr >> 6 & 1) ^ temp; + } else if (intlv_en & 4) + cs = sys_addr >> 15 & 1; + else if (intlv_en & 2) + cs = sys_addr >> 14 & 1; + else if (intlv_en & 1) + cs = sys_addr >> 13 & 1; + else + cs = sys_addr >> 12 & 1; + } else if (dct_high_range_enabled(pvt) && !dct_ganging_enabled(pvt)) + cs = ~dct_sel_high & 1; + else + cs = 0; + + return cs; +} + +static inline u32 f10_map_intlv_en_to_shift(u32 intlv_en) +{ + if (intlv_en == 1) + return 1; + else if (intlv_en == 3) + return 2; + else if (intlv_en == 7) + return 3; + + return 0; +} + +/* See F10h BKDG, 2.8.10.2 DctSelBaseOffset Programming */ +static inline u64 f10_get_base_addr_offset(u64 sys_addr, int hi_range_sel, + u32 dct_sel_base_addr, + u64 dct_sel_base_off, + u32 hole_valid, u32 hole_off, + u64 dram_base) +{ + u64 chan_off; + + if (hi_range_sel) { + if (!(dct_sel_base_addr & 0xFFFFF800) && + hole_valid && (sys_addr >= 0x100000000ULL)) + chan_off = hole_off << 16; + else + chan_off = dct_sel_base_off; + } else { + if (hole_valid && (sys_addr >= 0x100000000ULL)) + chan_off = hole_off << 16; + else + chan_off = dram_base & 0xFFFFF8000000ULL; + } + + return (sys_addr & 0x0000FFFFFFFFFFC0ULL) - + (chan_off & 0x0000FFFFFF800000ULL); +} + +/* Hack for the time being - Can we get this from BIOS?? */ +#define CH0SPARE_RANK 0 +#define CH1SPARE_RANK 1 + +/* + * checks if the csrow passed in is marked as SPARED, if so returns the new + * spare row + */ +static inline int f10_process_possible_spare(int csrow, + u32 cs, struct amd64_pvt *pvt) +{ + u32 swap_done; + u32 bad_dram_cs; + + /* Depending on channel, isolate respective SPARING info */ + if (cs) { + swap_done = F10_ONLINE_SPARE_SWAPDONE1(pvt->online_spare); + bad_dram_cs = F10_ONLINE_SPARE_BADDRAM_CS1(pvt->online_spare); + if (swap_done && (csrow == bad_dram_cs)) + csrow = CH1SPARE_RANK; + } else { + swap_done = F10_ONLINE_SPARE_SWAPDONE0(pvt->online_spare); + bad_dram_cs = F10_ONLINE_SPARE_BADDRAM_CS0(pvt->online_spare); + if (swap_done && (csrow == bad_dram_cs)) + csrow = CH0SPARE_RANK; + } + return csrow; +} + +/* + * Iterate over the DRAM DCT "base" and "mask" registers looking for a + * SystemAddr match on the specified 'ChannelSelect' and 'NodeID' + * + * Return: + * -EINVAL: NOT FOUND + * 0..csrow = Chip-Select Row + */ +static int f10_lookup_addr_in_dct(u32 in_addr, u32 nid, u32 cs) +{ + struct mem_ctl_info *mci; + struct amd64_pvt *pvt; + u32 cs_base, cs_mask; + int cs_found = -EINVAL; + int csrow; + + mci = mci_lookup[nid]; + if (!mci) + return cs_found; + + pvt = mci->pvt_info; + + debugf1("InputAddr=0x%x channelselect=%d\n", in_addr, cs); + + for (csrow = 0; csrow < CHIPSELECT_COUNT; csrow++) { + + cs_base = amd64_get_dct_base(pvt, cs, csrow); + if (!(cs_base & K8_DCSB_CS_ENABLE)) + continue; + + /* + * We have an ENABLED CSROW, Isolate just the MASK bits of the + * target: [28:19] and [13:5], which map to [36:27] and [21:13] + * of the actual address. + */ + cs_base &= REV_F_F1Xh_DCSB_BASE_BITS; + + /* + * Get the DCT Mask, and ENABLE the reserved bits: [18:16] and + * [4:0] to become ON. Then mask off bits [28:0] ([36:8]) + */ + cs_mask = amd64_get_dct_mask(pvt, cs, csrow); + + debugf1(" CSROW=%d CSBase=0x%x RAW CSMask=0x%x\n", + csrow, cs_base, cs_mask); + + cs_mask = (cs_mask | 0x0007C01F) & 0x1FFFFFFF; + + debugf1(" Final CSMask=0x%x\n", cs_mask); + debugf1(" (InputAddr & ~CSMask)=0x%x " + "(CSBase & ~CSMask)=0x%x\n", + (in_addr & ~cs_mask), (cs_base & ~cs_mask)); + + if ((in_addr & ~cs_mask) == (cs_base & ~cs_mask)) { + cs_found = f10_process_possible_spare(csrow, cs, pvt); + + debugf1(" MATCH csrow=%d\n", cs_found); + break; + } + } + return cs_found; +} + +/* For a given @dram_range, check if @sys_addr falls within it. */ +static int f10_match_to_this_node(struct amd64_pvt *pvt, int dram_range, + u64 sys_addr, int *nid, int *chan_sel) +{ + int node_id, cs_found = -EINVAL, high_range = 0; + u32 intlv_en, intlv_sel, intlv_shift, hole_off; + u32 hole_valid, tmp, dct_sel_base, channel; + u64 dram_base, chan_addr, dct_sel_base_off; + + dram_base = pvt->dram_base[dram_range]; + intlv_en = pvt->dram_IntlvEn[dram_range]; + + node_id = pvt->dram_DstNode[dram_range]; + intlv_sel = pvt->dram_IntlvSel[dram_range]; + + debugf1("(dram=%d) Base=0x%llx SystemAddr= 0x%llx Limit=0x%llx\n", + dram_range, dram_base, sys_addr, pvt->dram_limit[dram_range]); + + /* + * This assumes that one node's DHAR is the same as all the other + * nodes' DHAR. + */ + hole_off = (pvt->dhar & 0x0000FF80); + hole_valid = (pvt->dhar & 0x1); + dct_sel_base_off = (pvt->dram_ctl_select_high & 0xFFFFFC00) << 16; + + debugf1(" HoleOffset=0x%x HoleValid=0x%x IntlvSel=0x%x\n", + hole_off, hole_valid, intlv_sel); + + if (intlv_en || + (intlv_sel != ((sys_addr >> 12) & intlv_en))) + return -EINVAL; + + dct_sel_base = dct_sel_baseaddr(pvt); + + /* + * check whether addresses >= DctSelBaseAddr[47:27] are to be used to + * select between DCT0 and DCT1. + */ + if (dct_high_range_enabled(pvt) && + !dct_ganging_enabled(pvt) && + ((sys_addr >> 27) >= (dct_sel_base >> 11))) + high_range = 1; + + channel = f10_determine_channel(pvt, sys_addr, high_range, intlv_en); + + chan_addr = f10_get_base_addr_offset(sys_addr, high_range, dct_sel_base, + dct_sel_base_off, hole_valid, + hole_off, dram_base); + + intlv_shift = f10_map_intlv_en_to_shift(intlv_en); + + /* remove Node ID (in case of memory interleaving) */ + tmp = chan_addr & 0xFC0; + + chan_addr = ((chan_addr >> intlv_shift) & 0xFFFFFFFFF000ULL) | tmp; + + /* remove channel interleave and hash */ + if (dct_interleave_enabled(pvt) && + !dct_high_range_enabled(pvt) && + !dct_ganging_enabled(pvt)) { + if (dct_sel_interleave_addr(pvt) != 1) + chan_addr = (chan_addr >> 1) & 0xFFFFFFFFFFFFFFC0ULL; + else { + tmp = chan_addr & 0xFC0; + chan_addr = ((chan_addr & 0xFFFFFFFFFFFFC000ULL) >> 1) + | tmp; + } + } + + debugf1(" (ChannelAddrLong=0x%llx) >> 8 becomes InputAddr=0x%x\n", + chan_addr, (u32)(chan_addr >> 8)); + + cs_found = f10_lookup_addr_in_dct(chan_addr >> 8, node_id, channel); + + if (cs_found >= 0) { + *nid = node_id; + *chan_sel = channel; + } + return cs_found; +} + +static int f10_translate_sysaddr_to_cs(struct amd64_pvt *pvt, u64 sys_addr, + int *node, int *chan_sel) +{ + int dram_range, cs_found = -EINVAL; + u64 dram_base, dram_limit; + + for (dram_range = 0; dram_range < DRAM_REG_COUNT; dram_range++) { + + if (!pvt->dram_rw_en[dram_range]) + continue; + + dram_base = pvt->dram_base[dram_range]; + dram_limit = pvt->dram_limit[dram_range]; + + if ((dram_base <= sys_addr) && (sys_addr <= dram_limit)) { + + cs_found = f10_match_to_this_node(pvt, dram_range, + sys_addr, node, + chan_sel); + if (cs_found >= 0) + break; + } + } + return cs_found; +} + +/* + * This the F10h reference code from AMD to map a @sys_addr to NodeID, + * CSROW, Channel. + * + * The @sys_addr is usually an error address received from the hardware. + */ +static void f10_map_sysaddr_to_csrow(struct mem_ctl_info *mci, + struct amd64_error_info_regs *info, + u64 sys_addr) +{ + struct amd64_pvt *pvt = mci->pvt_info; + u32 page, offset; + unsigned short syndrome; + int nid, csrow, chan = 0; + + csrow = f10_translate_sysaddr_to_cs(pvt, sys_addr, &nid, &chan); + + if (csrow >= 0) { + error_address_to_page_and_offset(sys_addr, &page, &offset); + + syndrome = EXTRACT_HIGH_SYNDROME(info->nbsl) << 8; + syndrome |= EXTRACT_LOW_SYNDROME(info->nbsh); + + /* + * Is CHIPKILL on? If so, then we can attempt to use the + * syndrome to isolate which channel the error was on. + */ + if (pvt->nbcfg & K8_NBCFG_CHIPKILL) + chan = get_channel_from_ecc_syndrome(syndrome); + + if (chan >= 0) { + edac_mc_handle_ce(mci, page, offset, syndrome, + csrow, chan, EDAC_MOD_STR); + } else { + /* + * Channel unknown, report all channels on this + * CSROW as failed. + */ + for (chan = 0; chan < mci->csrows[csrow].nr_channels; + chan++) { + edac_mc_handle_ce(mci, page, offset, + syndrome, + csrow, chan, + EDAC_MOD_STR); + } + } + + } else { + edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR); + } +} + +/* + * Input (@index) is the DBAM DIMM value (1 of 4) used as an index into a shift + * table (revf_quad_ddr2_shift) which starts at 128MB DIMM size. Index of 0 + * indicates an empty DIMM slot, as reported by Hardware on empty slots. + * + * Normalize to 128MB by subracting 27 bit shift. + */ +static int map_dbam_to_csrow_size(int index) +{ + int mega_bytes = 0; + + if (index > 0 && index <= DBAM_MAX_VALUE) + mega_bytes = ((128 << (revf_quad_ddr2_shift[index]-27))); + + return mega_bytes; +} + +/* + * debug routine to display the memory sizes of a DIMM (ganged or not) and it + * CSROWs as well + */ +static void f10_debug_display_dimm_sizes(int ctrl, struct amd64_pvt *pvt, + int ganged) +{ + int dimm, size0, size1; + u32 dbam; + u32 *dcsb; + + debugf1(" dbam%d: 0x%8.08x CSROW is %s\n", ctrl, + ctrl ? pvt->dbam1 : pvt->dbam0, + ganged ? "GANGED - dbam1 not used" : "NON-GANGED"); + + dbam = ctrl ? pvt->dbam1 : pvt->dbam0; + dcsb = ctrl ? pvt->dcsb1 : pvt->dcsb0; + + /* Dump memory sizes for DIMM and its CSROWs */ + for (dimm = 0; dimm < 4; dimm++) { + + size0 = 0; + if (dcsb[dimm*2] & K8_DCSB_CS_ENABLE) + size0 = map_dbam_to_csrow_size(DBAM_DIMM(dimm, dbam)); + + size1 = 0; + if (dcsb[dimm*2 + 1] & K8_DCSB_CS_ENABLE) + size1 = map_dbam_to_csrow_size(DBAM_DIMM(dimm, dbam)); + + debugf1(" CTRL-%d DIMM-%d=%5dMB CSROW-%d=%5dMB " + "CSROW-%d=%5dMB\n", + ctrl, + dimm, + size0 + size1, + dimm * 2, + size0, + dimm * 2 + 1, + size1); + } +} + +/* + * Very early hardware probe on pci_probe thread to determine if this module + * supports the hardware. + * + * Return: + * 0 for OK + * 1 for error + */ +static int f10_probe_valid_hardware(struct amd64_pvt *pvt) +{ + int ret = 0; + + /* + * If we are on a DDR3 machine, we don't know yet if + * we support that properly at this time + */ + if ((pvt->dchr0 & F10_DCHR_Ddr3Mode) || + (pvt->dchr1 & F10_DCHR_Ddr3Mode)) { + + amd64_printk(KERN_WARNING, + "%s() This machine is running with DDR3 memory. " + "This is not currently supported. " + "DCHR0=0x%x DCHR1=0x%x\n", + __func__, pvt->dchr0, pvt->dchr1); + + amd64_printk(KERN_WARNING, + " Contact '%s' module MAINTAINER to help add" + " support.\n", + EDAC_MOD_STR); + + ret = 1; + + } + return ret; +} + +/* + * There currently are 3 types type of MC devices for AMD Athlon/Opterons + * (as per PCI DEVICE_IDs): + * + * Family K8: That is the Athlon64 and Opteron CPUs. They all have the same PCI + * DEVICE ID, even though there is differences between the different Revisions + * (CG,D,E,F). + * + * Family F10h and F11h. + * + */ +static struct amd64_family_type amd64_family_types[] = { + [K8_CPUS] = { + .ctl_name = "RevF", + .addr_f1_ctl = PCI_DEVICE_ID_AMD_K8_NB_ADDRMAP, + .misc_f3_ctl = PCI_DEVICE_ID_AMD_K8_NB_MISC, + .ops = { + .early_channel_count = k8_early_channel_count, + .get_error_address = k8_get_error_address, + .read_dram_base_limit = k8_read_dram_base_limit, + .map_sysaddr_to_csrow = k8_map_sysaddr_to_csrow, + .dbam_map_to_pages = k8_dbam_map_to_pages, + } + }, + [F10_CPUS] = { + .ctl_name = "Family 10h", + .addr_f1_ctl = PCI_DEVICE_ID_AMD_10H_NB_MAP, + .misc_f3_ctl = PCI_DEVICE_ID_AMD_10H_NB_MISC, + .ops = { + .probe_valid_hardware = f10_probe_valid_hardware, + .early_channel_count = f10_early_channel_count, + .get_error_address = f10_get_error_address, + .read_dram_base_limit = f10_read_dram_base_limit, + .read_dram_ctl_register = f10_read_dram_ctl_register, + .map_sysaddr_to_csrow = f10_map_sysaddr_to_csrow, + .dbam_map_to_pages = f10_dbam_map_to_pages, + } + }, + [F11_CPUS] = { + .ctl_name = "Family 11h", + .addr_f1_ctl = PCI_DEVICE_ID_AMD_11H_NB_MAP, + .misc_f3_ctl = PCI_DEVICE_ID_AMD_11H_NB_MISC, + .ops = { + .probe_valid_hardware = f10_probe_valid_hardware, + .early_channel_count = f10_early_channel_count, + .get_error_address = f10_get_error_address, + .read_dram_base_limit = f10_read_dram_base_limit, + .read_dram_ctl_register = f10_read_dram_ctl_register, + .map_sysaddr_to_csrow = f10_map_sysaddr_to_csrow, + .dbam_map_to_pages = f10_dbam_map_to_pages, + } + }, +}; + +static struct pci_dev *pci_get_related_function(unsigned int vendor, + unsigned int device, + struct pci_dev *related) +{ + struct pci_dev *dev = NULL; + + dev = pci_get_device(vendor, device, dev); + while (dev) { + if ((dev->bus->number == related->bus->number) && + (PCI_SLOT(dev->devfn) == PCI_SLOT(related->devfn))) + break; + dev = pci_get_device(vendor, device, dev); + } + + return dev; +} + +/* + * syndrome mapping table for ECC ChipKill devices + * + * The comment in each row is the token (nibble) number that is in error. + * The least significant nibble of the syndrome is the mask for the bits + * that are in error (need to be toggled) for the particular nibble. + * + * Each row contains 16 entries. + * The first entry (0th) is the channel number for that row of syndromes. + * The remaining 15 entries are the syndromes for the respective Error + * bit mask index. + * + * 1st index entry is 0x0001 mask, indicating that the rightmost bit is the + * bit in error. + * The 2nd index entry is 0x0010 that the second bit is damaged. + * The 3rd index entry is 0x0011 indicating that the rightmost 2 bits + * are damaged. + * Thus so on until index 15, 0x1111, whose entry has the syndrome + * indicating that all 4 bits are damaged. + * + * A search is performed on this table looking for a given syndrome. + * + * See the AMD documentation for ECC syndromes. This ECC table is valid + * across all the versions of the AMD64 processors. + * + * A fast lookup is to use the LAST four bits of the 16-bit syndrome as a + * COLUMN index, then search all ROWS of that column, looking for a match + * with the input syndrome. The ROW value will be the token number. + * + * The 0'th entry on that row, can be returned as the CHANNEL (0 or 1) of this + * error. + */ +#define NUMBER_ECC_ROWS 36 +static const unsigned short ecc_chipkill_syndromes[NUMBER_ECC_ROWS][16] = { + /* Channel 0 syndromes */ + {/*0*/ 0, 0xe821, 0x7c32, 0x9413, 0xbb44, 0x5365, 0xc776, 0x2f57, + 0xdd88, 0x35a9, 0xa1ba, 0x499b, 0x66cc, 0x8eed, 0x1afe, 0xf2df }, + {/*1*/ 0, 0x5d31, 0xa612, 0xfb23, 0x9584, 0xc8b5, 0x3396, 0x6ea7, + 0xeac8, 0xb7f9, 0x4cda, 0x11eb, 0x7f4c, 0x227d, 0xd95e, 0x846f }, + {/*2*/ 0, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f }, + {/*3*/ 0, 0x2021, 0x3032, 0x1013, 0x4044, 0x6065, 0x7076, 0x5057, + 0x8088, 0xa0a9, 0xb0ba, 0x909b, 0xc0cc, 0xe0ed, 0xf0fe, 0xd0df }, + {/*4*/ 0, 0x5041, 0xa082, 0xf0c3, 0x9054, 0xc015, 0x30d6, 0x6097, + 0xe0a8, 0xb0e9, 0x402a, 0x106b, 0x70fc, 0x20bd, 0xd07e, 0x803f }, + {/*5*/ 0, 0xbe21, 0xd732, 0x6913, 0x2144, 0x9f65, 0xf676, 0x4857, + 0x3288, 0x8ca9, 0xe5ba, 0x5b9b, 0x13cc, 0xaded, 0xc4fe, 0x7adf }, + {/*6*/ 0, 0x4951, 0x8ea2, 0xc7f3, 0x5394, 0x1ac5, 0xdd36, 0x9467, + 0xa1e8, 0xe8b9, 0x2f4a, 0x661b, 0xf27c, 0xbb2d, 0x7cde, 0x358f }, + {/*7*/ 0, 0x74e1, 0x9872, 0xec93, 0xd6b4, 0xa255, 0x4ec6, 0x3a27, + 0x6bd8, 0x1f39, 0xf3aa, 0x874b, 0xbd6c, 0xc98d, 0x251e, 0x51ff }, + {/*8*/ 0, 0x15c1, 0x2a42, 0x3f83, 0xcef4, 0xdb35, 0xe4b6, 0xf177, + 0x4758, 0x5299, 0x6d1a, 0x78db, 0x89ac, 0x9c6d, 0xa3ee, 0xb62f }, + {/*9*/ 0, 0x3d01, 0x1602, 0x2b03, 0x8504, 0xb805, 0x9306, 0xae07, + 0xca08, 0xf709, 0xdc0a, 0xe10b, 0x4f0c, 0x720d, 0x590e, 0x640f }, + {/*a*/ 0, 0x9801, 0xec02, 0x7403, 0x6b04, 0xf305, 0x8706, 0x1f07, + 0xbd08, 0x2509, 0x510a, 0xc90b, 0xd60c, 0x4e0d, 0x3a0e, 0xa20f }, + {/*b*/ 0, 0xd131, 0x6212, 0xb323, 0x3884, 0xe9b5, 0x5a96, 0x8ba7, + 0x1cc8, 0xcdf9, 0x7eda, 0xafeb, 0x244c, 0xf57d, 0x465e, 0x976f }, + {/*c*/ 0, 0xe1d1, 0x7262, 0x93b3, 0xb834, 0x59e5, 0xca56, 0x2b87, + 0xdc18, 0x3dc9, 0xae7a, 0x4fab, 0x542c, 0x85fd, 0x164e, 0xf79f }, + {/*d*/ 0, 0x6051, 0xb0a2, 0xd0f3, 0x1094, 0x70c5, 0xa036, 0xc067, + 0x20e8, 0x40b9, 0x904a, 0x601b, 0x307c, 0x502d, 0x80de, 0xe08f }, + {/*e*/ 0, 0xa4c1, 0xf842, 0x5c83, 0xe6f4, 0x4235, 0x1eb6, 0xba77, + 0x7b58, 0xdf99, 0x831a, 0x27db, 0x9dac, 0x396d, 0x65ee, 0xc12f }, + {/*f*/ 0, 0x11c1, 0x2242, 0x3383, 0xc8f4, 0xd935, 0xeab6, 0xfb77, + 0x4c58, 0x5d99, 0x6e1a, 0x7fdb, 0x84ac, 0x956d, 0xa6ee, 0xb72f }, + + /* Channel 1 syndromes */ + {/*10*/ 1, 0x45d1, 0x8a62, 0xcfb3, 0x5e34, 0x1be5, 0xd456, 0x9187, + 0xa718, 0xe2c9, 0x2d7a, 0x68ab, 0xf92c, 0xbcfd, 0x734e, 0x369f }, + {/*11*/ 1, 0x63e1, 0xb172, 0xd293, 0x14b4, 0x7755, 0xa5c6, 0xc627, + 0x28d8, 0x4b39, 0x99aa, 0xfa4b, 0x3c6c, 0x5f8d, 0x8d1e, 0xeeff }, + {/*12*/ 1, 0xb741, 0xd982, 0x6ec3, 0x2254, 0x9515, 0xfbd6, 0x4c97, + 0x33a8, 0x84e9, 0xea2a, 0x5d6b, 0x11fc, 0xa6bd, 0xc87e, 0x7f3f }, + {/*13*/ 1, 0xdd41, 0x6682, 0xbbc3, 0x3554, 0xe815, 0x53d6, 0xce97, + 0x1aa8, 0xc7e9, 0x7c2a, 0xa1fb, 0x2ffc, 0xf2bd, 0x497e, 0x943f }, + {/*14*/ 1, 0x2bd1, 0x3d62, 0x16b3, 0x4f34, 0x64e5, 0x7256, 0x5987, + 0x8518, 0xaec9, 0xb87a, 0x93ab, 0xca2c, 0xe1fd, 0xf74e, 0xdc9f }, + {/*15*/ 1, 0x83c1, 0xc142, 0x4283, 0xa4f4, 0x2735, 0x65b6, 0xe677, + 0xf858, 0x7b99, 0x391a, 0xbadb, 0x5cac, 0xdf6d, 0x9dee, 0x1e2f }, + {/*16*/ 1, 0x8fd1, 0xc562, 0x4ab3, 0xa934, 0x26e5, 0x6c56, 0xe387, + 0xfe18, 0x71c9, 0x3b7a, 0xb4ab, 0x572c, 0xd8fd, 0x924e, 0x1d9f }, + {/*17*/ 1, 0x4791, 0x89e2, 0xce73, 0x5264, 0x15f5, 0xdb86, 0x9c17, + 0xa3b8, 0xe429, 0x2a5a, 0x6dcb, 0xf1dc, 0xb64d, 0x783e, 0x3faf }, + {/*18*/ 1, 0x5781, 0xa9c2, 0xfe43, 0x92a4, 0xc525, 0x3b66, 0x6ce7, + 0xe3f8, 0xb479, 0x4a3a, 0x1dbb, 0x715c, 0x26dd, 0xd89e, 0x8f1f }, + {/*19*/ 1, 0xbf41, 0xd582, 0x6ac3, 0x2954, 0x9615, 0xfcd6, 0x4397, + 0x3ea8, 0x81e9, 0xeb2a, 0x546b, 0x17fc, 0xa8bd, 0xc27e, 0x7d3f }, + {/*1a*/ 1, 0x9891, 0xe1e2, 0x7273, 0x6464, 0xf7f5, 0x8586, 0x1617, + 0xb8b8, 0x2b29, 0x595a, 0xcacb, 0xdcdc, 0x4f4d, 0x3d3e, 0xaeaf }, + {/*1b*/ 1, 0xcce1, 0x4472, 0x8893, 0xfdb4, 0x3f55, 0xb9c6, 0x7527, + 0x56d8, 0x9a39, 0x12aa, 0xde4b, 0xab6c, 0x678d, 0xef1e, 0x23ff }, + {/*1c*/ 1, 0xa761, 0xf9b2, 0x5ed3, 0xe214, 0x4575, 0x1ba6, 0xbcc7, + 0x7328, 0xd449, 0x8a9a, 0x2dfb, 0x913c, 0x365d, 0x688e, 0xcfef }, + {/*1d*/ 1, 0xff61, 0x55b2, 0xaad3, 0x7914, 0x8675, 0x2ca6, 0xd3c7, + 0x9e28, 0x6149, 0xcb9a, 0x34fb, 0xe73c, 0x185d, 0xb28e, 0x4def }, + {/*1e*/ 1, 0x5451, 0xa8a2, 0xfcf3, 0x9694, 0xc2c5, 0x3e36, 0x6a67, + 0xebe8, 0xbfb9, 0x434a, 0x171b, 0x7d7c, 0x292d, 0xd5de, 0x818f }, + {/*1f*/ 1, 0x6fc1, 0xb542, 0xda83, 0x19f4, 0x7635, 0xacb6, 0xc377, + 0x2e58, 0x4199, 0x9b1a, 0xf4db, 0x37ac, 0x586d, 0x82ee, 0xed2f }, + + /* ECC bits are also in the set of tokens and they too can go bad + * first 2 cover channel 0, while the second 2 cover channel 1 + */ + {/*20*/ 0, 0xbe01, 0xd702, 0x6903, 0x2104, 0x9f05, 0xf606, 0x4807, + 0x3208, 0x8c09, 0xe50a, 0x5b0b, 0x130c, 0xad0d, 0xc40e, 0x7a0f }, + {/*21*/ 0, 0x4101, 0x8202, 0xc303, 0x5804, 0x1905, 0xda06, 0x9b07, + 0xac08, 0xed09, 0x2e0a, 0x6f0b, 0x640c, 0xb50d, 0x760e, 0x370f }, + {/*22*/ 1, 0xc441, 0x4882, 0x8cc3, 0xf654, 0x3215, 0xbed6, 0x7a97, + 0x5ba8, 0x9fe9, 0x132a, 0xd76b, 0xadfc, 0x69bd, 0xe57e, 0x213f }, + {/*23*/ 1, 0x7621, 0x9b32, 0xed13, 0xda44, 0xac65, 0x4176, 0x3757, + 0x6f88, 0x19a9, 0xf4ba, 0x829b, 0xb5cc, 0xc3ed, 0x2efe, 0x58df } +}; + +/* + * Given the syndrome argument, scan each of the channel tables for a syndrome + * match. Depending on which table it is found, return the channel number. + */ +static int get_channel_from_ecc_syndrome(unsigned short syndrome) +{ + int row; + int column; + + /* Determine column to scan */ + column = syndrome & 0xF; + + /* Scan all rows, looking for syndrome, or end of table */ + for (row = 0; row < NUMBER_ECC_ROWS; row++) { + if (ecc_chipkill_syndromes[row][column] == syndrome) + return ecc_chipkill_syndromes[row][0]; + } + + debugf0("syndrome(%x) not found\n", syndrome); + return -1; +} + +/* + * Check for valid error in the NB Status High register. If so, proceed to read + * NB Status Low, NB Address Low and NB Address High registers and store data + * into error structure. + * + * Returns: + * - 1: if hardware regs contains valid error info + * - 0: if no valid error is indicated + */ +static int amd64_get_error_info_regs(struct mem_ctl_info *mci, + struct amd64_error_info_regs *regs) +{ + struct amd64_pvt *pvt; + struct pci_dev *misc_f3_ctl; + int err = 0; + + pvt = mci->pvt_info; + misc_f3_ctl = pvt->misc_f3_ctl; + + err = pci_read_config_dword(misc_f3_ctl, K8_NBSH, ®s->nbsh); + if (err) + goto err_reg; + + if (!(regs->nbsh & K8_NBSH_VALID_BIT)) + return 0; + + /* valid error, read remaining error information registers */ + err = pci_read_config_dword(misc_f3_ctl, K8_NBSL, ®s->nbsl); + if (err) + goto err_reg; + + err = pci_read_config_dword(misc_f3_ctl, K8_NBEAL, ®s->nbeal); + if (err) + goto err_reg; + + err = pci_read_config_dword(misc_f3_ctl, K8_NBEAH, ®s->nbeah); + if (err) + goto err_reg; + + err = pci_read_config_dword(misc_f3_ctl, K8_NBCFG, ®s->nbcfg); + if (err) + goto err_reg; + + return 1; + +err_reg: + debugf0("Reading error info register failed\n"); + return 0; +} + +/* + * This function is called to retrieve the error data from hardware and store it + * in the info structure. + * + * Returns: + * - 1: if a valid error is found + * - 0: if no error is found + */ +static int amd64_get_error_info(struct mem_ctl_info *mci, + struct amd64_error_info_regs *info) +{ + struct amd64_pvt *pvt; + struct amd64_error_info_regs regs; + + pvt = mci->pvt_info; + + if (!amd64_get_error_info_regs(mci, info)) + return 0; + + /* + * Here's the problem with the K8's EDAC reporting: There are four + * registers which report pieces of error information. They are shared + * between CEs and UEs. Furthermore, contrary to what is stated in the + * BKDG, the overflow bit is never used! Every error always updates the + * reporting registers. + * + * Can you see the race condition? All four error reporting registers + * must be read before a new error updates them! There is no way to read + * all four registers atomically. The best than can be done is to detect + * that a race has occured and then report the error without any kind of + * precision. + * + * What is still positive is that errors are still reported and thus + * problems can still be detected - just not localized because the + * syndrome and address are spread out across registers. + * + * Grrrrr!!!!! Here's hoping that AMD fixes this in some future K8 rev. + * UEs and CEs should have separate register sets with proper overflow + * bits that are used! At very least the problem can be fixed by + * honoring the ErrValid bit in 'nbsh' and not updating registers - just + * set the overflow bit - unless the current error is CE and the new + * error is UE which would be the only situation for overwriting the + * current values. + */ + + regs = *info; + + /* Use info from the second read - most current */ + if (unlikely(!amd64_get_error_info_regs(mci, info))) + return 0; + + /* clear the error bits in hardware */ + pci_write_bits32(pvt->misc_f3_ctl, K8_NBSH, 0, K8_NBSH_VALID_BIT); + + /* Check for the possible race condition */ + if ((regs.nbsh != info->nbsh) || + (regs.nbsl != info->nbsl) || + (regs.nbeah != info->nbeah) || + (regs.nbeal != info->nbeal)) { + amd64_mc_printk(mci, KERN_WARNING, + "hardware STATUS read access race condition " + "detected!\n"); + return 0; + } + return 1; +} + +static inline void amd64_decode_gart_tlb_error(struct mem_ctl_info *mci, + struct amd64_error_info_regs *info) +{ + u32 err_code; + u32 ec_tt; /* error code transaction type (2b) */ + u32 ec_ll; /* error code cache level (2b) */ + + err_code = EXTRACT_ERROR_CODE(info->nbsl); + ec_ll = EXTRACT_LL_CODE(err_code); + ec_tt = EXTRACT_TT_CODE(err_code); + + amd64_mc_printk(mci, KERN_ERR, + "GART TLB event: transaction type(%s), " + "cache level(%s)\n", tt_msgs[ec_tt], ll_msgs[ec_ll]); +} + +static inline void amd64_decode_mem_cache_error(struct mem_ctl_info *mci, + struct amd64_error_info_regs *info) +{ + u32 err_code; + u32 ec_rrrr; /* error code memory transaction (4b) */ + u32 ec_tt; /* error code transaction type (2b) */ + u32 ec_ll; /* error code cache level (2b) */ + + err_code = EXTRACT_ERROR_CODE(info->nbsl); + ec_ll = EXTRACT_LL_CODE(err_code); + ec_tt = EXTRACT_TT_CODE(err_code); + ec_rrrr = EXTRACT_RRRR_CODE(err_code); + + amd64_mc_printk(mci, KERN_ERR, + "cache hierarchy error: memory transaction type(%s), " + "transaction type(%s), cache level(%s)\n", + rrrr_msgs[ec_rrrr], tt_msgs[ec_tt], ll_msgs[ec_ll]); +} + + +/* + * Handle any Correctable Errors (CEs) that have occurred. Check for valid ERROR + * ADDRESS and process. + */ +static void amd64_handle_ce(struct mem_ctl_info *mci, + struct amd64_error_info_regs *info) +{ + struct amd64_pvt *pvt = mci->pvt_info; + u64 SystemAddress; + + /* Ensure that the Error Address is VALID */ + if ((info->nbsh & K8_NBSH_VALID_ERROR_ADDR) == 0) { + amd64_mc_printk(mci, KERN_ERR, + "HW has no ERROR_ADDRESS available\n"); + edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR); + return; + } + + SystemAddress = extract_error_address(mci, info); + + amd64_mc_printk(mci, KERN_ERR, + "CE ERROR_ADDRESS= 0x%llx\n", SystemAddress); + + pvt->ops->map_sysaddr_to_csrow(mci, info, SystemAddress); +} + +/* Handle any Un-correctable Errors (UEs) */ +static void amd64_handle_ue(struct mem_ctl_info *mci, + struct amd64_error_info_regs *info) +{ + int csrow; + u64 SystemAddress; + u32 page, offset; + struct mem_ctl_info *log_mci, *src_mci = NULL; + + log_mci = mci; + + if ((info->nbsh & K8_NBSH_VALID_ERROR_ADDR) == 0) { + amd64_mc_printk(mci, KERN_CRIT, + "HW has no ERROR_ADDRESS available\n"); + edac_mc_handle_ue_no_info(log_mci, EDAC_MOD_STR); + return; + } + + SystemAddress = extract_error_address(mci, info); + + /* + * Find out which node the error address belongs to. This may be + * different from the node that detected the error. + */ + src_mci = find_mc_by_sys_addr(mci, SystemAddress); + if (!src_mci) { + amd64_mc_printk(mci, KERN_CRIT, + "ERROR ADDRESS (0x%lx) value NOT mapped to a MC\n", + (unsigned long)SystemAddress); + edac_mc_handle_ue_no_info(log_mci, EDAC_MOD_STR); + return; + } + + log_mci = src_mci; + + csrow = sys_addr_to_csrow(log_mci, SystemAddress); + if (csrow < 0) { + amd64_mc_printk(mci, KERN_CRIT, + "ERROR_ADDRESS (0x%lx) value NOT mapped to 'csrow'\n", + (unsigned long)SystemAddress); + edac_mc_handle_ue_no_info(log_mci, EDAC_MOD_STR); + } else { + error_address_to_page_and_offset(SystemAddress, &page, &offset); + edac_mc_handle_ue(log_mci, page, offset, csrow, EDAC_MOD_STR); + } +} + +static void amd64_decode_bus_error(struct mem_ctl_info *mci, + struct amd64_error_info_regs *info) +{ + u32 err_code, ext_ec; + u32 ec_pp; /* error code participating processor (2p) */ + u32 ec_to; /* error code timed out (1b) */ + u32 ec_rrrr; /* error code memory transaction (4b) */ + u32 ec_ii; /* error code memory or I/O (2b) */ + u32 ec_ll; /* error code cache level (2b) */ + + ext_ec = EXTRACT_EXT_ERROR_CODE(info->nbsl); + err_code = EXTRACT_ERROR_CODE(info->nbsl); + + ec_ll = EXTRACT_LL_CODE(err_code); + ec_ii = EXTRACT_II_CODE(err_code); + ec_rrrr = EXTRACT_RRRR_CODE(err_code); + ec_to = EXTRACT_TO_CODE(err_code); + ec_pp = EXTRACT_PP_CODE(err_code); + + amd64_mc_printk(mci, KERN_ERR, + "BUS ERROR:\n" + " time-out(%s) mem or i/o(%s)\n" + " participating processor(%s)\n" + " memory transaction type(%s)\n" + " cache level(%s) Error Found by: %s\n", + to_msgs[ec_to], + ii_msgs[ec_ii], + pp_msgs[ec_pp], + rrrr_msgs[ec_rrrr], + ll_msgs[ec_ll], + (info->nbsh & K8_NBSH_ERR_SCRUBER) ? + "Scrubber" : "Normal Operation"); + + /* If this was an 'observed' error, early out */ + if (ec_pp == K8_NBSL_PP_OBS) + return; /* We aren't the node involved */ + + /* Parse out the extended error code for ECC events */ + switch (ext_ec) { + /* F10 changed to one Extended ECC error code */ + case F10_NBSL_EXT_ERR_RES: /* Reserved field */ + case F10_NBSL_EXT_ERR_ECC: /* F10 ECC ext err code */ + break; + + default: + amd64_mc_printk(mci, KERN_ERR, "NOT ECC: no special error " + "handling for this error\n"); + return; + } + + if (info->nbsh & K8_NBSH_CECC) + amd64_handle_ce(mci, info); + else if (info->nbsh & K8_NBSH_UECC) + amd64_handle_ue(mci, info); + + /* + * If main error is CE then overflow must be CE. If main error is UE + * then overflow is unknown. We'll call the overflow a CE - if + * panic_on_ue is set then we're already panic'ed and won't arrive + * here. Else, then apparently someone doesn't think that UE's are + * catastrophic. + */ + if (info->nbsh & K8_NBSH_OVERFLOW) + edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR + "Error Overflow set"); +} + +int amd64_process_error_info(struct mem_ctl_info *mci, + struct amd64_error_info_regs *info, + int handle_errors) +{ + struct amd64_pvt *pvt; + struct amd64_error_info_regs *regs; + u32 err_code, ext_ec; + int gart_tlb_error = 0; + + pvt = mci->pvt_info; + + /* If caller doesn't want us to process the error, return */ + if (!handle_errors) + return 1; + + regs = info; + + debugf1("NorthBridge ERROR: mci(0x%p)\n", mci); + debugf1(" MC node(%d) Error-Address(0x%.8x-%.8x)\n", + pvt->mc_node_id, regs->nbeah, regs->nbeal); + debugf1(" nbsh(0x%.8x) nbsl(0x%.8x)\n", + regs->nbsh, regs->nbsl); + debugf1(" Valid Error=%s Overflow=%s\n", + (regs->nbsh & K8_NBSH_VALID_BIT) ? "True" : "False", + (regs->nbsh & K8_NBSH_OVERFLOW) ? "True" : "False"); + debugf1(" Err Uncorrected=%s MCA Error Reporting=%s\n", + (regs->nbsh & K8_NBSH_UNCORRECTED_ERR) ? + "True" : "False", + (regs->nbsh & K8_NBSH_ERR_ENABLE) ? + "True" : "False"); + debugf1(" MiscErr Valid=%s ErrAddr Valid=%s PCC=%s\n", + (regs->nbsh & K8_NBSH_MISC_ERR_VALID) ? + "True" : "False", + (regs->nbsh & K8_NBSH_VALID_ERROR_ADDR) ? + "True" : "False", + (regs->nbsh & K8_NBSH_PCC) ? + "True" : "False"); + debugf1(" CECC=%s UECC=%s Found by Scruber=%s\n", + (regs->nbsh & K8_NBSH_CECC) ? + "True" : "False", + (regs->nbsh & K8_NBSH_UECC) ? + "True" : "False", + (regs->nbsh & K8_NBSH_ERR_SCRUBER) ? + "True" : "False"); + debugf1(" CORE0=%s CORE1=%s CORE2=%s CORE3=%s\n", + (regs->nbsh & K8_NBSH_CORE0) ? "True" : "False", + (regs->nbsh & K8_NBSH_CORE1) ? "True" : "False", + (regs->nbsh & K8_NBSH_CORE2) ? "True" : "False", + (regs->nbsh & K8_NBSH_CORE3) ? "True" : "False"); + + + err_code = EXTRACT_ERROR_CODE(regs->nbsl); + + /* Determine which error type: + * 1) GART errors - non-fatal, developmental events + * 2) MEMORY errors + * 3) BUS errors + * 4) Unknown error + */ + if (TEST_TLB_ERROR(err_code)) { + /* + * GART errors are intended to help graphics driver developers + * to detect bad GART PTEs. It is recommended by AMD to disable + * GART table walk error reporting by default[1] (currently + * being disabled in mce_cpu_quirks()) and according to the + * comment in mce_cpu_quirks(), such GART errors can be + * incorrectly triggered. We may see these errors anyway and + * unless requested by the user, they won't be reported. + * + * [1] section 13.10.1 on BIOS and Kernel Developers Guide for + * AMD NPT family 0Fh processors + */ + if (report_gart_errors == 0) + return 1; + + /* + * Only if GART error reporting is requested should we generate + * any logs. + */ + gart_tlb_error = 1; + + debugf1("GART TLB error\n"); + amd64_decode_gart_tlb_error(mci, info); + } else if (TEST_MEM_ERROR(err_code)) { + debugf1("Memory/Cache error\n"); + amd64_decode_mem_cache_error(mci, info); + } else if (TEST_BUS_ERROR(err_code)) { + debugf1("Bus (Link/DRAM) error\n"); + amd64_decode_bus_error(mci, info); + } else { + /* shouldn't reach here! */ + amd64_mc_printk(mci, KERN_WARNING, + "%s(): unknown MCE error 0x%x\n", __func__, + err_code); + } + + ext_ec = EXTRACT_EXT_ERROR_CODE(regs->nbsl); + amd64_mc_printk(mci, KERN_ERR, + "ExtErr=(0x%x) %s\n", ext_ec, ext_msgs[ext_ec]); + + if (((ext_ec >= F10_NBSL_EXT_ERR_CRC && + ext_ec <= F10_NBSL_EXT_ERR_TGT) || + (ext_ec == F10_NBSL_EXT_ERR_RMW)) && + EXTRACT_LDT_LINK(info->nbsh)) { + + amd64_mc_printk(mci, KERN_ERR, + "Error on hypertransport link: %s\n", + htlink_msgs[ + EXTRACT_LDT_LINK(info->nbsh)]); + } + + /* + * Check the UE bit of the NB status high register, if set generate some + * logs. If NOT a GART error, then process the event as a NO-INFO event. + * If it was a GART error, skip that process. + */ + if (regs->nbsh & K8_NBSH_UNCORRECTED_ERR) { + amd64_mc_printk(mci, KERN_CRIT, "uncorrected error\n"); + if (!gart_tlb_error) + edac_mc_handle_ue_no_info(mci, "UE bit is set\n"); + } + + if (regs->nbsh & K8_NBSH_PCC) + amd64_mc_printk(mci, KERN_CRIT, + "PCC (processor context corrupt) set\n"); + + return 1; +} +EXPORT_SYMBOL_GPL(amd64_process_error_info); + +/* + * The main polling 'check' function, called FROM the edac core to perform the + * error checking and if an error is encountered, error processing. + */ +static void amd64_check(struct mem_ctl_info *mci) +{ + struct amd64_error_info_regs info; + + if (amd64_get_error_info(mci, &info)) + amd64_process_error_info(mci, &info, 1); +} + +/* + * Input: + * 1) struct amd64_pvt which contains pvt->dram_f2_ctl pointer + * 2) AMD Family index value + * + * Ouput: + * Upon return of 0, the following filled in: + * + * struct pvt->addr_f1_ctl + * struct pvt->misc_f3_ctl + * + * Filled in with related device funcitions of 'dram_f2_ctl' + * These devices are "reserved" via the pci_get_device() + * + * Upon return of 1 (error status): + * + * Nothing reserved + */ +static int amd64_reserve_mc_sibling_devices(struct amd64_pvt *pvt, int mc_idx) +{ + const struct amd64_family_type *amd64_dev = &amd64_family_types[mc_idx]; + + /* Reserve the ADDRESS MAP Device */ + pvt->addr_f1_ctl = pci_get_related_function(pvt->dram_f2_ctl->vendor, + amd64_dev->addr_f1_ctl, + pvt->dram_f2_ctl); + + if (!pvt->addr_f1_ctl) { + amd64_printk(KERN_ERR, "error address map device not found: " + "vendor %x device 0x%x (broken BIOS?)\n", + PCI_VENDOR_ID_AMD, amd64_dev->addr_f1_ctl); + return 1; + } + + /* Reserve the MISC Device */ + pvt->misc_f3_ctl = pci_get_related_function(pvt->dram_f2_ctl->vendor, + amd64_dev->misc_f3_ctl, + pvt->dram_f2_ctl); + + if (!pvt->misc_f3_ctl) { + pci_dev_put(pvt->addr_f1_ctl); + pvt->addr_f1_ctl = NULL; + + amd64_printk(KERN_ERR, "error miscellaneous device not found: " + "vendor %x device 0x%x (broken BIOS?)\n", + PCI_VENDOR_ID_AMD, amd64_dev->misc_f3_ctl); + return 1; + } + + debugf1(" Addr Map device PCI Bus ID:\t%s\n", + pci_name(pvt->addr_f1_ctl)); + debugf1(" DRAM MEM-CTL PCI Bus ID:\t%s\n", + pci_name(pvt->dram_f2_ctl)); + debugf1(" Misc device PCI Bus ID:\t%s\n", + pci_name(pvt->misc_f3_ctl)); + + return 0; +} + +static void amd64_free_mc_sibling_devices(struct amd64_pvt *pvt) +{ + pci_dev_put(pvt->addr_f1_ctl); + pci_dev_put(pvt->misc_f3_ctl); +} + +/* + * Retrieve the hardware registers of the memory controller (this includes the + * 'Address Map' and 'Misc' device regs) + */ +static void amd64_read_mc_registers(struct amd64_pvt *pvt) +{ + u64 msr_val; + int dram, err = 0; + + /* + * Retrieve TOP_MEM and TOP_MEM2; no masking off of reserved bits since + * those are Read-As-Zero + */ + rdmsrl(MSR_K8_TOP_MEM1, msr_val); + pvt->top_mem = msr_val >> 23; + debugf0(" TOP_MEM=0x%08llx\n", pvt->top_mem); + + /* check first whether TOP_MEM2 is enabled */ + rdmsrl(MSR_K8_SYSCFG, msr_val); + if (msr_val & (1U << 21)) { + rdmsrl(MSR_K8_TOP_MEM2, msr_val); + pvt->top_mem2 = msr_val >> 23; + debugf0(" TOP_MEM2=0x%08llx\n", pvt->top_mem2); + } else + debugf0(" TOP_MEM2 disabled.\n"); + + amd64_cpu_display_info(pvt); + + err = pci_read_config_dword(pvt->misc_f3_ctl, K8_NBCAP, &pvt->nbcap); + if (err) + goto err_reg; + + if (pvt->ops->read_dram_ctl_register) + pvt->ops->read_dram_ctl_register(pvt); + + for (dram = 0; dram < DRAM_REG_COUNT; dram++) { + /* + * Call CPU specific READ function to get the DRAM Base and + * Limit values from the DCT. + */ + pvt->ops->read_dram_base_limit(pvt, dram); + + /* + * Only print out debug info on rows with both R and W Enabled. + * Normal processing, compiler should optimize this whole 'if' + * debug output block away. + */ + if (pvt->dram_rw_en[dram] != 0) { + debugf1(" DRAM_BASE[%d]: 0x%8.08x-%8.08x " + "DRAM_LIMIT: 0x%8.08x-%8.08x\n", + dram, + (u32)(pvt->dram_base[dram] >> 32), + (u32)(pvt->dram_base[dram] & 0xFFFFFFFF), + (u32)(pvt->dram_limit[dram] >> 32), + (u32)(pvt->dram_limit[dram] & 0xFFFFFFFF)); + debugf1(" IntlvEn=%s %s %s " + "IntlvSel=%d DstNode=%d\n", + pvt->dram_IntlvEn[dram] ? + "Enabled" : "Disabled", + (pvt->dram_rw_en[dram] & 0x2) ? "W" : "!W", + (pvt->dram_rw_en[dram] & 0x1) ? "R" : "!R", + pvt->dram_IntlvSel[dram], + pvt->dram_DstNode[dram]); + } + } + + amd64_read_dct_base_mask(pvt); + + err = pci_read_config_dword(pvt->addr_f1_ctl, K8_DHAR, &pvt->dhar); + if (err) + goto err_reg; + + amd64_read_dbam_reg(pvt); + + err = pci_read_config_dword(pvt->misc_f3_ctl, + F10_ONLINE_SPARE, &pvt->online_spare); + if (err) + goto err_reg; + + err = pci_read_config_dword(pvt->dram_f2_ctl, F10_DCLR_0, &pvt->dclr0); + if (err) + goto err_reg; + + err = pci_read_config_dword(pvt->dram_f2_ctl, F10_DCHR_0, &pvt->dchr0); + if (err) + goto err_reg; + + if (!dct_ganging_enabled(pvt)) { + err = pci_read_config_dword(pvt->dram_f2_ctl, F10_DCLR_1, + &pvt->dclr1); + if (err) + goto err_reg; + + err = pci_read_config_dword(pvt->dram_f2_ctl, F10_DCHR_1, + &pvt->dchr1); + if (err) + goto err_reg; + } + + amd64_dump_misc_regs(pvt); + +err_reg: + debugf0("Reading an MC register failed\n"); + +} + +/* + * NOTE: CPU Revision Dependent code + * + * Input: + * @csrow_nr ChipSelect Row Number (0..CHIPSELECT_COUNT-1) + * k8 private pointer to --> + * DRAM Bank Address mapping register + * node_id + * DCL register where dual_channel_active is + * + * The DBAM register consists of 4 sets of 4 bits each definitions: + * + * Bits: CSROWs + * 0-3 CSROWs 0 and 1 + * 4-7 CSROWs 2 and 3 + * 8-11 CSROWs 4 and 5 + * 12-15 CSROWs 6 and 7 + * + * Values range from: 0 to 15 + * The meaning of the values depends on CPU revision and dual-channel state, + * see relevant BKDG more info. + * + * The memory controller provides for total of only 8 CSROWs in its current + * architecture. Each "pair" of CSROWs normally represents just one DIMM in + * single channel or two (2) DIMMs in dual channel mode. + * + * The following code logic collapses the various tables for CSROW based on CPU + * revision. + * + * Returns: + * The number of PAGE_SIZE pages on the specified CSROW number it + * encompasses + * + */ +static u32 amd64_csrow_nr_pages(int csrow_nr, struct amd64_pvt *pvt) +{ + u32 dram_map, nr_pages; + + /* + * The math on this doesn't look right on the surface because x/2*4 can + * be simplified to x*2 but this expression makes use of the fact that + * it is integral math where 1/2=0. This intermediate value becomes the + * number of bits to shift the DBAM register to extract the proper CSROW + * field. + */ + dram_map = (pvt->dbam0 >> ((csrow_nr / 2) * 4)) & 0xF; + + nr_pages = pvt->ops->dbam_map_to_pages(pvt, dram_map); + + /* + * If dual channel then double the memory size of single channel. + * Channel count is 1 or 2 + */ + nr_pages <<= (pvt->channel_count - 1); + + debugf0(" (csrow=%d) DBAM map index= %d\n", csrow_nr, dram_map); + debugf0(" nr_pages= %u channel-count = %d\n", + nr_pages, pvt->channel_count); + + return nr_pages; +} + +/* + * Initialize the array of csrow attribute instances, based on the values + * from pci config hardware registers. + */ +static int amd64_init_csrows(struct mem_ctl_info *mci) +{ + struct csrow_info *csrow; + struct amd64_pvt *pvt; + u64 input_addr_min, input_addr_max, sys_addr; + int i, err = 0, empty = 1; + + pvt = mci->pvt_info; + + err = pci_read_config_dword(pvt->misc_f3_ctl, K8_NBCFG, &pvt->nbcfg); + if (err) + debugf0("Reading K8_NBCFG failed\n"); + + debugf0("NBCFG= 0x%x CHIPKILL= %s DRAM ECC= %s\n", pvt->nbcfg, + (pvt->nbcfg & K8_NBCFG_CHIPKILL) ? "Enabled" : "Disabled", + (pvt->nbcfg & K8_NBCFG_ECC_ENABLE) ? "Enabled" : "Disabled" + ); + + for (i = 0; i < CHIPSELECT_COUNT; i++) { + csrow = &mci->csrows[i]; + + if ((pvt->dcsb0[i] & K8_DCSB_CS_ENABLE) == 0) { + debugf1("----CSROW %d EMPTY for node %d\n", i, + pvt->mc_node_id); + continue; + } + + debugf1("----CSROW %d VALID for MC node %d\n", + i, pvt->mc_node_id); + + empty = 0; + csrow->nr_pages = amd64_csrow_nr_pages(i, pvt); + find_csrow_limits(mci, i, &input_addr_min, &input_addr_max); + sys_addr = input_addr_to_sys_addr(mci, input_addr_min); + csrow->first_page = (u32) (sys_addr >> PAGE_SHIFT); + sys_addr = input_addr_to_sys_addr(mci, input_addr_max); + csrow->last_page = (u32) (sys_addr >> PAGE_SHIFT); + csrow->page_mask = ~mask_from_dct_mask(pvt, i); + /* 8 bytes of resolution */ + + csrow->mtype = amd64_determine_memory_type(pvt); + + debugf1(" for MC node %d csrow %d:\n", pvt->mc_node_id, i); + debugf1(" input_addr_min: 0x%lx input_addr_max: 0x%lx\n", + (unsigned long)input_addr_min, + (unsigned long)input_addr_max); + debugf1(" sys_addr: 0x%lx page_mask: 0x%lx\n", + (unsigned long)sys_addr, csrow->page_mask); + debugf1(" nr_pages: %u first_page: 0x%lx " + "last_page: 0x%lx\n", + (unsigned)csrow->nr_pages, + csrow->first_page, csrow->last_page); + + /* + * determine whether CHIPKILL or JUST ECC or NO ECC is operating + */ + if (pvt->nbcfg & K8_NBCFG_ECC_ENABLE) + csrow->edac_mode = + (pvt->nbcfg & K8_NBCFG_CHIPKILL) ? + EDAC_S4ECD4ED : EDAC_SECDED; + else + csrow->edac_mode = EDAC_NONE; + } + + return empty; +} + +/* + * Only if 'ecc_enable_override' is set AND BIOS had ECC disabled, do "we" + * enable it. + */ +static void amd64_enable_ecc_error_reporting(struct mem_ctl_info *mci) +{ + struct amd64_pvt *pvt = mci->pvt_info; + const cpumask_t *cpumask = cpumask_of_node(pvt->mc_node_id); + int cpu, idx = 0, err = 0; + struct msr msrs[cpumask_weight(cpumask)]; + u32 value; + u32 mask = K8_NBCTL_CECCEn | K8_NBCTL_UECCEn; + + if (!ecc_enable_override) + return; + + memset(msrs, 0, sizeof(msrs)); + + amd64_printk(KERN_WARNING, + "'ecc_enable_override' parameter is active, " + "Enabling AMD ECC hardware now: CAUTION\n"); + + err = pci_read_config_dword(pvt->misc_f3_ctl, K8_NBCTL, &value); + if (err) + debugf0("Reading K8_NBCTL failed\n"); + + /* turn on UECCn and CECCEn bits */ + pvt->old_nbctl = value & mask; + pvt->nbctl_mcgctl_saved = 1; + + value |= mask; + pci_write_config_dword(pvt->misc_f3_ctl, K8_NBCTL, value); + + rdmsr_on_cpus(cpumask, K8_MSR_MCGCTL, msrs); + + for_each_cpu(cpu, cpumask) { + if (msrs[idx].l & K8_MSR_MCGCTL_NBE) + set_bit(idx, &pvt->old_mcgctl); + + msrs[idx].l |= K8_MSR_MCGCTL_NBE; + idx++; + } + wrmsr_on_cpus(cpumask, K8_MSR_MCGCTL, msrs); + + err = pci_read_config_dword(pvt->misc_f3_ctl, K8_NBCFG, &value); + if (err) + debugf0("Reading K8_NBCFG failed\n"); + + debugf0("NBCFG(1)= 0x%x CHIPKILL= %s ECC_ENABLE= %s\n", value, + (value & K8_NBCFG_CHIPKILL) ? "Enabled" : "Disabled", + (value & K8_NBCFG_ECC_ENABLE) ? "Enabled" : "Disabled"); + + if (!(value & K8_NBCFG_ECC_ENABLE)) { + amd64_printk(KERN_WARNING, + "This node reports that DRAM ECC is " + "currently Disabled; ENABLING now\n"); + + /* Attempt to turn on DRAM ECC Enable */ + value |= K8_NBCFG_ECC_ENABLE; + pci_write_config_dword(pvt->misc_f3_ctl, K8_NBCFG, value); + + err = pci_read_config_dword(pvt->misc_f3_ctl, K8_NBCFG, &value); + if (err) + debugf0("Reading K8_NBCFG failed\n"); + + if (!(value & K8_NBCFG_ECC_ENABLE)) { + amd64_printk(KERN_WARNING, + "Hardware rejects Enabling DRAM ECC checking\n" + "Check memory DIMM configuration\n"); + } else { + amd64_printk(KERN_DEBUG, + "Hardware accepted DRAM ECC Enable\n"); + } + } + debugf0("NBCFG(2)= 0x%x CHIPKILL= %s ECC_ENABLE= %s\n", value, + (value & K8_NBCFG_CHIPKILL) ? "Enabled" : "Disabled", + (value & K8_NBCFG_ECC_ENABLE) ? "Enabled" : "Disabled"); + + pvt->ctl_error_info.nbcfg = value; +} + +static void amd64_restore_ecc_error_reporting(struct amd64_pvt *pvt) +{ + const cpumask_t *cpumask = cpumask_of_node(pvt->mc_node_id); + int cpu, idx = 0, err = 0; + struct msr msrs[cpumask_weight(cpumask)]; + u32 value; + u32 mask = K8_NBCTL_CECCEn | K8_NBCTL_UECCEn; + + if (!pvt->nbctl_mcgctl_saved) + return; + + memset(msrs, 0, sizeof(msrs)); + + err = pci_read_config_dword(pvt->misc_f3_ctl, K8_NBCTL, &value); + if (err) + debugf0("Reading K8_NBCTL failed\n"); + value &= ~mask; + value |= pvt->old_nbctl; + + /* restore the NB Enable MCGCTL bit */ + pci_write_config_dword(pvt->misc_f3_ctl, K8_NBCTL, value); + + rdmsr_on_cpus(cpumask, K8_MSR_MCGCTL, msrs); + + for_each_cpu(cpu, cpumask) { + msrs[idx].l &= ~K8_MSR_MCGCTL_NBE; + msrs[idx].l |= + test_bit(idx, &pvt->old_mcgctl) << K8_MSR_MCGCTL_NBE; + idx++; + } + + wrmsr_on_cpus(cpumask, K8_MSR_MCGCTL, msrs); +} + +static void check_mcg_ctl(void *ret) +{ + u64 msr_val = 0; + u8 nbe; + + rdmsrl(MSR_IA32_MCG_CTL, msr_val); + nbe = msr_val & K8_MSR_MCGCTL_NBE; + + debugf0("core: %u, MCG_CTL: 0x%llx, NB MSR is %s\n", + raw_smp_processor_id(), msr_val, + (nbe ? "enabled" : "disabled")); + + if (!nbe) + *(int *)ret = 0; +} + +/* check MCG_CTL on all the cpus on this node */ +static int amd64_mcg_ctl_enabled_on_cpus(const cpumask_t *mask) +{ + int ret = 1; + preempt_disable(); + smp_call_function_many(mask, check_mcg_ctl, &ret, 1); + preempt_enable(); + + return ret; +} + +/* + * EDAC requires that the BIOS have ECC enabled before taking over the + * processing of ECC errors. This is because the BIOS can properly initialize + * the memory system completely. A command line option allows to force-enable + * hardware ECC later in amd64_enable_ecc_error_reporting(). + */ +static int amd64_check_ecc_enabled(struct amd64_pvt *pvt) +{ + u32 value; + int err = 0, ret = 0; + u8 ecc_enabled = 0; + + err = pci_read_config_dword(pvt->misc_f3_ctl, K8_NBCFG, &value); + if (err) + debugf0("Reading K8_NBCTL failed\n"); + + ecc_enabled = !!(value & K8_NBCFG_ECC_ENABLE); + + ret = amd64_mcg_ctl_enabled_on_cpus(cpumask_of_node(pvt->mc_node_id)); + + debugf0("K8_NBCFG=0x%x, DRAM ECC is %s\n", value, + (value & K8_NBCFG_ECC_ENABLE ? "enabled" : "disabled")); + + if (!ecc_enabled || !ret) { + if (!ecc_enabled) { + amd64_printk(KERN_WARNING, "This node reports that " + "Memory ECC is currently " + "disabled.\n"); + + amd64_printk(KERN_WARNING, "bit 0x%lx in register " + "F3x%x of the MISC_CONTROL device (%s) " + "should be enabled\n", K8_NBCFG_ECC_ENABLE, + K8_NBCFG, pci_name(pvt->misc_f3_ctl)); + } + if (!ret) { + amd64_printk(KERN_WARNING, "bit 0x%016lx in MSR 0x%08x " + "of node %d should be enabled\n", + K8_MSR_MCGCTL_NBE, MSR_IA32_MCG_CTL, + pvt->mc_node_id); + } + if (!ecc_enable_override) { + amd64_printk(KERN_WARNING, "WARNING: ECC is NOT " + "currently enabled by the BIOS. Module " + "will NOT be loaded.\n" + " Either Enable ECC in the BIOS, " + "or use the 'ecc_enable_override' " + "parameter.\n" + " Might be a BIOS bug, if BIOS says " + "ECC is enabled\n" + " Use of the override can cause " + "unknown side effects.\n"); + ret = -ENODEV; + } + } else { + amd64_printk(KERN_INFO, + "ECC is enabled by BIOS, Proceeding " + "with EDAC module initialization\n"); + + /* CLEAR the override, since BIOS controlled it */ + ecc_enable_override = 0; + } + + return ret; +} + +struct mcidev_sysfs_attribute sysfs_attrs[ARRAY_SIZE(amd64_dbg_attrs) + + ARRAY_SIZE(amd64_inj_attrs) + + 1]; + +struct mcidev_sysfs_attribute terminator = { .attr = { .name = NULL } }; + +static void amd64_set_mc_sysfs_attributes(struct mem_ctl_info *mci) +{ + unsigned int i = 0, j = 0; + + for (; i < ARRAY_SIZE(amd64_dbg_attrs); i++) + sysfs_attrs[i] = amd64_dbg_attrs[i]; + + for (j = 0; j < ARRAY_SIZE(amd64_inj_attrs); j++, i++) + sysfs_attrs[i] = amd64_inj_attrs[j]; + + sysfs_attrs[i] = terminator; + + mci->mc_driver_sysfs_attributes = sysfs_attrs; +} + +static void amd64_setup_mci_misc_attributes(struct mem_ctl_info *mci) +{ + struct amd64_pvt *pvt = mci->pvt_info; + + mci->mtype_cap = MEM_FLAG_DDR2 | MEM_FLAG_RDDR2; + mci->edac_ctl_cap = EDAC_FLAG_NONE; + mci->edac_cap = EDAC_FLAG_NONE; + + if (pvt->nbcap & K8_NBCAP_SECDED) + mci->edac_ctl_cap |= EDAC_FLAG_SECDED; + + if (pvt->nbcap & K8_NBCAP_CHIPKILL) + mci->edac_ctl_cap |= EDAC_FLAG_S4ECD4ED; + + mci->edac_cap = amd64_determine_edac_cap(pvt); + mci->mod_name = EDAC_MOD_STR; + mci->mod_ver = EDAC_AMD64_VERSION; + mci->ctl_name = get_amd_family_name(pvt->mc_type_index); + mci->dev_name = pci_name(pvt->dram_f2_ctl); + mci->ctl_page_to_phys = NULL; + + /* IMPORTANT: Set the polling 'check' function in this module */ + mci->edac_check = amd64_check; + + /* memory scrubber interface */ + mci->set_sdram_scrub_rate = amd64_set_scrub_rate; + mci->get_sdram_scrub_rate = amd64_get_scrub_rate; +} + +/* + * Init stuff for this DRAM Controller device. + * + * Due to a hardware feature on Fam10h CPUs, the Enable Extended Configuration + * Space feature MUST be enabled on ALL Processors prior to actually reading + * from the ECS registers. Since the loading of the module can occur on any + * 'core', and cores don't 'see' all the other processors ECS data when the + * others are NOT enabled. Our solution is to first enable ECS access in this + * routine on all processors, gather some data in a amd64_pvt structure and + * later come back in a finish-setup function to perform that final + * initialization. See also amd64_init_2nd_stage() for that. + */ +static int amd64_probe_one_instance(struct pci_dev *dram_f2_ctl, + int mc_type_index) +{ + struct amd64_pvt *pvt = NULL; + int err = 0, ret; + + ret = -ENOMEM; + pvt = kzalloc(sizeof(struct amd64_pvt), GFP_KERNEL); + if (!pvt) + goto err_exit; + + pvt->mc_node_id = get_mc_node_id_from_pdev(dram_f2_ctl); + + pvt->dram_f2_ctl = dram_f2_ctl; + pvt->ext_model = boot_cpu_data.x86_model >> 4; + pvt->mc_type_index = mc_type_index; + pvt->ops = family_ops(mc_type_index); + pvt->old_mcgctl = 0; + + /* + * We have the dram_f2_ctl device as an argument, now go reserve its + * sibling devices from the PCI system. + */ + ret = -ENODEV; + err = amd64_reserve_mc_sibling_devices(pvt, mc_type_index); + if (err) + goto err_free; + + ret = -EINVAL; + err = amd64_check_ecc_enabled(pvt); + if (err) + goto err_put; + + /* + * Key operation here: setup of HW prior to performing ops on it. Some + * setup is required to access ECS data. After this is performed, the + * 'teardown' function must be called upon error and normal exit paths. + */ + if (boot_cpu_data.x86 >= 0x10) + amd64_setup(pvt); + + /* + * Save the pointer to the private data for use in 2nd initialization + * stage + */ + pvt_lookup[pvt->mc_node_id] = pvt; + + return 0; + +err_put: + amd64_free_mc_sibling_devices(pvt); + +err_free: + kfree(pvt); + +err_exit: + return ret; +} + +/* + * This is the finishing stage of the init code. Needs to be performed after all + * MCs' hardware have been prepped for accessing extended config space. + */ +static int amd64_init_2nd_stage(struct amd64_pvt *pvt) +{ + int node_id = pvt->mc_node_id; + struct mem_ctl_info *mci; + int ret, err = 0; + + amd64_read_mc_registers(pvt); + + ret = -ENODEV; + if (pvt->ops->probe_valid_hardware) { + err = pvt->ops->probe_valid_hardware(pvt); + if (err) + goto err_exit; + } + + /* + * We need to determine how many memory channels there are. Then use + * that information for calculating the size of the dynamic instance + * tables in the 'mci' structure + */ + pvt->channel_count = pvt->ops->early_channel_count(pvt); + if (pvt->channel_count < 0) + goto err_exit; + + ret = -ENOMEM; + mci = edac_mc_alloc(0, CHIPSELECT_COUNT, pvt->channel_count, node_id); + if (!mci) + goto err_exit; + + mci->pvt_info = pvt; + + mci->dev = &pvt->dram_f2_ctl->dev; + amd64_setup_mci_misc_attributes(mci); + + if (amd64_init_csrows(mci)) + mci->edac_cap = EDAC_FLAG_NONE; + + amd64_enable_ecc_error_reporting(mci); + amd64_set_mc_sysfs_attributes(mci); + + ret = -ENODEV; + if (edac_mc_add_mc(mci)) { + debugf1("failed edac_mc_add_mc()\n"); + goto err_add_mc; + } + + mci_lookup[node_id] = mci; + pvt_lookup[node_id] = NULL; + return 0; + +err_add_mc: + edac_mc_free(mci); + +err_exit: + debugf0("failure to init 2nd stage: ret=%d\n", ret); + + amd64_restore_ecc_error_reporting(pvt); + + if (boot_cpu_data.x86 > 0xf) + amd64_teardown(pvt); + + amd64_free_mc_sibling_devices(pvt); + + kfree(pvt_lookup[pvt->mc_node_id]); + pvt_lookup[node_id] = NULL; + + return ret; +} + + +static int __devinit amd64_init_one_instance(struct pci_dev *pdev, + const struct pci_device_id *mc_type) +{ + int ret = 0; + + debugf0("(MC node=%d,mc_type='%s')\n", + get_mc_node_id_from_pdev(pdev), + get_amd_family_name(mc_type->driver_data)); + + ret = pci_enable_device(pdev); + if (ret < 0) + ret = -EIO; + else + ret = amd64_probe_one_instance(pdev, mc_type->driver_data); + + if (ret < 0) + debugf0("ret=%d\n", ret); + + return ret; +} + +static void __devexit amd64_remove_one_instance(struct pci_dev *pdev) +{ + struct mem_ctl_info *mci; + struct amd64_pvt *pvt; + + /* Remove from EDAC CORE tracking list */ + mci = edac_mc_del_mc(&pdev->dev); + if (!mci) + return; + + pvt = mci->pvt_info; + + amd64_restore_ecc_error_reporting(pvt); + + if (boot_cpu_data.x86 > 0xf) + amd64_teardown(pvt); + + amd64_free_mc_sibling_devices(pvt); + + kfree(pvt); + mci->pvt_info = NULL; + + mci_lookup[pvt->mc_node_id] = NULL; + + /* Free the EDAC CORE resources */ + edac_mc_free(mci); +} + +/* + * This table is part of the interface for loading drivers for PCI devices. The + * PCI core identifies what devices are on a system during boot, and then + * inquiry this table to see if this driver is for a given device found. + */ +static const struct pci_device_id amd64_pci_table[] __devinitdata = { + { + .vendor = PCI_VENDOR_ID_AMD, + .device = PCI_DEVICE_ID_AMD_K8_NB_MEMCTL, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .class = 0, + .class_mask = 0, + .driver_data = K8_CPUS + }, + { + .vendor = PCI_VENDOR_ID_AMD, + .device = PCI_DEVICE_ID_AMD_10H_NB_DRAM, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .class = 0, + .class_mask = 0, + .driver_data = F10_CPUS + }, + { + .vendor = PCI_VENDOR_ID_AMD, + .device = PCI_DEVICE_ID_AMD_11H_NB_DRAM, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .class = 0, + .class_mask = 0, + .driver_data = F11_CPUS + }, + {0, } +}; +MODULE_DEVICE_TABLE(pci, amd64_pci_table); + +static struct pci_driver amd64_pci_driver = { + .name = EDAC_MOD_STR, + .probe = amd64_init_one_instance, + .remove = __devexit_p(amd64_remove_one_instance), + .id_table = amd64_pci_table, +}; + +static void amd64_setup_pci_device(void) +{ + struct mem_ctl_info *mci; + struct amd64_pvt *pvt; + + if (amd64_ctl_pci) + return; + + mci = mci_lookup[0]; + if (mci) { + + pvt = mci->pvt_info; + amd64_ctl_pci = + edac_pci_create_generic_ctl(&pvt->dram_f2_ctl->dev, + EDAC_MOD_STR); + + if (!amd64_ctl_pci) { + pr_warning("%s(): Unable to create PCI control\n", + __func__); + + pr_warning("%s(): PCI error report via EDAC not set\n", + __func__); + } + } +} + +static int __init amd64_edac_init(void) +{ + int nb, err = -ENODEV; + + edac_printk(KERN_INFO, EDAC_MOD_STR, EDAC_AMD64_VERSION "\n"); + + opstate_init(); + + if (cache_k8_northbridges() < 0) + goto err_exit; + + err = pci_register_driver(&amd64_pci_driver); + if (err) + return err; + + /* + * At this point, the array 'pvt_lookup[]' contains pointers to alloc'd + * amd64_pvt structs. These will be used in the 2nd stage init function + * to finish initialization of the MC instances. + */ + for (nb = 0; nb < num_k8_northbridges; nb++) { + if (!pvt_lookup[nb]) + continue; + + err = amd64_init_2nd_stage(pvt_lookup[nb]); + if (err) + goto err_exit; + } + + amd64_setup_pci_device(); + + return 0; + +err_exit: + debugf0("'finish_setup' stage failed\n"); + pci_unregister_driver(&amd64_pci_driver); + + return err; +} + +static void __exit amd64_edac_exit(void) +{ + if (amd64_ctl_pci) + edac_pci_release_generic_ctl(amd64_ctl_pci); + + pci_unregister_driver(&amd64_pci_driver); +} + +module_init(amd64_edac_init); +module_exit(amd64_edac_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("SoftwareBitMaker: Doug Thompson, " + "Dave Peterson, Thayne Harbaugh"); +MODULE_DESCRIPTION("MC support for AMD64 memory controllers - " + EDAC_AMD64_VERSION); + +module_param(edac_op_state, int, 0444); +MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI"); diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h new file mode 100644 index 000000000000..a159957e167b --- /dev/null +++ b/drivers/edac/amd64_edac.h @@ -0,0 +1,644 @@ +/* + * AMD64 class Memory Controller kernel module + * + * Copyright (c) 2009 SoftwareBitMaker. + * Copyright (c) 2009 Advanced Micro Devices, Inc. + * + * This file may be distributed under the terms of the + * GNU General Public License. + * + * Originally Written by Thayne Harbaugh + * + * Changes by Douglas "norsk" Thompson : + * - K8 CPU Revision D and greater support + * + * Changes by Dave Peterson : + * - Module largely rewritten, with new (and hopefully correct) + * code for dealing with node and chip select interleaving, + * various code cleanup, and bug fixes + * - Added support for memory hoisting using DRAM hole address + * register + * + * Changes by Douglas "norsk" Thompson : + * -K8 Rev (1207) revision support added, required Revision + * specific mini-driver code to support Rev F as well as + * prior revisions + * + * Changes by Douglas "norsk" Thompson : + * -Family 10h revision support added. New PCI Device IDs, + * indicating new changes. Actual registers modified + * were slight, less than the Rev E to Rev F transition + * but changing the PCI Device ID was the proper thing to + * do, as it provides for almost automactic family + * detection. The mods to Rev F required more family + * information detection. + * + * Changes/Fixes by Borislav Petkov : + * - misc fixes and code cleanups + * + * This module is based on the following documents + * (available from http://www.amd.com/): + * + * Title: BIOS and Kernel Developer's Guide for AMD Athlon 64 and AMD + * Opteron Processors + * AMD publication #: 26094 + *` Revision: 3.26 + * + * Title: BIOS and Kernel Developer's Guide for AMD NPT Family 0Fh + * Processors + * AMD publication #: 32559 + * Revision: 3.00 + * Issue Date: May 2006 + * + * Title: BIOS and Kernel Developer's Guide (BKDG) For AMD Family 10h + * Processors + * AMD publication #: 31116 + * Revision: 3.00 + * Issue Date: September 07, 2007 + * + * Sections in the first 2 documents are no longer in sync with each other. + * The Family 10h BKDG was totally re-written from scratch with a new + * presentation model. + * Therefore, comments that refer to a Document section might be off. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "edac_core.h" + +#define amd64_printk(level, fmt, arg...) \ + edac_printk(level, "amd64", fmt, ##arg) + +#define amd64_mc_printk(mci, level, fmt, arg...) \ + edac_mc_chipset_printk(mci, level, "amd64", fmt, ##arg) + +/* + * Throughout the comments in this code, the following terms are used: + * + * SysAddr, DramAddr, and InputAddr + * + * These terms come directly from the amd64 documentation + * (AMD publication #26094). They are defined as follows: + * + * SysAddr: + * This is a physical address generated by a CPU core or a device + * doing DMA. If generated by a CPU core, a SysAddr is the result of + * a virtual to physical address translation by the CPU core's address + * translation mechanism (MMU). + * + * DramAddr: + * A DramAddr is derived from a SysAddr by subtracting an offset that + * depends on which node the SysAddr maps to and whether the SysAddr + * is within a range affected by memory hoisting. The DRAM Base + * (section 3.4.4.1) and DRAM Limit (section 3.4.4.2) registers + * determine which node a SysAddr maps to. + * + * If the DRAM Hole Address Register (DHAR) is enabled and the SysAddr + * is within the range of addresses specified by this register, then + * a value x from the DHAR is subtracted from the SysAddr to produce a + * DramAddr. Here, x represents the base address for the node that + * the SysAddr maps to plus an offset due to memory hoisting. See + * section 3.4.8 and the comments in amd64_get_dram_hole_info() and + * sys_addr_to_dram_addr() below for more information. + * + * If the SysAddr is not affected by the DHAR then a value y is + * subtracted from the SysAddr to produce a DramAddr. Here, y is the + * base address for the node that the SysAddr maps to. See section + * 3.4.4 and the comments in sys_addr_to_dram_addr() below for more + * information. + * + * InputAddr: + * A DramAddr is translated to an InputAddr before being passed to the + * memory controller for the node that the DramAddr is associated + * with. The memory controller then maps the InputAddr to a csrow. + * If node interleaving is not in use, then the InputAddr has the same + * value as the DramAddr. Otherwise, the InputAddr is produced by + * discarding the bits used for node interleaving from the DramAddr. + * See section 3.4.4 for more information. + * + * The memory controller for a given node uses its DRAM CS Base and + * DRAM CS Mask registers to map an InputAddr to a csrow. See + * sections 3.5.4 and 3.5.5 for more information. + */ + +#define EDAC_AMD64_VERSION " Ver: 3.2.0 " __DATE__ +#define EDAC_MOD_STR "amd64_edac" + +/* Extended Model from CPUID, for CPU Revision numbers */ +#define OPTERON_CPU_LE_REV_C 0 +#define OPTERON_CPU_REV_D 1 +#define OPTERON_CPU_REV_E 2 + +/* NPT processors have the following Extended Models */ +#define OPTERON_CPU_REV_F 4 +#define OPTERON_CPU_REV_FA 5 + +/* Hardware limit on ChipSelect rows per MC and processors per system */ +#define CHIPSELECT_COUNT 8 +#define DRAM_REG_COUNT 8 + + +/* + * PCI-defined configuration space registers + */ + + +/* + * Function 1 - Address Map + */ +#define K8_DRAM_BASE_LOW 0x40 +#define K8_DRAM_LIMIT_LOW 0x44 +#define K8_DHAR 0xf0 + +#define DHAR_VALID BIT(0) +#define F10_DRAM_MEM_HOIST_VALID BIT(1) + +#define DHAR_BASE_MASK 0xff000000 +#define dhar_base(dhar) (dhar & DHAR_BASE_MASK) + +#define K8_DHAR_OFFSET_MASK 0x0000ff00 +#define k8_dhar_offset(dhar) ((dhar & K8_DHAR_OFFSET_MASK) << 16) + +#define F10_DHAR_OFFSET_MASK 0x0000ff80 + /* NOTE: Extra mask bit vs K8 */ +#define f10_dhar_offset(dhar) ((dhar & F10_DHAR_OFFSET_MASK) << 16) + + +/* F10 High BASE/LIMIT registers */ +#define F10_DRAM_BASE_HIGH 0x140 +#define F10_DRAM_LIMIT_HIGH 0x144 + + +/* + * Function 2 - DRAM controller + */ +#define K8_DCSB0 0x40 +#define F10_DCSB1 0x140 + +#define K8_DCSB_CS_ENABLE BIT(0) +#define K8_DCSB_NPT_SPARE BIT(1) +#define K8_DCSB_NPT_TESTFAIL BIT(2) + +/* + * REV E: select [31:21] and [15:9] from DCSB and the shift amount to form + * the address + */ +#define REV_E_DCSB_BASE_BITS (0xFFE0FE00ULL) +#define REV_E_DCS_SHIFT 4 +#define REV_E_DCSM_COUNT 8 + +#define REV_F_F1Xh_DCSB_BASE_BITS (0x1FF83FE0ULL) +#define REV_F_F1Xh_DCS_SHIFT 8 + +/* + * REV F and later: selects [28:19] and [13:5] from DCSB and the shift amount + * to form the address + */ +#define REV_F_DCSB_BASE_BITS (0x1FF83FE0ULL) +#define REV_F_DCS_SHIFT 8 +#define REV_F_DCSM_COUNT 4 +#define F10_DCSM_COUNT 4 +#define F11_DCSM_COUNT 2 + +/* DRAM CS Mask Registers */ +#define K8_DCSM0 0x60 +#define F10_DCSM1 0x160 + +/* REV E: select [29:21] and [15:9] from DCSM */ +#define REV_E_DCSM_MASK_BITS 0x3FE0FE00 + +/* unused bits [24:20] and [12:0] */ +#define REV_E_DCS_NOTUSED_BITS 0x01F01FFF + +/* REV F and later: select [28:19] and [13:5] from DCSM */ +#define REV_F_F1Xh_DCSM_MASK_BITS 0x1FF83FE0 + +/* unused bits [26:22] and [12:0] */ +#define REV_F_F1Xh_DCS_NOTUSED_BITS 0x07C01FFF + +#define DBAM0 0x80 +#define DBAM1 0x180 + +/* Extract the DIMM 'type' on the i'th DIMM from the DBAM reg value passed */ +#define DBAM_DIMM(i, reg) ((((reg) >> (4*i))) & 0xF) + +#define DBAM_MAX_VALUE 11 + + +#define F10_DCLR_0 0x90 +#define F10_DCLR_1 0x190 +#define REVE_WIDTH_128 BIT(16) +#define F10_WIDTH_128 BIT(11) + + +#define F10_DCHR_0 0x94 +#define F10_DCHR_1 0x194 + +#define F10_DCHR_FOUR_RANK_DIMM BIT(18) +#define F10_DCHR_Ddr3Mode BIT(8) +#define F10_DCHR_MblMode BIT(6) + + +#define F10_DCTL_SEL_LOW 0x110 + +#define dct_sel_baseaddr(pvt) \ + ((pvt->dram_ctl_select_low) & 0xFFFFF800) + +#define dct_sel_interleave_addr(pvt) \ + (((pvt->dram_ctl_select_low) >> 6) & 0x3) + +enum { + F10_DCTL_SEL_LOW_DctSelHiRngEn = BIT(0), + F10_DCTL_SEL_LOW_DctSelIntLvEn = BIT(2), + F10_DCTL_SEL_LOW_DctGangEn = BIT(4), + F10_DCTL_SEL_LOW_DctDatIntLv = BIT(5), + F10_DCTL_SEL_LOW_DramEnable = BIT(8), + F10_DCTL_SEL_LOW_MemCleared = BIT(10), +}; + +#define dct_high_range_enabled(pvt) \ + (pvt->dram_ctl_select_low & F10_DCTL_SEL_LOW_DctSelHiRngEn) + +#define dct_interleave_enabled(pvt) \ + (pvt->dram_ctl_select_low & F10_DCTL_SEL_LOW_DctSelIntLvEn) + +#define dct_ganging_enabled(pvt) \ + (pvt->dram_ctl_select_low & F10_DCTL_SEL_LOW_DctGangEn) + +#define dct_data_intlv_enabled(pvt) \ + (pvt->dram_ctl_select_low & F10_DCTL_SEL_LOW_DctDatIntLv) + +#define dct_dram_enabled(pvt) \ + (pvt->dram_ctl_select_low & F10_DCTL_SEL_LOW_DramEnable) + +#define dct_memory_cleared(pvt) \ + (pvt->dram_ctl_select_low & F10_DCTL_SEL_LOW_MemCleared) + + +#define F10_DCTL_SEL_HIGH 0x114 + + +/* + * Function 3 - Misc Control + */ +#define K8_NBCTL 0x40 + +/* Correctable ECC error reporting enable */ +#define K8_NBCTL_CECCEn BIT(0) + +/* UnCorrectable ECC error reporting enable */ +#define K8_NBCTL_UECCEn BIT(1) + +#define K8_NBCFG 0x44 +#define K8_NBCFG_CHIPKILL BIT(23) +#define K8_NBCFG_ECC_ENABLE BIT(22) + +#define K8_NBSL 0x48 + + +#define EXTRACT_HIGH_SYNDROME(x) (((x) >> 24) & 0xff) +#define EXTRACT_EXT_ERROR_CODE(x) (((x) >> 16) & 0x1f) + +/* Family F10h: Normalized Extended Error Codes */ +#define F10_NBSL_EXT_ERR_RES 0x0 +#define F10_NBSL_EXT_ERR_CRC 0x1 +#define F10_NBSL_EXT_ERR_SYNC 0x2 +#define F10_NBSL_EXT_ERR_MST 0x3 +#define F10_NBSL_EXT_ERR_TGT 0x4 +#define F10_NBSL_EXT_ERR_GART 0x5 +#define F10_NBSL_EXT_ERR_RMW 0x6 +#define F10_NBSL_EXT_ERR_WDT 0x7 +#define F10_NBSL_EXT_ERR_ECC 0x8 +#define F10_NBSL_EXT_ERR_DEV 0x9 +#define F10_NBSL_EXT_ERR_LINK_DATA 0xA + +/* Next two are overloaded values */ +#define F10_NBSL_EXT_ERR_LINK_PROTO 0xB +#define F10_NBSL_EXT_ERR_L3_PROTO 0xB + +#define F10_NBSL_EXT_ERR_NB_ARRAY 0xC +#define F10_NBSL_EXT_ERR_DRAM_PARITY 0xD +#define F10_NBSL_EXT_ERR_LINK_RETRY 0xE + +/* Next two are overloaded values */ +#define F10_NBSL_EXT_ERR_GART_WALK 0xF +#define F10_NBSL_EXT_ERR_DEV_WALK 0xF + +/* 0x10 to 0x1B: Reserved */ +#define F10_NBSL_EXT_ERR_L3_DATA 0x1C +#define F10_NBSL_EXT_ERR_L3_TAG 0x1D +#define F10_NBSL_EXT_ERR_L3_LRU 0x1E + +/* K8: Normalized Extended Error Codes */ +#define K8_NBSL_EXT_ERR_ECC 0x0 +#define K8_NBSL_EXT_ERR_CRC 0x1 +#define K8_NBSL_EXT_ERR_SYNC 0x2 +#define K8_NBSL_EXT_ERR_MST 0x3 +#define K8_NBSL_EXT_ERR_TGT 0x4 +#define K8_NBSL_EXT_ERR_GART 0x5 +#define K8_NBSL_EXT_ERR_RMW 0x6 +#define K8_NBSL_EXT_ERR_WDT 0x7 +#define K8_NBSL_EXT_ERR_CHIPKILL_ECC 0x8 +#define K8_NBSL_EXT_ERR_DRAM_PARITY 0xD + +#define EXTRACT_ERROR_CODE(x) ((x) & 0xffff) +#define TEST_TLB_ERROR(x) (((x) & 0xFFF0) == 0x0010) +#define TEST_MEM_ERROR(x) (((x) & 0xFF00) == 0x0100) +#define TEST_BUS_ERROR(x) (((x) & 0xF800) == 0x0800) +#define EXTRACT_TT_CODE(x) (((x) >> 2) & 0x3) +#define EXTRACT_II_CODE(x) (((x) >> 2) & 0x3) +#define EXTRACT_LL_CODE(x) (((x) >> 0) & 0x3) +#define EXTRACT_RRRR_CODE(x) (((x) >> 4) & 0xf) +#define EXTRACT_TO_CODE(x) (((x) >> 8) & 0x1) +#define EXTRACT_PP_CODE(x) (((x) >> 9) & 0x3) + +/* + * The following are for BUS type errors AFTER values have been normalized by + * shifting right + */ +#define K8_NBSL_PP_SRC 0x0 +#define K8_NBSL_PP_RES 0x1 +#define K8_NBSL_PP_OBS 0x2 +#define K8_NBSL_PP_GENERIC 0x3 + + +#define K8_NBSH 0x4C + +#define K8_NBSH_VALID_BIT BIT(31) +#define K8_NBSH_OVERFLOW BIT(30) +#define K8_NBSH_UNCORRECTED_ERR BIT(29) +#define K8_NBSH_ERR_ENABLE BIT(28) +#define K8_NBSH_MISC_ERR_VALID BIT(27) +#define K8_NBSH_VALID_ERROR_ADDR BIT(26) +#define K8_NBSH_PCC BIT(25) +#define K8_NBSH_CECC BIT(14) +#define K8_NBSH_UECC BIT(13) +#define K8_NBSH_ERR_SCRUBER BIT(8) +#define K8_NBSH_CORE3 BIT(3) +#define K8_NBSH_CORE2 BIT(2) +#define K8_NBSH_CORE1 BIT(1) +#define K8_NBSH_CORE0 BIT(0) + +#define EXTRACT_LDT_LINK(x) (((x) >> 4) & 0x7) +#define EXTRACT_ERR_CPU_MAP(x) ((x) & 0xF) +#define EXTRACT_LOW_SYNDROME(x) (((x) >> 15) & 0xff) + + +#define K8_NBEAL 0x50 +#define K8_NBEAH 0x54 +#define K8_SCRCTRL 0x58 + +#define F10_NB_CFG_LOW 0x88 +#define F10_NB_CFG_LOW_ENABLE_EXT_CFG BIT(14) + +#define F10_NB_CFG_HIGH 0x8C + +#define F10_ONLINE_SPARE 0xB0 +#define F10_ONLINE_SPARE_SWAPDONE0(x) ((x) & BIT(1)) +#define F10_ONLINE_SPARE_SWAPDONE1(x) ((x) & BIT(3)) +#define F10_ONLINE_SPARE_BADDRAM_CS0(x) (((x) >> 4) & 0x00000007) +#define F10_ONLINE_SPARE_BADDRAM_CS1(x) (((x) >> 8) & 0x00000007) + +#define F10_NB_ARRAY_ADDR 0xB8 + +#define F10_NB_ARRAY_DRAM_ECC 0x80000000 + +/* Bits [2:1] are used to select 16-byte section within a 64-byte cacheline */ +#define SET_NB_ARRAY_ADDRESS(section) (((section) & 0x3) << 1) + +#define F10_NB_ARRAY_DATA 0xBC + +#define SET_NB_DRAM_INJECTION_WRITE(word, bits) \ + (BIT(((word) & 0xF) + 20) | \ + BIT(17) | \ + ((bits) & 0xF)) + +#define SET_NB_DRAM_INJECTION_READ(word, bits) \ + (BIT(((word) & 0xF) + 20) | \ + BIT(16) | \ + ((bits) & 0xF)) + +#define K8_NBCAP 0xE8 +#define K8_NBCAP_CORES (BIT(12)|BIT(13)) +#define K8_NBCAP_CHIPKILL BIT(4) +#define K8_NBCAP_SECDED BIT(3) +#define K8_NBCAP_8_NODE BIT(2) +#define K8_NBCAP_DUAL_NODE BIT(1) +#define K8_NBCAP_DCT_DUAL BIT(0) + +/* + * MSR Regs + */ +#define K8_MSR_MCGCTL 0x017b +#define K8_MSR_MCGCTL_NBE BIT(4) + +#define K8_MSR_MC4CTL 0x0410 +#define K8_MSR_MC4STAT 0x0411 +#define K8_MSR_MC4ADDR 0x0412 + +/* AMD sets the first MC device at device ID 0x18. */ +static inline int get_mc_node_id_from_pdev(struct pci_dev *pdev) +{ + return PCI_SLOT(pdev->devfn) - 0x18; +} + +enum amd64_chipset_families { + K8_CPUS = 0, + F10_CPUS, + F11_CPUS, +}; + +/* + * Structure to hold: + * + * 1) dynamically read status and error address HW registers + * 2) sysfs entered values + * 3) MCE values + * + * Depends on entry into the modules + */ +struct amd64_error_info_regs { + u32 nbcfg; + u32 nbsh; + u32 nbsl; + u32 nbeah; + u32 nbeal; +}; + +/* Error injection control structure */ +struct error_injection { + u32 section; + u32 word; + u32 bit_map; +}; + +struct amd64_pvt { + /* pci_device handles which we utilize */ + struct pci_dev *addr_f1_ctl; + struct pci_dev *dram_f2_ctl; + struct pci_dev *misc_f3_ctl; + + int mc_node_id; /* MC index of this MC node */ + int ext_model; /* extended model value of this node */ + + struct low_ops *ops; /* pointer to per PCI Device ID func table */ + + int channel_count; + + /* Raw registers */ + u32 dclr0; /* DRAM Configuration Low DCT0 reg */ + u32 dclr1; /* DRAM Configuration Low DCT1 reg */ + u32 dchr0; /* DRAM Configuration High DCT0 reg */ + u32 dchr1; /* DRAM Configuration High DCT1 reg */ + u32 nbcap; /* North Bridge Capabilities */ + u32 nbcfg; /* F10 North Bridge Configuration */ + u32 ext_nbcfg; /* Extended F10 North Bridge Configuration */ + u32 dhar; /* DRAM Hoist reg */ + u32 dbam0; /* DRAM Base Address Mapping reg for DCT0 */ + u32 dbam1; /* DRAM Base Address Mapping reg for DCT1 */ + + /* DRAM CS Base Address Registers F2x[1,0][5C:40] */ + u32 dcsb0[CHIPSELECT_COUNT]; + u32 dcsb1[CHIPSELECT_COUNT]; + + /* DRAM CS Mask Registers F2x[1,0][6C:60] */ + u32 dcsm0[CHIPSELECT_COUNT]; + u32 dcsm1[CHIPSELECT_COUNT]; + + /* + * Decoded parts of DRAM BASE and LIMIT Registers + * F1x[78,70,68,60,58,50,48,40] + */ + u64 dram_base[DRAM_REG_COUNT]; + u64 dram_limit[DRAM_REG_COUNT]; + u8 dram_IntlvSel[DRAM_REG_COUNT]; + u8 dram_IntlvEn[DRAM_REG_COUNT]; + u8 dram_DstNode[DRAM_REG_COUNT]; + u8 dram_rw_en[DRAM_REG_COUNT]; + + /* + * The following fields are set at (load) run time, after CPU revision + * has been determined, since the dct_base and dct_mask registers vary + * based on revision + */ + u32 dcsb_base; /* DCSB base bits */ + u32 dcsm_mask; /* DCSM mask bits */ + u32 num_dcsm; /* Number of DCSM registers */ + u32 dcs_mask_notused; /* DCSM notused mask bits */ + u32 dcs_shift; /* DCSB and DCSM shift value */ + + u64 top_mem; /* top of memory below 4GB */ + u64 top_mem2; /* top of memory above 4GB */ + + u32 dram_ctl_select_low; /* DRAM Controller Select Low Reg */ + u32 dram_ctl_select_high; /* DRAM Controller Select High Reg */ + u32 online_spare; /* On-Line spare Reg */ + + /* temp storage for when input is received from sysfs */ + struct amd64_error_info_regs ctl_error_info; + + /* place to store error injection parameters prior to issue */ + struct error_injection injection; + + /* Save old hw registers' values before we modified them */ + u32 nbctl_mcgctl_saved; /* When true, following 2 are valid */ + u32 old_nbctl; + unsigned long old_mcgctl; /* per core on this node */ + + /* MC Type Index value: socket F vs Family 10h */ + u32 mc_type_index; + + /* misc settings */ + struct flags { + unsigned long cf8_extcfg:1; + } flags; +}; + +struct scrubrate { + u32 scrubval; /* bit pattern for scrub rate */ + u32 bandwidth; /* bandwidth consumed (bytes/sec) */ +}; + +extern struct scrubrate scrubrates[23]; +extern u32 revf_quad_ddr2_shift[16]; +extern const char *tt_msgs[4]; +extern const char *ll_msgs[4]; +extern const char *rrrr_msgs[16]; +extern const char *to_msgs[2]; +extern const char *pp_msgs[4]; +extern const char *ii_msgs[4]; +extern const char *ext_msgs[32]; +extern const char *htlink_msgs[8]; + +#ifdef CONFIG_EDAC_DEBUG +#define NUM_DBG_ATTRS 9 +#else +#define NUM_DBG_ATTRS 0 +#endif + +#ifdef CONFIG_EDAC_AMD64_ERROR_INJECTION +#define NUM_INJ_ATTRS 5 +#else +#define NUM_INJ_ATTRS 0 +#endif + +extern struct mcidev_sysfs_attribute amd64_dbg_attrs[NUM_DBG_ATTRS], + amd64_inj_attrs[NUM_INJ_ATTRS]; + +/* + * Each of the PCI Device IDs types have their own set of hardware accessor + * functions and per device encoding/decoding logic. + */ +struct low_ops { + int (*probe_valid_hardware)(struct amd64_pvt *pvt); + int (*early_channel_count)(struct amd64_pvt *pvt); + + u64 (*get_error_address)(struct mem_ctl_info *mci, + struct amd64_error_info_regs *info); + void (*read_dram_base_limit)(struct amd64_pvt *pvt, int dram); + void (*read_dram_ctl_register)(struct amd64_pvt *pvt); + void (*map_sysaddr_to_csrow)(struct mem_ctl_info *mci, + struct amd64_error_info_regs *info, + u64 SystemAddr); + int (*dbam_map_to_pages)(struct amd64_pvt *pvt, int dram_map); +}; + +struct amd64_family_type { + const char *ctl_name; + u16 addr_f1_ctl; + u16 misc_f3_ctl; + struct low_ops ops; +}; + +static struct amd64_family_type amd64_family_types[]; + +static inline const char *get_amd_family_name(int index) +{ + return amd64_family_types[index].ctl_name; +} + +static inline struct low_ops *family_ops(int index) +{ + return &amd64_family_types[index].ops; +} + +/* + * For future CPU versions, verify the following as new 'slow' rates appear and + * modify the necessary skip values for the supported CPU. + */ +#define K8_MIN_SCRUB_RATE_BITS 0x0 +#define F10_MIN_SCRUB_RATE_BITS 0x5 +#define F11_MIN_SCRUB_RATE_BITS 0x6 + +int amd64_process_error_info(struct mem_ctl_info *mci, + struct amd64_error_info_regs *info, + int handle_errors); +int amd64_get_dram_hole_info(struct mem_ctl_info *mci, u64 *hole_base, + u64 *hole_offset, u64 *hole_size); diff --git a/drivers/edac/amd64_edac_dbg.c b/drivers/edac/amd64_edac_dbg.c new file mode 100644 index 000000000000..0a41b248a4ad --- /dev/null +++ b/drivers/edac/amd64_edac_dbg.c @@ -0,0 +1,255 @@ +#include "amd64_edac.h" + +/* + * accept a hex value and store it into the virtual error register file, field: + * nbeal and nbeah. Assume virtual error values have already been set for: NBSL, + * NBSH and NBCFG. Then proceed to map the error values to a MC, CSROW and + * CHANNEL + */ +static ssize_t amd64_nbea_store(struct mem_ctl_info *mci, const char *data, + size_t count) +{ + struct amd64_pvt *pvt = mci->pvt_info; + unsigned long long value; + int ret = 0; + + ret = strict_strtoull(data, 16, &value); + if (ret != -EINVAL) { + debugf0("received NBEA= 0x%llx\n", value); + + /* place the value into the virtual error packet */ + pvt->ctl_error_info.nbeal = (u32) value; + value >>= 32; + pvt->ctl_error_info.nbeah = (u32) value; + + /* Process the Mapping request */ + /* TODO: Add race prevention */ + amd64_process_error_info(mci, &pvt->ctl_error_info, 1); + + return count; + } + return ret; +} + +/* display back what the last NBEA (MCA NB Address (MC4_ADDR)) was written */ +static ssize_t amd64_nbea_show(struct mem_ctl_info *mci, char *data) +{ + struct amd64_pvt *pvt = mci->pvt_info; + u64 value; + + value = pvt->ctl_error_info.nbeah; + value <<= 32; + value |= pvt->ctl_error_info.nbeal; + + return sprintf(data, "%llx\n", value); +} + +/* store the NBSL (MCA NB Status Low (MC4_STATUS)) value user desires */ +static ssize_t amd64_nbsl_store(struct mem_ctl_info *mci, const char *data, + size_t count) +{ + struct amd64_pvt *pvt = mci->pvt_info; + unsigned long value; + int ret = 0; + + ret = strict_strtoul(data, 16, &value); + if (ret != -EINVAL) { + debugf0("received NBSL= 0x%lx\n", value); + + pvt->ctl_error_info.nbsl = (u32) value; + + return count; + } + return ret; +} + +/* display back what the last NBSL value written */ +static ssize_t amd64_nbsl_show(struct mem_ctl_info *mci, char *data) +{ + struct amd64_pvt *pvt = mci->pvt_info; + u32 value; + + value = pvt->ctl_error_info.nbsl; + + return sprintf(data, "%x\n", value); +} + +/* store the NBSH (MCA NB Status High) value user desires */ +static ssize_t amd64_nbsh_store(struct mem_ctl_info *mci, const char *data, + size_t count) +{ + struct amd64_pvt *pvt = mci->pvt_info; + unsigned long value; + int ret = 0; + + ret = strict_strtoul(data, 16, &value); + if (ret != -EINVAL) { + debugf0("received NBSH= 0x%lx\n", value); + + pvt->ctl_error_info.nbsh = (u32) value; + + return count; + } + return ret; +} + +/* display back what the last NBSH value written */ +static ssize_t amd64_nbsh_show(struct mem_ctl_info *mci, char *data) +{ + struct amd64_pvt *pvt = mci->pvt_info; + u32 value; + + value = pvt->ctl_error_info.nbsh; + + return sprintf(data, "%x\n", value); +} + +/* accept and store the NBCFG (MCA NB Configuration) value user desires */ +static ssize_t amd64_nbcfg_store(struct mem_ctl_info *mci, + const char *data, size_t count) +{ + struct amd64_pvt *pvt = mci->pvt_info; + unsigned long value; + int ret = 0; + + ret = strict_strtoul(data, 16, &value); + if (ret != -EINVAL) { + debugf0("received NBCFG= 0x%lx\n", value); + + pvt->ctl_error_info.nbcfg = (u32) value; + + return count; + } + return ret; +} + +/* various show routines for the controls of a MCI */ +static ssize_t amd64_nbcfg_show(struct mem_ctl_info *mci, char *data) +{ + struct amd64_pvt *pvt = mci->pvt_info; + + return sprintf(data, "%x\n", pvt->ctl_error_info.nbcfg); +} + + +static ssize_t amd64_dhar_show(struct mem_ctl_info *mci, char *data) +{ + struct amd64_pvt *pvt = mci->pvt_info; + + return sprintf(data, "%x\n", pvt->dhar); +} + + +static ssize_t amd64_dbam_show(struct mem_ctl_info *mci, char *data) +{ + struct amd64_pvt *pvt = mci->pvt_info; + + return sprintf(data, "%x\n", pvt->dbam0); +} + + +static ssize_t amd64_topmem_show(struct mem_ctl_info *mci, char *data) +{ + struct amd64_pvt *pvt = mci->pvt_info; + + return sprintf(data, "%llx\n", pvt->top_mem); +} + + +static ssize_t amd64_topmem2_show(struct mem_ctl_info *mci, char *data) +{ + struct amd64_pvt *pvt = mci->pvt_info; + + return sprintf(data, "%llx\n", pvt->top_mem2); +} + +static ssize_t amd64_hole_show(struct mem_ctl_info *mci, char *data) +{ + u64 hole_base = 0; + u64 hole_offset = 0; + u64 hole_size = 0; + + amd64_get_dram_hole_info(mci, &hole_base, &hole_offset, &hole_size); + + return sprintf(data, "%llx %llx %llx\n", hole_base, hole_offset, + hole_size); +} + +/* + * update NUM_DBG_ATTRS in case you add new members + */ +struct mcidev_sysfs_attribute amd64_dbg_attrs[] = { + + { + .attr = { + .name = "nbea_ctl", + .mode = (S_IRUGO | S_IWUSR) + }, + .show = amd64_nbea_show, + .store = amd64_nbea_store, + }, + { + .attr = { + .name = "nbsl_ctl", + .mode = (S_IRUGO | S_IWUSR) + }, + .show = amd64_nbsl_show, + .store = amd64_nbsl_store, + }, + { + .attr = { + .name = "nbsh_ctl", + .mode = (S_IRUGO | S_IWUSR) + }, + .show = amd64_nbsh_show, + .store = amd64_nbsh_store, + }, + { + .attr = { + .name = "nbcfg_ctl", + .mode = (S_IRUGO | S_IWUSR) + }, + .show = amd64_nbcfg_show, + .store = amd64_nbcfg_store, + }, + { + .attr = { + .name = "dhar", + .mode = (S_IRUGO) + }, + .show = amd64_dhar_show, + .store = NULL, + }, + { + .attr = { + .name = "dbam", + .mode = (S_IRUGO) + }, + .show = amd64_dbam_show, + .store = NULL, + }, + { + .attr = { + .name = "topmem", + .mode = (S_IRUGO) + }, + .show = amd64_topmem_show, + .store = NULL, + }, + { + .attr = { + .name = "topmem2", + .mode = (S_IRUGO) + }, + .show = amd64_topmem2_show, + .store = NULL, + }, + { + .attr = { + .name = "dram_hole", + .mode = (S_IRUGO) + }, + .show = amd64_hole_show, + .store = NULL, + }, +}; diff --git a/drivers/edac/amd64_edac_err_types.c b/drivers/edac/amd64_edac_err_types.c new file mode 100644 index 000000000000..f212ff12a9d8 --- /dev/null +++ b/drivers/edac/amd64_edac_err_types.c @@ -0,0 +1,161 @@ +#include "amd64_edac.h" + +/* + * See F2x80 for K8 and F2x[1,0]80 for Fam10 and later. The table below is only + * for DDR2 DRAM mapping. + */ +u32 revf_quad_ddr2_shift[] = { + 0, /* 0000b NULL DIMM (128mb) */ + 28, /* 0001b 256mb */ + 29, /* 0010b 512mb */ + 29, /* 0011b 512mb */ + 29, /* 0100b 512mb */ + 30, /* 0101b 1gb */ + 30, /* 0110b 1gb */ + 31, /* 0111b 2gb */ + 31, /* 1000b 2gb */ + 32, /* 1001b 4gb */ + 32, /* 1010b 4gb */ + 33, /* 1011b 8gb */ + 0, /* 1100b future */ + 0, /* 1101b future */ + 0, /* 1110b future */ + 0 /* 1111b future */ +}; + +/* + * Valid scrub rates for the K8 hardware memory scrubber. We map the scrubbing + * bandwidth to a valid bit pattern. The 'set' operation finds the 'matching- + * or higher value'. + * + *FIXME: Produce a better mapping/linearisation. + */ + +struct scrubrate scrubrates[] = { + { 0x01, 1600000000UL}, + { 0x02, 800000000UL}, + { 0x03, 400000000UL}, + { 0x04, 200000000UL}, + { 0x05, 100000000UL}, + { 0x06, 50000000UL}, + { 0x07, 25000000UL}, + { 0x08, 12284069UL}, + { 0x09, 6274509UL}, + { 0x0A, 3121951UL}, + { 0x0B, 1560975UL}, + { 0x0C, 781440UL}, + { 0x0D, 390720UL}, + { 0x0E, 195300UL}, + { 0x0F, 97650UL}, + { 0x10, 48854UL}, + { 0x11, 24427UL}, + { 0x12, 12213UL}, + { 0x13, 6101UL}, + { 0x14, 3051UL}, + { 0x15, 1523UL}, + { 0x16, 761UL}, + { 0x00, 0UL}, /* scrubbing off */ +}; + +/* + * string representation for the different MCA reported error types, see F3x48 + * or MSR0000_0411. + */ +const char *tt_msgs[] = { /* transaction type */ + "instruction", + "data", + "generic", + "reserved" +}; + +const char *ll_msgs[] = { /* cache level */ + "L0", + "L1", + "L2", + "L3/generic" +}; + +const char *rrrr_msgs[] = { + "generic", + "generic read", + "generic write", + "data read", + "data write", + "inst fetch", + "prefetch", + "evict", + "snoop", + "reserved RRRR= 9", + "reserved RRRR= 10", + "reserved RRRR= 11", + "reserved RRRR= 12", + "reserved RRRR= 13", + "reserved RRRR= 14", + "reserved RRRR= 15" +}; + +const char *pp_msgs[] = { /* participating processor */ + "local node originated (SRC)", + "local node responded to request (RES)", + "local node observed as 3rd party (OBS)", + "generic" +}; + +const char *to_msgs[] = { + "no timeout", + "timed out" +}; + +const char *ii_msgs[] = { /* memory or i/o */ + "mem access", + "reserved", + "i/o access", + "generic" +}; + +/* Map the 5 bits of Extended Error code to the string table. */ +const char *ext_msgs[] = { /* extended error */ + "K8 ECC error/F10 reserved", /* 0_0000b */ + "CRC error", /* 0_0001b */ + "sync error", /* 0_0010b */ + "mst abort", /* 0_0011b */ + "tgt abort", /* 0_0100b */ + "GART error", /* 0_0101b */ + "RMW error", /* 0_0110b */ + "Wdog timer error", /* 0_0111b */ + "F10-ECC/K8-Chipkill error", /* 0_1000b */ + "DEV Error", /* 0_1001b */ + "Link Data error", /* 0_1010b */ + "Link or L3 Protocol error", /* 0_1011b */ + "NB Array error", /* 0_1100b */ + "DRAM Parity error", /* 0_1101b */ + "Link Retry/GART Table Walk/DEV Table Walk error", /* 0_1110b */ + "Res 0x0ff error", /* 0_1111b */ + "Res 0x100 error", /* 1_0000b */ + "Res 0x101 error", /* 1_0001b */ + "Res 0x102 error", /* 1_0010b */ + "Res 0x103 error", /* 1_0011b */ + "Res 0x104 error", /* 1_0100b */ + "Res 0x105 error", /* 1_0101b */ + "Res 0x106 error", /* 1_0110b */ + "Res 0x107 error", /* 1_0111b */ + "Res 0x108 error", /* 1_1000b */ + "Res 0x109 error", /* 1_1001b */ + "Res 0x10A error", /* 1_1010b */ + "Res 0x10B error", /* 1_1011b */ + "L3 Cache Data error", /* 1_1100b */ + "L3 CacheTag error", /* 1_1101b */ + "L3 Cache LRU error", /* 1_1110b */ + "Res 0x1FF error" /* 1_1111b */ +}; + +const char *htlink_msgs[] = { + "none", + "1", + "2", + "1 2", + "3", + "1 3", + "2 3", + "1 2 3" +}; diff --git a/drivers/edac/amd64_edac_inj.c b/drivers/edac/amd64_edac_inj.c new file mode 100644 index 000000000000..d3675b76b3a7 --- /dev/null +++ b/drivers/edac/amd64_edac_inj.c @@ -0,0 +1,185 @@ +#include "amd64_edac.h" + +/* + * store error injection section value which refers to one of 4 16-byte sections + * within a 64-byte cacheline + * + * range: 0..3 + */ +static ssize_t amd64_inject_section_store(struct mem_ctl_info *mci, + const char *data, size_t count) +{ + struct amd64_pvt *pvt = mci->pvt_info; + unsigned long value; + int ret = 0; + + ret = strict_strtoul(data, 10, &value); + if (ret != -EINVAL) { + pvt->injection.section = (u32) value; + return count; + } + return ret; +} + +/* + * store error injection word value which refers to one of 9 16-bit word of the + * 16-byte (128-bit + ECC bits) section + * + * range: 0..8 + */ +static ssize_t amd64_inject_word_store(struct mem_ctl_info *mci, + const char *data, size_t count) +{ + struct amd64_pvt *pvt = mci->pvt_info; + unsigned long value; + int ret = 0; + + ret = strict_strtoul(data, 10, &value); + if (ret != -EINVAL) { + + value = (value <= 8) ? value : 0; + pvt->injection.word = (u32) value; + + return count; + } + return ret; +} + +/* + * store 16 bit error injection vector which enables injecting errors to the + * corresponding bit within the error injection word above. When used during a + * DRAM ECC read, it holds the contents of the of the DRAM ECC bits. + */ +static ssize_t amd64_inject_ecc_vector_store(struct mem_ctl_info *mci, + const char *data, size_t count) +{ + struct amd64_pvt *pvt = mci->pvt_info; + unsigned long value; + int ret = 0; + + ret = strict_strtoul(data, 16, &value); + if (ret != -EINVAL) { + + pvt->injection.bit_map = (u32) value & 0xFFFF; + + return count; + } + return ret; +} + +/* + * Do a DRAM ECC read. Assemble staged values in the pvt area, format into + * fields needed by the injection registers and read the NB Array Data Port. + */ +static ssize_t amd64_inject_read_store(struct mem_ctl_info *mci, + const char *data, size_t count) +{ + struct amd64_pvt *pvt = mci->pvt_info; + unsigned long value; + u32 section, word_bits; + int ret = 0; + + ret = strict_strtoul(data, 10, &value); + if (ret != -EINVAL) { + + /* Form value to choose 16-byte section of cacheline */ + section = F10_NB_ARRAY_DRAM_ECC | + SET_NB_ARRAY_ADDRESS(pvt->injection.section); + pci_write_config_dword(pvt->misc_f3_ctl, + F10_NB_ARRAY_ADDR, section); + + word_bits = SET_NB_DRAM_INJECTION_READ(pvt->injection.word, + pvt->injection.bit_map); + + /* Issue 'word' and 'bit' along with the READ request */ + pci_write_config_dword(pvt->misc_f3_ctl, + F10_NB_ARRAY_DATA, word_bits); + + debugf0("section=0x%x word_bits=0x%x\n", section, word_bits); + + return count; + } + return ret; +} + +/* + * Do a DRAM ECC write. Assemble staged values in the pvt area and format into + * fields needed by the injection registers. + */ +static ssize_t amd64_inject_write_store(struct mem_ctl_info *mci, + const char *data, size_t count) +{ + struct amd64_pvt *pvt = mci->pvt_info; + unsigned long value; + u32 section, word_bits; + int ret = 0; + + ret = strict_strtoul(data, 10, &value); + if (ret != -EINVAL) { + + /* Form value to choose 16-byte section of cacheline */ + section = F10_NB_ARRAY_DRAM_ECC | + SET_NB_ARRAY_ADDRESS(pvt->injection.section); + pci_write_config_dword(pvt->misc_f3_ctl, + F10_NB_ARRAY_ADDR, section); + + word_bits = SET_NB_DRAM_INJECTION_WRITE(pvt->injection.word, + pvt->injection.bit_map); + + /* Issue 'word' and 'bit' along with the READ request */ + pci_write_config_dword(pvt->misc_f3_ctl, + F10_NB_ARRAY_DATA, word_bits); + + debugf0("section=0x%x word_bits=0x%x\n", section, word_bits); + + return count; + } + return ret; +} + +/* + * update NUM_INJ_ATTRS in case you add new members + */ +struct mcidev_sysfs_attribute amd64_inj_attrs[] = { + + { + .attr = { + .name = "inject_section", + .mode = (S_IRUGO | S_IWUSR) + }, + .show = NULL, + .store = amd64_inject_section_store, + }, + { + .attr = { + .name = "inject_word", + .mode = (S_IRUGO | S_IWUSR) + }, + .show = NULL, + .store = amd64_inject_word_store, + }, + { + .attr = { + .name = "inject_ecc_vector", + .mode = (S_IRUGO | S_IWUSR) + }, + .show = NULL, + .store = amd64_inject_ecc_vector_store, + }, + { + .attr = { + .name = "inject_write", + .mode = (S_IRUGO | S_IWUSR) + }, + .show = NULL, + .store = amd64_inject_write_store, + }, + { + .attr = { + .name = "inject_read", + .mode = (S_IRUGO | S_IWUSR) + }, + .show = NULL, + .store = amd64_inject_read_store, + }, +}; diff --git a/drivers/edac/amd8111_edac.c b/drivers/edac/amd8111_edac.c index 2cb58ef743e0..35b78d04bbfa 100644 --- a/drivers/edac/amd8111_edac.c +++ b/drivers/edac/amd8111_edac.c @@ -37,7 +37,6 @@ #define AMD8111_EDAC_MOD_STR "amd8111_edac" #define PCI_DEVICE_ID_AMD_8111_PCI 0x7460 -static int edac_dev_idx; enum amd8111_edac_devs { LPC_BRIDGE = 0, @@ -377,7 +376,7 @@ static int amd8111_dev_probe(struct pci_dev *dev, * edac_device_ctl_info, but make use of existing * one instead. */ - dev_info->edac_idx = edac_dev_idx++; + dev_info->edac_idx = edac_device_alloc_index(); dev_info->edac_dev = edac_device_alloc_ctl_info(0, dev_info->ctl_name, 1, NULL, 0, 0, diff --git a/drivers/edac/cell_edac.c b/drivers/edac/cell_edac.c index cb0f639f049d..c973004c002c 100644 --- a/drivers/edac/cell_edac.c +++ b/drivers/edac/cell_edac.c @@ -227,7 +227,7 @@ static struct platform_driver cell_edac_driver = { .owner = THIS_MODULE, }, .probe = cell_edac_probe, - .remove = cell_edac_remove, + .remove = __devexit_p(cell_edac_remove), }; static int __init cell_edac_init(void) diff --git a/drivers/edac/cpc925_edac.c b/drivers/edac/cpc925_edac.c new file mode 100644 index 000000000000..8c54196b5aba --- /dev/null +++ b/drivers/edac/cpc925_edac.c @@ -0,0 +1,1017 @@ +/* + * cpc925_edac.c, EDAC driver for IBM CPC925 Bridge and Memory Controller. + * + * Copyright (c) 2008 Wind River Systems, Inc. + * + * Authors: Cao Qingtao + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include + +#include "edac_core.h" +#include "edac_module.h" + +#define CPC925_EDAC_REVISION " Ver: 1.0.0 " __DATE__ +#define CPC925_EDAC_MOD_STR "cpc925_edac" + +#define cpc925_printk(level, fmt, arg...) \ + edac_printk(level, "CPC925", fmt, ##arg) + +#define cpc925_mc_printk(mci, level, fmt, arg...) \ + edac_mc_chipset_printk(mci, level, "CPC925", fmt, ##arg) + +/* + * CPC925 registers are of 32 bits with bit0 defined at the + * most significant bit and bit31 at that of least significant. + */ +#define CPC925_BITS_PER_REG 32 +#define CPC925_BIT(nr) (1UL << (CPC925_BITS_PER_REG - 1 - nr)) + +/* + * EDAC device names for the error detections of + * CPU Interface and Hypertransport Link. + */ +#define CPC925_CPU_ERR_DEV "cpu" +#define CPC925_HT_LINK_DEV "htlink" + +/* Suppose DDR Refresh cycle is 15.6 microsecond */ +#define CPC925_REF_FREQ 0xFA69 +#define CPC925_SCRUB_BLOCK_SIZE 64 /* bytes */ +#define CPC925_NR_CSROWS 8 + +/* + * All registers and bits definitions are taken from + * "CPC925 Bridge and Memory Controller User Manual, SA14-2761-02". + */ + +/* + * CPU and Memory Controller Registers + */ +/************************************************************ + * Processor Interface Exception Mask Register (APIMASK) + ************************************************************/ +#define REG_APIMASK_OFFSET 0x30070 +enum apimask_bits { + APIMASK_DART = CPC925_BIT(0), /* DART Exception */ + APIMASK_ADI0 = CPC925_BIT(1), /* Handshake Error on PI0_ADI */ + APIMASK_ADI1 = CPC925_BIT(2), /* Handshake Error on PI1_ADI */ + APIMASK_STAT = CPC925_BIT(3), /* Status Exception */ + APIMASK_DERR = CPC925_BIT(4), /* Data Error Exception */ + APIMASK_ADRS0 = CPC925_BIT(5), /* Addressing Exception on PI0 */ + APIMASK_ADRS1 = CPC925_BIT(6), /* Addressing Exception on PI1 */ + /* BIT(7) Reserved */ + APIMASK_ECC_UE_H = CPC925_BIT(8), /* UECC upper */ + APIMASK_ECC_CE_H = CPC925_BIT(9), /* CECC upper */ + APIMASK_ECC_UE_L = CPC925_BIT(10), /* UECC lower */ + APIMASK_ECC_CE_L = CPC925_BIT(11), /* CECC lower */ + + CPU_MASK_ENABLE = (APIMASK_DART | APIMASK_ADI0 | APIMASK_ADI1 | + APIMASK_STAT | APIMASK_DERR | APIMASK_ADRS0 | + APIMASK_ADRS1), + ECC_MASK_ENABLE = (APIMASK_ECC_UE_H | APIMASK_ECC_CE_H | + APIMASK_ECC_UE_L | APIMASK_ECC_CE_L), +}; + +/************************************************************ + * Processor Interface Exception Register (APIEXCP) + ************************************************************/ +#define REG_APIEXCP_OFFSET 0x30060 +enum apiexcp_bits { + APIEXCP_DART = CPC925_BIT(0), /* DART Exception */ + APIEXCP_ADI0 = CPC925_BIT(1), /* Handshake Error on PI0_ADI */ + APIEXCP_ADI1 = CPC925_BIT(2), /* Handshake Error on PI1_ADI */ + APIEXCP_STAT = CPC925_BIT(3), /* Status Exception */ + APIEXCP_DERR = CPC925_BIT(4), /* Data Error Exception */ + APIEXCP_ADRS0 = CPC925_BIT(5), /* Addressing Exception on PI0 */ + APIEXCP_ADRS1 = CPC925_BIT(6), /* Addressing Exception on PI1 */ + /* BIT(7) Reserved */ + APIEXCP_ECC_UE_H = CPC925_BIT(8), /* UECC upper */ + APIEXCP_ECC_CE_H = CPC925_BIT(9), /* CECC upper */ + APIEXCP_ECC_UE_L = CPC925_BIT(10), /* UECC lower */ + APIEXCP_ECC_CE_L = CPC925_BIT(11), /* CECC lower */ + + CPU_EXCP_DETECTED = (APIEXCP_DART | APIEXCP_ADI0 | APIEXCP_ADI1 | + APIEXCP_STAT | APIEXCP_DERR | APIEXCP_ADRS0 | + APIEXCP_ADRS1), + UECC_EXCP_DETECTED = (APIEXCP_ECC_UE_H | APIEXCP_ECC_UE_L), + CECC_EXCP_DETECTED = (APIEXCP_ECC_CE_H | APIEXCP_ECC_CE_L), + ECC_EXCP_DETECTED = (UECC_EXCP_DETECTED | CECC_EXCP_DETECTED), +}; + +/************************************************************ + * Memory Bus Configuration Register (MBCR) +************************************************************/ +#define REG_MBCR_OFFSET 0x2190 +#define MBCR_64BITCFG_SHIFT 23 +#define MBCR_64BITCFG_MASK (1UL << MBCR_64BITCFG_SHIFT) +#define MBCR_64BITBUS_SHIFT 22 +#define MBCR_64BITBUS_MASK (1UL << MBCR_64BITBUS_SHIFT) + +/************************************************************ + * Memory Bank Mode Register (MBMR) +************************************************************/ +#define REG_MBMR_OFFSET 0x21C0 +#define MBMR_MODE_MAX_VALUE 0xF +#define MBMR_MODE_SHIFT 25 +#define MBMR_MODE_MASK (MBMR_MODE_MAX_VALUE << MBMR_MODE_SHIFT) +#define MBMR_BBA_SHIFT 24 +#define MBMR_BBA_MASK (1UL << MBMR_BBA_SHIFT) + +/************************************************************ + * Memory Bank Boundary Address Register (MBBAR) + ************************************************************/ +#define REG_MBBAR_OFFSET 0x21D0 +#define MBBAR_BBA_MAX_VALUE 0xFF +#define MBBAR_BBA_SHIFT 24 +#define MBBAR_BBA_MASK (MBBAR_BBA_MAX_VALUE << MBBAR_BBA_SHIFT) + +/************************************************************ + * Memory Scrub Control Register (MSCR) + ************************************************************/ +#define REG_MSCR_OFFSET 0x2400 +#define MSCR_SCRUB_MOD_MASK 0xC0000000 /* scrub_mod - bit0:1*/ +#define MSCR_BACKGR_SCRUB 0x40000000 /* 01 */ +#define MSCR_SI_SHIFT 16 /* si - bit8:15*/ +#define MSCR_SI_MAX_VALUE 0xFF +#define MSCR_SI_MASK (MSCR_SI_MAX_VALUE << MSCR_SI_SHIFT) + +/************************************************************ + * Memory Scrub Range Start Register (MSRSR) + ************************************************************/ +#define REG_MSRSR_OFFSET 0x2410 + +/************************************************************ + * Memory Scrub Range End Register (MSRER) + ************************************************************/ +#define REG_MSRER_OFFSET 0x2420 + +/************************************************************ + * Memory Scrub Pattern Register (MSPR) + ************************************************************/ +#define REG_MSPR_OFFSET 0x2430 + +/************************************************************ + * Memory Check Control Register (MCCR) + ************************************************************/ +#define REG_MCCR_OFFSET 0x2440 +enum mccr_bits { + MCCR_ECC_EN = CPC925_BIT(0), /* ECC high and low check */ +}; + +/************************************************************ + * Memory Check Range End Register (MCRER) + ************************************************************/ +#define REG_MCRER_OFFSET 0x2450 + +/************************************************************ + * Memory Error Address Register (MEAR) + ************************************************************/ +#define REG_MEAR_OFFSET 0x2460 +#define MEAR_BCNT_MAX_VALUE 0x3 +#define MEAR_BCNT_SHIFT 30 +#define MEAR_BCNT_MASK (MEAR_BCNT_MAX_VALUE << MEAR_BCNT_SHIFT) +#define MEAR_RANK_MAX_VALUE 0x7 +#define MEAR_RANK_SHIFT 27 +#define MEAR_RANK_MASK (MEAR_RANK_MAX_VALUE << MEAR_RANK_SHIFT) +#define MEAR_COL_MAX_VALUE 0x7FF +#define MEAR_COL_SHIFT 16 +#define MEAR_COL_MASK (MEAR_COL_MAX_VALUE << MEAR_COL_SHIFT) +#define MEAR_BANK_MAX_VALUE 0x3 +#define MEAR_BANK_SHIFT 14 +#define MEAR_BANK_MASK (MEAR_BANK_MAX_VALUE << MEAR_BANK_SHIFT) +#define MEAR_ROW_MASK 0x00003FFF + +/************************************************************ + * Memory Error Syndrome Register (MESR) + ************************************************************/ +#define REG_MESR_OFFSET 0x2470 +#define MESR_ECC_SYN_H_MASK 0xFF00 +#define MESR_ECC_SYN_L_MASK 0x00FF + +/************************************************************ + * Memory Mode Control Register (MMCR) + ************************************************************/ +#define REG_MMCR_OFFSET 0x2500 +enum mmcr_bits { + MMCR_REG_DIMM_MODE = CPC925_BIT(3), +}; + +/* + * HyperTransport Link Registers + */ +/************************************************************ + * Error Handling/Enumeration Scratch Pad Register (ERRCTRL) + ************************************************************/ +#define REG_ERRCTRL_OFFSET 0x70140 +enum errctrl_bits { /* nonfatal interrupts for */ + ERRCTRL_SERR_NF = CPC925_BIT(0), /* system error */ + ERRCTRL_CRC_NF = CPC925_BIT(1), /* CRC error */ + ERRCTRL_RSP_NF = CPC925_BIT(2), /* Response error */ + ERRCTRL_EOC_NF = CPC925_BIT(3), /* End-Of-Chain error */ + ERRCTRL_OVF_NF = CPC925_BIT(4), /* Overflow error */ + ERRCTRL_PROT_NF = CPC925_BIT(5), /* Protocol error */ + + ERRCTRL_RSP_ERR = CPC925_BIT(6), /* Response error received */ + ERRCTRL_CHN_FAL = CPC925_BIT(7), /* Sync flooding detected */ + + HT_ERRCTRL_ENABLE = (ERRCTRL_SERR_NF | ERRCTRL_CRC_NF | + ERRCTRL_RSP_NF | ERRCTRL_EOC_NF | + ERRCTRL_OVF_NF | ERRCTRL_PROT_NF), + HT_ERRCTRL_DETECTED = (ERRCTRL_RSP_ERR | ERRCTRL_CHN_FAL), +}; + +/************************************************************ + * Link Configuration and Link Control Register (LINKCTRL) + ************************************************************/ +#define REG_LINKCTRL_OFFSET 0x70110 +enum linkctrl_bits { + LINKCTRL_CRC_ERR = (CPC925_BIT(22) | CPC925_BIT(23)), + LINKCTRL_LINK_FAIL = CPC925_BIT(27), + + HT_LINKCTRL_DETECTED = (LINKCTRL_CRC_ERR | LINKCTRL_LINK_FAIL), +}; + +/************************************************************ + * Link FreqCap/Error/Freq/Revision ID Register (LINKERR) + ************************************************************/ +#define REG_LINKERR_OFFSET 0x70120 +enum linkerr_bits { + LINKERR_EOC_ERR = CPC925_BIT(17), /* End-Of-Chain error */ + LINKERR_OVF_ERR = CPC925_BIT(18), /* Receive Buffer Overflow */ + LINKERR_PROT_ERR = CPC925_BIT(19), /* Protocol error */ + + HT_LINKERR_DETECTED = (LINKERR_EOC_ERR | LINKERR_OVF_ERR | + LINKERR_PROT_ERR), +}; + +/************************************************************ + * Bridge Control Register (BRGCTRL) + ************************************************************/ +#define REG_BRGCTRL_OFFSET 0x70300 +enum brgctrl_bits { + BRGCTRL_DETSERR = CPC925_BIT(0), /* SERR on Secondary Bus */ + BRGCTRL_SECBUSRESET = CPC925_BIT(9), /* Secondary Bus Reset */ +}; + +/* Private structure for edac memory controller */ +struct cpc925_mc_pdata { + void __iomem *vbase; + unsigned long total_mem; + const char *name; + int edac_idx; +}; + +/* Private structure for common edac device */ +struct cpc925_dev_info { + void __iomem *vbase; + struct platform_device *pdev; + char *ctl_name; + int edac_idx; + struct edac_device_ctl_info *edac_dev; + void (*init)(struct cpc925_dev_info *dev_info); + void (*exit)(struct cpc925_dev_info *dev_info); + void (*check)(struct edac_device_ctl_info *edac_dev); +}; + +/* Get total memory size from Open Firmware DTB */ +static void get_total_mem(struct cpc925_mc_pdata *pdata) +{ + struct device_node *np = NULL; + const unsigned int *reg, *reg_end; + int len, sw, aw; + unsigned long start, size; + + np = of_find_node_by_type(NULL, "memory"); + if (!np) + return; + + aw = of_n_addr_cells(np); + sw = of_n_size_cells(np); + reg = (const unsigned int *)of_get_property(np, "reg", &len); + reg_end = reg + len/4; + + pdata->total_mem = 0; + do { + start = of_read_number(reg, aw); + reg += aw; + size = of_read_number(reg, sw); + reg += sw; + debugf1("%s: start 0x%lx, size 0x%lx\n", __func__, + start, size); + pdata->total_mem += size; + } while (reg < reg_end); + + of_node_put(np); + debugf0("%s: total_mem 0x%lx\n", __func__, pdata->total_mem); +} + +static void cpc925_init_csrows(struct mem_ctl_info *mci) +{ + struct cpc925_mc_pdata *pdata = mci->pvt_info; + struct csrow_info *csrow; + int index; + u32 mbmr, mbbar, bba; + unsigned long row_size, last_nr_pages = 0; + + get_total_mem(pdata); + + for (index = 0; index < mci->nr_csrows; index++) { + mbmr = __raw_readl(pdata->vbase + REG_MBMR_OFFSET + + 0x20 * index); + mbbar = __raw_readl(pdata->vbase + REG_MBBAR_OFFSET + + 0x20 + index); + bba = (((mbmr & MBMR_BBA_MASK) >> MBMR_BBA_SHIFT) << 8) | + ((mbbar & MBBAR_BBA_MASK) >> MBBAR_BBA_SHIFT); + + if (bba == 0) + continue; /* not populated */ + + csrow = &mci->csrows[index]; + + row_size = bba * (1UL << 28); /* 256M */ + csrow->first_page = last_nr_pages; + csrow->nr_pages = row_size >> PAGE_SHIFT; + csrow->last_page = csrow->first_page + csrow->nr_pages - 1; + last_nr_pages = csrow->last_page + 1; + + csrow->mtype = MEM_RDDR; + csrow->edac_mode = EDAC_SECDED; + + switch (csrow->nr_channels) { + case 1: /* Single channel */ + csrow->grain = 32; /* four-beat burst of 32 bytes */ + break; + case 2: /* Dual channel */ + default: + csrow->grain = 64; /* four-beat burst of 64 bytes */ + break; + } + + switch ((mbmr & MBMR_MODE_MASK) >> MBMR_MODE_SHIFT) { + case 6: /* 0110, no way to differentiate X8 VS X16 */ + case 5: /* 0101 */ + case 8: /* 1000 */ + csrow->dtype = DEV_X16; + break; + case 7: /* 0111 */ + case 9: /* 1001 */ + csrow->dtype = DEV_X8; + break; + default: + csrow->dtype = DEV_UNKNOWN; + break; + } + } +} + +/* Enable memory controller ECC detection */ +static void cpc925_mc_init(struct mem_ctl_info *mci) +{ + struct cpc925_mc_pdata *pdata = mci->pvt_info; + u32 apimask; + u32 mccr; + + /* Enable various ECC error exceptions */ + apimask = __raw_readl(pdata->vbase + REG_APIMASK_OFFSET); + if ((apimask & ECC_MASK_ENABLE) == 0) { + apimask |= ECC_MASK_ENABLE; + __raw_writel(apimask, pdata->vbase + REG_APIMASK_OFFSET); + } + + /* Enable ECC detection */ + mccr = __raw_readl(pdata->vbase + REG_MCCR_OFFSET); + if ((mccr & MCCR_ECC_EN) == 0) { + mccr |= MCCR_ECC_EN; + __raw_writel(mccr, pdata->vbase + REG_MCCR_OFFSET); + } +} + +/* Disable memory controller ECC detection */ +static void cpc925_mc_exit(struct mem_ctl_info *mci) +{ + /* + * WARNING: + * We are supposed to clear the ECC error detection bits, + * and it will be no problem to do so. However, once they + * are cleared here if we want to re-install CPC925 EDAC + * module later, setting them up in cpc925_mc_init() will + * trigger machine check exception. + * Also, it's ok to leave ECC error detection bits enabled, + * since they are reset to 1 by default or by boot loader. + */ + + return; +} + +/* + * Revert DDR column/row/bank addresses into page frame number and + * offset in page. + * + * Suppose memory mode is 0x0111(128-bit mode, identical DIMM pairs), + * physical address(PA) bits to column address(CA) bits mappings are: + * CA 0 1 2 3 4 5 6 7 8 9 10 + * PA 59 58 57 56 55 54 53 52 51 50 49 + * + * physical address(PA) bits to bank address(BA) bits mappings are: + * BA 0 1 + * PA 43 44 + * + * physical address(PA) bits to row address(RA) bits mappings are: + * RA 0 1 2 3 4 5 6 7 8 9 10 11 12 + * PA 36 35 34 48 47 46 45 40 41 42 39 38 37 + */ +static void cpc925_mc_get_pfn(struct mem_ctl_info *mci, u32 mear, + unsigned long *pfn, unsigned long *offset, int *csrow) +{ + u32 bcnt, rank, col, bank, row; + u32 c; + unsigned long pa; + int i; + + bcnt = (mear & MEAR_BCNT_MASK) >> MEAR_BCNT_SHIFT; + rank = (mear & MEAR_RANK_MASK) >> MEAR_RANK_SHIFT; + col = (mear & MEAR_COL_MASK) >> MEAR_COL_SHIFT; + bank = (mear & MEAR_BANK_MASK) >> MEAR_BANK_SHIFT; + row = mear & MEAR_ROW_MASK; + + *csrow = rank; + +#ifdef CONFIG_EDAC_DEBUG + if (mci->csrows[rank].first_page == 0) { + cpc925_mc_printk(mci, KERN_ERR, "ECC occurs in a " + "non-populated csrow, broken hardware?\n"); + return; + } +#endif + + /* Revert csrow number */ + pa = mci->csrows[rank].first_page << PAGE_SHIFT; + + /* Revert column address */ + col += bcnt; + for (i = 0; i < 11; i++) { + c = col & 0x1; + col >>= 1; + pa |= c << (14 - i); + } + + /* Revert bank address */ + pa |= bank << 19; + + /* Revert row address, in 4 steps */ + for (i = 0; i < 3; i++) { + c = row & 0x1; + row >>= 1; + pa |= c << (26 - i); + } + + for (i = 0; i < 3; i++) { + c = row & 0x1; + row >>= 1; + pa |= c << (21 + i); + } + + for (i = 0; i < 4; i++) { + c = row & 0x1; + row >>= 1; + pa |= c << (18 - i); + } + + for (i = 0; i < 3; i++) { + c = row & 0x1; + row >>= 1; + pa |= c << (29 - i); + } + + *offset = pa & (PAGE_SIZE - 1); + *pfn = pa >> PAGE_SHIFT; + + debugf0("%s: ECC physical address 0x%lx\n", __func__, pa); +} + +static int cpc925_mc_find_channel(struct mem_ctl_info *mci, u16 syndrome) +{ + if ((syndrome & MESR_ECC_SYN_H_MASK) == 0) + return 0; + + if ((syndrome & MESR_ECC_SYN_L_MASK) == 0) + return 1; + + cpc925_mc_printk(mci, KERN_INFO, "Unexpected syndrome value: 0x%x\n", + syndrome); + return 1; +} + +/* Check memory controller registers for ECC errors */ +static void cpc925_mc_check(struct mem_ctl_info *mci) +{ + struct cpc925_mc_pdata *pdata = mci->pvt_info; + u32 apiexcp; + u32 mear; + u32 mesr; + u16 syndrome; + unsigned long pfn = 0, offset = 0; + int csrow = 0, channel = 0; + + /* APIEXCP is cleared when read */ + apiexcp = __raw_readl(pdata->vbase + REG_APIEXCP_OFFSET); + if ((apiexcp & ECC_EXCP_DETECTED) == 0) + return; + + mesr = __raw_readl(pdata->vbase + REG_MESR_OFFSET); + syndrome = mesr | (MESR_ECC_SYN_H_MASK | MESR_ECC_SYN_L_MASK); + + mear = __raw_readl(pdata->vbase + REG_MEAR_OFFSET); + + /* Revert column/row addresses into page frame number, etc */ + cpc925_mc_get_pfn(mci, mear, &pfn, &offset, &csrow); + + if (apiexcp & CECC_EXCP_DETECTED) { + cpc925_mc_printk(mci, KERN_INFO, "DRAM CECC Fault\n"); + channel = cpc925_mc_find_channel(mci, syndrome); + edac_mc_handle_ce(mci, pfn, offset, syndrome, + csrow, channel, mci->ctl_name); + } + + if (apiexcp & UECC_EXCP_DETECTED) { + cpc925_mc_printk(mci, KERN_INFO, "DRAM UECC Fault\n"); + edac_mc_handle_ue(mci, pfn, offset, csrow, mci->ctl_name); + } + + cpc925_mc_printk(mci, KERN_INFO, "Dump registers:\n"); + cpc925_mc_printk(mci, KERN_INFO, "APIMASK 0x%08x\n", + __raw_readl(pdata->vbase + REG_APIMASK_OFFSET)); + cpc925_mc_printk(mci, KERN_INFO, "APIEXCP 0x%08x\n", + apiexcp); + cpc925_mc_printk(mci, KERN_INFO, "Mem Scrub Ctrl 0x%08x\n", + __raw_readl(pdata->vbase + REG_MSCR_OFFSET)); + cpc925_mc_printk(mci, KERN_INFO, "Mem Scrub Rge Start 0x%08x\n", + __raw_readl(pdata->vbase + REG_MSRSR_OFFSET)); + cpc925_mc_printk(mci, KERN_INFO, "Mem Scrub Rge End 0x%08x\n", + __raw_readl(pdata->vbase + REG_MSRER_OFFSET)); + cpc925_mc_printk(mci, KERN_INFO, "Mem Scrub Pattern 0x%08x\n", + __raw_readl(pdata->vbase + REG_MSPR_OFFSET)); + cpc925_mc_printk(mci, KERN_INFO, "Mem Chk Ctrl 0x%08x\n", + __raw_readl(pdata->vbase + REG_MCCR_OFFSET)); + cpc925_mc_printk(mci, KERN_INFO, "Mem Chk Rge End 0x%08x\n", + __raw_readl(pdata->vbase + REG_MCRER_OFFSET)); + cpc925_mc_printk(mci, KERN_INFO, "Mem Err Address 0x%08x\n", + mesr); + cpc925_mc_printk(mci, KERN_INFO, "Mem Err Syndrome 0x%08x\n", + syndrome); +} + +/******************** CPU err device********************************/ +/* Enable CPU Errors detection */ +static void cpc925_cpu_init(struct cpc925_dev_info *dev_info) +{ + u32 apimask; + + apimask = __raw_readl(dev_info->vbase + REG_APIMASK_OFFSET); + if ((apimask & CPU_MASK_ENABLE) == 0) { + apimask |= CPU_MASK_ENABLE; + __raw_writel(apimask, dev_info->vbase + REG_APIMASK_OFFSET); + } +} + +/* Disable CPU Errors detection */ +static void cpc925_cpu_exit(struct cpc925_dev_info *dev_info) +{ + /* + * WARNING: + * We are supposed to clear the CPU error detection bits, + * and it will be no problem to do so. However, once they + * are cleared here if we want to re-install CPC925 EDAC + * module later, setting them up in cpc925_cpu_init() will + * trigger machine check exception. + * Also, it's ok to leave CPU error detection bits enabled, + * since they are reset to 1 by default. + */ + + return; +} + +/* Check for CPU Errors */ +static void cpc925_cpu_check(struct edac_device_ctl_info *edac_dev) +{ + struct cpc925_dev_info *dev_info = edac_dev->pvt_info; + u32 apiexcp; + u32 apimask; + + /* APIEXCP is cleared when read */ + apiexcp = __raw_readl(dev_info->vbase + REG_APIEXCP_OFFSET); + if ((apiexcp & CPU_EXCP_DETECTED) == 0) + return; + + apimask = __raw_readl(dev_info->vbase + REG_APIMASK_OFFSET); + cpc925_printk(KERN_INFO, "Processor Interface Fault\n" + "Processor Interface register dump:\n"); + cpc925_printk(KERN_INFO, "APIMASK 0x%08x\n", apimask); + cpc925_printk(KERN_INFO, "APIEXCP 0x%08x\n", apiexcp); + + edac_device_handle_ue(edac_dev, 0, 0, edac_dev->ctl_name); +} + +/******************** HT Link err device****************************/ +/* Enable HyperTransport Link Error detection */ +static void cpc925_htlink_init(struct cpc925_dev_info *dev_info) +{ + u32 ht_errctrl; + + ht_errctrl = __raw_readl(dev_info->vbase + REG_ERRCTRL_OFFSET); + if ((ht_errctrl & HT_ERRCTRL_ENABLE) == 0) { + ht_errctrl |= HT_ERRCTRL_ENABLE; + __raw_writel(ht_errctrl, dev_info->vbase + REG_ERRCTRL_OFFSET); + } +} + +/* Disable HyperTransport Link Error detection */ +static void cpc925_htlink_exit(struct cpc925_dev_info *dev_info) +{ + u32 ht_errctrl; + + ht_errctrl = __raw_readl(dev_info->vbase + REG_ERRCTRL_OFFSET); + ht_errctrl &= ~HT_ERRCTRL_ENABLE; + __raw_writel(ht_errctrl, dev_info->vbase + REG_ERRCTRL_OFFSET); +} + +/* Check for HyperTransport Link errors */ +static void cpc925_htlink_check(struct edac_device_ctl_info *edac_dev) +{ + struct cpc925_dev_info *dev_info = edac_dev->pvt_info; + u32 brgctrl = __raw_readl(dev_info->vbase + REG_BRGCTRL_OFFSET); + u32 linkctrl = __raw_readl(dev_info->vbase + REG_LINKCTRL_OFFSET); + u32 errctrl = __raw_readl(dev_info->vbase + REG_ERRCTRL_OFFSET); + u32 linkerr = __raw_readl(dev_info->vbase + REG_LINKERR_OFFSET); + + if (!((brgctrl & BRGCTRL_DETSERR) || + (linkctrl & HT_LINKCTRL_DETECTED) || + (errctrl & HT_ERRCTRL_DETECTED) || + (linkerr & HT_LINKERR_DETECTED))) + return; + + cpc925_printk(KERN_INFO, "HT Link Fault\n" + "HT register dump:\n"); + cpc925_printk(KERN_INFO, "Bridge Ctrl 0x%08x\n", + brgctrl); + cpc925_printk(KERN_INFO, "Link Config Ctrl 0x%08x\n", + linkctrl); + cpc925_printk(KERN_INFO, "Error Enum and Ctrl 0x%08x\n", + errctrl); + cpc925_printk(KERN_INFO, "Link Error 0x%08x\n", + linkerr); + + /* Clear by write 1 */ + if (brgctrl & BRGCTRL_DETSERR) + __raw_writel(BRGCTRL_DETSERR, + dev_info->vbase + REG_BRGCTRL_OFFSET); + + if (linkctrl & HT_LINKCTRL_DETECTED) + __raw_writel(HT_LINKCTRL_DETECTED, + dev_info->vbase + REG_LINKCTRL_OFFSET); + + /* Initiate Secondary Bus Reset to clear the chain failure */ + if (errctrl & ERRCTRL_CHN_FAL) + __raw_writel(BRGCTRL_SECBUSRESET, + dev_info->vbase + REG_BRGCTRL_OFFSET); + + if (errctrl & ERRCTRL_RSP_ERR) + __raw_writel(ERRCTRL_RSP_ERR, + dev_info->vbase + REG_ERRCTRL_OFFSET); + + if (linkerr & HT_LINKERR_DETECTED) + __raw_writel(HT_LINKERR_DETECTED, + dev_info->vbase + REG_LINKERR_OFFSET); + + edac_device_handle_ce(edac_dev, 0, 0, edac_dev->ctl_name); +} + +static struct cpc925_dev_info cpc925_devs[] = { + { + .ctl_name = CPC925_CPU_ERR_DEV, + .init = cpc925_cpu_init, + .exit = cpc925_cpu_exit, + .check = cpc925_cpu_check, + }, + { + .ctl_name = CPC925_HT_LINK_DEV, + .init = cpc925_htlink_init, + .exit = cpc925_htlink_exit, + .check = cpc925_htlink_check, + }, + {0}, /* Terminated by NULL */ +}; + +/* + * Add CPU Err detection and HyperTransport Link Err detection + * as common "edac_device", they have no corresponding device + * nodes in the Open Firmware DTB and we have to add platform + * devices for them. Also, they will share the MMIO with that + * of memory controller. + */ +static void cpc925_add_edac_devices(void __iomem *vbase) +{ + struct cpc925_dev_info *dev_info; + + if (!vbase) { + cpc925_printk(KERN_ERR, "MMIO not established yet\n"); + return; + } + + for (dev_info = &cpc925_devs[0]; dev_info->init; dev_info++) { + dev_info->vbase = vbase; + dev_info->pdev = platform_device_register_simple( + dev_info->ctl_name, 0, NULL, 0); + if (IS_ERR(dev_info->pdev)) { + cpc925_printk(KERN_ERR, + "Can't register platform device for %s\n", + dev_info->ctl_name); + continue; + } + + /* + * Don't have to allocate private structure but + * make use of cpc925_devs[] instead. + */ + dev_info->edac_idx = edac_device_alloc_index(); + dev_info->edac_dev = + edac_device_alloc_ctl_info(0, dev_info->ctl_name, + 1, NULL, 0, 0, NULL, 0, dev_info->edac_idx); + if (!dev_info->edac_dev) { + cpc925_printk(KERN_ERR, "No memory for edac device\n"); + goto err1; + } + + dev_info->edac_dev->pvt_info = dev_info; + dev_info->edac_dev->dev = &dev_info->pdev->dev; + dev_info->edac_dev->ctl_name = dev_info->ctl_name; + dev_info->edac_dev->mod_name = CPC925_EDAC_MOD_STR; + dev_info->edac_dev->dev_name = dev_name(&dev_info->pdev->dev); + + if (edac_op_state == EDAC_OPSTATE_POLL) + dev_info->edac_dev->edac_check = dev_info->check; + + if (dev_info->init) + dev_info->init(dev_info); + + if (edac_device_add_device(dev_info->edac_dev) > 0) { + cpc925_printk(KERN_ERR, + "Unable to add edac device for %s\n", + dev_info->ctl_name); + goto err2; + } + + debugf0("%s: Successfully added edac device for %s\n", + __func__, dev_info->ctl_name); + + continue; + +err2: + if (dev_info->exit) + dev_info->exit(dev_info); + edac_device_free_ctl_info(dev_info->edac_dev); +err1: + platform_device_unregister(dev_info->pdev); + } +} + +/* + * Delete the common "edac_device" for CPU Err Detection + * and HyperTransport Link Err Detection + */ +static void cpc925_del_edac_devices(void) +{ + struct cpc925_dev_info *dev_info; + + for (dev_info = &cpc925_devs[0]; dev_info->init; dev_info++) { + if (dev_info->edac_dev) { + edac_device_del_device(dev_info->edac_dev->dev); + edac_device_free_ctl_info(dev_info->edac_dev); + platform_device_unregister(dev_info->pdev); + } + + if (dev_info->exit) + dev_info->exit(dev_info); + + debugf0("%s: Successfully deleted edac device for %s\n", + __func__, dev_info->ctl_name); + } +} + +/* Convert current back-ground scrub rate into byte/sec bandwith */ +static int cpc925_get_sdram_scrub_rate(struct mem_ctl_info *mci, u32 *bw) +{ + struct cpc925_mc_pdata *pdata = mci->pvt_info; + u32 mscr; + u8 si; + + mscr = __raw_readl(pdata->vbase + REG_MSCR_OFFSET); + si = (mscr & MSCR_SI_MASK) >> MSCR_SI_SHIFT; + + debugf0("%s, Mem Scrub Ctrl Register 0x%x\n", __func__, mscr); + + if (((mscr & MSCR_SCRUB_MOD_MASK) != MSCR_BACKGR_SCRUB) || + (si == 0)) { + cpc925_mc_printk(mci, KERN_INFO, "Scrub mode not enabled\n"); + *bw = 0; + } else + *bw = CPC925_SCRUB_BLOCK_SIZE * 0xFA67 / si; + + return 0; +} + +/* Return 0 for single channel; 1 for dual channel */ +static int cpc925_mc_get_channels(void __iomem *vbase) +{ + int dual = 0; + u32 mbcr; + + mbcr = __raw_readl(vbase + REG_MBCR_OFFSET); + + /* + * Dual channel only when 128-bit wide physical bus + * and 128-bit configuration. + */ + if (((mbcr & MBCR_64BITCFG_MASK) == 0) && + ((mbcr & MBCR_64BITBUS_MASK) == 0)) + dual = 1; + + debugf0("%s: %s channel\n", __func__, + (dual > 0) ? "Dual" : "Single"); + + return dual; +} + +static int __devinit cpc925_probe(struct platform_device *pdev) +{ + static int edac_mc_idx; + struct mem_ctl_info *mci; + void __iomem *vbase; + struct cpc925_mc_pdata *pdata; + struct resource *r; + int res = 0, nr_channels; + + debugf0("%s: %s platform device found!\n", __func__, pdev->name); + + if (!devres_open_group(&pdev->dev, cpc925_probe, GFP_KERNEL)) { + res = -ENOMEM; + goto out; + } + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!r) { + cpc925_printk(KERN_ERR, "Unable to get resource\n"); + res = -ENOENT; + goto err1; + } + + if (!devm_request_mem_region(&pdev->dev, + r->start, + r->end - r->start + 1, + pdev->name)) { + cpc925_printk(KERN_ERR, "Unable to request mem region\n"); + res = -EBUSY; + goto err1; + } + + vbase = devm_ioremap(&pdev->dev, r->start, r->end - r->start + 1); + if (!vbase) { + cpc925_printk(KERN_ERR, "Unable to ioremap device\n"); + res = -ENOMEM; + goto err2; + } + + nr_channels = cpc925_mc_get_channels(vbase); + mci = edac_mc_alloc(sizeof(struct cpc925_mc_pdata), + CPC925_NR_CSROWS, nr_channels + 1, edac_mc_idx); + if (!mci) { + cpc925_printk(KERN_ERR, "No memory for mem_ctl_info\n"); + res = -ENOMEM; + goto err2; + } + + pdata = mci->pvt_info; + pdata->vbase = vbase; + pdata->edac_idx = edac_mc_idx++; + pdata->name = pdev->name; + + mci->dev = &pdev->dev; + platform_set_drvdata(pdev, mci); + mci->dev_name = dev_name(&pdev->dev); + mci->mtype_cap = MEM_FLAG_RDDR | MEM_FLAG_DDR; + mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED; + mci->edac_cap = EDAC_FLAG_SECDED; + mci->mod_name = CPC925_EDAC_MOD_STR; + mci->mod_ver = CPC925_EDAC_REVISION; + mci->ctl_name = pdev->name; + + if (edac_op_state == EDAC_OPSTATE_POLL) + mci->edac_check = cpc925_mc_check; + + mci->ctl_page_to_phys = NULL; + mci->scrub_mode = SCRUB_SW_SRC; + mci->set_sdram_scrub_rate = NULL; + mci->get_sdram_scrub_rate = cpc925_get_sdram_scrub_rate; + + cpc925_init_csrows(mci); + + /* Setup memory controller registers */ + cpc925_mc_init(mci); + + if (edac_mc_add_mc(mci) > 0) { + cpc925_mc_printk(mci, KERN_ERR, "Failed edac_mc_add_mc()\n"); + goto err3; + } + + cpc925_add_edac_devices(vbase); + + /* get this far and it's successful */ + debugf0("%s: success\n", __func__); + + res = 0; + goto out; + +err3: + cpc925_mc_exit(mci); + edac_mc_free(mci); +err2: + devm_release_mem_region(&pdev->dev, r->start, r->end-r->start+1); +err1: + devres_release_group(&pdev->dev, cpc925_probe); +out: + return res; +} + +static int cpc925_remove(struct platform_device *pdev) +{ + struct mem_ctl_info *mci = platform_get_drvdata(pdev); + + /* + * Delete common edac devices before edac mc, because + * the former share the MMIO of the latter. + */ + cpc925_del_edac_devices(); + cpc925_mc_exit(mci); + + edac_mc_del_mc(&pdev->dev); + edac_mc_free(mci); + + return 0; +} + +static struct platform_driver cpc925_edac_driver = { + .probe = cpc925_probe, + .remove = cpc925_remove, + .driver = { + .name = "cpc925_edac", + } +}; + +static int __init cpc925_edac_init(void) +{ + int ret = 0; + + printk(KERN_INFO "IBM CPC925 EDAC driver " CPC925_EDAC_REVISION "\n"); + printk(KERN_INFO "\t(c) 2008 Wind River Systems, Inc\n"); + + /* Only support POLL mode so far */ + edac_op_state = EDAC_OPSTATE_POLL; + + ret = platform_driver_register(&cpc925_edac_driver); + if (ret) { + printk(KERN_WARNING "Failed to register %s\n", + CPC925_EDAC_MOD_STR); + } + + return ret; +} + +static void __exit cpc925_edac_exit(void) +{ + platform_driver_unregister(&cpc925_edac_driver); +} + +module_init(cpc925_edac_init); +module_exit(cpc925_edac_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Cao Qingtao "); +MODULE_DESCRIPTION("IBM CPC925 Bridge and MC EDAC kernel module"); diff --git a/drivers/edac/e752x_edac.c b/drivers/edac/e752x_edac.c index facfdb1fa71c..d205d493a68a 100644 --- a/drivers/edac/e752x_edac.c +++ b/drivers/edac/e752x_edac.c @@ -1084,7 +1084,7 @@ static void e752x_init_sysbus_parity_mask(struct e752x_pvt *pvt) struct pci_dev *dev = pvt->dev_d0f1; int enable = 1; - /* Allow module paramter override, else see if CPU supports parity */ + /* Allow module parameter override, else see if CPU supports parity */ if (sysbus_parity != -1) { enable = sysbus_parity; } else if (cpu_id[0] && diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h index 6ad95c8d6363..3493c6bdb820 100644 --- a/drivers/edac/edac_core.h +++ b/drivers/edac/edac_core.h @@ -76,10 +76,11 @@ extern int edac_debug_level; #ifndef CONFIG_EDAC_DEBUG_VERBOSE -#define edac_debug_printk(level, fmt, arg...) \ - do { \ - if (level <= edac_debug_level) \ - edac_printk(KERN_DEBUG, EDAC_DEBUG, fmt, ##arg); \ +#define edac_debug_printk(level, fmt, arg...) \ + do { \ + if (level <= edac_debug_level) \ + edac_printk(KERN_DEBUG, EDAC_DEBUG, \ + "%s: " fmt, __func__, ##arg); \ } while (0) #else /* CONFIG_EDAC_DEBUG_VERBOSE */ #define edac_debug_printk(level, fmt, arg...) \ @@ -840,6 +841,7 @@ extern void edac_device_handle_ue(struct edac_device_ctl_info *edac_dev, int inst_nr, int block_nr, const char *msg); extern void edac_device_handle_ce(struct edac_device_ctl_info *edac_dev, int inst_nr, int block_nr, const char *msg); +extern int edac_device_alloc_index(void); /* * edac_pci APIs diff --git a/drivers/edac/edac_device.c b/drivers/edac/edac_device.c index a7d2c717d033..b02a6a69a8f0 100644 --- a/drivers/edac/edac_device.c +++ b/drivers/edac/edac_device.c @@ -490,6 +490,20 @@ void edac_device_reset_delay_period(struct edac_device_ctl_info *edac_dev, mutex_unlock(&device_ctls_mutex); } +/* + * edac_device_alloc_index: Allocate a unique device index number + * + * Return: + * allocated index number + */ +int edac_device_alloc_index(void) +{ + static atomic_t device_indexes = ATOMIC_INIT(0); + + return atomic_inc_return(&device_indexes) - 1; +} +EXPORT_SYMBOL_GPL(edac_device_alloc_index); + /** * edac_device_add_device: Insert the 'edac_dev' structure into the * edac_device global list and create sysfs entries associated with diff --git a/drivers/eisa/eisa.ids b/drivers/eisa/eisa.ids index ed69837d8b74..6cbb7a514436 100644 --- a/drivers/eisa/eisa.ids +++ b/drivers/eisa/eisa.ids @@ -1140,6 +1140,11 @@ NON0301 "c't Universale Graphic Adapter" NON0401 "c't Universal Ethernet Adapter" NON0501 "c't Universal 16-Bit Sound Adapter" NON0601 "c't Universal 8-Bit Adapter" +NPI0120 "Network Peripherals NP-EISA-1 FDDI Interface" +NPI0221 "Network Peripherals NP-EISA-2 FDDI Interface" +NPI0223 "Network Peripherals NP-EISA-2E Enhanced FDDI Interface" +NPI0301 "Network Peripherals NP-EISA-3 FDDI Interface" +NPI0303 "Network Peripherals NP-EISA-3E Enhanced FDDI Interface" NSS0011 "Newport Systems Solutions WNIC Adapter" NVL0701 "Novell NE3200 Bus Master Ethernet" NVL0702 "Novell NE3200T Bus Master Ethernet" diff --git a/drivers/eisa/pci_eisa.c b/drivers/eisa/pci_eisa.c index 74edb1d0110f..0dd0f633b18d 100644 --- a/drivers/eisa/pci_eisa.c +++ b/drivers/eisa/pci_eisa.c @@ -31,11 +31,11 @@ static int __init pci_eisa_init(struct pci_dev *pdev, } pci_eisa_root.dev = &pdev->dev; - pci_eisa_root.dev->driver_data = &pci_eisa_root; pci_eisa_root.res = pdev->bus->resource[0]; pci_eisa_root.bus_base_addr = pdev->bus->resource[0]->start; pci_eisa_root.slots = EISA_MAX_SLOTS; pci_eisa_root.dma_mask = pdev->dma_mask; + dev_set_drvdata(pci_eisa_root.dev, &pci_eisa_root); if (eisa_root_register (&pci_eisa_root)) { printk (KERN_ERR "pci_eisa : Could not register EISA root\n"); diff --git a/drivers/eisa/virtual_root.c b/drivers/eisa/virtual_root.c index 3074879f231f..535e4f9c83f4 100644 --- a/drivers/eisa/virtual_root.c +++ b/drivers/eisa/virtual_root.c @@ -57,7 +57,7 @@ static int __init virtual_eisa_root_init (void) eisa_bus_root.force_probe = force_probe; - eisa_root_dev.dev.driver_data = &eisa_bus_root; + dev_set_drvdata(&eisa_root_dev.dev, &eisa_bus_root); if (eisa_root_register (&eisa_bus_root)) { /* A real bridge may have been registered before diff --git a/drivers/firewire/Kconfig b/drivers/firewire/Kconfig index 450902438208..13efcd362072 100644 --- a/drivers/firewire/Kconfig +++ b/drivers/firewire/Kconfig @@ -1,28 +1,29 @@ -comment "A new alternative FireWire stack is available with EXPERIMENTAL=y" - depends on EXPERIMENTAL=n - -comment "Enable only one of the two stacks, unless you know what you are doing" - depends on EXPERIMENTAL +comment "You can enable one or both FireWire driver stacks." +comment "See the help texts for more information." config FIREWIRE - tristate "New FireWire stack, EXPERIMENTAL" - depends on EXPERIMENTAL + tristate "FireWire driver stack" select CRC_ITU_T help - This is the "Juju" FireWire stack, a new alternative implementation - designed for robustness and simplicity. You can build either this - stack, or the old stack (the ieee1394 driver, ohci1394 etc.) or both. - Please read http://ieee1394.wiki.kernel.org/index.php/Juju_Migration - before you enable the new stack. + This is the new-generation IEEE 1394 (FireWire) driver stack + a.k.a. Juju, a new implementation designed for robustness and + simplicity. + See http://ieee1394.wiki.kernel.org/index.php/Juju_Migration + for information about migration from the older Linux 1394 stack + to the new driver stack. To compile this driver as a module, say M here: the module will be called firewire-core. This module functionally replaces ieee1394, raw1394, and video1394. To access it from application programs, you generally need at least - libraw1394 version 2. IIDC/DCAM applications also need libdc1394 - version 2. No libraries are required to access storage devices - through the firewire-sbp2 driver. + libraw1394 v2. IIDC/DCAM applications need libdc1394 v2. + No libraries are required to access storage devices through the + firewire-sbp2 driver. + + NOTE: + FireWire audio devices currently require the old drivers (ieee1394, + ohci1394, raw1394). config FIREWIRE_OHCI tristate "OHCI-1394 controllers" @@ -37,11 +38,9 @@ config FIREWIRE_OHCI stack. NOTE: - - You should only build either firewire-ohci or the old ohci1394 driver, - but not both. If you nevertheless want to install both, you should - configure them only as modules and blacklist the driver(s) which you - don't want to have auto-loaded. Add either + If you want to install firewire-ohci and ohci1394 together, you + should configure them only as modules and blacklist the driver(s) + which you don't want to have auto-loaded. Add either blacklist firewire-ohci or @@ -50,12 +49,7 @@ config FIREWIRE_OHCI blacklist dv1394 to /etc/modprobe.conf or /etc/modprobe.d/* and update modprobe.conf - depending on your distribution. The latter two modules should be - blacklisted together with ohci1394 because they depend on ohci1394. - - If you have an old modprobe which doesn't implement the blacklist - directive, use "install modulename /bin/true" for the modules to be - blacklisted. + depending on your distribution. config FIREWIRE_OHCI_DEBUG bool @@ -77,3 +71,17 @@ config FIREWIRE_SBP2 You should also enable support for disks, CD-ROMs, etc. in the SCSI configuration section. + +config FIREWIRE_NET + tristate "IP networking over 1394 (EXPERIMENTAL)" + depends on FIREWIRE && INET && EXPERIMENTAL + help + This enables IPv4 over IEEE 1394, providing IP connectivity with + other implementations of RFC 2734 as found on several operating + systems. Multicast support is currently limited. + + NOTE, this driver is not stable yet! + + To compile this driver as a module, say M here: The module will be + called firewire-net. It replaces eth1394 of the classic IEEE 1394 + stack. diff --git a/drivers/firewire/Makefile b/drivers/firewire/Makefile index a7c31e9039c1..a8f9bb6d9fdf 100644 --- a/drivers/firewire/Makefile +++ b/drivers/firewire/Makefile @@ -2,11 +2,13 @@ # Makefile for the Linux IEEE 1394 implementation # -firewire-core-y += fw-card.o fw-topology.o fw-transaction.o fw-iso.o \ - fw-device.o fw-cdev.o -firewire-ohci-y += fw-ohci.o -firewire-sbp2-y += fw-sbp2.o +firewire-core-y += core-card.o core-cdev.o core-device.o \ + core-iso.o core-topology.o core-transaction.o +firewire-ohci-y += ohci.o +firewire-sbp2-y += sbp2.o +firewire-net-y += net.o -obj-$(CONFIG_FIREWIRE) += firewire-core.o +obj-$(CONFIG_FIREWIRE) += firewire-core.o obj-$(CONFIG_FIREWIRE_OHCI) += firewire-ohci.o obj-$(CONFIG_FIREWIRE_SBP2) += firewire-sbp2.o +obj-$(CONFIG_FIREWIRE_NET) += firewire-net.o diff --git a/drivers/firewire/fw-card.c b/drivers/firewire/core-card.c similarity index 92% rename from drivers/firewire/fw-card.c rename to drivers/firewire/core-card.c index 8b8c8c22f0fc..543fccac81bb 100644 --- a/drivers/firewire/fw-card.c +++ b/drivers/firewire/core-card.c @@ -16,18 +16,27 @@ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include #include #include -#include #include #include +#include +#include +#include +#include #include +#include #include #include +#include +#include +#include -#include "fw-transaction.h" -#include "fw-topology.h" -#include "fw-device.h" +#include +#include + +#include "core.h" int fw_compute_block_crc(u32 *block) { @@ -167,6 +176,7 @@ int fw_core_add_descriptor(struct fw_descriptor *desc) return 0; } +EXPORT_SYMBOL(fw_core_add_descriptor); void fw_core_remove_descriptor(struct fw_descriptor *desc) { @@ -180,12 +190,7 @@ void fw_core_remove_descriptor(struct fw_descriptor *desc) mutex_unlock(&card_mutex); } - -static int set_broadcast_channel(struct device *dev, void *data) -{ - fw_device_set_broadcast_channel(fw_device(dev), (long)data); - return 0; -} +EXPORT_SYMBOL(fw_core_remove_descriptor); static void allocate_broadcast_channel(struct fw_card *card, int generation) { @@ -196,7 +201,7 @@ static void allocate_broadcast_channel(struct fw_card *card, int generation) if (channel == 31) { card->broadcast_channel_allocated = true; device_for_each_child(card->device, (void *)(long)generation, - set_broadcast_channel); + fw_device_set_broadcast_channel); } } @@ -456,11 +461,11 @@ EXPORT_SYMBOL(fw_card_add); /* - * The next few functions implements a dummy driver that use once a - * card driver shuts down an fw_card. This allows the driver to - * cleanly unload, as all IO to the card will be handled by the dummy - * driver instead of calling into the (possibly) unloaded module. The - * dummy driver just fails all IO. + * The next few functions implement a dummy driver that is used once a card + * driver shuts down an fw_card. This allows the driver to cleanly unload, + * as all IO to the card will be handled (and failed) by the dummy driver + * instead of calling into the module. Only functions for iso context + * shutdown still need to be provided by the card driver. */ static int dummy_enable(struct fw_card *card, u32 *config_rom, size_t length) @@ -507,7 +512,7 @@ static int dummy_enable_phys_dma(struct fw_card *card, return -ENODEV; } -static struct fw_card_driver dummy_driver = { +static const struct fw_card_driver dummy_driver_template = { .enable = dummy_enable, .update_phy_reg = dummy_update_phy_reg, .set_config_rom = dummy_set_config_rom, @@ -526,6 +531,8 @@ void fw_card_release(struct kref *kref) void fw_core_remove_card(struct fw_card *card) { + struct fw_card_driver dummy_driver = dummy_driver_template; + card->driver->update_phy_reg(card, 4, PHY_LINK_ACTIVE | PHY_CONTENDER, 0); fw_core_initiate_bus_reset(card, 1); @@ -534,7 +541,9 @@ void fw_core_remove_card(struct fw_card *card) list_del_init(&card->link); mutex_unlock(&card_mutex); - /* Set up the dummy driver. */ + /* Switch off most of the card driver interface. */ + dummy_driver.free_iso_context = card->driver->free_iso_context; + dummy_driver.stop_iso = card->driver->stop_iso; card->driver = &dummy_driver; fw_destroy_nodes(card); diff --git a/drivers/firewire/fw-cdev.c b/drivers/firewire/core-cdev.c similarity index 99% rename from drivers/firewire/fw-cdev.c rename to drivers/firewire/core-cdev.c index 7eb6594cc3e5..d1d30c615b0f 100644 --- a/drivers/firewire/fw-cdev.c +++ b/drivers/firewire/core-cdev.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -34,16 +35,14 @@ #include #include #include +#include #include #include #include #include -#include -#include "fw-device.h" -#include "fw-topology.h" -#include "fw-transaction.h" +#include "core.h" struct client { u32 version; @@ -739,15 +738,11 @@ static void release_descriptor(struct client *client, static int ioctl_add_descriptor(struct client *client, void *buffer) { struct fw_cdev_add_descriptor *request = buffer; - struct fw_card *card = client->device->card; struct descriptor_resource *r; int ret; /* Access policy: Allow this ioctl only on local nodes' device files. */ - spin_lock_irq(&card->lock); - ret = client->device->node_id != card->local_node->node_id; - spin_unlock_irq(&card->lock); - if (ret) + if (!client->device->is_local) return -ENOSYS; if (request->length > 256) diff --git a/drivers/firewire/fw-device.c b/drivers/firewire/core-device.c similarity index 88% rename from drivers/firewire/fw-device.c rename to drivers/firewire/core-device.c index a47e2129d83d..97e656af2d22 100644 --- a/drivers/firewire/fw-device.c +++ b/drivers/firewire/core-device.c @@ -22,10 +22,14 @@ #include #include #include +#include +#include #include #include #include #include +#include +#include #include #include #include @@ -33,11 +37,11 @@ #include #include +#include +#include #include -#include "fw-device.h" -#include "fw-topology.h" -#include "fw-transaction.h" +#include "core.h" void fw_csr_iterator_init(struct fw_csr_iterator *ci, u32 * p) { @@ -55,9 +59,10 @@ int fw_csr_iterator_next(struct fw_csr_iterator *ci, int *key, int *value) } EXPORT_SYMBOL(fw_csr_iterator_next); -static int is_fw_unit(struct device *dev); +static bool is_fw_unit(struct device *dev); -static int match_unit_directory(u32 * directory, const struct fw_device_id *id) +static int match_unit_directory(u32 *directory, u32 match_flags, + const struct ieee1394_device_id *id) { struct fw_csr_iterator ci; int key, value, match; @@ -65,31 +70,42 @@ static int match_unit_directory(u32 * directory, const struct fw_device_id *id) match = 0; fw_csr_iterator_init(&ci, directory); while (fw_csr_iterator_next(&ci, &key, &value)) { - if (key == CSR_VENDOR && value == id->vendor) - match |= FW_MATCH_VENDOR; - if (key == CSR_MODEL && value == id->model) - match |= FW_MATCH_MODEL; + if (key == CSR_VENDOR && value == id->vendor_id) + match |= IEEE1394_MATCH_VENDOR_ID; + if (key == CSR_MODEL && value == id->model_id) + match |= IEEE1394_MATCH_MODEL_ID; if (key == CSR_SPECIFIER_ID && value == id->specifier_id) - match |= FW_MATCH_SPECIFIER_ID; + match |= IEEE1394_MATCH_SPECIFIER_ID; if (key == CSR_VERSION && value == id->version) - match |= FW_MATCH_VERSION; + match |= IEEE1394_MATCH_VERSION; } - return (match & id->match_flags) == id->match_flags; + return (match & match_flags) == match_flags; } static int fw_unit_match(struct device *dev, struct device_driver *drv) { struct fw_unit *unit = fw_unit(dev); - struct fw_driver *driver = fw_driver(drv); - int i; + struct fw_device *device; + const struct ieee1394_device_id *id; /* We only allow binding to fw_units. */ if (!is_fw_unit(dev)) return 0; - for (i = 0; driver->id_table[i].match_flags != 0; i++) { - if (match_unit_directory(unit->directory, &driver->id_table[i])) + device = fw_parent_device(unit); + id = container_of(drv, struct fw_driver, driver)->id_table; + + for (; id->match_flags != 0; id++) { + if (match_unit_directory(unit->directory, id->match_flags, id)) + return 1; + + /* Also check vendor ID in the root directory. */ + if ((id->match_flags & IEEE1394_MATCH_VENDOR_ID) && + match_unit_directory(&device->config_rom[5], + IEEE1394_MATCH_VENDOR_ID, id) && + match_unit_directory(unit->directory, id->match_flags + & ~IEEE1394_MATCH_VENDOR_ID, id)) return 1; } @@ -98,7 +114,7 @@ static int fw_unit_match(struct device *dev, struct device_driver *drv) static int get_modalias(struct fw_unit *unit, char *buffer, size_t buffer_size) { - struct fw_device *device = fw_device(unit->device.parent); + struct fw_device *device = fw_parent_device(unit); struct fw_csr_iterator ci; int key, value; @@ -292,8 +308,7 @@ static void init_fw_attribute_group(struct device *dev, group->attrs[j++] = &attr->attr; } - BUG_ON(j >= ARRAY_SIZE(group->attrs)); - group->attrs[j++] = NULL; + group->attrs[j] = NULL; group->groups[0] = &group->group; group->groups[1] = NULL; group->group.attrs = group->attrs; @@ -356,9 +371,56 @@ static ssize_t guid_show(struct device *dev, return ret; } +static int units_sprintf(char *buf, u32 *directory) +{ + struct fw_csr_iterator ci; + int key, value; + int specifier_id = 0; + int version = 0; + + fw_csr_iterator_init(&ci, directory); + while (fw_csr_iterator_next(&ci, &key, &value)) { + switch (key) { + case CSR_SPECIFIER_ID: + specifier_id = value; + break; + case CSR_VERSION: + version = value; + break; + } + } + + return sprintf(buf, "0x%06x:0x%06x ", specifier_id, version); +} + +static ssize_t units_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct fw_device *device = fw_device(dev); + struct fw_csr_iterator ci; + int key, value, i = 0; + + down_read(&fw_device_rwsem); + fw_csr_iterator_init(&ci, &device->config_rom[5]); + while (fw_csr_iterator_next(&ci, &key, &value)) { + if (key != (CSR_UNIT | CSR_DIRECTORY)) + continue; + i += units_sprintf(&buf[i], ci.p + value - 1); + if (i >= PAGE_SIZE - (8 + 1 + 8 + 1)) + break; + } + up_read(&fw_device_rwsem); + + if (i) + buf[i - 1] = '\n'; + + return i; +} + static struct device_attribute fw_device_attributes[] = { __ATTR_RO(config_rom), __ATTR_RO(guid), + __ATTR_RO(units), __ATTR_NULL, }; @@ -518,7 +580,9 @@ static int read_bus_info_block(struct fw_device *device, int generation) kfree(old_rom); ret = 0; - device->cmc = rom[2] >> 30 & 1; + device->max_rec = rom[2] >> 12 & 0xf; + device->cmc = rom[2] >> 30 & 1; + device->irmc = rom[2] >> 31 & 1; out: kfree(rom); @@ -537,7 +601,7 @@ static struct device_type fw_unit_type = { .release = fw_unit_release, }; -static int is_fw_unit(struct device *dev) +static bool is_fw_unit(struct device *dev) { return dev->type == &fw_unit_type; } @@ -570,9 +634,13 @@ static void create_units(struct fw_device *device) unit->device.parent = &device->device; dev_set_name(&unit->device, "%s.%d", dev_name(&device->device), i++); + BUILD_BUG_ON(ARRAY_SIZE(unit->attribute_group.attrs) < + ARRAY_SIZE(fw_unit_attributes) + + ARRAY_SIZE(config_rom_attributes)); init_fw_attribute_group(&unit->device, fw_unit_attributes, &unit->attribute_group); + if (device_register(&unit->device) < 0) goto skip_unit; @@ -683,6 +751,11 @@ static struct device_type fw_device_type = { .release = fw_device_release, }; +static bool is_fw_device(struct device *dev) +{ + return dev->type == &fw_device_type; +} + static int update_unit(struct device *dev, void *data) { struct fw_unit *unit = fw_unit(dev); @@ -719,6 +792,9 @@ static int lookup_existing_device(struct device *dev, void *data) struct fw_card *card = new->card; int match = 0; + if (!is_fw_device(dev)) + return 0; + down_read(&fw_device_rwsem); /* serialize config_rom access */ spin_lock_irq(&card->lock); /* serialize node access */ @@ -758,7 +834,7 @@ static int lookup_existing_device(struct device *dev, void *data) enum { BC_UNKNOWN = 0, BC_UNIMPLEMENTED, BC_IMPLEMENTED, }; -void fw_device_set_broadcast_channel(struct fw_device *device, int generation) +static void set_broadcast_channel(struct fw_device *device, int generation) { struct fw_card *card = device->card; __be32 data; @@ -767,6 +843,20 @@ void fw_device_set_broadcast_channel(struct fw_device *device, int generation) if (!card->broadcast_channel_allocated) return; + /* + * The Broadcast_Channel Valid bit is required by nodes which want to + * transmit on this channel. Such transmissions are practically + * exclusive to IP over 1394 (RFC 2734). IP capable nodes are required + * to be IRM capable and have a max_rec of 8 or more. We use this fact + * to narrow down to which nodes we send Broadcast_Channel updates. + */ + if (!device->irmc || device->max_rec < 8) + return; + + /* + * Some 1394-1995 nodes crash if this 1394a-2000 register is written. + * Perform a read test first. + */ if (device->bc_implemented == BC_UNKNOWN) { rcode = fw_run_transaction(card, TCODE_READ_QUADLET_REQUEST, device->node_id, generation, device->max_speed, @@ -794,6 +884,14 @@ void fw_device_set_broadcast_channel(struct fw_device *device, int generation) } } +int fw_device_set_broadcast_channel(struct device *dev, void *gen) +{ + if (is_fw_device(dev)) + set_broadcast_channel(fw_device(dev), (long)gen); + + return 0; +} + static void fw_device_init(struct work_struct *work) { struct fw_device *device = @@ -849,9 +947,13 @@ static void fw_device_init(struct work_struct *work) device->device.devt = MKDEV(fw_cdev_major, minor); dev_set_name(&device->device, "fw%d", minor); + BUILD_BUG_ON(ARRAY_SIZE(device->attribute_group.attrs) < + ARRAY_SIZE(fw_device_attributes) + + ARRAY_SIZE(config_rom_attributes)); init_fw_attribute_group(&device->device, fw_device_attributes, &device->attribute_group); + if (device_add(&device->device)) { fw_error("Failed to add device.\n"); goto error_with_cdev; @@ -888,7 +990,7 @@ static void fw_device_init(struct work_struct *work) 1 << device->max_speed); device->config_rom_retries = 0; - fw_device_set_broadcast_channel(device, device->generation); + set_broadcast_channel(device, device->generation); } /* @@ -993,6 +1095,9 @@ static void fw_device_refresh(struct work_struct *work) create_units(device); + /* Userspace may want to re-read attributes. */ + kobject_uevent(&device->device.kobj, KOBJ_CHANGE); + if (atomic_cmpxchg(&device->state, FW_DEVICE_INITIALIZING, FW_DEVICE_RUNNING) == FW_DEVICE_GONE) @@ -1042,6 +1147,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event) device->node = fw_node_get(node); device->node_id = node->node_id; device->generation = card->generation; + device->is_local = node == card->local_node; mutex_init(&device->client_list_mutex); INIT_LIST_HEAD(&device->client_list); @@ -1075,7 +1181,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event) FW_DEVICE_INITIALIZING) == FW_DEVICE_RUNNING) { PREPARE_DELAYED_WORK(&device->work, fw_device_refresh); schedule_delayed_work(&device->work, - node == card->local_node ? 0 : INITIAL_DELAY); + device->is_local ? 0 : INITIAL_DELAY); } break; diff --git a/drivers/firewire/fw-iso.c b/drivers/firewire/core-iso.c similarity index 95% rename from drivers/firewire/fw-iso.c rename to drivers/firewire/core-iso.c index 2baf1007253e..166f19c6d38d 100644 --- a/drivers/firewire/fw-iso.c +++ b/drivers/firewire/core-iso.c @@ -22,14 +22,16 @@ #include #include +#include #include #include #include #include #include -#include "fw-topology.h" -#include "fw-transaction.h" +#include + +#include "core.h" /* * Isochronous DMA context management @@ -69,7 +71,7 @@ int fw_iso_buffer_init(struct fw_iso_buffer *buffer, struct fw_card *card, for (j = 0; j < i; j++) { address = page_private(buffer->pages[j]); dma_unmap_page(card->device, address, - PAGE_SIZE, DMA_TO_DEVICE); + PAGE_SIZE, direction); __free_page(buffer->pages[j]); } kfree(buffer->pages); @@ -78,6 +80,7 @@ int fw_iso_buffer_init(struct fw_iso_buffer *buffer, struct fw_card *card, return -ENOMEM; } +EXPORT_SYMBOL(fw_iso_buffer_init); int fw_iso_buffer_map(struct fw_iso_buffer *buffer, struct vm_area_struct *vma) { @@ -105,13 +108,14 @@ void fw_iso_buffer_destroy(struct fw_iso_buffer *buffer, for (i = 0; i < buffer->page_count; i++) { address = page_private(buffer->pages[i]); dma_unmap_page(card->device, address, - PAGE_SIZE, DMA_TO_DEVICE); + PAGE_SIZE, buffer->direction); __free_page(buffer->pages[i]); } kfree(buffer->pages); buffer->pages = NULL; } +EXPORT_SYMBOL(fw_iso_buffer_destroy); struct fw_iso_context *fw_iso_context_create(struct fw_card *card, int type, int channel, int speed, size_t header_size, @@ -134,6 +138,7 @@ struct fw_iso_context *fw_iso_context_create(struct fw_card *card, return ctx; } +EXPORT_SYMBOL(fw_iso_context_create); void fw_iso_context_destroy(struct fw_iso_context *ctx) { @@ -141,12 +146,14 @@ void fw_iso_context_destroy(struct fw_iso_context *ctx) card->driver->free_iso_context(ctx); } +EXPORT_SYMBOL(fw_iso_context_destroy); int fw_iso_context_start(struct fw_iso_context *ctx, int cycle, int sync, int tags) { return ctx->card->driver->start_iso(ctx, cycle, sync, tags); } +EXPORT_SYMBOL(fw_iso_context_start); int fw_iso_context_queue(struct fw_iso_context *ctx, struct fw_iso_packet *packet, @@ -157,11 +164,13 @@ int fw_iso_context_queue(struct fw_iso_context *ctx, return card->driver->queue_iso(ctx, packet, buffer, payload); } +EXPORT_SYMBOL(fw_iso_context_queue); int fw_iso_context_stop(struct fw_iso_context *ctx) { return ctx->card->driver->stop_iso(ctx); } +EXPORT_SYMBOL(fw_iso_context_stop); /* * Isochronous bus resource management (channels, bandwidth), client side diff --git a/drivers/firewire/fw-topology.c b/drivers/firewire/core-topology.c similarity index 97% rename from drivers/firewire/fw-topology.c rename to drivers/firewire/core-topology.c index d0deecc4de93..fddf2b358936 100644 --- a/drivers/firewire/fw-topology.c +++ b/drivers/firewire/core-topology.c @@ -18,13 +18,22 @@ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include -#include +#include #include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include #include -#include "fw-transaction.h" -#include "fw-topology.h" + +#include "core.h" #define SELF_ID_PHY_ID(q) (((q) >> 24) & 0x3f) #define SELF_ID_EXTENDED(q) (((q) >> 23) & 0x01) @@ -37,6 +46,11 @@ #define SELF_ID_EXT_SEQUENCE(q) (((q) >> 20) & 0x07) +#define SELFID_PORT_CHILD 0x3 +#define SELFID_PORT_PARENT 0x2 +#define SELFID_PORT_NCONN 0x1 +#define SELFID_PORT_NONE 0x0 + static u32 *count_ports(u32 *sid, int *total_port_count, int *child_port_count) { u32 q; diff --git a/drivers/firewire/fw-transaction.c b/drivers/firewire/core-transaction.c similarity index 97% rename from drivers/firewire/fw-transaction.c rename to drivers/firewire/core-transaction.c index 283dac6d327d..479b22f5a1eb 100644 --- a/drivers/firewire/fw-transaction.c +++ b/drivers/firewire/core-transaction.c @@ -18,24 +18,28 @@ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include #include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include -#include -#include -#include -#include +#include +#include +#include #include -#include -#include +#include +#include +#include +#include +#include +#include -#include "fw-transaction.h" -#include "fw-topology.h" -#include "fw-device.h" +#include + +#include "core.h" #define HEADER_PRI(pri) ((pri) << 0) #define HEADER_TCODE(tcode) ((tcode) << 4) @@ -60,6 +64,10 @@ #define HEADER_DESTINATION_IS_BROADCAST(q) \ (((q) & HEADER_DESTINATION(0x3f)) == HEADER_DESTINATION(0x3f)) +#define PHY_PACKET_CONFIG 0x0 +#define PHY_PACKET_LINK_ON 0x1 +#define PHY_PACKET_SELF_ID 0x2 + #define PHY_CONFIG_GAP_COUNT(gap_count) (((gap_count) << 16) | (1 << 22)) #define PHY_CONFIG_ROOT_ID(node_id) ((((node_id) & 0x3f) << 24) | (1 << 23)) #define PHY_IDENTIFIER(id) ((id) << 30) @@ -74,7 +82,7 @@ static int close_transaction(struct fw_transaction *transaction, list_for_each_entry(t, &card->transaction_list, link) { if (t == transaction) { list_del(&t->link); - card->tlabel_mask &= ~(1 << t->tlabel); + card->tlabel_mask &= ~(1ULL << t->tlabel); break; } } @@ -280,14 +288,14 @@ void fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode, spin_lock_irqsave(&card->lock, flags); tlabel = card->current_tlabel; - if (card->tlabel_mask & (1 << tlabel)) { + if (card->tlabel_mask & (1ULL << tlabel)) { spin_unlock_irqrestore(&card->lock, flags); callback(card, RCODE_SEND_ERROR, NULL, 0, callback_data); return; } - card->current_tlabel = (card->current_tlabel + 1) & 0x1f; - card->tlabel_mask |= (1 << tlabel); + card->current_tlabel = (card->current_tlabel + 1) & 0x3f; + card->tlabel_mask |= (1ULL << tlabel); t->node_id = destination_id; t->tlabel = tlabel; diff --git a/drivers/firewire/core.h b/drivers/firewire/core.h new file mode 100644 index 000000000000..c3cfc647e5e3 --- /dev/null +++ b/drivers/firewire/core.h @@ -0,0 +1,206 @@ +#ifndef _FIREWIRE_CORE_H +#define _FIREWIRE_CORE_H + +#include +#include +#include +#include +#include +#include +#include + +#include + +struct device; +struct fw_card; +struct fw_device; +struct fw_iso_buffer; +struct fw_iso_context; +struct fw_iso_packet; +struct fw_node; +struct fw_packet; + + +/* -card */ + +/* bitfields within the PHY registers */ +#define PHY_LINK_ACTIVE 0x80 +#define PHY_CONTENDER 0x40 +#define PHY_BUS_RESET 0x40 +#define PHY_BUS_SHORT_RESET 0x40 + +#define BANDWIDTH_AVAILABLE_INITIAL 4915 +#define BROADCAST_CHANNEL_INITIAL (1 << 31 | 31) +#define BROADCAST_CHANNEL_VALID (1 << 30) + +struct fw_card_driver { + /* + * Enable the given card with the given initial config rom. + * This function is expected to activate the card, and either + * enable the PHY or set the link_on bit and initiate a bus + * reset. + */ + int (*enable)(struct fw_card *card, u32 *config_rom, size_t length); + + int (*update_phy_reg)(struct fw_card *card, int address, + int clear_bits, int set_bits); + + /* + * Update the config rom for an enabled card. This function + * should change the config rom that is presented on the bus + * an initiate a bus reset. + */ + int (*set_config_rom)(struct fw_card *card, + u32 *config_rom, size_t length); + + void (*send_request)(struct fw_card *card, struct fw_packet *packet); + void (*send_response)(struct fw_card *card, struct fw_packet *packet); + /* Calling cancel is valid once a packet has been submitted. */ + int (*cancel_packet)(struct fw_card *card, struct fw_packet *packet); + + /* + * Allow the specified node ID to do direct DMA out and in of + * host memory. The card will disable this for all node when + * a bus reset happens, so driver need to reenable this after + * bus reset. Returns 0 on success, -ENODEV if the card + * doesn't support this, -ESTALE if the generation doesn't + * match. + */ + int (*enable_phys_dma)(struct fw_card *card, + int node_id, int generation); + + u64 (*get_bus_time)(struct fw_card *card); + + struct fw_iso_context * + (*allocate_iso_context)(struct fw_card *card, + int type, int channel, size_t header_size); + void (*free_iso_context)(struct fw_iso_context *ctx); + + int (*start_iso)(struct fw_iso_context *ctx, + s32 cycle, u32 sync, u32 tags); + + int (*queue_iso)(struct fw_iso_context *ctx, + struct fw_iso_packet *packet, + struct fw_iso_buffer *buffer, + unsigned long payload); + + int (*stop_iso)(struct fw_iso_context *ctx); +}; + +void fw_card_initialize(struct fw_card *card, + const struct fw_card_driver *driver, struct device *device); +int fw_card_add(struct fw_card *card, + u32 max_receive, u32 link_speed, u64 guid); +void fw_core_remove_card(struct fw_card *card); +int fw_core_initiate_bus_reset(struct fw_card *card, int short_reset); +int fw_compute_block_crc(u32 *block); +void fw_schedule_bm_work(struct fw_card *card, unsigned long delay); + + +/* -cdev */ + +extern const struct file_operations fw_device_ops; + +void fw_device_cdev_update(struct fw_device *device); +void fw_device_cdev_remove(struct fw_device *device); + + +/* -device */ + +extern struct rw_semaphore fw_device_rwsem; +extern struct idr fw_device_idr; +extern int fw_cdev_major; + +struct fw_device *fw_device_get_by_devt(dev_t devt); +int fw_device_set_broadcast_channel(struct device *dev, void *gen); +void fw_node_event(struct fw_card *card, struct fw_node *node, int event); + + +/* -iso */ + +int fw_iso_buffer_map(struct fw_iso_buffer *buffer, struct vm_area_struct *vma); +void fw_iso_resource_manage(struct fw_card *card, int generation, + u64 channels_mask, int *channel, int *bandwidth, bool allocate); + + +/* -topology */ + +enum { + FW_NODE_CREATED, + FW_NODE_UPDATED, + FW_NODE_DESTROYED, + FW_NODE_LINK_ON, + FW_NODE_LINK_OFF, + FW_NODE_INITIATED_RESET, +}; + +struct fw_node { + u16 node_id; + u8 color; + u8 port_count; + u8 link_on:1; + u8 initiated_reset:1; + u8 b_path:1; + u8 phy_speed:2; /* As in the self ID packet. */ + u8 max_speed:2; /* Minimum of all phy-speeds on the path from the + * local node to this node. */ + u8 max_depth:4; /* Maximum depth to any leaf node */ + u8 max_hops:4; /* Max hops in this sub tree */ + atomic_t ref_count; + + /* For serializing node topology into a list. */ + struct list_head link; + + /* Upper layer specific data. */ + void *data; + + struct fw_node *ports[0]; +}; + +static inline struct fw_node *fw_node_get(struct fw_node *node) +{ + atomic_inc(&node->ref_count); + + return node; +} + +static inline void fw_node_put(struct fw_node *node) +{ + if (atomic_dec_and_test(&node->ref_count)) + kfree(node); +} + +void fw_core_handle_bus_reset(struct fw_card *card, int node_id, + int generation, int self_id_count, u32 *self_ids); +void fw_destroy_nodes(struct fw_card *card); + +/* + * Check whether new_generation is the immediate successor of old_generation. + * Take counter roll-over at 255 (as per OHCI) into account. + */ +static inline bool is_next_generation(int new_generation, int old_generation) +{ + return (new_generation & 0xff) == ((old_generation + 1) & 0xff); +} + + +/* -transaction */ + +#define TCODE_IS_READ_REQUEST(tcode) (((tcode) & ~1) == 4) +#define TCODE_IS_BLOCK_PACKET(tcode) (((tcode) & 1) != 0) +#define TCODE_IS_REQUEST(tcode) (((tcode) & 2) == 0) +#define TCODE_IS_RESPONSE(tcode) (((tcode) & 2) != 0) +#define TCODE_HAS_REQUEST_DATA(tcode) (((tcode) & 12) != 4) +#define TCODE_HAS_RESPONSE_DATA(tcode) (((tcode) & 12) != 0) + +#define LOCAL_BUS 0xffc0 + +void fw_core_handle_request(struct fw_card *card, struct fw_packet *request); +void fw_core_handle_response(struct fw_card *card, struct fw_packet *packet); +void fw_fill_response(struct fw_packet *response, u32 *request_header, + int rcode, void *payload, size_t length); +void fw_flush_transactions(struct fw_card *card); +void fw_send_phy_config(struct fw_card *card, + int node_id, int generation, int gap_count); + +#endif /* _FIREWIRE_CORE_H */ diff --git a/drivers/firewire/fw-device.h b/drivers/firewire/fw-device.h deleted file mode 100644 index 97588937c018..000000000000 --- a/drivers/firewire/fw-device.h +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Copyright (C) 2005-2006 Kristian Hoegsberg - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __fw_device_h -#define __fw_device_h - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -enum fw_device_state { - FW_DEVICE_INITIALIZING, - FW_DEVICE_RUNNING, - FW_DEVICE_GONE, - FW_DEVICE_SHUTDOWN, -}; - -struct fw_attribute_group { - struct attribute_group *groups[2]; - struct attribute_group group; - struct attribute *attrs[11]; -}; - -struct fw_node; -struct fw_card; - -/* - * Note, fw_device.generation always has to be read before fw_device.node_id. - * Use SMP memory barriers to ensure this. Otherwise requests will be sent - * to an outdated node_id if the generation was updated in the meantime due - * to a bus reset. - * - * Likewise, fw-core will take care to update .node_id before .generation so - * that whenever fw_device.generation is current WRT the actual bus generation, - * fw_device.node_id is guaranteed to be current too. - * - * The same applies to fw_device.card->node_id vs. fw_device.generation. - * - * fw_device.config_rom and fw_device.config_rom_length may be accessed during - * the lifetime of any fw_unit belonging to the fw_device, before device_del() - * was called on the last fw_unit. Alternatively, they may be accessed while - * holding fw_device_rwsem. - */ -struct fw_device { - atomic_t state; - struct fw_node *node; - int node_id; - int generation; - unsigned max_speed; - struct fw_card *card; - struct device device; - - struct mutex client_list_mutex; - struct list_head client_list; - - u32 *config_rom; - size_t config_rom_length; - int config_rom_retries; - unsigned cmc:1; - unsigned bc_implemented:2; - - struct delayed_work work; - struct fw_attribute_group attribute_group; -}; - -static inline struct fw_device *fw_device(struct device *dev) -{ - return container_of(dev, struct fw_device, device); -} - -static inline int fw_device_is_shutdown(struct fw_device *device) -{ - return atomic_read(&device->state) == FW_DEVICE_SHUTDOWN; -} - -static inline struct fw_device *fw_device_get(struct fw_device *device) -{ - get_device(&device->device); - - return device; -} - -static inline void fw_device_put(struct fw_device *device) -{ - put_device(&device->device); -} - -struct fw_device *fw_device_get_by_devt(dev_t devt); -int fw_device_enable_phys_dma(struct fw_device *device); -void fw_device_set_broadcast_channel(struct fw_device *device, int generation); - -void fw_device_cdev_update(struct fw_device *device); -void fw_device_cdev_remove(struct fw_device *device); - -extern struct rw_semaphore fw_device_rwsem; -extern struct idr fw_device_idr; -extern int fw_cdev_major; - -/* - * fw_unit.directory must not be accessed after device_del(&fw_unit.device). - */ -struct fw_unit { - struct device device; - u32 *directory; - struct fw_attribute_group attribute_group; -}; - -static inline struct fw_unit *fw_unit(struct device *dev) -{ - return container_of(dev, struct fw_unit, device); -} - -static inline struct fw_unit *fw_unit_get(struct fw_unit *unit) -{ - get_device(&unit->device); - - return unit; -} - -static inline void fw_unit_put(struct fw_unit *unit) -{ - put_device(&unit->device); -} - -#define CSR_OFFSET 0x40 -#define CSR_LEAF 0x80 -#define CSR_DIRECTORY 0xc0 - -#define CSR_DESCRIPTOR 0x01 -#define CSR_VENDOR 0x03 -#define CSR_HARDWARE_VERSION 0x04 -#define CSR_NODE_CAPABILITIES 0x0c -#define CSR_UNIT 0x11 -#define CSR_SPECIFIER_ID 0x12 -#define CSR_VERSION 0x13 -#define CSR_DEPENDENT_INFO 0x14 -#define CSR_MODEL 0x17 -#define CSR_INSTANCE 0x18 -#define CSR_DIRECTORY_ID 0x20 - -struct fw_csr_iterator { - u32 *p; - u32 *end; -}; - -void fw_csr_iterator_init(struct fw_csr_iterator *ci, u32 *p); -int fw_csr_iterator_next(struct fw_csr_iterator *ci, - int *key, int *value); - -#define FW_MATCH_VENDOR 0x0001 -#define FW_MATCH_MODEL 0x0002 -#define FW_MATCH_SPECIFIER_ID 0x0004 -#define FW_MATCH_VERSION 0x0008 - -struct fw_device_id { - u32 match_flags; - u32 vendor; - u32 model; - u32 specifier_id; - u32 version; - void *driver_data; -}; - -struct fw_driver { - struct device_driver driver; - /* Called when the parent device sits through a bus reset. */ - void (*update) (struct fw_unit *unit); - const struct fw_device_id *id_table; -}; - -static inline struct fw_driver *fw_driver(struct device_driver *drv) -{ - return container_of(drv, struct fw_driver, driver); -} - -extern const struct file_operations fw_device_ops; - -#endif /* __fw_device_h */ diff --git a/drivers/firewire/fw-topology.h b/drivers/firewire/fw-topology.h deleted file mode 100644 index 3c497bb4fae4..000000000000 --- a/drivers/firewire/fw-topology.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2003-2006 Kristian Hoegsberg - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __fw_topology_h -#define __fw_topology_h - -#include -#include - -#include - -enum { - FW_NODE_CREATED, - FW_NODE_UPDATED, - FW_NODE_DESTROYED, - FW_NODE_LINK_ON, - FW_NODE_LINK_OFF, - FW_NODE_INITIATED_RESET, -}; - -struct fw_node { - u16 node_id; - u8 color; - u8 port_count; - u8 link_on : 1; - u8 initiated_reset : 1; - u8 b_path : 1; - u8 phy_speed : 2; /* As in the self ID packet. */ - u8 max_speed : 2; /* Minimum of all phy-speeds on the path from the - * local node to this node. */ - u8 max_depth : 4; /* Maximum depth to any leaf node */ - u8 max_hops : 4; /* Max hops in this sub tree */ - atomic_t ref_count; - - /* For serializing node topology into a list. */ - struct list_head link; - - /* Upper layer specific data. */ - void *data; - - struct fw_node *ports[0]; -}; - -static inline struct fw_node *fw_node_get(struct fw_node *node) -{ - atomic_inc(&node->ref_count); - - return node; -} - -static inline void fw_node_put(struct fw_node *node) -{ - if (atomic_dec_and_test(&node->ref_count)) - kfree(node); -} - -struct fw_card; -void fw_destroy_nodes(struct fw_card *card); - -int fw_compute_block_crc(u32 *block); - -#endif /* __fw_topology_h */ diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c new file mode 100644 index 000000000000..a42209a73aed --- /dev/null +++ b/drivers/firewire/net.c @@ -0,0 +1,1655 @@ +/* + * IPv4 over IEEE 1394, per RFC 2734 + * + * Copyright (C) 2009 Jay Fenlason + * + * based on eth1394 by Ben Collins et al + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define FWNET_MAX_FRAGMENTS 25 /* arbitrary limit */ +#define FWNET_ISO_PAGE_COUNT (PAGE_SIZE < 16 * 1024 ? 4 : 2) + +#define IEEE1394_BROADCAST_CHANNEL 31 +#define IEEE1394_ALL_NODES (0xffc0 | 0x003f) +#define IEEE1394_MAX_PAYLOAD_S100 512 +#define FWNET_NO_FIFO_ADDR (~0ULL) + +#define IANA_SPECIFIER_ID 0x00005eU +#define RFC2734_SW_VERSION 0x000001U + +#define IEEE1394_GASP_HDR_SIZE 8 + +#define RFC2374_UNFRAG_HDR_SIZE 4 +#define RFC2374_FRAG_HDR_SIZE 8 +#define RFC2374_FRAG_OVERHEAD 4 + +#define RFC2374_HDR_UNFRAG 0 /* unfragmented */ +#define RFC2374_HDR_FIRSTFRAG 1 /* first fragment */ +#define RFC2374_HDR_LASTFRAG 2 /* last fragment */ +#define RFC2374_HDR_INTFRAG 3 /* interior fragment */ + +#define RFC2734_HW_ADDR_LEN 16 + +struct rfc2734_arp { + __be16 hw_type; /* 0x0018 */ + __be16 proto_type; /* 0x0806 */ + u8 hw_addr_len; /* 16 */ + u8 ip_addr_len; /* 4 */ + __be16 opcode; /* ARP Opcode */ + /* Above is exactly the same format as struct arphdr */ + + __be64 s_uniq_id; /* Sender's 64bit EUI */ + u8 max_rec; /* Sender's max packet size */ + u8 sspd; /* Sender's max speed */ + __be16 fifo_hi; /* hi 16bits of sender's FIFO addr */ + __be32 fifo_lo; /* lo 32bits of sender's FIFO addr */ + __be32 sip; /* Sender's IP Address */ + __be32 tip; /* IP Address of requested hw addr */ +} __attribute__((packed)); + +/* This header format is specific to this driver implementation. */ +#define FWNET_ALEN 8 +#define FWNET_HLEN 10 +struct fwnet_header { + u8 h_dest[FWNET_ALEN]; /* destination address */ + __be16 h_proto; /* packet type ID field */ +} __attribute__((packed)); + +/* IPv4 and IPv6 encapsulation header */ +struct rfc2734_header { + u32 w0; + u32 w1; +}; + +#define fwnet_get_hdr_lf(h) (((h)->w0 & 0xc0000000) >> 30) +#define fwnet_get_hdr_ether_type(h) (((h)->w0 & 0x0000ffff)) +#define fwnet_get_hdr_dg_size(h) (((h)->w0 & 0x0fff0000) >> 16) +#define fwnet_get_hdr_fg_off(h) (((h)->w0 & 0x00000fff)) +#define fwnet_get_hdr_dgl(h) (((h)->w1 & 0xffff0000) >> 16) + +#define fwnet_set_hdr_lf(lf) ((lf) << 30) +#define fwnet_set_hdr_ether_type(et) (et) +#define fwnet_set_hdr_dg_size(dgs) ((dgs) << 16) +#define fwnet_set_hdr_fg_off(fgo) (fgo) + +#define fwnet_set_hdr_dgl(dgl) ((dgl) << 16) + +static inline void fwnet_make_uf_hdr(struct rfc2734_header *hdr, + unsigned ether_type) +{ + hdr->w0 = fwnet_set_hdr_lf(RFC2374_HDR_UNFRAG) + | fwnet_set_hdr_ether_type(ether_type); +} + +static inline void fwnet_make_ff_hdr(struct rfc2734_header *hdr, + unsigned ether_type, unsigned dg_size, unsigned dgl) +{ + hdr->w0 = fwnet_set_hdr_lf(RFC2374_HDR_FIRSTFRAG) + | fwnet_set_hdr_dg_size(dg_size) + | fwnet_set_hdr_ether_type(ether_type); + hdr->w1 = fwnet_set_hdr_dgl(dgl); +} + +static inline void fwnet_make_sf_hdr(struct rfc2734_header *hdr, + unsigned lf, unsigned dg_size, unsigned fg_off, unsigned dgl) +{ + hdr->w0 = fwnet_set_hdr_lf(lf) + | fwnet_set_hdr_dg_size(dg_size) + | fwnet_set_hdr_fg_off(fg_off); + hdr->w1 = fwnet_set_hdr_dgl(dgl); +} + +/* This list keeps track of what parts of the datagram have been filled in */ +struct fwnet_fragment_info { + struct list_head fi_link; + u16 offset; + u16 len; +}; + +struct fwnet_partial_datagram { + struct list_head pd_link; + struct list_head fi_list; + struct sk_buff *skb; + /* FIXME Why not use skb->data? */ + char *pbuf; + u16 datagram_label; + u16 ether_type; + u16 datagram_size; +}; + +static DEFINE_MUTEX(fwnet_device_mutex); +static LIST_HEAD(fwnet_device_list); + +struct fwnet_device { + struct list_head dev_link; + spinlock_t lock; + enum { + FWNET_BROADCAST_ERROR, + FWNET_BROADCAST_RUNNING, + FWNET_BROADCAST_STOPPED, + } broadcast_state; + struct fw_iso_context *broadcast_rcv_context; + struct fw_iso_buffer broadcast_rcv_buffer; + void **broadcast_rcv_buffer_ptrs; + unsigned broadcast_rcv_next_ptr; + unsigned num_broadcast_rcv_ptrs; + unsigned rcv_buffer_size; + /* + * This value is the maximum unfragmented datagram size that can be + * sent by the hardware. It already has the GASP overhead and the + * unfragmented datagram header overhead calculated into it. + */ + unsigned broadcast_xmt_max_payload; + u16 broadcast_xmt_datagramlabel; + + /* + * The CSR address that remote nodes must send datagrams to for us to + * receive them. + */ + struct fw_address_handler handler; + u64 local_fifo; + + /* List of packets to be sent */ + struct list_head packet_list; + /* + * List of packets that were broadcasted. When we get an ISO interrupt + * one of them has been sent + */ + struct list_head broadcasted_list; + /* List of packets that have been sent but not yet acked */ + struct list_head sent_list; + + struct list_head peer_list; + struct fw_card *card; + struct net_device *netdev; +}; + +struct fwnet_peer { + struct list_head peer_link; + struct fwnet_device *dev; + u64 guid; + u64 fifo; + + /* guarded by dev->lock */ + struct list_head pd_list; /* received partial datagrams */ + unsigned pdg_size; /* pd_list size */ + + u16 datagram_label; /* outgoing datagram label */ + unsigned max_payload; /* includes RFC2374_FRAG_HDR_SIZE overhead */ + int node_id; + int generation; + unsigned speed; +}; + +/* This is our task struct. It's used for the packet complete callback. */ +struct fwnet_packet_task { + /* + * ptask can actually be on dev->packet_list, dev->broadcasted_list, + * or dev->sent_list depending on its current state. + */ + struct list_head pt_link; + struct fw_transaction transaction; + struct rfc2734_header hdr; + struct sk_buff *skb; + struct fwnet_device *dev; + + int outstanding_pkts; + unsigned max_payload; + u64 fifo_addr; + u16 dest_node; + u8 generation; + u8 speed; +}; + +/* + * saddr == NULL means use device source address. + * daddr == NULL means leave destination address (eg unresolved arp). + */ +static int fwnet_header_create(struct sk_buff *skb, struct net_device *net, + unsigned short type, const void *daddr, + const void *saddr, unsigned len) +{ + struct fwnet_header *h; + + h = (struct fwnet_header *)skb_push(skb, sizeof(*h)); + put_unaligned_be16(type, &h->h_proto); + + if (net->flags & (IFF_LOOPBACK | IFF_NOARP)) { + memset(h->h_dest, 0, net->addr_len); + + return net->hard_header_len; + } + + if (daddr) { + memcpy(h->h_dest, daddr, net->addr_len); + + return net->hard_header_len; + } + + return -net->hard_header_len; +} + +static int fwnet_header_rebuild(struct sk_buff *skb) +{ + struct fwnet_header *h = (struct fwnet_header *)skb->data; + + if (get_unaligned_be16(&h->h_proto) == ETH_P_IP) + return arp_find((unsigned char *)&h->h_dest, skb); + + fw_notify("%s: unable to resolve type %04x addresses\n", + skb->dev->name, be16_to_cpu(h->h_proto)); + return 0; +} + +static int fwnet_header_cache(const struct neighbour *neigh, + struct hh_cache *hh) +{ + struct net_device *net; + struct fwnet_header *h; + + if (hh->hh_type == cpu_to_be16(ETH_P_802_3)) + return -1; + net = neigh->dev; + h = (struct fwnet_header *)((u8 *)hh->hh_data + 16 - sizeof(*h)); + h->h_proto = hh->hh_type; + memcpy(h->h_dest, neigh->ha, net->addr_len); + hh->hh_len = FWNET_HLEN; + + return 0; +} + +/* Called by Address Resolution module to notify changes in address. */ +static void fwnet_header_cache_update(struct hh_cache *hh, + const struct net_device *net, const unsigned char *haddr) +{ + memcpy((u8 *)hh->hh_data + 16 - FWNET_HLEN, haddr, net->addr_len); +} + +static int fwnet_header_parse(const struct sk_buff *skb, unsigned char *haddr) +{ + memcpy(haddr, skb->dev->dev_addr, FWNET_ALEN); + + return FWNET_ALEN; +} + +static const struct header_ops fwnet_header_ops = { + .create = fwnet_header_create, + .rebuild = fwnet_header_rebuild, + .cache = fwnet_header_cache, + .cache_update = fwnet_header_cache_update, + .parse = fwnet_header_parse, +}; + +/* FIXME: is this correct for all cases? */ +static bool fwnet_frag_overlap(struct fwnet_partial_datagram *pd, + unsigned offset, unsigned len) +{ + struct fwnet_fragment_info *fi; + unsigned end = offset + len; + + list_for_each_entry(fi, &pd->fi_list, fi_link) + if (offset < fi->offset + fi->len && end > fi->offset) + return true; + + return false; +} + +/* Assumes that new fragment does not overlap any existing fragments */ +static struct fwnet_fragment_info *fwnet_frag_new( + struct fwnet_partial_datagram *pd, unsigned offset, unsigned len) +{ + struct fwnet_fragment_info *fi, *fi2, *new; + struct list_head *list; + + list = &pd->fi_list; + list_for_each_entry(fi, &pd->fi_list, fi_link) { + if (fi->offset + fi->len == offset) { + /* The new fragment can be tacked on to the end */ + /* Did the new fragment plug a hole? */ + fi2 = list_entry(fi->fi_link.next, + struct fwnet_fragment_info, fi_link); + if (fi->offset + fi->len == fi2->offset) { + /* glue fragments together */ + fi->len += len + fi2->len; + list_del(&fi2->fi_link); + kfree(fi2); + } else { + fi->len += len; + } + + return fi; + } + if (offset + len == fi->offset) { + /* The new fragment can be tacked on to the beginning */ + /* Did the new fragment plug a hole? */ + fi2 = list_entry(fi->fi_link.prev, + struct fwnet_fragment_info, fi_link); + if (fi2->offset + fi2->len == fi->offset) { + /* glue fragments together */ + fi2->len += fi->len + len; + list_del(&fi->fi_link); + kfree(fi); + + return fi2; + } + fi->offset = offset; + fi->len += len; + + return fi; + } + if (offset > fi->offset + fi->len) { + list = &fi->fi_link; + break; + } + if (offset + len < fi->offset) { + list = fi->fi_link.prev; + break; + } + } + + new = kmalloc(sizeof(*new), GFP_ATOMIC); + if (!new) { + fw_error("out of memory\n"); + return NULL; + } + + new->offset = offset; + new->len = len; + list_add(&new->fi_link, list); + + return new; +} + +static struct fwnet_partial_datagram *fwnet_pd_new(struct net_device *net, + struct fwnet_peer *peer, u16 datagram_label, unsigned dg_size, + void *frag_buf, unsigned frag_off, unsigned frag_len) +{ + struct fwnet_partial_datagram *new; + struct fwnet_fragment_info *fi; + + new = kmalloc(sizeof(*new), GFP_ATOMIC); + if (!new) + goto fail; + + INIT_LIST_HEAD(&new->fi_list); + fi = fwnet_frag_new(new, frag_off, frag_len); + if (fi == NULL) + goto fail_w_new; + + new->datagram_label = datagram_label; + new->datagram_size = dg_size; + new->skb = dev_alloc_skb(dg_size + net->hard_header_len + 15); + if (new->skb == NULL) + goto fail_w_fi; + + skb_reserve(new->skb, (net->hard_header_len + 15) & ~15); + new->pbuf = skb_put(new->skb, dg_size); + memcpy(new->pbuf + frag_off, frag_buf, frag_len); + list_add_tail(&new->pd_link, &peer->pd_list); + + return new; + +fail_w_fi: + kfree(fi); +fail_w_new: + kfree(new); +fail: + fw_error("out of memory\n"); + + return NULL; +} + +static struct fwnet_partial_datagram *fwnet_pd_find(struct fwnet_peer *peer, + u16 datagram_label) +{ + struct fwnet_partial_datagram *pd; + + list_for_each_entry(pd, &peer->pd_list, pd_link) + if (pd->datagram_label == datagram_label) + return pd; + + return NULL; +} + + +static void fwnet_pd_delete(struct fwnet_partial_datagram *old) +{ + struct fwnet_fragment_info *fi, *n; + + list_for_each_entry_safe(fi, n, &old->fi_list, fi_link) + kfree(fi); + + list_del(&old->pd_link); + dev_kfree_skb_any(old->skb); + kfree(old); +} + +static bool fwnet_pd_update(struct fwnet_peer *peer, + struct fwnet_partial_datagram *pd, void *frag_buf, + unsigned frag_off, unsigned frag_len) +{ + if (fwnet_frag_new(pd, frag_off, frag_len) == NULL) + return false; + + memcpy(pd->pbuf + frag_off, frag_buf, frag_len); + + /* + * Move list entry to beginnig of list so that oldest partial + * datagrams percolate to the end of the list + */ + list_move_tail(&pd->pd_link, &peer->pd_list); + + return true; +} + +static bool fwnet_pd_is_complete(struct fwnet_partial_datagram *pd) +{ + struct fwnet_fragment_info *fi; + + fi = list_entry(pd->fi_list.next, struct fwnet_fragment_info, fi_link); + + return fi->len == pd->datagram_size; +} + +/* caller must hold dev->lock */ +static struct fwnet_peer *fwnet_peer_find_by_guid(struct fwnet_device *dev, + u64 guid) +{ + struct fwnet_peer *peer; + + list_for_each_entry(peer, &dev->peer_list, peer_link) + if (peer->guid == guid) + return peer; + + return NULL; +} + +/* caller must hold dev->lock */ +static struct fwnet_peer *fwnet_peer_find_by_node_id(struct fwnet_device *dev, + int node_id, int generation) +{ + struct fwnet_peer *peer; + + list_for_each_entry(peer, &dev->peer_list, peer_link) + if (peer->node_id == node_id && + peer->generation == generation) + return peer; + + return NULL; +} + +/* See IEEE 1394-2008 table 6-4, table 8-8, table 16-18. */ +static unsigned fwnet_max_payload(unsigned max_rec, unsigned speed) +{ + max_rec = min(max_rec, speed + 8); + max_rec = min(max_rec, 0xbU); /* <= 4096 */ + if (max_rec < 8) { + fw_notify("max_rec %x out of range\n", max_rec); + max_rec = 8; + } + + return (1 << (max_rec + 1)) - RFC2374_FRAG_HDR_SIZE; +} + + +static int fwnet_finish_incoming_packet(struct net_device *net, + struct sk_buff *skb, u16 source_node_id, + bool is_broadcast, u16 ether_type) +{ + struct fwnet_device *dev; + static const __be64 broadcast_hw = cpu_to_be64(~0ULL); + int status; + __be64 guid; + + dev = netdev_priv(net); + /* Write metadata, and then pass to the receive level */ + skb->dev = net; + skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */ + + /* + * Parse the encapsulation header. This actually does the job of + * converting to an ethernet frame header, as well as arp + * conversion if needed. ARP conversion is easier in this + * direction, since we are using ethernet as our backend. + */ + /* + * If this is an ARP packet, convert it. First, we want to make + * use of some of the fields, since they tell us a little bit + * about the sending machine. + */ + if (ether_type == ETH_P_ARP) { + struct rfc2734_arp *arp1394; + struct arphdr *arp; + unsigned char *arp_ptr; + u64 fifo_addr; + u64 peer_guid; + unsigned sspd; + u16 max_payload; + struct fwnet_peer *peer; + unsigned long flags; + + arp1394 = (struct rfc2734_arp *)skb->data; + arp = (struct arphdr *)skb->data; + arp_ptr = (unsigned char *)(arp + 1); + peer_guid = get_unaligned_be64(&arp1394->s_uniq_id); + fifo_addr = (u64)get_unaligned_be16(&arp1394->fifo_hi) << 32 + | get_unaligned_be32(&arp1394->fifo_lo); + + sspd = arp1394->sspd; + /* Sanity check. OS X 10.3 PPC reportedly sends 131. */ + if (sspd > SCODE_3200) { + fw_notify("sspd %x out of range\n", sspd); + sspd = SCODE_3200; + } + max_payload = fwnet_max_payload(arp1394->max_rec, sspd); + + spin_lock_irqsave(&dev->lock, flags); + peer = fwnet_peer_find_by_guid(dev, peer_guid); + if (peer) { + peer->fifo = fifo_addr; + + if (peer->speed > sspd) + peer->speed = sspd; + if (peer->max_payload > max_payload) + peer->max_payload = max_payload; + } + spin_unlock_irqrestore(&dev->lock, flags); + + if (!peer) { + fw_notify("No peer for ARP packet from %016llx\n", + (unsigned long long)peer_guid); + goto failed_proto; + } + + /* + * Now that we're done with the 1394 specific stuff, we'll + * need to alter some of the data. Believe it or not, all + * that needs to be done is sender_IP_address needs to be + * moved, the destination hardware address get stuffed + * in and the hardware address length set to 8. + * + * IMPORTANT: The code below overwrites 1394 specific data + * needed above so keep the munging of the data for the + * higher level IP stack last. + */ + + arp->ar_hln = 8; + /* skip over sender unique id */ + arp_ptr += arp->ar_hln; + /* move sender IP addr */ + put_unaligned(arp1394->sip, (u32 *)arp_ptr); + /* skip over sender IP addr */ + arp_ptr += arp->ar_pln; + + if (arp->ar_op == htons(ARPOP_REQUEST)) + memset(arp_ptr, 0, sizeof(u64)); + else + memcpy(arp_ptr, net->dev_addr, sizeof(u64)); + } + + /* Now add the ethernet header. */ + guid = cpu_to_be64(dev->card->guid); + if (dev_hard_header(skb, net, ether_type, + is_broadcast ? &broadcast_hw : &guid, + NULL, skb->len) >= 0) { + struct fwnet_header *eth; + u16 *rawp; + __be16 protocol; + + skb_reset_mac_header(skb); + skb_pull(skb, sizeof(*eth)); + eth = (struct fwnet_header *)skb_mac_header(skb); + if (*eth->h_dest & 1) { + if (memcmp(eth->h_dest, net->broadcast, + net->addr_len) == 0) + skb->pkt_type = PACKET_BROADCAST; +#if 0 + else + skb->pkt_type = PACKET_MULTICAST; +#endif + } else { + if (memcmp(eth->h_dest, net->dev_addr, net->addr_len)) + skb->pkt_type = PACKET_OTHERHOST; + } + if (ntohs(eth->h_proto) >= 1536) { + protocol = eth->h_proto; + } else { + rawp = (u16 *)skb->data; + if (*rawp == 0xffff) + protocol = htons(ETH_P_802_3); + else + protocol = htons(ETH_P_802_2); + } + skb->protocol = protocol; + } + status = netif_rx(skb); + if (status == NET_RX_DROP) { + net->stats.rx_errors++; + net->stats.rx_dropped++; + } else { + net->stats.rx_packets++; + net->stats.rx_bytes += skb->len; + } + if (netif_queue_stopped(net)) + netif_wake_queue(net); + + return 0; + + failed_proto: + net->stats.rx_errors++; + net->stats.rx_dropped++; + + dev_kfree_skb_any(skb); + if (netif_queue_stopped(net)) + netif_wake_queue(net); + + net->last_rx = jiffies; + + return 0; +} + +static int fwnet_incoming_packet(struct fwnet_device *dev, __be32 *buf, int len, + int source_node_id, int generation, + bool is_broadcast) +{ + struct sk_buff *skb; + struct net_device *net = dev->netdev; + struct rfc2734_header hdr; + unsigned lf; + unsigned long flags; + struct fwnet_peer *peer; + struct fwnet_partial_datagram *pd; + int fg_off; + int dg_size; + u16 datagram_label; + int retval; + u16 ether_type; + + hdr.w0 = be32_to_cpu(buf[0]); + lf = fwnet_get_hdr_lf(&hdr); + if (lf == RFC2374_HDR_UNFRAG) { + /* + * An unfragmented datagram has been received by the ieee1394 + * bus. Build an skbuff around it so we can pass it to the + * high level network layer. + */ + ether_type = fwnet_get_hdr_ether_type(&hdr); + buf++; + len -= RFC2374_UNFRAG_HDR_SIZE; + + skb = dev_alloc_skb(len + net->hard_header_len + 15); + if (unlikely(!skb)) { + fw_error("out of memory\n"); + net->stats.rx_dropped++; + + return -1; + } + skb_reserve(skb, (net->hard_header_len + 15) & ~15); + memcpy(skb_put(skb, len), buf, len); + + return fwnet_finish_incoming_packet(net, skb, source_node_id, + is_broadcast, ether_type); + } + /* A datagram fragment has been received, now the fun begins. */ + hdr.w1 = ntohl(buf[1]); + buf += 2; + len -= RFC2374_FRAG_HDR_SIZE; + if (lf == RFC2374_HDR_FIRSTFRAG) { + ether_type = fwnet_get_hdr_ether_type(&hdr); + fg_off = 0; + } else { + ether_type = 0; + fg_off = fwnet_get_hdr_fg_off(&hdr); + } + datagram_label = fwnet_get_hdr_dgl(&hdr); + dg_size = fwnet_get_hdr_dg_size(&hdr); /* ??? + 1 */ + + spin_lock_irqsave(&dev->lock, flags); + + peer = fwnet_peer_find_by_node_id(dev, source_node_id, generation); + if (!peer) + goto bad_proto; + + pd = fwnet_pd_find(peer, datagram_label); + if (pd == NULL) { + while (peer->pdg_size >= FWNET_MAX_FRAGMENTS) { + /* remove the oldest */ + fwnet_pd_delete(list_first_entry(&peer->pd_list, + struct fwnet_partial_datagram, pd_link)); + peer->pdg_size--; + } + pd = fwnet_pd_new(net, peer, datagram_label, + dg_size, buf, fg_off, len); + if (pd == NULL) { + retval = -ENOMEM; + goto bad_proto; + } + peer->pdg_size++; + } else { + if (fwnet_frag_overlap(pd, fg_off, len) || + pd->datagram_size != dg_size) { + /* + * Differing datagram sizes or overlapping fragments, + * discard old datagram and start a new one. + */ + fwnet_pd_delete(pd); + pd = fwnet_pd_new(net, peer, datagram_label, + dg_size, buf, fg_off, len); + if (pd == NULL) { + retval = -ENOMEM; + peer->pdg_size--; + goto bad_proto; + } + } else { + if (!fwnet_pd_update(peer, pd, buf, fg_off, len)) { + /* + * Couldn't save off fragment anyway + * so might as well obliterate the + * datagram now. + */ + fwnet_pd_delete(pd); + peer->pdg_size--; + goto bad_proto; + } + } + } /* new datagram or add to existing one */ + + if (lf == RFC2374_HDR_FIRSTFRAG) + pd->ether_type = ether_type; + + if (fwnet_pd_is_complete(pd)) { + ether_type = pd->ether_type; + peer->pdg_size--; + skb = skb_get(pd->skb); + fwnet_pd_delete(pd); + + spin_unlock_irqrestore(&dev->lock, flags); + + return fwnet_finish_incoming_packet(net, skb, source_node_id, + false, ether_type); + } + /* + * Datagram is not complete, we're done for the + * moment. + */ + spin_unlock_irqrestore(&dev->lock, flags); + + return 0; + + bad_proto: + spin_unlock_irqrestore(&dev->lock, flags); + + if (netif_queue_stopped(net)) + netif_wake_queue(net); + + return 0; +} + +static void fwnet_receive_packet(struct fw_card *card, struct fw_request *r, + int tcode, int destination, int source, int generation, + int speed, unsigned long long offset, void *payload, + size_t length, void *callback_data) +{ + struct fwnet_device *dev = callback_data; + int rcode; + + if (destination == IEEE1394_ALL_NODES) { + kfree(r); + + return; + } + + if (offset != dev->handler.offset) + rcode = RCODE_ADDRESS_ERROR; + else if (tcode != TCODE_WRITE_BLOCK_REQUEST) + rcode = RCODE_TYPE_ERROR; + else if (fwnet_incoming_packet(dev, payload, length, + source, generation, false) != 0) { + fw_error("Incoming packet failure\n"); + rcode = RCODE_CONFLICT_ERROR; + } else + rcode = RCODE_COMPLETE; + + fw_send_response(card, r, rcode); +} + +static void fwnet_receive_broadcast(struct fw_iso_context *context, + u32 cycle, size_t header_length, void *header, void *data) +{ + struct fwnet_device *dev; + struct fw_iso_packet packet; + struct fw_card *card; + __be16 *hdr_ptr; + __be32 *buf_ptr; + int retval; + u32 length; + u16 source_node_id; + u32 specifier_id; + u32 ver; + unsigned long offset; + unsigned long flags; + + dev = data; + card = dev->card; + hdr_ptr = header; + length = be16_to_cpup(hdr_ptr); + + spin_lock_irqsave(&dev->lock, flags); + + offset = dev->rcv_buffer_size * dev->broadcast_rcv_next_ptr; + buf_ptr = dev->broadcast_rcv_buffer_ptrs[dev->broadcast_rcv_next_ptr++]; + if (dev->broadcast_rcv_next_ptr == dev->num_broadcast_rcv_ptrs) + dev->broadcast_rcv_next_ptr = 0; + + spin_unlock_irqrestore(&dev->lock, flags); + + specifier_id = (be32_to_cpu(buf_ptr[0]) & 0xffff) << 8 + | (be32_to_cpu(buf_ptr[1]) & 0xff000000) >> 24; + ver = be32_to_cpu(buf_ptr[1]) & 0xffffff; + source_node_id = be32_to_cpu(buf_ptr[0]) >> 16; + + if (specifier_id == IANA_SPECIFIER_ID && ver == RFC2734_SW_VERSION) { + buf_ptr += 2; + length -= IEEE1394_GASP_HDR_SIZE; + fwnet_incoming_packet(dev, buf_ptr, length, + source_node_id, -1, true); + } + + packet.payload_length = dev->rcv_buffer_size; + packet.interrupt = 1; + packet.skip = 0; + packet.tag = 3; + packet.sy = 0; + packet.header_length = IEEE1394_GASP_HDR_SIZE; + + spin_lock_irqsave(&dev->lock, flags); + + retval = fw_iso_context_queue(dev->broadcast_rcv_context, &packet, + &dev->broadcast_rcv_buffer, offset); + + spin_unlock_irqrestore(&dev->lock, flags); + + if (retval < 0) + fw_error("requeue failed\n"); +} + +static struct kmem_cache *fwnet_packet_task_cache; + +static int fwnet_send_packet(struct fwnet_packet_task *ptask); + +static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask) +{ + struct fwnet_device *dev; + unsigned long flags; + + dev = ptask->dev; + + spin_lock_irqsave(&dev->lock, flags); + list_del(&ptask->pt_link); + spin_unlock_irqrestore(&dev->lock, flags); + + ptask->outstanding_pkts--; /* FIXME access inside lock */ + + if (ptask->outstanding_pkts > 0) { + u16 dg_size; + u16 fg_off; + u16 datagram_label; + u16 lf; + struct sk_buff *skb; + + /* Update the ptask to point to the next fragment and send it */ + lf = fwnet_get_hdr_lf(&ptask->hdr); + switch (lf) { + case RFC2374_HDR_LASTFRAG: + case RFC2374_HDR_UNFRAG: + default: + fw_error("Outstanding packet %x lf %x, header %x,%x\n", + ptask->outstanding_pkts, lf, ptask->hdr.w0, + ptask->hdr.w1); + BUG(); + + case RFC2374_HDR_FIRSTFRAG: + /* Set frag type here for future interior fragments */ + dg_size = fwnet_get_hdr_dg_size(&ptask->hdr); + fg_off = ptask->max_payload - RFC2374_FRAG_HDR_SIZE; + datagram_label = fwnet_get_hdr_dgl(&ptask->hdr); + break; + + case RFC2374_HDR_INTFRAG: + dg_size = fwnet_get_hdr_dg_size(&ptask->hdr); + fg_off = fwnet_get_hdr_fg_off(&ptask->hdr) + + ptask->max_payload - RFC2374_FRAG_HDR_SIZE; + datagram_label = fwnet_get_hdr_dgl(&ptask->hdr); + break; + } + skb = ptask->skb; + skb_pull(skb, ptask->max_payload); + if (ptask->outstanding_pkts > 1) { + fwnet_make_sf_hdr(&ptask->hdr, RFC2374_HDR_INTFRAG, + dg_size, fg_off, datagram_label); + } else { + fwnet_make_sf_hdr(&ptask->hdr, RFC2374_HDR_LASTFRAG, + dg_size, fg_off, datagram_label); + ptask->max_payload = skb->len + RFC2374_FRAG_HDR_SIZE; + } + fwnet_send_packet(ptask); + } else { + dev_kfree_skb_any(ptask->skb); + kmem_cache_free(fwnet_packet_task_cache, ptask); + } +} + +static void fwnet_write_complete(struct fw_card *card, int rcode, + void *payload, size_t length, void *data) +{ + struct fwnet_packet_task *ptask; + + ptask = data; + + if (rcode == RCODE_COMPLETE) + fwnet_transmit_packet_done(ptask); + else + fw_error("fwnet_write_complete: failed: %x\n", rcode); + /* ??? error recovery */ +} + +static int fwnet_send_packet(struct fwnet_packet_task *ptask) +{ + struct fwnet_device *dev; + unsigned tx_len; + struct rfc2734_header *bufhdr; + unsigned long flags; + + dev = ptask->dev; + tx_len = ptask->max_payload; + switch (fwnet_get_hdr_lf(&ptask->hdr)) { + case RFC2374_HDR_UNFRAG: + bufhdr = (struct rfc2734_header *) + skb_push(ptask->skb, RFC2374_UNFRAG_HDR_SIZE); + put_unaligned_be32(ptask->hdr.w0, &bufhdr->w0); + break; + + case RFC2374_HDR_FIRSTFRAG: + case RFC2374_HDR_INTFRAG: + case RFC2374_HDR_LASTFRAG: + bufhdr = (struct rfc2734_header *) + skb_push(ptask->skb, RFC2374_FRAG_HDR_SIZE); + put_unaligned_be32(ptask->hdr.w0, &bufhdr->w0); + put_unaligned_be32(ptask->hdr.w1, &bufhdr->w1); + break; + + default: + BUG(); + } + if (ptask->dest_node == IEEE1394_ALL_NODES) { + u8 *p; + int generation; + int node_id; + + /* ptask->generation may not have been set yet */ + generation = dev->card->generation; + smp_rmb(); + node_id = dev->card->node_id; + + p = skb_push(ptask->skb, 8); + put_unaligned_be32(node_id << 16 | IANA_SPECIFIER_ID >> 8, p); + put_unaligned_be32((IANA_SPECIFIER_ID & 0xff) << 24 + | RFC2734_SW_VERSION, &p[4]); + + /* We should not transmit if broadcast_channel.valid == 0. */ + fw_send_request(dev->card, &ptask->transaction, + TCODE_STREAM_DATA, + fw_stream_packet_destination_id(3, + IEEE1394_BROADCAST_CHANNEL, 0), + generation, SCODE_100, 0ULL, ptask->skb->data, + tx_len + 8, fwnet_write_complete, ptask); + + /* FIXME race? */ + spin_lock_irqsave(&dev->lock, flags); + list_add_tail(&ptask->pt_link, &dev->broadcasted_list); + spin_unlock_irqrestore(&dev->lock, flags); + + return 0; + } + + fw_send_request(dev->card, &ptask->transaction, + TCODE_WRITE_BLOCK_REQUEST, ptask->dest_node, + ptask->generation, ptask->speed, ptask->fifo_addr, + ptask->skb->data, tx_len, fwnet_write_complete, ptask); + + /* FIXME race? */ + spin_lock_irqsave(&dev->lock, flags); + list_add_tail(&ptask->pt_link, &dev->sent_list); + spin_unlock_irqrestore(&dev->lock, flags); + + dev->netdev->trans_start = jiffies; + + return 0; +} + +static int fwnet_broadcast_start(struct fwnet_device *dev) +{ + struct fw_iso_context *context; + int retval; + unsigned num_packets; + unsigned max_receive; + struct fw_iso_packet packet; + unsigned long offset; + unsigned u; + + if (dev->local_fifo == FWNET_NO_FIFO_ADDR) { + /* outside OHCI posted write area? */ + static const struct fw_address_region region = { + .start = 0xffff00000000ULL, + .end = CSR_REGISTER_BASE, + }; + + dev->handler.length = 4096; + dev->handler.address_callback = fwnet_receive_packet; + dev->handler.callback_data = dev; + + retval = fw_core_add_address_handler(&dev->handler, ®ion); + if (retval < 0) + goto failed_initial; + + dev->local_fifo = dev->handler.offset; + } + + max_receive = 1U << (dev->card->max_receive + 1); + num_packets = (FWNET_ISO_PAGE_COUNT * PAGE_SIZE) / max_receive; + + if (!dev->broadcast_rcv_context) { + void **ptrptr; + + context = fw_iso_context_create(dev->card, + FW_ISO_CONTEXT_RECEIVE, IEEE1394_BROADCAST_CHANNEL, + dev->card->link_speed, 8, fwnet_receive_broadcast, dev); + if (IS_ERR(context)) { + retval = PTR_ERR(context); + goto failed_context_create; + } + + retval = fw_iso_buffer_init(&dev->broadcast_rcv_buffer, + dev->card, FWNET_ISO_PAGE_COUNT, DMA_FROM_DEVICE); + if (retval < 0) + goto failed_buffer_init; + + ptrptr = kmalloc(sizeof(void *) * num_packets, GFP_KERNEL); + if (!ptrptr) { + retval = -ENOMEM; + goto failed_ptrs_alloc; + } + + dev->broadcast_rcv_buffer_ptrs = ptrptr; + for (u = 0; u < FWNET_ISO_PAGE_COUNT; u++) { + void *ptr; + unsigned v; + + ptr = kmap(dev->broadcast_rcv_buffer.pages[u]); + for (v = 0; v < num_packets / FWNET_ISO_PAGE_COUNT; v++) + *ptrptr++ = (void *) + ((char *)ptr + v * max_receive); + } + dev->broadcast_rcv_context = context; + } else { + context = dev->broadcast_rcv_context; + } + + packet.payload_length = max_receive; + packet.interrupt = 1; + packet.skip = 0; + packet.tag = 3; + packet.sy = 0; + packet.header_length = IEEE1394_GASP_HDR_SIZE; + offset = 0; + + for (u = 0; u < num_packets; u++) { + retval = fw_iso_context_queue(context, &packet, + &dev->broadcast_rcv_buffer, offset); + if (retval < 0) + goto failed_rcv_queue; + + offset += max_receive; + } + dev->num_broadcast_rcv_ptrs = num_packets; + dev->rcv_buffer_size = max_receive; + dev->broadcast_rcv_next_ptr = 0U; + retval = fw_iso_context_start(context, -1, 0, + FW_ISO_CONTEXT_MATCH_ALL_TAGS); /* ??? sync */ + if (retval < 0) + goto failed_rcv_queue; + + /* FIXME: adjust it according to the min. speed of all known peers? */ + dev->broadcast_xmt_max_payload = IEEE1394_MAX_PAYLOAD_S100 + - IEEE1394_GASP_HDR_SIZE - RFC2374_UNFRAG_HDR_SIZE; + dev->broadcast_state = FWNET_BROADCAST_RUNNING; + + return 0; + + failed_rcv_queue: + kfree(dev->broadcast_rcv_buffer_ptrs); + dev->broadcast_rcv_buffer_ptrs = NULL; + failed_ptrs_alloc: + fw_iso_buffer_destroy(&dev->broadcast_rcv_buffer, dev->card); + failed_buffer_init: + fw_iso_context_destroy(context); + dev->broadcast_rcv_context = NULL; + failed_context_create: + fw_core_remove_address_handler(&dev->handler); + failed_initial: + dev->local_fifo = FWNET_NO_FIFO_ADDR; + + return retval; +} + +/* ifup */ +static int fwnet_open(struct net_device *net) +{ + struct fwnet_device *dev = netdev_priv(net); + int ret; + + if (dev->broadcast_state == FWNET_BROADCAST_ERROR) { + ret = fwnet_broadcast_start(dev); + if (ret) + return ret; + } + netif_start_queue(net); + + return 0; +} + +/* ifdown */ +static int fwnet_stop(struct net_device *net) +{ + netif_stop_queue(net); + + /* Deallocate iso context for use by other applications? */ + + return 0; +} + +static int fwnet_tx(struct sk_buff *skb, struct net_device *net) +{ + struct fwnet_header hdr_buf; + struct fwnet_device *dev = netdev_priv(net); + __be16 proto; + u16 dest_node; + unsigned max_payload; + u16 dg_size; + u16 *datagram_label_ptr; + struct fwnet_packet_task *ptask; + struct fwnet_peer *peer; + unsigned long flags; + + ptask = kmem_cache_alloc(fwnet_packet_task_cache, GFP_ATOMIC); + if (ptask == NULL) + goto fail; + + skb = skb_share_check(skb, GFP_ATOMIC); + if (!skb) + goto fail; + + /* + * Make a copy of the driver-specific header. + * We might need to rebuild the header on tx failure. + */ + memcpy(&hdr_buf, skb->data, sizeof(hdr_buf)); + skb_pull(skb, sizeof(hdr_buf)); + + proto = hdr_buf.h_proto; + dg_size = skb->len; + + /* serialize access to peer, including peer->datagram_label */ + spin_lock_irqsave(&dev->lock, flags); + + /* + * Set the transmission type for the packet. ARP packets and IP + * broadcast packets are sent via GASP. + */ + if (memcmp(hdr_buf.h_dest, net->broadcast, FWNET_ALEN) == 0 + || proto == htons(ETH_P_ARP) + || (proto == htons(ETH_P_IP) + && IN_MULTICAST(ntohl(ip_hdr(skb)->daddr)))) { + max_payload = dev->broadcast_xmt_max_payload; + datagram_label_ptr = &dev->broadcast_xmt_datagramlabel; + + ptask->fifo_addr = FWNET_NO_FIFO_ADDR; + ptask->generation = 0; + ptask->dest_node = IEEE1394_ALL_NODES; + ptask->speed = SCODE_100; + } else { + __be64 guid = get_unaligned((__be64 *)hdr_buf.h_dest); + u8 generation; + + peer = fwnet_peer_find_by_guid(dev, be64_to_cpu(guid)); + if (!peer || peer->fifo == FWNET_NO_FIFO_ADDR) + goto fail_unlock; + + generation = peer->generation; + dest_node = peer->node_id; + max_payload = peer->max_payload; + datagram_label_ptr = &peer->datagram_label; + + ptask->fifo_addr = peer->fifo; + ptask->generation = generation; + ptask->dest_node = dest_node; + ptask->speed = peer->speed; + } + + /* If this is an ARP packet, convert it */ + if (proto == htons(ETH_P_ARP)) { + struct arphdr *arp = (struct arphdr *)skb->data; + unsigned char *arp_ptr = (unsigned char *)(arp + 1); + struct rfc2734_arp *arp1394 = (struct rfc2734_arp *)skb->data; + __be32 ipaddr; + + ipaddr = get_unaligned((__be32 *)(arp_ptr + FWNET_ALEN)); + + arp1394->hw_addr_len = RFC2734_HW_ADDR_LEN; + arp1394->max_rec = dev->card->max_receive; + arp1394->sspd = dev->card->link_speed; + + put_unaligned_be16(dev->local_fifo >> 32, + &arp1394->fifo_hi); + put_unaligned_be32(dev->local_fifo & 0xffffffff, + &arp1394->fifo_lo); + put_unaligned(ipaddr, &arp1394->sip); + } + + ptask->hdr.w0 = 0; + ptask->hdr.w1 = 0; + ptask->skb = skb; + ptask->dev = dev; + + /* Does it all fit in one packet? */ + if (dg_size <= max_payload) { + fwnet_make_uf_hdr(&ptask->hdr, ntohs(proto)); + ptask->outstanding_pkts = 1; + max_payload = dg_size + RFC2374_UNFRAG_HDR_SIZE; + } else { + u16 datagram_label; + + max_payload -= RFC2374_FRAG_OVERHEAD; + datagram_label = (*datagram_label_ptr)++; + fwnet_make_ff_hdr(&ptask->hdr, ntohs(proto), dg_size, + datagram_label); + ptask->outstanding_pkts = DIV_ROUND_UP(dg_size, max_payload); + max_payload += RFC2374_FRAG_HDR_SIZE; + } + + spin_unlock_irqrestore(&dev->lock, flags); + + ptask->max_payload = max_payload; + fwnet_send_packet(ptask); + + return NETDEV_TX_OK; + + fail_unlock: + spin_unlock_irqrestore(&dev->lock, flags); + fail: + if (ptask) + kmem_cache_free(fwnet_packet_task_cache, ptask); + + if (skb != NULL) + dev_kfree_skb(skb); + + net->stats.tx_dropped++; + net->stats.tx_errors++; + + /* + * FIXME: According to a patch from 2003-02-26, "returning non-zero + * causes serious problems" here, allegedly. Before that patch, + * -ERRNO was returned which is not appropriate under Linux 2.6. + * Perhaps more needs to be done? Stop the queue in serious + * conditions and restart it elsewhere? + */ + return NETDEV_TX_OK; +} + +static int fwnet_change_mtu(struct net_device *net, int new_mtu) +{ + if (new_mtu < 68) + return -EINVAL; + + net->mtu = new_mtu; + return 0; +} + +static void fwnet_get_drvinfo(struct net_device *net, + struct ethtool_drvinfo *info) +{ + strcpy(info->driver, KBUILD_MODNAME); + strcpy(info->bus_info, "ieee1394"); +} + +static struct ethtool_ops fwnet_ethtool_ops = { + .get_drvinfo = fwnet_get_drvinfo, +}; + +static const struct net_device_ops fwnet_netdev_ops = { + .ndo_open = fwnet_open, + .ndo_stop = fwnet_stop, + .ndo_start_xmit = fwnet_tx, + .ndo_change_mtu = fwnet_change_mtu, +}; + +static void fwnet_init_dev(struct net_device *net) +{ + net->header_ops = &fwnet_header_ops; + net->netdev_ops = &fwnet_netdev_ops; + net->watchdog_timeo = 2 * HZ; + net->flags = IFF_BROADCAST | IFF_MULTICAST; + net->features = NETIF_F_HIGHDMA; + net->addr_len = FWNET_ALEN; + net->hard_header_len = FWNET_HLEN; + net->type = ARPHRD_IEEE1394; + net->tx_queue_len = 10; + SET_ETHTOOL_OPS(net, &fwnet_ethtool_ops); +} + +/* caller must hold fwnet_device_mutex */ +static struct fwnet_device *fwnet_dev_find(struct fw_card *card) +{ + struct fwnet_device *dev; + + list_for_each_entry(dev, &fwnet_device_list, dev_link) + if (dev->card == card) + return dev; + + return NULL; +} + +static int fwnet_add_peer(struct fwnet_device *dev, + struct fw_unit *unit, struct fw_device *device) +{ + struct fwnet_peer *peer; + + peer = kmalloc(sizeof(*peer), GFP_KERNEL); + if (!peer) + return -ENOMEM; + + dev_set_drvdata(&unit->device, peer); + + peer->dev = dev; + peer->guid = (u64)device->config_rom[3] << 32 | device->config_rom[4]; + peer->fifo = FWNET_NO_FIFO_ADDR; + INIT_LIST_HEAD(&peer->pd_list); + peer->pdg_size = 0; + peer->datagram_label = 0; + peer->speed = device->max_speed; + peer->max_payload = fwnet_max_payload(device->max_rec, peer->speed); + + peer->generation = device->generation; + smp_rmb(); + peer->node_id = device->node_id; + + spin_lock_irq(&dev->lock); + list_add_tail(&peer->peer_link, &dev->peer_list); + spin_unlock_irq(&dev->lock); + + return 0; +} + +static int fwnet_probe(struct device *_dev) +{ + struct fw_unit *unit = fw_unit(_dev); + struct fw_device *device = fw_parent_device(unit); + struct fw_card *card = device->card; + struct net_device *net; + bool allocated_netdev = false; + struct fwnet_device *dev; + unsigned max_mtu; + int ret; + + mutex_lock(&fwnet_device_mutex); + + dev = fwnet_dev_find(card); + if (dev) { + net = dev->netdev; + goto have_dev; + } + + net = alloc_netdev(sizeof(*dev), "firewire%d", fwnet_init_dev); + if (net == NULL) { + ret = -ENOMEM; + goto out; + } + + allocated_netdev = true; + SET_NETDEV_DEV(net, card->device); + dev = netdev_priv(net); + + spin_lock_init(&dev->lock); + dev->broadcast_state = FWNET_BROADCAST_ERROR; + dev->broadcast_rcv_context = NULL; + dev->broadcast_xmt_max_payload = 0; + dev->broadcast_xmt_datagramlabel = 0; + + dev->local_fifo = FWNET_NO_FIFO_ADDR; + + INIT_LIST_HEAD(&dev->packet_list); + INIT_LIST_HEAD(&dev->broadcasted_list); + INIT_LIST_HEAD(&dev->sent_list); + INIT_LIST_HEAD(&dev->peer_list); + + dev->card = card; + dev->netdev = net; + + /* + * Use the RFC 2734 default 1500 octets or the maximum payload + * as initial MTU + */ + max_mtu = (1 << (card->max_receive + 1)) + - sizeof(struct rfc2734_header) - IEEE1394_GASP_HDR_SIZE; + net->mtu = min(1500U, max_mtu); + + /* Set our hardware address while we're at it */ + put_unaligned_be64(card->guid, net->dev_addr); + put_unaligned_be64(~0ULL, net->broadcast); + ret = register_netdev(net); + if (ret) { + fw_error("Cannot register the driver\n"); + goto out; + } + + list_add_tail(&dev->dev_link, &fwnet_device_list); + fw_notify("%s: IPv4 over FireWire on device %016llx\n", + net->name, (unsigned long long)card->guid); + have_dev: + ret = fwnet_add_peer(dev, unit, device); + if (ret && allocated_netdev) { + unregister_netdev(net); + list_del(&dev->dev_link); + } + out: + if (ret && allocated_netdev) + free_netdev(net); + + mutex_unlock(&fwnet_device_mutex); + + return ret; +} + +static void fwnet_remove_peer(struct fwnet_peer *peer) +{ + struct fwnet_partial_datagram *pd, *pd_next; + + spin_lock_irq(&peer->dev->lock); + list_del(&peer->peer_link); + spin_unlock_irq(&peer->dev->lock); + + list_for_each_entry_safe(pd, pd_next, &peer->pd_list, pd_link) + fwnet_pd_delete(pd); + + kfree(peer); +} + +static int fwnet_remove(struct device *_dev) +{ + struct fwnet_peer *peer = dev_get_drvdata(_dev); + struct fwnet_device *dev = peer->dev; + struct net_device *net; + struct fwnet_packet_task *ptask, *pt_next; + + mutex_lock(&fwnet_device_mutex); + + fwnet_remove_peer(peer); + + if (list_empty(&dev->peer_list)) { + net = dev->netdev; + unregister_netdev(net); + + if (dev->local_fifo != FWNET_NO_FIFO_ADDR) + fw_core_remove_address_handler(&dev->handler); + if (dev->broadcast_rcv_context) { + fw_iso_context_stop(dev->broadcast_rcv_context); + fw_iso_buffer_destroy(&dev->broadcast_rcv_buffer, + dev->card); + fw_iso_context_destroy(dev->broadcast_rcv_context); + } + list_for_each_entry_safe(ptask, pt_next, + &dev->packet_list, pt_link) { + dev_kfree_skb_any(ptask->skb); + kmem_cache_free(fwnet_packet_task_cache, ptask); + } + list_for_each_entry_safe(ptask, pt_next, + &dev->broadcasted_list, pt_link) { + dev_kfree_skb_any(ptask->skb); + kmem_cache_free(fwnet_packet_task_cache, ptask); + } + list_for_each_entry_safe(ptask, pt_next, + &dev->sent_list, pt_link) { + dev_kfree_skb_any(ptask->skb); + kmem_cache_free(fwnet_packet_task_cache, ptask); + } + list_del(&dev->dev_link); + + free_netdev(net); + } + + mutex_unlock(&fwnet_device_mutex); + + return 0; +} + +/* + * FIXME abort partially sent fragmented datagrams, + * discard partially received fragmented datagrams + */ +static void fwnet_update(struct fw_unit *unit) +{ + struct fw_device *device = fw_parent_device(unit); + struct fwnet_peer *peer = dev_get_drvdata(&unit->device); + int generation; + + generation = device->generation; + + spin_lock_irq(&peer->dev->lock); + peer->node_id = device->node_id; + peer->generation = generation; + spin_unlock_irq(&peer->dev->lock); +} + +static const struct ieee1394_device_id fwnet_id_table[] = { + { + .match_flags = IEEE1394_MATCH_SPECIFIER_ID | + IEEE1394_MATCH_VERSION, + .specifier_id = IANA_SPECIFIER_ID, + .version = RFC2734_SW_VERSION, + }, + { } +}; + +static struct fw_driver fwnet_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "net", + .bus = &fw_bus_type, + .probe = fwnet_probe, + .remove = fwnet_remove, + }, + .update = fwnet_update, + .id_table = fwnet_id_table, +}; + +static const u32 rfc2374_unit_directory_data[] = { + 0x00040000, /* directory_length */ + 0x1200005e, /* unit_specifier_id: IANA */ + 0x81000003, /* textual descriptor offset */ + 0x13000001, /* unit_sw_version: RFC 2734 */ + 0x81000005, /* textual descriptor offset */ + 0x00030000, /* descriptor_length */ + 0x00000000, /* text */ + 0x00000000, /* minimal ASCII, en */ + 0x49414e41, /* I A N A */ + 0x00030000, /* descriptor_length */ + 0x00000000, /* text */ + 0x00000000, /* minimal ASCII, en */ + 0x49507634, /* I P v 4 */ +}; + +static struct fw_descriptor rfc2374_unit_directory = { + .length = ARRAY_SIZE(rfc2374_unit_directory_data), + .key = (CSR_DIRECTORY | CSR_UNIT) << 24, + .data = rfc2374_unit_directory_data +}; + +static int __init fwnet_init(void) +{ + int err; + + err = fw_core_add_descriptor(&rfc2374_unit_directory); + if (err) + return err; + + fwnet_packet_task_cache = kmem_cache_create("packet_task", + sizeof(struct fwnet_packet_task), 0, 0, NULL); + if (!fwnet_packet_task_cache) { + err = -ENOMEM; + goto out; + } + + err = driver_register(&fwnet_driver.driver); + if (!err) + return 0; + + kmem_cache_destroy(fwnet_packet_task_cache); +out: + fw_core_remove_descriptor(&rfc2374_unit_directory); + + return err; +} +module_init(fwnet_init); + +static void __exit fwnet_cleanup(void) +{ + driver_unregister(&fwnet_driver.driver); + kmem_cache_destroy(fwnet_packet_task_cache); + fw_core_remove_descriptor(&rfc2374_unit_directory); +} +module_exit(fwnet_cleanup); + +MODULE_AUTHOR("Jay Fenlason "); +MODULE_DESCRIPTION("IPv4 over IEEE1394 as per RFC 2734"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(ieee1394, fwnet_id_table); diff --git a/drivers/firewire/fw-ohci.c b/drivers/firewire/ohci.c similarity index 99% rename from drivers/firewire/fw-ohci.c rename to drivers/firewire/ohci.c index 1180d0be0bb4..ecddd11b797a 100644 --- a/drivers/firewire/fw-ohci.c +++ b/drivers/firewire/ohci.c @@ -20,17 +20,25 @@ #include #include +#include #include +#include +#include #include #include #include +#include #include +#include #include #include #include #include #include +#include +#include +#include #include #include @@ -38,8 +46,8 @@ #include #endif -#include "fw-ohci.h" -#include "fw-transaction.h" +#include "core.h" +#include "ohci.h" #define DESCRIPTOR_OUTPUT_MORE 0 #define DESCRIPTOR_OUTPUT_LAST (1 << 12) @@ -178,7 +186,7 @@ struct fw_ohci { int node_id; int generation; int request_generation; /* for timestamping incoming requests */ - u32 bus_seconds; + atomic_t bus_seconds; bool use_dualbuffer; bool old_uninorth; @@ -231,7 +239,6 @@ static inline struct fw_ohci *fw_ohci(struct fw_card *card) #define OHCI1394_MAX_AT_RESP_RETRIES 0x2 #define OHCI1394_MAX_PHYS_RESP_RETRIES 0x8 -#define FW_OHCI_MAJOR 240 #define OHCI1394_REGISTER_SIZE 0x800 #define OHCI_LOOP_COUNT 500 #define OHCI1394_PCI_HCI_Control 0x40 @@ -1434,7 +1441,7 @@ static irqreturn_t irq_handler(int irq, void *data) if (event & OHCI1394_cycle64Seconds) { cycle_time = reg_read(ohci, OHCI1394_IsochronousCycleTimer); if ((cycle_time & 0x80000000) == 0) - ohci->bus_seconds++; + atomic_inc(&ohci->bus_seconds); } return IRQ_HANDLED; @@ -1770,7 +1777,7 @@ static u64 ohci_get_bus_time(struct fw_card *card) u64 bus_time; cycle_time = reg_read(ohci, OHCI1394_IsochronousCycleTimer); - bus_time = ((u64) ohci->bus_seconds << 32) | cycle_time; + bus_time = ((u64)atomic_read(&ohci->bus_seconds) << 32) | cycle_time; return bus_time; } diff --git a/drivers/firewire/fw-ohci.h b/drivers/firewire/ohci.h similarity index 98% rename from drivers/firewire/fw-ohci.h rename to drivers/firewire/ohci.h index a2fbb6240ca7..ba492d85c516 100644 --- a/drivers/firewire/fw-ohci.h +++ b/drivers/firewire/ohci.h @@ -1,5 +1,5 @@ -#ifndef __fw_ohci_h -#define __fw_ohci_h +#ifndef _FIREWIRE_OHCI_H +#define _FIREWIRE_OHCI_H /* OHCI register map */ @@ -154,4 +154,4 @@ #define OHCI1394_phy_tcode 0xe -#endif /* __fw_ohci_h */ +#endif /* _FIREWIRE_OHCI_H */ diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/sbp2.c similarity index 96% rename from drivers/firewire/fw-sbp2.c rename to drivers/firewire/sbp2.c index 2bcf51557c72..24c45635376a 100644 --- a/drivers/firewire/fw-sbp2.c +++ b/drivers/firewire/sbp2.c @@ -30,18 +30,28 @@ #include #include +#include #include #include #include +#include +#include +#include +#include #include +#include +#include #include #include #include #include +#include +#include #include #include -#include #include + +#include #include #include @@ -49,10 +59,6 @@ #include #include -#include "fw-device.h" -#include "fw-topology.h" -#include "fw-transaction.h" - /* * So far only bridges from Oxford Semiconductor are known to support * concurrent logins. Depending on firmware, four or two concurrent logins @@ -174,6 +180,11 @@ struct sbp2_target { int blocked; /* ditto */ }; +static struct fw_device *target_device(struct sbp2_target *tgt) +{ + return fw_parent_device(tgt->unit); +} + /* Impossible login_id, to detect logout attempt before successful login */ #define INVALID_LOGIN_ID 0x10000 @@ -482,7 +493,7 @@ static void complete_transaction(struct fw_card *card, int rcode, static void sbp2_send_orb(struct sbp2_orb *orb, struct sbp2_logical_unit *lu, int node_id, int generation, u64 offset) { - struct fw_device *device = fw_device(lu->tgt->unit->device.parent); + struct fw_device *device = target_device(lu->tgt); unsigned long flags; orb->pointer.high = 0; @@ -504,7 +515,7 @@ static void sbp2_send_orb(struct sbp2_orb *orb, struct sbp2_logical_unit *lu, static int sbp2_cancel_orbs(struct sbp2_logical_unit *lu) { - struct fw_device *device = fw_device(lu->tgt->unit->device.parent); + struct fw_device *device = target_device(lu->tgt); struct sbp2_orb *orb, *next; struct list_head list; unsigned long flags; @@ -542,7 +553,7 @@ static int sbp2_send_management_orb(struct sbp2_logical_unit *lu, int node_id, int generation, int function, int lun_or_login_id, void *response) { - struct fw_device *device = fw_device(lu->tgt->unit->device.parent); + struct fw_device *device = target_device(lu->tgt); struct sbp2_management_orb *orb; unsigned int timeout; int retval = -ENOMEM; @@ -638,7 +649,7 @@ static int sbp2_send_management_orb(struct sbp2_logical_unit *lu, int node_id, static void sbp2_agent_reset(struct sbp2_logical_unit *lu) { - struct fw_device *device = fw_device(lu->tgt->unit->device.parent); + struct fw_device *device = target_device(lu->tgt); __be32 d = 0; fw_run_transaction(device->card, TCODE_WRITE_QUADLET_REQUEST, @@ -655,7 +666,7 @@ static void complete_agent_reset_write_no_wait(struct fw_card *card, static void sbp2_agent_reset_no_wait(struct sbp2_logical_unit *lu) { - struct fw_device *device = fw_device(lu->tgt->unit->device.parent); + struct fw_device *device = target_device(lu->tgt); struct fw_transaction *t; static __be32 d; @@ -694,7 +705,7 @@ static inline void sbp2_allow_block(struct sbp2_logical_unit *lu) static void sbp2_conditionally_block(struct sbp2_logical_unit *lu) { struct sbp2_target *tgt = lu->tgt; - struct fw_card *card = fw_device(tgt->unit->device.parent)->card; + struct fw_card *card = target_device(tgt)->card; struct Scsi_Host *shost = container_of((void *)tgt, struct Scsi_Host, hostdata[0]); unsigned long flags; @@ -718,7 +729,7 @@ static void sbp2_conditionally_block(struct sbp2_logical_unit *lu) static void sbp2_conditionally_unblock(struct sbp2_logical_unit *lu) { struct sbp2_target *tgt = lu->tgt; - struct fw_card *card = fw_device(tgt->unit->device.parent)->card; + struct fw_card *card = target_device(tgt)->card; struct Scsi_Host *shost = container_of((void *)tgt, struct Scsi_Host, hostdata[0]); unsigned long flags; @@ -743,7 +754,7 @@ static void sbp2_conditionally_unblock(struct sbp2_logical_unit *lu) */ static void sbp2_unblock(struct sbp2_target *tgt) { - struct fw_card *card = fw_device(tgt->unit->device.parent)->card; + struct fw_card *card = target_device(tgt)->card; struct Scsi_Host *shost = container_of((void *)tgt, struct Scsi_Host, hostdata[0]); unsigned long flags; @@ -773,7 +784,7 @@ static void sbp2_release_target(struct kref *kref) struct Scsi_Host *shost = container_of((void *)tgt, struct Scsi_Host, hostdata[0]); struct scsi_device *sdev; - struct fw_device *device = fw_device(tgt->unit->device.parent); + struct fw_device *device = target_device(tgt); /* prevent deadlocks */ sbp2_unblock(tgt); @@ -846,7 +857,7 @@ static void sbp2_queue_work(struct sbp2_logical_unit *lu, unsigned long delay) */ static void sbp2_set_busy_timeout(struct sbp2_logical_unit *lu) { - struct fw_device *device = fw_device(lu->tgt->unit->device.parent); + struct fw_device *device = target_device(lu->tgt); __be32 d = cpu_to_be32(SBP2_CYCLE_LIMIT | SBP2_RETRY_LIMIT); fw_run_transaction(device->card, TCODE_WRITE_QUADLET_REQUEST, @@ -862,7 +873,7 @@ static void sbp2_login(struct work_struct *work) struct sbp2_logical_unit *lu = container_of(work, struct sbp2_logical_unit, work.work); struct sbp2_target *tgt = lu->tgt; - struct fw_device *device = fw_device(tgt->unit->device.parent); + struct fw_device *device = target_device(tgt); struct Scsi_Host *shost; struct scsi_device *sdev; struct sbp2_login_response response; @@ -1110,7 +1121,7 @@ static struct scsi_host_template scsi_driver_template; static int sbp2_probe(struct device *dev) { struct fw_unit *unit = fw_unit(dev); - struct fw_device *device = fw_device(unit->device.parent); + struct fw_device *device = fw_parent_device(unit); struct sbp2_target *tgt; struct sbp2_logical_unit *lu; struct Scsi_Host *shost; @@ -1125,7 +1136,7 @@ static int sbp2_probe(struct device *dev) return -ENOMEM; tgt = (struct sbp2_target *)shost->hostdata; - unit->device.driver_data = tgt; + dev_set_drvdata(&unit->device, tgt); tgt->unit = unit; kref_init(&tgt->kref); INIT_LIST_HEAD(&tgt->lu_list); @@ -1180,7 +1191,7 @@ static int sbp2_probe(struct device *dev) static int sbp2_remove(struct device *dev) { struct fw_unit *unit = fw_unit(dev); - struct sbp2_target *tgt = unit->device.driver_data; + struct sbp2_target *tgt = dev_get_drvdata(&unit->device); sbp2_target_put(tgt); return 0; @@ -1191,7 +1202,7 @@ static void sbp2_reconnect(struct work_struct *work) struct sbp2_logical_unit *lu = container_of(work, struct sbp2_logical_unit, work.work); struct sbp2_target *tgt = lu->tgt; - struct fw_device *device = fw_device(tgt->unit->device.parent); + struct fw_device *device = target_device(tgt); int generation, node_id, local_node_id; if (fw_device_is_shutdown(device)) @@ -1240,10 +1251,10 @@ static void sbp2_reconnect(struct work_struct *work) static void sbp2_update(struct fw_unit *unit) { - struct sbp2_target *tgt = unit->device.driver_data; + struct sbp2_target *tgt = dev_get_drvdata(&unit->device); struct sbp2_logical_unit *lu; - fw_device_enable_phys_dma(fw_device(unit->device.parent)); + fw_device_enable_phys_dma(fw_parent_device(unit)); /* * Fw-core serializes sbp2_update() against sbp2_remove(). @@ -1259,9 +1270,10 @@ static void sbp2_update(struct fw_unit *unit) #define SBP2_UNIT_SPEC_ID_ENTRY 0x0000609e #define SBP2_SW_VERSION_ENTRY 0x00010483 -static const struct fw_device_id sbp2_id_table[] = { +static const struct ieee1394_device_id sbp2_id_table[] = { { - .match_flags = FW_MATCH_SPECIFIER_ID | FW_MATCH_VERSION, + .match_flags = IEEE1394_MATCH_SPECIFIER_ID | + IEEE1394_MATCH_VERSION, .specifier_id = SBP2_UNIT_SPEC_ID_ENTRY, .version = SBP2_SW_VERSION_ENTRY, }, @@ -1335,7 +1347,7 @@ static void complete_command_orb(struct sbp2_orb *base_orb, { struct sbp2_command_orb *orb = container_of(base_orb, struct sbp2_command_orb, base); - struct fw_device *device = fw_device(orb->lu->tgt->unit->device.parent); + struct fw_device *device = target_device(orb->lu->tgt); int result; if (status != NULL) { @@ -1442,7 +1454,7 @@ static int sbp2_map_scatterlist(struct sbp2_command_orb *orb, static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done) { struct sbp2_logical_unit *lu = cmd->device->hostdata; - struct fw_device *device = fw_device(lu->tgt->unit->device.parent); + struct fw_device *device = target_device(lu->tgt); struct sbp2_command_orb *orb; int generation, retval = SCSI_MLQUEUE_HOST_BUSY; diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index 5f1b5400d96a..24c84ae81527 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c @@ -596,6 +596,7 @@ int dmi_get_year(int field) return year; } +EXPORT_SYMBOL(dmi_get_year); /** * dmi_walk - Walk the DMI table and get called back for every record diff --git a/drivers/firmware/memmap.c b/drivers/firmware/memmap.c index 05aa2d406ac6..d5ea8a68d338 100644 --- a/drivers/firmware/memmap.c +++ b/drivers/firmware/memmap.c @@ -31,8 +31,12 @@ * information is necessary as for the resource tree. */ struct firmware_map_entry { - resource_size_t start; /* start of the memory range */ - resource_size_t end; /* end of the memory range (incl.) */ + /* + * start and end must be u64 rather than resource_size_t, because e820 + * resources can lie at addresses above 4G. + */ + u64 start; /* start of the memory range */ + u64 end; /* end of the memory range (incl.) */ const char *type; /* type of the memory range */ struct list_head list; /* entry for the linked list */ struct kobject kobj; /* kobject for each entry */ @@ -101,7 +105,7 @@ static LIST_HEAD(map_entries); * Common implementation of firmware_map_add() and firmware_map_add_early() * which expects a pre-allocated struct firmware_map_entry. **/ -static int firmware_map_add_entry(resource_size_t start, resource_size_t end, +static int firmware_map_add_entry(u64 start, u64 end, const char *type, struct firmware_map_entry *entry) { @@ -132,8 +136,7 @@ static int firmware_map_add_entry(resource_size_t start, resource_size_t end, * * Returns 0 on success, or -ENOMEM if no memory could be allocated. **/ -int firmware_map_add(resource_size_t start, resource_size_t end, - const char *type) +int firmware_map_add(u64 start, u64 end, const char *type) { struct firmware_map_entry *entry; @@ -157,8 +160,7 @@ int firmware_map_add(resource_size_t start, resource_size_t end, * * Returns 0 on success, or -ENOMEM if no memory could be allocated. **/ -int __init firmware_map_add_early(resource_size_t start, resource_size_t end, - const char *type) +int __init firmware_map_add_early(u64 start, u64 end, const char *type) { struct firmware_map_entry *entry; diff --git a/drivers/firmware/pcdp.c b/drivers/firmware/pcdp.c index 58e9f8e457f8..51e0e2d8fac6 100644 --- a/drivers/firmware/pcdp.c +++ b/drivers/firmware/pcdp.c @@ -28,10 +28,10 @@ setup_serial_console(struct pcdp_uart *uart) char parity; mmio = (uart->addr.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY); - p += sprintf(p, "uart8250,%s,0x%lx", + p += sprintf(p, "uart8250,%s,0x%llx", mmio ? "mmio" : "io", uart->addr.address); if (uart->baud) { - p += sprintf(p, ",%lu", uart->baud); + p += sprintf(p, ",%llu", uart->baud); if (uart->bits) { switch (uart->parity) { case 0x2: parity = 'e'; break; diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index edb02530e461..3582c39f9725 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -67,9 +67,15 @@ config GPIO_SYSFS comment "Memory mapped GPIO expanders:" +config GPIO_PL061 + bool "PrimeCell PL061 GPIO support" + depends on ARM_AMBA + help + Say yes here to support the PrimeCell PL061 GPIO device + config GPIO_XILINX bool "Xilinx GPIO support" - depends on PPC_OF + depends on PPC_OF || MICROBLAZE help Say yes here to support the Xilinx FPGA GPIO device diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 49ac64e515e6..ef90203e8f3c 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_GPIO_MAX732X) += max732x.o obj-$(CONFIG_GPIO_MCP23S08) += mcp23s08.o obj-$(CONFIG_GPIO_PCA953X) += pca953x.o obj-$(CONFIG_GPIO_PCF857X) += pcf857x.o +obj-$(CONFIG_GPIO_PL061) += pl061.o obj-$(CONFIG_GPIO_TWL4030) += twl4030-gpio.o obj-$(CONFIG_GPIO_XILINX) += xilinx_gpio.o obj-$(CONFIG_GPIO_BT8XX) += bt8xxgpio.o diff --git a/drivers/gpio/max7301.c b/drivers/gpio/max7301.c index 3e7f4e06386e..7b82eaae2621 100644 --- a/drivers/gpio/max7301.c +++ b/drivers/gpio/max7301.c @@ -287,7 +287,7 @@ exit_destroy: return ret; } -static int max7301_remove(struct spi_device *spi) +static int __devexit max7301_remove(struct spi_device *spi) { struct max7301 *ts; int ret; diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c index 8dc0164bd51e..cdb6574d25a6 100644 --- a/drivers/gpio/pca953x.c +++ b/drivers/gpio/pca953x.c @@ -15,6 +15,10 @@ #include #include #include +#ifdef CONFIG_OF_GPIO +#include +#include +#endif #include @@ -32,6 +36,7 @@ static const struct i2c_device_id pca953x_id[] = { { "pca9539", 16, }, { "pca9554", 8, }, { "pca9555", 16, }, + { "pca9556", 8, }, { "pca9557", 8, }, { "max7310", 8, }, @@ -49,7 +54,9 @@ struct pca953x_chip { uint16_t reg_direction; struct i2c_client *client; + struct pca953x_platform_data *dyn_pdata; struct gpio_chip gpio_chip; + char **names; }; static int pca953x_write_reg(struct pca953x_chip *chip, int reg, uint16_t val) @@ -192,8 +199,57 @@ static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios) gc->label = chip->client->name; gc->dev = &chip->client->dev; gc->owner = THIS_MODULE; + gc->names = chip->names; } +/* + * Handlers for alternative sources of platform_data + */ +#ifdef CONFIG_OF_GPIO +/* + * Translate OpenFirmware node properties into platform_data + */ +static struct pca953x_platform_data * +pca953x_get_alt_pdata(struct i2c_client *client) +{ + struct pca953x_platform_data *pdata; + struct device_node *node; + const uint16_t *val; + + node = dev_archdata_get_node(&client->dev.archdata); + if (node == NULL) + return NULL; + + pdata = kzalloc(sizeof(struct pca953x_platform_data), GFP_KERNEL); + if (pdata == NULL) { + dev_err(&client->dev, "Unable to allocate platform_data\n"); + return NULL; + } + + pdata->gpio_base = -1; + val = of_get_property(node, "linux,gpio-base", NULL); + if (val) { + if (*val < 0) + dev_warn(&client->dev, + "invalid gpio-base in device tree\n"); + else + pdata->gpio_base = *val; + } + + val = of_get_property(node, "polarity", NULL); + if (val) + pdata->invert = *val; + + return pdata; +} +#else +static struct pca953x_platform_data * +pca953x_get_alt_pdata(struct i2c_client *client) +{ + return NULL; +} +#endif + static int __devinit pca953x_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -201,20 +257,32 @@ static int __devinit pca953x_probe(struct i2c_client *client, struct pca953x_chip *chip; int ret; - pdata = client->dev.platform_data; - if (pdata == NULL) { - dev_dbg(&client->dev, "no platform data\n"); - return -EINVAL; - } - chip = kzalloc(sizeof(struct pca953x_chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; + pdata = client->dev.platform_data; + if (pdata == NULL) { + pdata = pca953x_get_alt_pdata(client); + /* + * Unlike normal platform_data, this is allocated + * dynamically and must be freed in the driver + */ + chip->dyn_pdata = pdata; + } + + if (pdata == NULL) { + dev_dbg(&client->dev, "no platform data\n"); + ret = -EINVAL; + goto out_failed; + } + chip->client = client; chip->gpio_start = pdata->gpio_base; + chip->names = pdata->names; + /* initialize cached registers from their original values. * we can't share this chip with another i2c master. */ @@ -249,6 +317,7 @@ static int __devinit pca953x_probe(struct i2c_client *client, return 0; out_failed: + kfree(chip->dyn_pdata); kfree(chip); return ret; } @@ -276,6 +345,7 @@ static int pca953x_remove(struct i2c_client *client) return ret; } + kfree(chip->dyn_pdata); kfree(chip); return 0; } diff --git a/drivers/gpio/pl061.c b/drivers/gpio/pl061.c new file mode 100644 index 000000000000..aa8e7cb020d9 --- /dev/null +++ b/drivers/gpio/pl061.c @@ -0,0 +1,341 @@ +/* + * linux/drivers/gpio/pl061.c + * + * Copyright (C) 2008, 2009 Provigent Ltd. + * + * 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. + * + * Driver for the ARM PrimeCell(tm) General Purpose Input/Output (PL061) + * + * Data sheet: ARM DDI 0190B, September 2000 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define GPIODIR 0x400 +#define GPIOIS 0x404 +#define GPIOIBE 0x408 +#define GPIOIEV 0x40C +#define GPIOIE 0x410 +#define GPIORIS 0x414 +#define GPIOMIS 0x418 +#define GPIOIC 0x41C + +#define PL061_GPIO_NR 8 + +struct pl061_gpio { + /* We use a list of pl061_gpio structs for each trigger IRQ in the main + * interrupts controller of the system. We need this to support systems + * in which more that one PL061s are connected to the same IRQ. The ISR + * interates through this list to find the source of the interrupt. + */ + struct list_head list; + + /* Each of the two spinlocks protects a different set of hardware + * regiters and data structurs. This decouples the code of the IRQ from + * the GPIO code. This also makes the case of a GPIO routine call from + * the IRQ code simpler. + */ + spinlock_t lock; /* GPIO registers */ + spinlock_t irq_lock; /* IRQ registers */ + + void __iomem *base; + unsigned irq_base; + struct gpio_chip gc; +}; + +static int pl061_direction_input(struct gpio_chip *gc, unsigned offset) +{ + struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc); + unsigned long flags; + unsigned char gpiodir; + + if (offset >= gc->ngpio) + return -EINVAL; + + spin_lock_irqsave(&chip->lock, flags); + gpiodir = readb(chip->base + GPIODIR); + gpiodir &= ~(1 << offset); + writeb(gpiodir, chip->base + GPIODIR); + spin_unlock_irqrestore(&chip->lock, flags); + + return 0; +} + +static int pl061_direction_output(struct gpio_chip *gc, unsigned offset, + int value) +{ + struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc); + unsigned long flags; + unsigned char gpiodir; + + if (offset >= gc->ngpio) + return -EINVAL; + + spin_lock_irqsave(&chip->lock, flags); + writeb(!!value << offset, chip->base + (1 << (offset + 2))); + gpiodir = readb(chip->base + GPIODIR); + gpiodir |= 1 << offset; + writeb(gpiodir, chip->base + GPIODIR); + spin_unlock_irqrestore(&chip->lock, flags); + + return 0; +} + +static int pl061_get_value(struct gpio_chip *gc, unsigned offset) +{ + struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc); + + return !!readb(chip->base + (1 << (offset + 2))); +} + +static void pl061_set_value(struct gpio_chip *gc, unsigned offset, int value) +{ + struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc); + + writeb(!!value << offset, chip->base + (1 << (offset + 2))); +} + +/* + * PL061 GPIO IRQ + */ +static void pl061_irq_disable(unsigned irq) +{ + struct pl061_gpio *chip = get_irq_chip_data(irq); + int offset = irq - chip->irq_base; + unsigned long flags; + u8 gpioie; + + spin_lock_irqsave(&chip->irq_lock, flags); + gpioie = readb(chip->base + GPIOIE); + gpioie &= ~(1 << offset); + writeb(gpioie, chip->base + GPIOIE); + spin_unlock_irqrestore(&chip->irq_lock, flags); +} + +static void pl061_irq_enable(unsigned irq) +{ + struct pl061_gpio *chip = get_irq_chip_data(irq); + int offset = irq - chip->irq_base; + unsigned long flags; + u8 gpioie; + + spin_lock_irqsave(&chip->irq_lock, flags); + gpioie = readb(chip->base + GPIOIE); + gpioie |= 1 << offset; + writeb(gpioie, chip->base + GPIOIE); + spin_unlock_irqrestore(&chip->irq_lock, flags); +} + +static int pl061_irq_type(unsigned irq, unsigned trigger) +{ + struct pl061_gpio *chip = get_irq_chip_data(irq); + int offset = irq - chip->irq_base; + unsigned long flags; + u8 gpiois, gpioibe, gpioiev; + + if (offset < 0 || offset > PL061_GPIO_NR) + return -EINVAL; + + spin_lock_irqsave(&chip->irq_lock, flags); + + gpioiev = readb(chip->base + GPIOIEV); + + gpiois = readb(chip->base + GPIOIS); + if (trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) { + gpiois |= 1 << offset; + if (trigger & IRQ_TYPE_LEVEL_HIGH) + gpioiev |= 1 << offset; + else + gpioiev &= ~(1 << offset); + } else + gpiois &= ~(1 << offset); + writeb(gpiois, chip->base + GPIOIS); + + gpioibe = readb(chip->base + GPIOIBE); + if ((trigger & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) + gpioibe |= 1 << offset; + else { + gpioibe &= ~(1 << offset); + if (trigger & IRQ_TYPE_EDGE_RISING) + gpioiev |= 1 << offset; + else + gpioiev &= ~(1 << offset); + } + writeb(gpioibe, chip->base + GPIOIBE); + + writeb(gpioiev, chip->base + GPIOIEV); + + spin_unlock_irqrestore(&chip->irq_lock, flags); + + return 0; +} + +static struct irq_chip pl061_irqchip = { + .name = "GPIO", + .enable = pl061_irq_enable, + .disable = pl061_irq_disable, + .set_type = pl061_irq_type, +}; + +static void pl061_irq_handler(unsigned irq, struct irq_desc *desc) +{ + struct list_head *chip_list = get_irq_chip_data(irq); + struct list_head *ptr; + struct pl061_gpio *chip; + + desc->chip->ack(irq); + list_for_each(ptr, chip_list) { + unsigned long pending; + int gpio; + + chip = list_entry(ptr, struct pl061_gpio, list); + pending = readb(chip->base + GPIOMIS); + writeb(pending, chip->base + GPIOIC); + + if (pending == 0) + continue; + + for_each_bit(gpio, &pending, PL061_GPIO_NR) + generic_handle_irq(gpio_to_irq(gpio)); + } + desc->chip->unmask(irq); +} + +static int __init pl061_probe(struct amba_device *dev, struct amba_id *id) +{ + struct pl061_platform_data *pdata; + struct pl061_gpio *chip; + struct list_head *chip_list; + int ret, irq, i; + static unsigned long init_irq[BITS_TO_LONGS(NR_IRQS)]; + + pdata = dev->dev.platform_data; + if (pdata == NULL) + return -ENODEV; + + chip = kzalloc(sizeof(*chip), GFP_KERNEL); + if (chip == NULL) + return -ENOMEM; + + if (!request_mem_region(dev->res.start, + resource_size(&dev->res), "pl061")) { + ret = -EBUSY; + goto free_mem; + } + + chip->base = ioremap(dev->res.start, resource_size(&dev->res)); + if (chip->base == NULL) { + ret = -ENOMEM; + goto release_region; + } + + spin_lock_init(&chip->lock); + spin_lock_init(&chip->irq_lock); + INIT_LIST_HEAD(&chip->list); + + chip->gc.direction_input = pl061_direction_input; + chip->gc.direction_output = pl061_direction_output; + chip->gc.get = pl061_get_value; + chip->gc.set = pl061_set_value; + chip->gc.base = pdata->gpio_base; + chip->gc.ngpio = PL061_GPIO_NR; + chip->gc.label = dev_name(&dev->dev); + chip->gc.dev = &dev->dev; + chip->gc.owner = THIS_MODULE; + + chip->irq_base = pdata->irq_base; + + ret = gpiochip_add(&chip->gc); + if (ret) + goto iounmap; + + /* + * irq_chip support + */ + + if (chip->irq_base == (unsigned) -1) + return 0; + + writeb(0, chip->base + GPIOIE); /* disable irqs */ + irq = dev->irq[0]; + if (irq < 0) { + ret = -ENODEV; + goto iounmap; + } + set_irq_chained_handler(irq, pl061_irq_handler); + if (!test_and_set_bit(irq, init_irq)) { /* list initialized? */ + chip_list = kmalloc(sizeof(*chip_list), GFP_KERNEL); + if (chip_list == NULL) { + ret = -ENOMEM; + goto iounmap; + } + INIT_LIST_HEAD(chip_list); + set_irq_chip_data(irq, chip_list); + } else + chip_list = get_irq_chip_data(irq); + list_add(&chip->list, chip_list); + + for (i = 0; i < PL061_GPIO_NR; i++) { + if (pdata->directions & (1 << i)) + pl061_direction_output(&chip->gc, i, + pdata->values & (1 << i)); + else + pl061_direction_input(&chip->gc, i); + + set_irq_chip(i+chip->irq_base, &pl061_irqchip); + set_irq_handler(i+chip->irq_base, handle_simple_irq); + set_irq_flags(i+chip->irq_base, IRQF_VALID); + set_irq_chip_data(i+chip->irq_base, chip); + } + + return 0; + +iounmap: + iounmap(chip->base); +release_region: + release_mem_region(dev->res.start, resource_size(&dev->res)); +free_mem: + kfree(chip); + + return ret; +} + +static struct amba_id pl061_ids[] __initdata = { + { + .id = 0x00041061, + .mask = 0x000fffff, + }, + { 0, 0 }, +}; + +static struct amba_driver pl061_gpio_driver = { + .drv = { + .name = "pl061_gpio", + }, + .id_table = pl061_ids, + .probe = pl061_probe, +}; + +static int __init pl061_gpio_init(void) +{ + return amba_driver_register(&pl061_gpio_driver); +} +subsys_initcall(pl061_gpio_init); + +MODULE_AUTHOR("Baruch Siach "); +MODULE_DESCRIPTION("PL061 GPIO driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index f5d46e7199d4..c961fe415aef 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -18,6 +18,14 @@ menuconfig DRM details. You should also select and configure AGP (/dev/agpgart) support. +config DRM_TTM + tristate + depends on DRM + help + GPU memory management subsystem for devices with multiple + GPU memory types. Will be enabled automatically if a device driver + uses it. + config DRM_TDFX tristate "3dfx Banshee/Voodoo3+" depends on DRM && PCI @@ -36,6 +44,11 @@ config DRM_R128 config DRM_RADEON tristate "ATI Radeon" depends on DRM && PCI + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB + select FRAMEBUFFER_CONSOLE if !EMBEDDED help Choose this option if you have an ATI Radeon graphics card. There are both PCI and AGP versions. You don't need to choose this to diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 4ec5061fa584..4e89ab08b7b8 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -26,4 +26,4 @@ obj-$(CONFIG_DRM_I915) += i915/ obj-$(CONFIG_DRM_SIS) += sis/ obj-$(CONFIG_DRM_SAVAGE)+= savage/ obj-$(CONFIG_DRM_VIA) +=via/ - +obj-$(CONFIG_DRM_TTM) += ttm/ diff --git a/drivers/gpu/drm/drm_agpsupport.c b/drivers/gpu/drm/drm_agpsupport.c index 14796594e5d9..d68888fe3df9 100644 --- a/drivers/gpu/drm/drm_agpsupport.c +++ b/drivers/gpu/drm/drm_agpsupport.c @@ -203,7 +203,7 @@ int drm_agp_alloc(struct drm_device *dev, struct drm_agp_buffer *request) if (!dev->agp || !dev->agp->acquired) return -EINVAL; - if (!(entry = drm_alloc(sizeof(*entry), DRM_MEM_AGPLISTS))) + if (!(entry = kmalloc(sizeof(*entry), GFP_KERNEL))) return -ENOMEM; memset(entry, 0, sizeof(*entry)); @@ -211,7 +211,7 @@ int drm_agp_alloc(struct drm_device *dev, struct drm_agp_buffer *request) pages = (request->size + PAGE_SIZE - 1) / PAGE_SIZE; type = (u32) request->type; if (!(memory = drm_alloc_agp(dev, pages, type))) { - drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS); + kfree(entry); return -ENOMEM; } @@ -369,7 +369,7 @@ int drm_agp_free(struct drm_device *dev, struct drm_agp_buffer *request) list_del(&entry->head); drm_free_agp(entry->memory, entry->pages); - drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS); + kfree(entry); return 0; } EXPORT_SYMBOL(drm_agp_free); @@ -397,13 +397,13 @@ struct drm_agp_head *drm_agp_init(struct drm_device *dev) { struct drm_agp_head *head = NULL; - if (!(head = drm_alloc(sizeof(*head), DRM_MEM_AGPLISTS))) + if (!(head = kmalloc(sizeof(*head), GFP_KERNEL))) return NULL; memset((void *)head, 0, sizeof(*head)); head->bridge = agp_find_bridge(dev->pdev); if (!head->bridge) { if (!(head->bridge = agp_backend_acquire(dev->pdev))) { - drm_free(head, sizeof(*head), DRM_MEM_AGPLISTS); + kfree(head); return NULL; } agp_copy_info(head->bridge, &head->agp_info); @@ -412,7 +412,7 @@ struct drm_agp_head *drm_agp_init(struct drm_device *dev) agp_copy_info(head->bridge, &head->agp_info); } if (head->agp_info.chipset == NOT_SUPPORTED) { - drm_free(head, sizeof(*head), DRM_MEM_AGPLISTS); + kfree(head); return NULL; } INIT_LIST_HEAD(&head->memory); @@ -482,7 +482,7 @@ drm_agp_bind_pages(struct drm_device *dev, } for (i = 0; i < num_pages; i++) - mem->memory[i] = phys_to_gart(page_to_phys(pages[i])); + mem->pages[i] = pages[i]; mem->page_count = num_pages; mem->is_flushed = true; diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c index ca7a9ef5007b..932b5aa96a67 100644 --- a/drivers/gpu/drm/drm_auth.c +++ b/drivers/gpu/drm/drm_auth.c @@ -79,7 +79,7 @@ static int drm_add_magic(struct drm_master *master, struct drm_file *priv, struct drm_device *dev = master->minor->dev; DRM_DEBUG("%d\n", magic); - entry = drm_alloc(sizeof(*entry), DRM_MEM_MAGIC); + entry = kmalloc(sizeof(*entry), GFP_KERNEL); if (!entry) return -ENOMEM; memset(entry, 0, sizeof(*entry)); @@ -120,7 +120,7 @@ static int drm_remove_magic(struct drm_master *master, drm_magic_t magic) list_del(&pt->head); mutex_unlock(&dev->struct_mutex); - drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC); + kfree(pt); return 0; } diff --git a/drivers/gpu/drm/drm_bufs.c b/drivers/gpu/drm/drm_bufs.c index 0411d912d82a..6246e3f3dad7 100644 --- a/drivers/gpu/drm/drm_bufs.c +++ b/drivers/gpu/drm/drm_bufs.c @@ -151,7 +151,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset, unsigned long user_token; int ret; - map = drm_alloc(sizeof(*map), DRM_MEM_MAPS); + map = kmalloc(sizeof(*map), GFP_KERNEL); if (!map) return -ENOMEM; @@ -165,7 +165,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset, * when processes fork. */ if ((map->flags & _DRM_REMOVABLE) && map->type != _DRM_SHM) { - drm_free(map, sizeof(*map), DRM_MEM_MAPS); + kfree(map); return -EINVAL; } DRM_DEBUG("offset = 0x%08llx, size = 0x%08lx, type = %d\n", @@ -179,7 +179,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset, map->size = PAGE_ALIGN(map->size); if ((map->offset & (~(resource_size_t)PAGE_MASK)) || (map->size & (~PAGE_MASK))) { - drm_free(map, sizeof(*map), DRM_MEM_MAPS); + kfree(map); return -EINVAL; } map->mtrr = -1; @@ -191,7 +191,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset, #if !defined(__sparc__) && !defined(__alpha__) && !defined(__ia64__) && !defined(__powerpc64__) && !defined(__x86_64__) if (map->offset + (map->size-1) < map->offset || map->offset < virt_to_phys(high_memory)) { - drm_free(map, sizeof(*map), DRM_MEM_MAPS); + kfree(map); return -EINVAL; } #endif @@ -212,7 +212,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset, list->map->size = map->size; } - drm_free(map, sizeof(*map), DRM_MEM_MAPS); + kfree(map); *maplist = list; return 0; } @@ -227,7 +227,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset, if (map->type == _DRM_REGISTERS) { map->handle = ioremap(map->offset, map->size); if (!map->handle) { - drm_free(map, sizeof(*map), DRM_MEM_MAPS); + kfree(map); return -ENOMEM; } } @@ -243,7 +243,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset, list->map->size = map->size; } - drm_free(map, sizeof(*map), DRM_MEM_MAPS); + kfree(map); *maplist = list; return 0; } @@ -251,7 +251,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset, DRM_DEBUG("%lu %d %p\n", map->size, drm_order(map->size), map->handle); if (!map->handle) { - drm_free(map, sizeof(*map), DRM_MEM_MAPS); + kfree(map); return -ENOMEM; } map->offset = (unsigned long)map->handle; @@ -259,7 +259,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset, /* Prevent a 2nd X Server from creating a 2nd lock */ if (dev->primary->master->lock.hw_lock != NULL) { vfree(map->handle); - drm_free(map, sizeof(*map), DRM_MEM_MAPS); + kfree(map); return -EBUSY; } dev->sigdata.lock = dev->primary->master->lock.hw_lock = map->handle; /* Pointer to lock */ @@ -270,7 +270,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset, int valid = 0; if (!drm_core_has_AGP(dev)) { - drm_free(map, sizeof(*map), DRM_MEM_MAPS); + kfree(map); return -EINVAL; } #ifdef __alpha__ @@ -303,7 +303,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset, } } if (!list_empty(&dev->agp->memory) && !valid) { - drm_free(map, sizeof(*map), DRM_MEM_MAPS); + kfree(map); return -EPERM; } DRM_DEBUG("AGP offset = 0x%08llx, size = 0x%08lx\n", @@ -316,7 +316,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset, } case _DRM_SCATTER_GATHER: if (!dev->sg) { - drm_free(map, sizeof(*map), DRM_MEM_MAPS); + kfree(map); return -EINVAL; } map->offset += (unsigned long)dev->sg->virtual; @@ -328,7 +328,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset, * need to point to a 64bit variable first. */ dmah = drm_pci_alloc(dev, map->size, map->size, 0xffffffffUL); if (!dmah) { - drm_free(map, sizeof(*map), DRM_MEM_MAPS); + kfree(map); return -ENOMEM; } map->handle = dmah->vaddr; @@ -336,15 +336,15 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset, kfree(dmah); break; default: - drm_free(map, sizeof(*map), DRM_MEM_MAPS); + kfree(map); return -EINVAL; } - list = drm_alloc(sizeof(*list), DRM_MEM_MAPS); + list = kmalloc(sizeof(*list), GFP_KERNEL); if (!list) { if (map->type == _DRM_REGISTERS) iounmap(map->handle); - drm_free(map, sizeof(*map), DRM_MEM_MAPS); + kfree(map); return -EINVAL; } memset(list, 0, sizeof(*list)); @@ -362,8 +362,8 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset, if (ret) { if (map->type == _DRM_REGISTERS) iounmap(map->handle); - drm_free(map, sizeof(*map), DRM_MEM_MAPS); - drm_free(list, sizeof(*list), DRM_MEM_MAPS); + kfree(map); + kfree(list); mutex_unlock(&dev->struct_mutex); return ret; } @@ -371,7 +371,8 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset, list->user_token = list->hash.key << PAGE_SHIFT; mutex_unlock(&dev->struct_mutex); - list->master = dev->primary->master; + if (!(map->flags & _DRM_DRIVER)) + list->master = dev->primary->master; *maplist = list; return 0; } @@ -447,7 +448,7 @@ int drm_rmmap_locked(struct drm_device *dev, struct drm_local_map *map) list_del(&r_list->head); drm_ht_remove_key(&dev->map_hash, r_list->user_token >> PAGE_SHIFT); - drm_free(r_list, sizeof(*r_list), DRM_MEM_MAPS); + kfree(r_list); found = 1; break; } @@ -490,7 +491,7 @@ int drm_rmmap_locked(struct drm_device *dev, struct drm_local_map *map) DRM_ERROR("tried to rmmap GEM object\n"); break; } - drm_free(map, sizeof(*map), DRM_MEM_MAPS); + kfree(map); return 0; } @@ -581,24 +582,16 @@ static void drm_cleanup_buf_error(struct drm_device * dev, drm_pci_free(dev, entry->seglist[i]); } } - drm_free(entry->seglist, - entry->seg_count * - sizeof(*entry->seglist), DRM_MEM_SEGS); + kfree(entry->seglist); entry->seg_count = 0; } if (entry->buf_count) { for (i = 0; i < entry->buf_count; i++) { - if (entry->buflist[i].dev_private) { - drm_free(entry->buflist[i].dev_private, - entry->buflist[i].dev_priv_size, - DRM_MEM_BUFS); - } + kfree(entry->buflist[i].dev_private); } - drm_free(entry->buflist, - entry->buf_count * - sizeof(*entry->buflist), DRM_MEM_BUFS); + kfree(entry->buflist); entry->buf_count = 0; } @@ -697,8 +690,7 @@ int drm_addbufs_agp(struct drm_device * dev, struct drm_buf_desc * request) return -EINVAL; } - entry->buflist = drm_alloc(count * sizeof(*entry->buflist), - DRM_MEM_BUFS); + entry->buflist = kmalloc(count * sizeof(*entry->buflist), GFP_KERNEL); if (!entry->buflist) { mutex_unlock(&dev->struct_mutex); atomic_dec(&dev->buf_alloc); @@ -728,7 +720,7 @@ int drm_addbufs_agp(struct drm_device * dev, struct drm_buf_desc * request) buf->file_priv = NULL; buf->dev_priv_size = dev->driver->dev_priv_size; - buf->dev_private = drm_alloc(buf->dev_priv_size, DRM_MEM_BUFS); + buf->dev_private = kmalloc(buf->dev_priv_size, GFP_KERNEL); if (!buf->dev_private) { /* Set count correctly so we free the proper amount. */ entry->buf_count = count; @@ -748,10 +740,9 @@ int drm_addbufs_agp(struct drm_device * dev, struct drm_buf_desc * request) DRM_DEBUG("byte_count: %d\n", byte_count); - temp_buflist = drm_realloc(dma->buflist, - dma->buf_count * sizeof(*dma->buflist), - (dma->buf_count + entry->buf_count) - * sizeof(*dma->buflist), DRM_MEM_BUFS); + temp_buflist = krealloc(dma->buflist, + (dma->buf_count + entry->buf_count) * + sizeof(*dma->buflist), GFP_KERNEL); if (!temp_buflist) { /* Free the entry because it isn't valid */ drm_cleanup_buf_error(dev, entry); @@ -853,8 +844,7 @@ int drm_addbufs_pci(struct drm_device * dev, struct drm_buf_desc * request) return -EINVAL; } - entry->buflist = drm_alloc(count * sizeof(*entry->buflist), - DRM_MEM_BUFS); + entry->buflist = kmalloc(count * sizeof(*entry->buflist), GFP_KERNEL); if (!entry->buflist) { mutex_unlock(&dev->struct_mutex); atomic_dec(&dev->buf_alloc); @@ -862,11 +852,9 @@ int drm_addbufs_pci(struct drm_device * dev, struct drm_buf_desc * request) } memset(entry->buflist, 0, count * sizeof(*entry->buflist)); - entry->seglist = drm_alloc(count * sizeof(*entry->seglist), - DRM_MEM_SEGS); + entry->seglist = kmalloc(count * sizeof(*entry->seglist), GFP_KERNEL); if (!entry->seglist) { - drm_free(entry->buflist, - count * sizeof(*entry->buflist), DRM_MEM_BUFS); + kfree(entry->buflist); mutex_unlock(&dev->struct_mutex); atomic_dec(&dev->buf_alloc); return -ENOMEM; @@ -876,13 +864,11 @@ int drm_addbufs_pci(struct drm_device * dev, struct drm_buf_desc * request) /* Keep the original pagelist until we know all the allocations * have succeeded */ - temp_pagelist = drm_alloc((dma->page_count + (count << page_order)) - * sizeof(*dma->pagelist), DRM_MEM_PAGES); + temp_pagelist = kmalloc((dma->page_count + (count << page_order)) * + sizeof(*dma->pagelist), GFP_KERNEL); if (!temp_pagelist) { - drm_free(entry->buflist, - count * sizeof(*entry->buflist), DRM_MEM_BUFS); - drm_free(entry->seglist, - count * sizeof(*entry->seglist), DRM_MEM_SEGS); + kfree(entry->buflist); + kfree(entry->seglist); mutex_unlock(&dev->struct_mutex); atomic_dec(&dev->buf_alloc); return -ENOMEM; @@ -906,9 +892,7 @@ int drm_addbufs_pci(struct drm_device * dev, struct drm_buf_desc * request) entry->buf_count = count; entry->seg_count = count; drm_cleanup_buf_error(dev, entry); - drm_free(temp_pagelist, - (dma->page_count + (count << page_order)) - * sizeof(*dma->pagelist), DRM_MEM_PAGES); + kfree(temp_pagelist); mutex_unlock(&dev->struct_mutex); atomic_dec(&dev->buf_alloc); return -ENOMEM; @@ -939,18 +923,14 @@ int drm_addbufs_pci(struct drm_device * dev, struct drm_buf_desc * request) buf->file_priv = NULL; buf->dev_priv_size = dev->driver->dev_priv_size; - buf->dev_private = drm_alloc(buf->dev_priv_size, - DRM_MEM_BUFS); + buf->dev_private = kmalloc(buf->dev_priv_size, + GFP_KERNEL); if (!buf->dev_private) { /* Set count correctly so we free the proper amount. */ entry->buf_count = count; entry->seg_count = count; drm_cleanup_buf_error(dev, entry); - drm_free(temp_pagelist, - (dma->page_count + - (count << page_order)) - * sizeof(*dma->pagelist), - DRM_MEM_PAGES); + kfree(temp_pagelist); mutex_unlock(&dev->struct_mutex); atomic_dec(&dev->buf_alloc); return -ENOMEM; @@ -963,16 +943,13 @@ int drm_addbufs_pci(struct drm_device * dev, struct drm_buf_desc * request) byte_count += PAGE_SIZE << page_order; } - temp_buflist = drm_realloc(dma->buflist, - dma->buf_count * sizeof(*dma->buflist), - (dma->buf_count + entry->buf_count) - * sizeof(*dma->buflist), DRM_MEM_BUFS); + temp_buflist = krealloc(dma->buflist, + (dma->buf_count + entry->buf_count) * + sizeof(*dma->buflist), GFP_KERNEL); if (!temp_buflist) { /* Free the entry because it isn't valid */ drm_cleanup_buf_error(dev, entry); - drm_free(temp_pagelist, - (dma->page_count + (count << page_order)) - * sizeof(*dma->pagelist), DRM_MEM_PAGES); + kfree(temp_pagelist); mutex_unlock(&dev->struct_mutex); atomic_dec(&dev->buf_alloc); return -ENOMEM; @@ -987,9 +964,7 @@ int drm_addbufs_pci(struct drm_device * dev, struct drm_buf_desc * request) * with the new one. */ if (dma->page_count) { - drm_free(dma->pagelist, - dma->page_count * sizeof(*dma->pagelist), - DRM_MEM_PAGES); + kfree(dma->pagelist); } dma->pagelist = temp_pagelist; @@ -1085,8 +1060,8 @@ static int drm_addbufs_sg(struct drm_device * dev, struct drm_buf_desc * request return -EINVAL; } - entry->buflist = drm_alloc(count * sizeof(*entry->buflist), - DRM_MEM_BUFS); + entry->buflist = kmalloc(count * sizeof(*entry->buflist), + GFP_KERNEL); if (!entry->buflist) { mutex_unlock(&dev->struct_mutex); atomic_dec(&dev->buf_alloc); @@ -1117,7 +1092,7 @@ static int drm_addbufs_sg(struct drm_device * dev, struct drm_buf_desc * request buf->file_priv = NULL; buf->dev_priv_size = dev->driver->dev_priv_size; - buf->dev_private = drm_alloc(buf->dev_priv_size, DRM_MEM_BUFS); + buf->dev_private = kmalloc(buf->dev_priv_size, GFP_KERNEL); if (!buf->dev_private) { /* Set count correctly so we free the proper amount. */ entry->buf_count = count; @@ -1138,10 +1113,9 @@ static int drm_addbufs_sg(struct drm_device * dev, struct drm_buf_desc * request DRM_DEBUG("byte_count: %d\n", byte_count); - temp_buflist = drm_realloc(dma->buflist, - dma->buf_count * sizeof(*dma->buflist), - (dma->buf_count + entry->buf_count) - * sizeof(*dma->buflist), DRM_MEM_BUFS); + temp_buflist = krealloc(dma->buflist, + (dma->buf_count + entry->buf_count) * + sizeof(*dma->buflist), GFP_KERNEL); if (!temp_buflist) { /* Free the entry because it isn't valid */ drm_cleanup_buf_error(dev, entry); @@ -1247,8 +1221,8 @@ static int drm_addbufs_fb(struct drm_device * dev, struct drm_buf_desc * request return -EINVAL; } - entry->buflist = drm_alloc(count * sizeof(*entry->buflist), - DRM_MEM_BUFS); + entry->buflist = kmalloc(count * sizeof(*entry->buflist), + GFP_KERNEL); if (!entry->buflist) { mutex_unlock(&dev->struct_mutex); atomic_dec(&dev->buf_alloc); @@ -1278,7 +1252,7 @@ static int drm_addbufs_fb(struct drm_device * dev, struct drm_buf_desc * request buf->file_priv = NULL; buf->dev_priv_size = dev->driver->dev_priv_size; - buf->dev_private = drm_alloc(buf->dev_priv_size, DRM_MEM_BUFS); + buf->dev_private = kmalloc(buf->dev_priv_size, GFP_KERNEL); if (!buf->dev_private) { /* Set count correctly so we free the proper amount. */ entry->buf_count = count; @@ -1298,10 +1272,9 @@ static int drm_addbufs_fb(struct drm_device * dev, struct drm_buf_desc * request DRM_DEBUG("byte_count: %d\n", byte_count); - temp_buflist = drm_realloc(dma->buflist, - dma->buf_count * sizeof(*dma->buflist), - (dma->buf_count + entry->buf_count) - * sizeof(*dma->buflist), DRM_MEM_BUFS); + temp_buflist = krealloc(dma->buflist, + (dma->buf_count + entry->buf_count) * + sizeof(*dma->buflist), GFP_KERNEL); if (!temp_buflist) { /* Free the entry because it isn't valid */ drm_cleanup_buf_error(dev, entry); diff --git a/drivers/gpu/drm/drm_context.c b/drivers/gpu/drm/drm_context.c index 7d1e53c10d4b..2607753a320b 100644 --- a/drivers/gpu/drm/drm_context.c +++ b/drivers/gpu/drm/drm_context.c @@ -341,7 +341,7 @@ int drm_addctx(struct drm_device *dev, void *data, } } - ctx_entry = drm_alloc(sizeof(*ctx_entry), DRM_MEM_CTXLIST); + ctx_entry = kmalloc(sizeof(*ctx_entry), GFP_KERNEL); if (!ctx_entry) { DRM_DEBUG("out of memory\n"); return -ENOMEM; @@ -456,7 +456,7 @@ int drm_rmctx(struct drm_device *dev, void *data, list_for_each_entry_safe(pos, n, &dev->ctxlist, head) { if (pos->handle == ctx->handle) { list_del(&pos->head); - drm_free(pos, sizeof(*pos), DRM_MEM_CTXLIST); + kfree(pos); --dev->ctx_count; } } diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c index c77c6c6d9d2c..2960b6d73456 100644 --- a/drivers/gpu/drm/drm_debugfs.c +++ b/drivers/gpu/drm/drm_debugfs.c @@ -100,15 +100,13 @@ int drm_debugfs_create_files(struct drm_info_list *files, int count, (dev->driver->driver_features & features) != features) continue; - tmp = drm_alloc(sizeof(struct drm_info_node), - _DRM_DRIVER); + tmp = kmalloc(sizeof(struct drm_info_node), GFP_KERNEL); ent = debugfs_create_file(files[i].name, S_IFREG | S_IRUGO, root, tmp, &drm_debugfs_fops); if (!ent) { - DRM_ERROR("Cannot create /debugfs/dri/%s/%s\n", + DRM_ERROR("Cannot create /sys/kernel/debug/dri/%s/%s\n", name, files[i].name); - drm_free(tmp, sizeof(struct drm_info_node), - _DRM_DRIVER); + kfree(tmp); ret = -1; goto fail; } @@ -133,9 +131,9 @@ EXPORT_SYMBOL(drm_debugfs_create_files); * \param minor device minor number * \param root DRI debugfs dir entry. * - * Create the DRI debugfs root entry "/debugfs/dri", the device debugfs root entry - * "/debugfs/dri/%minor%/", and each entry in debugfs_list as - * "/debugfs/dri/%minor%/%name%". + * Create the DRI debugfs root entry "/sys/kernel/debug/dri", the device debugfs root entry + * "/sys/kernel/debug/dri/%minor%/", and each entry in debugfs_list as + * "/sys/kernel/debug/dri/%minor%/%name%". */ int drm_debugfs_init(struct drm_minor *minor, int minor_id, struct dentry *root) @@ -148,7 +146,7 @@ int drm_debugfs_init(struct drm_minor *minor, int minor_id, sprintf(name, "%d", minor_id); minor->debugfs_root = debugfs_create_dir(name, root); if (!minor->debugfs_root) { - DRM_ERROR("Cannot create /debugfs/dri/%s\n", name); + DRM_ERROR("Cannot create /sys/kernel/debug/dri/%s\n", name); return -1; } @@ -165,7 +163,7 @@ int drm_debugfs_init(struct drm_minor *minor, int minor_id, ret = dev->driver->debugfs_init(minor); if (ret) { DRM_ERROR("DRM: Driver failed to initialize " - "/debugfs/dri.\n"); + "/sys/kernel/debug/dri.\n"); return ret; } } @@ -196,8 +194,7 @@ int drm_debugfs_remove_files(struct drm_info_list *files, int count, if (tmp->info_ent == &files[i]) { debugfs_remove(tmp->dent); list_del(pos); - drm_free(tmp, sizeof(struct drm_info_node), - _DRM_DRIVER); + kfree(tmp); } } } diff --git a/drivers/gpu/drm/drm_dma.c b/drivers/gpu/drm/drm_dma.c index 7a8e2fba4678..13f1537413fb 100644 --- a/drivers/gpu/drm/drm_dma.c +++ b/drivers/gpu/drm/drm_dma.c @@ -47,7 +47,7 @@ int drm_dma_setup(struct drm_device *dev) { int i; - dev->dma = drm_alloc(sizeof(*dev->dma), DRM_MEM_DRIVER); + dev->dma = kmalloc(sizeof(*dev->dma), GFP_KERNEL); if (!dev->dma) return -ENOMEM; @@ -88,36 +88,19 @@ void drm_dma_takedown(struct drm_device *dev) drm_pci_free(dev, dma->bufs[i].seglist[j]); } } - drm_free(dma->bufs[i].seglist, - dma->bufs[i].seg_count - * sizeof(*dma->bufs[0].seglist), DRM_MEM_SEGS); + kfree(dma->bufs[i].seglist); } if (dma->bufs[i].buf_count) { for (j = 0; j < dma->bufs[i].buf_count; j++) { - if (dma->bufs[i].buflist[j].dev_private) { - drm_free(dma->bufs[i].buflist[j]. - dev_private, - dma->bufs[i].buflist[j]. - dev_priv_size, DRM_MEM_BUFS); - } + kfree(dma->bufs[i].buflist[j].dev_private); } - drm_free(dma->bufs[i].buflist, - dma->bufs[i].buf_count * - sizeof(*dma->bufs[0].buflist), DRM_MEM_BUFS); + kfree(dma->bufs[i].buflist); } } - if (dma->buflist) { - drm_free(dma->buflist, - dma->buf_count * sizeof(*dma->buflist), DRM_MEM_BUFS); - } - - if (dma->pagelist) { - drm_free(dma->pagelist, - dma->page_count * sizeof(*dma->pagelist), - DRM_MEM_PAGES); - } - drm_free(dev->dma, sizeof(*dev->dma), DRM_MEM_DRIVER); + kfree(dma->buflist); + kfree(dma->pagelist); + kfree(dev->dma); dev->dma = NULL; } diff --git a/drivers/gpu/drm/drm_drawable.c b/drivers/gpu/drm/drm_drawable.c index 80be1cab62af..c53c9768cc11 100644 --- a/drivers/gpu/drm/drm_drawable.c +++ b/drivers/gpu/drm/drm_drawable.c @@ -85,9 +85,8 @@ int drm_rmdraw(struct drm_device *dev, void *data, struct drm_file *file_priv) spin_unlock_irqrestore(&dev->drw_lock, irqflags); return -EINVAL; } - drm_free(info->rects, info->num_rects * sizeof(struct drm_clip_rect), - DRM_MEM_BUFS); - drm_free(info, sizeof(struct drm_drawable_info), DRM_MEM_BUFS); + kfree(info->rects); + kfree(info); idr_remove(&dev->drw_idr, draw->handle); @@ -106,12 +105,12 @@ int drm_update_drawable_info(struct drm_device *dev, void *data, struct drm_file info = idr_find(&dev->drw_idr, update->handle); if (!info) { - info = drm_calloc(1, sizeof(*info), DRM_MEM_BUFS); + info = kzalloc(sizeof(*info), GFP_KERNEL); if (!info) return -ENOMEM; if (IS_ERR(idr_replace(&dev->drw_idr, info, update->handle))) { DRM_ERROR("No such drawable %d\n", update->handle); - drm_free(info, sizeof(*info), DRM_MEM_BUFS); + kfree(info); return -EINVAL; } } @@ -121,8 +120,9 @@ int drm_update_drawable_info(struct drm_device *dev, void *data, struct drm_file if (update->num == 0) rects = NULL; else if (update->num != info->num_rects) { - rects = drm_alloc(update->num * sizeof(struct drm_clip_rect), - DRM_MEM_BUFS); + rects = kmalloc(update->num * + sizeof(struct drm_clip_rect), + GFP_KERNEL); } else rects = info->rects; @@ -145,8 +145,7 @@ int drm_update_drawable_info(struct drm_device *dev, void *data, struct drm_file spin_lock_irqsave(&dev->drw_lock, irqflags); if (rects != info->rects) { - drm_free(info->rects, info->num_rects * - sizeof(struct drm_clip_rect), DRM_MEM_BUFS); + kfree(info->rects); } info->rects = rects; @@ -166,8 +165,7 @@ int drm_update_drawable_info(struct drm_device *dev, void *data, struct drm_file error: if (rects != info->rects) - drm_free(rects, update->num * sizeof(struct drm_clip_rect), - DRM_MEM_BUFS); + kfree(rects); return err; } @@ -186,9 +184,8 @@ static int drm_drawable_free(int idr, void *p, void *data) struct drm_drawable_info *info = p; if (info) { - drm_free(info->rects, info->num_rects * - sizeof(struct drm_clip_rect), DRM_MEM_BUFS); - drm_free(info, sizeof(*info), DRM_MEM_BUFS); + kfree(info->rects); + kfree(info); } return 0; diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 019b7c578236..b39d7bfc0c9c 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -189,7 +189,7 @@ int drm_lastclose(struct drm_device * dev) if (entry->bound) drm_unbind_agp(entry->memory); drm_free_agp(entry->memory, entry->pages); - drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS); + kfree(entry); } INIT_LIST_HEAD(&dev->agp->memory); @@ -208,21 +208,15 @@ int drm_lastclose(struct drm_device * dev) /* Clear vma list (only built for debugging) */ list_for_each_entry_safe(vma, vma_temp, &dev->vmalist, head) { list_del(&vma->head); - drm_free(vma, sizeof(*vma), DRM_MEM_VMAS); + kfree(vma); } if (drm_core_check_feature(dev, DRIVER_DMA_QUEUE) && dev->queuelist) { for (i = 0; i < dev->queue_count; i++) { - if (dev->queuelist[i]) { - drm_free(dev->queuelist[i], - sizeof(*dev->queuelist[0]), - DRM_MEM_QUEUES); - dev->queuelist[i] = NULL; - } + kfree(dev->queuelist[i]); + dev->queuelist[i] = NULL; } - drm_free(dev->queuelist, - dev->queue_slots * sizeof(*dev->queuelist), - DRM_MEM_QUEUES); + kfree(dev->queuelist); dev->queuelist = NULL; } dev->queue_count = 0; @@ -339,13 +333,11 @@ static int __init drm_core_init(void) drm_debugfs_root = debugfs_create_dir("dri", NULL); if (!drm_debugfs_root) { - DRM_ERROR("Cannot create /debugfs/dri\n"); + DRM_ERROR("Cannot create /sys/kernel/debug/dri\n"); ret = -1; goto err_p3; } - drm_mem_init(); - DRM_INFO("Initialized %s %d.%d.%d %s\n", CORE_NAME, CORE_MAJOR, CORE_MINOR, CORE_PATCHLEVEL, CORE_DATE); return 0; diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 6f6b26479d82..7d0835226f6e 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -252,16 +252,18 @@ struct drm_display_mode *drm_mode_std(struct drm_device *dev, { struct drm_display_mode *mode; int hsize = t->hsize * 8 + 248, vsize; + unsigned aspect_ratio = (t->vfreq_aspect & EDID_TIMING_ASPECT_MASK) + >> EDID_TIMING_ASPECT_SHIFT; mode = drm_mode_create(dev); if (!mode) return NULL; - if (t->aspect_ratio == 0) + if (aspect_ratio == 0) vsize = (hsize * 10) / 16; - else if (t->aspect_ratio == 1) + else if (aspect_ratio == 1) vsize = (hsize * 3) / 4; - else if (t->aspect_ratio == 2) + else if (aspect_ratio == 2) vsize = (hsize * 4) / 5; else vsize = (hsize * 9) / 16; @@ -288,17 +290,24 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev, { struct drm_display_mode *mode; struct detailed_pixel_timing *pt = &timing->data.pixel_data; + unsigned hactive = (pt->hactive_hblank_hi & 0xf0) << 4 | pt->hactive_lo; + unsigned vactive = (pt->vactive_vblank_hi & 0xf0) << 4 | pt->vactive_lo; + unsigned hblank = (pt->hactive_hblank_hi & 0xf) << 8 | pt->hblank_lo; + unsigned vblank = (pt->vactive_vblank_hi & 0xf) << 8 | pt->vblank_lo; + unsigned hsync_offset = (pt->hsync_vsync_offset_pulse_width_hi & 0x3) << 8 | pt->hsync_offset_lo; + unsigned hsync_pulse_width = (pt->hsync_vsync_offset_pulse_width_hi & 0xc) << 6 | pt->hsync_pulse_width_lo; + unsigned vsync_offset = (pt->hsync_vsync_offset_pulse_width_hi & 0x30) | (pt->vsync_offset_pulse_width_lo & 0xf); + unsigned vsync_pulse_width = (pt->hsync_vsync_offset_pulse_width_hi & 0xc0) >> 2 | pt->vsync_offset_pulse_width_lo >> 4; /* ignore tiny modes */ - if (((pt->hactive_hi << 8) | pt->hactive_lo) < 64 || - ((pt->vactive_hi << 8) | pt->hactive_lo) < 64) + if (hactive < 64 || vactive < 64) return NULL; - if (pt->stereo) { + if (pt->misc & DRM_EDID_PT_STEREO) { printk(KERN_WARNING "stereo mode not supported\n"); return NULL; } - if (!pt->separate_sync) { + if (!(pt->misc & DRM_EDID_PT_SEPARATE_SYNC)) { printk(KERN_WARNING "integrated sync not supported\n"); return NULL; } @@ -310,41 +319,36 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev, mode->type = DRM_MODE_TYPE_DRIVER; if (quirks & EDID_QUIRK_135_CLOCK_TOO_HIGH) - timing->pixel_clock = 1088; + timing->pixel_clock = cpu_to_le16(1088); - mode->clock = timing->pixel_clock * 10; + mode->clock = le16_to_cpu(timing->pixel_clock) * 10; - mode->hdisplay = (pt->hactive_hi << 8) | pt->hactive_lo; - mode->hsync_start = mode->hdisplay + ((pt->hsync_offset_hi << 8) | - pt->hsync_offset_lo); - mode->hsync_end = mode->hsync_start + - ((pt->hsync_pulse_width_hi << 8) | - pt->hsync_pulse_width_lo); - mode->htotal = mode->hdisplay + ((pt->hblank_hi << 8) | pt->hblank_lo); + mode->hdisplay = hactive; + mode->hsync_start = mode->hdisplay + hsync_offset; + mode->hsync_end = mode->hsync_start + hsync_pulse_width; + mode->htotal = mode->hdisplay + hblank; - mode->vdisplay = (pt->vactive_hi << 8) | pt->vactive_lo; - mode->vsync_start = mode->vdisplay + ((pt->vsync_offset_hi << 4) | - pt->vsync_offset_lo); - mode->vsync_end = mode->vsync_start + - ((pt->vsync_pulse_width_hi << 4) | - pt->vsync_pulse_width_lo); - mode->vtotal = mode->vdisplay + ((pt->vblank_hi << 8) | pt->vblank_lo); + mode->vdisplay = vactive; + mode->vsync_start = mode->vdisplay + vsync_offset; + mode->vsync_end = mode->vsync_start + vsync_pulse_width; + mode->vtotal = mode->vdisplay + vblank; drm_mode_set_name(mode); - if (pt->interlaced) + if (pt->misc & DRM_EDID_PT_INTERLACED) mode->flags |= DRM_MODE_FLAG_INTERLACE; if (quirks & EDID_QUIRK_DETAILED_SYNC_PP) { - pt->hsync_positive = 1; - pt->vsync_positive = 1; + pt->misc |= DRM_EDID_PT_HSYNC_POSITIVE | DRM_EDID_PT_VSYNC_POSITIVE; } - mode->flags |= pt->hsync_positive ? DRM_MODE_FLAG_PHSYNC : DRM_MODE_FLAG_NHSYNC; - mode->flags |= pt->vsync_positive ? DRM_MODE_FLAG_PVSYNC : DRM_MODE_FLAG_NVSYNC; + mode->flags |= (pt->misc & DRM_EDID_PT_HSYNC_POSITIVE) ? + DRM_MODE_FLAG_PHSYNC : DRM_MODE_FLAG_NHSYNC; + mode->flags |= (pt->misc & DRM_EDID_PT_VSYNC_POSITIVE) ? + DRM_MODE_FLAG_PVSYNC : DRM_MODE_FLAG_NVSYNC; - mode->width_mm = pt->width_mm_lo | (pt->width_mm_hi << 8); - mode->height_mm = pt->height_mm_lo | (pt->height_mm_hi << 8); + mode->width_mm = pt->width_mm_lo | (pt->width_height_mm_hi & 0xf) << 8; + mode->height_mm = pt->height_mm_lo | (pt->width_height_mm_hi & 0xf0) << 4; if (quirks & EDID_QUIRK_DETAILED_IN_CM) { mode->width_mm *= 10; @@ -465,7 +469,7 @@ static int add_standard_modes(struct drm_connector *connector, struct edid *edid struct drm_display_mode *newmode; /* If std timings bytes are 1, 1 it's empty */ - if (t->hsize == 1 && (t->aspect_ratio | t->vfreq) == 1) + if (t->hsize == 1 && t->vfreq_aspect == 1) continue; newmode = drm_mode_std(dev, &edid->standard_timings[i]); @@ -509,7 +513,7 @@ static int add_detailed_info(struct drm_connector *connector, continue; /* First detailed mode is preferred */ - if (i == 0 && edid->preferred_timing) + if (i == 0 && (edid->features & DRM_EDID_FEATURE_PREFERRED_TIMING)) newmode->type |= DRM_MODE_TYPE_PREFERRED; drm_mode_probed_add(connector, newmode); @@ -589,85 +593,13 @@ int drm_do_probe_ddc_edid(struct i2c_adapter *adapter, } EXPORT_SYMBOL(drm_do_probe_ddc_edid); -/** - * Get EDID information. - * - * \param adapter : i2c device adaptor. - * \param buf : EDID data buffer to be filled - * \param len : EDID data buffer length - * \return 0 on success or -1 on failure. - * - * Initialize DDC, then fetch EDID information - * by calling drm_do_probe_ddc_edid function. - */ -static int drm_ddc_read(struct i2c_adapter *adapter, - unsigned char *buf, int len) -{ - struct i2c_algo_bit_data *algo_data = adapter->algo_data; - int i, j; - int ret = -1; - - algo_data->setscl(algo_data->data, 1); - - for (i = 0; i < 1; i++) { - /* For some old monitors we need the - * following process to initialize/stop DDC - */ - algo_data->setsda(algo_data->data, 1); - msleep(13); - - algo_data->setscl(algo_data->data, 1); - for (j = 0; j < 5; j++) { - msleep(10); - if (algo_data->getscl(algo_data->data)) - break; - } - if (j == 5) - continue; - - algo_data->setsda(algo_data->data, 0); - msleep(15); - algo_data->setscl(algo_data->data, 0); - msleep(15); - algo_data->setsda(algo_data->data, 1); - msleep(15); - - /* Do the real work */ - ret = drm_do_probe_ddc_edid(adapter, buf, len); - algo_data->setsda(algo_data->data, 0); - algo_data->setscl(algo_data->data, 0); - msleep(15); - - algo_data->setscl(algo_data->data, 1); - for (j = 0; j < 10; j++) { - msleep(10); - if (algo_data->getscl(algo_data->data)) - break; - } - - algo_data->setsda(algo_data->data, 1); - msleep(15); - algo_data->setscl(algo_data->data, 0); - algo_data->setsda(algo_data->data, 0); - if (ret == 0) - break; - } - /* Release the DDC lines when done or the Apple Cinema HD display - * will switch off - */ - algo_data->setsda(algo_data->data, 1); - algo_data->setscl(algo_data->data, 1); - - return ret; -} - static int drm_ddc_read_edid(struct drm_connector *connector, struct i2c_adapter *adapter, char *buf, int len) { int ret; - ret = drm_ddc_read(adapter, buf, len); + ret = drm_do_probe_ddc_edid(adapter, buf, len); if (ret != 0) { dev_info(&connector->dev->pdev->dev, "%s: no EDID data\n", drm_get_connector_name(connector)); @@ -839,22 +771,22 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid) if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75)) edid_fixup_preferred(connector, quirks); - connector->display_info.serration_vsync = edid->serration_vsync; - connector->display_info.sync_on_green = edid->sync_on_green; - connector->display_info.composite_sync = edid->composite_sync; - connector->display_info.separate_syncs = edid->separate_syncs; - connector->display_info.blank_to_black = edid->blank_to_black; - connector->display_info.video_level = edid->video_level; - connector->display_info.digital = edid->digital; + connector->display_info.serration_vsync = (edid->input & DRM_EDID_INPUT_SERRATION_VSYNC) ? 1 : 0; + connector->display_info.sync_on_green = (edid->input & DRM_EDID_INPUT_SYNC_ON_GREEN) ? 1 : 0; + connector->display_info.composite_sync = (edid->input & DRM_EDID_INPUT_COMPOSITE_SYNC) ? 1 : 0; + connector->display_info.separate_syncs = (edid->input & DRM_EDID_INPUT_SEPARATE_SYNCS) ? 1 : 0; + connector->display_info.blank_to_black = (edid->input & DRM_EDID_INPUT_BLANK_TO_BLACK) ? 1 : 0; + connector->display_info.video_level = (edid->input & DRM_EDID_INPUT_VIDEO_LEVEL) >> 5; + connector->display_info.digital = (edid->input & DRM_EDID_INPUT_DIGITAL) ? 1 : 0; connector->display_info.width_mm = edid->width_cm * 10; connector->display_info.height_mm = edid->height_cm * 10; connector->display_info.gamma = edid->gamma; - connector->display_info.gtf_supported = edid->default_gtf; - connector->display_info.standard_color = edid->standard_color; - connector->display_info.display_type = edid->display_type; - connector->display_info.active_off_supported = edid->pm_active_off; - connector->display_info.suspend_supported = edid->pm_suspend; - connector->display_info.standby_supported = edid->pm_standby; + connector->display_info.gtf_supported = (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF) ? 1 : 0; + connector->display_info.standard_color = (edid->features & DRM_EDID_FEATURE_STANDARD_COLOR) ? 1 : 0; + connector->display_info.display_type = (edid->features & DRM_EDID_FEATURE_DISPLAY_TYPE) >> 3; + connector->display_info.active_off_supported = (edid->features & DRM_EDID_FEATURE_PM_ACTIVE_OFF) ? 1 : 0; + connector->display_info.suspend_supported = (edid->features & DRM_EDID_FEATURE_PM_SUSPEND) ? 1 : 0; + connector->display_info.standby_supported = (edid->features & DRM_EDID_FEATURE_PM_STANDBY) ? 1 : 0; connector->display_info.gamma = edid->gamma; return num_modes; diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c index 09a3571c9908..251bc0e3b5ec 100644 --- a/drivers/gpu/drm/drm_fops.c +++ b/drivers/gpu/drm/drm_fops.c @@ -240,7 +240,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp, DRM_DEBUG("pid = %d, minor = %d\n", task_pid_nr(current), minor_id); - priv = drm_alloc(sizeof(*priv), DRM_MEM_FILES); + priv = kmalloc(sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; @@ -328,7 +328,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp, return 0; out_free: - drm_free(priv, sizeof(*priv), DRM_MEM_FILES); + kfree(priv); filp->private_data = NULL; return ret; } @@ -471,7 +471,7 @@ int drm_release(struct inode *inode, struct file *filp) drm_ctxbitmap_free(dev, pos->handle); list_del(&pos->head); - drm_free(pos, sizeof(*pos), DRM_MEM_CTXLIST); + kfree(pos); --dev->ctx_count; } } @@ -516,7 +516,7 @@ int drm_release(struct inode *inode, struct file *filp) if (dev->driver->postclose) dev->driver->postclose(dev, file_priv); - drm_free(file_priv, sizeof(*file_priv), DRM_MEM_FILES); + kfree(file_priv); /* ======================================================== * End inline drm_release diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index 4984aa89cf3d..8104ecaea26f 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -89,7 +89,7 @@ drm_gem_init(struct drm_device *dev) atomic_set(&dev->gtt_count, 0); atomic_set(&dev->gtt_memory, 0); - mm = drm_calloc(1, sizeof(struct drm_gem_mm), DRM_MEM_MM); + mm = kzalloc(sizeof(struct drm_gem_mm), GFP_KERNEL); if (!mm) { DRM_ERROR("out of memory\n"); return -ENOMEM; @@ -98,14 +98,14 @@ drm_gem_init(struct drm_device *dev) dev->mm_private = mm; if (drm_ht_create(&mm->offset_hash, 19)) { - drm_free(mm, sizeof(struct drm_gem_mm), DRM_MEM_MM); + kfree(mm); return -ENOMEM; } if (drm_mm_init(&mm->offset_manager, DRM_FILE_PAGE_OFFSET_START, DRM_FILE_PAGE_OFFSET_SIZE)) { drm_ht_remove(&mm->offset_hash); - drm_free(mm, sizeof(struct drm_gem_mm), DRM_MEM_MM); + kfree(mm); return -ENOMEM; } @@ -119,7 +119,7 @@ drm_gem_destroy(struct drm_device *dev) drm_mm_takedown(&mm->offset_manager); drm_ht_remove(&mm->offset_hash); - drm_free(mm, sizeof(struct drm_gem_mm), DRM_MEM_MM); + kfree(mm); dev->mm_private = NULL; } @@ -133,7 +133,7 @@ drm_gem_object_alloc(struct drm_device *dev, size_t size) BUG_ON((size & (PAGE_SIZE - 1)) != 0); - obj = kcalloc(1, sizeof(*obj), GFP_KERNEL); + obj = kzalloc(sizeof(*obj), GFP_KERNEL); obj->dev = dev; obj->filp = shmem_file_setup("drm mm object", size, VM_NORESERVE); diff --git a/drivers/gpu/drm/drm_hashtab.c b/drivers/gpu/drm/drm_hashtab.c index af539f7d87dd..f36b21c5b2e1 100644 --- a/drivers/gpu/drm/drm_hashtab.c +++ b/drivers/gpu/drm/drm_hashtab.c @@ -46,8 +46,7 @@ int drm_ht_create(struct drm_open_hash *ht, unsigned int order) ht->table = NULL; ht->use_vmalloc = ((ht->size * sizeof(*ht->table)) > PAGE_SIZE); if (!ht->use_vmalloc) { - ht->table = drm_calloc(ht->size, sizeof(*ht->table), - DRM_MEM_HASHTAB); + ht->table = kcalloc(ht->size, sizeof(*ht->table), GFP_KERNEL); } if (!ht->table) { ht->use_vmalloc = 1; @@ -62,6 +61,7 @@ int drm_ht_create(struct drm_open_hash *ht, unsigned int order) } return 0; } +EXPORT_SYMBOL(drm_ht_create); void drm_ht_verbose_list(struct drm_open_hash *ht, unsigned long key) { @@ -156,6 +156,7 @@ int drm_ht_just_insert_please(struct drm_open_hash *ht, struct drm_hash_item *it } return 0; } +EXPORT_SYMBOL(drm_ht_just_insert_please); int drm_ht_find_item(struct drm_open_hash *ht, unsigned long key, struct drm_hash_item **item) @@ -169,6 +170,7 @@ int drm_ht_find_item(struct drm_open_hash *ht, unsigned long key, *item = hlist_entry(list, struct drm_hash_item, head); return 0; } +EXPORT_SYMBOL(drm_ht_find_item); int drm_ht_remove_key(struct drm_open_hash *ht, unsigned long key) { @@ -197,8 +199,8 @@ void drm_ht_remove(struct drm_open_hash *ht) if (ht->use_vmalloc) vfree(ht->table); else - drm_free(ht->table, ht->size * sizeof(*ht->table), - DRM_MEM_HASHTAB); + kfree(ht->table); ht->table = NULL; } } +EXPORT_SYMBOL(drm_ht_remove); diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index 1fad76289e66..9b9ff46c2378 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -93,7 +93,7 @@ int drm_setunique(struct drm_device *dev, void *data, master->unique_len = u->unique_len; master->unique_size = u->unique_len + 1; - master->unique = drm_alloc(master->unique_size, DRM_MEM_DRIVER); + master->unique = kmalloc(master->unique_size, GFP_KERNEL); if (!master->unique) return -ENOMEM; if (copy_from_user(master->unique, u->unique, master->unique_len)) @@ -101,9 +101,8 @@ int drm_setunique(struct drm_device *dev, void *data, master->unique[master->unique_len] = '\0'; - dev->devname = - drm_alloc(strlen(dev->driver->pci_driver.name) + - strlen(master->unique) + 2, DRM_MEM_DRIVER); + dev->devname = kmalloc(strlen(dev->driver->pci_driver.name) + + strlen(master->unique) + 2, GFP_KERNEL); if (!dev->devname) return -ENOMEM; @@ -138,7 +137,7 @@ static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv) master->unique_len = 40; master->unique_size = master->unique_len; - master->unique = drm_alloc(master->unique_size, DRM_MEM_DRIVER); + master->unique = kmalloc(master->unique_size, GFP_KERNEL); if (master->unique == NULL) return -ENOMEM; @@ -152,9 +151,8 @@ static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv) else master->unique_len = len; - dev->devname = - drm_alloc(strlen(dev->driver->pci_driver.name) + master->unique_len + - 2, DRM_MEM_DRIVER); + dev->devname = kmalloc(strlen(dev->driver->pci_driver.name) + + master->unique_len + 2, GFP_KERNEL); if (dev->devname == NULL) return -ENOMEM; diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index fc8e5acd9d9a..b4a3dbcebe9b 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -104,21 +104,13 @@ void drm_vblank_cleanup(struct drm_device *dev) vblank_disable_fn((unsigned long)dev); - drm_free(dev->vbl_queue, sizeof(*dev->vbl_queue) * dev->num_crtcs, - DRM_MEM_DRIVER); - drm_free(dev->_vblank_count, sizeof(*dev->_vblank_count) * - dev->num_crtcs, DRM_MEM_DRIVER); - drm_free(dev->vblank_refcount, sizeof(*dev->vblank_refcount) * - dev->num_crtcs, DRM_MEM_DRIVER); - drm_free(dev->vblank_enabled, sizeof(*dev->vblank_enabled) * - dev->num_crtcs, DRM_MEM_DRIVER); - drm_free(dev->last_vblank, sizeof(*dev->last_vblank) * dev->num_crtcs, - DRM_MEM_DRIVER); - drm_free(dev->last_vblank_wait, - sizeof(*dev->last_vblank_wait) * dev->num_crtcs, - DRM_MEM_DRIVER); - drm_free(dev->vblank_inmodeset, sizeof(*dev->vblank_inmodeset) * - dev->num_crtcs, DRM_MEM_DRIVER); + kfree(dev->vbl_queue); + kfree(dev->_vblank_count); + kfree(dev->vblank_refcount); + kfree(dev->vblank_enabled); + kfree(dev->last_vblank); + kfree(dev->last_vblank_wait); + kfree(dev->vblank_inmodeset); dev->num_crtcs = 0; } @@ -132,37 +124,33 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs) spin_lock_init(&dev->vbl_lock); dev->num_crtcs = num_crtcs; - dev->vbl_queue = drm_alloc(sizeof(wait_queue_head_t) * num_crtcs, - DRM_MEM_DRIVER); + dev->vbl_queue = kmalloc(sizeof(wait_queue_head_t) * num_crtcs, + GFP_KERNEL); if (!dev->vbl_queue) goto err; - dev->_vblank_count = drm_alloc(sizeof(atomic_t) * num_crtcs, - DRM_MEM_DRIVER); + dev->_vblank_count = kmalloc(sizeof(atomic_t) * num_crtcs, GFP_KERNEL); if (!dev->_vblank_count) goto err; - dev->vblank_refcount = drm_alloc(sizeof(atomic_t) * num_crtcs, - DRM_MEM_DRIVER); + dev->vblank_refcount = kmalloc(sizeof(atomic_t) * num_crtcs, + GFP_KERNEL); if (!dev->vblank_refcount) goto err; - dev->vblank_enabled = drm_calloc(num_crtcs, sizeof(int), - DRM_MEM_DRIVER); + dev->vblank_enabled = kcalloc(num_crtcs, sizeof(int), GFP_KERNEL); if (!dev->vblank_enabled) goto err; - dev->last_vblank = drm_calloc(num_crtcs, sizeof(u32), DRM_MEM_DRIVER); + dev->last_vblank = kcalloc(num_crtcs, sizeof(u32), GFP_KERNEL); if (!dev->last_vblank) goto err; - dev->last_vblank_wait = drm_calloc(num_crtcs, sizeof(u32), - DRM_MEM_DRIVER); + dev->last_vblank_wait = kcalloc(num_crtcs, sizeof(u32), GFP_KERNEL); if (!dev->last_vblank_wait) goto err; - dev->vblank_inmodeset = drm_calloc(num_crtcs, sizeof(int), - DRM_MEM_DRIVER); + dev->vblank_inmodeset = kcalloc(num_crtcs, sizeof(int), GFP_KERNEL); if (!dev->vblank_inmodeset) goto err; diff --git a/drivers/gpu/drm/drm_memory.c b/drivers/gpu/drm/drm_memory.c index 0c707f533eab..e4865f99989c 100644 --- a/drivers/gpu/drm/drm_memory.c +++ b/drivers/gpu/drm/drm_memory.c @@ -36,15 +36,6 @@ #include #include "drmP.h" -#ifdef DEBUG_MEMORY -#include "drm_memory_debug.h" -#else - -/** No-op. */ -void drm_mem_init(void) -{ -} - /** * Called when "/proc/dri/%dev%/mem" is read. * @@ -64,28 +55,15 @@ int drm_mem_info(char *buf, char **start, off_t offset, return 0; } -/** Wrapper around kmalloc() and kfree() */ -void *drm_realloc(void *oldpt, size_t oldsize, size_t size, int area) -{ - void *pt; - - if (!(pt = kmalloc(size, GFP_KERNEL))) - return NULL; - if (oldpt && oldsize) { - memcpy(pt, oldpt, oldsize); - kfree(oldpt); - } - return pt; -} - #if __OS_HAS_AGP static void *agp_remap(unsigned long offset, unsigned long size, struct drm_device * dev) { - unsigned long *phys_addr_map, i, num_pages = + unsigned long i, num_pages = PAGE_ALIGN(size) / PAGE_SIZE; struct drm_agp_mem *agpmem; struct page **page_map; + struct page **phys_page_map; void *addr; size = PAGE_ALIGN(size); @@ -112,10 +90,9 @@ static void *agp_remap(unsigned long offset, unsigned long size, if (!page_map) return NULL; - phys_addr_map = - agpmem->memory->memory + (offset - agpmem->bound) / PAGE_SIZE; + phys_page_map = (agpmem->memory->pages + (offset - agpmem->bound) / PAGE_SIZE); for (i = 0; i < num_pages; ++i) - page_map[i] = pfn_to_page(phys_addr_map[i] >> PAGE_SHIFT); + page_map[i] = phys_page_map[i]; addr = vmap(page_map, num_pages, VM_IOREMAP, PAGE_AGP); vfree(page_map); @@ -157,8 +134,6 @@ static inline void *agp_remap(unsigned long offset, unsigned long size, #endif /* agp */ -#endif /* debug_memory */ - void drm_core_ioremap(struct drm_local_map *map, struct drm_device *dev) { if (drm_core_has_AGP(dev) && diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c index 367c590ffbba..3e47869d6dae 100644 --- a/drivers/gpu/drm/drm_mm.c +++ b/drivers/gpu/drm/drm_mm.c @@ -42,8 +42,11 @@ */ #include "drmP.h" +#include "drm_mm.h" #include +#define MM_UNUSED_TARGET 4 + unsigned long drm_mm_tail_space(struct drm_mm *mm) { struct list_head *tail_node; @@ -74,16 +77,62 @@ int drm_mm_remove_space_from_tail(struct drm_mm *mm, unsigned long size) return 0; } - -static int drm_mm_create_tail_node(struct drm_mm *mm, - unsigned long start, - unsigned long size) +static struct drm_mm_node *drm_mm_kmalloc(struct drm_mm *mm, int atomic) { struct drm_mm_node *child; - child = (struct drm_mm_node *) - drm_alloc(sizeof(*child), DRM_MEM_MM); - if (!child) + if (atomic) + child = kmalloc(sizeof(*child), GFP_ATOMIC); + else + child = kmalloc(sizeof(*child), GFP_KERNEL); + + if (unlikely(child == NULL)) { + spin_lock(&mm->unused_lock); + if (list_empty(&mm->unused_nodes)) + child = NULL; + else { + child = + list_entry(mm->unused_nodes.next, + struct drm_mm_node, fl_entry); + list_del(&child->fl_entry); + --mm->num_unused; + } + spin_unlock(&mm->unused_lock); + } + return child; +} + +int drm_mm_pre_get(struct drm_mm *mm) +{ + struct drm_mm_node *node; + + spin_lock(&mm->unused_lock); + while (mm->num_unused < MM_UNUSED_TARGET) { + spin_unlock(&mm->unused_lock); + node = kmalloc(sizeof(*node), GFP_KERNEL); + spin_lock(&mm->unused_lock); + + if (unlikely(node == NULL)) { + int ret = (mm->num_unused < 2) ? -ENOMEM : 0; + spin_unlock(&mm->unused_lock); + return ret; + } + ++mm->num_unused; + list_add_tail(&node->fl_entry, &mm->unused_nodes); + } + spin_unlock(&mm->unused_lock); + return 0; +} +EXPORT_SYMBOL(drm_mm_pre_get); + +static int drm_mm_create_tail_node(struct drm_mm *mm, + unsigned long start, + unsigned long size, int atomic) +{ + struct drm_mm_node *child; + + child = drm_mm_kmalloc(mm, atomic); + if (unlikely(child == NULL)) return -ENOMEM; child->free = 1; @@ -97,8 +146,7 @@ static int drm_mm_create_tail_node(struct drm_mm *mm, return 0; } - -int drm_mm_add_space_to_tail(struct drm_mm *mm, unsigned long size) +int drm_mm_add_space_to_tail(struct drm_mm *mm, unsigned long size, int atomic) { struct list_head *tail_node; struct drm_mm_node *entry; @@ -106,20 +154,21 @@ int drm_mm_add_space_to_tail(struct drm_mm *mm, unsigned long size) tail_node = mm->ml_entry.prev; entry = list_entry(tail_node, struct drm_mm_node, ml_entry); if (!entry->free) { - return drm_mm_create_tail_node(mm, entry->start + entry->size, size); + return drm_mm_create_tail_node(mm, entry->start + entry->size, + size, atomic); } entry->size += size; return 0; } static struct drm_mm_node *drm_mm_split_at_start(struct drm_mm_node *parent, - unsigned long size) + unsigned long size, + int atomic) { struct drm_mm_node *child; - child = (struct drm_mm_node *) - drm_alloc(sizeof(*child), DRM_MEM_MM); - if (!child) + child = drm_mm_kmalloc(parent->mm, atomic); + if (unlikely(child == NULL)) return NULL; INIT_LIST_HEAD(&child->fl_entry); @@ -138,45 +187,45 @@ static struct drm_mm_node *drm_mm_split_at_start(struct drm_mm_node *parent, } - -struct drm_mm_node *drm_mm_get_block(struct drm_mm_node * parent, - unsigned long size, unsigned alignment) +struct drm_mm_node *drm_mm_get_block_generic(struct drm_mm_node *node, + unsigned long size, + unsigned alignment, + int atomic) { struct drm_mm_node *align_splitoff = NULL; - struct drm_mm_node *child; unsigned tmp = 0; if (alignment) - tmp = parent->start % alignment; + tmp = node->start % alignment; if (tmp) { - align_splitoff = drm_mm_split_at_start(parent, alignment - tmp); - if (!align_splitoff) + align_splitoff = + drm_mm_split_at_start(node, alignment - tmp, atomic); + if (unlikely(align_splitoff == NULL)) return NULL; } - if (parent->size == size) { - list_del_init(&parent->fl_entry); - parent->free = 0; - return parent; + if (node->size == size) { + list_del_init(&node->fl_entry); + node->free = 0; } else { - child = drm_mm_split_at_start(parent, size); + node = drm_mm_split_at_start(node, size, atomic); } if (align_splitoff) drm_mm_put_block(align_splitoff); - return child; + return node; } -EXPORT_SYMBOL(drm_mm_get_block); +EXPORT_SYMBOL(drm_mm_get_block_generic); /* * Put a block. Merge with the previous and / or next block if they are free. * Otherwise add to the free stack. */ -void drm_mm_put_block(struct drm_mm_node * cur) +void drm_mm_put_block(struct drm_mm_node *cur) { struct drm_mm *mm = cur->mm; @@ -188,21 +237,27 @@ void drm_mm_put_block(struct drm_mm_node * cur) int merged = 0; if (cur_head->prev != root_head) { - prev_node = list_entry(cur_head->prev, struct drm_mm_node, ml_entry); + prev_node = + list_entry(cur_head->prev, struct drm_mm_node, ml_entry); if (prev_node->free) { prev_node->size += cur->size; merged = 1; } } if (cur_head->next != root_head) { - next_node = list_entry(cur_head->next, struct drm_mm_node, ml_entry); + next_node = + list_entry(cur_head->next, struct drm_mm_node, ml_entry); if (next_node->free) { if (merged) { prev_node->size += next_node->size; list_del(&next_node->ml_entry); list_del(&next_node->fl_entry); - drm_free(next_node, sizeof(*next_node), - DRM_MEM_MM); + if (mm->num_unused < MM_UNUSED_TARGET) { + list_add(&next_node->fl_entry, + &mm->unused_nodes); + ++mm->num_unused; + } else + kfree(next_node); } else { next_node->size += cur->size; next_node->start = cur->start; @@ -215,14 +270,19 @@ void drm_mm_put_block(struct drm_mm_node * cur) list_add(&cur->fl_entry, &mm->fl_entry); } else { list_del(&cur->ml_entry); - drm_free(cur, sizeof(*cur), DRM_MEM_MM); + if (mm->num_unused < MM_UNUSED_TARGET) { + list_add(&cur->fl_entry, &mm->unused_nodes); + ++mm->num_unused; + } else + kfree(cur); } } + EXPORT_SYMBOL(drm_mm_put_block); -struct drm_mm_node *drm_mm_search_free(const struct drm_mm * mm, - unsigned long size, - unsigned alignment, int best_match) +struct drm_mm_node *drm_mm_search_free(const struct drm_mm *mm, + unsigned long size, + unsigned alignment, int best_match) { struct list_head *list; const struct list_head *free_stack = &mm->fl_entry; @@ -247,7 +307,6 @@ struct drm_mm_node *drm_mm_search_free(const struct drm_mm * mm, wasted += alignment - tmp; } - if (entry->size >= size + wasted) { if (!best_match) return entry; @@ -260,6 +319,7 @@ struct drm_mm_node *drm_mm_search_free(const struct drm_mm * mm, return best; } +EXPORT_SYMBOL(drm_mm_search_free); int drm_mm_clean(struct drm_mm * mm) { @@ -267,14 +327,17 @@ int drm_mm_clean(struct drm_mm * mm) return (head->next->next == head); } -EXPORT_SYMBOL(drm_mm_search_free); +EXPORT_SYMBOL(drm_mm_clean); int drm_mm_init(struct drm_mm * mm, unsigned long start, unsigned long size) { INIT_LIST_HEAD(&mm->ml_entry); INIT_LIST_HEAD(&mm->fl_entry); + INIT_LIST_HEAD(&mm->unused_nodes); + mm->num_unused = 0; + spin_lock_init(&mm->unused_lock); - return drm_mm_create_tail_node(mm, start, size); + return drm_mm_create_tail_node(mm, start, size, 0); } EXPORT_SYMBOL(drm_mm_init); @@ -282,6 +345,7 @@ void drm_mm_takedown(struct drm_mm * mm) { struct list_head *bnode = mm->fl_entry.next; struct drm_mm_node *entry; + struct drm_mm_node *next; entry = list_entry(bnode, struct drm_mm_node, fl_entry); @@ -293,7 +357,16 @@ void drm_mm_takedown(struct drm_mm * mm) list_del(&entry->fl_entry); list_del(&entry->ml_entry); + kfree(entry); - drm_free(entry, sizeof(*entry), DRM_MEM_MM); + spin_lock(&mm->unused_lock); + list_for_each_entry_safe(entry, next, &mm->unused_nodes, fl_entry) { + list_del(&entry->fl_entry); + kfree(entry); + --mm->num_unused; + } + spin_unlock(&mm->unused_lock); + + BUG_ON(mm->num_unused != 0); } EXPORT_SYMBOL(drm_mm_takedown); diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index c9b80fdd4630..54f492a488a9 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -38,6 +38,7 @@ #include "drm.h" #include "drm_crtc.h" +#define DRM_MODESET_DEBUG "drm_mode" /** * drm_mode_debug_printmodeline - debug print a mode * @dev: DRM device @@ -50,12 +51,13 @@ */ void drm_mode_debug_printmodeline(struct drm_display_mode *mode) { - DRM_DEBUG("Modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n", - mode->base.id, mode->name, mode->vrefresh, mode->clock, - mode->hdisplay, mode->hsync_start, - mode->hsync_end, mode->htotal, - mode->vdisplay, mode->vsync_start, - mode->vsync_end, mode->vtotal, mode->type, mode->flags); + DRM_DEBUG_MODE(DRM_MODESET_DEBUG, + "Modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n", + mode->base.id, mode->name, mode->vrefresh, mode->clock, + mode->hdisplay, mode->hsync_start, + mode->hsync_end, mode->htotal, + mode->vdisplay, mode->vsync_start, + mode->vsync_end, mode->vtotal, mode->type, mode->flags); } EXPORT_SYMBOL(drm_mode_debug_printmodeline); @@ -401,7 +403,9 @@ void drm_mode_prune_invalid(struct drm_device *dev, list_del(&mode->head); if (verbose) { drm_mode_debug_printmodeline(mode); - DRM_DEBUG("Not using %s mode %d\n", mode->name, mode->status); + DRM_DEBUG_MODE(DRM_MODESET_DEBUG, + "Not using %s mode %d\n", + mode->name, mode->status); } drm_mode_destroy(dev, mode); } diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c index b55d5bc6ea61..577094fb1995 100644 --- a/drivers/gpu/drm/drm_pci.c +++ b/drivers/gpu/drm/drm_pci.c @@ -55,17 +55,6 @@ drm_dma_handle_t *drm_pci_alloc(struct drm_device * dev, size_t size, size_t ali unsigned long addr; size_t sz; #endif -#ifdef DRM_DEBUG_MEMORY - int area = DRM_MEM_DMA; - - spin_lock(&drm_mem_lock); - if ((drm_ram_used >> PAGE_SHIFT) - > (DRM_RAM_PERCENT * drm_ram_available) / 100) { - spin_unlock(&drm_mem_lock); - return 0; - } - spin_unlock(&drm_mem_lock); -#endif /* pci_alloc_consistent only guarantees alignment to the smallest * PAGE_SIZE order which is greater than or equal to the requested size. @@ -86,26 +75,10 @@ drm_dma_handle_t *drm_pci_alloc(struct drm_device * dev, size_t size, size_t ali dmah->size = size; dmah->vaddr = dma_alloc_coherent(&dev->pdev->dev, size, &dmah->busaddr, GFP_KERNEL | __GFP_COMP); -#ifdef DRM_DEBUG_MEMORY - if (dmah->vaddr == NULL) { - spin_lock(&drm_mem_lock); - ++drm_mem_stats[area].fail_count; - spin_unlock(&drm_mem_lock); - kfree(dmah); - return NULL; - } - - spin_lock(&drm_mem_lock); - ++drm_mem_stats[area].succeed_count; - drm_mem_stats[area].bytes_allocated += size; - drm_ram_used += size; - spin_unlock(&drm_mem_lock); -#else if (dmah->vaddr == NULL) { kfree(dmah); return NULL; } -#endif memset(dmah->vaddr, 0, size); @@ -132,17 +105,8 @@ void __drm_pci_free(struct drm_device * dev, drm_dma_handle_t * dmah) unsigned long addr; size_t sz; #endif -#ifdef DRM_DEBUG_MEMORY - int area = DRM_MEM_DMA; - int alloc_count; - int free_count; -#endif - if (!dmah->vaddr) { -#ifdef DRM_DEBUG_MEMORY - DRM_MEM_ERROR(area, "Attempt to free address 0\n"); -#endif - } else { + if (dmah->vaddr) { /* XXX - Is virt_to_page() legal for consistent mem? */ /* Unreserve */ for (addr = (unsigned long)dmah->vaddr, sz = dmah->size; @@ -152,21 +116,6 @@ void __drm_pci_free(struct drm_device * dev, drm_dma_handle_t * dmah) dma_free_coherent(&dev->pdev->dev, dmah->size, dmah->vaddr, dmah->busaddr); } - -#ifdef DRM_DEBUG_MEMORY - spin_lock(&drm_mem_lock); - free_count = ++drm_mem_stats[area].free_count; - alloc_count = drm_mem_stats[area].succeed_count; - drm_mem_stats[area].bytes_freed += size; - drm_ram_used -= size; - spin_unlock(&drm_mem_lock); - if (free_count > alloc_count) { - DRM_MEM_ERROR(area, - "Excess frees: %d frees, %d allocs\n", - free_count, alloc_count); - } -#endif - } /** diff --git a/drivers/gpu/drm/drm_proc.c b/drivers/gpu/drm/drm_proc.c index bae5391165ac..bbd4b3d1074a 100644 --- a/drivers/gpu/drm/drm_proc.c +++ b/drivers/gpu/drm/drm_proc.c @@ -105,13 +105,12 @@ int drm_proc_create_files(struct drm_info_list *files, int count, (dev->driver->driver_features & features) != features) continue; - tmp = drm_alloc(sizeof(struct drm_info_node), _DRM_DRIVER); + tmp = kmalloc(sizeof(struct drm_info_node), GFP_KERNEL); ent = create_proc_entry(files[i].name, S_IFREG | S_IRUGO, root); if (!ent) { DRM_ERROR("Cannot create /proc/dri/%s/%s\n", name, files[i].name); - drm_free(tmp, sizeof(struct drm_info_node), - _DRM_DRIVER); + kfree(tmp); ret = -1; goto fail; } @@ -192,8 +191,7 @@ int drm_proc_remove_files(struct drm_info_list *files, int count, remove_proc_entry(files[i].name, minor->proc_root); list_del(pos); - drm_free(tmp, sizeof(struct drm_info_node), - _DRM_DRIVER); + kfree(tmp); } } } diff --git a/drivers/gpu/drm/drm_scatter.c b/drivers/gpu/drm/drm_scatter.c index b2b0f3d41714..c7823c863d4f 100644 --- a/drivers/gpu/drm/drm_scatter.c +++ b/drivers/gpu/drm/drm_scatter.c @@ -58,11 +58,9 @@ void drm_sg_cleanup(struct drm_sg_mem * entry) vfree(entry->virtual); - drm_free(entry->busaddr, - entry->pages * sizeof(*entry->busaddr), DRM_MEM_PAGES); - drm_free(entry->pagelist, - entry->pages * sizeof(*entry->pagelist), DRM_MEM_PAGES); - drm_free(entry, sizeof(*entry), DRM_MEM_SGLISTS); + kfree(entry->busaddr); + kfree(entry->pagelist); + kfree(entry); } #ifdef _LP64 @@ -84,7 +82,7 @@ int drm_sg_alloc(struct drm_device *dev, struct drm_scatter_gather * request) if (dev->sg) return -EINVAL; - entry = drm_alloc(sizeof(*entry), DRM_MEM_SGLISTS); + entry = kmalloc(sizeof(*entry), GFP_KERNEL); if (!entry) return -ENOMEM; @@ -93,34 +91,27 @@ int drm_sg_alloc(struct drm_device *dev, struct drm_scatter_gather * request) DRM_DEBUG("size=%ld pages=%ld\n", request->size, pages); entry->pages = pages; - entry->pagelist = drm_alloc(pages * sizeof(*entry->pagelist), - DRM_MEM_PAGES); + entry->pagelist = kmalloc(pages * sizeof(*entry->pagelist), GFP_KERNEL); if (!entry->pagelist) { - drm_free(entry, sizeof(*entry), DRM_MEM_SGLISTS); + kfree(entry); return -ENOMEM; } memset(entry->pagelist, 0, pages * sizeof(*entry->pagelist)); - entry->busaddr = drm_alloc(pages * sizeof(*entry->busaddr), - DRM_MEM_PAGES); + entry->busaddr = kmalloc(pages * sizeof(*entry->busaddr), GFP_KERNEL); if (!entry->busaddr) { - drm_free(entry->pagelist, - entry->pages * sizeof(*entry->pagelist), - DRM_MEM_PAGES); - drm_free(entry, sizeof(*entry), DRM_MEM_SGLISTS); + kfree(entry->pagelist); + kfree(entry); return -ENOMEM; } memset((void *)entry->busaddr, 0, pages * sizeof(*entry->busaddr)); entry->virtual = drm_vmalloc_dma(pages << PAGE_SHIFT); if (!entry->virtual) { - drm_free(entry->busaddr, - entry->pages * sizeof(*entry->busaddr), DRM_MEM_PAGES); - drm_free(entry->pagelist, - entry->pages * sizeof(*entry->pagelist), - DRM_MEM_PAGES); - drm_free(entry, sizeof(*entry), DRM_MEM_SGLISTS); + kfree(entry->busaddr); + kfree(entry->pagelist); + kfree(entry); return -ENOMEM; } diff --git a/drivers/gpu/drm/drm_sman.c b/drivers/gpu/drm/drm_sman.c index 926f146390ce..463aed9403db 100644 --- a/drivers/gpu/drm/drm_sman.c +++ b/drivers/gpu/drm/drm_sman.c @@ -48,9 +48,7 @@ void drm_sman_takedown(struct drm_sman * sman) { drm_ht_remove(&sman->user_hash_tab); drm_ht_remove(&sman->owner_hash_tab); - if (sman->mm) - drm_free(sman->mm, sman->num_managers * sizeof(*sman->mm), - DRM_MEM_MM); + kfree(sman->mm); } EXPORT_SYMBOL(drm_sman_takedown); @@ -61,8 +59,9 @@ drm_sman_init(struct drm_sman * sman, unsigned int num_managers, { int ret = 0; - sman->mm = (struct drm_sman_mm *) drm_calloc(num_managers, sizeof(*sman->mm), - DRM_MEM_MM); + sman->mm = (struct drm_sman_mm *) kcalloc(num_managers, + sizeof(*sman->mm), + GFP_KERNEL); if (!sman->mm) { ret = -ENOMEM; goto out; @@ -78,7 +77,7 @@ drm_sman_init(struct drm_sman * sman, unsigned int num_managers, drm_ht_remove(&sman->owner_hash_tab); out1: - drm_free(sman->mm, num_managers * sizeof(*sman->mm), DRM_MEM_MM); + kfree(sman->mm); out: return ret; } @@ -110,7 +109,7 @@ static void drm_sman_mm_destroy(void *private) { struct drm_mm *mm = (struct drm_mm *) private; drm_mm_takedown(mm); - drm_free(mm, sizeof(*mm), DRM_MEM_MM); + kfree(mm); } static unsigned long drm_sman_mm_offset(void *private, void *ref) @@ -130,7 +129,7 @@ drm_sman_set_range(struct drm_sman * sman, unsigned int manager, BUG_ON(manager >= sman->num_managers); sman_mm = &sman->mm[manager]; - mm = drm_calloc(1, sizeof(*mm), DRM_MEM_MM); + mm = kzalloc(sizeof(*mm), GFP_KERNEL); if (!mm) { return -ENOMEM; } @@ -138,7 +137,7 @@ drm_sman_set_range(struct drm_sman * sman, unsigned int manager, ret = drm_mm_init(mm, start, size); if (ret) { - drm_free(mm, sizeof(*mm), DRM_MEM_MM); + kfree(mm); return ret; } @@ -176,7 +175,7 @@ static struct drm_owner_item *drm_sman_get_owner_item(struct drm_sman * sman, owner_hash); } - owner_item = drm_calloc(1, sizeof(*owner_item), DRM_MEM_MM); + owner_item = kzalloc(sizeof(*owner_item), GFP_KERNEL); if (!owner_item) goto out; @@ -189,7 +188,7 @@ static struct drm_owner_item *drm_sman_get_owner_item(struct drm_sman * sman, return owner_item; out1: - drm_free(owner_item, sizeof(*owner_item), DRM_MEM_MM); + kfree(owner_item); out: return NULL; } @@ -212,7 +211,7 @@ struct drm_memblock_item *drm_sman_alloc(struct drm_sman *sman, unsigned int man return NULL; } - memblock = drm_calloc(1, sizeof(*memblock), DRM_MEM_MM); + memblock = kzalloc(sizeof(*memblock), GFP_KERNEL); if (!memblock) goto out; @@ -237,7 +236,7 @@ struct drm_memblock_item *drm_sman_alloc(struct drm_sman *sman, unsigned int man out2: drm_ht_remove_item(&sman->user_hash_tab, &memblock->user_hash); out1: - drm_free(memblock, sizeof(*memblock), DRM_MEM_MM); + kfree(memblock); out: sman_mm->free(sman_mm->private, tmp); @@ -253,7 +252,7 @@ static void drm_sman_free(struct drm_memblock_item *item) list_del(&item->owner_list); drm_ht_remove_item(&sman->user_hash_tab, &item->user_hash); item->mm->free(item->mm->private, item->mm_info); - drm_free(item, sizeof(*item), DRM_MEM_MM); + kfree(item); } int drm_sman_free_key(struct drm_sman *sman, unsigned int key) @@ -277,7 +276,7 @@ static void drm_sman_remove_owner(struct drm_sman *sman, { list_del(&owner_item->sman_list); drm_ht_remove_item(&sman->owner_hash_tab, &owner_item->owner_hash); - drm_free(owner_item, sizeof(*owner_item), DRM_MEM_MM); + kfree(owner_item); } int drm_sman_owner_clean(struct drm_sman *sman, unsigned long owner) diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c index b9631e3a1ea6..155a5bbce680 100644 --- a/drivers/gpu/drm/drm_stub.c +++ b/drivers/gpu/drm/drm_stub.c @@ -51,7 +51,22 @@ struct idr drm_minors_idr; struct class *drm_class; struct proc_dir_entry *drm_proc_root; struct dentry *drm_debugfs_root; +void drm_ut_debug_printk(unsigned int request_level, + const char *prefix, + const char *function_name, + const char *format, ...) +{ + va_list args; + if (drm_debug & request_level) { + if (function_name) + printk(KERN_DEBUG "[%s:%s], ", prefix, function_name); + va_start(args, format); + vprintk(format, args); + va_end(args); + } +} +EXPORT_SYMBOL(drm_ut_debug_printk); static int drm_minor_get_id(struct drm_device *dev, int type) { int new_id; @@ -92,7 +107,7 @@ struct drm_master *drm_master_create(struct drm_minor *minor) { struct drm_master *master; - master = drm_calloc(1, sizeof(*master), DRM_MEM_DRIVER); + master = kzalloc(sizeof(*master), GFP_KERNEL); if (!master) return NULL; @@ -134,7 +149,7 @@ static void drm_master_destroy(struct kref *kref) } if (master->unique) { - drm_free(master->unique, master->unique_size, DRM_MEM_DRIVER); + kfree(master->unique); master->unique = NULL; master->unique_len = 0; } @@ -142,12 +157,12 @@ static void drm_master_destroy(struct kref *kref) list_for_each_entry_safe(pt, next, &master->magicfree, head) { list_del(&pt->head); drm_ht_remove_item(&master->magiclist, &pt->hash_item); - drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC); + kfree(pt); } drm_ht_remove(&master->magiclist); - drm_free(master, sizeof(*master), DRM_MEM_DRIVER); + kfree(master); } void drm_master_put(struct drm_master **master) @@ -328,7 +343,7 @@ static int drm_get_minor(struct drm_device *dev, struct drm_minor **minor, int t #if defined(CONFIG_DEBUG_FS) ret = drm_debugfs_init(new_minor, minor_id, drm_debugfs_root); if (ret) { - DRM_ERROR("DRM: Failed to initialize /debugfs/dri.\n"); + DRM_ERROR("DRM: Failed to initialize /sys/kernel/debug/dri.\n"); goto err_g2; } #endif @@ -375,7 +390,7 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, DRM_DEBUG("\n"); - dev = drm_calloc(1, sizeof(*dev), DRM_MEM_STUB); + dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; @@ -428,7 +443,7 @@ err_g3: err_g2: pci_disable_device(pdev); err_g1: - drm_free(dev, sizeof(*dev), DRM_MEM_STUB); + kfree(dev); return ret; } EXPORT_SYMBOL(drm_get_dev); @@ -501,7 +516,7 @@ void drm_put_dev(struct drm_device *dev) dev->driver->unload(dev); if (drm_core_has_AGP(dev) && dev->agp) { - drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS); + kfree(dev->agp); dev->agp = NULL; } @@ -520,10 +535,9 @@ void drm_put_dev(struct drm_device *dev) drm_put_minor(&dev->primary); if (dev->devname) { - drm_free(dev->devname, strlen(dev->devname) + 1, - DRM_MEM_DRIVER); + kfree(dev->devname); dev->devname = NULL; } - drm_free(dev, sizeof(*dev), DRM_MEM_STUB); + kfree(dev); } EXPORT_SYMBOL(drm_put_dev); diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c index 9987ab880835..85ec31b3ff00 100644 --- a/drivers/gpu/drm/drm_sysfs.c +++ b/drivers/gpu/drm/drm_sysfs.c @@ -70,6 +70,11 @@ static ssize_t version_show(struct class *dev, char *buf) CORE_MINOR, CORE_PATCHLEVEL, CORE_DATE); } +static char *drm_nodename(struct device *dev) +{ + return kasprintf(GFP_KERNEL, "dri/%s", dev_name(dev)); +} + static CLASS_ATTR(version, S_IRUGO, version_show, NULL); /** @@ -101,6 +106,8 @@ struct class *drm_sysfs_create(struct module *owner, char *name) if (err) goto err_out_class; + class->nodename = drm_nodename; + return class; err_out_class: diff --git a/drivers/gpu/drm/drm_vm.c b/drivers/gpu/drm/drm_vm.c index 22f76567ac7d..7e1fbe5d4779 100644 --- a/drivers/gpu/drm/drm_vm.c +++ b/drivers/gpu/drm/drm_vm.c @@ -144,14 +144,14 @@ static int drm_do_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) * Get the page, inc the use count, and return it */ offset = (baddr - agpmem->bound) >> PAGE_SHIFT; - page = virt_to_page(__va(agpmem->memory->memory[offset])); + page = agpmem->memory->pages[offset]; get_page(page); vmf->page = page; DRM_DEBUG ("baddr = 0x%llx page = 0x%p, offset = 0x%llx, count=%d\n", (unsigned long long)baddr, - __va(agpmem->memory->memory[offset]), + agpmem->memory->pages[offset], (unsigned long long)offset, page_count(page)); return 0; @@ -227,7 +227,7 @@ static void drm_vm_shm_close(struct vm_area_struct *vma) found_maps++; if (pt->vma == vma) { list_del(&pt->head); - drm_free(pt, sizeof(*pt), DRM_MEM_VMAS); + kfree(pt); } } @@ -273,7 +273,7 @@ static void drm_vm_shm_close(struct vm_area_struct *vma) DRM_ERROR("tried to rmmap GEM object\n"); break; } - drm_free(map, sizeof(*map), DRM_MEM_MAPS); + kfree(map); } } mutex_unlock(&dev->struct_mutex); @@ -414,7 +414,7 @@ void drm_vm_open_locked(struct vm_area_struct *vma) vma->vm_start, vma->vm_end - vma->vm_start); atomic_inc(&dev->vma_count); - vma_entry = drm_alloc(sizeof(*vma_entry), DRM_MEM_VMAS); + vma_entry = kmalloc(sizeof(*vma_entry), GFP_KERNEL); if (vma_entry) { vma_entry->vma = vma; vma_entry->pid = current->pid; @@ -454,7 +454,7 @@ static void drm_vm_close(struct vm_area_struct *vma) list_for_each_entry_safe(pt, temp, &dev->vmalist, head) { if (pt->vma == vma) { list_del(&pt->head); - drm_free(pt, sizeof(*pt), DRM_MEM_VMAS); + kfree(pt); break; } } diff --git a/drivers/gpu/drm/i810/i810_dma.c b/drivers/gpu/drm/i810/i810_dma.c index e5de8ea41544..7d1d88cdf2dc 100644 --- a/drivers/gpu/drm/i810/i810_dma.c +++ b/drivers/gpu/drm/i810/i810_dma.c @@ -227,8 +227,7 @@ static int i810_dma_cleanup(struct drm_device * dev) /* Need to rewrite hardware status page */ I810_WRITE(0x02080, 0x1ffff000); } - drm_free(dev->dev_private, sizeof(drm_i810_private_t), - DRM_MEM_DRIVER); + kfree(dev->dev_private); dev->dev_private = NULL; for (i = 0; i < dma->buf_count; i++) { @@ -439,8 +438,7 @@ static int i810_dma_init(struct drm_device *dev, void *data, switch (init->func) { case I810_INIT_DMA_1_4: DRM_INFO("Using v1.4 init.\n"); - dev_priv = drm_alloc(sizeof(drm_i810_private_t), - DRM_MEM_DRIVER); + dev_priv = kmalloc(sizeof(drm_i810_private_t), GFP_KERNEL); if (dev_priv == NULL) return -ENOMEM; retcode = i810_dma_initialize(dev, dev_priv, init); diff --git a/drivers/gpu/drm/i830/i830_dma.c b/drivers/gpu/drm/i830/i830_dma.c index a86ab30b4620..877bf6cb14a4 100644 --- a/drivers/gpu/drm/i830/i830_dma.c +++ b/drivers/gpu/drm/i830/i830_dma.c @@ -232,8 +232,7 @@ static int i830_dma_cleanup(struct drm_device * dev) I830_WRITE(0x02080, 0x1ffff000); } - drm_free(dev->dev_private, sizeof(drm_i830_private_t), - DRM_MEM_DRIVER); + kfree(dev->dev_private); dev->dev_private = NULL; for (i = 0; i < dma->buf_count; i++) { @@ -459,8 +458,7 @@ static int i830_dma_init(struct drm_device *dev, void *data, switch (init->func) { case I830_INIT_DMA: - dev_priv = drm_alloc(sizeof(drm_i830_private_t), - DRM_MEM_DRIVER); + dev_priv = kmalloc(sizeof(drm_i830_private_t), GFP_KERNEL); if (dev_priv == NULL) return -ENOMEM; retcode = i830_dma_initialize(dev, dev_priv, init); diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 0ccb63ee50ee..f112c769d533 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -33,6 +33,8 @@ #include "i915_drm.h" #include "i915_drv.h" +#define I915_DRV "i915_drv" + /* Really want an OS-independent resettable timer. Would like to have * this loop run for (eg) 3 sec, but have the timer reset every time * the head pointer changes, so that EBUSY only happens if the ring @@ -99,7 +101,7 @@ static int i915_init_phys_hws(struct drm_device *dev) memset(dev_priv->hw_status_page, 0, PAGE_SIZE); I915_WRITE(HWS_PGA, dev_priv->dma_status_page); - DRM_DEBUG("Enabled hardware status page\n"); + DRM_DEBUG_DRIVER(I915_DRV, "Enabled hardware status page\n"); return 0; } @@ -185,7 +187,8 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init) master_priv->sarea_priv = (drm_i915_sarea_t *) ((u8 *)master_priv->sarea->handle + init->sarea_priv_offset); } else { - DRM_DEBUG("sarea not found assuming DRI2 userspace\n"); + DRM_DEBUG_DRIVER(I915_DRV, + "sarea not found assuming DRI2 userspace\n"); } if (init->ring_size != 0) { @@ -235,7 +238,7 @@ static int i915_dma_resume(struct drm_device * dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - DRM_DEBUG("%s\n", __func__); + DRM_DEBUG_DRIVER(I915_DRV, "%s\n", __func__); if (dev_priv->ring.map.handle == NULL) { DRM_ERROR("can not ioremap virtual address for" @@ -248,13 +251,14 @@ static int i915_dma_resume(struct drm_device * dev) DRM_ERROR("Can not find hardware status page\n"); return -EINVAL; } - DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page); + DRM_DEBUG_DRIVER(I915_DRV, "hw status page @ %p\n", + dev_priv->hw_status_page); if (dev_priv->status_gfx_addr != 0) I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr); else I915_WRITE(HWS_PGA, dev_priv->dma_status_page); - DRM_DEBUG("Enabled hardware status page\n"); + DRM_DEBUG_DRIVER(I915_DRV, "Enabled hardware status page\n"); return 0; } @@ -548,10 +552,10 @@ static int i915_dispatch_flip(struct drm_device * dev) if (!master_priv->sarea_priv) return -EINVAL; - DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n", - __func__, - dev_priv->current_page, - master_priv->sarea_priv->pf_current_page); + DRM_DEBUG_DRIVER(I915_DRV, "%s: page=%d pfCurrentPage=%d\n", + __func__, + dev_priv->current_page, + master_priv->sarea_priv->pf_current_page); i915_kernel_lost_context(dev); @@ -629,8 +633,9 @@ static int i915_batchbuffer(struct drm_device *dev, void *data, return -EINVAL; } - DRM_DEBUG("i915 batchbuffer, start %x used %d cliprects %d\n", - batch->start, batch->used, batch->num_cliprects); + DRM_DEBUG_DRIVER(I915_DRV, + "i915 batchbuffer, start %x used %d cliprects %d\n", + batch->start, batch->used, batch->num_cliprects); RING_LOCK_TEST_WITH_RETURN(dev, file_priv); @@ -638,9 +643,9 @@ static int i915_batchbuffer(struct drm_device *dev, void *data, return -EINVAL; if (batch->num_cliprects) { - cliprects = drm_calloc(batch->num_cliprects, - sizeof(struct drm_clip_rect), - DRM_MEM_DRIVER); + cliprects = kcalloc(batch->num_cliprects, + sizeof(struct drm_clip_rect), + GFP_KERNEL); if (cliprects == NULL) return -ENOMEM; @@ -659,9 +664,7 @@ static int i915_batchbuffer(struct drm_device *dev, void *data, sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); fail_free: - drm_free(cliprects, - batch->num_cliprects * sizeof(struct drm_clip_rect), - DRM_MEM_DRIVER); + kfree(cliprects); return ret; } @@ -678,15 +681,16 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data, void *batch_data; int ret; - DRM_DEBUG("i915 cmdbuffer, buf %p sz %d cliprects %d\n", - cmdbuf->buf, cmdbuf->sz, cmdbuf->num_cliprects); + DRM_DEBUG_DRIVER(I915_DRV, + "i915 cmdbuffer, buf %p sz %d cliprects %d\n", + cmdbuf->buf, cmdbuf->sz, cmdbuf->num_cliprects); RING_LOCK_TEST_WITH_RETURN(dev, file_priv); if (cmdbuf->num_cliprects < 0) return -EINVAL; - batch_data = drm_alloc(cmdbuf->sz, DRM_MEM_DRIVER); + batch_data = kmalloc(cmdbuf->sz, GFP_KERNEL); if (batch_data == NULL) return -ENOMEM; @@ -695,9 +699,8 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data, goto fail_batch_free; if (cmdbuf->num_cliprects) { - cliprects = drm_calloc(cmdbuf->num_cliprects, - sizeof(struct drm_clip_rect), - DRM_MEM_DRIVER); + cliprects = kcalloc(cmdbuf->num_cliprects, + sizeof(struct drm_clip_rect), GFP_KERNEL); if (cliprects == NULL) goto fail_batch_free; @@ -720,11 +723,9 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data, sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); fail_clip_free: - drm_free(cliprects, - cmdbuf->num_cliprects * sizeof(struct drm_clip_rect), - DRM_MEM_DRIVER); + kfree(cliprects); fail_batch_free: - drm_free(batch_data, cmdbuf->sz, DRM_MEM_DRIVER); + kfree(batch_data); return ret; } @@ -734,7 +735,7 @@ static int i915_flip_bufs(struct drm_device *dev, void *data, { int ret; - DRM_DEBUG("%s\n", __func__); + DRM_DEBUG_DRIVER(I915_DRV, "%s\n", __func__); RING_LOCK_TEST_WITH_RETURN(dev, file_priv); @@ -777,7 +778,8 @@ static int i915_getparam(struct drm_device *dev, void *data, value = dev_priv->num_fence_regs - dev_priv->fence_reg_start; break; default: - DRM_DEBUG("Unknown parameter %d\n", param->param); + DRM_DEBUG_DRIVER(I915_DRV, "Unknown parameter %d\n", + param->param); return -EINVAL; } @@ -817,7 +819,8 @@ static int i915_setparam(struct drm_device *dev, void *data, dev_priv->fence_reg_start = param->value; break; default: - DRM_DEBUG("unknown parameter %d\n", param->param); + DRM_DEBUG_DRIVER(I915_DRV, "unknown parameter %d\n", + param->param); return -EINVAL; } @@ -865,9 +868,10 @@ static int i915_set_status_page(struct drm_device *dev, void *data, memset(dev_priv->hw_status_page, 0, PAGE_SIZE); I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr); - DRM_DEBUG("load hws HWS_PGA with gfx mem 0x%x\n", - dev_priv->status_gfx_addr); - DRM_DEBUG("load hws at %p\n", dev_priv->hw_status_page); + DRM_DEBUG_DRIVER(I915_DRV, "load hws HWS_PGA with gfx mem 0x%x\n", + dev_priv->status_gfx_addr); + DRM_DEBUG_DRIVER(I915_DRV, "load hws at %p\n", + dev_priv->hw_status_page); return 0; } @@ -922,7 +926,7 @@ static int i915_probe_agp(struct drm_device *dev, unsigned long *aperture_size, * Some of the preallocated space is taken by the GTT * and popup. GTT is 1K per MB of aperture size, and popup is 4K. */ - if (IS_G4X(dev) || IS_IGD(dev)) + if (IS_G4X(dev) || IS_IGD(dev) || IS_IGDNG(dev)) overhead = 4096; else overhead = (*aperture_size / 1024) + 4096; @@ -1058,7 +1062,7 @@ int i915_master_create(struct drm_device *dev, struct drm_master *master) { struct drm_i915_master_private *master_priv; - master_priv = drm_calloc(1, sizeof(*master_priv), DRM_MEM_DRIVER); + master_priv = kzalloc(sizeof(*master_priv), GFP_KERNEL); if (!master_priv) return -ENOMEM; @@ -1073,7 +1077,7 @@ void i915_master_destroy(struct drm_device *dev, struct drm_master *master) if (!master_priv) return; - drm_free(master_priv, sizeof(*master_priv), DRM_MEM_DRIVER); + kfree(master_priv); master->driver_priv = NULL; } @@ -1102,12 +1106,10 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) dev->types[8] = _DRM_STAT_SECONDARY; dev->types[9] = _DRM_STAT_DMA; - dev_priv = drm_alloc(sizeof(drm_i915_private_t), DRM_MEM_DRIVER); + dev_priv = kzalloc(sizeof(drm_i915_private_t), GFP_KERNEL); if (dev_priv == NULL) return -ENOMEM; - memset(dev_priv, 0, sizeof(drm_i915_private_t)); - dev->dev_private = (void *)dev_priv; dev_priv->dev = dev; @@ -1144,17 +1146,15 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) "performance may suffer.\n"); } -#ifdef CONFIG_HIGHMEM64G - /* don't enable GEM on PAE - needs agp + set_memory_* interface fixes */ - dev_priv->has_gem = 0; -#else /* enable GEM by default */ dev_priv->has_gem = 1; -#endif dev->driver->get_vblank_counter = i915_get_vblank_counter; - if (IS_GM45(dev)) + dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ + if (IS_G4X(dev) || IS_IGDNG(dev)) { + dev->max_vblank_count = 0xffffffff; /* full 32 bit counter */ dev->driver->get_vblank_counter = gm45_get_vblank_counter; + } i915_gem_load(dev); @@ -1198,7 +1198,9 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) } /* Must be done after probing outputs */ - intel_opregion_init(dev, 0); + /* FIXME: verify on IGDNG */ + if (!IS_IGDNG(dev)) + intel_opregion_init(dev, 0); return 0; @@ -1207,7 +1209,7 @@ out_iomapfree: out_rmmap: iounmap(dev_priv->regs); free_priv: - drm_free(dev_priv, sizeof(struct drm_i915_private), DRM_MEM_DRIVER); + kfree(dev_priv); return ret; } @@ -1232,7 +1234,8 @@ int i915_driver_unload(struct drm_device *dev) if (dev_priv->regs != NULL) iounmap(dev_priv->regs); - intel_opregion_free(dev, 0); + if (!IS_IGDNG(dev)) + intel_opregion_free(dev, 0); if (drm_core_check_feature(dev, DRIVER_MODESET)) { intel_modeset_cleanup(dev); @@ -1246,8 +1249,7 @@ int i915_driver_unload(struct drm_device *dev) i915_gem_lastclose(dev); } - drm_free(dev->dev_private, sizeof(drm_i915_private_t), - DRM_MEM_DRIVER); + kfree(dev->dev_private); return 0; } @@ -1256,17 +1258,16 @@ int i915_driver_open(struct drm_device *dev, struct drm_file *file_priv) { struct drm_i915_file_private *i915_file_priv; - DRM_DEBUG("\n"); + DRM_DEBUG_DRIVER(I915_DRV, "\n"); i915_file_priv = (struct drm_i915_file_private *) - drm_alloc(sizeof(*i915_file_priv), DRM_MEM_FILES); + kmalloc(sizeof(*i915_file_priv), GFP_KERNEL); if (!i915_file_priv) return -ENOMEM; file_priv->driver_priv = i915_file_priv; - i915_file_priv->mm.last_gem_seqno = 0; - i915_file_priv->mm.last_gem_throttle_seqno = 0; + INIT_LIST_HEAD(&i915_file_priv->mm.request_list); return 0; } @@ -1303,6 +1304,7 @@ void i915_driver_lastclose(struct drm_device * dev) void i915_driver_preclose(struct drm_device * dev, struct drm_file *file_priv) { drm_i915_private_t *dev_priv = dev->dev_private; + i915_gem_release(dev, file_priv); if (!drm_core_check_feature(dev, DRIVER_MODESET)) i915_mem_release(dev, file_priv, dev_priv->agp_heap); } @@ -1311,7 +1313,7 @@ void i915_driver_postclose(struct drm_device *dev, struct drm_file *file_priv) { struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv; - drm_free(i915_file_priv, sizeof(*i915_file_priv), DRM_MEM_FILES); + kfree(i915_file_priv); } struct drm_ioctl_desc i915_ioctls[] = { diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index c431fa54bbb5..7a84f04e8439 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -126,6 +126,13 @@ struct drm_i915_fence_reg { struct drm_gem_object *obj; }; +struct sdvo_device_mapping { + u8 dvo_port; + u8 slave_addr; + u8 dvo_wiring; + u8 initialized; +}; + typedef struct drm_i915_private { struct drm_device *dev; @@ -143,6 +150,8 @@ typedef struct drm_i915_private { drm_local_map_t hws_map; struct drm_gem_object *hws_obj; + struct resource mch_res; + unsigned int cpp; int back_offset; int front_offset; @@ -158,6 +167,11 @@ typedef struct drm_i915_private { /** Cached value of IMR to avoid reads in updating the bitfield */ u32 irq_mask_reg; u32 pipestat[2]; + /** splitted irq regs for graphics and display engine on IGDNG, + irq_mask_reg is still used for display irq. */ + u32 gt_irq_mask_reg; + u32 gt_irq_enable_reg; + u32 de_irq_enable_reg; u32 hotplug_supported_mask; struct work_struct hotplug_work; @@ -285,6 +299,13 @@ typedef struct drm_i915_private { u8 saveDACMASK; u8 saveCR[37]; uint64_t saveFENCE[16]; + u32 saveCURACNTR; + u32 saveCURAPOS; + u32 saveCURABASE; + u32 saveCURBCNTR; + u32 saveCURBPOS; + u32 saveCURBBASE; + u32 saveCURSIZE; struct { struct drm_mm gtt_space; @@ -382,6 +403,7 @@ typedef struct drm_i915_private { /* storage for physical objects */ struct drm_i915_gem_phys_object *phys_objs[I915_MAX_PHYS_OBJECT]; } mm; + struct sdvo_device_mapping sdvo_mappings[2]; } drm_i915_private_t; /** driver private structure attached to each drm_gem_object */ @@ -491,13 +513,16 @@ struct drm_i915_gem_request { /** Time at which this request was emitted, in jiffies. */ unsigned long emitted_jiffies; + /** global list entry for this request */ struct list_head list; + + /** file_priv list entry for this request */ + struct list_head client_list; }; struct drm_i915_file_private { struct { - uint32_t last_gem_seqno; - uint32_t last_gem_throttle_seqno; + struct list_head request_list; } mm; }; @@ -621,6 +646,8 @@ void i915_gem_object_unpin(struct drm_gem_object *obj); int i915_gem_object_unbind(struct drm_gem_object *obj); void i915_gem_lastclose(struct drm_device *dev); uint32_t i915_get_gem_seqno(struct drm_device *dev); +int i915_gem_object_get_fence_reg(struct drm_gem_object *obj); +int i915_gem_object_put_fence_reg(struct drm_gem_object *obj); void i915_gem_retire_requests(struct drm_device *dev); void i915_gem_retire_work_handler(struct work_struct *work); void i915_gem_clflush_object(struct drm_gem_object *obj); @@ -642,6 +669,7 @@ void i915_gem_detach_phys_object(struct drm_device *dev, void i915_gem_free_all_phys_object(struct drm_device *dev); int i915_gem_object_get_pages(struct drm_gem_object *obj); void i915_gem_object_put_pages(struct drm_gem_object *obj); +void i915_gem_release(struct drm_device * dev, struct drm_file *file_priv); /* i915_gem_tiling.c */ void i915_gem_detect_bit_6_swizzle(struct drm_device *dev); @@ -785,7 +813,9 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); (dev)->pci_device == 0x2E02 || \ (dev)->pci_device == 0x2E12 || \ (dev)->pci_device == 0x2E22 || \ - (dev)->pci_device == 0x2E32) + (dev)->pci_device == 0x2E32 || \ + (dev)->pci_device == 0x0042 || \ + (dev)->pci_device == 0x0046) #define IS_I965GM(dev) ((dev)->pci_device == 0x2A02 || \ (dev)->pci_device == 0x2A12) @@ -807,20 +837,26 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); (dev)->pci_device == 0x29D2 || \ (IS_IGD(dev))) +#define IS_IGDNG_D(dev) ((dev)->pci_device == 0x0042) +#define IS_IGDNG_M(dev) ((dev)->pci_device == 0x0046) +#define IS_IGDNG(dev) (IS_IGDNG_D(dev) || IS_IGDNG_M(dev)) + #define IS_I9XX(dev) (IS_I915G(dev) || IS_I915GM(dev) || IS_I945G(dev) || \ - IS_I945GM(dev) || IS_I965G(dev) || IS_G33(dev)) + IS_I945GM(dev) || IS_I965G(dev) || IS_G33(dev) || \ + IS_IGDNG(dev)) #define IS_MOBILE(dev) (IS_I830(dev) || IS_I85X(dev) || IS_I915GM(dev) || \ IS_I945GM(dev) || IS_I965GM(dev) || IS_GM45(dev) || \ - IS_IGD(dev)) + IS_IGD(dev) || IS_IGDNG_M(dev)) -#define I915_NEED_GFX_HWS(dev) (IS_G33(dev) || IS_GM45(dev) || IS_G4X(dev)) +#define I915_NEED_GFX_HWS(dev) (IS_G33(dev) || IS_GM45(dev) || IS_G4X(dev) || \ + IS_IGDNG(dev)) /* With the 945 and later, Y tiling got adjusted so that it was 32 128-byte * rows, which changed the alignment requirements and fence programming. */ #define HAS_128_BYTE_Y_TILING(dev) (IS_I9XX(dev) && !(IS_I915G(dev) || \ IS_I915GM(dev))) -#define SUPPORTS_INTEGRATED_HDMI(dev) (IS_G4X(dev)) +#define SUPPORTS_INTEGRATED_HDMI(dev) (IS_G4X(dev) || IS_IGDNG(dev)) #define I915_HAS_HOTPLUG(dev) (IS_I945G(dev) || IS_I945GM(dev) || IS_I965G(dev)) #define PRIMARY_RINGBUFFER_SIZE (128*1024) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 39f5c658ef5e..fd2b8bdffe3f 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -46,7 +46,6 @@ static void i915_gem_object_set_to_full_cpu_read_domain(struct drm_gem_object *o static int i915_gem_object_wait_rendering(struct drm_gem_object *obj); static int i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment); -static int i915_gem_object_get_fence_reg(struct drm_gem_object *obj, bool write); static void i915_gem_clear_fence_reg(struct drm_gem_object *obj); static int i915_gem_evict_something(struct drm_device *dev); static int i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj, @@ -989,10 +988,10 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, return -ENODEV; /* Only handle setting domains to types used by the CPU. */ - if (write_domain & ~(I915_GEM_DOMAIN_CPU | I915_GEM_DOMAIN_GTT)) + if (write_domain & I915_GEM_GPU_DOMAINS) return -EINVAL; - if (read_domains & ~(I915_GEM_DOMAIN_CPU | I915_GEM_DOMAIN_GTT)) + if (read_domains & I915_GEM_GPU_DOMAINS) return -EINVAL; /* Having something in the write domain implies it's in the read @@ -1158,7 +1157,7 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) /* Need a new fence register? */ if (obj_priv->fence_reg == I915_FENCE_REG_NONE && obj_priv->tiling_mode != I915_TILING_NONE) { - ret = i915_gem_object_get_fence_reg(obj, write); + ret = i915_gem_object_get_fence_reg(obj); if (ret) { mutex_unlock(&dev->struct_mutex); return VM_FAULT_SIGBUS; @@ -1208,8 +1207,7 @@ i915_gem_create_mmap_offset(struct drm_gem_object *obj) /* Set the object up for mmap'ing */ list = &obj->map_list; - list->map = drm_calloc(1, sizeof(struct drm_map_list), - DRM_MEM_DRIVER); + list->map = kzalloc(sizeof(struct drm_map_list), GFP_KERNEL); if (!list->map) return -ENOMEM; @@ -1249,7 +1247,7 @@ i915_gem_create_mmap_offset(struct drm_gem_object *obj) out_free_mm: drm_mm_put_block(list->file_offset_node); out_free_list: - drm_free(list->map, sizeof(struct drm_map_list), DRM_MEM_DRIVER); + kfree(list->map); return ret; } @@ -1271,7 +1269,7 @@ i915_gem_free_mmap_offset(struct drm_gem_object *obj) } if (list->map) { - drm_free(list->map, sizeof(struct drm_map), DRM_MEM_DRIVER); + kfree(list->map); list->map = NULL; } @@ -1481,15 +1479,20 @@ i915_gem_object_move_to_inactive(struct drm_gem_object *obj) * Returned sequence numbers are nonzero on success. */ static uint32_t -i915_add_request(struct drm_device *dev, uint32_t flush_domains) +i915_add_request(struct drm_device *dev, struct drm_file *file_priv, + uint32_t flush_domains) { drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_file_private *i915_file_priv = NULL; struct drm_i915_gem_request *request; uint32_t seqno; int was_empty; RING_LOCALS; - request = drm_calloc(1, sizeof(*request), DRM_MEM_DRIVER); + if (file_priv != NULL) + i915_file_priv = file_priv->driver_priv; + + request = kzalloc(sizeof(*request), GFP_KERNEL); if (request == NULL) return 0; @@ -1515,6 +1518,12 @@ i915_add_request(struct drm_device *dev, uint32_t flush_domains) request->emitted_jiffies = jiffies; was_empty = list_empty(&dev_priv->mm.request_list); list_add_tail(&request->list, &dev_priv->mm.request_list); + if (i915_file_priv) { + list_add_tail(&request->client_list, + &i915_file_priv->mm.request_list); + } else { + INIT_LIST_HEAD(&request->client_list); + } /* Associate any objects on the flushing list matching the write * domain we're flushing with our flush. @@ -1664,7 +1673,8 @@ i915_gem_retire_requests(struct drm_device *dev) i915_gem_retire_request(dev, request); list_del(&request->list); - drm_free(request, sizeof(*request), DRM_MEM_DRIVER); + list_del(&request->client_list); + kfree(request); } else break; } @@ -1702,7 +1712,10 @@ i915_wait_request(struct drm_device *dev, uint32_t seqno) BUG_ON(seqno == 0); if (!i915_seqno_passed(i915_get_gem_seqno(dev), seqno)) { - ier = I915_READ(IER); + if (IS_IGDNG(dev)) + ier = I915_READ(DEIER) | I915_READ(GTIER); + else + ier = I915_READ(IER); if (!ier) { DRM_ERROR("something (likely vbetool) disabled " "interrupts, re-enabling\n"); @@ -1754,8 +1767,7 @@ i915_gem_flush(struct drm_device *dev, if (flush_domains & I915_GEM_DOMAIN_CPU) drm_agp_chipset_flush(dev); - if ((invalidate_domains | flush_domains) & ~(I915_GEM_DOMAIN_CPU | - I915_GEM_DOMAIN_GTT)) { + if ((invalidate_domains | flush_domains) & I915_GEM_GPU_DOMAINS) { /* * read/write caches: * @@ -1977,7 +1989,7 @@ i915_gem_evict_something(struct drm_device *dev) i915_gem_flush(dev, obj->write_domain, obj->write_domain); - i915_add_request(dev, obj->write_domain); + i915_add_request(dev, NULL, obj->write_domain); obj = NULL; continue; @@ -1991,7 +2003,7 @@ i915_gem_evict_something(struct drm_device *dev) /* If we didn't do any of the above, there's nothing to be done * and we just can't fit it in. */ - return -ENOMEM; + return -ENOSPC; } return ret; } @@ -2006,7 +2018,7 @@ i915_gem_evict_everything(struct drm_device *dev) if (ret != 0) break; } - if (ret == -ENOMEM) + if (ret == -ENOSPC) return 0; return ret; } @@ -2149,13 +2161,11 @@ static void i830_write_fence_reg(struct drm_i915_fence_reg *reg) val |= I830_FENCE_REG_VALID; I915_WRITE(FENCE_REG_830_0 + (regnum * 4), val); - } /** * i915_gem_object_get_fence_reg - set up a fence reg for an object * @obj: object to map through a fence reg - * @write: object is about to be written * * When mapping objects through the GTT, userspace wants to be able to write * to them without having to worry about swizzling if the object is tiled. @@ -2166,8 +2176,8 @@ static void i830_write_fence_reg(struct drm_i915_fence_reg *reg) * It then sets up the reg based on the object's properties: address, pitch * and tiling format. */ -static int -i915_gem_object_get_fence_reg(struct drm_gem_object *obj, bool write) +int +i915_gem_object_get_fence_reg(struct drm_gem_object *obj) { struct drm_device *dev = obj->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -2215,7 +2225,7 @@ try_again: loff_t offset; if (avail == 0) - return -ENOMEM; + return -ENOSPC; for (i = dev_priv->fence_reg_start; i < dev_priv->num_fence_regs; i++) { @@ -2248,7 +2258,7 @@ try_again: i915_gem_flush(dev, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS); - seqno = i915_add_request(dev, + seqno = i915_add_request(dev, NULL, I915_GEM_GPU_DOMAINS); if (seqno == 0) return -ENOMEM; @@ -2316,6 +2326,42 @@ i915_gem_clear_fence_reg(struct drm_gem_object *obj) obj_priv->fence_reg = I915_FENCE_REG_NONE; } +/** + * i915_gem_object_put_fence_reg - waits on outstanding fenced access + * to the buffer to finish, and then resets the fence register. + * @obj: tiled object holding a fence register. + * + * Zeroes out the fence register itself and clears out the associated + * data structures in dev_priv and obj_priv. + */ +int +i915_gem_object_put_fence_reg(struct drm_gem_object *obj) +{ + struct drm_device *dev = obj->dev; + struct drm_i915_gem_object *obj_priv = obj->driver_private; + + if (obj_priv->fence_reg == I915_FENCE_REG_NONE) + return 0; + + /* On the i915, GPU access to tiled buffers is via a fence, + * therefore we must wait for any outstanding access to complete + * before clearing the fence. + */ + if (!IS_I965G(dev)) { + int ret; + + i915_gem_object_flush_gpu_write_domain(obj); + i915_gem_object_flush_gtt_write_domain(obj); + ret = i915_gem_object_wait_rendering(obj); + if (ret != 0) + return ret; + } + + i915_gem_clear_fence_reg (obj); + + return 0; +} + /** * Finds free space in the GTT aperture and binds the object there. */ @@ -2364,7 +2410,7 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment) spin_unlock(&dev_priv->mm.active_list_lock); if (lists_empty) { DRM_ERROR("GTT full, but LRU list empty\n"); - return -ENOMEM; + return -ENOSPC; } ret = i915_gem_evict_something(dev); @@ -2409,8 +2455,8 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment) * wasn't in the GTT, there shouldn't be any way it could have been in * a GPU cache */ - BUG_ON(obj->read_domains & ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT)); - BUG_ON(obj->write_domain & ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT)); + BUG_ON(obj->read_domains & I915_GEM_GPU_DOMAINS); + BUG_ON(obj->write_domain & I915_GEM_GPU_DOMAINS); return 0; } @@ -2452,7 +2498,7 @@ i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj) /* Queue the GPU write cache flushing we need. */ i915_gem_flush(dev, 0, obj->write_domain); - seqno = i915_add_request(dev, obj->write_domain); + seqno = i915_add_request(dev, NULL, obj->write_domain); obj->write_domain = 0; i915_gem_object_move_to_active(obj, seqno); } @@ -2786,8 +2832,7 @@ i915_gem_object_set_to_full_cpu_read_domain(struct drm_gem_object *obj) /* Free the page_cpu_valid mappings which are now stale, whether * or not we've got I915_GEM_DOMAIN_CPU. */ - drm_free(obj_priv->page_cpu_valid, obj->size / PAGE_SIZE, - DRM_MEM_DRIVER); + kfree(obj_priv->page_cpu_valid); obj_priv->page_cpu_valid = NULL; } @@ -2829,8 +2874,8 @@ i915_gem_object_set_cpu_read_domain_range(struct drm_gem_object *obj, * newly adding I915_GEM_DOMAIN_CPU */ if (obj_priv->page_cpu_valid == NULL) { - obj_priv->page_cpu_valid = drm_calloc(1, obj->size / PAGE_SIZE, - DRM_MEM_DRIVER); + obj_priv->page_cpu_valid = kzalloc(obj->size / PAGE_SIZE, + GFP_KERNEL); if (obj_priv->page_cpu_valid == NULL) return -ENOMEM; } else if ((obj->read_domains & I915_GEM_DOMAIN_CPU) == 0) @@ -3035,20 +3080,12 @@ i915_dispatch_gem_execbuffer(struct drm_device *dev, drm_i915_private_t *dev_priv = dev->dev_private; int nbox = exec->num_cliprects; int i = 0, count; - uint32_t exec_start, exec_len; + uint32_t exec_start, exec_len; RING_LOCALS; exec_start = (uint32_t) exec_offset + exec->batch_start_offset; exec_len = (uint32_t) exec->batch_len; - if ((exec_start | exec_len) & 0x7) { - DRM_ERROR("alignment\n"); - return -EINVAL; - } - - if (!exec_start) - return -EINVAL; - count = nbox ? nbox : 1; for (i = 0; i < count; i++) { @@ -3089,6 +3126,10 @@ i915_dispatch_gem_execbuffer(struct drm_device *dev, /* Throttle our rendering by waiting until the ring has completed our requests * emitted over 20 msec ago. * + * Note that if we were to use the current jiffies each time around the loop, + * we wouldn't escape the function with any frames outstanding if the time to + * render a frame was over 20ms. + * * This should get us reasonable parallelism between CPU and GPU but also * relatively low latency when blocking on a particular request to finish. */ @@ -3097,15 +3138,25 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file_priv) { struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv; int ret = 0; - uint32_t seqno; + unsigned long recent_enough = jiffies - msecs_to_jiffies(20); mutex_lock(&dev->struct_mutex); - seqno = i915_file_priv->mm.last_gem_throttle_seqno; - i915_file_priv->mm.last_gem_throttle_seqno = - i915_file_priv->mm.last_gem_seqno; - if (seqno) - ret = i915_wait_request(dev, seqno); + while (!list_empty(&i915_file_priv->mm.request_list)) { + struct drm_i915_gem_request *request; + + request = list_first_entry(&i915_file_priv->mm.request_list, + struct drm_i915_gem_request, + client_list); + + if (time_after_eq(request->emitted_jiffies, recent_enough)) + break; + + ret = i915_wait_request(dev, request->seqno); + if (ret != 0) + break; + } mutex_unlock(&dev->struct_mutex); + return ret; } @@ -3182,12 +3233,29 @@ err: return ret; } +static int +i915_gem_check_execbuffer (struct drm_i915_gem_execbuffer *exec, + uint64_t exec_offset) +{ + uint32_t exec_start, exec_len; + + exec_start = (uint32_t) exec_offset + exec->batch_start_offset; + exec_len = (uint32_t) exec->batch_len; + + if ((exec_start | exec_len) & 0x7) + return -EINVAL; + + if (!exec_start) + return -EINVAL; + + return 0; +} + int i915_gem_execbuffer(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv; struct drm_i915_gem_execbuffer *args = data; struct drm_i915_gem_exec_object *exec_list = NULL; struct drm_gem_object **object_list = NULL; @@ -3230,8 +3298,8 @@ i915_gem_execbuffer(struct drm_device *dev, void *data, } if (args->num_cliprects != 0) { - cliprects = drm_calloc(args->num_cliprects, sizeof(*cliprects), - DRM_MEM_DRIVER); + cliprects = kcalloc(args->num_cliprects, sizeof(*cliprects), + GFP_KERNEL); if (cliprects == NULL) goto pre_mutex_err; @@ -3312,7 +3380,7 @@ i915_gem_execbuffer(struct drm_device *dev, void *data, break; /* error other than GTT full, or we've already tried again */ - if (ret != -ENOMEM || pin_tries >= 1) { + if (ret != -ENOSPC || pin_tries >= 1) { if (ret != -ERESTARTSYS) DRM_ERROR("Failed to pin buffers %d\n", ret); goto err; @@ -3331,8 +3399,20 @@ i915_gem_execbuffer(struct drm_device *dev, void *data, /* Set the pending read domains for the batch buffer to COMMAND */ batch_obj = object_list[args->buffer_count-1]; - batch_obj->pending_read_domains = I915_GEM_DOMAIN_COMMAND; - batch_obj->pending_write_domain = 0; + if (batch_obj->pending_write_domain) { + DRM_ERROR("Attempting to use self-modifying batch buffer\n"); + ret = -EINVAL; + goto err; + } + batch_obj->pending_read_domains |= I915_GEM_DOMAIN_COMMAND; + + /* Sanity check the batch buffer, prior to moving objects */ + exec_offset = exec_list[args->buffer_count - 1].offset; + ret = i915_gem_check_execbuffer (args, exec_offset); + if (ret != 0) { + DRM_ERROR("execbuf with invalid offset/length\n"); + goto err; + } i915_verify_inactive(dev, __FILE__, __LINE__); @@ -3363,7 +3443,8 @@ i915_gem_execbuffer(struct drm_device *dev, void *data, dev->invalidate_domains, dev->flush_domains); if (dev->flush_domains) - (void)i915_add_request(dev, dev->flush_domains); + (void)i915_add_request(dev, file_priv, + dev->flush_domains); } for (i = 0; i < args->buffer_count; i++) { @@ -3381,8 +3462,6 @@ i915_gem_execbuffer(struct drm_device *dev, void *data, } #endif - exec_offset = exec_list[args->buffer_count - 1].offset; - #if WATCH_EXEC i915_gem_dump_object(batch_obj, args->batch_len, @@ -3412,9 +3491,8 @@ i915_gem_execbuffer(struct drm_device *dev, void *data, * *some* interrupts representing completion of buffers that we can * wait on when trying to clear up gtt space). */ - seqno = i915_add_request(dev, flush_domains); + seqno = i915_add_request(dev, file_priv, flush_domains); BUG_ON(seqno == 0); - i915_file_priv->mm.last_gem_seqno = seqno; for (i = 0; i < args->buffer_count; i++) { struct drm_gem_object *obj = object_list[i]; @@ -3474,8 +3552,7 @@ err: pre_mutex_err: drm_free_large(object_list); drm_free_large(exec_list); - drm_free(cliprects, sizeof(*cliprects) * args->num_cliprects, - DRM_MEM_DRIVER); + kfree(cliprects); return ret; } @@ -3503,7 +3580,7 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment) if (!IS_I965G(dev) && obj_priv->fence_reg == I915_FENCE_REG_NONE && obj_priv->tiling_mode != I915_TILING_NONE) { - ret = i915_gem_object_get_fence_reg(obj, true); + ret = i915_gem_object_get_fence_reg(obj); if (ret != 0) { if (ret != -EBUSY && ret != -ERESTARTSYS) DRM_ERROR("Failure to install fence: %d\n", @@ -3520,8 +3597,7 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment) atomic_inc(&dev->pin_count); atomic_add(obj->size, &dev->pin_memory); if (!obj_priv->active && - (obj->write_domain & ~(I915_GEM_DOMAIN_CPU | - I915_GEM_DOMAIN_GTT)) == 0 && + (obj->write_domain & I915_GEM_GPU_DOMAINS) == 0 && !list_empty(&obj_priv->list)) list_del_init(&obj_priv->list); } @@ -3548,8 +3624,7 @@ i915_gem_object_unpin(struct drm_gem_object *obj) */ if (obj_priv->pin_count == 0) { if (!obj_priv->active && - (obj->write_domain & ~(I915_GEM_DOMAIN_CPU | - I915_GEM_DOMAIN_GTT)) == 0) + (obj->write_domain & I915_GEM_GPU_DOMAINS) == 0) list_move_tail(&obj_priv->list, &dev_priv->mm.inactive_list); atomic_dec(&dev->pin_count); @@ -3653,15 +3728,14 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data, struct drm_gem_object *obj; struct drm_i915_gem_object *obj_priv; - mutex_lock(&dev->struct_mutex); obj = drm_gem_object_lookup(dev, file_priv, args->handle); if (obj == NULL) { DRM_ERROR("Bad handle in i915_gem_busy_ioctl(): %d\n", args->handle); - mutex_unlock(&dev->struct_mutex); return -EBADF; } + mutex_lock(&dev->struct_mutex); /* Update the active list for the hardware's current position. * Otherwise this only updates on a delayed timer or when irqs are * actually unmasked, and our working set ends up being larger than @@ -3695,7 +3769,7 @@ int i915_gem_init_object(struct drm_gem_object *obj) { struct drm_i915_gem_object *obj_priv; - obj_priv = drm_calloc(1, sizeof(*obj_priv), DRM_MEM_DRIVER); + obj_priv = kzalloc(sizeof(*obj_priv), GFP_KERNEL); if (obj_priv == NULL) return -ENOMEM; @@ -3733,9 +3807,9 @@ void i915_gem_free_object(struct drm_gem_object *obj) i915_gem_free_mmap_offset(obj); - drm_free(obj_priv->page_cpu_valid, 1, DRM_MEM_DRIVER); + kfree(obj_priv->page_cpu_valid); kfree(obj_priv->bit_17); - drm_free(obj->driver_private, 1, DRM_MEM_DRIVER); + kfree(obj->driver_private); } /** Unbinds all objects that are on the given buffer list. */ @@ -3800,9 +3874,8 @@ i915_gem_idle(struct drm_device *dev) /* Flush the GPU along with all non-CPU write domains */ - i915_gem_flush(dev, ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT), - ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT)); - seqno = i915_add_request(dev, ~I915_GEM_DOMAIN_CPU); + i915_gem_flush(dev, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS); + seqno = i915_add_request(dev, NULL, I915_GEM_GPU_DOMAINS); if (seqno == 0) { mutex_unlock(&dev->struct_mutex); @@ -4190,7 +4263,7 @@ int i915_gem_init_phys_object(struct drm_device *dev, if (dev_priv->mm.phys_objs[id - 1] || !size) return 0; - phys_obj = drm_calloc(1, sizeof(struct drm_i915_gem_phys_object), DRM_MEM_DRIVER); + phys_obj = kzalloc(sizeof(struct drm_i915_gem_phys_object), GFP_KERNEL); if (!phys_obj) return -ENOMEM; @@ -4209,7 +4282,7 @@ int i915_gem_init_phys_object(struct drm_device *dev, return 0; kfree_obj: - drm_free(phys_obj, sizeof(struct drm_i915_gem_phys_object), DRM_MEM_DRIVER); + kfree(phys_obj); return ret; } @@ -4269,6 +4342,8 @@ void i915_gem_detach_phys_object(struct drm_device *dev, } drm_clflush_pages(obj_priv->pages, page_count); drm_agp_chipset_flush(dev); + + i915_gem_object_put_pages(obj); out: obj_priv->phys_obj->cur_obj = NULL; obj_priv->phys_obj = NULL; @@ -4326,6 +4401,8 @@ i915_gem_attach_phys_object(struct drm_device *dev, kunmap_atomic(src, KM_USER0); } + i915_gem_object_put_pages(obj); + return 0; out: return ret; @@ -4352,3 +4429,17 @@ i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj, drm_agp_chipset_flush(dev); return 0; } + +void i915_gem_release(struct drm_device * dev, struct drm_file *file_priv) +{ + struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv; + + /* Clean up our request list when the client is going away, so that + * later retire_requests won't dereference our soon-to-be-gone + * file_priv. + */ + mutex_lock(&dev->struct_mutex); + while (!list_empty(&i915_file_priv->mm.request_list)) + list_del_init(i915_file_priv->mm.request_list.next); + mutex_unlock(&dev->struct_mutex); +} diff --git a/drivers/gpu/drm/i915/i915_gem_debugfs.c b/drivers/gpu/drm/i915/i915_gem_debugfs.c index 986f1082c596..28146e405e87 100644 --- a/drivers/gpu/drm/i915/i915_gem_debugfs.c +++ b/drivers/gpu/drm/i915/i915_gem_debugfs.c @@ -104,7 +104,7 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data) if (obj->name) seq_printf(m, " (name: %d)", obj->name); if (obj_priv->fence_reg != I915_FENCE_REG_NONE) - seq_printf(m, " (fence: %d\n", obj_priv->fence_reg); + seq_printf(m, " (fence: %d)\n", obj_priv->fence_reg); seq_printf(m, "\n"); } @@ -318,7 +318,7 @@ static int i915_ringbuffer_info(struct seq_file *m, void *data) seq_printf(m, "RingTail : %08x\n", tail); seq_printf(m, "RingMask : %08x\n", mask); seq_printf(m, "RingSize : %08lx\n", dev_priv->ring.Size); - seq_printf(m, "Acthd : %08x\n", I915_READ(IS_I965G(dev) ? ACTHD_I965 : ACTHD)); + seq_printf(m, "Acthd : %08x\n", I915_READ(IS_I965G(dev) ? ACTHD_I965 : ACTHD)); return 0; } diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c index 540dd336e6ec..5c1ceec49f5b 100644 --- a/drivers/gpu/drm/i915/i915_gem_tiling.c +++ b/drivers/gpu/drm/i915/i915_gem_tiling.c @@ -25,6 +25,8 @@ * */ +#include +#include #include "linux/string.h" #include "linux/bitops.h" #include "drmP.h" @@ -81,6 +83,143 @@ * to match what the GPU expects. */ +#define MCHBAR_I915 0x44 +#define MCHBAR_I965 0x48 +#define MCHBAR_SIZE (4*4096) + +#define DEVEN_REG 0x54 +#define DEVEN_MCHBAR_EN (1 << 28) + +/* Allocate space for the MCH regs if needed, return nonzero on error */ +static int +intel_alloc_mchbar_resource(struct drm_device *dev) +{ + struct pci_dev *bridge_dev; + drm_i915_private_t *dev_priv = dev->dev_private; + int reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915; + u32 temp_lo, temp_hi = 0; + u64 mchbar_addr; + int ret = 0; + + bridge_dev = pci_get_bus_and_slot(0, PCI_DEVFN(0,0)); + if (!bridge_dev) { + DRM_DEBUG("no bridge dev?!\n"); + ret = -ENODEV; + goto out; + } + + if (IS_I965G(dev)) + pci_read_config_dword(bridge_dev, reg + 4, &temp_hi); + pci_read_config_dword(bridge_dev, reg, &temp_lo); + mchbar_addr = ((u64)temp_hi << 32) | temp_lo; + + /* If ACPI doesn't have it, assume we need to allocate it ourselves */ + if (mchbar_addr && + pnp_range_reserved(mchbar_addr, mchbar_addr + MCHBAR_SIZE)) { + ret = 0; + goto out_put; + } + + /* Get some space for it */ + ret = pci_bus_alloc_resource(bridge_dev->bus, &dev_priv->mch_res, + MCHBAR_SIZE, MCHBAR_SIZE, + PCIBIOS_MIN_MEM, + 0, pcibios_align_resource, + bridge_dev); + if (ret) { + DRM_DEBUG("failed bus alloc: %d\n", ret); + dev_priv->mch_res.start = 0; + goto out_put; + } + + if (IS_I965G(dev)) + pci_write_config_dword(bridge_dev, reg + 4, + upper_32_bits(dev_priv->mch_res.start)); + + pci_write_config_dword(bridge_dev, reg, + lower_32_bits(dev_priv->mch_res.start)); +out_put: + pci_dev_put(bridge_dev); +out: + return ret; +} + +/* Setup MCHBAR if possible, return true if we should disable it again */ +static bool +intel_setup_mchbar(struct drm_device *dev) +{ + struct pci_dev *bridge_dev; + int mchbar_reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915; + u32 temp; + bool need_disable = false, enabled; + + bridge_dev = pci_get_bus_and_slot(0, PCI_DEVFN(0,0)); + if (!bridge_dev) { + DRM_DEBUG("no bridge dev?!\n"); + goto out; + } + + if (IS_I915G(dev) || IS_I915GM(dev)) { + pci_read_config_dword(bridge_dev, DEVEN_REG, &temp); + enabled = !!(temp & DEVEN_MCHBAR_EN); + } else { + pci_read_config_dword(bridge_dev, mchbar_reg, &temp); + enabled = temp & 1; + } + + /* If it's already enabled, don't have to do anything */ + if (enabled) + goto out_put; + + if (intel_alloc_mchbar_resource(dev)) + goto out_put; + + need_disable = true; + + /* Space is allocated or reserved, so enable it. */ + if (IS_I915G(dev) || IS_I915GM(dev)) { + pci_write_config_dword(bridge_dev, DEVEN_REG, + temp | DEVEN_MCHBAR_EN); + } else { + pci_read_config_dword(bridge_dev, mchbar_reg, &temp); + pci_write_config_dword(bridge_dev, mchbar_reg, temp | 1); + } +out_put: + pci_dev_put(bridge_dev); +out: + return need_disable; +} + +static void +intel_teardown_mchbar(struct drm_device *dev, bool disable) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct pci_dev *bridge_dev; + int mchbar_reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915; + u32 temp; + + bridge_dev = pci_get_bus_and_slot(0, PCI_DEVFN(0,0)); + if (!bridge_dev) { + DRM_DEBUG("no bridge dev?!\n"); + return; + } + + if (disable) { + if (IS_I915G(dev) || IS_I915GM(dev)) { + pci_read_config_dword(bridge_dev, DEVEN_REG, &temp); + temp &= ~DEVEN_MCHBAR_EN; + pci_write_config_dword(bridge_dev, DEVEN_REG, temp); + } else { + pci_read_config_dword(bridge_dev, mchbar_reg, &temp); + temp &= ~1; + pci_write_config_dword(bridge_dev, mchbar_reg, temp); + } + } + + if (dev_priv->mch_res.start) + release_resource(&dev_priv->mch_res); +} + /** * Detects bit 6 swizzling of address lookup between IGD access and CPU * access through main memory. @@ -91,6 +230,7 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev) drm_i915_private_t *dev_priv = dev->dev_private; uint32_t swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN; uint32_t swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN; + bool need_disable; if (!IS_I9XX(dev)) { /* As far as we know, the 865 doesn't have these bit 6 @@ -101,6 +241,9 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev) } else if (IS_MOBILE(dev)) { uint32_t dcc; + /* Try to make sure MCHBAR is enabled before poking at it */ + need_disable = intel_setup_mchbar(dev); + /* On mobile 9xx chipsets, channel interleave by the CPU is * determined by DCC. For single-channel, neither the CPU * nor the GPU do swizzling. For dual channel interleaved, @@ -140,6 +283,8 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev) swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN; swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN; } + + intel_teardown_mchbar(dev, need_disable); } else { /* The 965, G33, and newer, have a very flexible memory * configuration. It will enable dual-channel mode @@ -170,6 +315,13 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev) } } + /* FIXME: check with memory config on IGDNG */ + if (IS_IGDNG(dev)) { + DRM_ERROR("disable tiling on IGDNG...\n"); + swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN; + swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN; + } + dev_priv->mm.bit_6_swizzle_x = swizzle_x; dev_priv->mm.bit_6_swizzle_y = swizzle_y; } @@ -256,7 +408,7 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode) if (stride & (stride - 1)) return false; - /* We don't handle the aperture area covered by the fence being bigger + /* We don't 0handle the aperture area covered by the fence being bigger * than the object size. */ if (i915_get_fence_size(dev, size) != size) @@ -265,6 +417,33 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode) return true; } +static bool +i915_gem_object_fence_offset_ok(struct drm_gem_object *obj, int tiling_mode) +{ + struct drm_device *dev = obj->dev; + struct drm_i915_gem_object *obj_priv = obj->driver_private; + + if (obj_priv->gtt_space == NULL) + return true; + + if (tiling_mode == I915_TILING_NONE) + return true; + + if (!IS_I965G(dev)) { + if (obj_priv->gtt_offset & (obj->size - 1)) + return false; + if (IS_I9XX(dev)) { + if (obj_priv->gtt_offset & ~I915_FENCE_START_MASK) + return false; + } else { + if (obj_priv->gtt_offset & ~I830_FENCE_START_MASK) + return false; + } + } + + return true; +} + /** * Sets the tiling mode of an object, returning the required swizzling of * bit 6 of addresses in the object. @@ -277,6 +456,7 @@ i915_gem_set_tiling(struct drm_device *dev, void *data, drm_i915_private_t *dev_priv = dev->dev_private; struct drm_gem_object *obj; struct drm_i915_gem_object *obj_priv; + int ret = 0; obj = drm_gem_object_lookup(dev, file_priv, args->handle); if (obj == NULL) @@ -284,14 +464,15 @@ i915_gem_set_tiling(struct drm_device *dev, void *data, obj_priv = obj->driver_private; if (!i915_tiling_ok(dev, args->stride, obj->size, args->tiling_mode)) { + mutex_lock(&dev->struct_mutex); drm_gem_object_unreference(obj); + mutex_unlock(&dev->struct_mutex); return -EINVAL; } - mutex_lock(&dev->struct_mutex); - if (args->tiling_mode == I915_TILING_NONE) { args->swizzle_mode = I915_BIT_6_SWIZZLE_NONE; + args->stride = 0; } else { if (args->tiling_mode == I915_TILING_X) args->swizzle_mode = dev_priv->mm.bit_6_swizzle_x; @@ -314,32 +495,38 @@ i915_gem_set_tiling(struct drm_device *dev, void *data, if (args->swizzle_mode == I915_BIT_6_SWIZZLE_UNKNOWN) { args->tiling_mode = I915_TILING_NONE; args->swizzle_mode = I915_BIT_6_SWIZZLE_NONE; + args->stride = 0; } } - if (args->tiling_mode != obj_priv->tiling_mode) { - int ret; - /* Unbind the object, as switching tiling means we're - * switching the cache organization due to fencing, probably. + mutex_lock(&dev->struct_mutex); + if (args->tiling_mode != obj_priv->tiling_mode || + args->stride != obj_priv->stride) { + /* We need to rebind the object if its current allocation + * no longer meets the alignment restrictions for its new + * tiling mode. Otherwise we can just leave it alone, but + * need to ensure that any fence register is cleared. */ - ret = i915_gem_object_unbind(obj); + if (!i915_gem_object_fence_offset_ok(obj, args->tiling_mode)) + ret = i915_gem_object_unbind(obj); + else + ret = i915_gem_object_put_fence_reg(obj); if (ret != 0) { WARN(ret != -ERESTARTSYS, - "failed to unbind object for tiling switch"); + "failed to reset object for tiling switch"); args->tiling_mode = obj_priv->tiling_mode; - mutex_unlock(&dev->struct_mutex); - drm_gem_object_unreference(obj); - - return ret; + args->stride = obj_priv->stride; + goto err; } - obj_priv->tiling_mode = args->tiling_mode; - } - obj_priv->stride = args->stride; + obj_priv->tiling_mode = args->tiling_mode; + obj_priv->stride = args->stride; + } +err: drm_gem_object_unreference(obj); mutex_unlock(&dev->struct_mutex); - return 0; + return ret; } /** diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 98bb4c878c4e..b86b7b7130c6 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -57,6 +57,47 @@ #define DRM_I915_VBLANK_PIPE_ALL (DRM_I915_VBLANK_PIPE_A | \ DRM_I915_VBLANK_PIPE_B) +void +igdng_enable_graphics_irq(drm_i915_private_t *dev_priv, u32 mask) +{ + if ((dev_priv->gt_irq_mask_reg & mask) != 0) { + dev_priv->gt_irq_mask_reg &= ~mask; + I915_WRITE(GTIMR, dev_priv->gt_irq_mask_reg); + (void) I915_READ(GTIMR); + } +} + +static inline void +igdng_disable_graphics_irq(drm_i915_private_t *dev_priv, u32 mask) +{ + if ((dev_priv->gt_irq_mask_reg & mask) != mask) { + dev_priv->gt_irq_mask_reg |= mask; + I915_WRITE(GTIMR, dev_priv->gt_irq_mask_reg); + (void) I915_READ(GTIMR); + } +} + +/* For display hotplug interrupt */ +void +igdng_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask) +{ + if ((dev_priv->irq_mask_reg & mask) != 0) { + dev_priv->irq_mask_reg &= ~mask; + I915_WRITE(DEIMR, dev_priv->irq_mask_reg); + (void) I915_READ(DEIMR); + } +} + +static inline void +igdng_disable_display_irq(drm_i915_private_t *dev_priv, u32 mask) +{ + if ((dev_priv->irq_mask_reg & mask) != mask) { + dev_priv->irq_mask_reg |= mask; + I915_WRITE(DEIMR, dev_priv->irq_mask_reg); + (void) I915_READ(DEIMR); + } +} + void i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask) { @@ -196,6 +237,47 @@ static void i915_hotplug_work_func(struct work_struct *work) drm_sysfs_hotplug_event(dev); } +irqreturn_t igdng_irq_handler(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + int ret = IRQ_NONE; + u32 de_iir, gt_iir; + u32 new_de_iir, new_gt_iir; + struct drm_i915_master_private *master_priv; + + de_iir = I915_READ(DEIIR); + gt_iir = I915_READ(GTIIR); + + for (;;) { + if (de_iir == 0 && gt_iir == 0) + break; + + ret = IRQ_HANDLED; + + I915_WRITE(DEIIR, de_iir); + new_de_iir = I915_READ(DEIIR); + I915_WRITE(GTIIR, gt_iir); + new_gt_iir = I915_READ(GTIIR); + + if (dev->primary->master) { + master_priv = dev->primary->master->driver_priv; + if (master_priv->sarea_priv) + master_priv->sarea_priv->last_dispatch = + READ_BREADCRUMB(dev_priv); + } + + if (gt_iir & GT_USER_INTERRUPT) { + dev_priv->mm.irq_gem_seqno = i915_get_gem_seqno(dev); + DRM_WAKEUP(&dev_priv->irq_queue); + } + + de_iir = new_de_iir; + gt_iir = new_gt_iir; + } + + return ret; +} + irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) { struct drm_device *dev = (struct drm_device *) arg; @@ -212,6 +294,9 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) atomic_inc(&dev_priv->irq_received); + if (IS_IGDNG(dev)) + return igdng_irq_handler(dev); + iir = I915_READ(IIR); if (IS_I965G(dev)) { @@ -349,8 +434,12 @@ void i915_user_irq_get(struct drm_device *dev) unsigned long irqflags; spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); - if (dev->irq_enabled && (++dev_priv->user_irq_refcount == 1)) - i915_enable_irq(dev_priv, I915_USER_INTERRUPT); + if (dev->irq_enabled && (++dev_priv->user_irq_refcount == 1)) { + if (IS_IGDNG(dev)) + igdng_enable_graphics_irq(dev_priv, GT_USER_INTERRUPT); + else + i915_enable_irq(dev_priv, I915_USER_INTERRUPT); + } spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); } @@ -361,8 +450,12 @@ void i915_user_irq_put(struct drm_device *dev) spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); BUG_ON(dev->irq_enabled && dev_priv->user_irq_refcount <= 0); - if (dev->irq_enabled && (--dev_priv->user_irq_refcount == 0)) - i915_disable_irq(dev_priv, I915_USER_INTERRUPT); + if (dev->irq_enabled && (--dev_priv->user_irq_refcount == 0)) { + if (IS_IGDNG(dev)) + igdng_disable_graphics_irq(dev_priv, GT_USER_INTERRUPT); + else + i915_disable_irq(dev_priv, I915_USER_INTERRUPT); + } spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); } @@ -455,6 +548,9 @@ int i915_enable_vblank(struct drm_device *dev, int pipe) if (!(pipeconf & PIPEACONF_ENABLE)) return -EINVAL; + if (IS_IGDNG(dev)) + return 0; + spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); if (IS_I965G(dev)) i915_enable_pipestat(dev_priv, pipe, @@ -474,6 +570,9 @@ void i915_disable_vblank(struct drm_device *dev, int pipe) drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; unsigned long irqflags; + if (IS_IGDNG(dev)) + return; + spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); i915_disable_pipestat(dev_priv, pipe, PIPE_VBLANK_INTERRUPT_ENABLE | @@ -484,7 +583,9 @@ void i915_disable_vblank(struct drm_device *dev, int pipe) void i915_enable_interrupt (struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - opregion_enable_asle(dev); + + if (!IS_IGDNG(dev)) + opregion_enable_asle(dev); dev_priv->irq_enabled = 1; } @@ -545,12 +646,65 @@ int i915_vblank_swap(struct drm_device *dev, void *data, /* drm_dma.h hooks */ +static void igdng_irq_preinstall(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + + I915_WRITE(HWSTAM, 0xeffe); + + /* XXX hotplug from PCH */ + + I915_WRITE(DEIMR, 0xffffffff); + I915_WRITE(DEIER, 0x0); + (void) I915_READ(DEIER); + + /* and GT */ + I915_WRITE(GTIMR, 0xffffffff); + I915_WRITE(GTIER, 0x0); + (void) I915_READ(GTIER); +} + +static int igdng_irq_postinstall(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + /* enable kind of interrupts always enabled */ + u32 display_mask = DE_MASTER_IRQ_CONTROL /*| DE_PCH_EVENT */; + u32 render_mask = GT_USER_INTERRUPT; + + dev_priv->irq_mask_reg = ~display_mask; + dev_priv->de_irq_enable_reg = display_mask; + + /* should always can generate irq */ + I915_WRITE(DEIIR, I915_READ(DEIIR)); + I915_WRITE(DEIMR, dev_priv->irq_mask_reg); + I915_WRITE(DEIER, dev_priv->de_irq_enable_reg); + (void) I915_READ(DEIER); + + /* user interrupt should be enabled, but masked initial */ + dev_priv->gt_irq_mask_reg = 0xffffffff; + dev_priv->gt_irq_enable_reg = render_mask; + + I915_WRITE(GTIIR, I915_READ(GTIIR)); + I915_WRITE(GTIMR, dev_priv->gt_irq_mask_reg); + I915_WRITE(GTIER, dev_priv->gt_irq_enable_reg); + (void) I915_READ(GTIER); + + return 0; +} + void i915_driver_irq_preinstall(struct drm_device * dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; atomic_set(&dev_priv->irq_received, 0); + INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func); + + if (IS_IGDNG(dev)) { + igdng_irq_preinstall(dev); + return; + } + if (I915_HAS_HOTPLUG(dev)) { I915_WRITE(PORT_HOTPLUG_EN, 0); I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); @@ -562,7 +716,6 @@ void i915_driver_irq_preinstall(struct drm_device * dev) I915_WRITE(IMR, 0xffffffff); I915_WRITE(IER, 0x0); (void) I915_READ(IER); - INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func); } int i915_driver_irq_postinstall(struct drm_device *dev) @@ -570,9 +723,12 @@ int i915_driver_irq_postinstall(struct drm_device *dev) drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; u32 enable_mask = I915_INTERRUPT_ENABLE_FIX | I915_INTERRUPT_ENABLE_VAR; + DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); + dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B; - dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ + if (IS_IGDNG(dev)) + return igdng_irq_postinstall(dev); /* Unmask the interrupts that we always want on. */ dev_priv->irq_mask_reg = ~I915_INTERRUPT_ENABLE_FIX; @@ -613,11 +769,24 @@ int i915_driver_irq_postinstall(struct drm_device *dev) (void) I915_READ(IER); opregion_enable_asle(dev); - DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); return 0; } +static void igdng_irq_uninstall(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + I915_WRITE(HWSTAM, 0xffffffff); + + I915_WRITE(DEIMR, 0xffffffff); + I915_WRITE(DEIER, 0x0); + I915_WRITE(DEIIR, I915_READ(DEIIR)); + + I915_WRITE(GTIMR, 0xffffffff); + I915_WRITE(GTIER, 0x0); + I915_WRITE(GTIIR, I915_READ(GTIIR)); +} + void i915_driver_irq_uninstall(struct drm_device * dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; @@ -627,6 +796,11 @@ void i915_driver_irq_uninstall(struct drm_device * dev) dev_priv->vblank_pipe = 0; + if (IS_IGDNG(dev)) { + igdng_irq_uninstall(dev); + return; + } + if (I915_HAS_HOTPLUG(dev)) { I915_WRITE(PORT_HOTPLUG_EN, 0); I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); diff --git a/drivers/gpu/drm/i915/i915_mem.c b/drivers/gpu/drm/i915/i915_mem.c index 96e271986d2a..83b7b81bb2b8 100644 --- a/drivers/gpu/drm/i915/i915_mem.c +++ b/drivers/gpu/drm/i915/i915_mem.c @@ -94,8 +94,8 @@ static struct mem_block *split_block(struct mem_block *p, int start, int size, { /* Maybe cut off the start of an existing block */ if (start > p->start) { - struct mem_block *newblock = - drm_alloc(sizeof(*newblock), DRM_MEM_BUFLISTS); + struct mem_block *newblock = kmalloc(sizeof(*newblock), + GFP_KERNEL); if (!newblock) goto out; newblock->start = start; @@ -111,8 +111,8 @@ static struct mem_block *split_block(struct mem_block *p, int start, int size, /* Maybe cut off the end of an existing block */ if (size < p->size) { - struct mem_block *newblock = - drm_alloc(sizeof(*newblock), DRM_MEM_BUFLISTS); + struct mem_block *newblock = kmalloc(sizeof(*newblock), + GFP_KERNEL); if (!newblock) goto out; newblock->start = start + size; @@ -169,7 +169,7 @@ static void free_block(struct mem_block *p) p->size += q->size; p->next = q->next; p->next->prev = p; - drm_free(q, sizeof(*q), DRM_MEM_BUFLISTS); + kfree(q); } if (p->prev->file_priv == NULL) { @@ -177,7 +177,7 @@ static void free_block(struct mem_block *p) q->size += p->size; q->next = p->next; q->next->prev = q; - drm_free(p, sizeof(*q), DRM_MEM_BUFLISTS); + kfree(p); } } @@ -185,14 +185,14 @@ static void free_block(struct mem_block *p) */ static int init_heap(struct mem_block **heap, int start, int size) { - struct mem_block *blocks = drm_alloc(sizeof(*blocks), DRM_MEM_BUFLISTS); + struct mem_block *blocks = kmalloc(sizeof(*blocks), GFP_KERNEL); if (!blocks) return -ENOMEM; - *heap = drm_alloc(sizeof(**heap), DRM_MEM_BUFLISTS); + *heap = kmalloc(sizeof(**heap), GFP_KERNEL); if (!*heap) { - drm_free(blocks, sizeof(*blocks), DRM_MEM_BUFLISTS); + kfree(blocks); return -ENOMEM; } @@ -233,7 +233,7 @@ void i915_mem_release(struct drm_device * dev, struct drm_file *file_priv, p->size += q->size; p->next = q->next; p->next->prev = p; - drm_free(q, sizeof(*q), DRM_MEM_BUFLISTS); + kfree(q); } } } @@ -250,10 +250,10 @@ void i915_mem_takedown(struct mem_block **heap) for (p = (*heap)->next; p != *heap;) { struct mem_block *q = p; p = p->next; - drm_free(q, sizeof(*q), DRM_MEM_BUFLISTS); + kfree(q); } - drm_free(*heap, sizeof(**heap), DRM_MEM_BUFLISTS); + kfree(*heap); *heap = NULL; } diff --git a/drivers/gpu/drm/i915/i915_opregion.c b/drivers/gpu/drm/i915/i915_opregion.c index dc425e74a268..e4b4e8898e39 100644 --- a/drivers/gpu/drm/i915/i915_opregion.c +++ b/drivers/gpu/drm/i915/i915_opregion.c @@ -419,7 +419,7 @@ void intel_opregion_free(struct drm_device *dev, int suspend) return; if (!suspend) - acpi_video_exit(); + acpi_video_unregister(); opregion->acpi->drdy = 0; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 375569d01d01..f6237a0b1133 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -450,6 +450,13 @@ #define PLLB_REF_INPUT_SPREADSPECTRUMIN (3 << 13) #define PLL_REF_INPUT_MASK (3 << 13) #define PLL_LOAD_PULSE_PHASE_SHIFT 9 +/* IGDNG */ +# define PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT 9 +# define PLL_REF_SDVO_HDMI_MULTIPLIER_MASK (7 << 9) +# define PLL_REF_SDVO_HDMI_MULTIPLIER(x) (((x)-1) << 9) +# define DPLL_FPA1_P1_POST_DIV_SHIFT 0 +# define DPLL_FPA1_P1_POST_DIV_MASK 0xff + /* * Parallel to Serial Load Pulse phase selection. * Selects the phase for the 10X DPLL clock for the PCIe @@ -631,8 +638,11 @@ /* Hotplug control (945+ only) */ #define PORT_HOTPLUG_EN 0x61110 #define HDMIB_HOTPLUG_INT_EN (1 << 29) +#define DPB_HOTPLUG_INT_EN (1 << 29) #define HDMIC_HOTPLUG_INT_EN (1 << 28) +#define DPC_HOTPLUG_INT_EN (1 << 28) #define HDMID_HOTPLUG_INT_EN (1 << 27) +#define DPD_HOTPLUG_INT_EN (1 << 27) #define SDVOB_HOTPLUG_INT_EN (1 << 26) #define SDVOC_HOTPLUG_INT_EN (1 << 25) #define TV_HOTPLUG_INT_EN (1 << 18) @@ -665,8 +675,11 @@ #define PORT_HOTPLUG_STAT 0x61114 #define HDMIB_HOTPLUG_INT_STATUS (1 << 29) +#define DPB_HOTPLUG_INT_STATUS (1 << 29) #define HDMIC_HOTPLUG_INT_STATUS (1 << 28) +#define DPC_HOTPLUG_INT_STATUS (1 << 28) #define HDMID_HOTPLUG_INT_STATUS (1 << 27) +#define DPD_HOTPLUG_INT_STATUS (1 << 27) #define CRT_HOTPLUG_INT_STATUS (1 << 11) #define TV_HOTPLUG_INT_STATUS (1 << 10) #define CRT_HOTPLUG_MONITOR_MASK (3 << 8) @@ -951,15 +964,15 @@ # define DAC_A_1_3_V (0 << 4) # define DAC_A_1_1_V (1 << 4) # define DAC_A_0_7_V (2 << 4) -# define DAC_A_OFF (3 << 4) +# define DAC_A_MASK (3 << 4) # define DAC_B_1_3_V (0 << 2) # define DAC_B_1_1_V (1 << 2) # define DAC_B_0_7_V (2 << 2) -# define DAC_B_OFF (3 << 2) +# define DAC_B_MASK (3 << 2) # define DAC_C_1_3_V (0 << 0) # define DAC_C_1_1_V (1 << 0) # define DAC_C_0_7_V (2 << 0) -# define DAC_C_OFF (3 << 0) +# define DAC_C_MASK (3 << 0) /** * CSC coefficients are stored in a floating point format with 9 bits of @@ -1328,6 +1341,163 @@ #define TV_V_CHROMA_0 0x68400 #define TV_V_CHROMA_42 0x684a8 +/* Display Port */ +#define DP_B 0x64100 +#define DP_C 0x64200 +#define DP_D 0x64300 + +#define DP_PORT_EN (1 << 31) +#define DP_PIPEB_SELECT (1 << 30) + +/* Link training mode - select a suitable mode for each stage */ +#define DP_LINK_TRAIN_PAT_1 (0 << 28) +#define DP_LINK_TRAIN_PAT_2 (1 << 28) +#define DP_LINK_TRAIN_PAT_IDLE (2 << 28) +#define DP_LINK_TRAIN_OFF (3 << 28) +#define DP_LINK_TRAIN_MASK (3 << 28) +#define DP_LINK_TRAIN_SHIFT 28 + +/* Signal voltages. These are mostly controlled by the other end */ +#define DP_VOLTAGE_0_4 (0 << 25) +#define DP_VOLTAGE_0_6 (1 << 25) +#define DP_VOLTAGE_0_8 (2 << 25) +#define DP_VOLTAGE_1_2 (3 << 25) +#define DP_VOLTAGE_MASK (7 << 25) +#define DP_VOLTAGE_SHIFT 25 + +/* Signal pre-emphasis levels, like voltages, the other end tells us what + * they want + */ +#define DP_PRE_EMPHASIS_0 (0 << 22) +#define DP_PRE_EMPHASIS_3_5 (1 << 22) +#define DP_PRE_EMPHASIS_6 (2 << 22) +#define DP_PRE_EMPHASIS_9_5 (3 << 22) +#define DP_PRE_EMPHASIS_MASK (7 << 22) +#define DP_PRE_EMPHASIS_SHIFT 22 + +/* How many wires to use. I guess 3 was too hard */ +#define DP_PORT_WIDTH_1 (0 << 19) +#define DP_PORT_WIDTH_2 (1 << 19) +#define DP_PORT_WIDTH_4 (3 << 19) +#define DP_PORT_WIDTH_MASK (7 << 19) + +/* Mystic DPCD version 1.1 special mode */ +#define DP_ENHANCED_FRAMING (1 << 18) + +/** locked once port is enabled */ +#define DP_PORT_REVERSAL (1 << 15) + +/** sends the clock on lane 15 of the PEG for debug */ +#define DP_CLOCK_OUTPUT_ENABLE (1 << 13) + +#define DP_SCRAMBLING_DISABLE (1 << 12) + +/** limit RGB values to avoid confusing TVs */ +#define DP_COLOR_RANGE_16_235 (1 << 8) + +/** Turn on the audio link */ +#define DP_AUDIO_OUTPUT_ENABLE (1 << 6) + +/** vs and hs sync polarity */ +#define DP_SYNC_VS_HIGH (1 << 4) +#define DP_SYNC_HS_HIGH (1 << 3) + +/** A fantasy */ +#define DP_DETECTED (1 << 2) + +/** The aux channel provides a way to talk to the + * signal sink for DDC etc. Max packet size supported + * is 20 bytes in each direction, hence the 5 fixed + * data registers + */ +#define DPB_AUX_CH_CTL 0x64110 +#define DPB_AUX_CH_DATA1 0x64114 +#define DPB_AUX_CH_DATA2 0x64118 +#define DPB_AUX_CH_DATA3 0x6411c +#define DPB_AUX_CH_DATA4 0x64120 +#define DPB_AUX_CH_DATA5 0x64124 + +#define DPC_AUX_CH_CTL 0x64210 +#define DPC_AUX_CH_DATA1 0x64214 +#define DPC_AUX_CH_DATA2 0x64218 +#define DPC_AUX_CH_DATA3 0x6421c +#define DPC_AUX_CH_DATA4 0x64220 +#define DPC_AUX_CH_DATA5 0x64224 + +#define DPD_AUX_CH_CTL 0x64310 +#define DPD_AUX_CH_DATA1 0x64314 +#define DPD_AUX_CH_DATA2 0x64318 +#define DPD_AUX_CH_DATA3 0x6431c +#define DPD_AUX_CH_DATA4 0x64320 +#define DPD_AUX_CH_DATA5 0x64324 + +#define DP_AUX_CH_CTL_SEND_BUSY (1 << 31) +#define DP_AUX_CH_CTL_DONE (1 << 30) +#define DP_AUX_CH_CTL_INTERRUPT (1 << 29) +#define DP_AUX_CH_CTL_TIME_OUT_ERROR (1 << 28) +#define DP_AUX_CH_CTL_TIME_OUT_400us (0 << 26) +#define DP_AUX_CH_CTL_TIME_OUT_600us (1 << 26) +#define DP_AUX_CH_CTL_TIME_OUT_800us (2 << 26) +#define DP_AUX_CH_CTL_TIME_OUT_1600us (3 << 26) +#define DP_AUX_CH_CTL_TIME_OUT_MASK (3 << 26) +#define DP_AUX_CH_CTL_RECEIVE_ERROR (1 << 25) +#define DP_AUX_CH_CTL_MESSAGE_SIZE_MASK (0x1f << 20) +#define DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT 20 +#define DP_AUX_CH_CTL_PRECHARGE_2US_MASK (0xf << 16) +#define DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT 16 +#define DP_AUX_CH_CTL_AUX_AKSV_SELECT (1 << 15) +#define DP_AUX_CH_CTL_MANCHESTER_TEST (1 << 14) +#define DP_AUX_CH_CTL_SYNC_TEST (1 << 13) +#define DP_AUX_CH_CTL_DEGLITCH_TEST (1 << 12) +#define DP_AUX_CH_CTL_PRECHARGE_TEST (1 << 11) +#define DP_AUX_CH_CTL_BIT_CLOCK_2X_MASK (0x7ff) +#define DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT 0 + +/* + * Computing GMCH M and N values for the Display Port link + * + * GMCH M/N = dot clock * bytes per pixel / ls_clk * # of lanes + * + * ls_clk (we assume) is the DP link clock (1.62 or 2.7 GHz) + * + * The GMCH value is used internally + * + * bytes_per_pixel is the number of bytes coming out of the plane, + * which is after the LUTs, so we want the bytes for our color format. + * For our current usage, this is always 3, one byte for R, G and B. + */ +#define PIPEA_GMCH_DATA_M 0x70050 +#define PIPEB_GMCH_DATA_M 0x71050 + +/* Transfer unit size for display port - 1, default is 0x3f (for TU size 64) */ +#define PIPE_GMCH_DATA_M_TU_SIZE_MASK (0x3f << 25) +#define PIPE_GMCH_DATA_M_TU_SIZE_SHIFT 25 + +#define PIPE_GMCH_DATA_M_MASK (0xffffff) + +#define PIPEA_GMCH_DATA_N 0x70054 +#define PIPEB_GMCH_DATA_N 0x71054 +#define PIPE_GMCH_DATA_N_MASK (0xffffff) + +/* + * Computing Link M and N values for the Display Port link + * + * Link M / N = pixel_clock / ls_clk + * + * (the DP spec calls pixel_clock the 'strm_clk') + * + * The Link value is transmitted in the Main Stream + * Attributes and VB-ID. + */ + +#define PIPEA_DP_LINK_M 0x70060 +#define PIPEB_DP_LINK_M 0x71060 +#define PIPEA_DP_LINK_M_MASK (0xffffff) + +#define PIPEA_DP_LINK_N 0x70064 +#define PIPEB_DP_LINK_N 0x71064 +#define PIPEA_DP_LINK_N_MASK (0xffffff) + /* Display & cursor control */ /* Pipe A */ @@ -1517,4 +1687,444 @@ # define VGA_2X_MODE (1 << 30) # define VGA_PIPE_B_SELECT (1 << 29) +/* IGDNG */ + +#define CPU_VGACNTRL 0x41000 + +#define DIGITAL_PORT_HOTPLUG_CNTRL 0x44030 +#define DIGITAL_PORTA_HOTPLUG_ENABLE (1 << 4) +#define DIGITAL_PORTA_SHORT_PULSE_2MS (0 << 2) +#define DIGITAL_PORTA_SHORT_PULSE_4_5MS (1 << 2) +#define DIGITAL_PORTA_SHORT_PULSE_6MS (2 << 2) +#define DIGITAL_PORTA_SHORT_PULSE_100MS (3 << 2) +#define DIGITAL_PORTA_NO_DETECT (0 << 0) +#define DIGITAL_PORTA_LONG_PULSE_DETECT_MASK (1 << 1) +#define DIGITAL_PORTA_SHORT_PULSE_DETECT_MASK (1 << 0) + +/* refresh rate hardware control */ +#define RR_HW_CTL 0x45300 +#define RR_HW_LOW_POWER_FRAMES_MASK 0xff +#define RR_HW_HIGH_POWER_FRAMES_MASK 0xff00 + +#define FDI_PLL_BIOS_0 0x46000 +#define FDI_PLL_BIOS_1 0x46004 +#define FDI_PLL_BIOS_2 0x46008 +#define DISPLAY_PORT_PLL_BIOS_0 0x4600c +#define DISPLAY_PORT_PLL_BIOS_1 0x46010 +#define DISPLAY_PORT_PLL_BIOS_2 0x46014 + +#define FDI_PLL_FREQ_CTL 0x46030 +#define FDI_PLL_FREQ_CHANGE_REQUEST (1<<24) +#define FDI_PLL_FREQ_LOCK_LIMIT_MASK 0xfff00 +#define FDI_PLL_FREQ_DISABLE_COUNT_LIMIT_MASK 0xff + + +#define PIPEA_DATA_M1 0x60030 +#define TU_SIZE(x) (((x)-1) << 25) /* default size 64 */ +#define TU_SIZE_MASK 0x7e000000 +#define PIPEA_DATA_M1_OFFSET 0 +#define PIPEA_DATA_N1 0x60034 +#define PIPEA_DATA_N1_OFFSET 0 + +#define PIPEA_DATA_M2 0x60038 +#define PIPEA_DATA_M2_OFFSET 0 +#define PIPEA_DATA_N2 0x6003c +#define PIPEA_DATA_N2_OFFSET 0 + +#define PIPEA_LINK_M1 0x60040 +#define PIPEA_LINK_M1_OFFSET 0 +#define PIPEA_LINK_N1 0x60044 +#define PIPEA_LINK_N1_OFFSET 0 + +#define PIPEA_LINK_M2 0x60048 +#define PIPEA_LINK_M2_OFFSET 0 +#define PIPEA_LINK_N2 0x6004c +#define PIPEA_LINK_N2_OFFSET 0 + +/* PIPEB timing regs are same start from 0x61000 */ + +#define PIPEB_DATA_M1 0x61030 +#define PIPEB_DATA_M1_OFFSET 0 +#define PIPEB_DATA_N1 0x61034 +#define PIPEB_DATA_N1_OFFSET 0 + +#define PIPEB_DATA_M2 0x61038 +#define PIPEB_DATA_M2_OFFSET 0 +#define PIPEB_DATA_N2 0x6103c +#define PIPEB_DATA_N2_OFFSET 0 + +#define PIPEB_LINK_M1 0x61040 +#define PIPEB_LINK_M1_OFFSET 0 +#define PIPEB_LINK_N1 0x61044 +#define PIPEB_LINK_N1_OFFSET 0 + +#define PIPEB_LINK_M2 0x61048 +#define PIPEB_LINK_M2_OFFSET 0 +#define PIPEB_LINK_N2 0x6104c +#define PIPEB_LINK_N2_OFFSET 0 + +/* CPU panel fitter */ +#define PFA_CTL_1 0x68080 +#define PFB_CTL_1 0x68880 +#define PF_ENABLE (1<<31) + +/* legacy palette */ +#define LGC_PALETTE_A 0x4a000 +#define LGC_PALETTE_B 0x4a800 + +/* interrupts */ +#define DE_MASTER_IRQ_CONTROL (1 << 31) +#define DE_SPRITEB_FLIP_DONE (1 << 29) +#define DE_SPRITEA_FLIP_DONE (1 << 28) +#define DE_PLANEB_FLIP_DONE (1 << 27) +#define DE_PLANEA_FLIP_DONE (1 << 26) +#define DE_PCU_EVENT (1 << 25) +#define DE_GTT_FAULT (1 << 24) +#define DE_POISON (1 << 23) +#define DE_PERFORM_COUNTER (1 << 22) +#define DE_PCH_EVENT (1 << 21) +#define DE_AUX_CHANNEL_A (1 << 20) +#define DE_DP_A_HOTPLUG (1 << 19) +#define DE_GSE (1 << 18) +#define DE_PIPEB_VBLANK (1 << 15) +#define DE_PIPEB_EVEN_FIELD (1 << 14) +#define DE_PIPEB_ODD_FIELD (1 << 13) +#define DE_PIPEB_LINE_COMPARE (1 << 12) +#define DE_PIPEB_VSYNC (1 << 11) +#define DE_PIPEB_FIFO_UNDERRUN (1 << 8) +#define DE_PIPEA_VBLANK (1 << 7) +#define DE_PIPEA_EVEN_FIELD (1 << 6) +#define DE_PIPEA_ODD_FIELD (1 << 5) +#define DE_PIPEA_LINE_COMPARE (1 << 4) +#define DE_PIPEA_VSYNC (1 << 3) +#define DE_PIPEA_FIFO_UNDERRUN (1 << 0) + +#define DEISR 0x44000 +#define DEIMR 0x44004 +#define DEIIR 0x44008 +#define DEIER 0x4400c + +/* GT interrupt */ +#define GT_SYNC_STATUS (1 << 2) +#define GT_USER_INTERRUPT (1 << 0) + +#define GTISR 0x44010 +#define GTIMR 0x44014 +#define GTIIR 0x44018 +#define GTIER 0x4401c + +/* PCH */ + +/* south display engine interrupt */ +#define SDE_CRT_HOTPLUG (1 << 11) +#define SDE_PORTD_HOTPLUG (1 << 10) +#define SDE_PORTC_HOTPLUG (1 << 9) +#define SDE_PORTB_HOTPLUG (1 << 8) +#define SDE_SDVOB_HOTPLUG (1 << 6) + +#define SDEISR 0xc4000 +#define SDEIMR 0xc4004 +#define SDEIIR 0xc4008 +#define SDEIER 0xc400c + +/* digital port hotplug */ +#define PCH_PORT_HOTPLUG 0xc4030 +#define PORTD_HOTPLUG_ENABLE (1 << 20) +#define PORTD_PULSE_DURATION_2ms (0) +#define PORTD_PULSE_DURATION_4_5ms (1 << 18) +#define PORTD_PULSE_DURATION_6ms (2 << 18) +#define PORTD_PULSE_DURATION_100ms (3 << 18) +#define PORTD_HOTPLUG_NO_DETECT (0) +#define PORTD_HOTPLUG_SHORT_DETECT (1 << 16) +#define PORTD_HOTPLUG_LONG_DETECT (1 << 17) +#define PORTC_HOTPLUG_ENABLE (1 << 12) +#define PORTC_PULSE_DURATION_2ms (0) +#define PORTC_PULSE_DURATION_4_5ms (1 << 10) +#define PORTC_PULSE_DURATION_6ms (2 << 10) +#define PORTC_PULSE_DURATION_100ms (3 << 10) +#define PORTC_HOTPLUG_NO_DETECT (0) +#define PORTC_HOTPLUG_SHORT_DETECT (1 << 8) +#define PORTC_HOTPLUG_LONG_DETECT (1 << 9) +#define PORTB_HOTPLUG_ENABLE (1 << 4) +#define PORTB_PULSE_DURATION_2ms (0) +#define PORTB_PULSE_DURATION_4_5ms (1 << 2) +#define PORTB_PULSE_DURATION_6ms (2 << 2) +#define PORTB_PULSE_DURATION_100ms (3 << 2) +#define PORTB_HOTPLUG_NO_DETECT (0) +#define PORTB_HOTPLUG_SHORT_DETECT (1 << 0) +#define PORTB_HOTPLUG_LONG_DETECT (1 << 1) + +#define PCH_GPIOA 0xc5010 +#define PCH_GPIOB 0xc5014 +#define PCH_GPIOC 0xc5018 +#define PCH_GPIOD 0xc501c +#define PCH_GPIOE 0xc5020 +#define PCH_GPIOF 0xc5024 + +#define PCH_DPLL_A 0xc6014 +#define PCH_DPLL_B 0xc6018 + +#define PCH_FPA0 0xc6040 +#define PCH_FPA1 0xc6044 +#define PCH_FPB0 0xc6048 +#define PCH_FPB1 0xc604c + +#define PCH_DPLL_TEST 0xc606c + +#define PCH_DREF_CONTROL 0xC6200 +#define DREF_CONTROL_MASK 0x7fc3 +#define DREF_CPU_SOURCE_OUTPUT_DISABLE (0<<13) +#define DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD (2<<13) +#define DREF_CPU_SOURCE_OUTPUT_NONSPREAD (3<<13) +#define DREF_CPU_SOURCE_OUTPUT_MASK (3<<13) +#define DREF_SSC_SOURCE_DISABLE (0<<11) +#define DREF_SSC_SOURCE_ENABLE (2<<11) +#define DREF_SSC_SOURCE_MASK (2<<11) +#define DREF_NONSPREAD_SOURCE_DISABLE (0<<9) +#define DREF_NONSPREAD_CK505_ENABLE (1<<9) +#define DREF_NONSPREAD_SOURCE_ENABLE (2<<9) +#define DREF_NONSPREAD_SOURCE_MASK (2<<9) +#define DREF_SUPERSPREAD_SOURCE_DISABLE (0<<7) +#define DREF_SUPERSPREAD_SOURCE_ENABLE (2<<7) +#define DREF_SSC4_DOWNSPREAD (0<<6) +#define DREF_SSC4_CENTERSPREAD (1<<6) +#define DREF_SSC1_DISABLE (0<<1) +#define DREF_SSC1_ENABLE (1<<1) +#define DREF_SSC4_DISABLE (0) +#define DREF_SSC4_ENABLE (1) + +#define PCH_RAWCLK_FREQ 0xc6204 +#define FDL_TP1_TIMER_SHIFT 12 +#define FDL_TP1_TIMER_MASK (3<<12) +#define FDL_TP2_TIMER_SHIFT 10 +#define FDL_TP2_TIMER_MASK (3<<10) +#define RAWCLK_FREQ_MASK 0x3ff + +#define PCH_DPLL_TMR_CFG 0xc6208 + +#define PCH_SSC4_PARMS 0xc6210 +#define PCH_SSC4_AUX_PARMS 0xc6214 + +/* transcoder */ + +#define TRANS_HTOTAL_A 0xe0000 +#define TRANS_HTOTAL_SHIFT 16 +#define TRANS_HACTIVE_SHIFT 0 +#define TRANS_HBLANK_A 0xe0004 +#define TRANS_HBLANK_END_SHIFT 16 +#define TRANS_HBLANK_START_SHIFT 0 +#define TRANS_HSYNC_A 0xe0008 +#define TRANS_HSYNC_END_SHIFT 16 +#define TRANS_HSYNC_START_SHIFT 0 +#define TRANS_VTOTAL_A 0xe000c +#define TRANS_VTOTAL_SHIFT 16 +#define TRANS_VACTIVE_SHIFT 0 +#define TRANS_VBLANK_A 0xe0010 +#define TRANS_VBLANK_END_SHIFT 16 +#define TRANS_VBLANK_START_SHIFT 0 +#define TRANS_VSYNC_A 0xe0014 +#define TRANS_VSYNC_END_SHIFT 16 +#define TRANS_VSYNC_START_SHIFT 0 + +#define TRANSA_DATA_M1 0xe0030 +#define TRANSA_DATA_N1 0xe0034 +#define TRANSA_DATA_M2 0xe0038 +#define TRANSA_DATA_N2 0xe003c +#define TRANSA_DP_LINK_M1 0xe0040 +#define TRANSA_DP_LINK_N1 0xe0044 +#define TRANSA_DP_LINK_M2 0xe0048 +#define TRANSA_DP_LINK_N2 0xe004c + +#define TRANS_HTOTAL_B 0xe1000 +#define TRANS_HBLANK_B 0xe1004 +#define TRANS_HSYNC_B 0xe1008 +#define TRANS_VTOTAL_B 0xe100c +#define TRANS_VBLANK_B 0xe1010 +#define TRANS_VSYNC_B 0xe1014 + +#define TRANSB_DATA_M1 0xe1030 +#define TRANSB_DATA_N1 0xe1034 +#define TRANSB_DATA_M2 0xe1038 +#define TRANSB_DATA_N2 0xe103c +#define TRANSB_DP_LINK_M1 0xe1040 +#define TRANSB_DP_LINK_N1 0xe1044 +#define TRANSB_DP_LINK_M2 0xe1048 +#define TRANSB_DP_LINK_N2 0xe104c + +#define TRANSACONF 0xf0008 +#define TRANSBCONF 0xf1008 +#define TRANS_DISABLE (0<<31) +#define TRANS_ENABLE (1<<31) +#define TRANS_STATE_MASK (1<<30) +#define TRANS_STATE_DISABLE (0<<30) +#define TRANS_STATE_ENABLE (1<<30) +#define TRANS_FSYNC_DELAY_HB1 (0<<27) +#define TRANS_FSYNC_DELAY_HB2 (1<<27) +#define TRANS_FSYNC_DELAY_HB3 (2<<27) +#define TRANS_FSYNC_DELAY_HB4 (3<<27) +#define TRANS_DP_AUDIO_ONLY (1<<26) +#define TRANS_DP_VIDEO_AUDIO (0<<26) +#define TRANS_PROGRESSIVE (0<<21) +#define TRANS_8BPC (0<<5) +#define TRANS_10BPC (1<<5) +#define TRANS_6BPC (2<<5) +#define TRANS_12BPC (3<<5) + +#define FDI_RXA_CHICKEN 0xc200c +#define FDI_RXB_CHICKEN 0xc2010 +#define FDI_RX_PHASE_SYNC_POINTER_ENABLE (1) + +/* CPU: FDI_TX */ +#define FDI_TXA_CTL 0x60100 +#define FDI_TXB_CTL 0x61100 +#define FDI_TX_DISABLE (0<<31) +#define FDI_TX_ENABLE (1<<31) +#define FDI_LINK_TRAIN_PATTERN_1 (0<<28) +#define FDI_LINK_TRAIN_PATTERN_2 (1<<28) +#define FDI_LINK_TRAIN_PATTERN_IDLE (2<<28) +#define FDI_LINK_TRAIN_NONE (3<<28) +#define FDI_LINK_TRAIN_VOLTAGE_0_4V (0<<25) +#define FDI_LINK_TRAIN_VOLTAGE_0_6V (1<<25) +#define FDI_LINK_TRAIN_VOLTAGE_0_8V (2<<25) +#define FDI_LINK_TRAIN_VOLTAGE_1_2V (3<<25) +#define FDI_LINK_TRAIN_PRE_EMPHASIS_NONE (0<<22) +#define FDI_LINK_TRAIN_PRE_EMPHASIS_1_5X (1<<22) +#define FDI_LINK_TRAIN_PRE_EMPHASIS_2X (2<<22) +#define FDI_LINK_TRAIN_PRE_EMPHASIS_3X (3<<22) +#define FDI_DP_PORT_WIDTH_X1 (0<<19) +#define FDI_DP_PORT_WIDTH_X2 (1<<19) +#define FDI_DP_PORT_WIDTH_X3 (2<<19) +#define FDI_DP_PORT_WIDTH_X4 (3<<19) +#define FDI_TX_ENHANCE_FRAME_ENABLE (1<<18) +/* IGDNG: hardwired to 1 */ +#define FDI_TX_PLL_ENABLE (1<<14) +/* both Tx and Rx */ +#define FDI_SCRAMBLING_ENABLE (0<<7) +#define FDI_SCRAMBLING_DISABLE (1<<7) + +/* FDI_RX, FDI_X is hard-wired to Transcoder_X */ +#define FDI_RXA_CTL 0xf000c +#define FDI_RXB_CTL 0xf100c +#define FDI_RX_ENABLE (1<<31) +#define FDI_RX_DISABLE (0<<31) +/* train, dp width same as FDI_TX */ +#define FDI_DP_PORT_WIDTH_X8 (7<<19) +#define FDI_8BPC (0<<16) +#define FDI_10BPC (1<<16) +#define FDI_6BPC (2<<16) +#define FDI_12BPC (3<<16) +#define FDI_LINK_REVERSE_OVERWRITE (1<<15) +#define FDI_DMI_LINK_REVERSE_MASK (1<<14) +#define FDI_RX_PLL_ENABLE (1<<13) +#define FDI_FS_ERR_CORRECT_ENABLE (1<<11) +#define FDI_FE_ERR_CORRECT_ENABLE (1<<10) +#define FDI_FS_ERR_REPORT_ENABLE (1<<9) +#define FDI_FE_ERR_REPORT_ENABLE (1<<8) +#define FDI_RX_ENHANCE_FRAME_ENABLE (1<<6) +#define FDI_SEL_RAWCLK (0<<4) +#define FDI_SEL_PCDCLK (1<<4) + +#define FDI_RXA_MISC 0xf0010 +#define FDI_RXB_MISC 0xf1010 +#define FDI_RXA_TUSIZE1 0xf0030 +#define FDI_RXA_TUSIZE2 0xf0038 +#define FDI_RXB_TUSIZE1 0xf1030 +#define FDI_RXB_TUSIZE2 0xf1038 + +/* FDI_RX interrupt register format */ +#define FDI_RX_INTER_LANE_ALIGN (1<<10) +#define FDI_RX_SYMBOL_LOCK (1<<9) /* train 2 */ +#define FDI_RX_BIT_LOCK (1<<8) /* train 1 */ +#define FDI_RX_TRAIN_PATTERN_2_FAIL (1<<7) +#define FDI_RX_FS_CODE_ERR (1<<6) +#define FDI_RX_FE_CODE_ERR (1<<5) +#define FDI_RX_SYMBOL_ERR_RATE_ABOVE (1<<4) +#define FDI_RX_HDCP_LINK_FAIL (1<<3) +#define FDI_RX_PIXEL_FIFO_OVERFLOW (1<<2) +#define FDI_RX_CROSS_CLOCK_OVERFLOW (1<<1) +#define FDI_RX_SYMBOL_QUEUE_OVERFLOW (1<<0) + +#define FDI_RXA_IIR 0xf0014 +#define FDI_RXA_IMR 0xf0018 +#define FDI_RXB_IIR 0xf1014 +#define FDI_RXB_IMR 0xf1018 + +#define FDI_PLL_CTL_1 0xfe000 +#define FDI_PLL_CTL_2 0xfe004 + +/* CRT */ +#define PCH_ADPA 0xe1100 +#define ADPA_TRANS_SELECT_MASK (1<<30) +#define ADPA_TRANS_A_SELECT 0 +#define ADPA_TRANS_B_SELECT (1<<30) +#define ADPA_CRT_HOTPLUG_MASK 0x03ff0000 /* bit 25-16 */ +#define ADPA_CRT_HOTPLUG_MONITOR_NONE (0<<24) +#define ADPA_CRT_HOTPLUG_MONITOR_MASK (3<<24) +#define ADPA_CRT_HOTPLUG_MONITOR_COLOR (3<<24) +#define ADPA_CRT_HOTPLUG_MONITOR_MONO (2<<24) +#define ADPA_CRT_HOTPLUG_ENABLE (1<<23) +#define ADPA_CRT_HOTPLUG_PERIOD_64 (0<<22) +#define ADPA_CRT_HOTPLUG_PERIOD_128 (1<<22) +#define ADPA_CRT_HOTPLUG_WARMUP_5MS (0<<21) +#define ADPA_CRT_HOTPLUG_WARMUP_10MS (1<<21) +#define ADPA_CRT_HOTPLUG_SAMPLE_2S (0<<20) +#define ADPA_CRT_HOTPLUG_SAMPLE_4S (1<<20) +#define ADPA_CRT_HOTPLUG_VOLTAGE_40 (0<<18) +#define ADPA_CRT_HOTPLUG_VOLTAGE_50 (1<<18) +#define ADPA_CRT_HOTPLUG_VOLTAGE_60 (2<<18) +#define ADPA_CRT_HOTPLUG_VOLTAGE_70 (3<<18) +#define ADPA_CRT_HOTPLUG_VOLREF_325MV (0<<17) +#define ADPA_CRT_HOTPLUG_VOLREF_475MV (1<<17) +#define ADPA_CRT_HOTPLUG_FORCE_TRIGGER (1<<16) + +/* or SDVOB */ +#define HDMIB 0xe1140 +#define PORT_ENABLE (1 << 31) +#define TRANSCODER_A (0) +#define TRANSCODER_B (1 << 30) +#define COLOR_FORMAT_8bpc (0) +#define COLOR_FORMAT_12bpc (3 << 26) +#define SDVOB_HOTPLUG_ENABLE (1 << 23) +#define SDVO_ENCODING (0) +#define TMDS_ENCODING (2 << 10) +#define NULL_PACKET_VSYNC_ENABLE (1 << 9) +#define SDVOB_BORDER_ENABLE (1 << 7) +#define AUDIO_ENABLE (1 << 6) +#define VSYNC_ACTIVE_HIGH (1 << 4) +#define HSYNC_ACTIVE_HIGH (1 << 3) +#define PORT_DETECTED (1 << 2) + +#define HDMIC 0xe1150 +#define HDMID 0xe1160 + +#define PCH_LVDS 0xe1180 +#define LVDS_DETECTED (1 << 1) + +#define BLC_PWM_CPU_CTL2 0x48250 +#define PWM_ENABLE (1 << 31) +#define PWM_PIPE_A (0 << 29) +#define PWM_PIPE_B (1 << 29) +#define BLC_PWM_CPU_CTL 0x48254 + +#define BLC_PWM_PCH_CTL1 0xc8250 +#define PWM_PCH_ENABLE (1 << 31) +#define PWM_POLARITY_ACTIVE_LOW (1 << 29) +#define PWM_POLARITY_ACTIVE_HIGH (0 << 29) +#define PWM_POLARITY_ACTIVE_LOW2 (1 << 28) +#define PWM_POLARITY_ACTIVE_HIGH2 (0 << 28) + +#define BLC_PWM_PCH_CTL2 0xc8254 + +#define PCH_PP_STATUS 0xc7200 +#define PCH_PP_CONTROL 0xc7204 +#define EDP_FORCE_VDD (1 << 3) +#define EDP_BLC_ENABLE (1 << 2) +#define PANEL_POWER_RESET (1 << 1) +#define PANEL_POWER_OFF (0 << 0) +#define PANEL_POWER_ON (1 << 0) +#define PCH_PP_ON_DELAYS 0xc7208 +#define EDP_PANEL (1 << 30) +#define PCH_PP_OFF_DELAYS 0xc720c +#define PCH_PP_DIVISOR 0xc7210 + #endif /* _I915_REG_H_ */ diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index ce8a21344a71..a98e2831ed31 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -295,6 +295,16 @@ int i915_save_state(struct drm_device *dev) i915_save_palette(dev, PIPE_B); dev_priv->savePIPEBSTAT = I915_READ(PIPEBSTAT); + /* Cursor state */ + dev_priv->saveCURACNTR = I915_READ(CURACNTR); + dev_priv->saveCURAPOS = I915_READ(CURAPOS); + dev_priv->saveCURABASE = I915_READ(CURABASE); + dev_priv->saveCURBCNTR = I915_READ(CURBCNTR); + dev_priv->saveCURBPOS = I915_READ(CURBPOS); + dev_priv->saveCURBBASE = I915_READ(CURBBASE); + if (!IS_I9XX(dev)) + dev_priv->saveCURSIZE = I915_READ(CURSIZE); + /* CRT state */ dev_priv->saveADPA = I915_READ(ADPA); @@ -480,6 +490,16 @@ int i915_restore_state(struct drm_device *dev) I915_WRITE(DSPBCNTR, dev_priv->saveDSPBCNTR); I915_WRITE(DSPBADDR, I915_READ(DSPBADDR)); + /* Cursor state */ + I915_WRITE(CURAPOS, dev_priv->saveCURAPOS); + I915_WRITE(CURACNTR, dev_priv->saveCURACNTR); + I915_WRITE(CURABASE, dev_priv->saveCURABASE); + I915_WRITE(CURBPOS, dev_priv->saveCURBPOS); + I915_WRITE(CURBCNTR, dev_priv->saveCURBCNTR); + I915_WRITE(CURBBASE, dev_priv->saveCURBBASE); + if (!IS_I9XX(dev)) + I915_WRITE(CURSIZE, dev_priv->saveCURSIZE); + /* CRT state */ I915_WRITE(ADPA, dev_priv->saveADPA); diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 9d78cff33b24..cdd126d068a7 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -30,6 +30,8 @@ #include "i915_drv.h" #include "intel_bios.h" +#define SLAVE_ADDR1 0x70 +#define SLAVE_ADDR2 0x72 static void * find_section(struct bdb_header *bdb, int section_id) @@ -122,8 +124,7 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv, entry = &lvds_lfp_data->data[lvds_options->panel_type]; dvo_timing = &entry->dvo_timing; - panel_fixed_mode = drm_calloc(1, sizeof(*panel_fixed_mode), - DRM_MEM_DRIVER); + panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL); fill_detail_timing_data(panel_fixed_mode, dvo_timing); @@ -154,8 +155,7 @@ parse_sdvo_panel_data(struct drm_i915_private *dev_priv, if (!dvo_timing) return; - panel_fixed_mode = drm_calloc(1, sizeof(*panel_fixed_mode), - DRM_MEM_DRIVER); + panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL); if (!panel_fixed_mode) return; @@ -193,6 +193,88 @@ parse_general_features(struct drm_i915_private *dev_priv, } } +static void +parse_sdvo_device_mapping(struct drm_i915_private *dev_priv, + struct bdb_header *bdb) +{ + struct sdvo_device_mapping *p_mapping; + struct bdb_general_definitions *p_defs; + struct child_device_config *p_child; + int i, child_device_num, count; + u16 block_size, *block_ptr; + + p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS); + if (!p_defs) { + DRM_DEBUG("No general definition block is found\n"); + return; + } + /* judge whether the size of child device meets the requirements. + * If the child device size obtained from general definition block + * is different with sizeof(struct child_device_config), skip the + * parsing of sdvo device info + */ + if (p_defs->child_dev_size != sizeof(*p_child)) { + /* different child dev size . Ignore it */ + DRM_DEBUG("different child size is found. Invalid.\n"); + return; + } + /* get the block size of general definitions */ + block_ptr = (u16 *)((char *)p_defs - 2); + block_size = *block_ptr; + /* get the number of child device */ + child_device_num = (block_size - sizeof(*p_defs)) / + sizeof(*p_child); + count = 0; + for (i = 0; i < child_device_num; i++) { + p_child = &(p_defs->devices[i]); + if (!p_child->device_type) { + /* skip the device block if device type is invalid */ + continue; + } + if (p_child->slave_addr != SLAVE_ADDR1 && + p_child->slave_addr != SLAVE_ADDR2) { + /* + * If the slave address is neither 0x70 nor 0x72, + * it is not a SDVO device. Skip it. + */ + continue; + } + if (p_child->dvo_port != DEVICE_PORT_DVOB && + p_child->dvo_port != DEVICE_PORT_DVOC) { + /* skip the incorrect SDVO port */ + DRM_DEBUG("Incorrect SDVO port. Skip it \n"); + continue; + } + DRM_DEBUG("the SDVO device with slave addr %2x is found on " + "%s port\n", + p_child->slave_addr, + (p_child->dvo_port == DEVICE_PORT_DVOB) ? + "SDVOB" : "SDVOC"); + p_mapping = &(dev_priv->sdvo_mappings[p_child->dvo_port - 1]); + if (!p_mapping->initialized) { + p_mapping->dvo_port = p_child->dvo_port; + p_mapping->slave_addr = p_child->slave_addr; + p_mapping->dvo_wiring = p_child->dvo_wiring; + p_mapping->initialized = 1; + } else { + DRM_DEBUG("Maybe one SDVO port is shared by " + "two SDVO device.\n"); + } + if (p_child->slave2_addr) { + /* Maybe this is a SDVO device with multiple inputs */ + /* And the mapping info is not added */ + DRM_DEBUG("there exists the slave2_addr. Maybe this " + "is a SDVO device with multiple inputs.\n"); + } + count++; + } + + if (!count) { + /* No SDVO device info is found */ + DRM_DEBUG("No SDVO device info is found in VBT\n"); + } + return; +} /** * intel_init_bios - initialize VBIOS settings & find VBT * @dev: DRM device @@ -242,7 +324,7 @@ intel_init_bios(struct drm_device *dev) parse_general_features(dev_priv, bdb); parse_lfp_panel_data(dev_priv, bdb); parse_sdvo_panel_data(dev_priv, bdb); - + parse_sdvo_device_mapping(dev_priv, bdb); pci_unmap_rom(pdev, bios); return 0; diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h index 8ca2cde15804..fe72e1c225d8 100644 --- a/drivers/gpu/drm/i915/intel_bios.h +++ b/drivers/gpu/drm/i915/intel_bios.h @@ -135,6 +135,86 @@ struct bdb_general_features { u8 rsvd11:6; /* finish byte */ } __attribute__((packed)); +/* pre-915 */ +#define GPIO_PIN_DVI_LVDS 0x03 /* "DVI/LVDS DDC GPIO pins" */ +#define GPIO_PIN_ADD_I2C 0x05 /* "ADDCARD I2C GPIO pins" */ +#define GPIO_PIN_ADD_DDC 0x04 /* "ADDCARD DDC GPIO pins" */ +#define GPIO_PIN_ADD_DDC_I2C 0x06 /* "ADDCARD DDC/I2C GPIO pins" */ + +/* Pre 915 */ +#define DEVICE_TYPE_NONE 0x00 +#define DEVICE_TYPE_CRT 0x01 +#define DEVICE_TYPE_TV 0x09 +#define DEVICE_TYPE_EFP 0x12 +#define DEVICE_TYPE_LFP 0x22 +/* On 915+ */ +#define DEVICE_TYPE_CRT_DPMS 0x6001 +#define DEVICE_TYPE_CRT_DPMS_HOTPLUG 0x4001 +#define DEVICE_TYPE_TV_COMPOSITE 0x0209 +#define DEVICE_TYPE_TV_MACROVISION 0x0289 +#define DEVICE_TYPE_TV_RF_COMPOSITE 0x020c +#define DEVICE_TYPE_TV_SVIDEO_COMPOSITE 0x0609 +#define DEVICE_TYPE_TV_SCART 0x0209 +#define DEVICE_TYPE_TV_CODEC_HOTPLUG_PWR 0x6009 +#define DEVICE_TYPE_EFP_HOTPLUG_PWR 0x6012 +#define DEVICE_TYPE_EFP_DVI_HOTPLUG_PWR 0x6052 +#define DEVICE_TYPE_EFP_DVI_I 0x6053 +#define DEVICE_TYPE_EFP_DVI_D_DUAL 0x6152 +#define DEVICE_TYPE_EFP_DVI_D_HDCP 0x60d2 +#define DEVICE_TYPE_OPENLDI_HOTPLUG_PWR 0x6062 +#define DEVICE_TYPE_OPENLDI_DUALPIX 0x6162 +#define DEVICE_TYPE_LFP_PANELLINK 0x5012 +#define DEVICE_TYPE_LFP_CMOS_PWR 0x5042 +#define DEVICE_TYPE_LFP_LVDS_PWR 0x5062 +#define DEVICE_TYPE_LFP_LVDS_DUAL 0x5162 +#define DEVICE_TYPE_LFP_LVDS_DUAL_HDCP 0x51e2 + +#define DEVICE_CFG_NONE 0x00 +#define DEVICE_CFG_12BIT_DVOB 0x01 +#define DEVICE_CFG_12BIT_DVOC 0x02 +#define DEVICE_CFG_24BIT_DVOBC 0x09 +#define DEVICE_CFG_24BIT_DVOCB 0x0a +#define DEVICE_CFG_DUAL_DVOB 0x11 +#define DEVICE_CFG_DUAL_DVOC 0x12 +#define DEVICE_CFG_DUAL_DVOBC 0x13 +#define DEVICE_CFG_DUAL_LINK_DVOBC 0x19 +#define DEVICE_CFG_DUAL_LINK_DVOCB 0x1a + +#define DEVICE_WIRE_NONE 0x00 +#define DEVICE_WIRE_DVOB 0x01 +#define DEVICE_WIRE_DVOC 0x02 +#define DEVICE_WIRE_DVOBC 0x03 +#define DEVICE_WIRE_DVOBB 0x05 +#define DEVICE_WIRE_DVOCC 0x06 +#define DEVICE_WIRE_DVOB_MASTER 0x0d +#define DEVICE_WIRE_DVOC_MASTER 0x0e + +#define DEVICE_PORT_DVOA 0x00 /* none on 845+ */ +#define DEVICE_PORT_DVOB 0x01 +#define DEVICE_PORT_DVOC 0x02 + +struct child_device_config { + u16 handle; + u16 device_type; + u8 device_id[10]; /* See DEVICE_TYPE_* above */ + u16 addin_offset; + u8 dvo_port; /* See Device_PORT_* above */ + u8 i2c_pin; + u8 slave_addr; + u8 ddc_pin; + u16 edid_ptr; + u8 dvo_cfg; /* See DEVICE_CFG_* above */ + u8 dvo2_port; + u8 i2c2_pin; + u8 slave2_addr; + u8 ddc2_pin; + u8 capabilities; + u8 dvo_wiring;/* See DEVICE_WIRE_* above */ + u8 dvo2_wiring; + u16 extended_type; + u8 dvo_function; +} __attribute__((packed)); + struct bdb_general_definitions { /* DDC GPIO */ u8 crt_ddc_gmbus_pin; @@ -149,14 +229,19 @@ struct bdb_general_definitions { u8 boot_display[2]; u8 child_dev_size; - /* device info */ - u8 tv_or_lvds_info[33]; - u8 dev1[33]; - u8 dev2[33]; - u8 dev3[33]; - u8 dev4[33]; - /* may be another device block here on some platforms */ -}; + /* + * Device info: + * If TV is present, it'll be at devices[0]. + * LVDS will be next, either devices[0] or [1], if present. + * On some platforms the number of device is 6. But could be as few as + * 4 if both TV and LVDS are missing. + * And the device num is related with the size of general definition + * block. It is obtained by using the following formula: + * number = (block_size - sizeof(bdb_general_definitions))/ + * sizeof(child_device_config); + */ + struct child_device_config devices[0]; +} __attribute__((packed)); struct bdb_lvds_options { u8 panel_type; diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 79acc4f4c1f8..6de97fc66029 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -37,9 +37,14 @@ static void intel_crt_dpms(struct drm_encoder *encoder, int mode) { struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; - u32 temp; + u32 temp, reg; - temp = I915_READ(ADPA); + if (IS_IGDNG(dev)) + reg = PCH_ADPA; + else + reg = ADPA; + + temp = I915_READ(reg); temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE); temp |= ADPA_DAC_ENABLE; @@ -58,7 +63,7 @@ static void intel_crt_dpms(struct drm_encoder *encoder, int mode) break; } - I915_WRITE(ADPA, temp); + I915_WRITE(reg, temp); } static int intel_crt_mode_valid(struct drm_connector *connector, @@ -101,17 +106,23 @@ static void intel_crt_mode_set(struct drm_encoder *encoder, struct drm_i915_private *dev_priv = dev->dev_private; int dpll_md_reg; u32 adpa, dpll_md; + u32 adpa_reg; if (intel_crtc->pipe == 0) dpll_md_reg = DPLL_A_MD; else dpll_md_reg = DPLL_B_MD; + if (IS_IGDNG(dev)) + adpa_reg = PCH_ADPA; + else + adpa_reg = ADPA; + /* * Disable separate mode multiplier used when cloning SDVO to CRT * XXX this needs to be adjusted when we really are cloning */ - if (IS_I965G(dev)) { + if (IS_I965G(dev) && !IS_IGDNG(dev)) { dpll_md = I915_READ(dpll_md_reg); I915_WRITE(dpll_md_reg, dpll_md & ~DPLL_MD_UDI_MULTIPLIER_MASK); @@ -125,13 +136,53 @@ static void intel_crt_mode_set(struct drm_encoder *encoder, if (intel_crtc->pipe == 0) { adpa |= ADPA_PIPE_A_SELECT; - I915_WRITE(BCLRPAT_A, 0); + if (!IS_IGDNG(dev)) + I915_WRITE(BCLRPAT_A, 0); } else { adpa |= ADPA_PIPE_B_SELECT; - I915_WRITE(BCLRPAT_B, 0); + if (!IS_IGDNG(dev)) + I915_WRITE(BCLRPAT_B, 0); } - I915_WRITE(ADPA, adpa); + I915_WRITE(adpa_reg, adpa); +} + +static bool intel_igdng_crt_detect_hotplug(struct drm_connector *connector) +{ + struct drm_device *dev = connector->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 adpa, temp; + bool ret; + + temp = adpa = I915_READ(PCH_ADPA); + + adpa &= ~ADPA_CRT_HOTPLUG_MASK; + + adpa |= (ADPA_CRT_HOTPLUG_PERIOD_128 | + ADPA_CRT_HOTPLUG_WARMUP_10MS | + ADPA_CRT_HOTPLUG_SAMPLE_4S | + ADPA_CRT_HOTPLUG_VOLTAGE_50 | /* default */ + ADPA_CRT_HOTPLUG_VOLREF_325MV | + ADPA_CRT_HOTPLUG_ENABLE | + ADPA_CRT_HOTPLUG_FORCE_TRIGGER); + + DRM_DEBUG("pch crt adpa 0x%x", adpa); + I915_WRITE(PCH_ADPA, adpa); + + /* This might not be needed as not specified in spec...*/ + udelay(1000); + + /* Check the status to see if both blue and green are on now */ + adpa = I915_READ(PCH_ADPA); + if ((adpa & ADPA_CRT_HOTPLUG_MONITOR_MASK) == + ADPA_CRT_HOTPLUG_MONITOR_COLOR) + ret = true; + else + ret = false; + + /* restore origin register */ + I915_WRITE(PCH_ADPA, temp); + return ret; } /** @@ -148,6 +199,10 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector) struct drm_i915_private *dev_priv = dev->dev_private; u32 hotplug_en; int i, tries = 0; + + if (IS_IGDNG(dev)) + return intel_igdng_crt_detect_hotplug(connector); + /* * On 4 series desktop, CRT detect sequence need to be done twice * to get a reliable result. @@ -423,6 +478,7 @@ void intel_crt_init(struct drm_device *dev) { struct drm_connector *connector; struct intel_output *intel_output; + u32 i2c_reg; intel_output = kzalloc(sizeof(struct intel_output), GFP_KERNEL); if (!intel_output) @@ -439,7 +495,11 @@ void intel_crt_init(struct drm_device *dev) &intel_output->enc); /* Set up the DDC bus. */ - intel_output->ddc_bus = intel_i2c_create(dev, GPIOA, "CRTDDC_A"); + if (IS_IGDNG(dev)) + i2c_reg = PCH_GPIOA; + else + i2c_reg = GPIOA; + intel_output->ddc_bus = intel_i2c_create(dev, i2c_reg, "CRTDDC_A"); if (!intel_output->ddc_bus) { dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration " "failed.\n"); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index c9d6f10ba92e..3e1c78162119 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -137,6 +137,8 @@ struct intel_limit { #define INTEL_LIMIT_G4X_DUAL_CHANNEL_LVDS 7 #define INTEL_LIMIT_IGD_SDVO_DAC 8 #define INTEL_LIMIT_IGD_LVDS 9 +#define INTEL_LIMIT_IGDNG_SDVO_DAC 10 +#define INTEL_LIMIT_IGDNG_LVDS 11 /*The parameter is for SDVO on G4x platform*/ #define G4X_DOT_SDVO_MIN 25000 @@ -216,12 +218,43 @@ struct intel_limit { #define G4X_P2_DUAL_CHANNEL_LVDS_FAST 7 #define G4X_P2_DUAL_CHANNEL_LVDS_LIMIT 0 +/* IGDNG */ +/* as we calculate clock using (register_value + 2) for + N/M1/M2, so here the range value for them is (actual_value-2). + */ +#define IGDNG_DOT_MIN 25000 +#define IGDNG_DOT_MAX 350000 +#define IGDNG_VCO_MIN 1760000 +#define IGDNG_VCO_MAX 3510000 +#define IGDNG_N_MIN 1 +#define IGDNG_N_MAX 5 +#define IGDNG_M_MIN 79 +#define IGDNG_M_MAX 118 +#define IGDNG_M1_MIN 12 +#define IGDNG_M1_MAX 23 +#define IGDNG_M2_MIN 5 +#define IGDNG_M2_MAX 9 +#define IGDNG_P_SDVO_DAC_MIN 5 +#define IGDNG_P_SDVO_DAC_MAX 80 +#define IGDNG_P_LVDS_MIN 28 +#define IGDNG_P_LVDS_MAX 112 +#define IGDNG_P1_MIN 1 +#define IGDNG_P1_MAX 8 +#define IGDNG_P2_SDVO_DAC_SLOW 10 +#define IGDNG_P2_SDVO_DAC_FAST 5 +#define IGDNG_P2_LVDS_SLOW 14 /* single channel */ +#define IGDNG_P2_LVDS_FAST 7 /* double channel */ +#define IGDNG_P2_DOT_LIMIT 225000 /* 225Mhz */ + static bool intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, int target, int refclk, intel_clock_t *best_clock); static bool intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, int target, int refclk, intel_clock_t *best_clock); +static bool +intel_igdng_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, + int target, int refclk, intel_clock_t *best_clock); static const intel_limit_t intel_limits[] = { { /* INTEL_LIMIT_I8XX_DVO_DAC */ @@ -383,9 +416,47 @@ static const intel_limit_t intel_limits[] = { .p2_slow = I9XX_P2_LVDS_SLOW, .p2_fast = I9XX_P2_LVDS_SLOW }, .find_pll = intel_find_best_PLL, }, - + { /* INTEL_LIMIT_IGDNG_SDVO_DAC */ + .dot = { .min = IGDNG_DOT_MIN, .max = IGDNG_DOT_MAX }, + .vco = { .min = IGDNG_VCO_MIN, .max = IGDNG_VCO_MAX }, + .n = { .min = IGDNG_N_MIN, .max = IGDNG_N_MAX }, + .m = { .min = IGDNG_M_MIN, .max = IGDNG_M_MAX }, + .m1 = { .min = IGDNG_M1_MIN, .max = IGDNG_M1_MAX }, + .m2 = { .min = IGDNG_M2_MIN, .max = IGDNG_M2_MAX }, + .p = { .min = IGDNG_P_SDVO_DAC_MIN, .max = IGDNG_P_SDVO_DAC_MAX }, + .p1 = { .min = IGDNG_P1_MIN, .max = IGDNG_P1_MAX }, + .p2 = { .dot_limit = IGDNG_P2_DOT_LIMIT, + .p2_slow = IGDNG_P2_SDVO_DAC_SLOW, + .p2_fast = IGDNG_P2_SDVO_DAC_FAST }, + .find_pll = intel_igdng_find_best_PLL, + }, + { /* INTEL_LIMIT_IGDNG_LVDS */ + .dot = { .min = IGDNG_DOT_MIN, .max = IGDNG_DOT_MAX }, + .vco = { .min = IGDNG_VCO_MIN, .max = IGDNG_VCO_MAX }, + .n = { .min = IGDNG_N_MIN, .max = IGDNG_N_MAX }, + .m = { .min = IGDNG_M_MIN, .max = IGDNG_M_MAX }, + .m1 = { .min = IGDNG_M1_MIN, .max = IGDNG_M1_MAX }, + .m2 = { .min = IGDNG_M2_MIN, .max = IGDNG_M2_MAX }, + .p = { .min = IGDNG_P_LVDS_MIN, .max = IGDNG_P_LVDS_MAX }, + .p1 = { .min = IGDNG_P1_MIN, .max = IGDNG_P1_MAX }, + .p2 = { .dot_limit = IGDNG_P2_DOT_LIMIT, + .p2_slow = IGDNG_P2_LVDS_SLOW, + .p2_fast = IGDNG_P2_LVDS_FAST }, + .find_pll = intel_igdng_find_best_PLL, + }, }; +static const intel_limit_t *intel_igdng_limit(struct drm_crtc *crtc) +{ + const intel_limit_t *limit; + if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) + limit = &intel_limits[INTEL_LIMIT_IGDNG_LVDS]; + else + limit = &intel_limits[INTEL_LIMIT_IGDNG_SDVO_DAC]; + + return limit; +} + static const intel_limit_t *intel_g4x_limit(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -418,7 +489,9 @@ static const intel_limit_t *intel_limit(struct drm_crtc *crtc) struct drm_device *dev = crtc->dev; const intel_limit_t *limit; - if (IS_G4X(dev)) { + if (IS_IGDNG(dev)) + limit = intel_igdng_limit(crtc); + else if (IS_G4X(dev)) { limit = intel_g4x_limit(crtc); } else if (IS_I9XX(dev) && !IS_IGD(dev)) { if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) @@ -630,7 +703,64 @@ intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, } } } + return found; +} +static bool +intel_igdng_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, + int target, int refclk, intel_clock_t *best_clock) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + intel_clock_t clock; + int max_n; + bool found; + int err_most = 47; + found = false; + + if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { + if ((I915_READ(LVDS) & LVDS_CLKB_POWER_MASK) == + LVDS_CLKB_POWER_UP) + clock.p2 = limit->p2.p2_fast; + else + clock.p2 = limit->p2.p2_slow; + } else { + if (target < limit->p2.dot_limit) + clock.p2 = limit->p2.p2_slow; + else + clock.p2 = limit->p2.p2_fast; + } + + memset(best_clock, 0, sizeof(*best_clock)); + max_n = limit->n.max; + /* based on hardware requriment prefer smaller n to precision */ + for (clock.n = limit->n.min; clock.n <= max_n; clock.n++) { + /* based on hardware requirment prefere larger m1,m2, p1 */ + for (clock.m1 = limit->m1.max; + clock.m1 >= limit->m1.min; clock.m1--) { + for (clock.m2 = limit->m2.max; + clock.m2 >= limit->m2.min; clock.m2--) { + for (clock.p1 = limit->p1.max; + clock.p1 >= limit->p1.min; clock.p1--) { + int this_err; + + intel_clock(dev, refclk, &clock); + if (!intel_PLL_is_valid(crtc, &clock)) + continue; + this_err = abs((10000 - (target*10000/clock.dot))); + if (this_err < err_most) { + *best_clock = clock; + err_most = this_err; + max_n = clock.n; + found = true; + /* found on first matching */ + goto out; + } + } + } + } + } +out: return found; } @@ -698,19 +828,31 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, } mutex_lock(&dev->struct_mutex); - ret = i915_gem_object_pin(intel_fb->obj, alignment); + ret = i915_gem_object_pin(obj, alignment); if (ret != 0) { mutex_unlock(&dev->struct_mutex); return ret; } - ret = i915_gem_object_set_to_gtt_domain(intel_fb->obj, 1); + ret = i915_gem_object_set_to_gtt_domain(obj, 1); if (ret != 0) { - i915_gem_object_unpin(intel_fb->obj); + i915_gem_object_unpin(obj); mutex_unlock(&dev->struct_mutex); return ret; } + /* Pre-i965 needs to install a fence for tiled scan-out */ + if (!IS_I965G(dev) && + obj_priv->fence_reg == I915_FENCE_REG_NONE && + obj_priv->tiling_mode != I915_TILING_NONE) { + ret = i915_gem_object_get_fence_reg(obj); + if (ret != 0) { + i915_gem_object_unpin(obj); + mutex_unlock(&dev->struct_mutex); + return ret; + } + } + dspcntr = I915_READ(dspcntr_reg); /* Mask out pixel format bits in case we change it */ dspcntr &= ~DISPPLANE_PIXFORMAT_MASK; @@ -730,7 +872,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, break; default: DRM_ERROR("Unknown color depth\n"); - i915_gem_object_unpin(intel_fb->obj); + i915_gem_object_unpin(obj); mutex_unlock(&dev->struct_mutex); return -EINVAL; } @@ -785,18 +927,292 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, return 0; } - - -/** - * Sets the power management mode of the pipe and plane. - * - * This code should probably grow support for turning the cursor off and back - * on appropriately at the same time as we're turning the pipe off/on. - */ -static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) +static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; + int plane = intel_crtc->pipe; + int pch_dpll_reg = (pipe == 0) ? PCH_DPLL_A : PCH_DPLL_B; + int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF; + int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR; + int dspbase_reg = (plane == 0) ? DSPAADDR : DSPBADDR; + int fdi_tx_reg = (pipe == 0) ? FDI_TXA_CTL : FDI_TXB_CTL; + int fdi_rx_reg = (pipe == 0) ? FDI_RXA_CTL : FDI_RXB_CTL; + int fdi_rx_iir_reg = (pipe == 0) ? FDI_RXA_IIR : FDI_RXB_IIR; + int fdi_rx_imr_reg = (pipe == 0) ? FDI_RXA_IMR : FDI_RXB_IMR; + int transconf_reg = (pipe == 0) ? TRANSACONF : TRANSBCONF; + int pf_ctl_reg = (pipe == 0) ? PFA_CTL_1 : PFB_CTL_1; + int cpu_htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B; + int cpu_hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B; + int cpu_hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B; + int cpu_vtot_reg = (pipe == 0) ? VTOTAL_A : VTOTAL_B; + int cpu_vblank_reg = (pipe == 0) ? VBLANK_A : VBLANK_B; + int cpu_vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B; + int trans_htot_reg = (pipe == 0) ? TRANS_HTOTAL_A : TRANS_HTOTAL_B; + int trans_hblank_reg = (pipe == 0) ? TRANS_HBLANK_A : TRANS_HBLANK_B; + int trans_hsync_reg = (pipe == 0) ? TRANS_HSYNC_A : TRANS_HSYNC_B; + int trans_vtot_reg = (pipe == 0) ? TRANS_VTOTAL_A : TRANS_VTOTAL_B; + int trans_vblank_reg = (pipe == 0) ? TRANS_VBLANK_A : TRANS_VBLANK_B; + int trans_vsync_reg = (pipe == 0) ? TRANS_VSYNC_A : TRANS_VSYNC_B; + u32 temp; + int tries = 5, j; + + /* XXX: When our outputs are all unaware of DPMS modes other than off + * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC. + */ + switch (mode) { + case DRM_MODE_DPMS_ON: + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + DRM_DEBUG("crtc %d dpms on\n", pipe); + /* enable PCH DPLL */ + temp = I915_READ(pch_dpll_reg); + if ((temp & DPLL_VCO_ENABLE) == 0) { + I915_WRITE(pch_dpll_reg, temp | DPLL_VCO_ENABLE); + I915_READ(pch_dpll_reg); + } + + /* enable PCH FDI RX PLL, wait warmup plus DMI latency */ + temp = I915_READ(fdi_rx_reg); + I915_WRITE(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE | + FDI_SEL_PCDCLK | + FDI_DP_PORT_WIDTH_X4); /* default 4 lanes */ + I915_READ(fdi_rx_reg); + udelay(200); + + /* Enable CPU FDI TX PLL, always on for IGDNG */ + temp = I915_READ(fdi_tx_reg); + if ((temp & FDI_TX_PLL_ENABLE) == 0) { + I915_WRITE(fdi_tx_reg, temp | FDI_TX_PLL_ENABLE); + I915_READ(fdi_tx_reg); + udelay(100); + } + + /* Enable CPU pipe */ + temp = I915_READ(pipeconf_reg); + if ((temp & PIPEACONF_ENABLE) == 0) { + I915_WRITE(pipeconf_reg, temp | PIPEACONF_ENABLE); + I915_READ(pipeconf_reg); + udelay(100); + } + + /* configure and enable CPU plane */ + temp = I915_READ(dspcntr_reg); + if ((temp & DISPLAY_PLANE_ENABLE) == 0) { + I915_WRITE(dspcntr_reg, temp | DISPLAY_PLANE_ENABLE); + /* Flush the plane changes */ + I915_WRITE(dspbase_reg, I915_READ(dspbase_reg)); + } + + /* enable CPU FDI TX and PCH FDI RX */ + temp = I915_READ(fdi_tx_reg); + temp |= FDI_TX_ENABLE; + temp |= FDI_DP_PORT_WIDTH_X4; /* default */ + temp &= ~FDI_LINK_TRAIN_NONE; + temp |= FDI_LINK_TRAIN_PATTERN_1; + I915_WRITE(fdi_tx_reg, temp); + I915_READ(fdi_tx_reg); + + temp = I915_READ(fdi_rx_reg); + temp &= ~FDI_LINK_TRAIN_NONE; + temp |= FDI_LINK_TRAIN_PATTERN_1; + I915_WRITE(fdi_rx_reg, temp | FDI_RX_ENABLE); + I915_READ(fdi_rx_reg); + + udelay(150); + + /* Train FDI. */ + /* umask FDI RX Interrupt symbol_lock and bit_lock bit + for train result */ + temp = I915_READ(fdi_rx_imr_reg); + temp &= ~FDI_RX_SYMBOL_LOCK; + temp &= ~FDI_RX_BIT_LOCK; + I915_WRITE(fdi_rx_imr_reg, temp); + I915_READ(fdi_rx_imr_reg); + udelay(150); + + temp = I915_READ(fdi_rx_iir_reg); + DRM_DEBUG("FDI_RX_IIR 0x%x\n", temp); + + if ((temp & FDI_RX_BIT_LOCK) == 0) { + for (j = 0; j < tries; j++) { + temp = I915_READ(fdi_rx_iir_reg); + DRM_DEBUG("FDI_RX_IIR 0x%x\n", temp); + if (temp & FDI_RX_BIT_LOCK) + break; + udelay(200); + } + if (j != tries) + I915_WRITE(fdi_rx_iir_reg, + temp | FDI_RX_BIT_LOCK); + else + DRM_DEBUG("train 1 fail\n"); + } else { + I915_WRITE(fdi_rx_iir_reg, + temp | FDI_RX_BIT_LOCK); + DRM_DEBUG("train 1 ok 2!\n"); + } + temp = I915_READ(fdi_tx_reg); + temp &= ~FDI_LINK_TRAIN_NONE; + temp |= FDI_LINK_TRAIN_PATTERN_2; + I915_WRITE(fdi_tx_reg, temp); + + temp = I915_READ(fdi_rx_reg); + temp &= ~FDI_LINK_TRAIN_NONE; + temp |= FDI_LINK_TRAIN_PATTERN_2; + I915_WRITE(fdi_rx_reg, temp); + + udelay(150); + + temp = I915_READ(fdi_rx_iir_reg); + DRM_DEBUG("FDI_RX_IIR 0x%x\n", temp); + + if ((temp & FDI_RX_SYMBOL_LOCK) == 0) { + for (j = 0; j < tries; j++) { + temp = I915_READ(fdi_rx_iir_reg); + DRM_DEBUG("FDI_RX_IIR 0x%x\n", temp); + if (temp & FDI_RX_SYMBOL_LOCK) + break; + udelay(200); + } + if (j != tries) { + I915_WRITE(fdi_rx_iir_reg, + temp | FDI_RX_SYMBOL_LOCK); + DRM_DEBUG("train 2 ok 1!\n"); + } else + DRM_DEBUG("train 2 fail\n"); + } else { + I915_WRITE(fdi_rx_iir_reg, temp | FDI_RX_SYMBOL_LOCK); + DRM_DEBUG("train 2 ok 2!\n"); + } + DRM_DEBUG("train done\n"); + + /* set transcoder timing */ + I915_WRITE(trans_htot_reg, I915_READ(cpu_htot_reg)); + I915_WRITE(trans_hblank_reg, I915_READ(cpu_hblank_reg)); + I915_WRITE(trans_hsync_reg, I915_READ(cpu_hsync_reg)); + + I915_WRITE(trans_vtot_reg, I915_READ(cpu_vtot_reg)); + I915_WRITE(trans_vblank_reg, I915_READ(cpu_vblank_reg)); + I915_WRITE(trans_vsync_reg, I915_READ(cpu_vsync_reg)); + + /* enable PCH transcoder */ + temp = I915_READ(transconf_reg); + I915_WRITE(transconf_reg, temp | TRANS_ENABLE); + I915_READ(transconf_reg); + + while ((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) == 0) + ; + + /* enable normal */ + + temp = I915_READ(fdi_tx_reg); + temp &= ~FDI_LINK_TRAIN_NONE; + I915_WRITE(fdi_tx_reg, temp | FDI_LINK_TRAIN_NONE | + FDI_TX_ENHANCE_FRAME_ENABLE); + I915_READ(fdi_tx_reg); + + temp = I915_READ(fdi_rx_reg); + temp &= ~FDI_LINK_TRAIN_NONE; + I915_WRITE(fdi_rx_reg, temp | FDI_LINK_TRAIN_NONE | + FDI_RX_ENHANCE_FRAME_ENABLE); + I915_READ(fdi_rx_reg); + + /* wait one idle pattern time */ + udelay(100); + + intel_crtc_load_lut(crtc); + + break; + case DRM_MODE_DPMS_OFF: + DRM_DEBUG("crtc %d dpms off\n", pipe); + + /* Disable the VGA plane that we never use */ + I915_WRITE(CPU_VGACNTRL, VGA_DISP_DISABLE); + + /* Disable display plane */ + temp = I915_READ(dspcntr_reg); + if ((temp & DISPLAY_PLANE_ENABLE) != 0) { + I915_WRITE(dspcntr_reg, temp & ~DISPLAY_PLANE_ENABLE); + /* Flush the plane changes */ + I915_WRITE(dspbase_reg, I915_READ(dspbase_reg)); + I915_READ(dspbase_reg); + } + + /* disable cpu pipe, disable after all planes disabled */ + temp = I915_READ(pipeconf_reg); + if ((temp & PIPEACONF_ENABLE) != 0) { + I915_WRITE(pipeconf_reg, temp & ~PIPEACONF_ENABLE); + I915_READ(pipeconf_reg); + /* wait for cpu pipe off, pipe state */ + while ((I915_READ(pipeconf_reg) & I965_PIPECONF_ACTIVE) != 0) + ; + } else + DRM_DEBUG("crtc %d is disabled\n", pipe); + + /* IGDNG-A : disable cpu panel fitter ? */ + temp = I915_READ(pf_ctl_reg); + if ((temp & PF_ENABLE) != 0) { + I915_WRITE(pf_ctl_reg, temp & ~PF_ENABLE); + I915_READ(pf_ctl_reg); + } + + /* disable CPU FDI tx and PCH FDI rx */ + temp = I915_READ(fdi_tx_reg); + I915_WRITE(fdi_tx_reg, temp & ~FDI_TX_ENABLE); + I915_READ(fdi_tx_reg); + + temp = I915_READ(fdi_rx_reg); + I915_WRITE(fdi_rx_reg, temp & ~FDI_RX_ENABLE); + I915_READ(fdi_rx_reg); + + /* still set train pattern 1 */ + temp = I915_READ(fdi_tx_reg); + temp &= ~FDI_LINK_TRAIN_NONE; + temp |= FDI_LINK_TRAIN_PATTERN_1; + I915_WRITE(fdi_tx_reg, temp); + + temp = I915_READ(fdi_rx_reg); + temp &= ~FDI_LINK_TRAIN_NONE; + temp |= FDI_LINK_TRAIN_PATTERN_1; + I915_WRITE(fdi_rx_reg, temp); + + /* disable PCH transcoder */ + temp = I915_READ(transconf_reg); + if ((temp & TRANS_ENABLE) != 0) { + I915_WRITE(transconf_reg, temp & ~TRANS_ENABLE); + I915_READ(transconf_reg); + /* wait for PCH transcoder off, transcoder state */ + while ((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) != 0) + ; + } + + /* disable PCH DPLL */ + temp = I915_READ(pch_dpll_reg); + if ((temp & DPLL_VCO_ENABLE) != 0) { + I915_WRITE(pch_dpll_reg, temp & ~DPLL_VCO_ENABLE); + I915_READ(pch_dpll_reg); + } + + temp = I915_READ(fdi_rx_reg); + if ((temp & FDI_RX_PLL_ENABLE) != 0) { + temp &= ~FDI_SEL_PCDCLK; + temp &= ~FDI_RX_PLL_ENABLE; + I915_WRITE(fdi_rx_reg, temp); + I915_READ(fdi_rx_reg); + } + + /* Wait for the clocks to turn off. */ + udelay(150); + break; + } +} + +static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode) { struct drm_device *dev = crtc->dev; - struct drm_i915_master_private *master_priv; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_crtc->pipe; @@ -805,7 +1221,6 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) int dspbase_reg = (pipe == 0) ? DSPAADDR : DSPBADDR; int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF; u32 temp; - bool enabled; /* XXX: When our outputs are all unaware of DPMS modes other than off * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC. @@ -890,6 +1305,26 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) udelay(150); break; } +} + +/** + * Sets the power management mode of the pipe and plane. + * + * This code should probably grow support for turning the cursor off and back + * on appropriately at the same time as we're turning the pipe off/on. + */ +static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_master_private *master_priv; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; + bool enabled; + + if (IS_IGDNG(dev)) + igdng_crtc_dpms(crtc, mode); + else + i9xx_crtc_dpms(crtc, mode); if (!dev->primary->master) return; @@ -947,6 +1382,12 @@ static bool intel_crtc_mode_fixup(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { + struct drm_device *dev = crtc->dev; + if (IS_IGDNG(dev)) { + /* FDI link clock is fixed at 2.7G */ + if (mode->clock * 3 > 27000 * 4) + return MODE_CLOCK_HIGH; + } return true; } @@ -1030,6 +1471,48 @@ static int intel_panel_fitter_pipe (struct drm_device *dev) return 1; } +struct fdi_m_n { + u32 tu; + u32 gmch_m; + u32 gmch_n; + u32 link_m; + u32 link_n; +}; + +static void +fdi_reduce_ratio(u32 *num, u32 *den) +{ + while (*num > 0xffffff || *den > 0xffffff) { + *num >>= 1; + *den >>= 1; + } +} + +#define DATA_N 0x800000 +#define LINK_N 0x80000 + +static void +igdng_compute_m_n(int bytes_per_pixel, int nlanes, + int pixel_clock, int link_clock, + struct fdi_m_n *m_n) +{ + u64 temp; + + m_n->tu = 64; /* default size */ + + temp = (u64) DATA_N * pixel_clock; + temp = div_u64(temp, link_clock); + m_n->gmch_m = (temp * bytes_per_pixel) / nlanes; + m_n->gmch_n = DATA_N; + fdi_reduce_ratio(&m_n->gmch_m, &m_n->gmch_n); + + temp = (u64) LINK_N * pixel_clock; + m_n->link_m = div_u64(temp, link_clock); + m_n->link_n = LINK_N; + fdi_reduce_ratio(&m_n->link_m, &m_n->link_n); +} + + static int intel_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode, @@ -1063,6 +1546,17 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, struct drm_connector *connector; const intel_limit_t *limit; int ret; + struct fdi_m_n m_n = {0}; + int data_m1_reg = (pipe == 0) ? PIPEA_DATA_M1 : PIPEB_DATA_M1; + int data_n1_reg = (pipe == 0) ? PIPEA_DATA_N1 : PIPEB_DATA_N1; + int link_m1_reg = (pipe == 0) ? PIPEA_LINK_M1 : PIPEB_LINK_M1; + int link_n1_reg = (pipe == 0) ? PIPEA_LINK_N1 : PIPEB_LINK_N1; + int pch_fp_reg = (pipe == 0) ? PCH_FPA0 : PCH_FPB0; + int pch_dpll_reg = (pipe == 0) ? PCH_DPLL_A : PCH_DPLL_B; + int fdi_rx_reg = (pipe == 0) ? FDI_RXA_CTL : FDI_RXB_CTL; + int lvds_reg = LVDS; + u32 temp; + int sdvo_pixel_multiply; drm_vblank_pre_modeset(dev, pipe); @@ -1101,6 +1595,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, DRM_DEBUG("using SSC reference clock of %d MHz\n", refclk / 1000); } else if (IS_I9XX(dev)) { refclk = 96000; + if (IS_IGDNG(dev)) + refclk = 120000; /* 120Mhz refclk */ } else { refclk = 48000; } @@ -1114,6 +1610,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, &clock); if (!ok) { DRM_ERROR("Couldn't find PLL settings for mode!\n"); + drm_vblank_post_modeset(dev, pipe); return -EINVAL; } @@ -1137,12 +1634,21 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, } } + /* FDI link */ + if (IS_IGDNG(dev)) + igdng_compute_m_n(3, 4, /* lane num 4 */ + adjusted_mode->clock, + 270000, /* lane clock */ + &m_n); + if (IS_IGD(dev)) fp = (1 << clock.n) << 16 | clock.m1 << 8 | clock.m2; else fp = clock.n << 16 | clock.m1 << 8 | clock.m2; - dpll = DPLL_VGA_MODE_DIS; + if (!IS_IGDNG(dev)) + dpll = DPLL_VGA_MODE_DIS; + if (IS_I9XX(dev)) { if (is_lvds) dpll |= DPLLB_MODE_LVDS; @@ -1150,17 +1656,22 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, dpll |= DPLLB_MODE_DAC_SERIAL; if (is_sdvo) { dpll |= DPLL_DVO_HIGH_SPEED; - if (IS_I945G(dev) || IS_I945GM(dev)) { - int sdvo_pixel_multiply = adjusted_mode->clock / mode->clock; + sdvo_pixel_multiply = adjusted_mode->clock / mode->clock; + if (IS_I945G(dev) || IS_I945GM(dev)) dpll |= (sdvo_pixel_multiply - 1) << SDVO_MULTIPLIER_SHIFT_HIRES; - } + else if (IS_IGDNG(dev)) + dpll |= (sdvo_pixel_multiply - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT; } /* compute bitmask from p1 value */ if (IS_IGD(dev)) dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT_IGD; - else + else { dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT; + /* also FPA1 */ + if (IS_IGDNG(dev)) + dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT; + } switch (clock.p2) { case 5: dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5; @@ -1175,7 +1686,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14; break; } - if (IS_I965G(dev)) + if (IS_I965G(dev) && !IS_IGDNG(dev)) dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT); } else { if (is_lvds) { @@ -1207,10 +1718,14 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, /* Set up the display plane register */ dspcntr = DISPPLANE_GAMMA_ENABLE; - if (pipe == 0) - dspcntr |= DISPPLANE_SEL_PIPE_A; - else - dspcntr |= DISPPLANE_SEL_PIPE_B; + /* IGDNG's plane is forced to pipe, bit 24 is to + enable color space conversion */ + if (!IS_IGDNG(dev)) { + if (pipe == 0) + dspcntr |= DISPPLANE_SEL_PIPE_A; + else + dspcntr |= DISPPLANE_SEL_PIPE_B; + } if (pipe == 0 && !IS_I965G(dev)) { /* Enable pixel doubling when the dot clock is > 90% of the (display) @@ -1231,12 +1746,17 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, /* Disable the panel fitter if it was on our pipe */ - if (intel_panel_fitter_pipe(dev) == pipe) + if (!IS_IGDNG(dev) && intel_panel_fitter_pipe(dev) == pipe) I915_WRITE(PFIT_CONTROL, 0); DRM_DEBUG("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B'); drm_mode_debug_printmodeline(mode); + /* assign to IGDNG registers */ + if (IS_IGDNG(dev)) { + fp_reg = pch_fp_reg; + dpll_reg = pch_dpll_reg; + } if (dpll & DPLL_VCO_ENABLE) { I915_WRITE(fp_reg, fp); @@ -1245,13 +1765,33 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, udelay(150); } + if (IS_IGDNG(dev)) { + /* enable PCH clock reference source */ + /* XXX need to change the setting for other outputs */ + u32 temp; + temp = I915_READ(PCH_DREF_CONTROL); + temp &= ~DREF_NONSPREAD_SOURCE_MASK; + temp |= DREF_NONSPREAD_CK505_ENABLE; + temp &= ~DREF_SSC_SOURCE_MASK; + temp |= DREF_SSC_SOURCE_ENABLE; + temp &= ~DREF_SSC1_ENABLE; + /* if no eDP, disable source output to CPU */ + temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK; + temp |= DREF_CPU_SOURCE_OUTPUT_DISABLE; + I915_WRITE(PCH_DREF_CONTROL, temp); + } + /* The LVDS pin pair needs to be on before the DPLLs are enabled. * This is an exception to the general rule that mode_set doesn't turn * things on. */ if (is_lvds) { - u32 lvds = I915_READ(LVDS); + u32 lvds; + if (IS_IGDNG(dev)) + lvds_reg = PCH_LVDS; + + lvds = I915_READ(lvds_reg); lvds |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP | LVDS_PIPEB_SELECT; /* Set the B0-B3 data pairs corresponding to whether we're going to * set the DPLLs for dual-channel mode or not. @@ -1266,8 +1806,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, * panels behave in the two modes. */ - I915_WRITE(LVDS, lvds); - I915_READ(LVDS); + I915_WRITE(lvds_reg, lvds); + I915_READ(lvds_reg); } I915_WRITE(fp_reg, fp); @@ -1276,8 +1816,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, /* Wait for the clocks to stabilize. */ udelay(150); - if (IS_I965G(dev)) { - int sdvo_pixel_multiply = adjusted_mode->clock / mode->clock; + if (IS_I965G(dev) && !IS_IGDNG(dev)) { + sdvo_pixel_multiply = adjusted_mode->clock / mode->clock; I915_WRITE(dpll_md_reg, (0 << DPLL_MD_UDI_DIVIDER_SHIFT) | ((sdvo_pixel_multiply - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT)); } else { @@ -1303,9 +1843,25 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, /* pipesrc and dspsize control the size that is scaled from, which should * always be the user's requested size. */ - I915_WRITE(dspsize_reg, ((mode->vdisplay - 1) << 16) | (mode->hdisplay - 1)); - I915_WRITE(dsppos_reg, 0); + if (!IS_IGDNG(dev)) { + I915_WRITE(dspsize_reg, ((mode->vdisplay - 1) << 16) | + (mode->hdisplay - 1)); + I915_WRITE(dsppos_reg, 0); + } I915_WRITE(pipesrc_reg, ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1)); + + if (IS_IGDNG(dev)) { + I915_WRITE(data_m1_reg, TU_SIZE(m_n.tu) | m_n.gmch_m); + I915_WRITE(data_n1_reg, TU_SIZE(m_n.tu) | m_n.gmch_n); + I915_WRITE(link_m1_reg, m_n.link_m); + I915_WRITE(link_n1_reg, m_n.link_n); + + /* enable FDI RX PLL too */ + temp = I915_READ(fdi_rx_reg); + I915_WRITE(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE); + udelay(200); + } + I915_WRITE(pipeconf_reg, pipeconf); I915_READ(pipeconf_reg); @@ -1315,12 +1871,9 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, /* Flush the plane changes */ ret = intel_pipe_set_base(crtc, x, y, old_fb); - if (ret != 0) - return ret; - drm_vblank_post_modeset(dev, pipe); - return 0; + return ret; } /** Loads the palette/gamma unit for the CRTC with the prepared values */ @@ -1336,6 +1889,11 @@ void intel_crtc_load_lut(struct drm_crtc *crtc) if (!crtc->enabled) return; + /* use legacy palette for IGDNG */ + if (IS_IGDNG(dev)) + palreg = (intel_crtc->pipe == 0) ? LGC_PALETTE_A : + LGC_PALETTE_B; + for (i = 0; i < 256; i++) { I915_WRITE(palreg + 4 * i, (intel_crtc->lut_r[i] << 16) | @@ -1464,16 +2022,16 @@ static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) uint32_t adder; if (x < 0) { - temp |= (CURSOR_POS_SIGN << CURSOR_X_SHIFT); + temp |= CURSOR_POS_SIGN << CURSOR_X_SHIFT; x = -x; } if (y < 0) { - temp |= (CURSOR_POS_SIGN << CURSOR_Y_SHIFT); + temp |= CURSOR_POS_SIGN << CURSOR_Y_SHIFT; y = -y; } - temp |= ((x & CURSOR_POS_MASK) << CURSOR_X_SHIFT); - temp |= ((y & CURSOR_POS_MASK) << CURSOR_Y_SHIFT); + temp |= x << CURSOR_X_SHIFT; + temp |= y << CURSOR_Y_SHIFT; adder = intel_crtc->cursor_addr; I915_WRITE((pipe == 0) ? CURAPOS : CURBPOS, temp); @@ -1590,6 +2148,7 @@ struct drm_crtc *intel_get_load_detect_pipe(struct intel_output *intel_output, } encoder->crtc = crtc; + intel_output->base.encoder = encoder; intel_output->load_detect_temp = true; intel_crtc = to_intel_crtc(crtc); @@ -1625,6 +2184,7 @@ void intel_release_load_detect_pipe(struct intel_output *intel_output, int dpms_ if (intel_output->load_detect_temp) { encoder->crtc = NULL; + intel_output->base.encoder = NULL; intel_output->load_detect_temp = false; crtc->enabled = drm_helper_crtc_in_use(crtc); drm_helper_disable_unused_functions(dev); @@ -1762,6 +2322,8 @@ static void intel_crtc_destroy(struct drm_crtc *crtc) { struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + if (intel_crtc->mode_set.mode) + drm_mode_destroy(crtc->dev, intel_crtc->mode_set.mode); drm_crtc_cleanup(crtc); kfree(intel_crtc); } @@ -1888,7 +2450,24 @@ static void intel_setup_outputs(struct drm_device *dev) if (IS_MOBILE(dev) && !IS_I830(dev)) intel_lvds_init(dev); - if (IS_I9XX(dev)) { + if (IS_IGDNG(dev)) { + int found; + + if (I915_READ(HDMIB) & PORT_DETECTED) { + /* check SDVOB */ + /* found = intel_sdvo_init(dev, HDMIB); */ + found = 0; + if (!found) + intel_hdmi_init(dev, HDMIB); + } + + if (I915_READ(HDMIC) & PORT_DETECTED) + intel_hdmi_init(dev, HDMIC); + + if (I915_READ(HDMID) & PORT_DETECTED) + intel_hdmi_init(dev, HDMID); + + } else if (IS_I9XX(dev)) { int found; u32 reg; @@ -1912,7 +2491,7 @@ static void intel_setup_outputs(struct drm_device *dev) } else intel_dvo_init(dev); - if (IS_I9XX(dev) && IS_MOBILE(dev)) + if (IS_I9XX(dev) && IS_MOBILE(dev) && !IS_IGDNG(dev)) intel_tv_init(dev); list_for_each_entry(connector, &dev->mode_config.connector_list, head) { diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index e4652dcdd9bb..1af7d68e3807 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -207,7 +207,7 @@ static int intelfb_set_par(struct fb_info *info) if (var->pixclock != -1) { - DRM_ERROR("PIXEL CLCOK SET\n"); + DRM_ERROR("PIXEL CLOCK SET\n"); return -EINVAL; } else { struct drm_crtc *crtc; @@ -504,6 +504,14 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width, info->fbops = &intelfb_ops; info->fix.line_length = fb->pitch; + + /* setup aperture base/size for vesafb takeover */ + info->aperture_base = dev->mode_config.fb_base; + if (IS_I9XX(dev)) + info->aperture_size = pci_resource_len(dev->pdev, 2); + else + info->aperture_size = pci_resource_len(dev->pdev, 0); + info->fix.smem_start = dev->mode_config.fb_base + obj_priv->gtt_offset; info->fix.smem_len = size; @@ -674,8 +682,12 @@ static int intelfb_multi_fb_probe_crtc(struct drm_device *dev, struct drm_crtc * par->crtc_ids[0] = crtc->base.id; modeset->num_connectors = conn_count; - if (modeset->mode != modeset->crtc->desired_mode) - modeset->mode = modeset->crtc->desired_mode; + if (modeset->crtc->desired_mode) { + if (modeset->mode) + drm_mode_destroy(dev, modeset->mode); + modeset->mode = drm_mode_duplicate(dev, + modeset->crtc->desired_mode); + } par->crtc_count = 1; @@ -824,8 +836,12 @@ static int intelfb_single_fb_probe(struct drm_device *dev) par->crtc_ids[crtc_count++] = crtc->base.id; modeset->num_connectors = conn_count; - if (modeset->mode != modeset->crtc->desired_mode) - modeset->mode = modeset->crtc->desired_mode; + if (modeset->crtc->desired_mode) { + if (modeset->mode) + drm_mode_destroy(dev, modeset->mode); + modeset->mode = drm_mode_duplicate(dev, + modeset->crtc->desired_mode); + } } par->crtc_count = crtc_count; @@ -854,12 +870,22 @@ static int intelfb_single_fb_probe(struct drm_device *dev) */ void intelfb_restore(void) { - drm_crtc_helper_set_config(&kernelfb_mode); + int ret; + if ((ret = drm_crtc_helper_set_config(&kernelfb_mode)) != 0) { + printk(KERN_ERR "Failed to restore crtc configuration: %d\n", + ret); + } } +static void intelfb_restore_work_fn(struct work_struct *ignored) +{ + intelfb_restore(); +} +static DECLARE_WORK(intelfb_restore_work, intelfb_restore_work_fn); + static void intelfb_sysrq(int dummy1, struct tty_struct *dummy3) { - intelfb_restore(); + schedule_work(&intelfb_restore_work); } static struct sysrq_key_op sysrq_intelfb_restore_op = { diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 7d6bdd705326..4ea2a651b92c 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -56,7 +56,8 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder, sdvox = SDVO_ENCODING_HDMI | SDVO_BORDER_ENABLE | SDVO_VSYNC_ACTIVE_HIGH | - SDVO_HSYNC_ACTIVE_HIGH; + SDVO_HSYNC_ACTIVE_HIGH | + SDVO_NULL_PACKETS_DURING_VSYNC; if (hdmi_priv->has_hdmi_sink) sdvox |= SDVO_AUDIO_ENABLE; @@ -144,6 +145,22 @@ intel_hdmi_sink_detect(struct drm_connector *connector) } } +static enum drm_connector_status +igdng_hdmi_detect(struct drm_connector *connector) +{ + struct intel_output *intel_output = to_intel_output(connector); + struct intel_hdmi_priv *hdmi_priv = intel_output->dev_priv; + + /* FIXME hotplug detect */ + + hdmi_priv->has_hdmi_sink = false; + intel_hdmi_sink_detect(connector); + if (hdmi_priv->has_hdmi_sink) + return connector_status_connected; + else + return connector_status_disconnected; +} + static enum drm_connector_status intel_hdmi_detect(struct drm_connector *connector) { @@ -153,6 +170,9 @@ intel_hdmi_detect(struct drm_connector *connector) struct intel_hdmi_priv *hdmi_priv = intel_output->dev_priv; u32 temp, bit; + if (IS_IGDNG(dev)) + return igdng_hdmi_detect(connector); + temp = I915_READ(PORT_HOTPLUG_EN); switch (hdmi_priv->sdvox_reg) { @@ -269,8 +289,17 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg) /* Set up the DDC bus. */ if (sdvox_reg == SDVOB) intel_output->ddc_bus = intel_i2c_create(dev, GPIOE, "HDMIB"); - else + else if (sdvox_reg == SDVOC) intel_output->ddc_bus = intel_i2c_create(dev, GPIOD, "HDMIC"); + else if (sdvox_reg == HDMIB) + intel_output->ddc_bus = intel_i2c_create(dev, PCH_GPIOE, + "HDMIB"); + else if (sdvox_reg == HDMIC) + intel_output->ddc_bus = intel_i2c_create(dev, PCH_GPIOD, + "HDMIC"); + else if (sdvox_reg == HDMID) + intel_output->ddc_bus = intel_i2c_create(dev, PCH_GPIOF, + "HDMID"); if (!intel_output->ddc_bus) goto err_connector; diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 53cccfa58b95..f073ed8432e8 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -37,6 +37,8 @@ #include "i915_drm.h" #include "i915_drv.h" +#define I915_LVDS "i915_lvds" + /** * Sets the backlight level. * @@ -45,10 +47,15 @@ static void intel_lvds_set_backlight(struct drm_device *dev, int level) { struct drm_i915_private *dev_priv = dev->dev_private; - u32 blc_pwm_ctl; + u32 blc_pwm_ctl, reg; - blc_pwm_ctl = I915_READ(BLC_PWM_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK; - I915_WRITE(BLC_PWM_CTL, (blc_pwm_ctl | + if (IS_IGDNG(dev)) + reg = BLC_PWM_CPU_CTL; + else + reg = BLC_PWM_CTL; + + blc_pwm_ctl = I915_READ(reg) & ~BACKLIGHT_DUTY_CYCLE_MASK; + I915_WRITE(reg, (blc_pwm_ctl | (level << BACKLIGHT_DUTY_CYCLE_SHIFT))); } @@ -58,8 +65,14 @@ static void intel_lvds_set_backlight(struct drm_device *dev, int level) static u32 intel_lvds_get_max_backlight(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + u32 reg; - return ((I915_READ(BLC_PWM_CTL) & BACKLIGHT_MODULATION_FREQ_MASK) >> + if (IS_IGDNG(dev)) + reg = BLC_PWM_PCH_CTL2; + else + reg = BLC_PWM_CTL; + + return ((I915_READ(reg) & BACKLIGHT_MODULATION_FREQ_MASK) >> BACKLIGHT_MODULATION_FREQ_SHIFT) * 2; } @@ -69,23 +82,31 @@ static u32 intel_lvds_get_max_backlight(struct drm_device *dev) static void intel_lvds_set_power(struct drm_device *dev, bool on) { struct drm_i915_private *dev_priv = dev->dev_private; - u32 pp_status; + u32 pp_status, ctl_reg, status_reg; + + if (IS_IGDNG(dev)) { + ctl_reg = PCH_PP_CONTROL; + status_reg = PCH_PP_STATUS; + } else { + ctl_reg = PP_CONTROL; + status_reg = PP_STATUS; + } if (on) { - I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) | + I915_WRITE(ctl_reg, I915_READ(ctl_reg) | POWER_TARGET_ON); do { - pp_status = I915_READ(PP_STATUS); + pp_status = I915_READ(status_reg); } while ((pp_status & PP_ON) == 0); intel_lvds_set_backlight(dev, dev_priv->backlight_duty_cycle); } else { intel_lvds_set_backlight(dev, 0); - I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) & + I915_WRITE(ctl_reg, I915_READ(ctl_reg) & ~POWER_TARGET_ON); do { - pp_status = I915_READ(PP_STATUS); + pp_status = I915_READ(status_reg); } while (pp_status & PP_ON); } } @@ -106,12 +127,28 @@ static void intel_lvds_save(struct drm_connector *connector) { struct drm_device *dev = connector->dev; struct drm_i915_private *dev_priv = dev->dev_private; + u32 pp_on_reg, pp_off_reg, pp_ctl_reg, pp_div_reg; + u32 pwm_ctl_reg; - dev_priv->savePP_ON = I915_READ(PP_ON_DELAYS); - dev_priv->savePP_OFF = I915_READ(PP_OFF_DELAYS); - dev_priv->savePP_CONTROL = I915_READ(PP_CONTROL); - dev_priv->savePP_DIVISOR = I915_READ(PP_DIVISOR); - dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL); + if (IS_IGDNG(dev)) { + pp_on_reg = PCH_PP_ON_DELAYS; + pp_off_reg = PCH_PP_OFF_DELAYS; + pp_ctl_reg = PCH_PP_CONTROL; + pp_div_reg = PCH_PP_DIVISOR; + pwm_ctl_reg = BLC_PWM_CPU_CTL; + } else { + pp_on_reg = PP_ON_DELAYS; + pp_off_reg = PP_OFF_DELAYS; + pp_ctl_reg = PP_CONTROL; + pp_div_reg = PP_DIVISOR; + pwm_ctl_reg = BLC_PWM_CTL; + } + + dev_priv->savePP_ON = I915_READ(pp_on_reg); + dev_priv->savePP_OFF = I915_READ(pp_off_reg); + dev_priv->savePP_CONTROL = I915_READ(pp_ctl_reg); + dev_priv->savePP_DIVISOR = I915_READ(pp_div_reg); + dev_priv->saveBLC_PWM_CTL = I915_READ(pwm_ctl_reg); dev_priv->backlight_duty_cycle = (dev_priv->saveBLC_PWM_CTL & BACKLIGHT_DUTY_CYCLE_MASK); @@ -127,12 +164,28 @@ static void intel_lvds_restore(struct drm_connector *connector) { struct drm_device *dev = connector->dev; struct drm_i915_private *dev_priv = dev->dev_private; + u32 pp_on_reg, pp_off_reg, pp_ctl_reg, pp_div_reg; + u32 pwm_ctl_reg; - I915_WRITE(BLC_PWM_CTL, dev_priv->saveBLC_PWM_CTL); - I915_WRITE(PP_ON_DELAYS, dev_priv->savePP_ON); - I915_WRITE(PP_OFF_DELAYS, dev_priv->savePP_OFF); - I915_WRITE(PP_DIVISOR, dev_priv->savePP_DIVISOR); - I915_WRITE(PP_CONTROL, dev_priv->savePP_CONTROL); + if (IS_IGDNG(dev)) { + pp_on_reg = PCH_PP_ON_DELAYS; + pp_off_reg = PCH_PP_OFF_DELAYS; + pp_ctl_reg = PCH_PP_CONTROL; + pp_div_reg = PCH_PP_DIVISOR; + pwm_ctl_reg = BLC_PWM_CPU_CTL; + } else { + pp_on_reg = PP_ON_DELAYS; + pp_off_reg = PP_OFF_DELAYS; + pp_ctl_reg = PP_CONTROL; + pp_div_reg = PP_DIVISOR; + pwm_ctl_reg = BLC_PWM_CTL; + } + + I915_WRITE(pwm_ctl_reg, dev_priv->saveBLC_PWM_CTL); + I915_WRITE(pp_on_reg, dev_priv->savePP_ON); + I915_WRITE(pp_off_reg, dev_priv->savePP_OFF); + I915_WRITE(pp_div_reg, dev_priv->savePP_DIVISOR); + I915_WRITE(pp_ctl_reg, dev_priv->savePP_CONTROL); if (dev_priv->savePP_CONTROL & POWER_TARGET_ON) intel_lvds_set_power(dev, true); else @@ -216,8 +269,14 @@ static void intel_lvds_prepare(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; + u32 reg; - dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL); + if (IS_IGDNG(dev)) + reg = BLC_PWM_CPU_CTL; + else + reg = BLC_PWM_CTL; + + dev_priv->saveBLC_PWM_CTL = I915_READ(reg); dev_priv->backlight_duty_cycle = (dev_priv->saveBLC_PWM_CTL & BACKLIGHT_DUTY_CYCLE_MASK); @@ -251,6 +310,10 @@ static void intel_lvds_mode_set(struct drm_encoder *encoder, * settings. */ + /* No panel fitting yet, fixme */ + if (IS_IGDNG(dev)) + return; + /* * Enable automatic panel scaling so that non-native modes fill the * screen. Should be enabled before the pipe is enabled, according to @@ -382,7 +445,8 @@ static const struct drm_encoder_funcs intel_lvds_enc_funcs = { static int __init intel_no_lvds_dmi_callback(const struct dmi_system_id *id) { - DRM_DEBUG("Skipping LVDS initialization for %s\n", id->ident); + DRM_DEBUG_KMS(I915_LVDS, + "Skipping LVDS initialization for %s\n", id->ident); return 1; } @@ -420,8 +484,21 @@ static const struct dmi_system_id intel_no_lvds[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Studio Hybrid 140g"), }, }, - - /* FIXME: add a check for the Aopen Mini PC */ + { + .callback = intel_no_lvds_dmi_callback, + .ident = "AOpen Mini PC", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "AOpen"), + DMI_MATCH(DMI_PRODUCT_NAME, "i965GMx-IF"), + }, + }, + { + .callback = intel_no_lvds_dmi_callback, + .ident = "Aopen i945GTt-VFA", + .matches = { + DMI_MATCH(DMI_PRODUCT_VERSION, "AO00001JW"), + }, + }, { } /* terminating entry */ }; @@ -442,12 +519,18 @@ void intel_lvds_init(struct drm_device *dev) struct drm_display_mode *scan; /* *modes, *bios_mode; */ struct drm_crtc *crtc; u32 lvds; - int pipe; + int pipe, gpio = GPIOC; /* Skip init on machines we know falsely report LVDS */ if (dmi_check_system(intel_no_lvds)) return; + if (IS_IGDNG(dev)) { + if ((I915_READ(PCH_LVDS) & LVDS_DETECTED) == 0) + return; + gpio = PCH_GPIOC; + } + intel_output = kzalloc(sizeof(struct intel_output), GFP_KERNEL); if (!intel_output) { return; @@ -482,7 +565,7 @@ void intel_lvds_init(struct drm_device *dev) */ /* Set up the DDC bus. */ - intel_output->ddc_bus = intel_i2c_create(dev, GPIOC, "LVDSDDC_C"); + intel_output->ddc_bus = intel_i2c_create(dev, gpio, "LVDSDDC_C"); if (!intel_output->ddc_bus) { dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration " "failed.\n"); @@ -524,6 +607,11 @@ void intel_lvds_init(struct drm_device *dev) * on. If so, assume that whatever is currently programmed is the * correct mode. */ + + /* IGDNG: FIXME if still fail, not try pipe mode now */ + if (IS_IGDNG(dev)) + goto failed; + lvds = I915_READ(LVDS); pipe = (lvds & LVDS_PIPEB_SELECT) ? 1 : 0; crtc = intel_get_crtc_from_pipe(dev, pipe); @@ -542,11 +630,22 @@ void intel_lvds_init(struct drm_device *dev) goto failed; out: + if (IS_IGDNG(dev)) { + u32 pwm; + /* make sure PWM is enabled */ + pwm = I915_READ(BLC_PWM_CPU_CTL2); + pwm |= (PWM_ENABLE | PWM_PIPE_B); + I915_WRITE(BLC_PWM_CPU_CTL2, pwm); + + pwm = I915_READ(BLC_PWM_PCH_CTL1); + pwm |= PWM_PCH_ENABLE; + I915_WRITE(BLC_PWM_PCH_CTL1, pwm); + } drm_sysfs_connector_add(connector); return; failed: - DRM_DEBUG("No LVDS modes found, disabling.\n"); + DRM_DEBUG_KMS(I915_LVDS, "No LVDS modes found, disabling.\n"); if (intel_output->ddc_bus) intel_i2c_destroy(intel_output->ddc_bus); drm_connector_cleanup(connector); diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 3093b4d4a4dd..9a00adb3a508 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -36,7 +36,7 @@ #include "intel_sdvo_regs.h" #undef SDVO_DEBUG - +#define I915_SDVO "i915_sdvo" struct intel_sdvo_priv { struct intel_i2c_chan *i2c_bus; int slaveaddr; @@ -277,20 +277,21 @@ static void intel_sdvo_debug_write(struct intel_output *intel_output, u8 cmd, struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; int i; - printk(KERN_DEBUG "%s: W: %02X ", SDVO_NAME(sdvo_priv), cmd); + DRM_DEBUG_KMS(I915_SDVO, "%s: W: %02X ", + SDVO_NAME(sdvo_priv), cmd); for (i = 0; i < args_len; i++) - printk(KERN_DEBUG "%02X ", ((u8 *)args)[i]); + DRM_LOG_KMS("%02X ", ((u8 *)args)[i]); for (; i < 8; i++) - printk(KERN_DEBUG " "); + DRM_LOG_KMS(" "); for (i = 0; i < sizeof(sdvo_cmd_names) / sizeof(sdvo_cmd_names[0]); i++) { if (cmd == sdvo_cmd_names[i].cmd) { - printk(KERN_DEBUG "(%s)", sdvo_cmd_names[i].name); + DRM_LOG_KMS("(%s)", sdvo_cmd_names[i].name); break; } } if (i == sizeof(sdvo_cmd_names)/ sizeof(sdvo_cmd_names[0])) - printk(KERN_DEBUG "(%02X)", cmd); - printk(KERN_DEBUG "\n"); + DRM_LOG_KMS("(%02X)", cmd); + DRM_LOG_KMS("\n"); } #else #define intel_sdvo_debug_write(o, c, a, l) @@ -329,16 +330,16 @@ static void intel_sdvo_debug_response(struct intel_output *intel_output, struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; int i; - printk(KERN_DEBUG "%s: R: ", SDVO_NAME(sdvo_priv)); + DRM_DEBUG_KMS(I915_SDVO, "%s: R: ", SDVO_NAME(sdvo_priv)); for (i = 0; i < response_len; i++) - printk(KERN_DEBUG "%02X ", ((u8 *)response)[i]); + DRM_LOG_KMS("%02X ", ((u8 *)response)[i]); for (; i < 8; i++) - printk(KERN_DEBUG " "); + DRM_LOG_KMS(" "); if (status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP) - printk(KERN_DEBUG "(%s)", cmd_status_names[status]); + DRM_LOG_KMS("(%s)", cmd_status_names[status]); else - printk(KERN_DEBUG "(??? %d)", status); - printk(KERN_DEBUG "\n"); + DRM_LOG_KMS("(??? %d)", status); + DRM_LOG_KMS("\n"); } #else #define intel_sdvo_debug_response(o, r, l, s) @@ -1742,6 +1743,43 @@ static struct i2c_algorithm intel_sdvo_i2c_bit_algo = { .master_xfer = intel_sdvo_master_xfer, }; +static u8 +intel_sdvo_get_slave_addr(struct drm_device *dev, int output_device) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct sdvo_device_mapping *my_mapping, *other_mapping; + + if (output_device == SDVOB) { + my_mapping = &dev_priv->sdvo_mappings[0]; + other_mapping = &dev_priv->sdvo_mappings[1]; + } else { + my_mapping = &dev_priv->sdvo_mappings[1]; + other_mapping = &dev_priv->sdvo_mappings[0]; + } + + /* If the BIOS described our SDVO device, take advantage of it. */ + if (my_mapping->slave_addr) + return my_mapping->slave_addr; + + /* If the BIOS only described a different SDVO device, use the + * address that it isn't using. + */ + if (other_mapping->slave_addr) { + if (other_mapping->slave_addr == 0x70) + return 0x72; + else + return 0x70; + } + + /* No SDVO device info is found for another DVO port, + * so use mapping assumption we had before BIOS parsing. + */ + if (output_device == SDVOB) + return 0x70; + else + return 0x72; +} + bool intel_sdvo_init(struct drm_device *dev, int output_device) { struct drm_connector *connector; @@ -1753,6 +1791,7 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device) u8 ch[0x40]; int i; int encoder_type, output_id; + u8 slave_addr; intel_output = kcalloc(sizeof(struct intel_output)+sizeof(struct intel_sdvo_priv), 1, GFP_KERNEL); if (!intel_output) { @@ -1771,16 +1810,15 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device) if (!i2cbus) goto err_inteloutput; + slave_addr = intel_sdvo_get_slave_addr(dev, output_device); sdvo_priv->i2c_bus = i2cbus; if (output_device == SDVOB) { output_id = 1; - sdvo_priv->i2c_bus->slave_addr = 0x38; } else { output_id = 2; - sdvo_priv->i2c_bus->slave_addr = 0x39; } - + sdvo_priv->i2c_bus->slave_addr = slave_addr >> 1; sdvo_priv->output_device = output_device; intel_output->i2c_bus = i2cbus; intel_output->dev_priv = sdvo_priv; @@ -1788,8 +1826,9 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device) /* Read the regs to test if we can talk to the device */ for (i = 0; i < 0x40; i++) { if (!intel_sdvo_read_byte(intel_output, i, &ch[i])) { - DRM_DEBUG("No SDVO device found on SDVO%c\n", - output_device == SDVOB ? 'B' : 'C'); + DRM_DEBUG_KMS(I915_SDVO, + "No SDVO device found on SDVO%c\n", + output_device == SDVOB ? 'B' : 'C'); goto err_i2c; } } @@ -1873,9 +1912,10 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device) sdvo_priv->controlled_output = 0; memcpy (bytes, &sdvo_priv->caps.output_flags, 2); - DRM_DEBUG("%s: Unknown SDVO output type (0x%02x%02x)\n", - SDVO_NAME(sdvo_priv), - bytes[0], bytes[1]); + DRM_DEBUG_KMS(I915_SDVO, + "%s: Unknown SDVO output type (0x%02x%02x)\n", + SDVO_NAME(sdvo_priv), + bytes[0], bytes[1]); encoder_type = DRM_MODE_ENCODER_NONE; connector_type = DRM_MODE_CONNECTOR_Unknown; goto err_i2c; @@ -1905,21 +1945,21 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device) &sdvo_priv->pixel_clock_max); - DRM_DEBUG("%s device VID/DID: %02X:%02X.%02X, " - "clock range %dMHz - %dMHz, " - "input 1: %c, input 2: %c, " - "output 1: %c, output 2: %c\n", - SDVO_NAME(sdvo_priv), - sdvo_priv->caps.vendor_id, sdvo_priv->caps.device_id, - sdvo_priv->caps.device_rev_id, - sdvo_priv->pixel_clock_min / 1000, - sdvo_priv->pixel_clock_max / 1000, - (sdvo_priv->caps.sdvo_inputs_mask & 0x1) ? 'Y' : 'N', - (sdvo_priv->caps.sdvo_inputs_mask & 0x2) ? 'Y' : 'N', - /* check currently supported outputs */ - sdvo_priv->caps.output_flags & + DRM_DEBUG_KMS(I915_SDVO, "%s device VID/DID: %02X:%02X.%02X, " + "clock range %dMHz - %dMHz, " + "input 1: %c, input 2: %c, " + "output 1: %c, output 2: %c\n", + SDVO_NAME(sdvo_priv), + sdvo_priv->caps.vendor_id, sdvo_priv->caps.device_id, + sdvo_priv->caps.device_rev_id, + sdvo_priv->pixel_clock_min / 1000, + sdvo_priv->pixel_clock_max / 1000, + (sdvo_priv->caps.sdvo_inputs_mask & 0x1) ? 'Y' : 'N', + (sdvo_priv->caps.sdvo_inputs_mask & 0x2) ? 'Y' : 'N', + /* check currently supported outputs */ + sdvo_priv->caps.output_flags & (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_RGB0) ? 'Y' : 'N', - sdvo_priv->caps.output_flags & + sdvo_priv->caps.output_flags & (SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1) ? 'Y' : 'N'); return true; diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index 98ac0546b7bd..ea68992e4416 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -1392,6 +1392,9 @@ intel_tv_detect_type (struct drm_crtc *crtc, struct intel_output *intel_output) tv_ctl &= ~TV_TEST_MODE_MASK; tv_ctl |= TV_TEST_MODE_MONITOR_DETECT; tv_dac &= ~TVDAC_SENSE_MASK; + tv_dac &= ~DAC_A_MASK; + tv_dac &= ~DAC_B_MASK; + tv_dac &= ~DAC_C_MASK; tv_dac |= (TVDAC_STATE_CHG_EN | TVDAC_A_SENSE_CTL | TVDAC_B_SENSE_CTL | @@ -1558,8 +1561,7 @@ intel_tv_destroy (struct drm_connector *connector) drm_sysfs_connector_remove(connector); drm_connector_cleanup(connector); - drm_free(intel_output, sizeof(struct intel_output) + sizeof(struct intel_tv_priv), - DRM_MEM_DRIVER); + kfree(intel_output); } @@ -1692,8 +1694,8 @@ intel_tv_init(struct drm_device *dev) (tv_dac_off & TVDAC_STATE_CHG_EN) != 0) return; - intel_output = drm_calloc(1, sizeof(struct intel_output) + - sizeof(struct intel_tv_priv), DRM_MEM_DRIVER); + intel_output = kzalloc(sizeof(struct intel_output) + + sizeof(struct intel_tv_priv), GFP_KERNEL); if (!intel_output) { return; } @@ -1727,8 +1729,8 @@ intel_tv_init(struct drm_device *dev) connector->doublescan_allowed = false; /* Create TV properties then attach current values */ - tv_format_names = drm_alloc(sizeof(char *) * NUM_TV_MODES, - DRM_MEM_DRIVER); + tv_format_names = kmalloc(sizeof(char *) * NUM_TV_MODES, + GFP_KERNEL); if (!tv_format_names) goto out; for (i = 0; i < NUM_TV_MODES; i++) diff --git a/drivers/gpu/drm/mga/mga_dma.c b/drivers/gpu/drm/mga/mga_dma.c index 7a6bf9ffc5a3..6c67a02910c8 100644 --- a/drivers/gpu/drm/mga/mga_dma.c +++ b/drivers/gpu/drm/mga/mga_dma.c @@ -254,23 +254,20 @@ static int mga_freelist_init(struct drm_device * dev, drm_mga_private_t * dev_pr int i; DRM_DEBUG("count=%d\n", dma->buf_count); - dev_priv->head = drm_alloc(sizeof(drm_mga_freelist_t), DRM_MEM_DRIVER); + dev_priv->head = kzalloc(sizeof(drm_mga_freelist_t), GFP_KERNEL); if (dev_priv->head == NULL) return -ENOMEM; - memset(dev_priv->head, 0, sizeof(drm_mga_freelist_t)); SET_AGE(&dev_priv->head->age, MGA_BUFFER_USED, 0); for (i = 0; i < dma->buf_count; i++) { buf = dma->buflist[i]; buf_priv = buf->dev_private; - entry = drm_alloc(sizeof(drm_mga_freelist_t), DRM_MEM_DRIVER); + entry = kzalloc(sizeof(drm_mga_freelist_t), GFP_KERNEL); if (entry == NULL) return -ENOMEM; - memset(entry, 0, sizeof(drm_mga_freelist_t)); - entry->next = dev_priv->head->next; entry->prev = dev_priv->head; SET_AGE(&entry->age, MGA_BUFFER_FREE, 0); @@ -301,7 +298,7 @@ static void mga_freelist_cleanup(struct drm_device * dev) entry = dev_priv->head; while (entry) { next = entry->next; - drm_free(entry, sizeof(drm_mga_freelist_t), DRM_MEM_DRIVER); + kfree(entry); entry = next; } @@ -399,12 +396,11 @@ int mga_driver_load(struct drm_device * dev, unsigned long flags) drm_mga_private_t *dev_priv; int ret; - dev_priv = drm_alloc(sizeof(drm_mga_private_t), DRM_MEM_DRIVER); + dev_priv = kzalloc(sizeof(drm_mga_private_t), GFP_KERNEL); if (!dev_priv) return -ENOMEM; dev->dev_private = (void *)dev_priv; - memset(dev_priv, 0, sizeof(drm_mga_private_t)); dev_priv->usec_timeout = MGA_DEFAULT_USEC_TIMEOUT; dev_priv->chipset = flags; @@ -1150,7 +1146,7 @@ int mga_dma_buffers(struct drm_device *dev, void *data, */ int mga_driver_unload(struct drm_device * dev) { - drm_free(dev->dev_private, sizeof(drm_mga_private_t), DRM_MEM_DRIVER); + kfree(dev->dev_private); dev->dev_private = NULL; return 0; diff --git a/drivers/gpu/drm/r128/r128_cce.c b/drivers/gpu/drm/r128/r128_cce.c index 077c0455a6b9..c75fd3564040 100644 --- a/drivers/gpu/drm/r128/r128_cce.c +++ b/drivers/gpu/drm/r128/r128_cce.c @@ -353,12 +353,10 @@ static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init) DRM_DEBUG("\n"); - dev_priv = drm_alloc(sizeof(drm_r128_private_t), DRM_MEM_DRIVER); + dev_priv = kzalloc(sizeof(drm_r128_private_t), GFP_KERNEL); if (dev_priv == NULL) return -ENOMEM; - memset(dev_priv, 0, sizeof(drm_r128_private_t)); - dev_priv->is_pci = init->is_pci; if (dev_priv->is_pci && !dev->sg) { @@ -619,8 +617,7 @@ int r128_do_cleanup_cce(struct drm_device * dev) ("failed to cleanup PCI GART!\n"); } - drm_free(dev->dev_private, sizeof(drm_r128_private_t), - DRM_MEM_DRIVER); + kfree(dev->dev_private); dev->dev_private = NULL; } @@ -768,18 +765,17 @@ static int r128_freelist_init(struct drm_device * dev) drm_r128_freelist_t *entry; int i; - dev_priv->head = drm_alloc(sizeof(drm_r128_freelist_t), DRM_MEM_DRIVER); + dev_priv->head = kzalloc(sizeof(drm_r128_freelist_t), GFP_KERNEL); if (dev_priv->head == NULL) return -ENOMEM; - memset(dev_priv->head, 0, sizeof(drm_r128_freelist_t)); dev_priv->head->age = R128_BUFFER_USED; for (i = 0; i < dma->buf_count; i++) { buf = dma->buflist[i]; buf_priv = buf->dev_private; - entry = drm_alloc(sizeof(drm_r128_freelist_t), DRM_MEM_DRIVER); + entry = kmalloc(sizeof(drm_r128_freelist_t), GFP_KERNEL); if (!entry) return -ENOMEM; diff --git a/drivers/gpu/drm/r128/r128_state.c b/drivers/gpu/drm/r128/r128_state.c index f7a5b5740764..026a48c95c8f 100644 --- a/drivers/gpu/drm/r128/r128_state.c +++ b/drivers/gpu/drm/r128/r128_state.c @@ -910,24 +910,24 @@ static int r128_cce_dispatch_write_span(struct drm_device * dev, } buffer_size = depth->n * sizeof(u32); - buffer = drm_alloc(buffer_size, DRM_MEM_BUFS); + buffer = kmalloc(buffer_size, GFP_KERNEL); if (buffer == NULL) return -ENOMEM; if (DRM_COPY_FROM_USER(buffer, depth->buffer, buffer_size)) { - drm_free(buffer, buffer_size, DRM_MEM_BUFS); + kfree(buffer); return -EFAULT; } mask_size = depth->n * sizeof(u8); if (depth->mask) { - mask = drm_alloc(mask_size, DRM_MEM_BUFS); + mask = kmalloc(mask_size, GFP_KERNEL); if (mask == NULL) { - drm_free(buffer, buffer_size, DRM_MEM_BUFS); + kfree(buffer); return -ENOMEM; } if (DRM_COPY_FROM_USER(mask, depth->mask, mask_size)) { - drm_free(buffer, buffer_size, DRM_MEM_BUFS); - drm_free(mask, mask_size, DRM_MEM_BUFS); + kfree(buffer); + kfree(mask); return -EFAULT; } @@ -954,7 +954,7 @@ static int r128_cce_dispatch_write_span(struct drm_device * dev, } } - drm_free(mask, mask_size, DRM_MEM_BUFS); + kfree(mask); } else { for (i = 0; i < count; i++, x++) { BEGIN_RING(6); @@ -978,7 +978,7 @@ static int r128_cce_dispatch_write_span(struct drm_device * dev, } } - drm_free(buffer, buffer_size, DRM_MEM_BUFS); + kfree(buffer); return 0; } @@ -1000,54 +1000,54 @@ static int r128_cce_dispatch_write_pixels(struct drm_device * dev, xbuf_size = count * sizeof(*x); ybuf_size = count * sizeof(*y); - x = drm_alloc(xbuf_size, DRM_MEM_BUFS); + x = kmalloc(xbuf_size, GFP_KERNEL); if (x == NULL) { return -ENOMEM; } - y = drm_alloc(ybuf_size, DRM_MEM_BUFS); + y = kmalloc(ybuf_size, GFP_KERNEL); if (y == NULL) { - drm_free(x, xbuf_size, DRM_MEM_BUFS); + kfree(x); return -ENOMEM; } if (DRM_COPY_FROM_USER(x, depth->x, xbuf_size)) { - drm_free(x, xbuf_size, DRM_MEM_BUFS); - drm_free(y, ybuf_size, DRM_MEM_BUFS); + kfree(x); + kfree(y); return -EFAULT; } if (DRM_COPY_FROM_USER(y, depth->y, xbuf_size)) { - drm_free(x, xbuf_size, DRM_MEM_BUFS); - drm_free(y, ybuf_size, DRM_MEM_BUFS); + kfree(x); + kfree(y); return -EFAULT; } buffer_size = depth->n * sizeof(u32); - buffer = drm_alloc(buffer_size, DRM_MEM_BUFS); + buffer = kmalloc(buffer_size, GFP_KERNEL); if (buffer == NULL) { - drm_free(x, xbuf_size, DRM_MEM_BUFS); - drm_free(y, ybuf_size, DRM_MEM_BUFS); + kfree(x); + kfree(y); return -ENOMEM; } if (DRM_COPY_FROM_USER(buffer, depth->buffer, buffer_size)) { - drm_free(x, xbuf_size, DRM_MEM_BUFS); - drm_free(y, ybuf_size, DRM_MEM_BUFS); - drm_free(buffer, buffer_size, DRM_MEM_BUFS); + kfree(x); + kfree(y); + kfree(buffer); return -EFAULT; } if (depth->mask) { mask_size = depth->n * sizeof(u8); - mask = drm_alloc(mask_size, DRM_MEM_BUFS); + mask = kmalloc(mask_size, GFP_KERNEL); if (mask == NULL) { - drm_free(x, xbuf_size, DRM_MEM_BUFS); - drm_free(y, ybuf_size, DRM_MEM_BUFS); - drm_free(buffer, buffer_size, DRM_MEM_BUFS); + kfree(x); + kfree(y); + kfree(buffer); return -ENOMEM; } if (DRM_COPY_FROM_USER(mask, depth->mask, mask_size)) { - drm_free(x, xbuf_size, DRM_MEM_BUFS); - drm_free(y, ybuf_size, DRM_MEM_BUFS); - drm_free(buffer, buffer_size, DRM_MEM_BUFS); - drm_free(mask, mask_size, DRM_MEM_BUFS); + kfree(x); + kfree(y); + kfree(buffer); + kfree(mask); return -EFAULT; } @@ -1074,7 +1074,7 @@ static int r128_cce_dispatch_write_pixels(struct drm_device * dev, } } - drm_free(mask, mask_size, DRM_MEM_BUFS); + kfree(mask); } else { for (i = 0; i < count; i++) { BEGIN_RING(6); @@ -1098,9 +1098,9 @@ static int r128_cce_dispatch_write_pixels(struct drm_device * dev, } } - drm_free(x, xbuf_size, DRM_MEM_BUFS); - drm_free(y, ybuf_size, DRM_MEM_BUFS); - drm_free(buffer, buffer_size, DRM_MEM_BUFS); + kfree(x); + kfree(y); + kfree(buffer); return 0; } @@ -1167,23 +1167,23 @@ static int r128_cce_dispatch_read_pixels(struct drm_device * dev, xbuf_size = count * sizeof(*x); ybuf_size = count * sizeof(*y); - x = drm_alloc(xbuf_size, DRM_MEM_BUFS); + x = kmalloc(xbuf_size, GFP_KERNEL); if (x == NULL) { return -ENOMEM; } - y = drm_alloc(ybuf_size, DRM_MEM_BUFS); + y = kmalloc(ybuf_size, GFP_KERNEL); if (y == NULL) { - drm_free(x, xbuf_size, DRM_MEM_BUFS); + kfree(x); return -ENOMEM; } if (DRM_COPY_FROM_USER(x, depth->x, xbuf_size)) { - drm_free(x, xbuf_size, DRM_MEM_BUFS); - drm_free(y, ybuf_size, DRM_MEM_BUFS); + kfree(x); + kfree(y); return -EFAULT; } if (DRM_COPY_FROM_USER(y, depth->y, ybuf_size)) { - drm_free(x, xbuf_size, DRM_MEM_BUFS); - drm_free(y, ybuf_size, DRM_MEM_BUFS); + kfree(x); + kfree(y); return -EFAULT; } @@ -1210,8 +1210,8 @@ static int r128_cce_dispatch_read_pixels(struct drm_device * dev, ADVANCE_RING(); } - drm_free(x, xbuf_size, DRM_MEM_BUFS); - drm_free(y, ybuf_size, DRM_MEM_BUFS); + kfree(x); + kfree(y); return 0; } diff --git a/drivers/gpu/drm/radeon/Kconfig b/drivers/gpu/drm/radeon/Kconfig new file mode 100644 index 000000000000..2168d67f09a6 --- /dev/null +++ b/drivers/gpu/drm/radeon/Kconfig @@ -0,0 +1,34 @@ +config DRM_RADEON_KMS + bool "Enable modesetting on radeon by default" + depends on DRM_RADEON + select DRM_TTM + help + Choose this option if you want kernel modesetting enabled by default, + and you have a new enough userspace to support this. Running old + userspaces with this enabled will cause pain. + + When kernel modesetting is enabled the IOCTL of radeon/drm + driver are considered as invalid and an error message is printed + in the log and they return failure. + + KMS enabled userspace will use new API to talk with the radeon/drm + driver. The new API provide functions to create/destroy/share/mmap + buffer object which are then managed by the kernel memory manager + (here TTM). In order to submit command to the GPU the userspace + provide a buffer holding the command stream, along this buffer + userspace have to provide a list of buffer object used by the + command stream. The kernel radeon driver will then place buffer + in GPU accessible memory and will update command stream to reflect + the position of the different buffers. + + The kernel will also perform security check on command stream + provided by the user, we want to catch and forbid any illegal use + of the GPU such as DMA into random system memory or into memory + not owned by the process supplying the command stream. This part + of the code is still incomplete and this why we propose that patch + as a staging driver addition, future security might forbid current + experimental userspace to run. + + This code support the following hardware : R1XX,R2XX,R3XX,R4XX,R5XX + (radeon up to X1950). Works is underway to provide support for R6XX, + R7XX and newer hardware (radeon from HD2XXX to HD4XXX). diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile index 52ce439a0f2e..5fae1e074b4b 100644 --- a/drivers/gpu/drm/radeon/Makefile +++ b/drivers/gpu/drm/radeon/Makefile @@ -3,7 +3,17 @@ # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. ccflags-y := -Iinclude/drm -radeon-y := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o r600_cp.o +radeon-y := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o \ + radeon_irq.o r300_cmdbuf.o r600_cp.o + +radeon-$(CONFIG_DRM_RADEON_KMS) += radeon_device.o radeon_kms.o \ + radeon_atombios.o radeon_agp.o atombios_crtc.o radeon_combios.o \ + atom.o radeon_fence.o radeon_ttm.o radeon_object.o radeon_gart.o \ + radeon_legacy_crtc.o radeon_legacy_encoders.o radeon_connectors.o \ + radeon_encoders.o radeon_display.o radeon_cursor.o radeon_i2c.o \ + radeon_clocks.o radeon_fb.o radeon_gem.o radeon_ring.o radeon_irq_kms.o \ + radeon_cs.o radeon_bios.o radeon_benchmark.o r100.o r300.o r420.o \ + rs400.o rs600.o rs690.o rv515.o r520.o r600.o rs780.o rv770.o radeon-$(CONFIG_COMPAT) += radeon_ioc32.o diff --git a/drivers/gpu/drm/radeon/ObjectID.h b/drivers/gpu/drm/radeon/ObjectID.h new file mode 100644 index 000000000000..6d0183c61d3b --- /dev/null +++ b/drivers/gpu/drm/radeon/ObjectID.h @@ -0,0 +1,578 @@ +/* +* Copyright 2006-2007 Advanced Micro Devices, Inc. +* +* Permission is hereby granted, free of charge, to any person obtaining a +* copy of this software and associated documentation files (the "Software"), +* to deal in the Software without restriction, including without limitation +* the rights to use, copy, modify, merge, publish, distribute, sublicense, +* and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR +* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +* OTHER DEALINGS IN THE SOFTWARE. +*/ +/* based on stg/asic_reg/drivers/inc/asic_reg/ObjectID.h ver 23 */ + +#ifndef _OBJECTID_H +#define _OBJECTID_H + +#if defined(_X86_) +#pragma pack(1) +#endif + +/****************************************************/ +/* Graphics Object Type Definition */ +/****************************************************/ +#define GRAPH_OBJECT_TYPE_NONE 0x0 +#define GRAPH_OBJECT_TYPE_GPU 0x1 +#define GRAPH_OBJECT_TYPE_ENCODER 0x2 +#define GRAPH_OBJECT_TYPE_CONNECTOR 0x3 +#define GRAPH_OBJECT_TYPE_ROUTER 0x4 +/* deleted */ + +/****************************************************/ +/* Encoder Object ID Definition */ +/****************************************************/ +#define ENCODER_OBJECT_ID_NONE 0x00 + +/* Radeon Class Display Hardware */ +#define ENCODER_OBJECT_ID_INTERNAL_LVDS 0x01 +#define ENCODER_OBJECT_ID_INTERNAL_TMDS1 0x02 +#define ENCODER_OBJECT_ID_INTERNAL_TMDS2 0x03 +#define ENCODER_OBJECT_ID_INTERNAL_DAC1 0x04 +#define ENCODER_OBJECT_ID_INTERNAL_DAC2 0x05 /* TV/CV DAC */ +#define ENCODER_OBJECT_ID_INTERNAL_SDVOA 0x06 +#define ENCODER_OBJECT_ID_INTERNAL_SDVOB 0x07 + +/* External Third Party Encoders */ +#define ENCODER_OBJECT_ID_SI170B 0x08 +#define ENCODER_OBJECT_ID_CH7303 0x09 +#define ENCODER_OBJECT_ID_CH7301 0x0A +#define ENCODER_OBJECT_ID_INTERNAL_DVO1 0x0B /* This belongs to Radeon Class Display Hardware */ +#define ENCODER_OBJECT_ID_EXTERNAL_SDVOA 0x0C +#define ENCODER_OBJECT_ID_EXTERNAL_SDVOB 0x0D +#define ENCODER_OBJECT_ID_TITFP513 0x0E +#define ENCODER_OBJECT_ID_INTERNAL_LVTM1 0x0F /* not used for Radeon */ +#define ENCODER_OBJECT_ID_VT1623 0x10 +#define ENCODER_OBJECT_ID_HDMI_SI1930 0x11 +#define ENCODER_OBJECT_ID_HDMI_INTERNAL 0x12 +/* Kaleidoscope (KLDSCP) Class Display Hardware (internal) */ +#define ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1 0x13 +#define ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1 0x14 +#define ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1 0x15 +#define ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2 0x16 /* Shared with CV/TV and CRT */ +#define ENCODER_OBJECT_ID_SI178 0X17 /* External TMDS (dual link, no HDCP.) */ +#define ENCODER_OBJECT_ID_MVPU_FPGA 0x18 /* MVPU FPGA chip */ +#define ENCODER_OBJECT_ID_INTERNAL_DDI 0x19 +#define ENCODER_OBJECT_ID_VT1625 0x1A +#define ENCODER_OBJECT_ID_HDMI_SI1932 0x1B +#define ENCODER_OBJECT_ID_DP_AN9801 0x1C +#define ENCODER_OBJECT_ID_DP_DP501 0x1D +#define ENCODER_OBJECT_ID_INTERNAL_UNIPHY 0x1E +#define ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA 0x1F +#define ENCODER_OBJECT_ID_INTERNAL_UNIPHY1 0x20 +#define ENCODER_OBJECT_ID_INTERNAL_UNIPHY2 0x21 + +#define ENCODER_OBJECT_ID_GENERAL_EXTERNAL_DVO 0xFF + +/****************************************************/ +/* Connector Object ID Definition */ +/****************************************************/ +#define CONNECTOR_OBJECT_ID_NONE 0x00 +#define CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I 0x01 +#define CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I 0x02 +#define CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D 0x03 +#define CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D 0x04 +#define CONNECTOR_OBJECT_ID_VGA 0x05 +#define CONNECTOR_OBJECT_ID_COMPOSITE 0x06 +#define CONNECTOR_OBJECT_ID_SVIDEO 0x07 +#define CONNECTOR_OBJECT_ID_YPbPr 0x08 +#define CONNECTOR_OBJECT_ID_D_CONNECTOR 0x09 +#define CONNECTOR_OBJECT_ID_9PIN_DIN 0x0A /* Supports both CV & TV */ +#define CONNECTOR_OBJECT_ID_SCART 0x0B +#define CONNECTOR_OBJECT_ID_HDMI_TYPE_A 0x0C +#define CONNECTOR_OBJECT_ID_HDMI_TYPE_B 0x0D +#define CONNECTOR_OBJECT_ID_LVDS 0x0E +#define CONNECTOR_OBJECT_ID_7PIN_DIN 0x0F +#define CONNECTOR_OBJECT_ID_PCIE_CONNECTOR 0x10 +#define CONNECTOR_OBJECT_ID_CROSSFIRE 0x11 +#define CONNECTOR_OBJECT_ID_HARDCODE_DVI 0x12 +#define CONNECTOR_OBJECT_ID_DISPLAYPORT 0x13 + +/* deleted */ + +/****************************************************/ +/* Router Object ID Definition */ +/****************************************************/ +#define ROUTER_OBJECT_ID_NONE 0x00 +#define ROUTER_OBJECT_ID_I2C_EXTENDER_CNTL 0x01 + +/****************************************************/ +/* Graphics Object ENUM ID Definition */ +/****************************************************/ +#define GRAPH_OBJECT_ENUM_ID1 0x01 +#define GRAPH_OBJECT_ENUM_ID2 0x02 +#define GRAPH_OBJECT_ENUM_ID3 0x03 +#define GRAPH_OBJECT_ENUM_ID4 0x04 +#define GRAPH_OBJECT_ENUM_ID5 0x05 +#define GRAPH_OBJECT_ENUM_ID6 0x06 + +/****************************************************/ +/* Graphics Object ID Bit definition */ +/****************************************************/ +#define OBJECT_ID_MASK 0x00FF +#define ENUM_ID_MASK 0x0700 +#define RESERVED1_ID_MASK 0x0800 +#define OBJECT_TYPE_MASK 0x7000 +#define RESERVED2_ID_MASK 0x8000 + +#define OBJECT_ID_SHIFT 0x00 +#define ENUM_ID_SHIFT 0x08 +#define OBJECT_TYPE_SHIFT 0x0C + +/****************************************************/ +/* Graphics Object family definition */ +/****************************************************/ +#define CONSTRUCTOBJECTFAMILYID(GRAPHICS_OBJECT_TYPE, GRAPHICS_OBJECT_ID) \ + (GRAPHICS_OBJECT_TYPE << OBJECT_TYPE_SHIFT | \ + GRAPHICS_OBJECT_ID << OBJECT_ID_SHIFT) +/****************************************************/ +/* GPU Object ID definition - Shared with BIOS */ +/****************************************************/ +#define GPU_ENUM_ID1 (GRAPH_OBJECT_TYPE_GPU << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT) + +/****************************************************/ +/* Encoder Object ID definition - Shared with BIOS */ +/****************************************************/ +/* +#define ENCODER_INTERNAL_LVDS_ENUM_ID1 0x2101 +#define ENCODER_INTERNAL_TMDS1_ENUM_ID1 0x2102 +#define ENCODER_INTERNAL_TMDS2_ENUM_ID1 0x2103 +#define ENCODER_INTERNAL_DAC1_ENUM_ID1 0x2104 +#define ENCODER_INTERNAL_DAC2_ENUM_ID1 0x2105 +#define ENCODER_INTERNAL_SDVOA_ENUM_ID1 0x2106 +#define ENCODER_INTERNAL_SDVOB_ENUM_ID1 0x2107 +#define ENCODER_SIL170B_ENUM_ID1 0x2108 +#define ENCODER_CH7303_ENUM_ID1 0x2109 +#define ENCODER_CH7301_ENUM_ID1 0x210A +#define ENCODER_INTERNAL_DVO1_ENUM_ID1 0x210B +#define ENCODER_EXTERNAL_SDVOA_ENUM_ID1 0x210C +#define ENCODER_EXTERNAL_SDVOB_ENUM_ID1 0x210D +#define ENCODER_TITFP513_ENUM_ID1 0x210E +#define ENCODER_INTERNAL_LVTM1_ENUM_ID1 0x210F +#define ENCODER_VT1623_ENUM_ID1 0x2110 +#define ENCODER_HDMI_SI1930_ENUM_ID1 0x2111 +#define ENCODER_HDMI_INTERNAL_ENUM_ID1 0x2112 +#define ENCODER_INTERNAL_KLDSCP_TMDS1_ENUM_ID1 0x2113 +#define ENCODER_INTERNAL_KLDSCP_DVO1_ENUM_ID1 0x2114 +#define ENCODER_INTERNAL_KLDSCP_DAC1_ENUM_ID1 0x2115 +#define ENCODER_INTERNAL_KLDSCP_DAC2_ENUM_ID1 0x2116 +#define ENCODER_SI178_ENUM_ID1 0x2117 +#define ENCODER_MVPU_FPGA_ENUM_ID1 0x2118 +#define ENCODER_INTERNAL_DDI_ENUM_ID1 0x2119 +#define ENCODER_VT1625_ENUM_ID1 0x211A +#define ENCODER_HDMI_SI1932_ENUM_ID1 0x211B +#define ENCODER_ENCODER_DP_AN9801_ENUM_ID1 0x211C +#define ENCODER_DP_DP501_ENUM_ID1 0x211D +#define ENCODER_INTERNAL_UNIPHY_ENUM_ID1 0x211E +*/ +#define ENCODER_INTERNAL_LVDS_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_LVDS << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_TMDS1_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_TMDS1 << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_TMDS2_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_TMDS2 << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_DAC1_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_DAC1 << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_DAC2_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_DAC2 << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_SDVOA_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_SDVOA << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_SDVOA_ENUM_ID2 \ + (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_SDVOA << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_SDVOB_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_SDVOB << OBJECT_ID_SHIFT) + +#define ENCODER_SIL170B_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_SI170B << OBJECT_ID_SHIFT) + +#define ENCODER_CH7303_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_CH7303 << OBJECT_ID_SHIFT) + +#define ENCODER_CH7301_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_CH7301 << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_DVO1_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_DVO1 << OBJECT_ID_SHIFT) + +#define ENCODER_EXTERNAL_SDVOA_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_EXTERNAL_SDVOA << OBJECT_ID_SHIFT) + +#define ENCODER_EXTERNAL_SDVOA_ENUM_ID2 \ + (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_EXTERNAL_SDVOA << OBJECT_ID_SHIFT) + +#define ENCODER_EXTERNAL_SDVOB_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_EXTERNAL_SDVOB << OBJECT_ID_SHIFT) + +#define ENCODER_TITFP513_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_TITFP513 << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_LVTM1_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_LVTM1 << OBJECT_ID_SHIFT) + +#define ENCODER_VT1623_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_VT1623 << OBJECT_ID_SHIFT) + +#define ENCODER_HDMI_SI1930_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_HDMI_SI1930 << OBJECT_ID_SHIFT) + +#define ENCODER_HDMI_INTERNAL_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_HDMI_INTERNAL << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_KLDSCP_TMDS1_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1 << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_KLDSCP_TMDS1_ENUM_ID2 \ + (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1 << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_KLDSCP_DVO1_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1 << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_KLDSCP_DAC1_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1 << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_KLDSCP_DAC2_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2 << OBJECT_ID_SHIFT) /* Shared with CV/TV and CRT */ + +#define ENCODER_SI178_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_SI178 << OBJECT_ID_SHIFT) + +#define ENCODER_MVPU_FPGA_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_MVPU_FPGA << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_DDI_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_DDI << OBJECT_ID_SHIFT) + +#define ENCODER_VT1625_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_VT1625 << OBJECT_ID_SHIFT) + +#define ENCODER_HDMI_SI1932_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_HDMI_SI1932 << OBJECT_ID_SHIFT) + +#define ENCODER_DP_DP501_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_DP_DP501 << OBJECT_ID_SHIFT) + +#define ENCODER_DP_AN9801_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_DP_AN9801 << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_UNIPHY_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_UNIPHY << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_UNIPHY_ENUM_ID2 \ + (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_UNIPHY << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_KLDSCP_LVTMA_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_UNIPHY1_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_UNIPHY1 << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_UNIPHY1_ENUM_ID2 \ + (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_UNIPHY1 << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_UNIPHY2_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_UNIPHY2 << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_UNIPHY2_ENUM_ID2 \ + (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_UNIPHY2 << OBJECT_ID_SHIFT) + +#define ENCODER_GENERAL_EXTERNAL_DVO_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_GENERAL_EXTERNAL_DVO << OBJECT_ID_SHIFT) + +/****************************************************/ +/* Connector Object ID definition - Shared with BIOS */ +/****************************************************/ +/* +#define CONNECTOR_SINGLE_LINK_DVI_I_ENUM_ID1 0x3101 +#define CONNECTOR_DUAL_LINK_DVI_I_ENUM_ID1 0x3102 +#define CONNECTOR_SINGLE_LINK_DVI_D_ENUM_ID1 0x3103 +#define CONNECTOR_DUAL_LINK_DVI_D_ENUM_ID1 0x3104 +#define CONNECTOR_VGA_ENUM_ID1 0x3105 +#define CONNECTOR_COMPOSITE_ENUM_ID1 0x3106 +#define CONNECTOR_SVIDEO_ENUM_ID1 0x3107 +#define CONNECTOR_YPbPr_ENUM_ID1 0x3108 +#define CONNECTOR_D_CONNECTORE_ENUM_ID1 0x3109 +#define CONNECTOR_9PIN_DIN_ENUM_ID1 0x310A +#define CONNECTOR_SCART_ENUM_ID1 0x310B +#define CONNECTOR_HDMI_TYPE_A_ENUM_ID1 0x310C +#define CONNECTOR_HDMI_TYPE_B_ENUM_ID1 0x310D +#define CONNECTOR_LVDS_ENUM_ID1 0x310E +#define CONNECTOR_7PIN_DIN_ENUM_ID1 0x310F +#define CONNECTOR_PCIE_CONNECTOR_ENUM_ID1 0x3110 +*/ +#define CONNECTOR_LVDS_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_LVDS << OBJECT_ID_SHIFT) + +#define CONNECTOR_SINGLE_LINK_DVI_I_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I << OBJECT_ID_SHIFT) + +#define CONNECTOR_SINGLE_LINK_DVI_I_ENUM_ID2 \ + (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I << OBJECT_ID_SHIFT) + +#define CONNECTOR_DUAL_LINK_DVI_I_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I << OBJECT_ID_SHIFT) + +#define CONNECTOR_DUAL_LINK_DVI_I_ENUM_ID2 \ + (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I << OBJECT_ID_SHIFT) + +#define CONNECTOR_SINGLE_LINK_DVI_D_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D << OBJECT_ID_SHIFT) + +#define CONNECTOR_SINGLE_LINK_DVI_D_ENUM_ID2 \ + (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D << OBJECT_ID_SHIFT) + +#define CONNECTOR_DUAL_LINK_DVI_D_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D << OBJECT_ID_SHIFT) + +#define CONNECTOR_VGA_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_VGA << OBJECT_ID_SHIFT) + +#define CONNECTOR_VGA_ENUM_ID2 \ + (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_VGA << OBJECT_ID_SHIFT) + +#define CONNECTOR_COMPOSITE_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_COMPOSITE << OBJECT_ID_SHIFT) + +#define CONNECTOR_SVIDEO_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_SVIDEO << OBJECT_ID_SHIFT) + +#define CONNECTOR_YPbPr_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_YPbPr << OBJECT_ID_SHIFT) + +#define CONNECTOR_D_CONNECTOR_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_D_CONNECTOR << OBJECT_ID_SHIFT) + +#define CONNECTOR_9PIN_DIN_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_9PIN_DIN << OBJECT_ID_SHIFT) + +#define CONNECTOR_SCART_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_SCART << OBJECT_ID_SHIFT) + +#define CONNECTOR_HDMI_TYPE_A_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_HDMI_TYPE_A << OBJECT_ID_SHIFT) + +#define CONNECTOR_HDMI_TYPE_B_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_HDMI_TYPE_B << OBJECT_ID_SHIFT) + +#define CONNECTOR_7PIN_DIN_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_7PIN_DIN << OBJECT_ID_SHIFT) + +#define CONNECTOR_PCIE_CONNECTOR_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_PCIE_CONNECTOR << OBJECT_ID_SHIFT) + +#define CONNECTOR_PCIE_CONNECTOR_ENUM_ID2 \ + (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_PCIE_CONNECTOR << OBJECT_ID_SHIFT) + +#define CONNECTOR_CROSSFIRE_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_CROSSFIRE << OBJECT_ID_SHIFT) + +#define CONNECTOR_CROSSFIRE_ENUM_ID2 \ + (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_CROSSFIRE << OBJECT_ID_SHIFT) + +#define CONNECTOR_HARDCODE_DVI_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_HARDCODE_DVI << OBJECT_ID_SHIFT) + +#define CONNECTOR_HARDCODE_DVI_ENUM_ID2 \ + (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_HARDCODE_DVI << OBJECT_ID_SHIFT) + +#define CONNECTOR_DISPLAYPORT_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_DISPLAYPORT << OBJECT_ID_SHIFT) + +#define CONNECTOR_DISPLAYPORT_ENUM_ID2 \ + (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_DISPLAYPORT << OBJECT_ID_SHIFT) + +#define CONNECTOR_DISPLAYPORT_ENUM_ID3 \ + (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID3 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_DISPLAYPORT << OBJECT_ID_SHIFT) + +#define CONNECTOR_DISPLAYPORT_ENUM_ID4 \ + (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID4 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_DISPLAYPORT << OBJECT_ID_SHIFT) + +/****************************************************/ +/* Router Object ID definition - Shared with BIOS */ +/****************************************************/ +#define ROUTER_I2C_EXTENDER_CNTL_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_ROUTER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ROUTER_OBJECT_ID_I2C_EXTENDER_CNTL << OBJECT_ID_SHIFT) + +/* deleted */ + +/****************************************************/ +/* Object Cap definition - Shared with BIOS */ +/****************************************************/ +#define GRAPHICS_OBJECT_CAP_I2C 0x00000001L +#define GRAPHICS_OBJECT_CAP_TABLE_ID 0x00000002L + +#define GRAPHICS_OBJECT_I2CCOMMAND_TABLE_ID 0x01 +#define GRAPHICS_OBJECT_HOTPLUGDETECTIONINTERUPT_TABLE_ID 0x02 +#define GRAPHICS_OBJECT_ENCODER_OUTPUT_PROTECTION_TABLE_ID 0x03 + +#if defined(_X86_) +#pragma pack() +#endif + +#endif /*GRAPHICTYPE */ diff --git a/drivers/gpu/drm/radeon/atom-bits.h b/drivers/gpu/drm/radeon/atom-bits.h new file mode 100644 index 000000000000..e8fae5c77514 --- /dev/null +++ b/drivers/gpu/drm/radeon/atom-bits.h @@ -0,0 +1,48 @@ +/* + * Copyright 2008 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Author: Stanislaw Skowronek + */ + +#ifndef ATOM_BITS_H +#define ATOM_BITS_H + +static inline uint8_t get_u8(void *bios, int ptr) +{ + return ((unsigned char *)bios)[ptr]; +} +#define U8(ptr) get_u8(ctx->ctx->bios, (ptr)) +#define CU8(ptr) get_u8(ctx->bios, (ptr)) +static inline uint16_t get_u16(void *bios, int ptr) +{ + return get_u8(bios ,ptr)|(((uint16_t)get_u8(bios, ptr+1))<<8); +} +#define U16(ptr) get_u16(ctx->ctx->bios, (ptr)) +#define CU16(ptr) get_u16(ctx->bios, (ptr)) +static inline uint32_t get_u32(void *bios, int ptr) +{ + return get_u16(bios, ptr)|(((uint32_t)get_u16(bios, ptr+2))<<16); +} +#define U32(ptr) get_u32(ctx->ctx->bios, (ptr)) +#define CU32(ptr) get_u32(ctx->bios, (ptr)) +#define CSTR(ptr) (((char *)(ctx->bios))+(ptr)) + +#endif diff --git a/drivers/gpu/drm/radeon/atom-names.h b/drivers/gpu/drm/radeon/atom-names.h new file mode 100644 index 000000000000..6f907a5ffa5f --- /dev/null +++ b/drivers/gpu/drm/radeon/atom-names.h @@ -0,0 +1,100 @@ +/* + * Copyright 2008 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Author: Stanislaw Skowronek + */ + +#ifndef ATOM_NAMES_H +#define ATOM_NAMES_H + +#include "atom.h" + +#ifdef ATOM_DEBUG + +#define ATOM_OP_NAMES_CNT 123 +static char *atom_op_names[ATOM_OP_NAMES_CNT] = { +"RESERVED", "MOVE_REG", "MOVE_PS", "MOVE_WS", "MOVE_FB", "MOVE_PLL", +"MOVE_MC", "AND_REG", "AND_PS", "AND_WS", "AND_FB", "AND_PLL", "AND_MC", +"OR_REG", "OR_PS", "OR_WS", "OR_FB", "OR_PLL", "OR_MC", "SHIFT_LEFT_REG", +"SHIFT_LEFT_PS", "SHIFT_LEFT_WS", "SHIFT_LEFT_FB", "SHIFT_LEFT_PLL", +"SHIFT_LEFT_MC", "SHIFT_RIGHT_REG", "SHIFT_RIGHT_PS", "SHIFT_RIGHT_WS", +"SHIFT_RIGHT_FB", "SHIFT_RIGHT_PLL", "SHIFT_RIGHT_MC", "MUL_REG", +"MUL_PS", "MUL_WS", "MUL_FB", "MUL_PLL", "MUL_MC", "DIV_REG", "DIV_PS", +"DIV_WS", "DIV_FB", "DIV_PLL", "DIV_MC", "ADD_REG", "ADD_PS", "ADD_WS", +"ADD_FB", "ADD_PLL", "ADD_MC", "SUB_REG", "SUB_PS", "SUB_WS", "SUB_FB", +"SUB_PLL", "SUB_MC", "SET_ATI_PORT", "SET_PCI_PORT", "SET_SYS_IO_PORT", +"SET_REG_BLOCK", "SET_FB_BASE", "COMPARE_REG", "COMPARE_PS", +"COMPARE_WS", "COMPARE_FB", "COMPARE_PLL", "COMPARE_MC", "SWITCH", +"JUMP", "JUMP_EQUAL", "JUMP_BELOW", "JUMP_ABOVE", "JUMP_BELOW_OR_EQUAL", +"JUMP_ABOVE_OR_EQUAL", "JUMP_NOT_EQUAL", "TEST_REG", "TEST_PS", "TEST_WS", +"TEST_FB", "TEST_PLL", "TEST_MC", "DELAY_MILLISEC", "DELAY_MICROSEC", +"CALL_TABLE", "REPEAT", "CLEAR_REG", "CLEAR_PS", "CLEAR_WS", "CLEAR_FB", +"CLEAR_PLL", "CLEAR_MC", "NOP", "EOT", "MASK_REG", "MASK_PS", "MASK_WS", +"MASK_FB", "MASK_PLL", "MASK_MC", "POST_CARD", "BEEP", "SAVE_REG", +"RESTORE_REG", "SET_DATA_BLOCK", "XOR_REG", "XOR_PS", "XOR_WS", "XOR_FB", +"XOR_PLL", "XOR_MC", "SHL_REG", "SHL_PS", "SHL_WS", "SHL_FB", "SHL_PLL", +"SHL_MC", "SHR_REG", "SHR_PS", "SHR_WS", "SHR_FB", "SHR_PLL", "SHR_MC", +"DEBUG", "CTB_DS", +}; + +#define ATOM_TABLE_NAMES_CNT 74 +static char *atom_table_names[ATOM_TABLE_NAMES_CNT] = { +"ASIC_Init", "GetDisplaySurfaceSize", "ASIC_RegistersInit", +"VRAM_BlockVenderDetection", "SetClocksRatio", "MemoryControllerInit", +"GPIO_PinInit", "MemoryParamAdjust", "DVOEncoderControl", +"GPIOPinControl", "SetEngineClock", "SetMemoryClock", "SetPixelClock", +"DynamicClockGating", "ResetMemoryDLL", "ResetMemoryDevice", +"MemoryPLLInit", "EnableMemorySelfRefresh", "AdjustMemoryController", +"EnableASIC_StaticPwrMgt", "ASIC_StaticPwrMgtStatusChange", +"DAC_LoadDetection", "TMDS2EncoderControl", "LCD1OutputControl", +"DAC1EncoderControl", "DAC2EncoderControl", "DVOOutputControl", +"CV1OutputControl", "SetCRTC_DPM_State", "TVEncoderControl", +"TMDS1EncoderControl", "LVDSEncoderControl", "TV1OutputControl", +"EnableScaler", "BlankCRTC", "EnableCRTC", "GetPixelClock", +"EnableVGA_Render", "EnableVGA_Access", "SetCRTC_Timing", +"SetCRTC_OverScan", "SetCRTC_Replication", "SelectCRTC_Source", +"EnableGraphSurfaces", "UpdateCRTC_DoubleBufferRegisters", +"LUT_AutoFill", "EnableHW_IconCursor", "GetMemoryClock", +"GetEngineClock", "SetCRTC_UsingDTDTiming", "TVBootUpStdPinDetection", +"DFP2OutputControl", "VRAM_BlockDetectionByStrap", "MemoryCleanUp", +"ReadEDIDFromHWAssistedI2C", "WriteOneByteToHWAssistedI2C", +"ReadHWAssistedI2CStatus", "SpeedFanControl", "PowerConnectorDetection", +"MC_Synchronization", "ComputeMemoryEnginePLL", "MemoryRefreshConversion", +"VRAM_GetCurrentInfoBlock", "DynamicMemorySettings", "MemoryTraining", +"EnableLVDS_SS", "DFP1OutputControl", "SetVoltage", "CRT1OutputControl", +"CRT2OutputControl", "SetupHWAssistedI2CStatus", "ClockSource", +"MemoryDeviceInit", "EnableYUV", +}; + +#define ATOM_IO_NAMES_CNT 5 +static char *atom_io_names[ATOM_IO_NAMES_CNT] = { +"MM", "PLL", "MC", "PCIE", "PCIE PORT", +}; + +#else + +#define ATOM_OP_NAMES_CNT 0 +#define ATOM_TABLE_NAMES_CNT 0 +#define ATOM_IO_NAMES_CNT 0 + +#endif + +#endif diff --git a/drivers/gpu/drm/radeon/atom-types.h b/drivers/gpu/drm/radeon/atom-types.h new file mode 100644 index 000000000000..1125b866cdb0 --- /dev/null +++ b/drivers/gpu/drm/radeon/atom-types.h @@ -0,0 +1,42 @@ +/* + * Copyright 2008 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Author: Dave Airlie + */ + +#ifndef ATOM_TYPES_H +#define ATOM_TYPES_H + +/* sync atom types to kernel types */ + +typedef uint16_t USHORT; +typedef uint32_t ULONG; +typedef uint8_t UCHAR; + + +#ifndef ATOM_BIG_ENDIAN +#if defined(__BIG_ENDIAN) +#define ATOM_BIG_ENDIAN 1 +#else +#define ATOM_BIG_ENDIAN 0 +#endif +#endif +#endif diff --git a/drivers/gpu/drm/radeon/atom.c b/drivers/gpu/drm/radeon/atom.c new file mode 100644 index 000000000000..901befe03da2 --- /dev/null +++ b/drivers/gpu/drm/radeon/atom.c @@ -0,0 +1,1215 @@ +/* + * Copyright 2008 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Author: Stanislaw Skowronek + */ + +#include +#include + +#define ATOM_DEBUG + +#include "atom.h" +#include "atom-names.h" +#include "atom-bits.h" + +#define ATOM_COND_ABOVE 0 +#define ATOM_COND_ABOVEOREQUAL 1 +#define ATOM_COND_ALWAYS 2 +#define ATOM_COND_BELOW 3 +#define ATOM_COND_BELOWOREQUAL 4 +#define ATOM_COND_EQUAL 5 +#define ATOM_COND_NOTEQUAL 6 + +#define ATOM_PORT_ATI 0 +#define ATOM_PORT_PCI 1 +#define ATOM_PORT_SYSIO 2 + +#define ATOM_UNIT_MICROSEC 0 +#define ATOM_UNIT_MILLISEC 1 + +#define PLL_INDEX 2 +#define PLL_DATA 3 + +typedef struct { + struct atom_context *ctx; + + uint32_t *ps, *ws; + int ps_shift; + uint16_t start; +} atom_exec_context; + +int atom_debug = 0; +void atom_execute_table(struct atom_context *ctx, int index, uint32_t * params); + +static uint32_t atom_arg_mask[8] = + { 0xFFFFFFFF, 0xFFFF, 0xFFFF00, 0xFFFF0000, 0xFF, 0xFF00, 0xFF0000, +0xFF000000 }; +static int atom_arg_shift[8] = { 0, 0, 8, 16, 0, 8, 16, 24 }; + +static int atom_dst_to_src[8][4] = { + /* translate destination alignment field to the source alignment encoding */ + {0, 0, 0, 0}, + {1, 2, 3, 0}, + {1, 2, 3, 0}, + {1, 2, 3, 0}, + {4, 5, 6, 7}, + {4, 5, 6, 7}, + {4, 5, 6, 7}, + {4, 5, 6, 7}, +}; +static int atom_def_dst[8] = { 0, 0, 1, 2, 0, 1, 2, 3 }; + +static int debug_depth = 0; +#ifdef ATOM_DEBUG +static void debug_print_spaces(int n) +{ + while (n--) + printk(" "); +} + +#define DEBUG(...) do if (atom_debug) { printk(KERN_DEBUG __VA_ARGS__); } while (0) +#define SDEBUG(...) do if (atom_debug) { printk(KERN_DEBUG); debug_print_spaces(debug_depth); printk(__VA_ARGS__); } while (0) +#else +#define DEBUG(...) do { } while (0) +#define SDEBUG(...) do { } while (0) +#endif + +static uint32_t atom_iio_execute(struct atom_context *ctx, int base, + uint32_t index, uint32_t data) +{ + uint32_t temp = 0xCDCDCDCD; + while (1) + switch (CU8(base)) { + case ATOM_IIO_NOP: + base++; + break; + case ATOM_IIO_READ: + temp = ctx->card->reg_read(ctx->card, CU16(base + 1)); + base += 3; + break; + case ATOM_IIO_WRITE: + ctx->card->reg_write(ctx->card, CU16(base + 1), temp); + base += 3; + break; + case ATOM_IIO_CLEAR: + temp &= + ~((0xFFFFFFFF >> (32 - CU8(base + 1))) << + CU8(base + 2)); + base += 3; + break; + case ATOM_IIO_SET: + temp |= + (0xFFFFFFFF >> (32 - CU8(base + 1))) << CU8(base + + 2); + base += 3; + break; + case ATOM_IIO_MOVE_INDEX: + temp &= + ~((0xFFFFFFFF >> (32 - CU8(base + 1))) << + CU8(base + 2)); + temp |= + ((index >> CU8(base + 2)) & + (0xFFFFFFFF >> (32 - CU8(base + 1)))) << CU8(base + + 3); + base += 4; + break; + case ATOM_IIO_MOVE_DATA: + temp &= + ~((0xFFFFFFFF >> (32 - CU8(base + 1))) << + CU8(base + 2)); + temp |= + ((data >> CU8(base + 2)) & + (0xFFFFFFFF >> (32 - CU8(base + 1)))) << CU8(base + + 3); + base += 4; + break; + case ATOM_IIO_MOVE_ATTR: + temp &= + ~((0xFFFFFFFF >> (32 - CU8(base + 1))) << + CU8(base + 2)); + temp |= + ((ctx-> + io_attr >> CU8(base + 2)) & (0xFFFFFFFF >> (32 - + CU8 + (base + + + 1)))) + << CU8(base + 3); + base += 4; + break; + case ATOM_IIO_END: + return temp; + default: + printk(KERN_INFO "Unknown IIO opcode.\n"); + return 0; + } +} + +static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr, + int *ptr, uint32_t *saved, int print) +{ + uint32_t idx, val = 0xCDCDCDCD, align, arg; + struct atom_context *gctx = ctx->ctx; + arg = attr & 7; + align = (attr >> 3) & 7; + switch (arg) { + case ATOM_ARG_REG: + idx = U16(*ptr); + (*ptr) += 2; + if (print) + DEBUG("REG[0x%04X]", idx); + idx += gctx->reg_block; + switch (gctx->io_mode) { + case ATOM_IO_MM: + val = gctx->card->reg_read(gctx->card, idx); + break; + case ATOM_IO_PCI: + printk(KERN_INFO + "PCI registers are not implemented.\n"); + return 0; + case ATOM_IO_SYSIO: + printk(KERN_INFO + "SYSIO registers are not implemented.\n"); + return 0; + default: + if (!(gctx->io_mode & 0x80)) { + printk(KERN_INFO "Bad IO mode.\n"); + return 0; + } + if (!gctx->iio[gctx->io_mode & 0x7F]) { + printk(KERN_INFO + "Undefined indirect IO read method %d.\n", + gctx->io_mode & 0x7F); + return 0; + } + val = + atom_iio_execute(gctx, + gctx->iio[gctx->io_mode & 0x7F], + idx, 0); + } + break; + case ATOM_ARG_PS: + idx = U8(*ptr); + (*ptr)++; + val = le32_to_cpu(ctx->ps[idx]); + if (print) + DEBUG("PS[0x%02X,0x%04X]", idx, val); + break; + case ATOM_ARG_WS: + idx = U8(*ptr); + (*ptr)++; + if (print) + DEBUG("WS[0x%02X]", idx); + switch (idx) { + case ATOM_WS_QUOTIENT: + val = gctx->divmul[0]; + break; + case ATOM_WS_REMAINDER: + val = gctx->divmul[1]; + break; + case ATOM_WS_DATAPTR: + val = gctx->data_block; + break; + case ATOM_WS_SHIFT: + val = gctx->shift; + break; + case ATOM_WS_OR_MASK: + val = 1 << gctx->shift; + break; + case ATOM_WS_AND_MASK: + val = ~(1 << gctx->shift); + break; + case ATOM_WS_FB_WINDOW: + val = gctx->fb_base; + break; + case ATOM_WS_ATTRIBUTES: + val = gctx->io_attr; + break; + default: + val = ctx->ws[idx]; + } + break; + case ATOM_ARG_ID: + idx = U16(*ptr); + (*ptr) += 2; + if (print) { + if (gctx->data_block) + DEBUG("ID[0x%04X+%04X]", idx, gctx->data_block); + else + DEBUG("ID[0x%04X]", idx); + } + val = U32(idx + gctx->data_block); + break; + case ATOM_ARG_FB: + idx = U8(*ptr); + (*ptr)++; + if (print) + DEBUG("FB[0x%02X]", idx); + printk(KERN_INFO "FB access is not implemented.\n"); + return 0; + case ATOM_ARG_IMM: + switch (align) { + case ATOM_SRC_DWORD: + val = U32(*ptr); + (*ptr) += 4; + if (print) + DEBUG("IMM 0x%08X\n", val); + return val; + case ATOM_SRC_WORD0: + case ATOM_SRC_WORD8: + case ATOM_SRC_WORD16: + val = U16(*ptr); + (*ptr) += 2; + if (print) + DEBUG("IMM 0x%04X\n", val); + return val; + case ATOM_SRC_BYTE0: + case ATOM_SRC_BYTE8: + case ATOM_SRC_BYTE16: + case ATOM_SRC_BYTE24: + val = U8(*ptr); + (*ptr)++; + if (print) + DEBUG("IMM 0x%02X\n", val); + return val; + } + return 0; + case ATOM_ARG_PLL: + idx = U8(*ptr); + (*ptr)++; + if (print) + DEBUG("PLL[0x%02X]", idx); + val = gctx->card->pll_read(gctx->card, idx); + break; + case ATOM_ARG_MC: + idx = U8(*ptr); + (*ptr)++; + if (print) + DEBUG("MC[0x%02X]", idx); + val = gctx->card->mc_read(gctx->card, idx); + break; + } + if (saved) + *saved = val; + val &= atom_arg_mask[align]; + val >>= atom_arg_shift[align]; + if (print) + switch (align) { + case ATOM_SRC_DWORD: + DEBUG(".[31:0] -> 0x%08X\n", val); + break; + case ATOM_SRC_WORD0: + DEBUG(".[15:0] -> 0x%04X\n", val); + break; + case ATOM_SRC_WORD8: + DEBUG(".[23:8] -> 0x%04X\n", val); + break; + case ATOM_SRC_WORD16: + DEBUG(".[31:16] -> 0x%04X\n", val); + break; + case ATOM_SRC_BYTE0: + DEBUG(".[7:0] -> 0x%02X\n", val); + break; + case ATOM_SRC_BYTE8: + DEBUG(".[15:8] -> 0x%02X\n", val); + break; + case ATOM_SRC_BYTE16: + DEBUG(".[23:16] -> 0x%02X\n", val); + break; + case ATOM_SRC_BYTE24: + DEBUG(".[31:24] -> 0x%02X\n", val); + break; + } + return val; +} + +static void atom_skip_src_int(atom_exec_context *ctx, uint8_t attr, int *ptr) +{ + uint32_t align = (attr >> 3) & 7, arg = attr & 7; + switch (arg) { + case ATOM_ARG_REG: + case ATOM_ARG_ID: + (*ptr) += 2; + break; + case ATOM_ARG_PLL: + case ATOM_ARG_MC: + case ATOM_ARG_PS: + case ATOM_ARG_WS: + case ATOM_ARG_FB: + (*ptr)++; + break; + case ATOM_ARG_IMM: + switch (align) { + case ATOM_SRC_DWORD: + (*ptr) += 4; + return; + case ATOM_SRC_WORD0: + case ATOM_SRC_WORD8: + case ATOM_SRC_WORD16: + (*ptr) += 2; + return; + case ATOM_SRC_BYTE0: + case ATOM_SRC_BYTE8: + case ATOM_SRC_BYTE16: + case ATOM_SRC_BYTE24: + (*ptr)++; + return; + } + return; + } +} + +static uint32_t atom_get_src(atom_exec_context *ctx, uint8_t attr, int *ptr) +{ + return atom_get_src_int(ctx, attr, ptr, NULL, 1); +} + +static uint32_t atom_get_dst(atom_exec_context *ctx, int arg, uint8_t attr, + int *ptr, uint32_t *saved, int print) +{ + return atom_get_src_int(ctx, + arg | atom_dst_to_src[(attr >> 3) & + 7][(attr >> 6) & 3] << 3, + ptr, saved, print); +} + +static void atom_skip_dst(atom_exec_context *ctx, int arg, uint8_t attr, int *ptr) +{ + atom_skip_src_int(ctx, + arg | atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) & + 3] << 3, ptr); +} + +static void atom_put_dst(atom_exec_context *ctx, int arg, uint8_t attr, + int *ptr, uint32_t val, uint32_t saved) +{ + uint32_t align = + atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) & 3], old_val = + val, idx; + struct atom_context *gctx = ctx->ctx; + old_val &= atom_arg_mask[align] >> atom_arg_shift[align]; + val <<= atom_arg_shift[align]; + val &= atom_arg_mask[align]; + saved &= ~atom_arg_mask[align]; + val |= saved; + switch (arg) { + case ATOM_ARG_REG: + idx = U16(*ptr); + (*ptr) += 2; + DEBUG("REG[0x%04X]", idx); + idx += gctx->reg_block; + switch (gctx->io_mode) { + case ATOM_IO_MM: + if (idx == 0) + gctx->card->reg_write(gctx->card, idx, + val << 2); + else + gctx->card->reg_write(gctx->card, idx, val); + break; + case ATOM_IO_PCI: + printk(KERN_INFO + "PCI registers are not implemented.\n"); + return; + case ATOM_IO_SYSIO: + printk(KERN_INFO + "SYSIO registers are not implemented.\n"); + return; + default: + if (!(gctx->io_mode & 0x80)) { + printk(KERN_INFO "Bad IO mode.\n"); + return; + } + if (!gctx->iio[gctx->io_mode & 0xFF]) { + printk(KERN_INFO + "Undefined indirect IO write method %d.\n", + gctx->io_mode & 0x7F); + return; + } + atom_iio_execute(gctx, gctx->iio[gctx->io_mode & 0xFF], + idx, val); + } + break; + case ATOM_ARG_PS: + idx = U8(*ptr); + (*ptr)++; + DEBUG("PS[0x%02X]", idx); + ctx->ps[idx] = cpu_to_le32(val); + break; + case ATOM_ARG_WS: + idx = U8(*ptr); + (*ptr)++; + DEBUG("WS[0x%02X]", idx); + switch (idx) { + case ATOM_WS_QUOTIENT: + gctx->divmul[0] = val; + break; + case ATOM_WS_REMAINDER: + gctx->divmul[1] = val; + break; + case ATOM_WS_DATAPTR: + gctx->data_block = val; + break; + case ATOM_WS_SHIFT: + gctx->shift = val; + break; + case ATOM_WS_OR_MASK: + case ATOM_WS_AND_MASK: + break; + case ATOM_WS_FB_WINDOW: + gctx->fb_base = val; + break; + case ATOM_WS_ATTRIBUTES: + gctx->io_attr = val; + break; + default: + ctx->ws[idx] = val; + } + break; + case ATOM_ARG_FB: + idx = U8(*ptr); + (*ptr)++; + DEBUG("FB[0x%02X]", idx); + printk(KERN_INFO "FB access is not implemented.\n"); + return; + case ATOM_ARG_PLL: + idx = U8(*ptr); + (*ptr)++; + DEBUG("PLL[0x%02X]", idx); + gctx->card->pll_write(gctx->card, idx, val); + break; + case ATOM_ARG_MC: + idx = U8(*ptr); + (*ptr)++; + DEBUG("MC[0x%02X]", idx); + gctx->card->mc_write(gctx->card, idx, val); + return; + } + switch (align) { + case ATOM_SRC_DWORD: + DEBUG(".[31:0] <- 0x%08X\n", old_val); + break; + case ATOM_SRC_WORD0: + DEBUG(".[15:0] <- 0x%04X\n", old_val); + break; + case ATOM_SRC_WORD8: + DEBUG(".[23:8] <- 0x%04X\n", old_val); + break; + case ATOM_SRC_WORD16: + DEBUG(".[31:16] <- 0x%04X\n", old_val); + break; + case ATOM_SRC_BYTE0: + DEBUG(".[7:0] <- 0x%02X\n", old_val); + break; + case ATOM_SRC_BYTE8: + DEBUG(".[15:8] <- 0x%02X\n", old_val); + break; + case ATOM_SRC_BYTE16: + DEBUG(".[23:16] <- 0x%02X\n", old_val); + break; + case ATOM_SRC_BYTE24: + DEBUG(".[31:24] <- 0x%02X\n", old_val); + break; + } +} + +static void atom_op_add(atom_exec_context *ctx, int *ptr, int arg) +{ + uint8_t attr = U8((*ptr)++); + uint32_t dst, src, saved; + int dptr = *ptr; + SDEBUG(" dst: "); + dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); + SDEBUG(" src: "); + src = atom_get_src(ctx, attr, ptr); + dst += src; + SDEBUG(" dst: "); + atom_put_dst(ctx, arg, attr, &dptr, dst, saved); +} + +static void atom_op_and(atom_exec_context *ctx, int *ptr, int arg) +{ + uint8_t attr = U8((*ptr)++); + uint32_t dst, src, saved; + int dptr = *ptr; + SDEBUG(" dst: "); + dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); + SDEBUG(" src: "); + src = atom_get_src(ctx, attr, ptr); + dst &= src; + SDEBUG(" dst: "); + atom_put_dst(ctx, arg, attr, &dptr, dst, saved); +} + +static void atom_op_beep(atom_exec_context *ctx, int *ptr, int arg) +{ + printk("ATOM BIOS beeped!\n"); +} + +static void atom_op_calltable(atom_exec_context *ctx, int *ptr, int arg) +{ + int idx = U8((*ptr)++); + if (idx < ATOM_TABLE_NAMES_CNT) + SDEBUG(" table: %d (%s)\n", idx, atom_table_names[idx]); + else + SDEBUG(" table: %d\n", idx); + if (U16(ctx->ctx->cmd_table + 4 + 2 * idx)) + atom_execute_table(ctx->ctx, idx, ctx->ps + ctx->ps_shift); +} + +static void atom_op_clear(atom_exec_context *ctx, int *ptr, int arg) +{ + uint8_t attr = U8((*ptr)++); + uint32_t saved; + int dptr = *ptr; + attr &= 0x38; + attr |= atom_def_dst[attr >> 3] << 6; + atom_get_dst(ctx, arg, attr, ptr, &saved, 0); + SDEBUG(" dst: "); + atom_put_dst(ctx, arg, attr, &dptr, 0, saved); +} + +static void atom_op_compare(atom_exec_context *ctx, int *ptr, int arg) +{ + uint8_t attr = U8((*ptr)++); + uint32_t dst, src; + SDEBUG(" src1: "); + dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1); + SDEBUG(" src2: "); + src = atom_get_src(ctx, attr, ptr); + ctx->ctx->cs_equal = (dst == src); + ctx->ctx->cs_above = (dst > src); + SDEBUG(" result: %s %s\n", ctx->ctx->cs_equal ? "EQ" : "NE", + ctx->ctx->cs_above ? "GT" : "LE"); +} + +static void atom_op_delay(atom_exec_context *ctx, int *ptr, int arg) +{ + uint8_t count = U8((*ptr)++); + SDEBUG(" count: %d\n", count); + if (arg == ATOM_UNIT_MICROSEC) + schedule_timeout_uninterruptible(usecs_to_jiffies(count)); + else + schedule_timeout_uninterruptible(msecs_to_jiffies(count)); +} + +static void atom_op_div(atom_exec_context *ctx, int *ptr, int arg) +{ + uint8_t attr = U8((*ptr)++); + uint32_t dst, src; + SDEBUG(" src1: "); + dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1); + SDEBUG(" src2: "); + src = atom_get_src(ctx, attr, ptr); + if (src != 0) { + ctx->ctx->divmul[0] = dst / src; + ctx->ctx->divmul[1] = dst % src; + } else { + ctx->ctx->divmul[0] = 0; + ctx->ctx->divmul[1] = 0; + } +} + +static void atom_op_eot(atom_exec_context *ctx, int *ptr, int arg) +{ + /* functionally, a nop */ +} + +static void atom_op_jump(atom_exec_context *ctx, int *ptr, int arg) +{ + int execute = 0, target = U16(*ptr); + (*ptr) += 2; + switch (arg) { + case ATOM_COND_ABOVE: + execute = ctx->ctx->cs_above; + break; + case ATOM_COND_ABOVEOREQUAL: + execute = ctx->ctx->cs_above || ctx->ctx->cs_equal; + break; + case ATOM_COND_ALWAYS: + execute = 1; + break; + case ATOM_COND_BELOW: + execute = !(ctx->ctx->cs_above || ctx->ctx->cs_equal); + break; + case ATOM_COND_BELOWOREQUAL: + execute = !ctx->ctx->cs_above; + break; + case ATOM_COND_EQUAL: + execute = ctx->ctx->cs_equal; + break; + case ATOM_COND_NOTEQUAL: + execute = !ctx->ctx->cs_equal; + break; + } + if (arg != ATOM_COND_ALWAYS) + SDEBUG(" taken: %s\n", execute ? "yes" : "no"); + SDEBUG(" target: 0x%04X\n", target); + if (execute) + *ptr = ctx->start + target; +} + +static void atom_op_mask(atom_exec_context *ctx, int *ptr, int arg) +{ + uint8_t attr = U8((*ptr)++); + uint32_t dst, src1, src2, saved; + int dptr = *ptr; + SDEBUG(" dst: "); + dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); + SDEBUG(" src1: "); + src1 = atom_get_src(ctx, attr, ptr); + SDEBUG(" src2: "); + src2 = atom_get_src(ctx, attr, ptr); + dst &= src1; + dst |= src2; + SDEBUG(" dst: "); + atom_put_dst(ctx, arg, attr, &dptr, dst, saved); +} + +static void atom_op_move(atom_exec_context *ctx, int *ptr, int arg) +{ + uint8_t attr = U8((*ptr)++); + uint32_t src, saved; + int dptr = *ptr; + if (((attr >> 3) & 7) != ATOM_SRC_DWORD) + atom_get_dst(ctx, arg, attr, ptr, &saved, 0); + else { + atom_skip_dst(ctx, arg, attr, ptr); + saved = 0xCDCDCDCD; + } + SDEBUG(" src: "); + src = atom_get_src(ctx, attr, ptr); + SDEBUG(" dst: "); + atom_put_dst(ctx, arg, attr, &dptr, src, saved); +} + +static void atom_op_mul(atom_exec_context *ctx, int *ptr, int arg) +{ + uint8_t attr = U8((*ptr)++); + uint32_t dst, src; + SDEBUG(" src1: "); + dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1); + SDEBUG(" src2: "); + src = atom_get_src(ctx, attr, ptr); + ctx->ctx->divmul[0] = dst * src; +} + +static void atom_op_nop(atom_exec_context *ctx, int *ptr, int arg) +{ + /* nothing */ +} + +static void atom_op_or(atom_exec_context *ctx, int *ptr, int arg) +{ + uint8_t attr = U8((*ptr)++); + uint32_t dst, src, saved; + int dptr = *ptr; + SDEBUG(" dst: "); + dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); + SDEBUG(" src: "); + src = atom_get_src(ctx, attr, ptr); + dst |= src; + SDEBUG(" dst: "); + atom_put_dst(ctx, arg, attr, &dptr, dst, saved); +} + +static void atom_op_postcard(atom_exec_context *ctx, int *ptr, int arg) +{ + uint8_t val = U8((*ptr)++); + SDEBUG("POST card output: 0x%02X\n", val); +} + +static void atom_op_repeat(atom_exec_context *ctx, int *ptr, int arg) +{ + printk(KERN_INFO "unimplemented!\n"); +} + +static void atom_op_restorereg(atom_exec_context *ctx, int *ptr, int arg) +{ + printk(KERN_INFO "unimplemented!\n"); +} + +static void atom_op_savereg(atom_exec_context *ctx, int *ptr, int arg) +{ + printk(KERN_INFO "unimplemented!\n"); +} + +static void atom_op_setdatablock(atom_exec_context *ctx, int *ptr, int arg) +{ + int idx = U8(*ptr); + (*ptr)++; + SDEBUG(" block: %d\n", idx); + if (!idx) + ctx->ctx->data_block = 0; + else if (idx == 255) + ctx->ctx->data_block = ctx->start; + else + ctx->ctx->data_block = U16(ctx->ctx->data_table + 4 + 2 * idx); + SDEBUG(" base: 0x%04X\n", ctx->ctx->data_block); +} + +static void atom_op_setfbbase(atom_exec_context *ctx, int *ptr, int arg) +{ + uint8_t attr = U8((*ptr)++); + SDEBUG(" fb_base: "); + ctx->ctx->fb_base = atom_get_src(ctx, attr, ptr); +} + +static void atom_op_setport(atom_exec_context *ctx, int *ptr, int arg) +{ + int port; + switch (arg) { + case ATOM_PORT_ATI: + port = U16(*ptr); + if (port < ATOM_IO_NAMES_CNT) + SDEBUG(" port: %d (%s)\n", port, atom_io_names[port]); + else + SDEBUG(" port: %d\n", port); + if (!port) + ctx->ctx->io_mode = ATOM_IO_MM; + else + ctx->ctx->io_mode = ATOM_IO_IIO | port; + (*ptr) += 2; + break; + case ATOM_PORT_PCI: + ctx->ctx->io_mode = ATOM_IO_PCI; + (*ptr)++; + break; + case ATOM_PORT_SYSIO: + ctx->ctx->io_mode = ATOM_IO_SYSIO; + (*ptr)++; + break; + } +} + +static void atom_op_setregblock(atom_exec_context *ctx, int *ptr, int arg) +{ + ctx->ctx->reg_block = U16(*ptr); + (*ptr) += 2; + SDEBUG(" base: 0x%04X\n", ctx->ctx->reg_block); +} + +static void atom_op_shl(atom_exec_context *ctx, int *ptr, int arg) +{ + uint8_t attr = U8((*ptr)++), shift; + uint32_t saved, dst; + int dptr = *ptr; + attr &= 0x38; + attr |= atom_def_dst[attr >> 3] << 6; + SDEBUG(" dst: "); + dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); + shift = U8((*ptr)++); + SDEBUG(" shift: %d\n", shift); + dst <<= shift; + SDEBUG(" dst: "); + atom_put_dst(ctx, arg, attr, &dptr, dst, saved); +} + +static void atom_op_shr(atom_exec_context *ctx, int *ptr, int arg) +{ + uint8_t attr = U8((*ptr)++), shift; + uint32_t saved, dst; + int dptr = *ptr; + attr &= 0x38; + attr |= atom_def_dst[attr >> 3] << 6; + SDEBUG(" dst: "); + dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); + shift = U8((*ptr)++); + SDEBUG(" shift: %d\n", shift); + dst >>= shift; + SDEBUG(" dst: "); + atom_put_dst(ctx, arg, attr, &dptr, dst, saved); +} + +static void atom_op_sub(atom_exec_context *ctx, int *ptr, int arg) +{ + uint8_t attr = U8((*ptr)++); + uint32_t dst, src, saved; + int dptr = *ptr; + SDEBUG(" dst: "); + dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); + SDEBUG(" src: "); + src = atom_get_src(ctx, attr, ptr); + dst -= src; + SDEBUG(" dst: "); + atom_put_dst(ctx, arg, attr, &dptr, dst, saved); +} + +static void atom_op_switch(atom_exec_context *ctx, int *ptr, int arg) +{ + uint8_t attr = U8((*ptr)++); + uint32_t src, val, target; + SDEBUG(" switch: "); + src = atom_get_src(ctx, attr, ptr); + while (U16(*ptr) != ATOM_CASE_END) + if (U8(*ptr) == ATOM_CASE_MAGIC) { + (*ptr)++; + SDEBUG(" case: "); + val = + atom_get_src(ctx, (attr & 0x38) | ATOM_ARG_IMM, + ptr); + target = U16(*ptr); + if (val == src) { + SDEBUG(" target: %04X\n", target); + *ptr = ctx->start + target; + return; + } + (*ptr) += 2; + } else { + printk(KERN_INFO "Bad case.\n"); + return; + } + (*ptr) += 2; +} + +static void atom_op_test(atom_exec_context *ctx, int *ptr, int arg) +{ + uint8_t attr = U8((*ptr)++); + uint32_t dst, src; + SDEBUG(" src1: "); + dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1); + SDEBUG(" src2: "); + src = atom_get_src(ctx, attr, ptr); + ctx->ctx->cs_equal = ((dst & src) == 0); + SDEBUG(" result: %s\n", ctx->ctx->cs_equal ? "EQ" : "NE"); +} + +static void atom_op_xor(atom_exec_context *ctx, int *ptr, int arg) +{ + uint8_t attr = U8((*ptr)++); + uint32_t dst, src, saved; + int dptr = *ptr; + SDEBUG(" dst: "); + dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); + SDEBUG(" src: "); + src = atom_get_src(ctx, attr, ptr); + dst ^= src; + SDEBUG(" dst: "); + atom_put_dst(ctx, arg, attr, &dptr, dst, saved); +} + +static void atom_op_debug(atom_exec_context *ctx, int *ptr, int arg) +{ + printk(KERN_INFO "unimplemented!\n"); +} + +static struct { + void (*func) (atom_exec_context *, int *, int); + int arg; +} opcode_table[ATOM_OP_CNT] = { + { + NULL, 0}, { + atom_op_move, ATOM_ARG_REG}, { + atom_op_move, ATOM_ARG_PS}, { + atom_op_move, ATOM_ARG_WS}, { + atom_op_move, ATOM_ARG_FB}, { + atom_op_move, ATOM_ARG_PLL}, { + atom_op_move, ATOM_ARG_MC}, { + atom_op_and, ATOM_ARG_REG}, { + atom_op_and, ATOM_ARG_PS}, { + atom_op_and, ATOM_ARG_WS}, { + atom_op_and, ATOM_ARG_FB}, { + atom_op_and, ATOM_ARG_PLL}, { + atom_op_and, ATOM_ARG_MC}, { + atom_op_or, ATOM_ARG_REG}, { + atom_op_or, ATOM_ARG_PS}, { + atom_op_or, ATOM_ARG_WS}, { + atom_op_or, ATOM_ARG_FB}, { + atom_op_or, ATOM_ARG_PLL}, { + atom_op_or, ATOM_ARG_MC}, { + atom_op_shl, ATOM_ARG_REG}, { + atom_op_shl, ATOM_ARG_PS}, { + atom_op_shl, ATOM_ARG_WS}, { + atom_op_shl, ATOM_ARG_FB}, { + atom_op_shl, ATOM_ARG_PLL}, { + atom_op_shl, ATOM_ARG_MC}, { + atom_op_shr, ATOM_ARG_REG}, { + atom_op_shr, ATOM_ARG_PS}, { + atom_op_shr, ATOM_ARG_WS}, { + atom_op_shr, ATOM_ARG_FB}, { + atom_op_shr, ATOM_ARG_PLL}, { + atom_op_shr, ATOM_ARG_MC}, { + atom_op_mul, ATOM_ARG_REG}, { + atom_op_mul, ATOM_ARG_PS}, { + atom_op_mul, ATOM_ARG_WS}, { + atom_op_mul, ATOM_ARG_FB}, { + atom_op_mul, ATOM_ARG_PLL}, { + atom_op_mul, ATOM_ARG_MC}, { + atom_op_div, ATOM_ARG_REG}, { + atom_op_div, ATOM_ARG_PS}, { + atom_op_div, ATOM_ARG_WS}, { + atom_op_div, ATOM_ARG_FB}, { + atom_op_div, ATOM_ARG_PLL}, { + atom_op_div, ATOM_ARG_MC}, { + atom_op_add, ATOM_ARG_REG}, { + atom_op_add, ATOM_ARG_PS}, { + atom_op_add, ATOM_ARG_WS}, { + atom_op_add, ATOM_ARG_FB}, { + atom_op_add, ATOM_ARG_PLL}, { + atom_op_add, ATOM_ARG_MC}, { + atom_op_sub, ATOM_ARG_REG}, { + atom_op_sub, ATOM_ARG_PS}, { + atom_op_sub, ATOM_ARG_WS}, { + atom_op_sub, ATOM_ARG_FB}, { + atom_op_sub, ATOM_ARG_PLL}, { + atom_op_sub, ATOM_ARG_MC}, { + atom_op_setport, ATOM_PORT_ATI}, { + atom_op_setport, ATOM_PORT_PCI}, { + atom_op_setport, ATOM_PORT_SYSIO}, { + atom_op_setregblock, 0}, { + atom_op_setfbbase, 0}, { + atom_op_compare, ATOM_ARG_REG}, { + atom_op_compare, ATOM_ARG_PS}, { + atom_op_compare, ATOM_ARG_WS}, { + atom_op_compare, ATOM_ARG_FB}, { + atom_op_compare, ATOM_ARG_PLL}, { + atom_op_compare, ATOM_ARG_MC}, { + atom_op_switch, 0}, { + atom_op_jump, ATOM_COND_ALWAYS}, { + atom_op_jump, ATOM_COND_EQUAL}, { + atom_op_jump, ATOM_COND_BELOW}, { + atom_op_jump, ATOM_COND_ABOVE}, { + atom_op_jump, ATOM_COND_BELOWOREQUAL}, { + atom_op_jump, ATOM_COND_ABOVEOREQUAL}, { + atom_op_jump, ATOM_COND_NOTEQUAL}, { + atom_op_test, ATOM_ARG_REG}, { + atom_op_test, ATOM_ARG_PS}, { + atom_op_test, ATOM_ARG_WS}, { + atom_op_test, ATOM_ARG_FB}, { + atom_op_test, ATOM_ARG_PLL}, { + atom_op_test, ATOM_ARG_MC}, { + atom_op_delay, ATOM_UNIT_MILLISEC}, { + atom_op_delay, ATOM_UNIT_MICROSEC}, { + atom_op_calltable, 0}, { + atom_op_repeat, 0}, { + atom_op_clear, ATOM_ARG_REG}, { + atom_op_clear, ATOM_ARG_PS}, { + atom_op_clear, ATOM_ARG_WS}, { + atom_op_clear, ATOM_ARG_FB}, { + atom_op_clear, ATOM_ARG_PLL}, { + atom_op_clear, ATOM_ARG_MC}, { + atom_op_nop, 0}, { + atom_op_eot, 0}, { + atom_op_mask, ATOM_ARG_REG}, { + atom_op_mask, ATOM_ARG_PS}, { + atom_op_mask, ATOM_ARG_WS}, { + atom_op_mask, ATOM_ARG_FB}, { + atom_op_mask, ATOM_ARG_PLL}, { + atom_op_mask, ATOM_ARG_MC}, { + atom_op_postcard, 0}, { + atom_op_beep, 0}, { + atom_op_savereg, 0}, { + atom_op_restorereg, 0}, { + atom_op_setdatablock, 0}, { + atom_op_xor, ATOM_ARG_REG}, { + atom_op_xor, ATOM_ARG_PS}, { + atom_op_xor, ATOM_ARG_WS}, { + atom_op_xor, ATOM_ARG_FB}, { + atom_op_xor, ATOM_ARG_PLL}, { + atom_op_xor, ATOM_ARG_MC}, { + atom_op_shl, ATOM_ARG_REG}, { + atom_op_shl, ATOM_ARG_PS}, { + atom_op_shl, ATOM_ARG_WS}, { + atom_op_shl, ATOM_ARG_FB}, { + atom_op_shl, ATOM_ARG_PLL}, { + atom_op_shl, ATOM_ARG_MC}, { + atom_op_shr, ATOM_ARG_REG}, { + atom_op_shr, ATOM_ARG_PS}, { + atom_op_shr, ATOM_ARG_WS}, { + atom_op_shr, ATOM_ARG_FB}, { + atom_op_shr, ATOM_ARG_PLL}, { + atom_op_shr, ATOM_ARG_MC}, { +atom_op_debug, 0},}; + +void atom_execute_table(struct atom_context *ctx, int index, uint32_t * params) +{ + int base = CU16(ctx->cmd_table + 4 + 2 * index); + int len, ws, ps, ptr; + unsigned char op; + atom_exec_context ectx; + + if (!base) + return; + + len = CU16(base + ATOM_CT_SIZE_PTR); + ws = CU8(base + ATOM_CT_WS_PTR); + ps = CU8(base + ATOM_CT_PS_PTR) & ATOM_CT_PS_MASK; + ptr = base + ATOM_CT_CODE_PTR; + + SDEBUG(">> execute %04X (len %d, WS %d, PS %d)\n", base, len, ws, ps); + + /* reset reg block */ + ctx->reg_block = 0; + ectx.ctx = ctx; + ectx.ps_shift = ps / 4; + ectx.start = base; + ectx.ps = params; + if (ws) + ectx.ws = kzalloc(4 * ws, GFP_KERNEL); + else + ectx.ws = NULL; + + debug_depth++; + while (1) { + op = CU8(ptr++); + if (op < ATOM_OP_NAMES_CNT) + SDEBUG("%s @ 0x%04X\n", atom_op_names[op], ptr - 1); + else + SDEBUG("[%d] @ 0x%04X\n", op, ptr - 1); + + if (op < ATOM_OP_CNT && op > 0) + opcode_table[op].func(&ectx, &ptr, + opcode_table[op].arg); + else + break; + + if (op == ATOM_OP_EOT) + break; + } + debug_depth--; + SDEBUG("<<\n"); + + if (ws) + kfree(ectx.ws); +} + +static int atom_iio_len[] = { 1, 2, 3, 3, 3, 3, 4, 4, 4, 3 }; + +static void atom_index_iio(struct atom_context *ctx, int base) +{ + ctx->iio = kzalloc(2 * 256, GFP_KERNEL); + while (CU8(base) == ATOM_IIO_START) { + ctx->iio[CU8(base + 1)] = base + 2; + base += 2; + while (CU8(base) != ATOM_IIO_END) + base += atom_iio_len[CU8(base)]; + base += 3; + } +} + +struct atom_context *atom_parse(struct card_info *card, void *bios) +{ + int base; + struct atom_context *ctx = + kzalloc(sizeof(struct atom_context), GFP_KERNEL); + char *str; + char name[512]; + int i; + + ctx->card = card; + ctx->bios = bios; + + if (CU16(0) != ATOM_BIOS_MAGIC) { + printk(KERN_INFO "Invalid BIOS magic.\n"); + kfree(ctx); + return NULL; + } + if (strncmp + (CSTR(ATOM_ATI_MAGIC_PTR), ATOM_ATI_MAGIC, + strlen(ATOM_ATI_MAGIC))) { + printk(KERN_INFO "Invalid ATI magic.\n"); + kfree(ctx); + return NULL; + } + + base = CU16(ATOM_ROM_TABLE_PTR); + if (strncmp + (CSTR(base + ATOM_ROM_MAGIC_PTR), ATOM_ROM_MAGIC, + strlen(ATOM_ROM_MAGIC))) { + printk(KERN_INFO "Invalid ATOM magic.\n"); + kfree(ctx); + return NULL; + } + + ctx->cmd_table = CU16(base + ATOM_ROM_CMD_PTR); + ctx->data_table = CU16(base + ATOM_ROM_DATA_PTR); + atom_index_iio(ctx, CU16(ctx->data_table + ATOM_DATA_IIO_PTR) + 4); + + str = CSTR(CU16(base + ATOM_ROM_MSG_PTR)); + while (*str && ((*str == '\n') || (*str == '\r'))) + str++; + /* name string isn't always 0 terminated */ + for (i = 0; i < 511; i++) { + name[i] = str[i]; + if (name[i] < '.' || name[i] > 'z') { + name[i] = 0; + break; + } + } + printk(KERN_INFO "ATOM BIOS: %s\n", name); + + return ctx; +} + +int atom_asic_init(struct atom_context *ctx) +{ + int hwi = CU16(ctx->data_table + ATOM_DATA_FWI_PTR); + uint32_t ps[16]; + memset(ps, 0, 64); + + ps[0] = cpu_to_le32(CU32(hwi + ATOM_FWI_DEFSCLK_PTR)); + ps[1] = cpu_to_le32(CU32(hwi + ATOM_FWI_DEFMCLK_PTR)); + if (!ps[0] || !ps[1]) + return 1; + + if (!CU16(ctx->cmd_table + 4 + 2 * ATOM_CMD_INIT)) + return 1; + atom_execute_table(ctx, ATOM_CMD_INIT, ps); + + return 0; +} + +void atom_destroy(struct atom_context *ctx) +{ + if (ctx->iio) + kfree(ctx->iio); + kfree(ctx); +} + +void atom_parse_data_header(struct atom_context *ctx, int index, + uint16_t * size, uint8_t * frev, uint8_t * crev, + uint16_t * data_start) +{ + int offset = index * 2 + 4; + int idx = CU16(ctx->data_table + offset); + + if (size) + *size = CU16(idx); + if (frev) + *frev = CU8(idx + 2); + if (crev) + *crev = CU8(idx + 3); + *data_start = idx; + return; +} + +void atom_parse_cmd_header(struct atom_context *ctx, int index, uint8_t * frev, + uint8_t * crev) +{ + int offset = index * 2 + 4; + int idx = CU16(ctx->cmd_table + offset); + + if (frev) + *frev = CU8(idx + 2); + if (crev) + *crev = CU8(idx + 3); + return; +} diff --git a/drivers/gpu/drm/radeon/atom.h b/drivers/gpu/drm/radeon/atom.h new file mode 100644 index 000000000000..e6eb38f2bcae --- /dev/null +++ b/drivers/gpu/drm/radeon/atom.h @@ -0,0 +1,149 @@ +/* + * Copyright 2008 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Author: Stanislaw Skowronek + */ + +#ifndef ATOM_H +#define ATOM_H + +#include +#include "drmP.h" + +#define ATOM_BIOS_MAGIC 0xAA55 +#define ATOM_ATI_MAGIC_PTR 0x30 +#define ATOM_ATI_MAGIC " 761295520" +#define ATOM_ROM_TABLE_PTR 0x48 + +#define ATOM_ROM_MAGIC "ATOM" +#define ATOM_ROM_MAGIC_PTR 4 + +#define ATOM_ROM_MSG_PTR 0x10 +#define ATOM_ROM_CMD_PTR 0x1E +#define ATOM_ROM_DATA_PTR 0x20 + +#define ATOM_CMD_INIT 0 +#define ATOM_CMD_SETSCLK 0x0A +#define ATOM_CMD_SETMCLK 0x0B +#define ATOM_CMD_SETPCLK 0x0C + +#define ATOM_DATA_FWI_PTR 0xC +#define ATOM_DATA_IIO_PTR 0x32 + +#define ATOM_FWI_DEFSCLK_PTR 8 +#define ATOM_FWI_DEFMCLK_PTR 0xC +#define ATOM_FWI_MAXSCLK_PTR 0x24 +#define ATOM_FWI_MAXMCLK_PTR 0x28 + +#define ATOM_CT_SIZE_PTR 0 +#define ATOM_CT_WS_PTR 4 +#define ATOM_CT_PS_PTR 5 +#define ATOM_CT_PS_MASK 0x7F +#define ATOM_CT_CODE_PTR 6 + +#define ATOM_OP_CNT 123 +#define ATOM_OP_EOT 91 + +#define ATOM_CASE_MAGIC 0x63 +#define ATOM_CASE_END 0x5A5A + +#define ATOM_ARG_REG 0 +#define ATOM_ARG_PS 1 +#define ATOM_ARG_WS 2 +#define ATOM_ARG_FB 3 +#define ATOM_ARG_ID 4 +#define ATOM_ARG_IMM 5 +#define ATOM_ARG_PLL 6 +#define ATOM_ARG_MC 7 + +#define ATOM_SRC_DWORD 0 +#define ATOM_SRC_WORD0 1 +#define ATOM_SRC_WORD8 2 +#define ATOM_SRC_WORD16 3 +#define ATOM_SRC_BYTE0 4 +#define ATOM_SRC_BYTE8 5 +#define ATOM_SRC_BYTE16 6 +#define ATOM_SRC_BYTE24 7 + +#define ATOM_WS_QUOTIENT 0x40 +#define ATOM_WS_REMAINDER 0x41 +#define ATOM_WS_DATAPTR 0x42 +#define ATOM_WS_SHIFT 0x43 +#define ATOM_WS_OR_MASK 0x44 +#define ATOM_WS_AND_MASK 0x45 +#define ATOM_WS_FB_WINDOW 0x46 +#define ATOM_WS_ATTRIBUTES 0x47 + +#define ATOM_IIO_NOP 0 +#define ATOM_IIO_START 1 +#define ATOM_IIO_READ 2 +#define ATOM_IIO_WRITE 3 +#define ATOM_IIO_CLEAR 4 +#define ATOM_IIO_SET 5 +#define ATOM_IIO_MOVE_INDEX 6 +#define ATOM_IIO_MOVE_ATTR 7 +#define ATOM_IIO_MOVE_DATA 8 +#define ATOM_IIO_END 9 + +#define ATOM_IO_MM 0 +#define ATOM_IO_PCI 1 +#define ATOM_IO_SYSIO 2 +#define ATOM_IO_IIO 0x80 + +struct card_info { + struct drm_device *dev; + void (* reg_write)(struct card_info *, uint32_t, uint32_t); /* filled by driver */ + uint32_t (* reg_read)(struct card_info *, uint32_t); /* filled by driver */ + void (* mc_write)(struct card_info *, uint32_t, uint32_t); /* filled by driver */ + uint32_t (* mc_read)(struct card_info *, uint32_t); /* filled by driver */ + void (* pll_write)(struct card_info *, uint32_t, uint32_t); /* filled by driver */ + uint32_t (* pll_read)(struct card_info *, uint32_t); /* filled by driver */ +}; + +struct atom_context { + struct card_info *card; + void *bios; + uint32_t cmd_table, data_table; + uint16_t *iio; + + uint16_t data_block; + uint32_t fb_base; + uint32_t divmul[2]; + uint16_t io_attr; + uint16_t reg_block; + uint8_t shift; + int cs_equal, cs_above; + int io_mode; +}; + +extern int atom_debug; + +struct atom_context *atom_parse(struct card_info *, void *); +void atom_execute_table(struct atom_context *, int, uint32_t *); +int atom_asic_init(struct atom_context *); +void atom_destroy(struct atom_context *); +void atom_parse_data_header(struct atom_context *ctx, int index, uint16_t *size, uint8_t *frev, uint8_t *crev, uint16_t *data_start); +void atom_parse_cmd_header(struct atom_context *ctx, int index, uint8_t *frev, uint8_t *crev); +#include "atom-types.h" +#include "atombios.h" +#include "ObjectID.h" + +#endif diff --git a/drivers/gpu/drm/radeon/atombios.h b/drivers/gpu/drm/radeon/atombios.h new file mode 100644 index 000000000000..cf67928abbc8 --- /dev/null +++ b/drivers/gpu/drm/radeon/atombios.h @@ -0,0 +1,4785 @@ +/* + * Copyright 2006-2007 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/****************************************************************************/ +/*Portion I: Definitions shared between VBIOS and Driver */ +/****************************************************************************/ + +#ifndef _ATOMBIOS_H +#define _ATOMBIOS_H + +#define ATOM_VERSION_MAJOR 0x00020000 +#define ATOM_VERSION_MINOR 0x00000002 + +#define ATOM_HEADER_VERSION (ATOM_VERSION_MAJOR | ATOM_VERSION_MINOR) + +/* Endianness should be specified before inclusion, + * default to little endian + */ +#ifndef ATOM_BIG_ENDIAN +#error Endian not specified +#endif + +#ifdef _H2INC +#ifndef ULONG +typedef unsigned long ULONG; +#endif + +#ifndef UCHAR +typedef unsigned char UCHAR; +#endif + +#ifndef USHORT +typedef unsigned short USHORT; +#endif +#endif + +#define ATOM_DAC_A 0 +#define ATOM_DAC_B 1 +#define ATOM_EXT_DAC 2 + +#define ATOM_CRTC1 0 +#define ATOM_CRTC2 1 + +#define ATOM_DIGA 0 +#define ATOM_DIGB 1 + +#define ATOM_PPLL1 0 +#define ATOM_PPLL2 1 + +#define ATOM_SCALER1 0 +#define ATOM_SCALER2 1 + +#define ATOM_SCALER_DISABLE 0 +#define ATOM_SCALER_CENTER 1 +#define ATOM_SCALER_EXPANSION 2 +#define ATOM_SCALER_MULTI_EX 3 + +#define ATOM_DISABLE 0 +#define ATOM_ENABLE 1 +#define ATOM_LCD_BLOFF (ATOM_DISABLE+2) +#define ATOM_LCD_BLON (ATOM_ENABLE+2) +#define ATOM_LCD_BL_BRIGHTNESS_CONTROL (ATOM_ENABLE+3) +#define ATOM_LCD_SELFTEST_START (ATOM_DISABLE+5) +#define ATOM_LCD_SELFTEST_STOP (ATOM_ENABLE+5) +#define ATOM_ENCODER_INIT (ATOM_DISABLE+7) + +#define ATOM_BLANKING 1 +#define ATOM_BLANKING_OFF 0 + +#define ATOM_CURSOR1 0 +#define ATOM_CURSOR2 1 + +#define ATOM_ICON1 0 +#define ATOM_ICON2 1 + +#define ATOM_CRT1 0 +#define ATOM_CRT2 1 + +#define ATOM_TV_NTSC 1 +#define ATOM_TV_NTSCJ 2 +#define ATOM_TV_PAL 3 +#define ATOM_TV_PALM 4 +#define ATOM_TV_PALCN 5 +#define ATOM_TV_PALN 6 +#define ATOM_TV_PAL60 7 +#define ATOM_TV_SECAM 8 +#define ATOM_TV_CV 16 + +#define ATOM_DAC1_PS2 1 +#define ATOM_DAC1_CV 2 +#define ATOM_DAC1_NTSC 3 +#define ATOM_DAC1_PAL 4 + +#define ATOM_DAC2_PS2 ATOM_DAC1_PS2 +#define ATOM_DAC2_CV ATOM_DAC1_CV +#define ATOM_DAC2_NTSC ATOM_DAC1_NTSC +#define ATOM_DAC2_PAL ATOM_DAC1_PAL + +#define ATOM_PM_ON 0 +#define ATOM_PM_STANDBY 1 +#define ATOM_PM_SUSPEND 2 +#define ATOM_PM_OFF 3 + +/* Bit0:{=0:single, =1:dual}, + Bit1 {=0:666RGB, =1:888RGB}, + Bit2:3:{Grey level} + Bit4:{=0:LDI format for RGB888, =1 FPDI format for RGB888}*/ + +#define ATOM_PANEL_MISC_DUAL 0x00000001 +#define ATOM_PANEL_MISC_888RGB 0x00000002 +#define ATOM_PANEL_MISC_GREY_LEVEL 0x0000000C +#define ATOM_PANEL_MISC_FPDI 0x00000010 +#define ATOM_PANEL_MISC_GREY_LEVEL_SHIFT 2 +#define ATOM_PANEL_MISC_SPATIAL 0x00000020 +#define ATOM_PANEL_MISC_TEMPORAL 0x00000040 +#define ATOM_PANEL_MISC_API_ENABLED 0x00000080 + +#define MEMTYPE_DDR1 "DDR1" +#define MEMTYPE_DDR2 "DDR2" +#define MEMTYPE_DDR3 "DDR3" +#define MEMTYPE_DDR4 "DDR4" + +#define ASIC_BUS_TYPE_PCI "PCI" +#define ASIC_BUS_TYPE_AGP "AGP" +#define ASIC_BUS_TYPE_PCIE "PCI_EXPRESS" + +/* Maximum size of that FireGL flag string */ + +#define ATOM_FIREGL_FLAG_STRING "FGL" /* Flag used to enable FireGL Support */ +#define ATOM_MAX_SIZE_OF_FIREGL_FLAG_STRING 3 /* sizeof( ATOM_FIREGL_FLAG_STRING ) */ + +#define ATOM_FAKE_DESKTOP_STRING "DSK" /* Flag used to enable mobile ASIC on Desktop */ +#define ATOM_MAX_SIZE_OF_FAKE_DESKTOP_STRING ATOM_MAX_SIZE_OF_FIREGL_FLAG_STRING + +#define ATOM_M54T_FLAG_STRING "M54T" /* Flag used to enable M54T Support */ +#define ATOM_MAX_SIZE_OF_M54T_FLAG_STRING 4 /* sizeof( ATOM_M54T_FLAG_STRING ) */ + +#define HW_ASSISTED_I2C_STATUS_FAILURE 2 +#define HW_ASSISTED_I2C_STATUS_SUCCESS 1 + +#pragma pack(1) /* BIOS data must use byte aligment */ + +/* Define offset to location of ROM header. */ + +#define OFFSET_TO_POINTER_TO_ATOM_ROM_HEADER 0x00000048L +#define OFFSET_TO_ATOM_ROM_IMAGE_SIZE 0x00000002L + +#define OFFSET_TO_ATOMBIOS_ASIC_BUS_MEM_TYPE 0x94 +#define MAXSIZE_OF_ATOMBIOS_ASIC_BUS_MEM_TYPE 20 /* including the terminator 0x0! */ +#define OFFSET_TO_GET_ATOMBIOS_STRINGS_NUMBER 0x002f +#define OFFSET_TO_GET_ATOMBIOS_STRINGS_START 0x006e + +/* Common header for all ROM Data tables. + Every table pointed _ATOM_MASTER_DATA_TABLE has this common header. + And the pointer actually points to this header. */ + +typedef struct _ATOM_COMMON_TABLE_HEADER { + USHORT usStructureSize; + UCHAR ucTableFormatRevision; /*Change it when the Parser is not backward compatible */ + UCHAR ucTableContentRevision; /*Change it only when the table needs to change but the firmware */ + /*Image can't be updated, while Driver needs to carry the new table! */ +} ATOM_COMMON_TABLE_HEADER; + +typedef struct _ATOM_ROM_HEADER { + ATOM_COMMON_TABLE_HEADER sHeader; + UCHAR uaFirmWareSignature[4]; /*Signature to distinguish between Atombios and non-atombios, + atombios should init it as "ATOM", don't change the position */ + USHORT usBiosRuntimeSegmentAddress; + USHORT usProtectedModeInfoOffset; + USHORT usConfigFilenameOffset; + USHORT usCRC_BlockOffset; + USHORT usBIOS_BootupMessageOffset; + USHORT usInt10Offset; + USHORT usPciBusDevInitCode; + USHORT usIoBaseAddress; + USHORT usSubsystemVendorID; + USHORT usSubsystemID; + USHORT usPCI_InfoOffset; + USHORT usMasterCommandTableOffset; /*Offset for SW to get all command table offsets, Don't change the position */ + USHORT usMasterDataTableOffset; /*Offset for SW to get all data table offsets, Don't change the position */ + UCHAR ucExtendedFunctionCode; + UCHAR ucReserved; +} ATOM_ROM_HEADER; + +/*==============================Command Table Portion==================================== */ + +#ifdef UEFI_BUILD +#define UTEMP USHORT +#define USHORT void* +#endif + +typedef struct _ATOM_MASTER_LIST_OF_COMMAND_TABLES { + USHORT ASIC_Init; /* Function Table, used by various SW components,latest version 1.1 */ + USHORT GetDisplaySurfaceSize; /* Atomic Table, Used by Bios when enabling HW ICON */ + USHORT ASIC_RegistersInit; /* Atomic Table, indirectly used by various SW components,called from ASIC_Init */ + USHORT VRAM_BlockVenderDetection; /* Atomic Table, used only by Bios */ + USHORT DIGxEncoderControl; /* Only used by Bios */ + USHORT MemoryControllerInit; /* Atomic Table, indirectly used by various SW components,called from ASIC_Init */ + USHORT EnableCRTCMemReq; /* Function Table,directly used by various SW components,latest version 2.1 */ + USHORT MemoryParamAdjust; /* Atomic Table, indirectly used by various SW components,called from SetMemoryClock if needed */ + USHORT DVOEncoderControl; /* Function Table,directly used by various SW components,latest version 1.2 */ + USHORT GPIOPinControl; /* Atomic Table, only used by Bios */ + USHORT SetEngineClock; /*Function Table,directly used by various SW components,latest version 1.1 */ + USHORT SetMemoryClock; /* Function Table,directly used by various SW components,latest version 1.1 */ + USHORT SetPixelClock; /*Function Table,directly used by various SW components,latest version 1.2 */ + USHORT DynamicClockGating; /* Atomic Table, indirectly used by various SW components,called from ASIC_Init */ + USHORT ResetMemoryDLL; /* Atomic Table, indirectly used by various SW components,called from SetMemoryClock */ + USHORT ResetMemoryDevice; /* Atomic Table, indirectly used by various SW components,called from SetMemoryClock */ + USHORT MemoryPLLInit; + USHORT AdjustDisplayPll; /* only used by Bios */ + USHORT AdjustMemoryController; /* Atomic Table, indirectly used by various SW components,called from SetMemoryClock */ + USHORT EnableASIC_StaticPwrMgt; /* Atomic Table, only used by Bios */ + USHORT ASIC_StaticPwrMgtStatusChange; /* Obsolete, only used by Bios */ + USHORT DAC_LoadDetection; /* Atomic Table, directly used by various SW components,latest version 1.2 */ + USHORT LVTMAEncoderControl; /* Atomic Table,directly used by various SW components,latest version 1.3 */ + USHORT LCD1OutputControl; /* Atomic Table, directly used by various SW components,latest version 1.1 */ + USHORT DAC1EncoderControl; /* Atomic Table, directly used by various SW components,latest version 1.1 */ + USHORT DAC2EncoderControl; /* Atomic Table, directly used by various SW components,latest version 1.1 */ + USHORT DVOOutputControl; /* Atomic Table, directly used by various SW components,latest version 1.1 */ + USHORT CV1OutputControl; /* Atomic Table, directly used by various SW components,latest version 1.1 */ + USHORT GetConditionalGoldenSetting; /* only used by Bios */ + USHORT TVEncoderControl; /* Function Table,directly used by various SW components,latest version 1.1 */ + USHORT TMDSAEncoderControl; /* Atomic Table, directly used by various SW components,latest version 1.3 */ + USHORT LVDSEncoderControl; /* Atomic Table, directly used by various SW components,latest version 1.3 */ + USHORT TV1OutputControl; /* Atomic Table, directly used by various SW components,latest version 1.1 */ + USHORT EnableScaler; /* Atomic Table, used only by Bios */ + USHORT BlankCRTC; /* Atomic Table, directly used by various SW components,latest version 1.1 */ + USHORT EnableCRTC; /* Atomic Table, directly used by various SW components,latest version 1.1 */ + USHORT GetPixelClock; /* Atomic Table, directly used by various SW components,latest version 1.1 */ + USHORT EnableVGA_Render; /* Function Table,directly used by various SW components,latest version 1.1 */ + USHORT EnableVGA_Access; /* Obsolete , only used by Bios */ + USHORT SetCRTC_Timing; /* Atomic Table, directly used by various SW components,latest version 1.1 */ + USHORT SetCRTC_OverScan; /* Atomic Table, used by various SW components,latest version 1.1 */ + USHORT SetCRTC_Replication; /* Atomic Table, used only by Bios */ + USHORT SelectCRTC_Source; /* Atomic Table, directly used by various SW components,latest version 1.1 */ + USHORT EnableGraphSurfaces; /* Atomic Table, used only by Bios */ + USHORT UpdateCRTC_DoubleBufferRegisters; + USHORT LUT_AutoFill; /* Atomic Table, only used by Bios */ + USHORT EnableHW_IconCursor; /* Atomic Table, only used by Bios */ + USHORT GetMemoryClock; /* Atomic Table, directly used by various SW components,latest version 1.1 */ + USHORT GetEngineClock; /* Atomic Table, directly used by various SW components,latest version 1.1 */ + USHORT SetCRTC_UsingDTDTiming; /* Atomic Table, directly used by various SW components,latest version 1.1 */ + USHORT ExternalEncoderControl; /* Atomic Table, directly used by various SW components,latest version 2.1 */ + USHORT LVTMAOutputControl; /* Atomic Table, directly used by various SW components,latest version 1.1 */ + USHORT VRAM_BlockDetectionByStrap; /* Atomic Table, used only by Bios */ + USHORT MemoryCleanUp; /* Atomic Table, only used by Bios */ + USHORT ProcessI2cChannelTransaction; /* Function Table,only used by Bios */ + USHORT WriteOneByteToHWAssistedI2C; /* Function Table,indirectly used by various SW components */ + USHORT ReadHWAssistedI2CStatus; /* Atomic Table, indirectly used by various SW components */ + USHORT SpeedFanControl; /* Function Table,indirectly used by various SW components,called from ASIC_Init */ + USHORT PowerConnectorDetection; /* Atomic Table, directly used by various SW components,latest version 1.1 */ + USHORT MC_Synchronization; /* Atomic Table, indirectly used by various SW components,called from SetMemoryClock */ + USHORT ComputeMemoryEnginePLL; /* Atomic Table, indirectly used by various SW components,called from SetMemory/EngineClock */ + USHORT MemoryRefreshConversion; /* Atomic Table, indirectly used by various SW components,called from SetMemory or SetEngineClock */ + USHORT VRAM_GetCurrentInfoBlock; /* Atomic Table, used only by Bios */ + USHORT DynamicMemorySettings; /* Atomic Table, indirectly used by various SW components,called from SetMemoryClock */ + USHORT MemoryTraining; /* Atomic Table, used only by Bios */ + USHORT EnableSpreadSpectrumOnPPLL; /* Atomic Table, directly used by various SW components,latest version 1.2 */ + USHORT TMDSAOutputControl; /* Atomic Table, directly used by various SW components,latest version 1.1 */ + USHORT SetVoltage; /* Function Table,directly and/or indirectly used by various SW components,latest version 1.1 */ + USHORT DAC1OutputControl; /* Atomic Table, directly used by various SW components,latest version 1.1 */ + USHORT DAC2OutputControl; /* Atomic Table, directly used by various SW components,latest version 1.1 */ + USHORT SetupHWAssistedI2CStatus; /* Function Table,only used by Bios, obsolete soon.Switch to use "ReadEDIDFromHWAssistedI2C" */ + USHORT ClockSource; /* Atomic Table, indirectly used by various SW components,called from ASIC_Init */ + USHORT MemoryDeviceInit; /* Atomic Table, indirectly used by various SW components,called from SetMemoryClock */ + USHORT EnableYUV; /* Atomic Table, indirectly used by various SW components,called from EnableVGARender */ + USHORT DIG1EncoderControl; /* Atomic Table,directly used by various SW components,latest version 1.1 */ + USHORT DIG2EncoderControl; /* Atomic Table,directly used by various SW components,latest version 1.1 */ + USHORT DIG1TransmitterControl; /* Atomic Table,directly used by various SW components,latest version 1.1 */ + USHORT DIG2TransmitterControl; /* Atomic Table,directly used by various SW components,latest version 1.1 */ + USHORT ProcessAuxChannelTransaction; /* Function Table,only used by Bios */ + USHORT DPEncoderService; /* Function Table,only used by Bios */ +} ATOM_MASTER_LIST_OF_COMMAND_TABLES; + +/* For backward compatible */ +#define ReadEDIDFromHWAssistedI2C ProcessI2cChannelTransaction +#define UNIPHYTransmitterControl DIG1TransmitterControl +#define LVTMATransmitterControl DIG2TransmitterControl +#define SetCRTC_DPM_State GetConditionalGoldenSetting +#define SetUniphyInstance ASIC_StaticPwrMgtStatusChange + +typedef struct _ATOM_MASTER_COMMAND_TABLE { + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_MASTER_LIST_OF_COMMAND_TABLES ListOfCommandTables; +} ATOM_MASTER_COMMAND_TABLE; + +/****************************************************************************/ +/* Structures used in every command table */ +/****************************************************************************/ +typedef struct _ATOM_TABLE_ATTRIBUTE { +#if ATOM_BIG_ENDIAN + USHORT UpdatedByUtility:1; /* [15]=Table updated by utility flag */ + USHORT PS_SizeInBytes:7; /* [14:8]=Size of parameter space in Bytes (multiple of a dword), */ + USHORT WS_SizeInBytes:8; /* [7:0]=Size of workspace in Bytes (in multiple of a dword), */ +#else + USHORT WS_SizeInBytes:8; /* [7:0]=Size of workspace in Bytes (in multiple of a dword), */ + USHORT PS_SizeInBytes:7; /* [14:8]=Size of parameter space in Bytes (multiple of a dword), */ + USHORT UpdatedByUtility:1; /* [15]=Table updated by utility flag */ +#endif +} ATOM_TABLE_ATTRIBUTE; + +typedef union _ATOM_TABLE_ATTRIBUTE_ACCESS { + ATOM_TABLE_ATTRIBUTE sbfAccess; + USHORT susAccess; +} ATOM_TABLE_ATTRIBUTE_ACCESS; + +/****************************************************************************/ +/* Common header for all command tables. */ +/* Every table pointed by _ATOM_MASTER_COMMAND_TABLE has this common header. */ +/* And the pointer actually points to this header. */ +/****************************************************************************/ +typedef struct _ATOM_COMMON_ROM_COMMAND_TABLE_HEADER { + ATOM_COMMON_TABLE_HEADER CommonHeader; + ATOM_TABLE_ATTRIBUTE TableAttribute; +} ATOM_COMMON_ROM_COMMAND_TABLE_HEADER; + +/****************************************************************************/ +/* Structures used by ComputeMemoryEnginePLLTable */ +/****************************************************************************/ +#define COMPUTE_MEMORY_PLL_PARAM 1 +#define COMPUTE_ENGINE_PLL_PARAM 2 + +typedef struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS { + ULONG ulClock; /* When returen, it's the re-calculated clock based on given Fb_div Post_Div and ref_div */ + UCHAR ucAction; /* 0:reserved //1:Memory //2:Engine */ + UCHAR ucReserved; /* may expand to return larger Fbdiv later */ + UCHAR ucFbDiv; /* return value */ + UCHAR ucPostDiv; /* return value */ +} COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS; + +typedef struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V2 { + ULONG ulClock; /* When return, [23:0] return real clock */ + UCHAR ucAction; /* 0:reserved;COMPUTE_MEMORY_PLL_PARAM:Memory;COMPUTE_ENGINE_PLL_PARAM:Engine. it return ref_div to be written to register */ + USHORT usFbDiv; /* return Feedback value to be written to register */ + UCHAR ucPostDiv; /* return post div to be written to register */ +} COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V2; +#define COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_PS_ALLOCATION COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS + +#define SET_CLOCK_FREQ_MASK 0x00FFFFFF /* Clock change tables only take bit [23:0] as the requested clock value */ +#define USE_NON_BUS_CLOCK_MASK 0x01000000 /* Applicable to both memory and engine clock change, when set, it uses another clock as the temporary clock (engine uses memory and vice versa) */ +#define USE_MEMORY_SELF_REFRESH_MASK 0x02000000 /* Only applicable to memory clock change, when set, using memory self refresh during clock transition */ +#define SKIP_INTERNAL_MEMORY_PARAMETER_CHANGE 0x04000000 /* Only applicable to memory clock change, when set, the table will skip predefined internal memory parameter change */ +#define FIRST_TIME_CHANGE_CLOCK 0x08000000 /* Applicable to both memory and engine clock change,when set, it means this is 1st time to change clock after ASIC bootup */ +#define SKIP_SW_PROGRAM_PLL 0x10000000 /* Applicable to both memory and engine clock change, when set, it means the table will not program SPLL/MPLL */ +#define USE_SS_ENABLED_PIXEL_CLOCK USE_NON_BUS_CLOCK_MASK + +#define b3USE_NON_BUS_CLOCK_MASK 0x01 /* Applicable to both memory and engine clock change, when set, it uses another clock as the temporary clock (engine uses memory and vice versa) */ +#define b3USE_MEMORY_SELF_REFRESH 0x02 /* Only applicable to memory clock change, when set, using memory self refresh during clock transition */ +#define b3SKIP_INTERNAL_MEMORY_PARAMETER_CHANGE 0x04 /* Only applicable to memory clock change, when set, the table will skip predefined internal memory parameter change */ +#define b3FIRST_TIME_CHANGE_CLOCK 0x08 /* Applicable to both memory and engine clock change,when set, it means this is 1st time to change clock after ASIC bootup */ +#define b3SKIP_SW_PROGRAM_PLL 0x10 /* Applicable to both memory and engine clock change, when set, it means the table will not program SPLL/MPLL */ + +typedef struct _ATOM_COMPUTE_CLOCK_FREQ { +#if ATOM_BIG_ENDIAN + ULONG ulComputeClockFlag:8; /* =1: COMPUTE_MEMORY_PLL_PARAM, =2: COMPUTE_ENGINE_PLL_PARAM */ + ULONG ulClockFreq:24; /* in unit of 10kHz */ +#else + ULONG ulClockFreq:24; /* in unit of 10kHz */ + ULONG ulComputeClockFlag:8; /* =1: COMPUTE_MEMORY_PLL_PARAM, =2: COMPUTE_ENGINE_PLL_PARAM */ +#endif +} ATOM_COMPUTE_CLOCK_FREQ; + +typedef struct _ATOM_S_MPLL_FB_DIVIDER { + USHORT usFbDivFrac; + USHORT usFbDiv; +} ATOM_S_MPLL_FB_DIVIDER; + +typedef struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V3 { + union { + ATOM_COMPUTE_CLOCK_FREQ ulClock; /* Input Parameter */ + ATOM_S_MPLL_FB_DIVIDER ulFbDiv; /* Output Parameter */ + }; + UCHAR ucRefDiv; /* Output Parameter */ + UCHAR ucPostDiv; /* Output Parameter */ + UCHAR ucCntlFlag; /* Output Parameter */ + UCHAR ucReserved; +} COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V3; + +/* ucCntlFlag */ +#define ATOM_PLL_CNTL_FLAG_PLL_POST_DIV_EN 1 +#define ATOM_PLL_CNTL_FLAG_MPLL_VCO_MODE 2 +#define ATOM_PLL_CNTL_FLAG_FRACTION_DISABLE 4 + +typedef struct _DYNAMICE_MEMORY_SETTINGS_PARAMETER { + ATOM_COMPUTE_CLOCK_FREQ ulClock; + ULONG ulReserved[2]; +} DYNAMICE_MEMORY_SETTINGS_PARAMETER; + +typedef struct _DYNAMICE_ENGINE_SETTINGS_PARAMETER { + ATOM_COMPUTE_CLOCK_FREQ ulClock; + ULONG ulMemoryClock; + ULONG ulReserved; +} DYNAMICE_ENGINE_SETTINGS_PARAMETER; + +/****************************************************************************/ +/* Structures used by SetEngineClockTable */ +/****************************************************************************/ +typedef struct _SET_ENGINE_CLOCK_PARAMETERS { + ULONG ulTargetEngineClock; /* In 10Khz unit */ +} SET_ENGINE_CLOCK_PARAMETERS; + +typedef struct _SET_ENGINE_CLOCK_PS_ALLOCATION { + ULONG ulTargetEngineClock; /* In 10Khz unit */ + COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_PS_ALLOCATION sReserved; +} SET_ENGINE_CLOCK_PS_ALLOCATION; + +/****************************************************************************/ +/* Structures used by SetMemoryClockTable */ +/****************************************************************************/ +typedef struct _SET_MEMORY_CLOCK_PARAMETERS { + ULONG ulTargetMemoryClock; /* In 10Khz unit */ +} SET_MEMORY_CLOCK_PARAMETERS; + +typedef struct _SET_MEMORY_CLOCK_PS_ALLOCATION { + ULONG ulTargetMemoryClock; /* In 10Khz unit */ + COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_PS_ALLOCATION sReserved; +} SET_MEMORY_CLOCK_PS_ALLOCATION; + +/****************************************************************************/ +/* Structures used by ASIC_Init.ctb */ +/****************************************************************************/ +typedef struct _ASIC_INIT_PARAMETERS { + ULONG ulDefaultEngineClock; /* In 10Khz unit */ + ULONG ulDefaultMemoryClock; /* In 10Khz unit */ +} ASIC_INIT_PARAMETERS; + +typedef struct _ASIC_INIT_PS_ALLOCATION { + ASIC_INIT_PARAMETERS sASICInitClocks; + SET_ENGINE_CLOCK_PS_ALLOCATION sReserved; /* Caller doesn't need to init this structure */ +} ASIC_INIT_PS_ALLOCATION; + +/****************************************************************************/ +/* Structure used by DynamicClockGatingTable.ctb */ +/****************************************************************************/ +typedef struct _DYNAMIC_CLOCK_GATING_PARAMETERS { + UCHAR ucEnable; /* ATOM_ENABLE or ATOM_DISABLE */ + UCHAR ucPadding[3]; +} DYNAMIC_CLOCK_GATING_PARAMETERS; +#define DYNAMIC_CLOCK_GATING_PS_ALLOCATION DYNAMIC_CLOCK_GATING_PARAMETERS + +/****************************************************************************/ +/* Structure used by EnableASIC_StaticPwrMgtTable.ctb */ +/****************************************************************************/ +typedef struct _ENABLE_ASIC_STATIC_PWR_MGT_PARAMETERS { + UCHAR ucEnable; /* ATOM_ENABLE or ATOM_DISABLE */ + UCHAR ucPadding[3]; +} ENABLE_ASIC_STATIC_PWR_MGT_PARAMETERS; +#define ENABLE_ASIC_STATIC_PWR_MGT_PS_ALLOCATION ENABLE_ASIC_STATIC_PWR_MGT_PARAMETERS + +/****************************************************************************/ +/* Structures used by DAC_LoadDetectionTable.ctb */ +/****************************************************************************/ +typedef struct _DAC_LOAD_DETECTION_PARAMETERS { + USHORT usDeviceID; /* {ATOM_DEVICE_CRTx_SUPPORT,ATOM_DEVICE_TVx_SUPPORT,ATOM_DEVICE_CVx_SUPPORT} */ + UCHAR ucDacType; /* {ATOM_DAC_A,ATOM_DAC_B, ATOM_EXT_DAC} */ + UCHAR ucMisc; /* Valid only when table revision =1.3 and above */ +} DAC_LOAD_DETECTION_PARAMETERS; + +/* DAC_LOAD_DETECTION_PARAMETERS.ucMisc */ +#define DAC_LOAD_MISC_YPrPb 0x01 + +typedef struct _DAC_LOAD_DETECTION_PS_ALLOCATION { + DAC_LOAD_DETECTION_PARAMETERS sDacload; + ULONG Reserved[2]; /* Don't set this one, allocation for EXT DAC */ +} DAC_LOAD_DETECTION_PS_ALLOCATION; + +/****************************************************************************/ +/* Structures used by DAC1EncoderControlTable.ctb and DAC2EncoderControlTable.ctb */ +/****************************************************************************/ +typedef struct _DAC_ENCODER_CONTROL_PARAMETERS { + USHORT usPixelClock; /* in 10KHz; for bios convenient */ + UCHAR ucDacStandard; /* See definition of ATOM_DACx_xxx, For DEC3.0, bit 7 used as internal flag to indicate DAC2 (==1) or DAC1 (==0) */ + UCHAR ucAction; /* 0: turn off encoder */ + /* 1: setup and turn on encoder */ + /* 7: ATOM_ENCODER_INIT Initialize DAC */ +} DAC_ENCODER_CONTROL_PARAMETERS; + +#define DAC_ENCODER_CONTROL_PS_ALLOCATION DAC_ENCODER_CONTROL_PARAMETERS + +/****************************************************************************/ +/* Structures used by DIG1EncoderControlTable */ +/* DIG2EncoderControlTable */ +/* ExternalEncoderControlTable */ +/****************************************************************************/ +typedef struct _DIG_ENCODER_CONTROL_PARAMETERS { + USHORT usPixelClock; /* in 10KHz; for bios convenient */ + UCHAR ucConfig; + /* [2] Link Select: */ + /* =0: PHY linkA if bfLane<3 */ + /* =1: PHY linkB if bfLanes<3 */ + /* =0: PHY linkA+B if bfLanes=3 */ + /* [3] Transmitter Sel */ + /* =0: UNIPHY or PCIEPHY */ + /* =1: LVTMA */ + UCHAR ucAction; /* =0: turn off encoder */ + /* =1: turn on encoder */ + UCHAR ucEncoderMode; + /* =0: DP encoder */ + /* =1: LVDS encoder */ + /* =2: DVI encoder */ + /* =3: HDMI encoder */ + /* =4: SDVO encoder */ + UCHAR ucLaneNum; /* how many lanes to enable */ + UCHAR ucReserved[2]; +} DIG_ENCODER_CONTROL_PARAMETERS; +#define DIG_ENCODER_CONTROL_PS_ALLOCATION DIG_ENCODER_CONTROL_PARAMETERS +#define EXTERNAL_ENCODER_CONTROL_PARAMETER DIG_ENCODER_CONTROL_PARAMETERS + +/* ucConfig */ +#define ATOM_ENCODER_CONFIG_DPLINKRATE_MASK 0x01 +#define ATOM_ENCODER_CONFIG_DPLINKRATE_1_62GHZ 0x00 +#define ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ 0x01 +#define ATOM_ENCODER_CONFIG_LINK_SEL_MASK 0x04 +#define ATOM_ENCODER_CONFIG_LINKA 0x00 +#define ATOM_ENCODER_CONFIG_LINKB 0x04 +#define ATOM_ENCODER_CONFIG_LINKA_B ATOM_TRANSMITTER_CONFIG_LINKA +#define ATOM_ENCODER_CONFIG_LINKB_A ATOM_ENCODER_CONFIG_LINKB +#define ATOM_ENCODER_CONFIG_TRANSMITTER_SEL_MASK 0x08 +#define ATOM_ENCODER_CONFIG_UNIPHY 0x00 +#define ATOM_ENCODER_CONFIG_LVTMA 0x08 +#define ATOM_ENCODER_CONFIG_TRANSMITTER1 0x00 +#define ATOM_ENCODER_CONFIG_TRANSMITTER2 0x08 +#define ATOM_ENCODER_CONFIG_DIGB 0x80 /* VBIOS Internal use, outside SW should set this bit=0 */ +/* ucAction */ +/* ATOM_ENABLE: Enable Encoder */ +/* ATOM_DISABLE: Disable Encoder */ + +/* ucEncoderMode */ +#define ATOM_ENCODER_MODE_DP 0 +#define ATOM_ENCODER_MODE_LVDS 1 +#define ATOM_ENCODER_MODE_DVI 2 +#define ATOM_ENCODER_MODE_HDMI 3 +#define ATOM_ENCODER_MODE_SDVO 4 +#define ATOM_ENCODER_MODE_TV 13 +#define ATOM_ENCODER_MODE_CV 14 +#define ATOM_ENCODER_MODE_CRT 15 + +typedef struct _ATOM_DIG_ENCODER_CONFIG_V2 { +#if ATOM_BIG_ENDIAN + UCHAR ucReserved1:2; + UCHAR ucTransmitterSel:2; /* =0: UniphyAB, =1: UniphyCD =2: UniphyEF */ + UCHAR ucLinkSel:1; /* =0: linkA/C/E =1: linkB/D/F */ + UCHAR ucReserved:1; + UCHAR ucDPLinkRate:1; /* =0: 1.62Ghz, =1: 2.7Ghz */ +#else + UCHAR ucDPLinkRate:1; /* =0: 1.62Ghz, =1: 2.7Ghz */ + UCHAR ucReserved:1; + UCHAR ucLinkSel:1; /* =0: linkA/C/E =1: linkB/D/F */ + UCHAR ucTransmitterSel:2; /* =0: UniphyAB, =1: UniphyCD =2: UniphyEF */ + UCHAR ucReserved1:2; +#endif +} ATOM_DIG_ENCODER_CONFIG_V2; + +typedef struct _DIG_ENCODER_CONTROL_PARAMETERS_V2 { + USHORT usPixelClock; /* in 10KHz; for bios convenient */ + ATOM_DIG_ENCODER_CONFIG_V2 acConfig; + UCHAR ucAction; + UCHAR ucEncoderMode; + /* =0: DP encoder */ + /* =1: LVDS encoder */ + /* =2: DVI encoder */ + /* =3: HDMI encoder */ + /* =4: SDVO encoder */ + UCHAR ucLaneNum; /* how many lanes to enable */ + UCHAR ucReserved[2]; +} DIG_ENCODER_CONTROL_PARAMETERS_V2; + +/* ucConfig */ +#define ATOM_ENCODER_CONFIG_V2_DPLINKRATE_MASK 0x01 +#define ATOM_ENCODER_CONFIG_V2_DPLINKRATE_1_62GHZ 0x00 +#define ATOM_ENCODER_CONFIG_V2_DPLINKRATE_2_70GHZ 0x01 +#define ATOM_ENCODER_CONFIG_V2_LINK_SEL_MASK 0x04 +#define ATOM_ENCODER_CONFIG_V2_LINKA 0x00 +#define ATOM_ENCODER_CONFIG_V2_LINKB 0x04 +#define ATOM_ENCODER_CONFIG_V2_TRANSMITTER_SEL_MASK 0x18 +#define ATOM_ENCODER_CONFIG_V2_TRANSMITTER1 0x00 +#define ATOM_ENCODER_CONFIG_V2_TRANSMITTER2 0x08 +#define ATOM_ENCODER_CONFIG_V2_TRANSMITTER3 0x10 + +/****************************************************************************/ +/* Structures used by UNIPHYTransmitterControlTable */ +/* LVTMATransmitterControlTable */ +/* DVOOutputControlTable */ +/****************************************************************************/ +typedef struct _ATOM_DP_VS_MODE { + UCHAR ucLaneSel; + UCHAR ucLaneSet; +} ATOM_DP_VS_MODE; + +typedef struct _DIG_TRANSMITTER_CONTROL_PARAMETERS { + union { + USHORT usPixelClock; /* in 10KHz; for bios convenient */ + USHORT usInitInfo; /* when init uniphy,lower 8bit is used for connector type defined in objectid.h */ + ATOM_DP_VS_MODE asMode; /* DP Voltage swing mode */ + }; + UCHAR ucConfig; + /* [0]=0: 4 lane Link, */ + /* =1: 8 lane Link ( Dual Links TMDS ) */ + /* [1]=0: InCoherent mode */ + /* =1: Coherent Mode */ + /* [2] Link Select: */ + /* =0: PHY linkA if bfLane<3 */ + /* =1: PHY linkB if bfLanes<3 */ + /* =0: PHY linkA+B if bfLanes=3 */ + /* [5:4]PCIE lane Sel */ + /* =0: lane 0~3 or 0~7 */ + /* =1: lane 4~7 */ + /* =2: lane 8~11 or 8~15 */ + /* =3: lane 12~15 */ + UCHAR ucAction; /* =0: turn off encoder */ + /* =1: turn on encoder */ + UCHAR ucReserved[4]; +} DIG_TRANSMITTER_CONTROL_PARAMETERS; + +#define DIG_TRANSMITTER_CONTROL_PS_ALLOCATION DIG_TRANSMITTER_CONTROL_PARAMETERS + +/* ucInitInfo */ +#define ATOM_TRAMITTER_INITINFO_CONNECTOR_MASK 0x00ff + +/* ucConfig */ +#define ATOM_TRANSMITTER_CONFIG_8LANE_LINK 0x01 +#define ATOM_TRANSMITTER_CONFIG_COHERENT 0x02 +#define ATOM_TRANSMITTER_CONFIG_LINK_SEL_MASK 0x04 +#define ATOM_TRANSMITTER_CONFIG_LINKA 0x00 +#define ATOM_TRANSMITTER_CONFIG_LINKB 0x04 +#define ATOM_TRANSMITTER_CONFIG_LINKA_B 0x00 +#define ATOM_TRANSMITTER_CONFIG_LINKB_A 0x04 + +#define ATOM_TRANSMITTER_CONFIG_ENCODER_SEL_MASK 0x08 /* only used when ATOM_TRANSMITTER_ACTION_ENABLE */ +#define ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER 0x00 /* only used when ATOM_TRANSMITTER_ACTION_ENABLE */ +#define ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER 0x08 /* only used when ATOM_TRANSMITTER_ACTION_ENABLE */ + +#define ATOM_TRANSMITTER_CONFIG_CLKSRC_MASK 0x30 +#define ATOM_TRANSMITTER_CONFIG_CLKSRC_PPLL 0x00 +#define ATOM_TRANSMITTER_CONFIG_CLKSRC_PCIE 0x20 +#define ATOM_TRANSMITTER_CONFIG_CLKSRC_XTALIN 0x30 +#define ATOM_TRANSMITTER_CONFIG_LANE_SEL_MASK 0xc0 +#define ATOM_TRANSMITTER_CONFIG_LANE_0_3 0x00 +#define ATOM_TRANSMITTER_CONFIG_LANE_0_7 0x00 +#define ATOM_TRANSMITTER_CONFIG_LANE_4_7 0x40 +#define ATOM_TRANSMITTER_CONFIG_LANE_8_11 0x80 +#define ATOM_TRANSMITTER_CONFIG_LANE_8_15 0x80 +#define ATOM_TRANSMITTER_CONFIG_LANE_12_15 0xc0 + +/* ucAction */ +#define ATOM_TRANSMITTER_ACTION_DISABLE 0 +#define ATOM_TRANSMITTER_ACTION_ENABLE 1 +#define ATOM_TRANSMITTER_ACTION_LCD_BLOFF 2 +#define ATOM_TRANSMITTER_ACTION_LCD_BLON 3 +#define ATOM_TRANSMITTER_ACTION_BL_BRIGHTNESS_CONTROL 4 +#define ATOM_TRANSMITTER_ACTION_LCD_SELFTEST_START 5 +#define ATOM_TRANSMITTER_ACTION_LCD_SELFTEST_STOP 6 +#define ATOM_TRANSMITTER_ACTION_INIT 7 +#define ATOM_TRANSMITTER_ACTION_DISABLE_OUTPUT 8 +#define ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT 9 +#define ATOM_TRANSMITTER_ACTION_SETUP 10 +#define ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH 11 + +/* Following are used for DigTransmitterControlTable ver1.2 */ +typedef struct _ATOM_DIG_TRANSMITTER_CONFIG_V2 { +#if ATOM_BIG_ENDIAN + UCHAR ucTransmitterSel:2; /* bit7:6: =0 Dig Transmitter 1 ( Uniphy AB ) */ + /* =1 Dig Transmitter 2 ( Uniphy CD ) */ + /* =2 Dig Transmitter 3 ( Uniphy EF ) */ + UCHAR ucReserved:1; + UCHAR fDPConnector:1; /* bit4=0: DP connector =1: None DP connector */ + UCHAR ucEncoderSel:1; /* bit3=0: Data/Clk path source from DIGA( DIG inst0 ). =1: Data/clk path source from DIGB ( DIG inst1 ) */ + UCHAR ucLinkSel:1; /* bit2=0: Uniphy LINKA or C or E when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is A or C or E */ + /* =1: Uniphy LINKB or D or F when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is B or D or F */ + + UCHAR fCoherentMode:1; /* bit1=1: Coherent Mode ( for DVI/HDMI mode ) */ + UCHAR fDualLinkConnector:1; /* bit0=1: Dual Link DVI connector */ +#else + UCHAR fDualLinkConnector:1; /* bit0=1: Dual Link DVI connector */ + UCHAR fCoherentMode:1; /* bit1=1: Coherent Mode ( for DVI/HDMI mode ) */ + UCHAR ucLinkSel:1; /* bit2=0: Uniphy LINKA or C or E when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is A or C or E */ + /* =1: Uniphy LINKB or D or F when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is B or D or F */ + UCHAR ucEncoderSel:1; /* bit3=0: Data/Clk path source from DIGA( DIG inst0 ). =1: Data/clk path source from DIGB ( DIG inst1 ) */ + UCHAR fDPConnector:1; /* bit4=0: DP connector =1: None DP connector */ + UCHAR ucReserved:1; + UCHAR ucTransmitterSel:2; /* bit7:6: =0 Dig Transmitter 1 ( Uniphy AB ) */ + /* =1 Dig Transmitter 2 ( Uniphy CD ) */ + /* =2 Dig Transmitter 3 ( Uniphy EF ) */ +#endif +} ATOM_DIG_TRANSMITTER_CONFIG_V2; + +/* ucConfig */ +/* Bit0 */ +#define ATOM_TRANSMITTER_CONFIG_V2_DUAL_LINK_CONNECTOR 0x01 + +/* Bit1 */ +#define ATOM_TRANSMITTER_CONFIG_V2_COHERENT 0x02 + +/* Bit2 */ +#define ATOM_TRANSMITTER_CONFIG_V2_LINK_SEL_MASK 0x04 +#define ATOM_TRANSMITTER_CONFIG_V2_LINKA 0x00 +#define ATOM_TRANSMITTER_CONFIG_V2_LINKB 0x04 + +/* Bit3 */ +#define ATOM_TRANSMITTER_CONFIG_V2_ENCODER_SEL_MASK 0x08 +#define ATOM_TRANSMITTER_CONFIG_V2_DIG1_ENCODER 0x00 /* only used when ucAction == ATOM_TRANSMITTER_ACTION_ENABLE or ATOM_TRANSMITTER_ACTION_SETUP */ +#define ATOM_TRANSMITTER_CONFIG_V2_DIG2_ENCODER 0x08 /* only used when ucAction == ATOM_TRANSMITTER_ACTION_ENABLE or ATOM_TRANSMITTER_ACTION_SETUP */ + +/* Bit4 */ +#define ATOM_TRASMITTER_CONFIG_V2_DP_CONNECTOR 0x10 + +/* Bit7:6 */ +#define ATOM_TRANSMITTER_CONFIG_V2_TRANSMITTER_SEL_MASK 0xC0 +#define ATOM_TRANSMITTER_CONFIG_V2_TRANSMITTER1 0x00 /* AB */ +#define ATOM_TRANSMITTER_CONFIG_V2_TRANSMITTER2 0x40 /* CD */ +#define ATOM_TRANSMITTER_CONFIG_V2_TRANSMITTER3 0x80 /* EF */ + +typedef struct _DIG_TRANSMITTER_CONTROL_PARAMETERS_V2 { + union { + USHORT usPixelClock; /* in 10KHz; for bios convenient */ + USHORT usInitInfo; /* when init uniphy,lower 8bit is used for connector type defined in objectid.h */ + ATOM_DP_VS_MODE asMode; /* DP Voltage swing mode */ + }; + ATOM_DIG_TRANSMITTER_CONFIG_V2 acConfig; + UCHAR ucAction; /* define as ATOM_TRANSMITER_ACTION_XXX */ + UCHAR ucReserved[4]; +} DIG_TRANSMITTER_CONTROL_PARAMETERS_V2; + +/****************************************************************************/ +/* Structures used by DAC1OuputControlTable */ +/* DAC2OuputControlTable */ +/* LVTMAOutputControlTable (Before DEC30) */ +/* TMDSAOutputControlTable (Before DEC30) */ +/****************************************************************************/ +typedef struct _DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS { + UCHAR ucAction; /* Possible input:ATOM_ENABLE||ATOMDISABLE */ + /* When the display is LCD, in addition to above: */ + /* ATOM_LCD_BLOFF|| ATOM_LCD_BLON ||ATOM_LCD_BL_BRIGHTNESS_CONTROL||ATOM_LCD_SELFTEST_START|| */ + /* ATOM_LCD_SELFTEST_STOP */ + + UCHAR aucPadding[3]; /* padding to DWORD aligned */ +} DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS; + +#define DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS + +#define CRT1_OUTPUT_CONTROL_PARAMETERS DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS +#define CRT1_OUTPUT_CONTROL_PS_ALLOCATION DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION + +#define CRT2_OUTPUT_CONTROL_PARAMETERS DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS +#define CRT2_OUTPUT_CONTROL_PS_ALLOCATION DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION + +#define CV1_OUTPUT_CONTROL_PARAMETERS DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS +#define CV1_OUTPUT_CONTROL_PS_ALLOCATION DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION + +#define TV1_OUTPUT_CONTROL_PARAMETERS DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS +#define TV1_OUTPUT_CONTROL_PS_ALLOCATION DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION + +#define DFP1_OUTPUT_CONTROL_PARAMETERS DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS +#define DFP1_OUTPUT_CONTROL_PS_ALLOCATION DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION + +#define DFP2_OUTPUT_CONTROL_PARAMETERS DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS +#define DFP2_OUTPUT_CONTROL_PS_ALLOCATION DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION + +#define LCD1_OUTPUT_CONTROL_PARAMETERS DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS +#define LCD1_OUTPUT_CONTROL_PS_ALLOCATION DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION + +#define DVO_OUTPUT_CONTROL_PARAMETERS DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS +#define DVO_OUTPUT_CONTROL_PS_ALLOCATION DIG_TRANSMITTER_CONTROL_PS_ALLOCATION +#define DVO_OUTPUT_CONTROL_PARAMETERS_V3 DIG_TRANSMITTER_CONTROL_PARAMETERS + +/****************************************************************************/ +/* Structures used by BlankCRTCTable */ +/****************************************************************************/ +typedef struct _BLANK_CRTC_PARAMETERS { + UCHAR ucCRTC; /* ATOM_CRTC1 or ATOM_CRTC2 */ + UCHAR ucBlanking; /* ATOM_BLANKING or ATOM_BLANKINGOFF */ + USHORT usBlackColorRCr; + USHORT usBlackColorGY; + USHORT usBlackColorBCb; +} BLANK_CRTC_PARAMETERS; +#define BLANK_CRTC_PS_ALLOCATION BLANK_CRTC_PARAMETERS + +/****************************************************************************/ +/* Structures used by EnableCRTCTable */ +/* EnableCRTCMemReqTable */ +/* UpdateCRTC_DoubleBufferRegistersTable */ +/****************************************************************************/ +typedef struct _ENABLE_CRTC_PARAMETERS { + UCHAR ucCRTC; /* ATOM_CRTC1 or ATOM_CRTC2 */ + UCHAR ucEnable; /* ATOM_ENABLE or ATOM_DISABLE */ + UCHAR ucPadding[2]; +} ENABLE_CRTC_PARAMETERS; +#define ENABLE_CRTC_PS_ALLOCATION ENABLE_CRTC_PARAMETERS + +/****************************************************************************/ +/* Structures used by SetCRTC_OverScanTable */ +/****************************************************************************/ +typedef struct _SET_CRTC_OVERSCAN_PARAMETERS { + USHORT usOverscanRight; /* right */ + USHORT usOverscanLeft; /* left */ + USHORT usOverscanBottom; /* bottom */ + USHORT usOverscanTop; /* top */ + UCHAR ucCRTC; /* ATOM_CRTC1 or ATOM_CRTC2 */ + UCHAR ucPadding[3]; +} SET_CRTC_OVERSCAN_PARAMETERS; +#define SET_CRTC_OVERSCAN_PS_ALLOCATION SET_CRTC_OVERSCAN_PARAMETERS + +/****************************************************************************/ +/* Structures used by SetCRTC_ReplicationTable */ +/****************************************************************************/ +typedef struct _SET_CRTC_REPLICATION_PARAMETERS { + UCHAR ucH_Replication; /* horizontal replication */ + UCHAR ucV_Replication; /* vertical replication */ + UCHAR usCRTC; /* ATOM_CRTC1 or ATOM_CRTC2 */ + UCHAR ucPadding; +} SET_CRTC_REPLICATION_PARAMETERS; +#define SET_CRTC_REPLICATION_PS_ALLOCATION SET_CRTC_REPLICATION_PARAMETERS + +/****************************************************************************/ +/* Structures used by SelectCRTC_SourceTable */ +/****************************************************************************/ +typedef struct _SELECT_CRTC_SOURCE_PARAMETERS { + UCHAR ucCRTC; /* ATOM_CRTC1 or ATOM_CRTC2 */ + UCHAR ucDevice; /* ATOM_DEVICE_CRT1|ATOM_DEVICE_CRT2|.... */ + UCHAR ucPadding[2]; +} SELECT_CRTC_SOURCE_PARAMETERS; +#define SELECT_CRTC_SOURCE_PS_ALLOCATION SELECT_CRTC_SOURCE_PARAMETERS + +typedef struct _SELECT_CRTC_SOURCE_PARAMETERS_V2 { + UCHAR ucCRTC; /* ATOM_CRTC1 or ATOM_CRTC2 */ + UCHAR ucEncoderID; /* DAC1/DAC2/TVOUT/DIG1/DIG2/DVO */ + UCHAR ucEncodeMode; /* Encoding mode, only valid when using DIG1/DIG2/DVO */ + UCHAR ucPadding; +} SELECT_CRTC_SOURCE_PARAMETERS_V2; + +/* ucEncoderID */ +/* #define ASIC_INT_DAC1_ENCODER_ID 0x00 */ +/* #define ASIC_INT_TV_ENCODER_ID 0x02 */ +/* #define ASIC_INT_DIG1_ENCODER_ID 0x03 */ +/* #define ASIC_INT_DAC2_ENCODER_ID 0x04 */ +/* #define ASIC_EXT_TV_ENCODER_ID 0x06 */ +/* #define ASIC_INT_DVO_ENCODER_ID 0x07 */ +/* #define ASIC_INT_DIG2_ENCODER_ID 0x09 */ +/* #define ASIC_EXT_DIG_ENCODER_ID 0x05 */ + +/* ucEncodeMode */ +/* #define ATOM_ENCODER_MODE_DP 0 */ +/* #define ATOM_ENCODER_MODE_LVDS 1 */ +/* #define ATOM_ENCODER_MODE_DVI 2 */ +/* #define ATOM_ENCODER_MODE_HDMI 3 */ +/* #define ATOM_ENCODER_MODE_SDVO 4 */ +/* #define ATOM_ENCODER_MODE_TV 13 */ +/* #define ATOM_ENCODER_MODE_CV 14 */ +/* #define ATOM_ENCODER_MODE_CRT 15 */ + +/****************************************************************************/ +/* Structures used by SetPixelClockTable */ +/* GetPixelClockTable */ +/****************************************************************************/ +/* Major revision=1., Minor revision=1 */ +typedef struct _PIXEL_CLOCK_PARAMETERS { + USHORT usPixelClock; /* in 10kHz unit; for bios convenient = (RefClk*FB_Div)/(Ref_Div*Post_Div) */ + /* 0 means disable PPLL */ + USHORT usRefDiv; /* Reference divider */ + USHORT usFbDiv; /* feedback divider */ + UCHAR ucPostDiv; /* post divider */ + UCHAR ucFracFbDiv; /* fractional feedback divider */ + UCHAR ucPpll; /* ATOM_PPLL1 or ATOM_PPL2 */ + UCHAR ucRefDivSrc; /* ATOM_PJITTER or ATO_NONPJITTER */ + UCHAR ucCRTC; /* Which CRTC uses this Ppll */ + UCHAR ucPadding; +} PIXEL_CLOCK_PARAMETERS; + +/* Major revision=1., Minor revision=2, add ucMiscIfno */ +/* ucMiscInfo: */ +#define MISC_FORCE_REPROG_PIXEL_CLOCK 0x1 +#define MISC_DEVICE_INDEX_MASK 0xF0 +#define MISC_DEVICE_INDEX_SHIFT 4 + +typedef struct _PIXEL_CLOCK_PARAMETERS_V2 { + USHORT usPixelClock; /* in 10kHz unit; for bios convenient = (RefClk*FB_Div)/(Ref_Div*Post_Div) */ + /* 0 means disable PPLL */ + USHORT usRefDiv; /* Reference divider */ + USHORT usFbDiv; /* feedback divider */ + UCHAR ucPostDiv; /* post divider */ + UCHAR ucFracFbDiv; /* fractional feedback divider */ + UCHAR ucPpll; /* ATOM_PPLL1 or ATOM_PPL2 */ + UCHAR ucRefDivSrc; /* ATOM_PJITTER or ATO_NONPJITTER */ + UCHAR ucCRTC; /* Which CRTC uses this Ppll */ + UCHAR ucMiscInfo; /* Different bits for different purpose, bit [7:4] as device index, bit[0]=Force prog */ +} PIXEL_CLOCK_PARAMETERS_V2; + +/* Major revision=1., Minor revision=3, structure/definition change */ +/* ucEncoderMode: */ +/* ATOM_ENCODER_MODE_DP */ +/* ATOM_ENOCDER_MODE_LVDS */ +/* ATOM_ENOCDER_MODE_DVI */ +/* ATOM_ENOCDER_MODE_HDMI */ +/* ATOM_ENOCDER_MODE_SDVO */ +/* ATOM_ENCODER_MODE_TV 13 */ +/* ATOM_ENCODER_MODE_CV 14 */ +/* ATOM_ENCODER_MODE_CRT 15 */ + +/* ucDVOConfig */ +/* #define DVO_ENCODER_CONFIG_RATE_SEL 0x01 */ +/* #define DVO_ENCODER_CONFIG_DDR_SPEED 0x00 */ +/* #define DVO_ENCODER_CONFIG_SDR_SPEED 0x01 */ +/* #define DVO_ENCODER_CONFIG_OUTPUT_SEL 0x0c */ +/* #define DVO_ENCODER_CONFIG_LOW12BIT 0x00 */ +/* #define DVO_ENCODER_CONFIG_UPPER12BIT 0x04 */ +/* #define DVO_ENCODER_CONFIG_24BIT 0x08 */ + +/* ucMiscInfo: also changed, see below */ +#define PIXEL_CLOCK_MISC_FORCE_PROG_PPLL 0x01 +#define PIXEL_CLOCK_MISC_VGA_MODE 0x02 +#define PIXEL_CLOCK_MISC_CRTC_SEL_MASK 0x04 +#define PIXEL_CLOCK_MISC_CRTC_SEL_CRTC1 0x00 +#define PIXEL_CLOCK_MISC_CRTC_SEL_CRTC2 0x04 +#define PIXEL_CLOCK_MISC_USE_ENGINE_FOR_DISPCLK 0x08 + +typedef struct _PIXEL_CLOCK_PARAMETERS_V3 { + USHORT usPixelClock; /* in 10kHz unit; for bios convenient = (RefClk*FB_Div)/(Ref_Div*Post_Div) */ + /* 0 means disable PPLL. For VGA PPLL,make sure this value is not 0. */ + USHORT usRefDiv; /* Reference divider */ + USHORT usFbDiv; /* feedback divider */ + UCHAR ucPostDiv; /* post divider */ + UCHAR ucFracFbDiv; /* fractional feedback divider */ + UCHAR ucPpll; /* ATOM_PPLL1 or ATOM_PPL2 */ + UCHAR ucTransmitterId; /* graphic encoder id defined in objectId.h */ + union { + UCHAR ucEncoderMode; /* encoder type defined as ATOM_ENCODER_MODE_DP/DVI/HDMI/ */ + UCHAR ucDVOConfig; /* when use DVO, need to know SDR/DDR, 12bit or 24bit */ + }; + UCHAR ucMiscInfo; /* bit[0]=Force program, bit[1]= set pclk for VGA, b[2]= CRTC sel */ + /* bit[3]=0:use PPLL for dispclk source, =1: use engine clock for dispclock source */ +} PIXEL_CLOCK_PARAMETERS_V3; + +#define PIXEL_CLOCK_PARAMETERS_LAST PIXEL_CLOCK_PARAMETERS_V2 +#define GET_PIXEL_CLOCK_PS_ALLOCATION PIXEL_CLOCK_PARAMETERS_LAST + +/****************************************************************************/ +/* Structures used by AdjustDisplayPllTable */ +/****************************************************************************/ +typedef struct _ADJUST_DISPLAY_PLL_PARAMETERS { + USHORT usPixelClock; + UCHAR ucTransmitterID; + UCHAR ucEncodeMode; + union { + UCHAR ucDVOConfig; /* if DVO, need passing link rate and output 12bitlow or 24bit */ + UCHAR ucConfig; /* if none DVO, not defined yet */ + }; + UCHAR ucReserved[3]; +} ADJUST_DISPLAY_PLL_PARAMETERS; + +#define ADJUST_DISPLAY_CONFIG_SS_ENABLE 0x10 + +#define ADJUST_DISPLAY_PLL_PS_ALLOCATION ADJUST_DISPLAY_PLL_PARAMETERS + +/****************************************************************************/ +/* Structures used by EnableYUVTable */ +/****************************************************************************/ +typedef struct _ENABLE_YUV_PARAMETERS { + UCHAR ucEnable; /* ATOM_ENABLE:Enable YUV or ATOM_DISABLE:Disable YUV (RGB) */ + UCHAR ucCRTC; /* Which CRTC needs this YUV or RGB format */ + UCHAR ucPadding[2]; +} ENABLE_YUV_PARAMETERS; +#define ENABLE_YUV_PS_ALLOCATION ENABLE_YUV_PARAMETERS + +/****************************************************************************/ +/* Structures used by GetMemoryClockTable */ +/****************************************************************************/ +typedef struct _GET_MEMORY_CLOCK_PARAMETERS { + ULONG ulReturnMemoryClock; /* current memory speed in 10KHz unit */ +} GET_MEMORY_CLOCK_PARAMETERS; +#define GET_MEMORY_CLOCK_PS_ALLOCATION GET_MEMORY_CLOCK_PARAMETERS + +/****************************************************************************/ +/* Structures used by GetEngineClockTable */ +/****************************************************************************/ +typedef struct _GET_ENGINE_CLOCK_PARAMETERS { + ULONG ulReturnEngineClock; /* current engine speed in 10KHz unit */ +} GET_ENGINE_CLOCK_PARAMETERS; +#define GET_ENGINE_CLOCK_PS_ALLOCATION GET_ENGINE_CLOCK_PARAMETERS + +/****************************************************************************/ +/* Following Structures and constant may be obsolete */ +/****************************************************************************/ +/* Maxium 8 bytes,the data read in will be placed in the parameter space. */ +/* Read operaion successeful when the paramter space is non-zero, otherwise read operation failed */ +typedef struct _READ_EDID_FROM_HW_I2C_DATA_PARAMETERS { + USHORT usPrescale; /* Ratio between Engine clock and I2C clock */ + USHORT usVRAMAddress; /* Adress in Frame Buffer where to pace raw EDID */ + USHORT usStatus; /* When use output: lower byte EDID checksum, high byte hardware status */ + /* WHen use input: lower byte as 'byte to read':currently limited to 128byte or 1byte */ + UCHAR ucSlaveAddr; /* Read from which slave */ + UCHAR ucLineNumber; /* Read from which HW assisted line */ +} READ_EDID_FROM_HW_I2C_DATA_PARAMETERS; +#define READ_EDID_FROM_HW_I2C_DATA_PS_ALLOCATION READ_EDID_FROM_HW_I2C_DATA_PARAMETERS + +#define ATOM_WRITE_I2C_FORMAT_PSOFFSET_PSDATABYTE 0 +#define ATOM_WRITE_I2C_FORMAT_PSOFFSET_PSTWODATABYTES 1 +#define ATOM_WRITE_I2C_FORMAT_PSCOUNTER_PSOFFSET_IDDATABLOCK 2 +#define ATOM_WRITE_I2C_FORMAT_PSCOUNTER_IDOFFSET_PLUS_IDDATABLOCK 3 +#define ATOM_WRITE_I2C_FORMAT_IDCOUNTER_IDOFFSET_IDDATABLOCK 4 + +typedef struct _WRITE_ONE_BYTE_HW_I2C_DATA_PARAMETERS { + USHORT usPrescale; /* Ratio between Engine clock and I2C clock */ + USHORT usByteOffset; /* Write to which byte */ + /* Upper portion of usByteOffset is Format of data */ + /* 1bytePS+offsetPS */ + /* 2bytesPS+offsetPS */ + /* blockID+offsetPS */ + /* blockID+offsetID */ + /* blockID+counterID+offsetID */ + UCHAR ucData; /* PS data1 */ + UCHAR ucStatus; /* Status byte 1=success, 2=failure, Also is used as PS data2 */ + UCHAR ucSlaveAddr; /* Write to which slave */ + UCHAR ucLineNumber; /* Write from which HW assisted line */ +} WRITE_ONE_BYTE_HW_I2C_DATA_PARAMETERS; + +#define WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION WRITE_ONE_BYTE_HW_I2C_DATA_PARAMETERS + +typedef struct _SET_UP_HW_I2C_DATA_PARAMETERS { + USHORT usPrescale; /* Ratio between Engine clock and I2C clock */ + UCHAR ucSlaveAddr; /* Write to which slave */ + UCHAR ucLineNumber; /* Write from which HW assisted line */ +} SET_UP_HW_I2C_DATA_PARAMETERS; + +/**************************************************************************/ +#define SPEED_FAN_CONTROL_PS_ALLOCATION WRITE_ONE_BYTE_HW_I2C_DATA_PARAMETERS + +/****************************************************************************/ +/* Structures used by PowerConnectorDetectionTable */ +/****************************************************************************/ +typedef struct _POWER_CONNECTOR_DETECTION_PARAMETERS { + UCHAR ucPowerConnectorStatus; /* Used for return value 0: detected, 1:not detected */ + UCHAR ucPwrBehaviorId; + USHORT usPwrBudget; /* how much power currently boot to in unit of watt */ +} POWER_CONNECTOR_DETECTION_PARAMETERS; + +typedef struct POWER_CONNECTOR_DETECTION_PS_ALLOCATION { + UCHAR ucPowerConnectorStatus; /* Used for return value 0: detected, 1:not detected */ + UCHAR ucReserved; + USHORT usPwrBudget; /* how much power currently boot to in unit of watt */ + WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved; +} POWER_CONNECTOR_DETECTION_PS_ALLOCATION; + +/****************************LVDS SS Command Table Definitions**********************/ + +/****************************************************************************/ +/* Structures used by EnableSpreadSpectrumOnPPLLTable */ +/****************************************************************************/ +typedef struct _ENABLE_LVDS_SS_PARAMETERS { + USHORT usSpreadSpectrumPercentage; + UCHAR ucSpreadSpectrumType; /* Bit1=0 Down Spread,=1 Center Spread. Bit1=1 Ext. =0 Int. Others:TBD */ + UCHAR ucSpreadSpectrumStepSize_Delay; /* bits3:2 SS_STEP_SIZE; bit 6:4 SS_DELAY */ + UCHAR ucEnable; /* ATOM_ENABLE or ATOM_DISABLE */ + UCHAR ucPadding[3]; +} ENABLE_LVDS_SS_PARAMETERS; + +/* ucTableFormatRevision=1,ucTableContentRevision=2 */ +typedef struct _ENABLE_LVDS_SS_PARAMETERS_V2 { + USHORT usSpreadSpectrumPercentage; + UCHAR ucSpreadSpectrumType; /* Bit1=0 Down Spread,=1 Center Spread. Bit1=1 Ext. =0 Int. Others:TBD */ + UCHAR ucSpreadSpectrumStep; /* */ + UCHAR ucEnable; /* ATOM_ENABLE or ATOM_DISABLE */ + UCHAR ucSpreadSpectrumDelay; + UCHAR ucSpreadSpectrumRange; + UCHAR ucPadding; +} ENABLE_LVDS_SS_PARAMETERS_V2; + +/* This new structure is based on ENABLE_LVDS_SS_PARAMETERS but expands to SS on PPLL, so other devices can use SS. */ +typedef struct _ENABLE_SPREAD_SPECTRUM_ON_PPLL { + USHORT usSpreadSpectrumPercentage; + UCHAR ucSpreadSpectrumType; /* Bit1=0 Down Spread,=1 Center Spread. Bit1=1 Ext. =0 Int. Others:TBD */ + UCHAR ucSpreadSpectrumStep; /* */ + UCHAR ucEnable; /* ATOM_ENABLE or ATOM_DISABLE */ + UCHAR ucSpreadSpectrumDelay; + UCHAR ucSpreadSpectrumRange; + UCHAR ucPpll; /* ATOM_PPLL1/ATOM_PPLL2 */ +} ENABLE_SPREAD_SPECTRUM_ON_PPLL; + +#define ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION ENABLE_SPREAD_SPECTRUM_ON_PPLL + +/**************************************************************************/ + +typedef struct _SET_PIXEL_CLOCK_PS_ALLOCATION { + PIXEL_CLOCK_PARAMETERS sPCLKInput; + ENABLE_SPREAD_SPECTRUM_ON_PPLL sReserved; /* Caller doesn't need to init this portion */ +} SET_PIXEL_CLOCK_PS_ALLOCATION; + +#define ENABLE_VGA_RENDER_PS_ALLOCATION SET_PIXEL_CLOCK_PS_ALLOCATION + +/****************************************************************************/ +/* Structures used by ### */ +/****************************************************************************/ +typedef struct _MEMORY_TRAINING_PARAMETERS { + ULONG ulTargetMemoryClock; /* In 10Khz unit */ +} MEMORY_TRAINING_PARAMETERS; +#define MEMORY_TRAINING_PS_ALLOCATION MEMORY_TRAINING_PARAMETERS + +/****************************LVDS and other encoder command table definitions **********************/ + +/****************************************************************************/ +/* Structures used by LVDSEncoderControlTable (Before DCE30) */ +/* LVTMAEncoderControlTable (Before DCE30) */ +/* TMDSAEncoderControlTable (Before DCE30) */ +/****************************************************************************/ +typedef struct _LVDS_ENCODER_CONTROL_PARAMETERS { + USHORT usPixelClock; /* in 10KHz; for bios convenient */ + UCHAR ucMisc; /* bit0=0: Enable single link */ + /* =1: Enable dual link */ + /* Bit1=0: 666RGB */ + /* =1: 888RGB */ + UCHAR ucAction; /* 0: turn off encoder */ + /* 1: setup and turn on encoder */ +} LVDS_ENCODER_CONTROL_PARAMETERS; + +#define LVDS_ENCODER_CONTROL_PS_ALLOCATION LVDS_ENCODER_CONTROL_PARAMETERS + +#define TMDS1_ENCODER_CONTROL_PARAMETERS LVDS_ENCODER_CONTROL_PARAMETERS +#define TMDS1_ENCODER_CONTROL_PS_ALLOCATION TMDS1_ENCODER_CONTROL_PARAMETERS + +#define TMDS2_ENCODER_CONTROL_PARAMETERS TMDS1_ENCODER_CONTROL_PARAMETERS +#define TMDS2_ENCODER_CONTROL_PS_ALLOCATION TMDS2_ENCODER_CONTROL_PARAMETERS + +/* ucTableFormatRevision=1,ucTableContentRevision=2 */ +typedef struct _LVDS_ENCODER_CONTROL_PARAMETERS_V2 { + USHORT usPixelClock; /* in 10KHz; for bios convenient */ + UCHAR ucMisc; /* see PANEL_ENCODER_MISC_xx defintions below */ + UCHAR ucAction; /* 0: turn off encoder */ + /* 1: setup and turn on encoder */ + UCHAR ucTruncate; /* bit0=0: Disable truncate */ + /* =1: Enable truncate */ + /* bit4=0: 666RGB */ + /* =1: 888RGB */ + UCHAR ucSpatial; /* bit0=0: Disable spatial dithering */ + /* =1: Enable spatial dithering */ + /* bit4=0: 666RGB */ + /* =1: 888RGB */ + UCHAR ucTemporal; /* bit0=0: Disable temporal dithering */ + /* =1: Enable temporal dithering */ + /* bit4=0: 666RGB */ + /* =1: 888RGB */ + /* bit5=0: Gray level 2 */ + /* =1: Gray level 4 */ + UCHAR ucFRC; /* bit4=0: 25FRC_SEL pattern E */ + /* =1: 25FRC_SEL pattern F */ + /* bit6:5=0: 50FRC_SEL pattern A */ + /* =1: 50FRC_SEL pattern B */ + /* =2: 50FRC_SEL pattern C */ + /* =3: 50FRC_SEL pattern D */ + /* bit7=0: 75FRC_SEL pattern E */ + /* =1: 75FRC_SEL pattern F */ +} LVDS_ENCODER_CONTROL_PARAMETERS_V2; + +#define LVDS_ENCODER_CONTROL_PS_ALLOCATION_V2 LVDS_ENCODER_CONTROL_PARAMETERS_V2 + +#define TMDS1_ENCODER_CONTROL_PARAMETERS_V2 LVDS_ENCODER_CONTROL_PARAMETERS_V2 +#define TMDS1_ENCODER_CONTROL_PS_ALLOCATION_V2 TMDS1_ENCODER_CONTROL_PARAMETERS_V2 + +#define TMDS2_ENCODER_CONTROL_PARAMETERS_V2 TMDS1_ENCODER_CONTROL_PARAMETERS_V2 +#define TMDS2_ENCODER_CONTROL_PS_ALLOCATION_V2 TMDS2_ENCODER_CONTROL_PARAMETERS_V2 + +#define LVDS_ENCODER_CONTROL_PARAMETERS_V3 LVDS_ENCODER_CONTROL_PARAMETERS_V2 +#define LVDS_ENCODER_CONTROL_PS_ALLOCATION_V3 LVDS_ENCODER_CONTROL_PARAMETERS_V3 + +#define TMDS1_ENCODER_CONTROL_PARAMETERS_V3 LVDS_ENCODER_CONTROL_PARAMETERS_V3 +#define TMDS1_ENCODER_CONTROL_PS_ALLOCATION_V3 TMDS1_ENCODER_CONTROL_PARAMETERS_V3 + +#define TMDS2_ENCODER_CONTROL_PARAMETERS_V3 LVDS_ENCODER_CONTROL_PARAMETERS_V3 +#define TMDS2_ENCODER_CONTROL_PS_ALLOCATION_V3 TMDS2_ENCODER_CONTROL_PARAMETERS_V3 + +/****************************************************************************/ +/* Structures used by ### */ +/****************************************************************************/ +typedef struct _ENABLE_EXTERNAL_TMDS_ENCODER_PARAMETERS { + UCHAR ucEnable; /* Enable or Disable External TMDS encoder */ + UCHAR ucMisc; /* Bit0=0:Enable Single link;=1:Enable Dual link;Bit1 {=0:666RGB, =1:888RGB} */ + UCHAR ucPadding[2]; +} ENABLE_EXTERNAL_TMDS_ENCODER_PARAMETERS; + +typedef struct _ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION { + ENABLE_EXTERNAL_TMDS_ENCODER_PARAMETERS sXTmdsEncoder; + WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved; /* Caller doesn't need to init this portion */ +} ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION; + +#define ENABLE_EXTERNAL_TMDS_ENCODER_PARAMETERS_V2 LVDS_ENCODER_CONTROL_PARAMETERS_V2 + +typedef struct _ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION_V2 { + ENABLE_EXTERNAL_TMDS_ENCODER_PARAMETERS_V2 sXTmdsEncoder; + WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved; /* Caller doesn't need to init this portion */ +} ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION_V2; + +typedef struct _EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION { + DIG_ENCODER_CONTROL_PARAMETERS sDigEncoder; + WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved; +} EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION; + +/****************************************************************************/ +/* Structures used by DVOEncoderControlTable */ +/****************************************************************************/ +/* ucTableFormatRevision=1,ucTableContentRevision=3 */ + +/* ucDVOConfig: */ +#define DVO_ENCODER_CONFIG_RATE_SEL 0x01 +#define DVO_ENCODER_CONFIG_DDR_SPEED 0x00 +#define DVO_ENCODER_CONFIG_SDR_SPEED 0x01 +#define DVO_ENCODER_CONFIG_OUTPUT_SEL 0x0c +#define DVO_ENCODER_CONFIG_LOW12BIT 0x00 +#define DVO_ENCODER_CONFIG_UPPER12BIT 0x04 +#define DVO_ENCODER_CONFIG_24BIT 0x08 + +typedef struct _DVO_ENCODER_CONTROL_PARAMETERS_V3 { + USHORT usPixelClock; + UCHAR ucDVOConfig; + UCHAR ucAction; /* ATOM_ENABLE/ATOM_DISABLE/ATOM_HPD_INIT */ + UCHAR ucReseved[4]; +} DVO_ENCODER_CONTROL_PARAMETERS_V3; +#define DVO_ENCODER_CONTROL_PS_ALLOCATION_V3 DVO_ENCODER_CONTROL_PARAMETERS_V3 + +/* ucTableFormatRevision=1 */ +/* ucTableContentRevision=3 structure is not changed but usMisc add bit 1 as another input for */ +/* bit1=0: non-coherent mode */ +/* =1: coherent mode */ + +/* ========================================================================================== */ +/* Only change is here next time when changing encoder parameter definitions again! */ +#define LVDS_ENCODER_CONTROL_PARAMETERS_LAST LVDS_ENCODER_CONTROL_PARAMETERS_V3 +#define LVDS_ENCODER_CONTROL_PS_ALLOCATION_LAST LVDS_ENCODER_CONTROL_PARAMETERS_LAST + +#define TMDS1_ENCODER_CONTROL_PARAMETERS_LAST LVDS_ENCODER_CONTROL_PARAMETERS_V3 +#define TMDS1_ENCODER_CONTROL_PS_ALLOCATION_LAST TMDS1_ENCODER_CONTROL_PARAMETERS_LAST + +#define TMDS2_ENCODER_CONTROL_PARAMETERS_LAST LVDS_ENCODER_CONTROL_PARAMETERS_V3 +#define TMDS2_ENCODER_CONTROL_PS_ALLOCATION_LAST TMDS2_ENCODER_CONTROL_PARAMETERS_LAST + +#define DVO_ENCODER_CONTROL_PARAMETERS_LAST DVO_ENCODER_CONTROL_PARAMETERS +#define DVO_ENCODER_CONTROL_PS_ALLOCATION_LAST DVO_ENCODER_CONTROL_PS_ALLOCATION + +/* ========================================================================================== */ +#define PANEL_ENCODER_MISC_DUAL 0x01 +#define PANEL_ENCODER_MISC_COHERENT 0x02 +#define PANEL_ENCODER_MISC_TMDS_LINKB 0x04 +#define PANEL_ENCODER_MISC_HDMI_TYPE 0x08 + +#define PANEL_ENCODER_ACTION_DISABLE ATOM_DISABLE +#define PANEL_ENCODER_ACTION_ENABLE ATOM_ENABLE +#define PANEL_ENCODER_ACTION_COHERENTSEQ (ATOM_ENABLE+1) + +#define PANEL_ENCODER_TRUNCATE_EN 0x01 +#define PANEL_ENCODER_TRUNCATE_DEPTH 0x10 +#define PANEL_ENCODER_SPATIAL_DITHER_EN 0x01 +#define PANEL_ENCODER_SPATIAL_DITHER_DEPTH 0x10 +#define PANEL_ENCODER_TEMPORAL_DITHER_EN 0x01 +#define PANEL_ENCODER_TEMPORAL_DITHER_DEPTH 0x10 +#define PANEL_ENCODER_TEMPORAL_LEVEL_4 0x20 +#define PANEL_ENCODER_25FRC_MASK 0x10 +#define PANEL_ENCODER_25FRC_E 0x00 +#define PANEL_ENCODER_25FRC_F 0x10 +#define PANEL_ENCODER_50FRC_MASK 0x60 +#define PANEL_ENCODER_50FRC_A 0x00 +#define PANEL_ENCODER_50FRC_B 0x20 +#define PANEL_ENCODER_50FRC_C 0x40 +#define PANEL_ENCODER_50FRC_D 0x60 +#define PANEL_ENCODER_75FRC_MASK 0x80 +#define PANEL_ENCODER_75FRC_E 0x00 +#define PANEL_ENCODER_75FRC_F 0x80 + +/****************************************************************************/ +/* Structures used by SetVoltageTable */ +/****************************************************************************/ +#define SET_VOLTAGE_TYPE_ASIC_VDDC 1 +#define SET_VOLTAGE_TYPE_ASIC_MVDDC 2 +#define SET_VOLTAGE_TYPE_ASIC_MVDDQ 3 +#define SET_VOLTAGE_TYPE_ASIC_VDDCI 4 +#define SET_VOLTAGE_INIT_MODE 5 +#define SET_VOLTAGE_GET_MAX_VOLTAGE 6 /* Gets the Max. voltage for the soldered Asic */ + +#define SET_ASIC_VOLTAGE_MODE_ALL_SOURCE 0x1 +#define SET_ASIC_VOLTAGE_MODE_SOURCE_A 0x2 +#define SET_ASIC_VOLTAGE_MODE_SOURCE_B 0x4 + +#define SET_ASIC_VOLTAGE_MODE_SET_VOLTAGE 0x0 +#define SET_ASIC_VOLTAGE_MODE_GET_GPIOVAL 0x1 +#define SET_ASIC_VOLTAGE_MODE_GET_GPIOMASK 0x2 + +typedef struct _SET_VOLTAGE_PARAMETERS { + UCHAR ucVoltageType; /* To tell which voltage to set up, VDDC/MVDDC/MVDDQ */ + UCHAR ucVoltageMode; /* To set all, to set source A or source B or ... */ + UCHAR ucVoltageIndex; /* An index to tell which voltage level */ + UCHAR ucReserved; +} SET_VOLTAGE_PARAMETERS; + +typedef struct _SET_VOLTAGE_PARAMETERS_V2 { + UCHAR ucVoltageType; /* To tell which voltage to set up, VDDC/MVDDC/MVDDQ */ + UCHAR ucVoltageMode; /* Not used, maybe use for state machine for differen power mode */ + USHORT usVoltageLevel; /* real voltage level */ +} SET_VOLTAGE_PARAMETERS_V2; + +typedef struct _SET_VOLTAGE_PS_ALLOCATION { + SET_VOLTAGE_PARAMETERS sASICSetVoltage; + WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved; +} SET_VOLTAGE_PS_ALLOCATION; + +/****************************************************************************/ +/* Structures used by TVEncoderControlTable */ +/****************************************************************************/ +typedef struct _TV_ENCODER_CONTROL_PARAMETERS { + USHORT usPixelClock; /* in 10KHz; for bios convenient */ + UCHAR ucTvStandard; /* See definition "ATOM_TV_NTSC ..." */ + UCHAR ucAction; /* 0: turn off encoder */ + /* 1: setup and turn on encoder */ +} TV_ENCODER_CONTROL_PARAMETERS; + +typedef struct _TV_ENCODER_CONTROL_PS_ALLOCATION { + TV_ENCODER_CONTROL_PARAMETERS sTVEncoder; + WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved; /* Don't set this one */ +} TV_ENCODER_CONTROL_PS_ALLOCATION; + +/* ==============================Data Table Portion==================================== */ + +#ifdef UEFI_BUILD +#define UTEMP USHORT +#define USHORT void* +#endif + +/****************************************************************************/ +/* Structure used in Data.mtb */ +/****************************************************************************/ +typedef struct _ATOM_MASTER_LIST_OF_DATA_TABLES { + USHORT UtilityPipeLine; /* Offest for the utility to get parser info,Don't change this position! */ + USHORT MultimediaCapabilityInfo; /* Only used by MM Lib,latest version 1.1, not configuable from Bios, need to include the table to build Bios */ + USHORT MultimediaConfigInfo; /* Only used by MM Lib,latest version 2.1, not configuable from Bios, need to include the table to build Bios */ + USHORT StandardVESA_Timing; /* Only used by Bios */ + USHORT FirmwareInfo; /* Shared by various SW components,latest version 1.4 */ + USHORT DAC_Info; /* Will be obsolete from R600 */ + USHORT LVDS_Info; /* Shared by various SW components,latest version 1.1 */ + USHORT TMDS_Info; /* Will be obsolete from R600 */ + USHORT AnalogTV_Info; /* Shared by various SW components,latest version 1.1 */ + USHORT SupportedDevicesInfo; /* Will be obsolete from R600 */ + USHORT GPIO_I2C_Info; /* Shared by various SW components,latest version 1.2 will be used from R600 */ + USHORT VRAM_UsageByFirmware; /* Shared by various SW components,latest version 1.3 will be used from R600 */ + USHORT GPIO_Pin_LUT; /* Shared by various SW components,latest version 1.1 */ + USHORT VESA_ToInternalModeLUT; /* Only used by Bios */ + USHORT ComponentVideoInfo; /* Shared by various SW components,latest version 2.1 will be used from R600 */ + USHORT PowerPlayInfo; /* Shared by various SW components,latest version 2.1,new design from R600 */ + USHORT CompassionateData; /* Will be obsolete from R600 */ + USHORT SaveRestoreInfo; /* Only used by Bios */ + USHORT PPLL_SS_Info; /* Shared by various SW components,latest version 1.2, used to call SS_Info, change to new name because of int ASIC SS info */ + USHORT OemInfo; /* Defined and used by external SW, should be obsolete soon */ + USHORT XTMDS_Info; /* Will be obsolete from R600 */ + USHORT MclkSS_Info; /* Shared by various SW components,latest version 1.1, only enabled when ext SS chip is used */ + USHORT Object_Header; /* Shared by various SW components,latest version 1.1 */ + USHORT IndirectIOAccess; /* Only used by Bios,this table position can't change at all!! */ + USHORT MC_InitParameter; /* Only used by command table */ + USHORT ASIC_VDDC_Info; /* Will be obsolete from R600 */ + USHORT ASIC_InternalSS_Info; /* New tabel name from R600, used to be called "ASIC_MVDDC_Info" */ + USHORT TV_VideoMode; /* Only used by command table */ + USHORT VRAM_Info; /* Only used by command table, latest version 1.3 */ + USHORT MemoryTrainingInfo; /* Used for VBIOS and Diag utility for memory training purpose since R600. the new table rev start from 2.1 */ + USHORT IntegratedSystemInfo; /* Shared by various SW components */ + USHORT ASIC_ProfilingInfo; /* New table name from R600, used to be called "ASIC_VDDCI_Info" for pre-R600 */ + USHORT VoltageObjectInfo; /* Shared by various SW components, latest version 1.1 */ + USHORT PowerSourceInfo; /* Shared by various SW components, latest versoin 1.1 */ +} ATOM_MASTER_LIST_OF_DATA_TABLES; + +#ifdef UEFI_BUILD +#define USHORT UTEMP +#endif + +typedef struct _ATOM_MASTER_DATA_TABLE { + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_MASTER_LIST_OF_DATA_TABLES ListOfDataTables; +} ATOM_MASTER_DATA_TABLE; + +/****************************************************************************/ +/* Structure used in MultimediaCapabilityInfoTable */ +/****************************************************************************/ +typedef struct _ATOM_MULTIMEDIA_CAPABILITY_INFO { + ATOM_COMMON_TABLE_HEADER sHeader; + ULONG ulSignature; /* HW info table signature string "$ATI" */ + UCHAR ucI2C_Type; /* I2C type (normal GP_IO, ImpactTV GP_IO, Dedicated I2C pin, etc) */ + UCHAR ucTV_OutInfo; /* Type of TV out supported (3:0) and video out crystal frequency (6:4) and TV data port (7) */ + UCHAR ucVideoPortInfo; /* Provides the video port capabilities */ + UCHAR ucHostPortInfo; /* Provides host port configuration information */ +} ATOM_MULTIMEDIA_CAPABILITY_INFO; + +/****************************************************************************/ +/* Structure used in MultimediaConfigInfoTable */ +/****************************************************************************/ +typedef struct _ATOM_MULTIMEDIA_CONFIG_INFO { + ATOM_COMMON_TABLE_HEADER sHeader; + ULONG ulSignature; /* MM info table signature sting "$MMT" */ + UCHAR ucTunerInfo; /* Type of tuner installed on the adapter (4:0) and video input for tuner (7:5) */ + UCHAR ucAudioChipInfo; /* List the audio chip type (3:0) product type (4) and OEM revision (7:5) */ + UCHAR ucProductID; /* Defines as OEM ID or ATI board ID dependent on product type setting */ + UCHAR ucMiscInfo1; /* Tuner voltage (1:0) HW teletext support (3:2) FM audio decoder (5:4) reserved (6) audio scrambling (7) */ + UCHAR ucMiscInfo2; /* I2S input config (0) I2S output config (1) I2S Audio Chip (4:2) SPDIF Output Config (5) reserved (7:6) */ + UCHAR ucMiscInfo3; /* Video Decoder Type (3:0) Video In Standard/Crystal (7:4) */ + UCHAR ucMiscInfo4; /* Video Decoder Host Config (2:0) reserved (7:3) */ + UCHAR ucVideoInput0Info; /* Video Input 0 Type (1:0) F/B setting (2) physical connector ID (5:3) reserved (7:6) */ + UCHAR ucVideoInput1Info; /* Video Input 1 Type (1:0) F/B setting (2) physical connector ID (5:3) reserved (7:6) */ + UCHAR ucVideoInput2Info; /* Video Input 2 Type (1:0) F/B setting (2) physical connector ID (5:3) reserved (7:6) */ + UCHAR ucVideoInput3Info; /* Video Input 3 Type (1:0) F/B setting (2) physical connector ID (5:3) reserved (7:6) */ + UCHAR ucVideoInput4Info; /* Video Input 4 Type (1:0) F/B setting (2) physical connector ID (5:3) reserved (7:6) */ +} ATOM_MULTIMEDIA_CONFIG_INFO; + +/****************************************************************************/ +/* Structures used in FirmwareInfoTable */ +/****************************************************************************/ + +/* usBIOSCapability Defintion: */ +/* Bit 0 = 0: Bios image is not Posted, =1:Bios image is Posted; */ +/* Bit 1 = 0: Dual CRTC is not supported, =1: Dual CRTC is supported; */ +/* Bit 2 = 0: Extended Desktop is not supported, =1: Extended Desktop is supported; */ +/* Others: Reserved */ +#define ATOM_BIOS_INFO_ATOM_FIRMWARE_POSTED 0x0001 +#define ATOM_BIOS_INFO_DUAL_CRTC_SUPPORT 0x0002 +#define ATOM_BIOS_INFO_EXTENDED_DESKTOP_SUPPORT 0x0004 +#define ATOM_BIOS_INFO_MEMORY_CLOCK_SS_SUPPORT 0x0008 +#define ATOM_BIOS_INFO_ENGINE_CLOCK_SS_SUPPORT 0x0010 +#define ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU 0x0020 +#define ATOM_BIOS_INFO_WMI_SUPPORT 0x0040 +#define ATOM_BIOS_INFO_PPMODE_ASSIGNGED_BY_SYSTEM 0x0080 +#define ATOM_BIOS_INFO_HYPERMEMORY_SUPPORT 0x0100 +#define ATOM_BIOS_INFO_HYPERMEMORY_SIZE_MASK 0x1E00 +#define ATOM_BIOS_INFO_VPOST_WITHOUT_FIRST_MODE_SET 0x2000 +#define ATOM_BIOS_INFO_BIOS_SCRATCH6_SCL2_REDEFINE 0x4000 + +#ifndef _H2INC + +/* Please don't add or expand this bitfield structure below, this one will retire soon.! */ +typedef struct _ATOM_FIRMWARE_CAPABILITY { +#if ATOM_BIG_ENDIAN + USHORT Reserved:3; + USHORT HyperMemory_Size:4; + USHORT HyperMemory_Support:1; + USHORT PPMode_Assigned:1; + USHORT WMI_SUPPORT:1; + USHORT GPUControlsBL:1; + USHORT EngineClockSS_Support:1; + USHORT MemoryClockSS_Support:1; + USHORT ExtendedDesktopSupport:1; + USHORT DualCRTC_Support:1; + USHORT FirmwarePosted:1; +#else + USHORT FirmwarePosted:1; + USHORT DualCRTC_Support:1; + USHORT ExtendedDesktopSupport:1; + USHORT MemoryClockSS_Support:1; + USHORT EngineClockSS_Support:1; + USHORT GPUControlsBL:1; + USHORT WMI_SUPPORT:1; + USHORT PPMode_Assigned:1; + USHORT HyperMemory_Support:1; + USHORT HyperMemory_Size:4; + USHORT Reserved:3; +#endif +} ATOM_FIRMWARE_CAPABILITY; + +typedef union _ATOM_FIRMWARE_CAPABILITY_ACCESS { + ATOM_FIRMWARE_CAPABILITY sbfAccess; + USHORT susAccess; +} ATOM_FIRMWARE_CAPABILITY_ACCESS; + +#else + +typedef union _ATOM_FIRMWARE_CAPABILITY_ACCESS { + USHORT susAccess; +} ATOM_FIRMWARE_CAPABILITY_ACCESS; + +#endif + +typedef struct _ATOM_FIRMWARE_INFO { + ATOM_COMMON_TABLE_HEADER sHeader; + ULONG ulFirmwareRevision; + ULONG ulDefaultEngineClock; /* In 10Khz unit */ + ULONG ulDefaultMemoryClock; /* In 10Khz unit */ + ULONG ulDriverTargetEngineClock; /* In 10Khz unit */ + ULONG ulDriverTargetMemoryClock; /* In 10Khz unit */ + ULONG ulMaxEngineClockPLL_Output; /* In 10Khz unit */ + ULONG ulMaxMemoryClockPLL_Output; /* In 10Khz unit */ + ULONG ulMaxPixelClockPLL_Output; /* In 10Khz unit */ + ULONG ulASICMaxEngineClock; /* In 10Khz unit */ + ULONG ulASICMaxMemoryClock; /* In 10Khz unit */ + UCHAR ucASICMaxTemperature; + UCHAR ucPadding[3]; /* Don't use them */ + ULONG aulReservedForBIOS[3]; /* Don't use them */ + USHORT usMinEngineClockPLL_Input; /* In 10Khz unit */ + USHORT usMaxEngineClockPLL_Input; /* In 10Khz unit */ + USHORT usMinEngineClockPLL_Output; /* In 10Khz unit */ + USHORT usMinMemoryClockPLL_Input; /* In 10Khz unit */ + USHORT usMaxMemoryClockPLL_Input; /* In 10Khz unit */ + USHORT usMinMemoryClockPLL_Output; /* In 10Khz unit */ + USHORT usMaxPixelClock; /* In 10Khz unit, Max. Pclk */ + USHORT usMinPixelClockPLL_Input; /* In 10Khz unit */ + USHORT usMaxPixelClockPLL_Input; /* In 10Khz unit */ + USHORT usMinPixelClockPLL_Output; /* In 10Khz unit, the definitions above can't change!!! */ + ATOM_FIRMWARE_CAPABILITY_ACCESS usFirmwareCapability; + USHORT usReferenceClock; /* In 10Khz unit */ + USHORT usPM_RTS_Location; /* RTS PM4 starting location in ROM in 1Kb unit */ + UCHAR ucPM_RTS_StreamSize; /* RTS PM4 packets in Kb unit */ + UCHAR ucDesign_ID; /* Indicate what is the board design */ + UCHAR ucMemoryModule_ID; /* Indicate what is the board design */ +} ATOM_FIRMWARE_INFO; + +typedef struct _ATOM_FIRMWARE_INFO_V1_2 { + ATOM_COMMON_TABLE_HEADER sHeader; + ULONG ulFirmwareRevision; + ULONG ulDefaultEngineClock; /* In 10Khz unit */ + ULONG ulDefaultMemoryClock; /* In 10Khz unit */ + ULONG ulDriverTargetEngineClock; /* In 10Khz unit */ + ULONG ulDriverTargetMemoryClock; /* In 10Khz unit */ + ULONG ulMaxEngineClockPLL_Output; /* In 10Khz unit */ + ULONG ulMaxMemoryClockPLL_Output; /* In 10Khz unit */ + ULONG ulMaxPixelClockPLL_Output; /* In 10Khz unit */ + ULONG ulASICMaxEngineClock; /* In 10Khz unit */ + ULONG ulASICMaxMemoryClock; /* In 10Khz unit */ + UCHAR ucASICMaxTemperature; + UCHAR ucMinAllowedBL_Level; + UCHAR ucPadding[2]; /* Don't use them */ + ULONG aulReservedForBIOS[2]; /* Don't use them */ + ULONG ulMinPixelClockPLL_Output; /* In 10Khz unit */ + USHORT usMinEngineClockPLL_Input; /* In 10Khz unit */ + USHORT usMaxEngineClockPLL_Input; /* In 10Khz unit */ + USHORT usMinEngineClockPLL_Output; /* In 10Khz unit */ + USHORT usMinMemoryClockPLL_Input; /* In 10Khz unit */ + USHORT usMaxMemoryClockPLL_Input; /* In 10Khz unit */ + USHORT usMinMemoryClockPLL_Output; /* In 10Khz unit */ + USHORT usMaxPixelClock; /* In 10Khz unit, Max. Pclk */ + USHORT usMinPixelClockPLL_Input; /* In 10Khz unit */ + USHORT usMaxPixelClockPLL_Input; /* In 10Khz unit */ + USHORT usMinPixelClockPLL_Output; /* In 10Khz unit - lower 16bit of ulMinPixelClockPLL_Output */ + ATOM_FIRMWARE_CAPABILITY_ACCESS usFirmwareCapability; + USHORT usReferenceClock; /* In 10Khz unit */ + USHORT usPM_RTS_Location; /* RTS PM4 starting location in ROM in 1Kb unit */ + UCHAR ucPM_RTS_StreamSize; /* RTS PM4 packets in Kb unit */ + UCHAR ucDesign_ID; /* Indicate what is the board design */ + UCHAR ucMemoryModule_ID; /* Indicate what is the board design */ +} ATOM_FIRMWARE_INFO_V1_2; + +typedef struct _ATOM_FIRMWARE_INFO_V1_3 { + ATOM_COMMON_TABLE_HEADER sHeader; + ULONG ulFirmwareRevision; + ULONG ulDefaultEngineClock; /* In 10Khz unit */ + ULONG ulDefaultMemoryClock; /* In 10Khz unit */ + ULONG ulDriverTargetEngineClock; /* In 10Khz unit */ + ULONG ulDriverTargetMemoryClock; /* In 10Khz unit */ + ULONG ulMaxEngineClockPLL_Output; /* In 10Khz unit */ + ULONG ulMaxMemoryClockPLL_Output; /* In 10Khz unit */ + ULONG ulMaxPixelClockPLL_Output; /* In 10Khz unit */ + ULONG ulASICMaxEngineClock; /* In 10Khz unit */ + ULONG ulASICMaxMemoryClock; /* In 10Khz unit */ + UCHAR ucASICMaxTemperature; + UCHAR ucMinAllowedBL_Level; + UCHAR ucPadding[2]; /* Don't use them */ + ULONG aulReservedForBIOS; /* Don't use them */ + ULONG ul3DAccelerationEngineClock; /* In 10Khz unit */ + ULONG ulMinPixelClockPLL_Output; /* In 10Khz unit */ + USHORT usMinEngineClockPLL_Input; /* In 10Khz unit */ + USHORT usMaxEngineClockPLL_Input; /* In 10Khz unit */ + USHORT usMinEngineClockPLL_Output; /* In 10Khz unit */ + USHORT usMinMemoryClockPLL_Input; /* In 10Khz unit */ + USHORT usMaxMemoryClockPLL_Input; /* In 10Khz unit */ + USHORT usMinMemoryClockPLL_Output; /* In 10Khz unit */ + USHORT usMaxPixelClock; /* In 10Khz unit, Max. Pclk */ + USHORT usMinPixelClockPLL_Input; /* In 10Khz unit */ + USHORT usMaxPixelClockPLL_Input; /* In 10Khz unit */ + USHORT usMinPixelClockPLL_Output; /* In 10Khz unit - lower 16bit of ulMinPixelClockPLL_Output */ + ATOM_FIRMWARE_CAPABILITY_ACCESS usFirmwareCapability; + USHORT usReferenceClock; /* In 10Khz unit */ + USHORT usPM_RTS_Location; /* RTS PM4 starting location in ROM in 1Kb unit */ + UCHAR ucPM_RTS_StreamSize; /* RTS PM4 packets in Kb unit */ + UCHAR ucDesign_ID; /* Indicate what is the board design */ + UCHAR ucMemoryModule_ID; /* Indicate what is the board design */ +} ATOM_FIRMWARE_INFO_V1_3; + +typedef struct _ATOM_FIRMWARE_INFO_V1_4 { + ATOM_COMMON_TABLE_HEADER sHeader; + ULONG ulFirmwareRevision; + ULONG ulDefaultEngineClock; /* In 10Khz unit */ + ULONG ulDefaultMemoryClock; /* In 10Khz unit */ + ULONG ulDriverTargetEngineClock; /* In 10Khz unit */ + ULONG ulDriverTargetMemoryClock; /* In 10Khz unit */ + ULONG ulMaxEngineClockPLL_Output; /* In 10Khz unit */ + ULONG ulMaxMemoryClockPLL_Output; /* In 10Khz unit */ + ULONG ulMaxPixelClockPLL_Output; /* In 10Khz unit */ + ULONG ulASICMaxEngineClock; /* In 10Khz unit */ + ULONG ulASICMaxMemoryClock; /* In 10Khz unit */ + UCHAR ucASICMaxTemperature; + UCHAR ucMinAllowedBL_Level; + USHORT usBootUpVDDCVoltage; /* In MV unit */ + USHORT usLcdMinPixelClockPLL_Output; /* In MHz unit */ + USHORT usLcdMaxPixelClockPLL_Output; /* In MHz unit */ + ULONG ul3DAccelerationEngineClock; /* In 10Khz unit */ + ULONG ulMinPixelClockPLL_Output; /* In 10Khz unit */ + USHORT usMinEngineClockPLL_Input; /* In 10Khz unit */ + USHORT usMaxEngineClockPLL_Input; /* In 10Khz unit */ + USHORT usMinEngineClockPLL_Output; /* In 10Khz unit */ + USHORT usMinMemoryClockPLL_Input; /* In 10Khz unit */ + USHORT usMaxMemoryClockPLL_Input; /* In 10Khz unit */ + USHORT usMinMemoryClockPLL_Output; /* In 10Khz unit */ + USHORT usMaxPixelClock; /* In 10Khz unit, Max. Pclk */ + USHORT usMinPixelClockPLL_Input; /* In 10Khz unit */ + USHORT usMaxPixelClockPLL_Input; /* In 10Khz unit */ + USHORT usMinPixelClockPLL_Output; /* In 10Khz unit - lower 16bit of ulMinPixelClockPLL_Output */ + ATOM_FIRMWARE_CAPABILITY_ACCESS usFirmwareCapability; + USHORT usReferenceClock; /* In 10Khz unit */ + USHORT usPM_RTS_Location; /* RTS PM4 starting location in ROM in 1Kb unit */ + UCHAR ucPM_RTS_StreamSize; /* RTS PM4 packets in Kb unit */ + UCHAR ucDesign_ID; /* Indicate what is the board design */ + UCHAR ucMemoryModule_ID; /* Indicate what is the board design */ +} ATOM_FIRMWARE_INFO_V1_4; + +#define ATOM_FIRMWARE_INFO_LAST ATOM_FIRMWARE_INFO_V1_4 + +/****************************************************************************/ +/* Structures used in IntegratedSystemInfoTable */ +/****************************************************************************/ +#define IGP_CAP_FLAG_DYNAMIC_CLOCK_EN 0x2 +#define IGP_CAP_FLAG_AC_CARD 0x4 +#define IGP_CAP_FLAG_SDVO_CARD 0x8 +#define IGP_CAP_FLAG_POSTDIV_BY_2_MODE 0x10 + +typedef struct _ATOM_INTEGRATED_SYSTEM_INFO { + ATOM_COMMON_TABLE_HEADER sHeader; + ULONG ulBootUpEngineClock; /* in 10kHz unit */ + ULONG ulBootUpMemoryClock; /* in 10kHz unit */ + ULONG ulMaxSystemMemoryClock; /* in 10kHz unit */ + ULONG ulMinSystemMemoryClock; /* in 10kHz unit */ + UCHAR ucNumberOfCyclesInPeriodHi; + UCHAR ucLCDTimingSel; /* =0:not valid.!=0 sel this timing descriptor from LCD EDID. */ + USHORT usReserved1; + USHORT usInterNBVoltageLow; /* An intermidiate PMW value to set the voltage */ + USHORT usInterNBVoltageHigh; /* Another intermidiate PMW value to set the voltage */ + ULONG ulReserved[2]; + + USHORT usFSBClock; /* In MHz unit */ + USHORT usCapabilityFlag; /* Bit0=1 indicates the fake HDMI support,Bit1=0/1 for Dynamic clocking dis/enable */ + /* Bit[3:2]== 0:No PCIE card, 1:AC card, 2:SDVO card */ + /* Bit[4]==1: P/2 mode, ==0: P/1 mode */ + USHORT usPCIENBCfgReg7; /* bit[7:0]=MUX_Sel, bit[9:8]=MUX_SEL_LEVEL2, bit[10]=Lane_Reversal */ + USHORT usK8MemoryClock; /* in MHz unit */ + USHORT usK8SyncStartDelay; /* in 0.01 us unit */ + USHORT usK8DataReturnTime; /* in 0.01 us unit */ + UCHAR ucMaxNBVoltage; + UCHAR ucMinNBVoltage; + UCHAR ucMemoryType; /* [7:4]=1:DDR1;=2:DDR2;=3:DDR3.[3:0] is reserved */ + UCHAR ucNumberOfCyclesInPeriod; /* CG.FVTHROT_PWM_CTRL_REG0.NumberOfCyclesInPeriod */ + UCHAR ucStartingPWM_HighTime; /* CG.FVTHROT_PWM_CTRL_REG0.StartingPWM_HighTime */ + UCHAR ucHTLinkWidth; /* 16 bit vs. 8 bit */ + UCHAR ucMaxNBVoltageHigh; + UCHAR ucMinNBVoltageHigh; +} ATOM_INTEGRATED_SYSTEM_INFO; + +/* Explanation on entries in ATOM_INTEGRATED_SYSTEM_INFO +ulBootUpMemoryClock: For Intel IGP,it's the UMA system memory clock + For AMD IGP,it's 0 if no SidePort memory installed or it's the boot-up SidePort memory clock +ulMaxSystemMemoryClock: For Intel IGP,it's the Max freq from memory SPD if memory runs in ASYNC mode or otherwise (SYNC mode) it's 0 + For AMD IGP,for now this can be 0 +ulMinSystemMemoryClock: For Intel IGP,it's 133MHz if memory runs in ASYNC mode or otherwise (SYNC mode) it's 0 + For AMD IGP,for now this can be 0 + +usFSBClock: For Intel IGP,it's FSB Freq + For AMD IGP,it's HT Link Speed + +usK8MemoryClock: For AMD IGP only. For RevF CPU, set it to 200 +usK8SyncStartDelay: For AMD IGP only. Memory access latency in K8, required for watermark calculation +usK8DataReturnTime: For AMD IGP only. Memory access latency in K8, required for watermark calculation + +VC:Voltage Control +ucMaxNBVoltage: Voltage regulator dependent PWM value. Low 8 bits of the value for the max voltage.Set this one to 0xFF if VC without PWM. Set this to 0x0 if no VC at all. +ucMinNBVoltage: Voltage regulator dependent PWM value. Low 8 bits of the value for the min voltage.Set this one to 0x00 if VC without PWM or no VC at all. + +ucNumberOfCyclesInPeriod: Indicate how many cycles when PWM duty is 100%. low 8 bits of the value. +ucNumberOfCyclesInPeriodHi: Indicate how many cycles when PWM duty is 100%. high 8 bits of the value.If the PWM has an inverter,set bit [7]==1,otherwise set it 0 + +ucMaxNBVoltageHigh: Voltage regulator dependent PWM value. High 8 bits of the value for the max voltage.Set this one to 0xFF if VC without PWM. Set this to 0x0 if no VC at all. +ucMinNBVoltageHigh: Voltage regulator dependent PWM value. High 8 bits of the value for the min voltage.Set this one to 0x00 if VC without PWM or no VC at all. + +usInterNBVoltageLow: Voltage regulator dependent PWM value. The value makes the the voltage >=Min NB voltage but <=InterNBVoltageHigh. Set this to 0x0000 if VC without PWM or no VC at all. +usInterNBVoltageHigh: Voltage regulator dependent PWM value. The value makes the the voltage >=InterNBVoltageLow but <=Max NB voltage.Set this to 0x0000 if VC without PWM or no VC at all. +*/ + +/* +The following IGP table is introduced from RS780, which is supposed to be put by SBIOS in FB before IGP VBIOS starts VPOST; +Then VBIOS will copy the whole structure to its image so all GPU SW components can access this data structure to get whatever they need. +The enough reservation should allow us to never change table revisions. Whenever needed, a GPU SW component can use reserved portion for new data entries. + +SW components can access the IGP system infor structure in the same way as before +*/ + +typedef struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 { + ATOM_COMMON_TABLE_HEADER sHeader; + ULONG ulBootUpEngineClock; /* in 10kHz unit */ + ULONG ulReserved1[2]; /* must be 0x0 for the reserved */ + ULONG ulBootUpUMAClock; /* in 10kHz unit */ + ULONG ulBootUpSidePortClock; /* in 10kHz unit */ + ULONG ulMinSidePortClock; /* in 10kHz unit */ + ULONG ulReserved2[6]; /* must be 0x0 for the reserved */ + ULONG ulSystemConfig; /* see explanation below */ + ULONG ulBootUpReqDisplayVector; + ULONG ulOtherDisplayMisc; + ULONG ulDDISlot1Config; + ULONG ulDDISlot2Config; + UCHAR ucMemoryType; /* [3:0]=1:DDR1;=2:DDR2;=3:DDR3.[7:4] is reserved */ + UCHAR ucUMAChannelNumber; + UCHAR ucDockingPinBit; + UCHAR ucDockingPinPolarity; + ULONG ulDockingPinCFGInfo; + ULONG ulCPUCapInfo; + USHORT usNumberOfCyclesInPeriod; + USHORT usMaxNBVoltage; + USHORT usMinNBVoltage; + USHORT usBootUpNBVoltage; + ULONG ulHTLinkFreq; /* in 10Khz */ + USHORT usMinHTLinkWidth; + USHORT usMaxHTLinkWidth; + USHORT usUMASyncStartDelay; + USHORT usUMADataReturnTime; + USHORT usLinkStatusZeroTime; + USHORT usReserved; + ULONG ulHighVoltageHTLinkFreq; /* in 10Khz */ + ULONG ulLowVoltageHTLinkFreq; /* in 10Khz */ + USHORT usMaxUpStreamHTLinkWidth; + USHORT usMaxDownStreamHTLinkWidth; + USHORT usMinUpStreamHTLinkWidth; + USHORT usMinDownStreamHTLinkWidth; + ULONG ulReserved3[97]; /* must be 0x0 */ +} ATOM_INTEGRATED_SYSTEM_INFO_V2; + +/* +ulBootUpEngineClock: Boot-up Engine Clock in 10Khz; +ulBootUpUMAClock: Boot-up UMA Clock in 10Khz; it must be 0x0 when UMA is not present +ulBootUpSidePortClock: Boot-up SidePort Clock in 10Khz; it must be 0x0 when SidePort Memory is not present,this could be equal to or less than maximum supported Sideport memory clock + +ulSystemConfig: +Bit[0]=1: PowerExpress mode =0 Non-PowerExpress mode; +Bit[1]=1: system boots up at AMD overdrived state or user customized mode. In this case, driver will just stick to this boot-up mode. No other PowerPlay state + =0: system boots up at driver control state. Power state depends on PowerPlay table. +Bit[2]=1: PWM method is used on NB voltage control. =0: GPIO method is used. +Bit[3]=1: Only one power state(Performance) will be supported. + =0: Multiple power states supported from PowerPlay table. +Bit[4]=1: CLMC is supported and enabled on current system. + =0: CLMC is not supported or enabled on current system. SBIOS need to support HT link/freq change through ATIF interface. +Bit[5]=1: Enable CDLW for all driver control power states. Max HT width is from SBIOS, while Min HT width is determined by display requirement. + =0: CDLW is disabled. If CLMC is enabled case, Min HT width will be set equal to Max HT width. If CLMC disabled case, Max HT width will be applied. +Bit[6]=1: High Voltage requested for all power states. In this case, voltage will be forced at 1.1v and powerplay table voltage drop/throttling request will be ignored. + =0: Voltage settings is determined by powerplay table. +Bit[7]=1: Enable CLMC as hybrid Mode. CDLD and CILR will be disabled in this case and we're using legacy C1E. This is workaround for CPU(Griffin) performance issue. + =0: Enable CLMC as regular mode, CDLD and CILR will be enabled. + +ulBootUpReqDisplayVector: This dword is a bit vector indicates what display devices are requested during boot-up. Refer to ATOM_DEVICE_xxx_SUPPORT for the bit vector definitions. + +ulOtherDisplayMisc: [15:8]- Bootup LCD Expansion selection; 0-center, 1-full panel size expansion; + [7:0] - BootupTV standard selection; This is a bit vector to indicate what TV standards are supported by the system. Refer to ucTVSuppportedStd definition; + +ulDDISlot1Config: Describes the PCIE lane configuration on this DDI PCIE slot (ADD2 card) or connector (Mobile design). + [3:0] - Bit vector to indicate PCIE lane config of the DDI slot/connector on chassis (bit 0=1 lane 3:0; bit 1=1 lane 7:4; bit 2=1 lane 11:8; bit 3=1 lane 15:12) + [7:4] - Bit vector to indicate PCIE lane config of the same DDI slot/connector on docking station (bit 0=1 lane 3:0; bit 1=1 lane 7:4; bit 2=1 lane 11:8; bit 3=1 lane 15:12) + [15:8] - Lane configuration attribute; + [23:16]- Connector type, possible value: + CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D + CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D + CONNECTOR_OBJECT_ID_HDMI_TYPE_A + CONNECTOR_OBJECT_ID_DISPLAYPORT + [31:24]- Reserved + +ulDDISlot2Config: Same as Slot1. +ucMemoryType: SidePort memory type, set it to 0x0 when Sideport memory is not installed. Driver needs this info to change sideport memory clock. Not for display in CCC. +For IGP, Hypermemory is the only memory type showed in CCC. + +ucUMAChannelNumber: how many channels for the UMA; + +ulDockingPinCFGInfo: [15:0]-Bus/Device/Function # to CFG to read this Docking Pin; [31:16]-reg offset in CFG to read this pin +ucDockingPinBit: which bit in this register to read the pin status; +ucDockingPinPolarity:Polarity of the pin when docked; + +ulCPUCapInfo: [7:0]=1:Griffin;[7:0]=2:Greyhound;[7:0]=3:K8, other bits reserved for now and must be 0x0 + +usNumberOfCyclesInPeriod:Indicate how many cycles when PWM duty is 100%. +usMaxNBVoltage:Max. voltage control value in either PWM or GPIO mode. +usMinNBVoltage:Min. voltage control value in either PWM or GPIO mode. + GPIO mode: both usMaxNBVoltage & usMinNBVoltage have a valid value ulSystemConfig.SYSTEM_CONFIG_USE_PWM_ON_VOLTAGE=0 + PWM mode: both usMaxNBVoltage & usMinNBVoltage have a valid value ulSystemConfig.SYSTEM_CONFIG_USE_PWM_ON_VOLTAGE=1 + GPU SW don't control mode: usMaxNBVoltage & usMinNBVoltage=0 and no care about ulSystemConfig.SYSTEM_CONFIG_USE_PWM_ON_VOLTAGE +usBootUpNBVoltage:Boot-up voltage regulator dependent PWM value. + +ulHTLinkFreq: Bootup HT link Frequency in 10Khz. +usMinHTLinkWidth: Bootup minimum HT link width. If CDLW disabled, this is equal to usMaxHTLinkWidth. + If CDLW enabled, both upstream and downstream width should be the same during bootup. +usMaxHTLinkWidth: Bootup maximum HT link width. If CDLW disabled, this is equal to usMinHTLinkWidth. + If CDLW enabled, both upstream and downstream width should be the same during bootup. + +usUMASyncStartDelay: Memory access latency, required for watermark calculation +usUMADataReturnTime: Memory access latency, required for watermark calculation +usLinkStatusZeroTime:Memory access latency required for watermark calculation, set this to 0x0 for K8 CPU, set a proper value in 0.01 the unit of us +for Griffin or Greyhound. SBIOS needs to convert to actual time by: + if T0Ttime [5:4]=00b, then usLinkStatusZeroTime=T0Ttime [3:0]*0.1us (0.0 to 1.5us) + if T0Ttime [5:4]=01b, then usLinkStatusZeroTime=T0Ttime [3:0]*0.5us (0.0 to 7.5us) + if T0Ttime [5:4]=10b, then usLinkStatusZeroTime=T0Ttime [3:0]*2.0us (0.0 to 30us) + if T0Ttime [5:4]=11b, and T0Ttime [3:0]=0x0 to 0xa, then usLinkStatusZeroTime=T0Ttime [3:0]*20us (0.0 to 200us) + +ulHighVoltageHTLinkFreq: HT link frequency for power state with low voltage. If boot up runs in HT1, this must be 0. + This must be less than or equal to ulHTLinkFreq(bootup frequency). +ulLowVoltageHTLinkFreq: HT link frequency for power state with low voltage or voltage scaling 1.0v~1.1v. If boot up runs in HT1, this must be 0. + This must be less than or equal to ulHighVoltageHTLinkFreq. + +usMaxUpStreamHTLinkWidth: Asymmetric link width support in the future, to replace usMaxHTLinkWidth. Not used for now. +usMaxDownStreamHTLinkWidth: same as above. +usMinUpStreamHTLinkWidth: Asymmetric link width support in the future, to replace usMinHTLinkWidth. Not used for now. +usMinDownStreamHTLinkWidth: same as above. +*/ + +#define SYSTEM_CONFIG_POWEREXPRESS_ENABLE 0x00000001 +#define SYSTEM_CONFIG_RUN_AT_OVERDRIVE_ENGINE 0x00000002 +#define SYSTEM_CONFIG_USE_PWM_ON_VOLTAGE 0x00000004 +#define SYSTEM_CONFIG_PERFORMANCE_POWERSTATE_ONLY 0x00000008 +#define SYSTEM_CONFIG_CLMC_ENABLED 0x00000010 +#define SYSTEM_CONFIG_CDLW_ENABLED 0x00000020 +#define SYSTEM_CONFIG_HIGH_VOLTAGE_REQUESTED 0x00000040 +#define SYSTEM_CONFIG_CLMC_HYBRID_MODE_ENABLED 0x00000080 + +#define IGP_DDI_SLOT_LANE_CONFIG_MASK 0x000000FF + +#define b0IGP_DDI_SLOT_LANE_MAP_MASK 0x0F +#define b0IGP_DDI_SLOT_DOCKING_LANE_MAP_MASK 0xF0 +#define b0IGP_DDI_SLOT_CONFIG_LANE_0_3 0x01 +#define b0IGP_DDI_SLOT_CONFIG_LANE_4_7 0x02 +#define b0IGP_DDI_SLOT_CONFIG_LANE_8_11 0x04 +#define b0IGP_DDI_SLOT_CONFIG_LANE_12_15 0x08 + +#define IGP_DDI_SLOT_ATTRIBUTE_MASK 0x0000FF00 +#define IGP_DDI_SLOT_CONFIG_REVERSED 0x00000100 +#define b1IGP_DDI_SLOT_CONFIG_REVERSED 0x01 + +#define IGP_DDI_SLOT_CONNECTOR_TYPE_MASK 0x00FF0000 + +#define ATOM_CRT_INT_ENCODER1_INDEX 0x00000000 +#define ATOM_LCD_INT_ENCODER1_INDEX 0x00000001 +#define ATOM_TV_INT_ENCODER1_INDEX 0x00000002 +#define ATOM_DFP_INT_ENCODER1_INDEX 0x00000003 +#define ATOM_CRT_INT_ENCODER2_INDEX 0x00000004 +#define ATOM_LCD_EXT_ENCODER1_INDEX 0x00000005 +#define ATOM_TV_EXT_ENCODER1_INDEX 0x00000006 +#define ATOM_DFP_EXT_ENCODER1_INDEX 0x00000007 +#define ATOM_CV_INT_ENCODER1_INDEX 0x00000008 +#define ATOM_DFP_INT_ENCODER2_INDEX 0x00000009 +#define ATOM_CRT_EXT_ENCODER1_INDEX 0x0000000A +#define ATOM_CV_EXT_ENCODER1_INDEX 0x0000000B +#define ATOM_DFP_INT_ENCODER3_INDEX 0x0000000C +#define ATOM_DFP_INT_ENCODER4_INDEX 0x0000000D + +/* define ASIC internal encoder id ( bit vector ) */ +#define ASIC_INT_DAC1_ENCODER_ID 0x00 +#define ASIC_INT_TV_ENCODER_ID 0x02 +#define ASIC_INT_DIG1_ENCODER_ID 0x03 +#define ASIC_INT_DAC2_ENCODER_ID 0x04 +#define ASIC_EXT_TV_ENCODER_ID 0x06 +#define ASIC_INT_DVO_ENCODER_ID 0x07 +#define ASIC_INT_DIG2_ENCODER_ID 0x09 +#define ASIC_EXT_DIG_ENCODER_ID 0x05 + +/* define Encoder attribute */ +#define ATOM_ANALOG_ENCODER 0 +#define ATOM_DIGITAL_ENCODER 1 + +#define ATOM_DEVICE_CRT1_INDEX 0x00000000 +#define ATOM_DEVICE_LCD1_INDEX 0x00000001 +#define ATOM_DEVICE_TV1_INDEX 0x00000002 +#define ATOM_DEVICE_DFP1_INDEX 0x00000003 +#define ATOM_DEVICE_CRT2_INDEX 0x00000004 +#define ATOM_DEVICE_LCD2_INDEX 0x00000005 +#define ATOM_DEVICE_TV2_INDEX 0x00000006 +#define ATOM_DEVICE_DFP2_INDEX 0x00000007 +#define ATOM_DEVICE_CV_INDEX 0x00000008 +#define ATOM_DEVICE_DFP3_INDEX 0x00000009 +#define ATOM_DEVICE_DFP4_INDEX 0x0000000A +#define ATOM_DEVICE_DFP5_INDEX 0x0000000B +#define ATOM_DEVICE_RESERVEDC_INDEX 0x0000000C +#define ATOM_DEVICE_RESERVEDD_INDEX 0x0000000D +#define ATOM_DEVICE_RESERVEDE_INDEX 0x0000000E +#define ATOM_DEVICE_RESERVEDF_INDEX 0x0000000F +#define ATOM_MAX_SUPPORTED_DEVICE_INFO (ATOM_DEVICE_DFP3_INDEX+1) +#define ATOM_MAX_SUPPORTED_DEVICE_INFO_2 ATOM_MAX_SUPPORTED_DEVICE_INFO +#define ATOM_MAX_SUPPORTED_DEVICE_INFO_3 (ATOM_DEVICE_DFP5_INDEX + 1) + +#define ATOM_MAX_SUPPORTED_DEVICE (ATOM_DEVICE_RESERVEDF_INDEX+1) + +#define ATOM_DEVICE_CRT1_SUPPORT (0x1L << ATOM_DEVICE_CRT1_INDEX) +#define ATOM_DEVICE_LCD1_SUPPORT (0x1L << ATOM_DEVICE_LCD1_INDEX) +#define ATOM_DEVICE_TV1_SUPPORT (0x1L << ATOM_DEVICE_TV1_INDEX) +#define ATOM_DEVICE_DFP1_SUPPORT (0x1L << ATOM_DEVICE_DFP1_INDEX) +#define ATOM_DEVICE_CRT2_SUPPORT (0x1L << ATOM_DEVICE_CRT2_INDEX) +#define ATOM_DEVICE_LCD2_SUPPORT (0x1L << ATOM_DEVICE_LCD2_INDEX) +#define ATOM_DEVICE_TV2_SUPPORT (0x1L << ATOM_DEVICE_TV2_INDEX) +#define ATOM_DEVICE_DFP2_SUPPORT (0x1L << ATOM_DEVICE_DFP2_INDEX) +#define ATOM_DEVICE_CV_SUPPORT (0x1L << ATOM_DEVICE_CV_INDEX) +#define ATOM_DEVICE_DFP3_SUPPORT (0x1L << ATOM_DEVICE_DFP3_INDEX) +#define ATOM_DEVICE_DFP4_SUPPORT (0x1L << ATOM_DEVICE_DFP4_INDEX ) +#define ATOM_DEVICE_DFP5_SUPPORT (0x1L << ATOM_DEVICE_DFP5_INDEX) + +#define ATOM_DEVICE_CRT_SUPPORT \ + (ATOM_DEVICE_CRT1_SUPPORT | ATOM_DEVICE_CRT2_SUPPORT) +#define ATOM_DEVICE_DFP_SUPPORT \ + (ATOM_DEVICE_DFP1_SUPPORT | ATOM_DEVICE_DFP2_SUPPORT | \ + ATOM_DEVICE_DFP3_SUPPORT | ATOM_DEVICE_DFP4_SUPPORT | \ + ATOM_DEVICE_DFP5_SUPPORT) +#define ATOM_DEVICE_TV_SUPPORT \ + (ATOM_DEVICE_TV1_SUPPORT | ATOM_DEVICE_TV2_SUPPORT) +#define ATOM_DEVICE_LCD_SUPPORT \ + (ATOM_DEVICE_LCD1_SUPPORT | ATOM_DEVICE_LCD2_SUPPORT) + +#define ATOM_DEVICE_CONNECTOR_TYPE_MASK 0x000000F0 +#define ATOM_DEVICE_CONNECTOR_TYPE_SHIFT 0x00000004 +#define ATOM_DEVICE_CONNECTOR_VGA 0x00000001 +#define ATOM_DEVICE_CONNECTOR_DVI_I 0x00000002 +#define ATOM_DEVICE_CONNECTOR_DVI_D 0x00000003 +#define ATOM_DEVICE_CONNECTOR_DVI_A 0x00000004 +#define ATOM_DEVICE_CONNECTOR_SVIDEO 0x00000005 +#define ATOM_DEVICE_CONNECTOR_COMPOSITE 0x00000006 +#define ATOM_DEVICE_CONNECTOR_LVDS 0x00000007 +#define ATOM_DEVICE_CONNECTOR_DIGI_LINK 0x00000008 +#define ATOM_DEVICE_CONNECTOR_SCART 0x00000009 +#define ATOM_DEVICE_CONNECTOR_HDMI_TYPE_A 0x0000000A +#define ATOM_DEVICE_CONNECTOR_HDMI_TYPE_B 0x0000000B +#define ATOM_DEVICE_CONNECTOR_CASE_1 0x0000000E +#define ATOM_DEVICE_CONNECTOR_DISPLAYPORT 0x0000000F + +#define ATOM_DEVICE_DAC_INFO_MASK 0x0000000F +#define ATOM_DEVICE_DAC_INFO_SHIFT 0x00000000 +#define ATOM_DEVICE_DAC_INFO_NODAC 0x00000000 +#define ATOM_DEVICE_DAC_INFO_DACA 0x00000001 +#define ATOM_DEVICE_DAC_INFO_DACB 0x00000002 +#define ATOM_DEVICE_DAC_INFO_EXDAC 0x00000003 + +#define ATOM_DEVICE_I2C_ID_NOI2C 0x00000000 + +#define ATOM_DEVICE_I2C_LINEMUX_MASK 0x0000000F +#define ATOM_DEVICE_I2C_LINEMUX_SHIFT 0x00000000 + +#define ATOM_DEVICE_I2C_ID_MASK 0x00000070 +#define ATOM_DEVICE_I2C_ID_SHIFT 0x00000004 +#define ATOM_DEVICE_I2C_ID_IS_FOR_NON_MM_USE 0x00000001 +#define ATOM_DEVICE_I2C_ID_IS_FOR_MM_USE 0x00000002 +#define ATOM_DEVICE_I2C_ID_IS_FOR_SDVO_USE 0x00000003 /* For IGP RS600 */ +#define ATOM_DEVICE_I2C_ID_IS_FOR_DAC_SCL 0x00000004 /* For IGP RS690 */ + +#define ATOM_DEVICE_I2C_HARDWARE_CAP_MASK 0x00000080 +#define ATOM_DEVICE_I2C_HARDWARE_CAP_SHIFT 0x00000007 +#define ATOM_DEVICE_USES_SOFTWARE_ASSISTED_I2C 0x00000000 +#define ATOM_DEVICE_USES_HARDWARE_ASSISTED_I2C 0x00000001 + +/* usDeviceSupport: */ +/* Bits0 = 0 - no CRT1 support= 1- CRT1 is supported */ +/* Bit 1 = 0 - no LCD1 support= 1- LCD1 is supported */ +/* Bit 2 = 0 - no TV1 support= 1- TV1 is supported */ +/* Bit 3 = 0 - no DFP1 support= 1- DFP1 is supported */ +/* Bit 4 = 0 - no CRT2 support= 1- CRT2 is supported */ +/* Bit 5 = 0 - no LCD2 support= 1- LCD2 is supported */ +/* Bit 6 = 0 - no TV2 support= 1- TV2 is supported */ +/* Bit 7 = 0 - no DFP2 support= 1- DFP2 is supported */ +/* Bit 8 = 0 - no CV support= 1- CV is supported */ +/* Bit 9 = 0 - no DFP3 support= 1- DFP3 is supported */ +/* Byte1 (Supported Device Info) */ +/* Bit 0 = = 0 - no CV support= 1- CV is supported */ +/* */ +/* */ + +/* ucI2C_ConfigID */ +/* [7:0] - I2C LINE Associate ID */ +/* = 0 - no I2C */ +/* [7] - HW_Cap = 1, [6:0]=HW assisted I2C ID(HW line selection) */ +/* = 0, [6:0]=SW assisted I2C ID */ +/* [6-4] - HW_ENGINE_ID = 1, HW engine for NON multimedia use */ +/* = 2, HW engine for Multimedia use */ +/* = 3-7 Reserved for future I2C engines */ +/* [3-0] - I2C_LINE_MUX = A Mux number when it's HW assisted I2C or GPIO ID when it's SW I2C */ + +typedef struct _ATOM_I2C_ID_CONFIG { +#if ATOM_BIG_ENDIAN + UCHAR bfHW_Capable:1; + UCHAR bfHW_EngineID:3; + UCHAR bfI2C_LineMux:4; +#else + UCHAR bfI2C_LineMux:4; + UCHAR bfHW_EngineID:3; + UCHAR bfHW_Capable:1; +#endif +} ATOM_I2C_ID_CONFIG; + +typedef union _ATOM_I2C_ID_CONFIG_ACCESS { + ATOM_I2C_ID_CONFIG sbfAccess; + UCHAR ucAccess; +} ATOM_I2C_ID_CONFIG_ACCESS; + +/****************************************************************************/ +/* Structure used in GPIO_I2C_InfoTable */ +/****************************************************************************/ +typedef struct _ATOM_GPIO_I2C_ASSIGMENT { + USHORT usClkMaskRegisterIndex; + USHORT usClkEnRegisterIndex; + USHORT usClkY_RegisterIndex; + USHORT usClkA_RegisterIndex; + USHORT usDataMaskRegisterIndex; + USHORT usDataEnRegisterIndex; + USHORT usDataY_RegisterIndex; + USHORT usDataA_RegisterIndex; + ATOM_I2C_ID_CONFIG_ACCESS sucI2cId; + UCHAR ucClkMaskShift; + UCHAR ucClkEnShift; + UCHAR ucClkY_Shift; + UCHAR ucClkA_Shift; + UCHAR ucDataMaskShift; + UCHAR ucDataEnShift; + UCHAR ucDataY_Shift; + UCHAR ucDataA_Shift; + UCHAR ucReserved1; + UCHAR ucReserved2; +} ATOM_GPIO_I2C_ASSIGMENT; + +typedef struct _ATOM_GPIO_I2C_INFO { + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_GPIO_I2C_ASSIGMENT asGPIO_Info[ATOM_MAX_SUPPORTED_DEVICE]; +} ATOM_GPIO_I2C_INFO; + +/****************************************************************************/ +/* Common Structure used in other structures */ +/****************************************************************************/ + +#ifndef _H2INC + +/* Please don't add or expand this bitfield structure below, this one will retire soon.! */ +typedef struct _ATOM_MODE_MISC_INFO { +#if ATOM_BIG_ENDIAN + USHORT Reserved:6; + USHORT RGB888:1; + USHORT DoubleClock:1; + USHORT Interlace:1; + USHORT CompositeSync:1; + USHORT V_ReplicationBy2:1; + USHORT H_ReplicationBy2:1; + USHORT VerticalCutOff:1; + USHORT VSyncPolarity:1; /* 0=Active High, 1=Active Low */ + USHORT HSyncPolarity:1; /* 0=Active High, 1=Active Low */ + USHORT HorizontalCutOff:1; +#else + USHORT HorizontalCutOff:1; + USHORT HSyncPolarity:1; /* 0=Active High, 1=Active Low */ + USHORT VSyncPolarity:1; /* 0=Active High, 1=Active Low */ + USHORT VerticalCutOff:1; + USHORT H_ReplicationBy2:1; + USHORT V_ReplicationBy2:1; + USHORT CompositeSync:1; + USHORT Interlace:1; + USHORT DoubleClock:1; + USHORT RGB888:1; + USHORT Reserved:6; +#endif +} ATOM_MODE_MISC_INFO; + +typedef union _ATOM_MODE_MISC_INFO_ACCESS { + ATOM_MODE_MISC_INFO sbfAccess; + USHORT usAccess; +} ATOM_MODE_MISC_INFO_ACCESS; + +#else + +typedef union _ATOM_MODE_MISC_INFO_ACCESS { + USHORT usAccess; +} ATOM_MODE_MISC_INFO_ACCESS; + +#endif + +/* usModeMiscInfo- */ +#define ATOM_H_CUTOFF 0x01 +#define ATOM_HSYNC_POLARITY 0x02 /* 0=Active High, 1=Active Low */ +#define ATOM_VSYNC_POLARITY 0x04 /* 0=Active High, 1=Active Low */ +#define ATOM_V_CUTOFF 0x08 +#define ATOM_H_REPLICATIONBY2 0x10 +#define ATOM_V_REPLICATIONBY2 0x20 +#define ATOM_COMPOSITESYNC 0x40 +#define ATOM_INTERLACE 0x80 +#define ATOM_DOUBLE_CLOCK_MODE 0x100 +#define ATOM_RGB888_MODE 0x200 + +/* usRefreshRate- */ +#define ATOM_REFRESH_43 43 +#define ATOM_REFRESH_47 47 +#define ATOM_REFRESH_56 56 +#define ATOM_REFRESH_60 60 +#define ATOM_REFRESH_65 65 +#define ATOM_REFRESH_70 70 +#define ATOM_REFRESH_72 72 +#define ATOM_REFRESH_75 75 +#define ATOM_REFRESH_85 85 + +/* ATOM_MODE_TIMING data are exactly the same as VESA timing data. */ +/* Translation from EDID to ATOM_MODE_TIMING, use the following formula. */ +/* */ +/* VESA_HTOTAL = VESA_ACTIVE + 2* VESA_BORDER + VESA_BLANK */ +/* = EDID_HA + EDID_HBL */ +/* VESA_HDISP = VESA_ACTIVE = EDID_HA */ +/* VESA_HSYNC_START = VESA_ACTIVE + VESA_BORDER + VESA_FRONT_PORCH */ +/* = EDID_HA + EDID_HSO */ +/* VESA_HSYNC_WIDTH = VESA_HSYNC_TIME = EDID_HSPW */ +/* VESA_BORDER = EDID_BORDER */ + +/****************************************************************************/ +/* Structure used in SetCRTC_UsingDTDTimingTable */ +/****************************************************************************/ +typedef struct _SET_CRTC_USING_DTD_TIMING_PARAMETERS { + USHORT usH_Size; + USHORT usH_Blanking_Time; + USHORT usV_Size; + USHORT usV_Blanking_Time; + USHORT usH_SyncOffset; + USHORT usH_SyncWidth; + USHORT usV_SyncOffset; + USHORT usV_SyncWidth; + ATOM_MODE_MISC_INFO_ACCESS susModeMiscInfo; + UCHAR ucH_Border; /* From DFP EDID */ + UCHAR ucV_Border; + UCHAR ucCRTC; /* ATOM_CRTC1 or ATOM_CRTC2 */ + UCHAR ucPadding[3]; +} SET_CRTC_USING_DTD_TIMING_PARAMETERS; + +/****************************************************************************/ +/* Structure used in SetCRTC_TimingTable */ +/****************************************************************************/ +typedef struct _SET_CRTC_TIMING_PARAMETERS { + USHORT usH_Total; /* horizontal total */ + USHORT usH_Disp; /* horizontal display */ + USHORT usH_SyncStart; /* horozontal Sync start */ + USHORT usH_SyncWidth; /* horizontal Sync width */ + USHORT usV_Total; /* vertical total */ + USHORT usV_Disp; /* vertical display */ + USHORT usV_SyncStart; /* vertical Sync start */ + USHORT usV_SyncWidth; /* vertical Sync width */ + ATOM_MODE_MISC_INFO_ACCESS susModeMiscInfo; + UCHAR ucCRTC; /* ATOM_CRTC1 or ATOM_CRTC2 */ + UCHAR ucOverscanRight; /* right */ + UCHAR ucOverscanLeft; /* left */ + UCHAR ucOverscanBottom; /* bottom */ + UCHAR ucOverscanTop; /* top */ + UCHAR ucReserved; +} SET_CRTC_TIMING_PARAMETERS; +#define SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION SET_CRTC_TIMING_PARAMETERS + +/****************************************************************************/ +/* Structure used in StandardVESA_TimingTable */ +/* AnalogTV_InfoTable */ +/* ComponentVideoInfoTable */ +/****************************************************************************/ +typedef struct _ATOM_MODE_TIMING { + USHORT usCRTC_H_Total; + USHORT usCRTC_H_Disp; + USHORT usCRTC_H_SyncStart; + USHORT usCRTC_H_SyncWidth; + USHORT usCRTC_V_Total; + USHORT usCRTC_V_Disp; + USHORT usCRTC_V_SyncStart; + USHORT usCRTC_V_SyncWidth; + USHORT usPixelClock; /* in 10Khz unit */ + ATOM_MODE_MISC_INFO_ACCESS susModeMiscInfo; + USHORT usCRTC_OverscanRight; + USHORT usCRTC_OverscanLeft; + USHORT usCRTC_OverscanBottom; + USHORT usCRTC_OverscanTop; + USHORT usReserve; + UCHAR ucInternalModeNumber; + UCHAR ucRefreshRate; +} ATOM_MODE_TIMING; + +typedef struct _ATOM_DTD_FORMAT { + USHORT usPixClk; + USHORT usHActive; + USHORT usHBlanking_Time; + USHORT usVActive; + USHORT usVBlanking_Time; + USHORT usHSyncOffset; + USHORT usHSyncWidth; + USHORT usVSyncOffset; + USHORT usVSyncWidth; + USHORT usImageHSize; + USHORT usImageVSize; + UCHAR ucHBorder; + UCHAR ucVBorder; + ATOM_MODE_MISC_INFO_ACCESS susModeMiscInfo; + UCHAR ucInternalModeNumber; + UCHAR ucRefreshRate; +} ATOM_DTD_FORMAT; + +/****************************************************************************/ +/* Structure used in LVDS_InfoTable */ +/* * Need a document to describe this table */ +/****************************************************************************/ +#define SUPPORTED_LCD_REFRESHRATE_30Hz 0x0004 +#define SUPPORTED_LCD_REFRESHRATE_40Hz 0x0008 +#define SUPPORTED_LCD_REFRESHRATE_50Hz 0x0010 +#define SUPPORTED_LCD_REFRESHRATE_60Hz 0x0020 + +/* Once DAL sees this CAP is set, it will read EDID from LCD on its own instead of using sLCDTiming in ATOM_LVDS_INFO_V12. */ +/* Other entries in ATOM_LVDS_INFO_V12 are still valid/useful to DAL */ +#define LCDPANEL_CAP_READ_EDID 0x1 + +/* ucTableFormatRevision=1 */ +/* ucTableContentRevision=1 */ +typedef struct _ATOM_LVDS_INFO { + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_DTD_FORMAT sLCDTiming; + USHORT usModePatchTableOffset; + USHORT usSupportedRefreshRate; /* Refer to panel info table in ATOMBIOS extension Spec. */ + USHORT usOffDelayInMs; + UCHAR ucPowerSequenceDigOntoDEin10Ms; + UCHAR ucPowerSequenceDEtoBLOnin10Ms; + UCHAR ucLVDS_Misc; /* Bit0:{=0:single, =1:dual},Bit1 {=0:666RGB, =1:888RGB},Bit2:3:{Grey level} */ + /* Bit4:{=0:LDI format for RGB888, =1 FPDI format for RGB888} */ + /* Bit5:{=0:Spatial Dithering disabled;1 Spatial Dithering enabled} */ + /* Bit6:{=0:Temporal Dithering disabled;1 Temporal Dithering enabled} */ + UCHAR ucPanelDefaultRefreshRate; + UCHAR ucPanelIdentification; + UCHAR ucSS_Id; +} ATOM_LVDS_INFO; + +/* ucTableFormatRevision=1 */ +/* ucTableContentRevision=2 */ +typedef struct _ATOM_LVDS_INFO_V12 { + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_DTD_FORMAT sLCDTiming; + USHORT usExtInfoTableOffset; + USHORT usSupportedRefreshRate; /* Refer to panel info table in ATOMBIOS extension Spec. */ + USHORT usOffDelayInMs; + UCHAR ucPowerSequenceDigOntoDEin10Ms; + UCHAR ucPowerSequenceDEtoBLOnin10Ms; + UCHAR ucLVDS_Misc; /* Bit0:{=0:single, =1:dual},Bit1 {=0:666RGB, =1:888RGB},Bit2:3:{Grey level} */ + /* Bit4:{=0:LDI format for RGB888, =1 FPDI format for RGB888} */ + /* Bit5:{=0:Spatial Dithering disabled;1 Spatial Dithering enabled} */ + /* Bit6:{=0:Temporal Dithering disabled;1 Temporal Dithering enabled} */ + UCHAR ucPanelDefaultRefreshRate; + UCHAR ucPanelIdentification; + UCHAR ucSS_Id; + USHORT usLCDVenderID; + USHORT usLCDProductID; + UCHAR ucLCDPanel_SpecialHandlingCap; + UCHAR ucPanelInfoSize; /* start from ATOM_DTD_FORMAT to end of panel info, include ExtInfoTable */ + UCHAR ucReserved[2]; +} ATOM_LVDS_INFO_V12; + +#define ATOM_LVDS_INFO_LAST ATOM_LVDS_INFO_V12 + +typedef struct _ATOM_PATCH_RECORD_MODE { + UCHAR ucRecordType; + USHORT usHDisp; + USHORT usVDisp; +} ATOM_PATCH_RECORD_MODE; + +typedef struct _ATOM_LCD_RTS_RECORD { + UCHAR ucRecordType; + UCHAR ucRTSValue; +} ATOM_LCD_RTS_RECORD; + +/* !! If the record below exits, it shoud always be the first record for easy use in command table!!! */ +typedef struct _ATOM_LCD_MODE_CONTROL_CAP { + UCHAR ucRecordType; + USHORT usLCDCap; +} ATOM_LCD_MODE_CONTROL_CAP; + +#define LCD_MODE_CAP_BL_OFF 1 +#define LCD_MODE_CAP_CRTC_OFF 2 +#define LCD_MODE_CAP_PANEL_OFF 4 + +typedef struct _ATOM_FAKE_EDID_PATCH_RECORD { + UCHAR ucRecordType; + UCHAR ucFakeEDIDLength; + UCHAR ucFakeEDIDString[1]; /* This actually has ucFakeEdidLength elements. */ +} ATOM_FAKE_EDID_PATCH_RECORD; + +typedef struct _ATOM_PANEL_RESOLUTION_PATCH_RECORD { + UCHAR ucRecordType; + USHORT usHSize; + USHORT usVSize; +} ATOM_PANEL_RESOLUTION_PATCH_RECORD; + +#define LCD_MODE_PATCH_RECORD_MODE_TYPE 1 +#define LCD_RTS_RECORD_TYPE 2 +#define LCD_CAP_RECORD_TYPE 3 +#define LCD_FAKE_EDID_PATCH_RECORD_TYPE 4 +#define LCD_PANEL_RESOLUTION_RECORD_TYPE 5 +#define ATOM_RECORD_END_TYPE 0xFF + +/****************************Spread Spectrum Info Table Definitions **********************/ + +/* ucTableFormatRevision=1 */ +/* ucTableContentRevision=2 */ +typedef struct _ATOM_SPREAD_SPECTRUM_ASSIGNMENT { + USHORT usSpreadSpectrumPercentage; + UCHAR ucSpreadSpectrumType; /* Bit1=0 Down Spread,=1 Center Spread. Bit1=1 Ext. =0 Int. Others:TBD */ + UCHAR ucSS_Step; + UCHAR ucSS_Delay; + UCHAR ucSS_Id; + UCHAR ucRecommandedRef_Div; + UCHAR ucSS_Range; /* it was reserved for V11 */ +} ATOM_SPREAD_SPECTRUM_ASSIGNMENT; + +#define ATOM_MAX_SS_ENTRY 16 +#define ATOM_DP_SS_ID1 0x0f1 /* SS modulation freq=30k */ +#define ATOM_DP_SS_ID2 0x0f2 /* SS modulation freq=33k */ + +#define ATOM_SS_DOWN_SPREAD_MODE_MASK 0x00000000 +#define ATOM_SS_DOWN_SPREAD_MODE 0x00000000 +#define ATOM_SS_CENTRE_SPREAD_MODE_MASK 0x00000001 +#define ATOM_SS_CENTRE_SPREAD_MODE 0x00000001 +#define ATOM_INTERNAL_SS_MASK 0x00000000 +#define ATOM_EXTERNAL_SS_MASK 0x00000002 +#define EXEC_SS_STEP_SIZE_SHIFT 2 +#define EXEC_SS_DELAY_SHIFT 4 +#define ACTIVEDATA_TO_BLON_DELAY_SHIFT 4 + +typedef struct _ATOM_SPREAD_SPECTRUM_INFO { + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_SPREAD_SPECTRUM_ASSIGNMENT asSS_Info[ATOM_MAX_SS_ENTRY]; +} ATOM_SPREAD_SPECTRUM_INFO; + +/****************************************************************************/ +/* Structure used in AnalogTV_InfoTable (Top level) */ +/****************************************************************************/ +/* ucTVBootUpDefaultStd definiton: */ + +/* ATOM_TV_NTSC 1 */ +/* ATOM_TV_NTSCJ 2 */ +/* ATOM_TV_PAL 3 */ +/* ATOM_TV_PALM 4 */ +/* ATOM_TV_PALCN 5 */ +/* ATOM_TV_PALN 6 */ +/* ATOM_TV_PAL60 7 */ +/* ATOM_TV_SECAM 8 */ + +/* ucTVSuppportedStd definition: */ +#define NTSC_SUPPORT 0x1 +#define NTSCJ_SUPPORT 0x2 + +#define PAL_SUPPORT 0x4 +#define PALM_SUPPORT 0x8 +#define PALCN_SUPPORT 0x10 +#define PALN_SUPPORT 0x20 +#define PAL60_SUPPORT 0x40 +#define SECAM_SUPPORT 0x80 + +#define MAX_SUPPORTED_TV_TIMING 2 + +typedef struct _ATOM_ANALOG_TV_INFO { + ATOM_COMMON_TABLE_HEADER sHeader; + UCHAR ucTV_SupportedStandard; + UCHAR ucTV_BootUpDefaultStandard; + UCHAR ucExt_TV_ASIC_ID; + UCHAR ucExt_TV_ASIC_SlaveAddr; + /*ATOM_DTD_FORMAT aModeTimings[MAX_SUPPORTED_TV_TIMING]; */ + ATOM_MODE_TIMING aModeTimings[MAX_SUPPORTED_TV_TIMING]; +} ATOM_ANALOG_TV_INFO; + +/**************************************************************************/ +/* VRAM usage and their defintions */ + +/* One chunk of VRAM used by Bios are for HWICON surfaces,EDID data. */ +/* Current Mode timing and Dail Timing and/or STD timing data EACH device. They can be broken down as below. */ +/* All the addresses below are the offsets from the frame buffer start.They all MUST be Dword aligned! */ +/* To driver: The physical address of this memory portion=mmFB_START(4K aligned)+ATOMBIOS_VRAM_USAGE_START_ADDR+ATOM_x_ADDR */ +/* To Bios: ATOMBIOS_VRAM_USAGE_START_ADDR+ATOM_x_ADDR->MM_INDEX */ + +#ifndef VESA_MEMORY_IN_64K_BLOCK +#define VESA_MEMORY_IN_64K_BLOCK 0x100 /* 256*64K=16Mb (Max. VESA memory is 16Mb!) */ +#endif + +#define ATOM_EDID_RAW_DATASIZE 256 /* In Bytes */ +#define ATOM_HWICON_SURFACE_SIZE 4096 /* In Bytes */ +#define ATOM_HWICON_INFOTABLE_SIZE 32 +#define MAX_DTD_MODE_IN_VRAM 6 +#define ATOM_DTD_MODE_SUPPORT_TBL_SIZE (MAX_DTD_MODE_IN_VRAM*28) /* 28= (SIZEOF ATOM_DTD_FORMAT) */ +#define ATOM_STD_MODE_SUPPORT_TBL_SIZE (32*8) /* 32 is a predefined number,8= (SIZEOF ATOM_STD_FORMAT) */ +#define DFP_ENCODER_TYPE_OFFSET 0x80 +#define DP_ENCODER_LANE_NUM_OFFSET 0x84 +#define DP_ENCODER_LINK_RATE_OFFSET 0x88 + +#define ATOM_HWICON1_SURFACE_ADDR 0 +#define ATOM_HWICON2_SURFACE_ADDR (ATOM_HWICON1_SURFACE_ADDR + ATOM_HWICON_SURFACE_SIZE) +#define ATOM_HWICON_INFOTABLE_ADDR (ATOM_HWICON2_SURFACE_ADDR + ATOM_HWICON_SURFACE_SIZE) +#define ATOM_CRT1_EDID_ADDR (ATOM_HWICON_INFOTABLE_ADDR + ATOM_HWICON_INFOTABLE_SIZE) +#define ATOM_CRT1_DTD_MODE_TBL_ADDR (ATOM_CRT1_EDID_ADDR + ATOM_EDID_RAW_DATASIZE) +#define ATOM_CRT1_STD_MODE_TBL_ADDR (ATOM_CRT1_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE) + +#define ATOM_LCD1_EDID_ADDR (ATOM_CRT1_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE) +#define ATOM_LCD1_DTD_MODE_TBL_ADDR (ATOM_LCD1_EDID_ADDR + ATOM_EDID_RAW_DATASIZE) +#define ATOM_LCD1_STD_MODE_TBL_ADDR (ATOM_LCD1_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE) + +#define ATOM_TV1_DTD_MODE_TBL_ADDR (ATOM_LCD1_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE) + +#define ATOM_DFP1_EDID_ADDR (ATOM_TV1_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE) +#define ATOM_DFP1_DTD_MODE_TBL_ADDR (ATOM_DFP1_EDID_ADDR + ATOM_EDID_RAW_DATASIZE) +#define ATOM_DFP1_STD_MODE_TBL_ADDR (ATOM_DFP1_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE) + +#define ATOM_CRT2_EDID_ADDR (ATOM_DFP1_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE) +#define ATOM_CRT2_DTD_MODE_TBL_ADDR (ATOM_CRT2_EDID_ADDR + ATOM_EDID_RAW_DATASIZE) +#define ATOM_CRT2_STD_MODE_TBL_ADDR (ATOM_CRT2_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE) + +#define ATOM_LCD2_EDID_ADDR (ATOM_CRT2_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE) +#define ATOM_LCD2_DTD_MODE_TBL_ADDR (ATOM_LCD2_EDID_ADDR + ATOM_EDID_RAW_DATASIZE) +#define ATOM_LCD2_STD_MODE_TBL_ADDR (ATOM_LCD2_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE) + +#define ATOM_TV2_EDID_ADDR (ATOM_LCD2_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE) +#define ATOM_TV2_DTD_MODE_TBL_ADDR (ATOM_TV2_EDID_ADDR + ATOM_EDID_RAW_DATASIZE) +#define ATOM_TV2_STD_MODE_TBL_ADDR (ATOM_TV2_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE) + +#define ATOM_DFP2_EDID_ADDR (ATOM_TV2_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE) +#define ATOM_DFP2_DTD_MODE_TBL_ADDR (ATOM_DFP2_EDID_ADDR + ATOM_EDID_RAW_DATASIZE) +#define ATOM_DFP2_STD_MODE_TBL_ADDR (ATOM_DFP2_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE) + +#define ATOM_CV_EDID_ADDR (ATOM_DFP2_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE) +#define ATOM_CV_DTD_MODE_TBL_ADDR (ATOM_CV_EDID_ADDR + ATOM_EDID_RAW_DATASIZE) +#define ATOM_CV_STD_MODE_TBL_ADDR (ATOM_CV_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE) + +#define ATOM_DFP3_EDID_ADDR (ATOM_CV_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE) +#define ATOM_DFP3_DTD_MODE_TBL_ADDR (ATOM_DFP3_EDID_ADDR + ATOM_EDID_RAW_DATASIZE) +#define ATOM_DFP3_STD_MODE_TBL_ADDR (ATOM_DFP3_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE) + +#define ATOM_DFP4_EDID_ADDR (ATOM_DFP3_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE) +#define ATOM_DFP4_DTD_MODE_TBL_ADDR (ATOM_DFP4_EDID_ADDR + ATOM_EDID_RAW_DATASIZE) +#define ATOM_DFP4_STD_MODE_TBL_ADDR (ATOM_DFP4_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE) + +#define ATOM_DFP5_EDID_ADDR (ATOM_DFP4_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE) +#define ATOM_DFP5_DTD_MODE_TBL_ADDR (ATOM_DFP5_EDID_ADDR + ATOM_EDID_RAW_DATASIZE) +#define ATOM_DFP5_STD_MODE_TBL_ADDR (ATOM_DFP5_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE) + +#define ATOM_DP_TRAINING_TBL_ADDR (ATOM_DFP5_STD_MODE_TBL_ADDR+ATOM_STD_MODE_SUPPORT_TBL_SIZE) + +#define ATOM_STACK_STORAGE_START (ATOM_DP_TRAINING_TBL_ADDR + 256) +#define ATOM_STACK_STORAGE_END (ATOM_STACK_STORAGE_START + 512) + +/* The size below is in Kb! */ +#define ATOM_VRAM_RESERVE_SIZE ((((ATOM_STACK_STORAGE_END - ATOM_HWICON1_SURFACE_ADDR)>>10)+4)&0xFFFC) + +#define ATOM_VRAM_OPERATION_FLAGS_MASK 0xC0000000L +#define ATOM_VRAM_OPERATION_FLAGS_SHIFT 30 +#define ATOM_VRAM_BLOCK_NEEDS_NO_RESERVATION 0x1 +#define ATOM_VRAM_BLOCK_NEEDS_RESERVATION 0x0 + +/***********************************************************************************/ +/* Structure used in VRAM_UsageByFirmwareTable */ +/* Note1: This table is filled by SetBiosReservationStartInFB in CoreCommSubs.asm */ +/* at running time. */ +/* note2: From RV770, the memory is more than 32bit addressable, so we will change */ +/* ucTableFormatRevision=1,ucTableContentRevision=4, the strcuture remains */ +/* exactly same as 1.1 and 1.2 (1.3 is never in use), but ulStartAddrUsedByFirmware */ +/* (in offset to start of memory address) is KB aligned instead of byte aligend. */ +/***********************************************************************************/ +#define ATOM_MAX_FIRMWARE_VRAM_USAGE_INFO 1 + +typedef struct _ATOM_FIRMWARE_VRAM_RESERVE_INFO { + ULONG ulStartAddrUsedByFirmware; + USHORT usFirmwareUseInKb; + USHORT usReserved; +} ATOM_FIRMWARE_VRAM_RESERVE_INFO; + +typedef struct _ATOM_VRAM_USAGE_BY_FIRMWARE { + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_FIRMWARE_VRAM_RESERVE_INFO + asFirmwareVramReserveInfo[ATOM_MAX_FIRMWARE_VRAM_USAGE_INFO]; +} ATOM_VRAM_USAGE_BY_FIRMWARE; + +/****************************************************************************/ +/* Structure used in GPIO_Pin_LUTTable */ +/****************************************************************************/ +typedef struct _ATOM_GPIO_PIN_ASSIGNMENT { + USHORT usGpioPin_AIndex; + UCHAR ucGpioPinBitShift; + UCHAR ucGPIO_ID; +} ATOM_GPIO_PIN_ASSIGNMENT; + +typedef struct _ATOM_GPIO_PIN_LUT { + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_GPIO_PIN_ASSIGNMENT asGPIO_Pin[1]; +} ATOM_GPIO_PIN_LUT; + +/****************************************************************************/ +/* Structure used in ComponentVideoInfoTable */ +/****************************************************************************/ +#define GPIO_PIN_ACTIVE_HIGH 0x1 + +#define MAX_SUPPORTED_CV_STANDARDS 5 + +/* definitions for ATOM_D_INFO.ucSettings */ +#define ATOM_GPIO_SETTINGS_BITSHIFT_MASK 0x1F /* [4:0] */ +#define ATOM_GPIO_SETTINGS_RESERVED_MASK 0x60 /* [6:5] = must be zeroed out */ +#define ATOM_GPIO_SETTINGS_ACTIVE_MASK 0x80 /* [7] */ + +typedef struct _ATOM_GPIO_INFO { + USHORT usAOffset; + UCHAR ucSettings; + UCHAR ucReserved; +} ATOM_GPIO_INFO; + +/* definitions for ATOM_COMPONENT_VIDEO_INFO.ucMiscInfo (bit vector) */ +#define ATOM_CV_RESTRICT_FORMAT_SELECTION 0x2 + +/* definitions for ATOM_COMPONENT_VIDEO_INFO.uc480i/uc480p/uc720p/uc1080i */ +#define ATOM_GPIO_DEFAULT_MODE_EN 0x80 /* [7]; */ +#define ATOM_GPIO_SETTING_PERMODE_MASK 0x7F /* [6:0] */ + +/* definitions for ATOM_COMPONENT_VIDEO_INFO.ucLetterBoxMode */ +/* Line 3 out put 5V. */ +#define ATOM_CV_LINE3_ASPECTRATIO_16_9_GPIO_A 0x01 /* represent gpio 3 state for 16:9 */ +#define ATOM_CV_LINE3_ASPECTRATIO_16_9_GPIO_B 0x02 /* represent gpio 4 state for 16:9 */ +#define ATOM_CV_LINE3_ASPECTRATIO_16_9_GPIO_SHIFT 0x0 + +/* Line 3 out put 2.2V */ +#define ATOM_CV_LINE3_ASPECTRATIO_4_3_LETBOX_GPIO_A 0x04 /* represent gpio 3 state for 4:3 Letter box */ +#define ATOM_CV_LINE3_ASPECTRATIO_4_3_LETBOX_GPIO_B 0x08 /* represent gpio 4 state for 4:3 Letter box */ +#define ATOM_CV_LINE3_ASPECTRATIO_4_3_LETBOX_GPIO_SHIFT 0x2 + +/* Line 3 out put 0V */ +#define ATOM_CV_LINE3_ASPECTRATIO_4_3_GPIO_A 0x10 /* represent gpio 3 state for 4:3 */ +#define ATOM_CV_LINE3_ASPECTRATIO_4_3_GPIO_B 0x20 /* represent gpio 4 state for 4:3 */ +#define ATOM_CV_LINE3_ASPECTRATIO_4_3_GPIO_SHIFT 0x4 + +#define ATOM_CV_LINE3_ASPECTRATIO_MASK 0x3F /* bit [5:0] */ + +#define ATOM_CV_LINE3_ASPECTRATIO_EXIST 0x80 /* bit 7 */ + +/* GPIO bit index in gpio setting per mode value, also represend the block no. in gpio blocks. */ +#define ATOM_GPIO_INDEX_LINE3_ASPECRATIO_GPIO_A 3 /* bit 3 in uc480i/uc480p/uc720p/uc1080i, which represend the default gpio bit setting for the mode. */ +#define ATOM_GPIO_INDEX_LINE3_ASPECRATIO_GPIO_B 4 /* bit 4 in uc480i/uc480p/uc720p/uc1080i, which represend the default gpio bit setting for the mode. */ + +typedef struct _ATOM_COMPONENT_VIDEO_INFO { + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT usMask_PinRegisterIndex; + USHORT usEN_PinRegisterIndex; + USHORT usY_PinRegisterIndex; + USHORT usA_PinRegisterIndex; + UCHAR ucBitShift; + UCHAR ucPinActiveState; /* ucPinActiveState: Bit0=1 active high, =0 active low */ + ATOM_DTD_FORMAT sReserved; /* must be zeroed out */ + UCHAR ucMiscInfo; + UCHAR uc480i; + UCHAR uc480p; + UCHAR uc720p; + UCHAR uc1080i; + UCHAR ucLetterBoxMode; + UCHAR ucReserved[3]; + UCHAR ucNumOfWbGpioBlocks; /* For Component video D-Connector support. If zere, NTSC type connector */ + ATOM_GPIO_INFO aWbGpioStateBlock[MAX_SUPPORTED_CV_STANDARDS]; + ATOM_DTD_FORMAT aModeTimings[MAX_SUPPORTED_CV_STANDARDS]; +} ATOM_COMPONENT_VIDEO_INFO; + +/* ucTableFormatRevision=2 */ +/* ucTableContentRevision=1 */ +typedef struct _ATOM_COMPONENT_VIDEO_INFO_V21 { + ATOM_COMMON_TABLE_HEADER sHeader; + UCHAR ucMiscInfo; + UCHAR uc480i; + UCHAR uc480p; + UCHAR uc720p; + UCHAR uc1080i; + UCHAR ucReserved; + UCHAR ucLetterBoxMode; + UCHAR ucNumOfWbGpioBlocks; /* For Component video D-Connector support. If zere, NTSC type connector */ + ATOM_GPIO_INFO aWbGpioStateBlock[MAX_SUPPORTED_CV_STANDARDS]; + ATOM_DTD_FORMAT aModeTimings[MAX_SUPPORTED_CV_STANDARDS]; +} ATOM_COMPONENT_VIDEO_INFO_V21; + +#define ATOM_COMPONENT_VIDEO_INFO_LAST ATOM_COMPONENT_VIDEO_INFO_V21 + +/****************************************************************************/ +/* Structure used in object_InfoTable */ +/****************************************************************************/ +typedef struct _ATOM_OBJECT_HEADER { + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT usDeviceSupport; + USHORT usConnectorObjectTableOffset; + USHORT usRouterObjectTableOffset; + USHORT usEncoderObjectTableOffset; + USHORT usProtectionObjectTableOffset; /* only available when Protection block is independent. */ + USHORT usDisplayPathTableOffset; +} ATOM_OBJECT_HEADER; + +typedef struct _ATOM_DISPLAY_OBJECT_PATH { + USHORT usDeviceTag; /* supported device */ + USHORT usSize; /* the size of ATOM_DISPLAY_OBJECT_PATH */ + USHORT usConnObjectId; /* Connector Object ID */ + USHORT usGPUObjectId; /* GPU ID */ + USHORT usGraphicObjIds[1]; /* 1st Encoder Obj source from GPU to last Graphic Obj destinate to connector. */ +} ATOM_DISPLAY_OBJECT_PATH; + +typedef struct _ATOM_DISPLAY_OBJECT_PATH_TABLE { + UCHAR ucNumOfDispPath; + UCHAR ucVersion; + UCHAR ucPadding[2]; + ATOM_DISPLAY_OBJECT_PATH asDispPath[1]; +} ATOM_DISPLAY_OBJECT_PATH_TABLE; + +typedef struct _ATOM_OBJECT /* each object has this structure */ +{ + USHORT usObjectID; + USHORT usSrcDstTableOffset; + USHORT usRecordOffset; /* this pointing to a bunch of records defined below */ + USHORT usReserved; +} ATOM_OBJECT; + +typedef struct _ATOM_OBJECT_TABLE /* Above 4 object table offset pointing to a bunch of objects all have this structure */ +{ + UCHAR ucNumberOfObjects; + UCHAR ucPadding[3]; + ATOM_OBJECT asObjects[1]; +} ATOM_OBJECT_TABLE; + +typedef struct _ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT /* usSrcDstTableOffset pointing to this structure */ +{ + UCHAR ucNumberOfSrc; + USHORT usSrcObjectID[1]; + UCHAR ucNumberOfDst; + USHORT usDstObjectID[1]; +} ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT; + +/* Related definitions, all records are differnt but they have a commond header */ +typedef struct _ATOM_COMMON_RECORD_HEADER { + UCHAR ucRecordType; /* An emun to indicate the record type */ + UCHAR ucRecordSize; /* The size of the whole record in byte */ +} ATOM_COMMON_RECORD_HEADER; + +#define ATOM_I2C_RECORD_TYPE 1 +#define ATOM_HPD_INT_RECORD_TYPE 2 +#define ATOM_OUTPUT_PROTECTION_RECORD_TYPE 3 +#define ATOM_CONNECTOR_DEVICE_TAG_RECORD_TYPE 4 +#define ATOM_CONNECTOR_DVI_EXT_INPUT_RECORD_TYPE 5 /* Obsolete, switch to use GPIO_CNTL_RECORD_TYPE */ +#define ATOM_ENCODER_FPGA_CONTROL_RECORD_TYPE 6 /* Obsolete, switch to use GPIO_CNTL_RECORD_TYPE */ +#define ATOM_CONNECTOR_CVTV_SHARE_DIN_RECORD_TYPE 7 +#define ATOM_JTAG_RECORD_TYPE 8 /* Obsolete, switch to use GPIO_CNTL_RECORD_TYPE */ +#define ATOM_OBJECT_GPIO_CNTL_RECORD_TYPE 9 +#define ATOM_ENCODER_DVO_CF_RECORD_TYPE 10 +#define ATOM_CONNECTOR_CF_RECORD_TYPE 11 +#define ATOM_CONNECTOR_HARDCODE_DTD_RECORD_TYPE 12 +#define ATOM_CONNECTOR_PCIE_SUBCONNECTOR_RECORD_TYPE 13 +#define ATOM_ROUTER_DDC_PATH_SELECT_RECORD_TYPE 14 +#define ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD_TYPE 15 + +/* Must be updated when new record type is added,equal to that record definition! */ +#define ATOM_MAX_OBJECT_RECORD_NUMBER ATOM_CONNECTOR_CF_RECORD_TYPE + +typedef struct _ATOM_I2C_RECORD { + ATOM_COMMON_RECORD_HEADER sheader; + ATOM_I2C_ID_CONFIG sucI2cId; + UCHAR ucI2CAddr; /* The slave address, it's 0 when the record is attached to connector for DDC */ +} ATOM_I2C_RECORD; + +typedef struct _ATOM_HPD_INT_RECORD { + ATOM_COMMON_RECORD_HEADER sheader; + UCHAR ucHPDIntGPIOID; /* Corresponding block in GPIO_PIN_INFO table gives the pin info */ + UCHAR ucPluggged_PinState; +} ATOM_HPD_INT_RECORD; + +typedef struct _ATOM_OUTPUT_PROTECTION_RECORD { + ATOM_COMMON_RECORD_HEADER sheader; + UCHAR ucProtectionFlag; + UCHAR ucReserved; +} ATOM_OUTPUT_PROTECTION_RECORD; + +typedef struct _ATOM_CONNECTOR_DEVICE_TAG { + ULONG ulACPIDeviceEnum; /* Reserved for now */ + USHORT usDeviceID; /* This Id is same as "ATOM_DEVICE_XXX_SUPPORT" */ + USHORT usPadding; +} ATOM_CONNECTOR_DEVICE_TAG; + +typedef struct _ATOM_CONNECTOR_DEVICE_TAG_RECORD { + ATOM_COMMON_RECORD_HEADER sheader; + UCHAR ucNumberOfDevice; + UCHAR ucReserved; + ATOM_CONNECTOR_DEVICE_TAG asDeviceTag[1]; /* This Id is same as "ATOM_DEVICE_XXX_SUPPORT", 1 is only for allocation */ +} ATOM_CONNECTOR_DEVICE_TAG_RECORD; + +typedef struct _ATOM_CONNECTOR_DVI_EXT_INPUT_RECORD { + ATOM_COMMON_RECORD_HEADER sheader; + UCHAR ucConfigGPIOID; + UCHAR ucConfigGPIOState; /* Set to 1 when it's active high to enable external flow in */ + UCHAR ucFlowinGPIPID; + UCHAR ucExtInGPIPID; +} ATOM_CONNECTOR_DVI_EXT_INPUT_RECORD; + +typedef struct _ATOM_ENCODER_FPGA_CONTROL_RECORD { + ATOM_COMMON_RECORD_HEADER sheader; + UCHAR ucCTL1GPIO_ID; + UCHAR ucCTL1GPIOState; /* Set to 1 when it's active high */ + UCHAR ucCTL2GPIO_ID; + UCHAR ucCTL2GPIOState; /* Set to 1 when it's active high */ + UCHAR ucCTL3GPIO_ID; + UCHAR ucCTL3GPIOState; /* Set to 1 when it's active high */ + UCHAR ucCTLFPGA_IN_ID; + UCHAR ucPadding[3]; +} ATOM_ENCODER_FPGA_CONTROL_RECORD; + +typedef struct _ATOM_CONNECTOR_CVTV_SHARE_DIN_RECORD { + ATOM_COMMON_RECORD_HEADER sheader; + UCHAR ucGPIOID; /* Corresponding block in GPIO_PIN_INFO table gives the pin info */ + UCHAR ucTVActiveState; /* Indicating when the pin==0 or 1 when TV is connected */ +} ATOM_CONNECTOR_CVTV_SHARE_DIN_RECORD; + +typedef struct _ATOM_JTAG_RECORD { + ATOM_COMMON_RECORD_HEADER sheader; + UCHAR ucTMSGPIO_ID; + UCHAR ucTMSGPIOState; /* Set to 1 when it's active high */ + UCHAR ucTCKGPIO_ID; + UCHAR ucTCKGPIOState; /* Set to 1 when it's active high */ + UCHAR ucTDOGPIO_ID; + UCHAR ucTDOGPIOState; /* Set to 1 when it's active high */ + UCHAR ucTDIGPIO_ID; + UCHAR ucTDIGPIOState; /* Set to 1 when it's active high */ + UCHAR ucPadding[2]; +} ATOM_JTAG_RECORD; + +/* The following generic object gpio pin control record type will replace JTAG_RECORD/FPGA_CONTROL_RECORD/DVI_EXT_INPUT_RECORD above gradually */ +typedef struct _ATOM_GPIO_PIN_CONTROL_PAIR { + UCHAR ucGPIOID; /* GPIO_ID, find the corresponding ID in GPIO_LUT table */ + UCHAR ucGPIO_PinState; /* Pin state showing how to set-up the pin */ +} ATOM_GPIO_PIN_CONTROL_PAIR; + +typedef struct _ATOM_OBJECT_GPIO_CNTL_RECORD { + ATOM_COMMON_RECORD_HEADER sheader; + UCHAR ucFlags; /* Future expnadibility */ + UCHAR ucNumberOfPins; /* Number of GPIO pins used to control the object */ + ATOM_GPIO_PIN_CONTROL_PAIR asGpio[1]; /* the real gpio pin pair determined by number of pins ucNumberOfPins */ +} ATOM_OBJECT_GPIO_CNTL_RECORD; + +/* Definitions for GPIO pin state */ +#define GPIO_PIN_TYPE_INPUT 0x00 +#define GPIO_PIN_TYPE_OUTPUT 0x10 +#define GPIO_PIN_TYPE_HW_CONTROL 0x20 + +/* For GPIO_PIN_TYPE_OUTPUT the following is defined */ +#define GPIO_PIN_OUTPUT_STATE_MASK 0x01 +#define GPIO_PIN_OUTPUT_STATE_SHIFT 0 +#define GPIO_PIN_STATE_ACTIVE_LOW 0x0 +#define GPIO_PIN_STATE_ACTIVE_HIGH 0x1 + +typedef struct _ATOM_ENCODER_DVO_CF_RECORD { + ATOM_COMMON_RECORD_HEADER sheader; + ULONG ulStrengthControl; /* DVOA strength control for CF */ + UCHAR ucPadding[2]; +} ATOM_ENCODER_DVO_CF_RECORD; + +/* value for ATOM_CONNECTOR_CF_RECORD.ucConnectedDvoBundle */ +#define ATOM_CONNECTOR_CF_RECORD_CONNECTED_UPPER12BITBUNDLEA 1 +#define ATOM_CONNECTOR_CF_RECORD_CONNECTED_LOWER12BITBUNDLEB 2 + +typedef struct _ATOM_CONNECTOR_CF_RECORD { + ATOM_COMMON_RECORD_HEADER sheader; + USHORT usMaxPixClk; + UCHAR ucFlowCntlGpioId; + UCHAR ucSwapCntlGpioId; + UCHAR ucConnectedDvoBundle; + UCHAR ucPadding; +} ATOM_CONNECTOR_CF_RECORD; + +typedef struct _ATOM_CONNECTOR_HARDCODE_DTD_RECORD { + ATOM_COMMON_RECORD_HEADER sheader; + ATOM_DTD_FORMAT asTiming; +} ATOM_CONNECTOR_HARDCODE_DTD_RECORD; + +typedef struct _ATOM_CONNECTOR_PCIE_SUBCONNECTOR_RECORD { + ATOM_COMMON_RECORD_HEADER sheader; /* ATOM_CONNECTOR_PCIE_SUBCONNECTOR_RECORD_TYPE */ + UCHAR ucSubConnectorType; /* CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D|X_ID_DUAL_LINK_DVI_D|HDMI_TYPE_A */ + UCHAR ucReserved; +} ATOM_CONNECTOR_PCIE_SUBCONNECTOR_RECORD; + +typedef struct _ATOM_ROUTER_DDC_PATH_SELECT_RECORD { + ATOM_COMMON_RECORD_HEADER sheader; + UCHAR ucMuxType; /* decide the number of ucMuxState, =0, no pin state, =1: single state with complement, >1: multiple state */ + UCHAR ucMuxControlPin; + UCHAR ucMuxState[2]; /* for alligment purpose */ +} ATOM_ROUTER_DDC_PATH_SELECT_RECORD; + +typedef struct _ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD { + ATOM_COMMON_RECORD_HEADER sheader; + UCHAR ucMuxType; + UCHAR ucMuxControlPin; + UCHAR ucMuxState[2]; /* for alligment purpose */ +} ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD; + +/* define ucMuxType */ +#define ATOM_ROUTER_MUX_PIN_STATE_MASK 0x0f +#define ATOM_ROUTER_MUX_PIN_SINGLE_STATE_COMPLEMENT 0x01 + +/****************************************************************************/ +/* ASIC voltage data table */ +/****************************************************************************/ +typedef struct _ATOM_VOLTAGE_INFO_HEADER { + USHORT usVDDCBaseLevel; /* In number of 50mv unit */ + USHORT usReserved; /* For possible extension table offset */ + UCHAR ucNumOfVoltageEntries; + UCHAR ucBytesPerVoltageEntry; + UCHAR ucVoltageStep; /* Indicating in how many mv increament is one step, 0.5mv unit */ + UCHAR ucDefaultVoltageEntry; + UCHAR ucVoltageControlI2cLine; + UCHAR ucVoltageControlAddress; + UCHAR ucVoltageControlOffset; +} ATOM_VOLTAGE_INFO_HEADER; + +typedef struct _ATOM_VOLTAGE_INFO { + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_VOLTAGE_INFO_HEADER viHeader; + UCHAR ucVoltageEntries[64]; /* 64 is for allocation, the actual number of entry is present at ucNumOfVoltageEntries*ucBytesPerVoltageEntry */ +} ATOM_VOLTAGE_INFO; + +typedef struct _ATOM_VOLTAGE_FORMULA { + USHORT usVoltageBaseLevel; /* In number of 1mv unit */ + USHORT usVoltageStep; /* Indicating in how many mv increament is one step, 1mv unit */ + UCHAR ucNumOfVoltageEntries; /* Number of Voltage Entry, which indicate max Voltage */ + UCHAR ucFlag; /* bit0=0 :step is 1mv =1 0.5mv */ + UCHAR ucBaseVID; /* if there is no lookup table, VID= BaseVID + ( Vol - BaseLevle ) /VoltageStep */ + UCHAR ucReserved; + UCHAR ucVIDAdjustEntries[32]; /* 32 is for allocation, the actual number of entry is present at ucNumOfVoltageEntries */ +} ATOM_VOLTAGE_FORMULA; + +typedef struct _ATOM_VOLTAGE_CONTROL { + UCHAR ucVoltageControlId; /* Indicate it is controlled by I2C or GPIO or HW state machine */ + UCHAR ucVoltageControlI2cLine; + UCHAR ucVoltageControlAddress; + UCHAR ucVoltageControlOffset; + USHORT usGpioPin_AIndex; /* GPIO_PAD register index */ + UCHAR ucGpioPinBitShift[9]; /* at most 8 pin support 255 VIDs, termintate with 0xff */ + UCHAR ucReserved; +} ATOM_VOLTAGE_CONTROL; + +/* Define ucVoltageControlId */ +#define VOLTAGE_CONTROLLED_BY_HW 0x00 +#define VOLTAGE_CONTROLLED_BY_I2C_MASK 0x7F +#define VOLTAGE_CONTROLLED_BY_GPIO 0x80 +#define VOLTAGE_CONTROL_ID_LM64 0x01 /* I2C control, used for R5xx Core Voltage */ +#define VOLTAGE_CONTROL_ID_DAC 0x02 /* I2C control, used for R5xx/R6xx MVDDC,MVDDQ or VDDCI */ +#define VOLTAGE_CONTROL_ID_VT116xM 0x03 /* I2C control, used for R6xx Core Voltage */ +#define VOLTAGE_CONTROL_ID_DS4402 0x04 + +typedef struct _ATOM_VOLTAGE_OBJECT { + UCHAR ucVoltageType; /* Indicate Voltage Source: VDDC, MVDDC, MVDDQ or MVDDCI */ + UCHAR ucSize; /* Size of Object */ + ATOM_VOLTAGE_CONTROL asControl; /* describ how to control */ + ATOM_VOLTAGE_FORMULA asFormula; /* Indicate How to convert real Voltage to VID */ +} ATOM_VOLTAGE_OBJECT; + +typedef struct _ATOM_VOLTAGE_OBJECT_INFO { + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_VOLTAGE_OBJECT asVoltageObj[3]; /* Info for Voltage control */ +} ATOM_VOLTAGE_OBJECT_INFO; + +typedef struct _ATOM_LEAKID_VOLTAGE { + UCHAR ucLeakageId; + UCHAR ucReserved; + USHORT usVoltage; +} ATOM_LEAKID_VOLTAGE; + +typedef struct _ATOM_ASIC_PROFILE_VOLTAGE { + UCHAR ucProfileId; + UCHAR ucReserved; + USHORT usSize; + USHORT usEfuseSpareStartAddr; + USHORT usFuseIndex[8]; /* from LSB to MSB, Max 8bit,end of 0xffff if less than 8 efuse id, */ + ATOM_LEAKID_VOLTAGE asLeakVol[2]; /* Leakid and relatd voltage */ +} ATOM_ASIC_PROFILE_VOLTAGE; + +/* ucProfileId */ +#define ATOM_ASIC_PROFILE_ID_EFUSE_VOLTAGE 1 +#define ATOM_ASIC_PROFILE_ID_EFUSE_PERFORMANCE_VOLTAGE 1 +#define ATOM_ASIC_PROFILE_ID_EFUSE_THERMAL_VOLTAGE 2 + +typedef struct _ATOM_ASIC_PROFILING_INFO { + ATOM_COMMON_TABLE_HEADER asHeader; + ATOM_ASIC_PROFILE_VOLTAGE asVoltage; +} ATOM_ASIC_PROFILING_INFO; + +typedef struct _ATOM_POWER_SOURCE_OBJECT { + UCHAR ucPwrSrcId; /* Power source */ + UCHAR ucPwrSensorType; /* GPIO, I2C or none */ + UCHAR ucPwrSensId; /* if GPIO detect, it is GPIO id, if I2C detect, it is I2C id */ + UCHAR ucPwrSensSlaveAddr; /* Slave address if I2C detect */ + UCHAR ucPwrSensRegIndex; /* I2C register Index if I2C detect */ + UCHAR ucPwrSensRegBitMask; /* detect which bit is used if I2C detect */ + UCHAR ucPwrSensActiveState; /* high active or low active */ + UCHAR ucReserve[3]; /* reserve */ + USHORT usSensPwr; /* in unit of watt */ +} ATOM_POWER_SOURCE_OBJECT; + +typedef struct _ATOM_POWER_SOURCE_INFO { + ATOM_COMMON_TABLE_HEADER asHeader; + UCHAR asPwrbehave[16]; + ATOM_POWER_SOURCE_OBJECT asPwrObj[1]; +} ATOM_POWER_SOURCE_INFO; + +/* Define ucPwrSrcId */ +#define POWERSOURCE_PCIE_ID1 0x00 +#define POWERSOURCE_6PIN_CONNECTOR_ID1 0x01 +#define POWERSOURCE_8PIN_CONNECTOR_ID1 0x02 +#define POWERSOURCE_6PIN_CONNECTOR_ID2 0x04 +#define POWERSOURCE_8PIN_CONNECTOR_ID2 0x08 + +/* define ucPwrSensorId */ +#define POWER_SENSOR_ALWAYS 0x00 +#define POWER_SENSOR_GPIO 0x01 +#define POWER_SENSOR_I2C 0x02 + +/**************************************************************************/ +/* This portion is only used when ext thermal chip or engine/memory clock SS chip is populated on a design */ +/* Memory SS Info Table */ +/* Define Memory Clock SS chip ID */ +#define ICS91719 1 +#define ICS91720 2 + +/* Define one structure to inform SW a "block of data" writing to external SS chip via I2C protocol */ +typedef struct _ATOM_I2C_DATA_RECORD { + UCHAR ucNunberOfBytes; /* Indicates how many bytes SW needs to write to the external ASIC for one block, besides to "Start" and "Stop" */ + UCHAR ucI2CData[1]; /* I2C data in bytes, should be less than 16 bytes usually */ +} ATOM_I2C_DATA_RECORD; + +/* Define one structure to inform SW how many blocks of data writing to external SS chip via I2C protocol, in addition to other information */ +typedef struct _ATOM_I2C_DEVICE_SETUP_INFO { + ATOM_I2C_ID_CONFIG_ACCESS sucI2cId; /* I2C line and HW/SW assisted cap. */ + UCHAR ucSSChipID; /* SS chip being used */ + UCHAR ucSSChipSlaveAddr; /* Slave Address to set up this SS chip */ + UCHAR ucNumOfI2CDataRecords; /* number of data block */ + ATOM_I2C_DATA_RECORD asI2CData[1]; +} ATOM_I2C_DEVICE_SETUP_INFO; + +/* ========================================================================================== */ +typedef struct _ATOM_ASIC_MVDD_INFO { + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_I2C_DEVICE_SETUP_INFO asI2CSetup[1]; +} ATOM_ASIC_MVDD_INFO; + +/* ========================================================================================== */ +#define ATOM_MCLK_SS_INFO ATOM_ASIC_MVDD_INFO + +/* ========================================================================================== */ +/**************************************************************************/ + +typedef struct _ATOM_ASIC_SS_ASSIGNMENT { + ULONG ulTargetClockRange; /* Clock Out frequence (VCO ), in unit of 10Khz */ + USHORT usSpreadSpectrumPercentage; /* in unit of 0.01% */ + USHORT usSpreadRateInKhz; /* in unit of kHz, modulation freq */ + UCHAR ucClockIndication; /* Indicate which clock source needs SS */ + UCHAR ucSpreadSpectrumMode; /* Bit1=0 Down Spread,=1 Center Spread. */ + UCHAR ucReserved[2]; +} ATOM_ASIC_SS_ASSIGNMENT; + +/* Define ucSpreadSpectrumType */ +#define ASIC_INTERNAL_MEMORY_SS 1 +#define ASIC_INTERNAL_ENGINE_SS 2 +#define ASIC_INTERNAL_UVD_SS 3 + +typedef struct _ATOM_ASIC_INTERNAL_SS_INFO { + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_ASIC_SS_ASSIGNMENT asSpreadSpectrum[4]; +} ATOM_ASIC_INTERNAL_SS_INFO; + +/* ==============================Scratch Pad Definition Portion=============================== */ +#define ATOM_DEVICE_CONNECT_INFO_DEF 0 +#define ATOM_ROM_LOCATION_DEF 1 +#define ATOM_TV_STANDARD_DEF 2 +#define ATOM_ACTIVE_INFO_DEF 3 +#define ATOM_LCD_INFO_DEF 4 +#define ATOM_DOS_REQ_INFO_DEF 5 +#define ATOM_ACC_CHANGE_INFO_DEF 6 +#define ATOM_DOS_MODE_INFO_DEF 7 +#define ATOM_I2C_CHANNEL_STATUS_DEF 8 +#define ATOM_I2C_CHANNEL_STATUS1_DEF 9 + +/* BIOS_0_SCRATCH Definition */ +#define ATOM_S0_CRT1_MONO 0x00000001L +#define ATOM_S0_CRT1_COLOR 0x00000002L +#define ATOM_S0_CRT1_MASK (ATOM_S0_CRT1_MONO+ATOM_S0_CRT1_COLOR) + +#define ATOM_S0_TV1_COMPOSITE_A 0x00000004L +#define ATOM_S0_TV1_SVIDEO_A 0x00000008L +#define ATOM_S0_TV1_MASK_A (ATOM_S0_TV1_COMPOSITE_A+ATOM_S0_TV1_SVIDEO_A) + +#define ATOM_S0_CV_A 0x00000010L +#define ATOM_S0_CV_DIN_A 0x00000020L +#define ATOM_S0_CV_MASK_A (ATOM_S0_CV_A+ATOM_S0_CV_DIN_A) + +#define ATOM_S0_CRT2_MONO 0x00000100L +#define ATOM_S0_CRT2_COLOR 0x00000200L +#define ATOM_S0_CRT2_MASK (ATOM_S0_CRT2_MONO+ATOM_S0_CRT2_COLOR) + +#define ATOM_S0_TV1_COMPOSITE 0x00000400L +#define ATOM_S0_TV1_SVIDEO 0x00000800L +#define ATOM_S0_TV1_SCART 0x00004000L +#define ATOM_S0_TV1_MASK (ATOM_S0_TV1_COMPOSITE+ATOM_S0_TV1_SVIDEO+ATOM_S0_TV1_SCART) + +#define ATOM_S0_CV 0x00001000L +#define ATOM_S0_CV_DIN 0x00002000L +#define ATOM_S0_CV_MASK (ATOM_S0_CV+ATOM_S0_CV_DIN) + +#define ATOM_S0_DFP1 0x00010000L +#define ATOM_S0_DFP2 0x00020000L +#define ATOM_S0_LCD1 0x00040000L +#define ATOM_S0_LCD2 0x00080000L +#define ATOM_S0_TV2 0x00100000L +#define ATOM_S0_DFP3 0x00200000L +#define ATOM_S0_DFP4 0x00400000L +#define ATOM_S0_DFP5 0x00800000L + +#define ATOM_S0_DFP_MASK \ + (ATOM_S0_DFP1 | ATOM_S0_DFP2 | ATOM_S0_DFP3 | ATOM_S0_DFP4 | ATOM_S0_DFP5) + +#define ATOM_S0_FAD_REGISTER_BUG 0x02000000L /* If set, indicates we are running a PCIE asic with */ + /* the FAD/HDP reg access bug. Bit is read by DAL */ + +#define ATOM_S0_THERMAL_STATE_MASK 0x1C000000L +#define ATOM_S0_THERMAL_STATE_SHIFT 26 + +#define ATOM_S0_SYSTEM_POWER_STATE_MASK 0xE0000000L +#define ATOM_S0_SYSTEM_POWER_STATE_SHIFT 29 + +#define ATOM_S0_SYSTEM_POWER_STATE_VALUE_AC 1 +#define ATOM_S0_SYSTEM_POWER_STATE_VALUE_DC 2 +#define ATOM_S0_SYSTEM_POWER_STATE_VALUE_LITEAC 3 + +/* Byte aligned defintion for BIOS usage */ +#define ATOM_S0_CRT1_MONOb0 0x01 +#define ATOM_S0_CRT1_COLORb0 0x02 +#define ATOM_S0_CRT1_MASKb0 (ATOM_S0_CRT1_MONOb0+ATOM_S0_CRT1_COLORb0) + +#define ATOM_S0_TV1_COMPOSITEb0 0x04 +#define ATOM_S0_TV1_SVIDEOb0 0x08 +#define ATOM_S0_TV1_MASKb0 (ATOM_S0_TV1_COMPOSITEb0+ATOM_S0_TV1_SVIDEOb0) + +#define ATOM_S0_CVb0 0x10 +#define ATOM_S0_CV_DINb0 0x20 +#define ATOM_S0_CV_MASKb0 (ATOM_S0_CVb0+ATOM_S0_CV_DINb0) + +#define ATOM_S0_CRT2_MONOb1 0x01 +#define ATOM_S0_CRT2_COLORb1 0x02 +#define ATOM_S0_CRT2_MASKb1 (ATOM_S0_CRT2_MONOb1+ATOM_S0_CRT2_COLORb1) + +#define ATOM_S0_TV1_COMPOSITEb1 0x04 +#define ATOM_S0_TV1_SVIDEOb1 0x08 +#define ATOM_S0_TV1_SCARTb1 0x40 +#define ATOM_S0_TV1_MASKb1 (ATOM_S0_TV1_COMPOSITEb1+ATOM_S0_TV1_SVIDEOb1+ATOM_S0_TV1_SCARTb1) + +#define ATOM_S0_CVb1 0x10 +#define ATOM_S0_CV_DINb1 0x20 +#define ATOM_S0_CV_MASKb1 (ATOM_S0_CVb1+ATOM_S0_CV_DINb1) + +#define ATOM_S0_DFP1b2 0x01 +#define ATOM_S0_DFP2b2 0x02 +#define ATOM_S0_LCD1b2 0x04 +#define ATOM_S0_LCD2b2 0x08 +#define ATOM_S0_TV2b2 0x10 +#define ATOM_S0_DFP3b2 0x20 + +#define ATOM_S0_THERMAL_STATE_MASKb3 0x1C +#define ATOM_S0_THERMAL_STATE_SHIFTb3 2 + +#define ATOM_S0_SYSTEM_POWER_STATE_MASKb3 0xE0 +#define ATOM_S0_LCD1_SHIFT 18 + +/* BIOS_1_SCRATCH Definition */ +#define ATOM_S1_ROM_LOCATION_MASK 0x0000FFFFL +#define ATOM_S1_PCI_BUS_DEV_MASK 0xFFFF0000L + +/* BIOS_2_SCRATCH Definition */ +#define ATOM_S2_TV1_STANDARD_MASK 0x0000000FL +#define ATOM_S2_CURRENT_BL_LEVEL_MASK 0x0000FF00L +#define ATOM_S2_CURRENT_BL_LEVEL_SHIFT 8 + +#define ATOM_S2_CRT1_DPMS_STATE 0x00010000L +#define ATOM_S2_LCD1_DPMS_STATE 0x00020000L +#define ATOM_S2_TV1_DPMS_STATE 0x00040000L +#define ATOM_S2_DFP1_DPMS_STATE 0x00080000L +#define ATOM_S2_CRT2_DPMS_STATE 0x00100000L +#define ATOM_S2_LCD2_DPMS_STATE 0x00200000L +#define ATOM_S2_TV2_DPMS_STATE 0x00400000L +#define ATOM_S2_DFP2_DPMS_STATE 0x00800000L +#define ATOM_S2_CV_DPMS_STATE 0x01000000L +#define ATOM_S2_DFP3_DPMS_STATE 0x02000000L +#define ATOM_S2_DFP4_DPMS_STATE 0x04000000L +#define ATOM_S2_DFP5_DPMS_STATE 0x08000000L + +#define ATOM_S2_DFP_DPM_STATE \ + (ATOM_S2_DFP1_DPMS_STATE | ATOM_S2_DFP2_DPMS_STATE | \ + ATOM_S2_DFP3_DPMS_STATE | ATOM_S2_DFP4_DPMS_STATE | \ + ATOM_S2_DFP5_DPMS_STATE) + +#define ATOM_S2_DEVICE_DPMS_STATE \ + (ATOM_S2_CRT1_DPMS_STATE + ATOM_S2_LCD1_DPMS_STATE + \ + ATOM_S2_TV1_DPMS_STATE + ATOM_S2_DFP_DPMS_STATE + \ + ATOM_S2_CRT2_DPMS_STATE + ATOM_S2_LCD2_DPMS_STATE + \ + ATOM_S2_TV2_DPMS_STATE + ATOM_S2_CV_DPMS_STATE) + +#define ATOM_S2_FORCEDLOWPWRMODE_STATE_MASK 0x0C000000L +#define ATOM_S2_FORCEDLOWPWRMODE_STATE_MASK_SHIFT 26 +#define ATOM_S2_FORCEDLOWPWRMODE_STATE_CHANGE 0x10000000L + +#define ATOM_S2_VRI_BRIGHT_ENABLE 0x20000000L + +#define ATOM_S2_DISPLAY_ROTATION_0_DEGREE 0x0 +#define ATOM_S2_DISPLAY_ROTATION_90_DEGREE 0x1 +#define ATOM_S2_DISPLAY_ROTATION_180_DEGREE 0x2 +#define ATOM_S2_DISPLAY_ROTATION_270_DEGREE 0x3 +#define ATOM_S2_DISPLAY_ROTATION_DEGREE_SHIFT 30 +#define ATOM_S2_DISPLAY_ROTATION_ANGLE_MASK 0xC0000000L + +/* Byte aligned defintion for BIOS usage */ +#define ATOM_S2_TV1_STANDARD_MASKb0 0x0F +#define ATOM_S2_CURRENT_BL_LEVEL_MASKb1 0xFF +#define ATOM_S2_CRT1_DPMS_STATEb2 0x01 +#define ATOM_S2_LCD1_DPMS_STATEb2 0x02 +#define ATOM_S2_TV1_DPMS_STATEb2 0x04 +#define ATOM_S2_DFP1_DPMS_STATEb2 0x08 +#define ATOM_S2_CRT2_DPMS_STATEb2 0x10 +#define ATOM_S2_LCD2_DPMS_STATEb2 0x20 +#define ATOM_S2_TV2_DPMS_STATEb2 0x40 +#define ATOM_S2_DFP2_DPMS_STATEb2 0x80 +#define ATOM_S2_CV_DPMS_STATEb3 0x01 +#define ATOM_S2_DFP3_DPMS_STATEb3 0x02 +#define ATOM_S2_DFP4_DPMS_STATEb3 0x04 +#define ATOM_S2_DFP5_DPMS_STATEb3 0x08 + +#define ATOM_S2_DEVICE_DPMS_MASKw1 0x3FF +#define ATOM_S2_FORCEDLOWPWRMODE_STATE_MASKb3 0x0C +#define ATOM_S2_FORCEDLOWPWRMODE_STATE_CHANGEb3 0x10 +#define ATOM_S2_VRI_BRIGHT_ENABLEb3 0x20 +#define ATOM_S2_ROTATION_STATE_MASKb3 0xC0 + +/* BIOS_3_SCRATCH Definition */ +#define ATOM_S3_CRT1_ACTIVE 0x00000001L +#define ATOM_S3_LCD1_ACTIVE 0x00000002L +#define ATOM_S3_TV1_ACTIVE 0x00000004L +#define ATOM_S3_DFP1_ACTIVE 0x00000008L +#define ATOM_S3_CRT2_ACTIVE 0x00000010L +#define ATOM_S3_LCD2_ACTIVE 0x00000020L +#define ATOM_S3_TV2_ACTIVE 0x00000040L +#define ATOM_S3_DFP2_ACTIVE 0x00000080L +#define ATOM_S3_CV_ACTIVE 0x00000100L +#define ATOM_S3_DFP3_ACTIVE 0x00000200L +#define ATOM_S3_DFP4_ACTIVE 0x00000400L +#define ATOM_S3_DFP5_ACTIVE 0x00000800L + +#define ATOM_S3_DEVICE_ACTIVE_MASK 0x000003FFL + +#define ATOM_S3_LCD_FULLEXPANSION_ACTIVE 0x00001000L +#define ATOM_S3_LCD_EXPANSION_ASPEC_RATIO_ACTIVE 0x00002000L + +#define ATOM_S3_CRT1_CRTC_ACTIVE 0x00010000L +#define ATOM_S3_LCD1_CRTC_ACTIVE 0x00020000L +#define ATOM_S3_TV1_CRTC_ACTIVE 0x00040000L +#define ATOM_S3_DFP1_CRTC_ACTIVE 0x00080000L +#define ATOM_S3_CRT2_CRTC_ACTIVE 0x00100000L +#define ATOM_S3_LCD2_CRTC_ACTIVE 0x00200000L +#define ATOM_S3_TV2_CRTC_ACTIVE 0x00400000L +#define ATOM_S3_DFP2_CRTC_ACTIVE 0x00800000L +#define ATOM_S3_CV_CRTC_ACTIVE 0x01000000L +#define ATOM_S3_DFP3_CRTC_ACTIVE 0x02000000L +#define ATOM_S3_DFP4_CRTC_ACTIVE 0x04000000L +#define ATOM_S3_DFP5_CRTC_ACTIVE 0x08000000L + +#define ATOM_S3_DEVICE_CRTC_ACTIVE_MASK 0x0FFF0000L +#define ATOM_S3_ASIC_GUI_ENGINE_HUNG 0x20000000L +#define ATOM_S3_ALLOW_FAST_PWR_SWITCH 0x40000000L +#define ATOM_S3_RQST_GPU_USE_MIN_PWR 0x80000000L + +/* Byte aligned defintion for BIOS usage */ +#define ATOM_S3_CRT1_ACTIVEb0 0x01 +#define ATOM_S3_LCD1_ACTIVEb0 0x02 +#define ATOM_S3_TV1_ACTIVEb0 0x04 +#define ATOM_S3_DFP1_ACTIVEb0 0x08 +#define ATOM_S3_CRT2_ACTIVEb0 0x10 +#define ATOM_S3_LCD2_ACTIVEb0 0x20 +#define ATOM_S3_TV2_ACTIVEb0 0x40 +#define ATOM_S3_DFP2_ACTIVEb0 0x80 +#define ATOM_S3_CV_ACTIVEb1 0x01 +#define ATOM_S3_DFP3_ACTIVEb1 0x02 +#define ATOM_S3_DFP4_ACTIVEb1 0x04 +#define ATOM_S3_DFP5_ACTIVEb1 0x08 + +#define ATOM_S3_ACTIVE_CRTC1w0 0xFFF + +#define ATOM_S3_CRT1_CRTC_ACTIVEb2 0x01 +#define ATOM_S3_LCD1_CRTC_ACTIVEb2 0x02 +#define ATOM_S3_TV1_CRTC_ACTIVEb2 0x04 +#define ATOM_S3_DFP1_CRTC_ACTIVEb2 0x08 +#define ATOM_S3_CRT2_CRTC_ACTIVEb2 0x10 +#define ATOM_S3_LCD2_CRTC_ACTIVEb2 0x20 +#define ATOM_S3_TV2_CRTC_ACTIVEb2 0x40 +#define ATOM_S3_DFP2_CRTC_ACTIVEb2 0x80 +#define ATOM_S3_CV_CRTC_ACTIVEb3 0x01 +#define ATOM_S3_DFP3_CRTC_ACTIVEb3 0x02 +#define ATOM_S3_DFP4_CRTC_ACTIVEb3 0x04 +#define ATOM_S3_DFP5_CRTC_ACTIVEb3 0x08 + +#define ATOM_S3_ACTIVE_CRTC2w1 0xFFF + +#define ATOM_S3_ASIC_GUI_ENGINE_HUNGb3 0x20 +#define ATOM_S3_ALLOW_FAST_PWR_SWITCHb3 0x40 +#define ATOM_S3_RQST_GPU_USE_MIN_PWRb3 0x80 + +/* BIOS_4_SCRATCH Definition */ +#define ATOM_S4_LCD1_PANEL_ID_MASK 0x000000FFL +#define ATOM_S4_LCD1_REFRESH_MASK 0x0000FF00L +#define ATOM_S4_LCD1_REFRESH_SHIFT 8 + +/* Byte aligned defintion for BIOS usage */ +#define ATOM_S4_LCD1_PANEL_ID_MASKb0 0x0FF +#define ATOM_S4_LCD1_REFRESH_MASKb1 ATOM_S4_LCD1_PANEL_ID_MASKb0 +#define ATOM_S4_VRAM_INFO_MASKb2 ATOM_S4_LCD1_PANEL_ID_MASKb0 + +/* BIOS_5_SCRATCH Definition, BIOS_5_SCRATCH is used by Firmware only !!!! */ +#define ATOM_S5_DOS_REQ_CRT1b0 0x01 +#define ATOM_S5_DOS_REQ_LCD1b0 0x02 +#define ATOM_S5_DOS_REQ_TV1b0 0x04 +#define ATOM_S5_DOS_REQ_DFP1b0 0x08 +#define ATOM_S5_DOS_REQ_CRT2b0 0x10 +#define ATOM_S5_DOS_REQ_LCD2b0 0x20 +#define ATOM_S5_DOS_REQ_TV2b0 0x40 +#define ATOM_S5_DOS_REQ_DFP2b0 0x80 +#define ATOM_S5_DOS_REQ_CVb1 0x01 +#define ATOM_S5_DOS_REQ_DFP3b1 0x02 +#define ATOM_S5_DOS_REQ_DFP4b1 0x04 +#define ATOM_S5_DOS_REQ_DFP5b1 0x08 + +#define ATOM_S5_DOS_REQ_DEVICEw0 0x03FF + +#define ATOM_S5_DOS_REQ_CRT1 0x0001 +#define ATOM_S5_DOS_REQ_LCD1 0x0002 +#define ATOM_S5_DOS_REQ_TV1 0x0004 +#define ATOM_S5_DOS_REQ_DFP1 0x0008 +#define ATOM_S5_DOS_REQ_CRT2 0x0010 +#define ATOM_S5_DOS_REQ_LCD2 0x0020 +#define ATOM_S5_DOS_REQ_TV2 0x0040 +#define ATOM_S5_DOS_REQ_DFP2 0x0080 +#define ATOM_S5_DOS_REQ_CV 0x0100 +#define ATOM_S5_DOS_REQ_DFP3 0x0200 +#define ATOM_S5_DOS_REQ_DFP4 0x0400 +#define ATOM_S5_DOS_REQ_DFP5 0x0800 + +#define ATOM_S5_DOS_FORCE_CRT1b2 ATOM_S5_DOS_REQ_CRT1b0 +#define ATOM_S5_DOS_FORCE_TV1b2 ATOM_S5_DOS_REQ_TV1b0 +#define ATOM_S5_DOS_FORCE_CRT2b2 ATOM_S5_DOS_REQ_CRT2b0 +#define ATOM_S5_DOS_FORCE_CVb3 ATOM_S5_DOS_REQ_CVb1 +#define ATOM_S5_DOS_FORCE_DEVICEw1 \ + (ATOM_S5_DOS_FORCE_CRT1b2 + ATOM_S5_DOS_FORCE_TV1b2 + \ + ATOM_S5_DOS_FORCE_CRT2b2 + (ATOM_S5_DOS_FORCE_CVb3 << 8)) + +/* BIOS_6_SCRATCH Definition */ +#define ATOM_S6_DEVICE_CHANGE 0x00000001L +#define ATOM_S6_SCALER_CHANGE 0x00000002L +#define ATOM_S6_LID_CHANGE 0x00000004L +#define ATOM_S6_DOCKING_CHANGE 0x00000008L +#define ATOM_S6_ACC_MODE 0x00000010L +#define ATOM_S6_EXT_DESKTOP_MODE 0x00000020L +#define ATOM_S6_LID_STATE 0x00000040L +#define ATOM_S6_DOCK_STATE 0x00000080L +#define ATOM_S6_CRITICAL_STATE 0x00000100L +#define ATOM_S6_HW_I2C_BUSY_STATE 0x00000200L +#define ATOM_S6_THERMAL_STATE_CHANGE 0x00000400L +#define ATOM_S6_INTERRUPT_SET_BY_BIOS 0x00000800L +#define ATOM_S6_REQ_LCD_EXPANSION_FULL 0x00001000L /* Normal expansion Request bit for LCD */ +#define ATOM_S6_REQ_LCD_EXPANSION_ASPEC_RATIO 0x00002000L /* Aspect ratio expansion Request bit for LCD */ + +#define ATOM_S6_DISPLAY_STATE_CHANGE 0x00004000L /* This bit is recycled when ATOM_BIOS_INFO_BIOS_SCRATCH6_SCL2_REDEFINE is set,previously it's SCL2_H_expansion */ +#define ATOM_S6_I2C_STATE_CHANGE 0x00008000L /* This bit is recycled,when ATOM_BIOS_INFO_BIOS_SCRATCH6_SCL2_REDEFINE is set,previously it's SCL2_V_expansion */ + +#define ATOM_S6_ACC_REQ_CRT1 0x00010000L +#define ATOM_S6_ACC_REQ_LCD1 0x00020000L +#define ATOM_S6_ACC_REQ_TV1 0x00040000L +#define ATOM_S6_ACC_REQ_DFP1 0x00080000L +#define ATOM_S6_ACC_REQ_CRT2 0x00100000L +#define ATOM_S6_ACC_REQ_LCD2 0x00200000L +#define ATOM_S6_ACC_REQ_TV2 0x00400000L +#define ATOM_S6_ACC_REQ_DFP2 0x00800000L +#define ATOM_S6_ACC_REQ_CV 0x01000000L +#define ATOM_S6_ACC_REQ_DFP3 0x02000000L +#define ATOM_S6_ACC_REQ_DFP4 0x04000000L +#define ATOM_S6_ACC_REQ_DFP5 0x08000000L + +#define ATOM_S6_ACC_REQ_MASK 0x0FFF0000L +#define ATOM_S6_SYSTEM_POWER_MODE_CHANGE 0x10000000L +#define ATOM_S6_ACC_BLOCK_DISPLAY_SWITCH 0x20000000L +#define ATOM_S6_VRI_BRIGHTNESS_CHANGE 0x40000000L +#define ATOM_S6_CONFIG_DISPLAY_CHANGE_MASK 0x80000000L + +/* Byte aligned defintion for BIOS usage */ +#define ATOM_S6_DEVICE_CHANGEb0 0x01 +#define ATOM_S6_SCALER_CHANGEb0 0x02 +#define ATOM_S6_LID_CHANGEb0 0x04 +#define ATOM_S6_DOCKING_CHANGEb0 0x08 +#define ATOM_S6_ACC_MODEb0 0x10 +#define ATOM_S6_EXT_DESKTOP_MODEb0 0x20 +#define ATOM_S6_LID_STATEb0 0x40 +#define ATOM_S6_DOCK_STATEb0 0x80 +#define ATOM_S6_CRITICAL_STATEb1 0x01 +#define ATOM_S6_HW_I2C_BUSY_STATEb1 0x02 +#define ATOM_S6_THERMAL_STATE_CHANGEb1 0x04 +#define ATOM_S6_INTERRUPT_SET_BY_BIOSb1 0x08 +#define ATOM_S6_REQ_LCD_EXPANSION_FULLb1 0x10 +#define ATOM_S6_REQ_LCD_EXPANSION_ASPEC_RATIOb1 0x20 + +#define ATOM_S6_ACC_REQ_CRT1b2 0x01 +#define ATOM_S6_ACC_REQ_LCD1b2 0x02 +#define ATOM_S6_ACC_REQ_TV1b2 0x04 +#define ATOM_S6_ACC_REQ_DFP1b2 0x08 +#define ATOM_S6_ACC_REQ_CRT2b2 0x10 +#define ATOM_S6_ACC_REQ_LCD2b2 0x20 +#define ATOM_S6_ACC_REQ_TV2b2 0x40 +#define ATOM_S6_ACC_REQ_DFP2b2 0x80 +#define ATOM_S6_ACC_REQ_CVb3 0x01 +#define ATOM_S6_ACC_REQ_DFP3b3 0x02 +#define ATOM_S6_ACC_REQ_DFP4b3 0x04 +#define ATOM_S6_ACC_REQ_DFP5b3 0x08 + +#define ATOM_S6_ACC_REQ_DEVICEw1 ATOM_S5_DOS_REQ_DEVICEw0 +#define ATOM_S6_SYSTEM_POWER_MODE_CHANGEb3 0x10 +#define ATOM_S6_ACC_BLOCK_DISPLAY_SWITCHb3 0x20 +#define ATOM_S6_VRI_BRIGHTNESS_CHANGEb3 0x40 +#define ATOM_S6_CONFIG_DISPLAY_CHANGEb3 0x80 + +#define ATOM_S6_DEVICE_CHANGE_SHIFT 0 +#define ATOM_S6_SCALER_CHANGE_SHIFT 1 +#define ATOM_S6_LID_CHANGE_SHIFT 2 +#define ATOM_S6_DOCKING_CHANGE_SHIFT 3 +#define ATOM_S6_ACC_MODE_SHIFT 4 +#define ATOM_S6_EXT_DESKTOP_MODE_SHIFT 5 +#define ATOM_S6_LID_STATE_SHIFT 6 +#define ATOM_S6_DOCK_STATE_SHIFT 7 +#define ATOM_S6_CRITICAL_STATE_SHIFT 8 +#define ATOM_S6_HW_I2C_BUSY_STATE_SHIFT 9 +#define ATOM_S6_THERMAL_STATE_CHANGE_SHIFT 10 +#define ATOM_S6_INTERRUPT_SET_BY_BIOS_SHIFT 11 +#define ATOM_S6_REQ_SCALER_SHIFT 12 +#define ATOM_S6_REQ_SCALER_ARATIO_SHIFT 13 +#define ATOM_S6_DISPLAY_STATE_CHANGE_SHIFT 14 +#define ATOM_S6_I2C_STATE_CHANGE_SHIFT 15 +#define ATOM_S6_SYSTEM_POWER_MODE_CHANGE_SHIFT 28 +#define ATOM_S6_ACC_BLOCK_DISPLAY_SWITCH_SHIFT 29 +#define ATOM_S6_VRI_BRIGHTNESS_CHANGE_SHIFT 30 +#define ATOM_S6_CONFIG_DISPLAY_CHANGE_SHIFT 31 + +/* BIOS_7_SCRATCH Definition, BIOS_7_SCRATCH is used by Firmware only !!!! */ +#define ATOM_S7_DOS_MODE_TYPEb0 0x03 +#define ATOM_S7_DOS_MODE_VGAb0 0x00 +#define ATOM_S7_DOS_MODE_VESAb0 0x01 +#define ATOM_S7_DOS_MODE_EXTb0 0x02 +#define ATOM_S7_DOS_MODE_PIXEL_DEPTHb0 0x0C +#define ATOM_S7_DOS_MODE_PIXEL_FORMATb0 0xF0 +#define ATOM_S7_DOS_8BIT_DAC_ENb1 0x01 +#define ATOM_S7_DOS_MODE_NUMBERw1 0x0FFFF + +#define ATOM_S7_DOS_8BIT_DAC_EN_SHIFT 8 + +/* BIOS_8_SCRATCH Definition */ +#define ATOM_S8_I2C_CHANNEL_BUSY_MASK 0x00000FFFF +#define ATOM_S8_I2C_HW_ENGINE_BUSY_MASK 0x0FFFF0000 + +#define ATOM_S8_I2C_CHANNEL_BUSY_SHIFT 0 +#define ATOM_S8_I2C_ENGINE_BUSY_SHIFT 16 + +/* BIOS_9_SCRATCH Definition */ +#ifndef ATOM_S9_I2C_CHANNEL_COMPLETED_MASK +#define ATOM_S9_I2C_CHANNEL_COMPLETED_MASK 0x0000FFFF +#endif +#ifndef ATOM_S9_I2C_CHANNEL_ABORTED_MASK +#define ATOM_S9_I2C_CHANNEL_ABORTED_MASK 0xFFFF0000 +#endif +#ifndef ATOM_S9_I2C_CHANNEL_COMPLETED_SHIFT +#define ATOM_S9_I2C_CHANNEL_COMPLETED_SHIFT 0 +#endif +#ifndef ATOM_S9_I2C_CHANNEL_ABORTED_SHIFT +#define ATOM_S9_I2C_CHANNEL_ABORTED_SHIFT 16 +#endif + +#define ATOM_FLAG_SET 0x20 +#define ATOM_FLAG_CLEAR 0 +#define CLEAR_ATOM_S6_ACC_MODE \ + ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \ + ATOM_S6_ACC_MODE_SHIFT | ATOM_FLAG_CLEAR) +#define SET_ATOM_S6_DEVICE_CHANGE \ + ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \ + ATOM_S6_DEVICE_CHANGE_SHIFT | ATOM_FLAG_SET) +#define SET_ATOM_S6_VRI_BRIGHTNESS_CHANGE \ + ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \ + ATOM_S6_VRI_BRIGHTNESS_CHANGE_SHIFT | ATOM_FLAG_SET) +#define SET_ATOM_S6_SCALER_CHANGE \ + ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \ + ATOM_S6_SCALER_CHANGE_SHIFT | ATOM_FLAG_SET) +#define SET_ATOM_S6_LID_CHANGE \ + ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \ + ATOM_S6_LID_CHANGE_SHIFT | ATOM_FLAG_SET) + +#define SET_ATOM_S6_LID_STATE \ + ((ATOM_ACC_CHANGE_INFO_DEF << 8) |\ + ATOM_S6_LID_STATE_SHIFT | ATOM_FLAG_SET) +#define CLEAR_ATOM_S6_LID_STATE \ + ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \ + ATOM_S6_LID_STATE_SHIFT | ATOM_FLAG_CLEAR) + +#define SET_ATOM_S6_DOCK_CHANGE \ + ((ATOM_ACC_CHANGE_INFO_DEF << 8)| \ + ATOM_S6_DOCKING_CHANGE_SHIFT | ATOM_FLAG_SET) +#define SET_ATOM_S6_DOCK_STATE \ + ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \ + ATOM_S6_DOCK_STATE_SHIFT | ATOM_FLAG_SET) +#define CLEAR_ATOM_S6_DOCK_STATE \ + ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \ + ATOM_S6_DOCK_STATE_SHIFT | ATOM_FLAG_CLEAR) + +#define SET_ATOM_S6_THERMAL_STATE_CHANGE \ + ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \ + ATOM_S6_THERMAL_STATE_CHANGE_SHIFT | ATOM_FLAG_SET) +#define SET_ATOM_S6_SYSTEM_POWER_MODE_CHANGE \ + ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \ + ATOM_S6_SYSTEM_POWER_MODE_CHANGE_SHIFT | ATOM_FLAG_SET) +#define SET_ATOM_S6_INTERRUPT_SET_BY_BIOS \ + ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \ + ATOM_S6_INTERRUPT_SET_BY_BIOS_SHIFT | ATOM_FLAG_SET) + +#define SET_ATOM_S6_CRITICAL_STATE \ + ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \ + ATOM_S6_CRITICAL_STATE_SHIFT | ATOM_FLAG_SET) +#define CLEAR_ATOM_S6_CRITICAL_STATE \ + ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \ + ATOM_S6_CRITICAL_STATE_SHIFT | ATOM_FLAG_CLEAR) + +#define SET_ATOM_S6_REQ_SCALER \ + ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \ + ATOM_S6_REQ_SCALER_SHIFT | ATOM_FLAG_SET) +#define CLEAR_ATOM_S6_REQ_SCALER \ + ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \ + ATOM_S6_REQ_SCALER_SHIFT | ATOM_FLAG_CLEAR ) + +#define SET_ATOM_S6_REQ_SCALER_ARATIO \ + ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \ + ATOM_S6_REQ_SCALER_ARATIO_SHIFT | ATOM_FLAG_SET ) +#define CLEAR_ATOM_S6_REQ_SCALER_ARATIO \ + ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \ + ATOM_S6_REQ_SCALER_ARATIO_SHIFT | ATOM_FLAG_CLEAR ) + +#define SET_ATOM_S6_I2C_STATE_CHANGE \ + ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \ + ATOM_S6_I2C_STATE_CHANGE_SHIFT | ATOM_FLAG_SET ) + +#define SET_ATOM_S6_DISPLAY_STATE_CHANGE \ + ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \ + ATOM_S6_DISPLAY_STATE_CHANGE_SHIFT | ATOM_FLAG_SET ) + +#define SET_ATOM_S6_DEVICE_RECONFIG \ + ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \ + ATOM_S6_CONFIG_DISPLAY_CHANGE_SHIFT | ATOM_FLAG_SET) +#define CLEAR_ATOM_S0_LCD1 \ + ((ATOM_DEVICE_CONNECT_INFO_DEF << 8 ) | \ + ATOM_S0_LCD1_SHIFT | ATOM_FLAG_CLEAR ) +#define SET_ATOM_S7_DOS_8BIT_DAC_EN \ + ((ATOM_DOS_MODE_INFO_DEF << 8) | \ + ATOM_S7_DOS_8BIT_DAC_EN_SHIFT | ATOM_FLAG_SET ) +#define CLEAR_ATOM_S7_DOS_8BIT_DAC_EN \ + ((ATOM_DOS_MODE_INFO_DEF << 8) | \ + ATOM_S7_DOS_8BIT_DAC_EN_SHIFT | ATOM_FLAG_CLEAR ) + +/****************************************************************************/ +/* Portion II: Definitinos only used in Driver */ +/****************************************************************************/ + +/* Macros used by driver */ + +#define GetIndexIntoMasterTable(MasterOrData, FieldName) (((char *)(&((ATOM_MASTER_LIST_OF_##MasterOrData##_TABLES *)0)->FieldName)-(char *)0)/sizeof(USHORT)) + +#define GET_COMMAND_TABLE_COMMANDSET_REVISION(TABLE_HEADER_OFFSET) ((((ATOM_COMMON_TABLE_HEADER*)TABLE_HEADER_OFFSET)->ucTableFormatRevision)&0x3F) +#define GET_COMMAND_TABLE_PARAMETER_REVISION(TABLE_HEADER_OFFSET) ((((ATOM_COMMON_TABLE_HEADER*)TABLE_HEADER_OFFSET)->ucTableContentRevision)&0x3F) + +#define GET_DATA_TABLE_MAJOR_REVISION GET_COMMAND_TABLE_COMMANDSET_REVISION +#define GET_DATA_TABLE_MINOR_REVISION GET_COMMAND_TABLE_PARAMETER_REVISION + +/****************************************************************************/ +/* Portion III: Definitinos only used in VBIOS */ +/****************************************************************************/ +#define ATOM_DAC_SRC 0x80 +#define ATOM_SRC_DAC1 0 +#define ATOM_SRC_DAC2 0x80 + +#ifdef UEFI_BUILD +#define USHORT UTEMP +#endif + +typedef struct _MEMORY_PLLINIT_PARAMETERS { + ULONG ulTargetMemoryClock; /* In 10Khz unit */ + UCHAR ucAction; /* not define yet */ + UCHAR ucFbDiv_Hi; /* Fbdiv Hi byte */ + UCHAR ucFbDiv; /* FB value */ + UCHAR ucPostDiv; /* Post div */ +} MEMORY_PLLINIT_PARAMETERS; + +#define MEMORY_PLLINIT_PS_ALLOCATION MEMORY_PLLINIT_PARAMETERS + +#define GPIO_PIN_WRITE 0x01 +#define GPIO_PIN_READ 0x00 + +typedef struct _GPIO_PIN_CONTROL_PARAMETERS { + UCHAR ucGPIO_ID; /* return value, read from GPIO pins */ + UCHAR ucGPIOBitShift; /* define which bit in uGPIOBitVal need to be update */ + UCHAR ucGPIOBitVal; /* Set/Reset corresponding bit defined in ucGPIOBitMask */ + UCHAR ucAction; /* =GPIO_PIN_WRITE: Read; =GPIO_PIN_READ: Write */ +} GPIO_PIN_CONTROL_PARAMETERS; + +typedef struct _ENABLE_SCALER_PARAMETERS { + UCHAR ucScaler; /* ATOM_SCALER1, ATOM_SCALER2 */ + UCHAR ucEnable; /* ATOM_SCALER_DISABLE or ATOM_SCALER_CENTER or ATOM_SCALER_EXPANSION */ + UCHAR ucTVStandard; /* */ + UCHAR ucPadding[1]; +} ENABLE_SCALER_PARAMETERS; +#define ENABLE_SCALER_PS_ALLOCATION ENABLE_SCALER_PARAMETERS + +/* ucEnable: */ +#define SCALER_BYPASS_AUTO_CENTER_NO_REPLICATION 0 +#define SCALER_BYPASS_AUTO_CENTER_AUTO_REPLICATION 1 +#define SCALER_ENABLE_2TAP_ALPHA_MODE 2 +#define SCALER_ENABLE_MULTITAP_MODE 3 + +typedef struct _ENABLE_HARDWARE_ICON_CURSOR_PARAMETERS { + ULONG usHWIconHorzVertPosn; /* Hardware Icon Vertical position */ + UCHAR ucHWIconVertOffset; /* Hardware Icon Vertical offset */ + UCHAR ucHWIconHorzOffset; /* Hardware Icon Horizontal offset */ + UCHAR ucSelection; /* ATOM_CURSOR1 or ATOM_ICON1 or ATOM_CURSOR2 or ATOM_ICON2 */ + UCHAR ucEnable; /* ATOM_ENABLE or ATOM_DISABLE */ +} ENABLE_HARDWARE_ICON_CURSOR_PARAMETERS; + +typedef struct _ENABLE_HARDWARE_ICON_CURSOR_PS_ALLOCATION { + ENABLE_HARDWARE_ICON_CURSOR_PARAMETERS sEnableIcon; + ENABLE_CRTC_PARAMETERS sReserved; +} ENABLE_HARDWARE_ICON_CURSOR_PS_ALLOCATION; + +typedef struct _ENABLE_GRAPH_SURFACE_PARAMETERS { + USHORT usHight; /* Image Hight */ + USHORT usWidth; /* Image Width */ + UCHAR ucSurface; /* Surface 1 or 2 */ + UCHAR ucPadding[3]; +} ENABLE_GRAPH_SURFACE_PARAMETERS; + +typedef struct _ENABLE_GRAPH_SURFACE_PARAMETERS_V1_2 { + USHORT usHight; /* Image Hight */ + USHORT usWidth; /* Image Width */ + UCHAR ucSurface; /* Surface 1 or 2 */ + UCHAR ucEnable; /* ATOM_ENABLE or ATOM_DISABLE */ + UCHAR ucPadding[2]; +} ENABLE_GRAPH_SURFACE_PARAMETERS_V1_2; + +typedef struct _ENABLE_GRAPH_SURFACE_PS_ALLOCATION { + ENABLE_GRAPH_SURFACE_PARAMETERS sSetSurface; + ENABLE_YUV_PS_ALLOCATION sReserved; /* Don't set this one */ +} ENABLE_GRAPH_SURFACE_PS_ALLOCATION; + +typedef struct _MEMORY_CLEAN_UP_PARAMETERS { + USHORT usMemoryStart; /* in 8Kb boundry, offset from memory base address */ + USHORT usMemorySize; /* 8Kb blocks aligned */ +} MEMORY_CLEAN_UP_PARAMETERS; +#define MEMORY_CLEAN_UP_PS_ALLOCATION MEMORY_CLEAN_UP_PARAMETERS + +typedef struct _GET_DISPLAY_SURFACE_SIZE_PARAMETERS { + USHORT usX_Size; /* When use as input parameter, usX_Size indicates which CRTC */ + USHORT usY_Size; +} GET_DISPLAY_SURFACE_SIZE_PARAMETERS; + +typedef struct _INDIRECT_IO_ACCESS { + ATOM_COMMON_TABLE_HEADER sHeader; + UCHAR IOAccessSequence[256]; +} INDIRECT_IO_ACCESS; + +#define INDIRECT_READ 0x00 +#define INDIRECT_WRITE 0x80 + +#define INDIRECT_IO_MM 0 +#define INDIRECT_IO_PLL 1 +#define INDIRECT_IO_MC 2 +#define INDIRECT_IO_PCIE 3 +#define INDIRECT_IO_PCIEP 4 +#define INDIRECT_IO_NBMISC 5 + +#define INDIRECT_IO_PLL_READ INDIRECT_IO_PLL | INDIRECT_READ +#define INDIRECT_IO_PLL_WRITE INDIRECT_IO_PLL | INDIRECT_WRITE +#define INDIRECT_IO_MC_READ INDIRECT_IO_MC | INDIRECT_READ +#define INDIRECT_IO_MC_WRITE INDIRECT_IO_MC | INDIRECT_WRITE +#define INDIRECT_IO_PCIE_READ INDIRECT_IO_PCIE | INDIRECT_READ +#define INDIRECT_IO_PCIE_WRITE INDIRECT_IO_PCIE | INDIRECT_WRITE +#define INDIRECT_IO_PCIEP_READ INDIRECT_IO_PCIEP | INDIRECT_READ +#define INDIRECT_IO_PCIEP_WRITE INDIRECT_IO_PCIEP | INDIRECT_WRITE +#define INDIRECT_IO_NBMISC_READ INDIRECT_IO_NBMISC | INDIRECT_READ +#define INDIRECT_IO_NBMISC_WRITE INDIRECT_IO_NBMISC | INDIRECT_WRITE + +typedef struct _ATOM_OEM_INFO { + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_I2C_ID_CONFIG_ACCESS sucI2cId; +} ATOM_OEM_INFO; + +typedef struct _ATOM_TV_MODE { + UCHAR ucVMode_Num; /* Video mode number */ + UCHAR ucTV_Mode_Num; /* Internal TV mode number */ +} ATOM_TV_MODE; + +typedef struct _ATOM_BIOS_INT_TVSTD_MODE { + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT usTV_Mode_LUT_Offset; /* Pointer to standard to internal number conversion table */ + USHORT usTV_FIFO_Offset; /* Pointer to FIFO entry table */ + USHORT usNTSC_Tbl_Offset; /* Pointer to SDTV_Mode_NTSC table */ + USHORT usPAL_Tbl_Offset; /* Pointer to SDTV_Mode_PAL table */ + USHORT usCV_Tbl_Offset; /* Pointer to SDTV_Mode_PAL table */ +} ATOM_BIOS_INT_TVSTD_MODE; + +typedef struct _ATOM_TV_MODE_SCALER_PTR { + USHORT ucFilter0_Offset; /* Pointer to filter format 0 coefficients */ + USHORT usFilter1_Offset; /* Pointer to filter format 0 coefficients */ + UCHAR ucTV_Mode_Num; +} ATOM_TV_MODE_SCALER_PTR; + +typedef struct _ATOM_STANDARD_VESA_TIMING { + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_DTD_FORMAT aModeTimings[16]; /* 16 is not the real array number, just for initial allocation */ +} ATOM_STANDARD_VESA_TIMING; + +typedef struct _ATOM_STD_FORMAT { + USHORT usSTD_HDisp; + USHORT usSTD_VDisp; + USHORT usSTD_RefreshRate; + USHORT usReserved; +} ATOM_STD_FORMAT; + +typedef struct _ATOM_VESA_TO_EXTENDED_MODE { + USHORT usVESA_ModeNumber; + USHORT usExtendedModeNumber; +} ATOM_VESA_TO_EXTENDED_MODE; + +typedef struct _ATOM_VESA_TO_INTENAL_MODE_LUT { + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_VESA_TO_EXTENDED_MODE asVESA_ToExtendedModeInfo[76]; +} ATOM_VESA_TO_INTENAL_MODE_LUT; + +/*************** ATOM Memory Related Data Structure ***********************/ +typedef struct _ATOM_MEMORY_VENDOR_BLOCK { + UCHAR ucMemoryType; + UCHAR ucMemoryVendor; + UCHAR ucAdjMCId; + UCHAR ucDynClkId; + ULONG ulDllResetClkRange; +} ATOM_MEMORY_VENDOR_BLOCK; + +typedef struct _ATOM_MEMORY_SETTING_ID_CONFIG { +#if ATOM_BIG_ENDIAN + ULONG ucMemBlkId:8; + ULONG ulMemClockRange:24; +#else + ULONG ulMemClockRange:24; + ULONG ucMemBlkId:8; +#endif +} ATOM_MEMORY_SETTING_ID_CONFIG; + +typedef union _ATOM_MEMORY_SETTING_ID_CONFIG_ACCESS { + ATOM_MEMORY_SETTING_ID_CONFIG slAccess; + ULONG ulAccess; +} ATOM_MEMORY_SETTING_ID_CONFIG_ACCESS; + +typedef struct _ATOM_MEMORY_SETTING_DATA_BLOCK { + ATOM_MEMORY_SETTING_ID_CONFIG_ACCESS ulMemoryID; + ULONG aulMemData[1]; +} ATOM_MEMORY_SETTING_DATA_BLOCK; + +typedef struct _ATOM_INIT_REG_INDEX_FORMAT { + USHORT usRegIndex; /* MC register index */ + UCHAR ucPreRegDataLength; /* offset in ATOM_INIT_REG_DATA_BLOCK.saRegDataBuf */ +} ATOM_INIT_REG_INDEX_FORMAT; + +typedef struct _ATOM_INIT_REG_BLOCK { + USHORT usRegIndexTblSize; /* size of asRegIndexBuf */ + USHORT usRegDataBlkSize; /* size of ATOM_MEMORY_SETTING_DATA_BLOCK */ + ATOM_INIT_REG_INDEX_FORMAT asRegIndexBuf[1]; + ATOM_MEMORY_SETTING_DATA_BLOCK asRegDataBuf[1]; +} ATOM_INIT_REG_BLOCK; + +#define END_OF_REG_INDEX_BLOCK 0x0ffff +#define END_OF_REG_DATA_BLOCK 0x00000000 +#define ATOM_INIT_REG_MASK_FLAG 0x80 +#define CLOCK_RANGE_HIGHEST 0x00ffffff + +#define VALUE_DWORD SIZEOF ULONG +#define VALUE_SAME_AS_ABOVE 0 +#define VALUE_MASK_DWORD 0x84 + +#define INDEX_ACCESS_RANGE_BEGIN (VALUE_DWORD + 1) +#define INDEX_ACCESS_RANGE_END (INDEX_ACCESS_RANGE_BEGIN + 1) +#define VALUE_INDEX_ACCESS_SINGLE (INDEX_ACCESS_RANGE_END + 1) + +typedef struct _ATOM_MC_INIT_PARAM_TABLE { + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT usAdjustARB_SEQDataOffset; + USHORT usMCInitMemTypeTblOffset; + USHORT usMCInitCommonTblOffset; + USHORT usMCInitPowerDownTblOffset; + ULONG ulARB_SEQDataBuf[32]; + ATOM_INIT_REG_BLOCK asMCInitMemType; + ATOM_INIT_REG_BLOCK asMCInitCommon; +} ATOM_MC_INIT_PARAM_TABLE; + +#define _4Mx16 0x2 +#define _4Mx32 0x3 +#define _8Mx16 0x12 +#define _8Mx32 0x13 +#define _16Mx16 0x22 +#define _16Mx32 0x23 +#define _32Mx16 0x32 +#define _32Mx32 0x33 +#define _64Mx8 0x41 +#define _64Mx16 0x42 + +#define SAMSUNG 0x1 +#define INFINEON 0x2 +#define ELPIDA 0x3 +#define ETRON 0x4 +#define NANYA 0x5 +#define HYNIX 0x6 +#define MOSEL 0x7 +#define WINBOND 0x8 +#define ESMT 0x9 +#define MICRON 0xF + +#define QIMONDA INFINEON +#define PROMOS MOSEL + +/* ///////////Support for GDDR5 MC uCode to reside in upper 64K of ROM///////////// */ + +#define UCODE_ROM_START_ADDRESS 0x1c000 +#define UCODE_SIGNATURE 0x4375434d /* 'MCuC' - MC uCode */ + +/* uCode block header for reference */ + +typedef struct _MCuCodeHeader { + ULONG ulSignature; + UCHAR ucRevision; + UCHAR ucChecksum; + UCHAR ucReserved1; + UCHAR ucReserved2; + USHORT usParametersLength; + USHORT usUCodeLength; + USHORT usReserved1; + USHORT usReserved2; +} MCuCodeHeader; + +/* //////////////////////////////////////////////////////////////////////////////// */ + +#define ATOM_MAX_NUMBER_OF_VRAM_MODULE 16 + +#define ATOM_VRAM_MODULE_MEMORY_VENDOR_ID_MASK 0xF +typedef struct _ATOM_VRAM_MODULE_V1 { + ULONG ulReserved; + USHORT usEMRSValue; + USHORT usMRSValue; + USHORT usReserved; + UCHAR ucExtMemoryID; /* An external indicator (by hardcode, callback or pin) to tell what is the current memory module */ + UCHAR ucMemoryType; /* [7:4]=0x1:DDR1;=0x2:DDR2;=0x3:DDR3;=0x4:DDR4;[3:0] reserved; */ + UCHAR ucMemoryVenderID; /* Predefined,never change across designs or memory type/vender */ + UCHAR ucMemoryDeviceCfg; /* [7:4]=0x0:4M;=0x1:8M;=0x2:16M;0x3:32M....[3:0]=0x0:x4;=0x1:x8;=0x2:x16;=0x3:x32... */ + UCHAR ucRow; /* Number of Row,in power of 2; */ + UCHAR ucColumn; /* Number of Column,in power of 2; */ + UCHAR ucBank; /* Nunber of Bank; */ + UCHAR ucRank; /* Number of Rank, in power of 2 */ + UCHAR ucChannelNum; /* Number of channel; */ + UCHAR ucChannelConfig; /* [3:0]=Indication of what channel combination;[4:7]=Channel bit width, in number of 2 */ + UCHAR ucDefaultMVDDQ_ID; /* Default MVDDQ setting for this memory block, ID linking to MVDDQ info table to find real set-up data; */ + UCHAR ucDefaultMVDDC_ID; /* Default MVDDC setting for this memory block, ID linking to MVDDC info table to find real set-up data; */ + UCHAR ucReserved[2]; +} ATOM_VRAM_MODULE_V1; + +typedef struct _ATOM_VRAM_MODULE_V2 { + ULONG ulReserved; + ULONG ulFlags; /* To enable/disable functionalities based on memory type */ + ULONG ulEngineClock; /* Override of default engine clock for particular memory type */ + ULONG ulMemoryClock; /* Override of default memory clock for particular memory type */ + USHORT usEMRS2Value; /* EMRS2 Value is used for GDDR2 and GDDR4 memory type */ + USHORT usEMRS3Value; /* EMRS3 Value is used for GDDR2 and GDDR4 memory type */ + USHORT usEMRSValue; + USHORT usMRSValue; + USHORT usReserved; + UCHAR ucExtMemoryID; /* An external indicator (by hardcode, callback or pin) to tell what is the current memory module */ + UCHAR ucMemoryType; /* [7:4]=0x1:DDR1;=0x2:DDR2;=0x3:DDR3;=0x4:DDR4;[3:0] - must not be used for now; */ + UCHAR ucMemoryVenderID; /* Predefined,never change across designs or memory type/vender. If not predefined, vendor detection table gets executed */ + UCHAR ucMemoryDeviceCfg; /* [7:4]=0x0:4M;=0x1:8M;=0x2:16M;0x3:32M....[3:0]=0x0:x4;=0x1:x8;=0x2:x16;=0x3:x32... */ + UCHAR ucRow; /* Number of Row,in power of 2; */ + UCHAR ucColumn; /* Number of Column,in power of 2; */ + UCHAR ucBank; /* Nunber of Bank; */ + UCHAR ucRank; /* Number of Rank, in power of 2 */ + UCHAR ucChannelNum; /* Number of channel; */ + UCHAR ucChannelConfig; /* [3:0]=Indication of what channel combination;[4:7]=Channel bit width, in number of 2 */ + UCHAR ucDefaultMVDDQ_ID; /* Default MVDDQ setting for this memory block, ID linking to MVDDQ info table to find real set-up data; */ + UCHAR ucDefaultMVDDC_ID; /* Default MVDDC setting for this memory block, ID linking to MVDDC info table to find real set-up data; */ + UCHAR ucRefreshRateFactor; + UCHAR ucReserved[3]; +} ATOM_VRAM_MODULE_V2; + +typedef struct _ATOM_MEMORY_TIMING_FORMAT { + ULONG ulClkRange; /* memory clock in 10kHz unit, when target memory clock is below this clock, use this memory timing */ + union { + USHORT usMRS; /* mode register */ + USHORT usDDR3_MR0; + }; + union { + USHORT usEMRS; /* extended mode register */ + USHORT usDDR3_MR1; + }; + UCHAR ucCL; /* CAS latency */ + UCHAR ucWL; /* WRITE Latency */ + UCHAR uctRAS; /* tRAS */ + UCHAR uctRC; /* tRC */ + UCHAR uctRFC; /* tRFC */ + UCHAR uctRCDR; /* tRCDR */ + UCHAR uctRCDW; /* tRCDW */ + UCHAR uctRP; /* tRP */ + UCHAR uctRRD; /* tRRD */ + UCHAR uctWR; /* tWR */ + UCHAR uctWTR; /* tWTR */ + UCHAR uctPDIX; /* tPDIX */ + UCHAR uctFAW; /* tFAW */ + UCHAR uctAOND; /* tAOND */ + union { + struct { + UCHAR ucflag; /* flag to control memory timing calculation. bit0= control EMRS2 Infineon */ + UCHAR ucReserved; + }; + USHORT usDDR3_MR2; + }; +} ATOM_MEMORY_TIMING_FORMAT; + +typedef struct _ATOM_MEMORY_TIMING_FORMAT_V1 { + ULONG ulClkRange; /* memory clock in 10kHz unit, when target memory clock is below this clock, use this memory timing */ + USHORT usMRS; /* mode register */ + USHORT usEMRS; /* extended mode register */ + UCHAR ucCL; /* CAS latency */ + UCHAR ucWL; /* WRITE Latency */ + UCHAR uctRAS; /* tRAS */ + UCHAR uctRC; /* tRC */ + UCHAR uctRFC; /* tRFC */ + UCHAR uctRCDR; /* tRCDR */ + UCHAR uctRCDW; /* tRCDW */ + UCHAR uctRP; /* tRP */ + UCHAR uctRRD; /* tRRD */ + UCHAR uctWR; /* tWR */ + UCHAR uctWTR; /* tWTR */ + UCHAR uctPDIX; /* tPDIX */ + UCHAR uctFAW; /* tFAW */ + UCHAR uctAOND; /* tAOND */ + UCHAR ucflag; /* flag to control memory timing calculation. bit0= control EMRS2 Infineon */ +/* ///////////////////////GDDR parameters/////////////////////////////////// */ + UCHAR uctCCDL; /* */ + UCHAR uctCRCRL; /* */ + UCHAR uctCRCWL; /* */ + UCHAR uctCKE; /* */ + UCHAR uctCKRSE; /* */ + UCHAR uctCKRSX; /* */ + UCHAR uctFAW32; /* */ + UCHAR ucReserved1; /* */ + UCHAR ucReserved2; /* */ + UCHAR ucTerminator; +} ATOM_MEMORY_TIMING_FORMAT_V1; + +typedef struct _ATOM_MEMORY_FORMAT { + ULONG ulDllDisClock; /* memory DLL will be disable when target memory clock is below this clock */ + union { + USHORT usEMRS2Value; /* EMRS2 Value is used for GDDR2 and GDDR4 memory type */ + USHORT usDDR3_Reserved; /* Not used for DDR3 memory */ + }; + union { + USHORT usEMRS3Value; /* EMRS3 Value is used for GDDR2 and GDDR4 memory type */ + USHORT usDDR3_MR3; /* Used for DDR3 memory */ + }; + UCHAR ucMemoryType; /* [7:4]=0x1:DDR1;=0x2:DDR2;=0x3:DDR3;=0x4:DDR4;[3:0] - must not be used for now; */ + UCHAR ucMemoryVenderID; /* Predefined,never change across designs or memory type/vender. If not predefined, vendor detection table gets executed */ + UCHAR ucRow; /* Number of Row,in power of 2; */ + UCHAR ucColumn; /* Number of Column,in power of 2; */ + UCHAR ucBank; /* Nunber of Bank; */ + UCHAR ucRank; /* Number of Rank, in power of 2 */ + UCHAR ucBurstSize; /* burst size, 0= burst size=4 1= burst size=8 */ + UCHAR ucDllDisBit; /* position of DLL Enable/Disable bit in EMRS ( Extended Mode Register ) */ + UCHAR ucRefreshRateFactor; /* memory refresh rate in unit of ms */ + UCHAR ucDensity; /* _8Mx32, _16Mx32, _16Mx16, _32Mx16 */ + UCHAR ucPreamble; /* [7:4] Write Preamble, [3:0] Read Preamble */ + UCHAR ucMemAttrib; /* Memory Device Addribute, like RDBI/WDBI etc */ + ATOM_MEMORY_TIMING_FORMAT asMemTiming[5]; /* Memory Timing block sort from lower clock to higher clock */ +} ATOM_MEMORY_FORMAT; + +typedef struct _ATOM_VRAM_MODULE_V3 { + ULONG ulChannelMapCfg; /* board dependent paramenter:Channel combination */ + USHORT usSize; /* size of ATOM_VRAM_MODULE_V3 */ + USHORT usDefaultMVDDQ; /* board dependent parameter:Default Memory Core Voltage */ + USHORT usDefaultMVDDC; /* board dependent parameter:Default Memory IO Voltage */ + UCHAR ucExtMemoryID; /* An external indicator (by hardcode, callback or pin) to tell what is the current memory module */ + UCHAR ucChannelNum; /* board dependent parameter:Number of channel; */ + UCHAR ucChannelSize; /* board dependent parameter:32bit or 64bit */ + UCHAR ucVREFI; /* board dependnt parameter: EXT or INT +160mv to -140mv */ + UCHAR ucNPL_RT; /* board dependent parameter:NPL round trip delay, used for calculate memory timing parameters */ + UCHAR ucFlag; /* To enable/disable functionalities based on memory type */ + ATOM_MEMORY_FORMAT asMemory; /* describ all of video memory parameters from memory spec */ +} ATOM_VRAM_MODULE_V3; + +/* ATOM_VRAM_MODULE_V3.ucNPL_RT */ +#define NPL_RT_MASK 0x0f +#define BATTERY_ODT_MASK 0xc0 + +#define ATOM_VRAM_MODULE ATOM_VRAM_MODULE_V3 + +typedef struct _ATOM_VRAM_MODULE_V4 { + ULONG ulChannelMapCfg; /* board dependent parameter: Channel combination */ + USHORT usModuleSize; /* size of ATOM_VRAM_MODULE_V4, make it easy for VBIOS to look for next entry of VRAM_MODULE */ + USHORT usPrivateReserved; /* BIOS internal reserved space to optimize code size, updated by the compiler, shouldn't be modified manually!! */ + /* MC_ARB_RAMCFG (includes NOOFBANK,NOOFRANKS,NOOFROWS,NOOFCOLS) */ + USHORT usReserved; + UCHAR ucExtMemoryID; /* An external indicator (by hardcode, callback or pin) to tell what is the current memory module */ + UCHAR ucMemoryType; /* [7:4]=0x1:DDR1;=0x2:DDR2;=0x3:DDR3;=0x4:DDR4; 0x5:DDR5 [3:0] - Must be 0x0 for now; */ + UCHAR ucChannelNum; /* Number of channels present in this module config */ + UCHAR ucChannelWidth; /* 0 - 32 bits; 1 - 64 bits */ + UCHAR ucDensity; /* _8Mx32, _16Mx32, _16Mx16, _32Mx16 */ + UCHAR ucFlag; /* To enable/disable functionalities based on memory type */ + UCHAR ucMisc; /* bit0: 0 - single rank; 1 - dual rank; bit2: 0 - burstlength 4, 1 - burstlength 8 */ + UCHAR ucVREFI; /* board dependent parameter */ + UCHAR ucNPL_RT; /* board dependent parameter:NPL round trip delay, used for calculate memory timing parameters */ + UCHAR ucPreamble; /* [7:4] Write Preamble, [3:0] Read Preamble */ + UCHAR ucMemorySize; /* BIOS internal reserved space to optimize code size, updated by the compiler, shouldn't be modified manually!! */ + /* Total memory size in unit of 16MB for CONFIG_MEMSIZE - bit[23:0] zeros */ + UCHAR ucReserved[3]; + +/* compare with V3, we flat the struct by merging ATOM_MEMORY_FORMAT (as is) into V4 as the same level */ + union { + USHORT usEMRS2Value; /* EMRS2 Value is used for GDDR2 and GDDR4 memory type */ + USHORT usDDR3_Reserved; + }; + union { + USHORT usEMRS3Value; /* EMRS3 Value is used for GDDR2 and GDDR4 memory type */ + USHORT usDDR3_MR3; /* Used for DDR3 memory */ + }; + UCHAR ucMemoryVenderID; /* Predefined, If not predefined, vendor detection table gets executed */ + UCHAR ucRefreshRateFactor; /* [1:0]=RefreshFactor (00=8ms, 01=16ms, 10=32ms,11=64ms) */ + UCHAR ucReserved2[2]; + ATOM_MEMORY_TIMING_FORMAT asMemTiming[5]; /* Memory Timing block sort from lower clock to higher clock */ +} ATOM_VRAM_MODULE_V4; + +#define VRAM_MODULE_V4_MISC_RANK_MASK 0x3 +#define VRAM_MODULE_V4_MISC_DUAL_RANK 0x1 +#define VRAM_MODULE_V4_MISC_BL_MASK 0x4 +#define VRAM_MODULE_V4_MISC_BL8 0x4 +#define VRAM_MODULE_V4_MISC_DUAL_CS 0x10 + +typedef struct _ATOM_VRAM_MODULE_V5 { + ULONG ulChannelMapCfg; /* board dependent parameter: Channel combination */ + USHORT usModuleSize; /* size of ATOM_VRAM_MODULE_V4, make it easy for VBIOS to look for next entry of VRAM_MODULE */ + USHORT usPrivateReserved; /* BIOS internal reserved space to optimize code size, updated by the compiler, shouldn't be modified manually!! */ + /* MC_ARB_RAMCFG (includes NOOFBANK,NOOFRANKS,NOOFROWS,NOOFCOLS) */ + USHORT usReserved; + UCHAR ucExtMemoryID; /* An external indicator (by hardcode, callback or pin) to tell what is the current memory module */ + UCHAR ucMemoryType; /* [7:4]=0x1:DDR1;=0x2:DDR2;=0x3:DDR3;=0x4:DDR4; 0x5:DDR5 [3:0] - Must be 0x0 for now; */ + UCHAR ucChannelNum; /* Number of channels present in this module config */ + UCHAR ucChannelWidth; /* 0 - 32 bits; 1 - 64 bits */ + UCHAR ucDensity; /* _8Mx32, _16Mx32, _16Mx16, _32Mx16 */ + UCHAR ucFlag; /* To enable/disable functionalities based on memory type */ + UCHAR ucMisc; /* bit0: 0 - single rank; 1 - dual rank; bit2: 0 - burstlength 4, 1 - burstlength 8 */ + UCHAR ucVREFI; /* board dependent parameter */ + UCHAR ucNPL_RT; /* board dependent parameter:NPL round trip delay, used for calculate memory timing parameters */ + UCHAR ucPreamble; /* [7:4] Write Preamble, [3:0] Read Preamble */ + UCHAR ucMemorySize; /* BIOS internal reserved space to optimize code size, updated by the compiler, shouldn't be modified manually!! */ + /* Total memory size in unit of 16MB for CONFIG_MEMSIZE - bit[23:0] zeros */ + UCHAR ucReserved[3]; + +/* compare with V3, we flat the struct by merging ATOM_MEMORY_FORMAT (as is) into V4 as the same level */ + USHORT usEMRS2Value; /* EMRS2 Value is used for GDDR2 and GDDR4 memory type */ + USHORT usEMRS3Value; /* EMRS3 Value is used for GDDR2 and GDDR4 memory type */ + UCHAR ucMemoryVenderID; /* Predefined, If not predefined, vendor detection table gets executed */ + UCHAR ucRefreshRateFactor; /* [1:0]=RefreshFactor (00=8ms, 01=16ms, 10=32ms,11=64ms) */ + UCHAR ucFIFODepth; /* FIFO depth supposes to be detected during vendor detection, but if we dont do vendor detection we have to hardcode FIFO Depth */ + UCHAR ucCDR_Bandwidth; /* [0:3]=Read CDR bandwidth, [4:7] - Write CDR Bandwidth */ + ATOM_MEMORY_TIMING_FORMAT_V1 asMemTiming[5]; /* Memory Timing block sort from lower clock to higher clock */ +} ATOM_VRAM_MODULE_V5; + +typedef struct _ATOM_VRAM_INFO_V2 { + ATOM_COMMON_TABLE_HEADER sHeader; + UCHAR ucNumOfVRAMModule; + ATOM_VRAM_MODULE aVramInfo[ATOM_MAX_NUMBER_OF_VRAM_MODULE]; /* just for allocation, real number of blocks is in ucNumOfVRAMModule; */ +} ATOM_VRAM_INFO_V2; + +typedef struct _ATOM_VRAM_INFO_V3 { + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT usMemAdjustTblOffset; /* offset of ATOM_INIT_REG_BLOCK structure for memory vendor specific MC adjust setting */ + USHORT usMemClkPatchTblOffset; /* offset of ATOM_INIT_REG_BLOCK structure for memory clock specific MC setting */ + USHORT usRerseved; + UCHAR aVID_PinsShift[9]; /* 8 bit strap maximum+terminator */ + UCHAR ucNumOfVRAMModule; + ATOM_VRAM_MODULE aVramInfo[ATOM_MAX_NUMBER_OF_VRAM_MODULE]; /* just for allocation, real number of blocks is in ucNumOfVRAMModule; */ + ATOM_INIT_REG_BLOCK asMemPatch; /* for allocation */ + /* ATOM_INIT_REG_BLOCK aMemAdjust; */ +} ATOM_VRAM_INFO_V3; + +#define ATOM_VRAM_INFO_LAST ATOM_VRAM_INFO_V3 + +typedef struct _ATOM_VRAM_INFO_V4 { + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT usMemAdjustTblOffset; /* offset of ATOM_INIT_REG_BLOCK structure for memory vendor specific MC adjust setting */ + USHORT usMemClkPatchTblOffset; /* offset of ATOM_INIT_REG_BLOCK structure for memory clock specific MC setting */ + USHORT usRerseved; + UCHAR ucMemDQ7_0ByteRemap; /* DQ line byte remap, =0: Memory Data line BYTE0, =1: BYTE1, =2: BYTE2, =3: BYTE3 */ + ULONG ulMemDQ7_0BitRemap; /* each DQ line ( 7~0) use 3bits, like: DQ0=Bit[2:0], DQ1:[5:3], ... DQ7:[23:21] */ + UCHAR ucReservde[4]; + UCHAR ucNumOfVRAMModule; + ATOM_VRAM_MODULE_V4 aVramInfo[ATOM_MAX_NUMBER_OF_VRAM_MODULE]; /* just for allocation, real number of blocks is in ucNumOfVRAMModule; */ + ATOM_INIT_REG_BLOCK asMemPatch; /* for allocation */ + /* ATOM_INIT_REG_BLOCK aMemAdjust; */ +} ATOM_VRAM_INFO_V4; + +typedef struct _ATOM_VRAM_GPIO_DETECTION_INFO { + ATOM_COMMON_TABLE_HEADER sHeader; + UCHAR aVID_PinsShift[9]; /* 8 bit strap maximum+terminator */ +} ATOM_VRAM_GPIO_DETECTION_INFO; + +typedef struct _ATOM_MEMORY_TRAINING_INFO { + ATOM_COMMON_TABLE_HEADER sHeader; + UCHAR ucTrainingLoop; + UCHAR ucReserved[3]; + ATOM_INIT_REG_BLOCK asMemTrainingSetting; +} ATOM_MEMORY_TRAINING_INFO; + +typedef struct SW_I2C_CNTL_DATA_PARAMETERS { + UCHAR ucControl; + UCHAR ucData; + UCHAR ucSatus; + UCHAR ucTemp; +} SW_I2C_CNTL_DATA_PARAMETERS; + +#define SW_I2C_CNTL_DATA_PS_ALLOCATION SW_I2C_CNTL_DATA_PARAMETERS + +typedef struct _SW_I2C_IO_DATA_PARAMETERS { + USHORT GPIO_Info; + UCHAR ucAct; + UCHAR ucData; +} SW_I2C_IO_DATA_PARAMETERS; + +#define SW_I2C_IO_DATA_PS_ALLOCATION SW_I2C_IO_DATA_PARAMETERS + +/****************************SW I2C CNTL DEFINITIONS**********************/ +#define SW_I2C_IO_RESET 0 +#define SW_I2C_IO_GET 1 +#define SW_I2C_IO_DRIVE 2 +#define SW_I2C_IO_SET 3 +#define SW_I2C_IO_START 4 + +#define SW_I2C_IO_CLOCK 0 +#define SW_I2C_IO_DATA 0x80 + +#define SW_I2C_IO_ZERO 0 +#define SW_I2C_IO_ONE 0x100 + +#define SW_I2C_CNTL_READ 0 +#define SW_I2C_CNTL_WRITE 1 +#define SW_I2C_CNTL_START 2 +#define SW_I2C_CNTL_STOP 3 +#define SW_I2C_CNTL_OPEN 4 +#define SW_I2C_CNTL_CLOSE 5 +#define SW_I2C_CNTL_WRITE1BIT 6 + +/* ==============================VESA definition Portion=============================== */ +#define VESA_OEM_PRODUCT_REV '01.00' +#define VESA_MODE_ATTRIBUTE_MODE_SUPPORT 0xBB /* refer to VBE spec p.32, no TTY support */ +#define VESA_MODE_WIN_ATTRIBUTE 7 +#define VESA_WIN_SIZE 64 + +typedef struct _PTR_32_BIT_STRUCTURE { + USHORT Offset16; + USHORT Segment16; +} PTR_32_BIT_STRUCTURE; + +typedef union _PTR_32_BIT_UNION { + PTR_32_BIT_STRUCTURE SegmentOffset; + ULONG Ptr32_Bit; +} PTR_32_BIT_UNION; + +typedef struct _VBE_1_2_INFO_BLOCK_UPDATABLE { + UCHAR VbeSignature[4]; + USHORT VbeVersion; + PTR_32_BIT_UNION OemStringPtr; + UCHAR Capabilities[4]; + PTR_32_BIT_UNION VideoModePtr; + USHORT TotalMemory; +} VBE_1_2_INFO_BLOCK_UPDATABLE; + +typedef struct _VBE_2_0_INFO_BLOCK_UPDATABLE { + VBE_1_2_INFO_BLOCK_UPDATABLE CommonBlock; + USHORT OemSoftRev; + PTR_32_BIT_UNION OemVendorNamePtr; + PTR_32_BIT_UNION OemProductNamePtr; + PTR_32_BIT_UNION OemProductRevPtr; +} VBE_2_0_INFO_BLOCK_UPDATABLE; + +typedef union _VBE_VERSION_UNION { + VBE_2_0_INFO_BLOCK_UPDATABLE VBE_2_0_InfoBlock; + VBE_1_2_INFO_BLOCK_UPDATABLE VBE_1_2_InfoBlock; +} VBE_VERSION_UNION; + +typedef struct _VBE_INFO_BLOCK { + VBE_VERSION_UNION UpdatableVBE_Info; + UCHAR Reserved[222]; + UCHAR OemData[256]; +} VBE_INFO_BLOCK; + +typedef struct _VBE_FP_INFO { + USHORT HSize; + USHORT VSize; + USHORT FPType; + UCHAR RedBPP; + UCHAR GreenBPP; + UCHAR BlueBPP; + UCHAR ReservedBPP; + ULONG RsvdOffScrnMemSize; + ULONG RsvdOffScrnMEmPtr; + UCHAR Reserved[14]; +} VBE_FP_INFO; + +typedef struct _VESA_MODE_INFO_BLOCK { +/* Mandatory information for all VBE revisions */ + USHORT ModeAttributes; /* dw ? ; mode attributes */ + UCHAR WinAAttributes; /* db ? ; window A attributes */ + UCHAR WinBAttributes; /* db ? ; window B attributes */ + USHORT WinGranularity; /* dw ? ; window granularity */ + USHORT WinSize; /* dw ? ; window size */ + USHORT WinASegment; /* dw ? ; window A start segment */ + USHORT WinBSegment; /* dw ? ; window B start segment */ + ULONG WinFuncPtr; /* dd ? ; real mode pointer to window function */ + USHORT BytesPerScanLine; /* dw ? ; bytes per scan line */ + +/* ; Mandatory information for VBE 1.2 and above */ + USHORT XResolution; /* dw ? ; horizontal resolution in pixels or characters */ + USHORT YResolution; /* dw ? ; vertical resolution in pixels or characters */ + UCHAR XCharSize; /* db ? ; character cell width in pixels */ + UCHAR YCharSize; /* db ? ; character cell height in pixels */ + UCHAR NumberOfPlanes; /* db ? ; number of memory planes */ + UCHAR BitsPerPixel; /* db ? ; bits per pixel */ + UCHAR NumberOfBanks; /* db ? ; number of banks */ + UCHAR MemoryModel; /* db ? ; memory model type */ + UCHAR BankSize; /* db ? ; bank size in KB */ + UCHAR NumberOfImagePages; /* db ? ; number of images */ + UCHAR ReservedForPageFunction; /* db 1 ; reserved for page function */ + +/* ; Direct Color fields(required for direct/6 and YUV/7 memory models) */ + UCHAR RedMaskSize; /* db ? ; size of direct color red mask in bits */ + UCHAR RedFieldPosition; /* db ? ; bit position of lsb of red mask */ + UCHAR GreenMaskSize; /* db ? ; size of direct color green mask in bits */ + UCHAR GreenFieldPosition; /* db ? ; bit position of lsb of green mask */ + UCHAR BlueMaskSize; /* db ? ; size of direct color blue mask in bits */ + UCHAR BlueFieldPosition; /* db ? ; bit position of lsb of blue mask */ + UCHAR RsvdMaskSize; /* db ? ; size of direct color reserved mask in bits */ + UCHAR RsvdFieldPosition; /* db ? ; bit position of lsb of reserved mask */ + UCHAR DirectColorModeInfo; /* db ? ; direct color mode attributes */ + +/* ; Mandatory information for VBE 2.0 and above */ + ULONG PhysBasePtr; /* dd ? ; physical address for flat memory frame buffer */ + ULONG Reserved_1; /* dd 0 ; reserved - always set to 0 */ + USHORT Reserved_2; /* dw 0 ; reserved - always set to 0 */ + +/* ; Mandatory information for VBE 3.0 and above */ + USHORT LinBytesPerScanLine; /* dw ? ; bytes per scan line for linear modes */ + UCHAR BnkNumberOfImagePages; /* db ? ; number of images for banked modes */ + UCHAR LinNumberOfImagPages; /* db ? ; number of images for linear modes */ + UCHAR LinRedMaskSize; /* db ? ; size of direct color red mask(linear modes) */ + UCHAR LinRedFieldPosition; /* db ? ; bit position of lsb of red mask(linear modes) */ + UCHAR LinGreenMaskSize; /* db ? ; size of direct color green mask(linear modes) */ + UCHAR LinGreenFieldPosition; /* db ? ; bit position of lsb of green mask(linear modes) */ + UCHAR LinBlueMaskSize; /* db ? ; size of direct color blue mask(linear modes) */ + UCHAR LinBlueFieldPosition; /* db ? ; bit position of lsb of blue mask(linear modes) */ + UCHAR LinRsvdMaskSize; /* db ? ; size of direct color reserved mask(linear modes) */ + UCHAR LinRsvdFieldPosition; /* db ? ; bit position of lsb of reserved mask(linear modes) */ + ULONG MaxPixelClock; /* dd ? ; maximum pixel clock(in Hz) for graphics mode */ + UCHAR Reserved; /* db 190 dup (0) */ +} VESA_MODE_INFO_BLOCK; + +/* BIOS function CALLS */ +#define ATOM_BIOS_EXTENDED_FUNCTION_CODE 0xA0 /* ATI Extended Function code */ +#define ATOM_BIOS_FUNCTION_COP_MODE 0x00 +#define ATOM_BIOS_FUNCTION_SHORT_QUERY1 0x04 +#define ATOM_BIOS_FUNCTION_SHORT_QUERY2 0x05 +#define ATOM_BIOS_FUNCTION_SHORT_QUERY3 0x06 +#define ATOM_BIOS_FUNCTION_GET_DDC 0x0B +#define ATOM_BIOS_FUNCTION_ASIC_DSTATE 0x0E +#define ATOM_BIOS_FUNCTION_DEBUG_PLAY 0x0F +#define ATOM_BIOS_FUNCTION_STV_STD 0x16 +#define ATOM_BIOS_FUNCTION_DEVICE_DET 0x17 +#define ATOM_BIOS_FUNCTION_DEVICE_SWITCH 0x18 + +#define ATOM_BIOS_FUNCTION_PANEL_CONTROL 0x82 +#define ATOM_BIOS_FUNCTION_OLD_DEVICE_DET 0x83 +#define ATOM_BIOS_FUNCTION_OLD_DEVICE_SWITCH 0x84 +#define ATOM_BIOS_FUNCTION_HW_ICON 0x8A +#define ATOM_BIOS_FUNCTION_SET_CMOS 0x8B +#define SUB_FUNCTION_UPDATE_DISPLAY_INFO 0x8000 /* Sub function 80 */ +#define SUB_FUNCTION_UPDATE_EXPANSION_INFO 0x8100 /* Sub function 80 */ + +#define ATOM_BIOS_FUNCTION_DISPLAY_INFO 0x8D +#define ATOM_BIOS_FUNCTION_DEVICE_ON_OFF 0x8E +#define ATOM_BIOS_FUNCTION_VIDEO_STATE 0x8F +#define ATOM_SUB_FUNCTION_GET_CRITICAL_STATE 0x0300 /* Sub function 03 */ +#define ATOM_SUB_FUNCTION_GET_LIDSTATE 0x0700 /* Sub function 7 */ +#define ATOM_SUB_FUNCTION_THERMAL_STATE_NOTICE 0x1400 /* Notify caller the current thermal state */ +#define ATOM_SUB_FUNCTION_CRITICAL_STATE_NOTICE 0x8300 /* Notify caller the current critical state */ +#define ATOM_SUB_FUNCTION_SET_LIDSTATE 0x8500 /* Sub function 85 */ +#define ATOM_SUB_FUNCTION_GET_REQ_DISPLAY_FROM_SBIOS_MODE 0x8900 /* Sub function 89 */ +#define ATOM_SUB_FUNCTION_INFORM_ADC_SUPPORT 0x9400 /* Notify caller that ADC is supported */ + +#define ATOM_BIOS_FUNCTION_VESA_DPMS 0x4F10 /* Set DPMS */ +#define ATOM_SUB_FUNCTION_SET_DPMS 0x0001 /* BL: Sub function 01 */ +#define ATOM_SUB_FUNCTION_GET_DPMS 0x0002 /* BL: Sub function 02 */ +#define ATOM_PARAMETER_VESA_DPMS_ON 0x0000 /* BH Parameter for DPMS ON. */ +#define ATOM_PARAMETER_VESA_DPMS_STANDBY 0x0100 /* BH Parameter for DPMS STANDBY */ +#define ATOM_PARAMETER_VESA_DPMS_SUSPEND 0x0200 /* BH Parameter for DPMS SUSPEND */ +#define ATOM_PARAMETER_VESA_DPMS_OFF 0x0400 /* BH Parameter for DPMS OFF */ +#define ATOM_PARAMETER_VESA_DPMS_REDUCE_ON 0x0800 /* BH Parameter for DPMS REDUCE ON (NOT SUPPORTED) */ + +#define ATOM_BIOS_RETURN_CODE_MASK 0x0000FF00L +#define ATOM_BIOS_REG_HIGH_MASK 0x0000FF00L +#define ATOM_BIOS_REG_LOW_MASK 0x000000FFL + +/* structure used for VBIOS only */ + +/* DispOutInfoTable */ +typedef struct _ASIC_TRANSMITTER_INFO { + USHORT usTransmitterObjId; + USHORT usSupportDevice; + UCHAR ucTransmitterCmdTblId; + UCHAR ucConfig; + UCHAR ucEncoderID; /* available 1st encoder ( default ) */ + UCHAR ucOptionEncoderID; /* available 2nd encoder ( optional ) */ + UCHAR uc2ndEncoderID; + UCHAR ucReserved; +} ASIC_TRANSMITTER_INFO; + +typedef struct _ASIC_ENCODER_INFO { + UCHAR ucEncoderID; + UCHAR ucEncoderConfig; + USHORT usEncoderCmdTblId; +} ASIC_ENCODER_INFO; + +typedef struct _ATOM_DISP_OUT_INFO { + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT ptrTransmitterInfo; + USHORT ptrEncoderInfo; + ASIC_TRANSMITTER_INFO asTransmitterInfo[1]; + ASIC_ENCODER_INFO asEncoderInfo[1]; +} ATOM_DISP_OUT_INFO; + +/* DispDevicePriorityInfo */ +typedef struct _ATOM_DISPLAY_DEVICE_PRIORITY_INFO { + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT asDevicePriority[16]; +} ATOM_DISPLAY_DEVICE_PRIORITY_INFO; + +/* ProcessAuxChannelTransactionTable */ +typedef struct _PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS { + USHORT lpAuxRequest; + USHORT lpDataOut; + UCHAR ucChannelID; + union { + UCHAR ucReplyStatus; + UCHAR ucDelay; + }; + UCHAR ucDataOutLen; + UCHAR ucReserved; +} PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS; + +#define PROCESS_AUX_CHANNEL_TRANSACTION_PS_ALLOCATION PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS + +/* GetSinkType */ + +typedef struct _DP_ENCODER_SERVICE_PARAMETERS { + USHORT ucLinkClock; + union { + UCHAR ucConfig; /* for DP training command */ + UCHAR ucI2cId; /* use for GET_SINK_TYPE command */ + }; + UCHAR ucAction; + UCHAR ucStatus; + UCHAR ucLaneNum; + UCHAR ucReserved[2]; +} DP_ENCODER_SERVICE_PARAMETERS; + +/* ucAction */ +#define ATOM_DP_ACTION_GET_SINK_TYPE 0x01 +#define ATOM_DP_ACTION_TRAINING_START 0x02 +#define ATOM_DP_ACTION_TRAINING_COMPLETE 0x03 +#define ATOM_DP_ACTION_TRAINING_PATTERN_SEL 0x04 +#define ATOM_DP_ACTION_SET_VSWING_PREEMP 0x05 +#define ATOM_DP_ACTION_GET_VSWING_PREEMP 0x06 +#define ATOM_DP_ACTION_BLANKING 0x07 + +/* ucConfig */ +#define ATOM_DP_CONFIG_ENCODER_SEL_MASK 0x03 +#define ATOM_DP_CONFIG_DIG1_ENCODER 0x00 +#define ATOM_DP_CONFIG_DIG2_ENCODER 0x01 +#define ATOM_DP_CONFIG_EXTERNAL_ENCODER 0x02 +#define ATOM_DP_CONFIG_LINK_SEL_MASK 0x04 +#define ATOM_DP_CONFIG_LINK_A 0x00 +#define ATOM_DP_CONFIG_LINK_B 0x04 + +#define DP_ENCODER_SERVICE_PS_ALLOCATION WRITE_ONE_BYTE_HW_I2C_DATA_PARAMETERS + +/* DP_TRAINING_TABLE */ +#define DPCD_SET_LINKRATE_LANENUM_PATTERN1_TBL_ADDR ATOM_DP_TRAINING_TBL_ADDR +#define DPCD_SET_SS_CNTL_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 8 ) +#define DPCD_SET_LANE_VSWING_PREEMP_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 16) +#define DPCD_SET_TRAINING_PATTERN0_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 24) +#define DPCD_SET_TRAINING_PATTERN2_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 32) +#define DPCD_GET_LINKRATE_LANENUM_SS_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 40) +#define DPCD_GET_LANE_STATUS_ADJUST_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 48) +#define DP_I2C_AUX_DDC_WRITE_START_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 60) +#define DP_I2C_AUX_DDC_WRITE_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 64) +#define DP_I2C_AUX_DDC_READ_START_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 72) +#define DP_I2C_AUX_DDC_READ_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 76) +#define DP_I2C_AUX_DDC_READ_END_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 80) + +typedef struct _PROCESS_I2C_CHANNEL_TRANSACTION_PARAMETERS { + UCHAR ucI2CSpeed; + union { + UCHAR ucRegIndex; + UCHAR ucStatus; + }; + USHORT lpI2CDataOut; + UCHAR ucFlag; + UCHAR ucTransBytes; + UCHAR ucSlaveAddr; + UCHAR ucLineNumber; +} PROCESS_I2C_CHANNEL_TRANSACTION_PARAMETERS; + +#define PROCESS_I2C_CHANNEL_TRANSACTION_PS_ALLOCATION PROCESS_I2C_CHANNEL_TRANSACTION_PARAMETERS + +/* ucFlag */ +#define HW_I2C_WRITE 1 +#define HW_I2C_READ 0 + +/****************************************************************************/ +/* Portion VI: Definitinos being oboselete */ +/****************************************************************************/ + +/* ========================================================================================== */ +/* Remove the definitions below when driver is ready! */ +typedef struct _ATOM_DAC_INFO { + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT usMaxFrequency; /* in 10kHz unit */ + USHORT usReserved; +} ATOM_DAC_INFO; + +typedef struct _COMPASSIONATE_DATA { + ATOM_COMMON_TABLE_HEADER sHeader; + + /* ============================== DAC1 portion */ + UCHAR ucDAC1_BG_Adjustment; + UCHAR ucDAC1_DAC_Adjustment; + USHORT usDAC1_FORCE_Data; + /* ============================== DAC2 portion */ + UCHAR ucDAC2_CRT2_BG_Adjustment; + UCHAR ucDAC2_CRT2_DAC_Adjustment; + USHORT usDAC2_CRT2_FORCE_Data; + USHORT usDAC2_CRT2_MUX_RegisterIndex; + UCHAR ucDAC2_CRT2_MUX_RegisterInfo; /* Bit[4:0]=Bit position,Bit[7]=1:Active High;=0 Active Low */ + UCHAR ucDAC2_NTSC_BG_Adjustment; + UCHAR ucDAC2_NTSC_DAC_Adjustment; + USHORT usDAC2_TV1_FORCE_Data; + USHORT usDAC2_TV1_MUX_RegisterIndex; + UCHAR ucDAC2_TV1_MUX_RegisterInfo; /* Bit[4:0]=Bit position,Bit[7]=1:Active High;=0 Active Low */ + UCHAR ucDAC2_CV_BG_Adjustment; + UCHAR ucDAC2_CV_DAC_Adjustment; + USHORT usDAC2_CV_FORCE_Data; + USHORT usDAC2_CV_MUX_RegisterIndex; + UCHAR ucDAC2_CV_MUX_RegisterInfo; /* Bit[4:0]=Bit position,Bit[7]=1:Active High;=0 Active Low */ + UCHAR ucDAC2_PAL_BG_Adjustment; + UCHAR ucDAC2_PAL_DAC_Adjustment; + USHORT usDAC2_TV2_FORCE_Data; +} COMPASSIONATE_DATA; + +/****************************Supported Device Info Table Definitions**********************/ +/* ucConnectInfo: */ +/* [7:4] - connector type */ +/* = 1 - VGA connector */ +/* = 2 - DVI-I */ +/* = 3 - DVI-D */ +/* = 4 - DVI-A */ +/* = 5 - SVIDEO */ +/* = 6 - COMPOSITE */ +/* = 7 - LVDS */ +/* = 8 - DIGITAL LINK */ +/* = 9 - SCART */ +/* = 0xA - HDMI_type A */ +/* = 0xB - HDMI_type B */ +/* = 0xE - Special case1 (DVI+DIN) */ +/* Others=TBD */ +/* [3:0] - DAC Associated */ +/* = 0 - no DAC */ +/* = 1 - DACA */ +/* = 2 - DACB */ +/* = 3 - External DAC */ +/* Others=TBD */ +/* */ + +typedef struct _ATOM_CONNECTOR_INFO { +#if ATOM_BIG_ENDIAN + UCHAR bfConnectorType:4; + UCHAR bfAssociatedDAC:4; +#else + UCHAR bfAssociatedDAC:4; + UCHAR bfConnectorType:4; +#endif +} ATOM_CONNECTOR_INFO; + +typedef union _ATOM_CONNECTOR_INFO_ACCESS { + ATOM_CONNECTOR_INFO sbfAccess; + UCHAR ucAccess; +} ATOM_CONNECTOR_INFO_ACCESS; + +typedef struct _ATOM_CONNECTOR_INFO_I2C { + ATOM_CONNECTOR_INFO_ACCESS sucConnectorInfo; + ATOM_I2C_ID_CONFIG_ACCESS sucI2cId; +} ATOM_CONNECTOR_INFO_I2C; + +typedef struct _ATOM_SUPPORTED_DEVICES_INFO { + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT usDeviceSupport; + ATOM_CONNECTOR_INFO_I2C asConnInfo[ATOM_MAX_SUPPORTED_DEVICE_INFO]; +} ATOM_SUPPORTED_DEVICES_INFO; + +#define NO_INT_SRC_MAPPED 0xFF + +typedef struct _ATOM_CONNECTOR_INC_SRC_BITMAP { + UCHAR ucIntSrcBitmap; +} ATOM_CONNECTOR_INC_SRC_BITMAP; + +typedef struct _ATOM_SUPPORTED_DEVICES_INFO_2 { + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT usDeviceSupport; + ATOM_CONNECTOR_INFO_I2C asConnInfo[ATOM_MAX_SUPPORTED_DEVICE_INFO_2]; + ATOM_CONNECTOR_INC_SRC_BITMAP + asIntSrcInfo[ATOM_MAX_SUPPORTED_DEVICE_INFO_2]; +} ATOM_SUPPORTED_DEVICES_INFO_2; + +typedef struct _ATOM_SUPPORTED_DEVICES_INFO_2d1 { + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT usDeviceSupport; + ATOM_CONNECTOR_INFO_I2C asConnInfo[ATOM_MAX_SUPPORTED_DEVICE]; + ATOM_CONNECTOR_INC_SRC_BITMAP asIntSrcInfo[ATOM_MAX_SUPPORTED_DEVICE]; +} ATOM_SUPPORTED_DEVICES_INFO_2d1; + +#define ATOM_SUPPORTED_DEVICES_INFO_LAST ATOM_SUPPORTED_DEVICES_INFO_2d1 + +typedef struct _ATOM_MISC_CONTROL_INFO { + USHORT usFrequency; + UCHAR ucPLL_ChargePump; /* PLL charge-pump gain control */ + UCHAR ucPLL_DutyCycle; /* PLL duty cycle control */ + UCHAR ucPLL_VCO_Gain; /* PLL VCO gain control */ + UCHAR ucPLL_VoltageSwing; /* PLL driver voltage swing control */ +} ATOM_MISC_CONTROL_INFO; + +#define ATOM_MAX_MISC_INFO 4 + +typedef struct _ATOM_TMDS_INFO { + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT usMaxFrequency; /* in 10Khz */ + ATOM_MISC_CONTROL_INFO asMiscInfo[ATOM_MAX_MISC_INFO]; +} ATOM_TMDS_INFO; + +typedef struct _ATOM_ENCODER_ANALOG_ATTRIBUTE { + UCHAR ucTVStandard; /* Same as TV standards defined above, */ + UCHAR ucPadding[1]; +} ATOM_ENCODER_ANALOG_ATTRIBUTE; + +typedef struct _ATOM_ENCODER_DIGITAL_ATTRIBUTE { + UCHAR ucAttribute; /* Same as other digital encoder attributes defined above */ + UCHAR ucPadding[1]; +} ATOM_ENCODER_DIGITAL_ATTRIBUTE; + +typedef union _ATOM_ENCODER_ATTRIBUTE { + ATOM_ENCODER_ANALOG_ATTRIBUTE sAlgAttrib; + ATOM_ENCODER_DIGITAL_ATTRIBUTE sDigAttrib; +} ATOM_ENCODER_ATTRIBUTE; + +typedef struct _DVO_ENCODER_CONTROL_PARAMETERS { + USHORT usPixelClock; + USHORT usEncoderID; + UCHAR ucDeviceType; /* Use ATOM_DEVICE_xxx1_Index to indicate device type only. */ + UCHAR ucAction; /* ATOM_ENABLE/ATOM_DISABLE/ATOM_HPD_INIT */ + ATOM_ENCODER_ATTRIBUTE usDevAttr; +} DVO_ENCODER_CONTROL_PARAMETERS; + +typedef struct _DVO_ENCODER_CONTROL_PS_ALLOCATION { + DVO_ENCODER_CONTROL_PARAMETERS sDVOEncoder; + WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved; /* Caller doesn't need to init this portion */ +} DVO_ENCODER_CONTROL_PS_ALLOCATION; + +#define ATOM_XTMDS_ASIC_SI164_ID 1 +#define ATOM_XTMDS_ASIC_SI178_ID 2 +#define ATOM_XTMDS_ASIC_TFP513_ID 3 +#define ATOM_XTMDS_SUPPORTED_SINGLELINK 0x00000001 +#define ATOM_XTMDS_SUPPORTED_DUALLINK 0x00000002 +#define ATOM_XTMDS_MVPU_FPGA 0x00000004 + +typedef struct _ATOM_XTMDS_INFO { + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT usSingleLinkMaxFrequency; + ATOM_I2C_ID_CONFIG_ACCESS sucI2cId; /* Point the ID on which I2C is used to control external chip */ + UCHAR ucXtransimitterID; + UCHAR ucSupportedLink; /* Bit field, bit0=1, single link supported;bit1=1,dual link supported */ + UCHAR ucSequnceAlterID; /* Even with the same external TMDS asic, it's possible that the program seqence alters */ + /* due to design. This ID is used to alert driver that the sequence is not "standard"! */ + UCHAR ucMasterAddress; /* Address to control Master xTMDS Chip */ + UCHAR ucSlaveAddress; /* Address to control Slave xTMDS Chip */ +} ATOM_XTMDS_INFO; + +typedef struct _DFP_DPMS_STATUS_CHANGE_PARAMETERS { + UCHAR ucEnable; /* ATOM_ENABLE=On or ATOM_DISABLE=Off */ + UCHAR ucDevice; /* ATOM_DEVICE_DFP1_INDEX.... */ + UCHAR ucPadding[2]; +} DFP_DPMS_STATUS_CHANGE_PARAMETERS; + +/****************************Legacy Power Play Table Definitions **********************/ + +/* Definitions for ulPowerPlayMiscInfo */ +#define ATOM_PM_MISCINFO_SPLIT_CLOCK 0x00000000L +#define ATOM_PM_MISCINFO_USING_MCLK_SRC 0x00000001L +#define ATOM_PM_MISCINFO_USING_SCLK_SRC 0x00000002L + +#define ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT 0x00000004L +#define ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH 0x00000008L + +#define ATOM_PM_MISCINFO_LOAD_PERFORMANCE_EN 0x00000010L + +#define ATOM_PM_MISCINFO_ENGINE_CLOCK_CONTRL_EN 0x00000020L +#define ATOM_PM_MISCINFO_MEMORY_CLOCK_CONTRL_EN 0x00000040L +#define ATOM_PM_MISCINFO_PROGRAM_VOLTAGE 0x00000080L /* When this bit set, ucVoltageDropIndex is not an index for GPIO pin, but a voltage ID that SW needs program */ + +#define ATOM_PM_MISCINFO_ASIC_REDUCED_SPEED_SCLK_EN 0x00000100L +#define ATOM_PM_MISCINFO_ASIC_DYNAMIC_VOLTAGE_EN 0x00000200L +#define ATOM_PM_MISCINFO_ASIC_SLEEP_MODE_EN 0x00000400L +#define ATOM_PM_MISCINFO_LOAD_BALANCE_EN 0x00000800L +#define ATOM_PM_MISCINFO_DEFAULT_DC_STATE_ENTRY_TRUE 0x00001000L +#define ATOM_PM_MISCINFO_DEFAULT_LOW_DC_STATE_ENTRY_TRUE 0x00002000L +#define ATOM_PM_MISCINFO_LOW_LCD_REFRESH_RATE 0x00004000L + +#define ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE 0x00008000L +#define ATOM_PM_MISCINFO_OVER_CLOCK_MODE 0x00010000L +#define ATOM_PM_MISCINFO_OVER_DRIVE_MODE 0x00020000L +#define ATOM_PM_MISCINFO_POWER_SAVING_MODE 0x00040000L +#define ATOM_PM_MISCINFO_THERMAL_DIODE_MODE 0x00080000L + +#define ATOM_PM_MISCINFO_FRAME_MODULATION_MASK 0x00300000L /* 0-FM Disable, 1-2 level FM, 2-4 level FM, 3-Reserved */ +#define ATOM_PM_MISCINFO_FRAME_MODULATION_SHIFT 20 + +#define ATOM_PM_MISCINFO_DYN_CLK_3D_IDLE 0x00400000L +#define ATOM_PM_MISCINFO_DYNAMIC_CLOCK_DIVIDER_BY_2 0x00800000L +#define ATOM_PM_MISCINFO_DYNAMIC_CLOCK_DIVIDER_BY_4 0x01000000L +#define ATOM_PM_MISCINFO_DYNAMIC_HDP_BLOCK_EN 0x02000000L /* When set, Dynamic */ +#define ATOM_PM_MISCINFO_DYNAMIC_MC_HOST_BLOCK_EN 0x04000000L /* When set, Dynamic */ +#define ATOM_PM_MISCINFO_3D_ACCELERATION_EN 0x08000000L /* When set, This mode is for acceleated 3D mode */ + +#define ATOM_PM_MISCINFO_POWERPLAY_SETTINGS_GROUP_MASK 0x70000000L /* 1-Optimal Battery Life Group, 2-High Battery, 3-Balanced, 4-High Performance, 5- Optimal Performance (Default state with Default clocks) */ +#define ATOM_PM_MISCINFO_POWERPLAY_SETTINGS_GROUP_SHIFT 28 +#define ATOM_PM_MISCINFO_ENABLE_BACK_BIAS 0x80000000L + +#define ATOM_PM_MISCINFO2_SYSTEM_AC_LITE_MODE 0x00000001L +#define ATOM_PM_MISCINFO2_MULTI_DISPLAY_SUPPORT 0x00000002L +#define ATOM_PM_MISCINFO2_DYNAMIC_BACK_BIAS_EN 0x00000004L +#define ATOM_PM_MISCINFO2_FS3D_OVERDRIVE_INFO 0x00000008L +#define ATOM_PM_MISCINFO2_FORCEDLOWPWR_MODE 0x00000010L +#define ATOM_PM_MISCINFO2_VDDCI_DYNAMIC_VOLTAGE_EN 0x00000020L +#define ATOM_PM_MISCINFO2_VIDEO_PLAYBACK_CAPABLE 0x00000040L /* If this bit is set in multi-pp mode, then driver will pack up one with the minior power consumption. */ + /* If it's not set in any pp mode, driver will use its default logic to pick a pp mode in video playback */ +#define ATOM_PM_MISCINFO2_NOT_VALID_ON_DC 0x00000080L +#define ATOM_PM_MISCINFO2_STUTTER_MODE_EN 0x00000100L +#define ATOM_PM_MISCINFO2_UVD_SUPPORT_MODE 0x00000200L + +/* ucTableFormatRevision=1 */ +/* ucTableContentRevision=1 */ +typedef struct _ATOM_POWERMODE_INFO { + ULONG ulMiscInfo; /* The power level should be arranged in ascending order */ + ULONG ulReserved1; /* must set to 0 */ + ULONG ulReserved2; /* must set to 0 */ + USHORT usEngineClock; + USHORT usMemoryClock; + UCHAR ucVoltageDropIndex; /* index to GPIO table */ + UCHAR ucSelectedPanel_RefreshRate; /* panel refresh rate */ + UCHAR ucMinTemperature; + UCHAR ucMaxTemperature; + UCHAR ucNumPciELanes; /* number of PCIE lanes */ +} ATOM_POWERMODE_INFO; + +/* ucTableFormatRevision=2 */ +/* ucTableContentRevision=1 */ +typedef struct _ATOM_POWERMODE_INFO_V2 { + ULONG ulMiscInfo; /* The power level should be arranged in ascending order */ + ULONG ulMiscInfo2; + ULONG ulEngineClock; + ULONG ulMemoryClock; + UCHAR ucVoltageDropIndex; /* index to GPIO table */ + UCHAR ucSelectedPanel_RefreshRate; /* panel refresh rate */ + UCHAR ucMinTemperature; + UCHAR ucMaxTemperature; + UCHAR ucNumPciELanes; /* number of PCIE lanes */ +} ATOM_POWERMODE_INFO_V2; + +/* ucTableFormatRevision=2 */ +/* ucTableContentRevision=2 */ +typedef struct _ATOM_POWERMODE_INFO_V3 { + ULONG ulMiscInfo; /* The power level should be arranged in ascending order */ + ULONG ulMiscInfo2; + ULONG ulEngineClock; + ULONG ulMemoryClock; + UCHAR ucVoltageDropIndex; /* index to Core (VDDC) votage table */ + UCHAR ucSelectedPanel_RefreshRate; /* panel refresh rate */ + UCHAR ucMinTemperature; + UCHAR ucMaxTemperature; + UCHAR ucNumPciELanes; /* number of PCIE lanes */ + UCHAR ucVDDCI_VoltageDropIndex; /* index to VDDCI votage table */ +} ATOM_POWERMODE_INFO_V3; + +#define ATOM_MAX_NUMBEROF_POWER_BLOCK 8 + +#define ATOM_PP_OVERDRIVE_INTBITMAP_AUXWIN 0x01 +#define ATOM_PP_OVERDRIVE_INTBITMAP_OVERDRIVE 0x02 + +#define ATOM_PP_OVERDRIVE_THERMALCONTROLLER_LM63 0x01 +#define ATOM_PP_OVERDRIVE_THERMALCONTROLLER_ADM1032 0x02 +#define ATOM_PP_OVERDRIVE_THERMALCONTROLLER_ADM1030 0x03 +#define ATOM_PP_OVERDRIVE_THERMALCONTROLLER_MUA6649 0x04 +#define ATOM_PP_OVERDRIVE_THERMALCONTROLLER_LM64 0x05 +#define ATOM_PP_OVERDRIVE_THERMALCONTROLLER_F75375 0x06 +#define ATOM_PP_OVERDRIVE_THERMALCONTROLLER_ASC7512 0x07 /* Andigilog */ + +typedef struct _ATOM_POWERPLAY_INFO { + ATOM_COMMON_TABLE_HEADER sHeader; + UCHAR ucOverdriveThermalController; + UCHAR ucOverdriveI2cLine; + UCHAR ucOverdriveIntBitmap; + UCHAR ucOverdriveControllerAddress; + UCHAR ucSizeOfPowerModeEntry; + UCHAR ucNumOfPowerModeEntries; + ATOM_POWERMODE_INFO asPowerPlayInfo[ATOM_MAX_NUMBEROF_POWER_BLOCK]; +} ATOM_POWERPLAY_INFO; + +typedef struct _ATOM_POWERPLAY_INFO_V2 { + ATOM_COMMON_TABLE_HEADER sHeader; + UCHAR ucOverdriveThermalController; + UCHAR ucOverdriveI2cLine; + UCHAR ucOverdriveIntBitmap; + UCHAR ucOverdriveControllerAddress; + UCHAR ucSizeOfPowerModeEntry; + UCHAR ucNumOfPowerModeEntries; + ATOM_POWERMODE_INFO_V2 asPowerPlayInfo[ATOM_MAX_NUMBEROF_POWER_BLOCK]; +} ATOM_POWERPLAY_INFO_V2; + +typedef struct _ATOM_POWERPLAY_INFO_V3 { + ATOM_COMMON_TABLE_HEADER sHeader; + UCHAR ucOverdriveThermalController; + UCHAR ucOverdriveI2cLine; + UCHAR ucOverdriveIntBitmap; + UCHAR ucOverdriveControllerAddress; + UCHAR ucSizeOfPowerModeEntry; + UCHAR ucNumOfPowerModeEntries; + ATOM_POWERMODE_INFO_V3 asPowerPlayInfo[ATOM_MAX_NUMBEROF_POWER_BLOCK]; +} ATOM_POWERPLAY_INFO_V3; + +/**************************************************************************/ + +/* Following definitions are for compatiblity issue in different SW components. */ +#define ATOM_MASTER_DATA_TABLE_REVISION 0x01 +#define Object_Info Object_Header +#define AdjustARB_SEQ MC_InitParameter +#define VRAM_GPIO_DetectionInfo VoltageObjectInfo +#define ASIC_VDDCI_Info ASIC_ProfilingInfo +#define ASIC_MVDDQ_Info MemoryTrainingInfo +#define SS_Info PPLL_SS_Info +#define ASIC_MVDDC_Info ASIC_InternalSS_Info +#define DispDevicePriorityInfo SaveRestoreInfo +#define DispOutInfo TV_VideoMode + +#define ATOM_ENCODER_OBJECT_TABLE ATOM_OBJECT_TABLE +#define ATOM_CONNECTOR_OBJECT_TABLE ATOM_OBJECT_TABLE + +/* New device naming, remove them when both DAL/VBIOS is ready */ +#define DFP2I_OUTPUT_CONTROL_PARAMETERS CRT1_OUTPUT_CONTROL_PARAMETERS +#define DFP2I_OUTPUT_CONTROL_PS_ALLOCATION DFP2I_OUTPUT_CONTROL_PARAMETERS + +#define DFP1X_OUTPUT_CONTROL_PARAMETERS CRT1_OUTPUT_CONTROL_PARAMETERS +#define DFP1X_OUTPUT_CONTROL_PS_ALLOCATION DFP1X_OUTPUT_CONTROL_PARAMETERS + +#define DFP1I_OUTPUT_CONTROL_PARAMETERS DFP1_OUTPUT_CONTROL_PARAMETERS +#define DFP1I_OUTPUT_CONTROL_PS_ALLOCATION DFP1_OUTPUT_CONTROL_PS_ALLOCATION + +#define ATOM_DEVICE_DFP1I_SUPPORT ATOM_DEVICE_DFP1_SUPPORT +#define ATOM_DEVICE_DFP1X_SUPPORT ATOM_DEVICE_DFP2_SUPPORT + +#define ATOM_DEVICE_DFP1I_INDEX ATOM_DEVICE_DFP1_INDEX +#define ATOM_DEVICE_DFP1X_INDEX ATOM_DEVICE_DFP2_INDEX + +#define ATOM_DEVICE_DFP2I_INDEX 0x00000009 +#define ATOM_DEVICE_DFP2I_SUPPORT (0x1L << ATOM_DEVICE_DFP2I_INDEX) + +#define ATOM_S0_DFP1I ATOM_S0_DFP1 +#define ATOM_S0_DFP1X ATOM_S0_DFP2 + +#define ATOM_S0_DFP2I 0x00200000L +#define ATOM_S0_DFP2Ib2 0x20 + +#define ATOM_S2_DFP1I_DPMS_STATE ATOM_S2_DFP1_DPMS_STATE +#define ATOM_S2_DFP1X_DPMS_STATE ATOM_S2_DFP2_DPMS_STATE + +#define ATOM_S2_DFP2I_DPMS_STATE 0x02000000L +#define ATOM_S2_DFP2I_DPMS_STATEb3 0x02 + +#define ATOM_S3_DFP2I_ACTIVEb1 0x02 + +#define ATOM_S3_DFP1I_ACTIVE ATOM_S3_DFP1_ACTIVE +#define ATOM_S3_DFP1X_ACTIVE ATOM_S3_DFP2_ACTIVE + +#define ATOM_S3_DFP2I_ACTIVE 0x00000200L + +#define ATOM_S3_DFP1I_CRTC_ACTIVE ATOM_S3_DFP1_CRTC_ACTIVE +#define ATOM_S3_DFP1X_CRTC_ACTIVE ATOM_S3_DFP2_CRTC_ACTIVE +#define ATOM_S3_DFP2I_CRTC_ACTIVE 0x02000000L + +#define ATOM_S3_DFP2I_CRTC_ACTIVEb3 0x02 +#define ATOM_S5_DOS_REQ_DFP2Ib1 0x02 + +#define ATOM_S5_DOS_REQ_DFP2I 0x0200 +#define ATOM_S6_ACC_REQ_DFP1I ATOM_S6_ACC_REQ_DFP1 +#define ATOM_S6_ACC_REQ_DFP1X ATOM_S6_ACC_REQ_DFP2 + +#define ATOM_S6_ACC_REQ_DFP2Ib3 0x02 +#define ATOM_S6_ACC_REQ_DFP2I 0x02000000L + +#define TMDS1XEncoderControl DVOEncoderControl +#define DFP1XOutputControl DVOOutputControl + +#define ExternalDFPOutputControl DFP1XOutputControl +#define EnableExternalTMDS_Encoder TMDS1XEncoderControl + +#define DFP1IOutputControl TMDSAOutputControl +#define DFP2IOutputControl LVTMAOutputControl + +#define DAC1_ENCODER_CONTROL_PARAMETERS DAC_ENCODER_CONTROL_PARAMETERS +#define DAC1_ENCODER_CONTROL_PS_ALLOCATION DAC_ENCODER_CONTROL_PS_ALLOCATION + +#define DAC2_ENCODER_CONTROL_PARAMETERS DAC_ENCODER_CONTROL_PARAMETERS +#define DAC2_ENCODER_CONTROL_PS_ALLOCATION DAC_ENCODER_CONTROL_PS_ALLOCATION + +#define ucDac1Standard ucDacStandard +#define ucDac2Standard ucDacStandard + +#define TMDS1EncoderControl TMDSAEncoderControl +#define TMDS2EncoderControl LVTMAEncoderControl + +#define DFP1OutputControl TMDSAOutputControl +#define DFP2OutputControl LVTMAOutputControl +#define CRT1OutputControl DAC1OutputControl +#define CRT2OutputControl DAC2OutputControl + +/* These two lines will be removed for sure in a few days, will follow up with Michael V. */ +#define EnableLVDS_SS EnableSpreadSpectrumOnPPLL +#define ENABLE_LVDS_SS_PARAMETERS_V3 ENABLE_SPREAD_SPECTRUM_ON_PPLL + +/*********************************************************************************/ + +#pragma pack() /* BIOS data must use byte aligment */ + +#endif /* _ATOMBIOS_H */ diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c new file mode 100644 index 000000000000..c0080cc9bf8d --- /dev/null +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -0,0 +1,695 @@ +/* + * Copyright 2007-8 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Dave Airlie + * Alex Deucher + */ +#include +#include +#include +#include "radeon_fixed.h" +#include "radeon.h" +#include "atom.h" +#include "atom-bits.h" + +static void atombios_lock_crtc(struct drm_crtc *crtc, int lock) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct radeon_device *rdev = dev->dev_private; + int index = + GetIndexIntoMasterTable(COMMAND, UpdateCRTC_DoubleBufferRegisters); + ENABLE_CRTC_PS_ALLOCATION args; + + memset(&args, 0, sizeof(args)); + + args.ucCRTC = radeon_crtc->crtc_id; + args.ucEnable = lock; + + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); +} + +static void atombios_enable_crtc(struct drm_crtc *crtc, int state) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct radeon_device *rdev = dev->dev_private; + int index = GetIndexIntoMasterTable(COMMAND, EnableCRTC); + ENABLE_CRTC_PS_ALLOCATION args; + + memset(&args, 0, sizeof(args)); + + args.ucCRTC = radeon_crtc->crtc_id; + args.ucEnable = state; + + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); +} + +static void atombios_enable_crtc_memreq(struct drm_crtc *crtc, int state) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct radeon_device *rdev = dev->dev_private; + int index = GetIndexIntoMasterTable(COMMAND, EnableCRTCMemReq); + ENABLE_CRTC_PS_ALLOCATION args; + + memset(&args, 0, sizeof(args)); + + args.ucCRTC = radeon_crtc->crtc_id; + args.ucEnable = state; + + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); +} + +static void atombios_blank_crtc(struct drm_crtc *crtc, int state) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct radeon_device *rdev = dev->dev_private; + int index = GetIndexIntoMasterTable(COMMAND, BlankCRTC); + BLANK_CRTC_PS_ALLOCATION args; + + memset(&args, 0, sizeof(args)); + + args.ucCRTC = radeon_crtc->crtc_id; + args.ucBlanking = state; + + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); +} + +void atombios_crtc_dpms(struct drm_crtc *crtc, int mode) +{ + struct drm_device *dev = crtc->dev; + struct radeon_device *rdev = dev->dev_private; + + switch (mode) { + case DRM_MODE_DPMS_ON: + if (ASIC_IS_DCE3(rdev)) + atombios_enable_crtc_memreq(crtc, 1); + atombios_enable_crtc(crtc, 1); + atombios_blank_crtc(crtc, 0); + break; + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + atombios_blank_crtc(crtc, 1); + atombios_enable_crtc(crtc, 0); + if (ASIC_IS_DCE3(rdev)) + atombios_enable_crtc_memreq(crtc, 0); + break; + } + + if (mode != DRM_MODE_DPMS_OFF) { + radeon_crtc_load_lut(crtc); + } +} + +static void +atombios_set_crtc_dtd_timing(struct drm_crtc *crtc, + SET_CRTC_USING_DTD_TIMING_PARAMETERS * crtc_param) +{ + struct drm_device *dev = crtc->dev; + struct radeon_device *rdev = dev->dev_private; + SET_CRTC_USING_DTD_TIMING_PARAMETERS conv_param; + int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_UsingDTDTiming); + + conv_param.usH_Size = cpu_to_le16(crtc_param->usH_Size); + conv_param.usH_Blanking_Time = + cpu_to_le16(crtc_param->usH_Blanking_Time); + conv_param.usV_Size = cpu_to_le16(crtc_param->usV_Size); + conv_param.usV_Blanking_Time = + cpu_to_le16(crtc_param->usV_Blanking_Time); + conv_param.usH_SyncOffset = cpu_to_le16(crtc_param->usH_SyncOffset); + conv_param.usH_SyncWidth = cpu_to_le16(crtc_param->usH_SyncWidth); + conv_param.usV_SyncOffset = cpu_to_le16(crtc_param->usV_SyncOffset); + conv_param.usV_SyncWidth = cpu_to_le16(crtc_param->usV_SyncWidth); + conv_param.susModeMiscInfo.usAccess = + cpu_to_le16(crtc_param->susModeMiscInfo.usAccess); + conv_param.ucCRTC = crtc_param->ucCRTC; + + printk("executing set crtc dtd timing\n"); + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&conv_param); +} + +void atombios_crtc_set_timing(struct drm_crtc *crtc, + SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION * + crtc_param) +{ + struct drm_device *dev = crtc->dev; + struct radeon_device *rdev = dev->dev_private; + SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION conv_param; + int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_Timing); + + conv_param.usH_Total = cpu_to_le16(crtc_param->usH_Total); + conv_param.usH_Disp = cpu_to_le16(crtc_param->usH_Disp); + conv_param.usH_SyncStart = cpu_to_le16(crtc_param->usH_SyncStart); + conv_param.usH_SyncWidth = cpu_to_le16(crtc_param->usH_SyncWidth); + conv_param.usV_Total = cpu_to_le16(crtc_param->usV_Total); + conv_param.usV_Disp = cpu_to_le16(crtc_param->usV_Disp); + conv_param.usV_SyncStart = cpu_to_le16(crtc_param->usV_SyncStart); + conv_param.usV_SyncWidth = cpu_to_le16(crtc_param->usV_SyncWidth); + conv_param.susModeMiscInfo.usAccess = + cpu_to_le16(crtc_param->susModeMiscInfo.usAccess); + conv_param.ucCRTC = crtc_param->ucCRTC; + conv_param.ucOverscanRight = crtc_param->ucOverscanRight; + conv_param.ucOverscanLeft = crtc_param->ucOverscanLeft; + conv_param.ucOverscanBottom = crtc_param->ucOverscanBottom; + conv_param.ucOverscanTop = crtc_param->ucOverscanTop; + conv_param.ucReserved = crtc_param->ucReserved; + + printk("executing set crtc timing\n"); + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&conv_param); +} + +void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct radeon_device *rdev = dev->dev_private; + struct drm_encoder *encoder = NULL; + struct radeon_encoder *radeon_encoder = NULL; + uint8_t frev, crev; + int index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); + SET_PIXEL_CLOCK_PS_ALLOCATION args; + PIXEL_CLOCK_PARAMETERS *spc1_ptr; + PIXEL_CLOCK_PARAMETERS_V2 *spc2_ptr; + PIXEL_CLOCK_PARAMETERS_V3 *spc3_ptr; + uint32_t sclock = mode->clock; + uint32_t ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0; + struct radeon_pll *pll; + int pll_flags = 0; + + memset(&args, 0, sizeof(args)); + + if (ASIC_IS_AVIVO(rdev)) { + uint32_t ss_cntl; + + if (ASIC_IS_DCE32(rdev) && mode->clock > 200000) /* range limits??? */ + pll_flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; + else + pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV; + + /* disable spread spectrum clocking for now -- thanks Hedy Lamarr */ + if (radeon_crtc->crtc_id == 0) { + ss_cntl = RREG32(AVIVO_P1PLL_INT_SS_CNTL); + WREG32(AVIVO_P1PLL_INT_SS_CNTL, ss_cntl & ~1); + } else { + ss_cntl = RREG32(AVIVO_P2PLL_INT_SS_CNTL); + WREG32(AVIVO_P2PLL_INT_SS_CNTL, ss_cntl & ~1); + } + } else { + pll_flags |= RADEON_PLL_LEGACY; + + if (mode->clock > 200000) /* range limits??? */ + pll_flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; + else + pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV; + + } + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + if (encoder->crtc == crtc) { + if (!ASIC_IS_AVIVO(rdev)) { + if (encoder->encoder_type != + DRM_MODE_ENCODER_DAC) + pll_flags |= RADEON_PLL_NO_ODD_POST_DIV; + if (!ASIC_IS_AVIVO(rdev) + && (encoder->encoder_type == + DRM_MODE_ENCODER_LVDS)) + pll_flags |= RADEON_PLL_USE_REF_DIV; + } + radeon_encoder = to_radeon_encoder(encoder); + } + } + + if (radeon_crtc->crtc_id == 0) + pll = &rdev->clock.p1pll; + else + pll = &rdev->clock.p2pll; + + radeon_compute_pll(pll, mode->clock, &sclock, &fb_div, &frac_fb_div, + &ref_div, &post_div, pll_flags); + + atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, + &crev); + + switch (frev) { + case 1: + switch (crev) { + case 1: + spc1_ptr = (PIXEL_CLOCK_PARAMETERS *) & args.sPCLKInput; + spc1_ptr->usPixelClock = cpu_to_le16(sclock); + spc1_ptr->usRefDiv = cpu_to_le16(ref_div); + spc1_ptr->usFbDiv = cpu_to_le16(fb_div); + spc1_ptr->ucFracFbDiv = frac_fb_div; + spc1_ptr->ucPostDiv = post_div; + spc1_ptr->ucPpll = + radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1; + spc1_ptr->ucCRTC = radeon_crtc->crtc_id; + spc1_ptr->ucRefDivSrc = 1; + break; + case 2: + spc2_ptr = + (PIXEL_CLOCK_PARAMETERS_V2 *) & args.sPCLKInput; + spc2_ptr->usPixelClock = cpu_to_le16(sclock); + spc2_ptr->usRefDiv = cpu_to_le16(ref_div); + spc2_ptr->usFbDiv = cpu_to_le16(fb_div); + spc2_ptr->ucFracFbDiv = frac_fb_div; + spc2_ptr->ucPostDiv = post_div; + spc2_ptr->ucPpll = + radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1; + spc2_ptr->ucCRTC = radeon_crtc->crtc_id; + spc2_ptr->ucRefDivSrc = 1; + break; + case 3: + if (!encoder) + return; + spc3_ptr = + (PIXEL_CLOCK_PARAMETERS_V3 *) & args.sPCLKInput; + spc3_ptr->usPixelClock = cpu_to_le16(sclock); + spc3_ptr->usRefDiv = cpu_to_le16(ref_div); + spc3_ptr->usFbDiv = cpu_to_le16(fb_div); + spc3_ptr->ucFracFbDiv = frac_fb_div; + spc3_ptr->ucPostDiv = post_div; + spc3_ptr->ucPpll = + radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1; + spc3_ptr->ucMiscInfo = (radeon_crtc->crtc_id << 2); + spc3_ptr->ucTransmitterId = radeon_encoder->encoder_id; + spc3_ptr->ucEncoderMode = + atombios_get_encoder_mode(encoder); + break; + default: + DRM_ERROR("Unknown table version %d %d\n", frev, crev); + return; + } + break; + default: + DRM_ERROR("Unknown table version %d %d\n", frev, crev); + return; + } + + printk("executing set pll\n"); + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); +} + +int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y, + struct drm_framebuffer *old_fb) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_framebuffer *radeon_fb; + struct drm_gem_object *obj; + struct drm_radeon_gem_object *obj_priv; + uint64_t fb_location; + uint32_t fb_format, fb_pitch_pixels; + + if (!crtc->fb) + return -EINVAL; + + radeon_fb = to_radeon_framebuffer(crtc->fb); + + obj = radeon_fb->obj; + obj_priv = obj->driver_private; + + if (radeon_gem_object_pin(obj, RADEON_GEM_DOMAIN_VRAM, &fb_location)) { + return -EINVAL; + } + + switch (crtc->fb->bits_per_pixel) { + case 15: + fb_format = + AVIVO_D1GRPH_CONTROL_DEPTH_16BPP | + AVIVO_D1GRPH_CONTROL_16BPP_ARGB1555; + break; + case 16: + fb_format = + AVIVO_D1GRPH_CONTROL_DEPTH_16BPP | + AVIVO_D1GRPH_CONTROL_16BPP_RGB565; + break; + case 24: + case 32: + fb_format = + AVIVO_D1GRPH_CONTROL_DEPTH_32BPP | + AVIVO_D1GRPH_CONTROL_32BPP_ARGB8888; + break; + default: + DRM_ERROR("Unsupported screen depth %d\n", + crtc->fb->bits_per_pixel); + return -EINVAL; + } + + /* TODO tiling */ + if (radeon_crtc->crtc_id == 0) + WREG32(AVIVO_D1VGA_CONTROL, 0); + else + WREG32(AVIVO_D2VGA_CONTROL, 0); + WREG32(AVIVO_D1GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, + (u32) fb_location); + WREG32(AVIVO_D1GRPH_SECONDARY_SURFACE_ADDRESS + + radeon_crtc->crtc_offset, (u32) fb_location); + WREG32(AVIVO_D1GRPH_CONTROL + radeon_crtc->crtc_offset, fb_format); + + WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0); + WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0); + WREG32(AVIVO_D1GRPH_X_START + radeon_crtc->crtc_offset, 0); + WREG32(AVIVO_D1GRPH_Y_START + radeon_crtc->crtc_offset, 0); + WREG32(AVIVO_D1GRPH_X_END + radeon_crtc->crtc_offset, crtc->fb->width); + WREG32(AVIVO_D1GRPH_Y_END + radeon_crtc->crtc_offset, crtc->fb->height); + + fb_pitch_pixels = crtc->fb->pitch / (crtc->fb->bits_per_pixel / 8); + WREG32(AVIVO_D1GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels); + WREG32(AVIVO_D1GRPH_ENABLE + radeon_crtc->crtc_offset, 1); + + WREG32(AVIVO_D1MODE_DESKTOP_HEIGHT + radeon_crtc->crtc_offset, + crtc->mode.vdisplay); + x &= ~3; + y &= ~1; + WREG32(AVIVO_D1MODE_VIEWPORT_START + radeon_crtc->crtc_offset, + (x << 16) | y); + WREG32(AVIVO_D1MODE_VIEWPORT_SIZE + radeon_crtc->crtc_offset, + (crtc->mode.hdisplay << 16) | crtc->mode.vdisplay); + + if (crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) + WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, + AVIVO_D1MODE_INTERLEAVE_EN); + else + WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, 0); + + if (old_fb && old_fb != crtc->fb) { + radeon_fb = to_radeon_framebuffer(old_fb); + radeon_gem_object_unpin(radeon_fb->obj); + } + return 0; +} + +int atombios_crtc_mode_set(struct drm_crtc *crtc, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode, + int x, int y, struct drm_framebuffer *old_fb) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct radeon_device *rdev = dev->dev_private; + struct drm_encoder *encoder; + SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION crtc_timing; + + /* TODO color tiling */ + memset(&crtc_timing, 0, sizeof(crtc_timing)); + + /* TODO tv */ + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + + } + + crtc_timing.ucCRTC = radeon_crtc->crtc_id; + crtc_timing.usH_Total = adjusted_mode->crtc_htotal; + crtc_timing.usH_Disp = adjusted_mode->crtc_hdisplay; + crtc_timing.usH_SyncStart = adjusted_mode->crtc_hsync_start; + crtc_timing.usH_SyncWidth = + adjusted_mode->crtc_hsync_end - adjusted_mode->crtc_hsync_start; + + crtc_timing.usV_Total = adjusted_mode->crtc_vtotal; + crtc_timing.usV_Disp = adjusted_mode->crtc_vdisplay; + crtc_timing.usV_SyncStart = adjusted_mode->crtc_vsync_start; + crtc_timing.usV_SyncWidth = + adjusted_mode->crtc_vsync_end - adjusted_mode->crtc_vsync_start; + + if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) + crtc_timing.susModeMiscInfo.usAccess |= ATOM_VSYNC_POLARITY; + + if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) + crtc_timing.susModeMiscInfo.usAccess |= ATOM_HSYNC_POLARITY; + + if (adjusted_mode->flags & DRM_MODE_FLAG_CSYNC) + crtc_timing.susModeMiscInfo.usAccess |= ATOM_COMPOSITESYNC; + + if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) + crtc_timing.susModeMiscInfo.usAccess |= ATOM_INTERLACE; + + if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) + crtc_timing.susModeMiscInfo.usAccess |= ATOM_DOUBLE_CLOCK_MODE; + + atombios_crtc_set_pll(crtc, adjusted_mode); + atombios_crtc_set_timing(crtc, &crtc_timing); + + if (ASIC_IS_AVIVO(rdev)) + atombios_crtc_set_base(crtc, x, y, old_fb); + else { + if (radeon_crtc->crtc_id == 0) { + SET_CRTC_USING_DTD_TIMING_PARAMETERS crtc_dtd_timing; + memset(&crtc_dtd_timing, 0, sizeof(crtc_dtd_timing)); + + /* setup FP shadow regs on R4xx */ + crtc_dtd_timing.ucCRTC = radeon_crtc->crtc_id; + crtc_dtd_timing.usH_Size = adjusted_mode->crtc_hdisplay; + crtc_dtd_timing.usV_Size = adjusted_mode->crtc_vdisplay; + crtc_dtd_timing.usH_Blanking_Time = + adjusted_mode->crtc_hblank_end - + adjusted_mode->crtc_hdisplay; + crtc_dtd_timing.usV_Blanking_Time = + adjusted_mode->crtc_vblank_end - + adjusted_mode->crtc_vdisplay; + crtc_dtd_timing.usH_SyncOffset = + adjusted_mode->crtc_hsync_start - + adjusted_mode->crtc_hdisplay; + crtc_dtd_timing.usV_SyncOffset = + adjusted_mode->crtc_vsync_start - + adjusted_mode->crtc_vdisplay; + crtc_dtd_timing.usH_SyncWidth = + adjusted_mode->crtc_hsync_end - + adjusted_mode->crtc_hsync_start; + crtc_dtd_timing.usV_SyncWidth = + adjusted_mode->crtc_vsync_end - + adjusted_mode->crtc_vsync_start; + /* crtc_dtd_timing.ucH_Border = adjusted_mode->crtc_hborder; */ + /* crtc_dtd_timing.ucV_Border = adjusted_mode->crtc_vborder; */ + + if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) + crtc_dtd_timing.susModeMiscInfo.usAccess |= + ATOM_VSYNC_POLARITY; + + if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) + crtc_dtd_timing.susModeMiscInfo.usAccess |= + ATOM_HSYNC_POLARITY; + + if (adjusted_mode->flags & DRM_MODE_FLAG_CSYNC) + crtc_dtd_timing.susModeMiscInfo.usAccess |= + ATOM_COMPOSITESYNC; + + if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) + crtc_dtd_timing.susModeMiscInfo.usAccess |= + ATOM_INTERLACE; + + if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) + crtc_dtd_timing.susModeMiscInfo.usAccess |= + ATOM_DOUBLE_CLOCK_MODE; + + atombios_set_crtc_dtd_timing(crtc, &crtc_dtd_timing); + } + radeon_crtc_set_base(crtc, x, y, old_fb); + radeon_legacy_atom_set_surface(crtc); + } + return 0; +} + +static bool atombios_crtc_mode_fixup(struct drm_crtc *crtc, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + return true; +} + +static void atombios_crtc_prepare(struct drm_crtc *crtc) +{ + atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); + atombios_lock_crtc(crtc, 1); +} + +static void atombios_crtc_commit(struct drm_crtc *crtc) +{ + atombios_crtc_dpms(crtc, DRM_MODE_DPMS_ON); + atombios_lock_crtc(crtc, 0); +} + +static const struct drm_crtc_helper_funcs atombios_helper_funcs = { + .dpms = atombios_crtc_dpms, + .mode_fixup = atombios_crtc_mode_fixup, + .mode_set = atombios_crtc_mode_set, + .mode_set_base = atombios_crtc_set_base, + .prepare = atombios_crtc_prepare, + .commit = atombios_crtc_commit, +}; + +void radeon_atombios_init_crtc(struct drm_device *dev, + struct radeon_crtc *radeon_crtc) +{ + if (radeon_crtc->crtc_id == 1) + radeon_crtc->crtc_offset = + AVIVO_D2CRTC_H_TOTAL - AVIVO_D1CRTC_H_TOTAL; + drm_crtc_helper_add(&radeon_crtc->base, &atombios_helper_funcs); +} + +void radeon_init_disp_bw_avivo(struct drm_device *dev, + struct drm_display_mode *mode1, + uint32_t pixel_bytes1, + struct drm_display_mode *mode2, + uint32_t pixel_bytes2) +{ + struct radeon_device *rdev = dev->dev_private; + fixed20_12 min_mem_eff; + fixed20_12 peak_disp_bw, mem_bw, pix_clk, pix_clk2, temp_ff; + fixed20_12 sclk_ff, mclk_ff; + uint32_t dc_lb_memory_split, temp; + + min_mem_eff.full = rfixed_const_8(0); + if (rdev->disp_priority == 2) { + uint32_t mc_init_misc_lat_timer = 0; + if (rdev->family == CHIP_RV515) + mc_init_misc_lat_timer = + RREG32_MC(RV515_MC_INIT_MISC_LAT_TIMER); + else if (rdev->family == CHIP_RS690) + mc_init_misc_lat_timer = + RREG32_MC(RS690_MC_INIT_MISC_LAT_TIMER); + + mc_init_misc_lat_timer &= + ~(R300_MC_DISP1R_INIT_LAT_MASK << + R300_MC_DISP1R_INIT_LAT_SHIFT); + mc_init_misc_lat_timer &= + ~(R300_MC_DISP0R_INIT_LAT_MASK << + R300_MC_DISP0R_INIT_LAT_SHIFT); + + if (mode2) + mc_init_misc_lat_timer |= + (1 << R300_MC_DISP1R_INIT_LAT_SHIFT); + if (mode1) + mc_init_misc_lat_timer |= + (1 << R300_MC_DISP0R_INIT_LAT_SHIFT); + + if (rdev->family == CHIP_RV515) + WREG32_MC(RV515_MC_INIT_MISC_LAT_TIMER, + mc_init_misc_lat_timer); + else if (rdev->family == CHIP_RS690) + WREG32_MC(RS690_MC_INIT_MISC_LAT_TIMER, + mc_init_misc_lat_timer); + } + + /* + * determine is there is enough bw for current mode + */ + temp_ff.full = rfixed_const(100); + mclk_ff.full = rfixed_const(rdev->clock.default_mclk); + mclk_ff.full = rfixed_div(mclk_ff, temp_ff); + sclk_ff.full = rfixed_const(rdev->clock.default_sclk); + sclk_ff.full = rfixed_div(sclk_ff, temp_ff); + + temp = (rdev->mc.vram_width / 8) * (rdev->mc.vram_is_ddr ? 2 : 1); + temp_ff.full = rfixed_const(temp); + mem_bw.full = rfixed_mul(mclk_ff, temp_ff); + mem_bw.full = rfixed_mul(mem_bw, min_mem_eff); + + pix_clk.full = 0; + pix_clk2.full = 0; + peak_disp_bw.full = 0; + if (mode1) { + temp_ff.full = rfixed_const(1000); + pix_clk.full = rfixed_const(mode1->clock); /* convert to fixed point */ + pix_clk.full = rfixed_div(pix_clk, temp_ff); + temp_ff.full = rfixed_const(pixel_bytes1); + peak_disp_bw.full += rfixed_mul(pix_clk, temp_ff); + } + if (mode2) { + temp_ff.full = rfixed_const(1000); + pix_clk2.full = rfixed_const(mode2->clock); /* convert to fixed point */ + pix_clk2.full = rfixed_div(pix_clk2, temp_ff); + temp_ff.full = rfixed_const(pixel_bytes2); + peak_disp_bw.full += rfixed_mul(pix_clk2, temp_ff); + } + + if (peak_disp_bw.full >= mem_bw.full) { + DRM_ERROR + ("You may not have enough display bandwidth for current mode\n" + "If you have flickering problem, try to lower resolution, refresh rate, or color depth\n"); + printk("peak disp bw %d, mem_bw %d\n", + rfixed_trunc(peak_disp_bw), rfixed_trunc(mem_bw)); + } + + /* + * Line Buffer Setup + * There is a single line buffer shared by both display controllers. + * DC_LB_MEMORY_SPLIT controls how that line buffer is shared between the display + * controllers. The paritioning can either be done manually or via one of four + * preset allocations specified in bits 1:0: + * 0 - line buffer is divided in half and shared between each display controller + * 1 - D1 gets 3/4 of the line buffer, D2 gets 1/4 + * 2 - D1 gets the whole buffer + * 3 - D1 gets 1/4 of the line buffer, D2 gets 3/4 + * Setting bit 2 of DC_LB_MEMORY_SPLIT controls switches to manual allocation mode. + * In manual allocation mode, D1 always starts at 0, D1 end/2 is specified in bits + * 14:4; D2 allocation follows D1. + */ + + /* is auto or manual better ? */ + dc_lb_memory_split = + RREG32(AVIVO_DC_LB_MEMORY_SPLIT) & ~AVIVO_DC_LB_MEMORY_SPLIT_MASK; + dc_lb_memory_split &= ~AVIVO_DC_LB_MEMORY_SPLIT_SHIFT_MODE; +#if 1 + /* auto */ + if (mode1 && mode2) { + if (mode1->hdisplay > mode2->hdisplay) { + if (mode1->hdisplay > 2560) + dc_lb_memory_split |= + AVIVO_DC_LB_MEMORY_SPLIT_D1_3Q_D2_1Q; + else + dc_lb_memory_split |= + AVIVO_DC_LB_MEMORY_SPLIT_D1HALF_D2HALF; + } else if (mode2->hdisplay > mode1->hdisplay) { + if (mode2->hdisplay > 2560) + dc_lb_memory_split |= + AVIVO_DC_LB_MEMORY_SPLIT_D1_1Q_D2_3Q; + else + dc_lb_memory_split |= + AVIVO_DC_LB_MEMORY_SPLIT_D1HALF_D2HALF; + } else + dc_lb_memory_split |= + AVIVO_DC_LB_MEMORY_SPLIT_D1HALF_D2HALF; + } else if (mode1) { + dc_lb_memory_split |= AVIVO_DC_LB_MEMORY_SPLIT_D1_ONLY; + } else if (mode2) { + dc_lb_memory_split |= AVIVO_DC_LB_MEMORY_SPLIT_D1_1Q_D2_3Q; + } +#else + /* manual */ + dc_lb_memory_split |= AVIVO_DC_LB_MEMORY_SPLIT_SHIFT_MODE; + dc_lb_memory_split &= + ~(AVIVO_DC_LB_DISP1_END_ADR_MASK << + AVIVO_DC_LB_DISP1_END_ADR_SHIFT); + if (mode1) { + dc_lb_memory_split |= + ((((mode1->hdisplay / 2) + 64) & AVIVO_DC_LB_DISP1_END_ADR_MASK) + << AVIVO_DC_LB_DISP1_END_ADR_SHIFT); + } else if (mode2) { + dc_lb_memory_split |= (0 << AVIVO_DC_LB_DISP1_END_ADR_SHIFT); + } +#endif + WREG32(AVIVO_DC_LB_MEMORY_SPLIT, dc_lb_memory_split); +} diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c new file mode 100644 index 000000000000..c550932a108f --- /dev/null +++ b/drivers/gpu/drm/radeon/r100.c @@ -0,0 +1,1535 @@ +/* + * Copyright 2008 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * Copyright 2009 Jerome Glisse. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Dave Airlie + * Alex Deucher + * Jerome Glisse + */ +#include +#include "drmP.h" +#include "drm.h" +#include "radeon_drm.h" +#include "radeon_microcode.h" +#include "radeon_reg.h" +#include "radeon.h" + +/* This files gather functions specifics to: + * r100,rv100,rs100,rv200,rs200,r200,rv250,rs300,rv280 + * + * Some of these functions might be used by newer ASICs. + */ +void r100_hdp_reset(struct radeon_device *rdev); +void r100_gpu_init(struct radeon_device *rdev); +int r100_gui_wait_for_idle(struct radeon_device *rdev); +int r100_mc_wait_for_idle(struct radeon_device *rdev); +void r100_gpu_wait_for_vsync(struct radeon_device *rdev); +void r100_gpu_wait_for_vsync2(struct radeon_device *rdev); +int r100_debugfs_mc_info_init(struct radeon_device *rdev); + + +/* + * PCI GART + */ +void r100_pci_gart_tlb_flush(struct radeon_device *rdev) +{ + /* TODO: can we do somethings here ? */ + /* It seems hw only cache one entry so we should discard this + * entry otherwise if first GPU GART read hit this entry it + * could end up in wrong address. */ +} + +int r100_pci_gart_enable(struct radeon_device *rdev) +{ + uint32_t tmp; + int r; + + /* Initialize common gart structure */ + r = radeon_gart_init(rdev); + if (r) { + return r; + } + if (rdev->gart.table.ram.ptr == NULL) { + rdev->gart.table_size = rdev->gart.num_gpu_pages * 4; + r = radeon_gart_table_ram_alloc(rdev); + if (r) { + return r; + } + } + /* discard memory request outside of configured range */ + tmp = RREG32(RADEON_AIC_CNTL) | RADEON_DIS_OUT_OF_PCI_GART_ACCESS; + WREG32(RADEON_AIC_CNTL, tmp); + /* set address range for PCI address translate */ + WREG32(RADEON_AIC_LO_ADDR, rdev->mc.gtt_location); + tmp = rdev->mc.gtt_location + rdev->mc.gtt_size - 1; + WREG32(RADEON_AIC_HI_ADDR, tmp); + /* Enable bus mastering */ + tmp = RREG32(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS; + WREG32(RADEON_BUS_CNTL, tmp); + /* set PCI GART page-table base address */ + WREG32(RADEON_AIC_PT_BASE, rdev->gart.table_addr); + tmp = RREG32(RADEON_AIC_CNTL) | RADEON_PCIGART_TRANSLATE_EN; + WREG32(RADEON_AIC_CNTL, tmp); + r100_pci_gart_tlb_flush(rdev); + rdev->gart.ready = true; + return 0; +} + +void r100_pci_gart_disable(struct radeon_device *rdev) +{ + uint32_t tmp; + + /* discard memory request outside of configured range */ + tmp = RREG32(RADEON_AIC_CNTL) | RADEON_DIS_OUT_OF_PCI_GART_ACCESS; + WREG32(RADEON_AIC_CNTL, tmp & ~RADEON_PCIGART_TRANSLATE_EN); + WREG32(RADEON_AIC_LO_ADDR, 0); + WREG32(RADEON_AIC_HI_ADDR, 0); +} + +int r100_pci_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr) +{ + if (i < 0 || i > rdev->gart.num_gpu_pages) { + return -EINVAL; + } + rdev->gart.table.ram.ptr[i] = cpu_to_le32((uint32_t)addr); + return 0; +} + +int r100_gart_enable(struct radeon_device *rdev) +{ + if (rdev->flags & RADEON_IS_AGP) { + r100_pci_gart_disable(rdev); + return 0; + } + return r100_pci_gart_enable(rdev); +} + + +/* + * MC + */ +void r100_mc_disable_clients(struct radeon_device *rdev) +{ + uint32_t ov0_scale_cntl, crtc_ext_cntl, crtc_gen_cntl, crtc2_gen_cntl; + + /* FIXME: is this function correct for rs100,rs200,rs300 ? */ + if (r100_gui_wait_for_idle(rdev)) { + printk(KERN_WARNING "Failed to wait GUI idle while " + "programming pipes. Bad things might happen.\n"); + } + + /* stop display and memory access */ + ov0_scale_cntl = RREG32(RADEON_OV0_SCALE_CNTL); + WREG32(RADEON_OV0_SCALE_CNTL, ov0_scale_cntl & ~RADEON_SCALER_ENABLE); + crtc_ext_cntl = RREG32(RADEON_CRTC_EXT_CNTL); + WREG32(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl | RADEON_CRTC_DISPLAY_DIS); + crtc_gen_cntl = RREG32(RADEON_CRTC_GEN_CNTL); + + r100_gpu_wait_for_vsync(rdev); + + WREG32(RADEON_CRTC_GEN_CNTL, + (crtc_gen_cntl & ~(RADEON_CRTC_CUR_EN | RADEON_CRTC_ICON_EN)) | + RADEON_CRTC_DISP_REQ_EN_B | RADEON_CRTC_EXT_DISP_EN); + + if (!(rdev->flags & RADEON_SINGLE_CRTC)) { + crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL); + + r100_gpu_wait_for_vsync2(rdev); + WREG32(RADEON_CRTC2_GEN_CNTL, + (crtc2_gen_cntl & + ~(RADEON_CRTC2_CUR_EN | RADEON_CRTC2_ICON_EN)) | + RADEON_CRTC2_DISP_REQ_EN_B); + } + + udelay(500); +} + +void r100_mc_setup(struct radeon_device *rdev) +{ + uint32_t tmp; + int r; + + r = r100_debugfs_mc_info_init(rdev); + if (r) { + DRM_ERROR("Failed to register debugfs file for R100 MC !\n"); + } + /* Write VRAM size in case we are limiting it */ + WREG32(RADEON_CONFIG_MEMSIZE, rdev->mc.vram_size); + tmp = rdev->mc.vram_location + rdev->mc.vram_size - 1; + tmp = REG_SET(RADEON_MC_FB_TOP, tmp >> 16); + tmp |= REG_SET(RADEON_MC_FB_START, rdev->mc.vram_location >> 16); + WREG32(RADEON_MC_FB_LOCATION, tmp); + + /* Enable bus mastering */ + tmp = RREG32(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS; + WREG32(RADEON_BUS_CNTL, tmp); + + if (rdev->flags & RADEON_IS_AGP) { + tmp = rdev->mc.gtt_location + rdev->mc.gtt_size - 1; + tmp = REG_SET(RADEON_MC_AGP_TOP, tmp >> 16); + tmp |= REG_SET(RADEON_MC_AGP_START, rdev->mc.gtt_location >> 16); + WREG32(RADEON_MC_AGP_LOCATION, tmp); + WREG32(RADEON_AGP_BASE, rdev->mc.agp_base); + } else { + WREG32(RADEON_MC_AGP_LOCATION, 0x0FFFFFFF); + WREG32(RADEON_AGP_BASE, 0); + } + + tmp = RREG32(RADEON_HOST_PATH_CNTL) & RADEON_HDP_APER_CNTL; + tmp |= (7 << 28); + WREG32(RADEON_HOST_PATH_CNTL, tmp | RADEON_HDP_SOFT_RESET | RADEON_HDP_READ_BUFFER_INVALIDATE); + (void)RREG32(RADEON_HOST_PATH_CNTL); + WREG32(RADEON_HOST_PATH_CNTL, tmp); + (void)RREG32(RADEON_HOST_PATH_CNTL); +} + +int r100_mc_init(struct radeon_device *rdev) +{ + int r; + + if (r100_debugfs_rbbm_init(rdev)) { + DRM_ERROR("Failed to register debugfs file for RBBM !\n"); + } + + r100_gpu_init(rdev); + /* Disable gart which also disable out of gart access */ + r100_pci_gart_disable(rdev); + + /* Setup GPU memory space */ + rdev->mc.vram_location = 0xFFFFFFFFUL; + rdev->mc.gtt_location = 0xFFFFFFFFUL; + if (rdev->flags & RADEON_IS_AGP) { + r = radeon_agp_init(rdev); + if (r) { + printk(KERN_WARNING "[drm] Disabling AGP\n"); + rdev->flags &= ~RADEON_IS_AGP; + rdev->mc.gtt_size = radeon_gart_size * 1024 * 1024; + } else { + rdev->mc.gtt_location = rdev->mc.agp_base; + } + } + r = radeon_mc_setup(rdev); + if (r) { + return r; + } + + r100_mc_disable_clients(rdev); + if (r100_mc_wait_for_idle(rdev)) { + printk(KERN_WARNING "Failed to wait MC idle while " + "programming pipes. Bad things might happen.\n"); + } + + r100_mc_setup(rdev); + return 0; +} + +void r100_mc_fini(struct radeon_device *rdev) +{ + r100_pci_gart_disable(rdev); + radeon_gart_table_ram_free(rdev); + radeon_gart_fini(rdev); +} + + +/* + * Fence emission + */ +void r100_fence_ring_emit(struct radeon_device *rdev, + struct radeon_fence *fence) +{ + /* Who ever call radeon_fence_emit should call ring_lock and ask + * for enough space (today caller are ib schedule and buffer move) */ + /* Wait until IDLE & CLEAN */ + radeon_ring_write(rdev, PACKET0(0x1720, 0)); + radeon_ring_write(rdev, (1 << 16) | (1 << 17)); + /* Emit fence sequence & fire IRQ */ + radeon_ring_write(rdev, PACKET0(rdev->fence_drv.scratch_reg, 0)); + radeon_ring_write(rdev, fence->seq); + radeon_ring_write(rdev, PACKET0(RADEON_GEN_INT_STATUS, 0)); + radeon_ring_write(rdev, RADEON_SW_INT_FIRE); +} + + +/* + * Writeback + */ +int r100_wb_init(struct radeon_device *rdev) +{ + int r; + + if (rdev->wb.wb_obj == NULL) { + r = radeon_object_create(rdev, NULL, 4096, + true, + RADEON_GEM_DOMAIN_GTT, + false, &rdev->wb.wb_obj); + if (r) { + DRM_ERROR("radeon: failed to create WB buffer (%d).\n", r); + return r; + } + r = radeon_object_pin(rdev->wb.wb_obj, + RADEON_GEM_DOMAIN_GTT, + &rdev->wb.gpu_addr); + if (r) { + DRM_ERROR("radeon: failed to pin WB buffer (%d).\n", r); + return r; + } + r = radeon_object_kmap(rdev->wb.wb_obj, (void **)&rdev->wb.wb); + if (r) { + DRM_ERROR("radeon: failed to map WB buffer (%d).\n", r); + return r; + } + } + WREG32(0x774, rdev->wb.gpu_addr); + WREG32(0x70C, rdev->wb.gpu_addr + 1024); + WREG32(0x770, 0xff); + return 0; +} + +void r100_wb_fini(struct radeon_device *rdev) +{ + if (rdev->wb.wb_obj) { + radeon_object_kunmap(rdev->wb.wb_obj); + radeon_object_unpin(rdev->wb.wb_obj); + radeon_object_unref(&rdev->wb.wb_obj); + rdev->wb.wb = NULL; + rdev->wb.wb_obj = NULL; + } +} + +int r100_copy_blit(struct radeon_device *rdev, + uint64_t src_offset, + uint64_t dst_offset, + unsigned num_pages, + struct radeon_fence *fence) +{ + uint32_t cur_pages; + uint32_t stride_bytes = PAGE_SIZE; + uint32_t pitch; + uint32_t stride_pixels; + unsigned ndw; + int num_loops; + int r = 0; + + /* radeon limited to 16k stride */ + stride_bytes &= 0x3fff; + /* radeon pitch is /64 */ + pitch = stride_bytes / 64; + stride_pixels = stride_bytes / 4; + num_loops = DIV_ROUND_UP(num_pages, 8191); + + /* Ask for enough room for blit + flush + fence */ + ndw = 64 + (10 * num_loops); + r = radeon_ring_lock(rdev, ndw); + if (r) { + DRM_ERROR("radeon: moving bo (%d) asking for %u dw.\n", r, ndw); + return -EINVAL; + } + while (num_pages > 0) { + cur_pages = num_pages; + if (cur_pages > 8191) { + cur_pages = 8191; + } + num_pages -= cur_pages; + + /* pages are in Y direction - height + page width in X direction - width */ + radeon_ring_write(rdev, PACKET3(PACKET3_BITBLT_MULTI, 8)); + radeon_ring_write(rdev, + RADEON_GMC_SRC_PITCH_OFFSET_CNTL | + RADEON_GMC_DST_PITCH_OFFSET_CNTL | + RADEON_GMC_SRC_CLIPPING | + RADEON_GMC_DST_CLIPPING | + RADEON_GMC_BRUSH_NONE | + (RADEON_COLOR_FORMAT_ARGB8888 << 8) | + RADEON_GMC_SRC_DATATYPE_COLOR | + RADEON_ROP3_S | + RADEON_DP_SRC_SOURCE_MEMORY | + RADEON_GMC_CLR_CMP_CNTL_DIS | + RADEON_GMC_WR_MSK_DIS); + radeon_ring_write(rdev, (pitch << 22) | (src_offset >> 10)); + radeon_ring_write(rdev, (pitch << 22) | (dst_offset >> 10)); + radeon_ring_write(rdev, (0x1fff) | (0x1fff << 16)); + radeon_ring_write(rdev, 0); + radeon_ring_write(rdev, (0x1fff) | (0x1fff << 16)); + radeon_ring_write(rdev, num_pages); + radeon_ring_write(rdev, num_pages); + radeon_ring_write(rdev, cur_pages | (stride_pixels << 16)); + } + radeon_ring_write(rdev, PACKET0(RADEON_DSTCACHE_CTLSTAT, 0)); + radeon_ring_write(rdev, RADEON_RB2D_DC_FLUSH_ALL); + radeon_ring_write(rdev, PACKET0(RADEON_WAIT_UNTIL, 0)); + radeon_ring_write(rdev, + RADEON_WAIT_2D_IDLECLEAN | + RADEON_WAIT_HOST_IDLECLEAN | + RADEON_WAIT_DMA_GUI_IDLE); + if (fence) { + r = radeon_fence_emit(rdev, fence); + } + radeon_ring_unlock_commit(rdev); + return r; +} + + +/* + * CP + */ +void r100_ring_start(struct radeon_device *rdev) +{ + int r; + + r = radeon_ring_lock(rdev, 2); + if (r) { + return; + } + radeon_ring_write(rdev, PACKET0(RADEON_ISYNC_CNTL, 0)); + radeon_ring_write(rdev, + RADEON_ISYNC_ANY2D_IDLE3D | + RADEON_ISYNC_ANY3D_IDLE2D | + RADEON_ISYNC_WAIT_IDLEGUI | + RADEON_ISYNC_CPSCRATCH_IDLEGUI); + radeon_ring_unlock_commit(rdev); +} + +static void r100_cp_load_microcode(struct radeon_device *rdev) +{ + int i; + + if (r100_gui_wait_for_idle(rdev)) { + printk(KERN_WARNING "Failed to wait GUI idle while " + "programming pipes. Bad things might happen.\n"); + } + + WREG32(RADEON_CP_ME_RAM_ADDR, 0); + if ((rdev->family == CHIP_R100) || (rdev->family == CHIP_RV100) || + (rdev->family == CHIP_RV200) || (rdev->family == CHIP_RS100) || + (rdev->family == CHIP_RS200)) { + DRM_INFO("Loading R100 Microcode\n"); + for (i = 0; i < 256; i++) { + WREG32(RADEON_CP_ME_RAM_DATAH, R100_cp_microcode[i][1]); + WREG32(RADEON_CP_ME_RAM_DATAL, R100_cp_microcode[i][0]); + } + } else if ((rdev->family == CHIP_R200) || + (rdev->family == CHIP_RV250) || + (rdev->family == CHIP_RV280) || + (rdev->family == CHIP_RS300)) { + DRM_INFO("Loading R200 Microcode\n"); + for (i = 0; i < 256; i++) { + WREG32(RADEON_CP_ME_RAM_DATAH, R200_cp_microcode[i][1]); + WREG32(RADEON_CP_ME_RAM_DATAL, R200_cp_microcode[i][0]); + } + } else if ((rdev->family == CHIP_R300) || + (rdev->family == CHIP_R350) || + (rdev->family == CHIP_RV350) || + (rdev->family == CHIP_RV380) || + (rdev->family == CHIP_RS400) || + (rdev->family == CHIP_RS480)) { + DRM_INFO("Loading R300 Microcode\n"); + for (i = 0; i < 256; i++) { + WREG32(RADEON_CP_ME_RAM_DATAH, R300_cp_microcode[i][1]); + WREG32(RADEON_CP_ME_RAM_DATAL, R300_cp_microcode[i][0]); + } + } else if ((rdev->family == CHIP_R420) || + (rdev->family == CHIP_R423) || + (rdev->family == CHIP_RV410)) { + DRM_INFO("Loading R400 Microcode\n"); + for (i = 0; i < 256; i++) { + WREG32(RADEON_CP_ME_RAM_DATAH, R420_cp_microcode[i][1]); + WREG32(RADEON_CP_ME_RAM_DATAL, R420_cp_microcode[i][0]); + } + } else if ((rdev->family == CHIP_RS690) || + (rdev->family == CHIP_RS740)) { + DRM_INFO("Loading RS690/RS740 Microcode\n"); + for (i = 0; i < 256; i++) { + WREG32(RADEON_CP_ME_RAM_DATAH, RS690_cp_microcode[i][1]); + WREG32(RADEON_CP_ME_RAM_DATAL, RS690_cp_microcode[i][0]); + } + } else if (rdev->family == CHIP_RS600) { + DRM_INFO("Loading RS600 Microcode\n"); + for (i = 0; i < 256; i++) { + WREG32(RADEON_CP_ME_RAM_DATAH, RS600_cp_microcode[i][1]); + WREG32(RADEON_CP_ME_RAM_DATAL, RS600_cp_microcode[i][0]); + } + } else if ((rdev->family == CHIP_RV515) || + (rdev->family == CHIP_R520) || + (rdev->family == CHIP_RV530) || + (rdev->family == CHIP_R580) || + (rdev->family == CHIP_RV560) || + (rdev->family == CHIP_RV570)) { + DRM_INFO("Loading R500 Microcode\n"); + for (i = 0; i < 256; i++) { + WREG32(RADEON_CP_ME_RAM_DATAH, R520_cp_microcode[i][1]); + WREG32(RADEON_CP_ME_RAM_DATAL, R520_cp_microcode[i][0]); + } + } +} + +int r100_cp_init(struct radeon_device *rdev, unsigned ring_size) +{ + unsigned rb_bufsz; + unsigned rb_blksz; + unsigned max_fetch; + unsigned pre_write_timer; + unsigned pre_write_limit; + unsigned indirect2_start; + unsigned indirect1_start; + uint32_t tmp; + int r; + + if (r100_debugfs_cp_init(rdev)) { + DRM_ERROR("Failed to register debugfs file for CP !\n"); + } + /* Reset CP */ + tmp = RREG32(RADEON_CP_CSQ_STAT); + if ((tmp & (1 << 31))) { + DRM_INFO("radeon: cp busy (0x%08X) resetting\n", tmp); + WREG32(RADEON_CP_CSQ_MODE, 0); + WREG32(RADEON_CP_CSQ_CNTL, 0); + WREG32(RADEON_RBBM_SOFT_RESET, RADEON_SOFT_RESET_CP); + tmp = RREG32(RADEON_RBBM_SOFT_RESET); + mdelay(2); + WREG32(RADEON_RBBM_SOFT_RESET, 0); + tmp = RREG32(RADEON_RBBM_SOFT_RESET); + mdelay(2); + tmp = RREG32(RADEON_CP_CSQ_STAT); + if ((tmp & (1 << 31))) { + DRM_INFO("radeon: cp reset failed (0x%08X)\n", tmp); + } + } else { + DRM_INFO("radeon: cp idle (0x%08X)\n", tmp); + } + /* Align ring size */ + rb_bufsz = drm_order(ring_size / 8); + ring_size = (1 << (rb_bufsz + 1)) * 4; + r100_cp_load_microcode(rdev); + r = radeon_ring_init(rdev, ring_size); + if (r) { + return r; + } + /* Each time the cp read 1024 bytes (16 dword/quadword) update + * the rptr copy in system ram */ + rb_blksz = 9; + /* cp will read 128bytes at a time (4 dwords) */ + max_fetch = 1; + rdev->cp.align_mask = 16 - 1; + /* Write to CP_RB_WPTR will be delayed for pre_write_timer clocks */ + pre_write_timer = 64; + /* Force CP_RB_WPTR write if written more than one time before the + * delay expire + */ + pre_write_limit = 0; + /* Setup the cp cache like this (cache size is 96 dwords) : + * RING 0 to 15 + * INDIRECT1 16 to 79 + * INDIRECT2 80 to 95 + * So ring cache size is 16dwords (> (2 * max_fetch = 2 * 4dwords)) + * indirect1 cache size is 64dwords (> (2 * max_fetch = 2 * 4dwords)) + * indirect2 cache size is 16dwords (> (2 * max_fetch = 2 * 4dwords)) + * Idea being that most of the gpu cmd will be through indirect1 buffer + * so it gets the bigger cache. + */ + indirect2_start = 80; + indirect1_start = 16; + /* cp setup */ + WREG32(0x718, pre_write_timer | (pre_write_limit << 28)); + WREG32(RADEON_CP_RB_CNTL, +#ifdef __BIG_ENDIAN + RADEON_BUF_SWAP_32BIT | +#endif + REG_SET(RADEON_RB_BUFSZ, rb_bufsz) | + REG_SET(RADEON_RB_BLKSZ, rb_blksz) | + REG_SET(RADEON_MAX_FETCH, max_fetch) | + RADEON_RB_NO_UPDATE); + /* Set ring address */ + DRM_INFO("radeon: ring at 0x%016lX\n", (unsigned long)rdev->cp.gpu_addr); + WREG32(RADEON_CP_RB_BASE, rdev->cp.gpu_addr); + /* Force read & write ptr to 0 */ + tmp = RREG32(RADEON_CP_RB_CNTL); + WREG32(RADEON_CP_RB_CNTL, tmp | RADEON_RB_RPTR_WR_ENA); + WREG32(RADEON_CP_RB_RPTR_WR, 0); + WREG32(RADEON_CP_RB_WPTR, 0); + WREG32(RADEON_CP_RB_CNTL, tmp); + udelay(10); + rdev->cp.rptr = RREG32(RADEON_CP_RB_RPTR); + rdev->cp.wptr = RREG32(RADEON_CP_RB_WPTR); + /* Set cp mode to bus mastering & enable cp*/ + WREG32(RADEON_CP_CSQ_MODE, + REG_SET(RADEON_INDIRECT2_START, indirect2_start) | + REG_SET(RADEON_INDIRECT1_START, indirect1_start)); + WREG32(0x718, 0); + WREG32(0x744, 0x00004D4D); + WREG32(RADEON_CP_CSQ_CNTL, RADEON_CSQ_PRIBM_INDBM); + radeon_ring_start(rdev); + r = radeon_ring_test(rdev); + if (r) { + DRM_ERROR("radeon: cp isn't working (%d).\n", r); + return r; + } + rdev->cp.ready = true; + return 0; +} + +void r100_cp_fini(struct radeon_device *rdev) +{ + /* Disable ring */ + rdev->cp.ready = false; + WREG32(RADEON_CP_CSQ_CNTL, 0); + radeon_ring_fini(rdev); + DRM_INFO("radeon: cp finalized\n"); +} + +void r100_cp_disable(struct radeon_device *rdev) +{ + /* Disable ring */ + rdev->cp.ready = false; + WREG32(RADEON_CP_CSQ_MODE, 0); + WREG32(RADEON_CP_CSQ_CNTL, 0); + if (r100_gui_wait_for_idle(rdev)) { + printk(KERN_WARNING "Failed to wait GUI idle while " + "programming pipes. Bad things might happen.\n"); + } +} + +int r100_cp_reset(struct radeon_device *rdev) +{ + uint32_t tmp; + bool reinit_cp; + int i; + + reinit_cp = rdev->cp.ready; + rdev->cp.ready = false; + WREG32(RADEON_CP_CSQ_MODE, 0); + WREG32(RADEON_CP_CSQ_CNTL, 0); + WREG32(RADEON_RBBM_SOFT_RESET, RADEON_SOFT_RESET_CP); + (void)RREG32(RADEON_RBBM_SOFT_RESET); + udelay(200); + WREG32(RADEON_RBBM_SOFT_RESET, 0); + /* Wait to prevent race in RBBM_STATUS */ + mdelay(1); + for (i = 0; i < rdev->usec_timeout; i++) { + tmp = RREG32(RADEON_RBBM_STATUS); + if (!(tmp & (1 << 16))) { + DRM_INFO("CP reset succeed (RBBM_STATUS=0x%08X)\n", + tmp); + if (reinit_cp) { + return r100_cp_init(rdev, rdev->cp.ring_size); + } + return 0; + } + DRM_UDELAY(1); + } + tmp = RREG32(RADEON_RBBM_STATUS); + DRM_ERROR("Failed to reset CP (RBBM_STATUS=0x%08X)!\n", tmp); + return -1; +} + + +/* + * CS functions + */ +int r100_cs_parse_packet0(struct radeon_cs_parser *p, + struct radeon_cs_packet *pkt, + const unsigned *auth, unsigned n, + radeon_packet0_check_t check) +{ + unsigned reg; + unsigned i, j, m; + unsigned idx; + int r; + + idx = pkt->idx + 1; + reg = pkt->reg; + /* Check that register fall into register range + * determined by the number of entry (n) in the + * safe register bitmap. + */ + if (pkt->one_reg_wr) { + if ((reg >> 7) > n) { + return -EINVAL; + } + } else { + if (((reg + (pkt->count << 2)) >> 7) > n) { + return -EINVAL; + } + } + for (i = 0; i <= pkt->count; i++, idx++) { + j = (reg >> 7); + m = 1 << ((reg >> 2) & 31); + if (auth[j] & m) { + r = check(p, pkt, idx, reg); + if (r) { + return r; + } + } + if (pkt->one_reg_wr) { + if (!(auth[j] & m)) { + break; + } + } else { + reg += 4; + } + } + return 0; +} + +void r100_cs_dump_packet(struct radeon_cs_parser *p, + struct radeon_cs_packet *pkt) +{ + struct radeon_cs_chunk *ib_chunk; + volatile uint32_t *ib; + unsigned i; + unsigned idx; + + ib = p->ib->ptr; + ib_chunk = &p->chunks[p->chunk_ib_idx]; + idx = pkt->idx; + for (i = 0; i <= (pkt->count + 1); i++, idx++) { + DRM_INFO("ib[%d]=0x%08X\n", idx, ib[idx]); + } +} + +/** + * r100_cs_packet_parse() - parse cp packet and point ib index to next packet + * @parser: parser structure holding parsing context. + * @pkt: where to store packet informations + * + * Assume that chunk_ib_index is properly set. Will return -EINVAL + * if packet is bigger than remaining ib size. or if packets is unknown. + **/ +int r100_cs_packet_parse(struct radeon_cs_parser *p, + struct radeon_cs_packet *pkt, + unsigned idx) +{ + struct radeon_cs_chunk *ib_chunk = &p->chunks[p->chunk_ib_idx]; + uint32_t header = ib_chunk->kdata[idx]; + + if (idx >= ib_chunk->length_dw) { + DRM_ERROR("Can not parse packet at %d after CS end %d !\n", + idx, ib_chunk->length_dw); + return -EINVAL; + } + pkt->idx = idx; + pkt->type = CP_PACKET_GET_TYPE(header); + pkt->count = CP_PACKET_GET_COUNT(header); + switch (pkt->type) { + case PACKET_TYPE0: + pkt->reg = CP_PACKET0_GET_REG(header); + pkt->one_reg_wr = CP_PACKET0_GET_ONE_REG_WR(header); + break; + case PACKET_TYPE3: + pkt->opcode = CP_PACKET3_GET_OPCODE(header); + break; + case PACKET_TYPE2: + pkt->count = -1; + break; + default: + DRM_ERROR("Unknown packet type %d at %d !\n", pkt->type, idx); + return -EINVAL; + } + if ((pkt->count + 1 + pkt->idx) >= ib_chunk->length_dw) { + DRM_ERROR("Packet (%d:%d:%d) end after CS buffer (%d) !\n", + pkt->idx, pkt->type, pkt->count, ib_chunk->length_dw); + return -EINVAL; + } + return 0; +} + +/** + * r100_cs_packet_next_reloc() - parse next packet which should be reloc packet3 + * @parser: parser structure holding parsing context. + * @data: pointer to relocation data + * @offset_start: starting offset + * @offset_mask: offset mask (to align start offset on) + * @reloc: reloc informations + * + * Check next packet is relocation packet3, do bo validation and compute + * GPU offset using the provided start. + **/ +int r100_cs_packet_next_reloc(struct radeon_cs_parser *p, + struct radeon_cs_reloc **cs_reloc) +{ + struct radeon_cs_chunk *ib_chunk; + struct radeon_cs_chunk *relocs_chunk; + struct radeon_cs_packet p3reloc; + unsigned idx; + int r; + + if (p->chunk_relocs_idx == -1) { + DRM_ERROR("No relocation chunk !\n"); + return -EINVAL; + } + *cs_reloc = NULL; + ib_chunk = &p->chunks[p->chunk_ib_idx]; + relocs_chunk = &p->chunks[p->chunk_relocs_idx]; + r = r100_cs_packet_parse(p, &p3reloc, p->idx); + if (r) { + return r; + } + p->idx += p3reloc.count + 2; + if (p3reloc.type != PACKET_TYPE3 || p3reloc.opcode != PACKET3_NOP) { + DRM_ERROR("No packet3 for relocation for packet at %d.\n", + p3reloc.idx); + r100_cs_dump_packet(p, &p3reloc); + return -EINVAL; + } + idx = ib_chunk->kdata[p3reloc.idx + 1]; + if (idx >= relocs_chunk->length_dw) { + DRM_ERROR("Relocs at %d after relocations chunk end %d !\n", + idx, relocs_chunk->length_dw); + r100_cs_dump_packet(p, &p3reloc); + return -EINVAL; + } + /* FIXME: we assume reloc size is 4 dwords */ + *cs_reloc = p->relocs_ptr[(idx / 4)]; + return 0; +} + +static int r100_packet0_check(struct radeon_cs_parser *p, + struct radeon_cs_packet *pkt) +{ + struct radeon_cs_chunk *ib_chunk; + struct radeon_cs_reloc *reloc; + volatile uint32_t *ib; + uint32_t tmp; + unsigned reg; + unsigned i; + unsigned idx; + bool onereg; + int r; + + ib = p->ib->ptr; + ib_chunk = &p->chunks[p->chunk_ib_idx]; + idx = pkt->idx + 1; + reg = pkt->reg; + onereg = false; + if (CP_PACKET0_GET_ONE_REG_WR(ib_chunk->kdata[pkt->idx])) { + onereg = true; + } + for (i = 0; i <= pkt->count; i++, idx++, reg += 4) { + switch (reg) { + /* FIXME: only allow PACKET3 blit? easier to check for out of + * range access */ + case RADEON_DST_PITCH_OFFSET: + case RADEON_SRC_PITCH_OFFSET: + r = r100_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("No reloc for ib[%d]=0x%04X\n", + idx, reg); + r100_cs_dump_packet(p, pkt); + return r; + } + tmp = ib_chunk->kdata[idx] & 0x003fffff; + tmp += (((u32)reloc->lobj.gpu_offset) >> 10); + ib[idx] = (ib_chunk->kdata[idx] & 0xffc00000) | tmp; + break; + case RADEON_RB3D_DEPTHOFFSET: + case RADEON_RB3D_COLOROFFSET: + case R300_RB3D_COLOROFFSET0: + case R300_ZB_DEPTHOFFSET: + case R200_PP_TXOFFSET_0: + case R200_PP_TXOFFSET_1: + case R200_PP_TXOFFSET_2: + case R200_PP_TXOFFSET_3: + case R200_PP_TXOFFSET_4: + case R200_PP_TXOFFSET_5: + case RADEON_PP_TXOFFSET_0: + case RADEON_PP_TXOFFSET_1: + case RADEON_PP_TXOFFSET_2: + case R300_TX_OFFSET_0: + case R300_TX_OFFSET_0+4: + case R300_TX_OFFSET_0+8: + case R300_TX_OFFSET_0+12: + case R300_TX_OFFSET_0+16: + case R300_TX_OFFSET_0+20: + case R300_TX_OFFSET_0+24: + case R300_TX_OFFSET_0+28: + case R300_TX_OFFSET_0+32: + case R300_TX_OFFSET_0+36: + case R300_TX_OFFSET_0+40: + case R300_TX_OFFSET_0+44: + case R300_TX_OFFSET_0+48: + case R300_TX_OFFSET_0+52: + case R300_TX_OFFSET_0+56: + case R300_TX_OFFSET_0+60: + r = r100_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("No reloc for ib[%d]=0x%04X\n", + idx, reg); + r100_cs_dump_packet(p, pkt); + return r; + } + ib[idx] = ib_chunk->kdata[idx] + ((u32)reloc->lobj.gpu_offset); + break; + default: + /* FIXME: we don't want to allow anyothers packet */ + break; + } + if (onereg) { + /* FIXME: forbid onereg write to register on relocate */ + break; + } + } + return 0; +} + +int r100_cs_track_check_pkt3_indx_buffer(struct radeon_cs_parser *p, + struct radeon_cs_packet *pkt, + struct radeon_object *robj) +{ + struct radeon_cs_chunk *ib_chunk; + unsigned idx; + + ib_chunk = &p->chunks[p->chunk_ib_idx]; + idx = pkt->idx + 1; + if ((ib_chunk->kdata[idx+2] + 1) > radeon_object_size(robj)) { + DRM_ERROR("[drm] Buffer too small for PACKET3 INDX_BUFFER " + "(need %u have %lu) !\n", + ib_chunk->kdata[idx+2] + 1, + radeon_object_size(robj)); + return -EINVAL; + } + return 0; +} + +static int r100_packet3_check(struct radeon_cs_parser *p, + struct radeon_cs_packet *pkt) +{ + struct radeon_cs_chunk *ib_chunk; + struct radeon_cs_reloc *reloc; + unsigned idx; + unsigned i, c; + volatile uint32_t *ib; + int r; + + ib = p->ib->ptr; + ib_chunk = &p->chunks[p->chunk_ib_idx]; + idx = pkt->idx + 1; + switch (pkt->opcode) { + case PACKET3_3D_LOAD_VBPNTR: + c = ib_chunk->kdata[idx++]; + for (i = 0; i < (c - 1); i += 2, idx += 3) { + r = r100_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("No reloc for packet3 %d\n", + pkt->opcode); + r100_cs_dump_packet(p, pkt); + return r; + } + ib[idx+1] = ib_chunk->kdata[idx+1] + ((u32)reloc->lobj.gpu_offset); + r = r100_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("No reloc for packet3 %d\n", + pkt->opcode); + r100_cs_dump_packet(p, pkt); + return r; + } + ib[idx+2] = ib_chunk->kdata[idx+2] + ((u32)reloc->lobj.gpu_offset); + } + if (c & 1) { + r = r100_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("No reloc for packet3 %d\n", + pkt->opcode); + r100_cs_dump_packet(p, pkt); + return r; + } + ib[idx+1] = ib_chunk->kdata[idx+1] + ((u32)reloc->lobj.gpu_offset); + } + break; + case PACKET3_INDX_BUFFER: + r = r100_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("No reloc for packet3 %d\n", pkt->opcode); + r100_cs_dump_packet(p, pkt); + return r; + } + ib[idx+1] = ib_chunk->kdata[idx+1] + ((u32)reloc->lobj.gpu_offset); + r = r100_cs_track_check_pkt3_indx_buffer(p, pkt, reloc->robj); + if (r) { + return r; + } + break; + case 0x23: + /* FIXME: cleanup */ + /* 3D_RNDR_GEN_INDX_PRIM on r100/r200 */ + r = r100_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("No reloc for packet3 %d\n", pkt->opcode); + r100_cs_dump_packet(p, pkt); + return r; + } + ib[idx] = ib_chunk->kdata[idx] + ((u32)reloc->lobj.gpu_offset); + break; + case PACKET3_3D_DRAW_IMMD: + /* triggers drawing using in-packet vertex data */ + case PACKET3_3D_DRAW_IMMD_2: + /* triggers drawing using in-packet vertex data */ + case PACKET3_3D_DRAW_VBUF_2: + /* triggers drawing of vertex buffers setup elsewhere */ + case PACKET3_3D_DRAW_INDX_2: + /* triggers drawing using indices to vertex buffer */ + case PACKET3_3D_DRAW_VBUF: + /* triggers drawing of vertex buffers setup elsewhere */ + case PACKET3_3D_DRAW_INDX: + /* triggers drawing using indices to vertex buffer */ + case PACKET3_NOP: + break; + default: + DRM_ERROR("Packet3 opcode %x not supported\n", pkt->opcode); + return -EINVAL; + } + return 0; +} + +int r100_cs_parse(struct radeon_cs_parser *p) +{ + struct radeon_cs_packet pkt; + int r; + + do { + r = r100_cs_packet_parse(p, &pkt, p->idx); + if (r) { + return r; + } + p->idx += pkt.count + 2; + switch (pkt.type) { + case PACKET_TYPE0: + r = r100_packet0_check(p, &pkt); + break; + case PACKET_TYPE2: + break; + case PACKET_TYPE3: + r = r100_packet3_check(p, &pkt); + break; + default: + DRM_ERROR("Unknown packet type %d !\n", + pkt.type); + return -EINVAL; + } + if (r) { + return r; + } + } while (p->idx < p->chunks[p->chunk_ib_idx].length_dw); + return 0; +} + + +/* + * Global GPU functions + */ +void r100_errata(struct radeon_device *rdev) +{ + rdev->pll_errata = 0; + + if (rdev->family == CHIP_RV200 || rdev->family == CHIP_RS200) { + rdev->pll_errata |= CHIP_ERRATA_PLL_DUMMYREADS; + } + + if (rdev->family == CHIP_RV100 || + rdev->family == CHIP_RS100 || + rdev->family == CHIP_RS200) { + rdev->pll_errata |= CHIP_ERRATA_PLL_DELAY; + } +} + +/* Wait for vertical sync on primary CRTC */ +void r100_gpu_wait_for_vsync(struct radeon_device *rdev) +{ + uint32_t crtc_gen_cntl, tmp; + int i; + + crtc_gen_cntl = RREG32(RADEON_CRTC_GEN_CNTL); + if ((crtc_gen_cntl & RADEON_CRTC_DISP_REQ_EN_B) || + !(crtc_gen_cntl & RADEON_CRTC_EN)) { + return; + } + /* Clear the CRTC_VBLANK_SAVE bit */ + WREG32(RADEON_CRTC_STATUS, RADEON_CRTC_VBLANK_SAVE_CLEAR); + for (i = 0; i < rdev->usec_timeout; i++) { + tmp = RREG32(RADEON_CRTC_STATUS); + if (tmp & RADEON_CRTC_VBLANK_SAVE) { + return; + } + DRM_UDELAY(1); + } +} + +/* Wait for vertical sync on secondary CRTC */ +void r100_gpu_wait_for_vsync2(struct radeon_device *rdev) +{ + uint32_t crtc2_gen_cntl, tmp; + int i; + + crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL); + if ((crtc2_gen_cntl & RADEON_CRTC2_DISP_REQ_EN_B) || + !(crtc2_gen_cntl & RADEON_CRTC2_EN)) + return; + + /* Clear the CRTC_VBLANK_SAVE bit */ + WREG32(RADEON_CRTC2_STATUS, RADEON_CRTC2_VBLANK_SAVE_CLEAR); + for (i = 0; i < rdev->usec_timeout; i++) { + tmp = RREG32(RADEON_CRTC2_STATUS); + if (tmp & RADEON_CRTC2_VBLANK_SAVE) { + return; + } + DRM_UDELAY(1); + } +} + +int r100_rbbm_fifo_wait_for_entry(struct radeon_device *rdev, unsigned n) +{ + unsigned i; + uint32_t tmp; + + for (i = 0; i < rdev->usec_timeout; i++) { + tmp = RREG32(RADEON_RBBM_STATUS) & RADEON_RBBM_FIFOCNT_MASK; + if (tmp >= n) { + return 0; + } + DRM_UDELAY(1); + } + return -1; +} + +int r100_gui_wait_for_idle(struct radeon_device *rdev) +{ + unsigned i; + uint32_t tmp; + + if (r100_rbbm_fifo_wait_for_entry(rdev, 64)) { + printk(KERN_WARNING "radeon: wait for empty RBBM fifo failed !" + " Bad things might happen.\n"); + } + for (i = 0; i < rdev->usec_timeout; i++) { + tmp = RREG32(RADEON_RBBM_STATUS); + if (!(tmp & (1 << 31))) { + return 0; + } + DRM_UDELAY(1); + } + return -1; +} + +int r100_mc_wait_for_idle(struct radeon_device *rdev) +{ + unsigned i; + uint32_t tmp; + + for (i = 0; i < rdev->usec_timeout; i++) { + /* read MC_STATUS */ + tmp = RREG32(0x0150); + if (tmp & (1 << 2)) { + return 0; + } + DRM_UDELAY(1); + } + return -1; +} + +void r100_gpu_init(struct radeon_device *rdev) +{ + /* TODO: anythings to do here ? pipes ? */ + r100_hdp_reset(rdev); +} + +void r100_hdp_reset(struct radeon_device *rdev) +{ + uint32_t tmp; + + tmp = RREG32(RADEON_HOST_PATH_CNTL) & RADEON_HDP_APER_CNTL; + tmp |= (7 << 28); + WREG32(RADEON_HOST_PATH_CNTL, tmp | RADEON_HDP_SOFT_RESET | RADEON_HDP_READ_BUFFER_INVALIDATE); + (void)RREG32(RADEON_HOST_PATH_CNTL); + udelay(200); + WREG32(RADEON_RBBM_SOFT_RESET, 0); + WREG32(RADEON_HOST_PATH_CNTL, tmp); + (void)RREG32(RADEON_HOST_PATH_CNTL); +} + +int r100_rb2d_reset(struct radeon_device *rdev) +{ + uint32_t tmp; + int i; + + WREG32(RADEON_RBBM_SOFT_RESET, RADEON_SOFT_RESET_E2); + (void)RREG32(RADEON_RBBM_SOFT_RESET); + udelay(200); + WREG32(RADEON_RBBM_SOFT_RESET, 0); + /* Wait to prevent race in RBBM_STATUS */ + mdelay(1); + for (i = 0; i < rdev->usec_timeout; i++) { + tmp = RREG32(RADEON_RBBM_STATUS); + if (!(tmp & (1 << 26))) { + DRM_INFO("RB2D reset succeed (RBBM_STATUS=0x%08X)\n", + tmp); + return 0; + } + DRM_UDELAY(1); + } + tmp = RREG32(RADEON_RBBM_STATUS); + DRM_ERROR("Failed to reset RB2D (RBBM_STATUS=0x%08X)!\n", tmp); + return -1; +} + +int r100_gpu_reset(struct radeon_device *rdev) +{ + uint32_t status; + + /* reset order likely matter */ + status = RREG32(RADEON_RBBM_STATUS); + /* reset HDP */ + r100_hdp_reset(rdev); + /* reset rb2d */ + if (status & ((1 << 17) | (1 << 18) | (1 << 27))) { + r100_rb2d_reset(rdev); + } + /* TODO: reset 3D engine */ + /* reset CP */ + status = RREG32(RADEON_RBBM_STATUS); + if (status & (1 << 16)) { + r100_cp_reset(rdev); + } + /* Check if GPU is idle */ + status = RREG32(RADEON_RBBM_STATUS); + if (status & (1 << 31)) { + DRM_ERROR("Failed to reset GPU (RBBM_STATUS=0x%08X)\n", status); + return -1; + } + DRM_INFO("GPU reset succeed (RBBM_STATUS=0x%08X)\n", status); + return 0; +} + + +/* + * VRAM info + */ +static void r100_vram_get_type(struct radeon_device *rdev) +{ + uint32_t tmp; + + rdev->mc.vram_is_ddr = false; + if (rdev->flags & RADEON_IS_IGP) + rdev->mc.vram_is_ddr = true; + else if (RREG32(RADEON_MEM_SDRAM_MODE_REG) & RADEON_MEM_CFG_TYPE_DDR) + rdev->mc.vram_is_ddr = true; + if ((rdev->family == CHIP_RV100) || + (rdev->family == CHIP_RS100) || + (rdev->family == CHIP_RS200)) { + tmp = RREG32(RADEON_MEM_CNTL); + if (tmp & RV100_HALF_MODE) { + rdev->mc.vram_width = 32; + } else { + rdev->mc.vram_width = 64; + } + if (rdev->flags & RADEON_SINGLE_CRTC) { + rdev->mc.vram_width /= 4; + rdev->mc.vram_is_ddr = true; + } + } else if (rdev->family <= CHIP_RV280) { + tmp = RREG32(RADEON_MEM_CNTL); + if (tmp & RADEON_MEM_NUM_CHANNELS_MASK) { + rdev->mc.vram_width = 128; + } else { + rdev->mc.vram_width = 64; + } + } else { + /* newer IGPs */ + rdev->mc.vram_width = 128; + } +} + +void r100_vram_info(struct radeon_device *rdev) +{ + r100_vram_get_type(rdev); + + if (rdev->flags & RADEON_IS_IGP) { + uint32_t tom; + /* read NB_TOM to get the amount of ram stolen for the GPU */ + tom = RREG32(RADEON_NB_TOM); + rdev->mc.vram_size = (((tom >> 16) - (tom & 0xffff) + 1) << 16); + WREG32(RADEON_CONFIG_MEMSIZE, rdev->mc.vram_size); + } else { + rdev->mc.vram_size = RREG32(RADEON_CONFIG_MEMSIZE); + /* Some production boards of m6 will report 0 + * if it's 8 MB + */ + if (rdev->mc.vram_size == 0) { + rdev->mc.vram_size = 8192 * 1024; + WREG32(RADEON_CONFIG_MEMSIZE, rdev->mc.vram_size); + } + } + + rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0); + rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0); +} + + +/* + * Indirect registers accessor + */ +void r100_pll_errata_after_index(struct radeon_device *rdev) +{ + if (!(rdev->pll_errata & CHIP_ERRATA_PLL_DUMMYREADS)) { + return; + } + (void)RREG32(RADEON_CLOCK_CNTL_DATA); + (void)RREG32(RADEON_CRTC_GEN_CNTL); +} + +static void r100_pll_errata_after_data(struct radeon_device *rdev) +{ + /* This workarounds is necessary on RV100, RS100 and RS200 chips + * or the chip could hang on a subsequent access + */ + if (rdev->pll_errata & CHIP_ERRATA_PLL_DELAY) { + udelay(5000); + } + + /* This function is required to workaround a hardware bug in some (all?) + * revisions of the R300. This workaround should be called after every + * CLOCK_CNTL_INDEX register access. If not, register reads afterward + * may not be correct. + */ + if (rdev->pll_errata & CHIP_ERRATA_R300_CG) { + uint32_t save, tmp; + + save = RREG32(RADEON_CLOCK_CNTL_INDEX); + tmp = save & ~(0x3f | RADEON_PLL_WR_EN); + WREG32(RADEON_CLOCK_CNTL_INDEX, tmp); + tmp = RREG32(RADEON_CLOCK_CNTL_DATA); + WREG32(RADEON_CLOCK_CNTL_INDEX, save); + } +} + +uint32_t r100_pll_rreg(struct radeon_device *rdev, uint32_t reg) +{ + uint32_t data; + + WREG8(RADEON_CLOCK_CNTL_INDEX, reg & 0x3f); + r100_pll_errata_after_index(rdev); + data = RREG32(RADEON_CLOCK_CNTL_DATA); + r100_pll_errata_after_data(rdev); + return data; +} + +void r100_pll_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v) +{ + WREG8(RADEON_CLOCK_CNTL_INDEX, ((reg & 0x3f) | RADEON_PLL_WR_EN)); + r100_pll_errata_after_index(rdev); + WREG32(RADEON_CLOCK_CNTL_DATA, v); + r100_pll_errata_after_data(rdev); +} + +uint32_t r100_mm_rreg(struct radeon_device *rdev, uint32_t reg) +{ + if (reg < 0x10000) + return readl(((void __iomem *)rdev->rmmio) + reg); + else { + writel(reg, ((void __iomem *)rdev->rmmio) + RADEON_MM_INDEX); + return readl(((void __iomem *)rdev->rmmio) + RADEON_MM_DATA); + } +} + +void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v) +{ + if (reg < 0x10000) + writel(v, ((void __iomem *)rdev->rmmio) + reg); + else { + writel(reg, ((void __iomem *)rdev->rmmio) + RADEON_MM_INDEX); + writel(v, ((void __iomem *)rdev->rmmio) + RADEON_MM_DATA); + } +} + +int r100_init(struct radeon_device *rdev) +{ + return 0; +} + +/* + * Debugfs info + */ +#if defined(CONFIG_DEBUG_FS) +static int r100_debugfs_rbbm_info(struct seq_file *m, void *data) +{ + struct drm_info_node *node = (struct drm_info_node *) m->private; + struct drm_device *dev = node->minor->dev; + struct radeon_device *rdev = dev->dev_private; + uint32_t reg, value; + unsigned i; + + seq_printf(m, "RBBM_STATUS 0x%08x\n", RREG32(RADEON_RBBM_STATUS)); + seq_printf(m, "RBBM_CMDFIFO_STAT 0x%08x\n", RREG32(0xE7C)); + seq_printf(m, "CP_STAT 0x%08x\n", RREG32(RADEON_CP_STAT)); + for (i = 0; i < 64; i++) { + WREG32(RADEON_RBBM_CMDFIFO_ADDR, i | 0x100); + reg = (RREG32(RADEON_RBBM_CMDFIFO_DATA) - 1) >> 2; + WREG32(RADEON_RBBM_CMDFIFO_ADDR, i); + value = RREG32(RADEON_RBBM_CMDFIFO_DATA); + seq_printf(m, "[0x%03X] 0x%04X=0x%08X\n", i, reg, value); + } + return 0; +} + +static int r100_debugfs_cp_ring_info(struct seq_file *m, void *data) +{ + struct drm_info_node *node = (struct drm_info_node *) m->private; + struct drm_device *dev = node->minor->dev; + struct radeon_device *rdev = dev->dev_private; + uint32_t rdp, wdp; + unsigned count, i, j; + + radeon_ring_free_size(rdev); + rdp = RREG32(RADEON_CP_RB_RPTR); + wdp = RREG32(RADEON_CP_RB_WPTR); + count = (rdp + rdev->cp.ring_size - wdp) & rdev->cp.ptr_mask; + seq_printf(m, "CP_STAT 0x%08x\n", RREG32(RADEON_CP_STAT)); + seq_printf(m, "CP_RB_WPTR 0x%08x\n", wdp); + seq_printf(m, "CP_RB_RPTR 0x%08x\n", rdp); + seq_printf(m, "%u free dwords in ring\n", rdev->cp.ring_free_dw); + seq_printf(m, "%u dwords in ring\n", count); + for (j = 0; j <= count; j++) { + i = (rdp + j) & rdev->cp.ptr_mask; + seq_printf(m, "r[%04d]=0x%08x\n", i, rdev->cp.ring[i]); + } + return 0; +} + + +static int r100_debugfs_cp_csq_fifo(struct seq_file *m, void *data) +{ + struct drm_info_node *node = (struct drm_info_node *) m->private; + struct drm_device *dev = node->minor->dev; + struct radeon_device *rdev = dev->dev_private; + uint32_t csq_stat, csq2_stat, tmp; + unsigned r_rptr, r_wptr, ib1_rptr, ib1_wptr, ib2_rptr, ib2_wptr; + unsigned i; + + seq_printf(m, "CP_STAT 0x%08x\n", RREG32(RADEON_CP_STAT)); + seq_printf(m, "CP_CSQ_MODE 0x%08x\n", RREG32(RADEON_CP_CSQ_MODE)); + csq_stat = RREG32(RADEON_CP_CSQ_STAT); + csq2_stat = RREG32(RADEON_CP_CSQ2_STAT); + r_rptr = (csq_stat >> 0) & 0x3ff; + r_wptr = (csq_stat >> 10) & 0x3ff; + ib1_rptr = (csq_stat >> 20) & 0x3ff; + ib1_wptr = (csq2_stat >> 0) & 0x3ff; + ib2_rptr = (csq2_stat >> 10) & 0x3ff; + ib2_wptr = (csq2_stat >> 20) & 0x3ff; + seq_printf(m, "CP_CSQ_STAT 0x%08x\n", csq_stat); + seq_printf(m, "CP_CSQ2_STAT 0x%08x\n", csq2_stat); + seq_printf(m, "Ring rptr %u\n", r_rptr); + seq_printf(m, "Ring wptr %u\n", r_wptr); + seq_printf(m, "Indirect1 rptr %u\n", ib1_rptr); + seq_printf(m, "Indirect1 wptr %u\n", ib1_wptr); + seq_printf(m, "Indirect2 rptr %u\n", ib2_rptr); + seq_printf(m, "Indirect2 wptr %u\n", ib2_wptr); + /* FIXME: 0, 128, 640 depends on fifo setup see cp_init_kms + * 128 = indirect1_start * 8 & 640 = indirect2_start * 8 */ + seq_printf(m, "Ring fifo:\n"); + for (i = 0; i < 256; i++) { + WREG32(RADEON_CP_CSQ_ADDR, i << 2); + tmp = RREG32(RADEON_CP_CSQ_DATA); + seq_printf(m, "rfifo[%04d]=0x%08X\n", i, tmp); + } + seq_printf(m, "Indirect1 fifo:\n"); + for (i = 256; i <= 512; i++) { + WREG32(RADEON_CP_CSQ_ADDR, i << 2); + tmp = RREG32(RADEON_CP_CSQ_DATA); + seq_printf(m, "ib1fifo[%04d]=0x%08X\n", i, tmp); + } + seq_printf(m, "Indirect2 fifo:\n"); + for (i = 640; i < ib1_wptr; i++) { + WREG32(RADEON_CP_CSQ_ADDR, i << 2); + tmp = RREG32(RADEON_CP_CSQ_DATA); + seq_printf(m, "ib2fifo[%04d]=0x%08X\n", i, tmp); + } + return 0; +} + +static int r100_debugfs_mc_info(struct seq_file *m, void *data) +{ + struct drm_info_node *node = (struct drm_info_node *) m->private; + struct drm_device *dev = node->minor->dev; + struct radeon_device *rdev = dev->dev_private; + uint32_t tmp; + + tmp = RREG32(RADEON_CONFIG_MEMSIZE); + seq_printf(m, "CONFIG_MEMSIZE 0x%08x\n", tmp); + tmp = RREG32(RADEON_MC_FB_LOCATION); + seq_printf(m, "MC_FB_LOCATION 0x%08x\n", tmp); + tmp = RREG32(RADEON_BUS_CNTL); + seq_printf(m, "BUS_CNTL 0x%08x\n", tmp); + tmp = RREG32(RADEON_MC_AGP_LOCATION); + seq_printf(m, "MC_AGP_LOCATION 0x%08x\n", tmp); + tmp = RREG32(RADEON_AGP_BASE); + seq_printf(m, "AGP_BASE 0x%08x\n", tmp); + tmp = RREG32(RADEON_HOST_PATH_CNTL); + seq_printf(m, "HOST_PATH_CNTL 0x%08x\n", tmp); + tmp = RREG32(0x01D0); + seq_printf(m, "AIC_CTRL 0x%08x\n", tmp); + tmp = RREG32(RADEON_AIC_LO_ADDR); + seq_printf(m, "AIC_LO_ADDR 0x%08x\n", tmp); + tmp = RREG32(RADEON_AIC_HI_ADDR); + seq_printf(m, "AIC_HI_ADDR 0x%08x\n", tmp); + tmp = RREG32(0x01E4); + seq_printf(m, "AIC_TLB_ADDR 0x%08x\n", tmp); + return 0; +} + +static struct drm_info_list r100_debugfs_rbbm_list[] = { + {"r100_rbbm_info", r100_debugfs_rbbm_info, 0, NULL}, +}; + +static struct drm_info_list r100_debugfs_cp_list[] = { + {"r100_cp_ring_info", r100_debugfs_cp_ring_info, 0, NULL}, + {"r100_cp_csq_fifo", r100_debugfs_cp_csq_fifo, 0, NULL}, +}; + +static struct drm_info_list r100_debugfs_mc_info_list[] = { + {"r100_mc_info", r100_debugfs_mc_info, 0, NULL}, +}; +#endif + +int r100_debugfs_rbbm_init(struct radeon_device *rdev) +{ +#if defined(CONFIG_DEBUG_FS) + return radeon_debugfs_add_files(rdev, r100_debugfs_rbbm_list, 1); +#else + return 0; +#endif +} + +int r100_debugfs_cp_init(struct radeon_device *rdev) +{ +#if defined(CONFIG_DEBUG_FS) + return radeon_debugfs_add_files(rdev, r100_debugfs_cp_list, 2); +#else + return 0; +#endif +} + +int r100_debugfs_mc_info_init(struct radeon_device *rdev) +{ +#if defined(CONFIG_DEBUG_FS) + return radeon_debugfs_add_files(rdev, r100_debugfs_mc_info_list, 1); +#else + return 0; +#endif +} diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c new file mode 100644 index 000000000000..e2ed5bc08170 --- /dev/null +++ b/drivers/gpu/drm/radeon/r300.c @@ -0,0 +1,1532 @@ +/* + * Copyright 2008 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * Copyright 2009 Jerome Glisse. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Dave Airlie + * Alex Deucher + * Jerome Glisse + */ +#include +#include "drmP.h" +#include "drm.h" +#include "radeon_reg.h" +#include "radeon.h" + +/* r300,r350,rv350,rv370,rv380 depends on : */ +void r100_hdp_reset(struct radeon_device *rdev); +int r100_cp_reset(struct radeon_device *rdev); +int r100_rb2d_reset(struct radeon_device *rdev); +int r100_cp_init(struct radeon_device *rdev, unsigned ring_size); +int r100_pci_gart_enable(struct radeon_device *rdev); +void r100_pci_gart_disable(struct radeon_device *rdev); +void r100_mc_setup(struct radeon_device *rdev); +void r100_mc_disable_clients(struct radeon_device *rdev); +int r100_gui_wait_for_idle(struct radeon_device *rdev); +int r100_cs_packet_parse(struct radeon_cs_parser *p, + struct radeon_cs_packet *pkt, + unsigned idx); +int r100_cs_packet_next_reloc(struct radeon_cs_parser *p, + struct radeon_cs_reloc **cs_reloc); +int r100_cs_parse_packet0(struct radeon_cs_parser *p, + struct radeon_cs_packet *pkt, + const unsigned *auth, unsigned n, + radeon_packet0_check_t check); +void r100_cs_dump_packet(struct radeon_cs_parser *p, + struct radeon_cs_packet *pkt); +int r100_cs_track_check_pkt3_indx_buffer(struct radeon_cs_parser *p, + struct radeon_cs_packet *pkt, + struct radeon_object *robj); + +/* This files gather functions specifics to: + * r300,r350,rv350,rv370,rv380 + * + * Some of these functions might be used by newer ASICs. + */ +void r300_gpu_init(struct radeon_device *rdev); +int r300_mc_wait_for_idle(struct radeon_device *rdev); +int rv370_debugfs_pcie_gart_info_init(struct radeon_device *rdev); + + +/* + * rv370,rv380 PCIE GART + */ +void rv370_pcie_gart_tlb_flush(struct radeon_device *rdev) +{ + uint32_t tmp; + int i; + + /* Workaround HW bug do flush 2 times */ + for (i = 0; i < 2; i++) { + tmp = RREG32_PCIE(RADEON_PCIE_TX_GART_CNTL); + WREG32_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp | RADEON_PCIE_TX_GART_INVALIDATE_TLB); + (void)RREG32_PCIE(RADEON_PCIE_TX_GART_CNTL); + WREG32_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp); + mb(); + } +} + +int rv370_pcie_gart_enable(struct radeon_device *rdev) +{ + uint32_t table_addr; + uint32_t tmp; + int r; + + /* Initialize common gart structure */ + r = radeon_gart_init(rdev); + if (r) { + return r; + } + r = rv370_debugfs_pcie_gart_info_init(rdev); + if (r) { + DRM_ERROR("Failed to register debugfs file for PCIE gart !\n"); + } + rdev->gart.table_size = rdev->gart.num_gpu_pages * 4; + r = radeon_gart_table_vram_alloc(rdev); + if (r) { + return r; + } + /* discard memory request outside of configured range */ + tmp = RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_DISCARD; + WREG32_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp); + WREG32_PCIE(RADEON_PCIE_TX_GART_START_LO, rdev->mc.gtt_location); + tmp = rdev->mc.gtt_location + rdev->mc.gtt_size - 4096; + WREG32_PCIE(RADEON_PCIE_TX_GART_END_LO, tmp); + WREG32_PCIE(RADEON_PCIE_TX_GART_START_HI, 0); + WREG32_PCIE(RADEON_PCIE_TX_GART_END_HI, 0); + table_addr = rdev->gart.table_addr; + WREG32_PCIE(RADEON_PCIE_TX_GART_BASE, table_addr); + /* FIXME: setup default page */ + WREG32_PCIE(RADEON_PCIE_TX_DISCARD_RD_ADDR_LO, rdev->mc.vram_location); + WREG32_PCIE(RADEON_PCIE_TX_DISCARD_RD_ADDR_HI, 0); + /* Clear error */ + WREG32_PCIE(0x18, 0); + tmp = RREG32_PCIE(RADEON_PCIE_TX_GART_CNTL); + tmp |= RADEON_PCIE_TX_GART_EN; + tmp |= RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_DISCARD; + WREG32_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp); + rv370_pcie_gart_tlb_flush(rdev); + DRM_INFO("PCIE GART of %uM enabled (table at 0x%08X).\n", + rdev->mc.gtt_size >> 20, table_addr); + rdev->gart.ready = true; + return 0; +} + +void rv370_pcie_gart_disable(struct radeon_device *rdev) +{ + uint32_t tmp; + + tmp = RREG32_PCIE(RADEON_PCIE_TX_GART_CNTL); + tmp |= RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_DISCARD; + WREG32_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp & ~RADEON_PCIE_TX_GART_EN); + if (rdev->gart.table.vram.robj) { + radeon_object_kunmap(rdev->gart.table.vram.robj); + radeon_object_unpin(rdev->gart.table.vram.robj); + } +} + +int rv370_pcie_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr) +{ + void __iomem *ptr = (void *)rdev->gart.table.vram.ptr; + + if (i < 0 || i > rdev->gart.num_gpu_pages) { + return -EINVAL; + } + addr = (((u32)addr) >> 8) | ((upper_32_bits(addr) & 0xff) << 4) | 0xC; + writel(cpu_to_le32(addr), ((void __iomem *)ptr) + (i * 4)); + return 0; +} + +int r300_gart_enable(struct radeon_device *rdev) +{ +#if __OS_HAS_AGP + if (rdev->flags & RADEON_IS_AGP) { + if (rdev->family > CHIP_RV350) { + rv370_pcie_gart_disable(rdev); + } else { + r100_pci_gart_disable(rdev); + } + return 0; + } +#endif + if (rdev->flags & RADEON_IS_PCIE) { + rdev->asic->gart_disable = &rv370_pcie_gart_disable; + rdev->asic->gart_tlb_flush = &rv370_pcie_gart_tlb_flush; + rdev->asic->gart_set_page = &rv370_pcie_gart_set_page; + return rv370_pcie_gart_enable(rdev); + } + return r100_pci_gart_enable(rdev); +} + + +/* + * MC + */ +int r300_mc_init(struct radeon_device *rdev) +{ + int r; + + if (r100_debugfs_rbbm_init(rdev)) { + DRM_ERROR("Failed to register debugfs file for RBBM !\n"); + } + + r300_gpu_init(rdev); + r100_pci_gart_disable(rdev); + if (rdev->flags & RADEON_IS_PCIE) { + rv370_pcie_gart_disable(rdev); + } + + /* Setup GPU memory space */ + rdev->mc.vram_location = 0xFFFFFFFFUL; + rdev->mc.gtt_location = 0xFFFFFFFFUL; + if (rdev->flags & RADEON_IS_AGP) { + r = radeon_agp_init(rdev); + if (r) { + printk(KERN_WARNING "[drm] Disabling AGP\n"); + rdev->flags &= ~RADEON_IS_AGP; + rdev->mc.gtt_size = radeon_gart_size * 1024 * 1024; + } else { + rdev->mc.gtt_location = rdev->mc.agp_base; + } + } + r = radeon_mc_setup(rdev); + if (r) { + return r; + } + + /* Program GPU memory space */ + r100_mc_disable_clients(rdev); + if (r300_mc_wait_for_idle(rdev)) { + printk(KERN_WARNING "Failed to wait MC idle while " + "programming pipes. Bad things might happen.\n"); + } + r100_mc_setup(rdev); + return 0; +} + +void r300_mc_fini(struct radeon_device *rdev) +{ + if (rdev->flags & RADEON_IS_PCIE) { + rv370_pcie_gart_disable(rdev); + radeon_gart_table_vram_free(rdev); + } else { + r100_pci_gart_disable(rdev); + radeon_gart_table_ram_free(rdev); + } + radeon_gart_fini(rdev); +} + + +/* + * Fence emission + */ +void r300_fence_ring_emit(struct radeon_device *rdev, + struct radeon_fence *fence) +{ + /* Who ever call radeon_fence_emit should call ring_lock and ask + * for enough space (today caller are ib schedule and buffer move) */ + /* Write SC register so SC & US assert idle */ + radeon_ring_write(rdev, PACKET0(0x43E0, 0)); + radeon_ring_write(rdev, 0); + radeon_ring_write(rdev, PACKET0(0x43E4, 0)); + radeon_ring_write(rdev, 0); + /* Flush 3D cache */ + radeon_ring_write(rdev, PACKET0(0x4E4C, 0)); + radeon_ring_write(rdev, (2 << 0)); + radeon_ring_write(rdev, PACKET0(0x4F18, 0)); + radeon_ring_write(rdev, (1 << 0)); + /* Wait until IDLE & CLEAN */ + radeon_ring_write(rdev, PACKET0(0x1720, 0)); + radeon_ring_write(rdev, (1 << 17) | (1 << 16) | (1 << 9)); + /* Emit fence sequence & fire IRQ */ + radeon_ring_write(rdev, PACKET0(rdev->fence_drv.scratch_reg, 0)); + radeon_ring_write(rdev, fence->seq); + radeon_ring_write(rdev, PACKET0(RADEON_GEN_INT_STATUS, 0)); + radeon_ring_write(rdev, RADEON_SW_INT_FIRE); +} + + +/* + * Global GPU functions + */ +int r300_copy_dma(struct radeon_device *rdev, + uint64_t src_offset, + uint64_t dst_offset, + unsigned num_pages, + struct radeon_fence *fence) +{ + uint32_t size; + uint32_t cur_size; + int i, num_loops; + int r = 0; + + /* radeon pitch is /64 */ + size = num_pages << PAGE_SHIFT; + num_loops = DIV_ROUND_UP(size, 0x1FFFFF); + r = radeon_ring_lock(rdev, num_loops * 4 + 64); + if (r) { + DRM_ERROR("radeon: moving bo (%d).\n", r); + return r; + } + /* Must wait for 2D idle & clean before DMA or hangs might happen */ + radeon_ring_write(rdev, PACKET0(RADEON_WAIT_UNTIL, 0 )); + radeon_ring_write(rdev, (1 << 16)); + for (i = 0; i < num_loops; i++) { + cur_size = size; + if (cur_size > 0x1FFFFF) { + cur_size = 0x1FFFFF; + } + size -= cur_size; + radeon_ring_write(rdev, PACKET0(0x720, 2)); + radeon_ring_write(rdev, src_offset); + radeon_ring_write(rdev, dst_offset); + radeon_ring_write(rdev, cur_size | (1 << 31) | (1 << 30)); + src_offset += cur_size; + dst_offset += cur_size; + } + radeon_ring_write(rdev, PACKET0(RADEON_WAIT_UNTIL, 0)); + radeon_ring_write(rdev, RADEON_WAIT_DMA_GUI_IDLE); + if (fence) { + r = radeon_fence_emit(rdev, fence); + } + radeon_ring_unlock_commit(rdev); + return r; +} + +void r300_ring_start(struct radeon_device *rdev) +{ + unsigned gb_tile_config; + int r; + + /* Sub pixel 1/12 so we can have 4K rendering according to doc */ + gb_tile_config = (R300_ENABLE_TILING | R300_TILE_SIZE_16); + switch(rdev->num_gb_pipes) { + case 2: + gb_tile_config |= R300_PIPE_COUNT_R300; + break; + case 3: + gb_tile_config |= R300_PIPE_COUNT_R420_3P; + break; + case 4: + gb_tile_config |= R300_PIPE_COUNT_R420; + break; + case 1: + default: + gb_tile_config |= R300_PIPE_COUNT_RV350; + break; + } + + r = radeon_ring_lock(rdev, 64); + if (r) { + return; + } + radeon_ring_write(rdev, PACKET0(RADEON_ISYNC_CNTL, 0)); + radeon_ring_write(rdev, + RADEON_ISYNC_ANY2D_IDLE3D | + RADEON_ISYNC_ANY3D_IDLE2D | + RADEON_ISYNC_WAIT_IDLEGUI | + RADEON_ISYNC_CPSCRATCH_IDLEGUI); + radeon_ring_write(rdev, PACKET0(R300_GB_TILE_CONFIG, 0)); + radeon_ring_write(rdev, gb_tile_config); + radeon_ring_write(rdev, PACKET0(RADEON_WAIT_UNTIL, 0)); + radeon_ring_write(rdev, + RADEON_WAIT_2D_IDLECLEAN | + RADEON_WAIT_3D_IDLECLEAN); + radeon_ring_write(rdev, PACKET0(0x170C, 0)); + radeon_ring_write(rdev, 1 << 31); + radeon_ring_write(rdev, PACKET0(R300_GB_SELECT, 0)); + radeon_ring_write(rdev, 0); + radeon_ring_write(rdev, PACKET0(R300_GB_ENABLE, 0)); + radeon_ring_write(rdev, 0); + radeon_ring_write(rdev, PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0)); + radeon_ring_write(rdev, R300_RB3D_DC_FLUSH | R300_RB3D_DC_FREE); + radeon_ring_write(rdev, PACKET0(R300_RB3D_ZCACHE_CTLSTAT, 0)); + radeon_ring_write(rdev, R300_ZC_FLUSH | R300_ZC_FREE); + radeon_ring_write(rdev, PACKET0(RADEON_WAIT_UNTIL, 0)); + radeon_ring_write(rdev, + RADEON_WAIT_2D_IDLECLEAN | + RADEON_WAIT_3D_IDLECLEAN); + radeon_ring_write(rdev, PACKET0(R300_GB_AA_CONFIG, 0)); + radeon_ring_write(rdev, 0); + radeon_ring_write(rdev, PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0)); + radeon_ring_write(rdev, R300_RB3D_DC_FLUSH | R300_RB3D_DC_FREE); + radeon_ring_write(rdev, PACKET0(R300_RB3D_ZCACHE_CTLSTAT, 0)); + radeon_ring_write(rdev, R300_ZC_FLUSH | R300_ZC_FREE); + radeon_ring_write(rdev, PACKET0(R300_GB_MSPOS0, 0)); + radeon_ring_write(rdev, + ((6 << R300_MS_X0_SHIFT) | + (6 << R300_MS_Y0_SHIFT) | + (6 << R300_MS_X1_SHIFT) | + (6 << R300_MS_Y1_SHIFT) | + (6 << R300_MS_X2_SHIFT) | + (6 << R300_MS_Y2_SHIFT) | + (6 << R300_MSBD0_Y_SHIFT) | + (6 << R300_MSBD0_X_SHIFT))); + radeon_ring_write(rdev, PACKET0(R300_GB_MSPOS1, 0)); + radeon_ring_write(rdev, + ((6 << R300_MS_X3_SHIFT) | + (6 << R300_MS_Y3_SHIFT) | + (6 << R300_MS_X4_SHIFT) | + (6 << R300_MS_Y4_SHIFT) | + (6 << R300_MS_X5_SHIFT) | + (6 << R300_MS_Y5_SHIFT) | + (6 << R300_MSBD1_SHIFT))); + radeon_ring_write(rdev, PACKET0(R300_GA_ENHANCE, 0)); + radeon_ring_write(rdev, R300_GA_DEADLOCK_CNTL | R300_GA_FASTSYNC_CNTL); + radeon_ring_write(rdev, PACKET0(R300_GA_POLY_MODE, 0)); + radeon_ring_write(rdev, + R300_FRONT_PTYPE_TRIANGE | R300_BACK_PTYPE_TRIANGE); + radeon_ring_write(rdev, PACKET0(R300_GA_ROUND_MODE, 0)); + radeon_ring_write(rdev, + R300_GEOMETRY_ROUND_NEAREST | + R300_COLOR_ROUND_NEAREST); + radeon_ring_unlock_commit(rdev); +} + +void r300_errata(struct radeon_device *rdev) +{ + rdev->pll_errata = 0; + + if (rdev->family == CHIP_R300 && + (RREG32(RADEON_CONFIG_CNTL) & RADEON_CFG_ATI_REV_ID_MASK) == RADEON_CFG_ATI_REV_A11) { + rdev->pll_errata |= CHIP_ERRATA_R300_CG; + } +} + +int r300_mc_wait_for_idle(struct radeon_device *rdev) +{ + unsigned i; + uint32_t tmp; + + for (i = 0; i < rdev->usec_timeout; i++) { + /* read MC_STATUS */ + tmp = RREG32(0x0150); + if (tmp & (1 << 4)) { + return 0; + } + DRM_UDELAY(1); + } + return -1; +} + +void r300_gpu_init(struct radeon_device *rdev) +{ + uint32_t gb_tile_config, tmp; + + r100_hdp_reset(rdev); + /* FIXME: rv380 one pipes ? */ + if ((rdev->family == CHIP_R300) || (rdev->family == CHIP_R350)) { + /* r300,r350 */ + rdev->num_gb_pipes = 2; + } else { + /* rv350,rv370,rv380 */ + rdev->num_gb_pipes = 1; + } + gb_tile_config = (R300_ENABLE_TILING | R300_TILE_SIZE_16); + switch (rdev->num_gb_pipes) { + case 2: + gb_tile_config |= R300_PIPE_COUNT_R300; + break; + case 3: + gb_tile_config |= R300_PIPE_COUNT_R420_3P; + break; + case 4: + gb_tile_config |= R300_PIPE_COUNT_R420; + break; + default: + case 1: + gb_tile_config |= R300_PIPE_COUNT_RV350; + break; + } + WREG32(R300_GB_TILE_CONFIG, gb_tile_config); + + if (r100_gui_wait_for_idle(rdev)) { + printk(KERN_WARNING "Failed to wait GUI idle while " + "programming pipes. Bad things might happen.\n"); + } + + tmp = RREG32(0x170C); + WREG32(0x170C, tmp | (1 << 31)); + + WREG32(R300_RB2D_DSTCACHE_MODE, + R300_DC_AUTOFLUSH_ENABLE | + R300_DC_DC_DISABLE_IGNORE_PE); + + if (r100_gui_wait_for_idle(rdev)) { + printk(KERN_WARNING "Failed to wait GUI idle while " + "programming pipes. Bad things might happen.\n"); + } + if (r300_mc_wait_for_idle(rdev)) { + printk(KERN_WARNING "Failed to wait MC idle while " + "programming pipes. Bad things might happen.\n"); + } + DRM_INFO("radeon: %d pipes initialized.\n", rdev->num_gb_pipes); +} + +int r300_ga_reset(struct radeon_device *rdev) +{ + uint32_t tmp; + bool reinit_cp; + int i; + + reinit_cp = rdev->cp.ready; + rdev->cp.ready = false; + for (i = 0; i < rdev->usec_timeout; i++) { + WREG32(RADEON_CP_CSQ_MODE, 0); + WREG32(RADEON_CP_CSQ_CNTL, 0); + WREG32(RADEON_RBBM_SOFT_RESET, 0x32005); + (void)RREG32(RADEON_RBBM_SOFT_RESET); + udelay(200); + WREG32(RADEON_RBBM_SOFT_RESET, 0); + /* Wait to prevent race in RBBM_STATUS */ + mdelay(1); + tmp = RREG32(RADEON_RBBM_STATUS); + if (tmp & ((1 << 20) | (1 << 26))) { + DRM_ERROR("VAP & CP still busy (RBBM_STATUS=0x%08X)", tmp); + /* GA still busy soft reset it */ + WREG32(0x429C, 0x200); + WREG32(R300_VAP_PVS_STATE_FLUSH_REG, 0); + WREG32(0x43E0, 0); + WREG32(0x43E4, 0); + WREG32(0x24AC, 0); + } + /* Wait to prevent race in RBBM_STATUS */ + mdelay(1); + tmp = RREG32(RADEON_RBBM_STATUS); + if (!(tmp & ((1 << 20) | (1 << 26)))) { + break; + } + } + for (i = 0; i < rdev->usec_timeout; i++) { + tmp = RREG32(RADEON_RBBM_STATUS); + if (!(tmp & ((1 << 20) | (1 << 26)))) { + DRM_INFO("GA reset succeed (RBBM_STATUS=0x%08X)\n", + tmp); + if (reinit_cp) { + return r100_cp_init(rdev, rdev->cp.ring_size); + } + return 0; + } + DRM_UDELAY(1); + } + tmp = RREG32(RADEON_RBBM_STATUS); + DRM_ERROR("Failed to reset GA ! (RBBM_STATUS=0x%08X)\n", tmp); + return -1; +} + +int r300_gpu_reset(struct radeon_device *rdev) +{ + uint32_t status; + + /* reset order likely matter */ + status = RREG32(RADEON_RBBM_STATUS); + /* reset HDP */ + r100_hdp_reset(rdev); + /* reset rb2d */ + if (status & ((1 << 17) | (1 << 18) | (1 << 27))) { + r100_rb2d_reset(rdev); + } + /* reset GA */ + if (status & ((1 << 20) | (1 << 26))) { + r300_ga_reset(rdev); + } + /* reset CP */ + status = RREG32(RADEON_RBBM_STATUS); + if (status & (1 << 16)) { + r100_cp_reset(rdev); + } + /* Check if GPU is idle */ + status = RREG32(RADEON_RBBM_STATUS); + if (status & (1 << 31)) { + DRM_ERROR("Failed to reset GPU (RBBM_STATUS=0x%08X)\n", status); + return -1; + } + DRM_INFO("GPU reset succeed (RBBM_STATUS=0x%08X)\n", status); + return 0; +} + + +/* + * r300,r350,rv350,rv380 VRAM info + */ +void r300_vram_info(struct radeon_device *rdev) +{ + uint32_t tmp; + + /* DDR for all card after R300 & IGP */ + rdev->mc.vram_is_ddr = true; + tmp = RREG32(RADEON_MEM_CNTL); + if (tmp & R300_MEM_NUM_CHANNELS_MASK) { + rdev->mc.vram_width = 128; + } else { + rdev->mc.vram_width = 64; + } + rdev->mc.vram_size = RREG32(RADEON_CONFIG_MEMSIZE); + + rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0); + rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0); +} + + +/* + * Indirect registers accessor + */ +uint32_t rv370_pcie_rreg(struct radeon_device *rdev, uint32_t reg) +{ + uint32_t r; + + WREG8(RADEON_PCIE_INDEX, ((reg) & 0xff)); + (void)RREG32(RADEON_PCIE_INDEX); + r = RREG32(RADEON_PCIE_DATA); + return r; +} + +void rv370_pcie_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v) +{ + WREG8(RADEON_PCIE_INDEX, ((reg) & 0xff)); + (void)RREG32(RADEON_PCIE_INDEX); + WREG32(RADEON_PCIE_DATA, (v)); + (void)RREG32(RADEON_PCIE_DATA); +} + +/* + * PCIE Lanes + */ + +void rv370_set_pcie_lanes(struct radeon_device *rdev, int lanes) +{ + uint32_t link_width_cntl, mask; + + if (rdev->flags & RADEON_IS_IGP) + return; + + if (!(rdev->flags & RADEON_IS_PCIE)) + return; + + /* FIXME wait for idle */ + + switch (lanes) { + case 0: + mask = RADEON_PCIE_LC_LINK_WIDTH_X0; + break; + case 1: + mask = RADEON_PCIE_LC_LINK_WIDTH_X1; + break; + case 2: + mask = RADEON_PCIE_LC_LINK_WIDTH_X2; + break; + case 4: + mask = RADEON_PCIE_LC_LINK_WIDTH_X4; + break; + case 8: + mask = RADEON_PCIE_LC_LINK_WIDTH_X8; + break; + case 12: + mask = RADEON_PCIE_LC_LINK_WIDTH_X12; + break; + case 16: + default: + mask = RADEON_PCIE_LC_LINK_WIDTH_X16; + break; + } + + link_width_cntl = RREG32_PCIE(RADEON_PCIE_LC_LINK_WIDTH_CNTL); + + if ((link_width_cntl & RADEON_PCIE_LC_LINK_WIDTH_RD_MASK) == + (mask << RADEON_PCIE_LC_LINK_WIDTH_RD_SHIFT)) + return; + + link_width_cntl &= ~(RADEON_PCIE_LC_LINK_WIDTH_MASK | + RADEON_PCIE_LC_RECONFIG_NOW | + RADEON_PCIE_LC_RECONFIG_LATER | + RADEON_PCIE_LC_SHORT_RECONFIG_EN); + link_width_cntl |= mask; + WREG32_PCIE(RADEON_PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl); + WREG32_PCIE(RADEON_PCIE_LC_LINK_WIDTH_CNTL, (link_width_cntl | + RADEON_PCIE_LC_RECONFIG_NOW)); + + /* wait for lane set to complete */ + link_width_cntl = RREG32_PCIE(RADEON_PCIE_LC_LINK_WIDTH_CNTL); + while (link_width_cntl == 0xffffffff) + link_width_cntl = RREG32_PCIE(RADEON_PCIE_LC_LINK_WIDTH_CNTL); + +} + + +/* + * Debugfs info + */ +#if defined(CONFIG_DEBUG_FS) +static int rv370_debugfs_pcie_gart_info(struct seq_file *m, void *data) +{ + struct drm_info_node *node = (struct drm_info_node *) m->private; + struct drm_device *dev = node->minor->dev; + struct radeon_device *rdev = dev->dev_private; + uint32_t tmp; + + tmp = RREG32_PCIE(RADEON_PCIE_TX_GART_CNTL); + seq_printf(m, "PCIE_TX_GART_CNTL 0x%08x\n", tmp); + tmp = RREG32_PCIE(RADEON_PCIE_TX_GART_BASE); + seq_printf(m, "PCIE_TX_GART_BASE 0x%08x\n", tmp); + tmp = RREG32_PCIE(RADEON_PCIE_TX_GART_START_LO); + seq_printf(m, "PCIE_TX_GART_START_LO 0x%08x\n", tmp); + tmp = RREG32_PCIE(RADEON_PCIE_TX_GART_START_HI); + seq_printf(m, "PCIE_TX_GART_START_HI 0x%08x\n", tmp); + tmp = RREG32_PCIE(RADEON_PCIE_TX_GART_END_LO); + seq_printf(m, "PCIE_TX_GART_END_LO 0x%08x\n", tmp); + tmp = RREG32_PCIE(RADEON_PCIE_TX_GART_END_HI); + seq_printf(m, "PCIE_TX_GART_END_HI 0x%08x\n", tmp); + tmp = RREG32_PCIE(RADEON_PCIE_TX_GART_ERROR); + seq_printf(m, "PCIE_TX_GART_ERROR 0x%08x\n", tmp); + return 0; +} + +static struct drm_info_list rv370_pcie_gart_info_list[] = { + {"rv370_pcie_gart_info", rv370_debugfs_pcie_gart_info, 0, NULL}, +}; +#endif + +int rv370_debugfs_pcie_gart_info_init(struct radeon_device *rdev) +{ +#if defined(CONFIG_DEBUG_FS) + return radeon_debugfs_add_files(rdev, rv370_pcie_gart_info_list, 1); +#else + return 0; +#endif +} + + +/* + * CS functions + */ +struct r300_cs_track_cb { + struct radeon_object *robj; + unsigned pitch; + unsigned cpp; + unsigned offset; +}; + +struct r300_cs_track_array { + struct radeon_object *robj; + unsigned esize; +}; + +struct r300_cs_track_texture { + struct radeon_object *robj; + unsigned pitch; + unsigned width; + unsigned height; + unsigned num_levels; + unsigned cpp; + unsigned tex_coord_type; + unsigned txdepth; + unsigned width_11; + unsigned height_11; + bool use_pitch; + bool enabled; + bool roundup_w; + bool roundup_h; +}; + +struct r300_cs_track { + unsigned num_cb; + unsigned maxy; + unsigned vtx_size; + unsigned vap_vf_cntl; + unsigned immd_dwords; + unsigned num_arrays; + unsigned max_indx; + struct r300_cs_track_array arrays[11]; + struct r300_cs_track_cb cb[4]; + struct r300_cs_track_cb zb; + struct r300_cs_track_texture textures[16]; + bool z_enabled; +}; + +static inline void r300_cs_track_texture_print(struct r300_cs_track_texture *t) +{ + DRM_ERROR("pitch %d\n", t->pitch); + DRM_ERROR("width %d\n", t->width); + DRM_ERROR("height %d\n", t->height); + DRM_ERROR("num levels %d\n", t->num_levels); + DRM_ERROR("depth %d\n", t->txdepth); + DRM_ERROR("bpp %d\n", t->cpp); + DRM_ERROR("coordinate type %d\n", t->tex_coord_type); + DRM_ERROR("width round to power of 2 %d\n", t->roundup_w); + DRM_ERROR("height round to power of 2 %d\n", t->roundup_h); +} + +static inline int r300_cs_track_texture_check(struct radeon_device *rdev, + struct r300_cs_track *track) +{ + struct radeon_object *robj; + unsigned long size; + unsigned u, i, w, h; + + for (u = 0; u < 16; u++) { + if (!track->textures[u].enabled) + continue; + robj = track->textures[u].robj; + if (robj == NULL) { + DRM_ERROR("No texture bound to unit %u\n", u); + return -EINVAL; + } + size = 0; + for (i = 0; i <= track->textures[u].num_levels; i++) { + if (track->textures[u].use_pitch) { + w = track->textures[u].pitch / (1 << i); + } else { + w = track->textures[u].width / (1 << i); + if (rdev->family >= CHIP_RV515) + w |= track->textures[u].width_11; + if (track->textures[u].roundup_w) + w = roundup_pow_of_two(w); + } + h = track->textures[u].height / (1 << i); + if (rdev->family >= CHIP_RV515) + h |= track->textures[u].height_11; + if (track->textures[u].roundup_h) + h = roundup_pow_of_two(h); + size += w * h; + } + size *= track->textures[u].cpp; + switch (track->textures[u].tex_coord_type) { + case 0: + break; + case 1: + size *= (1 << track->textures[u].txdepth); + break; + case 2: + size *= 6; + break; + default: + DRM_ERROR("Invalid texture coordinate type %u for unit " + "%u\n", track->textures[u].tex_coord_type, u); + return -EINVAL; + } + if (size > radeon_object_size(robj)) { + DRM_ERROR("Texture of unit %u needs %lu bytes but is " + "%lu\n", u, size, radeon_object_size(robj)); + r300_cs_track_texture_print(&track->textures[u]); + return -EINVAL; + } + } + return 0; +} + +int r300_cs_track_check(struct radeon_device *rdev, struct r300_cs_track *track) +{ + unsigned i; + unsigned long size; + unsigned prim_walk; + unsigned nverts; + + for (i = 0; i < track->num_cb; i++) { + if (track->cb[i].robj == NULL) { + DRM_ERROR("[drm] No buffer for color buffer %d !\n", i); + return -EINVAL; + } + size = track->cb[i].pitch * track->cb[i].cpp * track->maxy; + size += track->cb[i].offset; + if (size > radeon_object_size(track->cb[i].robj)) { + DRM_ERROR("[drm] Buffer too small for color buffer %d " + "(need %lu have %lu) !\n", i, size, + radeon_object_size(track->cb[i].robj)); + DRM_ERROR("[drm] color buffer %d (%u %u %u %u)\n", + i, track->cb[i].pitch, track->cb[i].cpp, + track->cb[i].offset, track->maxy); + return -EINVAL; + } + } + if (track->z_enabled) { + if (track->zb.robj == NULL) { + DRM_ERROR("[drm] No buffer for z buffer !\n"); + return -EINVAL; + } + size = track->zb.pitch * track->zb.cpp * track->maxy; + size += track->zb.offset; + if (size > radeon_object_size(track->zb.robj)) { + DRM_ERROR("[drm] Buffer too small for z buffer " + "(need %lu have %lu) !\n", size, + radeon_object_size(track->zb.robj)); + return -EINVAL; + } + } + prim_walk = (track->vap_vf_cntl >> 4) & 0x3; + nverts = (track->vap_vf_cntl >> 16) & 0xFFFF; + switch (prim_walk) { + case 1: + for (i = 0; i < track->num_arrays; i++) { + size = track->arrays[i].esize * track->max_indx * 4; + if (track->arrays[i].robj == NULL) { + DRM_ERROR("(PW %u) Vertex array %u no buffer " + "bound\n", prim_walk, i); + return -EINVAL; + } + if (size > radeon_object_size(track->arrays[i].robj)) { + DRM_ERROR("(PW %u) Vertex array %u need %lu dwords " + "have %lu dwords\n", prim_walk, i, + size >> 2, + radeon_object_size(track->arrays[i].robj) >> 2); + DRM_ERROR("Max indices %u\n", track->max_indx); + return -EINVAL; + } + } + break; + case 2: + for (i = 0; i < track->num_arrays; i++) { + size = track->arrays[i].esize * (nverts - 1) * 4; + if (track->arrays[i].robj == NULL) { + DRM_ERROR("(PW %u) Vertex array %u no buffer " + "bound\n", prim_walk, i); + return -EINVAL; + } + if (size > radeon_object_size(track->arrays[i].robj)) { + DRM_ERROR("(PW %u) Vertex array %u need %lu dwords " + "have %lu dwords\n", prim_walk, i, size >> 2, + radeon_object_size(track->arrays[i].robj) >> 2); + return -EINVAL; + } + } + break; + case 3: + size = track->vtx_size * nverts; + if (size != track->immd_dwords) { + DRM_ERROR("IMMD draw %u dwors but needs %lu dwords\n", + track->immd_dwords, size); + DRM_ERROR("VAP_VF_CNTL.NUM_VERTICES %u, VTX_SIZE %u\n", + nverts, track->vtx_size); + return -EINVAL; + } + break; + default: + DRM_ERROR("[drm] Invalid primitive walk %d for VAP_VF_CNTL\n", + prim_walk); + return -EINVAL; + } + return r300_cs_track_texture_check(rdev, track); +} + +static inline void r300_cs_track_clear(struct r300_cs_track *track) +{ + unsigned i; + + track->num_cb = 4; + track->maxy = 4096; + for (i = 0; i < track->num_cb; i++) { + track->cb[i].robj = NULL; + track->cb[i].pitch = 8192; + track->cb[i].cpp = 16; + track->cb[i].offset = 0; + } + track->z_enabled = true; + track->zb.robj = NULL; + track->zb.pitch = 8192; + track->zb.cpp = 4; + track->zb.offset = 0; + track->vtx_size = 0x7F; + track->immd_dwords = 0xFFFFFFFFUL; + track->num_arrays = 11; + track->max_indx = 0x00FFFFFFUL; + for (i = 0; i < track->num_arrays; i++) { + track->arrays[i].robj = NULL; + track->arrays[i].esize = 0x7F; + } + for (i = 0; i < 16; i++) { + track->textures[i].pitch = 16536; + track->textures[i].width = 16536; + track->textures[i].height = 16536; + track->textures[i].width_11 = 1 << 11; + track->textures[i].height_11 = 1 << 11; + track->textures[i].num_levels = 12; + track->textures[i].txdepth = 16; + track->textures[i].cpp = 64; + track->textures[i].tex_coord_type = 1; + track->textures[i].robj = NULL; + /* CS IB emission code makes sure texture unit are disabled */ + track->textures[i].enabled = false; + track->textures[i].roundup_w = true; + track->textures[i].roundup_h = true; + } +} + +static const unsigned r300_reg_safe_bm[159] = { + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFBF, 0xFFFFFFFF, 0xFFFFFFBF, 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, 0xFFFFFFFF, + 0x17FF1FFF, 0xFFFFFFFC, 0xFFFFFFFF, 0xFF30FFBF, + 0xFFFFFFF8, 0xC3E6FFFF, 0xFFFFF6DF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFF03F, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFEFCE, 0xF00EBFFF, 0x007C0000, + 0xF0000078, 0xFF000009, 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, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFF7FF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFC78, 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFF, + 0x38FF8F50, 0xFFF88082, 0xF000000C, 0xFAE009FF, + 0x0000FFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, + 0x00000000, 0x0000C100, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0xFFFF0000, 0xFFFFFFFF, 0xFF80FFFF, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x0003FC01, 0xFFFFFFF8, 0xFE800B19, +}; + +static int r300_packet0_check(struct radeon_cs_parser *p, + struct radeon_cs_packet *pkt, + unsigned idx, unsigned reg) +{ + struct radeon_cs_chunk *ib_chunk; + struct radeon_cs_reloc *reloc; + struct r300_cs_track *track; + volatile uint32_t *ib; + uint32_t tmp; + unsigned i; + int r; + + ib = p->ib->ptr; + ib_chunk = &p->chunks[p->chunk_ib_idx]; + track = (struct r300_cs_track*)p->track; + switch(reg) { + case RADEON_DST_PITCH_OFFSET: + case RADEON_SRC_PITCH_OFFSET: + r = r100_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("No reloc for ib[%d]=0x%04X\n", + idx, reg); + r100_cs_dump_packet(p, pkt); + return r; + } + tmp = ib_chunk->kdata[idx] & 0x003fffff; + tmp += (((u32)reloc->lobj.gpu_offset) >> 10); + ib[idx] = (ib_chunk->kdata[idx] & 0xffc00000) | tmp; + break; + case R300_RB3D_COLOROFFSET0: + case R300_RB3D_COLOROFFSET1: + case R300_RB3D_COLOROFFSET2: + case R300_RB3D_COLOROFFSET3: + i = (reg - R300_RB3D_COLOROFFSET0) >> 2; + r = r100_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("No reloc for ib[%d]=0x%04X\n", + idx, reg); + r100_cs_dump_packet(p, pkt); + return r; + } + track->cb[i].robj = reloc->robj; + track->cb[i].offset = ib_chunk->kdata[idx]; + ib[idx] = ib_chunk->kdata[idx] + ((u32)reloc->lobj.gpu_offset); + break; + case R300_ZB_DEPTHOFFSET: + r = r100_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("No reloc for ib[%d]=0x%04X\n", + idx, reg); + r100_cs_dump_packet(p, pkt); + return r; + } + track->zb.robj = reloc->robj; + track->zb.offset = ib_chunk->kdata[idx]; + ib[idx] = ib_chunk->kdata[idx] + ((u32)reloc->lobj.gpu_offset); + break; + case R300_TX_OFFSET_0: + case R300_TX_OFFSET_0+4: + case R300_TX_OFFSET_0+8: + case R300_TX_OFFSET_0+12: + case R300_TX_OFFSET_0+16: + case R300_TX_OFFSET_0+20: + case R300_TX_OFFSET_0+24: + case R300_TX_OFFSET_0+28: + case R300_TX_OFFSET_0+32: + case R300_TX_OFFSET_0+36: + case R300_TX_OFFSET_0+40: + case R300_TX_OFFSET_0+44: + case R300_TX_OFFSET_0+48: + case R300_TX_OFFSET_0+52: + case R300_TX_OFFSET_0+56: + case R300_TX_OFFSET_0+60: + i = (reg - R300_TX_OFFSET_0) >> 2; + r = r100_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("No reloc for ib[%d]=0x%04X\n", + idx, reg); + r100_cs_dump_packet(p, pkt); + return r; + } + ib[idx] = ib_chunk->kdata[idx] + ((u32)reloc->lobj.gpu_offset); + track->textures[i].robj = reloc->robj; + break; + /* Tracked registers */ + case 0x2084: + /* VAP_VF_CNTL */ + track->vap_vf_cntl = ib_chunk->kdata[idx]; + break; + case 0x20B4: + /* VAP_VTX_SIZE */ + track->vtx_size = ib_chunk->kdata[idx] & 0x7F; + break; + case 0x2134: + /* VAP_VF_MAX_VTX_INDX */ + track->max_indx = ib_chunk->kdata[idx] & 0x00FFFFFFUL; + break; + case 0x43E4: + /* SC_SCISSOR1 */ + track->maxy = ((ib_chunk->kdata[idx] >> 13) & 0x1FFF) + 1; + if (p->rdev->family < CHIP_RV515) { + track->maxy -= 1440; + } + break; + case 0x4E00: + /* RB3D_CCTL */ + track->num_cb = ((ib_chunk->kdata[idx] >> 5) & 0x3) + 1; + break; + case 0x4E38: + case 0x4E3C: + case 0x4E40: + case 0x4E44: + /* RB3D_COLORPITCH0 */ + /* RB3D_COLORPITCH1 */ + /* RB3D_COLORPITCH2 */ + /* RB3D_COLORPITCH3 */ + i = (reg - 0x4E38) >> 2; + track->cb[i].pitch = ib_chunk->kdata[idx] & 0x3FFE; + switch (((ib_chunk->kdata[idx] >> 21) & 0xF)) { + case 9: + case 11: + case 12: + track->cb[i].cpp = 1; + break; + case 3: + case 4: + case 13: + case 15: + track->cb[i].cpp = 2; + break; + case 6: + track->cb[i].cpp = 4; + break; + case 10: + track->cb[i].cpp = 8; + break; + case 7: + track->cb[i].cpp = 16; + break; + default: + DRM_ERROR("Invalid color buffer format (%d) !\n", + ((ib_chunk->kdata[idx] >> 21) & 0xF)); + return -EINVAL; + } + break; + case 0x4F00: + /* ZB_CNTL */ + if (ib_chunk->kdata[idx] & 2) { + track->z_enabled = true; + } else { + track->z_enabled = false; + } + break; + case 0x4F10: + /* ZB_FORMAT */ + switch ((ib_chunk->kdata[idx] & 0xF)) { + case 0: + case 1: + track->zb.cpp = 2; + break; + case 2: + track->zb.cpp = 4; + break; + default: + DRM_ERROR("Invalid z buffer format (%d) !\n", + (ib_chunk->kdata[idx] & 0xF)); + return -EINVAL; + } + break; + case 0x4F24: + /* ZB_DEPTHPITCH */ + track->zb.pitch = ib_chunk->kdata[idx] & 0x3FFC; + break; + case 0x4104: + for (i = 0; i < 16; i++) { + bool enabled; + + enabled = !!(ib_chunk->kdata[idx] & (1 << i)); + track->textures[i].enabled = enabled; + } + break; + case 0x44C0: + case 0x44C4: + case 0x44C8: + case 0x44CC: + case 0x44D0: + case 0x44D4: + case 0x44D8: + case 0x44DC: + case 0x44E0: + case 0x44E4: + case 0x44E8: + case 0x44EC: + case 0x44F0: + case 0x44F4: + case 0x44F8: + case 0x44FC: + /* TX_FORMAT1_[0-15] */ + i = (reg - 0x44C0) >> 2; + tmp = (ib_chunk->kdata[idx] >> 25) & 0x3; + track->textures[i].tex_coord_type = tmp; + switch ((ib_chunk->kdata[idx] & 0x1F)) { + case 0: + case 2: + case 5: + case 18: + case 20: + case 21: + track->textures[i].cpp = 1; + break; + case 1: + case 3: + case 6: + case 7: + case 10: + case 11: + case 19: + case 22: + case 24: + track->textures[i].cpp = 2; + break; + case 4: + case 8: + case 9: + case 12: + case 13: + case 23: + case 25: + case 27: + case 30: + track->textures[i].cpp = 4; + break; + case 14: + case 26: + case 28: + track->textures[i].cpp = 8; + break; + case 29: + track->textures[i].cpp = 16; + break; + default: + DRM_ERROR("Invalid texture format %u\n", + (ib_chunk->kdata[idx] & 0x1F)); + return -EINVAL; + break; + } + break; + case 0x4400: + case 0x4404: + case 0x4408: + case 0x440C: + case 0x4410: + case 0x4414: + case 0x4418: + case 0x441C: + case 0x4420: + case 0x4424: + case 0x4428: + case 0x442C: + case 0x4430: + case 0x4434: + case 0x4438: + case 0x443C: + /* TX_FILTER0_[0-15] */ + i = (reg - 0x4400) >> 2; + tmp = ib_chunk->kdata[idx] & 0x7;; + if (tmp == 2 || tmp == 4 || tmp == 6) { + track->textures[i].roundup_w = false; + } + tmp = (ib_chunk->kdata[idx] >> 3) & 0x7;; + if (tmp == 2 || tmp == 4 || tmp == 6) { + track->textures[i].roundup_h = false; + } + break; + case 0x4500: + case 0x4504: + case 0x4508: + case 0x450C: + case 0x4510: + case 0x4514: + case 0x4518: + case 0x451C: + case 0x4520: + case 0x4524: + case 0x4528: + case 0x452C: + case 0x4530: + case 0x4534: + case 0x4538: + case 0x453C: + /* TX_FORMAT2_[0-15] */ + i = (reg - 0x4500) >> 2; + tmp = ib_chunk->kdata[idx] & 0x3FFF; + track->textures[i].pitch = tmp + 1; + if (p->rdev->family >= CHIP_RV515) { + tmp = ((ib_chunk->kdata[idx] >> 15) & 1) << 11; + track->textures[i].width_11 = tmp; + tmp = ((ib_chunk->kdata[idx] >> 16) & 1) << 11; + track->textures[i].height_11 = tmp; + } + break; + case 0x4480: + case 0x4484: + case 0x4488: + case 0x448C: + case 0x4490: + case 0x4494: + case 0x4498: + case 0x449C: + case 0x44A0: + case 0x44A4: + case 0x44A8: + case 0x44AC: + case 0x44B0: + case 0x44B4: + case 0x44B8: + case 0x44BC: + /* TX_FORMAT0_[0-15] */ + i = (reg - 0x4480) >> 2; + tmp = ib_chunk->kdata[idx] & 0x7FF; + track->textures[i].width = tmp + 1; + tmp = (ib_chunk->kdata[idx] >> 11) & 0x7FF; + track->textures[i].height = tmp + 1; + tmp = (ib_chunk->kdata[idx] >> 26) & 0xF; + track->textures[i].num_levels = tmp; + tmp = ib_chunk->kdata[idx] & (1 << 31); + track->textures[i].use_pitch = !!tmp; + tmp = (ib_chunk->kdata[idx] >> 22) & 0xF; + track->textures[i].txdepth = tmp; + break; + default: + printk(KERN_ERR "Forbidden register 0x%04X in cs at %d\n", + reg, idx); + return -EINVAL; + } + return 0; +} + +static int r300_packet3_check(struct radeon_cs_parser *p, + struct radeon_cs_packet *pkt) +{ + struct radeon_cs_chunk *ib_chunk; + struct radeon_cs_reloc *reloc; + struct r300_cs_track *track; + volatile uint32_t *ib; + unsigned idx; + unsigned i, c; + int r; + + ib = p->ib->ptr; + ib_chunk = &p->chunks[p->chunk_ib_idx]; + idx = pkt->idx + 1; + track = (struct r300_cs_track*)p->track; + switch(pkt->opcode) { + case PACKET3_3D_LOAD_VBPNTR: + c = ib_chunk->kdata[idx++] & 0x1F; + track->num_arrays = c; + for (i = 0; i < (c - 1); i+=2, idx+=3) { + r = r100_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("No reloc for packet3 %d\n", + pkt->opcode); + r100_cs_dump_packet(p, pkt); + return r; + } + ib[idx+1] = ib_chunk->kdata[idx+1] + ((u32)reloc->lobj.gpu_offset); + track->arrays[i + 0].robj = reloc->robj; + track->arrays[i + 0].esize = ib_chunk->kdata[idx] >> 8; + track->arrays[i + 0].esize &= 0x7F; + r = r100_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("No reloc for packet3 %d\n", + pkt->opcode); + r100_cs_dump_packet(p, pkt); + return r; + } + ib[idx+2] = ib_chunk->kdata[idx+2] + ((u32)reloc->lobj.gpu_offset); + track->arrays[i + 1].robj = reloc->robj; + track->arrays[i + 1].esize = ib_chunk->kdata[idx] >> 24; + track->arrays[i + 1].esize &= 0x7F; + } + if (c & 1) { + r = r100_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("No reloc for packet3 %d\n", + pkt->opcode); + r100_cs_dump_packet(p, pkt); + return r; + } + ib[idx+1] = ib_chunk->kdata[idx+1] + ((u32)reloc->lobj.gpu_offset); + track->arrays[i + 0].robj = reloc->robj; + track->arrays[i + 0].esize = ib_chunk->kdata[idx] >> 8; + track->arrays[i + 0].esize &= 0x7F; + } + break; + case PACKET3_INDX_BUFFER: + r = r100_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("No reloc for packet3 %d\n", pkt->opcode); + r100_cs_dump_packet(p, pkt); + return r; + } + ib[idx+1] = ib_chunk->kdata[idx+1] + ((u32)reloc->lobj.gpu_offset); + r = r100_cs_track_check_pkt3_indx_buffer(p, pkt, reloc->robj); + if (r) { + return r; + } + break; + /* Draw packet */ + case PACKET3_3D_DRAW_IMMD: + /* Number of dwords is vtx_size * (num_vertices - 1) + * PRIM_WALK must be equal to 3 vertex data in embedded + * in cmd stream */ + if (((ib_chunk->kdata[idx+1] >> 4) & 0x3) != 3) { + DRM_ERROR("PRIM_WALK must be 3 for IMMD draw\n"); + return -EINVAL; + } + track->vap_vf_cntl = ib_chunk->kdata[idx+1]; + track->immd_dwords = pkt->count - 1; + r = r300_cs_track_check(p->rdev, track); + if (r) { + return r; + } + break; + case PACKET3_3D_DRAW_IMMD_2: + /* Number of dwords is vtx_size * (num_vertices - 1) + * PRIM_WALK must be equal to 3 vertex data in embedded + * in cmd stream */ + if (((ib_chunk->kdata[idx] >> 4) & 0x3) != 3) { + DRM_ERROR("PRIM_WALK must be 3 for IMMD draw\n"); + return -EINVAL; + } + track->vap_vf_cntl = ib_chunk->kdata[idx]; + track->immd_dwords = pkt->count; + r = r300_cs_track_check(p->rdev, track); + if (r) { + return r; + } + break; + case PACKET3_3D_DRAW_VBUF: + track->vap_vf_cntl = ib_chunk->kdata[idx + 1]; + r = r300_cs_track_check(p->rdev, track); + if (r) { + return r; + } + break; + case PACKET3_3D_DRAW_VBUF_2: + track->vap_vf_cntl = ib_chunk->kdata[idx]; + r = r300_cs_track_check(p->rdev, track); + if (r) { + return r; + } + break; + case PACKET3_3D_DRAW_INDX: + track->vap_vf_cntl = ib_chunk->kdata[idx + 1]; + r = r300_cs_track_check(p->rdev, track); + if (r) { + return r; + } + break; + case PACKET3_3D_DRAW_INDX_2: + track->vap_vf_cntl = ib_chunk->kdata[idx]; + r = r300_cs_track_check(p->rdev, track); + if (r) { + return r; + } + break; + case PACKET3_NOP: + break; + default: + DRM_ERROR("Packet3 opcode %x not supported\n", pkt->opcode); + return -EINVAL; + } + return 0; +} + +int r300_cs_parse(struct radeon_cs_parser *p) +{ + struct radeon_cs_packet pkt; + struct r300_cs_track track; + int r; + + r300_cs_track_clear(&track); + p->track = &track; + do { + r = r100_cs_packet_parse(p, &pkt, p->idx); + if (r) { + return r; + } + p->idx += pkt.count + 2; + switch (pkt.type) { + case PACKET_TYPE0: + r = r100_cs_parse_packet0(p, &pkt, + p->rdev->config.r300.reg_safe_bm, + p->rdev->config.r300.reg_safe_bm_size, + &r300_packet0_check); + break; + case PACKET_TYPE2: + break; + case PACKET_TYPE3: + r = r300_packet3_check(p, &pkt); + break; + default: + DRM_ERROR("Unknown packet type %d !\n", pkt.type); + return -EINVAL; + } + if (r) { + return r; + } + } while (p->idx < p->chunks[p->chunk_ib_idx].length_dw); + return 0; +} + +int r300_init(struct radeon_device *rdev) +{ + rdev->config.r300.reg_safe_bm = r300_reg_safe_bm; + rdev->config.r300.reg_safe_bm_size = ARRAY_SIZE(r300_reg_safe_bm); + return 0; +} diff --git a/drivers/gpu/drm/radeon/r300.h b/drivers/gpu/drm/radeon/r300.h new file mode 100644 index 000000000000..8486b4da9d69 --- /dev/null +++ b/drivers/gpu/drm/radeon/r300.h @@ -0,0 +1,36 @@ +/* + * Copyright 2008 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * Copyright 2009 Jerome Glisse. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Dave Airlie + * Alex Deucher + * Jerome Glisse + */ +#ifndef R300_H +#define R300_H + +struct r300_asic { + const unsigned *reg_safe_bm; + unsigned reg_safe_bm_size; +}; + +#endif diff --git a/drivers/gpu/drm/radeon/r300_reg.h b/drivers/gpu/drm/radeon/r300_reg.h index bdbc95fa6721..70f48609515e 100644 --- a/drivers/gpu/drm/radeon/r300_reg.h +++ b/drivers/gpu/drm/radeon/r300_reg.h @@ -1,30 +1,34 @@ -/************************************************************************** +/* + * Copyright 2005 Nicolai Haehnle et al. + * Copyright 2008 Advanced Micro Devices, Inc. + * Copyright 2009 Jerome Glisse. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Nicolai Haehnle + * Jerome Glisse + */ +#ifndef _R300_REG_H_ +#define _R300_REG_H_ -Copyright (C) 2004-2005 Nicolai Haehnle et al. -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -on the rights to use, copy, modify, merge, publish, distribute, sub -license, and/or sell copies of the Software, and to permit persons to whom -the Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice (including the next -paragraph) shall be included in all copies or substantial portions of the -Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL -THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -USE OR OTHER DEALINGS IN THE SOFTWARE. - -**************************************************************************/ - -#ifndef _R300_REG_H -#define _R300_REG_H #define R300_MC_INIT_MISC_LAT_TIMER 0x180 # define R300_MC_MISC__MC_CPR_INIT_LAT_SHIFT 0 diff --git a/drivers/gpu/drm/radeon/r420.c b/drivers/gpu/drm/radeon/r420.c new file mode 100644 index 000000000000..dea497a979f2 --- /dev/null +++ b/drivers/gpu/drm/radeon/r420.c @@ -0,0 +1,223 @@ +/* + * Copyright 2008 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * Copyright 2009 Jerome Glisse. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Dave Airlie + * Alex Deucher + * Jerome Glisse + */ +#include +#include "drmP.h" +#include "radeon_reg.h" +#include "radeon.h" + +/* r420,r423,rv410 depends on : */ +void r100_pci_gart_disable(struct radeon_device *rdev); +void r100_hdp_reset(struct radeon_device *rdev); +void r100_mc_setup(struct radeon_device *rdev); +int r100_gui_wait_for_idle(struct radeon_device *rdev); +void r100_mc_disable_clients(struct radeon_device *rdev); +void r300_vram_info(struct radeon_device *rdev); +int r300_mc_wait_for_idle(struct radeon_device *rdev); +int rv370_pcie_gart_enable(struct radeon_device *rdev); +void rv370_pcie_gart_disable(struct radeon_device *rdev); + +/* This files gather functions specifics to : + * r420,r423,rv410 + * + * Some of these functions might be used by newer ASICs. + */ +void r420_gpu_init(struct radeon_device *rdev); +int r420_debugfs_pipes_info_init(struct radeon_device *rdev); + + +/* + * MC + */ +int r420_mc_init(struct radeon_device *rdev) +{ + int r; + + if (r100_debugfs_rbbm_init(rdev)) { + DRM_ERROR("Failed to register debugfs file for RBBM !\n"); + } + if (r420_debugfs_pipes_info_init(rdev)) { + DRM_ERROR("Failed to register debugfs file for pipes !\n"); + } + + r420_gpu_init(rdev); + r100_pci_gart_disable(rdev); + if (rdev->flags & RADEON_IS_PCIE) { + rv370_pcie_gart_disable(rdev); + } + + /* Setup GPU memory space */ + rdev->mc.vram_location = 0xFFFFFFFFUL; + rdev->mc.gtt_location = 0xFFFFFFFFUL; + if (rdev->flags & RADEON_IS_AGP) { + r = radeon_agp_init(rdev); + if (r) { + printk(KERN_WARNING "[drm] Disabling AGP\n"); + rdev->flags &= ~RADEON_IS_AGP; + rdev->mc.gtt_size = radeon_gart_size * 1024 * 1024; + } else { + rdev->mc.gtt_location = rdev->mc.agp_base; + } + } + r = radeon_mc_setup(rdev); + if (r) { + return r; + } + + /* Program GPU memory space */ + r100_mc_disable_clients(rdev); + if (r300_mc_wait_for_idle(rdev)) { + printk(KERN_WARNING "Failed to wait MC idle while " + "programming pipes. Bad things might happen.\n"); + } + r100_mc_setup(rdev); + return 0; +} + +void r420_mc_fini(struct radeon_device *rdev) +{ + rv370_pcie_gart_disable(rdev); + radeon_gart_table_vram_free(rdev); + radeon_gart_fini(rdev); +} + + +/* + * Global GPU functions + */ +void r420_errata(struct radeon_device *rdev) +{ + rdev->pll_errata = 0; +} + +void r420_pipes_init(struct radeon_device *rdev) +{ + unsigned tmp; + unsigned gb_pipe_select; + unsigned num_pipes; + + /* GA_ENHANCE workaround TCL deadlock issue */ + WREG32(0x4274, (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3)); + /* get max number of pipes */ + gb_pipe_select = RREG32(0x402C); + num_pipes = ((gb_pipe_select >> 12) & 3) + 1; + rdev->num_gb_pipes = num_pipes; + tmp = 0; + switch (num_pipes) { + default: + /* force to 1 pipe */ + num_pipes = 1; + case 1: + tmp = (0 << 1); + break; + case 2: + tmp = (3 << 1); + break; + case 3: + tmp = (6 << 1); + break; + case 4: + tmp = (7 << 1); + break; + } + WREG32(0x42C8, (1 << num_pipes) - 1); + /* Sub pixel 1/12 so we can have 4K rendering according to doc */ + tmp |= (1 << 4) | (1 << 0); + WREG32(0x4018, tmp); + if (r100_gui_wait_for_idle(rdev)) { + printk(KERN_WARNING "Failed to wait GUI idle while " + "programming pipes. Bad things might happen.\n"); + } + + tmp = RREG32(0x170C); + WREG32(0x170C, tmp | (1 << 31)); + + WREG32(R300_RB2D_DSTCACHE_MODE, + RREG32(R300_RB2D_DSTCACHE_MODE) | + R300_DC_AUTOFLUSH_ENABLE | + R300_DC_DC_DISABLE_IGNORE_PE); + + if (r100_gui_wait_for_idle(rdev)) { + printk(KERN_WARNING "Failed to wait GUI idle while " + "programming pipes. Bad things might happen.\n"); + } + DRM_INFO("radeon: %d pipes initialized.\n", rdev->num_gb_pipes); +} + +void r420_gpu_init(struct radeon_device *rdev) +{ + r100_hdp_reset(rdev); + r420_pipes_init(rdev); + if (r300_mc_wait_for_idle(rdev)) { + printk(KERN_WARNING "Failed to wait MC idle while " + "programming pipes. Bad things might happen.\n"); + } +} + + +/* + * r420,r423,rv410 VRAM info + */ +void r420_vram_info(struct radeon_device *rdev) +{ + r300_vram_info(rdev); +} + + +/* + * Debugfs info + */ +#if defined(CONFIG_DEBUG_FS) +static int r420_debugfs_pipes_info(struct seq_file *m, void *data) +{ + struct drm_info_node *node = (struct drm_info_node *) m->private; + struct drm_device *dev = node->minor->dev; + struct radeon_device *rdev = dev->dev_private; + uint32_t tmp; + + tmp = RREG32(R400_GB_PIPE_SELECT); + seq_printf(m, "GB_PIPE_SELECT 0x%08x\n", tmp); + tmp = RREG32(R300_GB_TILE_CONFIG); + seq_printf(m, "GB_TILE_CONFIG 0x%08x\n", tmp); + tmp = RREG32(R300_DST_PIPE_CONFIG); + seq_printf(m, "DST_PIPE_CONFIG 0x%08x\n", tmp); + return 0; +} + +static struct drm_info_list r420_pipes_info_list[] = { + {"r420_pipes_info", r420_debugfs_pipes_info, 0, NULL}, +}; +#endif + +int r420_debugfs_pipes_info_init(struct radeon_device *rdev) +{ +#if defined(CONFIG_DEBUG_FS) + return radeon_debugfs_add_files(rdev, r420_pipes_info_list, 1); +#else + return 0; +#endif +} diff --git a/drivers/gpu/drm/radeon/r500_reg.h b/drivers/gpu/drm/radeon/r500_reg.h new file mode 100644 index 000000000000..9070a1c2ce23 --- /dev/null +++ b/drivers/gpu/drm/radeon/r500_reg.h @@ -0,0 +1,749 @@ +/* + * Copyright 2008 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * Copyright 2009 Jerome Glisse. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Dave Airlie + * Alex Deucher + * Jerome Glisse + */ +#ifndef __R500_REG_H__ +#define __R500_REG_H__ + +/* pipe config regs */ +#define R300_GA_POLY_MODE 0x4288 +# define R300_FRONT_PTYPE_POINT (0 << 4) +# define R300_FRONT_PTYPE_LINE (1 << 4) +# define R300_FRONT_PTYPE_TRIANGE (2 << 4) +# define R300_BACK_PTYPE_POINT (0 << 7) +# define R300_BACK_PTYPE_LINE (1 << 7) +# define R300_BACK_PTYPE_TRIANGE (2 << 7) +#define R300_GA_ROUND_MODE 0x428c +# define R300_GEOMETRY_ROUND_TRUNC (0 << 0) +# define R300_GEOMETRY_ROUND_NEAREST (1 << 0) +# define R300_COLOR_ROUND_TRUNC (0 << 2) +# define R300_COLOR_ROUND_NEAREST (1 << 2) +#define R300_GB_MSPOS0 0x4010 +# define R300_MS_X0_SHIFT 0 +# define R300_MS_Y0_SHIFT 4 +# define R300_MS_X1_SHIFT 8 +# define R300_MS_Y1_SHIFT 12 +# define R300_MS_X2_SHIFT 16 +# define R300_MS_Y2_SHIFT 20 +# define R300_MSBD0_Y_SHIFT 24 +# define R300_MSBD0_X_SHIFT 28 +#define R300_GB_MSPOS1 0x4014 +# define R300_MS_X3_SHIFT 0 +# define R300_MS_Y3_SHIFT 4 +# define R300_MS_X4_SHIFT 8 +# define R300_MS_Y4_SHIFT 12 +# define R300_MS_X5_SHIFT 16 +# define R300_MS_Y5_SHIFT 20 +# define R300_MSBD1_SHIFT 24 + +#define R300_GA_ENHANCE 0x4274 +# define R300_GA_DEADLOCK_CNTL (1 << 0) +# define R300_GA_FASTSYNC_CNTL (1 << 1) +#define R300_RB3D_DSTCACHE_CTLSTAT 0x4e4c +# define R300_RB3D_DC_FLUSH (2 << 0) +# define R300_RB3D_DC_FREE (2 << 2) +# define R300_RB3D_DC_FINISH (1 << 4) +#define R300_RB3D_ZCACHE_CTLSTAT 0x4f18 +# define R300_ZC_FLUSH (1 << 0) +# define R300_ZC_FREE (1 << 1) +# define R300_ZC_FLUSH_ALL 0x3 +#define R400_GB_PIPE_SELECT 0x402c +#define R500_DYN_SCLK_PWMEM_PIPE 0x000d /* PLL */ +#define R500_SU_REG_DEST 0x42c8 +#define R300_GB_TILE_CONFIG 0x4018 +# define R300_ENABLE_TILING (1 << 0) +# define R300_PIPE_COUNT_RV350 (0 << 1) +# define R300_PIPE_COUNT_R300 (3 << 1) +# define R300_PIPE_COUNT_R420_3P (6 << 1) +# define R300_PIPE_COUNT_R420 (7 << 1) +# define R300_TILE_SIZE_8 (0 << 4) +# define R300_TILE_SIZE_16 (1 << 4) +# define R300_TILE_SIZE_32 (2 << 4) +# define R300_SUBPIXEL_1_12 (0 << 16) +# define R300_SUBPIXEL_1_16 (1 << 16) +#define R300_DST_PIPE_CONFIG 0x170c +# define R300_PIPE_AUTO_CONFIG (1 << 31) +#define R300_RB2D_DSTCACHE_MODE 0x3428 +# define R300_DC_AUTOFLUSH_ENABLE (1 << 8) +# define R300_DC_DC_DISABLE_IGNORE_PE (1 << 17) + +#define RADEON_CP_STAT 0x7C0 +#define RADEON_RBBM_CMDFIFO_ADDR 0xE70 +#define RADEON_RBBM_CMDFIFO_DATA 0xE74 +#define RADEON_ISYNC_CNTL 0x1724 +# define RADEON_ISYNC_ANY2D_IDLE3D (1 << 0) +# define RADEON_ISYNC_ANY3D_IDLE2D (1 << 1) +# define RADEON_ISYNC_TRIG2D_IDLE3D (1 << 2) +# define RADEON_ISYNC_TRIG3D_IDLE2D (1 << 3) +# define RADEON_ISYNC_WAIT_IDLEGUI (1 << 4) +# define RADEON_ISYNC_CPSCRATCH_IDLEGUI (1 << 5) + +#define RS480_NB_MC_INDEX 0x168 +# define RS480_NB_MC_IND_WR_EN (1 << 8) +#define RS480_NB_MC_DATA 0x16c + +/* + * RS690 + */ +#define RS690_MCCFG_FB_LOCATION 0x100 +#define RS690_MC_FB_START_MASK 0x0000FFFF +#define RS690_MC_FB_START_SHIFT 0 +#define RS690_MC_FB_TOP_MASK 0xFFFF0000 +#define RS690_MC_FB_TOP_SHIFT 16 +#define RS690_MCCFG_AGP_LOCATION 0x101 +#define RS690_MC_AGP_START_MASK 0x0000FFFF +#define RS690_MC_AGP_START_SHIFT 0 +#define RS690_MC_AGP_TOP_MASK 0xFFFF0000 +#define RS690_MC_AGP_TOP_SHIFT 16 +#define RS690_MCCFG_AGP_BASE 0x102 +#define RS690_MCCFG_AGP_BASE_2 0x103 +#define RS690_MC_INIT_MISC_LAT_TIMER 0x104 +#define RS690_HDP_FB_LOCATION 0x0134 +#define RS690_MC_INDEX 0x78 +# define RS690_MC_INDEX_MASK 0x1ff +# define RS690_MC_INDEX_WR_EN (1 << 9) +# define RS690_MC_INDEX_WR_ACK 0x7f +#define RS690_MC_DATA 0x7c +#define RS690_MC_STATUS 0x90 +#define RS690_MC_STATUS_IDLE (1 << 0) +#define RS480_AGP_BASE_2 0x0164 +#define RS480_MC_MISC_CNTL 0x18 +# define RS480_DISABLE_GTW (1 << 1) +# define RS480_GART_INDEX_REG_EN (1 << 12) +# define RS690_BLOCK_GFX_D3_EN (1 << 14) +#define RS480_GART_FEATURE_ID 0x2b +# define RS480_HANG_EN (1 << 11) +# define RS480_TLB_ENABLE (1 << 18) +# define RS480_P2P_ENABLE (1 << 19) +# define RS480_GTW_LAC_EN (1 << 25) +# define RS480_2LEVEL_GART (0 << 30) +# define RS480_1LEVEL_GART (1 << 30) +# define RS480_PDC_EN (1 << 31) +#define RS480_GART_BASE 0x2c +#define RS480_GART_CACHE_CNTRL 0x2e +# define RS480_GART_CACHE_INVALIDATE (1 << 0) /* wait for it to clear */ +#define RS480_AGP_ADDRESS_SPACE_SIZE 0x38 +# define RS480_GART_EN (1 << 0) +# define RS480_VA_SIZE_32MB (0 << 1) +# define RS480_VA_SIZE_64MB (1 << 1) +# define RS480_VA_SIZE_128MB (2 << 1) +# define RS480_VA_SIZE_256MB (3 << 1) +# define RS480_VA_SIZE_512MB (4 << 1) +# define RS480_VA_SIZE_1GB (5 << 1) +# define RS480_VA_SIZE_2GB (6 << 1) +#define RS480_AGP_MODE_CNTL 0x39 +# define RS480_POST_GART_Q_SIZE (1 << 18) +# define RS480_NONGART_SNOOP (1 << 19) +# define RS480_AGP_RD_BUF_SIZE (1 << 20) +# define RS480_REQ_TYPE_SNOOP_SHIFT 22 +# define RS480_REQ_TYPE_SNOOP_MASK 0x3 +# define RS480_REQ_TYPE_SNOOP_DIS (1 << 24) + +#define RS690_AIC_CTRL_SCRATCH 0x3A +# define RS690_DIS_OUT_OF_PCI_GART_ACCESS (1 << 1) + +/* + * RS600 + */ +#define RS600_MC_STATUS 0x0 +#define RS600_MC_STATUS_IDLE (1 << 0) +#define RS600_MC_INDEX 0x70 +# define RS600_MC_ADDR_MASK 0xffff +# define RS600_MC_IND_SEQ_RBS_0 (1 << 16) +# define RS600_MC_IND_SEQ_RBS_1 (1 << 17) +# define RS600_MC_IND_SEQ_RBS_2 (1 << 18) +# define RS600_MC_IND_SEQ_RBS_3 (1 << 19) +# define RS600_MC_IND_AIC_RBS (1 << 20) +# define RS600_MC_IND_CITF_ARB0 (1 << 21) +# define RS600_MC_IND_CITF_ARB1 (1 << 22) +# define RS600_MC_IND_WR_EN (1 << 23) +#define RS600_MC_DATA 0x74 +#define RS600_MC_STATUS 0x0 +# define RS600_MC_IDLE (1 << 1) +#define RS600_MC_FB_LOCATION 0x4 +#define RS600_MC_FB_START_MASK 0x0000FFFF +#define RS600_MC_FB_START_SHIFT 0 +#define RS600_MC_FB_TOP_MASK 0xFFFF0000 +#define RS600_MC_FB_TOP_SHIFT 16 +#define RS600_MC_AGP_LOCATION 0x5 +#define RS600_MC_AGP_START_MASK 0x0000FFFF +#define RS600_MC_AGP_START_SHIFT 0 +#define RS600_MC_AGP_TOP_MASK 0xFFFF0000 +#define RS600_MC_AGP_TOP_SHIFT 16 +#define RS600_MC_AGP_BASE 0x6 +#define RS600_MC_AGP_BASE_2 0x7 +#define RS600_MC_CNTL1 0x9 +# define RS600_ENABLE_PAGE_TABLES (1 << 26) +#define RS600_MC_PT0_CNTL 0x100 +# define RS600_ENABLE_PT (1 << 0) +# define RS600_EFFECTIVE_L2_CACHE_SIZE(x) ((x) << 15) +# define RS600_EFFECTIVE_L2_QUEUE_SIZE(x) ((x) << 21) +# define RS600_INVALIDATE_ALL_L1_TLBS (1 << 28) +# define RS600_INVALIDATE_L2_CACHE (1 << 29) +#define RS600_MC_PT0_CONTEXT0_CNTL 0x102 +# define RS600_ENABLE_PAGE_TABLE (1 << 0) +# define RS600_PAGE_TABLE_TYPE_FLAT (0 << 1) +#define RS600_MC_PT0_SYSTEM_APERTURE_LOW_ADDR 0x112 +#define RS600_MC_PT0_SYSTEM_APERTURE_HIGH_ADDR 0x114 +#define RS600_MC_PT0_CONTEXT0_DEFAULT_READ_ADDR 0x11c +#define RS600_MC_PT0_CONTEXT0_FLAT_BASE_ADDR 0x12c +#define RS600_MC_PT0_CONTEXT0_FLAT_START_ADDR 0x13c +#define RS600_MC_PT0_CONTEXT0_FLAT_END_ADDR 0x14c +#define RS600_MC_PT0_CLIENT0_CNTL 0x16c +# define RS600_ENABLE_TRANSLATION_MODE_OVERRIDE (1 << 0) +# define RS600_TRANSLATION_MODE_OVERRIDE (1 << 1) +# define RS600_SYSTEM_ACCESS_MODE_MASK (3 << 8) +# define RS600_SYSTEM_ACCESS_MODE_PA_ONLY (0 << 8) +# define RS600_SYSTEM_ACCESS_MODE_USE_SYS_MAP (1 << 8) +# define RS600_SYSTEM_ACCESS_MODE_IN_SYS (2 << 8) +# define RS600_SYSTEM_ACCESS_MODE_NOT_IN_SYS (3 << 8) +# define RS600_SYSTEM_APERTURE_UNMAPPED_ACCESS_PASSTHROUGH (0 << 10) +# define RS600_SYSTEM_APERTURE_UNMAPPED_ACCESS_DEFAULT_PAGE (1 << 10) +# define RS600_EFFECTIVE_L1_CACHE_SIZE(x) ((x) << 11) +# define RS600_ENABLE_FRAGMENT_PROCESSING (1 << 14) +# define RS600_EFFECTIVE_L1_QUEUE_SIZE(x) ((x) << 15) +# define RS600_INVALIDATE_L1_TLB (1 << 20) +/* rs600/rs690/rs740 */ +# define RS600_BUS_MASTER_DIS (1 << 14) +# define RS600_MSI_REARM (1 << 20) +/* see RS400_MSI_REARM in AIC_CNTL for rs480 */ + + + +#define RV515_MC_FB_LOCATION 0x01 +#define RV515_MC_FB_START_MASK 0x0000FFFF +#define RV515_MC_FB_START_SHIFT 0 +#define RV515_MC_FB_TOP_MASK 0xFFFF0000 +#define RV515_MC_FB_TOP_SHIFT 16 +#define RV515_MC_AGP_LOCATION 0x02 +#define RV515_MC_AGP_START_MASK 0x0000FFFF +#define RV515_MC_AGP_START_SHIFT 0 +#define RV515_MC_AGP_TOP_MASK 0xFFFF0000 +#define RV515_MC_AGP_TOP_SHIFT 16 +#define RV515_MC_AGP_BASE 0x03 +#define RV515_MC_AGP_BASE_2 0x04 + +#define R520_MC_FB_LOCATION 0x04 +#define R520_MC_FB_START_MASK 0x0000FFFF +#define R520_MC_FB_START_SHIFT 0 +#define R520_MC_FB_TOP_MASK 0xFFFF0000 +#define R520_MC_FB_TOP_SHIFT 16 +#define R520_MC_AGP_LOCATION 0x05 +#define R520_MC_AGP_START_MASK 0x0000FFFF +#define R520_MC_AGP_START_SHIFT 0 +#define R520_MC_AGP_TOP_MASK 0xFFFF0000 +#define R520_MC_AGP_TOP_SHIFT 16 +#define R520_MC_AGP_BASE 0x06 +#define R520_MC_AGP_BASE_2 0x07 + + +#define AVIVO_MC_INDEX 0x0070 +#define R520_MC_STATUS 0x00 +#define R520_MC_STATUS_IDLE (1<<1) +#define RV515_MC_STATUS 0x08 +#define RV515_MC_STATUS_IDLE (1<<4) +#define RV515_MC_INIT_MISC_LAT_TIMER 0x09 +#define AVIVO_MC_DATA 0x0074 + +#define R520_MC_IND_INDEX 0x70 +#define R520_MC_IND_WR_EN (1 << 24) +#define R520_MC_IND_DATA 0x74 + +#define RV515_MC_CNTL 0x5 +# define RV515_MEM_NUM_CHANNELS_MASK 0x3 +#define R520_MC_CNTL0 0x8 +# define R520_MEM_NUM_CHANNELS_MASK (0x3 << 24) +# define R520_MEM_NUM_CHANNELS_SHIFT 24 +# define R520_MC_CHANNEL_SIZE (1 << 23) + +#define AVIVO_CP_DYN_CNTL 0x000f /* PLL */ +# define AVIVO_CP_FORCEON (1 << 0) +#define AVIVO_E2_DYN_CNTL 0x0011 /* PLL */ +# define AVIVO_E2_FORCEON (1 << 0) +#define AVIVO_IDCT_DYN_CNTL 0x0013 /* PLL */ +# define AVIVO_IDCT_FORCEON (1 << 0) + +#define AVIVO_HDP_FB_LOCATION 0x134 + +#define AVIVO_VGA_RENDER_CONTROL 0x0300 +# define AVIVO_VGA_VSTATUS_CNTL_MASK (3 << 16) +#define AVIVO_D1VGA_CONTROL 0x0330 +# define AVIVO_DVGA_CONTROL_MODE_ENABLE (1<<0) +# define AVIVO_DVGA_CONTROL_TIMING_SELECT (1<<8) +# define AVIVO_DVGA_CONTROL_SYNC_POLARITY_SELECT (1<<9) +# define AVIVO_DVGA_CONTROL_OVERSCAN_TIMING_SELECT (1<<10) +# define AVIVO_DVGA_CONTROL_OVERSCAN_COLOR_EN (1<<16) +# define AVIVO_DVGA_CONTROL_ROTATE (1<<24) +#define AVIVO_D2VGA_CONTROL 0x0338 + +#define AVIVO_EXT1_PPLL_REF_DIV_SRC 0x400 +#define AVIVO_EXT1_PPLL_REF_DIV 0x404 +#define AVIVO_EXT1_PPLL_UPDATE_LOCK 0x408 +#define AVIVO_EXT1_PPLL_UPDATE_CNTL 0x40c + +#define AVIVO_EXT2_PPLL_REF_DIV_SRC 0x410 +#define AVIVO_EXT2_PPLL_REF_DIV 0x414 +#define AVIVO_EXT2_PPLL_UPDATE_LOCK 0x418 +#define AVIVO_EXT2_PPLL_UPDATE_CNTL 0x41c + +#define AVIVO_EXT1_PPLL_FB_DIV 0x430 +#define AVIVO_EXT2_PPLL_FB_DIV 0x434 + +#define AVIVO_EXT1_PPLL_POST_DIV_SRC 0x438 +#define AVIVO_EXT1_PPLL_POST_DIV 0x43c + +#define AVIVO_EXT2_PPLL_POST_DIV_SRC 0x440 +#define AVIVO_EXT2_PPLL_POST_DIV 0x444 + +#define AVIVO_EXT1_PPLL_CNTL 0x448 +#define AVIVO_EXT2_PPLL_CNTL 0x44c + +#define AVIVO_P1PLL_CNTL 0x450 +#define AVIVO_P2PLL_CNTL 0x454 +#define AVIVO_P1PLL_INT_SS_CNTL 0x458 +#define AVIVO_P2PLL_INT_SS_CNTL 0x45c +#define AVIVO_P1PLL_TMDSA_CNTL 0x460 +#define AVIVO_P2PLL_LVTMA_CNTL 0x464 + +#define AVIVO_PCLK_CRTC1_CNTL 0x480 +#define AVIVO_PCLK_CRTC2_CNTL 0x484 + +#define AVIVO_D1CRTC_H_TOTAL 0x6000 +#define AVIVO_D1CRTC_H_BLANK_START_END 0x6004 +#define AVIVO_D1CRTC_H_SYNC_A 0x6008 +#define AVIVO_D1CRTC_H_SYNC_A_CNTL 0x600c +#define AVIVO_D1CRTC_H_SYNC_B 0x6010 +#define AVIVO_D1CRTC_H_SYNC_B_CNTL 0x6014 + +#define AVIVO_D1CRTC_V_TOTAL 0x6020 +#define AVIVO_D1CRTC_V_BLANK_START_END 0x6024 +#define AVIVO_D1CRTC_V_SYNC_A 0x6028 +#define AVIVO_D1CRTC_V_SYNC_A_CNTL 0x602c +#define AVIVO_D1CRTC_V_SYNC_B 0x6030 +#define AVIVO_D1CRTC_V_SYNC_B_CNTL 0x6034 + +#define AVIVO_D1CRTC_CONTROL 0x6080 +# define AVIVO_CRTC_EN (1 << 0) +#define AVIVO_D1CRTC_BLANK_CONTROL 0x6084 +#define AVIVO_D1CRTC_INTERLACE_CONTROL 0x6088 +#define AVIVO_D1CRTC_INTERLACE_STATUS 0x608c +#define AVIVO_D1CRTC_STEREO_CONTROL 0x60c4 + +/* master controls */ +#define AVIVO_DC_CRTC_MASTER_EN 0x60f8 +#define AVIVO_DC_CRTC_TV_CONTROL 0x60fc + +#define AVIVO_D1GRPH_ENABLE 0x6100 +#define AVIVO_D1GRPH_CONTROL 0x6104 +# define AVIVO_D1GRPH_CONTROL_DEPTH_8BPP (0 << 0) +# define AVIVO_D1GRPH_CONTROL_DEPTH_16BPP (1 << 0) +# define AVIVO_D1GRPH_CONTROL_DEPTH_32BPP (2 << 0) +# define AVIVO_D1GRPH_CONTROL_DEPTH_64BPP (3 << 0) + +# define AVIVO_D1GRPH_CONTROL_8BPP_INDEXED (0 << 8) + +# define AVIVO_D1GRPH_CONTROL_16BPP_ARGB1555 (0 << 8) +# define AVIVO_D1GRPH_CONTROL_16BPP_RGB565 (1 << 8) +# define AVIVO_D1GRPH_CONTROL_16BPP_ARGB4444 (2 << 8) +# define AVIVO_D1GRPH_CONTROL_16BPP_AI88 (3 << 8) +# define AVIVO_D1GRPH_CONTROL_16BPP_MONO16 (4 << 8) + +# define AVIVO_D1GRPH_CONTROL_32BPP_ARGB8888 (0 << 8) +# define AVIVO_D1GRPH_CONTROL_32BPP_ARGB2101010 (1 << 8) +# define AVIVO_D1GRPH_CONTROL_32BPP_DIGITAL (2 << 8) +# define AVIVO_D1GRPH_CONTROL_32BPP_8B_ARGB2101010 (3 << 8) + + +# define AVIVO_D1GRPH_CONTROL_64BPP_ARGB16161616 (0 << 8) + +# define AVIVO_D1GRPH_SWAP_RB (1 << 16) +# define AVIVO_D1GRPH_TILED (1 << 20) +# define AVIVO_D1GRPH_MACRO_ADDRESS_MODE (1 << 21) + +#define AVIVO_D1GRPH_LUT_SEL 0x6108 +#define AVIVO_D1GRPH_PRIMARY_SURFACE_ADDRESS 0x6110 +#define AVIVO_D1GRPH_SECONDARY_SURFACE_ADDRESS 0x6118 +#define AVIVO_D1GRPH_PITCH 0x6120 +#define AVIVO_D1GRPH_SURFACE_OFFSET_X 0x6124 +#define AVIVO_D1GRPH_SURFACE_OFFSET_Y 0x6128 +#define AVIVO_D1GRPH_X_START 0x612c +#define AVIVO_D1GRPH_Y_START 0x6130 +#define AVIVO_D1GRPH_X_END 0x6134 +#define AVIVO_D1GRPH_Y_END 0x6138 +#define AVIVO_D1GRPH_UPDATE 0x6144 +# define AVIVO_D1GRPH_UPDATE_LOCK (1 << 16) +#define AVIVO_D1GRPH_FLIP_CONTROL 0x6148 + +#define AVIVO_D1CUR_CONTROL 0x6400 +# define AVIVO_D1CURSOR_EN (1 << 0) +# define AVIVO_D1CURSOR_MODE_SHIFT 8 +# define AVIVO_D1CURSOR_MODE_MASK (3 << 8) +# define AVIVO_D1CURSOR_MODE_24BPP 2 +#define AVIVO_D1CUR_SURFACE_ADDRESS 0x6408 +#define AVIVO_D1CUR_SIZE 0x6410 +#define AVIVO_D1CUR_POSITION 0x6414 +#define AVIVO_D1CUR_HOT_SPOT 0x6418 +#define AVIVO_D1CUR_UPDATE 0x6424 +# define AVIVO_D1CURSOR_UPDATE_LOCK (1 << 16) + +#define AVIVO_DC_LUT_RW_SELECT 0x6480 +#define AVIVO_DC_LUT_RW_MODE 0x6484 +#define AVIVO_DC_LUT_RW_INDEX 0x6488 +#define AVIVO_DC_LUT_SEQ_COLOR 0x648c +#define AVIVO_DC_LUT_PWL_DATA 0x6490 +#define AVIVO_DC_LUT_30_COLOR 0x6494 +#define AVIVO_DC_LUT_READ_PIPE_SELECT 0x6498 +#define AVIVO_DC_LUT_WRITE_EN_MASK 0x649c +#define AVIVO_DC_LUT_AUTOFILL 0x64a0 + +#define AVIVO_DC_LUTA_CONTROL 0x64c0 +#define AVIVO_DC_LUTA_BLACK_OFFSET_BLUE 0x64c4 +#define AVIVO_DC_LUTA_BLACK_OFFSET_GREEN 0x64c8 +#define AVIVO_DC_LUTA_BLACK_OFFSET_RED 0x64cc +#define AVIVO_DC_LUTA_WHITE_OFFSET_BLUE 0x64d0 +#define AVIVO_DC_LUTA_WHITE_OFFSET_GREEN 0x64d4 +#define AVIVO_DC_LUTA_WHITE_OFFSET_RED 0x64d8 + +#define AVIVO_DC_LB_MEMORY_SPLIT 0x6520 +# define AVIVO_DC_LB_MEMORY_SPLIT_MASK 0x3 +# define AVIVO_DC_LB_MEMORY_SPLIT_SHIFT 0 +# define AVIVO_DC_LB_MEMORY_SPLIT_D1HALF_D2HALF 0 +# define AVIVO_DC_LB_MEMORY_SPLIT_D1_3Q_D2_1Q 1 +# define AVIVO_DC_LB_MEMORY_SPLIT_D1_ONLY 2 +# define AVIVO_DC_LB_MEMORY_SPLIT_D1_1Q_D2_3Q 3 +# define AVIVO_DC_LB_MEMORY_SPLIT_SHIFT_MODE (1 << 2) +# define AVIVO_DC_LB_DISP1_END_ADR_SHIFT 4 +# define AVIVO_DC_LB_DISP1_END_ADR_MASK 0x7ff + +#define R500_DxMODE_INT_MASK 0x6540 +#define R500_D1MODE_INT_MASK (1<<0) +#define R500_D2MODE_INT_MASK (1<<8) + +#define AVIVO_D1MODE_DATA_FORMAT 0x6528 +# define AVIVO_D1MODE_INTERLEAVE_EN (1 << 0) +#define AVIVO_D1MODE_DESKTOP_HEIGHT 0x652C +#define AVIVO_D1MODE_VIEWPORT_START 0x6580 +#define AVIVO_D1MODE_VIEWPORT_SIZE 0x6584 +#define AVIVO_D1MODE_EXT_OVERSCAN_LEFT_RIGHT 0x6588 +#define AVIVO_D1MODE_EXT_OVERSCAN_TOP_BOTTOM 0x658c + +#define AVIVO_D1SCL_SCALER_ENABLE 0x6590 +#define AVIVO_D1SCL_SCALER_TAP_CONTROL 0x6594 +#define AVIVO_D1SCL_UPDATE 0x65cc +# define AVIVO_D1SCL_UPDATE_LOCK (1 << 16) + +/* second crtc */ +#define AVIVO_D2CRTC_H_TOTAL 0x6800 +#define AVIVO_D2CRTC_H_BLANK_START_END 0x6804 +#define AVIVO_D2CRTC_H_SYNC_A 0x6808 +#define AVIVO_D2CRTC_H_SYNC_A_CNTL 0x680c +#define AVIVO_D2CRTC_H_SYNC_B 0x6810 +#define AVIVO_D2CRTC_H_SYNC_B_CNTL 0x6814 + +#define AVIVO_D2CRTC_V_TOTAL 0x6820 +#define AVIVO_D2CRTC_V_BLANK_START_END 0x6824 +#define AVIVO_D2CRTC_V_SYNC_A 0x6828 +#define AVIVO_D2CRTC_V_SYNC_A_CNTL 0x682c +#define AVIVO_D2CRTC_V_SYNC_B 0x6830 +#define AVIVO_D2CRTC_V_SYNC_B_CNTL 0x6834 + +#define AVIVO_D2CRTC_CONTROL 0x6880 +#define AVIVO_D2CRTC_BLANK_CONTROL 0x6884 +#define AVIVO_D2CRTC_INTERLACE_CONTROL 0x6888 +#define AVIVO_D2CRTC_INTERLACE_STATUS 0x688c +#define AVIVO_D2CRTC_STEREO_CONTROL 0x68c4 + +#define AVIVO_D2GRPH_ENABLE 0x6900 +#define AVIVO_D2GRPH_CONTROL 0x6904 +#define AVIVO_D2GRPH_LUT_SEL 0x6908 +#define AVIVO_D2GRPH_PRIMARY_SURFACE_ADDRESS 0x6910 +#define AVIVO_D2GRPH_SECONDARY_SURFACE_ADDRESS 0x6918 +#define AVIVO_D2GRPH_PITCH 0x6920 +#define AVIVO_D2GRPH_SURFACE_OFFSET_X 0x6924 +#define AVIVO_D2GRPH_SURFACE_OFFSET_Y 0x6928 +#define AVIVO_D2GRPH_X_START 0x692c +#define AVIVO_D2GRPH_Y_START 0x6930 +#define AVIVO_D2GRPH_X_END 0x6934 +#define AVIVO_D2GRPH_Y_END 0x6938 +#define AVIVO_D2GRPH_UPDATE 0x6944 +#define AVIVO_D2GRPH_FLIP_CONTROL 0x6948 + +#define AVIVO_D2CUR_CONTROL 0x6c00 +#define AVIVO_D2CUR_SURFACE_ADDRESS 0x6c08 +#define AVIVO_D2CUR_SIZE 0x6c10 +#define AVIVO_D2CUR_POSITION 0x6c14 + +#define AVIVO_D2MODE_VIEWPORT_START 0x6d80 +#define AVIVO_D2MODE_VIEWPORT_SIZE 0x6d84 +#define AVIVO_D2MODE_EXT_OVERSCAN_LEFT_RIGHT 0x6d88 +#define AVIVO_D2MODE_EXT_OVERSCAN_TOP_BOTTOM 0x6d8c + +#define AVIVO_D2SCL_SCALER_ENABLE 0x6d90 +#define AVIVO_D2SCL_SCALER_TAP_CONTROL 0x6d94 + +#define AVIVO_DDIA_BIT_DEPTH_CONTROL 0x7214 + +#define AVIVO_DACA_ENABLE 0x7800 +# define AVIVO_DAC_ENABLE (1 << 0) +#define AVIVO_DACA_SOURCE_SELECT 0x7804 +# define AVIVO_DAC_SOURCE_CRTC1 (0 << 0) +# define AVIVO_DAC_SOURCE_CRTC2 (1 << 0) +# define AVIVO_DAC_SOURCE_TV (2 << 0) + +#define AVIVO_DACA_FORCE_OUTPUT_CNTL 0x783c +# define AVIVO_DACA_FORCE_OUTPUT_CNTL_FORCE_DATA_EN (1 << 0) +# define AVIVO_DACA_FORCE_OUTPUT_CNTL_DATA_SEL_SHIFT (8) +# define AVIVO_DACA_FORCE_OUTPUT_CNTL_DATA_SEL_BLUE (1 << 0) +# define AVIVO_DACA_FORCE_OUTPUT_CNTL_DATA_SEL_GREEN (1 << 1) +# define AVIVO_DACA_FORCE_OUTPUT_CNTL_DATA_SEL_RED (1 << 2) +# define AVIVO_DACA_FORCE_OUTPUT_CNTL_DATA_ON_BLANKB_ONLY (1 << 24) +#define AVIVO_DACA_POWERDOWN 0x7850 +# define AVIVO_DACA_POWERDOWN_POWERDOWN (1 << 0) +# define AVIVO_DACA_POWERDOWN_BLUE (1 << 8) +# define AVIVO_DACA_POWERDOWN_GREEN (1 << 16) +# define AVIVO_DACA_POWERDOWN_RED (1 << 24) + +#define AVIVO_DACB_ENABLE 0x7a00 +#define AVIVO_DACB_SOURCE_SELECT 0x7a04 +#define AVIVO_DACB_FORCE_OUTPUT_CNTL 0x7a3c +# define AVIVO_DACB_FORCE_OUTPUT_CNTL_FORCE_DATA_EN (1 << 0) +# define AVIVO_DACB_FORCE_OUTPUT_CNTL_DATA_SEL_SHIFT (8) +# define AVIVO_DACB_FORCE_OUTPUT_CNTL_DATA_SEL_BLUE (1 << 0) +# define AVIVO_DACB_FORCE_OUTPUT_CNTL_DATA_SEL_GREEN (1 << 1) +# define AVIVO_DACB_FORCE_OUTPUT_CNTL_DATA_SEL_RED (1 << 2) +# define AVIVO_DACB_FORCE_OUTPUT_CNTL_DATA_ON_BLANKB_ONLY (1 << 24) +#define AVIVO_DACB_POWERDOWN 0x7a50 +# define AVIVO_DACB_POWERDOWN_POWERDOWN (1 << 0) +# define AVIVO_DACB_POWERDOWN_BLUE (1 << 8) +# define AVIVO_DACB_POWERDOWN_GREEN (1 << 16) +# define AVIVO_DACB_POWERDOWN_RED + +#define AVIVO_TMDSA_CNTL 0x7880 +# define AVIVO_TMDSA_CNTL_ENABLE (1 << 0) +# define AVIVO_TMDSA_CNTL_HPD_MASK (1 << 4) +# define AVIVO_TMDSA_CNTL_HPD_SELECT (1 << 8) +# define AVIVO_TMDSA_CNTL_SYNC_PHASE (1 << 12) +# define AVIVO_TMDSA_CNTL_PIXEL_ENCODING (1 << 16) +# define AVIVO_TMDSA_CNTL_DUAL_LINK_ENABLE (1 << 24) +# define AVIVO_TMDSA_CNTL_SWAP (1 << 28) +#define AVIVO_TMDSA_SOURCE_SELECT 0x7884 +/* 78a8 appears to be some kind of (reasonably tolerant) clock? + * 78d0 definitely hits the transmitter, definitely clock. */ +/* MYSTERY1 This appears to control dithering? */ +#define AVIVO_TMDSA_BIT_DEPTH_CONTROL 0x7894 +# define AVIVO_TMDS_BIT_DEPTH_CONTROL_TRUNCATE_EN (1 << 0) +# define AVIVO_TMDS_BIT_DEPTH_CONTROL_TRUNCATE_DEPTH (1 << 4) +# define AVIVO_TMDS_BIT_DEPTH_CONTROL_SPATIAL_DITHER_EN (1 << 8) +# define AVIVO_TMDS_BIT_DEPTH_CONTROL_SPATIAL_DITHER_DEPTH (1 << 12) +# define AVIVO_TMDS_BIT_DEPTH_CONTROL_TEMPORAL_DITHER_EN (1 << 16) +# define AVIVO_TMDS_BIT_DEPTH_CONTROL_TEMPORAL_DITHER_DEPTH (1 << 20) +# define AVIVO_TMDS_BIT_DEPTH_CONTROL_TEMPORAL_LEVEL (1 << 24) +# define AVIVO_TMDS_BIT_DEPTH_CONTROL_TEMPORAL_DITHER_RESET (1 << 26) +#define AVIVO_TMDSA_DCBALANCER_CONTROL 0x78d0 +# define AVIVO_TMDSA_DCBALANCER_CONTROL_EN (1 << 0) +# define AVIVO_TMDSA_DCBALANCER_CONTROL_TEST_EN (1 << 8) +# define AVIVO_TMDSA_DCBALANCER_CONTROL_TEST_IN_SHIFT (16) +# define AVIVO_TMDSA_DCBALANCER_CONTROL_FORCE (1 << 24) +#define AVIVO_TMDSA_DATA_SYNCHRONIZATION 0x78d8 +# define AVIVO_TMDSA_DATA_SYNCHRONIZATION_DSYNSEL (1 << 0) +# define AVIVO_TMDSA_DATA_SYNCHRONIZATION_PFREQCHG (1 << 8) +#define AVIVO_TMDSA_CLOCK_ENABLE 0x7900 +#define AVIVO_TMDSA_TRANSMITTER_ENABLE 0x7904 +# define AVIVO_TMDSA_TRANSMITTER_ENABLE_TX0_ENABLE (1 << 0) +# define AVIVO_TMDSA_TRANSMITTER_ENABLE_LNKC0EN (1 << 1) +# define AVIVO_TMDSA_TRANSMITTER_ENABLE_LNKD00EN (1 << 2) +# define AVIVO_TMDSA_TRANSMITTER_ENABLE_LNKD01EN (1 << 3) +# define AVIVO_TMDSA_TRANSMITTER_ENABLE_LNKD02EN (1 << 4) +# define AVIVO_TMDSA_TRANSMITTER_ENABLE_TX1_ENABLE (1 << 8) +# define AVIVO_TMDSA_TRANSMITTER_ENABLE_LNKD10EN (1 << 10) +# define AVIVO_TMDSA_TRANSMITTER_ENABLE_LNKD11EN (1 << 11) +# define AVIVO_TMDSA_TRANSMITTER_ENABLE_LNKD12EN (1 << 12) +# define AVIVO_TMDSA_TRANSMITTER_ENABLE_TX_ENABLE_HPD_MASK (1 << 16) +# define AVIVO_TMDSA_TRANSMITTER_ENABLE_LNKCEN_HPD_MASK (1 << 17) +# define AVIVO_TMDSA_TRANSMITTER_ENABLE_LNKDEN_HPD_MASK (1 << 18) + +#define AVIVO_TMDSA_TRANSMITTER_CONTROL 0x7910 +# define AVIVO_TMDSA_TRANSMITTER_CONTROL_PLL_ENABLE (1 << 0) +# define AVIVO_TMDSA_TRANSMITTER_CONTROL_PLL_RESET (1 << 1) +# define AVIVO_TMDSA_TRANSMITTER_CONTROL_PLL_HPD_MASK_SHIFT (2) +# define AVIVO_TMDSA_TRANSMITTER_CONTROL_IDSCKSEL (1 << 4) +# define AVIVO_TMDSA_TRANSMITTER_CONTROL_BGSLEEP (1 << 5) +# define AVIVO_TMDSA_TRANSMITTER_CONTROL_PLL_PWRUP_SEQ_EN (1 << 6) +# define AVIVO_TMDSA_TRANSMITTER_CONTROL_TMCLK (1 << 8) +# define AVIVO_TMDSA_TRANSMITTER_CONTROL_TMCLK_FROM_PADS (1 << 13) +# define AVIVO_TMDSA_TRANSMITTER_CONTROL_TDCLK (1 << 14) +# define AVIVO_TMDSA_TRANSMITTER_CONTROL_TDCLK_FROM_PADS (1 << 15) +# define AVIVO_TMDSA_TRANSMITTER_CONTROL_CLK_PATTERN_SHIFT (16) +# define AVIVO_TMDSA_TRANSMITTER_CONTROL_BYPASS_PLL (1 << 28) +# define AVIVO_TMDSA_TRANSMITTER_CONTROL_USE_CLK_DATA (1 << 29) +# define AVIVO_TMDSA_TRANSMITTER_CONTROL_INPUT_TEST_CLK_SEL (1 << 31) + +#define AVIVO_LVTMA_CNTL 0x7a80 +# define AVIVO_LVTMA_CNTL_ENABLE (1 << 0) +# define AVIVO_LVTMA_CNTL_HPD_MASK (1 << 4) +# define AVIVO_LVTMA_CNTL_HPD_SELECT (1 << 8) +# define AVIVO_LVTMA_CNTL_SYNC_PHASE (1 << 12) +# define AVIVO_LVTMA_CNTL_PIXEL_ENCODING (1 << 16) +# define AVIVO_LVTMA_CNTL_DUAL_LINK_ENABLE (1 << 24) +# define AVIVO_LVTMA_CNTL_SWAP (1 << 28) +#define AVIVO_LVTMA_SOURCE_SELECT 0x7a84 +#define AVIVO_LVTMA_COLOR_FORMAT 0x7a88 +#define AVIVO_LVTMA_BIT_DEPTH_CONTROL 0x7a94 +# define AVIVO_LVTMA_BIT_DEPTH_CONTROL_TRUNCATE_EN (1 << 0) +# define AVIVO_LVTMA_BIT_DEPTH_CONTROL_TRUNCATE_DEPTH (1 << 4) +# define AVIVO_LVTMA_BIT_DEPTH_CONTROL_SPATIAL_DITHER_EN (1 << 8) +# define AVIVO_LVTMA_BIT_DEPTH_CONTROL_SPATIAL_DITHER_DEPTH (1 << 12) +# define AVIVO_LVTMA_BIT_DEPTH_CONTROL_TEMPORAL_DITHER_EN (1 << 16) +# define AVIVO_LVTMA_BIT_DEPTH_CONTROL_TEMPORAL_DITHER_DEPTH (1 << 20) +# define AVIVO_LVTMA_BIT_DEPTH_CONTROL_TEMPORAL_LEVEL (1 << 24) +# define AVIVO_LVTMA_BIT_DEPTH_CONTROL_TEMPORAL_DITHER_RESET (1 << 26) + + + +#define AVIVO_LVTMA_DCBALANCER_CONTROL 0x7ad0 +# define AVIVO_LVTMA_DCBALANCER_CONTROL_EN (1 << 0) +# define AVIVO_LVTMA_DCBALANCER_CONTROL_TEST_EN (1 << 8) +# define AVIVO_LVTMA_DCBALANCER_CONTROL_TEST_IN_SHIFT (16) +# define AVIVO_LVTMA_DCBALANCER_CONTROL_FORCE (1 << 24) + +#define AVIVO_LVTMA_DATA_SYNCHRONIZATION 0x78d8 +# define AVIVO_LVTMA_DATA_SYNCHRONIZATION_DSYNSEL (1 << 0) +# define AVIVO_LVTMA_DATA_SYNCHRONIZATION_PFREQCHG (1 << 8) +#define R500_LVTMA_CLOCK_ENABLE 0x7b00 +#define R600_LVTMA_CLOCK_ENABLE 0x7b04 + +#define R500_LVTMA_TRANSMITTER_ENABLE 0x7b04 +#define R600_LVTMA_TRANSMITTER_ENABLE 0x7b08 +# define AVIVO_LVTMA_TRANSMITTER_ENABLE_LNKC0EN (1 << 1) +# define AVIVO_LVTMA_TRANSMITTER_ENABLE_LNKD00EN (1 << 2) +# define AVIVO_LVTMA_TRANSMITTER_ENABLE_LNKD01EN (1 << 3) +# define AVIVO_LVTMA_TRANSMITTER_ENABLE_LNKD02EN (1 << 4) +# define AVIVO_LVTMA_TRANSMITTER_ENABLE_LNKD03EN (1 << 5) +# define AVIVO_LVTMA_TRANSMITTER_ENABLE_LNKC1EN (1 << 9) +# define AVIVO_LVTMA_TRANSMITTER_ENABLE_LNKD10EN (1 << 10) +# define AVIVO_LVTMA_TRANSMITTER_ENABLE_LNKD11EN (1 << 11) +# define AVIVO_LVTMA_TRANSMITTER_ENABLE_LNKD12EN (1 << 12) +# define AVIVO_LVTMA_TRANSMITTER_ENABLE_LNKCEN_HPD_MASK (1 << 17) +# define AVIVO_LVTMA_TRANSMITTER_ENABLE_LNKDEN_HPD_MASK (1 << 18) + +#define R500_LVTMA_TRANSMITTER_CONTROL 0x7b10 +#define R600_LVTMA_TRANSMITTER_CONTROL 0x7b14 +# define AVIVO_LVTMA_TRANSMITTER_CONTROL_PLL_ENABLE (1 << 0) +# define AVIVO_LVTMA_TRANSMITTER_CONTROL_PLL_RESET (1 << 1) +# define AVIVO_LVTMA_TRANSMITTER_CONTROL_PLL_HPD_MASK_SHIFT (2) +# define AVIVO_LVTMA_TRANSMITTER_CONTROL_IDSCKSEL (1 << 4) +# define AVIVO_LVTMA_TRANSMITTER_CONTROL_BGSLEEP (1 << 5) +# define AVIVO_LVTMA_TRANSMITTER_CONTROL_PLL_PWRUP_SEQ_EN (1 << 6) +# define AVIVO_LVTMA_TRANSMITTER_CONTROL_TMCLK (1 << 8) +# define AVIVO_LVTMA_TRANSMITTER_CONTROL_TMCLK_FROM_PADS (1 << 13) +# define AVIVO_LVTMA_TRANSMITTER_CONTROL_TDCLK (1 << 14) +# define AVIVO_LVTMA_TRANSMITTER_CONTROL_TDCLK_FROM_PADS (1 << 15) +# define AVIVO_LVTMA_TRANSMITTER_CONTROL_CLK_PATTERN_SHIFT (16) +# define AVIVO_LVTMA_TRANSMITTER_CONTROL_BYPASS_PLL (1 << 28) +# define AVIVO_LVTMA_TRANSMITTER_CONTROL_USE_CLK_DATA (1 << 29) +# define AVIVO_LVTMA_TRANSMITTER_CONTROL_INPUT_TEST_CLK_SEL (1 << 31) + +#define R500_LVTMA_PWRSEQ_CNTL 0x7af0 +#define R600_LVTMA_PWRSEQ_CNTL 0x7af4 +# define AVIVO_LVTMA_PWRSEQ_EN (1 << 0) +# define AVIVO_LVTMA_PWRSEQ_PLL_ENABLE_MASK (1 << 2) +# define AVIVO_LVTMA_PWRSEQ_PLL_RESET_MASK (1 << 3) +# define AVIVO_LVTMA_PWRSEQ_TARGET_STATE (1 << 4) +# define AVIVO_LVTMA_SYNCEN (1 << 8) +# define AVIVO_LVTMA_SYNCEN_OVRD (1 << 9) +# define AVIVO_LVTMA_SYNCEN_POL (1 << 10) +# define AVIVO_LVTMA_DIGON (1 << 16) +# define AVIVO_LVTMA_DIGON_OVRD (1 << 17) +# define AVIVO_LVTMA_DIGON_POL (1 << 18) +# define AVIVO_LVTMA_BLON (1 << 24) +# define AVIVO_LVTMA_BLON_OVRD (1 << 25) +# define AVIVO_LVTMA_BLON_POL (1 << 26) + +#define R500_LVTMA_PWRSEQ_STATE 0x7af4 +#define R600_LVTMA_PWRSEQ_STATE 0x7af8 +# define AVIVO_LVTMA_PWRSEQ_STATE_TARGET_STATE_R (1 << 0) +# define AVIVO_LVTMA_PWRSEQ_STATE_DIGON (1 << 1) +# define AVIVO_LVTMA_PWRSEQ_STATE_SYNCEN (1 << 2) +# define AVIVO_LVTMA_PWRSEQ_STATE_BLON (1 << 3) +# define AVIVO_LVTMA_PWRSEQ_STATE_DONE (1 << 4) +# define AVIVO_LVTMA_PWRSEQ_STATE_STATUS_SHIFT (8) + +#define AVIVO_LVDS_BACKLIGHT_CNTL 0x7af8 +# define AVIVO_LVDS_BACKLIGHT_CNTL_EN (1 << 0) +# define AVIVO_LVDS_BACKLIGHT_LEVEL_MASK 0x0000ff00 +# define AVIVO_LVDS_BACKLIGHT_LEVEL_SHIFT 8 + +#define AVIVO_DVOA_BIT_DEPTH_CONTROL 0x7988 + +#define AVIVO_GPIO_0 0x7e30 +#define AVIVO_GPIO_1 0x7e40 +#define AVIVO_GPIO_2 0x7e50 +#define AVIVO_GPIO_3 0x7e60 + +#define AVIVO_DC_GPIO_HPD_Y 0x7e9c + +#define AVIVO_I2C_STATUS 0x7d30 +# define AVIVO_I2C_STATUS_DONE (1 << 0) +# define AVIVO_I2C_STATUS_NACK (1 << 1) +# define AVIVO_I2C_STATUS_HALT (1 << 2) +# define AVIVO_I2C_STATUS_GO (1 << 3) +# define AVIVO_I2C_STATUS_MASK 0x7 +/* If radeon_mm_i2c is to be believed, this is HALT, NACK, and maybe + * DONE? */ +# define AVIVO_I2C_STATUS_CMD_RESET 0x7 +# define AVIVO_I2C_STATUS_CMD_WAIT (1 << 3) +#define AVIVO_I2C_STOP 0x7d34 +#define AVIVO_I2C_START_CNTL 0x7d38 +# define AVIVO_I2C_START (1 << 8) +# define AVIVO_I2C_CONNECTOR0 (0 << 16) +# define AVIVO_I2C_CONNECTOR1 (1 << 16) +#define R520_I2C_START (1<<0) +#define R520_I2C_STOP (1<<1) +#define R520_I2C_RX (1<<2) +#define R520_I2C_EN (1<<8) +#define R520_I2C_DDC1 (0<<16) +#define R520_I2C_DDC2 (1<<16) +#define R520_I2C_DDC3 (2<<16) +#define R520_I2C_DDC_MASK (3<<16) +#define AVIVO_I2C_CONTROL2 0x7d3c +# define AVIVO_I2C_7D3C_SIZE_SHIFT 8 +# define AVIVO_I2C_7D3C_SIZE_MASK (0xf << 8) +#define AVIVO_I2C_CONTROL3 0x7d40 +/* Reading is done 4 bytes at a time: read the bottom 8 bits from + * 7d44, four times in a row. + * Writing is a little more complex. First write DATA with + * 0xnnnnnnzz, then 0xnnnnnnyy, where nnnnnn is some non-deterministic + * magic number, zz is, I think, the slave address, and yy is the byte + * you want to write. */ +#define AVIVO_I2C_DATA 0x7d44 +#define R520_I2C_ADDR_COUNT_MASK (0x7) +#define R520_I2C_DATA_COUNT_SHIFT (8) +#define R520_I2C_DATA_COUNT_MASK (0xF00) +#define AVIVO_I2C_CNTL 0x7d50 +# define AVIVO_I2C_EN (1 << 0) +# define AVIVO_I2C_RESET (1 << 8) + +#endif diff --git a/drivers/gpu/drm/radeon/r520.c b/drivers/gpu/drm/radeon/r520.c new file mode 100644 index 000000000000..570a244bd88b --- /dev/null +++ b/drivers/gpu/drm/radeon/r520.c @@ -0,0 +1,234 @@ +/* + * Copyright 2008 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * Copyright 2009 Jerome Glisse. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Dave Airlie + * Alex Deucher + * Jerome Glisse + */ +#include "drmP.h" +#include "radeon_reg.h" +#include "radeon.h" + +/* r520,rv530,rv560,rv570,r580 depends on : */ +void r100_hdp_reset(struct radeon_device *rdev); +int rv370_pcie_gart_enable(struct radeon_device *rdev); +void rv370_pcie_gart_disable(struct radeon_device *rdev); +void r420_pipes_init(struct radeon_device *rdev); +void rs600_mc_disable_clients(struct radeon_device *rdev); +void rs600_disable_vga(struct radeon_device *rdev); +int rv515_debugfs_pipes_info_init(struct radeon_device *rdev); +int rv515_debugfs_ga_info_init(struct radeon_device *rdev); + +/* This files gather functions specifics to: + * r520,rv530,rv560,rv570,r580 + * + * Some of these functions might be used by newer ASICs. + */ +void r520_gpu_init(struct radeon_device *rdev); +int r520_mc_wait_for_idle(struct radeon_device *rdev); + + +/* + * MC + */ +int r520_mc_init(struct radeon_device *rdev) +{ + uint32_t tmp; + int r; + + if (r100_debugfs_rbbm_init(rdev)) { + DRM_ERROR("Failed to register debugfs file for RBBM !\n"); + } + if (rv515_debugfs_pipes_info_init(rdev)) { + DRM_ERROR("Failed to register debugfs file for pipes !\n"); + } + if (rv515_debugfs_ga_info_init(rdev)) { + DRM_ERROR("Failed to register debugfs file for pipes !\n"); + } + + r520_gpu_init(rdev); + rv370_pcie_gart_disable(rdev); + + /* Setup GPU memory space */ + rdev->mc.vram_location = 0xFFFFFFFFUL; + rdev->mc.gtt_location = 0xFFFFFFFFUL; + if (rdev->flags & RADEON_IS_AGP) { + r = radeon_agp_init(rdev); + if (r) { + printk(KERN_WARNING "[drm] Disabling AGP\n"); + rdev->flags &= ~RADEON_IS_AGP; + rdev->mc.gtt_size = radeon_gart_size * 1024 * 1024; + } else { + rdev->mc.gtt_location = rdev->mc.agp_base; + } + } + r = radeon_mc_setup(rdev); + if (r) { + return r; + } + + /* Program GPU memory space */ + rs600_mc_disable_clients(rdev); + if (r520_mc_wait_for_idle(rdev)) { + printk(KERN_WARNING "Failed to wait MC idle while " + "programming pipes. Bad things might happen.\n"); + } + /* Write VRAM size in case we are limiting it */ + WREG32(RADEON_CONFIG_MEMSIZE, rdev->mc.vram_size); + tmp = rdev->mc.vram_location + rdev->mc.vram_size - 1; + tmp = REG_SET(R520_MC_FB_TOP, tmp >> 16); + tmp |= REG_SET(R520_MC_FB_START, rdev->mc.vram_location >> 16); + WREG32_MC(R520_MC_FB_LOCATION, tmp); + WREG32(RS690_HDP_FB_LOCATION, rdev->mc.vram_location >> 16); + WREG32(0x310, rdev->mc.vram_location); + if (rdev->flags & RADEON_IS_AGP) { + tmp = rdev->mc.gtt_location + rdev->mc.gtt_size - 1; + tmp = REG_SET(R520_MC_AGP_TOP, tmp >> 16); + tmp |= REG_SET(R520_MC_AGP_START, rdev->mc.gtt_location >> 16); + WREG32_MC(R520_MC_AGP_LOCATION, tmp); + WREG32_MC(R520_MC_AGP_BASE, rdev->mc.agp_base); + WREG32_MC(R520_MC_AGP_BASE_2, 0); + } else { + WREG32_MC(R520_MC_AGP_LOCATION, 0x0FFFFFFF); + WREG32_MC(R520_MC_AGP_BASE, 0); + WREG32_MC(R520_MC_AGP_BASE_2, 0); + } + return 0; +} + +void r520_mc_fini(struct radeon_device *rdev) +{ + rv370_pcie_gart_disable(rdev); + radeon_gart_table_vram_free(rdev); + radeon_gart_fini(rdev); +} + + +/* + * Global GPU functions + */ +void r520_errata(struct radeon_device *rdev) +{ + rdev->pll_errata = 0; +} + +int r520_mc_wait_for_idle(struct radeon_device *rdev) +{ + unsigned i; + uint32_t tmp; + + for (i = 0; i < rdev->usec_timeout; i++) { + /* read MC_STATUS */ + tmp = RREG32_MC(R520_MC_STATUS); + if (tmp & R520_MC_STATUS_IDLE) { + return 0; + } + DRM_UDELAY(1); + } + return -1; +} + +void r520_gpu_init(struct radeon_device *rdev) +{ + unsigned pipe_select_current, gb_pipe_select, tmp; + + r100_hdp_reset(rdev); + rs600_disable_vga(rdev); + /* + * DST_PIPE_CONFIG 0x170C + * GB_TILE_CONFIG 0x4018 + * GB_FIFO_SIZE 0x4024 + * GB_PIPE_SELECT 0x402C + * GB_PIPE_SELECT2 0x4124 + * Z_PIPE_SHIFT 0 + * Z_PIPE_MASK 0x000000003 + * GB_FIFO_SIZE2 0x4128 + * SC_SFIFO_SIZE_SHIFT 0 + * SC_SFIFO_SIZE_MASK 0x000000003 + * SC_MFIFO_SIZE_SHIFT 2 + * SC_MFIFO_SIZE_MASK 0x00000000C + * FG_SFIFO_SIZE_SHIFT 4 + * FG_SFIFO_SIZE_MASK 0x000000030 + * ZB_MFIFO_SIZE_SHIFT 6 + * ZB_MFIFO_SIZE_MASK 0x0000000C0 + * GA_ENHANCE 0x4274 + * SU_REG_DEST 0x42C8 + */ + /* workaround for RV530 */ + if (rdev->family == CHIP_RV530) { + WREG32(0x4124, 1); + WREG32(0x4128, 0xFF); + } + r420_pipes_init(rdev); + gb_pipe_select = RREG32(0x402C); + tmp = RREG32(0x170C); + pipe_select_current = (tmp >> 2) & 3; + tmp = (1 << pipe_select_current) | + (((gb_pipe_select >> 8) & 0xF) << 4); + WREG32_PLL(0x000D, tmp); + if (r520_mc_wait_for_idle(rdev)) { + printk(KERN_WARNING "Failed to wait MC idle while " + "programming pipes. Bad things might happen.\n"); + } +} + + +/* + * VRAM info + */ +static void r520_vram_get_type(struct radeon_device *rdev) +{ + uint32_t tmp; + + rdev->mc.vram_width = 128; + rdev->mc.vram_is_ddr = true; + tmp = RREG32_MC(R520_MC_CNTL0); + switch ((tmp & R520_MEM_NUM_CHANNELS_MASK) >> R520_MEM_NUM_CHANNELS_SHIFT) { + case 0: + rdev->mc.vram_width = 32; + break; + case 1: + rdev->mc.vram_width = 64; + break; + case 2: + rdev->mc.vram_width = 128; + break; + case 3: + rdev->mc.vram_width = 256; + break; + default: + rdev->mc.vram_width = 128; + break; + } + if (tmp & R520_MC_CHANNEL_SIZE) + rdev->mc.vram_width *= 2; +} + +void r520_vram_info(struct radeon_device *rdev) +{ + r520_vram_get_type(rdev); + rdev->mc.vram_size = RREG32(RADEON_CONFIG_MEMSIZE); + + rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0); + rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0); +} diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c new file mode 100644 index 000000000000..c45559fc97fd --- /dev/null +++ b/drivers/gpu/drm/radeon/r600.c @@ -0,0 +1,169 @@ +/* + * Copyright 2008 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * Copyright 2009 Jerome Glisse. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Dave Airlie + * Alex Deucher + * Jerome Glisse + */ +#include "drmP.h" +#include "radeon_reg.h" +#include "radeon.h" + +/* r600,rv610,rv630,rv620,rv635,rv670 depends on : */ +void rs600_mc_disable_clients(struct radeon_device *rdev); + +/* This files gather functions specifics to: + * r600,rv610,rv630,rv620,rv635,rv670 + * + * Some of these functions might be used by newer ASICs. + */ +int r600_mc_wait_for_idle(struct radeon_device *rdev); +void r600_gpu_init(struct radeon_device *rdev); + + +/* + * MC + */ +int r600_mc_init(struct radeon_device *rdev) +{ + uint32_t tmp; + + r600_gpu_init(rdev); + + /* setup the gart before changing location so we can ask to + * discard unmapped mc request + */ + /* FIXME: disable out of gart access */ + tmp = rdev->mc.gtt_location / 4096; + tmp = REG_SET(R600_LOGICAL_PAGE_NUMBER, tmp); + WREG32(R600_MC_VM_SYSTEM_APERTURE_LOW_ADDR, tmp); + tmp = (rdev->mc.gtt_location + rdev->mc.gtt_size) / 4096; + tmp = REG_SET(R600_LOGICAL_PAGE_NUMBER, tmp); + WREG32(R600_MC_VM_SYSTEM_APERTURE_HIGH_ADDR, tmp); + + rs600_mc_disable_clients(rdev); + if (r600_mc_wait_for_idle(rdev)) { + printk(KERN_WARNING "Failed to wait MC idle while " + "programming pipes. Bad things might happen.\n"); + } + + tmp = rdev->mc.vram_location + rdev->mc.vram_size - 1; + tmp = REG_SET(R600_MC_FB_TOP, tmp >> 24); + tmp |= REG_SET(R600_MC_FB_BASE, rdev->mc.vram_location >> 24); + WREG32(R600_MC_VM_FB_LOCATION, tmp); + tmp = rdev->mc.gtt_location + rdev->mc.gtt_size - 1; + tmp = REG_SET(R600_MC_AGP_TOP, tmp >> 22); + WREG32(R600_MC_VM_AGP_TOP, tmp); + tmp = REG_SET(R600_MC_AGP_BOT, rdev->mc.gtt_location >> 22); + WREG32(R600_MC_VM_AGP_BOT, tmp); + return 0; +} + +void r600_mc_fini(struct radeon_device *rdev) +{ + /* FIXME: implement */ +} + + +/* + * Global GPU functions + */ +void r600_errata(struct radeon_device *rdev) +{ + rdev->pll_errata = 0; +} + +int r600_mc_wait_for_idle(struct radeon_device *rdev) +{ + /* FIXME: implement */ + return 0; +} + +void r600_gpu_init(struct radeon_device *rdev) +{ + /* FIXME: implement */ +} + + +/* + * VRAM info + */ +void r600_vram_get_type(struct radeon_device *rdev) +{ + uint32_t tmp; + int chansize; + + rdev->mc.vram_width = 128; + rdev->mc.vram_is_ddr = true; + + tmp = RREG32(R600_RAMCFG); + if (tmp & R600_CHANSIZE_OVERRIDE) { + chansize = 16; + } else if (tmp & R600_CHANSIZE) { + chansize = 64; + } else { + chansize = 32; + } + if (rdev->family == CHIP_R600) { + rdev->mc.vram_width = 8 * chansize; + } else if (rdev->family == CHIP_RV670) { + rdev->mc.vram_width = 4 * chansize; + } else if ((rdev->family == CHIP_RV610) || + (rdev->family == CHIP_RV620)) { + rdev->mc.vram_width = chansize; + } else if ((rdev->family == CHIP_RV630) || + (rdev->family == CHIP_RV635)) { + rdev->mc.vram_width = 2 * chansize; + } +} + +void r600_vram_info(struct radeon_device *rdev) +{ + r600_vram_get_type(rdev); + rdev->mc.vram_size = RREG32(R600_CONFIG_MEMSIZE); + + /* Could aper size report 0 ? */ + rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0); + rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0); +} + +/* + * Indirect registers accessor + */ +uint32_t r600_pciep_rreg(struct radeon_device *rdev, uint32_t reg) +{ + uint32_t r; + + WREG32(R600_PCIE_PORT_INDEX, ((reg) & 0xff)); + (void)RREG32(R600_PCIE_PORT_INDEX); + r = RREG32(R600_PCIE_PORT_DATA); + return r; +} + +void r600_pciep_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v) +{ + WREG32(R600_PCIE_PORT_INDEX, ((reg) & 0xff)); + (void)RREG32(R600_PCIE_PORT_INDEX); + WREG32(R600_PCIE_PORT_DATA, (v)); + (void)RREG32(R600_PCIE_PORT_DATA); +} diff --git a/drivers/gpu/drm/radeon/r600_cp.c b/drivers/gpu/drm/radeon/r600_cp.c index bc9d09dfa8e7..146f3570af8e 100644 --- a/drivers/gpu/drm/radeon/r600_cp.c +++ b/drivers/gpu/drm/radeon/r600_cp.c @@ -478,26 +478,27 @@ static void r700_cp_load_microcode(drm_radeon_private_t *dev_priv) if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV770)) { RADEON_WRITE(R600_CP_PFP_UCODE_ADDR, 0); - DRM_INFO("Loading RV770 PFP Microcode\n"); + DRM_INFO("Loading RV770/RV790 PFP Microcode\n"); for (i = 0; i < R700_PFP_UCODE_SIZE; i++) RADEON_WRITE(R600_CP_PFP_UCODE_DATA, RV770_pfp_microcode[i]); RADEON_WRITE(R600_CP_PFP_UCODE_ADDR, 0); RADEON_WRITE(R600_CP_ME_RAM_WADDR, 0); - DRM_INFO("Loading RV770 CP Microcode\n"); + DRM_INFO("Loading RV770/RV790 CP Microcode\n"); for (i = 0; i < R700_PM4_UCODE_SIZE; i++) RADEON_WRITE(R600_CP_ME_RAM_DATA, RV770_cp_microcode[i]); RADEON_WRITE(R600_CP_ME_RAM_WADDR, 0); - } else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV730)) { + } else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV730) || + ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV740)) { RADEON_WRITE(R600_CP_PFP_UCODE_ADDR, 0); - DRM_INFO("Loading RV730 PFP Microcode\n"); + DRM_INFO("Loading RV730/RV740 PFP Microcode\n"); for (i = 0; i < R700_PFP_UCODE_SIZE; i++) RADEON_WRITE(R600_CP_PFP_UCODE_DATA, RV730_pfp_microcode[i]); RADEON_WRITE(R600_CP_PFP_UCODE_ADDR, 0); RADEON_WRITE(R600_CP_ME_RAM_WADDR, 0); - DRM_INFO("Loading RV730 CP Microcode\n"); + DRM_INFO("Loading RV730/RV740 CP Microcode\n"); for (i = 0; i < R700_PM4_UCODE_SIZE; i++) RADEON_WRITE(R600_CP_ME_RAM_DATA, RV730_cp_microcode[i]); RADEON_WRITE(R600_CP_ME_RAM_WADDR, 0); @@ -1324,6 +1325,10 @@ static void r700_gfx_init(struct drm_device *dev, dev_priv->r700_sc_prim_fifo_size = 0xf9; dev_priv->r700_sc_hiz_tile_fifo_size = 0x30; dev_priv->r700_sc_earlyz_tile_fifo_fize = 0x130; + if (dev_priv->r600_sx_max_export_pos_size > 16) { + dev_priv->r600_sx_max_export_pos_size -= 16; + dev_priv->r600_sx_max_export_smx_size += 16; + } break; case CHIP_RV710: dev_priv->r600_max_pipes = 2; @@ -1345,6 +1350,31 @@ static void r700_gfx_init(struct drm_device *dev, dev_priv->r700_sc_hiz_tile_fifo_size = 0x30; dev_priv->r700_sc_earlyz_tile_fifo_fize = 0x130; break; + case CHIP_RV740: + dev_priv->r600_max_pipes = 4; + dev_priv->r600_max_tile_pipes = 4; + dev_priv->r600_max_simds = 8; + dev_priv->r600_max_backends = 4; + dev_priv->r600_max_gprs = 256; + dev_priv->r600_max_threads = 248; + dev_priv->r600_max_stack_entries = 512; + dev_priv->r600_max_hw_contexts = 8; + dev_priv->r600_max_gs_threads = 16 * 2; + dev_priv->r600_sx_max_export_size = 256; + dev_priv->r600_sx_max_export_pos_size = 32; + dev_priv->r600_sx_max_export_smx_size = 224; + dev_priv->r600_sq_num_cf_insts = 2; + + dev_priv->r700_sx_num_of_sets = 7; + dev_priv->r700_sc_prim_fifo_size = 0x100; + dev_priv->r700_sc_hiz_tile_fifo_size = 0x30; + dev_priv->r700_sc_earlyz_tile_fifo_fize = 0x130; + + if (dev_priv->r600_sx_max_export_pos_size > 16) { + dev_priv->r600_sx_max_export_pos_size -= 16; + dev_priv->r600_sx_max_export_smx_size += 16; + } + break; default: break; } @@ -1493,6 +1523,7 @@ static void r700_gfx_init(struct drm_device *dev, break; case CHIP_RV730: case CHIP_RV710: + case CHIP_RV740: default: sq_ms_fifo_sizes |= R600_FETCH_FIFO_HIWATER(0x4); break; @@ -1569,6 +1600,7 @@ static void r700_gfx_init(struct drm_device *dev, switch (dev_priv->flags & RADEON_FAMILY_MASK) { case CHIP_RV770: case CHIP_RV730: + case CHIP_RV740: gs_prim_buffer_depth = 384; break; case CHIP_RV710: diff --git a/drivers/gpu/drm/radeon/r600_reg.h b/drivers/gpu/drm/radeon/r600_reg.h new file mode 100644 index 000000000000..e2d1f5f33f7e --- /dev/null +++ b/drivers/gpu/drm/radeon/r600_reg.h @@ -0,0 +1,114 @@ +/* + * Copyright 2008 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * Copyright 2009 Jerome Glisse. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Dave Airlie + * Alex Deucher + * Jerome Glisse + */ +#ifndef __R600_REG_H__ +#define __R600_REG_H__ + +#define R600_PCIE_PORT_INDEX 0x0038 +#define R600_PCIE_PORT_DATA 0x003c + +#define R600_MC_VM_FB_LOCATION 0x2180 +#define R600_MC_FB_BASE_MASK 0x0000FFFF +#define R600_MC_FB_BASE_SHIFT 0 +#define R600_MC_FB_TOP_MASK 0xFFFF0000 +#define R600_MC_FB_TOP_SHIFT 16 +#define R600_MC_VM_AGP_TOP 0x2184 +#define R600_MC_AGP_TOP_MASK 0x0003FFFF +#define R600_MC_AGP_TOP_SHIFT 0 +#define R600_MC_VM_AGP_BOT 0x2188 +#define R600_MC_AGP_BOT_MASK 0x0003FFFF +#define R600_MC_AGP_BOT_SHIFT 0 +#define R600_MC_VM_AGP_BASE 0x218c +#define R600_MC_VM_SYSTEM_APERTURE_LOW_ADDR 0x2190 +#define R600_LOGICAL_PAGE_NUMBER_MASK 0x000FFFFF +#define R600_LOGICAL_PAGE_NUMBER_SHIFT 0 +#define R600_MC_VM_SYSTEM_APERTURE_HIGH_ADDR 0x2194 +#define R600_MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR 0x2198 + +#define R700_MC_VM_FB_LOCATION 0x2024 +#define R700_MC_FB_BASE_MASK 0x0000FFFF +#define R700_MC_FB_BASE_SHIFT 0 +#define R700_MC_FB_TOP_MASK 0xFFFF0000 +#define R700_MC_FB_TOP_SHIFT 16 +#define R700_MC_VM_AGP_TOP 0x2028 +#define R700_MC_AGP_TOP_MASK 0x0003FFFF +#define R700_MC_AGP_TOP_SHIFT 0 +#define R700_MC_VM_AGP_BOT 0x202c +#define R700_MC_AGP_BOT_MASK 0x0003FFFF +#define R700_MC_AGP_BOT_SHIFT 0 +#define R700_MC_VM_AGP_BASE 0x2030 +#define R700_MC_VM_SYSTEM_APERTURE_LOW_ADDR 0x2034 +#define R700_LOGICAL_PAGE_NUMBER_MASK 0x000FFFFF +#define R700_LOGICAL_PAGE_NUMBER_SHIFT 0 +#define R700_MC_VM_SYSTEM_APERTURE_HIGH_ADDR 0x2038 +#define R700_MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR 0x203c + +#define R600_RAMCFG 0x2408 +# define R600_CHANSIZE (1 << 7) +# define R600_CHANSIZE_OVERRIDE (1 << 10) + + +#define R600_GENERAL_PWRMGT 0x618 +# define R600_OPEN_DRAIN_PADS (1 << 11) + +#define R600_LOWER_GPIO_ENABLE 0x710 +#define R600_CTXSW_VID_LOWER_GPIO_CNTL 0x718 +#define R600_HIGH_VID_LOWER_GPIO_CNTL 0x71c +#define R600_MEDIUM_VID_LOWER_GPIO_CNTL 0x720 +#define R600_LOW_VID_LOWER_GPIO_CNTL 0x724 + + + +#define R600_HDP_NONSURFACE_BASE 0x2c04 + +#define R600_BUS_CNTL 0x5420 +#define R600_CONFIG_CNTL 0x5424 +#define R600_CONFIG_MEMSIZE 0x5428 +#define R600_CONFIG_F0_BASE 0x542C +#define R600_CONFIG_APER_SIZE 0x5430 + +#define R600_ROM_CNTL 0x1600 +# define R600_SCK_OVERWRITE (1 << 1) +# define R600_SCK_PRESCALE_CRYSTAL_CLK_SHIFT 28 +# define R600_SCK_PRESCALE_CRYSTAL_CLK_MASK (0xf << 28) + +#define R600_CG_SPLL_FUNC_CNTL 0x600 +# define R600_SPLL_BYPASS_EN (1 << 3) +#define R600_CG_SPLL_STATUS 0x60c +# define R600_SPLL_CHG_STATUS (1 << 1) + +#define R600_BIOS_0_SCRATCH 0x1724 +#define R600_BIOS_1_SCRATCH 0x1728 +#define R600_BIOS_2_SCRATCH 0x172c +#define R600_BIOS_3_SCRATCH 0x1730 +#define R600_BIOS_4_SCRATCH 0x1734 +#define R600_BIOS_5_SCRATCH 0x1738 +#define R600_BIOS_6_SCRATCH 0x173c +#define R600_BIOS_7_SCRATCH 0x1740 + + +#endif diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h new file mode 100644 index 000000000000..d61f2fc61df5 --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon.h @@ -0,0 +1,800 @@ +/* + * Copyright 2008 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * Copyright 2009 Jerome Glisse. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Dave Airlie + * Alex Deucher + * Jerome Glisse + */ +#ifndef __RADEON_H__ +#define __RADEON_H__ + +#include "radeon_object.h" + +/* TODO: Here are things that needs to be done : + * - surface allocator & initializer : (bit like scratch reg) should + * initialize HDP_ stuff on RS600, R600, R700 hw, well anythings + * related to surface + * - WB : write back stuff (do it bit like scratch reg things) + * - Vblank : look at Jesse's rework and what we should do + * - r600/r700: gart & cp + * - cs : clean cs ioctl use bitmap & things like that. + * - power management stuff + * - Barrier in gart code + * - Unmappabled vram ? + * - TESTING, TESTING, TESTING + */ + +#include +#include +#include +#include + +#include "radeon_mode.h" +#include "radeon_reg.h" +#include "r300.h" + +/* + * Modules parameters. + */ +extern int radeon_no_wb; +extern int radeon_modeset; +extern int radeon_dynclks; +extern int radeon_r4xx_atom; +extern int radeon_agpmode; +extern int radeon_vram_limit; +extern int radeon_gart_size; +extern int radeon_benchmarking; +extern int radeon_connector_table; + +/* + * Copy from radeon_drv.h so we don't have to include both and have conflicting + * symbol; + */ +#define RADEON_MAX_USEC_TIMEOUT 100000 /* 100 ms */ +#define RADEON_IB_POOL_SIZE 16 +#define RADEON_DEBUGFS_MAX_NUM_FILES 32 +#define RADEONFB_CONN_LIMIT 4 + +enum radeon_family { + CHIP_R100, + CHIP_RV100, + CHIP_RS100, + CHIP_RV200, + CHIP_RS200, + CHIP_R200, + CHIP_RV250, + CHIP_RS300, + CHIP_RV280, + CHIP_R300, + CHIP_R350, + CHIP_RV350, + CHIP_RV380, + CHIP_R420, + CHIP_R423, + CHIP_RV410, + CHIP_RS400, + CHIP_RS480, + CHIP_RS600, + CHIP_RS690, + CHIP_RS740, + CHIP_RV515, + CHIP_R520, + CHIP_RV530, + CHIP_RV560, + CHIP_RV570, + CHIP_R580, + CHIP_R600, + CHIP_RV610, + CHIP_RV630, + CHIP_RV620, + CHIP_RV635, + CHIP_RV670, + CHIP_RS780, + CHIP_RV770, + CHIP_RV730, + CHIP_RV710, + CHIP_LAST, +}; + +enum radeon_chip_flags { + RADEON_FAMILY_MASK = 0x0000ffffUL, + RADEON_FLAGS_MASK = 0xffff0000UL, + RADEON_IS_MOBILITY = 0x00010000UL, + RADEON_IS_IGP = 0x00020000UL, + RADEON_SINGLE_CRTC = 0x00040000UL, + RADEON_IS_AGP = 0x00080000UL, + RADEON_HAS_HIERZ = 0x00100000UL, + RADEON_IS_PCIE = 0x00200000UL, + RADEON_NEW_MEMMAP = 0x00400000UL, + RADEON_IS_PCI = 0x00800000UL, + RADEON_IS_IGPGART = 0x01000000UL, +}; + + +/* + * Errata workarounds. + */ +enum radeon_pll_errata { + CHIP_ERRATA_R300_CG = 0x00000001, + CHIP_ERRATA_PLL_DUMMYREADS = 0x00000002, + CHIP_ERRATA_PLL_DELAY = 0x00000004 +}; + + +struct radeon_device; + + +/* + * BIOS. + */ +bool radeon_get_bios(struct radeon_device *rdev); + +/* + * Clocks + */ + +struct radeon_clock { + struct radeon_pll p1pll; + struct radeon_pll p2pll; + struct radeon_pll spll; + struct radeon_pll mpll; + /* 10 Khz units */ + uint32_t default_mclk; + uint32_t default_sclk; +}; + +/* + * Fences. + */ +struct radeon_fence_driver { + uint32_t scratch_reg; + atomic_t seq; + uint32_t last_seq; + unsigned long count_timeout; + wait_queue_head_t queue; + rwlock_t lock; + struct list_head created; + struct list_head emited; + struct list_head signaled; +}; + +struct radeon_fence { + struct radeon_device *rdev; + struct kref kref; + struct list_head list; + /* protected by radeon_fence.lock */ + uint32_t seq; + unsigned long timeout; + bool emited; + bool signaled; +}; + +int radeon_fence_driver_init(struct radeon_device *rdev); +void radeon_fence_driver_fini(struct radeon_device *rdev); +int radeon_fence_create(struct radeon_device *rdev, struct radeon_fence **fence); +int radeon_fence_emit(struct radeon_device *rdev, struct radeon_fence *fence); +void radeon_fence_process(struct radeon_device *rdev); +bool radeon_fence_signaled(struct radeon_fence *fence); +int radeon_fence_wait(struct radeon_fence *fence, bool interruptible); +int radeon_fence_wait_next(struct radeon_device *rdev); +int radeon_fence_wait_last(struct radeon_device *rdev); +struct radeon_fence *radeon_fence_ref(struct radeon_fence *fence); +void radeon_fence_unref(struct radeon_fence **fence); + + +/* + * Radeon buffer. + */ +struct radeon_object; + +struct radeon_object_list { + struct list_head list; + struct radeon_object *robj; + uint64_t gpu_offset; + unsigned rdomain; + unsigned wdomain; +}; + +int radeon_object_init(struct radeon_device *rdev); +void radeon_object_fini(struct radeon_device *rdev); +int radeon_object_create(struct radeon_device *rdev, + struct drm_gem_object *gobj, + unsigned long size, + bool kernel, + uint32_t domain, + bool interruptible, + struct radeon_object **robj_ptr); +int radeon_object_kmap(struct radeon_object *robj, void **ptr); +void radeon_object_kunmap(struct radeon_object *robj); +void radeon_object_unref(struct radeon_object **robj); +int radeon_object_pin(struct radeon_object *robj, uint32_t domain, + uint64_t *gpu_addr); +void radeon_object_unpin(struct radeon_object *robj); +int radeon_object_wait(struct radeon_object *robj); +int radeon_object_evict_vram(struct radeon_device *rdev); +int radeon_object_mmap(struct radeon_object *robj, uint64_t *offset); +void radeon_object_force_delete(struct radeon_device *rdev); +void radeon_object_list_add_object(struct radeon_object_list *lobj, + struct list_head *head); +int radeon_object_list_validate(struct list_head *head, void *fence); +void radeon_object_list_unvalidate(struct list_head *head); +void radeon_object_list_clean(struct list_head *head); +int radeon_object_fbdev_mmap(struct radeon_object *robj, + struct vm_area_struct *vma); +unsigned long radeon_object_size(struct radeon_object *robj); + + +/* + * GEM objects. + */ +struct radeon_gem { + struct list_head objects; +}; + +int radeon_gem_init(struct radeon_device *rdev); +void radeon_gem_fini(struct radeon_device *rdev); +int radeon_gem_object_create(struct radeon_device *rdev, int size, + int alignment, int initial_domain, + bool discardable, bool kernel, + bool interruptible, + struct drm_gem_object **obj); +int radeon_gem_object_pin(struct drm_gem_object *obj, uint32_t pin_domain, + uint64_t *gpu_addr); +void radeon_gem_object_unpin(struct drm_gem_object *obj); + + +/* + * GART structures, functions & helpers + */ +struct radeon_mc; + +struct radeon_gart_table_ram { + volatile uint32_t *ptr; +}; + +struct radeon_gart_table_vram { + struct radeon_object *robj; + volatile uint32_t *ptr; +}; + +union radeon_gart_table { + struct radeon_gart_table_ram ram; + struct radeon_gart_table_vram vram; +}; + +struct radeon_gart { + dma_addr_t table_addr; + unsigned num_gpu_pages; + unsigned num_cpu_pages; + unsigned table_size; + union radeon_gart_table table; + struct page **pages; + dma_addr_t *pages_addr; + bool ready; +}; + +int radeon_gart_table_ram_alloc(struct radeon_device *rdev); +void radeon_gart_table_ram_free(struct radeon_device *rdev); +int radeon_gart_table_vram_alloc(struct radeon_device *rdev); +void radeon_gart_table_vram_free(struct radeon_device *rdev); +int radeon_gart_init(struct radeon_device *rdev); +void radeon_gart_fini(struct radeon_device *rdev); +void radeon_gart_unbind(struct radeon_device *rdev, unsigned offset, + int pages); +int radeon_gart_bind(struct radeon_device *rdev, unsigned offset, + int pages, struct page **pagelist); + + +/* + * GPU MC structures, functions & helpers + */ +struct radeon_mc { + resource_size_t aper_size; + resource_size_t aper_base; + resource_size_t agp_base; + unsigned gtt_location; + unsigned gtt_size; + unsigned vram_location; + unsigned vram_size; + unsigned vram_width; + int vram_mtrr; + bool vram_is_ddr; +}; + +int radeon_mc_setup(struct radeon_device *rdev); + + +/* + * GPU scratch registers structures, functions & helpers + */ +struct radeon_scratch { + unsigned num_reg; + bool free[32]; + uint32_t reg[32]; +}; + +int radeon_scratch_get(struct radeon_device *rdev, uint32_t *reg); +void radeon_scratch_free(struct radeon_device *rdev, uint32_t reg); + + +/* + * IRQS. + */ +struct radeon_irq { + bool installed; + bool sw_int; + /* FIXME: use a define max crtc rather than hardcode it */ + bool crtc_vblank_int[2]; +}; + +int radeon_irq_kms_init(struct radeon_device *rdev); +void radeon_irq_kms_fini(struct radeon_device *rdev); + + +/* + * CP & ring. + */ +struct radeon_ib { + struct list_head list; + unsigned long idx; + uint64_t gpu_addr; + struct radeon_fence *fence; + volatile uint32_t *ptr; + uint32_t length_dw; +}; + +struct radeon_ib_pool { + struct mutex mutex; + struct radeon_object *robj; + struct list_head scheduled_ibs; + struct radeon_ib ibs[RADEON_IB_POOL_SIZE]; + bool ready; + DECLARE_BITMAP(alloc_bm, RADEON_IB_POOL_SIZE); +}; + +struct radeon_cp { + struct radeon_object *ring_obj; + volatile uint32_t *ring; + unsigned rptr; + unsigned wptr; + unsigned wptr_old; + unsigned ring_size; + unsigned ring_free_dw; + int count_dw; + uint64_t gpu_addr; + uint32_t align_mask; + uint32_t ptr_mask; + struct mutex mutex; + bool ready; +}; + +int radeon_ib_get(struct radeon_device *rdev, struct radeon_ib **ib); +void radeon_ib_free(struct radeon_device *rdev, struct radeon_ib **ib); +int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib); +int radeon_ib_pool_init(struct radeon_device *rdev); +void radeon_ib_pool_fini(struct radeon_device *rdev); +int radeon_ib_test(struct radeon_device *rdev); +/* Ring access between begin & end cannot sleep */ +void radeon_ring_free_size(struct radeon_device *rdev); +int radeon_ring_lock(struct radeon_device *rdev, unsigned ndw); +void radeon_ring_unlock_commit(struct radeon_device *rdev); +void radeon_ring_unlock_undo(struct radeon_device *rdev); +int radeon_ring_test(struct radeon_device *rdev); +int radeon_ring_init(struct radeon_device *rdev, unsigned ring_size); +void radeon_ring_fini(struct radeon_device *rdev); + + +/* + * CS. + */ +struct radeon_cs_reloc { + struct drm_gem_object *gobj; + struct radeon_object *robj; + struct radeon_object_list lobj; + uint32_t handle; + uint32_t flags; +}; + +struct radeon_cs_chunk { + uint32_t chunk_id; + uint32_t length_dw; + uint32_t *kdata; +}; + +struct radeon_cs_parser { + struct radeon_device *rdev; + struct drm_file *filp; + /* chunks */ + unsigned nchunks; + struct radeon_cs_chunk *chunks; + uint64_t *chunks_array; + /* IB */ + unsigned idx; + /* relocations */ + unsigned nrelocs; + struct radeon_cs_reloc *relocs; + struct radeon_cs_reloc **relocs_ptr; + struct list_head validated; + /* indices of various chunks */ + int chunk_ib_idx; + int chunk_relocs_idx; + struct radeon_ib *ib; + void *track; +}; + +struct radeon_cs_packet { + unsigned idx; + unsigned type; + unsigned reg; + unsigned opcode; + int count; + unsigned one_reg_wr; +}; + +typedef int (*radeon_packet0_check_t)(struct radeon_cs_parser *p, + struct radeon_cs_packet *pkt, + unsigned idx, unsigned reg); +typedef int (*radeon_packet3_check_t)(struct radeon_cs_parser *p, + struct radeon_cs_packet *pkt); + + +/* + * AGP + */ +int radeon_agp_init(struct radeon_device *rdev); +void radeon_agp_fini(struct radeon_device *rdev); + + +/* + * Writeback + */ +struct radeon_wb { + struct radeon_object *wb_obj; + volatile uint32_t *wb; + uint64_t gpu_addr; +}; + + +/* + * Benchmarking + */ +void radeon_benchmark(struct radeon_device *rdev); + + +/* + * Debugfs + */ +int radeon_debugfs_add_files(struct radeon_device *rdev, + struct drm_info_list *files, + unsigned nfiles); +int radeon_debugfs_fence_init(struct radeon_device *rdev); +int r100_debugfs_rbbm_init(struct radeon_device *rdev); +int r100_debugfs_cp_init(struct radeon_device *rdev); + + +/* + * ASIC specific functions. + */ +struct radeon_asic { + int (*init)(struct radeon_device *rdev); + void (*errata)(struct radeon_device *rdev); + void (*vram_info)(struct radeon_device *rdev); + int (*gpu_reset)(struct radeon_device *rdev); + int (*mc_init)(struct radeon_device *rdev); + void (*mc_fini)(struct radeon_device *rdev); + int (*wb_init)(struct radeon_device *rdev); + void (*wb_fini)(struct radeon_device *rdev); + int (*gart_enable)(struct radeon_device *rdev); + void (*gart_disable)(struct radeon_device *rdev); + void (*gart_tlb_flush)(struct radeon_device *rdev); + int (*gart_set_page)(struct radeon_device *rdev, int i, uint64_t addr); + int (*cp_init)(struct radeon_device *rdev, unsigned ring_size); + void (*cp_fini)(struct radeon_device *rdev); + void (*cp_disable)(struct radeon_device *rdev); + void (*ring_start)(struct radeon_device *rdev); + int (*irq_set)(struct radeon_device *rdev); + int (*irq_process)(struct radeon_device *rdev); + void (*fence_ring_emit)(struct radeon_device *rdev, struct radeon_fence *fence); + int (*cs_parse)(struct radeon_cs_parser *p); + int (*copy_blit)(struct radeon_device *rdev, + uint64_t src_offset, + uint64_t dst_offset, + unsigned num_pages, + struct radeon_fence *fence); + int (*copy_dma)(struct radeon_device *rdev, + uint64_t src_offset, + uint64_t dst_offset, + unsigned num_pages, + struct radeon_fence *fence); + int (*copy)(struct radeon_device *rdev, + uint64_t src_offset, + uint64_t dst_offset, + unsigned num_pages, + struct radeon_fence *fence); + void (*set_engine_clock)(struct radeon_device *rdev, uint32_t eng_clock); + void (*set_memory_clock)(struct radeon_device *rdev, uint32_t mem_clock); + void (*set_pcie_lanes)(struct radeon_device *rdev, int lanes); + void (*set_clock_gating)(struct radeon_device *rdev, int enable); +}; + +union radeon_asic_config { + struct r300_asic r300; +}; + + +/* + * IOCTL. + */ +int radeon_gem_info_ioctl(struct drm_device *dev, void *data, + struct drm_file *filp); +int radeon_gem_create_ioctl(struct drm_device *dev, void *data, + struct drm_file *filp); +int radeon_gem_pin_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +int radeon_gem_unpin_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +int radeon_gem_pwrite_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +int radeon_gem_pread_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +int radeon_gem_set_domain_ioctl(struct drm_device *dev, void *data, + struct drm_file *filp); +int radeon_gem_mmap_ioctl(struct drm_device *dev, void *data, + struct drm_file *filp); +int radeon_gem_busy_ioctl(struct drm_device *dev, void *data, + struct drm_file *filp); +int radeon_gem_wait_idle_ioctl(struct drm_device *dev, void *data, + struct drm_file *filp); +int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp); + + +/* + * Core structure, functions and helpers. + */ +typedef uint32_t (*radeon_rreg_t)(struct radeon_device*, uint32_t); +typedef void (*radeon_wreg_t)(struct radeon_device*, uint32_t, uint32_t); + +struct radeon_device { + struct drm_device *ddev; + struct pci_dev *pdev; + /* ASIC */ + union radeon_asic_config config; + enum radeon_family family; + unsigned long flags; + int usec_timeout; + enum radeon_pll_errata pll_errata; + int num_gb_pipes; + int disp_priority; + /* BIOS */ + uint8_t *bios; + bool is_atom_bios; + uint16_t bios_header_start; + struct radeon_object *stollen_vga_memory; + struct fb_info *fbdev_info; + struct radeon_object *fbdev_robj; + struct radeon_framebuffer *fbdev_rfb; + /* Register mmio */ + unsigned long rmmio_base; + unsigned long rmmio_size; + void *rmmio; + radeon_rreg_t mm_rreg; + radeon_wreg_t mm_wreg; + radeon_rreg_t mc_rreg; + radeon_wreg_t mc_wreg; + radeon_rreg_t pll_rreg; + radeon_wreg_t pll_wreg; + radeon_rreg_t pcie_rreg; + radeon_wreg_t pcie_wreg; + radeon_rreg_t pciep_rreg; + radeon_wreg_t pciep_wreg; + struct radeon_clock clock; + struct radeon_mc mc; + struct radeon_gart gart; + struct radeon_mode_info mode_info; + struct radeon_scratch scratch; + struct radeon_mman mman; + struct radeon_fence_driver fence_drv; + struct radeon_cp cp; + struct radeon_ib_pool ib_pool; + struct radeon_irq irq; + struct radeon_asic *asic; + struct radeon_gem gem; + struct mutex cs_mutex; + struct radeon_wb wb; + bool gpu_lockup; + bool shutdown; + bool suspend; +}; + +int radeon_device_init(struct radeon_device *rdev, + struct drm_device *ddev, + struct pci_dev *pdev, + uint32_t flags); +void radeon_device_fini(struct radeon_device *rdev); +int radeon_gpu_wait_for_idle(struct radeon_device *rdev); + + +/* + * Registers read & write functions. + */ +#define RREG8(reg) readb(((void __iomem *)rdev->rmmio) + (reg)) +#define WREG8(reg, v) writeb(v, ((void __iomem *)rdev->rmmio) + (reg)) +#define RREG32(reg) rdev->mm_rreg(rdev, (reg)) +#define WREG32(reg, v) rdev->mm_wreg(rdev, (reg), (v)) +#define REG_SET(FIELD, v) (((v) << FIELD##_SHIFT) & FIELD##_MASK) +#define REG_GET(FIELD, v) (((v) << FIELD##_SHIFT) & FIELD##_MASK) +#define RREG32_PLL(reg) rdev->pll_rreg(rdev, (reg)) +#define WREG32_PLL(reg, v) rdev->pll_wreg(rdev, (reg), (v)) +#define RREG32_MC(reg) rdev->mc_rreg(rdev, (reg)) +#define WREG32_MC(reg, v) rdev->mc_wreg(rdev, (reg), (v)) +#define RREG32_PCIE(reg) rdev->pcie_rreg(rdev, (reg)) +#define WREG32_PCIE(reg, v) rdev->pcie_wreg(rdev, (reg), (v)) +#define WREG32_P(reg, val, mask) \ + do { \ + uint32_t tmp_ = RREG32(reg); \ + tmp_ &= (mask); \ + tmp_ |= ((val) & ~(mask)); \ + WREG32(reg, tmp_); \ + } while (0) +#define WREG32_PLL_P(reg, val, mask) \ + do { \ + uint32_t tmp_ = RREG32_PLL(reg); \ + tmp_ &= (mask); \ + tmp_ |= ((val) & ~(mask)); \ + WREG32_PLL(reg, tmp_); \ + } while (0) + +void r100_pll_errata_after_index(struct radeon_device *rdev); + + +/* + * ASICs helpers. + */ +#define ASIC_IS_RV100(rdev) ((rdev->family == CHIP_RV100) || \ + (rdev->family == CHIP_RV200) || \ + (rdev->family == CHIP_RS100) || \ + (rdev->family == CHIP_RS200) || \ + (rdev->family == CHIP_RV250) || \ + (rdev->family == CHIP_RV280) || \ + (rdev->family == CHIP_RS300)) +#define ASIC_IS_R300(rdev) ((rdev->family == CHIP_R300) || \ + (rdev->family == CHIP_RV350) || \ + (rdev->family == CHIP_R350) || \ + (rdev->family == CHIP_RV380) || \ + (rdev->family == CHIP_R420) || \ + (rdev->family == CHIP_R423) || \ + (rdev->family == CHIP_RV410) || \ + (rdev->family == CHIP_RS400) || \ + (rdev->family == CHIP_RS480)) +#define ASIC_IS_AVIVO(rdev) ((rdev->family >= CHIP_RS600)) +#define ASIC_IS_DCE3(rdev) ((rdev->family >= CHIP_RV620)) +#define ASIC_IS_DCE32(rdev) ((rdev->family >= CHIP_RV730)) + + +/* + * BIOS helpers. + */ +#define RBIOS8(i) (rdev->bios[i]) +#define RBIOS16(i) (RBIOS8(i) | (RBIOS8((i)+1) << 8)) +#define RBIOS32(i) ((RBIOS16(i)) | (RBIOS16((i)+2) << 16)) + +int radeon_combios_init(struct radeon_device *rdev); +void radeon_combios_fini(struct radeon_device *rdev); +int radeon_atombios_init(struct radeon_device *rdev); +void radeon_atombios_fini(struct radeon_device *rdev); + + +/* + * RING helpers. + */ +#define CP_PACKET0 0x00000000 +#define PACKET0_BASE_INDEX_SHIFT 0 +#define PACKET0_BASE_INDEX_MASK (0x1ffff << 0) +#define PACKET0_COUNT_SHIFT 16 +#define PACKET0_COUNT_MASK (0x3fff << 16) +#define CP_PACKET1 0x40000000 +#define CP_PACKET2 0x80000000 +#define PACKET2_PAD_SHIFT 0 +#define PACKET2_PAD_MASK (0x3fffffff << 0) +#define CP_PACKET3 0xC0000000 +#define PACKET3_IT_OPCODE_SHIFT 8 +#define PACKET3_IT_OPCODE_MASK (0xff << 8) +#define PACKET3_COUNT_SHIFT 16 +#define PACKET3_COUNT_MASK (0x3fff << 16) +/* PACKET3 op code */ +#define PACKET3_NOP 0x10 +#define PACKET3_3D_DRAW_VBUF 0x28 +#define PACKET3_3D_DRAW_IMMD 0x29 +#define PACKET3_3D_DRAW_INDX 0x2A +#define PACKET3_3D_LOAD_VBPNTR 0x2F +#define PACKET3_INDX_BUFFER 0x33 +#define PACKET3_3D_DRAW_VBUF_2 0x34 +#define PACKET3_3D_DRAW_IMMD_2 0x35 +#define PACKET3_3D_DRAW_INDX_2 0x36 +#define PACKET3_BITBLT_MULTI 0x9B + +#define PACKET0(reg, n) (CP_PACKET0 | \ + REG_SET(PACKET0_BASE_INDEX, (reg) >> 2) | \ + REG_SET(PACKET0_COUNT, (n))) +#define PACKET2(v) (CP_PACKET2 | REG_SET(PACKET2_PAD, (v))) +#define PACKET3(op, n) (CP_PACKET3 | \ + REG_SET(PACKET3_IT_OPCODE, (op)) | \ + REG_SET(PACKET3_COUNT, (n))) + +#define PACKET_TYPE0 0 +#define PACKET_TYPE1 1 +#define PACKET_TYPE2 2 +#define PACKET_TYPE3 3 + +#define CP_PACKET_GET_TYPE(h) (((h) >> 30) & 3) +#define CP_PACKET_GET_COUNT(h) (((h) >> 16) & 0x3FFF) +#define CP_PACKET0_GET_REG(h) (((h) & 0x1FFF) << 2) +#define CP_PACKET0_GET_ONE_REG_WR(h) (((h) >> 15) & 1) +#define CP_PACKET3_GET_OPCODE(h) (((h) >> 8) & 0xFF) + +static inline void radeon_ring_write(struct radeon_device *rdev, uint32_t v) +{ +#if DRM_DEBUG_CODE + if (rdev->cp.count_dw <= 0) { + DRM_ERROR("radeon: writting more dword to ring than expected !\n"); + } +#endif + rdev->cp.ring[rdev->cp.wptr++] = v; + rdev->cp.wptr &= rdev->cp.ptr_mask; + rdev->cp.count_dw--; + rdev->cp.ring_free_dw--; +} + + +/* + * ASICs macro. + */ +#define radeon_init(rdev) (rdev)->asic->init((rdev)) +#define radeon_cs_parse(p) rdev->asic->cs_parse((p)) +#define radeon_errata(rdev) (rdev)->asic->errata((rdev)) +#define radeon_vram_info(rdev) (rdev)->asic->vram_info((rdev)) +#define radeon_gpu_reset(rdev) (rdev)->asic->gpu_reset((rdev)) +#define radeon_mc_init(rdev) (rdev)->asic->mc_init((rdev)) +#define radeon_mc_fini(rdev) (rdev)->asic->mc_fini((rdev)) +#define radeon_wb_init(rdev) (rdev)->asic->wb_init((rdev)) +#define radeon_wb_fini(rdev) (rdev)->asic->wb_fini((rdev)) +#define radeon_gart_enable(rdev) (rdev)->asic->gart_enable((rdev)) +#define radeon_gart_disable(rdev) (rdev)->asic->gart_disable((rdev)) +#define radeon_gart_tlb_flush(rdev) (rdev)->asic->gart_tlb_flush((rdev)) +#define radeon_gart_set_page(rdev, i, p) (rdev)->asic->gart_set_page((rdev), (i), (p)) +#define radeon_cp_init(rdev,rsize) (rdev)->asic->cp_init((rdev), (rsize)) +#define radeon_cp_fini(rdev) (rdev)->asic->cp_fini((rdev)) +#define radeon_cp_disable(rdev) (rdev)->asic->cp_disable((rdev)) +#define radeon_ring_start(rdev) (rdev)->asic->ring_start((rdev)) +#define radeon_irq_set(rdev) (rdev)->asic->irq_set((rdev)) +#define radeon_irq_process(rdev) (rdev)->asic->irq_process((rdev)) +#define radeon_fence_ring_emit(rdev, fence) (rdev)->asic->fence_ring_emit((rdev), (fence)) +#define radeon_copy_blit(rdev, s, d, np, f) (rdev)->asic->copy_blit((rdev), (s), (d), (np), (f)) +#define radeon_copy_dma(rdev, s, d, np, f) (rdev)->asic->copy_dma((rdev), (s), (d), (np), (f)) +#define radeon_copy(rdev, s, d, np, f) (rdev)->asic->copy((rdev), (s), (d), (np), (f)) +#define radeon_set_engine_clock(rdev, e) (rdev)->asic->set_engine_clock((rdev), (e)) +#define radeon_set_memory_clock(rdev, e) (rdev)->asic->set_engine_clock((rdev), (e)) +#define radeon_set_pcie_lanes(rdev, l) (rdev)->asic->set_pcie_lanes((rdev), (l)) +#define radeon_set_clock_gating(rdev, e) (rdev)->asic->set_clock_gating((rdev), (e)) + +#endif diff --git a/drivers/gpu/drm/radeon/radeon_agp.c b/drivers/gpu/drm/radeon/radeon_agp.c new file mode 100644 index 000000000000..23ea9955ac59 --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_agp.c @@ -0,0 +1,249 @@ +/* + * Copyright 2008 Red Hat Inc. + * Copyright 2009 Jerome Glisse. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: + * Dave Airlie + * Jerome Glisse + */ +#include "drmP.h" +#include "drm.h" +#include "radeon.h" +#include "radeon_drm.h" + +#if __OS_HAS_AGP + +struct radeon_agpmode_quirk { + u32 hostbridge_vendor; + u32 hostbridge_device; + u32 chip_vendor; + u32 chip_device; + u32 subsys_vendor; + u32 subsys_device; + u32 default_mode; +}; + +static struct radeon_agpmode_quirk radeon_agpmode_quirk_list[] = { + /* Intel E7505 Memory Controller Hub / RV350 AR [Radeon 9600XT] Needs AGPMode 4 (deb #515326) */ + { PCI_VENDOR_ID_INTEL, 0x2550, PCI_VENDOR_ID_ATI, 0x4152, 0x1458, 0x4038, 4}, + /* Intel 82865G/PE/P DRAM Controller/Host-Hub / Mobility 9800 Needs AGPMode 4 (deb #462590) */ + { PCI_VENDOR_ID_INTEL, 0x2570, PCI_VENDOR_ID_ATI, 0x4a4e, PCI_VENDOR_ID_DELL, 0x5106, 4}, + /* Intel 82865G/PE/P DRAM Controller/Host-Hub / RV280 [Radeon 9200 SE] Needs AGPMode 4 (lp #300304) */ + { PCI_VENDOR_ID_INTEL, 0x2570, PCI_VENDOR_ID_ATI, 0x5964, + 0x148c, 0x2073, 4}, + /* Intel 82855PM Processor to I/O Controller / Mobility M6 LY Needs AGPMode 1 (deb #467235) */ + { PCI_VENDOR_ID_INTEL, 0x3340, PCI_VENDOR_ID_ATI, 0x4c59, + PCI_VENDOR_ID_IBM, 0x052f, 1}, + /* Intel 82855PM host bridge / Mobility 9600 M10 RV350 Needs AGPMode 1 (lp #195051) */ + { PCI_VENDOR_ID_INTEL, 0x3340, PCI_VENDOR_ID_ATI, 0x4e50, + PCI_VENDOR_ID_IBM, 0x0550, 1}, + /* Intel 82855PM host bridge / Mobility M7 needs AGPMode 1 */ + { PCI_VENDOR_ID_INTEL, 0x3340, PCI_VENDOR_ID_ATI, 0x4c57, + PCI_VENDOR_ID_IBM, 0x0530, 1}, + /* Intel 82855PM host bridge / FireGL Mobility T2 RV350 Needs AGPMode 2 (fdo #20647) */ + { PCI_VENDOR_ID_INTEL, 0x3340, PCI_VENDOR_ID_ATI, 0x4e54, + PCI_VENDOR_ID_IBM, 0x054f, 2}, + /* Intel 82855PM host bridge / Mobility M9+ / VaioPCG-V505DX Needs AGPMode 2 (fdo #17928) */ + { PCI_VENDOR_ID_INTEL, 0x3340, PCI_VENDOR_ID_ATI, 0x5c61, + PCI_VENDOR_ID_SONY, 0x816b, 2}, + /* Intel 82855PM Processor to I/O Controller / Mobility M9+ Needs AGPMode 8 (phoronix forum) */ + { PCI_VENDOR_ID_INTEL, 0x3340, PCI_VENDOR_ID_ATI, 0x5c61, + PCI_VENDOR_ID_SONY, 0x8195, 8}, + /* Intel 82830 830 Chipset Host Bridge / Mobility M6 LY Needs AGPMode 2 (fdo #17360)*/ + { PCI_VENDOR_ID_INTEL, 0x3575, PCI_VENDOR_ID_ATI, 0x4c59, + PCI_VENDOR_ID_DELL, 0x00e3, 2}, + /* Intel 82852/82855 host bridge / Mobility FireGL 9000 R250 Needs AGPMode 1 (lp #296617) */ + { PCI_VENDOR_ID_INTEL, 0x3580, PCI_VENDOR_ID_ATI, 0x4c66, + PCI_VENDOR_ID_DELL, 0x0149, 1}, + /* Intel 82852/82855 host bridge / Mobility 9600 M10 RV350 Needs AGPMode 1 (deb #467460) */ + { PCI_VENDOR_ID_INTEL, 0x3580, PCI_VENDOR_ID_ATI, 0x4e50, + 0x1025, 0x0061, 1}, + /* Intel 82852/82855 host bridge / Mobility 9600 M10 RV350 Needs AGPMode 1 (lp #203007) */ + { PCI_VENDOR_ID_INTEL, 0x3580, PCI_VENDOR_ID_ATI, 0x4e50, + 0x1025, 0x0064, 1}, + /* Intel 82852/82855 host bridge / Mobility 9600 M10 RV350 Needs AGPMode 1 (lp #141551) */ + { PCI_VENDOR_ID_INTEL, 0x3580, PCI_VENDOR_ID_ATI, 0x4e50, + PCI_VENDOR_ID_ASUSTEK, 0x1942, 1}, + /* Intel 82852/82855 host bridge / Mobility 9600/9700 Needs AGPMode 1 (deb #510208) */ + { PCI_VENDOR_ID_INTEL, 0x3580, PCI_VENDOR_ID_ATI, 0x4e50, + 0x10cf, 0x127f, 1}, + /* ASRock K7VT4A+ AGP 8x / ATI Radeon 9250 AGP Needs AGPMode 4 (lp #133192) */ + { 0x1849, 0x3189, PCI_VENDOR_ID_ATI, 0x5960, + 0x1787, 0x5960, 4}, + /* VIA K8M800 Host Bridge / RV280 [Radeon 9200 PRO] Needs AGPMode 4 (fdo #12544) */ + { PCI_VENDOR_ID_VIA, 0x0204, PCI_VENDOR_ID_ATI, 0x5960, + 0x17af, 0x2020, 4}, + /* VIA KT880 Host Bridge / RV350 [Radeon 9550] Needs AGPMode 4 (fdo #19981) */ + { PCI_VENDOR_ID_VIA, 0x0269, PCI_VENDOR_ID_ATI, 0x4153, + PCI_VENDOR_ID_ASUSTEK, 0x003c, 4}, + /* VIA VT8363 Host Bridge / R200 QL [Radeon 8500] Needs AGPMode 2 (lp #141551) */ + { PCI_VENDOR_ID_VIA, 0x0305, PCI_VENDOR_ID_ATI, 0x514c, + PCI_VENDOR_ID_ATI, 0x013a, 2}, + /* VIA VT82C693A Host Bridge / RV280 [Radeon 9200 PRO] Needs AGPMode 2 (deb #515512) */ + { PCI_VENDOR_ID_VIA, 0x0691, PCI_VENDOR_ID_ATI, 0x5960, + PCI_VENDOR_ID_ASUSTEK, 0x004c, 2}, + /* VIA VT82C693A Host Bridge / RV280 [Radeon 9200 PRO] Needs AGPMode 2 */ + { PCI_VENDOR_ID_VIA, 0x0691, PCI_VENDOR_ID_ATI, 0x5960, + PCI_VENDOR_ID_ASUSTEK, 0x0054, 2}, + /* VIA VT8377 Host Bridge / R200 QM [Radeon 9100] Needs AGPMode 4 (deb #461144) */ + { PCI_VENDOR_ID_VIA, 0x3189, PCI_VENDOR_ID_ATI, 0x514d, + 0x174b, 0x7149, 4}, + /* VIA VT8377 Host Bridge / RV280 [Radeon 9200 PRO] Needs AGPMode 4 (lp #312693) */ + { PCI_VENDOR_ID_VIA, 0x3189, PCI_VENDOR_ID_ATI, 0x5960, + 0x1462, 0x0380, 4}, + /* VIA VT8377 Host Bridge / RV280 Needs AGPMode 4 (ati ML) */ + { PCI_VENDOR_ID_VIA, 0x3189, PCI_VENDOR_ID_ATI, 0x5964, + 0x148c, 0x2073, 4}, + /* ATI Host Bridge / RV280 [M9+] Needs AGPMode 1 (phoronix forum) */ + { PCI_VENDOR_ID_ATI, 0xcbb2, PCI_VENDOR_ID_ATI, 0x5c61, + PCI_VENDOR_ID_SONY, 0x8175, 1}, + /* HP Host Bridge / R300 [FireGL X1] Needs AGPMode 2 (fdo #7770) */ + { PCI_VENDOR_ID_HP, 0x122e, PCI_VENDOR_ID_ATI, 0x4e47, + PCI_VENDOR_ID_ATI, 0x0152, 2}, + { 0, 0, 0, 0, 0, 0, 0 }, +}; +#endif + +int radeon_agp_init(struct radeon_device *rdev) +{ +#if __OS_HAS_AGP + struct radeon_agpmode_quirk *p = radeon_agpmode_quirk_list; + struct drm_agp_mode mode; + struct drm_agp_info info; + uint32_t agp_status; + int default_mode; + bool is_v3; + int ret; + + /* Acquire AGP. */ + if (!rdev->ddev->agp->acquired) { + ret = drm_agp_acquire(rdev->ddev); + if (ret) { + DRM_ERROR("Unable to acquire AGP: %d\n", ret); + return ret; + } + } + + ret = drm_agp_info(rdev->ddev, &info); + if (ret) { + DRM_ERROR("Unable to get AGP info: %d\n", ret); + return ret; + } + mode.mode = info.mode; + agp_status = (RREG32(RADEON_AGP_STATUS) | RADEON_AGPv3_MODE) & mode.mode; + is_v3 = !!(agp_status & RADEON_AGPv3_MODE); + + if (is_v3) { + default_mode = (agp_status & RADEON_AGPv3_8X_MODE) ? 8 : 4; + } else { + if (agp_status & RADEON_AGP_4X_MODE) { + default_mode = 4; + } else if (agp_status & RADEON_AGP_2X_MODE) { + default_mode = 2; + } else { + default_mode = 1; + } + } + + /* Apply AGPMode Quirks */ + while (p && p->chip_device != 0) { + if (info.id_vendor == p->hostbridge_vendor && + info.id_device == p->hostbridge_device && + rdev->pdev->vendor == p->chip_vendor && + rdev->pdev->device == p->chip_device && + rdev->pdev->subsystem_vendor == p->subsys_vendor && + rdev->pdev->subsystem_device == p->subsys_device) { + default_mode = p->default_mode; + } + ++p; + } + + if (radeon_agpmode > 0) { + if ((radeon_agpmode < (is_v3 ? 4 : 1)) || + (radeon_agpmode > (is_v3 ? 8 : 4)) || + (radeon_agpmode & (radeon_agpmode - 1))) { + DRM_ERROR("Illegal AGP Mode: %d (valid %s), leaving at %d\n", + radeon_agpmode, is_v3 ? "4, 8" : "1, 2, 4", + default_mode); + radeon_agpmode = default_mode; + } else { + DRM_INFO("AGP mode requested: %d\n", radeon_agpmode); + } + } else { + radeon_agpmode = default_mode; + } + + mode.mode &= ~RADEON_AGP_MODE_MASK; + if (is_v3) { + switch (radeon_agpmode) { + case 8: + mode.mode |= RADEON_AGPv3_8X_MODE; + break; + case 4: + default: + mode.mode |= RADEON_AGPv3_4X_MODE; + break; + } + } else { + switch (radeon_agpmode) { + case 4: + mode.mode |= RADEON_AGP_4X_MODE; + break; + case 2: + mode.mode |= RADEON_AGP_2X_MODE; + break; + case 1: + default: + mode.mode |= RADEON_AGP_1X_MODE; + break; + } + } + + mode.mode &= ~RADEON_AGP_FW_MODE; /* disable fw */ + ret = drm_agp_enable(rdev->ddev, mode); + if (ret) { + DRM_ERROR("Unable to enable AGP (mode = 0x%lx)\n", mode.mode); + return ret; + } + + rdev->mc.agp_base = rdev->ddev->agp->agp_info.aper_base; + rdev->mc.gtt_size = rdev->ddev->agp->agp_info.aper_size << 20; + + /* workaround some hw issues */ + if (rdev->family < CHIP_R200) { + WREG32(RADEON_AGP_CNTL, RREG32(RADEON_AGP_CNTL) | 0x000e0000); + } + return 0; +#else + return 0; +#endif +} + +void radeon_agp_fini(struct radeon_device *rdev) +{ +#if __OS_HAS_AGP + if (rdev->flags & RADEON_IS_AGP) { + if (rdev->ddev->agp && rdev->ddev->agp->acquired) { + drm_agp_release(rdev->ddev); + } + } +#endif +} diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h new file mode 100644 index 000000000000..e2e567395df8 --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -0,0 +1,416 @@ +/* + * Copyright 2008 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * Copyright 2009 Jerome Glisse. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Dave Airlie + * Alex Deucher + * Jerome Glisse + */ +#ifndef __RADEON_ASIC_H__ +#define __RADEON_ASIC_H__ + +/* + * common functions + */ +void radeon_legacy_set_engine_clock(struct radeon_device *rdev, uint32_t eng_clock); +void radeon_legacy_set_clock_gating(struct radeon_device *rdev, int enable); + +void radeon_atom_set_engine_clock(struct radeon_device *rdev, uint32_t eng_clock); +void radeon_atom_set_memory_clock(struct radeon_device *rdev, uint32_t mem_clock); +void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable); + +/* + * r100,rv100,rs100,rv200,rs200,r200,rv250,rs300,rv280 + */ +int r100_init(struct radeon_device *rdev); +uint32_t r100_mm_rreg(struct radeon_device *rdev, uint32_t reg); +void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v); +void r100_errata(struct radeon_device *rdev); +void r100_vram_info(struct radeon_device *rdev); +int r100_gpu_reset(struct radeon_device *rdev); +int r100_mc_init(struct radeon_device *rdev); +void r100_mc_fini(struct radeon_device *rdev); +int r100_wb_init(struct radeon_device *rdev); +void r100_wb_fini(struct radeon_device *rdev); +int r100_gart_enable(struct radeon_device *rdev); +void r100_pci_gart_disable(struct radeon_device *rdev); +void r100_pci_gart_tlb_flush(struct radeon_device *rdev); +int r100_pci_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr); +int r100_cp_init(struct radeon_device *rdev, unsigned ring_size); +void r100_cp_fini(struct radeon_device *rdev); +void r100_cp_disable(struct radeon_device *rdev); +void r100_ring_start(struct radeon_device *rdev); +int r100_irq_set(struct radeon_device *rdev); +int r100_irq_process(struct radeon_device *rdev); +void r100_fence_ring_emit(struct radeon_device *rdev, + struct radeon_fence *fence); +int r100_cs_parse(struct radeon_cs_parser *p); +void r100_pll_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v); +uint32_t r100_pll_rreg(struct radeon_device *rdev, uint32_t reg); +int r100_copy_blit(struct radeon_device *rdev, + uint64_t src_offset, + uint64_t dst_offset, + unsigned num_pages, + struct radeon_fence *fence); + +static struct radeon_asic r100_asic = { + .init = &r100_init, + .errata = &r100_errata, + .vram_info = &r100_vram_info, + .gpu_reset = &r100_gpu_reset, + .mc_init = &r100_mc_init, + .mc_fini = &r100_mc_fini, + .wb_init = &r100_wb_init, + .wb_fini = &r100_wb_fini, + .gart_enable = &r100_gart_enable, + .gart_disable = &r100_pci_gart_disable, + .gart_tlb_flush = &r100_pci_gart_tlb_flush, + .gart_set_page = &r100_pci_gart_set_page, + .cp_init = &r100_cp_init, + .cp_fini = &r100_cp_fini, + .cp_disable = &r100_cp_disable, + .ring_start = &r100_ring_start, + .irq_set = &r100_irq_set, + .irq_process = &r100_irq_process, + .fence_ring_emit = &r100_fence_ring_emit, + .cs_parse = &r100_cs_parse, + .copy_blit = &r100_copy_blit, + .copy_dma = NULL, + .copy = &r100_copy_blit, + .set_engine_clock = &radeon_legacy_set_engine_clock, + .set_memory_clock = NULL, + .set_pcie_lanes = NULL, + .set_clock_gating = &radeon_legacy_set_clock_gating, +}; + + +/* + * r300,r350,rv350,rv380 + */ +int r300_init(struct radeon_device *rdev); +void r300_errata(struct radeon_device *rdev); +void r300_vram_info(struct radeon_device *rdev); +int r300_gpu_reset(struct radeon_device *rdev); +int r300_mc_init(struct radeon_device *rdev); +void r300_mc_fini(struct radeon_device *rdev); +void r300_ring_start(struct radeon_device *rdev); +void r300_fence_ring_emit(struct radeon_device *rdev, + struct radeon_fence *fence); +int r300_cs_parse(struct radeon_cs_parser *p); +int r300_gart_enable(struct radeon_device *rdev); +void rv370_pcie_gart_disable(struct radeon_device *rdev); +void rv370_pcie_gart_tlb_flush(struct radeon_device *rdev); +int rv370_pcie_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr); +uint32_t rv370_pcie_rreg(struct radeon_device *rdev, uint32_t reg); +void rv370_pcie_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v); +void rv370_set_pcie_lanes(struct radeon_device *rdev, int lanes); +int r300_copy_dma(struct radeon_device *rdev, + uint64_t src_offset, + uint64_t dst_offset, + unsigned num_pages, + struct radeon_fence *fence); +static struct radeon_asic r300_asic = { + .init = &r300_init, + .errata = &r300_errata, + .vram_info = &r300_vram_info, + .gpu_reset = &r300_gpu_reset, + .mc_init = &r300_mc_init, + .mc_fini = &r300_mc_fini, + .wb_init = &r100_wb_init, + .wb_fini = &r100_wb_fini, + .gart_enable = &r300_gart_enable, + .gart_disable = &r100_pci_gart_disable, + .gart_tlb_flush = &r100_pci_gart_tlb_flush, + .gart_set_page = &r100_pci_gart_set_page, + .cp_init = &r100_cp_init, + .cp_fini = &r100_cp_fini, + .cp_disable = &r100_cp_disable, + .ring_start = &r300_ring_start, + .irq_set = &r100_irq_set, + .irq_process = &r100_irq_process, + .fence_ring_emit = &r300_fence_ring_emit, + .cs_parse = &r300_cs_parse, + .copy_blit = &r100_copy_blit, + .copy_dma = &r300_copy_dma, + .copy = &r100_copy_blit, + .set_engine_clock = &radeon_legacy_set_engine_clock, + .set_memory_clock = NULL, + .set_pcie_lanes = &rv370_set_pcie_lanes, + .set_clock_gating = &radeon_legacy_set_clock_gating, +}; + +/* + * r420,r423,rv410 + */ +void r420_errata(struct radeon_device *rdev); +void r420_vram_info(struct radeon_device *rdev); +int r420_mc_init(struct radeon_device *rdev); +void r420_mc_fini(struct radeon_device *rdev); +static struct radeon_asic r420_asic = { + .init = &r300_init, + .errata = &r420_errata, + .vram_info = &r420_vram_info, + .gpu_reset = &r300_gpu_reset, + .mc_init = &r420_mc_init, + .mc_fini = &r420_mc_fini, + .wb_init = &r100_wb_init, + .wb_fini = &r100_wb_fini, + .gart_enable = &r300_gart_enable, + .gart_disable = &rv370_pcie_gart_disable, + .gart_tlb_flush = &rv370_pcie_gart_tlb_flush, + .gart_set_page = &rv370_pcie_gart_set_page, + .cp_init = &r100_cp_init, + .cp_fini = &r100_cp_fini, + .cp_disable = &r100_cp_disable, + .ring_start = &r300_ring_start, + .irq_set = &r100_irq_set, + .irq_process = &r100_irq_process, + .fence_ring_emit = &r300_fence_ring_emit, + .cs_parse = &r300_cs_parse, + .copy_blit = &r100_copy_blit, + .copy_dma = &r300_copy_dma, + .copy = &r100_copy_blit, + .set_engine_clock = &radeon_atom_set_engine_clock, + .set_memory_clock = &radeon_atom_set_memory_clock, + .set_pcie_lanes = &rv370_set_pcie_lanes, + .set_clock_gating = &radeon_atom_set_clock_gating, +}; + + +/* + * rs400,rs480 + */ +void rs400_errata(struct radeon_device *rdev); +void rs400_vram_info(struct radeon_device *rdev); +int rs400_mc_init(struct radeon_device *rdev); +void rs400_mc_fini(struct radeon_device *rdev); +int rs400_gart_enable(struct radeon_device *rdev); +void rs400_gart_disable(struct radeon_device *rdev); +void rs400_gart_tlb_flush(struct radeon_device *rdev); +int rs400_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr); +uint32_t rs400_mc_rreg(struct radeon_device *rdev, uint32_t reg); +void rs400_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v); +static struct radeon_asic rs400_asic = { + .init = &r300_init, + .errata = &rs400_errata, + .vram_info = &rs400_vram_info, + .gpu_reset = &r300_gpu_reset, + .mc_init = &rs400_mc_init, + .mc_fini = &rs400_mc_fini, + .wb_init = &r100_wb_init, + .wb_fini = &r100_wb_fini, + .gart_enable = &rs400_gart_enable, + .gart_disable = &rs400_gart_disable, + .gart_tlb_flush = &rs400_gart_tlb_flush, + .gart_set_page = &rs400_gart_set_page, + .cp_init = &r100_cp_init, + .cp_fini = &r100_cp_fini, + .cp_disable = &r100_cp_disable, + .ring_start = &r300_ring_start, + .irq_set = &r100_irq_set, + .irq_process = &r100_irq_process, + .fence_ring_emit = &r300_fence_ring_emit, + .cs_parse = &r300_cs_parse, + .copy_blit = &r100_copy_blit, + .copy_dma = &r300_copy_dma, + .copy = &r100_copy_blit, + .set_engine_clock = &radeon_legacy_set_engine_clock, + .set_memory_clock = NULL, + .set_pcie_lanes = NULL, + .set_clock_gating = &radeon_legacy_set_clock_gating, +}; + + +/* + * rs600. + */ +void rs600_errata(struct radeon_device *rdev); +void rs600_vram_info(struct radeon_device *rdev); +int rs600_mc_init(struct radeon_device *rdev); +void rs600_mc_fini(struct radeon_device *rdev); +int rs600_irq_set(struct radeon_device *rdev); +int rs600_gart_enable(struct radeon_device *rdev); +void rs600_gart_disable(struct radeon_device *rdev); +void rs600_gart_tlb_flush(struct radeon_device *rdev); +int rs600_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr); +uint32_t rs600_mc_rreg(struct radeon_device *rdev, uint32_t reg); +void rs600_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v); +static struct radeon_asic rs600_asic = { + .init = &r300_init, + .errata = &rs600_errata, + .vram_info = &rs600_vram_info, + .gpu_reset = &r300_gpu_reset, + .mc_init = &rs600_mc_init, + .mc_fini = &rs600_mc_fini, + .wb_init = &r100_wb_init, + .wb_fini = &r100_wb_fini, + .gart_enable = &rs600_gart_enable, + .gart_disable = &rs600_gart_disable, + .gart_tlb_flush = &rs600_gart_tlb_flush, + .gart_set_page = &rs600_gart_set_page, + .cp_init = &r100_cp_init, + .cp_fini = &r100_cp_fini, + .cp_disable = &r100_cp_disable, + .ring_start = &r300_ring_start, + .irq_set = &rs600_irq_set, + .irq_process = &r100_irq_process, + .fence_ring_emit = &r300_fence_ring_emit, + .cs_parse = &r300_cs_parse, + .copy_blit = &r100_copy_blit, + .copy_dma = &r300_copy_dma, + .copy = &r100_copy_blit, + .set_engine_clock = &radeon_atom_set_engine_clock, + .set_memory_clock = &radeon_atom_set_memory_clock, + .set_pcie_lanes = NULL, + .set_clock_gating = &radeon_atom_set_clock_gating, +}; + + +/* + * rs690,rs740 + */ +void rs690_errata(struct radeon_device *rdev); +void rs690_vram_info(struct radeon_device *rdev); +int rs690_mc_init(struct radeon_device *rdev); +void rs690_mc_fini(struct radeon_device *rdev); +uint32_t rs690_mc_rreg(struct radeon_device *rdev, uint32_t reg); +void rs690_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v); +static struct radeon_asic rs690_asic = { + .init = &r300_init, + .errata = &rs690_errata, + .vram_info = &rs690_vram_info, + .gpu_reset = &r300_gpu_reset, + .mc_init = &rs690_mc_init, + .mc_fini = &rs690_mc_fini, + .wb_init = &r100_wb_init, + .wb_fini = &r100_wb_fini, + .gart_enable = &rs400_gart_enable, + .gart_disable = &rs400_gart_disable, + .gart_tlb_flush = &rs400_gart_tlb_flush, + .gart_set_page = &rs400_gart_set_page, + .cp_init = &r100_cp_init, + .cp_fini = &r100_cp_fini, + .cp_disable = &r100_cp_disable, + .ring_start = &r300_ring_start, + .irq_set = &rs600_irq_set, + .irq_process = &r100_irq_process, + .fence_ring_emit = &r300_fence_ring_emit, + .cs_parse = &r300_cs_parse, + .copy_blit = &r100_copy_blit, + .copy_dma = &r300_copy_dma, + .copy = &r300_copy_dma, + .set_engine_clock = &radeon_atom_set_engine_clock, + .set_memory_clock = &radeon_atom_set_memory_clock, + .set_pcie_lanes = NULL, + .set_clock_gating = &radeon_atom_set_clock_gating, +}; + + +/* + * rv515 + */ +int rv515_init(struct radeon_device *rdev); +void rv515_errata(struct radeon_device *rdev); +void rv515_vram_info(struct radeon_device *rdev); +int rv515_gpu_reset(struct radeon_device *rdev); +int rv515_mc_init(struct radeon_device *rdev); +void rv515_mc_fini(struct radeon_device *rdev); +uint32_t rv515_mc_rreg(struct radeon_device *rdev, uint32_t reg); +void rv515_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v); +void rv515_ring_start(struct radeon_device *rdev); +uint32_t rv515_pcie_rreg(struct radeon_device *rdev, uint32_t reg); +void rv515_pcie_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v); +static struct radeon_asic rv515_asic = { + .init = &rv515_init, + .errata = &rv515_errata, + .vram_info = &rv515_vram_info, + .gpu_reset = &rv515_gpu_reset, + .mc_init = &rv515_mc_init, + .mc_fini = &rv515_mc_fini, + .wb_init = &r100_wb_init, + .wb_fini = &r100_wb_fini, + .gart_enable = &r300_gart_enable, + .gart_disable = &rv370_pcie_gart_disable, + .gart_tlb_flush = &rv370_pcie_gart_tlb_flush, + .gart_set_page = &rv370_pcie_gart_set_page, + .cp_init = &r100_cp_init, + .cp_fini = &r100_cp_fini, + .cp_disable = &r100_cp_disable, + .ring_start = &rv515_ring_start, + .irq_set = &r100_irq_set, + .irq_process = &r100_irq_process, + .fence_ring_emit = &r300_fence_ring_emit, + .cs_parse = &r300_cs_parse, + .copy_blit = &r100_copy_blit, + .copy_dma = &r300_copy_dma, + .copy = &r100_copy_blit, + .set_engine_clock = &radeon_atom_set_engine_clock, + .set_memory_clock = &radeon_atom_set_memory_clock, + .set_pcie_lanes = &rv370_set_pcie_lanes, + .set_clock_gating = &radeon_atom_set_clock_gating, +}; + + +/* + * r520,rv530,rv560,rv570,r580 + */ +void r520_errata(struct radeon_device *rdev); +void r520_vram_info(struct radeon_device *rdev); +int r520_mc_init(struct radeon_device *rdev); +void r520_mc_fini(struct radeon_device *rdev); +static struct radeon_asic r520_asic = { + .init = &rv515_init, + .errata = &r520_errata, + .vram_info = &r520_vram_info, + .gpu_reset = &rv515_gpu_reset, + .mc_init = &r520_mc_init, + .mc_fini = &r520_mc_fini, + .wb_init = &r100_wb_init, + .wb_fini = &r100_wb_fini, + .gart_enable = &r300_gart_enable, + .gart_disable = &rv370_pcie_gart_disable, + .gart_tlb_flush = &rv370_pcie_gart_tlb_flush, + .gart_set_page = &rv370_pcie_gart_set_page, + .cp_init = &r100_cp_init, + .cp_fini = &r100_cp_fini, + .cp_disable = &r100_cp_disable, + .ring_start = &rv515_ring_start, + .irq_set = &r100_irq_set, + .irq_process = &r100_irq_process, + .fence_ring_emit = &r300_fence_ring_emit, + .cs_parse = &r300_cs_parse, + .copy_blit = &r100_copy_blit, + .copy_dma = &r300_copy_dma, + .copy = &r100_copy_blit, + .set_engine_clock = &radeon_atom_set_engine_clock, + .set_memory_clock = &radeon_atom_set_memory_clock, + .set_pcie_lanes = &rv370_set_pcie_lanes, + .set_clock_gating = &radeon_atom_set_clock_gating, +}; + +/* + * r600,rv610,rv630,rv620,rv635,rv670,rs780,rv770,rv730,rv710 + */ +uint32_t r600_pciep_rreg(struct radeon_device *rdev, uint32_t reg); +void r600_pciep_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v); + +#endif diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c new file mode 100644 index 000000000000..1f5a1a490984 --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -0,0 +1,1296 @@ +/* + * Copyright 2007-8 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Dave Airlie + * Alex Deucher + */ +#include "drmP.h" +#include "radeon_drm.h" +#include "radeon.h" + +#include "atom.h" +#include "atom-bits.h" + +/* from radeon_encoder.c */ +extern uint32_t +radeon_get_encoder_id(struct drm_device *dev, uint32_t supported_device, + uint8_t dac); +extern void radeon_link_encoder_connector(struct drm_device *dev); +extern void +radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_id, + uint32_t supported_device); + +/* from radeon_connector.c */ +extern void +radeon_add_atom_connector(struct drm_device *dev, + uint32_t connector_id, + uint32_t supported_device, + int connector_type, + struct radeon_i2c_bus_rec *i2c_bus, + bool linkb, uint32_t igp_lane_info); + +/* from radeon_legacy_encoder.c */ +extern void +radeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_id, + uint32_t supported_device); + +union atom_supported_devices { + struct _ATOM_SUPPORTED_DEVICES_INFO info; + struct _ATOM_SUPPORTED_DEVICES_INFO_2 info_2; + struct _ATOM_SUPPORTED_DEVICES_INFO_2d1 info_2d1; +}; + +static inline struct radeon_i2c_bus_rec radeon_lookup_gpio(struct drm_device + *dev, uint8_t id) +{ + struct radeon_device *rdev = dev->dev_private; + struct atom_context *ctx = rdev->mode_info.atom_context; + ATOM_GPIO_I2C_ASSIGMENT gpio; + struct radeon_i2c_bus_rec i2c; + int index = GetIndexIntoMasterTable(DATA, GPIO_I2C_Info); + struct _ATOM_GPIO_I2C_INFO *i2c_info; + uint16_t data_offset; + + memset(&i2c, 0, sizeof(struct radeon_i2c_bus_rec)); + i2c.valid = false; + + atom_parse_data_header(ctx, index, NULL, NULL, NULL, &data_offset); + + i2c_info = (struct _ATOM_GPIO_I2C_INFO *)(ctx->bios + data_offset); + + gpio = i2c_info->asGPIO_Info[id]; + + i2c.mask_clk_reg = le16_to_cpu(gpio.usClkMaskRegisterIndex) * 4; + i2c.mask_data_reg = le16_to_cpu(gpio.usDataMaskRegisterIndex) * 4; + i2c.put_clk_reg = le16_to_cpu(gpio.usClkEnRegisterIndex) * 4; + i2c.put_data_reg = le16_to_cpu(gpio.usDataEnRegisterIndex) * 4; + i2c.get_clk_reg = le16_to_cpu(gpio.usClkY_RegisterIndex) * 4; + i2c.get_data_reg = le16_to_cpu(gpio.usDataY_RegisterIndex) * 4; + i2c.a_clk_reg = le16_to_cpu(gpio.usClkA_RegisterIndex) * 4; + i2c.a_data_reg = le16_to_cpu(gpio.usDataA_RegisterIndex) * 4; + i2c.mask_clk_mask = (1 << gpio.ucClkMaskShift); + i2c.mask_data_mask = (1 << gpio.ucDataMaskShift); + i2c.put_clk_mask = (1 << gpio.ucClkEnShift); + i2c.put_data_mask = (1 << gpio.ucDataEnShift); + i2c.get_clk_mask = (1 << gpio.ucClkY_Shift); + i2c.get_data_mask = (1 << gpio.ucDataY_Shift); + i2c.a_clk_mask = (1 << gpio.ucClkA_Shift); + i2c.a_data_mask = (1 << gpio.ucDataA_Shift); + i2c.valid = true; + + return i2c; +} + +static bool radeon_atom_apply_quirks(struct drm_device *dev, + uint32_t supported_device, + int *connector_type, + struct radeon_i2c_bus_rec *i2c_bus) +{ + + /* Asus M2A-VM HDMI board lists the DVI port as HDMI */ + if ((dev->pdev->device == 0x791e) && + (dev->pdev->subsystem_vendor == 0x1043) && + (dev->pdev->subsystem_device == 0x826d)) { + if ((*connector_type == DRM_MODE_CONNECTOR_HDMIA) && + (supported_device == ATOM_DEVICE_DFP3_SUPPORT)) + *connector_type = DRM_MODE_CONNECTOR_DVID; + } + + /* a-bit f-i90hd - ciaranm on #radeonhd - this board has no DVI */ + if ((dev->pdev->device == 0x7941) && + (dev->pdev->subsystem_vendor == 0x147b) && + (dev->pdev->subsystem_device == 0x2412)) { + if (*connector_type == DRM_MODE_CONNECTOR_DVII) + return false; + } + + /* Falcon NW laptop lists vga ddc line for LVDS */ + if ((dev->pdev->device == 0x5653) && + (dev->pdev->subsystem_vendor == 0x1462) && + (dev->pdev->subsystem_device == 0x0291)) { + if (*connector_type == DRM_MODE_CONNECTOR_LVDS) + i2c_bus->valid = false; + } + + /* Funky macbooks */ + if ((dev->pdev->device == 0x71C5) && + (dev->pdev->subsystem_vendor == 0x106b) && + (dev->pdev->subsystem_device == 0x0080)) { + if ((supported_device == ATOM_DEVICE_CRT1_SUPPORT) || + (supported_device == ATOM_DEVICE_DFP2_SUPPORT)) + return false; + } + + /* some BIOSes seem to report DAC on HDMI - they hurt me with their lies */ + if ((*connector_type == DRM_MODE_CONNECTOR_HDMIA) || + (*connector_type == DRM_MODE_CONNECTOR_HDMIB)) { + if (supported_device & (ATOM_DEVICE_CRT_SUPPORT)) { + return false; + } + } + + /* ASUS HD 3600 XT board lists the DVI port as HDMI */ + if ((dev->pdev->device == 0x9598) && + (dev->pdev->subsystem_vendor == 0x1043) && + (dev->pdev->subsystem_device == 0x01da)) { + if (*connector_type == DRM_MODE_CONNECTOR_HDMIB) { + *connector_type = DRM_MODE_CONNECTOR_DVID; + } + } + + return true; +} + +const int supported_devices_connector_convert[] = { + DRM_MODE_CONNECTOR_Unknown, + DRM_MODE_CONNECTOR_VGA, + DRM_MODE_CONNECTOR_DVII, + DRM_MODE_CONNECTOR_DVID, + DRM_MODE_CONNECTOR_DVIA, + DRM_MODE_CONNECTOR_SVIDEO, + DRM_MODE_CONNECTOR_Composite, + DRM_MODE_CONNECTOR_LVDS, + DRM_MODE_CONNECTOR_Unknown, + DRM_MODE_CONNECTOR_Unknown, + DRM_MODE_CONNECTOR_HDMIA, + DRM_MODE_CONNECTOR_HDMIB, + DRM_MODE_CONNECTOR_Unknown, + DRM_MODE_CONNECTOR_Unknown, + DRM_MODE_CONNECTOR_9PinDIN, + DRM_MODE_CONNECTOR_DisplayPort +}; + +const int object_connector_convert[] = { + DRM_MODE_CONNECTOR_Unknown, + DRM_MODE_CONNECTOR_DVII, + DRM_MODE_CONNECTOR_DVII, + DRM_MODE_CONNECTOR_DVID, + DRM_MODE_CONNECTOR_DVID, + DRM_MODE_CONNECTOR_VGA, + DRM_MODE_CONNECTOR_Composite, + DRM_MODE_CONNECTOR_SVIDEO, + DRM_MODE_CONNECTOR_Unknown, + DRM_MODE_CONNECTOR_9PinDIN, + DRM_MODE_CONNECTOR_Unknown, + DRM_MODE_CONNECTOR_HDMIA, + DRM_MODE_CONNECTOR_HDMIB, + DRM_MODE_CONNECTOR_HDMIB, + DRM_MODE_CONNECTOR_LVDS, + DRM_MODE_CONNECTOR_9PinDIN, + DRM_MODE_CONNECTOR_Unknown, + DRM_MODE_CONNECTOR_Unknown, + DRM_MODE_CONNECTOR_Unknown, + DRM_MODE_CONNECTOR_DisplayPort +}; + +bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev) +{ + struct radeon_device *rdev = dev->dev_private; + struct radeon_mode_info *mode_info = &rdev->mode_info; + struct atom_context *ctx = mode_info->atom_context; + int index = GetIndexIntoMasterTable(DATA, Object_Header); + uint16_t size, data_offset; + uint8_t frev, crev, line_mux = 0; + ATOM_CONNECTOR_OBJECT_TABLE *con_obj; + ATOM_DISPLAY_OBJECT_PATH_TABLE *path_obj; + ATOM_OBJECT_HEADER *obj_header; + int i, j, path_size, device_support; + int connector_type; + uint16_t igp_lane_info; + bool linkb; + struct radeon_i2c_bus_rec ddc_bus; + + atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset); + + if (data_offset == 0) + return false; + + if (crev < 2) + return false; + + obj_header = (ATOM_OBJECT_HEADER *) (ctx->bios + data_offset); + path_obj = (ATOM_DISPLAY_OBJECT_PATH_TABLE *) + (ctx->bios + data_offset + + le16_to_cpu(obj_header->usDisplayPathTableOffset)); + con_obj = (ATOM_CONNECTOR_OBJECT_TABLE *) + (ctx->bios + data_offset + + le16_to_cpu(obj_header->usConnectorObjectTableOffset)); + device_support = le16_to_cpu(obj_header->usDeviceSupport); + + path_size = 0; + for (i = 0; i < path_obj->ucNumOfDispPath; i++) { + uint8_t *addr = (uint8_t *) path_obj->asDispPath; + ATOM_DISPLAY_OBJECT_PATH *path; + addr += path_size; + path = (ATOM_DISPLAY_OBJECT_PATH *) addr; + path_size += le16_to_cpu(path->usSize); + linkb = false; + + if (device_support & le16_to_cpu(path->usDeviceTag)) { + uint8_t con_obj_id, con_obj_num, con_obj_type; + + con_obj_id = + (le16_to_cpu(path->usConnObjectId) & OBJECT_ID_MASK) + >> OBJECT_ID_SHIFT; + con_obj_num = + (le16_to_cpu(path->usConnObjectId) & ENUM_ID_MASK) + >> ENUM_ID_SHIFT; + con_obj_type = + (le16_to_cpu(path->usConnObjectId) & + OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT; + + if ((le16_to_cpu(path->usDeviceTag) == + ATOM_DEVICE_TV1_SUPPORT) + || (le16_to_cpu(path->usDeviceTag) == + ATOM_DEVICE_TV2_SUPPORT) + || (le16_to_cpu(path->usDeviceTag) == + ATOM_DEVICE_CV_SUPPORT)) + continue; + + if ((rdev->family == CHIP_RS780) && + (con_obj_id == + CONNECTOR_OBJECT_ID_PCIE_CONNECTOR)) { + uint16_t igp_offset = 0; + ATOM_INTEGRATED_SYSTEM_INFO_V2 *igp_obj; + + index = + GetIndexIntoMasterTable(DATA, + IntegratedSystemInfo); + + atom_parse_data_header(ctx, index, &size, &frev, + &crev, &igp_offset); + + if (crev >= 2) { + igp_obj = + (ATOM_INTEGRATED_SYSTEM_INFO_V2 + *) (ctx->bios + igp_offset); + + if (igp_obj) { + uint32_t slot_config, ct; + + if (con_obj_num == 1) + slot_config = + igp_obj-> + ulDDISlot1Config; + else + slot_config = + igp_obj-> + ulDDISlot2Config; + + ct = (slot_config >> 16) & 0xff; + connector_type = + object_connector_convert + [ct]; + igp_lane_info = + slot_config & 0xffff; + } else + continue; + } else + continue; + } else { + igp_lane_info = 0; + connector_type = + object_connector_convert[con_obj_id]; + } + + if (connector_type == DRM_MODE_CONNECTOR_Unknown) + continue; + + for (j = 0; j < ((le16_to_cpu(path->usSize) - 8) / 2); + j++) { + uint8_t enc_obj_id, enc_obj_num, enc_obj_type; + + enc_obj_id = + (le16_to_cpu(path->usGraphicObjIds[j]) & + OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; + enc_obj_num = + (le16_to_cpu(path->usGraphicObjIds[j]) & + ENUM_ID_MASK) >> ENUM_ID_SHIFT; + enc_obj_type = + (le16_to_cpu(path->usGraphicObjIds[j]) & + OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT; + + /* FIXME: add support for router objects */ + if (enc_obj_type == GRAPH_OBJECT_TYPE_ENCODER) { + if (enc_obj_num == 2) + linkb = true; + else + linkb = false; + + radeon_add_atom_encoder(dev, + enc_obj_id, + le16_to_cpu + (path-> + usDeviceTag)); + + } + } + + /* look up gpio for ddc */ + if ((le16_to_cpu(path->usDeviceTag) & + (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) + == 0) { + for (j = 0; j < con_obj->ucNumberOfObjects; j++) { + if (le16_to_cpu(path->usConnObjectId) == + le16_to_cpu(con_obj->asObjects[j]. + usObjectID)) { + ATOM_COMMON_RECORD_HEADER + *record = + (ATOM_COMMON_RECORD_HEADER + *) + (ctx->bios + data_offset + + le16_to_cpu(con_obj-> + asObjects[j]. + usRecordOffset)); + ATOM_I2C_RECORD *i2c_record; + + while (record->ucRecordType > 0 + && record-> + ucRecordType <= + ATOM_MAX_OBJECT_RECORD_NUMBER) { + DRM_ERROR + ("record type %d\n", + record-> + ucRecordType); + switch (record-> + ucRecordType) { + case ATOM_I2C_RECORD_TYPE: + i2c_record = + (ATOM_I2C_RECORD + *) record; + line_mux = + i2c_record-> + sucI2cId. + bfI2C_LineMux; + break; + } + record = + (ATOM_COMMON_RECORD_HEADER + *) ((char *)record + + + record-> + ucRecordSize); + } + break; + } + } + } else + line_mux = 0; + + if ((le16_to_cpu(path->usDeviceTag) == + ATOM_DEVICE_TV1_SUPPORT) + || (le16_to_cpu(path->usDeviceTag) == + ATOM_DEVICE_TV2_SUPPORT) + || (le16_to_cpu(path->usDeviceTag) == + ATOM_DEVICE_CV_SUPPORT)) + ddc_bus.valid = false; + else + ddc_bus = radeon_lookup_gpio(dev, line_mux); + + radeon_add_atom_connector(dev, + le16_to_cpu(path-> + usConnObjectId), + le16_to_cpu(path-> + usDeviceTag), + connector_type, &ddc_bus, + linkb, igp_lane_info); + + } + } + + radeon_link_encoder_connector(dev); + + return true; +} + +struct bios_connector { + bool valid; + uint8_t line_mux; + uint16_t devices; + int connector_type; + struct radeon_i2c_bus_rec ddc_bus; +}; + +bool radeon_get_atom_connector_info_from_supported_devices_table(struct + drm_device + *dev) +{ + struct radeon_device *rdev = dev->dev_private; + struct radeon_mode_info *mode_info = &rdev->mode_info; + struct atom_context *ctx = mode_info->atom_context; + int index = GetIndexIntoMasterTable(DATA, SupportedDevicesInfo); + uint16_t size, data_offset; + uint8_t frev, crev; + uint16_t device_support; + uint8_t dac; + union atom_supported_devices *supported_devices; + int i, j; + struct bios_connector bios_connectors[ATOM_MAX_SUPPORTED_DEVICE]; + + atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset); + + supported_devices = + (union atom_supported_devices *)(ctx->bios + data_offset); + + device_support = le16_to_cpu(supported_devices->info.usDeviceSupport); + + for (i = 0; i < ATOM_MAX_SUPPORTED_DEVICE; i++) { + ATOM_CONNECTOR_INFO_I2C ci = + supported_devices->info.asConnInfo[i]; + + bios_connectors[i].valid = false; + + if (!(device_support & (1 << i))) { + continue; + } + + if (i == ATOM_DEVICE_CV_INDEX) { + DRM_DEBUG("Skipping Component Video\n"); + continue; + } + + if (i == ATOM_DEVICE_TV1_INDEX) { + DRM_DEBUG("Skipping TV Out\n"); + continue; + } + + bios_connectors[i].connector_type = + supported_devices_connector_convert[ci.sucConnectorInfo. + sbfAccess. + bfConnectorType]; + + if (bios_connectors[i].connector_type == + DRM_MODE_CONNECTOR_Unknown) + continue; + + dac = ci.sucConnectorInfo.sbfAccess.bfAssociatedDAC; + + if ((rdev->family == CHIP_RS690) || + (rdev->family == CHIP_RS740)) { + if ((i == ATOM_DEVICE_DFP2_INDEX) + && (ci.sucI2cId.sbfAccess.bfI2C_LineMux == 2)) + bios_connectors[i].line_mux = + ci.sucI2cId.sbfAccess.bfI2C_LineMux + 1; + else if ((i == ATOM_DEVICE_DFP3_INDEX) + && (ci.sucI2cId.sbfAccess.bfI2C_LineMux == 1)) + bios_connectors[i].line_mux = + ci.sucI2cId.sbfAccess.bfI2C_LineMux + 1; + else + bios_connectors[i].line_mux = + ci.sucI2cId.sbfAccess.bfI2C_LineMux; + } else + bios_connectors[i].line_mux = + ci.sucI2cId.sbfAccess.bfI2C_LineMux; + + /* give tv unique connector ids */ + if (i == ATOM_DEVICE_TV1_INDEX) { + bios_connectors[i].ddc_bus.valid = false; + bios_connectors[i].line_mux = 50; + } else if (i == ATOM_DEVICE_TV2_INDEX) { + bios_connectors[i].ddc_bus.valid = false; + bios_connectors[i].line_mux = 51; + } else if (i == ATOM_DEVICE_CV_INDEX) { + bios_connectors[i].ddc_bus.valid = false; + bios_connectors[i].line_mux = 52; + } else + bios_connectors[i].ddc_bus = + radeon_lookup_gpio(dev, + bios_connectors[i].line_mux); + + /* Always set the connector type to VGA for CRT1/CRT2. if they are + * shared with a DVI port, we'll pick up the DVI connector when we + * merge the outputs. Some bioses incorrectly list VGA ports as DVI. + */ + if (i == ATOM_DEVICE_CRT1_INDEX || i == ATOM_DEVICE_CRT2_INDEX) + bios_connectors[i].connector_type = + DRM_MODE_CONNECTOR_VGA; + + if (!radeon_atom_apply_quirks + (dev, (1 << i), &bios_connectors[i].connector_type, + &bios_connectors[i].ddc_bus)) + continue; + + bios_connectors[i].valid = true; + bios_connectors[i].devices = (1 << i); + + if (ASIC_IS_AVIVO(rdev) || radeon_r4xx_atom) + radeon_add_atom_encoder(dev, + radeon_get_encoder_id(dev, + (1 << i), + dac), + (1 << i)); + else + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id(dev, + (1 << + i), + dac), + (1 << i)); + } + + /* combine shared connectors */ + for (i = 0; i < ATOM_MAX_SUPPORTED_DEVICE; i++) { + if (bios_connectors[i].valid) { + for (j = 0; j < ATOM_MAX_SUPPORTED_DEVICE; j++) { + if (bios_connectors[j].valid && (i != j)) { + if (bios_connectors[i].line_mux == + bios_connectors[j].line_mux) { + if (((bios_connectors[i]. + devices & + (ATOM_DEVICE_DFP_SUPPORT)) + && (bios_connectors[j]. + devices & + (ATOM_DEVICE_CRT_SUPPORT))) + || + ((bios_connectors[j]. + devices & + (ATOM_DEVICE_DFP_SUPPORT)) + && (bios_connectors[i]. + devices & + (ATOM_DEVICE_CRT_SUPPORT)))) { + bios_connectors[i]. + devices |= + bios_connectors[j]. + devices; + bios_connectors[i]. + connector_type = + DRM_MODE_CONNECTOR_DVII; + bios_connectors[j]. + valid = false; + } + } + } + } + } + } + + /* add the connectors */ + for (i = 0; i < ATOM_MAX_SUPPORTED_DEVICE; i++) { + if (bios_connectors[i].valid) + radeon_add_atom_connector(dev, + bios_connectors[i].line_mux, + bios_connectors[i].devices, + bios_connectors[i]. + connector_type, + &bios_connectors[i].ddc_bus, + false, 0); + } + + radeon_link_encoder_connector(dev); + + return true; +} + +union firmware_info { + ATOM_FIRMWARE_INFO info; + ATOM_FIRMWARE_INFO_V1_2 info_12; + ATOM_FIRMWARE_INFO_V1_3 info_13; + ATOM_FIRMWARE_INFO_V1_4 info_14; +}; + +bool radeon_atom_get_clock_info(struct drm_device *dev) +{ + struct radeon_device *rdev = dev->dev_private; + struct radeon_mode_info *mode_info = &rdev->mode_info; + int index = GetIndexIntoMasterTable(DATA, FirmwareInfo); + union firmware_info *firmware_info; + uint8_t frev, crev; + struct radeon_pll *p1pll = &rdev->clock.p1pll; + struct radeon_pll *p2pll = &rdev->clock.p2pll; + struct radeon_pll *spll = &rdev->clock.spll; + struct radeon_pll *mpll = &rdev->clock.mpll; + uint16_t data_offset; + + atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, + &crev, &data_offset); + + firmware_info = + (union firmware_info *)(mode_info->atom_context->bios + + data_offset); + + if (firmware_info) { + /* pixel clocks */ + p1pll->reference_freq = + le16_to_cpu(firmware_info->info.usReferenceClock); + p1pll->reference_div = 0; + + p1pll->pll_out_min = + le16_to_cpu(firmware_info->info.usMinPixelClockPLL_Output); + p1pll->pll_out_max = + le32_to_cpu(firmware_info->info.ulMaxPixelClockPLL_Output); + + if (p1pll->pll_out_min == 0) { + if (ASIC_IS_AVIVO(rdev)) + p1pll->pll_out_min = 64800; + else + p1pll->pll_out_min = 20000; + } + + p1pll->pll_in_min = + le16_to_cpu(firmware_info->info.usMinPixelClockPLL_Input); + p1pll->pll_in_max = + le16_to_cpu(firmware_info->info.usMaxPixelClockPLL_Input); + + *p2pll = *p1pll; + + /* system clock */ + spll->reference_freq = + le16_to_cpu(firmware_info->info.usReferenceClock); + spll->reference_div = 0; + + spll->pll_out_min = + le16_to_cpu(firmware_info->info.usMinEngineClockPLL_Output); + spll->pll_out_max = + le32_to_cpu(firmware_info->info.ulMaxEngineClockPLL_Output); + + /* ??? */ + if (spll->pll_out_min == 0) { + if (ASIC_IS_AVIVO(rdev)) + spll->pll_out_min = 64800; + else + spll->pll_out_min = 20000; + } + + spll->pll_in_min = + le16_to_cpu(firmware_info->info.usMinEngineClockPLL_Input); + spll->pll_in_max = + le16_to_cpu(firmware_info->info.usMaxEngineClockPLL_Input); + + /* memory clock */ + mpll->reference_freq = + le16_to_cpu(firmware_info->info.usReferenceClock); + mpll->reference_div = 0; + + mpll->pll_out_min = + le16_to_cpu(firmware_info->info.usMinMemoryClockPLL_Output); + mpll->pll_out_max = + le32_to_cpu(firmware_info->info.ulMaxMemoryClockPLL_Output); + + /* ??? */ + if (mpll->pll_out_min == 0) { + if (ASIC_IS_AVIVO(rdev)) + mpll->pll_out_min = 64800; + else + mpll->pll_out_min = 20000; + } + + mpll->pll_in_min = + le16_to_cpu(firmware_info->info.usMinMemoryClockPLL_Input); + mpll->pll_in_max = + le16_to_cpu(firmware_info->info.usMaxMemoryClockPLL_Input); + + rdev->clock.default_sclk = + le32_to_cpu(firmware_info->info.ulDefaultEngineClock); + rdev->clock.default_mclk = + le32_to_cpu(firmware_info->info.ulDefaultMemoryClock); + + return true; + } + return false; +} + +struct radeon_encoder_int_tmds *radeon_atombios_get_tmds_info(struct + radeon_encoder + *encoder) +{ + struct drm_device *dev = encoder->base.dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_mode_info *mode_info = &rdev->mode_info; + int index = GetIndexIntoMasterTable(DATA, TMDS_Info); + uint16_t data_offset; + struct _ATOM_TMDS_INFO *tmds_info; + uint8_t frev, crev; + uint16_t maxfreq; + int i; + struct radeon_encoder_int_tmds *tmds = NULL; + + atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, + &crev, &data_offset); + + tmds_info = + (struct _ATOM_TMDS_INFO *)(mode_info->atom_context->bios + + data_offset); + + if (tmds_info) { + tmds = + kzalloc(sizeof(struct radeon_encoder_int_tmds), GFP_KERNEL); + + if (!tmds) + return NULL; + + maxfreq = le16_to_cpu(tmds_info->usMaxFrequency); + for (i = 0; i < 4; i++) { + tmds->tmds_pll[i].freq = + le16_to_cpu(tmds_info->asMiscInfo[i].usFrequency); + tmds->tmds_pll[i].value = + tmds_info->asMiscInfo[i].ucPLL_ChargePump & 0x3f; + tmds->tmds_pll[i].value |= + (tmds_info->asMiscInfo[i]. + ucPLL_VCO_Gain & 0x3f) << 6; + tmds->tmds_pll[i].value |= + (tmds_info->asMiscInfo[i]. + ucPLL_DutyCycle & 0xf) << 12; + tmds->tmds_pll[i].value |= + (tmds_info->asMiscInfo[i]. + ucPLL_VoltageSwing & 0xf) << 16; + + DRM_DEBUG("TMDS PLL From ATOMBIOS %u %x\n", + tmds->tmds_pll[i].freq, + tmds->tmds_pll[i].value); + + if (maxfreq == tmds->tmds_pll[i].freq) { + tmds->tmds_pll[i].freq = 0xffffffff; + break; + } + } + } + return tmds; +} + +union lvds_info { + struct _ATOM_LVDS_INFO info; + struct _ATOM_LVDS_INFO_V12 info_12; +}; + +struct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct + radeon_encoder + *encoder) +{ + struct drm_device *dev = encoder->base.dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_mode_info *mode_info = &rdev->mode_info; + int index = GetIndexIntoMasterTable(DATA, LVDS_Info); + uint16_t data_offset; + union lvds_info *lvds_info; + uint8_t frev, crev; + struct radeon_encoder_atom_dig *lvds = NULL; + + atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, + &crev, &data_offset); + + lvds_info = + (union lvds_info *)(mode_info->atom_context->bios + data_offset); + + if (lvds_info) { + lvds = + kzalloc(sizeof(struct radeon_encoder_atom_dig), GFP_KERNEL); + + if (!lvds) + return NULL; + + lvds->native_mode.dotclock = + le16_to_cpu(lvds_info->info.sLCDTiming.usPixClk) * 10; + lvds->native_mode.panel_xres = + le16_to_cpu(lvds_info->info.sLCDTiming.usHActive); + lvds->native_mode.panel_yres = + le16_to_cpu(lvds_info->info.sLCDTiming.usVActive); + lvds->native_mode.hblank = + le16_to_cpu(lvds_info->info.sLCDTiming.usHBlanking_Time); + lvds->native_mode.hoverplus = + le16_to_cpu(lvds_info->info.sLCDTiming.usHSyncOffset); + lvds->native_mode.hsync_width = + le16_to_cpu(lvds_info->info.sLCDTiming.usHSyncWidth); + lvds->native_mode.vblank = + le16_to_cpu(lvds_info->info.sLCDTiming.usVBlanking_Time); + lvds->native_mode.voverplus = + le16_to_cpu(lvds_info->info.sLCDTiming.usVSyncOffset); + lvds->native_mode.vsync_width = + le16_to_cpu(lvds_info->info.sLCDTiming.usVSyncWidth); + lvds->panel_pwr_delay = + le16_to_cpu(lvds_info->info.usOffDelayInMs); + lvds->lvds_misc = lvds_info->info.ucLVDS_Misc; + + encoder->native_mode = lvds->native_mode; + } + return lvds; +} + +struct radeon_encoder_primary_dac * +radeon_atombios_get_primary_dac_info(struct radeon_encoder *encoder) +{ + struct drm_device *dev = encoder->base.dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_mode_info *mode_info = &rdev->mode_info; + int index = GetIndexIntoMasterTable(DATA, CompassionateData); + uint16_t data_offset; + struct _COMPASSIONATE_DATA *dac_info; + uint8_t frev, crev; + uint8_t bg, dac; + struct radeon_encoder_primary_dac *p_dac = NULL; + + atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, &crev, &data_offset); + + dac_info = (struct _COMPASSIONATE_DATA *)(mode_info->atom_context->bios + data_offset); + + if (dac_info) { + p_dac = kzalloc(sizeof(struct radeon_encoder_primary_dac), GFP_KERNEL); + + if (!p_dac) + return NULL; + + bg = dac_info->ucDAC1_BG_Adjustment; + dac = dac_info->ucDAC1_DAC_Adjustment; + p_dac->ps2_pdac_adj = (bg << 8) | (dac); + + } + return p_dac; +} + +struct radeon_encoder_tv_dac * +radeon_atombios_get_tv_dac_info(struct radeon_encoder *encoder) +{ + struct drm_device *dev = encoder->base.dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_mode_info *mode_info = &rdev->mode_info; + int index = GetIndexIntoMasterTable(DATA, CompassionateData); + uint16_t data_offset; + struct _COMPASSIONATE_DATA *dac_info; + uint8_t frev, crev; + uint8_t bg, dac; + struct radeon_encoder_tv_dac *tv_dac = NULL; + + atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, &crev, &data_offset); + + dac_info = (struct _COMPASSIONATE_DATA *)(mode_info->atom_context->bios + data_offset); + + if (dac_info) { + tv_dac = kzalloc(sizeof(struct radeon_encoder_tv_dac), GFP_KERNEL); + + if (!tv_dac) + return NULL; + + bg = dac_info->ucDAC2_CRT2_BG_Adjustment; + dac = dac_info->ucDAC2_CRT2_DAC_Adjustment; + tv_dac->ps2_tvdac_adj = (bg << 16) | (dac << 20); + + bg = dac_info->ucDAC2_PAL_BG_Adjustment; + dac = dac_info->ucDAC2_PAL_DAC_Adjustment; + tv_dac->pal_tvdac_adj = (bg << 16) | (dac << 20); + + bg = dac_info->ucDAC2_NTSC_BG_Adjustment; + dac = dac_info->ucDAC2_NTSC_DAC_Adjustment; + tv_dac->ntsc_tvdac_adj = (bg << 16) | (dac << 20); + + } + return tv_dac; +} + +void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable) +{ + DYNAMIC_CLOCK_GATING_PS_ALLOCATION args; + int index = GetIndexIntoMasterTable(COMMAND, DynamicClockGating); + + args.ucEnable = enable; + + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); +} + +void radeon_atom_static_pwrmgt_setup(struct radeon_device *rdev, int enable) +{ + ENABLE_ASIC_STATIC_PWR_MGT_PS_ALLOCATION args; + int index = GetIndexIntoMasterTable(COMMAND, EnableASIC_StaticPwrMgt); + + args.ucEnable = enable; + + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); +} + +void radeon_atom_set_engine_clock(struct radeon_device *rdev, + uint32_t eng_clock) +{ + SET_ENGINE_CLOCK_PS_ALLOCATION args; + int index = GetIndexIntoMasterTable(COMMAND, SetEngineClock); + + args.ulTargetEngineClock = eng_clock; /* 10 khz */ + + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); +} + +void radeon_atom_set_memory_clock(struct radeon_device *rdev, + uint32_t mem_clock) +{ + SET_MEMORY_CLOCK_PS_ALLOCATION args; + int index = GetIndexIntoMasterTable(COMMAND, SetMemoryClock); + + if (rdev->flags & RADEON_IS_IGP) + return; + + args.ulTargetMemoryClock = mem_clock; /* 10 khz */ + + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); +} + +void radeon_atom_initialize_bios_scratch_regs(struct drm_device *dev) +{ + struct radeon_device *rdev = dev->dev_private; + uint32_t bios_2_scratch, bios_6_scratch; + + if (rdev->family >= CHIP_R600) { + bios_2_scratch = RREG32(R600_BIOS_0_SCRATCH); + bios_6_scratch = RREG32(R600_BIOS_6_SCRATCH); + } else { + bios_2_scratch = RREG32(RADEON_BIOS_0_SCRATCH); + bios_6_scratch = RREG32(RADEON_BIOS_6_SCRATCH); + } + + /* let the bios control the backlight */ + bios_2_scratch &= ~ATOM_S2_VRI_BRIGHT_ENABLE; + + /* tell the bios not to handle mode switching */ + bios_6_scratch |= (ATOM_S6_ACC_BLOCK_DISPLAY_SWITCH | ATOM_S6_ACC_MODE); + + if (rdev->family >= CHIP_R600) { + WREG32(R600_BIOS_2_SCRATCH, bios_2_scratch); + WREG32(R600_BIOS_6_SCRATCH, bios_6_scratch); + } else { + WREG32(RADEON_BIOS_2_SCRATCH, bios_2_scratch); + WREG32(RADEON_BIOS_6_SCRATCH, bios_6_scratch); + } + +} + +void radeon_atom_output_lock(struct drm_encoder *encoder, bool lock) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + uint32_t bios_6_scratch; + + if (rdev->family >= CHIP_R600) + bios_6_scratch = RREG32(R600_BIOS_6_SCRATCH); + else + bios_6_scratch = RREG32(RADEON_BIOS_6_SCRATCH); + + if (lock) + bios_6_scratch |= ATOM_S6_CRITICAL_STATE; + else + bios_6_scratch &= ~ATOM_S6_CRITICAL_STATE; + + if (rdev->family >= CHIP_R600) + WREG32(R600_BIOS_6_SCRATCH, bios_6_scratch); + else + WREG32(RADEON_BIOS_6_SCRATCH, bios_6_scratch); +} + +/* at some point we may want to break this out into individual functions */ +void +radeon_atombios_connected_scratch_regs(struct drm_connector *connector, + struct drm_encoder *encoder, + bool connected) +{ + struct drm_device *dev = connector->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_connector *radeon_connector = + to_radeon_connector(connector); + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + uint32_t bios_0_scratch, bios_3_scratch, bios_6_scratch; + + if (rdev->family >= CHIP_R600) { + bios_0_scratch = RREG32(R600_BIOS_0_SCRATCH); + bios_3_scratch = RREG32(R600_BIOS_3_SCRATCH); + bios_6_scratch = RREG32(R600_BIOS_6_SCRATCH); + } else { + bios_0_scratch = RREG32(RADEON_BIOS_0_SCRATCH); + bios_3_scratch = RREG32(RADEON_BIOS_3_SCRATCH); + bios_6_scratch = RREG32(RADEON_BIOS_6_SCRATCH); + } + + if ((radeon_encoder->devices & ATOM_DEVICE_TV1_SUPPORT) && + (radeon_connector->devices & ATOM_DEVICE_TV1_SUPPORT)) { + if (connected) { + DRM_DEBUG("TV1 connected\n"); + bios_3_scratch |= ATOM_S3_TV1_ACTIVE; + bios_6_scratch |= ATOM_S6_ACC_REQ_TV1; + } else { + DRM_DEBUG("TV1 disconnected\n"); + bios_0_scratch &= ~ATOM_S0_TV1_MASK; + bios_3_scratch &= ~ATOM_S3_TV1_ACTIVE; + bios_6_scratch &= ~ATOM_S6_ACC_REQ_TV1; + } + } + if ((radeon_encoder->devices & ATOM_DEVICE_CV_SUPPORT) && + (radeon_connector->devices & ATOM_DEVICE_CV_SUPPORT)) { + if (connected) { + DRM_DEBUG("CV connected\n"); + bios_3_scratch |= ATOM_S3_CV_ACTIVE; + bios_6_scratch |= ATOM_S6_ACC_REQ_CV; + } else { + DRM_DEBUG("CV disconnected\n"); + bios_0_scratch &= ~ATOM_S0_CV_MASK; + bios_3_scratch &= ~ATOM_S3_CV_ACTIVE; + bios_6_scratch &= ~ATOM_S6_ACC_REQ_CV; + } + } + if ((radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) && + (radeon_connector->devices & ATOM_DEVICE_LCD1_SUPPORT)) { + if (connected) { + DRM_DEBUG("LCD1 connected\n"); + bios_0_scratch |= ATOM_S0_LCD1; + bios_3_scratch |= ATOM_S3_LCD1_ACTIVE; + bios_6_scratch |= ATOM_S6_ACC_REQ_LCD1; + } else { + DRM_DEBUG("LCD1 disconnected\n"); + bios_0_scratch &= ~ATOM_S0_LCD1; + bios_3_scratch &= ~ATOM_S3_LCD1_ACTIVE; + bios_6_scratch &= ~ATOM_S6_ACC_REQ_LCD1; + } + } + if ((radeon_encoder->devices & ATOM_DEVICE_CRT1_SUPPORT) && + (radeon_connector->devices & ATOM_DEVICE_CRT1_SUPPORT)) { + if (connected) { + DRM_DEBUG("CRT1 connected\n"); + bios_0_scratch |= ATOM_S0_CRT1_COLOR; + bios_3_scratch |= ATOM_S3_CRT1_ACTIVE; + bios_6_scratch |= ATOM_S6_ACC_REQ_CRT1; + } else { + DRM_DEBUG("CRT1 disconnected\n"); + bios_0_scratch &= ~ATOM_S0_CRT1_MASK; + bios_3_scratch &= ~ATOM_S3_CRT1_ACTIVE; + bios_6_scratch &= ~ATOM_S6_ACC_REQ_CRT1; + } + } + if ((radeon_encoder->devices & ATOM_DEVICE_CRT2_SUPPORT) && + (radeon_connector->devices & ATOM_DEVICE_CRT2_SUPPORT)) { + if (connected) { + DRM_DEBUG("CRT2 connected\n"); + bios_0_scratch |= ATOM_S0_CRT2_COLOR; + bios_3_scratch |= ATOM_S3_CRT2_ACTIVE; + bios_6_scratch |= ATOM_S6_ACC_REQ_CRT2; + } else { + DRM_DEBUG("CRT2 disconnected\n"); + bios_0_scratch &= ~ATOM_S0_CRT2_MASK; + bios_3_scratch &= ~ATOM_S3_CRT2_ACTIVE; + bios_6_scratch &= ~ATOM_S6_ACC_REQ_CRT2; + } + } + if ((radeon_encoder->devices & ATOM_DEVICE_DFP1_SUPPORT) && + (radeon_connector->devices & ATOM_DEVICE_DFP1_SUPPORT)) { + if (connected) { + DRM_DEBUG("DFP1 connected\n"); + bios_0_scratch |= ATOM_S0_DFP1; + bios_3_scratch |= ATOM_S3_DFP1_ACTIVE; + bios_6_scratch |= ATOM_S6_ACC_REQ_DFP1; + } else { + DRM_DEBUG("DFP1 disconnected\n"); + bios_0_scratch &= ~ATOM_S0_DFP1; + bios_3_scratch &= ~ATOM_S3_DFP1_ACTIVE; + bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP1; + } + } + if ((radeon_encoder->devices & ATOM_DEVICE_DFP2_SUPPORT) && + (radeon_connector->devices & ATOM_DEVICE_DFP2_SUPPORT)) { + if (connected) { + DRM_DEBUG("DFP2 connected\n"); + bios_0_scratch |= ATOM_S0_DFP2; + bios_3_scratch |= ATOM_S3_DFP2_ACTIVE; + bios_6_scratch |= ATOM_S6_ACC_REQ_DFP2; + } else { + DRM_DEBUG("DFP2 disconnected\n"); + bios_0_scratch &= ~ATOM_S0_DFP2; + bios_3_scratch &= ~ATOM_S3_DFP2_ACTIVE; + bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP2; + } + } + if ((radeon_encoder->devices & ATOM_DEVICE_DFP3_SUPPORT) && + (radeon_connector->devices & ATOM_DEVICE_DFP3_SUPPORT)) { + if (connected) { + DRM_DEBUG("DFP3 connected\n"); + bios_0_scratch |= ATOM_S0_DFP3; + bios_3_scratch |= ATOM_S3_DFP3_ACTIVE; + bios_6_scratch |= ATOM_S6_ACC_REQ_DFP3; + } else { + DRM_DEBUG("DFP3 disconnected\n"); + bios_0_scratch &= ~ATOM_S0_DFP3; + bios_3_scratch &= ~ATOM_S3_DFP3_ACTIVE; + bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP3; + } + } + if ((radeon_encoder->devices & ATOM_DEVICE_DFP4_SUPPORT) && + (radeon_connector->devices & ATOM_DEVICE_DFP4_SUPPORT)) { + if (connected) { + DRM_DEBUG("DFP4 connected\n"); + bios_0_scratch |= ATOM_S0_DFP4; + bios_3_scratch |= ATOM_S3_DFP4_ACTIVE; + bios_6_scratch |= ATOM_S6_ACC_REQ_DFP4; + } else { + DRM_DEBUG("DFP4 disconnected\n"); + bios_0_scratch &= ~ATOM_S0_DFP4; + bios_3_scratch &= ~ATOM_S3_DFP4_ACTIVE; + bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP4; + } + } + if ((radeon_encoder->devices & ATOM_DEVICE_DFP5_SUPPORT) && + (radeon_connector->devices & ATOM_DEVICE_DFP5_SUPPORT)) { + if (connected) { + DRM_DEBUG("DFP5 connected\n"); + bios_0_scratch |= ATOM_S0_DFP5; + bios_3_scratch |= ATOM_S3_DFP5_ACTIVE; + bios_6_scratch |= ATOM_S6_ACC_REQ_DFP5; + } else { + DRM_DEBUG("DFP5 disconnected\n"); + bios_0_scratch &= ~ATOM_S0_DFP5; + bios_3_scratch &= ~ATOM_S3_DFP5_ACTIVE; + bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP5; + } + } + + if (rdev->family >= CHIP_R600) { + WREG32(R600_BIOS_0_SCRATCH, bios_0_scratch); + WREG32(R600_BIOS_3_SCRATCH, bios_3_scratch); + WREG32(R600_BIOS_6_SCRATCH, bios_6_scratch); + } else { + WREG32(RADEON_BIOS_0_SCRATCH, bios_0_scratch); + WREG32(RADEON_BIOS_3_SCRATCH, bios_3_scratch); + WREG32(RADEON_BIOS_6_SCRATCH, bios_6_scratch); + } +} + +void +radeon_atombios_encoder_crtc_scratch_regs(struct drm_encoder *encoder, int crtc) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + uint32_t bios_3_scratch; + + if (rdev->family >= CHIP_R600) + bios_3_scratch = RREG32(R600_BIOS_3_SCRATCH); + else + bios_3_scratch = RREG32(RADEON_BIOS_3_SCRATCH); + + if (radeon_encoder->devices & ATOM_DEVICE_TV1_SUPPORT) { + bios_3_scratch &= ~ATOM_S3_TV1_CRTC_ACTIVE; + bios_3_scratch |= (crtc << 18); + } + if (radeon_encoder->devices & ATOM_DEVICE_CV_SUPPORT) { + bios_3_scratch &= ~ATOM_S3_CV_CRTC_ACTIVE; + bios_3_scratch |= (crtc << 24); + } + if (radeon_encoder->devices & ATOM_DEVICE_CRT1_SUPPORT) { + bios_3_scratch &= ~ATOM_S3_CRT1_CRTC_ACTIVE; + bios_3_scratch |= (crtc << 16); + } + if (radeon_encoder->devices & ATOM_DEVICE_CRT2_SUPPORT) { + bios_3_scratch &= ~ATOM_S3_CRT2_CRTC_ACTIVE; + bios_3_scratch |= (crtc << 20); + } + if (radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) { + bios_3_scratch &= ~ATOM_S3_LCD1_CRTC_ACTIVE; + bios_3_scratch |= (crtc << 17); + } + if (radeon_encoder->devices & ATOM_DEVICE_DFP1_SUPPORT) { + bios_3_scratch &= ~ATOM_S3_DFP1_CRTC_ACTIVE; + bios_3_scratch |= (crtc << 19); + } + if (radeon_encoder->devices & ATOM_DEVICE_DFP2_SUPPORT) { + bios_3_scratch &= ~ATOM_S3_DFP2_CRTC_ACTIVE; + bios_3_scratch |= (crtc << 23); + } + if (radeon_encoder->devices & ATOM_DEVICE_DFP3_SUPPORT) { + bios_3_scratch &= ~ATOM_S3_DFP3_CRTC_ACTIVE; + bios_3_scratch |= (crtc << 25); + } + + if (rdev->family >= CHIP_R600) + WREG32(R600_BIOS_3_SCRATCH, bios_3_scratch); + else + WREG32(RADEON_BIOS_3_SCRATCH, bios_3_scratch); +} + +void +radeon_atombios_encoder_dpms_scratch_regs(struct drm_encoder *encoder, bool on) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + uint32_t bios_2_scratch; + + if (rdev->family >= CHIP_R600) + bios_2_scratch = RREG32(R600_BIOS_2_SCRATCH); + else + bios_2_scratch = RREG32(RADEON_BIOS_2_SCRATCH); + + if (radeon_encoder->devices & ATOM_DEVICE_TV1_SUPPORT) { + if (on) + bios_2_scratch &= ~ATOM_S2_TV1_DPMS_STATE; + else + bios_2_scratch |= ATOM_S2_TV1_DPMS_STATE; + } + if (radeon_encoder->devices & ATOM_DEVICE_CV_SUPPORT) { + if (on) + bios_2_scratch &= ~ATOM_S2_CV_DPMS_STATE; + else + bios_2_scratch |= ATOM_S2_CV_DPMS_STATE; + } + if (radeon_encoder->devices & ATOM_DEVICE_CRT1_SUPPORT) { + if (on) + bios_2_scratch &= ~ATOM_S2_CRT1_DPMS_STATE; + else + bios_2_scratch |= ATOM_S2_CRT1_DPMS_STATE; + } + if (radeon_encoder->devices & ATOM_DEVICE_CRT2_SUPPORT) { + if (on) + bios_2_scratch &= ~ATOM_S2_CRT2_DPMS_STATE; + else + bios_2_scratch |= ATOM_S2_CRT2_DPMS_STATE; + } + if (radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) { + if (on) + bios_2_scratch &= ~ATOM_S2_LCD1_DPMS_STATE; + else + bios_2_scratch |= ATOM_S2_LCD1_DPMS_STATE; + } + if (radeon_encoder->devices & ATOM_DEVICE_DFP1_SUPPORT) { + if (on) + bios_2_scratch &= ~ATOM_S2_DFP1_DPMS_STATE; + else + bios_2_scratch |= ATOM_S2_DFP1_DPMS_STATE; + } + if (radeon_encoder->devices & ATOM_DEVICE_DFP2_SUPPORT) { + if (on) + bios_2_scratch &= ~ATOM_S2_DFP2_DPMS_STATE; + else + bios_2_scratch |= ATOM_S2_DFP2_DPMS_STATE; + } + if (radeon_encoder->devices & ATOM_DEVICE_DFP3_SUPPORT) { + if (on) + bios_2_scratch &= ~ATOM_S2_DFP3_DPMS_STATE; + else + bios_2_scratch |= ATOM_S2_DFP3_DPMS_STATE; + } + if (radeon_encoder->devices & ATOM_DEVICE_DFP4_SUPPORT) { + if (on) + bios_2_scratch &= ~ATOM_S2_DFP4_DPMS_STATE; + else + bios_2_scratch |= ATOM_S2_DFP4_DPMS_STATE; + } + if (radeon_encoder->devices & ATOM_DEVICE_DFP5_SUPPORT) { + if (on) + bios_2_scratch &= ~ATOM_S2_DFP5_DPMS_STATE; + else + bios_2_scratch |= ATOM_S2_DFP5_DPMS_STATE; + } + + if (rdev->family >= CHIP_R600) + WREG32(R600_BIOS_2_SCRATCH, bios_2_scratch); + else + WREG32(RADEON_BIOS_2_SCRATCH, bios_2_scratch); +} diff --git a/drivers/gpu/drm/radeon/radeon_benchmark.c b/drivers/gpu/drm/radeon/radeon_benchmark.c new file mode 100644 index 000000000000..c44403a2ca76 --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_benchmark.c @@ -0,0 +1,133 @@ +/* + * Copyright 2009 Jerome Glisse. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Jerome Glisse + */ +#include +#include +#include "radeon_reg.h" +#include "radeon.h" + +void radeon_benchmark_move(struct radeon_device *rdev, unsigned bsize, + unsigned sdomain, unsigned ddomain) +{ + struct radeon_object *dobj = NULL; + struct radeon_object *sobj = NULL; + struct radeon_fence *fence = NULL; + uint64_t saddr, daddr; + unsigned long start_jiffies; + unsigned long end_jiffies; + unsigned long time; + unsigned i, n, size; + int r; + + size = bsize; + n = 1024; + r = radeon_object_create(rdev, NULL, size, true, sdomain, false, &sobj); + if (r) { + goto out_cleanup; + } + r = radeon_object_pin(sobj, sdomain, &saddr); + if (r) { + goto out_cleanup; + } + r = radeon_object_create(rdev, NULL, size, true, ddomain, false, &dobj); + if (r) { + goto out_cleanup; + } + r = radeon_object_pin(dobj, ddomain, &daddr); + if (r) { + goto out_cleanup; + } + start_jiffies = jiffies; + for (i = 0; i < n; i++) { + r = radeon_fence_create(rdev, &fence); + if (r) { + goto out_cleanup; + } + r = radeon_copy_dma(rdev, saddr, daddr, size >> 14, fence); + if (r) { + goto out_cleanup; + } + r = radeon_fence_wait(fence, false); + if (r) { + goto out_cleanup; + } + radeon_fence_unref(&fence); + } + end_jiffies = jiffies; + time = end_jiffies - start_jiffies; + time = jiffies_to_msecs(time); + if (time > 0) { + i = ((n * size) >> 10) / time; + printk(KERN_INFO "radeon: dma %u bo moves of %ukb from %d to %d" + " in %lums (%ukb/ms %ukb/s %uM/s)\n", n, size >> 10, + sdomain, ddomain, time, i, i * 1000, (i * 1000) / 1024); + } + start_jiffies = jiffies; + for (i = 0; i < n; i++) { + r = radeon_fence_create(rdev, &fence); + if (r) { + goto out_cleanup; + } + r = radeon_copy_blit(rdev, saddr, daddr, size >> 14, fence); + if (r) { + goto out_cleanup; + } + r = radeon_fence_wait(fence, false); + if (r) { + goto out_cleanup; + } + radeon_fence_unref(&fence); + } + end_jiffies = jiffies; + time = end_jiffies - start_jiffies; + time = jiffies_to_msecs(time); + if (time > 0) { + i = ((n * size) >> 10) / time; + printk(KERN_INFO "radeon: blit %u bo moves of %ukb from %d to %d" + " in %lums (%ukb/ms %ukb/s %uM/s)\n", n, size >> 10, + sdomain, ddomain, time, i, i * 1000, (i * 1000) / 1024); + } +out_cleanup: + if (sobj) { + radeon_object_unpin(sobj); + radeon_object_unref(&sobj); + } + if (dobj) { + radeon_object_unpin(dobj); + radeon_object_unref(&dobj); + } + if (fence) { + radeon_fence_unref(&fence); + } + if (r) { + printk(KERN_WARNING "Error while benchmarking BO move.\n"); + } +} + +void radeon_benchmark(struct radeon_device *rdev) +{ + radeon_benchmark_move(rdev, 1024*1024, RADEON_GEM_DOMAIN_GTT, + RADEON_GEM_DOMAIN_VRAM); + radeon_benchmark_move(rdev, 1024*1024, RADEON_GEM_DOMAIN_VRAM, + RADEON_GEM_DOMAIN_GTT); +} diff --git a/drivers/gpu/drm/radeon/radeon_bios.c b/drivers/gpu/drm/radeon/radeon_bios.c new file mode 100644 index 000000000000..96e37a6e7ce4 --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_bios.c @@ -0,0 +1,390 @@ +/* + * Copyright 2008 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * Copyright 2009 Jerome Glisse. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Dave Airlie + * Alex Deucher + * Jerome Glisse + */ +#include "drmP.h" +#include "radeon_reg.h" +#include "radeon.h" +#include "atom.h" + +/* + * BIOS. + */ +static bool radeon_read_bios(struct radeon_device *rdev) +{ + uint8_t __iomem *bios; + size_t size; + + rdev->bios = NULL; + bios = pci_map_rom(rdev->pdev, &size); + if (!bios) { + return false; + } + + if (size == 0 || bios[0] != 0x55 || bios[1] != 0xaa) { + pci_unmap_rom(rdev->pdev, bios); + return false; + } + rdev->bios = kmalloc(size, GFP_KERNEL); + if (rdev->bios == NULL) { + pci_unmap_rom(rdev->pdev, bios); + return false; + } + memcpy(rdev->bios, bios, size); + pci_unmap_rom(rdev->pdev, bios); + return true; +} + +static bool r700_read_disabled_bios(struct radeon_device *rdev) +{ + uint32_t viph_control; + uint32_t bus_cntl; + uint32_t d1vga_control; + uint32_t d2vga_control; + uint32_t vga_render_control; + uint32_t rom_cntl; + uint32_t cg_spll_func_cntl = 0; + uint32_t cg_spll_status; + bool r; + + viph_control = RREG32(RADEON_VIPH_CONTROL); + bus_cntl = RREG32(RADEON_BUS_CNTL); + d1vga_control = RREG32(AVIVO_D1VGA_CONTROL); + d2vga_control = RREG32(AVIVO_D2VGA_CONTROL); + vga_render_control = RREG32(AVIVO_VGA_RENDER_CONTROL); + rom_cntl = RREG32(R600_ROM_CNTL); + + /* disable VIP */ + WREG32(RADEON_VIPH_CONTROL, (viph_control & ~RADEON_VIPH_EN)); + /* enable the rom */ + WREG32(RADEON_BUS_CNTL, (bus_cntl & ~RADEON_BUS_BIOS_DIS_ROM)); + /* Disable VGA mode */ + WREG32(AVIVO_D1VGA_CONTROL, + (d1vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE | + AVIVO_DVGA_CONTROL_TIMING_SELECT))); + WREG32(AVIVO_D2VGA_CONTROL, + (d2vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE | + AVIVO_DVGA_CONTROL_TIMING_SELECT))); + WREG32(AVIVO_VGA_RENDER_CONTROL, + (vga_render_control & ~AVIVO_VGA_VSTATUS_CNTL_MASK)); + + if (rdev->family == CHIP_RV730) { + cg_spll_func_cntl = RREG32(R600_CG_SPLL_FUNC_CNTL); + + /* enable bypass mode */ + WREG32(R600_CG_SPLL_FUNC_CNTL, (cg_spll_func_cntl | + R600_SPLL_BYPASS_EN)); + + /* wait for SPLL_CHG_STATUS to change to 1 */ + cg_spll_status = 0; + while (!(cg_spll_status & R600_SPLL_CHG_STATUS)) + cg_spll_status = RREG32(R600_CG_SPLL_STATUS); + + WREG32(R600_ROM_CNTL, (rom_cntl & ~R600_SCK_OVERWRITE)); + } else + WREG32(R600_ROM_CNTL, (rom_cntl | R600_SCK_OVERWRITE)); + + r = radeon_read_bios(rdev); + + /* restore regs */ + if (rdev->family == CHIP_RV730) { + WREG32(R600_CG_SPLL_FUNC_CNTL, cg_spll_func_cntl); + + /* wait for SPLL_CHG_STATUS to change to 1 */ + cg_spll_status = 0; + while (!(cg_spll_status & R600_SPLL_CHG_STATUS)) + cg_spll_status = RREG32(R600_CG_SPLL_STATUS); + } + WREG32(RADEON_VIPH_CONTROL, viph_control); + WREG32(RADEON_BUS_CNTL, bus_cntl); + WREG32(AVIVO_D1VGA_CONTROL, d1vga_control); + WREG32(AVIVO_D2VGA_CONTROL, d2vga_control); + WREG32(AVIVO_VGA_RENDER_CONTROL, vga_render_control); + WREG32(R600_ROM_CNTL, rom_cntl); + return r; +} + +static bool r600_read_disabled_bios(struct radeon_device *rdev) +{ + uint32_t viph_control; + uint32_t bus_cntl; + uint32_t d1vga_control; + uint32_t d2vga_control; + uint32_t vga_render_control; + uint32_t rom_cntl; + uint32_t general_pwrmgt; + uint32_t low_vid_lower_gpio_cntl; + uint32_t medium_vid_lower_gpio_cntl; + uint32_t high_vid_lower_gpio_cntl; + uint32_t ctxsw_vid_lower_gpio_cntl; + uint32_t lower_gpio_enable; + bool r; + + viph_control = RREG32(RADEON_VIPH_CONTROL); + bus_cntl = RREG32(RADEON_BUS_CNTL); + d1vga_control = RREG32(AVIVO_D1VGA_CONTROL); + d2vga_control = RREG32(AVIVO_D2VGA_CONTROL); + vga_render_control = RREG32(AVIVO_VGA_RENDER_CONTROL); + rom_cntl = RREG32(R600_ROM_CNTL); + general_pwrmgt = RREG32(R600_GENERAL_PWRMGT); + low_vid_lower_gpio_cntl = RREG32(R600_LOW_VID_LOWER_GPIO_CNTL); + medium_vid_lower_gpio_cntl = RREG32(R600_MEDIUM_VID_LOWER_GPIO_CNTL); + high_vid_lower_gpio_cntl = RREG32(R600_HIGH_VID_LOWER_GPIO_CNTL); + ctxsw_vid_lower_gpio_cntl = RREG32(R600_CTXSW_VID_LOWER_GPIO_CNTL); + lower_gpio_enable = RREG32(R600_LOWER_GPIO_ENABLE); + + /* disable VIP */ + WREG32(RADEON_VIPH_CONTROL, (viph_control & ~RADEON_VIPH_EN)); + /* enable the rom */ + WREG32(RADEON_BUS_CNTL, (bus_cntl & ~RADEON_BUS_BIOS_DIS_ROM)); + /* Disable VGA mode */ + WREG32(AVIVO_D1VGA_CONTROL, + (d1vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE | + AVIVO_DVGA_CONTROL_TIMING_SELECT))); + WREG32(AVIVO_D2VGA_CONTROL, + (d2vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE | + AVIVO_DVGA_CONTROL_TIMING_SELECT))); + WREG32(AVIVO_VGA_RENDER_CONTROL, + (vga_render_control & ~AVIVO_VGA_VSTATUS_CNTL_MASK)); + + WREG32(R600_ROM_CNTL, + ((rom_cntl & ~R600_SCK_PRESCALE_CRYSTAL_CLK_MASK) | + (1 << R600_SCK_PRESCALE_CRYSTAL_CLK_SHIFT) | + R600_SCK_OVERWRITE)); + + WREG32(R600_GENERAL_PWRMGT, (general_pwrmgt & ~R600_OPEN_DRAIN_PADS)); + WREG32(R600_LOW_VID_LOWER_GPIO_CNTL, + (low_vid_lower_gpio_cntl & ~0x400)); + WREG32(R600_MEDIUM_VID_LOWER_GPIO_CNTL, + (medium_vid_lower_gpio_cntl & ~0x400)); + WREG32(R600_HIGH_VID_LOWER_GPIO_CNTL, + (high_vid_lower_gpio_cntl & ~0x400)); + WREG32(R600_CTXSW_VID_LOWER_GPIO_CNTL, + (ctxsw_vid_lower_gpio_cntl & ~0x400)); + WREG32(R600_LOWER_GPIO_ENABLE, (lower_gpio_enable | 0x400)); + + r = radeon_read_bios(rdev); + + /* restore regs */ + WREG32(RADEON_VIPH_CONTROL, viph_control); + WREG32(RADEON_BUS_CNTL, bus_cntl); + WREG32(AVIVO_D1VGA_CONTROL, d1vga_control); + WREG32(AVIVO_D2VGA_CONTROL, d2vga_control); + WREG32(AVIVO_VGA_RENDER_CONTROL, vga_render_control); + WREG32(R600_ROM_CNTL, rom_cntl); + WREG32(R600_GENERAL_PWRMGT, general_pwrmgt); + WREG32(R600_LOW_VID_LOWER_GPIO_CNTL, low_vid_lower_gpio_cntl); + WREG32(R600_MEDIUM_VID_LOWER_GPIO_CNTL, medium_vid_lower_gpio_cntl); + WREG32(R600_HIGH_VID_LOWER_GPIO_CNTL, high_vid_lower_gpio_cntl); + WREG32(R600_CTXSW_VID_LOWER_GPIO_CNTL, ctxsw_vid_lower_gpio_cntl); + WREG32(R600_LOWER_GPIO_ENABLE, lower_gpio_enable); + return r; +} + +static bool avivo_read_disabled_bios(struct radeon_device *rdev) +{ + uint32_t seprom_cntl1; + uint32_t viph_control; + uint32_t bus_cntl; + uint32_t d1vga_control; + uint32_t d2vga_control; + uint32_t vga_render_control; + uint32_t gpiopad_a; + uint32_t gpiopad_en; + uint32_t gpiopad_mask; + bool r; + + seprom_cntl1 = RREG32(RADEON_SEPROM_CNTL1); + viph_control = RREG32(RADEON_VIPH_CONTROL); + bus_cntl = RREG32(RADEON_BUS_CNTL); + d1vga_control = RREG32(AVIVO_D1VGA_CONTROL); + d2vga_control = RREG32(AVIVO_D2VGA_CONTROL); + vga_render_control = RREG32(AVIVO_VGA_RENDER_CONTROL); + gpiopad_a = RREG32(RADEON_GPIOPAD_A); + gpiopad_en = RREG32(RADEON_GPIOPAD_EN); + gpiopad_mask = RREG32(RADEON_GPIOPAD_MASK); + + WREG32(RADEON_SEPROM_CNTL1, + ((seprom_cntl1 & ~RADEON_SCK_PRESCALE_MASK) | + (0xc << RADEON_SCK_PRESCALE_SHIFT))); + WREG32(RADEON_GPIOPAD_A, 0); + WREG32(RADEON_GPIOPAD_EN, 0); + WREG32(RADEON_GPIOPAD_MASK, 0); + + /* disable VIP */ + WREG32(RADEON_VIPH_CONTROL, (viph_control & ~RADEON_VIPH_EN)); + + /* enable the rom */ + WREG32(RADEON_BUS_CNTL, (bus_cntl & ~RADEON_BUS_BIOS_DIS_ROM)); + + /* Disable VGA mode */ + WREG32(AVIVO_D1VGA_CONTROL, + (d1vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE | + AVIVO_DVGA_CONTROL_TIMING_SELECT))); + WREG32(AVIVO_D2VGA_CONTROL, + (d2vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE | + AVIVO_DVGA_CONTROL_TIMING_SELECT))); + WREG32(AVIVO_VGA_RENDER_CONTROL, + (vga_render_control & ~AVIVO_VGA_VSTATUS_CNTL_MASK)); + + r = radeon_read_bios(rdev); + + /* restore regs */ + WREG32(RADEON_SEPROM_CNTL1, seprom_cntl1); + WREG32(RADEON_VIPH_CONTROL, viph_control); + WREG32(RADEON_BUS_CNTL, bus_cntl); + WREG32(AVIVO_D1VGA_CONTROL, d1vga_control); + WREG32(AVIVO_D2VGA_CONTROL, d2vga_control); + WREG32(AVIVO_VGA_RENDER_CONTROL, vga_render_control); + WREG32(RADEON_GPIOPAD_A, gpiopad_a); + WREG32(RADEON_GPIOPAD_EN, gpiopad_en); + WREG32(RADEON_GPIOPAD_MASK, gpiopad_mask); + return r; +} + +static bool legacy_read_disabled_bios(struct radeon_device *rdev) +{ + uint32_t seprom_cntl1; + uint32_t viph_control; + uint32_t bus_cntl; + uint32_t crtc_gen_cntl; + uint32_t crtc2_gen_cntl; + uint32_t crtc_ext_cntl; + uint32_t fp2_gen_cntl; + bool r; + + seprom_cntl1 = RREG32(RADEON_SEPROM_CNTL1); + viph_control = RREG32(RADEON_VIPH_CONTROL); + bus_cntl = RREG32(RADEON_BUS_CNTL); + crtc_gen_cntl = RREG32(RADEON_CRTC_GEN_CNTL); + crtc2_gen_cntl = 0; + crtc_ext_cntl = RREG32(RADEON_CRTC_EXT_CNTL); + fp2_gen_cntl = 0; + + if (rdev->ddev->pci_device == PCI_DEVICE_ID_ATI_RADEON_QY) { + fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL); + } + + if (!(rdev->flags & RADEON_SINGLE_CRTC)) { + crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL); + } + + WREG32(RADEON_SEPROM_CNTL1, + ((seprom_cntl1 & ~RADEON_SCK_PRESCALE_MASK) | + (0xc << RADEON_SCK_PRESCALE_SHIFT))); + + /* disable VIP */ + WREG32(RADEON_VIPH_CONTROL, (viph_control & ~RADEON_VIPH_EN)); + + /* enable the rom */ + WREG32(RADEON_BUS_CNTL, (bus_cntl & ~RADEON_BUS_BIOS_DIS_ROM)); + + /* Turn off mem requests and CRTC for both controllers */ + WREG32(RADEON_CRTC_GEN_CNTL, + ((crtc_gen_cntl & ~RADEON_CRTC_EN) | + (RADEON_CRTC_DISP_REQ_EN_B | + RADEON_CRTC_EXT_DISP_EN))); + if (!(rdev->flags & RADEON_SINGLE_CRTC)) { + WREG32(RADEON_CRTC2_GEN_CNTL, + ((crtc2_gen_cntl & ~RADEON_CRTC2_EN) | + RADEON_CRTC2_DISP_REQ_EN_B)); + } + /* Turn off CRTC */ + WREG32(RADEON_CRTC_EXT_CNTL, + ((crtc_ext_cntl & ~RADEON_CRTC_CRT_ON) | + (RADEON_CRTC_SYNC_TRISTAT | + RADEON_CRTC_DISPLAY_DIS))); + + if (rdev->ddev->pci_device == PCI_DEVICE_ID_ATI_RADEON_QY) { + WREG32(RADEON_FP2_GEN_CNTL, (fp2_gen_cntl & ~RADEON_FP2_ON)); + } + + r = radeon_read_bios(rdev); + + /* restore regs */ + WREG32(RADEON_SEPROM_CNTL1, seprom_cntl1); + WREG32(RADEON_VIPH_CONTROL, viph_control); + WREG32(RADEON_BUS_CNTL, bus_cntl); + WREG32(RADEON_CRTC_GEN_CNTL, crtc_gen_cntl); + if (!(rdev->flags & RADEON_SINGLE_CRTC)) { + WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl); + } + WREG32(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl); + if (rdev->ddev->pci_device == PCI_DEVICE_ID_ATI_RADEON_QY) { + WREG32(RADEON_FP2_GEN_CNTL, fp2_gen_cntl); + } + return r; +} + +static bool radeon_read_disabled_bios(struct radeon_device *rdev) +{ + if (rdev->family >= CHIP_RV770) + return r700_read_disabled_bios(rdev); + else if (rdev->family >= CHIP_R600) + return r600_read_disabled_bios(rdev); + else if (rdev->family >= CHIP_RS600) + return avivo_read_disabled_bios(rdev); + else + return legacy_read_disabled_bios(rdev); +} + +bool radeon_get_bios(struct radeon_device *rdev) +{ + bool r; + uint16_t tmp; + + r = radeon_read_bios(rdev); + if (r == false) { + r = radeon_read_disabled_bios(rdev); + } + if (r == false || rdev->bios == NULL) { + DRM_ERROR("Unable to locate a BIOS ROM\n"); + rdev->bios = NULL; + return false; + } + if (rdev->bios[0] != 0x55 || rdev->bios[1] != 0xaa) { + goto free_bios; + } + + rdev->bios_header_start = RBIOS16(0x48); + if (!rdev->bios_header_start) { + goto free_bios; + } + tmp = rdev->bios_header_start + 4; + if (!memcmp(rdev->bios + tmp, "ATOM", 4) || + !memcmp(rdev->bios + tmp, "MOTA", 4)) { + rdev->is_atom_bios = true; + } else { + rdev->is_atom_bios = false; + } + + DRM_DEBUG("%sBIOS detected\n", rdev->is_atom_bios ? "ATOM" : "COM"); + return true; +free_bios: + kfree(rdev->bios); + rdev->bios = NULL; + return false; +} diff --git a/drivers/gpu/drm/radeon/radeon_clocks.c b/drivers/gpu/drm/radeon/radeon_clocks.c new file mode 100644 index 000000000000..a37cbce53181 --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_clocks.c @@ -0,0 +1,833 @@ +/* + * Copyright 2008 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * Copyright 2009 Jerome Glisse. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Dave Airlie + * Alex Deucher + * Jerome Glisse + */ +#include "drmP.h" +#include "radeon_drm.h" +#include "radeon_reg.h" +#include "radeon.h" +#include "atom.h" + +/* 10 khz */ +static uint32_t radeon_legacy_get_engine_clock(struct radeon_device *rdev) +{ + struct radeon_pll *spll = &rdev->clock.spll; + uint32_t fb_div, ref_div, post_div, sclk; + + fb_div = RREG32_PLL(RADEON_M_SPLL_REF_FB_DIV); + fb_div = (fb_div >> RADEON_SPLL_FB_DIV_SHIFT) & RADEON_SPLL_FB_DIV_MASK; + fb_div <<= 1; + fb_div *= spll->reference_freq; + + ref_div = + RREG32_PLL(RADEON_M_SPLL_REF_FB_DIV) & RADEON_M_SPLL_REF_DIV_MASK; + sclk = fb_div / ref_div; + + post_div = RREG32_PLL(RADEON_SCLK_CNTL) & RADEON_SCLK_SRC_SEL_MASK; + if (post_div == 2) + sclk >>= 1; + else if (post_div == 3) + sclk >>= 2; + else if (post_div == 4) + sclk >>= 4; + + return sclk; +} + +/* 10 khz */ +static uint32_t radeon_legacy_get_memory_clock(struct radeon_device *rdev) +{ + struct radeon_pll *mpll = &rdev->clock.mpll; + uint32_t fb_div, ref_div, post_div, mclk; + + fb_div = RREG32_PLL(RADEON_M_SPLL_REF_FB_DIV); + fb_div = (fb_div >> RADEON_MPLL_FB_DIV_SHIFT) & RADEON_MPLL_FB_DIV_MASK; + fb_div <<= 1; + fb_div *= mpll->reference_freq; + + ref_div = + RREG32_PLL(RADEON_M_SPLL_REF_FB_DIV) & RADEON_M_SPLL_REF_DIV_MASK; + mclk = fb_div / ref_div; + + post_div = RREG32_PLL(RADEON_MCLK_CNTL) & 0x7; + if (post_div == 2) + mclk >>= 1; + else if (post_div == 3) + mclk >>= 2; + else if (post_div == 4) + mclk >>= 4; + + return mclk; +} + +void radeon_get_clock_info(struct drm_device *dev) +{ + struct radeon_device *rdev = dev->dev_private; + struct radeon_pll *p1pll = &rdev->clock.p1pll; + struct radeon_pll *p2pll = &rdev->clock.p2pll; + struct radeon_pll *spll = &rdev->clock.spll; + struct radeon_pll *mpll = &rdev->clock.mpll; + int ret; + + if (rdev->is_atom_bios) + ret = radeon_atom_get_clock_info(dev); + else + ret = radeon_combios_get_clock_info(dev); + + if (ret) { + if (p1pll->reference_div < 2) + p1pll->reference_div = 12; + if (p2pll->reference_div < 2) + p2pll->reference_div = 12; + if (spll->reference_div < 2) + spll->reference_div = + RREG32_PLL(RADEON_M_SPLL_REF_FB_DIV) & + RADEON_M_SPLL_REF_DIV_MASK; + if (mpll->reference_div < 2) + mpll->reference_div = spll->reference_div; + } else { + if (ASIC_IS_AVIVO(rdev)) { + /* TODO FALLBACK */ + } else { + DRM_INFO("Using generic clock info\n"); + + if (rdev->flags & RADEON_IS_IGP) { + p1pll->reference_freq = 1432; + p2pll->reference_freq = 1432; + spll->reference_freq = 1432; + mpll->reference_freq = 1432; + } else { + p1pll->reference_freq = 2700; + p2pll->reference_freq = 2700; + spll->reference_freq = 2700; + mpll->reference_freq = 2700; + } + p1pll->reference_div = + RREG32_PLL(RADEON_PPLL_REF_DIV) & 0x3ff; + if (p1pll->reference_div < 2) + p1pll->reference_div = 12; + p2pll->reference_div = p1pll->reference_div; + + if (rdev->family >= CHIP_R420) { + p1pll->pll_in_min = 100; + p1pll->pll_in_max = 1350; + p1pll->pll_out_min = 20000; + p1pll->pll_out_max = 50000; + p2pll->pll_in_min = 100; + p2pll->pll_in_max = 1350; + p2pll->pll_out_min = 20000; + p2pll->pll_out_max = 50000; + } else { + p1pll->pll_in_min = 40; + p1pll->pll_in_max = 500; + p1pll->pll_out_min = 12500; + p1pll->pll_out_max = 35000; + p2pll->pll_in_min = 40; + p2pll->pll_in_max = 500; + p2pll->pll_out_min = 12500; + p2pll->pll_out_max = 35000; + } + + spll->reference_div = + RREG32_PLL(RADEON_M_SPLL_REF_FB_DIV) & + RADEON_M_SPLL_REF_DIV_MASK; + mpll->reference_div = spll->reference_div; + rdev->clock.default_sclk = + radeon_legacy_get_engine_clock(rdev); + rdev->clock.default_mclk = + radeon_legacy_get_memory_clock(rdev); + } + } + + /* pixel clocks */ + if (ASIC_IS_AVIVO(rdev)) { + p1pll->min_post_div = 2; + p1pll->max_post_div = 0x7f; + p1pll->min_frac_feedback_div = 0; + p1pll->max_frac_feedback_div = 9; + p2pll->min_post_div = 2; + p2pll->max_post_div = 0x7f; + p2pll->min_frac_feedback_div = 0; + p2pll->max_frac_feedback_div = 9; + } else { + p1pll->min_post_div = 1; + p1pll->max_post_div = 16; + p1pll->min_frac_feedback_div = 0; + p1pll->max_frac_feedback_div = 0; + p2pll->min_post_div = 1; + p2pll->max_post_div = 12; + p2pll->min_frac_feedback_div = 0; + p2pll->max_frac_feedback_div = 0; + } + + p1pll->min_ref_div = 2; + p1pll->max_ref_div = 0x3ff; + p1pll->min_feedback_div = 4; + p1pll->max_feedback_div = 0x7ff; + p1pll->best_vco = 0; + + p2pll->min_ref_div = 2; + p2pll->max_ref_div = 0x3ff; + p2pll->min_feedback_div = 4; + p2pll->max_feedback_div = 0x7ff; + p2pll->best_vco = 0; + + /* system clock */ + spll->min_post_div = 1; + spll->max_post_div = 1; + spll->min_ref_div = 2; + spll->max_ref_div = 0xff; + spll->min_feedback_div = 4; + spll->max_feedback_div = 0xff; + spll->best_vco = 0; + + /* memory clock */ + mpll->min_post_div = 1; + mpll->max_post_div = 1; + mpll->min_ref_div = 2; + mpll->max_ref_div = 0xff; + mpll->min_feedback_div = 4; + mpll->max_feedback_div = 0xff; + mpll->best_vco = 0; + +} + +/* 10 khz */ +static uint32_t calc_eng_mem_clock(struct radeon_device *rdev, + uint32_t req_clock, + int *fb_div, int *post_div) +{ + struct radeon_pll *spll = &rdev->clock.spll; + int ref_div = spll->reference_div; + + if (!ref_div) + ref_div = + RREG32_PLL(RADEON_M_SPLL_REF_FB_DIV) & + RADEON_M_SPLL_REF_DIV_MASK; + + if (req_clock < 15000) { + *post_div = 8; + req_clock *= 8; + } else if (req_clock < 30000) { + *post_div = 4; + req_clock *= 4; + } else if (req_clock < 60000) { + *post_div = 2; + req_clock *= 2; + } else + *post_div = 1; + + req_clock *= ref_div; + req_clock += spll->reference_freq; + req_clock /= (2 * spll->reference_freq); + + *fb_div = req_clock & 0xff; + + req_clock = (req_clock & 0xffff) << 1; + req_clock *= spll->reference_freq; + req_clock /= ref_div; + req_clock /= *post_div; + + return req_clock; +} + +/* 10 khz */ +void radeon_legacy_set_engine_clock(struct radeon_device *rdev, + uint32_t eng_clock) +{ + uint32_t tmp; + int fb_div, post_div; + + /* XXX: wait for idle */ + + eng_clock = calc_eng_mem_clock(rdev, eng_clock, &fb_div, &post_div); + + tmp = RREG32_PLL(RADEON_CLK_PIN_CNTL); + tmp &= ~RADEON_DONT_USE_XTALIN; + WREG32_PLL(RADEON_CLK_PIN_CNTL, tmp); + + tmp = RREG32_PLL(RADEON_SCLK_CNTL); + tmp &= ~RADEON_SCLK_SRC_SEL_MASK; + WREG32_PLL(RADEON_SCLK_CNTL, tmp); + + udelay(10); + + tmp = RREG32_PLL(RADEON_SPLL_CNTL); + tmp |= RADEON_SPLL_SLEEP; + WREG32_PLL(RADEON_SPLL_CNTL, tmp); + + udelay(2); + + tmp = RREG32_PLL(RADEON_SPLL_CNTL); + tmp |= RADEON_SPLL_RESET; + WREG32_PLL(RADEON_SPLL_CNTL, tmp); + + udelay(200); + + tmp = RREG32_PLL(RADEON_M_SPLL_REF_FB_DIV); + tmp &= ~(RADEON_SPLL_FB_DIV_MASK << RADEON_SPLL_FB_DIV_SHIFT); + tmp |= (fb_div & RADEON_SPLL_FB_DIV_MASK) << RADEON_SPLL_FB_DIV_SHIFT; + WREG32_PLL(RADEON_M_SPLL_REF_FB_DIV, tmp); + + /* XXX: verify on different asics */ + tmp = RREG32_PLL(RADEON_SPLL_CNTL); + tmp &= ~RADEON_SPLL_PVG_MASK; + if ((eng_clock * post_div) >= 90000) + tmp |= (0x7 << RADEON_SPLL_PVG_SHIFT); + else + tmp |= (0x4 << RADEON_SPLL_PVG_SHIFT); + WREG32_PLL(RADEON_SPLL_CNTL, tmp); + + tmp = RREG32_PLL(RADEON_SPLL_CNTL); + tmp &= ~RADEON_SPLL_SLEEP; + WREG32_PLL(RADEON_SPLL_CNTL, tmp); + + udelay(2); + + tmp = RREG32_PLL(RADEON_SPLL_CNTL); + tmp &= ~RADEON_SPLL_RESET; + WREG32_PLL(RADEON_SPLL_CNTL, tmp); + + udelay(200); + + tmp = RREG32_PLL(RADEON_SCLK_CNTL); + tmp &= ~RADEON_SCLK_SRC_SEL_MASK; + switch (post_div) { + case 1: + default: + tmp |= 1; + break; + case 2: + tmp |= 2; + break; + case 4: + tmp |= 3; + break; + case 8: + tmp |= 4; + break; + } + WREG32_PLL(RADEON_SCLK_CNTL, tmp); + + udelay(20); + + tmp = RREG32_PLL(RADEON_CLK_PIN_CNTL); + tmp |= RADEON_DONT_USE_XTALIN; + WREG32_PLL(RADEON_CLK_PIN_CNTL, tmp); + + udelay(10); +} + +void radeon_legacy_set_clock_gating(struct radeon_device *rdev, int enable) +{ + uint32_t tmp; + + if (enable) { + if (rdev->flags & RADEON_SINGLE_CRTC) { + tmp = RREG32_PLL(RADEON_SCLK_CNTL); + if ((RREG32(RADEON_CONFIG_CNTL) & + RADEON_CFG_ATI_REV_ID_MASK) > + RADEON_CFG_ATI_REV_A13) { + tmp &= + ~(RADEON_SCLK_FORCE_CP | + RADEON_SCLK_FORCE_RB); + } + tmp &= + ~(RADEON_SCLK_FORCE_HDP | RADEON_SCLK_FORCE_DISP1 | + RADEON_SCLK_FORCE_TOP | RADEON_SCLK_FORCE_SE | + RADEON_SCLK_FORCE_IDCT | RADEON_SCLK_FORCE_RE | + RADEON_SCLK_FORCE_PB | RADEON_SCLK_FORCE_TAM | + RADEON_SCLK_FORCE_TDM); + WREG32_PLL(RADEON_SCLK_CNTL, tmp); + } else if (ASIC_IS_R300(rdev)) { + if ((rdev->family == CHIP_RS400) || + (rdev->family == CHIP_RS480)) { + tmp = RREG32_PLL(RADEON_SCLK_CNTL); + tmp &= + ~(RADEON_SCLK_FORCE_DISP2 | + RADEON_SCLK_FORCE_CP | + RADEON_SCLK_FORCE_HDP | + RADEON_SCLK_FORCE_DISP1 | + RADEON_SCLK_FORCE_TOP | + RADEON_SCLK_FORCE_E2 | R300_SCLK_FORCE_VAP + | RADEON_SCLK_FORCE_IDCT | + RADEON_SCLK_FORCE_VIP | R300_SCLK_FORCE_SR + | R300_SCLK_FORCE_PX | R300_SCLK_FORCE_TX + | R300_SCLK_FORCE_US | + RADEON_SCLK_FORCE_TV_SCLK | + R300_SCLK_FORCE_SU | + RADEON_SCLK_FORCE_OV0); + tmp |= RADEON_DYN_STOP_LAT_MASK; + tmp |= + RADEON_SCLK_FORCE_TOP | + RADEON_SCLK_FORCE_VIP; + WREG32_PLL(RADEON_SCLK_CNTL, tmp); + + tmp = RREG32_PLL(RADEON_SCLK_MORE_CNTL); + tmp &= ~RADEON_SCLK_MORE_FORCEON; + tmp |= RADEON_SCLK_MORE_MAX_DYN_STOP_LAT; + WREG32_PLL(RADEON_SCLK_MORE_CNTL, tmp); + + tmp = RREG32_PLL(RADEON_VCLK_ECP_CNTL); + tmp |= (RADEON_PIXCLK_ALWAYS_ONb | + RADEON_PIXCLK_DAC_ALWAYS_ONb); + WREG32_PLL(RADEON_VCLK_ECP_CNTL, tmp); + + tmp = RREG32_PLL(RADEON_PIXCLKS_CNTL); + tmp |= (RADEON_PIX2CLK_ALWAYS_ONb | + RADEON_PIX2CLK_DAC_ALWAYS_ONb | + RADEON_DISP_TVOUT_PIXCLK_TV_ALWAYS_ONb | + R300_DVOCLK_ALWAYS_ONb | + RADEON_PIXCLK_BLEND_ALWAYS_ONb | + RADEON_PIXCLK_GV_ALWAYS_ONb | + R300_PIXCLK_DVO_ALWAYS_ONb | + RADEON_PIXCLK_LVDS_ALWAYS_ONb | + RADEON_PIXCLK_TMDS_ALWAYS_ONb | + R300_PIXCLK_TRANS_ALWAYS_ONb | + R300_PIXCLK_TVO_ALWAYS_ONb | + R300_P2G2CLK_ALWAYS_ONb | + R300_P2G2CLK_ALWAYS_ONb); + WREG32_PLL(RADEON_PIXCLKS_CNTL, tmp); + } else if (rdev->family >= CHIP_RV350) { + tmp = RREG32_PLL(R300_SCLK_CNTL2); + tmp &= ~(R300_SCLK_FORCE_TCL | + R300_SCLK_FORCE_GA | + R300_SCLK_FORCE_CBA); + tmp |= (R300_SCLK_TCL_MAX_DYN_STOP_LAT | + R300_SCLK_GA_MAX_DYN_STOP_LAT | + R300_SCLK_CBA_MAX_DYN_STOP_LAT); + WREG32_PLL(R300_SCLK_CNTL2, tmp); + + tmp = RREG32_PLL(RADEON_SCLK_CNTL); + tmp &= + ~(RADEON_SCLK_FORCE_DISP2 | + RADEON_SCLK_FORCE_CP | + RADEON_SCLK_FORCE_HDP | + RADEON_SCLK_FORCE_DISP1 | + RADEON_SCLK_FORCE_TOP | + RADEON_SCLK_FORCE_E2 | R300_SCLK_FORCE_VAP + | RADEON_SCLK_FORCE_IDCT | + RADEON_SCLK_FORCE_VIP | R300_SCLK_FORCE_SR + | R300_SCLK_FORCE_PX | R300_SCLK_FORCE_TX + | R300_SCLK_FORCE_US | + RADEON_SCLK_FORCE_TV_SCLK | + R300_SCLK_FORCE_SU | + RADEON_SCLK_FORCE_OV0); + tmp |= RADEON_DYN_STOP_LAT_MASK; + WREG32_PLL(RADEON_SCLK_CNTL, tmp); + + tmp = RREG32_PLL(RADEON_SCLK_MORE_CNTL); + tmp &= ~RADEON_SCLK_MORE_FORCEON; + tmp |= RADEON_SCLK_MORE_MAX_DYN_STOP_LAT; + WREG32_PLL(RADEON_SCLK_MORE_CNTL, tmp); + + tmp = RREG32_PLL(RADEON_VCLK_ECP_CNTL); + tmp |= (RADEON_PIXCLK_ALWAYS_ONb | + RADEON_PIXCLK_DAC_ALWAYS_ONb); + WREG32_PLL(RADEON_VCLK_ECP_CNTL, tmp); + + tmp = RREG32_PLL(RADEON_PIXCLKS_CNTL); + tmp |= (RADEON_PIX2CLK_ALWAYS_ONb | + RADEON_PIX2CLK_DAC_ALWAYS_ONb | + RADEON_DISP_TVOUT_PIXCLK_TV_ALWAYS_ONb | + R300_DVOCLK_ALWAYS_ONb | + RADEON_PIXCLK_BLEND_ALWAYS_ONb | + RADEON_PIXCLK_GV_ALWAYS_ONb | + R300_PIXCLK_DVO_ALWAYS_ONb | + RADEON_PIXCLK_LVDS_ALWAYS_ONb | + RADEON_PIXCLK_TMDS_ALWAYS_ONb | + R300_PIXCLK_TRANS_ALWAYS_ONb | + R300_PIXCLK_TVO_ALWAYS_ONb | + R300_P2G2CLK_ALWAYS_ONb | + R300_P2G2CLK_ALWAYS_ONb); + WREG32_PLL(RADEON_PIXCLKS_CNTL, tmp); + + tmp = RREG32_PLL(RADEON_MCLK_MISC); + tmp |= (RADEON_MC_MCLK_DYN_ENABLE | + RADEON_IO_MCLK_DYN_ENABLE); + WREG32_PLL(RADEON_MCLK_MISC, tmp); + + tmp = RREG32_PLL(RADEON_MCLK_CNTL); + tmp |= (RADEON_FORCEON_MCLKA | + RADEON_FORCEON_MCLKB); + + tmp &= ~(RADEON_FORCEON_YCLKA | + RADEON_FORCEON_YCLKB | + RADEON_FORCEON_MC); + + /* Some releases of vbios have set DISABLE_MC_MCLKA + and DISABLE_MC_MCLKB bits in the vbios table. Setting these + bits will cause H/W hang when reading video memory with dynamic clocking + enabled. */ + if ((tmp & R300_DISABLE_MC_MCLKA) && + (tmp & R300_DISABLE_MC_MCLKB)) { + /* If both bits are set, then check the active channels */ + tmp = RREG32_PLL(RADEON_MCLK_CNTL); + if (rdev->mc.vram_width == 64) { + if (RREG32(RADEON_MEM_CNTL) & + R300_MEM_USE_CD_CH_ONLY) + tmp &= + ~R300_DISABLE_MC_MCLKB; + else + tmp &= + ~R300_DISABLE_MC_MCLKA; + } else { + tmp &= ~(R300_DISABLE_MC_MCLKA | + R300_DISABLE_MC_MCLKB); + } + } + + WREG32_PLL(RADEON_MCLK_CNTL, tmp); + } else { + tmp = RREG32_PLL(RADEON_SCLK_CNTL); + tmp &= ~(R300_SCLK_FORCE_VAP); + tmp |= RADEON_SCLK_FORCE_CP; + WREG32_PLL(RADEON_SCLK_CNTL, tmp); + udelay(15000); + + tmp = RREG32_PLL(R300_SCLK_CNTL2); + tmp &= ~(R300_SCLK_FORCE_TCL | + R300_SCLK_FORCE_GA | + R300_SCLK_FORCE_CBA); + WREG32_PLL(R300_SCLK_CNTL2, tmp); + } + } else { + tmp = RREG32_PLL(RADEON_CLK_PWRMGT_CNTL); + + tmp &= ~(RADEON_ACTIVE_HILO_LAT_MASK | + RADEON_DISP_DYN_STOP_LAT_MASK | + RADEON_DYN_STOP_MODE_MASK); + + tmp |= (RADEON_ENGIN_DYNCLK_MODE | + (0x01 << RADEON_ACTIVE_HILO_LAT_SHIFT)); + WREG32_PLL(RADEON_CLK_PWRMGT_CNTL, tmp); + udelay(15000); + + tmp = RREG32_PLL(RADEON_CLK_PIN_CNTL); + tmp |= RADEON_SCLK_DYN_START_CNTL; + WREG32_PLL(RADEON_CLK_PIN_CNTL, tmp); + udelay(15000); + + /* When DRI is enabled, setting DYN_STOP_LAT to zero can cause some R200 + to lockup randomly, leave them as set by BIOS. + */ + tmp = RREG32_PLL(RADEON_SCLK_CNTL); + /*tmp &= RADEON_SCLK_SRC_SEL_MASK; */ + tmp &= ~RADEON_SCLK_FORCEON_MASK; + + /*RAGE_6::A11 A12 A12N1 A13, RV250::A11 A12, R300 */ + if (((rdev->family == CHIP_RV250) && + ((RREG32(RADEON_CONFIG_CNTL) & + RADEON_CFG_ATI_REV_ID_MASK) < + RADEON_CFG_ATI_REV_A13)) + || ((rdev->family == CHIP_RV100) + && + ((RREG32(RADEON_CONFIG_CNTL) & + RADEON_CFG_ATI_REV_ID_MASK) <= + RADEON_CFG_ATI_REV_A13))) { + tmp |= RADEON_SCLK_FORCE_CP; + tmp |= RADEON_SCLK_FORCE_VIP; + } + + WREG32_PLL(RADEON_SCLK_CNTL, tmp); + + if ((rdev->family == CHIP_RV200) || + (rdev->family == CHIP_RV250) || + (rdev->family == CHIP_RV280)) { + tmp = RREG32_PLL(RADEON_SCLK_MORE_CNTL); + tmp &= ~RADEON_SCLK_MORE_FORCEON; + + /* RV200::A11 A12 RV250::A11 A12 */ + if (((rdev->family == CHIP_RV200) || + (rdev->family == CHIP_RV250)) && + ((RREG32(RADEON_CONFIG_CNTL) & + RADEON_CFG_ATI_REV_ID_MASK) < + RADEON_CFG_ATI_REV_A13)) { + tmp |= RADEON_SCLK_MORE_FORCEON; + } + WREG32_PLL(RADEON_SCLK_MORE_CNTL, tmp); + udelay(15000); + } + + /* RV200::A11 A12, RV250::A11 A12 */ + if (((rdev->family == CHIP_RV200) || + (rdev->family == CHIP_RV250)) && + ((RREG32(RADEON_CONFIG_CNTL) & + RADEON_CFG_ATI_REV_ID_MASK) < + RADEON_CFG_ATI_REV_A13)) { + tmp = RREG32_PLL(RADEON_PLL_PWRMGT_CNTL); + tmp |= RADEON_TCL_BYPASS_DISABLE; + WREG32_PLL(RADEON_PLL_PWRMGT_CNTL, tmp); + } + udelay(15000); + + /*enable dynamic mode for display clocks (PIXCLK and PIX2CLK) */ + tmp = RREG32_PLL(RADEON_PIXCLKS_CNTL); + tmp |= (RADEON_PIX2CLK_ALWAYS_ONb | + RADEON_PIX2CLK_DAC_ALWAYS_ONb | + RADEON_PIXCLK_BLEND_ALWAYS_ONb | + RADEON_PIXCLK_GV_ALWAYS_ONb | + RADEON_PIXCLK_DIG_TMDS_ALWAYS_ONb | + RADEON_PIXCLK_LVDS_ALWAYS_ONb | + RADEON_PIXCLK_TMDS_ALWAYS_ONb); + + WREG32_PLL(RADEON_PIXCLKS_CNTL, tmp); + udelay(15000); + + tmp = RREG32_PLL(RADEON_VCLK_ECP_CNTL); + tmp |= (RADEON_PIXCLK_ALWAYS_ONb | + RADEON_PIXCLK_DAC_ALWAYS_ONb); + + WREG32_PLL(RADEON_VCLK_ECP_CNTL, tmp); + udelay(15000); + } + } else { + /* Turn everything OFF (ForceON to everything) */ + if (rdev->flags & RADEON_SINGLE_CRTC) { + tmp = RREG32_PLL(RADEON_SCLK_CNTL); + tmp |= (RADEON_SCLK_FORCE_CP | RADEON_SCLK_FORCE_HDP | + RADEON_SCLK_FORCE_DISP1 | RADEON_SCLK_FORCE_TOP + | RADEON_SCLK_FORCE_E2 | RADEON_SCLK_FORCE_SE | + RADEON_SCLK_FORCE_IDCT | RADEON_SCLK_FORCE_VIP | + RADEON_SCLK_FORCE_RE | RADEON_SCLK_FORCE_PB | + RADEON_SCLK_FORCE_TAM | RADEON_SCLK_FORCE_TDM | + RADEON_SCLK_FORCE_RB); + WREG32_PLL(RADEON_SCLK_CNTL, tmp); + } else if ((rdev->family == CHIP_RS400) || + (rdev->family == CHIP_RS480)) { + tmp = RREG32_PLL(RADEON_SCLK_CNTL); + tmp |= (RADEON_SCLK_FORCE_DISP2 | RADEON_SCLK_FORCE_CP | + RADEON_SCLK_FORCE_HDP | RADEON_SCLK_FORCE_DISP1 + | RADEON_SCLK_FORCE_TOP | RADEON_SCLK_FORCE_E2 | + R300_SCLK_FORCE_VAP | RADEON_SCLK_FORCE_IDCT | + RADEON_SCLK_FORCE_VIP | R300_SCLK_FORCE_SR | + R300_SCLK_FORCE_PX | R300_SCLK_FORCE_TX | + R300_SCLK_FORCE_US | RADEON_SCLK_FORCE_TV_SCLK | + R300_SCLK_FORCE_SU | RADEON_SCLK_FORCE_OV0); + WREG32_PLL(RADEON_SCLK_CNTL, tmp); + + tmp = RREG32_PLL(RADEON_SCLK_MORE_CNTL); + tmp |= RADEON_SCLK_MORE_FORCEON; + WREG32_PLL(RADEON_SCLK_MORE_CNTL, tmp); + + tmp = RREG32_PLL(RADEON_VCLK_ECP_CNTL); + tmp &= ~(RADEON_PIXCLK_ALWAYS_ONb | + RADEON_PIXCLK_DAC_ALWAYS_ONb | + R300_DISP_DAC_PIXCLK_DAC_BLANK_OFF); + WREG32_PLL(RADEON_VCLK_ECP_CNTL, tmp); + + tmp = RREG32_PLL(RADEON_PIXCLKS_CNTL); + tmp &= ~(RADEON_PIX2CLK_ALWAYS_ONb | + RADEON_PIX2CLK_DAC_ALWAYS_ONb | + RADEON_DISP_TVOUT_PIXCLK_TV_ALWAYS_ONb | + R300_DVOCLK_ALWAYS_ONb | + RADEON_PIXCLK_BLEND_ALWAYS_ONb | + RADEON_PIXCLK_GV_ALWAYS_ONb | + R300_PIXCLK_DVO_ALWAYS_ONb | + RADEON_PIXCLK_LVDS_ALWAYS_ONb | + RADEON_PIXCLK_TMDS_ALWAYS_ONb | + R300_PIXCLK_TRANS_ALWAYS_ONb | + R300_PIXCLK_TVO_ALWAYS_ONb | + R300_P2G2CLK_ALWAYS_ONb | + R300_P2G2CLK_ALWAYS_ONb | + R300_DISP_DAC_PIXCLK_DAC2_BLANK_OFF); + WREG32_PLL(RADEON_PIXCLKS_CNTL, tmp); + } else if (rdev->family >= CHIP_RV350) { + /* for RV350/M10, no delays are required. */ + tmp = RREG32_PLL(R300_SCLK_CNTL2); + tmp |= (R300_SCLK_FORCE_TCL | + R300_SCLK_FORCE_GA | R300_SCLK_FORCE_CBA); + WREG32_PLL(R300_SCLK_CNTL2, tmp); + + tmp = RREG32_PLL(RADEON_SCLK_CNTL); + tmp |= (RADEON_SCLK_FORCE_DISP2 | RADEON_SCLK_FORCE_CP | + RADEON_SCLK_FORCE_HDP | RADEON_SCLK_FORCE_DISP1 + | RADEON_SCLK_FORCE_TOP | RADEON_SCLK_FORCE_E2 | + R300_SCLK_FORCE_VAP | RADEON_SCLK_FORCE_IDCT | + RADEON_SCLK_FORCE_VIP | R300_SCLK_FORCE_SR | + R300_SCLK_FORCE_PX | R300_SCLK_FORCE_TX | + R300_SCLK_FORCE_US | RADEON_SCLK_FORCE_TV_SCLK | + R300_SCLK_FORCE_SU | RADEON_SCLK_FORCE_OV0); + WREG32_PLL(RADEON_SCLK_CNTL, tmp); + + tmp = RREG32_PLL(RADEON_SCLK_MORE_CNTL); + tmp |= RADEON_SCLK_MORE_FORCEON; + WREG32_PLL(RADEON_SCLK_MORE_CNTL, tmp); + + tmp = RREG32_PLL(RADEON_MCLK_CNTL); + tmp |= (RADEON_FORCEON_MCLKA | + RADEON_FORCEON_MCLKB | + RADEON_FORCEON_YCLKA | + RADEON_FORCEON_YCLKB | RADEON_FORCEON_MC); + WREG32_PLL(RADEON_MCLK_CNTL, tmp); + + tmp = RREG32_PLL(RADEON_VCLK_ECP_CNTL); + tmp &= ~(RADEON_PIXCLK_ALWAYS_ONb | + RADEON_PIXCLK_DAC_ALWAYS_ONb | + R300_DISP_DAC_PIXCLK_DAC_BLANK_OFF); + WREG32_PLL(RADEON_VCLK_ECP_CNTL, tmp); + + tmp = RREG32_PLL(RADEON_PIXCLKS_CNTL); + tmp &= ~(RADEON_PIX2CLK_ALWAYS_ONb | + RADEON_PIX2CLK_DAC_ALWAYS_ONb | + RADEON_DISP_TVOUT_PIXCLK_TV_ALWAYS_ONb | + R300_DVOCLK_ALWAYS_ONb | + RADEON_PIXCLK_BLEND_ALWAYS_ONb | + RADEON_PIXCLK_GV_ALWAYS_ONb | + R300_PIXCLK_DVO_ALWAYS_ONb | + RADEON_PIXCLK_LVDS_ALWAYS_ONb | + RADEON_PIXCLK_TMDS_ALWAYS_ONb | + R300_PIXCLK_TRANS_ALWAYS_ONb | + R300_PIXCLK_TVO_ALWAYS_ONb | + R300_P2G2CLK_ALWAYS_ONb | + R300_P2G2CLK_ALWAYS_ONb | + R300_DISP_DAC_PIXCLK_DAC2_BLANK_OFF); + WREG32_PLL(RADEON_PIXCLKS_CNTL, tmp); + } else { + tmp = RREG32_PLL(RADEON_SCLK_CNTL); + tmp |= (RADEON_SCLK_FORCE_CP | RADEON_SCLK_FORCE_E2); + tmp |= RADEON_SCLK_FORCE_SE; + + if (rdev->flags & RADEON_SINGLE_CRTC) { + tmp |= (RADEON_SCLK_FORCE_RB | + RADEON_SCLK_FORCE_TDM | + RADEON_SCLK_FORCE_TAM | + RADEON_SCLK_FORCE_PB | + RADEON_SCLK_FORCE_RE | + RADEON_SCLK_FORCE_VIP | + RADEON_SCLK_FORCE_IDCT | + RADEON_SCLK_FORCE_TOP | + RADEON_SCLK_FORCE_DISP1 | + RADEON_SCLK_FORCE_DISP2 | + RADEON_SCLK_FORCE_HDP); + } else if ((rdev->family == CHIP_R300) || + (rdev->family == CHIP_R350)) { + tmp |= (RADEON_SCLK_FORCE_HDP | + RADEON_SCLK_FORCE_DISP1 | + RADEON_SCLK_FORCE_DISP2 | + RADEON_SCLK_FORCE_TOP | + RADEON_SCLK_FORCE_IDCT | + RADEON_SCLK_FORCE_VIP); + } + WREG32_PLL(RADEON_SCLK_CNTL, tmp); + + udelay(16000); + + if ((rdev->family == CHIP_R300) || + (rdev->family == CHIP_R350)) { + tmp = RREG32_PLL(R300_SCLK_CNTL2); + tmp |= (R300_SCLK_FORCE_TCL | + R300_SCLK_FORCE_GA | + R300_SCLK_FORCE_CBA); + WREG32_PLL(R300_SCLK_CNTL2, tmp); + udelay(16000); + } + + if (rdev->flags & RADEON_IS_IGP) { + tmp = RREG32_PLL(RADEON_MCLK_CNTL); + tmp &= ~(RADEON_FORCEON_MCLKA | + RADEON_FORCEON_YCLKA); + WREG32_PLL(RADEON_MCLK_CNTL, tmp); + udelay(16000); + } + + if ((rdev->family == CHIP_RV200) || + (rdev->family == CHIP_RV250) || + (rdev->family == CHIP_RV280)) { + tmp = RREG32_PLL(RADEON_SCLK_MORE_CNTL); + tmp |= RADEON_SCLK_MORE_FORCEON; + WREG32_PLL(RADEON_SCLK_MORE_CNTL, tmp); + udelay(16000); + } + + tmp = RREG32_PLL(RADEON_PIXCLKS_CNTL); + tmp &= ~(RADEON_PIX2CLK_ALWAYS_ONb | + RADEON_PIX2CLK_DAC_ALWAYS_ONb | + RADEON_PIXCLK_BLEND_ALWAYS_ONb | + RADEON_PIXCLK_GV_ALWAYS_ONb | + RADEON_PIXCLK_DIG_TMDS_ALWAYS_ONb | + RADEON_PIXCLK_LVDS_ALWAYS_ONb | + RADEON_PIXCLK_TMDS_ALWAYS_ONb); + + WREG32_PLL(RADEON_PIXCLKS_CNTL, tmp); + udelay(16000); + + tmp = RREG32_PLL(RADEON_VCLK_ECP_CNTL); + tmp &= ~(RADEON_PIXCLK_ALWAYS_ONb | + RADEON_PIXCLK_DAC_ALWAYS_ONb); + WREG32_PLL(RADEON_VCLK_ECP_CNTL, tmp); + } + } +} + +static void radeon_apply_clock_quirks(struct radeon_device *rdev) +{ + uint32_t tmp; + + /* XXX make sure engine is idle */ + + if (rdev->family < CHIP_RS600) { + tmp = RREG32_PLL(RADEON_SCLK_CNTL); + if (ASIC_IS_R300(rdev) || ASIC_IS_RV100(rdev)) + tmp |= RADEON_SCLK_FORCE_CP | RADEON_SCLK_FORCE_VIP; + if ((rdev->family == CHIP_RV250) + || (rdev->family == CHIP_RV280)) + tmp |= + RADEON_SCLK_FORCE_DISP1 | RADEON_SCLK_FORCE_DISP2; + if ((rdev->family == CHIP_RV350) + || (rdev->family == CHIP_RV380)) + tmp |= R300_SCLK_FORCE_VAP; + if (rdev->family == CHIP_R420) + tmp |= R300_SCLK_FORCE_PX | R300_SCLK_FORCE_TX; + WREG32_PLL(RADEON_SCLK_CNTL, tmp); + } else if (rdev->family < CHIP_R600) { + tmp = RREG32_PLL(AVIVO_CP_DYN_CNTL); + tmp |= AVIVO_CP_FORCEON; + WREG32_PLL(AVIVO_CP_DYN_CNTL, tmp); + + tmp = RREG32_PLL(AVIVO_E2_DYN_CNTL); + tmp |= AVIVO_E2_FORCEON; + WREG32_PLL(AVIVO_E2_DYN_CNTL, tmp); + + tmp = RREG32_PLL(AVIVO_IDCT_DYN_CNTL); + tmp |= AVIVO_IDCT_FORCEON; + WREG32_PLL(AVIVO_IDCT_DYN_CNTL, tmp); + } +} + +int radeon_static_clocks_init(struct drm_device *dev) +{ + struct radeon_device *rdev = dev->dev_private; + + /* XXX make sure engine is idle */ + + if (radeon_dynclks != -1) { + if (radeon_dynclks) + radeon_set_clock_gating(rdev, 1); + } + radeon_apply_clock_quirks(rdev); + return 0; +} diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c new file mode 100644 index 000000000000..afc4db280b94 --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -0,0 +1,2490 @@ +/* + * Copyright 2004 ATI Technologies Inc., Markham, Ontario + * Copyright 2007-8 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Dave Airlie + * Alex Deucher + */ +#include "drmP.h" +#include "radeon_drm.h" +#include "radeon.h" +#include "atom.h" + +#ifdef CONFIG_PPC_PMAC +/* not sure which of these are needed */ +#include +#include +#include +#include +#endif /* CONFIG_PPC_PMAC */ + +/* from radeon_encoder.c */ +extern uint32_t +radeon_get_encoder_id(struct drm_device *dev, uint32_t supported_device, + uint8_t dac); +extern void radeon_link_encoder_connector(struct drm_device *dev); + +/* from radeon_connector.c */ +extern void +radeon_add_legacy_connector(struct drm_device *dev, + uint32_t connector_id, + uint32_t supported_device, + int connector_type, + struct radeon_i2c_bus_rec *i2c_bus); + +/* from radeon_legacy_encoder.c */ +extern void +radeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_id, + uint32_t supported_device); + +/* old legacy ATI BIOS routines */ + +/* COMBIOS table offsets */ +enum radeon_combios_table_offset { + /* absolute offset tables */ + COMBIOS_ASIC_INIT_1_TABLE, + COMBIOS_BIOS_SUPPORT_TABLE, + COMBIOS_DAC_PROGRAMMING_TABLE, + COMBIOS_MAX_COLOR_DEPTH_TABLE, + COMBIOS_CRTC_INFO_TABLE, + COMBIOS_PLL_INFO_TABLE, + COMBIOS_TV_INFO_TABLE, + COMBIOS_DFP_INFO_TABLE, + COMBIOS_HW_CONFIG_INFO_TABLE, + COMBIOS_MULTIMEDIA_INFO_TABLE, + COMBIOS_TV_STD_PATCH_TABLE, + COMBIOS_LCD_INFO_TABLE, + COMBIOS_MOBILE_INFO_TABLE, + COMBIOS_PLL_INIT_TABLE, + COMBIOS_MEM_CONFIG_TABLE, + COMBIOS_SAVE_MASK_TABLE, + COMBIOS_HARDCODED_EDID_TABLE, + COMBIOS_ASIC_INIT_2_TABLE, + COMBIOS_CONNECTOR_INFO_TABLE, + COMBIOS_DYN_CLK_1_TABLE, + COMBIOS_RESERVED_MEM_TABLE, + COMBIOS_EXT_TMDS_INFO_TABLE, + COMBIOS_MEM_CLK_INFO_TABLE, + COMBIOS_EXT_DAC_INFO_TABLE, + COMBIOS_MISC_INFO_TABLE, + COMBIOS_CRT_INFO_TABLE, + COMBIOS_INTEGRATED_SYSTEM_INFO_TABLE, + COMBIOS_COMPONENT_VIDEO_INFO_TABLE, + COMBIOS_FAN_SPEED_INFO_TABLE, + COMBIOS_OVERDRIVE_INFO_TABLE, + COMBIOS_OEM_INFO_TABLE, + COMBIOS_DYN_CLK_2_TABLE, + COMBIOS_POWER_CONNECTOR_INFO_TABLE, + COMBIOS_I2C_INFO_TABLE, + /* relative offset tables */ + COMBIOS_ASIC_INIT_3_TABLE, /* offset from misc info */ + COMBIOS_ASIC_INIT_4_TABLE, /* offset from misc info */ + COMBIOS_DETECTED_MEM_TABLE, /* offset from misc info */ + COMBIOS_ASIC_INIT_5_TABLE, /* offset from misc info */ + COMBIOS_RAM_RESET_TABLE, /* offset from mem config */ + COMBIOS_POWERPLAY_INFO_TABLE, /* offset from mobile info */ + COMBIOS_GPIO_INFO_TABLE, /* offset from mobile info */ + COMBIOS_LCD_DDC_INFO_TABLE, /* offset from mobile info */ + COMBIOS_TMDS_POWER_TABLE, /* offset from mobile info */ + COMBIOS_TMDS_POWER_ON_TABLE, /* offset from tmds power */ + COMBIOS_TMDS_POWER_OFF_TABLE, /* offset from tmds power */ +}; + +enum radeon_combios_ddc { + DDC_NONE_DETECTED, + DDC_MONID, + DDC_DVI, + DDC_VGA, + DDC_CRT2, + DDC_LCD, + DDC_GPIO, +}; + +enum radeon_combios_connector { + CONNECTOR_NONE_LEGACY, + CONNECTOR_PROPRIETARY_LEGACY, + CONNECTOR_CRT_LEGACY, + CONNECTOR_DVI_I_LEGACY, + CONNECTOR_DVI_D_LEGACY, + CONNECTOR_CTV_LEGACY, + CONNECTOR_STV_LEGACY, + CONNECTOR_UNSUPPORTED_LEGACY +}; + +const int legacy_connector_convert[] = { + DRM_MODE_CONNECTOR_Unknown, + DRM_MODE_CONNECTOR_DVID, + DRM_MODE_CONNECTOR_VGA, + DRM_MODE_CONNECTOR_DVII, + DRM_MODE_CONNECTOR_DVID, + DRM_MODE_CONNECTOR_Composite, + DRM_MODE_CONNECTOR_SVIDEO, + DRM_MODE_CONNECTOR_Unknown, +}; + +static uint16_t combios_get_table_offset(struct drm_device *dev, + enum radeon_combios_table_offset table) +{ + struct radeon_device *rdev = dev->dev_private; + int rev; + uint16_t offset = 0, check_offset; + + switch (table) { + /* absolute offset tables */ + case COMBIOS_ASIC_INIT_1_TABLE: + check_offset = RBIOS16(rdev->bios_header_start + 0xc); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_BIOS_SUPPORT_TABLE: + check_offset = RBIOS16(rdev->bios_header_start + 0x14); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_DAC_PROGRAMMING_TABLE: + check_offset = RBIOS16(rdev->bios_header_start + 0x2a); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_MAX_COLOR_DEPTH_TABLE: + check_offset = RBIOS16(rdev->bios_header_start + 0x2c); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_CRTC_INFO_TABLE: + check_offset = RBIOS16(rdev->bios_header_start + 0x2e); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_PLL_INFO_TABLE: + check_offset = RBIOS16(rdev->bios_header_start + 0x30); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_TV_INFO_TABLE: + check_offset = RBIOS16(rdev->bios_header_start + 0x32); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_DFP_INFO_TABLE: + check_offset = RBIOS16(rdev->bios_header_start + 0x34); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_HW_CONFIG_INFO_TABLE: + check_offset = RBIOS16(rdev->bios_header_start + 0x36); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_MULTIMEDIA_INFO_TABLE: + check_offset = RBIOS16(rdev->bios_header_start + 0x38); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_TV_STD_PATCH_TABLE: + check_offset = RBIOS16(rdev->bios_header_start + 0x3e); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_LCD_INFO_TABLE: + check_offset = RBIOS16(rdev->bios_header_start + 0x40); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_MOBILE_INFO_TABLE: + check_offset = RBIOS16(rdev->bios_header_start + 0x42); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_PLL_INIT_TABLE: + check_offset = RBIOS16(rdev->bios_header_start + 0x46); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_MEM_CONFIG_TABLE: + check_offset = RBIOS16(rdev->bios_header_start + 0x48); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_SAVE_MASK_TABLE: + check_offset = RBIOS16(rdev->bios_header_start + 0x4a); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_HARDCODED_EDID_TABLE: + check_offset = RBIOS16(rdev->bios_header_start + 0x4c); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_ASIC_INIT_2_TABLE: + check_offset = RBIOS16(rdev->bios_header_start + 0x4e); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_CONNECTOR_INFO_TABLE: + check_offset = RBIOS16(rdev->bios_header_start + 0x50); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_DYN_CLK_1_TABLE: + check_offset = RBIOS16(rdev->bios_header_start + 0x52); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_RESERVED_MEM_TABLE: + check_offset = RBIOS16(rdev->bios_header_start + 0x54); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_EXT_TMDS_INFO_TABLE: + check_offset = RBIOS16(rdev->bios_header_start + 0x58); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_MEM_CLK_INFO_TABLE: + check_offset = RBIOS16(rdev->bios_header_start + 0x5a); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_EXT_DAC_INFO_TABLE: + check_offset = RBIOS16(rdev->bios_header_start + 0x5c); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_MISC_INFO_TABLE: + check_offset = RBIOS16(rdev->bios_header_start + 0x5e); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_CRT_INFO_TABLE: + check_offset = RBIOS16(rdev->bios_header_start + 0x60); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_INTEGRATED_SYSTEM_INFO_TABLE: + check_offset = RBIOS16(rdev->bios_header_start + 0x62); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_COMPONENT_VIDEO_INFO_TABLE: + check_offset = RBIOS16(rdev->bios_header_start + 0x64); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_FAN_SPEED_INFO_TABLE: + check_offset = RBIOS16(rdev->bios_header_start + 0x66); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_OVERDRIVE_INFO_TABLE: + check_offset = RBIOS16(rdev->bios_header_start + 0x68); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_OEM_INFO_TABLE: + check_offset = RBIOS16(rdev->bios_header_start + 0x6a); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_DYN_CLK_2_TABLE: + check_offset = RBIOS16(rdev->bios_header_start + 0x6c); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_POWER_CONNECTOR_INFO_TABLE: + check_offset = RBIOS16(rdev->bios_header_start + 0x6e); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_I2C_INFO_TABLE: + check_offset = RBIOS16(rdev->bios_header_start + 0x70); + if (check_offset) + offset = check_offset; + break; + /* relative offset tables */ + case COMBIOS_ASIC_INIT_3_TABLE: /* offset from misc info */ + check_offset = + combios_get_table_offset(dev, COMBIOS_MISC_INFO_TABLE); + if (check_offset) { + rev = RBIOS8(check_offset); + if (rev > 0) { + check_offset = RBIOS16(check_offset + 0x3); + if (check_offset) + offset = check_offset; + } + } + break; + case COMBIOS_ASIC_INIT_4_TABLE: /* offset from misc info */ + check_offset = + combios_get_table_offset(dev, COMBIOS_MISC_INFO_TABLE); + if (check_offset) { + rev = RBIOS8(check_offset); + if (rev > 0) { + check_offset = RBIOS16(check_offset + 0x5); + if (check_offset) + offset = check_offset; + } + } + break; + case COMBIOS_DETECTED_MEM_TABLE: /* offset from misc info */ + check_offset = + combios_get_table_offset(dev, COMBIOS_MISC_INFO_TABLE); + if (check_offset) { + rev = RBIOS8(check_offset); + if (rev > 0) { + check_offset = RBIOS16(check_offset + 0x7); + if (check_offset) + offset = check_offset; + } + } + break; + case COMBIOS_ASIC_INIT_5_TABLE: /* offset from misc info */ + check_offset = + combios_get_table_offset(dev, COMBIOS_MISC_INFO_TABLE); + if (check_offset) { + rev = RBIOS8(check_offset); + if (rev == 2) { + check_offset = RBIOS16(check_offset + 0x9); + if (check_offset) + offset = check_offset; + } + } + break; + case COMBIOS_RAM_RESET_TABLE: /* offset from mem config */ + check_offset = + combios_get_table_offset(dev, COMBIOS_MEM_CONFIG_TABLE); + if (check_offset) { + while (RBIOS8(check_offset++)); + check_offset += 2; + if (check_offset) + offset = check_offset; + } + break; + case COMBIOS_POWERPLAY_INFO_TABLE: /* offset from mobile info */ + check_offset = + combios_get_table_offset(dev, COMBIOS_MOBILE_INFO_TABLE); + if (check_offset) { + check_offset = RBIOS16(check_offset + 0x11); + if (check_offset) + offset = check_offset; + } + break; + case COMBIOS_GPIO_INFO_TABLE: /* offset from mobile info */ + check_offset = + combios_get_table_offset(dev, COMBIOS_MOBILE_INFO_TABLE); + if (check_offset) { + check_offset = RBIOS16(check_offset + 0x13); + if (check_offset) + offset = check_offset; + } + break; + case COMBIOS_LCD_DDC_INFO_TABLE: /* offset from mobile info */ + check_offset = + combios_get_table_offset(dev, COMBIOS_MOBILE_INFO_TABLE); + if (check_offset) { + check_offset = RBIOS16(check_offset + 0x15); + if (check_offset) + offset = check_offset; + } + break; + case COMBIOS_TMDS_POWER_TABLE: /* offset from mobile info */ + check_offset = + combios_get_table_offset(dev, COMBIOS_MOBILE_INFO_TABLE); + if (check_offset) { + check_offset = RBIOS16(check_offset + 0x17); + if (check_offset) + offset = check_offset; + } + break; + case COMBIOS_TMDS_POWER_ON_TABLE: /* offset from tmds power */ + check_offset = + combios_get_table_offset(dev, COMBIOS_TMDS_POWER_TABLE); + if (check_offset) { + check_offset = RBIOS16(check_offset + 0x2); + if (check_offset) + offset = check_offset; + } + break; + case COMBIOS_TMDS_POWER_OFF_TABLE: /* offset from tmds power */ + check_offset = + combios_get_table_offset(dev, COMBIOS_TMDS_POWER_TABLE); + if (check_offset) { + check_offset = RBIOS16(check_offset + 0x4); + if (check_offset) + offset = check_offset; + } + break; + default: + break; + } + + return offset; + +} + +struct radeon_i2c_bus_rec combios_setup_i2c_bus(int ddc_line) +{ + struct radeon_i2c_bus_rec i2c; + + i2c.mask_clk_mask = RADEON_GPIO_EN_1; + i2c.mask_data_mask = RADEON_GPIO_EN_0; + i2c.a_clk_mask = RADEON_GPIO_A_1; + i2c.a_data_mask = RADEON_GPIO_A_0; + i2c.put_clk_mask = RADEON_GPIO_EN_1; + i2c.put_data_mask = RADEON_GPIO_EN_0; + i2c.get_clk_mask = RADEON_GPIO_Y_1; + i2c.get_data_mask = RADEON_GPIO_Y_0; + if ((ddc_line == RADEON_LCD_GPIO_MASK) || + (ddc_line == RADEON_MDGPIO_EN_REG)) { + i2c.mask_clk_reg = ddc_line; + i2c.mask_data_reg = ddc_line; + i2c.a_clk_reg = ddc_line; + i2c.a_data_reg = ddc_line; + i2c.put_clk_reg = ddc_line; + i2c.put_data_reg = ddc_line; + i2c.get_clk_reg = ddc_line + 4; + i2c.get_data_reg = ddc_line + 4; + } else { + i2c.mask_clk_reg = ddc_line; + i2c.mask_data_reg = ddc_line; + i2c.a_clk_reg = ddc_line; + i2c.a_data_reg = ddc_line; + i2c.put_clk_reg = ddc_line; + i2c.put_data_reg = ddc_line; + i2c.get_clk_reg = ddc_line; + i2c.get_data_reg = ddc_line; + } + + if (ddc_line) + i2c.valid = true; + else + i2c.valid = false; + + return i2c; +} + +bool radeon_combios_get_clock_info(struct drm_device *dev) +{ + struct radeon_device *rdev = dev->dev_private; + uint16_t pll_info; + struct radeon_pll *p1pll = &rdev->clock.p1pll; + struct radeon_pll *p2pll = &rdev->clock.p2pll; + struct radeon_pll *spll = &rdev->clock.spll; + struct radeon_pll *mpll = &rdev->clock.mpll; + int8_t rev; + uint16_t sclk, mclk; + + if (rdev->bios == NULL) + return NULL; + + pll_info = combios_get_table_offset(dev, COMBIOS_PLL_INFO_TABLE); + if (pll_info) { + rev = RBIOS8(pll_info); + + /* pixel clocks */ + p1pll->reference_freq = RBIOS16(pll_info + 0xe); + p1pll->reference_div = RBIOS16(pll_info + 0x10); + p1pll->pll_out_min = RBIOS32(pll_info + 0x12); + p1pll->pll_out_max = RBIOS32(pll_info + 0x16); + + if (rev > 9) { + p1pll->pll_in_min = RBIOS32(pll_info + 0x36); + p1pll->pll_in_max = RBIOS32(pll_info + 0x3a); + } else { + p1pll->pll_in_min = 40; + p1pll->pll_in_max = 500; + } + *p2pll = *p1pll; + + /* system clock */ + spll->reference_freq = RBIOS16(pll_info + 0x1a); + spll->reference_div = RBIOS16(pll_info + 0x1c); + spll->pll_out_min = RBIOS32(pll_info + 0x1e); + spll->pll_out_max = RBIOS32(pll_info + 0x22); + + if (rev > 10) { + spll->pll_in_min = RBIOS32(pll_info + 0x48); + spll->pll_in_max = RBIOS32(pll_info + 0x4c); + } else { + /* ??? */ + spll->pll_in_min = 40; + spll->pll_in_max = 500; + } + + /* memory clock */ + mpll->reference_freq = RBIOS16(pll_info + 0x26); + mpll->reference_div = RBIOS16(pll_info + 0x28); + mpll->pll_out_min = RBIOS32(pll_info + 0x2a); + mpll->pll_out_max = RBIOS32(pll_info + 0x2e); + + if (rev > 10) { + mpll->pll_in_min = RBIOS32(pll_info + 0x5a); + mpll->pll_in_max = RBIOS32(pll_info + 0x5e); + } else { + /* ??? */ + mpll->pll_in_min = 40; + mpll->pll_in_max = 500; + } + + /* default sclk/mclk */ + sclk = RBIOS16(pll_info + 0xa); + mclk = RBIOS16(pll_info + 0x8); + if (sclk == 0) + sclk = 200 * 100; + if (mclk == 0) + mclk = 200 * 100; + + rdev->clock.default_sclk = sclk; + rdev->clock.default_mclk = mclk; + + return true; + } + return false; +} + +struct radeon_encoder_primary_dac *radeon_combios_get_primary_dac_info(struct + radeon_encoder + *encoder) +{ + struct drm_device *dev = encoder->base.dev; + struct radeon_device *rdev = dev->dev_private; + uint16_t dac_info; + uint8_t rev, bg, dac; + struct radeon_encoder_primary_dac *p_dac = NULL; + + if (rdev->bios == NULL) + return NULL; + + /* check CRT table */ + dac_info = combios_get_table_offset(dev, COMBIOS_CRT_INFO_TABLE); + if (dac_info) { + p_dac = + kzalloc(sizeof(struct radeon_encoder_primary_dac), + GFP_KERNEL); + + if (!p_dac) + return NULL; + + rev = RBIOS8(dac_info) & 0x3; + if (rev < 2) { + bg = RBIOS8(dac_info + 0x2) & 0xf; + dac = (RBIOS8(dac_info + 0x2) >> 4) & 0xf; + p_dac->ps2_pdac_adj = (bg << 8) | (dac); + } else { + bg = RBIOS8(dac_info + 0x2) & 0xf; + dac = RBIOS8(dac_info + 0x3) & 0xf; + p_dac->ps2_pdac_adj = (bg << 8) | (dac); + } + + } + + return p_dac; +} + +static enum radeon_tv_std +radeon_combios_get_tv_info(struct radeon_encoder *encoder) +{ + struct drm_device *dev = encoder->base.dev; + struct radeon_device *rdev = dev->dev_private; + uint16_t tv_info; + enum radeon_tv_std tv_std = TV_STD_NTSC; + + tv_info = combios_get_table_offset(dev, COMBIOS_TV_INFO_TABLE); + if (tv_info) { + if (RBIOS8(tv_info + 6) == 'T') { + switch (RBIOS8(tv_info + 7) & 0xf) { + case 1: + tv_std = TV_STD_NTSC; + DRM_INFO("Default TV standard: NTSC\n"); + break; + case 2: + tv_std = TV_STD_PAL; + DRM_INFO("Default TV standard: PAL\n"); + break; + case 3: + tv_std = TV_STD_PAL_M; + DRM_INFO("Default TV standard: PAL-M\n"); + break; + case 4: + tv_std = TV_STD_PAL_60; + DRM_INFO("Default TV standard: PAL-60\n"); + break; + case 5: + tv_std = TV_STD_NTSC_J; + DRM_INFO("Default TV standard: NTSC-J\n"); + break; + case 6: + tv_std = TV_STD_SCART_PAL; + DRM_INFO("Default TV standard: SCART-PAL\n"); + break; + default: + tv_std = TV_STD_NTSC; + DRM_INFO + ("Unknown TV standard; defaulting to NTSC\n"); + break; + } + + switch ((RBIOS8(tv_info + 9) >> 2) & 0x3) { + case 0: + DRM_INFO("29.498928713 MHz TV ref clk\n"); + break; + case 1: + DRM_INFO("28.636360000 MHz TV ref clk\n"); + break; + case 2: + DRM_INFO("14.318180000 MHz TV ref clk\n"); + break; + case 3: + DRM_INFO("27.000000000 MHz TV ref clk\n"); + break; + default: + break; + } + } + } + return tv_std; +} + +static const uint32_t default_tvdac_adj[CHIP_LAST] = { + 0x00000000, /* r100 */ + 0x00280000, /* rv100 */ + 0x00000000, /* rs100 */ + 0x00880000, /* rv200 */ + 0x00000000, /* rs200 */ + 0x00000000, /* r200 */ + 0x00770000, /* rv250 */ + 0x00290000, /* rs300 */ + 0x00560000, /* rv280 */ + 0x00780000, /* r300 */ + 0x00770000, /* r350 */ + 0x00780000, /* rv350 */ + 0x00780000, /* rv380 */ + 0x01080000, /* r420 */ + 0x01080000, /* r423 */ + 0x01080000, /* rv410 */ + 0x00780000, /* rs400 */ + 0x00780000, /* rs480 */ +}; + +static struct radeon_encoder_tv_dac + *radeon_legacy_get_tv_dac_info_from_table(struct radeon_device *rdev) +{ + struct radeon_encoder_tv_dac *tv_dac = NULL; + + tv_dac = kzalloc(sizeof(struct radeon_encoder_tv_dac), GFP_KERNEL); + + if (!tv_dac) + return NULL; + + tv_dac->ps2_tvdac_adj = default_tvdac_adj[rdev->family]; + if ((rdev->flags & RADEON_IS_MOBILITY) && (rdev->family == CHIP_RV250)) + tv_dac->ps2_tvdac_adj = 0x00880000; + tv_dac->pal_tvdac_adj = tv_dac->ps2_tvdac_adj; + tv_dac->ntsc_tvdac_adj = tv_dac->ps2_tvdac_adj; + + return tv_dac; +} + +struct radeon_encoder_tv_dac *radeon_combios_get_tv_dac_info(struct + radeon_encoder + *encoder) +{ + struct drm_device *dev = encoder->base.dev; + struct radeon_device *rdev = dev->dev_private; + uint16_t dac_info; + uint8_t rev, bg, dac; + struct radeon_encoder_tv_dac *tv_dac = NULL; + + if (rdev->bios == NULL) + return radeon_legacy_get_tv_dac_info_from_table(rdev); + + /* first check TV table */ + dac_info = combios_get_table_offset(dev, COMBIOS_TV_INFO_TABLE); + if (dac_info) { + tv_dac = + kzalloc(sizeof(struct radeon_encoder_tv_dac), GFP_KERNEL); + + if (!tv_dac) + return NULL; + + rev = RBIOS8(dac_info + 0x3); + if (rev > 4) { + bg = RBIOS8(dac_info + 0xc) & 0xf; + dac = RBIOS8(dac_info + 0xd) & 0xf; + tv_dac->ps2_tvdac_adj = (bg << 16) | (dac << 20); + + bg = RBIOS8(dac_info + 0xe) & 0xf; + dac = RBIOS8(dac_info + 0xf) & 0xf; + tv_dac->pal_tvdac_adj = (bg << 16) | (dac << 20); + + bg = RBIOS8(dac_info + 0x10) & 0xf; + dac = RBIOS8(dac_info + 0x11) & 0xf; + tv_dac->ntsc_tvdac_adj = (bg << 16) | (dac << 20); + } else if (rev > 1) { + bg = RBIOS8(dac_info + 0xc) & 0xf; + dac = (RBIOS8(dac_info + 0xc) >> 4) & 0xf; + tv_dac->ps2_tvdac_adj = (bg << 16) | (dac << 20); + + bg = RBIOS8(dac_info + 0xd) & 0xf; + dac = (RBIOS8(dac_info + 0xd) >> 4) & 0xf; + tv_dac->pal_tvdac_adj = (bg << 16) | (dac << 20); + + bg = RBIOS8(dac_info + 0xe) & 0xf; + dac = (RBIOS8(dac_info + 0xe) >> 4) & 0xf; + tv_dac->ntsc_tvdac_adj = (bg << 16) | (dac << 20); + } + + tv_dac->tv_std = radeon_combios_get_tv_info(encoder); + + } else { + /* then check CRT table */ + dac_info = + combios_get_table_offset(dev, COMBIOS_CRT_INFO_TABLE); + if (dac_info) { + tv_dac = + kzalloc(sizeof(struct radeon_encoder_tv_dac), + GFP_KERNEL); + + if (!tv_dac) + return NULL; + + rev = RBIOS8(dac_info) & 0x3; + if (rev < 2) { + bg = RBIOS8(dac_info + 0x3) & 0xf; + dac = (RBIOS8(dac_info + 0x3) >> 4) & 0xf; + tv_dac->ps2_tvdac_adj = + (bg << 16) | (dac << 20); + tv_dac->pal_tvdac_adj = tv_dac->ps2_tvdac_adj; + tv_dac->ntsc_tvdac_adj = tv_dac->ps2_tvdac_adj; + } else { + bg = RBIOS8(dac_info + 0x4) & 0xf; + dac = RBIOS8(dac_info + 0x5) & 0xf; + tv_dac->ps2_tvdac_adj = + (bg << 16) | (dac << 20); + tv_dac->pal_tvdac_adj = tv_dac->ps2_tvdac_adj; + tv_dac->ntsc_tvdac_adj = tv_dac->ps2_tvdac_adj; + } + } else { + DRM_INFO("No TV DAC info found in BIOS\n"); + return radeon_legacy_get_tv_dac_info_from_table(rdev); + } + } + + return tv_dac; +} + +static struct radeon_encoder_lvds *radeon_legacy_get_lvds_info_from_regs(struct + radeon_device + *rdev) +{ + struct radeon_encoder_lvds *lvds = NULL; + uint32_t fp_vert_stretch, fp_horz_stretch; + uint32_t ppll_div_sel, ppll_val; + uint32_t lvds_ss_gen_cntl = RREG32(RADEON_LVDS_SS_GEN_CNTL); + + lvds = kzalloc(sizeof(struct radeon_encoder_lvds), GFP_KERNEL); + + if (!lvds) + return NULL; + + fp_vert_stretch = RREG32(RADEON_FP_VERT_STRETCH); + fp_horz_stretch = RREG32(RADEON_FP_HORZ_STRETCH); + + /* These should be fail-safe defaults, fingers crossed */ + lvds->panel_pwr_delay = 200; + lvds->panel_vcc_delay = 2000; + + lvds->lvds_gen_cntl = RREG32(RADEON_LVDS_GEN_CNTL); + lvds->panel_digon_delay = (lvds_ss_gen_cntl >> RADEON_LVDS_PWRSEQ_DELAY1_SHIFT) & 0xf; + lvds->panel_blon_delay = (lvds_ss_gen_cntl >> RADEON_LVDS_PWRSEQ_DELAY2_SHIFT) & 0xf; + + if (fp_vert_stretch & RADEON_VERT_STRETCH_ENABLE) + lvds->native_mode.panel_yres = + ((fp_vert_stretch & RADEON_VERT_PANEL_SIZE) >> + RADEON_VERT_PANEL_SHIFT) + 1; + else + lvds->native_mode.panel_yres = + (RREG32(RADEON_CRTC_V_TOTAL_DISP) >> 16) + 1; + + if (fp_horz_stretch & RADEON_HORZ_STRETCH_ENABLE) + lvds->native_mode.panel_xres = + (((fp_horz_stretch & RADEON_HORZ_PANEL_SIZE) >> + RADEON_HORZ_PANEL_SHIFT) + 1) * 8; + else + lvds->native_mode.panel_xres = + ((RREG32(RADEON_CRTC_H_TOTAL_DISP) >> 16) + 1) * 8; + + if ((lvds->native_mode.panel_xres < 640) || + (lvds->native_mode.panel_yres < 480)) { + lvds->native_mode.panel_xres = 640; + lvds->native_mode.panel_yres = 480; + } + + ppll_div_sel = RREG8(RADEON_CLOCK_CNTL_INDEX + 1) & 0x3; + ppll_val = RREG32_PLL(RADEON_PPLL_DIV_0 + ppll_div_sel); + if ((ppll_val & 0x000707ff) == 0x1bb) + lvds->use_bios_dividers = false; + else { + lvds->panel_ref_divider = + RREG32_PLL(RADEON_PPLL_REF_DIV) & 0x3ff; + lvds->panel_post_divider = (ppll_val >> 16) & 0x7; + lvds->panel_fb_divider = ppll_val & 0x7ff; + + if ((lvds->panel_ref_divider != 0) && + (lvds->panel_fb_divider > 3)) + lvds->use_bios_dividers = true; + } + lvds->panel_vcc_delay = 200; + + DRM_INFO("Panel info derived from registers\n"); + DRM_INFO("Panel Size %dx%d\n", lvds->native_mode.panel_xres, + lvds->native_mode.panel_yres); + + return lvds; +} + +struct radeon_encoder_lvds *radeon_combios_get_lvds_info(struct radeon_encoder + *encoder) +{ + struct drm_device *dev = encoder->base.dev; + struct radeon_device *rdev = dev->dev_private; + uint16_t lcd_info; + uint32_t panel_setup; + char stmp[30]; + int tmp, i; + struct radeon_encoder_lvds *lvds = NULL; + + if (rdev->bios == NULL) + return radeon_legacy_get_lvds_info_from_regs(rdev); + + lcd_info = combios_get_table_offset(dev, COMBIOS_LCD_INFO_TABLE); + + if (lcd_info) { + lvds = kzalloc(sizeof(struct radeon_encoder_lvds), GFP_KERNEL); + + if (!lvds) + return NULL; + + for (i = 0; i < 24; i++) + stmp[i] = RBIOS8(lcd_info + i + 1); + stmp[24] = 0; + + DRM_INFO("Panel ID String: %s\n", stmp); + + lvds->native_mode.panel_xres = RBIOS16(lcd_info + 0x19); + lvds->native_mode.panel_yres = RBIOS16(lcd_info + 0x1b); + + DRM_INFO("Panel Size %dx%d\n", lvds->native_mode.panel_xres, + lvds->native_mode.panel_yres); + + lvds->panel_vcc_delay = RBIOS16(lcd_info + 0x2c); + if (lvds->panel_vcc_delay > 2000 || lvds->panel_vcc_delay < 0) + lvds->panel_vcc_delay = 2000; + + lvds->panel_pwr_delay = RBIOS8(lcd_info + 0x24); + lvds->panel_digon_delay = RBIOS16(lcd_info + 0x38) & 0xf; + lvds->panel_blon_delay = (RBIOS16(lcd_info + 0x38) >> 4) & 0xf; + + lvds->panel_ref_divider = RBIOS16(lcd_info + 0x2e); + lvds->panel_post_divider = RBIOS8(lcd_info + 0x30); + lvds->panel_fb_divider = RBIOS16(lcd_info + 0x31); + if ((lvds->panel_ref_divider != 0) && + (lvds->panel_fb_divider > 3)) + lvds->use_bios_dividers = true; + + panel_setup = RBIOS32(lcd_info + 0x39); + lvds->lvds_gen_cntl = 0xff00; + if (panel_setup & 0x1) + lvds->lvds_gen_cntl |= RADEON_LVDS_PANEL_FORMAT; + + if ((panel_setup >> 4) & 0x1) + lvds->lvds_gen_cntl |= RADEON_LVDS_PANEL_TYPE; + + switch ((panel_setup >> 8) & 0x7) { + case 0: + lvds->lvds_gen_cntl |= RADEON_LVDS_NO_FM; + break; + case 1: + lvds->lvds_gen_cntl |= RADEON_LVDS_2_GREY; + break; + case 2: + lvds->lvds_gen_cntl |= RADEON_LVDS_4_GREY; + break; + default: + break; + } + + if ((panel_setup >> 16) & 0x1) + lvds->lvds_gen_cntl |= RADEON_LVDS_FP_POL_LOW; + + if ((panel_setup >> 17) & 0x1) + lvds->lvds_gen_cntl |= RADEON_LVDS_LP_POL_LOW; + + if ((panel_setup >> 18) & 0x1) + lvds->lvds_gen_cntl |= RADEON_LVDS_DTM_POL_LOW; + + if ((panel_setup >> 23) & 0x1) + lvds->lvds_gen_cntl |= RADEON_LVDS_BL_CLK_SEL; + + lvds->lvds_gen_cntl |= (panel_setup & 0xf0000000); + + for (i = 0; i < 32; i++) { + tmp = RBIOS16(lcd_info + 64 + i * 2); + if (tmp == 0) + break; + + if ((RBIOS16(tmp) == lvds->native_mode.panel_xres) && + (RBIOS16(tmp + 2) == + lvds->native_mode.panel_yres)) { + lvds->native_mode.hblank = + (RBIOS16(tmp + 17) - RBIOS16(tmp + 19)) * 8; + lvds->native_mode.hoverplus = + (RBIOS16(tmp + 21) - RBIOS16(tmp + 19) - + 1) * 8; + lvds->native_mode.hsync_width = + RBIOS8(tmp + 23) * 8; + + lvds->native_mode.vblank = (RBIOS16(tmp + 24) - + RBIOS16(tmp + 26)); + lvds->native_mode.voverplus = + ((RBIOS16(tmp + 28) & 0x7ff) - + RBIOS16(tmp + 26)); + lvds->native_mode.vsync_width = + ((RBIOS16(tmp + 28) & 0xf800) >> 11); + lvds->native_mode.dotclock = + RBIOS16(tmp + 9) * 10; + lvds->native_mode.flags = 0; + } + } + encoder->native_mode = lvds->native_mode; + } else { + DRM_INFO("No panel info found in BIOS\n"); + return radeon_legacy_get_lvds_info_from_regs(rdev); + } + return lvds; +} + +static const struct radeon_tmds_pll default_tmds_pll[CHIP_LAST][4] = { + {{12000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}}, /* CHIP_R100 */ + {{12000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}}, /* CHIP_RV100 */ + {{0, 0}, {0, 0}, {0, 0}, {0, 0}}, /* CHIP_RS100 */ + {{15000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}}, /* CHIP_RV200 */ + {{12000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}}, /* CHIP_RS200 */ + {{15000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}}, /* CHIP_R200 */ + {{15500, 0x81b}, {0xffffffff, 0x83f}, {0, 0}, {0, 0}}, /* CHIP_RV250 */ + {{0, 0}, {0, 0}, {0, 0}, {0, 0}}, /* CHIP_RS300 */ + {{13000, 0x400f4}, {15000, 0x400f7}, {0xffffffff, 0x40111}, {0, 0}}, /* CHIP_RV280 */ + {{0xffffffff, 0xb01cb}, {0, 0}, {0, 0}, {0, 0}}, /* CHIP_R300 */ + {{0xffffffff, 0xb01cb}, {0, 0}, {0, 0}, {0, 0}}, /* CHIP_R350 */ + {{15000, 0xb0155}, {0xffffffff, 0xb01cb}, {0, 0}, {0, 0}}, /* CHIP_RV350 */ + {{15000, 0xb0155}, {0xffffffff, 0xb01cb}, {0, 0}, {0, 0}}, /* CHIP_RV380 */ + {{0xffffffff, 0xb01cb}, {0, 0}, {0, 0}, {0, 0}}, /* CHIP_R420 */ + {{0xffffffff, 0xb01cb}, {0, 0}, {0, 0}, {0, 0}}, /* CHIP_R423 */ + {{0xffffffff, 0xb01cb}, {0, 0}, {0, 0}, {0, 0}}, /* CHIP_RV410 */ + {{15000, 0xb0155}, {0xffffffff, 0xb01cb}, {0, 0}, {0, 0}}, /* CHIP_RS400 */ + {{15000, 0xb0155}, {0xffffffff, 0xb01cb}, {0, 0}, {0, 0}}, /* CHIP_RS480 */ +}; + +static struct radeon_encoder_int_tmds + *radeon_legacy_get_tmds_info_from_table(struct radeon_device *rdev) +{ + int i; + struct radeon_encoder_int_tmds *tmds = NULL; + + tmds = kzalloc(sizeof(struct radeon_encoder_int_tmds), GFP_KERNEL); + + if (!tmds) + return NULL; + + for (i = 0; i < 4; i++) { + tmds->tmds_pll[i].value = + default_tmds_pll[rdev->family][i].value; + tmds->tmds_pll[i].freq = default_tmds_pll[rdev->family][i].freq; + } + + return tmds; +} + +struct radeon_encoder_int_tmds *radeon_combios_get_tmds_info(struct + radeon_encoder + *encoder) +{ + struct drm_device *dev = encoder->base.dev; + struct radeon_device *rdev = dev->dev_private; + uint16_t tmds_info; + int i, n; + uint8_t ver; + struct radeon_encoder_int_tmds *tmds = NULL; + + if (rdev->bios == NULL) + return radeon_legacy_get_tmds_info_from_table(rdev); + + tmds_info = combios_get_table_offset(dev, COMBIOS_DFP_INFO_TABLE); + + if (tmds_info) { + tmds = + kzalloc(sizeof(struct radeon_encoder_int_tmds), GFP_KERNEL); + + if (!tmds) + return NULL; + + ver = RBIOS8(tmds_info); + DRM_INFO("DFP table revision: %d\n", ver); + if (ver == 3) { + n = RBIOS8(tmds_info + 5) + 1; + if (n > 4) + n = 4; + for (i = 0; i < n; i++) { + tmds->tmds_pll[i].value = + RBIOS32(tmds_info + i * 10 + 0x08); + tmds->tmds_pll[i].freq = + RBIOS16(tmds_info + i * 10 + 0x10); + DRM_DEBUG("TMDS PLL From COMBIOS %u %x\n", + tmds->tmds_pll[i].freq, + tmds->tmds_pll[i].value); + } + } else if (ver == 4) { + int stride = 0; + n = RBIOS8(tmds_info + 5) + 1; + if (n > 4) + n = 4; + for (i = 0; i < n; i++) { + tmds->tmds_pll[i].value = + RBIOS32(tmds_info + stride + 0x08); + tmds->tmds_pll[i].freq = + RBIOS16(tmds_info + stride + 0x10); + if (i == 0) + stride += 10; + else + stride += 6; + DRM_DEBUG("TMDS PLL From COMBIOS %u %x\n", + tmds->tmds_pll[i].freq, + tmds->tmds_pll[i].value); + } + } + } else + DRM_INFO("No TMDS info found in BIOS\n"); + return tmds; +} + +void radeon_combios_get_ext_tmds_info(struct radeon_encoder *encoder) +{ + struct drm_device *dev = encoder->base.dev; + struct radeon_device *rdev = dev->dev_private; + uint16_t ext_tmds_info; + uint8_t ver; + + if (rdev->bios == NULL) + return; + + ext_tmds_info = + combios_get_table_offset(dev, COMBIOS_EXT_TMDS_INFO_TABLE); + if (ext_tmds_info) { + ver = RBIOS8(ext_tmds_info); + DRM_INFO("External TMDS Table revision: %d\n", ver); + // TODO + } +} + +bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) +{ + struct radeon_device *rdev = dev->dev_private; + struct radeon_i2c_bus_rec ddc_i2c; + + rdev->mode_info.connector_table = radeon_connector_table; + if (rdev->mode_info.connector_table == CT_NONE) { +#ifdef CONFIG_PPC_PMAC + if (machine_is_compatible("PowerBook3,3")) { + /* powerbook with VGA */ + rdev->mode_info.connector_table = CT_POWERBOOK_VGA; + } else if (machine_is_compatible("PowerBook3,4") || + machine_is_compatible("PowerBook3,5")) { + /* powerbook with internal tmds */ + rdev->mode_info.connector_table = CT_POWERBOOK_INTERNAL; + } else if (machine_is_compatible("PowerBook5,1") || + machine_is_compatible("PowerBook5,2") || + machine_is_compatible("PowerBook5,3") || + machine_is_compatible("PowerBook5,4") || + machine_is_compatible("PowerBook5,5")) { + /* powerbook with external single link tmds (sil164) */ + rdev->mode_info.connector_table = CT_POWERBOOK_EXTERNAL; + } else if (machine_is_compatible("PowerBook5,6")) { + /* powerbook with external dual or single link tmds */ + rdev->mode_info.connector_table = CT_POWERBOOK_EXTERNAL; + } else if (machine_is_compatible("PowerBook5,7") || + machine_is_compatible("PowerBook5,8") || + machine_is_compatible("PowerBook5,9")) { + /* PowerBook6,2 ? */ + /* powerbook with external dual link tmds (sil1178?) */ + rdev->mode_info.connector_table = CT_POWERBOOK_EXTERNAL; + } else if (machine_is_compatible("PowerBook4,1") || + machine_is_compatible("PowerBook4,2") || + machine_is_compatible("PowerBook4,3") || + machine_is_compatible("PowerBook6,3") || + machine_is_compatible("PowerBook6,5") || + machine_is_compatible("PowerBook6,7")) { + /* ibook */ + rdev->mode_info.connector_table = CT_IBOOK; + } else if (machine_is_compatible("PowerMac4,4")) { + /* emac */ + rdev->mode_info.connector_table = CT_EMAC; + } else if (machine_is_compatible("PowerMac10,1")) { + /* mini with internal tmds */ + rdev->mode_info.connector_table = CT_MINI_INTERNAL; + } else if (machine_is_compatible("PowerMac10,2")) { + /* mini with external tmds */ + rdev->mode_info.connector_table = CT_MINI_EXTERNAL; + } else if (machine_is_compatible("PowerMac12,1")) { + /* PowerMac8,1 ? */ + /* imac g5 isight */ + rdev->mode_info.connector_table = CT_IMAC_G5_ISIGHT; + } else +#endif /* CONFIG_PPC_PMAC */ + rdev->mode_info.connector_table = CT_GENERIC; + } + + switch (rdev->mode_info.connector_table) { + case CT_GENERIC: + DRM_INFO("Connector Table: %d (generic)\n", + rdev->mode_info.connector_table); + /* these are the most common settings */ + if (rdev->flags & RADEON_SINGLE_CRTC) { + /* VGA - primary dac */ + ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_VGA_DDC); + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id(dev, + ATOM_DEVICE_CRT1_SUPPORT, + 1), + ATOM_DEVICE_CRT1_SUPPORT); + radeon_add_legacy_connector(dev, 0, + ATOM_DEVICE_CRT1_SUPPORT, + DRM_MODE_CONNECTOR_VGA, + &ddc_i2c); + } else if (rdev->flags & RADEON_IS_MOBILITY) { + /* LVDS */ + ddc_i2c = combios_setup_i2c_bus(RADEON_LCD_GPIO_MASK); + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id(dev, + ATOM_DEVICE_LCD1_SUPPORT, + 0), + ATOM_DEVICE_LCD1_SUPPORT); + radeon_add_legacy_connector(dev, 0, + ATOM_DEVICE_LCD1_SUPPORT, + DRM_MODE_CONNECTOR_LVDS, + &ddc_i2c); + + /* VGA - primary dac */ + ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_VGA_DDC); + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id(dev, + ATOM_DEVICE_CRT1_SUPPORT, + 1), + ATOM_DEVICE_CRT1_SUPPORT); + radeon_add_legacy_connector(dev, 1, + ATOM_DEVICE_CRT1_SUPPORT, + DRM_MODE_CONNECTOR_VGA, + &ddc_i2c); + } else { + /* DVI-I - tv dac, int tmds */ + ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_DVI_DDC); + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id(dev, + ATOM_DEVICE_DFP1_SUPPORT, + 0), + ATOM_DEVICE_DFP1_SUPPORT); + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id(dev, + ATOM_DEVICE_CRT2_SUPPORT, + 2), + ATOM_DEVICE_CRT2_SUPPORT); + radeon_add_legacy_connector(dev, 0, + ATOM_DEVICE_DFP1_SUPPORT | + ATOM_DEVICE_CRT2_SUPPORT, + DRM_MODE_CONNECTOR_DVII, + &ddc_i2c); + + /* VGA - primary dac */ + ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_VGA_DDC); + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id(dev, + ATOM_DEVICE_CRT1_SUPPORT, + 1), + ATOM_DEVICE_CRT1_SUPPORT); + radeon_add_legacy_connector(dev, 1, + ATOM_DEVICE_CRT1_SUPPORT, + DRM_MODE_CONNECTOR_VGA, + &ddc_i2c); + } + + if (rdev->family != CHIP_R100 && rdev->family != CHIP_R200) { + /* TV - tv dac */ + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id(dev, + ATOM_DEVICE_TV1_SUPPORT, + 2), + ATOM_DEVICE_TV1_SUPPORT); + radeon_add_legacy_connector(dev, 2, + ATOM_DEVICE_TV1_SUPPORT, + DRM_MODE_CONNECTOR_SVIDEO, + &ddc_i2c); + } + break; + case CT_IBOOK: + DRM_INFO("Connector Table: %d (ibook)\n", + rdev->mode_info.connector_table); + /* LVDS */ + ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_DVI_DDC); + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id(dev, + ATOM_DEVICE_LCD1_SUPPORT, + 0), + ATOM_DEVICE_LCD1_SUPPORT); + radeon_add_legacy_connector(dev, 0, ATOM_DEVICE_LCD1_SUPPORT, + DRM_MODE_CONNECTOR_LVDS, &ddc_i2c); + /* VGA - TV DAC */ + ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_VGA_DDC); + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id(dev, + ATOM_DEVICE_CRT2_SUPPORT, + 2), + ATOM_DEVICE_CRT2_SUPPORT); + radeon_add_legacy_connector(dev, 1, ATOM_DEVICE_CRT2_SUPPORT, + DRM_MODE_CONNECTOR_VGA, &ddc_i2c); + /* TV - TV DAC */ + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id(dev, + ATOM_DEVICE_TV1_SUPPORT, + 2), + ATOM_DEVICE_TV1_SUPPORT); + radeon_add_legacy_connector(dev, 2, ATOM_DEVICE_TV1_SUPPORT, + DRM_MODE_CONNECTOR_SVIDEO, + &ddc_i2c); + break; + case CT_POWERBOOK_EXTERNAL: + DRM_INFO("Connector Table: %d (powerbook external tmds)\n", + rdev->mode_info.connector_table); + /* LVDS */ + ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_DVI_DDC); + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id(dev, + ATOM_DEVICE_LCD1_SUPPORT, + 0), + ATOM_DEVICE_LCD1_SUPPORT); + radeon_add_legacy_connector(dev, 0, ATOM_DEVICE_LCD1_SUPPORT, + DRM_MODE_CONNECTOR_LVDS, &ddc_i2c); + /* DVI-I - primary dac, ext tmds */ + ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_VGA_DDC); + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id(dev, + ATOM_DEVICE_DFP2_SUPPORT, + 0), + ATOM_DEVICE_DFP2_SUPPORT); + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id(dev, + ATOM_DEVICE_CRT1_SUPPORT, + 1), + ATOM_DEVICE_CRT1_SUPPORT); + radeon_add_legacy_connector(dev, 1, + ATOM_DEVICE_DFP2_SUPPORT | + ATOM_DEVICE_CRT1_SUPPORT, + DRM_MODE_CONNECTOR_DVII, &ddc_i2c); + /* TV - TV DAC */ + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id(dev, + ATOM_DEVICE_TV1_SUPPORT, + 2), + ATOM_DEVICE_TV1_SUPPORT); + radeon_add_legacy_connector(dev, 2, ATOM_DEVICE_TV1_SUPPORT, + DRM_MODE_CONNECTOR_SVIDEO, + &ddc_i2c); + break; + case CT_POWERBOOK_INTERNAL: + DRM_INFO("Connector Table: %d (powerbook internal tmds)\n", + rdev->mode_info.connector_table); + /* LVDS */ + ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_DVI_DDC); + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id(dev, + ATOM_DEVICE_LCD1_SUPPORT, + 0), + ATOM_DEVICE_LCD1_SUPPORT); + radeon_add_legacy_connector(dev, 0, ATOM_DEVICE_LCD1_SUPPORT, + DRM_MODE_CONNECTOR_LVDS, &ddc_i2c); + /* DVI-I - primary dac, int tmds */ + ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_VGA_DDC); + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id(dev, + ATOM_DEVICE_DFP1_SUPPORT, + 0), + ATOM_DEVICE_DFP1_SUPPORT); + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id(dev, + ATOM_DEVICE_CRT1_SUPPORT, + 1), + ATOM_DEVICE_CRT1_SUPPORT); + radeon_add_legacy_connector(dev, 1, + ATOM_DEVICE_DFP1_SUPPORT | + ATOM_DEVICE_CRT1_SUPPORT, + DRM_MODE_CONNECTOR_DVII, &ddc_i2c); + /* TV - TV DAC */ + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id(dev, + ATOM_DEVICE_TV1_SUPPORT, + 2), + ATOM_DEVICE_TV1_SUPPORT); + radeon_add_legacy_connector(dev, 2, ATOM_DEVICE_TV1_SUPPORT, + DRM_MODE_CONNECTOR_SVIDEO, + &ddc_i2c); + break; + case CT_POWERBOOK_VGA: + DRM_INFO("Connector Table: %d (powerbook vga)\n", + rdev->mode_info.connector_table); + /* LVDS */ + ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_DVI_DDC); + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id(dev, + ATOM_DEVICE_LCD1_SUPPORT, + 0), + ATOM_DEVICE_LCD1_SUPPORT); + radeon_add_legacy_connector(dev, 0, ATOM_DEVICE_LCD1_SUPPORT, + DRM_MODE_CONNECTOR_LVDS, &ddc_i2c); + /* VGA - primary dac */ + ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_VGA_DDC); + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id(dev, + ATOM_DEVICE_CRT1_SUPPORT, + 1), + ATOM_DEVICE_CRT1_SUPPORT); + radeon_add_legacy_connector(dev, 1, ATOM_DEVICE_CRT1_SUPPORT, + DRM_MODE_CONNECTOR_VGA, &ddc_i2c); + /* TV - TV DAC */ + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id(dev, + ATOM_DEVICE_TV1_SUPPORT, + 2), + ATOM_DEVICE_TV1_SUPPORT); + radeon_add_legacy_connector(dev, 2, ATOM_DEVICE_TV1_SUPPORT, + DRM_MODE_CONNECTOR_SVIDEO, + &ddc_i2c); + break; + case CT_MINI_EXTERNAL: + DRM_INFO("Connector Table: %d (mini external tmds)\n", + rdev->mode_info.connector_table); + /* DVI-I - tv dac, ext tmds */ + ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_CRT2_DDC); + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id(dev, + ATOM_DEVICE_DFP2_SUPPORT, + 0), + ATOM_DEVICE_DFP2_SUPPORT); + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id(dev, + ATOM_DEVICE_CRT2_SUPPORT, + 2), + ATOM_DEVICE_CRT2_SUPPORT); + radeon_add_legacy_connector(dev, 0, + ATOM_DEVICE_DFP2_SUPPORT | + ATOM_DEVICE_CRT2_SUPPORT, + DRM_MODE_CONNECTOR_DVII, &ddc_i2c); + /* TV - TV DAC */ + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id(dev, + ATOM_DEVICE_TV1_SUPPORT, + 2), + ATOM_DEVICE_TV1_SUPPORT); + radeon_add_legacy_connector(dev, 1, ATOM_DEVICE_TV1_SUPPORT, + DRM_MODE_CONNECTOR_SVIDEO, + &ddc_i2c); + break; + case CT_MINI_INTERNAL: + DRM_INFO("Connector Table: %d (mini internal tmds)\n", + rdev->mode_info.connector_table); + /* DVI-I - tv dac, int tmds */ + ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_CRT2_DDC); + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id(dev, + ATOM_DEVICE_DFP1_SUPPORT, + 0), + ATOM_DEVICE_DFP1_SUPPORT); + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id(dev, + ATOM_DEVICE_CRT2_SUPPORT, + 2), + ATOM_DEVICE_CRT2_SUPPORT); + radeon_add_legacy_connector(dev, 0, + ATOM_DEVICE_DFP1_SUPPORT | + ATOM_DEVICE_CRT2_SUPPORT, + DRM_MODE_CONNECTOR_DVII, &ddc_i2c); + /* TV - TV DAC */ + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id(dev, + ATOM_DEVICE_TV1_SUPPORT, + 2), + ATOM_DEVICE_TV1_SUPPORT); + radeon_add_legacy_connector(dev, 1, ATOM_DEVICE_TV1_SUPPORT, + DRM_MODE_CONNECTOR_SVIDEO, + &ddc_i2c); + break; + case CT_IMAC_G5_ISIGHT: + DRM_INFO("Connector Table: %d (imac g5 isight)\n", + rdev->mode_info.connector_table); + /* DVI-D - int tmds */ + ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_MONID); + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id(dev, + ATOM_DEVICE_DFP1_SUPPORT, + 0), + ATOM_DEVICE_DFP1_SUPPORT); + radeon_add_legacy_connector(dev, 0, ATOM_DEVICE_DFP1_SUPPORT, + DRM_MODE_CONNECTOR_DVID, &ddc_i2c); + /* VGA - tv dac */ + ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_DVI_DDC); + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id(dev, + ATOM_DEVICE_CRT2_SUPPORT, + 2), + ATOM_DEVICE_CRT2_SUPPORT); + radeon_add_legacy_connector(dev, 1, ATOM_DEVICE_CRT2_SUPPORT, + DRM_MODE_CONNECTOR_VGA, &ddc_i2c); + /* TV - TV DAC */ + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id(dev, + ATOM_DEVICE_TV1_SUPPORT, + 2), + ATOM_DEVICE_TV1_SUPPORT); + radeon_add_legacy_connector(dev, 2, ATOM_DEVICE_TV1_SUPPORT, + DRM_MODE_CONNECTOR_SVIDEO, + &ddc_i2c); + break; + case CT_EMAC: + DRM_INFO("Connector Table: %d (emac)\n", + rdev->mode_info.connector_table); + /* VGA - primary dac */ + ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_VGA_DDC); + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id(dev, + ATOM_DEVICE_CRT1_SUPPORT, + 1), + ATOM_DEVICE_CRT1_SUPPORT); + radeon_add_legacy_connector(dev, 0, ATOM_DEVICE_CRT1_SUPPORT, + DRM_MODE_CONNECTOR_VGA, &ddc_i2c); + /* VGA - tv dac */ + ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_CRT2_DDC); + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id(dev, + ATOM_DEVICE_CRT2_SUPPORT, + 2), + ATOM_DEVICE_CRT2_SUPPORT); + radeon_add_legacy_connector(dev, 1, ATOM_DEVICE_CRT2_SUPPORT, + DRM_MODE_CONNECTOR_VGA, &ddc_i2c); + /* TV - TV DAC */ + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id(dev, + ATOM_DEVICE_TV1_SUPPORT, + 2), + ATOM_DEVICE_TV1_SUPPORT); + radeon_add_legacy_connector(dev, 2, ATOM_DEVICE_TV1_SUPPORT, + DRM_MODE_CONNECTOR_SVIDEO, + &ddc_i2c); + break; + default: + DRM_INFO("Connector table: %d (invalid)\n", + rdev->mode_info.connector_table); + return false; + } + + radeon_link_encoder_connector(dev); + + return true; +} + +static bool radeon_apply_legacy_quirks(struct drm_device *dev, + int bios_index, + enum radeon_combios_connector + *legacy_connector, + struct radeon_i2c_bus_rec *ddc_i2c) +{ + struct radeon_device *rdev = dev->dev_private; + + /* XPRESS DDC quirks */ + if ((rdev->family == CHIP_RS400 || + rdev->family == CHIP_RS480) && + ddc_i2c->mask_clk_reg == RADEON_GPIO_CRT2_DDC) + *ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_MONID); + else if ((rdev->family == CHIP_RS400 || + rdev->family == CHIP_RS480) && + ddc_i2c->mask_clk_reg == RADEON_GPIO_MONID) { + ddc_i2c->valid = true; + ddc_i2c->mask_clk_mask = (0x20 << 8); + ddc_i2c->mask_data_mask = 0x80; + ddc_i2c->a_clk_mask = (0x20 << 8); + ddc_i2c->a_data_mask = 0x80; + ddc_i2c->put_clk_mask = (0x20 << 8); + ddc_i2c->put_data_mask = 0x80; + ddc_i2c->get_clk_mask = (0x20 << 8); + ddc_i2c->get_data_mask = 0x80; + ddc_i2c->mask_clk_reg = RADEON_GPIOPAD_MASK; + ddc_i2c->mask_data_reg = RADEON_GPIOPAD_MASK; + ddc_i2c->a_clk_reg = RADEON_GPIOPAD_A; + ddc_i2c->a_data_reg = RADEON_GPIOPAD_A; + ddc_i2c->put_clk_reg = RADEON_GPIOPAD_EN; + ddc_i2c->put_data_reg = RADEON_GPIOPAD_EN; + ddc_i2c->get_clk_reg = RADEON_LCD_GPIO_Y_REG; + ddc_i2c->get_data_reg = RADEON_LCD_GPIO_Y_REG; + } + + /* Certain IBM chipset RN50s have a BIOS reporting two VGAs, + one with VGA DDC and one with CRT2 DDC. - kill the CRT2 DDC one */ + if (dev->pdev->device == 0x515e && + dev->pdev->subsystem_vendor == 0x1014) { + if (*legacy_connector == CONNECTOR_CRT_LEGACY && + ddc_i2c->mask_clk_reg == RADEON_GPIO_CRT2_DDC) + return false; + } + + /* Some RV100 cards with 2 VGA ports show up with DVI+VGA */ + if (dev->pdev->device == 0x5159 && + dev->pdev->subsystem_vendor == 0x1002 && + dev->pdev->subsystem_device == 0x013a) { + if (*legacy_connector == CONNECTOR_DVI_I_LEGACY) + *legacy_connector = CONNECTOR_CRT_LEGACY; + + } + + /* X300 card with extra non-existent DVI port */ + if (dev->pdev->device == 0x5B60 && + dev->pdev->subsystem_vendor == 0x17af && + dev->pdev->subsystem_device == 0x201e && bios_index == 2) { + if (*legacy_connector == CONNECTOR_DVI_I_LEGACY) + return false; + } + + return true; +} + +bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) +{ + struct radeon_device *rdev = dev->dev_private; + uint32_t conn_info, entry, devices; + uint16_t tmp; + enum radeon_combios_ddc ddc_type; + enum radeon_combios_connector connector; + int i = 0; + struct radeon_i2c_bus_rec ddc_i2c; + + if (rdev->bios == NULL) + return false; + + conn_info = combios_get_table_offset(dev, COMBIOS_CONNECTOR_INFO_TABLE); + if (conn_info) { + for (i = 0; i < 4; i++) { + entry = conn_info + 2 + i * 2; + + if (!RBIOS16(entry)) + break; + + tmp = RBIOS16(entry); + + connector = (tmp >> 12) & 0xf; + + ddc_type = (tmp >> 8) & 0xf; + switch (ddc_type) { + case DDC_MONID: + ddc_i2c = + combios_setup_i2c_bus(RADEON_GPIO_MONID); + break; + case DDC_DVI: + ddc_i2c = + combios_setup_i2c_bus(RADEON_GPIO_DVI_DDC); + break; + case DDC_VGA: + ddc_i2c = + combios_setup_i2c_bus(RADEON_GPIO_VGA_DDC); + break; + case DDC_CRT2: + ddc_i2c = + combios_setup_i2c_bus(RADEON_GPIO_CRT2_DDC); + break; + default: + break; + } + + radeon_apply_legacy_quirks(dev, i, &connector, + &ddc_i2c); + + switch (connector) { + case CONNECTOR_PROPRIETARY_LEGACY: + if ((tmp >> 4) & 0x1) + devices = ATOM_DEVICE_DFP2_SUPPORT; + else + devices = ATOM_DEVICE_DFP1_SUPPORT; + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id + (dev, devices, 0), + devices); + radeon_add_legacy_connector(dev, i, devices, + legacy_connector_convert + [connector], + &ddc_i2c); + break; + case CONNECTOR_CRT_LEGACY: + if (tmp & 0x1) { + devices = ATOM_DEVICE_CRT2_SUPPORT; + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id + (dev, + ATOM_DEVICE_CRT2_SUPPORT, + 2), + ATOM_DEVICE_CRT2_SUPPORT); + } else { + devices = ATOM_DEVICE_CRT1_SUPPORT; + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id + (dev, + ATOM_DEVICE_CRT1_SUPPORT, + 1), + ATOM_DEVICE_CRT1_SUPPORT); + } + radeon_add_legacy_connector(dev, + i, + devices, + legacy_connector_convert + [connector], + &ddc_i2c); + break; + case CONNECTOR_DVI_I_LEGACY: + devices = 0; + if (tmp & 0x1) { + devices |= ATOM_DEVICE_CRT2_SUPPORT; + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id + (dev, + ATOM_DEVICE_CRT2_SUPPORT, + 2), + ATOM_DEVICE_CRT2_SUPPORT); + } else { + devices |= ATOM_DEVICE_CRT1_SUPPORT; + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id + (dev, + ATOM_DEVICE_CRT1_SUPPORT, + 1), + ATOM_DEVICE_CRT1_SUPPORT); + } + if ((tmp >> 4) & 0x1) { + devices |= ATOM_DEVICE_DFP2_SUPPORT; + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id + (dev, + ATOM_DEVICE_DFP2_SUPPORT, + 0), + ATOM_DEVICE_DFP2_SUPPORT); + } else { + devices |= ATOM_DEVICE_DFP1_SUPPORT; + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id + (dev, + ATOM_DEVICE_DFP1_SUPPORT, + 0), + ATOM_DEVICE_DFP1_SUPPORT); + } + radeon_add_legacy_connector(dev, + i, + devices, + legacy_connector_convert + [connector], + &ddc_i2c); + break; + case CONNECTOR_DVI_D_LEGACY: + if ((tmp >> 4) & 0x1) + devices = ATOM_DEVICE_DFP2_SUPPORT; + else + devices = ATOM_DEVICE_DFP1_SUPPORT; + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id + (dev, devices, 0), + devices); + radeon_add_legacy_connector(dev, i, devices, + legacy_connector_convert + [connector], + &ddc_i2c); + break; + case CONNECTOR_CTV_LEGACY: + case CONNECTOR_STV_LEGACY: + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id + (dev, + ATOM_DEVICE_TV1_SUPPORT, + 2), + ATOM_DEVICE_TV1_SUPPORT); + radeon_add_legacy_connector(dev, i, + ATOM_DEVICE_TV1_SUPPORT, + legacy_connector_convert + [connector], + &ddc_i2c); + break; + default: + DRM_ERROR("Unknown connector type: %d\n", + connector); + continue; + } + + } + } else { + uint16_t tmds_info = + combios_get_table_offset(dev, COMBIOS_DFP_INFO_TABLE); + if (tmds_info) { + DRM_DEBUG("Found DFP table, assuming DVI connector\n"); + + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id(dev, + ATOM_DEVICE_CRT1_SUPPORT, + 1), + ATOM_DEVICE_CRT1_SUPPORT); + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id(dev, + ATOM_DEVICE_DFP1_SUPPORT, + 0), + ATOM_DEVICE_DFP1_SUPPORT); + + ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_DVI_DDC); + radeon_add_legacy_connector(dev, + 0, + ATOM_DEVICE_CRT1_SUPPORT | + ATOM_DEVICE_DFP1_SUPPORT, + DRM_MODE_CONNECTOR_DVII, + &ddc_i2c); + } else { + DRM_DEBUG("No connector info found\n"); + return false; + } + } + + if (rdev->flags & RADEON_IS_MOBILITY || rdev->flags & RADEON_IS_IGP) { + uint16_t lcd_info = + combios_get_table_offset(dev, COMBIOS_LCD_INFO_TABLE); + if (lcd_info) { + uint16_t lcd_ddc_info = + combios_get_table_offset(dev, + COMBIOS_LCD_DDC_INFO_TABLE); + + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id(dev, + ATOM_DEVICE_LCD1_SUPPORT, + 0), + ATOM_DEVICE_LCD1_SUPPORT); + + if (lcd_ddc_info) { + ddc_type = RBIOS8(lcd_ddc_info + 2); + switch (ddc_type) { + case DDC_MONID: + ddc_i2c = + combios_setup_i2c_bus + (RADEON_GPIO_MONID); + break; + case DDC_DVI: + ddc_i2c = + combios_setup_i2c_bus + (RADEON_GPIO_DVI_DDC); + break; + case DDC_VGA: + ddc_i2c = + combios_setup_i2c_bus + (RADEON_GPIO_VGA_DDC); + break; + case DDC_CRT2: + ddc_i2c = + combios_setup_i2c_bus + (RADEON_GPIO_CRT2_DDC); + break; + case DDC_LCD: + ddc_i2c = + combios_setup_i2c_bus + (RADEON_LCD_GPIO_MASK); + ddc_i2c.mask_clk_mask = + RBIOS32(lcd_ddc_info + 3); + ddc_i2c.mask_data_mask = + RBIOS32(lcd_ddc_info + 7); + ddc_i2c.a_clk_mask = + RBIOS32(lcd_ddc_info + 3); + ddc_i2c.a_data_mask = + RBIOS32(lcd_ddc_info + 7); + ddc_i2c.put_clk_mask = + RBIOS32(lcd_ddc_info + 3); + ddc_i2c.put_data_mask = + RBIOS32(lcd_ddc_info + 7); + ddc_i2c.get_clk_mask = + RBIOS32(lcd_ddc_info + 3); + ddc_i2c.get_data_mask = + RBIOS32(lcd_ddc_info + 7); + break; + case DDC_GPIO: + ddc_i2c = + combios_setup_i2c_bus + (RADEON_MDGPIO_EN_REG); + ddc_i2c.mask_clk_mask = + RBIOS32(lcd_ddc_info + 3); + ddc_i2c.mask_data_mask = + RBIOS32(lcd_ddc_info + 7); + ddc_i2c.a_clk_mask = + RBIOS32(lcd_ddc_info + 3); + ddc_i2c.a_data_mask = + RBIOS32(lcd_ddc_info + 7); + ddc_i2c.put_clk_mask = + RBIOS32(lcd_ddc_info + 3); + ddc_i2c.put_data_mask = + RBIOS32(lcd_ddc_info + 7); + ddc_i2c.get_clk_mask = + RBIOS32(lcd_ddc_info + 3); + ddc_i2c.get_data_mask = + RBIOS32(lcd_ddc_info + 7); + break; + default: + ddc_i2c.valid = false; + break; + } + DRM_DEBUG("LCD DDC Info Table found!\n"); + } else + ddc_i2c.valid = false; + + radeon_add_legacy_connector(dev, + 5, + ATOM_DEVICE_LCD1_SUPPORT, + DRM_MODE_CONNECTOR_LVDS, + &ddc_i2c); + } + } + + /* check TV table */ + if (rdev->family != CHIP_R100 && rdev->family != CHIP_R200) { + uint32_t tv_info = + combios_get_table_offset(dev, COMBIOS_TV_INFO_TABLE); + if (tv_info) { + if (RBIOS8(tv_info + 6) == 'T') { + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id + (dev, + ATOM_DEVICE_TV1_SUPPORT, + 2), + ATOM_DEVICE_TV1_SUPPORT); + radeon_add_legacy_connector(dev, 6, + ATOM_DEVICE_TV1_SUPPORT, + DRM_MODE_CONNECTOR_SVIDEO, + &ddc_i2c); + } + } + } + + radeon_link_encoder_connector(dev); + + return true; +} + +static void combios_parse_mmio_table(struct drm_device *dev, uint16_t offset) +{ + struct radeon_device *rdev = dev->dev_private; + + if (offset) { + while (RBIOS16(offset)) { + uint16_t cmd = ((RBIOS16(offset) & 0xe000) >> 13); + uint32_t addr = (RBIOS16(offset) & 0x1fff); + uint32_t val, and_mask, or_mask; + uint32_t tmp; + + offset += 2; + switch (cmd) { + case 0: + val = RBIOS32(offset); + offset += 4; + WREG32(addr, val); + break; + case 1: + val = RBIOS32(offset); + offset += 4; + WREG32(addr, val); + break; + case 2: + and_mask = RBIOS32(offset); + offset += 4; + or_mask = RBIOS32(offset); + offset += 4; + tmp = RREG32(addr); + tmp &= and_mask; + tmp |= or_mask; + WREG32(addr, tmp); + break; + case 3: + and_mask = RBIOS32(offset); + offset += 4; + or_mask = RBIOS32(offset); + offset += 4; + tmp = RREG32(addr); + tmp &= and_mask; + tmp |= or_mask; + WREG32(addr, tmp); + break; + case 4: + val = RBIOS16(offset); + offset += 2; + udelay(val); + break; + case 5: + val = RBIOS16(offset); + offset += 2; + switch (addr) { + case 8: + while (val--) { + if (! + (RREG32_PLL + (RADEON_CLK_PWRMGT_CNTL) & + RADEON_MC_BUSY)) + break; + } + break; + case 9: + while (val--) { + if ((RREG32(RADEON_MC_STATUS) & + RADEON_MC_IDLE)) + break; + } + break; + default: + break; + } + break; + default: + break; + } + } + } +} + +static void combios_parse_pll_table(struct drm_device *dev, uint16_t offset) +{ + struct radeon_device *rdev = dev->dev_private; + + if (offset) { + while (RBIOS8(offset)) { + uint8_t cmd = ((RBIOS8(offset) & 0xc0) >> 6); + uint8_t addr = (RBIOS8(offset) & 0x3f); + uint32_t val, shift, tmp; + uint32_t and_mask, or_mask; + + offset++; + switch (cmd) { + case 0: + val = RBIOS32(offset); + offset += 4; + WREG32_PLL(addr, val); + break; + case 1: + shift = RBIOS8(offset) * 8; + offset++; + and_mask = RBIOS8(offset) << shift; + and_mask |= ~(0xff << shift); + offset++; + or_mask = RBIOS8(offset) << shift; + offset++; + tmp = RREG32_PLL(addr); + tmp &= and_mask; + tmp |= or_mask; + WREG32_PLL(addr, tmp); + break; + case 2: + case 3: + tmp = 1000; + switch (addr) { + case 1: + udelay(150); + break; + case 2: + udelay(1000); + break; + case 3: + while (tmp--) { + if (! + (RREG32_PLL + (RADEON_CLK_PWRMGT_CNTL) & + RADEON_MC_BUSY)) + break; + } + break; + case 4: + while (tmp--) { + if (RREG32_PLL + (RADEON_CLK_PWRMGT_CNTL) & + RADEON_DLL_READY) + break; + } + break; + case 5: + tmp = + RREG32_PLL(RADEON_CLK_PWRMGT_CNTL); + if (tmp & RADEON_CG_NO1_DEBUG_0) { +#if 0 + uint32_t mclk_cntl = + RREG32_PLL + (RADEON_MCLK_CNTL); + mclk_cntl &= 0xffff0000; + /*mclk_cntl |= 0x00001111;*//* ??? */ + WREG32_PLL(RADEON_MCLK_CNTL, + mclk_cntl); + udelay(10000); +#endif + WREG32_PLL + (RADEON_CLK_PWRMGT_CNTL, + tmp & + ~RADEON_CG_NO1_DEBUG_0); + udelay(10000); + } + break; + default: + break; + } + break; + default: + break; + } + } + } +} + +static void combios_parse_ram_reset_table(struct drm_device *dev, + uint16_t offset) +{ + struct radeon_device *rdev = dev->dev_private; + uint32_t tmp; + + if (offset) { + uint8_t val = RBIOS8(offset); + while (val != 0xff) { + offset++; + + if (val == 0x0f) { + uint32_t channel_complete_mask; + + if (ASIC_IS_R300(rdev)) + channel_complete_mask = + R300_MEM_PWRUP_COMPLETE; + else + channel_complete_mask = + RADEON_MEM_PWRUP_COMPLETE; + tmp = 20000; + while (tmp--) { + if ((RREG32(RADEON_MEM_STR_CNTL) & + channel_complete_mask) == + channel_complete_mask) + break; + } + } else { + uint32_t or_mask = RBIOS16(offset); + offset += 2; + + tmp = RREG32(RADEON_MEM_SDRAM_MODE_REG); + tmp &= RADEON_SDRAM_MODE_MASK; + tmp |= or_mask; + WREG32(RADEON_MEM_SDRAM_MODE_REG, tmp); + + or_mask = val << 24; + tmp = RREG32(RADEON_MEM_SDRAM_MODE_REG); + tmp &= RADEON_B3MEM_RESET_MASK; + tmp |= or_mask; + WREG32(RADEON_MEM_SDRAM_MODE_REG, tmp); + } + val = RBIOS8(offset); + } + } +} + +static uint32_t combios_detect_ram(struct drm_device *dev, int ram, + int mem_addr_mapping) +{ + struct radeon_device *rdev = dev->dev_private; + uint32_t mem_cntl; + uint32_t mem_size; + uint32_t addr = 0; + + mem_cntl = RREG32(RADEON_MEM_CNTL); + if (mem_cntl & RV100_HALF_MODE) + ram /= 2; + mem_size = ram; + mem_cntl &= ~(0xff << 8); + mem_cntl |= (mem_addr_mapping & 0xff) << 8; + WREG32(RADEON_MEM_CNTL, mem_cntl); + RREG32(RADEON_MEM_CNTL); + + /* sdram reset ? */ + + /* something like this???? */ + while (ram--) { + addr = ram * 1024 * 1024; + /* write to each page */ + WREG32(RADEON_MM_INDEX, (addr) | RADEON_MM_APER); + WREG32(RADEON_MM_DATA, 0xdeadbeef); + /* read back and verify */ + WREG32(RADEON_MM_INDEX, (addr) | RADEON_MM_APER); + if (RREG32(RADEON_MM_DATA) != 0xdeadbeef) + return 0; + } + + return mem_size; +} + +static void combios_write_ram_size(struct drm_device *dev) +{ + struct radeon_device *rdev = dev->dev_private; + uint8_t rev; + uint16_t offset; + uint32_t mem_size = 0; + uint32_t mem_cntl = 0; + + /* should do something smarter here I guess... */ + if (rdev->flags & RADEON_IS_IGP) + return; + + /* first check detected mem table */ + offset = combios_get_table_offset(dev, COMBIOS_DETECTED_MEM_TABLE); + if (offset) { + rev = RBIOS8(offset); + if (rev < 3) { + mem_cntl = RBIOS32(offset + 1); + mem_size = RBIOS16(offset + 5); + if (((rdev->flags & RADEON_FAMILY_MASK) < CHIP_R200) && + ((dev->pdev->device != 0x515e) + && (dev->pdev->device != 0x5969))) + WREG32(RADEON_MEM_CNTL, mem_cntl); + } + } + + if (!mem_size) { + offset = + combios_get_table_offset(dev, COMBIOS_MEM_CONFIG_TABLE); + if (offset) { + rev = RBIOS8(offset - 1); + if (rev < 1) { + if (((rdev->flags & RADEON_FAMILY_MASK) < + CHIP_R200) + && ((dev->pdev->device != 0x515e) + && (dev->pdev->device != 0x5969))) { + int ram = 0; + int mem_addr_mapping = 0; + + while (RBIOS8(offset)) { + ram = RBIOS8(offset); + mem_addr_mapping = + RBIOS8(offset + 1); + if (mem_addr_mapping != 0x25) + ram *= 2; + mem_size = + combios_detect_ram(dev, ram, + mem_addr_mapping); + if (mem_size) + break; + offset += 2; + } + } else + mem_size = RBIOS8(offset); + } else { + mem_size = RBIOS8(offset); + mem_size *= 2; /* convert to MB */ + } + } + } + + mem_size *= (1024 * 1024); /* convert to bytes */ + WREG32(RADEON_CONFIG_MEMSIZE, mem_size); +} + +void radeon_combios_dyn_clk_setup(struct drm_device *dev, int enable) +{ + uint16_t dyn_clk_info = + combios_get_table_offset(dev, COMBIOS_DYN_CLK_1_TABLE); + + if (dyn_clk_info) + combios_parse_pll_table(dev, dyn_clk_info); +} + +void radeon_combios_asic_init(struct drm_device *dev) +{ + struct radeon_device *rdev = dev->dev_private; + uint16_t table; + + /* port hardcoded mac stuff from radeonfb */ + if (rdev->bios == NULL) + return; + + /* ASIC INIT 1 */ + table = combios_get_table_offset(dev, COMBIOS_ASIC_INIT_1_TABLE); + if (table) + combios_parse_mmio_table(dev, table); + + /* PLL INIT */ + table = combios_get_table_offset(dev, COMBIOS_PLL_INIT_TABLE); + if (table) + combios_parse_pll_table(dev, table); + + /* ASIC INIT 2 */ + table = combios_get_table_offset(dev, COMBIOS_ASIC_INIT_2_TABLE); + if (table) + combios_parse_mmio_table(dev, table); + + if (!(rdev->flags & RADEON_IS_IGP)) { + /* ASIC INIT 4 */ + table = + combios_get_table_offset(dev, COMBIOS_ASIC_INIT_4_TABLE); + if (table) + combios_parse_mmio_table(dev, table); + + /* RAM RESET */ + table = combios_get_table_offset(dev, COMBIOS_RAM_RESET_TABLE); + if (table) + combios_parse_ram_reset_table(dev, table); + + /* ASIC INIT 3 */ + table = + combios_get_table_offset(dev, COMBIOS_ASIC_INIT_3_TABLE); + if (table) + combios_parse_mmio_table(dev, table); + + /* write CONFIG_MEMSIZE */ + combios_write_ram_size(dev); + } + + /* DYN CLK 1 */ + table = combios_get_table_offset(dev, COMBIOS_DYN_CLK_1_TABLE); + if (table) + combios_parse_pll_table(dev, table); + +} + +void radeon_combios_initialize_bios_scratch_regs(struct drm_device *dev) +{ + struct radeon_device *rdev = dev->dev_private; + uint32_t bios_0_scratch, bios_6_scratch, bios_7_scratch; + + bios_0_scratch = RREG32(RADEON_BIOS_0_SCRATCH); + bios_6_scratch = RREG32(RADEON_BIOS_6_SCRATCH); + bios_7_scratch = RREG32(RADEON_BIOS_7_SCRATCH); + + /* let the bios control the backlight */ + bios_0_scratch &= ~RADEON_DRIVER_BRIGHTNESS_EN; + + /* tell the bios not to handle mode switching */ + bios_6_scratch |= (RADEON_DISPLAY_SWITCHING_DIS | + RADEON_ACC_MODE_CHANGE); + + /* tell the bios a driver is loaded */ + bios_7_scratch |= RADEON_DRV_LOADED; + + WREG32(RADEON_BIOS_0_SCRATCH, bios_0_scratch); + WREG32(RADEON_BIOS_6_SCRATCH, bios_6_scratch); + WREG32(RADEON_BIOS_7_SCRATCH, bios_7_scratch); +} + +void radeon_combios_output_lock(struct drm_encoder *encoder, bool lock) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + uint32_t bios_6_scratch; + + bios_6_scratch = RREG32(RADEON_BIOS_6_SCRATCH); + + if (lock) + bios_6_scratch |= RADEON_DRIVER_CRITICAL; + else + bios_6_scratch &= ~RADEON_DRIVER_CRITICAL; + + WREG32(RADEON_BIOS_6_SCRATCH, bios_6_scratch); +} + +void +radeon_combios_connected_scratch_regs(struct drm_connector *connector, + struct drm_encoder *encoder, + bool connected) +{ + struct drm_device *dev = connector->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_connector *radeon_connector = + to_radeon_connector(connector); + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + uint32_t bios_4_scratch = RREG32(RADEON_BIOS_4_SCRATCH); + uint32_t bios_5_scratch = RREG32(RADEON_BIOS_5_SCRATCH); + + if ((radeon_encoder->devices & ATOM_DEVICE_TV1_SUPPORT) && + (radeon_connector->devices & ATOM_DEVICE_TV1_SUPPORT)) { + if (connected) { + DRM_DEBUG("TV1 connected\n"); + /* fix me */ + bios_4_scratch |= RADEON_TV1_ATTACHED_SVIDEO; + /*save->bios_4_scratch |= RADEON_TV1_ATTACHED_COMP; */ + bios_5_scratch |= RADEON_TV1_ON; + bios_5_scratch |= RADEON_ACC_REQ_TV1; + } else { + DRM_DEBUG("TV1 disconnected\n"); + bios_4_scratch &= ~RADEON_TV1_ATTACHED_MASK; + bios_5_scratch &= ~RADEON_TV1_ON; + bios_5_scratch &= ~RADEON_ACC_REQ_TV1; + } + } + if ((radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) && + (radeon_connector->devices & ATOM_DEVICE_LCD1_SUPPORT)) { + if (connected) { + DRM_DEBUG("LCD1 connected\n"); + bios_4_scratch |= RADEON_LCD1_ATTACHED; + bios_5_scratch |= RADEON_LCD1_ON; + bios_5_scratch |= RADEON_ACC_REQ_LCD1; + } else { + DRM_DEBUG("LCD1 disconnected\n"); + bios_4_scratch &= ~RADEON_LCD1_ATTACHED; + bios_5_scratch &= ~RADEON_LCD1_ON; + bios_5_scratch &= ~RADEON_ACC_REQ_LCD1; + } + } + if ((radeon_encoder->devices & ATOM_DEVICE_CRT1_SUPPORT) && + (radeon_connector->devices & ATOM_DEVICE_CRT1_SUPPORT)) { + if (connected) { + DRM_DEBUG("CRT1 connected\n"); + bios_4_scratch |= RADEON_CRT1_ATTACHED_COLOR; + bios_5_scratch |= RADEON_CRT1_ON; + bios_5_scratch |= RADEON_ACC_REQ_CRT1; + } else { + DRM_DEBUG("CRT1 disconnected\n"); + bios_4_scratch &= ~RADEON_CRT1_ATTACHED_MASK; + bios_5_scratch &= ~RADEON_CRT1_ON; + bios_5_scratch &= ~RADEON_ACC_REQ_CRT1; + } + } + if ((radeon_encoder->devices & ATOM_DEVICE_CRT2_SUPPORT) && + (radeon_connector->devices & ATOM_DEVICE_CRT2_SUPPORT)) { + if (connected) { + DRM_DEBUG("CRT2 connected\n"); + bios_4_scratch |= RADEON_CRT2_ATTACHED_COLOR; + bios_5_scratch |= RADEON_CRT2_ON; + bios_5_scratch |= RADEON_ACC_REQ_CRT2; + } else { + DRM_DEBUG("CRT2 disconnected\n"); + bios_4_scratch &= ~RADEON_CRT2_ATTACHED_MASK; + bios_5_scratch &= ~RADEON_CRT2_ON; + bios_5_scratch &= ~RADEON_ACC_REQ_CRT2; + } + } + if ((radeon_encoder->devices & ATOM_DEVICE_DFP1_SUPPORT) && + (radeon_connector->devices & ATOM_DEVICE_DFP1_SUPPORT)) { + if (connected) { + DRM_DEBUG("DFP1 connected\n"); + bios_4_scratch |= RADEON_DFP1_ATTACHED; + bios_5_scratch |= RADEON_DFP1_ON; + bios_5_scratch |= RADEON_ACC_REQ_DFP1; + } else { + DRM_DEBUG("DFP1 disconnected\n"); + bios_4_scratch &= ~RADEON_DFP1_ATTACHED; + bios_5_scratch &= ~RADEON_DFP1_ON; + bios_5_scratch &= ~RADEON_ACC_REQ_DFP1; + } + } + if ((radeon_encoder->devices & ATOM_DEVICE_DFP2_SUPPORT) && + (radeon_connector->devices & ATOM_DEVICE_DFP2_SUPPORT)) { + if (connected) { + DRM_DEBUG("DFP2 connected\n"); + bios_4_scratch |= RADEON_DFP2_ATTACHED; + bios_5_scratch |= RADEON_DFP2_ON; + bios_5_scratch |= RADEON_ACC_REQ_DFP2; + } else { + DRM_DEBUG("DFP2 disconnected\n"); + bios_4_scratch &= ~RADEON_DFP2_ATTACHED; + bios_5_scratch &= ~RADEON_DFP2_ON; + bios_5_scratch &= ~RADEON_ACC_REQ_DFP2; + } + } + WREG32(RADEON_BIOS_4_SCRATCH, bios_4_scratch); + WREG32(RADEON_BIOS_5_SCRATCH, bios_5_scratch); +} + +void +radeon_combios_encoder_crtc_scratch_regs(struct drm_encoder *encoder, int crtc) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + uint32_t bios_5_scratch = RREG32(RADEON_BIOS_5_SCRATCH); + + if (radeon_encoder->devices & ATOM_DEVICE_TV1_SUPPORT) { + bios_5_scratch &= ~RADEON_TV1_CRTC_MASK; + bios_5_scratch |= (crtc << RADEON_TV1_CRTC_SHIFT); + } + if (radeon_encoder->devices & ATOM_DEVICE_CRT1_SUPPORT) { + bios_5_scratch &= ~RADEON_CRT1_CRTC_MASK; + bios_5_scratch |= (crtc << RADEON_CRT1_CRTC_SHIFT); + } + if (radeon_encoder->devices & ATOM_DEVICE_CRT2_SUPPORT) { + bios_5_scratch &= ~RADEON_CRT2_CRTC_MASK; + bios_5_scratch |= (crtc << RADEON_CRT2_CRTC_SHIFT); + } + if (radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) { + bios_5_scratch &= ~RADEON_LCD1_CRTC_MASK; + bios_5_scratch |= (crtc << RADEON_LCD1_CRTC_SHIFT); + } + if (radeon_encoder->devices & ATOM_DEVICE_DFP1_SUPPORT) { + bios_5_scratch &= ~RADEON_DFP1_CRTC_MASK; + bios_5_scratch |= (crtc << RADEON_DFP1_CRTC_SHIFT); + } + if (radeon_encoder->devices & ATOM_DEVICE_DFP2_SUPPORT) { + bios_5_scratch &= ~RADEON_DFP2_CRTC_MASK; + bios_5_scratch |= (crtc << RADEON_DFP2_CRTC_SHIFT); + } + WREG32(RADEON_BIOS_5_SCRATCH, bios_5_scratch); +} + +void +radeon_combios_encoder_dpms_scratch_regs(struct drm_encoder *encoder, bool on) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + uint32_t bios_6_scratch = RREG32(RADEON_BIOS_6_SCRATCH); + + if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT)) { + if (on) + bios_6_scratch |= RADEON_TV_DPMS_ON; + else + bios_6_scratch &= ~RADEON_TV_DPMS_ON; + } + if (radeon_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT)) { + if (on) + bios_6_scratch |= RADEON_CRT_DPMS_ON; + else + bios_6_scratch &= ~RADEON_CRT_DPMS_ON; + } + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { + if (on) + bios_6_scratch |= RADEON_LCD_DPMS_ON; + else + bios_6_scratch &= ~RADEON_LCD_DPMS_ON; + } + if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { + if (on) + bios_6_scratch |= RADEON_DFP_DPMS_ON; + else + bios_6_scratch &= ~RADEON_DFP_DPMS_ON; + } + WREG32(RADEON_BIOS_6_SCRATCH, bios_6_scratch); +} diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c new file mode 100644 index 000000000000..70ede6a52d4e --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -0,0 +1,603 @@ +/* + * Copyright 2007-8 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Dave Airlie + * Alex Deucher + */ +#include "drmP.h" +#include "drm_edid.h" +#include "drm_crtc_helper.h" +#include "radeon_drm.h" +#include "radeon.h" + +extern void +radeon_combios_connected_scratch_regs(struct drm_connector *connector, + struct drm_encoder *encoder, + bool connected); +extern void +radeon_atombios_connected_scratch_regs(struct drm_connector *connector, + struct drm_encoder *encoder, + bool connected); + +static void +radeon_connector_update_scratch_regs(struct drm_connector *connector, enum drm_connector_status status) +{ + struct drm_device *dev = connector->dev; + struct radeon_device *rdev = dev->dev_private; + struct drm_encoder *best_encoder = NULL; + struct drm_encoder *encoder = NULL; + struct drm_connector_helper_funcs *connector_funcs = connector->helper_private; + struct drm_mode_object *obj; + bool connected; + int i; + + best_encoder = connector_funcs->best_encoder(connector); + + for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { + if (connector->encoder_ids[i] == 0) + break; + + obj = drm_mode_object_find(connector->dev, + connector->encoder_ids[i], + DRM_MODE_OBJECT_ENCODER); + if (!obj) + continue; + + encoder = obj_to_encoder(obj); + + if ((encoder == best_encoder) && (status == connector_status_connected)) + connected = true; + else + connected = false; + + if (rdev->is_atom_bios) + radeon_atombios_connected_scratch_regs(connector, encoder, connected); + else + radeon_combios_connected_scratch_regs(connector, encoder, connected); + + } +} + +struct drm_encoder *radeon_best_single_encoder(struct drm_connector *connector) +{ + int enc_id = connector->encoder_ids[0]; + struct drm_mode_object *obj; + struct drm_encoder *encoder; + + /* pick the encoder ids */ + if (enc_id) { + obj = drm_mode_object_find(connector->dev, enc_id, DRM_MODE_OBJECT_ENCODER); + if (!obj) + return NULL; + encoder = obj_to_encoder(obj); + return encoder; + } + return NULL; +} + +static struct drm_display_mode *radeon_fp_native_mode(struct drm_encoder *encoder) +{ + struct drm_device *dev = encoder->dev; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct drm_display_mode *mode = NULL; + struct radeon_native_mode *native_mode = &radeon_encoder->native_mode; + + if (native_mode->panel_xres != 0 && + native_mode->panel_yres != 0 && + native_mode->dotclock != 0) { + mode = drm_mode_create(dev); + + mode->hdisplay = native_mode->panel_xres; + mode->vdisplay = native_mode->panel_yres; + + mode->htotal = mode->hdisplay + native_mode->hblank; + mode->hsync_start = mode->hdisplay + native_mode->hoverplus; + mode->hsync_end = mode->hsync_start + native_mode->hsync_width; + mode->vtotal = mode->vdisplay + native_mode->vblank; + mode->vsync_start = mode->vdisplay + native_mode->voverplus; + mode->vsync_end = mode->vsync_start + native_mode->vsync_width; + mode->clock = native_mode->dotclock; + mode->flags = 0; + + mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER; + drm_mode_set_name(mode); + + DRM_DEBUG("Adding native panel mode %s\n", mode->name); + } + return mode; +} + +int radeon_connector_set_property(struct drm_connector *connector, struct drm_property *property, + uint64_t val) +{ + return 0; +} + + +static int radeon_lvds_get_modes(struct drm_connector *connector) +{ + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + struct drm_encoder *encoder; + int ret = 0; + struct drm_display_mode *mode; + + if (radeon_connector->ddc_bus) { + ret = radeon_ddc_get_modes(radeon_connector); + if (ret > 0) { + return ret; + } + } + + encoder = radeon_best_single_encoder(connector); + if (!encoder) + return 0; + + /* we have no EDID modes */ + mode = radeon_fp_native_mode(encoder); + if (mode) { + ret = 1; + drm_mode_probed_add(connector, mode); + } + return ret; +} + +static int radeon_lvds_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + return MODE_OK; +} + +static enum drm_connector_status radeon_lvds_detect(struct drm_connector *connector) +{ + enum drm_connector_status ret = connector_status_connected; + /* check acpi lid status ??? */ + radeon_connector_update_scratch_regs(connector, ret); + return ret; +} + +static void radeon_connector_destroy(struct drm_connector *connector) +{ + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + + if (radeon_connector->ddc_bus) + radeon_i2c_destroy(radeon_connector->ddc_bus); + kfree(radeon_connector->con_priv); + drm_sysfs_connector_remove(connector); + drm_connector_cleanup(connector); + kfree(connector); +} + +struct drm_connector_helper_funcs radeon_lvds_connector_helper_funcs = { + .get_modes = radeon_lvds_get_modes, + .mode_valid = radeon_lvds_mode_valid, + .best_encoder = radeon_best_single_encoder, +}; + +struct drm_connector_funcs radeon_lvds_connector_funcs = { + .dpms = drm_helper_connector_dpms, + .detect = radeon_lvds_detect, + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = radeon_connector_destroy, + .set_property = radeon_connector_set_property, +}; + +static int radeon_vga_get_modes(struct drm_connector *connector) +{ + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + int ret; + + ret = radeon_ddc_get_modes(radeon_connector); + + return ret; +} + +static int radeon_vga_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + + return MODE_OK; +} + +static enum drm_connector_status radeon_vga_detect(struct drm_connector *connector) +{ + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + struct drm_encoder *encoder; + struct drm_encoder_helper_funcs *encoder_funcs; + bool dret; + enum drm_connector_status ret = connector_status_disconnected; + + radeon_i2c_do_lock(radeon_connector, 1); + dret = radeon_ddc_probe(radeon_connector); + radeon_i2c_do_lock(radeon_connector, 0); + if (dret) + ret = connector_status_connected; + else { + /* if EDID fails to a load detect */ + encoder = radeon_best_single_encoder(connector); + if (!encoder) + ret = connector_status_disconnected; + else { + encoder_funcs = encoder->helper_private; + ret = encoder_funcs->detect(encoder, connector); + } + } + + radeon_connector_update_scratch_regs(connector, ret); + return ret; +} + +struct drm_connector_helper_funcs radeon_vga_connector_helper_funcs = { + .get_modes = radeon_vga_get_modes, + .mode_valid = radeon_vga_mode_valid, + .best_encoder = radeon_best_single_encoder, +}; + +struct drm_connector_funcs radeon_vga_connector_funcs = { + .dpms = drm_helper_connector_dpms, + .detect = radeon_vga_detect, + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = radeon_connector_destroy, + .set_property = radeon_connector_set_property, +}; + +static int radeon_dvi_get_modes(struct drm_connector *connector) +{ + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + int ret; + + ret = radeon_ddc_get_modes(radeon_connector); + /* reset scratch regs here since radeon_dvi_detect doesn't check digital bit */ + radeon_connector_update_scratch_regs(connector, connector_status_connected); + return ret; +} + +static enum drm_connector_status radeon_dvi_detect(struct drm_connector *connector) +{ + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + struct drm_encoder *encoder; + struct drm_encoder_helper_funcs *encoder_funcs; + struct drm_mode_object *obj; + int i; + enum drm_connector_status ret = connector_status_disconnected; + bool dret; + + radeon_i2c_do_lock(radeon_connector, 1); + dret = radeon_ddc_probe(radeon_connector); + radeon_i2c_do_lock(radeon_connector, 0); + if (dret) + ret = connector_status_connected; + else { + for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { + if (connector->encoder_ids[i] == 0) + break; + + obj = drm_mode_object_find(connector->dev, + connector->encoder_ids[i], + DRM_MODE_OBJECT_ENCODER); + if (!obj) + continue; + + encoder = obj_to_encoder(obj); + + encoder_funcs = encoder->helper_private; + if (encoder_funcs->detect) { + ret = encoder_funcs->detect(encoder, connector); + if (ret == connector_status_connected) { + radeon_connector->use_digital = 0; + break; + } + } + } + } + + /* updated in get modes as well since we need to know if it's analog or digital */ + radeon_connector_update_scratch_regs(connector, ret); + return ret; +} + +/* okay need to be smart in here about which encoder to pick */ +struct drm_encoder *radeon_dvi_encoder(struct drm_connector *connector) +{ + int enc_id = connector->encoder_ids[0]; + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + struct drm_mode_object *obj; + struct drm_encoder *encoder; + int i; + for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { + if (connector->encoder_ids[i] == 0) + break; + + obj = drm_mode_object_find(connector->dev, connector->encoder_ids[i], DRM_MODE_OBJECT_ENCODER); + if (!obj) + continue; + + encoder = obj_to_encoder(obj); + + if (radeon_connector->use_digital) { + if (encoder->encoder_type == DRM_MODE_ENCODER_TMDS) + return encoder; + } else { + if (encoder->encoder_type == DRM_MODE_ENCODER_DAC || + encoder->encoder_type == DRM_MODE_ENCODER_TVDAC) + return encoder; + } + } + + /* see if we have a default encoder TODO */ + + /* then check use digitial */ + /* pick the first one */ + if (enc_id) { + obj = drm_mode_object_find(connector->dev, enc_id, DRM_MODE_OBJECT_ENCODER); + if (!obj) + return NULL; + encoder = obj_to_encoder(obj); + return encoder; + } + return NULL; +} + +struct drm_connector_helper_funcs radeon_dvi_connector_helper_funcs = { + .get_modes = radeon_dvi_get_modes, + .mode_valid = radeon_vga_mode_valid, + .best_encoder = radeon_dvi_encoder, +}; + +struct drm_connector_funcs radeon_dvi_connector_funcs = { + .dpms = drm_helper_connector_dpms, + .detect = radeon_dvi_detect, + .fill_modes = drm_helper_probe_single_connector_modes, + .set_property = radeon_connector_set_property, + .destroy = radeon_connector_destroy, +}; + +void +radeon_add_atom_connector(struct drm_device *dev, + uint32_t connector_id, + uint32_t supported_device, + int connector_type, + struct radeon_i2c_bus_rec *i2c_bus, + bool linkb, + uint32_t igp_lane_info) +{ + struct drm_connector *connector; + struct radeon_connector *radeon_connector; + struct radeon_connector_atom_dig *radeon_dig_connector; + uint32_t subpixel_order = SubPixelNone; + + /* fixme - tv/cv/din */ + if ((connector_type == DRM_MODE_CONNECTOR_Unknown) || + (connector_type == DRM_MODE_CONNECTOR_SVIDEO) || + (connector_type == DRM_MODE_CONNECTOR_Composite) || + (connector_type == DRM_MODE_CONNECTOR_9PinDIN)) + return; + + /* see if we already added it */ + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + radeon_connector = to_radeon_connector(connector); + if (radeon_connector->connector_id == connector_id) { + radeon_connector->devices |= supported_device; + return; + } + } + + radeon_connector = kzalloc(sizeof(struct radeon_connector), GFP_KERNEL); + if (!radeon_connector) + return; + + connector = &radeon_connector->base; + + radeon_connector->connector_id = connector_id; + radeon_connector->devices = supported_device; + switch (connector_type) { + case DRM_MODE_CONNECTOR_VGA: + drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type); + drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs); + if (i2c_bus->valid) { + radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "VGA"); + if (!radeon_connector->ddc_bus) + goto failed; + } + break; + case DRM_MODE_CONNECTOR_DVIA: + drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type); + drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs); + if (i2c_bus->valid) { + radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DVI"); + if (!radeon_connector->ddc_bus) + goto failed; + } + break; + case DRM_MODE_CONNECTOR_DVII: + case DRM_MODE_CONNECTOR_DVID: + radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL); + if (!radeon_dig_connector) + goto failed; + radeon_dig_connector->linkb = linkb; + radeon_dig_connector->igp_lane_info = igp_lane_info; + radeon_connector->con_priv = radeon_dig_connector; + drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type); + drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs); + if (i2c_bus->valid) { + radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DVI"); + if (!radeon_connector->ddc_bus) + goto failed; + } + subpixel_order = SubPixelHorizontalRGB; + break; + case DRM_MODE_CONNECTOR_HDMIA: + case DRM_MODE_CONNECTOR_HDMIB: + radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL); + if (!radeon_dig_connector) + goto failed; + radeon_dig_connector->linkb = linkb; + radeon_dig_connector->igp_lane_info = igp_lane_info; + radeon_connector->con_priv = radeon_dig_connector; + drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type); + drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs); + if (i2c_bus->valid) { + radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "HDMI"); + if (!radeon_connector->ddc_bus) + goto failed; + } + subpixel_order = SubPixelHorizontalRGB; + break; + case DRM_MODE_CONNECTOR_DisplayPort: + radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL); + if (!radeon_dig_connector) + goto failed; + radeon_dig_connector->linkb = linkb; + radeon_dig_connector->igp_lane_info = igp_lane_info; + radeon_connector->con_priv = radeon_dig_connector; + drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type); + drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs); + if (i2c_bus->valid) { + radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DP"); + if (!radeon_connector->ddc_bus) + goto failed; + } + subpixel_order = SubPixelHorizontalRGB; + break; + case DRM_MODE_CONNECTOR_SVIDEO: + case DRM_MODE_CONNECTOR_Composite: + case DRM_MODE_CONNECTOR_9PinDIN: + break; + case DRM_MODE_CONNECTOR_LVDS: + radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL); + if (!radeon_dig_connector) + goto failed; + radeon_dig_connector->linkb = linkb; + radeon_dig_connector->igp_lane_info = igp_lane_info; + radeon_connector->con_priv = radeon_dig_connector; + drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type); + drm_connector_helper_add(&radeon_connector->base, &radeon_lvds_connector_helper_funcs); + if (i2c_bus->valid) { + radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "LVDS"); + if (!radeon_connector->ddc_bus) + goto failed; + } + subpixel_order = SubPixelHorizontalRGB; + break; + } + + connector->display_info.subpixel_order = subpixel_order; + drm_sysfs_connector_add(connector); + return; + +failed: + if (radeon_connector->ddc_bus) + radeon_i2c_destroy(radeon_connector->ddc_bus); + drm_connector_cleanup(connector); + kfree(connector); +} + +void +radeon_add_legacy_connector(struct drm_device *dev, + uint32_t connector_id, + uint32_t supported_device, + int connector_type, + struct radeon_i2c_bus_rec *i2c_bus) +{ + struct drm_connector *connector; + struct radeon_connector *radeon_connector; + uint32_t subpixel_order = SubPixelNone; + + /* fixme - tv/cv/din */ + if ((connector_type == DRM_MODE_CONNECTOR_Unknown) || + (connector_type == DRM_MODE_CONNECTOR_SVIDEO) || + (connector_type == DRM_MODE_CONNECTOR_Composite) || + (connector_type == DRM_MODE_CONNECTOR_9PinDIN)) + return; + + /* see if we already added it */ + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + radeon_connector = to_radeon_connector(connector); + if (radeon_connector->connector_id == connector_id) { + radeon_connector->devices |= supported_device; + return; + } + } + + radeon_connector = kzalloc(sizeof(struct radeon_connector), GFP_KERNEL); + if (!radeon_connector) + return; + + connector = &radeon_connector->base; + + radeon_connector->connector_id = connector_id; + radeon_connector->devices = supported_device; + switch (connector_type) { + case DRM_MODE_CONNECTOR_VGA: + drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type); + drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs); + if (i2c_bus->valid) { + radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "VGA"); + if (!radeon_connector->ddc_bus) + goto failed; + } + break; + case DRM_MODE_CONNECTOR_DVIA: + drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type); + drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs); + if (i2c_bus->valid) { + radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DVI"); + if (!radeon_connector->ddc_bus) + goto failed; + } + break; + case DRM_MODE_CONNECTOR_DVII: + case DRM_MODE_CONNECTOR_DVID: + drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type); + drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs); + if (i2c_bus->valid) { + radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DVI"); + if (!radeon_connector->ddc_bus) + goto failed; + } + subpixel_order = SubPixelHorizontalRGB; + break; + case DRM_MODE_CONNECTOR_SVIDEO: + case DRM_MODE_CONNECTOR_Composite: + case DRM_MODE_CONNECTOR_9PinDIN: + break; + case DRM_MODE_CONNECTOR_LVDS: + drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type); + drm_connector_helper_add(&radeon_connector->base, &radeon_lvds_connector_helper_funcs); + if (i2c_bus->valid) { + radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "LVDS"); + if (!radeon_connector->ddc_bus) + goto failed; + } + subpixel_order = SubPixelHorizontalRGB; + break; + } + + connector->display_info.subpixel_order = subpixel_order; + drm_sysfs_connector_add(connector); + return; + +failed: + if (radeon_connector->ddc_bus) + radeon_i2c_destroy(radeon_connector->ddc_bus); + drm_connector_cleanup(connector); + kfree(connector); +} diff --git a/drivers/gpu/drm/radeon/radeon_cp.c b/drivers/gpu/drm/radeon/radeon_cp.c index aff90bb96488..d8356827ef17 100644 --- a/drivers/gpu/drm/radeon/radeon_cp.c +++ b/drivers/gpu/drm/radeon/radeon_cp.c @@ -2045,11 +2045,10 @@ int radeon_driver_load(struct drm_device *dev, unsigned long flags) drm_radeon_private_t *dev_priv; int ret = 0; - dev_priv = drm_alloc(sizeof(drm_radeon_private_t), DRM_MEM_DRIVER); + dev_priv = kzalloc(sizeof(drm_radeon_private_t), GFP_KERNEL); if (dev_priv == NULL) return -ENOMEM; - memset(dev_priv, 0, sizeof(drm_radeon_private_t)); dev->dev_private = (void *)dev_priv; dev_priv->flags = flags; @@ -2103,13 +2102,13 @@ int radeon_master_create(struct drm_device *dev, struct drm_master *master) unsigned long sareapage; int ret; - master_priv = drm_calloc(1, sizeof(*master_priv), DRM_MEM_DRIVER); + master_priv = kzalloc(sizeof(*master_priv), GFP_KERNEL); if (!master_priv) return -ENOMEM; /* prebuild the SAREA */ sareapage = max_t(unsigned long, SAREA_MAX, PAGE_SIZE); - ret = drm_addmap(dev, 0, sareapage, _DRM_SHM, _DRM_CONTAINS_LOCK|_DRM_DRIVER, + ret = drm_addmap(dev, 0, sareapage, _DRM_SHM, _DRM_CONTAINS_LOCK, &master_priv->sarea); if (ret) { DRM_ERROR("SAREA setup failed\n"); @@ -2137,7 +2136,7 @@ void radeon_master_destroy(struct drm_device *dev, struct drm_master *master) if (master_priv->sarea) drm_rmmap_locked(dev, master_priv->sarea); - drm_free(master_priv, sizeof(*master_priv), DRM_MEM_DRIVER); + kfree(master_priv); master->driver_priv = NULL; } @@ -2171,7 +2170,7 @@ int radeon_driver_unload(struct drm_device *dev) drm_rmmap(dev, dev_priv->mmio); - drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER); + kfree(dev_priv); dev->dev_private = NULL; return 0; diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c new file mode 100644 index 000000000000..b843f9bdfb14 --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_cs.c @@ -0,0 +1,249 @@ +/* + * Copyright 2008 Jerome Glisse. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Jerome Glisse + */ +#include "drmP.h" +#include "radeon_drm.h" +#include "radeon_reg.h" +#include "radeon.h" + +void r100_cs_dump_packet(struct radeon_cs_parser *p, + struct radeon_cs_packet *pkt); + +int radeon_cs_parser_relocs(struct radeon_cs_parser *p) +{ + struct drm_device *ddev = p->rdev->ddev; + struct radeon_cs_chunk *chunk; + unsigned i, j; + bool duplicate; + + if (p->chunk_relocs_idx == -1) { + return 0; + } + chunk = &p->chunks[p->chunk_relocs_idx]; + /* FIXME: we assume that each relocs use 4 dwords */ + p->nrelocs = chunk->length_dw / 4; + p->relocs_ptr = kcalloc(p->nrelocs, sizeof(void *), GFP_KERNEL); + if (p->relocs_ptr == NULL) { + return -ENOMEM; + } + p->relocs = kcalloc(p->nrelocs, sizeof(struct radeon_cs_reloc), GFP_KERNEL); + if (p->relocs == NULL) { + return -ENOMEM; + } + for (i = 0; i < p->nrelocs; i++) { + struct drm_radeon_cs_reloc *r; + + duplicate = false; + r = (struct drm_radeon_cs_reloc *)&chunk->kdata[i*4]; + for (j = 0; j < p->nrelocs; j++) { + if (r->handle == p->relocs[j].handle) { + p->relocs_ptr[i] = &p->relocs[j]; + duplicate = true; + break; + } + } + if (!duplicate) { + p->relocs[i].gobj = drm_gem_object_lookup(ddev, + p->filp, + r->handle); + if (p->relocs[i].gobj == NULL) { + DRM_ERROR("gem object lookup failed 0x%x\n", + r->handle); + return -EINVAL; + } + p->relocs_ptr[i] = &p->relocs[i]; + p->relocs[i].robj = p->relocs[i].gobj->driver_private; + p->relocs[i].lobj.robj = p->relocs[i].robj; + p->relocs[i].lobj.rdomain = r->read_domains; + p->relocs[i].lobj.wdomain = r->write_domain; + p->relocs[i].handle = r->handle; + p->relocs[i].flags = r->flags; + INIT_LIST_HEAD(&p->relocs[i].lobj.list); + radeon_object_list_add_object(&p->relocs[i].lobj, + &p->validated); + } + } + return radeon_object_list_validate(&p->validated, p->ib->fence); +} + +int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data) +{ + struct drm_radeon_cs *cs = data; + uint64_t *chunk_array_ptr; + unsigned size, i; + + if (!cs->num_chunks) { + return 0; + } + /* get chunks */ + INIT_LIST_HEAD(&p->validated); + p->idx = 0; + p->chunk_ib_idx = -1; + p->chunk_relocs_idx = -1; + p->chunks_array = kcalloc(cs->num_chunks, sizeof(uint64_t), GFP_KERNEL); + if (p->chunks_array == NULL) { + return -ENOMEM; + } + chunk_array_ptr = (uint64_t *)(unsigned long)(cs->chunks); + if (DRM_COPY_FROM_USER(p->chunks_array, chunk_array_ptr, + sizeof(uint64_t)*cs->num_chunks)) { + return -EFAULT; + } + p->nchunks = cs->num_chunks; + p->chunks = kcalloc(p->nchunks, sizeof(struct radeon_cs_chunk), GFP_KERNEL); + if (p->chunks == NULL) { + return -ENOMEM; + } + for (i = 0; i < p->nchunks; i++) { + struct drm_radeon_cs_chunk __user **chunk_ptr = NULL; + struct drm_radeon_cs_chunk user_chunk; + uint32_t __user *cdata; + + chunk_ptr = (void __user*)(unsigned long)p->chunks_array[i]; + if (DRM_COPY_FROM_USER(&user_chunk, chunk_ptr, + sizeof(struct drm_radeon_cs_chunk))) { + return -EFAULT; + } + p->chunks[i].chunk_id = user_chunk.chunk_id; + if (p->chunks[i].chunk_id == RADEON_CHUNK_ID_RELOCS) { + p->chunk_relocs_idx = i; + } + if (p->chunks[i].chunk_id == RADEON_CHUNK_ID_IB) { + p->chunk_ib_idx = i; + } + p->chunks[i].length_dw = user_chunk.length_dw; + cdata = (uint32_t *)(unsigned long)user_chunk.chunk_data; + + p->chunks[i].kdata = NULL; + size = p->chunks[i].length_dw * sizeof(uint32_t); + p->chunks[i].kdata = kzalloc(size, GFP_KERNEL); + if (p->chunks[i].kdata == NULL) { + return -ENOMEM; + } + if (DRM_COPY_FROM_USER(p->chunks[i].kdata, cdata, size)) { + return -EFAULT; + } + } + if (p->chunks[p->chunk_ib_idx].length_dw > (16 * 1024)) { + DRM_ERROR("cs IB too big: %d\n", + p->chunks[p->chunk_ib_idx].length_dw); + return -EINVAL; + } + return 0; +} + +/** + * cs_parser_fini() - clean parser states + * @parser: parser structure holding parsing context. + * @error: error number + * + * If error is set than unvalidate buffer, otherwise just free memory + * used by parsing context. + **/ +static void radeon_cs_parser_fini(struct radeon_cs_parser *parser, int error) +{ + unsigned i; + + if (error) { + radeon_object_list_unvalidate(&parser->validated); + } else { + radeon_object_list_clean(&parser->validated); + } + for (i = 0; i < parser->nrelocs; i++) { + if (parser->relocs[i].gobj) { + mutex_lock(&parser->rdev->ddev->struct_mutex); + drm_gem_object_unreference(parser->relocs[i].gobj); + mutex_unlock(&parser->rdev->ddev->struct_mutex); + } + } + kfree(parser->relocs); + kfree(parser->relocs_ptr); + for (i = 0; i < parser->nchunks; i++) { + kfree(parser->chunks[i].kdata); + } + kfree(parser->chunks); + kfree(parser->chunks_array); + radeon_ib_free(parser->rdev, &parser->ib); +} + +int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) +{ + struct radeon_device *rdev = dev->dev_private; + struct radeon_cs_parser parser; + struct radeon_cs_chunk *ib_chunk; + int r; + + mutex_lock(&rdev->cs_mutex); + if (rdev->gpu_lockup) { + mutex_unlock(&rdev->cs_mutex); + return -EINVAL; + } + /* initialize parser */ + memset(&parser, 0, sizeof(struct radeon_cs_parser)); + parser.filp = filp; + parser.rdev = rdev; + r = radeon_cs_parser_init(&parser, data); + if (r) { + DRM_ERROR("Failed to initialize parser !\n"); + radeon_cs_parser_fini(&parser, r); + mutex_unlock(&rdev->cs_mutex); + return r; + } + r = radeon_ib_get(rdev, &parser.ib); + if (r) { + DRM_ERROR("Failed to get ib !\n"); + radeon_cs_parser_fini(&parser, r); + mutex_unlock(&rdev->cs_mutex); + return r; + } + r = radeon_cs_parser_relocs(&parser); + if (r) { + DRM_ERROR("Failed to parse relocation !\n"); + radeon_cs_parser_fini(&parser, r); + mutex_unlock(&rdev->cs_mutex); + return r; + } + /* Copy the packet into the IB, the parser will read from the + * input memory (cached) and write to the IB (which can be + * uncached). */ + ib_chunk = &parser.chunks[parser.chunk_ib_idx]; + parser.ib->length_dw = ib_chunk->length_dw; + memcpy((void *)parser.ib->ptr, ib_chunk->kdata, ib_chunk->length_dw*4); + r = radeon_cs_parse(&parser); + if (r) { + DRM_ERROR("Invalid command stream !\n"); + radeon_cs_parser_fini(&parser, r); + mutex_unlock(&rdev->cs_mutex); + return r; + } + r = radeon_ib_schedule(rdev, parser.ib); + if (r) { + DRM_ERROR("Faild to schedule IB !\n"); + } + radeon_cs_parser_fini(&parser, r); + mutex_unlock(&rdev->cs_mutex); + return r; +} diff --git a/drivers/gpu/drm/radeon/radeon_cursor.c b/drivers/gpu/drm/radeon/radeon_cursor.c new file mode 100644 index 000000000000..5232441f119b --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_cursor.c @@ -0,0 +1,252 @@ +/* + * Copyright 2007-8 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Dave Airlie + * Alex Deucher + */ +#include "drmP.h" +#include "radeon_drm.h" +#include "radeon.h" + +#define CURSOR_WIDTH 64 +#define CURSOR_HEIGHT 64 + +static void radeon_lock_cursor(struct drm_crtc *crtc, bool lock) +{ + struct radeon_device *rdev = crtc->dev->dev_private; + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + uint32_t cur_lock; + + if (ASIC_IS_AVIVO(rdev)) { + cur_lock = RREG32(AVIVO_D1CUR_UPDATE + radeon_crtc->crtc_offset); + if (lock) + cur_lock |= AVIVO_D1CURSOR_UPDATE_LOCK; + else + cur_lock &= ~AVIVO_D1CURSOR_UPDATE_LOCK; + WREG32(AVIVO_D1CUR_UPDATE + radeon_crtc->crtc_offset, cur_lock); + } else { + cur_lock = RREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset); + if (lock) + cur_lock |= RADEON_CUR_LOCK; + else + cur_lock &= ~RADEON_CUR_LOCK; + WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, cur_lock); + } +} + +static void radeon_hide_cursor(struct drm_crtc *crtc) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct radeon_device *rdev = crtc->dev->dev_private; + + if (ASIC_IS_AVIVO(rdev)) { + WREG32(RADEON_MM_INDEX, AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset); + WREG32(RADEON_MM_DATA, (AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT)); + } else { + switch (radeon_crtc->crtc_id) { + case 0: + WREG32(RADEON_MM_INDEX, RADEON_CRTC_GEN_CNTL); + break; + case 1: + WREG32(RADEON_MM_INDEX, RADEON_CRTC2_GEN_CNTL); + break; + default: + return; + } + WREG32_P(RADEON_MM_DATA, 0, ~RADEON_CRTC_CUR_EN); + } +} + +static void radeon_show_cursor(struct drm_crtc *crtc) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct radeon_device *rdev = crtc->dev->dev_private; + + if (ASIC_IS_AVIVO(rdev)) { + WREG32(RADEON_MM_INDEX, AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset); + WREG32(RADEON_MM_DATA, AVIVO_D1CURSOR_EN | + (AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT)); + } else { + switch (radeon_crtc->crtc_id) { + case 0: + WREG32(RADEON_MM_INDEX, RADEON_CRTC_GEN_CNTL); + break; + case 1: + WREG32(RADEON_MM_INDEX, RADEON_CRTC2_GEN_CNTL); + break; + default: + return; + } + + WREG32_P(RADEON_MM_DATA, (RADEON_CRTC_CUR_EN | + (RADEON_CRTC_CUR_MODE_24BPP << RADEON_CRTC_CUR_MODE_SHIFT)), + ~(RADEON_CRTC_CUR_EN | RADEON_CRTC_CUR_MODE_MASK)); + } +} + +static void radeon_set_cursor(struct drm_crtc *crtc, struct drm_gem_object *obj, + uint32_t gpu_addr) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct radeon_device *rdev = crtc->dev->dev_private; + + if (ASIC_IS_AVIVO(rdev)) + WREG32(AVIVO_D1CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset, gpu_addr); + else + /* offset is from DISP(2)_BASE_ADDRESS */ + WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, gpu_addr); +} + +int radeon_crtc_cursor_set(struct drm_crtc *crtc, + struct drm_file *file_priv, + uint32_t handle, + uint32_t width, + uint32_t height) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_gem_object *obj; + uint64_t gpu_addr; + int ret; + + if (!handle) { + /* turn off cursor */ + radeon_hide_cursor(crtc); + obj = NULL; + goto unpin; + } + + if ((width > CURSOR_WIDTH) || (height > CURSOR_HEIGHT)) { + DRM_ERROR("bad cursor width or height %d x %d\n", width, height); + return -EINVAL; + } + + radeon_crtc->cursor_width = width; + radeon_crtc->cursor_height = height; + + obj = drm_gem_object_lookup(crtc->dev, file_priv, handle); + if (!obj) { + DRM_ERROR("Cannot find cursor object %x for crtc %d\n", handle, radeon_crtc->crtc_id); + return -EINVAL; + } + + ret = radeon_gem_object_pin(obj, RADEON_GEM_DOMAIN_VRAM, &gpu_addr); + if (ret) + goto fail; + + radeon_lock_cursor(crtc, true); + /* XXX only 27 bit offset for legacy cursor */ + radeon_set_cursor(crtc, obj, gpu_addr); + radeon_show_cursor(crtc); + radeon_lock_cursor(crtc, false); + +unpin: + if (radeon_crtc->cursor_bo) { + radeon_gem_object_unpin(radeon_crtc->cursor_bo); + mutex_lock(&crtc->dev->struct_mutex); + drm_gem_object_unreference(radeon_crtc->cursor_bo); + mutex_unlock(&crtc->dev->struct_mutex); + } + + radeon_crtc->cursor_bo = obj; + return 0; +fail: + mutex_lock(&crtc->dev->struct_mutex); + drm_gem_object_unreference(obj); + mutex_unlock(&crtc->dev->struct_mutex); + + return 0; +} + +int radeon_crtc_cursor_move(struct drm_crtc *crtc, + int x, int y) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct radeon_device *rdev = crtc->dev->dev_private; + int xorigin = 0, yorigin = 0; + + if (x < 0) + xorigin = -x + 1; + if (y < 0) + yorigin = -y + 1; + if (xorigin >= CURSOR_WIDTH) + xorigin = CURSOR_WIDTH - 1; + if (yorigin >= CURSOR_HEIGHT) + yorigin = CURSOR_HEIGHT - 1; + + radeon_lock_cursor(crtc, true); + if (ASIC_IS_AVIVO(rdev)) { + int w = radeon_crtc->cursor_width; + int i = 0; + struct drm_crtc *crtc_p; + + /* avivo cursor are offset into the total surface */ + x += crtc->x; + y += crtc->y; + DRM_DEBUG("x %d y %d c->x %d c->y %d\n", x, y, crtc->x, crtc->y); + + /* avivo cursor image can't end on 128 pixel boundry or + * go past the end of the frame if both crtcs are enabled + */ + list_for_each_entry(crtc_p, &crtc->dev->mode_config.crtc_list, head) { + if (crtc_p->enabled) + i++; + } + if (i > 1) { + int cursor_end, frame_end; + + cursor_end = x - xorigin + w; + frame_end = crtc->x + crtc->mode.crtc_hdisplay; + if (cursor_end >= frame_end) { + w = w - (cursor_end - frame_end); + if (!(frame_end & 0x7f)) + w--; + } else { + if (!(cursor_end & 0x7f)) + w--; + } + if (w <= 0) + w = 1; + } + + WREG32(AVIVO_D1CUR_POSITION + radeon_crtc->crtc_offset, + ((xorigin ? 0 : x) << 16) | + (yorigin ? 0 : y)); + WREG32(AVIVO_D1CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin); + WREG32(AVIVO_D1CUR_SIZE + radeon_crtc->crtc_offset, + ((w - 1) << 16) | (radeon_crtc->cursor_height - 1)); + } else { + if (crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN) + y *= 2; + + WREG32(RADEON_CUR_HORZ_VERT_OFF + radeon_crtc->crtc_offset, + (RADEON_CUR_LOCK + | (xorigin << 16) + | yorigin)); + WREG32(RADEON_CUR_HORZ_VERT_POSN + radeon_crtc->crtc_offset, + (RADEON_CUR_LOCK + | ((xorigin ? 0 : x) << 16) + | (yorigin ? 0 : y))); + } + radeon_lock_cursor(crtc, false); + + return 0; +} diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c new file mode 100644 index 000000000000..f30aa7274a54 --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -0,0 +1,817 @@ +/* + * Copyright 2008 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * Copyright 2009 Jerome Glisse. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Dave Airlie + * Alex Deucher + * Jerome Glisse + */ +#include +#include +#include +#include +#include "radeon_reg.h" +#include "radeon.h" +#include "radeon_asic.h" +#include "atom.h" + +/* + * GPU scratch registers helpers function. + */ +static void radeon_scratch_init(struct radeon_device *rdev) +{ + int i; + + /* FIXME: check this out */ + if (rdev->family < CHIP_R300) { + rdev->scratch.num_reg = 5; + } else { + rdev->scratch.num_reg = 7; + } + for (i = 0; i < rdev->scratch.num_reg; i++) { + rdev->scratch.free[i] = true; + rdev->scratch.reg[i] = RADEON_SCRATCH_REG0 + (i * 4); + } +} + +int radeon_scratch_get(struct radeon_device *rdev, uint32_t *reg) +{ + int i; + + for (i = 0; i < rdev->scratch.num_reg; i++) { + if (rdev->scratch.free[i]) { + rdev->scratch.free[i] = false; + *reg = rdev->scratch.reg[i]; + return 0; + } + } + return -EINVAL; +} + +void radeon_scratch_free(struct radeon_device *rdev, uint32_t reg) +{ + int i; + + for (i = 0; i < rdev->scratch.num_reg; i++) { + if (rdev->scratch.reg[i] == reg) { + rdev->scratch.free[i] = true; + return; + } + } +} + +/* + * MC common functions + */ +int radeon_mc_setup(struct radeon_device *rdev) +{ + uint32_t tmp; + + /* Some chips have an "issue" with the memory controller, the + * location must be aligned to the size. We just align it down, + * too bad if we walk over the top of system memory, we don't + * use DMA without a remapped anyway. + * Affected chips are rv280, all r3xx, and all r4xx, but not IGP + */ + /* FGLRX seems to setup like this, VRAM a 0, then GART. + */ + /* + * Note: from R6xx the address space is 40bits but here we only + * use 32bits (still have to see a card which would exhaust 4G + * address space). + */ + if (rdev->mc.vram_location != 0xFFFFFFFFUL) { + /* vram location was already setup try to put gtt after + * if it fits */ + tmp = rdev->mc.vram_location + rdev->mc.vram_size; + tmp = (tmp + rdev->mc.gtt_size - 1) & ~(rdev->mc.gtt_size - 1); + if ((0xFFFFFFFFUL - tmp) >= rdev->mc.gtt_size) { + rdev->mc.gtt_location = tmp; + } else { + if (rdev->mc.gtt_size >= rdev->mc.vram_location) { + printk(KERN_ERR "[drm] GTT too big to fit " + "before or after vram location.\n"); + return -EINVAL; + } + rdev->mc.gtt_location = 0; + } + } else if (rdev->mc.gtt_location != 0xFFFFFFFFUL) { + /* gtt location was already setup try to put vram before + * if it fits */ + if (rdev->mc.vram_size < rdev->mc.gtt_location) { + rdev->mc.vram_location = 0; + } else { + tmp = rdev->mc.gtt_location + rdev->mc.gtt_size; + tmp += (rdev->mc.vram_size - 1); + tmp &= ~(rdev->mc.vram_size - 1); + if ((0xFFFFFFFFUL - tmp) >= rdev->mc.vram_size) { + rdev->mc.vram_location = tmp; + } else { + printk(KERN_ERR "[drm] vram too big to fit " + "before or after GTT location.\n"); + return -EINVAL; + } + } + } else { + rdev->mc.vram_location = 0; + rdev->mc.gtt_location = rdev->mc.vram_size; + } + DRM_INFO("radeon: VRAM %uM\n", rdev->mc.vram_size >> 20); + DRM_INFO("radeon: VRAM from 0x%08X to 0x%08X\n", + rdev->mc.vram_location, + rdev->mc.vram_location + rdev->mc.vram_size - 1); + DRM_INFO("radeon: GTT %uM\n", rdev->mc.gtt_size >> 20); + DRM_INFO("radeon: GTT from 0x%08X to 0x%08X\n", + rdev->mc.gtt_location, + rdev->mc.gtt_location + rdev->mc.gtt_size - 1); + return 0; +} + + +/* + * GPU helpers function. + */ +static bool radeon_card_posted(struct radeon_device *rdev) +{ + uint32_t reg; + + /* first check CRTCs */ + if (ASIC_IS_AVIVO(rdev)) { + reg = RREG32(AVIVO_D1CRTC_CONTROL) | + RREG32(AVIVO_D2CRTC_CONTROL); + if (reg & AVIVO_CRTC_EN) { + return true; + } + } else { + reg = RREG32(RADEON_CRTC_GEN_CNTL) | + RREG32(RADEON_CRTC2_GEN_CNTL); + if (reg & RADEON_CRTC_EN) { + return true; + } + } + + /* then check MEM_SIZE, in case the crtcs are off */ + if (rdev->family >= CHIP_R600) + reg = RREG32(R600_CONFIG_MEMSIZE); + else + reg = RREG32(RADEON_CONFIG_MEMSIZE); + + if (reg) + return true; + + return false; + +} + + +/* + * Registers accessors functions. + */ +uint32_t radeon_invalid_rreg(struct radeon_device *rdev, uint32_t reg) +{ + DRM_ERROR("Invalid callback to read register 0x%04X\n", reg); + BUG_ON(1); + return 0; +} + +void radeon_invalid_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v) +{ + DRM_ERROR("Invalid callback to write register 0x%04X with 0x%08X\n", + reg, v); + BUG_ON(1); +} + +void radeon_register_accessor_init(struct radeon_device *rdev) +{ + rdev->mm_rreg = &r100_mm_rreg; + rdev->mm_wreg = &r100_mm_wreg; + rdev->mc_rreg = &radeon_invalid_rreg; + rdev->mc_wreg = &radeon_invalid_wreg; + rdev->pll_rreg = &radeon_invalid_rreg; + rdev->pll_wreg = &radeon_invalid_wreg; + rdev->pcie_rreg = &radeon_invalid_rreg; + rdev->pcie_wreg = &radeon_invalid_wreg; + rdev->pciep_rreg = &radeon_invalid_rreg; + rdev->pciep_wreg = &radeon_invalid_wreg; + + /* Don't change order as we are overridding accessor. */ + if (rdev->family < CHIP_RV515) { + rdev->pcie_rreg = &rv370_pcie_rreg; + rdev->pcie_wreg = &rv370_pcie_wreg; + } + if (rdev->family >= CHIP_RV515) { + rdev->pcie_rreg = &rv515_pcie_rreg; + rdev->pcie_wreg = &rv515_pcie_wreg; + } + /* FIXME: not sure here */ + if (rdev->family <= CHIP_R580) { + rdev->pll_rreg = &r100_pll_rreg; + rdev->pll_wreg = &r100_pll_wreg; + } + if (rdev->family >= CHIP_RV515) { + rdev->mc_rreg = &rv515_mc_rreg; + rdev->mc_wreg = &rv515_mc_wreg; + } + if (rdev->family == CHIP_RS400 || rdev->family == CHIP_RS480) { + rdev->mc_rreg = &rs400_mc_rreg; + rdev->mc_wreg = &rs400_mc_wreg; + } + if (rdev->family == CHIP_RS690 || rdev->family == CHIP_RS740) { + rdev->mc_rreg = &rs690_mc_rreg; + rdev->mc_wreg = &rs690_mc_wreg; + } + if (rdev->family == CHIP_RS600) { + rdev->mc_rreg = &rs600_mc_rreg; + rdev->mc_wreg = &rs600_mc_wreg; + } + if (rdev->family >= CHIP_R600) { + rdev->pciep_rreg = &r600_pciep_rreg; + rdev->pciep_wreg = &r600_pciep_wreg; + } +} + + +/* + * ASIC + */ +int radeon_asic_init(struct radeon_device *rdev) +{ + radeon_register_accessor_init(rdev); + switch (rdev->family) { + case CHIP_R100: + case CHIP_RV100: + case CHIP_RS100: + case CHIP_RV200: + case CHIP_RS200: + case CHIP_R200: + case CHIP_RV250: + case CHIP_RS300: + case CHIP_RV280: + rdev->asic = &r100_asic; + break; + case CHIP_R300: + case CHIP_R350: + case CHIP_RV350: + case CHIP_RV380: + rdev->asic = &r300_asic; + break; + case CHIP_R420: + case CHIP_R423: + case CHIP_RV410: + rdev->asic = &r420_asic; + break; + case CHIP_RS400: + case CHIP_RS480: + rdev->asic = &rs400_asic; + break; + case CHIP_RS600: + rdev->asic = &rs600_asic; + break; + case CHIP_RS690: + case CHIP_RS740: + rdev->asic = &rs690_asic; + break; + case CHIP_RV515: + rdev->asic = &rv515_asic; + break; + case CHIP_R520: + case CHIP_RV530: + case CHIP_RV560: + case CHIP_RV570: + case CHIP_R580: + rdev->asic = &r520_asic; + break; + case CHIP_R600: + case CHIP_RV610: + case CHIP_RV630: + case CHIP_RV620: + case CHIP_RV635: + case CHIP_RV670: + case CHIP_RS780: + case CHIP_RV770: + case CHIP_RV730: + case CHIP_RV710: + default: + /* FIXME: not supported yet */ + return -EINVAL; + } + return 0; +} + + +/* + * Wrapper around modesetting bits. + */ +int radeon_clocks_init(struct radeon_device *rdev) +{ + int r; + + radeon_get_clock_info(rdev->ddev); + r = radeon_static_clocks_init(rdev->ddev); + if (r) { + return r; + } + DRM_INFO("Clocks initialized !\n"); + return 0; +} + +void radeon_clocks_fini(struct radeon_device *rdev) +{ +} + +/* ATOM accessor methods */ +static uint32_t cail_pll_read(struct card_info *info, uint32_t reg) +{ + struct radeon_device *rdev = info->dev->dev_private; + uint32_t r; + + r = rdev->pll_rreg(rdev, reg); + return r; +} + +static void cail_pll_write(struct card_info *info, uint32_t reg, uint32_t val) +{ + struct radeon_device *rdev = info->dev->dev_private; + + rdev->pll_wreg(rdev, reg, val); +} + +static uint32_t cail_mc_read(struct card_info *info, uint32_t reg) +{ + struct radeon_device *rdev = info->dev->dev_private; + uint32_t r; + + r = rdev->mc_rreg(rdev, reg); + return r; +} + +static void cail_mc_write(struct card_info *info, uint32_t reg, uint32_t val) +{ + struct radeon_device *rdev = info->dev->dev_private; + + rdev->mc_wreg(rdev, reg, val); +} + +static void cail_reg_write(struct card_info *info, uint32_t reg, uint32_t val) +{ + struct radeon_device *rdev = info->dev->dev_private; + + WREG32(reg*4, val); +} + +static uint32_t cail_reg_read(struct card_info *info, uint32_t reg) +{ + struct radeon_device *rdev = info->dev->dev_private; + uint32_t r; + + r = RREG32(reg*4); + return r; +} + +static struct card_info atom_card_info = { + .dev = NULL, + .reg_read = cail_reg_read, + .reg_write = cail_reg_write, + .mc_read = cail_mc_read, + .mc_write = cail_mc_write, + .pll_read = cail_pll_read, + .pll_write = cail_pll_write, +}; + +int radeon_atombios_init(struct radeon_device *rdev) +{ + atom_card_info.dev = rdev->ddev; + rdev->mode_info.atom_context = atom_parse(&atom_card_info, rdev->bios); + radeon_atom_initialize_bios_scratch_regs(rdev->ddev); + return 0; +} + +void radeon_atombios_fini(struct radeon_device *rdev) +{ + kfree(rdev->mode_info.atom_context); +} + +int radeon_combios_init(struct radeon_device *rdev) +{ + radeon_combios_initialize_bios_scratch_regs(rdev->ddev); + return 0; +} + +void radeon_combios_fini(struct radeon_device *rdev) +{ +} + +int radeon_modeset_init(struct radeon_device *rdev); +void radeon_modeset_fini(struct radeon_device *rdev); + + +/* + * Radeon device. + */ +int radeon_device_init(struct radeon_device *rdev, + struct drm_device *ddev, + struct pci_dev *pdev, + uint32_t flags) +{ + int r, ret; + + DRM_INFO("radeon: Initializing kernel modesetting.\n"); + rdev->shutdown = false; + rdev->ddev = ddev; + rdev->pdev = pdev; + rdev->flags = flags; + rdev->family = flags & RADEON_FAMILY_MASK; + rdev->is_atom_bios = false; + rdev->usec_timeout = RADEON_MAX_USEC_TIMEOUT; + rdev->mc.gtt_size = radeon_gart_size * 1024 * 1024; + rdev->gpu_lockup = false; + /* mutex initialization are all done here so we + * can recall function without having locking issues */ + mutex_init(&rdev->cs_mutex); + mutex_init(&rdev->ib_pool.mutex); + mutex_init(&rdev->cp.mutex); + rwlock_init(&rdev->fence_drv.lock); + + if (radeon_agpmode == -1) { + rdev->flags &= ~RADEON_IS_AGP; + if (rdev->family > CHIP_RV515 || + rdev->family == CHIP_RV380 || + rdev->family == CHIP_RV410 || + rdev->family == CHIP_R423) { + DRM_INFO("Forcing AGP to PCIE mode\n"); + rdev->flags |= RADEON_IS_PCIE; + } else { + DRM_INFO("Forcing AGP to PCI mode\n"); + rdev->flags |= RADEON_IS_PCI; + } + } + + /* Set asic functions */ + r = radeon_asic_init(rdev); + if (r) { + return r; + } + r = radeon_init(rdev); + if (r) { + return r; + } + + /* Report DMA addressing limitation */ + r = pci_set_dma_mask(rdev->pdev, DMA_BIT_MASK(32)); + if (r) { + printk(KERN_WARNING "radeon: No suitable DMA available.\n"); + } + + /* Registers mapping */ + /* TODO: block userspace mapping of io register */ + rdev->rmmio_base = drm_get_resource_start(rdev->ddev, 2); + rdev->rmmio_size = drm_get_resource_len(rdev->ddev, 2); + rdev->rmmio = ioremap(rdev->rmmio_base, rdev->rmmio_size); + if (rdev->rmmio == NULL) { + return -ENOMEM; + } + DRM_INFO("register mmio base: 0x%08X\n", (uint32_t)rdev->rmmio_base); + DRM_INFO("register mmio size: %u\n", (unsigned)rdev->rmmio_size); + + /* Setup errata flags */ + radeon_errata(rdev); + /* Initialize scratch registers */ + radeon_scratch_init(rdev); + + /* TODO: disable VGA need to use VGA request */ + /* BIOS*/ + if (!radeon_get_bios(rdev)) { + if (ASIC_IS_AVIVO(rdev)) + return -EINVAL; + } + if (rdev->is_atom_bios) { + r = radeon_atombios_init(rdev); + if (r) { + return r; + } + } else { + r = radeon_combios_init(rdev); + if (r) { + return r; + } + } + /* Reset gpu before posting otherwise ATOM will enter infinite loop */ + if (radeon_gpu_reset(rdev)) { + /* FIXME: what do we want to do here ? */ + } + /* check if cards are posted or not */ + if (!radeon_card_posted(rdev) && rdev->bios) { + DRM_INFO("GPU not posted. posting now...\n"); + if (rdev->is_atom_bios) { + atom_asic_init(rdev->mode_info.atom_context); + } else { + radeon_combios_asic_init(rdev->ddev); + } + } + /* Get vram informations */ + radeon_vram_info(rdev); + /* Device is severly broken if aper size > vram size. + * for RN50/M6/M7 - Novell bug 204882 ? + */ + if (rdev->mc.vram_size < rdev->mc.aper_size) { + rdev->mc.aper_size = rdev->mc.vram_size; + } + /* Add an MTRR for the VRAM */ + rdev->mc.vram_mtrr = mtrr_add(rdev->mc.aper_base, rdev->mc.aper_size, + MTRR_TYPE_WRCOMB, 1); + DRM_INFO("Detected VRAM RAM=%uM, BAR=%uM\n", + rdev->mc.vram_size >> 20, + (unsigned)rdev->mc.aper_size >> 20); + DRM_INFO("RAM width %dbits %cDR\n", + rdev->mc.vram_width, rdev->mc.vram_is_ddr ? 'D' : 'S'); + /* Initialize clocks */ + r = radeon_clocks_init(rdev); + if (r) { + return r; + } + /* Initialize memory controller (also test AGP) */ + r = radeon_mc_init(rdev); + if (r) { + return r; + } + /* Fence driver */ + r = radeon_fence_driver_init(rdev); + if (r) { + return r; + } + r = radeon_irq_kms_init(rdev); + if (r) { + return r; + } + /* Memory manager */ + r = radeon_object_init(rdev); + if (r) { + return r; + } + /* Initialize GART (initialize after TTM so we can allocate + * memory through TTM but finalize after TTM) */ + r = radeon_gart_enable(rdev); + if (!r) { + r = radeon_gem_init(rdev); + } + + /* 1M ring buffer */ + if (!r) { + r = radeon_cp_init(rdev, 1024 * 1024); + } + if (!r) { + r = radeon_wb_init(rdev); + if (r) { + DRM_ERROR("radeon: failled initializing WB (%d).\n", r); + return r; + } + } + if (!r) { + r = radeon_ib_pool_init(rdev); + if (r) { + DRM_ERROR("radeon: failled initializing IB pool (%d).\n", r); + return r; + } + } + if (!r) { + r = radeon_ib_test(rdev); + if (r) { + DRM_ERROR("radeon: failled testing IB (%d).\n", r); + return r; + } + } + ret = r; + r = radeon_modeset_init(rdev); + if (r) { + return r; + } + if (rdev->fbdev_rfb && rdev->fbdev_rfb->obj) { + rdev->fbdev_robj = rdev->fbdev_rfb->obj->driver_private; + } + if (!ret) { + DRM_INFO("radeon: kernel modesetting successfully initialized.\n"); + } + if (radeon_benchmarking) { + radeon_benchmark(rdev); + } + return ret; +} + +void radeon_device_fini(struct radeon_device *rdev) +{ + if (rdev == NULL || rdev->rmmio == NULL) { + return; + } + DRM_INFO("radeon: finishing device.\n"); + rdev->shutdown = true; + /* Order matter so becarefull if you rearrange anythings */ + radeon_modeset_fini(rdev); + radeon_ib_pool_fini(rdev); + radeon_cp_fini(rdev); + radeon_wb_fini(rdev); + radeon_gem_fini(rdev); + radeon_object_fini(rdev); + /* mc_fini must be after object_fini */ + radeon_mc_fini(rdev); +#if __OS_HAS_AGP + radeon_agp_fini(rdev); +#endif + radeon_irq_kms_fini(rdev); + radeon_fence_driver_fini(rdev); + radeon_clocks_fini(rdev); + if (rdev->is_atom_bios) { + radeon_atombios_fini(rdev); + } else { + radeon_combios_fini(rdev); + } + kfree(rdev->bios); + rdev->bios = NULL; + iounmap(rdev->rmmio); + rdev->rmmio = NULL; +} + + +/* + * Suspend & resume. + */ +int radeon_suspend_kms(struct drm_device *dev, pm_message_t state) +{ + struct radeon_device *rdev = dev->dev_private; + struct drm_crtc *crtc; + + if (dev == NULL || rdev == NULL) { + return -ENODEV; + } + if (state.event == PM_EVENT_PRETHAW) { + return 0; + } + /* unpin the front buffers */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct radeon_framebuffer *rfb = to_radeon_framebuffer(crtc->fb); + struct radeon_object *robj; + + if (rfb == NULL || rfb->obj == NULL) { + continue; + } + robj = rfb->obj->driver_private; + if (robj != rdev->fbdev_robj) { + radeon_object_unpin(robj); + } + } + /* evict vram memory */ + radeon_object_evict_vram(rdev); + /* wait for gpu to finish processing current batch */ + radeon_fence_wait_last(rdev); + + radeon_cp_disable(rdev); + radeon_gart_disable(rdev); + + /* evict remaining vram memory */ + radeon_object_evict_vram(rdev); + + rdev->irq.sw_int = false; + radeon_irq_set(rdev); + + pci_save_state(dev->pdev); + if (state.event == PM_EVENT_SUSPEND) { + /* Shut down the device */ + pci_disable_device(dev->pdev); + pci_set_power_state(dev->pdev, PCI_D3hot); + } + acquire_console_sem(); + fb_set_suspend(rdev->fbdev_info, 1); + release_console_sem(); + return 0; +} + +int radeon_resume_kms(struct drm_device *dev) +{ + struct radeon_device *rdev = dev->dev_private; + int r; + + acquire_console_sem(); + pci_set_power_state(dev->pdev, PCI_D0); + pci_restore_state(dev->pdev); + if (pci_enable_device(dev->pdev)) { + release_console_sem(); + return -1; + } + pci_set_master(dev->pdev); + /* Reset gpu before posting otherwise ATOM will enter infinite loop */ + if (radeon_gpu_reset(rdev)) { + /* FIXME: what do we want to do here ? */ + } + /* post card */ + if (rdev->is_atom_bios) { + atom_asic_init(rdev->mode_info.atom_context); + } else { + radeon_combios_asic_init(rdev->ddev); + } + /* Initialize clocks */ + r = radeon_clocks_init(rdev); + if (r) { + release_console_sem(); + return r; + } + /* Enable IRQ */ + rdev->irq.sw_int = true; + radeon_irq_set(rdev); + /* Initialize GPU Memory Controller */ + r = radeon_mc_init(rdev); + if (r) { + goto out; + } + r = radeon_gart_enable(rdev); + if (r) { + goto out; + } + r = radeon_cp_init(rdev, rdev->cp.ring_size); + if (r) { + goto out; + } +out: + fb_set_suspend(rdev->fbdev_info, 0); + release_console_sem(); + + /* blat the mode back in */ + drm_helper_resume_force_mode(dev); + return 0; +} + + +/* + * Debugfs + */ +struct radeon_debugfs { + struct drm_info_list *files; + unsigned num_files; +}; +static struct radeon_debugfs _radeon_debugfs[RADEON_DEBUGFS_MAX_NUM_FILES]; +static unsigned _radeon_debugfs_count = 0; + +int radeon_debugfs_add_files(struct radeon_device *rdev, + struct drm_info_list *files, + unsigned nfiles) +{ + unsigned i; + + for (i = 0; i < _radeon_debugfs_count; i++) { + if (_radeon_debugfs[i].files == files) { + /* Already registered */ + return 0; + } + } + if ((_radeon_debugfs_count + nfiles) > RADEON_DEBUGFS_MAX_NUM_FILES) { + DRM_ERROR("Reached maximum number of debugfs files.\n"); + DRM_ERROR("Report so we increase RADEON_DEBUGFS_MAX_NUM_FILES.\n"); + return -EINVAL; + } + _radeon_debugfs[_radeon_debugfs_count].files = files; + _radeon_debugfs[_radeon_debugfs_count].num_files = nfiles; + _radeon_debugfs_count++; +#if defined(CONFIG_DEBUG_FS) + drm_debugfs_create_files(files, nfiles, + rdev->ddev->control->debugfs_root, + rdev->ddev->control); + drm_debugfs_create_files(files, nfiles, + rdev->ddev->primary->debugfs_root, + rdev->ddev->primary); +#endif + return 0; +} + +#if defined(CONFIG_DEBUG_FS) +int radeon_debugfs_init(struct drm_minor *minor) +{ + return 0; +} + +void radeon_debugfs_cleanup(struct drm_minor *minor) +{ + unsigned i; + + for (i = 0; i < _radeon_debugfs_count; i++) { + drm_debugfs_remove_files(_radeon_debugfs[i].files, + _radeon_debugfs[i].num_files, minor); + } +} +#endif diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c new file mode 100644 index 000000000000..3efcf1a526be --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -0,0 +1,692 @@ +/* + * Copyright 2007-8 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Dave Airlie + * Alex Deucher + */ +#include "drmP.h" +#include "radeon_drm.h" +#include "radeon.h" + +#include "atom.h" +#include + +#include "drm_crtc_helper.h" +#include "drm_edid.h" + +static int radeon_ddc_dump(struct drm_connector *connector); + +static void avivo_crtc_load_lut(struct drm_crtc *crtc) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct radeon_device *rdev = dev->dev_private; + int i; + + DRM_DEBUG("%d\n", radeon_crtc->crtc_id); + WREG32(AVIVO_DC_LUTA_CONTROL + radeon_crtc->crtc_offset, 0); + + WREG32(AVIVO_DC_LUTA_BLACK_OFFSET_BLUE + radeon_crtc->crtc_offset, 0); + WREG32(AVIVO_DC_LUTA_BLACK_OFFSET_GREEN + radeon_crtc->crtc_offset, 0); + WREG32(AVIVO_DC_LUTA_BLACK_OFFSET_RED + radeon_crtc->crtc_offset, 0); + + WREG32(AVIVO_DC_LUTA_WHITE_OFFSET_BLUE + radeon_crtc->crtc_offset, 0xffff); + WREG32(AVIVO_DC_LUTA_WHITE_OFFSET_GREEN + radeon_crtc->crtc_offset, 0xffff); + WREG32(AVIVO_DC_LUTA_WHITE_OFFSET_RED + radeon_crtc->crtc_offset, 0xffff); + + WREG32(AVIVO_DC_LUT_RW_SELECT, radeon_crtc->crtc_id); + WREG32(AVIVO_DC_LUT_RW_MODE, 0); + WREG32(AVIVO_DC_LUT_WRITE_EN_MASK, 0x0000003f); + + WREG8(AVIVO_DC_LUT_RW_INDEX, 0); + for (i = 0; i < 256; i++) { + WREG32(AVIVO_DC_LUT_30_COLOR, + (radeon_crtc->lut_r[i] << 20) | + (radeon_crtc->lut_g[i] << 10) | + (radeon_crtc->lut_b[i] << 0)); + } + + WREG32(AVIVO_D1GRPH_LUT_SEL + radeon_crtc->crtc_offset, radeon_crtc->crtc_id); +} + +static void legacy_crtc_load_lut(struct drm_crtc *crtc) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct radeon_device *rdev = dev->dev_private; + int i; + uint32_t dac2_cntl; + + dac2_cntl = RREG32(RADEON_DAC_CNTL2); + if (radeon_crtc->crtc_id == 0) + dac2_cntl &= (uint32_t)~RADEON_DAC2_PALETTE_ACC_CTL; + else + dac2_cntl |= RADEON_DAC2_PALETTE_ACC_CTL; + WREG32(RADEON_DAC_CNTL2, dac2_cntl); + + WREG8(RADEON_PALETTE_INDEX, 0); + for (i = 0; i < 256; i++) { + WREG32(RADEON_PALETTE_30_DATA, + (radeon_crtc->lut_r[i] << 20) | + (radeon_crtc->lut_g[i] << 10) | + (radeon_crtc->lut_b[i] << 0)); + } +} + +void radeon_crtc_load_lut(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct radeon_device *rdev = dev->dev_private; + + if (!crtc->enabled) + return; + + if (ASIC_IS_AVIVO(rdev)) + avivo_crtc_load_lut(crtc); + else + legacy_crtc_load_lut(crtc); +} + +/** Sets the color ramps on behalf of RandR */ +void radeon_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, + u16 blue, int regno) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + + if (regno == 0) + DRM_DEBUG("gamma set %d\n", radeon_crtc->crtc_id); + radeon_crtc->lut_r[regno] = red >> 6; + radeon_crtc->lut_g[regno] = green >> 6; + radeon_crtc->lut_b[regno] = blue >> 6; +} + +static void radeon_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, + u16 *blue, uint32_t size) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + int i, j; + + if (size != 256) { + return; + } + if (crtc->fb == NULL) { + return; + } + + if (crtc->fb->depth == 16) { + for (i = 0; i < 64; i++) { + if (i <= 31) { + for (j = 0; j < 8; j++) { + radeon_crtc->lut_r[i * 8 + j] = red[i] >> 6; + radeon_crtc->lut_b[i * 8 + j] = blue[i] >> 6; + } + } + for (j = 0; j < 4; j++) + radeon_crtc->lut_g[i * 4 + j] = green[i] >> 6; + } + } else { + for (i = 0; i < 256; i++) { + radeon_crtc->lut_r[i] = red[i] >> 6; + radeon_crtc->lut_g[i] = green[i] >> 6; + radeon_crtc->lut_b[i] = blue[i] >> 6; + } + } + + radeon_crtc_load_lut(crtc); +} + +static void radeon_crtc_destroy(struct drm_crtc *crtc) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + + if (radeon_crtc->mode_set.mode) { + drm_mode_destroy(crtc->dev, radeon_crtc->mode_set.mode); + } + drm_crtc_cleanup(crtc); + kfree(radeon_crtc); +} + +static const struct drm_crtc_funcs radeon_crtc_funcs = { + .cursor_set = radeon_crtc_cursor_set, + .cursor_move = radeon_crtc_cursor_move, + .gamma_set = radeon_crtc_gamma_set, + .set_config = drm_crtc_helper_set_config, + .destroy = radeon_crtc_destroy, +}; + +static void radeon_crtc_init(struct drm_device *dev, int index) +{ + struct radeon_device *rdev = dev->dev_private; + struct radeon_crtc *radeon_crtc; + int i; + + radeon_crtc = kzalloc(sizeof(struct radeon_crtc) + (RADEONFB_CONN_LIMIT * sizeof(struct drm_connector *)), GFP_KERNEL); + if (radeon_crtc == NULL) + return; + + drm_crtc_init(dev, &radeon_crtc->base, &radeon_crtc_funcs); + + drm_mode_crtc_set_gamma_size(&radeon_crtc->base, 256); + radeon_crtc->crtc_id = index; + + radeon_crtc->mode_set.crtc = &radeon_crtc->base; + radeon_crtc->mode_set.connectors = (struct drm_connector **)(radeon_crtc + 1); + radeon_crtc->mode_set.num_connectors = 0; + + for (i = 0; i < 256; i++) { + radeon_crtc->lut_r[i] = i << 2; + radeon_crtc->lut_g[i] = i << 2; + radeon_crtc->lut_b[i] = i << 2; + } + + if (rdev->is_atom_bios && (ASIC_IS_AVIVO(rdev) || radeon_r4xx_atom)) + radeon_atombios_init_crtc(dev, radeon_crtc); + else + radeon_legacy_init_crtc(dev, radeon_crtc); +} + +static const char *encoder_names[34] = { + "NONE", + "INTERNAL_LVDS", + "INTERNAL_TMDS1", + "INTERNAL_TMDS2", + "INTERNAL_DAC1", + "INTERNAL_DAC2", + "INTERNAL_SDVOA", + "INTERNAL_SDVOB", + "SI170B", + "CH7303", + "CH7301", + "INTERNAL_DVO1", + "EXTERNAL_SDVOA", + "EXTERNAL_SDVOB", + "TITFP513", + "INTERNAL_LVTM1", + "VT1623", + "HDMI_SI1930", + "HDMI_INTERNAL", + "INTERNAL_KLDSCP_TMDS1", + "INTERNAL_KLDSCP_DVO1", + "INTERNAL_KLDSCP_DAC1", + "INTERNAL_KLDSCP_DAC2", + "SI178", + "MVPU_FPGA", + "INTERNAL_DDI", + "VT1625", + "HDMI_SI1932", + "DP_AN9801", + "DP_DP501", + "INTERNAL_UNIPHY", + "INTERNAL_KLDSCP_LVTMA", + "INTERNAL_UNIPHY1", + "INTERNAL_UNIPHY2", +}; + +static const char *connector_names[13] = { + "Unknown", + "VGA", + "DVI-I", + "DVI-D", + "DVI-A", + "Composite", + "S-video", + "LVDS", + "Component", + "DIN", + "DisplayPort", + "HDMI-A", + "HDMI-B", +}; + +static void radeon_print_display_setup(struct drm_device *dev) +{ + struct drm_connector *connector; + struct radeon_connector *radeon_connector; + struct drm_encoder *encoder; + struct radeon_encoder *radeon_encoder; + uint32_t devices; + int i = 0; + + DRM_INFO("Radeon Display Connectors\n"); + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + radeon_connector = to_radeon_connector(connector); + DRM_INFO("Connector %d:\n", i); + DRM_INFO(" %s\n", connector_names[connector->connector_type]); + if (radeon_connector->ddc_bus) + DRM_INFO(" DDC: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", + radeon_connector->ddc_bus->rec.mask_clk_reg, + radeon_connector->ddc_bus->rec.mask_data_reg, + radeon_connector->ddc_bus->rec.a_clk_reg, + radeon_connector->ddc_bus->rec.a_data_reg, + radeon_connector->ddc_bus->rec.put_clk_reg, + radeon_connector->ddc_bus->rec.put_data_reg, + radeon_connector->ddc_bus->rec.get_clk_reg, + radeon_connector->ddc_bus->rec.get_data_reg); + DRM_INFO(" Encoders:\n"); + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + radeon_encoder = to_radeon_encoder(encoder); + devices = radeon_encoder->devices & radeon_connector->devices; + if (devices) { + if (devices & ATOM_DEVICE_CRT1_SUPPORT) + DRM_INFO(" CRT1: %s\n", encoder_names[radeon_encoder->encoder_id]); + if (devices & ATOM_DEVICE_CRT2_SUPPORT) + DRM_INFO(" CRT2: %s\n", encoder_names[radeon_encoder->encoder_id]); + if (devices & ATOM_DEVICE_LCD1_SUPPORT) + DRM_INFO(" LCD1: %s\n", encoder_names[radeon_encoder->encoder_id]); + if (devices & ATOM_DEVICE_DFP1_SUPPORT) + DRM_INFO(" DFP1: %s\n", encoder_names[radeon_encoder->encoder_id]); + if (devices & ATOM_DEVICE_DFP2_SUPPORT) + DRM_INFO(" DFP2: %s\n", encoder_names[radeon_encoder->encoder_id]); + if (devices & ATOM_DEVICE_DFP3_SUPPORT) + DRM_INFO(" DFP3: %s\n", encoder_names[radeon_encoder->encoder_id]); + if (devices & ATOM_DEVICE_DFP4_SUPPORT) + DRM_INFO(" DFP4: %s\n", encoder_names[radeon_encoder->encoder_id]); + if (devices & ATOM_DEVICE_DFP5_SUPPORT) + DRM_INFO(" DFP5: %s\n", encoder_names[radeon_encoder->encoder_id]); + if (devices & ATOM_DEVICE_TV1_SUPPORT) + DRM_INFO(" TV1: %s\n", encoder_names[radeon_encoder->encoder_id]); + if (devices & ATOM_DEVICE_CV_SUPPORT) + DRM_INFO(" CV: %s\n", encoder_names[radeon_encoder->encoder_id]); + } + } + i++; + } +} + +bool radeon_setup_enc_conn(struct drm_device *dev) +{ + struct radeon_device *rdev = dev->dev_private; + struct drm_connector *drm_connector; + bool ret = false; + + if (rdev->bios) { + if (rdev->is_atom_bios) { + if (rdev->family >= CHIP_R600) + ret = radeon_get_atom_connector_info_from_object_table(dev); + else + ret = radeon_get_atom_connector_info_from_supported_devices_table(dev); + } else + ret = radeon_get_legacy_connector_info_from_bios(dev); + } else { + if (!ASIC_IS_AVIVO(rdev)) + ret = radeon_get_legacy_connector_info_from_table(dev); + } + if (ret) { + radeon_print_display_setup(dev); + list_for_each_entry(drm_connector, &dev->mode_config.connector_list, head) + radeon_ddc_dump(drm_connector); + } + + return ret; +} + +int radeon_ddc_get_modes(struct radeon_connector *radeon_connector) +{ + struct edid *edid; + int ret = 0; + + if (!radeon_connector->ddc_bus) + return -1; + radeon_i2c_do_lock(radeon_connector, 1); + edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter); + radeon_i2c_do_lock(radeon_connector, 0); + if (edid) { + /* update digital bits here */ + if (edid->input & DRM_EDID_INPUT_DIGITAL) + radeon_connector->use_digital = 1; + else + radeon_connector->use_digital = 0; + drm_mode_connector_update_edid_property(&radeon_connector->base, edid); + ret = drm_add_edid_modes(&radeon_connector->base, edid); + kfree(edid); + return ret; + } + drm_mode_connector_update_edid_property(&radeon_connector->base, NULL); + return -1; +} + +static int radeon_ddc_dump(struct drm_connector *connector) +{ + struct edid *edid; + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + int ret = 0; + + if (!radeon_connector->ddc_bus) + return -1; + radeon_i2c_do_lock(radeon_connector, 1); + edid = drm_get_edid(connector, &radeon_connector->ddc_bus->adapter); + radeon_i2c_do_lock(radeon_connector, 0); + if (edid) { + kfree(edid); + } + return ret; +} + +static inline uint32_t radeon_div(uint64_t n, uint32_t d) +{ + uint64_t mod; + + n += d / 2; + + mod = do_div(n, d); + return n; +} + +void radeon_compute_pll(struct radeon_pll *pll, + uint64_t freq, + uint32_t *dot_clock_p, + uint32_t *fb_div_p, + uint32_t *frac_fb_div_p, + uint32_t *ref_div_p, + uint32_t *post_div_p, + int flags) +{ + uint32_t min_ref_div = pll->min_ref_div; + uint32_t max_ref_div = pll->max_ref_div; + uint32_t min_fractional_feed_div = 0; + uint32_t max_fractional_feed_div = 0; + uint32_t best_vco = pll->best_vco; + uint32_t best_post_div = 1; + uint32_t best_ref_div = 1; + uint32_t best_feedback_div = 1; + uint32_t best_frac_feedback_div = 0; + uint32_t best_freq = -1; + uint32_t best_error = 0xffffffff; + uint32_t best_vco_diff = 1; + uint32_t post_div; + + DRM_DEBUG("PLL freq %llu %u %u\n", freq, pll->min_ref_div, pll->max_ref_div); + freq = freq * 1000; + + if (flags & RADEON_PLL_USE_REF_DIV) + min_ref_div = max_ref_div = pll->reference_div; + else { + while (min_ref_div < max_ref_div-1) { + uint32_t mid = (min_ref_div + max_ref_div) / 2; + uint32_t pll_in = pll->reference_freq / mid; + if (pll_in < pll->pll_in_min) + max_ref_div = mid; + else if (pll_in > pll->pll_in_max) + min_ref_div = mid; + else + break; + } + } + + if (flags & RADEON_PLL_USE_FRAC_FB_DIV) { + min_fractional_feed_div = pll->min_frac_feedback_div; + max_fractional_feed_div = pll->max_frac_feedback_div; + } + + for (post_div = pll->min_post_div; post_div <= pll->max_post_div; ++post_div) { + uint32_t ref_div; + + if ((flags & RADEON_PLL_NO_ODD_POST_DIV) && (post_div & 1)) + continue; + + /* legacy radeons only have a few post_divs */ + if (flags & RADEON_PLL_LEGACY) { + if ((post_div == 5) || + (post_div == 7) || + (post_div == 9) || + (post_div == 10) || + (post_div == 11) || + (post_div == 13) || + (post_div == 14) || + (post_div == 15)) + continue; + } + + for (ref_div = min_ref_div; ref_div <= max_ref_div; ++ref_div) { + uint32_t feedback_div, current_freq = 0, error, vco_diff; + uint32_t pll_in = pll->reference_freq / ref_div; + uint32_t min_feed_div = pll->min_feedback_div; + uint32_t max_feed_div = pll->max_feedback_div + 1; + + if (pll_in < pll->pll_in_min || pll_in > pll->pll_in_max) + continue; + + while (min_feed_div < max_feed_div) { + uint32_t vco; + uint32_t min_frac_feed_div = min_fractional_feed_div; + uint32_t max_frac_feed_div = max_fractional_feed_div + 1; + uint32_t frac_feedback_div; + uint64_t tmp; + + feedback_div = (min_feed_div + max_feed_div) / 2; + + tmp = (uint64_t)pll->reference_freq * feedback_div; + vco = radeon_div(tmp, ref_div); + + if (vco < pll->pll_out_min) { + min_feed_div = feedback_div + 1; + continue; + } else if (vco > pll->pll_out_max) { + max_feed_div = feedback_div; + continue; + } + + while (min_frac_feed_div < max_frac_feed_div) { + frac_feedback_div = (min_frac_feed_div + max_frac_feed_div) / 2; + tmp = (uint64_t)pll->reference_freq * 10000 * feedback_div; + tmp += (uint64_t)pll->reference_freq * 1000 * frac_feedback_div; + current_freq = radeon_div(tmp, ref_div * post_div); + + error = abs(current_freq - freq); + vco_diff = abs(vco - best_vco); + + if ((best_vco == 0 && error < best_error) || + (best_vco != 0 && + (error < best_error - 100 || + (abs(error - best_error) < 100 && vco_diff < best_vco_diff)))) { + best_post_div = post_div; + best_ref_div = ref_div; + best_feedback_div = feedback_div; + best_frac_feedback_div = frac_feedback_div; + best_freq = current_freq; + best_error = error; + best_vco_diff = vco_diff; + } else if (current_freq == freq) { + if (best_freq == -1) { + best_post_div = post_div; + best_ref_div = ref_div; + best_feedback_div = feedback_div; + best_frac_feedback_div = frac_feedback_div; + best_freq = current_freq; + best_error = error; + best_vco_diff = vco_diff; + } else if (((flags & RADEON_PLL_PREFER_LOW_REF_DIV) && (ref_div < best_ref_div)) || + ((flags & RADEON_PLL_PREFER_HIGH_REF_DIV) && (ref_div > best_ref_div)) || + ((flags & RADEON_PLL_PREFER_LOW_FB_DIV) && (feedback_div < best_feedback_div)) || + ((flags & RADEON_PLL_PREFER_HIGH_FB_DIV) && (feedback_div > best_feedback_div)) || + ((flags & RADEON_PLL_PREFER_LOW_POST_DIV) && (post_div < best_post_div)) || + ((flags & RADEON_PLL_PREFER_HIGH_POST_DIV) && (post_div > best_post_div))) { + best_post_div = post_div; + best_ref_div = ref_div; + best_feedback_div = feedback_div; + best_frac_feedback_div = frac_feedback_div; + best_freq = current_freq; + best_error = error; + best_vco_diff = vco_diff; + } + } + if (current_freq < freq) + min_frac_feed_div = frac_feedback_div + 1; + else + max_frac_feed_div = frac_feedback_div; + } + if (current_freq < freq) + min_feed_div = feedback_div + 1; + else + max_feed_div = feedback_div; + } + } + } + + *dot_clock_p = best_freq / 10000; + *fb_div_p = best_feedback_div; + *frac_fb_div_p = best_frac_feedback_div; + *ref_div_p = best_ref_div; + *post_div_p = best_post_div; +} + +static void radeon_user_framebuffer_destroy(struct drm_framebuffer *fb) +{ + struct radeon_framebuffer *radeon_fb = to_radeon_framebuffer(fb); + struct drm_device *dev = fb->dev; + + if (fb->fbdev) + radeonfb_remove(dev, fb); + + if (radeon_fb->obj) { + radeon_gem_object_unpin(radeon_fb->obj); + mutex_lock(&dev->struct_mutex); + drm_gem_object_unreference(radeon_fb->obj); + mutex_unlock(&dev->struct_mutex); + } + drm_framebuffer_cleanup(fb); + kfree(radeon_fb); +} + +static int radeon_user_framebuffer_create_handle(struct drm_framebuffer *fb, + struct drm_file *file_priv, + unsigned int *handle) +{ + struct radeon_framebuffer *radeon_fb = to_radeon_framebuffer(fb); + + return drm_gem_handle_create(file_priv, radeon_fb->obj, handle); +} + +static const struct drm_framebuffer_funcs radeon_fb_funcs = { + .destroy = radeon_user_framebuffer_destroy, + .create_handle = radeon_user_framebuffer_create_handle, +}; + +struct drm_framebuffer * +radeon_framebuffer_create(struct drm_device *dev, + struct drm_mode_fb_cmd *mode_cmd, + struct drm_gem_object *obj) +{ + struct radeon_framebuffer *radeon_fb; + + radeon_fb = kzalloc(sizeof(*radeon_fb), GFP_KERNEL); + if (radeon_fb == NULL) { + return NULL; + } + drm_framebuffer_init(dev, &radeon_fb->base, &radeon_fb_funcs); + drm_helper_mode_fill_fb_struct(&radeon_fb->base, mode_cmd); + radeon_fb->obj = obj; + return &radeon_fb->base; +} + +static struct drm_framebuffer * +radeon_user_framebuffer_create(struct drm_device *dev, + struct drm_file *file_priv, + struct drm_mode_fb_cmd *mode_cmd) +{ + struct drm_gem_object *obj; + + obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handle); + + return radeon_framebuffer_create(dev, mode_cmd, obj); +} + +static const struct drm_mode_config_funcs radeon_mode_funcs = { + .fb_create = radeon_user_framebuffer_create, + .fb_changed = radeonfb_probe, +}; + +int radeon_modeset_init(struct radeon_device *rdev) +{ + int num_crtc = 2, i; + int ret; + + drm_mode_config_init(rdev->ddev); + rdev->mode_info.mode_config_initialized = true; + + rdev->ddev->mode_config.funcs = (void *)&radeon_mode_funcs; + + if (ASIC_IS_AVIVO(rdev)) { + rdev->ddev->mode_config.max_width = 8192; + rdev->ddev->mode_config.max_height = 8192; + } else { + rdev->ddev->mode_config.max_width = 4096; + rdev->ddev->mode_config.max_height = 4096; + } + + rdev->ddev->mode_config.fb_base = rdev->mc.aper_base; + + /* allocate crtcs - TODO single crtc */ + for (i = 0; i < num_crtc; i++) { + radeon_crtc_init(rdev->ddev, i); + } + + /* okay we should have all the bios connectors */ + ret = radeon_setup_enc_conn(rdev->ddev); + if (!ret) { + return ret; + } + drm_helper_initial_config(rdev->ddev); + return 0; +} + +void radeon_modeset_fini(struct radeon_device *rdev) +{ + if (rdev->mode_info.mode_config_initialized) { + drm_mode_config_cleanup(rdev->ddev); + rdev->mode_info.mode_config_initialized = false; + } +} + +void radeon_init_disp_bandwidth(struct drm_device *dev) +{ + struct radeon_device *rdev = dev->dev_private; + struct drm_display_mode *modes[2]; + int pixel_bytes[2]; + struct drm_crtc *crtc; + + pixel_bytes[0] = pixel_bytes[1] = 0; + modes[0] = modes[1] = NULL; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + + if (crtc->enabled && crtc->fb) { + modes[radeon_crtc->crtc_id] = &crtc->mode; + pixel_bytes[radeon_crtc->crtc_id] = crtc->fb->bits_per_pixel / 8; + } + } + + if (ASIC_IS_AVIVO(rdev)) { + radeon_init_disp_bw_avivo(dev, + modes[0], + pixel_bytes[0], + modes[1], + pixel_bytes[1]); + } else { + radeon_init_disp_bw_legacy(dev, + modes[0], + pixel_bytes[0], + modes[1], + pixel_bytes[1]); + } +} diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 13a60f4d4227..09c9fb9f6210 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -35,12 +35,92 @@ #include "radeon_drv.h" #include "drm_pciids.h" +#include + + +#if defined(CONFIG_DRM_RADEON_KMS) +/* + * KMS wrapper. + */ +#define KMS_DRIVER_MAJOR 2 +#define KMS_DRIVER_MINOR 0 +#define KMS_DRIVER_PATCHLEVEL 0 +int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags); +int radeon_driver_unload_kms(struct drm_device *dev); +int radeon_driver_firstopen_kms(struct drm_device *dev); +void radeon_driver_lastclose_kms(struct drm_device *dev); +int radeon_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv); +void radeon_driver_postclose_kms(struct drm_device *dev, + struct drm_file *file_priv); +void radeon_driver_preclose_kms(struct drm_device *dev, + struct drm_file *file_priv); +int radeon_suspend_kms(struct drm_device *dev, pm_message_t state); +int radeon_resume_kms(struct drm_device *dev); +u32 radeon_get_vblank_counter_kms(struct drm_device *dev, int crtc); +int radeon_enable_vblank_kms(struct drm_device *dev, int crtc); +void radeon_disable_vblank_kms(struct drm_device *dev, int crtc); +void radeon_driver_irq_preinstall_kms(struct drm_device *dev); +int radeon_driver_irq_postinstall_kms(struct drm_device *dev); +void radeon_driver_irq_uninstall_kms(struct drm_device *dev); +irqreturn_t radeon_driver_irq_handler_kms(DRM_IRQ_ARGS); +int radeon_master_create_kms(struct drm_device *dev, struct drm_master *master); +void radeon_master_destroy_kms(struct drm_device *dev, + struct drm_master *master); +int radeon_dma_ioctl_kms(struct drm_device *dev, void *data, + struct drm_file *file_priv); +int radeon_gem_object_init(struct drm_gem_object *obj); +void radeon_gem_object_free(struct drm_gem_object *obj); +extern struct drm_ioctl_desc radeon_ioctls_kms[]; +extern int radeon_max_kms_ioctl; +int radeon_mmap(struct file *filp, struct vm_area_struct *vma); +#if defined(CONFIG_DEBUG_FS) +int radeon_debugfs_init(struct drm_minor *minor); +void radeon_debugfs_cleanup(struct drm_minor *minor); +#endif +#endif + int radeon_no_wb; +#if defined(CONFIG_DRM_RADEON_KMS) +int radeon_modeset = -1; +int radeon_dynclks = -1; +int radeon_r4xx_atom = 0; +int radeon_agpmode = 0; +int radeon_vram_limit = 0; +int radeon_gart_size = 512; /* default gart size */ +int radeon_benchmarking = 0; +int radeon_connector_table = 0; +#endif MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers"); module_param_named(no_wb, radeon_no_wb, int, 0444); +#if defined(CONFIG_DRM_RADEON_KMS) +MODULE_PARM_DESC(modeset, "Disable/Enable modesetting"); +module_param_named(modeset, radeon_modeset, int, 0400); + +MODULE_PARM_DESC(dynclks, "Disable/Enable dynamic clocks"); +module_param_named(dynclks, radeon_dynclks, int, 0444); + +MODULE_PARM_DESC(r4xx_atom, "Enable ATOMBIOS modesetting for R4xx"); +module_param_named(r4xx_atom, radeon_r4xx_atom, int, 0444); + +MODULE_PARM_DESC(vramlimit, "Restrict VRAM for testing"); +module_param_named(vramlimit, radeon_vram_limit, int, 0600); + +MODULE_PARM_DESC(agpmode, "AGP Mode (-1 == PCI)"); +module_param_named(agpmode, radeon_agpmode, int, 0444); + +MODULE_PARM_DESC(gartsize, "Size of PCIE/IGP gart to setup in megabytes (32,64, etc)\n"); +module_param_named(gartsize, radeon_gart_size, int, 0600); + +MODULE_PARM_DESC(benchmark, "Run benchmark"); +module_param_named(benchmark, radeon_benchmarking, int, 0444); + +MODULE_PARM_DESC(connector_table, "Force connector table"); +module_param_named(connector_table, radeon_connector_table, int, 0444); +#endif + static int radeon_suspend(struct drm_device *dev, pm_message_t state) { drm_radeon_private_t *dev_priv = dev->dev_private; @@ -73,7 +153,11 @@ static struct pci_device_id pciidlist[] = { radeon_PCI_IDS }; -static struct drm_driver driver = { +#if defined(CONFIG_DRM_RADEON_KMS) +MODULE_DEVICE_TABLE(pci, pciidlist); +#endif + +static struct drm_driver driver_old = { .driver_features = DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG | DRIVER_HAVE_IRQ | DRIVER_HAVE_DMA | DRIVER_IRQ_SHARED, @@ -127,18 +211,141 @@ static struct drm_driver driver = { .patchlevel = DRIVER_PATCHLEVEL, }; +#if defined(CONFIG_DRM_RADEON_KMS) +static struct drm_driver kms_driver; + +static int __devinit +radeon_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + return drm_get_dev(pdev, ent, &kms_driver); +} + +static void +radeon_pci_remove(struct pci_dev *pdev) +{ + struct drm_device *dev = pci_get_drvdata(pdev); + + drm_put_dev(dev); +} + +static int +radeon_pci_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct drm_device *dev = pci_get_drvdata(pdev); + return radeon_suspend_kms(dev, state); +} + +static int +radeon_pci_resume(struct pci_dev *pdev) +{ + struct drm_device *dev = pci_get_drvdata(pdev); + return radeon_resume_kms(dev); +} + +static struct drm_driver kms_driver = { + .driver_features = + DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG | + DRIVER_HAVE_IRQ | DRIVER_HAVE_DMA | DRIVER_IRQ_SHARED | DRIVER_GEM, + .dev_priv_size = 0, + .load = radeon_driver_load_kms, + .firstopen = radeon_driver_firstopen_kms, + .open = radeon_driver_open_kms, + .preclose = radeon_driver_preclose_kms, + .postclose = radeon_driver_postclose_kms, + .lastclose = radeon_driver_lastclose_kms, + .unload = radeon_driver_unload_kms, + .suspend = radeon_suspend_kms, + .resume = radeon_resume_kms, + .get_vblank_counter = radeon_get_vblank_counter_kms, + .enable_vblank = radeon_enable_vblank_kms, + .disable_vblank = radeon_disable_vblank_kms, + .master_create = radeon_master_create_kms, + .master_destroy = radeon_master_destroy_kms, +#if defined(CONFIG_DEBUG_FS) + .debugfs_init = radeon_debugfs_init, + .debugfs_cleanup = radeon_debugfs_cleanup, +#endif + .irq_preinstall = radeon_driver_irq_preinstall_kms, + .irq_postinstall = radeon_driver_irq_postinstall_kms, + .irq_uninstall = radeon_driver_irq_uninstall_kms, + .irq_handler = radeon_driver_irq_handler_kms, + .reclaim_buffers = drm_core_reclaim_buffers, + .get_map_ofs = drm_core_get_map_ofs, + .get_reg_ofs = drm_core_get_reg_ofs, + .ioctls = radeon_ioctls_kms, + .gem_init_object = radeon_gem_object_init, + .gem_free_object = radeon_gem_object_free, + .dma_ioctl = radeon_dma_ioctl_kms, + .fops = { + .owner = THIS_MODULE, + .open = drm_open, + .release = drm_release, + .ioctl = drm_ioctl, + .mmap = radeon_mmap, + .poll = drm_poll, + .fasync = drm_fasync, +#ifdef CONFIG_COMPAT + .compat_ioctl = NULL, +#endif + }, + + .pci_driver = { + .name = DRIVER_NAME, + .id_table = pciidlist, + .probe = radeon_pci_probe, + .remove = radeon_pci_remove, + .suspend = radeon_pci_suspend, + .resume = radeon_pci_resume, + }, + + .name = DRIVER_NAME, + .desc = DRIVER_DESC, + .date = DRIVER_DATE, + .major = KMS_DRIVER_MAJOR, + .minor = KMS_DRIVER_MINOR, + .patchlevel = KMS_DRIVER_PATCHLEVEL, +}; +#endif + +static struct drm_driver *driver; + static int __init radeon_init(void) { - driver.num_ioctls = radeon_max_ioctl; - return drm_init(&driver); + driver = &driver_old; + driver->num_ioctls = radeon_max_ioctl; +#if defined(CONFIG_DRM_RADEON_KMS) + /* if enabled by default */ + if (radeon_modeset == -1) { + DRM_INFO("radeon default to kernel modesetting.\n"); + radeon_modeset = 1; + } + if (radeon_modeset == 1) { + DRM_INFO("radeon kernel modesetting enabled.\n"); + driver = &kms_driver; + driver->driver_features |= DRIVER_MODESET; + driver->num_ioctls = radeon_max_kms_ioctl; + } + + /* if the vga console setting is enabled still + * let modprobe override it */ +#ifdef CONFIG_VGA_CONSOLE + if (vgacon_text_force() && radeon_modeset == -1) { + DRM_INFO("VGACON disable radeon kernel modesetting.\n"); + driver = &driver_old; + driver->driver_features &= ~DRIVER_MODESET; + radeon_modeset = 0; + } +#endif +#endif + return drm_init(driver); } static void __exit radeon_exit(void) { - drm_exit(&driver); + drm_exit(driver); } -module_init(radeon_init); +late_initcall(radeon_init); module_exit(radeon_exit); MODULE_AUTHOR(DRIVER_AUTHOR); diff --git a/drivers/gpu/drm/radeon/radeon_drv.h b/drivers/gpu/drm/radeon/radeon_drv.h index 0c6bfc1de153..127d0456f628 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.h +++ b/drivers/gpu/drm/radeon/radeon_drv.h @@ -146,6 +146,7 @@ enum radeon_family { CHIP_RV770, CHIP_RV730, CHIP_RV710, + CHIP_RV740, CHIP_LAST, }; diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c new file mode 100644 index 000000000000..c8ef0d14ffab --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -0,0 +1,1708 @@ +/* + * Copyright 2007-8 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Dave Airlie + * Alex Deucher + */ +#include "drmP.h" +#include "drm_crtc_helper.h" +#include "radeon_drm.h" +#include "radeon.h" +#include "atom.h" + +extern int atom_debug; + +uint32_t +radeon_get_encoder_id(struct drm_device *dev, uint32_t supported_device, uint8_t dac) +{ + struct radeon_device *rdev = dev->dev_private; + uint32_t ret = 0; + + switch (supported_device) { + case ATOM_DEVICE_CRT1_SUPPORT: + case ATOM_DEVICE_TV1_SUPPORT: + case ATOM_DEVICE_TV2_SUPPORT: + case ATOM_DEVICE_CRT2_SUPPORT: + case ATOM_DEVICE_CV_SUPPORT: + switch (dac) { + case 1: /* dac a */ + if ((rdev->family == CHIP_RS300) || + (rdev->family == CHIP_RS400) || + (rdev->family == CHIP_RS480)) + ret = ENCODER_OBJECT_ID_INTERNAL_DAC2; + else if (ASIC_IS_AVIVO(rdev)) + ret = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1; + else + ret = ENCODER_OBJECT_ID_INTERNAL_DAC1; + break; + case 2: /* dac b */ + if (ASIC_IS_AVIVO(rdev)) + ret = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2; + else { + /*if (rdev->family == CHIP_R200) + ret = ENCODER_OBJECT_ID_INTERNAL_DVO1; + else*/ + ret = ENCODER_OBJECT_ID_INTERNAL_DAC2; + } + break; + case 3: /* external dac */ + if (ASIC_IS_AVIVO(rdev)) + ret = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1; + else + ret = ENCODER_OBJECT_ID_INTERNAL_DVO1; + break; + } + break; + case ATOM_DEVICE_LCD1_SUPPORT: + if (ASIC_IS_AVIVO(rdev)) + ret = ENCODER_OBJECT_ID_INTERNAL_LVTM1; + else + ret = ENCODER_OBJECT_ID_INTERNAL_LVDS; + break; + case ATOM_DEVICE_DFP1_SUPPORT: + if ((rdev->family == CHIP_RS300) || + (rdev->family == CHIP_RS400) || + (rdev->family == CHIP_RS480)) + ret = ENCODER_OBJECT_ID_INTERNAL_DVO1; + else if (ASIC_IS_AVIVO(rdev)) + ret = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1; + else + ret = ENCODER_OBJECT_ID_INTERNAL_TMDS1; + break; + case ATOM_DEVICE_LCD2_SUPPORT: + case ATOM_DEVICE_DFP2_SUPPORT: + if ((rdev->family == CHIP_RS600) || + (rdev->family == CHIP_RS690) || + (rdev->family == CHIP_RS740)) + ret = ENCODER_OBJECT_ID_INTERNAL_DDI; + else if (ASIC_IS_AVIVO(rdev)) + ret = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1; + else + ret = ENCODER_OBJECT_ID_INTERNAL_DVO1; + break; + case ATOM_DEVICE_DFP3_SUPPORT: + ret = ENCODER_OBJECT_ID_INTERNAL_LVTM1; + break; + } + + return ret; +} + +void +radeon_link_encoder_connector(struct drm_device *dev) +{ + struct drm_connector *connector; + struct radeon_connector *radeon_connector; + struct drm_encoder *encoder; + struct radeon_encoder *radeon_encoder; + + /* walk the list and link encoders to connectors */ + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + radeon_connector = to_radeon_connector(connector); + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + radeon_encoder = to_radeon_encoder(encoder); + if (radeon_encoder->devices & radeon_connector->devices) + drm_mode_connector_attach_encoder(connector, encoder); + } + } +} + +static struct drm_connector * +radeon_get_connector_for_encoder(struct drm_encoder *encoder) +{ + struct drm_device *dev = encoder->dev; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct drm_connector *connector; + struct radeon_connector *radeon_connector; + + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + radeon_connector = to_radeon_connector(connector); + if (radeon_encoder->devices & radeon_connector->devices) + return connector; + } + return NULL; +} + +/* used for both atom and legacy */ +void radeon_rmx_mode_fixup(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_native_mode *native_mode = &radeon_encoder->native_mode; + + if (mode->hdisplay < native_mode->panel_xres || + mode->vdisplay < native_mode->panel_yres) { + radeon_encoder->flags |= RADEON_USE_RMX; + if (ASIC_IS_AVIVO(rdev)) { + adjusted_mode->hdisplay = native_mode->panel_xres; + adjusted_mode->vdisplay = native_mode->panel_yres; + adjusted_mode->htotal = native_mode->panel_xres + native_mode->hblank; + adjusted_mode->hsync_start = native_mode->panel_xres + native_mode->hoverplus; + adjusted_mode->hsync_end = adjusted_mode->hsync_start + native_mode->hsync_width; + adjusted_mode->vtotal = native_mode->panel_yres + native_mode->vblank; + adjusted_mode->vsync_start = native_mode->panel_yres + native_mode->voverplus; + adjusted_mode->vsync_end = adjusted_mode->vsync_start + native_mode->vsync_width; + /* update crtc values */ + drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V); + /* adjust crtc values */ + adjusted_mode->crtc_hdisplay = native_mode->panel_xres; + adjusted_mode->crtc_vdisplay = native_mode->panel_yres; + adjusted_mode->crtc_htotal = adjusted_mode->crtc_hdisplay + native_mode->hblank; + adjusted_mode->crtc_hsync_start = adjusted_mode->crtc_hdisplay + native_mode->hoverplus; + adjusted_mode->crtc_hsync_end = adjusted_mode->crtc_hsync_start + native_mode->hsync_width; + adjusted_mode->crtc_vtotal = adjusted_mode->crtc_vdisplay + native_mode->vblank; + adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vdisplay + native_mode->voverplus; + adjusted_mode->crtc_vsync_end = adjusted_mode->crtc_vsync_start + native_mode->vsync_width; + } else { + adjusted_mode->htotal = native_mode->panel_xres + native_mode->hblank; + adjusted_mode->hsync_start = native_mode->panel_xres + native_mode->hoverplus; + adjusted_mode->hsync_end = adjusted_mode->hsync_start + native_mode->hsync_width; + adjusted_mode->vtotal = native_mode->panel_yres + native_mode->vblank; + adjusted_mode->vsync_start = native_mode->panel_yres + native_mode->voverplus; + adjusted_mode->vsync_end = adjusted_mode->vsync_start + native_mode->vsync_width; + /* update crtc values */ + drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V); + /* adjust crtc values */ + adjusted_mode->crtc_htotal = adjusted_mode->crtc_hdisplay + native_mode->hblank; + adjusted_mode->crtc_hsync_start = adjusted_mode->crtc_hdisplay + native_mode->hoverplus; + adjusted_mode->crtc_hsync_end = adjusted_mode->crtc_hsync_start + native_mode->hsync_width; + adjusted_mode->crtc_vtotal = adjusted_mode->crtc_vdisplay + native_mode->vblank; + adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vdisplay + native_mode->voverplus; + adjusted_mode->crtc_vsync_end = adjusted_mode->crtc_vsync_start + native_mode->vsync_width; + } + adjusted_mode->flags = native_mode->flags; + adjusted_mode->clock = native_mode->dotclock; + } +} + +static bool radeon_atom_mode_fixup(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + + radeon_encoder->flags &= ~RADEON_USE_RMX; + + drm_mode_set_crtcinfo(adjusted_mode, 0); + + if (radeon_encoder->rmx_type != RMX_OFF) + radeon_rmx_mode_fixup(encoder, mode, adjusted_mode); + + /* hw bug */ + if ((mode->flags & DRM_MODE_FLAG_INTERLACE) + && (mode->crtc_vsync_start < (mode->crtc_vdisplay + 2))) + adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vdisplay + 2; + + return true; +} + +static void +atombios_dac_setup(struct drm_encoder *encoder, int action) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + DAC_ENCODER_CONTROL_PS_ALLOCATION args; + int index = 0, num = 0; + /* fixme - fill in enc_priv for atom dac */ + enum radeon_tv_std tv_std = TV_STD_NTSC; + + memset(&args, 0, sizeof(args)); + + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_DAC1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: + index = GetIndexIntoMasterTable(COMMAND, DAC1EncoderControl); + num = 1; + break; + case ENCODER_OBJECT_ID_INTERNAL_DAC2: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: + index = GetIndexIntoMasterTable(COMMAND, DAC2EncoderControl); + num = 2; + break; + } + + args.ucAction = action; + + if (radeon_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT)) + args.ucDacStandard = ATOM_DAC1_PS2; + else if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT)) + args.ucDacStandard = ATOM_DAC1_CV; + else { + switch (tv_std) { + case TV_STD_PAL: + case TV_STD_PAL_M: + case TV_STD_SCART_PAL: + case TV_STD_SECAM: + case TV_STD_PAL_CN: + args.ucDacStandard = ATOM_DAC1_PAL; + break; + case TV_STD_NTSC: + case TV_STD_NTSC_J: + case TV_STD_PAL_60: + default: + args.ucDacStandard = ATOM_DAC1_NTSC; + break; + } + } + args.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + +} + +static void +atombios_tv_setup(struct drm_encoder *encoder, int action) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + TV_ENCODER_CONTROL_PS_ALLOCATION args; + int index = 0; + /* fixme - fill in enc_priv for atom dac */ + enum radeon_tv_std tv_std = TV_STD_NTSC; + + memset(&args, 0, sizeof(args)); + + index = GetIndexIntoMasterTable(COMMAND, TVEncoderControl); + + args.sTVEncoder.ucAction = action; + + if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT)) + args.sTVEncoder.ucTvStandard = ATOM_TV_CV; + else { + switch (tv_std) { + case TV_STD_NTSC: + args.sTVEncoder.ucTvStandard = ATOM_TV_NTSC; + break; + case TV_STD_PAL: + args.sTVEncoder.ucTvStandard = ATOM_TV_PAL; + break; + case TV_STD_PAL_M: + args.sTVEncoder.ucTvStandard = ATOM_TV_PALM; + break; + case TV_STD_PAL_60: + args.sTVEncoder.ucTvStandard = ATOM_TV_PAL60; + break; + case TV_STD_NTSC_J: + args.sTVEncoder.ucTvStandard = ATOM_TV_NTSCJ; + break; + case TV_STD_SCART_PAL: + args.sTVEncoder.ucTvStandard = ATOM_TV_PAL; /* ??? */ + break; + case TV_STD_SECAM: + args.sTVEncoder.ucTvStandard = ATOM_TV_SECAM; + break; + case TV_STD_PAL_CN: + args.sTVEncoder.ucTvStandard = ATOM_TV_PALCN; + break; + default: + args.sTVEncoder.ucTvStandard = ATOM_TV_NTSC; + break; + } + } + + args.sTVEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + +} + +void +atombios_external_tmds_setup(struct drm_encoder *encoder, int action) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION args; + int index = 0; + + memset(&args, 0, sizeof(args)); + + index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl); + + args.sXTmdsEncoder.ucEnable = action; + + if (radeon_encoder->pixel_clock > 165000) + args.sXTmdsEncoder.ucMisc = PANEL_ENCODER_MISC_DUAL; + + /*if (pScrn->rgbBits == 8)*/ + args.sXTmdsEncoder.ucMisc |= (1 << 1); + + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + +} + +static void +atombios_ddia_setup(struct drm_encoder *encoder, int action) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + DVO_ENCODER_CONTROL_PS_ALLOCATION args; + int index = 0; + + memset(&args, 0, sizeof(args)); + + index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl); + + args.sDVOEncoder.ucAction = action; + args.sDVOEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + + if (radeon_encoder->pixel_clock > 165000) + args.sDVOEncoder.usDevAttr.sDigAttrib.ucAttribute = PANEL_ENCODER_MISC_DUAL; + + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + +} + +union lvds_encoder_control { + LVDS_ENCODER_CONTROL_PS_ALLOCATION v1; + LVDS_ENCODER_CONTROL_PS_ALLOCATION_V2 v2; +}; + +static void +atombios_digital_setup(struct drm_encoder *encoder, int action) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + union lvds_encoder_control args; + int index = 0; + uint8_t frev, crev; + struct radeon_encoder_atom_dig *dig; + struct drm_connector *connector; + struct radeon_connector *radeon_connector; + struct radeon_connector_atom_dig *dig_connector; + + connector = radeon_get_connector_for_encoder(encoder); + if (!connector) + return; + + radeon_connector = to_radeon_connector(connector); + + if (!radeon_encoder->enc_priv) + return; + + dig = radeon_encoder->enc_priv; + + if (!radeon_connector->con_priv) + return; + + dig_connector = radeon_connector->con_priv; + + memset(&args, 0, sizeof(args)); + + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_LVDS: + index = GetIndexIntoMasterTable(COMMAND, LVDSEncoderControl); + break; + case ENCODER_OBJECT_ID_INTERNAL_TMDS1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: + index = GetIndexIntoMasterTable(COMMAND, TMDS1EncoderControl); + break; + case ENCODER_OBJECT_ID_INTERNAL_LVTM1: + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) + index = GetIndexIntoMasterTable(COMMAND, LVDSEncoderControl); + else + index = GetIndexIntoMasterTable(COMMAND, TMDS2EncoderControl); + break; + } + + atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev); + + switch (frev) { + case 1: + case 2: + switch (crev) { + case 1: + args.v1.ucMisc = 0; + args.v1.ucAction = action; + if (drm_detect_hdmi_monitor((struct edid *)connector->edid_blob_ptr)) + args.v1.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE; + args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { + if (dig->lvds_misc & (1 << 0)) + args.v1.ucMisc |= PANEL_ENCODER_MISC_DUAL; + if (dig->lvds_misc & (1 << 1)) + args.v1.ucMisc |= (1 << 1); + } else { + if (dig_connector->linkb) + args.v1.ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB; + if (radeon_encoder->pixel_clock > 165000) + args.v1.ucMisc |= PANEL_ENCODER_MISC_DUAL; + /*if (pScrn->rgbBits == 8) */ + args.v1.ucMisc |= (1 << 1); + } + break; + case 2: + case 3: + args.v2.ucMisc = 0; + args.v2.ucAction = action; + if (crev == 3) { + if (dig->coherent_mode) + args.v2.ucMisc |= PANEL_ENCODER_MISC_COHERENT; + } + if (drm_detect_hdmi_monitor((struct edid *)connector->edid_blob_ptr)) + args.v2.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE; + args.v2.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + args.v2.ucTruncate = 0; + args.v2.ucSpatial = 0; + args.v2.ucTemporal = 0; + args.v2.ucFRC = 0; + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { + if (dig->lvds_misc & (1 << 0)) + args.v2.ucMisc |= PANEL_ENCODER_MISC_DUAL; + if (dig->lvds_misc & (1 << 5)) { + args.v2.ucSpatial = PANEL_ENCODER_SPATIAL_DITHER_EN; + if (dig->lvds_misc & (1 << 1)) + args.v2.ucSpatial |= PANEL_ENCODER_SPATIAL_DITHER_DEPTH; + } + if (dig->lvds_misc & (1 << 6)) { + args.v2.ucTemporal = PANEL_ENCODER_TEMPORAL_DITHER_EN; + if (dig->lvds_misc & (1 << 1)) + args.v2.ucTemporal |= PANEL_ENCODER_TEMPORAL_DITHER_DEPTH; + if (((dig->lvds_misc >> 2) & 0x3) == 2) + args.v2.ucTemporal |= PANEL_ENCODER_TEMPORAL_LEVEL_4; + } + } else { + if (dig_connector->linkb) + args.v2.ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB; + if (radeon_encoder->pixel_clock > 165000) + args.v2.ucMisc |= PANEL_ENCODER_MISC_DUAL; + } + break; + default: + DRM_ERROR("Unknown table version %d, %d\n", frev, crev); + break; + } + break; + default: + DRM_ERROR("Unknown table version %d, %d\n", frev, crev); + break; + } + + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + +} + +int +atombios_get_encoder_mode(struct drm_encoder *encoder) +{ + struct drm_connector *connector; + struct radeon_connector *radeon_connector; + + connector = radeon_get_connector_for_encoder(encoder); + if (!connector) + return 0; + + radeon_connector = to_radeon_connector(connector); + + switch (connector->connector_type) { + case DRM_MODE_CONNECTOR_DVII: + if (drm_detect_hdmi_monitor((struct edid *)connector->edid_blob_ptr)) + return ATOM_ENCODER_MODE_HDMI; + else if (radeon_connector->use_digital) + return ATOM_ENCODER_MODE_DVI; + else + return ATOM_ENCODER_MODE_CRT; + break; + case DRM_MODE_CONNECTOR_DVID: + case DRM_MODE_CONNECTOR_HDMIA: + case DRM_MODE_CONNECTOR_HDMIB: + default: + if (drm_detect_hdmi_monitor((struct edid *)connector->edid_blob_ptr)) + return ATOM_ENCODER_MODE_HDMI; + else + return ATOM_ENCODER_MODE_DVI; + break; + case DRM_MODE_CONNECTOR_LVDS: + return ATOM_ENCODER_MODE_LVDS; + break; + case DRM_MODE_CONNECTOR_DisplayPort: + /*if (radeon_output->MonType == MT_DP) + return ATOM_ENCODER_MODE_DP; + else*/ + if (drm_detect_hdmi_monitor((struct edid *)connector->edid_blob_ptr)) + return ATOM_ENCODER_MODE_HDMI; + else + return ATOM_ENCODER_MODE_DVI; + break; + case CONNECTOR_DVI_A: + case CONNECTOR_VGA: + return ATOM_ENCODER_MODE_CRT; + break; + case CONNECTOR_STV: + case CONNECTOR_CTV: + case CONNECTOR_DIN: + /* fix me */ + return ATOM_ENCODER_MODE_TV; + /*return ATOM_ENCODER_MODE_CV;*/ + break; + } +} + +static void +atombios_dig_encoder_setup(struct drm_encoder *encoder, int action) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + DIG_ENCODER_CONTROL_PS_ALLOCATION args; + int index = 0, num = 0; + uint8_t frev, crev; + struct radeon_encoder_atom_dig *dig; + struct drm_connector *connector; + struct radeon_connector *radeon_connector; + struct radeon_connector_atom_dig *dig_connector; + + connector = radeon_get_connector_for_encoder(encoder); + if (!connector) + return; + + radeon_connector = to_radeon_connector(connector); + + if (!radeon_connector->con_priv) + return; + + dig_connector = radeon_connector->con_priv; + + if (!radeon_encoder->enc_priv) + return; + + dig = radeon_encoder->enc_priv; + + memset(&args, 0, sizeof(args)); + + if (ASIC_IS_DCE32(rdev)) { + if (dig->dig_block) + index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl); + else + index = GetIndexIntoMasterTable(COMMAND, DIG1EncoderControl); + num = dig->dig_block + 1; + } else { + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + index = GetIndexIntoMasterTable(COMMAND, DIG1EncoderControl); + num = 1; + break; + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: + index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl); + num = 2; + break; + } + } + + atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev); + + args.ucAction = action; + args.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + + if (ASIC_IS_DCE32(rdev)) { + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + args.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER1; + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: + args.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER2; + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: + args.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER3; + break; + } + } else { + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + args.ucConfig = ATOM_ENCODER_CONFIG_TRANSMITTER1; + break; + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: + args.ucConfig = ATOM_ENCODER_CONFIG_TRANSMITTER2; + break; + } + } + + if (radeon_encoder->pixel_clock > 165000) { + args.ucConfig |= ATOM_ENCODER_CONFIG_LINKA_B; + args.ucLaneNum = 8; + } else { + if (dig_connector->linkb) + args.ucConfig |= ATOM_ENCODER_CONFIG_LINKB; + else + args.ucConfig |= ATOM_ENCODER_CONFIG_LINKA; + args.ucLaneNum = 4; + } + + args.ucEncoderMode = atombios_get_encoder_mode(encoder); + + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + +} + +union dig_transmitter_control { + DIG_TRANSMITTER_CONTROL_PS_ALLOCATION v1; + DIG_TRANSMITTER_CONTROL_PARAMETERS_V2 v2; +}; + +static void +atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + union dig_transmitter_control args; + int index = 0, num = 0; + uint8_t frev, crev; + struct radeon_encoder_atom_dig *dig; + struct drm_connector *connector; + struct radeon_connector *radeon_connector; + struct radeon_connector_atom_dig *dig_connector; + + connector = radeon_get_connector_for_encoder(encoder); + if (!connector) + return; + + radeon_connector = to_radeon_connector(connector); + + if (!radeon_encoder->enc_priv) + return; + + dig = radeon_encoder->enc_priv; + + if (!radeon_connector->con_priv) + return; + + dig_connector = radeon_connector->con_priv; + + memset(&args, 0, sizeof(args)); + + if (ASIC_IS_DCE32(rdev)) + index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl); + else { + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + index = GetIndexIntoMasterTable(COMMAND, DIG1TransmitterControl); + break; + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: + index = GetIndexIntoMasterTable(COMMAND, DIG2TransmitterControl); + break; + } + } + + atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev); + + args.v1.ucAction = action; + + if (ASIC_IS_DCE32(rdev)) { + if (radeon_encoder->pixel_clock > 165000) { + args.v2.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock * 10 * 2) / 100); + args.v2.acConfig.fDualLinkConnector = 1; + } else { + args.v2.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock * 10 * 4) / 100); + } + if (dig->dig_block) + args.v2.acConfig.ucEncoderSel = 1; + + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + args.v2.acConfig.ucTransmitterSel = 0; + num = 0; + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: + args.v2.acConfig.ucTransmitterSel = 1; + num = 1; + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: + args.v2.acConfig.ucTransmitterSel = 2; + num = 2; + break; + } + + if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { + if (dig->coherent_mode) + args.v2.acConfig.fCoherentMode = 1; + } + } else { + args.v1.ucConfig = ATOM_TRANSMITTER_CONFIG_CLKSRC_PPLL; + args.v1.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock) / 10); + + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER; + if (rdev->flags & RADEON_IS_IGP) { + if (radeon_encoder->pixel_clock > 165000) { + args.v1.ucConfig |= (ATOM_TRANSMITTER_CONFIG_8LANE_LINK | + ATOM_TRANSMITTER_CONFIG_LINKA_B); + if (dig_connector->igp_lane_info & 0x3) + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_7; + else if (dig_connector->igp_lane_info & 0xc) + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_8_15; + } else { + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA; + if (dig_connector->igp_lane_info & 0x1) + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_3; + else if (dig_connector->igp_lane_info & 0x2) + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_4_7; + else if (dig_connector->igp_lane_info & 0x4) + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_8_11; + else if (dig_connector->igp_lane_info & 0x8) + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_12_15; + } + } else { + if (radeon_encoder->pixel_clock > 165000) + args.v1.ucConfig |= (ATOM_TRANSMITTER_CONFIG_8LANE_LINK | + ATOM_TRANSMITTER_CONFIG_LINKA_B | + ATOM_TRANSMITTER_CONFIG_LANE_0_7); + else { + if (dig_connector->linkb) + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKB | ATOM_TRANSMITTER_CONFIG_LANE_0_3; + else + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA | ATOM_TRANSMITTER_CONFIG_LANE_0_3; + } + } + break; + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER; + if (radeon_encoder->pixel_clock > 165000) + args.v1.ucConfig |= (ATOM_TRANSMITTER_CONFIG_8LANE_LINK | + ATOM_TRANSMITTER_CONFIG_LINKA_B | + ATOM_TRANSMITTER_CONFIG_LANE_0_7); + else { + if (dig_connector->linkb) + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKB | ATOM_TRANSMITTER_CONFIG_LANE_0_3; + else + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA | ATOM_TRANSMITTER_CONFIG_LANE_0_3; + } + break; + } + + if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { + if (dig->coherent_mode) + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_COHERENT; + } + } + + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + +} + +static void atom_rv515_force_tv_scaler(struct radeon_device *rdev) +{ + + WREG32(0x659C, 0x0); + WREG32(0x6594, 0x705); + WREG32(0x65A4, 0x10001); + WREG32(0x65D8, 0x0); + WREG32(0x65B0, 0x0); + WREG32(0x65C0, 0x0); + WREG32(0x65D4, 0x0); + WREG32(0x6578, 0x0); + WREG32(0x657C, 0x841880A8); + WREG32(0x6578, 0x1); + WREG32(0x657C, 0x84208680); + WREG32(0x6578, 0x2); + WREG32(0x657C, 0xBFF880B0); + WREG32(0x6578, 0x100); + WREG32(0x657C, 0x83D88088); + WREG32(0x6578, 0x101); + WREG32(0x657C, 0x84608680); + WREG32(0x6578, 0x102); + WREG32(0x657C, 0xBFF080D0); + WREG32(0x6578, 0x200); + WREG32(0x657C, 0x83988068); + WREG32(0x6578, 0x201); + WREG32(0x657C, 0x84A08680); + WREG32(0x6578, 0x202); + WREG32(0x657C, 0xBFF080F8); + WREG32(0x6578, 0x300); + WREG32(0x657C, 0x83588058); + WREG32(0x6578, 0x301); + WREG32(0x657C, 0x84E08660); + WREG32(0x6578, 0x302); + WREG32(0x657C, 0xBFF88120); + WREG32(0x6578, 0x400); + WREG32(0x657C, 0x83188040); + WREG32(0x6578, 0x401); + WREG32(0x657C, 0x85008660); + WREG32(0x6578, 0x402); + WREG32(0x657C, 0xBFF88150); + WREG32(0x6578, 0x500); + WREG32(0x657C, 0x82D88030); + WREG32(0x6578, 0x501); + WREG32(0x657C, 0x85408640); + WREG32(0x6578, 0x502); + WREG32(0x657C, 0xBFF88180); + WREG32(0x6578, 0x600); + WREG32(0x657C, 0x82A08018); + WREG32(0x6578, 0x601); + WREG32(0x657C, 0x85808620); + WREG32(0x6578, 0x602); + WREG32(0x657C, 0xBFF081B8); + WREG32(0x6578, 0x700); + WREG32(0x657C, 0x82608010); + WREG32(0x6578, 0x701); + WREG32(0x657C, 0x85A08600); + WREG32(0x6578, 0x702); + WREG32(0x657C, 0x800081F0); + WREG32(0x6578, 0x800); + WREG32(0x657C, 0x8228BFF8); + WREG32(0x6578, 0x801); + WREG32(0x657C, 0x85E085E0); + WREG32(0x6578, 0x802); + WREG32(0x657C, 0xBFF88228); + WREG32(0x6578, 0x10000); + WREG32(0x657C, 0x82A8BF00); + WREG32(0x6578, 0x10001); + WREG32(0x657C, 0x82A08CC0); + WREG32(0x6578, 0x10002); + WREG32(0x657C, 0x8008BEF8); + WREG32(0x6578, 0x10100); + WREG32(0x657C, 0x81F0BF28); + WREG32(0x6578, 0x10101); + WREG32(0x657C, 0x83608CA0); + WREG32(0x6578, 0x10102); + WREG32(0x657C, 0x8018BED0); + WREG32(0x6578, 0x10200); + WREG32(0x657C, 0x8148BF38); + WREG32(0x6578, 0x10201); + WREG32(0x657C, 0x84408C80); + WREG32(0x6578, 0x10202); + WREG32(0x657C, 0x8008BEB8); + WREG32(0x6578, 0x10300); + WREG32(0x657C, 0x80B0BF78); + WREG32(0x6578, 0x10301); + WREG32(0x657C, 0x85008C20); + WREG32(0x6578, 0x10302); + WREG32(0x657C, 0x8020BEA0); + WREG32(0x6578, 0x10400); + WREG32(0x657C, 0x8028BF90); + WREG32(0x6578, 0x10401); + WREG32(0x657C, 0x85E08BC0); + WREG32(0x6578, 0x10402); + WREG32(0x657C, 0x8018BE90); + WREG32(0x6578, 0x10500); + WREG32(0x657C, 0xBFB8BFB0); + WREG32(0x6578, 0x10501); + WREG32(0x657C, 0x86C08B40); + WREG32(0x6578, 0x10502); + WREG32(0x657C, 0x8010BE90); + WREG32(0x6578, 0x10600); + WREG32(0x657C, 0xBF58BFC8); + WREG32(0x6578, 0x10601); + WREG32(0x657C, 0x87A08AA0); + WREG32(0x6578, 0x10602); + WREG32(0x657C, 0x8010BE98); + WREG32(0x6578, 0x10700); + WREG32(0x657C, 0xBF10BFF0); + WREG32(0x6578, 0x10701); + WREG32(0x657C, 0x886089E0); + WREG32(0x6578, 0x10702); + WREG32(0x657C, 0x8018BEB0); + WREG32(0x6578, 0x10800); + WREG32(0x657C, 0xBED8BFE8); + WREG32(0x6578, 0x10801); + WREG32(0x657C, 0x89408940); + WREG32(0x6578, 0x10802); + WREG32(0x657C, 0xBFE8BED8); + WREG32(0x6578, 0x20000); + WREG32(0x657C, 0x80008000); + WREG32(0x6578, 0x20001); + WREG32(0x657C, 0x90008000); + WREG32(0x6578, 0x20002); + WREG32(0x657C, 0x80008000); + WREG32(0x6578, 0x20003); + WREG32(0x657C, 0x80008000); + WREG32(0x6578, 0x20100); + WREG32(0x657C, 0x80108000); + WREG32(0x6578, 0x20101); + WREG32(0x657C, 0x8FE0BF70); + WREG32(0x6578, 0x20102); + WREG32(0x657C, 0xBFE880C0); + WREG32(0x6578, 0x20103); + WREG32(0x657C, 0x80008000); + WREG32(0x6578, 0x20200); + WREG32(0x657C, 0x8018BFF8); + WREG32(0x6578, 0x20201); + WREG32(0x657C, 0x8F80BF08); + WREG32(0x6578, 0x20202); + WREG32(0x657C, 0xBFD081A0); + WREG32(0x6578, 0x20203); + WREG32(0x657C, 0xBFF88000); + WREG32(0x6578, 0x20300); + WREG32(0x657C, 0x80188000); + WREG32(0x6578, 0x20301); + WREG32(0x657C, 0x8EE0BEC0); + WREG32(0x6578, 0x20302); + WREG32(0x657C, 0xBFB082A0); + WREG32(0x6578, 0x20303); + WREG32(0x657C, 0x80008000); + WREG32(0x6578, 0x20400); + WREG32(0x657C, 0x80188000); + WREG32(0x6578, 0x20401); + WREG32(0x657C, 0x8E00BEA0); + WREG32(0x6578, 0x20402); + WREG32(0x657C, 0xBF8883C0); + WREG32(0x6578, 0x20403); + WREG32(0x657C, 0x80008000); + WREG32(0x6578, 0x20500); + WREG32(0x657C, 0x80188000); + WREG32(0x6578, 0x20501); + WREG32(0x657C, 0x8D00BE90); + WREG32(0x6578, 0x20502); + WREG32(0x657C, 0xBF588500); + WREG32(0x6578, 0x20503); + WREG32(0x657C, 0x80008008); + WREG32(0x6578, 0x20600); + WREG32(0x657C, 0x80188000); + WREG32(0x6578, 0x20601); + WREG32(0x657C, 0x8BC0BE98); + WREG32(0x6578, 0x20602); + WREG32(0x657C, 0xBF308660); + WREG32(0x6578, 0x20603); + WREG32(0x657C, 0x80008008); + WREG32(0x6578, 0x20700); + WREG32(0x657C, 0x80108000); + WREG32(0x6578, 0x20701); + WREG32(0x657C, 0x8A80BEB0); + WREG32(0x6578, 0x20702); + WREG32(0x657C, 0xBF0087C0); + WREG32(0x6578, 0x20703); + WREG32(0x657C, 0x80008008); + WREG32(0x6578, 0x20800); + WREG32(0x657C, 0x80108000); + WREG32(0x6578, 0x20801); + WREG32(0x657C, 0x8920BED0); + WREG32(0x6578, 0x20802); + WREG32(0x657C, 0xBED08920); + WREG32(0x6578, 0x20803); + WREG32(0x657C, 0x80008010); + WREG32(0x6578, 0x30000); + WREG32(0x657C, 0x90008000); + WREG32(0x6578, 0x30001); + WREG32(0x657C, 0x80008000); + WREG32(0x6578, 0x30100); + WREG32(0x657C, 0x8FE0BF90); + WREG32(0x6578, 0x30101); + WREG32(0x657C, 0xBFF880A0); + WREG32(0x6578, 0x30200); + WREG32(0x657C, 0x8F60BF40); + WREG32(0x6578, 0x30201); + WREG32(0x657C, 0xBFE88180); + WREG32(0x6578, 0x30300); + WREG32(0x657C, 0x8EC0BF00); + WREG32(0x6578, 0x30301); + WREG32(0x657C, 0xBFC88280); + WREG32(0x6578, 0x30400); + WREG32(0x657C, 0x8DE0BEE0); + WREG32(0x6578, 0x30401); + WREG32(0x657C, 0xBFA083A0); + WREG32(0x6578, 0x30500); + WREG32(0x657C, 0x8CE0BED0); + WREG32(0x6578, 0x30501); + WREG32(0x657C, 0xBF7884E0); + WREG32(0x6578, 0x30600); + WREG32(0x657C, 0x8BA0BED8); + WREG32(0x6578, 0x30601); + WREG32(0x657C, 0xBF508640); + WREG32(0x6578, 0x30700); + WREG32(0x657C, 0x8A60BEE8); + WREG32(0x6578, 0x30701); + WREG32(0x657C, 0xBF2087A0); + WREG32(0x6578, 0x30800); + WREG32(0x657C, 0x8900BF00); + WREG32(0x6578, 0x30801); + WREG32(0x657C, 0xBF008900); +} + +static void +atombios_yuv_setup(struct drm_encoder *encoder, bool enable) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + ENABLE_YUV_PS_ALLOCATION args; + int index = GetIndexIntoMasterTable(COMMAND, EnableYUV); + uint32_t temp, reg; + + memset(&args, 0, sizeof(args)); + + if (rdev->family >= CHIP_R600) + reg = R600_BIOS_3_SCRATCH; + else + reg = RADEON_BIOS_3_SCRATCH; + + /* XXX: fix up scratch reg handling */ + temp = RREG32(reg); + if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT)) + WREG32(reg, (ATOM_S3_TV1_ACTIVE | + (radeon_crtc->crtc_id << 18))); + else if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT)) + WREG32(reg, (ATOM_S3_CV_ACTIVE | (radeon_crtc->crtc_id << 24))); + else + WREG32(reg, 0); + + if (enable) + args.ucEnable = ATOM_ENABLE; + args.ucCRTC = radeon_crtc->crtc_id; + + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + + WREG32(reg, temp); +} + +static void +atombios_overscan_setup(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + SET_CRTC_OVERSCAN_PS_ALLOCATION args; + int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_OverScan); + + memset(&args, 0, sizeof(args)); + + args.usOverscanRight = 0; + args.usOverscanLeft = 0; + args.usOverscanBottom = 0; + args.usOverscanTop = 0; + args.ucCRTC = radeon_crtc->crtc_id; + + if (radeon_encoder->flags & RADEON_USE_RMX) { + if (radeon_encoder->rmx_type == RMX_FULL) { + args.usOverscanRight = 0; + args.usOverscanLeft = 0; + args.usOverscanBottom = 0; + args.usOverscanTop = 0; + } else if (radeon_encoder->rmx_type == RMX_CENTER) { + args.usOverscanTop = (adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2; + args.usOverscanBottom = (adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2; + args.usOverscanLeft = (adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2; + args.usOverscanRight = (adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2; + } else if (radeon_encoder->rmx_type == RMX_ASPECT) { + int a1 = mode->crtc_vdisplay * adjusted_mode->crtc_hdisplay; + int a2 = adjusted_mode->crtc_vdisplay * mode->crtc_hdisplay; + + if (a1 > a2) { + args.usOverscanLeft = (adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2; + args.usOverscanRight = (adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2; + } else if (a2 > a1) { + args.usOverscanLeft = (adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2; + args.usOverscanRight = (adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2; + } + } + } + + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + +} + +static void +atombios_scaler_setup(struct drm_encoder *encoder) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + ENABLE_SCALER_PS_ALLOCATION args; + int index = GetIndexIntoMasterTable(COMMAND, EnableScaler); + /* fixme - fill in enc_priv for atom dac */ + enum radeon_tv_std tv_std = TV_STD_NTSC; + + if (!ASIC_IS_AVIVO(rdev) && radeon_crtc->crtc_id) + return; + + memset(&args, 0, sizeof(args)); + + args.ucScaler = radeon_crtc->crtc_id; + + if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT)) { + switch (tv_std) { + case TV_STD_NTSC: + default: + args.ucTVStandard = ATOM_TV_NTSC; + break; + case TV_STD_PAL: + args.ucTVStandard = ATOM_TV_PAL; + break; + case TV_STD_PAL_M: + args.ucTVStandard = ATOM_TV_PALM; + break; + case TV_STD_PAL_60: + args.ucTVStandard = ATOM_TV_PAL60; + break; + case TV_STD_NTSC_J: + args.ucTVStandard = ATOM_TV_NTSCJ; + break; + case TV_STD_SCART_PAL: + args.ucTVStandard = ATOM_TV_PAL; /* ??? */ + break; + case TV_STD_SECAM: + args.ucTVStandard = ATOM_TV_SECAM; + break; + case TV_STD_PAL_CN: + args.ucTVStandard = ATOM_TV_PALCN; + break; + } + args.ucEnable = SCALER_ENABLE_MULTITAP_MODE; + } else if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT)) { + args.ucTVStandard = ATOM_TV_CV; + args.ucEnable = SCALER_ENABLE_MULTITAP_MODE; + } else if (radeon_encoder->flags & RADEON_USE_RMX) { + if (radeon_encoder->rmx_type == RMX_FULL) + args.ucEnable = ATOM_SCALER_EXPANSION; + else if (radeon_encoder->rmx_type == RMX_CENTER) + args.ucEnable = ATOM_SCALER_CENTER; + else if (radeon_encoder->rmx_type == RMX_ASPECT) + args.ucEnable = ATOM_SCALER_EXPANSION; + } else { + if (ASIC_IS_AVIVO(rdev)) + args.ucEnable = ATOM_SCALER_DISABLE; + else + args.ucEnable = ATOM_SCALER_CENTER; + } + + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + + if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT | ATOM_DEVICE_TV_SUPPORT) + && rdev->family >= CHIP_RV515 && rdev->family <= CHIP_RV570) { + atom_rv515_force_tv_scaler(rdev); + } + +} + +static void +radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION args; + int index = 0; + bool is_dig = false; + + memset(&args, 0, sizeof(args)); + + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_TMDS1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: + index = GetIndexIntoMasterTable(COMMAND, TMDSAOutputControl); + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: + is_dig = true; + break; + case ENCODER_OBJECT_ID_INTERNAL_DVO1: + case ENCODER_OBJECT_ID_INTERNAL_DDI: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: + index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl); + break; + case ENCODER_OBJECT_ID_INTERNAL_LVDS: + index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl); + break; + case ENCODER_OBJECT_ID_INTERNAL_LVTM1: + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) + index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl); + else + index = GetIndexIntoMasterTable(COMMAND, LVTMAOutputControl); + break; + case ENCODER_OBJECT_ID_INTERNAL_DAC1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: + if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT)) + index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl); + else if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT)) + index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl); + else + index = GetIndexIntoMasterTable(COMMAND, DAC1OutputControl); + break; + case ENCODER_OBJECT_ID_INTERNAL_DAC2: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: + if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT)) + index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl); + else if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT)) + index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl); + else + index = GetIndexIntoMasterTable(COMMAND, DAC2OutputControl); + break; + } + + if (is_dig) { + switch (mode) { + case DRM_MODE_DPMS_ON: + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE); + break; + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE); + break; + } + } else { + switch (mode) { + case DRM_MODE_DPMS_ON: + args.ucAction = ATOM_ENABLE; + break; + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + args.ucAction = ATOM_DISABLE; + break; + } + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + } + radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); +} + +union crtc_sourc_param { + SELECT_CRTC_SOURCE_PS_ALLOCATION v1; + SELECT_CRTC_SOURCE_PARAMETERS_V2 v2; +}; + +static void +atombios_set_encoder_crtc_source(struct drm_encoder *encoder) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + union crtc_sourc_param args; + int index = GetIndexIntoMasterTable(COMMAND, SelectCRTC_Source); + uint8_t frev, crev; + + memset(&args, 0, sizeof(args)); + + atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev); + + switch (frev) { + case 1: + switch (crev) { + case 1: + default: + if (ASIC_IS_AVIVO(rdev)) + args.v1.ucCRTC = radeon_crtc->crtc_id; + else { + if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) { + args.v1.ucCRTC = radeon_crtc->crtc_id; + } else { + args.v1.ucCRTC = radeon_crtc->crtc_id << 2; + } + } + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_TMDS1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: + args.v1.ucDevice = ATOM_DEVICE_DFP1_INDEX; + break; + case ENCODER_OBJECT_ID_INTERNAL_LVDS: + case ENCODER_OBJECT_ID_INTERNAL_LVTM1: + if (radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) + args.v1.ucDevice = ATOM_DEVICE_LCD1_INDEX; + else + args.v1.ucDevice = ATOM_DEVICE_DFP3_INDEX; + break; + case ENCODER_OBJECT_ID_INTERNAL_DVO1: + case ENCODER_OBJECT_ID_INTERNAL_DDI: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: + args.v1.ucDevice = ATOM_DEVICE_DFP2_INDEX; + break; + case ENCODER_OBJECT_ID_INTERNAL_DAC1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: + if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT)) + args.v1.ucDevice = ATOM_DEVICE_TV1_INDEX; + else if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT)) + args.v1.ucDevice = ATOM_DEVICE_CV_INDEX; + else + args.v1.ucDevice = ATOM_DEVICE_CRT1_INDEX; + break; + case ENCODER_OBJECT_ID_INTERNAL_DAC2: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: + if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT)) + args.v1.ucDevice = ATOM_DEVICE_TV1_INDEX; + else if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT)) + args.v1.ucDevice = ATOM_DEVICE_CV_INDEX; + else + args.v1.ucDevice = ATOM_DEVICE_CRT2_INDEX; + break; + } + break; + case 2: + args.v2.ucCRTC = radeon_crtc->crtc_id; + args.v2.ucEncodeMode = atombios_get_encoder_mode(encoder); + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: + if (ASIC_IS_DCE32(rdev)) { + if (radeon_crtc->crtc_id) + args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID; + else + args.v2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID; + } else + args.v2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID; + break; + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: + args.v2.ucEncoderID = ASIC_INT_DVO_ENCODER_ID; + break; + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: + args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID; + break; + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: + if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT)) + args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; + else if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT)) + args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; + else + args.v2.ucEncoderID = ASIC_INT_DAC1_ENCODER_ID; + break; + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: + if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT)) + args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; + else if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT)) + args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; + else + args.v2.ucEncoderID = ASIC_INT_DAC2_ENCODER_ID; + break; + } + break; + } + break; + default: + DRM_ERROR("Unknown table version: %d, %d\n", frev, crev); + break; + } + + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + +} + +static void +atombios_apply_encoder_quirks(struct drm_encoder *encoder, + struct drm_display_mode *mode) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + + /* Funky macbooks */ + if ((dev->pdev->device == 0x71C5) && + (dev->pdev->subsystem_vendor == 0x106b) && + (dev->pdev->subsystem_device == 0x0080)) { + if (radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) { + uint32_t lvtma_bit_depth_control = RREG32(AVIVO_LVTMA_BIT_DEPTH_CONTROL); + + lvtma_bit_depth_control &= ~AVIVO_LVTMA_BIT_DEPTH_CONTROL_TRUNCATE_EN; + lvtma_bit_depth_control &= ~AVIVO_LVTMA_BIT_DEPTH_CONTROL_SPATIAL_DITHER_EN; + + WREG32(AVIVO_LVTMA_BIT_DEPTH_CONTROL, lvtma_bit_depth_control); + } + } + + /* set scaler clears this on some chips */ + if (ASIC_IS_AVIVO(rdev) && (mode->flags & DRM_MODE_FLAG_INTERLACE)) + WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, AVIVO_D1MODE_INTERLEAVE_EN); +} + +static void +radeon_atom_encoder_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + + if (radeon_encoder->enc_priv) { + struct radeon_encoder_atom_dig *dig; + + dig = radeon_encoder->enc_priv; + dig->dig_block = radeon_crtc->crtc_id; + } + radeon_encoder->pixel_clock = adjusted_mode->clock; + + radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); + atombios_overscan_setup(encoder, mode, adjusted_mode); + atombios_scaler_setup(encoder); + atombios_set_encoder_crtc_source(encoder); + + if (ASIC_IS_AVIVO(rdev)) { + if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT | ATOM_DEVICE_TV_SUPPORT)) + atombios_yuv_setup(encoder, true); + else + atombios_yuv_setup(encoder, false); + } + + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_TMDS1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: + case ENCODER_OBJECT_ID_INTERNAL_LVDS: + case ENCODER_OBJECT_ID_INTERNAL_LVTM1: + atombios_digital_setup(encoder, PANEL_ENCODER_ACTION_ENABLE); + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: + /* disable the encoder and transmitter */ + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE); + atombios_dig_encoder_setup(encoder, ATOM_DISABLE); + + /* setup and enable the encoder and transmitter */ + atombios_dig_encoder_setup(encoder, ATOM_ENABLE); + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_SETUP); + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE); + break; + case ENCODER_OBJECT_ID_INTERNAL_DDI: + atombios_ddia_setup(encoder, ATOM_ENABLE); + break; + case ENCODER_OBJECT_ID_INTERNAL_DVO1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: + atombios_external_tmds_setup(encoder, ATOM_ENABLE); + break; + case ENCODER_OBJECT_ID_INTERNAL_DAC1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: + case ENCODER_OBJECT_ID_INTERNAL_DAC2: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: + atombios_dac_setup(encoder, ATOM_ENABLE); + if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) + atombios_tv_setup(encoder, ATOM_ENABLE); + break; + } + atombios_apply_encoder_quirks(encoder, adjusted_mode); +} + +static bool +atombios_dac_load_detect(struct drm_encoder *encoder) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + + if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT | + ATOM_DEVICE_CV_SUPPORT | + ATOM_DEVICE_CRT_SUPPORT)) { + DAC_LOAD_DETECTION_PS_ALLOCATION args; + int index = GetIndexIntoMasterTable(COMMAND, DAC_LoadDetection); + uint8_t frev, crev; + + memset(&args, 0, sizeof(args)); + + atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev); + + args.sDacload.ucMisc = 0; + + if ((radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) || + (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1)) + args.sDacload.ucDacType = ATOM_DAC_A; + else + args.sDacload.ucDacType = ATOM_DAC_B; + + if (radeon_encoder->devices & ATOM_DEVICE_CRT1_SUPPORT) + args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CRT1_SUPPORT); + else if (radeon_encoder->devices & ATOM_DEVICE_CRT2_SUPPORT) + args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CRT2_SUPPORT); + else if (radeon_encoder->devices & ATOM_DEVICE_CV_SUPPORT) { + args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CV_SUPPORT); + if (crev >= 3) + args.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb; + } else if (radeon_encoder->devices & ATOM_DEVICE_TV1_SUPPORT) { + args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_TV1_SUPPORT); + if (crev >= 3) + args.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb; + } + + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + + return true; + } else + return false; +} + +static enum drm_connector_status +radeon_atom_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + uint32_t bios_0_scratch; + + if (!atombios_dac_load_detect(encoder)) { + DRM_DEBUG("detect returned false \n"); + return connector_status_unknown; + } + + if (rdev->family >= CHIP_R600) + bios_0_scratch = RREG32(R600_BIOS_0_SCRATCH); + else + bios_0_scratch = RREG32(RADEON_BIOS_0_SCRATCH); + + DRM_DEBUG("Bios 0 scratch %x\n", bios_0_scratch); + if (radeon_encoder->devices & ATOM_DEVICE_CRT1_SUPPORT) { + if (bios_0_scratch & ATOM_S0_CRT1_MASK) + return connector_status_connected; + } else if (radeon_encoder->devices & ATOM_DEVICE_CRT2_SUPPORT) { + if (bios_0_scratch & ATOM_S0_CRT2_MASK) + return connector_status_connected; + } else if (radeon_encoder->devices & ATOM_DEVICE_CV_SUPPORT) { + if (bios_0_scratch & (ATOM_S0_CV_MASK|ATOM_S0_CV_MASK_A)) + return connector_status_connected; + } else if (radeon_encoder->devices & ATOM_DEVICE_TV1_SUPPORT) { + if (bios_0_scratch & (ATOM_S0_TV1_COMPOSITE | ATOM_S0_TV1_COMPOSITE_A)) + return connector_status_connected; /* CTV */ + else if (bios_0_scratch & (ATOM_S0_TV1_SVIDEO | ATOM_S0_TV1_SVIDEO_A)) + return connector_status_connected; /* STV */ + } + return connector_status_disconnected; +} + +static void radeon_atom_encoder_prepare(struct drm_encoder *encoder) +{ + radeon_atom_output_lock(encoder, true); + radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); +} + +static void radeon_atom_encoder_commit(struct drm_encoder *encoder) +{ + radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_ON); + radeon_atom_output_lock(encoder, false); +} + +static const struct drm_encoder_helper_funcs radeon_atom_dig_helper_funcs = { + .dpms = radeon_atom_encoder_dpms, + .mode_fixup = radeon_atom_mode_fixup, + .prepare = radeon_atom_encoder_prepare, + .mode_set = radeon_atom_encoder_mode_set, + .commit = radeon_atom_encoder_commit, + /* no detect for TMDS/LVDS yet */ +}; + +static const struct drm_encoder_helper_funcs radeon_atom_dac_helper_funcs = { + .dpms = radeon_atom_encoder_dpms, + .mode_fixup = radeon_atom_mode_fixup, + .prepare = radeon_atom_encoder_prepare, + .mode_set = radeon_atom_encoder_mode_set, + .commit = radeon_atom_encoder_commit, + .detect = radeon_atom_dac_detect, +}; + +void radeon_enc_destroy(struct drm_encoder *encoder) +{ + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + kfree(radeon_encoder->enc_priv); + drm_encoder_cleanup(encoder); + kfree(radeon_encoder); +} + +static const struct drm_encoder_funcs radeon_atom_enc_funcs = { + .destroy = radeon_enc_destroy, +}; + +struct radeon_encoder_atom_dig * +radeon_atombios_set_dig_info(struct radeon_encoder *radeon_encoder) +{ + struct radeon_encoder_atom_dig *dig = kzalloc(sizeof(struct radeon_encoder_atom_dig), GFP_KERNEL); + + if (!dig) + return NULL; + + /* coherent mode by default */ + dig->coherent_mode = true; + + return dig; +} + +void +radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_id, uint32_t supported_device) +{ + struct drm_encoder *encoder; + struct radeon_encoder *radeon_encoder; + + /* see if we already added it */ + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + radeon_encoder = to_radeon_encoder(encoder); + if (radeon_encoder->encoder_id == encoder_id) { + radeon_encoder->devices |= supported_device; + return; + } + + } + + /* add a new one */ + radeon_encoder = kzalloc(sizeof(struct radeon_encoder), GFP_KERNEL); + if (!radeon_encoder) + return; + + encoder = &radeon_encoder->base; + encoder->possible_crtcs = 0x3; + encoder->possible_clones = 0; + + radeon_encoder->enc_priv = NULL; + + radeon_encoder->encoder_id = encoder_id; + radeon_encoder->devices = supported_device; + + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_LVDS: + case ENCODER_OBJECT_ID_INTERNAL_TMDS1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: + case ENCODER_OBJECT_ID_INTERNAL_LVTM1: + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { + radeon_encoder->rmx_type = RMX_FULL; + drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_LVDS); + radeon_encoder->enc_priv = radeon_atombios_get_lvds_info(radeon_encoder); + } else { + drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TMDS); + radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder); + } + drm_encoder_helper_add(encoder, &radeon_atom_dig_helper_funcs); + break; + case ENCODER_OBJECT_ID_INTERNAL_DAC1: + drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_DAC); + drm_encoder_helper_add(encoder, &radeon_atom_dac_helper_funcs); + break; + case ENCODER_OBJECT_ID_INTERNAL_DAC2: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: + drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TVDAC); + drm_encoder_helper_add(encoder, &radeon_atom_dac_helper_funcs); + break; + case ENCODER_OBJECT_ID_INTERNAL_DVO1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: + case ENCODER_OBJECT_ID_INTERNAL_DDI: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: + drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TMDS); + radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder); + drm_encoder_helper_add(encoder, &radeon_atom_dig_helper_funcs); + break; + } +} diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c new file mode 100644 index 000000000000..fa86d398945e --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_fb.c @@ -0,0 +1,825 @@ +/* + * Copyright © 2007 David Airlie + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * David Airlie + */ + /* + * Modularization + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "drmP.h" +#include "drm.h" +#include "drm_crtc.h" +#include "drm_crtc_helper.h" +#include "radeon_drm.h" +#include "radeon.h" + +struct radeon_fb_device { + struct radeon_device *rdev; + struct drm_display_mode *mode; + struct radeon_framebuffer *rfb; + int crtc_count; + /* crtc currently bound to this */ + uint32_t crtc_ids[2]; +}; + +static int radeonfb_setcolreg(unsigned regno, + unsigned red, + unsigned green, + unsigned blue, + unsigned transp, + struct fb_info *info) +{ + struct radeon_fb_device *rfbdev = info->par; + struct drm_device *dev = rfbdev->rdev->ddev; + struct drm_crtc *crtc; + int i; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_mode_set *modeset = &radeon_crtc->mode_set; + struct drm_framebuffer *fb = modeset->fb; + + for (i = 0; i < rfbdev->crtc_count; i++) { + if (crtc->base.id == rfbdev->crtc_ids[i]) { + break; + } + } + if (i == rfbdev->crtc_count) { + continue; + } + if (regno > 255) { + return 1; + } + if (fb->depth == 8) { + radeon_crtc_fb_gamma_set(crtc, red, green, blue, regno); + return 0; + } + + if (regno < 16) { + switch (fb->depth) { + case 15: + fb->pseudo_palette[regno] = ((red & 0xf800) >> 1) | + ((green & 0xf800) >> 6) | + ((blue & 0xf800) >> 11); + break; + case 16: + fb->pseudo_palette[regno] = (red & 0xf800) | + ((green & 0xfc00) >> 5) | + ((blue & 0xf800) >> 11); + break; + case 24: + case 32: + fb->pseudo_palette[regno] = ((red & 0xff00) << 8) | + (green & 0xff00) | + ((blue & 0xff00) >> 8); + break; + } + } + } + return 0; +} + +static int radeonfb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct radeon_fb_device *rfbdev = info->par; + struct radeon_framebuffer *rfb = rfbdev->rfb; + struct drm_framebuffer *fb = &rfb->base; + int depth; + + if (var->pixclock == -1 || !var->pixclock) { + return -EINVAL; + } + /* Need to resize the fb object !!! */ + if (var->xres > fb->width || var->yres > fb->height) { + DRM_ERROR("Requested width/height is greater than current fb " + "object %dx%d > %dx%d\n", var->xres, var->yres, + fb->width, fb->height); + DRM_ERROR("Need resizing code.\n"); + return -EINVAL; + } + + switch (var->bits_per_pixel) { + case 16: + depth = (var->green.length == 6) ? 16 : 15; + break; + case 32: + depth = (var->transp.length > 0) ? 32 : 24; + break; + default: + depth = var->bits_per_pixel; + break; + } + + switch (depth) { + case 8: + var->red.offset = 0; + var->green.offset = 0; + var->blue.offset = 0; + var->red.length = 8; + var->green.length = 8; + var->blue.length = 8; + var->transp.length = 0; + var->transp.offset = 0; + break; + case 15: + var->red.offset = 10; + var->green.offset = 5; + var->blue.offset = 0; + var->red.length = 5; + var->green.length = 5; + var->blue.length = 5; + var->transp.length = 1; + var->transp.offset = 15; + break; + case 16: + var->red.offset = 11; + var->green.offset = 5; + var->blue.offset = 0; + var->red.length = 5; + var->green.length = 6; + var->blue.length = 5; + var->transp.length = 0; + var->transp.offset = 0; + break; + case 24: + var->red.offset = 16; + var->green.offset = 8; + var->blue.offset = 0; + var->red.length = 8; + var->green.length = 8; + var->blue.length = 8; + var->transp.length = 0; + var->transp.offset = 0; + break; + case 32: + var->red.offset = 16; + var->green.offset = 8; + var->blue.offset = 0; + var->red.length = 8; + var->green.length = 8; + var->blue.length = 8; + var->transp.length = 8; + var->transp.offset = 24; + break; + default: + return -EINVAL; + } + return 0; +} + +/* this will let fbcon do the mode init */ +static int radeonfb_set_par(struct fb_info *info) +{ + struct radeon_fb_device *rfbdev = info->par; + struct drm_device *dev = rfbdev->rdev->ddev; + struct fb_var_screeninfo *var = &info->var; + struct drm_crtc *crtc; + int ret; + int i; + + if (var->pixclock != -1) { + DRM_ERROR("PIXEL CLCOK SET\n"); + return -EINVAL; + } + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + + for (i = 0; i < rfbdev->crtc_count; i++) { + if (crtc->base.id == rfbdev->crtc_ids[i]) { + break; + } + } + if (i == rfbdev->crtc_count) { + continue; + } + if (crtc->fb == radeon_crtc->mode_set.fb) { + mutex_lock(&dev->mode_config.mutex); + ret = crtc->funcs->set_config(&radeon_crtc->mode_set); + mutex_unlock(&dev->mode_config.mutex); + if (ret) { + return ret; + } + } + } + return 0; +} + +static int radeonfb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct radeon_fb_device *rfbdev = info->par; + struct drm_device *dev = rfbdev->rdev->ddev; + struct drm_mode_set *modeset; + struct drm_crtc *crtc; + struct radeon_crtc *radeon_crtc; + int ret = 0; + int i; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + for (i = 0; i < rfbdev->crtc_count; i++) { + if (crtc->base.id == rfbdev->crtc_ids[i]) { + break; + } + } + + if (i == rfbdev->crtc_count) { + continue; + } + + radeon_crtc = to_radeon_crtc(crtc); + modeset = &radeon_crtc->mode_set; + + modeset->x = var->xoffset; + modeset->y = var->yoffset; + + if (modeset->num_connectors) { + mutex_lock(&dev->mode_config.mutex); + ret = crtc->funcs->set_config(modeset); + mutex_unlock(&dev->mode_config.mutex); + if (!ret) { + info->var.xoffset = var->xoffset; + info->var.yoffset = var->yoffset; + } + } + } + return ret; +} + +static void radeonfb_on(struct fb_info *info) +{ + struct radeon_fb_device *rfbdev = info->par; + struct drm_device *dev = rfbdev->rdev->ddev; + struct drm_crtc *crtc; + struct drm_encoder *encoder; + int i; + + /* + * For each CRTC in this fb, find all associated encoders + * and turn them off, then turn off the CRTC. + */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; + + for (i = 0; i < rfbdev->crtc_count; i++) { + if (crtc->base.id == rfbdev->crtc_ids[i]) { + break; + } + } + + mutex_lock(&dev->mode_config.mutex); + crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); + mutex_unlock(&dev->mode_config.mutex); + + /* Found a CRTC on this fb, now find encoders */ + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + if (encoder->crtc == crtc) { + struct drm_encoder_helper_funcs *encoder_funcs; + + encoder_funcs = encoder->helper_private; + mutex_lock(&dev->mode_config.mutex); + encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON); + mutex_unlock(&dev->mode_config.mutex); + } + } + } +} + +static void radeonfb_off(struct fb_info *info, int dpms_mode) +{ + struct radeon_fb_device *rfbdev = info->par; + struct drm_device *dev = rfbdev->rdev->ddev; + struct drm_crtc *crtc; + struct drm_encoder *encoder; + int i; + + /* + * For each CRTC in this fb, find all associated encoders + * and turn them off, then turn off the CRTC. + */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; + + for (i = 0; i < rfbdev->crtc_count; i++) { + if (crtc->base.id == rfbdev->crtc_ids[i]) { + break; + } + } + + /* Found a CRTC on this fb, now find encoders */ + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + if (encoder->crtc == crtc) { + struct drm_encoder_helper_funcs *encoder_funcs; + + encoder_funcs = encoder->helper_private; + mutex_lock(&dev->mode_config.mutex); + encoder_funcs->dpms(encoder, dpms_mode); + mutex_unlock(&dev->mode_config.mutex); + } + } + if (dpms_mode == DRM_MODE_DPMS_OFF) { + mutex_lock(&dev->mode_config.mutex); + crtc_funcs->dpms(crtc, dpms_mode); + mutex_unlock(&dev->mode_config.mutex); + } + } +} + +int radeonfb_blank(int blank, struct fb_info *info) +{ + switch (blank) { + case FB_BLANK_UNBLANK: + radeonfb_on(info); + break; + case FB_BLANK_NORMAL: + radeonfb_off(info, DRM_MODE_DPMS_STANDBY); + break; + case FB_BLANK_HSYNC_SUSPEND: + radeonfb_off(info, DRM_MODE_DPMS_STANDBY); + break; + case FB_BLANK_VSYNC_SUSPEND: + radeonfb_off(info, DRM_MODE_DPMS_SUSPEND); + break; + case FB_BLANK_POWERDOWN: + radeonfb_off(info, DRM_MODE_DPMS_OFF); + break; + } + return 0; +} + +static struct fb_ops radeonfb_ops = { + .owner = THIS_MODULE, + .fb_check_var = radeonfb_check_var, + .fb_set_par = radeonfb_set_par, + .fb_setcolreg = radeonfb_setcolreg, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_pan_display = radeonfb_pan_display, + .fb_blank = radeonfb_blank, +}; + +/** + * Curretly it is assumed that the old framebuffer is reused. + * + * LOCKING + * caller should hold the mode config lock. + * + */ +int radeonfb_resize(struct drm_device *dev, struct drm_crtc *crtc) +{ + struct fb_info *info; + struct drm_framebuffer *fb; + struct drm_display_mode *mode = crtc->desired_mode; + + fb = crtc->fb; + if (fb == NULL) { + return 1; + } + info = fb->fbdev; + if (info == NULL) { + return 1; + } + if (mode == NULL) { + return 1; + } + info->var.xres = mode->hdisplay; + info->var.right_margin = mode->hsync_start - mode->hdisplay; + info->var.hsync_len = mode->hsync_end - mode->hsync_start; + info->var.left_margin = mode->htotal - mode->hsync_end; + info->var.yres = mode->vdisplay; + info->var.lower_margin = mode->vsync_start - mode->vdisplay; + info->var.vsync_len = mode->vsync_end - mode->vsync_start; + info->var.upper_margin = mode->vtotal - mode->vsync_end; + info->var.pixclock = 10000000 / mode->htotal * 1000 / mode->vtotal * 100; + /* avoid overflow */ + info->var.pixclock = info->var.pixclock * 1000 / mode->vrefresh; + + return 0; +} +EXPORT_SYMBOL(radeonfb_resize); + +static struct drm_mode_set panic_mode; + +int radeonfb_panic(struct notifier_block *n, unsigned long ununsed, + void *panic_str) +{ + DRM_ERROR("panic occurred, switching back to text console\n"); + drm_crtc_helper_set_config(&panic_mode); + return 0; +} +EXPORT_SYMBOL(radeonfb_panic); + +static struct notifier_block paniced = { + .notifier_call = radeonfb_panic, +}; + +static int radeon_align_pitch(struct radeon_device *rdev, int width, int bpp) +{ + int aligned = width; + int align_large = (ASIC_IS_AVIVO(rdev)); + int pitch_mask = 0; + + switch (bpp / 8) { + case 1: + pitch_mask = align_large ? 255 : 127; + break; + case 2: + pitch_mask = align_large ? 127 : 31; + break; + case 3: + case 4: + pitch_mask = align_large ? 63 : 15; + break; + } + + aligned += pitch_mask; + aligned &= ~pitch_mask; + return aligned; +} + +int radeonfb_create(struct radeon_device *rdev, + uint32_t fb_width, uint32_t fb_height, + uint32_t surface_width, uint32_t surface_height, + struct radeon_framebuffer **rfb_p) +{ + struct fb_info *info; + struct radeon_fb_device *rfbdev; + struct drm_framebuffer *fb; + struct radeon_framebuffer *rfb; + struct drm_mode_fb_cmd mode_cmd; + struct drm_gem_object *gobj = NULL; + struct radeon_object *robj = NULL; + struct device *device = &rdev->pdev->dev; + int size, aligned_size, ret; + void *fbptr = NULL; + + mode_cmd.width = surface_width; + mode_cmd.height = surface_height; + mode_cmd.bpp = 32; + /* need to align pitch with crtc limits */ + mode_cmd.pitch = radeon_align_pitch(rdev, mode_cmd.width, mode_cmd.bpp) * ((mode_cmd.bpp + 1) / 8); + mode_cmd.depth = 24; + + size = mode_cmd.pitch * mode_cmd.height; + aligned_size = ALIGN(size, PAGE_SIZE); + + ret = radeon_gem_object_create(rdev, aligned_size, 0, + RADEON_GEM_DOMAIN_VRAM, + false, ttm_bo_type_kernel, + false, &gobj); + if (ret) { + printk(KERN_ERR "failed to allocate framebuffer\n"); + ret = -ENOMEM; + goto out; + } + robj = gobj->driver_private; + + mutex_lock(&rdev->ddev->struct_mutex); + fb = radeon_framebuffer_create(rdev->ddev, &mode_cmd, gobj); + if (fb == NULL) { + DRM_ERROR("failed to allocate fb.\n"); + ret = -ENOMEM; + goto out_unref; + } + + list_add(&fb->filp_head, &rdev->ddev->mode_config.fb_kernel_list); + + rfb = to_radeon_framebuffer(fb); + *rfb_p = rfb; + rdev->fbdev_rfb = rfb; + + info = framebuffer_alloc(sizeof(struct radeon_fb_device), device); + if (info == NULL) { + ret = -ENOMEM; + goto out_unref; + } + rfbdev = info->par; + + ret = radeon_object_kmap(robj, &fbptr); + if (ret) { + goto out_unref; + } + + strcpy(info->fix.id, "radeondrmfb"); + info->fix.type = FB_TYPE_PACKED_PIXELS; + info->fix.visual = FB_VISUAL_TRUECOLOR; + info->fix.type_aux = 0; + info->fix.xpanstep = 1; /* doing it in hw */ + info->fix.ypanstep = 1; /* doing it in hw */ + info->fix.ywrapstep = 0; + info->fix.accel = FB_ACCEL_I830; + info->fix.type_aux = 0; + info->flags = FBINFO_DEFAULT; + info->fbops = &radeonfb_ops; + info->fix.line_length = fb->pitch; + info->screen_base = fbptr; + info->fix.smem_start = (unsigned long)fbptr; + info->fix.smem_len = size; + info->screen_base = fbptr; + info->screen_size = size; + info->pseudo_palette = fb->pseudo_palette; + info->var.xres_virtual = fb->width; + info->var.yres_virtual = fb->height; + info->var.bits_per_pixel = fb->bits_per_pixel; + info->var.xoffset = 0; + info->var.yoffset = 0; + info->var.activate = FB_ACTIVATE_NOW; + info->var.height = -1; + info->var.width = -1; + info->var.xres = fb_width; + info->var.yres = fb_height; + info->fix.mmio_start = pci_resource_start(rdev->pdev, 2); + info->fix.mmio_len = pci_resource_len(rdev->pdev, 2); + info->pixmap.size = 64*1024; + info->pixmap.buf_align = 8; + info->pixmap.access_align = 32; + info->pixmap.flags = FB_PIXMAP_SYSTEM; + info->pixmap.scan_align = 1; + if (info->screen_base == NULL) { + ret = -ENOSPC; + goto out_unref; + } + DRM_INFO("fb mappable at 0x%lX\n", info->fix.smem_start); + DRM_INFO("vram apper at 0x%lX\n", (unsigned long)rdev->mc.aper_base); + DRM_INFO("size %lu\n", (unsigned long)size); + DRM_INFO("fb depth is %d\n", fb->depth); + DRM_INFO(" pitch is %d\n", fb->pitch); + + switch (fb->depth) { + case 8: + info->var.red.offset = 0; + info->var.green.offset = 0; + info->var.blue.offset = 0; + info->var.red.length = 8; /* 8bit DAC */ + info->var.green.length = 8; + info->var.blue.length = 8; + info->var.transp.offset = 0; + info->var.transp.length = 0; + break; + case 15: + info->var.red.offset = 10; + info->var.green.offset = 5; + info->var.blue.offset = 0; + info->var.red.length = 5; + info->var.green.length = 5; + info->var.blue.length = 5; + info->var.transp.offset = 15; + info->var.transp.length = 1; + break; + case 16: + info->var.red.offset = 11; + info->var.green.offset = 5; + info->var.blue.offset = 0; + info->var.red.length = 5; + info->var.green.length = 6; + info->var.blue.length = 5; + info->var.transp.offset = 0; + break; + case 24: + info->var.red.offset = 16; + info->var.green.offset = 8; + info->var.blue.offset = 0; + info->var.red.length = 8; + info->var.green.length = 8; + info->var.blue.length = 8; + info->var.transp.offset = 0; + info->var.transp.length = 0; + break; + case 32: + info->var.red.offset = 16; + info->var.green.offset = 8; + info->var.blue.offset = 0; + info->var.red.length = 8; + info->var.green.length = 8; + info->var.blue.length = 8; + info->var.transp.offset = 24; + info->var.transp.length = 8; + break; + default: + break; + } + + fb->fbdev = info; + rfbdev->rfb = rfb; + rfbdev->rdev = rdev; + + mutex_unlock(&rdev->ddev->struct_mutex); + return 0; + +out_unref: + if (robj) { + radeon_object_kunmap(robj); + } + if (ret) { + list_del(&fb->filp_head); + drm_gem_object_unreference(gobj); + drm_framebuffer_cleanup(fb); + kfree(fb); + } + drm_gem_object_unreference(gobj); + mutex_unlock(&rdev->ddev->struct_mutex); +out: + return ret; +} + +static int radeonfb_single_fb_probe(struct radeon_device *rdev) +{ + struct drm_crtc *crtc; + struct drm_connector *connector; + unsigned int fb_width = (unsigned)-1, fb_height = (unsigned)-1; + unsigned int surface_width = 0, surface_height = 0; + int new_fb = 0; + int crtc_count = 0; + int ret, i, conn_count = 0; + struct radeon_framebuffer *rfb; + struct fb_info *info; + struct radeon_fb_device *rfbdev; + struct drm_mode_set *modeset = NULL; + + /* first up get a count of crtcs now in use and new min/maxes width/heights */ + list_for_each_entry(crtc, &rdev->ddev->mode_config.crtc_list, head) { + if (drm_helper_crtc_in_use(crtc)) { + if (crtc->desired_mode) { + if (crtc->desired_mode->hdisplay < fb_width) + fb_width = crtc->desired_mode->hdisplay; + + if (crtc->desired_mode->vdisplay < fb_height) + fb_height = crtc->desired_mode->vdisplay; + + if (crtc->desired_mode->hdisplay > surface_width) + surface_width = crtc->desired_mode->hdisplay; + + if (crtc->desired_mode->vdisplay > surface_height) + surface_height = crtc->desired_mode->vdisplay; + } + crtc_count++; + } + } + + if (crtc_count == 0 || fb_width == -1 || fb_height == -1) { + /* hmm everyone went away - assume VGA cable just fell out + and will come back later. */ + return 0; + } + + /* do we have an fb already? */ + if (list_empty(&rdev->ddev->mode_config.fb_kernel_list)) { + /* create an fb if we don't have one */ + ret = radeonfb_create(rdev, fb_width, fb_height, surface_width, surface_height, &rfb); + if (ret) { + return -EINVAL; + } + new_fb = 1; + } else { + struct drm_framebuffer *fb; + fb = list_first_entry(&rdev->ddev->mode_config.fb_kernel_list, struct drm_framebuffer, filp_head); + rfb = to_radeon_framebuffer(fb); + + /* if someone hotplugs something bigger than we have already allocated, we are pwned. + As really we can't resize an fbdev that is in the wild currently due to fbdev + not really being designed for the lower layers moving stuff around under it. + - so in the grand style of things - punt. */ + if ((fb->width < surface_width) || (fb->height < surface_height)) { + DRM_ERROR("Framebuffer not large enough to scale console onto.\n"); + return -EINVAL; + } + } + + info = rfb->base.fbdev; + rdev->fbdev_info = info; + rfbdev = info->par; + + crtc_count = 0; + /* okay we need to setup new connector sets in the crtcs */ + list_for_each_entry(crtc, &rdev->ddev->mode_config.crtc_list, head) { + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + modeset = &radeon_crtc->mode_set; + modeset->fb = &rfb->base; + conn_count = 0; + list_for_each_entry(connector, &rdev->ddev->mode_config.connector_list, head) { + if (connector->encoder) + if (connector->encoder->crtc == modeset->crtc) { + modeset->connectors[conn_count] = connector; + conn_count++; + if (conn_count > RADEONFB_CONN_LIMIT) + BUG(); + } + } + + for (i = conn_count; i < RADEONFB_CONN_LIMIT; i++) + modeset->connectors[i] = NULL; + + + rfbdev->crtc_ids[crtc_count++] = crtc->base.id; + + modeset->num_connectors = conn_count; + if (modeset->crtc->desired_mode) { + if (modeset->mode) { + drm_mode_destroy(rdev->ddev, modeset->mode); + } + modeset->mode = drm_mode_duplicate(rdev->ddev, + modeset->crtc->desired_mode); + } + } + rfbdev->crtc_count = crtc_count; + + if (new_fb) { + info->var.pixclock = -1; + if (register_framebuffer(info) < 0) + return -EINVAL; + } else { + radeonfb_set_par(info); + } + printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, + info->fix.id); + + /* Switch back to kernel console on panic */ + panic_mode = *modeset; + atomic_notifier_chain_register(&panic_notifier_list, &paniced); + printk(KERN_INFO "registered panic notifier\n"); + + return 0; +} + +int radeonfb_probe(struct drm_device *dev) +{ + int ret; + + /* something has changed in the lower levels of hell - deal with it + here */ + + /* two modes : a) 1 fb to rule all crtcs. + b) one fb per crtc. + two actions 1) new connected device + 2) device removed. + case a/1 : if the fb surface isn't big enough - resize the surface fb. + if the fb size isn't big enough - resize fb into surface. + if everything big enough configure the new crtc/etc. + case a/2 : undo the configuration + possibly resize down the fb to fit the new configuration. + case b/1 : see if it is on a new crtc - setup a new fb and add it. + case b/2 : teardown the new fb. + */ + ret = radeonfb_single_fb_probe(dev->dev_private); + return ret; +} +EXPORT_SYMBOL(radeonfb_probe); + +int radeonfb_remove(struct drm_device *dev, struct drm_framebuffer *fb) +{ + struct fb_info *info; + struct radeon_framebuffer *rfb = to_radeon_framebuffer(fb); + struct radeon_object *robj; + + if (!fb) { + return -EINVAL; + } + info = fb->fbdev; + if (info) { + robj = rfb->obj->driver_private; + unregister_framebuffer(info); + radeon_object_kunmap(robj); + framebuffer_release(info); + } + + printk(KERN_INFO "unregistered panic notifier\n"); + atomic_notifier_chain_unregister(&panic_notifier_list, &paniced); + memset(&panic_mode, 0, sizeof(struct drm_mode_set)); + return 0; +} +EXPORT_SYMBOL(radeonfb_remove); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c new file mode 100644 index 000000000000..96afbf5ae2ad --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_fence.c @@ -0,0 +1,387 @@ +/* + * Copyright 2009 Jerome Glisse. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + */ +/* + * Authors: + * Jerome Glisse + * Dave Airlie + */ +#include +#include +#include +#include +#include +#include "drmP.h" +#include "drm.h" +#include "radeon_reg.h" +#include "radeon.h" + +int radeon_fence_emit(struct radeon_device *rdev, struct radeon_fence *fence) +{ + unsigned long irq_flags; + + write_lock_irqsave(&rdev->fence_drv.lock, irq_flags); + if (fence->emited) { + write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags); + return 0; + } + fence->seq = atomic_add_return(1, &rdev->fence_drv.seq); + if (!rdev->cp.ready) { + /* FIXME: cp is not running assume everythings is done right + * away + */ + WREG32(rdev->fence_drv.scratch_reg, fence->seq); + } else { + radeon_fence_ring_emit(rdev, fence); + } + fence->emited = true; + fence->timeout = jiffies + ((2000 * HZ) / 1000); + list_del(&fence->list); + list_add_tail(&fence->list, &rdev->fence_drv.emited); + write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags); + return 0; +} + +static bool radeon_fence_poll_locked(struct radeon_device *rdev) +{ + struct radeon_fence *fence; + struct list_head *i, *n; + uint32_t seq; + bool wake = false; + + if (rdev == NULL) { + return true; + } + if (rdev->shutdown) { + return true; + } + seq = RREG32(rdev->fence_drv.scratch_reg); + rdev->fence_drv.last_seq = seq; + n = NULL; + list_for_each(i, &rdev->fence_drv.emited) { + fence = list_entry(i, struct radeon_fence, list); + if (fence->seq == seq) { + n = i; + break; + } + } + /* all fence previous to this one are considered as signaled */ + if (n) { + i = n; + do { + n = i->prev; + list_del(i); + list_add_tail(i, &rdev->fence_drv.signaled); + fence = list_entry(i, struct radeon_fence, list); + fence->signaled = true; + i = n; + } while (i != &rdev->fence_drv.emited); + wake = true; + } + return wake; +} + +static void radeon_fence_destroy(struct kref *kref) +{ + unsigned long irq_flags; + struct radeon_fence *fence; + + fence = container_of(kref, struct radeon_fence, kref); + write_lock_irqsave(&fence->rdev->fence_drv.lock, irq_flags); + list_del(&fence->list); + fence->emited = false; + write_unlock_irqrestore(&fence->rdev->fence_drv.lock, irq_flags); + kfree(fence); +} + +int radeon_fence_create(struct radeon_device *rdev, struct radeon_fence **fence) +{ + unsigned long irq_flags; + + *fence = kmalloc(sizeof(struct radeon_fence), GFP_KERNEL); + if ((*fence) == NULL) { + return -ENOMEM; + } + kref_init(&((*fence)->kref)); + (*fence)->rdev = rdev; + (*fence)->emited = false; + (*fence)->signaled = false; + (*fence)->seq = 0; + INIT_LIST_HEAD(&(*fence)->list); + + write_lock_irqsave(&rdev->fence_drv.lock, irq_flags); + list_add_tail(&(*fence)->list, &rdev->fence_drv.created); + write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags); + return 0; +} + + +bool radeon_fence_signaled(struct radeon_fence *fence) +{ + struct radeon_device *rdev = fence->rdev; + unsigned long irq_flags; + bool signaled = false; + + if (rdev->gpu_lockup) { + return true; + } + if (fence == NULL) { + return true; + } + write_lock_irqsave(&fence->rdev->fence_drv.lock, irq_flags); + signaled = fence->signaled; + /* if we are shuting down report all fence as signaled */ + if (fence->rdev->shutdown) { + signaled = true; + } + if (!fence->emited) { + WARN(1, "Querying an unemited fence : %p !\n", fence); + signaled = true; + } + if (!signaled) { + radeon_fence_poll_locked(fence->rdev); + signaled = fence->signaled; + } + write_unlock_irqrestore(&fence->rdev->fence_drv.lock, irq_flags); + return signaled; +} + +int radeon_fence_wait(struct radeon_fence *fence, bool interruptible) +{ + struct radeon_device *rdev; + unsigned long cur_jiffies; + unsigned long timeout; + bool expired = false; + int r; + + + if (fence == NULL) { + WARN(1, "Querying an invalid fence : %p !\n", fence); + return 0; + } + rdev = fence->rdev; + if (radeon_fence_signaled(fence)) { + return 0; + } +retry: + cur_jiffies = jiffies; + timeout = HZ / 100; + if (time_after(fence->timeout, cur_jiffies)) { + timeout = fence->timeout - cur_jiffies; + } + if (interruptible) { + r = wait_event_interruptible_timeout(rdev->fence_drv.queue, + radeon_fence_signaled(fence), timeout); + if (unlikely(r == -ERESTARTSYS)) { + return -ERESTART; + } + } else { + r = wait_event_timeout(rdev->fence_drv.queue, + radeon_fence_signaled(fence), timeout); + } + if (unlikely(!radeon_fence_signaled(fence))) { + if (unlikely(r == 0)) { + expired = true; + } + if (unlikely(expired)) { + timeout = 1; + if (time_after(cur_jiffies, fence->timeout)) { + timeout = cur_jiffies - fence->timeout; + } + timeout = jiffies_to_msecs(timeout); + if (timeout > 500) { + DRM_ERROR("fence(%p:0x%08X) %lums timeout " + "going to reset GPU\n", + fence, fence->seq, timeout); + radeon_gpu_reset(rdev); + WREG32(rdev->fence_drv.scratch_reg, fence->seq); + } + } + goto retry; + } + if (unlikely(expired)) { + rdev->fence_drv.count_timeout++; + cur_jiffies = jiffies; + timeout = 1; + if (time_after(cur_jiffies, fence->timeout)) { + timeout = cur_jiffies - fence->timeout; + } + timeout = jiffies_to_msecs(timeout); + DRM_ERROR("fence(%p:0x%08X) %lums timeout\n", + fence, fence->seq, timeout); + DRM_ERROR("last signaled fence(0x%08X)\n", + rdev->fence_drv.last_seq); + } + return 0; +} + +int radeon_fence_wait_next(struct radeon_device *rdev) +{ + unsigned long irq_flags; + struct radeon_fence *fence; + int r; + + if (rdev->gpu_lockup) { + return 0; + } + write_lock_irqsave(&rdev->fence_drv.lock, irq_flags); + if (list_empty(&rdev->fence_drv.emited)) { + write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags); + return 0; + } + fence = list_entry(rdev->fence_drv.emited.next, + struct radeon_fence, list); + radeon_fence_ref(fence); + write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags); + r = radeon_fence_wait(fence, false); + radeon_fence_unref(&fence); + return r; +} + +int radeon_fence_wait_last(struct radeon_device *rdev) +{ + unsigned long irq_flags; + struct radeon_fence *fence; + int r; + + if (rdev->gpu_lockup) { + return 0; + } + write_lock_irqsave(&rdev->fence_drv.lock, irq_flags); + if (list_empty(&rdev->fence_drv.emited)) { + write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags); + return 0; + } + fence = list_entry(rdev->fence_drv.emited.prev, + struct radeon_fence, list); + radeon_fence_ref(fence); + write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags); + r = radeon_fence_wait(fence, false); + radeon_fence_unref(&fence); + return r; +} + +struct radeon_fence *radeon_fence_ref(struct radeon_fence *fence) +{ + kref_get(&fence->kref); + return fence; +} + +void radeon_fence_unref(struct radeon_fence **fence) +{ + struct radeon_fence *tmp = *fence; + + *fence = NULL; + if (tmp) { + kref_put(&tmp->kref, &radeon_fence_destroy); + } +} + +void radeon_fence_process(struct radeon_device *rdev) +{ + unsigned long irq_flags; + bool wake; + + write_lock_irqsave(&rdev->fence_drv.lock, irq_flags); + wake = radeon_fence_poll_locked(rdev); + write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags); + if (wake) { + wake_up_all(&rdev->fence_drv.queue); + } +} + +int radeon_fence_driver_init(struct radeon_device *rdev) +{ + unsigned long irq_flags; + int r; + + write_lock_irqsave(&rdev->fence_drv.lock, irq_flags); + r = radeon_scratch_get(rdev, &rdev->fence_drv.scratch_reg); + if (r) { + DRM_ERROR("Fence failed to get a scratch register."); + write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags); + return r; + } + WREG32(rdev->fence_drv.scratch_reg, 0); + atomic_set(&rdev->fence_drv.seq, 0); + INIT_LIST_HEAD(&rdev->fence_drv.created); + INIT_LIST_HEAD(&rdev->fence_drv.emited); + INIT_LIST_HEAD(&rdev->fence_drv.signaled); + rdev->fence_drv.count_timeout = 0; + init_waitqueue_head(&rdev->fence_drv.queue); + write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags); + if (radeon_debugfs_fence_init(rdev)) { + DRM_ERROR("Failed to register debugfs file for fence !\n"); + } + return 0; +} + +void radeon_fence_driver_fini(struct radeon_device *rdev) +{ + unsigned long irq_flags; + + wake_up_all(&rdev->fence_drv.queue); + write_lock_irqsave(&rdev->fence_drv.lock, irq_flags); + radeon_scratch_free(rdev, rdev->fence_drv.scratch_reg); + write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags); + DRM_INFO("radeon: fence finalized\n"); +} + + +/* + * Fence debugfs + */ +#if defined(CONFIG_DEBUG_FS) +static int radeon_debugfs_fence_info(struct seq_file *m, void *data) +{ + struct drm_info_node *node = (struct drm_info_node *)m->private; + struct drm_device *dev = node->minor->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_fence *fence; + + seq_printf(m, "Last signaled fence 0x%08X\n", + RREG32(rdev->fence_drv.scratch_reg)); + if (!list_empty(&rdev->fence_drv.emited)) { + fence = list_entry(rdev->fence_drv.emited.prev, + struct radeon_fence, list); + seq_printf(m, "Last emited fence %p with 0x%08X\n", + fence, fence->seq); + } + return 0; +} + +static struct drm_info_list radeon_debugfs_fence_list[] = { + {"radeon_fence_info", &radeon_debugfs_fence_info, 0, NULL}, +}; +#endif + +int radeon_debugfs_fence_init(struct radeon_device *rdev) +{ +#if defined(CONFIG_DEBUG_FS) + return radeon_debugfs_add_files(rdev, radeon_debugfs_fence_list, 1); +#else + return 0; +#endif +} diff --git a/drivers/gpu/drm/radeon/radeon_fixed.h b/drivers/gpu/drm/radeon/radeon_fixed.h new file mode 100644 index 000000000000..90187d173847 --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_fixed.h @@ -0,0 +1,50 @@ +/* + * Copyright 2009 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Dave Airlie + */ +#ifndef RADEON_FIXED_H +#define RADEON_FIXED_H + +typedef union rfixed { + u32 full; +} fixed20_12; + + +#define rfixed_const(A) (u32)(((A) << 12))/* + ((B + 0.000122)*4096)) */ +#define rfixed_const_half(A) (u32)(((A) << 12) + 2048) +#define rfixed_const_666(A) (u32)(((A) << 12) + 2731) +#define rfixed_const_8(A) (u32)(((A) << 12) + 3277) +#define rfixed_mul(A, B) ((u64)((u64)(A).full * (B).full + 2048) >> 12) +#define fixed_init(A) { .full = rfixed_const((A)) } +#define fixed_init_half(A) { .full = rfixed_const_half((A)) } +#define rfixed_trunc(A) ((A).full >> 12) + +static inline u32 rfixed_div(fixed20_12 A, fixed20_12 B) +{ + u64 tmp = ((u64)A.full << 13); + + do_div(tmp, B.full); + tmp += 1; + tmp /= 2; + return lower_32_bits(tmp); +} +#endif diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c new file mode 100644 index 000000000000..d343a15316ec --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_gart.c @@ -0,0 +1,233 @@ +/* + * Copyright 2008 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * Copyright 2009 Jerome Glisse. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Dave Airlie + * Alex Deucher + * Jerome Glisse + */ +#include "drmP.h" +#include "radeon_drm.h" +#include "radeon.h" +#include "radeon_reg.h" + +/* + * Common GART table functions. + */ +int radeon_gart_table_ram_alloc(struct radeon_device *rdev) +{ + void *ptr; + + ptr = pci_alloc_consistent(rdev->pdev, rdev->gart.table_size, + &rdev->gart.table_addr); + if (ptr == NULL) { + return -ENOMEM; + } +#ifdef CONFIG_X86 + if (rdev->family == CHIP_RS400 || rdev->family == CHIP_RS480 || + rdev->family == CHIP_RS690 || rdev->family == CHIP_RS740) { + set_memory_uc((unsigned long)ptr, + rdev->gart.table_size >> PAGE_SHIFT); + } +#endif + rdev->gart.table.ram.ptr = ptr; + memset((void *)rdev->gart.table.ram.ptr, 0, rdev->gart.table_size); + return 0; +} + +void radeon_gart_table_ram_free(struct radeon_device *rdev) +{ + if (rdev->gart.table.ram.ptr == NULL) { + return; + } +#ifdef CONFIG_X86 + if (rdev->family == CHIP_RS400 || rdev->family == CHIP_RS480 || + rdev->family == CHIP_RS690 || rdev->family == CHIP_RS740) { + set_memory_wb((unsigned long)rdev->gart.table.ram.ptr, + rdev->gart.table_size >> PAGE_SHIFT); + } +#endif + pci_free_consistent(rdev->pdev, rdev->gart.table_size, + (void *)rdev->gart.table.ram.ptr, + rdev->gart.table_addr); + rdev->gart.table.ram.ptr = NULL; + rdev->gart.table_addr = 0; +} + +int radeon_gart_table_vram_alloc(struct radeon_device *rdev) +{ + uint64_t gpu_addr; + int r; + + if (rdev->gart.table.vram.robj == NULL) { + r = radeon_object_create(rdev, NULL, + rdev->gart.table_size, + true, + RADEON_GEM_DOMAIN_VRAM, + false, &rdev->gart.table.vram.robj); + if (r) { + return r; + } + } + r = radeon_object_pin(rdev->gart.table.vram.robj, + RADEON_GEM_DOMAIN_VRAM, &gpu_addr); + if (r) { + radeon_object_unref(&rdev->gart.table.vram.robj); + return r; + } + r = radeon_object_kmap(rdev->gart.table.vram.robj, + (void **)&rdev->gart.table.vram.ptr); + if (r) { + radeon_object_unpin(rdev->gart.table.vram.robj); + radeon_object_unref(&rdev->gart.table.vram.robj); + DRM_ERROR("radeon: failed to map gart vram table.\n"); + return r; + } + rdev->gart.table_addr = gpu_addr; + return 0; +} + +void radeon_gart_table_vram_free(struct radeon_device *rdev) +{ + if (rdev->gart.table.vram.robj == NULL) { + return; + } + radeon_object_kunmap(rdev->gart.table.vram.robj); + radeon_object_unpin(rdev->gart.table.vram.robj); + radeon_object_unref(&rdev->gart.table.vram.robj); +} + + + + +/* + * Common gart functions. + */ +void radeon_gart_unbind(struct radeon_device *rdev, unsigned offset, + int pages) +{ + unsigned t; + unsigned p; + int i, j; + + if (!rdev->gart.ready) { + WARN(1, "trying to unbind memory to unitialized GART !\n"); + return; + } + t = offset / 4096; + p = t / (PAGE_SIZE / 4096); + for (i = 0; i < pages; i++, p++) { + if (rdev->gart.pages[p]) { + pci_unmap_page(rdev->pdev, rdev->gart.pages_addr[p], + PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); + rdev->gart.pages[p] = NULL; + rdev->gart.pages_addr[p] = 0; + for (j = 0; j < (PAGE_SIZE / 4096); j++, t++) { + radeon_gart_set_page(rdev, t, 0); + } + } + } + mb(); + radeon_gart_tlb_flush(rdev); +} + +int radeon_gart_bind(struct radeon_device *rdev, unsigned offset, + int pages, struct page **pagelist) +{ + unsigned t; + unsigned p; + uint64_t page_base; + int i, j; + + if (!rdev->gart.ready) { + DRM_ERROR("trying to bind memory to unitialized GART !\n"); + return -EINVAL; + } + t = offset / 4096; + p = t / (PAGE_SIZE / 4096); + + for (i = 0; i < pages; i++, p++) { + /* we need to support large memory configurations */ + /* assume that unbind have already been call on the range */ + rdev->gart.pages_addr[p] = pci_map_page(rdev->pdev, pagelist[i], + 0, PAGE_SIZE, + PCI_DMA_BIDIRECTIONAL); + if (pci_dma_mapping_error(rdev->pdev, rdev->gart.pages_addr[p])) { + /* FIXME: failed to map page (return -ENOMEM?) */ + radeon_gart_unbind(rdev, offset, pages); + return -ENOMEM; + } + rdev->gart.pages[p] = pagelist[i]; + page_base = (uint32_t)rdev->gart.pages_addr[p]; + for (j = 0; j < (PAGE_SIZE / 4096); j++, t++) { + radeon_gart_set_page(rdev, t, page_base); + page_base += 4096; + } + } + mb(); + radeon_gart_tlb_flush(rdev); + return 0; +} + +int radeon_gart_init(struct radeon_device *rdev) +{ + if (rdev->gart.pages) { + return 0; + } + /* We need PAGE_SIZE >= 4096 */ + if (PAGE_SIZE < 4096) { + DRM_ERROR("Page size is smaller than GPU page size!\n"); + return -EINVAL; + } + /* Compute table size */ + rdev->gart.num_cpu_pages = rdev->mc.gtt_size / PAGE_SIZE; + rdev->gart.num_gpu_pages = rdev->mc.gtt_size / 4096; + DRM_INFO("GART: num cpu pages %u, num gpu pages %u\n", + rdev->gart.num_cpu_pages, rdev->gart.num_gpu_pages); + /* Allocate pages table */ + rdev->gart.pages = kzalloc(sizeof(void *) * rdev->gart.num_cpu_pages, + GFP_KERNEL); + if (rdev->gart.pages == NULL) { + radeon_gart_fini(rdev); + return -ENOMEM; + } + rdev->gart.pages_addr = kzalloc(sizeof(dma_addr_t) * + rdev->gart.num_cpu_pages, GFP_KERNEL); + if (rdev->gart.pages_addr == NULL) { + radeon_gart_fini(rdev); + return -ENOMEM; + } + return 0; +} + +void radeon_gart_fini(struct radeon_device *rdev) +{ + if (rdev->gart.pages && rdev->gart.pages_addr && rdev->gart.ready) { + /* unbind pages */ + radeon_gart_unbind(rdev, 0, rdev->gart.num_cpu_pages); + } + rdev->gart.ready = false; + kfree(rdev->gart.pages); + kfree(rdev->gart.pages_addr); + rdev->gart.pages = NULL; + rdev->gart.pages_addr = NULL; +} diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c new file mode 100644 index 000000000000..eb516034235d --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_gem.c @@ -0,0 +1,287 @@ +/* + * Copyright 2008 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * Copyright 2009 Jerome Glisse. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Dave Airlie + * Alex Deucher + * Jerome Glisse + */ +#include "drmP.h" +#include "drm.h" +#include "radeon_drm.h" +#include "radeon.h" + +int radeon_gem_object_init(struct drm_gem_object *obj) +{ + /* we do nothings here */ + return 0; +} + +void radeon_gem_object_free(struct drm_gem_object *gobj) +{ + struct radeon_object *robj = gobj->driver_private; + + gobj->driver_private = NULL; + if (robj) { + radeon_object_unref(&robj); + } +} + +int radeon_gem_object_create(struct radeon_device *rdev, int size, + int alignment, int initial_domain, + bool discardable, bool kernel, + bool interruptible, + struct drm_gem_object **obj) +{ + struct drm_gem_object *gobj; + struct radeon_object *robj; + int r; + + *obj = NULL; + gobj = drm_gem_object_alloc(rdev->ddev, size); + if (!gobj) { + return -ENOMEM; + } + /* At least align on page size */ + if (alignment < PAGE_SIZE) { + alignment = PAGE_SIZE; + } + r = radeon_object_create(rdev, gobj, size, kernel, initial_domain, + interruptible, &robj); + if (r) { + DRM_ERROR("Failed to allocate GEM object (%d, %d, %u)\n", + size, initial_domain, alignment); + mutex_lock(&rdev->ddev->struct_mutex); + drm_gem_object_unreference(gobj); + mutex_unlock(&rdev->ddev->struct_mutex); + return r; + } + gobj->driver_private = robj; + *obj = gobj; + return 0; +} + +int radeon_gem_object_pin(struct drm_gem_object *obj, uint32_t pin_domain, + uint64_t *gpu_addr) +{ + struct radeon_object *robj = obj->driver_private; + uint32_t flags; + + switch (pin_domain) { + case RADEON_GEM_DOMAIN_VRAM: + flags = TTM_PL_FLAG_VRAM; + break; + case RADEON_GEM_DOMAIN_GTT: + flags = TTM_PL_FLAG_TT; + break; + default: + flags = TTM_PL_FLAG_SYSTEM; + break; + } + return radeon_object_pin(robj, flags, gpu_addr); +} + +void radeon_gem_object_unpin(struct drm_gem_object *obj) +{ + struct radeon_object *robj = obj->driver_private; + radeon_object_unpin(robj); +} + +int radeon_gem_set_domain(struct drm_gem_object *gobj, + uint32_t rdomain, uint32_t wdomain) +{ + struct radeon_object *robj; + uint32_t domain; + int r; + + /* FIXME: reeimplement */ + robj = gobj->driver_private; + /* work out where to validate the buffer to */ + domain = wdomain; + if (!domain) { + domain = rdomain; + } + if (!domain) { + /* Do nothings */ + printk(KERN_WARNING "Set domain withou domain !\n"); + return 0; + } + if (domain == RADEON_GEM_DOMAIN_CPU) { + /* Asking for cpu access wait for object idle */ + r = radeon_object_wait(robj); + if (r) { + printk(KERN_ERR "Failed to wait for object !\n"); + return r; + } + } + return 0; +} + +int radeon_gem_init(struct radeon_device *rdev) +{ + INIT_LIST_HEAD(&rdev->gem.objects); + return 0; +} + +void radeon_gem_fini(struct radeon_device *rdev) +{ + radeon_object_force_delete(rdev); +} + + +/* + * GEM ioctls. + */ +int radeon_gem_info_ioctl(struct drm_device *dev, void *data, + struct drm_file *filp) +{ + struct radeon_device *rdev = dev->dev_private; + struct drm_radeon_gem_info *args = data; + + args->vram_size = rdev->mc.vram_size; + /* FIXME: report somethings that makes sense */ + args->vram_visible = rdev->mc.vram_size - (4 * 1024 * 1024); + args->gart_size = rdev->mc.gtt_size; + return 0; +} + +int radeon_gem_pread_ioctl(struct drm_device *dev, void *data, + struct drm_file *filp) +{ + /* TODO: implement */ + DRM_ERROR("unimplemented %s\n", __func__); + return -ENOSYS; +} + +int radeon_gem_pwrite_ioctl(struct drm_device *dev, void *data, + struct drm_file *filp) +{ + /* TODO: implement */ + DRM_ERROR("unimplemented %s\n", __func__); + return -ENOSYS; +} + +int radeon_gem_create_ioctl(struct drm_device *dev, void *data, + struct drm_file *filp) +{ + struct radeon_device *rdev = dev->dev_private; + struct drm_radeon_gem_create *args = data; + struct drm_gem_object *gobj; + uint32_t handle; + int r; + + /* create a gem object to contain this object in */ + args->size = roundup(args->size, PAGE_SIZE); + r = radeon_gem_object_create(rdev, args->size, args->alignment, + args->initial_domain, false, + false, true, &gobj); + if (r) { + return r; + } + r = drm_gem_handle_create(filp, gobj, &handle); + if (r) { + mutex_lock(&dev->struct_mutex); + drm_gem_object_unreference(gobj); + mutex_unlock(&dev->struct_mutex); + return r; + } + mutex_lock(&dev->struct_mutex); + drm_gem_object_handle_unreference(gobj); + mutex_unlock(&dev->struct_mutex); + args->handle = handle; + return 0; +} + +int radeon_gem_set_domain_ioctl(struct drm_device *dev, void *data, + struct drm_file *filp) +{ + /* transition the BO to a domain - + * just validate the BO into a certain domain */ + struct drm_radeon_gem_set_domain *args = data; + struct drm_gem_object *gobj; + struct radeon_object *robj; + int r; + + /* for now if someone requests domain CPU - + * just make sure the buffer is finished with */ + + /* just do a BO wait for now */ + gobj = drm_gem_object_lookup(dev, filp, args->handle); + if (gobj == NULL) { + return -EINVAL; + } + robj = gobj->driver_private; + + r = radeon_gem_set_domain(gobj, args->read_domains, args->write_domain); + + mutex_lock(&dev->struct_mutex); + drm_gem_object_unreference(gobj); + mutex_unlock(&dev->struct_mutex); + return r; +} + +int radeon_gem_mmap_ioctl(struct drm_device *dev, void *data, + struct drm_file *filp) +{ + struct drm_radeon_gem_mmap *args = data; + struct drm_gem_object *gobj; + struct radeon_object *robj; + int r; + + gobj = drm_gem_object_lookup(dev, filp, args->handle); + if (gobj == NULL) { + return -EINVAL; + } + robj = gobj->driver_private; + r = radeon_object_mmap(robj, &args->addr_ptr); + mutex_lock(&dev->struct_mutex); + drm_gem_object_unreference(gobj); + mutex_unlock(&dev->struct_mutex); + return r; +} + +int radeon_gem_busy_ioctl(struct drm_device *dev, void *data, + struct drm_file *filp) +{ + /* FIXME: implement */ + return 0; +} + +int radeon_gem_wait_idle_ioctl(struct drm_device *dev, void *data, + struct drm_file *filp) +{ + struct drm_radeon_gem_wait_idle *args = data; + struct drm_gem_object *gobj; + struct radeon_object *robj; + int r; + + gobj = drm_gem_object_lookup(dev, filp, args->handle); + if (gobj == NULL) { + return -EINVAL; + } + robj = gobj->driver_private; + r = radeon_object_wait(robj); + mutex_lock(&dev->struct_mutex); + drm_gem_object_unreference(gobj); + mutex_unlock(&dev->struct_mutex); + return r; +} diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c new file mode 100644 index 000000000000..dd438d32e5c0 --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_i2c.c @@ -0,0 +1,209 @@ +/* + * Copyright 2007-8 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Dave Airlie + * Alex Deucher + */ +#include "drmP.h" +#include "radeon_drm.h" +#include "radeon.h" + +/** + * radeon_ddc_probe + * + */ +bool radeon_ddc_probe(struct radeon_connector *radeon_connector) +{ + u8 out_buf[] = { 0x0, 0x0}; + u8 buf[2]; + int ret; + struct i2c_msg msgs[] = { + { + .addr = 0x50, + .flags = 0, + .len = 1, + .buf = out_buf, + }, + { + .addr = 0x50, + .flags = I2C_M_RD, + .len = 1, + .buf = buf, + } + }; + + ret = i2c_transfer(&radeon_connector->ddc_bus->adapter, msgs, 2); + if (ret == 2) + return true; + + return false; +} + + +void radeon_i2c_do_lock(struct radeon_connector *radeon_connector, int lock_state) +{ + struct radeon_device *rdev = radeon_connector->base.dev->dev_private; + uint32_t temp; + struct radeon_i2c_bus_rec *rec = &radeon_connector->ddc_bus->rec; + + /* RV410 appears to have a bug where the hw i2c in reset + * holds the i2c port in a bad state - switch hw i2c away before + * doing DDC - do this for all r200s/r300s/r400s for safety sake + */ + if ((rdev->family >= CHIP_R200) && !ASIC_IS_AVIVO(rdev)) { + if (rec->a_clk_reg == RADEON_GPIO_MONID) { + WREG32(RADEON_DVI_I2C_CNTL_0, (RADEON_I2C_SOFT_RST | + R200_DVI_I2C_PIN_SEL(R200_SEL_DDC1))); + } else { + WREG32(RADEON_DVI_I2C_CNTL_0, (RADEON_I2C_SOFT_RST | + R200_DVI_I2C_PIN_SEL(R200_SEL_DDC3))); + } + } + if (lock_state) { + temp = RREG32(rec->a_clk_reg); + temp &= ~(rec->a_clk_mask); + WREG32(rec->a_clk_reg, temp); + + temp = RREG32(rec->a_data_reg); + temp &= ~(rec->a_data_mask); + WREG32(rec->a_data_reg, temp); + } + + temp = RREG32(rec->mask_clk_reg); + if (lock_state) + temp |= rec->mask_clk_mask; + else + temp &= ~rec->mask_clk_mask; + WREG32(rec->mask_clk_reg, temp); + temp = RREG32(rec->mask_clk_reg); + + temp = RREG32(rec->mask_data_reg); + if (lock_state) + temp |= rec->mask_data_mask; + else + temp &= ~rec->mask_data_mask; + WREG32(rec->mask_data_reg, temp); + temp = RREG32(rec->mask_data_reg); +} + +static int get_clock(void *i2c_priv) +{ + struct radeon_i2c_chan *i2c = i2c_priv; + struct radeon_device *rdev = i2c->dev->dev_private; + struct radeon_i2c_bus_rec *rec = &i2c->rec; + uint32_t val; + + val = RREG32(rec->get_clk_reg); + val &= rec->get_clk_mask; + + return (val != 0); +} + + +static int get_data(void *i2c_priv) +{ + struct radeon_i2c_chan *i2c = i2c_priv; + struct radeon_device *rdev = i2c->dev->dev_private; + struct radeon_i2c_bus_rec *rec = &i2c->rec; + uint32_t val; + + val = RREG32(rec->get_data_reg); + val &= rec->get_data_mask; + return (val != 0); +} + +static void set_clock(void *i2c_priv, int clock) +{ + struct radeon_i2c_chan *i2c = i2c_priv; + struct radeon_device *rdev = i2c->dev->dev_private; + struct radeon_i2c_bus_rec *rec = &i2c->rec; + uint32_t val; + + val = RREG32(rec->put_clk_reg) & (uint32_t)~(rec->put_clk_mask); + val |= clock ? 0 : rec->put_clk_mask; + WREG32(rec->put_clk_reg, val); +} + +static void set_data(void *i2c_priv, int data) +{ + struct radeon_i2c_chan *i2c = i2c_priv; + struct radeon_device *rdev = i2c->dev->dev_private; + struct radeon_i2c_bus_rec *rec = &i2c->rec; + uint32_t val; + + val = RREG32(rec->put_data_reg) & (uint32_t)~(rec->put_data_mask); + val |= data ? 0 : rec->put_data_mask; + WREG32(rec->put_data_reg, val); +} + +struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev, + struct radeon_i2c_bus_rec *rec, + const char *name) +{ + struct radeon_i2c_chan *i2c; + int ret; + + i2c = kzalloc(sizeof(struct radeon_i2c_chan), GFP_KERNEL); + if (i2c == NULL) + return NULL; + + i2c->adapter.owner = THIS_MODULE; + i2c->adapter.algo_data = &i2c->algo; + i2c->dev = dev; + i2c->algo.setsda = set_data; + i2c->algo.setscl = set_clock; + i2c->algo.getsda = get_data; + i2c->algo.getscl = get_clock; + i2c->algo.udelay = 20; + /* vesa says 2.2 ms is enough, 1 jiffy doesn't seem to always + * make this, 2 jiffies is a lot more reliable */ + i2c->algo.timeout = 2; + i2c->algo.data = i2c; + i2c->rec = *rec; + i2c_set_adapdata(&i2c->adapter, i2c); + + ret = i2c_bit_add_bus(&i2c->adapter); + if (ret) { + DRM_INFO("Failed to register i2c %s\n", name); + goto out_free; + } + + return i2c; +out_free: + kfree(i2c); + return NULL; + +} + +void radeon_i2c_destroy(struct radeon_i2c_chan *i2c) +{ + if (!i2c) + return; + + i2c_del_adapter(&i2c->adapter); + kfree(i2c); +} + +struct drm_encoder *radeon_best_encoder(struct drm_connector *connector) +{ + return NULL; +} diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c new file mode 100644 index 000000000000..491d569deb0e --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c @@ -0,0 +1,158 @@ +/* + * Copyright 2008 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * Copyright 2009 Jerome Glisse. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Dave Airlie + * Alex Deucher + * Jerome Glisse + */ +#include "drmP.h" +#include "radeon_drm.h" +#include "radeon_reg.h" +#include "radeon_microcode.h" +#include "radeon.h" +#include "atom.h" + +static inline uint32_t r100_irq_ack(struct radeon_device *rdev) +{ + uint32_t irqs = RREG32(RADEON_GEN_INT_STATUS); + uint32_t irq_mask = RADEON_SW_INT_TEST; + + if (irqs) { + WREG32(RADEON_GEN_INT_STATUS, irqs); + } + return irqs & irq_mask; +} + +int r100_irq_set(struct radeon_device *rdev) +{ + uint32_t tmp = 0; + + if (rdev->irq.sw_int) { + tmp |= RADEON_SW_INT_ENABLE; + } + /* Todo go through CRTC and enable vblank int or not */ + WREG32(RADEON_GEN_INT_CNTL, tmp); + return 0; +} + +int r100_irq_process(struct radeon_device *rdev) +{ + uint32_t status; + + status = r100_irq_ack(rdev); + if (!status) { + return IRQ_NONE; + } + while (status) { + /* SW interrupt */ + if (status & RADEON_SW_INT_TEST) { + radeon_fence_process(rdev); + } + status = r100_irq_ack(rdev); + } + return IRQ_HANDLED; +} + +int rs600_irq_set(struct radeon_device *rdev) +{ + uint32_t tmp = 0; + + if (rdev->irq.sw_int) { + tmp |= RADEON_SW_INT_ENABLE; + } + WREG32(RADEON_GEN_INT_CNTL, tmp); + /* Todo go through CRTC and enable vblank int or not */ + WREG32(R500_DxMODE_INT_MASK, 0); + return 0; +} + +irqreturn_t radeon_driver_irq_handler_kms(DRM_IRQ_ARGS) +{ + struct drm_device *dev = (struct drm_device *) arg; + struct radeon_device *rdev = dev->dev_private; + + return radeon_irq_process(rdev); +} + +void radeon_driver_irq_preinstall_kms(struct drm_device *dev) +{ + struct radeon_device *rdev = dev->dev_private; + unsigned i; + + /* Disable *all* interrupts */ + rdev->irq.sw_int = false; + for (i = 0; i < 2; i++) { + rdev->irq.crtc_vblank_int[i] = false; + } + radeon_irq_set(rdev); + /* Clear bits */ + radeon_irq_process(rdev); +} + +int radeon_driver_irq_postinstall_kms(struct drm_device *dev) +{ + struct radeon_device *rdev = dev->dev_private; + + dev->max_vblank_count = 0x001fffff; + rdev->irq.sw_int = true; + radeon_irq_set(rdev); + return 0; +} + +void radeon_driver_irq_uninstall_kms(struct drm_device *dev) +{ + struct radeon_device *rdev = dev->dev_private; + unsigned i; + + if (rdev == NULL) { + return; + } + /* Disable *all* interrupts */ + rdev->irq.sw_int = false; + for (i = 0; i < 2; i++) { + rdev->irq.crtc_vblank_int[i] = false; + } + radeon_irq_set(rdev); +} + +int radeon_irq_kms_init(struct radeon_device *rdev) +{ + int r = 0; + + r = drm_vblank_init(rdev->ddev, 2); + if (r) { + return r; + } + drm_irq_install(rdev->ddev); + rdev->irq.installed = true; + DRM_INFO("radeon: irq initialized.\n"); + return 0; +} + +void radeon_irq_kms_fini(struct radeon_device *rdev) +{ + if (rdev->irq.installed) { + rdev->irq.installed = false; + drm_irq_uninstall(rdev->ddev); + } +} diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c new file mode 100644 index 000000000000..4612a7c146d1 --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -0,0 +1,295 @@ +/* + * Copyright 2008 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * Copyright 2009 Jerome Glisse. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Dave Airlie + * Alex Deucher + * Jerome Glisse + */ +#include "drmP.h" +#include "drm_sarea.h" +#include "radeon.h" +#include "radeon_drm.h" + + +/* + * Driver load/unload + */ +int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags) +{ + struct radeon_device *rdev; + int r; + + rdev = kzalloc(sizeof(struct radeon_device), GFP_KERNEL); + if (rdev == NULL) { + return -ENOMEM; + } + dev->dev_private = (void *)rdev; + + /* update BUS flag */ + if (drm_device_is_agp(dev)) { + flags |= RADEON_IS_AGP; + } else if (drm_device_is_pcie(dev)) { + flags |= RADEON_IS_PCIE; + } else { + flags |= RADEON_IS_PCI; + } + + r = radeon_device_init(rdev, dev, dev->pdev, flags); + if (r) { + DRM_ERROR("Failed to initialize radeon, disabling IOCTL\n"); + radeon_device_fini(rdev); + return r; + } + return 0; +} + +int radeon_driver_unload_kms(struct drm_device *dev) +{ + struct radeon_device *rdev = dev->dev_private; + + radeon_device_fini(rdev); + kfree(rdev); + dev->dev_private = NULL; + return 0; +} + + +/* + * Userspace get informations ioctl + */ +int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) +{ + struct radeon_device *rdev = dev->dev_private; + struct drm_radeon_info *info; + uint32_t *value_ptr; + uint32_t value; + + info = data; + value_ptr = (uint32_t *)((unsigned long)info->value); + switch (info->request) { + case RADEON_INFO_DEVICE_ID: + value = dev->pci_device; + break; + case RADEON_INFO_NUM_GB_PIPES: + value = rdev->num_gb_pipes; + break; + default: + DRM_DEBUG("Invalid request %d\n", info->request); + return -EINVAL; + } + if (DRM_COPY_TO_USER(value_ptr, &value, sizeof(uint32_t))) { + DRM_ERROR("copy_to_user\n"); + return -EFAULT; + } + return 0; +} + + +/* + * Outdated mess for old drm with Xorg being in charge (void function now). + */ +int radeon_driver_firstopen_kms(struct drm_device *dev) +{ + return 0; +} + + +void radeon_driver_lastclose_kms(struct drm_device *dev) +{ +} + +int radeon_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv) +{ + return 0; +} + +void radeon_driver_postclose_kms(struct drm_device *dev, + struct drm_file *file_priv) +{ +} + +void radeon_driver_preclose_kms(struct drm_device *dev, + struct drm_file *file_priv) +{ +} + + +/* + * VBlank related functions. + */ +u32 radeon_get_vblank_counter_kms(struct drm_device *dev, int crtc) +{ + /* FIXME: implement */ + return 0; +} + +int radeon_enable_vblank_kms(struct drm_device *dev, int crtc) +{ + /* FIXME: implement */ + return 0; +} + +void radeon_disable_vblank_kms(struct drm_device *dev, int crtc) +{ + /* FIXME: implement */ +} + + +/* + * For multiple master (like multiple X). + */ +struct drm_radeon_master_private { + drm_local_map_t *sarea; + drm_radeon_sarea_t *sarea_priv; +}; + +int radeon_master_create_kms(struct drm_device *dev, struct drm_master *master) +{ + struct drm_radeon_master_private *master_priv; + unsigned long sareapage; + int ret; + + master_priv = kzalloc(sizeof(*master_priv), GFP_KERNEL); + if (master_priv == NULL) { + return -ENOMEM; + } + /* prebuild the SAREA */ + sareapage = max_t(unsigned long, SAREA_MAX, PAGE_SIZE); + ret = drm_addmap(dev, 0, sareapage, _DRM_SHM, + _DRM_CONTAINS_LOCK, + &master_priv->sarea); + if (ret) { + DRM_ERROR("SAREA setup failed\n"); + return ret; + } + master_priv->sarea_priv = master_priv->sarea->handle + sizeof(struct drm_sarea); + master_priv->sarea_priv->pfCurrentPage = 0; + master->driver_priv = master_priv; + return 0; +} + +void radeon_master_destroy_kms(struct drm_device *dev, + struct drm_master *master) +{ + struct drm_radeon_master_private *master_priv = master->driver_priv; + + if (master_priv == NULL) { + return; + } + if (master_priv->sarea) { + drm_rmmap_locked(dev, master_priv->sarea); + } + kfree(master_priv); + master->driver_priv = NULL; +} + + +/* + * IOCTL. + */ +int radeon_dma_ioctl_kms(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + /* Not valid in KMS. */ + return -EINVAL; +} + +#define KMS_INVALID_IOCTL(name) \ +int name(struct drm_device *dev, void *data, struct drm_file *file_priv)\ +{ \ + DRM_ERROR("invalid ioctl with kms %s\n", __func__); \ + return -EINVAL; \ +} + +/* + * All these ioctls are invalid in kms world. + */ +KMS_INVALID_IOCTL(radeon_cp_init_kms) +KMS_INVALID_IOCTL(radeon_cp_start_kms) +KMS_INVALID_IOCTL(radeon_cp_stop_kms) +KMS_INVALID_IOCTL(radeon_cp_reset_kms) +KMS_INVALID_IOCTL(radeon_cp_idle_kms) +KMS_INVALID_IOCTL(radeon_cp_resume_kms) +KMS_INVALID_IOCTL(radeon_engine_reset_kms) +KMS_INVALID_IOCTL(radeon_fullscreen_kms) +KMS_INVALID_IOCTL(radeon_cp_swap_kms) +KMS_INVALID_IOCTL(radeon_cp_clear_kms) +KMS_INVALID_IOCTL(radeon_cp_vertex_kms) +KMS_INVALID_IOCTL(radeon_cp_indices_kms) +KMS_INVALID_IOCTL(radeon_cp_texture_kms) +KMS_INVALID_IOCTL(radeon_cp_stipple_kms) +KMS_INVALID_IOCTL(radeon_cp_indirect_kms) +KMS_INVALID_IOCTL(radeon_cp_vertex2_kms) +KMS_INVALID_IOCTL(radeon_cp_cmdbuf_kms) +KMS_INVALID_IOCTL(radeon_cp_getparam_kms) +KMS_INVALID_IOCTL(radeon_cp_flip_kms) +KMS_INVALID_IOCTL(radeon_mem_alloc_kms) +KMS_INVALID_IOCTL(radeon_mem_free_kms) +KMS_INVALID_IOCTL(radeon_mem_init_heap_kms) +KMS_INVALID_IOCTL(radeon_irq_emit_kms) +KMS_INVALID_IOCTL(radeon_irq_wait_kms) +KMS_INVALID_IOCTL(radeon_cp_setparam_kms) +KMS_INVALID_IOCTL(radeon_surface_alloc_kms) +KMS_INVALID_IOCTL(radeon_surface_free_kms) + + +struct drm_ioctl_desc radeon_ioctls_kms[] = { + DRM_IOCTL_DEF(DRM_RADEON_CP_INIT, radeon_cp_init_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_RADEON_CP_START, radeon_cp_start_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_RADEON_CP_STOP, radeon_cp_stop_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_RADEON_CP_RESET, radeon_cp_reset_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_RADEON_CP_IDLE, radeon_cp_idle_kms, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_CP_RESUME, radeon_cp_resume_kms, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_RESET, radeon_engine_reset_kms, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_FULLSCREEN, radeon_fullscreen_kms, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_SWAP, radeon_cp_swap_kms, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_CLEAR, radeon_cp_clear_kms, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_VERTEX, radeon_cp_vertex_kms, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_INDICES, radeon_cp_indices_kms, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_TEXTURE, radeon_cp_texture_kms, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_STIPPLE, radeon_cp_stipple_kms, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_INDIRECT, radeon_cp_indirect_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_RADEON_VERTEX2, radeon_cp_vertex2_kms, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_CMDBUF, radeon_cp_cmdbuf_kms, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_GETPARAM, radeon_cp_getparam_kms, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_FLIP, radeon_cp_flip_kms, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_ALLOC, radeon_mem_alloc_kms, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_FREE, radeon_mem_free_kms, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_INIT_HEAP, radeon_mem_init_heap_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_RADEON_IRQ_EMIT, radeon_irq_emit_kms, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_IRQ_WAIT, radeon_irq_wait_kms, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_SETPARAM, radeon_cp_setparam_kms, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_SURF_ALLOC, radeon_surface_alloc_kms, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_SURF_FREE, radeon_surface_free_kms, DRM_AUTH), + /* KMS */ + DRM_IOCTL_DEF(DRM_RADEON_GEM_INFO, radeon_gem_info_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_GEM_CREATE, radeon_gem_create_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_GEM_MMAP, radeon_gem_mmap_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_GEM_SET_DOMAIN, radeon_gem_set_domain_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_GEM_PREAD, radeon_gem_pread_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_GEM_PWRITE, radeon_gem_pwrite_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_GEM_WAIT_IDLE, radeon_gem_wait_idle_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_CS, radeon_cs_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_INFO, radeon_info_ioctl, DRM_AUTH), +}; +int radeon_max_kms_ioctl = DRM_ARRAY_SIZE(radeon_ioctls_kms); diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c new file mode 100644 index 000000000000..8086ecf7f03d --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c @@ -0,0 +1,1276 @@ +/* + * Copyright 2007-8 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Dave Airlie + * Alex Deucher + */ +#include +#include +#include +#include "radeon_fixed.h" +#include "radeon.h" + +void radeon_restore_common_regs(struct drm_device *dev) +{ + /* don't need this yet */ +} + +static void radeon_pll_wait_for_read_update_complete(struct drm_device *dev) +{ + struct radeon_device *rdev = dev->dev_private; + int i = 0; + + /* FIXME: Certain revisions of R300 can't recover here. Not sure of + the cause yet, but this workaround will mask the problem for now. + Other chips usually will pass at the very first test, so the + workaround shouldn't have any effect on them. */ + for (i = 0; + (i < 10000 && + RREG32_PLL(RADEON_PPLL_REF_DIV) & RADEON_PPLL_ATOMIC_UPDATE_R); + i++); +} + +static void radeon_pll_write_update(struct drm_device *dev) +{ + struct radeon_device *rdev = dev->dev_private; + + while (RREG32_PLL(RADEON_PPLL_REF_DIV) & RADEON_PPLL_ATOMIC_UPDATE_R); + + WREG32_PLL_P(RADEON_PPLL_REF_DIV, + RADEON_PPLL_ATOMIC_UPDATE_W, + ~(RADEON_PPLL_ATOMIC_UPDATE_W)); +} + +static void radeon_pll2_wait_for_read_update_complete(struct drm_device *dev) +{ + struct radeon_device *rdev = dev->dev_private; + int i = 0; + + + /* FIXME: Certain revisions of R300 can't recover here. Not sure of + the cause yet, but this workaround will mask the problem for now. + Other chips usually will pass at the very first test, so the + workaround shouldn't have any effect on them. */ + for (i = 0; + (i < 10000 && + RREG32_PLL(RADEON_P2PLL_REF_DIV) & RADEON_P2PLL_ATOMIC_UPDATE_R); + i++); +} + +static void radeon_pll2_write_update(struct drm_device *dev) +{ + struct radeon_device *rdev = dev->dev_private; + + while (RREG32_PLL(RADEON_P2PLL_REF_DIV) & RADEON_P2PLL_ATOMIC_UPDATE_R); + + WREG32_PLL_P(RADEON_P2PLL_REF_DIV, + RADEON_P2PLL_ATOMIC_UPDATE_W, + ~(RADEON_P2PLL_ATOMIC_UPDATE_W)); +} + +static uint8_t radeon_compute_pll_gain(uint16_t ref_freq, uint16_t ref_div, + uint16_t fb_div) +{ + unsigned int vcoFreq; + + if (!ref_div) + return 1; + + vcoFreq = ((unsigned)ref_freq & fb_div) / ref_div; + + /* + * This is horribly crude: the VCO frequency range is divided into + * 3 parts, each part having a fixed PLL gain value. + */ + if (vcoFreq >= 30000) + /* + * [300..max] MHz : 7 + */ + return 7; + else if (vcoFreq >= 18000) + /* + * [180..300) MHz : 4 + */ + return 4; + else + /* + * [0..180) MHz : 1 + */ + return 1; +} + +void radeon_crtc_dpms(struct drm_crtc *crtc, int mode) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct radeon_device *rdev = dev->dev_private; + uint32_t mask; + + if (radeon_crtc->crtc_id) + mask = (RADEON_CRTC2_EN | + RADEON_CRTC2_DISP_DIS | + RADEON_CRTC2_VSYNC_DIS | + RADEON_CRTC2_HSYNC_DIS | + RADEON_CRTC2_DISP_REQ_EN_B); + else + mask = (RADEON_CRTC_DISPLAY_DIS | + RADEON_CRTC_VSYNC_DIS | + RADEON_CRTC_HSYNC_DIS); + + switch (mode) { + case DRM_MODE_DPMS_ON: + if (radeon_crtc->crtc_id) + WREG32_P(RADEON_CRTC2_GEN_CNTL, RADEON_CRTC2_EN, ~mask); + else { + WREG32_P(RADEON_CRTC_GEN_CNTL, RADEON_CRTC_EN, ~(RADEON_CRTC_EN | + RADEON_CRTC_DISP_REQ_EN_B)); + WREG32_P(RADEON_CRTC_EXT_CNTL, 0, ~mask); + } + break; + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + if (radeon_crtc->crtc_id) + WREG32_P(RADEON_CRTC2_GEN_CNTL, mask, ~mask); + else { + WREG32_P(RADEON_CRTC_GEN_CNTL, RADEON_CRTC_DISP_REQ_EN_B, ~(RADEON_CRTC_EN | + RADEON_CRTC_DISP_REQ_EN_B)); + WREG32_P(RADEON_CRTC_EXT_CNTL, mask, ~mask); + } + break; + } + + if (mode != DRM_MODE_DPMS_OFF) { + radeon_crtc_load_lut(crtc); + } +} + +/* properly set crtc bpp when using atombios */ +void radeon_legacy_atom_set_surface(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + int format; + uint32_t crtc_gen_cntl; + uint32_t disp_merge_cntl; + uint32_t crtc_pitch; + + switch (crtc->fb->bits_per_pixel) { + case 15: /* 555 */ + format = 3; + break; + case 16: /* 565 */ + format = 4; + break; + case 24: /* RGB */ + format = 5; + break; + case 32: /* xRGB */ + format = 6; + break; + default: + return; + } + + crtc_pitch = ((((crtc->fb->pitch / (crtc->fb->bits_per_pixel / 8)) * crtc->fb->bits_per_pixel) + + ((crtc->fb->bits_per_pixel * 8) - 1)) / + (crtc->fb->bits_per_pixel * 8)); + crtc_pitch |= crtc_pitch << 16; + + WREG32(RADEON_CRTC_PITCH + radeon_crtc->crtc_offset, crtc_pitch); + + switch (radeon_crtc->crtc_id) { + case 0: + disp_merge_cntl = RREG32(RADEON_DISP_MERGE_CNTL); + disp_merge_cntl &= ~RADEON_DISP_RGB_OFFSET_EN; + WREG32(RADEON_DISP_MERGE_CNTL, disp_merge_cntl); + + crtc_gen_cntl = RREG32(RADEON_CRTC_GEN_CNTL) & 0xfffff0ff; + crtc_gen_cntl |= (format << 8); + crtc_gen_cntl |= RADEON_CRTC_EXT_DISP_EN; + WREG32(RADEON_CRTC_GEN_CNTL, crtc_gen_cntl); + break; + case 1: + disp_merge_cntl = RREG32(RADEON_DISP2_MERGE_CNTL); + disp_merge_cntl &= ~RADEON_DISP2_RGB_OFFSET_EN; + WREG32(RADEON_DISP2_MERGE_CNTL, disp_merge_cntl); + + crtc_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL) & 0xfffff0ff; + crtc_gen_cntl |= (format << 8); + WREG32(RADEON_CRTC2_GEN_CNTL, crtc_gen_cntl); + WREG32(RADEON_FP_H2_SYNC_STRT_WID, RREG32(RADEON_CRTC2_H_SYNC_STRT_WID)); + WREG32(RADEON_FP_V2_SYNC_STRT_WID, RREG32(RADEON_CRTC2_V_SYNC_STRT_WID)); + break; + } +} + +int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y, + struct drm_framebuffer *old_fb) +{ + struct drm_device *dev = crtc->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct radeon_framebuffer *radeon_fb; + struct drm_gem_object *obj; + uint64_t base; + uint32_t crtc_offset, crtc_offset_cntl, crtc_tile_x0_y0 = 0; + uint32_t crtc_pitch, pitch_pixels; + + DRM_DEBUG("\n"); + + radeon_fb = to_radeon_framebuffer(crtc->fb); + + obj = radeon_fb->obj; + if (radeon_gem_object_pin(obj, RADEON_GEM_DOMAIN_VRAM, &base)) { + return -EINVAL; + } + crtc_offset = (u32)base; + crtc_offset_cntl = 0; + + pitch_pixels = crtc->fb->pitch / (crtc->fb->bits_per_pixel / 8); + crtc_pitch = (((pitch_pixels * crtc->fb->bits_per_pixel) + + ((crtc->fb->bits_per_pixel * 8) - 1)) / + (crtc->fb->bits_per_pixel * 8)); + crtc_pitch |= crtc_pitch << 16; + + /* TODO tiling */ + if (0) { + if (ASIC_IS_R300(rdev)) + crtc_offset_cntl |= (R300_CRTC_X_Y_MODE_EN | + R300_CRTC_MICRO_TILE_BUFFER_DIS | + R300_CRTC_MACRO_TILE_EN); + else + crtc_offset_cntl |= RADEON_CRTC_TILE_EN; + } else { + if (ASIC_IS_R300(rdev)) + crtc_offset_cntl &= ~(R300_CRTC_X_Y_MODE_EN | + R300_CRTC_MICRO_TILE_BUFFER_DIS | + R300_CRTC_MACRO_TILE_EN); + else + crtc_offset_cntl &= ~RADEON_CRTC_TILE_EN; + } + + + /* TODO more tiling */ + if (0) { + if (ASIC_IS_R300(rdev)) { + crtc_tile_x0_y0 = x | (y << 16); + base &= ~0x7ff; + } else { + int byteshift = crtc->fb->bits_per_pixel >> 4; + int tile_addr = (((y >> 3) * crtc->fb->width + x) >> (8 - byteshift)) << 11; + base += tile_addr + ((x << byteshift) % 256) + ((y % 8) << 8); + crtc_offset_cntl |= (y % 16); + } + } else { + int offset = y * pitch_pixels + x; + switch (crtc->fb->bits_per_pixel) { + case 15: + case 16: + offset *= 2; + break; + case 24: + offset *= 3; + break; + case 32: + offset *= 4; + break; + default: + return false; + } + base += offset; + } + + base &= ~7; + + /* update sarea TODO */ + + crtc_offset = (u32)base; + + WREG32(RADEON_DISPLAY_BASE_ADDR + radeon_crtc->crtc_offset, rdev->mc.vram_location); + + if (ASIC_IS_R300(rdev)) { + if (radeon_crtc->crtc_id) + WREG32(R300_CRTC2_TILE_X0_Y0, crtc_tile_x0_y0); + else + WREG32(R300_CRTC_TILE_X0_Y0, crtc_tile_x0_y0); + } + WREG32(RADEON_CRTC_OFFSET_CNTL + radeon_crtc->crtc_offset, crtc_offset_cntl); + WREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset, crtc_offset); + WREG32(RADEON_CRTC_PITCH + radeon_crtc->crtc_offset, crtc_pitch); + + if (old_fb && old_fb != crtc->fb) { + radeon_fb = to_radeon_framebuffer(old_fb); + radeon_gem_object_unpin(radeon_fb->obj); + } + return 0; +} + +static bool radeon_set_crtc_timing(struct drm_crtc *crtc, struct drm_display_mode *mode) +{ + struct drm_device *dev = crtc->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + int format; + int hsync_start; + int hsync_wid; + int vsync_wid; + uint32_t crtc_h_total_disp; + uint32_t crtc_h_sync_strt_wid; + uint32_t crtc_v_total_disp; + uint32_t crtc_v_sync_strt_wid; + + DRM_DEBUG("\n"); + + switch (crtc->fb->bits_per_pixel) { + case 15: /* 555 */ + format = 3; + break; + case 16: /* 565 */ + format = 4; + break; + case 24: /* RGB */ + format = 5; + break; + case 32: /* xRGB */ + format = 6; + break; + default: + return false; + } + + crtc_h_total_disp = ((((mode->crtc_htotal / 8) - 1) & 0x3ff) + | ((((mode->crtc_hdisplay / 8) - 1) & 0x1ff) << 16)); + + hsync_wid = (mode->crtc_hsync_end - mode->crtc_hsync_start) / 8; + if (!hsync_wid) + hsync_wid = 1; + hsync_start = mode->crtc_hsync_start - 8; + + crtc_h_sync_strt_wid = ((hsync_start & 0x1fff) + | ((hsync_wid & 0x3f) << 16) + | ((mode->flags & DRM_MODE_FLAG_NHSYNC) + ? RADEON_CRTC_H_SYNC_POL + : 0)); + + /* This works for double scan mode. */ + crtc_v_total_disp = (((mode->crtc_vtotal - 1) & 0xffff) + | ((mode->crtc_vdisplay - 1) << 16)); + + vsync_wid = mode->crtc_vsync_end - mode->crtc_vsync_start; + if (!vsync_wid) + vsync_wid = 1; + + crtc_v_sync_strt_wid = (((mode->crtc_vsync_start - 1) & 0xfff) + | ((vsync_wid & 0x1f) << 16) + | ((mode->flags & DRM_MODE_FLAG_NVSYNC) + ? RADEON_CRTC_V_SYNC_POL + : 0)); + + /* TODO -> Dell Server */ + if (0) { + uint32_t disp_hw_debug = RREG32(RADEON_DISP_HW_DEBUG); + uint32_t tv_dac_cntl = RREG32(RADEON_TV_DAC_CNTL); + uint32_t dac2_cntl = RREG32(RADEON_DAC_CNTL2); + uint32_t crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL); + + dac2_cntl &= ~RADEON_DAC2_DAC_CLK_SEL; + dac2_cntl |= RADEON_DAC2_DAC2_CLK_SEL; + + /* For CRT on DAC2, don't turn it on if BIOS didn't + enable it, even it's detected. + */ + disp_hw_debug |= RADEON_CRT2_DISP1_SEL; + tv_dac_cntl &= ~((1<<2) | (3<<8) | (7<<24) | (0xff<<16)); + tv_dac_cntl |= (0x03 | (2<<8) | (0x58<<16)); + + WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl); + WREG32(RADEON_DISP_HW_DEBUG, disp_hw_debug); + WREG32(RADEON_DAC_CNTL2, dac2_cntl); + WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl); + } + + if (radeon_crtc->crtc_id) { + uint32_t crtc2_gen_cntl; + uint32_t disp2_merge_cntl; + + /* check to see if TV DAC is enabled for another crtc and keep it enabled */ + if (RREG32(RADEON_CRTC2_GEN_CNTL) & RADEON_CRTC2_CRT2_ON) + crtc2_gen_cntl = RADEON_CRTC2_CRT2_ON; + else + crtc2_gen_cntl = 0; + + crtc2_gen_cntl |= ((format << 8) + | RADEON_CRTC2_VSYNC_DIS + | RADEON_CRTC2_HSYNC_DIS + | RADEON_CRTC2_DISP_DIS + | RADEON_CRTC2_DISP_REQ_EN_B + | ((mode->flags & DRM_MODE_FLAG_DBLSCAN) + ? RADEON_CRTC2_DBL_SCAN_EN + : 0) + | ((mode->flags & DRM_MODE_FLAG_CSYNC) + ? RADEON_CRTC2_CSYNC_EN + : 0) + | ((mode->flags & DRM_MODE_FLAG_INTERLACE) + ? RADEON_CRTC2_INTERLACE_EN + : 0)); + + disp2_merge_cntl = RREG32(RADEON_DISP2_MERGE_CNTL); + disp2_merge_cntl &= ~RADEON_DISP2_RGB_OFFSET_EN; + + WREG32(RADEON_DISP2_MERGE_CNTL, disp2_merge_cntl); + WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl); + } else { + uint32_t crtc_gen_cntl; + uint32_t crtc_ext_cntl; + uint32_t disp_merge_cntl; + + crtc_gen_cntl = (RADEON_CRTC_EXT_DISP_EN + | (format << 8) + | RADEON_CRTC_DISP_REQ_EN_B + | ((mode->flags & DRM_MODE_FLAG_DBLSCAN) + ? RADEON_CRTC_DBL_SCAN_EN + : 0) + | ((mode->flags & DRM_MODE_FLAG_CSYNC) + ? RADEON_CRTC_CSYNC_EN + : 0) + | ((mode->flags & DRM_MODE_FLAG_INTERLACE) + ? RADEON_CRTC_INTERLACE_EN + : 0)); + + crtc_ext_cntl = RREG32(RADEON_CRTC_EXT_CNTL); + crtc_ext_cntl |= (RADEON_XCRT_CNT_EN | + RADEON_CRTC_VSYNC_DIS | + RADEON_CRTC_HSYNC_DIS | + RADEON_CRTC_DISPLAY_DIS); + + disp_merge_cntl = RREG32(RADEON_DISP_MERGE_CNTL); + disp_merge_cntl &= ~RADEON_DISP_RGB_OFFSET_EN; + + WREG32(RADEON_DISP_MERGE_CNTL, disp_merge_cntl); + WREG32(RADEON_CRTC_GEN_CNTL, crtc_gen_cntl); + WREG32(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl); + } + + WREG32(RADEON_CRTC_H_TOTAL_DISP + radeon_crtc->crtc_offset, crtc_h_total_disp); + WREG32(RADEON_CRTC_H_SYNC_STRT_WID + radeon_crtc->crtc_offset, crtc_h_sync_strt_wid); + WREG32(RADEON_CRTC_V_TOTAL_DISP + radeon_crtc->crtc_offset, crtc_v_total_disp); + WREG32(RADEON_CRTC_V_SYNC_STRT_WID + radeon_crtc->crtc_offset, crtc_v_sync_strt_wid); + + return true; +} + +static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) +{ + struct drm_device *dev = crtc->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_encoder *encoder; + uint32_t feedback_div = 0; + uint32_t frac_fb_div = 0; + uint32_t reference_div = 0; + uint32_t post_divider = 0; + uint32_t freq = 0; + uint8_t pll_gain; + int pll_flags = RADEON_PLL_LEGACY; + bool use_bios_divs = false; + /* PLL registers */ + uint32_t pll_ref_div = 0; + uint32_t pll_fb_post_div = 0; + uint32_t htotal_cntl = 0; + + struct radeon_pll *pll; + + struct { + int divider; + int bitvalue; + } *post_div, post_divs[] = { + /* From RAGE 128 VR/RAGE 128 GL Register + * Reference Manual (Technical Reference + * Manual P/N RRG-G04100-C Rev. 0.04), page + * 3-17 (PLL_DIV_[3:0]). + */ + { 1, 0 }, /* VCLK_SRC */ + { 2, 1 }, /* VCLK_SRC/2 */ + { 4, 2 }, /* VCLK_SRC/4 */ + { 8, 3 }, /* VCLK_SRC/8 */ + { 3, 4 }, /* VCLK_SRC/3 */ + { 16, 5 }, /* VCLK_SRC/16 */ + { 6, 6 }, /* VCLK_SRC/6 */ + { 12, 7 }, /* VCLK_SRC/12 */ + { 0, 0 } + }; + + if (radeon_crtc->crtc_id) + pll = &rdev->clock.p2pll; + else + pll = &rdev->clock.p1pll; + + if (mode->clock > 200000) /* range limits??? */ + pll_flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; + else + pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV; + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + if (encoder->crtc == crtc) { + if (encoder->encoder_type != DRM_MODE_ENCODER_DAC) + pll_flags |= RADEON_PLL_NO_ODD_POST_DIV; + if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS) { + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_encoder_lvds *lvds = (struct radeon_encoder_lvds *)radeon_encoder->enc_priv; + if (lvds) { + if (lvds->use_bios_dividers) { + pll_ref_div = lvds->panel_ref_divider; + pll_fb_post_div = (lvds->panel_fb_divider | + (lvds->panel_post_divider << 16)); + htotal_cntl = 0; + use_bios_divs = true; + } + } + pll_flags |= RADEON_PLL_USE_REF_DIV; + } + } + } + + DRM_DEBUG("\n"); + + if (!use_bios_divs) { + radeon_compute_pll(pll, mode->clock, + &freq, &feedback_div, &frac_fb_div, + &reference_div, &post_divider, + pll_flags); + + for (post_div = &post_divs[0]; post_div->divider; ++post_div) { + if (post_div->divider == post_divider) + break; + } + + if (!post_div->divider) + post_div = &post_divs[0]; + + DRM_DEBUG("dc=%u, fd=%d, rd=%d, pd=%d\n", + (unsigned)freq, + feedback_div, + reference_div, + post_divider); + + pll_ref_div = reference_div; +#if defined(__powerpc__) && (0) /* TODO */ + /* apparently programming this otherwise causes a hang??? */ + if (info->MacModel == RADEON_MAC_IBOOK) + pll_fb_post_div = 0x000600ad; + else +#endif + pll_fb_post_div = (feedback_div | (post_div->bitvalue << 16)); + + htotal_cntl = mode->htotal & 0x7; + + } + + pll_gain = radeon_compute_pll_gain(pll->reference_freq, + pll_ref_div & 0x3ff, + pll_fb_post_div & 0x7ff); + + if (radeon_crtc->crtc_id) { + uint32_t pixclks_cntl = ((RREG32_PLL(RADEON_PIXCLKS_CNTL) & + ~(RADEON_PIX2CLK_SRC_SEL_MASK)) | + RADEON_PIX2CLK_SRC_SEL_P2PLLCLK); + + WREG32_PLL_P(RADEON_PIXCLKS_CNTL, + RADEON_PIX2CLK_SRC_SEL_CPUCLK, + ~(RADEON_PIX2CLK_SRC_SEL_MASK)); + + WREG32_PLL_P(RADEON_P2PLL_CNTL, + RADEON_P2PLL_RESET + | RADEON_P2PLL_ATOMIC_UPDATE_EN + | ((uint32_t)pll_gain << RADEON_P2PLL_PVG_SHIFT), + ~(RADEON_P2PLL_RESET + | RADEON_P2PLL_ATOMIC_UPDATE_EN + | RADEON_P2PLL_PVG_MASK)); + + WREG32_PLL_P(RADEON_P2PLL_REF_DIV, + pll_ref_div, + ~RADEON_P2PLL_REF_DIV_MASK); + + WREG32_PLL_P(RADEON_P2PLL_DIV_0, + pll_fb_post_div, + ~RADEON_P2PLL_FB0_DIV_MASK); + + WREG32_PLL_P(RADEON_P2PLL_DIV_0, + pll_fb_post_div, + ~RADEON_P2PLL_POST0_DIV_MASK); + + radeon_pll2_write_update(dev); + radeon_pll2_wait_for_read_update_complete(dev); + + WREG32_PLL(RADEON_HTOTAL2_CNTL, htotal_cntl); + + WREG32_PLL_P(RADEON_P2PLL_CNTL, + 0, + ~(RADEON_P2PLL_RESET + | RADEON_P2PLL_SLEEP + | RADEON_P2PLL_ATOMIC_UPDATE_EN)); + + DRM_DEBUG("Wrote2: 0x%08x 0x%08x 0x%08x (0x%08x)\n", + (unsigned)pll_ref_div, + (unsigned)pll_fb_post_div, + (unsigned)htotal_cntl, + RREG32_PLL(RADEON_P2PLL_CNTL)); + DRM_DEBUG("Wrote2: rd=%u, fd=%u, pd=%u\n", + (unsigned)pll_ref_div & RADEON_P2PLL_REF_DIV_MASK, + (unsigned)pll_fb_post_div & RADEON_P2PLL_FB0_DIV_MASK, + (unsigned)((pll_fb_post_div & + RADEON_P2PLL_POST0_DIV_MASK) >> 16)); + + mdelay(50); /* Let the clock to lock */ + + WREG32_PLL_P(RADEON_PIXCLKS_CNTL, + RADEON_PIX2CLK_SRC_SEL_P2PLLCLK, + ~(RADEON_PIX2CLK_SRC_SEL_MASK)); + + WREG32_PLL(RADEON_PIXCLKS_CNTL, pixclks_cntl); + } else { + if (rdev->flags & RADEON_IS_MOBILITY) { + /* A temporal workaround for the occational blanking on certain laptop panels. + This appears to related to the PLL divider registers (fail to lock?). + It occurs even when all dividers are the same with their old settings. + In this case we really don't need to fiddle with PLL registers. + By doing this we can avoid the blanking problem with some panels. + */ + if ((pll_ref_div == (RREG32_PLL(RADEON_PPLL_REF_DIV) & RADEON_PPLL_REF_DIV_MASK)) && + (pll_fb_post_div == (RREG32_PLL(RADEON_PPLL_DIV_3) & + (RADEON_PPLL_POST3_DIV_MASK | RADEON_PPLL_FB3_DIV_MASK)))) { + WREG32_P(RADEON_CLOCK_CNTL_INDEX, + RADEON_PLL_DIV_SEL, + ~(RADEON_PLL_DIV_SEL)); + r100_pll_errata_after_index(rdev); + return; + } + } + + WREG32_PLL_P(RADEON_VCLK_ECP_CNTL, + RADEON_VCLK_SRC_SEL_CPUCLK, + ~(RADEON_VCLK_SRC_SEL_MASK)); + WREG32_PLL_P(RADEON_PPLL_CNTL, + RADEON_PPLL_RESET + | RADEON_PPLL_ATOMIC_UPDATE_EN + | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN + | ((uint32_t)pll_gain << RADEON_PPLL_PVG_SHIFT), + ~(RADEON_PPLL_RESET + | RADEON_PPLL_ATOMIC_UPDATE_EN + | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN + | RADEON_PPLL_PVG_MASK)); + + WREG32_P(RADEON_CLOCK_CNTL_INDEX, + RADEON_PLL_DIV_SEL, + ~(RADEON_PLL_DIV_SEL)); + r100_pll_errata_after_index(rdev); + + if (ASIC_IS_R300(rdev) || + (rdev->family == CHIP_RS300) || + (rdev->family == CHIP_RS400) || + (rdev->family == CHIP_RS480)) { + if (pll_ref_div & R300_PPLL_REF_DIV_ACC_MASK) { + /* When restoring console mode, use saved PPLL_REF_DIV + * setting. + */ + WREG32_PLL_P(RADEON_PPLL_REF_DIV, + pll_ref_div, + 0); + } else { + /* R300 uses ref_div_acc field as real ref divider */ + WREG32_PLL_P(RADEON_PPLL_REF_DIV, + (pll_ref_div << R300_PPLL_REF_DIV_ACC_SHIFT), + ~R300_PPLL_REF_DIV_ACC_MASK); + } + } else + WREG32_PLL_P(RADEON_PPLL_REF_DIV, + pll_ref_div, + ~RADEON_PPLL_REF_DIV_MASK); + + WREG32_PLL_P(RADEON_PPLL_DIV_3, + pll_fb_post_div, + ~RADEON_PPLL_FB3_DIV_MASK); + + WREG32_PLL_P(RADEON_PPLL_DIV_3, + pll_fb_post_div, + ~RADEON_PPLL_POST3_DIV_MASK); + + radeon_pll_write_update(dev); + radeon_pll_wait_for_read_update_complete(dev); + + WREG32_PLL(RADEON_HTOTAL_CNTL, htotal_cntl); + + WREG32_PLL_P(RADEON_PPLL_CNTL, + 0, + ~(RADEON_PPLL_RESET + | RADEON_PPLL_SLEEP + | RADEON_PPLL_ATOMIC_UPDATE_EN + | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN)); + + DRM_DEBUG("Wrote: 0x%08x 0x%08x 0x%08x (0x%08x)\n", + pll_ref_div, + pll_fb_post_div, + (unsigned)htotal_cntl, + RREG32_PLL(RADEON_PPLL_CNTL)); + DRM_DEBUG("Wrote: rd=%d, fd=%d, pd=%d\n", + pll_ref_div & RADEON_PPLL_REF_DIV_MASK, + pll_fb_post_div & RADEON_PPLL_FB3_DIV_MASK, + (pll_fb_post_div & RADEON_PPLL_POST3_DIV_MASK) >> 16); + + mdelay(50); /* Let the clock to lock */ + + WREG32_PLL_P(RADEON_VCLK_ECP_CNTL, + RADEON_VCLK_SRC_SEL_PPLLCLK, + ~(RADEON_VCLK_SRC_SEL_MASK)); + + } +} + +static bool radeon_crtc_mode_fixup(struct drm_crtc *crtc, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + return true; +} + +static int radeon_crtc_mode_set(struct drm_crtc *crtc, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode, + int x, int y, struct drm_framebuffer *old_fb) +{ + + DRM_DEBUG("\n"); + + /* TODO TV */ + + radeon_crtc_set_base(crtc, x, y, old_fb); + radeon_set_crtc_timing(crtc, adjusted_mode); + radeon_set_pll(crtc, adjusted_mode); + radeon_init_disp_bandwidth(crtc->dev); + + return 0; +} + +static void radeon_crtc_prepare(struct drm_crtc *crtc) +{ + radeon_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); +} + +static void radeon_crtc_commit(struct drm_crtc *crtc) +{ + radeon_crtc_dpms(crtc, DRM_MODE_DPMS_ON); +} + +static const struct drm_crtc_helper_funcs legacy_helper_funcs = { + .dpms = radeon_crtc_dpms, + .mode_fixup = radeon_crtc_mode_fixup, + .mode_set = radeon_crtc_mode_set, + .mode_set_base = radeon_crtc_set_base, + .prepare = radeon_crtc_prepare, + .commit = radeon_crtc_commit, +}; + + +void radeon_legacy_init_crtc(struct drm_device *dev, + struct radeon_crtc *radeon_crtc) +{ + if (radeon_crtc->crtc_id == 1) + radeon_crtc->crtc_offset = RADEON_CRTC2_H_TOTAL_DISP - RADEON_CRTC_H_TOTAL_DISP; + drm_crtc_helper_add(&radeon_crtc->base, &legacy_helper_funcs); +} + +void radeon_init_disp_bw_legacy(struct drm_device *dev, + struct drm_display_mode *mode1, + uint32_t pixel_bytes1, + struct drm_display_mode *mode2, + uint32_t pixel_bytes2) +{ + struct radeon_device *rdev = dev->dev_private; + fixed20_12 trcd_ff, trp_ff, tras_ff, trbs_ff, tcas_ff; + fixed20_12 sclk_ff, mclk_ff, sclk_eff_ff, sclk_delay_ff; + fixed20_12 peak_disp_bw, mem_bw, pix_clk, pix_clk2, temp_ff, crit_point_ff; + uint32_t temp, data, mem_trcd, mem_trp, mem_tras; + fixed20_12 memtcas_ff[8] = { + fixed_init(1), + fixed_init(2), + fixed_init(3), + fixed_init(0), + fixed_init_half(1), + fixed_init_half(2), + fixed_init(0), + }; + fixed20_12 memtcas_rs480_ff[8] = { + fixed_init(0), + fixed_init(1), + fixed_init(2), + fixed_init(3), + fixed_init(0), + fixed_init_half(1), + fixed_init_half(2), + fixed_init_half(3), + }; + fixed20_12 memtcas2_ff[8] = { + fixed_init(0), + fixed_init(1), + fixed_init(2), + fixed_init(3), + fixed_init(4), + fixed_init(5), + fixed_init(6), + fixed_init(7), + }; + fixed20_12 memtrbs[8] = { + fixed_init(1), + fixed_init_half(1), + fixed_init(2), + fixed_init_half(2), + fixed_init(3), + fixed_init_half(3), + fixed_init(4), + fixed_init_half(4) + }; + fixed20_12 memtrbs_r4xx[8] = { + fixed_init(4), + fixed_init(5), + fixed_init(6), + fixed_init(7), + fixed_init(8), + fixed_init(9), + fixed_init(10), + fixed_init(11) + }; + fixed20_12 min_mem_eff; + fixed20_12 mc_latency_sclk, mc_latency_mclk, k1; + fixed20_12 cur_latency_mclk, cur_latency_sclk; + fixed20_12 disp_latency, disp_latency_overhead, disp_drain_rate, + disp_drain_rate2, read_return_rate; + fixed20_12 time_disp1_drop_priority; + int c; + int cur_size = 16; /* in octawords */ + int critical_point = 0, critical_point2; +/* uint32_t read_return_rate, time_disp1_drop_priority; */ + int stop_req, max_stop_req; + + min_mem_eff.full = rfixed_const_8(0); + /* get modes */ + if ((rdev->disp_priority == 2) && ASIC_IS_R300(rdev)) { + uint32_t mc_init_misc_lat_timer = RREG32(R300_MC_INIT_MISC_LAT_TIMER); + mc_init_misc_lat_timer &= ~(R300_MC_DISP1R_INIT_LAT_MASK << R300_MC_DISP1R_INIT_LAT_SHIFT); + mc_init_misc_lat_timer &= ~(R300_MC_DISP0R_INIT_LAT_MASK << R300_MC_DISP0R_INIT_LAT_SHIFT); + /* check crtc enables */ + if (mode2) + mc_init_misc_lat_timer |= (1 << R300_MC_DISP1R_INIT_LAT_SHIFT); + if (mode1) + mc_init_misc_lat_timer |= (1 << R300_MC_DISP0R_INIT_LAT_SHIFT); + WREG32(R300_MC_INIT_MISC_LAT_TIMER, mc_init_misc_lat_timer); + } + + /* + * determine is there is enough bw for current mode + */ + mclk_ff.full = rfixed_const(rdev->clock.default_mclk); + temp_ff.full = rfixed_const(100); + mclk_ff.full = rfixed_div(mclk_ff, temp_ff); + sclk_ff.full = rfixed_const(rdev->clock.default_sclk); + sclk_ff.full = rfixed_div(sclk_ff, temp_ff); + + temp = (rdev->mc.vram_width / 8) * (rdev->mc.vram_is_ddr ? 2 : 1); + temp_ff.full = rfixed_const(temp); + mem_bw.full = rfixed_mul(mclk_ff, temp_ff); + + pix_clk.full = 0; + pix_clk2.full = 0; + peak_disp_bw.full = 0; + if (mode1) { + temp_ff.full = rfixed_const(1000); + pix_clk.full = rfixed_const(mode1->clock); /* convert to fixed point */ + pix_clk.full = rfixed_div(pix_clk, temp_ff); + temp_ff.full = rfixed_const(pixel_bytes1); + peak_disp_bw.full += rfixed_mul(pix_clk, temp_ff); + } + if (mode2) { + temp_ff.full = rfixed_const(1000); + pix_clk2.full = rfixed_const(mode2->clock); /* convert to fixed point */ + pix_clk2.full = rfixed_div(pix_clk2, temp_ff); + temp_ff.full = rfixed_const(pixel_bytes2); + peak_disp_bw.full += rfixed_mul(pix_clk2, temp_ff); + } + + mem_bw.full = rfixed_mul(mem_bw, min_mem_eff); + if (peak_disp_bw.full >= mem_bw.full) { + DRM_ERROR("You may not have enough display bandwidth for current mode\n" + "If you have flickering problem, try to lower resolution, refresh rate, or color depth\n"); + } + + /* Get values from the EXT_MEM_CNTL register...converting its contents. */ + temp = RREG32(RADEON_MEM_TIMING_CNTL); + if ((rdev->family == CHIP_RV100) || (rdev->flags & RADEON_IS_IGP)) { /* RV100, M6, IGPs */ + mem_trcd = ((temp >> 2) & 0x3) + 1; + mem_trp = ((temp & 0x3)) + 1; + mem_tras = ((temp & 0x70) >> 4) + 1; + } else if (rdev->family == CHIP_R300 || + rdev->family == CHIP_R350) { /* r300, r350 */ + mem_trcd = (temp & 0x7) + 1; + mem_trp = ((temp >> 8) & 0x7) + 1; + mem_tras = ((temp >> 11) & 0xf) + 4; + } else if (rdev->family == CHIP_RV350 || + rdev->family <= CHIP_RV380) { + /* rv3x0 */ + mem_trcd = (temp & 0x7) + 3; + mem_trp = ((temp >> 8) & 0x7) + 3; + mem_tras = ((temp >> 11) & 0xf) + 6; + } else if (rdev->family == CHIP_R420 || + rdev->family == CHIP_R423 || + rdev->family == CHIP_RV410) { + /* r4xx */ + mem_trcd = (temp & 0xf) + 3; + if (mem_trcd > 15) + mem_trcd = 15; + mem_trp = ((temp >> 8) & 0xf) + 3; + if (mem_trp > 15) + mem_trp = 15; + mem_tras = ((temp >> 12) & 0x1f) + 6; + if (mem_tras > 31) + mem_tras = 31; + } else { /* RV200, R200 */ + mem_trcd = (temp & 0x7) + 1; + mem_trp = ((temp >> 8) & 0x7) + 1; + mem_tras = ((temp >> 12) & 0xf) + 4; + } + /* convert to FF */ + trcd_ff.full = rfixed_const(mem_trcd); + trp_ff.full = rfixed_const(mem_trp); + tras_ff.full = rfixed_const(mem_tras); + + /* Get values from the MEM_SDRAM_MODE_REG register...converting its */ + temp = RREG32(RADEON_MEM_SDRAM_MODE_REG); + data = (temp & (7 << 20)) >> 20; + if ((rdev->family == CHIP_RV100) || rdev->flags & RADEON_IS_IGP) { + if (rdev->family == CHIP_RS480) /* don't think rs400 */ + tcas_ff = memtcas_rs480_ff[data]; + else + tcas_ff = memtcas_ff[data]; + } else + tcas_ff = memtcas2_ff[data]; + + if (rdev->family == CHIP_RS400 || + rdev->family == CHIP_RS480) { + /* extra cas latency stored in bits 23-25 0-4 clocks */ + data = (temp >> 23) & 0x7; + if (data < 5) + tcas_ff.full += rfixed_const(data); + } + + if (ASIC_IS_R300(rdev) && !(rdev->flags & RADEON_IS_IGP)) { + /* on the R300, Tcas is included in Trbs. + */ + temp = RREG32(RADEON_MEM_CNTL); + data = (R300_MEM_NUM_CHANNELS_MASK & temp); + if (data == 1) { + if (R300_MEM_USE_CD_CH_ONLY & temp) { + temp = RREG32(R300_MC_IND_INDEX); + temp &= ~R300_MC_IND_ADDR_MASK; + temp |= R300_MC_READ_CNTL_CD_mcind; + WREG32(R300_MC_IND_INDEX, temp); + temp = RREG32(R300_MC_IND_DATA); + data = (R300_MEM_RBS_POSITION_C_MASK & temp); + } else { + temp = RREG32(R300_MC_READ_CNTL_AB); + data = (R300_MEM_RBS_POSITION_A_MASK & temp); + } + } else { + temp = RREG32(R300_MC_READ_CNTL_AB); + data = (R300_MEM_RBS_POSITION_A_MASK & temp); + } + if (rdev->family == CHIP_RV410 || + rdev->family == CHIP_R420 || + rdev->family == CHIP_R423) + trbs_ff = memtrbs_r4xx[data]; + else + trbs_ff = memtrbs[data]; + tcas_ff.full += trbs_ff.full; + } + + sclk_eff_ff.full = sclk_ff.full; + + if (rdev->flags & RADEON_IS_AGP) { + fixed20_12 agpmode_ff; + agpmode_ff.full = rfixed_const(radeon_agpmode); + temp_ff.full = rfixed_const_666(16); + sclk_eff_ff.full -= rfixed_mul(agpmode_ff, temp_ff); + } + /* TODO PCIE lanes may affect this - agpmode == 16?? */ + + if (ASIC_IS_R300(rdev)) { + sclk_delay_ff.full = rfixed_const(250); + } else { + if ((rdev->family == CHIP_RV100) || + rdev->flags & RADEON_IS_IGP) { + if (rdev->mc.vram_is_ddr) + sclk_delay_ff.full = rfixed_const(41); + else + sclk_delay_ff.full = rfixed_const(33); + } else { + if (rdev->mc.vram_width == 128) + sclk_delay_ff.full = rfixed_const(57); + else + sclk_delay_ff.full = rfixed_const(41); + } + } + + mc_latency_sclk.full = rfixed_div(sclk_delay_ff, sclk_eff_ff); + + if (rdev->mc.vram_is_ddr) { + if (rdev->mc.vram_width == 32) { + k1.full = rfixed_const(40); + c = 3; + } else { + k1.full = rfixed_const(20); + c = 1; + } + } else { + k1.full = rfixed_const(40); + c = 3; + } + + temp_ff.full = rfixed_const(2); + mc_latency_mclk.full = rfixed_mul(trcd_ff, temp_ff); + temp_ff.full = rfixed_const(c); + mc_latency_mclk.full += rfixed_mul(tcas_ff, temp_ff); + temp_ff.full = rfixed_const(4); + mc_latency_mclk.full += rfixed_mul(tras_ff, temp_ff); + mc_latency_mclk.full += rfixed_mul(trp_ff, temp_ff); + mc_latency_mclk.full += k1.full; + + mc_latency_mclk.full = rfixed_div(mc_latency_mclk, mclk_ff); + mc_latency_mclk.full += rfixed_div(temp_ff, sclk_eff_ff); + + /* + HW cursor time assuming worst case of full size colour cursor. + */ + temp_ff.full = rfixed_const((2 * (cur_size - (rdev->mc.vram_is_ddr + 1)))); + temp_ff.full += trcd_ff.full; + if (temp_ff.full < tras_ff.full) + temp_ff.full = tras_ff.full; + cur_latency_mclk.full = rfixed_div(temp_ff, mclk_ff); + + temp_ff.full = rfixed_const(cur_size); + cur_latency_sclk.full = rfixed_div(temp_ff, sclk_eff_ff); + /* + Find the total latency for the display data. + */ + disp_latency_overhead.full = rfixed_const(80); + disp_latency_overhead.full = rfixed_div(disp_latency_overhead, sclk_ff); + mc_latency_mclk.full += disp_latency_overhead.full + cur_latency_mclk.full; + mc_latency_sclk.full += disp_latency_overhead.full + cur_latency_sclk.full; + + if (mc_latency_mclk.full > mc_latency_sclk.full) + disp_latency.full = mc_latency_mclk.full; + else + disp_latency.full = mc_latency_sclk.full; + + /* setup Max GRPH_STOP_REQ default value */ + if (ASIC_IS_RV100(rdev)) + max_stop_req = 0x5c; + else + max_stop_req = 0x7c; + + if (mode1) { + /* CRTC1 + Set GRPH_BUFFER_CNTL register using h/w defined optimal values. + GRPH_STOP_REQ <= MIN[ 0x7C, (CRTC_H_DISP + 1) * (bit depth) / 0x10 ] + */ + stop_req = mode1->hdisplay * pixel_bytes1 / 16; + + if (stop_req > max_stop_req) + stop_req = max_stop_req; + + /* + Find the drain rate of the display buffer. + */ + temp_ff.full = rfixed_const((16/pixel_bytes1)); + disp_drain_rate.full = rfixed_div(pix_clk, temp_ff); + + /* + Find the critical point of the display buffer. + */ + crit_point_ff.full = rfixed_mul(disp_drain_rate, disp_latency); + crit_point_ff.full += rfixed_const_half(0); + + critical_point = rfixed_trunc(crit_point_ff); + + if (rdev->disp_priority == 2) { + critical_point = 0; + } + + /* + The critical point should never be above max_stop_req-4. Setting + GRPH_CRITICAL_CNTL = 0 will thus force high priority all the time. + */ + if (max_stop_req - critical_point < 4) + critical_point = 0; + + if (critical_point == 0 && mode2 && rdev->family == CHIP_R300) { + /* some R300 cards have problem with this set to 0, when CRTC2 is enabled.*/ + critical_point = 0x10; + } + + temp = RREG32(RADEON_GRPH_BUFFER_CNTL); + temp &= ~(RADEON_GRPH_STOP_REQ_MASK); + temp |= (stop_req << RADEON_GRPH_STOP_REQ_SHIFT); + temp &= ~(RADEON_GRPH_START_REQ_MASK); + if ((rdev->family == CHIP_R350) && + (stop_req > 0x15)) { + stop_req -= 0x10; + } + temp |= (stop_req << RADEON_GRPH_START_REQ_SHIFT); + temp |= RADEON_GRPH_BUFFER_SIZE; + temp &= ~(RADEON_GRPH_CRITICAL_CNTL | + RADEON_GRPH_CRITICAL_AT_SOF | + RADEON_GRPH_STOP_CNTL); + /* + Write the result into the register. + */ + WREG32(RADEON_GRPH_BUFFER_CNTL, ((temp & ~RADEON_GRPH_CRITICAL_POINT_MASK) | + (critical_point << RADEON_GRPH_CRITICAL_POINT_SHIFT))); + +#if 0 + if ((rdev->family == CHIP_RS400) || + (rdev->family == CHIP_RS480)) { + /* attempt to program RS400 disp regs correctly ??? */ + temp = RREG32(RS400_DISP1_REG_CNTL); + temp &= ~(RS400_DISP1_START_REQ_LEVEL_MASK | + RS400_DISP1_STOP_REQ_LEVEL_MASK); + WREG32(RS400_DISP1_REQ_CNTL1, (temp | + (critical_point << RS400_DISP1_START_REQ_LEVEL_SHIFT) | + (critical_point << RS400_DISP1_STOP_REQ_LEVEL_SHIFT))); + temp = RREG32(RS400_DMIF_MEM_CNTL1); + temp &= ~(RS400_DISP1_CRITICAL_POINT_START_MASK | + RS400_DISP1_CRITICAL_POINT_STOP_MASK); + WREG32(RS400_DMIF_MEM_CNTL1, (temp | + (critical_point << RS400_DISP1_CRITICAL_POINT_START_SHIFT) | + (critical_point << RS400_DISP1_CRITICAL_POINT_STOP_SHIFT))); + } +#endif + + DRM_DEBUG("GRPH_BUFFER_CNTL from to %x\n", + /* (unsigned int)info->SavedReg->grph_buffer_cntl, */ + (unsigned int)RREG32(RADEON_GRPH_BUFFER_CNTL)); + } + + if (mode2) { + u32 grph2_cntl; + stop_req = mode2->hdisplay * pixel_bytes2 / 16; + + if (stop_req > max_stop_req) + stop_req = max_stop_req; + + /* + Find the drain rate of the display buffer. + */ + temp_ff.full = rfixed_const((16/pixel_bytes2)); + disp_drain_rate2.full = rfixed_div(pix_clk2, temp_ff); + + grph2_cntl = RREG32(RADEON_GRPH2_BUFFER_CNTL); + grph2_cntl &= ~(RADEON_GRPH_STOP_REQ_MASK); + grph2_cntl |= (stop_req << RADEON_GRPH_STOP_REQ_SHIFT); + grph2_cntl &= ~(RADEON_GRPH_START_REQ_MASK); + if ((rdev->family == CHIP_R350) && + (stop_req > 0x15)) { + stop_req -= 0x10; + } + grph2_cntl |= (stop_req << RADEON_GRPH_START_REQ_SHIFT); + grph2_cntl |= RADEON_GRPH_BUFFER_SIZE; + grph2_cntl &= ~(RADEON_GRPH_CRITICAL_CNTL | + RADEON_GRPH_CRITICAL_AT_SOF | + RADEON_GRPH_STOP_CNTL); + + if ((rdev->family == CHIP_RS100) || + (rdev->family == CHIP_RS200)) + critical_point2 = 0; + else { + temp = (rdev->mc.vram_width * rdev->mc.vram_is_ddr + 1)/128; + temp_ff.full = rfixed_const(temp); + temp_ff.full = rfixed_mul(mclk_ff, temp_ff); + if (sclk_ff.full < temp_ff.full) + temp_ff.full = sclk_ff.full; + + read_return_rate.full = temp_ff.full; + + if (mode1) { + temp_ff.full = read_return_rate.full - disp_drain_rate.full; + time_disp1_drop_priority.full = rfixed_div(crit_point_ff, temp_ff); + } else { + time_disp1_drop_priority.full = 0; + } + crit_point_ff.full = disp_latency.full + time_disp1_drop_priority.full + disp_latency.full; + crit_point_ff.full = rfixed_mul(crit_point_ff, disp_drain_rate2); + crit_point_ff.full += rfixed_const_half(0); + + critical_point2 = rfixed_trunc(crit_point_ff); + + if (rdev->disp_priority == 2) { + critical_point2 = 0; + } + + if (max_stop_req - critical_point2 < 4) + critical_point2 = 0; + + } + + if (critical_point2 == 0 && rdev->family == CHIP_R300) { + /* some R300 cards have problem with this set to 0 */ + critical_point2 = 0x10; + } + + WREG32(RADEON_GRPH2_BUFFER_CNTL, ((grph2_cntl & ~RADEON_GRPH_CRITICAL_POINT_MASK) | + (critical_point2 << RADEON_GRPH_CRITICAL_POINT_SHIFT))); + + if ((rdev->family == CHIP_RS400) || + (rdev->family == CHIP_RS480)) { +#if 0 + /* attempt to program RS400 disp2 regs correctly ??? */ + temp = RREG32(RS400_DISP2_REQ_CNTL1); + temp &= ~(RS400_DISP2_START_REQ_LEVEL_MASK | + RS400_DISP2_STOP_REQ_LEVEL_MASK); + WREG32(RS400_DISP2_REQ_CNTL1, (temp | + (critical_point2 << RS400_DISP1_START_REQ_LEVEL_SHIFT) | + (critical_point2 << RS400_DISP1_STOP_REQ_LEVEL_SHIFT))); + temp = RREG32(RS400_DISP2_REQ_CNTL2); + temp &= ~(RS400_DISP2_CRITICAL_POINT_START_MASK | + RS400_DISP2_CRITICAL_POINT_STOP_MASK); + WREG32(RS400_DISP2_REQ_CNTL2, (temp | + (critical_point2 << RS400_DISP2_CRITICAL_POINT_START_SHIFT) | + (critical_point2 << RS400_DISP2_CRITICAL_POINT_STOP_SHIFT))); +#endif + WREG32(RS400_DISP2_REQ_CNTL1, 0x105DC1CC); + WREG32(RS400_DISP2_REQ_CNTL2, 0x2749D000); + WREG32(RS400_DMIF_MEM_CNTL1, 0x29CA71DC); + WREG32(RS400_DISP1_REQ_CNTL1, 0x28FBC3AC); + } + + DRM_DEBUG("GRPH2_BUFFER_CNTL from to %x\n", + (unsigned int)RREG32(RADEON_GRPH2_BUFFER_CNTL)); + } +} diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c new file mode 100644 index 000000000000..2c2f42de1d4c --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c @@ -0,0 +1,1288 @@ +/* + * Copyright 2007-8 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Dave Airlie + * Alex Deucher + */ +#include "drmP.h" +#include "drm_crtc_helper.h" +#include "radeon_drm.h" +#include "radeon.h" +#include "atom.h" + + +static void radeon_legacy_rmx_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + int xres = mode->hdisplay; + int yres = mode->vdisplay; + bool hscale = true, vscale = true; + int hsync_wid; + int vsync_wid; + int hsync_start; + uint32_t scale, inc; + uint32_t fp_horz_stretch, fp_vert_stretch, crtc_more_cntl, fp_horz_vert_active; + uint32_t fp_h_sync_strt_wid, fp_v_sync_strt_wid, fp_crtc_h_total_disp, fp_crtc_v_total_disp; + struct radeon_native_mode *native_mode = &radeon_encoder->native_mode; + + DRM_DEBUG("\n"); + + fp_vert_stretch = RREG32(RADEON_FP_VERT_STRETCH) & + (RADEON_VERT_STRETCH_RESERVED | + RADEON_VERT_AUTO_RATIO_INC); + fp_horz_stretch = RREG32(RADEON_FP_HORZ_STRETCH) & + (RADEON_HORZ_FP_LOOP_STRETCH | + RADEON_HORZ_AUTO_RATIO_INC); + + crtc_more_cntl = 0; + if ((rdev->family == CHIP_RS100) || + (rdev->family == CHIP_RS200)) { + /* This is to workaround the asic bug for RMX, some versions + of BIOS dosen't have this register initialized correctly. */ + crtc_more_cntl |= RADEON_CRTC_H_CUTOFF_ACTIVE_EN; + } + + + fp_crtc_h_total_disp = ((((mode->crtc_htotal / 8) - 1) & 0x3ff) + | ((((mode->crtc_hdisplay / 8) - 1) & 0x1ff) << 16)); + + hsync_wid = (mode->crtc_hsync_end - mode->crtc_hsync_start) / 8; + if (!hsync_wid) + hsync_wid = 1; + hsync_start = mode->crtc_hsync_start - 8; + + fp_h_sync_strt_wid = ((hsync_start & 0x1fff) + | ((hsync_wid & 0x3f) << 16) + | ((mode->flags & DRM_MODE_FLAG_NHSYNC) + ? RADEON_CRTC_H_SYNC_POL + : 0)); + + fp_crtc_v_total_disp = (((mode->crtc_vtotal - 1) & 0xffff) + | ((mode->crtc_vdisplay - 1) << 16)); + + vsync_wid = mode->crtc_vsync_end - mode->crtc_vsync_start; + if (!vsync_wid) + vsync_wid = 1; + + fp_v_sync_strt_wid = (((mode->crtc_vsync_start - 1) & 0xfff) + | ((vsync_wid & 0x1f) << 16) + | ((mode->flags & DRM_MODE_FLAG_NVSYNC) + ? RADEON_CRTC_V_SYNC_POL + : 0)); + + fp_horz_vert_active = 0; + + if (native_mode->panel_xres == 0 || + native_mode->panel_yres == 0) { + hscale = false; + vscale = false; + } else { + if (xres > native_mode->panel_xres) + xres = native_mode->panel_xres; + if (yres > native_mode->panel_yres) + yres = native_mode->panel_yres; + + if (xres == native_mode->panel_xres) + hscale = false; + if (yres == native_mode->panel_yres) + vscale = false; + } + + if (radeon_encoder->flags & RADEON_USE_RMX) { + if (radeon_encoder->rmx_type != RMX_CENTER) { + if (!hscale) + fp_horz_stretch |= ((xres/8-1) << 16); + else { + inc = (fp_horz_stretch & RADEON_HORZ_AUTO_RATIO_INC) ? 1 : 0; + scale = ((xres + inc) * RADEON_HORZ_STRETCH_RATIO_MAX) + / native_mode->panel_xres + 1; + fp_horz_stretch |= (((scale) & RADEON_HORZ_STRETCH_RATIO_MASK) | + RADEON_HORZ_STRETCH_BLEND | + RADEON_HORZ_STRETCH_ENABLE | + ((native_mode->panel_xres/8-1) << 16)); + } + + if (!vscale) + fp_vert_stretch |= ((yres-1) << 12); + else { + inc = (fp_vert_stretch & RADEON_VERT_AUTO_RATIO_INC) ? 1 : 0; + scale = ((yres + inc) * RADEON_VERT_STRETCH_RATIO_MAX) + / native_mode->panel_yres + 1; + fp_vert_stretch |= (((scale) & RADEON_VERT_STRETCH_RATIO_MASK) | + RADEON_VERT_STRETCH_ENABLE | + RADEON_VERT_STRETCH_BLEND | + ((native_mode->panel_yres-1) << 12)); + } + } else if (radeon_encoder->rmx_type == RMX_CENTER) { + int blank_width; + + fp_horz_stretch |= ((xres/8-1) << 16); + fp_vert_stretch |= ((yres-1) << 12); + + crtc_more_cntl |= (RADEON_CRTC_AUTO_HORZ_CENTER_EN | + RADEON_CRTC_AUTO_VERT_CENTER_EN); + + blank_width = (mode->crtc_hblank_end - mode->crtc_hblank_start) / 8; + if (blank_width > 110) + blank_width = 110; + + fp_crtc_h_total_disp = (((blank_width) & 0x3ff) + | ((((mode->crtc_hdisplay / 8) - 1) & 0x1ff) << 16)); + + hsync_wid = (mode->crtc_hsync_end - mode->crtc_hsync_start) / 8; + if (!hsync_wid) + hsync_wid = 1; + + fp_h_sync_strt_wid = ((((mode->crtc_hsync_start - mode->crtc_hblank_start) / 8) & 0x1fff) + | ((hsync_wid & 0x3f) << 16) + | ((mode->flags & DRM_MODE_FLAG_NHSYNC) + ? RADEON_CRTC_H_SYNC_POL + : 0)); + + fp_crtc_v_total_disp = (((mode->crtc_vblank_end - mode->crtc_vblank_start) & 0xffff) + | ((mode->crtc_vdisplay - 1) << 16)); + + vsync_wid = mode->crtc_vsync_end - mode->crtc_vsync_start; + if (!vsync_wid) + vsync_wid = 1; + + fp_v_sync_strt_wid = ((((mode->crtc_vsync_start - mode->crtc_vblank_start) & 0xfff) + | ((vsync_wid & 0x1f) << 16) + | ((mode->flags & DRM_MODE_FLAG_NVSYNC) + ? RADEON_CRTC_V_SYNC_POL + : 0))); + + fp_horz_vert_active = (((native_mode->panel_yres) & 0xfff) | + (((native_mode->panel_xres / 8) & 0x1ff) << 16)); + } + } else { + fp_horz_stretch |= ((xres/8-1) << 16); + fp_vert_stretch |= ((yres-1) << 12); + } + + WREG32(RADEON_FP_HORZ_STRETCH, fp_horz_stretch); + WREG32(RADEON_FP_VERT_STRETCH, fp_vert_stretch); + WREG32(RADEON_CRTC_MORE_CNTL, crtc_more_cntl); + WREG32(RADEON_FP_HORZ_VERT_ACTIVE, fp_horz_vert_active); + WREG32(RADEON_FP_H_SYNC_STRT_WID, fp_h_sync_strt_wid); + WREG32(RADEON_FP_V_SYNC_STRT_WID, fp_v_sync_strt_wid); + WREG32(RADEON_FP_CRTC_H_TOTAL_DISP, fp_crtc_h_total_disp); + WREG32(RADEON_FP_CRTC_V_TOTAL_DISP, fp_crtc_v_total_disp); + +} + +static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + uint32_t lvds_gen_cntl, lvds_pll_cntl, pixclks_cntl, disp_pwr_man; + int panel_pwr_delay = 2000; + DRM_DEBUG("\n"); + + if (radeon_encoder->enc_priv) { + if (rdev->is_atom_bios) { + struct radeon_encoder_atom_dig *lvds = radeon_encoder->enc_priv; + panel_pwr_delay = lvds->panel_pwr_delay; + } else { + struct radeon_encoder_lvds *lvds = radeon_encoder->enc_priv; + panel_pwr_delay = lvds->panel_pwr_delay; + } + } + + switch (mode) { + case DRM_MODE_DPMS_ON: + disp_pwr_man = RREG32(RADEON_DISP_PWR_MAN); + disp_pwr_man |= RADEON_AUTO_PWRUP_EN; + WREG32(RADEON_DISP_PWR_MAN, disp_pwr_man); + lvds_pll_cntl = RREG32(RADEON_LVDS_PLL_CNTL); + lvds_pll_cntl |= RADEON_LVDS_PLL_EN; + WREG32(RADEON_LVDS_PLL_CNTL, lvds_pll_cntl); + udelay(1000); + + lvds_pll_cntl = RREG32(RADEON_LVDS_PLL_CNTL); + lvds_pll_cntl &= ~RADEON_LVDS_PLL_RESET; + WREG32(RADEON_LVDS_PLL_CNTL, lvds_pll_cntl); + + lvds_gen_cntl = RREG32(RADEON_LVDS_GEN_CNTL); + lvds_gen_cntl |= (RADEON_LVDS_ON | RADEON_LVDS_EN | RADEON_LVDS_DIGON | RADEON_LVDS_BLON); + lvds_gen_cntl &= ~(RADEON_LVDS_DISPLAY_DIS); + udelay(panel_pwr_delay * 1000); + WREG32(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); + break; + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + pixclks_cntl = RREG32_PLL(RADEON_PIXCLKS_CNTL); + WREG32_PLL_P(RADEON_PIXCLKS_CNTL, 0, ~RADEON_PIXCLK_LVDS_ALWAYS_ONb); + lvds_gen_cntl = RREG32(RADEON_LVDS_GEN_CNTL); + lvds_gen_cntl |= RADEON_LVDS_DISPLAY_DIS; + lvds_gen_cntl &= ~(RADEON_LVDS_ON | RADEON_LVDS_BLON | RADEON_LVDS_EN | RADEON_LVDS_DIGON); + udelay(panel_pwr_delay * 1000); + WREG32(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); + WREG32_PLL(RADEON_PIXCLKS_CNTL, pixclks_cntl); + break; + } + + if (rdev->is_atom_bios) + radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); + else + radeon_combios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); +} + +static void radeon_legacy_lvds_prepare(struct drm_encoder *encoder) +{ + struct radeon_device *rdev = encoder->dev->dev_private; + + if (rdev->is_atom_bios) + radeon_atom_output_lock(encoder, true); + else + radeon_combios_output_lock(encoder, true); + radeon_legacy_lvds_dpms(encoder, DRM_MODE_DPMS_OFF); +} + +static void radeon_legacy_lvds_commit(struct drm_encoder *encoder) +{ + struct radeon_device *rdev = encoder->dev->dev_private; + + radeon_legacy_lvds_dpms(encoder, DRM_MODE_DPMS_ON); + if (rdev->is_atom_bios) + radeon_atom_output_lock(encoder, false); + else + radeon_combios_output_lock(encoder, false); +} + +static void radeon_legacy_lvds_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + uint32_t lvds_pll_cntl, lvds_gen_cntl, lvds_ss_gen_cntl; + + DRM_DEBUG("\n"); + + if (radeon_crtc->crtc_id == 0) + radeon_legacy_rmx_mode_set(encoder, mode, adjusted_mode); + + lvds_pll_cntl = RREG32(RADEON_LVDS_PLL_CNTL); + lvds_pll_cntl &= ~RADEON_LVDS_PLL_EN; + + lvds_ss_gen_cntl = RREG32(RADEON_LVDS_SS_GEN_CNTL); + if ((!rdev->is_atom_bios)) { + struct radeon_encoder_lvds *lvds = (struct radeon_encoder_lvds *)radeon_encoder->enc_priv; + if (lvds) { + DRM_DEBUG("bios LVDS_GEN_CNTL: 0x%x\n", lvds->lvds_gen_cntl); + lvds_gen_cntl = lvds->lvds_gen_cntl; + lvds_ss_gen_cntl &= ~((0xf << RADEON_LVDS_PWRSEQ_DELAY1_SHIFT) | + (0xf << RADEON_LVDS_PWRSEQ_DELAY2_SHIFT)); + lvds_ss_gen_cntl |= ((lvds->panel_digon_delay << RADEON_LVDS_PWRSEQ_DELAY1_SHIFT) | + (lvds->panel_blon_delay << RADEON_LVDS_PWRSEQ_DELAY2_SHIFT)); + } else + lvds_gen_cntl = RREG32(RADEON_LVDS_GEN_CNTL); + } else + lvds_gen_cntl = RREG32(RADEON_LVDS_GEN_CNTL); + lvds_gen_cntl |= RADEON_LVDS_DISPLAY_DIS; + lvds_gen_cntl &= ~(RADEON_LVDS_ON | + RADEON_LVDS_BLON | + RADEON_LVDS_EN | + RADEON_LVDS_RST_FM); + + if (ASIC_IS_R300(rdev)) + lvds_pll_cntl &= ~(R300_LVDS_SRC_SEL_MASK); + + if (radeon_crtc->crtc_id == 0) { + if (ASIC_IS_R300(rdev)) { + if (radeon_encoder->flags & RADEON_USE_RMX) + lvds_pll_cntl |= R300_LVDS_SRC_SEL_RMX; + } else + lvds_gen_cntl &= ~RADEON_LVDS_SEL_CRTC2; + } else { + if (ASIC_IS_R300(rdev)) + lvds_pll_cntl |= R300_LVDS_SRC_SEL_CRTC2; + else + lvds_gen_cntl |= RADEON_LVDS_SEL_CRTC2; + } + + WREG32(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); + WREG32(RADEON_LVDS_PLL_CNTL, lvds_pll_cntl); + WREG32(RADEON_LVDS_SS_GEN_CNTL, lvds_ss_gen_cntl); + + if (rdev->family == CHIP_RV410) + WREG32(RADEON_CLOCK_CNTL_INDEX, 0); + + if (rdev->is_atom_bios) + radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); + else + radeon_combios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); +} + +static bool radeon_legacy_lvds_mode_fixup(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + + drm_mode_set_crtcinfo(adjusted_mode, 0); + + radeon_encoder->flags &= ~RADEON_USE_RMX; + + if (radeon_encoder->rmx_type != RMX_OFF) + radeon_rmx_mode_fixup(encoder, mode, adjusted_mode); + + return true; +} + +static const struct drm_encoder_helper_funcs radeon_legacy_lvds_helper_funcs = { + .dpms = radeon_legacy_lvds_dpms, + .mode_fixup = radeon_legacy_lvds_mode_fixup, + .prepare = radeon_legacy_lvds_prepare, + .mode_set = radeon_legacy_lvds_mode_set, + .commit = radeon_legacy_lvds_commit, +}; + + +static const struct drm_encoder_funcs radeon_legacy_lvds_enc_funcs = { + .destroy = radeon_enc_destroy, +}; + +static bool radeon_legacy_primary_dac_mode_fixup(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + + drm_mode_set_crtcinfo(adjusted_mode, 0); + + return true; +} + +static void radeon_legacy_primary_dac_dpms(struct drm_encoder *encoder, int mode) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + uint32_t crtc_ext_cntl = RREG32(RADEON_CRTC_EXT_CNTL); + uint32_t dac_cntl = RREG32(RADEON_DAC_CNTL); + uint32_t dac_macro_cntl = RREG32(RADEON_DAC_MACRO_CNTL); + + DRM_DEBUG("\n"); + + switch (mode) { + case DRM_MODE_DPMS_ON: + crtc_ext_cntl |= RADEON_CRTC_CRT_ON; + dac_cntl &= ~RADEON_DAC_PDWN; + dac_macro_cntl &= ~(RADEON_DAC_PDWN_R | + RADEON_DAC_PDWN_G | + RADEON_DAC_PDWN_B); + break; + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + crtc_ext_cntl &= ~RADEON_CRTC_CRT_ON; + dac_cntl |= RADEON_DAC_PDWN; + dac_macro_cntl |= (RADEON_DAC_PDWN_R | + RADEON_DAC_PDWN_G | + RADEON_DAC_PDWN_B); + break; + } + + WREG32(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl); + WREG32(RADEON_DAC_CNTL, dac_cntl); + WREG32(RADEON_DAC_MACRO_CNTL, dac_macro_cntl); + + if (rdev->is_atom_bios) + radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); + else + radeon_combios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); +} + +static void radeon_legacy_primary_dac_prepare(struct drm_encoder *encoder) +{ + struct radeon_device *rdev = encoder->dev->dev_private; + + if (rdev->is_atom_bios) + radeon_atom_output_lock(encoder, true); + else + radeon_combios_output_lock(encoder, true); + radeon_legacy_primary_dac_dpms(encoder, DRM_MODE_DPMS_OFF); +} + +static void radeon_legacy_primary_dac_commit(struct drm_encoder *encoder) +{ + struct radeon_device *rdev = encoder->dev->dev_private; + + radeon_legacy_primary_dac_dpms(encoder, DRM_MODE_DPMS_ON); + + if (rdev->is_atom_bios) + radeon_atom_output_lock(encoder, false); + else + radeon_combios_output_lock(encoder, false); +} + +static void radeon_legacy_primary_dac_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + uint32_t disp_output_cntl, dac_cntl, dac2_cntl, dac_macro_cntl; + + DRM_DEBUG("\n"); + + if (radeon_crtc->crtc_id == 0) + radeon_legacy_rmx_mode_set(encoder, mode, adjusted_mode); + + if (radeon_crtc->crtc_id == 0) { + if (rdev->family == CHIP_R200 || ASIC_IS_R300(rdev)) { + disp_output_cntl = RREG32(RADEON_DISP_OUTPUT_CNTL) & + ~(RADEON_DISP_DAC_SOURCE_MASK); + WREG32(RADEON_DISP_OUTPUT_CNTL, disp_output_cntl); + } else { + dac2_cntl = RREG32(RADEON_DAC_CNTL2) & ~(RADEON_DAC2_DAC_CLK_SEL); + WREG32(RADEON_DAC_CNTL2, dac2_cntl); + } + } else { + if (rdev->family == CHIP_R200 || ASIC_IS_R300(rdev)) { + disp_output_cntl = RREG32(RADEON_DISP_OUTPUT_CNTL) & + ~(RADEON_DISP_DAC_SOURCE_MASK); + disp_output_cntl |= RADEON_DISP_DAC_SOURCE_CRTC2; + WREG32(RADEON_DISP_OUTPUT_CNTL, disp_output_cntl); + } else { + dac2_cntl = RREG32(RADEON_DAC_CNTL2) | RADEON_DAC2_DAC_CLK_SEL; + WREG32(RADEON_DAC_CNTL2, dac2_cntl); + } + } + + dac_cntl = (RADEON_DAC_MASK_ALL | + RADEON_DAC_VGA_ADR_EN | + /* TODO 6-bits */ + RADEON_DAC_8BIT_EN); + + WREG32_P(RADEON_DAC_CNTL, + dac_cntl, + RADEON_DAC_RANGE_CNTL | + RADEON_DAC_BLANKING); + + if (radeon_encoder->enc_priv) { + struct radeon_encoder_primary_dac *p_dac = (struct radeon_encoder_primary_dac *)radeon_encoder->enc_priv; + dac_macro_cntl = p_dac->ps2_pdac_adj; + } else + dac_macro_cntl = RREG32(RADEON_DAC_MACRO_CNTL); + dac_macro_cntl |= RADEON_DAC_PDWN_R | RADEON_DAC_PDWN_G | RADEON_DAC_PDWN_B; + WREG32(RADEON_DAC_MACRO_CNTL, dac_macro_cntl); + + if (rdev->is_atom_bios) + radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); + else + radeon_combios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); +} + +static enum drm_connector_status radeon_legacy_primary_dac_detect(struct drm_encoder *encoder, + struct drm_connector *connector) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + uint32_t vclk_ecp_cntl, crtc_ext_cntl; + uint32_t dac_ext_cntl, dac_cntl, dac_macro_cntl, tmp; + enum drm_connector_status found = connector_status_disconnected; + bool color = true; + + /* save the regs we need */ + vclk_ecp_cntl = RREG32_PLL(RADEON_VCLK_ECP_CNTL); + crtc_ext_cntl = RREG32(RADEON_CRTC_EXT_CNTL); + dac_ext_cntl = RREG32(RADEON_DAC_EXT_CNTL); + dac_cntl = RREG32(RADEON_DAC_CNTL); + dac_macro_cntl = RREG32(RADEON_DAC_MACRO_CNTL); + + tmp = vclk_ecp_cntl & + ~(RADEON_PIXCLK_ALWAYS_ONb | RADEON_PIXCLK_DAC_ALWAYS_ONb); + WREG32_PLL(RADEON_VCLK_ECP_CNTL, tmp); + + tmp = crtc_ext_cntl | RADEON_CRTC_CRT_ON; + WREG32(RADEON_CRTC_EXT_CNTL, tmp); + + tmp = RADEON_DAC_FORCE_BLANK_OFF_EN | + RADEON_DAC_FORCE_DATA_EN; + + if (color) + tmp |= RADEON_DAC_FORCE_DATA_SEL_RGB; + else + tmp |= RADEON_DAC_FORCE_DATA_SEL_G; + + if (ASIC_IS_R300(rdev)) + tmp |= (0x1b6 << RADEON_DAC_FORCE_DATA_SHIFT); + else + tmp |= (0x180 << RADEON_DAC_FORCE_DATA_SHIFT); + + WREG32(RADEON_DAC_EXT_CNTL, tmp); + + tmp = dac_cntl & ~(RADEON_DAC_RANGE_CNTL_MASK | RADEON_DAC_PDWN); + tmp |= RADEON_DAC_RANGE_CNTL_PS2 | RADEON_DAC_CMP_EN; + WREG32(RADEON_DAC_CNTL, tmp); + + tmp &= ~(RADEON_DAC_PDWN_R | + RADEON_DAC_PDWN_G | + RADEON_DAC_PDWN_B); + + WREG32(RADEON_DAC_MACRO_CNTL, tmp); + + udelay(2000); + + if (RREG32(RADEON_DAC_CNTL) & RADEON_DAC_CMP_OUTPUT) + found = connector_status_connected; + + /* restore the regs we used */ + WREG32(RADEON_DAC_CNTL, dac_cntl); + WREG32(RADEON_DAC_MACRO_CNTL, dac_macro_cntl); + WREG32(RADEON_DAC_EXT_CNTL, dac_ext_cntl); + WREG32(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl); + WREG32_PLL(RADEON_VCLK_ECP_CNTL, vclk_ecp_cntl); + + return found; +} + +static const struct drm_encoder_helper_funcs radeon_legacy_primary_dac_helper_funcs = { + .dpms = radeon_legacy_primary_dac_dpms, + .mode_fixup = radeon_legacy_primary_dac_mode_fixup, + .prepare = radeon_legacy_primary_dac_prepare, + .mode_set = radeon_legacy_primary_dac_mode_set, + .commit = radeon_legacy_primary_dac_commit, + .detect = radeon_legacy_primary_dac_detect, +}; + + +static const struct drm_encoder_funcs radeon_legacy_primary_dac_enc_funcs = { + .destroy = radeon_enc_destroy, +}; + +static bool radeon_legacy_tmds_int_mode_fixup(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + + drm_mode_set_crtcinfo(adjusted_mode, 0); + + return true; +} + +static void radeon_legacy_tmds_int_dpms(struct drm_encoder *encoder, int mode) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + uint32_t fp_gen_cntl = RREG32(RADEON_FP_GEN_CNTL); + DRM_DEBUG("\n"); + + switch (mode) { + case DRM_MODE_DPMS_ON: + fp_gen_cntl |= (RADEON_FP_FPON | RADEON_FP_TMDS_EN); + break; + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + fp_gen_cntl &= ~(RADEON_FP_FPON | RADEON_FP_TMDS_EN); + break; + } + + WREG32(RADEON_FP_GEN_CNTL, fp_gen_cntl); + + if (rdev->is_atom_bios) + radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); + else + radeon_combios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); +} + +static void radeon_legacy_tmds_int_prepare(struct drm_encoder *encoder) +{ + struct radeon_device *rdev = encoder->dev->dev_private; + + if (rdev->is_atom_bios) + radeon_atom_output_lock(encoder, true); + else + radeon_combios_output_lock(encoder, true); + radeon_legacy_tmds_int_dpms(encoder, DRM_MODE_DPMS_OFF); +} + +static void radeon_legacy_tmds_int_commit(struct drm_encoder *encoder) +{ + struct radeon_device *rdev = encoder->dev->dev_private; + + radeon_legacy_tmds_int_dpms(encoder, DRM_MODE_DPMS_ON); + + if (rdev->is_atom_bios) + radeon_atom_output_lock(encoder, true); + else + radeon_combios_output_lock(encoder, true); +} + +static void radeon_legacy_tmds_int_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + uint32_t tmp, tmds_pll_cntl, tmds_transmitter_cntl, fp_gen_cntl; + int i; + + DRM_DEBUG("\n"); + + if (radeon_crtc->crtc_id == 0) + radeon_legacy_rmx_mode_set(encoder, mode, adjusted_mode); + + tmp = tmds_pll_cntl = RREG32(RADEON_TMDS_PLL_CNTL); + tmp &= 0xfffff; + if (rdev->family == CHIP_RV280) { + /* bit 22 of TMDS_PLL_CNTL is read-back inverted */ + tmp ^= (1 << 22); + tmds_pll_cntl ^= (1 << 22); + } + + if (radeon_encoder->enc_priv) { + struct radeon_encoder_int_tmds *tmds = (struct radeon_encoder_int_tmds *)radeon_encoder->enc_priv; + + for (i = 0; i < 4; i++) { + if (tmds->tmds_pll[i].freq == 0) + break; + if ((uint32_t)(mode->clock / 10) < tmds->tmds_pll[i].freq) { + tmp = tmds->tmds_pll[i].value ; + break; + } + } + } + + if (ASIC_IS_R300(rdev) || (rdev->family == CHIP_RV280)) { + if (tmp & 0xfff00000) + tmds_pll_cntl = tmp; + else { + tmds_pll_cntl &= 0xfff00000; + tmds_pll_cntl |= tmp; + } + } else + tmds_pll_cntl = tmp; + + tmds_transmitter_cntl = RREG32(RADEON_TMDS_TRANSMITTER_CNTL) & + ~(RADEON_TMDS_TRANSMITTER_PLLRST); + + if (rdev->family == CHIP_R200 || + rdev->family == CHIP_R100 || + ASIC_IS_R300(rdev)) + tmds_transmitter_cntl &= ~(RADEON_TMDS_TRANSMITTER_PLLEN); + else /* RV chips got this bit reversed */ + tmds_transmitter_cntl |= RADEON_TMDS_TRANSMITTER_PLLEN; + + fp_gen_cntl = (RREG32(RADEON_FP_GEN_CNTL) | + (RADEON_FP_CRTC_DONT_SHADOW_VPAR | + RADEON_FP_CRTC_DONT_SHADOW_HEND)); + + fp_gen_cntl &= ~(RADEON_FP_FPON | RADEON_FP_TMDS_EN); + + if (1) /* FIXME rgbBits == 8 */ + fp_gen_cntl |= RADEON_FP_PANEL_FORMAT; /* 24 bit format */ + else + fp_gen_cntl &= ~RADEON_FP_PANEL_FORMAT;/* 18 bit format */ + + if (radeon_crtc->crtc_id == 0) { + if (ASIC_IS_R300(rdev) || rdev->family == CHIP_R200) { + fp_gen_cntl &= ~R200_FP_SOURCE_SEL_MASK; + if (radeon_encoder->flags & RADEON_USE_RMX) + fp_gen_cntl |= R200_FP_SOURCE_SEL_RMX; + else + fp_gen_cntl |= R200_FP_SOURCE_SEL_CRTC1; + } else + fp_gen_cntl |= RADEON_FP_SEL_CRTC1; + } else { + if (ASIC_IS_R300(rdev) || rdev->family == CHIP_R200) { + fp_gen_cntl &= ~R200_FP_SOURCE_SEL_MASK; + fp_gen_cntl |= R200_FP_SOURCE_SEL_CRTC2; + } else + fp_gen_cntl |= RADEON_FP_SEL_CRTC2; + } + + WREG32(RADEON_TMDS_PLL_CNTL, tmds_pll_cntl); + WREG32(RADEON_TMDS_TRANSMITTER_CNTL, tmds_transmitter_cntl); + WREG32(RADEON_FP_GEN_CNTL, fp_gen_cntl); + + if (rdev->is_atom_bios) + radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); + else + radeon_combios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); +} + +static const struct drm_encoder_helper_funcs radeon_legacy_tmds_int_helper_funcs = { + .dpms = radeon_legacy_tmds_int_dpms, + .mode_fixup = radeon_legacy_tmds_int_mode_fixup, + .prepare = radeon_legacy_tmds_int_prepare, + .mode_set = radeon_legacy_tmds_int_mode_set, + .commit = radeon_legacy_tmds_int_commit, +}; + + +static const struct drm_encoder_funcs radeon_legacy_tmds_int_enc_funcs = { + .destroy = radeon_enc_destroy, +}; + +static bool radeon_legacy_tmds_ext_mode_fixup(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + + drm_mode_set_crtcinfo(adjusted_mode, 0); + + return true; +} + +static void radeon_legacy_tmds_ext_dpms(struct drm_encoder *encoder, int mode) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + uint32_t fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL); + DRM_DEBUG("\n"); + + switch (mode) { + case DRM_MODE_DPMS_ON: + fp2_gen_cntl &= ~RADEON_FP2_BLANK_EN; + fp2_gen_cntl |= (RADEON_FP2_ON | RADEON_FP2_DVO_EN); + break; + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + fp2_gen_cntl |= RADEON_FP2_BLANK_EN; + fp2_gen_cntl &= ~(RADEON_FP2_ON | RADEON_FP2_DVO_EN); + break; + } + + WREG32(RADEON_FP2_GEN_CNTL, fp2_gen_cntl); + + if (rdev->is_atom_bios) + radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); + else + radeon_combios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); +} + +static void radeon_legacy_tmds_ext_prepare(struct drm_encoder *encoder) +{ + struct radeon_device *rdev = encoder->dev->dev_private; + + if (rdev->is_atom_bios) + radeon_atom_output_lock(encoder, true); + else + radeon_combios_output_lock(encoder, true); + radeon_legacy_tmds_ext_dpms(encoder, DRM_MODE_DPMS_OFF); +} + +static void radeon_legacy_tmds_ext_commit(struct drm_encoder *encoder) +{ + struct radeon_device *rdev = encoder->dev->dev_private; + radeon_legacy_tmds_ext_dpms(encoder, DRM_MODE_DPMS_ON); + + if (rdev->is_atom_bios) + radeon_atom_output_lock(encoder, false); + else + radeon_combios_output_lock(encoder, false); +} + +static void radeon_legacy_tmds_ext_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + uint32_t fp2_gen_cntl; + + DRM_DEBUG("\n"); + + if (radeon_crtc->crtc_id == 0) + radeon_legacy_rmx_mode_set(encoder, mode, adjusted_mode); + + if (rdev->is_atom_bios) { + radeon_encoder->pixel_clock = adjusted_mode->clock; + atombios_external_tmds_setup(encoder, ATOM_ENABLE); + fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL); + } else { + fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL); + + if (1) /* FIXME rgbBits == 8 */ + fp2_gen_cntl |= RADEON_FP2_PANEL_FORMAT; /* 24 bit format, */ + else + fp2_gen_cntl &= ~RADEON_FP2_PANEL_FORMAT;/* 18 bit format, */ + + fp2_gen_cntl &= ~(RADEON_FP2_ON | + RADEON_FP2_DVO_EN | + RADEON_FP2_DVO_RATE_SEL_SDR); + + /* XXX: these are oem specific */ + if (ASIC_IS_R300(rdev)) { + if ((dev->pdev->device == 0x4850) && + (dev->pdev->subsystem_vendor == 0x1028) && + (dev->pdev->subsystem_device == 0x2001)) /* Dell Inspiron 8600 */ + fp2_gen_cntl |= R300_FP2_DVO_CLOCK_MODE_SINGLE; + else + fp2_gen_cntl |= RADEON_FP2_PAD_FLOP_EN | R300_FP2_DVO_CLOCK_MODE_SINGLE; + + /*if (mode->clock > 165000) + fp2_gen_cntl |= R300_FP2_DVO_DUAL_CHANNEL_EN;*/ + } + } + + if (radeon_crtc->crtc_id == 0) { + if ((rdev->family == CHIP_R200) || ASIC_IS_R300(rdev)) { + fp2_gen_cntl &= ~R200_FP2_SOURCE_SEL_MASK; + if (radeon_encoder->flags & RADEON_USE_RMX) + fp2_gen_cntl |= R200_FP2_SOURCE_SEL_RMX; + else + fp2_gen_cntl |= R200_FP2_SOURCE_SEL_CRTC1; + } else + fp2_gen_cntl &= ~RADEON_FP2_SRC_SEL_CRTC2; + } else { + if ((rdev->family == CHIP_R200) || ASIC_IS_R300(rdev)) { + fp2_gen_cntl &= ~R200_FP2_SOURCE_SEL_MASK; + fp2_gen_cntl |= R200_FP2_SOURCE_SEL_CRTC2; + } else + fp2_gen_cntl |= RADEON_FP2_SRC_SEL_CRTC2; + } + + WREG32(RADEON_FP2_GEN_CNTL, fp2_gen_cntl); + + if (rdev->is_atom_bios) + radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); + else + radeon_combios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); +} + +static const struct drm_encoder_helper_funcs radeon_legacy_tmds_ext_helper_funcs = { + .dpms = radeon_legacy_tmds_ext_dpms, + .mode_fixup = radeon_legacy_tmds_ext_mode_fixup, + .prepare = radeon_legacy_tmds_ext_prepare, + .mode_set = radeon_legacy_tmds_ext_mode_set, + .commit = radeon_legacy_tmds_ext_commit, +}; + + +static const struct drm_encoder_funcs radeon_legacy_tmds_ext_enc_funcs = { + .destroy = radeon_enc_destroy, +}; + +static bool radeon_legacy_tv_dac_mode_fixup(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + + drm_mode_set_crtcinfo(adjusted_mode, 0); + + return true; +} + +static void radeon_legacy_tv_dac_dpms(struct drm_encoder *encoder, int mode) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + uint32_t fp2_gen_cntl = 0, crtc2_gen_cntl = 0, tv_dac_cntl = 0; + /* uint32_t tv_master_cntl = 0; */ + + DRM_DEBUG("\n"); + + if (rdev->family == CHIP_R200) + fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL); + else { + crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL); + /* FIXME TV */ + /* tv_master_cntl = RREG32(RADEON_TV_MASTER_CNTL); */ + tv_dac_cntl = RREG32(RADEON_TV_DAC_CNTL); + } + + switch (mode) { + case DRM_MODE_DPMS_ON: + if (rdev->family == CHIP_R200) { + fp2_gen_cntl |= (RADEON_FP2_ON | RADEON_FP2_DVO_EN); + } else { + crtc2_gen_cntl |= RADEON_CRTC2_CRT2_ON; + /* tv_master_cntl |= RADEON_TV_ON; */ + if (rdev->family == CHIP_R420 || + rdev->family == CHIP_R423 || + rdev->family == CHIP_RV410) + tv_dac_cntl &= ~(R420_TV_DAC_RDACPD | + R420_TV_DAC_GDACPD | + R420_TV_DAC_BDACPD | + RADEON_TV_DAC_BGSLEEP); + else + tv_dac_cntl &= ~(RADEON_TV_DAC_RDACPD | + RADEON_TV_DAC_GDACPD | + RADEON_TV_DAC_BDACPD | + RADEON_TV_DAC_BGSLEEP); + } + break; + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + if (rdev->family == CHIP_R200) + fp2_gen_cntl &= ~(RADEON_FP2_ON | RADEON_FP2_DVO_EN); + else { + crtc2_gen_cntl &= ~RADEON_CRTC2_CRT2_ON; + /* tv_master_cntl &= ~RADEON_TV_ON; */ + if (rdev->family == CHIP_R420 || + rdev->family == CHIP_R423 || + rdev->family == CHIP_RV410) + tv_dac_cntl |= (R420_TV_DAC_RDACPD | + R420_TV_DAC_GDACPD | + R420_TV_DAC_BDACPD | + RADEON_TV_DAC_BGSLEEP); + else + tv_dac_cntl |= (RADEON_TV_DAC_RDACPD | + RADEON_TV_DAC_GDACPD | + RADEON_TV_DAC_BDACPD | + RADEON_TV_DAC_BGSLEEP); + } + break; + } + + if (rdev->family == CHIP_R200) { + WREG32(RADEON_FP2_GEN_CNTL, fp2_gen_cntl); + } else { + WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl); + /* WREG32(RADEON_TV_MASTER_CNTL, tv_master_cntl); */ + WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl); + } + + if (rdev->is_atom_bios) + radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); + else + radeon_combios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); +} + +static void radeon_legacy_tv_dac_prepare(struct drm_encoder *encoder) +{ + struct radeon_device *rdev = encoder->dev->dev_private; + + if (rdev->is_atom_bios) + radeon_atom_output_lock(encoder, true); + else + radeon_combios_output_lock(encoder, true); + radeon_legacy_tv_dac_dpms(encoder, DRM_MODE_DPMS_OFF); +} + +static void radeon_legacy_tv_dac_commit(struct drm_encoder *encoder) +{ + struct radeon_device *rdev = encoder->dev->dev_private; + + radeon_legacy_tv_dac_dpms(encoder, DRM_MODE_DPMS_ON); + + if (rdev->is_atom_bios) + radeon_atom_output_lock(encoder, true); + else + radeon_combios_output_lock(encoder, true); +} + +static void radeon_legacy_tv_dac_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + uint32_t tv_dac_cntl, gpiopad_a = 0, dac2_cntl, disp_output_cntl = 0; + uint32_t disp_hw_debug = 0, fp2_gen_cntl = 0; + + DRM_DEBUG("\n"); + + if (radeon_crtc->crtc_id == 0) + radeon_legacy_rmx_mode_set(encoder, mode, adjusted_mode); + + if (rdev->family != CHIP_R200) { + tv_dac_cntl = RREG32(RADEON_TV_DAC_CNTL); + if (rdev->family == CHIP_R420 || + rdev->family == CHIP_R423 || + rdev->family == CHIP_RV410) { + tv_dac_cntl &= ~(RADEON_TV_DAC_STD_MASK | + RADEON_TV_DAC_BGADJ_MASK | + R420_TV_DAC_DACADJ_MASK | + R420_TV_DAC_RDACPD | + R420_TV_DAC_GDACPD | + R420_TV_DAC_GDACPD | + R420_TV_DAC_TVENABLE); + } else { + tv_dac_cntl &= ~(RADEON_TV_DAC_STD_MASK | + RADEON_TV_DAC_BGADJ_MASK | + RADEON_TV_DAC_DACADJ_MASK | + RADEON_TV_DAC_RDACPD | + RADEON_TV_DAC_GDACPD | + RADEON_TV_DAC_GDACPD); + } + + /* FIXME TV */ + if (radeon_encoder->enc_priv) { + struct radeon_encoder_tv_dac *tv_dac = radeon_encoder->enc_priv; + tv_dac_cntl |= (RADEON_TV_DAC_NBLANK | + RADEON_TV_DAC_NHOLD | + RADEON_TV_DAC_STD_PS2 | + tv_dac->ps2_tvdac_adj); + } else + tv_dac_cntl |= (RADEON_TV_DAC_NBLANK | + RADEON_TV_DAC_NHOLD | + RADEON_TV_DAC_STD_PS2); + + WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl); + } + + if (ASIC_IS_R300(rdev)) { + gpiopad_a = RREG32(RADEON_GPIOPAD_A) | 1; + disp_output_cntl = RREG32(RADEON_DISP_OUTPUT_CNTL); + } else if (rdev->family == CHIP_R200) + fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL); + else + disp_hw_debug = RREG32(RADEON_DISP_HW_DEBUG); + + dac2_cntl = RREG32(RADEON_DAC_CNTL2) | RADEON_DAC2_DAC2_CLK_SEL; + + if (radeon_crtc->crtc_id == 0) { + if (ASIC_IS_R300(rdev)) { + disp_output_cntl &= ~RADEON_DISP_TVDAC_SOURCE_MASK; + disp_output_cntl |= RADEON_DISP_TVDAC_SOURCE_CRTC; + } else if (rdev->family == CHIP_R200) { + fp2_gen_cntl &= ~(R200_FP2_SOURCE_SEL_MASK | + RADEON_FP2_DVO_RATE_SEL_SDR); + } else + disp_hw_debug |= RADEON_CRT2_DISP1_SEL; + } else { + if (ASIC_IS_R300(rdev)) { + disp_output_cntl &= ~RADEON_DISP_TVDAC_SOURCE_MASK; + disp_output_cntl |= RADEON_DISP_TVDAC_SOURCE_CRTC2; + } else if (rdev->family == CHIP_R200) { + fp2_gen_cntl &= ~(R200_FP2_SOURCE_SEL_MASK | + RADEON_FP2_DVO_RATE_SEL_SDR); + fp2_gen_cntl |= R200_FP2_SOURCE_SEL_CRTC2; + } else + disp_hw_debug &= ~RADEON_CRT2_DISP1_SEL; + } + + WREG32(RADEON_DAC_CNTL2, dac2_cntl); + + if (ASIC_IS_R300(rdev)) { + WREG32_P(RADEON_GPIOPAD_A, gpiopad_a, ~1); + WREG32(RADEON_DISP_TV_OUT_CNTL, disp_output_cntl); + } else if (rdev->family == CHIP_R200) + WREG32(RADEON_FP2_GEN_CNTL, fp2_gen_cntl); + else + WREG32(RADEON_DISP_HW_DEBUG, disp_hw_debug); + + if (rdev->is_atom_bios) + radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); + else + radeon_combios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); + +} + +static enum drm_connector_status radeon_legacy_tv_dac_detect(struct drm_encoder *encoder, + struct drm_connector *connector) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + uint32_t crtc2_gen_cntl, tv_dac_cntl, dac_cntl2, dac_ext_cntl; + uint32_t disp_hw_debug, disp_output_cntl, gpiopad_a, pixclks_cntl, tmp; + enum drm_connector_status found = connector_status_disconnected; + bool color = true; + + /* FIXME tv */ + + /* save the regs we need */ + pixclks_cntl = RREG32_PLL(RADEON_PIXCLKS_CNTL); + gpiopad_a = ASIC_IS_R300(rdev) ? RREG32(RADEON_GPIOPAD_A) : 0; + disp_output_cntl = ASIC_IS_R300(rdev) ? RREG32(RADEON_DISP_OUTPUT_CNTL) : 0; + disp_hw_debug = ASIC_IS_R300(rdev) ? 0 : RREG32(RADEON_DISP_HW_DEBUG); + crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL); + tv_dac_cntl = RREG32(RADEON_TV_DAC_CNTL); + dac_ext_cntl = RREG32(RADEON_DAC_EXT_CNTL); + dac_cntl2 = RREG32(RADEON_DAC_CNTL2); + + tmp = pixclks_cntl & ~(RADEON_PIX2CLK_ALWAYS_ONb + | RADEON_PIX2CLK_DAC_ALWAYS_ONb); + WREG32_PLL(RADEON_PIXCLKS_CNTL, tmp); + + if (ASIC_IS_R300(rdev)) + WREG32_P(RADEON_GPIOPAD_A, 1, ~1); + + tmp = crtc2_gen_cntl & ~RADEON_CRTC2_PIX_WIDTH_MASK; + tmp |= RADEON_CRTC2_CRT2_ON | + (2 << RADEON_CRTC2_PIX_WIDTH_SHIFT); + + WREG32(RADEON_CRTC2_GEN_CNTL, tmp); + + if (ASIC_IS_R300(rdev)) { + tmp = disp_output_cntl & ~RADEON_DISP_TVDAC_SOURCE_MASK; + tmp |= RADEON_DISP_TVDAC_SOURCE_CRTC2; + WREG32(RADEON_DISP_OUTPUT_CNTL, tmp); + } else { + tmp = disp_hw_debug & ~RADEON_CRT2_DISP1_SEL; + WREG32(RADEON_DISP_HW_DEBUG, tmp); + } + + tmp = RADEON_TV_DAC_NBLANK | + RADEON_TV_DAC_NHOLD | + RADEON_TV_MONITOR_DETECT_EN | + RADEON_TV_DAC_STD_PS2; + + WREG32(RADEON_TV_DAC_CNTL, tmp); + + tmp = RADEON_DAC2_FORCE_BLANK_OFF_EN | + RADEON_DAC2_FORCE_DATA_EN; + + if (color) + tmp |= RADEON_DAC_FORCE_DATA_SEL_RGB; + else + tmp |= RADEON_DAC_FORCE_DATA_SEL_G; + + if (ASIC_IS_R300(rdev)) + tmp |= (0x1b6 << RADEON_DAC_FORCE_DATA_SHIFT); + else + tmp |= (0x180 << RADEON_DAC_FORCE_DATA_SHIFT); + + WREG32(RADEON_DAC_EXT_CNTL, tmp); + + tmp = dac_cntl2 | RADEON_DAC2_DAC2_CLK_SEL | RADEON_DAC2_CMP_EN; + WREG32(RADEON_DAC_CNTL2, tmp); + + udelay(10000); + + if (ASIC_IS_R300(rdev)) { + if (RREG32(RADEON_DAC_CNTL2) & RADEON_DAC2_CMP_OUT_B) + found = connector_status_connected; + } else { + if (RREG32(RADEON_DAC_CNTL2) & RADEON_DAC2_CMP_OUTPUT) + found = connector_status_connected; + } + + /* restore regs we used */ + WREG32(RADEON_DAC_CNTL2, dac_cntl2); + WREG32(RADEON_DAC_EXT_CNTL, dac_ext_cntl); + WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl); + WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl); + + if (ASIC_IS_R300(rdev)) { + WREG32(RADEON_DISP_OUTPUT_CNTL, disp_output_cntl); + WREG32_P(RADEON_GPIOPAD_A, gpiopad_a, ~1); + } else { + WREG32(RADEON_DISP_HW_DEBUG, disp_hw_debug); + } + WREG32_PLL(RADEON_PIXCLKS_CNTL, pixclks_cntl); + + /* return found; */ + return connector_status_disconnected; + +} + +static const struct drm_encoder_helper_funcs radeon_legacy_tv_dac_helper_funcs = { + .dpms = radeon_legacy_tv_dac_dpms, + .mode_fixup = radeon_legacy_tv_dac_mode_fixup, + .prepare = radeon_legacy_tv_dac_prepare, + .mode_set = radeon_legacy_tv_dac_mode_set, + .commit = radeon_legacy_tv_dac_commit, + .detect = radeon_legacy_tv_dac_detect, +}; + + +static const struct drm_encoder_funcs radeon_legacy_tv_dac_enc_funcs = { + .destroy = radeon_enc_destroy, +}; + +void +radeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_id, uint32_t supported_device) +{ + struct radeon_device *rdev = dev->dev_private; + struct drm_encoder *encoder; + struct radeon_encoder *radeon_encoder; + + /* see if we already added it */ + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + radeon_encoder = to_radeon_encoder(encoder); + if (radeon_encoder->encoder_id == encoder_id) { + radeon_encoder->devices |= supported_device; + return; + } + + } + + /* add a new one */ + radeon_encoder = kzalloc(sizeof(struct radeon_encoder), GFP_KERNEL); + if (!radeon_encoder) + return; + + encoder = &radeon_encoder->base; + encoder->possible_crtcs = 0x3; + encoder->possible_clones = 0; + + radeon_encoder->enc_priv = NULL; + + radeon_encoder->encoder_id = encoder_id; + radeon_encoder->devices = supported_device; + + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_LVDS: + drm_encoder_init(dev, encoder, &radeon_legacy_lvds_enc_funcs, DRM_MODE_ENCODER_LVDS); + drm_encoder_helper_add(encoder, &radeon_legacy_lvds_helper_funcs); + if (rdev->is_atom_bios) + radeon_encoder->enc_priv = radeon_atombios_get_lvds_info(radeon_encoder); + else + radeon_encoder->enc_priv = radeon_combios_get_lvds_info(radeon_encoder); + radeon_encoder->rmx_type = RMX_FULL; + break; + case ENCODER_OBJECT_ID_INTERNAL_TMDS1: + drm_encoder_init(dev, encoder, &radeon_legacy_tmds_int_enc_funcs, DRM_MODE_ENCODER_TMDS); + drm_encoder_helper_add(encoder, &radeon_legacy_tmds_int_helper_funcs); + if (rdev->is_atom_bios) + radeon_encoder->enc_priv = radeon_atombios_get_tmds_info(radeon_encoder); + else + radeon_encoder->enc_priv = radeon_combios_get_tmds_info(radeon_encoder); + break; + case ENCODER_OBJECT_ID_INTERNAL_DAC1: + drm_encoder_init(dev, encoder, &radeon_legacy_primary_dac_enc_funcs, DRM_MODE_ENCODER_DAC); + drm_encoder_helper_add(encoder, &radeon_legacy_primary_dac_helper_funcs); + if (rdev->is_atom_bios) + radeon_encoder->enc_priv = radeon_atombios_get_primary_dac_info(radeon_encoder); + else + radeon_encoder->enc_priv = radeon_combios_get_primary_dac_info(radeon_encoder); + break; + case ENCODER_OBJECT_ID_INTERNAL_DAC2: + drm_encoder_init(dev, encoder, &radeon_legacy_tv_dac_enc_funcs, DRM_MODE_ENCODER_TVDAC); + drm_encoder_helper_add(encoder, &radeon_legacy_tv_dac_helper_funcs); + if (rdev->is_atom_bios) + radeon_encoder->enc_priv = radeon_atombios_get_tv_dac_info(radeon_encoder); + else + radeon_encoder->enc_priv = radeon_combios_get_tv_dac_info(radeon_encoder); + break; + case ENCODER_OBJECT_ID_INTERNAL_DVO1: + drm_encoder_init(dev, encoder, &radeon_legacy_tmds_ext_enc_funcs, DRM_MODE_ENCODER_TMDS); + drm_encoder_helper_add(encoder, &radeon_legacy_tmds_ext_helper_funcs); + if (!rdev->is_atom_bios) + radeon_combios_get_ext_tmds_info(radeon_encoder); + break; + } +} diff --git a/drivers/gpu/drm/radeon/radeon_mem.c b/drivers/gpu/drm/radeon/radeon_mem.c index 4af5286a36fb..ed95155c4b1d 100644 --- a/drivers/gpu/drm/radeon/radeon_mem.c +++ b/drivers/gpu/drm/radeon/radeon_mem.c @@ -43,8 +43,8 @@ static struct mem_block *split_block(struct mem_block *p, int start, int size, { /* Maybe cut off the start of an existing block */ if (start > p->start) { - struct mem_block *newblock = - drm_alloc(sizeof(*newblock), DRM_MEM_BUFS); + struct mem_block *newblock = kmalloc(sizeof(*newblock), + GFP_KERNEL); if (!newblock) goto out; newblock->start = start; @@ -60,8 +60,8 @@ static struct mem_block *split_block(struct mem_block *p, int start, int size, /* Maybe cut off the end of an existing block */ if (size < p->size) { - struct mem_block *newblock = - drm_alloc(sizeof(*newblock), DRM_MEM_BUFS); + struct mem_block *newblock = kmalloc(sizeof(*newblock), + GFP_KERNEL); if (!newblock) goto out; newblock->start = start + size; @@ -118,7 +118,7 @@ static void free_block(struct mem_block *p) p->size += q->size; p->next = q->next; p->next->prev = p; - drm_free(q, sizeof(*q), DRM_MEM_BUFS); + kfree(q); } if (p->prev->file_priv == NULL) { @@ -126,7 +126,7 @@ static void free_block(struct mem_block *p) q->size += p->size; q->next = p->next; q->next->prev = q; - drm_free(p, sizeof(*q), DRM_MEM_BUFS); + kfree(p); } } @@ -134,14 +134,14 @@ static void free_block(struct mem_block *p) */ static int init_heap(struct mem_block **heap, int start, int size) { - struct mem_block *blocks = drm_alloc(sizeof(*blocks), DRM_MEM_BUFS); + struct mem_block *blocks = kmalloc(sizeof(*blocks), GFP_KERNEL); if (!blocks) return -ENOMEM; - *heap = drm_alloc(sizeof(**heap), DRM_MEM_BUFS); + *heap = kmalloc(sizeof(**heap), GFP_KERNEL); if (!*heap) { - drm_free(blocks, sizeof(*blocks), DRM_MEM_BUFS); + kfree(blocks); return -ENOMEM; } @@ -179,7 +179,7 @@ void radeon_mem_release(struct drm_file *file_priv, struct mem_block *heap) p->size += q->size; p->next = q->next; p->next->prev = p; - drm_free(q, sizeof(*q), DRM_MEM_DRIVER); + kfree(q); } } } @@ -196,10 +196,10 @@ void radeon_mem_takedown(struct mem_block **heap) for (p = (*heap)->next; p != *heap;) { struct mem_block *q = p; p = p->next; - drm_free(q, sizeof(*q), DRM_MEM_DRIVER); + kfree(q); } - drm_free(*heap, sizeof(**heap), DRM_MEM_DRIVER); + kfree(*heap); *heap = NULL; } diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h new file mode 100644 index 000000000000..9173b687462b --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -0,0 +1,398 @@ +/* + * Copyright 2000 ATI Technologies Inc., Markham, Ontario, and + * VA Linux Systems Inc., Fremont, California. + * Copyright 2008 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Original Authors: + * Kevin E. Martin, Rickard E. Faith, Alan Hourihane + * + * Kernel port Author: Dave Airlie + */ + +#ifndef RADEON_MODE_H +#define RADEON_MODE_H + +#include +#include +#include +#include +#include +#include + +#define to_radeon_crtc(x) container_of(x, struct radeon_crtc, base) +#define to_radeon_connector(x) container_of(x, struct radeon_connector, base) +#define to_radeon_encoder(x) container_of(x, struct radeon_encoder, base) +#define to_radeon_framebuffer(x) container_of(x, struct radeon_framebuffer, base) + +enum radeon_connector_type { + CONNECTOR_NONE, + CONNECTOR_VGA, + CONNECTOR_DVI_I, + CONNECTOR_DVI_D, + CONNECTOR_DVI_A, + CONNECTOR_STV, + CONNECTOR_CTV, + CONNECTOR_LVDS, + CONNECTOR_DIGITAL, + CONNECTOR_SCART, + CONNECTOR_HDMI_TYPE_A, + CONNECTOR_HDMI_TYPE_B, + CONNECTOR_0XC, + CONNECTOR_0XD, + CONNECTOR_DIN, + CONNECTOR_DISPLAY_PORT, + CONNECTOR_UNSUPPORTED +}; + +enum radeon_dvi_type { + DVI_AUTO, + DVI_DIGITAL, + DVI_ANALOG +}; + +enum radeon_rmx_type { + RMX_OFF, + RMX_FULL, + RMX_CENTER, + RMX_ASPECT +}; + +enum radeon_tv_std { + TV_STD_NTSC, + TV_STD_PAL, + TV_STD_PAL_M, + TV_STD_PAL_60, + TV_STD_NTSC_J, + TV_STD_SCART_PAL, + TV_STD_SECAM, + TV_STD_PAL_CN, +}; + +struct radeon_i2c_bus_rec { + bool valid; + uint32_t mask_clk_reg; + uint32_t mask_data_reg; + uint32_t a_clk_reg; + uint32_t a_data_reg; + uint32_t put_clk_reg; + uint32_t put_data_reg; + uint32_t get_clk_reg; + uint32_t get_data_reg; + uint32_t mask_clk_mask; + uint32_t mask_data_mask; + uint32_t put_clk_mask; + uint32_t put_data_mask; + uint32_t get_clk_mask; + uint32_t get_data_mask; + uint32_t a_clk_mask; + uint32_t a_data_mask; +}; + +struct radeon_tmds_pll { + uint32_t freq; + uint32_t value; +}; + +#define RADEON_MAX_BIOS_CONNECTOR 16 + +#define RADEON_PLL_USE_BIOS_DIVS (1 << 0) +#define RADEON_PLL_NO_ODD_POST_DIV (1 << 1) +#define RADEON_PLL_USE_REF_DIV (1 << 2) +#define RADEON_PLL_LEGACY (1 << 3) +#define RADEON_PLL_PREFER_LOW_REF_DIV (1 << 4) +#define RADEON_PLL_PREFER_HIGH_REF_DIV (1 << 5) +#define RADEON_PLL_PREFER_LOW_FB_DIV (1 << 6) +#define RADEON_PLL_PREFER_HIGH_FB_DIV (1 << 7) +#define RADEON_PLL_PREFER_LOW_POST_DIV (1 << 8) +#define RADEON_PLL_PREFER_HIGH_POST_DIV (1 << 9) +#define RADEON_PLL_USE_FRAC_FB_DIV (1 << 10) + +struct radeon_pll { + uint16_t reference_freq; + uint16_t reference_div; + uint32_t pll_in_min; + uint32_t pll_in_max; + uint32_t pll_out_min; + uint32_t pll_out_max; + uint16_t xclk; + + uint32_t min_ref_div; + uint32_t max_ref_div; + uint32_t min_post_div; + uint32_t max_post_div; + uint32_t min_feedback_div; + uint32_t max_feedback_div; + uint32_t min_frac_feedback_div; + uint32_t max_frac_feedback_div; + uint32_t best_vco; +}; + +struct radeon_i2c_chan { + struct drm_device *dev; + struct i2c_adapter adapter; + struct i2c_algo_bit_data algo; + struct radeon_i2c_bus_rec rec; +}; + +/* mostly for macs, but really any system without connector tables */ +enum radeon_connector_table { + CT_NONE, + CT_GENERIC, + CT_IBOOK, + CT_POWERBOOK_EXTERNAL, + CT_POWERBOOK_INTERNAL, + CT_POWERBOOK_VGA, + CT_MINI_EXTERNAL, + CT_MINI_INTERNAL, + CT_IMAC_G5_ISIGHT, + CT_EMAC, +}; + +struct radeon_mode_info { + struct atom_context *atom_context; + enum radeon_connector_table connector_table; + bool mode_config_initialized; +}; + +struct radeon_crtc { + struct drm_crtc base; + int crtc_id; + u16 lut_r[256], lut_g[256], lut_b[256]; + bool enabled; + bool can_tile; + uint32_t crtc_offset; + struct radeon_framebuffer *fbdev_fb; + struct drm_mode_set mode_set; + struct drm_gem_object *cursor_bo; + uint64_t cursor_addr; + int cursor_width; + int cursor_height; +}; + +#define RADEON_USE_RMX 1 + +struct radeon_native_mode { + /* preferred mode */ + uint32_t panel_xres, panel_yres; + uint32_t hoverplus, hsync_width; + uint32_t hblank; + uint32_t voverplus, vsync_width; + uint32_t vblank; + uint32_t dotclock; + uint32_t flags; +}; + +struct radeon_encoder_primary_dac { + /* legacy primary dac */ + uint32_t ps2_pdac_adj; +}; + +struct radeon_encoder_lvds { + /* legacy lvds */ + uint16_t panel_vcc_delay; + uint8_t panel_pwr_delay; + uint8_t panel_digon_delay; + uint8_t panel_blon_delay; + uint16_t panel_ref_divider; + uint8_t panel_post_divider; + uint16_t panel_fb_divider; + bool use_bios_dividers; + uint32_t lvds_gen_cntl; + /* panel mode */ + struct radeon_native_mode native_mode; +}; + +struct radeon_encoder_tv_dac { + /* legacy tv dac */ + uint32_t ps2_tvdac_adj; + uint32_t ntsc_tvdac_adj; + uint32_t pal_tvdac_adj; + + enum radeon_tv_std tv_std; +}; + +struct radeon_encoder_int_tmds { + /* legacy int tmds */ + struct radeon_tmds_pll tmds_pll[4]; +}; + +struct radeon_encoder_atom_dig { + /* atom dig */ + bool coherent_mode; + int dig_block; + /* atom lvds */ + uint32_t lvds_misc; + uint16_t panel_pwr_delay; + /* panel mode */ + struct radeon_native_mode native_mode; +}; + +struct radeon_encoder { + struct drm_encoder base; + uint32_t encoder_id; + uint32_t devices; + uint32_t flags; + uint32_t pixel_clock; + enum radeon_rmx_type rmx_type; + struct radeon_native_mode native_mode; + void *enc_priv; +}; + +struct radeon_connector_atom_dig { + uint32_t igp_lane_info; + bool linkb; +}; + +struct radeon_connector { + struct drm_connector base; + uint32_t connector_id; + uint32_t devices; + struct radeon_i2c_chan *ddc_bus; + int use_digital; + void *con_priv; +}; + +struct radeon_framebuffer { + struct drm_framebuffer base; + struct drm_gem_object *obj; +}; + +extern struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev, + struct radeon_i2c_bus_rec *rec, + const char *name); +extern void radeon_i2c_destroy(struct radeon_i2c_chan *i2c); +extern bool radeon_ddc_probe(struct radeon_connector *radeon_connector); +extern int radeon_ddc_get_modes(struct radeon_connector *radeon_connector); + +extern struct drm_encoder *radeon_best_encoder(struct drm_connector *connector); + +extern void radeon_compute_pll(struct radeon_pll *pll, + uint64_t freq, + uint32_t *dot_clock_p, + uint32_t *fb_div_p, + uint32_t *frac_fb_div_p, + uint32_t *ref_div_p, + uint32_t *post_div_p, + int flags); + +struct drm_encoder *radeon_encoder_legacy_lvds_add(struct drm_device *dev, int bios_index); +struct drm_encoder *radeon_encoder_legacy_primary_dac_add(struct drm_device *dev, int bios_index, int with_tv); +struct drm_encoder *radeon_encoder_legacy_tv_dac_add(struct drm_device *dev, int bios_index, int with_tv); +struct drm_encoder *radeon_encoder_legacy_tmds_int_add(struct drm_device *dev, int bios_index); +struct drm_encoder *radeon_encoder_legacy_tmds_ext_add(struct drm_device *dev, int bios_index); +extern void atombios_external_tmds_setup(struct drm_encoder *encoder, int action); +extern int atombios_get_encoder_mode(struct drm_encoder *encoder); + +extern void radeon_crtc_load_lut(struct drm_crtc *crtc); +extern int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y, + struct drm_framebuffer *old_fb); +extern int atombios_crtc_mode_set(struct drm_crtc *crtc, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode, + int x, int y, + struct drm_framebuffer *old_fb); +extern void atombios_crtc_dpms(struct drm_crtc *crtc, int mode); + +extern int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y, + struct drm_framebuffer *old_fb); +extern void radeon_legacy_atom_set_surface(struct drm_crtc *crtc); + +extern int radeon_crtc_cursor_set(struct drm_crtc *crtc, + struct drm_file *file_priv, + uint32_t handle, + uint32_t width, + uint32_t height); +extern int radeon_crtc_cursor_move(struct drm_crtc *crtc, + int x, int y); + +extern bool radeon_atom_get_clock_info(struct drm_device *dev); +extern bool radeon_combios_get_clock_info(struct drm_device *dev); +extern struct radeon_encoder_atom_dig * +radeon_atombios_get_lvds_info(struct radeon_encoder *encoder); +extern struct radeon_encoder_int_tmds * +radeon_atombios_get_tmds_info(struct radeon_encoder *encoder); +extern struct radeon_encoder_primary_dac * +radeon_atombios_get_primary_dac_info(struct radeon_encoder *encoder); +extern struct radeon_encoder_tv_dac * +radeon_atombios_get_tv_dac_info(struct radeon_encoder *encoder); +extern struct radeon_encoder_lvds * +radeon_combios_get_lvds_info(struct radeon_encoder *encoder); +extern struct radeon_encoder_int_tmds * +radeon_combios_get_tmds_info(struct radeon_encoder *encoder); +extern void radeon_combios_get_ext_tmds_info(struct radeon_encoder *encoder); +extern struct radeon_encoder_tv_dac * +radeon_combios_get_tv_dac_info(struct radeon_encoder *encoder); +extern struct radeon_encoder_primary_dac * +radeon_combios_get_primary_dac_info(struct radeon_encoder *encoder); +extern void radeon_combios_output_lock(struct drm_encoder *encoder, bool lock); +extern void radeon_combios_initialize_bios_scratch_regs(struct drm_device *dev); +extern void radeon_atom_output_lock(struct drm_encoder *encoder, bool lock); +extern void radeon_atom_initialize_bios_scratch_regs(struct drm_device *dev); +extern void +radeon_atombios_encoder_crtc_scratch_regs(struct drm_encoder *encoder, int crtc); +extern void +radeon_atombios_encoder_dpms_scratch_regs(struct drm_encoder *encoder, bool on); +extern void +radeon_combios_encoder_crtc_scratch_regs(struct drm_encoder *encoder, int crtc); +extern void +radeon_combios_encoder_dpms_scratch_regs(struct drm_encoder *encoder, bool on); +extern void radeon_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, + u16 blue, int regno); +struct drm_framebuffer *radeon_framebuffer_create(struct drm_device *dev, + struct drm_mode_fb_cmd *mode_cmd, + struct drm_gem_object *obj); + +int radeonfb_probe(struct drm_device *dev); + +int radeonfb_remove(struct drm_device *dev, struct drm_framebuffer *fb); +bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev); +bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev); +void radeon_atombios_init_crtc(struct drm_device *dev, + struct radeon_crtc *radeon_crtc); +void radeon_legacy_init_crtc(struct drm_device *dev, + struct radeon_crtc *radeon_crtc); +void radeon_i2c_do_lock(struct radeon_connector *radeon_connector, int lock_state); + +void radeon_get_clock_info(struct drm_device *dev); + +extern bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev); +extern bool radeon_get_atom_connector_info_from_supported_devices_table(struct drm_device *dev); + +void radeon_rmx_mode_fixup(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); +void radeon_enc_destroy(struct drm_encoder *encoder); +void radeon_copy_fb(struct drm_device *dev, struct drm_gem_object *dst_obj); +void radeon_combios_asic_init(struct drm_device *dev); +extern int radeon_static_clocks_init(struct drm_device *dev); +void radeon_init_disp_bw_legacy(struct drm_device *dev, + struct drm_display_mode *mode1, + uint32_t pixel_bytes1, + struct drm_display_mode *mode2, + uint32_t pixel_bytes2); +void radeon_init_disp_bw_avivo(struct drm_device *dev, + struct drm_display_mode *mode1, + uint32_t pixel_bytes1, + struct drm_display_mode *mode2, + uint32_t pixel_bytes2); +void radeon_init_disp_bandwidth(struct drm_device *dev); + +#endif diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c new file mode 100644 index 000000000000..983e8df5e000 --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -0,0 +1,511 @@ +/* + * Copyright 2009 Jerome Glisse. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + */ +/* + * Authors: + * Jerome Glisse + * Thomas Hellstrom + * Dave Airlie + */ +#include +#include +#include "radeon_drm.h" +#include "radeon.h" + +struct radeon_object { + struct ttm_buffer_object tobj; + struct list_head list; + struct radeon_device *rdev; + struct drm_gem_object *gobj; + struct ttm_bo_kmap_obj kmap; + unsigned pin_count; + uint64_t gpu_addr; + void *kptr; + bool is_iomem; +}; + +int radeon_ttm_init(struct radeon_device *rdev); +void radeon_ttm_fini(struct radeon_device *rdev); + +/* + * To exclude mutual BO access we rely on bo_reserve exclusion, as all + * function are calling it. + */ + +static int radeon_object_reserve(struct radeon_object *robj, bool interruptible) +{ + return ttm_bo_reserve(&robj->tobj, interruptible, false, false, 0); +} + +static void radeon_object_unreserve(struct radeon_object *robj) +{ + ttm_bo_unreserve(&robj->tobj); +} + +static void radeon_ttm_object_object_destroy(struct ttm_buffer_object *tobj) +{ + struct radeon_object *robj; + + robj = container_of(tobj, struct radeon_object, tobj); + list_del_init(&robj->list); + kfree(robj); +} + +static inline void radeon_object_gpu_addr(struct radeon_object *robj) +{ + /* Default gpu address */ + robj->gpu_addr = 0xFFFFFFFFFFFFFFFFULL; + if (robj->tobj.mem.mm_node == NULL) { + return; + } + robj->gpu_addr = ((u64)robj->tobj.mem.mm_node->start) << PAGE_SHIFT; + switch (robj->tobj.mem.mem_type) { + case TTM_PL_VRAM: + robj->gpu_addr += (u64)robj->rdev->mc.vram_location; + break; + case TTM_PL_TT: + robj->gpu_addr += (u64)robj->rdev->mc.gtt_location; + break; + default: + DRM_ERROR("Unknown placement %d\n", robj->tobj.mem.mem_type); + robj->gpu_addr = 0xFFFFFFFFFFFFFFFFULL; + return; + } +} + +static inline uint32_t radeon_object_flags_from_domain(uint32_t domain) +{ + uint32_t flags = 0; + if (domain & RADEON_GEM_DOMAIN_VRAM) { + flags |= TTM_PL_FLAG_VRAM; + } + if (domain & RADEON_GEM_DOMAIN_GTT) { + flags |= TTM_PL_FLAG_TT; + } + if (domain & RADEON_GEM_DOMAIN_CPU) { + flags |= TTM_PL_FLAG_SYSTEM; + } + if (!flags) { + flags |= TTM_PL_FLAG_SYSTEM; + } + return flags; +} + +int radeon_object_create(struct radeon_device *rdev, + struct drm_gem_object *gobj, + unsigned long size, + bool kernel, + uint32_t domain, + bool interruptible, + struct radeon_object **robj_ptr) +{ + struct radeon_object *robj; + enum ttm_bo_type type; + uint32_t flags; + int r; + + if (unlikely(rdev->mman.bdev.dev_mapping == NULL)) { + rdev->mman.bdev.dev_mapping = rdev->ddev->dev_mapping; + } + if (kernel) { + type = ttm_bo_type_kernel; + } else { + type = ttm_bo_type_device; + } + *robj_ptr = NULL; + robj = kzalloc(sizeof(struct radeon_object), GFP_KERNEL); + if (robj == NULL) { + return -ENOMEM; + } + robj->rdev = rdev; + robj->gobj = gobj; + INIT_LIST_HEAD(&robj->list); + + flags = radeon_object_flags_from_domain(domain); + r = ttm_buffer_object_init(&rdev->mman.bdev, &robj->tobj, size, type, flags, + 0, 0, false, NULL, size, + &radeon_ttm_object_object_destroy); + if (unlikely(r != 0)) { + /* ttm call radeon_ttm_object_object_destroy if error happen */ + DRM_ERROR("Failed to allocate TTM object (%ld, 0x%08X, %u)\n", + size, flags, 0); + return r; + } + *robj_ptr = robj; + if (gobj) { + list_add_tail(&robj->list, &rdev->gem.objects); + } + return 0; +} + +int radeon_object_kmap(struct radeon_object *robj, void **ptr) +{ + int r; + + spin_lock(&robj->tobj.lock); + if (robj->kptr) { + if (ptr) { + *ptr = robj->kptr; + } + spin_unlock(&robj->tobj.lock); + return 0; + } + spin_unlock(&robj->tobj.lock); + r = ttm_bo_kmap(&robj->tobj, 0, robj->tobj.num_pages, &robj->kmap); + if (r) { + return r; + } + spin_lock(&robj->tobj.lock); + robj->kptr = ttm_kmap_obj_virtual(&robj->kmap, &robj->is_iomem); + spin_unlock(&robj->tobj.lock); + if (ptr) { + *ptr = robj->kptr; + } + return 0; +} + +void radeon_object_kunmap(struct radeon_object *robj) +{ + spin_lock(&robj->tobj.lock); + if (robj->kptr == NULL) { + spin_unlock(&robj->tobj.lock); + return; + } + robj->kptr = NULL; + spin_unlock(&robj->tobj.lock); + ttm_bo_kunmap(&robj->kmap); +} + +void radeon_object_unref(struct radeon_object **robj) +{ + struct ttm_buffer_object *tobj; + + if ((*robj) == NULL) { + return; + } + tobj = &((*robj)->tobj); + ttm_bo_unref(&tobj); + if (tobj == NULL) { + *robj = NULL; + } +} + +int radeon_object_mmap(struct radeon_object *robj, uint64_t *offset) +{ + *offset = robj->tobj.addr_space_offset; + return 0; +} + +int radeon_object_pin(struct radeon_object *robj, uint32_t domain, + uint64_t *gpu_addr) +{ + uint32_t flags; + uint32_t tmp; + void *fbptr; + int r; + + flags = radeon_object_flags_from_domain(domain); + spin_lock(&robj->tobj.lock); + if (robj->pin_count) { + robj->pin_count++; + if (gpu_addr != NULL) { + *gpu_addr = robj->gpu_addr; + } + spin_unlock(&robj->tobj.lock); + return 0; + } + spin_unlock(&robj->tobj.lock); + r = radeon_object_reserve(robj, false); + if (unlikely(r != 0)) { + DRM_ERROR("radeon: failed to reserve object for pinning it.\n"); + return r; + } + if (robj->rdev->fbdev_robj == robj) { + mutex_lock(&robj->rdev->fbdev_info->lock); + radeon_object_kunmap(robj); + } + tmp = robj->tobj.mem.placement; + ttm_flag_masked(&tmp, flags, TTM_PL_MASK_MEM); + robj->tobj.proposed_placement = tmp | TTM_PL_FLAG_NO_EVICT | TTM_PL_MASK_CACHING; + r = ttm_buffer_object_validate(&robj->tobj, + robj->tobj.proposed_placement, + false, false); + radeon_object_gpu_addr(robj); + if (gpu_addr != NULL) { + *gpu_addr = robj->gpu_addr; + } + robj->pin_count = 1; + if (unlikely(r != 0)) { + DRM_ERROR("radeon: failed to pin object.\n"); + } + radeon_object_unreserve(robj); + if (robj->rdev->fbdev_robj == robj) { + if (!r) { + r = radeon_object_kmap(robj, &fbptr); + } + if (!r) { + robj->rdev->fbdev_info->screen_base = fbptr; + robj->rdev->fbdev_info->fix.smem_start = (unsigned long)fbptr; + } + mutex_unlock(&robj->rdev->fbdev_info->lock); + } + return r; +} + +void radeon_object_unpin(struct radeon_object *robj) +{ + uint32_t flags; + void *fbptr; + int r; + + spin_lock(&robj->tobj.lock); + if (!robj->pin_count) { + spin_unlock(&robj->tobj.lock); + printk(KERN_WARNING "Unpin not necessary for %p !\n", robj); + return; + } + robj->pin_count--; + if (robj->pin_count) { + spin_unlock(&robj->tobj.lock); + return; + } + spin_unlock(&robj->tobj.lock); + r = radeon_object_reserve(robj, false); + if (unlikely(r != 0)) { + DRM_ERROR("radeon: failed to reserve object for unpinning it.\n"); + return; + } + if (robj->rdev->fbdev_robj == robj) { + mutex_lock(&robj->rdev->fbdev_info->lock); + radeon_object_kunmap(robj); + } + flags = robj->tobj.mem.placement; + robj->tobj.proposed_placement = flags & ~TTM_PL_FLAG_NO_EVICT; + r = ttm_buffer_object_validate(&robj->tobj, + robj->tobj.proposed_placement, + false, false); + if (unlikely(r != 0)) { + DRM_ERROR("radeon: failed to unpin buffer.\n"); + } + radeon_object_unreserve(robj); + if (robj->rdev->fbdev_robj == robj) { + if (!r) { + r = radeon_object_kmap(robj, &fbptr); + } + if (!r) { + robj->rdev->fbdev_info->screen_base = fbptr; + robj->rdev->fbdev_info->fix.smem_start = (unsigned long)fbptr; + } + mutex_unlock(&robj->rdev->fbdev_info->lock); + } +} + +int radeon_object_wait(struct radeon_object *robj) +{ + int r = 0; + + /* FIXME: should use block reservation instead */ + r = radeon_object_reserve(robj, true); + if (unlikely(r != 0)) { + DRM_ERROR("radeon: failed to reserve object for waiting.\n"); + return r; + } + spin_lock(&robj->tobj.lock); + if (robj->tobj.sync_obj) { + r = ttm_bo_wait(&robj->tobj, true, false, false); + } + spin_unlock(&robj->tobj.lock); + radeon_object_unreserve(robj); + return r; +} + +int radeon_object_evict_vram(struct radeon_device *rdev) +{ + if (rdev->flags & RADEON_IS_IGP) { + /* Useless to evict on IGP chips */ + return 0; + } + return ttm_bo_evict_mm(&rdev->mman.bdev, TTM_PL_VRAM); +} + +void radeon_object_force_delete(struct radeon_device *rdev) +{ + struct radeon_object *robj, *n; + struct drm_gem_object *gobj; + + if (list_empty(&rdev->gem.objects)) { + return; + } + DRM_ERROR("Userspace still has active objects !\n"); + list_for_each_entry_safe(robj, n, &rdev->gem.objects, list) { + mutex_lock(&rdev->ddev->struct_mutex); + gobj = robj->gobj; + DRM_ERROR("Force free for (%p,%p,%lu,%lu)\n", + gobj, robj, (unsigned long)gobj->size, + *((unsigned long *)&gobj->refcount)); + list_del_init(&robj->list); + radeon_object_unref(&robj); + gobj->driver_private = NULL; + drm_gem_object_unreference(gobj); + mutex_unlock(&rdev->ddev->struct_mutex); + } +} + +int radeon_object_init(struct radeon_device *rdev) +{ + return radeon_ttm_init(rdev); +} + +void radeon_object_fini(struct radeon_device *rdev) +{ + radeon_ttm_fini(rdev); +} + +void radeon_object_list_add_object(struct radeon_object_list *lobj, + struct list_head *head) +{ + if (lobj->wdomain) { + list_add(&lobj->list, head); + } else { + list_add_tail(&lobj->list, head); + } +} + +int radeon_object_list_reserve(struct list_head *head) +{ + struct radeon_object_list *lobj; + struct list_head *i; + int r; + + list_for_each(i, head) { + lobj = list_entry(i, struct radeon_object_list, list); + if (!lobj->robj->pin_count) { + r = radeon_object_reserve(lobj->robj, true); + if (unlikely(r != 0)) { + DRM_ERROR("radeon: failed to reserve object.\n"); + return r; + } + } else { + } + } + return 0; +} + +void radeon_object_list_unreserve(struct list_head *head) +{ + struct radeon_object_list *lobj; + struct list_head *i; + + list_for_each(i, head) { + lobj = list_entry(i, struct radeon_object_list, list); + if (!lobj->robj->pin_count) { + radeon_object_unreserve(lobj->robj); + } else { + } + } +} + +int radeon_object_list_validate(struct list_head *head, void *fence) +{ + struct radeon_object_list *lobj; + struct radeon_object *robj; + struct radeon_fence *old_fence = NULL; + struct list_head *i; + uint32_t flags; + int r; + + r = radeon_object_list_reserve(head); + if (unlikely(r != 0)) { + radeon_object_list_unreserve(head); + return r; + } + list_for_each(i, head) { + lobj = list_entry(i, struct radeon_object_list, list); + robj = lobj->robj; + if (lobj->wdomain) { + flags = radeon_object_flags_from_domain(lobj->wdomain); + flags |= TTM_PL_FLAG_TT; + } else { + flags = radeon_object_flags_from_domain(lobj->rdomain); + flags |= TTM_PL_FLAG_TT; + flags |= TTM_PL_FLAG_VRAM; + } + if (!robj->pin_count) { + robj->tobj.proposed_placement = flags | TTM_PL_MASK_CACHING; + r = ttm_buffer_object_validate(&robj->tobj, + robj->tobj.proposed_placement, + true, false); + if (unlikely(r)) { + radeon_object_list_unreserve(head); + DRM_ERROR("radeon: failed to validate.\n"); + return r; + } + radeon_object_gpu_addr(robj); + } + lobj->gpu_offset = robj->gpu_addr; + if (fence) { + old_fence = (struct radeon_fence *)robj->tobj.sync_obj; + robj->tobj.sync_obj = radeon_fence_ref(fence); + robj->tobj.sync_obj_arg = NULL; + } + if (old_fence) { + radeon_fence_unref(&old_fence); + } + } + return 0; +} + +void radeon_object_list_unvalidate(struct list_head *head) +{ + struct radeon_object_list *lobj; + struct radeon_fence *old_fence = NULL; + struct list_head *i; + + list_for_each(i, head) { + lobj = list_entry(i, struct radeon_object_list, list); + old_fence = (struct radeon_fence *)lobj->robj->tobj.sync_obj; + lobj->robj->tobj.sync_obj = NULL; + if (old_fence) { + radeon_fence_unref(&old_fence); + } + } + radeon_object_list_unreserve(head); +} + +void radeon_object_list_clean(struct list_head *head) +{ + radeon_object_list_unreserve(head); +} + +int radeon_object_fbdev_mmap(struct radeon_object *robj, + struct vm_area_struct *vma) +{ + return ttm_fbdev_mmap(vma, &robj->tobj); +} + +unsigned long radeon_object_size(struct radeon_object *robj) +{ + return robj->tobj.num_pages << PAGE_SHIFT; +} diff --git a/drivers/gpu/drm/radeon/radeon_object.h b/drivers/gpu/drm/radeon/radeon_object.h new file mode 100644 index 000000000000..473e4775dc5a --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_object.h @@ -0,0 +1,45 @@ +/* + * Copyright 2008 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * Copyright 2009 Jerome Glisse. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Dave Airlie + * Alex Deucher + * Jerome Glisse + */ +#ifndef __RADEON_OBJECT_H__ +#define __RADEON_OBJECT_H__ + +#include +#include +#include +#include + +/* + * TTM. + */ +struct radeon_mman { + struct ttm_global_reference mem_global_ref; + bool mem_global_referenced; + struct ttm_bo_device bdev; +}; + +#endif diff --git a/drivers/gpu/drm/radeon/radeon_reg.h b/drivers/gpu/drm/radeon/radeon_reg.h new file mode 100644 index 000000000000..e1b618574461 --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_reg.h @@ -0,0 +1,3571 @@ +/* + * Copyright 2000 ATI Technologies Inc., Markham, Ontario, and + * VA Linux Systems Inc., Fremont, California. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR + * THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/* + * Authors: + * Kevin E. Martin + * Rickard E. Faith + * Alan Hourihane + * + * References: + * + * !!!! FIXME !!!! + * RAGE 128 VR/ RAGE 128 GL Register Reference Manual (Technical + * Reference Manual P/N RRG-G04100-C Rev. 0.04), ATI Technologies: April + * 1999. + * + * !!!! FIXME !!!! + * RAGE 128 Software Development Manual (Technical Reference Manual P/N + * SDK-G04000 Rev. 0.01), ATI Technologies: June 1999. + * + */ + +/* !!!! FIXME !!!! NOTE: THIS FILE HAS BEEN CONVERTED FROM r128_reg.h + * AND CONTAINS REGISTERS AND REGISTER DEFINITIONS THAT ARE NOT CORRECT + * ON THE RADEON. A FULL AUDIT OF THIS CODE IS NEEDED! */ +#ifndef _RADEON_REG_H_ +#define _RADEON_REG_H_ + +#include "r300_reg.h" +#include "r500_reg.h" +#include "r600_reg.h" + + +#define RADEON_MC_AGP_LOCATION 0x014c +#define RADEON_MC_AGP_START_MASK 0x0000FFFF +#define RADEON_MC_AGP_START_SHIFT 0 +#define RADEON_MC_AGP_TOP_MASK 0xFFFF0000 +#define RADEON_MC_AGP_TOP_SHIFT 16 +#define RADEON_MC_FB_LOCATION 0x0148 +#define RADEON_MC_FB_START_MASK 0x0000FFFF +#define RADEON_MC_FB_START_SHIFT 0 +#define RADEON_MC_FB_TOP_MASK 0xFFFF0000 +#define RADEON_MC_FB_TOP_SHIFT 16 +#define RADEON_AGP_BASE_2 0x015c /* r200+ only */ +#define RADEON_AGP_BASE 0x0170 + +#define ATI_DATATYPE_VQ 0 +#define ATI_DATATYPE_CI4 1 +#define ATI_DATATYPE_CI8 2 +#define ATI_DATATYPE_ARGB1555 3 +#define ATI_DATATYPE_RGB565 4 +#define ATI_DATATYPE_RGB888 5 +#define ATI_DATATYPE_ARGB8888 6 +#define ATI_DATATYPE_RGB332 7 +#define ATI_DATATYPE_Y8 8 +#define ATI_DATATYPE_RGB8 9 +#define ATI_DATATYPE_CI16 10 +#define ATI_DATATYPE_VYUY_422 11 +#define ATI_DATATYPE_YVYU_422 12 +#define ATI_DATATYPE_AYUV_444 14 +#define ATI_DATATYPE_ARGB4444 15 + + /* Registers for 2D/Video/Overlay */ +#define RADEON_ADAPTER_ID 0x0f2c /* PCI */ +#define RADEON_AGP_BASE 0x0170 +#define RADEON_AGP_CNTL 0x0174 +# define RADEON_AGP_APER_SIZE_256MB (0x00 << 0) +# define RADEON_AGP_APER_SIZE_128MB (0x20 << 0) +# define RADEON_AGP_APER_SIZE_64MB (0x30 << 0) +# define RADEON_AGP_APER_SIZE_32MB (0x38 << 0) +# define RADEON_AGP_APER_SIZE_16MB (0x3c << 0) +# define RADEON_AGP_APER_SIZE_8MB (0x3e << 0) +# define RADEON_AGP_APER_SIZE_4MB (0x3f << 0) +# define RADEON_AGP_APER_SIZE_MASK (0x3f << 0) +#define RADEON_STATUS_PCI_CONFIG 0x06 +# define RADEON_CAP_LIST 0x100000 +#define RADEON_CAPABILITIES_PTR_PCI_CONFIG 0x34 /* offset in PCI config*/ +# define RADEON_CAP_PTR_MASK 0xfc /* mask off reserved bits of CAP_PTR */ +# define RADEON_CAP_ID_NULL 0x00 /* End of capability list */ +# define RADEON_CAP_ID_AGP 0x02 /* AGP capability ID */ +# define RADEON_CAP_ID_EXP 0x10 /* PCI Express */ +#define RADEON_AGP_COMMAND 0x0f60 /* PCI */ +#define RADEON_AGP_COMMAND_PCI_CONFIG 0x0060 /* offset in PCI config*/ +# define RADEON_AGP_ENABLE (1<<8) +#define RADEON_AGP_PLL_CNTL 0x000b /* PLL */ +#define RADEON_AGP_STATUS 0x0f5c /* PCI */ +# define RADEON_AGP_1X_MODE 0x01 +# define RADEON_AGP_2X_MODE 0x02 +# define RADEON_AGP_4X_MODE 0x04 +# define RADEON_AGP_FW_MODE 0x10 +# define RADEON_AGP_MODE_MASK 0x17 +# define RADEON_AGPv3_MODE 0x08 +# define RADEON_AGPv3_4X_MODE 0x01 +# define RADEON_AGPv3_8X_MODE 0x02 +#define RADEON_ATTRDR 0x03c1 /* VGA */ +#define RADEON_ATTRDW 0x03c0 /* VGA */ +#define RADEON_ATTRX 0x03c0 /* VGA */ +#define RADEON_AUX_SC_CNTL 0x1660 +# define RADEON_AUX1_SC_EN (1 << 0) +# define RADEON_AUX1_SC_MODE_OR (0 << 1) +# define RADEON_AUX1_SC_MODE_NAND (1 << 1) +# define RADEON_AUX2_SC_EN (1 << 2) +# define RADEON_AUX2_SC_MODE_OR (0 << 3) +# define RADEON_AUX2_SC_MODE_NAND (1 << 3) +# define RADEON_AUX3_SC_EN (1 << 4) +# define RADEON_AUX3_SC_MODE_OR (0 << 5) +# define RADEON_AUX3_SC_MODE_NAND (1 << 5) +#define RADEON_AUX1_SC_BOTTOM 0x1670 +#define RADEON_AUX1_SC_LEFT 0x1664 +#define RADEON_AUX1_SC_RIGHT 0x1668 +#define RADEON_AUX1_SC_TOP 0x166c +#define RADEON_AUX2_SC_BOTTOM 0x1680 +#define RADEON_AUX2_SC_LEFT 0x1674 +#define RADEON_AUX2_SC_RIGHT 0x1678 +#define RADEON_AUX2_SC_TOP 0x167c +#define RADEON_AUX3_SC_BOTTOM 0x1690 +#define RADEON_AUX3_SC_LEFT 0x1684 +#define RADEON_AUX3_SC_RIGHT 0x1688 +#define RADEON_AUX3_SC_TOP 0x168c +#define RADEON_AUX_WINDOW_HORZ_CNTL 0x02d8 +#define RADEON_AUX_WINDOW_VERT_CNTL 0x02dc + +#define RADEON_BASE_CODE 0x0f0b +#define RADEON_BIOS_0_SCRATCH 0x0010 +# define RADEON_FP_PANEL_SCALABLE (1 << 16) +# define RADEON_FP_PANEL_SCALE_EN (1 << 17) +# define RADEON_FP_CHIP_SCALE_EN (1 << 18) +# define RADEON_DRIVER_BRIGHTNESS_EN (1 << 26) +# define RADEON_DISPLAY_ROT_MASK (3 << 28) +# define RADEON_DISPLAY_ROT_00 (0 << 28) +# define RADEON_DISPLAY_ROT_90 (1 << 28) +# define RADEON_DISPLAY_ROT_180 (2 << 28) +# define RADEON_DISPLAY_ROT_270 (3 << 28) +#define RADEON_BIOS_1_SCRATCH 0x0014 +#define RADEON_BIOS_2_SCRATCH 0x0018 +#define RADEON_BIOS_3_SCRATCH 0x001c +#define RADEON_BIOS_4_SCRATCH 0x0020 +# define RADEON_CRT1_ATTACHED_MASK (3 << 0) +# define RADEON_CRT1_ATTACHED_MONO (1 << 0) +# define RADEON_CRT1_ATTACHED_COLOR (2 << 0) +# define RADEON_LCD1_ATTACHED (1 << 2) +# define RADEON_DFP1_ATTACHED (1 << 3) +# define RADEON_TV1_ATTACHED_MASK (3 << 4) +# define RADEON_TV1_ATTACHED_COMP (1 << 4) +# define RADEON_TV1_ATTACHED_SVIDEO (2 << 4) +# define RADEON_CRT2_ATTACHED_MASK (3 << 8) +# define RADEON_CRT2_ATTACHED_MONO (1 << 8) +# define RADEON_CRT2_ATTACHED_COLOR (2 << 8) +# define RADEON_DFP2_ATTACHED (1 << 11) +#define RADEON_BIOS_5_SCRATCH 0x0024 +# define RADEON_LCD1_ON (1 << 0) +# define RADEON_CRT1_ON (1 << 1) +# define RADEON_TV1_ON (1 << 2) +# define RADEON_DFP1_ON (1 << 3) +# define RADEON_CRT2_ON (1 << 5) +# define RADEON_CV1_ON (1 << 6) +# define RADEON_DFP2_ON (1 << 7) +# define RADEON_LCD1_CRTC_MASK (1 << 8) +# define RADEON_LCD1_CRTC_SHIFT 8 +# define RADEON_CRT1_CRTC_MASK (1 << 9) +# define RADEON_CRT1_CRTC_SHIFT 9 +# define RADEON_TV1_CRTC_MASK (1 << 10) +# define RADEON_TV1_CRTC_SHIFT 10 +# define RADEON_DFP1_CRTC_MASK (1 << 11) +# define RADEON_DFP1_CRTC_SHIFT 11 +# define RADEON_CRT2_CRTC_MASK (1 << 12) +# define RADEON_CRT2_CRTC_SHIFT 12 +# define RADEON_CV1_CRTC_MASK (1 << 13) +# define RADEON_CV1_CRTC_SHIFT 13 +# define RADEON_DFP2_CRTC_MASK (1 << 14) +# define RADEON_DFP2_CRTC_SHIFT 14 +# define RADEON_ACC_REQ_LCD1 (1 << 16) +# define RADEON_ACC_REQ_CRT1 (1 << 17) +# define RADEON_ACC_REQ_TV1 (1 << 18) +# define RADEON_ACC_REQ_DFP1 (1 << 19) +# define RADEON_ACC_REQ_CRT2 (1 << 21) +# define RADEON_ACC_REQ_TV2 (1 << 22) +# define RADEON_ACC_REQ_DFP2 (1 << 23) +#define RADEON_BIOS_6_SCRATCH 0x0028 +# define RADEON_ACC_MODE_CHANGE (1 << 2) +# define RADEON_EXT_DESKTOP_MODE (1 << 3) +# define RADEON_LCD_DPMS_ON (1 << 20) +# define RADEON_CRT_DPMS_ON (1 << 21) +# define RADEON_TV_DPMS_ON (1 << 22) +# define RADEON_DFP_DPMS_ON (1 << 23) +# define RADEON_DPMS_MASK (3 << 24) +# define RADEON_DPMS_ON (0 << 24) +# define RADEON_DPMS_STANDBY (1 << 24) +# define RADEON_DPMS_SUSPEND (2 << 24) +# define RADEON_DPMS_OFF (3 << 24) +# define RADEON_SCREEN_BLANKING (1 << 26) +# define RADEON_DRIVER_CRITICAL (1 << 27) +# define RADEON_DISPLAY_SWITCHING_DIS (1 << 30) +#define RADEON_BIOS_7_SCRATCH 0x002c +# define RADEON_SYS_HOTKEY (1 << 10) +# define RADEON_DRV_LOADED (1 << 12) +#define RADEON_BIOS_ROM 0x0f30 /* PCI */ +#define RADEON_BIST 0x0f0f /* PCI */ +#define RADEON_BRUSH_DATA0 0x1480 +#define RADEON_BRUSH_DATA1 0x1484 +#define RADEON_BRUSH_DATA10 0x14a8 +#define RADEON_BRUSH_DATA11 0x14ac +#define RADEON_BRUSH_DATA12 0x14b0 +#define RADEON_BRUSH_DATA13 0x14b4 +#define RADEON_BRUSH_DATA14 0x14b8 +#define RADEON_BRUSH_DATA15 0x14bc +#define RADEON_BRUSH_DATA16 0x14c0 +#define RADEON_BRUSH_DATA17 0x14c4 +#define RADEON_BRUSH_DATA18 0x14c8 +#define RADEON_BRUSH_DATA19 0x14cc +#define RADEON_BRUSH_DATA2 0x1488 +#define RADEON_BRUSH_DATA20 0x14d0 +#define RADEON_BRUSH_DATA21 0x14d4 +#define RADEON_BRUSH_DATA22 0x14d8 +#define RADEON_BRUSH_DATA23 0x14dc +#define RADEON_BRUSH_DATA24 0x14e0 +#define RADEON_BRUSH_DATA25 0x14e4 +#define RADEON_BRUSH_DATA26 0x14e8 +#define RADEON_BRUSH_DATA27 0x14ec +#define RADEON_BRUSH_DATA28 0x14f0 +#define RADEON_BRUSH_DATA29 0x14f4 +#define RADEON_BRUSH_DATA3 0x148c +#define RADEON_BRUSH_DATA30 0x14f8 +#define RADEON_BRUSH_DATA31 0x14fc +#define RADEON_BRUSH_DATA32 0x1500 +#define RADEON_BRUSH_DATA33 0x1504 +#define RADEON_BRUSH_DATA34 0x1508 +#define RADEON_BRUSH_DATA35 0x150c +#define RADEON_BRUSH_DATA36 0x1510 +#define RADEON_BRUSH_DATA37 0x1514 +#define RADEON_BRUSH_DATA38 0x1518 +#define RADEON_BRUSH_DATA39 0x151c +#define RADEON_BRUSH_DATA4 0x1490 +#define RADEON_BRUSH_DATA40 0x1520 +#define RADEON_BRUSH_DATA41 0x1524 +#define RADEON_BRUSH_DATA42 0x1528 +#define RADEON_BRUSH_DATA43 0x152c +#define RADEON_BRUSH_DATA44 0x1530 +#define RADEON_BRUSH_DATA45 0x1534 +#define RADEON_BRUSH_DATA46 0x1538 +#define RADEON_BRUSH_DATA47 0x153c +#define RADEON_BRUSH_DATA48 0x1540 +#define RADEON_BRUSH_DATA49 0x1544 +#define RADEON_BRUSH_DATA5 0x1494 +#define RADEON_BRUSH_DATA50 0x1548 +#define RADEON_BRUSH_DATA51 0x154c +#define RADEON_BRUSH_DATA52 0x1550 +#define RADEON_BRUSH_DATA53 0x1554 +#define RADEON_BRUSH_DATA54 0x1558 +#define RADEON_BRUSH_DATA55 0x155c +#define RADEON_BRUSH_DATA56 0x1560 +#define RADEON_BRUSH_DATA57 0x1564 +#define RADEON_BRUSH_DATA58 0x1568 +#define RADEON_BRUSH_DATA59 0x156c +#define RADEON_BRUSH_DATA6 0x1498 +#define RADEON_BRUSH_DATA60 0x1570 +#define RADEON_BRUSH_DATA61 0x1574 +#define RADEON_BRUSH_DATA62 0x1578 +#define RADEON_BRUSH_DATA63 0x157c +#define RADEON_BRUSH_DATA7 0x149c +#define RADEON_BRUSH_DATA8 0x14a0 +#define RADEON_BRUSH_DATA9 0x14a4 +#define RADEON_BRUSH_SCALE 0x1470 +#define RADEON_BRUSH_Y_X 0x1474 +#define RADEON_BUS_CNTL 0x0030 +# define RADEON_BUS_MASTER_DIS (1 << 6) +# define RADEON_BUS_BIOS_DIS_ROM (1 << 12) +# define RADEON_BUS_RD_DISCARD_EN (1 << 24) +# define RADEON_BUS_RD_ABORT_EN (1 << 25) +# define RADEON_BUS_MSTR_DISCONNECT_EN (1 << 28) +# define RADEON_BUS_WRT_BURST (1 << 29) +# define RADEON_BUS_READ_BURST (1 << 30) +#define RADEON_BUS_CNTL1 0x0034 +# define RADEON_BUS_WAIT_ON_LOCK_EN (1 << 4) + +/* #define RADEON_PCIE_INDEX 0x0030 */ +/* #define RADEON_PCIE_DATA 0x0034 */ +#define RADEON_PCIE_LC_LINK_WIDTH_CNTL 0xa2 /* PCIE */ +# define RADEON_PCIE_LC_LINK_WIDTH_SHIFT 0 +# define RADEON_PCIE_LC_LINK_WIDTH_MASK 0x7 +# define RADEON_PCIE_LC_LINK_WIDTH_X0 0 +# define RADEON_PCIE_LC_LINK_WIDTH_X1 1 +# define RADEON_PCIE_LC_LINK_WIDTH_X2 2 +# define RADEON_PCIE_LC_LINK_WIDTH_X4 3 +# define RADEON_PCIE_LC_LINK_WIDTH_X8 4 +# define RADEON_PCIE_LC_LINK_WIDTH_X12 5 +# define RADEON_PCIE_LC_LINK_WIDTH_X16 6 +# define RADEON_PCIE_LC_LINK_WIDTH_RD_SHIFT 4 +# define RADEON_PCIE_LC_LINK_WIDTH_RD_MASK 0x70 +# define RADEON_PCIE_LC_RECONFIG_NOW (1 << 8) +# define RADEON_PCIE_LC_RECONFIG_LATER (1 << 9) +# define RADEON_PCIE_LC_SHORT_RECONFIG_EN (1 << 10) + +#define RADEON_CACHE_CNTL 0x1724 +#define RADEON_CACHE_LINE 0x0f0c /* PCI */ +#define RADEON_CAPABILITIES_ID 0x0f50 /* PCI */ +#define RADEON_CAPABILITIES_PTR 0x0f34 /* PCI */ +#define RADEON_CLK_PIN_CNTL 0x0001 /* PLL */ +# define RADEON_DONT_USE_XTALIN (1 << 4) +# define RADEON_SCLK_DYN_START_CNTL (1 << 15) +#define RADEON_CLOCK_CNTL_DATA 0x000c +#define RADEON_CLOCK_CNTL_INDEX 0x0008 +# define RADEON_PLL_WR_EN (1 << 7) +# define RADEON_PLL_DIV_SEL (3 << 8) +# define RADEON_PLL2_DIV_SEL_MASK (~(3 << 8)) +#define RADEON_CLK_PWRMGT_CNTL 0x0014 +# define RADEON_ENGIN_DYNCLK_MODE (1 << 12) +# define RADEON_ACTIVE_HILO_LAT_MASK (3 << 13) +# define RADEON_ACTIVE_HILO_LAT_SHIFT 13 +# define RADEON_DISP_DYN_STOP_LAT_MASK (1 << 12) +# define RADEON_MC_BUSY (1 << 16) +# define RADEON_DLL_READY (1 << 19) +# define RADEON_CG_NO1_DEBUG_0 (1 << 24) +# define RADEON_CG_NO1_DEBUG_MASK (0x1f << 24) +# define RADEON_DYN_STOP_MODE_MASK (7 << 21) +# define RADEON_TVPLL_PWRMGT_OFF (1 << 30) +# define RADEON_TVCLK_TURNOFF (1 << 31) +#define RADEON_PLL_PWRMGT_CNTL 0x0015 /* PLL */ +# define RADEON_TCL_BYPASS_DISABLE (1 << 20) +#define RADEON_CLR_CMP_CLR_3D 0x1a24 +#define RADEON_CLR_CMP_CLR_DST 0x15c8 +#define RADEON_CLR_CMP_CLR_SRC 0x15c4 +#define RADEON_CLR_CMP_CNTL 0x15c0 +# define RADEON_SRC_CMP_EQ_COLOR (4 << 0) +# define RADEON_SRC_CMP_NEQ_COLOR (5 << 0) +# define RADEON_CLR_CMP_SRC_SOURCE (1 << 24) +#define RADEON_CLR_CMP_MASK 0x15cc +# define RADEON_CLR_CMP_MSK 0xffffffff +#define RADEON_CLR_CMP_MASK_3D 0x1A28 +#define RADEON_COMMAND 0x0f04 /* PCI */ +#define RADEON_COMPOSITE_SHADOW_ID 0x1a0c +#define RADEON_CONFIG_APER_0_BASE 0x0100 +#define RADEON_CONFIG_APER_1_BASE 0x0104 +#define RADEON_CONFIG_APER_SIZE 0x0108 +#define RADEON_CONFIG_BONDS 0x00e8 +#define RADEON_CONFIG_CNTL 0x00e0 +# define RADEON_CFG_ATI_REV_A11 (0 << 16) +# define RADEON_CFG_ATI_REV_A12 (1 << 16) +# define RADEON_CFG_ATI_REV_A13 (2 << 16) +# define RADEON_CFG_ATI_REV_ID_MASK (0xf << 16) +#define RADEON_CONFIG_MEMSIZE 0x00f8 +#define RADEON_CONFIG_MEMSIZE_EMBEDDED 0x0114 +#define RADEON_CONFIG_REG_1_BASE 0x010c +#define RADEON_CONFIG_REG_APER_SIZE 0x0110 +#define RADEON_CONFIG_XSTRAP 0x00e4 +#define RADEON_CONSTANT_COLOR_C 0x1d34 +# define RADEON_CONSTANT_COLOR_MASK 0x00ffffff +# define RADEON_CONSTANT_COLOR_ONE 0x00ffffff +# define RADEON_CONSTANT_COLOR_ZERO 0x00000000 +#define RADEON_CRC_CMDFIFO_ADDR 0x0740 +#define RADEON_CRC_CMDFIFO_DOUT 0x0744 +#define RADEON_GRPH_BUFFER_CNTL 0x02f0 +# define RADEON_GRPH_START_REQ_MASK (0x7f) +# define RADEON_GRPH_START_REQ_SHIFT 0 +# define RADEON_GRPH_STOP_REQ_MASK (0x7f<<8) +# define RADEON_GRPH_STOP_REQ_SHIFT 8 +# define RADEON_GRPH_CRITICAL_POINT_MASK (0x7f<<16) +# define RADEON_GRPH_CRITICAL_POINT_SHIFT 16 +# define RADEON_GRPH_CRITICAL_CNTL (1<<28) +# define RADEON_GRPH_BUFFER_SIZE (1<<29) +# define RADEON_GRPH_CRITICAL_AT_SOF (1<<30) +# define RADEON_GRPH_STOP_CNTL (1<<31) +#define RADEON_GRPH2_BUFFER_CNTL 0x03f0 +# define RADEON_GRPH2_START_REQ_MASK (0x7f) +# define RADEON_GRPH2_START_REQ_SHIFT 0 +# define RADEON_GRPH2_STOP_REQ_MASK (0x7f<<8) +# define RADEON_GRPH2_STOP_REQ_SHIFT 8 +# define RADEON_GRPH2_CRITICAL_POINT_MASK (0x7f<<16) +# define RADEON_GRPH2_CRITICAL_POINT_SHIFT 16 +# define RADEON_GRPH2_CRITICAL_CNTL (1<<28) +# define RADEON_GRPH2_BUFFER_SIZE (1<<29) +# define RADEON_GRPH2_CRITICAL_AT_SOF (1<<30) +# define RADEON_GRPH2_STOP_CNTL (1<<31) +#define RADEON_CRTC_CRNT_FRAME 0x0214 +#define RADEON_CRTC_EXT_CNTL 0x0054 +# define RADEON_CRTC_VGA_XOVERSCAN (1 << 0) +# define RADEON_VGA_ATI_LINEAR (1 << 3) +# define RADEON_XCRT_CNT_EN (1 << 6) +# define RADEON_CRTC_HSYNC_DIS (1 << 8) +# define RADEON_CRTC_VSYNC_DIS (1 << 9) +# define RADEON_CRTC_DISPLAY_DIS (1 << 10) +# define RADEON_CRTC_SYNC_TRISTAT (1 << 11) +# define RADEON_CRTC_CRT_ON (1 << 15) +#define RADEON_CRTC_EXT_CNTL_DPMS_BYTE 0x0055 +# define RADEON_CRTC_HSYNC_DIS_BYTE (1 << 0) +# define RADEON_CRTC_VSYNC_DIS_BYTE (1 << 1) +# define RADEON_CRTC_DISPLAY_DIS_BYTE (1 << 2) +#define RADEON_CRTC_GEN_CNTL 0x0050 +# define RADEON_CRTC_DBL_SCAN_EN (1 << 0) +# define RADEON_CRTC_INTERLACE_EN (1 << 1) +# define RADEON_CRTC_CSYNC_EN (1 << 4) +# define RADEON_CRTC_ICON_EN (1 << 15) +# define RADEON_CRTC_CUR_EN (1 << 16) +# define RADEON_CRTC_CUR_MODE_MASK (7 << 20) +# define RADEON_CRTC_CUR_MODE_SHIFT 20 +# define RADEON_CRTC_CUR_MODE_MONO 0 +# define RADEON_CRTC_CUR_MODE_24BPP 2 +# define RADEON_CRTC_EXT_DISP_EN (1 << 24) +# define RADEON_CRTC_EN (1 << 25) +# define RADEON_CRTC_DISP_REQ_EN_B (1 << 26) +#define RADEON_CRTC2_GEN_CNTL 0x03f8 +# define RADEON_CRTC2_DBL_SCAN_EN (1 << 0) +# define RADEON_CRTC2_INTERLACE_EN (1 << 1) +# define RADEON_CRTC2_SYNC_TRISTAT (1 << 4) +# define RADEON_CRTC2_HSYNC_TRISTAT (1 << 5) +# define RADEON_CRTC2_VSYNC_TRISTAT (1 << 6) +# define RADEON_CRTC2_CRT2_ON (1 << 7) +# define RADEON_CRTC2_PIX_WIDTH_SHIFT 8 +# define RADEON_CRTC2_PIX_WIDTH_MASK (0xf << 8) +# define RADEON_CRTC2_ICON_EN (1 << 15) +# define RADEON_CRTC2_CUR_EN (1 << 16) +# define RADEON_CRTC2_CUR_MODE_MASK (7 << 20) +# define RADEON_CRTC2_DISP_DIS (1 << 23) +# define RADEON_CRTC2_EN (1 << 25) +# define RADEON_CRTC2_DISP_REQ_EN_B (1 << 26) +# define RADEON_CRTC2_CSYNC_EN (1 << 27) +# define RADEON_CRTC2_HSYNC_DIS (1 << 28) +# define RADEON_CRTC2_VSYNC_DIS (1 << 29) +#define RADEON_CRTC_MORE_CNTL 0x27c +# define RADEON_CRTC_AUTO_HORZ_CENTER_EN (1<<2) +# define RADEON_CRTC_AUTO_VERT_CENTER_EN (1<<3) +# define RADEON_CRTC_H_CUTOFF_ACTIVE_EN (1<<4) +# define RADEON_CRTC_V_CUTOFF_ACTIVE_EN (1<<5) +#define RADEON_CRTC_GUI_TRIG_VLINE 0x0218 +#define RADEON_CRTC_H_SYNC_STRT_WID 0x0204 +# define RADEON_CRTC_H_SYNC_STRT_PIX (0x07 << 0) +# define RADEON_CRTC_H_SYNC_STRT_CHAR (0x3ff << 3) +# define RADEON_CRTC_H_SYNC_STRT_CHAR_SHIFT 3 +# define RADEON_CRTC_H_SYNC_WID (0x3f << 16) +# define RADEON_CRTC_H_SYNC_WID_SHIFT 16 +# define RADEON_CRTC_H_SYNC_POL (1 << 23) +#define RADEON_CRTC2_H_SYNC_STRT_WID 0x0304 +# define RADEON_CRTC2_H_SYNC_STRT_PIX (0x07 << 0) +# define RADEON_CRTC2_H_SYNC_STRT_CHAR (0x3ff << 3) +# define RADEON_CRTC2_H_SYNC_STRT_CHAR_SHIFT 3 +# define RADEON_CRTC2_H_SYNC_WID (0x3f << 16) +# define RADEON_CRTC2_H_SYNC_WID_SHIFT 16 +# define RADEON_CRTC2_H_SYNC_POL (1 << 23) +#define RADEON_CRTC_H_TOTAL_DISP 0x0200 +# define RADEON_CRTC_H_TOTAL (0x03ff << 0) +# define RADEON_CRTC_H_TOTAL_SHIFT 0 +# define RADEON_CRTC_H_DISP (0x01ff << 16) +# define RADEON_CRTC_H_DISP_SHIFT 16 +#define RADEON_CRTC2_H_TOTAL_DISP 0x0300 +# define RADEON_CRTC2_H_TOTAL (0x03ff << 0) +# define RADEON_CRTC2_H_TOTAL_SHIFT 0 +# define RADEON_CRTC2_H_DISP (0x01ff << 16) +# define RADEON_CRTC2_H_DISP_SHIFT 16 + +#define RADEON_CRTC_OFFSET_RIGHT 0x0220 +#define RADEON_CRTC_OFFSET 0x0224 +# define RADEON_CRTC_OFFSET__GUI_TRIG_OFFSET (1<<30) +# define RADEON_CRTC_OFFSET__OFFSET_LOCK (1<<31) + +#define RADEON_CRTC2_OFFSET 0x0324 +# define RADEON_CRTC2_OFFSET__GUI_TRIG_OFFSET (1<<30) +# define RADEON_CRTC2_OFFSET__OFFSET_LOCK (1<<31) +#define RADEON_CRTC_OFFSET_CNTL 0x0228 +# define RADEON_CRTC_TILE_LINE_SHIFT 0 +# define RADEON_CRTC_TILE_LINE_RIGHT_SHIFT 4 +# define R300_CRTC_X_Y_MODE_EN_RIGHT (1 << 6) +# define R300_CRTC_MICRO_TILE_BUFFER_RIGHT_MASK (3 << 7) +# define R300_CRTC_MICRO_TILE_BUFFER_RIGHT_AUTO (0 << 7) +# define R300_CRTC_MICRO_TILE_BUFFER_RIGHT_SINGLE (1 << 7) +# define R300_CRTC_MICRO_TILE_BUFFER_RIGHT_DOUBLE (2 << 7) +# define R300_CRTC_MICRO_TILE_BUFFER_RIGHT_DIS (3 << 7) +# define R300_CRTC_X_Y_MODE_EN (1 << 9) +# define R300_CRTC_MICRO_TILE_BUFFER_MASK (3 << 10) +# define R300_CRTC_MICRO_TILE_BUFFER_AUTO (0 << 10) +# define R300_CRTC_MICRO_TILE_BUFFER_SINGLE (1 << 10) +# define R300_CRTC_MICRO_TILE_BUFFER_DOUBLE (2 << 10) +# define R300_CRTC_MICRO_TILE_BUFFER_DIS (3 << 10) +# define R300_CRTC_MICRO_TILE_EN_RIGHT (1 << 12) +# define R300_CRTC_MICRO_TILE_EN (1 << 13) +# define R300_CRTC_MACRO_TILE_EN_RIGHT (1 << 14) +# define R300_CRTC_MACRO_TILE_EN (1 << 15) +# define RADEON_CRTC_TILE_EN_RIGHT (1 << 14) +# define RADEON_CRTC_TILE_EN (1 << 15) +# define RADEON_CRTC_OFFSET_FLIP_CNTL (1 << 16) +# define RADEON_CRTC_STEREO_OFFSET_EN (1 << 17) + +#define R300_CRTC_TILE_X0_Y0 0x0350 +#define R300_CRTC2_TILE_X0_Y0 0x0358 + +#define RADEON_CRTC2_OFFSET_CNTL 0x0328 +# define RADEON_CRTC2_OFFSET_FLIP_CNTL (1 << 16) +# define RADEON_CRTC2_TILE_EN (1 << 15) +#define RADEON_CRTC_PITCH 0x022c +# define RADEON_CRTC_PITCH__SHIFT 0 +# define RADEON_CRTC_PITCH__RIGHT_SHIFT 16 + +#define RADEON_CRTC2_PITCH 0x032c +#define RADEON_CRTC_STATUS 0x005c +# define RADEON_CRTC_VBLANK_SAVE (1 << 1) +# define RADEON_CRTC_VBLANK_SAVE_CLEAR (1 << 1) +#define RADEON_CRTC2_STATUS 0x03fc +# define RADEON_CRTC2_VBLANK_SAVE (1 << 1) +# define RADEON_CRTC2_VBLANK_SAVE_CLEAR (1 << 1) +#define RADEON_CRTC_V_SYNC_STRT_WID 0x020c +# define RADEON_CRTC_V_SYNC_STRT (0x7ff << 0) +# define RADEON_CRTC_V_SYNC_STRT_SHIFT 0 +# define RADEON_CRTC_V_SYNC_WID (0x1f << 16) +# define RADEON_CRTC_V_SYNC_WID_SHIFT 16 +# define RADEON_CRTC_V_SYNC_POL (1 << 23) +#define RADEON_CRTC2_V_SYNC_STRT_WID 0x030c +# define RADEON_CRTC2_V_SYNC_STRT (0x7ff << 0) +# define RADEON_CRTC2_V_SYNC_STRT_SHIFT 0 +# define RADEON_CRTC2_V_SYNC_WID (0x1f << 16) +# define RADEON_CRTC2_V_SYNC_WID_SHIFT 16 +# define RADEON_CRTC2_V_SYNC_POL (1 << 23) +#define RADEON_CRTC_V_TOTAL_DISP 0x0208 +# define RADEON_CRTC_V_TOTAL (0x07ff << 0) +# define RADEON_CRTC_V_TOTAL_SHIFT 0 +# define RADEON_CRTC_V_DISP (0x07ff << 16) +# define RADEON_CRTC_V_DISP_SHIFT 16 +#define RADEON_CRTC2_V_TOTAL_DISP 0x0308 +# define RADEON_CRTC2_V_TOTAL (0x07ff << 0) +# define RADEON_CRTC2_V_TOTAL_SHIFT 0 +# define RADEON_CRTC2_V_DISP (0x07ff << 16) +# define RADEON_CRTC2_V_DISP_SHIFT 16 +#define RADEON_CRTC_VLINE_CRNT_VLINE 0x0210 +# define RADEON_CRTC_CRNT_VLINE_MASK (0x7ff << 16) +#define RADEON_CRTC2_CRNT_FRAME 0x0314 +#define RADEON_CRTC2_GUI_TRIG_VLINE 0x0318 +#define RADEON_CRTC2_STATUS 0x03fc +#define RADEON_CRTC2_VLINE_CRNT_VLINE 0x0310 +#define RADEON_CRTC8_DATA 0x03d5 /* VGA, 0x3b5 */ +#define RADEON_CRTC8_IDX 0x03d4 /* VGA, 0x3b4 */ +#define RADEON_CUR_CLR0 0x026c +#define RADEON_CUR_CLR1 0x0270 +#define RADEON_CUR_HORZ_VERT_OFF 0x0268 +#define RADEON_CUR_HORZ_VERT_POSN 0x0264 +#define RADEON_CUR_OFFSET 0x0260 +# define RADEON_CUR_LOCK (1 << 31) +#define RADEON_CUR2_CLR0 0x036c +#define RADEON_CUR2_CLR1 0x0370 +#define RADEON_CUR2_HORZ_VERT_OFF 0x0368 +#define RADEON_CUR2_HORZ_VERT_POSN 0x0364 +#define RADEON_CUR2_OFFSET 0x0360 +# define RADEON_CUR2_LOCK (1 << 31) + +#define RADEON_DAC_CNTL 0x0058 +# define RADEON_DAC_RANGE_CNTL (3 << 0) +# define RADEON_DAC_RANGE_CNTL_PS2 (2 << 0) +# define RADEON_DAC_RANGE_CNTL_MASK 0x03 +# define RADEON_DAC_BLANKING (1 << 2) +# define RADEON_DAC_CMP_EN (1 << 3) +# define RADEON_DAC_CMP_OUTPUT (1 << 7) +# define RADEON_DAC_8BIT_EN (1 << 8) +# define RADEON_DAC_TVO_EN (1 << 10) +# define RADEON_DAC_VGA_ADR_EN (1 << 13) +# define RADEON_DAC_PDWN (1 << 15) +# define RADEON_DAC_MASK_ALL (0xff << 24) +#define RADEON_DAC_CNTL2 0x007c +# define RADEON_DAC2_TV_CLK_SEL (0 << 1) +# define RADEON_DAC2_DAC_CLK_SEL (1 << 0) +# define RADEON_DAC2_DAC2_CLK_SEL (1 << 1) +# define RADEON_DAC2_PALETTE_ACC_CTL (1 << 5) +# define RADEON_DAC2_CMP_EN (1 << 7) +# define RADEON_DAC2_CMP_OUT_R (1 << 8) +# define RADEON_DAC2_CMP_OUT_G (1 << 9) +# define RADEON_DAC2_CMP_OUT_B (1 << 10) +# define RADEON_DAC2_CMP_OUTPUT (1 << 11) +#define RADEON_DAC_EXT_CNTL 0x0280 +# define RADEON_DAC2_FORCE_BLANK_OFF_EN (1 << 0) +# define RADEON_DAC2_FORCE_DATA_EN (1 << 1) +# define RADEON_DAC_FORCE_BLANK_OFF_EN (1 << 4) +# define RADEON_DAC_FORCE_DATA_EN (1 << 5) +# define RADEON_DAC_FORCE_DATA_SEL_MASK (3 << 6) +# define RADEON_DAC_FORCE_DATA_SEL_R (0 << 6) +# define RADEON_DAC_FORCE_DATA_SEL_G (1 << 6) +# define RADEON_DAC_FORCE_DATA_SEL_B (2 << 6) +# define RADEON_DAC_FORCE_DATA_SEL_RGB (3 << 6) +# define RADEON_DAC_FORCE_DATA_MASK 0x0003ff00 +# define RADEON_DAC_FORCE_DATA_SHIFT 8 +#define RADEON_DAC_MACRO_CNTL 0x0d04 +# define RADEON_DAC_PDWN_R (1 << 16) +# define RADEON_DAC_PDWN_G (1 << 17) +# define RADEON_DAC_PDWN_B (1 << 18) +#define RADEON_DISP_PWR_MAN 0x0d08 +# define RADEON_DISP_PWR_MAN_D3_CRTC_EN (1 << 0) +# define RADEON_DISP_PWR_MAN_D3_CRTC2_EN (1 << 4) +# define RADEON_DISP_PWR_MAN_DPMS_ON (0 << 8) +# define RADEON_DISP_PWR_MAN_DPMS_STANDBY (1 << 8) +# define RADEON_DISP_PWR_MAN_DPMS_SUSPEND (2 << 8) +# define RADEON_DISP_PWR_MAN_DPMS_OFF (3 << 8) +# define RADEON_DISP_D3_RST (1 << 16) +# define RADEON_DISP_D3_REG_RST (1 << 17) +# define RADEON_DISP_D3_GRPH_RST (1 << 18) +# define RADEON_DISP_D3_SUBPIC_RST (1 << 19) +# define RADEON_DISP_D3_OV0_RST (1 << 20) +# define RADEON_DISP_D1D2_GRPH_RST (1 << 21) +# define RADEON_DISP_D1D2_SUBPIC_RST (1 << 22) +# define RADEON_DISP_D1D2_OV0_RST (1 << 23) +# define RADEON_DIG_TMDS_ENABLE_RST (1 << 24) +# define RADEON_TV_ENABLE_RST (1 << 25) +# define RADEON_AUTO_PWRUP_EN (1 << 26) +#define RADEON_TV_DAC_CNTL 0x088c +# define RADEON_TV_DAC_NBLANK (1 << 0) +# define RADEON_TV_DAC_NHOLD (1 << 1) +# define RADEON_TV_DAC_PEDESTAL (1 << 2) +# define RADEON_TV_MONITOR_DETECT_EN (1 << 4) +# define RADEON_TV_DAC_CMPOUT (1 << 5) +# define RADEON_TV_DAC_STD_MASK (3 << 8) +# define RADEON_TV_DAC_STD_PAL (0 << 8) +# define RADEON_TV_DAC_STD_NTSC (1 << 8) +# define RADEON_TV_DAC_STD_PS2 (2 << 8) +# define RADEON_TV_DAC_STD_RS343 (3 << 8) +# define RADEON_TV_DAC_BGSLEEP (1 << 6) +# define RADEON_TV_DAC_BGADJ_MASK (0xf << 16) +# define RADEON_TV_DAC_BGADJ_SHIFT 16 +# define RADEON_TV_DAC_DACADJ_MASK (0xf << 20) +# define RADEON_TV_DAC_DACADJ_SHIFT 20 +# define RADEON_TV_DAC_RDACPD (1 << 24) +# define RADEON_TV_DAC_GDACPD (1 << 25) +# define RADEON_TV_DAC_BDACPD (1 << 26) +# define RADEON_TV_DAC_RDACDET (1 << 29) +# define RADEON_TV_DAC_GDACDET (1 << 30) +# define RADEON_TV_DAC_BDACDET (1 << 31) +# define R420_TV_DAC_DACADJ_MASK (0x1f << 20) +# define R420_TV_DAC_RDACPD (1 << 25) +# define R420_TV_DAC_GDACPD (1 << 26) +# define R420_TV_DAC_BDACPD (1 << 27) +# define R420_TV_DAC_TVENABLE (1 << 28) +#define RADEON_DISP_HW_DEBUG 0x0d14 +# define RADEON_CRT2_DISP1_SEL (1 << 5) +#define RADEON_DISP_OUTPUT_CNTL 0x0d64 +# define RADEON_DISP_DAC_SOURCE_MASK 0x03 +# define RADEON_DISP_DAC2_SOURCE_MASK 0x0c +# define RADEON_DISP_DAC_SOURCE_CRTC2 0x01 +# define RADEON_DISP_DAC_SOURCE_RMX 0x02 +# define RADEON_DISP_DAC_SOURCE_LTU 0x03 +# define RADEON_DISP_DAC2_SOURCE_CRTC2 0x04 +# define RADEON_DISP_TVDAC_SOURCE_MASK (0x03 << 2) +# define RADEON_DISP_TVDAC_SOURCE_CRTC 0x0 +# define RADEON_DISP_TVDAC_SOURCE_CRTC2 (0x01 << 2) +# define RADEON_DISP_TVDAC_SOURCE_RMX (0x02 << 2) +# define RADEON_DISP_TVDAC_SOURCE_LTU (0x03 << 2) +# define RADEON_DISP_TRANS_MATRIX_MASK (0x03 << 4) +# define RADEON_DISP_TRANS_MATRIX_ALPHA_MSB (0x00 << 4) +# define RADEON_DISP_TRANS_MATRIX_GRAPHICS (0x01 << 4) +# define RADEON_DISP_TRANS_MATRIX_VIDEO (0x02 << 4) +# define RADEON_DISP_TV_SOURCE_CRTC (1 << 16) /* crtc1 or crtc2 */ +# define RADEON_DISP_TV_SOURCE_LTU (0 << 16) /* linear transform unit */ +#define RADEON_DISP_TV_OUT_CNTL 0x0d6c +# define RADEON_DISP_TV_PATH_SRC_CRTC2 (1 << 16) +# define RADEON_DISP_TV_PATH_SRC_CRTC1 (0 << 16) +#define RADEON_DAC_CRC_SIG 0x02cc +#define RADEON_DAC_DATA 0x03c9 /* VGA */ +#define RADEON_DAC_MASK 0x03c6 /* VGA */ +#define RADEON_DAC_R_INDEX 0x03c7 /* VGA */ +#define RADEON_DAC_W_INDEX 0x03c8 /* VGA */ +#define RADEON_DDA_CONFIG 0x02e0 +#define RADEON_DDA_ON_OFF 0x02e4 +#define RADEON_DEFAULT_OFFSET 0x16e0 +#define RADEON_DEFAULT_PITCH 0x16e4 +#define RADEON_DEFAULT_SC_BOTTOM_RIGHT 0x16e8 +# define RADEON_DEFAULT_SC_RIGHT_MAX (0x1fff << 0) +# define RADEON_DEFAULT_SC_BOTTOM_MAX (0x1fff << 16) +#define RADEON_DESTINATION_3D_CLR_CMP_VAL 0x1820 +#define RADEON_DESTINATION_3D_CLR_CMP_MSK 0x1824 +#define RADEON_DEVICE_ID 0x0f02 /* PCI */ +#define RADEON_DISP_MISC_CNTL 0x0d00 +# define RADEON_SOFT_RESET_GRPH_PP (1 << 0) +#define RADEON_DISP_MERGE_CNTL 0x0d60 +# define RADEON_DISP_ALPHA_MODE_MASK 0x03 +# define RADEON_DISP_ALPHA_MODE_KEY 0 +# define RADEON_DISP_ALPHA_MODE_PER_PIXEL 1 +# define RADEON_DISP_ALPHA_MODE_GLOBAL 2 +# define RADEON_DISP_RGB_OFFSET_EN (1 << 8) +# define RADEON_DISP_GRPH_ALPHA_MASK (0xff << 16) +# define RADEON_DISP_OV0_ALPHA_MASK (0xff << 24) +# define RADEON_DISP_LIN_TRANS_BYPASS (0x01 << 9) +#define RADEON_DISP2_MERGE_CNTL 0x0d68 +# define RADEON_DISP2_RGB_OFFSET_EN (1 << 8) +#define RADEON_DISP_LIN_TRANS_GRPH_A 0x0d80 +#define RADEON_DISP_LIN_TRANS_GRPH_B 0x0d84 +#define RADEON_DISP_LIN_TRANS_GRPH_C 0x0d88 +#define RADEON_DISP_LIN_TRANS_GRPH_D 0x0d8c +#define RADEON_DISP_LIN_TRANS_GRPH_E 0x0d90 +#define RADEON_DISP_LIN_TRANS_GRPH_F 0x0d98 +#define RADEON_DP_BRUSH_BKGD_CLR 0x1478 +#define RADEON_DP_BRUSH_FRGD_CLR 0x147c +#define RADEON_DP_CNTL 0x16c0 +# define RADEON_DST_X_LEFT_TO_RIGHT (1 << 0) +# define RADEON_DST_Y_TOP_TO_BOTTOM (1 << 1) +# define RADEON_DP_DST_TILE_LINEAR (0 << 3) +# define RADEON_DP_DST_TILE_MACRO (1 << 3) +# define RADEON_DP_DST_TILE_MICRO (2 << 3) +# define RADEON_DP_DST_TILE_BOTH (3 << 3) +#define RADEON_DP_CNTL_XDIR_YDIR_YMAJOR 0x16d0 +# define RADEON_DST_Y_MAJOR (1 << 2) +# define RADEON_DST_Y_DIR_TOP_TO_BOTTOM (1 << 15) +# define RADEON_DST_X_DIR_LEFT_TO_RIGHT (1 << 31) +#define RADEON_DP_DATATYPE 0x16c4 +# define RADEON_HOST_BIG_ENDIAN_EN (1 << 29) +#define RADEON_DP_GUI_MASTER_CNTL 0x146c +# define RADEON_GMC_SRC_PITCH_OFFSET_CNTL (1 << 0) +# define RADEON_GMC_DST_PITCH_OFFSET_CNTL (1 << 1) +# define RADEON_GMC_SRC_CLIPPING (1 << 2) +# define RADEON_GMC_DST_CLIPPING (1 << 3) +# define RADEON_GMC_BRUSH_DATATYPE_MASK (0x0f << 4) +# define RADEON_GMC_BRUSH_8X8_MONO_FG_BG (0 << 4) +# define RADEON_GMC_BRUSH_8X8_MONO_FG_LA (1 << 4) +# define RADEON_GMC_BRUSH_1X8_MONO_FG_BG (4 << 4) +# define RADEON_GMC_BRUSH_1X8_MONO_FG_LA (5 << 4) +# define RADEON_GMC_BRUSH_32x1_MONO_FG_BG (6 << 4) +# define RADEON_GMC_BRUSH_32x1_MONO_FG_LA (7 << 4) +# define RADEON_GMC_BRUSH_32x32_MONO_FG_BG (8 << 4) +# define RADEON_GMC_BRUSH_32x32_MONO_FG_LA (9 << 4) +# define RADEON_GMC_BRUSH_8x8_COLOR (10 << 4) +# define RADEON_GMC_BRUSH_1X8_COLOR (12 << 4) +# define RADEON_GMC_BRUSH_SOLID_COLOR (13 << 4) +# define RADEON_GMC_BRUSH_NONE (15 << 4) +# define RADEON_GMC_DST_8BPP_CI (2 << 8) +# define RADEON_GMC_DST_15BPP (3 << 8) +# define RADEON_GMC_DST_16BPP (4 << 8) +# define RADEON_GMC_DST_24BPP (5 << 8) +# define RADEON_GMC_DST_32BPP (6 << 8) +# define RADEON_GMC_DST_8BPP_RGB (7 << 8) +# define RADEON_GMC_DST_Y8 (8 << 8) +# define RADEON_GMC_DST_RGB8 (9 << 8) +# define RADEON_GMC_DST_VYUY (11 << 8) +# define RADEON_GMC_DST_YVYU (12 << 8) +# define RADEON_GMC_DST_AYUV444 (14 << 8) +# define RADEON_GMC_DST_ARGB4444 (15 << 8) +# define RADEON_GMC_DST_DATATYPE_MASK (0x0f << 8) +# define RADEON_GMC_DST_DATATYPE_SHIFT 8 +# define RADEON_GMC_SRC_DATATYPE_MASK (3 << 12) +# define RADEON_GMC_SRC_DATATYPE_MONO_FG_BG (0 << 12) +# define RADEON_GMC_SRC_DATATYPE_MONO_FG_LA (1 << 12) +# define RADEON_GMC_SRC_DATATYPE_COLOR (3 << 12) +# define RADEON_GMC_BYTE_PIX_ORDER (1 << 14) +# define RADEON_GMC_BYTE_MSB_TO_LSB (0 << 14) +# define RADEON_GMC_BYTE_LSB_TO_MSB (1 << 14) +# define RADEON_GMC_CONVERSION_TEMP (1 << 15) +# define RADEON_GMC_CONVERSION_TEMP_6500 (0 << 15) +# define RADEON_GMC_CONVERSION_TEMP_9300 (1 << 15) +# define RADEON_GMC_ROP3_MASK (0xff << 16) +# define RADEON_DP_SRC_SOURCE_MASK (7 << 24) +# define RADEON_DP_SRC_SOURCE_MEMORY (2 << 24) +# define RADEON_DP_SRC_SOURCE_HOST_DATA (3 << 24) +# define RADEON_GMC_3D_FCN_EN (1 << 27) +# define RADEON_GMC_CLR_CMP_CNTL_DIS (1 << 28) +# define RADEON_GMC_AUX_CLIP_DIS (1 << 29) +# define RADEON_GMC_WR_MSK_DIS (1 << 30) +# define RADEON_GMC_LD_BRUSH_Y_X (1 << 31) +# define RADEON_ROP3_ZERO 0x00000000 +# define RADEON_ROP3_DSa 0x00880000 +# define RADEON_ROP3_SDna 0x00440000 +# define RADEON_ROP3_S 0x00cc0000 +# define RADEON_ROP3_DSna 0x00220000 +# define RADEON_ROP3_D 0x00aa0000 +# define RADEON_ROP3_DSx 0x00660000 +# define RADEON_ROP3_DSo 0x00ee0000 +# define RADEON_ROP3_DSon 0x00110000 +# define RADEON_ROP3_DSxn 0x00990000 +# define RADEON_ROP3_Dn 0x00550000 +# define RADEON_ROP3_SDno 0x00dd0000 +# define RADEON_ROP3_Sn 0x00330000 +# define RADEON_ROP3_DSno 0x00bb0000 +# define RADEON_ROP3_DSan 0x00770000 +# define RADEON_ROP3_ONE 0x00ff0000 +# define RADEON_ROP3_DPa 0x00a00000 +# define RADEON_ROP3_PDna 0x00500000 +# define RADEON_ROP3_P 0x00f00000 +# define RADEON_ROP3_DPna 0x000a0000 +# define RADEON_ROP3_D 0x00aa0000 +# define RADEON_ROP3_DPx 0x005a0000 +# define RADEON_ROP3_DPo 0x00fa0000 +# define RADEON_ROP3_DPon 0x00050000 +# define RADEON_ROP3_PDxn 0x00a50000 +# define RADEON_ROP3_PDno 0x00f50000 +# define RADEON_ROP3_Pn 0x000f0000 +# define RADEON_ROP3_DPno 0x00af0000 +# define RADEON_ROP3_DPan 0x005f0000 +#define RADEON_DP_GUI_MASTER_CNTL_C 0x1c84 +#define RADEON_DP_MIX 0x16c8 +#define RADEON_DP_SRC_BKGD_CLR 0x15dc +#define RADEON_DP_SRC_FRGD_CLR 0x15d8 +#define RADEON_DP_WRITE_MASK 0x16cc +#define RADEON_DST_BRES_DEC 0x1630 +#define RADEON_DST_BRES_ERR 0x1628 +#define RADEON_DST_BRES_INC 0x162c +#define RADEON_DST_BRES_LNTH 0x1634 +#define RADEON_DST_BRES_LNTH_SUB 0x1638 +#define RADEON_DST_HEIGHT 0x1410 +#define RADEON_DST_HEIGHT_WIDTH 0x143c +#define RADEON_DST_HEIGHT_WIDTH_8 0x158c +#define RADEON_DST_HEIGHT_WIDTH_BW 0x15b4 +#define RADEON_DST_HEIGHT_Y 0x15a0 +#define RADEON_DST_LINE_START 0x1600 +#define RADEON_DST_LINE_END 0x1604 +#define RADEON_DST_LINE_PATCOUNT 0x1608 +# define RADEON_BRES_CNTL_SHIFT 8 +#define RADEON_DST_OFFSET 0x1404 +#define RADEON_DST_PITCH 0x1408 +#define RADEON_DST_PITCH_OFFSET 0x142c +#define RADEON_DST_PITCH_OFFSET_C 0x1c80 +# define RADEON_PITCH_SHIFT 21 +# define RADEON_DST_TILE_LINEAR (0 << 30) +# define RADEON_DST_TILE_MACRO (1 << 30) +# define RADEON_DST_TILE_MICRO (2 << 30) +# define RADEON_DST_TILE_BOTH (3 << 30) +#define RADEON_DST_WIDTH 0x140c +#define RADEON_DST_WIDTH_HEIGHT 0x1598 +#define RADEON_DST_WIDTH_X 0x1588 +#define RADEON_DST_WIDTH_X_INCY 0x159c +#define RADEON_DST_X 0x141c +#define RADEON_DST_X_SUB 0x15a4 +#define RADEON_DST_X_Y 0x1594 +#define RADEON_DST_Y 0x1420 +#define RADEON_DST_Y_SUB 0x15a8 +#define RADEON_DST_Y_X 0x1438 + +#define RADEON_FCP_CNTL 0x0910 +# define RADEON_FCP0_SRC_PCICLK 0 +# define RADEON_FCP0_SRC_PCLK 1 +# define RADEON_FCP0_SRC_PCLKb 2 +# define RADEON_FCP0_SRC_HREF 3 +# define RADEON_FCP0_SRC_GND 4 +# define RADEON_FCP0_SRC_HREFb 5 +#define RADEON_FLUSH_1 0x1704 +#define RADEON_FLUSH_2 0x1708 +#define RADEON_FLUSH_3 0x170c +#define RADEON_FLUSH_4 0x1710 +#define RADEON_FLUSH_5 0x1714 +#define RADEON_FLUSH_6 0x1718 +#define RADEON_FLUSH_7 0x171c +#define RADEON_FOG_3D_TABLE_START 0x1810 +#define RADEON_FOG_3D_TABLE_END 0x1814 +#define RADEON_FOG_3D_TABLE_DENSITY 0x181c +#define RADEON_FOG_TABLE_INDEX 0x1a14 +#define RADEON_FOG_TABLE_DATA 0x1a18 +#define RADEON_FP_CRTC_H_TOTAL_DISP 0x0250 +#define RADEON_FP_CRTC_V_TOTAL_DISP 0x0254 +# define RADEON_FP_CRTC_H_TOTAL_MASK 0x000003ff +# define RADEON_FP_CRTC_H_DISP_MASK 0x01ff0000 +# define RADEON_FP_CRTC_V_TOTAL_MASK 0x00000fff +# define RADEON_FP_CRTC_V_DISP_MASK 0x0fff0000 +# define RADEON_FP_H_SYNC_STRT_CHAR_MASK 0x00001ff8 +# define RADEON_FP_H_SYNC_WID_MASK 0x003f0000 +# define RADEON_FP_V_SYNC_STRT_MASK 0x00000fff +# define RADEON_FP_V_SYNC_WID_MASK 0x001f0000 +# define RADEON_FP_CRTC_H_TOTAL_SHIFT 0x00000000 +# define RADEON_FP_CRTC_H_DISP_SHIFT 0x00000010 +# define RADEON_FP_CRTC_V_TOTAL_SHIFT 0x00000000 +# define RADEON_FP_CRTC_V_DISP_SHIFT 0x00000010 +# define RADEON_FP_H_SYNC_STRT_CHAR_SHIFT 0x00000003 +# define RADEON_FP_H_SYNC_WID_SHIFT 0x00000010 +# define RADEON_FP_V_SYNC_STRT_SHIFT 0x00000000 +# define RADEON_FP_V_SYNC_WID_SHIFT 0x00000010 +#define RADEON_FP_GEN_CNTL 0x0284 +# define RADEON_FP_FPON (1 << 0) +# define RADEON_FP_BLANK_EN (1 << 1) +# define RADEON_FP_TMDS_EN (1 << 2) +# define RADEON_FP_PANEL_FORMAT (1 << 3) +# define RADEON_FP_EN_TMDS (1 << 7) +# define RADEON_FP_DETECT_SENSE (1 << 8) +# define R200_FP_SOURCE_SEL_MASK (3 << 10) +# define R200_FP_SOURCE_SEL_CRTC1 (0 << 10) +# define R200_FP_SOURCE_SEL_CRTC2 (1 << 10) +# define R200_FP_SOURCE_SEL_RMX (2 << 10) +# define R200_FP_SOURCE_SEL_TRANS (3 << 10) +# define RADEON_FP_SEL_CRTC1 (0 << 13) +# define RADEON_FP_SEL_CRTC2 (1 << 13) +# define RADEON_FP_CRTC_DONT_SHADOW_HPAR (1 << 15) +# define RADEON_FP_CRTC_DONT_SHADOW_VPAR (1 << 16) +# define RADEON_FP_CRTC_DONT_SHADOW_HEND (1 << 17) +# define RADEON_FP_CRTC_USE_SHADOW_VEND (1 << 18) +# define RADEON_FP_RMX_HVSYNC_CONTROL_EN (1 << 20) +# define RADEON_FP_DFP_SYNC_SEL (1 << 21) +# define RADEON_FP_CRTC_LOCK_8DOT (1 << 22) +# define RADEON_FP_CRT_SYNC_SEL (1 << 23) +# define RADEON_FP_USE_SHADOW_EN (1 << 24) +# define RADEON_FP_CRT_SYNC_ALT (1 << 26) +#define RADEON_FP2_GEN_CNTL 0x0288 +# define RADEON_FP2_BLANK_EN (1 << 1) +# define RADEON_FP2_ON (1 << 2) +# define RADEON_FP2_PANEL_FORMAT (1 << 3) +# define RADEON_FP2_DETECT_SENSE (1 << 8) +# define R200_FP2_SOURCE_SEL_MASK (3 << 10) +# define R200_FP2_SOURCE_SEL_CRTC1 (0 << 10) +# define R200_FP2_SOURCE_SEL_CRTC2 (1 << 10) +# define R200_FP2_SOURCE_SEL_RMX (2 << 10) +# define R200_FP2_SOURCE_SEL_TRANS_UNIT (3 << 10) +# define RADEON_FP2_SRC_SEL_MASK (3 << 13) +# define RADEON_FP2_SRC_SEL_CRTC2 (1 << 13) +# define RADEON_FP2_FP_POL (1 << 16) +# define RADEON_FP2_LP_POL (1 << 17) +# define RADEON_FP2_SCK_POL (1 << 18) +# define RADEON_FP2_LCD_CNTL_MASK (7 << 19) +# define RADEON_FP2_PAD_FLOP_EN (1 << 22) +# define RADEON_FP2_CRC_EN (1 << 23) +# define RADEON_FP2_CRC_READ_EN (1 << 24) +# define RADEON_FP2_DVO_EN (1 << 25) +# define RADEON_FP2_DVO_RATE_SEL_SDR (1 << 26) +# define R200_FP2_DVO_RATE_SEL_SDR (1 << 27) +# define R300_FP2_DVO_CLOCK_MODE_SINGLE (1 << 28) +# define R300_FP2_DVO_DUAL_CHANNEL_EN (1 << 29) +#define RADEON_FP_H_SYNC_STRT_WID 0x02c4 +#define RADEON_FP_H2_SYNC_STRT_WID 0x03c4 +#define RADEON_FP_HORZ_STRETCH 0x028c +#define RADEON_FP_HORZ2_STRETCH 0x038c +# define RADEON_HORZ_STRETCH_RATIO_MASK 0xffff +# define RADEON_HORZ_STRETCH_RATIO_MAX 4096 +# define RADEON_HORZ_PANEL_SIZE (0x1ff << 16) +# define RADEON_HORZ_PANEL_SHIFT 16 +# define RADEON_HORZ_STRETCH_PIXREP (0 << 25) +# define RADEON_HORZ_STRETCH_BLEND (1 << 26) +# define RADEON_HORZ_STRETCH_ENABLE (1 << 25) +# define RADEON_HORZ_AUTO_RATIO (1 << 27) +# define RADEON_HORZ_FP_LOOP_STRETCH (0x7 << 28) +# define RADEON_HORZ_AUTO_RATIO_INC (1 << 31) +#define RADEON_FP_HORZ_VERT_ACTIVE 0x0278 +#define RADEON_FP_V_SYNC_STRT_WID 0x02c8 +#define RADEON_FP_VERT_STRETCH 0x0290 +#define RADEON_FP_V2_SYNC_STRT_WID 0x03c8 +#define RADEON_FP_VERT2_STRETCH 0x0390 +# define RADEON_VERT_PANEL_SIZE (0xfff << 12) +# define RADEON_VERT_PANEL_SHIFT 12 +# define RADEON_VERT_STRETCH_RATIO_MASK 0xfff +# define RADEON_VERT_STRETCH_RATIO_SHIFT 0 +# define RADEON_VERT_STRETCH_RATIO_MAX 4096 +# define RADEON_VERT_STRETCH_ENABLE (1 << 25) +# define RADEON_VERT_STRETCH_LINEREP (0 << 26) +# define RADEON_VERT_STRETCH_BLEND (1 << 26) +# define RADEON_VERT_AUTO_RATIO_EN (1 << 27) +# define RADEON_VERT_AUTO_RATIO_INC (1 << 31) +# define RADEON_VERT_STRETCH_RESERVED 0x71000000 +#define RS400_FP_2ND_GEN_CNTL 0x0384 +# define RS400_FP_2ND_ON (1 << 0) +# define RS400_FP_2ND_BLANK_EN (1 << 1) +# define RS400_TMDS_2ND_EN (1 << 2) +# define RS400_PANEL_FORMAT_2ND (1 << 3) +# define RS400_FP_2ND_EN_TMDS (1 << 7) +# define RS400_FP_2ND_DETECT_SENSE (1 << 8) +# define RS400_FP_2ND_SOURCE_SEL_MASK (3 << 10) +# define RS400_FP_2ND_SOURCE_SEL_CRTC1 (0 << 10) +# define RS400_FP_2ND_SOURCE_SEL_CRTC2 (1 << 10) +# define RS400_FP_2ND_SOURCE_SEL_RMX (2 << 10) +# define RS400_FP_2ND_DETECT_EN (1 << 12) +# define RS400_HPD_2ND_SEL (1 << 13) +#define RS400_FP2_2_GEN_CNTL 0x0388 +# define RS400_FP2_2_BLANK_EN (1 << 1) +# define RS400_FP2_2_ON (1 << 2) +# define RS400_FP2_2_PANEL_FORMAT (1 << 3) +# define RS400_FP2_2_DETECT_SENSE (1 << 8) +# define RS400_FP2_2_SOURCE_SEL_MASK (3 << 10) +# define RS400_FP2_2_SOURCE_SEL_CRTC1 (0 << 10) +# define RS400_FP2_2_SOURCE_SEL_CRTC2 (1 << 10) +# define RS400_FP2_2_SOURCE_SEL_RMX (2 << 10) +# define RS400_FP2_2_DVO2_EN (1 << 25) +#define RS400_TMDS2_CNTL 0x0394 +#define RS400_TMDS2_TRANSMITTER_CNTL 0x03a4 +# define RS400_TMDS2_PLLEN (1 << 0) +# define RS400_TMDS2_PLLRST (1 << 1) + +#define RADEON_GEN_INT_CNTL 0x0040 +# define RADEON_SW_INT_ENABLE (1 << 25) +#define RADEON_GEN_INT_STATUS 0x0044 +# define RADEON_VSYNC_INT_AK (1 << 2) +# define RADEON_VSYNC_INT (1 << 2) +# define RADEON_VSYNC2_INT_AK (1 << 6) +# define RADEON_VSYNC2_INT (1 << 6) +# define RADEON_SW_INT_FIRE (1 << 26) +# define RADEON_SW_INT_TEST (1 << 25) +# define RADEON_SW_INT_TEST_ACK (1 << 25) +#define RADEON_GENENB 0x03c3 /* VGA */ +#define RADEON_GENFC_RD 0x03ca /* VGA */ +#define RADEON_GENFC_WT 0x03da /* VGA, 0x03ba */ +#define RADEON_GENMO_RD 0x03cc /* VGA */ +#define RADEON_GENMO_WT 0x03c2 /* VGA */ +#define RADEON_GENS0 0x03c2 /* VGA */ +#define RADEON_GENS1 0x03da /* VGA, 0x03ba */ +#define RADEON_GPIO_MONID 0x0068 /* DDC interface via I2C */ /* DDC3 */ +#define RADEON_GPIO_MONIDB 0x006c +#define RADEON_GPIO_CRT2_DDC 0x006c +#define RADEON_GPIO_DVI_DDC 0x0064 /* DDC2 */ +#define RADEON_GPIO_VGA_DDC 0x0060 /* DDC1 */ +# define RADEON_GPIO_A_0 (1 << 0) +# define RADEON_GPIO_A_1 (1 << 1) +# define RADEON_GPIO_Y_0 (1 << 8) +# define RADEON_GPIO_Y_1 (1 << 9) +# define RADEON_GPIO_Y_SHIFT_0 8 +# define RADEON_GPIO_Y_SHIFT_1 9 +# define RADEON_GPIO_EN_0 (1 << 16) +# define RADEON_GPIO_EN_1 (1 << 17) +# define RADEON_GPIO_MASK_0 (1 << 24) /*??*/ +# define RADEON_GPIO_MASK_1 (1 << 25) /*??*/ +#define RADEON_GRPH8_DATA 0x03cf /* VGA */ +#define RADEON_GRPH8_IDX 0x03ce /* VGA */ +#define RADEON_GUI_SCRATCH_REG0 0x15e0 +#define RADEON_GUI_SCRATCH_REG1 0x15e4 +#define RADEON_GUI_SCRATCH_REG2 0x15e8 +#define RADEON_GUI_SCRATCH_REG3 0x15ec +#define RADEON_GUI_SCRATCH_REG4 0x15f0 +#define RADEON_GUI_SCRATCH_REG5 0x15f4 + +#define RADEON_HEADER 0x0f0e /* PCI */ +#define RADEON_HOST_DATA0 0x17c0 +#define RADEON_HOST_DATA1 0x17c4 +#define RADEON_HOST_DATA2 0x17c8 +#define RADEON_HOST_DATA3 0x17cc +#define RADEON_HOST_DATA4 0x17d0 +#define RADEON_HOST_DATA5 0x17d4 +#define RADEON_HOST_DATA6 0x17d8 +#define RADEON_HOST_DATA7 0x17dc +#define RADEON_HOST_DATA_LAST 0x17e0 +#define RADEON_HOST_PATH_CNTL 0x0130 +# define RADEON_HP_LIN_RD_CACHE_DIS (1 << 24) +# define RADEON_HDP_READ_BUFFER_INVALIDATE (1 << 27) +# define RADEON_HDP_SOFT_RESET (1 << 26) +# define RADEON_HDP_APER_CNTL (1 << 23) +#define RADEON_HTOTAL_CNTL 0x0009 /* PLL */ +# define RADEON_HTOT_CNTL_VGA_EN (1 << 28) +#define RADEON_HTOTAL2_CNTL 0x002e /* PLL */ + + /* Multimedia I2C bus */ +#define RADEON_I2C_CNTL_0 0x0090 +#define RADEON_I2C_DONE (1<<0) +#define RADEON_I2C_NACK (1<<1) +#define RADEON_I2C_HALT (1<<2) +#define RADEON_I2C_SOFT_RST (1<<5) +#define RADEON_I2C_DRIVE_EN (1<<6) +#define RADEON_I2C_DRIVE_SEL (1<<7) +#define RADEON_I2C_START (1<<8) +#define RADEON_I2C_STOP (1<<9) +#define RADEON_I2C_RECEIVE (1<<10) +#define RADEON_I2C_ABORT (1<<11) +#define RADEON_I2C_GO (1<<12) +#define RADEON_I2C_CNTL_1 0x0094 +#define RADEON_I2C_SEL (1<<16) +#define RADEON_I2C_EN (1<<17) +#define RADEON_I2C_DATA 0x0098 + +#define RADEON_DVI_I2C_CNTL_0 0x02e0 +# define R200_DVI_I2C_PIN_SEL(x) ((x) << 3) +# define R200_SEL_DDC1 0 /* 0x60 - VGA_DDC */ +# define R200_SEL_DDC2 1 /* 0x64 - DVI_DDC */ +# define R200_SEL_DDC3 2 /* 0x68 - MONID_DDC */ +#define RADEON_DVI_I2C_CNTL_1 0x02e4 /* ? */ +#define RADEON_DVI_I2C_DATA 0x02e8 + +#define RADEON_INTERRUPT_LINE 0x0f3c /* PCI */ +#define RADEON_INTERRUPT_PIN 0x0f3d /* PCI */ +#define RADEON_IO_BASE 0x0f14 /* PCI */ + +#define RADEON_LATENCY 0x0f0d /* PCI */ +#define RADEON_LEAD_BRES_DEC 0x1608 +#define RADEON_LEAD_BRES_LNTH 0x161c +#define RADEON_LEAD_BRES_LNTH_SUB 0x1624 +#define RADEON_LVDS_GEN_CNTL 0x02d0 +# define RADEON_LVDS_ON (1 << 0) +# define RADEON_LVDS_DISPLAY_DIS (1 << 1) +# define RADEON_LVDS_PANEL_TYPE (1 << 2) +# define RADEON_LVDS_PANEL_FORMAT (1 << 3) +# define RADEON_LVDS_NO_FM (0 << 4) +# define RADEON_LVDS_2_GREY (1 << 4) +# define RADEON_LVDS_4_GREY (2 << 4) +# define RADEON_LVDS_RST_FM (1 << 6) +# define RADEON_LVDS_EN (1 << 7) +# define RADEON_LVDS_BL_MOD_LEVEL_SHIFT 8 +# define RADEON_LVDS_BL_MOD_LEVEL_MASK (0xff << 8) +# define RADEON_LVDS_BL_MOD_EN (1 << 16) +# define RADEON_LVDS_BL_CLK_SEL (1 << 17) +# define RADEON_LVDS_DIGON (1 << 18) +# define RADEON_LVDS_BLON (1 << 19) +# define RADEON_LVDS_FP_POL_LOW (1 << 20) +# define RADEON_LVDS_LP_POL_LOW (1 << 21) +# define RADEON_LVDS_DTM_POL_LOW (1 << 22) +# define RADEON_LVDS_SEL_CRTC2 (1 << 23) +# define RADEON_LVDS_FPDI_EN (1 << 27) +# define RADEON_LVDS_HSYNC_DELAY_SHIFT 28 +#define RADEON_LVDS_PLL_CNTL 0x02d4 +# define RADEON_HSYNC_DELAY_SHIFT 28 +# define RADEON_HSYNC_DELAY_MASK (0xf << 28) +# define RADEON_LVDS_PLL_EN (1 << 16) +# define RADEON_LVDS_PLL_RESET (1 << 17) +# define R300_LVDS_SRC_SEL_MASK (3 << 18) +# define R300_LVDS_SRC_SEL_CRTC1 (0 << 18) +# define R300_LVDS_SRC_SEL_CRTC2 (1 << 18) +# define R300_LVDS_SRC_SEL_RMX (2 << 18) +#define RADEON_LVDS_SS_GEN_CNTL 0x02ec +# define RADEON_LVDS_PWRSEQ_DELAY1_SHIFT 16 +# define RADEON_LVDS_PWRSEQ_DELAY2_SHIFT 20 + +#define RADEON_MAX_LATENCY 0x0f3f /* PCI */ +#define RADEON_DISPLAY_BASE_ADDR 0x23c +#define RADEON_DISPLAY2_BASE_ADDR 0x33c +#define RADEON_OV0_BASE_ADDR 0x43c +#define RADEON_NB_TOM 0x15c +#define R300_MC_INIT_MISC_LAT_TIMER 0x180 +# define R300_MC_DISP0R_INIT_LAT_SHIFT 8 +# define R300_MC_DISP0R_INIT_LAT_MASK 0xf +# define R300_MC_DISP1R_INIT_LAT_SHIFT 12 +# define R300_MC_DISP1R_INIT_LAT_MASK 0xf +#define RADEON_MCLK_CNTL 0x0012 /* PLL */ +# define RADEON_MCLKA_SRC_SEL_MASK 0x7 +# define RADEON_FORCEON_MCLKA (1 << 16) +# define RADEON_FORCEON_MCLKB (1 << 17) +# define RADEON_FORCEON_YCLKA (1 << 18) +# define RADEON_FORCEON_YCLKB (1 << 19) +# define RADEON_FORCEON_MC (1 << 20) +# define RADEON_FORCEON_AIC (1 << 21) +# define R300_DISABLE_MC_MCLKA (1 << 21) +# define R300_DISABLE_MC_MCLKB (1 << 21) +#define RADEON_MCLK_MISC 0x001f /* PLL */ +# define RADEON_MC_MCLK_MAX_DYN_STOP_LAT (1 << 12) +# define RADEON_IO_MCLK_MAX_DYN_STOP_LAT (1 << 13) +# define RADEON_MC_MCLK_DYN_ENABLE (1 << 14) +# define RADEON_IO_MCLK_DYN_ENABLE (1 << 15) +#define RADEON_LCD_GPIO_MASK 0x01a0 +#define RADEON_GPIOPAD_EN 0x01a0 +#define RADEON_LCD_GPIO_Y_REG 0x01a4 +#define RADEON_MDGPIO_A_REG 0x01ac +#define RADEON_MDGPIO_EN_REG 0x01b0 +#define RADEON_MDGPIO_MASK 0x0198 +#define RADEON_GPIOPAD_MASK 0x0198 +#define RADEON_GPIOPAD_A 0x019c +#define RADEON_MDGPIO_Y_REG 0x01b4 +#define RADEON_MEM_ADDR_CONFIG 0x0148 +#define RADEON_MEM_BASE 0x0f10 /* PCI */ +#define RADEON_MEM_CNTL 0x0140 +# define RADEON_MEM_NUM_CHANNELS_MASK 0x01 +# define RADEON_MEM_USE_B_CH_ONLY (1 << 1) +# define RV100_HALF_MODE (1 << 3) +# define R300_MEM_NUM_CHANNELS_MASK 0x03 +# define R300_MEM_USE_CD_CH_ONLY (1 << 2) +#define RADEON_MEM_TIMING_CNTL 0x0144 /* EXT_MEM_CNTL */ +#define RADEON_MEM_INIT_LAT_TIMER 0x0154 +#define RADEON_MEM_INTF_CNTL 0x014c +#define RADEON_MEM_SDRAM_MODE_REG 0x0158 +# define RADEON_SDRAM_MODE_MASK 0xffff0000 +# define RADEON_B3MEM_RESET_MASK 0x6fffffff +# define RADEON_MEM_CFG_TYPE_DDR (1 << 30) +#define RADEON_MEM_STR_CNTL 0x0150 +# define RADEON_MEM_PWRUP_COMPL_A (1 << 0) +# define RADEON_MEM_PWRUP_COMPL_B (1 << 1) +# define R300_MEM_PWRUP_COMPL_C (1 << 2) +# define R300_MEM_PWRUP_COMPL_D (1 << 3) +# define RADEON_MEM_PWRUP_COMPLETE 0x03 +# define R300_MEM_PWRUP_COMPLETE 0x0f +#define RADEON_MC_STATUS 0x0150 +# define RADEON_MC_IDLE (1 << 2) +# define R300_MC_IDLE (1 << 4) +#define RADEON_MEM_VGA_RP_SEL 0x003c +#define RADEON_MEM_VGA_WP_SEL 0x0038 +#define RADEON_MIN_GRANT 0x0f3e /* PCI */ +#define RADEON_MM_DATA 0x0004 +#define RADEON_MM_INDEX 0x0000 +# define RADEON_MM_APER (1 << 31) +#define RADEON_MPLL_CNTL 0x000e /* PLL */ +#define RADEON_MPP_TB_CONFIG 0x01c0 /* ? */ +#define RADEON_MPP_GP_CONFIG 0x01c8 /* ? */ +#define RADEON_SEPROM_CNTL1 0x01c0 +# define RADEON_SCK_PRESCALE_SHIFT 24 +# define RADEON_SCK_PRESCALE_MASK (0xff << 24) +#define R300_MC_IND_INDEX 0x01f8 +# define R300_MC_IND_ADDR_MASK 0x3f +# define R300_MC_IND_WR_EN (1 << 8) +#define R300_MC_IND_DATA 0x01fc +#define R300_MC_READ_CNTL_AB 0x017c +# define R300_MEM_RBS_POSITION_A_MASK 0x03 +#define R300_MC_READ_CNTL_CD_mcind 0x24 +# define R300_MEM_RBS_POSITION_C_MASK 0x03 + +#define RADEON_N_VIF_COUNT 0x0248 + +#define RADEON_OV0_AUTO_FLIP_CNTL 0x0470 +# define RADEON_OV0_AUTO_FLIP_CNTL_SOFT_BUF_NUM 0x00000007 +# define RADEON_OV0_AUTO_FLIP_CNTL_SOFT_REPEAT_FIELD 0x00000008 +# define RADEON_OV0_AUTO_FLIP_CNTL_SOFT_BUF_ODD 0x00000010 +# define RADEON_OV0_AUTO_FLIP_CNTL_IGNORE_REPEAT_FIELD 0x00000020 +# define RADEON_OV0_AUTO_FLIP_CNTL_SOFT_EOF_TOGGLE 0x00000040 +# define RADEON_OV0_AUTO_FLIP_CNTL_VID_PORT_SELECT 0x00000300 +# define RADEON_OV0_AUTO_FLIP_CNTL_P1_FIRST_LINE_EVEN 0x00010000 +# define RADEON_OV0_AUTO_FLIP_CNTL_SHIFT_EVEN_DOWN 0x00040000 +# define RADEON_OV0_AUTO_FLIP_CNTL_SHIFT_ODD_DOWN 0x00080000 +# define RADEON_OV0_AUTO_FLIP_CNTL_FIELD_POL_SOURCE 0x00800000 + +#define RADEON_OV0_COLOUR_CNTL 0x04E0 +#define RADEON_OV0_DEINTERLACE_PATTERN 0x0474 +#define RADEON_OV0_EXCLUSIVE_HORZ 0x0408 +# define RADEON_EXCL_HORZ_START_MASK 0x000000ff +# define RADEON_EXCL_HORZ_END_MASK 0x0000ff00 +# define RADEON_EXCL_HORZ_BACK_PORCH_MASK 0x00ff0000 +# define RADEON_EXCL_HORZ_EXCLUSIVE_EN 0x80000000 +#define RADEON_OV0_EXCLUSIVE_VERT 0x040C +# define RADEON_EXCL_VERT_START_MASK 0x000003ff +# define RADEON_EXCL_VERT_END_MASK 0x03ff0000 +#define RADEON_OV0_FILTER_CNTL 0x04A0 +# define RADEON_FILTER_PROGRAMMABLE_COEF 0x0 +# define RADEON_FILTER_HC_COEF_HORZ_Y 0x1 +# define RADEON_FILTER_HC_COEF_HORZ_UV 0x2 +# define RADEON_FILTER_HC_COEF_VERT_Y 0x4 +# define RADEON_FILTER_HC_COEF_VERT_UV 0x8 +# define RADEON_FILTER_HARDCODED_COEF 0xf +# define RADEON_FILTER_COEF_MASK 0xf + +#define RADEON_OV0_FOUR_TAP_COEF_0 0x04B0 +#define RADEON_OV0_FOUR_TAP_COEF_1 0x04B4 +#define RADEON_OV0_FOUR_TAP_COEF_2 0x04B8 +#define RADEON_OV0_FOUR_TAP_COEF_3 0x04BC +#define RADEON_OV0_FOUR_TAP_COEF_4 0x04C0 +#define RADEON_OV0_FLAG_CNTL 0x04DC +#define RADEON_OV0_GAMMA_000_00F 0x0d40 +#define RADEON_OV0_GAMMA_010_01F 0x0d44 +#define RADEON_OV0_GAMMA_020_03F 0x0d48 +#define RADEON_OV0_GAMMA_040_07F 0x0d4c +#define RADEON_OV0_GAMMA_080_0BF 0x0e00 +#define RADEON_OV0_GAMMA_0C0_0FF 0x0e04 +#define RADEON_OV0_GAMMA_100_13F 0x0e08 +#define RADEON_OV0_GAMMA_140_17F 0x0e0c +#define RADEON_OV0_GAMMA_180_1BF 0x0e10 +#define RADEON_OV0_GAMMA_1C0_1FF 0x0e14 +#define RADEON_OV0_GAMMA_200_23F 0x0e18 +#define RADEON_OV0_GAMMA_240_27F 0x0e1c +#define RADEON_OV0_GAMMA_280_2BF 0x0e20 +#define RADEON_OV0_GAMMA_2C0_2FF 0x0e24 +#define RADEON_OV0_GAMMA_300_33F 0x0e28 +#define RADEON_OV0_GAMMA_340_37F 0x0e2c +#define RADEON_OV0_GAMMA_380_3BF 0x0d50 +#define RADEON_OV0_GAMMA_3C0_3FF 0x0d54 +#define RADEON_OV0_GRAPHICS_KEY_CLR_LOW 0x04EC +#define RADEON_OV0_GRAPHICS_KEY_CLR_HIGH 0x04F0 +#define RADEON_OV0_H_INC 0x0480 +#define RADEON_OV0_KEY_CNTL 0x04F4 +# define RADEON_VIDEO_KEY_FN_MASK 0x00000003L +# define RADEON_VIDEO_KEY_FN_FALSE 0x00000000L +# define RADEON_VIDEO_KEY_FN_TRUE 0x00000001L +# define RADEON_VIDEO_KEY_FN_EQ 0x00000002L +# define RADEON_VIDEO_KEY_FN_NE 0x00000003L +# define RADEON_GRAPHIC_KEY_FN_MASK 0x00000030L +# define RADEON_GRAPHIC_KEY_FN_FALSE 0x00000000L +# define RADEON_GRAPHIC_KEY_FN_TRUE 0x00000010L +# define RADEON_GRAPHIC_KEY_FN_EQ 0x00000020L +# define RADEON_GRAPHIC_KEY_FN_NE 0x00000030L +# define RADEON_CMP_MIX_MASK 0x00000100L +# define RADEON_CMP_MIX_OR 0x00000000L +# define RADEON_CMP_MIX_AND 0x00000100L +#define RADEON_OV0_LIN_TRANS_A 0x0d20 +#define RADEON_OV0_LIN_TRANS_B 0x0d24 +#define RADEON_OV0_LIN_TRANS_C 0x0d28 +#define RADEON_OV0_LIN_TRANS_D 0x0d2c +#define RADEON_OV0_LIN_TRANS_E 0x0d30 +#define RADEON_OV0_LIN_TRANS_F 0x0d34 +#define RADEON_OV0_P1_BLANK_LINES_AT_TOP 0x0430 +# define RADEON_P1_BLNK_LN_AT_TOP_M1_MASK 0x00000fffL +# define RADEON_P1_ACTIVE_LINES_M1 0x0fff0000L +#define RADEON_OV0_P1_H_ACCUM_INIT 0x0488 +#define RADEON_OV0_P1_V_ACCUM_INIT 0x0428 +# define RADEON_OV0_P1_MAX_LN_IN_PER_LN_OUT 0x00000003L +# define RADEON_OV0_P1_V_ACCUM_INIT_MASK 0x01ff8000L +#define RADEON_OV0_P1_X_START_END 0x0494 +#define RADEON_OV0_P2_X_START_END 0x0498 +#define RADEON_OV0_P23_BLANK_LINES_AT_TOP 0x0434 +# define RADEON_P23_BLNK_LN_AT_TOP_M1_MASK 0x000007ffL +# define RADEON_P23_ACTIVE_LINES_M1 0x07ff0000L +#define RADEON_OV0_P23_H_ACCUM_INIT 0x048C +#define RADEON_OV0_P23_V_ACCUM_INIT 0x042C +#define RADEON_OV0_P3_X_START_END 0x049C +#define RADEON_OV0_REG_LOAD_CNTL 0x0410 +# define RADEON_REG_LD_CTL_LOCK 0x00000001L +# define RADEON_REG_LD_CTL_VBLANK_DURING_LOCK 0x00000002L +# define RADEON_REG_LD_CTL_STALL_GUI_UNTIL_FLIP 0x00000004L +# define RADEON_REG_LD_CTL_LOCK_READBACK 0x00000008L +# define RADEON_REG_LD_CTL_FLIP_READBACK 0x00000010L +#define RADEON_OV0_SCALE_CNTL 0x0420 +# define RADEON_SCALER_HORZ_PICK_NEAREST 0x00000004L +# define RADEON_SCALER_VERT_PICK_NEAREST 0x00000008L +# define RADEON_SCALER_SIGNED_UV 0x00000010L +# define RADEON_SCALER_GAMMA_SEL_MASK 0x00000060L +# define RADEON_SCALER_GAMMA_SEL_BRIGHT 0x00000000L +# define RADEON_SCALER_GAMMA_SEL_G22 0x00000020L +# define RADEON_SCALER_GAMMA_SEL_G18 0x00000040L +# define RADEON_SCALER_GAMMA_SEL_G14 0x00000060L +# define RADEON_SCALER_COMCORE_SHIFT_UP_ONE 0x00000080L +# define RADEON_SCALER_SURFAC_FORMAT 0x00000f00L +# define RADEON_SCALER_SOURCE_15BPP 0x00000300L +# define RADEON_SCALER_SOURCE_16BPP 0x00000400L +# define RADEON_SCALER_SOURCE_32BPP 0x00000600L +# define RADEON_SCALER_SOURCE_YUV9 0x00000900L +# define RADEON_SCALER_SOURCE_YUV12 0x00000A00L +# define RADEON_SCALER_SOURCE_VYUY422 0x00000B00L +# define RADEON_SCALER_SOURCE_YVYU422 0x00000C00L +# define RADEON_SCALER_ADAPTIVE_DEINT 0x00001000L +# define RADEON_SCALER_TEMPORAL_DEINT 0x00002000L +# define RADEON_SCALER_CRTC_SEL 0x00004000L +# define RADEON_SCALER_SMART_SWITCH 0x00008000L +# define RADEON_SCALER_BURST_PER_PLANE 0x007F0000L +# define RADEON_SCALER_DOUBLE_BUFFER 0x01000000L +# define RADEON_SCALER_DIS_LIMIT 0x08000000L +# define RADEON_SCALER_LIN_TRANS_BYPASS 0x10000000L +# define RADEON_SCALER_INT_EMU 0x20000000L +# define RADEON_SCALER_ENABLE 0x40000000L +# define RADEON_SCALER_SOFT_RESET 0x80000000L +#define RADEON_OV0_STEP_BY 0x0484 +#define RADEON_OV0_TEST 0x04F8 +#define RADEON_OV0_V_INC 0x0424 +#define RADEON_OV0_VID_BUF_PITCH0_VALUE 0x0460 +#define RADEON_OV0_VID_BUF_PITCH1_VALUE 0x0464 +#define RADEON_OV0_VID_BUF0_BASE_ADRS 0x0440 +# define RADEON_VIF_BUF0_PITCH_SEL 0x00000001L +# define RADEON_VIF_BUF0_TILE_ADRS 0x00000002L +# define RADEON_VIF_BUF0_BASE_ADRS_MASK 0x03fffff0L +# define RADEON_VIF_BUF0_1ST_LINE_LSBS_MASK 0x48000000L +#define RADEON_OV0_VID_BUF1_BASE_ADRS 0x0444 +# define RADEON_VIF_BUF1_PITCH_SEL 0x00000001L +# define RADEON_VIF_BUF1_TILE_ADRS 0x00000002L +# define RADEON_VIF_BUF1_BASE_ADRS_MASK 0x03fffff0L +# define RADEON_VIF_BUF1_1ST_LINE_LSBS_MASK 0x48000000L +#define RADEON_OV0_VID_BUF2_BASE_ADRS 0x0448 +# define RADEON_VIF_BUF2_PITCH_SEL 0x00000001L +# define RADEON_VIF_BUF2_TILE_ADRS 0x00000002L +# define RADEON_VIF_BUF2_BASE_ADRS_MASK 0x03fffff0L +# define RADEON_VIF_BUF2_1ST_LINE_LSBS_MASK 0x48000000L +#define RADEON_OV0_VID_BUF3_BASE_ADRS 0x044C +#define RADEON_OV0_VID_BUF4_BASE_ADRS 0x0450 +#define RADEON_OV0_VID_BUF5_BASE_ADRS 0x0454 +#define RADEON_OV0_VIDEO_KEY_CLR_HIGH 0x04E8 +#define RADEON_OV0_VIDEO_KEY_CLR_LOW 0x04E4 +#define RADEON_OV0_Y_X_START 0x0400 +#define RADEON_OV0_Y_X_END 0x0404 +#define RADEON_OV1_Y_X_START 0x0600 +#define RADEON_OV1_Y_X_END 0x0604 +#define RADEON_OVR_CLR 0x0230 +#define RADEON_OVR_WID_LEFT_RIGHT 0x0234 +#define RADEON_OVR_WID_TOP_BOTTOM 0x0238 + +/* first capture unit */ + +#define RADEON_CAP0_BUF0_OFFSET 0x0920 +#define RADEON_CAP0_BUF1_OFFSET 0x0924 +#define RADEON_CAP0_BUF0_EVEN_OFFSET 0x0928 +#define RADEON_CAP0_BUF1_EVEN_OFFSET 0x092C + +#define RADEON_CAP0_BUF_PITCH 0x0930 +#define RADEON_CAP0_V_WINDOW 0x0934 +#define RADEON_CAP0_H_WINDOW 0x0938 +#define RADEON_CAP0_VBI0_OFFSET 0x093C +#define RADEON_CAP0_VBI1_OFFSET 0x0940 +#define RADEON_CAP0_VBI_V_WINDOW 0x0944 +#define RADEON_CAP0_VBI_H_WINDOW 0x0948 +#define RADEON_CAP0_PORT_MODE_CNTL 0x094C +#define RADEON_CAP0_TRIG_CNTL 0x0950 +#define RADEON_CAP0_DEBUG 0x0954 +#define RADEON_CAP0_CONFIG 0x0958 +# define RADEON_CAP0_CONFIG_CONTINUOS 0x00000001 +# define RADEON_CAP0_CONFIG_START_FIELD_EVEN 0x00000002 +# define RADEON_CAP0_CONFIG_START_BUF_GET 0x00000004 +# define RADEON_CAP0_CONFIG_START_BUF_SET 0x00000008 +# define RADEON_CAP0_CONFIG_BUF_TYPE_ALT 0x00000010 +# define RADEON_CAP0_CONFIG_BUF_TYPE_FRAME 0x00000020 +# define RADEON_CAP0_CONFIG_ONESHOT_MODE_FRAME 0x00000040 +# define RADEON_CAP0_CONFIG_BUF_MODE_DOUBLE 0x00000080 +# define RADEON_CAP0_CONFIG_BUF_MODE_TRIPLE 0x00000100 +# define RADEON_CAP0_CONFIG_MIRROR_EN 0x00000200 +# define RADEON_CAP0_CONFIG_ONESHOT_MIRROR_EN 0x00000400 +# define RADEON_CAP0_CONFIG_VIDEO_SIGNED_UV 0x00000800 +# define RADEON_CAP0_CONFIG_ANC_DECODE_EN 0x00001000 +# define RADEON_CAP0_CONFIG_VBI_EN 0x00002000 +# define RADEON_CAP0_CONFIG_SOFT_PULL_DOWN_EN 0x00004000 +# define RADEON_CAP0_CONFIG_VIP_EXTEND_FLAG_EN 0x00008000 +# define RADEON_CAP0_CONFIG_FAKE_FIELD_EN 0x00010000 +# define RADEON_CAP0_CONFIG_ODD_ONE_MORE_LINE 0x00020000 +# define RADEON_CAP0_CONFIG_EVEN_ONE_MORE_LINE 0x00040000 +# define RADEON_CAP0_CONFIG_HORZ_DIVIDE_2 0x00080000 +# define RADEON_CAP0_CONFIG_HORZ_DIVIDE_4 0x00100000 +# define RADEON_CAP0_CONFIG_VERT_DIVIDE_2 0x00200000 +# define RADEON_CAP0_CONFIG_VERT_DIVIDE_4 0x00400000 +# define RADEON_CAP0_CONFIG_FORMAT_BROOKTREE 0x00000000 +# define RADEON_CAP0_CONFIG_FORMAT_CCIR656 0x00800000 +# define RADEON_CAP0_CONFIG_FORMAT_ZV 0x01000000 +# define RADEON_CAP0_CONFIG_FORMAT_VIP 0x01800000 +# define RADEON_CAP0_CONFIG_FORMAT_TRANSPORT 0x02000000 +# define RADEON_CAP0_CONFIG_HORZ_DECIMATOR 0x04000000 +# define RADEON_CAP0_CONFIG_VIDEO_IN_YVYU422 0x00000000 +# define RADEON_CAP0_CONFIG_VIDEO_IN_VYUY422 0x20000000 +# define RADEON_CAP0_CONFIG_VBI_DIVIDE_2 0x40000000 +# define RADEON_CAP0_CONFIG_VBI_DIVIDE_4 0x80000000 +#define RADEON_CAP0_ANC_ODD_OFFSET 0x095C +#define RADEON_CAP0_ANC_EVEN_OFFSET 0x0960 +#define RADEON_CAP0_ANC_H_WINDOW 0x0964 +#define RADEON_CAP0_VIDEO_SYNC_TEST 0x0968 +#define RADEON_CAP0_ONESHOT_BUF_OFFSET 0x096C +#define RADEON_CAP0_BUF_STATUS 0x0970 +/* #define RADEON_CAP0_DWNSC_XRATIO 0x0978 */ +/* #define RADEON_CAP0_XSHARPNESS 0x097C */ +#define RADEON_CAP0_VBI2_OFFSET 0x0980 +#define RADEON_CAP0_VBI3_OFFSET 0x0984 +#define RADEON_CAP0_ANC2_OFFSET 0x0988 +#define RADEON_CAP0_ANC3_OFFSET 0x098C +#define RADEON_VID_BUFFER_CONTROL 0x0900 + +/* second capture unit */ + +#define RADEON_CAP1_BUF0_OFFSET 0x0990 +#define RADEON_CAP1_BUF1_OFFSET 0x0994 +#define RADEON_CAP1_BUF0_EVEN_OFFSET 0x0998 +#define RADEON_CAP1_BUF1_EVEN_OFFSET 0x099C + +#define RADEON_CAP1_BUF_PITCH 0x09A0 +#define RADEON_CAP1_V_WINDOW 0x09A4 +#define RADEON_CAP1_H_WINDOW 0x09A8 +#define RADEON_CAP1_VBI_ODD_OFFSET 0x09AC +#define RADEON_CAP1_VBI_EVEN_OFFSET 0x09B0 +#define RADEON_CAP1_VBI_V_WINDOW 0x09B4 +#define RADEON_CAP1_VBI_H_WINDOW 0x09B8 +#define RADEON_CAP1_PORT_MODE_CNTL 0x09BC +#define RADEON_CAP1_TRIG_CNTL 0x09C0 +#define RADEON_CAP1_DEBUG 0x09C4 +#define RADEON_CAP1_CONFIG 0x09C8 +#define RADEON_CAP1_ANC_ODD_OFFSET 0x09CC +#define RADEON_CAP1_ANC_EVEN_OFFSET 0x09D0 +#define RADEON_CAP1_ANC_H_WINDOW 0x09D4 +#define RADEON_CAP1_VIDEO_SYNC_TEST 0x09D8 +#define RADEON_CAP1_ONESHOT_BUF_OFFSET 0x09DC +#define RADEON_CAP1_BUF_STATUS 0x09E0 +#define RADEON_CAP1_DWNSC_XRATIO 0x09E8 +#define RADEON_CAP1_XSHARPNESS 0x09EC + +/* misc multimedia registers */ + +#define RADEON_IDCT_RUNS 0x1F80 +#define RADEON_IDCT_LEVELS 0x1F84 +#define RADEON_IDCT_CONTROL 0x1FBC +#define RADEON_IDCT_AUTH_CONTROL 0x1F88 +#define RADEON_IDCT_AUTH 0x1F8C + +#define RADEON_P2PLL_CNTL 0x002a /* P2PLL */ +# define RADEON_P2PLL_RESET (1 << 0) +# define RADEON_P2PLL_SLEEP (1 << 1) +# define RADEON_P2PLL_PVG_MASK (7 << 11) +# define RADEON_P2PLL_PVG_SHIFT 11 +# define RADEON_P2PLL_ATOMIC_UPDATE_EN (1 << 16) +# define RADEON_P2PLL_VGA_ATOMIC_UPDATE_EN (1 << 17) +# define RADEON_P2PLL_ATOMIC_UPDATE_VSYNC (1 << 18) +#define RADEON_P2PLL_DIV_0 0x002c +# define RADEON_P2PLL_FB0_DIV_MASK 0x07ff +# define RADEON_P2PLL_POST0_DIV_MASK 0x00070000 +#define RADEON_P2PLL_REF_DIV 0x002B /* PLL */ +# define RADEON_P2PLL_REF_DIV_MASK 0x03ff +# define RADEON_P2PLL_ATOMIC_UPDATE_R (1 << 15) /* same as _W */ +# define RADEON_P2PLL_ATOMIC_UPDATE_W (1 << 15) /* same as _R */ +# define R300_PPLL_REF_DIV_ACC_MASK (0x3ff << 18) +# define R300_PPLL_REF_DIV_ACC_SHIFT 18 +#define RADEON_PALETTE_DATA 0x00b4 +#define RADEON_PALETTE_30_DATA 0x00b8 +#define RADEON_PALETTE_INDEX 0x00b0 +#define RADEON_PCI_GART_PAGE 0x017c +#define RADEON_PIXCLKS_CNTL 0x002d +# define RADEON_PIX2CLK_SRC_SEL_MASK 0x03 +# define RADEON_PIX2CLK_SRC_SEL_CPUCLK 0x00 +# define RADEON_PIX2CLK_SRC_SEL_PSCANCLK 0x01 +# define RADEON_PIX2CLK_SRC_SEL_BYTECLK 0x02 +# define RADEON_PIX2CLK_SRC_SEL_P2PLLCLK 0x03 +# define RADEON_PIX2CLK_ALWAYS_ONb (1<<6) +# define RADEON_PIX2CLK_DAC_ALWAYS_ONb (1<<7) +# define RADEON_PIXCLK_TV_SRC_SEL (1 << 8) +# define RADEON_DISP_TVOUT_PIXCLK_TV_ALWAYS_ONb (1 << 9) +# define R300_DVOCLK_ALWAYS_ONb (1 << 10) +# define RADEON_PIXCLK_BLEND_ALWAYS_ONb (1 << 11) +# define RADEON_PIXCLK_GV_ALWAYS_ONb (1 << 12) +# define RADEON_PIXCLK_DIG_TMDS_ALWAYS_ONb (1 << 13) +# define R300_PIXCLK_DVO_ALWAYS_ONb (1 << 13) +# define RADEON_PIXCLK_LVDS_ALWAYS_ONb (1 << 14) +# define RADEON_PIXCLK_TMDS_ALWAYS_ONb (1 << 15) +# define R300_PIXCLK_TRANS_ALWAYS_ONb (1 << 16) +# define R300_PIXCLK_TVO_ALWAYS_ONb (1 << 17) +# define R300_P2G2CLK_ALWAYS_ONb (1 << 18) +# define R300_P2G2CLK_DAC_ALWAYS_ONb (1 << 19) +# define R300_DISP_DAC_PIXCLK_DAC2_BLANK_OFF (1 << 23) +#define RADEON_PLANE_3D_MASK_C 0x1d44 +#define RADEON_PLL_TEST_CNTL 0x0013 /* PLL */ +# define RADEON_PLL_MASK_READ_B (1 << 9) +#define RADEON_PMI_CAP_ID 0x0f5c /* PCI */ +#define RADEON_PMI_DATA 0x0f63 /* PCI */ +#define RADEON_PMI_NXT_CAP_PTR 0x0f5d /* PCI */ +#define RADEON_PMI_PMC_REG 0x0f5e /* PCI */ +#define RADEON_PMI_PMCSR_REG 0x0f60 /* PCI */ +#define RADEON_PMI_REGISTER 0x0f5c /* PCI */ +#define RADEON_PPLL_CNTL 0x0002 /* PLL */ +# define RADEON_PPLL_RESET (1 << 0) +# define RADEON_PPLL_SLEEP (1 << 1) +# define RADEON_PPLL_PVG_MASK (7 << 11) +# define RADEON_PPLL_PVG_SHIFT 11 +# define RADEON_PPLL_ATOMIC_UPDATE_EN (1 << 16) +# define RADEON_PPLL_VGA_ATOMIC_UPDATE_EN (1 << 17) +# define RADEON_PPLL_ATOMIC_UPDATE_VSYNC (1 << 18) +#define RADEON_PPLL_DIV_0 0x0004 /* PLL */ +#define RADEON_PPLL_DIV_1 0x0005 /* PLL */ +#define RADEON_PPLL_DIV_2 0x0006 /* PLL */ +#define RADEON_PPLL_DIV_3 0x0007 /* PLL */ +# define RADEON_PPLL_FB3_DIV_MASK 0x07ff +# define RADEON_PPLL_POST3_DIV_MASK 0x00070000 +#define RADEON_PPLL_REF_DIV 0x0003 /* PLL */ +# define RADEON_PPLL_REF_DIV_MASK 0x03ff +# define RADEON_PPLL_ATOMIC_UPDATE_R (1 << 15) /* same as _W */ +# define RADEON_PPLL_ATOMIC_UPDATE_W (1 << 15) /* same as _R */ +#define RADEON_PWR_MNGMT_CNTL_STATUS 0x0f60 /* PCI */ + +#define RADEON_RBBM_GUICNTL 0x172c +# define RADEON_HOST_DATA_SWAP_NONE (0 << 0) +# define RADEON_HOST_DATA_SWAP_16BIT (1 << 0) +# define RADEON_HOST_DATA_SWAP_32BIT (2 << 0) +# define RADEON_HOST_DATA_SWAP_HDW (3 << 0) +#define RADEON_RBBM_SOFT_RESET 0x00f0 +# define RADEON_SOFT_RESET_CP (1 << 0) +# define RADEON_SOFT_RESET_HI (1 << 1) +# define RADEON_SOFT_RESET_SE (1 << 2) +# define RADEON_SOFT_RESET_RE (1 << 3) +# define RADEON_SOFT_RESET_PP (1 << 4) +# define RADEON_SOFT_RESET_E2 (1 << 5) +# define RADEON_SOFT_RESET_RB (1 << 6) +# define RADEON_SOFT_RESET_HDP (1 << 7) +#define RADEON_RBBM_STATUS 0x0e40 +# define RADEON_RBBM_FIFOCNT_MASK 0x007f +# define RADEON_RBBM_ACTIVE (1 << 31) +#define RADEON_RB2D_DSTCACHE_CTLSTAT 0x342c +# define RADEON_RB2D_DC_FLUSH (3 << 0) +# define RADEON_RB2D_DC_FREE (3 << 2) +# define RADEON_RB2D_DC_FLUSH_ALL 0xf +# define RADEON_RB2D_DC_BUSY (1 << 31) +#define RADEON_RB2D_DSTCACHE_MODE 0x3428 +#define RADEON_DSTCACHE_CTLSTAT 0x1714 + +#define RADEON_RB3D_ZCACHE_MODE 0x3250 +#define RADEON_RB3D_ZCACHE_CTLSTAT 0x3254 +# define RADEON_RB3D_ZC_FLUSH_ALL 0x5 +#define RADEON_RB3D_DSTCACHE_MODE 0x3258 +# define RADEON_RB3D_DC_CACHE_ENABLE (0) +# define RADEON_RB3D_DC_2D_CACHE_DISABLE (1) +# define RADEON_RB3D_DC_3D_CACHE_DISABLE (2) +# define RADEON_RB3D_DC_CACHE_DISABLE (3) +# define RADEON_RB3D_DC_2D_CACHE_LINESIZE_128 (1 << 2) +# define RADEON_RB3D_DC_3D_CACHE_LINESIZE_128 (2 << 2) +# define RADEON_RB3D_DC_2D_CACHE_AUTOFLUSH (1 << 8) +# define RADEON_RB3D_DC_3D_CACHE_AUTOFLUSH (2 << 8) +# define R200_RB3D_DC_2D_CACHE_AUTOFREE (1 << 10) +# define R200_RB3D_DC_3D_CACHE_AUTOFREE (2 << 10) +# define RADEON_RB3D_DC_FORCE_RMW (1 << 16) +# define RADEON_RB3D_DC_DISABLE_RI_FILL (1 << 24) +# define RADEON_RB3D_DC_DISABLE_RI_READ (1 << 25) + +#define RADEON_RB3D_DSTCACHE_CTLSTAT 0x325C +# define RADEON_RB3D_DC_FLUSH (3 << 0) +# define RADEON_RB3D_DC_FREE (3 << 2) +# define RADEON_RB3D_DC_FLUSH_ALL 0xf +# define RADEON_RB3D_DC_BUSY (1 << 31) + +#define RADEON_REG_BASE 0x0f18 /* PCI */ +#define RADEON_REGPROG_INF 0x0f09 /* PCI */ +#define RADEON_REVISION_ID 0x0f08 /* PCI */ + +#define RADEON_SC_BOTTOM 0x164c +#define RADEON_SC_BOTTOM_RIGHT 0x16f0 +#define RADEON_SC_BOTTOM_RIGHT_C 0x1c8c +#define RADEON_SC_LEFT 0x1640 +#define RADEON_SC_RIGHT 0x1644 +#define RADEON_SC_TOP 0x1648 +#define RADEON_SC_TOP_LEFT 0x16ec +#define RADEON_SC_TOP_LEFT_C 0x1c88 +# define RADEON_SC_SIGN_MASK_LO 0x8000 +# define RADEON_SC_SIGN_MASK_HI 0x80000000 +#define RADEON_M_SPLL_REF_FB_DIV 0x000a /* PLL */ +# define RADEON_M_SPLL_REF_DIV_SHIFT 0 +# define RADEON_M_SPLL_REF_DIV_MASK 0xff +# define RADEON_MPLL_FB_DIV_SHIFT 8 +# define RADEON_MPLL_FB_DIV_MASK 0xff +# define RADEON_SPLL_FB_DIV_SHIFT 16 +# define RADEON_SPLL_FB_DIV_MASK 0xff +#define RADEON_SPLL_CNTL 0x000c /* PLL */ +# define RADEON_SPLL_SLEEP (1 << 0) +# define RADEON_SPLL_RESET (1 << 1) +# define RADEON_SPLL_PCP_MASK 0x7 +# define RADEON_SPLL_PCP_SHIFT 8 +# define RADEON_SPLL_PVG_MASK 0x7 +# define RADEON_SPLL_PVG_SHIFT 11 +# define RADEON_SPLL_PDC_MASK 0x3 +# define RADEON_SPLL_PDC_SHIFT 14 +#define RADEON_SCLK_CNTL 0x000d /* PLL */ +# define RADEON_SCLK_SRC_SEL_MASK 0x0007 +# define RADEON_DYN_STOP_LAT_MASK 0x00007ff8 +# define RADEON_CP_MAX_DYN_STOP_LAT 0x0008 +# define RADEON_SCLK_FORCEON_MASK 0xffff8000 +# define RADEON_SCLK_FORCE_DISP2 (1<<15) +# define RADEON_SCLK_FORCE_CP (1<<16) +# define RADEON_SCLK_FORCE_HDP (1<<17) +# define RADEON_SCLK_FORCE_DISP1 (1<<18) +# define RADEON_SCLK_FORCE_TOP (1<<19) +# define RADEON_SCLK_FORCE_E2 (1<<20) +# define RADEON_SCLK_FORCE_SE (1<<21) +# define RADEON_SCLK_FORCE_IDCT (1<<22) +# define RADEON_SCLK_FORCE_VIP (1<<23) +# define RADEON_SCLK_FORCE_RE (1<<24) +# define RADEON_SCLK_FORCE_PB (1<<25) +# define RADEON_SCLK_FORCE_TAM (1<<26) +# define RADEON_SCLK_FORCE_TDM (1<<27) +# define RADEON_SCLK_FORCE_RB (1<<28) +# define RADEON_SCLK_FORCE_TV_SCLK (1<<29) +# define RADEON_SCLK_FORCE_SUBPIC (1<<30) +# define RADEON_SCLK_FORCE_OV0 (1<<31) +# define R300_SCLK_FORCE_VAP (1<<21) +# define R300_SCLK_FORCE_SR (1<<25) +# define R300_SCLK_FORCE_PX (1<<26) +# define R300_SCLK_FORCE_TX (1<<27) +# define R300_SCLK_FORCE_US (1<<28) +# define R300_SCLK_FORCE_SU (1<<30) +#define R300_SCLK_CNTL2 0x1e /* PLL */ +# define R300_SCLK_TCL_MAX_DYN_STOP_LAT (1<<10) +# define R300_SCLK_GA_MAX_DYN_STOP_LAT (1<<11) +# define R300_SCLK_CBA_MAX_DYN_STOP_LAT (1<<12) +# define R300_SCLK_FORCE_TCL (1<<13) +# define R300_SCLK_FORCE_CBA (1<<14) +# define R300_SCLK_FORCE_GA (1<<15) +#define RADEON_SCLK_MORE_CNTL 0x0035 /* PLL */ +# define RADEON_SCLK_MORE_MAX_DYN_STOP_LAT 0x0007 +# define RADEON_SCLK_MORE_FORCEON 0x0700 +#define RADEON_SDRAM_MODE_REG 0x0158 +#define RADEON_SEQ8_DATA 0x03c5 /* VGA */ +#define RADEON_SEQ8_IDX 0x03c4 /* VGA */ +#define RADEON_SNAPSHOT_F_COUNT 0x0244 +#define RADEON_SNAPSHOT_VH_COUNTS 0x0240 +#define RADEON_SNAPSHOT_VIF_COUNT 0x024c +#define RADEON_SRC_OFFSET 0x15ac +#define RADEON_SRC_PITCH 0x15b0 +#define RADEON_SRC_PITCH_OFFSET 0x1428 +#define RADEON_SRC_SC_BOTTOM 0x165c +#define RADEON_SRC_SC_BOTTOM_RIGHT 0x16f4 +#define RADEON_SRC_SC_RIGHT 0x1654 +#define RADEON_SRC_X 0x1414 +#define RADEON_SRC_X_Y 0x1590 +#define RADEON_SRC_Y 0x1418 +#define RADEON_SRC_Y_X 0x1434 +#define RADEON_STATUS 0x0f06 /* PCI */ +#define RADEON_SUBPIC_CNTL 0x0540 /* ? */ +#define RADEON_SUB_CLASS 0x0f0a /* PCI */ +#define RADEON_SURFACE_CNTL 0x0b00 +# define RADEON_SURF_TRANSLATION_DIS (1 << 8) +# define RADEON_NONSURF_AP0_SWP_16BPP (1 << 20) +# define RADEON_NONSURF_AP0_SWP_32BPP (1 << 21) +# define RADEON_NONSURF_AP1_SWP_16BPP (1 << 22) +# define RADEON_NONSURF_AP1_SWP_32BPP (1 << 23) +#define RADEON_SURFACE0_INFO 0x0b0c +# define RADEON_SURF_TILE_COLOR_MACRO (0 << 16) +# define RADEON_SURF_TILE_COLOR_BOTH (1 << 16) +# define RADEON_SURF_TILE_DEPTH_32BPP (2 << 16) +# define RADEON_SURF_TILE_DEPTH_16BPP (3 << 16) +# define R200_SURF_TILE_NONE (0 << 16) +# define R200_SURF_TILE_COLOR_MACRO (1 << 16) +# define R200_SURF_TILE_COLOR_MICRO (2 << 16) +# define R200_SURF_TILE_COLOR_BOTH (3 << 16) +# define R200_SURF_TILE_DEPTH_32BPP (4 << 16) +# define R200_SURF_TILE_DEPTH_16BPP (5 << 16) +# define R300_SURF_TILE_NONE (0 << 16) +# define R300_SURF_TILE_COLOR_MACRO (1 << 16) +# define R300_SURF_TILE_DEPTH_32BPP (2 << 16) +# define RADEON_SURF_AP0_SWP_16BPP (1 << 20) +# define RADEON_SURF_AP0_SWP_32BPP (1 << 21) +# define RADEON_SURF_AP1_SWP_16BPP (1 << 22) +# define RADEON_SURF_AP1_SWP_32BPP (1 << 23) +#define RADEON_SURFACE0_LOWER_BOUND 0x0b04 +#define RADEON_SURFACE0_UPPER_BOUND 0x0b08 +#define RADEON_SURFACE1_INFO 0x0b1c +#define RADEON_SURFACE1_LOWER_BOUND 0x0b14 +#define RADEON_SURFACE1_UPPER_BOUND 0x0b18 +#define RADEON_SURFACE2_INFO 0x0b2c +#define RADEON_SURFACE2_LOWER_BOUND 0x0b24 +#define RADEON_SURFACE2_UPPER_BOUND 0x0b28 +#define RADEON_SURFACE3_INFO 0x0b3c +#define RADEON_SURFACE3_LOWER_BOUND 0x0b34 +#define RADEON_SURFACE3_UPPER_BOUND 0x0b38 +#define RADEON_SURFACE4_INFO 0x0b4c +#define RADEON_SURFACE4_LOWER_BOUND 0x0b44 +#define RADEON_SURFACE4_UPPER_BOUND 0x0b48 +#define RADEON_SURFACE5_INFO 0x0b5c +#define RADEON_SURFACE5_LOWER_BOUND 0x0b54 +#define RADEON_SURFACE5_UPPER_BOUND 0x0b58 +#define RADEON_SURFACE6_INFO 0x0b6c +#define RADEON_SURFACE6_LOWER_BOUND 0x0b64 +#define RADEON_SURFACE6_UPPER_BOUND 0x0b68 +#define RADEON_SURFACE7_INFO 0x0b7c +#define RADEON_SURFACE7_LOWER_BOUND 0x0b74 +#define RADEON_SURFACE7_UPPER_BOUND 0x0b78 +#define RADEON_SW_SEMAPHORE 0x013c + +#define RADEON_TEST_DEBUG_CNTL 0x0120 +#define RADEON_TEST_DEBUG_CNTL__TEST_DEBUG_OUT_EN 0x00000001 + +#define RADEON_TEST_DEBUG_MUX 0x0124 +#define RADEON_TEST_DEBUG_OUT 0x012c +#define RADEON_TMDS_PLL_CNTL 0x02a8 +#define RADEON_TMDS_TRANSMITTER_CNTL 0x02a4 +# define RADEON_TMDS_TRANSMITTER_PLLEN 1 +# define RADEON_TMDS_TRANSMITTER_PLLRST 2 +#define RADEON_TRAIL_BRES_DEC 0x1614 +#define RADEON_TRAIL_BRES_ERR 0x160c +#define RADEON_TRAIL_BRES_INC 0x1610 +#define RADEON_TRAIL_X 0x1618 +#define RADEON_TRAIL_X_SUB 0x1620 + +#define RADEON_VCLK_ECP_CNTL 0x0008 /* PLL */ +# define RADEON_VCLK_SRC_SEL_MASK 0x03 +# define RADEON_VCLK_SRC_SEL_CPUCLK 0x00 +# define RADEON_VCLK_SRC_SEL_PSCANCLK 0x01 +# define RADEON_VCLK_SRC_SEL_BYTECLK 0x02 +# define RADEON_VCLK_SRC_SEL_PPLLCLK 0x03 +# define RADEON_PIXCLK_ALWAYS_ONb (1<<6) +# define RADEON_PIXCLK_DAC_ALWAYS_ONb (1<<7) +# define R300_DISP_DAC_PIXCLK_DAC_BLANK_OFF (1<<23) + +#define RADEON_VENDOR_ID 0x0f00 /* PCI */ +#define RADEON_VGA_DDA_CONFIG 0x02e8 +#define RADEON_VGA_DDA_ON_OFF 0x02ec +#define RADEON_VID_BUFFER_CONTROL 0x0900 +#define RADEON_VIDEOMUX_CNTL 0x0190 + +/* VIP bus */ +#define RADEON_VIPH_CH0_DATA 0x0c00 +#define RADEON_VIPH_CH1_DATA 0x0c04 +#define RADEON_VIPH_CH2_DATA 0x0c08 +#define RADEON_VIPH_CH3_DATA 0x0c0c +#define RADEON_VIPH_CH0_ADDR 0x0c10 +#define RADEON_VIPH_CH1_ADDR 0x0c14 +#define RADEON_VIPH_CH2_ADDR 0x0c18 +#define RADEON_VIPH_CH3_ADDR 0x0c1c +#define RADEON_VIPH_CH0_SBCNT 0x0c20 +#define RADEON_VIPH_CH1_SBCNT 0x0c24 +#define RADEON_VIPH_CH2_SBCNT 0x0c28 +#define RADEON_VIPH_CH3_SBCNT 0x0c2c +#define RADEON_VIPH_CH0_ABCNT 0x0c30 +#define RADEON_VIPH_CH1_ABCNT 0x0c34 +#define RADEON_VIPH_CH2_ABCNT 0x0c38 +#define RADEON_VIPH_CH3_ABCNT 0x0c3c +#define RADEON_VIPH_CONTROL 0x0c40 +# define RADEON_VIP_BUSY 0 +# define RADEON_VIP_IDLE 1 +# define RADEON_VIP_RESET 2 +# define RADEON_VIPH_EN (1 << 21) +#define RADEON_VIPH_DV_LAT 0x0c44 +#define RADEON_VIPH_BM_CHUNK 0x0c48 +#define RADEON_VIPH_DV_INT 0x0c4c +#define RADEON_VIPH_TIMEOUT_STAT 0x0c50 +#define RADEON_VIPH_TIMEOUT_STAT__VIPH_REG_STAT 0x00000010 +#define RADEON_VIPH_TIMEOUT_STAT__VIPH_REG_AK 0x00000010 +#define RADEON_VIPH_TIMEOUT_STAT__VIPH_REGR_DIS 0x01000000 + +#define RADEON_VIPH_REG_DATA 0x0084 +#define RADEON_VIPH_REG_ADDR 0x0080 + + +#define RADEON_WAIT_UNTIL 0x1720 +# define RADEON_WAIT_CRTC_PFLIP (1 << 0) +# define RADEON_WAIT_RE_CRTC_VLINE (1 << 1) +# define RADEON_WAIT_FE_CRTC_VLINE (1 << 2) +# define RADEON_WAIT_CRTC_VLINE (1 << 3) +# define RADEON_WAIT_DMA_VID_IDLE (1 << 8) +# define RADEON_WAIT_DMA_GUI_IDLE (1 << 9) +# define RADEON_WAIT_CMDFIFO (1 << 10) /* wait for CMDFIFO_ENTRIES */ +# define RADEON_WAIT_OV0_FLIP (1 << 11) +# define RADEON_WAIT_AGP_FLUSH (1 << 13) +# define RADEON_WAIT_2D_IDLE (1 << 14) +# define RADEON_WAIT_3D_IDLE (1 << 15) +# define RADEON_WAIT_2D_IDLECLEAN (1 << 16) +# define RADEON_WAIT_3D_IDLECLEAN (1 << 17) +# define RADEON_WAIT_HOST_IDLECLEAN (1 << 18) +# define RADEON_CMDFIFO_ENTRIES_SHIFT 10 +# define RADEON_CMDFIFO_ENTRIES_MASK 0x7f +# define RADEON_WAIT_VAP_IDLE (1 << 28) +# define RADEON_WAIT_BOTH_CRTC_PFLIP (1 << 30) +# define RADEON_ENG_DISPLAY_SELECT_CRTC0 (0 << 31) +# define RADEON_ENG_DISPLAY_SELECT_CRTC1 (1 << 31) + +#define RADEON_X_MPLL_REF_FB_DIV 0x000a /* PLL */ +#define RADEON_XCLK_CNTL 0x000d /* PLL */ +#define RADEON_XDLL_CNTL 0x000c /* PLL */ +#define RADEON_XPLL_CNTL 0x000b /* PLL */ + + + + /* Registers for 3D/TCL */ +#define RADEON_PP_BORDER_COLOR_0 0x1d40 +#define RADEON_PP_BORDER_COLOR_1 0x1d44 +#define RADEON_PP_BORDER_COLOR_2 0x1d48 +#define RADEON_PP_CNTL 0x1c38 +# define RADEON_STIPPLE_ENABLE (1 << 0) +# define RADEON_SCISSOR_ENABLE (1 << 1) +# define RADEON_PATTERN_ENABLE (1 << 2) +# define RADEON_SHADOW_ENABLE (1 << 3) +# define RADEON_TEX_ENABLE_MASK (0xf << 4) +# define RADEON_TEX_0_ENABLE (1 << 4) +# define RADEON_TEX_1_ENABLE (1 << 5) +# define RADEON_TEX_2_ENABLE (1 << 6) +# define RADEON_TEX_3_ENABLE (1 << 7) +# define RADEON_TEX_BLEND_ENABLE_MASK (0xf << 12) +# define RADEON_TEX_BLEND_0_ENABLE (1 << 12) +# define RADEON_TEX_BLEND_1_ENABLE (1 << 13) +# define RADEON_TEX_BLEND_2_ENABLE (1 << 14) +# define RADEON_TEX_BLEND_3_ENABLE (1 << 15) +# define RADEON_PLANAR_YUV_ENABLE (1 << 20) +# define RADEON_SPECULAR_ENABLE (1 << 21) +# define RADEON_FOG_ENABLE (1 << 22) +# define RADEON_ALPHA_TEST_ENABLE (1 << 23) +# define RADEON_ANTI_ALIAS_NONE (0 << 24) +# define RADEON_ANTI_ALIAS_LINE (1 << 24) +# define RADEON_ANTI_ALIAS_POLY (2 << 24) +# define RADEON_ANTI_ALIAS_LINE_POLY (3 << 24) +# define RADEON_BUMP_MAP_ENABLE (1 << 26) +# define RADEON_BUMPED_MAP_T0 (0 << 27) +# define RADEON_BUMPED_MAP_T1 (1 << 27) +# define RADEON_BUMPED_MAP_T2 (2 << 27) +# define RADEON_TEX_3D_ENABLE_0 (1 << 29) +# define RADEON_TEX_3D_ENABLE_1 (1 << 30) +# define RADEON_MC_ENABLE (1 << 31) +#define RADEON_PP_FOG_COLOR 0x1c18 +# define RADEON_FOG_COLOR_MASK 0x00ffffff +# define RADEON_FOG_VERTEX (0 << 24) +# define RADEON_FOG_TABLE (1 << 24) +# define RADEON_FOG_USE_DEPTH (0 << 25) +# define RADEON_FOG_USE_DIFFUSE_ALPHA (2 << 25) +# define RADEON_FOG_USE_SPEC_ALPHA (3 << 25) +#define RADEON_PP_LUM_MATRIX 0x1d00 +#define RADEON_PP_MISC 0x1c14 +# define RADEON_REF_ALPHA_MASK 0x000000ff +# define RADEON_ALPHA_TEST_FAIL (0 << 8) +# define RADEON_ALPHA_TEST_LESS (1 << 8) +# define RADEON_ALPHA_TEST_LEQUAL (2 << 8) +# define RADEON_ALPHA_TEST_EQUAL (3 << 8) +# define RADEON_ALPHA_TEST_GEQUAL (4 << 8) +# define RADEON_ALPHA_TEST_GREATER (5 << 8) +# define RADEON_ALPHA_TEST_NEQUAL (6 << 8) +# define RADEON_ALPHA_TEST_PASS (7 << 8) +# define RADEON_ALPHA_TEST_OP_MASK (7 << 8) +# define RADEON_CHROMA_FUNC_FAIL (0 << 16) +# define RADEON_CHROMA_FUNC_PASS (1 << 16) +# define RADEON_CHROMA_FUNC_NEQUAL (2 << 16) +# define RADEON_CHROMA_FUNC_EQUAL (3 << 16) +# define RADEON_CHROMA_KEY_NEAREST (0 << 18) +# define RADEON_CHROMA_KEY_ZERO (1 << 18) +# define RADEON_SHADOW_ID_AUTO_INC (1 << 20) +# define RADEON_SHADOW_FUNC_EQUAL (0 << 21) +# define RADEON_SHADOW_FUNC_NEQUAL (1 << 21) +# define RADEON_SHADOW_PASS_1 (0 << 22) +# define RADEON_SHADOW_PASS_2 (1 << 22) +# define RADEON_RIGHT_HAND_CUBE_D3D (0 << 24) +# define RADEON_RIGHT_HAND_CUBE_OGL (1 << 24) +#define RADEON_PP_ROT_MATRIX_0 0x1d58 +#define RADEON_PP_ROT_MATRIX_1 0x1d5c +#define RADEON_PP_TXFILTER_0 0x1c54 +#define RADEON_PP_TXFILTER_1 0x1c6c +#define RADEON_PP_TXFILTER_2 0x1c84 +# define RADEON_MAG_FILTER_NEAREST (0 << 0) +# define RADEON_MAG_FILTER_LINEAR (1 << 0) +# define RADEON_MAG_FILTER_MASK (1 << 0) +# define RADEON_MIN_FILTER_NEAREST (0 << 1) +# define RADEON_MIN_FILTER_LINEAR (1 << 1) +# define RADEON_MIN_FILTER_NEAREST_MIP_NEAREST (2 << 1) +# define RADEON_MIN_FILTER_NEAREST_MIP_LINEAR (3 << 1) +# define RADEON_MIN_FILTER_LINEAR_MIP_NEAREST (6 << 1) +# define RADEON_MIN_FILTER_LINEAR_MIP_LINEAR (7 << 1) +# define RADEON_MIN_FILTER_ANISO_NEAREST (8 << 1) +# define RADEON_MIN_FILTER_ANISO_LINEAR (9 << 1) +# define RADEON_MIN_FILTER_ANISO_NEAREST_MIP_NEAREST (10 << 1) +# define RADEON_MIN_FILTER_ANISO_NEAREST_MIP_LINEAR (11 << 1) +# define RADEON_MIN_FILTER_MASK (15 << 1) +# define RADEON_MAX_ANISO_1_TO_1 (0 << 5) +# define RADEON_MAX_ANISO_2_TO_1 (1 << 5) +# define RADEON_MAX_ANISO_4_TO_1 (2 << 5) +# define RADEON_MAX_ANISO_8_TO_1 (3 << 5) +# define RADEON_MAX_ANISO_16_TO_1 (4 << 5) +# define RADEON_MAX_ANISO_MASK (7 << 5) +# define RADEON_LOD_BIAS_MASK (0xff << 8) +# define RADEON_LOD_BIAS_SHIFT 8 +# define RADEON_MAX_MIP_LEVEL_MASK (0x0f << 16) +# define RADEON_MAX_MIP_LEVEL_SHIFT 16 +# define RADEON_YUV_TO_RGB (1 << 20) +# define RADEON_YUV_TEMPERATURE_COOL (0 << 21) +# define RADEON_YUV_TEMPERATURE_HOT (1 << 21) +# define RADEON_YUV_TEMPERATURE_MASK (1 << 21) +# define RADEON_WRAPEN_S (1 << 22) +# define RADEON_CLAMP_S_WRAP (0 << 23) +# define RADEON_CLAMP_S_MIRROR (1 << 23) +# define RADEON_CLAMP_S_CLAMP_LAST (2 << 23) +# define RADEON_CLAMP_S_MIRROR_CLAMP_LAST (3 << 23) +# define RADEON_CLAMP_S_CLAMP_BORDER (4 << 23) +# define RADEON_CLAMP_S_MIRROR_CLAMP_BORDER (5 << 23) +# define RADEON_CLAMP_S_CLAMP_GL (6 << 23) +# define RADEON_CLAMP_S_MIRROR_CLAMP_GL (7 << 23) +# define RADEON_CLAMP_S_MASK (7 << 23) +# define RADEON_WRAPEN_T (1 << 26) +# define RADEON_CLAMP_T_WRAP (0 << 27) +# define RADEON_CLAMP_T_MIRROR (1 << 27) +# define RADEON_CLAMP_T_CLAMP_LAST (2 << 27) +# define RADEON_CLAMP_T_MIRROR_CLAMP_LAST (3 << 27) +# define RADEON_CLAMP_T_CLAMP_BORDER (4 << 27) +# define RADEON_CLAMP_T_MIRROR_CLAMP_BORDER (5 << 27) +# define RADEON_CLAMP_T_CLAMP_GL (6 << 27) +# define RADEON_CLAMP_T_MIRROR_CLAMP_GL (7 << 27) +# define RADEON_CLAMP_T_MASK (7 << 27) +# define RADEON_BORDER_MODE_OGL (0 << 31) +# define RADEON_BORDER_MODE_D3D (1 << 31) +#define RADEON_PP_TXFORMAT_0 0x1c58 +#define RADEON_PP_TXFORMAT_1 0x1c70 +#define RADEON_PP_TXFORMAT_2 0x1c88 +# define RADEON_TXFORMAT_I8 (0 << 0) +# define RADEON_TXFORMAT_AI88 (1 << 0) +# define RADEON_TXFORMAT_RGB332 (2 << 0) +# define RADEON_TXFORMAT_ARGB1555 (3 << 0) +# define RADEON_TXFORMAT_RGB565 (4 << 0) +# define RADEON_TXFORMAT_ARGB4444 (5 << 0) +# define RADEON_TXFORMAT_ARGB8888 (6 << 0) +# define RADEON_TXFORMAT_RGBA8888 (7 << 0) +# define RADEON_TXFORMAT_Y8 (8 << 0) +# define RADEON_TXFORMAT_VYUY422 (10 << 0) +# define RADEON_TXFORMAT_YVYU422 (11 << 0) +# define RADEON_TXFORMAT_DXT1 (12 << 0) +# define RADEON_TXFORMAT_DXT23 (14 << 0) +# define RADEON_TXFORMAT_DXT45 (15 << 0) +# define RADEON_TXFORMAT_FORMAT_MASK (31 << 0) +# define RADEON_TXFORMAT_FORMAT_SHIFT 0 +# define RADEON_TXFORMAT_APPLE_YUV_MODE (1 << 5) +# define RADEON_TXFORMAT_ALPHA_IN_MAP (1 << 6) +# define RADEON_TXFORMAT_NON_POWER2 (1 << 7) +# define RADEON_TXFORMAT_WIDTH_MASK (15 << 8) +# define RADEON_TXFORMAT_WIDTH_SHIFT 8 +# define RADEON_TXFORMAT_HEIGHT_MASK (15 << 12) +# define RADEON_TXFORMAT_HEIGHT_SHIFT 12 +# define RADEON_TXFORMAT_F5_WIDTH_MASK (15 << 16) +# define RADEON_TXFORMAT_F5_WIDTH_SHIFT 16 +# define RADEON_TXFORMAT_F5_HEIGHT_MASK (15 << 20) +# define RADEON_TXFORMAT_F5_HEIGHT_SHIFT 20 +# define RADEON_TXFORMAT_ST_ROUTE_STQ0 (0 << 24) +# define RADEON_TXFORMAT_ST_ROUTE_MASK (3 << 24) +# define RADEON_TXFORMAT_ST_ROUTE_STQ1 (1 << 24) +# define RADEON_TXFORMAT_ST_ROUTE_STQ2 (2 << 24) +# define RADEON_TXFORMAT_ENDIAN_NO_SWAP (0 << 26) +# define RADEON_TXFORMAT_ENDIAN_16BPP_SWAP (1 << 26) +# define RADEON_TXFORMAT_ENDIAN_32BPP_SWAP (2 << 26) +# define RADEON_TXFORMAT_ENDIAN_HALFDW_SWAP (3 << 26) +# define RADEON_TXFORMAT_ALPHA_MASK_ENABLE (1 << 28) +# define RADEON_TXFORMAT_CHROMA_KEY_ENABLE (1 << 29) +# define RADEON_TXFORMAT_CUBIC_MAP_ENABLE (1 << 30) +# define RADEON_TXFORMAT_PERSPECTIVE_ENABLE (1 << 31) +#define RADEON_PP_CUBIC_FACES_0 0x1d24 +#define RADEON_PP_CUBIC_FACES_1 0x1d28 +#define RADEON_PP_CUBIC_FACES_2 0x1d2c +# define RADEON_FACE_WIDTH_1_SHIFT 0 +# define RADEON_FACE_HEIGHT_1_SHIFT 4 +# define RADEON_FACE_WIDTH_1_MASK (0xf << 0) +# define RADEON_FACE_HEIGHT_1_MASK (0xf << 4) +# define RADEON_FACE_WIDTH_2_SHIFT 8 +# define RADEON_FACE_HEIGHT_2_SHIFT 12 +# define RADEON_FACE_WIDTH_2_MASK (0xf << 8) +# define RADEON_FACE_HEIGHT_2_MASK (0xf << 12) +# define RADEON_FACE_WIDTH_3_SHIFT 16 +# define RADEON_FACE_HEIGHT_3_SHIFT 20 +# define RADEON_FACE_WIDTH_3_MASK (0xf << 16) +# define RADEON_FACE_HEIGHT_3_MASK (0xf << 20) +# define RADEON_FACE_WIDTH_4_SHIFT 24 +# define RADEON_FACE_HEIGHT_4_SHIFT 28 +# define RADEON_FACE_WIDTH_4_MASK (0xf << 24) +# define RADEON_FACE_HEIGHT_4_MASK (0xf << 28) + +#define RADEON_PP_TXOFFSET_0 0x1c5c +#define RADEON_PP_TXOFFSET_1 0x1c74 +#define RADEON_PP_TXOFFSET_2 0x1c8c +# define RADEON_TXO_ENDIAN_NO_SWAP (0 << 0) +# define RADEON_TXO_ENDIAN_BYTE_SWAP (1 << 0) +# define RADEON_TXO_ENDIAN_WORD_SWAP (2 << 0) +# define RADEON_TXO_ENDIAN_HALFDW_SWAP (3 << 0) +# define RADEON_TXO_MACRO_LINEAR (0 << 2) +# define RADEON_TXO_MACRO_TILE (1 << 2) +# define RADEON_TXO_MICRO_LINEAR (0 << 3) +# define RADEON_TXO_MICRO_TILE_X2 (1 << 3) +# define RADEON_TXO_MICRO_TILE_OPT (2 << 3) +# define RADEON_TXO_OFFSET_MASK 0xffffffe0 +# define RADEON_TXO_OFFSET_SHIFT 5 + +#define RADEON_PP_CUBIC_OFFSET_T0_0 0x1dd0 /* bits [31:5] */ +#define RADEON_PP_CUBIC_OFFSET_T0_1 0x1dd4 +#define RADEON_PP_CUBIC_OFFSET_T0_2 0x1dd8 +#define RADEON_PP_CUBIC_OFFSET_T0_3 0x1ddc +#define RADEON_PP_CUBIC_OFFSET_T0_4 0x1de0 +#define RADEON_PP_CUBIC_OFFSET_T1_0 0x1e00 +#define RADEON_PP_CUBIC_OFFSET_T1_1 0x1e04 +#define RADEON_PP_CUBIC_OFFSET_T1_2 0x1e08 +#define RADEON_PP_CUBIC_OFFSET_T1_3 0x1e0c +#define RADEON_PP_CUBIC_OFFSET_T1_4 0x1e10 +#define RADEON_PP_CUBIC_OFFSET_T2_0 0x1e14 +#define RADEON_PP_CUBIC_OFFSET_T2_1 0x1e18 +#define RADEON_PP_CUBIC_OFFSET_T2_2 0x1e1c +#define RADEON_PP_CUBIC_OFFSET_T2_3 0x1e20 +#define RADEON_PP_CUBIC_OFFSET_T2_4 0x1e24 + +#define RADEON_PP_TEX_SIZE_0 0x1d04 /* NPOT */ +#define RADEON_PP_TEX_SIZE_1 0x1d0c +#define RADEON_PP_TEX_SIZE_2 0x1d14 +# define RADEON_TEX_USIZE_MASK (0x7ff << 0) +# define RADEON_TEX_USIZE_SHIFT 0 +# define RADEON_TEX_VSIZE_MASK (0x7ff << 16) +# define RADEON_TEX_VSIZE_SHIFT 16 +# define RADEON_SIGNED_RGB_MASK (1 << 30) +# define RADEON_SIGNED_RGB_SHIFT 30 +# define RADEON_SIGNED_ALPHA_MASK (1 << 31) +# define RADEON_SIGNED_ALPHA_SHIFT 31 +#define RADEON_PP_TEX_PITCH_0 0x1d08 /* NPOT */ +#define RADEON_PP_TEX_PITCH_1 0x1d10 /* NPOT */ +#define RADEON_PP_TEX_PITCH_2 0x1d18 /* NPOT */ +/* note: bits 13-5: 32 byte aligned stride of texture map */ + +#define RADEON_PP_TXCBLEND_0 0x1c60 +#define RADEON_PP_TXCBLEND_1 0x1c78 +#define RADEON_PP_TXCBLEND_2 0x1c90 +# define RADEON_COLOR_ARG_A_SHIFT 0 +# define RADEON_COLOR_ARG_A_MASK (0x1f << 0) +# define RADEON_COLOR_ARG_A_ZERO (0 << 0) +# define RADEON_COLOR_ARG_A_CURRENT_COLOR (2 << 0) +# define RADEON_COLOR_ARG_A_CURRENT_ALPHA (3 << 0) +# define RADEON_COLOR_ARG_A_DIFFUSE_COLOR (4 << 0) +# define RADEON_COLOR_ARG_A_DIFFUSE_ALPHA (5 << 0) +# define RADEON_COLOR_ARG_A_SPECULAR_COLOR (6 << 0) +# define RADEON_COLOR_ARG_A_SPECULAR_ALPHA (7 << 0) +# define RADEON_COLOR_ARG_A_TFACTOR_COLOR (8 << 0) +# define RADEON_COLOR_ARG_A_TFACTOR_ALPHA (9 << 0) +# define RADEON_COLOR_ARG_A_T0_COLOR (10 << 0) +# define RADEON_COLOR_ARG_A_T0_ALPHA (11 << 0) +# define RADEON_COLOR_ARG_A_T1_COLOR (12 << 0) +# define RADEON_COLOR_ARG_A_T1_ALPHA (13 << 0) +# define RADEON_COLOR_ARG_A_T2_COLOR (14 << 0) +# define RADEON_COLOR_ARG_A_T2_ALPHA (15 << 0) +# define RADEON_COLOR_ARG_A_T3_COLOR (16 << 0) +# define RADEON_COLOR_ARG_A_T3_ALPHA (17 << 0) +# define RADEON_COLOR_ARG_B_SHIFT 5 +# define RADEON_COLOR_ARG_B_MASK (0x1f << 5) +# define RADEON_COLOR_ARG_B_ZERO (0 << 5) +# define RADEON_COLOR_ARG_B_CURRENT_COLOR (2 << 5) +# define RADEON_COLOR_ARG_B_CURRENT_ALPHA (3 << 5) +# define RADEON_COLOR_ARG_B_DIFFUSE_COLOR (4 << 5) +# define RADEON_COLOR_ARG_B_DIFFUSE_ALPHA (5 << 5) +# define RADEON_COLOR_ARG_B_SPECULAR_COLOR (6 << 5) +# define RADEON_COLOR_ARG_B_SPECULAR_ALPHA (7 << 5) +# define RADEON_COLOR_ARG_B_TFACTOR_COLOR (8 << 5) +# define RADEON_COLOR_ARG_B_TFACTOR_ALPHA (9 << 5) +# define RADEON_COLOR_ARG_B_T0_COLOR (10 << 5) +# define RADEON_COLOR_ARG_B_T0_ALPHA (11 << 5) +# define RADEON_COLOR_ARG_B_T1_COLOR (12 << 5) +# define RADEON_COLOR_ARG_B_T1_ALPHA (13 << 5) +# define RADEON_COLOR_ARG_B_T2_COLOR (14 << 5) +# define RADEON_COLOR_ARG_B_T2_ALPHA (15 << 5) +# define RADEON_COLOR_ARG_B_T3_COLOR (16 << 5) +# define RADEON_COLOR_ARG_B_T3_ALPHA (17 << 5) +# define RADEON_COLOR_ARG_C_SHIFT 10 +# define RADEON_COLOR_ARG_C_MASK (0x1f << 10) +# define RADEON_COLOR_ARG_C_ZERO (0 << 10) +# define RADEON_COLOR_ARG_C_CURRENT_COLOR (2 << 10) +# define RADEON_COLOR_ARG_C_CURRENT_ALPHA (3 << 10) +# define RADEON_COLOR_ARG_C_DIFFUSE_COLOR (4 << 10) +# define RADEON_COLOR_ARG_C_DIFFUSE_ALPHA (5 << 10) +# define RADEON_COLOR_ARG_C_SPECULAR_COLOR (6 << 10) +# define RADEON_COLOR_ARG_C_SPECULAR_ALPHA (7 << 10) +# define RADEON_COLOR_ARG_C_TFACTOR_COLOR (8 << 10) +# define RADEON_COLOR_ARG_C_TFACTOR_ALPHA (9 << 10) +# define RADEON_COLOR_ARG_C_T0_COLOR (10 << 10) +# define RADEON_COLOR_ARG_C_T0_ALPHA (11 << 10) +# define RADEON_COLOR_ARG_C_T1_COLOR (12 << 10) +# define RADEON_COLOR_ARG_C_T1_ALPHA (13 << 10) +# define RADEON_COLOR_ARG_C_T2_COLOR (14 << 10) +# define RADEON_COLOR_ARG_C_T2_ALPHA (15 << 10) +# define RADEON_COLOR_ARG_C_T3_COLOR (16 << 10) +# define RADEON_COLOR_ARG_C_T3_ALPHA (17 << 10) +# define RADEON_COMP_ARG_A (1 << 15) +# define RADEON_COMP_ARG_A_SHIFT 15 +# define RADEON_COMP_ARG_B (1 << 16) +# define RADEON_COMP_ARG_B_SHIFT 16 +# define RADEON_COMP_ARG_C (1 << 17) +# define RADEON_COMP_ARG_C_SHIFT 17 +# define RADEON_BLEND_CTL_MASK (7 << 18) +# define RADEON_BLEND_CTL_ADD (0 << 18) +# define RADEON_BLEND_CTL_SUBTRACT (1 << 18) +# define RADEON_BLEND_CTL_ADDSIGNED (2 << 18) +# define RADEON_BLEND_CTL_BLEND (3 << 18) +# define RADEON_BLEND_CTL_DOT3 (4 << 18) +# define RADEON_SCALE_SHIFT 21 +# define RADEON_SCALE_MASK (3 << 21) +# define RADEON_SCALE_1X (0 << 21) +# define RADEON_SCALE_2X (1 << 21) +# define RADEON_SCALE_4X (2 << 21) +# define RADEON_CLAMP_TX (1 << 23) +# define RADEON_T0_EQ_TCUR (1 << 24) +# define RADEON_T1_EQ_TCUR (1 << 25) +# define RADEON_T2_EQ_TCUR (1 << 26) +# define RADEON_T3_EQ_TCUR (1 << 27) +# define RADEON_COLOR_ARG_MASK 0x1f +# define RADEON_COMP_ARG_SHIFT 15 +#define RADEON_PP_TXABLEND_0 0x1c64 +#define RADEON_PP_TXABLEND_1 0x1c7c +#define RADEON_PP_TXABLEND_2 0x1c94 +# define RADEON_ALPHA_ARG_A_SHIFT 0 +# define RADEON_ALPHA_ARG_A_MASK (0xf << 0) +# define RADEON_ALPHA_ARG_A_ZERO (0 << 0) +# define RADEON_ALPHA_ARG_A_CURRENT_ALPHA (1 << 0) +# define RADEON_ALPHA_ARG_A_DIFFUSE_ALPHA (2 << 0) +# define RADEON_ALPHA_ARG_A_SPECULAR_ALPHA (3 << 0) +# define RADEON_ALPHA_ARG_A_TFACTOR_ALPHA (4 << 0) +# define RADEON_ALPHA_ARG_A_T0_ALPHA (5 << 0) +# define RADEON_ALPHA_ARG_A_T1_ALPHA (6 << 0) +# define RADEON_ALPHA_ARG_A_T2_ALPHA (7 << 0) +# define RADEON_ALPHA_ARG_A_T3_ALPHA (8 << 0) +# define RADEON_ALPHA_ARG_B_SHIFT 4 +# define RADEON_ALPHA_ARG_B_MASK (0xf << 4) +# define RADEON_ALPHA_ARG_B_ZERO (0 << 4) +# define RADEON_ALPHA_ARG_B_CURRENT_ALPHA (1 << 4) +# define RADEON_ALPHA_ARG_B_DIFFUSE_ALPHA (2 << 4) +# define RADEON_ALPHA_ARG_B_SPECULAR_ALPHA (3 << 4) +# define RADEON_ALPHA_ARG_B_TFACTOR_ALPHA (4 << 4) +# define RADEON_ALPHA_ARG_B_T0_ALPHA (5 << 4) +# define RADEON_ALPHA_ARG_B_T1_ALPHA (6 << 4) +# define RADEON_ALPHA_ARG_B_T2_ALPHA (7 << 4) +# define RADEON_ALPHA_ARG_B_T3_ALPHA (8 << 4) +# define RADEON_ALPHA_ARG_C_SHIFT 8 +# define RADEON_ALPHA_ARG_C_MASK (0xf << 8) +# define RADEON_ALPHA_ARG_C_ZERO (0 << 8) +# define RADEON_ALPHA_ARG_C_CURRENT_ALPHA (1 << 8) +# define RADEON_ALPHA_ARG_C_DIFFUSE_ALPHA (2 << 8) +# define RADEON_ALPHA_ARG_C_SPECULAR_ALPHA (3 << 8) +# define RADEON_ALPHA_ARG_C_TFACTOR_ALPHA (4 << 8) +# define RADEON_ALPHA_ARG_C_T0_ALPHA (5 << 8) +# define RADEON_ALPHA_ARG_C_T1_ALPHA (6 << 8) +# define RADEON_ALPHA_ARG_C_T2_ALPHA (7 << 8) +# define RADEON_ALPHA_ARG_C_T3_ALPHA (8 << 8) +# define RADEON_DOT_ALPHA_DONT_REPLICATE (1 << 9) +# define RADEON_ALPHA_ARG_MASK 0xf + +#define RADEON_PP_TFACTOR_0 0x1c68 +#define RADEON_PP_TFACTOR_1 0x1c80 +#define RADEON_PP_TFACTOR_2 0x1c98 + +#define RADEON_RB3D_BLENDCNTL 0x1c20 +# define RADEON_COMB_FCN_MASK (3 << 12) +# define RADEON_COMB_FCN_ADD_CLAMP (0 << 12) +# define RADEON_COMB_FCN_ADD_NOCLAMP (1 << 12) +# define RADEON_COMB_FCN_SUB_CLAMP (2 << 12) +# define RADEON_COMB_FCN_SUB_NOCLAMP (3 << 12) +# define RADEON_SRC_BLEND_GL_ZERO (32 << 16) +# define RADEON_SRC_BLEND_GL_ONE (33 << 16) +# define RADEON_SRC_BLEND_GL_SRC_COLOR (34 << 16) +# define RADEON_SRC_BLEND_GL_ONE_MINUS_SRC_COLOR (35 << 16) +# define RADEON_SRC_BLEND_GL_DST_COLOR (36 << 16) +# define RADEON_SRC_BLEND_GL_ONE_MINUS_DST_COLOR (37 << 16) +# define RADEON_SRC_BLEND_GL_SRC_ALPHA (38 << 16) +# define RADEON_SRC_BLEND_GL_ONE_MINUS_SRC_ALPHA (39 << 16) +# define RADEON_SRC_BLEND_GL_DST_ALPHA (40 << 16) +# define RADEON_SRC_BLEND_GL_ONE_MINUS_DST_ALPHA (41 << 16) +# define RADEON_SRC_BLEND_GL_SRC_ALPHA_SATURATE (42 << 16) +# define RADEON_SRC_BLEND_MASK (63 << 16) +# define RADEON_DST_BLEND_GL_ZERO (32 << 24) +# define RADEON_DST_BLEND_GL_ONE (33 << 24) +# define RADEON_DST_BLEND_GL_SRC_COLOR (34 << 24) +# define RADEON_DST_BLEND_GL_ONE_MINUS_SRC_COLOR (35 << 24) +# define RADEON_DST_BLEND_GL_DST_COLOR (36 << 24) +# define RADEON_DST_BLEND_GL_ONE_MINUS_DST_COLOR (37 << 24) +# define RADEON_DST_BLEND_GL_SRC_ALPHA (38 << 24) +# define RADEON_DST_BLEND_GL_ONE_MINUS_SRC_ALPHA (39 << 24) +# define RADEON_DST_BLEND_GL_DST_ALPHA (40 << 24) +# define RADEON_DST_BLEND_GL_ONE_MINUS_DST_ALPHA (41 << 24) +# define RADEON_DST_BLEND_MASK (63 << 24) +#define RADEON_RB3D_CNTL 0x1c3c +# define RADEON_ALPHA_BLEND_ENABLE (1 << 0) +# define RADEON_PLANE_MASK_ENABLE (1 << 1) +# define RADEON_DITHER_ENABLE (1 << 2) +# define RADEON_ROUND_ENABLE (1 << 3) +# define RADEON_SCALE_DITHER_ENABLE (1 << 4) +# define RADEON_DITHER_INIT (1 << 5) +# define RADEON_ROP_ENABLE (1 << 6) +# define RADEON_STENCIL_ENABLE (1 << 7) +# define RADEON_Z_ENABLE (1 << 8) +# define RADEON_DEPTH_XZ_OFFEST_ENABLE (1 << 9) +# define RADEON_RB3D_COLOR_FORMAT_SHIFT 10 + +# define RADEON_COLOR_FORMAT_ARGB1555 3 +# define RADEON_COLOR_FORMAT_RGB565 4 +# define RADEON_COLOR_FORMAT_ARGB8888 6 +# define RADEON_COLOR_FORMAT_RGB332 7 +# define RADEON_COLOR_FORMAT_Y8 8 +# define RADEON_COLOR_FORMAT_RGB8 9 +# define RADEON_COLOR_FORMAT_YUV422_VYUY 11 +# define RADEON_COLOR_FORMAT_YUV422_YVYU 12 +# define RADEON_COLOR_FORMAT_aYUV444 14 +# define RADEON_COLOR_FORMAT_ARGB4444 15 + +# define RADEON_CLRCMP_FLIP_ENABLE (1 << 14) +#define RADEON_RB3D_COLOROFFSET 0x1c40 +# define RADEON_COLOROFFSET_MASK 0xfffffff0 +#define RADEON_RB3D_COLORPITCH 0x1c48 +# define RADEON_COLORPITCH_MASK 0x000001ff8 +# define RADEON_COLOR_TILE_ENABLE (1 << 16) +# define RADEON_COLOR_MICROTILE_ENABLE (1 << 17) +# define RADEON_COLOR_ENDIAN_NO_SWAP (0 << 18) +# define RADEON_COLOR_ENDIAN_WORD_SWAP (1 << 18) +# define RADEON_COLOR_ENDIAN_DWORD_SWAP (2 << 18) +#define RADEON_RB3D_DEPTHOFFSET 0x1c24 +#define RADEON_RB3D_DEPTHPITCH 0x1c28 +# define RADEON_DEPTHPITCH_MASK 0x00001ff8 +# define RADEON_DEPTH_ENDIAN_NO_SWAP (0 << 18) +# define RADEON_DEPTH_ENDIAN_WORD_SWAP (1 << 18) +# define RADEON_DEPTH_ENDIAN_DWORD_SWAP (2 << 18) +#define RADEON_RB3D_PLANEMASK 0x1d84 +#define RADEON_RB3D_ROPCNTL 0x1d80 +# define RADEON_ROP_MASK (15 << 8) +# define RADEON_ROP_CLEAR (0 << 8) +# define RADEON_ROP_NOR (1 << 8) +# define RADEON_ROP_AND_INVERTED (2 << 8) +# define RADEON_ROP_COPY_INVERTED (3 << 8) +# define RADEON_ROP_AND_REVERSE (4 << 8) +# define RADEON_ROP_INVERT (5 << 8) +# define RADEON_ROP_XOR (6 << 8) +# define RADEON_ROP_NAND (7 << 8) +# define RADEON_ROP_AND (8 << 8) +# define RADEON_ROP_EQUIV (9 << 8) +# define RADEON_ROP_NOOP (10 << 8) +# define RADEON_ROP_OR_INVERTED (11 << 8) +# define RADEON_ROP_COPY (12 << 8) +# define RADEON_ROP_OR_REVERSE (13 << 8) +# define RADEON_ROP_OR (14 << 8) +# define RADEON_ROP_SET (15 << 8) +#define RADEON_RB3D_STENCILREFMASK 0x1d7c +# define RADEON_STENCIL_REF_SHIFT 0 +# define RADEON_STENCIL_REF_MASK (0xff << 0) +# define RADEON_STENCIL_MASK_SHIFT 16 +# define RADEON_STENCIL_VALUE_MASK (0xff << 16) +# define RADEON_STENCIL_WRITEMASK_SHIFT 24 +# define RADEON_STENCIL_WRITE_MASK (0xff << 24) +#define RADEON_RB3D_ZSTENCILCNTL 0x1c2c +# define RADEON_DEPTH_FORMAT_MASK (0xf << 0) +# define RADEON_DEPTH_FORMAT_16BIT_INT_Z (0 << 0) +# define RADEON_DEPTH_FORMAT_24BIT_INT_Z (2 << 0) +# define RADEON_DEPTH_FORMAT_24BIT_FLOAT_Z (3 << 0) +# define RADEON_DEPTH_FORMAT_32BIT_INT_Z (4 << 0) +# define RADEON_DEPTH_FORMAT_32BIT_FLOAT_Z (5 << 0) +# define RADEON_DEPTH_FORMAT_16BIT_FLOAT_W (7 << 0) +# define RADEON_DEPTH_FORMAT_24BIT_FLOAT_W (9 << 0) +# define RADEON_DEPTH_FORMAT_32BIT_FLOAT_W (11 << 0) +# define RADEON_Z_TEST_NEVER (0 << 4) +# define RADEON_Z_TEST_LESS (1 << 4) +# define RADEON_Z_TEST_LEQUAL (2 << 4) +# define RADEON_Z_TEST_EQUAL (3 << 4) +# define RADEON_Z_TEST_GEQUAL (4 << 4) +# define RADEON_Z_TEST_GREATER (5 << 4) +# define RADEON_Z_TEST_NEQUAL (6 << 4) +# define RADEON_Z_TEST_ALWAYS (7 << 4) +# define RADEON_Z_TEST_MASK (7 << 4) +# define RADEON_STENCIL_TEST_NEVER (0 << 12) +# define RADEON_STENCIL_TEST_LESS (1 << 12) +# define RADEON_STENCIL_TEST_LEQUAL (2 << 12) +# define RADEON_STENCIL_TEST_EQUAL (3 << 12) +# define RADEON_STENCIL_TEST_GEQUAL (4 << 12) +# define RADEON_STENCIL_TEST_GREATER (5 << 12) +# define RADEON_STENCIL_TEST_NEQUAL (6 << 12) +# define RADEON_STENCIL_TEST_ALWAYS (7 << 12) +# define RADEON_STENCIL_TEST_MASK (0x7 << 12) +# define RADEON_STENCIL_FAIL_KEEP (0 << 16) +# define RADEON_STENCIL_FAIL_ZERO (1 << 16) +# define RADEON_STENCIL_FAIL_REPLACE (2 << 16) +# define RADEON_STENCIL_FAIL_INC (3 << 16) +# define RADEON_STENCIL_FAIL_DEC (4 << 16) +# define RADEON_STENCIL_FAIL_INVERT (5 << 16) +# define RADEON_STENCIL_FAIL_MASK (0x7 << 16) +# define RADEON_STENCIL_ZPASS_KEEP (0 << 20) +# define RADEON_STENCIL_ZPASS_ZERO (1 << 20) +# define RADEON_STENCIL_ZPASS_REPLACE (2 << 20) +# define RADEON_STENCIL_ZPASS_INC (3 << 20) +# define RADEON_STENCIL_ZPASS_DEC (4 << 20) +# define RADEON_STENCIL_ZPASS_INVERT (5 << 20) +# define RADEON_STENCIL_ZPASS_MASK (0x7 << 20) +# define RADEON_STENCIL_ZFAIL_KEEP (0 << 24) +# define RADEON_STENCIL_ZFAIL_ZERO (1 << 24) +# define RADEON_STENCIL_ZFAIL_REPLACE (2 << 24) +# define RADEON_STENCIL_ZFAIL_INC (3 << 24) +# define RADEON_STENCIL_ZFAIL_DEC (4 << 24) +# define RADEON_STENCIL_ZFAIL_INVERT (5 << 24) +# define RADEON_STENCIL_ZFAIL_MASK (0x7 << 24) +# define RADEON_Z_COMPRESSION_ENABLE (1 << 28) +# define RADEON_FORCE_Z_DIRTY (1 << 29) +# define RADEON_Z_WRITE_ENABLE (1 << 30) +#define RADEON_RE_LINE_PATTERN 0x1cd0 +# define RADEON_LINE_PATTERN_MASK 0x0000ffff +# define RADEON_LINE_REPEAT_COUNT_SHIFT 16 +# define RADEON_LINE_PATTERN_START_SHIFT 24 +# define RADEON_LINE_PATTERN_LITTLE_BIT_ORDER (0 << 28) +# define RADEON_LINE_PATTERN_BIG_BIT_ORDER (1 << 28) +# define RADEON_LINE_PATTERN_AUTO_RESET (1 << 29) +#define RADEON_RE_LINE_STATE 0x1cd4 +# define RADEON_LINE_CURRENT_PTR_SHIFT 0 +# define RADEON_LINE_CURRENT_COUNT_SHIFT 8 +#define RADEON_RE_MISC 0x26c4 +# define RADEON_STIPPLE_COORD_MASK 0x1f +# define RADEON_STIPPLE_X_OFFSET_SHIFT 0 +# define RADEON_STIPPLE_X_OFFSET_MASK (0x1f << 0) +# define RADEON_STIPPLE_Y_OFFSET_SHIFT 8 +# define RADEON_STIPPLE_Y_OFFSET_MASK (0x1f << 8) +# define RADEON_STIPPLE_LITTLE_BIT_ORDER (0 << 16) +# define RADEON_STIPPLE_BIG_BIT_ORDER (1 << 16) +#define RADEON_RE_SOLID_COLOR 0x1c1c +#define RADEON_RE_TOP_LEFT 0x26c0 +# define RADEON_RE_LEFT_SHIFT 0 +# define RADEON_RE_TOP_SHIFT 16 +#define RADEON_RE_WIDTH_HEIGHT 0x1c44 +# define RADEON_RE_WIDTH_SHIFT 0 +# define RADEON_RE_HEIGHT_SHIFT 16 + +#define RADEON_SE_CNTL 0x1c4c +# define RADEON_FFACE_CULL_CW (0 << 0) +# define RADEON_FFACE_CULL_CCW (1 << 0) +# define RADEON_FFACE_CULL_DIR_MASK (1 << 0) +# define RADEON_BFACE_CULL (0 << 1) +# define RADEON_BFACE_SOLID (3 << 1) +# define RADEON_FFACE_CULL (0 << 3) +# define RADEON_FFACE_SOLID (3 << 3) +# define RADEON_FFACE_CULL_MASK (3 << 3) +# define RADEON_BADVTX_CULL_DISABLE (1 << 5) +# define RADEON_FLAT_SHADE_VTX_0 (0 << 6) +# define RADEON_FLAT_SHADE_VTX_1 (1 << 6) +# define RADEON_FLAT_SHADE_VTX_2 (2 << 6) +# define RADEON_FLAT_SHADE_VTX_LAST (3 << 6) +# define RADEON_DIFFUSE_SHADE_SOLID (0 << 8) +# define RADEON_DIFFUSE_SHADE_FLAT (1 << 8) +# define RADEON_DIFFUSE_SHADE_GOURAUD (2 << 8) +# define RADEON_DIFFUSE_SHADE_MASK (3 << 8) +# define RADEON_ALPHA_SHADE_SOLID (0 << 10) +# define RADEON_ALPHA_SHADE_FLAT (1 << 10) +# define RADEON_ALPHA_SHADE_GOURAUD (2 << 10) +# define RADEON_ALPHA_SHADE_MASK (3 << 10) +# define RADEON_SPECULAR_SHADE_SOLID (0 << 12) +# define RADEON_SPECULAR_SHADE_FLAT (1 << 12) +# define RADEON_SPECULAR_SHADE_GOURAUD (2 << 12) +# define RADEON_SPECULAR_SHADE_MASK (3 << 12) +# define RADEON_FOG_SHADE_SOLID (0 << 14) +# define RADEON_FOG_SHADE_FLAT (1 << 14) +# define RADEON_FOG_SHADE_GOURAUD (2 << 14) +# define RADEON_FOG_SHADE_MASK (3 << 14) +# define RADEON_ZBIAS_ENABLE_POINT (1 << 16) +# define RADEON_ZBIAS_ENABLE_LINE (1 << 17) +# define RADEON_ZBIAS_ENABLE_TRI (1 << 18) +# define RADEON_WIDELINE_ENABLE (1 << 20) +# define RADEON_VPORT_XY_XFORM_ENABLE (1 << 24) +# define RADEON_VPORT_Z_XFORM_ENABLE (1 << 25) +# define RADEON_VTX_PIX_CENTER_D3D (0 << 27) +# define RADEON_VTX_PIX_CENTER_OGL (1 << 27) +# define RADEON_ROUND_MODE_TRUNC (0 << 28) +# define RADEON_ROUND_MODE_ROUND (1 << 28) +# define RADEON_ROUND_MODE_ROUND_EVEN (2 << 28) +# define RADEON_ROUND_MODE_ROUND_ODD (3 << 28) +# define RADEON_ROUND_PREC_16TH_PIX (0 << 30) +# define RADEON_ROUND_PREC_8TH_PIX (1 << 30) +# define RADEON_ROUND_PREC_4TH_PIX (2 << 30) +# define RADEON_ROUND_PREC_HALF_PIX (3 << 30) +#define R200_RE_CNTL 0x1c50 +# define R200_STIPPLE_ENABLE 0x1 +# define R200_SCISSOR_ENABLE 0x2 +# define R200_PATTERN_ENABLE 0x4 +# define R200_PERSPECTIVE_ENABLE 0x8 +# define R200_POINT_SMOOTH 0x20 +# define R200_VTX_STQ0_D3D 0x00010000 +# define R200_VTX_STQ1_D3D 0x00040000 +# define R200_VTX_STQ2_D3D 0x00100000 +# define R200_VTX_STQ3_D3D 0x00400000 +# define R200_VTX_STQ4_D3D 0x01000000 +# define R200_VTX_STQ5_D3D 0x04000000 +#define RADEON_SE_CNTL_STATUS 0x2140 +# define RADEON_VC_NO_SWAP (0 << 0) +# define RADEON_VC_16BIT_SWAP (1 << 0) +# define RADEON_VC_32BIT_SWAP (2 << 0) +# define RADEON_VC_HALF_DWORD_SWAP (3 << 0) +# define RADEON_TCL_BYPASS (1 << 8) +#define RADEON_SE_COORD_FMT 0x1c50 +# define RADEON_VTX_XY_PRE_MULT_1_OVER_W0 (1 << 0) +# define RADEON_VTX_Z_PRE_MULT_1_OVER_W0 (1 << 1) +# define RADEON_VTX_ST0_NONPARAMETRIC (1 << 8) +# define RADEON_VTX_ST1_NONPARAMETRIC (1 << 9) +# define RADEON_VTX_ST2_NONPARAMETRIC (1 << 10) +# define RADEON_VTX_ST3_NONPARAMETRIC (1 << 11) +# define RADEON_VTX_W0_NORMALIZE (1 << 12) +# define RADEON_VTX_W0_IS_NOT_1_OVER_W0 (1 << 16) +# define RADEON_VTX_ST0_PRE_MULT_1_OVER_W0 (1 << 17) +# define RADEON_VTX_ST1_PRE_MULT_1_OVER_W0 (1 << 19) +# define RADEON_VTX_ST2_PRE_MULT_1_OVER_W0 (1 << 21) +# define RADEON_VTX_ST3_PRE_MULT_1_OVER_W0 (1 << 23) +# define RADEON_TEX1_W_ROUTING_USE_W0 (0 << 26) +# define RADEON_TEX1_W_ROUTING_USE_Q1 (1 << 26) +#define RADEON_SE_LINE_WIDTH 0x1db8 +#define RADEON_SE_TCL_LIGHT_MODEL_CTL 0x226c +# define RADEON_LIGHTING_ENABLE (1 << 0) +# define RADEON_LIGHT_IN_MODELSPACE (1 << 1) +# define RADEON_LOCAL_VIEWER (1 << 2) +# define RADEON_NORMALIZE_NORMALS (1 << 3) +# define RADEON_RESCALE_NORMALS (1 << 4) +# define RADEON_SPECULAR_LIGHTS (1 << 5) +# define RADEON_DIFFUSE_SPECULAR_COMBINE (1 << 6) +# define RADEON_LIGHT_ALPHA (1 << 7) +# define RADEON_LOCAL_LIGHT_VEC_GL (1 << 8) +# define RADEON_LIGHT_NO_NORMAL_AMBIENT_ONLY (1 << 9) +# define RADEON_LM_SOURCE_STATE_PREMULT 0 +# define RADEON_LM_SOURCE_STATE_MULT 1 +# define RADEON_LM_SOURCE_VERTEX_DIFFUSE 2 +# define RADEON_LM_SOURCE_VERTEX_SPECULAR 3 +# define RADEON_EMISSIVE_SOURCE_SHIFT 16 +# define RADEON_AMBIENT_SOURCE_SHIFT 18 +# define RADEON_DIFFUSE_SOURCE_SHIFT 20 +# define RADEON_SPECULAR_SOURCE_SHIFT 22 +#define RADEON_SE_TCL_MATERIAL_AMBIENT_RED 0x2220 +#define RADEON_SE_TCL_MATERIAL_AMBIENT_GREEN 0x2224 +#define RADEON_SE_TCL_MATERIAL_AMBIENT_BLUE 0x2228 +#define RADEON_SE_TCL_MATERIAL_AMBIENT_ALPHA 0x222c +#define RADEON_SE_TCL_MATERIAL_DIFFUSE_RED 0x2230 +#define RADEON_SE_TCL_MATERIAL_DIFFUSE_GREEN 0x2234 +#define RADEON_SE_TCL_MATERIAL_DIFFUSE_BLUE 0x2238 +#define RADEON_SE_TCL_MATERIAL_DIFFUSE_ALPHA 0x223c +#define RADEON_SE_TCL_MATERIAL_EMMISSIVE_RED 0x2210 +#define RADEON_SE_TCL_MATERIAL_EMMISSIVE_GREEN 0x2214 +#define RADEON_SE_TCL_MATERIAL_EMMISSIVE_BLUE 0x2218 +#define RADEON_SE_TCL_MATERIAL_EMMISSIVE_ALPHA 0x221c +#define RADEON_SE_TCL_MATERIAL_SPECULAR_RED 0x2240 +#define RADEON_SE_TCL_MATERIAL_SPECULAR_GREEN 0x2244 +#define RADEON_SE_TCL_MATERIAL_SPECULAR_BLUE 0x2248 +#define RADEON_SE_TCL_MATERIAL_SPECULAR_ALPHA 0x224c +#define RADEON_SE_TCL_MATRIX_SELECT_0 0x225c +# define RADEON_MODELVIEW_0_SHIFT 0 +# define RADEON_MODELVIEW_1_SHIFT 4 +# define RADEON_MODELVIEW_2_SHIFT 8 +# define RADEON_MODELVIEW_3_SHIFT 12 +# define RADEON_IT_MODELVIEW_0_SHIFT 16 +# define RADEON_IT_MODELVIEW_1_SHIFT 20 +# define RADEON_IT_MODELVIEW_2_SHIFT 24 +# define RADEON_IT_MODELVIEW_3_SHIFT 28 +#define RADEON_SE_TCL_MATRIX_SELECT_1 0x2260 +# define RADEON_MODELPROJECT_0_SHIFT 0 +# define RADEON_MODELPROJECT_1_SHIFT 4 +# define RADEON_MODELPROJECT_2_SHIFT 8 +# define RADEON_MODELPROJECT_3_SHIFT 12 +# define RADEON_TEXMAT_0_SHIFT 16 +# define RADEON_TEXMAT_1_SHIFT 20 +# define RADEON_TEXMAT_2_SHIFT 24 +# define RADEON_TEXMAT_3_SHIFT 28 + + +#define RADEON_SE_TCL_OUTPUT_VTX_FMT 0x2254 +# define RADEON_TCL_VTX_W0 (1 << 0) +# define RADEON_TCL_VTX_FP_DIFFUSE (1 << 1) +# define RADEON_TCL_VTX_FP_ALPHA (1 << 2) +# define RADEON_TCL_VTX_PK_DIFFUSE (1 << 3) +# define RADEON_TCL_VTX_FP_SPEC (1 << 4) +# define RADEON_TCL_VTX_FP_FOG (1 << 5) +# define RADEON_TCL_VTX_PK_SPEC (1 << 6) +# define RADEON_TCL_VTX_ST0 (1 << 7) +# define RADEON_TCL_VTX_ST1 (1 << 8) +# define RADEON_TCL_VTX_Q1 (1 << 9) +# define RADEON_TCL_VTX_ST2 (1 << 10) +# define RADEON_TCL_VTX_Q2 (1 << 11) +# define RADEON_TCL_VTX_ST3 (1 << 12) +# define RADEON_TCL_VTX_Q3 (1 << 13) +# define RADEON_TCL_VTX_Q0 (1 << 14) +# define RADEON_TCL_VTX_WEIGHT_COUNT_SHIFT 15 +# define RADEON_TCL_VTX_NORM0 (1 << 18) +# define RADEON_TCL_VTX_XY1 (1 << 27) +# define RADEON_TCL_VTX_Z1 (1 << 28) +# define RADEON_TCL_VTX_W1 (1 << 29) +# define RADEON_TCL_VTX_NORM1 (1 << 30) +# define RADEON_TCL_VTX_Z0 (1 << 31) + +#define RADEON_SE_TCL_OUTPUT_VTX_SEL 0x2258 +# define RADEON_TCL_COMPUTE_XYZW (1 << 0) +# define RADEON_TCL_COMPUTE_DIFFUSE (1 << 1) +# define RADEON_TCL_COMPUTE_SPECULAR (1 << 2) +# define RADEON_TCL_FORCE_NAN_IF_COLOR_NAN (1 << 3) +# define RADEON_TCL_FORCE_INORDER_PROC (1 << 4) +# define RADEON_TCL_TEX_INPUT_TEX_0 0 +# define RADEON_TCL_TEX_INPUT_TEX_1 1 +# define RADEON_TCL_TEX_INPUT_TEX_2 2 +# define RADEON_TCL_TEX_INPUT_TEX_3 3 +# define RADEON_TCL_TEX_COMPUTED_TEX_0 8 +# define RADEON_TCL_TEX_COMPUTED_TEX_1 9 +# define RADEON_TCL_TEX_COMPUTED_TEX_2 10 +# define RADEON_TCL_TEX_COMPUTED_TEX_3 11 +# define RADEON_TCL_TEX_0_OUTPUT_SHIFT 16 +# define RADEON_TCL_TEX_1_OUTPUT_SHIFT 20 +# define RADEON_TCL_TEX_2_OUTPUT_SHIFT 24 +# define RADEON_TCL_TEX_3_OUTPUT_SHIFT 28 + +#define RADEON_SE_TCL_PER_LIGHT_CTL_0 0x2270 +# define RADEON_LIGHT_0_ENABLE (1 << 0) +# define RADEON_LIGHT_0_ENABLE_AMBIENT (1 << 1) +# define RADEON_LIGHT_0_ENABLE_SPECULAR (1 << 2) +# define RADEON_LIGHT_0_IS_LOCAL (1 << 3) +# define RADEON_LIGHT_0_IS_SPOT (1 << 4) +# define RADEON_LIGHT_0_DUAL_CONE (1 << 5) +# define RADEON_LIGHT_0_ENABLE_RANGE_ATTEN (1 << 6) +# define RADEON_LIGHT_0_CONSTANT_RANGE_ATTEN (1 << 7) +# define RADEON_LIGHT_0_SHIFT 0 +# define RADEON_LIGHT_1_ENABLE (1 << 16) +# define RADEON_LIGHT_1_ENABLE_AMBIENT (1 << 17) +# define RADEON_LIGHT_1_ENABLE_SPECULAR (1 << 18) +# define RADEON_LIGHT_1_IS_LOCAL (1 << 19) +# define RADEON_LIGHT_1_IS_SPOT (1 << 20) +# define RADEON_LIGHT_1_DUAL_CONE (1 << 21) +# define RADEON_LIGHT_1_ENABLE_RANGE_ATTEN (1 << 22) +# define RADEON_LIGHT_1_CONSTANT_RANGE_ATTEN (1 << 23) +# define RADEON_LIGHT_1_SHIFT 16 +#define RADEON_SE_TCL_PER_LIGHT_CTL_1 0x2274 +# define RADEON_LIGHT_2_SHIFT 0 +# define RADEON_LIGHT_3_SHIFT 16 +#define RADEON_SE_TCL_PER_LIGHT_CTL_2 0x2278 +# define RADEON_LIGHT_4_SHIFT 0 +# define RADEON_LIGHT_5_SHIFT 16 +#define RADEON_SE_TCL_PER_LIGHT_CTL_3 0x227c +# define RADEON_LIGHT_6_SHIFT 0 +# define RADEON_LIGHT_7_SHIFT 16 + +#define RADEON_SE_TCL_SHININESS 0x2250 + +#define RADEON_SE_TCL_TEXTURE_PROC_CTL 0x2268 +# define RADEON_TEXGEN_TEXMAT_0_ENABLE (1 << 0) +# define RADEON_TEXGEN_TEXMAT_1_ENABLE (1 << 1) +# define RADEON_TEXGEN_TEXMAT_2_ENABLE (1 << 2) +# define RADEON_TEXGEN_TEXMAT_3_ENABLE (1 << 3) +# define RADEON_TEXMAT_0_ENABLE (1 << 4) +# define RADEON_TEXMAT_1_ENABLE (1 << 5) +# define RADEON_TEXMAT_2_ENABLE (1 << 6) +# define RADEON_TEXMAT_3_ENABLE (1 << 7) +# define RADEON_TEXGEN_INPUT_MASK 0xf +# define RADEON_TEXGEN_INPUT_TEXCOORD_0 0 +# define RADEON_TEXGEN_INPUT_TEXCOORD_1 1 +# define RADEON_TEXGEN_INPUT_TEXCOORD_2 2 +# define RADEON_TEXGEN_INPUT_TEXCOORD_3 3 +# define RADEON_TEXGEN_INPUT_OBJ 4 +# define RADEON_TEXGEN_INPUT_EYE 5 +# define RADEON_TEXGEN_INPUT_EYE_NORMAL 6 +# define RADEON_TEXGEN_INPUT_EYE_REFLECT 7 +# define RADEON_TEXGEN_INPUT_EYE_NORMALIZED 8 +# define RADEON_TEXGEN_0_INPUT_SHIFT 16 +# define RADEON_TEXGEN_1_INPUT_SHIFT 20 +# define RADEON_TEXGEN_2_INPUT_SHIFT 24 +# define RADEON_TEXGEN_3_INPUT_SHIFT 28 + +#define RADEON_SE_TCL_UCP_VERT_BLEND_CTL 0x2264 +# define RADEON_UCP_IN_CLIP_SPACE (1 << 0) +# define RADEON_UCP_IN_MODEL_SPACE (1 << 1) +# define RADEON_UCP_ENABLE_0 (1 << 2) +# define RADEON_UCP_ENABLE_1 (1 << 3) +# define RADEON_UCP_ENABLE_2 (1 << 4) +# define RADEON_UCP_ENABLE_3 (1 << 5) +# define RADEON_UCP_ENABLE_4 (1 << 6) +# define RADEON_UCP_ENABLE_5 (1 << 7) +# define RADEON_TCL_FOG_MASK (3 << 8) +# define RADEON_TCL_FOG_DISABLE (0 << 8) +# define RADEON_TCL_FOG_EXP (1 << 8) +# define RADEON_TCL_FOG_EXP2 (2 << 8) +# define RADEON_TCL_FOG_LINEAR (3 << 8) +# define RADEON_RNG_BASED_FOG (1 << 10) +# define RADEON_LIGHT_TWOSIDE (1 << 11) +# define RADEON_BLEND_OP_COUNT_MASK (7 << 12) +# define RADEON_BLEND_OP_COUNT_SHIFT 12 +# define RADEON_POSITION_BLEND_OP_ENABLE (1 << 16) +# define RADEON_NORMAL_BLEND_OP_ENABLE (1 << 17) +# define RADEON_VERTEX_BLEND_SRC_0_PRIMARY (1 << 18) +# define RADEON_VERTEX_BLEND_SRC_0_SECONDARY (1 << 18) +# define RADEON_VERTEX_BLEND_SRC_1_PRIMARY (1 << 19) +# define RADEON_VERTEX_BLEND_SRC_1_SECONDARY (1 << 19) +# define RADEON_VERTEX_BLEND_SRC_2_PRIMARY (1 << 20) +# define RADEON_VERTEX_BLEND_SRC_2_SECONDARY (1 << 20) +# define RADEON_VERTEX_BLEND_SRC_3_PRIMARY (1 << 21) +# define RADEON_VERTEX_BLEND_SRC_3_SECONDARY (1 << 21) +# define RADEON_VERTEX_BLEND_WGT_MINUS_ONE (1 << 22) +# define RADEON_CULL_FRONT_IS_CW (0 << 28) +# define RADEON_CULL_FRONT_IS_CCW (1 << 28) +# define RADEON_CULL_FRONT (1 << 29) +# define RADEON_CULL_BACK (1 << 30) +# define RADEON_FORCE_W_TO_ONE (1 << 31) + +#define RADEON_SE_VPORT_XSCALE 0x1d98 +#define RADEON_SE_VPORT_XOFFSET 0x1d9c +#define RADEON_SE_VPORT_YSCALE 0x1da0 +#define RADEON_SE_VPORT_YOFFSET 0x1da4 +#define RADEON_SE_VPORT_ZSCALE 0x1da8 +#define RADEON_SE_VPORT_ZOFFSET 0x1dac +#define RADEON_SE_ZBIAS_FACTOR 0x1db0 +#define RADEON_SE_ZBIAS_CONSTANT 0x1db4 + +#define RADEON_SE_VTX_FMT 0x2080 +# define RADEON_SE_VTX_FMT_XY 0x00000000 +# define RADEON_SE_VTX_FMT_W0 0x00000001 +# define RADEON_SE_VTX_FMT_FPCOLOR 0x00000002 +# define RADEON_SE_VTX_FMT_FPALPHA 0x00000004 +# define RADEON_SE_VTX_FMT_PKCOLOR 0x00000008 +# define RADEON_SE_VTX_FMT_FPSPEC 0x00000010 +# define RADEON_SE_VTX_FMT_FPFOG 0x00000020 +# define RADEON_SE_VTX_FMT_PKSPEC 0x00000040 +# define RADEON_SE_VTX_FMT_ST0 0x00000080 +# define RADEON_SE_VTX_FMT_ST1 0x00000100 +# define RADEON_SE_VTX_FMT_Q1 0x00000200 +# define RADEON_SE_VTX_FMT_ST2 0x00000400 +# define RADEON_SE_VTX_FMT_Q2 0x00000800 +# define RADEON_SE_VTX_FMT_ST3 0x00001000 +# define RADEON_SE_VTX_FMT_Q3 0x00002000 +# define RADEON_SE_VTX_FMT_Q0 0x00004000 +# define RADEON_SE_VTX_FMT_BLND_WEIGHT_CNT_MASK 0x00038000 +# define RADEON_SE_VTX_FMT_N0 0x00040000 +# define RADEON_SE_VTX_FMT_XY1 0x08000000 +# define RADEON_SE_VTX_FMT_Z1 0x10000000 +# define RADEON_SE_VTX_FMT_W1 0x20000000 +# define RADEON_SE_VTX_FMT_N1 0x40000000 +# define RADEON_SE_VTX_FMT_Z 0x80000000 + +#define RADEON_SE_VF_CNTL 0x2084 +# define RADEON_VF_PRIM_TYPE_POINT_LIST 1 +# define RADEON_VF_PRIM_TYPE_LINE_LIST 2 +# define RADEON_VF_PRIM_TYPE_LINE_STRIP 3 +# define RADEON_VF_PRIM_TYPE_TRIANGLE_LIST 4 +# define RADEON_VF_PRIM_TYPE_TRIANGLE_FAN 5 +# define RADEON_VF_PRIM_TYPE_TRIANGLE_STRIP 6 +# define RADEON_VF_PRIM_TYPE_TRIANGLE_FLAG 7 +# define RADEON_VF_PRIM_TYPE_RECTANGLE_LIST 8 +# define RADEON_VF_PRIM_TYPE_POINT_LIST_3 9 +# define RADEON_VF_PRIM_TYPE_LINE_LIST_3 10 +# define RADEON_VF_PRIM_TYPE_SPIRIT_LIST 11 +# define RADEON_VF_PRIM_TYPE_LINE_LOOP 12 +# define RADEON_VF_PRIM_TYPE_QUAD_LIST 13 +# define RADEON_VF_PRIM_TYPE_QUAD_STRIP 14 +# define RADEON_VF_PRIM_TYPE_POLYGON 15 +# define RADEON_VF_PRIM_WALK_STATE (0<<4) +# define RADEON_VF_PRIM_WALK_INDEX (1<<4) +# define RADEON_VF_PRIM_WALK_LIST (2<<4) +# define RADEON_VF_PRIM_WALK_DATA (3<<4) +# define RADEON_VF_COLOR_ORDER_RGBA (1<<6) +# define RADEON_VF_RADEON_MODE (1<<8) +# define RADEON_VF_TCL_OUTPUT_CTL_ENA (1<<9) +# define RADEON_VF_PROG_STREAM_ENA (1<<10) +# define RADEON_VF_INDEX_SIZE_SHIFT 11 +# define RADEON_VF_NUM_VERTICES_SHIFT 16 + +#define RADEON_SE_PORT_DATA0 0x2000 + +#define R200_SE_VAP_CNTL 0x2080 +# define R200_VAP_TCL_ENABLE 0x00000001 +# define R200_VAP_SINGLE_BUF_STATE_ENABLE 0x00000010 +# define R200_VAP_FORCE_W_TO_ONE 0x00010000 +# define R200_VAP_D3D_TEX_DEFAULT 0x00020000 +# define R200_VAP_VF_MAX_VTX_NUM__SHIFT 18 +# define R200_VAP_VF_MAX_VTX_NUM (9 << 18) +# define R200_VAP_DX_CLIP_SPACE_DEF 0x00400000 +#define R200_VF_MAX_VTX_INDX 0x210c +#define R200_VF_MIN_VTX_INDX 0x2110 +#define R200_SE_VTE_CNTL 0x20b0 +# define R200_VPORT_X_SCALE_ENA 0x00000001 +# define R200_VPORT_X_OFFSET_ENA 0x00000002 +# define R200_VPORT_Y_SCALE_ENA 0x00000004 +# define R200_VPORT_Y_OFFSET_ENA 0x00000008 +# define R200_VPORT_Z_SCALE_ENA 0x00000010 +# define R200_VPORT_Z_OFFSET_ENA 0x00000020 +# define R200_VTX_XY_FMT 0x00000100 +# define R200_VTX_Z_FMT 0x00000200 +# define R200_VTX_W0_FMT 0x00000400 +# define R200_VTX_W0_NORMALIZE 0x00000800 +# define R200_VTX_ST_DENORMALIZED 0x00001000 +#define R200_SE_VAP_CNTL_STATUS 0x2140 +# define R200_VC_NO_SWAP (0 << 0) +# define R200_VC_16BIT_SWAP (1 << 0) +# define R200_VC_32BIT_SWAP (2 << 0) +#define R200_PP_TXFILTER_0 0x2c00 +#define R200_PP_TXFILTER_1 0x2c20 +#define R200_PP_TXFILTER_2 0x2c40 +#define R200_PP_TXFILTER_3 0x2c60 +#define R200_PP_TXFILTER_4 0x2c80 +#define R200_PP_TXFILTER_5 0x2ca0 +# define R200_MAG_FILTER_NEAREST (0 << 0) +# define R200_MAG_FILTER_LINEAR (1 << 0) +# define R200_MAG_FILTER_MASK (1 << 0) +# define R200_MIN_FILTER_NEAREST (0 << 1) +# define R200_MIN_FILTER_LINEAR (1 << 1) +# define R200_MIN_FILTER_NEAREST_MIP_NEAREST (2 << 1) +# define R200_MIN_FILTER_NEAREST_MIP_LINEAR (3 << 1) +# define R200_MIN_FILTER_LINEAR_MIP_NEAREST (6 << 1) +# define R200_MIN_FILTER_LINEAR_MIP_LINEAR (7 << 1) +# define R200_MIN_FILTER_ANISO_NEAREST (8 << 1) +# define R200_MIN_FILTER_ANISO_LINEAR (9 << 1) +# define R200_MIN_FILTER_ANISO_NEAREST_MIP_NEAREST (10 << 1) +# define R200_MIN_FILTER_ANISO_NEAREST_MIP_LINEAR (11 << 1) +# define R200_MIN_FILTER_MASK (15 << 1) +# define R200_MAX_ANISO_1_TO_1 (0 << 5) +# define R200_MAX_ANISO_2_TO_1 (1 << 5) +# define R200_MAX_ANISO_4_TO_1 (2 << 5) +# define R200_MAX_ANISO_8_TO_1 (3 << 5) +# define R200_MAX_ANISO_16_TO_1 (4 << 5) +# define R200_MAX_ANISO_MASK (7 << 5) +# define R200_MAX_MIP_LEVEL_MASK (0x0f << 16) +# define R200_MAX_MIP_LEVEL_SHIFT 16 +# define R200_YUV_TO_RGB (1 << 20) +# define R200_YUV_TEMPERATURE_COOL (0 << 21) +# define R200_YUV_TEMPERATURE_HOT (1 << 21) +# define R200_YUV_TEMPERATURE_MASK (1 << 21) +# define R200_WRAPEN_S (1 << 22) +# define R200_CLAMP_S_WRAP (0 << 23) +# define R200_CLAMP_S_MIRROR (1 << 23) +# define R200_CLAMP_S_CLAMP_LAST (2 << 23) +# define R200_CLAMP_S_MIRROR_CLAMP_LAST (3 << 23) +# define R200_CLAMP_S_CLAMP_BORDER (4 << 23) +# define R200_CLAMP_S_MIRROR_CLAMP_BORDER (5 << 23) +# define R200_CLAMP_S_CLAMP_GL (6 << 23) +# define R200_CLAMP_S_MIRROR_CLAMP_GL (7 << 23) +# define R200_CLAMP_S_MASK (7 << 23) +# define R200_WRAPEN_T (1 << 26) +# define R200_CLAMP_T_WRAP (0 << 27) +# define R200_CLAMP_T_MIRROR (1 << 27) +# define R200_CLAMP_T_CLAMP_LAST (2 << 27) +# define R200_CLAMP_T_MIRROR_CLAMP_LAST (3 << 27) +# define R200_CLAMP_T_CLAMP_BORDER (4 << 27) +# define R200_CLAMP_T_MIRROR_CLAMP_BORDER (5 << 27) +# define R200_CLAMP_T_CLAMP_GL (6 << 27) +# define R200_CLAMP_T_MIRROR_CLAMP_GL (7 << 27) +# define R200_CLAMP_T_MASK (7 << 27) +# define R200_KILL_LT_ZERO (1 << 30) +# define R200_BORDER_MODE_OGL (0 << 31) +# define R200_BORDER_MODE_D3D (1 << 31) +#define R200_PP_TXFORMAT_0 0x2c04 +#define R200_PP_TXFORMAT_1 0x2c24 +#define R200_PP_TXFORMAT_2 0x2c44 +#define R200_PP_TXFORMAT_3 0x2c64 +#define R200_PP_TXFORMAT_4 0x2c84 +#define R200_PP_TXFORMAT_5 0x2ca4 +# define R200_TXFORMAT_I8 (0 << 0) +# define R200_TXFORMAT_AI88 (1 << 0) +# define R200_TXFORMAT_RGB332 (2 << 0) +# define R200_TXFORMAT_ARGB1555 (3 << 0) +# define R200_TXFORMAT_RGB565 (4 << 0) +# define R200_TXFORMAT_ARGB4444 (5 << 0) +# define R200_TXFORMAT_ARGB8888 (6 << 0) +# define R200_TXFORMAT_RGBA8888 (7 << 0) +# define R200_TXFORMAT_Y8 (8 << 0) +# define R200_TXFORMAT_AVYU4444 (9 << 0) +# define R200_TXFORMAT_VYUY422 (10 << 0) +# define R200_TXFORMAT_YVYU422 (11 << 0) +# define R200_TXFORMAT_DXT1 (12 << 0) +# define R200_TXFORMAT_DXT23 (14 << 0) +# define R200_TXFORMAT_DXT45 (15 << 0) +# define R200_TXFORMAT_ABGR8888 (22 << 0) +# define R200_TXFORMAT_FORMAT_MASK (31 << 0) +# define R200_TXFORMAT_FORMAT_SHIFT 0 +# define R200_TXFORMAT_ALPHA_IN_MAP (1 << 6) +# define R200_TXFORMAT_NON_POWER2 (1 << 7) +# define R200_TXFORMAT_WIDTH_MASK (15 << 8) +# define R200_TXFORMAT_WIDTH_SHIFT 8 +# define R200_TXFORMAT_HEIGHT_MASK (15 << 12) +# define R200_TXFORMAT_HEIGHT_SHIFT 12 +# define R200_TXFORMAT_F5_WIDTH_MASK (15 << 16) /* cube face 5 */ +# define R200_TXFORMAT_F5_WIDTH_SHIFT 16 +# define R200_TXFORMAT_F5_HEIGHT_MASK (15 << 20) +# define R200_TXFORMAT_F5_HEIGHT_SHIFT 20 +# define R200_TXFORMAT_ST_ROUTE_STQ0 (0 << 24) +# define R200_TXFORMAT_ST_ROUTE_STQ1 (1 << 24) +# define R200_TXFORMAT_ST_ROUTE_STQ2 (2 << 24) +# define R200_TXFORMAT_ST_ROUTE_STQ3 (3 << 24) +# define R200_TXFORMAT_ST_ROUTE_STQ4 (4 << 24) +# define R200_TXFORMAT_ST_ROUTE_STQ5 (5 << 24) +# define R200_TXFORMAT_ST_ROUTE_MASK (7 << 24) +# define R200_TXFORMAT_ST_ROUTE_SHIFT 24 +# define R200_TXFORMAT_ALPHA_MASK_ENABLE (1 << 28) +# define R200_TXFORMAT_CHROMA_KEY_ENABLE (1 << 29) +# define R200_TXFORMAT_CUBIC_MAP_ENABLE (1 << 30) +#define R200_PP_TXFORMAT_X_0 0x2c08 +#define R200_PP_TXFORMAT_X_1 0x2c28 +#define R200_PP_TXFORMAT_X_2 0x2c48 +#define R200_PP_TXFORMAT_X_3 0x2c68 +#define R200_PP_TXFORMAT_X_4 0x2c88 +#define R200_PP_TXFORMAT_X_5 0x2ca8 + +#define R200_PP_TXSIZE_0 0x2c0c /* NPOT only */ +#define R200_PP_TXSIZE_1 0x2c2c /* NPOT only */ +#define R200_PP_TXSIZE_2 0x2c4c /* NPOT only */ +#define R200_PP_TXSIZE_3 0x2c6c /* NPOT only */ +#define R200_PP_TXSIZE_4 0x2c8c /* NPOT only */ +#define R200_PP_TXSIZE_5 0x2cac /* NPOT only */ + +#define R200_PP_TXPITCH_0 0x2c10 /* NPOT only */ +#define R200_PP_TXPITCH_1 0x2c30 /* NPOT only */ +#define R200_PP_TXPITCH_2 0x2c50 /* NPOT only */ +#define R200_PP_TXPITCH_3 0x2c70 /* NPOT only */ +#define R200_PP_TXPITCH_4 0x2c90 /* NPOT only */ +#define R200_PP_TXPITCH_5 0x2cb0 /* NPOT only */ + +#define R200_PP_TXOFFSET_0 0x2d00 +# define R200_TXO_ENDIAN_NO_SWAP (0 << 0) +# define R200_TXO_ENDIAN_BYTE_SWAP (1 << 0) +# define R200_TXO_ENDIAN_WORD_SWAP (2 << 0) +# define R200_TXO_ENDIAN_HALFDW_SWAP (3 << 0) +# define R200_TXO_MACRO_LINEAR (0 << 2) +# define R200_TXO_MACRO_TILE (1 << 2) +# define R200_TXO_MICRO_LINEAR (0 << 3) +# define R200_TXO_MICRO_TILE (1 << 3) +# define R200_TXO_OFFSET_MASK 0xffffffe0 +# define R200_TXO_OFFSET_SHIFT 5 +#define R200_PP_TXOFFSET_1 0x2d18 +#define R200_PP_TXOFFSET_2 0x2d30 +#define R200_PP_TXOFFSET_3 0x2d48 +#define R200_PP_TXOFFSET_4 0x2d60 +#define R200_PP_TXOFFSET_5 0x2d78 + +#define R200_PP_TFACTOR_0 0x2ee0 +#define R200_PP_TFACTOR_1 0x2ee4 +#define R200_PP_TFACTOR_2 0x2ee8 +#define R200_PP_TFACTOR_3 0x2eec +#define R200_PP_TFACTOR_4 0x2ef0 +#define R200_PP_TFACTOR_5 0x2ef4 + +#define R200_PP_TXCBLEND_0 0x2f00 +# define R200_TXC_ARG_A_ZERO (0) +# define R200_TXC_ARG_A_CURRENT_COLOR (2) +# define R200_TXC_ARG_A_CURRENT_ALPHA (3) +# define R200_TXC_ARG_A_DIFFUSE_COLOR (4) +# define R200_TXC_ARG_A_DIFFUSE_ALPHA (5) +# define R200_TXC_ARG_A_SPECULAR_COLOR (6) +# define R200_TXC_ARG_A_SPECULAR_ALPHA (7) +# define R200_TXC_ARG_A_TFACTOR_COLOR (8) +# define R200_TXC_ARG_A_TFACTOR_ALPHA (9) +# define R200_TXC_ARG_A_R0_COLOR (10) +# define R200_TXC_ARG_A_R0_ALPHA (11) +# define R200_TXC_ARG_A_R1_COLOR (12) +# define R200_TXC_ARG_A_R1_ALPHA (13) +# define R200_TXC_ARG_A_R2_COLOR (14) +# define R200_TXC_ARG_A_R2_ALPHA (15) +# define R200_TXC_ARG_A_R3_COLOR (16) +# define R200_TXC_ARG_A_R3_ALPHA (17) +# define R200_TXC_ARG_A_R4_COLOR (18) +# define R200_TXC_ARG_A_R4_ALPHA (19) +# define R200_TXC_ARG_A_R5_COLOR (20) +# define R200_TXC_ARG_A_R5_ALPHA (21) +# define R200_TXC_ARG_A_TFACTOR1_COLOR (26) +# define R200_TXC_ARG_A_TFACTOR1_ALPHA (27) +# define R200_TXC_ARG_A_MASK (31 << 0) +# define R200_TXC_ARG_A_SHIFT 0 +# define R200_TXC_ARG_B_ZERO (0 << 5) +# define R200_TXC_ARG_B_CURRENT_COLOR (2 << 5) +# define R200_TXC_ARG_B_CURRENT_ALPHA (3 << 5) +# define R200_TXC_ARG_B_DIFFUSE_COLOR (4 << 5) +# define R200_TXC_ARG_B_DIFFUSE_ALPHA (5 << 5) +# define R200_TXC_ARG_B_SPECULAR_COLOR (6 << 5) +# define R200_TXC_ARG_B_SPECULAR_ALPHA (7 << 5) +# define R200_TXC_ARG_B_TFACTOR_COLOR (8 << 5) +# define R200_TXC_ARG_B_TFACTOR_ALPHA (9 << 5) +# define R200_TXC_ARG_B_R0_COLOR (10 << 5) +# define R200_TXC_ARG_B_R0_ALPHA (11 << 5) +# define R200_TXC_ARG_B_R1_COLOR (12 << 5) +# define R200_TXC_ARG_B_R1_ALPHA (13 << 5) +# define R200_TXC_ARG_B_R2_COLOR (14 << 5) +# define R200_TXC_ARG_B_R2_ALPHA (15 << 5) +# define R200_TXC_ARG_B_R3_COLOR (16 << 5) +# define R200_TXC_ARG_B_R3_ALPHA (17 << 5) +# define R200_TXC_ARG_B_R4_COLOR (18 << 5) +# define R200_TXC_ARG_B_R4_ALPHA (19 << 5) +# define R200_TXC_ARG_B_R5_COLOR (20 << 5) +# define R200_TXC_ARG_B_R5_ALPHA (21 << 5) +# define R200_TXC_ARG_B_TFACTOR1_COLOR (26 << 5) +# define R200_TXC_ARG_B_TFACTOR1_ALPHA (27 << 5) +# define R200_TXC_ARG_B_MASK (31 << 5) +# define R200_TXC_ARG_B_SHIFT 5 +# define R200_TXC_ARG_C_ZERO (0 << 10) +# define R200_TXC_ARG_C_CURRENT_COLOR (2 << 10) +# define R200_TXC_ARG_C_CURRENT_ALPHA (3 << 10) +# define R200_TXC_ARG_C_DIFFUSE_COLOR (4 << 10) +# define R200_TXC_ARG_C_DIFFUSE_ALPHA (5 << 10) +# define R200_TXC_ARG_C_SPECULAR_COLOR (6 << 10) +# define R200_TXC_ARG_C_SPECULAR_ALPHA (7 << 10) +# define R200_TXC_ARG_C_TFACTOR_COLOR (8 << 10) +# define R200_TXC_ARG_C_TFACTOR_ALPHA (9 << 10) +# define R200_TXC_ARG_C_R0_COLOR (10 << 10) +# define R200_TXC_ARG_C_R0_ALPHA (11 << 10) +# define R200_TXC_ARG_C_R1_COLOR (12 << 10) +# define R200_TXC_ARG_C_R1_ALPHA (13 << 10) +# define R200_TXC_ARG_C_R2_COLOR (14 << 10) +# define R200_TXC_ARG_C_R2_ALPHA (15 << 10) +# define R200_TXC_ARG_C_R3_COLOR (16 << 10) +# define R200_TXC_ARG_C_R3_ALPHA (17 << 10) +# define R200_TXC_ARG_C_R4_COLOR (18 << 10) +# define R200_TXC_ARG_C_R4_ALPHA (19 << 10) +# define R200_TXC_ARG_C_R5_COLOR (20 << 10) +# define R200_TXC_ARG_C_R5_ALPHA (21 << 10) +# define R200_TXC_ARG_C_TFACTOR1_COLOR (26 << 10) +# define R200_TXC_ARG_C_TFACTOR1_ALPHA (27 << 10) +# define R200_TXC_ARG_C_MASK (31 << 10) +# define R200_TXC_ARG_C_SHIFT 10 +# define R200_TXC_COMP_ARG_A (1 << 16) +# define R200_TXC_COMP_ARG_A_SHIFT (16) +# define R200_TXC_BIAS_ARG_A (1 << 17) +# define R200_TXC_SCALE_ARG_A (1 << 18) +# define R200_TXC_NEG_ARG_A (1 << 19) +# define R200_TXC_COMP_ARG_B (1 << 20) +# define R200_TXC_COMP_ARG_B_SHIFT (20) +# define R200_TXC_BIAS_ARG_B (1 << 21) +# define R200_TXC_SCALE_ARG_B (1 << 22) +# define R200_TXC_NEG_ARG_B (1 << 23) +# define R200_TXC_COMP_ARG_C (1 << 24) +# define R200_TXC_COMP_ARG_C_SHIFT (24) +# define R200_TXC_BIAS_ARG_C (1 << 25) +# define R200_TXC_SCALE_ARG_C (1 << 26) +# define R200_TXC_NEG_ARG_C (1 << 27) +# define R200_TXC_OP_MADD (0 << 28) +# define R200_TXC_OP_CND0 (2 << 28) +# define R200_TXC_OP_LERP (3 << 28) +# define R200_TXC_OP_DOT3 (4 << 28) +# define R200_TXC_OP_DOT4 (5 << 28) +# define R200_TXC_OP_CONDITIONAL (6 << 28) +# define R200_TXC_OP_DOT2_ADD (7 << 28) +# define R200_TXC_OP_MASK (7 << 28) +#define R200_PP_TXCBLEND2_0 0x2f04 +# define R200_TXC_TFACTOR_SEL_SHIFT 0 +# define R200_TXC_TFACTOR_SEL_MASK 0x7 +# define R200_TXC_TFACTOR1_SEL_SHIFT 4 +# define R200_TXC_TFACTOR1_SEL_MASK (0x7 << 4) +# define R200_TXC_SCALE_SHIFT 8 +# define R200_TXC_SCALE_MASK (7 << 8) +# define R200_TXC_SCALE_1X (0 << 8) +# define R200_TXC_SCALE_2X (1 << 8) +# define R200_TXC_SCALE_4X (2 << 8) +# define R200_TXC_SCALE_8X (3 << 8) +# define R200_TXC_SCALE_INV2 (5 << 8) +# define R200_TXC_SCALE_INV4 (6 << 8) +# define R200_TXC_SCALE_INV8 (7 << 8) +# define R200_TXC_CLAMP_SHIFT 12 +# define R200_TXC_CLAMP_MASK (3 << 12) +# define R200_TXC_CLAMP_WRAP (0 << 12) +# define R200_TXC_CLAMP_0_1 (1 << 12) +# define R200_TXC_CLAMP_8_8 (2 << 12) +# define R200_TXC_OUTPUT_REG_MASK (7 << 16) +# define R200_TXC_OUTPUT_REG_NONE (0 << 16) +# define R200_TXC_OUTPUT_REG_R0 (1 << 16) +# define R200_TXC_OUTPUT_REG_R1 (2 << 16) +# define R200_TXC_OUTPUT_REG_R2 (3 << 16) +# define R200_TXC_OUTPUT_REG_R3 (4 << 16) +# define R200_TXC_OUTPUT_REG_R4 (5 << 16) +# define R200_TXC_OUTPUT_REG_R5 (6 << 16) +# define R200_TXC_OUTPUT_MASK_MASK (7 << 20) +# define R200_TXC_OUTPUT_MASK_RGB (0 << 20) +# define R200_TXC_OUTPUT_MASK_RG (1 << 20) +# define R200_TXC_OUTPUT_MASK_RB (2 << 20) +# define R200_TXC_OUTPUT_MASK_R (3 << 20) +# define R200_TXC_OUTPUT_MASK_GB (4 << 20) +# define R200_TXC_OUTPUT_MASK_G (5 << 20) +# define R200_TXC_OUTPUT_MASK_B (6 << 20) +# define R200_TXC_OUTPUT_MASK_NONE (7 << 20) +# define R200_TXC_REPL_NORMAL 0 +# define R200_TXC_REPL_RED 1 +# define R200_TXC_REPL_GREEN 2 +# define R200_TXC_REPL_BLUE 3 +# define R200_TXC_REPL_ARG_A_SHIFT 26 +# define R200_TXC_REPL_ARG_A_MASK (3 << 26) +# define R200_TXC_REPL_ARG_B_SHIFT 28 +# define R200_TXC_REPL_ARG_B_MASK (3 << 28) +# define R200_TXC_REPL_ARG_C_SHIFT 30 +# define R200_TXC_REPL_ARG_C_MASK (3 << 30) +#define R200_PP_TXABLEND_0 0x2f08 +# define R200_TXA_ARG_A_ZERO (0) +# define R200_TXA_ARG_A_CURRENT_ALPHA (2) /* guess */ +# define R200_TXA_ARG_A_CURRENT_BLUE (3) /* guess */ +# define R200_TXA_ARG_A_DIFFUSE_ALPHA (4) +# define R200_TXA_ARG_A_DIFFUSE_BLUE (5) +# define R200_TXA_ARG_A_SPECULAR_ALPHA (6) +# define R200_TXA_ARG_A_SPECULAR_BLUE (7) +# define R200_TXA_ARG_A_TFACTOR_ALPHA (8) +# define R200_TXA_ARG_A_TFACTOR_BLUE (9) +# define R200_TXA_ARG_A_R0_ALPHA (10) +# define R200_TXA_ARG_A_R0_BLUE (11) +# define R200_TXA_ARG_A_R1_ALPHA (12) +# define R200_TXA_ARG_A_R1_BLUE (13) +# define R200_TXA_ARG_A_R2_ALPHA (14) +# define R200_TXA_ARG_A_R2_BLUE (15) +# define R200_TXA_ARG_A_R3_ALPHA (16) +# define R200_TXA_ARG_A_R3_BLUE (17) +# define R200_TXA_ARG_A_R4_ALPHA (18) +# define R200_TXA_ARG_A_R4_BLUE (19) +# define R200_TXA_ARG_A_R5_ALPHA (20) +# define R200_TXA_ARG_A_R5_BLUE (21) +# define R200_TXA_ARG_A_TFACTOR1_ALPHA (26) +# define R200_TXA_ARG_A_TFACTOR1_BLUE (27) +# define R200_TXA_ARG_A_MASK (31 << 0) +# define R200_TXA_ARG_A_SHIFT 0 +# define R200_TXA_ARG_B_ZERO (0 << 5) +# define R200_TXA_ARG_B_CURRENT_ALPHA (2 << 5) /* guess */ +# define R200_TXA_ARG_B_CURRENT_BLUE (3 << 5) /* guess */ +# define R200_TXA_ARG_B_DIFFUSE_ALPHA (4 << 5) +# define R200_TXA_ARG_B_DIFFUSE_BLUE (5 << 5) +# define R200_TXA_ARG_B_SPECULAR_ALPHA (6 << 5) +# define R200_TXA_ARG_B_SPECULAR_BLUE (7 << 5) +# define R200_TXA_ARG_B_TFACTOR_ALPHA (8 << 5) +# define R200_TXA_ARG_B_TFACTOR_BLUE (9 << 5) +# define R200_TXA_ARG_B_R0_ALPHA (10 << 5) +# define R200_TXA_ARG_B_R0_BLUE (11 << 5) +# define R200_TXA_ARG_B_R1_ALPHA (12 << 5) +# define R200_TXA_ARG_B_R1_BLUE (13 << 5) +# define R200_TXA_ARG_B_R2_ALPHA (14 << 5) +# define R200_TXA_ARG_B_R2_BLUE (15 << 5) +# define R200_TXA_ARG_B_R3_ALPHA (16 << 5) +# define R200_TXA_ARG_B_R3_BLUE (17 << 5) +# define R200_TXA_ARG_B_R4_ALPHA (18 << 5) +# define R200_TXA_ARG_B_R4_BLUE (19 << 5) +# define R200_TXA_ARG_B_R5_ALPHA (20 << 5) +# define R200_TXA_ARG_B_R5_BLUE (21 << 5) +# define R200_TXA_ARG_B_TFACTOR1_ALPHA (26 << 5) +# define R200_TXA_ARG_B_TFACTOR1_BLUE (27 << 5) +# define R200_TXA_ARG_B_MASK (31 << 5) +# define R200_TXA_ARG_B_SHIFT 5 +# define R200_TXA_ARG_C_ZERO (0 << 10) +# define R200_TXA_ARG_C_CURRENT_ALPHA (2 << 10) /* guess */ +# define R200_TXA_ARG_C_CURRENT_BLUE (3 << 10) /* guess */ +# define R200_TXA_ARG_C_DIFFUSE_ALPHA (4 << 10) +# define R200_TXA_ARG_C_DIFFUSE_BLUE (5 << 10) +# define R200_TXA_ARG_C_SPECULAR_ALPHA (6 << 10) +# define R200_TXA_ARG_C_SPECULAR_BLUE (7 << 10) +# define R200_TXA_ARG_C_TFACTOR_ALPHA (8 << 10) +# define R200_TXA_ARG_C_TFACTOR_BLUE (9 << 10) +# define R200_TXA_ARG_C_R0_ALPHA (10 << 10) +# define R200_TXA_ARG_C_R0_BLUE (11 << 10) +# define R200_TXA_ARG_C_R1_ALPHA (12 << 10) +# define R200_TXA_ARG_C_R1_BLUE (13 << 10) +# define R200_TXA_ARG_C_R2_ALPHA (14 << 10) +# define R200_TXA_ARG_C_R2_BLUE (15 << 10) +# define R200_TXA_ARG_C_R3_ALPHA (16 << 10) +# define R200_TXA_ARG_C_R3_BLUE (17 << 10) +# define R200_TXA_ARG_C_R4_ALPHA (18 << 10) +# define R200_TXA_ARG_C_R4_BLUE (19 << 10) +# define R200_TXA_ARG_C_R5_ALPHA (20 << 10) +# define R200_TXA_ARG_C_R5_BLUE (21 << 10) +# define R200_TXA_ARG_C_TFACTOR1_ALPHA (26 << 10) +# define R200_TXA_ARG_C_TFACTOR1_BLUE (27 << 10) +# define R200_TXA_ARG_C_MASK (31 << 10) +# define R200_TXA_ARG_C_SHIFT 10 +# define R200_TXA_COMP_ARG_A (1 << 16) +# define R200_TXA_COMP_ARG_A_SHIFT (16) +# define R200_TXA_BIAS_ARG_A (1 << 17) +# define R200_TXA_SCALE_ARG_A (1 << 18) +# define R200_TXA_NEG_ARG_A (1 << 19) +# define R200_TXA_COMP_ARG_B (1 << 20) +# define R200_TXA_COMP_ARG_B_SHIFT (20) +# define R200_TXA_BIAS_ARG_B (1 << 21) +# define R200_TXA_SCALE_ARG_B (1 << 22) +# define R200_TXA_NEG_ARG_B (1 << 23) +# define R200_TXA_COMP_ARG_C (1 << 24) +# define R200_TXA_COMP_ARG_C_SHIFT (24) +# define R200_TXA_BIAS_ARG_C (1 << 25) +# define R200_TXA_SCALE_ARG_C (1 << 26) +# define R200_TXA_NEG_ARG_C (1 << 27) +# define R200_TXA_OP_MADD (0 << 28) +# define R200_TXA_OP_CND0 (2 << 28) +# define R200_TXA_OP_LERP (3 << 28) +# define R200_TXA_OP_CONDITIONAL (6 << 28) +# define R200_TXA_OP_MASK (7 << 28) +#define R200_PP_TXABLEND2_0 0x2f0c +# define R200_TXA_TFACTOR_SEL_SHIFT 0 +# define R200_TXA_TFACTOR_SEL_MASK 0x7 +# define R200_TXA_TFACTOR1_SEL_SHIFT 4 +# define R200_TXA_TFACTOR1_SEL_MASK (0x7 << 4) +# define R200_TXA_SCALE_SHIFT 8 +# define R200_TXA_SCALE_MASK (7 << 8) +# define R200_TXA_SCALE_1X (0 << 8) +# define R200_TXA_SCALE_2X (1 << 8) +# define R200_TXA_SCALE_4X (2 << 8) +# define R200_TXA_SCALE_8X (3 << 8) +# define R200_TXA_SCALE_INV2 (5 << 8) +# define R200_TXA_SCALE_INV4 (6 << 8) +# define R200_TXA_SCALE_INV8 (7 << 8) +# define R200_TXA_CLAMP_SHIFT 12 +# define R200_TXA_CLAMP_MASK (3 << 12) +# define R200_TXA_CLAMP_WRAP (0 << 12) +# define R200_TXA_CLAMP_0_1 (1 << 12) +# define R200_TXA_CLAMP_8_8 (2 << 12) +# define R200_TXA_OUTPUT_REG_MASK (7 << 16) +# define R200_TXA_OUTPUT_REG_NONE (0 << 16) +# define R200_TXA_OUTPUT_REG_R0 (1 << 16) +# define R200_TXA_OUTPUT_REG_R1 (2 << 16) +# define R200_TXA_OUTPUT_REG_R2 (3 << 16) +# define R200_TXA_OUTPUT_REG_R3 (4 << 16) +# define R200_TXA_OUTPUT_REG_R4 (5 << 16) +# define R200_TXA_OUTPUT_REG_R5 (6 << 16) +# define R200_TXA_DOT_ALPHA (1 << 20) +# define R200_TXA_REPL_NORMAL 0 +# define R200_TXA_REPL_RED 1 +# define R200_TXA_REPL_GREEN 2 +# define R200_TXA_REPL_ARG_A_SHIFT 26 +# define R200_TXA_REPL_ARG_A_MASK (3 << 26) +# define R200_TXA_REPL_ARG_B_SHIFT 28 +# define R200_TXA_REPL_ARG_B_MASK (3 << 28) +# define R200_TXA_REPL_ARG_C_SHIFT 30 +# define R200_TXA_REPL_ARG_C_MASK (3 << 30) + +#define R200_SE_VTX_FMT_0 0x2088 +# define R200_VTX_XY 0 /* always have xy */ +# define R200_VTX_Z0 (1<<0) +# define R200_VTX_W0 (1<<1) +# define R200_VTX_WEIGHT_COUNT_SHIFT (2) +# define R200_VTX_PV_MATRIX_SEL (1<<5) +# define R200_VTX_N0 (1<<6) +# define R200_VTX_POINT_SIZE (1<<7) +# define R200_VTX_DISCRETE_FOG (1<<8) +# define R200_VTX_SHININESS_0 (1<<9) +# define R200_VTX_SHININESS_1 (1<<10) +# define R200_VTX_COLOR_NOT_PRESENT 0 +# define R200_VTX_PK_RGBA 1 +# define R200_VTX_FP_RGB 2 +# define R200_VTX_FP_RGBA 3 +# define R200_VTX_COLOR_MASK 3 +# define R200_VTX_COLOR_0_SHIFT 11 +# define R200_VTX_COLOR_1_SHIFT 13 +# define R200_VTX_COLOR_2_SHIFT 15 +# define R200_VTX_COLOR_3_SHIFT 17 +# define R200_VTX_COLOR_4_SHIFT 19 +# define R200_VTX_COLOR_5_SHIFT 21 +# define R200_VTX_COLOR_6_SHIFT 23 +# define R200_VTX_COLOR_7_SHIFT 25 +# define R200_VTX_XY1 (1<<28) +# define R200_VTX_Z1 (1<<29) +# define R200_VTX_W1 (1<<30) +# define R200_VTX_N1 (1<<31) +#define R200_SE_VTX_FMT_1 0x208c +# define R200_VTX_TEX0_COMP_CNT_SHIFT 0 +# define R200_VTX_TEX1_COMP_CNT_SHIFT 3 +# define R200_VTX_TEX2_COMP_CNT_SHIFT 6 +# define R200_VTX_TEX3_COMP_CNT_SHIFT 9 +# define R200_VTX_TEX4_COMP_CNT_SHIFT 12 +# define R200_VTX_TEX5_COMP_CNT_SHIFT 15 + +#define R200_SE_TCL_OUTPUT_VTX_FMT_0 0x2090 +#define R200_SE_TCL_OUTPUT_VTX_FMT_1 0x2094 +#define R200_SE_TCL_OUTPUT_VTX_COMP_SEL 0x2250 +# define R200_OUTPUT_XYZW (1<<0) +# define R200_OUTPUT_COLOR_0 (1<<8) +# define R200_OUTPUT_COLOR_1 (1<<9) +# define R200_OUTPUT_TEX_0 (1<<16) +# define R200_OUTPUT_TEX_1 (1<<17) +# define R200_OUTPUT_TEX_2 (1<<18) +# define R200_OUTPUT_TEX_3 (1<<19) +# define R200_OUTPUT_TEX_4 (1<<20) +# define R200_OUTPUT_TEX_5 (1<<21) +# define R200_OUTPUT_TEX_MASK (0x3f<<16) +# define R200_OUTPUT_DISCRETE_FOG (1<<24) +# define R200_OUTPUT_PT_SIZE (1<<25) +# define R200_FORCE_INORDER_PROC (1<<31) +#define R200_PP_CNTL_X 0x2cc4 +#define R200_PP_TXMULTI_CTL_0 0x2c1c +#define R200_SE_VTX_STATE_CNTL 0x2180 +# define R200_UPDATE_USER_COLOR_0_ENA_MASK (1<<16) + + /* Registers for CP and Microcode Engine */ +#define RADEON_CP_ME_RAM_ADDR 0x07d4 +#define RADEON_CP_ME_RAM_RADDR 0x07d8 +#define RADEON_CP_ME_RAM_DATAH 0x07dc +#define RADEON_CP_ME_RAM_DATAL 0x07e0 + +#define RADEON_CP_RB_BASE 0x0700 +#define RADEON_CP_RB_CNTL 0x0704 +# define RADEON_RB_BUFSZ_SHIFT 0 +# define RADEON_RB_BUFSZ_MASK (0x3f << 0) +# define RADEON_RB_BLKSZ_SHIFT 8 +# define RADEON_RB_BLKSZ_MASK (0x3f << 8) +# define RADEON_BUF_SWAP_32BIT (1 << 17) +# define RADEON_MAX_FETCH_SHIFT 18 +# define RADEON_MAX_FETCH_MASK (0x3 << 18) +# define RADEON_RB_NO_UPDATE (1 << 27) +# define RADEON_RB_RPTR_WR_ENA (1 << 31) +#define RADEON_CP_RB_RPTR_ADDR 0x070c +#define RADEON_CP_RB_RPTR 0x0710 +#define RADEON_CP_RB_WPTR 0x0714 +#define RADEON_CP_RB_RPTR_WR 0x071c + +#define RADEON_CP_IB_BASE 0x0738 +#define RADEON_CP_IB_BUFSZ 0x073c + +#define RADEON_CP_CSQ_CNTL 0x0740 +# define RADEON_CSQ_CNT_PRIMARY_MASK (0xff << 0) +# define RADEON_CSQ_PRIDIS_INDDIS (0 << 28) +# define RADEON_CSQ_PRIPIO_INDDIS (1 << 28) +# define RADEON_CSQ_PRIBM_INDDIS (2 << 28) +# define RADEON_CSQ_PRIPIO_INDBM (3 << 28) +# define RADEON_CSQ_PRIBM_INDBM (4 << 28) +# define RADEON_CSQ_PRIPIO_INDPIO (15 << 28) + +#define R300_CP_RESYNC_ADDR 0x778 +#define R300_CP_RESYNC_DATA 0x77c + +#define RADEON_CP_CSQ_STAT 0x07f8 +# define RADEON_CSQ_RPTR_PRIMARY_MASK (0xff << 0) +# define RADEON_CSQ_WPTR_PRIMARY_MASK (0xff << 8) +# define RADEON_CSQ_RPTR_INDIRECT_MASK (0xff << 16) +# define RADEON_CSQ_WPTR_INDIRECT_MASK (0xff << 24) +#define RADEON_CP_CSQ2_STAT 0x07fc +#define RADEON_CP_CSQ_ADDR 0x07f0 +#define RADEON_CP_CSQ_DATA 0x07f4 +#define RADEON_CP_CSQ_APER_PRIMARY 0x1000 +#define RADEON_CP_CSQ_APER_INDIRECT 0x1300 + +#define RADEON_CP_RB_WPTR_DELAY 0x0718 +# define RADEON_PRE_WRITE_TIMER_SHIFT 0 +# define RADEON_PRE_WRITE_LIMIT_SHIFT 23 +#define RADEON_CP_CSQ_MODE 0x0744 +# define RADEON_INDIRECT2_START_SHIFT 0 +# define RADEON_INDIRECT2_START_MASK (0x7f << 0) +# define RADEON_INDIRECT1_START_SHIFT 8 +# define RADEON_INDIRECT1_START_MASK (0x7f << 8) + +#define RADEON_AIC_CNTL 0x01d0 +# define RADEON_PCIGART_TRANSLATE_EN (1 << 0) +# define RADEON_DIS_OUT_OF_PCI_GART_ACCESS (1 << 1) +#define RADEON_AIC_LO_ADDR 0x01dc +#define RADEON_AIC_PT_BASE 0x01d8 +#define RADEON_AIC_HI_ADDR 0x01e0 + + + + /* Constants */ +/* #define RADEON_LAST_FRAME_REG RADEON_GUI_SCRATCH_REG0 */ +/* efine RADEON_LAST_CLEAR_REG RADEON_GUI_SCRATCH_REG2 */ + + + + /* CP packet types */ +#define RADEON_CP_PACKET0 0x00000000 +#define RADEON_CP_PACKET1 0x40000000 +#define RADEON_CP_PACKET2 0x80000000 +#define RADEON_CP_PACKET3 0xC0000000 +# define RADEON_CP_PACKET_MASK 0xC0000000 +# define RADEON_CP_PACKET_COUNT_MASK 0x3fff0000 +# define RADEON_CP_PACKET_MAX_DWORDS (1 << 12) +# define RADEON_CP_PACKET0_REG_MASK 0x000007ff +# define R300_CP_PACKET0_REG_MASK 0x00001fff +# define RADEON_CP_PACKET1_REG0_MASK 0x000007ff +# define RADEON_CP_PACKET1_REG1_MASK 0x003ff800 + +#define RADEON_CP_PACKET0_ONE_REG_WR 0x00008000 + +#define RADEON_CP_PACKET3_NOP 0xC0001000 +#define RADEON_CP_PACKET3_NEXT_CHAR 0xC0001900 +#define RADEON_CP_PACKET3_PLY_NEXTSCAN 0xC0001D00 +#define RADEON_CP_PACKET3_SET_SCISSORS 0xC0001E00 +#define RADEON_CP_PACKET3_3D_RNDR_GEN_INDX_PRIM 0xC0002300 +#define RADEON_CP_PACKET3_LOAD_MICROCODE 0xC0002400 +#define RADEON_CP_PACKET3_WAIT_FOR_IDLE 0xC0002600 +#define RADEON_CP_PACKET3_3D_DRAW_VBUF 0xC0002800 +#define RADEON_CP_PACKET3_3D_DRAW_IMMD 0xC0002900 +#define RADEON_CP_PACKET3_3D_DRAW_INDX 0xC0002A00 +#define RADEON_CP_PACKET3_LOAD_PALETTE 0xC0002C00 +#define R200_CP_PACKET3_3D_DRAW_IMMD_2 0xc0003500 +#define RADEON_CP_PACKET3_3D_LOAD_VBPNTR 0xC0002F00 +#define RADEON_CP_PACKET3_CNTL_PAINT 0xC0009100 +#define RADEON_CP_PACKET3_CNTL_BITBLT 0xC0009200 +#define RADEON_CP_PACKET3_CNTL_SMALLTEXT 0xC0009300 +#define RADEON_CP_PACKET3_CNTL_HOSTDATA_BLT 0xC0009400 +#define RADEON_CP_PACKET3_CNTL_POLYLINE 0xC0009500 +#define RADEON_CP_PACKET3_CNTL_POLYSCANLINES 0xC0009800 +#define RADEON_CP_PACKET3_CNTL_PAINT_MULTI 0xC0009A00 +#define RADEON_CP_PACKET3_CNTL_BITBLT_MULTI 0xC0009B00 +#define RADEON_CP_PACKET3_CNTL_TRANS_BITBLT 0xC0009C00 + + +#define RADEON_CP_VC_FRMT_XY 0x00000000 +#define RADEON_CP_VC_FRMT_W0 0x00000001 +#define RADEON_CP_VC_FRMT_FPCOLOR 0x00000002 +#define RADEON_CP_VC_FRMT_FPALPHA 0x00000004 +#define RADEON_CP_VC_FRMT_PKCOLOR 0x00000008 +#define RADEON_CP_VC_FRMT_FPSPEC 0x00000010 +#define RADEON_CP_VC_FRMT_FPFOG 0x00000020 +#define RADEON_CP_VC_FRMT_PKSPEC 0x00000040 +#define RADEON_CP_VC_FRMT_ST0 0x00000080 +#define RADEON_CP_VC_FRMT_ST1 0x00000100 +#define RADEON_CP_VC_FRMT_Q1 0x00000200 +#define RADEON_CP_VC_FRMT_ST2 0x00000400 +#define RADEON_CP_VC_FRMT_Q2 0x00000800 +#define RADEON_CP_VC_FRMT_ST3 0x00001000 +#define RADEON_CP_VC_FRMT_Q3 0x00002000 +#define RADEON_CP_VC_FRMT_Q0 0x00004000 +#define RADEON_CP_VC_FRMT_BLND_WEIGHT_CNT_MASK 0x00038000 +#define RADEON_CP_VC_FRMT_N0 0x00040000 +#define RADEON_CP_VC_FRMT_XY1 0x08000000 +#define RADEON_CP_VC_FRMT_Z1 0x10000000 +#define RADEON_CP_VC_FRMT_W1 0x20000000 +#define RADEON_CP_VC_FRMT_N1 0x40000000 +#define RADEON_CP_VC_FRMT_Z 0x80000000 + +#define RADEON_CP_VC_CNTL_PRIM_TYPE_NONE 0x00000000 +#define RADEON_CP_VC_CNTL_PRIM_TYPE_POINT 0x00000001 +#define RADEON_CP_VC_CNTL_PRIM_TYPE_LINE 0x00000002 +#define RADEON_CP_VC_CNTL_PRIM_TYPE_LINE_STRIP 0x00000003 +#define RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_LIST 0x00000004 +#define RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_FAN 0x00000005 +#define RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_STRIP 0x00000006 +#define RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_TYPE_2 0x00000007 +#define RADEON_CP_VC_CNTL_PRIM_TYPE_RECT_LIST 0x00000008 +#define RADEON_CP_VC_CNTL_PRIM_TYPE_3VRT_POINT_LIST 0x00000009 +#define RADEON_CP_VC_CNTL_PRIM_TYPE_3VRT_LINE_LIST 0x0000000a +#define RADEON_CP_VC_CNTL_PRIM_WALK_IND 0x00000010 +#define RADEON_CP_VC_CNTL_PRIM_WALK_LIST 0x00000020 +#define RADEON_CP_VC_CNTL_PRIM_WALK_RING 0x00000030 +#define RADEON_CP_VC_CNTL_COLOR_ORDER_BGRA 0x00000000 +#define RADEON_CP_VC_CNTL_COLOR_ORDER_RGBA 0x00000040 +#define RADEON_CP_VC_CNTL_MAOS_ENABLE 0x00000080 +#define RADEON_CP_VC_CNTL_VTX_FMT_NON_RADEON_MODE 0x00000000 +#define RADEON_CP_VC_CNTL_VTX_FMT_RADEON_MODE 0x00000100 +#define RADEON_CP_VC_CNTL_TCL_DISABLE 0x00000000 +#define RADEON_CP_VC_CNTL_TCL_ENABLE 0x00000200 +#define RADEON_CP_VC_CNTL_NUM_SHIFT 16 + +#define RADEON_VS_MATRIX_0_ADDR 0 +#define RADEON_VS_MATRIX_1_ADDR 4 +#define RADEON_VS_MATRIX_2_ADDR 8 +#define RADEON_VS_MATRIX_3_ADDR 12 +#define RADEON_VS_MATRIX_4_ADDR 16 +#define RADEON_VS_MATRIX_5_ADDR 20 +#define RADEON_VS_MATRIX_6_ADDR 24 +#define RADEON_VS_MATRIX_7_ADDR 28 +#define RADEON_VS_MATRIX_8_ADDR 32 +#define RADEON_VS_MATRIX_9_ADDR 36 +#define RADEON_VS_MATRIX_10_ADDR 40 +#define RADEON_VS_MATRIX_11_ADDR 44 +#define RADEON_VS_MATRIX_12_ADDR 48 +#define RADEON_VS_MATRIX_13_ADDR 52 +#define RADEON_VS_MATRIX_14_ADDR 56 +#define RADEON_VS_MATRIX_15_ADDR 60 +#define RADEON_VS_LIGHT_AMBIENT_ADDR 64 +#define RADEON_VS_LIGHT_DIFFUSE_ADDR 72 +#define RADEON_VS_LIGHT_SPECULAR_ADDR 80 +#define RADEON_VS_LIGHT_DIRPOS_ADDR 88 +#define RADEON_VS_LIGHT_HWVSPOT_ADDR 96 +#define RADEON_VS_LIGHT_ATTENUATION_ADDR 104 +#define RADEON_VS_MATRIX_EYE2CLIP_ADDR 112 +#define RADEON_VS_UCP_ADDR 116 +#define RADEON_VS_GLOBAL_AMBIENT_ADDR 122 +#define RADEON_VS_FOG_PARAM_ADDR 123 +#define RADEON_VS_EYE_VECTOR_ADDR 124 + +#define RADEON_SS_LIGHT_DCD_ADDR 0 +#define RADEON_SS_LIGHT_SPOT_EXPONENT_ADDR 8 +#define RADEON_SS_LIGHT_SPOT_CUTOFF_ADDR 16 +#define RADEON_SS_LIGHT_SPECULAR_THRESH_ADDR 24 +#define RADEON_SS_LIGHT_RANGE_CUTOFF_ADDR 32 +#define RADEON_SS_VERT_GUARD_CLIP_ADJ_ADDR 48 +#define RADEON_SS_VERT_GUARD_DISCARD_ADJ_ADDR 49 +#define RADEON_SS_HORZ_GUARD_CLIP_ADJ_ADDR 50 +#define RADEON_SS_HORZ_GUARD_DISCARD_ADJ_ADDR 51 +#define RADEON_SS_SHININESS 60 + +#define RADEON_TV_MASTER_CNTL 0x0800 +# define RADEON_TV_ASYNC_RST (1 << 0) +# define RADEON_CRT_ASYNC_RST (1 << 1) +# define RADEON_RESTART_PHASE_FIX (1 << 3) +# define RADEON_TV_FIFO_ASYNC_RST (1 << 4) +# define RADEON_VIN_ASYNC_RST (1 << 5) +# define RADEON_AUD_ASYNC_RST (1 << 6) +# define RADEON_DVS_ASYNC_RST (1 << 7) +# define RADEON_CRT_FIFO_CE_EN (1 << 9) +# define RADEON_TV_FIFO_CE_EN (1 << 10) +# define RADEON_RE_SYNC_NOW_SEL_MASK (3 << 14) +# define RADEON_TVCLK_ALWAYS_ONb (1 << 30) +# define RADEON_TV_ON (1 << 31) +#define RADEON_TV_PRE_DAC_MUX_CNTL 0x0888 +# define RADEON_Y_RED_EN (1 << 0) +# define RADEON_C_GRN_EN (1 << 1) +# define RADEON_CMP_BLU_EN (1 << 2) +# define RADEON_DAC_DITHER_EN (1 << 3) +# define RADEON_RED_MX_FORCE_DAC_DATA (6 << 4) +# define RADEON_GRN_MX_FORCE_DAC_DATA (6 << 8) +# define RADEON_BLU_MX_FORCE_DAC_DATA (6 << 12) +# define RADEON_TV_FORCE_DAC_DATA_SHIFT 16 +#define RADEON_TV_RGB_CNTL 0x0804 +# define RADEON_SWITCH_TO_BLUE (1 << 4) +# define RADEON_RGB_DITHER_EN (1 << 5) +# define RADEON_RGB_SRC_SEL_MASK (3 << 8) +# define RADEON_RGB_SRC_SEL_CRTC1 (0 << 8) +# define RADEON_RGB_SRC_SEL_RMX (1 << 8) +# define RADEON_RGB_SRC_SEL_CRTC2 (2 << 8) +# define RADEON_RGB_CONVERT_BY_PASS (1 << 10) +# define RADEON_UVRAM_READ_MARGIN_SHIFT 16 +# define RADEON_FIFORAM_FFMACRO_READ_MARGIN_SHIFT 20 +# define RADEON_TVOUT_SCALE_EN (1 << 26) +#define RADEON_TV_SYNC_CNTL 0x0808 +# define RADEON_SYNC_OE (1 << 0) +# define RADEON_SYNC_OUT (1 << 1) +# define RADEON_SYNC_IN (1 << 2) +# define RADEON_SYNC_PUB (1 << 3) +# define RADEON_SYNC_PD (1 << 4) +# define RADEON_TV_SYNC_IO_DRIVE (1 << 5) +#define RADEON_TV_HTOTAL 0x080c +#define RADEON_TV_HDISP 0x0810 +#define RADEON_TV_HSTART 0x0818 +#define RADEON_TV_HCOUNT 0x081C +#define RADEON_TV_VTOTAL 0x0820 +#define RADEON_TV_VDISP 0x0824 +#define RADEON_TV_VCOUNT 0x0828 +#define RADEON_TV_FTOTAL 0x082c +#define RADEON_TV_FCOUNT 0x0830 +#define RADEON_TV_FRESTART 0x0834 +#define RADEON_TV_HRESTART 0x0838 +#define RADEON_TV_VRESTART 0x083c +#define RADEON_TV_HOST_READ_DATA 0x0840 +#define RADEON_TV_HOST_WRITE_DATA 0x0844 +#define RADEON_TV_HOST_RD_WT_CNTL 0x0848 +# define RADEON_HOST_FIFO_RD (1 << 12) +# define RADEON_HOST_FIFO_RD_ACK (1 << 13) +# define RADEON_HOST_FIFO_WT (1 << 14) +# define RADEON_HOST_FIFO_WT_ACK (1 << 15) +#define RADEON_TV_VSCALER_CNTL1 0x084c +# define RADEON_UV_INC_MASK 0xffff +# define RADEON_UV_INC_SHIFT 0 +# define RADEON_Y_W_EN (1 << 24) +# define RADEON_RESTART_FIELD (1 << 29) /* restart on field 0 */ +# define RADEON_Y_DEL_W_SIG_SHIFT 26 +#define RADEON_TV_TIMING_CNTL 0x0850 +# define RADEON_H_INC_MASK 0xfff +# define RADEON_H_INC_SHIFT 0 +# define RADEON_REQ_Y_FIRST (1 << 19) +# define RADEON_FORCE_BURST_ALWAYS (1 << 21) +# define RADEON_UV_POST_SCALE_BYPASS (1 << 23) +# define RADEON_UV_OUTPUT_POST_SCALE_SHIFT 24 +#define RADEON_TV_VSCALER_CNTL2 0x0854 +# define RADEON_DITHER_MODE (1 << 0) +# define RADEON_Y_OUTPUT_DITHER_EN (1 << 1) +# define RADEON_UV_OUTPUT_DITHER_EN (1 << 2) +# define RADEON_UV_TO_BUF_DITHER_EN (1 << 3) +#define RADEON_TV_Y_FALL_CNTL 0x0858 +# define RADEON_Y_FALL_PING_PONG (1 << 16) +# define RADEON_Y_COEF_EN (1 << 17) +#define RADEON_TV_Y_RISE_CNTL 0x085c +# define RADEON_Y_RISE_PING_PONG (1 << 16) +#define RADEON_TV_Y_SAW_TOOTH_CNTL 0x0860 +#define RADEON_TV_UPSAMP_AND_GAIN_CNTL 0x0864 +# define RADEON_YUPSAMP_EN (1 << 0) +# define RADEON_UVUPSAMP_EN (1 << 2) +#define RADEON_TV_GAIN_LIMIT_SETTINGS 0x0868 +# define RADEON_Y_GAIN_LIMIT_SHIFT 0 +# define RADEON_UV_GAIN_LIMIT_SHIFT 16 +#define RADEON_TV_LINEAR_GAIN_SETTINGS 0x086c +# define RADEON_Y_GAIN_SHIFT 0 +# define RADEON_UV_GAIN_SHIFT 16 +#define RADEON_TV_MODULATOR_CNTL1 0x0870 +# define RADEON_YFLT_EN (1 << 2) +# define RADEON_UVFLT_EN (1 << 3) +# define RADEON_ALT_PHASE_EN (1 << 6) +# define RADEON_SYNC_TIP_LEVEL (1 << 7) +# define RADEON_BLANK_LEVEL_SHIFT 8 +# define RADEON_SET_UP_LEVEL_SHIFT 16 +# define RADEON_SLEW_RATE_LIMIT (1 << 23) +# define RADEON_CY_FILT_BLEND_SHIFT 28 +#define RADEON_TV_MODULATOR_CNTL2 0x0874 +# define RADEON_TV_U_BURST_LEVEL_MASK 0x1ff +# define RADEON_TV_V_BURST_LEVEL_MASK 0x1ff +# define RADEON_TV_V_BURST_LEVEL_SHIFT 16 +#define RADEON_TV_CRC_CNTL 0x0890 +#define RADEON_TV_UV_ADR 0x08ac +# define RADEON_MAX_UV_ADR_MASK 0x000000ff +# define RADEON_MAX_UV_ADR_SHIFT 0 +# define RADEON_TABLE1_BOT_ADR_MASK 0x0000ff00 +# define RADEON_TABLE1_BOT_ADR_SHIFT 8 +# define RADEON_TABLE3_TOP_ADR_MASK 0x00ff0000 +# define RADEON_TABLE3_TOP_ADR_SHIFT 16 +# define RADEON_HCODE_TABLE_SEL_MASK 0x06000000 +# define RADEON_HCODE_TABLE_SEL_SHIFT 25 +# define RADEON_VCODE_TABLE_SEL_MASK 0x18000000 +# define RADEON_VCODE_TABLE_SEL_SHIFT 27 +# define RADEON_TV_MAX_FIFO_ADDR 0x1a7 +# define RADEON_TV_MAX_FIFO_ADDR_INTERNAL 0x1ff +#define RADEON_TV_PLL_FINE_CNTL 0x0020 /* PLL */ +#define RADEON_TV_PLL_CNTL 0x0021 /* PLL */ +# define RADEON_TV_M0LO_MASK 0xff +# define RADEON_TV_M0HI_MASK 0x7 +# define RADEON_TV_M0HI_SHIFT 18 +# define RADEON_TV_N0LO_MASK 0x1ff +# define RADEON_TV_N0LO_SHIFT 8 +# define RADEON_TV_N0HI_MASK 0x3 +# define RADEON_TV_N0HI_SHIFT 21 +# define RADEON_TV_P_MASK 0xf +# define RADEON_TV_P_SHIFT 24 +# define RADEON_TV_SLIP_EN (1 << 23) +# define RADEON_TV_DTO_EN (1 << 28) +#define RADEON_TV_PLL_CNTL1 0x0022 /* PLL */ +# define RADEON_TVPLL_RESET (1 << 1) +# define RADEON_TVPLL_SLEEP (1 << 3) +# define RADEON_TVPLL_REFCLK_SEL (1 << 4) +# define RADEON_TVPCP_SHIFT 8 +# define RADEON_TVPCP_MASK (7 << 8) +# define RADEON_TVPVG_SHIFT 11 +# define RADEON_TVPVG_MASK (7 << 11) +# define RADEON_TVPDC_SHIFT 14 +# define RADEON_TVPDC_MASK (3 << 14) +# define RADEON_TVPLL_TEST_DIS (1 << 31) +# define RADEON_TVCLK_SRC_SEL_TVPLL (1 << 30) + +#define RS400_DISP2_REQ_CNTL1 0xe30 +# define RS400_DISP2_START_REQ_LEVEL_SHIFT 0 +# define RS400_DISP2_START_REQ_LEVEL_MASK 0x3ff +# define RS400_DISP2_STOP_REQ_LEVEL_SHIFT 12 +# define RS400_DISP2_STOP_REQ_LEVEL_MASK 0x3ff +# define RS400_DISP2_ALLOW_FID_LEVEL_SHIFT 22 +# define RS400_DISP2_ALLOW_FID_LEVEL_MASK 0x3ff +#define RS400_DISP2_REQ_CNTL2 0xe34 +# define RS400_DISP2_CRITICAL_POINT_START_SHIFT 12 +# define RS400_DISP2_CRITICAL_POINT_START_MASK 0x3ff +# define RS400_DISP2_CRITICAL_POINT_STOP_SHIFT 22 +# define RS400_DISP2_CRITICAL_POINT_STOP_MASK 0x3ff +#define RS400_DMIF_MEM_CNTL1 0xe38 +# define RS400_DISP2_START_ADR_SHIFT 0 +# define RS400_DISP2_START_ADR_MASK 0x3ff +# define RS400_DISP1_CRITICAL_POINT_START_SHIFT 12 +# define RS400_DISP1_CRITICAL_POINT_START_MASK 0x3ff +# define RS400_DISP1_CRITICAL_POINT_STOP_SHIFT 22 +# define RS400_DISP1_CRITICAL_POINT_STOP_MASK 0x3ff +#define RS400_DISP1_REQ_CNTL1 0xe3c +# define RS400_DISP1_START_REQ_LEVEL_SHIFT 0 +# define RS400_DISP1_START_REQ_LEVEL_MASK 0x3ff +# define RS400_DISP1_STOP_REQ_LEVEL_SHIFT 12 +# define RS400_DISP1_STOP_REQ_LEVEL_MASK 0x3ff +# define RS400_DISP1_ALLOW_FID_LEVEL_SHIFT 22 +# define RS400_DISP1_ALLOW_FID_LEVEL_MASK 0x3ff + +#define RADEON_PCIE_INDEX 0x0030 +#define RADEON_PCIE_DATA 0x0034 +#define RADEON_PCIE_TX_GART_CNTL 0x10 +# define RADEON_PCIE_TX_GART_EN (1 << 0) +# define RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_PASS_THRU (0 << 1) +# define RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_CLAMP_LO (1 << 1) +# define RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_DISCARD (3 << 1) +# define RADEON_PCIE_TX_GART_MODE_32_128_CACHE (0 << 3) +# define RADEON_PCIE_TX_GART_MODE_8_4_128_CACHE (1 << 3) +# define RADEON_PCIE_TX_GART_CHK_RW_VALID_EN (1 << 5) +# define RADEON_PCIE_TX_GART_INVALIDATE_TLB (1 << 8) +#define RADEON_PCIE_TX_DISCARD_RD_ADDR_LO 0x11 +#define RADEON_PCIE_TX_DISCARD_RD_ADDR_HI 0x12 +#define RADEON_PCIE_TX_GART_BASE 0x13 +#define RADEON_PCIE_TX_GART_START_LO 0x14 +#define RADEON_PCIE_TX_GART_START_HI 0x15 +#define RADEON_PCIE_TX_GART_END_LO 0x16 +#define RADEON_PCIE_TX_GART_END_HI 0x17 +#define RADEON_PCIE_TX_GART_ERROR 0x18 + +#define RADEON_SCRATCH_REG0 0x15e0 +#define RADEON_SCRATCH_REG1 0x15e4 +#define RADEON_SCRATCH_REG2 0x15e8 +#define RADEON_SCRATCH_REG3 0x15ec +#define RADEON_SCRATCH_REG4 0x15f0 +#define RADEON_SCRATCH_REG5 0x15f4 + +#endif diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c new file mode 100644 index 000000000000..a853261d1881 --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_ring.c @@ -0,0 +1,485 @@ +/* + * Copyright 2008 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * Copyright 2009 Jerome Glisse. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Dave Airlie + * Alex Deucher + * Jerome Glisse + */ +#include +#include "drmP.h" +#include "radeon_drm.h" +#include "radeon_reg.h" +#include "radeon.h" +#include "atom.h" + +int radeon_debugfs_ib_init(struct radeon_device *rdev); + +/* + * IB. + */ +int radeon_ib_get(struct radeon_device *rdev, struct radeon_ib **ib) +{ + struct radeon_fence *fence; + struct radeon_ib *nib; + unsigned long i; + int r = 0; + + *ib = NULL; + r = radeon_fence_create(rdev, &fence); + if (r) { + DRM_ERROR("failed to create fence for new IB\n"); + return r; + } + mutex_lock(&rdev->ib_pool.mutex); + i = find_first_zero_bit(rdev->ib_pool.alloc_bm, RADEON_IB_POOL_SIZE); + if (i < RADEON_IB_POOL_SIZE) { + set_bit(i, rdev->ib_pool.alloc_bm); + rdev->ib_pool.ibs[i].length_dw = 0; + *ib = &rdev->ib_pool.ibs[i]; + goto out; + } + if (list_empty(&rdev->ib_pool.scheduled_ibs)) { + /* we go do nothings here */ + DRM_ERROR("all IB allocated none scheduled.\n"); + r = -EINVAL; + goto out; + } + /* get the first ib on the scheduled list */ + nib = list_entry(rdev->ib_pool.scheduled_ibs.next, + struct radeon_ib, list); + if (nib->fence == NULL) { + /* we go do nothings here */ + DRM_ERROR("IB %lu scheduled without a fence.\n", nib->idx); + r = -EINVAL; + goto out; + } + r = radeon_fence_wait(nib->fence, false); + if (r) { + DRM_ERROR("radeon: IB(%lu:0x%016lX:%u)\n", nib->idx, + (unsigned long)nib->gpu_addr, nib->length_dw); + DRM_ERROR("radeon: GPU lockup detected, fail to get a IB\n"); + goto out; + } + radeon_fence_unref(&nib->fence); + nib->length_dw = 0; + list_del(&nib->list); + INIT_LIST_HEAD(&nib->list); + *ib = nib; +out: + mutex_unlock(&rdev->ib_pool.mutex); + if (r) { + radeon_fence_unref(&fence); + } else { + (*ib)->fence = fence; + } + return r; +} + +void radeon_ib_free(struct radeon_device *rdev, struct radeon_ib **ib) +{ + struct radeon_ib *tmp = *ib; + + *ib = NULL; + if (tmp == NULL) { + return; + } + mutex_lock(&rdev->ib_pool.mutex); + if (!list_empty(&tmp->list) && !radeon_fence_signaled(tmp->fence)) { + /* IB is scheduled & not signaled don't do anythings */ + mutex_unlock(&rdev->ib_pool.mutex); + return; + } + list_del(&tmp->list); + INIT_LIST_HEAD(&tmp->list); + if (tmp->fence) { + radeon_fence_unref(&tmp->fence); + } + tmp->length_dw = 0; + clear_bit(tmp->idx, rdev->ib_pool.alloc_bm); + mutex_unlock(&rdev->ib_pool.mutex); +} + +static void radeon_ib_align(struct radeon_device *rdev, struct radeon_ib *ib) +{ + while ((ib->length_dw & rdev->cp.align_mask)) { + ib->ptr[ib->length_dw++] = PACKET2(0); + } +} + +static void radeon_ib_cpu_flush(struct radeon_device *rdev, + struct radeon_ib *ib) +{ + unsigned long tmp; + unsigned i; + + /* To force CPU cache flush ugly but seems reliable */ + for (i = 0; i < ib->length_dw; i += (rdev->cp.align_mask + 1)) { + tmp = readl(&ib->ptr[i]); + } +} + +int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib) +{ + int r = 0; + + mutex_lock(&rdev->ib_pool.mutex); + radeon_ib_align(rdev, ib); + radeon_ib_cpu_flush(rdev, ib); + if (!ib->length_dw || !rdev->cp.ready) { + /* TODO: Nothings in the ib we should report. */ + mutex_unlock(&rdev->ib_pool.mutex); + DRM_ERROR("radeon: couldn't schedule IB(%lu).\n", ib->idx); + return -EINVAL; + } + /* 64 dwords should be enought for fence too */ + r = radeon_ring_lock(rdev, 64); + if (r) { + DRM_ERROR("radeon: scheduling IB failled (%d).\n", r); + mutex_unlock(&rdev->ib_pool.mutex); + return r; + } + radeon_ring_write(rdev, PACKET0(RADEON_CP_IB_BASE, 1)); + radeon_ring_write(rdev, ib->gpu_addr); + radeon_ring_write(rdev, ib->length_dw); + radeon_fence_emit(rdev, ib->fence); + radeon_ring_unlock_commit(rdev); + list_add_tail(&ib->list, &rdev->ib_pool.scheduled_ibs); + mutex_unlock(&rdev->ib_pool.mutex); + return 0; +} + +int radeon_ib_pool_init(struct radeon_device *rdev) +{ + void *ptr; + uint64_t gpu_addr; + int i; + int r = 0; + + /* Allocate 1M object buffer */ + INIT_LIST_HEAD(&rdev->ib_pool.scheduled_ibs); + r = radeon_object_create(rdev, NULL, RADEON_IB_POOL_SIZE*64*1024, + true, RADEON_GEM_DOMAIN_GTT, + false, &rdev->ib_pool.robj); + if (r) { + DRM_ERROR("radeon: failed to ib pool (%d).\n", r); + return r; + } + r = radeon_object_pin(rdev->ib_pool.robj, RADEON_GEM_DOMAIN_GTT, &gpu_addr); + if (r) { + DRM_ERROR("radeon: failed to pin ib pool (%d).\n", r); + return r; + } + r = radeon_object_kmap(rdev->ib_pool.robj, &ptr); + if (r) { + DRM_ERROR("radeon: failed to map ib poll (%d).\n", r); + return r; + } + for (i = 0; i < RADEON_IB_POOL_SIZE; i++) { + unsigned offset; + + offset = i * 64 * 1024; + rdev->ib_pool.ibs[i].gpu_addr = gpu_addr + offset; + rdev->ib_pool.ibs[i].ptr = ptr + offset; + rdev->ib_pool.ibs[i].idx = i; + rdev->ib_pool.ibs[i].length_dw = 0; + INIT_LIST_HEAD(&rdev->ib_pool.ibs[i].list); + } + bitmap_zero(rdev->ib_pool.alloc_bm, RADEON_IB_POOL_SIZE); + rdev->ib_pool.ready = true; + DRM_INFO("radeon: ib pool ready.\n"); + if (radeon_debugfs_ib_init(rdev)) { + DRM_ERROR("Failed to register debugfs file for IB !\n"); + } + return r; +} + +void radeon_ib_pool_fini(struct radeon_device *rdev) +{ + if (!rdev->ib_pool.ready) { + return; + } + mutex_lock(&rdev->ib_pool.mutex); + bitmap_zero(rdev->ib_pool.alloc_bm, RADEON_IB_POOL_SIZE); + if (rdev->ib_pool.robj) { + radeon_object_kunmap(rdev->ib_pool.robj); + radeon_object_unref(&rdev->ib_pool.robj); + rdev->ib_pool.robj = NULL; + } + mutex_unlock(&rdev->ib_pool.mutex); +} + +int radeon_ib_test(struct radeon_device *rdev) +{ + struct radeon_ib *ib; + uint32_t scratch; + uint32_t tmp = 0; + unsigned i; + int r; + + r = radeon_scratch_get(rdev, &scratch); + if (r) { + DRM_ERROR("radeon: failed to get scratch reg (%d).\n", r); + return r; + } + WREG32(scratch, 0xCAFEDEAD); + r = radeon_ib_get(rdev, &ib); + if (r) { + return r; + } + ib->ptr[0] = PACKET0(scratch, 0); + ib->ptr[1] = 0xDEADBEEF; + ib->ptr[2] = PACKET2(0); + ib->ptr[3] = PACKET2(0); + ib->ptr[4] = PACKET2(0); + ib->ptr[5] = PACKET2(0); + ib->ptr[6] = PACKET2(0); + ib->ptr[7] = PACKET2(0); + ib->length_dw = 8; + r = radeon_ib_schedule(rdev, ib); + if (r) { + radeon_scratch_free(rdev, scratch); + radeon_ib_free(rdev, &ib); + return r; + } + r = radeon_fence_wait(ib->fence, false); + if (r) { + return r; + } + for (i = 0; i < rdev->usec_timeout; i++) { + tmp = RREG32(scratch); + if (tmp == 0xDEADBEEF) { + break; + } + DRM_UDELAY(1); + } + if (i < rdev->usec_timeout) { + DRM_INFO("ib test succeeded in %u usecs\n", i); + } else { + DRM_ERROR("radeon: ib test failed (sracth(0x%04X)=0x%08X)\n", + scratch, tmp); + r = -EINVAL; + } + radeon_scratch_free(rdev, scratch); + radeon_ib_free(rdev, &ib); + return r; +} + + +/* + * Ring. + */ +void radeon_ring_free_size(struct radeon_device *rdev) +{ + rdev->cp.rptr = RREG32(RADEON_CP_RB_RPTR); + /* This works because ring_size is a power of 2 */ + rdev->cp.ring_free_dw = (rdev->cp.rptr + (rdev->cp.ring_size / 4)); + rdev->cp.ring_free_dw -= rdev->cp.wptr; + rdev->cp.ring_free_dw &= rdev->cp.ptr_mask; + if (!rdev->cp.ring_free_dw) { + rdev->cp.ring_free_dw = rdev->cp.ring_size / 4; + } +} + +int radeon_ring_lock(struct radeon_device *rdev, unsigned ndw) +{ + int r; + + /* Align requested size with padding so unlock_commit can + * pad safely */ + ndw = (ndw + rdev->cp.align_mask) & ~rdev->cp.align_mask; + mutex_lock(&rdev->cp.mutex); + while (ndw > (rdev->cp.ring_free_dw - 1)) { + radeon_ring_free_size(rdev); + if (ndw < rdev->cp.ring_free_dw) { + break; + } + r = radeon_fence_wait_next(rdev); + if (r) { + mutex_unlock(&rdev->cp.mutex); + return r; + } + } + rdev->cp.count_dw = ndw; + rdev->cp.wptr_old = rdev->cp.wptr; + return 0; +} + +void radeon_ring_unlock_commit(struct radeon_device *rdev) +{ + unsigned count_dw_pad; + unsigned i; + + /* We pad to match fetch size */ + count_dw_pad = (rdev->cp.align_mask + 1) - + (rdev->cp.wptr & rdev->cp.align_mask); + for (i = 0; i < count_dw_pad; i++) { + radeon_ring_write(rdev, PACKET2(0)); + } + DRM_MEMORYBARRIER(); + WREG32(RADEON_CP_RB_WPTR, rdev->cp.wptr); + (void)RREG32(RADEON_CP_RB_WPTR); + mutex_unlock(&rdev->cp.mutex); +} + +void radeon_ring_unlock_undo(struct radeon_device *rdev) +{ + rdev->cp.wptr = rdev->cp.wptr_old; + mutex_unlock(&rdev->cp.mutex); +} + +int radeon_ring_test(struct radeon_device *rdev) +{ + uint32_t scratch; + uint32_t tmp = 0; + unsigned i; + int r; + + r = radeon_scratch_get(rdev, &scratch); + if (r) { + DRM_ERROR("radeon: cp failed to get scratch reg (%d).\n", r); + return r; + } + WREG32(scratch, 0xCAFEDEAD); + r = radeon_ring_lock(rdev, 2); + if (r) { + DRM_ERROR("radeon: cp failed to lock ring (%d).\n", r); + radeon_scratch_free(rdev, scratch); + return r; + } + radeon_ring_write(rdev, PACKET0(scratch, 0)); + radeon_ring_write(rdev, 0xDEADBEEF); + radeon_ring_unlock_commit(rdev); + for (i = 0; i < rdev->usec_timeout; i++) { + tmp = RREG32(scratch); + if (tmp == 0xDEADBEEF) { + break; + } + DRM_UDELAY(1); + } + if (i < rdev->usec_timeout) { + DRM_INFO("ring test succeeded in %d usecs\n", i); + } else { + DRM_ERROR("radeon: ring test failed (sracth(0x%04X)=0x%08X)\n", + scratch, tmp); + r = -EINVAL; + } + radeon_scratch_free(rdev, scratch); + return r; +} + +int radeon_ring_init(struct radeon_device *rdev, unsigned ring_size) +{ + int r; + + rdev->cp.ring_size = ring_size; + /* Allocate ring buffer */ + if (rdev->cp.ring_obj == NULL) { + r = radeon_object_create(rdev, NULL, rdev->cp.ring_size, + true, + RADEON_GEM_DOMAIN_GTT, + false, + &rdev->cp.ring_obj); + if (r) { + DRM_ERROR("radeon: failed to create ring buffer (%d).\n", r); + mutex_unlock(&rdev->cp.mutex); + return r; + } + r = radeon_object_pin(rdev->cp.ring_obj, + RADEON_GEM_DOMAIN_GTT, + &rdev->cp.gpu_addr); + if (r) { + DRM_ERROR("radeon: failed to pin ring buffer (%d).\n", r); + mutex_unlock(&rdev->cp.mutex); + return r; + } + r = radeon_object_kmap(rdev->cp.ring_obj, + (void **)&rdev->cp.ring); + if (r) { + DRM_ERROR("radeon: failed to map ring buffer (%d).\n", r); + mutex_unlock(&rdev->cp.mutex); + return r; + } + } + rdev->cp.ptr_mask = (rdev->cp.ring_size / 4) - 1; + rdev->cp.ring_free_dw = rdev->cp.ring_size / 4; + return 0; +} + +void radeon_ring_fini(struct radeon_device *rdev) +{ + mutex_lock(&rdev->cp.mutex); + if (rdev->cp.ring_obj) { + radeon_object_kunmap(rdev->cp.ring_obj); + radeon_object_unpin(rdev->cp.ring_obj); + radeon_object_unref(&rdev->cp.ring_obj); + rdev->cp.ring = NULL; + rdev->cp.ring_obj = NULL; + } + mutex_unlock(&rdev->cp.mutex); +} + + +/* + * Debugfs info + */ +#if defined(CONFIG_DEBUG_FS) +static int radeon_debugfs_ib_info(struct seq_file *m, void *data) +{ + struct drm_info_node *node = (struct drm_info_node *) m->private; + struct radeon_ib *ib = node->info_ent->data; + unsigned i; + + if (ib == NULL) { + return 0; + } + seq_printf(m, "IB %04lu\n", ib->idx); + seq_printf(m, "IB fence %p\n", ib->fence); + seq_printf(m, "IB size %05u dwords\n", ib->length_dw); + for (i = 0; i < ib->length_dw; i++) { + seq_printf(m, "[%05u]=0x%08X\n", i, ib->ptr[i]); + } + return 0; +} + +static struct drm_info_list radeon_debugfs_ib_list[RADEON_IB_POOL_SIZE]; +static char radeon_debugfs_ib_names[RADEON_IB_POOL_SIZE][32]; +#endif + +int radeon_debugfs_ib_init(struct radeon_device *rdev) +{ +#if defined(CONFIG_DEBUG_FS) + unsigned i; + + for (i = 0; i < RADEON_IB_POOL_SIZE; i++) { + sprintf(radeon_debugfs_ib_names[i], "radeon_ib_%04u", i); + radeon_debugfs_ib_list[i].name = radeon_debugfs_ib_names[i]; + radeon_debugfs_ib_list[i].show = &radeon_debugfs_ib_info; + radeon_debugfs_ib_list[i].driver_features = 0; + radeon_debugfs_ib_list[i].data = &rdev->ib_pool.ibs[i]; + } + return radeon_debugfs_add_files(rdev, radeon_debugfs_ib_list, + RADEON_IB_POOL_SIZE); +#else + return 0; +#endif +} diff --git a/drivers/gpu/drm/radeon/radeon_state.c b/drivers/gpu/drm/radeon/radeon_state.c index fa728ec6ed34..46645f3e0328 100644 --- a/drivers/gpu/drm/radeon/radeon_state.c +++ b/drivers/gpu/drm/radeon/radeon_state.c @@ -2866,12 +2866,12 @@ static int radeon_cp_cmdbuf(struct drm_device *dev, void *data, struct drm_file */ orig_bufsz = cmdbuf->bufsz; if (orig_bufsz != 0) { - kbuf = drm_alloc(cmdbuf->bufsz, DRM_MEM_DRIVER); + kbuf = kmalloc(cmdbuf->bufsz, GFP_KERNEL); if (kbuf == NULL) return -ENOMEM; if (DRM_COPY_FROM_USER(kbuf, (void __user *)cmdbuf->buf, cmdbuf->bufsz)) { - drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER); + kfree(kbuf); return -EFAULT; } cmdbuf->buf = kbuf; @@ -2884,7 +2884,7 @@ static int radeon_cp_cmdbuf(struct drm_device *dev, void *data, struct drm_file temp = r300_do_cp_cmdbuf(dev, file_priv, cmdbuf); if (orig_bufsz != 0) - drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER); + kfree(kbuf); return temp; } @@ -2991,7 +2991,7 @@ static int radeon_cp_cmdbuf(struct drm_device *dev, void *data, struct drm_file } if (orig_bufsz != 0) - drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER); + kfree(kbuf); DRM_DEBUG("DONE\n"); COMMIT_RING(); @@ -2999,7 +2999,7 @@ static int radeon_cp_cmdbuf(struct drm_device *dev, void *data, struct drm_file err: if (orig_bufsz != 0) - drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER); + kfree(kbuf); return -EINVAL; } @@ -3175,9 +3175,7 @@ int radeon_driver_open(struct drm_device *dev, struct drm_file *file_priv) struct drm_radeon_driver_file_fields *radeon_priv; DRM_DEBUG("\n"); - radeon_priv = - (struct drm_radeon_driver_file_fields *) - drm_alloc(sizeof(*radeon_priv), DRM_MEM_FILES); + radeon_priv = kmalloc(sizeof(*radeon_priv), GFP_KERNEL); if (!radeon_priv) return -ENOMEM; @@ -3196,7 +3194,7 @@ void radeon_driver_postclose(struct drm_device *dev, struct drm_file *file_priv) struct drm_radeon_driver_file_fields *radeon_priv = file_priv->driver_priv; - drm_free(radeon_priv, sizeof(*radeon_priv), DRM_MEM_FILES); + kfree(radeon_priv); } struct drm_ioctl_desc radeon_ioctls[] = { diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c new file mode 100644 index 000000000000..1227a97f5169 --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_ttm.c @@ -0,0 +1,653 @@ +/* + * Copyright 2009 Jerome Glisse. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + */ +/* + * Authors: + * Jerome Glisse + * Thomas Hellstrom + * Dave Airlie + */ +#include +#include +#include +#include +#include +#include +#include "radeon_reg.h" +#include "radeon.h" + +#define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT) + +static struct radeon_device *radeon_get_rdev(struct ttm_bo_device *bdev) +{ + struct radeon_mman *mman; + struct radeon_device *rdev; + + mman = container_of(bdev, struct radeon_mman, bdev); + rdev = container_of(mman, struct radeon_device, mman); + return rdev; +} + + +/* + * Global memory. + */ +static int radeon_ttm_mem_global_init(struct ttm_global_reference *ref) +{ + return ttm_mem_global_init(ref->object); +} + +static void radeon_ttm_mem_global_release(struct ttm_global_reference *ref) +{ + ttm_mem_global_release(ref->object); +} + +static int radeon_ttm_global_init(struct radeon_device *rdev) +{ + struct ttm_global_reference *global_ref; + int r; + + rdev->mman.mem_global_referenced = false; + global_ref = &rdev->mman.mem_global_ref; + global_ref->global_type = TTM_GLOBAL_TTM_MEM; + global_ref->size = sizeof(struct ttm_mem_global); + global_ref->init = &radeon_ttm_mem_global_init; + global_ref->release = &radeon_ttm_mem_global_release; + r = ttm_global_item_ref(global_ref); + if (r != 0) { + DRM_ERROR("Failed referencing a global TTM memory object.\n"); + return r; + } + rdev->mman.mem_global_referenced = true; + return 0; +} + +static void radeon_ttm_global_fini(struct radeon_device *rdev) +{ + if (rdev->mman.mem_global_referenced) { + ttm_global_item_unref(&rdev->mman.mem_global_ref); + rdev->mman.mem_global_referenced = false; + } +} + +struct ttm_backend *radeon_ttm_backend_create(struct radeon_device *rdev); + +static struct ttm_backend* +radeon_create_ttm_backend_entry(struct ttm_bo_device *bdev) +{ + struct radeon_device *rdev; + + rdev = radeon_get_rdev(bdev); +#if __OS_HAS_AGP + if (rdev->flags & RADEON_IS_AGP) { + return ttm_agp_backend_init(bdev, rdev->ddev->agp->bridge); + } else +#endif + { + return radeon_ttm_backend_create(rdev); + } +} + +static int radeon_invalidate_caches(struct ttm_bo_device *bdev, uint32_t flags) +{ + return 0; +} + +static int radeon_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, + struct ttm_mem_type_manager *man) +{ + struct radeon_device *rdev; + + rdev = radeon_get_rdev(bdev); + + switch (type) { + case TTM_PL_SYSTEM: + /* System memory */ + man->flags = TTM_MEMTYPE_FLAG_MAPPABLE; + man->available_caching = TTM_PL_MASK_CACHING; + man->default_caching = TTM_PL_FLAG_CACHED; + break; + case TTM_PL_TT: + man->gpu_offset = 0; + man->available_caching = TTM_PL_MASK_CACHING; + man->default_caching = TTM_PL_FLAG_CACHED; + man->flags = TTM_MEMTYPE_FLAG_MAPPABLE | TTM_MEMTYPE_FLAG_CMA; +#if __OS_HAS_AGP + if (rdev->flags & RADEON_IS_AGP) { + if (!(drm_core_has_AGP(rdev->ddev) && rdev->ddev->agp)) { + DRM_ERROR("AGP is not enabled for memory type %u\n", + (unsigned)type); + return -EINVAL; + } + man->io_offset = rdev->mc.agp_base; + man->io_size = rdev->mc.gtt_size; + man->io_addr = NULL; + if (!rdev->ddev->agp->cant_use_aperture) + man->flags = TTM_MEMTYPE_FLAG_NEEDS_IOREMAP | + TTM_MEMTYPE_FLAG_MAPPABLE; + man->available_caching = TTM_PL_FLAG_UNCACHED | + TTM_PL_FLAG_WC; + man->default_caching = TTM_PL_FLAG_WC; + } else +#endif + { + man->io_offset = 0; + man->io_size = 0; + man->io_addr = NULL; + } + break; + case TTM_PL_VRAM: + /* "On-card" video ram */ + man->gpu_offset = 0; + man->flags = TTM_MEMTYPE_FLAG_FIXED | + TTM_MEMTYPE_FLAG_NEEDS_IOREMAP | + TTM_MEMTYPE_FLAG_MAPPABLE; + man->available_caching = TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_WC; + man->default_caching = TTM_PL_FLAG_WC; + man->io_addr = NULL; + man->io_offset = rdev->mc.aper_base; + man->io_size = rdev->mc.aper_size; + break; + default: + DRM_ERROR("Unsupported memory type %u\n", (unsigned)type); + return -EINVAL; + } + return 0; +} + +static uint32_t radeon_evict_flags(struct ttm_buffer_object *bo) +{ + uint32_t cur_placement = bo->mem.placement & ~TTM_PL_MASK_MEMTYPE; + + switch (bo->mem.mem_type) { + default: + return (cur_placement & ~TTM_PL_MASK_CACHING) | + TTM_PL_FLAG_SYSTEM | + TTM_PL_FLAG_CACHED; + } +} + +static int radeon_verify_access(struct ttm_buffer_object *bo, struct file *filp) +{ + return 0; +} + +static void radeon_move_null(struct ttm_buffer_object *bo, + struct ttm_mem_reg *new_mem) +{ + struct ttm_mem_reg *old_mem = &bo->mem; + + BUG_ON(old_mem->mm_node != NULL); + *old_mem = *new_mem; + new_mem->mm_node = NULL; +} + +static int radeon_move_blit(struct ttm_buffer_object *bo, + bool evict, int no_wait, + struct ttm_mem_reg *new_mem, + struct ttm_mem_reg *old_mem) +{ + struct radeon_device *rdev; + uint64_t old_start, new_start; + struct radeon_fence *fence; + int r; + + rdev = radeon_get_rdev(bo->bdev); + r = radeon_fence_create(rdev, &fence); + if (unlikely(r)) { + return r; + } + old_start = old_mem->mm_node->start << PAGE_SHIFT; + new_start = new_mem->mm_node->start << PAGE_SHIFT; + + switch (old_mem->mem_type) { + case TTM_PL_VRAM: + old_start += rdev->mc.vram_location; + break; + case TTM_PL_TT: + old_start += rdev->mc.gtt_location; + break; + default: + DRM_ERROR("Unknown placement %d\n", old_mem->mem_type); + return -EINVAL; + } + switch (new_mem->mem_type) { + case TTM_PL_VRAM: + new_start += rdev->mc.vram_location; + break; + case TTM_PL_TT: + new_start += rdev->mc.gtt_location; + break; + default: + DRM_ERROR("Unknown placement %d\n", old_mem->mem_type); + return -EINVAL; + } + if (!rdev->cp.ready) { + DRM_ERROR("Trying to move memory with CP turned off.\n"); + return -EINVAL; + } + r = radeon_copy(rdev, old_start, new_start, new_mem->num_pages, fence); + /* FIXME: handle copy error */ + r = ttm_bo_move_accel_cleanup(bo, (void *)fence, NULL, + evict, no_wait, new_mem); + radeon_fence_unref(&fence); + return r; +} + +static int radeon_move_vram_ram(struct ttm_buffer_object *bo, + bool evict, bool interruptible, bool no_wait, + struct ttm_mem_reg *new_mem) +{ + struct radeon_device *rdev; + struct ttm_mem_reg *old_mem = &bo->mem; + struct ttm_mem_reg tmp_mem; + uint32_t proposed_placement; + int r; + + rdev = radeon_get_rdev(bo->bdev); + tmp_mem = *new_mem; + tmp_mem.mm_node = NULL; + proposed_placement = TTM_PL_FLAG_TT | TTM_PL_MASK_CACHING; + r = ttm_bo_mem_space(bo, proposed_placement, &tmp_mem, + interruptible, no_wait); + if (unlikely(r)) { + return r; + } + r = ttm_tt_bind(bo->ttm, &tmp_mem); + if (unlikely(r)) { + goto out_cleanup; + } + r = radeon_move_blit(bo, true, no_wait, &tmp_mem, old_mem); + if (unlikely(r)) { + goto out_cleanup; + } + r = ttm_bo_move_ttm(bo, true, no_wait, new_mem); +out_cleanup: + if (tmp_mem.mm_node) { + spin_lock(&rdev->mman.bdev.lru_lock); + drm_mm_put_block(tmp_mem.mm_node); + spin_unlock(&rdev->mman.bdev.lru_lock); + return r; + } + return r; +} + +static int radeon_move_ram_vram(struct ttm_buffer_object *bo, + bool evict, bool interruptible, bool no_wait, + struct ttm_mem_reg *new_mem) +{ + struct radeon_device *rdev; + struct ttm_mem_reg *old_mem = &bo->mem; + struct ttm_mem_reg tmp_mem; + uint32_t proposed_flags; + int r; + + rdev = radeon_get_rdev(bo->bdev); + tmp_mem = *new_mem; + tmp_mem.mm_node = NULL; + proposed_flags = TTM_PL_FLAG_TT | TTM_PL_MASK_CACHING; + r = ttm_bo_mem_space(bo, proposed_flags, &tmp_mem, + interruptible, no_wait); + if (unlikely(r)) { + return r; + } + r = ttm_bo_move_ttm(bo, true, no_wait, &tmp_mem); + if (unlikely(r)) { + goto out_cleanup; + } + r = radeon_move_blit(bo, true, no_wait, new_mem, old_mem); + if (unlikely(r)) { + goto out_cleanup; + } +out_cleanup: + if (tmp_mem.mm_node) { + spin_lock(&rdev->mman.bdev.lru_lock); + drm_mm_put_block(tmp_mem.mm_node); + spin_unlock(&rdev->mman.bdev.lru_lock); + return r; + } + return r; +} + +static int radeon_bo_move(struct ttm_buffer_object *bo, + bool evict, bool interruptible, bool no_wait, + struct ttm_mem_reg *new_mem) +{ + struct radeon_device *rdev; + struct ttm_mem_reg *old_mem = &bo->mem; + int r; + + rdev = radeon_get_rdev(bo->bdev); + if (old_mem->mem_type == TTM_PL_SYSTEM && bo->ttm == NULL) { + radeon_move_null(bo, new_mem); + return 0; + } + if ((old_mem->mem_type == TTM_PL_TT && + new_mem->mem_type == TTM_PL_SYSTEM) || + (old_mem->mem_type == TTM_PL_SYSTEM && + new_mem->mem_type == TTM_PL_TT)) { + /* bind is enought */ + radeon_move_null(bo, new_mem); + return 0; + } + if (!rdev->cp.ready) { + /* use memcpy */ + DRM_ERROR("CP is not ready use memcpy.\n"); + return ttm_bo_move_memcpy(bo, evict, no_wait, new_mem); + } + + if (old_mem->mem_type == TTM_PL_VRAM && + new_mem->mem_type == TTM_PL_SYSTEM) { + return radeon_move_vram_ram(bo, evict, interruptible, + no_wait, new_mem); + } else if (old_mem->mem_type == TTM_PL_SYSTEM && + new_mem->mem_type == TTM_PL_VRAM) { + return radeon_move_ram_vram(bo, evict, interruptible, + no_wait, new_mem); + } else { + r = radeon_move_blit(bo, evict, no_wait, new_mem, old_mem); + if (unlikely(r)) { + return r; + } + } + return r; +} + +const uint32_t radeon_mem_prios[] = { + TTM_PL_VRAM, + TTM_PL_TT, + TTM_PL_SYSTEM, +}; + +const uint32_t radeon_busy_prios[] = { + TTM_PL_TT, + TTM_PL_VRAM, + TTM_PL_SYSTEM, +}; + +static int radeon_sync_obj_wait(void *sync_obj, void *sync_arg, + bool lazy, bool interruptible) +{ + return radeon_fence_wait((struct radeon_fence *)sync_obj, interruptible); +} + +static int radeon_sync_obj_flush(void *sync_obj, void *sync_arg) +{ + return 0; +} + +static void radeon_sync_obj_unref(void **sync_obj) +{ + radeon_fence_unref((struct radeon_fence **)sync_obj); +} + +static void *radeon_sync_obj_ref(void *sync_obj) +{ + return radeon_fence_ref((struct radeon_fence *)sync_obj); +} + +static bool radeon_sync_obj_signaled(void *sync_obj, void *sync_arg) +{ + return radeon_fence_signaled((struct radeon_fence *)sync_obj); +} + +static struct ttm_bo_driver radeon_bo_driver = { + .mem_type_prio = radeon_mem_prios, + .mem_busy_prio = radeon_busy_prios, + .num_mem_type_prio = ARRAY_SIZE(radeon_mem_prios), + .num_mem_busy_prio = ARRAY_SIZE(radeon_busy_prios), + .create_ttm_backend_entry = &radeon_create_ttm_backend_entry, + .invalidate_caches = &radeon_invalidate_caches, + .init_mem_type = &radeon_init_mem_type, + .evict_flags = &radeon_evict_flags, + .move = &radeon_bo_move, + .verify_access = &radeon_verify_access, + .sync_obj_signaled = &radeon_sync_obj_signaled, + .sync_obj_wait = &radeon_sync_obj_wait, + .sync_obj_flush = &radeon_sync_obj_flush, + .sync_obj_unref = &radeon_sync_obj_unref, + .sync_obj_ref = &radeon_sync_obj_ref, +}; + +int radeon_ttm_init(struct radeon_device *rdev) +{ + int r; + + r = radeon_ttm_global_init(rdev); + if (r) { + return r; + } + /* No others user of address space so set it to 0 */ + r = ttm_bo_device_init(&rdev->mman.bdev, + rdev->mman.mem_global_ref.object, + &radeon_bo_driver, DRM_FILE_PAGE_OFFSET); + if (r) { + DRM_ERROR("failed initializing buffer object driver(%d).\n", r); + return r; + } + r = ttm_bo_init_mm(&rdev->mman.bdev, TTM_PL_VRAM, 0, + ((rdev->mc.aper_size) >> PAGE_SHIFT)); + if (r) { + DRM_ERROR("Failed initializing VRAM heap.\n"); + return r; + } + r = radeon_object_create(rdev, NULL, 256 * 1024, true, + RADEON_GEM_DOMAIN_VRAM, false, + &rdev->stollen_vga_memory); + if (r) { + return r; + } + r = radeon_object_pin(rdev->stollen_vga_memory, RADEON_GEM_DOMAIN_VRAM, NULL); + if (r) { + radeon_object_unref(&rdev->stollen_vga_memory); + return r; + } + DRM_INFO("radeon: %uM of VRAM memory ready\n", + rdev->mc.vram_size / (1024 * 1024)); + r = ttm_bo_init_mm(&rdev->mman.bdev, TTM_PL_TT, 0, + ((rdev->mc.gtt_size) >> PAGE_SHIFT)); + if (r) { + DRM_ERROR("Failed initializing GTT heap.\n"); + return r; + } + DRM_INFO("radeon: %uM of GTT memory ready.\n", + rdev->mc.gtt_size / (1024 * 1024)); + if (unlikely(rdev->mman.bdev.dev_mapping == NULL)) { + rdev->mman.bdev.dev_mapping = rdev->ddev->dev_mapping; + } + return 0; +} + +void radeon_ttm_fini(struct radeon_device *rdev) +{ + if (rdev->stollen_vga_memory) { + radeon_object_unpin(rdev->stollen_vga_memory); + radeon_object_unref(&rdev->stollen_vga_memory); + } + ttm_bo_clean_mm(&rdev->mman.bdev, TTM_PL_VRAM); + ttm_bo_clean_mm(&rdev->mman.bdev, TTM_PL_TT); + ttm_bo_device_release(&rdev->mman.bdev); + radeon_gart_fini(rdev); + radeon_ttm_global_fini(rdev); + DRM_INFO("radeon: ttm finalized\n"); +} + +static struct vm_operations_struct radeon_ttm_vm_ops; +static struct vm_operations_struct *ttm_vm_ops = NULL; + +static int radeon_ttm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) +{ + struct ttm_buffer_object *bo; + int r; + + bo = (struct ttm_buffer_object *)vma->vm_private_data; + if (bo == NULL) { + return VM_FAULT_NOPAGE; + } + r = ttm_vm_ops->fault(vma, vmf); + return r; +} + +int radeon_mmap(struct file *filp, struct vm_area_struct *vma) +{ + struct drm_file *file_priv; + struct radeon_device *rdev; + int r; + + if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET)) { + return drm_mmap(filp, vma); + } + + file_priv = (struct drm_file *)filp->private_data; + rdev = file_priv->minor->dev->dev_private; + if (rdev == NULL) { + return -EINVAL; + } + r = ttm_bo_mmap(filp, vma, &rdev->mman.bdev); + if (unlikely(r != 0)) { + return r; + } + if (unlikely(ttm_vm_ops == NULL)) { + ttm_vm_ops = vma->vm_ops; + radeon_ttm_vm_ops = *ttm_vm_ops; + radeon_ttm_vm_ops.fault = &radeon_ttm_fault; + } + vma->vm_ops = &radeon_ttm_vm_ops; + return 0; +} + + +/* + * TTM backend functions. + */ +struct radeon_ttm_backend { + struct ttm_backend backend; + struct radeon_device *rdev; + unsigned long num_pages; + struct page **pages; + struct page *dummy_read_page; + bool populated; + bool bound; + unsigned offset; +}; + +static int radeon_ttm_backend_populate(struct ttm_backend *backend, + unsigned long num_pages, + struct page **pages, + struct page *dummy_read_page) +{ + struct radeon_ttm_backend *gtt; + + gtt = container_of(backend, struct radeon_ttm_backend, backend); + gtt->pages = pages; + gtt->num_pages = num_pages; + gtt->dummy_read_page = dummy_read_page; + gtt->populated = true; + return 0; +} + +static void radeon_ttm_backend_clear(struct ttm_backend *backend) +{ + struct radeon_ttm_backend *gtt; + + gtt = container_of(backend, struct radeon_ttm_backend, backend); + gtt->pages = NULL; + gtt->num_pages = 0; + gtt->dummy_read_page = NULL; + gtt->populated = false; + gtt->bound = false; +} + + +static int radeon_ttm_backend_bind(struct ttm_backend *backend, + struct ttm_mem_reg *bo_mem) +{ + struct radeon_ttm_backend *gtt; + int r; + + gtt = container_of(backend, struct radeon_ttm_backend, backend); + gtt->offset = bo_mem->mm_node->start << PAGE_SHIFT; + if (!gtt->num_pages) { + WARN(1, "nothing to bind %lu pages for mreg %p back %p!\n", gtt->num_pages, bo_mem, backend); + } + r = radeon_gart_bind(gtt->rdev, gtt->offset, + gtt->num_pages, gtt->pages); + if (r) { + DRM_ERROR("failed to bind %lu pages at 0x%08X\n", + gtt->num_pages, gtt->offset); + return r; + } + gtt->bound = true; + return 0; +} + +static int radeon_ttm_backend_unbind(struct ttm_backend *backend) +{ + struct radeon_ttm_backend *gtt; + + gtt = container_of(backend, struct radeon_ttm_backend, backend); + radeon_gart_unbind(gtt->rdev, gtt->offset, gtt->num_pages); + gtt->bound = false; + return 0; +} + +static void radeon_ttm_backend_destroy(struct ttm_backend *backend) +{ + struct radeon_ttm_backend *gtt; + + gtt = container_of(backend, struct radeon_ttm_backend, backend); + if (gtt->bound) { + radeon_ttm_backend_unbind(backend); + } + kfree(gtt); +} + +static struct ttm_backend_func radeon_backend_func = { + .populate = &radeon_ttm_backend_populate, + .clear = &radeon_ttm_backend_clear, + .bind = &radeon_ttm_backend_bind, + .unbind = &radeon_ttm_backend_unbind, + .destroy = &radeon_ttm_backend_destroy, +}; + +struct ttm_backend *radeon_ttm_backend_create(struct radeon_device *rdev) +{ + struct radeon_ttm_backend *gtt; + + gtt = kzalloc(sizeof(struct radeon_ttm_backend), GFP_KERNEL); + if (gtt == NULL) { + return NULL; + } + gtt->backend.bdev = &rdev->mman.bdev; + gtt->backend.flags = 0; + gtt->backend.func = &radeon_backend_func; + gtt->rdev = rdev; + gtt->pages = NULL; + gtt->num_pages = 0; + gtt->dummy_read_page = NULL; + gtt->populated = false; + gtt->bound = false; + return >t->backend; +} diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c new file mode 100644 index 000000000000..cc074b5a8f74 --- /dev/null +++ b/drivers/gpu/drm/radeon/rs400.c @@ -0,0 +1,411 @@ +/* + * Copyright 2008 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * Copyright 2009 Jerome Glisse. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Dave Airlie + * Alex Deucher + * Jerome Glisse + */ +#include +#include +#include "radeon_reg.h" +#include "radeon.h" + +/* rs400,rs480 depends on : */ +void r100_hdp_reset(struct radeon_device *rdev); +void r100_mc_disable_clients(struct radeon_device *rdev); +int r300_mc_wait_for_idle(struct radeon_device *rdev); +void r420_pipes_init(struct radeon_device *rdev); + +/* This files gather functions specifics to : + * rs400,rs480 + * + * Some of these functions might be used by newer ASICs. + */ +void rs400_gpu_init(struct radeon_device *rdev); +int rs400_debugfs_pcie_gart_info_init(struct radeon_device *rdev); + + +/* + * GART functions. + */ +void rs400_gart_adjust_size(struct radeon_device *rdev) +{ + /* Check gart size */ + switch (rdev->mc.gtt_size/(1024*1024)) { + case 32: + case 64: + case 128: + case 256: + case 512: + case 1024: + case 2048: + break; + default: + DRM_ERROR("Unable to use IGP GART size %uM\n", + rdev->mc.gtt_size >> 20); + DRM_ERROR("Valid GART size for IGP are 32M,64M,128M,256M,512M,1G,2G\n"); + DRM_ERROR("Forcing to 32M GART size\n"); + rdev->mc.gtt_size = 32 * 1024 * 1024; + return; + } + if (rdev->family == CHIP_RS400 || rdev->family == CHIP_RS480) { + /* FIXME: RS400 & RS480 seems to have issue with GART size + * if 4G of system memory (needs more testing) */ + rdev->mc.gtt_size = 32 * 1024 * 1024; + DRM_ERROR("Forcing to 32M GART size (because of ASIC bug ?)\n"); + } +} + +void rs400_gart_tlb_flush(struct radeon_device *rdev) +{ + uint32_t tmp; + unsigned int timeout = rdev->usec_timeout; + + WREG32_MC(RS480_GART_CACHE_CNTRL, RS480_GART_CACHE_INVALIDATE); + do { + tmp = RREG32_MC(RS480_GART_CACHE_CNTRL); + if ((tmp & RS480_GART_CACHE_INVALIDATE) == 0) + break; + DRM_UDELAY(1); + timeout--; + } while (timeout > 0); + WREG32_MC(RS480_GART_CACHE_CNTRL, 0); +} + +int rs400_gart_enable(struct radeon_device *rdev) +{ + uint32_t size_reg; + uint32_t tmp; + int r; + + /* Initialize common gart structure */ + r = radeon_gart_init(rdev); + if (r) { + return r; + } + if (rs400_debugfs_pcie_gart_info_init(rdev)) { + DRM_ERROR("Failed to register debugfs file for RS400 GART !\n"); + } + + tmp = RREG32_MC(RS690_AIC_CTRL_SCRATCH); + tmp |= RS690_DIS_OUT_OF_PCI_GART_ACCESS; + WREG32_MC(RS690_AIC_CTRL_SCRATCH, tmp); + /* Check gart size */ + switch(rdev->mc.gtt_size / (1024 * 1024)) { + case 32: + size_reg = RS480_VA_SIZE_32MB; + break; + case 64: + size_reg = RS480_VA_SIZE_64MB; + break; + case 128: + size_reg = RS480_VA_SIZE_128MB; + break; + case 256: + size_reg = RS480_VA_SIZE_256MB; + break; + case 512: + size_reg = RS480_VA_SIZE_512MB; + break; + case 1024: + size_reg = RS480_VA_SIZE_1GB; + break; + case 2048: + size_reg = RS480_VA_SIZE_2GB; + break; + default: + return -EINVAL; + } + if (rdev->gart.table.ram.ptr == NULL) { + rdev->gart.table_size = rdev->gart.num_gpu_pages * 4; + r = radeon_gart_table_ram_alloc(rdev); + if (r) { + return r; + } + } + /* It should be fine to program it to max value */ + if (rdev->family == CHIP_RS690 || (rdev->family == CHIP_RS740)) { + WREG32_MC(RS690_MCCFG_AGP_BASE, 0xFFFFFFFF); + WREG32_MC(RS690_MCCFG_AGP_BASE_2, 0); + } else { + WREG32(RADEON_AGP_BASE, 0xFFFFFFFF); + WREG32(RS480_AGP_BASE_2, 0); + } + tmp = rdev->mc.gtt_location + rdev->mc.gtt_size - 1; + tmp = REG_SET(RS690_MC_AGP_TOP, tmp >> 16); + tmp |= REG_SET(RS690_MC_AGP_START, rdev->mc.gtt_location >> 16); + if ((rdev->family == CHIP_RS690) || (rdev->family == CHIP_RS740)) { + WREG32_MC(RS690_MCCFG_AGP_LOCATION, tmp); + tmp = RREG32(RADEON_BUS_CNTL) & ~RS600_BUS_MASTER_DIS; + WREG32(RADEON_BUS_CNTL, tmp); + } else { + WREG32(RADEON_MC_AGP_LOCATION, tmp); + tmp = RREG32(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS; + WREG32(RADEON_BUS_CNTL, tmp); + } + /* Table should be in 32bits address space so ignore bits above. */ + tmp = rdev->gart.table_addr & 0xfffff000; + WREG32_MC(RS480_GART_BASE, tmp); + /* TODO: more tweaking here */ + WREG32_MC(RS480_GART_FEATURE_ID, + (RS480_TLB_ENABLE | + RS480_GTW_LAC_EN | RS480_1LEVEL_GART)); + /* Disable snooping */ + WREG32_MC(RS480_AGP_MODE_CNTL, + (1 << RS480_REQ_TYPE_SNOOP_SHIFT) | RS480_REQ_TYPE_SNOOP_DIS); + /* Disable AGP mode */ + /* FIXME: according to doc we should set HIDE_MMCFG_BAR=0, + * AGPMODE30=0 & AGP30ENHANCED=0 in NB_CNTL */ + if ((rdev->family == CHIP_RS690) || (rdev->family == CHIP_RS740)) { + WREG32_MC(RS480_MC_MISC_CNTL, + (RS480_GART_INDEX_REG_EN | RS690_BLOCK_GFX_D3_EN)); + } else { + WREG32_MC(RS480_MC_MISC_CNTL, RS480_GART_INDEX_REG_EN); + } + /* Enable gart */ + WREG32_MC(RS480_AGP_ADDRESS_SPACE_SIZE, (RS480_GART_EN | size_reg)); + rs400_gart_tlb_flush(rdev); + rdev->gart.ready = true; + return 0; +} + +void rs400_gart_disable(struct radeon_device *rdev) +{ + uint32_t tmp; + + tmp = RREG32_MC(RS690_AIC_CTRL_SCRATCH); + tmp |= RS690_DIS_OUT_OF_PCI_GART_ACCESS; + WREG32_MC(RS690_AIC_CTRL_SCRATCH, tmp); + WREG32_MC(RS480_AGP_ADDRESS_SPACE_SIZE, 0); +} + +int rs400_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr) +{ + if (i < 0 || i > rdev->gart.num_gpu_pages) { + return -EINVAL; + } + rdev->gart.table.ram.ptr[i] = cpu_to_le32(((uint32_t)addr) | 0xC); + return 0; +} + + +/* + * MC functions. + */ +int rs400_mc_init(struct radeon_device *rdev) +{ + uint32_t tmp; + int r; + + if (r100_debugfs_rbbm_init(rdev)) { + DRM_ERROR("Failed to register debugfs file for RBBM !\n"); + } + + rs400_gpu_init(rdev); + rs400_gart_disable(rdev); + rdev->mc.gtt_location = rdev->mc.vram_size; + rdev->mc.gtt_location += (rdev->mc.gtt_size - 1); + rdev->mc.gtt_location &= ~(rdev->mc.gtt_size - 1); + rdev->mc.vram_location = 0xFFFFFFFFUL; + r = radeon_mc_setup(rdev); + if (r) { + return r; + } + + r100_mc_disable_clients(rdev); + if (r300_mc_wait_for_idle(rdev)) { + printk(KERN_WARNING "Failed to wait MC idle while " + "programming pipes. Bad things might happen.\n"); + } + + tmp = rdev->mc.vram_location + rdev->mc.vram_size - 1; + tmp = REG_SET(RADEON_MC_FB_TOP, tmp >> 16); + tmp |= REG_SET(RADEON_MC_FB_START, rdev->mc.vram_location >> 16); + WREG32(RADEON_MC_FB_LOCATION, tmp); + tmp = RREG32(RADEON_HOST_PATH_CNTL) | RADEON_HP_LIN_RD_CACHE_DIS; + WREG32(RADEON_HOST_PATH_CNTL, tmp | RADEON_HDP_SOFT_RESET | RADEON_HDP_READ_BUFFER_INVALIDATE); + (void)RREG32(RADEON_HOST_PATH_CNTL); + WREG32(RADEON_HOST_PATH_CNTL, tmp); + (void)RREG32(RADEON_HOST_PATH_CNTL); + return 0; +} + +void rs400_mc_fini(struct radeon_device *rdev) +{ + rs400_gart_disable(rdev); + radeon_gart_table_ram_free(rdev); + radeon_gart_fini(rdev); +} + + +/* + * Global GPU functions + */ +void rs400_errata(struct radeon_device *rdev) +{ + rdev->pll_errata = 0; +} + +void rs400_gpu_init(struct radeon_device *rdev) +{ + /* FIXME: HDP same place on rs400 ? */ + r100_hdp_reset(rdev); + /* FIXME: is this correct ? */ + r420_pipes_init(rdev); + if (r300_mc_wait_for_idle(rdev)) { + printk(KERN_WARNING "Failed to wait MC idle while " + "programming pipes. Bad things might happen.\n"); + } +} + + +/* + * VRAM info. + */ +void rs400_vram_info(struct radeon_device *rdev) +{ + uint32_t tom; + + rs400_gart_adjust_size(rdev); + /* DDR for all card after R300 & IGP */ + rdev->mc.vram_is_ddr = true; + rdev->mc.vram_width = 128; + + /* read NB_TOM to get the amount of ram stolen for the GPU */ + tom = RREG32(RADEON_NB_TOM); + rdev->mc.vram_size = (((tom >> 16) - (tom & 0xffff) + 1) << 16); + WREG32(RADEON_CONFIG_MEMSIZE, rdev->mc.vram_size); + + /* Could aper size report 0 ? */ + rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0); + rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0); +} + + +/* + * Indirect registers accessor + */ +uint32_t rs400_mc_rreg(struct radeon_device *rdev, uint32_t reg) +{ + uint32_t r; + + WREG32(RS480_NB_MC_INDEX, reg & 0xff); + r = RREG32(RS480_NB_MC_DATA); + WREG32(RS480_NB_MC_INDEX, 0xff); + return r; +} + +void rs400_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v) +{ + WREG32(RS480_NB_MC_INDEX, ((reg) & 0xff) | RS480_NB_MC_IND_WR_EN); + WREG32(RS480_NB_MC_DATA, (v)); + WREG32(RS480_NB_MC_INDEX, 0xff); +} + + +/* + * Debugfs info + */ +#if defined(CONFIG_DEBUG_FS) +static int rs400_debugfs_gart_info(struct seq_file *m, void *data) +{ + struct drm_info_node *node = (struct drm_info_node *) m->private; + struct drm_device *dev = node->minor->dev; + struct radeon_device *rdev = dev->dev_private; + uint32_t tmp; + + tmp = RREG32(RADEON_HOST_PATH_CNTL); + seq_printf(m, "HOST_PATH_CNTL 0x%08x\n", tmp); + tmp = RREG32(RADEON_BUS_CNTL); + seq_printf(m, "BUS_CNTL 0x%08x\n", tmp); + tmp = RREG32_MC(RS690_AIC_CTRL_SCRATCH); + seq_printf(m, "AIC_CTRL_SCRATCH 0x%08x\n", tmp); + if (rdev->family == CHIP_RS690 || (rdev->family == CHIP_RS740)) { + tmp = RREG32_MC(RS690_MCCFG_AGP_BASE); + seq_printf(m, "MCCFG_AGP_BASE 0x%08x\n", tmp); + tmp = RREG32_MC(RS690_MCCFG_AGP_BASE_2); + seq_printf(m, "MCCFG_AGP_BASE_2 0x%08x\n", tmp); + tmp = RREG32_MC(RS690_MCCFG_AGP_LOCATION); + seq_printf(m, "MCCFG_AGP_LOCATION 0x%08x\n", tmp); + tmp = RREG32_MC(0x100); + seq_printf(m, "MCCFG_FB_LOCATION 0x%08x\n", tmp); + tmp = RREG32(0x134); + seq_printf(m, "HDP_FB_LOCATION 0x%08x\n", tmp); + } else { + tmp = RREG32(RADEON_AGP_BASE); + seq_printf(m, "AGP_BASE 0x%08x\n", tmp); + tmp = RREG32(RS480_AGP_BASE_2); + seq_printf(m, "AGP_BASE_2 0x%08x\n", tmp); + tmp = RREG32(RADEON_MC_AGP_LOCATION); + seq_printf(m, "MC_AGP_LOCATION 0x%08x\n", tmp); + } + tmp = RREG32_MC(RS480_GART_BASE); + seq_printf(m, "GART_BASE 0x%08x\n", tmp); + tmp = RREG32_MC(RS480_GART_FEATURE_ID); + seq_printf(m, "GART_FEATURE_ID 0x%08x\n", tmp); + tmp = RREG32_MC(RS480_AGP_MODE_CNTL); + seq_printf(m, "AGP_MODE_CONTROL 0x%08x\n", tmp); + tmp = RREG32_MC(RS480_MC_MISC_CNTL); + seq_printf(m, "MC_MISC_CNTL 0x%08x\n", tmp); + tmp = RREG32_MC(0x5F); + seq_printf(m, "MC_MISC_UMA_CNTL 0x%08x\n", tmp); + tmp = RREG32_MC(RS480_AGP_ADDRESS_SPACE_SIZE); + seq_printf(m, "AGP_ADDRESS_SPACE_SIZE 0x%08x\n", tmp); + tmp = RREG32_MC(RS480_GART_CACHE_CNTRL); + seq_printf(m, "GART_CACHE_CNTRL 0x%08x\n", tmp); + tmp = RREG32_MC(0x3B); + seq_printf(m, "MC_GART_ERROR_ADDRESS 0x%08x\n", tmp); + tmp = RREG32_MC(0x3C); + seq_printf(m, "MC_GART_ERROR_ADDRESS_HI 0x%08x\n", tmp); + tmp = RREG32_MC(0x30); + seq_printf(m, "GART_ERROR_0 0x%08x\n", tmp); + tmp = RREG32_MC(0x31); + seq_printf(m, "GART_ERROR_1 0x%08x\n", tmp); + tmp = RREG32_MC(0x32); + seq_printf(m, "GART_ERROR_2 0x%08x\n", tmp); + tmp = RREG32_MC(0x33); + seq_printf(m, "GART_ERROR_3 0x%08x\n", tmp); + tmp = RREG32_MC(0x34); + seq_printf(m, "GART_ERROR_4 0x%08x\n", tmp); + tmp = RREG32_MC(0x35); + seq_printf(m, "GART_ERROR_5 0x%08x\n", tmp); + tmp = RREG32_MC(0x36); + seq_printf(m, "GART_ERROR_6 0x%08x\n", tmp); + tmp = RREG32_MC(0x37); + seq_printf(m, "GART_ERROR_7 0x%08x\n", tmp); + return 0; +} + +static struct drm_info_list rs400_gart_info_list[] = { + {"rs400_gart_info", rs400_debugfs_gart_info, 0, NULL}, +}; +#endif + +int rs400_debugfs_pcie_gart_info_init(struct radeon_device *rdev) +{ +#if defined(CONFIG_DEBUG_FS) + return radeon_debugfs_add_files(rdev, rs400_gart_info_list, 1); +#else + return 0; +#endif +} diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c new file mode 100644 index 000000000000..ab0c967553e6 --- /dev/null +++ b/drivers/gpu/drm/radeon/rs600.c @@ -0,0 +1,324 @@ +/* + * Copyright 2008 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * Copyright 2009 Jerome Glisse. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Dave Airlie + * Alex Deucher + * Jerome Glisse + */ +#include "drmP.h" +#include "radeon_reg.h" +#include "radeon.h" + +/* rs600 depends on : */ +void r100_hdp_reset(struct radeon_device *rdev); +int r100_gui_wait_for_idle(struct radeon_device *rdev); +int r300_mc_wait_for_idle(struct radeon_device *rdev); +void r420_pipes_init(struct radeon_device *rdev); + +/* This files gather functions specifics to : + * rs600 + * + * Some of these functions might be used by newer ASICs. + */ +void rs600_gpu_init(struct radeon_device *rdev); +int rs600_mc_wait_for_idle(struct radeon_device *rdev); +void rs600_disable_vga(struct radeon_device *rdev); + + +/* + * GART. + */ +void rs600_gart_tlb_flush(struct radeon_device *rdev) +{ + uint32_t tmp; + + tmp = RREG32_MC(RS600_MC_PT0_CNTL); + tmp &= ~(RS600_INVALIDATE_ALL_L1_TLBS | RS600_INVALIDATE_L2_CACHE); + WREG32_MC(RS600_MC_PT0_CNTL, tmp); + + tmp = RREG32_MC(RS600_MC_PT0_CNTL); + tmp |= RS600_INVALIDATE_ALL_L1_TLBS | RS600_INVALIDATE_L2_CACHE; + WREG32_MC(RS600_MC_PT0_CNTL, tmp); + + tmp = RREG32_MC(RS600_MC_PT0_CNTL); + tmp &= ~(RS600_INVALIDATE_ALL_L1_TLBS | RS600_INVALIDATE_L2_CACHE); + WREG32_MC(RS600_MC_PT0_CNTL, tmp); + tmp = RREG32_MC(RS600_MC_PT0_CNTL); +} + +int rs600_gart_enable(struct radeon_device *rdev) +{ + uint32_t tmp; + int i; + int r; + + /* Initialize common gart structure */ + r = radeon_gart_init(rdev); + if (r) { + return r; + } + rdev->gart.table_size = rdev->gart.num_gpu_pages * 8; + r = radeon_gart_table_vram_alloc(rdev); + if (r) { + return r; + } + /* FIXME: setup default page */ + WREG32_MC(RS600_MC_PT0_CNTL, + (RS600_EFFECTIVE_L2_CACHE_SIZE(6) | + RS600_EFFECTIVE_L2_QUEUE_SIZE(6))); + for (i = 0; i < 19; i++) { + WREG32_MC(RS600_MC_PT0_CLIENT0_CNTL + i, + (RS600_ENABLE_TRANSLATION_MODE_OVERRIDE | + RS600_SYSTEM_ACCESS_MODE_IN_SYS | + RS600_SYSTEM_APERTURE_UNMAPPED_ACCESS_DEFAULT_PAGE | + RS600_EFFECTIVE_L1_CACHE_SIZE(3) | + RS600_ENABLE_FRAGMENT_PROCESSING | + RS600_EFFECTIVE_L1_QUEUE_SIZE(3))); + } + + /* System context map to GART space */ + WREG32_MC(RS600_MC_PT0_SYSTEM_APERTURE_LOW_ADDR, rdev->mc.gtt_location); + tmp = rdev->mc.gtt_location + rdev->mc.gtt_size - 1; + WREG32_MC(RS600_MC_PT0_SYSTEM_APERTURE_HIGH_ADDR, tmp); + + /* enable first context */ + WREG32_MC(RS600_MC_PT0_CONTEXT0_FLAT_START_ADDR, rdev->mc.gtt_location); + tmp = rdev->mc.gtt_location + rdev->mc.gtt_size - 1; + WREG32_MC(RS600_MC_PT0_CONTEXT0_FLAT_END_ADDR, tmp); + WREG32_MC(RS600_MC_PT0_CONTEXT0_CNTL, + (RS600_ENABLE_PAGE_TABLE | RS600_PAGE_TABLE_TYPE_FLAT)); + /* disable all other contexts */ + for (i = 1; i < 8; i++) { + WREG32_MC(RS600_MC_PT0_CONTEXT0_CNTL + i, 0); + } + + /* setup the page table */ + WREG32_MC(RS600_MC_PT0_CONTEXT0_FLAT_BASE_ADDR, + rdev->gart.table_addr); + WREG32_MC(RS600_MC_PT0_CONTEXT0_DEFAULT_READ_ADDR, 0); + + /* enable page tables */ + tmp = RREG32_MC(RS600_MC_PT0_CNTL); + WREG32_MC(RS600_MC_PT0_CNTL, (tmp | RS600_ENABLE_PT)); + tmp = RREG32_MC(RS600_MC_CNTL1); + WREG32_MC(RS600_MC_CNTL1, (tmp | RS600_ENABLE_PAGE_TABLES)); + rs600_gart_tlb_flush(rdev); + rdev->gart.ready = true; + return 0; +} + +void rs600_gart_disable(struct radeon_device *rdev) +{ + uint32_t tmp; + + /* FIXME: disable out of gart access */ + WREG32_MC(RS600_MC_PT0_CNTL, 0); + tmp = RREG32_MC(RS600_MC_CNTL1); + tmp &= ~RS600_ENABLE_PAGE_TABLES; + WREG32_MC(RS600_MC_CNTL1, tmp); + radeon_object_kunmap(rdev->gart.table.vram.robj); + radeon_object_unpin(rdev->gart.table.vram.robj); +} + +#define R600_PTE_VALID (1 << 0) +#define R600_PTE_SYSTEM (1 << 1) +#define R600_PTE_SNOOPED (1 << 2) +#define R600_PTE_READABLE (1 << 5) +#define R600_PTE_WRITEABLE (1 << 6) + +int rs600_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr) +{ + void __iomem *ptr = (void *)rdev->gart.table.vram.ptr; + + if (i < 0 || i > rdev->gart.num_gpu_pages) { + return -EINVAL; + } + addr = addr & 0xFFFFFFFFFFFFF000ULL; + addr |= R600_PTE_VALID | R600_PTE_SYSTEM | R600_PTE_SNOOPED; + addr |= R600_PTE_READABLE | R600_PTE_WRITEABLE; + writeq(addr, ((void __iomem *)ptr) + (i * 8)); + return 0; +} + + +/* + * MC. + */ +void rs600_mc_disable_clients(struct radeon_device *rdev) +{ + unsigned tmp; + + if (r100_gui_wait_for_idle(rdev)) { + printk(KERN_WARNING "Failed to wait GUI idle while " + "programming pipes. Bad things might happen.\n"); + } + + tmp = RREG32(AVIVO_D1VGA_CONTROL); + WREG32(AVIVO_D1VGA_CONTROL, tmp & ~AVIVO_DVGA_CONTROL_MODE_ENABLE); + tmp = RREG32(AVIVO_D2VGA_CONTROL); + WREG32(AVIVO_D2VGA_CONTROL, tmp & ~AVIVO_DVGA_CONTROL_MODE_ENABLE); + + tmp = RREG32(AVIVO_D1CRTC_CONTROL); + WREG32(AVIVO_D1CRTC_CONTROL, tmp & ~AVIVO_CRTC_EN); + tmp = RREG32(AVIVO_D2CRTC_CONTROL); + WREG32(AVIVO_D2CRTC_CONTROL, tmp & ~AVIVO_CRTC_EN); + + /* make sure all previous write got through */ + tmp = RREG32(AVIVO_D2CRTC_CONTROL); + + mdelay(1); +} + +int rs600_mc_init(struct radeon_device *rdev) +{ + uint32_t tmp; + int r; + + if (r100_debugfs_rbbm_init(rdev)) { + DRM_ERROR("Failed to register debugfs file for RBBM !\n"); + } + + rs600_gpu_init(rdev); + rs600_gart_disable(rdev); + + /* Setup GPU memory space */ + rdev->mc.vram_location = 0xFFFFFFFFUL; + rdev->mc.gtt_location = 0xFFFFFFFFUL; + r = radeon_mc_setup(rdev); + if (r) { + return r; + } + + /* Program GPU memory space */ + /* Enable bus master */ + tmp = RREG32(RADEON_BUS_CNTL) & ~RS600_BUS_MASTER_DIS; + WREG32(RADEON_BUS_CNTL, tmp); + /* FIXME: What does AGP means for such chipset ? */ + WREG32_MC(RS600_MC_AGP_LOCATION, 0x0FFFFFFF); + /* FIXME: are this AGP reg in indirect MC range ? */ + WREG32_MC(RS600_MC_AGP_BASE, 0); + WREG32_MC(RS600_MC_AGP_BASE_2, 0); + rs600_mc_disable_clients(rdev); + if (rs600_mc_wait_for_idle(rdev)) { + printk(KERN_WARNING "Failed to wait MC idle while " + "programming pipes. Bad things might happen.\n"); + } + tmp = rdev->mc.vram_location + rdev->mc.vram_size - 1; + tmp = REG_SET(RS600_MC_FB_TOP, tmp >> 16); + tmp |= REG_SET(RS600_MC_FB_START, rdev->mc.vram_location >> 16); + WREG32_MC(RS600_MC_FB_LOCATION, tmp); + WREG32(RS690_HDP_FB_LOCATION, rdev->mc.vram_location >> 16); + return 0; +} + +void rs600_mc_fini(struct radeon_device *rdev) +{ + rs600_gart_disable(rdev); + radeon_gart_table_vram_free(rdev); + radeon_gart_fini(rdev); +} + + +/* + * Global GPU functions + */ +void rs600_disable_vga(struct radeon_device *rdev) +{ + unsigned tmp; + + WREG32(0x330, 0); + WREG32(0x338, 0); + tmp = RREG32(0x300); + tmp &= ~(3 << 16); + WREG32(0x300, tmp); + WREG32(0x308, (1 << 8)); + WREG32(0x310, rdev->mc.vram_location); + WREG32(0x594, 0); +} + +int rs600_mc_wait_for_idle(struct radeon_device *rdev) +{ + unsigned i; + uint32_t tmp; + + for (i = 0; i < rdev->usec_timeout; i++) { + /* read MC_STATUS */ + tmp = RREG32_MC(RS600_MC_STATUS); + if (tmp & RS600_MC_STATUS_IDLE) { + return 0; + } + DRM_UDELAY(1); + } + return -1; +} + +void rs600_errata(struct radeon_device *rdev) +{ + rdev->pll_errata = 0; +} + +void rs600_gpu_init(struct radeon_device *rdev) +{ + /* FIXME: HDP same place on rs600 ? */ + r100_hdp_reset(rdev); + rs600_disable_vga(rdev); + /* FIXME: is this correct ? */ + r420_pipes_init(rdev); + if (rs600_mc_wait_for_idle(rdev)) { + printk(KERN_WARNING "Failed to wait MC idle while " + "programming pipes. Bad things might happen.\n"); + } +} + + +/* + * VRAM info. + */ +void rs600_vram_info(struct radeon_device *rdev) +{ + /* FIXME: to do or is these values sane ? */ + rdev->mc.vram_is_ddr = true; + rdev->mc.vram_width = 128; +} + + +/* + * Indirect registers accessor + */ +uint32_t rs600_mc_rreg(struct radeon_device *rdev, uint32_t reg) +{ + uint32_t r; + + WREG32(RS600_MC_INDEX, + ((reg & RS600_MC_ADDR_MASK) | RS600_MC_IND_CITF_ARB0)); + r = RREG32(RS600_MC_DATA); + return r; +} + +void rs600_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v) +{ + WREG32(RS600_MC_INDEX, + RS600_MC_IND_WR_EN | RS600_MC_IND_CITF_ARB0 | + ((reg) & RS600_MC_ADDR_MASK)); + WREG32(RS600_MC_DATA, v); +} diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c new file mode 100644 index 000000000000..79ba85042b5f --- /dev/null +++ b/drivers/gpu/drm/radeon/rs690.c @@ -0,0 +1,181 @@ +/* + * Copyright 2008 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * Copyright 2009 Jerome Glisse. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Dave Airlie + * Alex Deucher + * Jerome Glisse + */ +#include "drmP.h" +#include "radeon_reg.h" +#include "radeon.h" + +/* rs690,rs740 depends on : */ +void r100_hdp_reset(struct radeon_device *rdev); +int r300_mc_wait_for_idle(struct radeon_device *rdev); +void r420_pipes_init(struct radeon_device *rdev); +void rs400_gart_disable(struct radeon_device *rdev); +int rs400_gart_enable(struct radeon_device *rdev); +void rs400_gart_adjust_size(struct radeon_device *rdev); +void rs600_mc_disable_clients(struct radeon_device *rdev); +void rs600_disable_vga(struct radeon_device *rdev); + +/* This files gather functions specifics to : + * rs690,rs740 + * + * Some of these functions might be used by newer ASICs. + */ +void rs690_gpu_init(struct radeon_device *rdev); +int rs690_mc_wait_for_idle(struct radeon_device *rdev); + + +/* + * MC functions. + */ +int rs690_mc_init(struct radeon_device *rdev) +{ + uint32_t tmp; + int r; + + if (r100_debugfs_rbbm_init(rdev)) { + DRM_ERROR("Failed to register debugfs file for RBBM !\n"); + } + + rs690_gpu_init(rdev); + rs400_gart_disable(rdev); + + /* Setup GPU memory space */ + rdev->mc.gtt_location = rdev->mc.vram_size; + rdev->mc.gtt_location += (rdev->mc.gtt_size - 1); + rdev->mc.gtt_location &= ~(rdev->mc.gtt_size - 1); + rdev->mc.vram_location = 0xFFFFFFFFUL; + r = radeon_mc_setup(rdev); + if (r) { + return r; + } + + /* Program GPU memory space */ + rs600_mc_disable_clients(rdev); + if (rs690_mc_wait_for_idle(rdev)) { + printk(KERN_WARNING "Failed to wait MC idle while " + "programming pipes. Bad things might happen.\n"); + } + tmp = rdev->mc.vram_location + rdev->mc.vram_size - 1; + tmp = REG_SET(RS690_MC_FB_TOP, tmp >> 16); + tmp |= REG_SET(RS690_MC_FB_START, rdev->mc.vram_location >> 16); + WREG32_MC(RS690_MCCFG_FB_LOCATION, tmp); + /* FIXME: Does this reg exist on RS480,RS740 ? */ + WREG32(0x310, rdev->mc.vram_location); + WREG32(RS690_HDP_FB_LOCATION, rdev->mc.vram_location >> 16); + return 0; +} + +void rs690_mc_fini(struct radeon_device *rdev) +{ + rs400_gart_disable(rdev); + radeon_gart_table_ram_free(rdev); + radeon_gart_fini(rdev); +} + + +/* + * Global GPU functions + */ +int rs690_mc_wait_for_idle(struct radeon_device *rdev) +{ + unsigned i; + uint32_t tmp; + + for (i = 0; i < rdev->usec_timeout; i++) { + /* read MC_STATUS */ + tmp = RREG32_MC(RS690_MC_STATUS); + if (tmp & RS690_MC_STATUS_IDLE) { + return 0; + } + DRM_UDELAY(1); + } + return -1; +} + +void rs690_errata(struct radeon_device *rdev) +{ + rdev->pll_errata = 0; +} + +void rs690_gpu_init(struct radeon_device *rdev) +{ + /* FIXME: HDP same place on rs690 ? */ + r100_hdp_reset(rdev); + rs600_disable_vga(rdev); + /* FIXME: is this correct ? */ + r420_pipes_init(rdev); + if (rs690_mc_wait_for_idle(rdev)) { + printk(KERN_WARNING "Failed to wait MC idle while " + "programming pipes. Bad things might happen.\n"); + } +} + + +/* + * VRAM info. + */ +void rs690_vram_info(struct radeon_device *rdev) +{ + uint32_t tmp; + + rs400_gart_adjust_size(rdev); + /* DDR for all card after R300 & IGP */ + rdev->mc.vram_is_ddr = true; + /* FIXME: is this correct for RS690/RS740 ? */ + tmp = RREG32(RADEON_MEM_CNTL); + if (tmp & R300_MEM_NUM_CHANNELS_MASK) { + rdev->mc.vram_width = 128; + } else { + rdev->mc.vram_width = 64; + } + rdev->mc.vram_size = RREG32(RADEON_CONFIG_MEMSIZE); + + rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0); + rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0); +} + + +/* + * Indirect registers accessor + */ +uint32_t rs690_mc_rreg(struct radeon_device *rdev, uint32_t reg) +{ + uint32_t r; + + WREG32(RS690_MC_INDEX, (reg & RS690_MC_INDEX_MASK)); + r = RREG32(RS690_MC_DATA); + WREG32(RS690_MC_INDEX, RS690_MC_INDEX_MASK); + return r; +} + +void rs690_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v) +{ + WREG32(RS690_MC_INDEX, + RS690_MC_INDEX_WR_EN | ((reg) & RS690_MC_INDEX_MASK)); + WREG32(RS690_MC_DATA, v); + WREG32(RS690_MC_INDEX, RS690_MC_INDEX_WR_ACK); +} diff --git a/drivers/gpu/drm/radeon/rs780.c b/drivers/gpu/drm/radeon/rs780.c new file mode 100644 index 000000000000..0affcff81825 --- /dev/null +++ b/drivers/gpu/drm/radeon/rs780.c @@ -0,0 +1,102 @@ +/* + * Copyright 2008 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * Copyright 2009 Jerome Glisse. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Dave Airlie + * Alex Deucher + * Jerome Glisse + */ +#include "drmP.h" +#include "radeon_reg.h" +#include "radeon.h" + +/* rs780 depends on : */ +void rs600_mc_disable_clients(struct radeon_device *rdev); + +/* This files gather functions specifics to: + * rs780 + * + * Some of these functions might be used by newer ASICs. + */ +int rs780_mc_wait_for_idle(struct radeon_device *rdev); +void rs780_gpu_init(struct radeon_device *rdev); + + +/* + * MC + */ +int rs780_mc_init(struct radeon_device *rdev) +{ + rs780_gpu_init(rdev); + /* FIXME: implement */ + + rs600_mc_disable_clients(rdev); + if (rs780_mc_wait_for_idle(rdev)) { + printk(KERN_WARNING "Failed to wait MC idle while " + "programming pipes. Bad things might happen.\n"); + } + return 0; +} + +void rs780_mc_fini(struct radeon_device *rdev) +{ + /* FIXME: implement */ +} + + +/* + * Global GPU functions + */ +void rs780_errata(struct radeon_device *rdev) +{ + rdev->pll_errata = 0; +} + +int rs780_mc_wait_for_idle(struct radeon_device *rdev) +{ + /* FIXME: implement */ + return 0; +} + +void rs780_gpu_init(struct radeon_device *rdev) +{ + /* FIXME: implement */ +} + + +/* + * VRAM info + */ +void rs780_vram_get_type(struct radeon_device *rdev) +{ + /* FIXME: implement */ +} + +void rs780_vram_info(struct radeon_device *rdev) +{ + rs780_vram_get_type(rdev); + + /* FIXME: implement */ + /* Could aper size report 0 ? */ + rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0); + rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0); +} diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c new file mode 100644 index 000000000000..ffea37b1b3e2 --- /dev/null +++ b/drivers/gpu/drm/radeon/rv515.c @@ -0,0 +1,562 @@ +/* + * Copyright 2008 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * Copyright 2009 Jerome Glisse. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Dave Airlie + * Alex Deucher + * Jerome Glisse + */ +#include +#include "drmP.h" +#include "radeon_reg.h" +#include "radeon.h" + +/* rv515 depends on : */ +void r100_hdp_reset(struct radeon_device *rdev); +int r100_cp_reset(struct radeon_device *rdev); +int r100_rb2d_reset(struct radeon_device *rdev); +int r100_gui_wait_for_idle(struct radeon_device *rdev); +int r100_cp_init(struct radeon_device *rdev, unsigned ring_size); +int rv370_pcie_gart_enable(struct radeon_device *rdev); +void rv370_pcie_gart_disable(struct radeon_device *rdev); +void r420_pipes_init(struct radeon_device *rdev); +void rs600_mc_disable_clients(struct radeon_device *rdev); +void rs600_disable_vga(struct radeon_device *rdev); + +/* This files gather functions specifics to: + * rv515 + * + * Some of these functions might be used by newer ASICs. + */ +int rv515_debugfs_pipes_info_init(struct radeon_device *rdev); +int rv515_debugfs_ga_info_init(struct radeon_device *rdev); +void rv515_gpu_init(struct radeon_device *rdev); +int rv515_mc_wait_for_idle(struct radeon_device *rdev); + + +/* + * MC + */ +int rv515_mc_init(struct radeon_device *rdev) +{ + uint32_t tmp; + int r; + + if (r100_debugfs_rbbm_init(rdev)) { + DRM_ERROR("Failed to register debugfs file for RBBM !\n"); + } + if (rv515_debugfs_pipes_info_init(rdev)) { + DRM_ERROR("Failed to register debugfs file for pipes !\n"); + } + if (rv515_debugfs_ga_info_init(rdev)) { + DRM_ERROR("Failed to register debugfs file for pipes !\n"); + } + + rv515_gpu_init(rdev); + rv370_pcie_gart_disable(rdev); + + /* Setup GPU memory space */ + rdev->mc.vram_location = 0xFFFFFFFFUL; + rdev->mc.gtt_location = 0xFFFFFFFFUL; + if (rdev->flags & RADEON_IS_AGP) { + r = radeon_agp_init(rdev); + if (r) { + printk(KERN_WARNING "[drm] Disabling AGP\n"); + rdev->flags &= ~RADEON_IS_AGP; + rdev->mc.gtt_size = radeon_gart_size * 1024 * 1024; + } else { + rdev->mc.gtt_location = rdev->mc.agp_base; + } + } + r = radeon_mc_setup(rdev); + if (r) { + return r; + } + + /* Program GPU memory space */ + rs600_mc_disable_clients(rdev); + if (rv515_mc_wait_for_idle(rdev)) { + printk(KERN_WARNING "Failed to wait MC idle while " + "programming pipes. Bad things might happen.\n"); + } + /* Write VRAM size in case we are limiting it */ + WREG32(RADEON_CONFIG_MEMSIZE, rdev->mc.vram_size); + tmp = REG_SET(RV515_MC_FB_START, rdev->mc.vram_location >> 16); + WREG32(0x134, tmp); + tmp = rdev->mc.vram_location + rdev->mc.vram_size - 1; + tmp = REG_SET(RV515_MC_FB_TOP, tmp >> 16); + tmp |= REG_SET(RV515_MC_FB_START, rdev->mc.vram_location >> 16); + WREG32_MC(RV515_MC_FB_LOCATION, tmp); + WREG32(RS690_HDP_FB_LOCATION, rdev->mc.vram_location >> 16); + WREG32(0x310, rdev->mc.vram_location); + if (rdev->flags & RADEON_IS_AGP) { + tmp = rdev->mc.gtt_location + rdev->mc.gtt_size - 1; + tmp = REG_SET(RV515_MC_AGP_TOP, tmp >> 16); + tmp |= REG_SET(RV515_MC_AGP_START, rdev->mc.gtt_location >> 16); + WREG32_MC(RV515_MC_AGP_LOCATION, tmp); + WREG32_MC(RV515_MC_AGP_BASE, rdev->mc.agp_base); + WREG32_MC(RV515_MC_AGP_BASE_2, 0); + } else { + WREG32_MC(RV515_MC_AGP_LOCATION, 0x0FFFFFFF); + WREG32_MC(RV515_MC_AGP_BASE, 0); + WREG32_MC(RV515_MC_AGP_BASE_2, 0); + } + return 0; +} + +void rv515_mc_fini(struct radeon_device *rdev) +{ + rv370_pcie_gart_disable(rdev); + radeon_gart_table_vram_free(rdev); + radeon_gart_fini(rdev); +} + + +/* + * Global GPU functions + */ +void rv515_ring_start(struct radeon_device *rdev) +{ + unsigned gb_tile_config; + int r; + + /* Sub pixel 1/12 so we can have 4K rendering according to doc */ + gb_tile_config = R300_ENABLE_TILING | R300_TILE_SIZE_16; + switch (rdev->num_gb_pipes) { + case 2: + gb_tile_config |= R300_PIPE_COUNT_R300; + break; + case 3: + gb_tile_config |= R300_PIPE_COUNT_R420_3P; + break; + case 4: + gb_tile_config |= R300_PIPE_COUNT_R420; + break; + case 1: + default: + gb_tile_config |= R300_PIPE_COUNT_RV350; + break; + } + + r = radeon_ring_lock(rdev, 64); + if (r) { + return; + } + radeon_ring_write(rdev, PACKET0(RADEON_ISYNC_CNTL, 0)); + radeon_ring_write(rdev, + RADEON_ISYNC_ANY2D_IDLE3D | + RADEON_ISYNC_ANY3D_IDLE2D | + RADEON_ISYNC_WAIT_IDLEGUI | + RADEON_ISYNC_CPSCRATCH_IDLEGUI); + radeon_ring_write(rdev, PACKET0(R300_GB_TILE_CONFIG, 0)); + radeon_ring_write(rdev, gb_tile_config); + radeon_ring_write(rdev, PACKET0(RADEON_WAIT_UNTIL, 0)); + radeon_ring_write(rdev, + RADEON_WAIT_2D_IDLECLEAN | + RADEON_WAIT_3D_IDLECLEAN); + radeon_ring_write(rdev, PACKET0(0x170C, 0)); + radeon_ring_write(rdev, 1 << 31); + radeon_ring_write(rdev, PACKET0(R300_GB_SELECT, 0)); + radeon_ring_write(rdev, 0); + radeon_ring_write(rdev, PACKET0(R300_GB_ENABLE, 0)); + radeon_ring_write(rdev, 0); + radeon_ring_write(rdev, PACKET0(0x42C8, 0)); + radeon_ring_write(rdev, (1 << rdev->num_gb_pipes) - 1); + radeon_ring_write(rdev, PACKET0(R500_VAP_INDEX_OFFSET, 0)); + radeon_ring_write(rdev, 0); + radeon_ring_write(rdev, PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0)); + radeon_ring_write(rdev, R300_RB3D_DC_FLUSH | R300_RB3D_DC_FREE); + radeon_ring_write(rdev, PACKET0(R300_RB3D_ZCACHE_CTLSTAT, 0)); + radeon_ring_write(rdev, R300_ZC_FLUSH | R300_ZC_FREE); + radeon_ring_write(rdev, PACKET0(RADEON_WAIT_UNTIL, 0)); + radeon_ring_write(rdev, + RADEON_WAIT_2D_IDLECLEAN | + RADEON_WAIT_3D_IDLECLEAN); + radeon_ring_write(rdev, PACKET0(R300_GB_AA_CONFIG, 0)); + radeon_ring_write(rdev, 0); + radeon_ring_write(rdev, PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0)); + radeon_ring_write(rdev, R300_RB3D_DC_FLUSH | R300_RB3D_DC_FREE); + radeon_ring_write(rdev, PACKET0(R300_RB3D_ZCACHE_CTLSTAT, 0)); + radeon_ring_write(rdev, R300_ZC_FLUSH | R300_ZC_FREE); + radeon_ring_write(rdev, PACKET0(R300_GB_MSPOS0, 0)); + radeon_ring_write(rdev, + ((6 << R300_MS_X0_SHIFT) | + (6 << R300_MS_Y0_SHIFT) | + (6 << R300_MS_X1_SHIFT) | + (6 << R300_MS_Y1_SHIFT) | + (6 << R300_MS_X2_SHIFT) | + (6 << R300_MS_Y2_SHIFT) | + (6 << R300_MSBD0_Y_SHIFT) | + (6 << R300_MSBD0_X_SHIFT))); + radeon_ring_write(rdev, PACKET0(R300_GB_MSPOS1, 0)); + radeon_ring_write(rdev, + ((6 << R300_MS_X3_SHIFT) | + (6 << R300_MS_Y3_SHIFT) | + (6 << R300_MS_X4_SHIFT) | + (6 << R300_MS_Y4_SHIFT) | + (6 << R300_MS_X5_SHIFT) | + (6 << R300_MS_Y5_SHIFT) | + (6 << R300_MSBD1_SHIFT))); + radeon_ring_write(rdev, PACKET0(R300_GA_ENHANCE, 0)); + radeon_ring_write(rdev, R300_GA_DEADLOCK_CNTL | R300_GA_FASTSYNC_CNTL); + radeon_ring_write(rdev, PACKET0(R300_GA_POLY_MODE, 0)); + radeon_ring_write(rdev, + R300_FRONT_PTYPE_TRIANGE | R300_BACK_PTYPE_TRIANGE); + radeon_ring_write(rdev, PACKET0(R300_GA_ROUND_MODE, 0)); + radeon_ring_write(rdev, + R300_GEOMETRY_ROUND_NEAREST | + R300_COLOR_ROUND_NEAREST); + radeon_ring_write(rdev, PACKET0(0x20C8, 0)); + radeon_ring_write(rdev, 0); + radeon_ring_unlock_commit(rdev); +} + +void rv515_errata(struct radeon_device *rdev) +{ + rdev->pll_errata = 0; +} + +int rv515_mc_wait_for_idle(struct radeon_device *rdev) +{ + unsigned i; + uint32_t tmp; + + for (i = 0; i < rdev->usec_timeout; i++) { + /* read MC_STATUS */ + tmp = RREG32_MC(RV515_MC_STATUS); + if (tmp & RV515_MC_STATUS_IDLE) { + return 0; + } + DRM_UDELAY(1); + } + return -1; +} + +void rv515_gpu_init(struct radeon_device *rdev) +{ + unsigned pipe_select_current, gb_pipe_select, tmp; + + r100_hdp_reset(rdev); + r100_rb2d_reset(rdev); + + if (r100_gui_wait_for_idle(rdev)) { + printk(KERN_WARNING "Failed to wait GUI idle while " + "reseting GPU. Bad things might happen.\n"); + } + + rs600_disable_vga(rdev); + + r420_pipes_init(rdev); + gb_pipe_select = RREG32(0x402C); + tmp = RREG32(0x170C); + pipe_select_current = (tmp >> 2) & 3; + tmp = (1 << pipe_select_current) | + (((gb_pipe_select >> 8) & 0xF) << 4); + WREG32_PLL(0x000D, tmp); + if (r100_gui_wait_for_idle(rdev)) { + printk(KERN_WARNING "Failed to wait GUI idle while " + "reseting GPU. Bad things might happen.\n"); + } + if (rv515_mc_wait_for_idle(rdev)) { + printk(KERN_WARNING "Failed to wait MC idle while " + "programming pipes. Bad things might happen.\n"); + } +} + +int rv515_ga_reset(struct radeon_device *rdev) +{ + uint32_t tmp; + bool reinit_cp; + int i; + + reinit_cp = rdev->cp.ready; + rdev->cp.ready = false; + for (i = 0; i < rdev->usec_timeout; i++) { + WREG32(RADEON_CP_CSQ_MODE, 0); + WREG32(RADEON_CP_CSQ_CNTL, 0); + WREG32(RADEON_RBBM_SOFT_RESET, 0x32005); + (void)RREG32(RADEON_RBBM_SOFT_RESET); + udelay(200); + WREG32(RADEON_RBBM_SOFT_RESET, 0); + /* Wait to prevent race in RBBM_STATUS */ + mdelay(1); + tmp = RREG32(RADEON_RBBM_STATUS); + if (tmp & ((1 << 20) | (1 << 26))) { + DRM_ERROR("VAP & CP still busy (RBBM_STATUS=0x%08X)\n", tmp); + /* GA still busy soft reset it */ + WREG32(0x429C, 0x200); + WREG32(R300_VAP_PVS_STATE_FLUSH_REG, 0); + WREG32(0x43E0, 0); + WREG32(0x43E4, 0); + WREG32(0x24AC, 0); + } + /* Wait to prevent race in RBBM_STATUS */ + mdelay(1); + tmp = RREG32(RADEON_RBBM_STATUS); + if (!(tmp & ((1 << 20) | (1 << 26)))) { + break; + } + } + for (i = 0; i < rdev->usec_timeout; i++) { + tmp = RREG32(RADEON_RBBM_STATUS); + if (!(tmp & ((1 << 20) | (1 << 26)))) { + DRM_INFO("GA reset succeed (RBBM_STATUS=0x%08X)\n", + tmp); + DRM_INFO("GA_IDLE=0x%08X\n", RREG32(0x425C)); + DRM_INFO("RB3D_RESET_STATUS=0x%08X\n", RREG32(0x46f0)); + DRM_INFO("ISYNC_CNTL=0x%08X\n", RREG32(0x1724)); + if (reinit_cp) { + return r100_cp_init(rdev, rdev->cp.ring_size); + } + return 0; + } + DRM_UDELAY(1); + } + tmp = RREG32(RADEON_RBBM_STATUS); + DRM_ERROR("Failed to reset GA ! (RBBM_STATUS=0x%08X)\n", tmp); + return -1; +} + +int rv515_gpu_reset(struct radeon_device *rdev) +{ + uint32_t status; + + /* reset order likely matter */ + status = RREG32(RADEON_RBBM_STATUS); + /* reset HDP */ + r100_hdp_reset(rdev); + /* reset rb2d */ + if (status & ((1 << 17) | (1 << 18) | (1 << 27))) { + r100_rb2d_reset(rdev); + } + /* reset GA */ + if (status & ((1 << 20) | (1 << 26))) { + rv515_ga_reset(rdev); + } + /* reset CP */ + status = RREG32(RADEON_RBBM_STATUS); + if (status & (1 << 16)) { + r100_cp_reset(rdev); + } + /* Check if GPU is idle */ + status = RREG32(RADEON_RBBM_STATUS); + if (status & (1 << 31)) { + DRM_ERROR("Failed to reset GPU (RBBM_STATUS=0x%08X)\n", status); + return -1; + } + DRM_INFO("GPU reset succeed (RBBM_STATUS=0x%08X)\n", status); + return 0; +} + + +/* + * VRAM info + */ +static void rv515_vram_get_type(struct radeon_device *rdev) +{ + uint32_t tmp; + + rdev->mc.vram_width = 128; + rdev->mc.vram_is_ddr = true; + tmp = RREG32_MC(RV515_MC_CNTL); + tmp &= RV515_MEM_NUM_CHANNELS_MASK; + switch (tmp) { + case 0: + rdev->mc.vram_width = 64; + break; + case 1: + rdev->mc.vram_width = 128; + break; + default: + rdev->mc.vram_width = 128; + break; + } +} + +void rv515_vram_info(struct radeon_device *rdev) +{ + rv515_vram_get_type(rdev); + rdev->mc.vram_size = RREG32(RADEON_CONFIG_MEMSIZE); + + rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0); + rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0); +} + + +/* + * Indirect registers accessor + */ +uint32_t rv515_mc_rreg(struct radeon_device *rdev, uint32_t reg) +{ + uint32_t r; + + WREG32(R520_MC_IND_INDEX, 0x7f0000 | (reg & 0xffff)); + r = RREG32(R520_MC_IND_DATA); + WREG32(R520_MC_IND_INDEX, 0); + return r; +} + +void rv515_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v) +{ + WREG32(R520_MC_IND_INDEX, 0xff0000 | ((reg) & 0xffff)); + WREG32(R520_MC_IND_DATA, (v)); + WREG32(R520_MC_IND_INDEX, 0); +} + +uint32_t rv515_pcie_rreg(struct radeon_device *rdev, uint32_t reg) +{ + uint32_t r; + + WREG32(RADEON_PCIE_INDEX, ((reg) & 0x7ff)); + (void)RREG32(RADEON_PCIE_INDEX); + r = RREG32(RADEON_PCIE_DATA); + return r; +} + +void rv515_pcie_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v) +{ + WREG32(RADEON_PCIE_INDEX, ((reg) & 0x7ff)); + (void)RREG32(RADEON_PCIE_INDEX); + WREG32(RADEON_PCIE_DATA, (v)); + (void)RREG32(RADEON_PCIE_DATA); +} + + +/* + * Debugfs info + */ +#if defined(CONFIG_DEBUG_FS) +static int rv515_debugfs_pipes_info(struct seq_file *m, void *data) +{ + struct drm_info_node *node = (struct drm_info_node *) m->private; + struct drm_device *dev = node->minor->dev; + struct radeon_device *rdev = dev->dev_private; + uint32_t tmp; + + tmp = RREG32(R400_GB_PIPE_SELECT); + seq_printf(m, "GB_PIPE_SELECT 0x%08x\n", tmp); + tmp = RREG32(R500_SU_REG_DEST); + seq_printf(m, "SU_REG_DEST 0x%08x\n", tmp); + tmp = RREG32(R300_GB_TILE_CONFIG); + seq_printf(m, "GB_TILE_CONFIG 0x%08x\n", tmp); + tmp = RREG32(R300_DST_PIPE_CONFIG); + seq_printf(m, "DST_PIPE_CONFIG 0x%08x\n", tmp); + return 0; +} + +static int rv515_debugfs_ga_info(struct seq_file *m, void *data) +{ + struct drm_info_node *node = (struct drm_info_node *) m->private; + struct drm_device *dev = node->minor->dev; + struct radeon_device *rdev = dev->dev_private; + uint32_t tmp; + + tmp = RREG32(0x2140); + seq_printf(m, "VAP_CNTL_STATUS 0x%08x\n", tmp); + radeon_gpu_reset(rdev); + tmp = RREG32(0x425C); + seq_printf(m, "GA_IDLE 0x%08x\n", tmp); + return 0; +} + +static struct drm_info_list rv515_pipes_info_list[] = { + {"rv515_pipes_info", rv515_debugfs_pipes_info, 0, NULL}, +}; + +static struct drm_info_list rv515_ga_info_list[] = { + {"rv515_ga_info", rv515_debugfs_ga_info, 0, NULL}, +}; +#endif + +int rv515_debugfs_pipes_info_init(struct radeon_device *rdev) +{ +#if defined(CONFIG_DEBUG_FS) + return radeon_debugfs_add_files(rdev, rv515_pipes_info_list, 1); +#else + return 0; +#endif +} + +int rv515_debugfs_ga_info_init(struct radeon_device *rdev) +{ +#if defined(CONFIG_DEBUG_FS) + return radeon_debugfs_add_files(rdev, rv515_ga_info_list, 1); +#else + return 0; +#endif +} + + +/* + * Asic initialization + */ +static const unsigned r500_reg_safe_bm[159] = { + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFBF, 0xFFFFFFFF, 0xFFFFFFBF, 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, 0xFFFFFFFF, + 0x17FF1FFF, 0xFFFFFFFC, 0xFFFFFFFF, 0xFF30FFBF, + 0xFFFFFFF8, 0xC3E6FFFF, 0xFFFFF6DF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFF03F, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFEFCE, 0xF00EBFFF, 0x007C0000, + 0xF0000038, 0xFF000009, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 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, + 0xFFFFF7FF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0x1FFFFC78, 0xFFFFE000, 0xFFFFFFFE, 0xFFFFFFFF, + 0x38CF8F50, 0xFFF88082, 0xFF0000FC, 0xFAE009FF, + 0x0000FFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, + 0xFFFF8CFC, 0xFFFFC1FF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF80FFFF, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x0003FC01, 0x3FFFFCF8, 0xFE800B19, +}; + + + +int rv515_init(struct radeon_device *rdev) +{ + rdev->config.r300.reg_safe_bm = r500_reg_safe_bm; + rdev->config.r300.reg_safe_bm_size = ARRAY_SIZE(r500_reg_safe_bm); + return 0; +} diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c new file mode 100644 index 000000000000..da50cc51ede3 --- /dev/null +++ b/drivers/gpu/drm/radeon/rv770.c @@ -0,0 +1,124 @@ +/* + * Copyright 2008 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * Copyright 2009 Jerome Glisse. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Dave Airlie + * Alex Deucher + * Jerome Glisse + */ +#include "drmP.h" +#include "radeon_reg.h" +#include "radeon.h" + +/* rv770,rv730,rv710 depends on : */ +void rs600_mc_disable_clients(struct radeon_device *rdev); + +/* This files gather functions specifics to: + * rv770,rv730,rv710 + * + * Some of these functions might be used by newer ASICs. + */ +int rv770_mc_wait_for_idle(struct radeon_device *rdev); +void rv770_gpu_init(struct radeon_device *rdev); + + +/* + * MC + */ +int rv770_mc_init(struct radeon_device *rdev) +{ + uint32_t tmp; + + rv770_gpu_init(rdev); + + /* setup the gart before changing location so we can ask to + * discard unmapped mc request + */ + /* FIXME: disable out of gart access */ + tmp = rdev->mc.gtt_location / 4096; + tmp = REG_SET(R700_LOGICAL_PAGE_NUMBER, tmp); + WREG32(R700_MC_VM_SYSTEM_APERTURE_LOW_ADDR, tmp); + tmp = (rdev->mc.gtt_location + rdev->mc.gtt_size) / 4096; + tmp = REG_SET(R700_LOGICAL_PAGE_NUMBER, tmp); + WREG32(R700_MC_VM_SYSTEM_APERTURE_HIGH_ADDR, tmp); + + rs600_mc_disable_clients(rdev); + if (rv770_mc_wait_for_idle(rdev)) { + printk(KERN_WARNING "Failed to wait MC idle while " + "programming pipes. Bad things might happen.\n"); + } + + tmp = rdev->mc.vram_location + rdev->mc.vram_size - 1; + tmp = REG_SET(R700_MC_FB_TOP, tmp >> 24); + tmp |= REG_SET(R700_MC_FB_BASE, rdev->mc.vram_location >> 24); + WREG32(R700_MC_VM_FB_LOCATION, tmp); + tmp = rdev->mc.gtt_location + rdev->mc.gtt_size - 1; + tmp = REG_SET(R700_MC_AGP_TOP, tmp >> 22); + WREG32(R700_MC_VM_AGP_TOP, tmp); + tmp = REG_SET(R700_MC_AGP_BOT, rdev->mc.gtt_location >> 22); + WREG32(R700_MC_VM_AGP_BOT, tmp); + return 0; +} + +void rv770_mc_fini(struct radeon_device *rdev) +{ + /* FIXME: implement */ +} + + +/* + * Global GPU functions + */ +void rv770_errata(struct radeon_device *rdev) +{ + rdev->pll_errata = 0; +} + +int rv770_mc_wait_for_idle(struct radeon_device *rdev) +{ + /* FIXME: implement */ + return 0; +} + +void rv770_gpu_init(struct radeon_device *rdev) +{ + /* FIXME: implement */ +} + + +/* + * VRAM info + */ +void rv770_vram_get_type(struct radeon_device *rdev) +{ + /* FIXME: implement */ +} + +void rv770_vram_info(struct radeon_device *rdev) +{ + rv770_vram_get_type(rdev); + + /* FIXME: implement */ + /* Could aper size report 0 ? */ + rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0); + rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0); +} diff --git a/drivers/gpu/drm/savage/savage_bci.c b/drivers/gpu/drm/savage/savage_bci.c index 456cd040f31a..bff6fc2524c8 100644 --- a/drivers/gpu/drm/savage/savage_bci.c +++ b/drivers/gpu/drm/savage/savage_bci.c @@ -298,8 +298,8 @@ static int savage_dma_init(drm_savage_private_t * dev_priv) dev_priv->nr_dma_pages = dev_priv->cmd_dma->size / (SAVAGE_DMA_PAGE_SIZE * 4); - dev_priv->dma_pages = drm_alloc(sizeof(drm_savage_dma_page_t) * - dev_priv->nr_dma_pages, DRM_MEM_DRIVER); + dev_priv->dma_pages = kmalloc(sizeof(drm_savage_dma_page_t) * + dev_priv->nr_dma_pages, GFP_KERNEL); if (dev_priv->dma_pages == NULL) return -ENOMEM; @@ -539,7 +539,7 @@ int savage_driver_load(struct drm_device *dev, unsigned long chipset) { drm_savage_private_t *dev_priv; - dev_priv = drm_alloc(sizeof(drm_savage_private_t), DRM_MEM_DRIVER); + dev_priv = kmalloc(sizeof(drm_savage_private_t), GFP_KERNEL); if (dev_priv == NULL) return -ENOMEM; @@ -671,7 +671,7 @@ int savage_driver_unload(struct drm_device *dev) { drm_savage_private_t *dev_priv = dev->dev_private; - drm_free(dev_priv, sizeof(drm_savage_private_t), DRM_MEM_DRIVER); + kfree(dev_priv); return 0; } @@ -804,8 +804,8 @@ static int savage_do_init_bci(struct drm_device * dev, drm_savage_init_t * init) dev_priv->fake_dma.offset = 0; dev_priv->fake_dma.size = SAVAGE_FAKE_DMA_SIZE; dev_priv->fake_dma.type = _DRM_SHM; - dev_priv->fake_dma.handle = drm_alloc(SAVAGE_FAKE_DMA_SIZE, - DRM_MEM_DRIVER); + dev_priv->fake_dma.handle = kmalloc(SAVAGE_FAKE_DMA_SIZE, + GFP_KERNEL); if (!dev_priv->fake_dma.handle) { DRM_ERROR("could not allocate faked DMA buffer!\n"); savage_do_cleanup_bci(dev); @@ -903,9 +903,7 @@ static int savage_do_cleanup_bci(struct drm_device * dev) drm_savage_private_t *dev_priv = dev->dev_private; if (dev_priv->cmd_dma == &dev_priv->fake_dma) { - if (dev_priv->fake_dma.handle) - drm_free(dev_priv->fake_dma.handle, - SAVAGE_FAKE_DMA_SIZE, DRM_MEM_DRIVER); + kfree(dev_priv->fake_dma.handle); } else if (dev_priv->cmd_dma && dev_priv->cmd_dma->handle && dev_priv->cmd_dma->type == _DRM_AGP && dev_priv->dma_type == SAVAGE_DMA_AGP) @@ -920,10 +918,7 @@ static int savage_do_cleanup_bci(struct drm_device * dev) dev->agp_buffer_map = NULL; } - if (dev_priv->dma_pages) - drm_free(dev_priv->dma_pages, - sizeof(drm_savage_dma_page_t) * dev_priv->nr_dma_pages, - DRM_MEM_DRIVER); + kfree(dev_priv->dma_pages); return 0; } diff --git a/drivers/gpu/drm/savage/savage_state.c b/drivers/gpu/drm/savage/savage_state.c index 5f6238fdf1fa..8a3e31599c94 100644 --- a/drivers/gpu/drm/savage/savage_state.c +++ b/drivers/gpu/drm/savage/savage_state.c @@ -988,20 +988,20 @@ int savage_bci_cmdbuf(struct drm_device *dev, void *data, struct drm_file *file_ * for locking on FreeBSD. */ if (cmdbuf->size) { - kcmd_addr = drm_alloc(cmdbuf->size * 8, DRM_MEM_DRIVER); + kcmd_addr = kmalloc(cmdbuf->size * 8, GFP_KERNEL); if (kcmd_addr == NULL) return -ENOMEM; if (DRM_COPY_FROM_USER(kcmd_addr, cmdbuf->cmd_addr, cmdbuf->size * 8)) { - drm_free(kcmd_addr, cmdbuf->size * 8, DRM_MEM_DRIVER); + kfree(kcmd_addr); return -EFAULT; } cmdbuf->cmd_addr = kcmd_addr; } if (cmdbuf->vb_size) { - kvb_addr = drm_alloc(cmdbuf->vb_size, DRM_MEM_DRIVER); + kvb_addr = kmalloc(cmdbuf->vb_size, GFP_KERNEL); if (kvb_addr == NULL) { ret = -ENOMEM; goto done; @@ -1015,8 +1015,8 @@ int savage_bci_cmdbuf(struct drm_device *dev, void *data, struct drm_file *file_ cmdbuf->vb_addr = kvb_addr; } if (cmdbuf->nbox) { - kbox_addr = drm_alloc(cmdbuf->nbox * sizeof(struct drm_clip_rect), - DRM_MEM_DRIVER); + kbox_addr = kmalloc(cmdbuf->nbox * sizeof(struct drm_clip_rect), + GFP_KERNEL); if (kbox_addr == NULL) { ret = -ENOMEM; goto done; @@ -1154,10 +1154,9 @@ int savage_bci_cmdbuf(struct drm_device *dev, void *data, struct drm_file *file_ done: /* If we didn't need to allocate them, these'll be NULL */ - drm_free(kcmd_addr, cmdbuf->size * 8, DRM_MEM_DRIVER); - drm_free(kvb_addr, cmdbuf->vb_size, DRM_MEM_DRIVER); - drm_free(kbox_addr, cmdbuf->nbox * sizeof(struct drm_clip_rect), - DRM_MEM_DRIVER); + kfree(kcmd_addr); + kfree(kvb_addr); + kfree(kbox_addr); return ret; } diff --git a/drivers/gpu/drm/sis/sis_drv.c b/drivers/gpu/drm/sis/sis_drv.c index 7dacc64e9b56..e725cc0b1155 100644 --- a/drivers/gpu/drm/sis/sis_drv.c +++ b/drivers/gpu/drm/sis/sis_drv.c @@ -40,7 +40,7 @@ static int sis_driver_load(struct drm_device *dev, unsigned long chipset) drm_sis_private_t *dev_priv; int ret; - dev_priv = drm_calloc(1, sizeof(drm_sis_private_t), DRM_MEM_DRIVER); + dev_priv = kzalloc(sizeof(drm_sis_private_t), GFP_KERNEL); if (dev_priv == NULL) return -ENOMEM; @@ -48,7 +48,7 @@ static int sis_driver_load(struct drm_device *dev, unsigned long chipset) dev_priv->chipset = chipset; ret = drm_sman_init(&dev_priv->sman, 2, 12, 8); if (ret) { - drm_free(dev_priv, sizeof(dev_priv), DRM_MEM_DRIVER); + kfree(dev_priv); } return ret; @@ -59,7 +59,7 @@ static int sis_driver_unload(struct drm_device *dev) drm_sis_private_t *dev_priv = dev->dev_private; drm_sman_takedown(&dev_priv->sman); - drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER); + kfree(dev_priv); return 0; } diff --git a/drivers/gpu/drm/ttm/Makefile b/drivers/gpu/drm/ttm/Makefile new file mode 100644 index 000000000000..b0a9de7a57c2 --- /dev/null +++ b/drivers/gpu/drm/ttm/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for the drm device driver. This driver provides support for the + +ccflags-y := -Iinclude/drm +ttm-y := ttm_agp_backend.o ttm_memory.o ttm_tt.o ttm_bo.o \ + ttm_bo_util.o ttm_bo_vm.o ttm_module.o ttm_global.o + +obj-$(CONFIG_DRM_TTM) += ttm.o diff --git a/drivers/gpu/drm/ttm/ttm_agp_backend.c b/drivers/gpu/drm/ttm/ttm_agp_backend.c new file mode 100644 index 000000000000..4648ed2f0143 --- /dev/null +++ b/drivers/gpu/drm/ttm/ttm_agp_backend.c @@ -0,0 +1,149 @@ +/************************************************************************** + * + * Copyright (c) 2006-2009 VMware, Inc., Palo Alto, CA., USA + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ +/* + * Authors: Thomas Hellstrom + * Keith Packard. + */ + +#include "ttm/ttm_module.h" +#include "ttm/ttm_bo_driver.h" +#ifdef TTM_HAS_AGP +#include "ttm/ttm_placement.h" +#include +#include +#include +#include + +struct ttm_agp_backend { + struct ttm_backend backend; + struct agp_memory *mem; + struct agp_bridge_data *bridge; +}; + +static int ttm_agp_populate(struct ttm_backend *backend, + unsigned long num_pages, struct page **pages, + struct page *dummy_read_page) +{ + struct ttm_agp_backend *agp_be = + container_of(backend, struct ttm_agp_backend, backend); + struct page **cur_page, **last_page = pages + num_pages; + struct agp_memory *mem; + + mem = agp_allocate_memory(agp_be->bridge, num_pages, AGP_USER_MEMORY); + if (unlikely(mem == NULL)) + return -ENOMEM; + + mem->page_count = 0; + for (cur_page = pages; cur_page < last_page; ++cur_page) { + struct page *page = *cur_page; + if (!page) + page = dummy_read_page; + + mem->pages[mem->page_count++] = page; + } + agp_be->mem = mem; + return 0; +} + +static int ttm_agp_bind(struct ttm_backend *backend, struct ttm_mem_reg *bo_mem) +{ + struct ttm_agp_backend *agp_be = + container_of(backend, struct ttm_agp_backend, backend); + struct agp_memory *mem = agp_be->mem; + int cached = (bo_mem->placement & TTM_PL_FLAG_CACHED); + int ret; + + mem->is_flushed = 1; + mem->type = (cached) ? AGP_USER_CACHED_MEMORY : AGP_USER_MEMORY; + + ret = agp_bind_memory(mem, bo_mem->mm_node->start); + if (ret) + printk(KERN_ERR TTM_PFX "AGP Bind memory failed.\n"); + + return ret; +} + +static int ttm_agp_unbind(struct ttm_backend *backend) +{ + struct ttm_agp_backend *agp_be = + container_of(backend, struct ttm_agp_backend, backend); + + if (agp_be->mem->is_bound) + return agp_unbind_memory(agp_be->mem); + else + return 0; +} + +static void ttm_agp_clear(struct ttm_backend *backend) +{ + struct ttm_agp_backend *agp_be = + container_of(backend, struct ttm_agp_backend, backend); + struct agp_memory *mem = agp_be->mem; + + if (mem) { + ttm_agp_unbind(backend); + agp_free_memory(mem); + } + agp_be->mem = NULL; +} + +static void ttm_agp_destroy(struct ttm_backend *backend) +{ + struct ttm_agp_backend *agp_be = + container_of(backend, struct ttm_agp_backend, backend); + + if (agp_be->mem) + ttm_agp_clear(backend); + kfree(agp_be); +} + +static struct ttm_backend_func ttm_agp_func = { + .populate = ttm_agp_populate, + .clear = ttm_agp_clear, + .bind = ttm_agp_bind, + .unbind = ttm_agp_unbind, + .destroy = ttm_agp_destroy, +}; + +struct ttm_backend *ttm_agp_backend_init(struct ttm_bo_device *bdev, + struct agp_bridge_data *bridge) +{ + struct ttm_agp_backend *agp_be; + + agp_be = kmalloc(sizeof(*agp_be), GFP_KERNEL); + if (!agp_be) + return NULL; + + agp_be->mem = NULL; + agp_be->bridge = bridge; + agp_be->backend.func = &ttm_agp_func; + agp_be->backend.bdev = bdev; + return &agp_be->backend; +} +EXPORT_SYMBOL(ttm_agp_backend_init); + +#endif diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c new file mode 100644 index 000000000000..c1c407f7cca3 --- /dev/null +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -0,0 +1,1701 @@ +/************************************************************************** + * + * Copyright (c) 2006-2009 VMware, Inc., Palo Alto, CA., USA + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ +/* + * Authors: Thomas Hellstrom + */ + +#include "ttm/ttm_module.h" +#include "ttm/ttm_bo_driver.h" +#include "ttm/ttm_placement.h" +#include +#include +#include +#include +#include +#include + +#define TTM_ASSERT_LOCKED(param) +#define TTM_DEBUG(fmt, arg...) +#define TTM_BO_HASH_ORDER 13 + +static int ttm_bo_setup_vm(struct ttm_buffer_object *bo); +static void ttm_bo_unmap_virtual(struct ttm_buffer_object *bo); +static int ttm_bo_swapout(struct ttm_mem_shrink *shrink); + +static inline uint32_t ttm_bo_type_flags(unsigned type) +{ + return 1 << (type); +} + +static void ttm_bo_release_list(struct kref *list_kref) +{ + struct ttm_buffer_object *bo = + container_of(list_kref, struct ttm_buffer_object, list_kref); + struct ttm_bo_device *bdev = bo->bdev; + + BUG_ON(atomic_read(&bo->list_kref.refcount)); + BUG_ON(atomic_read(&bo->kref.refcount)); + BUG_ON(atomic_read(&bo->cpu_writers)); + BUG_ON(bo->sync_obj != NULL); + BUG_ON(bo->mem.mm_node != NULL); + BUG_ON(!list_empty(&bo->lru)); + BUG_ON(!list_empty(&bo->ddestroy)); + + if (bo->ttm) + ttm_tt_destroy(bo->ttm); + if (bo->destroy) + bo->destroy(bo); + else { + ttm_mem_global_free(bdev->mem_glob, bo->acc_size, false); + kfree(bo); + } +} + +int ttm_bo_wait_unreserved(struct ttm_buffer_object *bo, bool interruptible) +{ + + if (interruptible) { + int ret = 0; + + ret = wait_event_interruptible(bo->event_queue, + atomic_read(&bo->reserved) == 0); + if (unlikely(ret != 0)) + return -ERESTART; + } else { + wait_event(bo->event_queue, atomic_read(&bo->reserved) == 0); + } + return 0; +} + +static void ttm_bo_add_to_lru(struct ttm_buffer_object *bo) +{ + struct ttm_bo_device *bdev = bo->bdev; + struct ttm_mem_type_manager *man; + + BUG_ON(!atomic_read(&bo->reserved)); + + if (!(bo->mem.placement & TTM_PL_FLAG_NO_EVICT)) { + + BUG_ON(!list_empty(&bo->lru)); + + man = &bdev->man[bo->mem.mem_type]; + list_add_tail(&bo->lru, &man->lru); + kref_get(&bo->list_kref); + + if (bo->ttm != NULL) { + list_add_tail(&bo->swap, &bdev->swap_lru); + kref_get(&bo->list_kref); + } + } +} + +/** + * Call with the lru_lock held. + */ + +static int ttm_bo_del_from_lru(struct ttm_buffer_object *bo) +{ + int put_count = 0; + + if (!list_empty(&bo->swap)) { + list_del_init(&bo->swap); + ++put_count; + } + if (!list_empty(&bo->lru)) { + list_del_init(&bo->lru); + ++put_count; + } + + /* + * TODO: Add a driver hook to delete from + * driver-specific LRU's here. + */ + + return put_count; +} + +int ttm_bo_reserve_locked(struct ttm_buffer_object *bo, + bool interruptible, + bool no_wait, bool use_sequence, uint32_t sequence) +{ + struct ttm_bo_device *bdev = bo->bdev; + int ret; + + while (unlikely(atomic_cmpxchg(&bo->reserved, 0, 1) != 0)) { + if (use_sequence && bo->seq_valid && + (sequence - bo->val_seq < (1 << 31))) { + return -EAGAIN; + } + + if (no_wait) + return -EBUSY; + + spin_unlock(&bdev->lru_lock); + ret = ttm_bo_wait_unreserved(bo, interruptible); + spin_lock(&bdev->lru_lock); + + if (unlikely(ret)) + return ret; + } + + if (use_sequence) { + bo->val_seq = sequence; + bo->seq_valid = true; + } else { + bo->seq_valid = false; + } + + return 0; +} +EXPORT_SYMBOL(ttm_bo_reserve); + +static void ttm_bo_ref_bug(struct kref *list_kref) +{ + BUG(); +} + +int ttm_bo_reserve(struct ttm_buffer_object *bo, + bool interruptible, + bool no_wait, bool use_sequence, uint32_t sequence) +{ + struct ttm_bo_device *bdev = bo->bdev; + int put_count = 0; + int ret; + + spin_lock(&bdev->lru_lock); + ret = ttm_bo_reserve_locked(bo, interruptible, no_wait, use_sequence, + sequence); + if (likely(ret == 0)) + put_count = ttm_bo_del_from_lru(bo); + spin_unlock(&bdev->lru_lock); + + while (put_count--) + kref_put(&bo->list_kref, ttm_bo_ref_bug); + + return ret; +} + +void ttm_bo_unreserve(struct ttm_buffer_object *bo) +{ + struct ttm_bo_device *bdev = bo->bdev; + + spin_lock(&bdev->lru_lock); + ttm_bo_add_to_lru(bo); + atomic_set(&bo->reserved, 0); + wake_up_all(&bo->event_queue); + spin_unlock(&bdev->lru_lock); +} +EXPORT_SYMBOL(ttm_bo_unreserve); + +/* + * Call bo->mutex locked. + */ + +static int ttm_bo_add_ttm(struct ttm_buffer_object *bo, bool zero_alloc) +{ + struct ttm_bo_device *bdev = bo->bdev; + int ret = 0; + uint32_t page_flags = 0; + + TTM_ASSERT_LOCKED(&bo->mutex); + bo->ttm = NULL; + + switch (bo->type) { + case ttm_bo_type_device: + if (zero_alloc) + page_flags |= TTM_PAGE_FLAG_ZERO_ALLOC; + case ttm_bo_type_kernel: + bo->ttm = ttm_tt_create(bdev, bo->num_pages << PAGE_SHIFT, + page_flags, bdev->dummy_read_page); + if (unlikely(bo->ttm == NULL)) + ret = -ENOMEM; + break; + case ttm_bo_type_user: + bo->ttm = ttm_tt_create(bdev, bo->num_pages << PAGE_SHIFT, + page_flags | TTM_PAGE_FLAG_USER, + bdev->dummy_read_page); + if (unlikely(bo->ttm == NULL)) + ret = -ENOMEM; + break; + + ret = ttm_tt_set_user(bo->ttm, current, + bo->buffer_start, bo->num_pages); + if (unlikely(ret != 0)) + ttm_tt_destroy(bo->ttm); + break; + default: + printk(KERN_ERR TTM_PFX "Illegal buffer object type\n"); + ret = -EINVAL; + break; + } + + return ret; +} + +static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo, + struct ttm_mem_reg *mem, + bool evict, bool interruptible, bool no_wait) +{ + struct ttm_bo_device *bdev = bo->bdev; + bool old_is_pci = ttm_mem_reg_is_pci(bdev, &bo->mem); + bool new_is_pci = ttm_mem_reg_is_pci(bdev, mem); + struct ttm_mem_type_manager *old_man = &bdev->man[bo->mem.mem_type]; + struct ttm_mem_type_manager *new_man = &bdev->man[mem->mem_type]; + int ret = 0; + + if (old_is_pci || new_is_pci || + ((mem->placement & bo->mem.placement & TTM_PL_MASK_CACHING) == 0)) + ttm_bo_unmap_virtual(bo); + + /* + * Create and bind a ttm if required. + */ + + if (!(new_man->flags & TTM_MEMTYPE_FLAG_FIXED) && (bo->ttm == NULL)) { + ret = ttm_bo_add_ttm(bo, false); + if (ret) + goto out_err; + + ret = ttm_tt_set_placement_caching(bo->ttm, mem->placement); + if (ret) + goto out_err; + + if (mem->mem_type != TTM_PL_SYSTEM) { + ret = ttm_tt_bind(bo->ttm, mem); + if (ret) + goto out_err; + } + + if (bo->mem.mem_type == TTM_PL_SYSTEM) { + + struct ttm_mem_reg *old_mem = &bo->mem; + uint32_t save_flags = old_mem->placement; + + *old_mem = *mem; + mem->mm_node = NULL; + ttm_flag_masked(&save_flags, mem->placement, + TTM_PL_MASK_MEMTYPE); + goto moved; + } + + } + + if (!(old_man->flags & TTM_MEMTYPE_FLAG_FIXED) && + !(new_man->flags & TTM_MEMTYPE_FLAG_FIXED)) + ret = ttm_bo_move_ttm(bo, evict, no_wait, mem); + else if (bdev->driver->move) + ret = bdev->driver->move(bo, evict, interruptible, + no_wait, mem); + else + ret = ttm_bo_move_memcpy(bo, evict, no_wait, mem); + + if (ret) + goto out_err; + +moved: + if (bo->evicted) { + ret = bdev->driver->invalidate_caches(bdev, bo->mem.placement); + if (ret) + printk(KERN_ERR TTM_PFX "Can not flush read caches\n"); + bo->evicted = false; + } + + if (bo->mem.mm_node) { + spin_lock(&bo->lock); + bo->offset = (bo->mem.mm_node->start << PAGE_SHIFT) + + bdev->man[bo->mem.mem_type].gpu_offset; + bo->cur_placement = bo->mem.placement; + spin_unlock(&bo->lock); + } + + return 0; + +out_err: + new_man = &bdev->man[bo->mem.mem_type]; + if ((new_man->flags & TTM_MEMTYPE_FLAG_FIXED) && bo->ttm) { + ttm_tt_unbind(bo->ttm); + ttm_tt_destroy(bo->ttm); + bo->ttm = NULL; + } + + return ret; +} + +/** + * If bo idle, remove from delayed- and lru lists, and unref. + * If not idle, and already on delayed list, do nothing. + * If not idle, and not on delayed list, put on delayed list, + * up the list_kref and schedule a delayed list check. + */ + +static int ttm_bo_cleanup_refs(struct ttm_buffer_object *bo, bool remove_all) +{ + struct ttm_bo_device *bdev = bo->bdev; + struct ttm_bo_driver *driver = bdev->driver; + int ret; + + spin_lock(&bo->lock); + (void) ttm_bo_wait(bo, false, false, !remove_all); + + if (!bo->sync_obj) { + int put_count; + + spin_unlock(&bo->lock); + + spin_lock(&bdev->lru_lock); + ret = ttm_bo_reserve_locked(bo, false, false, false, 0); + BUG_ON(ret); + if (bo->ttm) + ttm_tt_unbind(bo->ttm); + + if (!list_empty(&bo->ddestroy)) { + list_del_init(&bo->ddestroy); + kref_put(&bo->list_kref, ttm_bo_ref_bug); + } + if (bo->mem.mm_node) { + drm_mm_put_block(bo->mem.mm_node); + bo->mem.mm_node = NULL; + } + put_count = ttm_bo_del_from_lru(bo); + spin_unlock(&bdev->lru_lock); + + atomic_set(&bo->reserved, 0); + + while (put_count--) + kref_put(&bo->list_kref, ttm_bo_release_list); + + return 0; + } + + spin_lock(&bdev->lru_lock); + if (list_empty(&bo->ddestroy)) { + void *sync_obj = bo->sync_obj; + void *sync_obj_arg = bo->sync_obj_arg; + + kref_get(&bo->list_kref); + list_add_tail(&bo->ddestroy, &bdev->ddestroy); + spin_unlock(&bdev->lru_lock); + spin_unlock(&bo->lock); + + if (sync_obj) + driver->sync_obj_flush(sync_obj, sync_obj_arg); + schedule_delayed_work(&bdev->wq, + ((HZ / 100) < 1) ? 1 : HZ / 100); + ret = 0; + + } else { + spin_unlock(&bdev->lru_lock); + spin_unlock(&bo->lock); + ret = -EBUSY; + } + + return ret; +} + +/** + * Traverse the delayed list, and call ttm_bo_cleanup_refs on all + * encountered buffers. + */ + +static int ttm_bo_delayed_delete(struct ttm_bo_device *bdev, bool remove_all) +{ + struct ttm_buffer_object *entry, *nentry; + struct list_head *list, *next; + int ret; + + spin_lock(&bdev->lru_lock); + list_for_each_safe(list, next, &bdev->ddestroy) { + entry = list_entry(list, struct ttm_buffer_object, ddestroy); + nentry = NULL; + + /* + * Protect the next list entry from destruction while we + * unlock the lru_lock. + */ + + if (next != &bdev->ddestroy) { + nentry = list_entry(next, struct ttm_buffer_object, + ddestroy); + kref_get(&nentry->list_kref); + } + kref_get(&entry->list_kref); + + spin_unlock(&bdev->lru_lock); + ret = ttm_bo_cleanup_refs(entry, remove_all); + kref_put(&entry->list_kref, ttm_bo_release_list); + + spin_lock(&bdev->lru_lock); + if (nentry) { + bool next_onlist = !list_empty(next); + spin_unlock(&bdev->lru_lock); + kref_put(&nentry->list_kref, ttm_bo_release_list); + spin_lock(&bdev->lru_lock); + /* + * Someone might have raced us and removed the + * next entry from the list. We don't bother restarting + * list traversal. + */ + + if (!next_onlist) + break; + } + if (ret) + break; + } + ret = !list_empty(&bdev->ddestroy); + spin_unlock(&bdev->lru_lock); + + return ret; +} + +static void ttm_bo_delayed_workqueue(struct work_struct *work) +{ + struct ttm_bo_device *bdev = + container_of(work, struct ttm_bo_device, wq.work); + + if (ttm_bo_delayed_delete(bdev, false)) { + schedule_delayed_work(&bdev->wq, + ((HZ / 100) < 1) ? 1 : HZ / 100); + } +} + +static void ttm_bo_release(struct kref *kref) +{ + struct ttm_buffer_object *bo = + container_of(kref, struct ttm_buffer_object, kref); + struct ttm_bo_device *bdev = bo->bdev; + + if (likely(bo->vm_node != NULL)) { + rb_erase(&bo->vm_rb, &bdev->addr_space_rb); + drm_mm_put_block(bo->vm_node); + bo->vm_node = NULL; + } + write_unlock(&bdev->vm_lock); + ttm_bo_cleanup_refs(bo, false); + kref_put(&bo->list_kref, ttm_bo_release_list); + write_lock(&bdev->vm_lock); +} + +void ttm_bo_unref(struct ttm_buffer_object **p_bo) +{ + struct ttm_buffer_object *bo = *p_bo; + struct ttm_bo_device *bdev = bo->bdev; + + *p_bo = NULL; + write_lock(&bdev->vm_lock); + kref_put(&bo->kref, ttm_bo_release); + write_unlock(&bdev->vm_lock); +} +EXPORT_SYMBOL(ttm_bo_unref); + +static int ttm_bo_evict(struct ttm_buffer_object *bo, unsigned mem_type, + bool interruptible, bool no_wait) +{ + int ret = 0; + struct ttm_bo_device *bdev = bo->bdev; + struct ttm_mem_reg evict_mem; + uint32_t proposed_placement; + + if (bo->mem.mem_type != mem_type) + goto out; + + spin_lock(&bo->lock); + ret = ttm_bo_wait(bo, false, interruptible, no_wait); + spin_unlock(&bo->lock); + + if (unlikely(ret != 0)) { + if (ret != -ERESTART) { + printk(KERN_ERR TTM_PFX + "Failed to expire sync object before " + "buffer eviction.\n"); + } + goto out; + } + + BUG_ON(!atomic_read(&bo->reserved)); + + evict_mem = bo->mem; + evict_mem.mm_node = NULL; + + proposed_placement = bdev->driver->evict_flags(bo); + + ret = ttm_bo_mem_space(bo, proposed_placement, + &evict_mem, interruptible, no_wait); + if (unlikely(ret != 0 && ret != -ERESTART)) + ret = ttm_bo_mem_space(bo, TTM_PL_FLAG_SYSTEM, + &evict_mem, interruptible, no_wait); + + if (ret) { + if (ret != -ERESTART) + printk(KERN_ERR TTM_PFX + "Failed to find memory space for " + "buffer 0x%p eviction.\n", bo); + goto out; + } + + ret = ttm_bo_handle_move_mem(bo, &evict_mem, true, interruptible, + no_wait); + if (ret) { + if (ret != -ERESTART) + printk(KERN_ERR TTM_PFX "Buffer eviction failed\n"); + goto out; + } + + spin_lock(&bdev->lru_lock); + if (evict_mem.mm_node) { + drm_mm_put_block(evict_mem.mm_node); + evict_mem.mm_node = NULL; + } + spin_unlock(&bdev->lru_lock); + bo->evicted = true; +out: + return ret; +} + +/** + * Repeatedly evict memory from the LRU for @mem_type until we create enough + * space, or we've evicted everything and there isn't enough space. + */ +static int ttm_bo_mem_force_space(struct ttm_bo_device *bdev, + struct ttm_mem_reg *mem, + uint32_t mem_type, + bool interruptible, bool no_wait) +{ + struct drm_mm_node *node; + struct ttm_buffer_object *entry; + struct ttm_mem_type_manager *man = &bdev->man[mem_type]; + struct list_head *lru; + unsigned long num_pages = mem->num_pages; + int put_count = 0; + int ret; + +retry_pre_get: + ret = drm_mm_pre_get(&man->manager); + if (unlikely(ret != 0)) + return ret; + + spin_lock(&bdev->lru_lock); + do { + node = drm_mm_search_free(&man->manager, num_pages, + mem->page_alignment, 1); + if (node) + break; + + lru = &man->lru; + if (list_empty(lru)) + break; + + entry = list_first_entry(lru, struct ttm_buffer_object, lru); + kref_get(&entry->list_kref); + + ret = + ttm_bo_reserve_locked(entry, interruptible, no_wait, + false, 0); + + if (likely(ret == 0)) + put_count = ttm_bo_del_from_lru(entry); + + spin_unlock(&bdev->lru_lock); + + if (unlikely(ret != 0)) + return ret; + + while (put_count--) + kref_put(&entry->list_kref, ttm_bo_ref_bug); + + ret = ttm_bo_evict(entry, mem_type, interruptible, no_wait); + + ttm_bo_unreserve(entry); + + kref_put(&entry->list_kref, ttm_bo_release_list); + if (ret) + return ret; + + spin_lock(&bdev->lru_lock); + } while (1); + + if (!node) { + spin_unlock(&bdev->lru_lock); + return -ENOMEM; + } + + node = drm_mm_get_block_atomic(node, num_pages, mem->page_alignment); + if (unlikely(!node)) { + spin_unlock(&bdev->lru_lock); + goto retry_pre_get; + } + + spin_unlock(&bdev->lru_lock); + mem->mm_node = node; + mem->mem_type = mem_type; + return 0; +} + +static bool ttm_bo_mt_compatible(struct ttm_mem_type_manager *man, + bool disallow_fixed, + uint32_t mem_type, + uint32_t mask, uint32_t *res_mask) +{ + uint32_t cur_flags = ttm_bo_type_flags(mem_type); + + if ((man->flags & TTM_MEMTYPE_FLAG_FIXED) && disallow_fixed) + return false; + + if ((cur_flags & mask & TTM_PL_MASK_MEM) == 0) + return false; + + if ((mask & man->available_caching) == 0) + return false; + if (mask & man->default_caching) + cur_flags |= man->default_caching; + else if (mask & TTM_PL_FLAG_CACHED) + cur_flags |= TTM_PL_FLAG_CACHED; + else if (mask & TTM_PL_FLAG_WC) + cur_flags |= TTM_PL_FLAG_WC; + else + cur_flags |= TTM_PL_FLAG_UNCACHED; + + *res_mask = cur_flags; + return true; +} + +/** + * Creates space for memory region @mem according to its type. + * + * This function first searches for free space in compatible memory types in + * the priority order defined by the driver. If free space isn't found, then + * ttm_bo_mem_force_space is attempted in priority order to evict and find + * space. + */ +int ttm_bo_mem_space(struct ttm_buffer_object *bo, + uint32_t proposed_placement, + struct ttm_mem_reg *mem, + bool interruptible, bool no_wait) +{ + struct ttm_bo_device *bdev = bo->bdev; + struct ttm_mem_type_manager *man; + + uint32_t num_prios = bdev->driver->num_mem_type_prio; + const uint32_t *prios = bdev->driver->mem_type_prio; + uint32_t i; + uint32_t mem_type = TTM_PL_SYSTEM; + uint32_t cur_flags = 0; + bool type_found = false; + bool type_ok = false; + bool has_eagain = false; + struct drm_mm_node *node = NULL; + int ret; + + mem->mm_node = NULL; + for (i = 0; i < num_prios; ++i) { + mem_type = prios[i]; + man = &bdev->man[mem_type]; + + type_ok = ttm_bo_mt_compatible(man, + bo->type == ttm_bo_type_user, + mem_type, proposed_placement, + &cur_flags); + + if (!type_ok) + continue; + + if (mem_type == TTM_PL_SYSTEM) + break; + + if (man->has_type && man->use_type) { + type_found = true; + do { + ret = drm_mm_pre_get(&man->manager); + if (unlikely(ret)) + return ret; + + spin_lock(&bdev->lru_lock); + node = drm_mm_search_free(&man->manager, + mem->num_pages, + mem->page_alignment, + 1); + if (unlikely(!node)) { + spin_unlock(&bdev->lru_lock); + break; + } + node = drm_mm_get_block_atomic(node, + mem->num_pages, + mem-> + page_alignment); + spin_unlock(&bdev->lru_lock); + } while (!node); + } + if (node) + break; + } + + if ((type_ok && (mem_type == TTM_PL_SYSTEM)) || node) { + mem->mm_node = node; + mem->mem_type = mem_type; + mem->placement = cur_flags; + return 0; + } + + if (!type_found) + return -EINVAL; + + num_prios = bdev->driver->num_mem_busy_prio; + prios = bdev->driver->mem_busy_prio; + + for (i = 0; i < num_prios; ++i) { + mem_type = prios[i]; + man = &bdev->man[mem_type]; + + if (!man->has_type) + continue; + + if (!ttm_bo_mt_compatible(man, + bo->type == ttm_bo_type_user, + mem_type, + proposed_placement, &cur_flags)) + continue; + + ret = ttm_bo_mem_force_space(bdev, mem, mem_type, + interruptible, no_wait); + + if (ret == 0 && mem->mm_node) { + mem->placement = cur_flags; + return 0; + } + + if (ret == -ERESTART) + has_eagain = true; + } + + ret = (has_eagain) ? -ERESTART : -ENOMEM; + return ret; +} +EXPORT_SYMBOL(ttm_bo_mem_space); + +int ttm_bo_wait_cpu(struct ttm_buffer_object *bo, bool no_wait) +{ + int ret = 0; + + if ((atomic_read(&bo->cpu_writers) > 0) && no_wait) + return -EBUSY; + + ret = wait_event_interruptible(bo->event_queue, + atomic_read(&bo->cpu_writers) == 0); + + if (ret == -ERESTARTSYS) + ret = -ERESTART; + + return ret; +} + +int ttm_bo_move_buffer(struct ttm_buffer_object *bo, + uint32_t proposed_placement, + bool interruptible, bool no_wait) +{ + struct ttm_bo_device *bdev = bo->bdev; + int ret = 0; + struct ttm_mem_reg mem; + + BUG_ON(!atomic_read(&bo->reserved)); + + /* + * FIXME: It's possible to pipeline buffer moves. + * Have the driver move function wait for idle when necessary, + * instead of doing it here. + */ + + spin_lock(&bo->lock); + ret = ttm_bo_wait(bo, false, interruptible, no_wait); + spin_unlock(&bo->lock); + + if (ret) + return ret; + + mem.num_pages = bo->num_pages; + mem.size = mem.num_pages << PAGE_SHIFT; + mem.page_alignment = bo->mem.page_alignment; + + /* + * Determine where to move the buffer. + */ + + ret = ttm_bo_mem_space(bo, proposed_placement, &mem, + interruptible, no_wait); + if (ret) + goto out_unlock; + + ret = ttm_bo_handle_move_mem(bo, &mem, false, interruptible, no_wait); + +out_unlock: + if (ret && mem.mm_node) { + spin_lock(&bdev->lru_lock); + drm_mm_put_block(mem.mm_node); + spin_unlock(&bdev->lru_lock); + } + return ret; +} + +static int ttm_bo_mem_compat(uint32_t proposed_placement, + struct ttm_mem_reg *mem) +{ + if ((proposed_placement & mem->placement & TTM_PL_MASK_MEM) == 0) + return 0; + if ((proposed_placement & mem->placement & TTM_PL_MASK_CACHING) == 0) + return 0; + + return 1; +} + +int ttm_buffer_object_validate(struct ttm_buffer_object *bo, + uint32_t proposed_placement, + bool interruptible, bool no_wait) +{ + int ret; + + BUG_ON(!atomic_read(&bo->reserved)); + bo->proposed_placement = proposed_placement; + + TTM_DEBUG("Proposed placement 0x%08lx, Old flags 0x%08lx\n", + (unsigned long)proposed_placement, + (unsigned long)bo->mem.placement); + + /* + * Check whether we need to move buffer. + */ + + if (!ttm_bo_mem_compat(bo->proposed_placement, &bo->mem)) { + ret = ttm_bo_move_buffer(bo, bo->proposed_placement, + interruptible, no_wait); + if (ret) { + if (ret != -ERESTART) + printk(KERN_ERR TTM_PFX + "Failed moving buffer. " + "Proposed placement 0x%08x\n", + bo->proposed_placement); + if (ret == -ENOMEM) + printk(KERN_ERR TTM_PFX + "Out of aperture space or " + "DRM memory quota.\n"); + return ret; + } + } + + /* + * We might need to add a TTM. + */ + + if (bo->mem.mem_type == TTM_PL_SYSTEM && bo->ttm == NULL) { + ret = ttm_bo_add_ttm(bo, true); + if (ret) + return ret; + } + /* + * Validation has succeeded, move the access and other + * non-mapping-related flag bits from the proposed flags to + * the active flags + */ + + ttm_flag_masked(&bo->mem.placement, bo->proposed_placement, + ~TTM_PL_MASK_MEMTYPE); + + return 0; +} +EXPORT_SYMBOL(ttm_buffer_object_validate); + +int +ttm_bo_check_placement(struct ttm_buffer_object *bo, + uint32_t set_flags, uint32_t clr_flags) +{ + uint32_t new_mask = set_flags | clr_flags; + + if ((bo->type == ttm_bo_type_user) && + (clr_flags & TTM_PL_FLAG_CACHED)) { + printk(KERN_ERR TTM_PFX + "User buffers require cache-coherent memory.\n"); + return -EINVAL; + } + + if (!capable(CAP_SYS_ADMIN)) { + if (new_mask & TTM_PL_FLAG_NO_EVICT) { + printk(KERN_ERR TTM_PFX "Need to be root to modify" + " NO_EVICT status.\n"); + return -EINVAL; + } + + if ((clr_flags & bo->mem.placement & TTM_PL_MASK_MEMTYPE) && + (bo->mem.placement & TTM_PL_FLAG_NO_EVICT)) { + printk(KERN_ERR TTM_PFX + "Incompatible memory specification" + " for NO_EVICT buffer.\n"); + return -EINVAL; + } + } + return 0; +} + +int ttm_buffer_object_init(struct ttm_bo_device *bdev, + struct ttm_buffer_object *bo, + unsigned long size, + enum ttm_bo_type type, + uint32_t flags, + uint32_t page_alignment, + unsigned long buffer_start, + bool interruptible, + struct file *persistant_swap_storage, + size_t acc_size, + void (*destroy) (struct ttm_buffer_object *)) +{ + int ret = 0; + unsigned long num_pages; + + size += buffer_start & ~PAGE_MASK; + num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; + if (num_pages == 0) { + printk(KERN_ERR TTM_PFX "Illegal buffer object size.\n"); + return -EINVAL; + } + bo->destroy = destroy; + + spin_lock_init(&bo->lock); + kref_init(&bo->kref); + kref_init(&bo->list_kref); + atomic_set(&bo->cpu_writers, 0); + atomic_set(&bo->reserved, 1); + init_waitqueue_head(&bo->event_queue); + INIT_LIST_HEAD(&bo->lru); + INIT_LIST_HEAD(&bo->ddestroy); + INIT_LIST_HEAD(&bo->swap); + bo->bdev = bdev; + bo->type = type; + bo->num_pages = num_pages; + bo->mem.mem_type = TTM_PL_SYSTEM; + bo->mem.num_pages = bo->num_pages; + bo->mem.mm_node = NULL; + bo->mem.page_alignment = page_alignment; + bo->buffer_start = buffer_start & PAGE_MASK; + bo->priv_flags = 0; + bo->mem.placement = (TTM_PL_FLAG_SYSTEM | TTM_PL_FLAG_CACHED); + bo->seq_valid = false; + bo->persistant_swap_storage = persistant_swap_storage; + bo->acc_size = acc_size; + + ret = ttm_bo_check_placement(bo, flags, 0ULL); + if (unlikely(ret != 0)) + goto out_err; + + /* + * If no caching attributes are set, accept any form of caching. + */ + + if ((flags & TTM_PL_MASK_CACHING) == 0) + flags |= TTM_PL_MASK_CACHING; + + /* + * For ttm_bo_type_device buffers, allocate + * address space from the device. + */ + + if (bo->type == ttm_bo_type_device) { + ret = ttm_bo_setup_vm(bo); + if (ret) + goto out_err; + } + + ret = ttm_buffer_object_validate(bo, flags, interruptible, false); + if (ret) + goto out_err; + + ttm_bo_unreserve(bo); + return 0; + +out_err: + ttm_bo_unreserve(bo); + ttm_bo_unref(&bo); + + return ret; +} +EXPORT_SYMBOL(ttm_buffer_object_init); + +static inline size_t ttm_bo_size(struct ttm_bo_device *bdev, + unsigned long num_pages) +{ + size_t page_array_size = (num_pages * sizeof(void *) + PAGE_SIZE - 1) & + PAGE_MASK; + + return bdev->ttm_bo_size + 2 * page_array_size; +} + +int ttm_buffer_object_create(struct ttm_bo_device *bdev, + unsigned long size, + enum ttm_bo_type type, + uint32_t flags, + uint32_t page_alignment, + unsigned long buffer_start, + bool interruptible, + struct file *persistant_swap_storage, + struct ttm_buffer_object **p_bo) +{ + struct ttm_buffer_object *bo; + int ret; + struct ttm_mem_global *mem_glob = bdev->mem_glob; + + size_t acc_size = + ttm_bo_size(bdev, (size + PAGE_SIZE - 1) >> PAGE_SHIFT); + ret = ttm_mem_global_alloc(mem_glob, acc_size, false, false, false); + if (unlikely(ret != 0)) + return ret; + + bo = kzalloc(sizeof(*bo), GFP_KERNEL); + + if (unlikely(bo == NULL)) { + ttm_mem_global_free(mem_glob, acc_size, false); + return -ENOMEM; + } + + ret = ttm_buffer_object_init(bdev, bo, size, type, flags, + page_alignment, buffer_start, + interruptible, + persistant_swap_storage, acc_size, NULL); + if (likely(ret == 0)) + *p_bo = bo; + + return ret; +} + +static int ttm_bo_leave_list(struct ttm_buffer_object *bo, + uint32_t mem_type, bool allow_errors) +{ + int ret; + + spin_lock(&bo->lock); + ret = ttm_bo_wait(bo, false, false, false); + spin_unlock(&bo->lock); + + if (ret && allow_errors) + goto out; + + if (bo->mem.mem_type == mem_type) + ret = ttm_bo_evict(bo, mem_type, false, false); + + if (ret) { + if (allow_errors) { + goto out; + } else { + ret = 0; + printk(KERN_ERR TTM_PFX "Cleanup eviction failed\n"); + } + } + +out: + return ret; +} + +static int ttm_bo_force_list_clean(struct ttm_bo_device *bdev, + struct list_head *head, + unsigned mem_type, bool allow_errors) +{ + struct ttm_buffer_object *entry; + int ret; + int put_count; + + /* + * Can't use standard list traversal since we're unlocking. + */ + + spin_lock(&bdev->lru_lock); + + while (!list_empty(head)) { + entry = list_first_entry(head, struct ttm_buffer_object, lru); + kref_get(&entry->list_kref); + ret = ttm_bo_reserve_locked(entry, false, false, false, 0); + put_count = ttm_bo_del_from_lru(entry); + spin_unlock(&bdev->lru_lock); + while (put_count--) + kref_put(&entry->list_kref, ttm_bo_ref_bug); + BUG_ON(ret); + ret = ttm_bo_leave_list(entry, mem_type, allow_errors); + ttm_bo_unreserve(entry); + kref_put(&entry->list_kref, ttm_bo_release_list); + spin_lock(&bdev->lru_lock); + } + + spin_unlock(&bdev->lru_lock); + + return 0; +} + +int ttm_bo_clean_mm(struct ttm_bo_device *bdev, unsigned mem_type) +{ + struct ttm_mem_type_manager *man = &bdev->man[mem_type]; + int ret = -EINVAL; + + if (mem_type >= TTM_NUM_MEM_TYPES) { + printk(KERN_ERR TTM_PFX "Illegal memory type %d\n", mem_type); + return ret; + } + + if (!man->has_type) { + printk(KERN_ERR TTM_PFX "Trying to take down uninitialized " + "memory manager type %u\n", mem_type); + return ret; + } + + man->use_type = false; + man->has_type = false; + + ret = 0; + if (mem_type > 0) { + ttm_bo_force_list_clean(bdev, &man->lru, mem_type, false); + + spin_lock(&bdev->lru_lock); + if (drm_mm_clean(&man->manager)) + drm_mm_takedown(&man->manager); + else + ret = -EBUSY; + + spin_unlock(&bdev->lru_lock); + } + + return ret; +} +EXPORT_SYMBOL(ttm_bo_clean_mm); + +int ttm_bo_evict_mm(struct ttm_bo_device *bdev, unsigned mem_type) +{ + struct ttm_mem_type_manager *man = &bdev->man[mem_type]; + + if (mem_type == 0 || mem_type >= TTM_NUM_MEM_TYPES) { + printk(KERN_ERR TTM_PFX + "Illegal memory manager memory type %u.\n", + mem_type); + return -EINVAL; + } + + if (!man->has_type) { + printk(KERN_ERR TTM_PFX + "Memory type %u has not been initialized.\n", + mem_type); + return 0; + } + + return ttm_bo_force_list_clean(bdev, &man->lru, mem_type, true); +} +EXPORT_SYMBOL(ttm_bo_evict_mm); + +int ttm_bo_init_mm(struct ttm_bo_device *bdev, unsigned type, + unsigned long p_offset, unsigned long p_size) +{ + int ret = -EINVAL; + struct ttm_mem_type_manager *man; + + if (type >= TTM_NUM_MEM_TYPES) { + printk(KERN_ERR TTM_PFX "Illegal memory type %d\n", type); + return ret; + } + + man = &bdev->man[type]; + if (man->has_type) { + printk(KERN_ERR TTM_PFX + "Memory manager already initialized for type %d\n", + type); + return ret; + } + + ret = bdev->driver->init_mem_type(bdev, type, man); + if (ret) + return ret; + + ret = 0; + if (type != TTM_PL_SYSTEM) { + if (!p_size) { + printk(KERN_ERR TTM_PFX + "Zero size memory manager type %d\n", + type); + return ret; + } + ret = drm_mm_init(&man->manager, p_offset, p_size); + if (ret) + return ret; + } + man->has_type = true; + man->use_type = true; + man->size = p_size; + + INIT_LIST_HEAD(&man->lru); + + return 0; +} +EXPORT_SYMBOL(ttm_bo_init_mm); + +int ttm_bo_device_release(struct ttm_bo_device *bdev) +{ + int ret = 0; + unsigned i = TTM_NUM_MEM_TYPES; + struct ttm_mem_type_manager *man; + + while (i--) { + man = &bdev->man[i]; + if (man->has_type) { + man->use_type = false; + if ((i != TTM_PL_SYSTEM) && ttm_bo_clean_mm(bdev, i)) { + ret = -EBUSY; + printk(KERN_ERR TTM_PFX + "DRM memory manager type %d " + "is not clean.\n", i); + } + man->has_type = false; + } + } + + if (!cancel_delayed_work(&bdev->wq)) + flush_scheduled_work(); + + while (ttm_bo_delayed_delete(bdev, true)) + ; + + spin_lock(&bdev->lru_lock); + if (list_empty(&bdev->ddestroy)) + TTM_DEBUG("Delayed destroy list was clean\n"); + + if (list_empty(&bdev->man[0].lru)) + TTM_DEBUG("Swap list was clean\n"); + spin_unlock(&bdev->lru_lock); + + ttm_mem_unregister_shrink(bdev->mem_glob, &bdev->shrink); + BUG_ON(!drm_mm_clean(&bdev->addr_space_mm)); + write_lock(&bdev->vm_lock); + drm_mm_takedown(&bdev->addr_space_mm); + write_unlock(&bdev->vm_lock); + + __free_page(bdev->dummy_read_page); + return ret; +} +EXPORT_SYMBOL(ttm_bo_device_release); + +/* + * This function is intended to be called on drm driver load. + * If you decide to call it from firstopen, you must protect the call + * from a potentially racing ttm_bo_driver_finish in lastclose. + * (This may happen on X server restart). + */ + +int ttm_bo_device_init(struct ttm_bo_device *bdev, + struct ttm_mem_global *mem_glob, + struct ttm_bo_driver *driver, uint64_t file_page_offset) +{ + int ret = -EINVAL; + + bdev->dummy_read_page = NULL; + rwlock_init(&bdev->vm_lock); + spin_lock_init(&bdev->lru_lock); + + bdev->driver = driver; + bdev->mem_glob = mem_glob; + + memset(bdev->man, 0, sizeof(bdev->man)); + + bdev->dummy_read_page = alloc_page(__GFP_ZERO | GFP_DMA32); + if (unlikely(bdev->dummy_read_page == NULL)) { + ret = -ENOMEM; + goto out_err0; + } + + /* + * Initialize the system memory buffer type. + * Other types need to be driver / IOCTL initialized. + */ + ret = ttm_bo_init_mm(bdev, TTM_PL_SYSTEM, 0, 0); + if (unlikely(ret != 0)) + goto out_err1; + + bdev->addr_space_rb = RB_ROOT; + ret = drm_mm_init(&bdev->addr_space_mm, file_page_offset, 0x10000000); + if (unlikely(ret != 0)) + goto out_err2; + + INIT_DELAYED_WORK(&bdev->wq, ttm_bo_delayed_workqueue); + bdev->nice_mode = true; + INIT_LIST_HEAD(&bdev->ddestroy); + INIT_LIST_HEAD(&bdev->swap_lru); + bdev->dev_mapping = NULL; + ttm_mem_init_shrink(&bdev->shrink, ttm_bo_swapout); + ret = ttm_mem_register_shrink(mem_glob, &bdev->shrink); + if (unlikely(ret != 0)) { + printk(KERN_ERR TTM_PFX + "Could not register buffer object swapout.\n"); + goto out_err2; + } + + bdev->ttm_bo_extra_size = + ttm_round_pot(sizeof(struct ttm_tt)) + + ttm_round_pot(sizeof(struct ttm_backend)); + + bdev->ttm_bo_size = bdev->ttm_bo_extra_size + + ttm_round_pot(sizeof(struct ttm_buffer_object)); + + return 0; +out_err2: + ttm_bo_clean_mm(bdev, 0); +out_err1: + __free_page(bdev->dummy_read_page); +out_err0: + return ret; +} +EXPORT_SYMBOL(ttm_bo_device_init); + +/* + * buffer object vm functions. + */ + +bool ttm_mem_reg_is_pci(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) +{ + struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type]; + + if (!(man->flags & TTM_MEMTYPE_FLAG_FIXED)) { + if (mem->mem_type == TTM_PL_SYSTEM) + return false; + + if (man->flags & TTM_MEMTYPE_FLAG_CMA) + return false; + + if (mem->placement & TTM_PL_FLAG_CACHED) + return false; + } + return true; +} + +int ttm_bo_pci_offset(struct ttm_bo_device *bdev, + struct ttm_mem_reg *mem, + unsigned long *bus_base, + unsigned long *bus_offset, unsigned long *bus_size) +{ + struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type]; + + *bus_size = 0; + if (!(man->flags & TTM_MEMTYPE_FLAG_MAPPABLE)) + return -EINVAL; + + if (ttm_mem_reg_is_pci(bdev, mem)) { + *bus_offset = mem->mm_node->start << PAGE_SHIFT; + *bus_size = mem->num_pages << PAGE_SHIFT; + *bus_base = man->io_offset; + } + + return 0; +} + +void ttm_bo_unmap_virtual(struct ttm_buffer_object *bo) +{ + struct ttm_bo_device *bdev = bo->bdev; + loff_t offset = (loff_t) bo->addr_space_offset; + loff_t holelen = ((loff_t) bo->mem.num_pages) << PAGE_SHIFT; + + if (!bdev->dev_mapping) + return; + + unmap_mapping_range(bdev->dev_mapping, offset, holelen, 1); +} + +static void ttm_bo_vm_insert_rb(struct ttm_buffer_object *bo) +{ + struct ttm_bo_device *bdev = bo->bdev; + struct rb_node **cur = &bdev->addr_space_rb.rb_node; + struct rb_node *parent = NULL; + struct ttm_buffer_object *cur_bo; + unsigned long offset = bo->vm_node->start; + unsigned long cur_offset; + + while (*cur) { + parent = *cur; + cur_bo = rb_entry(parent, struct ttm_buffer_object, vm_rb); + cur_offset = cur_bo->vm_node->start; + if (offset < cur_offset) + cur = &parent->rb_left; + else if (offset > cur_offset) + cur = &parent->rb_right; + else + BUG(); + } + + rb_link_node(&bo->vm_rb, parent, cur); + rb_insert_color(&bo->vm_rb, &bdev->addr_space_rb); +} + +/** + * ttm_bo_setup_vm: + * + * @bo: the buffer to allocate address space for + * + * Allocate address space in the drm device so that applications + * can mmap the buffer and access the contents. This only + * applies to ttm_bo_type_device objects as others are not + * placed in the drm device address space. + */ + +static int ttm_bo_setup_vm(struct ttm_buffer_object *bo) +{ + struct ttm_bo_device *bdev = bo->bdev; + int ret; + +retry_pre_get: + ret = drm_mm_pre_get(&bdev->addr_space_mm); + if (unlikely(ret != 0)) + return ret; + + write_lock(&bdev->vm_lock); + bo->vm_node = drm_mm_search_free(&bdev->addr_space_mm, + bo->mem.num_pages, 0, 0); + + if (unlikely(bo->vm_node == NULL)) { + ret = -ENOMEM; + goto out_unlock; + } + + bo->vm_node = drm_mm_get_block_atomic(bo->vm_node, + bo->mem.num_pages, 0); + + if (unlikely(bo->vm_node == NULL)) { + write_unlock(&bdev->vm_lock); + goto retry_pre_get; + } + + ttm_bo_vm_insert_rb(bo); + write_unlock(&bdev->vm_lock); + bo->addr_space_offset = ((uint64_t) bo->vm_node->start) << PAGE_SHIFT; + + return 0; +out_unlock: + write_unlock(&bdev->vm_lock); + return ret; +} + +int ttm_bo_wait(struct ttm_buffer_object *bo, + bool lazy, bool interruptible, bool no_wait) +{ + struct ttm_bo_driver *driver = bo->bdev->driver; + void *sync_obj; + void *sync_obj_arg; + int ret = 0; + + if (likely(bo->sync_obj == NULL)) + return 0; + + while (bo->sync_obj) { + + if (driver->sync_obj_signaled(bo->sync_obj, bo->sync_obj_arg)) { + void *tmp_obj = bo->sync_obj; + bo->sync_obj = NULL; + clear_bit(TTM_BO_PRIV_FLAG_MOVING, &bo->priv_flags); + spin_unlock(&bo->lock); + driver->sync_obj_unref(&tmp_obj); + spin_lock(&bo->lock); + continue; + } + + if (no_wait) + return -EBUSY; + + sync_obj = driver->sync_obj_ref(bo->sync_obj); + sync_obj_arg = bo->sync_obj_arg; + spin_unlock(&bo->lock); + ret = driver->sync_obj_wait(sync_obj, sync_obj_arg, + lazy, interruptible); + if (unlikely(ret != 0)) { + driver->sync_obj_unref(&sync_obj); + spin_lock(&bo->lock); + return ret; + } + spin_lock(&bo->lock); + if (likely(bo->sync_obj == sync_obj && + bo->sync_obj_arg == sync_obj_arg)) { + void *tmp_obj = bo->sync_obj; + bo->sync_obj = NULL; + clear_bit(TTM_BO_PRIV_FLAG_MOVING, + &bo->priv_flags); + spin_unlock(&bo->lock); + driver->sync_obj_unref(&sync_obj); + driver->sync_obj_unref(&tmp_obj); + spin_lock(&bo->lock); + } + } + return 0; +} +EXPORT_SYMBOL(ttm_bo_wait); + +void ttm_bo_unblock_reservation(struct ttm_buffer_object *bo) +{ + atomic_set(&bo->reserved, 0); + wake_up_all(&bo->event_queue); +} + +int ttm_bo_block_reservation(struct ttm_buffer_object *bo, bool interruptible, + bool no_wait) +{ + int ret; + + while (unlikely(atomic_cmpxchg(&bo->reserved, 0, 1) != 0)) { + if (no_wait) + return -EBUSY; + else if (interruptible) { + ret = wait_event_interruptible + (bo->event_queue, atomic_read(&bo->reserved) == 0); + if (unlikely(ret != 0)) + return -ERESTART; + } else { + wait_event(bo->event_queue, + atomic_read(&bo->reserved) == 0); + } + } + return 0; +} + +int ttm_bo_synccpu_write_grab(struct ttm_buffer_object *bo, bool no_wait) +{ + int ret = 0; + + /* + * Using ttm_bo_reserve instead of ttm_bo_block_reservation + * makes sure the lru lists are updated. + */ + + ret = ttm_bo_reserve(bo, true, no_wait, false, 0); + if (unlikely(ret != 0)) + return ret; + spin_lock(&bo->lock); + ret = ttm_bo_wait(bo, false, true, no_wait); + spin_unlock(&bo->lock); + if (likely(ret == 0)) + atomic_inc(&bo->cpu_writers); + ttm_bo_unreserve(bo); + return ret; +} + +void ttm_bo_synccpu_write_release(struct ttm_buffer_object *bo) +{ + if (atomic_dec_and_test(&bo->cpu_writers)) + wake_up_all(&bo->event_queue); +} + +/** + * A buffer object shrink method that tries to swap out the first + * buffer object on the bo_global::swap_lru list. + */ + +static int ttm_bo_swapout(struct ttm_mem_shrink *shrink) +{ + struct ttm_bo_device *bdev = + container_of(shrink, struct ttm_bo_device, shrink); + struct ttm_buffer_object *bo; + int ret = -EBUSY; + int put_count; + uint32_t swap_placement = (TTM_PL_FLAG_CACHED | TTM_PL_FLAG_SYSTEM); + + spin_lock(&bdev->lru_lock); + while (ret == -EBUSY) { + if (unlikely(list_empty(&bdev->swap_lru))) { + spin_unlock(&bdev->lru_lock); + return -EBUSY; + } + + bo = list_first_entry(&bdev->swap_lru, + struct ttm_buffer_object, swap); + kref_get(&bo->list_kref); + + /** + * Reserve buffer. Since we unlock while sleeping, we need + * to re-check that nobody removed us from the swap-list while + * we slept. + */ + + ret = ttm_bo_reserve_locked(bo, false, true, false, 0); + if (unlikely(ret == -EBUSY)) { + spin_unlock(&bdev->lru_lock); + ttm_bo_wait_unreserved(bo, false); + kref_put(&bo->list_kref, ttm_bo_release_list); + spin_lock(&bdev->lru_lock); + } + } + + BUG_ON(ret != 0); + put_count = ttm_bo_del_from_lru(bo); + spin_unlock(&bdev->lru_lock); + + while (put_count--) + kref_put(&bo->list_kref, ttm_bo_ref_bug); + + /** + * Wait for GPU, then move to system cached. + */ + + spin_lock(&bo->lock); + ret = ttm_bo_wait(bo, false, false, false); + spin_unlock(&bo->lock); + + if (unlikely(ret != 0)) + goto out; + + if ((bo->mem.placement & swap_placement) != swap_placement) { + struct ttm_mem_reg evict_mem; + + evict_mem = bo->mem; + evict_mem.mm_node = NULL; + evict_mem.placement = TTM_PL_FLAG_SYSTEM | TTM_PL_FLAG_CACHED; + evict_mem.mem_type = TTM_PL_SYSTEM; + + ret = ttm_bo_handle_move_mem(bo, &evict_mem, true, + false, false); + if (unlikely(ret != 0)) + goto out; + } + + ttm_bo_unmap_virtual(bo); + + /** + * Swap out. Buffer will be swapped in again as soon as + * anyone tries to access a ttm page. + */ + + ret = ttm_tt_swapout(bo->ttm, bo->persistant_swap_storage); +out: + + /** + * + * Unreserve without putting on LRU to avoid swapping out an + * already swapped buffer. + */ + + atomic_set(&bo->reserved, 0); + wake_up_all(&bo->event_queue); + kref_put(&bo->list_kref, ttm_bo_release_list); + return ret; +} + +void ttm_bo_swapout_all(struct ttm_bo_device *bdev) +{ + while (ttm_bo_swapout(&bdev->shrink) == 0) + ; +} diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c new file mode 100644 index 000000000000..517c84559633 --- /dev/null +++ b/drivers/gpu/drm/ttm/ttm_bo_util.c @@ -0,0 +1,561 @@ +/************************************************************************** + * + * Copyright (c) 2007-2009 VMware, Inc., Palo Alto, CA., USA + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ +/* + * Authors: Thomas Hellstrom + */ + +#include "ttm/ttm_bo_driver.h" +#include "ttm/ttm_placement.h" +#include +#include +#include +#include +#include +#include + +void ttm_bo_free_old_node(struct ttm_buffer_object *bo) +{ + struct ttm_mem_reg *old_mem = &bo->mem; + + if (old_mem->mm_node) { + spin_lock(&bo->bdev->lru_lock); + drm_mm_put_block(old_mem->mm_node); + spin_unlock(&bo->bdev->lru_lock); + } + old_mem->mm_node = NULL; +} + +int ttm_bo_move_ttm(struct ttm_buffer_object *bo, + bool evict, bool no_wait, struct ttm_mem_reg *new_mem) +{ + struct ttm_tt *ttm = bo->ttm; + struct ttm_mem_reg *old_mem = &bo->mem; + uint32_t save_flags = old_mem->placement; + int ret; + + if (old_mem->mem_type != TTM_PL_SYSTEM) { + ttm_tt_unbind(ttm); + ttm_bo_free_old_node(bo); + ttm_flag_masked(&old_mem->placement, TTM_PL_FLAG_SYSTEM, + TTM_PL_MASK_MEM); + old_mem->mem_type = TTM_PL_SYSTEM; + save_flags = old_mem->placement; + } + + ret = ttm_tt_set_placement_caching(ttm, new_mem->placement); + if (unlikely(ret != 0)) + return ret; + + if (new_mem->mem_type != TTM_PL_SYSTEM) { + ret = ttm_tt_bind(ttm, new_mem); + if (unlikely(ret != 0)) + return ret; + } + + *old_mem = *new_mem; + new_mem->mm_node = NULL; + ttm_flag_masked(&save_flags, new_mem->placement, TTM_PL_MASK_MEMTYPE); + return 0; +} +EXPORT_SYMBOL(ttm_bo_move_ttm); + +int ttm_mem_reg_ioremap(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem, + void **virtual) +{ + struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type]; + unsigned long bus_offset; + unsigned long bus_size; + unsigned long bus_base; + int ret; + void *addr; + + *virtual = NULL; + ret = ttm_bo_pci_offset(bdev, mem, &bus_base, &bus_offset, &bus_size); + if (ret || bus_size == 0) + return ret; + + if (!(man->flags & TTM_MEMTYPE_FLAG_NEEDS_IOREMAP)) + addr = (void *)(((u8 *) man->io_addr) + bus_offset); + else { + if (mem->placement & TTM_PL_FLAG_WC) + addr = ioremap_wc(bus_base + bus_offset, bus_size); + else + addr = ioremap_nocache(bus_base + bus_offset, bus_size); + if (!addr) + return -ENOMEM; + } + *virtual = addr; + return 0; +} + +void ttm_mem_reg_iounmap(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem, + void *virtual) +{ + struct ttm_mem_type_manager *man; + + man = &bdev->man[mem->mem_type]; + + if (virtual && (man->flags & TTM_MEMTYPE_FLAG_NEEDS_IOREMAP)) + iounmap(virtual); +} + +static int ttm_copy_io_page(void *dst, void *src, unsigned long page) +{ + uint32_t *dstP = + (uint32_t *) ((unsigned long)dst + (page << PAGE_SHIFT)); + uint32_t *srcP = + (uint32_t *) ((unsigned long)src + (page << PAGE_SHIFT)); + + int i; + for (i = 0; i < PAGE_SIZE / sizeof(uint32_t); ++i) + iowrite32(ioread32(srcP++), dstP++); + return 0; +} + +static int ttm_copy_io_ttm_page(struct ttm_tt *ttm, void *src, + unsigned long page) +{ + struct page *d = ttm_tt_get_page(ttm, page); + void *dst; + + if (!d) + return -ENOMEM; + + src = (void *)((unsigned long)src + (page << PAGE_SHIFT)); + dst = kmap(d); + if (!dst) + return -ENOMEM; + + memcpy_fromio(dst, src, PAGE_SIZE); + kunmap(d); + return 0; +} + +static int ttm_copy_ttm_io_page(struct ttm_tt *ttm, void *dst, + unsigned long page) +{ + struct page *s = ttm_tt_get_page(ttm, page); + void *src; + + if (!s) + return -ENOMEM; + + dst = (void *)((unsigned long)dst + (page << PAGE_SHIFT)); + src = kmap(s); + if (!src) + return -ENOMEM; + + memcpy_toio(dst, src, PAGE_SIZE); + kunmap(s); + return 0; +} + +int ttm_bo_move_memcpy(struct ttm_buffer_object *bo, + bool evict, bool no_wait, struct ttm_mem_reg *new_mem) +{ + struct ttm_bo_device *bdev = bo->bdev; + struct ttm_mem_type_manager *man = &bdev->man[new_mem->mem_type]; + struct ttm_tt *ttm = bo->ttm; + struct ttm_mem_reg *old_mem = &bo->mem; + struct ttm_mem_reg old_copy = *old_mem; + void *old_iomap; + void *new_iomap; + int ret; + uint32_t save_flags = old_mem->placement; + unsigned long i; + unsigned long page; + unsigned long add = 0; + int dir; + + ret = ttm_mem_reg_ioremap(bdev, old_mem, &old_iomap); + if (ret) + return ret; + ret = ttm_mem_reg_ioremap(bdev, new_mem, &new_iomap); + if (ret) + goto out; + + if (old_iomap == NULL && new_iomap == NULL) + goto out2; + if (old_iomap == NULL && ttm == NULL) + goto out2; + + add = 0; + dir = 1; + + if ((old_mem->mem_type == new_mem->mem_type) && + (new_mem->mm_node->start < + old_mem->mm_node->start + old_mem->mm_node->size)) { + dir = -1; + add = new_mem->num_pages - 1; + } + + for (i = 0; i < new_mem->num_pages; ++i) { + page = i * dir + add; + if (old_iomap == NULL) + ret = ttm_copy_ttm_io_page(ttm, new_iomap, page); + else if (new_iomap == NULL) + ret = ttm_copy_io_ttm_page(ttm, old_iomap, page); + else + ret = ttm_copy_io_page(new_iomap, old_iomap, page); + if (ret) + goto out1; + } + mb(); +out2: + ttm_bo_free_old_node(bo); + + *old_mem = *new_mem; + new_mem->mm_node = NULL; + ttm_flag_masked(&save_flags, new_mem->placement, TTM_PL_MASK_MEMTYPE); + + if ((man->flags & TTM_MEMTYPE_FLAG_FIXED) && (ttm != NULL)) { + ttm_tt_unbind(ttm); + ttm_tt_destroy(ttm); + bo->ttm = NULL; + } + +out1: + ttm_mem_reg_iounmap(bdev, new_mem, new_iomap); +out: + ttm_mem_reg_iounmap(bdev, &old_copy, old_iomap); + return ret; +} +EXPORT_SYMBOL(ttm_bo_move_memcpy); + +static void ttm_transfered_destroy(struct ttm_buffer_object *bo) +{ + kfree(bo); +} + +/** + * ttm_buffer_object_transfer + * + * @bo: A pointer to a struct ttm_buffer_object. + * @new_obj: A pointer to a pointer to a newly created ttm_buffer_object, + * holding the data of @bo with the old placement. + * + * This is a utility function that may be called after an accelerated move + * has been scheduled. A new buffer object is created as a placeholder for + * the old data while it's being copied. When that buffer object is idle, + * it can be destroyed, releasing the space of the old placement. + * Returns: + * !0: Failure. + */ + +static int ttm_buffer_object_transfer(struct ttm_buffer_object *bo, + struct ttm_buffer_object **new_obj) +{ + struct ttm_buffer_object *fbo; + struct ttm_bo_device *bdev = bo->bdev; + struct ttm_bo_driver *driver = bdev->driver; + + fbo = kzalloc(sizeof(*fbo), GFP_KERNEL); + if (!fbo) + return -ENOMEM; + + *fbo = *bo; + + /** + * Fix up members that we shouldn't copy directly: + * TODO: Explicit member copy would probably be better here. + */ + + spin_lock_init(&fbo->lock); + init_waitqueue_head(&fbo->event_queue); + INIT_LIST_HEAD(&fbo->ddestroy); + INIT_LIST_HEAD(&fbo->lru); + INIT_LIST_HEAD(&fbo->swap); + fbo->vm_node = NULL; + + fbo->sync_obj = driver->sync_obj_ref(bo->sync_obj); + if (fbo->mem.mm_node) + fbo->mem.mm_node->private = (void *)fbo; + kref_init(&fbo->list_kref); + kref_init(&fbo->kref); + fbo->destroy = &ttm_transfered_destroy; + + *new_obj = fbo; + return 0; +} + +pgprot_t ttm_io_prot(uint32_t caching_flags, pgprot_t tmp) +{ +#if defined(__i386__) || defined(__x86_64__) + if (caching_flags & TTM_PL_FLAG_WC) + tmp = pgprot_writecombine(tmp); + else if (boot_cpu_data.x86 > 3) + tmp = pgprot_noncached(tmp); + +#elif defined(__powerpc__) + if (!(caching_flags & TTM_PL_FLAG_CACHED)) { + pgprot_val(tmp) |= _PAGE_NO_CACHE; + if (caching_flags & TTM_PL_FLAG_UNCACHED) + pgprot_val(tmp) |= _PAGE_GUARDED; + } +#endif +#if defined(__ia64__) + if (caching_flags & TTM_PL_FLAG_WC) + tmp = pgprot_writecombine(tmp); + else + tmp = pgprot_noncached(tmp); +#endif +#if defined(__sparc__) + if (!(caching_flags & TTM_PL_FLAG_CACHED)) + tmp = pgprot_noncached(tmp); +#endif + return tmp; +} + +static int ttm_bo_ioremap(struct ttm_buffer_object *bo, + unsigned long bus_base, + unsigned long bus_offset, + unsigned long bus_size, + struct ttm_bo_kmap_obj *map) +{ + struct ttm_bo_device *bdev = bo->bdev; + struct ttm_mem_reg *mem = &bo->mem; + struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type]; + + if (!(man->flags & TTM_MEMTYPE_FLAG_NEEDS_IOREMAP)) { + map->bo_kmap_type = ttm_bo_map_premapped; + map->virtual = (void *)(((u8 *) man->io_addr) + bus_offset); + } else { + map->bo_kmap_type = ttm_bo_map_iomap; + if (mem->placement & TTM_PL_FLAG_WC) + map->virtual = ioremap_wc(bus_base + bus_offset, + bus_size); + else + map->virtual = ioremap_nocache(bus_base + bus_offset, + bus_size); + } + return (!map->virtual) ? -ENOMEM : 0; +} + +static int ttm_bo_kmap_ttm(struct ttm_buffer_object *bo, + unsigned long start_page, + unsigned long num_pages, + struct ttm_bo_kmap_obj *map) +{ + struct ttm_mem_reg *mem = &bo->mem; pgprot_t prot; + struct ttm_tt *ttm = bo->ttm; + struct page *d; + int i; + + BUG_ON(!ttm); + if (num_pages == 1 && (mem->placement & TTM_PL_FLAG_CACHED)) { + /* + * We're mapping a single page, and the desired + * page protection is consistent with the bo. + */ + + map->bo_kmap_type = ttm_bo_map_kmap; + map->page = ttm_tt_get_page(ttm, start_page); + map->virtual = kmap(map->page); + } else { + /* + * Populate the part we're mapping; + */ + for (i = start_page; i < start_page + num_pages; ++i) { + d = ttm_tt_get_page(ttm, i); + if (!d) + return -ENOMEM; + } + + /* + * We need to use vmap to get the desired page protection + * or to make the buffer object look contigous. + */ + prot = (mem->placement & TTM_PL_FLAG_CACHED) ? + PAGE_KERNEL : + ttm_io_prot(mem->placement, PAGE_KERNEL); + map->bo_kmap_type = ttm_bo_map_vmap; + map->virtual = vmap(ttm->pages + start_page, num_pages, + 0, prot); + } + return (!map->virtual) ? -ENOMEM : 0; +} + +int ttm_bo_kmap(struct ttm_buffer_object *bo, + unsigned long start_page, unsigned long num_pages, + struct ttm_bo_kmap_obj *map) +{ + int ret; + unsigned long bus_base; + unsigned long bus_offset; + unsigned long bus_size; + + BUG_ON(!list_empty(&bo->swap)); + map->virtual = NULL; + if (num_pages > bo->num_pages) + return -EINVAL; + if (start_page > bo->num_pages) + return -EINVAL; +#if 0 + if (num_pages > 1 && !DRM_SUSER(DRM_CURPROC)) + return -EPERM; +#endif + ret = ttm_bo_pci_offset(bo->bdev, &bo->mem, &bus_base, + &bus_offset, &bus_size); + if (ret) + return ret; + if (bus_size == 0) { + return ttm_bo_kmap_ttm(bo, start_page, num_pages, map); + } else { + bus_offset += start_page << PAGE_SHIFT; + bus_size = num_pages << PAGE_SHIFT; + return ttm_bo_ioremap(bo, bus_base, bus_offset, bus_size, map); + } +} +EXPORT_SYMBOL(ttm_bo_kmap); + +void ttm_bo_kunmap(struct ttm_bo_kmap_obj *map) +{ + if (!map->virtual) + return; + switch (map->bo_kmap_type) { + case ttm_bo_map_iomap: + iounmap(map->virtual); + break; + case ttm_bo_map_vmap: + vunmap(map->virtual); + break; + case ttm_bo_map_kmap: + kunmap(map->page); + break; + case ttm_bo_map_premapped: + break; + default: + BUG(); + } + map->virtual = NULL; + map->page = NULL; +} +EXPORT_SYMBOL(ttm_bo_kunmap); + +int ttm_bo_pfn_prot(struct ttm_buffer_object *bo, + unsigned long dst_offset, + unsigned long *pfn, pgprot_t *prot) +{ + struct ttm_mem_reg *mem = &bo->mem; + struct ttm_bo_device *bdev = bo->bdev; + unsigned long bus_offset; + unsigned long bus_size; + unsigned long bus_base; + int ret; + ret = ttm_bo_pci_offset(bdev, mem, &bus_base, &bus_offset, + &bus_size); + if (ret) + return -EINVAL; + if (bus_size != 0) + *pfn = (bus_base + bus_offset + dst_offset) >> PAGE_SHIFT; + else + if (!bo->ttm) + return -EINVAL; + else + *pfn = page_to_pfn(ttm_tt_get_page(bo->ttm, + dst_offset >> + PAGE_SHIFT)); + *prot = (mem->placement & TTM_PL_FLAG_CACHED) ? + PAGE_KERNEL : ttm_io_prot(mem->placement, PAGE_KERNEL); + + return 0; +} + +int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo, + void *sync_obj, + void *sync_obj_arg, + bool evict, bool no_wait, + struct ttm_mem_reg *new_mem) +{ + struct ttm_bo_device *bdev = bo->bdev; + struct ttm_bo_driver *driver = bdev->driver; + struct ttm_mem_type_manager *man = &bdev->man[new_mem->mem_type]; + struct ttm_mem_reg *old_mem = &bo->mem; + int ret; + uint32_t save_flags = old_mem->placement; + struct ttm_buffer_object *ghost_obj; + void *tmp_obj = NULL; + + spin_lock(&bo->lock); + if (bo->sync_obj) { + tmp_obj = bo->sync_obj; + bo->sync_obj = NULL; + } + bo->sync_obj = driver->sync_obj_ref(sync_obj); + bo->sync_obj_arg = sync_obj_arg; + if (evict) { + ret = ttm_bo_wait(bo, false, false, false); + spin_unlock(&bo->lock); + driver->sync_obj_unref(&bo->sync_obj); + + if (ret) + return ret; + + ttm_bo_free_old_node(bo); + if ((man->flags & TTM_MEMTYPE_FLAG_FIXED) && + (bo->ttm != NULL)) { + ttm_tt_unbind(bo->ttm); + ttm_tt_destroy(bo->ttm); + bo->ttm = NULL; + } + } else { + /** + * This should help pipeline ordinary buffer moves. + * + * Hang old buffer memory on a new buffer object, + * and leave it to be released when the GPU + * operation has completed. + */ + + set_bit(TTM_BO_PRIV_FLAG_MOVING, &bo->priv_flags); + spin_unlock(&bo->lock); + + ret = ttm_buffer_object_transfer(bo, &ghost_obj); + if (ret) + return ret; + + /** + * If we're not moving to fixed memory, the TTM object + * needs to stay alive. Otherwhise hang it on the ghost + * bo to be unbound and destroyed. + */ + + if (!(man->flags & TTM_MEMTYPE_FLAG_FIXED)) + ghost_obj->ttm = NULL; + else + bo->ttm = NULL; + + ttm_bo_unreserve(ghost_obj); + ttm_bo_unref(&ghost_obj); + } + + *old_mem = *new_mem; + new_mem->mm_node = NULL; + ttm_flag_masked(&save_flags, new_mem->placement, TTM_PL_MASK_MEMTYPE); + return 0; +} +EXPORT_SYMBOL(ttm_bo_move_accel_cleanup); diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c new file mode 100644 index 000000000000..27b146c54fbc --- /dev/null +++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c @@ -0,0 +1,454 @@ +/************************************************************************** + * + * Copyright (c) 2006-2009 VMware, Inc., Palo Alto, CA., USA + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ +/* + * Authors: Thomas Hellstrom + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define TTM_BO_VM_NUM_PREFAULT 16 + +static struct ttm_buffer_object *ttm_bo_vm_lookup_rb(struct ttm_bo_device *bdev, + unsigned long page_start, + unsigned long num_pages) +{ + struct rb_node *cur = bdev->addr_space_rb.rb_node; + unsigned long cur_offset; + struct ttm_buffer_object *bo; + struct ttm_buffer_object *best_bo = NULL; + + while (likely(cur != NULL)) { + bo = rb_entry(cur, struct ttm_buffer_object, vm_rb); + cur_offset = bo->vm_node->start; + if (page_start >= cur_offset) { + cur = cur->rb_right; + best_bo = bo; + if (page_start == cur_offset) + break; + } else + cur = cur->rb_left; + } + + if (unlikely(best_bo == NULL)) + return NULL; + + if (unlikely((best_bo->vm_node->start + best_bo->num_pages) < + (page_start + num_pages))) + return NULL; + + return best_bo; +} + +static int ttm_bo_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) +{ + struct ttm_buffer_object *bo = (struct ttm_buffer_object *) + vma->vm_private_data; + struct ttm_bo_device *bdev = bo->bdev; + unsigned long bus_base; + unsigned long bus_offset; + unsigned long bus_size; + unsigned long page_offset; + unsigned long page_last; + unsigned long pfn; + struct ttm_tt *ttm = NULL; + struct page *page; + int ret; + int i; + bool is_iomem; + unsigned long address = (unsigned long)vmf->virtual_address; + int retval = VM_FAULT_NOPAGE; + + /* + * Work around locking order reversal in fault / nopfn + * between mmap_sem and bo_reserve: Perform a trylock operation + * for reserve, and if it fails, retry the fault after scheduling. + */ + + ret = ttm_bo_reserve(bo, true, true, false, 0); + if (unlikely(ret != 0)) { + if (ret == -EBUSY) + set_need_resched(); + return VM_FAULT_NOPAGE; + } + + /* + * Wait for buffer data in transit, due to a pipelined + * move. + */ + + spin_lock(&bo->lock); + if (test_bit(TTM_BO_PRIV_FLAG_MOVING, &bo->priv_flags)) { + ret = ttm_bo_wait(bo, false, true, false); + spin_unlock(&bo->lock); + if (unlikely(ret != 0)) { + retval = (ret != -ERESTART) ? + VM_FAULT_SIGBUS : VM_FAULT_NOPAGE; + goto out_unlock; + } + } else + spin_unlock(&bo->lock); + + + ret = ttm_bo_pci_offset(bdev, &bo->mem, &bus_base, &bus_offset, + &bus_size); + if (unlikely(ret != 0)) { + retval = VM_FAULT_SIGBUS; + goto out_unlock; + } + + is_iomem = (bus_size != 0); + + page_offset = ((address - vma->vm_start) >> PAGE_SHIFT) + + bo->vm_node->start - vma->vm_pgoff; + page_last = ((vma->vm_end - vma->vm_start) >> PAGE_SHIFT) + + bo->vm_node->start - vma->vm_pgoff; + + if (unlikely(page_offset >= bo->num_pages)) { + retval = VM_FAULT_SIGBUS; + goto out_unlock; + } + + /* + * Strictly, we're not allowed to modify vma->vm_page_prot here, + * since the mmap_sem is only held in read mode. However, we + * modify only the caching bits of vma->vm_page_prot and + * consider those bits protected by + * the bo->mutex, as we should be the only writers. + * There shouldn't really be any readers of these bits except + * within vm_insert_mixed()? fork? + * + * TODO: Add a list of vmas to the bo, and change the + * vma->vm_page_prot when the object changes caching policy, with + * the correct locks held. + */ + + if (is_iomem) { + vma->vm_page_prot = ttm_io_prot(bo->mem.placement, + vma->vm_page_prot); + } else { + ttm = bo->ttm; + vma->vm_page_prot = (bo->mem.placement & TTM_PL_FLAG_CACHED) ? + vm_get_page_prot(vma->vm_flags) : + ttm_io_prot(bo->mem.placement, vma->vm_page_prot); + } + + /* + * Speculatively prefault a number of pages. Only error on + * first page. + */ + + for (i = 0; i < TTM_BO_VM_NUM_PREFAULT; ++i) { + + if (is_iomem) + pfn = ((bus_base + bus_offset) >> PAGE_SHIFT) + + page_offset; + else { + page = ttm_tt_get_page(ttm, page_offset); + if (unlikely(!page && i == 0)) { + retval = VM_FAULT_OOM; + goto out_unlock; + } else if (unlikely(!page)) { + break; + } + pfn = page_to_pfn(page); + } + + ret = vm_insert_mixed(vma, address, pfn); + /* + * Somebody beat us to this PTE or prefaulting to + * an already populated PTE, or prefaulting error. + */ + + if (unlikely((ret == -EBUSY) || (ret != 0 && i > 0))) + break; + else if (unlikely(ret != 0)) { + retval = + (ret == -ENOMEM) ? VM_FAULT_OOM : VM_FAULT_SIGBUS; + goto out_unlock; + + } + + address += PAGE_SIZE; + if (unlikely(++page_offset >= page_last)) + break; + } + +out_unlock: + ttm_bo_unreserve(bo); + return retval; +} + +static void ttm_bo_vm_open(struct vm_area_struct *vma) +{ + struct ttm_buffer_object *bo = + (struct ttm_buffer_object *)vma->vm_private_data; + + (void)ttm_bo_reference(bo); +} + +static void ttm_bo_vm_close(struct vm_area_struct *vma) +{ + struct ttm_buffer_object *bo = + (struct ttm_buffer_object *)vma->vm_private_data; + + ttm_bo_unref(&bo); + vma->vm_private_data = NULL; +} + +static struct vm_operations_struct ttm_bo_vm_ops = { + .fault = ttm_bo_vm_fault, + .open = ttm_bo_vm_open, + .close = ttm_bo_vm_close +}; + +int ttm_bo_mmap(struct file *filp, struct vm_area_struct *vma, + struct ttm_bo_device *bdev) +{ + struct ttm_bo_driver *driver; + struct ttm_buffer_object *bo; + int ret; + + read_lock(&bdev->vm_lock); + bo = ttm_bo_vm_lookup_rb(bdev, vma->vm_pgoff, + (vma->vm_end - vma->vm_start) >> PAGE_SHIFT); + if (likely(bo != NULL)) + ttm_bo_reference(bo); + read_unlock(&bdev->vm_lock); + + if (unlikely(bo == NULL)) { + printk(KERN_ERR TTM_PFX + "Could not find buffer object to map.\n"); + return -EINVAL; + } + + driver = bo->bdev->driver; + if (unlikely(!driver->verify_access)) { + ret = -EPERM; + goto out_unref; + } + ret = driver->verify_access(bo, filp); + if (unlikely(ret != 0)) + goto out_unref; + + vma->vm_ops = &ttm_bo_vm_ops; + + /* + * Note: We're transferring the bo reference to + * vma->vm_private_data here. + */ + + vma->vm_private_data = bo; + vma->vm_flags |= VM_RESERVED | VM_IO | VM_MIXEDMAP | VM_DONTEXPAND; + return 0; +out_unref: + ttm_bo_unref(&bo); + return ret; +} +EXPORT_SYMBOL(ttm_bo_mmap); + +int ttm_fbdev_mmap(struct vm_area_struct *vma, struct ttm_buffer_object *bo) +{ + if (vma->vm_pgoff != 0) + return -EACCES; + + vma->vm_ops = &ttm_bo_vm_ops; + vma->vm_private_data = ttm_bo_reference(bo); + vma->vm_flags |= VM_RESERVED | VM_IO | VM_MIXEDMAP | VM_DONTEXPAND; + return 0; +} +EXPORT_SYMBOL(ttm_fbdev_mmap); + + +ssize_t ttm_bo_io(struct ttm_bo_device *bdev, struct file *filp, + const char __user *wbuf, char __user *rbuf, size_t count, + loff_t *f_pos, bool write) +{ + struct ttm_buffer_object *bo; + struct ttm_bo_driver *driver; + struct ttm_bo_kmap_obj map; + unsigned long dev_offset = (*f_pos >> PAGE_SHIFT); + unsigned long kmap_offset; + unsigned long kmap_end; + unsigned long kmap_num; + size_t io_size; + unsigned int page_offset; + char *virtual; + int ret; + bool no_wait = false; + bool dummy; + + read_lock(&bdev->vm_lock); + bo = ttm_bo_vm_lookup_rb(bdev, dev_offset, 1); + if (likely(bo != NULL)) + ttm_bo_reference(bo); + read_unlock(&bdev->vm_lock); + + if (unlikely(bo == NULL)) + return -EFAULT; + + driver = bo->bdev->driver; + if (unlikely(driver->verify_access)) { + ret = -EPERM; + goto out_unref; + } + + ret = driver->verify_access(bo, filp); + if (unlikely(ret != 0)) + goto out_unref; + + kmap_offset = dev_offset - bo->vm_node->start; + if (unlikely(kmap_offset) >= bo->num_pages) { + ret = -EFBIG; + goto out_unref; + } + + page_offset = *f_pos & ~PAGE_MASK; + io_size = bo->num_pages - kmap_offset; + io_size = (io_size << PAGE_SHIFT) - page_offset; + if (count < io_size) + io_size = count; + + kmap_end = (*f_pos + count - 1) >> PAGE_SHIFT; + kmap_num = kmap_end - kmap_offset + 1; + + ret = ttm_bo_reserve(bo, true, no_wait, false, 0); + + switch (ret) { + case 0: + break; + case -ERESTART: + ret = -EINTR; + goto out_unref; + case -EBUSY: + ret = -EAGAIN; + goto out_unref; + default: + goto out_unref; + } + + ret = ttm_bo_kmap(bo, kmap_offset, kmap_num, &map); + if (unlikely(ret != 0)) { + ttm_bo_unreserve(bo); + goto out_unref; + } + + virtual = ttm_kmap_obj_virtual(&map, &dummy); + virtual += page_offset; + + if (write) + ret = copy_from_user(virtual, wbuf, io_size); + else + ret = copy_to_user(rbuf, virtual, io_size); + + ttm_bo_kunmap(&map); + ttm_bo_unreserve(bo); + ttm_bo_unref(&bo); + + if (unlikely(ret != 0)) + return -EFBIG; + + *f_pos += io_size; + + return io_size; +out_unref: + ttm_bo_unref(&bo); + return ret; +} + +ssize_t ttm_bo_fbdev_io(struct ttm_buffer_object *bo, const char __user *wbuf, + char __user *rbuf, size_t count, loff_t *f_pos, + bool write) +{ + struct ttm_bo_kmap_obj map; + unsigned long kmap_offset; + unsigned long kmap_end; + unsigned long kmap_num; + size_t io_size; + unsigned int page_offset; + char *virtual; + int ret; + bool no_wait = false; + bool dummy; + + kmap_offset = (*f_pos >> PAGE_SHIFT); + if (unlikely(kmap_offset) >= bo->num_pages) + return -EFBIG; + + page_offset = *f_pos & ~PAGE_MASK; + io_size = bo->num_pages - kmap_offset; + io_size = (io_size << PAGE_SHIFT) - page_offset; + if (count < io_size) + io_size = count; + + kmap_end = (*f_pos + count - 1) >> PAGE_SHIFT; + kmap_num = kmap_end - kmap_offset + 1; + + ret = ttm_bo_reserve(bo, true, no_wait, false, 0); + + switch (ret) { + case 0: + break; + case -ERESTART: + return -EINTR; + case -EBUSY: + return -EAGAIN; + default: + return ret; + } + + ret = ttm_bo_kmap(bo, kmap_offset, kmap_num, &map); + if (unlikely(ret != 0)) { + ttm_bo_unreserve(bo); + return ret; + } + + virtual = ttm_kmap_obj_virtual(&map, &dummy); + virtual += page_offset; + + if (write) + ret = copy_from_user(virtual, wbuf, io_size); + else + ret = copy_to_user(rbuf, virtual, io_size); + + ttm_bo_kunmap(&map); + ttm_bo_unreserve(bo); + ttm_bo_unref(&bo); + + if (unlikely(ret != 0)) + return ret; + + *f_pos += io_size; + + return io_size; +} diff --git a/drivers/gpu/drm/ttm/ttm_global.c b/drivers/gpu/drm/ttm/ttm_global.c new file mode 100644 index 000000000000..0b14eb1972b8 --- /dev/null +++ b/drivers/gpu/drm/ttm/ttm_global.c @@ -0,0 +1,114 @@ +/************************************************************************** + * + * Copyright 2008-2009 VMware, Inc., Palo Alto, CA., USA + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ +/* + * Authors: Thomas Hellstrom + */ + +#include "ttm/ttm_module.h" +#include +#include +#include + +struct ttm_global_item { + struct mutex mutex; + void *object; + int refcount; +}; + +static struct ttm_global_item glob[TTM_GLOBAL_NUM]; + +void ttm_global_init(void) +{ + int i; + + for (i = 0; i < TTM_GLOBAL_NUM; ++i) { + struct ttm_global_item *item = &glob[i]; + mutex_init(&item->mutex); + item->object = NULL; + item->refcount = 0; + } +} + +void ttm_global_release(void) +{ + int i; + for (i = 0; i < TTM_GLOBAL_NUM; ++i) { + struct ttm_global_item *item = &glob[i]; + BUG_ON(item->object != NULL); + BUG_ON(item->refcount != 0); + } +} + +int ttm_global_item_ref(struct ttm_global_reference *ref) +{ + int ret; + struct ttm_global_item *item = &glob[ref->global_type]; + void *object; + + mutex_lock(&item->mutex); + if (item->refcount == 0) { + item->object = kmalloc(ref->size, GFP_KERNEL); + if (unlikely(item->object == NULL)) { + ret = -ENOMEM; + goto out_err; + } + + ref->object = item->object; + ret = ref->init(ref); + if (unlikely(ret != 0)) + goto out_err; + + ++item->refcount; + } + ref->object = item->object; + object = item->object; + mutex_unlock(&item->mutex); + return 0; +out_err: + kfree(item->object); + mutex_unlock(&item->mutex); + item->object = NULL; + return ret; +} +EXPORT_SYMBOL(ttm_global_item_ref); + +void ttm_global_item_unref(struct ttm_global_reference *ref) +{ + struct ttm_global_item *item = &glob[ref->global_type]; + + mutex_lock(&item->mutex); + BUG_ON(item->refcount == 0); + BUG_ON(ref->object != item->object); + if (--item->refcount == 0) { + ref->release(ref); + kfree(item->object); + item->object = NULL; + } + mutex_unlock(&item->mutex); +} +EXPORT_SYMBOL(ttm_global_item_unref); + diff --git a/drivers/gpu/drm/ttm/ttm_memory.c b/drivers/gpu/drm/ttm/ttm_memory.c new file mode 100644 index 000000000000..87323d4ff68d --- /dev/null +++ b/drivers/gpu/drm/ttm/ttm_memory.c @@ -0,0 +1,234 @@ +/************************************************************************** + * + * Copyright (c) 2006-2009 VMware, Inc., Palo Alto, CA., USA + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include "ttm/ttm_memory.h" +#include +#include +#include +#include +#include + +#define TTM_PFX "[TTM] " +#define TTM_MEMORY_ALLOC_RETRIES 4 + +/** + * At this point we only support a single shrink callback. + * Extend this if needed, perhaps using a linked list of callbacks. + * Note that this function is reentrant: + * many threads may try to swap out at any given time. + */ + +static void ttm_shrink(struct ttm_mem_global *glob, bool from_workqueue, + uint64_t extra) +{ + int ret; + struct ttm_mem_shrink *shrink; + uint64_t target; + uint64_t total_target; + + spin_lock(&glob->lock); + if (glob->shrink == NULL) + goto out; + + if (from_workqueue) { + target = glob->swap_limit; + total_target = glob->total_memory_swap_limit; + } else if (capable(CAP_SYS_ADMIN)) { + total_target = glob->emer_total_memory; + target = glob->emer_memory; + } else { + total_target = glob->max_total_memory; + target = glob->max_memory; + } + + total_target = (extra >= total_target) ? 0 : total_target - extra; + target = (extra >= target) ? 0 : target - extra; + + while (glob->used_memory > target || + glob->used_total_memory > total_target) { + shrink = glob->shrink; + spin_unlock(&glob->lock); + ret = shrink->do_shrink(shrink); + spin_lock(&glob->lock); + if (unlikely(ret != 0)) + goto out; + } +out: + spin_unlock(&glob->lock); +} + +static void ttm_shrink_work(struct work_struct *work) +{ + struct ttm_mem_global *glob = + container_of(work, struct ttm_mem_global, work); + + ttm_shrink(glob, true, 0ULL); +} + +int ttm_mem_global_init(struct ttm_mem_global *glob) +{ + struct sysinfo si; + uint64_t mem; + + spin_lock_init(&glob->lock); + glob->swap_queue = create_singlethread_workqueue("ttm_swap"); + INIT_WORK(&glob->work, ttm_shrink_work); + init_waitqueue_head(&glob->queue); + + si_meminfo(&si); + + mem = si.totalram - si.totalhigh; + mem *= si.mem_unit; + + glob->max_memory = mem >> 1; + glob->emer_memory = (mem >> 1) + (mem >> 2); + glob->swap_limit = glob->max_memory - (mem >> 3); + glob->used_memory = 0; + glob->used_total_memory = 0; + glob->shrink = NULL; + + mem = si.totalram; + mem *= si.mem_unit; + + glob->max_total_memory = mem >> 1; + glob->emer_total_memory = (mem >> 1) + (mem >> 2); + + glob->total_memory_swap_limit = glob->max_total_memory - (mem >> 3); + + printk(KERN_INFO TTM_PFX "TTM available graphics memory: %llu MiB\n", + glob->max_total_memory >> 20); + printk(KERN_INFO TTM_PFX "TTM available object memory: %llu MiB\n", + glob->max_memory >> 20); + + return 0; +} +EXPORT_SYMBOL(ttm_mem_global_init); + +void ttm_mem_global_release(struct ttm_mem_global *glob) +{ + printk(KERN_INFO TTM_PFX "Used total memory is %llu bytes.\n", + (unsigned long long)glob->used_total_memory); + flush_workqueue(glob->swap_queue); + destroy_workqueue(glob->swap_queue); + glob->swap_queue = NULL; +} +EXPORT_SYMBOL(ttm_mem_global_release); + +static inline void ttm_check_swapping(struct ttm_mem_global *glob) +{ + bool needs_swapping; + + spin_lock(&glob->lock); + needs_swapping = (glob->used_memory > glob->swap_limit || + glob->used_total_memory > + glob->total_memory_swap_limit); + spin_unlock(&glob->lock); + + if (unlikely(needs_swapping)) + (void)queue_work(glob->swap_queue, &glob->work); + +} + +void ttm_mem_global_free(struct ttm_mem_global *glob, + uint64_t amount, bool himem) +{ + spin_lock(&glob->lock); + glob->used_total_memory -= amount; + if (!himem) + glob->used_memory -= amount; + wake_up_all(&glob->queue); + spin_unlock(&glob->lock); +} + +static int ttm_mem_global_reserve(struct ttm_mem_global *glob, + uint64_t amount, bool himem, bool reserve) +{ + uint64_t limit; + uint64_t lomem_limit; + int ret = -ENOMEM; + + spin_lock(&glob->lock); + + if (capable(CAP_SYS_ADMIN)) { + limit = glob->emer_total_memory; + lomem_limit = glob->emer_memory; + } else { + limit = glob->max_total_memory; + lomem_limit = glob->max_memory; + } + + if (unlikely(glob->used_total_memory + amount > limit)) + goto out_unlock; + if (unlikely(!himem && glob->used_memory + amount > lomem_limit)) + goto out_unlock; + + if (reserve) { + glob->used_total_memory += amount; + if (!himem) + glob->used_memory += amount; + } + ret = 0; +out_unlock: + spin_unlock(&glob->lock); + ttm_check_swapping(glob); + + return ret; +} + +int ttm_mem_global_alloc(struct ttm_mem_global *glob, uint64_t memory, + bool no_wait, bool interruptible, bool himem) +{ + int count = TTM_MEMORY_ALLOC_RETRIES; + + while (unlikely(ttm_mem_global_reserve(glob, memory, himem, true) + != 0)) { + if (no_wait) + return -ENOMEM; + if (unlikely(count-- == 0)) + return -ENOMEM; + ttm_shrink(glob, false, memory + (memory >> 2) + 16); + } + + return 0; +} + +size_t ttm_round_pot(size_t size) +{ + if ((size & (size - 1)) == 0) + return size; + else if (size > PAGE_SIZE) + return PAGE_ALIGN(size); + else { + size_t tmp_size = 4; + + while (tmp_size < size) + tmp_size <<= 1; + + return tmp_size; + } + return 0; +} diff --git a/drivers/gpu/drm/ttm/ttm_module.c b/drivers/gpu/drm/ttm/ttm_module.c new file mode 100644 index 000000000000..59ce8191d584 --- /dev/null +++ b/drivers/gpu/drm/ttm/ttm_module.c @@ -0,0 +1,50 @@ +/************************************************************************** + * + * Copyright (c) 2006-2009 VMware, Inc., Palo Alto, CA., USA + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ +/* + * Authors: Thomas Hellstrom + * Jerome Glisse + */ +#include +#include + +static int __init ttm_init(void) +{ + ttm_global_init(); + return 0; +} + +static void __exit ttm_exit(void) +{ + ttm_global_release(); +} + +module_init(ttm_init); +module_exit(ttm_exit); + +MODULE_AUTHOR("Thomas Hellstrom, Jerome Glisse"); +MODULE_DESCRIPTION("TTM memory manager subsystem (for DRM device)"); +MODULE_LICENSE("GPL and additional rights"); diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c new file mode 100644 index 000000000000..0331fa74cd3f --- /dev/null +++ b/drivers/gpu/drm/ttm/ttm_tt.c @@ -0,0 +1,644 @@ +/************************************************************************** + * + * Copyright (c) 2006-2009 VMware, Inc., Palo Alto, CA., USA + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ +/* + * Authors: Thomas Hellstrom + */ + +#include +#include +#include +#include +#include +#include +#include +#include "ttm/ttm_module.h" +#include "ttm/ttm_bo_driver.h" +#include "ttm/ttm_placement.h" + +static int ttm_tt_swapin(struct ttm_tt *ttm); + +#if defined(CONFIG_X86) +static void ttm_tt_clflush_page(struct page *page) +{ + uint8_t *page_virtual; + unsigned int i; + + if (unlikely(page == NULL)) + return; + + page_virtual = kmap_atomic(page, KM_USER0); + + for (i = 0; i < PAGE_SIZE; i += boot_cpu_data.x86_clflush_size) + clflush(page_virtual + i); + + kunmap_atomic(page_virtual, KM_USER0); +} + +static void ttm_tt_cache_flush_clflush(struct page *pages[], + unsigned long num_pages) +{ + unsigned long i; + + mb(); + for (i = 0; i < num_pages; ++i) + ttm_tt_clflush_page(*pages++); + mb(); +} +#elif !defined(__powerpc__) +static void ttm_tt_ipi_handler(void *null) +{ + ; +} +#endif + +void ttm_tt_cache_flush(struct page *pages[], unsigned long num_pages) +{ + +#if defined(CONFIG_X86) + if (cpu_has_clflush) { + ttm_tt_cache_flush_clflush(pages, num_pages); + return; + } +#elif defined(__powerpc__) + unsigned long i; + + for (i = 0; i < num_pages; ++i) { + if (pages[i]) { + unsigned long start = (unsigned long)page_address(pages[i]); + flush_dcache_range(start, start + PAGE_SIZE); + } + } +#else + if (on_each_cpu(ttm_tt_ipi_handler, NULL, 1) != 0) + printk(KERN_ERR TTM_PFX + "Timed out waiting for drm cache flush.\n"); +#endif +} + +/** + * Allocates storage for pointers to the pages that back the ttm. + * + * Uses kmalloc if possible. Otherwise falls back to vmalloc. + */ +static void ttm_tt_alloc_page_directory(struct ttm_tt *ttm) +{ + unsigned long size = ttm->num_pages * sizeof(*ttm->pages); + ttm->pages = NULL; + + if (size <= PAGE_SIZE) + ttm->pages = kzalloc(size, GFP_KERNEL); + + if (!ttm->pages) { + ttm->pages = vmalloc_user(size); + if (ttm->pages) + ttm->page_flags |= TTM_PAGE_FLAG_VMALLOC; + } +} + +static void ttm_tt_free_page_directory(struct ttm_tt *ttm) +{ + if (ttm->page_flags & TTM_PAGE_FLAG_VMALLOC) { + vfree(ttm->pages); + ttm->page_flags &= ~TTM_PAGE_FLAG_VMALLOC; + } else { + kfree(ttm->pages); + } + ttm->pages = NULL; +} + +static struct page *ttm_tt_alloc_page(unsigned page_flags) +{ + if (page_flags & TTM_PAGE_FLAG_ZERO_ALLOC) + return alloc_page(GFP_HIGHUSER | __GFP_ZERO); + + return alloc_page(GFP_HIGHUSER); +} + +static void ttm_tt_free_user_pages(struct ttm_tt *ttm) +{ + int write; + int dirty; + struct page *page; + int i; + struct ttm_backend *be = ttm->be; + + BUG_ON(!(ttm->page_flags & TTM_PAGE_FLAG_USER)); + write = ((ttm->page_flags & TTM_PAGE_FLAG_WRITE) != 0); + dirty = ((ttm->page_flags & TTM_PAGE_FLAG_USER_DIRTY) != 0); + + if (be) + be->func->clear(be); + + for (i = 0; i < ttm->num_pages; ++i) { + page = ttm->pages[i]; + if (page == NULL) + continue; + + if (page == ttm->dummy_read_page) { + BUG_ON(write); + continue; + } + + if (write && dirty && !PageReserved(page)) + set_page_dirty_lock(page); + + ttm->pages[i] = NULL; + ttm_mem_global_free(ttm->bdev->mem_glob, PAGE_SIZE, false); + put_page(page); + } + ttm->state = tt_unpopulated; + ttm->first_himem_page = ttm->num_pages; + ttm->last_lomem_page = -1; +} + +static struct page *__ttm_tt_get_page(struct ttm_tt *ttm, int index) +{ + struct page *p; + struct ttm_bo_device *bdev = ttm->bdev; + struct ttm_mem_global *mem_glob = bdev->mem_glob; + int ret; + + while (NULL == (p = ttm->pages[index])) { + p = ttm_tt_alloc_page(ttm->page_flags); + + if (!p) + return NULL; + + if (PageHighMem(p)) { + ret = + ttm_mem_global_alloc(mem_glob, PAGE_SIZE, + false, false, true); + if (unlikely(ret != 0)) + goto out_err; + ttm->pages[--ttm->first_himem_page] = p; + } else { + ret = + ttm_mem_global_alloc(mem_glob, PAGE_SIZE, + false, false, false); + if (unlikely(ret != 0)) + goto out_err; + ttm->pages[++ttm->last_lomem_page] = p; + } + } + return p; +out_err: + put_page(p); + return NULL; +} + +struct page *ttm_tt_get_page(struct ttm_tt *ttm, int index) +{ + int ret; + + if (unlikely(ttm->page_flags & TTM_PAGE_FLAG_SWAPPED)) { + ret = ttm_tt_swapin(ttm); + if (unlikely(ret != 0)) + return NULL; + } + return __ttm_tt_get_page(ttm, index); +} + +int ttm_tt_populate(struct ttm_tt *ttm) +{ + struct page *page; + unsigned long i; + struct ttm_backend *be; + int ret; + + if (ttm->state != tt_unpopulated) + return 0; + + if (unlikely(ttm->page_flags & TTM_PAGE_FLAG_SWAPPED)) { + ret = ttm_tt_swapin(ttm); + if (unlikely(ret != 0)) + return ret; + } + + be = ttm->be; + + for (i = 0; i < ttm->num_pages; ++i) { + page = __ttm_tt_get_page(ttm, i); + if (!page) + return -ENOMEM; + } + + be->func->populate(be, ttm->num_pages, ttm->pages, + ttm->dummy_read_page); + ttm->state = tt_unbound; + return 0; +} + +#ifdef CONFIG_X86 +static inline int ttm_tt_set_page_caching(struct page *p, + enum ttm_caching_state c_state) +{ + if (PageHighMem(p)) + return 0; + + switch (c_state) { + case tt_cached: + return set_pages_wb(p, 1); + case tt_wc: + return set_memory_wc((unsigned long) page_address(p), 1); + default: + return set_pages_uc(p, 1); + } +} +#else /* CONFIG_X86 */ +static inline int ttm_tt_set_page_caching(struct page *p, + enum ttm_caching_state c_state) +{ + return 0; +} +#endif /* CONFIG_X86 */ + +/* + * Change caching policy for the linear kernel map + * for range of pages in a ttm. + */ + +static int ttm_tt_set_caching(struct ttm_tt *ttm, + enum ttm_caching_state c_state) +{ + int i, j; + struct page *cur_page; + int ret; + + if (ttm->caching_state == c_state) + return 0; + + if (c_state != tt_cached) { + ret = ttm_tt_populate(ttm); + if (unlikely(ret != 0)) + return ret; + } + + if (ttm->caching_state == tt_cached) + ttm_tt_cache_flush(ttm->pages, ttm->num_pages); + + for (i = 0; i < ttm->num_pages; ++i) { + cur_page = ttm->pages[i]; + if (likely(cur_page != NULL)) { + ret = ttm_tt_set_page_caching(cur_page, c_state); + if (unlikely(ret != 0)) + goto out_err; + } + } + + ttm->caching_state = c_state; + + return 0; + +out_err: + for (j = 0; j < i; ++j) { + cur_page = ttm->pages[j]; + if (likely(cur_page != NULL)) { + (void)ttm_tt_set_page_caching(cur_page, + ttm->caching_state); + } + } + + return ret; +} + +int ttm_tt_set_placement_caching(struct ttm_tt *ttm, uint32_t placement) +{ + enum ttm_caching_state state; + + if (placement & TTM_PL_FLAG_WC) + state = tt_wc; + else if (placement & TTM_PL_FLAG_UNCACHED) + state = tt_uncached; + else + state = tt_cached; + + return ttm_tt_set_caching(ttm, state); +} + +static void ttm_tt_free_alloced_pages(struct ttm_tt *ttm) +{ + int i; + struct page *cur_page; + struct ttm_backend *be = ttm->be; + + if (be) + be->func->clear(be); + (void)ttm_tt_set_caching(ttm, tt_cached); + for (i = 0; i < ttm->num_pages; ++i) { + cur_page = ttm->pages[i]; + ttm->pages[i] = NULL; + if (cur_page) { + if (page_count(cur_page) != 1) + printk(KERN_ERR TTM_PFX + "Erroneous page count. " + "Leaking pages.\n"); + ttm_mem_global_free(ttm->bdev->mem_glob, PAGE_SIZE, + PageHighMem(cur_page)); + __free_page(cur_page); + } + } + ttm->state = tt_unpopulated; + ttm->first_himem_page = ttm->num_pages; + ttm->last_lomem_page = -1; +} + +void ttm_tt_destroy(struct ttm_tt *ttm) +{ + struct ttm_backend *be; + + if (unlikely(ttm == NULL)) + return; + + be = ttm->be; + if (likely(be != NULL)) { + be->func->destroy(be); + ttm->be = NULL; + } + + if (likely(ttm->pages != NULL)) { + if (ttm->page_flags & TTM_PAGE_FLAG_USER) + ttm_tt_free_user_pages(ttm); + else + ttm_tt_free_alloced_pages(ttm); + + ttm_tt_free_page_directory(ttm); + } + + if (!(ttm->page_flags & TTM_PAGE_FLAG_PERSISTANT_SWAP) && + ttm->swap_storage) + fput(ttm->swap_storage); + + kfree(ttm); +} + +int ttm_tt_set_user(struct ttm_tt *ttm, + struct task_struct *tsk, + unsigned long start, unsigned long num_pages) +{ + struct mm_struct *mm = tsk->mm; + int ret; + int write = (ttm->page_flags & TTM_PAGE_FLAG_WRITE) != 0; + struct ttm_mem_global *mem_glob = ttm->bdev->mem_glob; + + BUG_ON(num_pages != ttm->num_pages); + BUG_ON((ttm->page_flags & TTM_PAGE_FLAG_USER) == 0); + + /** + * Account user pages as lowmem pages for now. + */ + + ret = ttm_mem_global_alloc(mem_glob, num_pages * PAGE_SIZE, + false, false, false); + if (unlikely(ret != 0)) + return ret; + + down_read(&mm->mmap_sem); + ret = get_user_pages(tsk, mm, start, num_pages, + write, 0, ttm->pages, NULL); + up_read(&mm->mmap_sem); + + if (ret != num_pages && write) { + ttm_tt_free_user_pages(ttm); + ttm_mem_global_free(mem_glob, num_pages * PAGE_SIZE, false); + return -ENOMEM; + } + + ttm->tsk = tsk; + ttm->start = start; + ttm->state = tt_unbound; + + return 0; +} + +struct ttm_tt *ttm_tt_create(struct ttm_bo_device *bdev, unsigned long size, + uint32_t page_flags, struct page *dummy_read_page) +{ + struct ttm_bo_driver *bo_driver = bdev->driver; + struct ttm_tt *ttm; + + if (!bo_driver) + return NULL; + + ttm = kzalloc(sizeof(*ttm), GFP_KERNEL); + if (!ttm) + return NULL; + + ttm->bdev = bdev; + + ttm->num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; + ttm->first_himem_page = ttm->num_pages; + ttm->last_lomem_page = -1; + ttm->caching_state = tt_cached; + ttm->page_flags = page_flags; + + ttm->dummy_read_page = dummy_read_page; + + ttm_tt_alloc_page_directory(ttm); + if (!ttm->pages) { + ttm_tt_destroy(ttm); + printk(KERN_ERR TTM_PFX "Failed allocating page table\n"); + return NULL; + } + ttm->be = bo_driver->create_ttm_backend_entry(bdev); + if (!ttm->be) { + ttm_tt_destroy(ttm); + printk(KERN_ERR TTM_PFX "Failed creating ttm backend entry\n"); + return NULL; + } + ttm->state = tt_unpopulated; + return ttm; +} + +void ttm_tt_unbind(struct ttm_tt *ttm) +{ + int ret; + struct ttm_backend *be = ttm->be; + + if (ttm->state == tt_bound) { + ret = be->func->unbind(be); + BUG_ON(ret); + ttm->state = tt_unbound; + } +} + +int ttm_tt_bind(struct ttm_tt *ttm, struct ttm_mem_reg *bo_mem) +{ + int ret = 0; + struct ttm_backend *be; + + if (!ttm) + return -EINVAL; + + if (ttm->state == tt_bound) + return 0; + + be = ttm->be; + + ret = ttm_tt_populate(ttm); + if (ret) + return ret; + + ret = be->func->bind(be, bo_mem); + if (ret) { + printk(KERN_ERR TTM_PFX "Couldn't bind backend.\n"); + return ret; + } + + ttm->state = tt_bound; + + if (ttm->page_flags & TTM_PAGE_FLAG_USER) + ttm->page_flags |= TTM_PAGE_FLAG_USER_DIRTY; + return 0; +} +EXPORT_SYMBOL(ttm_tt_bind); + +static int ttm_tt_swapin(struct ttm_tt *ttm) +{ + struct address_space *swap_space; + struct file *swap_storage; + struct page *from_page; + struct page *to_page; + void *from_virtual; + void *to_virtual; + int i; + int ret; + + if (ttm->page_flags & TTM_PAGE_FLAG_USER) { + ret = ttm_tt_set_user(ttm, ttm->tsk, ttm->start, + ttm->num_pages); + if (unlikely(ret != 0)) + return ret; + + ttm->page_flags &= ~TTM_PAGE_FLAG_SWAPPED; + return 0; + } + + swap_storage = ttm->swap_storage; + BUG_ON(swap_storage == NULL); + + swap_space = swap_storage->f_path.dentry->d_inode->i_mapping; + + for (i = 0; i < ttm->num_pages; ++i) { + from_page = read_mapping_page(swap_space, i, NULL); + if (IS_ERR(from_page)) + goto out_err; + to_page = __ttm_tt_get_page(ttm, i); + if (unlikely(to_page == NULL)) + goto out_err; + + preempt_disable(); + from_virtual = kmap_atomic(from_page, KM_USER0); + to_virtual = kmap_atomic(to_page, KM_USER1); + memcpy(to_virtual, from_virtual, PAGE_SIZE); + kunmap_atomic(to_virtual, KM_USER1); + kunmap_atomic(from_virtual, KM_USER0); + preempt_enable(); + page_cache_release(from_page); + } + + if (!(ttm->page_flags & TTM_PAGE_FLAG_PERSISTANT_SWAP)) + fput(swap_storage); + ttm->swap_storage = NULL; + ttm->page_flags &= ~TTM_PAGE_FLAG_SWAPPED; + + return 0; +out_err: + ttm_tt_free_alloced_pages(ttm); + return -ENOMEM; +} + +int ttm_tt_swapout(struct ttm_tt *ttm, struct file *persistant_swap_storage) +{ + struct address_space *swap_space; + struct file *swap_storage; + struct page *from_page; + struct page *to_page; + void *from_virtual; + void *to_virtual; + int i; + + BUG_ON(ttm->state != tt_unbound && ttm->state != tt_unpopulated); + BUG_ON(ttm->caching_state != tt_cached); + + /* + * For user buffers, just unpin the pages, as there should be + * vma references. + */ + + if (ttm->page_flags & TTM_PAGE_FLAG_USER) { + ttm_tt_free_user_pages(ttm); + ttm->page_flags |= TTM_PAGE_FLAG_SWAPPED; + ttm->swap_storage = NULL; + return 0; + } + + if (!persistant_swap_storage) { + swap_storage = shmem_file_setup("ttm swap", + ttm->num_pages << PAGE_SHIFT, + 0); + if (unlikely(IS_ERR(swap_storage))) { + printk(KERN_ERR "Failed allocating swap storage.\n"); + return -ENOMEM; + } + } else + swap_storage = persistant_swap_storage; + + swap_space = swap_storage->f_path.dentry->d_inode->i_mapping; + + for (i = 0; i < ttm->num_pages; ++i) { + from_page = ttm->pages[i]; + if (unlikely(from_page == NULL)) + continue; + to_page = read_mapping_page(swap_space, i, NULL); + if (unlikely(to_page == NULL)) + goto out_err; + + preempt_disable(); + from_virtual = kmap_atomic(from_page, KM_USER0); + to_virtual = kmap_atomic(to_page, KM_USER1); + memcpy(to_virtual, from_virtual, PAGE_SIZE); + kunmap_atomic(to_virtual, KM_USER1); + kunmap_atomic(from_virtual, KM_USER0); + preempt_enable(); + set_page_dirty(to_page); + mark_page_accessed(to_page); + page_cache_release(to_page); + } + + ttm_tt_free_alloced_pages(ttm); + ttm->swap_storage = swap_storage; + ttm->page_flags |= TTM_PAGE_FLAG_SWAPPED; + if (persistant_swap_storage) + ttm->page_flags |= TTM_PAGE_FLAG_PERSISTANT_SWAP; + + return 0; +out_err: + if (!persistant_swap_storage) + fput(swap_storage); + + return -ENOMEM; +} diff --git a/drivers/gpu/drm/via/via_dmablit.c b/drivers/gpu/drm/via/via_dmablit.c index 409e00afdd07..327380888b4a 100644 --- a/drivers/gpu/drm/via/via_dmablit.c +++ b/drivers/gpu/drm/via/via_dmablit.c @@ -195,10 +195,8 @@ via_free_sg_info(struct pci_dev *pdev, drm_via_sg_info_t *vsg) default: vsg->state = dr_via_sg_init; } - if (vsg->bounce_buffer) { - vfree(vsg->bounce_buffer); - vsg->bounce_buffer = NULL; - } + vfree(vsg->bounce_buffer); + vsg->bounce_buffer = NULL; vsg->free_on_sequence = 0; } diff --git a/drivers/gpu/drm/via/via_map.c b/drivers/gpu/drm/via/via_map.c index 2c4f0b485792..6e6f91591639 100644 --- a/drivers/gpu/drm/via/via_map.c +++ b/drivers/gpu/drm/via/via_map.c @@ -96,7 +96,7 @@ int via_driver_load(struct drm_device *dev, unsigned long chipset) drm_via_private_t *dev_priv; int ret = 0; - dev_priv = drm_calloc(1, sizeof(drm_via_private_t), DRM_MEM_DRIVER); + dev_priv = kzalloc(sizeof(drm_via_private_t), GFP_KERNEL); if (dev_priv == NULL) return -ENOMEM; @@ -106,14 +106,14 @@ int via_driver_load(struct drm_device *dev, unsigned long chipset) ret = drm_sman_init(&dev_priv->sman, 2, 12, 8); if (ret) { - drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER); + kfree(dev_priv); return ret; } ret = drm_vblank_init(dev, 1); if (ret) { drm_sman_takedown(&dev_priv->sman); - drm_free(dev_priv, sizeof(drm_via_private_t), DRM_MEM_DRIVER); + kfree(dev_priv); return ret; } @@ -126,7 +126,7 @@ int via_driver_unload(struct drm_device *dev) drm_sman_takedown(&dev_priv->sman); - drm_free(dev_priv, sizeof(drm_via_private_t), DRM_MEM_DRIVER); + kfree(dev_priv); return 0; } diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 7e67dcb3d4f6..7831a0318d3c 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -116,9 +116,16 @@ config HID_CYPRESS ---help--- Support for cypress mouse and barcode readers. -config DRAGONRISE_FF - tristate "DragonRise Inc. force feedback support" +config HID_DRAGONRISE + tristate "DragonRise Inc. support" if EMBEDDED depends on USB_HID + default !EMBEDDED + ---help--- + Say Y here if you have DragonRise Inc.game controllers. + +config DRAGONRISE_FF + bool "DragonRise Inc. force feedback support" + depends on HID_DRAGONRISE select INPUT_FF_MEMLESS ---help--- Say Y here if you want to enable force feedback support for DragonRise Inc. @@ -160,7 +167,7 @@ config HID_LOGITECH Support for Logitech devices that are not fully compliant with HID standard. config LOGITECH_FF - bool "Logitech force feedback" + bool "Logitech force feedback support" depends on HID_LOGITECH select INPUT_FF_MEMLESS help @@ -176,7 +183,7 @@ config LOGITECH_FF force feedback. config LOGIRUMBLEPAD2_FF - bool "Logitech Rumblepad 2 force feedback" + bool "Logitech Rumblepad 2 force feedback support" depends on HID_LOGITECH select INPUT_FF_MEMLESS help @@ -211,11 +218,19 @@ config HID_PANTHERLORD ---help--- Support for PantherLord/GreenAsia based device support. +config HID_PANTHERLORD + tristate "Pantherlord support" if EMBEDDED + depends on USB_HID + default !EMBEDDED + ---help--- + Say Y here if you have a PantherLord/GreenAsia based game controller + or adapter. + config PANTHERLORD_FF bool "Pantherlord force feedback support" depends on HID_PANTHERLORD select INPUT_FF_MEMLESS - help + ---help--- Say Y here if you have a PantherLord/GreenAsia based game controller or adapter and want to enable force feedback support for it. @@ -247,15 +262,38 @@ config HID_SUNPLUS ---help--- Support for Sunplus wireless desktop. -config GREENASIA_FF - tristate "GreenAsia (Product ID 0x12) force feedback support" +config HID_GREENASIA + tristate "GreenAsia (Product ID 0x12) support" if EMBEDDED depends on USB_HID + default !EMBEDDED + ---help--- + Say Y here if you have a GreenAsia (Product ID 0x12) based game + controller or adapter. + +config GREENASIA_FF + bool "GreenAsia (Product ID 0x12) force feedback support" + depends on HID_GREENASIA select INPUT_FF_MEMLESS ---help--- Say Y here if you have a GreenAsia (Product ID 0x12) based game controller (like MANTA Warrior MM816 and SpeedLink Strike2 SL-6635) or adapter and want to enable force feedback support for it. +config HID_SMARTJOYPLUS + tristate "SmartJoy PLUS PS2/USB adapter support" if EMBEDDED + depends on USB_HID + default !EMBEDDED + ---help--- + Support for SmartJoy PLUS PS2/USB adapter. + +config SMARTJOYPLUS_FF + bool "SmartJoy PLUS PS2/USB adapter force feedback support" + depends on HID_SMARTJOYPLUS + select INPUT_FF_MEMLESS + ---help--- + Say Y here if you have a SmartJoy PLUS PS2/USB adapter and want to + enable force feedback support for it. + config HID_TOPSEED tristate "TopSeed Cyberlink remote control support" if EMBEDDED depends on USB_HID @@ -263,20 +301,44 @@ config HID_TOPSEED ---help--- Say Y if you have a TopSeed Cyberlink remote control. -config THRUSTMASTER_FF - tristate "ThrustMaster devices support" +config HID_THRUSTMASTER + tristate "ThrustMaster devices support" if EMBEDDED depends on USB_HID - select INPUT_FF_MEMLESS - help + default !EMBEDDED + ---help--- Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or - a THRUSTMASTER Ferrari GT Rumble Force or Force Feedback Wheel. + a THRUSTMASTER Ferrari GT Rumble Wheel. + +config THRUSTMASTER_FF + bool "ThrustMaster devices force feedback support" + depends on HID_THRUSTMASTER + select INPUT_FF_MEMLESS + ---help--- + Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or + a THRUSTMASTER Ferrari GT Rumble Force or Force Feedback Wheel and + want to enable force feedback support for it. + +config HID_WACOM + tristate "Wacom Bluetooth devices support" if EMBEDDED + depends on BT_HIDP + default !EMBEDDED + ---help--- + Support for Wacom Graphire Bluetooth tablet. + +config HID_ZEROPLUS + tristate "Zeroplus based game controller support" if EMBEDDED + depends on USB_HID + default !EMBEDDED + ---help--- + Say Y here if you have a Zeroplus based game controller. config ZEROPLUS_FF - tristate "Zeroplus based game controller support" - depends on USB_HID + bool "Zeroplus based game controller force feedback support" + depends on HID_ZEROPLUS select INPUT_FF_MEMLESS - help - Say Y here if you have a Zeroplus based game controller. + ---help--- + Say Y here if you have a Zeroplus based game controller and want + to have force feedback support for it. endmenu diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 1f7cb0fd4505..db35151673b1 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -22,7 +22,7 @@ obj-$(CONFIG_HID_BELKIN) += hid-belkin.o obj-$(CONFIG_HID_CHERRY) += hid-cherry.o obj-$(CONFIG_HID_CHICONY) += hid-chicony.o obj-$(CONFIG_HID_CYPRESS) += hid-cypress.o -obj-$(CONFIG_DRAGONRISE_FF) += hid-drff.o +obj-$(CONFIG_HID_DRAGONRISE) += hid-drff.o obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o obj-$(CONFIG_HID_GYRATION) += hid-gyration.o obj-$(CONFIG_HID_KENSINGTON) += hid-kensington.o @@ -34,12 +34,14 @@ obj-$(CONFIG_HID_NTRIG) += hid-ntrig.o obj-$(CONFIG_HID_PANTHERLORD) += hid-pl.o obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o +obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o obj-$(CONFIG_HID_SONY) += hid-sony.o obj-$(CONFIG_HID_SUNPLUS) += hid-sunplus.o -obj-$(CONFIG_GREENASIA_FF) += hid-gaff.o -obj-$(CONFIG_THRUSTMASTER_FF) += hid-tmff.o +obj-$(CONFIG_HID_GREENASIA) += hid-gaff.o +obj-$(CONFIG_HID_THRUSTMASTER) += hid-tmff.o obj-$(CONFIG_HID_TOPSEED) += hid-topseed.o -obj-$(CONFIG_ZEROPLUS_FF) += hid-zpff.o +obj-$(CONFIG_HID_ZEROPLUS) += hid-zpff.o +obj-$(CONFIG_HID_WACOM) += hid-wacom.o obj-$(CONFIG_USB_HID) += usbhid/ obj-$(CONFIG_USB_MOUSE) += usbhid/ diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index acbce5745b0c..303ccce05bb3 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -436,10 +436,6 @@ static const struct hid_device_id apple_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY), .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN }, - /* Apple wireless Mighty Mouse */ - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, 0x030c), - .driver_data = APPLE_MIGHTYMOUSE | APPLE_INVERT_HWHEEL }, - { } }; MODULE_DEVICE_TABLE(hid, apple_devices); diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 8551693d645f..f2c21d5d24e8 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1312,6 +1312,8 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb651) }, { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb654) }, { HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) }, + { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SMARTJOY_PLUS) }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) }, { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) }, { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) }, diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c index 47ac1a7d66e1..04359ed64b87 100644 --- a/drivers/hid/hid-debug.c +++ b/drivers/hid/hid-debug.c @@ -137,6 +137,14 @@ static const struct hid_usage_entry hid_usage_table[] = { {0, 0x44, "BarrelSwitch"}, {0, 0x45, "Eraser"}, {0, 0x46, "TabletPick"}, + {0, 0x47, "Confidence"}, + {0, 0x48, "Width"}, + {0, 0x49, "Height"}, + {0, 0x51, "ContactID"}, + {0, 0x52, "InputMode"}, + {0, 0x53, "DeviceIndex"}, + {0, 0x54, "ContactCount"}, + {0, 0x55, "ContactMaximumNumber"}, { 15, 0, "PhysicalInterfaceDevice" }, {0, 0x00, "Undefined"}, {0, 0x01, "Physical_Interface_Device"}, @@ -514,9 +522,11 @@ static const char *events[EV_MAX + 1] = { [EV_FF_STATUS] = "ForceFeedbackStatus", }; -static const char *syncs[2] = { +static const char *syncs[3] = { [SYN_REPORT] = "Report", [SYN_CONFIG] = "Config", + [SYN_MT_REPORT] = "MT Report", }; + static const char *keys[KEY_MAX + 1] = { [KEY_RESERVED] = "Reserved", [KEY_ESC] = "Esc", [KEY_1] = "1", [KEY_2] = "2", @@ -734,8 +744,17 @@ static const char *absolutes[ABS_MAX + 1] = { [ABS_HAT2Y] = "Hat2Y", [ABS_HAT3X] = "Hat3X", [ABS_HAT3Y] = "Hat 3Y", [ABS_PRESSURE] = "Pressure", [ABS_DISTANCE] = "Distance", [ABS_TILT_X] = "XTilt", - [ABS_TILT_Y] = "YTilt", [ABS_TOOL_WIDTH] = "Tool Width", + [ABS_TILT_Y] = "YTilt", [ABS_TOOL_WIDTH] = "ToolWidth", [ABS_VOLUME] = "Volume", [ABS_MISC] = "Misc", + [ABS_MT_TOUCH_MAJOR] = "MTMajor", + [ABS_MT_TOUCH_MINOR] = "MTMinor", + [ABS_MT_WIDTH_MAJOR] = "MTMajorW", + [ABS_MT_WIDTH_MINOR] = "MTMinorW", + [ABS_MT_ORIENTATION] = "MTOrientation", + [ABS_MT_POSITION_X] = "MTPositionX", + [ABS_MT_POSITION_Y] = "MTPositionY", + [ABS_MT_TOOL_TYPE] = "MTToolType", + [ABS_MT_BLOB_ID] = "MTBlobID", }; static const char *misc[MSC_MAX + 1] = { diff --git a/drivers/hid/hid-drff.c b/drivers/hid/hid-drff.c index 34f3eb65100b..a239d20ad7a5 100644 --- a/drivers/hid/hid-drff.c +++ b/drivers/hid/hid-drff.c @@ -32,6 +32,8 @@ #include #include "hid-ids.h" + +#ifdef CONFIG_DRAGONRISE_FF #include "usbhid/usbhid.h" struct drff_device { @@ -135,6 +137,12 @@ static int drff_init(struct hid_device *hid) return 0; } +#else +static inline int drff_init(struct hid_device *hid) +{ + return 0; +} +#endif static int dr_probe(struct hid_device *hdev, const struct hid_device_id *id) { diff --git a/drivers/hid/hid-gaff.c b/drivers/hid/hid-gaff.c index 510ad3ab8d33..8a11ccddaf2e 100644 --- a/drivers/hid/hid-gaff.c +++ b/drivers/hid/hid-gaff.c @@ -31,6 +31,8 @@ #include #include #include "hid-ids.h" + +#ifdef CONFIG_GREENASIA_FF #include "usbhid/usbhid.h" struct gaff_device { @@ -130,6 +132,12 @@ static int gaff_init(struct hid_device *hid) return 0; } +#else +static inline int gaff_init(struct hid_device *hdev) +{ + return 0; +} +#endif static int ga_probe(struct hid_device *hdev, const struct hid_device_id *id) { diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 4d5ee2bbc62b..630101037921 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -414,8 +414,10 @@ #define USB_DEVICE_ID_VERNIER_LCSPEC 0x0006 #define USB_VENDOR_ID_WACOM 0x056a +#define USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH 0x81 #define USB_VENDOR_ID_WISEGROUP 0x0925 +#define USB_DEVICE_ID_SMARTJOY_PLUS 0x0005 #define USB_DEVICE_ID_1_PHIDGETSERVO_20 0x8101 #define USB_DEVICE_ID_4_PHIDGETSERVO_20 0x8104 #define USB_DEVICE_ID_8_8_4_IF_KIT 0x8201 diff --git a/drivers/hid/hid-lgff.c b/drivers/hid/hid-lgff.c index 51aff08e10ce..56099709581c 100644 --- a/drivers/hid/hid-lgff.c +++ b/drivers/hid/hid-lgff.c @@ -50,6 +50,12 @@ static const signed short ff_joystick[] = { -1 }; +static const signed short ff_joystick_ac[] = { + FF_CONSTANT, + FF_AUTOCENTER, + -1 +}; + static const signed short ff_wheel[] = { FF_CONSTANT, FF_AUTOCENTER, @@ -60,8 +66,8 @@ static const struct dev_type devices[] = { { 0x046d, 0xc211, ff_rumble }, { 0x046d, 0xc219, ff_rumble }, { 0x046d, 0xc283, ff_joystick }, - { 0x046d, 0xc286, ff_joystick }, - { 0x046d, 0xc294, ff_joystick }, + { 0x046d, 0xc286, ff_joystick_ac }, + { 0x046d, 0xc294, ff_wheel }, { 0x046d, 0xc295, ff_joystick }, { 0x046d, 0xca03, ff_wheel }, }; diff --git a/drivers/hid/hid-ntrig.c b/drivers/hid/hid-ntrig.c index c5b252be9c21..75ed9d2c1a36 100644 --- a/drivers/hid/hid-ntrig.c +++ b/drivers/hid/hid-ntrig.c @@ -1,13 +1,8 @@ /* - * HID driver for some ntrig "special" devices + * HID driver for N-Trig touchscreens * - * Copyright (c) 1999 Andreas Gal - * Copyright (c) 2000-2005 Vojtech Pavlik - * Copyright (c) 2005 Michael Haboustak for Concept2, Inc - * Copyright (c) 2006-2007 Jiri Kosina - * Copyright (c) 2007 Paul Walmsley - * Copyright (c) 2008 Jiri Slaby * Copyright (c) 2008 Rafi Rubin + * Copyright (c) 2009 Stephane Chatty * */ @@ -29,15 +24,79 @@ #define nt_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \ EV_KEY, (c)) +struct ntrig_data { + __s32 x, y, id, w, h; + char reading_a_point, found_contact_id; +}; + +/* + * this driver is aimed at two firmware versions in circulation: + * - dual pen/finger single touch + * - finger multitouch, pen not working + */ + static int ntrig_input_mapping(struct hid_device *hdev, struct hid_input *hi, struct hid_field *field, struct hid_usage *usage, unsigned long **bit, int *max) { - if ((usage->hid & HID_USAGE_PAGE) == HID_UP_DIGITIZER && - (usage->hid & 0xff) == 0x47) { - nt_map_key_clear(BTN_TOOL_DOUBLETAP); - return 1; + switch (usage->hid & HID_USAGE_PAGE) { + + case HID_UP_GENDESK: + switch (usage->hid) { + case HID_GD_X: + hid_map_usage(hi, usage, bit, max, + EV_ABS, ABS_MT_POSITION_X); + input_set_abs_params(hi->input, ABS_X, + field->logical_minimum, + field->logical_maximum, 0, 0); + return 1; + case HID_GD_Y: + hid_map_usage(hi, usage, bit, max, + EV_ABS, ABS_MT_POSITION_Y); + input_set_abs_params(hi->input, ABS_Y, + field->logical_minimum, + field->logical_maximum, 0, 0); + return 1; + } + return 0; + + case HID_UP_DIGITIZER: + switch (usage->hid) { + /* we do not want to map these for now */ + case HID_DG_INVERT: /* value is always 0 */ + case HID_DG_ERASER: /* value is always 0 */ + case HID_DG_CONTACTID: /* value is useless */ + case HID_DG_BARRELSWITCH: /* doubtful */ + case HID_DG_INPUTMODE: + case HID_DG_DEVICEINDEX: + case HID_DG_CONTACTCOUNT: + case HID_DG_CONTACTMAX: + return -1; + + /* original mapping by Rafi Rubin */ + case HID_DG_CONFIDENCE: + nt_map_key_clear(BTN_TOOL_DOUBLETAP); + return 1; + + /* width/height mapped on TouchMajor/TouchMinor/Orientation */ + case HID_DG_WIDTH: + hid_map_usage(hi, usage, bit, max, + EV_ABS, ABS_MT_TOUCH_MAJOR); + return 1; + case HID_DG_HEIGHT: + hid_map_usage(hi, usage, bit, max, + EV_ABS, ABS_MT_TOUCH_MINOR); + input_set_abs_params(hi->input, ABS_MT_ORIENTATION, + 0, 1, 0, 0); + return 1; + } + return 0; + + case 0xff000000: + /* we do not want to map these: no input-oriented meaning */ + return -1; } + return 0; } @@ -51,6 +110,138 @@ static int ntrig_input_mapped(struct hid_device *hdev, struct hid_input *hi, return 0; } + +/* + * this function is called upon all reports + * so that we can filter contact point information, + * decide whether we are in multi or single touch mode + * and call input_mt_sync after each point if necessary + */ +static int ntrig_event (struct hid_device *hid, struct hid_field *field, + struct hid_usage *usage, __s32 value) +{ + struct input_dev *input = field->hidinput->input; + struct ntrig_data *nd = hid_get_drvdata(hid); + + if (hid->claimed & HID_CLAIMED_INPUT) { + switch (usage->hid) { + case HID_GD_X: + nd->x = value; + nd->reading_a_point = 1; + break; + case HID_GD_Y: + nd->y = value; + break; + case HID_DG_CONTACTID: + nd->id = value; + /* we receive this only when in multitouch mode */ + nd->found_contact_id = 1; + break; + case HID_DG_WIDTH: + nd->w = value; + break; + case HID_DG_HEIGHT: + nd->h = value; + /* + * when in single touch mode, this is the last + * report received in a finger event. We want + * to emit a normal (X, Y) position + */ + if (! nd->found_contact_id) { + input_event(input, EV_ABS, ABS_X, nd->x); + input_event(input, EV_ABS, ABS_Y, nd->y); + } + break; + case HID_DG_TIPPRESSURE: + /* + * when in single touch mode, this is the last + * report received in a pen event. We want + * to emit a normal (X, Y) position + */ + if (! nd->found_contact_id) { + input_event(input, EV_ABS, ABS_X, nd->x); + input_event(input, EV_ABS, ABS_Y, nd->y); + input_event(input, EV_ABS, ABS_PRESSURE, value); + } + break; + case 0xff000002: + /* + * we receive this when the device is in multitouch + * mode. The first of the three values tagged with + * this usage tells if the contact point is real + * or a placeholder + */ + if (!nd->reading_a_point || value != 1) + break; + /* emit a normal (X, Y) for the first point only */ + if (nd->id == 0) { + input_event(input, EV_ABS, ABS_X, nd->x); + input_event(input, EV_ABS, ABS_Y, nd->y); + } + input_event(input, EV_ABS, ABS_MT_POSITION_X, nd->x); + input_event(input, EV_ABS, ABS_MT_POSITION_Y, nd->y); + if (nd->w > nd->h) { + input_event(input, EV_ABS, + ABS_MT_ORIENTATION, 1); + input_event(input, EV_ABS, + ABS_MT_TOUCH_MAJOR, nd->w); + input_event(input, EV_ABS, + ABS_MT_TOUCH_MINOR, nd->h); + } else { + input_event(input, EV_ABS, + ABS_MT_ORIENTATION, 0); + input_event(input, EV_ABS, + ABS_MT_TOUCH_MAJOR, nd->h); + input_event(input, EV_ABS, + ABS_MT_TOUCH_MINOR, nd->w); + } + input_mt_sync(field->hidinput->input); + nd->reading_a_point = 0; + nd->found_contact_id = 0; + break; + + default: + /* fallback to the generic hidinput handling */ + return 0; + } + } + + /* we have handled the hidinput part, now remains hiddev */ + if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event) + hid->hiddev_hid_event(hid, field, usage, value); + + return 1; +} + +static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id) +{ + int ret; + struct ntrig_data *nd; + + nd = kmalloc(sizeof(struct ntrig_data), GFP_KERNEL); + if (!nd) { + dev_err(&hdev->dev, "cannot allocate N-Trig data\n"); + return -ENOMEM; + } + nd->reading_a_point = 0; + nd->found_contact_id = 0; + hid_set_drvdata(hdev, nd); + + ret = hid_parse(hdev); + if (!ret) + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); + + if (ret) + kfree (nd); + return ret; +} + +static void ntrig_remove(struct hid_device *hdev) +{ + hid_hw_stop(hdev); + kfree(hid_get_drvdata(hdev)); +} + static const struct hid_device_id ntrig_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN), .driver_data = NTRIG_DUPLICATE_USAGES }, @@ -58,11 +249,20 @@ static const struct hid_device_id ntrig_devices[] = { }; MODULE_DEVICE_TABLE(hid, ntrig_devices); +static const struct hid_usage_id ntrig_grabbed_usages[] = { + { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID }, + { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1} +}; + static struct hid_driver ntrig_driver = { .name = "ntrig", .id_table = ntrig_devices, + .probe = ntrig_probe, + .remove = ntrig_remove, .input_mapping = ntrig_input_mapping, .input_mapped = ntrig_input_mapped, + .usage_table = ntrig_grabbed_usages, + .event = ntrig_event, }; static int ntrig_init(void) diff --git a/drivers/hid/hid-sjoy.c b/drivers/hid/hid-sjoy.c new file mode 100644 index 000000000000..eab169e5c371 --- /dev/null +++ b/drivers/hid/hid-sjoy.c @@ -0,0 +1,180 @@ +/* + * Force feedback support for SmartJoy PLUS PS2->USB adapter + * + * Copyright (c) 2009 Jussi Kivilinna + * + * Based of hid-pl.c and hid-gaff.c + * Copyright (c) 2007, 2009 Anssi Hannula + * Copyright (c) 2008 Lukasz Lubojanski + */ + +/* + * 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 DEBUG */ + +#include +#include +#include +#include "hid-ids.h" + +#ifdef CONFIG_SMARTJOYPLUS_FF +#include "usbhid/usbhid.h" + +struct sjoyff_device { + struct hid_report *report; +}; + +static int hid_sjoyff_play(struct input_dev *dev, void *data, + struct ff_effect *effect) +{ + struct hid_device *hid = input_get_drvdata(dev); + struct sjoyff_device *sjoyff = data; + u32 left, right; + + left = effect->u.rumble.strong_magnitude; + right = effect->u.rumble.weak_magnitude; + dev_dbg(&dev->dev, "called with 0x%08x 0x%08x\n", left, right); + + left = left * 0xff / 0xffff; + right = (right != 0); /* on/off only */ + + sjoyff->report->field[0]->value[1] = right; + sjoyff->report->field[0]->value[2] = left; + dev_dbg(&dev->dev, "running with 0x%02x 0x%02x\n", left, right); + usbhid_submit_report(hid, sjoyff->report, USB_DIR_OUT); + + return 0; +} + +static int sjoyff_init(struct hid_device *hid) +{ + struct sjoyff_device *sjoyff; + struct hid_report *report; + struct hid_input *hidinput = list_entry(hid->inputs.next, + struct hid_input, list); + struct list_head *report_list = + &hid->report_enum[HID_OUTPUT_REPORT].report_list; + struct list_head *report_ptr = report_list; + struct input_dev *dev; + int error; + + if (list_empty(report_list)) { + dev_err(&hid->dev, "no output reports found\n"); + return -ENODEV; + } + + report_ptr = report_ptr->next; + + if (report_ptr == report_list) { + dev_err(&hid->dev, "required output report is " + "missing\n"); + return -ENODEV; + } + + report = list_entry(report_ptr, struct hid_report, list); + if (report->maxfield < 1) { + dev_err(&hid->dev, "no fields in the report\n"); + return -ENODEV; + } + + if (report->field[0]->report_count < 3) { + dev_err(&hid->dev, "not enough values in the field\n"); + return -ENODEV; + } + + sjoyff = kzalloc(sizeof(struct sjoyff_device), GFP_KERNEL); + if (!sjoyff) + return -ENOMEM; + + dev = hidinput->input; + + set_bit(FF_RUMBLE, dev->ffbit); + + error = input_ff_create_memless(dev, sjoyff, hid_sjoyff_play); + if (error) { + kfree(sjoyff); + return error; + } + + sjoyff->report = report; + sjoyff->report->field[0]->value[0] = 0x01; + sjoyff->report->field[0]->value[1] = 0x00; + sjoyff->report->field[0]->value[2] = 0x00; + usbhid_submit_report(hid, sjoyff->report, USB_DIR_OUT); + + dev_info(&hid->dev, + "Force feedback for SmartJoy PLUS PS2/USB adapter\n"); + + return 0; +} +#else +static inline int sjoyff_init(struct hid_device *hid) +{ + return 0; +} +#endif + +static int sjoy_probe(struct hid_device *hdev, const struct hid_device_id *id) +{ + int ret; + + ret = hid_parse(hdev); + if (ret) { + dev_err(&hdev->dev, "parse failed\n"); + goto err; + } + + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF); + if (ret) { + dev_err(&hdev->dev, "hw start failed\n"); + goto err; + } + + sjoyff_init(hdev); + + return 0; +err: + return ret; +} + +static const struct hid_device_id sjoy_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SMARTJOY_PLUS) }, + { } +}; +MODULE_DEVICE_TABLE(hid, sjoy_devices); + +static struct hid_driver sjoy_driver = { + .name = "smartjoyplus", + .id_table = sjoy_devices, + .probe = sjoy_probe, +}; + +static int sjoy_init(void) +{ + return hid_register_driver(&sjoy_driver); +} + +static void sjoy_exit(void) +{ + hid_unregister_driver(&sjoy_driver); +} + +module_init(sjoy_init); +module_exit(sjoy_exit); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jussi Kivilinna"); + diff --git a/drivers/hid/hid-tmff.c b/drivers/hid/hid-tmff.c index 7c1f7b50330c..fcd6ccd02fee 100644 --- a/drivers/hid/hid-tmff.c +++ b/drivers/hid/hid-tmff.c @@ -33,11 +33,6 @@ #include "hid-ids.h" -#include "usbhid/usbhid.h" - -/* Usages for thrustmaster devices I know about */ -#define THRUSTMASTER_USAGE_FF (HID_UP_GENDESK | 0xbb) - static const signed short ff_rumble[] = { FF_RUMBLE, -1 @@ -48,6 +43,12 @@ static const signed short ff_joystick[] = { -1 }; +#ifdef CONFIG_THRUSTMASTER_FF +#include "usbhid/usbhid.h" + +/* Usages for thrustmaster devices I know about */ +#define THRUSTMASTER_USAGE_FF (HID_UP_GENDESK | 0xbb) + struct tmff_device { struct hid_report *report; struct hid_field *ff_field; @@ -209,6 +210,12 @@ fail: kfree(tmff); return error; } +#else +static inline int tmff_init(struct hid_device *hid, const signed short *ff_bits) +{ + return 0; +} +#endif static int tm_probe(struct hid_device *hdev, const struct hid_device_id *id) { diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c new file mode 100644 index 000000000000..1f9237f511e3 --- /dev/null +++ b/drivers/hid/hid-wacom.c @@ -0,0 +1,259 @@ +/* + * Bluetooth Wacom Tablet support + * + * Copyright (c) 1999 Andreas Gal + * Copyright (c) 2000-2005 Vojtech Pavlik + * Copyright (c) 2005 Michael Haboustak for Concept2, Inc + * Copyright (c) 2006-2007 Jiri Kosina + * Copyright (c) 2007 Paul Walmsley + * Copyright (c) 2008 Jiri Slaby + * Copyright (c) 2006 Andrew Zabolotny + * Copyright (c) 2009 Bastien Nocera + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +#include +#include +#include + +#include "hid-ids.h" + +struct wacom_data { + __u16 tool; + unsigned char butstate; +}; + +static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report, + u8 *raw_data, int size) +{ + struct wacom_data *wdata = hid_get_drvdata(hdev); + struct hid_input *hidinput; + struct input_dev *input; + unsigned char *data = (unsigned char *) raw_data; + int tool, x, y, rw; + + if (!(hdev->claimed & HID_CLAIMED_INPUT)) + return 0; + + tool = 0; + hidinput = list_entry(hdev->inputs.next, struct hid_input, list); + input = hidinput->input; + + /* Check if this is a tablet report */ + if (data[0] != 0x03) + return 0; + + /* Get X & Y positions */ + x = le16_to_cpu(*(__le16 *) &data[2]); + y = le16_to_cpu(*(__le16 *) &data[4]); + + /* Get current tool identifier */ + if (data[1] & 0x90) { /* If pen is in the in/active area */ + switch ((data[1] >> 5) & 3) { + case 0: /* Pen */ + tool = BTN_TOOL_PEN; + break; + + case 1: /* Rubber */ + tool = BTN_TOOL_RUBBER; + break; + + case 2: /* Mouse with wheel */ + case 3: /* Mouse without wheel */ + tool = BTN_TOOL_MOUSE; + break; + } + + /* Reset tool if out of active tablet area */ + if (!(data[1] & 0x10)) + tool = 0; + } + + /* If tool changed, notify input subsystem */ + if (wdata->tool != tool) { + if (wdata->tool) { + /* Completely reset old tool state */ + if (wdata->tool == BTN_TOOL_MOUSE) { + input_report_key(input, BTN_LEFT, 0); + input_report_key(input, BTN_RIGHT, 0); + input_report_key(input, BTN_MIDDLE, 0); + input_report_abs(input, ABS_DISTANCE, + input->absmax[ABS_DISTANCE]); + } else { + input_report_key(input, BTN_TOUCH, 0); + input_report_key(input, BTN_STYLUS, 0); + input_report_key(input, BTN_STYLUS2, 0); + input_report_abs(input, ABS_PRESSURE, 0); + } + input_report_key(input, wdata->tool, 0); + input_sync(input); + } + wdata->tool = tool; + if (tool) + input_report_key(input, tool, 1); + } + + if (tool) { + input_report_abs(input, ABS_X, x); + input_report_abs(input, ABS_Y, y); + + switch ((data[1] >> 5) & 3) { + case 2: /* Mouse with wheel */ + input_report_key(input, BTN_MIDDLE, data[1] & 0x04); + rw = (data[6] & 0x01) ? -1 : + (data[6] & 0x02) ? 1 : 0; + input_report_rel(input, REL_WHEEL, rw); + /* fall through */ + + case 3: /* Mouse without wheel */ + input_report_key(input, BTN_LEFT, data[1] & 0x01); + input_report_key(input, BTN_RIGHT, data[1] & 0x02); + /* Compute distance between mouse and tablet */ + rw = 44 - (data[6] >> 2); + if (rw < 0) + rw = 0; + else if (rw > 31) + rw = 31; + input_report_abs(input, ABS_DISTANCE, rw); + break; + + default: + input_report_abs(input, ABS_PRESSURE, + data[6] | (((__u16) (data[1] & 0x08)) << 5)); + input_report_key(input, BTN_TOUCH, data[1] & 0x01); + input_report_key(input, BTN_STYLUS, data[1] & 0x02); + input_report_key(input, BTN_STYLUS2, (tool == BTN_TOOL_PEN) && data[1] & 0x04); + break; + } + + input_sync(input); + } + + /* Report the state of the two buttons at the top of the tablet + * as two extra fingerpad keys (buttons 4 & 5). */ + rw = data[7] & 0x03; + if (rw != wdata->butstate) { + wdata->butstate = rw; + input_report_key(input, BTN_0, rw & 0x02); + input_report_key(input, BTN_1, rw & 0x01); + input_event(input, EV_MSC, MSC_SERIAL, 0xf0); + input_sync(input); + } + + return 1; +} + +static int wacom_probe(struct hid_device *hdev, + const struct hid_device_id *id) +{ + struct hid_input *hidinput; + struct input_dev *input; + struct wacom_data *wdata; + int ret; + + wdata = kzalloc(sizeof(*wdata), GFP_KERNEL); + if (wdata == NULL) { + dev_err(&hdev->dev, "can't alloc wacom descriptor\n"); + return -ENOMEM; + } + + hid_set_drvdata(hdev, wdata); + + ret = hid_parse(hdev); + if (ret) { + dev_err(&hdev->dev, "parse failed\n"); + goto err_free; + } + + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); + if (ret) { + dev_err(&hdev->dev, "hw start failed\n"); + goto err_free; + } + + hidinput = list_entry(hdev->inputs.next, struct hid_input, list); + input = hidinput->input; + + /* Basics */ + input->evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_REL); + input->absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) | + BIT(ABS_PRESSURE) | BIT(ABS_DISTANCE); + input->relbit[0] |= BIT(REL_WHEEL); + set_bit(BTN_TOOL_PEN, input->keybit); + set_bit(BTN_TOUCH, input->keybit); + set_bit(BTN_STYLUS, input->keybit); + set_bit(BTN_STYLUS2, input->keybit); + set_bit(BTN_LEFT, input->keybit); + set_bit(BTN_RIGHT, input->keybit); + set_bit(BTN_MIDDLE, input->keybit); + + /* Pad */ + input->evbit[0] |= BIT(EV_MSC); + input->mscbit[0] |= BIT(MSC_SERIAL); + + /* Distance, rubber and mouse */ + input->absbit[0] |= BIT(ABS_DISTANCE); + set_bit(BTN_TOOL_RUBBER, input->keybit); + set_bit(BTN_TOOL_MOUSE, input->keybit); + + input->absmax[ABS_PRESSURE] = 511; + input->absmax[ABS_DISTANCE] = 32; + + input->absmax[ABS_X] = 16704; + input->absmax[ABS_Y] = 12064; + input->absfuzz[ABS_X] = 4; + input->absfuzz[ABS_Y] = 4; + + return 0; +err_free: + kfree(wdata); + return ret; +} + +static void wacom_remove(struct hid_device *hdev) +{ + hid_hw_stop(hdev); + kfree(hid_get_drvdata(hdev)); +} + +static const struct hid_device_id wacom_devices[] = { + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) }, + + { } +}; +MODULE_DEVICE_TABLE(hid, wacom_devices); + +static struct hid_driver wacom_driver = { + .name = "wacom", + .id_table = wacom_devices, + .probe = wacom_probe, + .remove = wacom_remove, + .raw_event = wacom_raw_event, +}; + +static int wacom_init(void) +{ + int ret; + + ret = hid_register_driver(&wacom_driver); + if (ret) + printk(KERN_ERR "can't register wacom driver\n"); + printk(KERN_ERR "wacom driver registered\n"); + return ret; +} + +static void wacom_exit(void) +{ + hid_unregister_driver(&wacom_driver); +} + +module_init(wacom_init); +module_exit(wacom_exit); +MODULE_LICENSE("GPL"); + diff --git a/drivers/hid/hid-zpff.c b/drivers/hid/hid-zpff.c index 85a198a18537..57f710757bf4 100644 --- a/drivers/hid/hid-zpff.c +++ b/drivers/hid/hid-zpff.c @@ -27,6 +27,7 @@ #include "hid-ids.h" +#ifdef CONFIG_ZEROPLUS_FF #include "usbhid/usbhid.h" struct zpff_device { @@ -108,6 +109,12 @@ static int zpff_init(struct hid_device *hid) return 0; } +#else +static inline int zpff_init(struct hid_device *hid) +{ + return 0; +} +#endif static int zp_probe(struct hid_device *hdev, const struct hid_device_id *id) { diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c index 00ccf4b1985d..0c6639ea03dd 100644 --- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c @@ -349,10 +349,7 @@ int hidraw_connect(struct hid_device *hid) int minor, result; struct hidraw *dev; - /* TODO currently we accept any HID device. This should later - * probably be fixed to accept only those devices which provide - * non-input applications - */ + /* we accept any HID device, no matter the applications */ dev = kzalloc(sizeof(struct hidraw), GFP_KERNEL); if (!dev) diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index ac8049b5f1e9..76c4bbe9dccb 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -1234,12 +1234,11 @@ static int hid_post_reset(struct usb_interface *intf) struct hid_device *hid = usb_get_intfdata(intf); struct usbhid_device *usbhid = hid->driver_data; int status; - + spin_lock_irq(&usbhid->lock); clear_bit(HID_RESET_PENDING, &usbhid->iofl); spin_unlock_irq(&usbhid->lock); hid_set_idle(dev, intf->cur_altsetting->desc.bInterfaceNumber, 0, 0); - /* FIXME: Any more reinitialization needed? */ status = hid_start_in(hid); if (status < 0) hid_io_error(hid); @@ -1251,14 +1250,14 @@ static int hid_post_reset(struct usb_interface *intf) int usbhid_get_power(struct hid_device *hid) { struct usbhid_device *usbhid = hid->driver_data; - + return usb_autopm_get_interface(usbhid->intf); } void usbhid_put_power(struct hid_device *hid) { struct usbhid_device *usbhid = hid->driver_data; - + usb_autopm_put_interface(usbhid->intf); } diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c index e9b436d2d944..9e9421525fb9 100644 --- a/drivers/hid/usbhid/hiddev.c +++ b/drivers/hid/usbhid/hiddev.c @@ -850,8 +850,14 @@ static const struct file_operations hiddev_fops = { #endif }; +static char *hiddev_nodename(struct device *dev) +{ + return kasprintf(GFP_KERNEL, "usb/%s", dev_name(dev)); +} + static struct usb_class_driver hiddev_class = { .name = "hiddev%d", + .nodename = hiddev_nodename, .fops = &hiddev_fops, .minor_base = HIDDEV_MINOR_BASE, }; @@ -955,7 +961,6 @@ static int hiddev_usbd_probe(struct usb_interface *intf, return -ENODEV; } - static /* const */ struct usb_driver hiddev_driver = { .name = "hiddev", .probe = hiddev_usbd_probe, diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index d73f5f473e38..2d5016691d40 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -306,11 +306,11 @@ config SENSORS_F71805F will be called f71805f. config SENSORS_F71882FG - tristate "Fintek F71862FG, F71882FG and F8000" + tristate "Fintek F71858FG, F71862FG, F71882FG and F8000" depends on EXPERIMENTAL help If you say yes here you get support for hardware monitoring - features of the Fintek F71882FG/F71883FG, F71862FG/71863FG + features of the Fintek F71858FG, F71862FG/71863FG, F71882FG/F71883FG and F8000 Super-I/O chips. This driver can also be built as a module. If so, the module @@ -418,7 +418,7 @@ config SENSORS_IBMAEM power sensors and capping hardware in various IBM System X servers that support Active Energy Manager. This includes the x3350, x3550, x3650, x3655, x3755, x3850 M2, x3950 M2, - and certain HS2x/LS2x/QS2x blades. + and certain HC10/HS2x/LS2x/QS2x blades. This driver can also be built as a module. If so, the module will be called ibmaem. @@ -787,6 +787,16 @@ config SENSORS_THMC50 This driver can also be built as a module. If so, the module will be called thmc50. +config SENSORS_TMP401 + tristate "Texas Instruments TMP401 and compatibles" + depends on I2C && EXPERIMENTAL + help + If you say yes here you get support for Texas Instruments TMP401 and + TMP411 temperature sensor chips. + + This driver can also be built as a module. If so, the module + will be called tmp401. + config SENSORS_VIA686A tristate "VIA686A" depends on PCI @@ -940,6 +950,7 @@ config SENSORS_HDAPS config SENSORS_LIS3LV02D tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer" depends on ACPI && INPUT + select INPUT_POLLDEV select NEW_LEDS select LEDS_CLASS default n @@ -967,6 +978,7 @@ config SENSORS_LIS3LV02D config SENSORS_LIS3_SPI tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer (SPI)" depends on !ACPI && SPI_MASTER && INPUT + select INPUT_POLLDEV default n help This driver provides support for the LIS3LV02Dx accelerometer connected diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 0ae26984ba45..b793dce6bed5 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -82,6 +82,7 @@ obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o obj-$(CONFIG_SENSORS_THMC50) += thmc50.o +obj-$(CONFIG_SENSORS_TMP401) += tmp401.o obj-$(CONFIG_SENSORS_VIA686A) += via686a.o obj-$(CONFIG_SENSORS_VT1211) += vt1211.o obj-$(CONFIG_SENSORS_VT8231) += vt8231.o diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c index 5f81ddf71508..4146105f1a57 100644 --- a/drivers/hwmon/f71882fg.c +++ b/drivers/hwmon/f71882fg.c @@ -1,6 +1,6 @@ /*************************************************************************** * Copyright (C) 2006 by Hans Edgington * - * Copyright (C) 2007,2008 by Hans de Goede * + * Copyright (C) 2007-2009 Hans de Goede * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -32,6 +32,7 @@ #define DRVNAME "f71882fg" +#define SIO_F71858FG_LD_HWM 0x02 /* Hardware monitor logical device */ #define SIO_F71882FG_LD_HWM 0x04 /* Hardware monitor logical device */ #define SIO_UNLOCK_KEY 0x87 /* Key to enable Super-I/O */ #define SIO_LOCK_KEY 0xAA /* Key to diasble Super-I/O */ @@ -44,6 +45,7 @@ #define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */ #define SIO_FINTEK_ID 0x1934 /* Manufacturers ID */ +#define SIO_F71858_ID 0x0507 /* Chipset ID */ #define SIO_F71862_ID 0x0601 /* Chipset ID */ #define SIO_F71882_ID 0x0541 /* Chipset ID */ #define SIO_F8000_ID 0x0581 /* Chipset ID */ @@ -70,6 +72,7 @@ #define F71882FG_REG_TEMP_HIGH(nr) (0x81 + 2 * (nr)) #define F71882FG_REG_TEMP_STATUS 0x62 #define F71882FG_REG_TEMP_BEEP 0x63 +#define F71882FG_REG_TEMP_CONFIG 0x69 #define F71882FG_REG_TEMP_HYST(nr) (0x6C + (nr)) #define F71882FG_REG_TEMP_TYPE 0x6B #define F71882FG_REG_TEMP_DIODE_OPEN 0x6F @@ -92,9 +95,10 @@ static unsigned short force_id; module_param(force_id, ushort, 0); MODULE_PARM_DESC(force_id, "Override the detected device ID"); -enum chips { f71862fg, f71882fg, f8000 }; +enum chips { f71858fg, f71862fg, f71882fg, f8000 }; static const char *f71882fg_names[] = { + "f71858fg", "f71862fg", "f71882fg", "f8000", @@ -119,6 +123,7 @@ struct f71882fg_data { struct device *hwmon_dev; struct mutex update_lock; + int temp_start; /* temp numbering start (0 or 1) */ char valid; /* !=0 if following fields are valid */ unsigned long last_updated; /* In jiffies */ unsigned long last_limits; /* In jiffies */ @@ -136,7 +141,7 @@ struct f71882fg_data { /* Note: all models have only 3 temperature channels, but on some they are addressed as 0-2 and on others as 1-3, so for coding convenience we reserve space for 4 channels */ - u8 temp[4]; + u16 temp[4]; u8 temp_ovt[4]; u8 temp_high[4]; u8 temp_hyst[2]; /* 2 hysts stored per reg */ @@ -144,6 +149,7 @@ struct f71882fg_data { u8 temp_status; u8 temp_beep; u8 temp_diode_open; + u8 temp_config; u8 pwm[4]; u8 pwm_enable; u8 pwm_auto_point_hyst[2]; @@ -247,11 +253,55 @@ static struct platform_driver f71882fg_driver = { .name = DRVNAME, }, .probe = f71882fg_probe, - .remove = __devexit_p(f71882fg_remove), + .remove = f71882fg_remove, }; static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); +/* Temp and in attr for the f71858fg */ +static struct sensor_device_attribute_2 f71858fg_in_temp_attr[] = { + SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0), + SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1), + SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2), + SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0), + SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max, + store_temp_max, 0, 0), + SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst, + store_temp_max_hyst, 0, 0), + SENSOR_ATTR_2(temp1_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 0), + SENSOR_ATTR_2(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit, + store_temp_crit, 0, 0), + SENSOR_ATTR_2(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL, + 0, 0), + SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4), + SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0), + SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1), + SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_max, + store_temp_max, 0, 1), + SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst, + store_temp_max_hyst, 0, 1), + SENSOR_ATTR_2(temp2_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1), + SENSOR_ATTR_2(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit, + store_temp_crit, 0, 1), + SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL, + 0, 1), + SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5), + SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 1), + SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1), + SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2), + SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max, + store_temp_max, 0, 2), + SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst, + store_temp_max_hyst, 0, 2), + SENSOR_ATTR_2(temp3_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 2), + SENSOR_ATTR_2(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit, + store_temp_crit, 0, 2), + SENSOR_ATTR_2(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL, + 0, 2), + SENSOR_ATTR_2(temp3_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6), + SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2), +}; + /* Temp and in attr common to both the f71862fg and f71882fg */ static struct sensor_device_attribute_2 f718x2fg_in_temp_attr[] = { SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0), @@ -344,6 +394,7 @@ static struct sensor_device_attribute_2 f8000_in_temp_attr[] = { SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max, store_temp_max, 0, 0), SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4), + SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0), SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1), SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_crit, store_temp_crit, 0, 1), @@ -351,12 +402,14 @@ static struct sensor_device_attribute_2 f8000_in_temp_attr[] = { store_temp_max, 0, 1), SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5), SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 1), + SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1), SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2), SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_crit, store_temp_crit, 0, 2), SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max, store_temp_max, 0, 2), SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6), + SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2), }; /* Fan / PWM attr common to all models */ @@ -395,6 +448,9 @@ static struct sensor_device_attribute_2 fxxxx_fan_attr[] = { show_pwm_auto_point_channel, store_pwm_auto_point_channel, 0, 1), + SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 2), + SENSOR_ATTR_2(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable, + store_pwm_enable, 0, 2), SENSOR_ATTR_2(pwm3_interpolate, S_IRUGO|S_IWUSR, show_pwm_interpolate, store_pwm_interpolate, 0, 2), SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR, @@ -450,9 +506,6 @@ static struct sensor_device_attribute_2 f71862fg_fan_attr[] = { SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO, show_pwm_auto_point_temp_hyst, NULL, 3, 1), - SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 2), - SENSOR_ATTR_2(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable, - store_pwm_enable, 0, 2), SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR, show_pwm_auto_point_pwm, store_pwm_auto_point_pwm, 1, 2), @@ -473,22 +526,8 @@ static struct sensor_device_attribute_2 f71862fg_fan_attr[] = { show_pwm_auto_point_temp_hyst, NULL, 3, 2), }; -/* Fan / PWM attr for the f71882fg */ -static struct sensor_device_attribute_2 f71882fg_fan_attr[] = { - SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep, - store_fan_beep, 0, 0), - SENSOR_ATTR_2(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep, - store_fan_beep, 0, 1), - SENSOR_ATTR_2(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep, - store_fan_beep, 0, 2), - SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3), - SENSOR_ATTR_2(fan4_full_speed, S_IRUGO|S_IWUSR, - show_fan_full_speed, - store_fan_full_speed, 0, 3), - SENSOR_ATTR_2(fan4_beep, S_IRUGO|S_IWUSR, show_fan_beep, - store_fan_beep, 0, 3), - SENSOR_ATTR_2(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 3), - +/* Fan / PWM attr common to both the f71882fg and f71858fg */ +static struct sensor_device_attribute_2 f71882fg_f71858fg_fan_attr[] = { SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR, show_pwm_auto_point_pwm, store_pwm_auto_point_pwm, 0, 0), @@ -565,9 +604,6 @@ static struct sensor_device_attribute_2 f71882fg_fan_attr[] = { SENSOR_ATTR_2(pwm2_auto_point4_temp_hyst, S_IRUGO, show_pwm_auto_point_temp_hyst, NULL, 3, 1), - SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 2), - SENSOR_ATTR_2(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable, - store_pwm_enable, 0, 2), SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR, show_pwm_auto_point_pwm, store_pwm_auto_point_pwm, 0, 2), @@ -605,6 +641,24 @@ static struct sensor_device_attribute_2 f71882fg_fan_attr[] = { show_pwm_auto_point_temp_hyst, NULL, 2, 2), SENSOR_ATTR_2(pwm3_auto_point4_temp_hyst, S_IRUGO, show_pwm_auto_point_temp_hyst, NULL, 3, 2), +}; + +/* Fan / PWM attr found on the f71882fg but not on the f71858fg */ +static struct sensor_device_attribute_2 f71882fg_fan_attr[] = { + SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep, + store_fan_beep, 0, 0), + SENSOR_ATTR_2(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep, + store_fan_beep, 0, 1), + SENSOR_ATTR_2(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep, + store_fan_beep, 0, 2), + + SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3), + SENSOR_ATTR_2(fan4_full_speed, S_IRUGO|S_IWUSR, + show_fan_full_speed, + store_fan_full_speed, 0, 3), + SENSOR_ATTR_2(fan4_beep, S_IRUGO|S_IWUSR, show_fan_beep, + store_fan_beep, 0, 3), + SENSOR_ATTR_2(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 3), SENSOR_ATTR_2(pwm4, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 3), SENSOR_ATTR_2(pwm4_enable, S_IRUGO|S_IWUSR, show_pwm_enable, @@ -659,8 +713,6 @@ static struct sensor_device_attribute_2 f71882fg_fan_attr[] = { static struct sensor_device_attribute_2 f8000_fan_attr[] = { SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3), - SENSOR_ATTR_2(pwm3, S_IRUGO, show_pwm, NULL, 0, 2), - SENSOR_ATTR_2(temp1_auto_point1_pwm, S_IRUGO|S_IWUSR, show_pwm_auto_point_pwm, store_pwm_auto_point_pwm, 0, 2), @@ -857,13 +909,20 @@ static void f71882fg_write16(struct f71882fg_data *data, u8 reg, u16 val) outb(val & 255, data->addr + DATA_REG_OFFSET); } +static u16 f71882fg_read_temp(struct f71882fg_data *data, int nr) +{ + if (data->type == f71858fg) + return f71882fg_read16(data, F71882FG_REG_TEMP(nr)); + else + return f71882fg_read8(data, F71882FG_REG_TEMP(nr)); +} + static struct f71882fg_data *f71882fg_update_device(struct device *dev) { struct f71882fg_data *data = dev_get_drvdata(dev); int nr, reg = 0, reg2; int nr_fans = (data->type == f71882fg) ? 4 : 3; - int nr_ins = (data->type == f8000) ? 3 : 9; - int temp_start = (data->type == f8000) ? 0 : 1; + int nr_ins = (data->type == f71858fg || data->type == f8000) ? 3 : 9; mutex_lock(&data->update_lock); @@ -878,7 +937,7 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev) } /* Get High & boundary temps*/ - for (nr = temp_start; nr < 3 + temp_start; nr++) { + for (nr = data->temp_start; nr < 3 + data->temp_start; nr++) { data->temp_ovt[nr] = f71882fg_read8(data, F71882FG_REG_TEMP_OVT(nr)); data->temp_high[nr] = f71882fg_read8(data, @@ -886,14 +945,17 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev) } if (data->type != f8000) { - data->fan_beep = f71882fg_read8(data, - F71882FG_REG_FAN_BEEP); - data->temp_beep = f71882fg_read8(data, - F71882FG_REG_TEMP_BEEP); data->temp_hyst[0] = f71882fg_read8(data, F71882FG_REG_TEMP_HYST(0)); data->temp_hyst[1] = f71882fg_read8(data, F71882FG_REG_TEMP_HYST(1)); + } + + if (data->type == f71862fg || data->type == f71882fg) { + data->fan_beep = f71882fg_read8(data, + F71882FG_REG_FAN_BEEP); + data->temp_beep = f71882fg_read8(data, + F71882FG_REG_TEMP_BEEP); /* Have to hardcode type, because temp1 is special */ reg = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE); data->temp_type[2] = (reg & 0x04) ? 2 : 4; @@ -904,10 +966,10 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev) data->temp_type[1] = 6 /* PECI */; else if ((reg2 & 0x03) == 0x02) data->temp_type[1] = 5 /* AMDSI */; - else if (data->type != f8000) + else if (data->type == f71862fg || data->type == f71882fg) data->temp_type[1] = (reg & 0x02) ? 2 : 4; else - data->temp_type[1] = 2; /* F8000 only supports BJT */ + data->temp_type[1] = 2; /* Only supports BJT */ data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE); @@ -963,9 +1025,8 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev) F71882FG_REG_TEMP_STATUS); data->temp_diode_open = f71882fg_read8(data, F71882FG_REG_TEMP_DIODE_OPEN); - for (nr = temp_start; nr < 3 + temp_start; nr++) - data->temp[nr] = f71882fg_read8(data, - F71882FG_REG_TEMP(nr)); + for (nr = data->temp_start; nr < 3 + data->temp_start; nr++) + data->temp[nr] = f71882fg_read_temp(data, nr); data->fan_status = f71882fg_read8(data, F71882FG_REG_FAN_STATUS); @@ -1168,8 +1229,24 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, { struct f71882fg_data *data = f71882fg_update_device(dev); int nr = to_sensor_dev_attr_2(devattr)->index; + int sign, temp; - return sprintf(buf, "%d\n", data->temp[nr] * 1000); + if (data->type == f71858fg) { + /* TEMP_TABLE_SEL 1 or 3 ? */ + if (data->temp_config & 1) { + sign = data->temp[nr] & 0x0001; + temp = (data->temp[nr] >> 5) & 0x7ff; + } else { + sign = data->temp[nr] & 0x8000; + temp = (data->temp[nr] >> 5) & 0x3ff; + } + temp *= 125; + if (sign) + temp -= 128000; + } else + temp = data->temp[nr] * 1000; + + return sprintf(buf, "%d\n", temp); } static ssize_t show_temp_max(struct device *dev, struct device_attribute @@ -1440,6 +1517,10 @@ static ssize_t store_pwm_enable(struct device *dev, struct device_attribute int nr = to_sensor_dev_attr_2(devattr)->index; long val = simple_strtol(buf, NULL, 10); + /* Special case for F8000 pwm channel 3 which only does auto mode */ + if (data->type == f8000 && nr == 2 && val != 2) + return -EINVAL; + mutex_lock(&data->update_lock); data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE); /* Special case for F8000 auto PWM mode / Thermostat mode */ @@ -1458,6 +1539,12 @@ static ssize_t store_pwm_enable(struct device *dev, struct device_attribute } else { switch (val) { case 1: + /* The f71858fg does not support manual RPM mode */ + if (data->type == f71858fg && + ((data->pwm_enable >> (2 * nr)) & 1)) { + count = -EINVAL; + goto leave; + } data->pwm_enable |= 2 << (2 * nr); break; /* Manual */ case 2: @@ -1616,9 +1703,9 @@ static ssize_t show_pwm_auto_point_channel(struct device *dev, int result; struct f71882fg_data *data = f71882fg_update_device(dev); int nr = to_sensor_dev_attr_2(devattr)->index; - int temp_start = (data->type == f8000) ? 0 : 1; - result = 1 << ((data->pwm_auto_point_mapping[nr] & 3) - temp_start); + result = 1 << ((data->pwm_auto_point_mapping[nr] & 3) - + data->temp_start); return sprintf(buf, "%d\n", result); } @@ -1629,7 +1716,6 @@ static ssize_t store_pwm_auto_point_channel(struct device *dev, { struct f71882fg_data *data = dev_get_drvdata(dev); int nr = to_sensor_dev_attr_2(devattr)->index; - int temp_start = (data->type == f8000) ? 0 : 1; long val = simple_strtol(buf, NULL, 10); switch (val) { @@ -1645,7 +1731,7 @@ static ssize_t store_pwm_auto_point_channel(struct device *dev, default: return -EINVAL; } - val += temp_start; + val += data->temp_start; mutex_lock(&data->update_lock); data->pwm_auto_point_mapping[nr] = f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr)); @@ -1721,6 +1807,8 @@ static int __devinit f71882fg_probe(struct platform_device *pdev) data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start; data->type = sio_data->type; + data->temp_start = + (data->type == f71858fg || data->type == f8000) ? 0 : 1; mutex_init(&data->update_lock); platform_set_drvdata(pdev, data); @@ -1736,19 +1824,6 @@ static int __devinit f71882fg_probe(struct platform_device *pdev) goto exit_free; } - data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE); - /* If it is a 71862 and the fan / pwm part is enabled sanity check - the pwm settings */ - if (data->type == f71862fg && (start_reg & 0x02)) { - if ((data->pwm_enable & 0x15) != 0x15) { - dev_err(&pdev->dev, - "Invalid (reserved) pwm settings: 0x%02x\n", - (unsigned int)data->pwm_enable); - err = -ENODEV; - goto exit_free; - } - } - /* Register sysfs interface files */ err = device_create_file(&pdev->dev, &dev_attr_name); if (err) @@ -1756,6 +1831,20 @@ static int __devinit f71882fg_probe(struct platform_device *pdev) if (start_reg & 0x01) { switch (data->type) { + case f71858fg: + data->temp_config = + f71882fg_read8(data, F71882FG_REG_TEMP_CONFIG); + if (data->temp_config & 0x10) + /* The f71858fg temperature alarms behave as + the f8000 alarms in this mode */ + err = f71882fg_create_sysfs_files(pdev, + f8000_in_temp_attr, + ARRAY_SIZE(f8000_in_temp_attr)); + else + err = f71882fg_create_sysfs_files(pdev, + f71858fg_in_temp_attr, + ARRAY_SIZE(f71858fg_in_temp_attr)); + break; case f71882fg: err = f71882fg_create_sysfs_files(pdev, f71882fg_in_temp_attr, @@ -1779,6 +1868,35 @@ static int __devinit f71882fg_probe(struct platform_device *pdev) } if (start_reg & 0x02) { + data->pwm_enable = + f71882fg_read8(data, F71882FG_REG_PWM_ENABLE); + + /* Sanity check the pwm settings */ + switch (data->type) { + case f71858fg: + err = 0; + for (i = 0; i < nr_fans; i++) + if (((data->pwm_enable >> (i * 2)) & 3) == 3) + err = 1; + break; + case f71862fg: + err = (data->pwm_enable & 0x15) != 0x15; + break; + case f71882fg: + err = 0; + break; + case f8000: + err = data->pwm_enable & 0x20; + break; + } + if (err) { + dev_err(&pdev->dev, + "Invalid (reserved) pwm settings: 0x%02x\n", + (unsigned int)data->pwm_enable); + err = -ENODEV; + goto exit_unregister_sysfs; + } + err = f71882fg_create_sysfs_files(pdev, fxxxx_fan_attr, ARRAY_SIZE(fxxxx_fan_attr)); if (err) @@ -1794,6 +1912,13 @@ static int __devinit f71882fg_probe(struct platform_device *pdev) err = f71882fg_create_sysfs_files(pdev, f71882fg_fan_attr, ARRAY_SIZE(f71882fg_fan_attr)); + if (err) + goto exit_unregister_sysfs; + /* fall through! */ + case f71858fg: + err = f71882fg_create_sysfs_files(pdev, + f71882fg_f71858fg_fan_attr, + ARRAY_SIZE(f71882fg_f71858fg_fan_attr)); break; case f8000: err = f71882fg_create_sysfs_files(pdev, @@ -1878,6 +2003,9 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address, devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID); switch (devid) { + case SIO_F71858_ID: + sio_data->type = f71858fg; + break; case SIO_F71862_ID: sio_data->type = f71862fg; break; @@ -1892,7 +2020,11 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address, goto exit; } - superio_select(sioaddr, SIO_F71882FG_LD_HWM); + if (sio_data->type == f71858fg) + superio_select(sioaddr, SIO_F71858FG_LD_HWM); + else + superio_select(sioaddr, SIO_F71882FG_LD_HWM); + if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) { printk(KERN_WARNING DRVNAME ": Device not activated\n"); goto exit; diff --git a/drivers/hwmon/hp_accel.c b/drivers/hwmon/hp_accel.c index abca7e9f953b..6679854c85b0 100644 --- a/drivers/hwmon/hp_accel.c +++ b/drivers/hwmon/hp_accel.c @@ -27,9 +27,6 @@ #include #include #include -#include -#include -#include #include #include #include @@ -161,6 +158,7 @@ static struct axis_conversion lis3lv02d_axis_normal = {1, 2, 3}; static struct axis_conversion lis3lv02d_axis_y_inverted = {1, -2, 3}; static struct axis_conversion lis3lv02d_axis_x_inverted = {-1, 2, 3}; static struct axis_conversion lis3lv02d_axis_z_inverted = {1, 2, -3}; +static struct axis_conversion lis3lv02d_axis_xy_swap = {2, 1, 3}; static struct axis_conversion lis3lv02d_axis_xy_rotated_left = {-2, 1, 3}; static struct axis_conversion lis3lv02d_axis_xy_rotated_left_usd = {-2, 1, -3}; static struct axis_conversion lis3lv02d_axis_xy_swap_inverted = {-2, -1, 3}; @@ -194,13 +192,16 @@ static struct dmi_system_id lis3lv02d_dmi_ids[] = { AXIS_DMI_MATCH("NX9420", "HP Compaq nx9420", x_inverted), AXIS_DMI_MATCH("NW9440", "HP Compaq nw9440", x_inverted), AXIS_DMI_MATCH("NC2510", "HP Compaq 2510", y_inverted), + AXIS_DMI_MATCH("NC2710", "HP Compaq 2710", xy_swap), AXIS_DMI_MATCH("NC8510", "HP Compaq 8510", xy_swap_inverted), AXIS_DMI_MATCH("HP2133", "HP 2133", xy_rotated_left), AXIS_DMI_MATCH("HP2140", "HP 2140", xy_swap_inverted), AXIS_DMI_MATCH("NC653x", "HP Compaq 653", xy_rotated_left_usd), AXIS_DMI_MATCH("NC673x", "HP Compaq 673", xy_rotated_left_usd), AXIS_DMI_MATCH("NC651xx", "HP Compaq 651", xy_rotated_right), - AXIS_DMI_MATCH("NC671xx", "HP Compaq 671", xy_swap_yz_inverted), + AXIS_DMI_MATCH("NC6710x", "HP Compaq 6710", xy_swap_yz_inverted), + AXIS_DMI_MATCH("NC6715x", "HP Compaq 6715", y_inverted), + AXIS_DMI_MATCH("NC693xx", "HP EliteBook 693", xy_rotated_right), /* Intel-based HP Pavilion dv5 */ AXIS_DMI_MATCH2("HPDV5_I", PRODUCT_NAME, "HP Pavilion dv5", @@ -216,7 +217,6 @@ static struct dmi_system_id lis3lv02d_dmi_ids[] = { { NULL, } /* Laptop models without axis info (yet): * "NC6910" "HP Compaq 6910" - * HP Compaq 8710x Notebook PC / Mobile Workstation * "NC2400" "HP Compaq nc2400" * "NX74x0" "HP Compaq nx74" * "NX6325" "HP Compaq nx6325" @@ -324,7 +324,7 @@ static int lis3lv02d_remove(struct acpi_device *device, int type) flush_work(&hpled_led.work); led_classdev_unregister(&hpled_led.led_classdev); - return lis3lv02d_remove_fs(); + return lis3lv02d_remove_fs(&lis3_dev); } @@ -338,13 +338,7 @@ static int lis3lv02d_suspend(struct acpi_device *device, pm_message_t state) static int lis3lv02d_resume(struct acpi_device *device) { - /* put back the device in the right state (ACPI might turn it on) */ - mutex_lock(&lis3_dev.lock); - if (lis3_dev.usage > 0) - lis3lv02d_poweron(&lis3_dev); - else - lis3lv02d_poweroff(&lis3_dev); - mutex_unlock(&lis3_dev.lock); + lis3lv02d_poweron(&lis3_dev); return 0; } #else diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c index e15c3e7b07e9..29ea6753f3bb 100644 --- a/drivers/hwmon/hwmon.c +++ b/drivers/hwmon/hwmon.c @@ -18,6 +18,7 @@ #include #include #include +#include #define HWMON_ID_PREFIX "hwmon" #define HWMON_ID_FORMAT HWMON_ID_PREFIX "%d" @@ -86,8 +87,36 @@ void hwmon_device_unregister(struct device *dev) "hwmon_device_unregister() failed: bad class ID!\n"); } +static void __init hwmon_pci_quirks(void) +{ +#if defined CONFIG_X86 && defined CONFIG_PCI + struct pci_dev *sb; + u16 base; + u8 enable; + + /* Open access to 0x295-0x296 on MSI MS-7031 */ + sb = pci_get_device(PCI_VENDOR_ID_ATI, 0x436c, NULL); + if (sb && + (sb->subsystem_vendor == 0x1462 && /* MSI */ + sb->subsystem_device == 0x0031)) { /* MS-7031 */ + + pci_read_config_byte(sb, 0x48, &enable); + pci_read_config_word(sb, 0x64, &base); + + if (base == 0 && !(enable & BIT(2))) { + dev_info(&sb->dev, + "Opening wide generic port at 0x295\n"); + pci_write_config_word(sb, 0x64, 0x295); + pci_write_config_byte(sb, 0x48, enable | BIT(2)); + } + } +#endif +} + static int __init hwmon_init(void) { + hwmon_pci_quirks(); + hwmon_class = class_create(THIS_MODULE, "hwmon"); if (IS_ERR(hwmon_class)) { printk(KERN_ERR "hwmon.c: couldn't create sysfs class\n"); diff --git a/drivers/hwmon/ibmaem.c b/drivers/hwmon/ibmaem.c index fe74609a7feb..405d3fb5d76f 100644 --- a/drivers/hwmon/ibmaem.c +++ b/drivers/hwmon/ibmaem.c @@ -1127,3 +1127,4 @@ MODULE_ALIAS("dmi:bvnIBM:*:pnIBMSystemx3650-*"); MODULE_ALIAS("dmi:bvnIBM:*:pnIBMSystemx3655-*"); MODULE_ALIAS("dmi:bvnIBM:*:pnIBMSystemx3755-*"); MODULE_ALIAS("dmi:bvnIBM:*:pnIBM3850M2/x3950M2-*"); +MODULE_ALIAS("dmi:bvnIBM:*:pnIBMBladeHC10-*"); diff --git a/drivers/hwmon/lis3lv02d.c b/drivers/hwmon/lis3lv02d.c index 778eb7795983..271338bdb6be 100644 --- a/drivers/hwmon/lis3lv02d.c +++ b/drivers/hwmon/lis3lv02d.c @@ -27,9 +27,7 @@ #include #include #include -#include -#include -#include +#include #include #include #include @@ -105,56 +103,39 @@ static void lis3lv02d_get_xyz(struct lis3lv02d *lis3, int *x, int *y, int *z) { int position[3]; - position[0] = lis3_dev.read_data(lis3, OUTX); - position[1] = lis3_dev.read_data(lis3, OUTY); - position[2] = lis3_dev.read_data(lis3, OUTZ); + position[0] = lis3->read_data(lis3, OUTX); + position[1] = lis3->read_data(lis3, OUTY); + position[2] = lis3->read_data(lis3, OUTZ); - *x = lis3lv02d_get_axis(lis3_dev.ac.x, position); - *y = lis3lv02d_get_axis(lis3_dev.ac.y, position); - *z = lis3lv02d_get_axis(lis3_dev.ac.z, position); + *x = lis3lv02d_get_axis(lis3->ac.x, position); + *y = lis3lv02d_get_axis(lis3->ac.y, position); + *z = lis3lv02d_get_axis(lis3->ac.z, position); } void lis3lv02d_poweroff(struct lis3lv02d *lis3) { - lis3_dev.is_on = 0; + /* disable X,Y,Z axis and power down */ + lis3->write(lis3, CTRL_REG1, 0x00); } EXPORT_SYMBOL_GPL(lis3lv02d_poweroff); void lis3lv02d_poweron(struct lis3lv02d *lis3) { - lis3_dev.is_on = 1; - lis3_dev.init(lis3); + u8 reg; + + lis3->init(lis3); + + /* + * Common configuration + * BDU: LSB and MSB values are not updated until both have been read. + * So the value read will always be correct. + */ + lis3->read(lis3, CTRL_REG2, ®); + reg |= CTRL2_BDU; + lis3->write(lis3, CTRL_REG2, reg); } EXPORT_SYMBOL_GPL(lis3lv02d_poweron); -/* - * To be called before starting to use the device. It makes sure that the - * device will always be on until a call to lis3lv02d_decrease_use(). Not to be - * used from interrupt context. - */ -static void lis3lv02d_increase_use(struct lis3lv02d *dev) -{ - mutex_lock(&dev->lock); - dev->usage++; - if (dev->usage == 1) { - if (!dev->is_on) - lis3lv02d_poweron(dev); - } - mutex_unlock(&dev->lock); -} - -/* - * To be called whenever a usage of the device is stopped. - * It will make sure to turn off the device when there is not usage. - */ -static void lis3lv02d_decrease_use(struct lis3lv02d *dev) -{ - mutex_lock(&dev->lock); - dev->usage--; - if (dev->usage == 0) - lis3lv02d_poweroff(dev); - mutex_unlock(&dev->lock); -} static irqreturn_t lis302dl_interrupt(int irq, void *dummy) { @@ -198,15 +179,12 @@ static int lis3lv02d_misc_open(struct inode *inode, struct file *file) printk(KERN_ERR DRIVER_NAME ": IRQ%d allocation failed\n", lis3_dev.irq); return -EBUSY; } - lis3lv02d_increase_use(&lis3_dev); - printk("lis3: registered interrupt %d\n", lis3_dev.irq); return 0; } static int lis3lv02d_misc_release(struct inode *inode, struct file *file) { fasync_helper(-1, file, 0, &lis3_dev.async_queue); - lis3lv02d_decrease_use(&lis3_dev); free_irq(lis3_dev.irq, &lis3_dev); clear_bit(0, &lis3_dev.misc_opened); /* release the device */ return 0; @@ -290,46 +268,16 @@ static struct miscdevice lis3lv02d_misc_device = { .fops = &lis3lv02d_misc_fops, }; -/** - * lis3lv02d_joystick_kthread - Kthread polling function - * @data: unused - here to conform to threadfn prototype - */ -static int lis3lv02d_joystick_kthread(void *data) +static void lis3lv02d_joystick_poll(struct input_polled_dev *pidev) { int x, y, z; - while (!kthread_should_stop()) { - lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z); - input_report_abs(lis3_dev.idev, ABS_X, x - lis3_dev.xcalib); - input_report_abs(lis3_dev.idev, ABS_Y, y - lis3_dev.ycalib); - input_report_abs(lis3_dev.idev, ABS_Z, z - lis3_dev.zcalib); - - input_sync(lis3_dev.idev); - - try_to_freeze(); - msleep_interruptible(MDPS_POLL_INTERVAL); - } - - return 0; + lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z); + input_report_abs(pidev->input, ABS_X, x - lis3_dev.xcalib); + input_report_abs(pidev->input, ABS_Y, y - lis3_dev.ycalib); + input_report_abs(pidev->input, ABS_Z, z - lis3_dev.zcalib); } -static int lis3lv02d_joystick_open(struct input_dev *input) -{ - lis3lv02d_increase_use(&lis3_dev); - lis3_dev.kthread = kthread_run(lis3lv02d_joystick_kthread, NULL, "klis3lv02d"); - if (IS_ERR(lis3_dev.kthread)) { - lis3lv02d_decrease_use(&lis3_dev); - return PTR_ERR(lis3_dev.kthread); - } - - return 0; -} - -static void lis3lv02d_joystick_close(struct input_dev *input) -{ - kthread_stop(lis3_dev.kthread); - lis3lv02d_decrease_use(&lis3_dev); -} static inline void lis3lv02d_calibrate_joystick(void) { @@ -339,33 +287,36 @@ static inline void lis3lv02d_calibrate_joystick(void) int lis3lv02d_joystick_enable(void) { + struct input_dev *input_dev; int err; if (lis3_dev.idev) return -EINVAL; - lis3_dev.idev = input_allocate_device(); + lis3_dev.idev = input_allocate_polled_device(); if (!lis3_dev.idev) return -ENOMEM; + lis3_dev.idev->poll = lis3lv02d_joystick_poll; + lis3_dev.idev->poll_interval = MDPS_POLL_INTERVAL; + input_dev = lis3_dev.idev->input; + lis3lv02d_calibrate_joystick(); - lis3_dev.idev->name = "ST LIS3LV02DL Accelerometer"; - lis3_dev.idev->phys = DRIVER_NAME "/input0"; - lis3_dev.idev->id.bustype = BUS_HOST; - lis3_dev.idev->id.vendor = 0; - lis3_dev.idev->dev.parent = &lis3_dev.pdev->dev; - lis3_dev.idev->open = lis3lv02d_joystick_open; - lis3_dev.idev->close = lis3lv02d_joystick_close; + input_dev->name = "ST LIS3LV02DL Accelerometer"; + input_dev->phys = DRIVER_NAME "/input0"; + input_dev->id.bustype = BUS_HOST; + input_dev->id.vendor = 0; + input_dev->dev.parent = &lis3_dev.pdev->dev; - set_bit(EV_ABS, lis3_dev.idev->evbit); - input_set_abs_params(lis3_dev.idev, ABS_X, -lis3_dev.mdps_max_val, lis3_dev.mdps_max_val, 3, 3); - input_set_abs_params(lis3_dev.idev, ABS_Y, -lis3_dev.mdps_max_val, lis3_dev.mdps_max_val, 3, 3); - input_set_abs_params(lis3_dev.idev, ABS_Z, -lis3_dev.mdps_max_val, lis3_dev.mdps_max_val, 3, 3); + set_bit(EV_ABS, input_dev->evbit); + input_set_abs_params(input_dev, ABS_X, -lis3_dev.mdps_max_val, lis3_dev.mdps_max_val, 3, 3); + input_set_abs_params(input_dev, ABS_Y, -lis3_dev.mdps_max_val, lis3_dev.mdps_max_val, 3, 3); + input_set_abs_params(input_dev, ABS_Z, -lis3_dev.mdps_max_val, lis3_dev.mdps_max_val, 3, 3); - err = input_register_device(lis3_dev.idev); + err = input_register_polled_device(lis3_dev.idev); if (err) { - input_free_device(lis3_dev.idev); + input_free_polled_device(lis3_dev.idev); lis3_dev.idev = NULL; } @@ -378,8 +329,9 @@ void lis3lv02d_joystick_disable(void) if (!lis3_dev.idev) return; - misc_deregister(&lis3lv02d_misc_device); - input_unregister_device(lis3_dev.idev); + if (lis3_dev.irq) + misc_deregister(&lis3lv02d_misc_device); + input_unregister_polled_device(lis3_dev.idev); lis3_dev.idev = NULL; } EXPORT_SYMBOL_GPL(lis3lv02d_joystick_disable); @@ -390,9 +342,7 @@ static ssize_t lis3lv02d_position_show(struct device *dev, { int x, y, z; - lis3lv02d_increase_use(&lis3_dev); lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z); - lis3lv02d_decrease_use(&lis3_dev); return sprintf(buf, "(%d,%d,%d)\n", x, y, z); } @@ -406,9 +356,7 @@ static ssize_t lis3lv02d_calibrate_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - lis3lv02d_increase_use(&lis3_dev); lis3lv02d_calibrate_joystick(); - lis3lv02d_decrease_use(&lis3_dev); return count; } @@ -420,9 +368,7 @@ static ssize_t lis3lv02d_rate_show(struct device *dev, u8 ctrl; int val; - lis3lv02d_increase_use(&lis3_dev); lis3_dev.read(&lis3_dev, CTRL_REG1, &ctrl); - lis3lv02d_decrease_use(&lis3_dev); val = (ctrl & (CTRL1_DF0 | CTRL1_DF1)) >> 4; return sprintf(buf, "%d\n", lis3lv02dl_df_val[val]); } @@ -446,17 +392,17 @@ static struct attribute_group lis3lv02d_attribute_group = { static int lis3lv02d_add_fs(struct lis3lv02d *lis3) { - lis3_dev.pdev = platform_device_register_simple(DRIVER_NAME, -1, NULL, 0); - if (IS_ERR(lis3_dev.pdev)) - return PTR_ERR(lis3_dev.pdev); + lis3->pdev = platform_device_register_simple(DRIVER_NAME, -1, NULL, 0); + if (IS_ERR(lis3->pdev)) + return PTR_ERR(lis3->pdev); - return sysfs_create_group(&lis3_dev.pdev->dev.kobj, &lis3lv02d_attribute_group); + return sysfs_create_group(&lis3->pdev->dev.kobj, &lis3lv02d_attribute_group); } -int lis3lv02d_remove_fs(void) +int lis3lv02d_remove_fs(struct lis3lv02d *lis3) { - sysfs_remove_group(&lis3_dev.pdev->dev.kobj, &lis3lv02d_attribute_group); - platform_device_unregister(lis3_dev.pdev); + sysfs_remove_group(&lis3->pdev->dev.kobj, &lis3lv02d_attribute_group); + platform_device_unregister(lis3->pdev); return 0; } EXPORT_SYMBOL_GPL(lis3lv02d_remove_fs); @@ -482,18 +428,35 @@ int lis3lv02d_init_device(struct lis3lv02d *dev) break; default: printk(KERN_ERR DRIVER_NAME - ": unknown sensor type 0x%X\n", lis3_dev.whoami); + ": unknown sensor type 0x%X\n", dev->whoami); return -EINVAL; } - mutex_init(&dev->lock); lis3lv02d_add_fs(dev); - lis3lv02d_increase_use(dev); + lis3lv02d_poweron(dev); if (lis3lv02d_joystick_enable()) printk(KERN_ERR DRIVER_NAME ": joystick initialization failed\n"); - printk("lis3_init_device: irq %d\n", dev->irq); + /* passing in platform specific data is purely optional and only + * used by the SPI transport layer at the moment */ + if (dev->pdata) { + struct lis3lv02d_platform_data *p = dev->pdata; + + if (p->click_flags && (dev->whoami == LIS_SINGLE_ID)) { + dev->write(dev, CLICK_CFG, p->click_flags); + dev->write(dev, CLICK_TIMELIMIT, p->click_time_limit); + dev->write(dev, CLICK_LATENCY, p->click_latency); + dev->write(dev, CLICK_WINDOW, p->click_window); + dev->write(dev, CLICK_THSZ, p->click_thresh_z & 0xf); + dev->write(dev, CLICK_THSY_X, + (p->click_thresh_x & 0xf) | + (p->click_thresh_y << 4)); + } + + if (p->irq_cfg) + dev->write(dev, CTRL_REG3, p->irq_cfg); + } /* bail if we did not get an IRQ from the bus layer */ if (!dev->irq) { @@ -502,11 +465,9 @@ int lis3lv02d_init_device(struct lis3lv02d *dev) goto out; } - printk("lis3: registering device\n"); if (misc_register(&lis3lv02d_misc_device)) printk(KERN_ERR DRIVER_NAME ": misc_register failed\n"); out: - lis3lv02d_decrease_use(dev); return 0; } EXPORT_SYMBOL_GPL(lis3lv02d_init_device); diff --git a/drivers/hwmon/lis3lv02d.h b/drivers/hwmon/lis3lv02d.h index 745ec96806d4..e320e2f511f1 100644 --- a/drivers/hwmon/lis3lv02d.h +++ b/drivers/hwmon/lis3lv02d.h @@ -18,6 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include +#include /* * The actual chip is STMicroelectronics LIS3LV02DL or LIS3LV02DQ that seems to @@ -27,12 +29,14 @@ * They can also be connected via I²C. */ +#include + /* 2-byte registers */ #define LIS_DOUBLE_ID 0x3A /* LIS3LV02D[LQ] */ /* 1-byte registers */ #define LIS_SINGLE_ID 0x3B /* LIS[32]02DL and others */ -enum lis3lv02d_reg { +enum lis3_reg { WHO_AM_I = 0x0F, OFFSET_X = 0x16, OFFSET_Y = 0x17, @@ -60,6 +64,19 @@ enum lis3lv02d_reg { FF_WU_THS_L = 0x34, FF_WU_THS_H = 0x35, FF_WU_DURATION = 0x36, +}; + +enum lis302d_reg { + CLICK_CFG = 0x38, + CLICK_SRC = 0x39, + CLICK_THSY_X = 0x3B, + CLICK_THSZ = 0x3C, + CLICK_TIMELIMIT = 0x3D, + CLICK_LATENCY = 0x3E, + CLICK_WINDOW = 0x3F, +}; + +enum lis3lv02d_reg { DD_CFG = 0x38, DD_SRC = 0x39, DD_ACK = 0x3A, @@ -169,22 +186,20 @@ struct lis3lv02d { s16 (*read_data) (struct lis3lv02d *lis3, int reg); int mdps_max_val; - struct input_dev *idev; /* input device */ - struct task_struct *kthread; /* kthread for input */ - struct mutex lock; + struct input_polled_dev *idev; /* input device */ struct platform_device *pdev; /* platform device */ atomic_t count; /* interrupt count after last read */ int xcalib; /* calibrated null value for x */ int ycalib; /* calibrated null value for y */ int zcalib; /* calibrated null value for z */ - unsigned char is_on; /* whether the device is on or off */ - unsigned char usage; /* usage counter */ struct axis_conversion ac; /* hw -> logical axis */ u32 irq; /* IRQ number */ struct fasync_struct *async_queue; /* queue for the misc device */ wait_queue_head_t misc_wait; /* Wait queue for the misc device */ unsigned long misc_opened; /* bit0: whether the device is open */ + + struct lis3lv02d_platform_data *pdata; /* for passing board config */ }; int lis3lv02d_init_device(struct lis3lv02d *lis3); @@ -192,6 +207,6 @@ int lis3lv02d_joystick_enable(void); void lis3lv02d_joystick_disable(void); void lis3lv02d_poweroff(struct lis3lv02d *lis3); void lis3lv02d_poweron(struct lis3lv02d *lis3); -int lis3lv02d_remove_fs(void); +int lis3lv02d_remove_fs(struct lis3lv02d *lis3); extern struct lis3lv02d lis3_dev; diff --git a/drivers/hwmon/lis3lv02d_spi.c b/drivers/hwmon/lis3lv02d_spi.c index 07ae74b0e191..3827ff04485f 100644 --- a/drivers/hwmon/lis3lv02d_spi.c +++ b/drivers/hwmon/lis3lv02d_spi.c @@ -72,6 +72,7 @@ static int __devinit lis302dl_spi_probe(struct spi_device *spi) lis3_dev.write = lis3_spi_write; lis3_dev.irq = spi->irq; lis3_dev.ac = lis3lv02d_axis_normal; + lis3_dev.pdata = spi->dev.platform_data; spi_set_drvdata(spi, &lis3_dev); ret = lis3lv02d_init_device(&lis3_dev); diff --git a/drivers/hwmon/max6650.c b/drivers/hwmon/max6650.c index f27af6a9da41..86142a858238 100644 --- a/drivers/hwmon/max6650.c +++ b/drivers/hwmon/max6650.c @@ -12,7 +12,7 @@ * also work with the MAX6651. It does not distinguish max6650 and max6651 * chips. * - * Tha datasheet was last seen at: + * The datasheet was last seen at: * * http://pdfserv.maxim-ic.com/en/ds/MAX6650-MAX6651.pdf * @@ -98,6 +98,16 @@ I2C_CLIENT_INSMOD_1(max6650); #define MAX6650_CFG_MODE_OPEN_LOOP 0x30 #define MAX6650_COUNT_MASK 0x03 +/* + * Alarm status register bits + */ + +#define MAX6650_ALRM_MAX 0x01 +#define MAX6650_ALRM_MIN 0x02 +#define MAX6650_ALRM_TACH 0x04 +#define MAX6650_ALRM_GPIO1 0x08 +#define MAX6650_ALRM_GPIO2 0x10 + /* Minimum and maximum values of the FAN-RPM */ #define FAN_RPM_MIN 240 #define FAN_RPM_MAX 30000 @@ -151,6 +161,7 @@ struct max6650_data u8 tach[4]; u8 count; u8 dac; + u8 alarm; }; static ssize_t get_fan(struct device *dev, struct device_attribute *devattr, @@ -418,6 +429,33 @@ static ssize_t set_div(struct device *dev, struct device_attribute *devattr, return count; } +/* + * Get alarm stati: + * Possible values: + * 0 = no alarm + * 1 = alarm + */ + +static ssize_t get_alarm(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct max6650_data *data = max6650_update_device(dev); + struct i2c_client *client = to_i2c_client(dev); + int alarm = 0; + + if (data->alarm & attr->index) { + mutex_lock(&data->update_lock); + alarm = 1; + data->alarm &= ~attr->index; + data->alarm |= i2c_smbus_read_byte_data(client, + MAX6650_REG_ALARM); + mutex_unlock(&data->update_lock); + } + + return sprintf(buf, "%d\n", alarm); +} + static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, get_fan, NULL, 0); static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, get_fan, NULL, 1); static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, get_fan, NULL, 2); @@ -426,7 +464,41 @@ static DEVICE_ATTR(fan1_target, S_IWUSR | S_IRUGO, get_target, set_target); static DEVICE_ATTR(fan1_div, S_IWUSR | S_IRUGO, get_div, set_div); static DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, get_enable, set_enable); static DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, get_pwm, set_pwm); +static SENSOR_DEVICE_ATTR(fan1_max_alarm, S_IRUGO, get_alarm, NULL, + MAX6650_ALRM_MAX); +static SENSOR_DEVICE_ATTR(fan1_min_alarm, S_IRUGO, get_alarm, NULL, + MAX6650_ALRM_MIN); +static SENSOR_DEVICE_ATTR(fan1_fault, S_IRUGO, get_alarm, NULL, + MAX6650_ALRM_TACH); +static SENSOR_DEVICE_ATTR(gpio1_alarm, S_IRUGO, get_alarm, NULL, + MAX6650_ALRM_GPIO1); +static SENSOR_DEVICE_ATTR(gpio2_alarm, S_IRUGO, get_alarm, NULL, + MAX6650_ALRM_GPIO2); +static mode_t max6650_attrs_visible(struct kobject *kobj, struct attribute *a, + int n) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct i2c_client *client = to_i2c_client(dev); + u8 alarm_en = i2c_smbus_read_byte_data(client, MAX6650_REG_ALARM_EN); + struct device_attribute *devattr; + + /* + * Hide the alarms that have not been enabled by the firmware + */ + + devattr = container_of(a, struct device_attribute, attr); + if (devattr == &sensor_dev_attr_fan1_max_alarm.dev_attr + || devattr == &sensor_dev_attr_fan1_min_alarm.dev_attr + || devattr == &sensor_dev_attr_fan1_fault.dev_attr + || devattr == &sensor_dev_attr_gpio1_alarm.dev_attr + || devattr == &sensor_dev_attr_gpio2_alarm.dev_attr) { + if (!(alarm_en & to_sensor_dev_attr(devattr)->index)) + return 0; + } + + return a->mode; +} static struct attribute *max6650_attrs[] = { &sensor_dev_attr_fan1_input.dev_attr.attr, @@ -437,11 +509,17 @@ static struct attribute *max6650_attrs[] = { &dev_attr_fan1_div.attr, &dev_attr_pwm1_enable.attr, &dev_attr_pwm1.attr, + &sensor_dev_attr_fan1_max_alarm.dev_attr.attr, + &sensor_dev_attr_fan1_min_alarm.dev_attr.attr, + &sensor_dev_attr_fan1_fault.dev_attr.attr, + &sensor_dev_attr_gpio1_alarm.dev_attr.attr, + &sensor_dev_attr_gpio2_alarm.dev_attr.attr, NULL }; static struct attribute_group max6650_attr_grp = { .attrs = max6650_attrs, + .is_visible = max6650_attrs_visible, }; /* @@ -659,6 +737,12 @@ static struct max6650_data *max6650_update_device(struct device *dev) MAX6650_REG_COUNT); data->dac = i2c_smbus_read_byte_data(client, MAX6650_REG_DAC); + /* Alarms are cleared on read in case the condition that + * caused the alarm is removed. Keep the value latched here + * for providing the register through different alarm files. */ + data->alarm |= i2c_smbus_read_byte_data(client, + MAX6650_REG_ALARM); + data->last_updated = jiffies; data->valid = 1; } diff --git a/drivers/hwmon/sht15.c b/drivers/hwmon/sht15.c index 6cbdc2fea734..56cd6004da36 100644 --- a/drivers/hwmon/sht15.c +++ b/drivers/hwmon/sht15.c @@ -627,35 +627,35 @@ static struct platform_driver sht_drivers[] = { .owner = THIS_MODULE, }, .probe = sht15_probe, - .remove = sht15_remove, + .remove = __devexit_p(sht15_remove), }, { .driver = { .name = "sht11", .owner = THIS_MODULE, }, .probe = sht15_probe, - .remove = sht15_remove, + .remove = __devexit_p(sht15_remove), }, { .driver = { .name = "sht15", .owner = THIS_MODULE, }, .probe = sht15_probe, - .remove = sht15_remove, + .remove = __devexit_p(sht15_remove), }, { .driver = { .name = "sht71", .owner = THIS_MODULE, }, .probe = sht15_probe, - .remove = sht15_remove, + .remove = __devexit_p(sht15_remove), }, { .driver = { .name = "sht75", .owner = THIS_MODULE, }, .probe = sht15_probe, - .remove = sht15_remove, + .remove = __devexit_p(sht15_remove), }, }; diff --git a/drivers/hwmon/tmp401.c b/drivers/hwmon/tmp401.c new file mode 100644 index 000000000000..7b34f2cd08bb --- /dev/null +++ b/drivers/hwmon/tmp401.c @@ -0,0 +1,690 @@ +/* tmp401.c + * + * Copyright (C) 2007,2008 Hans de Goede + * Preliminary tmp411 support by: + * Gabriel Konat, Sander Leget, Wouter Willems + * Copyright (C) 2009 Andre Prendel + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * Driver for the Texas Instruments TMP401 SMBUS temperature sensor IC. + * + * Note this IC is in some aspect similar to the LM90, but it has quite a + * few differences too, for example the local temp has a higher resolution + * and thus has 16 bits registers for its value and limit instead of 8 bits. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Addresses to scan */ +static const unsigned short normal_i2c[] = { 0x4c, I2C_CLIENT_END }; + +/* Insmod parameters */ +I2C_CLIENT_INSMOD_2(tmp401, tmp411); + +/* + * The TMP401 registers, note some registers have different addresses for + * reading and writing + */ +#define TMP401_STATUS 0x02 +#define TMP401_CONFIG_READ 0x03 +#define TMP401_CONFIG_WRITE 0x09 +#define TMP401_CONVERSION_RATE_READ 0x04 +#define TMP401_CONVERSION_RATE_WRITE 0x0A +#define TMP401_TEMP_CRIT_HYST 0x21 +#define TMP401_CONSECUTIVE_ALERT 0x22 +#define TMP401_MANUFACTURER_ID_REG 0xFE +#define TMP401_DEVICE_ID_REG 0xFF +#define TMP411_N_FACTOR_REG 0x18 + +static const u8 TMP401_TEMP_MSB[2] = { 0x00, 0x01 }; +static const u8 TMP401_TEMP_LSB[2] = { 0x15, 0x10 }; +static const u8 TMP401_TEMP_LOW_LIMIT_MSB_READ[2] = { 0x06, 0x08 }; +static const u8 TMP401_TEMP_LOW_LIMIT_MSB_WRITE[2] = { 0x0C, 0x0E }; +static const u8 TMP401_TEMP_LOW_LIMIT_LSB[2] = { 0x17, 0x14 }; +static const u8 TMP401_TEMP_HIGH_LIMIT_MSB_READ[2] = { 0x05, 0x07 }; +static const u8 TMP401_TEMP_HIGH_LIMIT_MSB_WRITE[2] = { 0x0B, 0x0D }; +static const u8 TMP401_TEMP_HIGH_LIMIT_LSB[2] = { 0x16, 0x13 }; +/* These are called the THERM limit / hysteresis / mask in the datasheet */ +static const u8 TMP401_TEMP_CRIT_LIMIT[2] = { 0x20, 0x19 }; + +static const u8 TMP411_TEMP_LOWEST_MSB[2] = { 0x30, 0x34 }; +static const u8 TMP411_TEMP_LOWEST_LSB[2] = { 0x31, 0x35 }; +static const u8 TMP411_TEMP_HIGHEST_MSB[2] = { 0x32, 0x36 }; +static const u8 TMP411_TEMP_HIGHEST_LSB[2] = { 0x33, 0x37 }; + +/* Flags */ +#define TMP401_CONFIG_RANGE 0x04 +#define TMP401_CONFIG_SHUTDOWN 0x40 +#define TMP401_STATUS_LOCAL_CRIT 0x01 +#define TMP401_STATUS_REMOTE_CRIT 0x02 +#define TMP401_STATUS_REMOTE_OPEN 0x04 +#define TMP401_STATUS_REMOTE_LOW 0x08 +#define TMP401_STATUS_REMOTE_HIGH 0x10 +#define TMP401_STATUS_LOCAL_LOW 0x20 +#define TMP401_STATUS_LOCAL_HIGH 0x40 + +/* Manufacturer / Device ID's */ +#define TMP401_MANUFACTURER_ID 0x55 +#define TMP401_DEVICE_ID 0x11 +#define TMP411_DEVICE_ID 0x12 + +/* + * Functions declarations + */ + +static int tmp401_probe(struct i2c_client *client, + const struct i2c_device_id *id); +static int tmp401_detect(struct i2c_client *client, int kind, + struct i2c_board_info *info); +static int tmp401_remove(struct i2c_client *client); +static struct tmp401_data *tmp401_update_device(struct device *dev); + +/* + * Driver data (common to all clients) + */ + +static const struct i2c_device_id tmp401_id[] = { + { "tmp401", tmp401 }, + { "tmp411", tmp411 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tmp401_id); + +static struct i2c_driver tmp401_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "tmp401", + }, + .probe = tmp401_probe, + .remove = tmp401_remove, + .id_table = tmp401_id, + .detect = tmp401_detect, + .address_data = &addr_data, +}; + +/* + * Client data (each client gets its own) + */ + +struct tmp401_data { + struct device *hwmon_dev; + struct mutex update_lock; + char valid; /* zero until following fields are valid */ + unsigned long last_updated; /* in jiffies */ + int kind; + + /* register values */ + u8 status; + u8 config; + u16 temp[2]; + u16 temp_low[2]; + u16 temp_high[2]; + u8 temp_crit[2]; + u8 temp_crit_hyst; + u16 temp_lowest[2]; + u16 temp_highest[2]; +}; + +/* + * Sysfs attr show / store functions + */ + +static int tmp401_register_to_temp(u16 reg, u8 config) +{ + int temp = reg; + + if (config & TMP401_CONFIG_RANGE) + temp -= 64 * 256; + + return (temp * 625 + 80) / 160; +} + +static u16 tmp401_temp_to_register(long temp, u8 config) +{ + if (config & TMP401_CONFIG_RANGE) { + temp = SENSORS_LIMIT(temp, -64000, 191000); + temp += 64000; + } else + temp = SENSORS_LIMIT(temp, 0, 127000); + + return (temp * 160 + 312) / 625; +} + +static int tmp401_crit_register_to_temp(u8 reg, u8 config) +{ + int temp = reg; + + if (config & TMP401_CONFIG_RANGE) + temp -= 64; + + return temp * 1000; +} + +static u8 tmp401_crit_temp_to_register(long temp, u8 config) +{ + if (config & TMP401_CONFIG_RANGE) { + temp = SENSORS_LIMIT(temp, -64000, 191000); + temp += 64000; + } else + temp = SENSORS_LIMIT(temp, 0, 127000); + + return (temp + 500) / 1000; +} + +static ssize_t show_temp_value(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct tmp401_data *data = tmp401_update_device(dev); + + return sprintf(buf, "%d\n", + tmp401_register_to_temp(data->temp[index], data->config)); +} + +static ssize_t show_temp_min(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct tmp401_data *data = tmp401_update_device(dev); + + return sprintf(buf, "%d\n", + tmp401_register_to_temp(data->temp_low[index], data->config)); +} + +static ssize_t show_temp_max(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct tmp401_data *data = tmp401_update_device(dev); + + return sprintf(buf, "%d\n", + tmp401_register_to_temp(data->temp_high[index], data->config)); +} + +static ssize_t show_temp_crit(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct tmp401_data *data = tmp401_update_device(dev); + + return sprintf(buf, "%d\n", + tmp401_crit_register_to_temp(data->temp_crit[index], + data->config)); +} + +static ssize_t show_temp_crit_hyst(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int temp, index = to_sensor_dev_attr(devattr)->index; + struct tmp401_data *data = tmp401_update_device(dev); + + mutex_lock(&data->update_lock); + temp = tmp401_crit_register_to_temp(data->temp_crit[index], + data->config); + temp -= data->temp_crit_hyst * 1000; + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%d\n", temp); +} + +static ssize_t show_temp_lowest(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct tmp401_data *data = tmp401_update_device(dev); + + return sprintf(buf, "%d\n", + tmp401_register_to_temp(data->temp_lowest[index], + data->config)); +} + +static ssize_t show_temp_highest(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct tmp401_data *data = tmp401_update_device(dev); + + return sprintf(buf, "%d\n", + tmp401_register_to_temp(data->temp_highest[index], + data->config)); +} + +static ssize_t show_status(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int mask = to_sensor_dev_attr(devattr)->index; + struct tmp401_data *data = tmp401_update_device(dev); + + if (data->status & mask) + return sprintf(buf, "1\n"); + else + return sprintf(buf, "0\n"); +} + +static ssize_t store_temp_min(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct tmp401_data *data = tmp401_update_device(dev); + long val; + u16 reg; + + if (strict_strtol(buf, 10, &val)) + return -EINVAL; + + reg = tmp401_temp_to_register(val, data->config); + + mutex_lock(&data->update_lock); + + i2c_smbus_write_byte_data(to_i2c_client(dev), + TMP401_TEMP_LOW_LIMIT_MSB_WRITE[index], reg >> 8); + i2c_smbus_write_byte_data(to_i2c_client(dev), + TMP401_TEMP_LOW_LIMIT_LSB[index], reg & 0xFF); + + data->temp_low[index] = reg; + + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t store_temp_max(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct tmp401_data *data = tmp401_update_device(dev); + long val; + u16 reg; + + if (strict_strtol(buf, 10, &val)) + return -EINVAL; + + reg = tmp401_temp_to_register(val, data->config); + + mutex_lock(&data->update_lock); + + i2c_smbus_write_byte_data(to_i2c_client(dev), + TMP401_TEMP_HIGH_LIMIT_MSB_WRITE[index], reg >> 8); + i2c_smbus_write_byte_data(to_i2c_client(dev), + TMP401_TEMP_HIGH_LIMIT_LSB[index], reg & 0xFF); + + data->temp_high[index] = reg; + + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t store_temp_crit(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct tmp401_data *data = tmp401_update_device(dev); + long val; + u8 reg; + + if (strict_strtol(buf, 10, &val)) + return -EINVAL; + + reg = tmp401_crit_temp_to_register(val, data->config); + + mutex_lock(&data->update_lock); + + i2c_smbus_write_byte_data(to_i2c_client(dev), + TMP401_TEMP_CRIT_LIMIT[index], reg); + + data->temp_crit[index] = reg; + + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t store_temp_crit_hyst(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count) +{ + int temp, index = to_sensor_dev_attr(devattr)->index; + struct tmp401_data *data = tmp401_update_device(dev); + long val; + u8 reg; + + if (strict_strtol(buf, 10, &val)) + return -EINVAL; + + if (data->config & TMP401_CONFIG_RANGE) + val = SENSORS_LIMIT(val, -64000, 191000); + else + val = SENSORS_LIMIT(val, 0, 127000); + + mutex_lock(&data->update_lock); + temp = tmp401_crit_register_to_temp(data->temp_crit[index], + data->config); + val = SENSORS_LIMIT(val, temp - 255000, temp); + reg = ((temp - val) + 500) / 1000; + + i2c_smbus_write_byte_data(to_i2c_client(dev), + TMP401_TEMP_CRIT_HYST, reg); + + data->temp_crit_hyst = reg; + + mutex_unlock(&data->update_lock); + + return count; +} + +/* + * Resets the historical measurements of minimum and maximum temperatures. + * This is done by writing any value to any of the minimum/maximum registers + * (0x30-0x37). + */ +static ssize_t reset_temp_history(struct device *dev, + struct device_attribute *devattr, const char *buf, size_t count) +{ + long val; + + if (strict_strtol(buf, 10, &val)) + return -EINVAL; + + if (val != 1) { + dev_err(dev, "temp_reset_history value %ld not" + " supported. Use 1 to reset the history!\n", val); + return -EINVAL; + } + i2c_smbus_write_byte_data(to_i2c_client(dev), + TMP411_TEMP_LOWEST_MSB[0], val); + + return count; +} + +static struct sensor_device_attribute tmp401_attr[] = { + SENSOR_ATTR(temp1_input, 0444, show_temp_value, NULL, 0), + SENSOR_ATTR(temp1_min, 0644, show_temp_min, store_temp_min, 0), + SENSOR_ATTR(temp1_max, 0644, show_temp_max, store_temp_max, 0), + SENSOR_ATTR(temp1_crit, 0644, show_temp_crit, store_temp_crit, 0), + SENSOR_ATTR(temp1_crit_hyst, 0644, show_temp_crit_hyst, + store_temp_crit_hyst, 0), + SENSOR_ATTR(temp1_min_alarm, 0444, show_status, NULL, + TMP401_STATUS_LOCAL_LOW), + SENSOR_ATTR(temp1_max_alarm, 0444, show_status, NULL, + TMP401_STATUS_LOCAL_HIGH), + SENSOR_ATTR(temp1_crit_alarm, 0444, show_status, NULL, + TMP401_STATUS_LOCAL_CRIT), + SENSOR_ATTR(temp2_input, 0444, show_temp_value, NULL, 1), + SENSOR_ATTR(temp2_min, 0644, show_temp_min, store_temp_min, 1), + SENSOR_ATTR(temp2_max, 0644, show_temp_max, store_temp_max, 1), + SENSOR_ATTR(temp2_crit, 0644, show_temp_crit, store_temp_crit, 1), + SENSOR_ATTR(temp2_crit_hyst, 0444, show_temp_crit_hyst, NULL, 1), + SENSOR_ATTR(temp2_fault, 0444, show_status, NULL, + TMP401_STATUS_REMOTE_OPEN), + SENSOR_ATTR(temp2_min_alarm, 0444, show_status, NULL, + TMP401_STATUS_REMOTE_LOW), + SENSOR_ATTR(temp2_max_alarm, 0444, show_status, NULL, + TMP401_STATUS_REMOTE_HIGH), + SENSOR_ATTR(temp2_crit_alarm, 0444, show_status, NULL, + TMP401_STATUS_REMOTE_CRIT), +}; + +/* + * Additional features of the TMP411 chip. + * The TMP411 stores the minimum and maximum + * temperature measured since power-on, chip-reset, or + * minimum and maximum register reset for both the local + * and remote channels. + */ +static struct sensor_device_attribute tmp411_attr[] = { + SENSOR_ATTR(temp1_highest, 0444, show_temp_highest, NULL, 0), + SENSOR_ATTR(temp1_lowest, 0444, show_temp_lowest, NULL, 0), + SENSOR_ATTR(temp2_highest, 0444, show_temp_highest, NULL, 1), + SENSOR_ATTR(temp2_lowest, 0444, show_temp_lowest, NULL, 1), + SENSOR_ATTR(temp_reset_history, 0200, NULL, reset_temp_history, 0), +}; + +/* + * Begin non sysfs callback code (aka Real code) + */ + +static void tmp401_init_client(struct i2c_client *client) +{ + int config, config_orig; + + /* Set the conversion rate to 2 Hz */ + i2c_smbus_write_byte_data(client, TMP401_CONVERSION_RATE_WRITE, 5); + + /* Start conversions (disable shutdown if necessary) */ + config = i2c_smbus_read_byte_data(client, TMP401_CONFIG_READ); + if (config < 0) { + dev_warn(&client->dev, "Initialization failed!\n"); + return; + } + + config_orig = config; + config &= ~TMP401_CONFIG_SHUTDOWN; + + if (config != config_orig) + i2c_smbus_write_byte_data(client, TMP401_CONFIG_WRITE, config); +} + +static int tmp401_detect(struct i2c_client *client, int kind, + struct i2c_board_info *info) +{ + struct i2c_adapter *adapter = client->adapter; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -ENODEV; + + /* Detect and identify the chip */ + if (kind <= 0) { + u8 reg; + + reg = i2c_smbus_read_byte_data(client, + TMP401_MANUFACTURER_ID_REG); + if (reg != TMP401_MANUFACTURER_ID) + return -ENODEV; + + reg = i2c_smbus_read_byte_data(client, TMP401_DEVICE_ID_REG); + + switch (reg) { + case TMP401_DEVICE_ID: + kind = tmp401; + break; + case TMP411_DEVICE_ID: + kind = tmp411; + break; + default: + return -ENODEV; + } + + reg = i2c_smbus_read_byte_data(client, TMP401_CONFIG_READ); + if (reg & 0x1b) + return -ENODEV; + + reg = i2c_smbus_read_byte_data(client, + TMP401_CONVERSION_RATE_READ); + /* Datasheet says: 0x1-0x6 */ + if (reg > 15) + return -ENODEV; + } + strlcpy(info->type, tmp401_id[kind - 1].name, I2C_NAME_SIZE); + + return 0; +} + +static int tmp401_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int i, err = 0; + struct tmp401_data *data; + const char *names[] = { "TMP401", "TMP411" }; + + data = kzalloc(sizeof(struct tmp401_data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + i2c_set_clientdata(client, data); + mutex_init(&data->update_lock); + data->kind = id->driver_data; + + /* Initialize the TMP401 chip */ + tmp401_init_client(client); + + /* Register sysfs hooks */ + for (i = 0; i < ARRAY_SIZE(tmp401_attr); i++) { + err = device_create_file(&client->dev, + &tmp401_attr[i].dev_attr); + if (err) + goto exit_remove; + } + + /* Register aditional tmp411 sysfs hooks */ + if (data->kind == tmp411) { + for (i = 0; i < ARRAY_SIZE(tmp411_attr); i++) { + err = device_create_file(&client->dev, + &tmp411_attr[i].dev_attr); + if (err) + goto exit_remove; + } + } + + data->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); + data->hwmon_dev = NULL; + goto exit_remove; + } + + dev_info(&client->dev, "Detected TI %s chip\n", + names[data->kind - 1]); + + return 0; + +exit_remove: + tmp401_remove(client); /* will also free data for us */ + return err; +} + +static int tmp401_remove(struct i2c_client *client) +{ + struct tmp401_data *data = i2c_get_clientdata(client); + int i; + + if (data->hwmon_dev) + hwmon_device_unregister(data->hwmon_dev); + + for (i = 0; i < ARRAY_SIZE(tmp401_attr); i++) + device_remove_file(&client->dev, &tmp401_attr[i].dev_attr); + + if (data->kind == tmp411) { + for (i = 0; i < ARRAY_SIZE(tmp411_attr); i++) + device_remove_file(&client->dev, + &tmp411_attr[i].dev_attr); + } + + kfree(data); + return 0; +} + +static struct tmp401_data *tmp401_update_device_reg16( + struct i2c_client *client, struct tmp401_data *data) +{ + int i; + + for (i = 0; i < 2; i++) { + /* + * High byte must be read first immediately followed + * by the low byte + */ + data->temp[i] = i2c_smbus_read_byte_data(client, + TMP401_TEMP_MSB[i]) << 8; + data->temp[i] |= i2c_smbus_read_byte_data(client, + TMP401_TEMP_LSB[i]); + data->temp_low[i] = i2c_smbus_read_byte_data(client, + TMP401_TEMP_LOW_LIMIT_MSB_READ[i]) << 8; + data->temp_low[i] |= i2c_smbus_read_byte_data(client, + TMP401_TEMP_LOW_LIMIT_LSB[i]); + data->temp_high[i] = i2c_smbus_read_byte_data(client, + TMP401_TEMP_HIGH_LIMIT_MSB_READ[i]) << 8; + data->temp_high[i] |= i2c_smbus_read_byte_data(client, + TMP401_TEMP_HIGH_LIMIT_LSB[i]); + data->temp_crit[i] = i2c_smbus_read_byte_data(client, + TMP401_TEMP_CRIT_LIMIT[i]); + + if (data->kind == tmp411) { + data->temp_lowest[i] = i2c_smbus_read_byte_data(client, + TMP411_TEMP_LOWEST_MSB[i]) << 8; + data->temp_lowest[i] |= i2c_smbus_read_byte_data( + client, TMP411_TEMP_LOWEST_LSB[i]); + + data->temp_highest[i] = i2c_smbus_read_byte_data( + client, TMP411_TEMP_HIGHEST_MSB[i]) << 8; + data->temp_highest[i] |= i2c_smbus_read_byte_data( + client, TMP411_TEMP_HIGHEST_LSB[i]); + } + } + return data; +} + +static struct tmp401_data *tmp401_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct tmp401_data *data = i2c_get_clientdata(client); + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { + data->status = i2c_smbus_read_byte_data(client, TMP401_STATUS); + data->config = i2c_smbus_read_byte_data(client, + TMP401_CONFIG_READ); + tmp401_update_device_reg16(client, data); + + data->temp_crit_hyst = i2c_smbus_read_byte_data(client, + TMP401_TEMP_CRIT_HYST); + + data->last_updated = jiffies; + data->valid = 1; + } + + mutex_unlock(&data->update_lock); + + return data; +} + +static int __init tmp401_init(void) +{ + return i2c_add_driver(&tmp401_driver); +} + +static void __exit tmp401_exit(void) +{ + i2c_del_driver(&tmp401_driver); +} + +MODULE_AUTHOR("Hans de Goede "); +MODULE_DESCRIPTION("Texas Instruments TMP401 temperature sensor driver"); +MODULE_LICENSE("GPL"); + +module_init(tmp401_init); +module_exit(tmp401_exit); diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index e64b42058b21..0e9746913d2b 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c @@ -36,6 +36,7 @@ w83627ehf 10 5 4 3 0x8850 0x88 0x5ca3 0x8860 0xa1 w83627dhg 9 5 4 3 0xa020 0xc1 0x5ca3 + w83627dhg-p 9 5 4 3 0xb070 0xc1 0x5ca3 w83667hg 9 5 3 3 0xa510 0xc1 0x5ca3 */ @@ -53,12 +54,13 @@ #include #include "lm75.h" -enum kinds { w83627ehf, w83627dhg, w83667hg }; +enum kinds { w83627ehf, w83627dhg, w83627dhg_p, w83667hg }; /* used to set data->name = w83627ehf_device_names[data->sio_kind] */ static const char * w83627ehf_device_names[] = { "w83627ehf", "w83627dhg", + "w83627dhg", "w83667hg", }; @@ -86,6 +88,7 @@ MODULE_PARM_DESC(force_id, "Override the detected device ID"); #define SIO_W83627EHF_ID 0x8850 #define SIO_W83627EHG_ID 0x8860 #define SIO_W83627DHG_ID 0xa020 +#define SIO_W83627DHG_P_ID 0xb070 #define SIO_W83667HG_ID 0xa510 #define SIO_ID_MASK 0xFFF0 @@ -1517,6 +1520,7 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr, static const char __initdata sio_name_W83627EHF[] = "W83627EHF"; static const char __initdata sio_name_W83627EHG[] = "W83627EHG"; static const char __initdata sio_name_W83627DHG[] = "W83627DHG"; + static const char __initdata sio_name_W83627DHG_P[] = "W83627DHG-P"; static const char __initdata sio_name_W83667HG[] = "W83667HG"; u16 val; @@ -1542,6 +1546,10 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr, sio_data->kind = w83627dhg; sio_name = sio_name_W83627DHG; break; + case SIO_W83627DHG_P_ID: + sio_data->kind = w83627dhg_p; + sio_name = sio_name_W83627DHG_P; + break; case SIO_W83667HG_ID: sio_data->kind = w83667hg; sio_name = sio_name_W83667HG; diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index f1c6ca7e2852..aa87b6a3bbef 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -211,7 +211,7 @@ config I2C_VIA will be called i2c-via. config I2C_VIAPRO - tristate "VIA VT82C596/82C686/82xx and CX700/VX800/VX820" + tristate "VIA VT82C596/82C686/82xx and CX700/VX8xx" depends on PCI help If you say yes to this option, support will be included for the VIA @@ -225,8 +225,8 @@ config I2C_VIAPRO VT8237R/A/S VT8251 CX700 - VX800 - VX820 + VX800/VX820 + VX855/VX875 This driver can also be built as a module. If so, the module will be called i2c-viapro. @@ -298,7 +298,7 @@ config I2C_BLACKFIN_TWI config I2C_BLACKFIN_TWI_CLK_KHZ int "Blackfin TWI I2C clock (kHz)" depends on I2C_BLACKFIN_TWI - range 10 400 + range 21 400 default 50 help The unit of the TWI clock is kHz. @@ -326,6 +326,15 @@ config I2C_DAVINCI devices such as DaVinci NIC. For details please see http://www.ti.com/davinci +config I2C_DESIGNWARE + tristate "Synopsys DesignWare" + help + If you say yes to this option, support will be included for the + Synopsys DesignWare I2C adapter. Only master mode is supported. + + This driver can also be built as a module. If so, the module + will be called i2c-designware. + config I2C_GPIO tristate "GPIO-based bitbanging I2C" depends on GENERIC_GPIO @@ -513,6 +522,19 @@ config I2C_SIMTEC This driver can also be built as a module. If so, the module will be called i2c-simtec. +config I2C_STU300 + tristate "ST Microelectronics DDC I2C interface" + depends on MACH_U300 + default y if MACH_U300 + help + If you say yes to this option, support will be included for the + I2C interface from ST Microelectronics simply called "DDC I2C" + supporting both I2C and DDC, used in e.g. the U300 series + mobile platforms. + + This driver can also be built as a module. If so, the module + will be called i2c-stu300. + config I2C_VERSATILE tristate "ARM Versatile/Realview I2C bus support" depends on ARCH_VERSATILE || ARCH_REALVIEW diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 776acb6403a7..e654263bfc01 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -30,6 +30,7 @@ obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o obj-$(CONFIG_I2C_CPM) += i2c-cpm.o obj-$(CONFIG_I2C_DAVINCI) += i2c-davinci.o +obj-$(CONFIG_I2C_DESIGNWARE) += i2c-designware.o obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o obj-$(CONFIG_I2C_HIGHLANDER) += i2c-highlander.o obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o @@ -48,6 +49,7 @@ obj-$(CONFIG_I2C_S6000) += i2c-s6000.o obj-$(CONFIG_I2C_SH7760) += i2c-sh7760.o obj-$(CONFIG_I2C_SH_MOBILE) += i2c-sh_mobile.o obj-$(CONFIG_I2C_SIMTEC) += i2c-simtec.o +obj-$(CONFIG_I2C_STU300) += i2c-stu300.o obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o # External I2C/SMBus adapter drivers diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index 67d9dc5b351b..06e1ecb4919f 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c @@ -200,10 +200,10 @@ static int __devinit at91_i2c_probe(struct platform_device *pdev) if (!res) return -ENXIO; - if (!request_mem_region(res->start, res->end - res->start + 1, "at91_i2c")) + if (!request_mem_region(res->start, resource_size(res), "at91_i2c")) return -EBUSY; - twi_base = ioremap(res->start, res->end - res->start + 1); + twi_base = ioremap(res->start, resource_size(res)); if (!twi_base) { rc = -ENOMEM; goto fail0; @@ -252,7 +252,7 @@ fail2: fail1: iounmap(twi_base); fail0: - release_mem_region(res->start, res->end - res->start + 1); + release_mem_region(res->start, resource_size(res)); return rc; } @@ -268,7 +268,7 @@ static int __devexit at91_i2c_remove(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); iounmap(twi_base); - release_mem_region(res->start, res->end - res->start + 1); + release_mem_region(res->start, resource_size(res)); clk_disable(twi_clk); /* disable peripheral clock */ clk_put(twi_clk); diff --git a/drivers/i2c/busses/i2c-au1550.c b/drivers/i2c/busses/i2c-au1550.c index f78ce523e3db..532828bc50e6 100644 --- a/drivers/i2c/busses/i2c-au1550.c +++ b/drivers/i2c/busses/i2c-au1550.c @@ -389,7 +389,7 @@ i2c_au1550_probe(struct platform_device *pdev) goto out; } - priv->ioarea = request_mem_region(r->start, r->end - r->start + 1, + priv->ioarea = request_mem_region(r->start, resource_size(r), pdev->name); if (!priv->ioarea) { ret = -EBUSY; diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c index fc548b3d002e..b309ac2c3d5c 100644 --- a/drivers/i2c/busses/i2c-bfin-twi.c +++ b/drivers/i2c/busses/i2c-bfin-twi.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -104,9 +105,14 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface) write_MASTER_CTL(iface, read_MASTER_CTL(iface) | STOP); else if (iface->cur_mode == TWI_I2C_MODE_REPEAT && - iface->cur_msg+1 < iface->msg_num) - write_MASTER_CTL(iface, - read_MASTER_CTL(iface) | RSTART); + iface->cur_msg + 1 < iface->msg_num) { + if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD) + write_MASTER_CTL(iface, + read_MASTER_CTL(iface) | RSTART | MDIR); + else + write_MASTER_CTL(iface, + (read_MASTER_CTL(iface) | RSTART) & ~MDIR); + } SSYNC(); /* Clear status */ write_INT_STAT(iface, XMTSERV); @@ -134,9 +140,13 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface) read_MASTER_CTL(iface) | STOP); SSYNC(); } else if (iface->cur_mode == TWI_I2C_MODE_REPEAT && - iface->cur_msg+1 < iface->msg_num) { - write_MASTER_CTL(iface, - read_MASTER_CTL(iface) | RSTART); + iface->cur_msg + 1 < iface->msg_num) { + if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD) + write_MASTER_CTL(iface, + read_MASTER_CTL(iface) | RSTART | MDIR); + else + write_MASTER_CTL(iface, + (read_MASTER_CTL(iface) | RSTART) & ~MDIR); SSYNC(); } /* Clear interrupt source */ @@ -196,8 +206,6 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface) /* remove restart bit and enable master receive */ write_MASTER_CTL(iface, read_MASTER_CTL(iface) & ~RSTART); - write_MASTER_CTL(iface, - read_MASTER_CTL(iface) | MEN | MDIR); SSYNC(); } else if (iface->cur_mode == TWI_I2C_MODE_REPEAT && iface->cur_msg+1 < iface->msg_num) { @@ -222,18 +230,19 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface) } if (iface->pmsg[iface->cur_msg].len <= 255) - write_MASTER_CTL(iface, - iface->pmsg[iface->cur_msg].len << 6); + write_MASTER_CTL(iface, + (read_MASTER_CTL(iface) & + (~(0xff << 6))) | + (iface->pmsg[iface->cur_msg].len << 6)); else { - write_MASTER_CTL(iface, 0xff << 6); + write_MASTER_CTL(iface, + (read_MASTER_CTL(iface) | + (0xff << 6))); iface->manual_stop = 1; } /* remove restart bit and enable master receive */ write_MASTER_CTL(iface, read_MASTER_CTL(iface) & ~RSTART); - write_MASTER_CTL(iface, read_MASTER_CTL(iface) | - MEN | ((iface->read_write == I2C_SMBUS_READ) ? - MDIR : 0)); SSYNC(); } else { iface->result = 1; @@ -441,6 +450,16 @@ int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr, } iface->transPtr = data->block; break; + case I2C_SMBUS_I2C_BLOCK_DATA: + if (read_write == I2C_SMBUS_READ) { + iface->readNum = data->block[0]; + iface->cur_mode = TWI_I2C_MODE_COMBINED; + } else { + iface->writeNum = data->block[0]; + iface->cur_mode = TWI_I2C_MODE_STANDARDSUB; + } + iface->transPtr = (u8 *)&data->block[1]; + break; default: return -1; } @@ -564,7 +583,7 @@ static u32 bfin_twi_functionality(struct i2c_adapter *adap) return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_PROC_CALL | - I2C_FUNC_I2C; + I2C_FUNC_I2C | I2C_FUNC_SMBUS_I2C_BLOCK; } static struct i2c_algorithm bfin_twi_algorithm = { @@ -614,6 +633,7 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev) struct i2c_adapter *p_adap; struct resource *res; int rc; + unsigned int clkhilow; iface = kzalloc(sizeof(struct bfin_twi_iface), GFP_KERNEL); if (!iface) { @@ -632,7 +652,7 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev) goto out_error_get_res; } - iface->regs_base = ioremap(res->start, res->end - res->start + 1); + iface->regs_base = ioremap(res->start, resource_size(res)); if (iface->regs_base == NULL) { dev_err(&pdev->dev, "Cannot map IO\n"); rc = -ENXIO; @@ -675,10 +695,14 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev) /* Set TWI internal clock as 10MHz */ write_CONTROL(iface, ((get_sclk() / 1024 / 1024 + 5) / 10) & 0x7F); + /* + * We will not end up with a CLKDIV=0 because no one will specify + * 20kHz SCL or less in Kconfig now. (5 * 1024 / 20 = 0x100) + */ + clkhilow = 5 * 1024 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ; + /* Set Twi interface clock as specified */ - write_CLKDIV(iface, ((5*1024 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ) - << 8) | ((5*1024 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ) - & 0xFF)); + write_CLKDIV(iface, (clkhilow << 8) | clkhilow); /* Enable TWI */ write_CONTROL(iface, read_CONTROL(iface) | TWI_ENA); diff --git a/drivers/i2c/busses/i2c-cpm.c b/drivers/i2c/busses/i2c-cpm.c index b5db8b883615..9c2e10082b79 100644 --- a/drivers/i2c/busses/i2c-cpm.c +++ b/drivers/i2c/busses/i2c-cpm.c @@ -140,7 +140,7 @@ static irqreturn_t cpm_i2c_interrupt(int irq, void *dev_id) dev_dbg(&adap->dev, "Interrupt: %x\n", i); - wake_up_interruptible(&cpm->i2c_wait); + wake_up(&cpm->i2c_wait); return i ? IRQ_HANDLED : IRQ_NONE; } @@ -364,12 +364,12 @@ static int cpm_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) dev_dbg(&adap->dev, "test ready.\n"); pmsg = &msgs[tptr]; if (pmsg->flags & I2C_M_RD) - ret = wait_event_interruptible_timeout(cpm->i2c_wait, + ret = wait_event_timeout(cpm->i2c_wait, (in_be16(&tbdf[tptr].cbd_sc) & BD_SC_NAK) || !(in_be16(&rbdf[rptr].cbd_sc) & BD_SC_EMPTY), 1 * HZ); else - ret = wait_event_interruptible_timeout(cpm->i2c_wait, + ret = wait_event_timeout(cpm->i2c_wait, !(in_be16(&tbdf[tptr].cbd_sc) & BD_SC_READY), 1 * HZ); if (ret == 0) { diff --git a/drivers/i2c/busses/i2c-designware.c b/drivers/i2c/busses/i2c-designware.c new file mode 100644 index 000000000000..b444762e9b9f --- /dev/null +++ b/drivers/i2c/busses/i2c-designware.c @@ -0,0 +1,624 @@ +/* + * Synopsys Designware I2C adapter driver (master only). + * + * Based on the TI DAVINCI I2C adapter driver. + * + * Copyright (C) 2006 Texas Instruments. + * Copyright (C) 2007 MontaVista Software Inc. + * Copyright (C) 2009 Provigent Ltd. + * + * ---------------------------------------------------------------------------- + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Registers offset + */ +#define DW_IC_CON 0x0 +#define DW_IC_TAR 0x4 +#define DW_IC_DATA_CMD 0x10 +#define DW_IC_SS_SCL_HCNT 0x14 +#define DW_IC_SS_SCL_LCNT 0x18 +#define DW_IC_FS_SCL_HCNT 0x1c +#define DW_IC_FS_SCL_LCNT 0x20 +#define DW_IC_INTR_STAT 0x2c +#define DW_IC_INTR_MASK 0x30 +#define DW_IC_CLR_INTR 0x40 +#define DW_IC_ENABLE 0x6c +#define DW_IC_STATUS 0x70 +#define DW_IC_TXFLR 0x74 +#define DW_IC_RXFLR 0x78 +#define DW_IC_COMP_PARAM_1 0xf4 +#define DW_IC_TX_ABRT_SOURCE 0x80 + +#define DW_IC_CON_MASTER 0x1 +#define DW_IC_CON_SPEED_STD 0x2 +#define DW_IC_CON_SPEED_FAST 0x4 +#define DW_IC_CON_10BITADDR_MASTER 0x10 +#define DW_IC_CON_RESTART_EN 0x20 +#define DW_IC_CON_SLAVE_DISABLE 0x40 + +#define DW_IC_INTR_TX_EMPTY 0x10 +#define DW_IC_INTR_TX_ABRT 0x40 +#define DW_IC_INTR_STOP_DET 0x200 + +#define DW_IC_STATUS_ACTIVITY 0x1 + +#define DW_IC_ERR_TX_ABRT 0x1 + +/* + * status codes + */ +#define STATUS_IDLE 0x0 +#define STATUS_WRITE_IN_PROGRESS 0x1 +#define STATUS_READ_IN_PROGRESS 0x2 + +#define TIMEOUT 20 /* ms */ + +/* + * hardware abort codes from the DW_IC_TX_ABRT_SOURCE register + * + * only expected abort codes are listed here + * refer to the datasheet for the full list + */ +#define ABRT_7B_ADDR_NOACK 0 +#define ABRT_10ADDR1_NOACK 1 +#define ABRT_10ADDR2_NOACK 2 +#define ABRT_TXDATA_NOACK 3 +#define ABRT_GCALL_NOACK 4 +#define ABRT_GCALL_READ 5 +#define ABRT_SBYTE_ACKDET 7 +#define ABRT_SBYTE_NORSTRT 9 +#define ABRT_10B_RD_NORSTRT 10 +#define ARB_MASTER_DIS 11 +#define ARB_LOST 12 + +static char *abort_sources[] = { + [ABRT_7B_ADDR_NOACK] = + "slave address not acknowledged (7bit mode)", + [ABRT_10ADDR1_NOACK] = + "first address byte not acknowledged (10bit mode)", + [ABRT_10ADDR2_NOACK] = + "second address byte not acknowledged (10bit mode)", + [ABRT_TXDATA_NOACK] = + "data not acknowledged", + [ABRT_GCALL_NOACK] = + "no acknowledgement for a general call", + [ABRT_GCALL_READ] = + "read after general call", + [ABRT_SBYTE_ACKDET] = + "start byte acknowledged", + [ABRT_SBYTE_NORSTRT] = + "trying to send start byte when restart is disabled", + [ABRT_10B_RD_NORSTRT] = + "trying to read when restart is disabled (10bit mode)", + [ARB_MASTER_DIS] = + "trying to use disabled adapter", + [ARB_LOST] = + "lost arbitration", +}; + +/** + * struct dw_i2c_dev - private i2c-designware data + * @dev: driver model device node + * @base: IO registers pointer + * @cmd_complete: tx completion indicator + * @pump_msg: continue in progress transfers + * @lock: protect this struct and IO registers + * @clk: input reference clock + * @cmd_err: run time hadware error code + * @msgs: points to an array of messages currently being transfered + * @msgs_num: the number of elements in msgs + * @msg_write_idx: the element index of the current tx message in the msgs + * array + * @tx_buf_len: the length of the current tx buffer + * @tx_buf: the current tx buffer + * @msg_read_idx: the element index of the current rx message in the msgs + * array + * @rx_buf_len: the length of the current rx buffer + * @rx_buf: the current rx buffer + * @msg_err: error status of the current transfer + * @status: i2c master status, one of STATUS_* + * @abort_source: copy of the TX_ABRT_SOURCE register + * @irq: interrupt number for the i2c master + * @adapter: i2c subsystem adapter node + * @tx_fifo_depth: depth of the hardware tx fifo + * @rx_fifo_depth: depth of the hardware rx fifo + */ +struct dw_i2c_dev { + struct device *dev; + void __iomem *base; + struct completion cmd_complete; + struct tasklet_struct pump_msg; + struct mutex lock; + struct clk *clk; + int cmd_err; + struct i2c_msg *msgs; + int msgs_num; + int msg_write_idx; + u16 tx_buf_len; + u8 *tx_buf; + int msg_read_idx; + u16 rx_buf_len; + u8 *rx_buf; + int msg_err; + unsigned int status; + u16 abort_source; + int irq; + struct i2c_adapter adapter; + unsigned int tx_fifo_depth; + unsigned int rx_fifo_depth; +}; + +/** + * i2c_dw_init() - initialize the designware i2c master hardware + * @dev: device private data + * + * This functions configures and enables the I2C master. + * This function is called during I2C init function, and in case of timeout at + * run time. + */ +static void i2c_dw_init(struct dw_i2c_dev *dev) +{ + u32 input_clock_khz = clk_get_rate(dev->clk) / 1000; + u16 ic_con; + + /* Disable the adapter */ + writeb(0, dev->base + DW_IC_ENABLE); + + /* set standard and fast speed deviders for high/low periods */ + writew((input_clock_khz * 40 / 10000)+1, /* std speed high, 4us */ + dev->base + DW_IC_SS_SCL_HCNT); + writew((input_clock_khz * 47 / 10000)+1, /* std speed low, 4.7us */ + dev->base + DW_IC_SS_SCL_LCNT); + writew((input_clock_khz * 6 / 10000)+1, /* fast speed high, 0.6us */ + dev->base + DW_IC_FS_SCL_HCNT); + writew((input_clock_khz * 13 / 10000)+1, /* fast speed low, 1.3us */ + dev->base + DW_IC_FS_SCL_LCNT); + + /* configure the i2c master */ + ic_con = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE | + DW_IC_CON_RESTART_EN | DW_IC_CON_SPEED_FAST; + writew(ic_con, dev->base + DW_IC_CON); +} + +/* + * Waiting for bus not busy + */ +static int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev) +{ + int timeout = TIMEOUT; + + while (readb(dev->base + DW_IC_STATUS) & DW_IC_STATUS_ACTIVITY) { + if (timeout <= 0) { + dev_warn(dev->dev, "timeout waiting for bus ready\n"); + return -ETIMEDOUT; + } + timeout--; + mdelay(1); + } + + return 0; +} + +/* + * Initiate low level master read/write transaction. + * This function is called from i2c_dw_xfer when starting a transfer. + * This function is also called from dw_i2c_pump_msg to continue a transfer + * that is longer than the size of the TX FIFO. + */ +static void +i2c_dw_xfer_msg(struct i2c_adapter *adap) +{ + struct dw_i2c_dev *dev = i2c_get_adapdata(adap); + struct i2c_msg *msgs = dev->msgs; + int num = dev->msgs_num; + u16 ic_con, intr_mask; + int tx_limit = dev->tx_fifo_depth - readb(dev->base + DW_IC_TXFLR); + int rx_limit = dev->rx_fifo_depth - readb(dev->base + DW_IC_RXFLR); + u16 addr = msgs[dev->msg_write_idx].addr; + u16 buf_len = dev->tx_buf_len; + + if (!(dev->status & STATUS_WRITE_IN_PROGRESS)) { + /* Disable the adapter */ + writeb(0, dev->base + DW_IC_ENABLE); + + /* set the slave (target) address */ + writew(msgs[dev->msg_write_idx].addr, dev->base + DW_IC_TAR); + + /* if the slave address is ten bit address, enable 10BITADDR */ + ic_con = readw(dev->base + DW_IC_CON); + if (msgs[dev->msg_write_idx].flags & I2C_M_TEN) + ic_con |= DW_IC_CON_10BITADDR_MASTER; + else + ic_con &= ~DW_IC_CON_10BITADDR_MASTER; + writew(ic_con, dev->base + DW_IC_CON); + + /* Enable the adapter */ + writeb(1, dev->base + DW_IC_ENABLE); + } + + for (; dev->msg_write_idx < num; dev->msg_write_idx++) { + /* if target address has changed, we need to + * reprogram the target address in the i2c + * adapter when we are done with this transfer + */ + if (msgs[dev->msg_write_idx].addr != addr) + return; + + if (msgs[dev->msg_write_idx].len == 0) { + dev_err(dev->dev, + "%s: invalid message length\n", __func__); + dev->msg_err = -EINVAL; + return; + } + + if (!(dev->status & STATUS_WRITE_IN_PROGRESS)) { + /* new i2c_msg */ + dev->tx_buf = msgs[dev->msg_write_idx].buf; + buf_len = msgs[dev->msg_write_idx].len; + } + + while (buf_len > 0 && tx_limit > 0 && rx_limit > 0) { + if (msgs[dev->msg_write_idx].flags & I2C_M_RD) { + writew(0x100, dev->base + DW_IC_DATA_CMD); + rx_limit--; + } else + writew(*(dev->tx_buf++), + dev->base + DW_IC_DATA_CMD); + tx_limit--; buf_len--; + } + } + + intr_mask = DW_IC_INTR_STOP_DET | DW_IC_INTR_TX_ABRT; + if (buf_len > 0) { /* more bytes to be written */ + intr_mask |= DW_IC_INTR_TX_EMPTY; + dev->status |= STATUS_WRITE_IN_PROGRESS; + } else + dev->status &= ~STATUS_WRITE_IN_PROGRESS; + writew(intr_mask, dev->base + DW_IC_INTR_MASK); + + dev->tx_buf_len = buf_len; +} + +static void +i2c_dw_read(struct i2c_adapter *adap) +{ + struct dw_i2c_dev *dev = i2c_get_adapdata(adap); + struct i2c_msg *msgs = dev->msgs; + int num = dev->msgs_num; + u16 addr = msgs[dev->msg_read_idx].addr; + int rx_valid = readw(dev->base + DW_IC_RXFLR); + + for (; dev->msg_read_idx < num; dev->msg_read_idx++) { + u16 len; + u8 *buf; + + if (!(msgs[dev->msg_read_idx].flags & I2C_M_RD)) + continue; + + /* different i2c client, reprogram the i2c adapter */ + if (msgs[dev->msg_read_idx].addr != addr) + return; + + if (!(dev->status & STATUS_READ_IN_PROGRESS)) { + len = msgs[dev->msg_read_idx].len; + buf = msgs[dev->msg_read_idx].buf; + } else { + len = dev->rx_buf_len; + buf = dev->rx_buf; + } + + for (; len > 0 && rx_valid > 0; len--, rx_valid--) + *buf++ = readb(dev->base + DW_IC_DATA_CMD); + + if (len > 0) { + dev->status |= STATUS_READ_IN_PROGRESS; + dev->rx_buf_len = len; + dev->rx_buf = buf; + return; + } else + dev->status &= ~STATUS_READ_IN_PROGRESS; + } +} + +/* + * Prepare controller for a transaction and call i2c_dw_xfer_msg + */ +static int +i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) +{ + struct dw_i2c_dev *dev = i2c_get_adapdata(adap); + int ret; + + dev_dbg(dev->dev, "%s: msgs: %d\n", __func__, num); + + mutex_lock(&dev->lock); + + INIT_COMPLETION(dev->cmd_complete); + dev->msgs = msgs; + dev->msgs_num = num; + dev->cmd_err = 0; + dev->msg_write_idx = 0; + dev->msg_read_idx = 0; + dev->msg_err = 0; + dev->status = STATUS_IDLE; + + ret = i2c_dw_wait_bus_not_busy(dev); + if (ret < 0) + goto done; + + /* start the transfers */ + i2c_dw_xfer_msg(adap); + + /* wait for tx to complete */ + ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete, HZ); + if (ret == 0) { + dev_err(dev->dev, "controller timed out\n"); + i2c_dw_init(dev); + ret = -ETIMEDOUT; + goto done; + } else if (ret < 0) + goto done; + + if (dev->msg_err) { + ret = dev->msg_err; + goto done; + } + + /* no error */ + if (likely(!dev->cmd_err)) { + /* read rx fifo, and disable the adapter */ + do { + i2c_dw_read(adap); + } while (dev->status & STATUS_READ_IN_PROGRESS); + writeb(0, dev->base + DW_IC_ENABLE); + ret = num; + goto done; + } + + /* We have an error */ + if (dev->cmd_err == DW_IC_ERR_TX_ABRT) { + unsigned long abort_source = dev->abort_source; + int i; + + for_each_bit(i, &abort_source, ARRAY_SIZE(abort_sources)) { + dev_err(dev->dev, "%s: %s\n", __func__, abort_sources[i]); + } + } + ret = -EIO; + +done: + mutex_unlock(&dev->lock); + + return ret; +} + +static u32 i2c_dw_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR; +} + +static void dw_i2c_pump_msg(unsigned long data) +{ + struct dw_i2c_dev *dev = (struct dw_i2c_dev *) data; + u16 intr_mask; + + i2c_dw_read(&dev->adapter); + i2c_dw_xfer_msg(&dev->adapter); + + intr_mask = DW_IC_INTR_STOP_DET | DW_IC_INTR_TX_ABRT; + if (dev->status & STATUS_WRITE_IN_PROGRESS) + intr_mask |= DW_IC_INTR_TX_EMPTY; + writew(intr_mask, dev->base + DW_IC_INTR_MASK); +} + +/* + * Interrupt service routine. This gets called whenever an I2C interrupt + * occurs. + */ +static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id) +{ + struct dw_i2c_dev *dev = dev_id; + u16 stat; + + stat = readw(dev->base + DW_IC_INTR_STAT); + dev_dbg(dev->dev, "%s: stat=0x%x\n", __func__, stat); + if (stat & DW_IC_INTR_TX_ABRT) { + dev->abort_source = readw(dev->base + DW_IC_TX_ABRT_SOURCE); + dev->cmd_err |= DW_IC_ERR_TX_ABRT; + dev->status = STATUS_IDLE; + } else if (stat & DW_IC_INTR_TX_EMPTY) + tasklet_schedule(&dev->pump_msg); + + readb(dev->base + DW_IC_CLR_INTR); /* clear interrupts */ + writew(0, dev->base + DW_IC_INTR_MASK); /* disable interrupts */ + if (stat & (DW_IC_INTR_TX_ABRT | DW_IC_INTR_STOP_DET)) + complete(&dev->cmd_complete); + + return IRQ_HANDLED; +} + +static struct i2c_algorithm i2c_dw_algo = { + .master_xfer = i2c_dw_xfer, + .functionality = i2c_dw_func, +}; + +static int __devinit dw_i2c_probe(struct platform_device *pdev) +{ + struct dw_i2c_dev *dev; + struct i2c_adapter *adap; + struct resource *mem, *irq, *ioarea; + int r; + + /* NOTE: driver uses the static register mapping */ + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) { + dev_err(&pdev->dev, "no mem resource?\n"); + return -EINVAL; + } + + irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!irq) { + dev_err(&pdev->dev, "no irq resource?\n"); + return -EINVAL; + } + + ioarea = request_mem_region(mem->start, resource_size(mem), + pdev->name); + if (!ioarea) { + dev_err(&pdev->dev, "I2C region already claimed\n"); + return -EBUSY; + } + + dev = kzalloc(sizeof(struct dw_i2c_dev), GFP_KERNEL); + if (!dev) { + r = -ENOMEM; + goto err_release_region; + } + + init_completion(&dev->cmd_complete); + tasklet_init(&dev->pump_msg, dw_i2c_pump_msg, (unsigned long) dev); + mutex_init(&dev->lock); + dev->dev = get_device(&pdev->dev); + dev->irq = irq->start; + platform_set_drvdata(pdev, dev); + + dev->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(dev->clk)) { + r = -ENODEV; + goto err_free_mem; + } + clk_enable(dev->clk); + + dev->base = ioremap(mem->start, resource_size(mem)); + if (dev->base == NULL) { + dev_err(&pdev->dev, "failure mapping io resources\n"); + r = -EBUSY; + goto err_unuse_clocks; + } + { + u32 param1 = readl(dev->base + DW_IC_COMP_PARAM_1); + + dev->tx_fifo_depth = ((param1 >> 16) & 0xff) + 1; + dev->rx_fifo_depth = ((param1 >> 8) & 0xff) + 1; + } + i2c_dw_init(dev); + + writew(0, dev->base + DW_IC_INTR_MASK); /* disable IRQ */ + r = request_irq(dev->irq, i2c_dw_isr, 0, pdev->name, dev); + if (r) { + dev_err(&pdev->dev, "failure requesting irq %i\n", dev->irq); + goto err_iounmap; + } + + adap = &dev->adapter; + i2c_set_adapdata(adap, dev); + adap->owner = THIS_MODULE; + adap->class = I2C_CLASS_HWMON; + strlcpy(adap->name, "Synopsys DesignWare I2C adapter", + sizeof(adap->name)); + adap->algo = &i2c_dw_algo; + adap->dev.parent = &pdev->dev; + + adap->nr = pdev->id; + r = i2c_add_numbered_adapter(adap); + if (r) { + dev_err(&pdev->dev, "failure adding adapter\n"); + goto err_free_irq; + } + + return 0; + +err_free_irq: + free_irq(dev->irq, dev); +err_iounmap: + iounmap(dev->base); +err_unuse_clocks: + clk_disable(dev->clk); + clk_put(dev->clk); + dev->clk = NULL; +err_free_mem: + platform_set_drvdata(pdev, NULL); + put_device(&pdev->dev); + kfree(dev); +err_release_region: + release_mem_region(mem->start, resource_size(mem)); + + return r; +} + +static int __devexit dw_i2c_remove(struct platform_device *pdev) +{ + struct dw_i2c_dev *dev = platform_get_drvdata(pdev); + struct resource *mem; + + platform_set_drvdata(pdev, NULL); + i2c_del_adapter(&dev->adapter); + put_device(&pdev->dev); + + clk_disable(dev->clk); + clk_put(dev->clk); + dev->clk = NULL; + + writeb(0, dev->base + DW_IC_ENABLE); + free_irq(dev->irq, dev); + kfree(dev); + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(mem->start, resource_size(mem)); + return 0; +} + +/* work with hotplug and coldplug */ +MODULE_ALIAS("platform:i2c_designware"); + +static struct platform_driver dw_i2c_driver = { + .remove = __devexit_p(dw_i2c_remove), + .driver = { + .name = "i2c_designware", + .owner = THIS_MODULE, + }, +}; + +static int __init dw_i2c_init_driver(void) +{ + return platform_driver_probe(&dw_i2c_driver, dw_i2c_probe); +} +module_init(dw_i2c_init_driver); + +static void __exit dw_i2c_exit_driver(void) +{ + platform_driver_unregister(&dw_i2c_driver); +} +module_exit(dw_i2c_exit_driver); + +MODULE_AUTHOR("Baruch Siach "); +MODULE_DESCRIPTION("Synopsys DesignWare I2C bus adapter"); +MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/busses/i2c-highlander.c b/drivers/i2c/busses/i2c-highlander.c index e5a8dae4a289..87ecace415da 100644 --- a/drivers/i2c/busses/i2c-highlander.c +++ b/drivers/i2c/busses/i2c-highlander.c @@ -373,7 +373,7 @@ static int __devinit highlander_i2c_probe(struct platform_device *pdev) if (unlikely(!dev)) return -ENOMEM; - dev->base = ioremap_nocache(res->start, res->end - res->start + 1); + dev->base = ioremap_nocache(res->start, resource_size(res)); if (unlikely(!dev->base)) { ret = -ENXIO; goto err; diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c index 8b92a4666e02..e4476743f203 100644 --- a/drivers/i2c/busses/i2c-ibm_iic.c +++ b/drivers/i2c/busses/i2c-ibm_iic.c @@ -756,12 +756,12 @@ static int __devinit iic_probe(struct of_device *ofdev, goto error_cleanup; } - /* Now register all the child nodes */ - of_register_i2c_devices(adap, np); - dev_info(&ofdev->dev, "using %s mode\n", dev->fast_mode ? "fast (400 kHz)" : "standard (100 kHz)"); + /* Now register all the child nodes */ + of_register_i2c_devices(adap, np); + return 0; error_cleanup: diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index dd778d7ae047..d325e86e3103 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -197,7 +197,7 @@ int mpc_i2c_get_fdr_52xx(struct device_node *node, u32 clock, int prescaler) return -EINVAL; /* Determine divider value */ - divider = mpc52xx_find_ipb_freq(node) / clock; + divider = mpc5xxx_get_bus_frequency(node) / clock; /* * We want to choose an FDR/DFSR that generates an I2C bus speed that diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index 5a4945d1dba4..c3869d94ad42 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -469,7 +469,7 @@ mv64xxx_i2c_map_regs(struct platform_device *pd, if (!r) return -ENODEV; - size = r->end - r->start + 1; + size = resource_size(r); if (!request_mem_region(r->start, size, drv_data->adapter.name)) return -EBUSY; diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index e5193bf75483..0dabe643ec51 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -216,6 +216,7 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev) struct ocores_i2c_platform_data *pdata; struct resource *res, *res2; int ret; + int i; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) @@ -233,14 +234,14 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev) if (!i2c) return -ENOMEM; - if (!request_mem_region(res->start, res->end - res->start + 1, + if (!request_mem_region(res->start, resource_size(res), pdev->name)) { dev_err(&pdev->dev, "Memory region busy\n"); ret = -EBUSY; goto request_mem_failed; } - i2c->base = ioremap(res->start, res->end - res->start + 1); + i2c->base = ioremap(res->start, resource_size(res)); if (!i2c->base) { dev_err(&pdev->dev, "Unable to map registers\n"); ret = -EIO; @@ -271,6 +272,10 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev) goto add_adapter_failed; } + /* add in known devices to the bus */ + for (i = 0; i < pdata->num_devices; i++) + i2c_new_device(&i2c->adap, pdata->devices + i); + return 0; add_adapter_failed: @@ -278,7 +283,7 @@ add_adapter_failed: request_irq_failed: iounmap(i2c->base); map_failed: - release_mem_region(res->start, res->end - res->start + 1); + release_mem_region(res->start, resource_size(res)); request_mem_failed: kfree(i2c); @@ -306,7 +311,7 @@ static int __devexit ocores_i2c_remove(struct platform_device* pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res) - release_mem_region(res->start, res->end - res->start + 1); + release_mem_region(res->start, resource_size(res)); kfree(i2c); diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index ece0125a1ee5..ad8d2010c921 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -333,8 +333,18 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) if (cpu_is_omap2430() || cpu_is_omap34xx()) { - /* HSI2C controller internal clk rate should be 19.2 Mhz */ - internal_clk = 19200; + /* + * HSI2C controller internal clk rate should be 19.2 Mhz for + * HS and for all modes on 2430. On 34xx we can use lower rate + * to get longer filter period for better noise suppression. + * The filter is iclk (fclk for HS) period. + */ + if (dev->speed > 400 || cpu_is_omap2430()) + internal_clk = 19200; + else if (dev->speed > 100) + internal_clk = 9600; + else + internal_clk = 4000; fclk_rate = clk_get_rate(dev->fclk) / 1000; /* Compute prescaler divisor */ @@ -343,17 +353,28 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) /* If configured for High Speed */ if (dev->speed > 400) { + unsigned long scl; + /* For first phase of HS mode */ - fsscll = internal_clk / (400 * 2) - 6; - fssclh = internal_clk / (400 * 2) - 6; + scl = internal_clk / 400; + fsscll = scl - (scl / 3) - 7; + fssclh = (scl / 3) - 5; /* For second phase of HS mode */ - hsscll = fclk_rate / (dev->speed * 2) - 6; - hssclh = fclk_rate / (dev->speed * 2) - 6; + scl = fclk_rate / dev->speed; + hsscll = scl - (scl / 3) - 7; + hssclh = (scl / 3) - 5; + } else if (dev->speed > 100) { + unsigned long scl; + + /* Fast mode */ + scl = internal_clk / dev->speed; + fsscll = scl - (scl / 3) - 7; + fssclh = (scl / 3) - 5; } else { - /* To handle F/S modes */ - fsscll = internal_clk / (dev->speed * 2) - 6; - fssclh = internal_clk / (dev->speed * 2) - 6; + /* Standard mode */ + fsscll = internal_clk / (dev->speed * 2) - 7; + fssclh = internal_clk / (dev->speed * 2) - 5; } scll = (hsscll << OMAP_I2C_SCLL_HSSCLL) | fsscll; sclh = (hssclh << OMAP_I2C_SCLH_HSSCLH) | fssclh; @@ -807,7 +828,7 @@ omap_i2c_probe(struct platform_device *pdev) dev->idle = 1; dev->dev = &pdev->dev; dev->irq = irq->start; - dev->base = ioremap(mem->start, mem->end - mem->start + 1); + dev->base = ioremap(mem->start, resource_size(mem)); if (!dev->base) { r = -ENOMEM; goto err_free_mem; diff --git a/drivers/i2c/busses/i2c-pca-platform.c b/drivers/i2c/busses/i2c-pca-platform.c index 7b23891b7d59..c4df9d411cd5 100644 --- a/drivers/i2c/busses/i2c-pca-platform.c +++ b/drivers/i2c/busses/i2c-pca-platform.c @@ -27,8 +27,6 @@ #include #include -#define res_len(r) ((r)->end - (r)->start + 1) - struct i2c_pca_pf_data { void __iomem *reg_base; int irq; /* if 0, use polling */ @@ -148,7 +146,7 @@ static int __devinit i2c_pca_pf_probe(struct platform_device *pdev) goto e_print; } - if (!request_mem_region(res->start, res_len(res), res->name)) { + if (!request_mem_region(res->start, resource_size(res), res->name)) { ret = -ENOMEM; goto e_print; } @@ -161,13 +159,13 @@ static int __devinit i2c_pca_pf_probe(struct platform_device *pdev) init_waitqueue_head(&i2c->wait); - i2c->reg_base = ioremap(res->start, res_len(res)); + i2c->reg_base = ioremap(res->start, resource_size(res)); if (!i2c->reg_base) { ret = -ENOMEM; goto e_remap; } i2c->io_base = res->start; - i2c->io_size = res_len(res); + i2c->io_size = resource_size(res); i2c->irq = irq; i2c->adap.nr = pdev->id >= 0 ? pdev->id : 0; @@ -250,7 +248,7 @@ e_reqirq: e_remap: kfree(i2c); e_alloc: - release_mem_region(res->start, res_len(res)); + release_mem_region(res->start, resource_size(res)); e_print: printk(KERN_ERR "Registering PCA9564/PCA9665 FAILED! (%d)\n", ret); return ret; diff --git a/drivers/i2c/busses/i2c-pmcmsp.c b/drivers/i2c/busses/i2c-pmcmsp.c index 0bdb2d7f0570..7b57d5f267e1 100644 --- a/drivers/i2c/busses/i2c-pmcmsp.c +++ b/drivers/i2c/busses/i2c-pmcmsp.c @@ -283,7 +283,7 @@ static int __devinit pmcmsptwi_probe(struct platform_device *pldev) } /* reserve the memory region */ - if (!request_mem_region(res->start, res->end - res->start + 1, + if (!request_mem_region(res->start, resource_size(res), pldev->name)) { dev_err(&pldev->dev, "Unable to get memory/io address region 0x%08x\n", @@ -294,7 +294,7 @@ static int __devinit pmcmsptwi_probe(struct platform_device *pldev) /* remap the memory */ pmcmsptwi_data.iobase = ioremap_nocache(res->start, - res->end - res->start + 1); + resource_size(res)); if (!pmcmsptwi_data.iobase) { dev_err(&pldev->dev, "Unable to ioremap address 0x%08x\n", res->start); @@ -360,7 +360,7 @@ ret_unmap: iounmap(pmcmsptwi_data.iobase); ret_unreserve: - release_mem_region(res->start, res->end - res->start + 1); + release_mem_region(res->start, resource_size(res)); ret_err: return rc; @@ -385,7 +385,7 @@ static int __devexit pmcmsptwi_remove(struct platform_device *pldev) iounmap(pmcmsptwi_data.iobase); res = platform_get_resource(pldev, IORESOURCE_MEM, 0); - release_mem_region(res->start, res->end - res->start + 1); + release_mem_region(res->start, resource_size(res)); return 0; } diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index acc7143d9655..762e1e530882 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -34,10 +34,24 @@ #include #include -#include #include #include -#include +#include + +/* + * I2C register offsets will be shifted 0 or 1 bit left, depending on + * different SoCs + */ +#define REG_SHIFT_0 (0 << 0) +#define REG_SHIFT_1 (1 << 0) +#define REG_SHIFT(d) ((d) & 0x1) + +static const struct platform_device_id i2c_pxa_id_table[] = { + { "pxa2xx-i2c", REG_SHIFT_1 }, + { "pxa3xx-pwri2c", REG_SHIFT_0 }, + { }, +}; +MODULE_DEVICE_TABLE(platform, i2c_pxa_id_table); /* * I2C registers and bit definitions @@ -979,12 +993,12 @@ static const struct i2c_algorithm i2c_pxa_pio_algorithm = { .functionality = i2c_pxa_functionality, }; -#define res_len(r) ((r)->end - (r)->start + 1) static int i2c_pxa_probe(struct platform_device *dev) { struct pxa_i2c *i2c; struct resource *res; struct i2c_pxa_platform_data *plat = dev->dev.platform_data; + struct platform_device_id *id = platform_get_device_id(dev); int ret; int irq; @@ -993,7 +1007,7 @@ static int i2c_pxa_probe(struct platform_device *dev) if (res == NULL || irq < 0) return -ENODEV; - if (!request_mem_region(res->start, res_len(res), res->name)) + if (!request_mem_region(res->start, resource_size(res), res->name)) return -ENOMEM; i2c = kzalloc(sizeof(struct pxa_i2c), GFP_KERNEL); @@ -1023,15 +1037,15 @@ static int i2c_pxa_probe(struct platform_device *dev) goto eclk; } - i2c->reg_base = ioremap(res->start, res_len(res)); + i2c->reg_base = ioremap(res->start, resource_size(res)); if (!i2c->reg_base) { ret = -EIO; goto eremap; } - i2c->reg_shift = (cpu_is_pxa3xx() && (dev->id == 1)) ? 0 : 1; + i2c->reg_shift = REG_SHIFT(id->driver_data); i2c->iobase = res->start; - i2c->iosize = res_len(res); + i2c->iosize = resource_size(res); i2c->irq = irq; @@ -1095,7 +1109,7 @@ eremap: eclk: kfree(i2c); emalloc: - release_mem_region(res->start, res_len(res)); + release_mem_region(res->start, resource_size(res)); return ret; } @@ -1150,6 +1164,7 @@ static struct platform_driver i2c_pxa_driver = { .name = "pxa2xx-i2c", .owner = THIS_MODULE, }, + .id_table = i2c_pxa_id_table, }; static int __init i2c_adap_pxa_init(void) diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 1691ef0f1ee1..8f42a4536cdf 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -51,6 +51,11 @@ enum s3c24xx_i2c_state { STATE_STOP }; +enum s3c24xx_i2c_type { + TYPE_S3C2410, + TYPE_S3C2440, +}; + struct s3c24xx_i2c { spinlock_t lock; wait_queue_head_t wait; @@ -88,8 +93,10 @@ struct s3c24xx_i2c { static inline int s3c24xx_i2c_is2440(struct s3c24xx_i2c *i2c) { struct platform_device *pdev = to_platform_device(i2c->dev); + enum s3c24xx_i2c_type type; - return !strcmp(pdev->name, "s3c2440-i2c"); + type = platform_get_device_id(pdev)->driver_data; + return type == TYPE_S3C2440; } /* s3c24xx_i2c_master_complete @@ -821,7 +828,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) goto err_clk; } - i2c->ioarea = request_mem_region(res->start, (res->end-res->start)+1, + i2c->ioarea = request_mem_region(res->start, resource_size(res), pdev->name); if (i2c->ioarea == NULL) { @@ -830,7 +837,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) goto err_clk; } - i2c->regs = ioremap(res->start, (res->end-res->start)+1); + i2c->regs = ioremap(res->start, resource_size(res)); if (i2c->regs == NULL) { dev_err(&pdev->dev, "cannot map IO\n"); @@ -969,52 +976,41 @@ static int s3c24xx_i2c_resume(struct platform_device *dev) /* device driver for platform bus bits */ -static struct platform_driver s3c2410_i2c_driver = { - .probe = s3c24xx_i2c_probe, - .remove = s3c24xx_i2c_remove, - .suspend_late = s3c24xx_i2c_suspend_late, - .resume = s3c24xx_i2c_resume, - .driver = { - .owner = THIS_MODULE, - .name = "s3c2410-i2c", - }, +static struct platform_device_id s3c24xx_driver_ids[] = { + { + .name = "s3c2410-i2c", + .driver_data = TYPE_S3C2410, + }, { + .name = "s3c2440-i2c", + .driver_data = TYPE_S3C2440, + }, { }, }; +MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids); -static struct platform_driver s3c2440_i2c_driver = { +static struct platform_driver s3c24xx_i2c_driver = { .probe = s3c24xx_i2c_probe, .remove = s3c24xx_i2c_remove, .suspend_late = s3c24xx_i2c_suspend_late, .resume = s3c24xx_i2c_resume, + .id_table = s3c24xx_driver_ids, .driver = { .owner = THIS_MODULE, - .name = "s3c2440-i2c", + .name = "s3c-i2c", }, }; static int __init i2c_adap_s3c_init(void) { - int ret; - - ret = platform_driver_register(&s3c2410_i2c_driver); - if (ret == 0) { - ret = platform_driver_register(&s3c2440_i2c_driver); - if (ret) - platform_driver_unregister(&s3c2410_i2c_driver); - } - - return ret; + return platform_driver_register(&s3c24xx_i2c_driver); } subsys_initcall(i2c_adap_s3c_init); static void __exit i2c_adap_s3c_exit(void) { - platform_driver_unregister(&s3c2410_i2c_driver); - platform_driver_unregister(&s3c2440_i2c_driver); + platform_driver_unregister(&s3c24xx_i2c_driver); } module_exit(i2c_adap_s3c_exit); MODULE_DESCRIPTION("S3C24XX I2C Bus driver"); MODULE_AUTHOR("Ben Dooks, "); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:s3c2410-i2c"); -MODULE_ALIAS("platform:s3c2440-i2c"); diff --git a/drivers/i2c/busses/i2c-sh7760.c b/drivers/i2c/busses/i2c-sh7760.c index baa28b73ae42..b9680f50f541 100644 --- a/drivers/i2c/busses/i2c-sh7760.c +++ b/drivers/i2c/busses/i2c-sh7760.c @@ -396,7 +396,7 @@ static int __devinit calc_CCR(unsigned long scl_hz) signed char cdf, cdfm; int scgd, scgdm, scgds; - mclk = clk_get(NULL, "module_clk"); + mclk = clk_get(NULL, "peripheral_clk"); if (IS_ERR(mclk)) { return PTR_ERR(mclk); } else { diff --git a/drivers/i2c/busses/i2c-stu300.c b/drivers/i2c/busses/i2c-stu300.c new file mode 100644 index 000000000000..182e711318ba --- /dev/null +++ b/drivers/i2c/busses/i2c-stu300.c @@ -0,0 +1,1029 @@ +/* + * Copyright (C) 2007-2009 ST-Ericsson AB + * License terms: GNU General Public License (GPL) version 2 + * ST DDC I2C master mode driver, used in e.g. U300 series platforms. + * Author: Linus Walleij + * Author: Jonas Aaberg + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* the name of this kernel module */ +#define NAME "stu300" + +/* CR (Control Register) 8bit (R/W) */ +#define I2C_CR (0x00000000) +#define I2C_CR_RESET_VALUE (0x00) +#define I2C_CR_RESET_UMASK (0x00) +#define I2C_CR_DDC1_ENABLE (0x80) +#define I2C_CR_TRANS_ENABLE (0x40) +#define I2C_CR_PERIPHERAL_ENABLE (0x20) +#define I2C_CR_DDC2B_ENABLE (0x10) +#define I2C_CR_START_ENABLE (0x08) +#define I2C_CR_ACK_ENABLE (0x04) +#define I2C_CR_STOP_ENABLE (0x02) +#define I2C_CR_INTERRUPT_ENABLE (0x01) +/* SR1 (Status Register 1) 8bit (R/-) */ +#define I2C_SR1 (0x00000004) +#define I2C_SR1_RESET_VALUE (0x00) +#define I2C_SR1_RESET_UMASK (0x00) +#define I2C_SR1_EVF_IND (0x80) +#define I2C_SR1_ADD10_IND (0x40) +#define I2C_SR1_TRA_IND (0x20) +#define I2C_SR1_BUSY_IND (0x10) +#define I2C_SR1_BTF_IND (0x08) +#define I2C_SR1_ADSL_IND (0x04) +#define I2C_SR1_MSL_IND (0x02) +#define I2C_SR1_SB_IND (0x01) +/* SR2 (Status Register 2) 8bit (R/-) */ +#define I2C_SR2 (0x00000008) +#define I2C_SR2_RESET_VALUE (0x00) +#define I2C_SR2_RESET_UMASK (0x40) +#define I2C_SR2_MASK (0xBF) +#define I2C_SR2_SCLFAL_IND (0x80) +#define I2C_SR2_ENDAD_IND (0x20) +#define I2C_SR2_AF_IND (0x10) +#define I2C_SR2_STOPF_IND (0x08) +#define I2C_SR2_ARLO_IND (0x04) +#define I2C_SR2_BERR_IND (0x02) +#define I2C_SR2_DDC2BF_IND (0x01) +/* CCR (Clock Control Register) 8bit (R/W) */ +#define I2C_CCR (0x0000000C) +#define I2C_CCR_RESET_VALUE (0x00) +#define I2C_CCR_RESET_UMASK (0x00) +#define I2C_CCR_MASK (0xFF) +#define I2C_CCR_FMSM (0x80) +#define I2C_CCR_CC_MASK (0x7F) +/* OAR1 (Own Address Register 1) 8bit (R/W) */ +#define I2C_OAR1 (0x00000010) +#define I2C_OAR1_RESET_VALUE (0x00) +#define I2C_OAR1_RESET_UMASK (0x00) +#define I2C_OAR1_ADD_MASK (0xFF) +/* OAR2 (Own Address Register 2) 8bit (R/W) */ +#define I2C_OAR2 (0x00000014) +#define I2C_OAR2_RESET_VALUE (0x40) +#define I2C_OAR2_RESET_UMASK (0x19) +#define I2C_OAR2_MASK (0xE6) +#define I2C_OAR2_FR_25_10MHZ (0x00) +#define I2C_OAR2_FR_10_1667MHZ (0x20) +#define I2C_OAR2_FR_1667_2667MHZ (0x40) +#define I2C_OAR2_FR_2667_40MHZ (0x60) +#define I2C_OAR2_FR_40_5333MHZ (0x80) +#define I2C_OAR2_FR_5333_66MHZ (0xA0) +#define I2C_OAR2_FR_66_80MHZ (0xC0) +#define I2C_OAR2_FR_80_100MHZ (0xE0) +#define I2C_OAR2_FR_MASK (0xE0) +#define I2C_OAR2_ADD_MASK (0x06) +/* DR (Data Register) 8bit (R/W) */ +#define I2C_DR (0x00000018) +#define I2C_DR_RESET_VALUE (0x00) +#define I2C_DR_RESET_UMASK (0xFF) +#define I2C_DR_D_MASK (0xFF) +/* ECCR (Extended Clock Control Register) 8bit (R/W) */ +#define I2C_ECCR (0x0000001C) +#define I2C_ECCR_RESET_VALUE (0x00) +#define I2C_ECCR_RESET_UMASK (0xE0) +#define I2C_ECCR_MASK (0x1F) +#define I2C_ECCR_CC_MASK (0x1F) + +/* + * These events are more or less responses to commands + * sent into the hardware, presumably reflecting the state + * of an internal state machine. + */ +enum stu300_event { + STU300_EVENT_NONE = 0, + STU300_EVENT_1, + STU300_EVENT_2, + STU300_EVENT_3, + STU300_EVENT_4, + STU300_EVENT_5, + STU300_EVENT_6, + STU300_EVENT_7, + STU300_EVENT_8, + STU300_EVENT_9 +}; + +enum stu300_error { + STU300_ERROR_NONE = 0, + STU300_ERROR_ACKNOWLEDGE_FAILURE, + STU300_ERROR_BUS_ERROR, + STU300_ERROR_ARBITRATION_LOST +}; + +/* timeout waiting for the controller to respond */ +#define STU300_TIMEOUT (msecs_to_jiffies(1000)) + +/* + * The number of address send athemps tried before giving up. + * If the first one failes it seems like 5 to 8 attempts are required. + */ +#define NUM_ADDR_RESEND_ATTEMPTS 10 + +/* I2C clock speed, in Hz 0-400kHz*/ +static unsigned int scl_frequency = 100000; +module_param(scl_frequency, uint, 0644); + +/** + * struct stu300_dev - the stu300 driver state holder + * @pdev: parent platform device + * @adapter: corresponding I2C adapter + * @phybase: location of I/O area in memory + * @physize: size of I/O area in memory + * @clk: hardware block clock + * @irq: assigned interrupt line + * @cmd_issue_lock: this locks the following cmd_ variables + * @cmd_complete: acknowledge completion for an I2C command + * @cmd_event: expected event coming in as a response to a command + * @cmd_err: error code as response to a command + * @speed: current bus speed in Hz + * @msg_index: index of current message + * @msg_len: length of current message + */ +struct stu300_dev { + struct platform_device *pdev; + struct i2c_adapter adapter; + resource_size_t phybase; + resource_size_t physize; + void __iomem *virtbase; + struct clk *clk; + int irq; + spinlock_t cmd_issue_lock; + struct completion cmd_complete; + enum stu300_event cmd_event; + enum stu300_error cmd_err; + unsigned int speed; + int msg_index; + int msg_len; +}; + +/* Local forward function declarations */ +static int stu300_init_hw(struct stu300_dev *dev); + +/* + * The block needs writes in both MSW and LSW in order + * for all data lines to reach their destination. + */ +static inline void stu300_wr8(u32 value, void __iomem *address) +{ + writel((value << 16) | value, address); +} + +/* + * This merely masks off the duplicates which appear + * in bytes 1-3. You _MUST_ use 32-bit bus access on this + * device, else it will not work. + */ +static inline u32 stu300_r8(void __iomem *address) +{ + return readl(address) & 0x000000FFU; +} + +/* + * Tells whether a certain event or events occurred in + * response to a command. The events represent states in + * the internal state machine of the hardware. The events + * are not very well described in the hardware + * documentation and can only be treated as abstract state + * machine states. + * + * @ret 0 = event has not occurred, any other value means + * the event occurred. + */ +static int stu300_event_occurred(struct stu300_dev *dev, + enum stu300_event mr_event) { + u32 status1; + u32 status2; + + /* What event happened? */ + status1 = stu300_r8(dev->virtbase + I2C_SR1); + if (!(status1 & I2C_SR1_EVF_IND)) + /* No event at all */ + return 0; + status2 = stu300_r8(dev->virtbase + I2C_SR2); + + switch (mr_event) { + case STU300_EVENT_1: + if (status1 & I2C_SR1_ADSL_IND) + return 1; + break; + case STU300_EVENT_2: + case STU300_EVENT_3: + case STU300_EVENT_7: + case STU300_EVENT_8: + if (status1 & I2C_SR1_BTF_IND) { + if (status2 & I2C_SR2_AF_IND) + dev->cmd_err = STU300_ERROR_ACKNOWLEDGE_FAILURE; + else if (status2 & I2C_SR2_BERR_IND) + dev->cmd_err = STU300_ERROR_BUS_ERROR; + return 1; + } + break; + case STU300_EVENT_4: + if (status2 & I2C_SR2_STOPF_IND) + return 1; + break; + case STU300_EVENT_5: + if (status1 & I2C_SR1_SB_IND) + /* Clear start bit */ + return 1; + break; + case STU300_EVENT_6: + if (status2 & I2C_SR2_ENDAD_IND) { + /* First check for any errors */ + if (status2 & I2C_SR2_AF_IND) + dev->cmd_err = STU300_ERROR_ACKNOWLEDGE_FAILURE; + return 1; + } + break; + case STU300_EVENT_9: + if (status1 & I2C_SR1_ADD10_IND) + return 1; + break; + default: + break; + } + if (status2 & I2C_SR2_ARLO_IND) + dev->cmd_err = STU300_ERROR_ARBITRATION_LOST; + return 0; +} + +static irqreturn_t stu300_irh(int irq, void *data) +{ + struct stu300_dev *dev = data; + int res; + + /* See if this was what we were waiting for */ + spin_lock(&dev->cmd_issue_lock); + if (dev->cmd_event != STU300_EVENT_NONE) { + res = stu300_event_occurred(dev, dev->cmd_event); + if (res || dev->cmd_err != STU300_ERROR_NONE) { + u32 val; + + complete(&dev->cmd_complete); + /* Block any multiple interrupts */ + val = stu300_r8(dev->virtbase + I2C_CR); + val &= ~I2C_CR_INTERRUPT_ENABLE; + stu300_wr8(val, dev->virtbase + I2C_CR); + } + } + spin_unlock(&dev->cmd_issue_lock); + return IRQ_HANDLED; +} + +/* + * Sends a command and then waits for the bits masked by *flagmask* + * to go high or low by IRQ awaiting. + */ +static int stu300_start_and_await_event(struct stu300_dev *dev, + u8 cr_value, + enum stu300_event mr_event) +{ + int ret; + + if (unlikely(irqs_disabled())) { + /* TODO: implement polling for this case if need be. */ + WARN(1, "irqs are disabled, cannot poll for event\n"); + return -EIO; + } + + /* Lock command issue, fill in an event we wait for */ + spin_lock_irq(&dev->cmd_issue_lock); + init_completion(&dev->cmd_complete); + dev->cmd_err = STU300_ERROR_NONE; + dev->cmd_event = mr_event; + spin_unlock_irq(&dev->cmd_issue_lock); + + /* Turn on interrupt, send command and wait. */ + cr_value |= I2C_CR_INTERRUPT_ENABLE; + stu300_wr8(cr_value, dev->virtbase + I2C_CR); + ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete, + STU300_TIMEOUT); + + if (ret < 0) { + dev_err(&dev->pdev->dev, + "wait_for_completion_interruptible_timeout() " + "returned %d waiting for event %04x\n", ret, mr_event); + return ret; + } + + if (ret == 0) { + dev_err(&dev->pdev->dev, "controller timed out " + "waiting for event %d, reinit hardware\n", mr_event); + (void) stu300_init_hw(dev); + return -ETIMEDOUT; + } + + if (dev->cmd_err != STU300_ERROR_NONE) { + dev_err(&dev->pdev->dev, "controller (start) " + "error %d waiting for event %d, reinit hardware\n", + dev->cmd_err, mr_event); + (void) stu300_init_hw(dev); + return -EIO; + } + + return 0; +} + +/* + * This waits for a flag to be set, if it is not set on entry, an interrupt is + * configured to wait for the flag using a completion. + */ +static int stu300_await_event(struct stu300_dev *dev, + enum stu300_event mr_event) +{ + int ret; + u32 val; + + if (unlikely(irqs_disabled())) { + /* TODO: implement polling for this case if need be. */ + dev_err(&dev->pdev->dev, "irqs are disabled on this " + "system!\n"); + return -EIO; + } + + /* Is it already here? */ + spin_lock_irq(&dev->cmd_issue_lock); + dev->cmd_err = STU300_ERROR_NONE; + if (stu300_event_occurred(dev, mr_event)) { + spin_unlock_irq(&dev->cmd_issue_lock); + goto exit_await_check_err; + } + init_completion(&dev->cmd_complete); + dev->cmd_err = STU300_ERROR_NONE; + dev->cmd_event = mr_event; + + /* Turn on the I2C interrupt for current operation */ + val = stu300_r8(dev->virtbase + I2C_CR); + val |= I2C_CR_INTERRUPT_ENABLE; + stu300_wr8(val, dev->virtbase + I2C_CR); + + /* Twice paranoia (possible HW glitch) */ + stu300_wr8(val, dev->virtbase + I2C_CR); + + /* Check again: is it already here? */ + if (unlikely(stu300_event_occurred(dev, mr_event))) { + /* Disable IRQ again. */ + val &= ~I2C_CR_INTERRUPT_ENABLE; + stu300_wr8(val, dev->virtbase + I2C_CR); + spin_unlock_irq(&dev->cmd_issue_lock); + goto exit_await_check_err; + } + + /* Unlock the command block and wait for the event to occur */ + spin_unlock_irq(&dev->cmd_issue_lock); + ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete, + STU300_TIMEOUT); + + if (ret < 0) { + dev_err(&dev->pdev->dev, + "wait_for_completion_interruptible_timeout()" + "returned %d waiting for event %04x\n", ret, mr_event); + return ret; + } + + if (ret == 0) { + if (mr_event != STU300_EVENT_6) { + dev_err(&dev->pdev->dev, "controller " + "timed out waiting for event %d, reinit " + "hardware\n", mr_event); + (void) stu300_init_hw(dev); + } + return -ETIMEDOUT; + } + + exit_await_check_err: + if (dev->cmd_err != STU300_ERROR_NONE) { + if (mr_event != STU300_EVENT_6) { + dev_err(&dev->pdev->dev, "controller " + "error (await_event) %d waiting for event %d, " + "reinit hardware\n", dev->cmd_err, mr_event); + (void) stu300_init_hw(dev); + } + return -EIO; + } + + return 0; +} + +/* + * Waits for the busy bit to go low by repeated polling. + */ +#define BUSY_RELEASE_ATTEMPTS 10 +static int stu300_wait_while_busy(struct stu300_dev *dev) +{ + unsigned long timeout; + int i; + + for (i = 0; i < BUSY_RELEASE_ATTEMPTS; i++) { + timeout = jiffies + STU300_TIMEOUT; + + while (!time_after(jiffies, timeout)) { + /* Is not busy? */ + if ((stu300_r8(dev->virtbase + I2C_SR1) & + I2C_SR1_BUSY_IND) == 0) + return 0; + msleep(1); + } + + dev_err(&dev->pdev->dev, "transaction timed out " + "waiting for device to be free (not busy). " + "Attempt: %d\n", i+1); + + dev_err(&dev->pdev->dev, "base address = " + "0x%08x, reinit hardware\n", (u32) dev->virtbase); + + (void) stu300_init_hw(dev); + } + + dev_err(&dev->pdev->dev, "giving up after %d attempts " + "to reset the bus.\n", BUSY_RELEASE_ATTEMPTS); + + return -ETIMEDOUT; +} + +struct stu300_clkset { + unsigned long rate; + u32 setting; +}; + +static const struct stu300_clkset stu300_clktable[] = { + { 0, 0xFFU }, + { 2500000, I2C_OAR2_FR_25_10MHZ }, + { 10000000, I2C_OAR2_FR_10_1667MHZ }, + { 16670000, I2C_OAR2_FR_1667_2667MHZ }, + { 26670000, I2C_OAR2_FR_2667_40MHZ }, + { 40000000, I2C_OAR2_FR_40_5333MHZ }, + { 53330000, I2C_OAR2_FR_5333_66MHZ }, + { 66000000, I2C_OAR2_FR_66_80MHZ }, + { 80000000, I2C_OAR2_FR_80_100MHZ }, + { 100000000, 0xFFU }, +}; + +static int stu300_set_clk(struct stu300_dev *dev, unsigned long clkrate) +{ + + u32 val; + int i = 0; + + /* Locate the apropriate clock setting */ + while (i < ARRAY_SIZE(stu300_clktable) && + stu300_clktable[i].rate < clkrate) + i++; + + if (stu300_clktable[i].setting == 0xFFU) { + dev_err(&dev->pdev->dev, "too %s clock rate requested " + "(%lu Hz).\n", i ? "high" : "low", clkrate); + return -EINVAL; + } + + stu300_wr8(stu300_clktable[i].setting, + dev->virtbase + I2C_OAR2); + + dev_dbg(&dev->pdev->dev, "Clock rate %lu Hz, I2C bus speed %d Hz " + "virtbase %p\n", clkrate, dev->speed, dev->virtbase); + + if (dev->speed > 100000) + /* Fast Mode I2C */ + val = ((clkrate/dev->speed)-9)/3; + else + /* Standard Mode I2C */ + val = ((clkrate/dev->speed)-7)/2; + + /* According to spec the divider must be > 2 */ + if (val < 0x002) { + dev_err(&dev->pdev->dev, "too low clock rate (%lu Hz).\n", + clkrate); + return -EINVAL; + } + + /* We have 12 bits clock divider only! */ + if (val & 0xFFFFF000U) { + dev_err(&dev->pdev->dev, "too high clock rate (%lu Hz).\n", + clkrate); + return -EINVAL; + } + + if (dev->speed > 100000) { + /* CC6..CC0 */ + stu300_wr8((val & I2C_CCR_CC_MASK) | I2C_CCR_FMSM, + dev->virtbase + I2C_CCR); + dev_dbg(&dev->pdev->dev, "set clock divider to 0x%08x, " + "Fast Mode I2C\n", val); + } else { + /* CC6..CC0 */ + stu300_wr8((val & I2C_CCR_CC_MASK), + dev->virtbase + I2C_CCR); + dev_dbg(&dev->pdev->dev, "set clock divider to " + "0x%08x, Standard Mode I2C\n", val); + } + + /* CC11..CC7 */ + stu300_wr8(((val >> 7) & 0x1F), + dev->virtbase + I2C_ECCR); + + return 0; +} + + +static int stu300_init_hw(struct stu300_dev *dev) +{ + u32 dummy; + unsigned long clkrate; + int ret; + + /* Disable controller */ + stu300_wr8(0x00, dev->virtbase + I2C_CR); + /* + * Set own address to some default value (0x00). + * We do not support slave mode anyway. + */ + stu300_wr8(0x00, dev->virtbase + I2C_OAR1); + /* + * The I2C controller only operates properly in 26 MHz but we + * program this driver as if we didn't know. This will also set the two + * high bits of the own address to zero as well. + * There is no known hardware issue with running in 13 MHz + * However, speeds over 200 kHz are not used. + */ + clkrate = clk_get_rate(dev->clk); + ret = stu300_set_clk(dev, clkrate); + if (ret) + return ret; + /* + * Enable block, do it TWICE (hardware glitch) + * Setting bit 7 can enable DDC mode. (Not used currently.) + */ + stu300_wr8(I2C_CR_PERIPHERAL_ENABLE, + dev->virtbase + I2C_CR); + stu300_wr8(I2C_CR_PERIPHERAL_ENABLE, + dev->virtbase + I2C_CR); + /* Make a dummy read of the status register SR1 & SR2 */ + dummy = stu300_r8(dev->virtbase + I2C_SR2); + dummy = stu300_r8(dev->virtbase + I2C_SR1); + + return 0; +} + + + +/* Send slave address. */ +static int stu300_send_address(struct stu300_dev *dev, + struct i2c_msg *msg, int resend) +{ + u32 val; + int ret; + + if (msg->flags & I2C_M_TEN) + /* This is probably how 10 bit addresses look */ + val = (0xf0 | (((u32) msg->addr & 0x300) >> 7)) & + I2C_DR_D_MASK; + else + val = ((msg->addr << 1) & I2C_DR_D_MASK); + + if (msg->flags & I2C_M_RD) { + /* This is the direction bit */ + val |= 0x01; + if (resend) + dev_dbg(&dev->pdev->dev, "read resend\n"); + } else if (resend) + dev_dbg(&dev->pdev->dev, "write resend\n"); + stu300_wr8(val, dev->virtbase + I2C_DR); + + /* For 10bit addressing, await 10bit request (EVENT 9) */ + if (msg->flags & I2C_M_TEN) { + ret = stu300_await_event(dev, STU300_EVENT_9); + /* + * The slave device wants a 10bit address, send the rest + * of the bits (the LSBits) + */ + val = msg->addr & I2C_DR_D_MASK; + /* This clears "event 9" */ + stu300_wr8(val, dev->virtbase + I2C_DR); + if (ret != 0) + return ret; + } + /* FIXME: Why no else here? two events for 10bit? + * Await event 6 (normal) or event 9 (10bit) + */ + + if (resend) + dev_dbg(&dev->pdev->dev, "await event 6\n"); + ret = stu300_await_event(dev, STU300_EVENT_6); + + /* + * Clear any pending EVENT 6 no matter what happend during + * await_event. + */ + val = stu300_r8(dev->virtbase + I2C_CR); + val |= I2C_CR_PERIPHERAL_ENABLE; + stu300_wr8(val, dev->virtbase + I2C_CR); + + return ret; +} + +static int stu300_xfer_msg(struct i2c_adapter *adap, + struct i2c_msg *msg, int stop) +{ + u32 cr; + u32 val; + u32 i; + int ret; + int attempts = 0; + struct stu300_dev *dev = i2c_get_adapdata(adap); + + + clk_enable(dev->clk); + + /* Remove this if (0) to trace each and every message. */ + if (0) { + dev_dbg(&dev->pdev->dev, "I2C message to: 0x%04x, len: %d, " + "flags: 0x%04x, stop: %d\n", + msg->addr, msg->len, msg->flags, stop); + } + + /* Zero-length messages are not supported by this hardware */ + if (msg->len == 0) { + ret = -EINVAL; + goto exit_disable; + } + + /* + * For some reason, sending the address sometimes fails when running + * on the 13 MHz clock. No interrupt arrives. This is a work around, + * which tries to restart and send the address up to 10 times before + * really giving up. Usually 5 to 8 attempts are enough. + */ + do { + if (attempts) + dev_dbg(&dev->pdev->dev, "wait while busy\n"); + /* Check that the bus is free, or wait until some timeout */ + ret = stu300_wait_while_busy(dev); + if (ret != 0) + goto exit_disable; + + if (attempts) + dev_dbg(&dev->pdev->dev, "re-int hw\n"); + /* + * According to ST, there is no problem if the clock is + * changed between 13 and 26 MHz during a transfer. + */ + ret = stu300_init_hw(dev); + if (ret) + goto exit_disable; + + /* Send a start condition */ + cr = I2C_CR_PERIPHERAL_ENABLE; + /* Setting the START bit puts the block in master mode */ + if (!(msg->flags & I2C_M_NOSTART)) + cr |= I2C_CR_START_ENABLE; + if ((msg->flags & I2C_M_RD) && (msg->len > 1)) + /* On read more than 1 byte, we need ack. */ + cr |= I2C_CR_ACK_ENABLE; + /* Check that it gets through */ + if (!(msg->flags & I2C_M_NOSTART)) { + if (attempts) + dev_dbg(&dev->pdev->dev, "send start event\n"); + ret = stu300_start_and_await_event(dev, cr, + STU300_EVENT_5); + } + + if (attempts) + dev_dbg(&dev->pdev->dev, "send address\n"); + + if (ret == 0) + /* Send address */ + ret = stu300_send_address(dev, msg, attempts != 0); + + if (ret != 0) { + attempts++; + dev_dbg(&dev->pdev->dev, "failed sending address, " + "retrying. Attempt: %d msg_index: %d/%d\n", + attempts, dev->msg_index, dev->msg_len); + } + + } while (ret != 0 && attempts < NUM_ADDR_RESEND_ATTEMPTS); + + if (attempts < NUM_ADDR_RESEND_ATTEMPTS && attempts > 0) { + dev_dbg(&dev->pdev->dev, "managed to get address " + "through after %d attempts\n", attempts); + } else if (attempts == NUM_ADDR_RESEND_ATTEMPTS) { + dev_dbg(&dev->pdev->dev, "I give up, tried %d times " + "to resend address.\n", + NUM_ADDR_RESEND_ATTEMPTS); + goto exit_disable; + } + + if (msg->flags & I2C_M_RD) { + /* READ: we read the actual bytes one at a time */ + for (i = 0; i < msg->len; i++) { + if (i == msg->len-1) { + /* + * Disable ACK and set STOP condition before + * reading last byte + */ + val = I2C_CR_PERIPHERAL_ENABLE; + + if (stop) + val |= I2C_CR_STOP_ENABLE; + + stu300_wr8(val, + dev->virtbase + I2C_CR); + } + /* Wait for this byte... */ + ret = stu300_await_event(dev, STU300_EVENT_7); + if (ret != 0) + goto exit_disable; + /* This clears event 7 */ + msg->buf[i] = (u8) stu300_r8(dev->virtbase + I2C_DR); + } + } else { + /* WRITE: we send the actual bytes one at a time */ + for (i = 0; i < msg->len; i++) { + /* Write the byte */ + stu300_wr8(msg->buf[i], + dev->virtbase + I2C_DR); + /* Check status */ + ret = stu300_await_event(dev, STU300_EVENT_8); + /* Next write to DR will clear event 8 */ + if (ret != 0) { + dev_err(&dev->pdev->dev, "error awaiting " + "event 8 (%d)\n", ret); + goto exit_disable; + } + } + /* Check NAK */ + if (!(msg->flags & I2C_M_IGNORE_NAK)) { + if (stu300_r8(dev->virtbase + I2C_SR2) & + I2C_SR2_AF_IND) { + dev_err(&dev->pdev->dev, "I2C payload " + "send returned NAK!\n"); + ret = -EIO; + goto exit_disable; + } + } + if (stop) { + /* Send stop condition */ + val = I2C_CR_PERIPHERAL_ENABLE; + val |= I2C_CR_STOP_ENABLE; + stu300_wr8(val, dev->virtbase + I2C_CR); + } + } + + /* Check that the bus is free, or wait until some timeout occurs */ + ret = stu300_wait_while_busy(dev); + if (ret != 0) { + dev_err(&dev->pdev->dev, "timout waiting for transfer " + "to commence.\n"); + goto exit_disable; + } + + /* Dummy read status registers */ + val = stu300_r8(dev->virtbase + I2C_SR2); + val = stu300_r8(dev->virtbase + I2C_SR1); + ret = 0; + + exit_disable: + /* Disable controller */ + stu300_wr8(0x00, dev->virtbase + I2C_CR); + clk_disable(dev->clk); + return ret; +} + +static int stu300_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, + int num) +{ + int ret = -1; + int i; + struct stu300_dev *dev = i2c_get_adapdata(adap); + dev->msg_len = num; + for (i = 0; i < num; i++) { + /* + * Another driver appears to send stop for each message, + * here we only do that for the last message. Possibly some + * peripherals require this behaviour, then their drivers + * have to send single messages in order to get "stop" for + * each message. + */ + dev->msg_index = i; + + ret = stu300_xfer_msg(adap, &msgs[i], (i == (num - 1))); + if (ret != 0) { + num = ret; + break; + } + } + + return num; +} + +static u32 stu300_func(struct i2c_adapter *adap) +{ + /* This is the simplest thing you can think of... */ + return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR; +} + +static const struct i2c_algorithm stu300_algo = { + .master_xfer = stu300_xfer, + .functionality = stu300_func, +}; + +static int __init +stu300_probe(struct platform_device *pdev) +{ + struct stu300_dev *dev; + struct i2c_adapter *adap; + struct resource *res; + int bus_nr; + int ret = 0; + + dev = kzalloc(sizeof(struct stu300_dev), GFP_KERNEL); + if (!dev) { + dev_err(&pdev->dev, "could not allocate device struct\n"); + ret = -ENOMEM; + goto err_no_devmem; + } + + bus_nr = pdev->id; + dev->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(dev->clk)) { + ret = PTR_ERR(dev->clk); + dev_err(&pdev->dev, "could not retrieve i2c bus clock\n"); + goto err_no_clk; + } + + dev->pdev = pdev; + platform_set_drvdata(pdev, dev); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + ret = -ENOENT; + goto err_no_resource; + } + + dev->phybase = res->start; + dev->physize = resource_size(res); + + if (request_mem_region(dev->phybase, dev->physize, + NAME " I/O Area") == NULL) { + ret = -EBUSY; + goto err_no_ioregion; + } + + dev->virtbase = ioremap(dev->phybase, dev->physize); + dev_dbg(&pdev->dev, "initialize bus device I2C%d on virtual " + "base %p\n", bus_nr, dev->virtbase); + if (!dev->virtbase) { + ret = -ENOMEM; + goto err_no_ioremap; + } + + dev->irq = platform_get_irq(pdev, 0); + if (request_irq(dev->irq, stu300_irh, IRQF_DISABLED, + NAME, dev)) { + ret = -EIO; + goto err_no_irq; + } + + dev->speed = scl_frequency; + + clk_enable(dev->clk); + ret = stu300_init_hw(dev); + clk_disable(dev->clk); + + if (ret != 0) { + dev_err(&dev->pdev->dev, "error initializing hardware.\n"); + goto err_init_hw; + } + + /* IRQ event handling initialization */ + spin_lock_init(&dev->cmd_issue_lock); + dev->cmd_event = STU300_EVENT_NONE; + dev->cmd_err = STU300_ERROR_NONE; + + adap = &dev->adapter; + adap->owner = THIS_MODULE; + /* DDC class but actually often used for more generic I2C */ + adap->class = I2C_CLASS_DDC; + strncpy(adap->name, "ST Microelectronics DDC I2C adapter", + sizeof(adap->name)); + adap->nr = bus_nr; + adap->algo = &stu300_algo; + adap->dev.parent = &pdev->dev; + i2c_set_adapdata(adap, dev); + + /* i2c device drivers may be active on return from add_adapter() */ + ret = i2c_add_numbered_adapter(adap); + if (ret) { + dev_err(&dev->pdev->dev, "failure adding ST Micro DDC " + "I2C adapter\n"); + goto err_add_adapter; + } + return 0; + + err_add_adapter: + err_init_hw: + free_irq(dev->irq, dev); + err_no_irq: + iounmap(dev->virtbase); + err_no_ioremap: + release_mem_region(dev->phybase, dev->physize); + err_no_ioregion: + platform_set_drvdata(pdev, NULL); + err_no_resource: + clk_put(dev->clk); + err_no_clk: + kfree(dev); + err_no_devmem: + dev_err(&pdev->dev, "failed to add " NAME " adapter: %d\n", + pdev->id); + return ret; +} + +#ifdef CONFIG_PM +static int stu300_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct stu300_dev *dev = platform_get_drvdata(pdev); + + /* Turn off everything */ + stu300_wr8(0x00, dev->virtbase + I2C_CR); + return 0; +} + +static int stu300_resume(struct platform_device *pdev) +{ + int ret = 0; + struct stu300_dev *dev = platform_get_drvdata(pdev); + + clk_enable(dev->clk); + ret = stu300_init_hw(dev); + clk_disable(dev->clk); + + if (ret != 0) + dev_err(&pdev->dev, "error re-initializing hardware.\n"); + return ret; +} +#else +#define stu300_suspend NULL +#define stu300_resume NULL +#endif + +static int __exit +stu300_remove(struct platform_device *pdev) +{ + struct stu300_dev *dev = platform_get_drvdata(pdev); + + i2c_del_adapter(&dev->adapter); + /* Turn off everything */ + stu300_wr8(0x00, dev->virtbase + I2C_CR); + free_irq(dev->irq, dev); + iounmap(dev->virtbase); + release_mem_region(dev->phybase, dev->physize); + clk_put(dev->clk); + platform_set_drvdata(pdev, NULL); + kfree(dev); + return 0; +} + +static struct platform_driver stu300_i2c_driver = { + .driver = { + .name = NAME, + .owner = THIS_MODULE, + }, + .remove = __exit_p(stu300_remove), + .suspend = stu300_suspend, + .resume = stu300_resume, + +}; + +static int __init stu300_init(void) +{ + return platform_driver_probe(&stu300_i2c_driver, stu300_probe); +} + +static void __exit stu300_exit(void) +{ + platform_driver_unregister(&stu300_i2c_driver); +} + +/* + * The systems using this bus often have very basic devices such + * as regulators on the I2C bus, so this needs to be loaded early. + * Therefore it is registered in the subsys_initcall(). + */ +subsys_initcall(stu300_init); +module_exit(stu300_exit); + +MODULE_AUTHOR("Linus Walleij "); +MODULE_DESCRIPTION("ST Micro DDC I2C adapter (" NAME ")"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" NAME); diff --git a/drivers/i2c/busses/i2c-versatile.c b/drivers/i2c/busses/i2c-versatile.c index fede619ba227..70de82163463 100644 --- a/drivers/i2c/busses/i2c-versatile.c +++ b/drivers/i2c/busses/i2c-versatile.c @@ -76,7 +76,7 @@ static int i2c_versatile_probe(struct platform_device *dev) goto err_out; } - if (!request_mem_region(r->start, r->end - r->start + 1, "versatile-i2c")) { + if (!request_mem_region(r->start, resource_size(r), "versatile-i2c")) { ret = -EBUSY; goto err_out; } @@ -87,7 +87,7 @@ static int i2c_versatile_probe(struct platform_device *dev) goto err_release; } - i2c->base = ioremap(r->start, r->end - r->start + 1); + i2c->base = ioremap(r->start, resource_size(r)); if (!i2c->base) { ret = -ENOMEM; goto err_free; @@ -118,7 +118,7 @@ static int i2c_versatile_probe(struct platform_device *dev) err_free: kfree(i2c); err_release: - release_mem_region(r->start, r->end - r->start + 1); + release_mem_region(r->start, resource_size(r)); err_out: return ret; } diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c index 02e6f724b05f..54d810a4d00f 100644 --- a/drivers/i2c/busses/i2c-viapro.c +++ b/drivers/i2c/busses/i2c-viapro.c @@ -37,6 +37,7 @@ VT8251 0x3287 yes CX700 0x8324 yes VX800/VX820 0x8353 yes + VX855/VX875 0x8409 yes Note: we assume there can only be one device, with one SMBus interface. */ @@ -404,6 +405,7 @@ found: switch (pdev->device) { case PCI_DEVICE_ID_VIA_CX700: case PCI_DEVICE_ID_VIA_VX800: + case PCI_DEVICE_ID_VIA_VX855: case PCI_DEVICE_ID_VIA_8251: case PCI_DEVICE_ID_VIA_8237: case PCI_DEVICE_ID_VIA_8237A: @@ -469,6 +471,8 @@ static struct pci_device_id vt596_ids[] = { .driver_data = SMBBA3 }, { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX800), .driver_data = SMBBA3 }, + { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX855), + .driver_data = SMBBA3 }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-voodoo3.c b/drivers/i2c/busses/i2c-voodoo3.c index 1a474acc0ddd..7663d57833a0 100644 --- a/drivers/i2c/busses/i2c-voodoo3.c +++ b/drivers/i2c/busses/i2c-voodoo3.c @@ -163,7 +163,6 @@ static struct i2c_algo_bit_data voo_i2c_bit_data = { static struct i2c_adapter voodoo3_i2c_adapter = { .owner = THIS_MODULE, - .class = I2C_CLASS_TV_ANALOG, .name = "I2C Voodoo3/Banshee adapter", .algo_data = &voo_i2c_bit_data, }; diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig index 8f8c81eb0aee..02d746c9c474 100644 --- a/drivers/i2c/chips/Kconfig +++ b/drivers/i2c/chips/Kconfig @@ -64,21 +64,6 @@ config SENSORS_PCA9539 This driver is deprecated and will be dropped soon. Use drivers/gpio/pca953x.c instead. -config SENSORS_MAX6875 - tristate "Maxim MAX6875 Power supply supervisor" - depends on EXPERIMENTAL - help - If you say yes here you get support for the Maxim MAX6875 - EEPROM-programmable, quad power-supply sequencer/supervisor. - - This provides an interface to program the EEPROM and reset the chip. - - This driver also supports the Maxim MAX6874 hex power-supply - sequencer/supervisor if found at a compatible address. - - This driver can also be built as a module. If so, the module - will be called max6875. - config SENSORS_TSL2550 tristate "Taos TSL2550 ambient light sensor" depends on EXPERIMENTAL diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile index 55a376037183..f4680d16ee34 100644 --- a/drivers/i2c/chips/Makefile +++ b/drivers/i2c/chips/Makefile @@ -11,7 +11,6 @@ # obj-$(CONFIG_DS1682) += ds1682.o -obj-$(CONFIG_SENSORS_MAX6875) += max6875.o obj-$(CONFIG_SENSORS_PCA9539) += pca9539.o obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o obj-$(CONFIG_PCF8575) += pcf8575.o diff --git a/drivers/i2c/i2c-boardinfo.c b/drivers/i2c/i2c-boardinfo.c index ffb35f09df03..a26a34a06641 100644 --- a/drivers/i2c/i2c-boardinfo.c +++ b/drivers/i2c/i2c-boardinfo.c @@ -18,6 +18,7 @@ #include #include +#include #include "i2c-core.h" @@ -25,7 +26,7 @@ /* These symbols are exported ONLY FOR the i2c core. * No other users will be supported. */ -DEFINE_MUTEX(__i2c_board_lock); +DECLARE_RWSEM(__i2c_board_lock); EXPORT_SYMBOL_GPL(__i2c_board_lock); LIST_HEAD(__i2c_board_list); @@ -63,7 +64,7 @@ i2c_register_board_info(int busnum, { int status; - mutex_lock(&__i2c_board_lock); + down_write(&__i2c_board_lock); /* dynamic bus numbers will be assigned after the last static one */ if (busnum >= __i2c_first_dynamic_bus_num) @@ -84,7 +85,7 @@ i2c_register_board_info(int busnum, list_add_tail(&devinfo->list, &__i2c_board_list); } - mutex_unlock(&__i2c_board_lock); + up_write(&__i2c_board_lock); return status; } diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 85e2e919d1cd..0e45c296d3d2 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -29,21 +29,24 @@ #include #include #include -#include #include #include #include #include +#include #include #include "i2c-core.h" +/* core_lock protects i2c_adapter_idr, userspace_devices, and guarantees + that device detection, deletion of detected devices, and attach_adapter + and detach_adapter calls are serialized */ static DEFINE_MUTEX(core_lock); static DEFINE_IDR(i2c_adapter_idr); +static LIST_HEAD(userspace_devices); -#define is_newstyle_driver(d) ((d)->probe || (d)->remove || (d)->detect) - +static int i2c_check_addr(struct i2c_adapter *adapter, int addr); static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver); /* ------------------------------------------------------------------------- */ @@ -64,12 +67,6 @@ static int i2c_device_match(struct device *dev, struct device_driver *drv) struct i2c_client *client = to_i2c_client(dev); struct i2c_driver *driver = to_i2c_driver(drv); - /* make legacy i2c drivers bypass driver model probing entirely; - * such drivers scan each i2c adapter/bus themselves. - */ - if (!is_newstyle_driver(driver)) - return 0; - /* match on an id table if there is one */ if (driver->id_table) return i2c_match_id(driver->id_table, client) != NULL; @@ -84,10 +81,6 @@ static int i2c_device_uevent(struct device *dev, struct kobj_uevent_env *env) { struct i2c_client *client = to_i2c_client(dev); - /* by definition, legacy drivers can't hotplug */ - if (dev->driver) - return 0; - if (add_uevent_var(env, "MODALIAS=%s%s", I2C_MODULE_PREFIX, client->name)) return -ENOMEM; @@ -176,12 +169,6 @@ static int i2c_device_resume(struct device *dev) return driver->resume(to_i2c_client(dev)); } -static void i2c_client_release(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - complete(&client->released); -} - static void i2c_client_dev_release(struct device *dev) { kfree(to_i2c_client(dev)); @@ -241,15 +228,17 @@ EXPORT_SYMBOL(i2c_verify_client); /** - * i2c_new_device - instantiate an i2c device for use with a new style driver + * i2c_new_device - instantiate an i2c device * @adap: the adapter managing the device * @info: describes one I2C device; bus_num is ignored * Context: can sleep * - * Create a device to work with a new style i2c driver, where binding is - * handled through driver model probe()/remove() methods. This call is not - * appropriate for use by mainboad initialization logic, which usually runs - * during an arch_initcall() long before any i2c_adapter could exist. + * Create an i2c device. Binding is handled through driver model + * probe()/remove() methods. A driver may be bound to this device when we + * return from this function, or any later moment (e.g. maybe hotplugging will + * load the driver module). This call is not appropriate for use by mainboard + * initialization logic, which usually runs during an arch_initcall() long + * before any i2c_adapter could exist. * * This returns the new i2c client, which may be saved for later use with * i2c_unregister_device(); or NULL to indicate an error. @@ -277,17 +266,31 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) strlcpy(client->name, info->type, sizeof(client->name)); - /* a new style driver may be bound to this device when we - * return from this function, or any later moment (e.g. maybe - * hotplugging will load the driver module). and the device - * refcount model is the standard driver model one. - */ - status = i2c_attach_client(client); - if (status < 0) { - kfree(client); - client = NULL; - } + /* Check for address business */ + status = i2c_check_addr(adap, client->addr); + if (status) + goto out_err; + + client->dev.parent = &client->adapter->dev; + client->dev.bus = &i2c_bus_type; + client->dev.release = i2c_client_dev_release; + + dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap), + client->addr); + status = device_register(&client->dev); + if (status) + goto out_err; + + dev_dbg(&adap->dev, "client [%s] registered with bus id %s\n", + client->name, dev_name(&client->dev)); + return client; + +out_err: + dev_err(&adap->dev, "Failed to register i2c client %s at 0x%02x " + "(%d)\n", client->name, client->addr, status); + kfree(client); + return NULL; } EXPORT_SYMBOL_GPL(i2c_new_device); @@ -299,28 +302,6 @@ EXPORT_SYMBOL_GPL(i2c_new_device); */ void i2c_unregister_device(struct i2c_client *client) { - struct i2c_adapter *adapter = client->adapter; - struct i2c_driver *driver = client->driver; - - if (driver && !is_newstyle_driver(driver)) { - dev_err(&client->dev, "can't unregister devices " - "with legacy drivers\n"); - WARN_ON(1); - return; - } - - if (adapter->client_unregister) { - if (adapter->client_unregister(client)) { - dev_warn(&client->dev, - "client_unregister [%s] failed\n", - client->name); - } - } - - mutex_lock(&adapter->clist_lock); - list_del(&client->list); - mutex_unlock(&adapter->clist_lock); - device_unregister(&client->dev); } EXPORT_SYMBOL_GPL(i2c_unregister_device); @@ -394,8 +375,128 @@ show_adapter_name(struct device *dev, struct device_attribute *attr, char *buf) return sprintf(buf, "%s\n", adap->name); } +/* + * Let users instantiate I2C devices through sysfs. This can be used when + * platform initialization code doesn't contain the proper data for + * whatever reason. Also useful for drivers that do device detection and + * detection fails, either because the device uses an unexpected address, + * or this is a compatible device with different ID register values. + * + * Parameter checking may look overzealous, but we really don't want + * the user to provide incorrect parameters. + */ +static ssize_t +i2c_sysfs_new_device(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_adapter *adap = to_i2c_adapter(dev); + struct i2c_board_info info; + struct i2c_client *client; + char *blank, end; + int res; + + dev_warn(dev, "The new_device interface is still experimental " + "and may change in a near future\n"); + memset(&info, 0, sizeof(struct i2c_board_info)); + + blank = strchr(buf, ' '); + if (!blank) { + dev_err(dev, "%s: Missing parameters\n", "new_device"); + return -EINVAL; + } + if (blank - buf > I2C_NAME_SIZE - 1) { + dev_err(dev, "%s: Invalid device name\n", "new_device"); + return -EINVAL; + } + memcpy(info.type, buf, blank - buf); + + /* Parse remaining parameters, reject extra parameters */ + res = sscanf(++blank, "%hi%c", &info.addr, &end); + if (res < 1) { + dev_err(dev, "%s: Can't parse I2C address\n", "new_device"); + return -EINVAL; + } + if (res > 1 && end != '\n') { + dev_err(dev, "%s: Extra parameters\n", "new_device"); + return -EINVAL; + } + + if (info.addr < 0x03 || info.addr > 0x77) { + dev_err(dev, "%s: Invalid I2C address 0x%hx\n", "new_device", + info.addr); + return -EINVAL; + } + + client = i2c_new_device(adap, &info); + if (!client) + return -EEXIST; + + /* Keep track of the added device */ + mutex_lock(&core_lock); + list_add_tail(&client->detected, &userspace_devices); + mutex_unlock(&core_lock); + dev_info(dev, "%s: Instantiated device %s at 0x%02hx\n", "new_device", + info.type, info.addr); + + return count; +} + +/* + * And of course let the users delete the devices they instantiated, if + * they got it wrong. This interface can only be used to delete devices + * instantiated by i2c_sysfs_new_device above. This guarantees that we + * don't delete devices to which some kernel code still has references. + * + * Parameter checking may look overzealous, but we really don't want + * the user to delete the wrong device. + */ +static ssize_t +i2c_sysfs_delete_device(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_adapter *adap = to_i2c_adapter(dev); + struct i2c_client *client, *next; + unsigned short addr; + char end; + int res; + + /* Parse parameters, reject extra parameters */ + res = sscanf(buf, "%hi%c", &addr, &end); + if (res < 1) { + dev_err(dev, "%s: Can't parse I2C address\n", "delete_device"); + return -EINVAL; + } + if (res > 1 && end != '\n') { + dev_err(dev, "%s: Extra parameters\n", "delete_device"); + return -EINVAL; + } + + /* Make sure the device was added through sysfs */ + res = -ENOENT; + mutex_lock(&core_lock); + list_for_each_entry_safe(client, next, &userspace_devices, detected) { + if (client->addr == addr && client->adapter == adap) { + dev_info(dev, "%s: Deleting device %s at 0x%02hx\n", + "delete_device", client->name, client->addr); + + list_del(&client->detected); + i2c_unregister_device(client); + res = count; + break; + } + } + mutex_unlock(&core_lock); + + if (res < 0) + dev_err(dev, "%s: Can't find device in list\n", + "delete_device"); + return res; +} + static struct device_attribute i2c_adapter_attrs[] = { __ATTR(name, S_IRUGO, show_adapter_name, NULL), + __ATTR(new_device, S_IWUSR, NULL, i2c_sysfs_new_device), + __ATTR(delete_device, S_IWUSR, NULL, i2c_sysfs_delete_device), { }, }; @@ -409,7 +510,7 @@ static void i2c_scan_static_board_info(struct i2c_adapter *adapter) { struct i2c_devinfo *devinfo; - mutex_lock(&__i2c_board_lock); + down_read(&__i2c_board_lock); list_for_each_entry(devinfo, &__i2c_board_list, list) { if (devinfo->busnum == adapter->nr && !i2c_new_device(adapter, @@ -418,7 +519,7 @@ static void i2c_scan_static_board_info(struct i2c_adapter *adapter) "Can't create device at 0x%02x\n", devinfo->board_info.addr); } - mutex_unlock(&__i2c_board_lock); + up_read(&__i2c_board_lock); } static int i2c_do_add_adapter(struct device_driver *d, void *data) @@ -442,24 +543,12 @@ static int i2c_register_adapter(struct i2c_adapter *adap) int res = 0, dummy; /* Can't register until after driver model init */ - if (unlikely(WARN_ON(!i2c_bus_type.p))) - return -EAGAIN; + if (unlikely(WARN_ON(!i2c_bus_type.p))) { + res = -EAGAIN; + goto out_list; + } mutex_init(&adap->bus_lock); - mutex_init(&adap->clist_lock); - INIT_LIST_HEAD(&adap->clients); - - mutex_lock(&core_lock); - - /* Add the adapter to the driver core. - * If the parent pointer is not set up, - * we add this adapter to the host bus. - */ - if (adap->dev.parent == NULL) { - adap->dev.parent = &platform_bus; - pr_debug("I2C adapter driver [%s] forgot to specify " - "physical device\n", adap->name); - } /* Set default timeout to 1 second if not already set */ if (adap->timeout == 0) @@ -474,21 +563,23 @@ static int i2c_register_adapter(struct i2c_adapter *adap) dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name); - /* create pre-declared device nodes for new-style drivers */ + /* create pre-declared device nodes */ if (adap->nr < __i2c_first_dynamic_bus_num) i2c_scan_static_board_info(adap); /* Notify drivers */ + mutex_lock(&core_lock); dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap, i2c_do_add_adapter); - -out_unlock: mutex_unlock(&core_lock); - return res; + + return 0; out_list: + mutex_lock(&core_lock); idr_remove(&i2c_adapter_idr, adap->nr); - goto out_unlock; + mutex_unlock(&core_lock); + return res; } /** @@ -607,6 +698,14 @@ static int i2c_do_del_adapter(struct device_driver *d, void *data) return res; } +static int __unregister_client(struct device *dev, void *dummy) +{ + struct i2c_client *client = i2c_verify_client(dev); + if (client) + i2c_unregister_device(client); + return 0; +} + /** * i2c_del_adapter - unregister I2C adapter * @adap: the adapter being unregistered @@ -617,46 +716,30 @@ static int i2c_do_del_adapter(struct device_driver *d, void *data) */ int i2c_del_adapter(struct i2c_adapter *adap) { - struct i2c_client *client, *_n; int res = 0; - - mutex_lock(&core_lock); + struct i2c_adapter *found; /* First make sure that this adapter was ever added */ - if (idr_find(&i2c_adapter_idr, adap->nr) != adap) { + mutex_lock(&core_lock); + found = idr_find(&i2c_adapter_idr, adap->nr); + mutex_unlock(&core_lock); + if (found != adap) { pr_debug("i2c-core: attempting to delete unregistered " "adapter [%s]\n", adap->name); - res = -EINVAL; - goto out_unlock; + return -EINVAL; } /* Tell drivers about this removal */ + mutex_lock(&core_lock); res = bus_for_each_drv(&i2c_bus_type, NULL, adap, i2c_do_del_adapter); + mutex_unlock(&core_lock); if (res) - goto out_unlock; + return res; - /* detach any active clients. This must be done first, because - * it can fail; in which case we give up. */ - list_for_each_entry_safe_reverse(client, _n, &adap->clients, list) { - struct i2c_driver *driver; - - driver = client->driver; - - /* new style, follow standard driver model */ - if (!driver || is_newstyle_driver(driver)) { - i2c_unregister_device(client); - continue; - } - - /* legacy drivers create and remove clients themselves */ - if ((res = driver->detach_client(client))) { - dev_err(&adap->dev, "detach_client failed for client " - "[%s] at address 0x%02x\n", client->name, - client->addr); - goto out_unlock; - } - } + /* Detach any active clients. This can't fail, thus we do not + checking the returned value. */ + res = device_for_each_child(&adap->dev, NULL, __unregister_client); /* clean up the sysfs representation */ init_completion(&adap->dev_released); @@ -666,7 +749,9 @@ int i2c_del_adapter(struct i2c_adapter *adap) wait_for_completion(&adap->dev_released); /* free bus id */ + mutex_lock(&core_lock); idr_remove(&i2c_adapter_idr, adap->nr); + mutex_unlock(&core_lock); dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name); @@ -674,9 +759,7 @@ int i2c_del_adapter(struct i2c_adapter *adap) added again */ memset(&adap->dev, 0, sizeof(adap->dev)); - out_unlock: - mutex_unlock(&core_lock); - return res; + return 0; } EXPORT_SYMBOL(i2c_del_adapter); @@ -699,11 +782,7 @@ static int __attach_adapter(struct device *dev, void *data) /* * An i2c_driver is used with one or more i2c_client (device) nodes to access - * i2c slave chips, on a bus instance associated with some i2c_adapter. There - * are two models for binding the driver to its device: "new style" drivers - * follow the standard Linux driver model and just respond to probe() calls - * issued if the driver core sees they match(); "legacy" drivers create device - * nodes themselves. + * i2c slave chips, on a bus instance associated with some i2c_adapter. */ int i2c_register_driver(struct module *owner, struct i2c_driver *driver) @@ -714,37 +793,26 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver) if (unlikely(WARN_ON(!i2c_bus_type.p))) return -EAGAIN; - /* new style driver methods can't mix with legacy ones */ - if (is_newstyle_driver(driver)) { - if (driver->detach_adapter || driver->detach_client) { - printk(KERN_WARNING - "i2c-core: driver [%s] is confused\n", - driver->driver.name); - return -EINVAL; - } - } - /* add the driver to the list of i2c drivers in the driver core */ driver->driver.owner = owner; driver->driver.bus = &i2c_bus_type; - /* for new style drivers, when registration returns the driver core + /* When registration returns, the driver core * will have called probe() for all matching-but-unbound devices. */ res = driver_register(&driver->driver); if (res) return res; - mutex_lock(&core_lock); - pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name); INIT_LIST_HEAD(&driver->clients); /* Walk the adapters that are already present */ + mutex_lock(&core_lock); class_for_each_device(&i2c_adapter_class, NULL, driver, __attach_adapter); - mutex_unlock(&core_lock); + return 0; } EXPORT_SYMBOL(i2c_register_driver); @@ -764,32 +832,11 @@ static int __detach_adapter(struct device *dev, void *data) i2c_unregister_device(client); } - if (is_newstyle_driver(driver)) - return 0; - - /* Have a look at each adapter, if clients of this driver are still - * attached. If so, detach them to be able to kill the driver - * afterwards. - */ if (driver->detach_adapter) { if (driver->detach_adapter(adapter)) dev_err(&adapter->dev, "detach_adapter failed for driver [%s]\n", driver->driver.name); - } else { - struct i2c_client *client, *_n; - - list_for_each_entry_safe(client, _n, &adapter->clients, list) { - if (client->driver != driver) - continue; - dev_dbg(&adapter->dev, - "detaching client [%s] at 0x%02x\n", - client->name, client->addr); - if (driver->detach_client(client)) - dev_err(&adapter->dev, "detach_client " - "failed for client [%s] at 0x%02x\n", - client->name, client->addr); - } } return 0; @@ -803,14 +850,12 @@ static int __detach_adapter(struct device *dev, void *data) void i2c_del_driver(struct i2c_driver *driver) { mutex_lock(&core_lock); - class_for_each_device(&i2c_adapter_class, NULL, driver, __detach_adapter); + mutex_unlock(&core_lock); driver_unregister(&driver->driver); pr_debug("i2c-core: driver [%s] unregistered\n", driver->driver.name); - - mutex_unlock(&core_lock); } EXPORT_SYMBOL(i2c_del_driver); @@ -831,86 +876,6 @@ static int i2c_check_addr(struct i2c_adapter *adapter, int addr) return device_for_each_child(&adapter->dev, &addr, __i2c_check_addr); } -int i2c_attach_client(struct i2c_client *client) -{ - struct i2c_adapter *adapter = client->adapter; - int res; - - /* Check for address business */ - res = i2c_check_addr(adapter, client->addr); - if (res) - return res; - - client->dev.parent = &client->adapter->dev; - client->dev.bus = &i2c_bus_type; - - if (client->driver) - client->dev.driver = &client->driver->driver; - - if (client->driver && !is_newstyle_driver(client->driver)) { - client->dev.release = i2c_client_release; - dev_set_uevent_suppress(&client->dev, 1); - } else - client->dev.release = i2c_client_dev_release; - - dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adapter), - client->addr); - res = device_register(&client->dev); - if (res) - goto out_err; - - mutex_lock(&adapter->clist_lock); - list_add_tail(&client->list, &adapter->clients); - mutex_unlock(&adapter->clist_lock); - - dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n", - client->name, dev_name(&client->dev)); - - if (adapter->client_register) { - if (adapter->client_register(client)) { - dev_dbg(&adapter->dev, "client_register " - "failed for client [%s] at 0x%02x\n", - client->name, client->addr); - } - } - - return 0; - -out_err: - dev_err(&adapter->dev, "Failed to attach i2c client %s at 0x%02x " - "(%d)\n", client->name, client->addr, res); - return res; -} -EXPORT_SYMBOL(i2c_attach_client); - -int i2c_detach_client(struct i2c_client *client) -{ - struct i2c_adapter *adapter = client->adapter; - int res = 0; - - if (adapter->client_unregister) { - res = adapter->client_unregister(client); - if (res) { - dev_err(&client->dev, - "client_unregister [%s] failed, " - "client not detached\n", client->name); - goto out; - } - } - - mutex_lock(&adapter->clist_lock); - list_del(&client->list); - mutex_unlock(&adapter->clist_lock); - - init_completion(&client->released); - device_unregister(&client->dev); - wait_for_completion(&client->released); - - out: - return res; -} -EXPORT_SYMBOL(i2c_detach_client); - /** * i2c_use_client - increments the reference count of the i2c client structure * @client: the client being referenced @@ -1022,7 +987,8 @@ module_exit(i2c_exit); */ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { - int ret; + unsigned long orig_jiffies; + int ret, try; /* REVISIT the fault reporting model here is weak: * @@ -1060,7 +1026,15 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) mutex_lock_nested(&adap->bus_lock, adap->level); } - ret = adap->algo->master_xfer(adap,msgs,num); + /* Retry automatically on arbitration loss */ + orig_jiffies = jiffies; + for (ret = 0, try = 0; try <= adap->retries; try++) { + ret = adap->algo->master_xfer(adap, msgs, num); + if (ret != -EAGAIN) + break; + if (time_after(jiffies, orig_jiffies + adap->timeout)) + break; + } mutex_unlock(&adap->bus_lock); return ret; @@ -1131,144 +1105,7 @@ EXPORT_SYMBOL(i2c_master_recv); * Will not work for 10-bit addresses! * ---------------------------------------------------- */ -static int i2c_probe_address(struct i2c_adapter *adapter, int addr, int kind, - int (*found_proc) (struct i2c_adapter *, int, int)) -{ - int err; - /* Make sure the address is valid */ - if (addr < 0x03 || addr > 0x77) { - dev_warn(&adapter->dev, "Invalid probe address 0x%02x\n", - addr); - return -EINVAL; - } - - /* Skip if already in use */ - if (i2c_check_addr(adapter, addr)) - return 0; - - /* Make sure there is something at this address, unless forced */ - if (kind < 0) { - if (i2c_smbus_xfer(adapter, addr, 0, 0, 0, - I2C_SMBUS_QUICK, NULL) < 0) - return 0; - - /* prevent 24RF08 corruption */ - if ((addr & ~0x0f) == 0x50) - i2c_smbus_xfer(adapter, addr, 0, 0, 0, - I2C_SMBUS_QUICK, NULL); - } - - /* Finally call the custom detection function */ - err = found_proc(adapter, addr, kind); - /* -ENODEV can be returned if there is a chip at the given address - but it isn't supported by this chip driver. We catch it here as - this isn't an error. */ - if (err == -ENODEV) - err = 0; - - if (err) - dev_warn(&adapter->dev, "Client creation failed at 0x%x (%d)\n", - addr, err); - return err; -} - -int i2c_probe(struct i2c_adapter *adapter, - const struct i2c_client_address_data *address_data, - int (*found_proc) (struct i2c_adapter *, int, int)) -{ - int i, err; - int adap_id = i2c_adapter_id(adapter); - - /* Force entries are done first, and are not affected by ignore - entries */ - if (address_data->forces) { - const unsigned short * const *forces = address_data->forces; - int kind; - - for (kind = 0; forces[kind]; kind++) { - for (i = 0; forces[kind][i] != I2C_CLIENT_END; - i += 2) { - if (forces[kind][i] == adap_id - || forces[kind][i] == ANY_I2C_BUS) { - dev_dbg(&adapter->dev, "found force " - "parameter for adapter %d, " - "addr 0x%02x, kind %d\n", - adap_id, forces[kind][i + 1], - kind); - err = i2c_probe_address(adapter, - forces[kind][i + 1], - kind, found_proc); - if (err) - return err; - } - } - } - } - - /* Stop here if we can't use SMBUS_QUICK */ - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_QUICK)) { - if (address_data->probe[0] == I2C_CLIENT_END - && address_data->normal_i2c[0] == I2C_CLIENT_END) - return 0; - - dev_dbg(&adapter->dev, "SMBus Quick command not supported, " - "can't probe for chips\n"); - return -EOPNOTSUPP; - } - - /* Probe entries are done second, and are not affected by ignore - entries either */ - for (i = 0; address_data->probe[i] != I2C_CLIENT_END; i += 2) { - if (address_data->probe[i] == adap_id - || address_data->probe[i] == ANY_I2C_BUS) { - dev_dbg(&adapter->dev, "found probe parameter for " - "adapter %d, addr 0x%02x\n", adap_id, - address_data->probe[i + 1]); - err = i2c_probe_address(adapter, - address_data->probe[i + 1], - -1, found_proc); - if (err) - return err; - } - } - - /* Normal entries are done last, unless shadowed by an ignore entry */ - for (i = 0; address_data->normal_i2c[i] != I2C_CLIENT_END; i += 1) { - int j, ignore; - - ignore = 0; - for (j = 0; address_data->ignore[j] != I2C_CLIENT_END; - j += 2) { - if ((address_data->ignore[j] == adap_id || - address_data->ignore[j] == ANY_I2C_BUS) - && address_data->ignore[j + 1] - == address_data->normal_i2c[i]) { - dev_dbg(&adapter->dev, "found ignore " - "parameter for adapter %d, " - "addr 0x%02x\n", adap_id, - address_data->ignore[j + 1]); - ignore = 1; - break; - } - } - if (ignore) - continue; - - dev_dbg(&adapter->dev, "found normal entry for adapter %d, " - "addr 0x%02x\n", adap_id, - address_data->normal_i2c[i]); - err = i2c_probe_address(adapter, address_data->normal_i2c[i], - -1, found_proc); - if (err) - return err; - } - - return 0; -} -EXPORT_SYMBOL(i2c_probe); - -/* Separate detection function for new-style drivers */ static int i2c_detect_address(struct i2c_client *temp_client, int kind, struct i2c_driver *driver) { @@ -1509,7 +1346,7 @@ struct i2c_adapter* i2c_get_adapter(int id) struct i2c_adapter *adapter; mutex_lock(&core_lock); - adapter = (struct i2c_adapter *)idr_find(&i2c_adapter_idr, id); + adapter = idr_find(&i2c_adapter_idr, id); if (adapter && !try_module_get(adapter->owner)) adapter = NULL; @@ -1995,14 +1832,27 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags, char read_write, u8 command, int protocol, union i2c_smbus_data *data) { + unsigned long orig_jiffies; + int try; s32 res; flags &= I2C_M_TEN | I2C_CLIENT_PEC; if (adapter->algo->smbus_xfer) { mutex_lock(&adapter->bus_lock); - res = adapter->algo->smbus_xfer(adapter,addr,flags,read_write, - command, protocol, data); + + /* Retry automatically on arbitration loss */ + orig_jiffies = jiffies; + for (res = 0, try = 0; try <= adapter->retries; try++) { + res = adapter->algo->smbus_xfer(adapter, addr, flags, + read_write, command, + protocol, data); + if (res != -EAGAIN) + break; + if (time_after(jiffies, + orig_jiffies + adapter->timeout)) + break; + } mutex_unlock(&adapter->bus_lock); } else res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write, diff --git a/drivers/i2c/i2c-core.h b/drivers/i2c/i2c-core.h index cd5bff874855..9f9c57ff6708 100644 --- a/drivers/i2c/i2c-core.h +++ b/drivers/i2c/i2c-core.h @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include + struct i2c_devinfo { struct list_head list; int busnum; @@ -25,7 +27,7 @@ struct i2c_devinfo { /* board_lock protects board_list and first_dynamic_bus_num. * only i2c core components are allowed to use these symbols. */ -extern struct mutex __i2c_board_lock; +extern struct rw_semaphore __i2c_board_lock; extern struct list_head __i2c_board_list; extern int __i2c_first_dynamic_bus_num; diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index cf06494bb744..9a5d0aaac9d0 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig @@ -46,7 +46,7 @@ menuconfig IDE SMART parameters from disk drives. To compile this driver as a module, choose M here: the - module will be called ide-core.ko. + module will be called ide-core. For further information, please read . diff --git a/drivers/ide/alim15x3.c b/drivers/ide/alim15x3.c index 537da1cde16d..e59b6dee9ae2 100644 --- a/drivers/ide/alim15x3.c +++ b/drivers/ide/alim15x3.c @@ -402,27 +402,23 @@ static u8 ali_cable_detect(ide_hwif_t *hwif) return cbl; } -#if !defined(CONFIG_SPARC64) && !defined(CONFIG_PPC) +#ifndef CONFIG_SPARC64 /** * init_hwif_ali15x3 - Initialize the ALI IDE x86 stuff * @hwif: interface to configure * * Obtain the IRQ tables for an ALi based IDE solution on the PC * class platforms. This part of the code isn't applicable to the - * Sparc and PowerPC systems. + * Sparc systems. */ static void __devinit init_hwif_ali15x3 (ide_hwif_t *hwif) { - struct pci_dev *dev = to_pci_dev(hwif->dev); u8 ideic, inmir; s8 irq_routing_table[] = { -1, 9, 3, 10, 4, 5, 7, 6, 1, 11, 0, 12, 0, 14, 0, 15 }; int irq = -1; - if (dev->device == PCI_DEVICE_ID_AL_M5229) - hwif->irq = hwif->channel ? 15 : 14; - if (isa_dev) { /* * read IDE interface control @@ -455,7 +451,7 @@ static void __devinit init_hwif_ali15x3 (ide_hwif_t *hwif) } #else #define init_hwif_ali15x3 NULL -#endif /* !defined(CONFIG_SPARC64) && !defined(CONFIG_PPC) */ +#endif /* CONFIG_SPARC64 */ /** * init_dma_ali15x3 - set up DMA on ALi15x3 diff --git a/drivers/ide/at91_ide.c b/drivers/ide/at91_ide.c index 403d0e4265db..dbfeda42b940 100644 --- a/drivers/ide/at91_ide.c +++ b/drivers/ide/at91_ide.c @@ -185,8 +185,7 @@ static void at91_ide_set_pio_mode(ide_drive_t *drive, const u8 pio) timing = ide_timing_find_mode(XFER_PIO_0 + pio); BUG_ON(!timing); - if ((pio > 2 || ata_id_has_iordy(drive->id)) && - !(ata_id_is_cfa(drive->id) && pio > 4)) + if (ide_pio_need_iordy(drive, pio)) use_iordy = 1; apply_timings(chipselect, pio, timing, use_iordy); @@ -216,6 +215,7 @@ static const struct ide_port_info at91_ide_port_info __initdata = { .host_flags = IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA | IDE_HFLAG_SINGLE | IDE_HFLAG_NO_IO_32BIT | IDE_HFLAG_UNMASK_IRQS, .pio_mask = ATA_PIO6, + .chipset = ide_generic, }; /* @@ -246,8 +246,7 @@ irqreturn_t at91_irq_handler(int irq, void *dev_id) static int __init at91_ide_probe(struct platform_device *pdev) { int ret; - hw_regs_t hw; - hw_regs_t *hws[] = { &hw, NULL, NULL, NULL }; + struct ide_hw hw, *hws[] = { &hw }; struct ide_host *host; struct resource *res; unsigned long tf_base = 0, ctl_base = 0; @@ -304,10 +303,9 @@ static int __init at91_ide_probe(struct platform_device *pdev) ide_std_init_ports(&hw, tf_base, ctl_base + 6); hw.irq = board->irq_pin; - hw.chipset = ide_generic; hw.dev = &pdev->dev; - host = ide_host_alloc(&at91_ide_port_info, hws); + host = ide_host_alloc(&at91_ide_port_info, hws, 1); if (!host) { perr("failed to allocate ide host\n"); return -ENOMEM; diff --git a/drivers/ide/au1xxx-ide.c b/drivers/ide/au1xxx-ide.c index 46013644c965..58121bd6c115 100644 --- a/drivers/ide/au1xxx-ide.c +++ b/drivers/ide/au1xxx-ide.c @@ -449,7 +449,7 @@ static int auide_ddma_init(ide_hwif_t *hwif, const struct ide_port_info *d) } #endif -static void auide_setup_ports(hw_regs_t *hw, _auide_hwif *ahwif) +static void auide_setup_ports(struct ide_hw *hw, _auide_hwif *ahwif) { int i; unsigned long *ata_regs = hw->io_ports_array; @@ -499,6 +499,7 @@ static const struct ide_port_info au1xxx_port_info = { #ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA .mwdma_mask = ATA_MWDMA2, #endif + .chipset = ide_au1xxx, }; static int au_ide_probe(struct platform_device *dev) @@ -507,7 +508,7 @@ static int au_ide_probe(struct platform_device *dev) struct resource *res; struct ide_host *host; int ret = 0; - hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL }; + struct ide_hw hw, *hws[] = { &hw }; #if defined(CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA) char *mode = "MWDMA2"; @@ -548,9 +549,8 @@ static int au_ide_probe(struct platform_device *dev) auide_setup_ports(&hw, ahwif); hw.irq = ahwif->irq; hw.dev = &dev->dev; - hw.chipset = ide_au1xxx; - ret = ide_host_add(&au1xxx_port_info, hws, &host); + ret = ide_host_add(&au1xxx_port_info, hws, 1, &host); if (ret) goto out; diff --git a/drivers/ide/buddha.c b/drivers/ide/buddha.c index d028f8864bc1..ab4f169d0837 100644 --- a/drivers/ide/buddha.c +++ b/drivers/ide/buddha.c @@ -99,7 +99,7 @@ static const char *buddha_board_name[] = { "Buddha", "Catweasel", "X-Surf" }; * Check and acknowledge the interrupt status */ -static int buddha_ack_intr(ide_hwif_t *hwif) +static int buddha_test_irq(ide_hwif_t *hwif) { unsigned char ch; @@ -109,21 +109,16 @@ static int buddha_ack_intr(ide_hwif_t *hwif) return 1; } -static int xsurf_ack_intr(ide_hwif_t *hwif) +static void xsurf_clear_irq(ide_drive_t *drive) { - unsigned char ch; - - ch = z_readb(hwif->io_ports.irq_addr); - /* X-Surf needs a 0 written to IRQ register to ensure ISA bit A11 stays at 0 */ - z_writeb(0, hwif->io_ports.irq_addr); - if (!(ch & 0x80)) - return 0; - return 1; + /* + * X-Surf needs 0 written to IRQ register to ensure ISA bit A11 stays at 0 + */ + z_writeb(0, drive->hwif->io_ports.irq_addr); } -static void __init buddha_setup_ports(hw_regs_t *hw, unsigned long base, - unsigned long ctl, unsigned long irq_port, - ide_ack_intr_t *ack_intr) +static void __init buddha_setup_ports(struct ide_hw *hw, unsigned long base, + unsigned long ctl, unsigned long irq_port) { int i; @@ -138,14 +133,22 @@ static void __init buddha_setup_ports(hw_regs_t *hw, unsigned long base, hw->io_ports.irq_addr = irq_port; hw->irq = IRQ_AMIGA_PORTS; - hw->ack_intr = ack_intr; - - hw->chipset = ide_generic; } +static const struct ide_port_ops buddha_port_ops = { + .test_irq = buddha_test_irq, +}; + +static const struct ide_port_ops xsurf_port_ops = { + .clear_irq = xsurf_clear_irq, + .test_irq = buddha_test_irq, +}; + static const struct ide_port_info buddha_port_info = { + .port_ops = &buddha_port_ops, .host_flags = IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA, .irq_flags = IRQF_SHARED, + .chipset = ide_generic, }; /* @@ -161,7 +164,8 @@ static int __init buddha_init(void) while ((z = zorro_find_device(ZORRO_WILDCARD, z))) { unsigned long board; - hw_regs_t hw[MAX_NUM_HWIFS], *hws[] = { NULL, NULL, NULL, NULL }; + struct ide_hw hw[MAX_NUM_HWIFS], *hws[MAX_NUM_HWIFS]; + struct ide_port_info d = buddha_port_info; if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_BUDDHA) { buddha_num_hwifs = BUDDHA_NUM_HWIFS; @@ -172,6 +176,7 @@ static int __init buddha_init(void) } else if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_X_SURF) { buddha_num_hwifs = XSURF_NUM_HWIFS; type=BOARD_XSURF; + d.port_ops = &xsurf_port_ops; } else continue; @@ -204,28 +209,24 @@ fail_base2: for (i = 0; i < buddha_num_hwifs; i++) { unsigned long base, ctl, irq_port; - ide_ack_intr_t *ack_intr; if (type != BOARD_XSURF) { base = buddha_board + buddha_bases[i]; ctl = base + BUDDHA_CONTROL; irq_port = buddha_board + buddha_irqports[i]; - ack_intr = buddha_ack_intr; } else { base = buddha_board + xsurf_bases[i]; /* X-Surf has no CS1* (Control/AltStat) */ ctl = 0; irq_port = buddha_board + xsurf_irqports[i]; - ack_intr = xsurf_ack_intr; } - buddha_setup_ports(&hw[i], base, ctl, irq_port, - ack_intr); + buddha_setup_ports(&hw[i], base, ctl, irq_port); hws[i] = &hw[i]; } - ide_host_add(&buddha_port_info, hws, NULL); + ide_host_add(&d, hws, i, NULL); } return 0; diff --git a/drivers/ide/cmd640.c b/drivers/ide/cmd640.c index 8890276fef7f..1a32d62ed86b 100644 --- a/drivers/ide/cmd640.c +++ b/drivers/ide/cmd640.c @@ -153,6 +153,7 @@ static int cmd640_vlb; #define ARTTIM23 0x57 #define ARTTIM23_DIS_RA2 0x04 #define ARTTIM23_DIS_RA3 0x08 +#define ARTTIM23_IDE23INTR 0x10 #define DRWTIM23 0x58 #define BRST 0x59 @@ -629,12 +630,24 @@ static void cmd640_init_dev(ide_drive_t *drive) #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */ } +static int cmd640_test_irq(ide_hwif_t *hwif) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + int irq_reg = hwif->channel ? ARTTIM23 : CFR; + u8 irq_stat, irq_mask = hwif->channel ? ARTTIM23_IDE23INTR : + CFR_IDE01INTR; + + pci_read_config_byte(dev, irq_reg, &irq_stat); + + return (irq_stat & irq_mask) ? 1 : 0; +} static const struct ide_port_ops cmd640_port_ops = { .init_dev = cmd640_init_dev, #ifdef CONFIG_BLK_DEV_CMD640_ENHANCED .set_pio_mode = cmd640_set_pio_mode, #endif + .test_irq = cmd640_test_irq, }; static int pci_conf1(void) @@ -708,7 +721,7 @@ static int __init cmd640x_init(void) int second_port_cmd640 = 0, rc; const char *bus_type, *port2; u8 b, cfr; - hw_regs_t hw[2], *hws[] = { NULL, NULL, NULL, NULL }; + struct ide_hw hw[2], *hws[2]; if (cmd640_vlb && probe_for_cmd640_vlb()) { bus_type = "VLB"; @@ -762,11 +775,9 @@ static int __init cmd640x_init(void) ide_std_init_ports(&hw[0], 0x1f0, 0x3f6); hw[0].irq = 14; - hw[0].chipset = ide_cmd640; ide_std_init_ports(&hw[1], 0x170, 0x376); hw[1].irq = 15; - hw[1].chipset = ide_cmd640; printk(KERN_INFO "cmd640: buggy cmd640%c interface on %s, config=0x%02x" "\n", 'a' + cmd640_chip_version - 1, bus_type, cfr); @@ -824,7 +835,8 @@ static int __init cmd640x_init(void) cmd640_dump_regs(); #endif - return ide_host_add(&cmd640_port_info, hws, NULL); + return ide_host_add(&cmd640_port_info, hws, second_port_cmd640 ? 2 : 1, + NULL); } module_param_named(probe_vlb, cmd640_vlb, bool, 0); diff --git a/drivers/ide/cmd64x.c b/drivers/ide/cmd64x.c index 80b777e4247b..680e5975217f 100644 --- a/drivers/ide/cmd64x.c +++ b/drivers/ide/cmd64x.c @@ -7,7 +7,7 @@ * Copyright (C) 1998 David S. Miller (davem@redhat.com) * * Copyright (C) 1999-2002 Andre Hedrick - * Copyright (C) 2007 MontaVista Software, Inc. + * Copyright (C) 2007,2009 MontaVista Software, Inc. */ #include @@ -118,8 +118,9 @@ static void cmd64x_tune_pio(ide_drive_t *drive, const u8 pio) ide_hwif_t *hwif = drive->hwif; struct pci_dev *dev = to_pci_dev(hwif->dev); struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio); + unsigned long setup_count; unsigned int cycle_time; - u8 setup_count, arttim = 0; + u8 arttim = 0; static const u8 setup_values[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0}; static const u8 arttim_regs[4] = {ARTTIM0, ARTTIM1, ARTTIM23, ARTTIM23}; @@ -140,10 +141,11 @@ static void cmd64x_tune_pio(ide_drive_t *drive, const u8 pio) if (hwif->channel) { ide_drive_t *pair = ide_get_pair_dev(drive); - drive->drive_data = setup_count; + ide_set_drivedata(drive, (void *)setup_count); if (pair) - setup_count = max_t(u8, setup_count, pair->drive_data); + setup_count = max_t(u8, setup_count, + (unsigned long)ide_get_drivedata(pair)); } if (setup_count > 5) /* shouldn't actually happen... */ @@ -226,11 +228,11 @@ static void cmd64x_set_dma_mode(ide_drive_t *drive, const u8 speed) (void) pci_write_config_byte(dev, pciU, regU); } -static int cmd648_dma_end(ide_drive_t *drive) +static void cmd648_clear_irq(ide_drive_t *drive) { ide_hwif_t *hwif = drive->hwif; - unsigned long base = hwif->dma_base - (hwif->channel * 8); - int err = ide_dma_end(drive); + struct pci_dev *dev = to_pci_dev(hwif->dev); + unsigned long base = pci_resource_start(dev, 4); u8 irq_mask = hwif->channel ? MRDMODE_INTR_CH1 : MRDMODE_INTR_CH0; u8 mrdmode = inb(base + 1); @@ -238,11 +240,9 @@ static int cmd648_dma_end(ide_drive_t *drive) /* clear the interrupt bit */ outb((mrdmode & ~(MRDMODE_INTR_CH0 | MRDMODE_INTR_CH1)) | irq_mask, base + 1); - - return err; } -static int cmd64x_dma_end(ide_drive_t *drive) +static void cmd64x_clear_irq(ide_drive_t *drive) { ide_hwif_t *hwif = drive->hwif; struct pci_dev *dev = to_pci_dev(hwif->dev); @@ -250,62 +250,40 @@ static int cmd64x_dma_end(ide_drive_t *drive) u8 irq_mask = hwif->channel ? ARTTIM23_INTR_CH1 : CFR_INTR_CH0; u8 irq_stat = 0; - int err = ide_dma_end(drive); (void) pci_read_config_byte(dev, irq_reg, &irq_stat); /* clear the interrupt bit */ (void) pci_write_config_byte(dev, irq_reg, irq_stat | irq_mask); - - return err; } -static int cmd648_dma_test_irq(ide_drive_t *drive) +static int cmd648_test_irq(ide_hwif_t *hwif) { - ide_hwif_t *hwif = drive->hwif; - unsigned long base = hwif->dma_base - (hwif->channel * 8); + struct pci_dev *dev = to_pci_dev(hwif->dev); + unsigned long base = pci_resource_start(dev, 4); u8 irq_mask = hwif->channel ? MRDMODE_INTR_CH1 : MRDMODE_INTR_CH0; - u8 dma_stat = inb(hwif->dma_base + ATA_DMA_STATUS); u8 mrdmode = inb(base + 1); -#ifdef DEBUG - printk("%s: dma_stat: 0x%02x mrdmode: 0x%02x irq_mask: 0x%02x\n", - drive->name, dma_stat, mrdmode, irq_mask); -#endif - if (!(mrdmode & irq_mask)) - return 0; + pr_debug("%s: mrdmode: 0x%02x irq_mask: 0x%02x\n", + hwif->name, mrdmode, irq_mask); - /* return 1 if INTR asserted */ - if (dma_stat & 4) - return 1; - - return 0; + return (mrdmode & irq_mask) ? 1 : 0; } -static int cmd64x_dma_test_irq(ide_drive_t *drive) +static int cmd64x_test_irq(ide_hwif_t *hwif) { - ide_hwif_t *hwif = drive->hwif; struct pci_dev *dev = to_pci_dev(hwif->dev); int irq_reg = hwif->channel ? ARTTIM23 : CFR; u8 irq_mask = hwif->channel ? ARTTIM23_INTR_CH1 : CFR_INTR_CH0; - u8 dma_stat = inb(hwif->dma_base + ATA_DMA_STATUS); u8 irq_stat = 0; (void) pci_read_config_byte(dev, irq_reg, &irq_stat); -#ifdef DEBUG - printk("%s: dma_stat: 0x%02x irq_stat: 0x%02x irq_mask: 0x%02x\n", - drive->name, dma_stat, irq_stat, irq_mask); -#endif - if (!(irq_stat & irq_mask)) - return 0; + pr_debug("%s: irq_stat: 0x%02x irq_mask: 0x%02x\n", + hwif->name, irq_stat, irq_mask); - /* return 1 if INTR asserted */ - if (dma_stat & 4) - return 1; - - return 0; + return (irq_stat & irq_mask) ? 1 : 0; } /* @@ -370,18 +348,17 @@ static u8 cmd64x_cable_detect(ide_hwif_t *hwif) static const struct ide_port_ops cmd64x_port_ops = { .set_pio_mode = cmd64x_set_pio_mode, .set_dma_mode = cmd64x_set_dma_mode, + .clear_irq = cmd64x_clear_irq, + .test_irq = cmd64x_test_irq, .cable_detect = cmd64x_cable_detect, }; -static const struct ide_dma_ops cmd64x_dma_ops = { - .dma_host_set = ide_dma_host_set, - .dma_setup = ide_dma_setup, - .dma_start = ide_dma_start, - .dma_end = cmd64x_dma_end, - .dma_test_irq = cmd64x_dma_test_irq, - .dma_lost_irq = ide_dma_lost_irq, - .dma_timer_expiry = ide_dma_sff_timer_expiry, - .dma_sff_read_status = ide_dma_sff_read_status, +static const struct ide_port_ops cmd648_port_ops = { + .set_pio_mode = cmd64x_set_pio_mode, + .set_dma_mode = cmd64x_set_dma_mode, + .clear_irq = cmd648_clear_irq, + .test_irq = cmd648_test_irq, + .cable_detect = cmd64x_cable_detect, }; static const struct ide_dma_ops cmd646_rev1_dma_ops = { @@ -395,24 +372,12 @@ static const struct ide_dma_ops cmd646_rev1_dma_ops = { .dma_sff_read_status = ide_dma_sff_read_status, }; -static const struct ide_dma_ops cmd648_dma_ops = { - .dma_host_set = ide_dma_host_set, - .dma_setup = ide_dma_setup, - .dma_start = ide_dma_start, - .dma_end = cmd648_dma_end, - .dma_test_irq = cmd648_dma_test_irq, - .dma_lost_irq = ide_dma_lost_irq, - .dma_timer_expiry = ide_dma_sff_timer_expiry, - .dma_sff_read_status = ide_dma_sff_read_status, -}; - static const struct ide_port_info cmd64x_chipsets[] __devinitdata = { { /* 0: CMD643 */ .name = DRV_NAME, .init_chipset = init_chipset_cmd64x, .enablebits = {{0x00,0x00,0x00}, {0x51,0x08,0x08}}, .port_ops = &cmd64x_port_ops, - .dma_ops = &cmd64x_dma_ops, .host_flags = IDE_HFLAG_CLEAR_SIMPLEX | IDE_HFLAG_ABUSE_PREFETCH, .pio_mask = ATA_PIO5, @@ -423,10 +388,8 @@ static const struct ide_port_info cmd64x_chipsets[] __devinitdata = { .name = DRV_NAME, .init_chipset = init_chipset_cmd64x, .enablebits = {{0x51,0x04,0x04}, {0x51,0x08,0x08}}, - .port_ops = &cmd64x_port_ops, - .dma_ops = &cmd648_dma_ops, - .host_flags = IDE_HFLAG_SERIALIZE | - IDE_HFLAG_ABUSE_PREFETCH, + .port_ops = &cmd648_port_ops, + .host_flags = IDE_HFLAG_ABUSE_PREFETCH, .pio_mask = ATA_PIO5, .mwdma_mask = ATA_MWDMA2, .udma_mask = ATA_UDMA2, @@ -435,8 +398,7 @@ static const struct ide_port_info cmd64x_chipsets[] __devinitdata = { .name = DRV_NAME, .init_chipset = init_chipset_cmd64x, .enablebits = {{0x51,0x04,0x04}, {0x51,0x08,0x08}}, - .port_ops = &cmd64x_port_ops, - .dma_ops = &cmd648_dma_ops, + .port_ops = &cmd648_port_ops, .host_flags = IDE_HFLAG_ABUSE_PREFETCH, .pio_mask = ATA_PIO5, .mwdma_mask = ATA_MWDMA2, @@ -446,8 +408,7 @@ static const struct ide_port_info cmd64x_chipsets[] __devinitdata = { .name = DRV_NAME, .init_chipset = init_chipset_cmd64x, .enablebits = {{0x51,0x04,0x04}, {0x51,0x08,0x08}}, - .port_ops = &cmd64x_port_ops, - .dma_ops = &cmd648_dma_ops, + .port_ops = &cmd648_port_ops, .host_flags = IDE_HFLAG_ABUSE_PREFETCH, .pio_mask = ATA_PIO5, .mwdma_mask = ATA_MWDMA2, @@ -484,10 +445,9 @@ static int __devinit cmd64x_init_one(struct pci_dev *dev, const struct pci_devic */ if (dev->revision < 3) { d.enablebits[0].reg = 0; + d.port_ops = &cmd64x_port_ops; if (dev->revision == 1) d.dma_ops = &cmd646_rev1_dma_ops; - else - d.dma_ops = &cmd64x_dma_ops; } } } diff --git a/drivers/ide/cs5520.c b/drivers/ide/cs5520.c index 87987a7d36c9..bd066bb9d611 100644 --- a/drivers/ide/cs5520.c +++ b/drivers/ide/cs5520.c @@ -110,7 +110,7 @@ static const struct ide_port_info cyrix_chipset __devinitdata = { static int __devinit cs5520_init_one(struct pci_dev *dev, const struct pci_device_id *id) { const struct ide_port_info *d = &cyrix_chipset; - hw_regs_t hw[4], *hws[] = { NULL, NULL, NULL, NULL }; + struct ide_hw hw[2], *hws[] = { NULL, NULL }; ide_setup_pci_noise(dev, d); @@ -136,7 +136,7 @@ static int __devinit cs5520_init_one(struct pci_dev *dev, const struct pci_devic ide_pci_setup_ports(dev, d, &hw[0], &hws[0]); hw[0].irq = 14; - return ide_host_add(d, hws, NULL); + return ide_host_add(d, hws, 2, NULL); } static const struct pci_device_id cs5520_pci_tbl[] = { diff --git a/drivers/ide/cs5536.c b/drivers/ide/cs5536.c index 0332a95eefd4..9623b852c616 100644 --- a/drivers/ide/cs5536.c +++ b/drivers/ide/cs5536.c @@ -146,14 +146,16 @@ static void cs5536_set_pio_mode(ide_drive_t *drive, const u8 pio) struct pci_dev *pdev = to_pci_dev(drive->hwif->dev); ide_drive_t *pair = ide_get_pair_dev(drive); int cshift = (drive->dn & 1) ? IDE_CAST_D1_SHIFT : IDE_CAST_D0_SHIFT; + unsigned long timings = (unsigned long)ide_get_drivedata(drive); u32 cast; u8 cmd_pio = pio; if (pair) cmd_pio = min(pio, ide_get_best_pio_mode(pair, 255, 4)); - drive->drive_data &= (IDE_DRV_MASK << 8); - drive->drive_data |= drv_timings[pio]; + timings &= (IDE_DRV_MASK << 8); + timings |= drv_timings[pio]; + ide_set_drivedata(drive, (void *)timings); cs5536_program_dtc(drive, drv_timings[pio]); @@ -186,6 +188,7 @@ static void cs5536_set_dma_mode(ide_drive_t *drive, const u8 mode) struct pci_dev *pdev = to_pci_dev(drive->hwif->dev); int dshift = (drive->dn & 1) ? IDE_D1_SHIFT : IDE_D0_SHIFT; + unsigned long timings = (unsigned long)ide_get_drivedata(drive); u32 etc; cs5536_read(pdev, ETC, &etc); @@ -195,8 +198,9 @@ static void cs5536_set_dma_mode(ide_drive_t *drive, const u8 mode) etc |= udma_timings[mode - XFER_UDMA_0] << dshift; } else { /* MWDMA */ etc &= ~(IDE_ETC_UDMA_MASK << dshift); - drive->drive_data &= IDE_DRV_MASK; - drive->drive_data |= mwdma_timings[mode - XFER_MW_DMA_0] << 8; + timings &= IDE_DRV_MASK; + timings |= mwdma_timings[mode - XFER_MW_DMA_0] << 8; + ide_set_drivedata(drive, (void *)timings); } cs5536_write(pdev, ETC, etc); @@ -204,9 +208,11 @@ static void cs5536_set_dma_mode(ide_drive_t *drive, const u8 mode) static void cs5536_dma_start(ide_drive_t *drive) { + unsigned long timings = (unsigned long)ide_get_drivedata(drive); + if (drive->current_speed < XFER_UDMA_0 && - (drive->drive_data >> 8) != (drive->drive_data & IDE_DRV_MASK)) - cs5536_program_dtc(drive, drive->drive_data >> 8); + (timings >> 8) != (timings & IDE_DRV_MASK)) + cs5536_program_dtc(drive, timings >> 8); ide_dma_start(drive); } @@ -214,10 +220,11 @@ static void cs5536_dma_start(ide_drive_t *drive) static int cs5536_dma_end(ide_drive_t *drive) { int ret = ide_dma_end(drive); + unsigned long timings = (unsigned long)ide_get_drivedata(drive); if (drive->current_speed < XFER_UDMA_0 && - (drive->drive_data >> 8) != (drive->drive_data & IDE_DRV_MASK)) - cs5536_program_dtc(drive, drive->drive_data & IDE_DRV_MASK); + (timings >> 8) != (timings & IDE_DRV_MASK)) + cs5536_program_dtc(drive, timings & IDE_DRV_MASK); return ret; } diff --git a/drivers/ide/delkin_cb.c b/drivers/ide/delkin_cb.c index f153b95619bb..1e10eba62ceb 100644 --- a/drivers/ide/delkin_cb.c +++ b/drivers/ide/delkin_cb.c @@ -68,6 +68,7 @@ static const struct ide_port_info delkin_cb_port_info = { IDE_HFLAG_NO_DMA, .irq_flags = IRQF_SHARED, .init_chipset = delkin_cb_init_chipset, + .chipset = ide_pci, }; static int __devinit @@ -76,7 +77,7 @@ delkin_cb_probe (struct pci_dev *dev, const struct pci_device_id *id) struct ide_host *host; unsigned long base; int rc; - hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL }; + struct ide_hw hw, *hws[] = { &hw }; rc = pci_enable_device(dev); if (rc) { @@ -97,9 +98,8 @@ delkin_cb_probe (struct pci_dev *dev, const struct pci_device_id *id) ide_std_init_ports(&hw, base + 0x10, base + 0x1e); hw.irq = dev->irq; hw.dev = &dev->dev; - hw.chipset = ide_pci; /* this enables IRQ sharing */ - rc = ide_host_add(&delkin_cb_port_info, hws, &host); + rc = ide_host_add(&delkin_cb_port_info, hws, 1, &host); if (rc) goto out_disable; diff --git a/drivers/ide/falconide.c b/drivers/ide/falconide.c index 0e2df6755ec9..a5a07ccb81a7 100644 --- a/drivers/ide/falconide.c +++ b/drivers/ide/falconide.c @@ -111,9 +111,10 @@ static const struct ide_port_info falconide_port_info = { .host_flags = IDE_HFLAG_MMIO | IDE_HFLAG_SERIALIZE | IDE_HFLAG_NO_DMA, .irq_flags = IRQF_SHARED, + .chipset = ide_generic, }; -static void __init falconide_setup_ports(hw_regs_t *hw) +static void __init falconide_setup_ports(struct ide_hw *hw) { int i; @@ -127,9 +128,6 @@ static void __init falconide_setup_ports(hw_regs_t *hw) hw->io_ports.ctl_addr = ATA_HD_BASE + ATA_HD_CONTROL; hw->irq = IRQ_MFP_IDE; - hw->ack_intr = NULL; - - hw->chipset = ide_generic; } /* @@ -139,7 +137,7 @@ static void __init falconide_setup_ports(hw_regs_t *hw) static int __init falconide_init(void) { struct ide_host *host; - hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL }; + struct ide_hw hw, *hws[] = { &hw }; int rc; if (!MACH_IS_ATARI || !ATARIHW_PRESENT(IDE)) @@ -154,7 +152,7 @@ static int __init falconide_init(void) falconide_setup_ports(&hw); - host = ide_host_alloc(&falconide_port_info, hws); + host = ide_host_alloc(&falconide_port_info, hws, 1); if (host == NULL) { rc = -ENOMEM; goto err; diff --git a/drivers/ide/gayle.c b/drivers/ide/gayle.c index c7119516c5a7..b9e517de6a82 100644 --- a/drivers/ide/gayle.c +++ b/drivers/ide/gayle.c @@ -66,7 +66,7 @@ MODULE_PARM_DESC(doubler, "enable support for IDE doublers"); * Check and acknowledge the interrupt status */ -static int gayle_ack_intr_a4000(ide_hwif_t *hwif) +static int gayle_test_irq(ide_hwif_t *hwif) { unsigned char ch; @@ -76,21 +76,16 @@ static int gayle_ack_intr_a4000(ide_hwif_t *hwif) return 1; } -static int gayle_ack_intr_a1200(ide_hwif_t *hwif) +static void gayle_a1200_clear_irq(ide_drive_t *drive) { - unsigned char ch; + ide_hwif_t *hwif = drive->hwif; - ch = z_readb(hwif->io_ports.irq_addr); - if (!(ch & GAYLE_IRQ_IDE)) - return 0; (void)z_readb(hwif->io_ports.status_addr); z_writeb(0x7c, hwif->io_ports.irq_addr); - return 1; } -static void __init gayle_setup_ports(hw_regs_t *hw, unsigned long base, - unsigned long ctl, unsigned long irq_port, - ide_ack_intr_t *ack_intr) +static void __init gayle_setup_ports(struct ide_hw *hw, unsigned long base, + unsigned long ctl, unsigned long irq_port) { int i; @@ -105,15 +100,22 @@ static void __init gayle_setup_ports(hw_regs_t *hw, unsigned long base, hw->io_ports.irq_addr = irq_port; hw->irq = IRQ_AMIGA_PORTS; - hw->ack_intr = ack_intr; - - hw->chipset = ide_generic; } +static const struct ide_port_ops gayle_a4000_port_ops = { + .test_irq = gayle_test_irq, +}; + +static const struct ide_port_ops gayle_a1200_port_ops = { + .clear_irq = gayle_a1200_clear_irq, + .test_irq = gayle_test_irq, +}; + static const struct ide_port_info gayle_port_info = { .host_flags = IDE_HFLAG_MMIO | IDE_HFLAG_SERIALIZE | IDE_HFLAG_NO_DMA, .irq_flags = IRQF_SHARED, + .chipset = ide_generic, }; /* @@ -124,9 +126,9 @@ static int __init gayle_init(void) { unsigned long phys_base, res_start, res_n; unsigned long base, ctrlport, irqport; - ide_ack_intr_t *ack_intr; int a4000, i, rc; - hw_regs_t hw[GAYLE_NUM_HWIFS], *hws[] = { NULL, NULL, NULL, NULL }; + struct ide_hw hw[GAYLE_NUM_HWIFS], *hws[GAYLE_NUM_HWIFS]; + struct ide_port_info d = gayle_port_info; if (!MACH_IS_AMIGA) return -ENODEV; @@ -149,11 +151,11 @@ found: if (a4000) { phys_base = GAYLE_BASE_4000; irqport = (unsigned long)ZTWO_VADDR(GAYLE_IRQ_4000); - ack_intr = gayle_ack_intr_a4000; + d.port_ops = &gayle_a4000_port_ops; } else { phys_base = GAYLE_BASE_1200; irqport = (unsigned long)ZTWO_VADDR(GAYLE_IRQ_1200); - ack_intr = gayle_ack_intr_a1200; + d.port_ops = &gayle_a1200_port_ops; } res_start = ((unsigned long)phys_base) & ~(GAYLE_NEXT_PORT-1); @@ -166,12 +168,12 @@ found: base = (unsigned long)ZTWO_VADDR(phys_base + i * GAYLE_NEXT_PORT); ctrlport = GAYLE_HAS_CONTROL_REG ? (base + GAYLE_CONTROL) : 0; - gayle_setup_ports(&hw[i], base, ctrlport, irqport, ack_intr); + gayle_setup_ports(&hw[i], base, ctrlport, irqport); hws[i] = &hw[i]; } - rc = ide_host_add(&gayle_port_info, hws, NULL); + rc = ide_host_add(&d, hws, i, NULL); if (rc) release_mem_region(res_start, res_n); diff --git a/drivers/ide/hpt366.c b/drivers/ide/hpt366.c index 0feb66c720e1..7ce68ef6b904 100644 --- a/drivers/ide/hpt366.c +++ b/drivers/ide/hpt366.c @@ -138,14 +138,6 @@ #undef HPT_RESET_STATE_ENGINE #undef HPT_DELAY_INTERRUPT -static const char *quirk_drives[] = { - "QUANTUM FIREBALLlct08 08", - "QUANTUM FIREBALLP KA6.4", - "QUANTUM FIREBALLP LM20.4", - "QUANTUM FIREBALLP LM20.5", - NULL -}; - static const char *bad_ata100_5[] = { "IBM-DTLA-307075", "IBM-DTLA-307060", @@ -729,27 +721,13 @@ static void hpt3xx_set_pio_mode(ide_drive_t *drive, const u8 pio) hpt3xx_set_mode(drive, XFER_PIO_0 + pio); } -static void hpt3xx_quirkproc(ide_drive_t *drive) -{ - char *m = (char *)&drive->id[ATA_ID_PROD]; - const char **list = quirk_drives; - - while (*list) - if (strstr(m, *list++)) { - drive->quirk_list = 1; - return; - } - - drive->quirk_list = 0; -} - static void hpt3xx_maskproc(ide_drive_t *drive, int mask) { ide_hwif_t *hwif = drive->hwif; struct pci_dev *dev = to_pci_dev(hwif->dev); struct hpt_info *info = hpt3xx_get_info(hwif->dev); - if (drive->quirk_list == 0) + if ((drive->dev_flags & IDE_DFLAG_NIEN_QUIRK) == 0) return; if (info->chip_type >= HPT370) { @@ -1404,7 +1382,6 @@ static int __devinit hpt36x_init(struct pci_dev *dev, struct pci_dev *dev2) static const struct ide_port_ops hpt3xx_port_ops = { .set_pio_mode = hpt3xx_set_pio_mode, .set_dma_mode = hpt3xx_set_mode, - .quirkproc = hpt3xx_quirkproc, .maskproc = hpt3xx_maskproc, .mdma_filter = hpt3xx_mdma_filter, .udma_filter = hpt3xx_udma_filter, diff --git a/drivers/ide/ht6560b.c b/drivers/ide/ht6560b.c index 2fb0f2965009..aafed8060e17 100644 --- a/drivers/ide/ht6560b.c +++ b/drivers/ide/ht6560b.c @@ -44,7 +44,12 @@ * bit3 (0x08): "1" 3 cycle time, "0" 2 cycle time (?) */ #define HT_CONFIG_PORT 0x3e6 -#define HT_CONFIG(drivea) (u8)(((drivea)->drive_data & 0xff00) >> 8) + +static inline u8 HT_CONFIG(ide_drive_t *drive) +{ + return ((unsigned long)ide_get_drivedata(drive) & 0xff00) >> 8; +} + /* * FIFO + PREFETCH (both a/b-model) */ @@ -90,7 +95,11 @@ * Active Time for each drive. Smaller value gives higher speed. * In case of failures you should probably fall back to a higher value. */ -#define HT_TIMING(drivea) (u8)((drivea)->drive_data & 0x00ff) +static inline u8 HT_TIMING(ide_drive_t *drive) +{ + return (unsigned long)ide_get_drivedata(drive) & 0x00ff; +} + #define HT_TIMING_DEFAULT 0xff /* @@ -242,23 +251,27 @@ static DEFINE_SPINLOCK(ht6560b_lock); */ static void ht_set_prefetch(ide_drive_t *drive, u8 state) { - unsigned long flags; + unsigned long flags, config; int t = HT_PREFETCH_MODE << 8; spin_lock_irqsave(&ht6560b_lock, flags); + config = (unsigned long)ide_get_drivedata(drive); + /* * Prefetch mode and unmask irq seems to conflict */ if (state) { - drive->drive_data |= t; /* enable prefetch mode */ + config |= t; /* enable prefetch mode */ drive->dev_flags |= IDE_DFLAG_NO_UNMASK; drive->dev_flags &= ~IDE_DFLAG_UNMASK; } else { - drive->drive_data &= ~t; /* disable prefetch mode */ + config &= ~t; /* disable prefetch mode */ drive->dev_flags &= ~IDE_DFLAG_NO_UNMASK; } + ide_set_drivedata(drive, (void *)config); + spin_unlock_irqrestore(&ht6560b_lock, flags); #ifdef DEBUG @@ -268,7 +281,7 @@ static void ht_set_prefetch(ide_drive_t *drive, u8 state) static void ht6560b_set_pio_mode(ide_drive_t *drive, const u8 pio) { - unsigned long flags; + unsigned long flags, config; u8 timing; switch (pio) { @@ -281,8 +294,10 @@ static void ht6560b_set_pio_mode(ide_drive_t *drive, const u8 pio) timing = ht_pio2timings(drive, pio); spin_lock_irqsave(&ht6560b_lock, flags); - drive->drive_data &= 0xff00; - drive->drive_data |= timing; + config = (unsigned long)ide_get_drivedata(drive); + config &= 0xff00; + config |= timing; + ide_set_drivedata(drive, (void *)config); spin_unlock_irqrestore(&ht6560b_lock, flags); #ifdef DEBUG @@ -299,7 +314,7 @@ static void __init ht6560b_init_dev(ide_drive_t *drive) if (hwif->channel) t |= (HT_SECONDARY_IF << 8); - drive->drive_data = t; + ide_set_drivedata(drive, (void *)t); } static int probe_ht6560b; diff --git a/drivers/ide/icside.c b/drivers/ide/icside.c index 36da913cc553..0f67f1abbbd3 100644 --- a/drivers/ide/icside.c +++ b/drivers/ide/icside.c @@ -65,8 +65,6 @@ static struct cardinfo icside_cardinfo_v6_2 = { }; struct icside_state { - unsigned int channel; - unsigned int enabled; void __iomem *irq_port; void __iomem *ioc_base; unsigned int sel; @@ -116,18 +114,11 @@ static void icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr) struct icside_state *state = ec->irq_data; void __iomem *base = state->irq_port; - state->enabled = 1; + writeb(0, base + ICS_ARCIN_V6_INTROFFSET_1); + readb(base + ICS_ARCIN_V6_INTROFFSET_2); - switch (state->channel) { - case 0: - writeb(0, base + ICS_ARCIN_V6_INTROFFSET_1); - readb(base + ICS_ARCIN_V6_INTROFFSET_2); - break; - case 1: - writeb(0, base + ICS_ARCIN_V6_INTROFFSET_2); - readb(base + ICS_ARCIN_V6_INTROFFSET_1); - break; - } + writeb(0, base + ICS_ARCIN_V6_INTROFFSET_2); + readb(base + ICS_ARCIN_V6_INTROFFSET_1); } /* Prototype: icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr) @@ -137,8 +128,6 @@ static void icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr) { struct icside_state *state = ec->irq_data; - state->enabled = 0; - readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1); readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2); } @@ -160,44 +149,6 @@ static const expansioncard_ops_t icside_ops_arcin_v6 = { .irqpending = icside_irqpending_arcin_v6, }; -/* - * Handle routing of interrupts. This is called before - * we write the command to the drive. - */ -static void icside_maskproc(ide_drive_t *drive, int mask) -{ - ide_hwif_t *hwif = drive->hwif; - struct expansion_card *ec = ECARD_DEV(hwif->dev); - struct icside_state *state = ecard_get_drvdata(ec); - unsigned long flags; - - local_irq_save(flags); - - state->channel = hwif->channel; - - if (state->enabled && !mask) { - switch (hwif->channel) { - case 0: - writeb(0, state->irq_port + ICS_ARCIN_V6_INTROFFSET_1); - readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2); - break; - case 1: - writeb(0, state->irq_port + ICS_ARCIN_V6_INTROFFSET_2); - readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1); - break; - } - } else { - readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2); - readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1); - } - - local_irq_restore(flags); -} - -static const struct ide_port_ops icside_v6_no_dma_port_ops = { - .maskproc = icside_maskproc, -}; - #ifdef CONFIG_BLK_DEV_IDEDMA_ICS /* * SG-DMA support. @@ -236,7 +187,8 @@ static const struct ide_port_ops icside_v6_no_dma_port_ops = { */ static void icside_set_dma_mode(ide_drive_t *drive, const u8 xfer_mode) { - int cycle_time, use_dma_info = 0; + unsigned long cycle_time; + int use_dma_info = 0; switch (xfer_mode) { case XFER_MW_DMA_2: @@ -267,15 +219,15 @@ static void icside_set_dma_mode(ide_drive_t *drive, const u8 xfer_mode) if (use_dma_info && drive->id[ATA_ID_EIDE_DMA_TIME] > cycle_time) cycle_time = drive->id[ATA_ID_EIDE_DMA_TIME]; - drive->drive_data = cycle_time; + ide_set_drivedata(drive, (void *)cycle_time); printk("%s: %s selected (peak %dMB/s)\n", drive->name, - ide_xfer_verbose(xfer_mode), 2000 / drive->drive_data); + ide_xfer_verbose(xfer_mode), + 2000 / (unsigned long)ide_get_drivedata(drive)); } static const struct ide_port_ops icside_v6_port_ops = { .set_dma_mode = icside_set_dma_mode, - .maskproc = icside_maskproc, }; static void icside_dma_host_set(ide_drive_t *drive, int on) @@ -319,11 +271,6 @@ static int icside_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd) */ BUG_ON(dma_channel_active(ec->dma)); - /* - * Ensure that we have the right interrupt routed. - */ - icside_maskproc(drive, 0); - /* * Route the DMA signals to the correct interface. */ @@ -332,7 +279,7 @@ static int icside_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd) /* * Select the correct timing for this drive. */ - set_dma_speed(ec->dma, drive->drive_data); + set_dma_speed(ec->dma, (unsigned long)ide_get_drivedata(drive)); /* * Tell the DMA engine about the SG table and @@ -381,7 +328,7 @@ static int icside_dma_off_init(ide_hwif_t *hwif, const struct ide_port_info *d) return -EOPNOTSUPP; } -static void icside_setup_ports(hw_regs_t *hw, void __iomem *base, +static void icside_setup_ports(struct ide_hw *hw, void __iomem *base, struct cardinfo *info, struct expansion_card *ec) { unsigned long port = (unsigned long)base + info->dataoffset; @@ -398,11 +345,11 @@ static void icside_setup_ports(hw_regs_t *hw, void __iomem *base, hw->irq = ec->irq; hw->dev = &ec->dev; - hw->chipset = ide_acorn; } static const struct ide_port_info icside_v5_port_info = { .host_flags = IDE_HFLAG_NO_DMA, + .chipset = ide_acorn, }; static int __devinit @@ -410,7 +357,7 @@ icside_register_v5(struct icside_state *state, struct expansion_card *ec) { void __iomem *base; struct ide_host *host; - hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL }; + struct ide_hw hw, *hws[] = { &hw }; int ret; base = ecardm_iomap(ec, ECARD_RES_MEMC, 0, 0); @@ -431,7 +378,7 @@ icside_register_v5(struct icside_state *state, struct expansion_card *ec) icside_setup_ports(&hw, base, &icside_cardinfo_v5, ec); - host = ide_host_alloc(&icside_v5_port_info, hws); + host = ide_host_alloc(&icside_v5_port_info, hws, 1); if (host == NULL) return -ENODEV; @@ -452,11 +399,11 @@ err_free: static const struct ide_port_info icside_v6_port_info __initdata = { .init_dma = icside_dma_off_init, - .port_ops = &icside_v6_no_dma_port_ops, .dma_ops = &icside_v6_dma_ops, .host_flags = IDE_HFLAG_SERIALIZE | IDE_HFLAG_MMIO, .mwdma_mask = ATA_MWDMA2, .swdma_mask = ATA_SWDMA2, + .chipset = ide_acorn, }; static int __devinit @@ -466,7 +413,7 @@ icside_register_v6(struct icside_state *state, struct expansion_card *ec) struct ide_host *host; unsigned int sel = 0; int ret; - hw_regs_t hw[2], *hws[] = { &hw[0], &hw[1], NULL, NULL }; + struct ide_hw hw[2], *hws[] = { &hw[0], &hw[1] }; struct ide_port_info d = icside_v6_port_info; ioc_base = ecardm_iomap(ec, ECARD_RES_IOCFAST, 0, 0); @@ -506,7 +453,7 @@ icside_register_v6(struct icside_state *state, struct expansion_card *ec) icside_setup_ports(&hw[0], easi_base, &icside_cardinfo_v6_1, ec); icside_setup_ports(&hw[1], easi_base, &icside_cardinfo_v6_2, ec); - host = ide_host_alloc(&d, hws); + host = ide_host_alloc(&d, hws, 2); if (host == NULL) return -ENODEV; diff --git a/drivers/ide/ide-4drives.c b/drivers/ide/ide-4drives.c index 78aca75a2c48..979d342c338a 100644 --- a/drivers/ide/ide-4drives.c +++ b/drivers/ide/ide-4drives.c @@ -25,12 +25,13 @@ static const struct ide_port_info ide_4drives_port_info = { .port_ops = &ide_4drives_port_ops, .host_flags = IDE_HFLAG_SERIALIZE | IDE_HFLAG_NO_DMA | IDE_HFLAG_4DRIVES, + .chipset = ide_4drives, }; static int __init ide_4drives_init(void) { unsigned long base = 0x1f0, ctl = 0x3f6; - hw_regs_t hw, *hws[] = { &hw, &hw, NULL, NULL }; + struct ide_hw hw, *hws[] = { &hw, &hw }; if (probe_4drives == 0) return -ENODEV; @@ -52,9 +53,8 @@ static int __init ide_4drives_init(void) ide_std_init_ports(&hw, base, ctl); hw.irq = 14; - hw.chipset = ide_4drives; - return ide_host_add(&ide_4drives_port_info, hws, NULL); + return ide_host_add(&ide_4drives_port_info, hws, 2, NULL); } module_init(ide_4drives_init); diff --git a/drivers/ide/ide-atapi.c b/drivers/ide/ide-atapi.c index 7201b176d75b..eb2181a6a11c 100644 --- a/drivers/ide/ide-atapi.c +++ b/drivers/ide/ide-atapi.c @@ -10,6 +10,9 @@ #include +#define DRV_NAME "ide-atapi" +#define PFX DRV_NAME ": " + #ifdef DEBUG #define debug_log(fmt, args...) \ printk(KERN_INFO "ide: " fmt, ## args) @@ -74,64 +77,36 @@ EXPORT_SYMBOL_GPL(ide_check_atapi_device); void ide_init_pc(struct ide_atapi_pc *pc) { memset(pc, 0, sizeof(*pc)); - pc->buf = pc->pc_buf; - pc->buf_size = IDE_PC_BUFFER_SIZE; } EXPORT_SYMBOL_GPL(ide_init_pc); -/* - * Generate a new packet command request in front of the request queue, before - * the current request, so that it will be processed immediately, on the next - * pass through the driver. - */ -static void ide_queue_pc_head(ide_drive_t *drive, struct gendisk *disk, - struct ide_atapi_pc *pc, struct request *rq) -{ - blk_rq_init(NULL, rq); - rq->cmd_type = REQ_TYPE_SPECIAL; - rq->cmd_flags |= REQ_PREEMPT; - rq->buffer = (char *)pc; - rq->rq_disk = disk; - - if (pc->req_xfer) { - rq->data = pc->buf; - rq->data_len = pc->req_xfer; - } - - memcpy(rq->cmd, pc->c, 12); - if (drive->media == ide_tape) - rq->cmd[13] = REQ_IDETAPE_PC1; - - drive->hwif->rq = NULL; - - elv_add_request(drive->queue, rq, ELEVATOR_INSERT_FRONT, 0); -} - /* * Add a special packet command request to the tail of the request queue, * and wait for it to be serviced. */ int ide_queue_pc_tail(ide_drive_t *drive, struct gendisk *disk, - struct ide_atapi_pc *pc) + struct ide_atapi_pc *pc, void *buf, unsigned int bufflen) { struct request *rq; int error; rq = blk_get_request(drive->queue, READ, __GFP_WAIT); rq->cmd_type = REQ_TYPE_SPECIAL; - rq->buffer = (char *)pc; + rq->special = (char *)pc; - if (pc->req_xfer) { - rq->data = pc->buf; - rq->data_len = pc->req_xfer; + if (buf && bufflen) { + error = blk_rq_map_kern(drive->queue, rq, buf, bufflen, + GFP_NOIO); + if (error) + goto put_req; } memcpy(rq->cmd, pc->c, 12); if (drive->media == ide_tape) rq->cmd[13] = REQ_IDETAPE_PC1; error = blk_execute_rq(drive->queue, disk, rq, 0); +put_req: blk_put_request(rq); - return error; } EXPORT_SYMBOL_GPL(ide_queue_pc_tail); @@ -143,7 +118,7 @@ int ide_do_test_unit_ready(ide_drive_t *drive, struct gendisk *disk) ide_init_pc(&pc); pc.c[0] = TEST_UNIT_READY; - return ide_queue_pc_tail(drive, disk, &pc); + return ide_queue_pc_tail(drive, disk, &pc, NULL, 0); } EXPORT_SYMBOL_GPL(ide_do_test_unit_ready); @@ -158,7 +133,7 @@ int ide_do_start_stop(ide_drive_t *drive, struct gendisk *disk, int start) if (drive->media == ide_tape) pc.flags |= PC_FLAG_WAIT_FOR_DSC; - return ide_queue_pc_tail(drive, disk, &pc); + return ide_queue_pc_tail(drive, disk, &pc, NULL, 0); } EXPORT_SYMBOL_GPL(ide_do_start_stop); @@ -173,7 +148,7 @@ int ide_set_media_lock(ide_drive_t *drive, struct gendisk *disk, int on) pc.c[0] = ALLOW_MEDIUM_REMOVAL; pc.c[4] = on; - return ide_queue_pc_tail(drive, disk, &pc); + return ide_queue_pc_tail(drive, disk, &pc, NULL, 0); } EXPORT_SYMBOL_GPL(ide_set_media_lock); @@ -191,20 +166,109 @@ void ide_create_request_sense_cmd(ide_drive_t *drive, struct ide_atapi_pc *pc) } EXPORT_SYMBOL_GPL(ide_create_request_sense_cmd); +void ide_prep_sense(ide_drive_t *drive, struct request *rq) +{ + struct request_sense *sense = &drive->sense_data; + struct request *sense_rq = &drive->sense_rq; + unsigned int cmd_len, sense_len; + int err; + + switch (drive->media) { + case ide_floppy: + cmd_len = 255; + sense_len = 18; + break; + case ide_tape: + cmd_len = 20; + sense_len = 20; + break; + default: + cmd_len = 18; + sense_len = 18; + } + + BUG_ON(sense_len > sizeof(*sense)); + + if (blk_sense_request(rq) || drive->sense_rq_armed) + return; + + memset(sense, 0, sizeof(*sense)); + + blk_rq_init(rq->q, sense_rq); + + err = blk_rq_map_kern(drive->queue, sense_rq, sense, sense_len, + GFP_NOIO); + if (unlikely(err)) { + if (printk_ratelimit()) + printk(KERN_WARNING PFX "%s: failed to map sense " + "buffer\n", drive->name); + return; + } + + sense_rq->rq_disk = rq->rq_disk; + sense_rq->cmd[0] = GPCMD_REQUEST_SENSE; + sense_rq->cmd[4] = cmd_len; + sense_rq->cmd_type = REQ_TYPE_SENSE; + sense_rq->cmd_flags |= REQ_PREEMPT; + + if (drive->media == ide_tape) + sense_rq->cmd[13] = REQ_IDETAPE_PC1; + + drive->sense_rq_armed = true; +} +EXPORT_SYMBOL_GPL(ide_prep_sense); + +int ide_queue_sense_rq(ide_drive_t *drive, void *special) +{ + /* deferred failure from ide_prep_sense() */ + if (!drive->sense_rq_armed) { + printk(KERN_WARNING PFX "%s: error queuing a sense request\n", + drive->name); + return -ENOMEM; + } + + drive->sense_rq.special = special; + drive->sense_rq_armed = false; + + drive->hwif->rq = NULL; + + elv_add_request(drive->queue, &drive->sense_rq, + ELEVATOR_INSERT_FRONT, 0); + return 0; +} +EXPORT_SYMBOL_GPL(ide_queue_sense_rq); + /* * Called when an error was detected during the last packet command. - * We queue a request sense packet command in the head of the request list. + * We queue a request sense packet command at the head of the request + * queue. */ -void ide_retry_pc(ide_drive_t *drive, struct gendisk *disk) +void ide_retry_pc(ide_drive_t *drive) { - struct request *rq = &drive->request_sense_rq; + struct request *failed_rq = drive->hwif->rq; + struct request *sense_rq = &drive->sense_rq; struct ide_atapi_pc *pc = &drive->request_sense_pc; (void)ide_read_error(drive); - ide_create_request_sense_cmd(drive, pc); + + /* init pc from sense_rq */ + ide_init_pc(pc); + memcpy(pc->c, sense_rq->cmd, 12); + if (drive->media == ide_tape) - set_bit(IDE_AFLAG_IGNORE_DSC, &drive->atapi_flags); - ide_queue_pc_head(drive, disk, pc, rq); + drive->atapi_flags |= IDE_AFLAG_IGNORE_DSC; + + /* + * Push back the failed request and put request sense on top + * of it. The failed command will be retried after sense data + * is acquired. + */ + blk_requeue_request(failed_rq->q, failed_rq); + drive->hwif->rq = NULL; + if (ide_queue_sense_rq(drive, pc)) { + blk_start_request(failed_rq); + ide_complete_rq(drive, -EIO, blk_rq_bytes(failed_rq)); + } } EXPORT_SYMBOL_GPL(ide_retry_pc); @@ -231,7 +295,7 @@ int ide_cd_expiry(ide_drive_t *drive) break; default: if (!(rq->cmd_flags & REQ_QUIET)) - printk(KERN_INFO "cmd 0x%x timed out\n", + printk(KERN_INFO PFX "cmd 0x%x timed out\n", rq->cmd[0]); wait = 0; break; @@ -246,7 +310,7 @@ int ide_cd_get_xferlen(struct request *rq) return 32768; else if (blk_sense_request(rq) || blk_pc_request(rq) || rq->cmd_type == REQ_TYPE_ATA_PC) - return rq->data_len; + return blk_rq_bytes(rq); else return 0; } @@ -264,6 +328,55 @@ void ide_read_bcount_and_ireason(ide_drive_t *drive, u16 *bcount, u8 *ireason) } EXPORT_SYMBOL_GPL(ide_read_bcount_and_ireason); +/* + * Check the contents of the interrupt reason register and attempt to recover if + * there are problems. + * + * Returns: + * - 0 if everything's ok + * - 1 if the request has to be terminated. + */ +int ide_check_ireason(ide_drive_t *drive, struct request *rq, int len, + int ireason, int rw) +{ + ide_hwif_t *hwif = drive->hwif; + + debug_log("ireason: 0x%x, rw: 0x%x\n", ireason, rw); + + if (ireason == (!rw << 1)) + return 0; + else if (ireason == (rw << 1)) { + printk(KERN_ERR PFX "%s: %s: wrong transfer direction!\n", + drive->name, __func__); + + if (dev_is_idecd(drive)) + ide_pad_transfer(drive, rw, len); + } else if (!rw && ireason == ATAPI_COD) { + if (dev_is_idecd(drive)) { + /* + * Some drives (ASUS) seem to tell us that status info + * is available. Just get it and ignore. + */ + (void)hwif->tp_ops->read_status(hwif); + return 0; + } + } else { + if (ireason & ATAPI_COD) + printk(KERN_ERR PFX "%s: CoD != 0 in %s\n", drive->name, + __func__); + + /* drive wants a command packet, or invalid ireason... */ + printk(KERN_ERR PFX "%s: %s: bad interrupt reason 0x%02x\n", + drive->name, __func__, ireason); + } + + if (dev_is_idecd(drive) && rq->cmd_type == REQ_TYPE_ATA_PC) + rq->cmd_flags |= REQ_FAILED; + + return 1; +} +EXPORT_SYMBOL_GPL(ide_check_ireason); + /* * This is the usual interrupt handler which will be called during a packet * command. We will transfer some of the data (as requested by the drive) @@ -276,7 +389,6 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) struct ide_cmd *cmd = &hwif->cmd; struct request *rq = hwif->rq; const struct ide_tp_ops *tp_ops = hwif->tp_ops; - xfer_func_t *xferfunc; unsigned int timeout, done; u16 bcount; u8 stat, ireason, dsc = 0; @@ -299,25 +411,21 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) if (rc || (drive->media == ide_tape && (stat & ATA_ERR))) { if (drive->media == ide_floppy) - printk(KERN_ERR "%s: DMA %s error\n", + printk(KERN_ERR PFX "%s: DMA %s error\n", drive->name, rq_data_dir(pc->rq) ? "write" : "read"); pc->flags |= PC_FLAG_DMA_ERROR; - } else { - pc->xferred = pc->req_xfer; - if (drive->pc_update_buffers) - drive->pc_update_buffers(drive, pc); - } + } else + rq->resid_len = 0; debug_log("%s: DMA finished\n", drive->name); } /* No more interrupts */ if ((stat & ATA_DRQ) == 0) { int uptodate, error; - unsigned int done; debug_log("Packet command completed, %d bytes transferred\n", - pc->xferred); + blk_rq_bytes(rq)); pc->flags &= ~PC_FLAG_DMA_IN_PROGRESS; @@ -335,15 +443,15 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) pc->rq->errors++; if (rq->cmd[0] == REQUEST_SENSE) { - printk(KERN_ERR "%s: I/O error in request sense" - " command\n", drive->name); + printk(KERN_ERR PFX "%s: I/O error in request " + "sense command\n", drive->name); return ide_do_reset(drive); } debug_log("[cmd %x]: check condition\n", rq->cmd[0]); /* Retry operation */ - ide_retry_pc(drive, rq->rq_disk); + ide_retry_pc(drive); /* queued, but not started */ return ide_stopped; @@ -353,6 +461,12 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) if ((pc->flags & PC_FLAG_WAIT_FOR_DSC) && (stat & ATA_DSC) == 0) dsc = 1; + /* + * ->pc_callback() might change rq->data_len for + * residual count, cache total length. + */ + done = blk_rq_bytes(rq); + /* Command finished - Call the callback function */ uptodate = drive->pc_callback(drive, dsc); @@ -361,7 +475,6 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) if (blk_special_request(rq)) { rq->errors = 0; - done = blk_rq_bytes(rq); error = 0; } else { @@ -370,22 +483,17 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) rq->errors = -EIO; } - if (drive->media == ide_tape) - done = ide_rq_bytes(rq); /* FIXME */ - else - done = blk_rq_bytes(rq); - error = uptodate ? 0 : -EIO; } - ide_complete_rq(drive, error, done); + ide_complete_rq(drive, error, blk_rq_bytes(rq)); return ide_stopped; } if (pc->flags & PC_FLAG_DMA_IN_PROGRESS) { pc->flags &= ~PC_FLAG_DMA_IN_PROGRESS; - printk(KERN_ERR "%s: The device wants to issue more interrupts " - "in DMA mode\n", drive->name); + printk(KERN_ERR PFX "%s: The device wants to issue more " + "interrupts in DMA mode\n", drive->name); ide_dma_off(drive); return ide_do_reset(drive); } @@ -393,43 +501,22 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) /* Get the number of bytes to transfer on this interrupt. */ ide_read_bcount_and_ireason(drive, &bcount, &ireason); - if (ireason & ATAPI_COD) { - printk(KERN_ERR "%s: CoD != 0 in %s\n", drive->name, __func__); + if (ide_check_ireason(drive, rq, bcount, ireason, write)) return ide_do_reset(drive); - } - if (((ireason & ATAPI_IO) == ATAPI_IO) == write) { - /* Hopefully, we will never get here */ - printk(KERN_ERR "%s: We wanted to %s, but the device wants us " - "to %s!\n", drive->name, - (ireason & ATAPI_IO) ? "Write" : "Read", - (ireason & ATAPI_IO) ? "Read" : "Write"); - return ide_do_reset(drive); - } + done = min_t(unsigned int, bcount, cmd->nleft); + ide_pio_bytes(drive, cmd, write, done); - xferfunc = write ? tp_ops->output_data : tp_ops->input_data; - - if (drive->media == ide_floppy && pc->buf == NULL) { - done = min_t(unsigned int, bcount, cmd->nleft); - ide_pio_bytes(drive, cmd, write, done); - } else if (drive->media == ide_tape && pc->bh) { - done = drive->pc_io_buffers(drive, pc, bcount, write); - } else { - done = min_t(unsigned int, bcount, pc->req_xfer - pc->xferred); - xferfunc(drive, NULL, pc->cur_pos, done); - } - - /* Update the current position */ - pc->xferred += done; - pc->cur_pos += done; + /* Update transferred byte count */ + rq->resid_len -= done; bcount -= done; if (bcount) ide_pad_transfer(drive, write, bcount); - debug_log("[cmd %x] transferred %d bytes, padded %d bytes\n", - rq->cmd[0], done, bcount); + debug_log("[cmd %x] transferred %d bytes, padded %d bytes, resid: %u\n", + rq->cmd[0], done, bcount, rq->resid_len); /* And set the interrupt handler again */ ide_set_handler(drive, ide_pc_intr, timeout); @@ -463,13 +550,13 @@ static u8 ide_wait_ireason(ide_drive_t *drive, u8 ireason) while (retries-- && ((ireason & ATAPI_COD) == 0 || (ireason & ATAPI_IO))) { - printk(KERN_ERR "%s: (IO,CoD != (0,1) while issuing " + printk(KERN_ERR PFX "%s: (IO,CoD != (0,1) while issuing " "a packet command, retrying\n", drive->name); udelay(100); ireason = ide_read_ireason(drive); if (retries == 0) { - printk(KERN_ERR "%s: (IO,CoD != (0,1) while issuing " - "a packet command, ignoring\n", + printk(KERN_ERR PFX "%s: (IO,CoD != (0,1) while issuing" + " a packet command, ignoring\n", drive->name); ireason |= ATAPI_COD; ireason &= ~ATAPI_IO; @@ -500,7 +587,7 @@ static ide_startstop_t ide_transfer_pc(ide_drive_t *drive) u8 ireason; if (ide_wait_stat(&startstop, drive, ATA_DRQ, ATA_BUSY, WAIT_READY)) { - printk(KERN_ERR "%s: Strange, packet command initiated yet " + printk(KERN_ERR PFX "%s: Strange, packet command initiated yet " "DRQ isn't asserted\n", drive->name); return startstop; } @@ -525,7 +612,7 @@ static ide_startstop_t ide_transfer_pc(ide_drive_t *drive) /* * If necessary schedule the packet transfer to occur 'timeout' - * miliseconds later in ide_delayed_transfer_pc() after the + * milliseconds later in ide_delayed_transfer_pc() after the * device says it's ready for a packet. */ if (drive->atapi_flags & IDE_AFLAG_ZIP_DRIVE) { @@ -542,8 +629,8 @@ static ide_startstop_t ide_transfer_pc(ide_drive_t *drive) ireason = ide_wait_ireason(drive, ireason); if ((ireason & ATAPI_COD) == 0 || (ireason & ATAPI_IO)) { - printk(KERN_ERR "%s: (IO,CoD) != (0,1) while issuing " - "a packet command\n", drive->name); + printk(KERN_ERR PFX "%s: (IO,CoD) != (0,1) while " + "issuing a packet command\n", drive->name); return ide_do_reset(drive); } @@ -581,7 +668,7 @@ ide_startstop_t ide_issue_pc(ide_drive_t *drive, struct ide_cmd *cmd) ide_hwif_t *hwif = drive->hwif; ide_expiry_t *expiry = NULL; struct request *rq = hwif->rq; - unsigned int timeout; + unsigned int timeout, bytes; u16 bcount; u8 valid_tf; u8 drq_int = !!(drive->atapi_flags & IDE_AFLAG_DRQ_INTERRUPT); @@ -597,14 +684,14 @@ ide_startstop_t ide_issue_pc(ide_drive_t *drive, struct ide_cmd *cmd) } else { pc = drive->pc; - /* We haven't transferred any data yet */ - pc->xferred = 0; - pc->cur_pos = pc->buf; - valid_tf = IDE_VALID_DEVICE; - bcount = ((drive->media == ide_tape) ? - pc->req_xfer : - min(pc->req_xfer, 63 * 1024)); + bytes = blk_rq_bytes(rq); + bcount = ((drive->media == ide_tape) ? bytes + : min_t(unsigned int, + bytes, 63 * 1024)); + + /* We haven't transferred any data yet */ + rq->resid_len = bcount; if (pc->flags & PC_FLAG_DMA_ERROR) { pc->flags &= ~PC_FLAG_DMA_ERROR; diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index 925eb9e245d1..4a19686fcfe9 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -92,16 +92,16 @@ static void cdrom_saw_media_change(ide_drive_t *drive) drive->atapi_flags &= ~IDE_AFLAG_TOC_VALID; } -static int cdrom_log_sense(ide_drive_t *drive, struct request *rq, - struct request_sense *sense) +static int cdrom_log_sense(ide_drive_t *drive, struct request *rq) { + struct request_sense *sense = &drive->sense_data; int log = 0; - ide_debug_log(IDE_DBG_SENSE, "sense_key: 0x%x", sense->sense_key); - if (!sense || !rq || (rq->cmd_flags & REQ_QUIET)) return 0; + ide_debug_log(IDE_DBG_SENSE, "sense_key: 0x%x", sense->sense_key); + switch (sense->sense_key) { case NO_SENSE: case RECOVERED_ERROR: @@ -140,12 +140,12 @@ static int cdrom_log_sense(ide_drive_t *drive, struct request *rq, } static void cdrom_analyze_sense_data(ide_drive_t *drive, - struct request *failed_command, - struct request_sense *sense) + struct request *failed_command) { + struct request_sense *sense = &drive->sense_data; + struct cdrom_info *info = drive->driver_data; unsigned long sector; unsigned long bio_sectors; - struct cdrom_info *info = drive->driver_data; ide_debug_log(IDE_DBG_SENSE, "error_code: 0x%x, sense_key: 0x%x", sense->error_code, sense->sense_key); @@ -154,7 +154,7 @@ static void cdrom_analyze_sense_data(ide_drive_t *drive, ide_debug_log(IDE_DBG_SENSE, "failed cmd: 0x%x", failed_command->cmd[0]); - if (!cdrom_log_sense(drive, failed_command, sense)) + if (!cdrom_log_sense(drive, failed_command)) return; /* @@ -182,7 +182,7 @@ static void cdrom_analyze_sense_data(ide_drive_t *drive, (sense->information[2] << 8) | (sense->information[3]); - if (drive->queue->hardsect_size == 2048) + if (queue_logical_block_size(drive->queue) == 2048) /* device sector size is 2K */ sector <<= 2; @@ -206,63 +206,33 @@ static void cdrom_analyze_sense_data(ide_drive_t *drive, ide_cd_log_error(drive->name, failed_command, sense); } -static void cdrom_queue_request_sense(ide_drive_t *drive, void *sense, - struct request *failed_command) -{ - struct cdrom_info *info = drive->driver_data; - struct request *rq = &drive->request_sense_rq; - - ide_debug_log(IDE_DBG_SENSE, "enter"); - - if (sense == NULL) - sense = &info->sense_data; - - /* stuff the sense request in front of our current request */ - blk_rq_init(NULL, rq); - rq->cmd_type = REQ_TYPE_ATA_PC; - rq->rq_disk = info->disk; - - rq->data = sense; - rq->cmd[0] = GPCMD_REQUEST_SENSE; - rq->cmd[4] = 18; - rq->data_len = 18; - - rq->cmd_type = REQ_TYPE_SENSE; - rq->cmd_flags |= REQ_PREEMPT; - - /* NOTE! Save the failed command in "rq->buffer" */ - rq->buffer = (void *) failed_command; - - if (failed_command) - ide_debug_log(IDE_DBG_SENSE, "failed_cmd: 0x%x", - failed_command->cmd[0]); - - drive->hwif->rq = NULL; - - elv_add_request(drive->queue, rq, ELEVATOR_INSERT_FRONT, 0); -} - static void ide_cd_complete_failed_rq(ide_drive_t *drive, struct request *rq) { /* - * For REQ_TYPE_SENSE, "rq->buffer" points to the original - * failed request + * For REQ_TYPE_SENSE, "rq->special" points to the original + * failed request. Also, the sense data should be read + * directly from rq which might be different from the original + * sense buffer if it got copied during mapping. */ - struct request *failed = (struct request *)rq->buffer; - struct cdrom_info *info = drive->driver_data; - void *sense = &info->sense_data; + struct request *failed = (struct request *)rq->special; + void *sense = bio_data(rq->bio); if (failed) { if (failed->sense) { - sense = failed->sense; + /* + * Sense is always read into drive->sense_data. + * Copy back if the failed request has its + * sense pointer set. + */ + memcpy(failed->sense, sense, 18); failed->sense_len = rq->sense_len; } - cdrom_analyze_sense_data(drive, failed, sense); + cdrom_analyze_sense_data(drive, failed); if (ide_end_rq(drive, failed, -EIO, blk_rq_bytes(failed))) BUG(); } else - cdrom_analyze_sense_data(drive, NULL, sense); + cdrom_analyze_sense_data(drive, NULL); } @@ -428,70 +398,17 @@ static int cdrom_decode_status(ide_drive_t *drive, u8 stat) /* if we got a CHECK_CONDITION status, queue a request sense command */ if (stat & ATA_ERR) - cdrom_queue_request_sense(drive, NULL, NULL); + return ide_queue_sense_rq(drive, NULL) ? 2 : 1; return 1; end_request: if (stat & ATA_ERR) { - struct request_queue *q = drive->queue; - unsigned long flags; - - spin_lock_irqsave(q->queue_lock, flags); - blkdev_dequeue_request(rq); - spin_unlock_irqrestore(q->queue_lock, flags); - hwif->rq = NULL; - - cdrom_queue_request_sense(drive, rq->sense, rq); - return 1; + return ide_queue_sense_rq(drive, rq) ? 2 : 1; } else return 2; } -/* - * Check the contents of the interrupt reason register from the cdrom - * and attempt to recover if there are problems. Returns 0 if everything's - * ok; nonzero if the request has been terminated. - */ -static int ide_cd_check_ireason(ide_drive_t *drive, struct request *rq, - int len, int ireason, int rw) -{ - ide_hwif_t *hwif = drive->hwif; - - ide_debug_log(IDE_DBG_FUNC, "ireason: 0x%x, rw: 0x%x", ireason, rw); - - /* - * ireason == 0: the drive wants to receive data from us - * ireason == 2: the drive is expecting to transfer data to us - */ - if (ireason == (!rw << 1)) - return 0; - else if (ireason == (rw << 1)) { - - /* whoops... */ - printk(KERN_ERR PFX "%s: %s: wrong transfer direction!\n", - drive->name, __func__); - - ide_pad_transfer(drive, rw, len); - } else if (rw == 0 && ireason == 1) { - /* - * Some drives (ASUS) seem to tell us that status info is - * available. Just get it and ignore. - */ - (void)hwif->tp_ops->read_status(hwif); - return 0; - } else { - /* drive wants a command packet, or invalid ireason... */ - printk(KERN_ERR PFX "%s: %s: bad interrupt reason 0x%02x\n", - drive->name, __func__, ireason); - } - - if (rq->cmd_type == REQ_TYPE_ATA_PC) - rq->cmd_flags |= REQ_FAILED; - - return -1; -} - static void ide_cd_request_sense_fixup(ide_drive_t *drive, struct ide_cmd *cmd) { struct request *rq = cmd->rq; @@ -503,14 +420,8 @@ static void ide_cd_request_sense_fixup(ide_drive_t *drive, struct ide_cmd *cmd) * and some drives don't send them. Sigh. */ if (rq->cmd[0] == GPCMD_REQUEST_SENSE && - cmd->nleft > 0 && cmd->nleft <= 5) { - unsigned int ofs = cmd->nbytes - cmd->nleft; - - while (cmd->nleft > 0) { - *((u8 *)rq->data + ofs++) = 0; - cmd->nleft--; - } - } + cmd->nleft > 0 && cmd->nleft <= 5) + cmd->nleft = 0; } int ide_cd_queue_pc(ide_drive_t *drive, const unsigned char *cmd, @@ -543,14 +454,18 @@ int ide_cd_queue_pc(ide_drive_t *drive, const unsigned char *cmd, rq->cmd_flags |= cmd_flags; rq->timeout = timeout; if (buffer) { - rq->data = buffer; - rq->data_len = *bufflen; + error = blk_rq_map_kern(drive->queue, rq, buffer, + *bufflen, GFP_NOIO); + if (error) { + blk_put_request(rq); + return error; + } } error = blk_execute_rq(drive->queue, info->disk, rq, 0); if (buffer) - *bufflen = rq->data_len; + *bufflen = rq->resid_len; flags = rq->cmd_flags; blk_put_request(rq); @@ -608,7 +523,7 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) struct request *rq = hwif->rq; ide_expiry_t *expiry = NULL; int dma_error = 0, dma, thislen, uptodate = 0; - int write = (rq_data_dir(rq) == WRITE) ? 1 : 0, rc = 0, nsectors; + int write = (rq_data_dir(rq) == WRITE) ? 1 : 0, rc = 0; int sense = blk_sense_request(rq); unsigned int timeout; u16 len; @@ -685,8 +600,7 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) goto out_end; } - /* check which way to transfer data */ - rc = ide_cd_check_ireason(drive, rq, len, ireason, write); + rc = ide_check_ireason(drive, rq, len, ireason, write); if (rc) goto out_end; @@ -738,13 +652,8 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) out_end: if (blk_pc_request(rq) && rc == 0) { - unsigned int dlen = rq->data_len; - - rq->data_len = 0; - - if (blk_end_request(rq, 0, dlen)) - BUG(); - + rq->resid_len = 0; + blk_end_request_all(rq, 0); hwif->rq = NULL; } else { if (sense && uptodate) @@ -758,25 +667,17 @@ out_end: rq->errors = -EIO; } - if (uptodate == 0) + if (uptodate == 0 && rq->bio) ide_cd_error_cmd(drive, cmd); /* make sure it's fully ended */ - if (blk_pc_request(rq)) - nsectors = (rq->data_len + 511) >> 9; - else - nsectors = rq->hard_nr_sectors; - - if (nsectors == 0) - nsectors = 1; - if (blk_fs_request(rq) == 0) { - rq->data_len -= (cmd->nbytes - cmd->nleft); + rq->resid_len -= cmd->nbytes - cmd->nleft; if (uptodate == 0 && (cmd->tf_flags & IDE_TFLAG_WRITE)) - rq->data_len += cmd->last_xfer_len; + rq->resid_len += cmd->last_xfer_len; } - ide_complete_rq(drive, uptodate ? 0 : -EIO, nsectors << 9); + ide_complete_rq(drive, uptodate ? 0 : -EIO, blk_rq_bytes(rq)); if (sense && rc == 2) ide_error(drive, "request sense failure", stat); @@ -790,7 +691,7 @@ static ide_startstop_t cdrom_start_rw(ide_drive_t *drive, struct request *rq) struct request_queue *q = drive->queue; int write = rq_data_dir(rq) == WRITE; unsigned short sectors_per_frame = - queue_hardsect_size(q) >> SECTOR_BITS; + queue_logical_block_size(q) >> SECTOR_BITS; ide_debug_log(IDE_DBG_RQ, "rq->cmd[0]: 0x%x, rq->cmd_flags: 0x%x, " "secs_per_frame: %u", @@ -809,8 +710,8 @@ static ide_startstop_t cdrom_start_rw(ide_drive_t *drive, struct request *rq) } /* fs requests *must* be hardware frame aligned */ - if ((rq->nr_sectors & (sectors_per_frame - 1)) || - (rq->sector & (sectors_per_frame - 1))) + if ((blk_rq_sectors(rq) & (sectors_per_frame - 1)) || + (blk_rq_pos(rq) & (sectors_per_frame - 1))) return ide_stopped; /* use DMA, if possible */ @@ -838,15 +739,10 @@ static void cdrom_do_block_pc(ide_drive_t *drive, struct request *rq) drive->dma = 0; /* sg request */ - if (rq->bio || ((rq->cmd_type == REQ_TYPE_ATA_PC) && rq->data_len)) { + if (rq->bio) { struct request_queue *q = drive->queue; + char *buf = bio_data(rq->bio); unsigned int alignment; - char *buf; - - if (rq->bio) - buf = bio_data(rq->bio); - else - buf = rq->data; drive->dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA); @@ -858,7 +754,7 @@ static void cdrom_do_block_pc(ide_drive_t *drive, struct request *rq) */ alignment = queue_dma_alignment(q) | q->dma_pad_mask; if ((unsigned long)buf & alignment - || rq->data_len & q->dma_pad_mask + || blk_rq_bytes(rq) & q->dma_pad_mask || object_is_on_stack(buf)) drive->dma = 0; } @@ -889,12 +785,11 @@ static ide_startstop_t ide_cd_do_request(ide_drive_t *drive, struct request *rq, /* right now this can only be a reset... */ uptodate = 1; goto out_end; - } else { - blk_dump_rq_flags(rq, DRV_NAME " bad flags"); - if (rq->errors == 0) - rq->errors = -EIO; - goto out_end; - } + } else + BUG(); + + /* prepare sense request for this command */ + ide_prep_sense(drive, rq); memset(&cmd, 0, sizeof(cmd)); @@ -903,15 +798,14 @@ static ide_startstop_t ide_cd_do_request(ide_drive_t *drive, struct request *rq, cmd.rq = rq; - if (blk_fs_request(rq) || rq->data_len) { - ide_init_sg_cmd(&cmd, blk_fs_request(rq) ? (rq->nr_sectors << 9) - : rq->data_len); + if (blk_fs_request(rq) || blk_rq_bytes(rq)) { + ide_init_sg_cmd(&cmd, blk_rq_bytes(rq)); ide_map_sg(drive, &cmd); } return ide_issue_pc(drive, &cmd); out_end: - nsectors = rq->hard_nr_sectors; + nsectors = blk_rq_sectors(rq); if (nsectors == 0) nsectors = 1; @@ -1077,8 +971,8 @@ int ide_cd_read_toc(ide_drive_t *drive, struct request_sense *sense) /* save a private copy of the TOC capacity for error handling */ drive->probed_capacity = toc->capacity * sectors_per_frame; - blk_queue_hardsect_size(drive->queue, - sectors_per_frame << SECTOR_BITS); + blk_queue_logical_block_size(drive->queue, + sectors_per_frame << SECTOR_BITS); /* first read just the header, so we know how long the TOC is */ stat = cdrom_read_tocentry(drive, 0, 1, 0, (char *) &toc->hdr, @@ -1394,9 +1288,9 @@ static int ide_cdrom_probe_capabilities(ide_drive_t *drive) /* standard prep_rq_fn that builds 10 byte cmds */ static int ide_cdrom_prep_fs(struct request_queue *q, struct request *rq) { - int hard_sect = queue_hardsect_size(q); - long block = (long)rq->hard_sector / (hard_sect >> 9); - unsigned long blocks = rq->hard_nr_sectors / (hard_sect >> 9); + int hard_sect = queue_logical_block_size(q); + long block = (long)blk_rq_pos(rq) / (hard_sect >> 9); + unsigned long blocks = blk_rq_sectors(rq) / (hard_sect >> 9); memset(rq->cmd, 0, BLK_MAX_CDB); @@ -1599,7 +1493,7 @@ static int ide_cdrom_setup(ide_drive_t *drive) nslots = ide_cdrom_probe_capabilities(drive); - blk_queue_hardsect_size(q, CD_FRAMESIZE); + blk_queue_logical_block_size(q, CD_FRAMESIZE); if (ide_cdrom_register(drive, nslots)) { printk(KERN_ERR PFX "%s: %s failed to register device with the" diff --git a/drivers/ide/ide-cd.h b/drivers/ide/ide-cd.h index 1d97101099ce..93a3cf1b0f3f 100644 --- a/drivers/ide/ide-cd.h +++ b/drivers/ide/ide-cd.h @@ -87,10 +87,6 @@ struct cdrom_info { struct atapi_toc *toc; - /* The result of the last successful request sense command - on this device. */ - struct request_sense sense_data; - u8 max_speed; /* Max speed of the drive. */ u8 current_speed; /* Current speed of the drive. */ diff --git a/drivers/ide/ide-cs.c b/drivers/ide/ide-cs.c index 9e47f3529d55..527908ff298c 100644 --- a/drivers/ide/ide-cs.c +++ b/drivers/ide/ide-cs.c @@ -155,6 +155,7 @@ static const struct ide_port_info idecs_port_info = { .port_ops = &idecs_port_ops, .host_flags = IDE_HFLAG_NO_DMA, .irq_flags = IRQF_SHARED, + .chipset = ide_pci, }; static struct ide_host *idecs_register(unsigned long io, unsigned long ctl, @@ -163,7 +164,7 @@ static struct ide_host *idecs_register(unsigned long io, unsigned long ctl, struct ide_host *host; ide_hwif_t *hwif; int i, rc; - hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL }; + struct ide_hw hw, *hws[] = { &hw }; if (!request_region(io, 8, DRV_NAME)) { printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX not free.\n", @@ -181,10 +182,9 @@ static struct ide_host *idecs_register(unsigned long io, unsigned long ctl, memset(&hw, 0, sizeof(hw)); ide_std_init_ports(&hw, io, ctl); hw.irq = irq; - hw.chipset = ide_pci; hw.dev = &handle->dev; - rc = ide_host_add(&idecs_port_info, hws, &host); + rc = ide_host_add(&idecs_port_info, hws, 1, &host); if (rc) goto out_release; diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index a9fbe2c31210..695181120cdb 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c @@ -82,7 +82,7 @@ static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq, sector_t block) { ide_hwif_t *hwif = drive->hwif; - u16 nsectors = (u16)rq->nr_sectors; + u16 nsectors = (u16)blk_rq_sectors(rq); u8 lba48 = !!(drive->dev_flags & IDE_DFLAG_LBA48); u8 dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA); struct ide_cmd cmd; @@ -90,7 +90,7 @@ static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq, ide_startstop_t rc; if ((hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA) && lba48 && dma) { - if (block + rq->nr_sectors > 1ULL << 28) + if (block + blk_rq_sectors(rq) > 1ULL << 28) dma = 0; else lba48 = 0; @@ -184,20 +184,13 @@ static ide_startstop_t ide_do_rw_disk(ide_drive_t *drive, struct request *rq, ide_hwif_t *hwif = drive->hwif; BUG_ON(drive->dev_flags & IDE_DFLAG_BLOCKED); - - if (!blk_fs_request(rq)) { - blk_dump_rq_flags(rq, "ide_do_rw_disk - bad command"); - if (rq->errors == 0) - rq->errors = -EIO; - ide_complete_rq(drive, -EIO, ide_rq_bytes(rq)); - return ide_stopped; - } + BUG_ON(!blk_fs_request(rq)); ledtrig_ide_activity(); - pr_debug("%s: %sing: block=%llu, sectors=%lu, buffer=0x%08lx\n", + pr_debug("%s: %sing: block=%llu, sectors=%u, buffer=0x%08lx\n", drive->name, rq_data_dir(rq) == READ ? "read" : "writ", - (unsigned long long)block, rq->nr_sectors, + (unsigned long long)block, blk_rq_sectors(rq), (unsigned long)rq->buffer); if (hwif->rw_disk) @@ -302,14 +295,12 @@ static const struct drive_list_entry hpa_list[] = { { NULL, NULL } }; -static void idedisk_check_hpa(ide_drive_t *drive) +static u64 ide_disk_hpa_get_native_capacity(ide_drive_t *drive, int lba48) { - unsigned long long capacity, set_max; - int lba48 = ata_id_lba48_enabled(drive->id); + u64 capacity, set_max; capacity = drive->capacity64; - - set_max = idedisk_read_native_max_address(drive, lba48); + set_max = idedisk_read_native_max_address(drive, lba48); if (ide_in_drive_list(drive->id, hpa_list)) { /* @@ -320,9 +311,31 @@ static void idedisk_check_hpa(ide_drive_t *drive) set_max--; } + return set_max; +} + +static u64 ide_disk_hpa_set_capacity(ide_drive_t *drive, u64 set_max, int lba48) +{ + set_max = idedisk_set_max_address(drive, set_max, lba48); + if (set_max) + drive->capacity64 = set_max; + + return set_max; +} + +static void idedisk_check_hpa(ide_drive_t *drive) +{ + u64 capacity, set_max; + int lba48 = ata_id_lba48_enabled(drive->id); + + capacity = drive->capacity64; + set_max = ide_disk_hpa_get_native_capacity(drive, lba48); + if (set_max <= capacity) return; + drive->probed_capacity = set_max; + printk(KERN_INFO "%s: Host Protected Area detected.\n" "\tcurrent capacity is %llu sectors (%llu MB)\n" "\tnative capacity is %llu sectors (%llu MB)\n", @@ -330,13 +343,13 @@ static void idedisk_check_hpa(ide_drive_t *drive) capacity, sectors_to_MB(capacity), set_max, sectors_to_MB(set_max)); - set_max = idedisk_set_max_address(drive, set_max, lba48); + if ((drive->dev_flags & IDE_DFLAG_NOHPA) == 0) + return; - if (set_max) { - drive->capacity64 = set_max; + set_max = ide_disk_hpa_set_capacity(drive, set_max, lba48); + if (set_max) printk(KERN_INFO "%s: Host Protected Area disabled.\n", drive->name); - } } static int ide_disk_get_capacity(ide_drive_t *drive) @@ -358,6 +371,8 @@ static int ide_disk_get_capacity(ide_drive_t *drive) drive->capacity64 = drive->cyl * drive->head * drive->sect; } + drive->probed_capacity = drive->capacity64; + if (lba) { drive->dev_flags |= IDE_DFLAG_LBA; @@ -376,7 +391,7 @@ static int ide_disk_get_capacity(ide_drive_t *drive) "%llu sectors (%llu MB)\n", drive->name, (unsigned long long)drive->capacity64, sectors_to_MB(drive->capacity64)); - drive->capacity64 = 1ULL << 28; + drive->probed_capacity = drive->capacity64 = 1ULL << 28; } if ((drive->hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA) && @@ -392,6 +407,34 @@ static int ide_disk_get_capacity(ide_drive_t *drive) return 0; } +static u64 ide_disk_set_capacity(ide_drive_t *drive, u64 capacity) +{ + u64 set = min(capacity, drive->probed_capacity); + u16 *id = drive->id; + int lba48 = ata_id_lba48_enabled(id); + + if ((drive->dev_flags & IDE_DFLAG_LBA) == 0 || + ata_id_hpa_enabled(id) == 0) + goto out; + + /* + * according to the spec the SET MAX ADDRESS command shall be + * immediately preceded by a READ NATIVE MAX ADDRESS command + */ + capacity = ide_disk_hpa_get_native_capacity(drive, lba48); + if (capacity == 0) + goto out; + + set = ide_disk_hpa_set_capacity(drive, set, lba48); + if (set) { + /* needed for ->resume to disable HPA */ + drive->dev_flags |= IDE_DFLAG_NOHPA; + return set; + } +out: + return drive->capacity64; +} + static void idedisk_prepare_flush(struct request_queue *q, struct request *rq) { ide_drive_t *drive = q->queuedata; @@ -411,7 +454,6 @@ static void idedisk_prepare_flush(struct request_queue *q, struct request *rq) cmd->protocol = ATA_PROT_NODATA; rq->cmd_type = REQ_TYPE_ATA_TASKFILE; - rq->cmd_flags |= REQ_SOFTBARRIER; rq->special = cmd; } @@ -429,14 +471,14 @@ static int set_multcount(ide_drive_t *drive, int arg) if (arg < 0 || arg > (drive->id[ATA_ID_MAX_MULTSECT] & 0xff)) return -EINVAL; - if (drive->special.b.set_multmode) + if (drive->special_flags & IDE_SFLAG_SET_MULTMODE) return -EBUSY; rq = blk_get_request(drive->queue, READ, __GFP_WAIT); rq->cmd_type = REQ_TYPE_ATA_TASKFILE; drive->mult_req = arg; - drive->special.b.set_multmode = 1; + drive->special_flags |= IDE_SFLAG_SET_MULTMODE; error = blk_execute_rq(drive->queue, NULL, rq, 0); blk_put_request(rq); @@ -640,7 +682,7 @@ static void ide_disk_setup(ide_drive_t *drive) } printk(KERN_INFO "%s: max request size: %dKiB\n", drive->name, - q->max_sectors / 2); + queue_max_sectors(q) / 2); if (ata_id_is_ssd(id)) queue_flag_set_unlocked(QUEUE_FLAG_NONROT, q); @@ -741,6 +783,7 @@ static int ide_disk_set_doorlock(ide_drive_t *drive, struct gendisk *disk, const struct ide_disk_ops ide_ata_disk_ops = { .check = ide_disk_check, + .set_capacity = ide_disk_set_capacity, .get_capacity = ide_disk_get_capacity, .setup = ide_disk_setup, .flush = ide_disk_flush, diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c index a0b8cab1d9a6..219e6fb78dc6 100644 --- a/drivers/ide/ide-dma.c +++ b/drivers/ide/ide-dma.c @@ -103,7 +103,7 @@ ide_startstop_t ide_dma_intr(ide_drive_t *drive) ide_finish_cmd(drive, cmd, stat); else ide_complete_rq(drive, 0, - cmd->rq->nr_sectors << 9); + blk_rq_sectors(cmd->rq) << 9); return ide_stopped; } printk(KERN_ERR "%s: %s: bad DMA status (0x%02x)\n", @@ -347,7 +347,6 @@ u8 ide_find_dma_mode(ide_drive_t *drive, u8 req_mode) return mode; } -EXPORT_SYMBOL_GPL(ide_find_dma_mode); static int ide_tune_dma(ide_drive_t *drive) { @@ -510,23 +509,11 @@ ide_startstop_t ide_dma_timeout_retry(ide_drive_t *drive, int error) /* * un-busy drive etc and make sure request is sane */ - rq = hwif->rq; - if (!rq) - goto out; - - hwif->rq = NULL; - - rq->errors = 0; - - if (!rq->bio) - goto out; - - rq->sector = rq->bio->bi_sector; - rq->current_nr_sectors = bio_iovec(rq->bio)->bv_len >> 9; - rq->hard_cur_sectors = rq->current_nr_sectors; - rq->buffer = bio_data(rq->bio); -out: + if (rq) { + hwif->rq = NULL; + rq->errors = 0; + } return ret; } diff --git a/drivers/ide/ide-eh.c b/drivers/ide/ide-eh.c index 5d5fb961b5ce..2b9141979613 100644 --- a/drivers/ide/ide-eh.c +++ b/drivers/ide/ide-eh.c @@ -52,7 +52,7 @@ static ide_startstop_t ide_ata_error(ide_drive_t *drive, struct request *rq, } if ((rq->errors & ERROR_RECAL) == ERROR_RECAL) - drive->special.b.recalibrate = 1; + drive->special_flags |= IDE_SFLAG_RECALIBRATE; ++rq->errors; @@ -268,9 +268,8 @@ static void ide_disk_pre_reset(ide_drive_t *drive) { int legacy = (drive->id[ATA_ID_CFS_ENABLE_2] & 0x0400) ? 0 : 1; - drive->special.all = 0; - drive->special.b.set_geometry = legacy; - drive->special.b.recalibrate = legacy; + drive->special_flags = + legacy ? (IDE_SFLAG_SET_GEOMETRY | IDE_SFLAG_RECALIBRATE) : 0; drive->mult_count = 0; drive->dev_flags &= ~IDE_DFLAG_PARKED; @@ -280,7 +279,7 @@ static void ide_disk_pre_reset(ide_drive_t *drive) drive->mult_req = 0; if (drive->mult_req != drive->mult_count) - drive->special.b.set_multmode = 1; + drive->special_flags |= IDE_SFLAG_SET_MULTMODE; } static void pre_reset(ide_drive_t *drive) @@ -408,8 +407,9 @@ static ide_startstop_t do_reset1(ide_drive_t *drive, int do_not_try_atapi) /* more than enough time */ udelay(10); /* clear SRST, leave nIEN (unless device is on the quirk list) */ - tp_ops->write_devctl(hwif, (drive->quirk_list == 2 ? 0 : ATA_NIEN) | - ATA_DEVCTL_OBS); + tp_ops->write_devctl(hwif, + ((drive->dev_flags & IDE_DFLAG_NIEN_QUIRK) ? 0 : ATA_NIEN) | + ATA_DEVCTL_OBS); /* more than enough time */ udelay(10); hwif->poll_timeout = jiffies + WAIT_WORSTCASE; diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c index 2b4868d95f8b..8b3f204f7d73 100644 --- a/drivers/ide/ide-floppy.c +++ b/drivers/ide/ide-floppy.c @@ -77,7 +77,8 @@ static int ide_floppy_callback(ide_drive_t *drive, int dsc) (rq && blk_pc_request(rq))) uptodate = 1; /* FIXME */ else if (pc->c[0] == GPCMD_REQUEST_SENSE) { - u8 *buf = pc->buf; + + u8 *buf = bio_data(rq->bio); if (!pc->error) { floppy->sense_key = buf[2] & 0x0F; @@ -134,13 +135,17 @@ static ide_startstop_t ide_floppy_issue_pc(ide_drive_t *drive, drive->pc = pc; if (pc->retries > IDEFLOPPY_MAX_PC_RETRIES) { + unsigned int done = blk_rq_bytes(drive->hwif->rq); + if (!(pc->flags & PC_FLAG_SUPPRESS_ERROR)) ide_floppy_report_error(floppy, pc); + /* Giving up */ pc->error = IDE_DRV_ERROR_GENERAL; drive->failed_pc = NULL; drive->pc_callback(drive, 0); + ide_complete_rq(drive, -EIO, done); return ide_stopped; } @@ -190,7 +195,7 @@ static void idefloppy_create_rw_cmd(ide_drive_t *drive, { struct ide_disk_obj *floppy = drive->driver_data; int block = sector / floppy->bs_factor; - int blocks = rq->nr_sectors / floppy->bs_factor; + int blocks = blk_rq_sectors(rq) / floppy->bs_factor; int cmd = rq_data_dir(rq); ide_debug_log(IDE_DBG_FUNC, "block: %d, blocks: %d", block, blocks); @@ -205,8 +210,7 @@ static void idefloppy_create_rw_cmd(ide_drive_t *drive, pc->rq = rq; if (rq->cmd_flags & REQ_RW) pc->flags |= PC_FLAG_WRITING; - pc->buf = NULL; - pc->req_xfer = pc->buf_size = blocks * floppy->block_size; + pc->flags |= PC_FLAG_DMA_OK; } @@ -216,16 +220,11 @@ static void idefloppy_blockpc_cmd(struct ide_disk_obj *floppy, ide_init_pc(pc); memcpy(pc->c, rq->cmd, sizeof(pc->c)); pc->rq = rq; - if (rq->data_len && rq_data_dir(rq) == WRITE) - pc->flags |= PC_FLAG_WRITING; - pc->buf = rq->data; - if (rq->bio) + if (blk_rq_bytes(rq)) { pc->flags |= PC_FLAG_DMA_OK; - /* - * possibly problematic, doesn't look like ide-floppy correctly - * handled scattered requests if dma fails... - */ - pc->req_xfer = pc->buf_size = rq->data_len; + if (rq_data_dir(rq) == WRITE) + pc->flags |= PC_FLAG_WRITING; + } } static ide_startstop_t ide_floppy_do_request(ide_drive_t *drive, @@ -257,23 +256,23 @@ static ide_startstop_t ide_floppy_do_request(ide_drive_t *drive, goto out_end; } if (blk_fs_request(rq)) { - if (((long)rq->sector % floppy->bs_factor) || - (rq->nr_sectors % floppy->bs_factor)) { + if (((long)blk_rq_pos(rq) % floppy->bs_factor) || + (blk_rq_sectors(rq) % floppy->bs_factor)) { printk(KERN_ERR PFX "%s: unsupported r/w rq size\n", drive->name); goto out_end; } pc = &floppy->queued_pc; idefloppy_create_rw_cmd(drive, pc, rq, (unsigned long)block); - } else if (blk_special_request(rq)) { - pc = (struct ide_atapi_pc *) rq->buffer; + } else if (blk_special_request(rq) || blk_sense_request(rq)) { + pc = (struct ide_atapi_pc *)rq->special; } else if (blk_pc_request(rq)) { pc = &floppy->queued_pc; idefloppy_blockpc_cmd(floppy, pc, rq); - } else { - blk_dump_rq_flags(rq, PFX "unsupported command in queue"); - goto out_end; - } + } else + BUG(); + + ide_prep_sense(drive, rq); memset(&cmd, 0, sizeof(cmd)); @@ -282,8 +281,8 @@ static ide_startstop_t ide_floppy_do_request(ide_drive_t *drive, cmd.rq = rq; - if (blk_fs_request(rq) || pc->req_xfer) { - ide_init_sg_cmd(&cmd, pc->req_xfer); + if (blk_fs_request(rq) || blk_rq_bytes(rq)) { + ide_init_sg_cmd(&cmd, blk_rq_bytes(rq)); ide_map_sg(drive, &cmd); } @@ -307,33 +306,33 @@ static int ide_floppy_get_flexible_disk_page(ide_drive_t *drive, { struct ide_disk_obj *floppy = drive->driver_data; struct gendisk *disk = floppy->disk; - u8 *page; + u8 *page, buf[40]; int capacity, lba_capacity; u16 transfer_rate, sector_size, cyls, rpm; u8 heads, sectors; ide_floppy_create_mode_sense_cmd(pc, IDEFLOPPY_FLEXIBLE_DISK_PAGE); - if (ide_queue_pc_tail(drive, disk, pc)) { + if (ide_queue_pc_tail(drive, disk, pc, buf, pc->req_xfer)) { printk(KERN_ERR PFX "Can't get flexible disk page params\n"); return 1; } - if (pc->buf[3] & 0x80) + if (buf[3] & 0x80) drive->dev_flags |= IDE_DFLAG_WP; else drive->dev_flags &= ~IDE_DFLAG_WP; set_disk_ro(disk, !!(drive->dev_flags & IDE_DFLAG_WP)); - page = &pc->buf[8]; + page = &buf[8]; - transfer_rate = be16_to_cpup((__be16 *)&pc->buf[8 + 2]); - sector_size = be16_to_cpup((__be16 *)&pc->buf[8 + 6]); - cyls = be16_to_cpup((__be16 *)&pc->buf[8 + 8]); - rpm = be16_to_cpup((__be16 *)&pc->buf[8 + 28]); - heads = pc->buf[8 + 4]; - sectors = pc->buf[8 + 5]; + transfer_rate = be16_to_cpup((__be16 *)&buf[8 + 2]); + sector_size = be16_to_cpup((__be16 *)&buf[8 + 6]); + cyls = be16_to_cpup((__be16 *)&buf[8 + 8]); + rpm = be16_to_cpup((__be16 *)&buf[8 + 28]); + heads = buf[8 + 4]; + sectors = buf[8 + 5]; capacity = cyls * heads * sectors * sector_size; @@ -383,22 +382,19 @@ static int ide_floppy_get_capacity(ide_drive_t *drive) drive->capacity64 = 0; ide_floppy_create_read_capacity_cmd(&pc); - pc.buf = &pc_buf[0]; - pc.buf_size = sizeof(pc_buf); - - if (ide_queue_pc_tail(drive, disk, &pc)) { + if (ide_queue_pc_tail(drive, disk, &pc, pc_buf, pc.req_xfer)) { printk(KERN_ERR PFX "Can't get floppy parameters\n"); return 1; } - header_len = pc.buf[3]; - cap_desc = &pc.buf[4]; + header_len = pc_buf[3]; + cap_desc = &pc_buf[4]; desc_cnt = header_len / 8; /* capacity descriptor of 8 bytes */ for (i = 0; i < desc_cnt; i++) { unsigned int desc_start = 4 + i*8; - blocks = be32_to_cpup((__be32 *)&pc.buf[desc_start]); - length = be16_to_cpup((__be16 *)&pc.buf[desc_start + 6]); + blocks = be32_to_cpup((__be32 *)&pc_buf[desc_start]); + length = be16_to_cpup((__be16 *)&pc_buf[desc_start + 6]); ide_debug_log(IDE_DBG_PROBE, "Descriptor %d: %dkB, %d blocks, " "%d sector size", @@ -411,7 +407,7 @@ static int ide_floppy_get_capacity(ide_drive_t *drive) * the code below is valid only for the 1st descriptor, ie i=0 */ - switch (pc.buf[desc_start + 4] & 0x03) { + switch (pc_buf[desc_start + 4] & 0x03) { /* Clik! drive returns this instead of CAPACITY_CURRENT */ case CAPACITY_UNFORMATTED: if (!(drive->atapi_flags & IDE_AFLAG_CLIK_DRIVE)) @@ -460,7 +456,7 @@ static int ide_floppy_get_capacity(ide_drive_t *drive) break; } ide_debug_log(IDE_DBG_PROBE, "Descriptor 0 Code: %d", - pc.buf[desc_start + 4] & 0x03); + pc_buf[desc_start + 4] & 0x03); } /* Clik! disk does not support get_flexible_disk_page */ diff --git a/drivers/ide/ide-floppy_ioctl.c b/drivers/ide/ide-floppy_ioctl.c index cd8a42027ede..9c2288234dea 100644 --- a/drivers/ide/ide-floppy_ioctl.c +++ b/drivers/ide/ide-floppy_ioctl.c @@ -47,15 +47,13 @@ static int ide_floppy_get_format_capacities(ide_drive_t *drive, return -EINVAL; ide_floppy_create_read_capacity_cmd(pc); - pc->buf = &pc_buf[0]; - pc->buf_size = sizeof(pc_buf); - if (ide_queue_pc_tail(drive, floppy->disk, pc)) { + if (ide_queue_pc_tail(drive, floppy->disk, pc, pc_buf, pc->req_xfer)) { printk(KERN_ERR "ide-floppy: Can't get floppy parameters\n"); return -EIO; } - header_len = pc->buf[3]; + header_len = pc_buf[3]; desc_cnt = header_len / 8; /* capacity descriptor of 8 bytes */ u_index = 0; @@ -72,8 +70,8 @@ static int ide_floppy_get_format_capacities(ide_drive_t *drive, if (u_index >= u_array_size) break; /* User-supplied buffer too small */ - blocks = be32_to_cpup((__be32 *)&pc->buf[desc_start]); - length = be16_to_cpup((__be16 *)&pc->buf[desc_start + 6]); + blocks = be32_to_cpup((__be32 *)&pc_buf[desc_start]); + length = be16_to_cpup((__be16 *)&pc_buf[desc_start + 6]); if (put_user(blocks, argp)) return -EFAULT; @@ -94,40 +92,42 @@ static int ide_floppy_get_format_capacities(ide_drive_t *drive, return 0; } -static void ide_floppy_create_format_unit_cmd(struct ide_atapi_pc *pc, int b, - int l, int flags) +static void ide_floppy_create_format_unit_cmd(struct ide_atapi_pc *pc, + u8 *buf, int b, int l, + int flags) { ide_init_pc(pc); pc->c[0] = GPCMD_FORMAT_UNIT; pc->c[1] = 0x17; - memset(pc->buf, 0, 12); - pc->buf[1] = 0xA2; + memset(buf, 0, 12); + buf[1] = 0xA2; /* Default format list header, u8 1: FOV/DCRT/IMM bits set */ if (flags & 1) /* Verify bit on... */ - pc->buf[1] ^= 0x20; /* ... turn off DCRT bit */ - pc->buf[3] = 8; + buf[1] ^= 0x20; /* ... turn off DCRT bit */ + buf[3] = 8; - put_unaligned(cpu_to_be32(b), (unsigned int *)(&pc->buf[4])); - put_unaligned(cpu_to_be32(l), (unsigned int *)(&pc->buf[8])); - pc->buf_size = 12; + put_unaligned(cpu_to_be32(b), (unsigned int *)(&buf[4])); + put_unaligned(cpu_to_be32(l), (unsigned int *)(&buf[8])); + pc->req_xfer = 12; pc->flags |= PC_FLAG_WRITING; } static int ide_floppy_get_sfrp_bit(ide_drive_t *drive, struct ide_atapi_pc *pc) { struct ide_disk_obj *floppy = drive->driver_data; + u8 buf[20]; drive->atapi_flags &= ~IDE_AFLAG_SRFP; ide_floppy_create_mode_sense_cmd(pc, IDEFLOPPY_CAPABILITIES_PAGE); pc->flags |= PC_FLAG_SUPPRESS_ERROR; - if (ide_queue_pc_tail(drive, floppy->disk, pc)) + if (ide_queue_pc_tail(drive, floppy->disk, pc, buf, pc->req_xfer)) return 1; - if (pc->buf[8 + 2] & 0x40) + if (buf[8 + 2] & 0x40) drive->atapi_flags |= IDE_AFLAG_SRFP; return 0; @@ -137,6 +137,7 @@ static int ide_floppy_format_unit(ide_drive_t *drive, struct ide_atapi_pc *pc, int __user *arg) { struct ide_disk_obj *floppy = drive->driver_data; + u8 buf[12]; int blocks, length, flags, err = 0; if (floppy->openers > 1) { @@ -170,9 +171,9 @@ static int ide_floppy_format_unit(ide_drive_t *drive, struct ide_atapi_pc *pc, } ide_floppy_get_sfrp_bit(drive, pc); - ide_floppy_create_format_unit_cmd(pc, blocks, length, flags); + ide_floppy_create_format_unit_cmd(pc, buf, blocks, length, flags); - if (ide_queue_pc_tail(drive, floppy->disk, pc)) + if (ide_queue_pc_tail(drive, floppy->disk, pc, buf, pc->req_xfer)) err = -EIO; out: @@ -196,11 +197,13 @@ static int ide_floppy_get_format_progress(ide_drive_t *drive, int __user *arg) { struct ide_disk_obj *floppy = drive->driver_data; + u8 sense_buf[18]; int progress_indication = 0x10000; if (drive->atapi_flags & IDE_AFLAG_SRFP) { ide_create_request_sense_cmd(drive, pc); - if (ide_queue_pc_tail(drive, floppy->disk, pc)) + if (ide_queue_pc_tail(drive, floppy->disk, pc, sense_buf, + pc->req_xfer)) return -EIO; if (floppy->sense_key == 2 && diff --git a/drivers/ide/ide-gd.c b/drivers/ide/ide-gd.c index 4b6b71e2cdf5..214119026b3f 100644 --- a/drivers/ide/ide-gd.c +++ b/drivers/ide/ide-gd.c @@ -287,6 +287,19 @@ static int ide_gd_media_changed(struct gendisk *disk) return ret; } +static unsigned long long ide_gd_set_capacity(struct gendisk *disk, + unsigned long long capacity) +{ + struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj); + ide_drive_t *drive = idkp->drive; + const struct ide_disk_ops *disk_ops = drive->disk_ops; + + if (disk_ops->set_capacity) + return disk_ops->set_capacity(drive, capacity); + + return drive->capacity64; +} + static int ide_gd_revalidate_disk(struct gendisk *disk) { struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj); @@ -315,6 +328,7 @@ static struct block_device_operations ide_gd_ops = { .locked_ioctl = ide_gd_ioctl, .getgeo = ide_gd_getgeo, .media_changed = ide_gd_media_changed, + .set_capacity = ide_gd_set_capacity, .revalidate_disk = ide_gd_revalidate_disk }; diff --git a/drivers/ide/ide-generic.c b/drivers/ide/ide-generic.c index 7812ca0be13b..54d7c4685d23 100644 --- a/drivers/ide/ide-generic.c +++ b/drivers/ide/ide-generic.c @@ -29,6 +29,7 @@ MODULE_PARM_DESC(probe_mask, "probe mask for legacy ISA IDE ports"); static const struct ide_port_info ide_generic_port_info = { .host_flags = IDE_HFLAG_NO_DMA, + .chipset = ide_generic, }; #ifdef CONFIG_ARM @@ -85,7 +86,7 @@ static void ide_generic_check_pci_legacy_iobases(int *primary, int *secondary) static int __init ide_generic_init(void) { - hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL }; + struct ide_hw hw, *hws[] = { &hw }; unsigned long io_addr; int i, rc = 0, primary = 0, secondary = 0; @@ -132,9 +133,7 @@ static int __init ide_generic_init(void) #else hw.irq = legacy_irqs[i]; #endif - hw.chipset = ide_generic; - - rc = ide_host_add(&ide_generic_port_info, hws, NULL); + rc = ide_host_add(&ide_generic_port_info, hws, 1, NULL); if (rc) { release_region(io_addr + 0x206, 1); release_region(io_addr, 8); diff --git a/drivers/ide/ide-h8300.c b/drivers/ide/ide-h8300.c index c06ebdc4a130..520f42c5445a 100644 --- a/drivers/ide/ide-h8300.c +++ b/drivers/ide/ide-h8300.c @@ -64,26 +64,26 @@ static const struct ide_tp_ops h8300_tp_ops = { #define H8300_IDE_GAP (2) -static inline void hw_setup(hw_regs_t *hw) +static inline void hw_setup(struct ide_hw *hw) { int i; - memset(hw, 0, sizeof(hw_regs_t)); + memset(hw, 0, sizeof(*hw)); for (i = 0; i <= 7; i++) hw->io_ports_array[i] = CONFIG_H8300_IDE_BASE + H8300_IDE_GAP*i; hw->io_ports.ctl_addr = CONFIG_H8300_IDE_ALT; hw->irq = EXT_IRQ0 + CONFIG_H8300_IDE_IRQ; - hw->chipset = ide_generic; } static const struct ide_port_info h8300_port_info = { .tp_ops = &h8300_tp_ops, .host_flags = IDE_HFLAG_NO_IO_32BIT | IDE_HFLAG_NO_DMA, + .chipset = ide_generic, }; static int __init h8300_ide_init(void) { - hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL }; + struct ide_hw hw, *hws[] = { &hw }; printk(KERN_INFO DRV_NAME ": H8/300 generic IDE interface\n"); @@ -96,7 +96,7 @@ static int __init h8300_ide_init(void) hw_setup(&hw); - return ide_host_add(&h8300_port_info, hws, NULL); + return ide_host_add(&h8300_port_info, hws, 1, NULL); out_busy: printk(KERN_ERR "ide-h8300: IDE I/F resource already used.\n"); diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index 6415a2e2ba87..1059f809b809 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -116,9 +116,9 @@ void ide_complete_cmd(ide_drive_t *drive, struct ide_cmd *cmd, u8 stat, u8 err) unsigned int ide_rq_bytes(struct request *rq) { if (blk_pc_request(rq)) - return rq->data_len; + return blk_rq_bytes(rq); else - return rq->hard_cur_sectors << 9; + return blk_rq_cur_sectors(rq) << 9; } EXPORT_SYMBOL_GPL(ide_rq_bytes); @@ -133,7 +133,7 @@ int ide_complete_rq(ide_drive_t *drive, int error, unsigned int nr_bytes) * and complete the whole request right now */ if (blk_noretry_request(rq) && error <= 0) - nr_bytes = rq->hard_nr_sectors << 9; + nr_bytes = blk_rq_sectors(rq) << 9; rc = ide_end_rq(drive, rq, error, nr_bytes); if (rc == 0) @@ -184,29 +184,42 @@ static void ide_tf_set_setmult_cmd(ide_drive_t *drive, struct ide_taskfile *tf) tf->command = ATA_CMD_SET_MULTI; } -static ide_startstop_t ide_disk_special(ide_drive_t *drive) +/** + * do_special - issue some special commands + * @drive: drive the command is for + * + * do_special() is used to issue ATA_CMD_INIT_DEV_PARAMS, + * ATA_CMD_RESTORE and ATA_CMD_SET_MULTI commands to a drive. + */ + +static ide_startstop_t do_special(ide_drive_t *drive) { - special_t *s = &drive->special; struct ide_cmd cmd; +#ifdef DEBUG + printk(KERN_DEBUG "%s: %s: 0x%02x\n", drive->name, __func__, + drive->special_flags); +#endif + if (drive->media != ide_disk) { + drive->special_flags = 0; + drive->mult_req = 0; + return ide_stopped; + } + memset(&cmd, 0, sizeof(cmd)); cmd.protocol = ATA_PROT_NODATA; - if (s->b.set_geometry) { - s->b.set_geometry = 0; + if (drive->special_flags & IDE_SFLAG_SET_GEOMETRY) { + drive->special_flags &= ~IDE_SFLAG_SET_GEOMETRY; ide_tf_set_specify_cmd(drive, &cmd.tf); - } else if (s->b.recalibrate) { - s->b.recalibrate = 0; + } else if (drive->special_flags & IDE_SFLAG_RECALIBRATE) { + drive->special_flags &= ~IDE_SFLAG_RECALIBRATE; ide_tf_set_restore_cmd(drive, &cmd.tf); - } else if (s->b.set_multmode) { - s->b.set_multmode = 0; + } else if (drive->special_flags & IDE_SFLAG_SET_MULTMODE) { + drive->special_flags &= ~IDE_SFLAG_SET_MULTMODE; ide_tf_set_setmult_cmd(drive, &cmd.tf); - } else if (s->all) { - int special = s->all; - s->all = 0; - printk(KERN_ERR "%s: bad special flag: 0x%02x\n", drive->name, special); - return ide_stopped; - } + } else + BUG(); cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE; @@ -217,45 +230,13 @@ static ide_startstop_t ide_disk_special(ide_drive_t *drive) return ide_started; } -/** - * do_special - issue some special commands - * @drive: drive the command is for - * - * do_special() is used to issue ATA_CMD_INIT_DEV_PARAMS, - * ATA_CMD_RESTORE and ATA_CMD_SET_MULTI commands to a drive. - * - * It used to do much more, but has been scaled back. - */ - -static ide_startstop_t do_special (ide_drive_t *drive) -{ - special_t *s = &drive->special; - -#ifdef DEBUG - printk("%s: do_special: 0x%02x\n", drive->name, s->all); -#endif - if (drive->media == ide_disk) - return ide_disk_special(drive); - - s->all = 0; - drive->mult_req = 0; - return ide_stopped; -} - void ide_map_sg(ide_drive_t *drive, struct ide_cmd *cmd) { ide_hwif_t *hwif = drive->hwif; struct scatterlist *sg = hwif->sg_table; struct request *rq = cmd->rq; - if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) { - sg_init_one(sg, rq->buffer, rq->nr_sectors * SECTOR_SIZE); - cmd->sg_nents = 1; - } else if (!rq->bio) { - sg_init_one(sg, rq->data, rq->data_len); - cmd->sg_nents = 1; - } else - cmd->sg_nents = blk_rq_map_sg(drive->queue, rq, sg); + cmd->sg_nents = blk_rq_map_sg(drive->queue, rq, sg); } EXPORT_SYMBOL_GPL(ide_map_sg); @@ -286,7 +267,7 @@ static ide_startstop_t execute_drive_cmd (ide_drive_t *drive, if (cmd) { if (cmd->protocol == ATA_PROT_PIO) { - ide_init_sg_cmd(cmd, rq->nr_sectors << 9); + ide_init_sg_cmd(cmd, blk_rq_sectors(rq) << 9); ide_map_sg(drive, cmd); } @@ -358,7 +339,8 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq) printk(KERN_ERR "%s: drive not ready for command\n", drive->name); return startstop; } - if (!drive->special.all) { + + if (drive->special_flags == 0) { struct ide_driver *drv; /* @@ -371,7 +353,7 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq) if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) return execute_drive_cmd(drive, rq); else if (blk_pm_request(rq)) { - struct request_pm_state *pm = rq->data; + struct request_pm_state *pm = rq->special; #ifdef DEBUG_PM printk("%s: start_power_step(step: %d)\n", drive->name, pm->pm_step); @@ -394,7 +376,7 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq) drv = *(struct ide_driver **)rq->rq_disk->private_data; - return drv->do_request(drive, rq, rq->sector); + return drv->do_request(drive, rq, blk_rq_pos(rq)); } return do_special(drive); kill_rq: @@ -484,6 +466,9 @@ void do_ide_request(struct request_queue *q) spin_unlock_irq(q->queue_lock); + /* HLD do_request() callback might sleep, make sure it's okay */ + might_sleep(); + if (ide_lock_host(host, hwif)) goto plug_device_2; @@ -491,10 +476,10 @@ void do_ide_request(struct request_queue *q) if (!ide_lock_port(hwif)) { ide_hwif_t *prev_port; + + WARN_ON_ONCE(hwif->rq); repeat: prev_port = hwif->host->cur_port; - hwif->rq = NULL; - if (drive->dev_flags & IDE_DFLAG_SLEEPING && time_after(drive->sleep, jiffies)) { ide_unlock_port(hwif); @@ -503,11 +488,15 @@ repeat: if ((hwif->host->host_flags & IDE_HFLAG_SERIALIZE) && hwif != prev_port) { + ide_drive_t *cur_dev = + prev_port ? prev_port->cur_dev : NULL; + /* * set nIEN for previous port, drives in the - * quirk_list may not like intr setups/cleanups + * quirk list may not like intr setups/cleanups */ - if (prev_port && prev_port->cur_dev->quirk_list == 0) + if (cur_dev && + (cur_dev->dev_flags & IDE_DFLAG_NIEN_QUIRK) == 0) prev_port->tp_ops->write_devctl(prev_port, ATA_NIEN | ATA_DEVCTL_OBS); @@ -523,7 +512,9 @@ repeat: * we know that the queue isn't empty, but this can happen * if the q->prep_rq_fn() decides to kill a request */ - rq = elv_next_request(drive->queue); + if (!rq) + rq = blk_fetch_request(drive->queue); + spin_unlock_irq(q->queue_lock); spin_lock_irq(&hwif->lock); @@ -535,7 +526,7 @@ repeat: /* * Sanity: don't accept a request that isn't a PM request * if we are currently power managed. This is very important as - * blk_stop_queue() doesn't prevent the elv_next_request() + * blk_stop_queue() doesn't prevent the blk_fetch_request() * above to return us whatever is in the queue. Since we call * ide_do_request() ourselves, we end up taking requests while * the queue is blocked... @@ -559,8 +550,11 @@ repeat: startstop = start_request(drive, rq); spin_lock_irq(&hwif->lock); - if (startstop == ide_stopped) + if (startstop == ide_stopped) { + rq = hwif->rq; + hwif->rq = NULL; goto repeat; + } } else goto plug_device; out: @@ -576,18 +570,24 @@ plug_device: plug_device_2: spin_lock_irq(q->queue_lock); + if (rq) + blk_requeue_request(q, rq); if (!elv_queue_empty(q)) blk_plug_device(q); } -static void ide_plug_device(ide_drive_t *drive) +static void ide_requeue_and_plug(ide_drive_t *drive, struct request *rq) { struct request_queue *q = drive->queue; unsigned long flags; spin_lock_irqsave(q->queue_lock, flags); + + if (rq) + blk_requeue_request(q, rq); if (!elv_queue_empty(q)) blk_plug_device(q); + spin_unlock_irqrestore(q->queue_lock, flags); } @@ -636,6 +636,7 @@ void ide_timer_expiry (unsigned long data) unsigned long flags; int wait = -1; int plug_device = 0; + struct request *uninitialized_var(rq_in_flight); spin_lock_irqsave(&hwif->lock, flags); @@ -682,8 +683,9 @@ void ide_timer_expiry (unsigned long data) } else if (drive_is_ready(drive)) { if (drive->waiting_for_dma) hwif->dma_ops->dma_lost_irq(drive); - if (hwif->ack_intr) - hwif->ack_intr(hwif); + if (hwif->port_ops && hwif->port_ops->clear_irq) + hwif->port_ops->clear_irq(drive); + printk(KERN_WARNING "%s: lost interrupt\n", drive->name); startstop = handler(drive); @@ -697,6 +699,8 @@ void ide_timer_expiry (unsigned long data) spin_lock_irq(&hwif->lock); enable_irq(hwif->irq); if (startstop == ide_stopped && hwif->polling == 0) { + rq_in_flight = hwif->rq; + hwif->rq = NULL; ide_unlock_port(hwif); plug_device = 1; } @@ -705,7 +709,7 @@ void ide_timer_expiry (unsigned long data) if (plug_device) { ide_unlock_host(hwif->host); - ide_plug_device(drive); + ide_requeue_and_plug(drive, rq_in_flight); } } @@ -791,6 +795,7 @@ irqreturn_t ide_intr (int irq, void *dev_id) ide_startstop_t startstop; irqreturn_t irq_ret = IRQ_NONE; int plug_device = 0; + struct request *uninitialized_var(rq_in_flight); if (host->host_flags & IDE_HFLAG_SERIALIZE) { if (hwif != host->cur_port) @@ -799,7 +804,8 @@ irqreturn_t ide_intr (int irq, void *dev_id) spin_lock_irqsave(&hwif->lock, flags); - if (hwif->ack_intr && hwif->ack_intr(hwif) == 0) + if (hwif->port_ops && hwif->port_ops->test_irq && + hwif->port_ops->test_irq(hwif) == 0) goto out; handler = hwif->handler; @@ -870,6 +876,8 @@ irqreturn_t ide_intr (int irq, void *dev_id) */ if (startstop == ide_stopped && hwif->polling == 0) { BUG_ON(hwif->handler); + rq_in_flight = hwif->rq; + hwif->rq = NULL; ide_unlock_port(hwif); plug_device = 1; } @@ -879,7 +887,7 @@ out: out_early: if (plug_device) { ide_unlock_host(hwif->host); - ide_plug_device(drive); + ide_requeue_and_plug(drive, rq_in_flight); } return irq_ret; diff --git a/drivers/ide/ide-ioctls.c b/drivers/ide/ide-ioctls.c index c1c25ebbaa1f..82f252c3ee6e 100644 --- a/drivers/ide/ide-ioctls.c +++ b/drivers/ide/ide-ioctls.c @@ -118,7 +118,6 @@ static int ide_cmd_ioctl(ide_drive_t *drive, unsigned long arg) u8 args[4], xfer_rate = 0; struct ide_cmd cmd; struct ide_taskfile *tf = &cmd.tf; - u16 *id = drive->id; if (NULL == (void *) arg) { struct request *rq; @@ -161,14 +160,10 @@ static int ide_cmd_ioctl(ide_drive_t *drive, unsigned long arg) if (tf->command == ATA_CMD_SET_FEATURES && tf->feature == SETFEATURES_XFER && - tf->nsect >= XFER_SW_DMA_0 && - (id[ATA_ID_UDMA_MODES] || - id[ATA_ID_MWDMA_MODES] || - id[ATA_ID_SWDMA_MODES])) { - xfer_rate = args[1]; - if (tf->nsect > XFER_UDMA_2 && !eighty_ninty_three(drive)) { - printk(KERN_WARNING "%s: UDMA speeds >UDMA33 cannot " - "be set\n", drive->name); + tf->nsect >= XFER_SW_DMA_0) { + xfer_rate = ide_find_dma_mode(drive, XFER_UDMA_6); + if (xfer_rate != tf->nsect) { + err = -EINVAL; goto abort; } } @@ -231,7 +226,6 @@ static int generic_drive_reset(ide_drive_t *drive) rq->cmd_type = REQ_TYPE_SPECIAL; rq->cmd_len = 1; rq->cmd[0] = REQ_DRIVE_RESET; - rq->cmd_flags |= REQ_SOFTBARRIER; if (blk_execute_rq(drive->queue, NULL, rq, 1)) ret = rq->errors; blk_put_request(rq); diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c index 06fe002116ec..fa047150a1c6 100644 --- a/drivers/ide/ide-iops.c +++ b/drivers/ide/ide-iops.c @@ -282,6 +282,29 @@ no_80w: return 0; } +static const char *nien_quirk_list[] = { + "QUANTUM FIREBALLlct08 08", + "QUANTUM FIREBALLP KA6.4", + "QUANTUM FIREBALLP KA9.1", + "QUANTUM FIREBALLP KX13.6", + "QUANTUM FIREBALLP KX20.5", + "QUANTUM FIREBALLP KX27.3", + "QUANTUM FIREBALLP LM20.4", + "QUANTUM FIREBALLP LM20.5", + NULL +}; + +void ide_check_nien_quirk_list(ide_drive_t *drive) +{ + const char **list, *m = (char *)&drive->id[ATA_ID_PROD]; + + for (list = nien_quirk_list; *list != NULL; list++) + if (strstr(m, *list) != NULL) { + drive->dev_flags |= IDE_DFLAG_NIEN_QUIRK; + return; + } +} + int ide_driveid_update(ide_drive_t *drive) { u16 *id; @@ -311,7 +334,6 @@ int ide_driveid_update(ide_drive_t *drive) return 1; out_err: - SELECT_MASK(drive, 0); if (rc == 2) printk(KERN_ERR "%s: %s: bad status\n", drive->name, __func__); kfree(id); @@ -365,7 +387,7 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed) tp_ops->exec_command(hwif, ATA_CMD_SET_FEATURES); - if (drive->quirk_list == 2) + if (drive->dev_flags & IDE_DFLAG_NIEN_QUIRK) tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS); error = __ide_wait_stat(drive, drive->ready_stat, diff --git a/drivers/ide/ide-legacy.c b/drivers/ide/ide-legacy.c index 8c5dcbf22547..b9654a7bb7be 100644 --- a/drivers/ide/ide-legacy.c +++ b/drivers/ide/ide-legacy.c @@ -1,7 +1,7 @@ #include #include -static void ide_legacy_init_one(hw_regs_t **hws, hw_regs_t *hw, +static void ide_legacy_init_one(struct ide_hw **hws, struct ide_hw *hw, u8 port_no, const struct ide_port_info *d, unsigned long config) { @@ -33,7 +33,6 @@ static void ide_legacy_init_one(hw_regs_t **hws, hw_regs_t *hw, ide_std_init_ports(hw, base, ctl); hw->irq = irq; - hw->chipset = d->chipset; hw->config = config; hws[port_no] = hw; @@ -41,7 +40,7 @@ static void ide_legacy_init_one(hw_regs_t **hws, hw_regs_t *hw, int ide_legacy_device_add(const struct ide_port_info *d, unsigned long config) { - hw_regs_t hw[2], *hws[] = { NULL, NULL, NULL, NULL }; + struct ide_hw hw[2], *hws[] = { NULL, NULL }; memset(&hw, 0, sizeof(hw)); @@ -53,6 +52,6 @@ int ide_legacy_device_add(const struct ide_port_info *d, unsigned long config) (d->host_flags & IDE_HFLAG_SINGLE)) return -ENOENT; - return ide_host_add(d, hws, NULL); + return ide_host_add(d, hws, 2, NULL); } EXPORT_SYMBOL_GPL(ide_legacy_device_add); diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c index 2148df836ce7..e386a32dc9ba 100644 --- a/drivers/ide/ide-lib.c +++ b/drivers/ide/ide-lib.c @@ -96,7 +96,7 @@ static void ide_dump_ata_error(ide_drive_t *drive, u8 err) if (rq) printk(KERN_CONT ", sector=%llu", - (unsigned long long)rq->sector); + (unsigned long long)blk_rq_pos(rq)); } printk(KERN_CONT "\n"); } diff --git a/drivers/ide/ide-park.c b/drivers/ide/ide-park.c index 310d03f2b5b7..a914023d6d03 100644 --- a/drivers/ide/ide-park.c +++ b/drivers/ide/ide-park.c @@ -24,11 +24,8 @@ static void issue_park_cmd(ide_drive_t *drive, unsigned long timeout) start_queue = 1; spin_unlock_irq(&hwif->lock); - if (start_queue) { - spin_lock_irq(q->queue_lock); - blk_start_queueing(q); - spin_unlock_irq(q->queue_lock); - } + if (start_queue) + blk_run_queue(q); return; } spin_unlock_irq(&hwif->lock); diff --git a/drivers/ide/ide-pm.c b/drivers/ide/ide-pm.c index 0d8a151c0a01..c14ca144cffe 100644 --- a/drivers/ide/ide-pm.c +++ b/drivers/ide/ide-pm.c @@ -3,11 +3,11 @@ int generic_ide_suspend(struct device *dev, pm_message_t mesg) { - ide_drive_t *drive = dev->driver_data, *pair = ide_get_pair_dev(drive); + ide_drive_t *drive = dev_get_drvdata(dev); + ide_drive_t *pair = ide_get_pair_dev(drive); ide_hwif_t *hwif = drive->hwif; struct request *rq; struct request_pm_state rqpm; - struct ide_cmd cmd; int ret; /* call ACPI _GTM only once */ @@ -15,11 +15,9 @@ int generic_ide_suspend(struct device *dev, pm_message_t mesg) ide_acpi_get_timing(hwif); memset(&rqpm, 0, sizeof(rqpm)); - memset(&cmd, 0, sizeof(cmd)); rq = blk_get_request(drive->queue, READ, __GFP_WAIT); rq->cmd_type = REQ_TYPE_PM_SUSPEND; - rq->special = &cmd; - rq->data = &rqpm; + rq->special = &rqpm; rqpm.pm_step = IDE_PM_START_SUSPEND; if (mesg.event == PM_EVENT_PRETHAW) mesg.event = PM_EVENT_FREEZE; @@ -37,11 +35,11 @@ int generic_ide_suspend(struct device *dev, pm_message_t mesg) int generic_ide_resume(struct device *dev) { - ide_drive_t *drive = dev->driver_data, *pair = ide_get_pair_dev(drive); + ide_drive_t *drive = dev_get_drvdata(dev); + ide_drive_t *pair = ide_get_pair_dev(drive); ide_hwif_t *hwif = drive->hwif; struct request *rq; struct request_pm_state rqpm; - struct ide_cmd cmd; int err; /* call ACPI _PS0 / _STM only once */ @@ -53,12 +51,10 @@ int generic_ide_resume(struct device *dev) ide_acpi_exec_tfs(drive); memset(&rqpm, 0, sizeof(rqpm)); - memset(&cmd, 0, sizeof(cmd)); rq = blk_get_request(drive->queue, READ, __GFP_WAIT); rq->cmd_type = REQ_TYPE_PM_RESUME; rq->cmd_flags |= REQ_PREEMPT; - rq->special = &cmd; - rq->data = &rqpm; + rq->special = &rqpm; rqpm.pm_step = IDE_PM_START_RESUME; rqpm.pm_state = PM_EVENT_ON; @@ -77,7 +73,7 @@ int generic_ide_resume(struct device *dev) void ide_complete_power_step(ide_drive_t *drive, struct request *rq) { - struct request_pm_state *pm = rq->data; + struct request_pm_state *pm = rq->special; #ifdef DEBUG_PM printk(KERN_INFO "%s: complete_power_step(step: %d)\n", @@ -107,10 +103,8 @@ void ide_complete_power_step(ide_drive_t *drive, struct request *rq) ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *rq) { - struct request_pm_state *pm = rq->data; - struct ide_cmd *cmd = rq->special; - - memset(cmd, 0, sizeof(*cmd)); + struct request_pm_state *pm = rq->special; + struct ide_cmd cmd = { }; switch (pm->pm_step) { case IDE_PM_FLUSH_CACHE: /* Suspend step 1 (flush cache) */ @@ -123,12 +117,12 @@ ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *rq) return ide_stopped; } if (ata_id_flush_ext_enabled(drive->id)) - cmd->tf.command = ATA_CMD_FLUSH_EXT; + cmd.tf.command = ATA_CMD_FLUSH_EXT; else - cmd->tf.command = ATA_CMD_FLUSH; + cmd.tf.command = ATA_CMD_FLUSH; goto out_do_tf; case IDE_PM_STANDBY: /* Suspend step 2 (standby) */ - cmd->tf.command = ATA_CMD_STANDBYNOW1; + cmd.tf.command = ATA_CMD_STANDBYNOW1; goto out_do_tf; case IDE_PM_RESTORE_PIO: /* Resume step 1 (restore PIO) */ ide_set_max_pio(drive); @@ -141,7 +135,7 @@ ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *rq) ide_complete_power_step(drive, rq); return ide_stopped; case IDE_PM_IDLE: /* Resume step 2 (idle) */ - cmd->tf.command = ATA_CMD_IDLEIMMEDIATE; + cmd.tf.command = ATA_CMD_IDLEIMMEDIATE; goto out_do_tf; case IDE_PM_RESTORE_DMA: /* Resume step 3 (restore DMA) */ /* @@ -163,11 +157,11 @@ ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *rq) return ide_stopped; out_do_tf: - cmd->valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; - cmd->valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE; - cmd->protocol = ATA_PROT_NODATA; + cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; + cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE; + cmd.protocol = ATA_PROT_NODATA; - return do_rw_taskfile(drive, cmd); + return do_rw_taskfile(drive, &cmd); } /** @@ -181,7 +175,7 @@ out_do_tf: void ide_complete_pm_rq(ide_drive_t *drive, struct request *rq) { struct request_queue *q = drive->queue; - struct request_pm_state *pm = rq->data; + struct request_pm_state *pm = rq->special; unsigned long flags; ide_complete_power_step(drive, rq); @@ -207,7 +201,7 @@ void ide_complete_pm_rq(ide_drive_t *drive, struct request *rq) void ide_check_pm_state(ide_drive_t *drive, struct request *rq) { - struct request_pm_state *pm = rq->data; + struct request_pm_state *pm = rq->special; if (blk_pm_suspend_request(rq) && pm->pm_step == IDE_PM_START_SUSPEND) diff --git a/drivers/ide/ide-pnp.c b/drivers/ide/ide-pnp.c index 6e80b774e88a..017b1df3b805 100644 --- a/drivers/ide/ide-pnp.c +++ b/drivers/ide/ide-pnp.c @@ -29,6 +29,7 @@ static struct pnp_device_id idepnp_devices[] = { static const struct ide_port_info ide_pnp_port_info = { .host_flags = IDE_HFLAG_NO_DMA, + .chipset = ide_generic, }; static int idepnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id) @@ -36,7 +37,7 @@ static int idepnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id) struct ide_host *host; unsigned long base, ctl; int rc; - hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL }; + struct ide_hw hw, *hws[] = { &hw }; printk(KERN_INFO DRV_NAME ": generic PnP IDE interface\n"); @@ -62,9 +63,8 @@ static int idepnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id) memset(&hw, 0, sizeof(hw)); ide_std_init_ports(&hw, base, ctl); hw.irq = pnp_irq(dev, 0); - hw.chipset = ide_generic; - rc = ide_host_add(&ide_pnp_port_info, hws, &host); + rc = ide_host_add(&ide_pnp_port_info, hws, 1, &host); if (rc) goto out; diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index c895ed52b2e8..51af4eea0d36 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -97,7 +97,7 @@ static void ide_disk_init_mult_count(ide_drive_t *drive) drive->mult_req = id[ATA_ID_MULTSECT] & 0xff; if (drive->mult_req) - drive->special.b.set_multmode = 1; + drive->special_flags |= IDE_SFLAG_SET_MULTMODE; } } @@ -465,23 +465,8 @@ static u8 probe_for_drive(ide_drive_t *drive) int rc; u8 cmd; - /* - * In order to keep things simple we have an id - * block for all drives at all times. If the device - * is pre ATA or refuses ATA/ATAPI identify we - * will add faked data to this. - * - * Also note that 0 everywhere means "can't do X" - */ - drive->dev_flags &= ~IDE_DFLAG_ID_READ; - drive->id = kzalloc(SECTOR_SIZE, GFP_KERNEL); - if (drive->id == NULL) { - printk(KERN_ERR "ide: out of memory for id data.\n"); - return 0; - } - m = (char *)&drive->id[ATA_ID_PROD]; strcpy(m, "UNKNOWN"); @@ -497,7 +482,7 @@ static u8 probe_for_drive(ide_drive_t *drive) } if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0) - goto out_free; + return 0; /* identification failed? */ if ((drive->dev_flags & IDE_DFLAG_ID_READ) == 0) { @@ -521,7 +506,7 @@ static u8 probe_for_drive(ide_drive_t *drive) } if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0) - goto out_free; + return 0; /* The drive wasn't being helpful. Add generic info only */ if ((drive->dev_flags & IDE_DFLAG_ID_READ) == 0) { @@ -535,9 +520,6 @@ static u8 probe_for_drive(ide_drive_t *drive) } return 1; -out_free: - kfree(drive->id); - return 0; } static void hwif_release_dev(struct device *dev) @@ -553,7 +535,7 @@ static int ide_register_port(ide_hwif_t *hwif) /* register with global device tree */ dev_set_name(&hwif->gendev, hwif->name); - hwif->gendev.driver_data = hwif; + dev_set_drvdata(&hwif->gendev, hwif); if (hwif->gendev.parent == NULL) hwif->gendev.parent = hwif->dev; hwif->gendev.release = hwif_release_dev; @@ -702,8 +684,14 @@ static int ide_probe_port(ide_hwif_t *hwif) if (irqd) disable_irq(hwif->irq); - if (ide_port_wait_ready(hwif) == -EBUSY) - printk(KERN_DEBUG "%s: Wait for ready failed before probe !\n", hwif->name); + rc = ide_port_wait_ready(hwif); + if (rc == -ENODEV) { + printk(KERN_INFO "%s: no devices on the port\n", hwif->name); + goto out; + } else if (rc == -EBUSY) + printk(KERN_ERR "%s: not ready before the probe\n", hwif->name); + else + rc = -ENODEV; /* * Second drive should only exist if first drive was found, @@ -714,7 +702,7 @@ static int ide_probe_port(ide_hwif_t *hwif) if (drive->dev_flags & IDE_DFLAG_PRESENT) rc = 0; } - +out: /* * Use cached IRQ number. It might be (and is...) changed by probe * code above @@ -732,6 +720,8 @@ static void ide_port_tune_devices(ide_hwif_t *hwif) int i; ide_port_for_each_present_dev(i, drive, hwif) { + ide_check_nien_quirk_list(drive); + if (port_ops && port_ops->quirkproc) port_ops->quirkproc(drive); } @@ -817,8 +807,6 @@ static int ide_port_setup_devices(ide_hwif_t *hwif) if (ide_init_queue(drive)) { printk(KERN_ERR "ide: failed to init %s\n", drive->name); - kfree(drive->id); - drive->id = NULL; drive->dev_flags &= ~IDE_DFLAG_PRESENT; continue; } @@ -947,9 +935,6 @@ static void drive_release_dev (struct device *dev) blk_cleanup_queue(drive->queue); drive->queue = NULL; - kfree(drive->id); - drive->id = NULL; - drive->dev_flags &= ~IDE_DFLAG_PRESENT; complete(&drive->gendev_rel_comp); @@ -1002,9 +987,9 @@ static void hwif_register_devices(ide_hwif_t *hwif) int ret; dev_set_name(dev, "%u.%u", hwif->index, i); + dev_set_drvdata(dev, drive); dev->parent = &hwif->gendev; dev->bus = &ide_bus_type; - dev->driver_data = drive; dev->release = drive_release_dev; ret = device_register(dev); @@ -1035,6 +1020,15 @@ static void ide_port_init_devices(ide_hwif_t *hwif) if (port_ops && port_ops->init_dev) port_ops->init_dev(drive); } + + ide_port_for_each_dev(i, drive, hwif) { + /* + * default to PIO Mode 0 before we figure out + * the most suited mode for the attached device + */ + if (port_ops && port_ops->set_pio_mode) + port_ops->set_pio_mode(drive, 0); + } } static void ide_init_port(ide_hwif_t *hwif, unsigned int port, @@ -1042,8 +1036,7 @@ static void ide_init_port(ide_hwif_t *hwif, unsigned int port, { hwif->channel = port; - if (d->chipset) - hwif->chipset = d->chipset; + hwif->chipset = d->chipset ? d->chipset : ide_pci; if (d->init_iops) d->init_iops(hwif); @@ -1124,16 +1117,19 @@ static void ide_port_init_devices_data(ide_hwif_t *hwif) ide_port_for_each_dev(i, drive, hwif) { u8 j = (hwif->index * MAX_DRIVES) + i; + u16 *saved_id = drive->id; memset(drive, 0, sizeof(*drive)); + memset(saved_id, 0, SECTOR_SIZE); + drive->id = saved_id; drive->media = ide_disk; drive->select = (i << 4) | ATA_DEVICE_OBS; drive->hwif = hwif; drive->ready_stat = ATA_DRDY; drive->bad_wstat = BAD_W_STAT; - drive->special.b.recalibrate = 1; - drive->special.b.set_geometry = 1; + drive->special_flags = IDE_SFLAG_RECALIBRATE | + IDE_SFLAG_SET_GEOMETRY; drive->name[0] = 'h'; drive->name[1] = 'd'; drive->name[2] = 'a' + j; @@ -1168,14 +1164,12 @@ static void ide_init_port_data(ide_hwif_t *hwif, unsigned int index) ide_port_init_devices_data(hwif); } -static void ide_init_port_hw(ide_hwif_t *hwif, hw_regs_t *hw) +static void ide_init_port_hw(ide_hwif_t *hwif, struct ide_hw *hw) { memcpy(&hwif->io_ports, &hw->io_ports, sizeof(hwif->io_ports)); hwif->irq = hw->irq; - hwif->chipset = hw->chipset; hwif->dev = hw->dev; hwif->gendev.parent = hw->parent ? hw->parent : hw->dev; - hwif->ack_intr = hw->ack_intr; hwif->config_data = hw->config; } @@ -1233,8 +1227,10 @@ static void ide_port_free_devices(ide_hwif_t *hwif) ide_drive_t *drive; int i; - ide_port_for_each_dev(i, drive, hwif) + ide_port_for_each_dev(i, drive, hwif) { + kfree(drive->id); kfree(drive); + } } static int ide_port_alloc_devices(ide_hwif_t *hwif, int node) @@ -1248,6 +1244,18 @@ static int ide_port_alloc_devices(ide_hwif_t *hwif, int node) if (drive == NULL) goto out_nomem; + /* + * In order to keep things simple we have an id + * block for all drives at all times. If the device + * is pre ATA or refuses ATA/ATAPI identify we + * will add faked data to this. + * + * Also note that 0 everywhere means "can't do X" + */ + drive->id = kzalloc_node(SECTOR_SIZE, GFP_KERNEL, node); + if (drive->id == NULL) + goto out_nomem; + hwif->devices[i] = drive; } return 0; @@ -1257,7 +1265,8 @@ out_nomem: return -ENOMEM; } -struct ide_host *ide_host_alloc(const struct ide_port_info *d, hw_regs_t **hws) +struct ide_host *ide_host_alloc(const struct ide_port_info *d, + struct ide_hw **hws, unsigned int n_ports) { struct ide_host *host; struct device *dev = hws[0] ? hws[0]->dev : NULL; @@ -1268,7 +1277,7 @@ struct ide_host *ide_host_alloc(const struct ide_port_info *d, hw_regs_t **hws) if (host == NULL) return NULL; - for (i = 0; i < MAX_HOST_PORTS; i++) { + for (i = 0; i < n_ports; i++) { ide_hwif_t *hwif; int idx; @@ -1288,6 +1297,7 @@ struct ide_host *ide_host_alloc(const struct ide_port_info *d, hw_regs_t **hws) if (idx < 0) { printk(KERN_ERR "%s: no free slot for interface\n", d ? d->name : "ide"); + ide_port_free_devices(hwif); kfree(hwif); continue; } @@ -1344,7 +1354,7 @@ static void ide_disable_port(ide_hwif_t *hwif) } int ide_host_register(struct ide_host *host, const struct ide_port_info *d, - hw_regs_t **hws) + struct ide_hw **hws) { ide_hwif_t *hwif, *mate = NULL; int i, j = 0; @@ -1367,6 +1377,9 @@ int ide_host_register(struct ide_host *host, const struct ide_port_info *d, ide_init_port(hwif, i & 1, d); ide_port_cable_detect(hwif); + + hwif->port_flags |= IDE_PFLAG_PROBING; + ide_port_init_devices(hwif); } @@ -1377,6 +1390,8 @@ int ide_host_register(struct ide_host *host, const struct ide_port_info *d, if (ide_probe_port(hwif) == 0) hwif->present = 1; + hwif->port_flags &= ~IDE_PFLAG_PROBING; + if ((hwif->host_flags & IDE_HFLAG_4DRIVES) == 0 || hwif->mate == NULL || hwif->mate->present == 0) { if (ide_register_port(hwif)) { @@ -1438,13 +1453,13 @@ int ide_host_register(struct ide_host *host, const struct ide_port_info *d, } EXPORT_SYMBOL_GPL(ide_host_register); -int ide_host_add(const struct ide_port_info *d, hw_regs_t **hws, - struct ide_host **hostp) +int ide_host_add(const struct ide_port_info *d, struct ide_hw **hws, + unsigned int n_ports, struct ide_host **hostp) { struct ide_host *host; int rc; - host = ide_host_alloc(d, hws); + host = ide_host_alloc(d, hws, n_ports); if (host == NULL) return -ENOMEM; @@ -1558,11 +1573,20 @@ EXPORT_SYMBOL_GPL(ide_host_remove); void ide_port_scan(ide_hwif_t *hwif) { + int rc; + ide_port_apply_params(hwif); ide_port_cable_detect(hwif); + + hwif->port_flags |= IDE_PFLAG_PROBING; + ide_port_init_devices(hwif); - if (ide_probe_port(hwif) < 0) + rc = ide_probe_port(hwif); + + hwif->port_flags &= ~IDE_PFLAG_PROBING; + + if (rc < 0) return; hwif->present = 1; diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index 3a53e0834cf7..013dc595fab6 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -131,13 +131,6 @@ enum { IDETAPE_DIR_WRITE = (1 << 2), }; -struct idetape_bh { - u32 b_size; - atomic_t b_count; - struct idetape_bh *b_reqnext; - char *b_data; -}; - /* Tape door status */ #define DOOR_UNLOCKED 0 #define DOOR_LOCKED 1 @@ -219,18 +212,12 @@ typedef struct ide_tape_obj { /* Data buffer size chosen based on the tape's recommendation */ int buffer_size; - /* merge buffer */ - struct idetape_bh *merge_bh; - /* size of the merge buffer */ - int merge_bh_size; - /* pointer to current buffer head within the merge buffer */ - struct idetape_bh *bh; - char *b_data; - int b_count; - - int pages_per_buffer; - /* Wasted space in each stage */ - int excess_bh_size; + /* Staging buffer of buffer_size bytes */ + void *buf; + /* The read/write cursor */ + void *cur; + /* The number of valid bytes in buf */ + size_t valid; /* Measures average tape speed */ unsigned long avg_time; @@ -253,18 +240,27 @@ static struct class *idetape_sysfs_class; static void ide_tape_release(struct device *); -static struct ide_tape_obj *ide_tape_get(struct gendisk *disk) +static struct ide_tape_obj *idetape_devs[MAX_HWIFS * MAX_DRIVES]; + +static struct ide_tape_obj *ide_tape_get(struct gendisk *disk, bool cdev, + unsigned int i) { struct ide_tape_obj *tape = NULL; mutex_lock(&idetape_ref_mutex); - tape = ide_drv_g(disk, ide_tape_obj); + + if (cdev) + tape = idetape_devs[i]; + else + tape = ide_drv_g(disk, ide_tape_obj); + if (tape) { if (ide_device_get(tape->drive)) tape = NULL; else get_device(&tape->dev); } + mutex_unlock(&idetape_ref_mutex); return tape; } @@ -279,110 +275,16 @@ static void ide_tape_put(struct ide_tape_obj *tape) mutex_unlock(&idetape_ref_mutex); } -/* - * The variables below are used for the character device interface. Additional - * state variables are defined in our ide_drive_t structure. - */ -static struct ide_tape_obj *idetape_devs[MAX_HWIFS * MAX_DRIVES]; - -static struct ide_tape_obj *ide_tape_chrdev_get(unsigned int i) -{ - struct ide_tape_obj *tape = NULL; - - mutex_lock(&idetape_ref_mutex); - tape = idetape_devs[i]; - if (tape) - get_device(&tape->dev); - mutex_unlock(&idetape_ref_mutex); - return tape; -} - -static int idetape_input_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc, - unsigned int bcount) -{ - struct idetape_bh *bh = pc->bh; - int count; - - while (bcount) { - if (bh == NULL) - break; - count = min( - (unsigned int)(bh->b_size - atomic_read(&bh->b_count)), - bcount); - drive->hwif->tp_ops->input_data(drive, NULL, bh->b_data + - atomic_read(&bh->b_count), count); - bcount -= count; - atomic_add(count, &bh->b_count); - if (atomic_read(&bh->b_count) == bh->b_size) { - bh = bh->b_reqnext; - if (bh) - atomic_set(&bh->b_count, 0); - } - } - - pc->bh = bh; - - return bcount; -} - -static int idetape_output_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc, - unsigned int bcount) -{ - struct idetape_bh *bh = pc->bh; - int count; - - while (bcount) { - if (bh == NULL) - break; - count = min((unsigned int)pc->b_count, (unsigned int)bcount); - drive->hwif->tp_ops->output_data(drive, NULL, pc->b_data, count); - bcount -= count; - pc->b_data += count; - pc->b_count -= count; - if (!pc->b_count) { - bh = bh->b_reqnext; - pc->bh = bh; - if (bh) { - pc->b_data = bh->b_data; - pc->b_count = atomic_read(&bh->b_count); - } - } - } - - return bcount; -} - -static void idetape_update_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc) -{ - struct idetape_bh *bh = pc->bh; - int count; - unsigned int bcount = pc->xferred; - - if (pc->flags & PC_FLAG_WRITING) - return; - while (bcount) { - if (bh == NULL) { - printk(KERN_ERR "ide-tape: bh == NULL in %s\n", - __func__); - return; - } - count = min((unsigned int)bh->b_size, (unsigned int)bcount); - atomic_set(&bh->b_count, count); - if (atomic_read(&bh->b_count) == bh->b_size) - bh = bh->b_reqnext; - bcount -= count; - } - pc->bh = bh; -} - /* * called on each failed packet command retry to analyze the request sense. We * currently do not utilize this information. */ -static void idetape_analyze_error(ide_drive_t *drive, u8 *sense) +static void idetape_analyze_error(ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; struct ide_atapi_pc *pc = drive->failed_pc; + struct request *rq = drive->hwif->rq; + u8 *sense = bio_data(rq->bio); tape->sense_key = sense[2] & 0xF; tape->asc = sense[12]; @@ -391,13 +293,9 @@ static void idetape_analyze_error(ide_drive_t *drive, u8 *sense) debug_log(DBG_ERR, "pc = %x, sense key = %x, asc = %x, ascq = %x\n", pc->c[0], tape->sense_key, tape->asc, tape->ascq); - /* Correct pc->xferred by asking the tape. */ - if (pc->flags & PC_FLAG_DMA_ERROR) { - pc->xferred = pc->req_xfer - - tape->blk_size * - get_unaligned_be32(&sense[3]); - idetape_update_buffers(drive, pc); - } + /* correct remaining bytes to transfer */ + if (pc->flags & PC_FLAG_DMA_ERROR) + rq->resid_len = tape->blk_size * get_unaligned_be32(&sense[3]); /* * If error was the result of a zero-length read or write command, @@ -431,34 +329,11 @@ static void idetape_analyze_error(ide_drive_t *drive, u8 *sense) pc->flags |= PC_FLAG_ABORT; } if (!(pc->flags & PC_FLAG_ABORT) && - pc->xferred) + (blk_rq_bytes(rq) - rq->resid_len)) pc->retries = IDETAPE_MAX_PC_RETRIES + 1; } } -/* Free data buffers completely. */ -static void ide_tape_kfree_buffer(idetape_tape_t *tape) -{ - struct idetape_bh *prev_bh, *bh = tape->merge_bh; - - while (bh) { - u32 size = bh->b_size; - - while (size) { - unsigned int order = fls(size >> PAGE_SHIFT)-1; - - if (bh->b_data) - free_pages((unsigned long)bh->b_data, order); - - size &= (order-1); - bh->b_data += (1 << order) * PAGE_SIZE; - } - prev_bh = bh; - bh = bh->b_reqnext; - kfree(prev_bh); - } -} - static void ide_tape_handle_dsc(ide_drive_t *); static int ide_tape_callback(ide_drive_t *drive, int dsc) @@ -479,12 +354,13 @@ static int ide_tape_callback(ide_drive_t *drive, int dsc) if (pc->c[0] == REQUEST_SENSE) { if (uptodate) - idetape_analyze_error(drive, pc->buf); + idetape_analyze_error(drive); else printk(KERN_ERR "ide-tape: Error in REQUEST SENSE " "itself - Aborting request!\n"); } else if (pc->c[0] == READ_6 || pc->c[0] == WRITE_6) { - int blocks = pc->xferred / tape->blk_size; + unsigned int blocks = + (blk_rq_bytes(rq) - rq->resid_len) / tape->blk_size; tape->avg_size += blocks * tape->blk_size; @@ -496,36 +372,12 @@ static int ide_tape_callback(ide_drive_t *drive, int dsc) } tape->first_frame += blocks; - rq->current_nr_sectors -= blocks; if (pc->error) { uptodate = 0; err = pc->error; } - } else if (pc->c[0] == READ_POSITION && uptodate) { - u8 *readpos = pc->buf; - - debug_log(DBG_SENSE, "BOP - %s\n", - (readpos[0] & 0x80) ? "Yes" : "No"); - debug_log(DBG_SENSE, "EOP - %s\n", - (readpos[0] & 0x40) ? "Yes" : "No"); - - if (readpos[0] & 0x4) { - printk(KERN_INFO "ide-tape: Block location is unknown" - "to the tape\n"); - clear_bit(IDE_AFLAG_ADDRESS_VALID, &drive->atapi_flags); - uptodate = 0; - err = IDE_DRV_ERROR_GENERAL; - } else { - debug_log(DBG_SENSE, "Block Location - %u\n", - be32_to_cpup((__be32 *)&readpos[4])); - - tape->partition = readpos[1]; - tape->first_frame = be32_to_cpup((__be32 *)&readpos[4]); - set_bit(IDE_AFLAG_ADDRESS_VALID, &drive->atapi_flags); - } } - rq->errors = err; return uptodate; @@ -558,19 +410,6 @@ static void ide_tape_handle_dsc(ide_drive_t *drive) idetape_postpone_request(drive); } -static int ide_tape_io_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc, - unsigned int bcount, int write) -{ - unsigned int bleft; - - if (write) - bleft = idetape_output_buffers(drive, pc, bcount); - else - bleft = idetape_input_buffers(drive, pc, bcount); - - return bcount - bleft; -} - /* * Packet Command Interface * @@ -613,6 +452,7 @@ static ide_startstop_t ide_tape_issue_pc(ide_drive_t *drive, struct ide_atapi_pc *pc) { idetape_tape_t *tape = drive->driver_data; + struct request *rq = drive->hwif->rq; if (drive->failed_pc == NULL && pc->c[0] != REQUEST_SENSE) drive->failed_pc = pc; @@ -622,6 +462,7 @@ static ide_startstop_t ide_tape_issue_pc(ide_drive_t *drive, if (pc->retries > IDETAPE_MAX_PC_RETRIES || (pc->flags & PC_FLAG_ABORT)) { + /* * We will "abort" retrying a packet command in case legitimate * error code was received (crossing a filemark, or end of the @@ -641,8 +482,10 @@ static ide_startstop_t ide_tape_issue_pc(ide_drive_t *drive, /* Giving up */ pc->error = IDE_DRV_ERROR_GENERAL; } + drive->failed_pc = NULL; drive->pc_callback(drive, 0); + ide_complete_rq(drive, -EIO, blk_rq_bytes(rq)); return ide_stopped; } debug_log(DBG_SENSE, "Retry #%d, cmd = %02X\n", pc->retries, pc->c[0]); @@ -695,7 +538,7 @@ static ide_startstop_t idetape_media_access_finished(ide_drive_t *drive) printk(KERN_ERR "ide-tape: %s: I/O error, ", tape->name); /* Retry operation */ - ide_retry_pc(drive, tape->disk); + ide_retry_pc(drive); return ide_stopped; } pc->error = 0; @@ -711,27 +554,20 @@ static void ide_tape_create_rw_cmd(idetape_tape_t *tape, struct ide_atapi_pc *pc, struct request *rq, u8 opcode) { - struct idetape_bh *bh = (struct idetape_bh *)rq->special; - unsigned int length = rq->current_nr_sectors; + unsigned int length = blk_rq_sectors(rq) / (tape->blk_size >> 9); ide_init_pc(pc); put_unaligned(cpu_to_be32(length), (unsigned int *) &pc->c[1]); pc->c[1] = 1; - pc->bh = bh; - pc->buf = NULL; - pc->buf_size = length * tape->blk_size; - pc->req_xfer = pc->buf_size; - if (pc->req_xfer == tape->buffer_size) + + if (blk_rq_bytes(rq) == tape->buffer_size) pc->flags |= PC_FLAG_DMA_OK; - if (opcode == READ_6) { + if (opcode == READ_6) pc->c[0] = READ_6; - atomic_set(&bh->b_count, 0); - } else if (opcode == WRITE_6) { + else if (opcode == WRITE_6) { pc->c[0] = WRITE_6; pc->flags |= PC_FLAG_WRITING; - pc->b_data = bh->b_data; - pc->b_count = atomic_read(&bh->b_count); } memcpy(rq->cmd, pc->c, 12); @@ -747,20 +583,10 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive, struct ide_cmd cmd; u8 stat; - debug_log(DBG_SENSE, "sector: %llu, nr_sectors: %lu," - " current_nr_sectors: %u\n", - (unsigned long long)rq->sector, rq->nr_sectors, - rq->current_nr_sectors); + debug_log(DBG_SENSE, "sector: %llu, nr_sectors: %u\n" + (unsigned long long)blk_rq_pos(rq), blk_rq_sectors(rq)); - if (!blk_special_request(rq)) { - /* We do not support buffer cache originated requests. */ - printk(KERN_NOTICE "ide-tape: %s: Unsupported request in " - "request queue (%d)\n", drive->name, rq->cmd_type); - if (blk_fs_request(rq) == 0 && rq->errors == 0) - rq->errors = -EIO; - ide_complete_rq(drive, -EIO, ide_rq_bytes(rq)); - return ide_stopped; - } + BUG_ON(!(blk_special_request(rq) || blk_sense_request(rq))); /* Retry a failed packet command */ if (drive->failed_pc && drive->pc->c[0] == REQUEST_SENSE) { @@ -788,15 +614,15 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive, if ((drive->dev_flags & IDE_DFLAG_DSC_OVERLAP) == 0 && (rq->cmd[13] & REQ_IDETAPE_PC2) == 0) - set_bit(IDE_AFLAG_IGNORE_DSC, &drive->atapi_flags); + drive->atapi_flags |= IDE_AFLAG_IGNORE_DSC; if (drive->dev_flags & IDE_DFLAG_POST_RESET) { - set_bit(IDE_AFLAG_IGNORE_DSC, &drive->atapi_flags); + drive->atapi_flags |= IDE_AFLAG_IGNORE_DSC; drive->dev_flags &= ~IDE_DFLAG_POST_RESET; } - if (!test_and_clear_bit(IDE_AFLAG_IGNORE_DSC, &drive->atapi_flags) && - (stat & ATA_DSC) == 0) { + if (!(drive->atapi_flags & IDE_AFLAG_IGNORE_DSC) && + !(stat & ATA_DSC)) { if (postponed_rq == NULL) { tape->dsc_polling_start = jiffies; tape->dsc_poll_freq = tape->best_dsc_rw_freq; @@ -816,7 +642,9 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive, tape->dsc_poll_freq = IDETAPE_DSC_MA_SLOW; idetape_postpone_request(drive); return ide_stopped; - } + } else + drive->atapi_flags &= ~IDE_AFLAG_IGNORE_DSC; + if (rq->cmd[13] & REQ_IDETAPE_READ) { pc = &tape->queued_pc; ide_tape_create_rw_cmd(tape, pc, rq, READ_6); @@ -828,7 +656,7 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive, goto out; } if (rq->cmd[13] & REQ_IDETAPE_PC1) { - pc = (struct ide_atapi_pc *) rq->buffer; + pc = (struct ide_atapi_pc *)rq->special; rq->cmd[13] &= ~(REQ_IDETAPE_PC1); rq->cmd[13] |= REQ_IDETAPE_PC2; goto out; @@ -840,6 +668,9 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive, BUG(); out: + /* prepare sense request for this command */ + ide_prep_sense(drive, rq); + memset(&cmd, 0, sizeof(cmd)); if (rq_data_dir(rq)) @@ -847,169 +678,12 @@ out: cmd.rq = rq; + ide_init_sg_cmd(&cmd, blk_rq_bytes(rq)); + ide_map_sg(drive, &cmd); + return ide_tape_issue_pc(drive, &cmd, pc); } -/* - * The function below uses __get_free_pages to allocate a data buffer of size - * tape->buffer_size (or a bit more). We attempt to combine sequential pages as - * much as possible. - * - * It returns a pointer to the newly allocated buffer, or NULL in case of - * failure. - */ -static struct idetape_bh *ide_tape_kmalloc_buffer(idetape_tape_t *tape, - int full, int clear) -{ - struct idetape_bh *prev_bh, *bh, *merge_bh; - int pages = tape->pages_per_buffer; - unsigned int order, b_allocd; - char *b_data = NULL; - - merge_bh = kmalloc(sizeof(struct idetape_bh), GFP_KERNEL); - bh = merge_bh; - if (bh == NULL) - goto abort; - - order = fls(pages) - 1; - bh->b_data = (char *) __get_free_pages(GFP_KERNEL, order); - if (!bh->b_data) - goto abort; - b_allocd = (1 << order) * PAGE_SIZE; - pages &= (order-1); - - if (clear) - memset(bh->b_data, 0, b_allocd); - bh->b_reqnext = NULL; - bh->b_size = b_allocd; - atomic_set(&bh->b_count, full ? bh->b_size : 0); - - while (pages) { - order = fls(pages) - 1; - b_data = (char *) __get_free_pages(GFP_KERNEL, order); - if (!b_data) - goto abort; - b_allocd = (1 << order) * PAGE_SIZE; - - if (clear) - memset(b_data, 0, b_allocd); - - /* newly allocated page frames below buffer header or ...*/ - if (bh->b_data == b_data + b_allocd) { - bh->b_size += b_allocd; - bh->b_data -= b_allocd; - if (full) - atomic_add(b_allocd, &bh->b_count); - continue; - } - /* they are above the header */ - if (b_data == bh->b_data + bh->b_size) { - bh->b_size += b_allocd; - if (full) - atomic_add(b_allocd, &bh->b_count); - continue; - } - prev_bh = bh; - bh = kmalloc(sizeof(struct idetape_bh), GFP_KERNEL); - if (!bh) { - free_pages((unsigned long) b_data, order); - goto abort; - } - bh->b_reqnext = NULL; - bh->b_data = b_data; - bh->b_size = b_allocd; - atomic_set(&bh->b_count, full ? bh->b_size : 0); - prev_bh->b_reqnext = bh; - - pages &= (order-1); - } - - bh->b_size -= tape->excess_bh_size; - if (full) - atomic_sub(tape->excess_bh_size, &bh->b_count); - return merge_bh; -abort: - ide_tape_kfree_buffer(tape); - return NULL; -} - -static int idetape_copy_stage_from_user(idetape_tape_t *tape, - const char __user *buf, int n) -{ - struct idetape_bh *bh = tape->bh; - int count; - int ret = 0; - - while (n) { - if (bh == NULL) { - printk(KERN_ERR "ide-tape: bh == NULL in %s\n", - __func__); - return 1; - } - count = min((unsigned int) - (bh->b_size - atomic_read(&bh->b_count)), - (unsigned int)n); - if (copy_from_user(bh->b_data + atomic_read(&bh->b_count), buf, - count)) - ret = 1; - n -= count; - atomic_add(count, &bh->b_count); - buf += count; - if (atomic_read(&bh->b_count) == bh->b_size) { - bh = bh->b_reqnext; - if (bh) - atomic_set(&bh->b_count, 0); - } - } - tape->bh = bh; - return ret; -} - -static int idetape_copy_stage_to_user(idetape_tape_t *tape, char __user *buf, - int n) -{ - struct idetape_bh *bh = tape->bh; - int count; - int ret = 0; - - while (n) { - if (bh == NULL) { - printk(KERN_ERR "ide-tape: bh == NULL in %s\n", - __func__); - return 1; - } - count = min(tape->b_count, n); - if (copy_to_user(buf, tape->b_data, count)) - ret = 1; - n -= count; - tape->b_data += count; - tape->b_count -= count; - buf += count; - if (!tape->b_count) { - bh = bh->b_reqnext; - tape->bh = bh; - if (bh) { - tape->b_data = bh->b_data; - tape->b_count = atomic_read(&bh->b_count); - } - } - } - return ret; -} - -static void idetape_init_merge_buffer(idetape_tape_t *tape) -{ - struct idetape_bh *bh = tape->merge_bh; - tape->bh = tape->merge_bh; - - if (tape->chrdev_dir == IDETAPE_DIR_WRITE) - atomic_set(&bh->b_count, 0); - else { - tape->b_data = bh->b_data; - tape->b_count = atomic_read(&bh->b_count); - } -} - /* * Write a filemark if write_filemark=1. Flush the device buffers without * writing a filemark otherwise. @@ -1030,7 +704,7 @@ static int idetape_wait_ready(ide_drive_t *drive, unsigned long timeout) int load_attempted = 0; /* Wait for the tape to become ready */ - set_bit(IDE_AFLAG_MEDIUM_PRESENT, &drive->atapi_flags); + set_bit(ilog2(IDE_AFLAG_MEDIUM_PRESENT), &drive->atapi_flags); timeout += jiffies; while (time_before(jiffies, timeout)) { if (ide_do_test_unit_ready(drive, disk) == 0) @@ -1058,33 +732,53 @@ static int idetape_flush_tape_buffers(ide_drive_t *drive) int rc; idetape_create_write_filemark_cmd(drive, &pc, 0); - rc = ide_queue_pc_tail(drive, tape->disk, &pc); + rc = ide_queue_pc_tail(drive, tape->disk, &pc, NULL, 0); if (rc) return rc; idetape_wait_ready(drive, 60 * 5 * HZ); return 0; } -static void idetape_create_read_position_cmd(struct ide_atapi_pc *pc) -{ - ide_init_pc(pc); - pc->c[0] = READ_POSITION; - pc->req_xfer = 20; -} - -static int idetape_read_position(ide_drive_t *drive) +static int ide_tape_read_position(ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; struct ide_atapi_pc pc; - int position; + u8 buf[20]; debug_log(DBG_PROCS, "Enter %s\n", __func__); - idetape_create_read_position_cmd(&pc); - if (ide_queue_pc_tail(drive, tape->disk, &pc)) + /* prep cmd */ + ide_init_pc(&pc); + pc.c[0] = READ_POSITION; + pc.req_xfer = 20; + + if (ide_queue_pc_tail(drive, tape->disk, &pc, buf, pc.req_xfer)) return -1; - position = tape->first_frame; - return position; + + if (!pc.error) { + debug_log(DBG_SENSE, "BOP - %s\n", + (buf[0] & 0x80) ? "Yes" : "No"); + debug_log(DBG_SENSE, "EOP - %s\n", + (buf[0] & 0x40) ? "Yes" : "No"); + + if (buf[0] & 0x4) { + printk(KERN_INFO "ide-tape: Block location is unknown" + "to the tape\n"); + clear_bit(ilog2(IDE_AFLAG_ADDRESS_VALID), + &drive->atapi_flags); + return -1; + } else { + debug_log(DBG_SENSE, "Block Location - %u\n", + be32_to_cpup((__be32 *)&buf[4])); + + tape->partition = buf[1]; + tape->first_frame = be32_to_cpup((__be32 *)&buf[4]); + set_bit(ilog2(IDE_AFLAG_ADDRESS_VALID), + &drive->atapi_flags); + } + } + + return tape->first_frame; } static void idetape_create_locate_cmd(ide_drive_t *drive, @@ -1106,11 +800,11 @@ static void __ide_tape_discard_merge_buffer(ide_drive_t *drive) if (tape->chrdev_dir != IDETAPE_DIR_READ) return; - clear_bit(IDE_AFLAG_FILEMARK, &drive->atapi_flags); - tape->merge_bh_size = 0; - if (tape->merge_bh != NULL) { - ide_tape_kfree_buffer(tape); - tape->merge_bh = NULL; + clear_bit(ilog2(IDE_AFLAG_FILEMARK), &drive->atapi_flags); + tape->valid = 0; + if (tape->buf != NULL) { + kfree(tape->buf); + tape->buf = NULL; } tape->chrdev_dir = IDETAPE_DIR_NONE; @@ -1127,19 +821,21 @@ static int idetape_position_tape(ide_drive_t *drive, unsigned int block, { idetape_tape_t *tape = drive->driver_data; struct gendisk *disk = tape->disk; - int retval; + int ret; struct ide_atapi_pc pc; if (tape->chrdev_dir == IDETAPE_DIR_READ) __ide_tape_discard_merge_buffer(drive); idetape_wait_ready(drive, 60 * 5 * HZ); idetape_create_locate_cmd(drive, &pc, block, partition, skip); - retval = ide_queue_pc_tail(drive, disk, &pc); - if (retval) - return (retval); + ret = ide_queue_pc_tail(drive, disk, &pc, NULL, 0); + if (ret) + return ret; - idetape_create_read_position_cmd(&pc); - return ide_queue_pc_tail(drive, disk, &pc); + ret = ide_tape_read_position(drive); + if (ret < 0) + return ret; + return 0; } static void ide_tape_discard_merge_buffer(ide_drive_t *drive, @@ -1150,7 +846,7 @@ static void ide_tape_discard_merge_buffer(ide_drive_t *drive, __ide_tape_discard_merge_buffer(drive); if (restore_position) { - position = idetape_read_position(drive); + position = ide_tape_read_position(drive); seek = position > 0 ? position : 0; if (idetape_position_tape(drive, seek, 0, 0)) { printk(KERN_INFO "ide-tape: %s: position_tape failed in" @@ -1164,36 +860,44 @@ static void ide_tape_discard_merge_buffer(ide_drive_t *drive, * Generate a read/write request for the block device interface and wait for it * to be serviced. */ -static int idetape_queue_rw_tail(ide_drive_t *drive, int cmd, int blocks, - struct idetape_bh *bh) +static int idetape_queue_rw_tail(ide_drive_t *drive, int cmd, int size) { idetape_tape_t *tape = drive->driver_data; struct request *rq; - int ret, errors; + int ret; debug_log(DBG_SENSE, "%s: cmd=%d\n", __func__, cmd); + BUG_ON(cmd != REQ_IDETAPE_READ && cmd != REQ_IDETAPE_WRITE); + BUG_ON(size < 0 || size % tape->blk_size); rq = blk_get_request(drive->queue, READ, __GFP_WAIT); rq->cmd_type = REQ_TYPE_SPECIAL; rq->cmd[13] = cmd; rq->rq_disk = tape->disk; - rq->special = (void *)bh; - rq->sector = tape->first_frame; - rq->nr_sectors = blocks; - rq->current_nr_sectors = blocks; + rq->__sector = tape->first_frame; + + if (size) { + ret = blk_rq_map_kern(drive->queue, rq, tape->buf, size, + __GFP_WAIT); + if (ret) + goto out_put; + } + blk_execute_rq(drive->queue, tape->disk, rq, 0); - errors = rq->errors; - ret = tape->blk_size * (blocks - rq->current_nr_sectors); + /* calculate the number of transferred bytes and update buffer state */ + size -= rq->resid_len; + tape->cur = tape->buf; + if (cmd == REQ_IDETAPE_READ) + tape->valid = size; + else + tape->valid = 0; + + ret = size; + if (rq->errors == IDE_DRV_ERROR_GENERAL) + ret = -EIO; +out_put: blk_put_request(rq); - - if ((cmd & (REQ_IDETAPE_READ | REQ_IDETAPE_WRITE)) == 0) - return 0; - - if (tape->merge_bh) - idetape_init_merge_buffer(tape); - if (errors == IDE_DRV_ERROR_GENERAL) - return -EIO; return ret; } @@ -1230,153 +934,87 @@ static void idetape_create_space_cmd(struct ide_atapi_pc *pc, int count, u8 cmd) pc->flags |= PC_FLAG_WAIT_FOR_DSC; } -/* Queue up a character device originated write request. */ -static int idetape_add_chrdev_write_request(ide_drive_t *drive, int blocks) -{ - idetape_tape_t *tape = drive->driver_data; - - debug_log(DBG_CHRDEV, "Enter %s\n", __func__); - - return idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, - blocks, tape->merge_bh); -} - static void ide_tape_flush_merge_buffer(ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; - int blocks, min; - struct idetape_bh *bh; if (tape->chrdev_dir != IDETAPE_DIR_WRITE) { printk(KERN_ERR "ide-tape: bug: Trying to empty merge buffer" " but we are not writing.\n"); return; } - if (tape->merge_bh_size > tape->buffer_size) { - printk(KERN_ERR "ide-tape: bug: merge_buffer too big\n"); - tape->merge_bh_size = tape->buffer_size; - } - if (tape->merge_bh_size) { - blocks = tape->merge_bh_size / tape->blk_size; - if (tape->merge_bh_size % tape->blk_size) { - unsigned int i; + if (tape->buf) { + size_t aligned = roundup(tape->valid, tape->blk_size); - blocks++; - i = tape->blk_size - tape->merge_bh_size % - tape->blk_size; - bh = tape->bh->b_reqnext; - while (bh) { - atomic_set(&bh->b_count, 0); - bh = bh->b_reqnext; - } - bh = tape->bh; - while (i) { - if (bh == NULL) { - printk(KERN_INFO "ide-tape: bug," - " bh NULL\n"); - break; - } - min = min(i, (unsigned int)(bh->b_size - - atomic_read(&bh->b_count))); - memset(bh->b_data + atomic_read(&bh->b_count), - 0, min); - atomic_add(min, &bh->b_count); - i -= min; - bh = bh->b_reqnext; - } - } - (void) idetape_add_chrdev_write_request(drive, blocks); - tape->merge_bh_size = 0; - } - if (tape->merge_bh != NULL) { - ide_tape_kfree_buffer(tape); - tape->merge_bh = NULL; + memset(tape->cur, 0, aligned - tape->valid); + idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, aligned); + kfree(tape->buf); + tape->buf = NULL; } tape->chrdev_dir = IDETAPE_DIR_NONE; } -static int idetape_init_read(ide_drive_t *drive) +static int idetape_init_rw(ide_drive_t *drive, int dir) { idetape_tape_t *tape = drive->driver_data; - int bytes_read; + int rc; - /* Initialize read operation */ - if (tape->chrdev_dir != IDETAPE_DIR_READ) { - if (tape->chrdev_dir == IDETAPE_DIR_WRITE) { - ide_tape_flush_merge_buffer(drive); - idetape_flush_tape_buffers(drive); - } - if (tape->merge_bh || tape->merge_bh_size) { - printk(KERN_ERR "ide-tape: merge_bh_size should be" - " 0 now\n"); - tape->merge_bh_size = 0; - } - tape->merge_bh = ide_tape_kmalloc_buffer(tape, 0, 0); - if (!tape->merge_bh) - return -ENOMEM; - tape->chrdev_dir = IDETAPE_DIR_READ; + BUG_ON(dir != IDETAPE_DIR_READ && dir != IDETAPE_DIR_WRITE); - /* - * Issue a read 0 command to ensure that DSC handshake is - * switched from completion mode to buffer available mode. - * No point in issuing this if DSC overlap isn't supported, some - * drives (Seagate STT3401A) will return an error. - */ - if (drive->dev_flags & IDE_DFLAG_DSC_OVERLAP) { - bytes_read = idetape_queue_rw_tail(drive, - REQ_IDETAPE_READ, 0, - tape->merge_bh); - if (bytes_read < 0) { - ide_tape_kfree_buffer(tape); - tape->merge_bh = NULL; - tape->chrdev_dir = IDETAPE_DIR_NONE; - return bytes_read; - } + if (tape->chrdev_dir == dir) + return 0; + + if (tape->chrdev_dir == IDETAPE_DIR_READ) + ide_tape_discard_merge_buffer(drive, 1); + else if (tape->chrdev_dir == IDETAPE_DIR_WRITE) { + ide_tape_flush_merge_buffer(drive); + idetape_flush_tape_buffers(drive); + } + + if (tape->buf || tape->valid) { + printk(KERN_ERR "ide-tape: valid should be 0 now\n"); + tape->valid = 0; + } + + tape->buf = kmalloc(tape->buffer_size, GFP_KERNEL); + if (!tape->buf) + return -ENOMEM; + tape->chrdev_dir = dir; + tape->cur = tape->buf; + + /* + * Issue a 0 rw command to ensure that DSC handshake is + * switched from completion mode to buffer available mode. No + * point in issuing this if DSC overlap isn't supported, some + * drives (Seagate STT3401A) will return an error. + */ + if (drive->dev_flags & IDE_DFLAG_DSC_OVERLAP) { + int cmd = dir == IDETAPE_DIR_READ ? REQ_IDETAPE_READ + : REQ_IDETAPE_WRITE; + + rc = idetape_queue_rw_tail(drive, cmd, 0); + if (rc < 0) { + kfree(tape->buf); + tape->buf = NULL; + tape->chrdev_dir = IDETAPE_DIR_NONE; + return rc; } } return 0; } -/* called from idetape_chrdev_read() to service a chrdev read request. */ -static int idetape_add_chrdev_read_request(ide_drive_t *drive, int blocks) -{ - idetape_tape_t *tape = drive->driver_data; - - debug_log(DBG_PROCS, "Enter %s, %d blocks\n", __func__, blocks); - - /* If we are at a filemark, return a read length of 0 */ - if (test_bit(IDE_AFLAG_FILEMARK, &drive->atapi_flags)) - return 0; - - idetape_init_read(drive); - - return idetape_queue_rw_tail(drive, REQ_IDETAPE_READ, blocks, - tape->merge_bh); -} - static void idetape_pad_zeros(ide_drive_t *drive, int bcount) { idetape_tape_t *tape = drive->driver_data; - struct idetape_bh *bh; - int blocks; + + memset(tape->buf, 0, tape->buffer_size); while (bcount) { - unsigned int count; + unsigned int count = min(tape->buffer_size, bcount); - bh = tape->merge_bh; - count = min(tape->buffer_size, bcount); + idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, count); bcount -= count; - blocks = count / tape->blk_size; - while (count) { - atomic_set(&bh->b_count, - min(count, (unsigned int)bh->b_size)); - memset(bh->b_data, 0, atomic_read(&bh->b_count)); - count -= atomic_read(&bh->b_count); - bh = bh->b_reqnext; - } - idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, blocks, - tape->merge_bh); } } @@ -1388,20 +1026,19 @@ static int idetape_rewind_tape(ide_drive_t *drive) { struct ide_tape_obj *tape = drive->driver_data; struct gendisk *disk = tape->disk; - int retval; struct ide_atapi_pc pc; + int ret; debug_log(DBG_SENSE, "Enter %s\n", __func__); idetape_create_rewind_cmd(drive, &pc); - retval = ide_queue_pc_tail(drive, disk, &pc); - if (retval) - return retval; + ret = ide_queue_pc_tail(drive, disk, &pc, NULL, 0); + if (ret) + return ret; - idetape_create_read_position_cmd(&pc); - retval = ide_queue_pc_tail(drive, disk, &pc); - if (retval) - return retval; + ret = ide_tape_read_position(drive); + if (ret < 0) + return ret; return 0; } @@ -1456,8 +1093,9 @@ static int idetape_space_over_filemarks(ide_drive_t *drive, short mt_op, } if (tape->chrdev_dir == IDETAPE_DIR_READ) { - tape->merge_bh_size = 0; - if (test_and_clear_bit(IDE_AFLAG_FILEMARK, &drive->atapi_flags)) + tape->valid = 0; + if (test_and_clear_bit(ilog2(IDE_AFLAG_FILEMARK), + &drive->atapi_flags)) ++count; ide_tape_discard_merge_buffer(drive, 0); } @@ -1467,7 +1105,7 @@ static int idetape_space_over_filemarks(ide_drive_t *drive, short mt_op, case MTBSF: idetape_create_space_cmd(&pc, mt_count - count, IDETAPE_SPACE_OVER_FILEMARK); - return ide_queue_pc_tail(drive, disk, &pc); + return ide_queue_pc_tail(drive, disk, &pc, NULL, 0); case MTFSFM: case MTBSFM: if (!sprev) @@ -1505,61 +1143,56 @@ static ssize_t idetape_chrdev_read(struct file *file, char __user *buf, { struct ide_tape_obj *tape = file->private_data; ide_drive_t *drive = tape->drive; - ssize_t bytes_read, temp, actually_read = 0, rc; + size_t done = 0; ssize_t ret = 0; - u16 ctl = *(u16 *)&tape->caps[12]; + int rc; debug_log(DBG_CHRDEV, "Enter %s, count %Zd\n", __func__, count); if (tape->chrdev_dir != IDETAPE_DIR_READ) { - if (test_bit(IDE_AFLAG_DETECT_BS, &drive->atapi_flags)) + if (test_bit(ilog2(IDE_AFLAG_DETECT_BS), &drive->atapi_flags)) if (count > tape->blk_size && (count % tape->blk_size) == 0) tape->user_bs_factor = count / tape->blk_size; } - rc = idetape_init_read(drive); + + rc = idetape_init_rw(drive, IDETAPE_DIR_READ); if (rc < 0) return rc; - if (count == 0) - return (0); - if (tape->merge_bh_size) { - actually_read = min((unsigned int)(tape->merge_bh_size), - (unsigned int)count); - if (idetape_copy_stage_to_user(tape, buf, actually_read)) + + while (done < count) { + size_t todo; + + /* refill if staging buffer is empty */ + if (!tape->valid) { + /* If we are at a filemark, nothing more to read */ + if (test_bit(ilog2(IDE_AFLAG_FILEMARK), + &drive->atapi_flags)) + break; + /* read */ + if (idetape_queue_rw_tail(drive, REQ_IDETAPE_READ, + tape->buffer_size) <= 0) + break; + } + + /* copy out */ + todo = min_t(size_t, count - done, tape->valid); + if (copy_to_user(buf + done, tape->cur, todo)) ret = -EFAULT; - buf += actually_read; - tape->merge_bh_size -= actually_read; - count -= actually_read; + + tape->cur += todo; + tape->valid -= todo; + done += todo; } - while (count >= tape->buffer_size) { - bytes_read = idetape_add_chrdev_read_request(drive, ctl); - if (bytes_read <= 0) - goto finish; - if (idetape_copy_stage_to_user(tape, buf, bytes_read)) - ret = -EFAULT; - buf += bytes_read; - count -= bytes_read; - actually_read += bytes_read; - } - if (count) { - bytes_read = idetape_add_chrdev_read_request(drive, ctl); - if (bytes_read <= 0) - goto finish; - temp = min((unsigned long)count, (unsigned long)bytes_read); - if (idetape_copy_stage_to_user(tape, buf, temp)) - ret = -EFAULT; - actually_read += temp; - tape->merge_bh_size = bytes_read-temp; - } -finish: - if (!actually_read && test_bit(IDE_AFLAG_FILEMARK, &drive->atapi_flags)) { + + if (!done && test_bit(ilog2(IDE_AFLAG_FILEMARK), &drive->atapi_flags)) { debug_log(DBG_SENSE, "%s: spacing over filemark\n", tape->name); idetape_space_over_filemarks(drive, MTFSF, 1); return 0; } - return ret ? ret : actually_read; + return ret ? ret : done; } static ssize_t idetape_chrdev_write(struct file *file, const char __user *buf, @@ -1567,9 +1200,9 @@ static ssize_t idetape_chrdev_write(struct file *file, const char __user *buf, { struct ide_tape_obj *tape = file->private_data; ide_drive_t *drive = tape->drive; - ssize_t actually_written = 0; + size_t done = 0; ssize_t ret = 0; - u16 ctl = *(u16 *)&tape->caps[12]; + int rc; /* The drive is write protected. */ if (tape->write_prot) @@ -1578,80 +1211,31 @@ static ssize_t idetape_chrdev_write(struct file *file, const char __user *buf, debug_log(DBG_CHRDEV, "Enter %s, count %Zd\n", __func__, count); /* Initialize write operation */ - if (tape->chrdev_dir != IDETAPE_DIR_WRITE) { - if (tape->chrdev_dir == IDETAPE_DIR_READ) - ide_tape_discard_merge_buffer(drive, 1); - if (tape->merge_bh || tape->merge_bh_size) { - printk(KERN_ERR "ide-tape: merge_bh_size " - "should be 0 now\n"); - tape->merge_bh_size = 0; - } - tape->merge_bh = ide_tape_kmalloc_buffer(tape, 0, 0); - if (!tape->merge_bh) - return -ENOMEM; - tape->chrdev_dir = IDETAPE_DIR_WRITE; - idetape_init_merge_buffer(tape); + rc = idetape_init_rw(drive, IDETAPE_DIR_WRITE); + if (rc < 0) + return rc; - /* - * Issue a write 0 command to ensure that DSC handshake is - * switched from completion mode to buffer available mode. No - * point in issuing this if DSC overlap isn't supported, some - * drives (Seagate STT3401A) will return an error. - */ - if (drive->dev_flags & IDE_DFLAG_DSC_OVERLAP) { - ssize_t retval = idetape_queue_rw_tail(drive, - REQ_IDETAPE_WRITE, 0, - tape->merge_bh); - if (retval < 0) { - ide_tape_kfree_buffer(tape); - tape->merge_bh = NULL; - tape->chrdev_dir = IDETAPE_DIR_NONE; - return retval; - } - } - } - if (count == 0) - return (0); - if (tape->merge_bh_size) { - if (tape->merge_bh_size >= tape->buffer_size) { - printk(KERN_ERR "ide-tape: bug: merge buf too big\n"); - tape->merge_bh_size = 0; - } - actually_written = min((unsigned int) - (tape->buffer_size - tape->merge_bh_size), - (unsigned int)count); - if (idetape_copy_stage_from_user(tape, buf, actually_written)) - ret = -EFAULT; - buf += actually_written; - tape->merge_bh_size += actually_written; - count -= actually_written; + while (done < count) { + size_t todo; - if (tape->merge_bh_size == tape->buffer_size) { - ssize_t retval; - tape->merge_bh_size = 0; - retval = idetape_add_chrdev_write_request(drive, ctl); - if (retval <= 0) - return (retval); - } - } - while (count >= tape->buffer_size) { - ssize_t retval; - if (idetape_copy_stage_from_user(tape, buf, tape->buffer_size)) + /* flush if staging buffer is full */ + if (tape->valid == tape->buffer_size && + idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, + tape->buffer_size) <= 0) + return rc; + + /* copy in */ + todo = min_t(size_t, count - done, + tape->buffer_size - tape->valid); + if (copy_from_user(tape->cur, buf + done, todo)) ret = -EFAULT; - buf += tape->buffer_size; - count -= tape->buffer_size; - retval = idetape_add_chrdev_write_request(drive, ctl); - actually_written += tape->buffer_size; - if (retval <= 0) - return (retval); + + tape->cur += todo; + tape->valid += todo; + done += todo; } - if (count) { - actually_written += count; - if (idetape_copy_stage_from_user(tape, buf, count)) - ret = -EFAULT; - tape->merge_bh_size += count; - } - return ret ? ret : actually_written; + + return ret ? ret : done; } static int idetape_write_filemark(ide_drive_t *drive) @@ -1661,7 +1245,7 @@ static int idetape_write_filemark(ide_drive_t *drive) /* Write a filemark */ idetape_create_write_filemark_cmd(drive, &pc, 1); - if (ide_queue_pc_tail(drive, tape->disk, &pc)) { + if (ide_queue_pc_tail(drive, tape->disk, &pc, NULL, 0)) { printk(KERN_ERR "ide-tape: Couldn't write a filemark\n"); return -EIO; } @@ -1735,7 +1319,8 @@ static int idetape_mtioctop(ide_drive_t *drive, short mt_op, int mt_count) ide_tape_discard_merge_buffer(drive, 0); retval = ide_do_start_stop(drive, disk, !IDETAPE_LU_LOAD_MASK); if (!retval) - clear_bit(IDE_AFLAG_MEDIUM_PRESENT, &drive->atapi_flags); + clear_bit(ilog2(IDE_AFLAG_MEDIUM_PRESENT), + &drive->atapi_flags); return retval; case MTNOP: ide_tape_discard_merge_buffer(drive, 0); @@ -1746,20 +1331,22 @@ static int idetape_mtioctop(ide_drive_t *drive, short mt_op, int mt_count) IDETAPE_LU_RETENSION_MASK | IDETAPE_LU_LOAD_MASK); case MTEOM: idetape_create_space_cmd(&pc, 0, IDETAPE_SPACE_TO_EOD); - return ide_queue_pc_tail(drive, disk, &pc); + return ide_queue_pc_tail(drive, disk, &pc, NULL, 0); case MTERASE: (void)idetape_rewind_tape(drive); idetape_create_erase_cmd(&pc); - return ide_queue_pc_tail(drive, disk, &pc); + return ide_queue_pc_tail(drive, disk, &pc, NULL, 0); case MTSETBLK: if (mt_count) { if (mt_count < tape->blk_size || mt_count % tape->blk_size) return -EIO; tape->user_bs_factor = mt_count / tape->blk_size; - clear_bit(IDE_AFLAG_DETECT_BS, &drive->atapi_flags); + clear_bit(ilog2(IDE_AFLAG_DETECT_BS), + &drive->atapi_flags); } else - set_bit(IDE_AFLAG_DETECT_BS, &drive->atapi_flags); + set_bit(ilog2(IDE_AFLAG_DETECT_BS), + &drive->atapi_flags); return 0; case MTSEEK: ide_tape_discard_merge_buffer(drive, 0); @@ -1812,9 +1399,9 @@ static int idetape_chrdev_ioctl(struct inode *inode, struct file *file, idetape_flush_tape_buffers(drive); } if (cmd == MTIOCGET || cmd == MTIOCPOS) { - block_offset = tape->merge_bh_size / + block_offset = tape->valid / (tape->blk_size * tape->user_bs_factor); - position = idetape_read_position(drive); + position = ide_tape_read_position(drive); if (position < 0) return -EIO; } @@ -1857,9 +1444,10 @@ static void ide_tape_get_bsize_from_bdesc(ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; struct ide_atapi_pc pc; + u8 buf[12]; idetape_create_mode_sense_cmd(&pc, IDETAPE_BLOCK_DESCRIPTOR); - if (ide_queue_pc_tail(drive, tape->disk, &pc)) { + if (ide_queue_pc_tail(drive, tape->disk, &pc, buf, pc.req_xfer)) { printk(KERN_ERR "ide-tape: Can't get block descriptor\n"); if (tape->blk_size == 0) { printk(KERN_WARNING "ide-tape: Cannot deal with zero " @@ -1868,10 +1456,10 @@ static void ide_tape_get_bsize_from_bdesc(ide_drive_t *drive) } return; } - tape->blk_size = (pc.buf[4 + 5] << 16) + - (pc.buf[4 + 6] << 8) + - pc.buf[4 + 7]; - tape->drv_write_prot = (pc.buf[2] & 0x80) >> 7; + tape->blk_size = (buf[4 + 5] << 16) + + (buf[4 + 6] << 8) + + buf[4 + 7]; + tape->drv_write_prot = (buf[2] & 0x80) >> 7; } static int idetape_chrdev_open(struct inode *inode, struct file *filp) @@ -1885,7 +1473,7 @@ static int idetape_chrdev_open(struct inode *inode, struct file *filp) return -ENXIO; lock_kernel(); - tape = ide_tape_chrdev_get(i); + tape = ide_tape_get(NULL, true, i); if (!tape) { unlock_kernel(); return -ENXIO; @@ -1904,20 +1492,20 @@ static int idetape_chrdev_open(struct inode *inode, struct file *filp) filp->private_data = tape; - if (test_and_set_bit(IDE_AFLAG_BUSY, &drive->atapi_flags)) { + if (test_and_set_bit(ilog2(IDE_AFLAG_BUSY), &drive->atapi_flags)) { retval = -EBUSY; goto out_put_tape; } retval = idetape_wait_ready(drive, 60 * HZ); if (retval) { - clear_bit(IDE_AFLAG_BUSY, &drive->atapi_flags); + clear_bit(ilog2(IDE_AFLAG_BUSY), &drive->atapi_flags); printk(KERN_ERR "ide-tape: %s: drive not ready\n", tape->name); goto out_put_tape; } - idetape_read_position(drive); - if (!test_bit(IDE_AFLAG_ADDRESS_VALID, &drive->atapi_flags)) + ide_tape_read_position(drive); + if (!test_bit(ilog2(IDE_AFLAG_ADDRESS_VALID), &drive->atapi_flags)) (void)idetape_rewind_tape(drive); /* Read block size and write protect status from drive. */ @@ -1933,7 +1521,7 @@ static int idetape_chrdev_open(struct inode *inode, struct file *filp) if (tape->write_prot) { if ((filp->f_flags & O_ACCMODE) == O_WRONLY || (filp->f_flags & O_ACCMODE) == O_RDWR) { - clear_bit(IDE_AFLAG_BUSY, &drive->atapi_flags); + clear_bit(ilog2(IDE_AFLAG_BUSY), &drive->atapi_flags); retval = -EROFS; goto out_put_tape; } @@ -1960,12 +1548,12 @@ static void idetape_write_release(ide_drive_t *drive, unsigned int minor) idetape_tape_t *tape = drive->driver_data; ide_tape_flush_merge_buffer(drive); - tape->merge_bh = ide_tape_kmalloc_buffer(tape, 1, 0); - if (tape->merge_bh != NULL) { + tape->buf = kmalloc(tape->buffer_size, GFP_KERNEL); + if (tape->buf != NULL) { idetape_pad_zeros(drive, tape->blk_size * (tape->user_bs_factor - 1)); - ide_tape_kfree_buffer(tape); - tape->merge_bh = NULL; + kfree(tape->buf); + tape->buf = NULL; } idetape_write_filemark(drive); idetape_flush_tape_buffers(drive); @@ -1990,15 +1578,17 @@ static int idetape_chrdev_release(struct inode *inode, struct file *filp) ide_tape_discard_merge_buffer(drive, 1); } - if (minor < 128 && test_bit(IDE_AFLAG_MEDIUM_PRESENT, &drive->atapi_flags)) + if (minor < 128 && test_bit(ilog2(IDE_AFLAG_MEDIUM_PRESENT), + &drive->atapi_flags)) (void) idetape_rewind_tape(drive); + if (tape->chrdev_dir == IDETAPE_DIR_NONE) { if (tape->door_locked == DOOR_LOCKED) { if (!ide_set_media_lock(drive, tape->disk, 0)) tape->door_locked = DOOR_UNLOCKED; } } - clear_bit(IDE_AFLAG_BUSY, &drive->atapi_flags); + clear_bit(ilog2(IDE_AFLAG_BUSY), &drive->atapi_flags); ide_tape_put(tape); unlock_kernel(); return 0; @@ -2012,17 +1602,14 @@ static void idetape_get_inquiry_results(ide_drive_t *drive) char fw_rev[4], vendor_id[8], product_id[16]; idetape_create_inquiry_cmd(&pc); - pc.buf = &pc_buf[0]; - pc.buf_size = sizeof(pc_buf); - - if (ide_queue_pc_tail(drive, tape->disk, &pc)) { + if (ide_queue_pc_tail(drive, tape->disk, &pc, pc_buf, pc.req_xfer)) { printk(KERN_ERR "ide-tape: %s: can't get INQUIRY results\n", tape->name); return; } - memcpy(vendor_id, &pc.buf[8], 8); - memcpy(product_id, &pc.buf[16], 16); - memcpy(fw_rev, &pc.buf[32], 4); + memcpy(vendor_id, &pc_buf[8], 8); + memcpy(product_id, &pc_buf[16], 16); + memcpy(fw_rev, &pc_buf[32], 4); ide_fixstring(vendor_id, 8, 0); ide_fixstring(product_id, 16, 0); @@ -2040,11 +1627,11 @@ static void idetape_get_mode_sense_results(ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; struct ide_atapi_pc pc; - u8 *caps; + u8 buf[24], *caps; u8 speed, max_speed; idetape_create_mode_sense_cmd(&pc, IDETAPE_CAPABILITIES_PAGE); - if (ide_queue_pc_tail(drive, tape->disk, &pc)) { + if (ide_queue_pc_tail(drive, tape->disk, &pc, buf, pc.req_xfer)) { printk(KERN_ERR "ide-tape: Can't get tape parameters - assuming" " some default values\n"); tape->blk_size = 512; @@ -2053,7 +1640,7 @@ static void idetape_get_mode_sense_results(ide_drive_t *drive) put_unaligned(6*52, (u16 *)&tape->caps[16]); return; } - caps = pc.buf + 4 + pc.buf[3]; + caps = buf + 4 + buf[3]; /* convert to host order and save for later use */ speed = be16_to_cpup((__be16 *)&caps[14]); @@ -2159,8 +1746,6 @@ static void idetape_setup(ide_drive_t *drive, idetape_tape_t *tape, int minor) u16 *ctl = (u16 *)&tape->caps[12]; drive->pc_callback = ide_tape_callback; - drive->pc_update_buffers = idetape_update_buffers; - drive->pc_io_buffers = ide_tape_io_buffers; drive->dev_flags |= IDE_DFLAG_DSC_OVERLAP; @@ -2191,11 +1776,6 @@ static void idetape_setup(ide_drive_t *drive, idetape_tape_t *tape, int minor) tape->buffer_size = *ctl * tape->blk_size; } buffer_size = tape->buffer_size; - tape->pages_per_buffer = buffer_size / PAGE_SIZE; - if (buffer_size % PAGE_SIZE) { - tape->pages_per_buffer++; - tape->excess_bh_size = PAGE_SIZE - buffer_size % PAGE_SIZE; - } /* select the "best" DSC read/write polling freq */ speed = max(*(u16 *)&tape->caps[14], *(u16 *)&tape->caps[8]); @@ -2238,7 +1818,7 @@ static void ide_tape_release(struct device *dev) ide_drive_t *drive = tape->drive; struct gendisk *g = tape->disk; - BUG_ON(tape->merge_bh_size); + BUG_ON(tape->valid); drive->dev_flags &= ~IDE_DFLAG_DSC_OVERLAP; drive->driver_data = NULL; @@ -2311,7 +1891,7 @@ static const struct file_operations idetape_fops = { static int idetape_open(struct block_device *bdev, fmode_t mode) { - struct ide_tape_obj *tape = ide_tape_get(bdev->bd_disk); + struct ide_tape_obj *tape = ide_tape_get(bdev->bd_disk, false, 0); if (!tape) return -ENXIO; diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c index 4aa6223c11be..75b85a8cd2d4 100644 --- a/drivers/ide/ide-taskfile.c +++ b/drivers/ide/ide-taskfile.c @@ -98,7 +98,6 @@ ide_startstop_t do_rw_taskfile(ide_drive_t *drive, struct ide_cmd *orig_cmd) if ((cmd->tf_flags & IDE_TFLAG_DMA_PIO_FALLBACK) == 0) { ide_tf_dump(drive->name, cmd); tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS); - SELECT_MASK(drive, 0); if (cmd->ftf_flags & IDE_FTFLAG_OUT_DATA) { u8 data[2] = { cmd->tf.data, cmd->hob.data }; @@ -166,7 +165,7 @@ static ide_startstop_t task_no_data_intr(ide_drive_t *drive) if (!OK_STAT(stat, ATA_DRDY, BAD_STAT)) { if (custom && tf->command == ATA_CMD_SET_MULTI) { drive->mult_req = drive->mult_count = 0; - drive->special.b.recalibrate = 1; + drive->special_flags |= IDE_SFLAG_RECALIBRATE; (void)ide_dump_status(drive, __func__, stat); return ide_stopped; } else if (custom && tf->command == ATA_CMD_INIT_DEV_PARAMS) { @@ -385,7 +384,7 @@ out_end: if ((cmd->tf_flags & IDE_TFLAG_FS) == 0) ide_finish_cmd(drive, cmd, stat); else - ide_complete_rq(drive, 0, cmd->rq->nr_sectors << 9); + ide_complete_rq(drive, 0, blk_rq_sectors(cmd->rq) << 9); return ide_stopped; out_err: ide_error_cmd(drive, cmd); @@ -424,7 +423,9 @@ int ide_raw_taskfile(ide_drive_t *drive, struct ide_cmd *cmd, u8 *buf, rq = blk_get_request(drive->queue, READ, __GFP_WAIT); rq->cmd_type = REQ_TYPE_ATA_TASKFILE; - rq->buffer = buf; + + if (cmd->tf_flags & IDE_TFLAG_WRITE) + rq->cmd_flags |= REQ_RW; /* * (ks) We transfer currently only whole sectors. @@ -432,18 +433,20 @@ int ide_raw_taskfile(ide_drive_t *drive, struct ide_cmd *cmd, u8 *buf, * if we would find a solution to transfer any size. * To support special commands like READ LONG. */ - rq->hard_nr_sectors = rq->nr_sectors = nsect; - rq->hard_cur_sectors = rq->current_nr_sectors = nsect; - - if (cmd->tf_flags & IDE_TFLAG_WRITE) - rq->cmd_flags |= REQ_RW; + if (nsect) { + error = blk_rq_map_kern(drive->queue, rq, buf, + nsect * SECTOR_SIZE, __GFP_WAIT); + if (error) + goto put_req; + } rq->special = cmd; cmd->rq = rq; error = blk_execute_rq(drive->queue, NULL, rq, 0); - blk_put_request(rq); +put_req: + blk_put_request(rq); return error; } diff --git a/drivers/ide/ide-xfer-mode.c b/drivers/ide/ide-xfer-mode.c index af44be9d546c..46d203ce60cc 100644 --- a/drivers/ide/ide-xfer-mode.c +++ b/drivers/ide/ide-xfer-mode.c @@ -107,6 +107,18 @@ u8 ide_get_best_pio_mode(ide_drive_t *drive, u8 mode_wanted, u8 max_mode) } EXPORT_SYMBOL_GPL(ide_get_best_pio_mode); +int ide_pio_need_iordy(ide_drive_t *drive, const u8 pio) +{ + /* + * IORDY may lead to controller lock up on certain controllers + * if the port is not occupied. + */ + if (pio == 0 && (drive->hwif->port_flags & IDE_PFLAG_PROBING)) + return 0; + return ata_id_pio_need_iordy(drive->id, pio); +} +EXPORT_SYMBOL_GPL(ide_pio_need_iordy); + int ide_set_pio_mode(ide_drive_t *drive, const u8 mode) { ide_hwif_t *hwif = drive->hwif; diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index 92c9b90931e7..16d056939f9f 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -211,6 +211,11 @@ static unsigned int ide_noflush; module_param_call(noflush, ide_set_dev_param_mask, NULL, &ide_noflush, 0); MODULE_PARM_DESC(noflush, "disable flush requests for a device"); +static unsigned int ide_nohpa; + +module_param_call(nohpa, ide_set_dev_param_mask, NULL, &ide_nohpa, 0); +MODULE_PARM_DESC(nohpa, "disable Host Protected Area for a device"); + static unsigned int ide_noprobe; module_param_call(noprobe, ide_set_dev_param_mask, NULL, &ide_noprobe, 0); @@ -281,6 +286,11 @@ static void ide_dev_apply_params(ide_drive_t *drive, u8 unit) drive->name); drive->dev_flags |= IDE_DFLAG_NOFLUSH; } + if (ide_nohpa & (1 << i)) { + printk(KERN_INFO "ide: disabling Host Protected Area for %s\n", + drive->name); + drive->dev_flags |= IDE_DFLAG_NOHPA; + } if (ide_noprobe & (1 << i)) { printk(KERN_INFO "ide: skipping probe for %s\n", drive->name); drive->dev_flags |= IDE_DFLAG_NOPROBE; diff --git a/drivers/ide/ide_platform.c b/drivers/ide/ide_platform.c index 051b4ab0f359..b579fbe88370 100644 --- a/drivers/ide/ide_platform.c +++ b/drivers/ide/ide_platform.c @@ -21,7 +21,7 @@ #include #include -static void __devinit plat_ide_setup_ports(hw_regs_t *hw, +static void __devinit plat_ide_setup_ports(struct ide_hw *hw, void __iomem *base, void __iomem *ctrl, struct pata_platform_info *pdata, @@ -40,12 +40,11 @@ static void __devinit plat_ide_setup_ports(hw_regs_t *hw, hw->io_ports.ctl_addr = (unsigned long)ctrl; hw->irq = irq; - - hw->chipset = ide_generic; } static const struct ide_port_info platform_ide_port_info = { .host_flags = IDE_HFLAG_NO_DMA, + .chipset = ide_generic, }; static int __devinit plat_ide_probe(struct platform_device *pdev) @@ -55,7 +54,7 @@ static int __devinit plat_ide_probe(struct platform_device *pdev) struct pata_platform_info *pdata; struct ide_host *host; int ret = 0, mmio = 0; - hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL }; + struct ide_hw hw, *hws[] = { &hw }; struct ide_port_info d = platform_ide_port_info; pdata = pdev->dev.platform_data; @@ -99,7 +98,7 @@ static int __devinit plat_ide_probe(struct platform_device *pdev) if (mmio) d.host_flags |= IDE_HFLAG_MMIO; - ret = ide_host_add(&d, hws, &host); + ret = ide_host_add(&d, hws, 1, &host); if (ret) goto out; @@ -113,7 +112,7 @@ out: static int __devexit plat_ide_remove(struct platform_device *pdev) { - struct ide_host *host = pdev->dev.driver_data; + struct ide_host *host = dev_get_drvdata(&pdev->dev); ide_host_remove(host); diff --git a/drivers/ide/it8172.c b/drivers/ide/it8172.c index e021078cd06b..0d266a5b524d 100644 --- a/drivers/ide/it8172.c +++ b/drivers/ide/it8172.c @@ -66,7 +66,7 @@ static void it8172_set_pio_mode(ide_drive_t *drive, const u8 pio) if (drive->media == ide_disk) /* enable prefetch */ drive_enables |= 0x0004 << (drive->dn * 4); - if (ata_id_has_iordy(drive->id)) + if (ide_pio_need_iordy(drive, pio)) /* enable IORDY sample-point */ drive_enables |= 0x0002 << (drive->dn * 4); diff --git a/drivers/ide/it8213.c b/drivers/ide/it8213.c index d7969b6d139e..47976167796a 100644 --- a/drivers/ide/it8213.c +++ b/drivers/ide/it8213.c @@ -50,7 +50,7 @@ static void it8213_set_pio_mode(ide_drive_t *drive, const u8 pio) control |= 1; /* Programmable timing on */ if (drive->media != ide_disk) control |= 4; /* ATAPI */ - if (pio > 2) + if (ide_pio_need_iordy(drive, pio)) control |= 2; /* IORDY */ if (is_slave) { master_data |= 0x4000; diff --git a/drivers/ide/macide.c b/drivers/ide/macide.c index 4b1718e83283..505ec43e5606 100644 --- a/drivers/ide/macide.c +++ b/drivers/ide/macide.c @@ -53,17 +53,20 @@ volatile unsigned char *ide_ifr = (unsigned char *) (IDE_BASE + IDE_IFR); -int macide_ack_intr(ide_hwif_t* hwif) +int macide_test_irq(ide_hwif_t *hwif) { - if (*ide_ifr & 0x20) { - *ide_ifr &= ~0x20; + if (*ide_ifr & 0x20) return 1; - } return 0; } -static void __init macide_setup_ports(hw_regs_t *hw, unsigned long base, - int irq, ide_ack_intr_t *ack_intr) +static void macide_clear_irq(ide_drive_t *drive) +{ + *ide_ifr &= ~0x20; +} + +static void __init macide_setup_ports(struct ide_hw *hw, unsigned long base, + int irq) { int i; @@ -75,14 +78,18 @@ static void __init macide_setup_ports(hw_regs_t *hw, unsigned long base, hw->io_ports.ctl_addr = base + IDE_CONTROL; hw->irq = irq; - hw->ack_intr = ack_intr; - - hw->chipset = ide_generic; } +static const struct ide_port_ops macide_port_ops = { + .clear_irq = macide_clear_irq, + .test_irq = macide_test_irq, +}; + static const struct ide_port_info macide_port_info = { + .port_ops = &macide_port_ops, .host_flags = IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA, .irq_flags = IRQF_SHARED, + .chipset = ide_generic, }; static const char *mac_ide_name[] = @@ -94,10 +101,10 @@ static const char *mac_ide_name[] = static int __init macide_init(void) { - ide_ack_intr_t *ack_intr; unsigned long base; int irq; - hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL }; + struct ide_hw hw, *hws[] = { &hw }; + struct ide_port_info d = macide_port_info; if (!MACH_IS_MAC) return -ENODEV; @@ -105,17 +112,15 @@ static int __init macide_init(void) switch (macintosh_config->ide_type) { case MAC_IDE_QUADRA: base = IDE_BASE; - ack_intr = macide_ack_intr; irq = IRQ_NUBUS_F; break; case MAC_IDE_PB: base = IDE_BASE; - ack_intr = macide_ack_intr; irq = IRQ_NUBUS_C; break; case MAC_IDE_BABOON: base = BABOON_BASE; - ack_intr = NULL; + d.port_ops = NULL; irq = IRQ_BABOON_1; break; default: @@ -125,9 +130,9 @@ static int __init macide_init(void) printk(KERN_INFO "ide: Macintosh %s IDE controller\n", mac_ide_name[macintosh_config->ide_type - 1]); - macide_setup_ports(&hw, base, irq, ack_intr); + macide_setup_ports(&hw, base, irq); - return ide_host_add(&macide_port_info, hws, NULL); + return ide_host_add(&d, hws, 1, NULL); } module_init(macide_init); diff --git a/drivers/ide/opti621.c b/drivers/ide/opti621.c index 6048eda3cd61..f1d70d6630fe 100644 --- a/drivers/ide/opti621.c +++ b/drivers/ide/opti621.c @@ -138,6 +138,7 @@ static void opti621_set_pio_mode(ide_drive_t *drive, const u8 pio) ide_hwif_t *hwif = drive->hwif; ide_drive_t *pair = ide_get_pair_dev(drive); unsigned long flags; + unsigned long mode = XFER_PIO_0 + pio, pair_mode; u8 tim, misc, addr_pio = pio, clk; /* DRDY is default 2 (by OPTi Databook) */ @@ -150,11 +151,12 @@ static void opti621_set_pio_mode(ide_drive_t *drive, const u8 pio) { 0x48, 0x34, 0x21, 0x10, 0x10 } /* 25 MHz */ }; - drive->drive_data = XFER_PIO_0 + pio; + ide_set_drivedata(drive, (void *)mode); if (pair) { - if (pair->drive_data && pair->drive_data < drive->drive_data) - addr_pio = pair->drive_data - XFER_PIO_0; + pair_mode = (unsigned long)ide_get_drivedata(pair); + if (pair_mode && pair_mode < mode) + addr_pio = pair_mode - XFER_PIO_0; } spin_lock_irqsave(&opti621_lock, flags); diff --git a/drivers/ide/palm_bk3710.c b/drivers/ide/palm_bk3710.c index 09d813d313f4..3c1dc0152153 100644 --- a/drivers/ide/palm_bk3710.c +++ b/drivers/ide/palm_bk3710.c @@ -306,6 +306,7 @@ static struct ide_port_info __devinitdata palm_bk3710_port_info = { .host_flags = IDE_HFLAG_MMIO, .pio_mask = ATA_PIO4, .mwdma_mask = ATA_MWDMA2, + .chipset = ide_palm3710, }; static int __init palm_bk3710_probe(struct platform_device *pdev) @@ -315,7 +316,7 @@ static int __init palm_bk3710_probe(struct platform_device *pdev) void __iomem *base; unsigned long rate, mem_size; int i, rc; - hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL }; + struct ide_hw hw, *hws[] = { &hw }; clk = clk_get(&pdev->dev, "IDECLK"); if (IS_ERR(clk)) @@ -363,13 +364,12 @@ static int __init palm_bk3710_probe(struct platform_device *pdev) (base + IDE_PALM_ATA_PRI_CTL_OFFSET); hw.irq = irq->start; hw.dev = &pdev->dev; - hw.chipset = ide_palm3710; palm_bk3710_port_info.udma_mask = rate < 100000000 ? ATA_UDMA4 : ATA_UDMA5; /* Register the IDE interface with Linux */ - rc = ide_host_add(&palm_bk3710_port_info, hws, NULL); + rc = ide_host_add(&palm_bk3710_port_info, hws, 1, NULL); if (rc) goto out; diff --git a/drivers/ide/pdc202xx_new.c b/drivers/ide/pdc202xx_new.c index b68906c3c17e..65ba8239e7b5 100644 --- a/drivers/ide/pdc202xx_new.c +++ b/drivers/ide/pdc202xx_new.c @@ -40,18 +40,6 @@ #define DBG(fmt, args...) #endif -static const char *pdc_quirk_drives[] = { - "QUANTUM FIREBALLlct08 08", - "QUANTUM FIREBALLP KA6.4", - "QUANTUM FIREBALLP KA9.1", - "QUANTUM FIREBALLP LM20.4", - "QUANTUM FIREBALLP KX13.6", - "QUANTUM FIREBALLP KX20.5", - "QUANTUM FIREBALLP KX27.3", - "QUANTUM FIREBALLP LM20.5", - NULL -}; - static u8 max_dma_rate(struct pci_dev *pdev) { u8 mode; @@ -200,19 +188,6 @@ static u8 pdcnew_cable_detect(ide_hwif_t *hwif) return ATA_CBL_PATA80; } -static void pdcnew_quirkproc(ide_drive_t *drive) -{ - const char **list, *m = (char *)&drive->id[ATA_ID_PROD]; - - for (list = pdc_quirk_drives; *list != NULL; list++) - if (strstr(m, *list) != NULL) { - drive->quirk_list = 2; - return; - } - - drive->quirk_list = 0; -} - static void pdcnew_reset(ide_drive_t *drive) { /* @@ -473,7 +448,6 @@ static struct pci_dev * __devinit pdc20270_get_dev2(struct pci_dev *dev) static const struct ide_port_ops pdcnew_port_ops = { .set_pio_mode = pdcnew_set_pio_mode, .set_dma_mode = pdcnew_set_dma_mode, - .quirkproc = pdcnew_quirkproc, .resetproc = pdcnew_reset, .cable_detect = pdcnew_cable_detect, }; diff --git a/drivers/ide/pdc202xx_old.c b/drivers/ide/pdc202xx_old.c index b3bc96f930a6..cb812f3700e8 100644 --- a/drivers/ide/pdc202xx_old.c +++ b/drivers/ide/pdc202xx_old.c @@ -23,18 +23,6 @@ #define PDC202XX_DEBUG_DRIVE_INFO 0 -static const char *pdc_quirk_drives[] = { - "QUANTUM FIREBALLlct08 08", - "QUANTUM FIREBALLP KA6.4", - "QUANTUM FIREBALLP KA9.1", - "QUANTUM FIREBALLP LM20.4", - "QUANTUM FIREBALLP KX13.6", - "QUANTUM FIREBALLP KX20.5", - "QUANTUM FIREBALLP KX27.3", - "QUANTUM FIREBALLP LM20.5", - NULL -}; - static void pdc_old_disable_66MHz_clock(ide_hwif_t *); static void pdc202xx_set_mode(ide_drive_t *drive, const u8 speed) @@ -85,7 +73,7 @@ static void pdc202xx_set_mode(ide_drive_t *drive, const u8 speed) * Prefetch_EN / IORDY_EN / PA[3:0] bits of register A */ AP &= ~0x3f; - if (ata_id_iordy_disable(drive->id)) + if (ide_pio_need_iordy(drive, speed - XFER_PIO_0)) AP |= 0x20; /* set IORDY_EN bit */ if (drive->media == ide_disk) AP |= 0x10; /* set Prefetch_EN bit */ @@ -116,6 +104,27 @@ static void pdc202xx_set_pio_mode(ide_drive_t *drive, const u8 pio) pdc202xx_set_mode(drive, XFER_PIO_0 + pio); } +static int pdc202xx_test_irq(ide_hwif_t *hwif) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + unsigned long high_16 = pci_resource_start(dev, 4); + u8 sc1d = inb(high_16 + 0x1d); + + if (hwif->channel) { + /* + * bit 7: error, bit 6: interrupting, + * bit 5: FIFO full, bit 4: FIFO empty + */ + return ((sc1d & 0x50) == 0x40) ? 1 : 0; + } else { + /* + * bit 3: error, bit 2: interrupting, + * bit 1: FIFO full, bit 0: FIFO empty + */ + return ((sc1d & 0x05) == 0x04) ? 1 : 0; + } +} + static u8 pdc2026x_cable_detect(ide_hwif_t *hwif) { struct pci_dev *dev = to_pci_dev(hwif->dev); @@ -151,19 +160,6 @@ static void pdc_old_disable_66MHz_clock(ide_hwif_t *hwif) outb(clock & ~(hwif->channel ? 0x08 : 0x02), clock_reg); } -static void pdc202xx_quirkproc(ide_drive_t *drive) -{ - const char **list, *m = (char *)&drive->id[ATA_ID_PROD]; - - for (list = pdc_quirk_drives; *list != NULL; list++) - if (strstr(m, *list) != NULL) { - drive->quirk_list = 2; - return; - } - - drive->quirk_list = 0; -} - static void pdc202xx_dma_start(ide_drive_t *drive) { if (drive->current_speed > XFER_UDMA_2) @@ -177,7 +173,7 @@ static void pdc202xx_dma_start(ide_drive_t *drive) u8 clock = inb(high_16 + 0x11); outb(clock | (hwif->channel ? 0x08 : 0x02), high_16 + 0x11); - word_count = (rq->nr_sectors << 8); + word_count = (blk_rq_sectors(rq) << 8); word_count = (rq_data_dir(rq) == READ) ? word_count | 0x05000000 : word_count | 0x06000000; @@ -203,52 +199,6 @@ static int pdc202xx_dma_end(ide_drive_t *drive) return ide_dma_end(drive); } -static int pdc202xx_dma_test_irq(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - unsigned long high_16 = hwif->extra_base - 16; - u8 dma_stat = inb(hwif->dma_base + ATA_DMA_STATUS); - u8 sc1d = inb(high_16 + 0x001d); - - if (hwif->channel) { - /* bit7: Error, bit6: Interrupting, bit5: FIFO Full, bit4: FIFO Empty */ - if ((sc1d & 0x50) == 0x50) - goto somebody_else; - else if ((sc1d & 0x40) == 0x40) - return (dma_stat & 4) == 4; - } else { - /* bit3: Error, bit2: Interrupting, bit1: FIFO Full, bit0: FIFO Empty */ - if ((sc1d & 0x05) == 0x05) - goto somebody_else; - else if ((sc1d & 0x04) == 0x04) - return (dma_stat & 4) == 4; - } -somebody_else: - return (dma_stat & 4) == 4; /* return 1 if INTR asserted */ -} - -static void pdc202xx_reset(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - unsigned long high_16 = hwif->extra_base - 16; - u8 udma_speed_flag = inb(high_16 | 0x001f); - - printk(KERN_WARNING "PDC202xx: software reset...\n"); - - outb(udma_speed_flag | 0x10, high_16 | 0x001f); - mdelay(100); - outb(udma_speed_flag & ~0x10, high_16 | 0x001f); - mdelay(2000); /* 2 seconds ?! */ - - ide_set_max_pio(drive); -} - -static void pdc202xx_dma_lost_irq(ide_drive_t *drive) -{ - pdc202xx_reset(drive); - ide_dma_lost_irq(drive); -} - static int init_chipset_pdc202xx(struct pci_dev *dev) { unsigned long dmabase = pci_resource_start(dev, 4); @@ -302,37 +252,23 @@ static void __devinit pdc202ata4_fixup_irq(struct pci_dev *dev, static const struct ide_port_ops pdc20246_port_ops = { .set_pio_mode = pdc202xx_set_pio_mode, .set_dma_mode = pdc202xx_set_mode, - .quirkproc = pdc202xx_quirkproc, + .test_irq = pdc202xx_test_irq, }; static const struct ide_port_ops pdc2026x_port_ops = { .set_pio_mode = pdc202xx_set_pio_mode, .set_dma_mode = pdc202xx_set_mode, - .quirkproc = pdc202xx_quirkproc, - .resetproc = pdc202xx_reset, .cable_detect = pdc2026x_cable_detect, }; -static const struct ide_dma_ops pdc20246_dma_ops = { - .dma_host_set = ide_dma_host_set, - .dma_setup = ide_dma_setup, - .dma_start = ide_dma_start, - .dma_end = ide_dma_end, - .dma_test_irq = pdc202xx_dma_test_irq, - .dma_lost_irq = ide_dma_lost_irq, - .dma_timer_expiry = ide_dma_sff_timer_expiry, - .dma_sff_read_status = ide_dma_sff_read_status, -}; - static const struct ide_dma_ops pdc2026x_dma_ops = { .dma_host_set = ide_dma_host_set, .dma_setup = ide_dma_setup, .dma_start = pdc202xx_dma_start, .dma_end = pdc202xx_dma_end, - .dma_test_irq = pdc202xx_dma_test_irq, - .dma_lost_irq = pdc202xx_dma_lost_irq, + .dma_test_irq = ide_dma_test_irq, + .dma_lost_irq = ide_dma_lost_irq, .dma_timer_expiry = ide_dma_sff_timer_expiry, - .dma_clear = pdc202xx_reset, .dma_sff_read_status = ide_dma_sff_read_status, }; @@ -354,7 +290,7 @@ static const struct ide_port_info pdc202xx_chipsets[] __devinitdata = { .name = DRV_NAME, .init_chipset = init_chipset_pdc202xx, .port_ops = &pdc20246_port_ops, - .dma_ops = &pdc20246_dma_ops, + .dma_ops = &sff_dma_ops, .host_flags = IDE_HFLAGS_PDC202XX, .pio_mask = ATA_PIO4, .mwdma_mask = ATA_MWDMA2, diff --git a/drivers/ide/piix.c b/drivers/ide/piix.c index 69860dea3820..bf14f39bd3a7 100644 --- a/drivers/ide/piix.c +++ b/drivers/ide/piix.c @@ -98,7 +98,7 @@ static void piix_set_pio_mode(ide_drive_t *drive, const u8 pio) control |= 1; /* Programmable timing on */ if (drive->media == ide_disk) control |= 4; /* Prefetch, post write */ - if (pio > 2) + if (ide_pio_need_iordy(drive, pio)) control |= 2; /* IORDY */ if (is_slave) { master_data |= 0x4000; diff --git a/drivers/ide/pmac.c b/drivers/ide/pmac.c index f76e4e6b408f..97642a7a79c4 100644 --- a/drivers/ide/pmac.c +++ b/drivers/ide/pmac.c @@ -1023,13 +1023,14 @@ static const struct ide_port_info pmac_port_info = { * Setup, register & probe an IDE channel driven by this driver, this is * called by one of the 2 probe functions (macio or PCI). */ -static int __devinit pmac_ide_setup_device(pmac_ide_hwif_t *pmif, hw_regs_t *hw) +static int __devinit pmac_ide_setup_device(pmac_ide_hwif_t *pmif, + struct ide_hw *hw) { struct device_node *np = pmif->node; const int *bidp; struct ide_host *host; ide_hwif_t *hwif; - hw_regs_t *hws[] = { hw, NULL, NULL, NULL }; + struct ide_hw *hws[] = { hw }; struct ide_port_info d = pmac_port_info; int rc; @@ -1077,7 +1078,7 @@ static int __devinit pmac_ide_setup_device(pmac_ide_hwif_t *pmif, hw_regs_t *hw) /* Make sure we have sane timings */ sanitize_timings(pmif); - host = ide_host_alloc(&d, hws); + host = ide_host_alloc(&d, hws, 1); if (host == NULL) return -ENOMEM; hwif = host->ports[0]; @@ -1124,7 +1125,7 @@ static int __devinit pmac_ide_setup_device(pmac_ide_hwif_t *pmif, hw_regs_t *hw) return 0; } -static void __devinit pmac_ide_init_ports(hw_regs_t *hw, unsigned long base) +static void __devinit pmac_ide_init_ports(struct ide_hw *hw, unsigned long base) { int i; @@ -1144,7 +1145,7 @@ pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match) unsigned long regbase; pmac_ide_hwif_t *pmif; int irq, rc; - hw_regs_t hw; + struct ide_hw hw; pmif = kzalloc(sizeof(*pmif), GFP_KERNEL); if (pmif == NULL) @@ -1268,7 +1269,7 @@ pmac_ide_pci_attach(struct pci_dev *pdev, const struct pci_device_id *id) void __iomem *base; unsigned long rbase, rlen; int rc; - hw_regs_t hw; + struct ide_hw hw; np = pci_device_to_OF_node(pdev); if (np == NULL) { diff --git a/drivers/ide/q40ide.c b/drivers/ide/q40ide.c index c79346679244..90786083b439 100644 --- a/drivers/ide/q40ide.c +++ b/drivers/ide/q40ide.c @@ -51,11 +51,9 @@ static int q40ide_default_irq(unsigned long base) /* * Addresses are pretranslated for Q40 ISA access. */ -static void q40_ide_setup_ports(hw_regs_t *hw, unsigned long base, - ide_ack_intr_t *ack_intr, - int irq) +static void q40_ide_setup_ports(struct ide_hw *hw, unsigned long base, int irq) { - memset(hw, 0, sizeof(hw_regs_t)); + memset(hw, 0, sizeof(*hw)); /* BIG FAT WARNING: assumption: only DATA port is ever used in 16 bit mode */ hw->io_ports.data_addr = Q40_ISA_IO_W(base); @@ -69,9 +67,6 @@ static void q40_ide_setup_ports(hw_regs_t *hw, unsigned long base, hw->io_ports.ctl_addr = Q40_ISA_IO_B(base + 0x206); hw->irq = irq; - hw->ack_intr = ack_intr; - - hw->chipset = ide_generic; } static void q40ide_input_data(ide_drive_t *drive, struct ide_cmd *cmd, @@ -119,6 +114,7 @@ static const struct ide_port_info q40ide_port_info = { .tp_ops = &q40ide_tp_ops, .host_flags = IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA, .irq_flags = IRQF_SHARED, + .chipset = ide_generic, }; /* @@ -136,7 +132,7 @@ static const char *q40_ide_names[Q40IDE_NUM_HWIFS]={ static int __init q40ide_init(void) { int i; - hw_regs_t hw[Q40IDE_NUM_HWIFS], *hws[] = { NULL, NULL, NULL, NULL }; + struct ide_hw hw[Q40IDE_NUM_HWIFS], *hws[] = { NULL, NULL }; if (!MACH_IS_Q40) return -ENODEV; @@ -157,13 +153,13 @@ static int __init q40ide_init(void) release_region(pcide_bases[i], 8); continue; } - q40_ide_setup_ports(&hw[i], pcide_bases[i], NULL, + q40_ide_setup_ports(&hw[i], pcide_bases[i], q40ide_default_irq(pcide_bases[i])); hws[i] = &hw[i]; } - return ide_host_add(&q40ide_port_info, hws, NULL); + return ide_host_add(&q40ide_port_info, hws, Q40IDE_NUM_HWIFS, NULL); } module_init(q40ide_init); diff --git a/drivers/ide/qd65xx.c b/drivers/ide/qd65xx.c index c9a134986891..74696edc8d1d 100644 --- a/drivers/ide/qd65xx.c +++ b/drivers/ide/qd65xx.c @@ -180,8 +180,11 @@ static int qd_find_disk_type (ide_drive_t *drive, static void qd_set_timing (ide_drive_t *drive, u8 timing) { - drive->drive_data &= 0xff00; - drive->drive_data |= timing; + unsigned long data = (unsigned long)ide_get_drivedata(drive); + + data &= 0xff00; + data |= timing; + ide_set_drivedata(drive, (void *)data); printk(KERN_DEBUG "%s: %#x\n", drive->name, timing); } @@ -292,7 +295,7 @@ static void __init qd6500_init_dev(ide_drive_t *drive) u8 base = (hwif->config_data & 0xff00) >> 8; u8 config = QD_CONFIG(hwif); - drive->drive_data = QD6500_DEF_DATA; + ide_set_drivedata(drive, (void *)QD6500_DEF_DATA); } static void __init qd6580_init_dev(ide_drive_t *drive) @@ -308,7 +311,7 @@ static void __init qd6580_init_dev(ide_drive_t *drive) } else t2 = t1 = hwif->channel ? QD6580_DEF_DATA2 : QD6580_DEF_DATA; - drive->drive_data = (drive->dn & 1) ? t2 : t1; + ide_set_drivedata(drive, (void *)((drive->dn & 1) ? t2 : t1)); } static const struct ide_tp_ops qd65xx_tp_ops = { diff --git a/drivers/ide/qd65xx.h b/drivers/ide/qd65xx.h index d7e67a1a1dcc..1fba2a5f281c 100644 --- a/drivers/ide/qd65xx.h +++ b/drivers/ide/qd65xx.h @@ -31,8 +31,15 @@ #define QD_CONFIG(hwif) ((hwif)->config_data & 0x00ff) -#define QD_TIMING(drive) (u8)(((drive)->drive_data) & 0x00ff) -#define QD_TIMREG(drive) (u8)((((drive)->drive_data) & 0xff00) >> 8) +static inline u8 QD_TIMING(ide_drive_t *drive) +{ + return (unsigned long)ide_get_drivedata(drive) & 0x00ff; +} + +static inline u8 QD_TIMREG(ide_drive_t *drive) +{ + return ((unsigned long)ide_get_drivedata(drive) & 0xff00) >> 8; +} #define QD6500_DEF_DATA ((QD_TIM1_PORT<<8) | (QD_ID3 ? 0x0c : 0x08)) #define QD6580_DEF_DATA ((QD_TIM1_PORT<<8) | (QD_ID3 ? 0x0a : 0x00)) diff --git a/drivers/ide/rapide.c b/drivers/ide/rapide.c index d5003ca69801..00f54248f41f 100644 --- a/drivers/ide/rapide.c +++ b/drivers/ide/rapide.c @@ -13,9 +13,10 @@ static const struct ide_port_info rapide_port_info = { .host_flags = IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA, + .chipset = ide_generic, }; -static void rapide_setup_ports(hw_regs_t *hw, void __iomem *base, +static void rapide_setup_ports(struct ide_hw *hw, void __iomem *base, void __iomem *ctrl, unsigned int sz, int irq) { unsigned long port = (unsigned long)base; @@ -35,7 +36,7 @@ rapide_probe(struct expansion_card *ec, const struct ecard_id *id) void __iomem *base; struct ide_host *host; int ret; - hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL }; + struct ide_hw hw, *hws[] = { &hw }; ret = ecard_request_resources(ec); if (ret) @@ -49,10 +50,9 @@ rapide_probe(struct expansion_card *ec, const struct ecard_id *id) memset(&hw, 0, sizeof(hw)); rapide_setup_ports(&hw, base, base + 0x818, 1 << 6, ec->irq); - hw.chipset = ide_generic; hw.dev = &ec->dev; - ret = ide_host_add(&rapide_port_info, hws, &host); + ret = ide_host_add(&rapide_port_info, hws, 1, &host); if (ret) goto release; diff --git a/drivers/ide/scc_pata.c b/drivers/ide/scc_pata.c index 5be41f25204f..1104bb301eb9 100644 --- a/drivers/ide/scc_pata.c +++ b/drivers/ide/scc_pata.c @@ -559,7 +559,7 @@ static int scc_ide_setup_pci_device(struct pci_dev *dev, { struct scc_ports *ports = pci_get_drvdata(dev); struct ide_host *host; - hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL }; + struct ide_hw hw, *hws[] = { &hw }; int i, rc; memset(&hw, 0, sizeof(hw)); @@ -567,9 +567,8 @@ static int scc_ide_setup_pci_device(struct pci_dev *dev, hw.io_ports_array[i] = ports->dma + 0x20 + i * 4; hw.irq = dev->irq; hw.dev = &dev->dev; - hw.chipset = ide_pci; - rc = ide_host_add(d, hws, &host); + rc = ide_host_add(d, hws, 1, &host); if (rc) return rc; @@ -823,6 +822,7 @@ static const struct ide_port_info scc_chipset __devinitdata = { .host_flags = IDE_HFLAG_SINGLE, .irq_flags = IRQF_SHARED, .pio_mask = ATA_PIO4, + .chipset = ide_pci, }; /** diff --git a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c index 7a3a12d6e638..ab3db61d2ba0 100644 --- a/drivers/ide/setup-pci.c +++ b/drivers/ide/setup-pci.c @@ -1,7 +1,7 @@ /* * Copyright (C) 1998-2000 Andre Hedrick * Copyright (C) 1995-1998 Mark Lord - * Copyright (C) 2007 Bartlomiej Zolnierkiewicz + * Copyright (C) 2007-2009 Bartlomiej Zolnierkiewicz * * May be copied or modified under the terms of the GNU General Public License */ @@ -301,11 +301,11 @@ static int ide_pci_check_iomem(struct pci_dev *dev, const struct ide_port_info * } /** - * ide_hw_configure - configure a hw_regs_t instance + * ide_hw_configure - configure a struct ide_hw instance * @dev: PCI device holding interface * @d: IDE port info * @port: port number - * @hw: hw_regs_t instance corresponding to this port + * @hw: struct ide_hw instance corresponding to this port * * Perform the initial set up for the hardware interface structure. This * is done per interface port rather than per PCI device. There may be @@ -315,7 +315,7 @@ static int ide_pci_check_iomem(struct pci_dev *dev, const struct ide_port_info * */ static int ide_hw_configure(struct pci_dev *dev, const struct ide_port_info *d, - unsigned int port, hw_regs_t *hw) + unsigned int port, struct ide_hw *hw) { unsigned long ctl = 0, base = 0; @@ -344,7 +344,6 @@ static int ide_hw_configure(struct pci_dev *dev, const struct ide_port_info *d, memset(hw, 0, sizeof(*hw)); hw->dev = &dev->dev; - hw->chipset = d->chipset ? d->chipset : ide_pci; ide_std_init_ports(hw, base, ctl | 2); return 0; @@ -446,8 +445,8 @@ out: * ide_pci_setup_ports - configure ports/devices on PCI IDE * @dev: PCI device * @d: IDE port info - * @hw: hw_regs_t instances corresponding to this PCI IDE device - * @hws: hw_regs_t pointers table to update + * @hw: struct ide_hw instances corresponding to this PCI IDE device + * @hws: struct ide_hw pointers table to update * * Scan the interfaces attached to this device and do any * necessary per port setup. Attach the devices and ask the @@ -459,7 +458,7 @@ out: */ void ide_pci_setup_ports(struct pci_dev *dev, const struct ide_port_info *d, - hw_regs_t *hw, hw_regs_t **hws) + struct ide_hw *hw, struct ide_hw **hws) { int channels = (d->host_flags & IDE_HFLAG_SINGLE) ? 1 : 2, port; u8 tmp; @@ -535,61 +534,15 @@ out: return ret; } -int ide_pci_init_one(struct pci_dev *dev, const struct ide_port_info *d, - void *priv) -{ - struct ide_host *host; - hw_regs_t hw[4], *hws[] = { NULL, NULL, NULL, NULL }; - int ret; - - ret = ide_setup_pci_controller(dev, d, 1); - if (ret < 0) - goto out; - - ide_pci_setup_ports(dev, d, &hw[0], &hws[0]); - - host = ide_host_alloc(d, hws); - if (host == NULL) { - ret = -ENOMEM; - goto out; - } - - host->dev[0] = &dev->dev; - - host->host_priv = priv; - - host->irq_flags = IRQF_SHARED; - - pci_set_drvdata(dev, host); - - ret = do_ide_setup_pci_device(dev, d, 1); - if (ret < 0) - goto out; - - /* fixup IRQ */ - if (ide_pci_is_in_compatibility_mode(dev)) { - hw[0].irq = pci_get_legacy_ide_irq(dev, 0); - hw[1].irq = pci_get_legacy_ide_irq(dev, 1); - } else - hw[1].irq = hw[0].irq = ret; - - ret = ide_host_register(host, d, hws); - if (ret) - ide_host_free(host); -out: - return ret; -} -EXPORT_SYMBOL_GPL(ide_pci_init_one); - int ide_pci_init_two(struct pci_dev *dev1, struct pci_dev *dev2, const struct ide_port_info *d, void *priv) { struct pci_dev *pdev[] = { dev1, dev2 }; struct ide_host *host; - int ret, i; - hw_regs_t hw[4], *hws[] = { NULL, NULL, NULL, NULL }; + int ret, i, n_ports = dev2 ? 4 : 2; + struct ide_hw hw[4], *hws[] = { NULL, NULL, NULL, NULL }; - for (i = 0; i < 2; i++) { + for (i = 0; i < n_ports / 2; i++) { ret = ide_setup_pci_controller(pdev[i], d, !i); if (ret < 0) goto out; @@ -597,23 +550,24 @@ int ide_pci_init_two(struct pci_dev *dev1, struct pci_dev *dev2, ide_pci_setup_ports(pdev[i], d, &hw[i*2], &hws[i*2]); } - host = ide_host_alloc(d, hws); + host = ide_host_alloc(d, hws, n_ports); if (host == NULL) { ret = -ENOMEM; goto out; } host->dev[0] = &dev1->dev; - host->dev[1] = &dev2->dev; + if (dev2) + host->dev[1] = &dev2->dev; host->host_priv = priv; - host->irq_flags = IRQF_SHARED; pci_set_drvdata(pdev[0], host); - pci_set_drvdata(pdev[1], host); + if (dev2) + pci_set_drvdata(pdev[1], host); - for (i = 0; i < 2; i++) { + for (i = 0; i < n_ports / 2; i++) { ret = do_ide_setup_pci_device(pdev[i], d, !i); /* @@ -639,6 +593,13 @@ out: } EXPORT_SYMBOL_GPL(ide_pci_init_two); +int ide_pci_init_one(struct pci_dev *dev, const struct ide_port_info *d, + void *priv) +{ + return ide_pci_init_two(dev, NULL, d, priv); +} +EXPORT_SYMBOL_GPL(ide_pci_init_one); + void ide_pci_remove(struct pci_dev *dev) { struct ide_host *host = pci_get_drvdata(dev); diff --git a/drivers/ide/sgiioc4.c b/drivers/ide/sgiioc4.c index e5d2a48a84de..b7d61dc64096 100644 --- a/drivers/ide/sgiioc4.c +++ b/drivers/ide/sgiioc4.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2003-2006 Silicon Graphics, Inc. All Rights Reserved. - * Copyright (C) 2008 MontaVista Software, Inc. + * Copyright (C) 2008-2009 MontaVista Software, Inc. * * 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 @@ -29,8 +29,7 @@ #include #include #include -#include - +#include #include #define DRV_NAME "SGIIOC4" @@ -72,7 +71,7 @@ #define IOC4_CMD_CTL_BLK_SIZE 0x20 #define IOC4_SUPPORTED_FIRMWARE_REV 46 -typedef struct { +struct ioc4_dma_regs { u32 timing_reg0; u32 timing_reg1; u32 low_mem_ptr; @@ -82,17 +81,18 @@ typedef struct { u32 dev_byte_count; u32 mem_byte_count; u32 status; -} ioc4_dma_regs_t; +}; /* Each Physical Region Descriptor Entry size is 16 bytes (2 * 64 bits) */ /* IOC4 has only 1 IDE channel */ -#define IOC4_PRD_BYTES 16 -#define IOC4_PRD_ENTRIES (PAGE_SIZE /(4*IOC4_PRD_BYTES)) +#define IOC4_PRD_BYTES 16 +#define IOC4_PRD_ENTRIES (PAGE_SIZE / (4 * IOC4_PRD_BYTES)) -static void -sgiioc4_init_hwif_ports(hw_regs_t * hw, unsigned long data_port, - unsigned long ctrl_port, unsigned long irq_port) +static void sgiioc4_init_hwif_ports(struct ide_hw *hw, + unsigned long data_port, + unsigned long ctrl_port, + unsigned long irq_port) { unsigned long reg = data_port; int i; @@ -105,13 +105,11 @@ sgiioc4_init_hwif_ports(hw_regs_t * hw, unsigned long data_port, hw->io_ports.irq_addr = irq_port; } -static int -sgiioc4_checkirq(ide_hwif_t * hwif) +static int sgiioc4_checkirq(ide_hwif_t *hwif) { - unsigned long intr_addr = - hwif->io_ports.irq_addr + IOC4_INTR_REG * 4; + unsigned long intr_addr = hwif->io_ports.irq_addr + IOC4_INTR_REG * 4; - if ((u8)readl((void __iomem *)intr_addr) & 0x03) + if (readl((void __iomem *)intr_addr) & 0x03) return 1; return 0; @@ -119,8 +117,7 @@ sgiioc4_checkirq(ide_hwif_t * hwif) static u8 sgiioc4_read_status(ide_hwif_t *); -static int -sgiioc4_clearirq(ide_drive_t * drive) +static int sgiioc4_clearirq(ide_drive_t *drive) { u32 intr_reg; ide_hwif_t *hwif = drive->hwif; @@ -158,12 +155,10 @@ sgiioc4_clearirq(ide_drive_t * drive) readl((void __iomem *)(io_ports->irq_addr + 4)); pci_read_config_dword(dev, PCI_COMMAND, &pci_stat_cmd_reg); - printk(KERN_ERR - "%s(%s) : PCI Bus Error when doing DMA:" - " status-cmd reg is 0x%x\n", + printk(KERN_ERR "%s(%s): PCI Bus Error when doing DMA: " + "status-cmd reg is 0x%x\n", __func__, drive->name, pci_stat_cmd_reg); - printk(KERN_ERR - "%s(%s) : PCI Error Address is 0x%x%x\n", + printk(KERN_ERR "%s(%s): PCI Error Address is 0x%x%x\n", __func__, drive->name, pci_err_addr_high, pci_err_addr_low); /* Clear the PCI Error indicator */ @@ -189,8 +184,7 @@ static void sgiioc4_dma_start(ide_drive_t *drive) writel(temp_reg, (void __iomem *)ioc4_dma_addr); } -static u32 -sgiioc4_ide_dma_stop(ide_hwif_t *hwif, u64 dma_base) +static u32 sgiioc4_ide_dma_stop(ide_hwif_t *hwif, u64 dma_base) { unsigned long ioc4_dma_addr = dma_base + IOC4_DMA_CTRL * 4; u32 ioc4_dma; @@ -227,7 +221,7 @@ static int sgiioc4_dma_end(ide_drive_t *drive) } /* - * The IOC4 will DMA 1's to the ending dma area to indicate that + * The IOC4 will DMA 1's to the ending DMA area to indicate that * previous data DMA is complete. This is necessary because of relaxed * ordering between register reads and DMA writes on the Altix. */ @@ -265,7 +259,7 @@ static void sgiioc4_set_dma_mode(ide_drive_t *drive, const u8 speed) { } -/* returns 1 if dma irq issued, 0 otherwise */ +/* Returns 1 if DMA IRQ issued, 0 otherwise */ static int sgiioc4_dma_test_irq(ide_drive_t *drive) { return sgiioc4_checkirq(drive->hwif); @@ -286,8 +280,7 @@ static void sgiioc4_resetproc(ide_drive_t *drive) sgiioc4_clearirq(drive); } -static void -sgiioc4_dma_lost_irq(ide_drive_t * drive) +static void sgiioc4_dma_lost_irq(ide_drive_t *drive) { sgiioc4_resetproc(drive); @@ -313,13 +306,13 @@ static u8 sgiioc4_read_status(ide_hwif_t *hwif) return reg; } -/* Creates a dma map for the scatter-gather list entries */ -static int __devinit -ide_dma_sgiioc4(ide_hwif_t *hwif, const struct ide_port_info *d) +/* Creates a DMA map for the scatter-gather list entries */ +static int __devinit ide_dma_sgiioc4(ide_hwif_t *hwif, + const struct ide_port_info *d) { struct pci_dev *dev = to_pci_dev(hwif->dev); unsigned long dma_base = pci_resource_start(dev, 0) + IOC4_DMA_OFFSET; - int num_ports = sizeof (ioc4_dma_regs_t); + int num_ports = sizeof(struct ioc4_dma_regs); void *pad; printk(KERN_INFO " %s: MMIO-DMA\n", hwif->name); @@ -362,8 +355,7 @@ dma_pci_alloc_failure: } /* Initializes the IOC4 DMA Engine */ -static void -sgiioc4_configure_for_dma(int dma_direction, ide_drive_t * drive) +static void sgiioc4_configure_for_dma(int dma_direction, ide_drive_t *drive) { u32 ioc4_dma; ide_hwif_t *hwif = drive->hwif; @@ -374,31 +366,27 @@ sgiioc4_configure_for_dma(int dma_direction, ide_drive_t * drive) ioc4_dma = readl((void __iomem *)ioc4_dma_addr); if (ioc4_dma & IOC4_S_DMA_ACTIVE) { - printk(KERN_WARNING - "%s(%s):Warning!! DMA from previous transfer was still active\n", - __func__, drive->name); + printk(KERN_WARNING "%s(%s): Warning!! DMA from previous " + "transfer was still active\n", __func__, drive->name); writel(IOC4_S_DMA_STOP, (void __iomem *)ioc4_dma_addr); ioc4_dma = sgiioc4_ide_dma_stop(hwif, dma_base); if (ioc4_dma & IOC4_S_DMA_STOP) - printk(KERN_ERR - "%s(%s) : IOC4 Dma STOP bit is still 1\n", - __func__, drive->name); + printk(KERN_ERR "%s(%s): IOC4 DMA STOP bit is " + "still 1\n", __func__, drive->name); } ioc4_dma = readl((void __iomem *)ioc4_dma_addr); if (ioc4_dma & IOC4_S_DMA_ERROR) { - printk(KERN_WARNING - "%s(%s) : Warning!! - DMA Error during Previous" - " transfer | status 0x%x\n", + printk(KERN_WARNING "%s(%s): Warning!! DMA Error during " + "previous transfer, status 0x%x\n", __func__, drive->name, ioc4_dma); writel(IOC4_S_DMA_STOP, (void __iomem *)ioc4_dma_addr); ioc4_dma = sgiioc4_ide_dma_stop(hwif, dma_base); if (ioc4_dma & IOC4_S_DMA_STOP) - printk(KERN_ERR - "%s(%s) : IOC4 DMA STOP bit is still 1\n", - __func__, drive->name); + printk(KERN_ERR "%s(%s): IOC4 DMA STOP bit is " + "still 1\n", __func__, drive->name); } /* Address of the Scatter Gather List */ @@ -408,20 +396,22 @@ sgiioc4_configure_for_dma(int dma_direction, ide_drive_t * drive) /* Address of the Ending DMA */ memset(ide_get_hwifdata(hwif), 0, IOC4_IDE_CACHELINE_SIZE); ending_dma_addr = cpu_to_le32(hwif->extra_base); - writel(ending_dma_addr, (void __iomem *)(dma_base + IOC4_DMA_END_ADDR * 4)); + writel(ending_dma_addr, (void __iomem *)(dma_base + + IOC4_DMA_END_ADDR * 4)); writel(dma_direction, (void __iomem *)ioc4_dma_addr); } -/* IOC4 Scatter Gather list Format */ +/* IOC4 Scatter Gather list Format */ /* 128 Bit entries to support 64 bit addresses in the future */ /* The Scatter Gather list Entry should be in the BIG-ENDIAN Format */ /* --------------------------------------------------------------------- */ -/* | Upper 32 bits - Zero | Lower 32 bits- address | */ +/* | Upper 32 bits - Zero | Lower 32 bits- address | */ /* --------------------------------------------------------------------- */ /* | Upper 32 bits - Zero |EOL| 15 unused | 16 Bit Length| */ /* --------------------------------------------------------------------- */ -/* Creates the scatter gather list, DMA Table */ +/* Creates the scatter gather list, DMA Table */ + static int sgiioc4_build_dmatable(ide_drive_t *drive, struct ide_cmd *cmd) { ide_hwif_t *hwif = drive->hwif; @@ -448,8 +438,10 @@ static int sgiioc4_build_dmatable(ide_drive_t *drive, struct ide_cmd *cmd) if (bcount > cur_len) bcount = cur_len; - /* put the addr, length in - * the IOC4 dma-table format */ + /* + * Put the address, length in + * the IOC4 dma-table format + */ *table = 0x0; table++; *table = cpu_to_be32(cur_addr); @@ -540,16 +532,15 @@ static const struct ide_port_info sgiioc4_port_info __devinitconst = { .mwdma_mask = ATA_MWDMA2_ONLY, }; -static int __devinit -sgiioc4_ide_setup_pci_device(struct pci_dev *dev) +static int __devinit sgiioc4_ide_setup_pci_device(struct pci_dev *dev) { unsigned long cmd_base, irqport; unsigned long bar0, cmd_phys_base, ctl; void __iomem *virt_base; - hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL }; + struct ide_hw hw, *hws[] = { &hw }; int rc; - /* Get the CmdBlk and CtrlBlk Base Registers */ + /* Get the CmdBlk and CtrlBlk base registers */ bar0 = pci_resource_start(dev, 0); virt_base = pci_ioremap_bar(dev, 0); if (virt_base == NULL) { @@ -557,9 +548,9 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev) DRV_NAME, bar0); return -ENOMEM; } - cmd_base = (unsigned long) virt_base + IOC4_CMD_OFFSET; - ctl = (unsigned long) virt_base + IOC4_CTRL_OFFSET; - irqport = (unsigned long) virt_base + IOC4_INTR_OFFSET; + cmd_base = (unsigned long)virt_base + IOC4_CMD_OFFSET; + ctl = (unsigned long)virt_base + IOC4_CTRL_OFFSET; + irqport = (unsigned long)virt_base + IOC4_INTR_OFFSET; cmd_phys_base = bar0 + IOC4_CMD_OFFSET; if (request_mem_region(cmd_phys_base, IOC4_CMD_CTL_BLK_SIZE, @@ -575,13 +566,12 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev) memset(&hw, 0, sizeof(hw)); sgiioc4_init_hwif_ports(&hw, cmd_base, ctl, irqport); hw.irq = dev->irq; - hw.chipset = ide_pci; hw.dev = &dev->dev; - /* Initializing chipset IRQ Registers */ + /* Initialize chipset IRQ registers */ writel(0x03, (void __iomem *)(irqport + IOC4_INTR_SET * 4)); - rc = ide_host_add(&sgiioc4_port_info, hws, NULL); + rc = ide_host_add(&sgiioc4_port_info, hws, 1, NULL); if (!rc) return 0; @@ -591,8 +581,7 @@ req_mem_rgn_err: return rc; } -static unsigned int __devinit -pci_init_sgiioc4(struct pci_dev *dev) +static unsigned int __devinit pci_init_sgiioc4(struct pci_dev *dev) { int ret; @@ -612,10 +601,10 @@ out: return ret; } -int __devinit -ioc4_ide_attach_one(struct ioc4_driver_data *idd) +int __devinit ioc4_ide_attach_one(struct ioc4_driver_data *idd) { - /* PCI-RT does not bring out IDE connection. + /* + * PCI-RT does not bring out IDE connection. * Do not attach to this particular IOC4. */ if (idd->idd_variant == IOC4_VARIANT_PCI_RT) @@ -628,7 +617,6 @@ static struct ioc4_submodule __devinitdata ioc4_ide_submodule = { .is_name = "IOC4_ide", .is_owner = THIS_MODULE, .is_probe = ioc4_ide_attach_one, -/* .is_remove = ioc4_ide_remove_one, */ }; static int __init ioc4_ide_init(void) diff --git a/drivers/ide/siimage.c b/drivers/ide/siimage.c index e4973cd1fba9..d95df528562f 100644 --- a/drivers/ide/siimage.c +++ b/drivers/ide/siimage.c @@ -32,7 +32,6 @@ * smarter code in libata. * * TODO: - * - IORDY fixes * - VDMA support */ @@ -234,8 +233,7 @@ static u8 sil_sata_udma_filter(ide_drive_t *drive) * @pio: PIO mode number * * Load the timing settings for this device mode into the - * controller. If we are in PIO mode 3 or 4 turn on IORDY - * monitoring (bit 9). The TF timing is bits 31:16 + * controller. */ static void sil_set_pio_mode(ide_drive_t *drive, u8 pio) @@ -276,13 +274,16 @@ static void sil_set_pio_mode(ide_drive_t *drive, u8 pio) /* now set up IORDY */ speedp = sil_ioread16(dev, tfaddr - 2); speedp &= ~0x200; - if (pio > 2) - speedp |= 0x200; - sil_iowrite16(dev, speedp, tfaddr - 2); mode = sil_ioread8(dev, base + addr_mask); mode &= ~(unit ? 0x30 : 0x03); - mode |= unit ? 0x10 : 0x01; + + if (ide_pio_need_iordy(drive, pio)) { + speedp |= 0x200; + mode |= unit ? 0x10 : 0x01; + } + + sil_iowrite16(dev, speedp, tfaddr - 2); sil_iowrite8(dev, mode, base + addr_mask); } @@ -337,24 +338,14 @@ static void sil_set_dma_mode(ide_drive_t *drive, const u8 speed) sil_iowrite16(dev, ultra, ua); } -/* returns 1 if dma irq issued, 0 otherwise */ -static int siimage_io_dma_test_irq(ide_drive_t *drive) +static int sil_test_irq(ide_hwif_t *hwif) { - ide_hwif_t *hwif = drive->hwif; struct pci_dev *dev = to_pci_dev(hwif->dev); - u8 dma_altstat = 0; unsigned long addr = siimage_selreg(hwif, 1); + u8 val = sil_ioread8(dev, addr); - /* return 1 if INTR asserted */ - if (inb(hwif->dma_base + ATA_DMA_STATUS) & 4) - return 1; - - /* return 1 if Device INTR asserted */ - pci_read_config_byte(dev, addr, &dma_altstat); - if (dma_altstat & 8) - return 0; /* return 1; */ - - return 0; + /* Return 1 if INTRQ asserted */ + return (val & 8) ? 1 : 0; } /** @@ -368,7 +359,6 @@ static int siimage_io_dma_test_irq(ide_drive_t *drive) static int siimage_mmio_dma_test_irq(ide_drive_t *drive) { ide_hwif_t *hwif = drive->hwif; - unsigned long addr = siimage_selreg(hwif, 0x1); void __iomem *sata_error_addr = (void __iomem *)hwif->sata_scr[SATA_ERROR_OFFSET]; @@ -397,10 +387,6 @@ static int siimage_mmio_dma_test_irq(ide_drive_t *drive) if (readb((void __iomem *)(hwif->dma_base + ATA_DMA_STATUS)) & 4) return 1; - /* return 1 if Device INTR asserted */ - if (readb((void __iomem *)addr) & 8) - return 0; /* return 1; */ - return 0; } @@ -409,7 +395,7 @@ static int siimage_dma_test_irq(ide_drive_t *drive) if (drive->hwif->host_flags & IDE_HFLAG_MMIO) return siimage_mmio_dma_test_irq(drive); else - return siimage_io_dma_test_irq(drive); + return ide_dma_test_irq(drive); } /** @@ -451,8 +437,8 @@ static int sil_sata_reset_poll(ide_drive_t *drive) static void sil_sata_pre_reset(ide_drive_t *drive) { if (drive->media == ide_disk) { - drive->special.b.set_geometry = 0; - drive->special.b.recalibrate = 0; + drive->special_flags &= + ~(IDE_SFLAG_SET_GEOMETRY | IDE_SFLAG_RECALIBRATE); } } @@ -694,6 +680,7 @@ static const struct ide_port_ops sil_pata_port_ops = { .set_pio_mode = sil_set_pio_mode, .set_dma_mode = sil_set_dma_mode, .quirkproc = sil_quirkproc, + .test_irq = sil_test_irq, .udma_filter = sil_pata_udma_filter, .cable_detect = sil_cable_detect, }; @@ -704,6 +691,7 @@ static const struct ide_port_ops sil_sata_port_ops = { .reset_poll = sil_sata_reset_poll, .pre_reset = sil_sata_pre_reset, .quirkproc = sil_quirkproc, + .test_irq = sil_test_irq, .udma_filter = sil_sata_udma_filter, .cable_detect = sil_cable_detect, }; diff --git a/drivers/ide/sl82c105.c b/drivers/ide/sl82c105.c index b0a460625335..d698da470d6f 100644 --- a/drivers/ide/sl82c105.c +++ b/drivers/ide/sl82c105.c @@ -10,7 +10,7 @@ * with the timing registers setup. * -- Benjamin Herrenschmidt (01/11/03) benh@kernel.crashing.org * - * Copyright (C) 2006-2007 MontaVista Software, Inc. + * Copyright (C) 2006-2007,2009 MontaVista Software, Inc. * Copyright (C) 2007 Bartlomiej Zolnierkiewicz */ @@ -61,8 +61,7 @@ static unsigned int get_pio_timings(ide_drive_t *drive, u8 pio) if (cmd_off == 0) cmd_off = 1; - if ((pio > 2 || ata_id_has_iordy(drive->id)) && - !(pio > 4 && ata_id_is_cfa(drive->id))) + if (ide_pio_need_iordy(drive, pio)) iordy = 0x40; return (cmd_on - 1) << 8 | (cmd_off - 1) | iordy; @@ -74,6 +73,7 @@ static unsigned int get_pio_timings(ide_drive_t *drive, u8 pio) static void sl82c105_set_pio_mode(ide_drive_t *drive, const u8 pio) { struct pci_dev *dev = to_pci_dev(drive->hwif->dev); + unsigned long timings = (unsigned long)ide_get_drivedata(drive); int reg = 0x44 + drive->dn * 4; u16 drv_ctrl; @@ -83,8 +83,9 @@ static void sl82c105_set_pio_mode(ide_drive_t *drive, const u8 pio) * Store the PIO timings so that we can restore them * in case DMA will be turned off... */ - drive->drive_data &= 0xffff0000; - drive->drive_data |= drv_ctrl; + timings &= 0xffff0000; + timings |= drv_ctrl; + ide_set_drivedata(drive, (void *)timings); pci_write_config_word(dev, reg, drv_ctrl); pci_read_config_word (dev, reg, &drv_ctrl); @@ -100,6 +101,7 @@ static void sl82c105_set_pio_mode(ide_drive_t *drive, const u8 pio) static void sl82c105_set_dma_mode(ide_drive_t *drive, const u8 speed) { static u16 mwdma_timings[] = {0x0707, 0x0201, 0x0200}; + unsigned long timings = (unsigned long)ide_get_drivedata(drive); u16 drv_ctrl; DBG(("sl82c105_tune_chipset(drive:%s, speed:%s)\n", @@ -111,8 +113,19 @@ static void sl82c105_set_dma_mode(ide_drive_t *drive, const u8 speed) * Store the DMA timings so that we can actually program * them when DMA will be turned on... */ - drive->drive_data &= 0x0000ffff; - drive->drive_data |= (unsigned long)drv_ctrl << 16; + timings &= 0x0000ffff; + timings |= (unsigned long)drv_ctrl << 16; + ide_set_drivedata(drive, (void *)timings); +} + +static int sl82c105_test_irq(ide_hwif_t *hwif) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + u32 val, mask = hwif->channel ? CTRL_IDE_IRQB : CTRL_IDE_IRQA; + + pci_read_config_dword(dev, 0x40, &val); + + return (val & mask) ? 1 : 0; } /* @@ -146,14 +159,15 @@ static void sl82c105_dma_lost_irq(ide_drive_t *drive) u32 val, mask = hwif->channel ? CTRL_IDE_IRQB : CTRL_IDE_IRQA; u8 dma_cmd; - printk("sl82c105: lost IRQ, resetting host\n"); + printk(KERN_WARNING "sl82c105: lost IRQ, resetting host\n"); /* * Check the raw interrupt from the drive. */ pci_read_config_dword(dev, 0x40, &val); if (val & mask) - printk("sl82c105: drive was requesting IRQ, but host lost it\n"); + printk(KERN_INFO "sl82c105: drive was requesting IRQ, " + "but host lost it\n"); /* * Was DMA enabled? If so, disable it - we're resetting the @@ -162,7 +176,7 @@ static void sl82c105_dma_lost_irq(ide_drive_t *drive) dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD); if (dma_cmd & 1) { outb(dma_cmd & ~1, hwif->dma_base + ATA_DMA_CMD); - printk("sl82c105: DMA was enabled\n"); + printk(KERN_INFO "sl82c105: DMA was enabled\n"); } sl82c105_reset_host(dev); @@ -184,7 +198,8 @@ static void sl82c105_dma_start(ide_drive_t *drive) DBG(("%s(drive:%s)\n", __func__, drive->name)); - pci_write_config_word(dev, reg, drive->drive_data >> 16); + pci_write_config_word(dev, reg, + (unsigned long)ide_get_drivedata(drive) >> 16); sl82c105_reset_host(dev); ide_dma_start(drive); @@ -209,7 +224,8 @@ static int sl82c105_dma_end(ide_drive_t *drive) ret = ide_dma_end(drive); - pci_write_config_word(dev, reg, drive->drive_data); + pci_write_config_word(dev, reg, + (unsigned long)ide_get_drivedata(drive)); return ret; } @@ -288,6 +304,7 @@ static const struct ide_port_ops sl82c105_port_ops = { .set_pio_mode = sl82c105_set_pio_mode, .set_dma_mode = sl82c105_set_dma_mode, .resetproc = sl82c105_resetproc, + .test_irq = sl82c105_test_irq, }; static const struct ide_dma_ops sl82c105_dma_ops = { diff --git a/drivers/ide/slc90e66.c b/drivers/ide/slc90e66.c index f55d7d6313e8..9aec78d3bcff 100644 --- a/drivers/ide/slc90e66.c +++ b/drivers/ide/slc90e66.c @@ -44,7 +44,7 @@ static void slc90e66_set_pio_mode(ide_drive_t *drive, const u8 pio) control |= 1; /* Programmable timing on */ if (drive->media == ide_disk) control |= 4; /* Prefetch, post write */ - if (pio > 2) + if (ide_pio_need_iordy(drive, pio)) control |= 2; /* IORDY */ if (is_slave) { master_data |= 0x4000; diff --git a/drivers/ide/tc86c001.c b/drivers/ide/tc86c001.c index b4cf42dc8a6f..05a93d6baecc 100644 --- a/drivers/ide/tc86c001.c +++ b/drivers/ide/tc86c001.c @@ -112,7 +112,7 @@ static void tc86c001_dma_start(ide_drive_t *drive) ide_hwif_t *hwif = drive->hwif; unsigned long sc_base = hwif->config_data; unsigned long twcr_port = sc_base + (drive->dn ? 0x06 : 0x04); - unsigned long nsectors = hwif->rq->nr_sectors; + unsigned long nsectors = blk_rq_sectors(hwif->rq); /* * We have to manually load the sector count and size into diff --git a/drivers/ide/tx4938ide.c b/drivers/ide/tx4938ide.c index e33d764e2945..ea89fddeed91 100644 --- a/drivers/ide/tx4938ide.c +++ b/drivers/ide/tx4938ide.c @@ -130,8 +130,7 @@ static const struct ide_port_info tx4938ide_port_info __initdata = { static int __init tx4938ide_probe(struct platform_device *pdev) { - hw_regs_t hw; - hw_regs_t *hws[] = { &hw, NULL, NULL, NULL }; + struct ide_hw hw, *hws[] = { &hw }; struct ide_host *host; struct resource *res; struct tx4938ide_platform_info *pdata = pdev->dev.platform_data; @@ -183,7 +182,7 @@ static int __init tx4938ide_probe(struct platform_device *pdev) tx4938ide_tune_ebusc(pdata->ebus_ch, pdata->gbus_clock, 0); else d.port_ops = NULL; - ret = ide_host_add(&d, hws, &host); + ret = ide_host_add(&d, hws, 1, &host); if (!ret) platform_set_drvdata(pdev, host); return ret; diff --git a/drivers/ide/tx4939ide.c b/drivers/ide/tx4939ide.c index 564422d23976..64b58ecc3f0e 100644 --- a/drivers/ide/tx4939ide.c +++ b/drivers/ide/tx4939ide.c @@ -307,7 +307,7 @@ static int tx4939ide_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd) tx4939ide_writew(SECTOR_SIZE / 2, base, drive->dn ? TX4939IDE_Xfer_Cnt_2 : TX4939IDE_Xfer_Cnt_1); - tx4939ide_writew(cmd->rq->nr_sectors, base, TX4939IDE_Sec_Cnt); + tx4939ide_writew(blk_rq_sectors(cmd->rq), base, TX4939IDE_Sec_Cnt); return 0; } @@ -537,8 +537,7 @@ static const struct ide_port_info tx4939ide_port_info __initdata = { static int __init tx4939ide_probe(struct platform_device *pdev) { - hw_regs_t hw; - hw_regs_t *hws[] = { &hw, NULL, NULL, NULL }; + struct ide_hw hw, *hws[] = { &hw }; struct ide_host *host; struct resource *res; int irq, ret; @@ -581,7 +580,7 @@ static int __init tx4939ide_probe(struct platform_device *pdev) hw.dev = &pdev->dev; pr_info("TX4939 IDE interface (base %#lx, irq %d)\n", mapbase, irq); - host = ide_host_alloc(&tx4939ide_port_info, hws); + host = ide_host_alloc(&tx4939ide_port_info, hws, 1); if (!host) return -ENOMEM; /* use extra_base for base address of the all registers */ diff --git a/drivers/ieee1394/Kconfig b/drivers/ieee1394/Kconfig index 95f45f9b8e5e..f102fcc7e52a 100644 --- a/drivers/ieee1394/Kconfig +++ b/drivers/ieee1394/Kconfig @@ -4,7 +4,7 @@ menu "IEEE 1394 (FireWire) support" source "drivers/firewire/Kconfig" config IEEE1394 - tristate "Stable FireWire stack" + tristate "Legacy alternative FireWire driver stack" depends on PCI || BROKEN help IEEE 1394 describes a high performance serial bus, which is also @@ -33,11 +33,9 @@ config IEEE1394_OHCI1394 module will be called ohci1394. NOTE: - - You should only build either ohci1394 or the new firewire-ohci driver, - but not both. If you nevertheless want to install both, you should - configure them only as modules and blacklist the driver(s) which you - don't want to have auto-loaded. Add either + If you want to install firewire-ohci and ohci1394 together, you + should configure them only as modules and blacklist the driver(s) + which you don't want to have auto-loaded. Add either blacklist firewire-ohci or @@ -46,12 +44,7 @@ config IEEE1394_OHCI1394 blacklist dv1394 to /etc/modprobe.conf or /etc/modprobe.d/* and update modprobe.conf - depending on your distribution. The latter two modules should be - blacklisted together with ohci1394 because they depend on ohci1394. - - If you have an old modprobe which doesn't implement the blacklist - directive, use "install modulename /bin/true" for the modules to be - blacklisted. + depending on your distribution. comment "PCILynx controller requires I2C" depends on IEEE1394 && I2C=n @@ -105,7 +98,7 @@ config IEEE1394_ETH1394_ROM_ENTRY default n config IEEE1394_ETH1394 - tristate "IP over 1394" + tristate "IP networking over 1394 (experimental)" depends on IEEE1394 && EXPERIMENTAL && INET select IEEE1394_ETH1394_ROM_ENTRY help diff --git a/drivers/ieee1394/csr1212.c b/drivers/ieee1394/csr1212.c index a6dfeb0b3372..e76cac64c533 100644 --- a/drivers/ieee1394/csr1212.c +++ b/drivers/ieee1394/csr1212.c @@ -35,6 +35,7 @@ #include #include +#include #include #include #include @@ -387,6 +388,7 @@ csr1212_new_descriptor_leaf(u8 dtype, u32 specifier_id, if (!kv) return NULL; + kmemcheck_annotate_variable(kv->value.leaf.data[0]); CSR1212_DESCRIPTOR_LEAF_SET_TYPE(kv, dtype); CSR1212_DESCRIPTOR_LEAF_SET_SPECIFIER_ID(kv, specifier_id); diff --git a/drivers/ieee1394/dv1394.c b/drivers/ieee1394/dv1394.c index 823a6297a1af..2cd00b5b45b4 100644 --- a/drivers/ieee1394/dv1394.c +++ b/drivers/ieee1394/dv1394.c @@ -1789,12 +1789,13 @@ static int dv1394_open(struct inode *inode, struct file *file) } else { /* look up the card by ID */ unsigned long flags; + int idx = ieee1394_file_to_instance(file); spin_lock_irqsave(&dv1394_cards_lock, flags); if (!list_empty(&dv1394_cards)) { struct video_card *p; list_for_each_entry(p, &dv1394_cards, list) { - if ((p->id) == ieee1394_file_to_instance(file)) { + if ((p->id) == idx) { video = p; break; } @@ -1803,7 +1804,7 @@ static int dv1394_open(struct inode *inode, struct file *file) spin_unlock_irqrestore(&dv1394_cards_lock, flags); if (!video) { - debug_printk("dv1394: OHCI card %d not found", ieee1394_file_to_instance(file)); + debug_printk("dv1394: OHCI card %d not found", idx); return -ENODEV; } diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c index 4ca103577c0a..f5c586c2bba6 100644 --- a/drivers/ieee1394/eth1394.c +++ b/drivers/ieee1394/eth1394.c @@ -361,7 +361,7 @@ static int eth1394_new_node(struct eth1394_host_info *hi, node_info->pdg.sz = 0; node_info->fifo = CSR1212_INVALID_ADDR_SPACE; - ud->device.driver_data = node_info; + dev_set_drvdata(&ud->device, node_info); new_node->ud = ud; priv = netdev_priv(hi->dev); @@ -406,7 +406,7 @@ static int eth1394_remove(struct device *dev) list_del(&old_node->list); kfree(old_node); - node_info = (struct eth1394_node_info*)ud->device.driver_data; + node_info = dev_get_drvdata(&ud->device); spin_lock_irqsave(&node_info->pdg.lock, flags); /* The partial datagram list should be empty, but we'll just @@ -416,7 +416,7 @@ static int eth1394_remove(struct device *dev) spin_unlock_irqrestore(&node_info->pdg.lock, flags); kfree(node_info); - ud->device.driver_data = NULL; + dev_set_drvdata(&ud->device, NULL); return 0; } @@ -688,7 +688,7 @@ static void ether1394_host_reset(struct hpsb_host *host) ether1394_reset_priv(dev, 0); list_for_each_entry(node, &priv->ip_node_list, list) { - node_info = node->ud->device.driver_data; + node_info = dev_get_drvdata(&node->ud->device); spin_lock_irqsave(&node_info->pdg.lock, flags); @@ -872,8 +872,7 @@ static __be16 ether1394_parse_encap(struct sk_buff *skb, struct net_device *dev, if (!node) return cpu_to_be16(0); - node_info = - (struct eth1394_node_info *)node->ud->device.driver_data; + node_info = dev_get_drvdata(&node->ud->device); /* Update our speed/payload/fifo_offset table */ node_info->maxpayload = maxpayload; @@ -1080,7 +1079,7 @@ static int ether1394_data_handler(struct net_device *dev, int srcid, int destid, priv->ud_list[NODEID_TO_NODE(srcid)] = ud; } - node_info = (struct eth1394_node_info *)ud->device.driver_data; + node_info = dev_get_drvdata(&ud->device); /* First, did we receive a fragmented or unfragmented datagram? */ hdr->words.word1 = ntohs(hdr->words.word1); @@ -1617,8 +1616,7 @@ static int ether1394_tx(struct sk_buff *skb, struct net_device *dev) if (!node) goto fail; - node_info = - (struct eth1394_node_info *)node->ud->device.driver_data; + node_info = dev_get_drvdata(&node->ud->device); if (node_info->fifo == CSR1212_INVALID_ADDR_SPACE) goto fail; diff --git a/drivers/ieee1394/ieee1394_core.h b/drivers/ieee1394/ieee1394_core.h index 21d50f73a210..28b9f58bafd2 100644 --- a/drivers/ieee1394/ieee1394_core.h +++ b/drivers/ieee1394/ieee1394_core.h @@ -5,6 +5,7 @@ #include #include #include +#include #include #include "hosts.h" @@ -155,7 +156,10 @@ void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size, */ static inline unsigned char ieee1394_file_to_instance(struct file *file) { - return file->f_path.dentry->d_inode->i_cindex; + int idx = cdev_index(file->f_path.dentry->d_inode); + if (idx < 0) + idx = 0; + return idx; } extern int hpsb_disable_irm; diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c index a6d55bebe61a..5122b5a8aa2d 100644 --- a/drivers/ieee1394/nodemgr.c +++ b/drivers/ieee1394/nodemgr.c @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -39,7 +40,10 @@ struct nodemgr_csr_info { struct hpsb_host *host; nodeid_t nodeid; unsigned int generation; + + kmemcheck_bitfield_begin(flags); unsigned int speed_unverified:1; + kmemcheck_bitfield_end(flags); }; @@ -1293,6 +1297,7 @@ static void nodemgr_node_scan_one(struct hpsb_host *host, u8 *speed; ci = kmalloc(sizeof(*ci), GFP_KERNEL); + kmemcheck_annotate_bitfield(ci, flags); if (!ci) return; diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c index a51ab233342d..83b734aec923 100644 --- a/drivers/ieee1394/sbp2.c +++ b/drivers/ieee1394/sbp2.c @@ -718,7 +718,7 @@ static int sbp2_remove(struct device *dev) struct scsi_device *sdev; ud = container_of(dev, struct unit_directory, device); - lu = ud->device.driver_data; + lu = dev_get_drvdata(&ud->device); if (!lu) return 0; @@ -746,7 +746,7 @@ static int sbp2_remove(struct device *dev) static int sbp2_update(struct unit_directory *ud) { - struct sbp2_lu *lu = ud->device.driver_data; + struct sbp2_lu *lu = dev_get_drvdata(&ud->device); if (sbp2_reconnect_device(lu) != 0) { /* @@ -815,7 +815,7 @@ static struct sbp2_lu *sbp2_alloc_device(struct unit_directory *ud) atomic_set(&lu->state, SBP2LU_STATE_RUNNING); INIT_WORK(&lu->protocol_work, NULL); - ud->device.driver_data = lu; + dev_set_drvdata(&ud->device, lu); hi = hpsb_get_hostinfo(&sbp2_highlevel, ud->ne->host); if (!hi) { @@ -1051,7 +1051,7 @@ static void sbp2_remove_device(struct sbp2_lu *lu) hpsb_unregister_addrspace(&sbp2_highlevel, hi->host, lu->status_fifo_addr); - lu->ud->device.driver_data = NULL; + dev_set_drvdata(&lu->ud->device, NULL); module_put(hi->host->driver->owner); no_hi: diff --git a/drivers/ieee802154/Kconfig b/drivers/ieee802154/Kconfig new file mode 100644 index 000000000000..9b9f43aa2f85 --- /dev/null +++ b/drivers/ieee802154/Kconfig @@ -0,0 +1,22 @@ +menuconfig IEEE802154_DRIVERS + tristate "IEEE 802.15.4 drivers" + depends on NETDEVICES && IEEE802154 + default y + ---help--- + Say Y here to get to see options for IEEE 802.15.4 Low-Rate + Wireless Personal Area Network device drivers. This option alone + does not add any kernel code. + + If you say N, all options in this submenu will be skipped and + disabled. + +config IEEE802154_FAKEHARD + tristate "Fake LR-WPAN driver with several interconnected devices" + depends on IEEE802154_DRIVERS + ---help--- + Say Y here to enable the fake driver that serves as an example + of HardMAC device driver. + + This driver can also be built as a module. To do so say M here. + The module will be called 'fakehard'. + diff --git a/drivers/ieee802154/Makefile b/drivers/ieee802154/Makefile new file mode 100644 index 000000000000..e0e8e1a184ff --- /dev/null +++ b/drivers/ieee802154/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_IEEE802154_FAKEHARD) += fakehard.o + +EXTRA_CFLAGS += -DDEBUG -DCONFIG_FFD diff --git a/drivers/ieee802154/fakehard.c b/drivers/ieee802154/fakehard.c new file mode 100644 index 000000000000..0384144c0b34 --- /dev/null +++ b/drivers/ieee802154/fakehard.c @@ -0,0 +1,270 @@ +/* + * Sample driver for HardMAC IEEE 802.15.4 devices + * + * Copyright (C) 2009 Siemens AG + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Written by: + * Dmitry Eremin-Solenikov + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +static u16 fake_get_pan_id(struct net_device *dev) +{ + BUG_ON(dev->type != ARPHRD_IEEE802154); + + return 0xeba1; +} + +static u16 fake_get_short_addr(struct net_device *dev) +{ + BUG_ON(dev->type != ARPHRD_IEEE802154); + + return 0x1; +} + +static u8 fake_get_dsn(struct net_device *dev) +{ + BUG_ON(dev->type != ARPHRD_IEEE802154); + + return 0x00; /* DSN are implemented in HW, so return just 0 */ +} + +static u8 fake_get_bsn(struct net_device *dev) +{ + BUG_ON(dev->type != ARPHRD_IEEE802154); + + return 0x00; /* BSN are implemented in HW, so return just 0 */ +} + +static int fake_assoc_req(struct net_device *dev, + struct ieee802154_addr *addr, u8 channel, u8 cap) +{ + /* We simply emulate it here */ + return ieee802154_nl_assoc_confirm(dev, fake_get_short_addr(dev), + IEEE802154_SUCCESS); +} + +static int fake_assoc_resp(struct net_device *dev, + struct ieee802154_addr *addr, u16 short_addr, u8 status) +{ + return 0; +} + +static int fake_disassoc_req(struct net_device *dev, + struct ieee802154_addr *addr, u8 reason) +{ + return ieee802154_nl_disassoc_confirm(dev, IEEE802154_SUCCESS); +} + +static int fake_start_req(struct net_device *dev, struct ieee802154_addr *addr, + u8 channel, + u8 bcn_ord, u8 sf_ord, u8 pan_coord, u8 blx, + u8 coord_realign) +{ + return 0; +} + +static int fake_scan_req(struct net_device *dev, u8 type, u32 channels, + u8 duration) +{ + u8 edl[27] = {}; + return ieee802154_nl_scan_confirm(dev, IEEE802154_SUCCESS, type, + channels, + type == IEEE802154_MAC_SCAN_ED ? edl : NULL); +} + +static struct ieee802154_mlme_ops fake_mlme = { + .assoc_req = fake_assoc_req, + .assoc_resp = fake_assoc_resp, + .disassoc_req = fake_disassoc_req, + .start_req = fake_start_req, + .scan_req = fake_scan_req, + + .get_pan_id = fake_get_pan_id, + .get_short_addr = fake_get_short_addr, + .get_dsn = fake_get_dsn, + .get_bsn = fake_get_bsn, +}; + +static int ieee802154_fake_open(struct net_device *dev) +{ + netif_start_queue(dev); + return 0; +} + +static int ieee802154_fake_close(struct net_device *dev) +{ + netif_stop_queue(dev); + return 0; +} + +static int ieee802154_fake_xmit(struct sk_buff *skb, struct net_device *dev) +{ + skb->iif = dev->ifindex; + skb->dev = dev; + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; + + dev->trans_start = jiffies; + + /* FIXME: do hardware work here ... */ + + return 0; +} + + +static int ieee802154_fake_ioctl(struct net_device *dev, struct ifreq *ifr, + int cmd) +{ + struct sockaddr_ieee802154 *sa = + (struct sockaddr_ieee802154 *)&ifr->ifr_addr; + u16 pan_id, short_addr; + + switch (cmd) { + case SIOCGIFADDR: + /* FIXME: fixed here, get from device IRL */ + pan_id = fake_get_pan_id(dev); + short_addr = fake_get_short_addr(dev); + if (pan_id == IEEE802154_PANID_BROADCAST || + short_addr == IEEE802154_ADDR_BROADCAST) + return -EADDRNOTAVAIL; + + sa->family = AF_IEEE802154; + sa->addr.addr_type = IEEE802154_ADDR_SHORT; + sa->addr.pan_id = pan_id; + sa->addr.short_addr = short_addr; + return 0; + } + return -ENOIOCTLCMD; +} + +static int ieee802154_fake_mac_addr(struct net_device *dev, void *p) +{ + return -EBUSY; /* HW address is built into the device */ +} + +static const struct net_device_ops fake_ops = { + .ndo_open = ieee802154_fake_open, + .ndo_stop = ieee802154_fake_close, + .ndo_start_xmit = ieee802154_fake_xmit, + .ndo_do_ioctl = ieee802154_fake_ioctl, + .ndo_set_mac_address = ieee802154_fake_mac_addr, +}; + + +static void ieee802154_fake_setup(struct net_device *dev) +{ + dev->addr_len = IEEE802154_ADDR_LEN; + memset(dev->broadcast, 0xff, IEEE802154_ADDR_LEN); + dev->features = NETIF_F_NO_CSUM; + dev->needed_tailroom = 2; /* FCS */ + dev->mtu = 127; + dev->tx_queue_len = 10; + dev->type = ARPHRD_IEEE802154; + dev->flags = IFF_NOARP | IFF_BROADCAST; + dev->watchdog_timeo = 0; +} + + +static int __devinit ieee802154fake_probe(struct platform_device *pdev) +{ + struct net_device *dev = + alloc_netdev(0, "hardwpan%d", ieee802154_fake_setup); + int err; + + if (!dev) + return -ENOMEM; + + memcpy(dev->dev_addr, "\xba\xbe\xca\xfe\xde\xad\xbe\xef", + dev->addr_len); + memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); + + dev->netdev_ops = &fake_ops; + dev->ml_priv = &fake_mlme; + + /* + * If the name is a format string the caller wants us to do a + * name allocation. + */ + if (strchr(dev->name, '%')) { + err = dev_alloc_name(dev, dev->name); + if (err < 0) + goto out; + } + + SET_NETDEV_DEV(dev, &pdev->dev); + + platform_set_drvdata(pdev, dev); + + err = register_netdev(dev); + if (err < 0) + goto out; + + + dev_info(&pdev->dev, "Added ieee802154 HardMAC hardware\n"); + return 0; + +out: + unregister_netdev(dev); + return err; +} + +static int __devexit ieee802154fake_remove(struct platform_device *pdev) +{ + struct net_device *dev = platform_get_drvdata(pdev); + unregister_netdev(dev); + free_netdev(dev); + return 0; +} + +static struct platform_device *ieee802154fake_dev; + +static struct platform_driver ieee802154fake_driver = { + .probe = ieee802154fake_probe, + .remove = __devexit_p(ieee802154fake_remove), + .driver = { + .name = "ieee802154hardmac", + .owner = THIS_MODULE, + }, +}; + +static __init int fake_init(void) +{ + ieee802154fake_dev = platform_device_register_simple( + "ieee802154hardmac", -1, NULL, 0); + return platform_driver_register(&ieee802154fake_driver); +} + +static __exit void fake_exit(void) +{ + platform_driver_unregister(&ieee802154fake_driver); + platform_device_unregister(ieee802154fake_dev); +} + +module_init(fake_init); +module_exit(fake_exit); +MODULE_LICENSE("GPL"); + diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c index ce511d8748ce..5be1bd4fc7ed 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c @@ -514,7 +514,7 @@ static struct notifier_block nb = { .notifier_call = netevent_callback }; -static int addr_init(void) +static int __init addr_init(void) { addr_wq = create_singlethread_workqueue("ib_addr"); if (!addr_wq) @@ -524,7 +524,7 @@ static int addr_init(void) return 0; } -static void addr_cleanup(void) +static void __exit addr_cleanup(void) { unregister_netevent_notifier(&nb); destroy_workqueue(addr_wq); diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 851de83ff455..075317884b53 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -2960,7 +2960,7 @@ static void cma_remove_one(struct ib_device *device) kfree(cma_dev); } -static int cma_init(void) +static int __init cma_init(void) { int ret, low, high, remaining; @@ -2990,7 +2990,7 @@ err: return ret; } -static void cma_cleanup(void) +static void __exit cma_cleanup(void) { ib_unregister_client(&cma_client); unregister_netdevice_notifier(&cma_nb); diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c index 5c04cfb54cb9..158a214da2f7 100644 --- a/drivers/infiniband/core/sysfs.c +++ b/drivers/infiniband/core/sysfs.c @@ -760,9 +760,9 @@ int ib_device_register_sysfs(struct ib_device *device) int i; class_dev->class = &ib_class; - class_dev->driver_data = device; class_dev->parent = device->dma_device; dev_set_name(class_dev, device->name); + dev_set_drvdata(class_dev, device); INIT_LIST_HEAD(&device->port_list); diff --git a/drivers/infiniband/hw/amso1100/c2_cq.c b/drivers/infiniband/hw/amso1100/c2_cq.c index bb17cce3cb59..f5c45b194f53 100644 --- a/drivers/infiniband/hw/amso1100/c2_cq.c +++ b/drivers/infiniband/hw/amso1100/c2_cq.c @@ -133,7 +133,7 @@ static inline int c2_poll_one(struct c2_dev *c2dev, struct c2_qp *qp; int is_recv = 0; - ce = (struct c2wr_ce *) c2_mq_consume(&cq->mq); + ce = c2_mq_consume(&cq->mq); if (!ce) { return -EAGAIN; } @@ -146,7 +146,7 @@ static inline int c2_poll_one(struct c2_dev *c2dev, while ((qp = (struct c2_qp *) (unsigned long) ce->qp_user_context) == NULL) { c2_mq_free(&cq->mq); - ce = (struct c2wr_ce *) c2_mq_consume(&cq->mq); + ce = c2_mq_consume(&cq->mq); if (!ce) return -EAGAIN; } diff --git a/drivers/infiniband/hw/cxgb3/cxio_wr.h b/drivers/infiniband/hw/cxgb3/cxio_wr.h index ff9be1a13106..32e3b1461d81 100644 --- a/drivers/infiniband/hw/cxgb3/cxio_wr.h +++ b/drivers/infiniband/hw/cxgb3/cxio_wr.h @@ -176,7 +176,7 @@ struct t3_send_wr { struct t3_sge sgl[T3_MAX_SGE]; /* 4+ */ }; -#define T3_MAX_FASTREG_DEPTH 24 +#define T3_MAX_FASTREG_DEPTH 10 #define T3_MAX_FASTREG_FRAG 10 struct t3_fastreg_wr { diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c index 160ef482712d..e2a63214008a 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_provider.c +++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -1152,12 +1153,39 @@ static int iwch_query_device(struct ib_device *ibdev, static int iwch_query_port(struct ib_device *ibdev, u8 port, struct ib_port_attr *props) { + struct iwch_dev *dev; + struct net_device *netdev; + struct in_device *inetdev; + PDBG("%s ibdev %p\n", __func__, ibdev); + dev = to_iwch_dev(ibdev); + netdev = dev->rdev.port_info.lldevs[port-1]; + memset(props, 0, sizeof(struct ib_port_attr)); props->max_mtu = IB_MTU_4096; - props->active_mtu = IB_MTU_2048; - props->state = IB_PORT_ACTIVE; + if (netdev->mtu >= 4096) + props->active_mtu = IB_MTU_4096; + else if (netdev->mtu >= 2048) + props->active_mtu = IB_MTU_2048; + else if (netdev->mtu >= 1024) + props->active_mtu = IB_MTU_1024; + else if (netdev->mtu >= 512) + props->active_mtu = IB_MTU_512; + else + props->active_mtu = IB_MTU_256; + + if (!netif_carrier_ok(netdev)) + props->state = IB_PORT_DOWN; + else { + inetdev = in_dev_get(netdev); + if (inetdev->ifa_list) + props->state = IB_PORT_ACTIVE; + else + props->state = IB_PORT_INIT; + in_dev_put(inetdev); + } + props->port_cap_flags = IB_PORT_CM_SUP | IB_PORT_SNMP_TUNNEL_SUP | diff --git a/drivers/infiniband/hw/ehca/ehca_classes_pSeries.h b/drivers/infiniband/hw/ehca/ehca_classes_pSeries.h index 1798e6466bd0..689c35786dd2 100644 --- a/drivers/infiniband/hw/ehca/ehca_classes_pSeries.h +++ b/drivers/infiniband/hw/ehca/ehca_classes_pSeries.h @@ -165,7 +165,6 @@ struct hcp_modify_qp_control_block { #define MQPCB_MASK_ALT_P_KEY_IDX EHCA_BMASK_IBM( 7, 7) #define MQPCB_MASK_RDMA_ATOMIC_CTRL EHCA_BMASK_IBM( 8, 8) #define MQPCB_MASK_QP_STATE EHCA_BMASK_IBM( 9, 9) -#define MQPCB_QP_STATE EHCA_BMASK_IBM(24, 31) #define MQPCB_MASK_RDMA_NR_ATOMIC_RESP_RES EHCA_BMASK_IBM(11, 11) #define MQPCB_MASK_PATH_MIGRATION_STATE EHCA_BMASK_IBM(12, 12) #define MQPCB_MASK_RDMA_ATOMIC_OUTST_DEST_QP EHCA_BMASK_IBM(13, 13) @@ -176,60 +175,33 @@ struct hcp_modify_qp_control_block { #define MQPCB_MASK_RETRY_COUNT EHCA_BMASK_IBM(18, 18) #define MQPCB_MASK_TIMEOUT EHCA_BMASK_IBM(19, 19) #define MQPCB_MASK_PATH_MTU EHCA_BMASK_IBM(20, 20) -#define MQPCB_PATH_MTU EHCA_BMASK_IBM(24, 31) #define MQPCB_MASK_MAX_STATIC_RATE EHCA_BMASK_IBM(21, 21) -#define MQPCB_MAX_STATIC_RATE EHCA_BMASK_IBM(24, 31) #define MQPCB_MASK_DLID EHCA_BMASK_IBM(22, 22) -#define MQPCB_DLID EHCA_BMASK_IBM(16, 31) #define MQPCB_MASK_RNR_RETRY_COUNT EHCA_BMASK_IBM(23, 23) -#define MQPCB_RNR_RETRY_COUNT EHCA_BMASK_IBM(29, 31) #define MQPCB_MASK_SOURCE_PATH_BITS EHCA_BMASK_IBM(24, 24) -#define MQPCB_SOURCE_PATH_BITS EHCA_BMASK_IBM(25, 31) #define MQPCB_MASK_TRAFFIC_CLASS EHCA_BMASK_IBM(25, 25) -#define MQPCB_TRAFFIC_CLASS EHCA_BMASK_IBM(24, 31) #define MQPCB_MASK_HOP_LIMIT EHCA_BMASK_IBM(26, 26) -#define MQPCB_HOP_LIMIT EHCA_BMASK_IBM(24, 31) #define MQPCB_MASK_SOURCE_GID_IDX EHCA_BMASK_IBM(27, 27) -#define MQPCB_SOURCE_GID_IDX EHCA_BMASK_IBM(24, 31) #define MQPCB_MASK_FLOW_LABEL EHCA_BMASK_IBM(28, 28) -#define MQPCB_FLOW_LABEL EHCA_BMASK_IBM(12, 31) #define MQPCB_MASK_DEST_GID EHCA_BMASK_IBM(30, 30) #define MQPCB_MASK_SERVICE_LEVEL_AL EHCA_BMASK_IBM(31, 31) -#define MQPCB_SERVICE_LEVEL_AL EHCA_BMASK_IBM(28, 31) #define MQPCB_MASK_SEND_GRH_FLAG_AL EHCA_BMASK_IBM(32, 32) -#define MQPCB_SEND_GRH_FLAG_AL EHCA_BMASK_IBM(31, 31) #define MQPCB_MASK_RETRY_COUNT_AL EHCA_BMASK_IBM(33, 33) -#define MQPCB_RETRY_COUNT_AL EHCA_BMASK_IBM(29, 31) #define MQPCB_MASK_TIMEOUT_AL EHCA_BMASK_IBM(34, 34) -#define MQPCB_TIMEOUT_AL EHCA_BMASK_IBM(27, 31) #define MQPCB_MASK_MAX_STATIC_RATE_AL EHCA_BMASK_IBM(35, 35) -#define MQPCB_MAX_STATIC_RATE_AL EHCA_BMASK_IBM(24, 31) #define MQPCB_MASK_DLID_AL EHCA_BMASK_IBM(36, 36) -#define MQPCB_DLID_AL EHCA_BMASK_IBM(16, 31) #define MQPCB_MASK_RNR_RETRY_COUNT_AL EHCA_BMASK_IBM(37, 37) -#define MQPCB_RNR_RETRY_COUNT_AL EHCA_BMASK_IBM(29, 31) #define MQPCB_MASK_SOURCE_PATH_BITS_AL EHCA_BMASK_IBM(38, 38) -#define MQPCB_SOURCE_PATH_BITS_AL EHCA_BMASK_IBM(25, 31) #define MQPCB_MASK_TRAFFIC_CLASS_AL EHCA_BMASK_IBM(39, 39) -#define MQPCB_TRAFFIC_CLASS_AL EHCA_BMASK_IBM(24, 31) #define MQPCB_MASK_HOP_LIMIT_AL EHCA_BMASK_IBM(40, 40) -#define MQPCB_HOP_LIMIT_AL EHCA_BMASK_IBM(24, 31) #define MQPCB_MASK_SOURCE_GID_IDX_AL EHCA_BMASK_IBM(41, 41) -#define MQPCB_SOURCE_GID_IDX_AL EHCA_BMASK_IBM(24, 31) #define MQPCB_MASK_FLOW_LABEL_AL EHCA_BMASK_IBM(42, 42) -#define MQPCB_FLOW_LABEL_AL EHCA_BMASK_IBM(12, 31) #define MQPCB_MASK_DEST_GID_AL EHCA_BMASK_IBM(44, 44) #define MQPCB_MASK_MAX_NR_OUTST_SEND_WR EHCA_BMASK_IBM(45, 45) -#define MQPCB_MAX_NR_OUTST_SEND_WR EHCA_BMASK_IBM(16, 31) #define MQPCB_MASK_MAX_NR_OUTST_RECV_WR EHCA_BMASK_IBM(46, 46) -#define MQPCB_MAX_NR_OUTST_RECV_WR EHCA_BMASK_IBM(16, 31) #define MQPCB_MASK_DISABLE_ETE_CREDIT_CHECK EHCA_BMASK_IBM(47, 47) -#define MQPCB_DISABLE_ETE_CREDIT_CHECK EHCA_BMASK_IBM(31, 31) -#define MQPCB_QP_NUMBER EHCA_BMASK_IBM( 8, 31) #define MQPCB_MASK_QP_ENABLE EHCA_BMASK_IBM(48, 48) -#define MQPCB_QP_ENABLE EHCA_BMASK_IBM(31, 31) #define MQPCB_MASK_CURR_SRQ_LIMIT EHCA_BMASK_IBM(49, 49) -#define MQPCB_CURR_SRQ_LIMIT EHCA_BMASK_IBM(16, 31) #define MQPCB_MASK_QP_AFF_ASYN_EV_LOG_REG EHCA_BMASK_IBM(50, 50) #define MQPCB_MASK_SHARED_RQ_HNDL EHCA_BMASK_IBM(51, 51) diff --git a/drivers/infiniband/hw/ehca/ehca_hca.c b/drivers/infiniband/hw/ehca/ehca_hca.c index 9209c5332dfe..8b92f85d4dd0 100644 --- a/drivers/infiniband/hw/ehca/ehca_hca.c +++ b/drivers/infiniband/hw/ehca/ehca_hca.c @@ -319,7 +319,7 @@ int ehca_query_gid(struct ib_device *ibdev, u8 port, ib_device); struct hipz_query_port *rblock; - if (index > 255) { + if (index < 0 || index > 255) { ehca_err(&shca->ib_device, "Invalid index: %x.", index); return -EINVAL; } diff --git a/drivers/infiniband/hw/ehca/ehca_irq.c b/drivers/infiniband/hw/ehca/ehca_irq.c index 99bcbd7ffb0a..4b89b791be6a 100644 --- a/drivers/infiniband/hw/ehca/ehca_irq.c +++ b/drivers/infiniband/hw/ehca/ehca_irq.c @@ -479,13 +479,13 @@ void ehca_tasklet_neq(unsigned long data) struct ehca_eqe *eqe; u64 ret; - eqe = (struct ehca_eqe *)ehca_poll_eq(shca, &shca->neq); + eqe = ehca_poll_eq(shca, &shca->neq); while (eqe) { if (!EHCA_BMASK_GET(NEQE_COMPLETION_EVENT, eqe->entry)) parse_ec(shca, eqe->entry); - eqe = (struct ehca_eqe *)ehca_poll_eq(shca, &shca->neq); + eqe = ehca_poll_eq(shca, &shca->neq); } ret = hipz_h_reset_event(shca->ipz_hca_handle, @@ -572,8 +572,7 @@ void ehca_process_eq(struct ehca_shca *shca, int is_irq) eqe_cnt = 0; do { u32 token; - eqe_cache[eqe_cnt].eqe = - (struct ehca_eqe *)ehca_poll_eq(shca, eq); + eqe_cache[eqe_cnt].eqe = ehca_poll_eq(shca, eq); if (!eqe_cache[eqe_cnt].eqe) break; eqe_value = eqe_cache[eqe_cnt].eqe->entry; @@ -637,7 +636,7 @@ void ehca_process_eq(struct ehca_shca *shca, int is_irq) goto unlock_irq_spinlock; do { struct ehca_eqe *eqe; - eqe = (struct ehca_eqe *)ehca_poll_eq(shca, &shca->eq); + eqe = ehca_poll_eq(shca, &shca->eq); if (!eqe) break; process_eqe(shca, eqe); diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c index 368311ce332b..fab18a2c74a8 100644 --- a/drivers/infiniband/hw/ehca/ehca_main.c +++ b/drivers/infiniband/hw/ehca/ehca_main.c @@ -52,7 +52,7 @@ #include "ehca_tools.h" #include "hcp_if.h" -#define HCAD_VERSION "0026" +#define HCAD_VERSION "0028" MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Christoph Raisch "); @@ -506,6 +506,7 @@ static int ehca_init_device(struct ehca_shca *shca) shca->ib_device.detach_mcast = ehca_detach_mcast; shca->ib_device.process_mad = ehca_process_mad; shca->ib_device.mmap = ehca_mmap; + shca->ib_device.dma_ops = &ehca_dma_mapping_ops; if (EHCA_BMASK_GET(HCA_CAP_SRQ, shca->hca_cap)) { shca->ib_device.uverbs_cmd_mask |= @@ -636,7 +637,7 @@ static ssize_t ehca_show_##name(struct device *dev, \ struct hipz_query_hca *rblock; \ int data; \ \ - shca = dev->driver_data; \ + shca = dev_get_drvdata(dev); \ \ rblock = ehca_alloc_fw_ctrlblock(GFP_KERNEL); \ if (!rblock) { \ @@ -680,7 +681,7 @@ static ssize_t ehca_show_adapter_handle(struct device *dev, struct device_attribute *attr, char *buf) { - struct ehca_shca *shca = dev->driver_data; + struct ehca_shca *shca = dev_get_drvdata(dev); return sprintf(buf, "%llx\n", shca->ipz_hca_handle.handle); @@ -749,7 +750,7 @@ static int __devinit ehca_probe(struct of_device *dev, shca->ofdev = dev; shca->ipz_hca_handle.handle = *handle; - dev->dev.driver_data = shca; + dev_set_drvdata(&dev->dev, shca); ret = ehca_sense_attributes(shca); if (ret < 0) { @@ -878,7 +879,7 @@ probe1: static int __devexit ehca_remove(struct of_device *dev) { - struct ehca_shca *shca = dev->dev.driver_data; + struct ehca_shca *shca = dev_get_drvdata(&dev->dev); unsigned long flags; int ret; @@ -1028,17 +1029,23 @@ static int __init ehca_module_init(void) goto module_init1; } + ret = ehca_create_busmap(); + if (ret) { + ehca_gen_err("Cannot create busmap."); + goto module_init2; + } + ret = ibmebus_register_driver(&ehca_driver); if (ret) { ehca_gen_err("Cannot register eHCA device driver"); ret = -EINVAL; - goto module_init2; + goto module_init3; } ret = register_memory_notifier(&ehca_mem_nb); if (ret) { ehca_gen_err("Failed registering memory add/remove notifier"); - goto module_init3; + goto module_init4; } if (ehca_poll_all_eqs != 1) { @@ -1053,9 +1060,12 @@ static int __init ehca_module_init(void) return 0; -module_init3: +module_init4: ibmebus_unregister_driver(&ehca_driver); +module_init3: + ehca_destroy_busmap(); + module_init2: ehca_destroy_slab_caches(); @@ -1073,6 +1083,8 @@ static void __exit ehca_module_exit(void) unregister_memory_notifier(&ehca_mem_nb); + ehca_destroy_busmap(); + ehca_destroy_slab_caches(); ehca_destroy_comp_pool(); diff --git a/drivers/infiniband/hw/ehca/ehca_mrmw.c b/drivers/infiniband/hw/ehca/ehca_mrmw.c index 72f83f7df614..7663a2a9f130 100644 --- a/drivers/infiniband/hw/ehca/ehca_mrmw.c +++ b/drivers/infiniband/hw/ehca/ehca_mrmw.c @@ -53,6 +53,38 @@ /* max number of rpages (per hcall register_rpages) */ #define MAX_RPAGES 512 +/* DMEM toleration management */ +#define EHCA_SECTSHIFT SECTION_SIZE_BITS +#define EHCA_SECTSIZE (1UL << EHCA_SECTSHIFT) +#define EHCA_HUGEPAGESHIFT 34 +#define EHCA_HUGEPAGE_SIZE (1UL << EHCA_HUGEPAGESHIFT) +#define EHCA_HUGEPAGE_PFN_MASK ((EHCA_HUGEPAGE_SIZE - 1) >> PAGE_SHIFT) +#define EHCA_INVAL_ADDR 0xFFFFFFFFFFFFFFFFULL +#define EHCA_DIR_INDEX_SHIFT 13 /* 8k Entries in 64k block */ +#define EHCA_TOP_INDEX_SHIFT (EHCA_DIR_INDEX_SHIFT * 2) +#define EHCA_MAP_ENTRIES (1 << EHCA_DIR_INDEX_SHIFT) +#define EHCA_TOP_MAP_SIZE (0x10000) /* currently fixed map size */ +#define EHCA_DIR_MAP_SIZE (0x10000) +#define EHCA_ENT_MAP_SIZE (0x10000) +#define EHCA_INDEX_MASK (EHCA_MAP_ENTRIES - 1) + +static unsigned long ehca_mr_len; + +/* + * Memory map data structures + */ +struct ehca_dir_bmap { + u64 ent[EHCA_MAP_ENTRIES]; +}; +struct ehca_top_bmap { + struct ehca_dir_bmap *dir[EHCA_MAP_ENTRIES]; +}; +struct ehca_bmap { + struct ehca_top_bmap *top[EHCA_MAP_ENTRIES]; +}; + +static struct ehca_bmap *ehca_bmap; + static struct kmem_cache *mr_cache; static struct kmem_cache *mw_cache; @@ -68,6 +100,8 @@ enum ehca_mr_pgsize { #define EHCA_MR_PGSHIFT1M 20 #define EHCA_MR_PGSHIFT16M 24 +static u64 ehca_map_vaddr(void *caddr); + static u32 ehca_encode_hwpage_size(u32 pgsize) { int log = ilog2(pgsize); @@ -135,7 +169,8 @@ struct ib_mr *ehca_get_dma_mr(struct ib_pd *pd, int mr_access_flags) goto get_dma_mr_exit0; } - ret = ehca_reg_maxmr(shca, e_maxmr, (u64 *)KERNELBASE, + ret = ehca_reg_maxmr(shca, e_maxmr, + (void *)ehca_map_vaddr((void *)KERNELBASE), mr_access_flags, e_pd, &e_maxmr->ib.ib_mr.lkey, &e_maxmr->ib.ib_mr.rkey); @@ -251,7 +286,7 @@ struct ib_mr *ehca_reg_phys_mr(struct ib_pd *pd, ret = ehca_reg_mr(shca, e_mr, iova_start, size, mr_access_flags, e_pd, &pginfo, &e_mr->ib.ib_mr.lkey, - &e_mr->ib.ib_mr.rkey); + &e_mr->ib.ib_mr.rkey, EHCA_REG_MR); if (ret) { ib_mr = ERR_PTR(ret); goto reg_phys_mr_exit1; @@ -370,7 +405,7 @@ reg_user_mr_fallback: ret = ehca_reg_mr(shca, e_mr, (u64 *)virt, length, mr_access_flags, e_pd, &pginfo, &e_mr->ib.ib_mr.lkey, - &e_mr->ib.ib_mr.rkey); + &e_mr->ib.ib_mr.rkey, EHCA_REG_MR); if (ret == -EINVAL && pginfo.hwpage_size > PAGE_SIZE) { ehca_warn(pd->device, "failed to register mr " "with hwpage_size=%llx", hwpage_size); @@ -794,7 +829,7 @@ struct ib_fmr *ehca_alloc_fmr(struct ib_pd *pd, ret = ehca_reg_mr(shca, e_fmr, NULL, fmr_attr->max_pages * (1 << fmr_attr->page_shift), mr_access_flags, e_pd, &pginfo, - &tmp_lkey, &tmp_rkey); + &tmp_lkey, &tmp_rkey, EHCA_REG_MR); if (ret) { ib_fmr = ERR_PTR(ret); goto alloc_fmr_exit1; @@ -983,6 +1018,10 @@ free_fmr_exit0: /*----------------------------------------------------------------------*/ +static int ehca_reg_bmap_mr_rpages(struct ehca_shca *shca, + struct ehca_mr *e_mr, + struct ehca_mr_pginfo *pginfo); + int ehca_reg_mr(struct ehca_shca *shca, struct ehca_mr *e_mr, u64 *iova_start, @@ -991,7 +1030,8 @@ int ehca_reg_mr(struct ehca_shca *shca, struct ehca_pd *e_pd, struct ehca_mr_pginfo *pginfo, u32 *lkey, /*OUT*/ - u32 *rkey) /*OUT*/ + u32 *rkey, /*OUT*/ + enum ehca_reg_type reg_type) { int ret; u64 h_ret; @@ -1015,7 +1055,13 @@ int ehca_reg_mr(struct ehca_shca *shca, e_mr->ipz_mr_handle = hipzout.handle; - ret = ehca_reg_mr_rpages(shca, e_mr, pginfo); + if (reg_type == EHCA_REG_BUSMAP_MR) + ret = ehca_reg_bmap_mr_rpages(shca, e_mr, pginfo); + else if (reg_type == EHCA_REG_MR) + ret = ehca_reg_mr_rpages(shca, e_mr, pginfo); + else + ret = -EINVAL; + if (ret) goto ehca_reg_mr_exit1; @@ -1316,7 +1362,7 @@ int ehca_rereg_mr(struct ehca_shca *shca, e_mr->fmr_map_cnt = save_mr.fmr_map_cnt; ret = ehca_reg_mr(shca, e_mr, iova_start, size, acl, - e_pd, pginfo, lkey, rkey); + e_pd, pginfo, lkey, rkey, EHCA_REG_MR); if (ret) { u32 offset = (u64)(&e_mr->flags) - (u64)e_mr; memcpy(&e_mr->flags, &(save_mr.flags), @@ -1409,7 +1455,7 @@ int ehca_unmap_one_fmr(struct ehca_shca *shca, ret = ehca_reg_mr(shca, e_fmr, NULL, (e_fmr->fmr_max_pages * e_fmr->fmr_page_size), e_fmr->acl, e_pd, &pginfo, &tmp_lkey, - &tmp_rkey); + &tmp_rkey, EHCA_REG_MR); if (ret) { u32 offset = (u64)(&e_fmr->flags) - (u64)e_fmr; memcpy(&e_fmr->flags, &(save_mr.flags), @@ -1478,6 +1524,90 @@ ehca_reg_smr_exit0: } /* end ehca_reg_smr() */ /*----------------------------------------------------------------------*/ +static inline void *ehca_calc_sectbase(int top, int dir, int idx) +{ + unsigned long ret = idx; + ret |= dir << EHCA_DIR_INDEX_SHIFT; + ret |= top << EHCA_TOP_INDEX_SHIFT; + return abs_to_virt(ret << SECTION_SIZE_BITS); +} + +#define ehca_bmap_valid(entry) \ + ((u64)entry != (u64)EHCA_INVAL_ADDR) + +static u64 ehca_reg_mr_section(int top, int dir, int idx, u64 *kpage, + struct ehca_shca *shca, struct ehca_mr *mr, + struct ehca_mr_pginfo *pginfo) +{ + u64 h_ret = 0; + unsigned long page = 0; + u64 rpage = virt_to_abs(kpage); + int page_count; + + void *sectbase = ehca_calc_sectbase(top, dir, idx); + if ((unsigned long)sectbase & (pginfo->hwpage_size - 1)) { + ehca_err(&shca->ib_device, "reg_mr_section will probably fail:" + "hwpage_size does not fit to " + "section start address"); + } + page_count = EHCA_SECTSIZE / pginfo->hwpage_size; + + while (page < page_count) { + u64 rnum; + for (rnum = 0; (rnum < MAX_RPAGES) && (page < page_count); + rnum++) { + void *pg = sectbase + ((page++) * pginfo->hwpage_size); + kpage[rnum] = virt_to_abs(pg); + } + + h_ret = hipz_h_register_rpage_mr(shca->ipz_hca_handle, mr, + ehca_encode_hwpage_size(pginfo->hwpage_size), + 0, rpage, rnum); + + if ((h_ret != H_SUCCESS) && (h_ret != H_PAGE_REGISTERED)) { + ehca_err(&shca->ib_device, "register_rpage_mr failed"); + return h_ret; + } + } + return h_ret; +} + +static u64 ehca_reg_mr_sections(int top, int dir, u64 *kpage, + struct ehca_shca *shca, struct ehca_mr *mr, + struct ehca_mr_pginfo *pginfo) +{ + u64 hret = H_SUCCESS; + int idx; + + for (idx = 0; idx < EHCA_MAP_ENTRIES; idx++) { + if (!ehca_bmap_valid(ehca_bmap->top[top]->dir[dir]->ent[idx])) + continue; + + hret = ehca_reg_mr_section(top, dir, idx, kpage, shca, mr, + pginfo); + if ((hret != H_SUCCESS) && (hret != H_PAGE_REGISTERED)) + return hret; + } + return hret; +} + +static u64 ehca_reg_mr_dir_sections(int top, u64 *kpage, struct ehca_shca *shca, + struct ehca_mr *mr, + struct ehca_mr_pginfo *pginfo) +{ + u64 hret = H_SUCCESS; + int dir; + + for (dir = 0; dir < EHCA_MAP_ENTRIES; dir++) { + if (!ehca_bmap_valid(ehca_bmap->top[top]->dir[dir])) + continue; + + hret = ehca_reg_mr_sections(top, dir, kpage, shca, mr, pginfo); + if ((hret != H_SUCCESS) && (hret != H_PAGE_REGISTERED)) + return hret; + } + return hret; +} /* register internal max-MR to internal SHCA */ int ehca_reg_internal_maxmr( @@ -1495,6 +1625,11 @@ int ehca_reg_internal_maxmr( u32 num_hwpages; u64 hw_pgsize; + if (!ehca_bmap) { + ret = -EFAULT; + goto ehca_reg_internal_maxmr_exit0; + } + e_mr = ehca_mr_new(); if (!e_mr) { ehca_err(&shca->ib_device, "out of memory"); @@ -1504,8 +1639,8 @@ int ehca_reg_internal_maxmr( e_mr->flags |= EHCA_MR_FLAG_MAXMR; /* register internal max-MR on HCA */ - size_maxmr = (u64)high_memory - PAGE_OFFSET; - iova_start = (u64 *)KERNELBASE; + size_maxmr = ehca_mr_len; + iova_start = (u64 *)ehca_map_vaddr((void *)KERNELBASE); ib_pbuf.addr = 0; ib_pbuf.size = size_maxmr; num_kpages = NUM_CHUNKS(((u64)iova_start % PAGE_SIZE) + size_maxmr, @@ -1524,7 +1659,7 @@ int ehca_reg_internal_maxmr( ret = ehca_reg_mr(shca, e_mr, iova_start, size_maxmr, 0, e_pd, &pginfo, &e_mr->ib.ib_mr.lkey, - &e_mr->ib.ib_mr.rkey); + &e_mr->ib.ib_mr.rkey, EHCA_REG_BUSMAP_MR); if (ret) { ehca_err(&shca->ib_device, "reg of internal max MR failed, " "e_mr=%p iova_start=%p size_maxmr=%llx num_kpages=%x " @@ -2077,8 +2212,8 @@ int ehca_mr_is_maxmr(u64 size, u64 *iova_start) { /* a MR is treated as max-MR only if it fits following: */ - if ((size == ((u64)high_memory - PAGE_OFFSET)) && - (iova_start == (void *)KERNELBASE)) { + if ((size == ehca_mr_len) && + (iova_start == (void *)ehca_map_vaddr((void *)KERNELBASE))) { ehca_gen_dbg("this is a max-MR"); return 1; } else @@ -2184,3 +2319,350 @@ void ehca_cleanup_mrmw_cache(void) if (mw_cache) kmem_cache_destroy(mw_cache); } + +static inline int ehca_init_top_bmap(struct ehca_top_bmap *ehca_top_bmap, + int dir) +{ + if (!ehca_bmap_valid(ehca_top_bmap->dir[dir])) { + ehca_top_bmap->dir[dir] = + kmalloc(sizeof(struct ehca_dir_bmap), GFP_KERNEL); + if (!ehca_top_bmap->dir[dir]) + return -ENOMEM; + /* Set map block to 0xFF according to EHCA_INVAL_ADDR */ + memset(ehca_top_bmap->dir[dir], 0xFF, EHCA_ENT_MAP_SIZE); + } + return 0; +} + +static inline int ehca_init_bmap(struct ehca_bmap *ehca_bmap, int top, int dir) +{ + if (!ehca_bmap_valid(ehca_bmap->top[top])) { + ehca_bmap->top[top] = + kmalloc(sizeof(struct ehca_top_bmap), GFP_KERNEL); + if (!ehca_bmap->top[top]) + return -ENOMEM; + /* Set map block to 0xFF according to EHCA_INVAL_ADDR */ + memset(ehca_bmap->top[top], 0xFF, EHCA_DIR_MAP_SIZE); + } + return ehca_init_top_bmap(ehca_bmap->top[top], dir); +} + +static inline int ehca_calc_index(unsigned long i, unsigned long s) +{ + return (i >> s) & EHCA_INDEX_MASK; +} + +void ehca_destroy_busmap(void) +{ + int top, dir; + + if (!ehca_bmap) + return; + + for (top = 0; top < EHCA_MAP_ENTRIES; top++) { + if (!ehca_bmap_valid(ehca_bmap->top[top])) + continue; + for (dir = 0; dir < EHCA_MAP_ENTRIES; dir++) { + if (!ehca_bmap_valid(ehca_bmap->top[top]->dir[dir])) + continue; + + kfree(ehca_bmap->top[top]->dir[dir]); + } + + kfree(ehca_bmap->top[top]); + } + + kfree(ehca_bmap); + ehca_bmap = NULL; +} + +static int ehca_update_busmap(unsigned long pfn, unsigned long nr_pages) +{ + unsigned long i, start_section, end_section; + int top, dir, idx; + + if (!nr_pages) + return 0; + + if (!ehca_bmap) { + ehca_bmap = kmalloc(sizeof(struct ehca_bmap), GFP_KERNEL); + if (!ehca_bmap) + return -ENOMEM; + /* Set map block to 0xFF according to EHCA_INVAL_ADDR */ + memset(ehca_bmap, 0xFF, EHCA_TOP_MAP_SIZE); + } + + start_section = phys_to_abs(pfn * PAGE_SIZE) / EHCA_SECTSIZE; + end_section = phys_to_abs((pfn + nr_pages) * PAGE_SIZE) / EHCA_SECTSIZE; + for (i = start_section; i < end_section; i++) { + int ret; + top = ehca_calc_index(i, EHCA_TOP_INDEX_SHIFT); + dir = ehca_calc_index(i, EHCA_DIR_INDEX_SHIFT); + idx = i & EHCA_INDEX_MASK; + + ret = ehca_init_bmap(ehca_bmap, top, dir); + if (ret) { + ehca_destroy_busmap(); + return ret; + } + ehca_bmap->top[top]->dir[dir]->ent[idx] = ehca_mr_len; + ehca_mr_len += EHCA_SECTSIZE; + } + return 0; +} + +static int ehca_is_hugepage(unsigned long pfn) +{ + int page_order; + + if (pfn & EHCA_HUGEPAGE_PFN_MASK) + return 0; + + page_order = compound_order(pfn_to_page(pfn)); + if (page_order + PAGE_SHIFT != EHCA_HUGEPAGESHIFT) + return 0; + + return 1; +} + +static int ehca_create_busmap_callback(unsigned long initial_pfn, + unsigned long total_nr_pages, void *arg) +{ + int ret; + unsigned long pfn, start_pfn, end_pfn, nr_pages; + + if ((total_nr_pages * PAGE_SIZE) < EHCA_HUGEPAGE_SIZE) + return ehca_update_busmap(initial_pfn, total_nr_pages); + + /* Given chunk is >= 16GB -> check for hugepages */ + start_pfn = initial_pfn; + end_pfn = initial_pfn + total_nr_pages; + pfn = start_pfn; + + while (pfn < end_pfn) { + if (ehca_is_hugepage(pfn)) { + /* Add mem found in front of the hugepage */ + nr_pages = pfn - start_pfn; + ret = ehca_update_busmap(start_pfn, nr_pages); + if (ret) + return ret; + /* Skip the hugepage */ + pfn += (EHCA_HUGEPAGE_SIZE / PAGE_SIZE); + start_pfn = pfn; + } else + pfn += (EHCA_SECTSIZE / PAGE_SIZE); + } + + /* Add mem found behind the hugepage(s) */ + nr_pages = pfn - start_pfn; + return ehca_update_busmap(start_pfn, nr_pages); +} + +int ehca_create_busmap(void) +{ + int ret; + + ehca_mr_len = 0; + ret = walk_memory_resource(0, 1ULL << MAX_PHYSMEM_BITS, NULL, + ehca_create_busmap_callback); + return ret; +} + +static int ehca_reg_bmap_mr_rpages(struct ehca_shca *shca, + struct ehca_mr *e_mr, + struct ehca_mr_pginfo *pginfo) +{ + int top; + u64 hret, *kpage; + + kpage = ehca_alloc_fw_ctrlblock(GFP_KERNEL); + if (!kpage) { + ehca_err(&shca->ib_device, "kpage alloc failed"); + return -ENOMEM; + } + for (top = 0; top < EHCA_MAP_ENTRIES; top++) { + if (!ehca_bmap_valid(ehca_bmap->top[top])) + continue; + hret = ehca_reg_mr_dir_sections(top, kpage, shca, e_mr, pginfo); + if ((hret != H_PAGE_REGISTERED) && (hret != H_SUCCESS)) + break; + } + + ehca_free_fw_ctrlblock(kpage); + + if (hret == H_SUCCESS) + return 0; /* Everything is fine */ + else { + ehca_err(&shca->ib_device, "ehca_reg_bmap_mr_rpages failed, " + "h_ret=%lli e_mr=%p top=%x lkey=%x " + "hca_hndl=%llx mr_hndl=%llx", hret, e_mr, top, + e_mr->ib.ib_mr.lkey, + shca->ipz_hca_handle.handle, + e_mr->ipz_mr_handle.handle); + return ehca2ib_return_code(hret); + } +} + +static u64 ehca_map_vaddr(void *caddr) +{ + int top, dir, idx; + unsigned long abs_addr, offset; + u64 entry; + + if (!ehca_bmap) + return EHCA_INVAL_ADDR; + + abs_addr = virt_to_abs(caddr); + top = ehca_calc_index(abs_addr, EHCA_TOP_INDEX_SHIFT + EHCA_SECTSHIFT); + if (!ehca_bmap_valid(ehca_bmap->top[top])) + return EHCA_INVAL_ADDR; + + dir = ehca_calc_index(abs_addr, EHCA_DIR_INDEX_SHIFT + EHCA_SECTSHIFT); + if (!ehca_bmap_valid(ehca_bmap->top[top]->dir[dir])) + return EHCA_INVAL_ADDR; + + idx = ehca_calc_index(abs_addr, EHCA_SECTSHIFT); + + entry = ehca_bmap->top[top]->dir[dir]->ent[idx]; + if (ehca_bmap_valid(entry)) { + offset = (unsigned long)caddr & (EHCA_SECTSIZE - 1); + return entry | offset; + } else + return EHCA_INVAL_ADDR; +} + +static int ehca_dma_mapping_error(struct ib_device *dev, u64 dma_addr) +{ + return dma_addr == EHCA_INVAL_ADDR; +} + +static u64 ehca_dma_map_single(struct ib_device *dev, void *cpu_addr, + size_t size, enum dma_data_direction direction) +{ + if (cpu_addr) + return ehca_map_vaddr(cpu_addr); + else + return EHCA_INVAL_ADDR; +} + +static void ehca_dma_unmap_single(struct ib_device *dev, u64 addr, size_t size, + enum dma_data_direction direction) +{ + /* This is only a stub; nothing to be done here */ +} + +static u64 ehca_dma_map_page(struct ib_device *dev, struct page *page, + unsigned long offset, size_t size, + enum dma_data_direction direction) +{ + u64 addr; + + if (offset + size > PAGE_SIZE) + return EHCA_INVAL_ADDR; + + addr = ehca_map_vaddr(page_address(page)); + if (!ehca_dma_mapping_error(dev, addr)) + addr += offset; + + return addr; +} + +static void ehca_dma_unmap_page(struct ib_device *dev, u64 addr, size_t size, + enum dma_data_direction direction) +{ + /* This is only a stub; nothing to be done here */ +} + +static int ehca_dma_map_sg(struct ib_device *dev, struct scatterlist *sgl, + int nents, enum dma_data_direction direction) +{ + struct scatterlist *sg; + int i; + + for_each_sg(sgl, sg, nents, i) { + u64 addr; + addr = ehca_map_vaddr(sg_virt(sg)); + if (ehca_dma_mapping_error(dev, addr)) + return 0; + + sg->dma_address = addr; + sg->dma_length = sg->length; + } + return nents; +} + +static void ehca_dma_unmap_sg(struct ib_device *dev, struct scatterlist *sg, + int nents, enum dma_data_direction direction) +{ + /* This is only a stub; nothing to be done here */ +} + +static u64 ehca_dma_address(struct ib_device *dev, struct scatterlist *sg) +{ + return sg->dma_address; +} + +static unsigned int ehca_dma_len(struct ib_device *dev, struct scatterlist *sg) +{ + return sg->length; +} + +static void ehca_dma_sync_single_for_cpu(struct ib_device *dev, u64 addr, + size_t size, + enum dma_data_direction dir) +{ + dma_sync_single_for_cpu(dev->dma_device, addr, size, dir); +} + +static void ehca_dma_sync_single_for_device(struct ib_device *dev, u64 addr, + size_t size, + enum dma_data_direction dir) +{ + dma_sync_single_for_device(dev->dma_device, addr, size, dir); +} + +static void *ehca_dma_alloc_coherent(struct ib_device *dev, size_t size, + u64 *dma_handle, gfp_t flag) +{ + struct page *p; + void *addr = NULL; + u64 dma_addr; + + p = alloc_pages(flag, get_order(size)); + if (p) { + addr = page_address(p); + dma_addr = ehca_map_vaddr(addr); + if (ehca_dma_mapping_error(dev, dma_addr)) { + free_pages((unsigned long)addr, get_order(size)); + return NULL; + } + if (dma_handle) + *dma_handle = dma_addr; + return addr; + } + return NULL; +} + +static void ehca_dma_free_coherent(struct ib_device *dev, size_t size, + void *cpu_addr, u64 dma_handle) +{ + if (cpu_addr && size) + free_pages((unsigned long)cpu_addr, get_order(size)); +} + + +struct ib_dma_mapping_ops ehca_dma_mapping_ops = { + .mapping_error = ehca_dma_mapping_error, + .map_single = ehca_dma_map_single, + .unmap_single = ehca_dma_unmap_single, + .map_page = ehca_dma_map_page, + .unmap_page = ehca_dma_unmap_page, + .map_sg = ehca_dma_map_sg, + .unmap_sg = ehca_dma_unmap_sg, + .dma_address = ehca_dma_address, + .dma_len = ehca_dma_len, + .sync_single_for_cpu = ehca_dma_sync_single_for_cpu, + .sync_single_for_device = ehca_dma_sync_single_for_device, + .alloc_coherent = ehca_dma_alloc_coherent, + .free_coherent = ehca_dma_free_coherent, +}; diff --git a/drivers/infiniband/hw/ehca/ehca_mrmw.h b/drivers/infiniband/hw/ehca/ehca_mrmw.h index bc8f4e31c123..50d8b51306dd 100644 --- a/drivers/infiniband/hw/ehca/ehca_mrmw.h +++ b/drivers/infiniband/hw/ehca/ehca_mrmw.h @@ -42,6 +42,11 @@ #ifndef _EHCA_MRMW_H_ #define _EHCA_MRMW_H_ +enum ehca_reg_type { + EHCA_REG_MR, + EHCA_REG_BUSMAP_MR +}; + int ehca_reg_mr(struct ehca_shca *shca, struct ehca_mr *e_mr, u64 *iova_start, @@ -50,7 +55,8 @@ int ehca_reg_mr(struct ehca_shca *shca, struct ehca_pd *e_pd, struct ehca_mr_pginfo *pginfo, u32 *lkey, - u32 *rkey); + u32 *rkey, + enum ehca_reg_type reg_type); int ehca_reg_mr_rpages(struct ehca_shca *shca, struct ehca_mr *e_mr, @@ -118,4 +124,9 @@ void ehca_mrmw_reverse_map_acl(const u32 *hipz_acl, void ehca_mr_deletenew(struct ehca_mr *mr); +int ehca_create_busmap(void); + +void ehca_destroy_busmap(void); + +extern struct ib_dma_mapping_ops ehca_dma_mapping_ops; #endif /*_EHCA_MRMW_H_*/ diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c index 00c108159714..0338f1fabe8a 100644 --- a/drivers/infiniband/hw/ehca/ehca_qp.c +++ b/drivers/infiniband/hw/ehca/ehca_qp.c @@ -461,7 +461,7 @@ static struct ehca_qp *internal_create_qp( ib_device); struct ib_ucontext *context = NULL; u64 h_ret; - int is_llqp = 0, has_srq = 0; + int is_llqp = 0, has_srq = 0, is_user = 0; int qp_type, max_send_sge, max_recv_sge, ret; /* h_call's out parameters */ @@ -609,9 +609,6 @@ static struct ehca_qp *internal_create_qp( } } - if (pd->uobject && udata) - context = pd->uobject->context; - my_qp = kmem_cache_zalloc(qp_cache, GFP_KERNEL); if (!my_qp) { ehca_err(pd->device, "pd=%p not enough memory to alloc qp", pd); @@ -619,6 +616,11 @@ static struct ehca_qp *internal_create_qp( return ERR_PTR(-ENOMEM); } + if (pd->uobject && udata) { + is_user = 1; + context = pd->uobject->context; + } + atomic_set(&my_qp->nr_events, 0); init_waitqueue_head(&my_qp->wait_completion); spin_lock_init(&my_qp->spinlock_s); @@ -707,7 +709,7 @@ static struct ehca_qp *internal_create_qp( (parms.squeue.is_small || parms.rqueue.is_small); } - h_ret = hipz_h_alloc_resource_qp(shca->ipz_hca_handle, &parms); + h_ret = hipz_h_alloc_resource_qp(shca->ipz_hca_handle, &parms, is_user); if (h_ret != H_SUCCESS) { ehca_err(pd->device, "h_alloc_resource_qp() failed h_ret=%lli", h_ret); @@ -769,18 +771,20 @@ static struct ehca_qp *internal_create_qp( goto create_qp_exit2; } - my_qp->sq_map.entries = my_qp->ipz_squeue.queue_length / - my_qp->ipz_squeue.qe_size; - my_qp->sq_map.map = vmalloc(my_qp->sq_map.entries * - sizeof(struct ehca_qmap_entry)); - if (!my_qp->sq_map.map) { - ehca_err(pd->device, "Couldn't allocate squeue " - "map ret=%i", ret); - goto create_qp_exit3; + if (!is_user) { + my_qp->sq_map.entries = my_qp->ipz_squeue.queue_length / + my_qp->ipz_squeue.qe_size; + my_qp->sq_map.map = vmalloc(my_qp->sq_map.entries * + sizeof(struct ehca_qmap_entry)); + if (!my_qp->sq_map.map) { + ehca_err(pd->device, "Couldn't allocate squeue " + "map ret=%i", ret); + goto create_qp_exit3; + } + INIT_LIST_HEAD(&my_qp->sq_err_node); + /* to avoid the generation of bogus flush CQEs */ + reset_queue_map(&my_qp->sq_map); } - INIT_LIST_HEAD(&my_qp->sq_err_node); - /* to avoid the generation of bogus flush CQEs */ - reset_queue_map(&my_qp->sq_map); } if (HAS_RQ(my_qp)) { @@ -792,20 +796,21 @@ static struct ehca_qp *internal_create_qp( "and pages ret=%i", ret); goto create_qp_exit4; } - - my_qp->rq_map.entries = my_qp->ipz_rqueue.queue_length / - my_qp->ipz_rqueue.qe_size; - my_qp->rq_map.map = vmalloc(my_qp->rq_map.entries * - sizeof(struct ehca_qmap_entry)); - if (!my_qp->rq_map.map) { - ehca_err(pd->device, "Couldn't allocate squeue " - "map ret=%i", ret); - goto create_qp_exit5; + if (!is_user) { + my_qp->rq_map.entries = my_qp->ipz_rqueue.queue_length / + my_qp->ipz_rqueue.qe_size; + my_qp->rq_map.map = vmalloc(my_qp->rq_map.entries * + sizeof(struct ehca_qmap_entry)); + if (!my_qp->rq_map.map) { + ehca_err(pd->device, "Couldn't allocate squeue " + "map ret=%i", ret); + goto create_qp_exit5; + } + INIT_LIST_HEAD(&my_qp->rq_err_node); + /* to avoid the generation of bogus flush CQEs */ + reset_queue_map(&my_qp->rq_map); } - INIT_LIST_HEAD(&my_qp->rq_err_node); - /* to avoid the generation of bogus flush CQEs */ - reset_queue_map(&my_qp->rq_map); - } else if (init_attr->srq) { + } else if (init_attr->srq && !is_user) { /* this is a base QP, use the queue map of the SRQ */ my_qp->rq_map = my_srq->rq_map; INIT_LIST_HEAD(&my_qp->rq_err_node); @@ -918,7 +923,7 @@ create_qp_exit7: kfree(my_qp->mod_qp_parm); create_qp_exit6: - if (HAS_RQ(my_qp)) + if (HAS_RQ(my_qp) && !is_user) vfree(my_qp->rq_map.map); create_qp_exit5: @@ -926,7 +931,7 @@ create_qp_exit5: ipz_queue_dtor(my_pd, &my_qp->ipz_rqueue); create_qp_exit4: - if (HAS_SQ(my_qp)) + if (HAS_SQ(my_qp) && !is_user) vfree(my_qp->sq_map.map); create_qp_exit3: @@ -1244,6 +1249,7 @@ static int internal_modify_qp(struct ib_qp *ibqp, u64 update_mask; u64 h_ret; int bad_wqe_cnt = 0; + int is_user = 0; int squeue_locked = 0; unsigned long flags = 0; @@ -1266,6 +1272,8 @@ static int internal_modify_qp(struct ib_qp *ibqp, ret = ehca2ib_return_code(h_ret); goto modify_qp_exit1; } + if (ibqp->uobject) + is_user = 1; qp_cur_state = ehca2ib_qp_state(mqpcb->qp_state); @@ -1728,7 +1736,8 @@ static int internal_modify_qp(struct ib_qp *ibqp, goto modify_qp_exit2; } } - if ((qp_new_state == IB_QPS_ERR) && (qp_cur_state != IB_QPS_ERR)) { + if ((qp_new_state == IB_QPS_ERR) && (qp_cur_state != IB_QPS_ERR) + && !is_user) { ret = check_for_left_cqes(my_qp, shca); if (ret) goto modify_qp_exit2; @@ -1738,16 +1747,17 @@ static int internal_modify_qp(struct ib_qp *ibqp, ipz_qeit_reset(&my_qp->ipz_rqueue); ipz_qeit_reset(&my_qp->ipz_squeue); - if (qp_cur_state == IB_QPS_ERR) { + if (qp_cur_state == IB_QPS_ERR && !is_user) { del_from_err_list(my_qp->send_cq, &my_qp->sq_err_node); if (HAS_RQ(my_qp)) del_from_err_list(my_qp->recv_cq, &my_qp->rq_err_node); } - reset_queue_map(&my_qp->sq_map); + if (!is_user) + reset_queue_map(&my_qp->sq_map); - if (HAS_RQ(my_qp)) + if (HAS_RQ(my_qp) && !is_user) reset_queue_map(&my_qp->rq_map); } @@ -1952,19 +1962,13 @@ int ehca_query_qp(struct ib_qp *qp, qp_attr->cap.max_inline_data = my_qp->sq_max_inline_data_size; qp_attr->dest_qp_num = qpcb->dest_qp_nr; - qp_attr->pkey_index = - EHCA_BMASK_GET(MQPCB_PRIM_P_KEY_IDX, qpcb->prim_p_key_idx); - - qp_attr->port_num = - EHCA_BMASK_GET(MQPCB_PRIM_PHYS_PORT, qpcb->prim_phys_port); - + qp_attr->pkey_index = qpcb->prim_p_key_idx; + qp_attr->port_num = qpcb->prim_phys_port; qp_attr->timeout = qpcb->timeout; qp_attr->retry_cnt = qpcb->retry_count; qp_attr->rnr_retry = qpcb->rnr_retry_count; - qp_attr->alt_pkey_index = - EHCA_BMASK_GET(MQPCB_PRIM_P_KEY_IDX, qpcb->alt_p_key_idx); - + qp_attr->alt_pkey_index = qpcb->alt_p_key_idx; qp_attr->alt_port_num = qpcb->alt_phys_port; qp_attr->alt_timeout = qpcb->timeout_al; @@ -2051,8 +2055,7 @@ int ehca_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr, update_mask |= EHCA_BMASK_SET(MQPCB_MASK_CURR_SRQ_LIMIT, 1) | EHCA_BMASK_SET(MQPCB_MASK_QP_AFF_ASYN_EV_LOG_REG, 1); - mqpcb->curr_srq_limit = - EHCA_BMASK_SET(MQPCB_CURR_SRQ_LIMIT, attr->srq_limit); + mqpcb->curr_srq_limit = attr->srq_limit; mqpcb->qp_aff_asyn_ev_log_reg = EHCA_BMASK_SET(QPX_AAELOG_RESET_SRQ_LIMIT, 1); } @@ -2115,8 +2118,7 @@ int ehca_query_srq(struct ib_srq *srq, struct ib_srq_attr *srq_attr) srq_attr->max_wr = qpcb->max_nr_outst_recv_wr - 1; srq_attr->max_sge = 3; - srq_attr->srq_limit = EHCA_BMASK_GET( - MQPCB_CURR_SRQ_LIMIT, qpcb->curr_srq_limit); + srq_attr->srq_limit = qpcb->curr_srq_limit; if (ehca_debug_level >= 2) ehca_dmp(qpcb, 4*70, "qp_num=%x", my_qp->real_qp_num); @@ -2138,10 +2140,12 @@ static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp, int ret; u64 h_ret; u8 port_num; + int is_user = 0; enum ib_qp_type qp_type; unsigned long flags; if (uobject) { + is_user = 1; if (my_qp->mm_count_galpa || my_qp->mm_count_rqueue || my_qp->mm_count_squeue) { ehca_err(dev, "Resources still referenced in " @@ -2168,10 +2172,10 @@ static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp, * SRQs will never get into an error list and do not have a recv_cq, * so we need to skip them here. */ - if (HAS_RQ(my_qp) && !IS_SRQ(my_qp)) + if (HAS_RQ(my_qp) && !IS_SRQ(my_qp) && !is_user) del_from_err_list(my_qp->recv_cq, &my_qp->rq_err_node); - if (HAS_SQ(my_qp)) + if (HAS_SQ(my_qp) && !is_user) del_from_err_list(my_qp->send_cq, &my_qp->sq_err_node); /* now wait until all pending events have completed */ @@ -2209,13 +2213,13 @@ static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp, if (HAS_RQ(my_qp)) { ipz_queue_dtor(my_pd, &my_qp->ipz_rqueue); - - vfree(my_qp->rq_map.map); + if (!is_user) + vfree(my_qp->rq_map.map); } if (HAS_SQ(my_qp)) { ipz_queue_dtor(my_pd, &my_qp->ipz_squeue); - - vfree(my_qp->sq_map.map); + if (!is_user) + vfree(my_qp->sq_map.map); } kmem_cache_free(qp_cache, my_qp); atomic_dec(&shca->num_qps); diff --git a/drivers/infiniband/hw/ehca/hcp_if.c b/drivers/infiniband/hw/ehca/hcp_if.c index d0ab0c0d5e91..4d5dc3304d42 100644 --- a/drivers/infiniband/hw/ehca/hcp_if.c +++ b/drivers/infiniband/hw/ehca/hcp_if.c @@ -284,7 +284,7 @@ u64 hipz_h_alloc_resource_cq(const struct ipz_adapter_handle adapter_handle, param->act_pages = (u32)outs[4]; if (ret == H_SUCCESS) - hcp_galpas_ctor(&cq->galpas, outs[5], outs[6]); + hcp_galpas_ctor(&cq->galpas, 0, outs[5], outs[6]); if (ret == H_NOT_ENOUGH_RESOURCES) ehca_gen_err("Not enough resources. ret=%lli", ret); @@ -293,7 +293,7 @@ u64 hipz_h_alloc_resource_cq(const struct ipz_adapter_handle adapter_handle, } u64 hipz_h_alloc_resource_qp(const struct ipz_adapter_handle adapter_handle, - struct ehca_alloc_qp_parms *parms) + struct ehca_alloc_qp_parms *parms, int is_user) { u64 ret; u64 allocate_controls, max_r10_reg, r11, r12; @@ -359,7 +359,7 @@ u64 hipz_h_alloc_resource_qp(const struct ipz_adapter_handle adapter_handle, (u32)EHCA_BMASK_GET(H_ALL_RES_QP_RQUEUE_SIZE_PAGES, outs[4]); if (ret == H_SUCCESS) - hcp_galpas_ctor(&parms->galpas, outs[6], outs[6]); + hcp_galpas_ctor(&parms->galpas, is_user, outs[6], outs[6]); if (ret == H_NOT_ENOUGH_RESOURCES) ehca_gen_err("Not enough resources. ret=%lli", ret); diff --git a/drivers/infiniband/hw/ehca/hcp_if.h b/drivers/infiniband/hw/ehca/hcp_if.h index 2c3c6e0ea5c2..39c1c3618ec7 100644 --- a/drivers/infiniband/hw/ehca/hcp_if.h +++ b/drivers/infiniband/hw/ehca/hcp_if.h @@ -78,7 +78,7 @@ u64 hipz_h_alloc_resource_cq(const struct ipz_adapter_handle adapter_handle, * initialize resources, create empty QPPTs (2 rings). */ u64 hipz_h_alloc_resource_qp(const struct ipz_adapter_handle adapter_handle, - struct ehca_alloc_qp_parms *parms); + struct ehca_alloc_qp_parms *parms, int is_user); u64 hipz_h_query_port(const struct ipz_adapter_handle adapter_handle, const u8 port_id, diff --git a/drivers/infiniband/hw/ehca/hcp_phyp.c b/drivers/infiniband/hw/ehca/hcp_phyp.c index 214821095cb1..b3e0e72e8a73 100644 --- a/drivers/infiniband/hw/ehca/hcp_phyp.c +++ b/drivers/infiniband/hw/ehca/hcp_phyp.c @@ -54,12 +54,15 @@ int hcall_unmap_page(u64 mapaddr) return 0; } -int hcp_galpas_ctor(struct h_galpas *galpas, +int hcp_galpas_ctor(struct h_galpas *galpas, int is_user, u64 paddr_kernel, u64 paddr_user) { - int ret = hcall_map_page(paddr_kernel, &galpas->kernel.fw_handle); - if (ret) - return ret; + if (!is_user) { + int ret = hcall_map_page(paddr_kernel, &galpas->kernel.fw_handle); + if (ret) + return ret; + } else + galpas->kernel.fw_handle = 0; galpas->user.fw_handle = paddr_user; diff --git a/drivers/infiniband/hw/ehca/hcp_phyp.h b/drivers/infiniband/hw/ehca/hcp_phyp.h index 5305c2a3ed94..204227d5303a 100644 --- a/drivers/infiniband/hw/ehca/hcp_phyp.h +++ b/drivers/infiniband/hw/ehca/hcp_phyp.h @@ -78,7 +78,7 @@ static inline void hipz_galpa_store(struct h_galpa galpa, u32 offset, u64 value) *(volatile u64 __force *)addr = value; } -int hcp_galpas_ctor(struct h_galpas *galpas, +int hcp_galpas_ctor(struct h_galpas *galpas, int is_user, u64 paddr_kernel, u64 paddr_user); int hcp_galpas_dtor(struct h_galpas *galpas); diff --git a/drivers/infiniband/hw/ehca/ipz_pt_fn.c b/drivers/infiniband/hw/ehca/ipz_pt_fn.c index c3a328465431..1227c593627a 100644 --- a/drivers/infiniband/hw/ehca/ipz_pt_fn.c +++ b/drivers/infiniband/hw/ehca/ipz_pt_fn.c @@ -220,10 +220,13 @@ int ipz_queue_ctor(struct ehca_pd *pd, struct ipz_queue *queue, queue->small_page = NULL; /* allocate queue page pointers */ - queue->queue_pages = vmalloc(nr_of_pages * sizeof(void *)); + queue->queue_pages = kmalloc(nr_of_pages * sizeof(void *), GFP_KERNEL); if (!queue->queue_pages) { - ehca_gen_err("Couldn't allocate queue page list"); - return 0; + queue->queue_pages = vmalloc(nr_of_pages * sizeof(void *)); + if (!queue->queue_pages) { + ehca_gen_err("Couldn't allocate queue page list"); + return 0; + } } memset(queue->queue_pages, 0, nr_of_pages * sizeof(void *)); @@ -240,7 +243,10 @@ int ipz_queue_ctor(struct ehca_pd *pd, struct ipz_queue *queue, ipz_queue_ctor_exit0: ehca_gen_err("Couldn't alloc pages queue=%p " "nr_of_pages=%x", queue, nr_of_pages); - vfree(queue->queue_pages); + if (is_vmalloc_addr(queue->queue_pages)) + vfree(queue->queue_pages); + else + kfree(queue->queue_pages); return 0; } @@ -262,7 +268,10 @@ int ipz_queue_dtor(struct ehca_pd *pd, struct ipz_queue *queue) free_page((unsigned long)queue->queue_pages[i]); } - vfree(queue->queue_pages); + if (is_vmalloc_addr(queue->queue_pages)) + vfree(queue->queue_pages); + else + kfree(queue->queue_pages); return 1; } diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c index 20724aee76f4..c4a02648c8af 100644 --- a/drivers/infiniband/hw/mlx4/qp.c +++ b/drivers/infiniband/hw/mlx4/qp.c @@ -1585,12 +1585,16 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, break; case IB_WR_LOCAL_INV: + ctrl->srcrb_flags |= + cpu_to_be32(MLX4_WQE_CTRL_STRONG_ORDER); set_local_inv_seg(wqe, wr->ex.invalidate_rkey); wqe += sizeof (struct mlx4_wqe_local_inval_seg); size += sizeof (struct mlx4_wqe_local_inval_seg) / 16; break; case IB_WR_FAST_REG_MR: + ctrl->srcrb_flags |= + cpu_to_be32(MLX4_WQE_CTRL_STRONG_ORDER); set_fmr_seg(wqe, wr); wqe += sizeof (struct mlx4_wqe_fmr_seg); size += sizeof (struct mlx4_wqe_fmr_seg) / 16; diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.c b/drivers/infiniband/hw/mthca/mthca_cmd.c index 6d55f9d748f6..8c2ed994d540 100644 --- a/drivers/infiniband/hw/mthca/mthca_cmd.c +++ b/drivers/infiniband/hw/mthca/mthca_cmd.c @@ -1059,7 +1059,7 @@ int mthca_QUERY_DEV_LIM(struct mthca_dev *dev, MTHCA_GET(field, outbox, QUERY_DEV_LIM_RSVD_MTT_OFFSET); if (mthca_is_memfree(dev)) dev_lim->reserved_mtts = ALIGN((1 << (field >> 4)) * sizeof(u64), - MTHCA_MTT_SEG_SIZE) / MTHCA_MTT_SEG_SIZE; + dev->limits.mtt_seg_size) / dev->limits.mtt_seg_size; else dev_lim->reserved_mtts = 1 << (field >> 4); MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_MRW_SZ_OFFSET); diff --git a/drivers/infiniband/hw/mthca/mthca_dev.h b/drivers/infiniband/hw/mthca/mthca_dev.h index 252590116df5..9ef611f6dd36 100644 --- a/drivers/infiniband/hw/mthca/mthca_dev.h +++ b/drivers/infiniband/hw/mthca/mthca_dev.h @@ -159,6 +159,7 @@ struct mthca_limits { int reserved_eqs; int num_mpts; int num_mtt_segs; + int mtt_seg_size; int fmr_reserved_mtts; int reserved_mtts; int reserved_mrws; diff --git a/drivers/infiniband/hw/mthca/mthca_eq.c b/drivers/infiniband/hw/mthca/mthca_eq.c index 28f0e0c40d7d..90e4e450a120 100644 --- a/drivers/infiniband/hw/mthca/mthca_eq.c +++ b/drivers/infiniband/hw/mthca/mthca_eq.c @@ -641,9 +641,11 @@ static void mthca_free_irqs(struct mthca_dev *dev) if (dev->eq_table.have_irq) free_irq(dev->pdev->irq, dev); for (i = 0; i < MTHCA_NUM_EQ; ++i) - if (dev->eq_table.eq[i].have_irq) + if (dev->eq_table.eq[i].have_irq) { free_irq(dev->eq_table.eq[i].msi_x_vector, dev->eq_table.eq + i); + dev->eq_table.eq[i].have_irq = 0; + } } static int mthca_map_reg(struct mthca_dev *dev, diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c index 1d83cf7caf38..13da9f1d24c0 100644 --- a/drivers/infiniband/hw/mthca/mthca_main.c +++ b/drivers/infiniband/hw/mthca/mthca_main.c @@ -125,6 +125,10 @@ module_param_named(fmr_reserved_mtts, hca_profile.fmr_reserved_mtts, int, 0444); MODULE_PARM_DESC(fmr_reserved_mtts, "number of memory translation table segments reserved for FMR"); +static int log_mtts_per_seg = ilog2(MTHCA_MTT_SEG_SIZE / 8); +module_param_named(log_mtts_per_seg, log_mtts_per_seg, int, 0444); +MODULE_PARM_DESC(log_mtts_per_seg, "Log2 number of MTT entries per segment (1-5)"); + static char mthca_version[] __devinitdata = DRV_NAME ": Mellanox InfiniBand HCA driver v" DRV_VERSION " (" DRV_RELDATE ")\n"; @@ -162,6 +166,7 @@ static int mthca_dev_lim(struct mthca_dev *mdev, struct mthca_dev_lim *dev_lim) int err; u8 status; + mdev->limits.mtt_seg_size = (1 << log_mtts_per_seg) * 8; err = mthca_QUERY_DEV_LIM(mdev, dev_lim, &status); if (err) { mthca_err(mdev, "QUERY_DEV_LIM command failed, aborting.\n"); @@ -460,11 +465,11 @@ static int mthca_init_icm(struct mthca_dev *mdev, } /* CPU writes to non-reserved MTTs, while HCA might DMA to reserved mtts */ - mdev->limits.reserved_mtts = ALIGN(mdev->limits.reserved_mtts * MTHCA_MTT_SEG_SIZE, - dma_get_cache_alignment()) / MTHCA_MTT_SEG_SIZE; + mdev->limits.reserved_mtts = ALIGN(mdev->limits.reserved_mtts * mdev->limits.mtt_seg_size, + dma_get_cache_alignment()) / mdev->limits.mtt_seg_size; mdev->mr_table.mtt_table = mthca_alloc_icm_table(mdev, init_hca->mtt_base, - MTHCA_MTT_SEG_SIZE, + mdev->limits.mtt_seg_size, mdev->limits.num_mtt_segs, mdev->limits.reserved_mtts, 1, 0); @@ -1315,6 +1320,12 @@ static void __init mthca_validate_profile(void) printk(KERN_WARNING PFX "Corrected fmr_reserved_mtts to %d.\n", hca_profile.fmr_reserved_mtts); } + + if ((log_mtts_per_seg < 1) || (log_mtts_per_seg > 5)) { + printk(KERN_WARNING PFX "bad log_mtts_per_seg (%d). Using default - %d\n", + log_mtts_per_seg, ilog2(MTHCA_MTT_SEG_SIZE / 8)); + log_mtts_per_seg = ilog2(MTHCA_MTT_SEG_SIZE / 8); + } } static int __init mthca_init(void) diff --git a/drivers/infiniband/hw/mthca/mthca_mr.c b/drivers/infiniband/hw/mthca/mthca_mr.c index 882e6b735915..065b20899876 100644 --- a/drivers/infiniband/hw/mthca/mthca_mr.c +++ b/drivers/infiniband/hw/mthca/mthca_mr.c @@ -220,7 +220,7 @@ static struct mthca_mtt *__mthca_alloc_mtt(struct mthca_dev *dev, int size, mtt->buddy = buddy; mtt->order = 0; - for (i = MTHCA_MTT_SEG_SIZE / 8; i < size; i <<= 1) + for (i = dev->limits.mtt_seg_size / 8; i < size; i <<= 1) ++mtt->order; mtt->first_seg = mthca_alloc_mtt_range(dev, mtt->order, buddy); @@ -267,7 +267,7 @@ static int __mthca_write_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt, while (list_len > 0) { mtt_entry[0] = cpu_to_be64(dev->mr_table.mtt_base + - mtt->first_seg * MTHCA_MTT_SEG_SIZE + + mtt->first_seg * dev->limits.mtt_seg_size + start_index * 8); mtt_entry[1] = 0; for (i = 0; i < list_len && i < MTHCA_MAILBOX_SIZE / 8 - 2; ++i) @@ -326,7 +326,7 @@ static void mthca_tavor_write_mtt_seg(struct mthca_dev *dev, u64 __iomem *mtts; int i; - mtts = dev->mr_table.tavor_fmr.mtt_base + mtt->first_seg * MTHCA_MTT_SEG_SIZE + + mtts = dev->mr_table.tavor_fmr.mtt_base + mtt->first_seg * dev->limits.mtt_seg_size + start_index * sizeof (u64); for (i = 0; i < list_len; ++i) mthca_write64_raw(cpu_to_be64(buffer_list[i] | MTHCA_MTT_FLAG_PRESENT), @@ -345,17 +345,21 @@ static void mthca_arbel_write_mtt_seg(struct mthca_dev *dev, /* For Arbel, all MTTs must fit in the same page. */ BUG_ON(s / PAGE_SIZE != (s + list_len * sizeof(u64) - 1) / PAGE_SIZE); /* Require full segments */ - BUG_ON(s % MTHCA_MTT_SEG_SIZE); + BUG_ON(s % dev->limits.mtt_seg_size); mtts = mthca_table_find(dev->mr_table.mtt_table, mtt->first_seg + - s / MTHCA_MTT_SEG_SIZE, &dma_handle); + s / dev->limits.mtt_seg_size, &dma_handle); BUG_ON(!mtts); + dma_sync_single_for_cpu(&dev->pdev->dev, dma_handle, + list_len * sizeof (u64), DMA_TO_DEVICE); + for (i = 0; i < list_len; ++i) mtts[i] = cpu_to_be64(buffer_list[i] | MTHCA_MTT_FLAG_PRESENT); - dma_sync_single(&dev->pdev->dev, dma_handle, list_len * sizeof (u64), DMA_TO_DEVICE); + dma_sync_single_for_device(&dev->pdev->dev, dma_handle, + list_len * sizeof (u64), DMA_TO_DEVICE); } int mthca_write_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt, @@ -479,7 +483,7 @@ int mthca_mr_alloc(struct mthca_dev *dev, u32 pd, int buffer_size_shift, if (mr->mtt) mpt_entry->mtt_seg = cpu_to_be64(dev->mr_table.mtt_base + - mr->mtt->first_seg * MTHCA_MTT_SEG_SIZE); + mr->mtt->first_seg * dev->limits.mtt_seg_size); if (0) { mthca_dbg(dev, "Dumping MPT entry %08x:\n", mr->ibmr.lkey); @@ -626,7 +630,7 @@ int mthca_fmr_alloc(struct mthca_dev *dev, u32 pd, goto err_out_table; } - mtt_seg = mr->mtt->first_seg * MTHCA_MTT_SEG_SIZE; + mtt_seg = mr->mtt->first_seg * dev->limits.mtt_seg_size; if (mthca_is_memfree(dev)) { mr->mem.arbel.mtts = mthca_table_find(dev->mr_table.mtt_table, @@ -803,12 +807,15 @@ int mthca_arbel_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list, wmb(); + dma_sync_single_for_cpu(&dev->pdev->dev, fmr->mem.arbel.dma_handle, + list_len * sizeof(u64), DMA_TO_DEVICE); + for (i = 0; i < list_len; ++i) fmr->mem.arbel.mtts[i] = cpu_to_be64(page_list[i] | MTHCA_MTT_FLAG_PRESENT); - dma_sync_single(&dev->pdev->dev, fmr->mem.arbel.dma_handle, - list_len * sizeof(u64), DMA_TO_DEVICE); + dma_sync_single_for_device(&dev->pdev->dev, fmr->mem.arbel.dma_handle, + list_len * sizeof(u64), DMA_TO_DEVICE); fmr->mem.arbel.mpt->key = cpu_to_be32(key); fmr->mem.arbel.mpt->lkey = cpu_to_be32(key); @@ -908,7 +915,7 @@ int mthca_init_mr_table(struct mthca_dev *dev) dev->mr_table.mtt_base); dev->mr_table.tavor_fmr.mtt_base = - ioremap(addr, mtts * MTHCA_MTT_SEG_SIZE); + ioremap(addr, mtts * dev->limits.mtt_seg_size); if (!dev->mr_table.tavor_fmr.mtt_base) { mthca_warn(dev, "MTT ioremap for FMR failed.\n"); err = -ENOMEM; diff --git a/drivers/infiniband/hw/mthca/mthca_profile.c b/drivers/infiniband/hw/mthca/mthca_profile.c index d168c2540611..8edb28a9a0e7 100644 --- a/drivers/infiniband/hw/mthca/mthca_profile.c +++ b/drivers/infiniband/hw/mthca/mthca_profile.c @@ -94,7 +94,7 @@ s64 mthca_make_profile(struct mthca_dev *dev, profile[MTHCA_RES_RDB].size = MTHCA_RDB_ENTRY_SIZE; profile[MTHCA_RES_MCG].size = MTHCA_MGM_ENTRY_SIZE; profile[MTHCA_RES_MPT].size = dev_lim->mpt_entry_sz; - profile[MTHCA_RES_MTT].size = MTHCA_MTT_SEG_SIZE; + profile[MTHCA_RES_MTT].size = dev->limits.mtt_seg_size; profile[MTHCA_RES_UAR].size = dev_lim->uar_scratch_entry_sz; profile[MTHCA_RES_UDAV].size = MTHCA_AV_SIZE; profile[MTHCA_RES_UARC].size = request->uarc_size; @@ -232,7 +232,7 @@ s64 mthca_make_profile(struct mthca_dev *dev, dev->limits.num_mtt_segs = profile[i].num; dev->mr_table.mtt_base = profile[i].start; init_hca->mtt_base = profile[i].start; - init_hca->mtt_seg_sz = ffs(MTHCA_MTT_SEG_SIZE) - 7; + init_hca->mtt_seg_sz = ffs(dev->limits.mtt_seg_size) - 7; break; case MTHCA_RES_UAR: dev->limits.num_uars = profile[i].num; diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c index 11c7d6642014..114b802771ad 100644 --- a/drivers/infiniband/hw/nes/nes_cm.c +++ b/drivers/infiniband/hw/nes/nes_cm.c @@ -472,6 +472,7 @@ int schedule_nes_timer(struct nes_cm_node *cm_node, struct sk_buff *skb, static void nes_retrans_expired(struct nes_cm_node *cm_node) { + struct iw_cm_id *cm_id = cm_node->cm_id; switch (cm_node->state) { case NES_CM_STATE_SYN_RCVD: case NES_CM_STATE_CLOSING: @@ -479,7 +480,9 @@ static void nes_retrans_expired(struct nes_cm_node *cm_node) break; case NES_CM_STATE_LAST_ACK: case NES_CM_STATE_FIN_WAIT1: - case NES_CM_STATE_MPAREJ_RCVD: + if (cm_node->cm_id) + cm_id->rem_ref(cm_id); + cm_node->state = NES_CM_STATE_CLOSED; send_reset(cm_node, NULL); break; default: @@ -1406,6 +1409,7 @@ static void handle_rst_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb, case NES_CM_STATE_CLOSED: drop_packet(skb); break; + case NES_CM_STATE_FIN_WAIT1: case NES_CM_STATE_LAST_ACK: cm_node->cm_id->rem_ref(cm_node->cm_id); case NES_CM_STATE_TIME_WAIT: @@ -1413,8 +1417,6 @@ static void handle_rst_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb, rem_ref_cm_node(cm_node->cm_core, cm_node); drop_packet(skb); break; - case NES_CM_STATE_FIN_WAIT1: - nes_debug(NES_DBG_CM, "Bad state %s[%u]\n", __func__, __LINE__); default: drop_packet(skb); break; diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c index b832a7b814a2..4a84d02ece06 100644 --- a/drivers/infiniband/hw/nes/nes_hw.c +++ b/drivers/infiniband/hw/nes/nes_hw.c @@ -667,7 +667,7 @@ static unsigned int nes_reset_adapter_ne020(struct nes_device *nesdev, u8 *OneG_ i = 0; while (((nes_read32(nesdev->regs+NES_SOFTWARE_RESET) & 0x00000040) == 0) && i++ < 10000) mdelay(1); - if (i >= 10000) { + if (i > 10000) { nes_debug(NES_DBG_INIT, "Did not see full soft reset done.\n"); return 0; } @@ -675,7 +675,7 @@ static unsigned int nes_reset_adapter_ne020(struct nes_device *nesdev, u8 *OneG_ i = 0; while ((nes_read_indexed(nesdev, NES_IDX_INT_CPU_STATUS) != 0x80) && i++ < 10000) mdelay(1); - if (i >= 10000) { + if (i > 10000) { printk(KERN_ERR PFX "Internal CPU not ready, status = %02X\n", nes_read_indexed(nesdev, NES_IDX_INT_CPU_STATUS)); return 0; @@ -701,7 +701,7 @@ static unsigned int nes_reset_adapter_ne020(struct nes_device *nesdev, u8 *OneG_ i = 0; while (((nes_read32(nesdev->regs+NES_SOFTWARE_RESET) & 0x00000040) == 0) && i++ < 10000) mdelay(1); - if (i >= 10000) { + if (i > 10000) { nes_debug(NES_DBG_INIT, "Did not see port soft reset done.\n"); return 0; } @@ -711,7 +711,7 @@ static unsigned int nes_reset_adapter_ne020(struct nes_device *nesdev, u8 *OneG_ while (((u32temp = (nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS0) & 0x0000000f)) != 0x0000000f) && i++ < 5000) mdelay(1); - if (i >= 5000) { + if (i > 5000) { nes_debug(NES_DBG_INIT, "Serdes 0 not ready, status=%x\n", u32temp); return 0; } @@ -722,7 +722,7 @@ static unsigned int nes_reset_adapter_ne020(struct nes_device *nesdev, u8 *OneG_ while (((u32temp = (nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS1) & 0x0000000f)) != 0x0000000f) && i++ < 5000) mdelay(1); - if (i >= 5000) { + if (i > 5000) { nes_debug(NES_DBG_INIT, "Serdes 1 not ready, status=%x\n", u32temp); return 0; } @@ -792,7 +792,7 @@ static int nes_init_serdes(struct nes_device *nesdev, u8 hw_rev, u8 port_count, while (((u32temp = (nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS0) & 0x0000000f)) != 0x0000000f) && i++ < 5000) mdelay(1); - if (i >= 5000) { + if (i > 5000) { nes_debug(NES_DBG_PHY, "Init: serdes 0 not ready, status=%x\n", u32temp); return 1; } @@ -815,7 +815,7 @@ static int nes_init_serdes(struct nes_device *nesdev, u8 hw_rev, u8 port_count, while (((u32temp = (nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS1) & 0x0000000f)) != 0x0000000f) && (i++ < 5000)) mdelay(1); - if (i >= 5000) { + if (i > 5000) { printk("%s: Init: serdes 1 not ready, status=%x\n", __func__, u32temp); /* return 1; */ } diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c index 64d5cfd8f380..21e0fd336cf7 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.c +++ b/drivers/infiniband/hw/nes/nes_verbs.c @@ -654,7 +654,7 @@ static int nes_query_device(struct ib_device *ibdev, struct ib_device_attr *prop default: props->max_qp_rd_atom = 0; } - props->max_qp_init_rd_atom = props->max_qp_wr; + props->max_qp_init_rd_atom = props->max_qp_rd_atom; props->atomic_cap = IB_ATOMIC_NONE; props->max_map_per_fmr = 1; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index 47d588ba2a7f..181b1f32325f 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -1394,8 +1394,8 @@ void ipoib_cm_skb_too_long(struct net_device *dev, struct sk_buff *skb, struct ipoib_dev_priv *priv = netdev_priv(dev); int e = skb_queue_empty(&priv->cm.skb_queue); - if (skb->dst) - skb->dst->ops->update_pmtu(skb->dst, mtu); + if (skb_dst(skb)) + skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu); skb_queue_tail(&priv->cm.skb_queue, skb); if (e) @@ -1455,13 +1455,15 @@ static ssize_t set_mode(struct device *d, struct device_attribute *attr, struct net_device *dev = to_net_dev(d); struct ipoib_dev_priv *priv = netdev_priv(dev); + if (!rtnl_trylock()) + return restart_syscall(); + /* flush paths if we switch modes so that connections are restarted */ if (IPOIB_CM_SUPPORTED(dev->dev_addr) && !strcmp(buf, "connected\n")) { set_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags); ipoib_warn(priv, "enabling connected mode " "will cause multicast packet drops\n"); - rtnl_lock(); dev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_TSO); rtnl_unlock(); priv->tx_wr.send_flags &= ~IB_SEND_IP_CSUM; @@ -1473,7 +1475,6 @@ static ssize_t set_mode(struct device *d, struct device_attribute *attr, if (!strcmp(buf, "datagram\n")) { clear_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags); - rtnl_lock(); if (test_bit(IPOIB_FLAG_CSUM, &priv->flags)) { dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; if (priv->hca_caps & IB_DEVICE_UD_TSO) @@ -1485,6 +1486,7 @@ static ssize_t set_mode(struct device *d, struct device_attribute *attr, return count; } + rtnl_unlock(); return -EINVAL; } diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index ab2c192c76bc..e319d91f60a6 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -561,7 +561,7 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev) struct ipoib_neigh *neigh; unsigned long flags; - neigh = ipoib_neigh_alloc(skb->dst->neighbour, skb->dev); + neigh = ipoib_neigh_alloc(skb_dst(skb)->neighbour, skb->dev); if (!neigh) { ++dev->stats.tx_dropped; dev_kfree_skb_any(skb); @@ -570,9 +570,9 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev) spin_lock_irqsave(&priv->lock, flags); - path = __path_find(dev, skb->dst->neighbour->ha + 4); + path = __path_find(dev, skb_dst(skb)->neighbour->ha + 4); if (!path) { - path = path_rec_create(dev, skb->dst->neighbour->ha + 4); + path = path_rec_create(dev, skb_dst(skb)->neighbour->ha + 4); if (!path) goto err_path; @@ -605,7 +605,7 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev) goto err_drop; } } else - ipoib_send(dev, skb, path->ah, IPOIB_QPN(skb->dst->neighbour->ha)); + ipoib_send(dev, skb, path->ah, IPOIB_QPN(skb_dst(skb)->neighbour->ha)); } else { neigh->ah = NULL; @@ -635,15 +635,15 @@ static void ipoib_path_lookup(struct sk_buff *skb, struct net_device *dev) struct ipoib_dev_priv *priv = netdev_priv(skb->dev); /* Look up path record for unicasts */ - if (skb->dst->neighbour->ha[4] != 0xff) { + if (skb_dst(skb)->neighbour->ha[4] != 0xff) { neigh_add_path(skb, dev); return; } /* Add in the P_Key for multicasts */ - skb->dst->neighbour->ha[8] = (priv->pkey >> 8) & 0xff; - skb->dst->neighbour->ha[9] = priv->pkey & 0xff; - ipoib_mcast_send(dev, skb->dst->neighbour->ha + 4, skb); + skb_dst(skb)->neighbour->ha[8] = (priv->pkey >> 8) & 0xff; + skb_dst(skb)->neighbour->ha[9] = priv->pkey & 0xff; + ipoib_mcast_send(dev, skb_dst(skb)->neighbour->ha + 4, skb); } static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev, @@ -708,16 +708,16 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) struct ipoib_neigh *neigh; unsigned long flags; - if (likely(skb->dst && skb->dst->neighbour)) { - if (unlikely(!*to_ipoib_neigh(skb->dst->neighbour))) { + if (likely(skb_dst(skb) && skb_dst(skb)->neighbour)) { + if (unlikely(!*to_ipoib_neigh(skb_dst(skb)->neighbour))) { ipoib_path_lookup(skb, dev); return NETDEV_TX_OK; } - neigh = *to_ipoib_neigh(skb->dst->neighbour); + neigh = *to_ipoib_neigh(skb_dst(skb)->neighbour); if (unlikely((memcmp(&neigh->dgid.raw, - skb->dst->neighbour->ha + 4, + skb_dst(skb)->neighbour->ha + 4, sizeof(union ib_gid))) || (neigh->dev != dev))) { spin_lock_irqsave(&priv->lock, flags); @@ -743,7 +743,7 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } } else if (neigh->ah) { - ipoib_send(dev, skb, neigh->ah, IPOIB_QPN(skb->dst->neighbour->ha)); + ipoib_send(dev, skb, neigh->ah, IPOIB_QPN(skb_dst(skb)->neighbour->ha)); return NETDEV_TX_OK; } @@ -772,7 +772,7 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) if ((be16_to_cpup((__be16 *) skb->data) != ETH_P_ARP) && (be16_to_cpup((__be16 *) skb->data) != ETH_P_RARP)) { ipoib_warn(priv, "Unicast, no %s: type %04x, QPN %06x %pI6\n", - skb->dst ? "neigh" : "dst", + skb_dst(skb) ? "neigh" : "dst", be16_to_cpup((__be16 *) skb->data), IPOIB_QPN(phdr->hwaddr), phdr->hwaddr + 4); @@ -817,7 +817,7 @@ static int ipoib_hard_header(struct sk_buff *skb, * destination address onto the front of the skb so we can * figure out where to send the packet later. */ - if ((!skb->dst || !skb->dst->neighbour) && daddr) { + if ((!skb_dst(skb) || !skb_dst(skb)->neighbour) && daddr) { struct ipoib_pseudoheader *phdr = (struct ipoib_pseudoheader *) skb_push(skb, sizeof *phdr); memcpy(phdr->hwaddr, daddr, INFINIBAND_ALEN); @@ -1053,6 +1053,7 @@ static void ipoib_setup(struct net_device *dev) dev->tx_queue_len = ipoib_sendq_size * 2; dev->features = (NETIF_F_VLAN_CHALLENGED | NETIF_F_HIGHDMA); + dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; memcpy(dev->broadcast, ipv4_bcast_addr, INFINIBAND_ALEN); diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index 425e31112ed7..a0e97532e714 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -261,7 +261,7 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast, skb->dev = dev; - if (!skb->dst || !skb->dst->neighbour) { + if (!skb_dst(skb) || !skb_dst(skb)->neighbour) { /* put pseudoheader back on for next time */ skb_push(skb, sizeof (struct ipoib_pseudoheader)); } @@ -707,10 +707,10 @@ void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb) out: if (mcast && mcast->ah) { - if (skb->dst && - skb->dst->neighbour && - !*to_ipoib_neigh(skb->dst->neighbour)) { - struct ipoib_neigh *neigh = ipoib_neigh_alloc(skb->dst->neighbour, + if (skb_dst(skb) && + skb_dst(skb)->neighbour && + !*to_ipoib_neigh(skb_dst(skb)->neighbour)) { + struct ipoib_neigh *neigh = ipoib_neigh_alloc(skb_dst(skb)->neighbour, skb->dev); if (neigh) { diff --git a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c index 4c57f329dd50..e3bf00d8cd25 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c @@ -61,7 +61,8 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey) ppriv = netdev_priv(pdev); - rtnl_lock(); + if (!rtnl_trylock()) + return restart_syscall(); mutex_lock(&ppriv->vlan_mutex); /* @@ -167,7 +168,8 @@ int ipoib_vlan_delete(struct net_device *pdev, unsigned short pkey) ppriv = netdev_priv(pdev); - rtnl_lock(); + if (!rtnl_trylock()) + return restart_syscall(); mutex_lock(&ppriv->vlan_mutex); list_for_each_entry_safe(priv, tpriv, &ppriv->child_intfs, list) { if (priv->pkey == pkey) { diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index 75223f50de58..0ba6ec876296 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -257,11 +257,8 @@ static void iscsi_iser_cleanup_task(struct iscsi_task *task) { struct iscsi_iser_task *iser_task = task->dd_data; - /* - * mgmt tasks do not need special cleanup and we do not - * allocate anything in the init task callout - */ - if (!task->sc || task->state == ISCSI_TASK_PENDING) + /* mgmt tasks do not need special cleanup */ + if (!task->sc) return; if (iser_task->status == ISER_TASK_STATUS_STARTED) { @@ -517,7 +514,8 @@ iscsi_iser_conn_get_stats(struct iscsi_cls_conn *cls_conn, struct iscsi_stats *s } static struct iscsi_endpoint * -iscsi_iser_ep_connect(struct sockaddr *dst_addr, int non_blocking) +iscsi_iser_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr, + int non_blocking) { int err; struct iser_conn *ib_conn; diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 7a7a026ba712..114efd8dc8f5 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -25,7 +25,6 @@ struct evdev { int exist; int open; int minor; - char name[16]; struct input_handle handle; wait_queue_head_t wait; struct evdev_client *grab; @@ -609,7 +608,8 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, p, compat_mode); if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) - return str_to_user(dev->name, _IOC_SIZE(cmd), p); + return str_to_user(dev_name(&evdev->dev), + _IOC_SIZE(cmd), p); if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0))) return str_to_user(dev->phys, _IOC_SIZE(cmd), p); @@ -626,8 +626,11 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, abs.maximum = dev->absmax[t]; abs.fuzz = dev->absfuzz[t]; abs.flat = dev->absflat[t]; + abs.resolution = dev->absres[t]; - if (copy_to_user(p, &abs, sizeof(struct input_absinfo))) + if (copy_to_user(p, &abs, min_t(size_t, + _IOC_SIZE(cmd), + sizeof(struct input_absinfo)))) return -EFAULT; return 0; @@ -654,8 +657,9 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, t = _IOC_NR(cmd) & ABS_MAX; - if (copy_from_user(&abs, p, - sizeof(struct input_absinfo))) + if (copy_from_user(&abs, p, min_t(size_t, + _IOC_SIZE(cmd), + sizeof(struct input_absinfo)))) return -EFAULT; /* @@ -670,6 +674,8 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, dev->absmax[t] = abs.maximum; dev->absfuzz[t] = abs.fuzz; dev->absflat[t] = abs.flat; + dev->absres[t] = _IOC_SIZE(cmd) < sizeof(struct input_absinfo) ? + 0 : abs.resolution; spin_unlock_irq(&dev->event_lock); @@ -807,16 +813,15 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev, mutex_init(&evdev->mutex); init_waitqueue_head(&evdev->wait); - snprintf(evdev->name, sizeof(evdev->name), "event%d", minor); + dev_set_name(&evdev->dev, "event%d", minor); evdev->exist = 1; evdev->minor = minor; evdev->handle.dev = input_get_device(dev); - evdev->handle.name = evdev->name; + evdev->handle.name = dev_name(&evdev->dev); evdev->handle.handler = handler; evdev->handle.private = evdev; - dev_set_name(&evdev->dev, evdev->name); evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor); evdev->dev.class = &input_class; evdev->dev.parent = &dev->dev; diff --git a/drivers/input/gameport/fm801-gp.c b/drivers/input/gameport/fm801-gp.c index 1dec00e20dbc..8a1810f88b9e 100644 --- a/drivers/input/gameport/fm801-gp.c +++ b/drivers/input/gameport/fm801-gp.c @@ -167,5 +167,6 @@ module_exit(fm801_gp_exit); MODULE_DEVICE_TABLE(pci, fm801_gp_id_table); +MODULE_DESCRIPTION("FM801 gameport driver"); MODULE_AUTHOR("Takashi Iwai "); MODULE_LICENSE("GPL"); diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c index 2d175b5928ff..ac11be08585e 100644 --- a/drivers/input/gameport/gameport.c +++ b/drivers/input/gameport/gameport.c @@ -30,16 +30,6 @@ MODULE_AUTHOR("Vojtech Pavlik "); MODULE_DESCRIPTION("Generic gameport layer"); MODULE_LICENSE("GPL"); -EXPORT_SYMBOL(__gameport_register_port); -EXPORT_SYMBOL(gameport_unregister_port); -EXPORT_SYMBOL(__gameport_register_driver); -EXPORT_SYMBOL(gameport_unregister_driver); -EXPORT_SYMBOL(gameport_open); -EXPORT_SYMBOL(gameport_close); -EXPORT_SYMBOL(gameport_set_phys); -EXPORT_SYMBOL(gameport_start_polling); -EXPORT_SYMBOL(gameport_stop_polling); - /* * gameport_mutex protects entire gameport subsystem and is taken * every time gameport port or driver registrered or unregistered. @@ -162,6 +152,7 @@ void gameport_start_polling(struct gameport *gameport) spin_unlock(&gameport->timer_lock); } +EXPORT_SYMBOL(gameport_start_polling); void gameport_stop_polling(struct gameport *gameport) { @@ -172,6 +163,7 @@ void gameport_stop_polling(struct gameport *gameport) spin_unlock(&gameport->timer_lock); } +EXPORT_SYMBOL(gameport_stop_polling); static void gameport_run_poll_handler(unsigned long d) { @@ -516,6 +508,7 @@ void gameport_set_phys(struct gameport *gameport, const char *fmt, ...) vsnprintf(gameport->phys, sizeof(gameport->phys), fmt, args); va_end(args); } +EXPORT_SYMBOL(gameport_set_phys); /* * Prepare gameport port for registration. @@ -658,6 +651,7 @@ void __gameport_register_port(struct gameport *gameport, struct module *owner) gameport_init_port(gameport); gameport_queue_event(gameport, owner, GAMEPORT_REGISTER_PORT); } +EXPORT_SYMBOL(__gameport_register_port); /* * Synchronously unregisters gameport port. @@ -669,6 +663,7 @@ void gameport_unregister_port(struct gameport *gameport) gameport_destroy_port(gameport); mutex_unlock(&gameport_mutex); } +EXPORT_SYMBOL(gameport_unregister_port); /* @@ -728,7 +723,7 @@ int __gameport_register_driver(struct gameport_driver *drv, struct module *owner * Temporarily disable automatic binding because probing * takes long time and we are better off doing it in kgameportd */ - drv->ignore = 1; + drv->ignore = true; error = driver_register(&drv->driver); if (error) { @@ -741,7 +736,7 @@ int __gameport_register_driver(struct gameport_driver *drv, struct module *owner /* * Reset ignore flag and let kgameportd bind the driver to free ports */ - drv->ignore = 0; + drv->ignore = false; error = gameport_queue_event(drv, NULL, GAMEPORT_ATTACH_DRIVER); if (error) { driver_unregister(&drv->driver); @@ -750,6 +745,7 @@ int __gameport_register_driver(struct gameport_driver *drv, struct module *owner return 0; } +EXPORT_SYMBOL(__gameport_register_driver); void gameport_unregister_driver(struct gameport_driver *drv) { @@ -757,7 +753,7 @@ void gameport_unregister_driver(struct gameport_driver *drv) mutex_lock(&gameport_mutex); - drv->ignore = 1; /* so gameport_find_driver ignores it */ + drv->ignore = true; /* so gameport_find_driver ignores it */ gameport_remove_pending_events(drv); start_over: @@ -774,6 +770,7 @@ start_over: mutex_unlock(&gameport_mutex); } +EXPORT_SYMBOL(gameport_unregister_driver); static int gameport_bus_match(struct device *dev, struct device_driver *drv) { @@ -812,6 +809,7 @@ int gameport_open(struct gameport *gameport, struct gameport_driver *drv, int mo gameport_set_drv(gameport, drv); return 0; } +EXPORT_SYMBOL(gameport_open); void gameport_close(struct gameport *gameport) { @@ -822,6 +820,7 @@ void gameport_close(struct gameport *gameport) if (gameport->close) gameport->close(gameport); } +EXPORT_SYMBOL(gameport_close); static int __init gameport_init(void) { diff --git a/drivers/input/input.c b/drivers/input/input.c index 5d445f48789b..7c237e6ac711 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -1265,8 +1265,14 @@ static struct device_type input_dev_type = { .uevent = input_dev_uevent, }; +static char *input_nodename(struct device *dev) +{ + return kasprintf(GFP_KERNEL, "input/%s", dev_name(dev)); +} + struct class input_class = { .name = "input", + .nodename = input_nodename, }; EXPORT_SYMBOL_GPL(input_class); diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index 012a5e753991..0e12f89276a3 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c @@ -39,7 +39,6 @@ struct joydev { int exist; int open; int minor; - char name[16]; struct input_handle handle; wait_queue_head_t wait; struct list_head client_list; @@ -537,12 +536,14 @@ static int joydev_ioctl_common(struct joydev *joydev, default: if ((cmd & ~IOCSIZE_MASK) == JSIOCGNAME(0)) { int len; - if (!dev->name) + const char *name = dev_name(&dev->dev); + + if (!name) return 0; - len = strlen(dev->name) + 1; + len = strlen(name) + 1; if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); - if (copy_to_user(argp, dev->name, len)) + if (copy_to_user(argp, name, len)) return -EFAULT; return len; } @@ -742,13 +743,13 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev, mutex_init(&joydev->mutex); init_waitqueue_head(&joydev->wait); - snprintf(joydev->name, sizeof(joydev->name), "js%d", minor); + dev_set_name(&joydev->dev, "js%d", minor); joydev->exist = 1; joydev->minor = minor; joydev->exist = 1; joydev->handle.dev = input_get_device(dev); - joydev->handle.name = joydev->name; + joydev->handle.name = dev_name(&joydev->dev); joydev->handle.handler = handler; joydev->handle.private = joydev; @@ -797,7 +798,6 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev, } } - dev_set_name(&joydev->dev, joydev->name); joydev->dev.devt = MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor); joydev->dev.class = &input_class; joydev->dev.parent = &dev->dev; diff --git a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c index 356b3a25efa2..1c0b529c06aa 100644 --- a/drivers/input/joystick/analog.c +++ b/drivers/input/joystick/analog.c @@ -35,7 +35,7 @@ #include #include #include -#include +#include #define DRIVER_DESC "Analog joystick and gamepad driver" diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index ea2638b41982..9d8f796c6745 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -250,6 +250,17 @@ config KEYBOARD_HP7XX To compile this driver as a module, choose M here: the module will be called jornada720_kbd. +config KEYBOARD_LM8323 + tristate "LM8323 keypad chip" + depends on I2C + depends on LEDS_CLASS + help + If you say yes here you get support for the National Semiconductor + LM8323 keypad controller. + + To compile this driver as a module, choose M here: the + module will be called lm8323. + config KEYBOARD_OMAP tristate "TI OMAP keypad support" depends on (ARCH_OMAP1 || ARCH_OMAP2) @@ -332,4 +343,14 @@ config KEYBOARD_SH_KEYSC To compile this driver as a module, choose M here: the module will be called sh_keysc. + +config KEYBOARD_EP93XX + tristate "EP93xx Matrix Keypad support" + depends on ARCH_EP93XX + help + Say Y here to enable the matrix keypad on the Cirrus EP93XX. + + To compile this driver as a module, choose M here: the + module will be called ep93xx_keypad. + endif diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index 36351e1190f9..156b647a259b 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_KEYBOARD_SPITZ) += spitzkbd.o obj-$(CONFIG_KEYBOARD_TOSA) += tosakbd.o obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o +obj-$(CONFIG_KEYBOARD_LM8323) += lm8323.o obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keypad.o obj-$(CONFIG_KEYBOARD_PXA930_ROTARY) += pxa930_rotary.o @@ -28,3 +29,4 @@ obj-$(CONFIG_KEYBOARD_HP7XX) += jornada720_kbd.o obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o +obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o diff --git a/drivers/input/keyboard/ep93xx_keypad.c b/drivers/input/keyboard/ep93xx_keypad.c new file mode 100644 index 000000000000..181d30e3018e --- /dev/null +++ b/drivers/input/keyboard/ep93xx_keypad.c @@ -0,0 +1,470 @@ +/* + * Driver for the Cirrus EP93xx matrix keypad controller. + * + * Copyright (c) 2008 H Hartley Sweeten + * + * Based on the pxa27x matrix keypad controller by Rodolfo Giometti. + * + * 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. + * + * NOTE: + * + * The 3-key reset is triggered by pressing the 3 keys in + * Row 0, Columns 2, 4, and 7 at the same time. This action can + * be disabled by setting the EP93XX_KEYPAD_DISABLE_3_KEY flag. + * + * Normal operation for the matrix does not autorepeat the key press. + * This action can be enabled by setting the EP93XX_KEYPAD_AUTOREPEAT + * flag. + */ + +#include +#include +#include +#include + +#include +#include +#include + +/* + * Keypad Interface Register offsets + */ +#define KEY_INIT 0x00 /* Key Scan Initialization register */ +#define KEY_DIAG 0x04 /* Key Scan Diagnostic register */ +#define KEY_REG 0x08 /* Key Value Capture register */ + +/* Key Scan Initialization Register bit defines */ +#define KEY_INIT_DBNC_MASK (0x00ff0000) +#define KEY_INIT_DBNC_SHIFT (16) +#define KEY_INIT_DIS3KY (1<<15) +#define KEY_INIT_DIAG (1<<14) +#define KEY_INIT_BACK (1<<13) +#define KEY_INIT_T2 (1<<12) +#define KEY_INIT_PRSCL_MASK (0x000003ff) +#define KEY_INIT_PRSCL_SHIFT (0) + +/* Key Scan Diagnostic Register bit defines */ +#define KEY_DIAG_MASK (0x0000003f) +#define KEY_DIAG_SHIFT (0) + +/* Key Value Capture Register bit defines */ +#define KEY_REG_K (1<<15) +#define KEY_REG_INT (1<<14) +#define KEY_REG_2KEYS (1<<13) +#define KEY_REG_1KEY (1<<12) +#define KEY_REG_KEY2_MASK (0x00000fc0) +#define KEY_REG_KEY2_SHIFT (6) +#define KEY_REG_KEY1_MASK (0x0000003f) +#define KEY_REG_KEY1_SHIFT (0) + +#define keypad_readl(off) __raw_readl(keypad->mmio_base + (off)) +#define keypad_writel(v, off) __raw_writel((v), keypad->mmio_base + (off)) + +#define MAX_MATRIX_KEY_NUM (MAX_MATRIX_KEY_ROWS * MAX_MATRIX_KEY_COLS) + +struct ep93xx_keypad { + struct ep93xx_keypad_platform_data *pdata; + + struct clk *clk; + struct input_dev *input_dev; + void __iomem *mmio_base; + + int irq; + int enabled; + + int key1; + int key2; + + unsigned int matrix_keycodes[MAX_MATRIX_KEY_NUM]; +}; + +static void ep93xx_keypad_build_keycode(struct ep93xx_keypad *keypad) +{ + struct ep93xx_keypad_platform_data *pdata = keypad->pdata; + struct input_dev *input_dev = keypad->input_dev; + int i; + + for (i = 0; i < pdata->matrix_key_map_size; i++) { + unsigned int key = pdata->matrix_key_map[i]; + int row = (key >> 28) & 0xf; + int col = (key >> 24) & 0xf; + int code = key & 0xffffff; + + keypad->matrix_keycodes[(row << 3) + col] = code; + __set_bit(code, input_dev->keybit); + } +} + +static irqreturn_t ep93xx_keypad_irq_handler(int irq, void *dev_id) +{ + struct ep93xx_keypad *keypad = dev_id; + struct input_dev *input_dev = keypad->input_dev; + unsigned int status = keypad_readl(KEY_REG); + int keycode, key1, key2; + + keycode = (status & KEY_REG_KEY1_MASK) >> KEY_REG_KEY1_SHIFT; + key1 = keypad->matrix_keycodes[keycode]; + + keycode = (status & KEY_REG_KEY2_MASK) >> KEY_REG_KEY2_SHIFT; + key2 = keypad->matrix_keycodes[keycode]; + + if (status & KEY_REG_2KEYS) { + if (keypad->key1 && key1 != keypad->key1 && key2 != keypad->key1) + input_report_key(input_dev, keypad->key1, 0); + + if (keypad->key2 && key1 != keypad->key2 && key2 != keypad->key2) + input_report_key(input_dev, keypad->key2, 0); + + input_report_key(input_dev, key1, 1); + input_report_key(input_dev, key2, 1); + + keypad->key1 = key1; + keypad->key2 = key2; + + } else if (status & KEY_REG_1KEY) { + if (keypad->key1 && key1 != keypad->key1) + input_report_key(input_dev, keypad->key1, 0); + + if (keypad->key2 && key1 != keypad->key2) + input_report_key(input_dev, keypad->key2, 0); + + input_report_key(input_dev, key1, 1); + + keypad->key1 = key1; + keypad->key2 = 0; + + } else { + input_report_key(input_dev, keypad->key1, 0); + input_report_key(input_dev, keypad->key2, 0); + + keypad->key1 = keypad->key2 = 0; + } + input_sync(input_dev); + + return IRQ_HANDLED; +} + +static void ep93xx_keypad_config(struct ep93xx_keypad *keypad) +{ + struct ep93xx_keypad_platform_data *pdata = keypad->pdata; + unsigned int val = 0; + + clk_set_rate(keypad->clk, pdata->flags & EP93XX_KEYPAD_KDIV); + + if (pdata->flags & EP93XX_KEYPAD_DISABLE_3_KEY) + val |= KEY_INIT_DIS3KY; + if (pdata->flags & EP93XX_KEYPAD_DIAG_MODE) + val |= KEY_INIT_DIAG; + if (pdata->flags & EP93XX_KEYPAD_BACK_DRIVE) + val |= KEY_INIT_BACK; + if (pdata->flags & EP93XX_KEYPAD_TEST_MODE) + val |= KEY_INIT_T2; + + val |= ((pdata->debounce << KEY_INIT_DBNC_SHIFT) & KEY_INIT_DBNC_MASK); + + val |= ((pdata->prescale << KEY_INIT_PRSCL_SHIFT) & KEY_INIT_PRSCL_MASK); + + keypad_writel(val, KEY_INIT); +} + +static int ep93xx_keypad_open(struct input_dev *pdev) +{ + struct ep93xx_keypad *keypad = input_get_drvdata(pdev); + + if (!keypad->enabled) { + ep93xx_keypad_config(keypad); + clk_enable(keypad->clk); + keypad->enabled = 1; + } + + return 0; +} + +static void ep93xx_keypad_close(struct input_dev *pdev) +{ + struct ep93xx_keypad *keypad = input_get_drvdata(pdev); + + if (keypad->enabled) { + clk_disable(keypad->clk); + keypad->enabled = 0; + } +} + + +#ifdef CONFIG_PM +/* + * NOTE: I don't know if this is correct, or will work on the ep93xx. + * + * None of the existing ep93xx drivers have power management support. + * But, this is basically what the pxa27x_keypad driver does. + */ +static int ep93xx_keypad_suspend(struct platform_device *pdev, + pm_message_t state) +{ + struct ep93xx_keypad *keypad = platform_get_drvdata(pdev); + struct input_dev *input_dev = keypad->input_dev; + + mutex_lock(&input_dev->mutex); + + if (keypad->enabled) { + clk_disable(keypad->clk); + keypad->enabled = 0; + } + + mutex_unlock(&input_dev->mutex); + + if (device_may_wakeup(&pdev->dev)) + enable_irq_wake(keypad->irq); + + return 0; +} + +static int ep93xx_keypad_resume(struct platform_device *pdev) +{ + struct ep93xx_keypad *keypad = platform_get_drvdata(pdev); + struct input_dev *input_dev = keypad->input_dev; + + if (device_may_wakeup(&pdev->dev)) + disable_irq_wake(keypad->irq); + + mutex_lock(&input_dev->mutex); + + if (input_dev->users) { + if (!keypad->enabled) { + ep93xx_keypad_config(keypad); + clk_enable(keypad->clk); + keypad->enabled = 1; + } + } + + mutex_unlock(&input_dev->mutex); + + return 0; +} +#else /* !CONFIG_PM */ +#define ep93xx_keypad_suspend NULL +#define ep93xx_keypad_resume NULL +#endif /* !CONFIG_PM */ + +static int __devinit ep93xx_keypad_probe(struct platform_device *pdev) +{ + struct ep93xx_keypad *keypad; + struct ep93xx_keypad_platform_data *pdata = pdev->dev.platform_data; + struct input_dev *input_dev; + struct resource *res; + int irq, err, i, gpio; + + if (!pdata || + !pdata->matrix_key_rows || + pdata->matrix_key_rows > MAX_MATRIX_KEY_ROWS || + !pdata->matrix_key_cols || + pdata->matrix_key_cols > MAX_MATRIX_KEY_COLS) { + dev_err(&pdev->dev, "invalid or missing platform data\n"); + return -EINVAL; + } + + keypad = kzalloc(sizeof(struct ep93xx_keypad), GFP_KERNEL); + if (!keypad) { + dev_err(&pdev->dev, "failed to allocate driver data\n"); + return -ENOMEM; + } + + keypad->pdata = pdata; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "failed to get keypad irq\n"); + err = -ENXIO; + goto failed_free; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "failed to get I/O memory\n"); + err = -ENXIO; + goto failed_free; + } + + res = request_mem_region(res->start, resource_size(res), pdev->name); + if (!res) { + dev_err(&pdev->dev, "failed to request I/O memory\n"); + err = -EBUSY; + goto failed_free; + } + + keypad->mmio_base = ioremap(res->start, resource_size(res)); + if (keypad->mmio_base == NULL) { + dev_err(&pdev->dev, "failed to remap I/O memory\n"); + err = -ENXIO; + goto failed_free_mem; + } + + /* Request the needed GPIO's */ + gpio = EP93XX_GPIO_LINE_ROW0; + for (i = 0; i < keypad->pdata->matrix_key_rows; i++, gpio++) { + err = gpio_request(gpio, pdev->name); + if (err) { + dev_err(&pdev->dev, "failed to request gpio-%d\n", + gpio); + goto failed_free_rows; + } + } + + gpio = EP93XX_GPIO_LINE_COL0; + for (i = 0; i < keypad->pdata->matrix_key_cols; i++, gpio++) { + err = gpio_request(gpio, pdev->name); + if (err) { + dev_err(&pdev->dev, "failed to request gpio-%d\n", + gpio); + goto failed_free_cols; + } + } + + keypad->clk = clk_get(&pdev->dev, "key_clk"); + if (IS_ERR(keypad->clk)) { + dev_err(&pdev->dev, "failed to get keypad clock\n"); + err = PTR_ERR(keypad->clk); + goto failed_free_io; + } + + /* Create and register the input driver */ + input_dev = input_allocate_device(); + if (!input_dev) { + dev_err(&pdev->dev, "failed to allocate input device\n"); + err = -ENOMEM; + goto failed_put_clk; + } + + keypad->input_dev = input_dev; + + input_dev->name = pdev->name; + input_dev->id.bustype = BUS_HOST; + input_dev->open = ep93xx_keypad_open; + input_dev->close = ep93xx_keypad_close; + input_dev->dev.parent = &pdev->dev; + input_dev->keycode = keypad->matrix_keycodes; + input_dev->keycodesize = sizeof(keypad->matrix_keycodes[0]); + input_dev->keycodemax = ARRAY_SIZE(keypad->matrix_keycodes); + + input_set_drvdata(input_dev, keypad); + + input_dev->evbit[0] = BIT_MASK(EV_KEY); + if (keypad->pdata->flags & EP93XX_KEYPAD_AUTOREPEAT) + input_dev->evbit[0] |= BIT_MASK(EV_REP); + + ep93xx_keypad_build_keycode(keypad); + platform_set_drvdata(pdev, keypad); + + err = request_irq(irq, ep93xx_keypad_irq_handler, IRQF_DISABLED, + pdev->name, keypad); + if (err) { + dev_err(&pdev->dev, "failed to request IRQ\n"); + goto failed_free_dev; + } + + keypad->irq = irq; + + /* Register the input device */ + err = input_register_device(input_dev); + if (err) { + dev_err(&pdev->dev, "failed to register input device\n"); + goto failed_free_irq; + } + + device_init_wakeup(&pdev->dev, 1); + + return 0; + +failed_free_irq: + free_irq(irq, pdev); + platform_set_drvdata(pdev, NULL); +failed_free_dev: + input_free_device(input_dev); +failed_put_clk: + clk_put(keypad->clk); +failed_free_io: + i = keypad->pdata->matrix_key_cols - 1; + gpio = EP93XX_GPIO_LINE_COL0 + i; +failed_free_cols: + for ( ; i >= 0; i--, gpio--) + gpio_free(gpio); + i = keypad->pdata->matrix_key_rows - 1; + gpio = EP93XX_GPIO_LINE_ROW0 + i; +failed_free_rows: + for ( ; i >= 0; i--, gpio--) + gpio_free(gpio); + iounmap(keypad->mmio_base); +failed_free_mem: + release_mem_region(res->start, resource_size(res)); +failed_free: + kfree(keypad); + return err; +} + +static int __devexit ep93xx_keypad_remove(struct platform_device *pdev) +{ + struct ep93xx_keypad *keypad = platform_get_drvdata(pdev); + struct resource *res; + int i, gpio; + + free_irq(keypad->irq, pdev); + + platform_set_drvdata(pdev, NULL); + + if (keypad->enabled) + clk_disable(keypad->clk); + clk_put(keypad->clk); + + input_unregister_device(keypad->input_dev); + + i = keypad->pdata->matrix_key_cols - 1; + gpio = EP93XX_GPIO_LINE_COL0 + i; + for ( ; i >= 0; i--, gpio--) + gpio_free(gpio); + + i = keypad->pdata->matrix_key_rows - 1; + gpio = EP93XX_GPIO_LINE_ROW0 + i; + for ( ; i >= 0; i--, gpio--) + gpio_free(gpio); + + iounmap(keypad->mmio_base); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(res->start, resource_size(res)); + + kfree(keypad); + + return 0; +} + +static struct platform_driver ep93xx_keypad_driver = { + .driver = { + .name = "ep93xx-keypad", + .owner = THIS_MODULE, + }, + .probe = ep93xx_keypad_probe, + .remove = __devexit_p(ep93xx_keypad_remove), + .suspend = ep93xx_keypad_suspend, + .resume = ep93xx_keypad_resume, +}; + +static int __init ep93xx_keypad_init(void) +{ + return platform_driver_register(&ep93xx_keypad_driver); +} + +static void __exit ep93xx_keypad_exit(void) +{ + platform_driver_unregister(&ep93xx_keypad_driver); +} + +module_init(ep93xx_keypad_init); +module_exit(ep93xx_keypad_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("H Hartley Sweeten "); +MODULE_DESCRIPTION("EP93xx Matrix Keypad Controller"); +MODULE_ALIAS("platform:ep93xx-keypad"); diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index ad67d763fdbd..2157cd7de00c 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -22,13 +22,14 @@ #include #include #include +#include #include struct gpio_button_data { struct gpio_keys_button *button; struct input_dev *input; - struct timer_list timer; + struct delayed_work work; }; struct gpio_keys_drvdata { @@ -36,8 +37,10 @@ struct gpio_keys_drvdata { struct gpio_button_data data[0]; }; -static void gpio_keys_report_event(struct gpio_button_data *bdata) +static void gpio_keys_report_event(struct work_struct *work) { + struct gpio_button_data *bdata = + container_of(work, struct gpio_button_data, work.work); struct gpio_keys_button *button = bdata->button; struct input_dev *input = bdata->input; unsigned int type = button->type ?: EV_KEY; @@ -47,25 +50,17 @@ static void gpio_keys_report_event(struct gpio_button_data *bdata) input_sync(input); } -static void gpio_check_button(unsigned long _data) -{ - struct gpio_button_data *data = (struct gpio_button_data *)_data; - - gpio_keys_report_event(data); -} - static irqreturn_t gpio_keys_isr(int irq, void *dev_id) { struct gpio_button_data *bdata = dev_id; struct gpio_keys_button *button = bdata->button; + unsigned long delay; BUG_ON(irq != gpio_to_irq(button->gpio)); - if (button->debounce_interval) - mod_timer(&bdata->timer, - jiffies + msecs_to_jiffies(button->debounce_interval)); - else - gpio_keys_report_event(bdata); + delay = button->debounce_interval ? + msecs_to_jiffies(button->debounce_interval) : 0; + schedule_delayed_work(&bdata->work, delay); return IRQ_HANDLED; } @@ -112,8 +107,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) bdata->input = input; bdata->button = button; - setup_timer(&bdata->timer, - gpio_check_button, (unsigned long)bdata); + INIT_DELAYED_WORK(&bdata->work, gpio_keys_report_event); error = gpio_request(button->gpio, button->desc ?: "gpio_keys"); if (error < 0) { @@ -142,8 +136,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) } error = request_irq(irq, gpio_keys_isr, - IRQF_SAMPLE_RANDOM | IRQF_TRIGGER_RISING | - IRQF_TRIGGER_FALLING, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, button->desc ? button->desc : "gpio_keys", bdata); if (error) { @@ -173,8 +166,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) fail2: while (--i >= 0) { free_irq(gpio_to_irq(pdata->buttons[i].gpio), &ddata->data[i]); - if (pdata->buttons[i].debounce_interval) - del_timer_sync(&ddata->data[i].timer); + cancel_delayed_work_sync(&ddata->data[i].work); gpio_free(pdata->buttons[i].gpio); } @@ -198,8 +190,7 @@ static int __devexit gpio_keys_remove(struct platform_device *pdev) for (i = 0; i < pdata->nbuttons; i++) { int irq = gpio_to_irq(pdata->buttons[i].gpio); free_irq(irq, &ddata->data[i]); - if (pdata->buttons[i].debounce_interval) - del_timer_sync(&ddata->data[i].timer); + cancel_delayed_work_sync(&ddata->data[i].work); gpio_free(pdata->buttons[i].gpio); } diff --git a/drivers/input/keyboard/lm8323.c b/drivers/input/keyboard/lm8323.c new file mode 100644 index 000000000000..574eda2a4957 --- /dev/null +++ b/drivers/input/keyboard/lm8323.c @@ -0,0 +1,878 @@ +/* + * drivers/i2c/chips/lm8323.c + * + * Copyright (C) 2007-2009 Nokia Corporation + * + * Written by Daniel Stone + * Timo O. Karjalainen + * + * Updated by Felipe Balbi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation (version 2 of the License only). + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Commands to send to the chip. */ +#define LM8323_CMD_READ_ID 0x80 /* Read chip ID. */ +#define LM8323_CMD_WRITE_CFG 0x81 /* Set configuration item. */ +#define LM8323_CMD_READ_INT 0x82 /* Get interrupt status. */ +#define LM8323_CMD_RESET 0x83 /* Reset, same as external one */ +#define LM8323_CMD_WRITE_PORT_SEL 0x85 /* Set GPIO in/out. */ +#define LM8323_CMD_WRITE_PORT_STATE 0x86 /* Set GPIO pullup. */ +#define LM8323_CMD_READ_PORT_SEL 0x87 /* Get GPIO in/out. */ +#define LM8323_CMD_READ_PORT_STATE 0x88 /* Get GPIO pullup. */ +#define LM8323_CMD_READ_FIFO 0x89 /* Read byte from FIFO. */ +#define LM8323_CMD_RPT_READ_FIFO 0x8a /* Read FIFO (no increment). */ +#define LM8323_CMD_SET_ACTIVE 0x8b /* Set active time. */ +#define LM8323_CMD_READ_ERR 0x8c /* Get error status. */ +#define LM8323_CMD_READ_ROTATOR 0x8e /* Read rotator status. */ +#define LM8323_CMD_SET_DEBOUNCE 0x8f /* Set debouncing time. */ +#define LM8323_CMD_SET_KEY_SIZE 0x90 /* Set keypad size. */ +#define LM8323_CMD_READ_KEY_SIZE 0x91 /* Get keypad size. */ +#define LM8323_CMD_READ_CFG 0x92 /* Get configuration item. */ +#define LM8323_CMD_WRITE_CLOCK 0x93 /* Set clock config. */ +#define LM8323_CMD_READ_CLOCK 0x94 /* Get clock config. */ +#define LM8323_CMD_PWM_WRITE 0x95 /* Write PWM script. */ +#define LM8323_CMD_START_PWM 0x96 /* Start PWM engine. */ +#define LM8323_CMD_STOP_PWM 0x97 /* Stop PWM engine. */ + +/* Interrupt status. */ +#define INT_KEYPAD 0x01 /* Key event. */ +#define INT_ROTATOR 0x02 /* Rotator event. */ +#define INT_ERROR 0x08 /* Error: use CMD_READ_ERR. */ +#define INT_NOINIT 0x10 /* Lost configuration. */ +#define INT_PWM1 0x20 /* PWM1 stopped. */ +#define INT_PWM2 0x40 /* PWM2 stopped. */ +#define INT_PWM3 0x80 /* PWM3 stopped. */ + +/* Errors (signalled by INT_ERROR, read with CMD_READ_ERR). */ +#define ERR_BADPAR 0x01 /* Bad parameter. */ +#define ERR_CMDUNK 0x02 /* Unknown command. */ +#define ERR_KEYOVR 0x04 /* Too many keys pressed. */ +#define ERR_FIFOOVER 0x40 /* FIFO overflow. */ + +/* Configuration keys (CMD_{WRITE,READ}_CFG). */ +#define CFG_MUX1SEL 0x01 /* Select MUX1_OUT input. */ +#define CFG_MUX1EN 0x02 /* Enable MUX1_OUT. */ +#define CFG_MUX2SEL 0x04 /* Select MUX2_OUT input. */ +#define CFG_MUX2EN 0x08 /* Enable MUX2_OUT. */ +#define CFG_PSIZE 0x20 /* Package size (must be 0). */ +#define CFG_ROTEN 0x40 /* Enable rotator. */ + +/* Clock settings (CMD_{WRITE,READ}_CLOCK). */ +#define CLK_RCPWM_INTERNAL 0x00 +#define CLK_RCPWM_EXTERNAL 0x03 +#define CLK_SLOWCLKEN 0x08 /* Enable 32.768kHz clock. */ +#define CLK_SLOWCLKOUT 0x40 /* Enable slow pulse output. */ + +/* The possible addresses corresponding to CONFIG1 and CONFIG2 pin wirings. */ +#define LM8323_I2C_ADDR00 (0x84 >> 1) /* 1000 010x */ +#define LM8323_I2C_ADDR01 (0x86 >> 1) /* 1000 011x */ +#define LM8323_I2C_ADDR10 (0x88 >> 1) /* 1000 100x */ +#define LM8323_I2C_ADDR11 (0x8A >> 1) /* 1000 101x */ + +/* Key event fifo length */ +#define LM8323_FIFO_LEN 15 + +/* Commands for PWM engine; feed in with PWM_WRITE. */ +/* Load ramp counter from duty cycle field (range 0 - 0xff). */ +#define PWM_SET(v) (0x4000 | ((v) & 0xff)) +/* Go to start of script. */ +#define PWM_GOTOSTART 0x0000 +/* + * Stop engine (generates interrupt). If reset is 1, clear the program + * counter, else leave it. + */ +#define PWM_END(reset) (0xc000 | (!!(reset) << 11)) +/* + * Ramp. If s is 1, divide clock by 512, else divide clock by 16. + * Take t clock scales (up to 63) per step, for n steps (up to 126). + * If u is set, ramp up, else ramp down. + */ +#define PWM_RAMP(s, t, n, u) ((!!(s) << 14) | ((t) & 0x3f) << 8 | \ + ((n) & 0x7f) | ((u) ? 0 : 0x80)) +/* + * Loop (i.e. jump back to pos) for a given number of iterations (up to 63). + * If cnt is zero, execute until PWM_END is encountered. + */ +#define PWM_LOOP(cnt, pos) (0xa000 | (((cnt) & 0x3f) << 7) | \ + ((pos) & 0x3f)) +/* + * Wait for trigger. Argument is a mask of channels, shifted by the channel + * number, e.g. 0xa for channels 3 and 1. Note that channels are numbered + * from 1, not 0. + */ +#define PWM_WAIT_TRIG(chans) (0xe000 | (((chans) & 0x7) << 6)) +/* Send trigger. Argument is same as PWM_WAIT_TRIG. */ +#define PWM_SEND_TRIG(chans) (0xe000 | ((chans) & 0x7)) + +struct lm8323_pwm { + int id; + int fade_time; + int brightness; + int desired_brightness; + bool enabled; + bool running; + /* pwm lock */ + struct mutex lock; + struct work_struct work; + struct led_classdev cdev; + struct lm8323_chip *chip; +}; + +struct lm8323_chip { + /* device lock */ + struct mutex lock; + struct i2c_client *client; + struct work_struct work; + struct input_dev *idev; + bool kp_enabled; + bool pm_suspend; + unsigned keys_down; + char phys[32]; + unsigned short keymap[LM8323_KEYMAP_SIZE]; + int size_x; + int size_y; + int debounce_time; + int active_time; + struct lm8323_pwm pwm[LM8323_NUM_PWMS]; +}; + +#define client_to_lm8323(c) container_of(c, struct lm8323_chip, client) +#define dev_to_lm8323(d) container_of(d, struct lm8323_chip, client->dev) +#define work_to_lm8323(w) container_of(w, struct lm8323_chip, work) +#define cdev_to_pwm(c) container_of(c, struct lm8323_pwm, cdev) +#define work_to_pwm(w) container_of(w, struct lm8323_pwm, work) + +#define LM8323_MAX_DATA 8 + +/* + * To write, we just access the chip's address in write mode, and dump the + * command and data out on the bus. The command byte and data are taken as + * sequential u8s out of varargs, to a maximum of LM8323_MAX_DATA. + */ +static int lm8323_write(struct lm8323_chip *lm, int len, ...) +{ + int ret, i; + va_list ap; + u8 data[LM8323_MAX_DATA]; + + va_start(ap, len); + + if (unlikely(len > LM8323_MAX_DATA)) { + dev_err(&lm->client->dev, "tried to send %d bytes\n", len); + va_end(ap); + return 0; + } + + for (i = 0; i < len; i++) + data[i] = va_arg(ap, int); + + va_end(ap); + + /* + * If the host is asleep while we send the data, we can get a NACK + * back while it wakes up, so try again, once. + */ + ret = i2c_master_send(lm->client, data, len); + if (unlikely(ret == -EREMOTEIO)) + ret = i2c_master_send(lm->client, data, len); + if (unlikely(ret != len)) + dev_err(&lm->client->dev, "sent %d bytes of %d total\n", + len, ret); + + return ret; +} + +/* + * To read, we first send the command byte to the chip and end the transaction, + * then access the chip in read mode, at which point it will send the data. + */ +static int lm8323_read(struct lm8323_chip *lm, u8 cmd, u8 *buf, int len) +{ + int ret; + + /* + * If the host is asleep while we send the byte, we can get a NACK + * back while it wakes up, so try again, once. + */ + ret = i2c_master_send(lm->client, &cmd, 1); + if (unlikely(ret == -EREMOTEIO)) + ret = i2c_master_send(lm->client, &cmd, 1); + if (unlikely(ret != 1)) { + dev_err(&lm->client->dev, "sending read cmd 0x%02x failed\n", + cmd); + return 0; + } + + ret = i2c_master_recv(lm->client, buf, len); + if (unlikely(ret != len)) + dev_err(&lm->client->dev, "wanted %d bytes, got %d\n", + len, ret); + + return ret; +} + +/* + * Set the chip active time (idle time before it enters halt). + */ +static void lm8323_set_active_time(struct lm8323_chip *lm, int time) +{ + lm8323_write(lm, 2, LM8323_CMD_SET_ACTIVE, time >> 2); +} + +/* + * The signals are AT-style: the low 7 bits are the keycode, and the top + * bit indicates the state (1 for down, 0 for up). + */ +static inline u8 lm8323_whichkey(u8 event) +{ + return event & 0x7f; +} + +static inline int lm8323_ispress(u8 event) +{ + return (event & 0x80) ? 1 : 0; +} + +static void process_keys(struct lm8323_chip *lm) +{ + u8 event; + u8 key_fifo[LM8323_FIFO_LEN + 1]; + int old_keys_down = lm->keys_down; + int ret; + int i = 0; + + /* + * Read all key events from the FIFO at once. Next READ_FIFO clears the + * FIFO even if we didn't read all events previously. + */ + ret = lm8323_read(lm, LM8323_CMD_READ_FIFO, key_fifo, LM8323_FIFO_LEN); + + if (ret < 0) { + dev_err(&lm->client->dev, "Failed reading fifo \n"); + return; + } + key_fifo[ret] = 0; + + while ((event = key_fifo[i++])) { + u8 key = lm8323_whichkey(event); + int isdown = lm8323_ispress(event); + unsigned short keycode = lm->keymap[key]; + + dev_vdbg(&lm->client->dev, "key 0x%02x %s\n", + key, isdown ? "down" : "up"); + + if (lm->kp_enabled) { + input_event(lm->idev, EV_MSC, MSC_SCAN, key); + input_report_key(lm->idev, keycode, isdown); + input_sync(lm->idev); + } + + if (isdown) + lm->keys_down++; + else + lm->keys_down--; + } + + /* + * Errata: We need to ensure that the chip never enters halt mode + * during a keypress, so set active time to 0. When it's released, + * we can enter halt again, so set the active time back to normal. + */ + if (!old_keys_down && lm->keys_down) + lm8323_set_active_time(lm, 0); + if (old_keys_down && !lm->keys_down) + lm8323_set_active_time(lm, lm->active_time); +} + +static void lm8323_process_error(struct lm8323_chip *lm) +{ + u8 error; + + if (lm8323_read(lm, LM8323_CMD_READ_ERR, &error, 1) == 1) { + if (error & ERR_FIFOOVER) + dev_vdbg(&lm->client->dev, "fifo overflow!\n"); + if (error & ERR_KEYOVR) + dev_vdbg(&lm->client->dev, + "more than two keys pressed\n"); + if (error & ERR_CMDUNK) + dev_vdbg(&lm->client->dev, + "unknown command submitted\n"); + if (error & ERR_BADPAR) + dev_vdbg(&lm->client->dev, "bad command parameter\n"); + } +} + +static void lm8323_reset(struct lm8323_chip *lm) +{ + /* The docs say we must pass 0xAA as the data byte. */ + lm8323_write(lm, 2, LM8323_CMD_RESET, 0xAA); +} + +static int lm8323_configure(struct lm8323_chip *lm) +{ + int keysize = (lm->size_x << 4) | lm->size_y; + int clock = (CLK_SLOWCLKEN | CLK_RCPWM_EXTERNAL); + int debounce = lm->debounce_time >> 2; + int active = lm->active_time >> 2; + + /* + * Active time must be greater than the debounce time: if it's + * a close-run thing, give ourselves a 12ms buffer. + */ + if (debounce >= active) + active = debounce + 3; + + lm8323_write(lm, 2, LM8323_CMD_WRITE_CFG, 0); + lm8323_write(lm, 2, LM8323_CMD_WRITE_CLOCK, clock); + lm8323_write(lm, 2, LM8323_CMD_SET_KEY_SIZE, keysize); + lm8323_set_active_time(lm, lm->active_time); + lm8323_write(lm, 2, LM8323_CMD_SET_DEBOUNCE, debounce); + lm8323_write(lm, 3, LM8323_CMD_WRITE_PORT_STATE, 0xff, 0xff); + lm8323_write(lm, 3, LM8323_CMD_WRITE_PORT_SEL, 0, 0); + + /* + * Not much we can do about errors at this point, so just hope + * for the best. + */ + + return 0; +} + +static void pwm_done(struct lm8323_pwm *pwm) +{ + mutex_lock(&pwm->lock); + pwm->running = false; + if (pwm->desired_brightness != pwm->brightness) + schedule_work(&pwm->work); + mutex_unlock(&pwm->lock); +} + +/* + * Bottom half: handle the interrupt by posting key events, or dealing with + * errors appropriately. + */ +static void lm8323_work(struct work_struct *work) +{ + struct lm8323_chip *lm = work_to_lm8323(work); + u8 ints; + int i; + + mutex_lock(&lm->lock); + + while ((lm8323_read(lm, LM8323_CMD_READ_INT, &ints, 1) == 1) && ints) { + if (likely(ints & INT_KEYPAD)) + process_keys(lm); + if (ints & INT_ROTATOR) { + /* We don't currently support the rotator. */ + dev_vdbg(&lm->client->dev, "rotator fired\n"); + } + if (ints & INT_ERROR) { + dev_vdbg(&lm->client->dev, "error!\n"); + lm8323_process_error(lm); + } + if (ints & INT_NOINIT) { + dev_err(&lm->client->dev, "chip lost config; " + "reinitialising\n"); + lm8323_configure(lm); + } + for (i = 0; i < LM8323_NUM_PWMS; i++) { + if (ints & (1 << (INT_PWM1 + i))) { + dev_vdbg(&lm->client->dev, + "pwm%d engine completed\n", i); + pwm_done(&lm->pwm[i]); + } + } + } + + mutex_unlock(&lm->lock); +} + +/* + * We cannot use I2C in interrupt context, so we just schedule work. + */ +static irqreturn_t lm8323_irq(int irq, void *data) +{ + struct lm8323_chip *lm = data; + + schedule_work(&lm->work); + + return IRQ_HANDLED; +} + +/* + * Read the chip ID. + */ +static int lm8323_read_id(struct lm8323_chip *lm, u8 *buf) +{ + int bytes; + + bytes = lm8323_read(lm, LM8323_CMD_READ_ID, buf, 2); + if (unlikely(bytes != 2)) + return -EIO; + + return 0; +} + +static void lm8323_write_pwm_one(struct lm8323_pwm *pwm, int pos, u16 cmd) +{ + lm8323_write(pwm->chip, 4, LM8323_CMD_PWM_WRITE, (pos << 2) | pwm->id, + (cmd & 0xff00) >> 8, cmd & 0x00ff); +} + +/* + * Write a script into a given PWM engine, concluding with PWM_END. + * If 'kill' is nonzero, the engine will be shut down at the end + * of the script, producing a zero output. Otherwise the engine + * will be kept running at the final PWM level indefinitely. + */ +static void lm8323_write_pwm(struct lm8323_pwm *pwm, int kill, + int len, const u16 *cmds) +{ + int i; + + for (i = 0; i < len; i++) + lm8323_write_pwm_one(pwm, i, cmds[i]); + + lm8323_write_pwm_one(pwm, i++, PWM_END(kill)); + lm8323_write(pwm->chip, 2, LM8323_CMD_START_PWM, pwm->id); + pwm->running = true; +} + +static void lm8323_pwm_work(struct work_struct *work) +{ + struct lm8323_pwm *pwm = work_to_pwm(work); + int div512, perstep, steps, hz, up, kill; + u16 pwm_cmds[3]; + int num_cmds = 0; + + mutex_lock(&pwm->lock); + + /* + * Do nothing if we're already at the requested level, + * or previous setting is not yet complete. In the latter + * case we will be called again when the previous PWM script + * finishes. + */ + if (pwm->running || pwm->desired_brightness == pwm->brightness) + goto out; + + kill = (pwm->desired_brightness == 0); + up = (pwm->desired_brightness > pwm->brightness); + steps = abs(pwm->desired_brightness - pwm->brightness); + + /* + * Convert time (in ms) into a divisor (512 or 16 on a refclk of + * 32768Hz), and number of ticks per step. + */ + if ((pwm->fade_time / steps) > (32768 / 512)) { + div512 = 1; + hz = 32768 / 512; + } else { + div512 = 0; + hz = 32768 / 16; + } + + perstep = (hz * pwm->fade_time) / (steps * 1000); + + if (perstep == 0) + perstep = 1; + else if (perstep > 63) + perstep = 63; + + while (steps) { + int s; + + s = min(126, steps); + pwm_cmds[num_cmds++] = PWM_RAMP(div512, perstep, s, up); + steps -= s; + } + + lm8323_write_pwm(pwm, kill, num_cmds, pwm_cmds); + pwm->brightness = pwm->desired_brightness; + + out: + mutex_unlock(&pwm->lock); +} + +static void lm8323_pwm_set_brightness(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct lm8323_pwm *pwm = cdev_to_pwm(led_cdev); + struct lm8323_chip *lm = pwm->chip; + + mutex_lock(&pwm->lock); + pwm->desired_brightness = brightness; + mutex_unlock(&pwm->lock); + + if (in_interrupt()) { + schedule_work(&pwm->work); + } else { + /* + * Schedule PWM work as usual unless we are going into suspend + */ + mutex_lock(&lm->lock); + if (likely(!lm->pm_suspend)) + schedule_work(&pwm->work); + else + lm8323_pwm_work(&pwm->work); + mutex_unlock(&lm->lock); + } +} + +static ssize_t lm8323_pwm_show_time(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct lm8323_pwm *pwm = cdev_to_pwm(led_cdev); + + return sprintf(buf, "%d\n", pwm->fade_time); +} + +static ssize_t lm8323_pwm_store_time(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct lm8323_pwm *pwm = cdev_to_pwm(led_cdev); + int ret; + unsigned long time; + + ret = strict_strtoul(buf, 10, &time); + /* Numbers only, please. */ + if (ret) + return -EINVAL; + + pwm->fade_time = time; + + return strlen(buf); +} +static DEVICE_ATTR(time, 0644, lm8323_pwm_show_time, lm8323_pwm_store_time); + +static int init_pwm(struct lm8323_chip *lm, int id, struct device *dev, + const char *name) +{ + struct lm8323_pwm *pwm; + + BUG_ON(id > 3); + + pwm = &lm->pwm[id - 1]; + + pwm->id = id; + pwm->fade_time = 0; + pwm->brightness = 0; + pwm->desired_brightness = 0; + pwm->running = false; + pwm->enabled = false; + INIT_WORK(&pwm->work, lm8323_pwm_work); + mutex_init(&pwm->lock); + pwm->chip = lm; + + if (name) { + pwm->cdev.name = name; + pwm->cdev.brightness_set = lm8323_pwm_set_brightness; + if (led_classdev_register(dev, &pwm->cdev) < 0) { + dev_err(dev, "couldn't register PWM %d\n", id); + return -1; + } + if (device_create_file(pwm->cdev.dev, + &dev_attr_time) < 0) { + dev_err(dev, "couldn't register time attribute\n"); + led_classdev_unregister(&pwm->cdev); + return -1; + } + pwm->enabled = true; + } + + return 0; +} + +static struct i2c_driver lm8323_i2c_driver; + +static ssize_t lm8323_show_disable(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct lm8323_chip *lm = dev_get_drvdata(dev); + + return sprintf(buf, "%u\n", !lm->kp_enabled); +} + +static ssize_t lm8323_set_disable(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct lm8323_chip *lm = dev_get_drvdata(dev); + int ret; + unsigned long i; + + ret = strict_strtoul(buf, 10, &i); + + mutex_lock(&lm->lock); + lm->kp_enabled = !i; + mutex_unlock(&lm->lock); + + return count; +} +static DEVICE_ATTR(disable_kp, 0644, lm8323_show_disable, lm8323_set_disable); + +static int __devinit lm8323_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct lm8323_platform_data *pdata = client->dev.platform_data; + struct input_dev *idev; + struct lm8323_chip *lm; + int i, err; + unsigned long tmo; + u8 data[2]; + + if (!pdata || !pdata->size_x || !pdata->size_y) { + dev_err(&client->dev, "missing platform_data\n"); + return -EINVAL; + } + + if (pdata->size_x > 8) { + dev_err(&client->dev, "invalid x size %d specified\n", + pdata->size_x); + return -EINVAL; + } + + if (pdata->size_y > 12) { + dev_err(&client->dev, "invalid y size %d specified\n", + pdata->size_y); + return -EINVAL; + } + + lm = kzalloc(sizeof *lm, GFP_KERNEL); + idev = input_allocate_device(); + if (!lm || !idev) { + err = -ENOMEM; + goto fail1; + } + + i2c_set_clientdata(client, lm); + + lm->client = client; + lm->idev = idev; + mutex_init(&lm->lock); + INIT_WORK(&lm->work, lm8323_work); + + lm->size_x = pdata->size_x; + lm->size_y = pdata->size_y; + dev_vdbg(&client->dev, "Keypad size: %d x %d\n", + lm->size_x, lm->size_y); + + lm->debounce_time = pdata->debounce_time; + lm->active_time = pdata->active_time; + + lm8323_reset(lm); + + /* Nothing's set up to service the IRQ yet, so just spin for max. + * 100ms until we can configure. */ + tmo = jiffies + msecs_to_jiffies(100); + while (lm8323_read(lm, LM8323_CMD_READ_INT, data, 1) == 1) { + if (data[0] & INT_NOINIT) + break; + + if (time_after(jiffies, tmo)) { + dev_err(&client->dev, + "timeout waiting for initialisation\n"); + break; + } + + msleep(1); + } + + lm8323_configure(lm); + + /* If a true probe check the device */ + if (lm8323_read_id(lm, data) != 0) { + dev_err(&client->dev, "device not found\n"); + err = -ENODEV; + goto fail1; + } + + for (i = 0; i < LM8323_NUM_PWMS; i++) { + err = init_pwm(lm, i + 1, &client->dev, pdata->pwm_names[i]); + if (err < 0) + goto fail2; + } + + lm->kp_enabled = true; + err = device_create_file(&client->dev, &dev_attr_disable_kp); + if (err < 0) + goto fail2; + + idev->name = pdata->name ? : "LM8323 keypad"; + snprintf(lm->phys, sizeof(lm->phys), + "%s/input-kp", dev_name(&client->dev)); + idev->phys = lm->phys; + + idev->evbit[0] = BIT(EV_KEY) | BIT(EV_MSC); + __set_bit(MSC_SCAN, idev->mscbit); + for (i = 0; i < LM8323_KEYMAP_SIZE; i++) { + __set_bit(pdata->keymap[i], idev->keybit); + lm->keymap[i] = pdata->keymap[i]; + } + __clear_bit(KEY_RESERVED, idev->keybit); + + if (pdata->repeat) + __set_bit(EV_REP, idev->evbit); + + err = input_register_device(idev); + if (err) { + dev_dbg(&client->dev, "error registering input device\n"); + goto fail3; + } + + err = request_irq(client->irq, lm8323_irq, + IRQF_TRIGGER_FALLING | IRQF_DISABLED, + "lm8323", lm); + if (err) { + dev_err(&client->dev, "could not get IRQ %d\n", client->irq); + goto fail4; + } + + device_init_wakeup(&client->dev, 1); + enable_irq_wake(client->irq); + + return 0; + +fail4: + input_unregister_device(idev); + idev = NULL; +fail3: + device_remove_file(&client->dev, &dev_attr_disable_kp); +fail2: + while (--i >= 0) + if (lm->pwm[i].enabled) + led_classdev_unregister(&lm->pwm[i].cdev); +fail1: + input_free_device(idev); + kfree(lm); + return err; +} + +static int __devexit lm8323_remove(struct i2c_client *client) +{ + struct lm8323_chip *lm = i2c_get_clientdata(client); + int i; + + disable_irq_wake(client->irq); + free_irq(client->irq, lm); + cancel_work_sync(&lm->work); + + input_unregister_device(lm->idev); + + device_remove_file(&lm->client->dev, &dev_attr_disable_kp); + + for (i = 0; i < 3; i++) + if (lm->pwm[i].enabled) + led_classdev_unregister(&lm->pwm[i].cdev); + + kfree(lm); + + return 0; +} + +#ifdef CONFIG_PM +/* + * We don't need to explicitly suspend the chip, as it already switches off + * when there's no activity. + */ +static int lm8323_suspend(struct i2c_client *client, pm_message_t mesg) +{ + struct lm8323_chip *lm = i2c_get_clientdata(client); + int i; + + set_irq_wake(client->irq, 0); + disable_irq(client->irq); + + mutex_lock(&lm->lock); + lm->pm_suspend = true; + mutex_unlock(&lm->lock); + + for (i = 0; i < 3; i++) + if (lm->pwm[i].enabled) + led_classdev_suspend(&lm->pwm[i].cdev); + + return 0; +} + +static int lm8323_resume(struct i2c_client *client) +{ + struct lm8323_chip *lm = i2c_get_clientdata(client); + int i; + + mutex_lock(&lm->lock); + lm->pm_suspend = false; + mutex_unlock(&lm->lock); + + for (i = 0; i < 3; i++) + if (lm->pwm[i].enabled) + led_classdev_resume(&lm->pwm[i].cdev); + + enable_irq(client->irq); + set_irq_wake(client->irq, 1); + + return 0; +} +#else +#define lm8323_suspend NULL +#define lm8323_resume NULL +#endif + +static const struct i2c_device_id lm8323_id[] = { + { "lm8323", 0 }, + { } +}; + +static struct i2c_driver lm8323_i2c_driver = { + .driver = { + .name = "lm8323", + }, + .probe = lm8323_probe, + .remove = __devexit_p(lm8323_remove), + .suspend = lm8323_suspend, + .resume = lm8323_resume, + .id_table = lm8323_id, +}; +MODULE_DEVICE_TABLE(i2c, lm8323_id); + +static int __init lm8323_init(void) +{ + return i2c_add_driver(&lm8323_i2c_driver); +} +module_init(lm8323_init); + +static void __exit lm8323_exit(void) +{ + i2c_del_driver(&lm8323_i2c_driver); +} +module_exit(lm8323_exit); + +MODULE_AUTHOR("Timo O. Karjalainen "); +MODULE_AUTHOR("Daniel Stone"); +MODULE_AUTHOR("Felipe Balbi "); +MODULE_DESCRIPTION("LM8323 keypad driver"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 5c0a631d1455..1acfa3a05aad 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -193,6 +193,16 @@ config INPUT_CM109 To compile this driver as a module, choose M here: the module will be called cm109. +config INPUT_TWL4030_PWRBUTTON + tristate "TWL4030 Power button Driver" + depends on TWL4030_CORE + help + Say Y here if you want to enable power key reporting via the + TWL4030 family of chips. + + To compile this driver as a module, choose M here. The module will + be called twl4030_pwrbutton. + config INPUT_UINPUT tristate "User level driver support" help @@ -232,7 +242,7 @@ config INPUT_GPIO_ROTARY_ENCODER depends on GPIOLIB && GENERIC_GPIO help Say Y here to add support for rotary encoders connected to GPIO lines. - Check file:Documentation/incput/rotary_encoder.txt for more + Check file:Documentation/input/rotary-encoder.txt for more information. To compile this driver as a module, choose M here: the @@ -250,4 +260,13 @@ config INPUT_RB532_BUTTON To compile this driver as a module, choose M here: the module will be called rb532_button. +config INPUT_DM355EVM + tristate "TI DaVinci DM355 EVM Keypad and IR Remote" + depends on MFD_DM355EVM_MSP + help + Supports the pushbuttons and IR remote used with + the DM355 EVM board. + + To compile this driver as a module, choose M here: the + module will be called dm355evm_keys. endif diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index eb3f407baedf..0d979fd4cd57 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o obj-$(CONFIG_INPUT_CM109) += cm109.o obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o +obj-$(CONFIG_INPUT_DM355EVM) += dm355evm_keys.o obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o @@ -21,6 +22,7 @@ obj-$(CONFIG_INPUT_RB532_BUTTON) += rb532_button.o obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER) += rotary_encoder.o obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o +obj-$(CONFIG_INPUT_TWL4030_PWRBUTTON) += twl4030-pwrbutton.o obj-$(CONFIG_INPUT_UINPUT) += uinput.o obj-$(CONFIG_INPUT_WISTRON_BTNS) += wistron_btns.o obj-$(CONFIG_INPUT_YEALINK) += yealink.o diff --git a/drivers/input/misc/ati_remote2.c b/drivers/input/misc/ati_remote2.c index 922c05141585..0501f0e65157 100644 --- a/drivers/input/misc/ati_remote2.c +++ b/drivers/input/misc/ati_remote2.c @@ -509,7 +509,7 @@ static int ati_remote2_setkeycode(struct input_dev *idev, int scancode, int keyc old_keycode = ar2->keycode[mode][index]; ar2->keycode[mode][index] = keycode; - set_bit(keycode, idev->keybit); + __set_bit(keycode, idev->keybit); for (mode = 0; mode < ATI_REMOTE2_MODES; mode++) { for (index = 0; index < ARRAY_SIZE(ati_remote2_key_table); index++) { @@ -518,7 +518,7 @@ static int ati_remote2_setkeycode(struct input_dev *idev, int scancode, int keyc } } - clear_bit(old_keycode, idev->keybit); + __clear_bit(old_keycode, idev->keybit); return 0; } @@ -543,7 +543,7 @@ static int ati_remote2_input_init(struct ati_remote2 *ar2) for (mode = 0; mode < ATI_REMOTE2_MODES; mode++) { for (index = 0; index < ARRAY_SIZE(ati_remote2_key_table); index++) { ar2->keycode[mode][index] = ati_remote2_key_table[index].keycode; - set_bit(ar2->keycode[mode][index], idev->keybit); + __set_bit(ar2->keycode[mode][index], idev->keybit); } } @@ -554,11 +554,11 @@ static int ati_remote2_input_init(struct ati_remote2 *ar2) ar2->keycode[ATI_REMOTE2_AUX3][index] = KEY_PROG3; ar2->keycode[ATI_REMOTE2_AUX4][index] = KEY_PROG4; ar2->keycode[ATI_REMOTE2_PC][index] = KEY_PC; - set_bit(KEY_PROG1, idev->keybit); - set_bit(KEY_PROG2, idev->keybit); - set_bit(KEY_PROG3, idev->keybit); - set_bit(KEY_PROG4, idev->keybit); - set_bit(KEY_PC, idev->keybit); + __set_bit(KEY_PROG1, idev->keybit); + __set_bit(KEY_PROG2, idev->keybit); + __set_bit(KEY_PROG3, idev->keybit); + __set_bit(KEY_PROG4, idev->keybit); + __set_bit(KEY_PC, idev->keybit); idev->rep[REP_DELAY] = 250; idev->rep[REP_PERIOD] = 33; diff --git a/drivers/input/misc/dm355evm_keys.c b/drivers/input/misc/dm355evm_keys.c new file mode 100644 index 000000000000..a63315ce4a6c --- /dev/null +++ b/drivers/input/misc/dm355evm_keys.c @@ -0,0 +1,329 @@ +/* + * dm355evm_keys.c - support buttons and IR remote on DM355 EVM board + * + * Copyright (c) 2008 by David Brownell + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include +#include +#include +#include +#include + +#include + + +/* + * The MSP430 firmware on the DM355 EVM monitors on-board pushbuttons + * and an IR receptor used for the remote control. When any key is + * pressed, or its autorepeat kicks in, an event is sent. This driver + * read those events from the small (32 event) queue and reports them. + * + * Because we communicate with the MSP430 using I2C, and all I2C calls + * in Linux sleep, we need to cons up a kind of threaded IRQ handler + * using a work_struct. The IRQ is active low, but we use it through + * the GPIO controller so we can trigger on falling edges. + * + * Note that physically there can only be one of these devices. + * + * This driver was tested with firmware revision A4. + */ +struct dm355evm_keys { + struct work_struct work; + struct input_dev *input; + struct device *dev; + int irq; +}; + +static irqreturn_t dm355evm_keys_irq(int irq, void *_keys) +{ + struct dm355evm_keys *keys = _keys; + + schedule_work(&keys->work); + return IRQ_HANDLED; +} + +/* These initial keycodes can be remapped by dm355evm_setkeycode(). */ +static struct { + u16 event; + u16 keycode; +} dm355evm_keys[] = { + + /* + * Pushbuttons on the EVM board ... note that the labels for these + * are SW10/SW11/etc on the PC board. The left/right orientation + * comes only from the firmware's documentation, and presumes the + * power connector is immediately in front of you and the IR sensor + * is to the right. (That is, rotate the board counter-clockwise + * by 90 degrees from the SW10/etc and "DM355 EVM" labels.) + */ + { 0x00d8, KEY_OK, }, /* SW12 */ + { 0x00b8, KEY_UP, }, /* SW13 */ + { 0x00e8, KEY_DOWN, }, /* SW11 */ + { 0x0078, KEY_LEFT, }, /* SW14 */ + { 0x00f0, KEY_RIGHT, }, /* SW10 */ + + /* + * IR buttons ... codes assigned to match the universal remote + * provided with the EVM (Philips PM4S) using DVD code 0020. + * + * These event codes match firmware documentation, but other + * remote controls could easily send more RC5-encoded events. + * The PM4S manual was used in several cases to help select + * a keycode reflecting the intended usage. + * + * RC5 codes are 14 bits, with two start bits (0x3 prefix) + * and a toggle bit (masked out below). + */ + { 0x300c, KEY_POWER, }, /* NOTE: docs omit this */ + { 0x3000, KEY_NUMERIC_0, }, + { 0x3001, KEY_NUMERIC_1, }, + { 0x3002, KEY_NUMERIC_2, }, + { 0x3003, KEY_NUMERIC_3, }, + { 0x3004, KEY_NUMERIC_4, }, + { 0x3005, KEY_NUMERIC_5, }, + { 0x3006, KEY_NUMERIC_6, }, + { 0x3007, KEY_NUMERIC_7, }, + { 0x3008, KEY_NUMERIC_8, }, + { 0x3009, KEY_NUMERIC_9, }, + { 0x3022, KEY_ENTER, }, + { 0x30ec, KEY_MODE, }, /* "tv/vcr/..." */ + { 0x300f, KEY_SELECT, }, /* "info" */ + { 0x3020, KEY_CHANNELUP, }, /* "up" */ + { 0x302e, KEY_MENU, }, /* "in/out" */ + { 0x3011, KEY_VOLUMEDOWN, }, /* "left" */ + { 0x300d, KEY_MUTE, }, /* "ok" */ + { 0x3010, KEY_VOLUMEUP, }, /* "right" */ + { 0x301e, KEY_SUBTITLE, }, /* "cc" */ + { 0x3021, KEY_CHANNELDOWN, }, /* "down" */ + { 0x3022, KEY_PREVIOUS, }, + { 0x3026, KEY_SLEEP, }, + { 0x3172, KEY_REWIND, }, /* NOTE: docs wrongly say 0x30ca */ + { 0x3175, KEY_PLAY, }, + { 0x3174, KEY_FASTFORWARD, }, + { 0x3177, KEY_RECORD, }, + { 0x3176, KEY_STOP, }, + { 0x3169, KEY_PAUSE, }, +}; + +static void dm355evm_keys_work(struct work_struct *work) +{ + struct dm355evm_keys *keys; + int status; + + keys = container_of(work, struct dm355evm_keys, work); + + /* For simplicity we ignore INPUT_COUNT and just read + * events until we get the "queue empty" indicator. + * Reading INPUT_LOW decrements the count. + */ + for (;;) { + static u16 last_event; + u16 event; + int keycode; + int i; + + status = dm355evm_msp_read(DM355EVM_MSP_INPUT_HIGH); + if (status < 0) { + dev_dbg(keys->dev, "input high err %d\n", + status); + break; + } + event = status << 8; + + status = dm355evm_msp_read(DM355EVM_MSP_INPUT_LOW); + if (status < 0) { + dev_dbg(keys->dev, "input low err %d\n", + status); + break; + } + event |= status; + if (event == 0xdead) + break; + + /* Press and release a button: two events, same code. + * Press and hold (autorepeat), then release: N events + * (N > 2), same code. For RC5 buttons the toggle bits + * distinguish (for example) "1-autorepeat" from "1 1"; + * but PCB buttons don't support that bit. + * + * So we must synthesize release events. We do that by + * mapping events to a press/release event pair; then + * to avoid adding extra events, skip the second event + * of each pair. + */ + if (event == last_event) { + last_event = 0; + continue; + } + last_event = event; + + /* ignore the RC5 toggle bit */ + event &= ~0x0800; + + /* find the key, or leave it as unknown */ + keycode = KEY_UNKNOWN; + for (i = 0; i < ARRAY_SIZE(dm355evm_keys); i++) { + if (dm355evm_keys[i].event != event) + continue; + keycode = dm355evm_keys[i].keycode; + break; + } + dev_dbg(keys->dev, + "input event 0x%04x--> keycode %d\n", + event, keycode); + + /* report press + release */ + input_report_key(keys->input, keycode, 1); + input_sync(keys->input); + input_report_key(keys->input, keycode, 0); + input_sync(keys->input); + } +} + +static int dm355evm_setkeycode(struct input_dev *dev, int index, int keycode) +{ + u16 old_keycode; + unsigned i; + + if (((unsigned)index) >= ARRAY_SIZE(dm355evm_keys)) + return -EINVAL; + + old_keycode = dm355evm_keys[index].keycode; + dm355evm_keys[index].keycode = keycode; + set_bit(keycode, dev->keybit); + + for (i = 0; i < ARRAY_SIZE(dm355evm_keys); i++) { + if (dm355evm_keys[index].keycode == old_keycode) + goto done; + } + clear_bit(old_keycode, dev->keybit); +done: + return 0; +} + +static int dm355evm_getkeycode(struct input_dev *dev, int index, int *keycode) +{ + if (((unsigned)index) >= ARRAY_SIZE(dm355evm_keys)) + return -EINVAL; + + return dm355evm_keys[index].keycode; +} + +/*----------------------------------------------------------------------*/ + +static int __devinit dm355evm_keys_probe(struct platform_device *pdev) +{ + struct dm355evm_keys *keys; + struct input_dev *input; + int status; + int i; + + /* allocate instance struct and input dev */ + keys = kzalloc(sizeof *keys, GFP_KERNEL); + input = input_allocate_device(); + if (!keys || !input) { + status = -ENOMEM; + goto fail1; + } + + keys->dev = &pdev->dev; + keys->input = input; + INIT_WORK(&keys->work, dm355evm_keys_work); + + /* set up "threaded IRQ handler" */ + status = platform_get_irq(pdev, 0); + if (status < 0) + goto fail1; + keys->irq = status; + + input_set_drvdata(input, keys); + + input->name = "DM355 EVM Controls"; + input->phys = "dm355evm/input0"; + input->dev.parent = &pdev->dev; + + input->id.bustype = BUS_I2C; + input->id.product = 0x0355; + input->id.version = dm355evm_msp_read(DM355EVM_MSP_FIRMREV); + + input->evbit[0] = BIT(EV_KEY); + for (i = 0; i < ARRAY_SIZE(dm355evm_keys); i++) + __set_bit(dm355evm_keys[i].keycode, input->keybit); + + input->setkeycode = dm355evm_setkeycode; + input->getkeycode = dm355evm_getkeycode; + + /* REVISIT: flush the event queue? */ + + status = request_irq(keys->irq, dm355evm_keys_irq, + IRQF_TRIGGER_FALLING, + dev_name(&pdev->dev), keys); + if (status < 0) + goto fail1; + + /* register */ + status = input_register_device(input); + if (status < 0) + goto fail2; + + platform_set_drvdata(pdev, keys); + + return 0; + +fail2: + free_irq(keys->irq, keys); +fail1: + input_free_device(input); + kfree(keys); + dev_err(&pdev->dev, "can't register, err %d\n", status); + + return status; +} + +static int __devexit dm355evm_keys_remove(struct platform_device *pdev) +{ + struct dm355evm_keys *keys = platform_get_drvdata(pdev); + + free_irq(keys->irq, keys); + input_unregister_device(keys->input); + kfree(keys); + + return 0; +} + +/* REVISIT: add suspend/resume when DaVinci supports it. The IRQ should + * be able to wake up the system. When device_may_wakeup(&pdev->dev), call + * enable_irq_wake() on suspend, and disable_irq_wake() on resume. + */ + +/* + * I2C is used to talk to the MSP430, but this platform device is + * exposed by an MFD driver that manages I2C communications. + */ +static struct platform_driver dm355evm_keys_driver = { + .probe = dm355evm_keys_probe, + .remove = __devexit_p(dm355evm_keys_remove), + .driver = { + .owner = THIS_MODULE, + .name = "dm355evm_keys", + }, +}; + +static int __init dm355evm_keys_init(void) +{ + return platform_driver_register(&dm355evm_keys_driver); +} +module_init(dm355evm_keys_init); + +static void __exit dm355evm_keys_exit(void) +{ + platform_driver_unregister(&dm355evm_keys_driver); +} +module_exit(dm355evm_keys_exit); + +MODULE_LICENSE("GPL"); diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c index d6a30cee7bc7..6d67af5387ad 100644 --- a/drivers/input/misc/pcspkr.c +++ b/drivers/input/misc/pcspkr.c @@ -17,6 +17,7 @@ #include #include #include +#include #include MODULE_AUTHOR("Vojtech Pavlik "); diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c index 5bb3ab51b8c6..c806fbf1e174 100644 --- a/drivers/input/misc/rotary_encoder.c +++ b/drivers/input/misc/rotary_encoder.c @@ -26,13 +26,17 @@ #define DRV_NAME "rotary-encoder" struct rotary_encoder { - unsigned int irq_a; - unsigned int irq_b; - unsigned int pos; - unsigned int armed; - unsigned int dir; struct input_dev *input; struct rotary_encoder_platform_data *pdata; + + unsigned int axis; + unsigned int pos; + + unsigned int irq_a; + unsigned int irq_b; + + bool armed; + unsigned char dir; /* 0 - clockwise, 1 - CCW */ }; static irqreturn_t rotary_encoder_irq(int irq, void *dev_id) @@ -53,21 +57,32 @@ static irqreturn_t rotary_encoder_irq(int irq, void *dev_id) if (!encoder->armed) break; - if (encoder->dir) { - /* turning counter-clockwise */ - encoder->pos += pdata->steps; - encoder->pos--; - encoder->pos %= pdata->steps; + if (pdata->relative_axis) { + input_report_rel(encoder->input, pdata->axis, + encoder->dir ? -1 : 1); } else { - /* turning clockwise */ - encoder->pos++; - encoder->pos %= pdata->steps; - } + unsigned int pos = encoder->pos; - input_report_abs(encoder->input, pdata->axis, encoder->pos); + if (encoder->dir) { + /* turning counter-clockwise */ + if (pdata->rollover) + pos += pdata->steps; + if (pos) + pos--; + } else { + /* turning clockwise */ + if (pdata->rollover || pos < pdata->steps) + pos++; + } + if (pdata->rollover) + pos %= pdata->steps; + encoder->pos = pos; + input_report_abs(encoder->input, pdata->axis, + encoder->pos); + } input_sync(encoder->input); - encoder->armed = 0; + encoder->armed = false; break; case 0x1: @@ -77,7 +92,7 @@ static irqreturn_t rotary_encoder_irq(int irq, void *dev_id) break; case 0x3: - encoder->armed = 1; + encoder->armed = true; break; } @@ -113,9 +128,15 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev) input->name = pdev->name; input->id.bustype = BUS_HOST; input->dev.parent = &pdev->dev; - input->evbit[0] = BIT_MASK(EV_ABS); - input_set_abs_params(encoder->input, - pdata->axis, 0, pdata->steps, 0, 1); + + if (pdata->relative_axis) { + input->evbit[0] = BIT_MASK(EV_REL); + input->relbit[0] = BIT_MASK(pdata->axis); + } else { + input->evbit[0] = BIT_MASK(EV_ABS); + input_set_abs_params(encoder->input, + pdata->axis, 0, pdata->steps, 0, 1); + } err = input_register_device(input); if (err) { diff --git a/drivers/input/misc/twl4030-pwrbutton.c b/drivers/input/misc/twl4030-pwrbutton.c new file mode 100644 index 000000000000..f5fc9974a111 --- /dev/null +++ b/drivers/input/misc/twl4030-pwrbutton.c @@ -0,0 +1,145 @@ +/** + * twl4030-pwrbutton.c - TWL4030 Power Button Input Driver + * + * Copyright (C) 2008-2009 Nokia Corporation + * + * Written by Peter De Schrijver + * Several fixes by Felipe Balbi + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define PWR_PWRON_IRQ (1 << 0) + +#define STS_HW_CONDITIONS 0xf + +static irqreturn_t powerbutton_irq(int irq, void *_pwr) +{ + struct input_dev *pwr = _pwr; + int err; + u8 value; + +#ifdef CONFIG_LOCKDEP + /* WORKAROUND for lockdep forcing IRQF_DISABLED on us, which + * we don't want and can't tolerate since this is a threaded + * IRQ and can sleep due to the i2c reads it has to issue. + * Although it might be friendlier not to borrow this thread + * context... + */ + local_irq_enable(); +#endif + + err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &value, + STS_HW_CONDITIONS); + if (!err) { + input_report_key(pwr, KEY_POWER, value & PWR_PWRON_IRQ); + input_sync(pwr); + } else { + dev_err(pwr->dev.parent, "twl4030: i2c error %d while reading" + " TWL4030 PM_MASTER STS_HW_CONDITIONS register\n", err); + } + + return IRQ_HANDLED; +} + +static int __devinit twl4030_pwrbutton_probe(struct platform_device *pdev) +{ + struct input_dev *pwr; + int irq = platform_get_irq(pdev, 0); + int err; + + pwr = input_allocate_device(); + if (!pwr) { + dev_dbg(&pdev->dev, "Can't allocate power button\n"); + return -ENOMEM; + } + + pwr->evbit[0] = BIT_MASK(EV_KEY); + pwr->keybit[BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER); + pwr->name = "twl4030_pwrbutton"; + pwr->phys = "twl4030_pwrbutton/input0"; + pwr->dev.parent = &pdev->dev; + + err = request_irq(irq, powerbutton_irq, + IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, + "twl4030_pwrbutton", pwr); + if (err < 0) { + dev_dbg(&pdev->dev, "Can't get IRQ for pwrbutton: %d\n", err); + goto free_input_dev; + } + + err = input_register_device(pwr); + if (err) { + dev_dbg(&pdev->dev, "Can't register power button: %d\n", err); + goto free_irq; + } + + platform_set_drvdata(pdev, pwr); + + return 0; + +free_irq: + free_irq(irq, NULL); +free_input_dev: + input_free_device(pwr); + return err; +} + +static int __devexit twl4030_pwrbutton_remove(struct platform_device *pdev) +{ + struct input_dev *pwr = platform_get_drvdata(pdev); + int irq = platform_get_irq(pdev, 0); + + free_irq(irq, pwr); + input_unregister_device(pwr); + + return 0; +} + +struct platform_driver twl4030_pwrbutton_driver = { + .probe = twl4030_pwrbutton_probe, + .remove = __devexit_p(twl4030_pwrbutton_remove), + .driver = { + .name = "twl4030_pwrbutton", + .owner = THIS_MODULE, + }, +}; + +static int __init twl4030_pwrbutton_init(void) +{ + return platform_driver_register(&twl4030_pwrbutton_driver); +} +module_init(twl4030_pwrbutton_init); + +static void __exit twl4030_pwrbutton_exit(void) +{ + platform_driver_unregister(&twl4030_pwrbutton_driver); +} +module_exit(twl4030_pwrbutton_exit); + +MODULE_ALIAS("platform:twl4030_pwrbutton"); +MODULE_DESCRIPTION("Triton2 Power Button"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Peter De Schrijver "); +MODULE_AUTHOR("Felipe Balbi "); + diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index 46b7caeb2817..c5a49aba418f 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -54,27 +54,28 @@ static int uinput_dev_event(struct input_dev *dev, unsigned int type, unsigned i return 0; } +/* Atomically allocate an ID for the given request. Returns 0 on success. */ static int uinput_request_alloc_id(struct uinput_device *udev, struct uinput_request *request) { - /* Atomically allocate an ID for the given request. Returns 0 on success. */ int id; int err = -1; spin_lock(&udev->requests_lock); - for (id = 0; id < UINPUT_NUM_REQUESTS; id++) + for (id = 0; id < UINPUT_NUM_REQUESTS; id++) { if (!udev->requests[id]) { request->id = id; udev->requests[id] = request; err = 0; break; } + } spin_unlock(&udev->requests_lock); return err; } -static struct uinput_request* uinput_request_find(struct uinput_device *udev, int id) +static struct uinput_request *uinput_request_find(struct uinput_device *udev, int id) { /* Find an input request, by ID. Returns NULL if the ID isn't valid. */ if (id >= UINPUT_NUM_REQUESTS || id < 0) @@ -99,14 +100,51 @@ static void uinput_request_done(struct uinput_device *udev, struct uinput_reques complete(&request->done); } -static int uinput_request_submit(struct input_dev *dev, struct uinput_request *request) +static int uinput_request_submit(struct uinput_device *udev, struct uinput_request *request) { - /* Tell our userspace app about this new request by queueing an input event */ - uinput_dev_event(dev, EV_UINPUT, request->code, request->id); + int retval; - /* Wait for the request to complete */ - wait_for_completion(&request->done); - return request->retval; + retval = uinput_request_reserve_slot(udev, request); + if (retval) + return retval; + + retval = mutex_lock_interruptible(&udev->mutex); + if (retval) + return retval; + + if (udev->state != UIST_CREATED) { + retval = -ENODEV; + goto out; + } + + /* Tell our userspace app about this new request by queueing an input event */ + uinput_dev_event(udev->dev, EV_UINPUT, request->code, request->id); + + out: + mutex_unlock(&udev->mutex); + return retval; +} + +/* + * Fail all ouitstanding requests so handlers don't wait for the userspace + * to finish processing them. + */ +static void uinput_flush_requests(struct uinput_device *udev) +{ + struct uinput_request *request; + int i; + + spin_lock(&udev->requests_lock); + + for (i = 0; i < UINPUT_NUM_REQUESTS; i++) { + request = udev->requests[i]; + if (request) { + request->retval = -ENODEV; + uinput_request_done(udev, request); + } + } + + spin_unlock(&udev->requests_lock); } static void uinput_dev_set_gain(struct input_dev *dev, u16 gain) @@ -126,6 +164,7 @@ static int uinput_dev_playback(struct input_dev *dev, int effect_id, int value) static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *effect, struct ff_effect *old) { + struct uinput_device *udev = input_get_drvdata(dev); struct uinput_request request; int retval; @@ -146,15 +185,18 @@ static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *eff request.u.upload.effect = effect; request.u.upload.old = old; - retval = uinput_request_reserve_slot(input_get_drvdata(dev), &request); - if (!retval) - retval = uinput_request_submit(dev, &request); + retval = uinput_request_submit(udev, &request); + if (!retval) { + wait_for_completion(&request.done); + retval = request.retval; + } return retval; } static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id) { + struct uinput_device *udev = input_get_drvdata(dev); struct uinput_request request; int retval; @@ -166,9 +208,11 @@ static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id) request.code = UI_FF_ERASE; request.u.effect_id = effect_id; - retval = uinput_request_reserve_slot(input_get_drvdata(dev), &request); - if (!retval) - retval = uinput_request_submit(dev, &request); + retval = uinput_request_submit(udev, &request); + if (!retval) { + wait_for_completion(&request.done); + retval = request.retval; + } return retval; } @@ -176,20 +220,24 @@ static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id) static void uinput_destroy_device(struct uinput_device *udev) { const char *name, *phys; + struct input_dev *dev = udev->dev; + enum uinput_state old_state = udev->state; - if (udev->dev) { - name = udev->dev->name; - phys = udev->dev->phys; - if (udev->state == UIST_CREATED) - input_unregister_device(udev->dev); - else - input_free_device(udev->dev); + udev->state = UIST_NEW_DEVICE; + + if (dev) { + name = dev->name; + phys = dev->phys; + if (old_state == UIST_CREATED) { + uinput_flush_requests(udev); + input_unregister_device(dev); + } else { + input_free_device(dev); + } kfree(name); kfree(phys); udev->dev = NULL; } - - udev->state = UIST_NEW_DEVICE; } static int uinput_create_device(struct uinput_device *udev) diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig index c66cc3d08c2f..8a2c5b14c8d8 100644 --- a/drivers/input/mouse/Kconfig +++ b/drivers/input/mouse/Kconfig @@ -303,4 +303,22 @@ config MOUSE_MAPLE To compile this driver as a module choose M here: the module will be called maplemouse. +config MOUSE_SYNAPTICS_I2C + tristate "Synaptics I2C Touchpad support" + depends on I2C + help + This driver supports Synaptics I2C touchpad controller on eXeda + mobile device. + The device will not work the synaptics X11 driver because + (i) it reports only relative coordinates and has no capabilities + to report absolute coordinates + (ii) the eXeda device itself uses Xfbdev as X Server and it does + not allow using xf86-input-* drivers. + + Say y here if you have eXeda device and want to use a Synaptics + I2C Touchpad. + + To compile this driver as a module, choose M here: the + module will be called synaptics_i2c. + endif diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile index 472189468d67..010f265ec152 100644 --- a/drivers/input/mouse/Makefile +++ b/drivers/input/mouse/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_MOUSE_PS2) += psmouse.o obj-$(CONFIG_MOUSE_PXA930_TRKBALL) += pxa930_trkball.o obj-$(CONFIG_MOUSE_RISCPC) += rpcmouse.o obj-$(CONFIG_MOUSE_SERIAL) += sermouse.o +obj-$(CONFIG_MOUSE_SYNAPTICS_I2C) += synaptics_i2c.o obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o psmouse-objs := psmouse-base.o synaptics.o diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index daecc75c72e6..5547e2429fbe 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -38,25 +38,25 @@ static const struct alps_model_info alps_model_data[] = { { { 0x32, 0x02, 0x14 }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Toshiba Salellite Pro M10 */ - { { 0x33, 0x02, 0x0a }, 0x88, 0xf8, ALPS_OLDPROTO }, /* UMAX-530T */ + { { 0x33, 0x02, 0x0a }, 0x88, 0xf8, ALPS_OLDPROTO }, /* UMAX-530T */ { { 0x53, 0x02, 0x0a }, 0xf8, 0xf8, 0 }, { { 0x53, 0x02, 0x14 }, 0xf8, 0xf8, 0 }, - { { 0x60, 0x03, 0xc8 }, 0xf8, 0xf8, 0 }, /* HP ze1115 */ + { { 0x60, 0x03, 0xc8 }, 0xf8, 0xf8, 0 }, /* HP ze1115 */ { { 0x63, 0x02, 0x0a }, 0xf8, 0xf8, 0 }, { { 0x63, 0x02, 0x14 }, 0xf8, 0xf8, 0 }, - { { 0x63, 0x02, 0x28 }, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Fujitsu Siemens S6010 */ - { { 0x63, 0x02, 0x3c }, 0x8f, 0x8f, ALPS_WHEEL }, /* Toshiba Satellite S2400-103 */ - { { 0x63, 0x02, 0x50 }, 0xef, 0xef, ALPS_FW_BK_1 }, /* NEC Versa L320 */ + { { 0x63, 0x02, 0x28 }, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Fujitsu Siemens S6010 */ + { { 0x63, 0x02, 0x3c }, 0x8f, 0x8f, ALPS_WHEEL }, /* Toshiba Satellite S2400-103 */ + { { 0x63, 0x02, 0x50 }, 0xef, 0xef, ALPS_FW_BK_1 }, /* NEC Versa L320 */ { { 0x63, 0x02, 0x64 }, 0xf8, 0xf8, 0 }, - { { 0x63, 0x03, 0xc8 }, 0xf8, 0xf8, ALPS_PASS }, /* Dell Latitude D800 */ - { { 0x73, 0x00, 0x0a }, 0xf8, 0xf8, ALPS_DUALPOINT }, /* ThinkPad R61 8918-5QG */ + { { 0x63, 0x03, 0xc8 }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D800 */ + { { 0x73, 0x00, 0x0a }, 0xf8, 0xf8, ALPS_DUALPOINT }, /* ThinkPad R61 8918-5QG */ { { 0x73, 0x02, 0x0a }, 0xf8, 0xf8, 0 }, - { { 0x73, 0x02, 0x14 }, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Ahtec Laptop */ + { { 0x73, 0x02, 0x14 }, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Ahtec Laptop */ { { 0x20, 0x02, 0x0e }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */ { { 0x22, 0x02, 0x0a }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, { { 0x22, 0x02, 0x14 }, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */ { { 0x62, 0x02, 0x14 }, 0xcf, 0xcf, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude E6500 */ - { { 0x73, 0x02, 0x50 }, 0xcf, 0xcf, ALPS_FW_BK_1 } /* Dell Vostro 1400 */ + { { 0x73, 0x02, 0x50 }, 0xcf, 0xcf, ALPS_FW_BK_1 }, /* Dell Vostro 1400 */ }; /* @@ -132,18 +132,23 @@ static void alps_process_packet(struct psmouse *psmouse) ges = packet[2] & 1; fin = packet[2] & 2; - input_report_key(dev, BTN_LEFT, left); - input_report_key(dev, BTN_RIGHT, right); - input_report_key(dev, BTN_MIDDLE, middle); - if ((priv->i->flags & ALPS_DUALPOINT) && z == 127) { input_report_rel(dev2, REL_X, (x > 383 ? (x - 768) : x)); input_report_rel(dev2, REL_Y, -(y > 255 ? (y - 512) : y)); + + input_report_key(dev2, BTN_LEFT, left); + input_report_key(dev2, BTN_RIGHT, right); + input_report_key(dev2, BTN_MIDDLE, middle); + input_sync(dev); input_sync(dev2); return; } + input_report_key(dev, BTN_LEFT, left); + input_report_key(dev, BTN_RIGHT, right); + input_report_key(dev, BTN_MIDDLE, middle); + /* Convert hardware tap to a reasonable Z value */ if (ges && !fin) z = 40; diff --git a/drivers/input/mouse/appletouch.c b/drivers/input/mouse/appletouch.c index e0140fdc02a5..908b5b44052f 100644 --- a/drivers/input/mouse/appletouch.c +++ b/drivers/input/mouse/appletouch.c @@ -361,7 +361,7 @@ static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact, (!is_increasing && xy_sensors[i - 1] < xy_sensors[i])) { (*fingers)++; is_increasing = 1; - } else if (i > 0 && xy_sensors[i - 1] >= xy_sensors[i]) { + } else if (i > 0 && (xy_sensors[i - 1] - xy_sensors[i] > threshold)) { is_increasing = 0; } diff --git a/drivers/input/mouse/lifebook.c b/drivers/input/mouse/lifebook.c index 15ac3205ac05..dcd4236af1e3 100644 --- a/drivers/input/mouse/lifebook.c +++ b/drivers/input/mouse/lifebook.c @@ -159,21 +159,22 @@ static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse) if (!dev2) printk(KERN_WARNING "lifebook.c: got relative packet " "but no relative device set up\n"); - } else if (lifebook_use_6byte_proto) { - input_report_abs(dev1, ABS_X, - ((packet[1] & 0x3f) << 6) | (packet[2] & 0x3f)); - input_report_abs(dev1, ABS_Y, - 4096 - (((packet[4] & 0x3f) << 6) | (packet[5] & 0x3f))); } else { - input_report_abs(dev1, ABS_X, - (packet[1] | ((packet[0] & 0x30) << 4))); - input_report_abs(dev1, ABS_Y, - 1024 - (packet[2] | ((packet[0] & 0xC0) << 2))); + if (lifebook_use_6byte_proto) { + input_report_abs(dev1, ABS_X, + ((packet[1] & 0x3f) << 6) | (packet[2] & 0x3f)); + input_report_abs(dev1, ABS_Y, + 4096 - (((packet[4] & 0x3f) << 6) | (packet[5] & 0x3f))); + } else { + input_report_abs(dev1, ABS_X, + (packet[1] | ((packet[0] & 0x30) << 4))); + input_report_abs(dev1, ABS_Y, + 1024 - (packet[2] | ((packet[0] & 0xC0) << 2))); + } + input_report_key(dev1, BTN_TOUCH, packet[0] & 0x04); + input_sync(dev1); } - input_report_key(dev1, BTN_TOUCH, packet[0] & 0x04); - input_sync(dev1); - if (dev2) { if (relative_packet) { input_report_rel(dev2, REL_X, diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index f8f86de694bb..b407b355dceb 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -327,7 +327,9 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, goto out; } - if (psmouse->packet[1] == PSMOUSE_RET_ID) { + if (psmouse->packet[1] == PSMOUSE_RET_ID || + (psmouse->type == PSMOUSE_HGPK && + psmouse->packet[1] == PSMOUSE_RET_BAT)) { __psmouse_set_state(psmouse, PSMOUSE_IGNORE); serio_reconnect(serio); goto out; diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index f3e4f7b0240d..19984bf06cad 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -180,6 +180,29 @@ static int synaptics_identify(struct psmouse *psmouse) return -1; } +/* + * Read touchpad resolution + * Resolution is left zero if touchpad does not support the query + */ +static int synaptics_resolution(struct psmouse *psmouse) +{ + struct synaptics_data *priv = psmouse->private; + unsigned char res[3]; + + if (SYN_ID_MAJOR(priv->identity) < 4) + return 0; + + if (synaptics_send_cmd(psmouse, SYN_QUE_RESOLUTION, res)) + return 0; + + if ((res[0] != 0) && (res[1] & 0x80) && (res[2] != 0)) { + priv->x_res = res[0]; /* x resolution in units/mm */ + priv->y_res = res[2]; /* y resolution in units/mm */ + } + + return 0; +} + static int synaptics_query_hardware(struct psmouse *psmouse) { if (synaptics_identify(psmouse)) @@ -188,6 +211,8 @@ static int synaptics_query_hardware(struct psmouse *psmouse) return -1; if (synaptics_capability(psmouse)) return -1; + if (synaptics_resolution(psmouse)) + return -1; return 0; } @@ -563,6 +588,9 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv) clear_bit(EV_REL, dev->evbit); clear_bit(REL_X, dev->relbit); clear_bit(REL_Y, dev->relbit); + + dev->absres[ABS_X] = priv->x_res; + dev->absres[ABS_Y] = priv->y_res; } static void synaptics_disconnect(struct psmouse *psmouse) diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h index 02aa4cf7bc77..302382151752 100644 --- a/drivers/input/mouse/synaptics.h +++ b/drivers/input/mouse/synaptics.h @@ -97,6 +97,8 @@ struct synaptics_data { unsigned long int capabilities; /* Capabilities */ unsigned long int ext_cap; /* Extended Capabilities */ unsigned long int identity; /* Identification */ + int x_res; /* X resolution in units/mm */ + int y_res; /* Y resolution in units/mm */ unsigned char pkt_type; /* packet type - old, new, etc */ unsigned char mode; /* current mode byte */ diff --git a/drivers/input/mouse/synaptics_i2c.c b/drivers/input/mouse/synaptics_i2c.c new file mode 100644 index 000000000000..eac9fdde7ee9 --- /dev/null +++ b/drivers/input/mouse/synaptics_i2c.c @@ -0,0 +1,676 @@ +/* + * Synaptics touchpad with I2C interface + * + * Copyright (C) 2009 Compulab, Ltd. + * Mike Rapoport + * Igor Grinberg + * + * 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 +#include +#include +#include +#include +#include +#include + +#define DRIVER_NAME "synaptics_i2c" +/* maximum product id is 15 characters */ +#define PRODUCT_ID_LENGTH 15 +#define REGISTER_LENGTH 8 + +/* + * after soft reset, we should wait for 1 ms + * before the device becomes operational + */ +#define SOFT_RESET_DELAY_MS 3 +/* and after hard reset, we should wait for max 500ms */ +#define HARD_RESET_DELAY_MS 500 + +/* Registers by SMBus address */ +#define PAGE_SEL_REG 0xff +#define DEVICE_STATUS_REG 0x09 + +/* Registers by RMI address */ +#define DEV_CONTROL_REG 0x0000 +#define INTERRUPT_EN_REG 0x0001 +#define ERR_STAT_REG 0x0002 +#define INT_REQ_STAT_REG 0x0003 +#define DEV_COMMAND_REG 0x0004 + +#define RMI_PROT_VER_REG 0x0200 +#define MANUFACT_ID_REG 0x0201 +#define PHYS_INT_VER_REG 0x0202 +#define PROD_PROPERTY_REG 0x0203 +#define INFO_QUERY_REG0 0x0204 +#define INFO_QUERY_REG1 (INFO_QUERY_REG0 + 1) +#define INFO_QUERY_REG2 (INFO_QUERY_REG0 + 2) +#define INFO_QUERY_REG3 (INFO_QUERY_REG0 + 3) + +#define PRODUCT_ID_REG0 0x0210 +#define PRODUCT_ID_REG1 (PRODUCT_ID_REG0 + 1) +#define PRODUCT_ID_REG2 (PRODUCT_ID_REG0 + 2) +#define PRODUCT_ID_REG3 (PRODUCT_ID_REG0 + 3) +#define PRODUCT_ID_REG4 (PRODUCT_ID_REG0 + 4) +#define PRODUCT_ID_REG5 (PRODUCT_ID_REG0 + 5) +#define PRODUCT_ID_REG6 (PRODUCT_ID_REG0 + 6) +#define PRODUCT_ID_REG7 (PRODUCT_ID_REG0 + 7) +#define PRODUCT_ID_REG8 (PRODUCT_ID_REG0 + 8) +#define PRODUCT_ID_REG9 (PRODUCT_ID_REG0 + 9) +#define PRODUCT_ID_REG10 (PRODUCT_ID_REG0 + 10) +#define PRODUCT_ID_REG11 (PRODUCT_ID_REG0 + 11) +#define PRODUCT_ID_REG12 (PRODUCT_ID_REG0 + 12) +#define PRODUCT_ID_REG13 (PRODUCT_ID_REG0 + 13) +#define PRODUCT_ID_REG14 (PRODUCT_ID_REG0 + 14) +#define PRODUCT_ID_REG15 (PRODUCT_ID_REG0 + 15) + +#define DATA_REG0 0x0400 +#define ABS_PRESSURE_REG 0x0401 +#define ABS_MSB_X_REG 0x0402 +#define ABS_LSB_X_REG (ABS_MSB_X_REG + 1) +#define ABS_MSB_Y_REG 0x0404 +#define ABS_LSB_Y_REG (ABS_MSB_Y_REG + 1) +#define REL_X_REG 0x0406 +#define REL_Y_REG 0x0407 + +#define DEV_QUERY_REG0 0x1000 +#define DEV_QUERY_REG1 (DEV_QUERY_REG0 + 1) +#define DEV_QUERY_REG2 (DEV_QUERY_REG0 + 2) +#define DEV_QUERY_REG3 (DEV_QUERY_REG0 + 3) +#define DEV_QUERY_REG4 (DEV_QUERY_REG0 + 4) +#define DEV_QUERY_REG5 (DEV_QUERY_REG0 + 5) +#define DEV_QUERY_REG6 (DEV_QUERY_REG0 + 6) +#define DEV_QUERY_REG7 (DEV_QUERY_REG0 + 7) +#define DEV_QUERY_REG8 (DEV_QUERY_REG0 + 8) + +#define GENERAL_2D_CONTROL_REG 0x1041 +#define SENSOR_SENSITIVITY_REG 0x1044 +#define SENS_MAX_POS_MSB_REG 0x1046 +#define SENS_MAX_POS_LSB_REG (SENS_MAX_POS_UPPER_REG + 1) + +/* Register bits */ +/* Device Control Register Bits */ +#define REPORT_RATE_1ST_BIT 6 + +/* Interrupt Enable Register Bits (INTERRUPT_EN_REG) */ +#define F10_ABS_INT_ENA 0 +#define F10_REL_INT_ENA 1 +#define F20_INT_ENA 2 + +/* Interrupt Request Register Bits (INT_REQ_STAT_REG | DEVICE_STATUS_REG) */ +#define F10_ABS_INT_REQ 0 +#define F10_REL_INT_REQ 1 +#define F20_INT_REQ 2 +/* Device Status Register Bits (DEVICE_STATUS_REG) */ +#define STAT_CONFIGURED 6 +#define STAT_ERROR 7 + +/* Device Command Register Bits (DEV_COMMAND_REG) */ +#define RESET_COMMAND 0x01 +#define REZERO_COMMAND 0x02 + +/* Data Register 0 Bits (DATA_REG0) */ +#define GESTURE 3 + +/* Device Query Registers Bits */ +/* DEV_QUERY_REG3 */ +#define HAS_PALM_DETECT 1 +#define HAS_MULTI_FING 2 +#define HAS_SCROLLER 4 +#define HAS_2D_SCROLL 5 + +/* General 2D Control Register Bits (GENERAL_2D_CONTROL_REG) */ +#define NO_DECELERATION 1 +#define REDUCE_REPORTING 3 +#define NO_FILTER 5 + +/* Function Masks */ +/* Device Control Register Masks (DEV_CONTROL_REG) */ +#define REPORT_RATE_MSK 0xc0 +#define SLEEP_MODE_MSK 0x07 + +/* Device Sleep Modes */ +#define FULL_AWAKE 0x0 +#define NORMAL_OP 0x1 +#define LOW_PWR_OP 0x2 +#define VERY_LOW_PWR_OP 0x3 +#define SENS_SLEEP 0x4 +#define SLEEP_MOD 0x5 +#define DEEP_SLEEP 0x6 +#define HIBERNATE 0x7 + +/* Interrupt Register Mask */ +/* (INT_REQ_STAT_REG | DEVICE_STATUS_REG | INTERRUPT_EN_REG) */ +#define INT_ENA_REQ_MSK 0x07 +#define INT_ENA_ABS_MSK 0x01 +#define INT_ENA_REL_MSK 0x02 +#define INT_ENA_F20_MSK 0x04 + +/* Device Status Register Masks (DEVICE_STATUS_REG) */ +#define CONFIGURED_MSK 0x40 +#define ERROR_MSK 0x80 + +/* Data Register 0 Masks */ +#define FINGER_WIDTH_MSK 0xf0 +#define GESTURE_MSK 0x08 +#define SENSOR_STATUS_MSK 0x07 + +/* + * MSB Position Register Masks + * ABS_MSB_X_REG | ABS_MSB_Y_REG | SENS_MAX_POS_MSB_REG | + * DEV_QUERY_REG3 | DEV_QUERY_REG5 + */ +#define MSB_POSITION_MSK 0x1f + +/* Device Query Registers Masks */ + +/* DEV_QUERY_REG2 */ +#define NUM_EXTRA_POS_MSK 0x07 + +/* When in IRQ mode read the device every THREAD_IRQ_SLEEP_SECS */ +#define THREAD_IRQ_SLEEP_SECS 2 +#define THREAD_IRQ_SLEEP_MSECS (THREAD_IRQ_SLEEP_SECS * MSEC_PER_SEC) + +/* + * When in Polling mode and no data received for NO_DATA_THRES msecs + * reduce the polling rate to NO_DATA_SLEEP_MSECS + */ +#define NO_DATA_THRES (MSEC_PER_SEC) +#define NO_DATA_SLEEP_MSECS (MSEC_PER_SEC / 4) + +/* Control touchpad's No Deceleration option */ +static int no_decel = 1; +module_param(no_decel, bool, 0644); +MODULE_PARM_DESC(no_decel, "No Deceleration. Default = 1 (on)"); + +/* Control touchpad's Reduced Reporting option */ +static int reduce_report; +module_param(reduce_report, bool, 0644); +MODULE_PARM_DESC(reduce_report, "Reduced Reporting. Default = 0 (off)"); + +/* Control touchpad's No Filter option */ +static int no_filter; +module_param(no_filter, bool, 0644); +MODULE_PARM_DESC(no_filter, "No Filter. Default = 0 (off)"); + +/* + * touchpad Attention line is Active Low and Open Drain, + * therefore should be connected to pulled up line + * and the irq configuration should be set to Falling Edge Trigger + */ +/* Control IRQ / Polling option */ +static int polling_req; +module_param(polling_req, bool, 0444); +MODULE_PARM_DESC(polling_req, "Request Polling. Default = 0 (use irq)"); + +/* Control Polling Rate */ +static int scan_rate = 80; +module_param(scan_rate, int, 0644); +MODULE_PARM_DESC(scan_rate, "Polling rate in times/sec. Default = 80"); + +/* The main device structure */ +struct synaptics_i2c { + struct i2c_client *client; + struct input_dev *input; + struct delayed_work dwork; + int no_data_count; + int no_decel_param; + int reduce_report_param; + int no_filter_param; + int scan_rate_param; + int scan_ms; +}; + +static inline void set_scan_rate(struct synaptics_i2c *touch, int scan_rate) +{ + touch->scan_ms = MSEC_PER_SEC / scan_rate; + touch->scan_rate_param = scan_rate; +} + +/* + * Driver's initial design makes no race condition possible on i2c bus, + * so there is no need in any locking. + * Keep it in mind, while playing with the code. + */ +static s32 synaptics_i2c_reg_get(struct i2c_client *client, u16 reg) +{ + int ret; + + ret = i2c_smbus_write_byte_data(client, PAGE_SEL_REG, reg >> 8); + if (ret == 0) + ret = i2c_smbus_read_byte_data(client, reg & 0xff); + + return ret; +} + +static s32 synaptics_i2c_reg_set(struct i2c_client *client, u16 reg, u8 val) +{ + int ret; + + ret = i2c_smbus_write_byte_data(client, PAGE_SEL_REG, reg >> 8); + if (ret == 0) + ret = i2c_smbus_write_byte_data(client, reg & 0xff, val); + + return ret; +} + +static s32 synaptics_i2c_word_get(struct i2c_client *client, u16 reg) +{ + int ret; + + ret = i2c_smbus_write_byte_data(client, PAGE_SEL_REG, reg >> 8); + if (ret == 0) + ret = i2c_smbus_read_word_data(client, reg & 0xff); + + return ret; +} + +static int synaptics_i2c_config(struct i2c_client *client) +{ + int ret, control; + u8 int_en; + + /* set Report Rate to Device Highest (>=80) and Sleep to normal */ + ret = synaptics_i2c_reg_set(client, DEV_CONTROL_REG, 0xc1); + if (ret) + return ret; + + /* set Interrupt Disable to Func20 / Enable to Func10) */ + int_en = (polling_req) ? 0 : INT_ENA_ABS_MSK | INT_ENA_REL_MSK; + ret = synaptics_i2c_reg_set(client, INTERRUPT_EN_REG, int_en); + if (ret) + return ret; + + control = synaptics_i2c_reg_get(client, GENERAL_2D_CONTROL_REG); + /* No Deceleration */ + control |= no_decel ? 1 << NO_DECELERATION : 0; + /* Reduced Reporting */ + control |= reduce_report ? 1 << REDUCE_REPORTING : 0; + /* No Filter */ + control |= no_filter ? 1 << NO_FILTER : 0; + ret = synaptics_i2c_reg_set(client, GENERAL_2D_CONTROL_REG, control); + if (ret) + return ret; + + return 0; +} + +static int synaptics_i2c_reset_config(struct i2c_client *client) +{ + int ret; + + /* Reset the Touchpad */ + ret = synaptics_i2c_reg_set(client, DEV_COMMAND_REG, RESET_COMMAND); + if (ret) { + dev_err(&client->dev, "Unable to reset device\n"); + } else { + msleep(SOFT_RESET_DELAY_MS); + ret = synaptics_i2c_config(client); + if (ret) + dev_err(&client->dev, "Unable to config device\n"); + } + + return ret; +} + +static int synaptics_i2c_check_error(struct i2c_client *client) +{ + int status, ret = 0; + + status = i2c_smbus_read_byte_data(client, DEVICE_STATUS_REG) & + (CONFIGURED_MSK | ERROR_MSK); + + if (status != CONFIGURED_MSK) + ret = synaptics_i2c_reset_config(client); + + return ret; +} + +static bool synaptics_i2c_get_input(struct synaptics_i2c *touch) +{ + struct input_dev *input = touch->input; + int xy_delta, gesture; + s32 data; + s8 x_delta, y_delta; + + /* Deal with spontanious resets and errors */ + if (synaptics_i2c_check_error(touch->client)) + return 0; + + /* Get Gesture Bit */ + data = synaptics_i2c_reg_get(touch->client, DATA_REG0); + gesture = (data >> GESTURE) & 0x1; + + /* + * Get Relative axes. we have to get them in one shot, + * so we get 2 bytes starting from REL_X_REG. + */ + xy_delta = synaptics_i2c_word_get(touch->client, REL_X_REG) & 0xffff; + + /* Separate X from Y */ + x_delta = xy_delta & 0xff; + y_delta = (xy_delta >> REGISTER_LENGTH) & 0xff; + + /* Report the button event */ + input_report_key(input, BTN_LEFT, gesture); + + /* Report the deltas */ + input_report_rel(input, REL_X, x_delta); + input_report_rel(input, REL_Y, -y_delta); + input_sync(input); + + return xy_delta || gesture; +} + +static irqreturn_t synaptics_i2c_irq(int irq, void *dev_id) +{ + struct synaptics_i2c *touch = dev_id; + + /* + * We want to have the work run immediately but it might have + * already been scheduled with a delay, that's why we have to + * cancel it first. + */ + cancel_delayed_work(&touch->dwork); + schedule_delayed_work(&touch->dwork, 0); + + return IRQ_HANDLED; +} + +static void synaptics_i2c_check_params(struct synaptics_i2c *touch) +{ + bool reset = false; + + if (scan_rate != touch->scan_rate_param) + set_scan_rate(touch, scan_rate); + + if (no_decel != touch->no_decel_param) { + touch->no_decel_param = no_decel; + reset = true; + } + + if (no_filter != touch->no_filter_param) { + touch->no_filter_param = no_filter; + reset = true; + } + + if (reduce_report != touch->reduce_report_param) { + touch->reduce_report_param = reduce_report; + reset = true; + } + + if (reset) + synaptics_i2c_reset_config(touch->client); +} + +/* Control the Device polling rate / Work Handler sleep time */ +unsigned long synaptics_i2c_adjust_delay(struct synaptics_i2c *touch, + bool have_data) +{ + unsigned long delay, nodata_count_thres; + + if (polling_req) { + delay = touch->scan_ms; + if (have_data) { + touch->no_data_count = 0; + } else { + nodata_count_thres = NO_DATA_THRES / touch->scan_ms; + if (touch->no_data_count < nodata_count_thres) + touch->no_data_count++; + else + delay = NO_DATA_SLEEP_MSECS; + } + return msecs_to_jiffies(delay); + } else { + delay = msecs_to_jiffies(THREAD_IRQ_SLEEP_MSECS); + return round_jiffies_relative(delay); + } +} + +/* Work Handler */ +static void synaptics_i2c_work_handler(struct work_struct *work) +{ + bool have_data; + struct synaptics_i2c *touch = + container_of(work, struct synaptics_i2c, dwork.work); + unsigned long delay; + + synaptics_i2c_check_params(touch); + + have_data = synaptics_i2c_get_input(touch); + delay = synaptics_i2c_adjust_delay(touch, have_data); + + /* + * While interrupt driven, there is no real need to poll the device. + * But touchpads are very sensitive, so there could be errors + * related to physical environment and the attention line isn't + * neccesarily asserted. In such case we can lose the touchpad. + * We poll the device once in THREAD_IRQ_SLEEP_SECS and + * if error is detected, we try to reset and reconfigure the touchpad. + */ + schedule_delayed_work(&touch->dwork, delay); +} + +static int synaptics_i2c_open(struct input_dev *input) +{ + struct synaptics_i2c *touch = input_get_drvdata(input); + int ret; + + ret = synaptics_i2c_reset_config(touch->client); + if (ret) + return ret; + + if (polling_req) + schedule_delayed_work(&touch->dwork, + msecs_to_jiffies(NO_DATA_SLEEP_MSECS)); + + return 0; +} + +static void synaptics_i2c_close(struct input_dev *input) +{ + struct synaptics_i2c *touch = input_get_drvdata(input); + + if (!polling_req) + synaptics_i2c_reg_set(touch->client, INTERRUPT_EN_REG, 0); + + cancel_delayed_work_sync(&touch->dwork); + + /* Save some power */ + synaptics_i2c_reg_set(touch->client, DEV_CONTROL_REG, DEEP_SLEEP); +} + +static void synaptics_i2c_set_input_params(struct synaptics_i2c *touch) +{ + struct input_dev *input = touch->input; + + input->name = touch->client->name; + input->phys = touch->client->adapter->name; + input->id.bustype = BUS_I2C; + input->id.version = synaptics_i2c_word_get(touch->client, + INFO_QUERY_REG0); + input->dev.parent = &touch->client->dev; + input->open = synaptics_i2c_open; + input->close = synaptics_i2c_close; + input_set_drvdata(input, touch); + + /* Register the device as mouse */ + __set_bit(EV_REL, input->evbit); + __set_bit(REL_X, input->relbit); + __set_bit(REL_Y, input->relbit); + + /* Register device's buttons and keys */ + __set_bit(EV_KEY, input->evbit); + __set_bit(BTN_LEFT, input->keybit); +} + +struct synaptics_i2c *synaptics_i2c_touch_create(struct i2c_client *client) +{ + struct synaptics_i2c *touch; + + touch = kzalloc(sizeof(struct synaptics_i2c), GFP_KERNEL); + if (!touch) + return NULL; + + touch->client = client; + touch->no_decel_param = no_decel; + touch->scan_rate_param = scan_rate; + set_scan_rate(touch, scan_rate); + INIT_DELAYED_WORK(&touch->dwork, synaptics_i2c_work_handler); + + return touch; +} + +static int __devinit synaptics_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *dev_id) +{ + int ret; + struct synaptics_i2c *touch; + + touch = synaptics_i2c_touch_create(client); + if (!touch) + return -ENOMEM; + + i2c_set_clientdata(client, touch); + + ret = synaptics_i2c_reset_config(client); + if (ret) + goto err_mem_free; + + if (client->irq < 1) + polling_req = 1; + + touch->input = input_allocate_device(); + if (!touch->input) { + ret = -ENOMEM; + goto err_mem_free; + } + + synaptics_i2c_set_input_params(touch); + + if (!polling_req) { + dev_dbg(&touch->client->dev, + "Requesting IRQ: %d\n", touch->client->irq); + + ret = request_irq(touch->client->irq, synaptics_i2c_irq, + IRQF_DISABLED|IRQ_TYPE_EDGE_FALLING, + DRIVER_NAME, touch); + if (ret) { + dev_warn(&touch->client->dev, + "IRQ request failed: %d, " + "falling back to polling\n", ret); + polling_req = 1; + synaptics_i2c_reg_set(touch->client, + INTERRUPT_EN_REG, 0); + } + } + + if (polling_req) + dev_dbg(&touch->client->dev, + "Using polling at rate: %d times/sec\n", scan_rate); + + /* Register the device in input subsystem */ + ret = input_register_device(touch->input); + if (ret) { + dev_err(&client->dev, + "Input device register failed: %d\n", ret); + goto err_input_free; + } + return 0; + +err_input_free: + input_free_device(touch->input); +err_mem_free: + i2c_set_clientdata(client, NULL); + kfree(touch); + + return ret; +} + +static int __devexit synaptics_i2c_remove(struct i2c_client *client) +{ + struct synaptics_i2c *touch = i2c_get_clientdata(client); + + if (!polling_req) + free_irq(touch->client->irq, touch); + + input_unregister_device(touch->input); + i2c_set_clientdata(client, NULL); + kfree(touch); + + return 0; +} + +#ifdef CONFIG_PM +static int synaptics_i2c_suspend(struct i2c_client *client, pm_message_t mesg) +{ + struct synaptics_i2c *touch = i2c_get_clientdata(client); + + cancel_delayed_work_sync(&touch->dwork); + + /* Save some power */ + synaptics_i2c_reg_set(touch->client, DEV_CONTROL_REG, DEEP_SLEEP); + + return 0; +} + +static int synaptics_i2c_resume(struct i2c_client *client) +{ + int ret; + struct synaptics_i2c *touch = i2c_get_clientdata(client); + + ret = synaptics_i2c_reset_config(client); + if (ret) + return ret; + + schedule_delayed_work(&touch->dwork, + msecs_to_jiffies(NO_DATA_SLEEP_MSECS)); + + return 0; +} +#else +#define synaptics_i2c_suspend NULL +#define synaptics_i2c_resume NULL +#endif + +static const struct i2c_device_id synaptics_i2c_id_table[] = { + { "synaptics_i2c", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, synaptics_i2c_id_table); + +static struct i2c_driver synaptics_i2c_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, + + .probe = synaptics_i2c_probe, + .remove = __devexit_p(synaptics_i2c_remove), + + .suspend = synaptics_i2c_suspend, + .resume = synaptics_i2c_resume, + .id_table = synaptics_i2c_id_table, +}; + +static int __init synaptics_i2c_init(void) +{ + return i2c_add_driver(&synaptics_i2c_driver); +} + +static void __exit synaptics_i2c_exit(void) +{ + i2c_del_driver(&synaptics_i2c_driver); +} + +module_init(synaptics_i2c_init); +module_exit(synaptics_i2c_exit); + +MODULE_DESCRIPTION("Synaptics I2C touchpad driver"); +MODULE_AUTHOR("Mike Rapoport, Igor Grinberg, Compulab"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index 17fd6d46d082..966b8868f792 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c @@ -60,7 +60,6 @@ struct mousedev { int exist; int open; int minor; - char name[16]; struct input_handle handle; wait_queue_head_t wait; struct list_head client_list; @@ -863,19 +862,17 @@ static struct mousedev *mousedev_create(struct input_dev *dev, init_waitqueue_head(&mousedev->wait); if (minor == MOUSEDEV_MIX) - strlcpy(mousedev->name, "mice", sizeof(mousedev->name)); + dev_set_name(&mousedev->dev, "mice"); else - snprintf(mousedev->name, sizeof(mousedev->name), - "mouse%d", minor); + dev_set_name(&mousedev->dev, "mouse%d", minor); mousedev->minor = minor; mousedev->exist = 1; mousedev->handle.dev = input_get_device(dev); - mousedev->handle.name = mousedev->name; + mousedev->handle.name = dev_name(&mousedev->dev); mousedev->handle.handler = handler; mousedev->handle.private = mousedev; - dev_set_name(&mousedev->dev, mousedev->name); mousedev->dev.class = &input_class; if (dev) mousedev->dev.parent = &dev->dev; diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig index da3c3a5d2689..c4b3fbd1a80f 100644 --- a/drivers/input/serio/Kconfig +++ b/drivers/input/serio/Kconfig @@ -192,7 +192,7 @@ config SERIO_RAW config SERIO_XILINX_XPS_PS2 tristate "Xilinx XPS PS/2 Controller Support" - depends on PPC + depends on PPC || MICROBLAZE help This driver supports XPS PS/2 IP from the Xilinx EDK on PowerPC platform. diff --git a/drivers/input/serio/ambakmi.c b/drivers/input/serio/ambakmi.c index a28c06d686e1..89b394183a75 100644 --- a/drivers/input/serio/ambakmi.c +++ b/drivers/input/serio/ambakmi.c @@ -135,7 +135,7 @@ static int amba_kmi_probe(struct amba_device *dev, struct amba_id *id) io->dev.parent = &dev->dev; kmi->io = io; - kmi->base = ioremap(dev->res.start, KMI_SIZE); + kmi->base = ioremap(dev->res.start, resource_size(&dev->res)); if (!kmi->base) { ret = -ENOMEM; goto out; diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 3cffb704e374..f919bf57293c 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -10,6 +10,7 @@ * the Free Software Foundation. */ +#include #include #include #include @@ -921,6 +922,9 @@ static void i8042_dritek_enable(void) #endif #ifdef CONFIG_PM + +static bool i8042_suspended; + /* * Here we try to restore the original BIOS settings. We only want to * do that once, when we really suspend, not when we taking memory @@ -930,11 +934,9 @@ static void i8042_dritek_enable(void) static int i8042_suspend(struct platform_device *dev, pm_message_t state) { - if (dev->dev.power.power_state.event != state.event) { - if (state.event == PM_EVENT_SUSPEND) - i8042_controller_reset(); - - dev->dev.power.power_state = state; + if (!i8042_suspended && state.event == PM_EVENT_SUSPEND) { + i8042_controller_reset(); + i8042_suspended = true; } return 0; @@ -952,7 +954,7 @@ static int i8042_resume(struct platform_device *dev) /* * Do not bother with restoring state if we haven't suspened yet */ - if (dev->dev.power.power_state.event == PM_EVENT_ON) + if (!i8042_suspended) return 0; error = i8042_controller_check(); @@ -998,10 +1000,9 @@ static int i8042_resume(struct platform_device *dev) if (i8042_ports[I8042_KBD_PORT_NO].serio) i8042_enable_kbd_port(); + i8042_suspended = false; i8042_interrupt(0, NULL); - dev->dev.power.power_state = PMSG_ON; - return 0; } #endif /* CONFIG_PM */ diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index bc033250dfcd..fb17573f8f2d 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -41,17 +41,6 @@ MODULE_AUTHOR("Vojtech Pavlik "); MODULE_DESCRIPTION("Serio abstraction core"); MODULE_LICENSE("GPL"); -EXPORT_SYMBOL(serio_interrupt); -EXPORT_SYMBOL(__serio_register_port); -EXPORT_SYMBOL(serio_unregister_port); -EXPORT_SYMBOL(serio_unregister_child_port); -EXPORT_SYMBOL(__serio_register_driver); -EXPORT_SYMBOL(serio_unregister_driver); -EXPORT_SYMBOL(serio_open); -EXPORT_SYMBOL(serio_close); -EXPORT_SYMBOL(serio_rescan); -EXPORT_SYMBOL(serio_reconnect); - /* * serio_mutex protects entire serio subsystem and is taken every time * serio port or driver registrered or unregistered. @@ -506,9 +495,9 @@ static ssize_t serio_set_bind_mode(struct device *dev, struct device_attribute * retval = count; if (!strncmp(buf, "manual", count)) { - serio->manual_bind = 1; + serio->manual_bind = true; } else if (!strncmp(buf, "auto", count)) { - serio->manual_bind = 0; + serio->manual_bind = false; } else { retval = -EINVAL; } @@ -581,7 +570,7 @@ static void serio_add_port(struct serio *serio) "serio: device_add() failed for %s (%s), error: %d\n", serio->phys, serio->name, error); else { - serio->registered = 1; + serio->registered = true; error = sysfs_create_group(&serio->dev.kobj, &serio_id_attr_group); if (error) printk(KERN_ERR @@ -617,7 +606,7 @@ static void serio_destroy_port(struct serio *serio) if (serio->registered) { sysfs_remove_group(&serio->dev.kobj, &serio_id_attr_group); device_del(&serio->dev); - serio->registered = 0; + serio->registered = false; } list_del_init(&serio->node); @@ -692,11 +681,13 @@ void serio_rescan(struct serio *serio) { serio_queue_event(serio, NULL, SERIO_RESCAN_PORT); } +EXPORT_SYMBOL(serio_rescan); void serio_reconnect(struct serio *serio) { serio_queue_event(serio, NULL, SERIO_RECONNECT_CHAIN); } +EXPORT_SYMBOL(serio_reconnect); /* * Submits register request to kseriod for subsequent execution. @@ -707,6 +698,7 @@ void __serio_register_port(struct serio *serio, struct module *owner) serio_init_port(serio); serio_queue_event(serio, owner, SERIO_REGISTER_PORT); } +EXPORT_SYMBOL(__serio_register_port); /* * Synchronously unregisters serio port. @@ -718,6 +710,7 @@ void serio_unregister_port(struct serio *serio) serio_destroy_port(serio); mutex_unlock(&serio_mutex); } +EXPORT_SYMBOL(serio_unregister_port); /* * Safely unregisters child port if one is present. @@ -731,6 +724,7 @@ void serio_unregister_child_port(struct serio *serio) } mutex_unlock(&serio_mutex); } +EXPORT_SYMBOL(serio_unregister_child_port); /* @@ -756,9 +750,9 @@ static ssize_t serio_driver_set_bind_mode(struct device_driver *drv, const char retval = count; if (!strncmp(buf, "manual", count)) { - serio_drv->manual_bind = 1; + serio_drv->manual_bind = true; } else if (!strncmp(buf, "auto", count)) { - serio_drv->manual_bind = 0; + serio_drv->manual_bind = false; } else { retval = -EINVAL; } @@ -818,7 +812,7 @@ static void serio_attach_driver(struct serio_driver *drv) int __serio_register_driver(struct serio_driver *drv, struct module *owner, const char *mod_name) { - int manual_bind = drv->manual_bind; + bool manual_bind = drv->manual_bind; int error; drv->driver.bus = &serio_bus; @@ -829,7 +823,7 @@ int __serio_register_driver(struct serio_driver *drv, struct module *owner, cons * Temporarily disable automatic binding because probing * takes long time and we are better off doing it in kseriod */ - drv->manual_bind = 1; + drv->manual_bind = true; error = driver_register(&drv->driver); if (error) { @@ -844,7 +838,7 @@ int __serio_register_driver(struct serio_driver *drv, struct module *owner, cons * driver to free ports */ if (!manual_bind) { - drv->manual_bind = 0; + drv->manual_bind = false; error = serio_queue_event(drv, NULL, SERIO_ATTACH_DRIVER); if (error) { driver_unregister(&drv->driver); @@ -854,6 +848,7 @@ int __serio_register_driver(struct serio_driver *drv, struct module *owner, cons return 0; } +EXPORT_SYMBOL(__serio_register_driver); void serio_unregister_driver(struct serio_driver *drv) { @@ -861,7 +856,7 @@ void serio_unregister_driver(struct serio_driver *drv) mutex_lock(&serio_mutex); - drv->manual_bind = 1; /* so serio_find_driver ignores it */ + drv->manual_bind = true; /* so serio_find_driver ignores it */ serio_remove_pending_events(drv); start_over: @@ -877,6 +872,7 @@ start_over: driver_unregister(&drv->driver); mutex_unlock(&serio_mutex); } +EXPORT_SYMBOL(serio_unregister_driver); static void serio_set_drv(struct serio *serio, struct serio_driver *drv) { @@ -937,11 +933,11 @@ static int serio_uevent(struct device *dev, struct kobj_uevent_env *env) #ifdef CONFIG_PM static int serio_suspend(struct device *dev, pm_message_t state) { - if (dev->power.power_state.event != state.event) { - if (state.event == PM_EVENT_SUSPEND) - serio_cleanup(to_serio_port(dev)); + struct serio *serio = to_serio_port(dev); - dev->power.power_state = state; + if (!serio->suspended && state.event == PM_EVENT_SUSPEND) { + serio_cleanup(serio); + serio->suspended = true; } return 0; @@ -949,14 +945,15 @@ static int serio_suspend(struct device *dev, pm_message_t state) static int serio_resume(struct device *dev) { + struct serio *serio = to_serio_port(dev); + /* * Driver reconnect can take a while, so better let kseriod * deal with it. */ - if (dev->power.power_state.event != PM_EVENT_ON) { - dev->power.power_state = PMSG_ON; - serio_queue_event(to_serio_port(dev), NULL, - SERIO_RECONNECT_PORT); + if (serio->suspended) { + serio->suspended = false; + serio_queue_event(serio, NULL, SERIO_RECONNECT_PORT); } return 0; @@ -974,6 +971,7 @@ int serio_open(struct serio *serio, struct serio_driver *drv) } return 0; } +EXPORT_SYMBOL(serio_open); /* called from serio_driver->connect/disconnect methods under serio_mutex */ void serio_close(struct serio *serio) @@ -983,6 +981,7 @@ void serio_close(struct serio *serio) serio_set_drv(serio, NULL); } +EXPORT_SYMBOL(serio_close); irqreturn_t serio_interrupt(struct serio *serio, unsigned char data, unsigned int dfl) @@ -1003,6 +1002,7 @@ irqreturn_t serio_interrupt(struct serio *serio, return ret; } +EXPORT_SYMBOL(serio_interrupt); static struct bus_type serio_bus = { .name = "serio", diff --git a/drivers/input/tablet/gtco.c b/drivers/input/tablet/gtco.c index 2e18a1c0c351..3d32d3f4e486 100644 --- a/drivers/input/tablet/gtco.c +++ b/drivers/input/tablet/gtco.c @@ -1050,4 +1050,5 @@ static void __exit gtco_exit(void) module_init(gtco_init); module_exit(gtco_exit); +MODULE_DESCRIPTION("GTCO digitizer USB driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/input/tablet/wacom.h b/drivers/input/tablet/wacom.h index 9710bfd49cf9..9114ae1c7488 100644 --- a/drivers/input/tablet/wacom.h +++ b/drivers/input/tablet/wacom.h @@ -68,6 +68,7 @@ * v1.48 (pc) - Added support for Bamboo1, BambooFun, and Cintiq 12WX * v1.49 (pc) - Added support for USB Tablet PC (0x90, 0x93, and 0x9A) * v1.50 (pc) - Fixed a TabletPC touch bug in 2.6.28 + * v1.51 (pc) - Added support for Intuos4 */ /* @@ -88,7 +89,7 @@ /* * Version Information */ -#define DRIVER_VERSION "v1.50" +#define DRIVER_VERSION "v1.51" #define DRIVER_AUTHOR "Vojtech Pavlik " #define DRIVER_DESC "USB Wacom Graphire and Wacom Intuos tablet driver" #define DRIVER_LICENSE "GPL" @@ -128,6 +129,8 @@ extern void input_dev_g(struct input_dev *input_dev, struct wacom_wac *wacom_wac extern void input_dev_i3s(struct input_dev *input_dev, struct wacom_wac *wacom_wac); extern void input_dev_i3(struct input_dev *input_dev, struct wacom_wac *wacom_wac); extern void input_dev_i(struct input_dev *input_dev, struct wacom_wac *wacom_wac); +extern void input_dev_i4s(struct input_dev *input_dev, struct wacom_wac *wacom_wac); +extern void input_dev_i4(struct input_dev *input_dev, struct wacom_wac *wacom_wac); extern void input_dev_pl(struct input_dev *input_dev, struct wacom_wac *wacom_wac); extern void input_dev_pt(struct input_dev *input_dev, struct wacom_wac *wacom_wac); extern void input_dev_mo(struct input_dev *input_dev, struct wacom_wac *wacom_wac); diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c index b8624f27abf9..a9d5031b855e 100644 --- a/drivers/input/tablet/wacom_sys.c +++ b/drivers/input/tablet/wacom_sys.c @@ -229,6 +229,19 @@ void input_dev_i3(struct input_dev *input_dev, struct wacom_wac *wacom_wac) input_set_abs_params(input_dev, ABS_RY, 0, 4096, 0, 0); } +void input_dev_i4s(struct input_dev *input_dev, struct wacom_wac *wacom_wac) +{ + input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_FINGER); + input_dev->keybit[BIT_WORD(BTN_MISC)] |= BIT_MASK(BTN_0) | BIT_MASK(BTN_1) | BIT_MASK(BTN_2) | BIT_MASK(BTN_3); + input_dev->keybit[BIT_WORD(BTN_MISC)] |= BIT_MASK(BTN_4) | BIT_MASK(BTN_5) | BIT_MASK(BTN_6); + input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0); +} + +void input_dev_i4(struct input_dev *input_dev, struct wacom_wac *wacom_wac) +{ + input_dev->keybit[BIT_WORD(BTN_MISC)] |= BIT_MASK(BTN_7) | BIT_MASK(BTN_8); +} + void input_dev_bee(struct input_dev *input_dev, struct wacom_wac *wacom_wac) { input_dev->keybit[BIT_WORD(BTN_MISC)] |= BIT_MASK(BTN_8) | BIT_MASK(BTN_9); diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index 2638811c61ac..38bf86384aeb 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c @@ -283,10 +283,11 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo) static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo) { unsigned char *data = wacom->data; - int idx; + int idx = 0; /* tool number */ - idx = data[1] & 0x01; + if (wacom->features->type == INTUOS) + idx = data[1] & 0x01; /* Enter report */ if ((data[1] & 0xfc) == 0xc0) { @@ -299,6 +300,7 @@ static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo) switch (wacom->id[idx]) { case 0x812: /* Inking pen */ case 0x801: /* Intuos3 Inking pen */ + case 0x20802: /* Intuos4 Classic Pen */ case 0x012: wacom->tool[idx] = BTN_TOOL_PENCIL; break; @@ -308,6 +310,9 @@ static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo) case 0x823: /* Intuos3 Grip Pen */ case 0x813: /* Intuos3 Classic Pen */ case 0x885: /* Intuos3 Marker Pen */ + case 0x802: /* Intuos4 Grip Pen Eraser */ + case 0x804: /* Intuos4 Marker Pen */ + case 0x40802: /* Intuos4 Classic Pen */ case 0x022: wacom->tool[idx] = BTN_TOOL_PEN; break; @@ -319,10 +324,12 @@ static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo) case 0x09c: case 0x094: case 0x017: /* Intuos3 2D Mouse */ + case 0x806: /* Intuos4 Mouse */ wacom->tool[idx] = BTN_TOOL_MOUSE; break; case 0x096: /* Lens cursor */ case 0x097: /* Intuos3 Lens cursor */ + case 0x006: /* Intuos4 Lens cursor */ wacom->tool[idx] = BTN_TOOL_LENS; break; case 0x82a: /* Eraser */ @@ -333,12 +340,17 @@ static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo) case 0x82b: /* Intuos3 Grip Pen Eraser */ case 0x81b: /* Intuos3 Classic Pen Eraser */ case 0x91b: /* Intuos3 Airbrush Eraser */ + case 0x80c: /* Intuos4 Marker Pen Eraser */ + case 0x80a: /* Intuos4 Grip Pen Eraser */ + case 0x4080a: /* Intuos4 Classic Pen Eraser */ + case 0x90a: /* Intuos4 Airbrush Eraser */ wacom->tool[idx] = BTN_TOOL_RUBBER; break; case 0xd12: case 0x912: case 0x112: case 0x913: /* Intuos3 Airbrush */ + case 0x902: /* Intuos4 Airbrush */ wacom->tool[idx] = BTN_TOOL_AIRBRUSH; break; default: /* Unknown tool */ @@ -349,9 +361,15 @@ static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo) /* Exit report */ if ((data[1] & 0xfe) == 0x80) { + /* + * Reset all states otherwise we lose the initial states + * when in-prox next time + */ wacom_report_abs(wcombo, ABS_X, 0); wacom_report_abs(wcombo, ABS_Y, 0); wacom_report_abs(wcombo, ABS_DISTANCE, 0); + wacom_report_abs(wcombo, ABS_TILT_X, 0); + wacom_report_abs(wcombo, ABS_TILT_Y, 0); if (wacom->tool[idx] >= BTN_TOOL_MOUSE) { wacom_report_key(wcombo, BTN_LEFT, 0); wacom_report_key(wcombo, BTN_MIDDLE, 0); @@ -362,8 +380,6 @@ static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo) wacom_report_abs(wcombo, ABS_RZ, 0); } else { wacom_report_abs(wcombo, ABS_PRESSURE, 0); - wacom_report_abs(wcombo, ABS_TILT_X, 0); - wacom_report_abs(wcombo, ABS_TILT_Y, 0); wacom_report_key(wcombo, BTN_STYLUS, 0); wacom_report_key(wcombo, BTN_STYLUS2, 0); wacom_report_key(wcombo, BTN_TOUCH, 0); @@ -372,6 +388,7 @@ static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo) wacom_report_key(wcombo, wacom->tool[idx], 0); wacom_report_abs(wcombo, ABS_MISC, 0); /* reset tool id */ wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, wacom->serial[idx]); + wacom->id[idx] = 0; return 2; } return 0; @@ -385,6 +402,8 @@ static void wacom_intuos_general(struct wacom_wac *wacom, void *wcombo) /* general pen packet */ if ((data[1] & 0xb8) == 0xa0) { t = (data[6] << 2) | ((data[7] >> 6) & 3); + if (wacom->features->type >= INTUOS4S && wacom->features->type <= INTUOS4L) + t = (t << 1) | (data[1] & 1); wacom_report_abs(wcombo, ABS_PRESSURE, t); wacom_report_abs(wcombo, ABS_TILT_X, ((data[7] << 1) & 0x7e) | (data[8] >> 7)); @@ -409,7 +428,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo) { unsigned char *data = wacom->data; unsigned int t; - int idx, result; + int idx = 0, result; if (data[0] != 2 && data[0] != 5 && data[0] != 6 && data[0] != 12) { dbg("wacom_intuos_irq: received unknown report #%d", data[0]); @@ -417,7 +436,8 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo) } /* tool number */ - idx = data[1] & 0x01; + if (wacom->features->type == INTUOS) + idx = data[1] & 0x01; /* pad packets. Works as a second tool and is always in prox */ if (data[0] == 12) { @@ -425,25 +445,54 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo) if (wacom->tool[1] != BTN_TOOL_FINGER) wacom->tool[1] = BTN_TOOL_FINGER; - wacom_report_key(wcombo, BTN_0, (data[5] & 0x01)); - wacom_report_key(wcombo, BTN_1, (data[5] & 0x02)); - wacom_report_key(wcombo, BTN_2, (data[5] & 0x04)); - wacom_report_key(wcombo, BTN_3, (data[5] & 0x08)); - wacom_report_key(wcombo, BTN_4, (data[6] & 0x01)); - wacom_report_key(wcombo, BTN_5, (data[6] & 0x02)); - wacom_report_key(wcombo, BTN_6, (data[6] & 0x04)); - wacom_report_key(wcombo, BTN_7, (data[6] & 0x08)); - wacom_report_key(wcombo, BTN_8, (data[5] & 0x10)); - wacom_report_key(wcombo, BTN_9, (data[6] & 0x10)); - wacom_report_abs(wcombo, ABS_RX, ((data[1] & 0x1f) << 8) | data[2]); - wacom_report_abs(wcombo, ABS_RY, ((data[3] & 0x1f) << 8) | data[4]); + if (wacom->features->type >= INTUOS4S && wacom->features->type <= INTUOS4L) { + wacom_report_key(wcombo, BTN_0, (data[2] & 0x01)); + wacom_report_key(wcombo, BTN_1, (data[3] & 0x01)); + wacom_report_key(wcombo, BTN_2, (data[3] & 0x02)); + wacom_report_key(wcombo, BTN_3, (data[3] & 0x04)); + wacom_report_key(wcombo, BTN_4, (data[3] & 0x08)); + wacom_report_key(wcombo, BTN_5, (data[3] & 0x10)); + wacom_report_key(wcombo, BTN_6, (data[3] & 0x20)); + if (data[1] & 0x80) { + wacom_report_abs(wcombo, ABS_WHEEL, (data[1] & 0x7f)); + } else { + /* Out of proximity, clear wheel value. */ + wacom_report_abs(wcombo, ABS_WHEEL, 0); + } + if (wacom->features->type != INTUOS4S) { + wacom_report_key(wcombo, BTN_7, (data[3] & 0x40)); + wacom_report_key(wcombo, BTN_8, (data[3] & 0x80)); + } + if (data[1] | (data[2] & 0x01) | data[3]) { + wacom_report_key(wcombo, wacom->tool[1], 1); + wacom_report_abs(wcombo, ABS_MISC, PAD_DEVICE_ID); + } else { + wacom_report_key(wcombo, wacom->tool[1], 0); + wacom_report_abs(wcombo, ABS_MISC, 0); + } + } else { + wacom_report_key(wcombo, BTN_0, (data[5] & 0x01)); + wacom_report_key(wcombo, BTN_1, (data[5] & 0x02)); + wacom_report_key(wcombo, BTN_2, (data[5] & 0x04)); + wacom_report_key(wcombo, BTN_3, (data[5] & 0x08)); + wacom_report_key(wcombo, BTN_4, (data[6] & 0x01)); + wacom_report_key(wcombo, BTN_5, (data[6] & 0x02)); + wacom_report_key(wcombo, BTN_6, (data[6] & 0x04)); + wacom_report_key(wcombo, BTN_7, (data[6] & 0x08)); + wacom_report_key(wcombo, BTN_8, (data[5] & 0x10)); + wacom_report_key(wcombo, BTN_9, (data[6] & 0x10)); + wacom_report_abs(wcombo, ABS_RX, ((data[1] & 0x1f) << 8) | data[2]); + wacom_report_abs(wcombo, ABS_RY, ((data[3] & 0x1f) << 8) | data[4]); - if ((data[5] & 0x1f) | (data[6] & 0x1f) | (data[1] & 0x1f) | - data[2] | (data[3] & 0x1f) | data[4]) - wacom_report_key(wcombo, wacom->tool[1], 1); - else - wacom_report_key(wcombo, wacom->tool[1], 0); - wacom_report_abs(wcombo, ABS_MISC, PAD_DEVICE_ID); + if ((data[5] & 0x1f) | (data[6] & 0x1f) | (data[1] & 0x1f) | + data[2] | (data[3] & 0x1f) | data[4]) { + wacom_report_key(wcombo, wacom->tool[1], 1); + wacom_report_abs(wcombo, ABS_MISC, PAD_DEVICE_ID); + } else { + wacom_report_key(wcombo, wacom->tool[1], 0); + wacom_report_abs(wcombo, ABS_MISC, 0); + } + } wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xffffffff); return 1; } @@ -453,10 +502,16 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo) if (result) return result-1; - /* Only large I3 and I1 & I2 support Lense Cursor */ + /* don't proceed if we don't know the ID */ + if (!wacom->id[idx]) + return 0; + + /* Only large Intuos support Lense Cursor */ if ((wacom->tool[idx] == BTN_TOOL_LENS) && ((wacom->features->type == INTUOS3) - || (wacom->features->type == INTUOS3S))) + || (wacom->features->type == INTUOS3S) + || (wacom->features->type == INTUOS4) + || (wacom->features->type == INTUOS4S))) return 0; /* Cintiq doesn't send data when RDY bit isn't set */ @@ -476,8 +531,8 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo) /* process general packets */ wacom_intuos_general(wacom, wcombo); - /* 4D mouse, 2D mouse, marker pen rotation, or Lens cursor packets */ - if ((data[1] & 0xbc) == 0xa8 || (data[1] & 0xbe) == 0xb0) { + /* 4D mouse, 2D mouse, marker pen rotation, tilt mouse, or Lens cursor packets */ + if ((data[1] & 0xbc) == 0xa8 || (data[1] & 0xbe) == 0xb0 || (data[1] & 0xbc) == 0xac) { if (data[1] & 0x02) { /* Rotation packet */ @@ -506,20 +561,36 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo) wacom_report_abs(wcombo, ABS_THROTTLE, (data[8] & 0x08) ? -t : t); } else if (wacom->tool[idx] == BTN_TOOL_MOUSE) { - /* 2D mouse packet */ - wacom_report_key(wcombo, BTN_LEFT, data[8] & 0x04); - wacom_report_key(wcombo, BTN_MIDDLE, data[8] & 0x08); - wacom_report_key(wcombo, BTN_RIGHT, data[8] & 0x10); - wacom_report_rel(wcombo, REL_WHEEL, (data[8] & 0x01) + /* I4 mouse */ + if (wacom->features->type >= INTUOS4S && wacom->features->type <= INTUOS4L) { + wacom_report_key(wcombo, BTN_LEFT, data[6] & 0x01); + wacom_report_key(wcombo, BTN_MIDDLE, data[6] & 0x02); + wacom_report_key(wcombo, BTN_RIGHT, data[6] & 0x04); + wacom_report_rel(wcombo, REL_WHEEL, ((data[7] & 0x80) >> 7) + - ((data[7] & 0x40) >> 6)); + wacom_report_key(wcombo, BTN_SIDE, data[6] & 0x08); + wacom_report_key(wcombo, BTN_EXTRA, data[6] & 0x10); + + wacom_report_abs(wcombo, ABS_TILT_X, + ((data[7] << 1) & 0x7e) | (data[8] >> 7)); + wacom_report_abs(wcombo, ABS_TILT_Y, data[8] & 0x7f); + } else { + /* 2D mouse packet */ + wacom_report_key(wcombo, BTN_LEFT, data[8] & 0x04); + wacom_report_key(wcombo, BTN_MIDDLE, data[8] & 0x08); + wacom_report_key(wcombo, BTN_RIGHT, data[8] & 0x10); + wacom_report_rel(wcombo, REL_WHEEL, (data[8] & 0x01) - ((data[8] & 0x02) >> 1)); - /* I3 2D mouse side buttons */ - if (wacom->features->type >= INTUOS3S && wacom->features->type <= INTUOS3L) { - wacom_report_key(wcombo, BTN_SIDE, data[8] & 0x40); - wacom_report_key(wcombo, BTN_EXTRA, data[8] & 0x20); + /* I3 2D mouse side buttons */ + if (wacom->features->type >= INTUOS3S && wacom->features->type <= INTUOS3L) { + wacom_report_key(wcombo, BTN_SIDE, data[8] & 0x40); + wacom_report_key(wcombo, BTN_EXTRA, data[8] & 0x20); + } } - - } else if (wacom->features->type < INTUOS3S || wacom->features->type == INTUOS3L) { + } else if ((wacom->features->type < INTUOS3S || wacom->features->type == INTUOS3L || + wacom->features->type == INTUOS4L) && + wacom->tool[idx] == BTN_TOOL_LENS) { /* Lens cursor packets */ wacom_report_key(wcombo, BTN_LEFT, data[8] & 0x01); wacom_report_key(wcombo, BTN_MIDDLE, data[8] & 0x02); @@ -581,6 +652,7 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, void *wcombo) } } else if (touchOut || !prox) { /* force touch out-prox */ wacom_report_abs(wcombo, ABS_MISC, TOUCH_DEVICE_ID); + wacom_report_key(wcombo, wacom->tool[1], 0); wacom_report_key(wcombo, BTN_TOUCH, 0); touchOut = 0; touchInProx = 1; @@ -669,6 +741,9 @@ int wacom_wac_irq(struct wacom_wac *wacom_wac, void *wcombo) case INTUOS3S: case INTUOS3: case INTUOS3L: + case INTUOS4S: + case INTUOS4: + case INTUOS4L: case CINTIQ: case WACOM_BEE: return wacom_intuos_irq(wacom_wac, wcombo); @@ -706,6 +781,14 @@ void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_w case INTUOS: input_dev_i(input_dev, wacom_wac); break; + case INTUOS4: + case INTUOS4L: + input_dev_i4(input_dev, wacom_wac); + /* fall through */ + case INTUOS4S: + input_dev_i4s(input_dev, wacom_wac); + input_dev_i(input_dev, wacom_wac); + break; case PL: case PTU: case TABLETPC: @@ -766,6 +849,10 @@ static struct wacom_features wacom_features[] = { { "Wacom Intuos3 12x19", 10, 97536, 60960, 1023, 63, INTUOS3L }, { "Wacom Intuos3 6x11", 10, 54204, 31750, 1023, 63, INTUOS3 }, { "Wacom Intuos3 4x6", 10, 31496, 19685, 1023, 63, INTUOS3S }, + { "Wacom Intuos4 4x6", 10, 31496, 19685, 2047, 63, INTUOS4S }, + { "Wacom Intuos4 6x9", 10, 44704, 27940, 2047, 63, INTUOS4 }, + { "Wacom Intuos4 8x13", 10, 65024, 40640, 2047, 63, INTUOS4L }, + { "Wacom Intuos4 12x19", 10, 97536, 60960, 2047, 63, INTUOS4L }, { "Wacom Cintiq 21UX", 10, 87200, 65600, 1023, 63, CINTIQ }, { "Wacom Cintiq 20WSX", 10, 86680, 54180, 1023, 63, WACOM_BEE }, { "Wacom Cintiq 12WX", 10, 53020, 33440, 1023, 63, WACOM_BEE }, @@ -825,6 +912,10 @@ static struct usb_device_id wacom_ids[] = { { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB4) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB5) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB7) }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB8) }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB9) }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xBA) }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xBB) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x3F) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC5) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC6) }, diff --git a/drivers/input/tablet/wacom_wac.h b/drivers/input/tablet/wacom_wac.h index f9c8b69673b7..c10235aba7e5 100644 --- a/drivers/input/tablet/wacom_wac.h +++ b/drivers/input/tablet/wacom_wac.h @@ -25,6 +25,9 @@ enum { INTUOS3S, INTUOS3, INTUOS3L, + INTUOS4S, + INTUOS4, + INTUOS4L, CINTIQ, WACOM_BEE, WACOM_MO, diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index b01fd61dadcc..72e2712c7e2a 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -111,6 +111,15 @@ config TOUCHSCREEN_DA9034 Say Y here to enable the support for the touchscreen found on Dialog Semiconductor DA9034 PMIC. +config TOUCHSCREEN_EETI + tristate "EETI touchscreen panel support" + depends on I2C + help + Say Y here to enable support for I2C connected EETI touch panels. + + To compile this driver as a module, choose M here: the + module will be called eeti_ts. + config TOUCHSCREEN_FUJITSU tristate "Fujitsu serial touchscreen" select SERIO @@ -341,6 +350,21 @@ config TOUCHSCREEN_WM9713 Say Y here to enable support for the Wolfson Microelectronics WM9713 touchscreen controller. +config TOUCHSCREEN_WM97XX_ATMEL + tristate "WM97xx Atmel accelerated touch" + depends on TOUCHSCREEN_WM97XX && (AVR32 || ARCH_AT91) + help + Say Y here for support for streaming mode with WM97xx touchscreens + on Atmel AT91 or AVR32 systems with an AC97C module. + + Be aware that this will use channel B in the controller for + streaming data, this must not conflict with other AC97C drivers. + + If unsure, say N. + + To compile this driver as a module, choose M here: the module will + be called atmel-wm97xx. + config TOUCHSCREEN_WM97XX_MAINSTONE tristate "WM97xx Mainstone accelerated touch" depends on TOUCHSCREEN_WM97XX && ARCH_PXA @@ -466,4 +490,12 @@ config TOUCHSCREEN_TSC2007 To compile this driver as a module, choose M here: the module will be called tsc2007. +config TOUCHSCREEN_W90X900 + tristate "W90P910 touchscreen driver" + help + Say Y here if you have a W90P910 based touchscreen. + + To compile this driver as a module, choose M here: the + module will be called w90p910_ts. + endif diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 6700f7b9d165..3e1c5e0b952f 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) += atmel_tsadcc.o obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o obj-$(CONFIG_TOUCHSCREEN_CORGI) += corgi_ts.o obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o +obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o obj-$(CONFIG_TOUCHSCREEN_INEXIO) += inexio.o @@ -35,5 +36,7 @@ obj-$(CONFIG_TOUCHSCREEN_DA9034) += da9034-ts.o wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9705) += wm9705.o wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9712) += wm9712.o wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9713) += wm9713.o +obj-$(CONFIG_TOUCHSCREEN_WM97XX_ATMEL) += atmel-wm97xx.o obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE) += mainstone-wm97xx.o obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o +obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index 2b01e56568f8..ba9d38c3f412 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -83,6 +83,7 @@ struct ads7846_packet { struct ads7846 { struct input_dev *input; char phys[32]; + char name[32]; struct spi_device *spi; @@ -97,6 +98,8 @@ struct ads7846 { u16 x_plate_ohms; u16 pressure_max; + bool swap_xy; + struct ads7846_packet *packet; struct spi_transfer xfer[18]; @@ -599,6 +602,10 @@ static void ads7846_rx(void *ads) dev_dbg(&ts->spi->dev, "DOWN\n"); #endif } + + if (ts->swap_xy) + swap(x, y); + input_report_abs(input, ABS_X, x); input_report_abs(input, ABS_Y, y); input_report_abs(input, ABS_PRESSURE, Rt); @@ -917,6 +924,7 @@ static int __devinit ads7846_probe(struct spi_device *spi) ts->spi = spi; ts->input = input_dev; ts->vref_mv = pdata->vref_mv; + ts->swap_xy = pdata->swap_xy; hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); ts->timer.function = ads7846_timer; @@ -958,8 +966,9 @@ static int __devinit ads7846_probe(struct spi_device *spi) ts->wait_for_sync = pdata->wait_for_sync ? : null_wait_for_sync; snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&spi->dev)); + snprintf(ts->name, sizeof(ts->name), "ADS%d Touchscreen", ts->model); - input_dev->name = "ADS784x Touchscreen"; + input_dev->name = ts->name; input_dev->phys = ts->phys; input_dev->dev.parent = &spi->dev; @@ -1141,9 +1150,15 @@ static int __devinit ads7846_probe(struct spi_device *spi) if (request_irq(spi->irq, ads7846_irq, IRQF_TRIGGER_FALLING, spi->dev.driver->name, ts)) { - dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq); - err = -EBUSY; - goto err_free_gpio; + dev_info(&spi->dev, + "trying pin change workaround on irq %d\n", spi->irq); + err = request_irq(spi->irq, ads7846_irq, + IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, + spi->dev.driver->name, ts); + if (err) { + dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq); + goto err_free_gpio; + } } err = ads784x_hwmon_register(spi, ts); diff --git a/drivers/input/touchscreen/atmel-wm97xx.c b/drivers/input/touchscreen/atmel-wm97xx.c new file mode 100644 index 000000000000..35377f583e28 --- /dev/null +++ b/drivers/input/touchscreen/atmel-wm97xx.c @@ -0,0 +1,446 @@ +/* + * Atmel AT91 and AVR32 continuous touch screen driver for Wolfson WM97xx AC97 + * codecs. + * + * Copyright (C) 2008 - 2009 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define AC97C_ICA 0x10 +#define AC97C_CBRHR 0x30 +#define AC97C_CBSR 0x38 +#define AC97C_CBMR 0x3c +#define AC97C_IER 0x54 +#define AC97C_IDR 0x58 + +#define AC97C_RXRDY (1 << 4) +#define AC97C_OVRUN (1 << 5) + +#define AC97C_CMR_SIZE_20 (0 << 16) +#define AC97C_CMR_SIZE_18 (1 << 16) +#define AC97C_CMR_SIZE_16 (2 << 16) +#define AC97C_CMR_SIZE_10 (3 << 16) +#define AC97C_CMR_CEM_LITTLE (1 << 18) +#define AC97C_CMR_CEM_BIG (0 << 18) +#define AC97C_CMR_CENA (1 << 21) + +#define AC97C_INT_CBEVT (1 << 4) + +#define AC97C_SR_CAEVT (1 << 3) + +#define AC97C_CH_MASK(slot) \ + (0x7 << (3 * (slot - 3))) +#define AC97C_CH_ASSIGN(slot, channel) \ + (AC97C_CHANNEL_##channel << (3 * (slot - 3))) +#define AC97C_CHANNEL_NONE 0x0 +#define AC97C_CHANNEL_B 0x2 + +#define ac97c_writel(chip, reg, val) \ + __raw_writel((val), (chip)->regs + AC97C_##reg) +#define ac97c_readl(chip, reg) \ + __raw_readl((chip)->regs + AC97C_##reg) + +#ifdef CONFIG_CPU_AT32AP700X +#define ATMEL_WM97XX_AC97C_IOMEM (0xfff02800) +#define ATMEL_WM97XX_AC97C_IRQ (29) +#define ATMEL_WM97XX_GPIO_DEFAULT (32+16) /* Pin 16 on port B. */ +#else +#error Unkown CPU, this driver only supports AT32AP700X CPUs. +#endif + +struct continuous { + u16 id; /* codec id */ + u8 code; /* continuous code */ + u8 reads; /* number of coord reads per read cycle */ + u32 speed; /* number of coords per second */ +}; + +#define WM_READS(sp) ((sp / HZ) + 1) + +static const struct continuous cinfo[] = { + {WM9705_ID2, 0, WM_READS(94), 94}, + {WM9705_ID2, 1, WM_READS(188), 188}, + {WM9705_ID2, 2, WM_READS(375), 375}, + {WM9705_ID2, 3, WM_READS(750), 750}, + {WM9712_ID2, 0, WM_READS(94), 94}, + {WM9712_ID2, 1, WM_READS(188), 188}, + {WM9712_ID2, 2, WM_READS(375), 375}, + {WM9712_ID2, 3, WM_READS(750), 750}, + {WM9713_ID2, 0, WM_READS(94), 94}, + {WM9713_ID2, 1, WM_READS(120), 120}, + {WM9713_ID2, 2, WM_READS(154), 154}, + {WM9713_ID2, 3, WM_READS(188), 188}, +}; + +/* Continuous speed index. */ +static int sp_idx; + +/* + * Pen sampling frequency (Hz) in continuous mode. + */ +static int cont_rate = 188; +module_param(cont_rate, int, 0); +MODULE_PARM_DESC(cont_rate, "Sampling rate in continuous mode (Hz)"); + +/* + * Pen down detection. + * + * This driver can either poll or use an interrupt to indicate a pen down + * event. If the irq request fails then it will fall back to polling mode. + */ +static int pen_int = 1; +module_param(pen_int, int, 0); +MODULE_PARM_DESC(pen_int, "Pen down detection (1 = interrupt, 0 = polling)"); + +/* + * Pressure readback. + * + * Set to 1 to read back pen down pressure. + */ +static int pressure; +module_param(pressure, int, 0); +MODULE_PARM_DESC(pressure, "Pressure readback (1 = pressure, 0 = no pressure)"); + +/* + * AC97 touch data slot. + * + * Touch screen readback data ac97 slot. + */ +static int ac97_touch_slot = 5; +module_param(ac97_touch_slot, int, 0); +MODULE_PARM_DESC(ac97_touch_slot, "Touch screen data slot AC97 number"); + +/* + * GPIO line number. + * + * Set to GPIO number where the signal from the WM97xx device is hooked up. + */ +static int atmel_gpio_line = ATMEL_WM97XX_GPIO_DEFAULT; +module_param(atmel_gpio_line, int, 0); +MODULE_PARM_DESC(atmel_gpio_line, "GPIO line number connected to WM97xx"); + +struct atmel_wm97xx { + struct wm97xx *wm; + struct timer_list pen_timer; + void __iomem *regs; + unsigned long ac97c_irq; + unsigned long gpio_pen; + unsigned long gpio_irq; + unsigned short x; + unsigned short y; +}; + +static irqreturn_t atmel_wm97xx_channel_b_interrupt(int irq, void *dev_id) +{ + struct atmel_wm97xx *atmel_wm97xx = dev_id; + struct wm97xx *wm = atmel_wm97xx->wm; + int status = ac97c_readl(atmel_wm97xx, CBSR); + irqreturn_t retval = IRQ_NONE; + + if (status & AC97C_OVRUN) { + dev_dbg(&wm->touch_dev->dev, "AC97C overrun\n"); + ac97c_readl(atmel_wm97xx, CBRHR); + retval = IRQ_HANDLED; + } else if (status & AC97C_RXRDY) { + u16 data; + u16 value; + u16 source; + u16 pen_down; + + data = ac97c_readl(atmel_wm97xx, CBRHR); + value = data & 0x0fff; + source = data & WM97XX_ADCSRC_MASK; + pen_down = (data & WM97XX_PEN_DOWN) >> 8; + + if (source == WM97XX_ADCSEL_X) + atmel_wm97xx->x = value; + if (source == WM97XX_ADCSEL_Y) + atmel_wm97xx->y = value; + + if (!pressure && source == WM97XX_ADCSEL_Y) { + input_report_abs(wm->input_dev, ABS_X, atmel_wm97xx->x); + input_report_abs(wm->input_dev, ABS_Y, atmel_wm97xx->y); + input_report_key(wm->input_dev, BTN_TOUCH, pen_down); + input_sync(wm->input_dev); + } else if (pressure && source == WM97XX_ADCSEL_PRES) { + input_report_abs(wm->input_dev, ABS_X, atmel_wm97xx->x); + input_report_abs(wm->input_dev, ABS_Y, atmel_wm97xx->y); + input_report_abs(wm->input_dev, ABS_PRESSURE, value); + input_report_key(wm->input_dev, BTN_TOUCH, value); + input_sync(wm->input_dev); + } + + retval = IRQ_HANDLED; + } + + return retval; +} + +static void atmel_wm97xx_acc_pen_up(struct wm97xx *wm) +{ + struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(wm->touch_dev); + struct input_dev *input_dev = wm->input_dev; + int pen_down = gpio_get_value(atmel_wm97xx->gpio_pen); + + if (pen_down != 0) { + mod_timer(&atmel_wm97xx->pen_timer, + jiffies + msecs_to_jiffies(1)); + } else { + if (pressure) + input_report_abs(input_dev, ABS_PRESSURE, 0); + input_report_key(input_dev, BTN_TOUCH, 0); + input_sync(input_dev); + } +} + +static void atmel_wm97xx_pen_timer(unsigned long data) +{ + atmel_wm97xx_acc_pen_up((struct wm97xx *)data); +} + +static int atmel_wm97xx_acc_startup(struct wm97xx *wm) +{ + struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(wm->touch_dev); + int idx = 0; + + if (wm->ac97 == NULL) + return -ENODEV; + + for (idx = 0; idx < ARRAY_SIZE(cinfo); idx++) { + if (wm->id != cinfo[idx].id) + continue; + + sp_idx = idx; + + if (cont_rate <= cinfo[idx].speed) + break; + } + + wm->acc_rate = cinfo[sp_idx].code; + wm->acc_slot = ac97_touch_slot; + dev_info(&wm->touch_dev->dev, "atmel accelerated touchscreen driver, " + "%d samples/sec\n", cinfo[sp_idx].speed); + + if (pen_int) { + unsigned long reg; + + wm->pen_irq = atmel_wm97xx->gpio_irq; + + switch (wm->id) { + case WM9712_ID2: /* Fall through. */ + case WM9713_ID2: + /* + * Use GPIO 13 (PEN_DOWN) to assert GPIO line 3 + * (PENDOWN). + */ + wm97xx_config_gpio(wm, WM97XX_GPIO_13, WM97XX_GPIO_IN, + WM97XX_GPIO_POL_HIGH, + WM97XX_GPIO_STICKY, + WM97XX_GPIO_WAKE); + wm97xx_config_gpio(wm, WM97XX_GPIO_3, WM97XX_GPIO_OUT, + WM97XX_GPIO_POL_HIGH, + WM97XX_GPIO_NOTSTICKY, + WM97XX_GPIO_NOWAKE); + case WM9705_ID2: /* Fall through. */ + /* + * Enable touch data slot in AC97 controller channel B. + */ + reg = ac97c_readl(atmel_wm97xx, ICA); + reg &= ~AC97C_CH_MASK(wm->acc_slot); + reg |= AC97C_CH_ASSIGN(wm->acc_slot, B); + ac97c_writel(atmel_wm97xx, ICA, reg); + + /* + * Enable channel and interrupt for RXRDY and OVERRUN. + */ + ac97c_writel(atmel_wm97xx, CBMR, AC97C_CMR_CENA + | AC97C_CMR_CEM_BIG + | AC97C_CMR_SIZE_16 + | AC97C_OVRUN + | AC97C_RXRDY); + /* Dummy read to empty RXRHR. */ + ac97c_readl(atmel_wm97xx, CBRHR); + /* + * Enable interrupt for channel B in the AC97 + * controller. + */ + ac97c_writel(atmel_wm97xx, IER, AC97C_INT_CBEVT); + break; + default: + dev_err(&wm->touch_dev->dev, "pen down irq not " + "supported on this device\n"); + pen_int = 0; + break; + } + } + + return 0; +} + +static void atmel_wm97xx_acc_shutdown(struct wm97xx *wm) +{ + if (pen_int) { + struct atmel_wm97xx *atmel_wm97xx = + platform_get_drvdata(wm->touch_dev); + unsigned long ica; + + switch (wm->id & 0xffff) { + case WM9705_ID2: /* Fall through. */ + case WM9712_ID2: /* Fall through. */ + case WM9713_ID2: + /* Disable slot and turn off channel B interrupts. */ + ica = ac97c_readl(atmel_wm97xx, ICA); + ica &= ~AC97C_CH_MASK(wm->acc_slot); + ac97c_writel(atmel_wm97xx, ICA, ica); + ac97c_writel(atmel_wm97xx, IDR, AC97C_INT_CBEVT); + ac97c_writel(atmel_wm97xx, CBMR, 0); + wm->pen_irq = 0; + break; + default: + dev_err(&wm->touch_dev->dev, "unknown codec\n"); + break; + } + } +} + +static void atmel_wm97xx_irq_enable(struct wm97xx *wm, int enable) +{ + /* Intentionally left empty. */ +} + +static struct wm97xx_mach_ops atmel_mach_ops = { + .acc_enabled = 1, + .acc_pen_up = atmel_wm97xx_acc_pen_up, + .acc_startup = atmel_wm97xx_acc_startup, + .acc_shutdown = atmel_wm97xx_acc_shutdown, + .irq_enable = atmel_wm97xx_irq_enable, + .irq_gpio = WM97XX_GPIO_3, +}; + +static int __init atmel_wm97xx_probe(struct platform_device *pdev) +{ + struct wm97xx *wm = platform_get_drvdata(pdev); + struct atmel_wm97xx *atmel_wm97xx; + int ret; + + atmel_wm97xx = kzalloc(sizeof(struct atmel_wm97xx), GFP_KERNEL); + if (!atmel_wm97xx) { + dev_dbg(&pdev->dev, "out of memory\n"); + return -ENOMEM; + } + + atmel_wm97xx->wm = wm; + atmel_wm97xx->regs = (void *)ATMEL_WM97XX_AC97C_IOMEM; + atmel_wm97xx->ac97c_irq = ATMEL_WM97XX_AC97C_IRQ; + atmel_wm97xx->gpio_pen = atmel_gpio_line; + atmel_wm97xx->gpio_irq = gpio_to_irq(atmel_wm97xx->gpio_pen); + + setup_timer(&atmel_wm97xx->pen_timer, atmel_wm97xx_pen_timer, + (unsigned long)wm); + + ret = request_irq(atmel_wm97xx->ac97c_irq, + atmel_wm97xx_channel_b_interrupt, + IRQF_SHARED, "atmel-wm97xx-ch-b", atmel_wm97xx); + if (ret) { + dev_dbg(&pdev->dev, "could not request ac97c irq\n"); + goto err; + } + + platform_set_drvdata(pdev, atmel_wm97xx); + + ret = wm97xx_register_mach_ops(wm, &atmel_mach_ops); + if (ret) + goto err_irq; + + return ret; + +err_irq: + free_irq(atmel_wm97xx->ac97c_irq, atmel_wm97xx); +err: + platform_set_drvdata(pdev, NULL); + kfree(atmel_wm97xx); + return ret; +} + +static int __exit atmel_wm97xx_remove(struct platform_device *pdev) +{ + struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(pdev); + struct wm97xx *wm = atmel_wm97xx->wm; + + ac97c_writel(atmel_wm97xx, IDR, AC97C_INT_CBEVT); + free_irq(atmel_wm97xx->ac97c_irq, atmel_wm97xx); + del_timer_sync(&atmel_wm97xx->pen_timer); + wm97xx_unregister_mach_ops(wm); + platform_set_drvdata(pdev, NULL); + kfree(atmel_wm97xx); + + return 0; +} + +#ifdef CONFIG_PM +static int atmel_wm97xx_suspend(struct platform_device *pdev, pm_message_t msg) +{ + struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(pdev); + + ac97c_writel(atmel_wm97xx, IDR, AC97C_INT_CBEVT); + disable_irq(atmel_wm97xx->gpio_irq); + del_timer_sync(&atmel_wm97xx->pen_timer); + + return 0; +} + +static int atmel_wm97xx_resume(struct platform_device *pdev) +{ + struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(pdev); + struct wm97xx *wm = atmel_wm97xx->wm; + + if (wm->input_dev->users) { + enable_irq(atmel_wm97xx->gpio_irq); + ac97c_writel(atmel_wm97xx, IER, AC97C_INT_CBEVT); + } + + return 0; +} +#else +#define atmel_wm97xx_suspend NULL +#define atmel_wm97xx_resume NULL +#endif + +static struct platform_driver atmel_wm97xx_driver = { + .remove = __exit_p(atmel_wm97xx_remove), + .driver = { + .name = "wm97xx-touch", + }, + .suspend = atmel_wm97xx_suspend, + .resume = atmel_wm97xx_resume, +}; + +static int __init atmel_wm97xx_init(void) +{ + return platform_driver_probe(&atmel_wm97xx_driver, atmel_wm97xx_probe); +} +module_init(atmel_wm97xx_init); + +static void __exit atmel_wm97xx_exit(void) +{ + platform_driver_unregister(&atmel_wm97xx_driver); +} +module_exit(atmel_wm97xx_exit); + +MODULE_AUTHOR("Hans-Christian Egtvedt "); +MODULE_DESCRIPTION("wm97xx continuous touch driver for Atmel AT91 and AVR32"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c new file mode 100644 index 000000000000..3ab92222a525 --- /dev/null +++ b/drivers/input/touchscreen/eeti_ts.c @@ -0,0 +1,286 @@ +/* + * Touch Screen driver for EETI's I2C connected touch screen panels + * Copyright (c) 2009 Daniel Mack + * + * See EETI's software guide for the protocol specification: + * http://home.eeti.com.tw/web20/eg/guide.htm + * + * Based on migor_ts.c + * Copyright (c) 2008 Magnus Damm + * Copyright (c) 2007 Ujjwal Pande + * + * This file 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 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 library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static int flip_x; +module_param(flip_x, bool, 0644); +MODULE_PARM_DESC(flip_x, "flip x coordinate"); + +static int flip_y; +module_param(flip_y, bool, 0644); +MODULE_PARM_DESC(flip_y, "flip y coordinate"); + +struct eeti_ts_priv { + struct i2c_client *client; + struct input_dev *input; + struct work_struct work; + struct mutex mutex; + int irq; +}; + +#define EETI_TS_BITDEPTH (11) +#define EETI_MAXVAL ((1 << (EETI_TS_BITDEPTH + 1)) - 1) + +#define REPORT_BIT_PRESSED (1 << 0) +#define REPORT_BIT_AD0 (1 << 1) +#define REPORT_BIT_AD1 (1 << 2) +#define REPORT_BIT_HAS_PRESSURE (1 << 6) +#define REPORT_RES_BITS(v) (((v) >> 1) + EETI_TS_BITDEPTH) + +static void eeti_ts_read(struct work_struct *work) +{ + char buf[6]; + unsigned int x, y, res, pressed, to = 100; + struct eeti_ts_priv *priv = + container_of(work, struct eeti_ts_priv, work); + + mutex_lock(&priv->mutex); + + while (!gpio_get_value(irq_to_gpio(priv->irq)) && --to) + i2c_master_recv(priv->client, buf, sizeof(buf)); + + if (!to) { + dev_err(&priv->client->dev, + "unable to clear IRQ - line stuck?\n"); + goto out; + } + + /* drop non-report packets */ + if (!(buf[0] & 0x80)) + goto out; + + pressed = buf[0] & REPORT_BIT_PRESSED; + res = REPORT_RES_BITS(buf[0] & (REPORT_BIT_AD0 | REPORT_BIT_AD1)); + x = buf[2] | (buf[1] << 8); + y = buf[4] | (buf[3] << 8); + + /* fix the range to 11 bits */ + x >>= res - EETI_TS_BITDEPTH; + y >>= res - EETI_TS_BITDEPTH; + + if (flip_x) + x = EETI_MAXVAL - x; + + if (flip_y) + y = EETI_MAXVAL - y; + + if (buf[0] & REPORT_BIT_HAS_PRESSURE) + input_report_abs(priv->input, ABS_PRESSURE, buf[5]); + + input_report_abs(priv->input, ABS_X, x); + input_report_abs(priv->input, ABS_Y, y); + input_report_key(priv->input, BTN_TOUCH, !!pressed); + input_sync(priv->input); + +out: + mutex_unlock(&priv->mutex); +} + +static irqreturn_t eeti_ts_isr(int irq, void *dev_id) +{ + struct eeti_ts_priv *priv = dev_id; + + /* postpone I2C transactions as we are atomic */ + schedule_work(&priv->work); + + return IRQ_HANDLED; +} + +static int eeti_ts_open(struct input_dev *dev) +{ + struct eeti_ts_priv *priv = input_get_drvdata(dev); + + enable_irq(priv->irq); + + /* Read the events once to arm the IRQ */ + eeti_ts_read(&priv->work); + + return 0; +} + +static void eeti_ts_close(struct input_dev *dev) +{ + struct eeti_ts_priv *priv = input_get_drvdata(dev); + + disable_irq(priv->irq); + cancel_work_sync(&priv->work); +} + +static int __devinit eeti_ts_probe(struct i2c_client *client, + const struct i2c_device_id *idp) +{ + struct eeti_ts_priv *priv; + struct input_dev *input; + int err = -ENOMEM; + + /* In contrast to what's described in the datasheet, there seems + * to be no way of probing the presence of that device using I2C + * commands. So we need to blindly believe it is there, and wait + * for interrupts to occur. */ + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) { + dev_err(&client->dev, "failed to allocate driver data\n"); + goto err0; + } + + mutex_init(&priv->mutex); + input = input_allocate_device(); + + if (!input) { + dev_err(&client->dev, "Failed to allocate input device.\n"); + goto err1; + } + + input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); + + input_set_abs_params(input, ABS_X, 0, EETI_MAXVAL, 0, 0); + input_set_abs_params(input, ABS_Y, 0, EETI_MAXVAL, 0, 0); + input_set_abs_params(input, ABS_PRESSURE, 0, 0xff, 0, 0); + + input->name = client->name; + input->id.bustype = BUS_I2C; + input->dev.parent = &client->dev; + input->open = eeti_ts_open; + input->close = eeti_ts_close; + + priv->client = client; + priv->input = input; + priv->irq = client->irq; + + INIT_WORK(&priv->work, eeti_ts_read); + i2c_set_clientdata(client, priv); + input_set_drvdata(input, priv); + + err = input_register_device(input); + if (err) + goto err1; + + err = request_irq(priv->irq, eeti_ts_isr, IRQF_TRIGGER_FALLING, + client->name, priv); + if (err) { + dev_err(&client->dev, "Unable to request touchscreen IRQ.\n"); + goto err2; + } + + /* Disable the irq for now. It will be enabled once the input device + * is opened. */ + disable_irq(priv->irq); + + device_init_wakeup(&client->dev, 0); + return 0; + +err2: + input_unregister_device(input); + input = NULL; /* so we dont try to free it below */ +err1: + input_free_device(input); + i2c_set_clientdata(client, NULL); + kfree(priv); +err0: + return err; +} + +static int __devexit eeti_ts_remove(struct i2c_client *client) +{ + struct eeti_ts_priv *priv = i2c_get_clientdata(client); + + free_irq(priv->irq, priv); + input_unregister_device(priv->input); + i2c_set_clientdata(client, NULL); + kfree(priv); + + return 0; +} + +#ifdef CONFIG_PM +static int eeti_ts_suspend(struct i2c_client *client, pm_message_t mesg) +{ + struct eeti_ts_priv *priv = i2c_get_clientdata(client); + + if (device_may_wakeup(&client->dev)) + enable_irq_wake(priv->irq); + + return 0; +} + +static int eeti_ts_resume(struct i2c_client *client) +{ + struct eeti_ts_priv *priv = i2c_get_clientdata(client); + + if (device_may_wakeup(&client->dev)) + disable_irq_wake(priv->irq); + + return 0; +} +#else +#define eeti_ts_suspend NULL +#define eeti_ts_resume NULL +#endif + +static const struct i2c_device_id eeti_ts_id[] = { + { "eeti_ts", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, eeti_ts_id); + +static struct i2c_driver eeti_ts_driver = { + .driver = { + .name = "eeti_ts", + }, + .probe = eeti_ts_probe, + .remove = __devexit_p(eeti_ts_remove), + .suspend = eeti_ts_suspend, + .resume = eeti_ts_resume, + .id_table = eeti_ts_id, +}; + +static int __init eeti_ts_init(void) +{ + return i2c_add_driver(&eeti_ts_driver); +} + +static void __exit eeti_ts_exit(void) +{ + i2c_del_driver(&eeti_ts_driver); +} + +MODULE_DESCRIPTION("EETI Touchscreen driver"); +MODULE_AUTHOR("Daniel Mack "); +MODULE_LICENSE("GPL"); + +module_init(eeti_ts_init); +module_exit(eeti_ts_exit); + diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c index 948e167557f1..880f58c6a7c4 100644 --- a/drivers/input/touchscreen/tsc2007.c +++ b/drivers/input/touchscreen/tsc2007.c @@ -257,7 +257,7 @@ static int tsc2007_probe(struct i2c_client *client, struct input_dev *input_dev; int err; - if (!pdata) { + if (!pdata || !pdata->get_pendown_state) { dev_err(&client->dev, "platform data is required!\n"); return -EINVAL; } diff --git a/drivers/input/touchscreen/w90p910_ts.c b/drivers/input/touchscreen/w90p910_ts.c new file mode 100644 index 000000000000..6071f5882572 --- /dev/null +++ b/drivers/input/touchscreen/w90p910_ts.c @@ -0,0 +1,350 @@ +/* + * Copyright (c) 2008 Nuvoton technology corporation. + * + * Wan ZongShun + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation;version 2 of the License. + * + */ + +#include +#include +#include +#include +#include +#include + +/* ADC controller bit defines */ +#define ADC_DELAY 0xf00 +#define ADC_DOWN 0x01 +#define ADC_TSC_Y (0x01 << 8) +#define ADC_TSC_X (0x00 << 8) +#define TSC_FOURWIRE (~(0x03 << 1)) +#define ADC_CLK_EN (0x01 << 28) /* ADC clock enable */ +#define ADC_READ_CON (0x01 << 12) +#define ADC_CONV (0x01 << 13) +#define ADC_SEMIAUTO (0x01 << 14) +#define ADC_WAITTRIG (0x03 << 14) +#define ADC_RST1 (0x01 << 16) +#define ADC_RST0 (0x00 << 16) +#define ADC_EN (0x01 << 17) +#define ADC_INT (0x01 << 18) +#define WT_INT (0x01 << 20) +#define ADC_INT_EN (0x01 << 21) +#define LVD_INT_EN (0x01 << 22) +#define WT_INT_EN (0x01 << 23) +#define ADC_DIV (0x04 << 1) /* div = 6 */ + +enum ts_state { + TS_WAIT_NEW_PACKET, /* We are waiting next touch report */ + TS_WAIT_X_COORD, /* We are waiting for ADC to report X coord */ + TS_WAIT_Y_COORD, /* We are waiting for ADC to report Y coord */ + TS_IDLE, /* Input device is closed, don't do anything */ +}; + +struct w90p910_ts { + struct input_dev *input; + struct timer_list timer; + int irq_num; + void __iomem *clocken; + void __iomem *ts_reg; + spinlock_t lock; + enum ts_state state; +}; + +static void w90p910_report_event(struct w90p910_ts *w90p910_ts, bool down) +{ + struct input_dev *dev = w90p910_ts->input; + + if (down) { + input_report_abs(dev, ABS_X, + __raw_readl(w90p910_ts->ts_reg + 0x0c)); + input_report_abs(dev, ABS_Y, + __raw_readl(w90p910_ts->ts_reg + 0x10)); + } + + input_report_key(dev, BTN_TOUCH, down); + input_sync(dev); +} + +static void w90p910_prepare_x_reading(struct w90p910_ts *w90p910_ts) +{ + unsigned long ctlreg; + + __raw_writel(ADC_TSC_X, w90p910_ts->ts_reg + 0x04); + ctlreg = __raw_readl(w90p910_ts->ts_reg); + ctlreg &= ~(ADC_WAITTRIG | WT_INT | WT_INT_EN); + ctlreg |= ADC_SEMIAUTO | ADC_INT_EN | ADC_CONV; + __raw_writel(ctlreg, w90p910_ts->ts_reg); + + w90p910_ts->state = TS_WAIT_X_COORD; +} + +static void w90p910_prepare_y_reading(struct w90p910_ts *w90p910_ts) +{ + unsigned long ctlreg; + + __raw_writel(ADC_TSC_Y, w90p910_ts->ts_reg + 0x04); + ctlreg = __raw_readl(w90p910_ts->ts_reg); + ctlreg &= ~(ADC_WAITTRIG | ADC_INT | WT_INT_EN); + ctlreg |= ADC_SEMIAUTO | ADC_INT_EN | ADC_CONV; + __raw_writel(ctlreg, w90p910_ts->ts_reg); + + w90p910_ts->state = TS_WAIT_Y_COORD; +} + +static void w90p910_prepare_next_packet(struct w90p910_ts *w90p910_ts) +{ + unsigned long ctlreg; + + ctlreg = __raw_readl(w90p910_ts->ts_reg); + ctlreg &= ~(ADC_INT | ADC_INT_EN | ADC_SEMIAUTO | ADC_CONV); + ctlreg |= ADC_WAITTRIG | WT_INT_EN; + __raw_writel(ctlreg, w90p910_ts->ts_reg); + + w90p910_ts->state = TS_WAIT_NEW_PACKET; +} + +static irqreturn_t w90p910_ts_interrupt(int irq, void *dev_id) +{ + struct w90p910_ts *w90p910_ts = dev_id; + unsigned long flags; + + spin_lock_irqsave(&w90p910_ts->lock, flags); + + switch (w90p910_ts->state) { + case TS_WAIT_NEW_PACKET: + /* + * The controller only generates interrupts when pen + * is down. + */ + del_timer(&w90p910_ts->timer); + w90p910_prepare_x_reading(w90p910_ts); + break; + + + case TS_WAIT_X_COORD: + w90p910_prepare_y_reading(w90p910_ts); + break; + + case TS_WAIT_Y_COORD: + w90p910_report_event(w90p910_ts, true); + w90p910_prepare_next_packet(w90p910_ts); + mod_timer(&w90p910_ts->timer, jiffies + msecs_to_jiffies(100)); + break; + + case TS_IDLE: + break; + } + + spin_unlock_irqrestore(&w90p910_ts->lock, flags); + + return IRQ_HANDLED; +} + +static void w90p910_check_pen_up(unsigned long data) +{ + struct w90p910_ts *w90p910_ts = (struct w90p910_ts *) data; + unsigned long flags; + + spin_lock_irqsave(&w90p910_ts->lock, flags); + + if (w90p910_ts->state == TS_WAIT_NEW_PACKET && + !(__raw_readl(w90p910_ts->ts_reg + 0x04) & ADC_DOWN)) { + + w90p910_report_event(w90p910_ts, false); + } + + spin_unlock_irqrestore(&w90p910_ts->lock, flags); +} + +static int w90p910_open(struct input_dev *dev) +{ + struct w90p910_ts *w90p910_ts = input_get_drvdata(dev); + unsigned long val; + + /* enable the ADC clock */ + val = __raw_readl(w90p910_ts->clocken); + __raw_writel(val | ADC_CLK_EN, w90p910_ts->clocken); + + __raw_writel(ADC_RST1, w90p910_ts->ts_reg); + msleep(1); + __raw_writel(ADC_RST0, w90p910_ts->ts_reg); + msleep(1); + + /* set delay and screen type */ + val = __raw_readl(w90p910_ts->ts_reg + 0x04); + __raw_writel(val & TSC_FOURWIRE, w90p910_ts->ts_reg + 0x04); + __raw_writel(ADC_DELAY, w90p910_ts->ts_reg + 0x08); + + w90p910_ts->state = TS_WAIT_NEW_PACKET; + wmb(); + + /* set trigger mode */ + val = __raw_readl(w90p910_ts->ts_reg); + val |= ADC_WAITTRIG | ADC_DIV | ADC_EN | WT_INT_EN; + __raw_writel(val, w90p910_ts->ts_reg); + + return 0; +} + +static void w90p910_close(struct input_dev *dev) +{ + struct w90p910_ts *w90p910_ts = input_get_drvdata(dev); + unsigned long val; + + /* disable trigger mode */ + + spin_lock_irq(&w90p910_ts->lock); + + w90p910_ts->state = TS_IDLE; + + val = __raw_readl(w90p910_ts->ts_reg); + val &= ~(ADC_WAITTRIG | ADC_DIV | ADC_EN | WT_INT_EN | ADC_INT_EN); + __raw_writel(val, w90p910_ts->ts_reg); + + spin_unlock_irq(&w90p910_ts->lock); + + /* Now that interrupts are shut off we can safely delete timer */ + del_timer_sync(&w90p910_ts->timer); + + /* stop the ADC clock */ + val = __raw_readl(w90p910_ts->clocken); + __raw_writel(val & ~ADC_CLK_EN, w90p910_ts->clocken); +} + +static int __devinit w90x900ts_probe(struct platform_device *pdev) +{ + struct w90p910_ts *w90p910_ts; + struct input_dev *input_dev; + struct resource *res; + int err; + + w90p910_ts = kzalloc(sizeof(struct w90p910_ts), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!w90p910_ts || !input_dev) { + err = -ENOMEM; + goto fail1; + } + + w90p910_ts->input = input_dev; + w90p910_ts->state = TS_IDLE; + spin_lock_init(&w90p910_ts->lock); + setup_timer(&w90p910_ts->timer, w90p910_check_pen_up, + (unsigned long)&w90p910_ts); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + err = -ENXIO; + goto fail1; + } + + if (!request_mem_region(res->start, res->end - res->start + 1, + pdev->name)) { + err = -EBUSY; + goto fail1; + } + + w90p910_ts->ts_reg = ioremap(res->start, res->end - res->start + 1); + if (!w90p910_ts->ts_reg) { + err = -ENOMEM; + goto fail2; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!res) { + err = -ENXIO; + goto fail3; + } + + w90p910_ts->clocken = (void __iomem *)res->start; + + input_dev->name = "W90P910 TouchScreen"; + input_dev->phys = "w90p910ts/event0"; + input_dev->id.bustype = BUS_HOST; + input_dev->id.vendor = 0x0005; + input_dev->id.product = 0x0001; + input_dev->id.version = 0x0100; + input_dev->dev.parent = &pdev->dev; + input_dev->open = w90p910_open; + input_dev->close = w90p910_close; + + input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); + + input_set_abs_params(input_dev, ABS_X, 0, 0x400, 0, 0); + input_set_abs_params(input_dev, ABS_Y, 0, 0x400, 0, 0); + + input_set_drvdata(input_dev, w90p910_ts); + + w90p910_ts->irq_num = platform_get_irq(pdev, 0); + if (request_irq(w90p910_ts->irq_num, w90p910_ts_interrupt, + IRQF_DISABLED, "w90p910ts", w90p910_ts)) { + err = -EBUSY; + goto fail3; + } + + err = input_register_device(w90p910_ts->input); + if (err) + goto fail4; + + platform_set_drvdata(pdev, w90p910_ts); + + return 0; + +fail4: free_irq(w90p910_ts->irq_num, w90p910_ts); +fail3: iounmap(w90p910_ts->ts_reg); +fail2: release_mem_region(res->start, res->end - res->start + 1); +fail1: input_free_device(input_dev); + kfree(w90p910_ts); + return err; +} + +static int __devexit w90x900ts_remove(struct platform_device *pdev) +{ + struct w90p910_ts *w90p910_ts = platform_get_drvdata(pdev); + struct resource *res; + + free_irq(w90p910_ts->irq_num, w90p910_ts); + del_timer_sync(&w90p910_ts->timer); + iounmap(w90p910_ts->ts_reg); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(res->start, res->end - res->start + 1); + + input_unregister_device(w90p910_ts->input); + kfree(w90p910_ts); + + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static struct platform_driver w90x900ts_driver = { + .probe = w90x900ts_probe, + .remove = __devexit_p(w90x900ts_remove), + .driver = { + .name = "w90x900-ts", + .owner = THIS_MODULE, + }, +}; + +static int __init w90x900ts_init(void) +{ + return platform_driver_register(&w90x900ts_driver); +} + +static void __exit w90x900ts_exit(void) +{ + platform_driver_unregister(&w90x900ts_driver); +} + +module_init(w90x900ts_init); +module_exit(w90x900ts_exit); + +MODULE_AUTHOR("Wan ZongShun "); +MODULE_DESCRIPTION("w90p910 touch screen driver!"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:w90p910-ts"); diff --git a/drivers/input/touchscreen/wm97xx-core.c b/drivers/input/touchscreen/wm97xx-core.c index 69af8385ab14..2957d48e0045 100644 --- a/drivers/input/touchscreen/wm97xx-core.c +++ b/drivers/input/touchscreen/wm97xx-core.c @@ -569,7 +569,7 @@ static int wm97xx_probe(struct device *dev) mutex_init(&wm->codec_mutex); wm->dev = dev; - dev->driver_data = wm; + dev_set_drvdata(dev, wm); wm->ac97 = to_ac97_t(dev); /* check that we have a supported codec */ diff --git a/drivers/input/xen-kbdfront.c b/drivers/input/xen-kbdfront.c index 928d2ed8865f..b115726dc088 100644 --- a/drivers/input/xen-kbdfront.c +++ b/drivers/input/xen-kbdfront.c @@ -114,7 +114,7 @@ static int __devinit xenkbd_probe(struct xenbus_device *dev, xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure"); return -ENOMEM; } - dev->dev.driver_data = info; + dev_set_drvdata(&dev->dev, info); info->xbdev = dev; info->irq = -1; snprintf(info->phys, sizeof(info->phys), "xenbus/%s", dev->nodename); @@ -186,7 +186,7 @@ static int __devinit xenkbd_probe(struct xenbus_device *dev, static int xenkbd_resume(struct xenbus_device *dev) { - struct xenkbd_info *info = dev->dev.driver_data; + struct xenkbd_info *info = dev_get_drvdata(&dev->dev); xenkbd_disconnect_backend(info); memset(info->page, 0, PAGE_SIZE); @@ -195,7 +195,7 @@ static int xenkbd_resume(struct xenbus_device *dev) static int xenkbd_remove(struct xenbus_device *dev) { - struct xenkbd_info *info = dev->dev.driver_data; + struct xenkbd_info *info = dev_get_drvdata(&dev->dev); xenkbd_disconnect_backend(info); if (info->kbd) @@ -266,7 +266,7 @@ static void xenkbd_disconnect_backend(struct xenkbd_info *info) static void xenkbd_backend_changed(struct xenbus_device *dev, enum xenbus_state backend_state) { - struct xenkbd_info *info = dev->dev.driver_data; + struct xenkbd_info *info = dev_get_drvdata(&dev->dev); int ret, val; switch (backend_state) { diff --git a/drivers/isdn/Kconfig b/drivers/isdn/Kconfig index 3d113c6e4a70..02bdca6f95c3 100644 --- a/drivers/isdn/Kconfig +++ b/drivers/isdn/Kconfig @@ -61,4 +61,6 @@ source "drivers/isdn/hardware/Kconfig" endif # ISDN_CAPI +source "drivers/isdn/gigaset/Kconfig" + endif # ISDN diff --git a/drivers/isdn/capi/capiutil.c b/drivers/isdn/capi/capiutil.c index 29419a8d31dc..16f2e465e5f9 100644 --- a/drivers/isdn/capi/capiutil.c +++ b/drivers/isdn/capi/capiutil.c @@ -490,7 +490,14 @@ static void pars_2_message(_cmsg * cmsg) } } -/*-------------------------------------------------------*/ +/** + * capi_cmsg2message() - assemble CAPI 2.0 message from _cmsg structure + * @cmsg: _cmsg structure + * @msg: buffer for assembled message + * + * Return value: 0 for success + */ + unsigned capi_cmsg2message(_cmsg * cmsg, u8 * msg) { cmsg->m = msg; @@ -553,7 +560,14 @@ static void message_2_pars(_cmsg * cmsg) } } -/*-------------------------------------------------------*/ +/** + * capi_message2cmsg() - disassemble CAPI 2.0 message into _cmsg structure + * @cmsg: _cmsg structure + * @msg: buffer for assembled message + * + * Return value: 0 for success + */ + unsigned capi_message2cmsg(_cmsg * cmsg, u8 * msg) { memset(cmsg, 0, sizeof(_cmsg)); @@ -573,7 +587,18 @@ unsigned capi_message2cmsg(_cmsg * cmsg, u8 * msg) return 0; } -/*-------------------------------------------------------*/ +/** + * capi_cmsg_header() - initialize header part of _cmsg structure + * @cmsg: _cmsg structure + * @_ApplId: ApplID field value + * @_Command: Command field value + * @_Subcommand: Subcommand field value + * @_Messagenumber: Message Number field value + * @_Controller: Controller/PLCI/NCCI field value + * + * Return value: 0 for success + */ + unsigned capi_cmsg_header(_cmsg * cmsg, u16 _ApplId, u8 _Command, u8 _Subcommand, u16 _Messagenumber, u32 _Controller) @@ -641,6 +666,14 @@ static char *mnames[] = [0x4e] = "MANUFACTURER_RESP" }; +/** + * capi_cmd2str() - convert CAPI 2.0 command/subcommand number to name + * @cmd: command number + * @subcmd: subcommand number + * + * Return value: static string, NULL if command/subcommand unknown + */ + char *capi_cmd2str(u8 cmd, u8 subcmd) { return mnames[command_2_index(cmd, subcmd)]; @@ -879,6 +912,11 @@ init: return cdb; } +/** + * cdebbuf_free() - free CAPI debug buffer + * @cdb: buffer to free + */ + void cdebbuf_free(_cdebbuf *cdb) { if (likely(cdb == g_debbuf)) { @@ -891,6 +929,16 @@ void cdebbuf_free(_cdebbuf *cdb) } +/** + * capi_message2str() - format CAPI 2.0 message for printing + * @msg: CAPI 2.0 message + * + * Allocates a CAPI debug buffer and fills it with a printable representation + * of the CAPI 2.0 message in @msg. + * Return value: allocated debug buffer, NULL on error + * The returned buffer should be freed by a call to cdebbuf_free() after use. + */ + _cdebbuf *capi_message2str(u8 * msg) { _cdebbuf *cdb; @@ -926,10 +974,23 @@ _cdebbuf *capi_message2str(u8 * msg) return cdb; } +/** + * capi_cmsg2str() - format _cmsg structure for printing + * @cmsg: _cmsg structure + * + * Allocates a CAPI debug buffer and fills it with a printable representation + * of the CAPI 2.0 message stored in @cmsg by a previous call to + * capi_cmsg2message() or capi_message2cmsg(). + * Return value: allocated debug buffer, NULL on error + * The returned buffer should be freed by a call to cdebbuf_free() after use. + */ + _cdebbuf *capi_cmsg2str(_cmsg * cmsg) { _cdebbuf *cdb; + if (!cmsg->m) + return NULL; /* no message */ cdb = cdebbuf_alloc(); if (!cdb) return NULL; diff --git a/drivers/isdn/capi/kcapi.c b/drivers/isdn/capi/kcapi.c index f33170368cd1..57d26360f64e 100644 --- a/drivers/isdn/capi/kcapi.c +++ b/drivers/isdn/capi/kcapi.c @@ -377,14 +377,14 @@ void capi_ctr_ready(struct capi_ctr * card) EXPORT_SYMBOL(capi_ctr_ready); /** - * capi_ctr_reseted() - signal CAPI controller reset + * capi_ctr_down() - signal CAPI controller not ready * @card: controller descriptor structure. * * Called by hardware driver to signal that the controller is down and * unavailable for use. */ -void capi_ctr_reseted(struct capi_ctr * card) +void capi_ctr_down(struct capi_ctr * card) { u16 appl; @@ -413,7 +413,7 @@ void capi_ctr_reseted(struct capi_ctr * card) notify_push(KCI_CONTRDOWN, card->cnr, 0, 0); } -EXPORT_SYMBOL(capi_ctr_reseted); +EXPORT_SYMBOL(capi_ctr_down); /** * capi_ctr_suspend_output() - suspend controller @@ -517,7 +517,7 @@ EXPORT_SYMBOL(attach_capi_ctr); int detach_capi_ctr(struct capi_ctr *card) { if (card->cardstate != CARD_DETECTED) - capi_ctr_reseted(card); + capi_ctr_down(card); ncards--; diff --git a/drivers/isdn/divert/isdn_divert.c b/drivers/isdn/divert/isdn_divert.c index 7d97d54588d9..77e9fdda0597 100644 --- a/drivers/isdn/divert/isdn_divert.c +++ b/drivers/isdn/divert/isdn_divert.c @@ -183,7 +183,7 @@ int cf_command(int drvid, int mode, (mode != 1) ? "" : " 0 ", (mode != 1) ? "" : fwd_nr); - retval = divert_if.ll_cmd(&cs->ics); /* excute command */ + retval = divert_if.ll_cmd(&cs->ics); /* execute command */ if (!retval) { cs->prev = NULL; diff --git a/drivers/isdn/gigaset/Kconfig b/drivers/isdn/gigaset/Kconfig index 9ca889adf120..18ab8652aa57 100644 --- a/drivers/isdn/gigaset/Kconfig +++ b/drivers/isdn/gigaset/Kconfig @@ -1,5 +1,6 @@ menuconfig ISDN_DRV_GIGASET tristate "Siemens Gigaset support" + depends on ISDN_I4L select CRC_CCITT select BITREVERSE help @@ -42,11 +43,4 @@ config GIGASET_DEBUG This enables debugging code in the Gigaset drivers. If in doubt, say yes. -config GIGASET_UNDOCREQ - bool "Support for undocumented USB requests" - help - This enables support for USB requests we only know from - reverse engineering (currently M105 only). If you need - features like configuration mode of M105, say yes. - endif # ISDN_DRV_GIGASET diff --git a/drivers/isdn/gigaset/asyncdata.c b/drivers/isdn/gigaset/asyncdata.c index 2a4ce96f04bd..234cc5d53312 100644 --- a/drivers/isdn/gigaset/asyncdata.c +++ b/drivers/isdn/gigaset/asyncdata.c @@ -174,9 +174,8 @@ byte_stuff: if (unlikely(fcs != PPP_GOODFCS)) { dev_err(cs->dev, - "Packet checksum at %lu failed, " - "packet is corrupted (%u bytes)!\n", - bcs->rcvbytes, skb->len); + "Checksum failed, %u bytes corrupted!\n", + skb->len); compskb = NULL; gigaset_rcv_error(compskb, cs, bcs); error = 1; diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c index 0048ce98bfa8..e4141bf8b2f3 100644 --- a/drivers/isdn/gigaset/common.c +++ b/drivers/isdn/gigaset/common.c @@ -565,8 +565,6 @@ static struct bc_state *gigaset_initbcs(struct bc_state *bcs, gig_dbg(DEBUG_INIT, "setting up bcs[%d]->at_state", channel); gigaset_at_init(&bcs->at_state, bcs, cs, -1); - bcs->rcvbytes = 0; - #ifdef CONFIG_GIGASET_DEBUG bcs->emptycount = 0; #endif @@ -672,14 +670,8 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels, cs->tty = NULL; cs->tty_dev = NULL; cs->cidmode = cidmode != 0; - - //if(onechannel) { //FIXME - cs->tabnocid = gigaset_tab_nocid_m10x; - cs->tabcid = gigaset_tab_cid_m10x; - //} else { - // cs->tabnocid = gigaset_tab_nocid; - // cs->tabcid = gigaset_tab_cid; - //} + cs->tabnocid = gigaset_tab_nocid; + cs->tabcid = gigaset_tab_cid; init_waitqueue_head(&cs->waitqueue); cs->waiting = 0; diff --git a/drivers/isdn/gigaset/ev-layer.c b/drivers/isdn/gigaset/ev-layer.c index e582a4887bc1..ec5169604a6a 100644 --- a/drivers/isdn/gigaset/ev-layer.c +++ b/drivers/isdn/gigaset/ev-layer.c @@ -160,7 +160,7 @@ // 100: init, 200: dle0, 250:dle1, 300: get cid (dial), 350: "hup" (no cid), 400: hup, 500: reset, 600: dial, 700: ring -struct reply_t gigaset_tab_nocid_m10x[]= /* with dle mode */ +struct reply_t gigaset_tab_nocid[] = { /* resp_code, min_ConState, max_ConState, parameter, new_ConState, timeout, action, command */ @@ -280,7 +280,7 @@ struct reply_t gigaset_tab_nocid_m10x[]= /* with dle mode */ }; // 600: start dialing, 650: dial in progress, 800: connection is up, 700: ring, 400: hup, 750: accepted icall -struct reply_t gigaset_tab_cid_m10x[] = /* for M10x */ +struct reply_t gigaset_tab_cid[] = { /* resp_code, min_ConState, max_ConState, parameter, new_ConState, timeout, action, command */ diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/isdn/gigaset/gigaset.h index 747178f03d2c..a2f6125739eb 100644 --- a/drivers/isdn/gigaset/gigaset.h +++ b/drivers/isdn/gigaset/gigaset.h @@ -282,8 +282,8 @@ struct reply_t { char *command; /* NULL==none */ }; -extern struct reply_t gigaset_tab_cid_m10x[]; -extern struct reply_t gigaset_tab_nocid_m10x[]; +extern struct reply_t gigaset_tab_cid[]; +extern struct reply_t gigaset_tab_nocid[]; struct inbuf_t { unsigned char *rcvbuf; /* usb-gigaset receive buffer */ @@ -384,7 +384,6 @@ struct bc_state { int trans_up; /* Counter of packages (upstream) */ struct at_state_t at_state; - unsigned long rcvbytes; __u16 fcs; struct sk_buff *skb; diff --git a/drivers/isdn/gigaset/i4l.c b/drivers/isdn/gigaset/i4l.c index 69a702f0db93..9b22f9cf2f33 100644 --- a/drivers/isdn/gigaset/i4l.c +++ b/drivers/isdn/gigaset/i4l.c @@ -544,11 +544,11 @@ int gigaset_register_to_LL(struct cardstate *cs, const char *isdnid) gig_dbg(DEBUG_ANY, "Register driver capabilities to LL"); - //iif->id[sizeof(iif->id) - 1]=0; - //strncpy(iif->id, isdnid, sizeof(iif->id) - 1); if (snprintf(iif->id, sizeof iif->id, "%s_%u", isdnid, cs->minor_index) - >= sizeof iif->id) - return -ENOMEM; //FIXME EINVAL/...?? + >= sizeof iif->id) { + pr_err("ID too long: %s\n", isdnid); + return 0; + } iif->owner = THIS_MODULE; iif->channels = cs->channels; @@ -568,8 +568,10 @@ int gigaset_register_to_LL(struct cardstate *cs, const char *isdnid) iif->rcvcallb_skb = NULL; /* Will be set by LL */ iif->statcallb = NULL; /* Will be set by LL */ - if (!register_isdn(iif)) + if (!register_isdn(iif)) { + pr_err("register_isdn failed\n"); return 0; + } cs->myid = iif->channels; /* Set my device id */ return 1; diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c index 820a30923fee..1ebfcab74662 100644 --- a/drivers/isdn/gigaset/interface.c +++ b/drivers/isdn/gigaset/interface.c @@ -599,8 +599,7 @@ void gigaset_if_init(struct cardstate *cs) if (!IS_ERR(cs->tty_dev)) dev_set_drvdata(cs->tty_dev, cs); else { - dev_warn(cs->dev, - "could not register device to the tty subsystem\n"); + pr_warning("could not register device to the tty subsystem\n"); cs->tty_dev = NULL; } mutex_unlock(&cs->mutex); diff --git a/drivers/isdn/gigaset/isocdata.c b/drivers/isdn/gigaset/isocdata.c index 29808c4fb1cb..db3a1e4cd489 100644 --- a/drivers/isdn/gigaset/isocdata.c +++ b/drivers/isdn/gigaset/isocdata.c @@ -246,6 +246,10 @@ static inline void dump_bytes(enum debuglevel level, const char *tag, unsigned char c; static char dbgline[3 * 32 + 1]; int i = 0; + + if (!(gigaset_debuglevel & level)) + return; + while (count-- > 0) { if (i > sizeof(dbgline) - 4) { dbgline[i] = '\0'; diff --git a/drivers/isdn/gigaset/proc.c b/drivers/isdn/gigaset/proc.c index da6f3acf9fd0..9715aad9c3f0 100644 --- a/drivers/isdn/gigaset/proc.c +++ b/drivers/isdn/gigaset/proc.c @@ -79,5 +79,5 @@ void gigaset_init_dev_sysfs(struct cardstate *cs) gig_dbg(DEBUG_INIT, "setting up sysfs"); if (device_create_file(cs->tty_dev, &dev_attr_cidmode)) - dev_err(cs->dev, "could not create sysfs attribute\n"); + pr_err("could not create sysfs attribute\n"); } diff --git a/drivers/isdn/gigaset/usb-gigaset.c b/drivers/isdn/gigaset/usb-gigaset.c index d78385166099..4deb1ab0dbf8 100644 --- a/drivers/isdn/gigaset/usb-gigaset.c +++ b/drivers/isdn/gigaset/usb-gigaset.c @@ -153,8 +153,6 @@ static inline unsigned tiocm_to_gigaset(unsigned state) return ((state & TIOCM_DTR) ? 1 : 0) | ((state & TIOCM_RTS) ? 2 : 0); } -#ifdef CONFIG_GIGASET_UNDOCREQ -/* WARNING: EXPERIMENTAL! */ static int gigaset_set_modem_ctrl(struct cardstate *cs, unsigned old_state, unsigned new_state) { @@ -176,6 +174,11 @@ static int gigaset_set_modem_ctrl(struct cardstate *cs, unsigned old_state, return 0; } +/* + * Set M105 configuration value + * using undocumented device commands reverse engineered from USB traces + * of the Siemens Windows driver + */ static int set_value(struct cardstate *cs, u8 req, u16 val) { struct usb_device *udev = cs->hw.usb->udev; @@ -205,8 +208,10 @@ static int set_value(struct cardstate *cs, u8 req, u16 val) return r < 0 ? r : (r2 < 0 ? r2 : 0); } -/* WARNING: HIGHLY EXPERIMENTAL! */ -// don't use this in an interrupt/BH +/* + * set the baud rate on the internal serial adapter + * using the undocumented parameter setting command + */ static int gigaset_baud_rate(struct cardstate *cs, unsigned cflag) { u16 val; @@ -237,8 +242,10 @@ static int gigaset_baud_rate(struct cardstate *cs, unsigned cflag) return set_value(cs, 1, val); } -/* WARNING: HIGHLY EXPERIMENTAL! */ -// don't use this in an interrupt/BH +/* + * set the line format on the internal serial adapter + * using the undocumented parameter setting command + */ static int gigaset_set_line_ctrl(struct cardstate *cs, unsigned cflag) { u16 val = 0; @@ -274,24 +281,6 @@ static int gigaset_set_line_ctrl(struct cardstate *cs, unsigned cflag) return set_value(cs, 3, val); } -#else -static int gigaset_set_modem_ctrl(struct cardstate *cs, unsigned old_state, - unsigned new_state) -{ - return -ENOTTY; -} - -static int gigaset_set_line_ctrl(struct cardstate *cs, unsigned cflag) -{ - return -ENOTTY; -} - -static int gigaset_baud_rate(struct cardstate *cs, unsigned cflag) -{ - return -ENOTTY; -} -#endif - /*================================================================================================================*/ static int gigaset_init_bchannel(struct bc_state *bcs) @@ -362,10 +351,8 @@ static void gigaset_modem_fill(unsigned long data) } while (again); } -/** - * gigaset_read_int_callback - * - * It is called if the data was received from the device. +/* + * Interrupt Input URB completion routine */ static void gigaset_read_int_callback(struct urb *urb) { @@ -567,18 +554,19 @@ static int gigaset_chars_in_buffer(struct cardstate *cs) return cs->cmdbytes; } +/* + * set the break characters on the internal serial adapter + * using undocumented device commands reverse engineered from USB traces + * of the Siemens Windows driver + */ static int gigaset_brkchars(struct cardstate *cs, const unsigned char buf[6]) { -#ifdef CONFIG_GIGASET_UNDOCREQ struct usb_device *udev = cs->hw.usb->udev; gigaset_dbg_buffer(DEBUG_USBREQ, "brkchars", 6, buf); memcpy(cs->hw.usb->bchars, buf, 6); return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x19, 0x41, 0, 0, &buf, 6, 2000); -#else - return -ENOTTY; -#endif } static int gigaset_freebcshw(struct bc_state *bcs) @@ -625,7 +613,6 @@ static int gigaset_initcshw(struct cardstate *cs) ucs->bchars[5] = 0x13; ucs->bulk_out_buffer = NULL; ucs->bulk_out_urb = NULL; - //ucs->urb_cmd_out = NULL; ucs->read_urb = NULL; tasklet_init(&cs->write_tasklet, &gigaset_modem_fill, (unsigned long) cs); @@ -742,7 +729,7 @@ static int gigaset_probe(struct usb_interface *interface, cs->dev = &interface->dev; /* save address of controller structure */ - usb_set_intfdata(interface, cs); // dev_set_drvdata(&interface->dev, cs); + usb_set_intfdata(interface, cs); endpoint = &hostif->endpoint[0].desc; @@ -921,8 +908,7 @@ static const struct gigaset_ops ops = { gigaset_m10x_input, }; -/** - * usb_gigaset_init +/* * This function is called while kernel-module is loaded */ static int __init usb_gigaset_init(void) @@ -952,9 +938,7 @@ error: return -1; } - -/** - * usb_gigaset_exit +/* * This function is called while unloading the kernel-module */ static void __exit usb_gigaset_exit(void) diff --git a/drivers/isdn/hardware/avm/b1.c b/drivers/isdn/hardware/avm/b1.c index abf05ec31760..a7c0083e78a7 100644 --- a/drivers/isdn/hardware/avm/b1.c +++ b/drivers/isdn/hardware/avm/b1.c @@ -330,7 +330,7 @@ void b1_reset_ctr(struct capi_ctr *ctrl) spin_lock_irqsave(&card->lock, flags); capilib_release(&cinfo->ncci_head); spin_unlock_irqrestore(&card->lock, flags); - capi_ctr_reseted(ctrl); + capi_ctr_down(ctrl); } void b1_register_appl(struct capi_ctr *ctrl, diff --git a/drivers/isdn/hardware/avm/b1dma.c b/drivers/isdn/hardware/avm/b1dma.c index da34b98e3de7..0e84aaae43fd 100644 --- a/drivers/isdn/hardware/avm/b1dma.c +++ b/drivers/isdn/hardware/avm/b1dma.c @@ -759,7 +759,7 @@ void b1dma_reset_ctr(struct capi_ctr *ctrl) memset(cinfo->version, 0, sizeof(cinfo->version)); capilib_release(&cinfo->ncci_head); spin_unlock_irqrestore(&card->lock, flags); - capi_ctr_reseted(ctrl); + capi_ctr_down(ctrl); } /* ------------------------------------------------------------- */ diff --git a/drivers/isdn/hardware/avm/c4.c b/drivers/isdn/hardware/avm/c4.c index 9df1d3f66c87..6833301a45fc 100644 --- a/drivers/isdn/hardware/avm/c4.c +++ b/drivers/isdn/hardware/avm/c4.c @@ -681,7 +681,7 @@ static irqreturn_t c4_handle_interrupt(avmcard *card) spin_lock_irqsave(&card->lock, flags); capilib_release(&cinfo->ncci_head); spin_unlock_irqrestore(&card->lock, flags); - capi_ctr_reseted(&cinfo->capi_ctrl); + capi_ctr_down(&cinfo->capi_ctrl); } card->nlogcontr = 0; return IRQ_HANDLED; @@ -909,7 +909,7 @@ static void c4_reset_ctr(struct capi_ctr *ctrl) for (i=0; i < card->nr_controllers; i++) { cinfo = &card->ctrlinfo[i]; memset(cinfo->version, 0, sizeof(cinfo->version)); - capi_ctr_reseted(&cinfo->capi_ctrl); + capi_ctr_down(&cinfo->capi_ctrl); } card->nlogcontr = 0; } diff --git a/drivers/isdn/hardware/avm/t1isa.c b/drivers/isdn/hardware/avm/t1isa.c index e7724493738c..1c53fd49adb6 100644 --- a/drivers/isdn/hardware/avm/t1isa.c +++ b/drivers/isdn/hardware/avm/t1isa.c @@ -339,7 +339,7 @@ static void t1isa_reset_ctr(struct capi_ctr *ctrl) spin_lock_irqsave(&card->lock, flags); capilib_release(&cinfo->ncci_head); spin_unlock_irqrestore(&card->lock, flags); - capi_ctr_reseted(ctrl); + capi_ctr_down(ctrl); } static void t1isa_remove(struct pci_dev *pdev) diff --git a/drivers/isdn/hardware/mISDN/Kconfig b/drivers/isdn/hardware/mISDN/Kconfig index fd112ae252cf..3024566dd099 100644 --- a/drivers/isdn/hardware/mISDN/Kconfig +++ b/drivers/isdn/hardware/mISDN/Kconfig @@ -13,7 +13,7 @@ config MISDN_HFCPCI config MISDN_HFCMULTI tristate "Support for HFC multiport cards (HFC-4S/8S/E1)" - depends on PCI + depends on PCI || 8xx depends on MISDN help Enable support for cards with Cologne Chip AG's HFC multiport @@ -23,6 +23,15 @@ config MISDN_HFCMULTI * HFC-8S (8 S/T interfaces on one chip) * HFC-E1 (E1 interface for 2Mbit ISDN) +config MISDN_HFCMULTI_8xx + boolean "Support for XHFC embedded board in HFC multiport driver" + depends on MISDN + depends on MISDN_HFCMULTI + depends on 8xx + default 8xx + help + Enable support for the XHFC embedded solution from Speech Design. + config MISDN_HFCUSB tristate "Support for HFC-S USB based TAs" depends on USB diff --git a/drivers/isdn/hardware/mISDN/hfc_multi.h b/drivers/isdn/hardware/mISDN/hfc_multi.h index 663b77f578be..0c773866efc7 100644 --- a/drivers/isdn/hardware/mISDN/hfc_multi.h +++ b/drivers/isdn/hardware/mISDN/hfc_multi.h @@ -17,6 +17,16 @@ #define PCI_ENA_REGIO 0x01 #define PCI_ENA_MEMIO 0x02 +#define XHFC_IRQ 4 /* SIU_IRQ2 */ +#define XHFC_MEMBASE 0xFE000000 +#define XHFC_MEMSIZE 0x00001000 +#define XHFC_OFFSET 0x00001000 +#define PA_XHFC_A0 0x0020 /* PA10 */ +#define PB_XHFC_IRQ1 0x00000100 /* PB23 */ +#define PB_XHFC_IRQ2 0x00000200 /* PB22 */ +#define PB_XHFC_IRQ3 0x00000400 /* PB21 */ +#define PB_XHFC_IRQ4 0x00000800 /* PB20 */ + /* * NOTE: some registers are assigned multiple times due to different modes * also registers are assigned differen for HFC-4s/8s and HFC-E1 @@ -44,6 +54,7 @@ struct hfc_chan { int conf; /* conference setting of TX slot */ int txpending; /* if there is currently data in */ /* the FIFO 0=no, 1=yes, 2=splloop */ + int Zfill; /* rx-fifo level on last hfcmulti_tx */ int rx_off; /* set to turn fifo receive off */ int coeff_count; /* curren coeff block */ s32 *coeff; /* memory pointer to 8 coeff blocks */ @@ -62,6 +73,7 @@ struct hfcm_hw { u_char r_sci_msk; u_char r_tx0, r_tx1; u_char a_st_ctrl0[8]; + u_char r_bert_wd_md; timer_t timer; }; @@ -79,6 +91,11 @@ struct hfcm_hw { #define HFC_CFG_CRC4 10 /* disable CRC-4 Multiframe mode, */ /* use double frame instead. */ +#define HFC_TYPE_E1 1 /* controller is HFC-E1 */ +#define HFC_TYPE_4S 4 /* controller is HFC-4S */ +#define HFC_TYPE_8S 8 /* controller is HFC-8S */ +#define HFC_TYPE_XHFC 5 /* controller is XHFC */ + #define HFC_CHIP_EXRAM_128 0 /* external ram 128k */ #define HFC_CHIP_EXRAM_512 1 /* external ram 256k */ #define HFC_CHIP_REVISION0 2 /* old fifo handling */ @@ -86,19 +103,22 @@ struct hfcm_hw { #define HFC_CHIP_PCM_MASTER 4 /* PCM is master */ #define HFC_CHIP_RX_SYNC 5 /* disable pll sync for pcm */ #define HFC_CHIP_DTMF 6 /* DTMF decoding is enabled */ -#define HFC_CHIP_ULAW 7 /* ULAW mode */ -#define HFC_CHIP_CLOCK2 8 /* double clock mode */ -#define HFC_CHIP_E1CLOCK_GET 9 /* always get clock from E1 interface */ -#define HFC_CHIP_E1CLOCK_PUT 10 /* always put clock from E1 interface */ -#define HFC_CHIP_WATCHDOG 11 /* whether we should send signals */ +#define HFC_CHIP_CONF 7 /* conference handling is enabled */ +#define HFC_CHIP_ULAW 8 /* ULAW mode */ +#define HFC_CHIP_CLOCK2 9 /* double clock mode */ +#define HFC_CHIP_E1CLOCK_GET 10 /* always get clock from E1 interface */ +#define HFC_CHIP_E1CLOCK_PUT 11 /* always put clock from E1 interface */ +#define HFC_CHIP_WATCHDOG 12 /* whether we should send signals */ /* to the watchdog */ -#define HFC_CHIP_B410P 12 /* whether we have a b410p with echocan in */ +#define HFC_CHIP_B410P 13 /* whether we have a b410p with echocan in */ /* hw */ -#define HFC_CHIP_PLXSD 13 /* whether we have a Speech-Design PLX */ +#define HFC_CHIP_PLXSD 14 /* whether we have a Speech-Design PLX */ +#define HFC_CHIP_EMBSD 15 /* whether we have a SD Embedded board */ #define HFC_IO_MODE_PCIMEM 0x00 /* normal memory mapped IO */ #define HFC_IO_MODE_REGIO 0x01 /* PCI io access */ #define HFC_IO_MODE_PLXSD 0x02 /* access HFC via PLX9030 */ +#define HFC_IO_MODE_EMBSD 0x03 /* direct access */ /* table entry in the PCI devices list */ struct hm_map { @@ -111,6 +131,7 @@ struct hm_map { int opticalsupport; int dip_type; int io_mode; + int irq; }; struct hfc_multi { @@ -118,7 +139,7 @@ struct hfc_multi { struct hm_map *mtyp; int id; int pcm; /* id of pcm bus */ - int type; + int ctype; /* controller type */ int ports; u_int irq; /* irq used by card */ @@ -158,10 +179,16 @@ struct hfc_multi { int len); void (*write_fifo)(struct hfc_multi *hc, u_char *data, int len); - u_long pci_origmembase, plx_origmembase, dsp_origmembase; + u_long pci_origmembase, plx_origmembase; void __iomem *pci_membase; /* PCI memory */ void __iomem *plx_membase; /* PLX memory */ - u_char *dsp_membase; /* DSP on PLX */ + u_long xhfc_origmembase; + u_char *xhfc_membase; + u_long *xhfc_memaddr, *xhfc_memdata; +#ifdef CONFIG_MISDN_HFCMULTI_8xx + struct immap *immap; +#endif + u_long pb_irqmsk; /* Portbit mask to check the IRQ line */ u_long pci_iobase; /* PCI IO */ struct hfcm_hw hw; /* remember data of write-only-registers */ diff --git a/drivers/isdn/hardware/mISDN/hfc_multi_8xx.h b/drivers/isdn/hardware/mISDN/hfc_multi_8xx.h new file mode 100644 index 000000000000..45ddced956d5 --- /dev/null +++ b/drivers/isdn/hardware/mISDN/hfc_multi_8xx.h @@ -0,0 +1,167 @@ +/* + * For License see notice in hfc_multi.c + * + * special IO and init functions for the embedded XHFC board + * from Speech Design + * + */ + +#include + +/* Change this to the value used by your board */ +#ifndef IMAP_ADDR +#define IMAP_ADDR 0xFFF00000 +#endif + +static void +#ifdef HFC_REGISTER_DEBUG +HFC_outb_embsd(struct hfc_multi *hc, u_char reg, u_char val, + const char *function, int line) +#else +HFC_outb_embsd(struct hfc_multi *hc, u_char reg, u_char val) +#endif +{ + hc->immap->im_ioport.iop_padat |= PA_XHFC_A0; + writeb(reg, hc->xhfc_memaddr); + hc->immap->im_ioport.iop_padat &= ~(PA_XHFC_A0); + writeb(val, hc->xhfc_memdata); +} +static u_char +#ifdef HFC_REGISTER_DEBUG +HFC_inb_embsd(struct hfc_multi *hc, u_char reg, const char *function, int line) +#else +HFC_inb_embsd(struct hfc_multi *hc, u_char reg) +#endif +{ + hc->immap->im_ioport.iop_padat |= PA_XHFC_A0; + writeb(reg, hc->xhfc_memaddr); + hc->immap->im_ioport.iop_padat &= ~(PA_XHFC_A0); + return readb(hc->xhfc_memdata); +} +static u_short +#ifdef HFC_REGISTER_DEBUG +HFC_inw_embsd(struct hfc_multi *hc, u_char reg, const char *function, int line) +#else +HFC_inw_embsd(struct hfc_multi *hc, u_char reg) +#endif +{ + hc->immap->im_ioport.iop_padat |= PA_XHFC_A0; + writeb(reg, hc->xhfc_memaddr); + hc->immap->im_ioport.iop_padat &= ~(PA_XHFC_A0); + return readb(hc->xhfc_memdata); +} +static void +#ifdef HFC_REGISTER_DEBUG +HFC_wait_embsd(struct hfc_multi *hc, const char *function, int line) +#else +HFC_wait_embsd(struct hfc_multi *hc) +#endif +{ + hc->immap->im_ioport.iop_padat |= PA_XHFC_A0; + writeb(R_STATUS, hc->xhfc_memaddr); + hc->immap->im_ioport.iop_padat &= ~(PA_XHFC_A0); + while (readb(hc->xhfc_memdata) & V_BUSY) + cpu_relax(); +} + +/* write fifo data (EMBSD) */ +void +write_fifo_embsd(struct hfc_multi *hc, u_char *data, int len) +{ + hc->immap->im_ioport.iop_padat |= PA_XHFC_A0; + *hc->xhfc_memaddr = A_FIFO_DATA0; + hc->immap->im_ioport.iop_padat &= ~(PA_XHFC_A0); + while (len) { + *hc->xhfc_memdata = *data; + data++; + len--; + } +} + +/* read fifo data (EMBSD) */ +void +read_fifo_embsd(struct hfc_multi *hc, u_char *data, int len) +{ + hc->immap->im_ioport.iop_padat |= PA_XHFC_A0; + *hc->xhfc_memaddr = A_FIFO_DATA0; + hc->immap->im_ioport.iop_padat &= ~(PA_XHFC_A0); + while (len) { + *data = (u_char)(*hc->xhfc_memdata); + data++; + len--; + } +} + +static int +setup_embedded(struct hfc_multi *hc, struct hm_map *m) +{ + printk(KERN_INFO + "HFC-multi: card manufacturer: '%s' card name: '%s' clock: %s\n", + m->vendor_name, m->card_name, m->clock2 ? "double" : "normal"); + + hc->pci_dev = NULL; + if (m->clock2) + test_and_set_bit(HFC_CHIP_CLOCK2, &hc->chip); + + hc->leds = m->leds; + hc->ledstate = 0xAFFEAFFE; + hc->opticalsupport = m->opticalsupport; + + hc->pci_iobase = 0; + hc->pci_membase = 0; + hc->xhfc_membase = NULL; + hc->xhfc_memaddr = NULL; + hc->xhfc_memdata = NULL; + + /* set memory access methods */ + if (m->io_mode) /* use mode from card config */ + hc->io_mode = m->io_mode; + switch (hc->io_mode) { + case HFC_IO_MODE_EMBSD: + test_and_set_bit(HFC_CHIP_EMBSD, &hc->chip); + hc->slots = 128; /* required */ + /* fall through */ + hc->HFC_outb = HFC_outb_embsd; + hc->HFC_inb = HFC_inb_embsd; + hc->HFC_inw = HFC_inw_embsd; + hc->HFC_wait = HFC_wait_embsd; + hc->read_fifo = read_fifo_embsd; + hc->write_fifo = write_fifo_embsd; + hc->xhfc_origmembase = XHFC_MEMBASE + XHFC_OFFSET * hc->id; + hc->xhfc_membase = (u_char *)ioremap(hc->xhfc_origmembase, + XHFC_MEMSIZE); + if (!hc->xhfc_membase) { + printk(KERN_WARNING + "HFC-multi: failed to remap xhfc address space. " + "(internal error)\n"); + return -EIO; + } + hc->xhfc_memaddr = (u_long *)(hc->xhfc_membase + 4); + hc->xhfc_memdata = (u_long *)(hc->xhfc_membase); + printk(KERN_INFO + "HFC-multi: xhfc_membase:%#lx xhfc_origmembase:%#lx " + "xhfc_memaddr:%#lx xhfc_memdata:%#lx\n", + (u_long)hc->xhfc_membase, hc->xhfc_origmembase, + (u_long)hc->xhfc_memaddr, (u_long)hc->xhfc_memdata); + break; + default: + printk(KERN_WARNING "HFC-multi: Invalid IO mode.\n"); + return -EIO; + } + + /* Prepare the MPC8XX PortA 10 as output (address/data selector) */ + hc->immap = (struct immap *)(IMAP_ADDR); + hc->immap->im_ioport.iop_papar &= ~(PA_XHFC_A0); + hc->immap->im_ioport.iop_paodr &= ~(PA_XHFC_A0); + hc->immap->im_ioport.iop_padir |= PA_XHFC_A0; + + /* Prepare the MPC8xx PortB __X__ as input (ISDN__X__IRQ) */ + hc->pb_irqmsk = (PB_XHFC_IRQ1 << hc->id); + hc->immap->im_cpm.cp_pbpar &= ~(hc->pb_irqmsk); + hc->immap->im_cpm.cp_pbodr &= ~(hc->pb_irqmsk); + hc->immap->im_cpm.cp_pbdir &= ~(hc->pb_irqmsk); + + /* At this point the needed config is done */ + /* fifos are still not enabled */ + return 0; +} diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c index 0b28141e43bf..e1dab30aed30 100644 --- a/drivers/isdn/hardware/mISDN/hfcmulti.c +++ b/drivers/isdn/hardware/mISDN/hfcmulti.c @@ -104,7 +104,7 @@ * If unsure, don't give this parameter. * * dslot: - * NOTE: only one poll value must be given for every card. + * NOTE: only one dslot value must be given for every card. * Also this value must be given for non-E1 cards. If omitted, the E1 * card has D-channel on time slot 16, which is default. * If 1..15 or 17..31, an alternate time slot is used for D-channel. @@ -139,6 +139,10 @@ * Selects interface with clock source for mISDN and applications. * Set to card number starting with 1. Set to -1 to disable. * By default, the first card is used as clock source. + * + * hwid: + * NOTE: only one hwid value must be given once + * Enable special embedded devices with XHFC controllers. */ /* @@ -206,6 +210,11 @@ static int clock; static uint timer; static uint clockdelay_te = CLKDEL_TE; static uint clockdelay_nt = CLKDEL_NT; +#define HWID_NONE 0 +#define HWID_MINIP4 1 +#define HWID_MINIP8 2 +#define HWID_MINIP16 3 +static uint hwid = HWID_NONE; static int HFC_cnt, Port_cnt, PCM_cnt = 99; @@ -223,6 +232,7 @@ module_param_array(pcm, int, NULL, S_IRUGO | S_IWUSR); module_param_array(dslot, int, NULL, S_IRUGO | S_IWUSR); module_param_array(iomode, uint, NULL, S_IRUGO | S_IWUSR); module_param_array(port, uint, NULL, S_IRUGO | S_IWUSR); +module_param(hwid, uint, S_IRUGO | S_IWUSR); /* The hardware ID */ #ifdef HFC_REGISTER_DEBUG #define HFC_outb(hc, reg, val) \ @@ -252,6 +262,10 @@ module_param_array(port, uint, NULL, S_IRUGO | S_IWUSR); #define HFC_wait_nodebug(hc) (hc->HFC_wait_nodebug(hc)) #endif +#ifdef CONFIG_MISDN_HFCMULTI_8xx +#include "hfc_multi_8xx.h" +#endif + /* HFC_IO_MODE_PCIMEM */ static void #ifdef HFC_REGISTER_DEBUG @@ -261,7 +275,7 @@ HFC_outb_pcimem(struct hfc_multi *hc, u_char reg, u_char val, HFC_outb_pcimem(struct hfc_multi *hc, u_char reg, u_char val) #endif { - writeb(val, (hc->pci_membase)+reg); + writeb(val, hc->pci_membase + reg); } static u_char #ifdef HFC_REGISTER_DEBUG @@ -270,7 +284,7 @@ HFC_inb_pcimem(struct hfc_multi *hc, u_char reg, const char *function, int line) HFC_inb_pcimem(struct hfc_multi *hc, u_char reg) #endif { - return readb((hc->pci_membase)+reg); + return readb(hc->pci_membase + reg); } static u_short #ifdef HFC_REGISTER_DEBUG @@ -279,7 +293,7 @@ HFC_inw_pcimem(struct hfc_multi *hc, u_char reg, const char *function, int line) HFC_inw_pcimem(struct hfc_multi *hc, u_char reg) #endif { - return readw((hc->pci_membase)+reg); + return readw(hc->pci_membase + reg); } static void #ifdef HFC_REGISTER_DEBUG @@ -288,7 +302,8 @@ HFC_wait_pcimem(struct hfc_multi *hc, const char *function, int line) HFC_wait_pcimem(struct hfc_multi *hc) #endif { - while (readb((hc->pci_membase)+R_STATUS) & V_BUSY); + while (readb(hc->pci_membase + R_STATUS) & V_BUSY) + cpu_relax(); } /* HFC_IO_MODE_REGIO */ @@ -300,7 +315,7 @@ HFC_outb_regio(struct hfc_multi *hc, u_char reg, u_char val, HFC_outb_regio(struct hfc_multi *hc, u_char reg, u_char val) #endif { - outb(reg, (hc->pci_iobase)+4); + outb(reg, hc->pci_iobase + 4); outb(val, hc->pci_iobase); } static u_char @@ -310,7 +325,7 @@ HFC_inb_regio(struct hfc_multi *hc, u_char reg, const char *function, int line) HFC_inb_regio(struct hfc_multi *hc, u_char reg) #endif { - outb(reg, (hc->pci_iobase)+4); + outb(reg, hc->pci_iobase + 4); return inb(hc->pci_iobase); } static u_short @@ -320,7 +335,7 @@ HFC_inw_regio(struct hfc_multi *hc, u_char reg, const char *function, int line) HFC_inw_regio(struct hfc_multi *hc, u_char reg) #endif { - outb(reg, (hc->pci_iobase)+4); + outb(reg, hc->pci_iobase + 4); return inw(hc->pci_iobase); } static void @@ -330,8 +345,9 @@ HFC_wait_regio(struct hfc_multi *hc, const char *function, int line) HFC_wait_regio(struct hfc_multi *hc) #endif { - outb(R_STATUS, (hc->pci_iobase)+4); - while (inb(hc->pci_iobase) & V_BUSY); + outb(R_STATUS, hc->pci_iobase + 4); + while (inb(hc->pci_iobase) & V_BUSY) + cpu_relax(); } #ifdef HFC_REGISTER_DEBUG @@ -350,14 +366,14 @@ HFC_outb_debug(struct hfc_multi *hc, u_char reg, u_char val, if (regname[0] == '\0') strcpy(regname, "register"); - bits[7] = '0'+(!!(val&1)); - bits[6] = '0'+(!!(val&2)); - bits[5] = '0'+(!!(val&4)); - bits[4] = '0'+(!!(val&8)); - bits[3] = '0'+(!!(val&16)); - bits[2] = '0'+(!!(val&32)); - bits[1] = '0'+(!!(val&64)); - bits[0] = '0'+(!!(val&128)); + bits[7] = '0' + (!!(val & 1)); + bits[6] = '0' + (!!(val & 2)); + bits[5] = '0' + (!!(val & 4)); + bits[4] = '0' + (!!(val & 8)); + bits[3] = '0' + (!!(val & 16)); + bits[2] = '0' + (!!(val & 32)); + bits[1] = '0' + (!!(val & 64)); + bits[0] = '0' + (!!(val & 128)); printk(KERN_DEBUG "HFC_outb(chip %d, %02x=%s, 0x%02x=%s); in %s() line %d\n", hc->id, reg, regname, val, bits, function, line); @@ -380,14 +396,14 @@ HFC_inb_debug(struct hfc_multi *hc, u_char reg, const char *function, int line) if (regname[0] == '\0') strcpy(regname, "register"); - bits[7] = '0'+(!!(val&1)); - bits[6] = '0'+(!!(val&2)); - bits[5] = '0'+(!!(val&4)); - bits[4] = '0'+(!!(val&8)); - bits[3] = '0'+(!!(val&16)); - bits[2] = '0'+(!!(val&32)); - bits[1] = '0'+(!!(val&64)); - bits[0] = '0'+(!!(val&128)); + bits[7] = '0' + (!!(val & 1)); + bits[6] = '0' + (!!(val & 2)); + bits[5] = '0' + (!!(val & 4)); + bits[4] = '0' + (!!(val & 8)); + bits[3] = '0' + (!!(val & 16)); + bits[2] = '0' + (!!(val & 32)); + bits[1] = '0' + (!!(val & 64)); + bits[0] = '0' + (!!(val & 128)); printk(KERN_DEBUG "HFC_inb(chip %d, %02x=%s) = 0x%02x=%s; in %s() line %d\n", hc->id, reg, regname, val, bits, function, line); @@ -467,6 +483,7 @@ write_fifo_pcimem(struct hfc_multi *hc, u_char *data, int len) len--; } } + /* read fifo data (REGIO) */ static void read_fifo_regio(struct hfc_multi *hc, u_char *data, int len) @@ -512,7 +529,6 @@ read_fifo_pcimem(struct hfc_multi *hc, u_char *data, int len) } } - static void enable_hwirq(struct hfc_multi *hc) { @@ -928,7 +944,7 @@ hfcmulti_resync(struct hfc_multi *locked, struct hfc_multi *newmaster, int rm) writel(pv, plx_acc_32); if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip)) { pcmmaster = hc; - if (hc->type == 1) { + if (hc->ctype == HFC_TYPE_E1) { if (debug & DEBUG_HFCMULTI_PLXSD) printk(KERN_DEBUG "Schedule SYNC_I\n"); @@ -949,7 +965,8 @@ hfcmulti_resync(struct hfc_multi *locked, struct hfc_multi *newmaster, int rm) pv |= PLX_SYNC_O_EN; writel(pv, plx_acc_32); /* switch to jatt PLL, if not disabled by RX_SYNC */ - if (hc->type == 1 && !test_bit(HFC_CHIP_RX_SYNC, &hc->chip)) { + if (hc->ctype == HFC_TYPE_E1 + && !test_bit(HFC_CHIP_RX_SYNC, &hc->chip)) { if (debug & DEBUG_HFCMULTI_PLXSD) printk(KERN_DEBUG "Schedule jatt PLL\n"); hc->e1_resync |= 2; /* switch to jatt */ @@ -961,7 +978,7 @@ hfcmulti_resync(struct hfc_multi *locked, struct hfc_multi *newmaster, int rm) printk(KERN_DEBUG "id=%d (0x%p) = PCM master syncronized " "with QUARTZ\n", hc->id, hc); - if (hc->type == 1) { + if (hc->ctype == HFC_TYPE_E1) { /* Use the crystal clock for the PCM master card */ if (debug & DEBUG_HFCMULTI_PLXSD) @@ -972,7 +989,7 @@ hfcmulti_resync(struct hfc_multi *locked, struct hfc_multi *newmaster, int rm) if (debug & DEBUG_HFCMULTI_PLXSD) printk(KERN_DEBUG "QUARTZ is automatically " - "enabled by HFC-%dS\n", hc->type); + "enabled by HFC-%dS\n", hc->ctype); } plx_acc_32 = hc->plx_membase + PLX_GPIOC; pv = readl(plx_acc_32); @@ -996,7 +1013,7 @@ plxsd_checksync(struct hfc_multi *hc, int rm) if (hc->syncronized) { if (syncmaster == NULL) { if (debug & DEBUG_HFCMULTI_PLXSD) - printk(KERN_WARNING "%s: GOT sync on card %d" + printk(KERN_DEBUG "%s: GOT sync on card %d" " (id=%d)\n", __func__, hc->id + 1, hc->id); hfcmulti_resync(hc, hc, rm); @@ -1004,7 +1021,7 @@ plxsd_checksync(struct hfc_multi *hc, int rm) } else { if (syncmaster == hc) { if (debug & DEBUG_HFCMULTI_PLXSD) - printk(KERN_WARNING "%s: LOST sync on card %d" + printk(KERN_DEBUG "%s: LOST sync on card %d" " (id=%d)\n", __func__, hc->id + 1, hc->id); hfcmulti_resync(hc, NULL, rm); @@ -1053,20 +1070,23 @@ release_io_hfcmulti(struct hfc_multi *hc) pv &= ~PLX_DSP_RES_N; writel(pv, plx_acc_32); if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_WARNING "%s: PCM off: PLX_GPIO=%x\n", + printk(KERN_DEBUG "%s: PCM off: PLX_GPIO=%x\n", __func__, pv); spin_unlock_irqrestore(&plx_lock, plx_flags); } /* disable memory mapped ports / io ports */ test_and_clear_bit(HFC_CHIP_PLXSD, &hc->chip); /* prevent resync */ - pci_write_config_word(hc->pci_dev, PCI_COMMAND, 0); + if (hc->pci_dev) + pci_write_config_word(hc->pci_dev, PCI_COMMAND, 0); if (hc->pci_membase) iounmap(hc->pci_membase); if (hc->plx_membase) iounmap(hc->plx_membase); if (hc->pci_iobase) release_region(hc->pci_iobase, 8); + if (hc->xhfc_membase) + iounmap((void *)hc->xhfc_membase); if (hc->pci_dev) { pci_disable_device(hc->pci_dev); @@ -1100,8 +1120,9 @@ init_chip(struct hfc_multi *hc) /* revision check */ if (debug & DEBUG_HFCMULTI_INIT) printk(KERN_DEBUG "%s: entered\n", __func__); - val = HFC_inb(hc, R_CHIP_ID)>>4; - if (val != 0x8 && val != 0xc && val != 0xe) { + val = HFC_inb(hc, R_CHIP_ID); + if ((val >> 4) != 0x8 && (val >> 4) != 0xc && (val >> 4) != 0xe && + (val >> 1) != 0x31) { printk(KERN_INFO "HFC_multi: unknown CHIP_ID:%x\n", (u_int)val); err = -EIO; goto out; @@ -1109,8 +1130,9 @@ init_chip(struct hfc_multi *hc) rev = HFC_inb(hc, R_CHIP_RV); printk(KERN_INFO "HFC_multi: detected HFC with chip ID=0x%lx revision=%ld%s\n", - val, rev, (rev == 0) ? " (old FIFO handling)" : ""); - if (rev == 0) { + val, rev, (rev == 0 && (hc->ctype != HFC_TYPE_XHFC)) ? + " (old FIFO handling)" : ""); + if (hc->ctype != HFC_TYPE_XHFC && rev == 0) { test_and_set_bit(HFC_CHIP_REVISION0, &hc->chip); printk(KERN_WARNING "HFC_multi: NOTE: Your chip is revision 0, " @@ -1152,6 +1174,12 @@ init_chip(struct hfc_multi *hc) hc->Zlen = 8000; hc->DTMFbase = 0x2000; } + if (hc->ctype == HFC_TYPE_XHFC) { + hc->Flen = 0x8; + hc->Zmin = 0x0; + hc->Zlen = 64; + hc->DTMFbase = 0x0; + } hc->max_trans = poll << 1; if (hc->max_trans > hc->Zlen) hc->max_trans = hc->Zlen; @@ -1176,7 +1204,7 @@ init_chip(struct hfc_multi *hc) writel(pv, plx_acc_32); spin_unlock_irqrestore(&plx_lock, plx_flags); if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_WARNING "%s: slave/term: PLX_GPIO=%x\n", + printk(KERN_DEBUG "%s: slave/term: PLX_GPIO=%x\n", __func__, pv); /* * If we are the 3rd PLXSD card or higher, we must turn @@ -1204,13 +1232,17 @@ init_chip(struct hfc_multi *hc) writel(pv, plx_acc_32); spin_unlock_irqrestore(&plx_lock, plx_flags); if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_WARNING "%s: term off: PLX_GPIO=%x\n", - __func__, pv); + printk(KERN_DEBUG + "%s: term off: PLX_GPIO=%x\n", + __func__, pv); } spin_unlock_irqrestore(&HFClock, hfc_flags); hc->hw.r_pcm_md0 = V_F0_LEN; /* shift clock for DSP */ } + if (test_bit(HFC_CHIP_EMBSD, &hc->chip)) + hc->hw.r_pcm_md0 = V_F0_LEN; /* shift clock for DSP */ + /* we only want the real Z2 read-pointer for revision > 0 */ if (!test_bit(HFC_CHIP_REVISION0, &hc->chip)) hc->hw.r_ram_sz |= V_FZ_MD; @@ -1234,15 +1266,24 @@ init_chip(struct hfc_multi *hc) /* soft reset */ HFC_outb(hc, R_CTRL, hc->hw.r_ctrl); - HFC_outb(hc, R_RAM_SZ, hc->hw.r_ram_sz); + if (hc->ctype == HFC_TYPE_XHFC) + HFC_outb(hc, 0x0C /* R_FIFO_THRES */, + 0x11 /* 16 Bytes TX/RX */); + else + HFC_outb(hc, R_RAM_SZ, hc->hw.r_ram_sz); HFC_outb(hc, R_FIFO_MD, 0); - hc->hw.r_cirm = V_SRES | V_HFCRES | V_PCMRES | V_STRES | V_RLD_EPR; + if (hc->ctype == HFC_TYPE_XHFC) + hc->hw.r_cirm = V_SRES | V_HFCRES | V_PCMRES | V_STRES; + else + hc->hw.r_cirm = V_SRES | V_HFCRES | V_PCMRES | V_STRES + | V_RLD_EPR; HFC_outb(hc, R_CIRM, hc->hw.r_cirm); udelay(100); hc->hw.r_cirm = 0; HFC_outb(hc, R_CIRM, hc->hw.r_cirm); udelay(100); - HFC_outb(hc, R_RAM_SZ, hc->hw.r_ram_sz); + if (hc->ctype != HFC_TYPE_XHFC) + HFC_outb(hc, R_RAM_SZ, hc->hw.r_ram_sz); /* Speech Design PLX bridge pcm and sync mode */ if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { @@ -1254,13 +1295,13 @@ init_chip(struct hfc_multi *hc) pv |= PLX_MASTER_EN | PLX_SLAVE_EN_N; pv |= PLX_SYNC_O_EN; if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_WARNING "%s: master: PLX_GPIO=%x\n", + printk(KERN_DEBUG "%s: master: PLX_GPIO=%x\n", __func__, pv); } else { pv &= ~(PLX_MASTER_EN | PLX_SLAVE_EN_N); pv &= ~PLX_SYNC_O_EN; if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_WARNING "%s: slave: PLX_GPIO=%x\n", + printk(KERN_DEBUG "%s: slave: PLX_GPIO=%x\n", __func__, pv); } writel(pv, plx_acc_32); @@ -1278,13 +1319,16 @@ init_chip(struct hfc_multi *hc) HFC_outb(hc, R_PCM_MD0, hc->hw.r_pcm_md0 | 0xa0); if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) HFC_outb(hc, R_PCM_MD2, V_SYNC_SRC); /* sync via SYNC_I / O */ + else if (test_bit(HFC_CHIP_EMBSD, &hc->chip)) + HFC_outb(hc, R_PCM_MD2, 0x10); /* V_C2O_EN */ else HFC_outb(hc, R_PCM_MD2, 0x00); /* sync from interface */ HFC_outb(hc, R_PCM_MD0, hc->hw.r_pcm_md0 | 0x00); for (i = 0; i < 256; i++) { HFC_outb_nodebug(hc, R_SLOT, i); HFC_outb_nodebug(hc, A_SL_CFG, 0); - HFC_outb_nodebug(hc, A_CONF, 0); + if (hc->ctype != HFC_TYPE_XHFC) + HFC_outb_nodebug(hc, A_CONF, 0); hc->slot_owner[i] = -1; } @@ -1296,6 +1340,9 @@ init_chip(struct hfc_multi *hc) HFC_outb(hc, R_BRG_PCM_CFG, V_PCM_CLK); } + if (test_bit(HFC_CHIP_EMBSD, &hc->chip)) + HFC_outb(hc, 0x02 /* R_CLK_CFG */, 0x40 /* V_CLKO_OFF */); + /* B410P GPIO */ if (test_bit(HFC_CHIP_B410P, &hc->chip)) { printk(KERN_NOTICE "Setting GPIOs\n"); @@ -1366,8 +1413,8 @@ controller_fail: writel(pv, plx_acc_32); spin_unlock_irqrestore(&plx_lock, plx_flags); if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_WARNING "%s: master: PLX_GPIO" - "=%x\n", __func__, pv); + printk(KERN_DEBUG "%s: master: " + "PLX_GPIO=%x\n", __func__, pv); } hc->hw.r_pcm_md0 |= V_PCM_MD; HFC_outb(hc, R_PCM_MD0, hc->hw.r_pcm_md0 | 0x00); @@ -1401,7 +1448,7 @@ controller_fail: writel(pv, plx_acc_32); spin_unlock_irqrestore(&plx_lock, plx_flags); if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_WARNING "%s: reset off: PLX_GPIO=%x\n", + printk(KERN_DEBUG "%s: reset off: PLX_GPIO=%x\n", __func__, pv); } @@ -1424,7 +1471,7 @@ controller_fail: hc->hw.r_irqmsk_misc |= V_TI_IRQMSK; /* set E1 state machine IRQ */ - if (hc->type == 1) + if (hc->ctype == HFC_TYPE_E1) hc->hw.r_irqmsk_misc |= V_STA_IRQMSK; /* set DTMF detection */ @@ -1444,7 +1491,8 @@ controller_fail: r_conf_en = V_CONF_EN | V_ULAW; else r_conf_en = V_CONF_EN; - HFC_outb(hc, R_CONF_EN, r_conf_en); + if (hc->ctype != HFC_TYPE_XHFC) + HFC_outb(hc, R_CONF_EN, r_conf_en); /* setting leds */ switch (hc->leds) { @@ -1468,16 +1516,23 @@ controller_fail: break; } + if (test_bit(HFC_CHIP_EMBSD, &hc->chip)) { + hc->hw.r_st_sync = 0x10; /* V_AUTO_SYNCI */ + HFC_outb(hc, R_ST_SYNC, hc->hw.r_st_sync); + } + /* set master clock */ if (hc->masterclk >= 0) { if (debug & DEBUG_HFCMULTI_INIT) printk(KERN_DEBUG "%s: setting ST master clock " "to port %d (0..%d)\n", __func__, hc->masterclk, hc->ports-1); - hc->hw.r_st_sync = hc->masterclk | V_AUTO_SYNC; + hc->hw.r_st_sync |= (hc->masterclk | V_AUTO_SYNC); HFC_outb(hc, R_ST_SYNC, hc->hw.r_st_sync); } + + /* setting misc irq */ HFC_outb(hc, R_IRQMSK_MISC, hc->hw.r_irqmsk_misc); if (debug & DEBUG_HFCMULTI_INIT) @@ -1817,8 +1872,8 @@ hfcmulti_dtmf(struct hfc_multi *hc) coeff[(co<<1)|1] = mantissa; } if (debug & DEBUG_HFCMULTI_DTMF) - printk("%s: DTMF ready %08x %08x %08x %08x " - "%08x %08x %08x %08x\n", __func__, + printk(" DTMF ready %08x %08x %08x %08x " + "%08x %08x %08x %08x\n", coeff[0], coeff[1], coeff[2], coeff[3], coeff[4], coeff[5], coeff[6], coeff[7]); hc->chan[ch].coeff_count++; @@ -1826,7 +1881,7 @@ hfcmulti_dtmf(struct hfc_multi *hc) hc->chan[ch].coeff_count = 0; skb = mI_alloc_skb(512, GFP_ATOMIC); if (!skb) { - printk(KERN_WARNING "%s: No memory for skb\n", + printk(KERN_DEBUG "%s: No memory for skb\n", __func__); continue; } @@ -1929,7 +1984,7 @@ next_frame: Fspace = 1; } /* one frame only for ST D-channels, to allow resending */ - if (hc->type != 1 && dch) { + if (hc->ctype != HFC_TYPE_E1 && dch) { if (f1 != f2) Fspace = 0; } @@ -1945,6 +2000,9 @@ next_frame: "%d!=%d\n", __func__, hc->id + 1, temp, z2); z2 = temp; /* repeat unti Z2 is equal */ } + hc->chan[ch].Zfill = z1 - z2; + if (hc->chan[ch].Zfill < 0) + hc->chan[ch].Zfill += hc->Zlen; Zspace = z2 - z1; if (Zspace <= 0) Zspace += hc->Zlen; @@ -1968,12 +2026,22 @@ next_frame: "slot_tx %d\n", __func__, ch, slot_tx); /* connect slot */ - HFC_outb(hc, A_CON_HDLC, 0xc0 | 0x00 | - V_HDLC_TRP | V_IFF); + if (hc->ctype == HFC_TYPE_XHFC) + HFC_outb(hc, A_CON_HDLC, 0xc0 + | 0x07 << 2 | V_HDLC_TRP | V_IFF); + /* Enable FIFO, no interrupt */ + else + HFC_outb(hc, A_CON_HDLC, 0xc0 | 0x00 | + V_HDLC_TRP | V_IFF); HFC_outb_nodebug(hc, R_FIFO, ch<<1 | 1); HFC_wait_nodebug(hc); - HFC_outb(hc, A_CON_HDLC, 0xc0 | 0x00 | - V_HDLC_TRP | V_IFF); + if (hc->ctype == HFC_TYPE_XHFC) + HFC_outb(hc, A_CON_HDLC, 0xc0 + | 0x07 << 2 | V_HDLC_TRP | V_IFF); + /* Enable FIFO, no interrupt */ + else + HFC_outb(hc, A_CON_HDLC, 0xc0 | 0x00 | + V_HDLC_TRP | V_IFF); HFC_outb_nodebug(hc, R_FIFO, ch<<1); HFC_wait_nodebug(hc); } @@ -2001,10 +2069,22 @@ next_frame: "FIFO data: channel %d slot_tx %d\n", __func__, ch, slot_tx); /* disconnect slot */ - HFC_outb(hc, A_CON_HDLC, 0x80 | 0x00 | V_HDLC_TRP | V_IFF); + if (hc->ctype == HFC_TYPE_XHFC) + HFC_outb(hc, A_CON_HDLC, 0x80 + | 0x07 << 2 | V_HDLC_TRP | V_IFF); + /* Enable FIFO, no interrupt */ + else + HFC_outb(hc, A_CON_HDLC, 0x80 | 0x00 | + V_HDLC_TRP | V_IFF); HFC_outb_nodebug(hc, R_FIFO, ch<<1 | 1); HFC_wait_nodebug(hc); - HFC_outb(hc, A_CON_HDLC, 0x80 | 0x00 | V_HDLC_TRP | V_IFF); + if (hc->ctype == HFC_TYPE_XHFC) + HFC_outb(hc, A_CON_HDLC, 0x80 + | 0x07 << 2 | V_HDLC_TRP | V_IFF); + /* Enable FIFO, no interrupt */ + else + HFC_outb(hc, A_CON_HDLC, 0x80 | 0x00 | + V_HDLC_TRP | V_IFF); HFC_outb_nodebug(hc, R_FIFO, ch<<1); HFC_wait_nodebug(hc); } @@ -2027,10 +2107,11 @@ next_frame: printk(KERN_DEBUG "%s(card %d): fifo(%d) has %d bytes space " "left (z1=%04x, z2=%04x) sending %d of %d bytes %s\n", __func__, hc->id + 1, ch, Zspace, z1, z2, ii-i, len-i, - temp ? "HDLC":"TRANS"); + temp ? "HDLC" : "TRANS"); /* Have to prep the audio data */ hc->write_fifo(hc, d, ii - i); + hc->chan[ch].Zfill += ii - i; *idxp = ii; /* if not all data has been written */ @@ -2226,7 +2307,7 @@ next_frame: if (dch) recv_Dchannel(dch); else - recv_Bchannel(bch); + recv_Bchannel(bch, MISDN_ID_ANY); *sp = skb; again++; goto next_frame; @@ -2258,7 +2339,7 @@ next_frame: "(z1=%04x, z2=%04x) TRANS\n", __func__, hc->id + 1, ch, Zsize, z1, z2); /* only bch is transparent */ - recv_Bchannel(bch); + recv_Bchannel(bch, hc->chan[ch].Zfill); *sp = skb; } } @@ -2323,7 +2404,7 @@ handle_timer_irq(struct hfc_multi *hc) spin_unlock_irqrestore(&HFClock, flags); } - if (hc->type != 1 || hc->e1_state == 1) + if (hc->ctype != HFC_TYPE_E1 || hc->e1_state == 1) for (ch = 0; ch <= 31; ch++) { if (hc->created[hc->chan[ch].port]) { hfcmulti_tx(hc, ch); @@ -2346,7 +2427,7 @@ handle_timer_irq(struct hfc_multi *hc) } } } - if (hc->type == 1 && hc->created[0]) { + if (hc->ctype == HFC_TYPE_E1 && hc->created[0]) { dch = hc->chan[hc->dslot].dch; if (test_bit(HFC_CFG_REPORT_LOS, &hc->chan[hc->dslot].cfg)) { /* LOS */ @@ -2606,7 +2687,10 @@ hfcmulti_interrupt(int intno, void *dev_id) "card %d, this is no bug.\n", hc->id + 1, irqsem); irqsem = hc->id + 1; #endif - +#ifdef CONFIG_MISDN_HFCMULTI_8xx + if (hc->immap->im_cpm.cp_pbdat & hc->pb_irqmsk) + goto irq_notforus; +#endif if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { spin_lock_irqsave(&plx_lock, flags); plx_acc = hc->plx_membase + PLX_INTCSR; @@ -2646,7 +2730,7 @@ hfcmulti_interrupt(int intno, void *dev_id) } hc->irqcnt++; if (r_irq_statech) { - if (hc->type != 1) + if (hc->ctype != HFC_TYPE_E1) ph_state_irq(hc, r_irq_statech); } if (status & V_EXT_IRQSTA) @@ -2660,7 +2744,7 @@ hfcmulti_interrupt(int intno, void *dev_id) r_irq_misc = HFC_inb_nodebug(hc, R_IRQ_MISC); r_irq_misc &= hc->hw.r_irqmsk_misc; /* ignore disabled irqs */ if (r_irq_misc & V_STA_IRQ) { - if (hc->type == 1) { + if (hc->ctype == HFC_TYPE_E1) { /* state machine */ dch = hc->chan[hc->dslot].dch; e1_syncsta = HFC_inb_nodebug(hc, R_SYNC_STA); @@ -2699,13 +2783,13 @@ hfcmulti_interrupt(int intno, void *dev_id) handle_timer_irq(hc); } - if (r_irq_misc & V_DTMF_IRQ) { + if (r_irq_misc & V_DTMF_IRQ) hfcmulti_dtmf(hc); - } + if (r_irq_misc & V_IRQ_PROC) { static int irq_proc_cnt; if (!irq_proc_cnt++) - printk(KERN_WARNING "%s: got V_IRQ_PROC -" + printk(KERN_DEBUG "%s: got V_IRQ_PROC -" " this should not happen\n", __func__); } @@ -2782,7 +2866,8 @@ mode_hfcmulti(struct hfc_multi *hc, int ch, int protocol, int slot_tx, if (hc->slot_owner[oslot_tx<<1] == ch) { HFC_outb(hc, R_SLOT, oslot_tx << 1); HFC_outb(hc, A_SL_CFG, 0); - HFC_outb(hc, A_CONF, 0); + if (hc->ctype != HFC_TYPE_XHFC) + HFC_outb(hc, A_CONF, 0); hc->slot_owner[oslot_tx<<1] = -1; } else { if (debug & DEBUG_HFCMULTI_MODE) @@ -2835,7 +2920,9 @@ mode_hfcmulti(struct hfc_multi *hc, int ch, int protocol, int slot_tx, flow_tx, routing, conf); HFC_outb(hc, R_SLOT, slot_tx << 1); HFC_outb(hc, A_SL_CFG, (ch<<1) | routing); - HFC_outb(hc, A_CONF, (conf < 0) ? 0 : (conf | V_CONF_SL)); + if (hc->ctype != HFC_TYPE_XHFC) + HFC_outb(hc, A_CONF, + (conf < 0) ? 0 : (conf | V_CONF_SL)); hc->slot_owner[slot_tx << 1] = ch; hc->chan[ch].slot_tx = slot_tx; hc->chan[ch].bank_tx = bank_tx; @@ -2852,7 +2939,7 @@ mode_hfcmulti(struct hfc_multi *hc, int ch, int protocol, int slot_tx, else flow_rx = 0xc0; /* ST->(FIFO,PCM) */ /* put on slot */ - routing = bank_rx?0x80:0xc0; /* reversed */ + routing = bank_rx ? 0x80 : 0xc0; /* reversed */ if (conf >= 0 || bank_rx > 1) routing = 0x40; /* loop */ if (debug & DEBUG_HFCMULTI_MODE) @@ -2885,9 +2972,9 @@ mode_hfcmulti(struct hfc_multi *hc, int ch, int protocol, int slot_tx, HFC_outb(hc, A_IRQ_MSK, 0); HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); HFC_wait(hc); - if (hc->chan[ch].bch && hc->type != 1) { + if (hc->chan[ch].bch && hc->ctype != HFC_TYPE_E1) { hc->hw.a_st_ctrl0[hc->chan[ch].port] &= - ((ch & 0x3) == 0)? ~V_B1_EN: ~V_B2_EN; + ((ch & 0x3) == 0) ? ~V_B1_EN : ~V_B2_EN; HFC_outb(hc, R_ST_SEL, hc->chan[ch].port); /* undocumented: delay after R_ST_SEL */ udelay(1); @@ -2961,8 +3048,13 @@ mode_hfcmulti(struct hfc_multi *hc, int ch, int protocol, int slot_tx, /* enable TX fifo */ HFC_outb(hc, R_FIFO, ch << 1); HFC_wait(hc); - HFC_outb(hc, A_CON_HDLC, flow_tx | 0x00 | - V_HDLC_TRP | V_IFF); + if (hc->ctype == HFC_TYPE_XHFC) + HFC_outb(hc, A_CON_HDLC, flow_tx | 0x07 << 2 | + V_HDLC_TRP | V_IFF); + /* Enable FIFO, no interrupt */ + else + HFC_outb(hc, A_CON_HDLC, flow_tx | 0x00 | + V_HDLC_TRP | V_IFF); HFC_outb(hc, A_SUBCH_CFG, 0); HFC_outb(hc, A_IRQ_MSK, 0); HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); @@ -2972,13 +3064,19 @@ mode_hfcmulti(struct hfc_multi *hc, int ch, int protocol, int slot_tx, /* enable RX fifo */ HFC_outb(hc, R_FIFO, (ch<<1)|1); HFC_wait(hc); - HFC_outb(hc, A_CON_HDLC, flow_rx | 0x00 | V_HDLC_TRP); + if (hc->ctype == HFC_TYPE_XHFC) + HFC_outb(hc, A_CON_HDLC, flow_rx | 0x07 << 2 | + V_HDLC_TRP); + /* Enable FIFO, no interrupt*/ + else + HFC_outb(hc, A_CON_HDLC, flow_rx | 0x00 | + V_HDLC_TRP); HFC_outb(hc, A_SUBCH_CFG, 0); HFC_outb(hc, A_IRQ_MSK, 0); HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); HFC_wait(hc); } - if (hc->type != 1) { + if (hc->ctype != HFC_TYPE_E1) { hc->hw.a_st_ctrl0[hc->chan[ch].port] |= ((ch & 0x3) == 0) ? V_B1_EN : V_B2_EN; HFC_outb(hc, R_ST_SEL, hc->chan[ch].port); @@ -2999,7 +3097,7 @@ mode_hfcmulti(struct hfc_multi *hc, int ch, int protocol, int slot_tx, /* enable TX fifo */ HFC_outb(hc, R_FIFO, ch<<1); HFC_wait(hc); - if (hc->type == 1 || hc->chan[ch].bch) { + if (hc->ctype == HFC_TYPE_E1 || hc->chan[ch].bch) { /* E1 or B-channel */ HFC_outb(hc, A_CON_HDLC, flow_tx | 0x04); HFC_outb(hc, A_SUBCH_CFG, 0); @@ -3015,7 +3113,7 @@ mode_hfcmulti(struct hfc_multi *hc, int ch, int protocol, int slot_tx, HFC_outb(hc, R_FIFO, (ch<<1)|1); HFC_wait(hc); HFC_outb(hc, A_CON_HDLC, flow_rx | 0x04); - if (hc->type == 1 || hc->chan[ch].bch) + if (hc->ctype == HFC_TYPE_E1 || hc->chan[ch].bch) HFC_outb(hc, A_SUBCH_CFG, 0); /* full 8 bits */ else HFC_outb(hc, A_SUBCH_CFG, 2); /* 2 bits dchannel */ @@ -3024,7 +3122,7 @@ mode_hfcmulti(struct hfc_multi *hc, int ch, int protocol, int slot_tx, HFC_wait(hc); if (hc->chan[ch].bch) { test_and_set_bit(FLG_HDLC, &hc->chan[ch].bch->Flags); - if (hc->type != 1) { + if (hc->ctype != HFC_TYPE_E1) { hc->hw.a_st_ctrl0[hc->chan[ch].port] |= ((ch&0x3) == 0) ? V_B1_EN : V_B2_EN; HFC_outb(hc, R_ST_SEL, hc->chan[ch].port); @@ -3104,7 +3202,7 @@ hfcm_l1callback(struct dchannel *dch, u_int cmd) case HW_RESET_REQ: /* start activation */ spin_lock_irqsave(&hc->lock, flags); - if (hc->type == 1) { + if (hc->ctype == HFC_TYPE_E1) { if (debug & DEBUG_HFCMULTI_MSG) printk(KERN_DEBUG "%s: HW_RESET_REQ no BRI\n", @@ -3125,7 +3223,7 @@ hfcm_l1callback(struct dchannel *dch, u_int cmd) case HW_DEACT_REQ: /* start deactivation */ spin_lock_irqsave(&hc->lock, flags); - if (hc->type == 1) { + if (hc->ctype == HFC_TYPE_E1) { if (debug & DEBUG_HFCMULTI_MSG) printk(KERN_DEBUG "%s: HW_DEACT_REQ no BRI\n", @@ -3159,7 +3257,7 @@ hfcm_l1callback(struct dchannel *dch, u_int cmd) break; case HW_POWERUP_REQ: spin_lock_irqsave(&hc->lock, flags); - if (hc->type == 1) { + if (hc->ctype == HFC_TYPE_E1) { if (debug & DEBUG_HFCMULTI_MSG) printk(KERN_DEBUG "%s: HW_POWERUP_REQ no BRI\n", @@ -3236,7 +3334,7 @@ handle_dmsg(struct mISDNchannel *ch, struct sk_buff *skb) __func__, hc->chan[dch->slot].port, hc->ports-1); /* start activation */ - if (hc->type == 1) { + if (hc->ctype == HFC_TYPE_E1) { ph_state_change(dch); if (debug & DEBUG_HFCMULTI_STATE) printk(KERN_DEBUG @@ -3269,7 +3367,7 @@ handle_dmsg(struct mISDNchannel *ch, struct sk_buff *skb) __func__, hc->chan[dch->slot].port, hc->ports-1); /* start deactivation */ - if (hc->type == 1) { + if (hc->ctype == HFC_TYPE_E1) { if (debug & DEBUG_HFCMULTI_MSG) printk(KERN_DEBUG "%s: PH_DEACTIVATE no BRI\n", @@ -3410,9 +3508,9 @@ handle_bmsg(struct mISDNchannel *ch, struct sk_buff *skb) switch (hh->id) { case HFC_SPL_LOOP_ON: /* set sample loop */ if (debug & DEBUG_HFCMULTI_MSG) - printk(KERN_DEBUG - "%s: HFC_SPL_LOOP_ON (len = %d)\n", - __func__, skb->len); + printk(KERN_DEBUG + "%s: HFC_SPL_LOOP_ON (len = %d)\n", + __func__, skb->len); ret = 0; break; case HFC_SPL_LOOP_OFF: /* set silence */ @@ -3489,6 +3587,8 @@ channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) features->hfc_id = hc->id; if (test_bit(HFC_CHIP_DTMF, &hc->chip)) features->hfc_dtmf = 1; + if (test_bit(HFC_CHIP_CONF, &hc->chip)) + features->hfc_conf = 1; features->hfc_loops = 0; if (test_bit(HFC_CHIP_B410P, &hc->chip)) { features->hfc_echocanhw = 1; @@ -3619,14 +3719,13 @@ ph_state_change(struct dchannel *dch) int ch, i; if (!dch) { - printk(KERN_WARNING "%s: ERROR given dch is NULL\n", - __func__); + printk(KERN_WARNING "%s: ERROR given dch is NULL\n", __func__); return; } hc = dch->hw; ch = dch->slot; - if (hc->type == 1) { + if (hc->ctype == HFC_TYPE_E1) { if (dch->dev.D.protocol == ISDN_P_TE_E1) { if (debug & DEBUG_HFCMULTI_STATE) printk(KERN_DEBUG @@ -3641,14 +3740,15 @@ ph_state_change(struct dchannel *dch) switch (dch->state) { case (1): if (hc->e1_state != 1) { - for (i = 1; i <= 31; i++) { - /* reset fifos on e1 activation */ - HFC_outb_nodebug(hc, R_FIFO, (i << 1) | 1); - HFC_wait_nodebug(hc); - HFC_outb_nodebug(hc, - R_INC_RES_FIFO, V_RES_F); - HFC_wait_nodebug(hc); - } + for (i = 1; i <= 31; i++) { + /* reset fifos on e1 activation */ + HFC_outb_nodebug(hc, R_FIFO, + (i << 1) | 1); + HFC_wait_nodebug(hc); + HFC_outb_nodebug(hc, R_INC_RES_FIFO, + V_RES_F); + HFC_wait_nodebug(hc); + } } test_and_set_bit(FLG_ACTIVE, &dch->Flags); _queue_data(&dch->dev.D, PH_ACTIVATE_IND, @@ -3751,7 +3851,7 @@ hfcmulti_initmode(struct dchannel *dch) if (debug & DEBUG_HFCMULTI_INIT) printk(KERN_DEBUG "%s: entered\n", __func__); - if (hc->type == 1) { + if (hc->ctype == HFC_TYPE_E1) { hc->chan[hc->dslot].slot_tx = -1; hc->chan[hc->dslot].slot_rx = -1; hc->chan[hc->dslot].conf = -1; @@ -3900,6 +4000,11 @@ hfcmulti_initmode(struct dchannel *dch) } if (!test_bit(HFC_CFG_NONCAP_TX, &hc->chan[i].cfg)) hc->hw.a_st_ctrl0[pt] |= V_TX_LI; + if (hc->ctype == HFC_TYPE_XHFC) { + hc->hw.a_st_ctrl0[pt] |= 0x40 /* V_ST_PU_CTRL */; + HFC_outb(hc, 0x35 /* A_ST_CTRL3 */, + 0x7c << 1 /* V_ST_PULSE */); + } /* line setup */ HFC_outb(hc, A_ST_CTRL0, hc->hw.a_st_ctrl0[pt]); /* disable E-channel */ @@ -3943,12 +4048,12 @@ open_dchannel(struct hfc_multi *hc, struct dchannel *dch, return -EINVAL; if ((dch->dev.D.protocol != ISDN_P_NONE) && (dch->dev.D.protocol != rq->protocol)) { - if (debug & DEBUG_HFCMULTI_MODE) - printk(KERN_WARNING "%s: change protocol %x to %x\n", - __func__, dch->dev.D.protocol, rq->protocol); + if (debug & DEBUG_HFCMULTI_MODE) + printk(KERN_DEBUG "%s: change protocol %x to %x\n", + __func__, dch->dev.D.protocol, rq->protocol); } - if ((dch->dev.D.protocol == ISDN_P_TE_S0) - && (rq->protocol != ISDN_P_TE_S0)) + if ((dch->dev.D.protocol == ISDN_P_TE_S0) && + (rq->protocol != ISDN_P_TE_S0)) l1_event(dch->l1, CLOSE_CHANNEL); if (dch->dev.D.protocol != rq->protocol) { if (rq->protocol == ISDN_P_TE_S0) { @@ -3986,7 +4091,7 @@ open_bchannel(struct hfc_multi *hc, struct dchannel *dch, return -EINVAL; if (rq->protocol == ISDN_P_NONE) return -EINVAL; - if (hc->type == 1) + if (hc->ctype == HFC_TYPE_E1) ch = rq->adr.channel; else ch = (rq->adr.channel - 1) + (dch->slot - 2); @@ -4013,11 +4118,41 @@ open_bchannel(struct hfc_multi *hc, struct dchannel *dch, static int channel_dctrl(struct dchannel *dch, struct mISDN_ctrl_req *cq) { + struct hfc_multi *hc = dch->hw; int ret = 0; + int wd_mode, wd_cnt; switch (cq->op) { case MISDN_CTRL_GETOP: - cq->op = 0; + cq->op = MISDN_CTRL_HFC_OP; + break; + case MISDN_CTRL_HFC_WD_INIT: /* init the watchdog */ + wd_cnt = cq->p1 & 0xf; + wd_mode = !!(cq->p1 >> 4); + if (debug & DEBUG_HFCMULTI_MSG) + printk(KERN_DEBUG "%s: MISDN_CTRL_HFC_WD_INIT mode %s" + ", counter 0x%x\n", __func__, + wd_mode ? "AUTO" : "MANUAL", wd_cnt); + /* set the watchdog timer */ + HFC_outb(hc, R_TI_WD, poll_timer | (wd_cnt << 4)); + hc->hw.r_bert_wd_md = (wd_mode ? V_AUTO_WD_RES : 0); + if (hc->ctype == HFC_TYPE_XHFC) + hc->hw.r_bert_wd_md |= 0x40 /* V_WD_EN */; + /* init the watchdog register and reset the counter */ + HFC_outb(hc, R_BERT_WD_MD, hc->hw.r_bert_wd_md | V_WD_RES); + if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { + /* enable the watchdog output for Speech-Design */ + HFC_outb(hc, R_GPIO_SEL, V_GPIO_SEL7); + HFC_outb(hc, R_GPIO_EN1, V_GPIO_EN15); + HFC_outb(hc, R_GPIO_OUT1, 0); + HFC_outb(hc, R_GPIO_OUT1, V_GPIO_OUT15); + } + break; + case MISDN_CTRL_HFC_WD_RESET: /* reset the watchdog counter */ + if (debug & DEBUG_HFCMULTI_MSG) + printk(KERN_DEBUG "%s: MISDN_CTRL_HFC_WD_RESET\n", + __func__); + HFC_outb(hc, R_BERT_WD_MD, hc->hw.r_bert_wd_md | V_WD_RES); break; default: printk(KERN_WARNING "%s: unknown Op %x\n", @@ -4047,7 +4182,7 @@ hfcm_dctrl(struct mISDNchannel *ch, u_int cmd, void *arg) switch (rq->protocol) { case ISDN_P_TE_S0: case ISDN_P_NT_S0: - if (hc->type == 1) { + if (hc->ctype == HFC_TYPE_E1) { err = -EINVAL; break; } @@ -4055,7 +4190,7 @@ hfcm_dctrl(struct mISDNchannel *ch, u_int cmd, void *arg) break; case ISDN_P_TE_E1: case ISDN_P_NT_E1: - if (hc->type != 1) { + if (hc->ctype != HFC_TYPE_E1) { err = -EINVAL; break; } @@ -4122,13 +4257,13 @@ init_card(struct hfc_multi *hc) disable_hwirq(hc); spin_unlock_irqrestore(&hc->lock, flags); - if (request_irq(hc->pci_dev->irq, hfcmulti_interrupt, IRQF_SHARED, + if (request_irq(hc->irq, hfcmulti_interrupt, IRQF_SHARED, "HFC-multi", hc)) { printk(KERN_WARNING "mISDN: Could not get interrupt %d.\n", - hc->pci_dev->irq); + hc->irq); + hc->irq = 0; return -EIO; } - hc->irq = hc->pci_dev->irq; if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { spin_lock_irqsave(&plx_lock, plx_flags); @@ -4187,7 +4322,7 @@ error: } if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_WARNING "%s: free irq %d\n", __func__, hc->irq); + printk(KERN_DEBUG "%s: free irq %d\n", __func__, hc->irq); if (hc->irq) { free_irq(hc->irq, hc); hc->irq = 0; @@ -4235,6 +4370,10 @@ setup_pci(struct hfc_multi *hc, struct pci_dev *pdev, hc->ledstate = 0xAFFEAFFE; hc->opticalsupport = m->opticalsupport; + hc->pci_iobase = 0; + hc->pci_membase = NULL; + hc->plx_membase = NULL; + /* set memory access methods */ if (m->io_mode) /* use mode from card config */ hc->io_mode = m->io_mode; @@ -4242,44 +4381,12 @@ setup_pci(struct hfc_multi *hc, struct pci_dev *pdev, case HFC_IO_MODE_PLXSD: test_and_set_bit(HFC_CHIP_PLXSD, &hc->chip); hc->slots = 128; /* required */ - /* fall through */ - case HFC_IO_MODE_PCIMEM: hc->HFC_outb = HFC_outb_pcimem; hc->HFC_inb = HFC_inb_pcimem; hc->HFC_inw = HFC_inw_pcimem; hc->HFC_wait = HFC_wait_pcimem; hc->read_fifo = read_fifo_pcimem; hc->write_fifo = write_fifo_pcimem; - break; - case HFC_IO_MODE_REGIO: - hc->HFC_outb = HFC_outb_regio; - hc->HFC_inb = HFC_inb_regio; - hc->HFC_inw = HFC_inw_regio; - hc->HFC_wait = HFC_wait_regio; - hc->read_fifo = read_fifo_regio; - hc->write_fifo = write_fifo_regio; - break; - default: - printk(KERN_WARNING "HFC-multi: Invalid IO mode.\n"); - pci_disable_device(hc->pci_dev); - return -EIO; - } - hc->HFC_outb_nodebug = hc->HFC_outb; - hc->HFC_inb_nodebug = hc->HFC_inb; - hc->HFC_inw_nodebug = hc->HFC_inw; - hc->HFC_wait_nodebug = hc->HFC_wait; -#ifdef HFC_REGISTER_DEBUG - hc->HFC_outb = HFC_outb_debug; - hc->HFC_inb = HFC_inb_debug; - hc->HFC_inw = HFC_inw_debug; - hc->HFC_wait = HFC_wait_debug; -#endif - hc->pci_iobase = 0; - hc->pci_membase = NULL; - hc->plx_membase = NULL; - - switch (hc->io_mode) { - case HFC_IO_MODE_PLXSD: hc->plx_origmembase = hc->pci_dev->resource[0].start; /* MEMBASE 1 is PLX PCI Bridge */ @@ -4327,6 +4434,12 @@ setup_pci(struct hfc_multi *hc, struct pci_dev *pdev, pci_write_config_word(hc->pci_dev, PCI_COMMAND, PCI_ENA_MEMIO); break; case HFC_IO_MODE_PCIMEM: + hc->HFC_outb = HFC_outb_pcimem; + hc->HFC_inb = HFC_inb_pcimem; + hc->HFC_inw = HFC_inw_pcimem; + hc->HFC_wait = HFC_wait_pcimem; + hc->read_fifo = read_fifo_pcimem; + hc->write_fifo = write_fifo_pcimem; hc->pci_origmembase = hc->pci_dev->resource[1].start; if (!hc->pci_origmembase) { printk(KERN_WARNING @@ -4343,12 +4456,18 @@ setup_pci(struct hfc_multi *hc, struct pci_dev *pdev, pci_disable_device(hc->pci_dev); return -EIO; } - printk(KERN_INFO "card %d: defined at MEMBASE %#lx (%#lx) IRQ %d " - "HZ %d leds-type %d\n", hc->id, (u_long)hc->pci_membase, + printk(KERN_INFO "card %d: defined at MEMBASE %#lx (%#lx) IRQ " + "%d HZ %d leds-type %d\n", hc->id, (u_long)hc->pci_membase, hc->pci_origmembase, hc->pci_dev->irq, HZ, hc->leds); pci_write_config_word(hc->pci_dev, PCI_COMMAND, PCI_ENA_MEMIO); break; case HFC_IO_MODE_REGIO: + hc->HFC_outb = HFC_outb_regio; + hc->HFC_inb = HFC_inb_regio; + hc->HFC_inw = HFC_inw_regio; + hc->HFC_wait = HFC_wait_regio; + hc->read_fifo = read_fifo_regio; + hc->write_fifo = write_fifo_regio; hc->pci_iobase = (u_int) hc->pci_dev->resource[0].start; if (!hc->pci_iobase) { printk(KERN_WARNING @@ -4430,7 +4549,7 @@ release_port(struct hfc_multi *hc, struct dchannel *dch) dch->timer.function = NULL; } - if (hc->type == 1) { /* E1 */ + if (hc->ctype == HFC_TYPE_E1) { /* E1 */ /* remove sync */ if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { hc->syncronized = 0; @@ -4508,7 +4627,7 @@ release_card(struct hfc_multi *hc) int ch; if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_WARNING "%s: release card (%d) entered\n", + printk(KERN_DEBUG "%s: release card (%d) entered\n", __func__, hc->id); /* unregister clock source */ @@ -4537,7 +4656,7 @@ release_card(struct hfc_multi *hc) /* release hardware & irq */ if (hc->irq) { if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_WARNING "%s: free irq %d\n", + printk(KERN_DEBUG "%s: free irq %d\n", __func__, hc->irq); free_irq(hc->irq, hc); hc->irq = 0; @@ -4546,17 +4665,17 @@ release_card(struct hfc_multi *hc) release_io_hfcmulti(hc); if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_WARNING "%s: remove instance from list\n", + printk(KERN_DEBUG "%s: remove instance from list\n", __func__); list_del(&hc->list); if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_WARNING "%s: delete instance\n", __func__); + printk(KERN_DEBUG "%s: delete instance\n", __func__); if (hc == syncmaster) syncmaster = NULL; kfree(hc); if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_WARNING "%s: card successfully removed\n", + printk(KERN_DEBUG "%s: card successfully removed\n", __func__); } @@ -4579,7 +4698,7 @@ init_e1_port(struct hfc_multi *hc, struct hm_map *m) (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)); dch->dev.D.send = handle_dmsg; dch->dev.D.ctrl = hfcm_dctrl; - dch->dev.nrbchan = (hc->dslot)?30:31; + dch->dev.nrbchan = (hc->dslot) ? 30 : 31; dch->slot = hc->dslot; hc->chan[hc->dslot].dch = dch; hc->chan[hc->dslot].port = 0; @@ -4821,7 +4940,7 @@ init_multi_port(struct hfc_multi *hc, int pt) } /* disable E-channel */ if (port[Port_cnt] & 0x004) { - if (debug & DEBUG_HFCMULTI_INIT) + if (debug & DEBUG_HFCMULTI_INIT) printk(KERN_DEBUG "%s: PROTOCOL disable E-channel: " "card(%d) port(%d)\n", @@ -4829,9 +4948,15 @@ init_multi_port(struct hfc_multi *hc, int pt) test_and_set_bit(HFC_CFG_DIS_ECHANNEL, &hc->chan[i + 2].cfg); } - snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-%ds.%d-%d", - hc->type, HFC_cnt + 1, pt + 1); - ret = mISDN_register_device(&dch->dev, &hc->pci_dev->dev, name); + if (hc->ctype == HFC_TYPE_XHFC) { + snprintf(name, MISDN_MAX_IDLEN - 1, "xhfc.%d-%d", + HFC_cnt + 1, pt + 1); + ret = mISDN_register_device(&dch->dev, NULL, name); + } else { + snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-%ds.%d-%d", + hc->ctype, HFC_cnt + 1, pt + 1); + ret = mISDN_register_device(&dch->dev, &hc->pci_dev->dev, name); + } if (ret) goto free_chan; hc->created[pt] = 1; @@ -4842,9 +4967,9 @@ free_chan: } static int -hfcmulti_init(struct pci_dev *pdev, const struct pci_device_id *ent) +hfcmulti_init(struct hm_map *m, struct pci_dev *pdev, + const struct pci_device_id *ent) { - struct hm_map *m = (struct hm_map *)ent->driver_data; int ret_err = 0; int pt; struct hfc_multi *hc; @@ -4879,16 +5004,18 @@ hfcmulti_init(struct pci_dev *pdev, const struct pci_device_id *ent) } spin_lock_init(&hc->lock); hc->mtyp = m; - hc->type = m->type; + hc->ctype = m->type; hc->ports = m->ports; hc->id = HFC_cnt; hc->pcm = pcm[HFC_cnt]; hc->io_mode = iomode[HFC_cnt]; - if (dslot[HFC_cnt] < 0 && hc->type == 1) { + if (dslot[HFC_cnt] < 0 && hc->ctype == HFC_TYPE_E1) { hc->dslot = 0; printk(KERN_INFO "HFC-E1 card has disabled D-channel, but " "31 B-channels\n"); - } if (dslot[HFC_cnt] > 0 && dslot[HFC_cnt] < 32 && hc->type == 1) { + } + if (dslot[HFC_cnt] > 0 && dslot[HFC_cnt] < 32 + && hc->ctype == HFC_TYPE_E1) { hc->dslot = dslot[HFC_cnt]; printk(KERN_INFO "HFC-E1 card has alternating D-channel on " "time slot %d\n", dslot[HFC_cnt]); @@ -4910,8 +5037,11 @@ hfcmulti_init(struct pci_dev *pdev, const struct pci_device_id *ent) for (i = 0; i < (poll >> 1); i++) hc->silence_data[i] = hc->silence; - if (!(type[HFC_cnt] & 0x200)) - test_and_set_bit(HFC_CHIP_DTMF, &hc->chip); + if (hc->ctype != HFC_TYPE_XHFC) { + if (!(type[HFC_cnt] & 0x200)) + test_and_set_bit(HFC_CHIP_DTMF, &hc->chip); + test_and_set_bit(HFC_CHIP_CONF, &hc->chip); + } if (type[HFC_cnt] & 0x800) test_and_set_bit(HFC_CHIP_PCM_SLAVE, &hc->chip); @@ -4935,8 +5065,18 @@ hfcmulti_init(struct pci_dev *pdev, const struct pci_device_id *ent) printk(KERN_NOTICE "Watchdog enabled\n"); } - /* setup pci, hc->slots may change due to PLXSD */ - ret_err = setup_pci(hc, pdev, ent); + if (pdev && ent) + /* setup pci, hc->slots may change due to PLXSD */ + ret_err = setup_pci(hc, pdev, ent); + else +#ifdef CONFIG_MISDN_HFCMULTI_8xx + ret_err = setup_embedded(hc, m); +#else + { + printk(KERN_WARNING "Embedded IO Mode not selected\n"); + ret_err = -EIO; + } +#endif if (ret_err) { if (hc == syncmaster) syncmaster = NULL; @@ -4944,7 +5084,17 @@ hfcmulti_init(struct pci_dev *pdev, const struct pci_device_id *ent) return ret_err; } - /* crate channels */ + hc->HFC_outb_nodebug = hc->HFC_outb; + hc->HFC_inb_nodebug = hc->HFC_inb; + hc->HFC_inw_nodebug = hc->HFC_inw; + hc->HFC_wait_nodebug = hc->HFC_wait; +#ifdef HFC_REGISTER_DEBUG + hc->HFC_outb = HFC_outb_debug; + hc->HFC_inb = HFC_inb_debug; + hc->HFC_inw = HFC_inw_debug; + hc->HFC_wait = HFC_wait_debug; +#endif + /* create channels */ for (pt = 0; pt < hc->ports; pt++) { if (Port_cnt >= MAX_PORTS) { printk(KERN_ERR "too many ports (max=%d).\n", @@ -4952,7 +5102,7 @@ hfcmulti_init(struct pci_dev *pdev, const struct pci_device_id *ent) ret_err = -EINVAL; goto free_card; } - if (hc->type == 1) + if (hc->ctype == HFC_TYPE_E1) ret_err = init_e1_port(hc, m); else ret_err = init_multi_port(hc, pt); @@ -5036,6 +5186,7 @@ hfcmulti_init(struct pci_dev *pdev, const struct pci_device_id *ent) hc->iclock = mISDN_register_clock("HFCMulti", 0, clockctl, hc); /* initialize hardware */ + hc->irq = (m->irq) ? : hc->pci_dev->irq; ret_err = init_card(hc); if (ret_err) { printk(KERN_ERR "init card returns %d\n", ret_err); @@ -5074,7 +5225,7 @@ static void __devexit hfc_remove_pci(struct pci_dev *pdev) spin_unlock_irqrestore(&HFClock, flags); } else { if (debug) - printk(KERN_WARNING "%s: drvdata allready removed\n", + printk(KERN_DEBUG "%s: drvdata allready removed\n", __func__); } } @@ -5086,45 +5237,48 @@ static void __devexit hfc_remove_pci(struct pci_dev *pdev) #define VENDOR_PRIM "PrimuX" static const struct hm_map hfcm_map[] = { -/*0*/ {VENDOR_BN, "HFC-1S Card (mini PCI)", 4, 1, 1, 3, 0, DIP_4S, 0}, -/*1*/ {VENDOR_BN, "HFC-2S Card", 4, 2, 1, 3, 0, DIP_4S, 0}, -/*2*/ {VENDOR_BN, "HFC-2S Card (mini PCI)", 4, 2, 1, 3, 0, DIP_4S, 0}, -/*3*/ {VENDOR_BN, "HFC-4S Card", 4, 4, 1, 2, 0, DIP_4S, 0}, -/*4*/ {VENDOR_BN, "HFC-4S Card (mini PCI)", 4, 4, 1, 2, 0, 0, 0}, -/*5*/ {VENDOR_CCD, "HFC-4S Eval (old)", 4, 4, 0, 0, 0, 0, 0}, -/*6*/ {VENDOR_CCD, "HFC-4S IOB4ST", 4, 4, 1, 2, 0, DIP_4S, 0}, -/*7*/ {VENDOR_CCD, "HFC-4S", 4, 4, 1, 2, 0, 0, 0}, -/*8*/ {VENDOR_DIG, "HFC-4S Card", 4, 4, 0, 2, 0, 0, HFC_IO_MODE_REGIO}, -/*9*/ {VENDOR_CCD, "HFC-4S Swyx 4xS0 SX2 QuadBri", 4, 4, 1, 2, 0, 0, 0}, -/*10*/ {VENDOR_JH, "HFC-4S (junghanns 2.0)", 4, 4, 1, 2, 0, 0, 0}, -/*11*/ {VENDOR_PRIM, "HFC-2S Primux Card", 4, 2, 0, 0, 0, 0, 0}, +/*0*/ {VENDOR_BN, "HFC-1S Card (mini PCI)", 4, 1, 1, 3, 0, DIP_4S, 0, 0}, +/*1*/ {VENDOR_BN, "HFC-2S Card", 4, 2, 1, 3, 0, DIP_4S, 0, 0}, +/*2*/ {VENDOR_BN, "HFC-2S Card (mini PCI)", 4, 2, 1, 3, 0, DIP_4S, 0, 0}, +/*3*/ {VENDOR_BN, "HFC-4S Card", 4, 4, 1, 2, 0, DIP_4S, 0, 0}, +/*4*/ {VENDOR_BN, "HFC-4S Card (mini PCI)", 4, 4, 1, 2, 0, 0, 0, 0}, +/*5*/ {VENDOR_CCD, "HFC-4S Eval (old)", 4, 4, 0, 0, 0, 0, 0, 0}, +/*6*/ {VENDOR_CCD, "HFC-4S IOB4ST", 4, 4, 1, 2, 0, DIP_4S, 0, 0}, +/*7*/ {VENDOR_CCD, "HFC-4S", 4, 4, 1, 2, 0, 0, 0, 0}, +/*8*/ {VENDOR_DIG, "HFC-4S Card", 4, 4, 0, 2, 0, 0, HFC_IO_MODE_REGIO, 0}, +/*9*/ {VENDOR_CCD, "HFC-4S Swyx 4xS0 SX2 QuadBri", 4, 4, 1, 2, 0, 0, 0, 0}, +/*10*/ {VENDOR_JH, "HFC-4S (junghanns 2.0)", 4, 4, 1, 2, 0, 0, 0, 0}, +/*11*/ {VENDOR_PRIM, "HFC-2S Primux Card", 4, 2, 0, 0, 0, 0, 0, 0}, -/*12*/ {VENDOR_BN, "HFC-8S Card", 8, 8, 1, 0, 0, 0, 0}, +/*12*/ {VENDOR_BN, "HFC-8S Card", 8, 8, 1, 0, 0, 0, 0, 0}, /*13*/ {VENDOR_BN, "HFC-8S Card (+)", 8, 8, 1, 8, 0, DIP_8S, - HFC_IO_MODE_REGIO}, -/*14*/ {VENDOR_CCD, "HFC-8S Eval (old)", 8, 8, 0, 0, 0, 0, 0}, -/*15*/ {VENDOR_CCD, "HFC-8S IOB4ST Recording", 8, 8, 1, 0, 0, 0, 0}, + HFC_IO_MODE_REGIO, 0}, +/*14*/ {VENDOR_CCD, "HFC-8S Eval (old)", 8, 8, 0, 0, 0, 0, 0, 0}, +/*15*/ {VENDOR_CCD, "HFC-8S IOB4ST Recording", 8, 8, 1, 0, 0, 0, 0, 0}, -/*16*/ {VENDOR_CCD, "HFC-8S IOB8ST", 8, 8, 1, 0, 0, 0, 0}, -/*17*/ {VENDOR_CCD, "HFC-8S", 8, 8, 1, 0, 0, 0, 0}, -/*18*/ {VENDOR_CCD, "HFC-8S", 8, 8, 1, 0, 0, 0, 0}, +/*16*/ {VENDOR_CCD, "HFC-8S IOB8ST", 8, 8, 1, 0, 0, 0, 0, 0}, +/*17*/ {VENDOR_CCD, "HFC-8S", 8, 8, 1, 0, 0, 0, 0, 0}, +/*18*/ {VENDOR_CCD, "HFC-8S", 8, 8, 1, 0, 0, 0, 0, 0}, -/*19*/ {VENDOR_BN, "HFC-E1 Card", 1, 1, 0, 1, 0, DIP_E1, 0}, -/*20*/ {VENDOR_BN, "HFC-E1 Card (mini PCI)", 1, 1, 0, 1, 0, 0, 0}, -/*21*/ {VENDOR_BN, "HFC-E1+ Card (Dual)", 1, 1, 0, 1, 0, DIP_E1, 0}, -/*22*/ {VENDOR_BN, "HFC-E1 Card (Dual)", 1, 1, 0, 1, 0, DIP_E1, 0}, +/*19*/ {VENDOR_BN, "HFC-E1 Card", 1, 1, 0, 1, 0, DIP_E1, 0, 0}, +/*20*/ {VENDOR_BN, "HFC-E1 Card (mini PCI)", 1, 1, 0, 1, 0, 0, 0, 0}, +/*21*/ {VENDOR_BN, "HFC-E1+ Card (Dual)", 1, 1, 0, 1, 0, DIP_E1, 0, 0}, +/*22*/ {VENDOR_BN, "HFC-E1 Card (Dual)", 1, 1, 0, 1, 0, DIP_E1, 0, 0}, -/*23*/ {VENDOR_CCD, "HFC-E1 Eval (old)", 1, 1, 0, 0, 0, 0, 0}, -/*24*/ {VENDOR_CCD, "HFC-E1 IOB1E1", 1, 1, 0, 1, 0, 0, 0}, -/*25*/ {VENDOR_CCD, "HFC-E1", 1, 1, 0, 1, 0, 0, 0}, +/*23*/ {VENDOR_CCD, "HFC-E1 Eval (old)", 1, 1, 0, 0, 0, 0, 0, 0}, +/*24*/ {VENDOR_CCD, "HFC-E1 IOB1E1", 1, 1, 0, 1, 0, 0, 0, 0}, +/*25*/ {VENDOR_CCD, "HFC-E1", 1, 1, 0, 1, 0, 0, 0, 0}, /*26*/ {VENDOR_CCD, "HFC-4S Speech Design", 4, 4, 0, 0, 0, 0, - HFC_IO_MODE_PLXSD}, + HFC_IO_MODE_PLXSD, 0}, /*27*/ {VENDOR_CCD, "HFC-E1 Speech Design", 1, 1, 0, 0, 0, 0, - HFC_IO_MODE_PLXSD}, -/*28*/ {VENDOR_CCD, "HFC-4S OpenVox", 4, 4, 1, 0, 0, 0, 0}, -/*29*/ {VENDOR_CCD, "HFC-2S OpenVox", 4, 2, 1, 0, 0, 0, 0}, -/*30*/ {VENDOR_CCD, "HFC-8S OpenVox", 8, 8, 1, 0, 0, 0, 0}, + HFC_IO_MODE_PLXSD, 0}, +/*28*/ {VENDOR_CCD, "HFC-4S OpenVox", 4, 4, 1, 0, 0, 0, 0, 0}, +/*29*/ {VENDOR_CCD, "HFC-2S OpenVox", 4, 2, 1, 0, 0, 0, 0, 0}, +/*30*/ {VENDOR_CCD, "HFC-8S OpenVox", 8, 8, 1, 0, 0, 0, 0, 0}, +/*31*/ {VENDOR_CCD, "XHFC-4S Speech Design", 5, 4, 0, 0, 0, 0, + HFC_IO_MODE_EMBSD, XHFC_IRQ}, +/*32*/ {VENDOR_JH, "HFC-8S (junghanns)", 8, 8, 1, 0, 0, 0, 0, 0}, }; #undef H @@ -5178,6 +5332,8 @@ static struct pci_device_id hfmultipci_ids[] __devinitdata = { PCI_SUBDEVICE_ID_CCD_HFC8S, 0, 0, H(18)}, /* 8S */ { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, PCI_SUBDEVICE_ID_CCD_OV8S, 0, 0, H(30)}, /* OpenVox 8 */ + { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, + PCI_SUBDEVICE_ID_CCD_JH8S, 0, 0, H(32)}, /* Junganns 8S */ /* Cards with HFC-E1 Chip */ @@ -5201,6 +5357,10 @@ static struct pci_device_id hfmultipci_ids[] __devinitdata = { PCI_SUBDEVICE_ID_CCD_SPD4S, 0, 0, H(26)}, /* PLX PCI Bridge */ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_CCD, PCI_SUBDEVICE_ID_CCD_SPDE1, 0, 0, H(27)}, /* PLX PCI Bridge */ + + { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD, + PCI_SUBDEVICE_ID_CCD_JHSE1, 0, 0, H(25)}, /* Junghanns E1 */ + { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_ANY_ID, PCI_ANY_ID, @@ -5231,7 +5391,7 @@ hfcmulti_probe(struct pci_dev *pdev, const struct pci_device_id *ent) "Please contact the driver maintainer for support.\n"); return -ENODEV; } - ret = hfcmulti_init(pdev, ent); + ret = hfcmulti_init(m, pdev, ent); if (ret) return ret; HFC_cnt++; @@ -5261,6 +5421,8 @@ static int __init HFCmulti_init(void) { int err; + int i, xhfc = 0; + struct hm_map m; printk(KERN_INFO "mISDN: HFC-multi driver %s\n", HFC_MULTI_VERSION); @@ -5308,11 +5470,43 @@ HFCmulti_init(void) if (!clock) clock = 1; + /* Register the embedded devices. + * This should be done before the PCI cards registration */ + switch (hwid) { + case HWID_MINIP4: + xhfc = 1; + m = hfcm_map[31]; + break; + case HWID_MINIP8: + xhfc = 2; + m = hfcm_map[31]; + break; + case HWID_MINIP16: + xhfc = 4; + m = hfcm_map[31]; + break; + default: + xhfc = 0; + } + + for (i = 0; i < xhfc; ++i) { + err = hfcmulti_init(&m, NULL, NULL); + if (err) { + printk(KERN_ERR "error registering embedded driver: " + "%x\n", err); + return -err; + } + HFC_cnt++; + printk(KERN_INFO "%d devices registered\n", HFC_cnt); + } + + /* Register the PCI cards */ err = pci_register_driver(&hfcmultipci_driver); if (err < 0) { printk(KERN_ERR "error registering pci driver: %x\n", err); return err; } + return 0; } diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c index 641a9cd1a532..228ffbed1286 100644 --- a/drivers/isdn/hardware/mISDN/hfcpci.c +++ b/drivers/isdn/hardware/mISDN/hfcpci.c @@ -257,7 +257,7 @@ reset_hfcpci(struct hfc_pci *hc) Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); /* Clear already pending ints */ - if (Read_hfc(hc, HFCPCI_INT_S1)); + val = Read_hfc(hc, HFCPCI_INT_S1); /* set NT/TE mode */ hfcpci_setmode(hc); @@ -452,7 +452,7 @@ hfcpci_empty_bfifo(struct bchannel *bch, struct bzfifo *bz, } bz->za[new_f2].z2 = cpu_to_le16(new_z2); bz->f2 = new_f2; /* next buffer */ - recv_Bchannel(bch); + recv_Bchannel(bch, MISDN_ID_ANY); } } @@ -499,7 +499,8 @@ receive_dmsg(struct hfc_pci *hc) df->f2 = ((df->f2 + 1) & MAX_D_FRAMES) | (MAX_D_FRAMES + 1); /* next buffer */ df->za[df->f2 & D_FREG_MASK].z2 = - cpu_to_le16((le16_to_cpu(zp->z2) + rcnt) & (D_FIFO_SIZE - 1)); + cpu_to_le16((le16_to_cpu(zp->z2) + rcnt) & + (D_FIFO_SIZE - 1)); } else { dch->rx_skb = mI_alloc_skb(rcnt - 3, GFP_ATOMIC); if (!dch->rx_skb) { @@ -541,35 +542,45 @@ receive_dmsg(struct hfc_pci *hc) * check for transparent receive data and read max one 'poll' size if avail */ static void -hfcpci_empty_fifo_trans(struct bchannel *bch, struct bzfifo *bz, u_char *bdata) +hfcpci_empty_fifo_trans(struct bchannel *bch, struct bzfifo *rxbz, + struct bzfifo *txbz, u_char *bdata) { - __le16 *z1r, *z2r; - int new_z2, fcnt, maxlen; - u_char *ptr, *ptr1; + __le16 *z1r, *z2r, *z1t, *z2t; + int new_z2, fcnt_rx, fcnt_tx, maxlen; + u_char *ptr, *ptr1; - z1r = &bz->za[MAX_B_FRAMES].z1; /* pointer to z reg */ + z1r = &rxbz->za[MAX_B_FRAMES].z1; /* pointer to z reg */ z2r = z1r + 1; + z1t = &txbz->za[MAX_B_FRAMES].z1; + z2t = z1t + 1; - fcnt = le16_to_cpu(*z1r) - le16_to_cpu(*z2r); - if (!fcnt) + fcnt_rx = le16_to_cpu(*z1r) - le16_to_cpu(*z2r); + if (!fcnt_rx) return; /* no data avail */ - if (fcnt <= 0) - fcnt += B_FIFO_SIZE; /* bytes actually buffered */ - new_z2 = le16_to_cpu(*z2r) + fcnt; /* new position in fifo */ + if (fcnt_rx <= 0) + fcnt_rx += B_FIFO_SIZE; /* bytes actually buffered */ + new_z2 = le16_to_cpu(*z2r) + fcnt_rx; /* new position in fifo */ if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL)) new_z2 -= B_FIFO_SIZE; /* buffer wrap */ - if (fcnt > MAX_DATA_SIZE) { /* flush, if oversized */ + if (fcnt_rx > MAX_DATA_SIZE) { /* flush, if oversized */ *z2r = cpu_to_le16(new_z2); /* new position */ return; } - bch->rx_skb = mI_alloc_skb(fcnt, GFP_ATOMIC); + fcnt_tx = le16_to_cpu(*z2t) - le16_to_cpu(*z1t); + if (fcnt_tx <= 0) + fcnt_tx += B_FIFO_SIZE; + /* fcnt_tx contains available bytes in tx-fifo */ + fcnt_tx = B_FIFO_SIZE - fcnt_tx; + /* remaining bytes to send (bytes in tx-fifo) */ + + bch->rx_skb = mI_alloc_skb(fcnt_rx, GFP_ATOMIC); if (bch->rx_skb) { - ptr = skb_put(bch->rx_skb, fcnt); - if (le16_to_cpu(*z2r) + fcnt <= B_FIFO_SIZE + B_SUB_VAL) - maxlen = fcnt; /* complete transfer */ + ptr = skb_put(bch->rx_skb, fcnt_rx); + if (le16_to_cpu(*z2r) + fcnt_rx <= B_FIFO_SIZE + B_SUB_VAL) + maxlen = fcnt_rx; /* complete transfer */ else maxlen = B_FIFO_SIZE + B_SUB_VAL - le16_to_cpu(*z2r); /* maximum */ @@ -577,14 +588,14 @@ hfcpci_empty_fifo_trans(struct bchannel *bch, struct bzfifo *bz, u_char *bdata) ptr1 = bdata + (le16_to_cpu(*z2r) - B_SUB_VAL); /* start of data */ memcpy(ptr, ptr1, maxlen); /* copy data */ - fcnt -= maxlen; + fcnt_rx -= maxlen; - if (fcnt) { /* rest remaining */ + if (fcnt_rx) { /* rest remaining */ ptr += maxlen; ptr1 = bdata; /* start of buffer */ - memcpy(ptr, ptr1, fcnt); /* rest */ + memcpy(ptr, ptr1, fcnt_rx); /* rest */ } - recv_Bchannel(bch); + recv_Bchannel(bch, fcnt_tx); /* bch, id */ } else printk(KERN_WARNING "HFCPCI: receive out of memory\n"); @@ -600,26 +611,28 @@ main_rec_hfcpci(struct bchannel *bch) struct hfc_pci *hc = bch->hw; int rcnt, real_fifo; int receive = 0, count = 5; - struct bzfifo *bz; + struct bzfifo *txbz, *rxbz; u_char *bdata; struct zt *zp; if ((bch->nr & 2) && (!hc->hw.bswapped)) { - bz = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b2; + rxbz = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b2; + txbz = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b2; bdata = ((union fifo_area *)(hc->hw.fifos))->b_chans.rxdat_b2; real_fifo = 1; } else { - bz = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b1; + rxbz = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b1; + txbz = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b1; bdata = ((union fifo_area *)(hc->hw.fifos))->b_chans.rxdat_b1; real_fifo = 0; } Begin: count--; - if (bz->f1 != bz->f2) { + if (rxbz->f1 != rxbz->f2) { if (bch->debug & DEBUG_HW_BCHANNEL) printk(KERN_DEBUG "hfcpci rec ch(%x) f1(%d) f2(%d)\n", - bch->nr, bz->f1, bz->f2); - zp = &bz->za[bz->f2]; + bch->nr, rxbz->f1, rxbz->f2); + zp = &rxbz->za[rxbz->f2]; rcnt = le16_to_cpu(zp->z1) - le16_to_cpu(zp->z2); if (rcnt < 0) @@ -630,8 +643,8 @@ Begin: "hfcpci rec ch(%x) z1(%x) z2(%x) cnt(%d)\n", bch->nr, le16_to_cpu(zp->z1), le16_to_cpu(zp->z2), rcnt); - hfcpci_empty_bfifo(bch, bz, bdata, rcnt); - rcnt = bz->f1 - bz->f2; + hfcpci_empty_bfifo(bch, rxbz, bdata, rcnt); + rcnt = rxbz->f1 - rxbz->f2; if (rcnt < 0) rcnt += MAX_B_FRAMES + 1; if (hc->hw.last_bfifo_cnt[real_fifo] > rcnt + 1) { @@ -644,7 +657,7 @@ Begin: else receive = 0; } else if (test_bit(FLG_TRANSPARENT, &bch->Flags)) { - hfcpci_empty_fifo_trans(bch, bz, bdata); + hfcpci_empty_fifo_trans(bch, rxbz, txbz, bdata); return; } else receive = 0; @@ -954,6 +967,7 @@ static void ph_state_nt(struct dchannel *dch) { struct hfc_pci *hc = dch->hw; + u_char val; if (dch->debug) printk(KERN_DEBUG "%s: NT newstate %x\n", @@ -967,7 +981,7 @@ ph_state_nt(struct dchannel *dch) hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER; Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); /* Clear already pending ints */ - if (Read_hfc(hc, HFCPCI_INT_S1)); + val = Read_hfc(hc, HFCPCI_INT_S1); Write_hfc(hc, HFCPCI_STATES, 4 | HFCPCI_LOAD_STATE); udelay(10); Write_hfc(hc, HFCPCI_STATES, 4); @@ -1256,8 +1270,7 @@ mode_hfcpci(struct bchannel *bch, int bc, int protocol) rx_slot = (bc>>8) & 0xff; tx_slot = (bc>>16) & 0xff; bc = bc & 0xff; - } else if (test_bit(HFC_CFG_PCM, &hc->cfg) && - (protocol > ISDN_P_NONE)) + } else if (test_bit(HFC_CFG_PCM, &hc->cfg) && (protocol > ISDN_P_NONE)) printk(KERN_WARNING "%s: no pcm channel id but HFC_CFG_PCM\n", __func__); if (hc->chanlimit > 1) { @@ -1315,8 +1328,8 @@ mode_hfcpci(struct bchannel *bch, int bc, int protocol) case (ISDN_P_B_RAW): bch->state = protocol; bch->nr = bc; - hfcpci_clear_fifo_rx(hc, (fifo2 & 2)?1:0); - hfcpci_clear_fifo_tx(hc, (fifo2 & 2)?1:0); + hfcpci_clear_fifo_rx(hc, (fifo2 & 2) ? 1 : 0); + hfcpci_clear_fifo_tx(hc, (fifo2 & 2) ? 1 : 0); if (bc & 2) { hc->hw.sctrl |= SCTRL_B2_ENA; hc->hw.sctrl_r |= SCTRL_B2_ENA; @@ -1350,8 +1363,8 @@ mode_hfcpci(struct bchannel *bch, int bc, int protocol) case (ISDN_P_B_HDLC): bch->state = protocol; bch->nr = bc; - hfcpci_clear_fifo_rx(hc, (fifo2 & 2)?1:0); - hfcpci_clear_fifo_tx(hc, (fifo2 & 2)?1:0); + hfcpci_clear_fifo_rx(hc, (fifo2 & 2) ? 1 : 0); + hfcpci_clear_fifo_tx(hc, (fifo2 & 2) ? 1 : 0); if (bc & 2) { hc->hw.sctrl |= SCTRL_B2_ENA; hc->hw.sctrl_r |= SCTRL_B2_ENA; @@ -1445,7 +1458,7 @@ set_hfcpci_rxtest(struct bchannel *bch, int protocol, int chan) switch (protocol) { case (ISDN_P_B_RAW): bch->state = protocol; - hfcpci_clear_fifo_rx(hc, (chan & 2)?1:0); + hfcpci_clear_fifo_rx(hc, (chan & 2) ? 1 : 0); if (chan & 2) { hc->hw.sctrl_r |= SCTRL_B2_ENA; hc->hw.fifo_en |= HFCPCI_FIFOEN_B2RX; @@ -1470,7 +1483,7 @@ set_hfcpci_rxtest(struct bchannel *bch, int protocol, int chan) break; case (ISDN_P_B_HDLC): bch->state = protocol; - hfcpci_clear_fifo_rx(hc, (chan & 2)?1:0); + hfcpci_clear_fifo_rx(hc, (chan & 2) ? 1 : 0); if (chan & 2) { hc->hw.sctrl_r |= SCTRL_B2_ENA; hc->hw.last_bfifo_cnt[1] = 0; @@ -1793,10 +1806,9 @@ init_card(struct hfc_pci *hc) printk(KERN_WARNING "HFC PCI: IRQ(%d) getting no interrupts " "during init %d\n", hc->irq, 4 - cnt); - if (cnt == 1) { - spin_unlock_irqrestore(&hc->lock, flags); - return -EIO; - } else { + if (cnt == 1) + break; + else { reset_hfcpci(hc); cnt--; } @@ -2035,7 +2047,8 @@ setup_hw(struct hfc_pci *hc) printk(KERN_WARNING "HFC-PCI: No IRQ for PCI card found\n"); return 1; } - hc->hw.pci_io = (char __iomem *)(unsigned long)hc->pdev->resource[1].start; + hc->hw.pci_io = + (char __iomem *)(unsigned long)hc->pdev->resource[1].start; if (!hc->hw.pci_io) { printk(KERN_WARNING "HFC-PCI: No IO-Mem for PCI card found\n"); @@ -2277,7 +2290,7 @@ hfc_remove_pci(struct pci_dev *pdev) release_card(card); else if (debug) - printk(KERN_WARNING "%s: drvdata already removed\n", + printk(KERN_DEBUG "%s: drvdata already removed\n", __func__); } diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.c b/drivers/isdn/hardware/mISDN/hfcsusb.c index 9c427fb204ee..6b7704c41b94 100644 --- a/drivers/isdn/hardware/mISDN/hfcsusb.c +++ b/drivers/isdn/hardware/mISDN/hfcsusb.c @@ -947,7 +947,7 @@ hfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len, if (fifo->dch) recv_Dchannel(fifo->dch); if (fifo->bch) - recv_Bchannel(fifo->bch); + recv_Bchannel(fifo->bch, MISDN_ID_ANY); if (fifo->ech) recv_Echannel(fifo->ech, &hw->dch); @@ -969,7 +969,7 @@ hfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len, } else { /* deliver transparent data to layer2 */ if (rx_skb->len >= poll) - recv_Bchannel(fifo->bch); + recv_Bchannel(fifo->bch, MISDN_ID_ANY); } spin_unlock(&hw->lock); } diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c index f1265667b062..3d337d924c23 100644 --- a/drivers/isdn/hisax/hfc_pci.c +++ b/drivers/isdn/hisax/hfc_pci.c @@ -82,8 +82,9 @@ release_io_hfcpci(struct IsdnCardState *cs) Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2); pci_write_config_word(cs->hw.hfcpci.dev, PCI_COMMAND, 0); /* disable memory mapped ports + busmaster */ del_timer(&cs->hw.hfcpci.timer); - kfree(cs->hw.hfcpci.share_start); - cs->hw.hfcpci.share_start = NULL; + pci_free_consistent(cs->hw.hfcpci.dev, 0x8000, + cs->hw.hfcpci.fifos, cs->hw.hfcpci.dma); + cs->hw.hfcpci.fifos = NULL; iounmap((void *)cs->hw.hfcpci.pci_io); } @@ -1663,8 +1664,19 @@ setup_hfcpci(struct IsdnCard *card) dev_hfcpci); i++; if (tmp_hfcpci) { + dma_addr_t dma_mask = DMA_BIT_MASK(32) & ~0x7fffUL; if (pci_enable_device(tmp_hfcpci)) continue; + if (pci_set_dma_mask(tmp_hfcpci, dma_mask)) { + printk(KERN_WARNING + "HiSax hfc_pci: No suitable DMA available.\n"); + continue; + } + if (pci_set_consistent_dma_mask(tmp_hfcpci, dma_mask)) { + printk(KERN_WARNING + "HiSax hfc_pci: No suitable consistent DMA available.\n"); + continue; + } pci_set_master(tmp_hfcpci); if ((card->para[0]) && (card->para[0] != (tmp_hfcpci->resource[ 0].start & PCI_BASE_ADDRESS_IO_MASK))) continue; @@ -1693,22 +1705,29 @@ setup_hfcpci(struct IsdnCard *card) printk(KERN_WARNING "HFC-PCI: No IO-Mem for PCI card found\n"); return (0); } + /* Allocate memory for FIFOS */ - /* Because the HFC-PCI needs a 32K physical alignment, we */ - /* need to allocate the double mem and align the address */ - if (!(cs->hw.hfcpci.share_start = kmalloc(65536, GFP_KERNEL))) { - printk(KERN_WARNING "HFC-PCI: Error allocating memory for FIFO!\n"); + cs->hw.hfcpci.fifos = pci_alloc_consistent(cs->hw.hfcpci.dev, + 0x8000, &cs->hw.hfcpci.dma); + if (!cs->hw.hfcpci.fifos) { + printk(KERN_WARNING "HFC-PCI: Error allocating FIFO memory!\n"); return 0; } - cs->hw.hfcpci.fifos = (void *) - (((ulong) cs->hw.hfcpci.share_start) & ~0x7FFF) + 0x8000; - pci_write_config_dword(cs->hw.hfcpci.dev, 0x80, (u_int) virt_to_bus(cs->hw.hfcpci.fifos)); + if (cs->hw.hfcpci.dma & 0x7fff) { + printk(KERN_WARNING + "HFC-PCI: Error DMA memory not on 32K boundary (%lx)\n", + (u_long)cs->hw.hfcpci.dma); + pci_free_consistent(cs->hw.hfcpci.dev, 0x8000, + cs->hw.hfcpci.fifos, cs->hw.hfcpci.dma); + return 0; + } + pci_write_config_dword(cs->hw.hfcpci.dev, 0x80, (u32)cs->hw.hfcpci.dma); cs->hw.hfcpci.pci_io = ioremap((ulong) cs->hw.hfcpci.pci_io, 256); printk(KERN_INFO - "HFC-PCI: defined at mem %p fifo %p(%#x) IRQ %d HZ %d\n", + "HFC-PCI: defined at mem %p fifo %p(%lx) IRQ %d HZ %d\n", cs->hw.hfcpci.pci_io, cs->hw.hfcpci.fifos, - (u_int) virt_to_bus(cs->hw.hfcpci.fifos), + (u_long)cs->hw.hfcpci.dma, cs->irq, HZ); spin_lock_irqsave(&cs->lock, flags); diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h index f8527046f197..0685c1946969 100644 --- a/drivers/isdn/hisax/hisax.h +++ b/drivers/isdn/hisax/hisax.h @@ -703,7 +703,7 @@ struct hfcPCI_hw { int nt_timer; struct pci_dev *dev; unsigned char *pci_io; /* start of PCI IO memory */ - void *share_start; /* shared memory for Fifos start */ + dma_addr_t dma; /* dma handle for Fifos */ void *fifos; /* FIFO memory */ int last_bfifo_cnt[2]; /* marker saving last b-fifo frame count */ struct timer_list timer; diff --git a/drivers/isdn/hysdn/hycapi.c b/drivers/isdn/hysdn/hycapi.c index 53f6ad1235db..4ffaa14b9fc4 100644 --- a/drivers/isdn/hysdn/hycapi.c +++ b/drivers/isdn/hysdn/hycapi.c @@ -67,7 +67,7 @@ hycapi_reset_ctr(struct capi_ctr *ctrl) printk(KERN_NOTICE "HYCAPI hycapi_reset_ctr\n"); #endif capilib_release(&cinfo->ncci_head); - capi_ctr_reseted(ctrl); + capi_ctr_down(ctrl); } /****************************** @@ -347,7 +347,7 @@ int hycapi_capi_stop(hysdn_card *card) if(cinfo) { ctrl = &cinfo->capi_ctrl; /* ctrl->suspend_output(ctrl); */ - capi_ctr_reseted(ctrl); + capi_ctr_down(ctrl); } return 0; } diff --git a/drivers/isdn/i4l/Kconfig b/drivers/isdn/i4l/Kconfig index 36778b270c30..ed3510f273d8 100644 --- a/drivers/isdn/i4l/Kconfig +++ b/drivers/isdn/i4l/Kconfig @@ -135,5 +135,3 @@ source "drivers/isdn/act2000/Kconfig" source "drivers/isdn/hysdn/Kconfig" endmenu - -source "drivers/isdn/gigaset/Kconfig" diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c index cb8943da4f12..de4aad076ebc 100644 --- a/drivers/isdn/i4l/isdn_net.c +++ b/drivers/isdn/i4l/isdn_net.c @@ -1069,7 +1069,7 @@ isdn_net_xmit(struct net_device *ndev, struct sk_buff *skb) lp = isdn_net_get_locked_lp(nd); if (!lp) { printk(KERN_WARNING "%s: all channels busy - requeuing!\n", ndev->name); - return 1; + return NETDEV_TX_BUSY; } /* we have our lp locked from now on */ @@ -1273,14 +1273,14 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) spin_unlock_irqrestore(&dev->lock, flags); isdn_net_dial(); /* Initiate dialing */ netif_stop_queue(ndev); - return 1; /* let upper layer requeue skb packet */ + return NETDEV_TX_BUSY; /* let upper layer requeue skb packet */ } #endif /* Initiate dialing */ spin_unlock_irqrestore(&dev->lock, flags); isdn_net_dial(); isdn_net_device_stop_queue(lp); - return 1; + return NETDEV_TX_BUSY; } else { isdn_net_unreachable(ndev, skb, "No phone number"); @@ -1300,7 +1300,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) netif_stop_queue(ndev); } } - return 1; + return NETDEV_TX_BUSY; } /* diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c index 1a2222cbb805..b4d4522e5071 100644 --- a/drivers/isdn/i4l/isdn_tty.c +++ b/drivers/isdn/i4l/isdn_tty.c @@ -1592,7 +1592,7 @@ isdn_tty_open(struct tty_struct *tty, struct file *filp) int retval, line; line = tty->index; - if (line < 0 || line > ISDN_MAX_CHANNELS) + if (line < 0 || line >= ISDN_MAX_CHANNELS) return -ENODEV; info = &dev->mdm.info[line]; if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_open")) diff --git a/drivers/isdn/mISDN/core.c b/drivers/isdn/mISDN/core.c index 9426c9827e47..21d34be5af6a 100644 --- a/drivers/isdn/mISDN/core.c +++ b/drivers/isdn/mISDN/core.c @@ -214,7 +214,7 @@ get_free_devid(void) if (!test_and_set_bit(i, (u_long *)&device_ids)) break; if (i > MAX_DEVICE_ID) - return -1; + return -EBUSY; return i; } @@ -224,10 +224,10 @@ mISDN_register_device(struct mISDNdevice *dev, { int err; - dev->id = get_free_devid(); - err = -EBUSY; - if (dev->id < 0) + err = get_free_devid(); + if (err < 0) goto error1; + dev->id = err; device_initialize(&dev->dev); if (name && name[0]) diff --git a/drivers/isdn/mISDN/dsp.h b/drivers/isdn/mISDN/dsp.h index 98a33c58f091..18af86879c05 100644 --- a/drivers/isdn/mISDN/dsp.h +++ b/drivers/isdn/mISDN/dsp.h @@ -112,9 +112,11 @@ struct dsp_conf { #define DSP_DTMF_NPOINTS 102 -#define ECHOCAN_BUFLEN (4*128) +#define ECHOCAN_BUFF_SIZE 0x400 /* must be 2**n */ +#define ECHOCAN_BUFF_MASK 0x3ff /* -1 */ struct dsp_dtmf { + int enable; /* dtmf is enabled */ int treshold; /* above this is dtmf (square of) */ int software; /* dtmf uses software decoding */ int hardware; /* dtmf uses hardware decoding */ @@ -123,7 +125,7 @@ struct dsp_dtmf { /* buffers one full dtmf frame */ u8 lastwhat, lastdigit; int count; - u8 digits[16]; /* just the dtmf result */ + u8 digits[16]; /* dtmf result */ }; @@ -150,6 +152,15 @@ struct dsp_tone { struct timer_list tl; }; +/*************** + * echo stuff * + ***************/ + +struct dsp_echo { + int software; /* echo is generated by software */ + int hardware; /* echo is generated by hardware */ +}; + /***************** * general stuff * *****************/ @@ -160,7 +171,7 @@ struct dsp { struct mISDNchannel *up; unsigned char name[64]; int b_active; - int echo; /* echo is enabled */ + struct dsp_echo echo; int rx_disabled; /* what the user wants */ int rx_is_off; /* what the card is */ int tx_mix; @@ -261,5 +272,5 @@ extern int dsp_pipeline_build(struct dsp_pipeline *pipeline, const char *cfg); extern void dsp_pipeline_process_tx(struct dsp_pipeline *pipeline, u8 *data, int len); extern void dsp_pipeline_process_rx(struct dsp_pipeline *pipeline, u8 *data, - int len); + int len, unsigned int txlen); diff --git a/drivers/isdn/mISDN/dsp_audio.c b/drivers/isdn/mISDN/dsp_audio.c index de3795e3f432..9c7c6451bf3d 100644 --- a/drivers/isdn/mISDN/dsp_audio.c +++ b/drivers/isdn/mISDN/dsp_audio.c @@ -210,9 +210,8 @@ dsp_audio_generate_seven(void) j = 0; for (k = 0; k < 256; k++) { if (dsp_audio_alaw_to_s32[k] - < dsp_audio_alaw_to_s32[i]) { - j++; - } + < dsp_audio_alaw_to_s32[i]) + j++; } sorted_alaw[j] = i; } diff --git a/drivers/isdn/mISDN/dsp_cmx.c b/drivers/isdn/mISDN/dsp_cmx.c index 58c43e429f73..9c7c0d1ba55f 100644 --- a/drivers/isdn/mISDN/dsp_cmx.c +++ b/drivers/isdn/mISDN/dsp_cmx.c @@ -163,8 +163,9 @@ dsp_cmx_debug(struct dsp *dsp) printk(KERN_DEBUG "-----Current DSP\n"); list_for_each_entry(odsp, &dsp_ilist, list) { - printk(KERN_DEBUG "* %s echo=%d txmix=%d", - odsp->name, odsp->echo, odsp->tx_mix); + printk(KERN_DEBUG "* %s hardecho=%d softecho=%d txmix=%d", + odsp->name, odsp->echo.hardware, odsp->echo.software, + odsp->tx_mix); if (odsp->conf) printk(" (Conf %d)", odsp->conf->id); if (dsp == odsp) @@ -177,10 +178,12 @@ dsp_cmx_debug(struct dsp *dsp) list_for_each_entry(member, &conf->mlist, list) { printk(KERN_DEBUG " - member = %s (slot_tx %d, bank_tx %d, " - "slot_rx %d, bank_rx %d hfc_conf %d)%s\n", + "slot_rx %d, bank_rx %d hfc_conf %d " + "tx_data %d rx_is_off %d)%s\n", member->dsp->name, member->dsp->pcm_slot_tx, member->dsp->pcm_bank_tx, member->dsp->pcm_slot_rx, member->dsp->pcm_bank_rx, member->dsp->hfc_conf, + member->dsp->tx_data, member->dsp->rx_is_off, (member->dsp == dsp) ? " *this*" : ""); } } @@ -235,7 +238,7 @@ dsp_cmx_add_conf_member(struct dsp *dsp, struct dsp_conf *conf) member = kzalloc(sizeof(struct dsp_conf_member), GFP_ATOMIC); if (!member) { - printk(KERN_ERR "kmalloc struct dsp_conf_member failed\n"); + printk(KERN_ERR "kzalloc struct dsp_conf_member failed\n"); return -ENOMEM; } member->dsp = dsp; @@ -314,7 +317,7 @@ static struct dsp_conf conf = kzalloc(sizeof(struct dsp_conf), GFP_ATOMIC); if (!conf) { - printk(KERN_ERR "kmalloc struct dsp_conf failed\n"); + printk(KERN_ERR "kzalloc struct dsp_conf failed\n"); return NULL; } INIT_LIST_HEAD(&conf->mlist); @@ -385,7 +388,7 @@ dsp_cmx_hardware(struct dsp_conf *conf, struct dsp *dsp) int freeunits[8]; u_char freeslots[256]; int same_hfc = -1, same_pcm = -1, current_conf = -1, - all_conf = 1; + all_conf = 1, tx_data = 0; /* dsp gets updated (no conf) */ if (!conf) { @@ -409,7 +412,7 @@ one_member: /* process hw echo */ if (dsp->features.pcm_banks < 1) return; - if (!dsp->echo) { + if (!dsp->echo.software && !dsp->echo.hardware) { /* NO ECHO: remove PCM slot if assigned */ if (dsp->pcm_slot_tx >= 0 || dsp->pcm_slot_rx >= 0) { if (dsp_debug & DEBUG_DSP_CMX) @@ -427,10 +430,15 @@ one_member: } return; } + /* echo is enabled, find out if we use soft or hardware */ + dsp->echo.software = dsp->tx_data; + dsp->echo.hardware = 0; /* ECHO: already echo */ if (dsp->pcm_slot_tx >= 0 && dsp->pcm_slot_rx < 0 && - dsp->pcm_bank_tx == 2 && dsp->pcm_bank_rx == 2) + dsp->pcm_bank_tx == 2 && dsp->pcm_bank_rx == 2) { + dsp->echo.hardware = 1; return; + } /* ECHO: if slot already assigned */ if (dsp->pcm_slot_tx >= 0) { dsp->pcm_slot_rx = dsp->pcm_slot_tx; @@ -443,6 +451,7 @@ one_member: dsp->pcm_slot_tx); dsp_cmx_hw_message(dsp, MISDN_CTRL_HFC_PCM_CONN, dsp->pcm_slot_tx, 2, dsp->pcm_slot_rx, 2); + dsp->echo.hardware = 1; return; } /* ECHO: find slot */ @@ -472,6 +481,7 @@ one_member: "%s no slot available for echo\n", __func__); /* no more slots available */ + dsp->echo.software = 1; return; } /* assign free slot */ @@ -485,6 +495,7 @@ one_member: __func__, dsp->name, dsp->pcm_slot_tx); dsp_cmx_hw_message(dsp, MISDN_CTRL_HFC_PCM_CONN, dsp->pcm_slot_tx, 2, dsp->pcm_slot_rx, 2); + dsp->echo.hardware = 1; return; } @@ -554,7 +565,7 @@ conf_software: return; } /* check if member has echo turned on */ - if (member->dsp->echo) { + if (member->dsp->echo.hardware || member->dsp->echo.software) { if (dsp_debug & DEBUG_DSP_CMX) printk(KERN_DEBUG "%s dsp %s cannot form a conf, because " @@ -592,10 +603,9 @@ conf_software: if (member->dsp->tx_data) { if (dsp_debug & DEBUG_DSP_CMX) printk(KERN_DEBUG - "%s dsp %s cannot form a conf, because " - "tx_data is turned on\n", + "%s dsp %s tx_data is turned on\n", __func__, member->dsp->name); - goto conf_software; + tx_data = 1; } /* check if pipeline exists */ if (member->dsp->pipeline.inuse) { @@ -794,7 +804,7 @@ conf_software: nextm->dsp->pcm_slot_tx, nextm->dsp->pcm_bank_tx, nextm->dsp->pcm_slot_rx, nextm->dsp->pcm_bank_rx); conf->hardware = 1; - conf->software = 0; + conf->software = tx_data; return; /* if members have one bank (or on the same chip) */ } else { @@ -904,7 +914,7 @@ conf_software: nextm->dsp->pcm_slot_tx, nextm->dsp->pcm_bank_tx, nextm->dsp->pcm_slot_rx, nextm->dsp->pcm_bank_rx); conf->hardware = 1; - conf->software = 0; + conf->software = tx_data; return; } } @@ -937,6 +947,10 @@ conf_software: if (current_conf >= 0) { join_members: list_for_each_entry(member, &conf->mlist, list) { + /* if no conference engine on our chip, change to + * software */ + if (!member->dsp->features.hfc_conf) + goto conf_software; /* in case of hdlc, change to software */ if (member->dsp->hdlc) goto conf_software; @@ -1295,17 +1309,25 @@ dsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members) int r, rr, t, tt, o_r, o_rr; int preload = 0; struct mISDNhead *hh, *thh; + int tx_data_only = 0; /* don't process if: */ if (!dsp->b_active) { /* if not active */ dsp->last_tx = 0; return; } - if (dsp->pcm_slot_tx >= 0 && /* connected to pcm slot */ + if (((dsp->conf && dsp->conf->hardware) || /* hardware conf */ + dsp->echo.hardware) && /* OR hardware echo */ dsp->tx_R == dsp->tx_W && /* AND no tx-data */ !(dsp->tone.tone && dsp->tone.software)) { /* AND not soft tones */ - dsp->last_tx = 0; - return; + if (!dsp->tx_data) { /* no tx_data for user space required */ + dsp->last_tx = 0; + return; + } + if (dsp->conf && dsp->conf->software && dsp->conf->hardware) + tx_data_only = 1; + if (dsp->conf->software && dsp->echo.hardware) + tx_data_only = 1; } #ifdef CMX_DEBUG @@ -1367,7 +1389,8 @@ dsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members) while (r != rr && t != tt) { #ifdef CMX_TX_DEBUG if (strlen(debugbuf) < 48) - sprintf(debugbuf+strlen(debugbuf), " %02x", p[t]); + sprintf(debugbuf+strlen(debugbuf), " %02x", + p[t]); #endif *d++ = p[t]; /* write tx_buff */ t = (t+1) & CMX_BUFF_MASK; @@ -1388,7 +1411,7 @@ dsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members) /* PROCESS DATA (one member / no conf) */ if (!conf || members <= 1) { /* -> if echo is NOT enabled */ - if (!dsp->echo) { + if (!dsp->echo.software) { /* -> send tx-data if available or use 0-volume */ while (r != rr && t != tt) { *d++ = p[t]; /* write tx_buff */ @@ -1438,7 +1461,7 @@ dsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members) o_r = (o_rr - rr + r) & CMX_BUFF_MASK; /* start rx-pointer at current read position*/ /* -> if echo is NOT enabled */ - if (!dsp->echo) { + if (!dsp->echo.software) { /* * -> copy other member's rx-data, * if tx-data is available, mix @@ -1486,7 +1509,7 @@ dsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members) #endif /* PROCESS DATA (three or more members) */ /* -> if echo is NOT enabled */ - if (!dsp->echo) { + if (!dsp->echo.software) { /* * -> substract rx-data from conf-data, * if tx-data is available, mix @@ -1550,27 +1573,40 @@ send_packet: * becuase we want what we send, not what we filtered */ if (dsp->tx_data) { - /* PREPARE RESULT */ - txskb = mI_alloc_skb(len, GFP_ATOMIC); - if (!txskb) { - printk(KERN_ERR - "FATAL ERROR in mISDN_dsp.o: " - "cannot alloc %d bytes\n", len); + if (tx_data_only) { + hh->prim = DL_DATA_REQ; + hh->id = 0; + /* queue and trigger */ + skb_queue_tail(&dsp->sendq, nskb); + schedule_work(&dsp->workq); + /* exit because only tx_data is used */ + return; } else { - thh = mISDN_HEAD_P(txskb); - thh->prim = DL_DATA_REQ; - thh->id = 0; - memcpy(skb_put(txskb, len), nskb->data+preload, len); - /* queue (trigger later) */ - skb_queue_tail(&dsp->sendq, txskb); + txskb = mI_alloc_skb(len, GFP_ATOMIC); + if (!txskb) { + printk(KERN_ERR + "FATAL ERROR in mISDN_dsp.o: " + "cannot alloc %d bytes\n", len); + } else { + thh = mISDN_HEAD_P(txskb); + thh->prim = DL_DATA_REQ; + thh->id = 0; + memcpy(skb_put(txskb, len), nskb->data+preload, + len); + /* queue (trigger later) */ + skb_queue_tail(&dsp->sendq, txskb); + } } } + + /* send data only to card, if we don't just calculated tx_data */ /* adjust volume */ if (dsp->tx_volume) dsp_change_volume(nskb, dsp->tx_volume); /* pipeline */ if (dsp->pipeline.inuse) - dsp_pipeline_process_tx(&dsp->pipeline, nskb->data, nskb->len); + dsp_pipeline_process_tx(&dsp->pipeline, nskb->data, + nskb->len); /* crypt */ if (dsp->bf_enable) dsp_bf_encrypt(dsp, nskb->data, nskb->len); @@ -1592,7 +1628,8 @@ dsp_cmx_send(void *arg) struct dsp_conf_member *member; struct dsp *dsp; int mustmix, members; - s32 mixbuffer[MAX_POLL+100], *c; + static s32 mixbuffer[MAX_POLL+100]; + s32 *c; u8 *p, *q; int r, rr; int jittercheck = 0, delay, i; @@ -1890,10 +1927,8 @@ dsp_cmx_hdlc(struct dsp *dsp, struct sk_buff *skb) /* no conf */ if (!dsp->conf) { - /* in case of hardware (echo) */ - if (dsp->pcm_slot_tx >= 0) - return; - if (dsp->echo) { + /* in case of software echo */ + if (dsp->echo.software) { nskb = skb_clone(skb, GFP_ATOMIC); if (nskb) { hh = mISDN_HEAD_P(nskb); @@ -1909,7 +1944,7 @@ dsp_cmx_hdlc(struct dsp *dsp, struct sk_buff *skb) if (dsp->conf->hardware) return; list_for_each_entry(member, &dsp->conf->mlist, list) { - if (dsp->echo || member->dsp != dsp) { + if (dsp->echo.software || member->dsp != dsp) { nskb = skb_clone(skb, GFP_ATOMIC); if (nskb) { hh = mISDN_HEAD_P(nskb); diff --git a/drivers/isdn/mISDN/dsp_core.c b/drivers/isdn/mISDN/dsp_core.c index 3083338716b2..77ee2867c8b4 100644 --- a/drivers/isdn/mISDN/dsp_core.c +++ b/drivers/isdn/mISDN/dsp_core.c @@ -203,13 +203,13 @@ dsp_rx_off_member(struct dsp *dsp) else if (dsp->dtmf.software) rx_off = 0; /* echo in software */ - else if (dsp->echo && dsp->pcm_slot_tx < 0) + else if (dsp->echo.software) rx_off = 0; /* bridge in software */ - else if (dsp->conf) { - if (dsp->conf->software) - rx_off = 0; - } + else if (dsp->conf && dsp->conf->software) + rx_off = 0; + /* data is not required by user space and not required + * for echo dtmf detection, soft-echo, soft-bridging */ if (rx_off == dsp->rx_is_off) return; @@ -280,7 +280,7 @@ dsp_fill_empty(struct dsp *dsp) static int dsp_control_req(struct dsp *dsp, struct mISDNhead *hh, struct sk_buff *skb) { - struct sk_buff *nskb; + struct sk_buff *nskb; int ret = 0; int cont; u8 *data; @@ -306,15 +306,18 @@ dsp_control_req(struct dsp *dsp, struct mISDNhead *hh, struct sk_buff *skb) "to %d\n", *((int *)data)); dsp->dtmf.treshold = (*(int *)data) * 10000; } + dsp->dtmf.enable = 1; /* init goertzel */ dsp_dtmf_goertzel_init(dsp); /* check dtmf hardware */ dsp_dtmf_hardware(dsp); + dsp_rx_off(dsp); break; case DTMF_TONE_STOP: /* turn off DTMF */ if (dsp_debug & DEBUG_DSP_CORE) printk(KERN_DEBUG "%s: stop dtmf\n", __func__); + dsp->dtmf.enable = 0; dsp->dtmf.hardware = 0; dsp->dtmf.software = 0; break; @@ -414,7 +417,7 @@ tone_off: dsp_rx_off(dsp); break; case DSP_ECHO_ON: /* enable echo */ - dsp->echo = 1; /* soft echo */ + dsp->echo.software = 1; /* soft echo */ if (dsp_debug & DEBUG_DSP_CORE) printk(KERN_DEBUG "%s: enable cmx-echo\n", __func__); dsp_cmx_hardware(dsp->conf, dsp); @@ -423,7 +426,8 @@ tone_off: dsp_cmx_debug(dsp); break; case DSP_ECHO_OFF: /* disable echo */ - dsp->echo = 0; + dsp->echo.software = 0; + dsp->echo.hardware = 0; if (dsp_debug & DEBUG_DSP_CORE) printk(KERN_DEBUG "%s: disable cmx-echo\n", __func__); dsp_cmx_hardware(dsp->conf, dsp); @@ -502,7 +506,7 @@ tone_off: break; } dsp->cmx_delay = (*((int *)data)) << 3; - /* miliseconds to samples */ + /* milliseconds to samples */ if (dsp->cmx_delay >= (CMX_BUFF_HALF>>1)) /* clip to half of maximum usable buffer (half of half buffer) */ @@ -556,7 +560,7 @@ tone_off: dsp->pipeline.inuse = 1; dsp_cmx_hardware(dsp->conf, dsp); ret = dsp_pipeline_build(&dsp->pipeline, - len > 0 ? (char *)data : NULL); + len > 0 ? data : NULL); dsp_cmx_hardware(dsp->conf, dsp); dsp_rx_off(dsp); } @@ -657,11 +661,10 @@ get_features(struct mISDNchannel *ch) static int dsp_function(struct mISDNchannel *ch, struct sk_buff *skb) { - struct dsp *dsp = container_of(ch, struct dsp, ch); + struct dsp *dsp = container_of(ch, struct dsp, ch); struct mISDNhead *hh; int ret = 0; - u8 *digits; - int cont; + u8 *digits = NULL; u_long flags; hh = mISDN_HEAD_P(skb); @@ -704,50 +707,55 @@ dsp_function(struct mISDNchannel *ch, struct sk_buff *skb) break; } + spin_lock_irqsave(&dsp_lock, flags); + /* decrypt if enabled */ if (dsp->bf_enable) dsp_bf_decrypt(dsp, skb->data, skb->len); /* pipeline */ if (dsp->pipeline.inuse) dsp_pipeline_process_rx(&dsp->pipeline, skb->data, - skb->len); + skb->len, hh->id); /* change volume if requested */ if (dsp->rx_volume) dsp_change_volume(skb, dsp->rx_volume); - /* check if dtmf soft decoding is turned on */ if (dsp->dtmf.software) { digits = dsp_dtmf_goertzel_decode(dsp, skb->data, - skb->len, (dsp_options&DSP_OPT_ULAW)?1:0); + skb->len, (dsp_options&DSP_OPT_ULAW) ? 1 : 0); + } + /* we need to process receive data if software */ + if (dsp->conf && dsp->conf->software) { + /* process data from card at cmx */ + dsp_cmx_receive(dsp, skb); + } + + spin_unlock_irqrestore(&dsp_lock, flags); + + /* send dtmf result, if any */ + if (digits) { while (*digits) { + int k; struct sk_buff *nskb; if (dsp_debug & DEBUG_DSP_DTMF) printk(KERN_DEBUG "%s: digit" "(%c) to layer %s\n", __func__, *digits, dsp->name); - cont = DTMF_TONE_VAL | *digits; + k = *digits | DTMF_TONE_VAL; nskb = _alloc_mISDN_skb(PH_CONTROL_IND, - MISDN_ID_ANY, sizeof(int), &cont, - GFP_ATOMIC); + MISDN_ID_ANY, sizeof(int), &k, + GFP_ATOMIC); if (nskb) { if (dsp->up) { if (dsp->up->send( dsp->up, nskb)) - dev_kfree_skb(nskb); + dev_kfree_skb(nskb); } else dev_kfree_skb(nskb); } digits++; } } - /* we need to process receive data if software */ - spin_lock_irqsave(&dsp_lock, flags); - if (dsp->pcm_slot_tx < 0 && dsp->pcm_slot_rx < 0) { - /* process data from card at cmx */ - dsp_cmx_receive(dsp, skb); - } - spin_unlock_irqrestore(&dsp_lock, flags); - if (dsp->rx_disabled) { /* if receive is not allowed */ break; @@ -787,7 +795,7 @@ dsp_function(struct mISDNchannel *ch, struct sk_buff *skb) if (dsp->up) { if (dsp->up->send( dsp->up, nskb)) - dev_kfree_skb(nskb); + dev_kfree_skb(nskb); } else dev_kfree_skb(nskb); } @@ -946,7 +954,7 @@ dsp_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg) int err = 0; if (debug & DEBUG_DSP_CTRL) - printk(KERN_DEBUG "%s:(%x)\n", __func__, cmd); + printk(KERN_DEBUG "%s:(%x)\n", __func__, cmd); switch (cmd) { case OPEN_CHANNEL: @@ -1169,9 +1177,9 @@ static int dsp_init(void) /* init conversion tables */ dsp_audio_generate_law_tables(); - dsp_silence = (dsp_options&DSP_OPT_ULAW)?0xff:0x2a; - dsp_audio_law_to_s32 = (dsp_options&DSP_OPT_ULAW)?dsp_audio_ulaw_to_s32: - dsp_audio_alaw_to_s32; + dsp_silence = (dsp_options&DSP_OPT_ULAW) ? 0xff : 0x2a; + dsp_audio_law_to_s32 = (dsp_options&DSP_OPT_ULAW) ? + dsp_audio_ulaw_to_s32 : dsp_audio_alaw_to_s32; dsp_audio_generate_s2law_table(); dsp_audio_generate_seven(); dsp_audio_generate_mix_table(); diff --git a/drivers/isdn/mISDN/dsp_dtmf.c b/drivers/isdn/mISDN/dsp_dtmf.c index efc371c1f0dc..9ae2d33b06f7 100644 --- a/drivers/isdn/mISDN/dsp_dtmf.c +++ b/drivers/isdn/mISDN/dsp_dtmf.c @@ -51,6 +51,9 @@ void dsp_dtmf_hardware(struct dsp *dsp) { int hardware = 1; + if (!dsp->dtmf.enable) + return; + if (!dsp->features.hfc_dtmf) hardware = 0; diff --git a/drivers/isdn/mISDN/dsp_ecdis.h b/drivers/isdn/mISDN/dsp_ecdis.h index 8a20af43308b..21dbd153ee26 100644 --- a/drivers/isdn/mISDN/dsp_ecdis.h +++ b/drivers/isdn/mISDN/dsp_ecdis.h @@ -91,7 +91,7 @@ int16_t amp) && det->tone_cycle_duration <= 475*8) { det->good_cycles++; if (det->good_cycles > 2) - det->hit = TRUE; + det->hit = TRUE; } det->tone_cycle_duration = 0; } diff --git a/drivers/isdn/mISDN/dsp_pipeline.c b/drivers/isdn/mISDN/dsp_pipeline.c index 18cf87c113e7..e9941678edfa 100644 --- a/drivers/isdn/mISDN/dsp_pipeline.c +++ b/drivers/isdn/mISDN/dsp_pipeline.c @@ -55,20 +55,19 @@ static ssize_t attr_show_args(struct device *dev, struct device_attribute *attr, char *buf) { struct mISDN_dsp_element *elem = dev_get_drvdata(dev); - ssize_t len = 0; - int i = 0; + int i; + char *p = buf; *buf = 0; - for (; i < elem->num_args; ++i) - len = sprintf(buf, "%sName: %s\n%s%s%sDescription: %s\n" - "\n", buf, + for (i = 0; i < elem->num_args; i++) + p += sprintf(p, "Name: %s\n%s%s%sDescription: %s\n\n", elem->args[i].name, elem->args[i].def ? "Default: " : "", elem->args[i].def ? elem->args[i].def : "", elem->args[i].def ? "\n" : "", elem->args[i].desc); - return len; + return p - buf; } static struct device_attribute element_attributes[] = { @@ -347,7 +346,8 @@ void dsp_pipeline_process_tx(struct dsp_pipeline *pipeline, u8 *data, int len) entry->elem->process_tx(entry->p, data, len); } -void dsp_pipeline_process_rx(struct dsp_pipeline *pipeline, u8 *data, int len) +void dsp_pipeline_process_rx(struct dsp_pipeline *pipeline, u8 *data, int len, + unsigned int txlen) { struct dsp_pipeline_entry *entry; @@ -356,7 +356,7 @@ void dsp_pipeline_process_rx(struct dsp_pipeline *pipeline, u8 *data, int len) list_for_each_entry_reverse(entry, &pipeline->list, list) if (entry->elem->process_rx) - entry->elem->process_rx(entry->p, data, len); + entry->elem->process_rx(entry->p, data, len, txlen); } diff --git a/drivers/isdn/mISDN/dsp_tones.c b/drivers/isdn/mISDN/dsp_tones.c index 7a9af66f4b19..1debf53670de 100644 --- a/drivers/isdn/mISDN/dsp_tones.c +++ b/drivers/isdn/mISDN/dsp_tones.c @@ -253,18 +253,24 @@ static struct pattern { {8000, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, {TONE_GERMAN_DIALPBX, - {DATA_GA, DATA_S, DATA_GA, DATA_S, DATA_GA, DATA_S, NULL, NULL, NULL, NULL}, - {SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, NULL, NULL, NULL, NULL}, + {DATA_GA, DATA_S, DATA_GA, DATA_S, DATA_GA, DATA_S, NULL, NULL, NULL, + NULL}, + {SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, NULL, NULL, NULL, + NULL}, {2000, 2000, 2000, 2000, 2000, 12000, 0, 0, 0, 0} }, {TONE_GERMAN_OLDDIALPBX, - {DATA_GO, DATA_S, DATA_GO, DATA_S, DATA_GO, DATA_S, NULL, NULL, NULL, NULL}, - {SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, NULL, NULL, NULL, NULL}, + {DATA_GO, DATA_S, DATA_GO, DATA_S, DATA_GO, DATA_S, NULL, NULL, NULL, + NULL}, + {SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, NULL, NULL, NULL, + NULL}, {2000, 2000, 2000, 2000, 2000, 12000, 0, 0, 0, 0} }, {TONE_AMERICAN_DIALPBX, - {DATA_DT, DATA_S, DATA_DT, DATA_S, DATA_DT, DATA_S, NULL, NULL, NULL, NULL}, - {SIZE_DT, SIZE_S, SIZE_DT, SIZE_S, SIZE_DT, SIZE_S, NULL, NULL, NULL, NULL}, + {DATA_DT, DATA_S, DATA_DT, DATA_S, DATA_DT, DATA_S, NULL, NULL, NULL, + NULL}, + {SIZE_DT, SIZE_S, SIZE_DT, SIZE_S, SIZE_DT, SIZE_S, NULL, NULL, NULL, + NULL}, {2000, 2000, 2000, 2000, 2000, 12000, 0, 0, 0, 0} }, {TONE_GERMAN_RINGING, @@ -434,7 +440,7 @@ dsp_tone_hw_message(struct dsp *dsp, u8 *sample, int len) /* unlocking is not required, because we don't expect a response */ nskb = _alloc_mISDN_skb(PH_CONTROL_REQ, - (len)?HFC_SPL_LOOP_ON:HFC_SPL_LOOP_OFF, len, sample, + (len) ? HFC_SPL_LOOP_ON : HFC_SPL_LOOP_OFF, len, sample, GFP_ATOMIC); if (nskb) { if (dsp->ch.peer) { @@ -498,8 +504,7 @@ dsp_tone(struct dsp *dsp, int tone) /* we turn off the tone */ if (!tone) { - if (dsp->features.hfc_loops) - if (timer_pending(&tonet->tl)) + if (dsp->features.hfc_loops && timer_pending(&tonet->tl)) del_timer(&tonet->tl); if (dsp->features.hfc_loops) dsp_tone_hw_message(dsp, NULL, 0); diff --git a/drivers/isdn/mISDN/hwchannel.c b/drivers/isdn/mISDN/hwchannel.c index ab1168a110ae..0481a0cdf6db 100644 --- a/drivers/isdn/mISDN/hwchannel.c +++ b/drivers/isdn/mISDN/hwchannel.c @@ -185,13 +185,13 @@ recv_Echannel(struct dchannel *ech, struct dchannel *dch) EXPORT_SYMBOL(recv_Echannel); void -recv_Bchannel(struct bchannel *bch) +recv_Bchannel(struct bchannel *bch, unsigned int id) { struct mISDNhead *hh; hh = mISDN_HEAD_P(bch->rx_skb); hh->prim = PH_DATA_IND; - hh->id = MISDN_ID_ANY; + hh->id = id; if (bch->rcount >= 64) { printk(KERN_WARNING "B-channel %p receive queue overflow, " "fushing!\n", bch); diff --git a/drivers/isdn/mISDN/l1oip.h b/drivers/isdn/mISDN/l1oip.h index a23d575449f6..bc26c890d9a2 100644 --- a/drivers/isdn/mISDN/l1oip.h +++ b/drivers/isdn/mISDN/l1oip.h @@ -76,7 +76,7 @@ struct l1oip { struct sockaddr_in sin_local; /* local socket name */ struct sockaddr_in sin_remote; /* remote socket name */ struct msghdr sendmsg; /* ip message to send */ - struct iovec sendiov; /* iov for message */ + struct kvec sendiov; /* iov for message */ /* frame */ struct l1oip_chan chan[128]; /* channel instances */ diff --git a/drivers/isdn/mISDN/l1oip_codec.c b/drivers/isdn/mISDN/l1oip_codec.c index e4ecba3d48df..bbfd1b863ed3 100644 --- a/drivers/isdn/mISDN/l1oip_codec.c +++ b/drivers/isdn/mISDN/l1oip_codec.c @@ -48,6 +48,7 @@ NOTE: The bytes are handled as they are law-encoded. #include #include +#include #include "core.h" #include "l1oip.h" diff --git a/drivers/isdn/mISDN/l1oip_core.c b/drivers/isdn/mISDN/l1oip_core.c index abe574989572..990e6a7e6674 100644 --- a/drivers/isdn/mISDN/l1oip_core.c +++ b/drivers/isdn/mISDN/l1oip_core.c @@ -279,7 +279,6 @@ l1oip_socket_send(struct l1oip *hc, u8 localcodec, u8 channel, u32 chanmask, int multi = 0; u8 frame[len+32]; struct socket *socket = NULL; - mm_segment_t oldfs; if (debug & DEBUG_L1OIP_MSG) printk(KERN_DEBUG "%s: sending data to socket (len = %d)\n", @@ -308,8 +307,8 @@ l1oip_socket_send(struct l1oip *hc, u8 localcodec, u8 channel, u32 chanmask, /* assemble frame */ *p++ = (L1OIP_VERSION<<6) /* version and coding */ - | (hc->pri?0x20:0x00) /* type */ - | (hc->id?0x10:0x00) /* id */ + | (hc->pri ? 0x20 : 0x00) /* type */ + | (hc->id ? 0x10 : 0x00) /* id */ | localcodec; if (hc->id) { *p++ = hc->id>>24; /* id */ @@ -317,7 +316,7 @@ l1oip_socket_send(struct l1oip *hc, u8 localcodec, u8 channel, u32 chanmask, *p++ = hc->id>>8; *p++ = hc->id; } - *p++ = (multi == 1)?0x80:0x00 + channel; /* m-flag, channel */ + *p++ = (multi == 1) ? 0x80 : 0x00 + channel; /* m-flag, channel */ if (multi == 1) *p++ = len; /* length */ *p++ = timebase>>8; /* time base */ @@ -352,10 +351,7 @@ l1oip_socket_send(struct l1oip *hc, u8 localcodec, u8 channel, u32 chanmask, "= %d)\n", __func__, len); hc->sendiov.iov_base = frame; hc->sendiov.iov_len = len; - oldfs = get_fs(); - set_fs(KERNEL_DS); - len = sock_sendmsg(socket, &hc->sendmsg, len); - set_fs(oldfs); + len = kernel_sendmsg(socket, &hc->sendmsg, &hc->sendiov, 1, len); /* give socket back */ hc->socket = socket; /* no locking required */ @@ -401,12 +397,12 @@ l1oip_socket_recv(struct l1oip *hc, u8 remotecodec, u8 channel, u16 timebase, } /* prepare message */ - nskb = mI_alloc_skb((remotecodec == 3)?(len<<1):len, GFP_ATOMIC); + nskb = mI_alloc_skb((remotecodec == 3) ? (len<<1) : len, GFP_ATOMIC); if (!nskb) { printk(KERN_ERR "%s: No mem for skb.\n", __func__); return; } - p = skb_put(nskb, (remotecodec == 3)?(len<<1):len); + p = skb_put(nskb, (remotecodec == 3) ? (len<<1) : len); if (remotecodec == 1 && ulaw) l1oip_alaw_to_ulaw(buf, len, p); @@ -458,7 +454,7 @@ l1oip_socket_recv(struct l1oip *hc, u8 remotecodec, u8 channel, u16 timebase, hc->chan[channel].disorder_flag ^= 1; if (nskb) #endif - queue_ch_frame(&bch->ch, PH_DATA_IND, rx_counter, nskb); + queue_ch_frame(&bch->ch, PH_DATA_IND, rx_counter, nskb); } } @@ -660,21 +656,29 @@ l1oip_socket_thread(void *data) struct l1oip *hc = (struct l1oip *)data; int ret = 0; struct msghdr msg; - struct iovec iov; - mm_segment_t oldfs; struct sockaddr_in sin_rx; - unsigned char recvbuf[1500]; + unsigned char *recvbuf; + size_t recvbuf_size = 1500; int recvlen; struct socket *socket = NULL; DECLARE_COMPLETION(wait); + /* allocate buffer memory */ + recvbuf = kmalloc(recvbuf_size, GFP_KERNEL); + if (!recvbuf) { + printk(KERN_ERR "%s: Failed to alloc recvbuf.\n", __func__); + ret = -ENOMEM; + goto fail; + } + /* make daemon */ allow_signal(SIGTERM); /* create socket */ if (sock_create(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &socket)) { printk(KERN_ERR "%s: Failed to create socket.\n", __func__); - return -EIO; + ret = -EIO; + goto fail; } /* set incoming address */ @@ -708,16 +712,12 @@ l1oip_socket_thread(void *data) msg.msg_namelen = sizeof(sin_rx); msg.msg_control = NULL; msg.msg_controllen = 0; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; /* build send message */ hc->sendmsg.msg_name = &hc->sin_remote; hc->sendmsg.msg_namelen = sizeof(hc->sin_remote); hc->sendmsg.msg_control = NULL; hc->sendmsg.msg_controllen = 0; - hc->sendmsg.msg_iov = &hc->sendiov; - hc->sendmsg.msg_iovlen = 1; /* give away socket */ spin_lock(&hc->socket_lock); @@ -729,18 +729,18 @@ l1oip_socket_thread(void *data) printk(KERN_DEBUG "%s: socket created and open\n", __func__); while (!signal_pending(current)) { - iov.iov_base = recvbuf; - iov.iov_len = sizeof(recvbuf); - oldfs = get_fs(); - set_fs(KERNEL_DS); - recvlen = sock_recvmsg(socket, &msg, sizeof(recvbuf), 0); - set_fs(oldfs); + struct kvec iov = { + .iov_base = recvbuf, + .iov_len = sizeof(recvbuf), + }; + recvlen = kernel_recvmsg(socket, &msg, &iov, 1, + sizeof(recvbuf), 0); if (recvlen > 0) { l1oip_socket_parse(hc, &sin_rx, recvbuf, recvlen); } else { if (debug & DEBUG_L1OIP_SOCKET) - printk(KERN_WARNING "%s: broken pipe on socket\n", - __func__); + printk(KERN_WARNING + "%s: broken pipe on socket\n", __func__); } } @@ -760,6 +760,9 @@ l1oip_socket_thread(void *data) __func__); fail: + /* free recvbuf */ + kfree(recvbuf); + /* close socket */ if (socket) sock_release(socket); @@ -912,7 +915,7 @@ handle_dmsg(struct mISDNchannel *ch, struct sk_buff *skb) p = skb->data; l = skb->len; while (l) { - ll = (l < L1OIP_MAX_PERFRAME)?l:L1OIP_MAX_PERFRAME; + ll = (l < L1OIP_MAX_PERFRAME) ? l : L1OIP_MAX_PERFRAME; l1oip_socket_send(hc, 0, dch->slot, 0, hc->chan[dch->slot].tx_counter++, p, ll); p += ll; @@ -1160,7 +1163,7 @@ handle_bmsg(struct mISDNchannel *ch, struct sk_buff *skb) p = skb->data; l = skb->len; while (l) { - ll = (l < L1OIP_MAX_PERFRAME)?l:L1OIP_MAX_PERFRAME; + ll = (l < L1OIP_MAX_PERFRAME) ? l : L1OIP_MAX_PERFRAME; l1oip_socket_send(hc, hc->codec, bch->slot, 0, hc->chan[bch->slot].tx_counter, p, ll); hc->chan[bch->slot].tx_counter += ll; @@ -1318,8 +1321,8 @@ init_card(struct l1oip *hc, int pri, int bundle) spin_lock_init(&hc->socket_lock); hc->idx = l1oip_cnt; hc->pri = pri; - hc->d_idx = pri?16:3; - hc->b_num = pri?30:2; + hc->d_idx = pri ? 16 : 3; + hc->b_num = pri ? 30 : 2; hc->bundle = bundle; if (hc->pri) sprintf(hc->name, "l1oip-e1.%d", l1oip_cnt + 1); @@ -1504,9 +1507,9 @@ l1oip_init(void) if (debug & DEBUG_L1OIP_INIT) printk(KERN_DEBUG "%s: interface %d is %s with %s.\n", - __func__, l1oip_cnt, pri?"PRI":"BRI", - bundle?"bundled IP packet for all B-channels" - :"seperate IP packets for every B-channel"); + __func__, l1oip_cnt, pri ? "PRI" : "BRI", + bundle ? "bundled IP packet for all B-channels" : + "seperate IP packets for every B-channel"); hc = kzalloc(sizeof(struct l1oip), GFP_ATOMIC); if (!hc) { diff --git a/drivers/isdn/mISDN/layer2.c b/drivers/isdn/mISDN/layer2.c index d6e2863f224a..9c2589e986d6 100644 --- a/drivers/isdn/mISDN/layer2.c +++ b/drivers/isdn/mISDN/layer2.c @@ -99,7 +99,7 @@ l2m_debug(struct FsmInst *fi, char *fmt, ...) if (!(*debug & DEBUG_L2_FSM)) return; va_start(va, fmt); - printk(KERN_DEBUG "l2 (tei %d): ", l2->tei); + printk(KERN_DEBUG "l2 (sapi %d tei %d): ", l2->sapi, l2->tei); vprintk(fmt, va); printk("\n"); va_end(va); @@ -1859,20 +1859,18 @@ ph_data_indication(struct layer2 *l2, struct mISDNhead *hh, struct sk_buff *skb) psapi >>= 2; ptei >>= 1; if (psapi != l2->sapi) { - /* not our bussiness - * printk(KERN_DEBUG "%s: sapi %d/%d sapi mismatch\n", - * __func__, - * psapi, l2->sapi); - */ + /* not our bussiness */ + if (*debug & DEBUG_L2) + printk(KERN_DEBUG "%s: sapi %d/%d mismatch\n", + __func__, psapi, l2->sapi); dev_kfree_skb(skb); return 0; } if ((ptei != l2->tei) && (ptei != GROUP_TEI)) { - /* not our bussiness - * printk(KERN_DEBUG "%s: tei %d/%d sapi %d mismatch\n", - * __func__, - * ptei, l2->tei, psapi); - */ + /* not our bussiness */ + if (*debug & DEBUG_L2) + printk(KERN_DEBUG "%s: tei %d/%d mismatch\n", + __func__, ptei, l2->tei); dev_kfree_skb(skb); return 0; } @@ -1927,8 +1925,8 @@ l2_send(struct mISDNchannel *ch, struct sk_buff *skb) int ret = -EINVAL; if (*debug & DEBUG_L2_RECV) - printk(KERN_DEBUG "%s: prim(%x) id(%x) tei(%d)\n", - __func__, hh->prim, hh->id, l2->tei); + printk(KERN_DEBUG "%s: prim(%x) id(%x) sapi(%d) tei(%d)\n", + __func__, hh->prim, hh->id, l2->sapi, l2->tei); switch (hh->prim) { case PH_DATA_IND: ret = ph_data_indication(l2, hh, skb); @@ -2068,7 +2066,8 @@ l2_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg) } struct layer2 * -create_l2(struct mISDNchannel *ch, u_int protocol, u_long options, u_long arg) +create_l2(struct mISDNchannel *ch, u_int protocol, u_long options, int tei, + int sapi) { struct layer2 *l2; struct channel_req rq; @@ -2089,7 +2088,7 @@ create_l2(struct mISDNchannel *ch, u_int protocol, u_long options, u_long arg) test_and_set_bit(FLG_LAPD, &l2->flag); test_and_set_bit(FLG_LAPD_NET, &l2->flag); test_and_set_bit(FLG_MOD128, &l2->flag); - l2->sapi = 0; + l2->sapi = sapi; l2->maxlen = MAX_DFRAME_LEN; if (test_bit(OPTION_L2_PMX, &options)) l2->window = 7; @@ -2099,7 +2098,7 @@ create_l2(struct mISDNchannel *ch, u_int protocol, u_long options, u_long arg) test_and_set_bit(FLG_PTP, &l2->flag); if (test_bit(OPTION_L2_FIXEDTEI, &options)) test_and_set_bit(FLG_FIXED_TEI, &l2->flag); - l2->tei = (u_int)arg; + l2->tei = tei; l2->T200 = 1000; l2->N200 = 3; l2->T203 = 10000; @@ -2114,7 +2113,7 @@ create_l2(struct mISDNchannel *ch, u_int protocol, u_long options, u_long arg) test_and_set_bit(FLG_LAPD, &l2->flag); test_and_set_bit(FLG_MOD128, &l2->flag); test_and_set_bit(FLG_ORIG, &l2->flag); - l2->sapi = 0; + l2->sapi = sapi; l2->maxlen = MAX_DFRAME_LEN; if (test_bit(OPTION_L2_PMX, &options)) l2->window = 7; @@ -2124,7 +2123,7 @@ create_l2(struct mISDNchannel *ch, u_int protocol, u_long options, u_long arg) test_and_set_bit(FLG_PTP, &l2->flag); if (test_bit(OPTION_L2_FIXEDTEI, &options)) test_and_set_bit(FLG_FIXED_TEI, &l2->flag); - l2->tei = (u_int)arg; + l2->tei = tei; l2->T200 = 1000; l2->N200 = 3; l2->T203 = 10000; @@ -2180,7 +2179,7 @@ x75create(struct channel_req *crq) if (crq->protocol != ISDN_P_B_X75SLP) return -EPROTONOSUPPORT; - l2 = create_l2(crq->ch, crq->protocol, 0, 0); + l2 = create_l2(crq->ch, crq->protocol, 0, 0, 0); if (!l2) return -ENOMEM; crq->ch = &l2->ch; diff --git a/drivers/isdn/mISDN/layer2.h b/drivers/isdn/mISDN/layer2.h index 6293f80dc2d3..9547fb3707a3 100644 --- a/drivers/isdn/mISDN/layer2.h +++ b/drivers/isdn/mISDN/layer2.h @@ -90,7 +90,7 @@ enum { #define L2_STATE_COUNT (ST_L2_8+1) extern struct layer2 *create_l2(struct mISDNchannel *, u_int, - u_long, u_long); + u_long, int, int); extern int tei_l2(struct layer2 *, u_int, u_long arg); diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c index 508945d1b9c1..c36f52137456 100644 --- a/drivers/isdn/mISDN/socket.c +++ b/drivers/isdn/mISDN/socket.c @@ -209,7 +209,7 @@ mISDN_sock_sendmsg(struct kiocb *iocb, struct socket *sock, if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) { err = -EFAULT; - goto drop; + goto done; } memcpy(mISDN_HEAD_P(skb), skb->data, MISDN_HEADER_LEN); @@ -222,7 +222,7 @@ mISDN_sock_sendmsg(struct kiocb *iocb, struct socket *sock, } else { /* use default for L2 messages */ if ((sk->sk_protocol == ISDN_P_LAPD_TE) || (sk->sk_protocol == ISDN_P_LAPD_NT)) - mISDN_HEAD_ID(skb) = _pms(sk)->ch.nr; + mISDN_HEAD_ID(skb) = _pms(sk)->ch.nr; } if (*debug & DEBUG_SOCKET) @@ -230,19 +230,21 @@ mISDN_sock_sendmsg(struct kiocb *iocb, struct socket *sock, __func__, mISDN_HEAD_ID(skb)); err = -ENODEV; - if (!_pms(sk)->ch.peer || - (err = _pms(sk)->ch.recv(_pms(sk)->ch.peer, skb))) - goto drop; - - err = len; + if (!_pms(sk)->ch.peer) + goto done; + err = _pms(sk)->ch.recv(_pms(sk)->ch.peer, skb); + if (err) + goto done; + else { + skb = NULL; + err = len; + } done: + if (skb) + kfree_skb(skb); release_sock(sk); return err; - -drop: - kfree_skb(skb); - goto done; } static int @@ -292,7 +294,7 @@ static int data_sock_ioctl_bound(struct sock *sk, unsigned int cmd, void __user *p) { struct mISDN_ctrl_req cq; - int err = -EINVAL, val; + int err = -EINVAL, val[2]; struct mISDNchannel *bchan, *next; lock_sock(sk); @@ -328,12 +330,27 @@ data_sock_ioctl_bound(struct sock *sk, unsigned int cmd, void __user *p) err = -EINVAL; break; } - if (get_user(val, (int __user *)p)) { + val[0] = cmd; + if (get_user(val[1], (int __user *)p)) { err = -EFAULT; break; } err = _pms(sk)->dev->teimgr->ctrl(_pms(sk)->dev->teimgr, - CONTROL_CHANNEL, &val); + CONTROL_CHANNEL, val); + break; + case IMHOLD_L1: + if (sk->sk_protocol != ISDN_P_LAPD_NT + && sk->sk_protocol != ISDN_P_LAPD_TE) { + err = -EINVAL; + break; + } + val[0] = cmd; + if (get_user(val[1], (int __user *)p)) { + err = -EFAULT; + break; + } + err = _pms(sk)->dev->teimgr->ctrl(_pms(sk)->dev->teimgr, + CONTROL_CHANNEL, val); break; default: err = -EINVAL; diff --git a/drivers/isdn/mISDN/tei.c b/drivers/isdn/mISDN/tei.c index b452dead8fd0..e04bad6c5baf 100644 --- a/drivers/isdn/mISDN/tei.c +++ b/drivers/isdn/mISDN/tei.c @@ -122,8 +122,11 @@ da_deactivate(struct FsmInst *fi, int event, void *arg) } read_unlock_irqrestore(&mgr->lock, flags); /* All TEI are inactiv */ - mISDN_FsmAddTimer(&mgr->datimer, DATIMER_VAL, EV_DATIMER, NULL, 1); - mISDN_FsmChangeState(fi, ST_L1_DEACT_PENDING); + if (!test_bit(OPTION_L1_HOLD, &mgr->options)) { + mISDN_FsmAddTimer(&mgr->datimer, DATIMER_VAL, EV_DATIMER, + NULL, 1); + mISDN_FsmChangeState(fi, ST_L1_DEACT_PENDING); + } } static void @@ -132,9 +135,11 @@ da_ui(struct FsmInst *fi, int event, void *arg) struct manager *mgr = fi->userdata; /* restart da timer */ - mISDN_FsmDelTimer(&mgr->datimer, 2); - mISDN_FsmAddTimer(&mgr->datimer, DATIMER_VAL, EV_DATIMER, NULL, 2); - + if (!test_bit(OPTION_L1_HOLD, &mgr->options)) { + mISDN_FsmDelTimer(&mgr->datimer, 2); + mISDN_FsmAddTimer(&mgr->datimer, DATIMER_VAL, EV_DATIMER, + NULL, 2); + } } static void @@ -222,7 +227,7 @@ tei_debug(struct FsmInst *fi, char *fmt, ...) if (!(*debug & DEBUG_L2_TEIFSM)) return; va_start(va, fmt); - printk(KERN_DEBUG "tei(%d): ", tm->l2->tei); + printk(KERN_DEBUG "sapi(%d) tei(%d): ", tm->l2->sapi, tm->l2->tei); vprintk(fmt, va); printk("\n"); va_end(va); @@ -421,7 +426,7 @@ done: } static void -put_tei_msg(struct manager *mgr, u_char m_id, unsigned int ri, u_char tei) +put_tei_msg(struct manager *mgr, u_char m_id, unsigned int ri, int tei) { struct sk_buff *skb; u_char bp[8]; @@ -435,9 +440,8 @@ put_tei_msg(struct manager *mgr, u_char m_id, unsigned int ri, u_char tei) bp[4] = ri >> 8; bp[5] = ri & 0xff; bp[6] = m_id; - bp[7] = (tei << 1) | 1; - skb = _alloc_mISDN_skb(PH_DATA_REQ, new_id(mgr), - 8, bp, GFP_ATOMIC); + bp[7] = ((tei << 1) & 0xff) | 1; + skb = _alloc_mISDN_skb(PH_DATA_REQ, new_id(mgr), 8, bp, GFP_ATOMIC); if (!skb) { printk(KERN_WARNING "%s: no skb for tei msg\n", __func__); return; @@ -772,7 +776,7 @@ tei_ph_data_ind(struct teimgr *tm, u_int mt, u_char *dp, int len) } static struct layer2 * -create_new_tei(struct manager *mgr, int tei) +create_new_tei(struct manager *mgr, int tei, int sapi) { u_long opt = 0; u_long flags; @@ -781,12 +785,12 @@ create_new_tei(struct manager *mgr, int tei) if (!mgr->up) return NULL; - if (tei < 64) + if ((tei >= 0) && (tei < 64)) test_and_set_bit(OPTION_L2_FIXEDTEI, &opt); if (mgr->ch.st->dev->Dprotocols & ((1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1))) test_and_set_bit(OPTION_L2_PMX, &opt); - l2 = create_l2(mgr->up, ISDN_P_LAPD_NT, (u_int)opt, (u_long)tei); + l2 = create_l2(mgr->up, ISDN_P_LAPD_NT, opt, tei, sapi); if (!l2) { printk(KERN_WARNING "%s:no memory for layer2\n", __func__); return NULL; @@ -834,12 +838,17 @@ new_tei_req(struct manager *mgr, u_char *dp) ri += dp[1]; if (!mgr->up) goto denied; - tei = get_free_tei(mgr); + if (!(dp[3] & 1)) /* Extension bit != 1 */ + goto denied; + if (dp[3] != 0xff) + tei = dp[3] >> 1; /* 3GPP TS 08.56 6.1.11.2 */ + else + tei = get_free_tei(mgr); if (tei < 0) { printk(KERN_WARNING "%s:No free tei\n", __func__); goto denied; } - l2 = create_new_tei(mgr, tei); + l2 = create_new_tei(mgr, tei, CTRL_SAPI); if (!l2) goto denied; else @@ -853,8 +862,7 @@ static int ph_data_ind(struct manager *mgr, struct sk_buff *skb) { int ret = -EINVAL; - struct layer2 *l2; - u_long flags; + struct layer2 *l2, *nl2; u_char mt; if (skb->len < 8) { @@ -863,7 +871,6 @@ ph_data_ind(struct manager *mgr, struct sk_buff *skb) __func__, skb->len); goto done; } - if (*debug & DEBUG_L2_TEI) if ((skb->data[0] >> 2) != TEI_SAPI) /* not for us */ goto done; @@ -900,11 +907,9 @@ ph_data_ind(struct manager *mgr, struct sk_buff *skb) new_tei_req(mgr, &skb->data[4]); goto done; } - read_lock_irqsave(&mgr->lock, flags); - list_for_each_entry(l2, &mgr->layer2, list) { + list_for_each_entry_safe(l2, nl2, &mgr->layer2, list) { tei_ph_data_ind(l2->tm, mt, &skb->data[4], skb->len - 4); } - read_unlock_irqrestore(&mgr->lock, flags); done: return ret; } @@ -971,8 +976,6 @@ create_teimgr(struct manager *mgr, struct channel_req *crq) __func__, dev_name(&mgr->ch.st->dev->dev), crq->protocol, crq->adr.dev, crq->adr.channel, crq->adr.sapi, crq->adr.tei); - if (crq->adr.sapi != 0) /* not supported yet */ - return -EINVAL; if (crq->adr.tei > GROUP_TEI) return -EINVAL; if (crq->adr.tei < 64) @@ -1019,8 +1022,8 @@ create_teimgr(struct manager *mgr, struct channel_req *crq) } return 0; } - l2 = create_l2(crq->ch, crq->protocol, (u_int)opt, - (u_long)crq->adr.tei); + l2 = create_l2(crq->ch, crq->protocol, opt, + crq->adr.tei, crq->adr.sapi); if (!l2) return -ENOMEM; l2->tm = kzalloc(sizeof(struct teimgr), GFP_KERNEL); @@ -1103,6 +1106,7 @@ free_teimanager(struct manager *mgr) { struct layer2 *l2, *nl2; + test_and_clear_bit(OPTION_L1_HOLD, &mgr->options); if (test_bit(MGR_OPT_NETWORK, &mgr->options)) { /* not locked lock is taken in release tei */ mgr->up = NULL; @@ -1133,13 +1137,26 @@ static int ctrl_teimanager(struct manager *mgr, void *arg) { /* currently we only have one option */ - int clean = *((int *)arg); + int *val = (int *)arg; + int ret = 0; - if (clean) - test_and_set_bit(OPTION_L2_CLEANUP, &mgr->options); - else - test_and_clear_bit(OPTION_L2_CLEANUP, &mgr->options); - return 0; + switch (val[0]) { + case IMCLEAR_L2: + if (val[1]) + test_and_set_bit(OPTION_L2_CLEANUP, &mgr->options); + else + test_and_clear_bit(OPTION_L2_CLEANUP, &mgr->options); + break; + case IMHOLD_L1: + if (val[1]) + test_and_set_bit(OPTION_L1_HOLD, &mgr->options); + else + test_and_clear_bit(OPTION_L1_HOLD, &mgr->options); + break; + default: + ret = -EINVAL; + } + return ret; } /* This function does create a L2 for fixed TEI in NT Mode */ @@ -1147,7 +1164,7 @@ static int check_data(struct manager *mgr, struct sk_buff *skb) { struct mISDNhead *hh = mISDN_HEAD_P(skb); - int ret, tei; + int ret, tei, sapi; struct layer2 *l2; if (*debug & DEBUG_L2_CTRL) @@ -1159,20 +1176,27 @@ check_data(struct manager *mgr, struct sk_buff *skb) return -ENOTCONN; if (skb->len != 3) return -ENOTCONN; - if (skb->data[0] != 0) - /* only SAPI 0 command */ - return -ENOTCONN; + if (skb->data[0] & 3) /* EA0 and CR must be 0 */ + return -EINVAL; + sapi = skb->data[0] >> 2; if (!(skb->data[1] & 1)) /* invalid EA1 */ return -EINVAL; - tei = skb->data[1] >> 0; + tei = skb->data[1] >> 1; if (tei > 63) /* not a fixed tei */ return -ENOTCONN; if ((skb->data[2] & ~0x10) != SABME) return -ENOTCONN; /* We got a SABME for a fixed TEI */ - l2 = create_new_tei(mgr, tei); - if (!l2) + if (*debug & DEBUG_L2_CTRL) + printk(KERN_DEBUG "%s: SABME sapi(%d) tei(%d)\n", + __func__, sapi, tei); + l2 = create_new_tei(mgr, tei, sapi); + if (!l2) { + if (*debug & DEBUG_L2_CTRL) + printk(KERN_DEBUG "%s: failed to create new tei\n", + __func__); return -ENOMEM; + } ret = l2->ch.send(&l2->ch, skb); return ret; } diff --git a/drivers/isdn/mISDN/timerdev.c b/drivers/isdn/mISDN/timerdev.c index bbd99d3282c0..5b7e9bf514f1 100644 --- a/drivers/isdn/mISDN/timerdev.c +++ b/drivers/isdn/mISDN/timerdev.c @@ -259,7 +259,7 @@ mISDN_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, return ret; } -static struct file_operations mISDN_fops = { +static const struct file_operations mISDN_fops = { .read = mISDN_read, .poll = mISDN_poll, .ioctl = mISDN_ioctl, diff --git a/drivers/leds/leds-h1940.c b/drivers/leds/leds-h1940.c index 1aa46a390a0d..173d104d9ff2 100644 --- a/drivers/leds/leds-h1940.c +++ b/drivers/leds/leds-h1940.c @@ -16,6 +16,8 @@ #include #include #include +#include + #include #include #include diff --git a/drivers/leds/leds-s3c24xx.c b/drivers/leds/leds-s3c24xx.c index aa2e7ae0cdae..aa7acf3b9224 100644 --- a/drivers/leds/leds-s3c24xx.c +++ b/drivers/leds/leds-s3c24xx.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include diff --git a/drivers/lguest/Kconfig b/drivers/lguest/Kconfig index a3d3cbab359a..0aaa0597a622 100644 --- a/drivers/lguest/Kconfig +++ b/drivers/lguest/Kconfig @@ -1,6 +1,6 @@ config LGUEST tristate "Linux hypervisor example code" - depends on X86_32 && EXPERIMENTAL && !X86_PAE && FUTEX + depends on X86_32 && EXPERIMENTAL && EVENTFD select HVC_DRIVER ---help--- This is a very simple module which allows you to run diff --git a/drivers/lguest/core.c b/drivers/lguest/core.c index 4845fb3cf74b..a6974e9b8ebf 100644 --- a/drivers/lguest/core.c +++ b/drivers/lguest/core.c @@ -95,7 +95,7 @@ static __init int map_switcher(void) * array of struct pages. It increments that pointer, but we don't * care. */ pagep = switcher_page; - err = map_vm_area(switcher_vma, PAGE_KERNEL, &pagep); + err = map_vm_area(switcher_vma, PAGE_KERNEL_EXEC, &pagep); if (err) { printk("lguest: map_vm_area failed: %i\n", err); goto free_vma; @@ -188,6 +188,9 @@ int run_guest(struct lg_cpu *cpu, unsigned long __user *user) { /* We stop running once the Guest is dead. */ while (!cpu->lg->dead) { + unsigned int irq; + bool more; + /* First we run any hypercalls the Guest wants done. */ if (cpu->hcall) do_hypercalls(cpu); @@ -195,23 +198,23 @@ int run_guest(struct lg_cpu *cpu, unsigned long __user *user) /* It's possible the Guest did a NOTIFY hypercall to the * Launcher, in which case we return from the read() now. */ if (cpu->pending_notify) { - if (put_user(cpu->pending_notify, user)) - return -EFAULT; - return sizeof(cpu->pending_notify); + if (!send_notify_to_eventfd(cpu)) { + if (put_user(cpu->pending_notify, user)) + return -EFAULT; + return sizeof(cpu->pending_notify); + } } /* Check for signals */ if (signal_pending(current)) return -ERESTARTSYS; - /* If Waker set break_out, return to Launcher. */ - if (cpu->break_out) - return -EAGAIN; - /* Check if there are any interrupts which can be delivered now: * if so, this sets up the hander to be executed when we next * run the Guest. */ - maybe_do_interrupt(cpu); + irq = interrupt_pending(cpu, &more); + if (irq < LGUEST_IRQS) + try_deliver_interrupt(cpu, irq, more); /* All long-lived kernel loops need to check with this horrible * thing called the freezer. If the Host is trying to suspend, @@ -224,10 +227,15 @@ int run_guest(struct lg_cpu *cpu, unsigned long __user *user) break; /* If the Guest asked to be stopped, we sleep. The Guest's - * clock timer or LHREQ_BREAK from the Waker will wake us. */ + * clock timer will wake us. */ if (cpu->halted) { set_current_state(TASK_INTERRUPTIBLE); - schedule(); + /* Just before we sleep, make sure no interrupt snuck in + * which we should be doing. */ + if (interrupt_pending(cpu, &more) < LGUEST_IRQS) + set_current_state(TASK_RUNNING); + else + schedule(); continue; } diff --git a/drivers/lguest/hypercalls.c b/drivers/lguest/hypercalls.c index 54d66f05fefa..c29ffa19cb74 100644 --- a/drivers/lguest/hypercalls.c +++ b/drivers/lguest/hypercalls.c @@ -37,6 +37,10 @@ static void do_hcall(struct lg_cpu *cpu, struct hcall_args *args) /* This call does nothing, except by breaking out of the Guest * it makes us process all the asynchronous hypercalls. */ break; + case LHCALL_SEND_INTERRUPTS: + /* This call does nothing too, but by breaking out of the Guest + * it makes us process any pending interrupts. */ + break; case LHCALL_LGUEST_INIT: /* You can't get here unless you're already initialized. Don't * do that. */ @@ -73,11 +77,21 @@ static void do_hcall(struct lg_cpu *cpu, struct hcall_args *args) guest_set_stack(cpu, args->arg1, args->arg2, args->arg3); break; case LHCALL_SET_PTE: +#ifdef CONFIG_X86_PAE + guest_set_pte(cpu, args->arg1, args->arg2, + __pte(args->arg3 | (u64)args->arg4 << 32)); +#else guest_set_pte(cpu, args->arg1, args->arg2, __pte(args->arg3)); +#endif break; + case LHCALL_SET_PGD: + guest_set_pgd(cpu->lg, args->arg1, args->arg2); + break; +#ifdef CONFIG_X86_PAE case LHCALL_SET_PMD: guest_set_pmd(cpu->lg, args->arg1, args->arg2); break; +#endif case LHCALL_SET_CLOCKEVENT: guest_set_clockevent(cpu, args->arg1); break; diff --git a/drivers/lguest/interrupts_and_traps.c b/drivers/lguest/interrupts_and_traps.c index 6e99adbe1946..0e9067b0d507 100644 --- a/drivers/lguest/interrupts_and_traps.c +++ b/drivers/lguest/interrupts_and_traps.c @@ -128,30 +128,39 @@ static void set_guest_interrupt(struct lg_cpu *cpu, u32 lo, u32 hi, /*H:205 * Virtual Interrupts. * - * maybe_do_interrupt() gets called before every entry to the Guest, to see if - * we should divert the Guest to running an interrupt handler. */ -void maybe_do_interrupt(struct lg_cpu *cpu) + * interrupt_pending() returns the first pending interrupt which isn't blocked + * by the Guest. It is called before every entry to the Guest, and just before + * we go to sleep when the Guest has halted itself. */ +unsigned int interrupt_pending(struct lg_cpu *cpu, bool *more) { unsigned int irq; DECLARE_BITMAP(blk, LGUEST_IRQS); - struct desc_struct *idt; /* If the Guest hasn't even initialized yet, we can do nothing. */ if (!cpu->lg->lguest_data) - return; + return LGUEST_IRQS; /* Take our "irqs_pending" array and remove any interrupts the Guest * wants blocked: the result ends up in "blk". */ if (copy_from_user(&blk, cpu->lg->lguest_data->blocked_interrupts, sizeof(blk))) - return; + return LGUEST_IRQS; bitmap_andnot(blk, cpu->irqs_pending, blk, LGUEST_IRQS); /* Find the first interrupt. */ irq = find_first_bit(blk, LGUEST_IRQS); - /* None? Nothing to do */ - if (irq >= LGUEST_IRQS) - return; + *more = find_next_bit(blk, LGUEST_IRQS, irq+1); + + return irq; +} + +/* This actually diverts the Guest to running an interrupt handler, once an + * interrupt has been identified by interrupt_pending(). */ +void try_deliver_interrupt(struct lg_cpu *cpu, unsigned int irq, bool more) +{ + struct desc_struct *idt; + + BUG_ON(irq >= LGUEST_IRQS); /* They may be in the middle of an iret, where they asked us never to * deliver interrupts. */ @@ -170,8 +179,12 @@ void maybe_do_interrupt(struct lg_cpu *cpu) u32 irq_enabled; if (get_user(irq_enabled, &cpu->lg->lguest_data->irq_enabled)) irq_enabled = 0; - if (!irq_enabled) + if (!irq_enabled) { + /* Make sure they know an IRQ is pending. */ + put_user(X86_EFLAGS_IF, + &cpu->lg->lguest_data->irq_pending); return; + } } /* Look at the IDT entry the Guest gave us for this interrupt. The @@ -194,6 +207,25 @@ void maybe_do_interrupt(struct lg_cpu *cpu) * here is a compromise which means at least it gets updated every * timer interrupt. */ write_timestamp(cpu); + + /* If there are no other interrupts we want to deliver, clear + * the pending flag. */ + if (!more) + put_user(0, &cpu->lg->lguest_data->irq_pending); +} + +/* And this is the routine when we want to set an interrupt for the Guest. */ +void set_interrupt(struct lg_cpu *cpu, unsigned int irq) +{ + /* Next time the Guest runs, the core code will see if it can deliver + * this interrupt. */ + set_bit(irq, cpu->irqs_pending); + + /* Make sure it sees it; it might be asleep (eg. halted), or + * running the Guest right now, in which case kick_process() + * will knock it out. */ + if (!wake_up_process(cpu->tsk)) + kick_process(cpu->tsk); } /*:*/ @@ -510,10 +542,7 @@ static enum hrtimer_restart clockdev_fn(struct hrtimer *timer) struct lg_cpu *cpu = container_of(timer, struct lg_cpu, hrt); /* Remember the first interrupt is the timer interrupt. */ - set_bit(0, cpu->irqs_pending); - /* If the Guest is actually stopped, we need to wake it up. */ - if (cpu->halted) - wake_up_process(cpu->tsk); + set_interrupt(cpu, 0); return HRTIMER_NORESTART; } diff --git a/drivers/lguest/lg.h b/drivers/lguest/lg.h index af92a176697f..d4e8979735cb 100644 --- a/drivers/lguest/lg.h +++ b/drivers/lguest/lg.h @@ -49,7 +49,7 @@ struct lg_cpu { u32 cr2; int ts; u32 esp1; - u8 ss1; + u16 ss1; /* Bitmap of what has changed: see CHANGED_* above. */ int changed; @@ -71,9 +71,7 @@ struct lg_cpu { /* Virtual clock device */ struct hrtimer hrt; - /* Do we need to stop what we're doing and return to userspace? */ - int break_out; - wait_queue_head_t break_wq; + /* Did the Guest tell us to halt? */ int halted; /* Pending virtual interrupts */ @@ -82,6 +80,16 @@ struct lg_cpu { struct lg_cpu_arch arch; }; +struct lg_eventfd { + unsigned long addr; + struct file *event; +}; + +struct lg_eventfd_map { + unsigned int num; + struct lg_eventfd map[]; +}; + /* The private info the thread maintains about the guest. */ struct lguest { @@ -102,6 +110,8 @@ struct lguest unsigned int stack_pages; u32 tsc_khz; + struct lg_eventfd_map *eventfds; + /* Dead? */ const char *dead; }; @@ -137,9 +147,13 @@ int run_guest(struct lg_cpu *cpu, unsigned long __user *user); * in the kernel. */ #define pgd_flags(x) (pgd_val(x) & ~PAGE_MASK) #define pgd_pfn(x) (pgd_val(x) >> PAGE_SHIFT) +#define pmd_flags(x) (pmd_val(x) & ~PAGE_MASK) +#define pmd_pfn(x) (pmd_val(x) >> PAGE_SHIFT) /* interrupts_and_traps.c: */ -void maybe_do_interrupt(struct lg_cpu *cpu); +unsigned int interrupt_pending(struct lg_cpu *cpu, bool *more); +void try_deliver_interrupt(struct lg_cpu *cpu, unsigned int irq, bool more); +void set_interrupt(struct lg_cpu *cpu, unsigned int irq); bool deliver_trap(struct lg_cpu *cpu, unsigned int num); void load_guest_idt_entry(struct lg_cpu *cpu, unsigned int i, u32 low, u32 hi); @@ -150,6 +164,7 @@ void setup_default_idt_entries(struct lguest_ro_state *state, void copy_traps(const struct lg_cpu *cpu, struct desc_struct *idt, const unsigned long *def); void guest_set_clockevent(struct lg_cpu *cpu, unsigned long delta); +bool send_notify_to_eventfd(struct lg_cpu *cpu); void init_clockdev(struct lg_cpu *cpu); bool check_syscall_vector(struct lguest *lg); int init_interrupts(void); @@ -168,7 +183,10 @@ void copy_gdt_tls(const struct lg_cpu *cpu, struct desc_struct *gdt); int init_guest_pagetable(struct lguest *lg); void free_guest_pagetable(struct lguest *lg); void guest_new_pagetable(struct lg_cpu *cpu, unsigned long pgtable); +void guest_set_pgd(struct lguest *lg, unsigned long gpgdir, u32 i); +#ifdef CONFIG_X86_PAE void guest_set_pmd(struct lguest *lg, unsigned long gpgdir, u32 i); +#endif void guest_pagetable_clear_all(struct lg_cpu *cpu); void guest_pagetable_flush_user(struct lg_cpu *cpu); void guest_set_pte(struct lg_cpu *cpu, unsigned long gpgdir, diff --git a/drivers/lguest/lguest_device.c b/drivers/lguest/lguest_device.c index df44d962626d..e082cdac88b4 100644 --- a/drivers/lguest/lguest_device.c +++ b/drivers/lguest/lguest_device.c @@ -228,7 +228,8 @@ extern void lguest_setup_irq(unsigned int irq); * function. */ static struct virtqueue *lg_find_vq(struct virtio_device *vdev, unsigned index, - void (*callback)(struct virtqueue *vq)) + void (*callback)(struct virtqueue *vq), + const char *name) { struct lguest_device *ldev = to_lgdev(vdev); struct lguest_vq_info *lvq; @@ -263,7 +264,7 @@ static struct virtqueue *lg_find_vq(struct virtio_device *vdev, /* OK, tell virtio_ring.c to set up a virtqueue now we know its size * and we've got a pointer to its pages. */ vq = vring_new_virtqueue(lvq->config.num, LGUEST_VRING_ALIGN, - vdev, lvq->pages, lg_notify, callback); + vdev, lvq->pages, lg_notify, callback, name); if (!vq) { err = -ENOMEM; goto unmap; @@ -312,6 +313,38 @@ static void lg_del_vq(struct virtqueue *vq) kfree(lvq); } +static void lg_del_vqs(struct virtio_device *vdev) +{ + struct virtqueue *vq, *n; + + list_for_each_entry_safe(vq, n, &vdev->vqs, list) + lg_del_vq(vq); +} + +static int lg_find_vqs(struct virtio_device *vdev, unsigned nvqs, + struct virtqueue *vqs[], + vq_callback_t *callbacks[], + const char *names[]) +{ + struct lguest_device *ldev = to_lgdev(vdev); + int i; + + /* We must have this many virtqueues. */ + if (nvqs > ldev->desc->num_vq) + return -ENOENT; + + for (i = 0; i < nvqs; ++i) { + vqs[i] = lg_find_vq(vdev, i, callbacks[i], names[i]); + if (IS_ERR(vqs[i])) + goto error; + } + return 0; + +error: + lg_del_vqs(vdev); + return PTR_ERR(vqs[i]); +} + /* The ops structure which hooks everything together. */ static struct virtio_config_ops lguest_config_ops = { .get_features = lg_get_features, @@ -321,8 +354,8 @@ static struct virtio_config_ops lguest_config_ops = { .get_status = lg_get_status, .set_status = lg_set_status, .reset = lg_reset, - .find_vq = lg_find_vq, - .del_vq = lg_del_vq, + .find_vqs = lg_find_vqs, + .del_vqs = lg_del_vqs, }; /* The root device for the lguest virtio devices. This makes them appear as diff --git a/drivers/lguest/lguest_user.c b/drivers/lguest/lguest_user.c index b8ee103eed5f..32e297121058 100644 --- a/drivers/lguest/lguest_user.c +++ b/drivers/lguest/lguest_user.c @@ -7,32 +7,83 @@ #include #include #include +#include +#include #include "lg.h" -/*L:055 When something happens, the Waker process needs a way to stop the - * kernel running the Guest and return to the Launcher. So the Waker writes - * LHREQ_BREAK and the value "1" to /dev/lguest to do this. Once the Launcher - * has done whatever needs attention, it writes LHREQ_BREAK and "0" to release - * the Waker. */ -static int break_guest_out(struct lg_cpu *cpu, const unsigned long __user*input) +bool send_notify_to_eventfd(struct lg_cpu *cpu) { - unsigned long on; + unsigned int i; + struct lg_eventfd_map *map; - /* Fetch whether they're turning break on or off. */ - if (get_user(on, input) != 0) + /* lg->eventfds is RCU-protected */ + rcu_read_lock(); + map = rcu_dereference(cpu->lg->eventfds); + for (i = 0; i < map->num; i++) { + if (map->map[i].addr == cpu->pending_notify) { + eventfd_signal(map->map[i].event, 1); + cpu->pending_notify = 0; + break; + } + } + rcu_read_unlock(); + return cpu->pending_notify == 0; +} + +static int add_eventfd(struct lguest *lg, unsigned long addr, int fd) +{ + struct lg_eventfd_map *new, *old = lg->eventfds; + + if (!addr) + return -EINVAL; + + /* Replace the old array with the new one, carefully: others can + * be accessing it at the same time */ + new = kmalloc(sizeof(*new) + sizeof(new->map[0]) * (old->num + 1), + GFP_KERNEL); + if (!new) + return -ENOMEM; + + /* First make identical copy. */ + memcpy(new->map, old->map, sizeof(old->map[0]) * old->num); + new->num = old->num; + + /* Now append new entry. */ + new->map[new->num].addr = addr; + new->map[new->num].event = eventfd_fget(fd); + if (IS_ERR(new->map[new->num].event)) { + kfree(new); + return PTR_ERR(new->map[new->num].event); + } + new->num++; + + /* Now put new one in place. */ + rcu_assign_pointer(lg->eventfds, new); + + /* We're not in a big hurry. Wait until noone's looking at old + * version, then delete it. */ + synchronize_rcu(); + kfree(old); + + return 0; +} + +static int attach_eventfd(struct lguest *lg, const unsigned long __user *input) +{ + unsigned long addr, fd; + int err; + + if (get_user(addr, input) != 0) + return -EFAULT; + input++; + if (get_user(fd, input) != 0) return -EFAULT; - if (on) { - cpu->break_out = 1; - /* Pop it out of the Guest (may be running on different CPU) */ - wake_up_process(cpu->tsk); - /* Wait for them to reset it */ - return wait_event_interruptible(cpu->break_wq, !cpu->break_out); - } else { - cpu->break_out = 0; - wake_up(&cpu->break_wq); - return 0; - } + mutex_lock(&lguest_lock); + err = add_eventfd(lg, addr, fd); + mutex_unlock(&lguest_lock); + + return 0; } /*L:050 Sending an interrupt is done by writing LHREQ_IRQ and an interrupt @@ -45,9 +96,8 @@ static int user_send_irq(struct lg_cpu *cpu, const unsigned long __user *input) return -EFAULT; if (irq >= LGUEST_IRQS) return -EINVAL; - /* Next time the Guest runs, the core code will see if it can deliver - * this interrupt. */ - set_bit(irq, cpu->irqs_pending); + + set_interrupt(cpu, irq); return 0; } @@ -126,9 +176,6 @@ static int lg_cpu_start(struct lg_cpu *cpu, unsigned id, unsigned long start_ip) * address. */ lguest_arch_setup_regs(cpu, start_ip); - /* Initialize the queue for the Waker to wait on */ - init_waitqueue_head(&cpu->break_wq); - /* We keep a pointer to the Launcher task (ie. current task) for when * other Guests want to wake this one (eg. console input). */ cpu->tsk = current; @@ -185,6 +232,13 @@ static int initialize(struct file *file, const unsigned long __user *input) goto unlock; } + lg->eventfds = kmalloc(sizeof(*lg->eventfds), GFP_KERNEL); + if (!lg->eventfds) { + err = -ENOMEM; + goto free_lg; + } + lg->eventfds->num = 0; + /* Populate the easy fields of our "struct lguest" */ lg->mem_base = (void __user *)args[0]; lg->pfn_limit = args[1]; @@ -192,7 +246,7 @@ static int initialize(struct file *file, const unsigned long __user *input) /* This is the first cpu (cpu 0) and it will start booting at args[2] */ err = lg_cpu_start(&lg->cpus[0], 0, args[2]); if (err) - goto release_guest; + goto free_eventfds; /* Initialize the Guest's shadow page tables, using the toplevel * address the Launcher gave us. This allocates memory, so can fail. */ @@ -211,7 +265,9 @@ static int initialize(struct file *file, const unsigned long __user *input) free_regs: /* FIXME: This should be in free_vcpu */ free_page(lg->cpus[0].regs_page); -release_guest: +free_eventfds: + kfree(lg->eventfds); +free_lg: kfree(lg); unlock: mutex_unlock(&lguest_lock); @@ -252,11 +308,6 @@ static ssize_t write(struct file *file, const char __user *in, /* Once the Guest is dead, you can only read() why it died. */ if (lg->dead) return -ENOENT; - - /* If you're not the task which owns the Guest, all you can do - * is break the Launcher out of running the Guest. */ - if (current != cpu->tsk && req != LHREQ_BREAK) - return -EPERM; } switch (req) { @@ -264,8 +315,8 @@ static ssize_t write(struct file *file, const char __user *in, return initialize(file, input); case LHREQ_IRQ: return user_send_irq(cpu, input); - case LHREQ_BREAK: - return break_guest_out(cpu, input); + case LHREQ_EVENTFD: + return attach_eventfd(lg, input); default: return -EINVAL; } @@ -303,6 +354,12 @@ static int close(struct inode *inode, struct file *file) * the Launcher's memory management structure. */ mmput(lg->cpus[i].mm); } + + /* Release any eventfds they registered. */ + for (i = 0; i < lg->eventfds->num; i++) + fput(lg->eventfds->map[i].event); + kfree(lg->eventfds); + /* If lg->dead doesn't contain an error code it will be NULL or a * kmalloc()ed string, either of which is ok to hand to kfree(). */ if (!IS_ERR(lg->dead)) diff --git a/drivers/lguest/page_tables.c b/drivers/lguest/page_tables.c index a059cf9980f7..a6fe1abda240 100644 --- a/drivers/lguest/page_tables.c +++ b/drivers/lguest/page_tables.c @@ -53,6 +53,17 @@ * page. */ #define SWITCHER_PGD_INDEX (PTRS_PER_PGD - 1) +/* For PAE we need the PMD index as well. We use the last 2MB, so we + * will need the last pmd entry of the last pmd page. */ +#ifdef CONFIG_X86_PAE +#define SWITCHER_PMD_INDEX (PTRS_PER_PMD - 1) +#define RESERVE_MEM 2U +#define CHECK_GPGD_MASK _PAGE_PRESENT +#else +#define RESERVE_MEM 4U +#define CHECK_GPGD_MASK _PAGE_TABLE +#endif + /* We actually need a separate PTE page for each CPU. Remember that after the * Switcher code itself comes two pages for each CPU, and we don't want this * CPU's guest to see the pages of any other CPU. */ @@ -73,24 +84,59 @@ static pgd_t *spgd_addr(struct lg_cpu *cpu, u32 i, unsigned long vaddr) { unsigned int index = pgd_index(vaddr); +#ifndef CONFIG_X86_PAE /* We kill any Guest trying to touch the Switcher addresses. */ if (index >= SWITCHER_PGD_INDEX) { kill_guest(cpu, "attempt to access switcher pages"); index = 0; } +#endif /* Return a pointer index'th pgd entry for the i'th page table. */ return &cpu->lg->pgdirs[i].pgdir[index]; } +#ifdef CONFIG_X86_PAE +/* This routine then takes the PGD entry given above, which contains the + * address of the PMD page. It then returns a pointer to the PMD entry for the + * given address. */ +static pmd_t *spmd_addr(struct lg_cpu *cpu, pgd_t spgd, unsigned long vaddr) +{ + unsigned int index = pmd_index(vaddr); + pmd_t *page; + + /* We kill any Guest trying to touch the Switcher addresses. */ + if (pgd_index(vaddr) == SWITCHER_PGD_INDEX && + index >= SWITCHER_PMD_INDEX) { + kill_guest(cpu, "attempt to access switcher pages"); + index = 0; + } + + /* You should never call this if the PGD entry wasn't valid */ + BUG_ON(!(pgd_flags(spgd) & _PAGE_PRESENT)); + page = __va(pgd_pfn(spgd) << PAGE_SHIFT); + + return &page[index]; +} +#endif + /* This routine then takes the page directory entry returned above, which * contains the address of the page table entry (PTE) page. It then returns a * pointer to the PTE entry for the given address. */ -static pte_t *spte_addr(pgd_t spgd, unsigned long vaddr) +static pte_t *spte_addr(struct lg_cpu *cpu, pgd_t spgd, unsigned long vaddr) { +#ifdef CONFIG_X86_PAE + pmd_t *pmd = spmd_addr(cpu, spgd, vaddr); + pte_t *page = __va(pmd_pfn(*pmd) << PAGE_SHIFT); + + /* You should never call this if the PMD entry wasn't valid */ + BUG_ON(!(pmd_flags(*pmd) & _PAGE_PRESENT)); +#else pte_t *page = __va(pgd_pfn(spgd) << PAGE_SHIFT); /* You should never call this if the PGD entry wasn't valid */ BUG_ON(!(pgd_flags(spgd) & _PAGE_PRESENT)); - return &page[(vaddr >> PAGE_SHIFT) % PTRS_PER_PTE]; +#endif + + return &page[pte_index(vaddr)]; } /* These two functions just like the above two, except they access the Guest @@ -101,12 +147,32 @@ static unsigned long gpgd_addr(struct lg_cpu *cpu, unsigned long vaddr) return cpu->lg->pgdirs[cpu->cpu_pgd].gpgdir + index * sizeof(pgd_t); } -static unsigned long gpte_addr(pgd_t gpgd, unsigned long vaddr) +#ifdef CONFIG_X86_PAE +static unsigned long gpmd_addr(pgd_t gpgd, unsigned long vaddr) { unsigned long gpage = pgd_pfn(gpgd) << PAGE_SHIFT; BUG_ON(!(pgd_flags(gpgd) & _PAGE_PRESENT)); - return gpage + ((vaddr>>PAGE_SHIFT) % PTRS_PER_PTE) * sizeof(pte_t); + return gpage + pmd_index(vaddr) * sizeof(pmd_t); } + +static unsigned long gpte_addr(struct lg_cpu *cpu, + pmd_t gpmd, unsigned long vaddr) +{ + unsigned long gpage = pmd_pfn(gpmd) << PAGE_SHIFT; + + BUG_ON(!(pmd_flags(gpmd) & _PAGE_PRESENT)); + return gpage + pte_index(vaddr) * sizeof(pte_t); +} +#else +static unsigned long gpte_addr(struct lg_cpu *cpu, + pgd_t gpgd, unsigned long vaddr) +{ + unsigned long gpage = pgd_pfn(gpgd) << PAGE_SHIFT; + + BUG_ON(!(pgd_flags(gpgd) & _PAGE_PRESENT)); + return gpage + pte_index(vaddr) * sizeof(pte_t); +} +#endif /*:*/ /*M:014 get_pfn is slow: we could probably try to grab batches of pages here as @@ -171,7 +237,7 @@ static void release_pte(pte_t pte) /* Remember that get_user_pages_fast() took a reference to the page, in * get_pfn()? We have to put it back now. */ if (pte_flags(pte) & _PAGE_PRESENT) - put_page(pfn_to_page(pte_pfn(pte))); + put_page(pte_page(pte)); } /*:*/ @@ -184,11 +250,20 @@ static void check_gpte(struct lg_cpu *cpu, pte_t gpte) static void check_gpgd(struct lg_cpu *cpu, pgd_t gpgd) { - if ((pgd_flags(gpgd) & ~_PAGE_TABLE) || + if ((pgd_flags(gpgd) & ~CHECK_GPGD_MASK) || (pgd_pfn(gpgd) >= cpu->lg->pfn_limit)) kill_guest(cpu, "bad page directory entry"); } +#ifdef CONFIG_X86_PAE +static void check_gpmd(struct lg_cpu *cpu, pmd_t gpmd) +{ + if ((pmd_flags(gpmd) & ~_PAGE_TABLE) || + (pmd_pfn(gpmd) >= cpu->lg->pfn_limit)) + kill_guest(cpu, "bad page middle directory entry"); +} +#endif + /*H:330 * (i) Looking up a page table entry when the Guest faults. * @@ -207,6 +282,11 @@ bool demand_page(struct lg_cpu *cpu, unsigned long vaddr, int errcode) pte_t gpte; pte_t *spte; +#ifdef CONFIG_X86_PAE + pmd_t *spmd; + pmd_t gpmd; +#endif + /* First step: get the top-level Guest page table entry. */ gpgd = lgread(cpu, gpgd_addr(cpu, vaddr), pgd_t); /* Toplevel not present? We can't map it in. */ @@ -228,12 +308,45 @@ bool demand_page(struct lg_cpu *cpu, unsigned long vaddr, int errcode) check_gpgd(cpu, gpgd); /* And we copy the flags to the shadow PGD entry. The page * number in the shadow PGD is the page we just allocated. */ - *spgd = __pgd(__pa(ptepage) | pgd_flags(gpgd)); + set_pgd(spgd, __pgd(__pa(ptepage) | pgd_flags(gpgd))); + } + +#ifdef CONFIG_X86_PAE + gpmd = lgread(cpu, gpmd_addr(gpgd, vaddr), pmd_t); + /* middle level not present? We can't map it in. */ + if (!(pmd_flags(gpmd) & _PAGE_PRESENT)) + return false; + + /* Now look at the matching shadow entry. */ + spmd = spmd_addr(cpu, *spgd, vaddr); + + if (!(pmd_flags(*spmd) & _PAGE_PRESENT)) { + /* No shadow entry: allocate a new shadow PTE page. */ + unsigned long ptepage = get_zeroed_page(GFP_KERNEL); + + /* This is not really the Guest's fault, but killing it is + * simple for this corner case. */ + if (!ptepage) { + kill_guest(cpu, "out of memory allocating pte page"); + return false; + } + + /* We check that the Guest pmd is OK. */ + check_gpmd(cpu, gpmd); + + /* And we copy the flags to the shadow PMD entry. The page + * number in the shadow PMD is the page we just allocated. */ + native_set_pmd(spmd, __pmd(__pa(ptepage) | pmd_flags(gpmd))); } /* OK, now we look at the lower level in the Guest page table: keep its * address, because we might update it later. */ - gpte_ptr = gpte_addr(gpgd, vaddr); + gpte_ptr = gpte_addr(cpu, gpmd, vaddr); +#else + /* OK, now we look at the lower level in the Guest page table: keep its + * address, because we might update it later. */ + gpte_ptr = gpte_addr(cpu, gpgd, vaddr); +#endif gpte = lgread(cpu, gpte_ptr, pte_t); /* If this page isn't in the Guest page tables, we can't page it in. */ @@ -259,7 +372,7 @@ bool demand_page(struct lg_cpu *cpu, unsigned long vaddr, int errcode) gpte = pte_mkdirty(gpte); /* Get the pointer to the shadow PTE entry we're going to set. */ - spte = spte_addr(*spgd, vaddr); + spte = spte_addr(cpu, *spgd, vaddr); /* If there was a valid shadow PTE entry here before, we release it. * This can happen with a write to a previously read-only entry. */ release_pte(*spte); @@ -273,7 +386,7 @@ bool demand_page(struct lg_cpu *cpu, unsigned long vaddr, int errcode) * table entry, even if the Guest says it's writable. That way * we will come back here when a write does actually occur, so * we can update the Guest's _PAGE_DIRTY flag. */ - *spte = gpte_to_spte(cpu, pte_wrprotect(gpte), 0); + native_set_pte(spte, gpte_to_spte(cpu, pte_wrprotect(gpte), 0)); /* Finally, we write the Guest PTE entry back: we've set the * _PAGE_ACCESSED and maybe the _PAGE_DIRTY flags. */ @@ -301,14 +414,23 @@ static bool page_writable(struct lg_cpu *cpu, unsigned long vaddr) pgd_t *spgd; unsigned long flags; +#ifdef CONFIG_X86_PAE + pmd_t *spmd; +#endif /* Look at the current top level entry: is it present? */ spgd = spgd_addr(cpu, cpu->cpu_pgd, vaddr); if (!(pgd_flags(*spgd) & _PAGE_PRESENT)) return false; +#ifdef CONFIG_X86_PAE + spmd = spmd_addr(cpu, *spgd, vaddr); + if (!(pmd_flags(*spmd) & _PAGE_PRESENT)) + return false; +#endif + /* Check the flags on the pte entry itself: it must be present and * writable. */ - flags = pte_flags(*(spte_addr(*spgd, vaddr))); + flags = pte_flags(*(spte_addr(cpu, *spgd, vaddr))); return (flags & (_PAGE_PRESENT|_PAGE_RW)) == (_PAGE_PRESENT|_PAGE_RW); } @@ -322,8 +444,43 @@ void pin_page(struct lg_cpu *cpu, unsigned long vaddr) kill_guest(cpu, "bad stack page %#lx", vaddr); } +#ifdef CONFIG_X86_PAE +static void release_pmd(pmd_t *spmd) +{ + /* If the entry's not present, there's nothing to release. */ + if (pmd_flags(*spmd) & _PAGE_PRESENT) { + unsigned int i; + pte_t *ptepage = __va(pmd_pfn(*spmd) << PAGE_SHIFT); + /* For each entry in the page, we might need to release it. */ + for (i = 0; i < PTRS_PER_PTE; i++) + release_pte(ptepage[i]); + /* Now we can free the page of PTEs */ + free_page((long)ptepage); + /* And zero out the PMD entry so we never release it twice. */ + native_set_pmd(spmd, __pmd(0)); + } +} + +static void release_pgd(pgd_t *spgd) +{ + /* If the entry's not present, there's nothing to release. */ + if (pgd_flags(*spgd) & _PAGE_PRESENT) { + unsigned int i; + pmd_t *pmdpage = __va(pgd_pfn(*spgd) << PAGE_SHIFT); + + for (i = 0; i < PTRS_PER_PMD; i++) + release_pmd(&pmdpage[i]); + + /* Now we can free the page of PMDs */ + free_page((long)pmdpage); + /* And zero out the PGD entry so we never release it twice. */ + set_pgd(spgd, __pgd(0)); + } +} + +#else /* !CONFIG_X86_PAE */ /*H:450 If we chase down the release_pgd() code, it looks like this: */ -static void release_pgd(struct lguest *lg, pgd_t *spgd) +static void release_pgd(pgd_t *spgd) { /* If the entry's not present, there's nothing to release. */ if (pgd_flags(*spgd) & _PAGE_PRESENT) { @@ -341,7 +498,7 @@ static void release_pgd(struct lguest *lg, pgd_t *spgd) *spgd = __pgd(0); } } - +#endif /*H:445 We saw flush_user_mappings() twice: once from the flush_user_mappings() * hypercall and once in new_pgdir() when we re-used a top-level pgdir page. * It simply releases every PTE page from 0 up to the Guest's kernel address. */ @@ -350,7 +507,7 @@ static void flush_user_mappings(struct lguest *lg, int idx) unsigned int i; /* Release every pgd entry up to the kernel's address. */ for (i = 0; i < pgd_index(lg->kernel_address); i++) - release_pgd(lg, lg->pgdirs[idx].pgdir + i); + release_pgd(lg->pgdirs[idx].pgdir + i); } /*H:440 (v) Flushing (throwing away) page tables, @@ -369,7 +526,9 @@ unsigned long guest_pa(struct lg_cpu *cpu, unsigned long vaddr) { pgd_t gpgd; pte_t gpte; - +#ifdef CONFIG_X86_PAE + pmd_t gpmd; +#endif /* First step: get the top-level Guest page table entry. */ gpgd = lgread(cpu, gpgd_addr(cpu, vaddr), pgd_t); /* Toplevel not present? We can't map it in. */ @@ -378,7 +537,14 @@ unsigned long guest_pa(struct lg_cpu *cpu, unsigned long vaddr) return -1UL; } - gpte = lgread(cpu, gpte_addr(gpgd, vaddr), pte_t); +#ifdef CONFIG_X86_PAE + gpmd = lgread(cpu, gpmd_addr(gpgd, vaddr), pmd_t); + if (!(pmd_flags(gpmd) & _PAGE_PRESENT)) + kill_guest(cpu, "Bad address %#lx", vaddr); + gpte = lgread(cpu, gpte_addr(cpu, gpmd, vaddr), pte_t); +#else + gpte = lgread(cpu, gpte_addr(cpu, gpgd, vaddr), pte_t); +#endif if (!(pte_flags(gpte) & _PAGE_PRESENT)) kill_guest(cpu, "Bad address %#lx", vaddr); @@ -405,6 +571,9 @@ static unsigned int new_pgdir(struct lg_cpu *cpu, int *blank_pgdir) { unsigned int next; +#ifdef CONFIG_X86_PAE + pmd_t *pmd_table; +#endif /* We pick one entry at random to throw out. Choosing the Least * Recently Used might be better, but this is easy. */ @@ -416,10 +585,27 @@ static unsigned int new_pgdir(struct lg_cpu *cpu, /* If the allocation fails, just keep using the one we have */ if (!cpu->lg->pgdirs[next].pgdir) next = cpu->cpu_pgd; - else - /* This is a blank page, so there are no kernel - * mappings: caller must map the stack! */ + else { +#ifdef CONFIG_X86_PAE + /* In PAE mode, allocate a pmd page and populate the + * last pgd entry. */ + pmd_table = (pmd_t *)get_zeroed_page(GFP_KERNEL); + if (!pmd_table) { + free_page((long)cpu->lg->pgdirs[next].pgdir); + set_pgd(cpu->lg->pgdirs[next].pgdir, __pgd(0)); + next = cpu->cpu_pgd; + } else { + set_pgd(cpu->lg->pgdirs[next].pgdir + + SWITCHER_PGD_INDEX, + __pgd(__pa(pmd_table) | _PAGE_PRESENT)); + /* This is a blank page, so there are no kernel + * mappings: caller must map the stack! */ + *blank_pgdir = 1; + } +#else *blank_pgdir = 1; +#endif + } } /* Record which Guest toplevel this shadows. */ cpu->lg->pgdirs[next].gpgdir = gpgdir; @@ -431,7 +617,7 @@ static unsigned int new_pgdir(struct lg_cpu *cpu, /*H:430 (iv) Switching page tables * - * Now we've seen all the page table setting and manipulation, let's see what + * Now we've seen all the page table setting and manipulation, let's see * what happens when the Guest changes page tables (ie. changes the top-level * pgdir). This occurs on almost every context switch. */ void guest_new_pagetable(struct lg_cpu *cpu, unsigned long pgtable) @@ -460,10 +646,25 @@ static void release_all_pagetables(struct lguest *lg) /* Every shadow pagetable this Guest has */ for (i = 0; i < ARRAY_SIZE(lg->pgdirs); i++) - if (lg->pgdirs[i].pgdir) + if (lg->pgdirs[i].pgdir) { +#ifdef CONFIG_X86_PAE + pgd_t *spgd; + pmd_t *pmdpage; + unsigned int k; + + /* Get the last pmd page. */ + spgd = lg->pgdirs[i].pgdir + SWITCHER_PGD_INDEX; + pmdpage = __va(pgd_pfn(*spgd) << PAGE_SHIFT); + + /* And release the pmd entries of that pmd page, + * except for the switcher pmd. */ + for (k = 0; k < SWITCHER_PMD_INDEX; k++) + release_pmd(&pmdpage[k]); +#endif /* Every PGD entry except the Switcher at the top */ for (j = 0; j < SWITCHER_PGD_INDEX; j++) - release_pgd(lg, lg->pgdirs[i].pgdir + j); + release_pgd(lg->pgdirs[i].pgdir + j); + } } /* We also throw away everything when a Guest tells us it's changed a kernel @@ -504,24 +705,37 @@ static void do_set_pte(struct lg_cpu *cpu, int idx, { /* Look up the matching shadow page directory entry. */ pgd_t *spgd = spgd_addr(cpu, idx, vaddr); +#ifdef CONFIG_X86_PAE + pmd_t *spmd; +#endif /* If the top level isn't present, there's no entry to update. */ if (pgd_flags(*spgd) & _PAGE_PRESENT) { - /* Otherwise, we start by releasing the existing entry. */ - pte_t *spte = spte_addr(*spgd, vaddr); - release_pte(*spte); +#ifdef CONFIG_X86_PAE + spmd = spmd_addr(cpu, *spgd, vaddr); + if (pmd_flags(*spmd) & _PAGE_PRESENT) { +#endif + /* Otherwise, we start by releasing + * the existing entry. */ + pte_t *spte = spte_addr(cpu, *spgd, vaddr); + release_pte(*spte); - /* If they're setting this entry as dirty or accessed, we might - * as well put that entry they've given us in now. This shaves - * 10% off a copy-on-write micro-benchmark. */ - if (pte_flags(gpte) & (_PAGE_DIRTY | _PAGE_ACCESSED)) { - check_gpte(cpu, gpte); - *spte = gpte_to_spte(cpu, gpte, - pte_flags(gpte) & _PAGE_DIRTY); - } else - /* Otherwise kill it and we can demand_page() it in - * later. */ - *spte = __pte(0); + /* If they're setting this entry as dirty or accessed, + * we might as well put that entry they've given us + * in now. This shaves 10% off a + * copy-on-write micro-benchmark. */ + if (pte_flags(gpte) & (_PAGE_DIRTY | _PAGE_ACCESSED)) { + check_gpte(cpu, gpte); + native_set_pte(spte, + gpte_to_spte(cpu, gpte, + pte_flags(gpte) & _PAGE_DIRTY)); + } else + /* Otherwise kill it and we can demand_page() + * it in later. */ + native_set_pte(spte, __pte(0)); +#ifdef CONFIG_X86_PAE + } +#endif } } @@ -568,12 +782,10 @@ void guest_set_pte(struct lg_cpu *cpu, * * So with that in mind here's our code to to update a (top-level) PGD entry: */ -void guest_set_pmd(struct lguest *lg, unsigned long gpgdir, u32 idx) +void guest_set_pgd(struct lguest *lg, unsigned long gpgdir, u32 idx) { int pgdir; - /* The kernel seems to try to initialize this early on: we ignore its - * attempts to map over the Switcher. */ if (idx >= SWITCHER_PGD_INDEX) return; @@ -581,8 +793,14 @@ void guest_set_pmd(struct lguest *lg, unsigned long gpgdir, u32 idx) pgdir = find_pgdir(lg, gpgdir); if (pgdir < ARRAY_SIZE(lg->pgdirs)) /* ... throw it away. */ - release_pgd(lg, lg->pgdirs[pgdir].pgdir + idx); + release_pgd(lg->pgdirs[pgdir].pgdir + idx); } +#ifdef CONFIG_X86_PAE +void guest_set_pmd(struct lguest *lg, unsigned long pmdp, u32 idx) +{ + guest_pagetable_clear_all(&lg->cpus[0]); +} +#endif /* Once we know how much memory we have we can construct simple identity * (which set virtual == physical) and linear mappings @@ -596,8 +814,16 @@ static unsigned long setup_pagetables(struct lguest *lg, { pgd_t __user *pgdir; pte_t __user *linear; - unsigned int mapped_pages, i, linear_pages, phys_linear; unsigned long mem_base = (unsigned long)lg->mem_base; + unsigned int mapped_pages, i, linear_pages; +#ifdef CONFIG_X86_PAE + pmd_t __user *pmds; + unsigned int j; + pgd_t pgd; + pmd_t pmd; +#else + unsigned int phys_linear; +#endif /* We have mapped_pages frames to map, so we need * linear_pages page tables to map them. */ @@ -610,6 +836,9 @@ static unsigned long setup_pagetables(struct lguest *lg, /* Now we use the next linear_pages pages as pte pages */ linear = (void *)pgdir - linear_pages * PAGE_SIZE; +#ifdef CONFIG_X86_PAE + pmds = (void *)linear - PAGE_SIZE; +#endif /* Linear mapping is easy: put every page's address into the * mapping in order. */ for (i = 0; i < mapped_pages; i++) { @@ -621,6 +850,22 @@ static unsigned long setup_pagetables(struct lguest *lg, /* The top level points to the linear page table pages above. * We setup the identity and linear mappings here. */ +#ifdef CONFIG_X86_PAE + for (i = j = 0; i < mapped_pages && j < PTRS_PER_PMD; + i += PTRS_PER_PTE, j++) { + native_set_pmd(&pmd, __pmd(((unsigned long)(linear + i) + - mem_base) | _PAGE_PRESENT | _PAGE_RW | _PAGE_USER)); + + if (copy_to_user(&pmds[j], &pmd, sizeof(pmd)) != 0) + return -EFAULT; + } + + set_pgd(&pgd, __pgd(((u32)pmds - mem_base) | _PAGE_PRESENT)); + if (copy_to_user(&pgdir[0], &pgd, sizeof(pgd)) != 0) + return -EFAULT; + if (copy_to_user(&pgdir[3], &pgd, sizeof(pgd)) != 0) + return -EFAULT; +#else phys_linear = (unsigned long)linear - mem_base; for (i = 0; i < mapped_pages; i += PTRS_PER_PTE) { pgd_t pgd; @@ -633,6 +878,7 @@ static unsigned long setup_pagetables(struct lguest *lg, &pgd, sizeof(pgd))) return -EFAULT; } +#endif /* We return the top level (guest-physical) address: remember where * this is. */ @@ -648,7 +894,10 @@ int init_guest_pagetable(struct lguest *lg) u64 mem; u32 initrd_size; struct boot_params __user *boot = (struct boot_params *)lg->mem_base; - +#ifdef CONFIG_X86_PAE + pgd_t *pgd; + pmd_t *pmd_table; +#endif /* Get the Guest memory size and the ramdisk size from the boot header * located at lg->mem_base (Guest address 0). */ if (copy_from_user(&mem, &boot->e820_map[0].size, sizeof(mem)) @@ -663,6 +912,15 @@ int init_guest_pagetable(struct lguest *lg) lg->pgdirs[0].pgdir = (pgd_t *)get_zeroed_page(GFP_KERNEL); if (!lg->pgdirs[0].pgdir) return -ENOMEM; +#ifdef CONFIG_X86_PAE + pgd = lg->pgdirs[0].pgdir; + pmd_table = (pmd_t *) get_zeroed_page(GFP_KERNEL); + if (!pmd_table) + return -ENOMEM; + + set_pgd(pgd + SWITCHER_PGD_INDEX, + __pgd(__pa(pmd_table) | _PAGE_PRESENT)); +#endif lg->cpus[0].cpu_pgd = 0; return 0; } @@ -672,17 +930,24 @@ void page_table_guest_data_init(struct lg_cpu *cpu) { /* We get the kernel address: above this is all kernel memory. */ if (get_user(cpu->lg->kernel_address, - &cpu->lg->lguest_data->kernel_address) - /* We tell the Guest that it can't use the top 4MB of virtual - * addresses used by the Switcher. */ - || put_user(4U*1024*1024, &cpu->lg->lguest_data->reserve_mem) - || put_user(cpu->lg->pgdirs[0].gpgdir, &cpu->lg->lguest_data->pgdir)) + &cpu->lg->lguest_data->kernel_address) + /* We tell the Guest that it can't use the top 2 or 4 MB + * of virtual addresses used by the Switcher. */ + || put_user(RESERVE_MEM * 1024 * 1024, + &cpu->lg->lguest_data->reserve_mem) + || put_user(cpu->lg->pgdirs[0].gpgdir, + &cpu->lg->lguest_data->pgdir)) kill_guest(cpu, "bad guest page %p", cpu->lg->lguest_data); /* In flush_user_mappings() we loop from 0 to * "pgd_index(lg->kernel_address)". This assumes it won't hit the * Switcher mappings, so check that now. */ +#ifdef CONFIG_X86_PAE + if (pgd_index(cpu->lg->kernel_address) == SWITCHER_PGD_INDEX && + pmd_index(cpu->lg->kernel_address) == SWITCHER_PMD_INDEX) +#else if (pgd_index(cpu->lg->kernel_address) >= SWITCHER_PGD_INDEX) +#endif kill_guest(cpu, "bad kernel address %#lx", cpu->lg->kernel_address); } @@ -708,16 +973,30 @@ void free_guest_pagetable(struct lguest *lg) void map_switcher_in_guest(struct lg_cpu *cpu, struct lguest_pages *pages) { pte_t *switcher_pte_page = __get_cpu_var(switcher_pte_pages); - pgd_t switcher_pgd; pte_t regs_pte; unsigned long pfn; +#ifdef CONFIG_X86_PAE + pmd_t switcher_pmd; + pmd_t *pmd_table; + + native_set_pmd(&switcher_pmd, pfn_pmd(__pa(switcher_pte_page) >> + PAGE_SHIFT, PAGE_KERNEL_EXEC)); + + pmd_table = __va(pgd_pfn(cpu->lg-> + pgdirs[cpu->cpu_pgd].pgdir[SWITCHER_PGD_INDEX]) + << PAGE_SHIFT); + native_set_pmd(&pmd_table[SWITCHER_PMD_INDEX], switcher_pmd); +#else + pgd_t switcher_pgd; + /* Make the last PGD entry for this Guest point to the Switcher's PTE * page for this CPU (with appropriate flags). */ - switcher_pgd = __pgd(__pa(switcher_pte_page) | __PAGE_KERNEL); + switcher_pgd = __pgd(__pa(switcher_pte_page) | __PAGE_KERNEL_EXEC); cpu->lg->pgdirs[cpu->cpu_pgd].pgdir[SWITCHER_PGD_INDEX] = switcher_pgd; +#endif /* We also change the Switcher PTE page. When we're running the Guest, * we want the Guest's "regs" page to appear where the first Switcher * page for this CPU is. This is an optimization: when the Switcher @@ -726,8 +1005,9 @@ void map_switcher_in_guest(struct lg_cpu *cpu, struct lguest_pages *pages) * page is already mapped there, we don't have to copy them out * again. */ pfn = __pa(cpu->regs_page) >> PAGE_SHIFT; - regs_pte = pfn_pte(pfn, __pgprot(__PAGE_KERNEL)); - switcher_pte_page[(unsigned long)pages/PAGE_SIZE%PTRS_PER_PTE] = regs_pte; + native_set_pte(®s_pte, pfn_pte(pfn, PAGE_KERNEL)); + native_set_pte(&switcher_pte_page[pte_index((unsigned long)pages)], + regs_pte); } /*:*/ @@ -752,21 +1032,21 @@ static __init void populate_switcher_pte_page(unsigned int cpu, /* The first entries are easy: they map the Switcher code. */ for (i = 0; i < pages; i++) { - pte[i] = mk_pte(switcher_page[i], - __pgprot(_PAGE_PRESENT|_PAGE_ACCESSED)); + native_set_pte(&pte[i], mk_pte(switcher_page[i], + __pgprot(_PAGE_PRESENT|_PAGE_ACCESSED))); } /* The only other thing we map is this CPU's pair of pages. */ i = pages + cpu*2; /* First page (Guest registers) is writable from the Guest */ - pte[i] = pfn_pte(page_to_pfn(switcher_page[i]), - __pgprot(_PAGE_PRESENT|_PAGE_ACCESSED|_PAGE_RW)); + native_set_pte(&pte[i], pfn_pte(page_to_pfn(switcher_page[i]), + __pgprot(_PAGE_PRESENT|_PAGE_ACCESSED|_PAGE_RW))); /* The second page contains the "struct lguest_ro_state", and is * read-only. */ - pte[i+1] = pfn_pte(page_to_pfn(switcher_page[i+1]), - __pgprot(_PAGE_PRESENT|_PAGE_ACCESSED)); + native_set_pte(&pte[i+1], pfn_pte(page_to_pfn(switcher_page[i+1]), + __pgprot(_PAGE_PRESENT|_PAGE_ACCESSED))); } /* We've made it through the page table code. Perhaps our tired brains are diff --git a/drivers/lguest/segments.c b/drivers/lguest/segments.c index 7ede64ffeef9..482ed5a18750 100644 --- a/drivers/lguest/segments.c +++ b/drivers/lguest/segments.c @@ -150,7 +150,7 @@ void load_guest_gdt_entry(struct lg_cpu *cpu, u32 num, u32 lo, u32 hi) { /* We assume the Guest has the same number of GDT entries as the * Host, otherwise we'd have to dynamically allocate the Guest GDT. */ - if (num > ARRAY_SIZE(cpu->arch.gdt)) + if (num >= ARRAY_SIZE(cpu->arch.gdt)) kill_guest(cpu, "too many gdt entries %i", num); /* Set it up, then fix it. */ diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c index c0621d50c8a0..fde377c60cca 100644 --- a/drivers/macintosh/therm_adt746x.c +++ b/drivers/macintosh/therm_adt746x.c @@ -37,6 +37,7 @@ #define CONFIG_REG 0x40 #define MANUAL_MASK 0xe0 #define AUTO_MASK 0x20 +#define INVERT_MASK 0x10 static u8 TEMP_REG[3] = {0x26, 0x25, 0x27}; /* local, sensor1, sensor2 */ static u8 LIMIT_REG[3] = {0x6b, 0x6a, 0x6c}; /* local, sensor1, sensor2 */ @@ -71,7 +72,7 @@ MODULE_PARM_DESC(verbose,"Verbose log operations " "(default 0)"); struct thermostat { - struct i2c_client clt; + struct i2c_client *clt; u8 temps[3]; u8 cached_temp[3]; u8 initial_limits[3]; @@ -86,9 +87,6 @@ static struct of_device * of_dev; static struct thermostat* thermostat; static struct task_struct *thread_therm = NULL; -static int attach_one_thermostat(struct i2c_adapter *adapter, int addr, - int busno); - static void write_both_fan_speed(struct thermostat *th, int speed); static void write_fan_speed(struct thermostat *th, int speed, int fan); @@ -100,7 +98,7 @@ write_reg(struct thermostat* th, int reg, u8 data) tmp[0] = reg; tmp[1] = data; - rc = i2c_master_send(&th->clt, (const char *)tmp, 2); + rc = i2c_master_send(th->clt, (const char *)tmp, 2); if (rc < 0) return rc; if (rc != 2) @@ -115,12 +113,12 @@ read_reg(struct thermostat* th, int reg) int rc; reg_addr = (u8)reg; - rc = i2c_master_send(&th->clt, ®_addr, 1); + rc = i2c_master_send(th->clt, ®_addr, 1); if (rc < 0) return rc; if (rc != 1) return -ENODEV; - rc = i2c_master_recv(&th->clt, (char *)&data, 1); + rc = i2c_master_recv(th->clt, (char *)&data, 1); if (rc < 0) return rc; return data; @@ -130,26 +128,36 @@ static int attach_thermostat(struct i2c_adapter *adapter) { unsigned long bus_no; + struct i2c_board_info info; + struct i2c_client *client; if (strncmp(adapter->name, "uni-n", 5)) return -ENODEV; bus_no = simple_strtoul(adapter->name + 6, NULL, 10); if (bus_no != therm_bus) return -ENODEV; - return attach_one_thermostat(adapter, therm_address, bus_no); + + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "therm_adt746x", I2C_NAME_SIZE); + info.addr = therm_address; + client = i2c_new_device(adapter, &info); + if (!client) + return -ENODEV; + + /* + * Let i2c-core delete that device on driver removal. + * This is safe because i2c-core holds the core_lock mutex for us. + */ + list_add_tail(&client->detected, &client->driver->clients); + return 0; } static int -detach_thermostat(struct i2c_adapter *adapter) +remove_thermostat(struct i2c_client *client) { - struct thermostat* th; + struct thermostat *th = i2c_get_clientdata(client); int i; - if (thermostat == NULL) - return 0; - - th = thermostat; - if (thread_therm != NULL) { kthread_stop(thread_therm); } @@ -165,8 +173,6 @@ detach_thermostat(struct i2c_adapter *adapter) write_both_fan_speed(th, -1); - i2c_detach_client(&th->clt); - thermostat = NULL; kfree(th); @@ -174,14 +180,6 @@ detach_thermostat(struct i2c_adapter *adapter) return 0; } -static struct i2c_driver thermostat_driver = { - .driver = { - .name = "therm_adt746x", - }, - .attach_adapter = attach_thermostat, - .detach_adapter = detach_thermostat, -}; - static int read_fan_speed(struct thermostat *th, u8 addr) { u8 tmp[2]; @@ -229,7 +227,8 @@ static void write_fan_speed(struct thermostat *th, int speed, int fan) if (speed >= 0) { manual = read_reg(th, MANUAL_MODE[fan]); - write_reg(th, MANUAL_MODE[fan], manual|MANUAL_MASK); + write_reg(th, MANUAL_MODE[fan], + (manual|MANUAL_MASK) & (~INVERT_MASK)); write_reg(th, FAN_SPD_SET[fan], speed); } else { /* back to automatic */ @@ -369,8 +368,8 @@ static void set_limit(struct thermostat *th, int i) th->limits[i] = default_limits_local[i] + limit_adjust; } -static int attach_one_thermostat(struct i2c_adapter *adapter, int addr, - int busno) +static int probe_thermostat(struct i2c_client *client, + const struct i2c_device_id *id) { struct thermostat* th; int rc; @@ -383,16 +382,12 @@ static int attach_one_thermostat(struct i2c_adapter *adapter, int addr, if (!th) return -ENOMEM; - th->clt.addr = addr; - th->clt.adapter = adapter; - th->clt.driver = &thermostat_driver; - strcpy(th->clt.name, "thermostat"); + i2c_set_clientdata(client, th); + th->clt = client; rc = read_reg(th, 0); if (rc < 0) { - printk(KERN_ERR "adt746x: Thermostat failed to read config " - "from bus %d !\n", - busno); + dev_err(&client->dev, "Thermostat failed to read config!\n"); kfree(th); return -ENODEV; } @@ -421,14 +416,6 @@ static int attach_one_thermostat(struct i2c_adapter *adapter, int addr, thermostat = th; - if (i2c_attach_client(&th->clt)) { - printk(KERN_INFO "adt746x: Thermostat failed to attach " - "client !\n"); - thermostat = NULL; - kfree(th); - return -ENODEV; - } - /* be sure to really write fan speed the first time */ th->last_speed[0] = -2; th->last_speed[1] = -2; @@ -454,6 +441,21 @@ static int attach_one_thermostat(struct i2c_adapter *adapter, int addr, return 0; } +static const struct i2c_device_id therm_adt746x_id[] = { + { "therm_adt746x", 0 }, + { } +}; + +static struct i2c_driver thermostat_driver = { + .driver = { + .name = "therm_adt746x", + }, + .attach_adapter = attach_thermostat, + .probe = probe_thermostat, + .remove = remove_thermostat, + .id_table = therm_adt746x_id, +}; + /* * Now, unfortunately, sysfs doesn't give us a nice void * we could * pass around to the attribute functions, so we don't really have diff --git a/drivers/macintosh/therm_pm72.c b/drivers/macintosh/therm_pm72.c index 817607e2af6a..a028598af2d3 100644 --- a/drivers/macintosh/therm_pm72.c +++ b/drivers/macintosh/therm_pm72.c @@ -286,22 +286,6 @@ struct fcu_fan_table fcu_fans[] = { }, }; -/* - * i2c_driver structure to attach to the host i2c controller - */ - -static int therm_pm72_attach(struct i2c_adapter *adapter); -static int therm_pm72_detach(struct i2c_adapter *adapter); - -static struct i2c_driver therm_pm72_driver = -{ - .driver = { - .name = "therm_pm72", - }, - .attach_adapter = therm_pm72_attach, - .detach_adapter = therm_pm72_detach, -}; - /* * Utility function to create an i2c_client structure and * attach it to one of u3 adapters @@ -310,6 +294,7 @@ static struct i2c_client *attach_i2c_chip(int id, const char *name) { struct i2c_client *clt; struct i2c_adapter *adap; + struct i2c_board_info info; if (id & 0x200) adap = k2; @@ -320,31 +305,21 @@ static struct i2c_client *attach_i2c_chip(int id, const char *name) if (adap == NULL) return NULL; - clt = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (clt == NULL) - return NULL; - - clt->addr = (id >> 1) & 0x7f; - clt->adapter = adap; - clt->driver = &therm_pm72_driver; - strncpy(clt->name, name, I2C_NAME_SIZE-1); - - if (i2c_attach_client(clt)) { + memset(&info, 0, sizeof(struct i2c_board_info)); + info.addr = (id >> 1) & 0x7f; + strlcpy(info.type, "therm_pm72", I2C_NAME_SIZE); + clt = i2c_new_device(adap, &info); + if (!clt) { printk(KERN_ERR "therm_pm72: Failed to attach to i2c ID 0x%x\n", id); - kfree(clt); return NULL; } - return clt; -} -/* - * Utility function to get rid of the i2c_client structure - * (will also detach from the adapter hopepfully) - */ -static void detach_i2c_chip(struct i2c_client *clt) -{ - i2c_detach_client(clt); - kfree(clt); + /* + * Let i2c-core delete that device on driver removal. + * This is safe because i2c-core holds the core_lock mutex for us. + */ + list_add_tail(&clt->detected, &clt->driver->clients); + return clt; } /* @@ -1203,8 +1178,6 @@ static int init_cpu_state(struct cpu_pid_state *state, int index) return 0; fail: - if (state->monitor) - detach_i2c_chip(state->monitor); state->monitor = NULL; return -ENODEV; @@ -1232,7 +1205,6 @@ static void dispose_cpu_state(struct cpu_pid_state *state) device_remove_file(&of_dev->dev, &dev_attr_cpu1_intake_fan_rpm); } - detach_i2c_chip(state->monitor); state->monitor = NULL; } @@ -1407,7 +1379,6 @@ static void dispose_backside_state(struct backside_pid_state *state) device_remove_file(&of_dev->dev, &dev_attr_backside_temperature); device_remove_file(&of_dev->dev, &dev_attr_backside_fan_pwm); - detach_i2c_chip(state->monitor); state->monitor = NULL; } @@ -1532,7 +1503,6 @@ static void dispose_drives_state(struct drives_pid_state *state) device_remove_file(&of_dev->dev, &dev_attr_drives_temperature); device_remove_file(&of_dev->dev, &dev_attr_drives_fan_rpm); - detach_i2c_chip(state->monitor); state->monitor = NULL; } @@ -1654,7 +1624,6 @@ static void dispose_dimms_state(struct dimm_pid_state *state) device_remove_file(&of_dev->dev, &dev_attr_dimms_temperature); - detach_i2c_chip(state->monitor); state->monitor = NULL; } @@ -1779,7 +1748,6 @@ static void dispose_slots_state(struct slots_pid_state *state) device_remove_file(&of_dev->dev, &dev_attr_slots_temperature); device_remove_file(&of_dev->dev, &dev_attr_slots_fan_pwm); - detach_i2c_chip(state->monitor); state->monitor = NULL; } @@ -2008,8 +1976,6 @@ static int attach_fcu(void) */ static void detach_fcu(void) { - if (fcu) - detach_i2c_chip(fcu); fcu = NULL; } @@ -2060,12 +2026,21 @@ static int therm_pm72_attach(struct i2c_adapter *adapter) return 0; } +static int therm_pm72_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + /* Always succeed, the real work was done in therm_pm72_attach() */ + return 0; +} + /* - * Called on every adapter when the driver or the i2c controller + * Called when any of the devices which participates into thermal management * is going away. */ -static int therm_pm72_detach(struct i2c_adapter *adapter) +static int therm_pm72_remove(struct i2c_client *client) { + struct i2c_adapter *adapter = client->adapter; + mutex_lock(&driver_lock); if (state != state_detached) @@ -2096,6 +2071,30 @@ static int therm_pm72_detach(struct i2c_adapter *adapter) return 0; } +/* + * i2c_driver structure to attach to the host i2c controller + */ + +static const struct i2c_device_id therm_pm72_id[] = { + /* + * Fake device name, thermal management is done by several + * chips but we don't need to differentiate between them at + * this point. + */ + { "therm_pm72", 0 }, + { } +}; + +static struct i2c_driver therm_pm72_driver = { + .driver = { + .name = "therm_pm72", + }, + .attach_adapter = therm_pm72_attach, + .probe = therm_pm72_probe, + .remove = therm_pm72_remove, + .id_table = therm_pm72_id, +}; + static int fan_check_loc_match(const char *loc, int fan) { char tmp[64]; diff --git a/drivers/macintosh/therm_windtunnel.c b/drivers/macintosh/therm_windtunnel.c index 3da0a02efd76..40023313a760 100644 --- a/drivers/macintosh/therm_windtunnel.c +++ b/drivers/macintosh/therm_windtunnel.c @@ -48,16 +48,6 @@ #define LOG_TEMP 0 /* continously log temperature */ -static int do_probe( struct i2c_adapter *adapter, int addr, int kind); - -/* scan 0x48-0x4f (DS1775) and 0x2c-2x2f (ADM1030) */ -static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, - 0x4c, 0x4d, 0x4e, 0x4f, - 0x2c, 0x2d, 0x2e, 0x2f, - I2C_CLIENT_END }; - -I2C_CLIENT_INSMOD; - static struct { volatile int running; struct task_struct *poll_task; @@ -315,53 +305,54 @@ static int control_loop(void *dummy) static int do_attach( struct i2c_adapter *adapter ) { - int ret = 0; + /* scan 0x48-0x4f (DS1775) and 0x2c-2x2f (ADM1030) */ + static const unsigned short scan_ds1775[] = { + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + I2C_CLIENT_END + }; + static const unsigned short scan_adm1030[] = { + 0x2c, 0x2d, 0x2e, 0x2f, + I2C_CLIENT_END + }; if( strncmp(adapter->name, "uni-n", 5) ) return 0; if( !x.running ) { - ret = i2c_probe( adapter, &addr_data, &do_probe ); + struct i2c_board_info info; + + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "therm_ds1775", I2C_NAME_SIZE); + i2c_new_probed_device(adapter, &info, scan_ds1775); + + strlcpy(info.type, "therm_adm1030", I2C_NAME_SIZE); + i2c_new_probed_device(adapter, &info, scan_adm1030); + if( x.thermostat && x.fan ) { x.running = 1; x.poll_task = kthread_run(control_loop, NULL, "g4fand"); } } - return ret; + return 0; } static int -do_detach( struct i2c_client *client ) +do_remove(struct i2c_client *client) { - int err; - - if( (err=i2c_detach_client(client)) ) - printk(KERN_ERR "failed to detach thermostat client\n"); - else { - if( x.running ) { - x.running = 0; - kthread_stop(x.poll_task); - x.poll_task = NULL; - } - if( client == x.thermostat ) - x.thermostat = NULL; - else if( client == x.fan ) - x.fan = NULL; - else { - printk(KERN_ERR "g4fan: bad client\n"); - } - kfree( client ); + if (x.running) { + x.running = 0; + kthread_stop(x.poll_task); + x.poll_task = NULL; } - return err; -} + if (client == x.thermostat) + x.thermostat = NULL; + else if (client == x.fan) + x.fan = NULL; + else + printk(KERN_ERR "g4fan: bad client\n"); -static struct i2c_driver g4fan_driver = { - .driver = { - .name = "therm_windtunnel", - }, - .attach_adapter = do_attach, - .detach_client = do_detach, -}; + return 0; +} static int attach_fan( struct i2c_client *cl ) @@ -374,13 +365,8 @@ attach_fan( struct i2c_client *cl ) goto out; printk("ADM1030 fan controller [@%02x]\n", cl->addr ); - strlcpy( cl->name, "ADM1030 fan controller", sizeof(cl->name) ); - - if( !i2c_attach_client(cl) ) - x.fan = cl; + x.fan = cl; out: - if( cl != x.fan ) - kfree( cl ); return 0; } @@ -412,39 +398,47 @@ attach_thermostat( struct i2c_client *cl ) x.temp = temp; x.overheat_temp = os_temp; x.overheat_hyst = hyst_temp; - - strlcpy( cl->name, "DS1775 thermostat", sizeof(cl->name) ); - - if( !i2c_attach_client(cl) ) - x.thermostat = cl; + x.thermostat = cl; out: - if( cl != x.thermostat ) - kfree( cl ); return 0; } +enum chip { ds1775, adm1030 }; + +static const struct i2c_device_id therm_windtunnel_id[] = { + { "therm_ds1775", ds1775 }, + { "therm_adm1030", adm1030 }, + { } +}; + static int -do_probe( struct i2c_adapter *adapter, int addr, int kind ) +do_probe(struct i2c_client *cl, const struct i2c_device_id *id) { - struct i2c_client *cl; + struct i2c_adapter *adapter = cl->adapter; if( !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_WRITE_BYTE) ) return 0; - if( !(cl=kzalloc(sizeof(*cl), GFP_KERNEL)) ) - return -ENOMEM; - - cl->addr = addr; - cl->adapter = adapter; - cl->driver = &g4fan_driver; - cl->flags = 0; - - if( addr < 0x48 ) + switch (id->driver_data) { + case adm1030: return attach_fan( cl ); - return attach_thermostat( cl ); + case ds1775: + return attach_thermostat(cl); + } + return 0; } +static struct i2c_driver g4fan_driver = { + .driver = { + .name = "therm_windtunnel", + }, + .attach_adapter = do_attach, + .probe = do_probe, + .remove = do_remove, + .id_table = therm_windtunnel_id, +}; + /************************************************************************/ /* initialization / cleanup */ diff --git a/drivers/macintosh/windfarm_lm75_sensor.c b/drivers/macintosh/windfarm_lm75_sensor.c index b92b959fe16e..529886c7a826 100644 --- a/drivers/macintosh/windfarm_lm75_sensor.c +++ b/drivers/macintosh/windfarm_lm75_sensor.c @@ -37,34 +37,22 @@ struct wf_lm75_sensor { int ds1775 : 1; int inited : 1; - struct i2c_client i2c; + struct i2c_client *i2c; struct wf_sensor sens; }; #define wf_to_lm75(c) container_of(c, struct wf_lm75_sensor, sens) -#define i2c_to_lm75(c) container_of(c, struct wf_lm75_sensor, i2c) - -static int wf_lm75_attach(struct i2c_adapter *adapter); -static int wf_lm75_detach(struct i2c_client *client); - -static struct i2c_driver wf_lm75_driver = { - .driver = { - .name = "wf_lm75", - }, - .attach_adapter = wf_lm75_attach, - .detach_client = wf_lm75_detach, -}; static int wf_lm75_get(struct wf_sensor *sr, s32 *value) { struct wf_lm75_sensor *lm = wf_to_lm75(sr); s32 data; - if (lm->i2c.adapter == NULL) + if (lm->i2c == NULL) return -ENODEV; /* Init chip if necessary */ if (!lm->inited) { - u8 cfg_new, cfg = (u8)i2c_smbus_read_byte_data(&lm->i2c, 1); + u8 cfg_new, cfg = (u8)i2c_smbus_read_byte_data(lm->i2c, 1); DBG("wf_lm75: Initializing %s, cfg was: %02x\n", sr->name, cfg); @@ -73,7 +61,7 @@ static int wf_lm75_get(struct wf_sensor *sr, s32 *value) * the firmware for now */ cfg_new = cfg & ~0x01; - i2c_smbus_write_byte_data(&lm->i2c, 1, cfg_new); + i2c_smbus_write_byte_data(lm->i2c, 1, cfg_new); lm->inited = 1; /* If we just powered it up, let's wait 200 ms */ @@ -81,7 +69,7 @@ static int wf_lm75_get(struct wf_sensor *sr, s32 *value) } /* Read temperature register */ - data = (s32)le16_to_cpu(i2c_smbus_read_word_data(&lm->i2c, 0)); + data = (s32)le16_to_cpu(i2c_smbus_read_word_data(lm->i2c, 0)); data <<= 8; *value = data; @@ -92,12 +80,6 @@ static void wf_lm75_release(struct wf_sensor *sr) { struct wf_lm75_sensor *lm = wf_to_lm75(sr); - /* check if client is registered and detach from i2c */ - if (lm->i2c.adapter) { - i2c_detach_client(&lm->i2c); - lm->i2c.adapter = NULL; - } - kfree(lm); } @@ -107,59 +89,77 @@ static struct wf_sensor_ops wf_lm75_ops = { .owner = THIS_MODULE, }; -static struct wf_lm75_sensor *wf_lm75_create(struct i2c_adapter *adapter, - u8 addr, int ds1775, - const char *loc) +static int wf_lm75_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct wf_lm75_sensor *lm; int rc; - DBG("wf_lm75: creating %s device at address 0x%02x\n", - ds1775 ? "ds1775" : "lm75", addr); - lm = kzalloc(sizeof(struct wf_lm75_sensor), GFP_KERNEL); if (lm == NULL) - return NULL; + return -ENODEV; + + lm->inited = 0; + lm->ds1775 = id->driver_data; + lm->i2c = client; + lm->sens.name = client->dev.platform_data; + lm->sens.ops = &wf_lm75_ops; + i2c_set_clientdata(client, lm); + + rc = wf_register_sensor(&lm->sens); + if (rc) { + i2c_set_clientdata(client, NULL); + kfree(lm); + } + + return rc; +} + +static struct i2c_client *wf_lm75_create(struct i2c_adapter *adapter, + u8 addr, int ds1775, + const char *loc) +{ + struct i2c_board_info info; + struct i2c_client *client; + char *name; + + DBG("wf_lm75: creating %s device at address 0x%02x\n", + ds1775 ? "ds1775" : "lm75", addr); /* Usual rant about sensor names not beeing very consistent in * the device-tree, oh well ... * Add more entries below as you deal with more setups */ if (!strcmp(loc, "Hard drive") || !strcmp(loc, "DRIVE BAY")) - lm->sens.name = "hd-temp"; + name = "hd-temp"; else if (!strcmp(loc, "Incoming Air Temp")) - lm->sens.name = "incoming-air-temp"; + name = "incoming-air-temp"; else if (!strcmp(loc, "ODD Temp")) - lm->sens.name = "optical-drive-temp"; + name = "optical-drive-temp"; else if (!strcmp(loc, "HD Temp")) - lm->sens.name = "hard-drive-temp"; + name = "hard-drive-temp"; else goto fail; - lm->inited = 0; - lm->sens.ops = &wf_lm75_ops; - lm->ds1775 = ds1775; - lm->i2c.addr = (addr >> 1) & 0x7f; - lm->i2c.adapter = adapter; - lm->i2c.driver = &wf_lm75_driver; - strncpy(lm->i2c.name, lm->sens.name, I2C_NAME_SIZE-1); + memset(&info, 0, sizeof(struct i2c_board_info)); + info.addr = (addr >> 1) & 0x7f; + info.platform_data = name; + strlcpy(info.type, ds1775 ? "wf_ds1775" : "wf_lm75", I2C_NAME_SIZE); - rc = i2c_attach_client(&lm->i2c); - if (rc) { - printk(KERN_ERR "windfarm: failed to attach %s %s to i2c," - " err %d\n", ds1775 ? "ds1775" : "lm75", - lm->i2c.name, rc); + client = i2c_new_device(adapter, &info); + if (client == NULL) { + printk(KERN_ERR "windfarm: failed to attach %s %s to i2c\n", + ds1775 ? "ds1775" : "lm75", name); goto fail; } - if (wf_register_sensor(&lm->sens)) { - i2c_detach_client(&lm->i2c); - goto fail; - } - - return lm; + /* + * Let i2c-core delete that device on driver removal. + * This is safe because i2c-core holds the core_lock mutex for us. + */ + list_add_tail(&client->detected, &client->driver->clients); + return client; fail: - kfree(lm); return NULL; } @@ -202,21 +202,38 @@ static int wf_lm75_attach(struct i2c_adapter *adapter) return 0; } -static int wf_lm75_detach(struct i2c_client *client) +static int wf_lm75_remove(struct i2c_client *client) { - struct wf_lm75_sensor *lm = i2c_to_lm75(client); + struct wf_lm75_sensor *lm = i2c_get_clientdata(client); DBG("wf_lm75: i2c detatch called for %s\n", lm->sens.name); /* Mark client detached */ - lm->i2c.adapter = NULL; + lm->i2c = NULL; /* release sensor */ wf_unregister_sensor(&lm->sens); + i2c_set_clientdata(client, NULL); return 0; } +static const struct i2c_device_id wf_lm75_id[] = { + { "wf_lm75", 0 }, + { "wf_ds1775", 1 }, + { } +}; + +static struct i2c_driver wf_lm75_driver = { + .driver = { + .name = "wf_lm75", + }, + .attach_adapter = wf_lm75_attach, + .probe = wf_lm75_probe, + .remove = wf_lm75_remove, + .id_table = wf_lm75_id, +}; + static int __init wf_lm75_sensor_init(void) { /* Don't register on old machines that use therm_pm72 for now */ diff --git a/drivers/macintosh/windfarm_max6690_sensor.c b/drivers/macintosh/windfarm_max6690_sensor.c index e207a90d6b27..e2a55ecda2b2 100644 --- a/drivers/macintosh/windfarm_max6690_sensor.c +++ b/drivers/macintosh/windfarm_max6690_sensor.c @@ -26,34 +26,22 @@ #define MAX6690_EXTERNAL_TEMP 1 struct wf_6690_sensor { - struct i2c_client i2c; + struct i2c_client *i2c; struct wf_sensor sens; }; #define wf_to_6690(x) container_of((x), struct wf_6690_sensor, sens) -#define i2c_to_6690(x) container_of((x), struct wf_6690_sensor, i2c) - -static int wf_max6690_attach(struct i2c_adapter *adapter); -static int wf_max6690_detach(struct i2c_client *client); - -static struct i2c_driver wf_max6690_driver = { - .driver = { - .name = "wf_max6690", - }, - .attach_adapter = wf_max6690_attach, - .detach_client = wf_max6690_detach, -}; static int wf_max6690_get(struct wf_sensor *sr, s32 *value) { struct wf_6690_sensor *max = wf_to_6690(sr); s32 data; - if (max->i2c.adapter == NULL) + if (max->i2c == NULL) return -ENODEV; /* chip gets initialized by firmware */ - data = i2c_smbus_read_byte_data(&max->i2c, MAX6690_EXTERNAL_TEMP); + data = i2c_smbus_read_byte_data(max->i2c, MAX6690_EXTERNAL_TEMP); if (data < 0) return data; *value = data << 16; @@ -64,10 +52,6 @@ static void wf_max6690_release(struct wf_sensor *sr) { struct wf_6690_sensor *max = wf_to_6690(sr); - if (max->i2c.adapter) { - i2c_detach_client(&max->i2c); - max->i2c.adapter = NULL; - } kfree(max); } @@ -77,19 +61,40 @@ static struct wf_sensor_ops wf_max6690_ops = { .owner = THIS_MODULE, }; -static void wf_max6690_create(struct i2c_adapter *adapter, u8 addr, - const char *loc) +static int wf_max6690_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct wf_6690_sensor *max; - char *name; + int rc; max = kzalloc(sizeof(struct wf_6690_sensor), GFP_KERNEL); if (max == NULL) { - printk(KERN_ERR "windfarm: Couldn't create MAX6690 sensor %s: " - "no memory\n", loc); - return; + printk(KERN_ERR "windfarm: Couldn't create MAX6690 sensor: " + "no memory\n"); + return -ENOMEM; } + max->i2c = client; + max->sens.name = client->dev.platform_data; + max->sens.ops = &wf_max6690_ops; + i2c_set_clientdata(client, max); + + rc = wf_register_sensor(&max->sens); + if (rc) { + i2c_set_clientdata(client, NULL); + kfree(max); + } + + return rc; +} + +static struct i2c_client *wf_max6690_create(struct i2c_adapter *adapter, + u8 addr, const char *loc) +{ + struct i2c_board_info info; + struct i2c_client *client; + char *name; + if (!strcmp(loc, "BACKSIDE")) name = "backside-temp"; else if (!strcmp(loc, "NB Ambient")) @@ -99,27 +104,26 @@ static void wf_max6690_create(struct i2c_adapter *adapter, u8 addr, else goto fail; - max->sens.ops = &wf_max6690_ops; - max->sens.name = name; - max->i2c.addr = addr >> 1; - max->i2c.adapter = adapter; - max->i2c.driver = &wf_max6690_driver; - strncpy(max->i2c.name, name, I2C_NAME_SIZE-1); + memset(&info, 0, sizeof(struct i2c_board_info)); + info.addr = addr >> 1; + info.platform_data = name; + strlcpy(info.type, "wf_max6690", I2C_NAME_SIZE); - if (i2c_attach_client(&max->i2c)) { + client = i2c_new_device(adapter, &info); + if (client == NULL) { printk(KERN_ERR "windfarm: failed to attach MAX6690 sensor\n"); goto fail; } - if (wf_register_sensor(&max->sens)) { - i2c_detach_client(&max->i2c); - goto fail; - } - - return; + /* + * Let i2c-core delete that device on driver removal. + * This is safe because i2c-core holds the core_lock mutex for us. + */ + list_add_tail(&client->detected, &client->driver->clients); + return client; fail: - kfree(max); + return NULL; } static int wf_max6690_attach(struct i2c_adapter *adapter) @@ -154,16 +158,31 @@ static int wf_max6690_attach(struct i2c_adapter *adapter) return 0; } -static int wf_max6690_detach(struct i2c_client *client) +static int wf_max6690_remove(struct i2c_client *client) { - struct wf_6690_sensor *max = i2c_to_6690(client); + struct wf_6690_sensor *max = i2c_get_clientdata(client); - max->i2c.adapter = NULL; + max->i2c = NULL; wf_unregister_sensor(&max->sens); return 0; } +static const struct i2c_device_id wf_max6690_id[] = { + { "wf_max6690", 0 }, + { } +}; + +static struct i2c_driver wf_max6690_driver = { + .driver = { + .name = "wf_max6690", + }, + .attach_adapter = wf_max6690_attach, + .probe = wf_max6690_probe, + .remove = wf_max6690_remove, + .id_table = wf_max6690_id, +}; + static int __init wf_max6690_sensor_init(void) { /* Don't register on old machines that use therm_pm72 for now */ diff --git a/drivers/macintosh/windfarm_smu_sat.c b/drivers/macintosh/windfarm_smu_sat.c index 7847e981ac33..5da729e58f99 100644 --- a/drivers/macintosh/windfarm_smu_sat.c +++ b/drivers/macintosh/windfarm_smu_sat.c @@ -39,7 +39,7 @@ struct wf_sat { struct mutex mutex; unsigned long last_read; /* jiffies when cache last updated */ u8 cache[16]; - struct i2c_client i2c; + struct i2c_client *i2c; struct device_node *node; }; @@ -54,18 +54,6 @@ struct wf_sat_sensor { }; #define wf_to_sat(c) container_of(c, struct wf_sat_sensor, sens) -#define i2c_to_sat(c) container_of(c, struct wf_sat, i2c) - -static int wf_sat_attach(struct i2c_adapter *adapter); -static int wf_sat_detach(struct i2c_client *client); - -static struct i2c_driver wf_sat_driver = { - .driver = { - .name = "wf_smu_sat", - }, - .attach_adapter = wf_sat_attach, - .detach_client = wf_sat_detach, -}; struct smu_sdbp_header *smu_sat_get_sdb_partition(unsigned int sat_id, int id, unsigned int *size) @@ -81,13 +69,13 @@ struct smu_sdbp_header *smu_sat_get_sdb_partition(unsigned int sat_id, int id, if (sat_id > 1 || (sat = sats[sat_id]) == NULL) return NULL; - err = i2c_smbus_write_word_data(&sat->i2c, 8, id << 8); + err = i2c_smbus_write_word_data(sat->i2c, 8, id << 8); if (err) { printk(KERN_ERR "smu_sat_get_sdb_part wr error %d\n", err); return NULL; } - err = i2c_smbus_read_word_data(&sat->i2c, 9); + err = i2c_smbus_read_word_data(sat->i2c, 9); if (err < 0) { printk(KERN_ERR "smu_sat_get_sdb_part rd len error\n"); return NULL; @@ -105,7 +93,7 @@ struct smu_sdbp_header *smu_sat_get_sdb_partition(unsigned int sat_id, int id, return NULL; for (i = 0; i < len; i += 4) { - err = i2c_smbus_read_i2c_block_data(&sat->i2c, 0xa, 4, data); + err = i2c_smbus_read_i2c_block_data(sat->i2c, 0xa, 4, data); if (err < 0) { printk(KERN_ERR "smu_sat_get_sdb_part rd err %d\n", err); @@ -138,7 +126,7 @@ static int wf_sat_read_cache(struct wf_sat *sat) { int err; - err = i2c_smbus_read_i2c_block_data(&sat->i2c, 0x3f, 16, sat->cache); + err = i2c_smbus_read_i2c_block_data(sat->i2c, 0x3f, 16, sat->cache); if (err < 0) return err; sat->last_read = jiffies; @@ -161,7 +149,7 @@ static int wf_sat_get(struct wf_sensor *sr, s32 *value) int i, err; s32 val; - if (sat->i2c.adapter == NULL) + if (sat->i2c == NULL) return -ENODEV; mutex_lock(&sat->mutex); @@ -193,10 +181,6 @@ static void wf_sat_release(struct wf_sensor *sr) struct wf_sat *sat = sens->sat; if (atomic_dec_and_test(&sat->refcnt)) { - if (sat->i2c.adapter) { - i2c_detach_client(&sat->i2c); - sat->i2c.adapter = NULL; - } if (sat->nr >= 0) sats[sat->nr] = NULL; kfree(sat); @@ -212,15 +196,10 @@ static struct wf_sensor_ops wf_sat_ops = { static void wf_sat_create(struct i2c_adapter *adapter, struct device_node *dev) { - struct wf_sat *sat; - struct wf_sat_sensor *sens; + struct i2c_board_info info; + struct i2c_client *client; const u32 *reg; - const char *loc, *type; - u8 addr, chip, core; - struct device_node *child; - int shift, cpu, index; - char *name; - int vsens[2], isens[2]; + u8 addr; reg = of_get_property(dev, "reg", NULL); if (reg == NULL) @@ -228,22 +207,47 @@ static void wf_sat_create(struct i2c_adapter *adapter, struct device_node *dev) addr = *reg; DBG(KERN_DEBUG "wf_sat: creating sat at address %x\n", addr); + memset(&info, 0, sizeof(struct i2c_board_info)); + info.addr = (addr >> 1) & 0x7f; + info.platform_data = dev; + strlcpy(info.type, "wf_sat", I2C_NAME_SIZE); + + client = i2c_new_device(adapter, &info); + if (client == NULL) { + printk(KERN_ERR "windfarm: failed to attach smu-sat to i2c\n"); + return; + } + + /* + * Let i2c-core delete that device on driver removal. + * This is safe because i2c-core holds the core_lock mutex for us. + */ + list_add_tail(&client->detected, &client->driver->clients); +} + +static int wf_sat_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device_node *dev = client->dev.platform_data; + struct wf_sat *sat; + struct wf_sat_sensor *sens; + const u32 *reg; + const char *loc, *type; + u8 chip, core; + struct device_node *child; + int shift, cpu, index; + char *name; + int vsens[2], isens[2]; + sat = kzalloc(sizeof(struct wf_sat), GFP_KERNEL); if (sat == NULL) - return; + return -ENOMEM; sat->nr = -1; sat->node = of_node_get(dev); atomic_set(&sat->refcnt, 0); mutex_init(&sat->mutex); - sat->i2c.addr = (addr >> 1) & 0x7f; - sat->i2c.adapter = adapter; - sat->i2c.driver = &wf_sat_driver; - strncpy(sat->i2c.name, "smu-sat", I2C_NAME_SIZE-1); - - if (i2c_attach_client(&sat->i2c)) { - printk(KERN_ERR "windfarm: failed to attach smu-sat to i2c\n"); - goto fail; - } + sat->i2c = client; + i2c_set_clientdata(client, sat); vsens[0] = vsens[1] = -1; isens[0] = isens[1] = -1; @@ -344,10 +348,7 @@ static void wf_sat_create(struct i2c_adapter *adapter, struct device_node *dev) if (sat->nr >= 0) sats[sat->nr] = sat; - return; - - fail: - kfree(sat); + return 0; } static int wf_sat_attach(struct i2c_adapter *adapter) @@ -366,16 +367,32 @@ static int wf_sat_attach(struct i2c_adapter *adapter) return 0; } -static int wf_sat_detach(struct i2c_client *client) +static int wf_sat_remove(struct i2c_client *client) { - struct wf_sat *sat = i2c_to_sat(client); + struct wf_sat *sat = i2c_get_clientdata(client); /* XXX TODO */ - sat->i2c.adapter = NULL; + sat->i2c = NULL; + i2c_set_clientdata(client, NULL); return 0; } +static const struct i2c_device_id wf_sat_id[] = { + { "wf_sat", 0 }, + { } +}; + +static struct i2c_driver wf_sat_driver = { + .driver = { + .name = "wf_smu_sat", + }, + .attach_adapter = wf_sat_attach, + .probe = wf_sat_probe, + .remove = wf_sat_remove, + .id_table = wf_sat_id, +}; + static int __init sat_sensors_init(void) { return i2c_add_driver(&wf_sat_driver); diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig index 09c0c6e49ab5..2158377a1359 100644 --- a/drivers/md/Kconfig +++ b/drivers/md/Kconfig @@ -257,6 +257,17 @@ config DM_MIRROR Allow volume managers to mirror logical volumes, also needed for live data migration tools such as 'pvmove'. +config DM_LOG_USERSPACE + tristate "Mirror userspace logging (EXPERIMENTAL)" + depends on DM_MIRROR && EXPERIMENTAL && NET + select CONNECTOR + ---help--- + The userspace logging module provides a mechanism for + relaying the dm-dirty-log API to userspace. Log designs + which are more suited to userspace implementation (e.g. + shared storage logs) or experimental logs can be implemented + by leveraging this framework. + config DM_ZERO tristate "Zero target" depends on BLK_DEV_DM @@ -275,6 +286,25 @@ config DM_MULTIPATH ---help--- Allow volume managers to support multipath hardware. +config DM_MULTIPATH_QL + tristate "I/O Path Selector based on the number of in-flight I/Os" + depends on DM_MULTIPATH + ---help--- + This path selector is a dynamic load balancer which selects + the path with the least number of in-flight I/Os. + + If unsure, say N. + +config DM_MULTIPATH_ST + tristate "I/O Path Selector based on the service time" + depends on DM_MULTIPATH + ---help--- + This path selector is a dynamic load balancer which selects + the path expected to complete the incoming I/O in the shortest + time. + + If unsure, say N. + config DM_DELAY tristate "I/O delaying target (EXPERIMENTAL)" depends on BLK_DEV_DM && EXPERIMENTAL diff --git a/drivers/md/Makefile b/drivers/md/Makefile index 45cc5951d928..1dc4185bd781 100644 --- a/drivers/md/Makefile +++ b/drivers/md/Makefile @@ -8,6 +8,8 @@ dm-multipath-y += dm-path-selector.o dm-mpath.o dm-snapshot-y += dm-snap.o dm-exception-store.o dm-snap-transient.o \ dm-snap-persistent.o dm-mirror-y += dm-raid1.o +dm-log-userspace-y \ + += dm-log-userspace-base.o dm-log-userspace-transfer.o md-mod-y += md.o bitmap.o raid456-y += raid5.o raid6_pq-y += raid6algos.o raid6recov.o raid6tables.o \ @@ -36,8 +38,11 @@ obj-$(CONFIG_BLK_DEV_DM) += dm-mod.o obj-$(CONFIG_DM_CRYPT) += dm-crypt.o obj-$(CONFIG_DM_DELAY) += dm-delay.o obj-$(CONFIG_DM_MULTIPATH) += dm-multipath.o dm-round-robin.o +obj-$(CONFIG_DM_MULTIPATH_QL) += dm-queue-length.o +obj-$(CONFIG_DM_MULTIPATH_ST) += dm-service-time.o obj-$(CONFIG_DM_SNAPSHOT) += dm-snapshot.o obj-$(CONFIG_DM_MIRROR) += dm-mirror.o dm-log.o dm-region-hash.o +obj-$(CONFIG_DM_LOG_USERSPACE) += dm-log-userspace.o obj-$(CONFIG_DM_ZERO) += dm-zero.o quiet_cmd_unroll = UNROLL $@ diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 56df1cee8fb3..3319c2fec28e 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -232,7 +232,7 @@ static struct page *read_sb_page(mddev_t *mddev, long offset, target = rdev->sb_start + offset + index * (PAGE_SIZE/512); if (sync_page_io(rdev->bdev, target, - roundup(size, bdev_hardsect_size(rdev->bdev)), + roundup(size, bdev_logical_block_size(rdev->bdev)), page, READ)) { page->index = index; attach_page_buffers(page, NULL); /* so that free_buffer will @@ -287,7 +287,7 @@ static int write_sb_page(struct bitmap *bitmap, struct page *page, int wait) int size = PAGE_SIZE; if (page->index == bitmap->file_pages-1) size = roundup(bitmap->last_page_size, - bdev_hardsect_size(rdev->bdev)); + bdev_logical_block_size(rdev->bdev)); /* Just make sure we aren't corrupting data or * metadata */ diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 53394e863c74..9933eb861c71 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -1132,6 +1132,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) goto bad_crypt_queue; } + ti->num_flush_requests = 1; ti->private = cc; return 0; @@ -1189,6 +1190,13 @@ static int crypt_map(struct dm_target *ti, struct bio *bio, union map_info *map_context) { struct dm_crypt_io *io; + struct crypt_config *cc; + + if (unlikely(bio_empty_barrier(bio))) { + cc = ti->private; + bio->bi_bdev = cc->dev->bdev; + return DM_MAPIO_REMAPPED; + } io = crypt_io_alloc(ti, bio, bio->bi_sector - ti->begin); @@ -1305,9 +1313,17 @@ static int crypt_merge(struct dm_target *ti, struct bvec_merge_data *bvm, return min(max_size, q->merge_bvec_fn(q, bvm, biovec)); } +static int crypt_iterate_devices(struct dm_target *ti, + iterate_devices_callout_fn fn, void *data) +{ + struct crypt_config *cc = ti->private; + + return fn(ti, cc->dev, cc->start, data); +} + static struct target_type crypt_target = { .name = "crypt", - .version= {1, 6, 0}, + .version = {1, 7, 0}, .module = THIS_MODULE, .ctr = crypt_ctr, .dtr = crypt_dtr, @@ -1318,6 +1334,7 @@ static struct target_type crypt_target = { .resume = crypt_resume, .message = crypt_message, .merge = crypt_merge, + .iterate_devices = crypt_iterate_devices, }; static int __init dm_crypt_init(void) diff --git a/drivers/md/dm-delay.c b/drivers/md/dm-delay.c index 559dbb52bc85..4e5b843cd4d7 100644 --- a/drivers/md/dm-delay.c +++ b/drivers/md/dm-delay.c @@ -197,6 +197,7 @@ out: mutex_init(&dc->timer_lock); atomic_set(&dc->may_delay, 1); + ti->num_flush_requests = 1; ti->private = dc; return 0; @@ -278,8 +279,9 @@ static int delay_map(struct dm_target *ti, struct bio *bio, if ((bio_data_dir(bio) == WRITE) && (dc->dev_write)) { bio->bi_bdev = dc->dev_write->bdev; - bio->bi_sector = dc->start_write + - (bio->bi_sector - ti->begin); + if (bio_sectors(bio)) + bio->bi_sector = dc->start_write + + (bio->bi_sector - ti->begin); return delay_bio(dc, dc->write_delay, bio); } @@ -316,9 +318,26 @@ static int delay_status(struct dm_target *ti, status_type_t type, return 0; } +static int delay_iterate_devices(struct dm_target *ti, + iterate_devices_callout_fn fn, void *data) +{ + struct delay_c *dc = ti->private; + int ret = 0; + + ret = fn(ti, dc->dev_read, dc->start_read, data); + if (ret) + goto out; + + if (dc->dev_write) + ret = fn(ti, dc->dev_write, dc->start_write, data); + +out: + return ret; +} + static struct target_type delay_target = { .name = "delay", - .version = {1, 0, 2}, + .version = {1, 1, 0}, .module = THIS_MODULE, .ctr = delay_ctr, .dtr = delay_dtr, @@ -326,6 +345,7 @@ static struct target_type delay_target = { .presuspend = delay_presuspend, .resume = delay_resume, .status = delay_status, + .iterate_devices = delay_iterate_devices, }; static int __init dm_delay_init(void) diff --git a/drivers/md/dm-exception-store.c b/drivers/md/dm-exception-store.c index a2e26c242141..c3ae51584b12 100644 --- a/drivers/md/dm-exception-store.c +++ b/drivers/md/dm-exception-store.c @@ -178,7 +178,7 @@ static int set_chunk_size(struct dm_exception_store *store, } /* Validate the chunk size against the device block size */ - if (chunk_size_ulong % (bdev_hardsect_size(store->cow->bdev) >> 9)) { + if (chunk_size_ulong % (bdev_logical_block_size(store->cow->bdev) >> 9)) { *error = "Chunk size is not a multiple of device blocksize"; return -EINVAL; } @@ -216,7 +216,7 @@ int dm_exception_store_create(struct dm_target *ti, int argc, char **argv, return -EINVAL; } - type = get_type(argv[1]); + type = get_type(&persistent); if (!type) { ti->error = "Exception store type not recognised"; r = -EINVAL; diff --git a/drivers/md/dm-exception-store.h b/drivers/md/dm-exception-store.h index 0a2e6e7f67b3..2442c8c07898 100644 --- a/drivers/md/dm-exception-store.h +++ b/drivers/md/dm-exception-store.h @@ -111,7 +111,7 @@ struct dm_exception_store { /* * Funtions to manipulate consecutive chunks */ -# if defined(CONFIG_LBD) || (BITS_PER_LONG == 64) +# if defined(CONFIG_LBDAF) || (BITS_PER_LONG == 64) # define DM_CHUNK_CONSECUTIVE_BITS 8 # define DM_CHUNK_NUMBER_BITS 56 @@ -156,7 +156,7 @@ static inline void dm_consecutive_chunk_count_inc(struct dm_snap_exception *e) */ static inline sector_t get_dev_size(struct block_device *bdev) { - return bdev->bd_inode->i_size >> SECTOR_SHIFT; + return i_size_read(bdev->bd_inode) >> SECTOR_SHIFT; } static inline chunk_t sector_to_chunk(struct dm_exception_store *store, diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c index e73aabd61cd7..3a2e6a2f8bdd 100644 --- a/drivers/md/dm-io.c +++ b/drivers/md/dm-io.c @@ -22,6 +22,7 @@ struct dm_io_client { /* FIXME: can we shrink this ? */ struct io { unsigned long error_bits; + unsigned long eopnotsupp_bits; atomic_t count; struct task_struct *sleeper; struct dm_io_client *client; @@ -107,8 +108,11 @@ static inline unsigned bio_get_region(struct bio *bio) *---------------------------------------------------------------*/ static void dec_count(struct io *io, unsigned int region, int error) { - if (error) + if (error) { set_bit(region, &io->error_bits); + if (error == -EOPNOTSUPP) + set_bit(region, &io->eopnotsupp_bits); + } if (atomic_dec_and_test(&io->count)) { if (io->sleeper) @@ -360,7 +364,9 @@ static int sync_io(struct dm_io_client *client, unsigned int num_regions, return -EIO; } +retry: io.error_bits = 0; + io.eopnotsupp_bits = 0; atomic_set(&io.count, 1); /* see dispatch_io() */ io.sleeper = current; io.client = client; @@ -377,6 +383,11 @@ static int sync_io(struct dm_io_client *client, unsigned int num_regions, } set_current_state(TASK_RUNNING); + if (io.eopnotsupp_bits && (rw & (1 << BIO_RW_BARRIER))) { + rw &= ~(1 << BIO_RW_BARRIER); + goto retry; + } + if (error_bits) *error_bits = io.error_bits; @@ -397,6 +408,7 @@ static int async_io(struct dm_io_client *client, unsigned int num_regions, io = mempool_alloc(client->pool, GFP_NOIO); io->error_bits = 0; + io->eopnotsupp_bits = 0; atomic_set(&io->count, 1); /* see dispatch_io() */ io->sleeper = NULL; io->client = client; diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c index 823ceba6efa8..7f77f18fcafa 100644 --- a/drivers/md/dm-ioctl.c +++ b/drivers/md/dm-ioctl.c @@ -276,7 +276,7 @@ retry: up_write(&_hash_lock); } -static int dm_hash_rename(const char *old, const char *new) +static int dm_hash_rename(uint32_t cookie, const char *old, const char *new) { char *new_name, *old_name; struct hash_cell *hc; @@ -333,7 +333,7 @@ static int dm_hash_rename(const char *old, const char *new) dm_table_put(table); } - dm_kobject_uevent(hc->md); + dm_kobject_uevent(hc->md, KOBJ_CHANGE, cookie); dm_put(hc->md); up_write(&_hash_lock); @@ -680,6 +680,9 @@ static int dev_remove(struct dm_ioctl *param, size_t param_size) __hash_remove(hc); up_write(&_hash_lock); + + dm_kobject_uevent(md, KOBJ_REMOVE, param->event_nr); + dm_put(md); param->data_size = 0; return 0; @@ -715,7 +718,7 @@ static int dev_rename(struct dm_ioctl *param, size_t param_size) return r; param->data_size = 0; - return dm_hash_rename(param->name, new_name); + return dm_hash_rename(param->event_nr, param->name, new_name); } static int dev_set_geometry(struct dm_ioctl *param, size_t param_size) @@ -842,8 +845,11 @@ static int do_resume(struct dm_ioctl *param) if (dm_suspended(md)) r = dm_resume(md); - if (!r) + + if (!r) { + dm_kobject_uevent(md, KOBJ_CHANGE, param->event_nr); r = __dev_status(md, param); + } dm_put(md); return r; @@ -1044,6 +1050,12 @@ static int populate_table(struct dm_table *table, next = spec->next; } + r = dm_table_set_type(table); + if (r) { + DMWARN("unable to set table type"); + return r; + } + return dm_table_complete(table); } @@ -1089,6 +1101,13 @@ static int table_load(struct dm_ioctl *param, size_t param_size) goto out; } + r = dm_table_alloc_md_mempools(t); + if (r) { + DMWARN("unable to allocate mempools for this table"); + dm_table_destroy(t); + goto out; + } + down_write(&_hash_lock); hc = dm_get_mdptr(md); if (!hc || hc->md != md) { @@ -1513,6 +1532,7 @@ static const struct file_operations _ctl_fops = { static struct miscdevice _dm_misc = { .minor = MISC_DYNAMIC_MINOR, .name = DM_NAME, + .devnode = "mapper/control", .fops = &_ctl_fops }; diff --git a/drivers/md/dm-linear.c b/drivers/md/dm-linear.c index 79fb53e51c70..9184b6deb868 100644 --- a/drivers/md/dm-linear.c +++ b/drivers/md/dm-linear.c @@ -53,6 +53,7 @@ static int linear_ctr(struct dm_target *ti, unsigned int argc, char **argv) goto bad; } + ti->num_flush_requests = 1; ti->private = lc; return 0; @@ -81,7 +82,8 @@ static void linear_map_bio(struct dm_target *ti, struct bio *bio) struct linear_c *lc = ti->private; bio->bi_bdev = lc->dev->bdev; - bio->bi_sector = linear_map_sector(ti, bio->bi_sector); + if (bio_sectors(bio)) + bio->bi_sector = linear_map_sector(ti, bio->bi_sector); } static int linear_map(struct dm_target *ti, struct bio *bio, @@ -132,9 +134,17 @@ static int linear_merge(struct dm_target *ti, struct bvec_merge_data *bvm, return min(max_size, q->merge_bvec_fn(q, bvm, biovec)); } +static int linear_iterate_devices(struct dm_target *ti, + iterate_devices_callout_fn fn, void *data) +{ + struct linear_c *lc = ti->private; + + return fn(ti, lc->dev, lc->start, data); +} + static struct target_type linear_target = { .name = "linear", - .version= {1, 0, 3}, + .version = {1, 1, 0}, .module = THIS_MODULE, .ctr = linear_ctr, .dtr = linear_dtr, @@ -142,6 +152,7 @@ static struct target_type linear_target = { .status = linear_status, .ioctl = linear_ioctl, .merge = linear_merge, + .iterate_devices = linear_iterate_devices, }; int __init dm_linear_init(void) diff --git a/drivers/md/dm-log-userspace-base.c b/drivers/md/dm-log-userspace-base.c new file mode 100644 index 000000000000..e69b96560997 --- /dev/null +++ b/drivers/md/dm-log-userspace-base.c @@ -0,0 +1,696 @@ +/* + * Copyright (C) 2006-2009 Red Hat, Inc. + * + * This file is released under the LGPL. + */ + +#include +#include +#include +#include + +#include "dm-log-userspace-transfer.h" + +struct flush_entry { + int type; + region_t region; + struct list_head list; +}; + +struct log_c { + struct dm_target *ti; + uint32_t region_size; + region_t region_count; + char uuid[DM_UUID_LEN]; + + char *usr_argv_str; + uint32_t usr_argc; + + /* + * in_sync_hint gets set when doing is_remote_recovering. It + * represents the first region that needs recovery. IOW, the + * first zero bit of sync_bits. This can be useful for to limit + * traffic for calls like is_remote_recovering and get_resync_work, + * but be take care in its use for anything else. + */ + uint64_t in_sync_hint; + + spinlock_t flush_lock; + struct list_head flush_list; /* only for clear and mark requests */ +}; + +static mempool_t *flush_entry_pool; + +static void *flush_entry_alloc(gfp_t gfp_mask, void *pool_data) +{ + return kmalloc(sizeof(struct flush_entry), gfp_mask); +} + +static void flush_entry_free(void *element, void *pool_data) +{ + kfree(element); +} + +static int userspace_do_request(struct log_c *lc, const char *uuid, + int request_type, char *data, size_t data_size, + char *rdata, size_t *rdata_size) +{ + int r; + + /* + * If the server isn't there, -ESRCH is returned, + * and we must keep trying until the server is + * restored. + */ +retry: + r = dm_consult_userspace(uuid, request_type, data, + data_size, rdata, rdata_size); + + if (r != -ESRCH) + return r; + + DMERR(" Userspace log server not found."); + while (1) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(2*HZ); + DMWARN("Attempting to contact userspace log server..."); + r = dm_consult_userspace(uuid, DM_ULOG_CTR, lc->usr_argv_str, + strlen(lc->usr_argv_str) + 1, + NULL, NULL); + if (!r) + break; + } + DMINFO("Reconnected to userspace log server... DM_ULOG_CTR complete"); + r = dm_consult_userspace(uuid, DM_ULOG_RESUME, NULL, + 0, NULL, NULL); + if (!r) + goto retry; + + DMERR("Error trying to resume userspace log: %d", r); + + return -ESRCH; +} + +static int build_constructor_string(struct dm_target *ti, + unsigned argc, char **argv, + char **ctr_str) +{ + int i, str_size; + char *str = NULL; + + *ctr_str = NULL; + + for (i = 0, str_size = 0; i < argc; i++) + str_size += strlen(argv[i]) + 1; /* +1 for space between args */ + + str_size += 20; /* Max number of chars in a printed u64 number */ + + str = kzalloc(str_size, GFP_KERNEL); + if (!str) { + DMWARN("Unable to allocate memory for constructor string"); + return -ENOMEM; + } + + for (i = 0, str_size = 0; i < argc; i++) + str_size += sprintf(str + str_size, "%s ", argv[i]); + str_size += sprintf(str + str_size, "%llu", + (unsigned long long)ti->len); + + *ctr_str = str; + return str_size; +} + +/* + * userspace_ctr + * + * argv contains: + * + * Where 'other args' is the userspace implementation specific log + * arguments. An example might be: + * clustered_disk [[no]sync] + * + * So, this module will strip off the for identification purposes + * when communicating with userspace about a log; but will pass on everything + * else. + */ +static int userspace_ctr(struct dm_dirty_log *log, struct dm_target *ti, + unsigned argc, char **argv) +{ + int r = 0; + int str_size; + char *ctr_str = NULL; + struct log_c *lc = NULL; + uint64_t rdata; + size_t rdata_size = sizeof(rdata); + + if (argc < 3) { + DMWARN("Too few arguments to userspace dirty log"); + return -EINVAL; + } + + lc = kmalloc(sizeof(*lc), GFP_KERNEL); + if (!lc) { + DMWARN("Unable to allocate userspace log context."); + return -ENOMEM; + } + + lc->ti = ti; + + if (strlen(argv[0]) > (DM_UUID_LEN - 1)) { + DMWARN("UUID argument too long."); + kfree(lc); + return -EINVAL; + } + + strncpy(lc->uuid, argv[0], DM_UUID_LEN); + spin_lock_init(&lc->flush_lock); + INIT_LIST_HEAD(&lc->flush_list); + + str_size = build_constructor_string(ti, argc - 1, argv + 1, &ctr_str); + if (str_size < 0) { + kfree(lc); + return str_size; + } + + /* Send table string */ + r = dm_consult_userspace(lc->uuid, DM_ULOG_CTR, + ctr_str, str_size, NULL, NULL); + + if (r == -ESRCH) { + DMERR("Userspace log server not found"); + goto out; + } + + /* Since the region size does not change, get it now */ + rdata_size = sizeof(rdata); + r = dm_consult_userspace(lc->uuid, DM_ULOG_GET_REGION_SIZE, + NULL, 0, (char *)&rdata, &rdata_size); + + if (r) { + DMERR("Failed to get region size of dirty log"); + goto out; + } + + lc->region_size = (uint32_t)rdata; + lc->region_count = dm_sector_div_up(ti->len, lc->region_size); + +out: + if (r) { + kfree(lc); + kfree(ctr_str); + } else { + lc->usr_argv_str = ctr_str; + lc->usr_argc = argc; + log->context = lc; + } + + return r; +} + +static void userspace_dtr(struct dm_dirty_log *log) +{ + int r; + struct log_c *lc = log->context; + + r = dm_consult_userspace(lc->uuid, DM_ULOG_DTR, + NULL, 0, + NULL, NULL); + + kfree(lc->usr_argv_str); + kfree(lc); + + return; +} + +static int userspace_presuspend(struct dm_dirty_log *log) +{ + int r; + struct log_c *lc = log->context; + + r = dm_consult_userspace(lc->uuid, DM_ULOG_PRESUSPEND, + NULL, 0, + NULL, NULL); + + return r; +} + +static int userspace_postsuspend(struct dm_dirty_log *log) +{ + int r; + struct log_c *lc = log->context; + + r = dm_consult_userspace(lc->uuid, DM_ULOG_POSTSUSPEND, + NULL, 0, + NULL, NULL); + + return r; +} + +static int userspace_resume(struct dm_dirty_log *log) +{ + int r; + struct log_c *lc = log->context; + + lc->in_sync_hint = 0; + r = dm_consult_userspace(lc->uuid, DM_ULOG_RESUME, + NULL, 0, + NULL, NULL); + + return r; +} + +static uint32_t userspace_get_region_size(struct dm_dirty_log *log) +{ + struct log_c *lc = log->context; + + return lc->region_size; +} + +/* + * userspace_is_clean + * + * Check whether a region is clean. If there is any sort of + * failure when consulting the server, we return not clean. + * + * Returns: 1 if clean, 0 otherwise + */ +static int userspace_is_clean(struct dm_dirty_log *log, region_t region) +{ + int r; + uint64_t region64 = (uint64_t)region; + int64_t is_clean; + size_t rdata_size; + struct log_c *lc = log->context; + + rdata_size = sizeof(is_clean); + r = userspace_do_request(lc, lc->uuid, DM_ULOG_IS_CLEAN, + (char *)®ion64, sizeof(region64), + (char *)&is_clean, &rdata_size); + + return (r) ? 0 : (int)is_clean; +} + +/* + * userspace_in_sync + * + * Check if the region is in-sync. If there is any sort + * of failure when consulting the server, we assume that + * the region is not in sync. + * + * If 'can_block' is set, return immediately + * + * Returns: 1 if in-sync, 0 if not-in-sync, -EWOULDBLOCK + */ +static int userspace_in_sync(struct dm_dirty_log *log, region_t region, + int can_block) +{ + int r; + uint64_t region64 = region; + int64_t in_sync; + size_t rdata_size; + struct log_c *lc = log->context; + + /* + * We can never respond directly - even if in_sync_hint is + * set. This is because another machine could see a device + * failure and mark the region out-of-sync. If we don't go + * to userspace to ask, we might think the region is in-sync + * and allow a read to pick up data that is stale. (This is + * very unlikely if a device actually fails; but it is very + * likely if a connection to one device from one machine fails.) + * + * There still might be a problem if the mirror caches the region + * state as in-sync... but then this call would not be made. So, + * that is a mirror problem. + */ + if (!can_block) + return -EWOULDBLOCK; + + rdata_size = sizeof(in_sync); + r = userspace_do_request(lc, lc->uuid, DM_ULOG_IN_SYNC, + (char *)®ion64, sizeof(region64), + (char *)&in_sync, &rdata_size); + return (r) ? 0 : (int)in_sync; +} + +/* + * userspace_flush + * + * This function is ok to block. + * The flush happens in two stages. First, it sends all + * clear/mark requests that are on the list. Then it + * tells the server to commit them. This gives the + * server a chance to optimise the commit, instead of + * doing it for every request. + * + * Additionally, we could implement another thread that + * sends the requests up to the server - reducing the + * load on flush. Then the flush would have less in + * the list and be responsible for the finishing commit. + * + * Returns: 0 on success, < 0 on failure + */ +static int userspace_flush(struct dm_dirty_log *log) +{ + int r = 0; + unsigned long flags; + struct log_c *lc = log->context; + LIST_HEAD(flush_list); + struct flush_entry *fe, *tmp_fe; + + spin_lock_irqsave(&lc->flush_lock, flags); + list_splice_init(&lc->flush_list, &flush_list); + spin_unlock_irqrestore(&lc->flush_lock, flags); + + if (list_empty(&flush_list)) + return 0; + + /* + * FIXME: Count up requests, group request types, + * allocate memory to stick all requests in and + * send to server in one go. Failing the allocation, + * do it one by one. + */ + + list_for_each_entry(fe, &flush_list, list) { + r = userspace_do_request(lc, lc->uuid, fe->type, + (char *)&fe->region, + sizeof(fe->region), + NULL, NULL); + if (r) + goto fail; + } + + r = userspace_do_request(lc, lc->uuid, DM_ULOG_FLUSH, + NULL, 0, NULL, NULL); + +fail: + /* + * We can safely remove these entries, even if failure. + * Calling code will receive an error and will know that + * the log facility has failed. + */ + list_for_each_entry_safe(fe, tmp_fe, &flush_list, list) { + list_del(&fe->list); + mempool_free(fe, flush_entry_pool); + } + + if (r) + dm_table_event(lc->ti->table); + + return r; +} + +/* + * userspace_mark_region + * + * This function should avoid blocking unless absolutely required. + * (Memory allocation is valid for blocking.) + */ +static void userspace_mark_region(struct dm_dirty_log *log, region_t region) +{ + unsigned long flags; + struct log_c *lc = log->context; + struct flush_entry *fe; + + /* Wait for an allocation, but _never_ fail */ + fe = mempool_alloc(flush_entry_pool, GFP_NOIO); + BUG_ON(!fe); + + spin_lock_irqsave(&lc->flush_lock, flags); + fe->type = DM_ULOG_MARK_REGION; + fe->region = region; + list_add(&fe->list, &lc->flush_list); + spin_unlock_irqrestore(&lc->flush_lock, flags); + + return; +} + +/* + * userspace_clear_region + * + * This function must not block. + * So, the alloc can't block. In the worst case, it is ok to + * fail. It would simply mean we can't clear the region. + * Does nothing to current sync context, but does mean + * the region will be re-sync'ed on a reload of the mirror + * even though it is in-sync. + */ +static void userspace_clear_region(struct dm_dirty_log *log, region_t region) +{ + unsigned long flags; + struct log_c *lc = log->context; + struct flush_entry *fe; + + /* + * If we fail to allocate, we skip the clearing of + * the region. This doesn't hurt us in any way, except + * to cause the region to be resync'ed when the + * device is activated next time. + */ + fe = mempool_alloc(flush_entry_pool, GFP_ATOMIC); + if (!fe) { + DMERR("Failed to allocate memory to clear region."); + return; + } + + spin_lock_irqsave(&lc->flush_lock, flags); + fe->type = DM_ULOG_CLEAR_REGION; + fe->region = region; + list_add(&fe->list, &lc->flush_list); + spin_unlock_irqrestore(&lc->flush_lock, flags); + + return; +} + +/* + * userspace_get_resync_work + * + * Get a region that needs recovery. It is valid to return + * an error for this function. + * + * Returns: 1 if region filled, 0 if no work, <0 on error + */ +static int userspace_get_resync_work(struct dm_dirty_log *log, region_t *region) +{ + int r; + size_t rdata_size; + struct log_c *lc = log->context; + struct { + int64_t i; /* 64-bit for mix arch compatibility */ + region_t r; + } pkg; + + if (lc->in_sync_hint >= lc->region_count) + return 0; + + rdata_size = sizeof(pkg); + r = userspace_do_request(lc, lc->uuid, DM_ULOG_GET_RESYNC_WORK, + NULL, 0, + (char *)&pkg, &rdata_size); + + *region = pkg.r; + return (r) ? r : (int)pkg.i; +} + +/* + * userspace_set_region_sync + * + * Set the sync status of a given region. This function + * must not fail. + */ +static void userspace_set_region_sync(struct dm_dirty_log *log, + region_t region, int in_sync) +{ + int r; + struct log_c *lc = log->context; + struct { + region_t r; + int64_t i; + } pkg; + + pkg.r = region; + pkg.i = (int64_t)in_sync; + + r = userspace_do_request(lc, lc->uuid, DM_ULOG_SET_REGION_SYNC, + (char *)&pkg, sizeof(pkg), + NULL, NULL); + + /* + * It would be nice to be able to report failures. + * However, it is easy emough to detect and resolve. + */ + return; +} + +/* + * userspace_get_sync_count + * + * If there is any sort of failure when consulting the server, + * we assume that the sync count is zero. + * + * Returns: sync count on success, 0 on failure + */ +static region_t userspace_get_sync_count(struct dm_dirty_log *log) +{ + int r; + size_t rdata_size; + uint64_t sync_count; + struct log_c *lc = log->context; + + rdata_size = sizeof(sync_count); + r = userspace_do_request(lc, lc->uuid, DM_ULOG_GET_SYNC_COUNT, + NULL, 0, + (char *)&sync_count, &rdata_size); + + if (r) + return 0; + + if (sync_count >= lc->region_count) + lc->in_sync_hint = lc->region_count; + + return (region_t)sync_count; +} + +/* + * userspace_status + * + * Returns: amount of space consumed + */ +static int userspace_status(struct dm_dirty_log *log, status_type_t status_type, + char *result, unsigned maxlen) +{ + int r = 0; + size_t sz = (size_t)maxlen; + struct log_c *lc = log->context; + + switch (status_type) { + case STATUSTYPE_INFO: + r = userspace_do_request(lc, lc->uuid, DM_ULOG_STATUS_INFO, + NULL, 0, + result, &sz); + + if (r) { + sz = 0; + DMEMIT("%s 1 COM_FAILURE", log->type->name); + } + break; + case STATUSTYPE_TABLE: + sz = 0; + DMEMIT("%s %u %s %s", log->type->name, lc->usr_argc + 1, + lc->uuid, lc->usr_argv_str); + break; + } + return (r) ? 0 : (int)sz; +} + +/* + * userspace_is_remote_recovering + * + * Returns: 1 if region recovering, 0 otherwise + */ +static int userspace_is_remote_recovering(struct dm_dirty_log *log, + region_t region) +{ + int r; + uint64_t region64 = region; + struct log_c *lc = log->context; + static unsigned long long limit; + struct { + int64_t is_recovering; + uint64_t in_sync_hint; + } pkg; + size_t rdata_size = sizeof(pkg); + + /* + * Once the mirror has been reported to be in-sync, + * it will never again ask for recovery work. So, + * we can safely say there is not a remote machine + * recovering if the device is in-sync. (in_sync_hint + * must be reset at resume time.) + */ + if (region < lc->in_sync_hint) + return 0; + else if (jiffies < limit) + return 1; + + limit = jiffies + (HZ / 4); + r = userspace_do_request(lc, lc->uuid, DM_ULOG_IS_REMOTE_RECOVERING, + (char *)®ion64, sizeof(region64), + (char *)&pkg, &rdata_size); + if (r) + return 1; + + lc->in_sync_hint = pkg.in_sync_hint; + + return (int)pkg.is_recovering; +} + +static struct dm_dirty_log_type _userspace_type = { + .name = "userspace", + .module = THIS_MODULE, + .ctr = userspace_ctr, + .dtr = userspace_dtr, + .presuspend = userspace_presuspend, + .postsuspend = userspace_postsuspend, + .resume = userspace_resume, + .get_region_size = userspace_get_region_size, + .is_clean = userspace_is_clean, + .in_sync = userspace_in_sync, + .flush = userspace_flush, + .mark_region = userspace_mark_region, + .clear_region = userspace_clear_region, + .get_resync_work = userspace_get_resync_work, + .set_region_sync = userspace_set_region_sync, + .get_sync_count = userspace_get_sync_count, + .status = userspace_status, + .is_remote_recovering = userspace_is_remote_recovering, +}; + +static int __init userspace_dirty_log_init(void) +{ + int r = 0; + + flush_entry_pool = mempool_create(100, flush_entry_alloc, + flush_entry_free, NULL); + + if (!flush_entry_pool) { + DMWARN("Unable to create flush_entry_pool: No memory."); + return -ENOMEM; + } + + r = dm_ulog_tfr_init(); + if (r) { + DMWARN("Unable to initialize userspace log communications"); + mempool_destroy(flush_entry_pool); + return r; + } + + r = dm_dirty_log_type_register(&_userspace_type); + if (r) { + DMWARN("Couldn't register userspace dirty log type"); + dm_ulog_tfr_exit(); + mempool_destroy(flush_entry_pool); + return r; + } + + DMINFO("version 1.0.0 loaded"); + return 0; +} + +static void __exit userspace_dirty_log_exit(void) +{ + dm_dirty_log_type_unregister(&_userspace_type); + dm_ulog_tfr_exit(); + mempool_destroy(flush_entry_pool); + + DMINFO("version 1.0.0 unloaded"); + return; +} + +module_init(userspace_dirty_log_init); +module_exit(userspace_dirty_log_exit); + +MODULE_DESCRIPTION(DM_NAME " userspace dirty log link"); +MODULE_AUTHOR("Jonathan Brassow "); +MODULE_LICENSE("GPL"); diff --git a/drivers/md/dm-log-userspace-transfer.c b/drivers/md/dm-log-userspace-transfer.c new file mode 100644 index 000000000000..0ca1ee768a1f --- /dev/null +++ b/drivers/md/dm-log-userspace-transfer.c @@ -0,0 +1,276 @@ +/* + * Copyright (C) 2006-2009 Red Hat, Inc. + * + * This file is released under the LGPL. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "dm-log-userspace-transfer.h" + +static uint32_t dm_ulog_seq; + +/* + * Netlink/Connector is an unreliable protocol. How long should + * we wait for a response before assuming it was lost and retrying? + * (If we do receive a response after this time, it will be discarded + * and the response to the resent request will be waited for. + */ +#define DM_ULOG_RETRY_TIMEOUT (15 * HZ) + +/* + * Pre-allocated space for speed + */ +#define DM_ULOG_PREALLOCED_SIZE 512 +static struct cn_msg *prealloced_cn_msg; +static struct dm_ulog_request *prealloced_ulog_tfr; + +static struct cb_id ulog_cn_id = { + .idx = CN_IDX_DM, + .val = CN_VAL_DM_USERSPACE_LOG +}; + +static DEFINE_MUTEX(dm_ulog_lock); + +struct receiving_pkg { + struct list_head list; + struct completion complete; + + uint32_t seq; + + int error; + size_t *data_size; + char *data; +}; + +static DEFINE_SPINLOCK(receiving_list_lock); +static struct list_head receiving_list; + +static int dm_ulog_sendto_server(struct dm_ulog_request *tfr) +{ + int r; + struct cn_msg *msg = prealloced_cn_msg; + + memset(msg, 0, sizeof(struct cn_msg)); + + msg->id.idx = ulog_cn_id.idx; + msg->id.val = ulog_cn_id.val; + msg->ack = 0; + msg->seq = tfr->seq; + msg->len = sizeof(struct dm_ulog_request) + tfr->data_size; + + r = cn_netlink_send(msg, 0, gfp_any()); + + return r; +} + +/* + * Parameters for this function can be either msg or tfr, but not + * both. This function fills in the reply for a waiting request. + * If just msg is given, then the reply is simply an ACK from userspace + * that the request was received. + * + * Returns: 0 on success, -ENOENT on failure + */ +static int fill_pkg(struct cn_msg *msg, struct dm_ulog_request *tfr) +{ + uint32_t rtn_seq = (msg) ? msg->seq : (tfr) ? tfr->seq : 0; + struct receiving_pkg *pkg; + + /* + * The 'receiving_pkg' entries in this list are statically + * allocated on the stack in 'dm_consult_userspace'. + * Each process that is waiting for a reply from the user + * space server will have an entry in this list. + * + * We are safe to do it this way because the stack space + * is unique to each process, but still addressable by + * other processes. + */ + list_for_each_entry(pkg, &receiving_list, list) { + if (rtn_seq != pkg->seq) + continue; + + if (msg) { + pkg->error = -msg->ack; + /* + * If we are trying again, we will need to know our + * storage capacity. Otherwise, along with the + * error code, we make explicit that we have no data. + */ + if (pkg->error != -EAGAIN) + *(pkg->data_size) = 0; + } else if (tfr->data_size > *(pkg->data_size)) { + DMERR("Insufficient space to receive package [%u] " + "(%u vs %lu)", tfr->request_type, + tfr->data_size, *(pkg->data_size)); + + *(pkg->data_size) = 0; + pkg->error = -ENOSPC; + } else { + pkg->error = tfr->error; + memcpy(pkg->data, tfr->data, tfr->data_size); + *(pkg->data_size) = tfr->data_size; + } + complete(&pkg->complete); + return 0; + } + + return -ENOENT; +} + +/* + * This is the connector callback that delivers data + * that was sent from userspace. + */ +static void cn_ulog_callback(void *data) +{ + struct cn_msg *msg = (struct cn_msg *)data; + struct dm_ulog_request *tfr = (struct dm_ulog_request *)(msg + 1); + + spin_lock(&receiving_list_lock); + if (msg->len == 0) + fill_pkg(msg, NULL); + else if (msg->len < sizeof(*tfr)) + DMERR("Incomplete message received (expected %u, got %u): [%u]", + (unsigned)sizeof(*tfr), msg->len, msg->seq); + else + fill_pkg(NULL, tfr); + spin_unlock(&receiving_list_lock); +} + +/** + * dm_consult_userspace + * @uuid: log's uuid (must be DM_UUID_LEN in size) + * @request_type: found in include/linux/dm-log-userspace.h + * @data: data to tx to the server + * @data_size: size of data in bytes + * @rdata: place to put return data from server + * @rdata_size: value-result (amount of space given/amount of space used) + * + * rdata_size is undefined on failure. + * + * Memory used to communicate with userspace is zero'ed + * before populating to ensure that no unwanted bits leak + * from kernel space to user-space. All userspace log communications + * between kernel and user space go through this function. + * + * Returns: 0 on success, -EXXX on failure + **/ +int dm_consult_userspace(const char *uuid, int request_type, + char *data, size_t data_size, + char *rdata, size_t *rdata_size) +{ + int r = 0; + size_t dummy = 0; + int overhead_size = + sizeof(struct dm_ulog_request *) + sizeof(struct cn_msg); + struct dm_ulog_request *tfr = prealloced_ulog_tfr; + struct receiving_pkg pkg; + + if (data_size > (DM_ULOG_PREALLOCED_SIZE - overhead_size)) { + DMINFO("Size of tfr exceeds preallocated size"); + return -EINVAL; + } + + if (!rdata_size) + rdata_size = &dummy; +resend: + /* + * We serialize the sending of requests so we can + * use the preallocated space. + */ + mutex_lock(&dm_ulog_lock); + + memset(tfr, 0, DM_ULOG_PREALLOCED_SIZE - overhead_size); + memcpy(tfr->uuid, uuid, DM_UUID_LEN); + tfr->seq = dm_ulog_seq++; + + /* + * Must be valid request type (all other bits set to + * zero). This reserves other bits for possible future + * use. + */ + tfr->request_type = request_type & DM_ULOG_REQUEST_MASK; + + tfr->data_size = data_size; + if (data && data_size) + memcpy(tfr->data, data, data_size); + + memset(&pkg, 0, sizeof(pkg)); + init_completion(&pkg.complete); + pkg.seq = tfr->seq; + pkg.data_size = rdata_size; + pkg.data = rdata; + spin_lock(&receiving_list_lock); + list_add(&(pkg.list), &receiving_list); + spin_unlock(&receiving_list_lock); + + r = dm_ulog_sendto_server(tfr); + + mutex_unlock(&dm_ulog_lock); + + if (r) { + DMERR("Unable to send log request [%u] to userspace: %d", + request_type, r); + spin_lock(&receiving_list_lock); + list_del_init(&(pkg.list)); + spin_unlock(&receiving_list_lock); + + goto out; + } + + r = wait_for_completion_timeout(&(pkg.complete), DM_ULOG_RETRY_TIMEOUT); + spin_lock(&receiving_list_lock); + list_del_init(&(pkg.list)); + spin_unlock(&receiving_list_lock); + if (!r) { + DMWARN("[%s] Request timed out: [%u/%u] - retrying", + (strlen(uuid) > 8) ? + (uuid + (strlen(uuid) - 8)) : (uuid), + request_type, pkg.seq); + goto resend; + } + + r = pkg.error; + if (r == -EAGAIN) + goto resend; + +out: + return r; +} + +int dm_ulog_tfr_init(void) +{ + int r; + void *prealloced; + + INIT_LIST_HEAD(&receiving_list); + + prealloced = kmalloc(DM_ULOG_PREALLOCED_SIZE, GFP_KERNEL); + if (!prealloced) + return -ENOMEM; + + prealloced_cn_msg = prealloced; + prealloced_ulog_tfr = prealloced + sizeof(struct cn_msg); + + r = cn_add_callback(&ulog_cn_id, "dmlogusr", cn_ulog_callback); + if (r) { + cn_del_callback(&ulog_cn_id); + return r; + } + + return 0; +} + +void dm_ulog_tfr_exit(void) +{ + cn_del_callback(&ulog_cn_id); + kfree(prealloced_cn_msg); +} diff --git a/drivers/md/dm-log-userspace-transfer.h b/drivers/md/dm-log-userspace-transfer.h new file mode 100644 index 000000000000..c26d8e4e2710 --- /dev/null +++ b/drivers/md/dm-log-userspace-transfer.h @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2006-2009 Red Hat, Inc. + * + * This file is released under the LGPL. + */ + +#ifndef __DM_LOG_USERSPACE_TRANSFER_H__ +#define __DM_LOG_USERSPACE_TRANSFER_H__ + +#define DM_MSG_PREFIX "dm-log-userspace" + +int dm_ulog_tfr_init(void); +void dm_ulog_tfr_exit(void); +int dm_consult_userspace(const char *uuid, int request_type, + char *data, size_t data_size, + char *rdata, size_t *rdata_size); + +#endif /* __DM_LOG_USERSPACE_TRANSFER_H__ */ diff --git a/drivers/md/dm-log.c b/drivers/md/dm-log.c index be233bc4d917..9443896ede07 100644 --- a/drivers/md/dm-log.c +++ b/drivers/md/dm-log.c @@ -412,10 +412,12 @@ static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti, /* * Buffer holds both header and bitset. */ - buf_size = dm_round_up((LOG_OFFSET << SECTOR_SHIFT) + - bitset_size, ti->limits.hardsect_size); + buf_size = + dm_round_up((LOG_OFFSET << SECTOR_SHIFT) + bitset_size, + bdev_logical_block_size(lc->header_location. + bdev)); - if (buf_size > dev->bdev->bd_inode->i_size) { + if (buf_size > i_size_read(dev->bdev->bd_inode)) { DMWARN("log device %s too small: need %llu bytes", dev->name, (unsigned long long)buf_size); kfree(lc); diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index 6a386ab4f7eb..c70604a20897 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c @@ -8,7 +8,6 @@ #include #include "dm-path-selector.h" -#include "dm-bio-record.h" #include "dm-uevent.h" #include @@ -35,6 +34,7 @@ struct pgpath { struct dm_path path; struct work_struct deactivate_path; + struct work_struct activate_path; }; #define path_to_pgpath(__pgp) container_of((__pgp), struct pgpath, path) @@ -64,8 +64,6 @@ struct multipath { spinlock_t lock; const char *hw_handler_name; - struct work_struct activate_path; - struct pgpath *pgpath_to_activate; unsigned nr_priority_groups; struct list_head priority_groups; unsigned pg_init_required; /* pg_init needs calling? */ @@ -84,7 +82,7 @@ struct multipath { unsigned pg_init_count; /* Number of times pg_init called */ struct work_struct process_queued_ios; - struct bio_list queued_ios; + struct list_head queued_ios; unsigned queue_size; struct work_struct trigger_event; @@ -101,7 +99,7 @@ struct multipath { */ struct dm_mpath_io { struct pgpath *pgpath; - struct dm_bio_details details; + size_t nr_bytes; }; typedef int (*action_fn) (struct pgpath *pgpath); @@ -128,6 +126,7 @@ static struct pgpath *alloc_pgpath(void) if (pgpath) { pgpath->is_active = 1; INIT_WORK(&pgpath->deactivate_path, deactivate_path); + INIT_WORK(&pgpath->activate_path, activate_path); } return pgpath; @@ -160,7 +159,6 @@ static struct priority_group *alloc_priority_group(void) static void free_pgpaths(struct list_head *pgpaths, struct dm_target *ti) { - unsigned long flags; struct pgpath *pgpath, *tmp; struct multipath *m = ti->private; @@ -169,10 +167,6 @@ static void free_pgpaths(struct list_head *pgpaths, struct dm_target *ti) if (m->hw_handler_name) scsi_dh_detach(bdev_get_queue(pgpath->path.dev->bdev)); dm_put_device(ti, pgpath->path.dev); - spin_lock_irqsave(&m->lock, flags); - if (m->pgpath_to_activate == pgpath) - m->pgpath_to_activate = NULL; - spin_unlock_irqrestore(&m->lock, flags); free_pgpath(pgpath); } } @@ -198,11 +192,11 @@ static struct multipath *alloc_multipath(struct dm_target *ti) m = kzalloc(sizeof(*m), GFP_KERNEL); if (m) { INIT_LIST_HEAD(&m->priority_groups); + INIT_LIST_HEAD(&m->queued_ios); spin_lock_init(&m->lock); m->queue_io = 1; INIT_WORK(&m->process_queued_ios, process_queued_ios); INIT_WORK(&m->trigger_event, trigger_event); - INIT_WORK(&m->activate_path, activate_path); m->mpio_pool = mempool_create_slab_pool(MIN_IOS, _mpio_cache); if (!m->mpio_pool) { kfree(m); @@ -250,11 +244,12 @@ static void __switch_pg(struct multipath *m, struct pgpath *pgpath) m->pg_init_count = 0; } -static int __choose_path_in_pg(struct multipath *m, struct priority_group *pg) +static int __choose_path_in_pg(struct multipath *m, struct priority_group *pg, + size_t nr_bytes) { struct dm_path *path; - path = pg->ps.type->select_path(&pg->ps, &m->repeat_count); + path = pg->ps.type->select_path(&pg->ps, &m->repeat_count, nr_bytes); if (!path) return -ENXIO; @@ -266,7 +261,7 @@ static int __choose_path_in_pg(struct multipath *m, struct priority_group *pg) return 0; } -static void __choose_pgpath(struct multipath *m) +static void __choose_pgpath(struct multipath *m, size_t nr_bytes) { struct priority_group *pg; unsigned bypassed = 1; @@ -278,12 +273,12 @@ static void __choose_pgpath(struct multipath *m) if (m->next_pg) { pg = m->next_pg; m->next_pg = NULL; - if (!__choose_path_in_pg(m, pg)) + if (!__choose_path_in_pg(m, pg, nr_bytes)) return; } /* Don't change PG until it has no remaining paths */ - if (m->current_pg && !__choose_path_in_pg(m, m->current_pg)) + if (m->current_pg && !__choose_path_in_pg(m, m->current_pg, nr_bytes)) return; /* @@ -295,7 +290,7 @@ static void __choose_pgpath(struct multipath *m) list_for_each_entry(pg, &m->priority_groups, list) { if (pg->bypassed == bypassed) continue; - if (!__choose_path_in_pg(m, pg)) + if (!__choose_path_in_pg(m, pg, nr_bytes)) return; } } while (bypassed--); @@ -322,19 +317,21 @@ static int __must_push_back(struct multipath *m) dm_noflush_suspending(m->ti)); } -static int map_io(struct multipath *m, struct bio *bio, +static int map_io(struct multipath *m, struct request *clone, struct dm_mpath_io *mpio, unsigned was_queued) { int r = DM_MAPIO_REMAPPED; + size_t nr_bytes = blk_rq_bytes(clone); unsigned long flags; struct pgpath *pgpath; + struct block_device *bdev; spin_lock_irqsave(&m->lock, flags); /* Do we need to select a new pgpath? */ if (!m->current_pgpath || (!m->queue_io && (m->repeat_count && --m->repeat_count == 0))) - __choose_pgpath(m); + __choose_pgpath(m, nr_bytes); pgpath = m->current_pgpath; @@ -344,21 +341,28 @@ static int map_io(struct multipath *m, struct bio *bio, if ((pgpath && m->queue_io) || (!pgpath && m->queue_if_no_path)) { /* Queue for the daemon to resubmit */ - bio_list_add(&m->queued_ios, bio); + list_add_tail(&clone->queuelist, &m->queued_ios); m->queue_size++; if ((m->pg_init_required && !m->pg_init_in_progress) || !m->queue_io) queue_work(kmultipathd, &m->process_queued_ios); pgpath = NULL; r = DM_MAPIO_SUBMITTED; - } else if (pgpath) - bio->bi_bdev = pgpath->path.dev->bdev; - else if (__must_push_back(m)) + } else if (pgpath) { + bdev = pgpath->path.dev->bdev; + clone->q = bdev_get_queue(bdev); + clone->rq_disk = bdev->bd_disk; + } else if (__must_push_back(m)) r = DM_MAPIO_REQUEUE; else r = -EIO; /* Failed */ mpio->pgpath = pgpath; + mpio->nr_bytes = nr_bytes; + + if (r == DM_MAPIO_REMAPPED && pgpath->pg->ps.type->start_io) + pgpath->pg->ps.type->start_io(&pgpath->pg->ps, &pgpath->path, + nr_bytes); spin_unlock_irqrestore(&m->lock, flags); @@ -396,30 +400,31 @@ static void dispatch_queued_ios(struct multipath *m) { int r; unsigned long flags; - struct bio *bio = NULL, *next; struct dm_mpath_io *mpio; union map_info *info; + struct request *clone, *n; + LIST_HEAD(cl); spin_lock_irqsave(&m->lock, flags); - bio = bio_list_get(&m->queued_ios); + list_splice_init(&m->queued_ios, &cl); spin_unlock_irqrestore(&m->lock, flags); - while (bio) { - next = bio->bi_next; - bio->bi_next = NULL; + list_for_each_entry_safe(clone, n, &cl, queuelist) { + list_del_init(&clone->queuelist); - info = dm_get_mapinfo(bio); + info = dm_get_rq_mapinfo(clone); mpio = info->ptr; - r = map_io(m, bio, mpio, 1); - if (r < 0) - bio_endio(bio, r); - else if (r == DM_MAPIO_REMAPPED) - generic_make_request(bio); - else if (r == DM_MAPIO_REQUEUE) - bio_endio(bio, -EIO); - - bio = next; + r = map_io(m, clone, mpio, 1); + if (r < 0) { + mempool_free(mpio, m->mpio_pool); + dm_kill_unmapped_request(clone, r); + } else if (r == DM_MAPIO_REMAPPED) + dm_dispatch_request(clone); + else if (r == DM_MAPIO_REQUEUE) { + mempool_free(mpio, m->mpio_pool); + dm_requeue_unmapped_request(clone); + } } } @@ -427,8 +432,8 @@ static void process_queued_ios(struct work_struct *work) { struct multipath *m = container_of(work, struct multipath, process_queued_ios); - struct pgpath *pgpath = NULL; - unsigned init_required = 0, must_queue = 1; + struct pgpath *pgpath = NULL, *tmp; + unsigned must_queue = 1; unsigned long flags; spin_lock_irqsave(&m->lock, flags); @@ -437,7 +442,7 @@ static void process_queued_ios(struct work_struct *work) goto out; if (!m->current_pgpath) - __choose_pgpath(m); + __choose_pgpath(m, 0); pgpath = m->current_pgpath; @@ -446,19 +451,15 @@ static void process_queued_ios(struct work_struct *work) must_queue = 0; if (m->pg_init_required && !m->pg_init_in_progress && pgpath) { - m->pgpath_to_activate = pgpath; m->pg_init_count++; m->pg_init_required = 0; - m->pg_init_in_progress = 1; - init_required = 1; + list_for_each_entry(tmp, &pgpath->pg->pgpaths, list) { + if (queue_work(kmpath_handlerd, &tmp->activate_path)) + m->pg_init_in_progress++; + } } - out: spin_unlock_irqrestore(&m->lock, flags); - - if (init_required) - queue_work(kmpath_handlerd, &m->activate_path); - if (!must_queue) dispatch_queued_ios(m); } @@ -553,6 +554,12 @@ static int parse_path_selector(struct arg_set *as, struct priority_group *pg, return -EINVAL; } + if (ps_argc > as->argc) { + dm_put_path_selector(pst); + ti->error = "not enough arguments for path selector"; + return -EINVAL; + } + r = pst->create(&pg->ps, ps_argc, as->argv); if (r) { dm_put_path_selector(pst); @@ -591,9 +598,20 @@ static struct pgpath *parse_path(struct arg_set *as, struct path_selector *ps, } if (m->hw_handler_name) { - r = scsi_dh_attach(bdev_get_queue(p->path.dev->bdev), - m->hw_handler_name); + struct request_queue *q = bdev_get_queue(p->path.dev->bdev); + + r = scsi_dh_attach(q, m->hw_handler_name); + if (r == -EBUSY) { + /* + * Already attached to different hw_handler, + * try to reattach with correct one. + */ + scsi_dh_detach(q); + r = scsi_dh_attach(q, m->hw_handler_name); + } + if (r < 0) { + ti->error = "error attaching hardware handler"; dm_put_device(ti, p->path.dev); goto bad; } @@ -699,6 +717,11 @@ static int parse_hw_handler(struct arg_set *as, struct multipath *m) if (!hw_argc) return 0; + if (hw_argc > as->argc) { + ti->error = "not enough arguments for hardware handler"; + return -EINVAL; + } + m->hw_handler_name = kstrdup(shift(as), GFP_KERNEL); request_module("scsi_dh_%s", m->hw_handler_name); if (scsi_dh_handler_exist(m->hw_handler_name) == 0) { @@ -823,6 +846,8 @@ static int multipath_ctr(struct dm_target *ti, unsigned int argc, goto bad; } + ti->num_flush_requests = 1; + return 0; bad: @@ -836,25 +861,29 @@ static void multipath_dtr(struct dm_target *ti) flush_workqueue(kmpath_handlerd); flush_workqueue(kmultipathd); + flush_scheduled_work(); free_multipath(m); } /* - * Map bios, recording original fields for later in case we have to resubmit + * Map cloned requests */ -static int multipath_map(struct dm_target *ti, struct bio *bio, +static int multipath_map(struct dm_target *ti, struct request *clone, union map_info *map_context) { int r; struct dm_mpath_io *mpio; struct multipath *m = (struct multipath *) ti->private; - mpio = mempool_alloc(m->mpio_pool, GFP_NOIO); - dm_bio_record(&mpio->details, bio); + mpio = mempool_alloc(m->mpio_pool, GFP_ATOMIC); + if (!mpio) + /* ENOMEM, requeue */ + return DM_MAPIO_REQUEUE; + memset(mpio, 0, sizeof(*mpio)); map_context->ptr = mpio; - bio->bi_rw |= (1 << BIO_RW_FAILFAST_TRANSPORT); - r = map_io(m, bio, mpio, 0); + clone->cmd_flags |= REQ_FAILFAST_TRANSPORT; + r = map_io(m, clone, mpio, 0); if (r < 0 || r == DM_MAPIO_REQUEUE) mempool_free(mpio, m->mpio_pool); @@ -924,9 +953,13 @@ static int reinstate_path(struct pgpath *pgpath) pgpath->is_active = 1; - m->current_pgpath = NULL; - if (!m->nr_valid_paths++ && m->queue_size) + if (!m->nr_valid_paths++ && m->queue_size) { + m->current_pgpath = NULL; queue_work(kmultipathd, &m->process_queued_ios); + } else if (m->hw_handler_name && (m->current_pg == pgpath->pg)) { + if (queue_work(kmpath_handlerd, &pgpath->activate_path)) + m->pg_init_in_progress++; + } dm_path_uevent(DM_UEVENT_PATH_REINSTATED, m->ti, pgpath->path.dev->name, m->nr_valid_paths); @@ -1102,87 +1135,70 @@ static void pg_init_done(struct dm_path *path, int errors) spin_lock_irqsave(&m->lock, flags); if (errors) { - DMERR("Could not failover device. Error %d.", errors); - m->current_pgpath = NULL; - m->current_pg = NULL; + if (pgpath == m->current_pgpath) { + DMERR("Could not failover device. Error %d.", errors); + m->current_pgpath = NULL; + m->current_pg = NULL; + } } else if (!m->pg_init_required) { m->queue_io = 0; pg->bypassed = 0; } - m->pg_init_in_progress = 0; - queue_work(kmultipathd, &m->process_queued_ios); + m->pg_init_in_progress--; + if (!m->pg_init_in_progress) + queue_work(kmultipathd, &m->process_queued_ios); spin_unlock_irqrestore(&m->lock, flags); } static void activate_path(struct work_struct *work) { int ret; - struct multipath *m = - container_of(work, struct multipath, activate_path); - struct dm_path *path; - unsigned long flags; + struct pgpath *pgpath = + container_of(work, struct pgpath, activate_path); - spin_lock_irqsave(&m->lock, flags); - path = &m->pgpath_to_activate->path; - m->pgpath_to_activate = NULL; - spin_unlock_irqrestore(&m->lock, flags); - if (!path) - return; - ret = scsi_dh_activate(bdev_get_queue(path->dev->bdev)); - pg_init_done(path, ret); + ret = scsi_dh_activate(bdev_get_queue(pgpath->path.dev->bdev)); + pg_init_done(&pgpath->path, ret); } /* * end_io handling */ -static int do_end_io(struct multipath *m, struct bio *bio, +static int do_end_io(struct multipath *m, struct request *clone, int error, struct dm_mpath_io *mpio) { + /* + * We don't queue any clone request inside the multipath target + * during end I/O handling, since those clone requests don't have + * bio clones. If we queue them inside the multipath target, + * we need to make bio clones, that requires memory allocation. + * (See drivers/md/dm.c:end_clone_bio() about why the clone requests + * don't have bio clones.) + * Instead of queueing the clone request here, we queue the original + * request into dm core, which will remake a clone request and + * clone bios for it and resubmit it later. + */ + int r = DM_ENDIO_REQUEUE; unsigned long flags; - if (!error) + if (!error && !clone->errors) return 0; /* I/O complete */ - if ((error == -EWOULDBLOCK) && bio_rw_ahead(bio)) - return error; - if (error == -EOPNOTSUPP) return error; - spin_lock_irqsave(&m->lock, flags); - if (!m->nr_valid_paths) { - if (__must_push_back(m)) { - spin_unlock_irqrestore(&m->lock, flags); - return DM_ENDIO_REQUEUE; - } else if (!m->queue_if_no_path) { - spin_unlock_irqrestore(&m->lock, flags); - return -EIO; - } else { - spin_unlock_irqrestore(&m->lock, flags); - goto requeue; - } - } - spin_unlock_irqrestore(&m->lock, flags); - if (mpio->pgpath) fail_path(mpio->pgpath); - requeue: - dm_bio_restore(&mpio->details, bio); - - /* queue for the daemon to resubmit or fail */ spin_lock_irqsave(&m->lock, flags); - bio_list_add(&m->queued_ios, bio); - m->queue_size++; - if (!m->queue_io) - queue_work(kmultipathd, &m->process_queued_ios); + if (!m->nr_valid_paths && !m->queue_if_no_path && !__must_push_back(m)) + r = -EIO; spin_unlock_irqrestore(&m->lock, flags); - return DM_ENDIO_INCOMPLETE; /* io not complete */ + return r; } -static int multipath_end_io(struct dm_target *ti, struct bio *bio, +static int multipath_end_io(struct dm_target *ti, struct request *clone, int error, union map_info *map_context) { struct multipath *m = ti->private; @@ -1191,14 +1207,13 @@ static int multipath_end_io(struct dm_target *ti, struct bio *bio, struct path_selector *ps; int r; - r = do_end_io(m, bio, error, mpio); + r = do_end_io(m, clone, error, mpio); if (pgpath) { ps = &pgpath->pg->ps; if (ps->type->end_io) - ps->type->end_io(ps, &pgpath->path); + ps->type->end_io(ps, &pgpath->path, mpio->nr_bytes); } - if (r != DM_ENDIO_INCOMPLETE) - mempool_free(mpio, m->mpio_pool); + mempool_free(mpio, m->mpio_pool); return r; } @@ -1411,7 +1426,7 @@ static int multipath_ioctl(struct dm_target *ti, unsigned int cmd, spin_lock_irqsave(&m->lock, flags); if (!m->current_pgpath) - __choose_pgpath(m); + __choose_pgpath(m, 0); if (m->current_pgpath) { bdev = m->current_pgpath->path.dev->bdev; @@ -1428,22 +1443,113 @@ static int multipath_ioctl(struct dm_target *ti, unsigned int cmd, return r ? : __blkdev_driver_ioctl(bdev, mode, cmd, arg); } +static int multipath_iterate_devices(struct dm_target *ti, + iterate_devices_callout_fn fn, void *data) +{ + struct multipath *m = ti->private; + struct priority_group *pg; + struct pgpath *p; + int ret = 0; + + list_for_each_entry(pg, &m->priority_groups, list) { + list_for_each_entry(p, &pg->pgpaths, list) { + ret = fn(ti, p->path.dev, ti->begin, data); + if (ret) + goto out; + } + } + +out: + return ret; +} + +static int __pgpath_busy(struct pgpath *pgpath) +{ + struct request_queue *q = bdev_get_queue(pgpath->path.dev->bdev); + + return dm_underlying_device_busy(q); +} + +/* + * We return "busy", only when we can map I/Os but underlying devices + * are busy (so even if we map I/Os now, the I/Os will wait on + * the underlying queue). + * In other words, if we want to kill I/Os or queue them inside us + * due to map unavailability, we don't return "busy". Otherwise, + * dm core won't give us the I/Os and we can't do what we want. + */ +static int multipath_busy(struct dm_target *ti) +{ + int busy = 0, has_active = 0; + struct multipath *m = ti->private; + struct priority_group *pg; + struct pgpath *pgpath; + unsigned long flags; + + spin_lock_irqsave(&m->lock, flags); + + /* Guess which priority_group will be used at next mapping time */ + if (unlikely(!m->current_pgpath && m->next_pg)) + pg = m->next_pg; + else if (likely(m->current_pg)) + pg = m->current_pg; + else + /* + * We don't know which pg will be used at next mapping time. + * We don't call __choose_pgpath() here to avoid to trigger + * pg_init just by busy checking. + * So we don't know whether underlying devices we will be using + * at next mapping time are busy or not. Just try mapping. + */ + goto out; + + /* + * If there is one non-busy active path at least, the path selector + * will be able to select it. So we consider such a pg as not busy. + */ + busy = 1; + list_for_each_entry(pgpath, &pg->pgpaths, list) + if (pgpath->is_active) { + has_active = 1; + + if (!__pgpath_busy(pgpath)) { + busy = 0; + break; + } + } + + if (!has_active) + /* + * No active path in this pg, so this pg won't be used and + * the current_pg will be changed at next mapping time. + * We need to try mapping to determine it. + */ + busy = 0; + +out: + spin_unlock_irqrestore(&m->lock, flags); + + return busy; +} + /*----------------------------------------------------------------- * Module setup *---------------------------------------------------------------*/ static struct target_type multipath_target = { .name = "multipath", - .version = {1, 0, 5}, + .version = {1, 1, 0}, .module = THIS_MODULE, .ctr = multipath_ctr, .dtr = multipath_dtr, - .map = multipath_map, - .end_io = multipath_end_io, + .map_rq = multipath_map, + .rq_end_io = multipath_end_io, .presuspend = multipath_presuspend, .resume = multipath_resume, .status = multipath_status, .message = multipath_message, .ioctl = multipath_ioctl, + .iterate_devices = multipath_iterate_devices, + .busy = multipath_busy, }; static int __init dm_multipath_init(void) diff --git a/drivers/md/dm-path-selector.h b/drivers/md/dm-path-selector.h index 27357b85d73d..e7d1fa8b0459 100644 --- a/drivers/md/dm-path-selector.h +++ b/drivers/md/dm-path-selector.h @@ -56,7 +56,8 @@ struct path_selector_type { * the path fails. */ struct dm_path *(*select_path) (struct path_selector *ps, - unsigned *repeat_count); + unsigned *repeat_count, + size_t nr_bytes); /* * Notify the selector that a path has failed. @@ -75,7 +76,10 @@ struct path_selector_type { int (*status) (struct path_selector *ps, struct dm_path *path, status_type_t type, char *result, unsigned int maxlen); - int (*end_io) (struct path_selector *ps, struct dm_path *path); + int (*start_io) (struct path_selector *ps, struct dm_path *path, + size_t nr_bytes); + int (*end_io) (struct path_selector *ps, struct dm_path *path, + size_t nr_bytes); }; /* Register a path selector */ diff --git a/drivers/md/dm-queue-length.c b/drivers/md/dm-queue-length.c new file mode 100644 index 000000000000..f92b6cea9d9c --- /dev/null +++ b/drivers/md/dm-queue-length.c @@ -0,0 +1,263 @@ +/* + * Copyright (C) 2004-2005 IBM Corp. All Rights Reserved. + * Copyright (C) 2006-2009 NEC Corporation. + * + * dm-queue-length.c + * + * Module Author: Stefan Bader, IBM + * Modified by: Kiyoshi Ueda, NEC + * + * This file is released under the GPL. + * + * queue-length path selector - choose a path with the least number of + * in-flight I/Os. + */ + +#include "dm.h" +#include "dm-path-selector.h" + +#include +#include +#include +#include +#include + +#define DM_MSG_PREFIX "multipath queue-length" +#define QL_MIN_IO 128 +#define QL_VERSION "0.1.0" + +struct selector { + struct list_head valid_paths; + struct list_head failed_paths; +}; + +struct path_info { + struct list_head list; + struct dm_path *path; + unsigned repeat_count; + atomic_t qlen; /* the number of in-flight I/Os */ +}; + +static struct selector *alloc_selector(void) +{ + struct selector *s = kmalloc(sizeof(*s), GFP_KERNEL); + + if (s) { + INIT_LIST_HEAD(&s->valid_paths); + INIT_LIST_HEAD(&s->failed_paths); + } + + return s; +} + +static int ql_create(struct path_selector *ps, unsigned argc, char **argv) +{ + struct selector *s = alloc_selector(); + + if (!s) + return -ENOMEM; + + ps->context = s; + return 0; +} + +static void ql_free_paths(struct list_head *paths) +{ + struct path_info *pi, *next; + + list_for_each_entry_safe(pi, next, paths, list) { + list_del(&pi->list); + kfree(pi); + } +} + +static void ql_destroy(struct path_selector *ps) +{ + struct selector *s = ps->context; + + ql_free_paths(&s->valid_paths); + ql_free_paths(&s->failed_paths); + kfree(s); + ps->context = NULL; +} + +static int ql_status(struct path_selector *ps, struct dm_path *path, + status_type_t type, char *result, unsigned maxlen) +{ + unsigned sz = 0; + struct path_info *pi; + + /* When called with NULL path, return selector status/args. */ + if (!path) + DMEMIT("0 "); + else { + pi = path->pscontext; + + switch (type) { + case STATUSTYPE_INFO: + DMEMIT("%d ", atomic_read(&pi->qlen)); + break; + case STATUSTYPE_TABLE: + DMEMIT("%u ", pi->repeat_count); + break; + } + } + + return sz; +} + +static int ql_add_path(struct path_selector *ps, struct dm_path *path, + int argc, char **argv, char **error) +{ + struct selector *s = ps->context; + struct path_info *pi; + unsigned repeat_count = QL_MIN_IO; + + /* + * Arguments: [] + * : The number of I/Os before switching path. + * If not given, default (QL_MIN_IO) is used. + */ + if (argc > 1) { + *error = "queue-length ps: incorrect number of arguments"; + return -EINVAL; + } + + if ((argc == 1) && (sscanf(argv[0], "%u", &repeat_count) != 1)) { + *error = "queue-length ps: invalid repeat count"; + return -EINVAL; + } + + /* Allocate the path information structure */ + pi = kmalloc(sizeof(*pi), GFP_KERNEL); + if (!pi) { + *error = "queue-length ps: Error allocating path information"; + return -ENOMEM; + } + + pi->path = path; + pi->repeat_count = repeat_count; + atomic_set(&pi->qlen, 0); + + path->pscontext = pi; + + list_add_tail(&pi->list, &s->valid_paths); + + return 0; +} + +static void ql_fail_path(struct path_selector *ps, struct dm_path *path) +{ + struct selector *s = ps->context; + struct path_info *pi = path->pscontext; + + list_move(&pi->list, &s->failed_paths); +} + +static int ql_reinstate_path(struct path_selector *ps, struct dm_path *path) +{ + struct selector *s = ps->context; + struct path_info *pi = path->pscontext; + + list_move_tail(&pi->list, &s->valid_paths); + + return 0; +} + +/* + * Select a path having the minimum number of in-flight I/Os + */ +static struct dm_path *ql_select_path(struct path_selector *ps, + unsigned *repeat_count, size_t nr_bytes) +{ + struct selector *s = ps->context; + struct path_info *pi = NULL, *best = NULL; + + if (list_empty(&s->valid_paths)) + return NULL; + + /* Change preferred (first in list) path to evenly balance. */ + list_move_tail(s->valid_paths.next, &s->valid_paths); + + list_for_each_entry(pi, &s->valid_paths, list) { + if (!best || + (atomic_read(&pi->qlen) < atomic_read(&best->qlen))) + best = pi; + + if (!atomic_read(&best->qlen)) + break; + } + + if (!best) + return NULL; + + *repeat_count = best->repeat_count; + + return best->path; +} + +static int ql_start_io(struct path_selector *ps, struct dm_path *path, + size_t nr_bytes) +{ + struct path_info *pi = path->pscontext; + + atomic_inc(&pi->qlen); + + return 0; +} + +static int ql_end_io(struct path_selector *ps, struct dm_path *path, + size_t nr_bytes) +{ + struct path_info *pi = path->pscontext; + + atomic_dec(&pi->qlen); + + return 0; +} + +static struct path_selector_type ql_ps = { + .name = "queue-length", + .module = THIS_MODULE, + .table_args = 1, + .info_args = 1, + .create = ql_create, + .destroy = ql_destroy, + .status = ql_status, + .add_path = ql_add_path, + .fail_path = ql_fail_path, + .reinstate_path = ql_reinstate_path, + .select_path = ql_select_path, + .start_io = ql_start_io, + .end_io = ql_end_io, +}; + +static int __init dm_ql_init(void) +{ + int r = dm_register_path_selector(&ql_ps); + + if (r < 0) + DMERR("register failed %d", r); + + DMINFO("version " QL_VERSION " loaded"); + + return r; +} + +static void __exit dm_ql_exit(void) +{ + int r = dm_unregister_path_selector(&ql_ps); + + if (r < 0) + DMERR("unregister failed %d", r); +} + +module_init(dm_ql_init); +module_exit(dm_ql_exit); + +MODULE_AUTHOR("Stefan Bader "); +MODULE_DESCRIPTION( + "(C) Copyright IBM Corp. 2004,2005 All Rights Reserved.\n" + DM_NAME " path selector to balance the number of in-flight I/Os" +); +MODULE_LICENSE("GPL"); diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index 076fbb4e967a..ce8868c768cc 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c @@ -1283,9 +1283,23 @@ static int mirror_status(struct dm_target *ti, status_type_t type, return 0; } +static int mirror_iterate_devices(struct dm_target *ti, + iterate_devices_callout_fn fn, void *data) +{ + struct mirror_set *ms = ti->private; + int ret = 0; + unsigned i; + + for (i = 0; !ret && i < ms->nr_mirrors; i++) + ret = fn(ti, ms->mirror[i].dev, + ms->mirror[i].offset, data); + + return ret; +} + static struct target_type mirror_target = { .name = "mirror", - .version = {1, 0, 20}, + .version = {1, 12, 0}, .module = THIS_MODULE, .ctr = mirror_ctr, .dtr = mirror_dtr, @@ -1295,6 +1309,7 @@ static struct target_type mirror_target = { .postsuspend = mirror_postsuspend, .resume = mirror_resume, .status = mirror_status, + .iterate_devices = mirror_iterate_devices, }; static int __init dm_mirror_init(void) diff --git a/drivers/md/dm-region-hash.c b/drivers/md/dm-region-hash.c index 7b899be0b087..36dbe29f2fd6 100644 --- a/drivers/md/dm-region-hash.c +++ b/drivers/md/dm-region-hash.c @@ -283,7 +283,7 @@ static struct dm_region *__rh_alloc(struct dm_region_hash *rh, region_t region) nreg = mempool_alloc(rh->region_pool, GFP_ATOMIC); if (unlikely(!nreg)) - nreg = kmalloc(sizeof(*nreg), GFP_NOIO); + nreg = kmalloc(sizeof(*nreg), GFP_NOIO | __GFP_NOFAIL); nreg->state = rh->log->type->in_sync(rh->log, region, 1) ? DM_RH_CLEAN : DM_RH_NOSYNC; diff --git a/drivers/md/dm-round-robin.c b/drivers/md/dm-round-robin.c index cdfbf65b28cb..24752f449bef 100644 --- a/drivers/md/dm-round-robin.c +++ b/drivers/md/dm-round-robin.c @@ -161,7 +161,7 @@ static int rr_reinstate_path(struct path_selector *ps, struct dm_path *p) } static struct dm_path *rr_select_path(struct path_selector *ps, - unsigned *repeat_count) + unsigned *repeat_count, size_t nr_bytes) { struct selector *s = (struct selector *) ps->context; struct path_info *pi = NULL; diff --git a/drivers/md/dm-service-time.c b/drivers/md/dm-service-time.c new file mode 100644 index 000000000000..cfa668f46c40 --- /dev/null +++ b/drivers/md/dm-service-time.c @@ -0,0 +1,339 @@ +/* + * Copyright (C) 2007-2009 NEC Corporation. All Rights Reserved. + * + * Module Author: Kiyoshi Ueda + * + * This file is released under the GPL. + * + * Throughput oriented path selector. + */ + +#include "dm.h" +#include "dm-path-selector.h" + +#define DM_MSG_PREFIX "multipath service-time" +#define ST_MIN_IO 1 +#define ST_MAX_RELATIVE_THROUGHPUT 100 +#define ST_MAX_RELATIVE_THROUGHPUT_SHIFT 7 +#define ST_MAX_INFLIGHT_SIZE ((size_t)-1 >> ST_MAX_RELATIVE_THROUGHPUT_SHIFT) +#define ST_VERSION "0.2.0" + +struct selector { + struct list_head valid_paths; + struct list_head failed_paths; +}; + +struct path_info { + struct list_head list; + struct dm_path *path; + unsigned repeat_count; + unsigned relative_throughput; + atomic_t in_flight_size; /* Total size of in-flight I/Os */ +}; + +static struct selector *alloc_selector(void) +{ + struct selector *s = kmalloc(sizeof(*s), GFP_KERNEL); + + if (s) { + INIT_LIST_HEAD(&s->valid_paths); + INIT_LIST_HEAD(&s->failed_paths); + } + + return s; +} + +static int st_create(struct path_selector *ps, unsigned argc, char **argv) +{ + struct selector *s = alloc_selector(); + + if (!s) + return -ENOMEM; + + ps->context = s; + return 0; +} + +static void free_paths(struct list_head *paths) +{ + struct path_info *pi, *next; + + list_for_each_entry_safe(pi, next, paths, list) { + list_del(&pi->list); + kfree(pi); + } +} + +static void st_destroy(struct path_selector *ps) +{ + struct selector *s = ps->context; + + free_paths(&s->valid_paths); + free_paths(&s->failed_paths); + kfree(s); + ps->context = NULL; +} + +static int st_status(struct path_selector *ps, struct dm_path *path, + status_type_t type, char *result, unsigned maxlen) +{ + unsigned sz = 0; + struct path_info *pi; + + if (!path) + DMEMIT("0 "); + else { + pi = path->pscontext; + + switch (type) { + case STATUSTYPE_INFO: + DMEMIT("%d %u ", atomic_read(&pi->in_flight_size), + pi->relative_throughput); + break; + case STATUSTYPE_TABLE: + DMEMIT("%u %u ", pi->repeat_count, + pi->relative_throughput); + break; + } + } + + return sz; +} + +static int st_add_path(struct path_selector *ps, struct dm_path *path, + int argc, char **argv, char **error) +{ + struct selector *s = ps->context; + struct path_info *pi; + unsigned repeat_count = ST_MIN_IO; + unsigned relative_throughput = 1; + + /* + * Arguments: [ []] + * : The number of I/Os before switching path. + * If not given, default (ST_MIN_IO) is used. + * : The relative throughput value of + * the path among all paths in the path-group. + * The valid range: 0- + * If not given, minimum value '1' is used. + * If '0' is given, the path isn't selected while + * other paths having a positive value are + * available. + */ + if (argc > 2) { + *error = "service-time ps: incorrect number of arguments"; + return -EINVAL; + } + + if (argc && (sscanf(argv[0], "%u", &repeat_count) != 1)) { + *error = "service-time ps: invalid repeat count"; + return -EINVAL; + } + + if ((argc == 2) && + (sscanf(argv[1], "%u", &relative_throughput) != 1 || + relative_throughput > ST_MAX_RELATIVE_THROUGHPUT)) { + *error = "service-time ps: invalid relative_throughput value"; + return -EINVAL; + } + + /* allocate the path */ + pi = kmalloc(sizeof(*pi), GFP_KERNEL); + if (!pi) { + *error = "service-time ps: Error allocating path context"; + return -ENOMEM; + } + + pi->path = path; + pi->repeat_count = repeat_count; + pi->relative_throughput = relative_throughput; + atomic_set(&pi->in_flight_size, 0); + + path->pscontext = pi; + + list_add_tail(&pi->list, &s->valid_paths); + + return 0; +} + +static void st_fail_path(struct path_selector *ps, struct dm_path *path) +{ + struct selector *s = ps->context; + struct path_info *pi = path->pscontext; + + list_move(&pi->list, &s->failed_paths); +} + +static int st_reinstate_path(struct path_selector *ps, struct dm_path *path) +{ + struct selector *s = ps->context; + struct path_info *pi = path->pscontext; + + list_move_tail(&pi->list, &s->valid_paths); + + return 0; +} + +/* + * Compare the estimated service time of 2 paths, pi1 and pi2, + * for the incoming I/O. + * + * Returns: + * < 0 : pi1 is better + * 0 : no difference between pi1 and pi2 + * > 0 : pi2 is better + * + * Description: + * Basically, the service time is estimated by: + * ('pi->in-flight-size' + 'incoming') / 'pi->relative_throughput' + * To reduce the calculation, some optimizations are made. + * (See comments inline) + */ +static int st_compare_load(struct path_info *pi1, struct path_info *pi2, + size_t incoming) +{ + size_t sz1, sz2, st1, st2; + + sz1 = atomic_read(&pi1->in_flight_size); + sz2 = atomic_read(&pi2->in_flight_size); + + /* + * Case 1: Both have same throughput value. Choose less loaded path. + */ + if (pi1->relative_throughput == pi2->relative_throughput) + return sz1 - sz2; + + /* + * Case 2a: Both have same load. Choose higher throughput path. + * Case 2b: One path has no throughput value. Choose the other one. + */ + if (sz1 == sz2 || + !pi1->relative_throughput || !pi2->relative_throughput) + return pi2->relative_throughput - pi1->relative_throughput; + + /* + * Case 3: Calculate service time. Choose faster path. + * Service time using pi1: + * st1 = (sz1 + incoming) / pi1->relative_throughput + * Service time using pi2: + * st2 = (sz2 + incoming) / pi2->relative_throughput + * + * To avoid the division, transform the expression to use + * multiplication. + * Because ->relative_throughput > 0 here, if st1 < st2, + * the expressions below are the same meaning: + * (sz1 + incoming) / pi1->relative_throughput < + * (sz2 + incoming) / pi2->relative_throughput + * (sz1 + incoming) * pi2->relative_throughput < + * (sz2 + incoming) * pi1->relative_throughput + * So use the later one. + */ + sz1 += incoming; + sz2 += incoming; + if (unlikely(sz1 >= ST_MAX_INFLIGHT_SIZE || + sz2 >= ST_MAX_INFLIGHT_SIZE)) { + /* + * Size may be too big for multiplying pi->relative_throughput + * and overflow. + * To avoid the overflow and mis-selection, shift down both. + */ + sz1 >>= ST_MAX_RELATIVE_THROUGHPUT_SHIFT; + sz2 >>= ST_MAX_RELATIVE_THROUGHPUT_SHIFT; + } + st1 = sz1 * pi2->relative_throughput; + st2 = sz2 * pi1->relative_throughput; + if (st1 != st2) + return st1 - st2; + + /* + * Case 4: Service time is equal. Choose higher throughput path. + */ + return pi2->relative_throughput - pi1->relative_throughput; +} + +static struct dm_path *st_select_path(struct path_selector *ps, + unsigned *repeat_count, size_t nr_bytes) +{ + struct selector *s = ps->context; + struct path_info *pi = NULL, *best = NULL; + + if (list_empty(&s->valid_paths)) + return NULL; + + /* Change preferred (first in list) path to evenly balance. */ + list_move_tail(s->valid_paths.next, &s->valid_paths); + + list_for_each_entry(pi, &s->valid_paths, list) + if (!best || (st_compare_load(pi, best, nr_bytes) < 0)) + best = pi; + + if (!best) + return NULL; + + *repeat_count = best->repeat_count; + + return best->path; +} + +static int st_start_io(struct path_selector *ps, struct dm_path *path, + size_t nr_bytes) +{ + struct path_info *pi = path->pscontext; + + atomic_add(nr_bytes, &pi->in_flight_size); + + return 0; +} + +static int st_end_io(struct path_selector *ps, struct dm_path *path, + size_t nr_bytes) +{ + struct path_info *pi = path->pscontext; + + atomic_sub(nr_bytes, &pi->in_flight_size); + + return 0; +} + +static struct path_selector_type st_ps = { + .name = "service-time", + .module = THIS_MODULE, + .table_args = 2, + .info_args = 2, + .create = st_create, + .destroy = st_destroy, + .status = st_status, + .add_path = st_add_path, + .fail_path = st_fail_path, + .reinstate_path = st_reinstate_path, + .select_path = st_select_path, + .start_io = st_start_io, + .end_io = st_end_io, +}; + +static int __init dm_st_init(void) +{ + int r = dm_register_path_selector(&st_ps); + + if (r < 0) + DMERR("register failed %d", r); + + DMINFO("version " ST_VERSION " loaded"); + + return r; +} + +static void __exit dm_st_exit(void) +{ + int r = dm_unregister_path_selector(&st_ps); + + if (r < 0) + DMERR("unregister failed %d", r); +} + +module_init(dm_st_init); +module_exit(dm_st_exit); + +MODULE_DESCRIPTION(DM_NAME " throughput oriented path selector"); +MODULE_AUTHOR("Kiyoshi Ueda "); +MODULE_LICENSE("GPL"); diff --git a/drivers/md/dm-snap-persistent.c b/drivers/md/dm-snap-persistent.c index e75c6dd76a9a..6e3fe4f14934 100644 --- a/drivers/md/dm-snap-persistent.c +++ b/drivers/md/dm-snap-persistent.c @@ -282,7 +282,7 @@ static int read_header(struct pstore *ps, int *new_snapshot) */ if (!ps->store->chunk_size) { ps->store->chunk_size = max(DM_CHUNK_SIZE_DEFAULT_SECTORS, - bdev_hardsect_size(ps->store->cow->bdev) >> 9); + bdev_logical_block_size(ps->store->cow->bdev) >> 9); ps->store->chunk_mask = ps->store->chunk_size - 1; ps->store->chunk_shift = ffs(ps->store->chunk_size) - 1; chunk_size_supplied = 0; @@ -636,7 +636,7 @@ static void persistent_commit_exception(struct dm_exception_store *store, /* * Commit exceptions to disk. */ - if (ps->valid && area_io(ps, WRITE)) + if (ps->valid && area_io(ps, WRITE_BARRIER)) ps->valid = 0; /* diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index d73f17fc7778..d573165cd2b7 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c @@ -678,6 +678,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) ti->private = s; ti->split_io = s->store->chunk_size; + ti->num_flush_requests = 1; return 0; @@ -1030,6 +1031,11 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio, chunk_t chunk; struct dm_snap_pending_exception *pe = NULL; + if (unlikely(bio_empty_barrier(bio))) { + bio->bi_bdev = s->store->cow->bdev; + return DM_MAPIO_REMAPPED; + } + chunk = sector_to_chunk(s->store, bio->bi_sector); /* Full snapshots are not usable */ @@ -1338,6 +1344,8 @@ static int origin_ctr(struct dm_target *ti, unsigned int argc, char **argv) } ti->private = dev; + ti->num_flush_requests = 1; + return 0; } @@ -1353,6 +1361,9 @@ static int origin_map(struct dm_target *ti, struct bio *bio, struct dm_dev *dev = ti->private; bio->bi_bdev = dev->bdev; + if (unlikely(bio_empty_barrier(bio))) + return DM_MAPIO_REMAPPED; + /* Only tell snapshots if this is a write */ return (bio_rw(bio) == WRITE) ? do_origin(dev, bio) : DM_MAPIO_REMAPPED; } diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c index 41569bc60abc..b240e85ae39a 100644 --- a/drivers/md/dm-stripe.c +++ b/drivers/md/dm-stripe.c @@ -167,6 +167,7 @@ static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv) sc->stripes = stripes; sc->stripe_width = width; ti->split_io = chunk_size; + ti->num_flush_requests = stripes; sc->chunk_mask = ((sector_t) chunk_size) - 1; for (sc->chunk_shift = 0; chunk_size; sc->chunk_shift++) @@ -211,10 +212,18 @@ static int stripe_map(struct dm_target *ti, struct bio *bio, union map_info *map_context) { struct stripe_c *sc = (struct stripe_c *) ti->private; + sector_t offset, chunk; + uint32_t stripe; - sector_t offset = bio->bi_sector - ti->begin; - sector_t chunk = offset >> sc->chunk_shift; - uint32_t stripe = sector_div(chunk, sc->stripes); + if (unlikely(bio_empty_barrier(bio))) { + BUG_ON(map_context->flush_request >= sc->stripes); + bio->bi_bdev = sc->stripe[map_context->flush_request].dev->bdev; + return DM_MAPIO_REMAPPED; + } + + offset = bio->bi_sector - ti->begin; + chunk = offset >> sc->chunk_shift; + stripe = sector_div(chunk, sc->stripes); bio->bi_bdev = sc->stripe[stripe].dev->bdev; bio->bi_sector = sc->stripe[stripe].physical_start + @@ -304,15 +313,31 @@ static int stripe_end_io(struct dm_target *ti, struct bio *bio, return error; } +static int stripe_iterate_devices(struct dm_target *ti, + iterate_devices_callout_fn fn, void *data) +{ + struct stripe_c *sc = ti->private; + int ret = 0; + unsigned i = 0; + + do + ret = fn(ti, sc->stripe[i].dev, + sc->stripe[i].physical_start, data); + while (!ret && ++i < sc->stripes); + + return ret; +} + static struct target_type stripe_target = { .name = "striped", - .version = {1, 1, 0}, + .version = {1, 2, 0}, .module = THIS_MODULE, .ctr = stripe_ctr, .dtr = stripe_dtr, .map = stripe_map, .end_io = stripe_end_io, .status = stripe_status, + .iterate_devices = stripe_iterate_devices, }; int __init dm_stripe_init(void) diff --git a/drivers/md/dm-sysfs.c b/drivers/md/dm-sysfs.c index a2a45e6c7c8b..4b045903a4e2 100644 --- a/drivers/md/dm-sysfs.c +++ b/drivers/md/dm-sysfs.c @@ -57,12 +57,21 @@ static ssize_t dm_attr_uuid_show(struct mapped_device *md, char *buf) return strlen(buf); } +static ssize_t dm_attr_suspended_show(struct mapped_device *md, char *buf) +{ + sprintf(buf, "%d\n", dm_suspended(md)); + + return strlen(buf); +} + static DM_ATTR_RO(name); static DM_ATTR_RO(uuid); +static DM_ATTR_RO(suspended); static struct attribute *dm_attrs[] = { &dm_attr_name.attr, &dm_attr_uuid.attr, + &dm_attr_suspended.attr, NULL, }; diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 429b50b975d5..4899ebe767c8 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -41,6 +41,7 @@ struct dm_table { struct mapped_device *md; atomic_t holders; + unsigned type; /* btree table */ unsigned int depth; @@ -62,15 +63,11 @@ struct dm_table { /* a list of devices used by this table */ struct list_head devices; - /* - * These are optimistic limits taken from all the - * targets, some targets will need smaller limits. - */ - struct io_restrictions limits; - /* events get handed up using this callback */ void (*event_fn)(void *); void *event_context; + + struct dm_md_mempools *mempools; }; /* @@ -88,42 +85,6 @@ static unsigned int int_log(unsigned int n, unsigned int base) return result; } -/* - * Returns the minimum that is _not_ zero, unless both are zero. - */ -#define min_not_zero(l, r) (l == 0) ? r : ((r == 0) ? l : min(l, r)) - -/* - * Combine two io_restrictions, always taking the lower value. - */ -static void combine_restrictions_low(struct io_restrictions *lhs, - struct io_restrictions *rhs) -{ - lhs->max_sectors = - min_not_zero(lhs->max_sectors, rhs->max_sectors); - - lhs->max_phys_segments = - min_not_zero(lhs->max_phys_segments, rhs->max_phys_segments); - - lhs->max_hw_segments = - min_not_zero(lhs->max_hw_segments, rhs->max_hw_segments); - - lhs->hardsect_size = max(lhs->hardsect_size, rhs->hardsect_size); - - lhs->max_segment_size = - min_not_zero(lhs->max_segment_size, rhs->max_segment_size); - - lhs->max_hw_sectors = - min_not_zero(lhs->max_hw_sectors, rhs->max_hw_sectors); - - lhs->seg_boundary_mask = - min_not_zero(lhs->seg_boundary_mask, rhs->seg_boundary_mask); - - lhs->bounce_pfn = min_not_zero(lhs->bounce_pfn, rhs->bounce_pfn); - - lhs->no_cluster |= rhs->no_cluster; -} - /* * Calculate the index of the child node of the n'th node k'th key. */ @@ -266,6 +227,8 @@ static void free_devices(struct list_head *devices) list_for_each_safe(tmp, next, devices) { struct dm_dev_internal *dd = list_entry(tmp, struct dm_dev_internal, list); + DMWARN("dm_table_destroy: dm_put_device call missing for %s", + dd->dm_dev.name); kfree(dd); } } @@ -295,12 +258,10 @@ void dm_table_destroy(struct dm_table *t) vfree(t->highs); /* free the device list */ - if (t->devices.next != &t->devices) { - DMWARN("devices still present during destroy: " - "dm_table_remove_device calls missing"); - + if (t->devices.next != &t->devices) free_devices(&t->devices); - } + + dm_free_md_mempools(t->mempools); kfree(t); } @@ -384,15 +345,48 @@ static void close_dev(struct dm_dev_internal *d, struct mapped_device *md) /* * If possible, this checks an area of a destination device is valid. */ -static int check_device_area(struct dm_dev_internal *dd, sector_t start, - sector_t len) +static int device_area_is_valid(struct dm_target *ti, struct dm_dev *dev, + sector_t start, void *data) { - sector_t dev_size = dd->dm_dev.bdev->bd_inode->i_size >> SECTOR_SHIFT; + struct queue_limits *limits = data; + struct block_device *bdev = dev->bdev; + sector_t dev_size = + i_size_read(bdev->bd_inode) >> SECTOR_SHIFT; + unsigned short logical_block_size_sectors = + limits->logical_block_size >> SECTOR_SHIFT; + char b[BDEVNAME_SIZE]; if (!dev_size) return 1; - return ((start < dev_size) && (len <= (dev_size - start))); + if ((start >= dev_size) || (start + ti->len > dev_size)) { + DMWARN("%s: %s too small for target", + dm_device_name(ti->table->md), bdevname(bdev, b)); + return 0; + } + + if (logical_block_size_sectors <= 1) + return 1; + + if (start & (logical_block_size_sectors - 1)) { + DMWARN("%s: start=%llu not aligned to h/w " + "logical block size %hu of %s", + dm_device_name(ti->table->md), + (unsigned long long)start, + limits->logical_block_size, bdevname(bdev, b)); + return 0; + } + + if (ti->len & (logical_block_size_sectors - 1)) { + DMWARN("%s: len=%llu not aligned to h/w " + "logical block size %hu of %s", + dm_device_name(ti->table->md), + (unsigned long long)ti->len, + limits->logical_block_size, bdevname(bdev, b)); + return 0; + } + + return 1; } /* @@ -478,38 +472,32 @@ static int __table_get_device(struct dm_table *t, struct dm_target *ti, } atomic_inc(&dd->count); - if (!check_device_area(dd, start, len)) { - DMWARN("device %s too small for target", path); - dm_put_device(ti, &dd->dm_dev); - return -EINVAL; - } - *result = &dd->dm_dev; - return 0; } -void dm_set_device_limits(struct dm_target *ti, struct block_device *bdev) +/* + * Returns the minimum that is _not_ zero, unless both are zero. + */ +#define min_not_zero(l, r) (l == 0) ? r : ((r == 0) ? l : min(l, r)) + +int dm_set_device_limits(struct dm_target *ti, struct dm_dev *dev, + sector_t start, void *data) { + struct queue_limits *limits = data; + struct block_device *bdev = dev->bdev; struct request_queue *q = bdev_get_queue(bdev); - struct io_restrictions *rs = &ti->limits; char b[BDEVNAME_SIZE]; if (unlikely(!q)) { DMWARN("%s: Cannot set limits for nonexistent device %s", dm_device_name(ti->table->md), bdevname(bdev, b)); - return; + return 0; } - /* - * Combine the device limits low. - * - * FIXME: if we move an io_restriction struct - * into q this would just be a call to - * combine_restrictions_low() - */ - rs->max_sectors = - min_not_zero(rs->max_sectors, q->max_sectors); + if (blk_stack_limits(limits, &q->limits, start) < 0) + DMWARN("%s: target device %s is misaligned", + dm_device_name(ti->table->md), bdevname(bdev, b)); /* * Check if merge fn is supported. @@ -518,47 +506,21 @@ void dm_set_device_limits(struct dm_target *ti, struct block_device *bdev) */ if (q->merge_bvec_fn && !ti->type->merge) - rs->max_sectors = - min_not_zero(rs->max_sectors, + limits->max_sectors = + min_not_zero(limits->max_sectors, (unsigned int) (PAGE_SIZE >> 9)); - - rs->max_phys_segments = - min_not_zero(rs->max_phys_segments, - q->max_phys_segments); - - rs->max_hw_segments = - min_not_zero(rs->max_hw_segments, q->max_hw_segments); - - rs->hardsect_size = max(rs->hardsect_size, q->hardsect_size); - - rs->max_segment_size = - min_not_zero(rs->max_segment_size, q->max_segment_size); - - rs->max_hw_sectors = - min_not_zero(rs->max_hw_sectors, q->max_hw_sectors); - - rs->seg_boundary_mask = - min_not_zero(rs->seg_boundary_mask, - q->seg_boundary_mask); - - rs->bounce_pfn = min_not_zero(rs->bounce_pfn, q->bounce_pfn); - - rs->no_cluster |= !test_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags); + return 0; } EXPORT_SYMBOL_GPL(dm_set_device_limits); int dm_get_device(struct dm_target *ti, const char *path, sector_t start, sector_t len, fmode_t mode, struct dm_dev **result) { - int r = __table_get_device(ti->table, ti, path, - start, len, mode, result); - - if (!r) - dm_set_device_limits(ti, (*result)->bdev); - - return r; + return __table_get_device(ti->table, ti, path, + start, len, mode, result); } + /* * Decrement a devices use count and remove it if necessary. */ @@ -673,24 +635,78 @@ int dm_split_args(int *argc, char ***argvp, char *input) return 0; } -static void check_for_valid_limits(struct io_restrictions *rs) +/* + * Impose necessary and sufficient conditions on a devices's table such + * that any incoming bio which respects its logical_block_size can be + * processed successfully. If it falls across the boundary between + * two or more targets, the size of each piece it gets split into must + * be compatible with the logical_block_size of the target processing it. + */ +static int validate_hardware_logical_block_alignment(struct dm_table *table, + struct queue_limits *limits) { - if (!rs->max_sectors) - rs->max_sectors = SAFE_MAX_SECTORS; - if (!rs->max_hw_sectors) - rs->max_hw_sectors = SAFE_MAX_SECTORS; - if (!rs->max_phys_segments) - rs->max_phys_segments = MAX_PHYS_SEGMENTS; - if (!rs->max_hw_segments) - rs->max_hw_segments = MAX_HW_SEGMENTS; - if (!rs->hardsect_size) - rs->hardsect_size = 1 << SECTOR_SHIFT; - if (!rs->max_segment_size) - rs->max_segment_size = MAX_SEGMENT_SIZE; - if (!rs->seg_boundary_mask) - rs->seg_boundary_mask = BLK_SEG_BOUNDARY_MASK; - if (!rs->bounce_pfn) - rs->bounce_pfn = -1; + /* + * This function uses arithmetic modulo the logical_block_size + * (in units of 512-byte sectors). + */ + unsigned short device_logical_block_size_sects = + limits->logical_block_size >> SECTOR_SHIFT; + + /* + * Offset of the start of the next table entry, mod logical_block_size. + */ + unsigned short next_target_start = 0; + + /* + * Given an aligned bio that extends beyond the end of a + * target, how many sectors must the next target handle? + */ + unsigned short remaining = 0; + + struct dm_target *uninitialized_var(ti); + struct queue_limits ti_limits; + unsigned i = 0; + + /* + * Check each entry in the table in turn. + */ + while (i < dm_table_get_num_targets(table)) { + ti = dm_table_get_target(table, i++); + + blk_set_default_limits(&ti_limits); + + /* combine all target devices' limits */ + if (ti->type->iterate_devices) + ti->type->iterate_devices(ti, dm_set_device_limits, + &ti_limits); + + /* + * If the remaining sectors fall entirely within this + * table entry are they compatible with its logical_block_size? + */ + if (remaining < ti->len && + remaining & ((ti_limits.logical_block_size >> + SECTOR_SHIFT) - 1)) + break; /* Error */ + + next_target_start = + (unsigned short) ((next_target_start + ti->len) & + (device_logical_block_size_sects - 1)); + remaining = next_target_start ? + device_logical_block_size_sects - next_target_start : 0; + } + + if (remaining) { + DMWARN("%s: table line %u (start sect %llu len %llu) " + "not aligned to h/w logical block size %hu", + dm_device_name(table->md), i, + (unsigned long long) ti->begin, + (unsigned long long) ti->len, + limits->logical_block_size); + return -EINVAL; + } + + return 0; } int dm_table_add_target(struct dm_table *t, const char *type, @@ -745,9 +761,6 @@ int dm_table_add_target(struct dm_table *t, const char *type, t->highs[t->num_targets++] = tgt->begin + tgt->len - 1; - /* FIXME: the plan is to combine high here and then have - * the merge fn apply the target level restrictions. */ - combine_restrictions_low(&t->limits, &tgt->limits); return 0; bad: @@ -756,6 +769,104 @@ int dm_table_add_target(struct dm_table *t, const char *type, return r; } +int dm_table_set_type(struct dm_table *t) +{ + unsigned i; + unsigned bio_based = 0, request_based = 0; + struct dm_target *tgt; + struct dm_dev_internal *dd; + struct list_head *devices; + + for (i = 0; i < t->num_targets; i++) { + tgt = t->targets + i; + if (dm_target_request_based(tgt)) + request_based = 1; + else + bio_based = 1; + + if (bio_based && request_based) { + DMWARN("Inconsistent table: different target types" + " can't be mixed up"); + return -EINVAL; + } + } + + if (bio_based) { + /* We must use this table as bio-based */ + t->type = DM_TYPE_BIO_BASED; + return 0; + } + + BUG_ON(!request_based); /* No targets in this table */ + + /* Non-request-stackable devices can't be used for request-based dm */ + devices = dm_table_get_devices(t); + list_for_each_entry(dd, devices, list) { + if (!blk_queue_stackable(bdev_get_queue(dd->dm_dev.bdev))) { + DMWARN("table load rejected: including" + " non-request-stackable devices"); + return -EINVAL; + } + } + + /* + * Request-based dm supports only tables that have a single target now. + * To support multiple targets, request splitting support is needed, + * and that needs lots of changes in the block-layer. + * (e.g. request completion process for partial completion.) + */ + if (t->num_targets > 1) { + DMWARN("Request-based dm doesn't support multiple targets yet"); + return -EINVAL; + } + + t->type = DM_TYPE_REQUEST_BASED; + + return 0; +} + +unsigned dm_table_get_type(struct dm_table *t) +{ + return t->type; +} + +bool dm_table_bio_based(struct dm_table *t) +{ + return dm_table_get_type(t) == DM_TYPE_BIO_BASED; +} + +bool dm_table_request_based(struct dm_table *t) +{ + return dm_table_get_type(t) == DM_TYPE_REQUEST_BASED; +} + +int dm_table_alloc_md_mempools(struct dm_table *t) +{ + unsigned type = dm_table_get_type(t); + + if (unlikely(type == DM_TYPE_NONE)) { + DMWARN("no table type is set, can't allocate mempools"); + return -EINVAL; + } + + t->mempools = dm_alloc_md_mempools(type); + if (!t->mempools) + return -ENOMEM; + + return 0; +} + +void dm_table_free_md_mempools(struct dm_table *t) +{ + dm_free_md_mempools(t->mempools); + t->mempools = NULL; +} + +struct dm_md_mempools *dm_table_get_md_mempools(struct dm_table *t) +{ + return t->mempools; +} + static int setup_indexes(struct dm_table *t) { int i; @@ -790,8 +901,6 @@ int dm_table_complete(struct dm_table *t) int r = 0; unsigned int leaf_nodes; - check_for_valid_limits(&t->limits); - /* how many indexes will the btree have ? */ leaf_nodes = dm_div_up(t->num_targets, KEYS_PER_NODE); t->depth = 1 + int_log(leaf_nodes, CHILDREN_PER_NODE); @@ -866,6 +975,57 @@ struct dm_target *dm_table_find_target(struct dm_table *t, sector_t sector) return &t->targets[(KEYS_PER_NODE * n) + k]; } +/* + * Establish the new table's queue_limits and validate them. + */ +int dm_calculate_queue_limits(struct dm_table *table, + struct queue_limits *limits) +{ + struct dm_target *uninitialized_var(ti); + struct queue_limits ti_limits; + unsigned i = 0; + + blk_set_default_limits(limits); + + while (i < dm_table_get_num_targets(table)) { + blk_set_default_limits(&ti_limits); + + ti = dm_table_get_target(table, i++); + + if (!ti->type->iterate_devices) + goto combine_limits; + + /* + * Combine queue limits of all the devices this target uses. + */ + ti->type->iterate_devices(ti, dm_set_device_limits, + &ti_limits); + + /* + * Check each device area is consistent with the target's + * overall queue limits. + */ + if (!ti->type->iterate_devices(ti, device_area_is_valid, + &ti_limits)) + return -EINVAL; + +combine_limits: + /* + * Merge this target's queue limits into the overall limits + * for the table. + */ + if (blk_stack_limits(limits, &ti_limits, 0) < 0) + DMWARN("%s: target device " + "(start sect %llu len %llu) " + "is misaligned", + dm_device_name(table->md), + (unsigned long long) ti->begin, + (unsigned long long) ti->len); + } + + return validate_hardware_logical_block_alignment(table, limits); +} + /* * Set the integrity profile for this device if all devices used have * matching profiles. @@ -905,27 +1065,42 @@ no_integrity: return; } -void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q) +void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q, + struct queue_limits *limits) { /* - * Make sure we obey the optimistic sub devices - * restrictions. + * Each target device in the table has a data area that should normally + * be aligned such that the DM device's alignment_offset is 0. + * FIXME: Propagate alignment_offsets up the stack and warn of + * sub-optimal or inconsistent settings. */ - blk_queue_max_sectors(q, t->limits.max_sectors); - q->max_phys_segments = t->limits.max_phys_segments; - q->max_hw_segments = t->limits.max_hw_segments; - q->hardsect_size = t->limits.hardsect_size; - q->max_segment_size = t->limits.max_segment_size; - q->max_hw_sectors = t->limits.max_hw_sectors; - q->seg_boundary_mask = t->limits.seg_boundary_mask; - q->bounce_pfn = t->limits.bounce_pfn; + limits->alignment_offset = 0; + limits->misaligned = 0; - if (t->limits.no_cluster) + /* + * Copy table's limits to the DM device's request_queue + */ + q->limits = *limits; + + if (limits->no_cluster) queue_flag_clear_unlocked(QUEUE_FLAG_CLUSTER, q); else queue_flag_set_unlocked(QUEUE_FLAG_CLUSTER, q); dm_table_set_integrity(t); + + /* + * QUEUE_FLAG_STACKABLE must be set after all queue settings are + * visible to other CPUs because, once the flag is set, incoming bios + * are processed by request-based dm, which refers to the queue + * settings. + * Until the flag set, bios are passed to bio-based dm and queued to + * md->deferred where queue settings are not needed yet. + * Those bios are passed to request-based dm at the resume time. + */ + smp_mb(); + if (dm_table_request_based(t)) + queue_flag_set_unlocked(QUEUE_FLAG_STACKABLE, q); } unsigned int dm_table_get_num_targets(struct dm_table *t) @@ -1021,6 +1196,20 @@ int dm_table_any_congested(struct dm_table *t, int bdi_bits) return r; } +int dm_table_any_busy_target(struct dm_table *t) +{ + unsigned i; + struct dm_target *ti; + + for (i = 0; i < t->num_targets; i++) { + ti = t->targets + i; + if (ti->type->busy && ti->type->busy(ti)) + return 1; + } + + return 0; +} + void dm_table_unplug_all(struct dm_table *t) { struct dm_dev_internal *dd; diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 424f7b048c30..3c6d4ee8921d 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -19,11 +19,18 @@ #include #include #include -#include -#include + +#include #define DM_MSG_PREFIX "core" +/* + * Cookies are numeric values sent with CHANGE and REMOVE + * uevents while resuming, removing or renaming the device. + */ +#define DM_COOKIE_ENV_VAR_NAME "DM_COOKIE" +#define DM_COOKIE_LENGTH 24 + static const char *_name = DM_NAME; static unsigned int major = 0; @@ -53,8 +60,6 @@ struct dm_target_io { union map_info info; }; -DEFINE_TRACE(block_bio_complete); - /* * For request-based dm. * One of these is allocated per request. @@ -73,7 +78,7 @@ struct dm_rq_target_io { */ struct dm_rq_clone_bio_info { struct bio *orig; - struct request *rq; + struct dm_rq_target_io *tio; }; union map_info *dm_get_mapinfo(struct bio *bio) @@ -83,6 +88,14 @@ union map_info *dm_get_mapinfo(struct bio *bio) return NULL; } +union map_info *dm_get_rq_mapinfo(struct request *rq) +{ + if (rq && rq->end_io_data) + return &((struct dm_rq_target_io *)rq->end_io_data)->info; + return NULL; +} +EXPORT_SYMBOL_GPL(dm_get_rq_mapinfo); + #define MINOR_ALLOCED ((void *)-1) /* @@ -159,13 +172,31 @@ struct mapped_device { * freeze/thaw support require holding onto a super block */ struct super_block *frozen_sb; - struct block_device *suspended_bdev; + struct block_device *bdev; /* forced geometry settings */ struct hd_geometry geometry; + /* marker of flush suspend for request-based dm */ + struct request suspend_rq; + + /* For saving the address of __make_request for request based dm */ + make_request_fn *saved_make_request_fn; + /* sysfs handle */ struct kobject kobj; + + /* zero-length barrier that will be cloned and submitted to targets */ + struct bio barrier_bio; +}; + +/* + * For mempools pre-allocation at the table loading time. + */ +struct dm_md_mempools { + mempool_t *io_pool; + mempool_t *tio_pool; + struct bio_set *bs; }; #define MIN_IOS 256 @@ -393,16 +424,31 @@ static void free_io(struct mapped_device *md, struct dm_io *io) mempool_free(io, md->io_pool); } -static struct dm_target_io *alloc_tio(struct mapped_device *md) -{ - return mempool_alloc(md->tio_pool, GFP_NOIO); -} - static void free_tio(struct mapped_device *md, struct dm_target_io *tio) { mempool_free(tio, md->tio_pool); } +static struct dm_rq_target_io *alloc_rq_tio(struct mapped_device *md) +{ + return mempool_alloc(md->tio_pool, GFP_ATOMIC); +} + +static void free_rq_tio(struct dm_rq_target_io *tio) +{ + mempool_free(tio, tio->md->tio_pool); +} + +static struct dm_rq_clone_bio_info *alloc_bio_info(struct mapped_device *md) +{ + return mempool_alloc(md->io_pool, GFP_ATOMIC); +} + +static void free_bio_info(struct dm_rq_clone_bio_info *info) +{ + mempool_free(info, info->tio->md->io_pool); +} + static void start_io_acct(struct dm_io *io) { struct mapped_device *md = io->md; @@ -466,12 +512,13 @@ static void queue_io(struct mapped_device *md, struct bio *bio) struct dm_table *dm_get_table(struct mapped_device *md) { struct dm_table *t; + unsigned long flags; - read_lock(&md->map_lock); + read_lock_irqsave(&md->map_lock, flags); t = md->map; if (t) dm_table_get(t); - read_unlock(&md->map_lock); + read_unlock_irqrestore(&md->map_lock, flags); return t; } @@ -538,9 +585,11 @@ static void dec_pending(struct dm_io *io, int error) * Target requested pushing back the I/O. */ spin_lock_irqsave(&md->deferred_lock, flags); - if (__noflush_suspending(md)) - bio_list_add_head(&md->deferred, io->bio); - else + if (__noflush_suspending(md)) { + if (!bio_barrier(io->bio)) + bio_list_add_head(&md->deferred, + io->bio); + } else /* noflush suspend was interrupted. */ io->error = -EIO; spin_unlock_irqrestore(&md->deferred_lock, flags); @@ -555,7 +604,8 @@ static void dec_pending(struct dm_io *io, int error) * a per-device variable for error reporting. * Note that you can't touch the bio after end_io_acct */ - md->barrier_error = io_error; + if (!md->barrier_error && io_error != -EOPNOTSUPP) + md->barrier_error = io_error; end_io_acct(io); } else { end_io_acct(io); @@ -609,6 +659,262 @@ static void clone_endio(struct bio *bio, int error) dec_pending(io, error); } +/* + * Partial completion handling for request-based dm + */ +static void end_clone_bio(struct bio *clone, int error) +{ + struct dm_rq_clone_bio_info *info = clone->bi_private; + struct dm_rq_target_io *tio = info->tio; + struct bio *bio = info->orig; + unsigned int nr_bytes = info->orig->bi_size; + + bio_put(clone); + + if (tio->error) + /* + * An error has already been detected on the request. + * Once error occurred, just let clone->end_io() handle + * the remainder. + */ + return; + else if (error) { + /* + * Don't notice the error to the upper layer yet. + * The error handling decision is made by the target driver, + * when the request is completed. + */ + tio->error = error; + return; + } + + /* + * I/O for the bio successfully completed. + * Notice the data completion to the upper layer. + */ + + /* + * bios are processed from the head of the list. + * So the completing bio should always be rq->bio. + * If it's not, something wrong is happening. + */ + if (tio->orig->bio != bio) + DMERR("bio completion is going in the middle of the request"); + + /* + * Update the original request. + * Do not use blk_end_request() here, because it may complete + * the original request before the clone, and break the ordering. + */ + blk_update_request(tio->orig, 0, nr_bytes); +} + +/* + * Don't touch any member of the md after calling this function because + * the md may be freed in dm_put() at the end of this function. + * Or do dm_get() before calling this function and dm_put() later. + */ +static void rq_completed(struct mapped_device *md, int run_queue) +{ + int wakeup_waiters = 0; + struct request_queue *q = md->queue; + unsigned long flags; + + spin_lock_irqsave(q->queue_lock, flags); + if (!queue_in_flight(q)) + wakeup_waiters = 1; + spin_unlock_irqrestore(q->queue_lock, flags); + + /* nudge anyone waiting on suspend queue */ + if (wakeup_waiters) + wake_up(&md->wait); + + if (run_queue) + blk_run_queue(q); + + /* + * dm_put() must be at the end of this function. See the comment above + */ + dm_put(md); +} + +static void dm_unprep_request(struct request *rq) +{ + struct request *clone = rq->special; + struct dm_rq_target_io *tio = clone->end_io_data; + + rq->special = NULL; + rq->cmd_flags &= ~REQ_DONTPREP; + + blk_rq_unprep_clone(clone); + free_rq_tio(tio); +} + +/* + * Requeue the original request of a clone. + */ +void dm_requeue_unmapped_request(struct request *clone) +{ + struct dm_rq_target_io *tio = clone->end_io_data; + struct mapped_device *md = tio->md; + struct request *rq = tio->orig; + struct request_queue *q = rq->q; + unsigned long flags; + + dm_unprep_request(rq); + + spin_lock_irqsave(q->queue_lock, flags); + if (elv_queue_empty(q)) + blk_plug_device(q); + blk_requeue_request(q, rq); + spin_unlock_irqrestore(q->queue_lock, flags); + + rq_completed(md, 0); +} +EXPORT_SYMBOL_GPL(dm_requeue_unmapped_request); + +static void __stop_queue(struct request_queue *q) +{ + blk_stop_queue(q); +} + +static void stop_queue(struct request_queue *q) +{ + unsigned long flags; + + spin_lock_irqsave(q->queue_lock, flags); + __stop_queue(q); + spin_unlock_irqrestore(q->queue_lock, flags); +} + +static void __start_queue(struct request_queue *q) +{ + if (blk_queue_stopped(q)) + blk_start_queue(q); +} + +static void start_queue(struct request_queue *q) +{ + unsigned long flags; + + spin_lock_irqsave(q->queue_lock, flags); + __start_queue(q); + spin_unlock_irqrestore(q->queue_lock, flags); +} + +/* + * Complete the clone and the original request. + * Must be called without queue lock. + */ +static void dm_end_request(struct request *clone, int error) +{ + struct dm_rq_target_io *tio = clone->end_io_data; + struct mapped_device *md = tio->md; + struct request *rq = tio->orig; + + if (blk_pc_request(rq)) { + rq->errors = clone->errors; + rq->resid_len = clone->resid_len; + + if (rq->sense) + /* + * We are using the sense buffer of the original + * request. + * So setting the length of the sense data is enough. + */ + rq->sense_len = clone->sense_len; + } + + BUG_ON(clone->bio); + free_rq_tio(tio); + + blk_end_request_all(rq, error); + + rq_completed(md, 1); +} + +/* + * Request completion handler for request-based dm + */ +static void dm_softirq_done(struct request *rq) +{ + struct request *clone = rq->completion_data; + struct dm_rq_target_io *tio = clone->end_io_data; + dm_request_endio_fn rq_end_io = tio->ti->type->rq_end_io; + int error = tio->error; + + if (!(rq->cmd_flags & REQ_FAILED) && rq_end_io) + error = rq_end_io(tio->ti, clone, error, &tio->info); + + if (error <= 0) + /* The target wants to complete the I/O */ + dm_end_request(clone, error); + else if (error == DM_ENDIO_INCOMPLETE) + /* The target will handle the I/O */ + return; + else if (error == DM_ENDIO_REQUEUE) + /* The target wants to requeue the I/O */ + dm_requeue_unmapped_request(clone); + else { + DMWARN("unimplemented target endio return value: %d", error); + BUG(); + } +} + +/* + * Complete the clone and the original request with the error status + * through softirq context. + */ +static void dm_complete_request(struct request *clone, int error) +{ + struct dm_rq_target_io *tio = clone->end_io_data; + struct request *rq = tio->orig; + + tio->error = error; + rq->completion_data = clone; + blk_complete_request(rq); +} + +/* + * Complete the not-mapped clone and the original request with the error status + * through softirq context. + * Target's rq_end_io() function isn't called. + * This may be used when the target's map_rq() function fails. + */ +void dm_kill_unmapped_request(struct request *clone, int error) +{ + struct dm_rq_target_io *tio = clone->end_io_data; + struct request *rq = tio->orig; + + rq->cmd_flags |= REQ_FAILED; + dm_complete_request(clone, error); +} +EXPORT_SYMBOL_GPL(dm_kill_unmapped_request); + +/* + * Called with the queue lock held + */ +static void end_clone_request(struct request *clone, int error) +{ + /* + * For just cleaning up the information of the queue in which + * the clone was dispatched. + * The clone is *NOT* freed actually here because it is alloced from + * dm own mempool and REQ_ALLOCED isn't set in clone->cmd_flags. + */ + __blk_put_request(clone->q, clone); + + /* + * Actual request completion is done in a softirq context which doesn't + * hold the queue lock. Otherwise, deadlock could occur because: + * - another request may be submitted by the upper level driver + * of the stacking during the completion + * - the submission which requires queue lock may be done + * against this queue + */ + dm_complete_request(clone, error); +} + static sector_t max_io_len(struct mapped_device *md, sector_t sector, struct dm_target *ti) { @@ -636,11 +942,6 @@ static void __map_bio(struct dm_target *ti, struct bio *clone, sector_t sector; struct mapped_device *md; - /* - * Sanity checks. - */ - BUG_ON(!clone->bi_size); - clone->bi_end_io = clone_endio; clone->bi_private = tio; @@ -656,8 +957,7 @@ static void __map_bio(struct dm_target *ti, struct bio *clone, /* the bio has been remapped so dispatch it */ trace_block_remap(bdev_get_queue(clone->bi_bdev), clone, - tio->io->bio->bi_bdev->bd_dev, - clone->bi_sector, sector); + tio->io->bio->bi_bdev->bd_dev, sector); generic_make_request(clone); } else if (r < 0 || r == DM_MAPIO_REQUEUE) { @@ -755,6 +1055,48 @@ static struct bio *clone_bio(struct bio *bio, sector_t sector, return clone; } +static struct dm_target_io *alloc_tio(struct clone_info *ci, + struct dm_target *ti) +{ + struct dm_target_io *tio = mempool_alloc(ci->md->tio_pool, GFP_NOIO); + + tio->io = ci->io; + tio->ti = ti; + memset(&tio->info, 0, sizeof(tio->info)); + + return tio; +} + +static void __flush_target(struct clone_info *ci, struct dm_target *ti, + unsigned flush_nr) +{ + struct dm_target_io *tio = alloc_tio(ci, ti); + struct bio *clone; + + tio->info.flush_request = flush_nr; + + clone = bio_alloc_bioset(GFP_NOIO, 0, ci->md->bs); + __bio_clone(clone, ci->bio); + clone->bi_destructor = dm_bio_destructor; + + __map_bio(ti, clone, tio); +} + +static int __clone_and_map_empty_barrier(struct clone_info *ci) +{ + unsigned target_nr = 0, flush_nr; + struct dm_target *ti; + + while ((ti = dm_table_get_target(ci->map, target_nr++))) + for (flush_nr = 0; flush_nr < ti->num_flush_requests; + flush_nr++) + __flush_target(ci, ti, flush_nr); + + ci->sector_count = 0; + + return 0; +} + static int __clone_and_map(struct clone_info *ci) { struct bio *clone, *bio = ci->bio; @@ -762,6 +1104,9 @@ static int __clone_and_map(struct clone_info *ci) sector_t len = 0, max; struct dm_target_io *tio; + if (unlikely(bio_empty_barrier(bio))) + return __clone_and_map_empty_barrier(ci); + ti = dm_table_find_target(ci->map, ci->sector); if (!dm_target_is_valid(ti)) return -EIO; @@ -771,10 +1116,7 @@ static int __clone_and_map(struct clone_info *ci) /* * Allocate a target io object. */ - tio = alloc_tio(ci->md); - tio->io = ci->io; - tio->ti = ti; - memset(&tio->info, 0, sizeof(tio->info)); + tio = alloc_tio(ci, ti); if (ci->sector_count <= max) { /* @@ -830,10 +1172,7 @@ static int __clone_and_map(struct clone_info *ci) max = max_io_len(ci->md, ci->sector, ti); - tio = alloc_tio(ci->md); - tio->io = ci->io; - tio->ti = ti; - memset(&tio->info, 0, sizeof(tio->info)); + tio = alloc_tio(ci, ti); } len = min(remaining, max); @@ -868,7 +1207,8 @@ static void __split_and_process_bio(struct mapped_device *md, struct bio *bio) if (!bio_barrier(bio)) bio_io_error(bio); else - md->barrier_error = -EIO; + if (!md->barrier_error) + md->barrier_error = -EIO; return; } @@ -881,6 +1221,8 @@ static void __split_and_process_bio(struct mapped_device *md, struct bio *bio) ci.io->md = md; ci.sector = bio->bi_sector; ci.sector_count = bio_sectors(bio); + if (unlikely(bio_empty_barrier(bio))) + ci.sector_count = 1; ci.idx = bio->bi_idx; start_io_acct(ci.io); @@ -928,6 +1270,16 @@ static int dm_merge_bvec(struct request_queue *q, */ if (max_size && ti->type->merge) max_size = ti->type->merge(ti, bvm, biovec, max_size); + /* + * If the target doesn't support merge method and some of the devices + * provided their merge_bvec method (we know this by looking at + * queue_max_hw_sectors), then we can't allow bios with multiple vector + * entries. So always set max_size to 0, and the code below allows + * just one page. + */ + else if (queue_max_hw_sectors(q) <= PAGE_SIZE >> 9) + + max_size = 0; out_table: dm_table_put(map); @@ -946,7 +1298,7 @@ out: * The request function that just remaps the bio built up by * dm_merge_bvec. */ -static int dm_request(struct request_queue *q, struct bio *bio) +static int _dm_request(struct request_queue *q, struct bio *bio) { int rw = bio_data_dir(bio); struct mapped_device *md = q->queuedata; @@ -983,12 +1335,274 @@ static int dm_request(struct request_queue *q, struct bio *bio) return 0; } +static int dm_make_request(struct request_queue *q, struct bio *bio) +{ + struct mapped_device *md = q->queuedata; + + if (unlikely(bio_barrier(bio))) { + bio_endio(bio, -EOPNOTSUPP); + return 0; + } + + return md->saved_make_request_fn(q, bio); /* call __make_request() */ +} + +static int dm_request_based(struct mapped_device *md) +{ + return blk_queue_stackable(md->queue); +} + +static int dm_request(struct request_queue *q, struct bio *bio) +{ + struct mapped_device *md = q->queuedata; + + if (dm_request_based(md)) + return dm_make_request(q, bio); + + return _dm_request(q, bio); +} + +void dm_dispatch_request(struct request *rq) +{ + int r; + + if (blk_queue_io_stat(rq->q)) + rq->cmd_flags |= REQ_IO_STAT; + + rq->start_time = jiffies; + r = blk_insert_cloned_request(rq->q, rq); + if (r) + dm_complete_request(rq, r); +} +EXPORT_SYMBOL_GPL(dm_dispatch_request); + +static void dm_rq_bio_destructor(struct bio *bio) +{ + struct dm_rq_clone_bio_info *info = bio->bi_private; + struct mapped_device *md = info->tio->md; + + free_bio_info(info); + bio_free(bio, md->bs); +} + +static int dm_rq_bio_constructor(struct bio *bio, struct bio *bio_orig, + void *data) +{ + struct dm_rq_target_io *tio = data; + struct mapped_device *md = tio->md; + struct dm_rq_clone_bio_info *info = alloc_bio_info(md); + + if (!info) + return -ENOMEM; + + info->orig = bio_orig; + info->tio = tio; + bio->bi_end_io = end_clone_bio; + bio->bi_private = info; + bio->bi_destructor = dm_rq_bio_destructor; + + return 0; +} + +static int setup_clone(struct request *clone, struct request *rq, + struct dm_rq_target_io *tio) +{ + int r = blk_rq_prep_clone(clone, rq, tio->md->bs, GFP_ATOMIC, + dm_rq_bio_constructor, tio); + + if (r) + return r; + + clone->cmd = rq->cmd; + clone->cmd_len = rq->cmd_len; + clone->sense = rq->sense; + clone->buffer = rq->buffer; + clone->end_io = end_clone_request; + clone->end_io_data = tio; + + return 0; +} + +static int dm_rq_flush_suspending(struct mapped_device *md) +{ + return !md->suspend_rq.special; +} + +/* + * Called with the queue lock held. + */ +static int dm_prep_fn(struct request_queue *q, struct request *rq) +{ + struct mapped_device *md = q->queuedata; + struct dm_rq_target_io *tio; + struct request *clone; + + if (unlikely(rq == &md->suspend_rq)) { + if (dm_rq_flush_suspending(md)) + return BLKPREP_OK; + else + /* The flush suspend was interrupted */ + return BLKPREP_KILL; + } + + if (unlikely(rq->special)) { + DMWARN("Already has something in rq->special."); + return BLKPREP_KILL; + } + + tio = alloc_rq_tio(md); /* Only one for each original request */ + if (!tio) + /* -ENOMEM */ + return BLKPREP_DEFER; + + tio->md = md; + tio->ti = NULL; + tio->orig = rq; + tio->error = 0; + memset(&tio->info, 0, sizeof(tio->info)); + + clone = &tio->clone; + if (setup_clone(clone, rq, tio)) { + /* -ENOMEM */ + free_rq_tio(tio); + return BLKPREP_DEFER; + } + + rq->special = clone; + rq->cmd_flags |= REQ_DONTPREP; + + return BLKPREP_OK; +} + +static void map_request(struct dm_target *ti, struct request *rq, + struct mapped_device *md) +{ + int r; + struct request *clone = rq->special; + struct dm_rq_target_io *tio = clone->end_io_data; + + /* + * Hold the md reference here for the in-flight I/O. + * We can't rely on the reference count by device opener, + * because the device may be closed during the request completion + * when all bios are completed. + * See the comment in rq_completed() too. + */ + dm_get(md); + + tio->ti = ti; + r = ti->type->map_rq(ti, clone, &tio->info); + switch (r) { + case DM_MAPIO_SUBMITTED: + /* The target has taken the I/O to submit by itself later */ + break; + case DM_MAPIO_REMAPPED: + /* The target has remapped the I/O so dispatch it */ + dm_dispatch_request(clone); + break; + case DM_MAPIO_REQUEUE: + /* The target wants to requeue the I/O */ + dm_requeue_unmapped_request(clone); + break; + default: + if (r > 0) { + DMWARN("unimplemented target map return value: %d", r); + BUG(); + } + + /* The target wants to complete the I/O */ + dm_kill_unmapped_request(clone, r); + break; + } +} + +/* + * q->request_fn for request-based dm. + * Called with the queue lock held. + */ +static void dm_request_fn(struct request_queue *q) +{ + struct mapped_device *md = q->queuedata; + struct dm_table *map = dm_get_table(md); + struct dm_target *ti; + struct request *rq; + + /* + * For noflush suspend, check blk_queue_stopped() to immediately + * quit I/O dispatching. + */ + while (!blk_queue_plugged(q) && !blk_queue_stopped(q)) { + rq = blk_peek_request(q); + if (!rq) + goto plug_and_out; + + if (unlikely(rq == &md->suspend_rq)) { /* Flush suspend maker */ + if (queue_in_flight(q)) + /* Not quiet yet. Wait more */ + goto plug_and_out; + + /* This device should be quiet now */ + __stop_queue(q); + blk_start_request(rq); + __blk_end_request_all(rq, 0); + wake_up(&md->wait); + goto out; + } + + ti = dm_table_find_target(map, blk_rq_pos(rq)); + if (ti->type->busy && ti->type->busy(ti)) + goto plug_and_out; + + blk_start_request(rq); + spin_unlock(q->queue_lock); + map_request(ti, rq, md); + spin_lock_irq(q->queue_lock); + } + + goto out; + +plug_and_out: + if (!elv_queue_empty(q)) + /* Some requests still remain, retry later */ + blk_plug_device(q); + +out: + dm_table_put(map); + + return; +} + +int dm_underlying_device_busy(struct request_queue *q) +{ + return blk_lld_busy(q); +} +EXPORT_SYMBOL_GPL(dm_underlying_device_busy); + +static int dm_lld_busy(struct request_queue *q) +{ + int r; + struct mapped_device *md = q->queuedata; + struct dm_table *map = dm_get_table(md); + + if (!map || test_bit(DMF_BLOCK_IO_FOR_SUSPEND, &md->flags)) + r = 1; + else + r = dm_table_any_busy_target(map); + + dm_table_put(map); + + return r; +} + static void dm_unplug_all(struct request_queue *q) { struct mapped_device *md = q->queuedata; struct dm_table *map = dm_get_table(md); if (map) { + if (dm_request_based(md)) + generic_unplug_device(q); + dm_table_unplug_all(map); dm_table_put(map); } @@ -1003,7 +1617,16 @@ static int dm_any_congested(void *congested_data, int bdi_bits) if (!test_bit(DMF_BLOCK_IO_FOR_SUSPEND, &md->flags)) { map = dm_get_table(md); if (map) { - r = dm_table_any_congested(map, bdi_bits); + /* + * Request-based dm cares about only own queue for + * the query about congestion status of request_queue + */ + if (dm_request_based(md)) + r = md->queue->backing_dev_info.state & + bdi_bits; + else + r = dm_table_any_congested(map, bdi_bits); + dm_table_put(map); } } @@ -1126,30 +1749,32 @@ static struct mapped_device *alloc_dev(int minor) INIT_LIST_HEAD(&md->uevent_list); spin_lock_init(&md->uevent_lock); - md->queue = blk_alloc_queue(GFP_KERNEL); + md->queue = blk_init_queue(dm_request_fn, NULL); if (!md->queue) goto bad_queue; + /* + * Request-based dm devices cannot be stacked on top of bio-based dm + * devices. The type of this dm device has not been decided yet, + * although we initialized the queue using blk_init_queue(). + * The type is decided at the first table loading time. + * To prevent problematic device stacking, clear the queue flag + * for request stacking support until then. + * + * This queue is new, so no concurrency on the queue_flags. + */ + queue_flag_clear_unlocked(QUEUE_FLAG_STACKABLE, md->queue); + md->saved_make_request_fn = md->queue->make_request_fn; md->queue->queuedata = md; md->queue->backing_dev_info.congested_fn = dm_any_congested; md->queue->backing_dev_info.congested_data = md; blk_queue_make_request(md->queue, dm_request); - blk_queue_ordered(md->queue, QUEUE_ORDERED_DRAIN, NULL); blk_queue_bounce_limit(md->queue, BLK_BOUNCE_ANY); md->queue->unplug_fn = dm_unplug_all; blk_queue_merge_bvec(md->queue, dm_merge_bvec); - - md->io_pool = mempool_create_slab_pool(MIN_IOS, _io_cache); - if (!md->io_pool) - goto bad_io_pool; - - md->tio_pool = mempool_create_slab_pool(MIN_IOS, _tio_cache); - if (!md->tio_pool) - goto bad_tio_pool; - - md->bs = bioset_create(16, 0); - if (!md->bs) - goto bad_no_bioset; + blk_queue_softirq_done(md->queue, dm_softirq_done); + blk_queue_prep_rq(md->queue, dm_prep_fn); + blk_queue_lld_busy(md->queue, dm_lld_busy); md->disk = alloc_disk(1); if (!md->disk) @@ -1173,6 +1798,10 @@ static struct mapped_device *alloc_dev(int minor) if (!md->wq) goto bad_thread; + md->bdev = bdget_disk(md->disk, 0); + if (!md->bdev) + goto bad_bdev; + /* Populate the mapping, nobody knows we exist yet */ spin_lock(&_minor_lock); old_md = idr_replace(&_minor_idr, md, minor); @@ -1182,15 +1811,11 @@ static struct mapped_device *alloc_dev(int minor) return md; +bad_bdev: + destroy_workqueue(md->wq); bad_thread: put_disk(md->disk); bad_disk: - bioset_free(md->bs); -bad_no_bioset: - mempool_destroy(md->tio_pool); -bad_tio_pool: - mempool_destroy(md->io_pool); -bad_io_pool: blk_cleanup_queue(md->queue); bad_queue: free_minor(minor); @@ -1207,14 +1832,15 @@ static void free_dev(struct mapped_device *md) { int minor = MINOR(disk_devt(md->disk)); - if (md->suspended_bdev) { - unlock_fs(md); - bdput(md->suspended_bdev); - } + unlock_fs(md); + bdput(md->bdev); destroy_workqueue(md->wq); - mempool_destroy(md->tio_pool); - mempool_destroy(md->io_pool); - bioset_free(md->bs); + if (md->tio_pool) + mempool_destroy(md->tio_pool); + if (md->io_pool) + mempool_destroy(md->io_pool); + if (md->bs) + bioset_free(md->bs); blk_integrity_unregister(md->disk); del_gendisk(md->disk); free_minor(minor); @@ -1229,6 +1855,29 @@ static void free_dev(struct mapped_device *md) kfree(md); } +static void __bind_mempools(struct mapped_device *md, struct dm_table *t) +{ + struct dm_md_mempools *p; + + if (md->io_pool && md->tio_pool && md->bs) + /* the md already has necessary mempools */ + goto out; + + p = dm_table_get_md_mempools(t); + BUG_ON(!p || md->io_pool || md->tio_pool || md->bs); + + md->io_pool = p->io_pool; + p->io_pool = NULL; + md->tio_pool = p->tio_pool; + p->tio_pool = NULL; + md->bs = p->bs; + p->bs = NULL; + +out: + /* mempool bind completed, now no need any mempools in the table */ + dm_table_free_md_mempools(t); +} + /* * Bind a table to the device. */ @@ -1252,15 +1901,17 @@ static void __set_size(struct mapped_device *md, sector_t size) { set_capacity(md->disk, size); - mutex_lock(&md->suspended_bdev->bd_inode->i_mutex); - i_size_write(md->suspended_bdev->bd_inode, (loff_t)size << SECTOR_SHIFT); - mutex_unlock(&md->suspended_bdev->bd_inode->i_mutex); + mutex_lock(&md->bdev->bd_inode->i_mutex); + i_size_write(md->bdev->bd_inode, (loff_t)size << SECTOR_SHIFT); + mutex_unlock(&md->bdev->bd_inode->i_mutex); } -static int __bind(struct mapped_device *md, struct dm_table *t) +static int __bind(struct mapped_device *md, struct dm_table *t, + struct queue_limits *limits) { struct request_queue *q = md->queue; sector_t size; + unsigned long flags; size = dm_table_get_size(t); @@ -1270,8 +1921,7 @@ static int __bind(struct mapped_device *md, struct dm_table *t) if (size != get_capacity(md->disk)) memset(&md->geometry, 0, sizeof(md->geometry)); - if (md->suspended_bdev) - __set_size(md, size); + __set_size(md, size); if (!size) { dm_table_destroy(t); @@ -1280,10 +1930,22 @@ static int __bind(struct mapped_device *md, struct dm_table *t) dm_table_event_callback(t, event_callback, md); - write_lock(&md->map_lock); + /* + * The queue hasn't been stopped yet, if the old table type wasn't + * for request-based during suspension. So stop it to prevent + * I/O mapping before resume. + * This must be done before setting the queue restrictions, + * because request-based dm may be run just after the setting. + */ + if (dm_table_request_based(t) && !blk_queue_stopped(q)) + stop_queue(q); + + __bind_mempools(md, t); + + write_lock_irqsave(&md->map_lock, flags); md->map = t; - dm_table_set_restrictions(t, q); - write_unlock(&md->map_lock); + dm_table_set_restrictions(t, q, limits); + write_unlock_irqrestore(&md->map_lock, flags); return 0; } @@ -1291,14 +1953,15 @@ static int __bind(struct mapped_device *md, struct dm_table *t) static void __unbind(struct mapped_device *md) { struct dm_table *map = md->map; + unsigned long flags; if (!map) return; dm_table_event_callback(map, NULL, NULL); - write_lock(&md->map_lock); + write_lock_irqsave(&md->map_lock, flags); md->map = NULL; - write_unlock(&md->map_lock); + write_unlock_irqrestore(&md->map_lock, flags); dm_table_destroy(map); } @@ -1402,6 +2065,8 @@ static int dm_wait_for_completion(struct mapped_device *md, int interruptible) { int r = 0; DECLARE_WAITQUEUE(wait, current); + struct request_queue *q = md->queue; + unsigned long flags; dm_unplug_all(md->queue); @@ -1411,7 +2076,14 @@ static int dm_wait_for_completion(struct mapped_device *md, int interruptible) set_current_state(interruptible); smp_mb(); - if (!atomic_read(&md->pending)) + if (dm_request_based(md)) { + spin_lock_irqsave(q->queue_lock, flags); + if (!queue_in_flight(q) && blk_queue_stopped(q)) { + spin_unlock_irqrestore(q->queue_lock, flags); + break; + } + spin_unlock_irqrestore(q->queue_lock, flags); + } else if (!atomic_read(&md->pending)) break; if (interruptible == TASK_INTERRUPTIBLE && @@ -1429,34 +2101,36 @@ static int dm_wait_for_completion(struct mapped_device *md, int interruptible) return r; } -static int dm_flush(struct mapped_device *md) +static void dm_flush(struct mapped_device *md) { dm_wait_for_completion(md, TASK_UNINTERRUPTIBLE); - return 0; + + bio_init(&md->barrier_bio); + md->barrier_bio.bi_bdev = md->bdev; + md->barrier_bio.bi_rw = WRITE_BARRIER; + __split_and_process_bio(md, &md->barrier_bio); + + dm_wait_for_completion(md, TASK_UNINTERRUPTIBLE); } static void process_barrier(struct mapped_device *md, struct bio *bio) { - int error = dm_flush(md); + md->barrier_error = 0; - if (unlikely(error)) { - bio_endio(bio, error); - return; + dm_flush(md); + + if (!bio_empty_barrier(bio)) { + __split_and_process_bio(md, bio); + dm_flush(md); } - if (bio_empty_barrier(bio)) { - bio_endio(bio, 0); - return; - } - - __split_and_process_bio(md, bio); - - error = dm_flush(md); - - if (!error && md->barrier_error) - error = md->barrier_error; if (md->barrier_error != DM_ENDIO_REQUEUE) - bio_endio(bio, error); + bio_endio(bio, md->barrier_error); + else { + spin_lock_irq(&md->deferred_lock); + bio_list_add_head(&md->deferred, bio); + spin_unlock_irq(&md->deferred_lock); + } } /* @@ -1482,10 +2156,14 @@ static void dm_wq_work(struct work_struct *work) up_write(&md->io_lock); - if (bio_barrier(c)) - process_barrier(md, c); - else - __split_and_process_bio(md, c); + if (dm_request_based(md)) + generic_make_request(c); + else { + if (bio_barrier(c)) + process_barrier(md, c); + else + __split_and_process_bio(md, c); + } down_write(&md->io_lock); } @@ -1505,6 +2183,7 @@ static void dm_queue_flush(struct mapped_device *md) */ int dm_swap_table(struct mapped_device *md, struct dm_table *table) { + struct queue_limits limits; int r = -EINVAL; mutex_lock(&md->suspend_lock); @@ -1513,19 +2192,96 @@ int dm_swap_table(struct mapped_device *md, struct dm_table *table) if (!dm_suspended(md)) goto out; - /* without bdev, the device size cannot be changed */ - if (!md->suspended_bdev) - if (get_capacity(md->disk) != dm_table_get_size(table)) - goto out; + r = dm_calculate_queue_limits(table, &limits); + if (r) + goto out; + + /* cannot change the device type, once a table is bound */ + if (md->map && + (dm_table_get_type(md->map) != dm_table_get_type(table))) { + DMWARN("can't change the device type after a table is bound"); + goto out; + } + + /* + * It is enought that blk_queue_ordered() is called only once when + * the first bio-based table is bound. + * + * This setting should be moved to alloc_dev() when request-based dm + * supports barrier. + */ + if (!md->map && dm_table_bio_based(table)) + blk_queue_ordered(md->queue, QUEUE_ORDERED_DRAIN, NULL); __unbind(md); - r = __bind(md, table); + r = __bind(md, table, &limits); out: mutex_unlock(&md->suspend_lock); return r; } +static void dm_rq_invalidate_suspend_marker(struct mapped_device *md) +{ + md->suspend_rq.special = (void *)0x1; +} + +static void dm_rq_abort_suspend(struct mapped_device *md, int noflush) +{ + struct request_queue *q = md->queue; + unsigned long flags; + + spin_lock_irqsave(q->queue_lock, flags); + if (!noflush) + dm_rq_invalidate_suspend_marker(md); + __start_queue(q); + spin_unlock_irqrestore(q->queue_lock, flags); +} + +static void dm_rq_start_suspend(struct mapped_device *md, int noflush) +{ + struct request *rq = &md->suspend_rq; + struct request_queue *q = md->queue; + + if (noflush) + stop_queue(q); + else { + blk_rq_init(q, rq); + blk_insert_request(q, rq, 0, NULL); + } +} + +static int dm_rq_suspend_available(struct mapped_device *md, int noflush) +{ + int r = 1; + struct request *rq = &md->suspend_rq; + struct request_queue *q = md->queue; + unsigned long flags; + + if (noflush) + return r; + + /* The marker must be protected by queue lock if it is in use */ + spin_lock_irqsave(q->queue_lock, flags); + if (unlikely(rq->ref_count)) { + /* + * This can happen, when the previous flush suspend was + * interrupted, the marker is still in the queue and + * this flush suspend has been invoked, because we don't + * remove the marker at the time of suspend interruption. + * We have only one marker per mapped_device, so we can't + * start another flush suspend while it is in use. + */ + BUG_ON(!rq->special); /* The marker should be invalidated */ + DMWARN("Invalidating the previous flush suspend is still in" + " progress. Please retry later."); + r = 0; + } + spin_unlock_irqrestore(q->queue_lock, flags); + + return r; +} + /* * Functions to lock and unlock any filesystem running on the * device. @@ -1536,7 +2292,7 @@ static int lock_fs(struct mapped_device *md) WARN_ON(md->frozen_sb); - md->frozen_sb = freeze_bdev(md->suspended_bdev); + md->frozen_sb = freeze_bdev(md->bdev); if (IS_ERR(md->frozen_sb)) { r = PTR_ERR(md->frozen_sb); md->frozen_sb = NULL; @@ -1545,9 +2301,6 @@ static int lock_fs(struct mapped_device *md) set_bit(DMF_FROZEN, &md->flags); - /* don't bdput right now, we don't want the bdev - * to go away while it is locked. - */ return 0; } @@ -1556,7 +2309,7 @@ static void unlock_fs(struct mapped_device *md) if (!test_bit(DMF_FROZEN, &md->flags)) return; - thaw_bdev(md->suspended_bdev, md->frozen_sb); + thaw_bdev(md->bdev, md->frozen_sb); md->frozen_sb = NULL; clear_bit(DMF_FROZEN, &md->flags); } @@ -1568,6 +2321,53 @@ static void unlock_fs(struct mapped_device *md) * dm_bind_table, dm_suspend must be called to flush any in * flight bios and ensure that any further io gets deferred. */ +/* + * Suspend mechanism in request-based dm. + * + * After the suspend starts, further incoming requests are kept in + * the request_queue and deferred. + * Remaining requests in the request_queue at the start of suspend are flushed + * if it is flush suspend. + * The suspend completes when the following conditions have been satisfied, + * so wait for it: + * 1. q->in_flight is 0 (which means no in_flight request) + * 2. queue has been stopped (which means no request dispatching) + * + * + * Noflush suspend + * --------------- + * Noflush suspend doesn't need to dispatch remaining requests. + * So stop the queue immediately. Then, wait for all in_flight requests + * to be completed or requeued. + * + * To abort noflush suspend, start the queue. + * + * + * Flush suspend + * ------------- + * Flush suspend needs to dispatch remaining requests. So stop the queue + * after the remaining requests are completed. (Requeued request must be also + * re-dispatched and completed. Until then, we can't stop the queue.) + * + * During flushing the remaining requests, further incoming requests are also + * inserted to the same queue. To distinguish which requests are to be + * flushed, we insert a marker request to the queue at the time of starting + * flush suspend, like a barrier. + * The dispatching is blocked when the marker is found on the top of the queue. + * And the queue is stopped when all in_flight requests are completed, since + * that means the remaining requests are completely flushed. + * Then, the marker is removed from the queue. + * + * To abort flush suspend, we also need to take care of the marker, not only + * starting the queue. + * We don't remove the marker forcibly from the queue since it's against + * the block-layer manner. Instead, we put a invalidated mark on the marker. + * When the invalidated marker is found on the top of the queue, it is + * immediately removed from the queue, so it doesn't block dispatching. + * Because we have only one marker per mapped_device, we can't start another + * flush suspend until the invalidated marker is removed from the queue. + * So fail and return with -EBUSY in such a case. + */ int dm_suspend(struct mapped_device *md, unsigned suspend_flags) { struct dm_table *map = NULL; @@ -1582,6 +2382,11 @@ int dm_suspend(struct mapped_device *md, unsigned suspend_flags) goto out_unlock; } + if (dm_request_based(md) && !dm_rq_suspend_available(md, noflush)) { + r = -EBUSY; + goto out_unlock; + } + map = dm_get_table(md); /* @@ -1594,24 +2399,14 @@ int dm_suspend(struct mapped_device *md, unsigned suspend_flags) /* This does not get reverted if there's an error later. */ dm_table_presuspend_targets(map); - /* bdget() can stall if the pending I/Os are not flushed */ - if (!noflush) { - md->suspended_bdev = bdget_disk(md->disk, 0); - if (!md->suspended_bdev) { - DMWARN("bdget failed in dm_suspend"); - r = -ENOMEM; + /* + * Flush I/O to the device. noflush supersedes do_lockfs, + * because lock_fs() needs to flush I/Os. + */ + if (!noflush && do_lockfs) { + r = lock_fs(md); + if (r) goto out; - } - - /* - * Flush I/O to the device. noflush supersedes do_lockfs, - * because lock_fs() needs to flush I/Os. - */ - if (do_lockfs) { - r = lock_fs(md); - if (r) - goto out; - } } /* @@ -1637,6 +2432,9 @@ int dm_suspend(struct mapped_device *md, unsigned suspend_flags) flush_workqueue(md->wq); + if (dm_request_based(md)) + dm_rq_start_suspend(md, noflush); + /* * At this point no more requests are entering target request routines. * We call dm_wait_for_completion to wait for all existing requests @@ -1653,6 +2451,9 @@ int dm_suspend(struct mapped_device *md, unsigned suspend_flags) if (r < 0) { dm_queue_flush(md); + if (dm_request_based(md)) + dm_rq_abort_suspend(md, noflush); + unlock_fs(md); goto out; /* pushback list is already flushed, so skip flush */ } @@ -1668,11 +2469,6 @@ int dm_suspend(struct mapped_device *md, unsigned suspend_flags) set_bit(DMF_SUSPENDED, &md->flags); out: - if (r && md->suspended_bdev) { - bdput(md->suspended_bdev); - md->suspended_bdev = NULL; - } - dm_table_put(map); out_unlock: @@ -1699,21 +2495,20 @@ int dm_resume(struct mapped_device *md) dm_queue_flush(md); - unlock_fs(md); + /* + * Flushing deferred I/Os must be done after targets are resumed + * so that mapping of targets can work correctly. + * Request-based dm is queueing the deferred I/Os in its request_queue. + */ + if (dm_request_based(md)) + start_queue(md->queue); - if (md->suspended_bdev) { - bdput(md->suspended_bdev); - md->suspended_bdev = NULL; - } + unlock_fs(md); clear_bit(DMF_SUSPENDED, &md->flags); dm_table_unplug_all(map); - - dm_kobject_uevent(md); - r = 0; - out: dm_table_put(map); mutex_unlock(&md->suspend_lock); @@ -1724,9 +2519,19 @@ out: /*----------------------------------------------------------------- * Event notification. *---------------------------------------------------------------*/ -void dm_kobject_uevent(struct mapped_device *md) +void dm_kobject_uevent(struct mapped_device *md, enum kobject_action action, + unsigned cookie) { - kobject_uevent(&disk_to_dev(md->disk)->kobj, KOBJ_CHANGE); + char udev_cookie[DM_COOKIE_LENGTH]; + char *envp[] = { udev_cookie, NULL }; + + if (!cookie) + kobject_uevent(&disk_to_dev(md->disk)->kobj, action); + else { + snprintf(udev_cookie, DM_COOKIE_LENGTH, "%s=%u", + DM_COOKIE_ENV_VAR_NAME, cookie); + kobject_uevent_env(&disk_to_dev(md->disk)->kobj, action, envp); + } } uint32_t dm_next_uevent_seq(struct mapped_device *md) @@ -1780,6 +2585,10 @@ struct mapped_device *dm_get_from_kobject(struct kobject *kobj) if (&md->kobj != kobj) return NULL; + if (test_bit(DMF_FREEING, &md->flags) || + test_bit(DMF_DELETING, &md->flags)) + return NULL; + dm_get(md); return md; } @@ -1800,6 +2609,61 @@ int dm_noflush_suspending(struct dm_target *ti) } EXPORT_SYMBOL_GPL(dm_noflush_suspending); +struct dm_md_mempools *dm_alloc_md_mempools(unsigned type) +{ + struct dm_md_mempools *pools = kmalloc(sizeof(*pools), GFP_KERNEL); + + if (!pools) + return NULL; + + pools->io_pool = (type == DM_TYPE_BIO_BASED) ? + mempool_create_slab_pool(MIN_IOS, _io_cache) : + mempool_create_slab_pool(MIN_IOS, _rq_bio_info_cache); + if (!pools->io_pool) + goto free_pools_and_out; + + pools->tio_pool = (type == DM_TYPE_BIO_BASED) ? + mempool_create_slab_pool(MIN_IOS, _tio_cache) : + mempool_create_slab_pool(MIN_IOS, _rq_tio_cache); + if (!pools->tio_pool) + goto free_io_pool_and_out; + + pools->bs = (type == DM_TYPE_BIO_BASED) ? + bioset_create(16, 0) : bioset_create(MIN_IOS, 0); + if (!pools->bs) + goto free_tio_pool_and_out; + + return pools; + +free_tio_pool_and_out: + mempool_destroy(pools->tio_pool); + +free_io_pool_and_out: + mempool_destroy(pools->io_pool); + +free_pools_and_out: + kfree(pools); + + return NULL; +} + +void dm_free_md_mempools(struct dm_md_mempools *pools) +{ + if (!pools) + return; + + if (pools->io_pool) + mempool_destroy(pools->io_pool); + + if (pools->tio_pool) + mempool_destroy(pools->tio_pool); + + if (pools->bs) + bioset_free(pools->bs); + + kfree(pools); +} + static struct block_device_operations dm_blk_dops = { .open = dm_blk_open, .release = dm_blk_close, diff --git a/drivers/md/dm.h b/drivers/md/dm.h index a31506d93e91..23278ae80f08 100644 --- a/drivers/md/dm.h +++ b/drivers/md/dm.h @@ -22,6 +22,13 @@ #define DM_SUSPEND_LOCKFS_FLAG (1 << 0) #define DM_SUSPEND_NOFLUSH_FLAG (1 << 1) +/* + * Type of table and mapped_device's mempool + */ +#define DM_TYPE_NONE 0 +#define DM_TYPE_BIO_BASED 1 +#define DM_TYPE_REQUEST_BASED 2 + /* * List of devices that a metadevice uses and should open/close. */ @@ -32,6 +39,7 @@ struct dm_dev_internal { }; struct dm_table; +struct dm_md_mempools; /*----------------------------------------------------------------- * Internal table functions. @@ -41,18 +49,34 @@ void dm_table_event_callback(struct dm_table *t, void (*fn)(void *), void *context); struct dm_target *dm_table_get_target(struct dm_table *t, unsigned int index); struct dm_target *dm_table_find_target(struct dm_table *t, sector_t sector); -void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q); +int dm_calculate_queue_limits(struct dm_table *table, + struct queue_limits *limits); +void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q, + struct queue_limits *limits); struct list_head *dm_table_get_devices(struct dm_table *t); void dm_table_presuspend_targets(struct dm_table *t); void dm_table_postsuspend_targets(struct dm_table *t); int dm_table_resume_targets(struct dm_table *t); int dm_table_any_congested(struct dm_table *t, int bdi_bits); +int dm_table_any_busy_target(struct dm_table *t); +int dm_table_set_type(struct dm_table *t); +unsigned dm_table_get_type(struct dm_table *t); +bool dm_table_bio_based(struct dm_table *t); +bool dm_table_request_based(struct dm_table *t); +int dm_table_alloc_md_mempools(struct dm_table *t); +void dm_table_free_md_mempools(struct dm_table *t); +struct dm_md_mempools *dm_table_get_md_mempools(struct dm_table *t); /* * To check the return value from dm_table_find_target(). */ #define dm_target_is_valid(t) ((t)->table) +/* + * To check whether the target type is request-based or not (bio-based). + */ +#define dm_target_request_based(t) ((t)->type->map_rq != NULL) + /*----------------------------------------------------------------- * A registry of target types. *---------------------------------------------------------------*/ @@ -92,9 +116,16 @@ void dm_stripe_exit(void); int dm_open_count(struct mapped_device *md); int dm_lock_for_deletion(struct mapped_device *md); -void dm_kobject_uevent(struct mapped_device *md); +void dm_kobject_uevent(struct mapped_device *md, enum kobject_action action, + unsigned cookie); int dm_kcopyd_init(void); void dm_kcopyd_exit(void); +/* + * Mempool operations + */ +struct dm_md_mempools *dm_alloc_md_mempools(unsigned type); +void dm_free_md_mempools(struct dm_md_mempools *pools); + #endif diff --git a/drivers/md/faulty.c b/drivers/md/faulty.c index 8695809b24b0..87d88dbb667f 100644 --- a/drivers/md/faulty.c +++ b/drivers/md/faulty.c @@ -255,14 +255,14 @@ static void status(struct seq_file *seq, mddev_t *mddev) } -static int reconfig(mddev_t *mddev, int layout, int chunk_size) +static int reshape(mddev_t *mddev) { - int mode = layout & ModeMask; - int count = layout >> ModeShift; + int mode = mddev->new_layout & ModeMask; + int count = mddev->new_layout >> ModeShift; conf_t *conf = mddev->private; - if (chunk_size != -1) - return -EINVAL; + if (mddev->new_layout < 0) + return 0; /* new layout */ if (mode == ClearFaults) @@ -279,6 +279,7 @@ static int reconfig(mddev_t *mddev, int layout, int chunk_size) atomic_set(&conf->counters[mode], count); } else return -EINVAL; + mddev->new_layout = -1; mddev->layout = -1; /* makes sure further changes come through */ return 0; } @@ -298,8 +299,12 @@ static int run(mddev_t *mddev) { mdk_rdev_t *rdev; int i; + conf_t *conf; - conf_t *conf = kmalloc(sizeof(*conf), GFP_KERNEL); + if (md_check_no_bitmap(mddev)) + return -EINVAL; + + conf = kmalloc(sizeof(*conf), GFP_KERNEL); if (!conf) return -ENOMEM; @@ -315,7 +320,7 @@ static int run(mddev_t *mddev) md_set_array_sectors(mddev, faulty_size(mddev, 0, 0)); mddev->private = conf; - reconfig(mddev, mddev->layout, -1); + reshape(mddev); return 0; } @@ -338,7 +343,7 @@ static struct mdk_personality faulty_personality = .run = run, .stop = stop, .status = status, - .reconfig = reconfig, + .check_reshape = reshape, .size = faulty_size, }; diff --git a/drivers/md/linear.c b/drivers/md/linear.c index 7a36e38393a1..15c8b7b25a9b 100644 --- a/drivers/md/linear.c +++ b/drivers/md/linear.c @@ -27,19 +27,27 @@ */ static inline dev_info_t *which_dev(mddev_t *mddev, sector_t sector) { - dev_info_t *hash; - linear_conf_t *conf = mddev_to_conf(mddev); - sector_t idx = sector >> conf->sector_shift; + int lo, mid, hi; + linear_conf_t *conf; + + lo = 0; + hi = mddev->raid_disks - 1; + conf = rcu_dereference(mddev->private); /* - * sector_div(a,b) returns the remainer and sets a to a/b + * Binary Search */ - (void)sector_div(idx, conf->spacing); - hash = conf->hash_table[idx]; - while (sector >= hash->num_sectors + hash->start_sector) - hash++; - return hash; + while (hi > lo) { + + mid = (hi + lo) / 2; + if (sector < conf->disks[mid].end_sector) + hi = mid; + else + lo = mid + 1; + } + + return conf->disks + lo; } /** @@ -59,8 +67,10 @@ static int linear_mergeable_bvec(struct request_queue *q, unsigned long maxsectors, bio_sectors = bvm->bi_size >> 9; sector_t sector = bvm->bi_sector + get_start_sect(bvm->bi_bdev); + rcu_read_lock(); dev0 = which_dev(mddev, sector); - maxsectors = dev0->num_sectors - (sector - dev0->start_sector); + maxsectors = dev0->end_sector - sector; + rcu_read_unlock(); if (maxsectors < bio_sectors) maxsectors = 0; @@ -79,46 +89,57 @@ static int linear_mergeable_bvec(struct request_queue *q, static void linear_unplug(struct request_queue *q) { mddev_t *mddev = q->queuedata; - linear_conf_t *conf = mddev_to_conf(mddev); + linear_conf_t *conf; int i; + rcu_read_lock(); + conf = rcu_dereference(mddev->private); + for (i=0; i < mddev->raid_disks; i++) { struct request_queue *r_queue = bdev_get_queue(conf->disks[i].rdev->bdev); blk_unplug(r_queue); } + rcu_read_unlock(); } static int linear_congested(void *data, int bits) { mddev_t *mddev = data; - linear_conf_t *conf = mddev_to_conf(mddev); + linear_conf_t *conf; int i, ret = 0; + rcu_read_lock(); + conf = rcu_dereference(mddev->private); + for (i = 0; i < mddev->raid_disks && !ret ; i++) { struct request_queue *q = bdev_get_queue(conf->disks[i].rdev->bdev); ret |= bdi_congested(&q->backing_dev_info, bits); } + + rcu_read_unlock(); return ret; } static sector_t linear_size(mddev_t *mddev, sector_t sectors, int raid_disks) { - linear_conf_t *conf = mddev_to_conf(mddev); + linear_conf_t *conf; + sector_t array_sectors; + rcu_read_lock(); + conf = rcu_dereference(mddev->private); WARN_ONCE(sectors || raid_disks, "%s does not support generic reshape\n", __func__); + array_sectors = conf->array_sectors; + rcu_read_unlock(); - return conf->array_sectors; + return array_sectors; } static linear_conf_t *linear_conf(mddev_t *mddev, int raid_disks) { linear_conf_t *conf; - dev_info_t **table; mdk_rdev_t *rdev; - int i, nb_zone, cnt; - sector_t min_sectors; - sector_t curr_sector; + int i, cnt; conf = kzalloc (sizeof (*conf) + raid_disks*sizeof(dev_info_t), GFP_KERNEL); @@ -131,6 +152,7 @@ static linear_conf_t *linear_conf(mddev_t *mddev, int raid_disks) list_for_each_entry(rdev, &mddev->disks, same_set) { int j = rdev->raid_disk; dev_info_t *disk = conf->disks + j; + sector_t sectors; if (j < 0 || j >= raid_disks || disk->rdev) { printk("linear: disk numbering problem. Aborting!\n"); @@ -138,6 +160,11 @@ static linear_conf_t *linear_conf(mddev_t *mddev, int raid_disks) } disk->rdev = rdev; + if (mddev->chunk_sectors) { + sectors = rdev->sectors; + sector_div(sectors, mddev->chunk_sectors); + rdev->sectors = sectors * mddev->chunk_sectors; + } blk_queue_stack_limits(mddev->queue, rdev->bdev->bd_disk->queue); @@ -146,105 +173,27 @@ static linear_conf_t *linear_conf(mddev_t *mddev, int raid_disks) * a one page request is never in violation. */ if (rdev->bdev->bd_disk->queue->merge_bvec_fn && - mddev->queue->max_sectors > (PAGE_SIZE>>9)) + queue_max_sectors(mddev->queue) > (PAGE_SIZE>>9)) blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9); - disk->num_sectors = rdev->sectors; conf->array_sectors += rdev->sectors; - cnt++; + } if (cnt != raid_disks) { printk("linear: not enough drives present. Aborting!\n"); goto out; } - min_sectors = conf->array_sectors; - sector_div(min_sectors, PAGE_SIZE/sizeof(struct dev_info *)); - if (min_sectors == 0) - min_sectors = 1; - - /* min_sectors is the minimum spacing that will fit the hash - * table in one PAGE. This may be much smaller than needed. - * We find the smallest non-terminal set of consecutive devices - * that is larger than min_sectors and use the size of that as - * the actual spacing - */ - conf->spacing = conf->array_sectors; - for (i=0; i < cnt-1 ; i++) { - sector_t tmp = 0; - int j; - for (j = i; j < cnt - 1 && tmp < min_sectors; j++) - tmp += conf->disks[j].num_sectors; - if (tmp >= min_sectors && tmp < conf->spacing) - conf->spacing = tmp; - } - - /* spacing may be too large for sector_div to work with, - * so we might need to pre-shift - */ - conf->sector_shift = 0; - if (sizeof(sector_t) > sizeof(u32)) { - sector_t space = conf->spacing; - while (space > (sector_t)(~(u32)0)) { - space >>= 1; - conf->sector_shift++; - } - } /* - * This code was restructured to work around a gcc-2.95.3 internal - * compiler error. Alter it with care. + * Here we calculate the device offsets. */ - { - sector_t sz; - unsigned round; - unsigned long base; + conf->disks[0].end_sector = conf->disks[0].rdev->sectors; - sz = conf->array_sectors >> conf->sector_shift; - sz += 1; /* force round-up */ - base = conf->spacing >> conf->sector_shift; - round = sector_div(sz, base); - nb_zone = sz + (round ? 1 : 0); - } - BUG_ON(nb_zone > PAGE_SIZE / sizeof(struct dev_info *)); - - conf->hash_table = kmalloc (sizeof (struct dev_info *) * nb_zone, - GFP_KERNEL); - if (!conf->hash_table) - goto out; - - /* - * Here we generate the linear hash table - * First calculate the device offsets. - */ - conf->disks[0].start_sector = 0; for (i = 1; i < raid_disks; i++) - conf->disks[i].start_sector = - conf->disks[i-1].start_sector + - conf->disks[i-1].num_sectors; - - table = conf->hash_table; - i = 0; - for (curr_sector = 0; - curr_sector < conf->array_sectors; - curr_sector += conf->spacing) { - - while (i < raid_disks-1 && - curr_sector >= conf->disks[i+1].start_sector) - i++; - - *table ++ = conf->disks + i; - } - - if (conf->sector_shift) { - conf->spacing >>= conf->sector_shift; - /* round spacing up so that when we divide by it, - * we err on the side of "too-low", which is safest. - */ - conf->spacing++; - } - - BUG_ON(table - conf->hash_table > nb_zone); + conf->disks[i].end_sector = + conf->disks[i-1].end_sector + + conf->disks[i].rdev->sectors; return conf; @@ -257,6 +206,8 @@ static int linear_run (mddev_t *mddev) { linear_conf_t *conf; + if (md_check_no_bitmap(mddev)) + return -EINVAL; mddev->queue->queue_lock = &mddev->queue->__queue_lock; conf = linear_conf(mddev, mddev->raid_disks); @@ -272,6 +223,12 @@ static int linear_run (mddev_t *mddev) return 0; } +static void free_conf(struct rcu_head *head) +{ + linear_conf_t *conf = container_of(head, linear_conf_t, rcu); + kfree(conf); +} + static int linear_add(mddev_t *mddev, mdk_rdev_t *rdev) { /* Adding a drive to a linear array allows the array to grow. @@ -282,7 +239,7 @@ static int linear_add(mddev_t *mddev, mdk_rdev_t *rdev) * The current one is never freed until the array is stopped. * This avoids races. */ - linear_conf_t *newconf; + linear_conf_t *newconf, *oldconf; if (rdev->saved_raid_disk != mddev->raid_disks) return -EINVAL; @@ -294,25 +251,29 @@ static int linear_add(mddev_t *mddev, mdk_rdev_t *rdev) if (!newconf) return -ENOMEM; - newconf->prev = mddev_to_conf(mddev); - mddev->private = newconf; + oldconf = rcu_dereference(mddev->private); mddev->raid_disks++; + rcu_assign_pointer(mddev->private, newconf); md_set_array_sectors(mddev, linear_size(mddev, 0, 0)); set_capacity(mddev->gendisk, mddev->array_sectors); + call_rcu(&oldconf->rcu, free_conf); return 0; } static int linear_stop (mddev_t *mddev) { - linear_conf_t *conf = mddev_to_conf(mddev); - + linear_conf_t *conf = mddev->private; + + /* + * We do not require rcu protection here since + * we hold reconfig_mutex for both linear_add and + * linear_stop, so they cannot race. + * We should make sure any old 'conf's are properly + * freed though. + */ + rcu_barrier(); blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/ - do { - linear_conf_t *t = conf->prev; - kfree(conf->hash_table); - kfree(conf); - conf = t; - } while (conf); + kfree(conf); return 0; } @@ -322,6 +283,7 @@ static int linear_make_request (struct request_queue *q, struct bio *bio) const int rw = bio_data_dir(bio); mddev_t *mddev = q->queuedata; dev_info_t *tmp_dev; + sector_t start_sector; int cpu; if (unlikely(bio_barrier(bio))) { @@ -335,33 +297,36 @@ static int linear_make_request (struct request_queue *q, struct bio *bio) bio_sectors(bio)); part_stat_unlock(); + rcu_read_lock(); tmp_dev = which_dev(mddev, bio->bi_sector); - - if (unlikely(bio->bi_sector >= (tmp_dev->num_sectors + - tmp_dev->start_sector) - || (bio->bi_sector < - tmp_dev->start_sector))) { + start_sector = tmp_dev->end_sector - tmp_dev->rdev->sectors; + + + if (unlikely(bio->bi_sector >= (tmp_dev->end_sector) + || (bio->bi_sector < start_sector))) { char b[BDEVNAME_SIZE]; printk("linear_make_request: Sector %llu out of bounds on " "dev %s: %llu sectors, offset %llu\n", (unsigned long long)bio->bi_sector, bdevname(tmp_dev->rdev->bdev, b), - (unsigned long long)tmp_dev->num_sectors, - (unsigned long long)tmp_dev->start_sector); + (unsigned long long)tmp_dev->rdev->sectors, + (unsigned long long)start_sector); + rcu_read_unlock(); bio_io_error(bio); return 0; } if (unlikely(bio->bi_sector + (bio->bi_size >> 9) > - tmp_dev->start_sector + tmp_dev->num_sectors)) { + tmp_dev->end_sector)) { /* This bio crosses a device boundary, so we have to * split it. */ struct bio_pair *bp; + sector_t end_sector = tmp_dev->end_sector; - bp = bio_split(bio, - tmp_dev->start_sector + tmp_dev->num_sectors - - bio->bi_sector); + rcu_read_unlock(); + + bp = bio_split(bio, end_sector - bio->bi_sector); if (linear_make_request(q, &bp->bio1)) generic_make_request(&bp->bio1); @@ -372,8 +337,9 @@ static int linear_make_request (struct request_queue *q, struct bio *bio) } bio->bi_bdev = tmp_dev->rdev->bdev; - bio->bi_sector = bio->bi_sector - tmp_dev->start_sector + bio->bi_sector = bio->bi_sector - start_sector + tmp_dev->rdev->data_offset; + rcu_read_unlock(); return 1; } @@ -381,7 +347,7 @@ static int linear_make_request (struct request_queue *q, struct bio *bio) static void linear_status (struct seq_file *seq, mddev_t *mddev) { - seq_printf(seq, " %dk rounding", mddev->chunk_size/1024); + seq_printf(seq, " %dk rounding", mddev->chunk_sectors / 2); } diff --git a/drivers/md/linear.h b/drivers/md/linear.h index bf8179587f95..0ce29b61605a 100644 --- a/drivers/md/linear.h +++ b/drivers/md/linear.h @@ -3,27 +3,19 @@ struct dev_info { mdk_rdev_t *rdev; - sector_t num_sectors; - sector_t start_sector; + sector_t end_sector; }; typedef struct dev_info dev_info_t; struct linear_private_data { - struct linear_private_data *prev; /* earlier version */ - dev_info_t **hash_table; - sector_t spacing; sector_t array_sectors; - int sector_shift; /* shift before dividing - * by spacing - */ dev_info_t disks[0]; + struct rcu_head rcu; }; typedef struct linear_private_data linear_conf_t; -#define mddev_to_conf(mddev) ((linear_conf_t *) mddev->private) - #endif diff --git a/drivers/md/md.c b/drivers/md/md.c index 641b211fe3fe..09be637d52cb 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -440,15 +440,6 @@ static inline sector_t calc_dev_sboffset(struct block_device *bdev) return MD_NEW_SIZE_SECTORS(num_sectors); } -static sector_t calc_num_sectors(mdk_rdev_t *rdev, unsigned chunk_size) -{ - sector_t num_sectors = rdev->sb_start; - - if (chunk_size) - num_sectors &= ~((sector_t)chunk_size/512 - 1); - return num_sectors; -} - static int alloc_disk_sb(mdk_rdev_t * rdev) { if (rdev->sb_page) @@ -744,6 +735,24 @@ struct super_type { sector_t num_sectors); }; +/* + * Check that the given mddev has no bitmap. + * + * This function is called from the run method of all personalities that do not + * support bitmaps. It prints an error message and returns non-zero if mddev + * has a bitmap. Otherwise, it returns 0. + * + */ +int md_check_no_bitmap(mddev_t *mddev) +{ + if (!mddev->bitmap_file && !mddev->bitmap_offset) + return 0; + printk(KERN_ERR "%s: bitmaps are not supported for %s\n", + mdname(mddev), mddev->pers->name); + return 1; +} +EXPORT_SYMBOL(md_check_no_bitmap); + /* * load_super for 0.90.0 */ @@ -797,17 +806,6 @@ static int super_90_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version rdev->data_offset = 0; rdev->sb_size = MD_SB_BYTES; - if (sb->state & (1<level != 1 && sb->level != 4 - && sb->level != 5 && sb->level != 6 - && sb->level != 10) { - /* FIXME use a better test */ - printk(KERN_WARNING - "md: bitmaps not supported for this level.\n"); - goto abort; - } - } - if (sb->level == LEVEL_MULTIPATH) rdev->desc_nr = -1; else @@ -836,7 +834,7 @@ static int super_90_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version else ret = 0; } - rdev->sectors = calc_num_sectors(rdev, sb->chunk_size); + rdev->sectors = rdev->sb_start; if (rdev->sectors < sb->size * 2 && sb->level > 1) /* "this cannot possibly happen" ... */ @@ -866,7 +864,7 @@ static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev) mddev->minor_version = sb->minor_version; mddev->patch_version = sb->patch_version; mddev->external = 0; - mddev->chunk_size = sb->chunk_size; + mddev->chunk_sectors = sb->chunk_size >> 9; mddev->ctime = sb->ctime; mddev->utime = sb->utime; mddev->level = sb->level; @@ -883,13 +881,13 @@ static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev) mddev->delta_disks = sb->delta_disks; mddev->new_level = sb->new_level; mddev->new_layout = sb->new_layout; - mddev->new_chunk = sb->new_chunk; + mddev->new_chunk_sectors = sb->new_chunk >> 9; } else { mddev->reshape_position = MaxSector; mddev->delta_disks = 0; mddev->new_level = mddev->level; mddev->new_layout = mddev->layout; - mddev->new_chunk = mddev->chunk_size; + mddev->new_chunk_sectors = mddev->chunk_sectors; } if (sb->state & (1<new_level = mddev->new_level; sb->delta_disks = mddev->delta_disks; sb->new_layout = mddev->new_layout; - sb->new_chunk = mddev->new_chunk; + sb->new_chunk = mddev->new_chunk_sectors << 9; } mddev->minor_version = sb->minor_version; if (mddev->in_sync) @@ -1018,7 +1016,7 @@ static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev) sb->recovery_cp = 0; sb->layout = mddev->layout; - sb->chunk_size = mddev->chunk_size; + sb->chunk_size = mddev->chunk_sectors << 9; if (mddev->bitmap && mddev->bitmap_file == NULL) sb->state |= (1<bdev,b)); return -EINVAL; } - if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_BITMAP_OFFSET)) { - if (sb->level != cpu_to_le32(1) && - sb->level != cpu_to_le32(4) && - sb->level != cpu_to_le32(5) && - sb->level != cpu_to_le32(6) && - sb->level != cpu_to_le32(10)) { - printk(KERN_WARNING - "md: bitmaps not supported for this level.\n"); - return -EINVAL; - } - } rdev->preferred_minor = 0xffff; rdev->data_offset = le64_to_cpu(sb->data_offset); atomic_set(&rdev->corrected_errors, le32_to_cpu(sb->cnt_corrected_read)); rdev->sb_size = le32_to_cpu(sb->max_dev) * 2 + 256; - bmask = queue_hardsect_size(rdev->bdev->bd_disk->queue)-1; + bmask = queue_logical_block_size(rdev->bdev->bd_disk->queue)-1; if (rdev->sb_size & bmask) rdev->sb_size = (rdev->sb_size | bmask) + 1; @@ -1248,9 +1235,6 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version) if (rdev->sectors < le64_to_cpu(sb->data_size)) return -EINVAL; rdev->sectors = le64_to_cpu(sb->data_size); - if (le32_to_cpu(sb->chunksize)) - rdev->sectors &= ~((sector_t)le32_to_cpu(sb->chunksize) - 1); - if (le64_to_cpu(sb->size) > rdev->sectors) return -EINVAL; return ret; @@ -1271,7 +1255,7 @@ static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev) mddev->major_version = 1; mddev->patch_version = 0; mddev->external = 0; - mddev->chunk_size = le32_to_cpu(sb->chunksize) << 9; + mddev->chunk_sectors = le32_to_cpu(sb->chunksize); mddev->ctime = le64_to_cpu(sb->ctime) & ((1ULL << 32)-1); mddev->utime = le64_to_cpu(sb->utime) & ((1ULL << 32)-1); mddev->level = le32_to_cpu(sb->level); @@ -1297,13 +1281,13 @@ static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev) mddev->delta_disks = le32_to_cpu(sb->delta_disks); mddev->new_level = le32_to_cpu(sb->new_level); mddev->new_layout = le32_to_cpu(sb->new_layout); - mddev->new_chunk = le32_to_cpu(sb->new_chunk)<<9; + mddev->new_chunk_sectors = le32_to_cpu(sb->new_chunk); } else { mddev->reshape_position = MaxSector; mddev->delta_disks = 0; mddev->new_level = mddev->level; mddev->new_layout = mddev->layout; - mddev->new_chunk = mddev->chunk_size; + mddev->new_chunk_sectors = mddev->chunk_sectors; } } else if (mddev->pers == NULL) { @@ -1375,7 +1359,7 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev) sb->raid_disks = cpu_to_le32(mddev->raid_disks); sb->size = cpu_to_le64(mddev->dev_sectors); - sb->chunksize = cpu_to_le32(mddev->chunk_size >> 9); + sb->chunksize = cpu_to_le32(mddev->chunk_sectors); sb->level = cpu_to_le32(mddev->level); sb->layout = cpu_to_le32(mddev->layout); @@ -1402,7 +1386,7 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev) sb->new_layout = cpu_to_le32(mddev->new_layout); sb->delta_disks = cpu_to_le32(mddev->delta_disks); sb->new_level = cpu_to_le32(mddev->new_level); - sb->new_chunk = cpu_to_le32(mddev->new_chunk>>9); + sb->new_chunk = cpu_to_le32(mddev->new_chunk_sectors); } max_dev = 0; @@ -1897,6 +1881,7 @@ static void md_update_sb(mddev_t * mddev, int force_change) int sync_req; int nospares = 0; + mddev->utime = get_seconds(); if (mddev->external) return; repeat: @@ -1926,7 +1911,6 @@ repeat: nospares = 0; sync_req = mddev->in_sync; - mddev->utime = get_seconds(); /* If this is just a dirty<->clean transition, and the array is clean * and 'events' is odd, we can roll back to the previous clean state */ @@ -2597,15 +2581,6 @@ static void analyze_sbs(mddev_t * mddev) clear_bit(In_sync, &rdev->flags); } } - - - - if (mddev->recovery_cp != MaxSector && - mddev->level >= 1) - printk(KERN_ERR "md: %s: raid array is not clean" - " -- starting background reconstruction\n", - mdname(mddev)); - } static void md_safemode_timeout(unsigned long data); @@ -2746,7 +2721,7 @@ level_store(mddev_t *mddev, const char *buf, size_t len) if (IS_ERR(priv)) { mddev->new_level = mddev->level; mddev->new_layout = mddev->layout; - mddev->new_chunk = mddev->chunk_size; + mddev->new_chunk_sectors = mddev->chunk_sectors; mddev->raid_disks -= mddev->delta_disks; mddev->delta_disks = 0; module_put(pers->owner); @@ -2764,7 +2739,7 @@ level_store(mddev_t *mddev, const char *buf, size_t len) strlcpy(mddev->clevel, pers->name, sizeof(mddev->clevel)); mddev->level = mddev->new_level; mddev->layout = mddev->new_layout; - mddev->chunk_size = mddev->new_chunk; + mddev->chunk_sectors = mddev->new_chunk_sectors; mddev->delta_disks = 0; pers->run(mddev); mddev_resume(mddev); @@ -2800,11 +2775,14 @@ layout_store(mddev_t *mddev, const char *buf, size_t len) if (mddev->pers) { int err; - if (mddev->pers->reconfig == NULL) + if (mddev->pers->check_reshape == NULL) return -EBUSY; - err = mddev->pers->reconfig(mddev, n, -1); - if (err) + mddev->new_layout = n; + err = mddev->pers->check_reshape(mddev); + if (err) { + mddev->new_layout = mddev->layout; return err; + } } else { mddev->new_layout = n; if (mddev->reshape_position == MaxSector) @@ -2857,10 +2835,11 @@ static ssize_t chunk_size_show(mddev_t *mddev, char *page) { if (mddev->reshape_position != MaxSector && - mddev->chunk_size != mddev->new_chunk) - return sprintf(page, "%d (%d)\n", mddev->new_chunk, - mddev->chunk_size); - return sprintf(page, "%d\n", mddev->chunk_size); + mddev->chunk_sectors != mddev->new_chunk_sectors) + return sprintf(page, "%d (%d)\n", + mddev->new_chunk_sectors << 9, + mddev->chunk_sectors << 9); + return sprintf(page, "%d\n", mddev->chunk_sectors << 9); } static ssize_t @@ -2874,15 +2853,18 @@ chunk_size_store(mddev_t *mddev, const char *buf, size_t len) if (mddev->pers) { int err; - if (mddev->pers->reconfig == NULL) + if (mddev->pers->check_reshape == NULL) return -EBUSY; - err = mddev->pers->reconfig(mddev, -1, n); - if (err) + mddev->new_chunk_sectors = n >> 9; + err = mddev->pers->check_reshape(mddev); + if (err) { + mddev->new_chunk_sectors = mddev->chunk_sectors; return err; + } } else { - mddev->new_chunk = n; + mddev->new_chunk_sectors = n >> 9; if (mddev->reshape_position == MaxSector) - mddev->chunk_size = n; + mddev->chunk_sectors = n >> 9; } return len; } @@ -3527,8 +3509,9 @@ min_sync_store(mddev_t *mddev, const char *buf, size_t len) return -EBUSY; /* Must be a multiple of chunk_size */ - if (mddev->chunk_size) { - if (min & (sector_t)((mddev->chunk_size>>9)-1)) + if (mddev->chunk_sectors) { + sector_t temp = min; + if (sector_div(temp, mddev->chunk_sectors)) return -EINVAL; } mddev->resync_min = min; @@ -3564,8 +3547,9 @@ max_sync_store(mddev_t *mddev, const char *buf, size_t len) return -EBUSY; /* Must be a multiple of chunk_size */ - if (mddev->chunk_size) { - if (max & (sector_t)((mddev->chunk_size>>9)-1)) + if (mddev->chunk_sectors) { + sector_t temp = max; + if (sector_div(temp, mddev->chunk_sectors)) return -EINVAL; } mddev->resync_max = max; @@ -3656,7 +3640,7 @@ reshape_position_store(mddev_t *mddev, const char *buf, size_t len) mddev->delta_disks = 0; mddev->new_level = mddev->level; mddev->new_layout = mddev->layout; - mddev->new_chunk = mddev->chunk_size; + mddev->new_chunk_sectors = mddev->chunk_sectors; return len; } @@ -3976,11 +3960,9 @@ static int start_dirty_degraded; static int do_md_run(mddev_t * mddev) { int err; - int chunk_size; mdk_rdev_t *rdev; struct gendisk *disk; struct mdk_personality *pers; - char b[BDEVNAME_SIZE]; if (list_empty(&mddev->disks)) /* cannot run an array with no devices.. */ @@ -3998,38 +3980,6 @@ static int do_md_run(mddev_t * mddev) analyze_sbs(mddev); } - chunk_size = mddev->chunk_size; - - if (chunk_size) { - if (chunk_size > MAX_CHUNK_SIZE) { - printk(KERN_ERR "too big chunk_size: %d > %d\n", - chunk_size, MAX_CHUNK_SIZE); - return -EINVAL; - } - /* - * chunk-size has to be a power of 2 - */ - if ( (1 << ffz(~chunk_size)) != chunk_size) { - printk(KERN_ERR "chunk_size of %d not valid\n", chunk_size); - return -EINVAL; - } - - /* devices must have minimum size of one chunk */ - list_for_each_entry(rdev, &mddev->disks, same_set) { - if (test_bit(Faulty, &rdev->flags)) - continue; - if (rdev->sectors < chunk_size / 512) { - printk(KERN_WARNING - "md: Dev %s smaller than chunk_size:" - " %llu < %d\n", - bdevname(rdev->bdev,b), - (unsigned long long)rdev->sectors, - chunk_size / 512); - return -EINVAL; - } - } - } - if (mddev->level != LEVEL_NONE) request_module("md-level-%d", mddev->level); else if (mddev->clevel[0]) @@ -4405,7 +4355,7 @@ static int do_md_stop(mddev_t * mddev, int mode, int is_open) mddev->flags = 0; mddev->ro = 0; mddev->metadata_type[0] = 0; - mddev->chunk_size = 0; + mddev->chunk_sectors = 0; mddev->ctime = mddev->utime = 0; mddev->layout = 0; mddev->max_disks = 0; @@ -4413,7 +4363,7 @@ static int do_md_stop(mddev_t * mddev, int mode, int is_open) mddev->delta_disks = 0; mddev->new_level = LEVEL_NONE; mddev->new_layout = 0; - mddev->new_chunk = 0; + mddev->new_chunk_sectors = 0; mddev->curr_resync = 0; mddev->resync_mismatches = 0; mddev->suspend_lo = mddev->suspend_hi = 0; @@ -4618,7 +4568,7 @@ static int get_array_info(mddev_t * mddev, void __user * arg) info.spare_disks = spare; info.layout = mddev->layout; - info.chunk_size = mddev->chunk_size; + info.chunk_size = mddev->chunk_sectors << 9; if (copy_to_user(arg, &info, sizeof(info))) return -EFAULT; @@ -4843,7 +4793,7 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info) rdev->sb_start = rdev->bdev->bd_inode->i_size / 512; } else rdev->sb_start = calc_dev_sboffset(rdev->bdev); - rdev->sectors = calc_num_sectors(rdev, mddev->chunk_size); + rdev->sectors = rdev->sb_start; err = bind_rdev_to_array(rdev, mddev); if (err) { @@ -4913,7 +4863,7 @@ static int hot_add_disk(mddev_t * mddev, dev_t dev) else rdev->sb_start = rdev->bdev->bd_inode->i_size / 512; - rdev->sectors = calc_num_sectors(rdev, mddev->chunk_size); + rdev->sectors = rdev->sb_start; if (test_bit(Faulty, &rdev->flags)) { printk(KERN_WARNING @@ -5062,7 +5012,7 @@ static int set_array_info(mddev_t * mddev, mdu_array_info_t *info) mddev->external = 0; mddev->layout = info->layout; - mddev->chunk_size = info->chunk_size; + mddev->chunk_sectors = info->chunk_size >> 9; mddev->max_disks = MD_SB_DISKS; @@ -5081,7 +5031,7 @@ static int set_array_info(mddev_t * mddev, mdu_array_info_t *info) get_random_bytes(mddev->uuid, 16); mddev->new_level = mddev->level; - mddev->new_chunk = mddev->chunk_size; + mddev->new_chunk_sectors = mddev->chunk_sectors; mddev->new_layout = mddev->layout; mddev->delta_disks = 0; @@ -5191,7 +5141,7 @@ static int update_array_info(mddev_t *mddev, mdu_array_info_t *info) mddev->level != info->level || /* mddev->layout != info->layout || */ !mddev->persistent != info->not_persistent|| - mddev->chunk_size != info->chunk_size || + mddev->chunk_sectors != info->chunk_size >> 9 || /* ignore bottom 8 bits of state, and allow SB_BITMAP_PRESENT to change */ ((state^info->state) & 0xfffffe00) ) @@ -5215,10 +5165,15 @@ static int update_array_info(mddev_t *mddev, mdu_array_info_t *info) * we don't need to do anything at the md level, the * personality will take care of it all. */ - if (mddev->pers->reconfig == NULL) + if (mddev->pers->check_reshape == NULL) return -EINVAL; - else - return mddev->pers->reconfig(mddev, info->layout, -1); + else { + mddev->new_layout = info->layout; + rv = mddev->pers->check_reshape(mddev); + if (rv) + mddev->new_layout = mddev->layout; + return rv; + } } if (info->size >= 0 && mddev->dev_sectors / 2 != info->size) rv = update_size(mddev, (sector_t)info->size * 2); @@ -6717,7 +6672,8 @@ void md_check_recovery(mddev_t *mddev) */ if (mddev->reshape_position != MaxSector) { - if (mddev->pers->check_reshape(mddev) != 0) + if (mddev->pers->check_reshape == NULL || + mddev->pers->check_reshape(mddev) != 0) /* Cannot proceed */ goto unlock; set_bit(MD_RECOVERY_RESHAPE, &mddev->recovery); diff --git a/drivers/md/md.h b/drivers/md/md.h index 8227ab909d44..9430a110db93 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h @@ -29,13 +29,6 @@ typedef struct mddev_s mddev_t; typedef struct mdk_rdev_s mdk_rdev_t; -/* - * options passed in raidrun: - */ - -/* Currently this must fit in an 'int' */ -#define MAX_CHUNK_SIZE (1<<30) - /* * MD's 'extended' device */ @@ -145,7 +138,7 @@ struct mddev_s int external; /* metadata is * managed externally */ char metadata_type[17]; /* externally set*/ - int chunk_size; + int chunk_sectors; time_t ctime, utime; int level, layout; char clevel[16]; @@ -166,7 +159,8 @@ struct mddev_s * If reshape_position is MaxSector, then no reshape is happening (yet). */ sector_t reshape_position; - int delta_disks, new_level, new_layout, new_chunk; + int delta_disks, new_level, new_layout; + int new_chunk_sectors; struct mdk_thread_s *thread; /* management thread */ struct mdk_thread_s *sync_thread; /* doing resync or reconstruct */ @@ -325,7 +319,6 @@ struct mdk_personality int (*check_reshape) (mddev_t *mddev); int (*start_reshape) (mddev_t *mddev); void (*finish_reshape) (mddev_t *mddev); - int (*reconfig) (mddev_t *mddev, int layout, int chunk_size); /* quiesce moves between quiescence states * 0 - fully active * 1 - no new requests allowed @@ -437,5 +430,6 @@ extern void md_new_event(mddev_t *mddev); extern int md_allow_write(mddev_t *mddev); extern void md_wait_for_blocked_rdev(mdk_rdev_t *rdev, mddev_t *mddev); extern void md_set_array_sectors(mddev_t *mddev, sector_t array_sectors); +extern int md_check_no_bitmap(mddev_t *mddev); #endif /* _MD_MD_H */ diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index 41ced0cbe823..cbe368fa6598 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -58,7 +58,7 @@ static void multipath_reschedule_retry (struct multipath_bh *mp_bh) { unsigned long flags; mddev_t *mddev = mp_bh->mddev; - multipath_conf_t *conf = mddev_to_conf(mddev); + multipath_conf_t *conf = mddev->private; spin_lock_irqsave(&conf->device_lock, flags); list_add(&mp_bh->retry_list, &conf->retry_list); @@ -75,7 +75,7 @@ static void multipath_reschedule_retry (struct multipath_bh *mp_bh) static void multipath_end_bh_io (struct multipath_bh *mp_bh, int err) { struct bio *bio = mp_bh->master_bio; - multipath_conf_t *conf = mddev_to_conf(mp_bh->mddev); + multipath_conf_t *conf = mp_bh->mddev->private; bio_endio(bio, err); mempool_free(mp_bh, conf->pool); @@ -85,7 +85,7 @@ static void multipath_end_request(struct bio *bio, int error) { int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); struct multipath_bh * mp_bh = (struct multipath_bh *)(bio->bi_private); - multipath_conf_t *conf = mddev_to_conf(mp_bh->mddev); + multipath_conf_t *conf = mp_bh->mddev->private; mdk_rdev_t *rdev = conf->multipaths[mp_bh->path].rdev; if (uptodate) @@ -107,7 +107,7 @@ static void multipath_end_request(struct bio *bio, int error) static void unplug_slaves(mddev_t *mddev) { - multipath_conf_t *conf = mddev_to_conf(mddev); + multipath_conf_t *conf = mddev->private; int i; rcu_read_lock(); @@ -138,7 +138,7 @@ static void multipath_unplug(struct request_queue *q) static int multipath_make_request (struct request_queue *q, struct bio * bio) { mddev_t *mddev = q->queuedata; - multipath_conf_t *conf = mddev_to_conf(mddev); + multipath_conf_t *conf = mddev->private; struct multipath_bh * mp_bh; struct multipath_info *multipath; const int rw = bio_data_dir(bio); @@ -180,7 +180,7 @@ static int multipath_make_request (struct request_queue *q, struct bio * bio) static void multipath_status (struct seq_file *seq, mddev_t *mddev) { - multipath_conf_t *conf = mddev_to_conf(mddev); + multipath_conf_t *conf = mddev->private; int i; seq_printf (seq, " [%d/%d] [", conf->raid_disks, @@ -195,7 +195,7 @@ static void multipath_status (struct seq_file *seq, mddev_t *mddev) static int multipath_congested(void *data, int bits) { mddev_t *mddev = data; - multipath_conf_t *conf = mddev_to_conf(mddev); + multipath_conf_t *conf = mddev->private; int i, ret = 0; rcu_read_lock(); @@ -220,7 +220,7 @@ static int multipath_congested(void *data, int bits) */ static void multipath_error (mddev_t *mddev, mdk_rdev_t *rdev) { - multipath_conf_t *conf = mddev_to_conf(mddev); + multipath_conf_t *conf = mddev->private; if (conf->working_disks <= 1) { /* @@ -303,7 +303,7 @@ static int multipath_add_disk(mddev_t *mddev, mdk_rdev_t *rdev) * merge_bvec_fn will be involved in multipath.) */ if (q->merge_bvec_fn && - mddev->queue->max_sectors > (PAGE_SIZE>>9)) + queue_max_sectors(q) > (PAGE_SIZE>>9)) blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9); conf->working_disks++; @@ -367,7 +367,7 @@ static void multipathd (mddev_t *mddev) struct multipath_bh *mp_bh; struct bio *bio; unsigned long flags; - multipath_conf_t *conf = mddev_to_conf(mddev); + multipath_conf_t *conf = mddev->private; struct list_head *head = &conf->retry_list; md_check_recovery(mddev); @@ -421,6 +421,9 @@ static int multipath_run (mddev_t *mddev) struct multipath_info *disk; mdk_rdev_t *rdev; + if (md_check_no_bitmap(mddev)) + return -EINVAL; + if (mddev->level != LEVEL_MULTIPATH) { printk("multipath: %s: raid level not set to multipath IO (%d)\n", mdname(mddev), mddev->level); @@ -467,7 +470,7 @@ static int multipath_run (mddev_t *mddev) * violating it, not that we ever expect a device with * a merge_bvec_fn to be involved in multipath */ if (rdev->bdev->bd_disk->queue->merge_bvec_fn && - mddev->queue->max_sectors > (PAGE_SIZE>>9)) + queue_max_sectors(mddev->queue) > (PAGE_SIZE>>9)) blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9); if (!test_bit(Faulty, &rdev->flags)) @@ -531,7 +534,7 @@ out: static int multipath_stop (mddev_t *mddev) { - multipath_conf_t *conf = mddev_to_conf(mddev); + multipath_conf_t *conf = mddev->private; md_unregister_thread(mddev->thread); mddev->thread = NULL; diff --git a/drivers/md/multipath.h b/drivers/md/multipath.h index 6fa70b400cda..d1c2a8d78395 100644 --- a/drivers/md/multipath.h +++ b/drivers/md/multipath.h @@ -18,12 +18,6 @@ struct multipath_private_data { typedef struct multipath_private_data multipath_conf_t; -/* - * this is the only point in the RAID code where we violate - * C type safety. mddev->private is an 'opaque' pointer. - */ -#define mddev_to_conf(mddev) ((multipath_conf_t *) mddev->private) - /* * this is our 'private' 'collective' MULTIPATH buffer head. * it contains information about what kind of IO operations were started diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index c08d7559be55..ab4a489d8695 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -26,8 +26,8 @@ static void raid0_unplug(struct request_queue *q) { mddev_t *mddev = q->queuedata; - raid0_conf_t *conf = mddev_to_conf(mddev); - mdk_rdev_t **devlist = conf->strip_zone[0].dev; + raid0_conf_t *conf = mddev->private; + mdk_rdev_t **devlist = conf->devlist; int i; for (i=0; iraid_disks; i++) { @@ -40,8 +40,8 @@ static void raid0_unplug(struct request_queue *q) static int raid0_congested(void *data, int bits) { mddev_t *mddev = data; - raid0_conf_t *conf = mddev_to_conf(mddev); - mdk_rdev_t **devlist = conf->strip_zone[0].dev; + raid0_conf_t *conf = mddev->private; + mdk_rdev_t **devlist = conf->devlist; int i, ret = 0; for (i = 0; i < mddev->raid_disks && !ret ; i++) { @@ -52,27 +52,60 @@ static int raid0_congested(void *data, int bits) return ret; } - -static int create_strip_zones (mddev_t *mddev) +/* + * inform the user of the raid configuration +*/ +static void dump_zones(mddev_t *mddev) { - int i, c, j; - sector_t current_start, curr_zone_start; - sector_t min_spacing; - raid0_conf_t *conf = mddev_to_conf(mddev); - mdk_rdev_t *smallest, *rdev1, *rdev2, *rdev; + int j, k, h; + sector_t zone_size = 0; + sector_t zone_start = 0; + char b[BDEVNAME_SIZE]; + raid0_conf_t *conf = mddev->private; + printk(KERN_INFO "******* %s configuration *********\n", + mdname(mddev)); + h = 0; + for (j = 0; j < conf->nr_strip_zones; j++) { + printk(KERN_INFO "zone%d=[", j); + for (k = 0; k < conf->strip_zone[j].nb_dev; k++) + printk("%s/", + bdevname(conf->devlist[j*mddev->raid_disks + + k]->bdev, b)); + printk("]\n"); + + zone_size = conf->strip_zone[j].zone_end - zone_start; + printk(KERN_INFO " zone offset=%llukb " + "device offset=%llukb size=%llukb\n", + (unsigned long long)zone_start>>1, + (unsigned long long)conf->strip_zone[j].dev_start>>1, + (unsigned long long)zone_size>>1); + zone_start = conf->strip_zone[j].zone_end; + } + printk(KERN_INFO "**********************************\n\n"); +} + +static int create_strip_zones(mddev_t *mddev) +{ + int i, c, j, err; + sector_t curr_zone_end, sectors; + mdk_rdev_t *smallest, *rdev1, *rdev2, *rdev, **dev; struct strip_zone *zone; int cnt; char b[BDEVNAME_SIZE]; - - /* - * The number of 'same size groups' - */ - conf->nr_strip_zones = 0; - + raid0_conf_t *conf = kzalloc(sizeof(*conf), GFP_KERNEL); + + if (!conf) + return -ENOMEM; list_for_each_entry(rdev1, &mddev->disks, same_set) { printk(KERN_INFO "raid0: looking at %s\n", bdevname(rdev1->bdev,b)); c = 0; + + /* round size to chunk_size */ + sectors = rdev1->sectors; + sector_div(sectors, mddev->chunk_sectors); + rdev1->sectors = sectors * mddev->chunk_sectors; + list_for_each_entry(rdev2, &mddev->disks, same_set) { printk(KERN_INFO "raid0: comparing %s(%llu)", bdevname(rdev1->bdev,b), @@ -103,16 +136,16 @@ static int create_strip_zones (mddev_t *mddev) } } printk(KERN_INFO "raid0: FINAL %d zones\n", conf->nr_strip_zones); - + err = -ENOMEM; conf->strip_zone = kzalloc(sizeof(struct strip_zone)* conf->nr_strip_zones, GFP_KERNEL); if (!conf->strip_zone) - return 1; + goto abort; conf->devlist = kzalloc(sizeof(mdk_rdev_t*)* conf->nr_strip_zones*mddev->raid_disks, GFP_KERNEL); if (!conf->devlist) - return 1; + goto abort; /* The first zone must contain all devices, so here we check that * there is a proper alignment of slots to devices and find them all @@ -120,7 +153,8 @@ static int create_strip_zones (mddev_t *mddev) zone = &conf->strip_zone[0]; cnt = 0; smallest = NULL; - zone->dev = conf->devlist; + dev = conf->devlist; + err = -EINVAL; list_for_each_entry(rdev1, &mddev->disks, same_set) { int j = rdev1->raid_disk; @@ -129,12 +163,12 @@ static int create_strip_zones (mddev_t *mddev) "aborting!\n", j); goto abort; } - if (zone->dev[j]) { + if (dev[j]) { printk(KERN_ERR "raid0: multiple devices for %d - " "aborting!\n", j); goto abort; } - zone->dev[j] = rdev1; + dev[j] = rdev1; blk_queue_stack_limits(mddev->queue, rdev1->bdev->bd_disk->queue); @@ -144,7 +178,7 @@ static int create_strip_zones (mddev_t *mddev) */ if (rdev1->bdev->bd_disk->queue->merge_bvec_fn && - mddev->queue->max_sectors > (PAGE_SIZE>>9)) + queue_max_sectors(mddev->queue) > (PAGE_SIZE>>9)) blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9); if (!smallest || (rdev1->sectors < smallest->sectors)) @@ -157,34 +191,32 @@ static int create_strip_zones (mddev_t *mddev) goto abort; } zone->nb_dev = cnt; - zone->sectors = smallest->sectors * cnt; - zone->zone_start = 0; + zone->zone_end = smallest->sectors * cnt; - current_start = smallest->sectors; - curr_zone_start = zone->sectors; + curr_zone_end = zone->zone_end; /* now do the other zones */ for (i = 1; i < conf->nr_strip_zones; i++) { zone = conf->strip_zone + i; - zone->dev = conf->strip_zone[i-1].dev + mddev->raid_disks; + dev = conf->devlist + i * mddev->raid_disks; printk(KERN_INFO "raid0: zone %d\n", i); - zone->dev_start = current_start; + zone->dev_start = smallest->sectors; smallest = NULL; c = 0; for (j=0; jstrip_zone[0].dev[j]; + rdev = conf->devlist[j]; printk(KERN_INFO "raid0: checking %s ...", bdevname(rdev->bdev, b)); - if (rdev->sectors <= current_start) { + if (rdev->sectors <= zone->dev_start) { printk(KERN_INFO " nope.\n"); continue; } printk(KERN_INFO " contained as device %d\n", c); - zone->dev[c] = rdev; + dev[c] = rdev; c++; if (!smallest || rdev->sectors < smallest->sectors) { smallest = rdev; @@ -194,47 +226,39 @@ static int create_strip_zones (mddev_t *mddev) } zone->nb_dev = c; - zone->sectors = (smallest->sectors - current_start) * c; + sectors = (smallest->sectors - zone->dev_start) * c; printk(KERN_INFO "raid0: zone->nb_dev: %d, sectors: %llu\n", - zone->nb_dev, (unsigned long long)zone->sectors); + zone->nb_dev, (unsigned long long)sectors); - zone->zone_start = curr_zone_start; - curr_zone_start += zone->sectors; + curr_zone_end += sectors; + zone->zone_end = curr_zone_end; - current_start = smallest->sectors; printk(KERN_INFO "raid0: current zone start: %llu\n", - (unsigned long long)current_start); + (unsigned long long)smallest->sectors); } - - /* Now find appropriate hash spacing. - * We want a number which causes most hash entries to cover - * at most two strips, but the hash table must be at most - * 1 PAGE. We choose the smallest strip, or contiguous collection - * of strips, that has big enough size. We never consider the last - * strip though as it's size has no bearing on the efficacy of the hash - * table. - */ - conf->spacing = curr_zone_start; - min_spacing = curr_zone_start; - sector_div(min_spacing, PAGE_SIZE/sizeof(struct strip_zone*)); - for (i=0; i < conf->nr_strip_zones-1; i++) { - sector_t s = 0; - for (j = i; j < conf->nr_strip_zones - 1 && - s < min_spacing; j++) - s += conf->strip_zone[j].sectors; - if (s >= min_spacing && s < conf->spacing) - conf->spacing = s; - } - mddev->queue->unplug_fn = raid0_unplug; - mddev->queue->backing_dev_info.congested_fn = raid0_congested; mddev->queue->backing_dev_info.congested_data = mddev; + /* + * now since we have the hard sector sizes, we can make sure + * chunk size is a multiple of that sector size + */ + if ((mddev->chunk_sectors << 9) % queue_logical_block_size(mddev->queue)) { + printk(KERN_ERR "%s chunk_size of %d not valid\n", + mdname(mddev), + mddev->chunk_sectors << 9); + goto abort; + } printk(KERN_INFO "raid0: done.\n"); + mddev->private = conf; return 0; - abort: - return 1; +abort: + kfree(conf->strip_zone); + kfree(conf->devlist); + kfree(conf); + mddev->private = NULL; + return err; } /** @@ -252,10 +276,15 @@ static int raid0_mergeable_bvec(struct request_queue *q, mddev_t *mddev = q->queuedata; sector_t sector = bvm->bi_sector + get_start_sect(bvm->bi_bdev); int max; - unsigned int chunk_sectors = mddev->chunk_size >> 9; + unsigned int chunk_sectors = mddev->chunk_sectors; unsigned int bio_sectors = bvm->bi_size >> 9; - max = (chunk_sectors - ((sector & (chunk_sectors - 1)) + bio_sectors)) << 9; + if (is_power_of_2(chunk_sectors)) + max = (chunk_sectors - ((sector & (chunk_sectors-1)) + + bio_sectors)) << 9; + else + max = (chunk_sectors - (sector_div(sector, chunk_sectors) + + bio_sectors)) << 9; if (max < 0) max = 0; /* bio_add cannot handle a negative return */ if (max <= biovec->bv_len && bio_sectors == 0) return biovec->bv_len; @@ -277,84 +306,28 @@ static sector_t raid0_size(mddev_t *mddev, sector_t sectors, int raid_disks) return array_sectors; } -static int raid0_run (mddev_t *mddev) +static int raid0_run(mddev_t *mddev) { - unsigned cur=0, i=0, nb_zone; - s64 sectors; - raid0_conf_t *conf; + int ret; - if (mddev->chunk_size == 0) { - printk(KERN_ERR "md/raid0: non-zero chunk size required.\n"); + if (mddev->chunk_sectors == 0) { + printk(KERN_ERR "md/raid0: chunk size must be set.\n"); return -EINVAL; } - printk(KERN_INFO "%s: setting max_sectors to %d, segment boundary to %d\n", - mdname(mddev), - mddev->chunk_size >> 9, - (mddev->chunk_size>>1)-1); - blk_queue_max_sectors(mddev->queue, mddev->chunk_size >> 9); - blk_queue_segment_boundary(mddev->queue, (mddev->chunk_size>>1) - 1); + if (md_check_no_bitmap(mddev)) + return -EINVAL; + blk_queue_max_sectors(mddev->queue, mddev->chunk_sectors); mddev->queue->queue_lock = &mddev->queue->__queue_lock; - conf = kmalloc(sizeof (raid0_conf_t), GFP_KERNEL); - if (!conf) - goto out; - mddev->private = (void *)conf; - - conf->strip_zone = NULL; - conf->devlist = NULL; - if (create_strip_zones (mddev)) - goto out_free_conf; + ret = create_strip_zones(mddev); + if (ret < 0) + return ret; /* calculate array device size */ md_set_array_sectors(mddev, raid0_size(mddev, 0, 0)); printk(KERN_INFO "raid0 : md_size is %llu sectors.\n", (unsigned long long)mddev->array_sectors); - printk(KERN_INFO "raid0 : conf->spacing is %llu sectors.\n", - (unsigned long long)conf->spacing); - { - sector_t s = raid0_size(mddev, 0, 0); - sector_t space = conf->spacing; - int round; - conf->sector_shift = 0; - if (sizeof(sector_t) > sizeof(u32)) { - /*shift down space and s so that sector_div will work */ - while (space > (sector_t) (~(u32)0)) { - s >>= 1; - space >>= 1; - s += 1; /* force round-up */ - conf->sector_shift++; - } - } - round = sector_div(s, (u32)space) ? 1 : 0; - nb_zone = s + round; - } - printk(KERN_INFO "raid0 : nb_zone is %d.\n", nb_zone); - - printk(KERN_INFO "raid0 : Allocating %zu bytes for hash.\n", - nb_zone*sizeof(struct strip_zone*)); - conf->hash_table = kmalloc (sizeof (struct strip_zone *)*nb_zone, GFP_KERNEL); - if (!conf->hash_table) - goto out_free_conf; - sectors = conf->strip_zone[cur].sectors; - - conf->hash_table[0] = conf->strip_zone + cur; - for (i=1; i< nb_zone; i++) { - while (sectors <= conf->spacing) { - cur++; - sectors += conf->strip_zone[cur].sectors; - } - sectors -= conf->spacing; - conf->hash_table[i] = conf->strip_zone + cur; - } - if (conf->sector_shift) { - conf->spacing >>= conf->sector_shift; - /* round spacing up so when we divide by it, we - * err on the side of too-low, which is safest - */ - conf->spacing++; - } - /* calculate the max read-ahead size. * For read-ahead of large files to be effective, we need to * readahead at least twice a whole stripe. i.e. number of devices @@ -365,48 +338,107 @@ static int raid0_run (mddev_t *mddev) * chunksize should be used in that case. */ { - int stripe = mddev->raid_disks * mddev->chunk_size / PAGE_SIZE; + int stripe = mddev->raid_disks * + (mddev->chunk_sectors << 9) / PAGE_SIZE; if (mddev->queue->backing_dev_info.ra_pages < 2* stripe) mddev->queue->backing_dev_info.ra_pages = 2* stripe; } - blk_queue_merge_bvec(mddev->queue, raid0_mergeable_bvec); + dump_zones(mddev); return 0; +} -out_free_conf: +static int raid0_stop(mddev_t *mddev) +{ + raid0_conf_t *conf = mddev->private; + + blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/ kfree(conf->strip_zone); kfree(conf->devlist); kfree(conf); mddev->private = NULL; -out: - return -ENOMEM; -} - -static int raid0_stop (mddev_t *mddev) -{ - raid0_conf_t *conf = mddev_to_conf(mddev); - - blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/ - kfree(conf->hash_table); - conf->hash_table = NULL; - kfree(conf->strip_zone); - conf->strip_zone = NULL; - kfree(conf); - mddev->private = NULL; - return 0; } -static int raid0_make_request (struct request_queue *q, struct bio *bio) +/* Find the zone which holds a particular offset + * Update *sectorp to be an offset in that zone + */ +static struct strip_zone *find_zone(struct raid0_private_data *conf, + sector_t *sectorp) +{ + int i; + struct strip_zone *z = conf->strip_zone; + sector_t sector = *sectorp; + + for (i = 0; i < conf->nr_strip_zones; i++) + if (sector < z[i].zone_end) { + if (i) + *sectorp = sector - z[i-1].zone_end; + return z + i; + } + BUG(); +} + +/* + * remaps the bio to the target device. we separate two flows. + * power 2 flow and a general flow for the sake of perfromance +*/ +static mdk_rdev_t *map_sector(mddev_t *mddev, struct strip_zone *zone, + sector_t sector, sector_t *sector_offset) +{ + unsigned int sect_in_chunk; + sector_t chunk; + raid0_conf_t *conf = mddev->private; + unsigned int chunk_sects = mddev->chunk_sectors; + + if (is_power_of_2(chunk_sects)) { + int chunksect_bits = ffz(~chunk_sects); + /* find the sector offset inside the chunk */ + sect_in_chunk = sector & (chunk_sects - 1); + sector >>= chunksect_bits; + /* chunk in zone */ + chunk = *sector_offset; + /* quotient is the chunk in real device*/ + sector_div(chunk, zone->nb_dev << chunksect_bits); + } else{ + sect_in_chunk = sector_div(sector, chunk_sects); + chunk = *sector_offset; + sector_div(chunk, chunk_sects * zone->nb_dev); + } + /* + * position the bio over the real device + * real sector = chunk in device + starting of zone + * + the position in the chunk + */ + *sector_offset = (chunk * chunk_sects) + sect_in_chunk; + return conf->devlist[(zone - conf->strip_zone)*mddev->raid_disks + + sector_div(sector, zone->nb_dev)]; +} + +/* + * Is io distribute over 1 or more chunks ? +*/ +static inline int is_io_in_chunk_boundary(mddev_t *mddev, + unsigned int chunk_sects, struct bio *bio) +{ + if (likely(is_power_of_2(chunk_sects))) { + return chunk_sects >= ((bio->bi_sector & (chunk_sects-1)) + + (bio->bi_size >> 9)); + } else{ + sector_t sector = bio->bi_sector; + return chunk_sects >= (sector_div(sector, chunk_sects) + + (bio->bi_size >> 9)); + } +} + +static int raid0_make_request(struct request_queue *q, struct bio *bio) { mddev_t *mddev = q->queuedata; - unsigned int sect_in_chunk, chunksect_bits, chunk_sects; - raid0_conf_t *conf = mddev_to_conf(mddev); + unsigned int chunk_sects; + sector_t sector_offset; struct strip_zone *zone; mdk_rdev_t *tmp_dev; - sector_t chunk; - sector_t sector, rsect; const int rw = bio_data_dir(bio); int cpu; @@ -421,11 +453,9 @@ static int raid0_make_request (struct request_queue *q, struct bio *bio) bio_sectors(bio)); part_stat_unlock(); - chunk_sects = mddev->chunk_size >> 9; - chunksect_bits = ffz(~chunk_sects); - sector = bio->bi_sector; - - if (unlikely(chunk_sects < (bio->bi_sector & (chunk_sects - 1)) + (bio->bi_size >> 9))) { + chunk_sects = mddev->chunk_sectors; + if (unlikely(!is_io_in_chunk_boundary(mddev, chunk_sects, bio))) { + sector_t sector = bio->bi_sector; struct bio_pair *bp; /* Sanity check -- queue functions should prevent this happening */ if (bio->bi_vcnt != 1 || @@ -434,7 +464,12 @@ static int raid0_make_request (struct request_queue *q, struct bio *bio) /* This is a one page bio that upper layers * refuse to split for us, so we need to split it. */ - bp = bio_split(bio, chunk_sects - (bio->bi_sector & (chunk_sects - 1))); + if (likely(is_power_of_2(chunk_sects))) + bp = bio_split(bio, chunk_sects - (sector & + (chunk_sects-1))); + else + bp = bio_split(bio, chunk_sects - + sector_div(sector, chunk_sects)); if (raid0_make_request(q, &bp->bio1)) generic_make_request(&bp->bio1); if (raid0_make_request(q, &bp->bio2)) @@ -443,34 +478,14 @@ static int raid0_make_request (struct request_queue *q, struct bio *bio) bio_pair_release(bp); return 0; } - - { - sector_t x = sector >> conf->sector_shift; - sector_div(x, (u32)conf->spacing); - zone = conf->hash_table[x]; - } - - while (sector >= zone->zone_start + zone->sectors) - zone++; - - sect_in_chunk = bio->bi_sector & (chunk_sects - 1); - - - { - sector_t x = (sector - zone->zone_start) >> chunksect_bits; - - sector_div(x, zone->nb_dev); - chunk = x; - - x = sector >> chunksect_bits; - tmp_dev = zone->dev[sector_div(x, zone->nb_dev)]; - } - rsect = (chunk << chunksect_bits) + zone->dev_start + sect_in_chunk; - + sector_offset = bio->bi_sector; + zone = find_zone(mddev->private, §or_offset); + tmp_dev = map_sector(mddev, zone, bio->bi_sector, + §or_offset); bio->bi_bdev = tmp_dev->bdev; - bio->bi_sector = rsect + tmp_dev->data_offset; - + bio->bi_sector = sector_offset + zone->dev_start + + tmp_dev->data_offset; /* * Let the main block layer submit the IO and resolve recursion: */ @@ -485,31 +500,35 @@ bad_map: return 0; } -static void raid0_status (struct seq_file *seq, mddev_t *mddev) +static void raid0_status(struct seq_file *seq, mddev_t *mddev) { #undef MD_DEBUG #ifdef MD_DEBUG int j, k, h; char b[BDEVNAME_SIZE]; - raid0_conf_t *conf = mddev_to_conf(mddev); + raid0_conf_t *conf = mddev->private; + sector_t zone_size; + sector_t zone_start = 0; h = 0; + for (j = 0; j < conf->nr_strip_zones; j++) { seq_printf(seq, " z%d", j); - if (conf->hash_table[h] == conf->strip_zone+j) - seq_printf(seq, "(h%d)", h++); seq_printf(seq, "=["); for (k = 0; k < conf->strip_zone[j].nb_dev; k++) seq_printf(seq, "%s/", bdevname( - conf->strip_zone[j].dev[k]->bdev,b)); + conf->devlist[j*mddev->raid_disks + k] + ->bdev, b)); - seq_printf(seq, "] zs=%d ds=%d s=%d\n", - conf->strip_zone[j].zone_start, - conf->strip_zone[j].dev_start, - conf->strip_zone[j].sectors); + zone_size = conf->strip_zone[j].zone_end - zone_start; + seq_printf(seq, "] ze=%lld ds=%lld s=%lld\n", + (unsigned long long)zone_start>>1, + (unsigned long long)conf->strip_zone[j].dev_start>>1, + (unsigned long long)zone_size>>1); + zone_start = conf->strip_zone[j].zone_end; } #endif - seq_printf(seq, " %dk chunks", mddev->chunk_size/1024); + seq_printf(seq, " %dk chunks", mddev->chunk_sectors / 2); return; } diff --git a/drivers/md/raid0.h b/drivers/md/raid0.h index 824b12eb1d4f..91f8e876ee64 100644 --- a/drivers/md/raid0.h +++ b/drivers/md/raid0.h @@ -3,26 +3,18 @@ struct strip_zone { - sector_t zone_start; /* Zone offset in md_dev (in sectors) */ + sector_t zone_end; /* Start of the next zone (in sectors) */ sector_t dev_start; /* Zone offset in real dev (in sectors) */ - sector_t sectors; /* Zone size in sectors */ int nb_dev; /* # of devices attached to the zone */ - mdk_rdev_t **dev; /* Devices attached to the zone */ }; struct raid0_private_data { - struct strip_zone **hash_table; /* Table of indexes into strip_zone */ struct strip_zone *strip_zone; mdk_rdev_t **devlist; /* lists of rdevs, pointed to by strip_zone->dev */ int nr_strip_zones; - - sector_t spacing; - int sector_shift; /* shift this before divide by spacing */ }; typedef struct raid0_private_data raid0_conf_t; -#define mddev_to_conf(mddev) ((raid0_conf_t *) mddev->private) - #endif diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 36df9109cde1..89939a7aef57 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -182,7 +182,7 @@ static void put_all_bios(conf_t *conf, r1bio_t *r1_bio) static void free_r1bio(r1bio_t *r1_bio) { - conf_t *conf = mddev_to_conf(r1_bio->mddev); + conf_t *conf = r1_bio->mddev->private; /* * Wake up any possible resync thread that waits for the device @@ -196,7 +196,7 @@ static void free_r1bio(r1bio_t *r1_bio) static void put_buf(r1bio_t *r1_bio) { - conf_t *conf = mddev_to_conf(r1_bio->mddev); + conf_t *conf = r1_bio->mddev->private; int i; for (i=0; iraid_disks; i++) { @@ -214,7 +214,7 @@ static void reschedule_retry(r1bio_t *r1_bio) { unsigned long flags; mddev_t *mddev = r1_bio->mddev; - conf_t *conf = mddev_to_conf(mddev); + conf_t *conf = mddev->private; spin_lock_irqsave(&conf->device_lock, flags); list_add(&r1_bio->retry_list, &conf->retry_list); @@ -253,7 +253,7 @@ static void raid_end_bio_io(r1bio_t *r1_bio) */ static inline void update_head_pos(int disk, r1bio_t *r1_bio) { - conf_t *conf = mddev_to_conf(r1_bio->mddev); + conf_t *conf = r1_bio->mddev->private; conf->mirrors[disk].head_position = r1_bio->sector + (r1_bio->sectors); @@ -264,7 +264,7 @@ static void raid1_end_read_request(struct bio *bio, int error) int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); r1bio_t * r1_bio = (r1bio_t *)(bio->bi_private); int mirror; - conf_t *conf = mddev_to_conf(r1_bio->mddev); + conf_t *conf = r1_bio->mddev->private; mirror = r1_bio->read_disk; /* @@ -309,7 +309,7 @@ static void raid1_end_write_request(struct bio *bio, int error) int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); r1bio_t * r1_bio = (r1bio_t *)(bio->bi_private); int mirror, behind = test_bit(R1BIO_BehindIO, &r1_bio->state); - conf_t *conf = mddev_to_conf(r1_bio->mddev); + conf_t *conf = r1_bio->mddev->private; struct bio *to_put = NULL; @@ -541,7 +541,7 @@ static int read_balance(conf_t *conf, r1bio_t *r1_bio) static void unplug_slaves(mddev_t *mddev) { - conf_t *conf = mddev_to_conf(mddev); + conf_t *conf = mddev->private; int i; rcu_read_lock(); @@ -573,7 +573,7 @@ static void raid1_unplug(struct request_queue *q) static int raid1_congested(void *data, int bits) { mddev_t *mddev = data; - conf_t *conf = mddev_to_conf(mddev); + conf_t *conf = mddev->private; int i, ret = 0; rcu_read_lock(); @@ -772,7 +772,7 @@ do_sync_io: static int make_request(struct request_queue *q, struct bio * bio) { mddev_t *mddev = q->queuedata; - conf_t *conf = mddev_to_conf(mddev); + conf_t *conf = mddev->private; mirror_info_t *mirror; r1bio_t *r1_bio; struct bio *read_bio; @@ -991,7 +991,7 @@ static int make_request(struct request_queue *q, struct bio * bio) static void status(struct seq_file *seq, mddev_t *mddev) { - conf_t *conf = mddev_to_conf(mddev); + conf_t *conf = mddev->private; int i; seq_printf(seq, " [%d/%d] [", conf->raid_disks, @@ -1010,7 +1010,7 @@ static void status(struct seq_file *seq, mddev_t *mddev) static void error(mddev_t *mddev, mdk_rdev_t *rdev) { char b[BDEVNAME_SIZE]; - conf_t *conf = mddev_to_conf(mddev); + conf_t *conf = mddev->private; /* * If it is not operational, then we have already marked it as dead @@ -1130,7 +1130,7 @@ static int raid1_add_disk(mddev_t *mddev, mdk_rdev_t *rdev) * a one page request is never in violation. */ if (rdev->bdev->bd_disk->queue->merge_bvec_fn && - mddev->queue->max_sectors > (PAGE_SIZE>>9)) + queue_max_sectors(mddev->queue) > (PAGE_SIZE>>9)) blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9); p->head_position = 0; @@ -1214,7 +1214,7 @@ static void end_sync_write(struct bio *bio, int error) int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); r1bio_t * r1_bio = (r1bio_t *)(bio->bi_private); mddev_t *mddev = r1_bio->mddev; - conf_t *conf = mddev_to_conf(mddev); + conf_t *conf = mddev->private; int i; int mirror=0; @@ -1248,7 +1248,7 @@ static void end_sync_write(struct bio *bio, int error) static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio) { - conf_t *conf = mddev_to_conf(mddev); + conf_t *conf = mddev->private; int i; int disks = conf->raid_disks; struct bio *bio, *wbio; @@ -1562,7 +1562,7 @@ static void raid1d(mddev_t *mddev) r1bio_t *r1_bio; struct bio *bio; unsigned long flags; - conf_t *conf = mddev_to_conf(mddev); + conf_t *conf = mddev->private; struct list_head *head = &conf->retry_list; int unplug=0; mdk_rdev_t *rdev; @@ -1585,7 +1585,7 @@ static void raid1d(mddev_t *mddev) spin_unlock_irqrestore(&conf->device_lock, flags); mddev = r1_bio->mddev; - conf = mddev_to_conf(mddev); + conf = mddev->private; if (test_bit(R1BIO_IsSync, &r1_bio->state)) { sync_request_write(mddev, r1_bio); unplug = 1; @@ -1706,7 +1706,7 @@ static int init_resync(conf_t *conf) static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, int go_faster) { - conf_t *conf = mddev_to_conf(mddev); + conf_t *conf = mddev->private; r1bio_t *r1_bio; struct bio *bio; sector_t max_sector, nr_sectors; @@ -1996,7 +1996,7 @@ static int run(mddev_t *mddev) * a one page request is never in violation. */ if (rdev->bdev->bd_disk->queue->merge_bvec_fn && - mddev->queue->max_sectors > (PAGE_SIZE>>9)) + queue_max_sectors(mddev->queue) > (PAGE_SIZE>>9)) blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9); disk->head_position = 0; @@ -2052,6 +2052,10 @@ static int run(mddev_t *mddev) goto out_free_conf; } + if (mddev->recovery_cp != MaxSector) + printk(KERN_NOTICE "raid1: %s is not clean" + " -- starting background reconstruction\n", + mdname(mddev)); printk(KERN_INFO "raid1: raid set %s active with %d out of %d mirrors\n", mdname(mddev), mddev->raid_disks - mddev->degraded, @@ -2087,7 +2091,7 @@ out: static int stop(mddev_t *mddev) { - conf_t *conf = mddev_to_conf(mddev); + conf_t *conf = mddev->private; struct bitmap *bitmap = mddev->bitmap; int behind_wait = 0; @@ -2155,16 +2159,16 @@ static int raid1_reshape(mddev_t *mddev) mempool_t *newpool, *oldpool; struct pool_info *newpoolinfo; mirror_info_t *newmirrors; - conf_t *conf = mddev_to_conf(mddev); + conf_t *conf = mddev->private; int cnt, raid_disks; unsigned long flags; int d, d2, err; /* Cannot change chunk_size, layout, or level */ - if (mddev->chunk_size != mddev->new_chunk || + if (mddev->chunk_sectors != mddev->new_chunk_sectors || mddev->layout != mddev->new_layout || mddev->level != mddev->new_level) { - mddev->new_chunk = mddev->chunk_size; + mddev->new_chunk_sectors = mddev->chunk_sectors; mddev->new_layout = mddev->layout; mddev->new_level = mddev->level; return -EINVAL; @@ -2252,7 +2256,7 @@ static int raid1_reshape(mddev_t *mddev) static void raid1_quiesce(mddev_t *mddev, int state) { - conf_t *conf = mddev_to_conf(mddev); + conf_t *conf = mddev->private; switch(state) { case 1: diff --git a/drivers/md/raid1.h b/drivers/md/raid1.h index 1620eea3d57c..e87b84deff68 100644 --- a/drivers/md/raid1.h +++ b/drivers/md/raid1.h @@ -63,12 +63,6 @@ struct r1_private_data_s { typedef struct r1_private_data_s conf_t; -/* - * this is the only point in the RAID code where we violate - * C type safety. mddev->private is an 'opaque' pointer. - */ -#define mddev_to_conf(mddev) ((conf_t *) mddev->private) - /* * this is our 'private' RAID1 bio. * diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 499620afb44b..ae12ceafe10c 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -188,7 +188,7 @@ static void put_all_bios(conf_t *conf, r10bio_t *r10_bio) static void free_r10bio(r10bio_t *r10_bio) { - conf_t *conf = mddev_to_conf(r10_bio->mddev); + conf_t *conf = r10_bio->mddev->private; /* * Wake up any possible resync thread that waits for the device @@ -202,7 +202,7 @@ static void free_r10bio(r10bio_t *r10_bio) static void put_buf(r10bio_t *r10_bio) { - conf_t *conf = mddev_to_conf(r10_bio->mddev); + conf_t *conf = r10_bio->mddev->private; mempool_free(r10_bio, conf->r10buf_pool); @@ -213,7 +213,7 @@ static void reschedule_retry(r10bio_t *r10_bio) { unsigned long flags; mddev_t *mddev = r10_bio->mddev; - conf_t *conf = mddev_to_conf(mddev); + conf_t *conf = mddev->private; spin_lock_irqsave(&conf->device_lock, flags); list_add(&r10_bio->retry_list, &conf->retry_list); @@ -245,7 +245,7 @@ static void raid_end_bio_io(r10bio_t *r10_bio) */ static inline void update_head_pos(int slot, r10bio_t *r10_bio) { - conf_t *conf = mddev_to_conf(r10_bio->mddev); + conf_t *conf = r10_bio->mddev->private; conf->mirrors[r10_bio->devs[slot].devnum].head_position = r10_bio->devs[slot].addr + (r10_bio->sectors); @@ -256,7 +256,7 @@ static void raid10_end_read_request(struct bio *bio, int error) int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); r10bio_t * r10_bio = (r10bio_t *)(bio->bi_private); int slot, dev; - conf_t *conf = mddev_to_conf(r10_bio->mddev); + conf_t *conf = r10_bio->mddev->private; slot = r10_bio->read_slot; @@ -297,7 +297,7 @@ static void raid10_end_write_request(struct bio *bio, int error) int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); r10bio_t * r10_bio = (r10bio_t *)(bio->bi_private); int slot, dev; - conf_t *conf = mddev_to_conf(r10_bio->mddev); + conf_t *conf = r10_bio->mddev->private; for (slot = 0; slot < conf->copies; slot++) if (r10_bio->devs[slot].bio == bio) @@ -461,7 +461,7 @@ static int raid10_mergeable_bvec(struct request_queue *q, mddev_t *mddev = q->queuedata; sector_t sector = bvm->bi_sector + get_start_sect(bvm->bi_bdev); int max; - unsigned int chunk_sectors = mddev->chunk_size >> 9; + unsigned int chunk_sectors = mddev->chunk_sectors; unsigned int bio_sectors = bvm->bi_size >> 9; max = (chunk_sectors - ((sector & (chunk_sectors - 1)) + bio_sectors)) << 9; @@ -596,7 +596,7 @@ rb_out: static void unplug_slaves(mddev_t *mddev) { - conf_t *conf = mddev_to_conf(mddev); + conf_t *conf = mddev->private; int i; rcu_read_lock(); @@ -628,7 +628,7 @@ static void raid10_unplug(struct request_queue *q) static int raid10_congested(void *data, int bits) { mddev_t *mddev = data; - conf_t *conf = mddev_to_conf(mddev); + conf_t *conf = mddev->private; int i, ret = 0; rcu_read_lock(); @@ -788,7 +788,7 @@ static void unfreeze_array(conf_t *conf) static int make_request(struct request_queue *q, struct bio * bio) { mddev_t *mddev = q->queuedata; - conf_t *conf = mddev_to_conf(mddev); + conf_t *conf = mddev->private; mirror_info_t *mirror; r10bio_t *r10_bio; struct bio *read_bio; @@ -981,11 +981,11 @@ static int make_request(struct request_queue *q, struct bio * bio) static void status(struct seq_file *seq, mddev_t *mddev) { - conf_t *conf = mddev_to_conf(mddev); + conf_t *conf = mddev->private; int i; if (conf->near_copies < conf->raid_disks) - seq_printf(seq, " %dK chunks", mddev->chunk_size/1024); + seq_printf(seq, " %dK chunks", mddev->chunk_sectors / 2); if (conf->near_copies > 1) seq_printf(seq, " %d near-copies", conf->near_copies); if (conf->far_copies > 1) { @@ -1006,7 +1006,7 @@ static void status(struct seq_file *seq, mddev_t *mddev) static void error(mddev_t *mddev, mdk_rdev_t *rdev) { char b[BDEVNAME_SIZE]; - conf_t *conf = mddev_to_conf(mddev); + conf_t *conf = mddev->private; /* * If it is not operational, then we have already marked it as dead @@ -1158,8 +1158,8 @@ static int raid10_add_disk(mddev_t *mddev, mdk_rdev_t *rdev) * a one page request is never in violation. */ if (rdev->bdev->bd_disk->queue->merge_bvec_fn && - mddev->queue->max_sectors > (PAGE_SIZE>>9)) - mddev->queue->max_sectors = (PAGE_SIZE>>9); + queue_max_sectors(mddev->queue) > (PAGE_SIZE>>9)) + blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9); p->head_position = 0; rdev->raid_disk = mirror; @@ -1215,7 +1215,7 @@ abort: static void end_sync_read(struct bio *bio, int error) { r10bio_t * r10_bio = (r10bio_t *)(bio->bi_private); - conf_t *conf = mddev_to_conf(r10_bio->mddev); + conf_t *conf = r10_bio->mddev->private; int i,d; for (i=0; icopies; i++) @@ -1253,7 +1253,7 @@ static void end_sync_write(struct bio *bio, int error) int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); r10bio_t * r10_bio = (r10bio_t *)(bio->bi_private); mddev_t *mddev = r10_bio->mddev; - conf_t *conf = mddev_to_conf(mddev); + conf_t *conf = mddev->private; int i,d; for (i = 0; i < conf->copies; i++) @@ -1300,7 +1300,7 @@ static void end_sync_write(struct bio *bio, int error) */ static void sync_request_write(mddev_t *mddev, r10bio_t *r10_bio) { - conf_t *conf = mddev_to_conf(mddev); + conf_t *conf = mddev->private; int i, first; struct bio *tbio, *fbio; @@ -1400,7 +1400,7 @@ done: static void recovery_request_write(mddev_t *mddev, r10bio_t *r10_bio) { - conf_t *conf = mddev_to_conf(mddev); + conf_t *conf = mddev->private; int i, d; struct bio *bio, *wbio; @@ -1549,7 +1549,7 @@ static void raid10d(mddev_t *mddev) r10bio_t *r10_bio; struct bio *bio; unsigned long flags; - conf_t *conf = mddev_to_conf(mddev); + conf_t *conf = mddev->private; struct list_head *head = &conf->retry_list; int unplug=0; mdk_rdev_t *rdev; @@ -1572,7 +1572,7 @@ static void raid10d(mddev_t *mddev) spin_unlock_irqrestore(&conf->device_lock, flags); mddev = r10_bio->mddev; - conf = mddev_to_conf(mddev); + conf = mddev->private; if (test_bit(R10BIO_IsSync, &r10_bio->state)) { sync_request_write(mddev, r10_bio); unplug = 1; @@ -1680,7 +1680,7 @@ static int init_resync(conf_t *conf) static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, int go_faster) { - conf_t *conf = mddev_to_conf(mddev); + conf_t *conf = mddev->private; r10bio_t *r10_bio; struct bio *biolist = NULL, *bio; sector_t max_sector, nr_sectors; @@ -2026,7 +2026,7 @@ static sector_t raid10_size(mddev_t *mddev, sector_t sectors, int raid_disks) { sector_t size; - conf_t *conf = mddev_to_conf(mddev); + conf_t *conf = mddev->private; if (!raid_disks) raid_disks = mddev->raid_disks; @@ -2050,9 +2050,10 @@ static int run(mddev_t *mddev) int nc, fc, fo; sector_t stride, size; - if (mddev->chunk_size < PAGE_SIZE) { + if (mddev->chunk_sectors < (PAGE_SIZE >> 9) || + !is_power_of_2(mddev->chunk_sectors)) { printk(KERN_ERR "md/raid10: chunk size must be " - "at least PAGE_SIZE(%ld).\n", PAGE_SIZE); + "at least PAGE_SIZE(%ld) and be a power of 2.\n", PAGE_SIZE); return -EINVAL; } @@ -2095,8 +2096,8 @@ static int run(mddev_t *mddev) conf->far_copies = fc; conf->copies = nc*fc; conf->far_offset = fo; - conf->chunk_mask = (sector_t)(mddev->chunk_size>>9)-1; - conf->chunk_shift = ffz(~mddev->chunk_size) - 9; + conf->chunk_mask = mddev->chunk_sectors - 1; + conf->chunk_shift = ffz(~mddev->chunk_sectors); size = mddev->dev_sectors >> conf->chunk_shift; sector_div(size, fc); size = size * conf->raid_disks; @@ -2145,8 +2146,8 @@ static int run(mddev_t *mddev) * a one page request is never in violation. */ if (rdev->bdev->bd_disk->queue->merge_bvec_fn && - mddev->queue->max_sectors > (PAGE_SIZE>>9)) - mddev->queue->max_sectors = (PAGE_SIZE>>9); + queue_max_sectors(mddev->queue) > (PAGE_SIZE>>9)) + blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9); disk->head_position = 0; } @@ -2185,6 +2186,10 @@ static int run(mddev_t *mddev) goto out_free_conf; } + if (mddev->recovery_cp != MaxSector) + printk(KERN_NOTICE "raid10: %s is not clean" + " -- starting background reconstruction\n", + mdname(mddev)); printk(KERN_INFO "raid10: raid set %s active with %d out of %d devices\n", mdname(mddev), mddev->raid_disks - mddev->degraded, @@ -2204,7 +2209,8 @@ static int run(mddev_t *mddev) * maybe... */ { - int stripe = conf->raid_disks * (mddev->chunk_size / PAGE_SIZE); + int stripe = conf->raid_disks * + ((mddev->chunk_sectors << 9) / PAGE_SIZE); stripe /= conf->near_copies; if (mddev->queue->backing_dev_info.ra_pages < 2* stripe) mddev->queue->backing_dev_info.ra_pages = 2* stripe; @@ -2227,7 +2233,7 @@ out: static int stop(mddev_t *mddev) { - conf_t *conf = mddev_to_conf(mddev); + conf_t *conf = mddev->private; raise_barrier(conf, 0); lower_barrier(conf); @@ -2245,7 +2251,7 @@ static int stop(mddev_t *mddev) static void raid10_quiesce(mddev_t *mddev, int state) { - conf_t *conf = mddev_to_conf(mddev); + conf_t *conf = mddev->private; switch(state) { case 1: diff --git a/drivers/md/raid10.h b/drivers/md/raid10.h index 244dbe507a54..59cd1efb8d30 100644 --- a/drivers/md/raid10.h +++ b/drivers/md/raid10.h @@ -61,12 +61,6 @@ struct r10_private_data_s { typedef struct r10_private_data_s conf_t; -/* - * this is the only point in the RAID code where we violate - * C type safety. mddev->private is an 'opaque' pointer. - */ -#define mddev_to_conf(mddev) ((conf_t *) mddev->private) - /* * this is our 'private' RAID10 bio. * diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 54ef8d75541d..cac6f4d3a143 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -1617,8 +1617,8 @@ static sector_t raid5_compute_sector(raid5_conf_t *conf, sector_t r_sector, sector_t new_sector; int algorithm = previous ? conf->prev_algo : conf->algorithm; - int sectors_per_chunk = previous ? (conf->prev_chunk >> 9) - : (conf->chunk_size >> 9); + int sectors_per_chunk = previous ? conf->prev_chunk_sectors + : conf->chunk_sectors; int raid_disks = previous ? conf->previous_raid_disks : conf->raid_disks; int data_disks = raid_disks - conf->max_degraded; @@ -1823,8 +1823,8 @@ static sector_t compute_blocknr(struct stripe_head *sh, int i, int previous) int raid_disks = sh->disks; int data_disks = raid_disks - conf->max_degraded; sector_t new_sector = sh->sector, check; - int sectors_per_chunk = previous ? (conf->prev_chunk >> 9) - : (conf->chunk_size >> 9); + int sectors_per_chunk = previous ? conf->prev_chunk_sectors + : conf->chunk_sectors; int algorithm = previous ? conf->prev_algo : conf->algorithm; sector_t stripe; @@ -2098,8 +2098,7 @@ static void stripe_set_idx(sector_t stripe, raid5_conf_t *conf, int previous, struct stripe_head *sh) { int sectors_per_chunk = - previous ? (conf->prev_chunk >> 9) - : (conf->chunk_size >> 9); + previous ? conf->prev_chunk_sectors : conf->chunk_sectors; int dd_idx; int chunk_offset = sector_div(stripe, sectors_per_chunk); int disks = previous ? conf->previous_raid_disks : conf->raid_disks; @@ -3496,7 +3495,7 @@ static void activate_bit_delay(raid5_conf_t *conf) static void unplug_slaves(mddev_t *mddev) { - raid5_conf_t *conf = mddev_to_conf(mddev); + raid5_conf_t *conf = mddev->private; int i; rcu_read_lock(); @@ -3520,7 +3519,7 @@ static void unplug_slaves(mddev_t *mddev) static void raid5_unplug_device(struct request_queue *q) { mddev_t *mddev = q->queuedata; - raid5_conf_t *conf = mddev_to_conf(mddev); + raid5_conf_t *conf = mddev->private; unsigned long flags; spin_lock_irqsave(&conf->device_lock, flags); @@ -3539,7 +3538,7 @@ static void raid5_unplug_device(struct request_queue *q) static int raid5_congested(void *data, int bits) { mddev_t *mddev = data; - raid5_conf_t *conf = mddev_to_conf(mddev); + raid5_conf_t *conf = mddev->private; /* No difference between reads and writes. Just check * how busy the stripe_cache is @@ -3564,14 +3563,14 @@ static int raid5_mergeable_bvec(struct request_queue *q, mddev_t *mddev = q->queuedata; sector_t sector = bvm->bi_sector + get_start_sect(bvm->bi_bdev); int max; - unsigned int chunk_sectors = mddev->chunk_size >> 9; + unsigned int chunk_sectors = mddev->chunk_sectors; unsigned int bio_sectors = bvm->bi_size >> 9; if ((bvm->bi_rw & 1) == WRITE) return biovec->bv_len; /* always allow writes to be mergeable */ - if (mddev->new_chunk < mddev->chunk_size) - chunk_sectors = mddev->new_chunk >> 9; + if (mddev->new_chunk_sectors < mddev->chunk_sectors) + chunk_sectors = mddev->new_chunk_sectors; max = (chunk_sectors - ((sector & (chunk_sectors - 1)) + bio_sectors)) << 9; if (max < 0) max = 0; if (max <= biovec->bv_len && bio_sectors == 0) @@ -3584,11 +3583,11 @@ static int raid5_mergeable_bvec(struct request_queue *q, static int in_chunk_boundary(mddev_t *mddev, struct bio *bio) { sector_t sector = bio->bi_sector + get_start_sect(bio->bi_bdev); - unsigned int chunk_sectors = mddev->chunk_size >> 9; + unsigned int chunk_sectors = mddev->chunk_sectors; unsigned int bio_sectors = bio->bi_size >> 9; - if (mddev->new_chunk < mddev->chunk_size) - chunk_sectors = mddev->new_chunk >> 9; + if (mddev->new_chunk_sectors < mddev->chunk_sectors) + chunk_sectors = mddev->new_chunk_sectors; return chunk_sectors >= ((sector & (chunk_sectors - 1)) + bio_sectors); } @@ -3652,7 +3651,7 @@ static void raid5_align_endio(struct bio *bi, int error) bio_put(bi); mddev = raid_bi->bi_bdev->bd_disk->queue->queuedata; - conf = mddev_to_conf(mddev); + conf = mddev->private; rdev = (void*)raid_bi->bi_next; raid_bi->bi_next = NULL; @@ -3675,10 +3674,10 @@ static int bio_fits_rdev(struct bio *bi) { struct request_queue *q = bdev_get_queue(bi->bi_bdev); - if ((bi->bi_size>>9) > q->max_sectors) + if ((bi->bi_size>>9) > queue_max_sectors(q)) return 0; blk_recount_segments(q, bi); - if (bi->bi_phys_segments > q->max_phys_segments) + if (bi->bi_phys_segments > queue_max_phys_segments(q)) return 0; if (q->merge_bvec_fn) @@ -3694,7 +3693,7 @@ static int bio_fits_rdev(struct bio *bi) static int chunk_aligned_read(struct request_queue *q, struct bio * raid_bio) { mddev_t *mddev = q->queuedata; - raid5_conf_t *conf = mddev_to_conf(mddev); + raid5_conf_t *conf = mddev->private; unsigned int dd_idx; struct bio* align_bi; mdk_rdev_t *rdev; @@ -3811,7 +3810,7 @@ static struct stripe_head *__get_priority_stripe(raid5_conf_t *conf) static int make_request(struct request_queue *q, struct bio * bi) { mddev_t *mddev = q->queuedata; - raid5_conf_t *conf = mddev_to_conf(mddev); + raid5_conf_t *conf = mddev->private; int dd_idx; sector_t new_sector; sector_t logical_sector, last_sector; @@ -3908,6 +3907,7 @@ static int make_request(struct request_queue *q, struct bio * bi) spin_unlock_irq(&conf->device_lock); if (must_retry) { release_stripe(sh); + schedule(); goto retry; } } @@ -4003,10 +4003,10 @@ static sector_t reshape_request(mddev_t *mddev, sector_t sector_nr, int *skipped * If old and new chunk sizes differ, we need to process the * largest of these */ - if (mddev->new_chunk > mddev->chunk_size) - reshape_sectors = mddev->new_chunk / 512; + if (mddev->new_chunk_sectors > mddev->chunk_sectors) + reshape_sectors = mddev->new_chunk_sectors; else - reshape_sectors = mddev->chunk_size / 512; + reshape_sectors = mddev->chunk_sectors; /* we update the metadata when there is more than 3Meg * in the block range (that is rather arbitrary, should @@ -4129,7 +4129,7 @@ static sector_t reshape_request(mddev_t *mddev, sector_t sector_nr, int *skipped 1, &dd_idx, NULL); last_sector = raid5_compute_sector(conf, ((stripe_addr+reshape_sectors) - *(new_data_disks) - 1), + * new_data_disks - 1), 1, &dd_idx, NULL); if (last_sector >= mddev->dev_sectors) last_sector = mddev->dev_sectors - 1; @@ -4158,7 +4158,7 @@ static sector_t reshape_request(mddev_t *mddev, sector_t sector_nr, int *skipped wait_event(conf->wait_for_overlap, atomic_read(&conf->reshape_stripes) == 0); mddev->reshape_position = conf->reshape_progress; - mddev->curr_resync_completed = mddev->curr_resync; + mddev->curr_resync_completed = mddev->curr_resync + reshape_sectors; conf->reshape_checkpoint = jiffies; set_bit(MD_CHANGE_DEVS, &mddev->flags); md_wakeup_thread(mddev->thread); @@ -4371,7 +4371,7 @@ static void synchronize_stripe_processing(struct list_head *domain) static void raid5d(mddev_t *mddev) { struct stripe_head *sh; - raid5_conf_t *conf = mddev_to_conf(mddev); + raid5_conf_t *conf = mddev->private; int handled; LIST_HEAD(raid_domain); @@ -4428,7 +4428,7 @@ static void raid5d(mddev_t *mddev) static ssize_t raid5_show_stripe_cache_size(mddev_t *mddev, char *page) { - raid5_conf_t *conf = mddev_to_conf(mddev); + raid5_conf_t *conf = mddev->private; if (conf) return sprintf(page, "%d\n", conf->max_nr_stripes); else @@ -4438,7 +4438,7 @@ raid5_show_stripe_cache_size(mddev_t *mddev, char *page) static ssize_t raid5_store_stripe_cache_size(mddev_t *mddev, const char *page, size_t len) { - raid5_conf_t *conf = mddev_to_conf(mddev); + raid5_conf_t *conf = mddev->private; unsigned long new; int err; @@ -4476,7 +4476,7 @@ raid5_stripecache_size = __ATTR(stripe_cache_size, S_IRUGO | S_IWUSR, static ssize_t raid5_show_preread_threshold(mddev_t *mddev, char *page) { - raid5_conf_t *conf = mddev_to_conf(mddev); + raid5_conf_t *conf = mddev->private; if (conf) return sprintf(page, "%d\n", conf->bypass_threshold); else @@ -4486,7 +4486,7 @@ raid5_show_preread_threshold(mddev_t *mddev, char *page) static ssize_t raid5_store_preread_threshold(mddev_t *mddev, const char *page, size_t len) { - raid5_conf_t *conf = mddev_to_conf(mddev); + raid5_conf_t *conf = mddev->private; unsigned long new; if (len >= PAGE_SIZE) return -EINVAL; @@ -4510,7 +4510,7 @@ raid5_preread_bypass_threshold = __ATTR(preread_bypass_threshold, static ssize_t stripe_cache_active_show(mddev_t *mddev, char *page) { - raid5_conf_t *conf = mddev_to_conf(mddev); + raid5_conf_t *conf = mddev->private; if (conf) return sprintf(page, "%d\n", atomic_read(&conf->active_stripes)); else @@ -4534,7 +4534,7 @@ static struct attribute_group raid5_attrs_group = { static sector_t raid5_size(mddev_t *mddev, sector_t sectors, int raid_disks) { - raid5_conf_t *conf = mddev_to_conf(mddev); + raid5_conf_t *conf = mddev->private; if (!sectors) sectors = mddev->dev_sectors; @@ -4546,8 +4546,8 @@ raid5_size(mddev_t *mddev, sector_t sectors, int raid_disks) raid_disks = conf->previous_raid_disks; } - sectors &= ~((sector_t)mddev->chunk_size/512 - 1); - sectors &= ~((sector_t)mddev->new_chunk/512 - 1); + sectors &= ~((sector_t)mddev->chunk_sectors - 1); + sectors &= ~((sector_t)mddev->new_chunk_sectors - 1); return sectors * (raid_disks - conf->max_degraded); } @@ -4691,9 +4691,11 @@ static raid5_conf_t *setup_conf(mddev_t *mddev) return ERR_PTR(-EINVAL); } - if (!mddev->new_chunk || mddev->new_chunk % PAGE_SIZE) { + if (!mddev->new_chunk_sectors || + (mddev->new_chunk_sectors << 9) % PAGE_SIZE || + !is_power_of_2(mddev->new_chunk_sectors)) { printk(KERN_ERR "raid5: invalid chunk size %d for %s\n", - mddev->new_chunk, mdname(mddev)); + mddev->new_chunk_sectors << 9, mdname(mddev)); return ERR_PTR(-EINVAL); } @@ -4756,7 +4758,8 @@ static raid5_conf_t *setup_conf(mddev_t *mddev) conf->fullsync = 1; } - conf->chunk_size = mddev->new_chunk; + conf->chunk_sectors = mddev->new_chunk_sectors; + conf->level = mddev->new_level; if (conf->level == 6) conf->max_degraded = 2; else @@ -4765,7 +4768,7 @@ static raid5_conf_t *setup_conf(mddev_t *mddev) conf->max_nr_stripes = NR_STRIPES; conf->reshape_progress = mddev->reshape_position; if (conf->reshape_progress != MaxSector) { - conf->prev_chunk = mddev->chunk_size; + conf->prev_chunk_sectors = mddev->chunk_sectors; conf->prev_algo = mddev->layout; } @@ -4803,6 +4806,10 @@ static int run(mddev_t *mddev) int working_disks = 0; mdk_rdev_t *rdev; + if (mddev->recovery_cp != MaxSector) + printk(KERN_NOTICE "raid5: %s is not clean" + " -- starting background reconstruction\n", + mdname(mddev)); if (mddev->reshape_position != MaxSector) { /* Check that we can continue the reshape. * Currently only disks can change, it must @@ -4825,7 +4832,7 @@ static int run(mddev_t *mddev) * geometry. */ here_new = mddev->reshape_position; - if (sector_div(here_new, (mddev->new_chunk>>9)* + if (sector_div(here_new, mddev->new_chunk_sectors * (mddev->raid_disks - max_degraded))) { printk(KERN_ERR "raid5: reshape_position not " "on a stripe boundary\n"); @@ -4833,7 +4840,7 @@ static int run(mddev_t *mddev) } /* here_new is the stripe we will write to */ here_old = mddev->reshape_position; - sector_div(here_old, (mddev->chunk_size>>9)* + sector_div(here_old, mddev->chunk_sectors * (old_disks-max_degraded)); /* here_old is the first stripe that we might need to read * from */ @@ -4848,7 +4855,7 @@ static int run(mddev_t *mddev) } else { BUG_ON(mddev->level != mddev->new_level); BUG_ON(mddev->layout != mddev->new_layout); - BUG_ON(mddev->chunk_size != mddev->new_chunk); + BUG_ON(mddev->chunk_sectors != mddev->new_chunk_sectors); BUG_ON(mddev->delta_disks != 0); } @@ -4882,7 +4889,7 @@ static int run(mddev_t *mddev) } /* device size must be a multiple of chunk size */ - mddev->dev_sectors &= ~(mddev->chunk_size / 512 - 1); + mddev->dev_sectors &= ~(mddev->chunk_sectors - 1); mddev->resync_max_sectors = mddev->dev_sectors; if (mddev->degraded > 0 && @@ -4931,7 +4938,7 @@ static int run(mddev_t *mddev) { int data_disks = conf->previous_raid_disks - conf->max_degraded; int stripe = data_disks * - (mddev->chunk_size / PAGE_SIZE); + ((mddev->chunk_sectors << 9) / PAGE_SIZE); if (mddev->queue->backing_dev_info.ra_pages < 2 * stripe) mddev->queue->backing_dev_info.ra_pages = 2 * stripe; } @@ -5021,7 +5028,8 @@ static void status(struct seq_file *seq, mddev_t *mddev) raid5_conf_t *conf = (raid5_conf_t *) mddev->private; int i; - seq_printf (seq, " level %d, %dk chunk, algorithm %d", mddev->level, mddev->chunk_size >> 10, mddev->layout); + seq_printf(seq, " level %d, %dk chunk, algorithm %d", mddev->level, + mddev->chunk_sectors / 2, mddev->layout); seq_printf (seq, " [%d/%d] [", conf->raid_disks, conf->raid_disks - mddev->degraded); for (i = 0; i < conf->raid_disks; i++) seq_printf (seq, "%s", @@ -5169,7 +5177,7 @@ static int raid5_resize(mddev_t *mddev, sector_t sectors) * any io in the removed space completes, but it hardly seems * worth it. */ - sectors &= ~((sector_t)mddev->chunk_size/512 - 1); + sectors &= ~((sector_t)mddev->chunk_sectors - 1); md_set_array_sectors(mddev, raid5_size(mddev, sectors, mddev->raid_disks)); if (mddev->array_sectors > @@ -5186,14 +5194,37 @@ static int raid5_resize(mddev_t *mddev, sector_t sectors) return 0; } -static int raid5_check_reshape(mddev_t *mddev) +static int check_stripe_cache(mddev_t *mddev) { - raid5_conf_t *conf = mddev_to_conf(mddev); + /* Can only proceed if there are plenty of stripe_heads. + * We need a minimum of one full stripe,, and for sensible progress + * it is best to have about 4 times that. + * If we require 4 times, then the default 256 4K stripe_heads will + * allow for chunk sizes up to 256K, which is probably OK. + * If the chunk size is greater, user-space should request more + * stripe_heads first. + */ + raid5_conf_t *conf = mddev->private; + if (((mddev->chunk_sectors << 9) / STRIPE_SIZE) * 4 + > conf->max_nr_stripes || + ((mddev->new_chunk_sectors << 9) / STRIPE_SIZE) * 4 + > conf->max_nr_stripes) { + printk(KERN_WARNING "raid5: reshape: not enough stripes. Needed %lu\n", + ((max(mddev->chunk_sectors, mddev->new_chunk_sectors) << 9) + / STRIPE_SIZE)*4); + return 0; + } + return 1; +} + +static int check_reshape(mddev_t *mddev) +{ + raid5_conf_t *conf = mddev->private; if (mddev->delta_disks == 0 && mddev->new_layout == mddev->layout && - mddev->new_chunk == mddev->chunk_size) - return -EINVAL; /* nothing to do */ + mddev->new_chunk_sectors == mddev->chunk_sectors) + return 0; /* nothing to do */ if (mddev->bitmap) /* Cannot grow a bitmap yet */ return -EBUSY; @@ -5212,28 +5243,15 @@ static int raid5_check_reshape(mddev_t *mddev) return -EINVAL; } - /* Can only proceed if there are plenty of stripe_heads. - * We need a minimum of one full stripe,, and for sensible progress - * it is best to have about 4 times that. - * If we require 4 times, then the default 256 4K stripe_heads will - * allow for chunk sizes up to 256K, which is probably OK. - * If the chunk size is greater, user-space should request more - * stripe_heads first. - */ - if ((mddev->chunk_size / STRIPE_SIZE) * 4 > conf->max_nr_stripes || - (mddev->new_chunk / STRIPE_SIZE) * 4 > conf->max_nr_stripes) { - printk(KERN_WARNING "raid5: reshape: not enough stripes. Needed %lu\n", - (max(mddev->chunk_size, mddev->new_chunk) - / STRIPE_SIZE)*4); + if (!check_stripe_cache(mddev)) return -ENOSPC; - } return resize_stripes(conf, conf->raid_disks + mddev->delta_disks); } static int raid5_start_reshape(mddev_t *mddev) { - raid5_conf_t *conf = mddev_to_conf(mddev); + raid5_conf_t *conf = mddev->private; mdk_rdev_t *rdev; int spares = 0; int added_devices = 0; @@ -5242,6 +5260,9 @@ static int raid5_start_reshape(mddev_t *mddev) if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery)) return -EBUSY; + if (!check_stripe_cache(mddev)) + return -ENOSPC; + list_for_each_entry(rdev, &mddev->disks, same_set) if (rdev->raid_disk < 0 && !test_bit(Faulty, &rdev->flags)) @@ -5268,8 +5289,8 @@ static int raid5_start_reshape(mddev_t *mddev) spin_lock_irq(&conf->device_lock); conf->previous_raid_disks = conf->raid_disks; conf->raid_disks += mddev->delta_disks; - conf->prev_chunk = conf->chunk_size; - conf->chunk_size = mddev->new_chunk; + conf->prev_chunk_sectors = conf->chunk_sectors; + conf->chunk_sectors = mddev->new_chunk_sectors; conf->prev_algo = conf->algorithm; conf->algorithm = mddev->new_layout; if (mddev->delta_disks < 0) @@ -5351,7 +5372,7 @@ static void end_reshape(raid5_conf_t *conf) */ { int data_disks = conf->raid_disks - conf->max_degraded; - int stripe = data_disks * (conf->chunk_size + int stripe = data_disks * ((conf->chunk_sectors << 9) / PAGE_SIZE); if (conf->mddev->queue->backing_dev_info.ra_pages < 2 * stripe) conf->mddev->queue->backing_dev_info.ra_pages = 2 * stripe; @@ -5365,7 +5386,7 @@ static void end_reshape(raid5_conf_t *conf) static void raid5_finish_reshape(mddev_t *mddev) { struct block_device *bdev; - raid5_conf_t *conf = mddev_to_conf(mddev); + raid5_conf_t *conf = mddev->private; if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery)) { @@ -5396,7 +5417,7 @@ static void raid5_finish_reshape(mddev_t *mddev) raid5_remove_disk(mddev, d); } mddev->layout = conf->algorithm; - mddev->chunk_size = conf->chunk_size; + mddev->chunk_sectors = conf->chunk_sectors; mddev->reshape_position = MaxSector; mddev->delta_disks = 0; } @@ -5404,7 +5425,7 @@ static void raid5_finish_reshape(mddev_t *mddev) static void raid5_quiesce(mddev_t *mddev, int state) { - raid5_conf_t *conf = mddev_to_conf(mddev); + raid5_conf_t *conf = mddev->private; switch(state) { case 2: /* resume for a suspend */ @@ -5454,7 +5475,7 @@ static void *raid5_takeover_raid1(mddev_t *mddev) mddev->new_level = 5; mddev->new_layout = ALGORITHM_LEFT_SYMMETRIC; - mddev->new_chunk = chunksect << 9; + mddev->new_chunk_sectors = chunksect; return setup_conf(mddev); } @@ -5493,24 +5514,24 @@ static void *raid5_takeover_raid6(mddev_t *mddev) } -static int raid5_reconfig(mddev_t *mddev, int new_layout, int new_chunk) +static int raid5_check_reshape(mddev_t *mddev) { /* For a 2-drive array, the layout and chunk size can be changed * immediately as not restriping is needed. * For larger arrays we record the new value - after validation * to be used by a reshape pass. */ - raid5_conf_t *conf = mddev_to_conf(mddev); + raid5_conf_t *conf = mddev->private; + int new_chunk = mddev->new_chunk_sectors; - if (new_layout >= 0 && !algorithm_valid_raid5(new_layout)) + if (mddev->new_layout >= 0 && !algorithm_valid_raid5(mddev->new_layout)) return -EINVAL; if (new_chunk > 0) { - if (new_chunk & (new_chunk-1)) - /* not a power of 2 */ + if (!is_power_of_2(new_chunk)) return -EINVAL; - if (new_chunk < PAGE_SIZE) + if (new_chunk < (PAGE_SIZE>>9)) return -EINVAL; - if (mddev->array_sectors & ((new_chunk>>9)-1)) + if (mddev->array_sectors & (new_chunk-1)) /* not factor of array size */ return -EINVAL; } @@ -5518,49 +5539,39 @@ static int raid5_reconfig(mddev_t *mddev, int new_layout, int new_chunk) /* They look valid */ if (mddev->raid_disks == 2) { - - if (new_layout >= 0) { - conf->algorithm = new_layout; - mddev->layout = mddev->new_layout = new_layout; + /* can make the change immediately */ + if (mddev->new_layout >= 0) { + conf->algorithm = mddev->new_layout; + mddev->layout = mddev->new_layout; } if (new_chunk > 0) { - conf->chunk_size = new_chunk; - mddev->chunk_size = mddev->new_chunk = new_chunk; + conf->chunk_sectors = new_chunk ; + mddev->chunk_sectors = new_chunk; } set_bit(MD_CHANGE_DEVS, &mddev->flags); md_wakeup_thread(mddev->thread); - } else { - if (new_layout >= 0) - mddev->new_layout = new_layout; - if (new_chunk > 0) - mddev->new_chunk = new_chunk; } - return 0; + return check_reshape(mddev); } -static int raid6_reconfig(mddev_t *mddev, int new_layout, int new_chunk) +static int raid6_check_reshape(mddev_t *mddev) { - if (new_layout >= 0 && !algorithm_valid_raid6(new_layout)) + int new_chunk = mddev->new_chunk_sectors; + + if (mddev->new_layout >= 0 && !algorithm_valid_raid6(mddev->new_layout)) return -EINVAL; if (new_chunk > 0) { - if (new_chunk & (new_chunk-1)) - /* not a power of 2 */ + if (!is_power_of_2(new_chunk)) return -EINVAL; - if (new_chunk < PAGE_SIZE) + if (new_chunk < (PAGE_SIZE >> 9)) return -EINVAL; - if (mddev->array_sectors & ((new_chunk>>9)-1)) + if (mddev->array_sectors & (new_chunk-1)) /* not factor of array size */ return -EINVAL; } /* They look valid */ - - if (new_layout >= 0) - mddev->new_layout = new_layout; - if (new_chunk > 0) - mddev->new_chunk = new_chunk; - - return 0; + return check_reshape(mddev); } static void *raid5_takeover(mddev_t *mddev) @@ -5570,8 +5581,6 @@ static void *raid5_takeover(mddev_t *mddev) * raid1 - if there are two drives. We need to know the chunk size * raid4 - trivial - just use a raid4 layout. * raid6 - Providing it is a *_6 layout - * - * For now, just do raid1 */ if (mddev->level == 1) @@ -5653,12 +5662,11 @@ static struct mdk_personality raid6_personality = .sync_request = sync_request, .resize = raid5_resize, .size = raid5_size, - .check_reshape = raid5_check_reshape, + .check_reshape = raid6_check_reshape, .start_reshape = raid5_start_reshape, .finish_reshape = raid5_finish_reshape, .quiesce = raid5_quiesce, .takeover = raid6_takeover, - .reconfig = raid6_reconfig, }; static struct mdk_personality raid5_personality = { @@ -5681,7 +5689,6 @@ static struct mdk_personality raid5_personality = .finish_reshape = raid5_finish_reshape, .quiesce = raid5_quiesce, .takeover = raid5_takeover, - .reconfig = raid5_reconfig, }; static struct mdk_personality raid4_personality = diff --git a/drivers/md/raid5.h b/drivers/md/raid5.h index 116d0b44b2a9..2390e0e83daf 100644 --- a/drivers/md/raid5.h +++ b/drivers/md/raid5.h @@ -337,7 +337,8 @@ struct raid5_private_data { struct hlist_head *stripe_hashtbl; mddev_t *mddev; struct disk_info *spare; - int chunk_size, level, algorithm; + int chunk_sectors; + int level, algorithm; int max_degraded; int raid_disks; int max_nr_stripes; @@ -353,7 +354,8 @@ struct raid5_private_data { */ sector_t reshape_safe; int previous_raid_disks; - int prev_chunk, prev_algo; + int prev_chunk_sectors; + int prev_algo; short generation; /* increments with every reshape */ unsigned long reshape_checkpoint; /* Time we last updated * metadata */ @@ -424,8 +426,6 @@ struct raid5_private_data { typedef struct raid5_private_data raid5_conf_t; -#define mddev_to_conf(mddev) ((raid5_conf_t *) mddev->private) - /* * Our supported algorithms */ diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 223c36ede5ae..ba69beeb0e21 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -2,8 +2,14 @@ # Multimedia device configuration # -menu "Multimedia devices" +menuconfig MEDIA_SUPPORT + tristate "Multimedia support" depends on HAS_IOMEM + help + If you want to use Video for Linux, DVB for Linux, or DAB adapters, + enable this option and other options below. + +if MEDIA_SUPPORT comment "Multimedia core support" @@ -136,4 +142,4 @@ config USB_DABUSB module will be called dabusb. endif # DAB -endmenu +endif # MEDIA_SUPPORT diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/common/ir-keymaps.c index 3fe158ac7bbf..4216328552f6 100644 --- a/drivers/media/common/ir-keymaps.c +++ b/drivers/media/common/ir-keymaps.c @@ -2750,3 +2750,26 @@ IR_KEYTAB_TYPE ir_codes_dm1105_nec[IR_KEYTAB_SIZE] = { [0x1b] = KEY_B, /*recall*/ }; EXPORT_SYMBOL_GPL(ir_codes_dm1105_nec); + +/* EVGA inDtube + Devin Heitmueller + */ +IR_KEYTAB_TYPE ir_codes_evga_indtube[IR_KEYTAB_SIZE] = { + [0x12] = KEY_POWER, + [0x02] = KEY_MODE, /* TV */ + [0x14] = KEY_MUTE, + [0x1a] = KEY_CHANNELUP, + [0x16] = KEY_TV2, /* PIP */ + [0x1d] = KEY_VOLUMEUP, + [0x05] = KEY_CHANNELDOWN, + [0x0f] = KEY_PLAYPAUSE, + [0x19] = KEY_VOLUMEDOWN, + [0x1c] = KEY_REWIND, + [0x0d] = KEY_RECORD, + [0x18] = KEY_FORWARD, + [0x1e] = KEY_PREVIOUS, + [0x1b] = KEY_STOP, + [0x1f] = KEY_NEXT, + [0x13] = KEY_CAMERA, +}; +EXPORT_SYMBOL_GPL(ir_codes_evga_indtube); diff --git a/drivers/media/common/tuners/tuner-simple.c b/drivers/media/common/tuners/tuner-simple.c index 78412c9c424a..149d54cdf7b9 100644 --- a/drivers/media/common/tuners/tuner-simple.c +++ b/drivers/media/common/tuners/tuner-simple.c @@ -416,6 +416,24 @@ static int simple_std_setup(struct dvb_frontend *fe, return 0; } +static int simple_set_aux_byte(struct dvb_frontend *fe, u8 config, u8 aux) +{ + struct tuner_simple_priv *priv = fe->tuner_priv; + int rc; + u8 buffer[2]; + + buffer[0] = (config & ~0x38) | 0x18; + buffer[1] = aux; + + tuner_dbg("setting aux byte: 0x%02x 0x%02x\n", buffer[0], buffer[1]); + + rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 2); + if (2 != rc) + tuner_warn("i2c i/o error: rc == %d (should be 2)\n", rc); + + return rc == 2 ? 0 : rc; +} + static int simple_post_tune(struct dvb_frontend *fe, u8 *buffer, u16 div, u8 config, u8 cb) { @@ -424,17 +442,10 @@ static int simple_post_tune(struct dvb_frontend *fe, u8 *buffer, switch (priv->type) { case TUNER_LG_TDVS_H06XF: - /* Set the Auxiliary Byte. */ - buffer[0] = buffer[2]; - buffer[0] &= ~0x20; - buffer[0] |= 0x18; - buffer[1] = 0x20; - tuner_dbg("tv 0x%02x 0x%02x\n", buffer[0], buffer[1]); - - rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 2); - if (2 != rc) - tuner_warn("i2c i/o error: rc == %d " - "(should be 2)\n", rc); + simple_set_aux_byte(fe, config, 0x20); + break; + case TUNER_PHILIPS_FQ1216LME_MK3: + simple_set_aux_byte(fe, config, 0x60); /* External AGC */ break; case TUNER_MICROTUNE_4042FI5: { @@ -506,6 +517,11 @@ static int simple_radio_bandswitch(struct dvb_frontend *fe, u8 *buffer) case TUNER_THOMSON_DTT761X: buffer[3] = 0x39; break; + case TUNER_PHILIPS_FQ1216LME_MK3: + tuner_err("This tuner doesn't have FM\n"); + /* Set the low band for sanity, since it covers 88-108 MHz */ + buffer[3] = 0x01; + break; case TUNER_MICROTUNE_4049FM5: default: buffer[3] = 0xa4; @@ -678,12 +694,12 @@ static int simple_set_radio_freq(struct dvb_frontend *fe, return 0; } - /* Bandswitch byte */ - simple_radio_bandswitch(fe, &buffer[0]); - buffer[2] = (t_params->ranges[0].config & ~TUNER_RATIO_MASK) | TUNER_RATIO_SELECT_50; /* 50 kHz step */ + /* Bandswitch byte */ + simple_radio_bandswitch(fe, &buffer[0]); + /* Convert from 1/16 kHz V4L steps to 1/20 MHz (=50 kHz) PLL steps freq * (1 Mhz / 16000 V4L steps) * (20 PLL steps / 1 MHz) = freq * (1/800) */ diff --git a/drivers/media/common/tuners/tuner-types.c b/drivers/media/common/tuners/tuner-types.c index 7c0bc064c008..6a7f1a417c27 100644 --- a/drivers/media/common/tuners/tuner-types.c +++ b/drivers/media/common/tuners/tuner-types.c @@ -578,6 +578,31 @@ static struct tuner_params tuner_fm1216me_mk3_params[] = { }, }; +/* ------------ TUNER_PHILIPS_FM1216MK5 - Philips PAL ------------ */ + +static struct tuner_range tuner_fm1216mk5_pal_ranges[] = { + { 16 * 158.00 /*MHz*/, 0xce, 0x01, }, + { 16 * 441.00 /*MHz*/, 0xce, 0x02, }, + { 16 * 864.00 , 0xce, 0x04, }, +}; + +static struct tuner_params tuner_fm1216mk5_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_fm1216mk5_pal_ranges, + .count = ARRAY_SIZE(tuner_fm1216mk5_pal_ranges), + .cb_first_if_lower_freq = 1, + .has_tda9887 = 1, + .port1_active = 1, + .port2_active = 1, + .port2_invert_for_secam_lc = 1, + .port1_fm_high_sensitivity = 1, + .default_top_mid = -2, + .default_top_secam_mid = -2, + .default_top_secam_high = -2, + }, +}; + /* ------------ TUNER_LG_NTSC_NEW_TAPC - LGINNOTEK NTSC ------------ */ static struct tuner_params tuner_lg_ntsc_new_tapc_params[] = { @@ -1254,6 +1279,28 @@ static struct tuner_params tuner_tcl_mf02gip_5n_params[] = { }, }; +/* 80-89 */ +/* --------- TUNER_PHILIPS_FQ1216LME_MK3 -- active loopthrough, no FM ------- */ + +static struct tuner_params tuner_fq1216lme_mk3_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_fm1216me_mk3_pal_ranges, + .count = ARRAY_SIZE(tuner_fm1216me_mk3_pal_ranges), + .cb_first_if_lower_freq = 1, /* not specified, but safe to do */ + .has_tda9887 = 1, /* TDA9886 */ + .port1_active = 1, + .port2_active = 1, + .port2_invert_for_secam_lc = 1, + .default_top_low = 4, + .default_top_mid = 4, + .default_top_high = 4, + .default_top_secam_low = 4, + .default_top_secam_mid = 4, + .default_top_secam_high = 4, + }, +}; + /* --------------------------------------------------------------------- */ struct tunertype tuners[] = { @@ -1694,6 +1741,18 @@ struct tunertype tuners[] = { .initdata = tua603x_agc112, .sleepdata = (u8[]){ 4, 0x9c, 0x60, 0x85, 0x54 }, }, + [TUNER_PHILIPS_FM1216MK5] = { /* Philips PAL */ + .name = "Philips PAL/SECAM multi (FM1216 MK5)", + .params = tuner_fm1216mk5_params, + .count = ARRAY_SIZE(tuner_fm1216mk5_params), + }, + + /* 80-89 */ + [TUNER_PHILIPS_FQ1216LME_MK3] = { /* PAL/SECAM, Loop-thru, no FM */ + .name = "Philips FQ1216LME MK3 PAL/SECAM w/active loopthrough", + .params = tuner_fq1216lme_mk3_params, + .count = ARRAY_SIZE(tuner_fq1216lme_mk3_params), + }, }; EXPORT_SYMBOL(tuners); diff --git a/drivers/media/common/tuners/tuner-xc2028.c b/drivers/media/common/tuners/tuner-xc2028.c index 1adce9ff52ce..b6da9c3873fe 100644 --- a/drivers/media/common/tuners/tuner-xc2028.c +++ b/drivers/media/common/tuners/tuner-xc2028.c @@ -30,7 +30,7 @@ MODULE_PARM_DESC(debug, "enable verbose debug messages"); static int no_poweroff; module_param(no_poweroff, int, 0644); -MODULE_PARM_DESC(debug, "0 (default) powers device off when not used.\n" +MODULE_PARM_DESC(no_poweroff, "0 (default) powers device off when not used.\n" "1 keep device energized and with tuner ready all the times.\n" " Faster, but consumes more power and keeps the device hotter\n"); @@ -48,7 +48,7 @@ MODULE_PARM_DESC(audio_std, "NICAM/A\n" "NICAM/B\n"); -static char firmware_name[FIRMWARE_NAME_MAX]; +static char firmware_name[30]; module_param_string(firmware_name, firmware_name, sizeof(firmware_name), 0); MODULE_PARM_DESC(firmware_name, "Firmware file name. Allows overriding the " "default firmware name\n"); @@ -272,7 +272,7 @@ static int load_all_firmwares(struct dvb_frontend *fe) fname = firmware_name; tuner_dbg("Reading firmware %s\n", fname); - rc = request_firmware(&fw, fname, &priv->i2c_props.adap->dev); + rc = request_firmware(&fw, fname, priv->i2c_props.adap->dev.parent); if (rc < 0) { if (rc == -ENOENT) tuner_err("Error: firmware %s not found.\n", @@ -917,22 +917,29 @@ static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */, * that xc2028 will be in a safe state. * Maybe this might also be needed for DTV. */ - if (new_mode == T_ANALOG_TV) { + if (new_mode == T_ANALOG_TV) rc = send_seq(priv, {0x00, 0x00}); - } else if (priv->cur_fw.type & ATSC) { - offset = 1750000; - } else { - offset = 2750000; + + /* + * Digital modes require an offset to adjust to the + * proper frequency. + * Analog modes require offset = 0 + */ + if (new_mode == T_DIGITAL_TV) { + /* Sets the offset according with firmware */ + if (priv->cur_fw.type & DTV6) + offset = 1750000; + else if (priv->cur_fw.type & DTV7) + offset = 2250000; + else /* DTV8 or DTV78 */ + offset = 2750000; + /* - * We must adjust the offset by 500kHz in two cases in order - * to correctly center the IF output: - * 1) When the ZARLINK456 or DIBCOM52 tables were explicitly - * selected and a 7MHz channel is tuned; - * 2) When tuning a VHF channel with DTV78 firmware. + * We must adjust the offset by 500kHz when + * tuning a 7MHz VHF channel with DTV78 firmware + * (used in Australia, Italy and Germany) */ - if (((priv->cur_fw.type & DTV7) && - (priv->cur_fw.scode_table & (ZARLINK456 | DIBCOM52))) || - ((priv->cur_fw.type & DTV78) && freq < 470000000)) + if ((priv->cur_fw.type & DTV78) && freq < 470000000) offset -= 500000; } @@ -991,7 +998,7 @@ static int xc2028_set_analog_freq(struct dvb_frontend *fe, if (priv->ctrl.input1) type |= INPUT1; return generic_set_freq(fe, (625l * p->frequency) / 10, - T_ANALOG_TV, type, 0, 0); + T_RADIO, type, 0, 0); } /* if std is not defined, choose one */ @@ -1022,21 +1029,20 @@ static int xc2028_set_params(struct dvb_frontend *fe, switch(fe->ops.info.type) { case FE_OFDM: bw = p->u.ofdm.bandwidth; - break; - case FE_QAM: - tuner_info("WARN: There are some reports that " - "QAM 6 MHz doesn't work.\n" - "If this works for you, please report by " - "e-mail to: v4l-dvb-maintainer@linuxtv.org\n"); - bw = BANDWIDTH_6_MHZ; - type |= QAM; + /* + * The only countries with 6MHz seem to be Taiwan/Uruguay. + * Both seem to require QAM firmware for OFDM decoding + * Tested in Taiwan by Terry Wu + */ + if (bw == BANDWIDTH_6_MHZ) + type |= QAM; break; case FE_ATSC: bw = BANDWIDTH_6_MHZ; /* The only ATSC firmware (at least on v2.7) is D2633 */ type |= ATSC | D2633; break; - /* DVB-S is not supported */ + /* DVB-S and pure QAM (FE_QAM) are not supported */ default: return -EINVAL; } diff --git a/drivers/media/common/tuners/xc5000.c b/drivers/media/common/tuners/xc5000.c index b54598550dc4..f4ffcdc9b848 100644 --- a/drivers/media/common/tuners/xc5000.c +++ b/drivers/media/common/tuners/xc5000.c @@ -3,6 +3,7 @@ * * Copyright (c) 2007 Xceive Corporation * Copyright (c) 2007 Steven Toth + * Copyright (c) 2009 Devin Heitmueller * * 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 @@ -36,14 +37,20 @@ static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); +static int no_poweroff; +module_param(no_poweroff, int, 0644); +MODULE_PARM_DESC(no_poweroff, "0 (default) powers device off when not used.\n" + "\t\t1 keep device energized and with tuner ready all the times.\n" + "\t\tFaster, but consumes more power and keeps the device hotter"); + static DEFINE_MUTEX(xc5000_list_mutex); static LIST_HEAD(hybrid_tuner_instance_list); #define dprintk(level, fmt, arg...) if (debug >= level) \ printk(KERN_INFO "%s: " fmt, "xc5000", ## arg) -#define XC5000_DEFAULT_FIRMWARE "dvb-fe-xc5000-1.1.fw" -#define XC5000_DEFAULT_FIRMWARE_SIZE 12332 +#define XC5000_DEFAULT_FIRMWARE "dvb-fe-xc5000-1.6.114.fw" +#define XC5000_DEFAULT_FIRMWARE_SIZE 12401 struct xc5000_priv { struct tuner_i2c_props i2c_props; @@ -83,11 +90,11 @@ struct xc5000_priv { #define XREG_D_CODE 0x04 #define XREG_IF_OUT 0x05 #define XREG_SEEK_MODE 0x07 -#define XREG_POWER_DOWN 0x0A +#define XREG_POWER_DOWN 0x0A /* Obsolete */ #define XREG_SIGNALSOURCE 0x0D /* 0=Air, 1=Cable */ #define XREG_SMOOTHEDCVBS 0x0E #define XREG_XTALFREQ 0x0F -#define XREG_FINERFFREQ 0x10 +#define XREG_FINERFREQ 0x10 #define XREG_DDIMODE 0x11 #define XREG_ADC_ENV 0x00 @@ -100,6 +107,7 @@ struct xc5000_priv { #define XREG_VERSION 0x07 #define XREG_PRODUCT_ID 0x08 #define XREG_BUSY 0x09 +#define XREG_BUILD 0x0D /* Basic firmware description. This will remain with @@ -191,27 +199,36 @@ static struct XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = { {"FM Radio-INPUT1", 0x0208, 0x9002} }; -static int xc5000_is_firmware_loaded(struct dvb_frontend *fe); -static int xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len); -static int xc5000_readregs(struct xc5000_priv *priv, u8 *buf, u8 len); -static void xc5000_TunerReset(struct dvb_frontend *fe); +static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe); +static int xc5000_is_firmware_loaded(struct dvb_frontend *fe); +static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val); +static int xc5000_TunerReset(struct dvb_frontend *fe); static int xc_send_i2c_data(struct xc5000_priv *priv, u8 *buf, int len) { - return xc5000_writeregs(priv, buf, len) - ? XC_RESULT_I2C_WRITE_FAILURE : XC_RESULT_SUCCESS; + struct i2c_msg msg = { .addr = priv->i2c_props.addr, + .flags = 0, .buf = buf, .len = len }; + + if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) { + printk(KERN_ERR "xc5000: I2C write failed (len=%i)\n", len); + return XC_RESULT_I2C_WRITE_FAILURE; + } + return XC_RESULT_SUCCESS; } +/* This routine is never used because the only time we read data from the + i2c bus is when we read registers, and we want that to be an atomic i2c + transaction in case we are on a multi-master bus */ static int xc_read_i2c_data(struct xc5000_priv *priv, u8 *buf, int len) { - return xc5000_readregs(priv, buf, len) - ? XC_RESULT_I2C_READ_FAILURE : XC_RESULT_SUCCESS; -} + struct i2c_msg msg = { .addr = priv->i2c_props.addr, + .flags = I2C_M_RD, .buf = buf, .len = len }; -static int xc_reset(struct dvb_frontend *fe) -{ - xc5000_TunerReset(fe); - return XC_RESULT_SUCCESS; + if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) { + printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n", len); + return -EREMOTEIO; + } + return 0; } static void xc_wait(int wait_ms) @@ -219,7 +236,7 @@ static void xc_wait(int wait_ms) msleep(wait_ms); } -static void xc5000_TunerReset(struct dvb_frontend *fe) +static int xc5000_TunerReset(struct dvb_frontend *fe) { struct xc5000_priv *priv = fe->tuner_priv; int ret; @@ -232,16 +249,21 @@ static void xc5000_TunerReset(struct dvb_frontend *fe) priv->i2c_props.adap->algo_data, DVB_FRONTEND_COMPONENT_TUNER, XC5000_TUNER_RESET, 0); - if (ret) + if (ret) { printk(KERN_ERR "xc5000: reset failed\n"); - } else + return XC_RESULT_RESET_FAILURE; + } + } else { printk(KERN_ERR "xc5000: no tuner reset callback function, fatal\n"); + return XC_RESULT_RESET_FAILURE; + } + return XC_RESULT_SUCCESS; } static int xc_write_reg(struct xc5000_priv *priv, u16 regAddr, u16 i2cData) { u8 buf[4]; - int WatchDogTimer = 5; + int WatchDogTimer = 100; int result; buf[0] = (regAddr >> 8) & 0xFF; @@ -263,7 +285,7 @@ static int xc_write_reg(struct xc5000_priv *priv, u16 regAddr, u16 i2cData) /* busy flag cleared */ break; } else { - xc_wait(100); /* wait 5 ms */ + xc_wait(5); /* wait 5 ms */ WatchDogTimer--; } } @@ -276,25 +298,6 @@ static int xc_write_reg(struct xc5000_priv *priv, u16 regAddr, u16 i2cData) return result; } -static int xc_read_reg(struct xc5000_priv *priv, u16 regAddr, u16 *i2cData) -{ - u8 buf[2]; - int result; - - buf[0] = (regAddr >> 8) & 0xFF; - buf[1] = regAddr & 0xFF; - result = xc_send_i2c_data(priv, buf, 2); - if (result != XC_RESULT_SUCCESS) - return result; - - result = xc_read_i2c_data(priv, buf, 2); - if (result != XC_RESULT_SUCCESS) - return result; - - *i2cData = buf[0] * 256 + buf[1]; - return result; -} - static int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence) { struct xc5000_priv *priv = fe->tuner_priv; @@ -309,7 +312,7 @@ static int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence) len = i2c_sequence[index] * 256 + i2c_sequence[index+1]; if (len == 0x0000) { /* RESET command */ - result = xc_reset(fe); + result = xc5000_TunerReset(fe); index += 2; if (result != XC_RESULT_SUCCESS) return result; @@ -371,15 +374,6 @@ static int xc_SetTVStandard(struct xc5000_priv *priv, return ret; } -static int xc_shutdown(struct xc5000_priv *priv) -{ - return XC_RESULT_SUCCESS; - /* Fixme: cannot bring tuner back alive once shutdown - * without reloading the driver modules. - * return xc_write_reg(priv, XREG_POWER_DOWN, 0); - */ -} - static int xc_SetSignalSource(struct xc5000_priv *priv, u16 rf_mode) { dprintk(1, "%s(%d) Source = %s\n", __func__, rf_mode, @@ -408,7 +402,10 @@ static int xc_set_RF_frequency(struct xc5000_priv *priv, u32 freq_hz) freq_code = (u16)(freq_hz / 15625); - return xc_write_reg(priv, XREG_RF_FREQ, freq_code); + /* Starting in firmware version 1.1.44, Xceive recommends using the + FINERFREQ for all normal tuning (the doc indicates reg 0x03 should + only be used for fast scanning for channel lock) */ + return xc_write_reg(priv, XREG_FINERFREQ, freq_code); } @@ -424,7 +421,7 @@ static int xc_set_IF_frequency(struct xc5000_priv *priv, u32 freq_khz) static int xc_get_ADC_Envelope(struct xc5000_priv *priv, u16 *adc_envelope) { - return xc_read_reg(priv, XREG_ADC_ENV, adc_envelope); + return xc5000_readreg(priv, XREG_ADC_ENV, adc_envelope); } static int xc_get_frequency_error(struct xc5000_priv *priv, u32 *freq_error_hz) @@ -433,8 +430,8 @@ static int xc_get_frequency_error(struct xc5000_priv *priv, u32 *freq_error_hz) u16 regData; u32 tmp; - result = xc_read_reg(priv, XREG_FREQ_ERROR, ®Data); - if (result) + result = xc5000_readreg(priv, XREG_FREQ_ERROR, ®Data); + if (result != XC_RESULT_SUCCESS) return result; tmp = (u32)regData; @@ -444,7 +441,7 @@ static int xc_get_frequency_error(struct xc5000_priv *priv, u32 *freq_error_hz) static int xc_get_lock_status(struct xc5000_priv *priv, u16 *lock_status) { - return xc_read_reg(priv, XREG_LOCK, lock_status); + return xc5000_readreg(priv, XREG_LOCK, lock_status); } static int xc_get_version(struct xc5000_priv *priv, @@ -454,8 +451,8 @@ static int xc_get_version(struct xc5000_priv *priv, u16 data; int result; - result = xc_read_reg(priv, XREG_VERSION, &data); - if (result) + result = xc5000_readreg(priv, XREG_VERSION, &data); + if (result != XC_RESULT_SUCCESS) return result; (*hw_majorversion) = (data >> 12) & 0x0F; @@ -466,13 +463,18 @@ static int xc_get_version(struct xc5000_priv *priv, return 0; } +static int xc_get_buildversion(struct xc5000_priv *priv, u16 *buildrev) +{ + return xc5000_readreg(priv, XREG_BUILD, buildrev); +} + static int xc_get_hsync_freq(struct xc5000_priv *priv, u32 *hsync_freq_hz) { u16 regData; int result; - result = xc_read_reg(priv, XREG_HSYNC_FREQ, ®Data); - if (result) + result = xc5000_readreg(priv, XREG_HSYNC_FREQ, ®Data); + if (result != XC_RESULT_SUCCESS) return result; (*hsync_freq_hz) = ((regData & 0x0fff) * 763)/100; @@ -481,12 +483,12 @@ static int xc_get_hsync_freq(struct xc5000_priv *priv, u32 *hsync_freq_hz) static int xc_get_frame_lines(struct xc5000_priv *priv, u16 *frame_lines) { - return xc_read_reg(priv, XREG_FRAME_LINES, frame_lines); + return xc5000_readreg(priv, XREG_FRAME_LINES, frame_lines); } static int xc_get_quality(struct xc5000_priv *priv, u16 *quality) { - return xc_read_reg(priv, XREG_QUALITY, quality); + return xc5000_readreg(priv, XREG_QUALITY, quality); } static u16 WaitForLock(struct xc5000_priv *priv) @@ -504,7 +506,9 @@ static u16 WaitForLock(struct xc5000_priv *priv) return lockState; } -static int xc_tune_channel(struct xc5000_priv *priv, u32 freq_hz) +#define XC_TUNE_ANALOG 0 +#define XC_TUNE_DIGITAL 1 +static int xc_tune_channel(struct xc5000_priv *priv, u32 freq_hz, int mode) { int found = 0; @@ -513,8 +517,10 @@ static int xc_tune_channel(struct xc5000_priv *priv, u32 freq_hz) if (xc_set_RF_frequency(priv, freq_hz) != XC_RESULT_SUCCESS) return 0; - if (WaitForLock(priv) == 1) - found = 1; + if (mode == XC_TUNE_ANALOG) { + if (WaitForLock(priv) == 1) + found = 1; + } return found; } @@ -536,32 +542,7 @@ static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val) } *val = (bval[0] << 8) | bval[1]; - return 0; -} - -static int xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len) -{ - struct i2c_msg msg = { .addr = priv->i2c_props.addr, - .flags = 0, .buf = buf, .len = len }; - - if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) { - printk(KERN_ERR "xc5000: I2C write failed (len=%i)\n", - (int)len); - return -EREMOTEIO; - } - return 0; -} - -static int xc5000_readregs(struct xc5000_priv *priv, u8 *buf, u8 len) -{ - struct i2c_msg msg = { .addr = priv->i2c_props.addr, - .flags = I2C_M_RD, .buf = buf, .len = len }; - - if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) { - printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n", (int)len); - return -EREMOTEIO; - } - return 0; + return XC_RESULT_SUCCESS; } static int xc5000_fwupload(struct dvb_frontend *fe) @@ -575,13 +556,13 @@ static int xc5000_fwupload(struct dvb_frontend *fe) XC5000_DEFAULT_FIRMWARE); ret = request_firmware(&fw, XC5000_DEFAULT_FIRMWARE, - &priv->i2c_props.adap->dev); + priv->i2c_props.adap->dev.parent); if (ret) { printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n"); ret = XC_RESULT_RESET_FAILURE; goto out; } else { - printk(KERN_INFO "xc5000: firmware read %Zu bytes.\n", + printk(KERN_DEBUG "xc5000: firmware read %Zu bytes.\n", fw->size); ret = XC_RESULT_SUCCESS; } @@ -590,8 +571,9 @@ static int xc5000_fwupload(struct dvb_frontend *fe) printk(KERN_ERR "xc5000: firmware incorrect size\n"); ret = XC_RESULT_RESET_FAILURE; } else { - printk(KERN_INFO "xc5000: firmware upload\n"); + printk(KERN_INFO "xc5000: firmware uploading...\n"); ret = xc_load_i2c_sequence(fe, fw->data); + printk(KERN_INFO "xc5000: firmware upload complete...\n"); } out: @@ -609,6 +591,7 @@ static void xc_debug_dump(struct xc5000_priv *priv) u16 quality; u8 hw_majorversion = 0, hw_minorversion = 0; u8 fw_majorversion = 0, fw_minorversion = 0; + u16 fw_buildversion = 0; /* Wait for stats to stabilize. * Frame Lines needs two frame times after initial lock @@ -628,9 +611,10 @@ static void xc_debug_dump(struct xc5000_priv *priv) xc_get_version(priv, &hw_majorversion, &hw_minorversion, &fw_majorversion, &fw_minorversion); - dprintk(1, "*** HW: V%02x.%02x, FW: V%02x.%02x\n", + xc_get_buildversion(priv, &fw_buildversion); + dprintk(1, "*** HW: V%02x.%02x, FW: V%02x.%02x.%04x\n", hw_majorversion, hw_minorversion, - fw_majorversion, fw_minorversion); + fw_majorversion, fw_minorversion, fw_buildversion); xc_get_hsync_freq(priv, &hsync_freq_hz); dprintk(1, "*** Horizontal sync frequency = %d Hz\n", hsync_freq_hz); @@ -648,27 +632,57 @@ static int xc5000_set_params(struct dvb_frontend *fe, struct xc5000_priv *priv = fe->tuner_priv; int ret; + if (xc5000_is_firmware_loaded(fe) != XC_RESULT_SUCCESS) + xc_load_fw_and_init_tuner(fe); + dprintk(1, "%s() frequency=%d (Hz)\n", __func__, params->frequency); - switch (params->u.vsb.modulation) { - case VSB_8: - case VSB_16: - dprintk(1, "%s() VSB modulation\n", __func__); + if (fe->ops.info.type == FE_ATSC) { + dprintk(1, "%s() ATSC\n", __func__); + switch (params->u.vsb.modulation) { + case VSB_8: + case VSB_16: + dprintk(1, "%s() VSB modulation\n", __func__); + priv->rf_mode = XC_RF_MODE_AIR; + priv->freq_hz = params->frequency - 1750000; + priv->bandwidth = BANDWIDTH_6_MHZ; + priv->video_standard = DTV6; + break; + case QAM_64: + case QAM_256: + case QAM_AUTO: + dprintk(1, "%s() QAM modulation\n", __func__); + priv->rf_mode = XC_RF_MODE_CABLE; + priv->freq_hz = params->frequency - 1750000; + priv->bandwidth = BANDWIDTH_6_MHZ; + priv->video_standard = DTV6; + break; + default: + return -EINVAL; + } + } else if (fe->ops.info.type == FE_OFDM) { + dprintk(1, "%s() OFDM\n", __func__); + switch (params->u.ofdm.bandwidth) { + case BANDWIDTH_6_MHZ: + priv->bandwidth = BANDWIDTH_6_MHZ; + priv->video_standard = DTV6; + priv->freq_hz = params->frequency - 1750000; + break; + case BANDWIDTH_7_MHZ: + printk(KERN_ERR "xc5000 bandwidth 7MHz not supported\n"); + return -EINVAL; + case BANDWIDTH_8_MHZ: + priv->bandwidth = BANDWIDTH_8_MHZ; + priv->video_standard = DTV8; + priv->freq_hz = params->frequency - 2750000; + break; + default: + printk(KERN_ERR "xc5000 bandwidth not set!\n"); + return -EINVAL; + } priv->rf_mode = XC_RF_MODE_AIR; - priv->freq_hz = params->frequency - 1750000; - priv->bandwidth = BANDWIDTH_6_MHZ; - priv->video_standard = DTV6; - break; - case QAM_64: - case QAM_256: - case QAM_AUTO: - dprintk(1, "%s() QAM modulation\n", __func__); - priv->rf_mode = XC_RF_MODE_CABLE; - priv->freq_hz = params->frequency - 1750000; - priv->bandwidth = BANDWIDTH_6_MHZ; - priv->video_standard = DTV6; - break; - default: + } else { + printk(KERN_ERR "xc5000 modulation type not supported!\n"); return -EINVAL; } @@ -698,7 +712,7 @@ static int xc5000_set_params(struct dvb_frontend *fe, return -EIO; } - xc_tune_channel(priv, priv->freq_hz); + xc_tune_channel(priv, priv->freq_hz, XC_TUNE_DIGITAL); if (debug) xc_debug_dump(priv); @@ -725,8 +739,6 @@ static int xc5000_is_firmware_loaded(struct dvb_frontend *fe) return ret; } -static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe); - static int xc5000_set_analog_params(struct dvb_frontend *fe, struct analog_parameters *params) { @@ -807,7 +819,7 @@ tune_channel: return -EREMOTEIO; } - xc_tune_channel(priv, priv->freq_hz); + xc_tune_channel(priv, priv->freq_hz, XC_TUNE_ANALOG); if (debug) xc_debug_dump(priv); @@ -875,18 +887,18 @@ static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe) static int xc5000_sleep(struct dvb_frontend *fe) { - struct xc5000_priv *priv = fe->tuner_priv; int ret; dprintk(1, "%s()\n", __func__); - /* On Pinnacle PCTV HD 800i, the tuner cannot be reinitialized - * once shutdown without reloading the driver. Maybe I am not - * doing something right. - * - */ + /* Avoid firmware reload on slow devices */ + if (no_poweroff) + return 0; - ret = xc_shutdown(priv); + /* According to Xceive technical support, the "powerdown" register + was removed in newer versions of the firmware. The "supported" + way to sleep the tuner is to pull the reset pin low for 10ms */ + ret = xc5000_TunerReset(fe); if (ret != XC_RESULT_SUCCESS) { printk(KERN_ERR "xc5000: %s() unable to shutdown tuner\n", @@ -991,7 +1003,7 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe, /* Check if firmware has been loaded. It is possible that another instance of the driver has loaded the firmware. */ - if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != 0) + if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != XC_RESULT_SUCCESS) goto fail; switch (id) { diff --git a/drivers/media/dvb/b2c2/flexcop-common.h b/drivers/media/dvb/b2c2/flexcop-common.h index 3e1c472092ab..9e2148a19967 100644 --- a/drivers/media/dvb/b2c2/flexcop-common.h +++ b/drivers/media/dvb/b2c2/flexcop-common.h @@ -1,9 +1,7 @@ /* - * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III - * - * flexcop-common.h - common header file for device-specific source files also. - * - * see flexcop.c for copyright information. + * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III + * flexcop-common.h - common header file for device-specific source files + * see flexcop.c for copyright information */ #ifndef __FLEXCOP_COMMON_H__ #define __FLEXCOP_COMMON_H__ diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c index f7afab5944cf..efb4a6c2b57a 100644 --- a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c +++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c @@ -1,34 +1,27 @@ /* - * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III - * - * flexcop-fe-tuner.c - methods for attaching a frontend and controlling DiSEqC. - * - * see flexcop.c for copyright information. + * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III + * flexcop-fe-tuner.c - methods for frontend attachment and DiSEqC controlling + * see flexcop.c for copyright information */ #include - #include "flexcop.h" - -#include "stv0299.h" -#include "mt352.h" -#include "nxt200x.h" -#include "bcm3510.h" -#include "stv0297.h" #include "mt312.h" -#include "lgdt330x.h" -#include "dvb-pll.h" -#include "tuner-simple.h" - +#include "stv0299.h" #include "s5h1420.h" #include "itd1000.h" - -#include "cx24123.h" #include "cx24113.h" - +#include "cx24123.h" #include "isl6421.h" +#include "mt352.h" +#include "bcm3510.h" +#include "nxt200x.h" +#include "dvb-pll.h" +#include "lgdt330x.h" +#include "tuner-simple.h" +#include "stv0297.h" /* lnb control */ - +#if defined(CONFIG_DVB_MT312_MODULE) || defined(CONFIG_DVB_STV0299_MODULE) static int flexcop_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) { struct flexcop_device *fc = fe->dvb->priv; @@ -37,65 +30,62 @@ static int flexcop_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage v = fc->read_ibi_reg(fc, misc_204); switch (voltage) { - case SEC_VOLTAGE_OFF: - v.misc_204.ACPI1_sig = 1; - break; - case SEC_VOLTAGE_13: - v.misc_204.ACPI1_sig = 0; - v.misc_204.LNB_L_H_sig = 0; - break; - case SEC_VOLTAGE_18: - v.misc_204.ACPI1_sig = 0; - v.misc_204.LNB_L_H_sig = 1; - break; - default: - err("unknown SEC_VOLTAGE value"); - return -EINVAL; + case SEC_VOLTAGE_OFF: + v.misc_204.ACPI1_sig = 1; + break; + case SEC_VOLTAGE_13: + v.misc_204.ACPI1_sig = 0; + v.misc_204.LNB_L_H_sig = 0; + break; + case SEC_VOLTAGE_18: + v.misc_204.ACPI1_sig = 0; + v.misc_204.LNB_L_H_sig = 1; + break; + default: + err("unknown SEC_VOLTAGE value"); + return -EINVAL; } return fc->write_ibi_reg(fc, misc_204, v); } +#endif +#if defined(CONFIG_DVB_S5H1420_MODULE) || defined(CONFIG_DVB_STV0299_MODULE) \ + || defined(CONFIG_DVB_MT312_MODULE) static int flexcop_sleep(struct dvb_frontend* fe) { struct flexcop_device *fc = fe->dvb->priv; -/* flexcop_ibi_value v = fc->read_ibi_reg(fc,misc_204); */ - if (fc->fe_sleep) return fc->fe_sleep(fe); - -/* v.misc_204.ACPI3_sig = 1; - fc->write_ibi_reg(fc,misc_204,v);*/ - return 0; } +#endif +/* SkyStar2 DVB-S rev 2.3 */ +#if defined(CONFIG_DVB_MT312_MODULE) static int flexcop_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) { - /* u16 wz_half_period_for_45_mhz[] = { 0x01ff, 0x0154, 0x00ff, 0x00cc }; */ +/* u16 wz_half_period_for_45_mhz[] = { 0x01ff, 0x0154, 0x00ff, 0x00cc }; */ struct flexcop_device *fc = fe->dvb->priv; flexcop_ibi_value v; u16 ax; v.raw = 0; - deb_tuner("tone = %u\n",tone); switch (tone) { - case SEC_TONE_ON: - ax = 0x01ff; - break; - case SEC_TONE_OFF: - ax = 0; - break; - default: - err("unknown SEC_TONE value"); - return -EINVAL; + case SEC_TONE_ON: + ax = 0x01ff; + break; + case SEC_TONE_OFF: + ax = 0; + break; + default: + err("unknown SEC_TONE value"); + return -EINVAL; } v.lnb_switch_freq_200.LNB_CTLPrescaler_sig = 1; /* divide by 2 */ - v.lnb_switch_freq_200.LNB_CTLHighCount_sig = ax; v.lnb_switch_freq_200.LNB_CTLLowCount_sig = ax == 0 ? 0x1ff : ax; - return fc->write_ibi_reg(fc,lnb_switch_freq_200,v); } @@ -110,17 +100,16 @@ static void flexcop_diseqc_send_bit(struct dvb_frontend* fe, int data) static void flexcop_diseqc_send_byte(struct dvb_frontend* fe, int data) { int i, par = 1, d; - for (i = 7; i >= 0; i--) { d = (data >> i) & 1; par ^= d; flexcop_diseqc_send_bit(fe, d); } - flexcop_diseqc_send_bit(fe, par); } -static int flexcop_send_diseqc_msg(struct dvb_frontend* fe, int len, u8 *msg, unsigned long burst) +static int flexcop_send_diseqc_msg(struct dvb_frontend *fe, + int len, u8 *msg, unsigned long burst) { int i; @@ -129,7 +118,6 @@ static int flexcop_send_diseqc_msg(struct dvb_frontend* fe, int len, u8 *msg, un for (i = 0; i < len; i++) flexcop_diseqc_send_byte(fe,msg[i]); - mdelay(16); if (burst != -1) { @@ -146,197 +134,30 @@ static int flexcop_send_diseqc_msg(struct dvb_frontend* fe, int len, u8 *msg, un return 0; } -static int flexcop_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd) +static int flexcop_diseqc_send_master_cmd(struct dvb_frontend *fe, + struct dvb_diseqc_master_cmd *cmd) { return flexcop_send_diseqc_msg(fe, cmd->msg_len, cmd->msg, 0); } -static int flexcop_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd) +static int flexcop_diseqc_send_burst(struct dvb_frontend *fe, + fe_sec_mini_cmd_t minicmd) { return flexcop_send_diseqc_msg(fe, 0, NULL, minicmd); } -/* dvb-s stv0299 */ -static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio) -{ - u8 aclk = 0; - u8 bclk = 0; +static struct mt312_config skystar23_samsung_tbdu18132_config = { + .demod_address = 0x0e, +}; - if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; } - else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; } - else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; } - else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; } - else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; } - else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; } - - stv0299_writereg (fe, 0x13, aclk); - stv0299_writereg (fe, 0x14, bclk); - stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff); - stv0299_writereg (fe, 0x20, (ratio >> 8) & 0xff); - stv0299_writereg (fe, 0x21, (ratio ) & 0xf0); - - return 0; -} - -static int samsung_tbmu24112_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params) +static int skystar23_samsung_tbdu18132_tuner_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) { u8 buf[4]; u32 div; - struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, + .len = sizeof(buf) }; struct flexcop_device *fc = fe->dvb->priv; - - div = params->frequency / 125; - - buf[0] = (div >> 8) & 0x7f; - buf[1] = div & 0xff; - buf[2] = 0x84; /* 0xC4 */ - buf[3] = 0x08; - - if (params->frequency < 1500000) - buf[3] |= 0x10; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&fc->fc_i2c_adap[0].i2c_adap, &msg, 1) != 1) - return -EIO; - return 0; -} - -static u8 samsung_tbmu24112_inittab[] = { - 0x01, 0x15, - 0x02, 0x30, - 0x03, 0x00, - 0x04, 0x7D, - 0x05, 0x35, - 0x06, 0x02, - 0x07, 0x00, - 0x08, 0xC3, - 0x0C, 0x00, - 0x0D, 0x81, - 0x0E, 0x23, - 0x0F, 0x12, - 0x10, 0x7E, - 0x11, 0x84, - 0x12, 0xB9, - 0x13, 0x88, - 0x14, 0x89, - 0x15, 0xC9, - 0x16, 0x00, - 0x17, 0x5C, - 0x18, 0x00, - 0x19, 0x00, - 0x1A, 0x00, - 0x1C, 0x00, - 0x1D, 0x00, - 0x1E, 0x00, - 0x1F, 0x3A, - 0x20, 0x2E, - 0x21, 0x80, - 0x22, 0xFF, - 0x23, 0xC1, - 0x28, 0x00, - 0x29, 0x1E, - 0x2A, 0x14, - 0x2B, 0x0F, - 0x2C, 0x09, - 0x2D, 0x05, - 0x31, 0x1F, - 0x32, 0x19, - 0x33, 0xFE, - 0x34, 0x93, - 0xff, 0xff, -}; - -static struct stv0299_config samsung_tbmu24112_config = { - .demod_address = 0x68, - .inittab = samsung_tbmu24112_inittab, - .mclk = 88000000UL, - .invert = 0, - .skip_reinit = 0, - .lock_output = STV0299_LOCKOUTPUT_LK, - .volt13_op0_op1 = STV0299_VOLT13_OP1, - .min_delay_ms = 100, - .set_symbol_rate = samsung_tbmu24112_set_symbol_rate, -}; - -/* dvb-t mt352 */ -static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe) -{ - static u8 mt352_clock_config [] = { 0x89, 0x18, 0x2d }; - static u8 mt352_reset [] = { 0x50, 0x80 }; - static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 }; - static u8 mt352_agc_cfg [] = { 0x67, 0x28, 0xa1 }; - static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 }; - - mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config)); - udelay(2000); - mt352_write(fe, mt352_reset, sizeof(mt352_reset)); - mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); - - mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg)); - mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg)); - - return 0; -} - -static int samsung_tdtc9251dh0_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters *params, u8* pllbuf, int buf_len) -{ - u32 div; - unsigned char bs = 0; - - if (buf_len < 5) - return -EINVAL; - - #define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */ - div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; - - if (params->frequency >= 48000000 && params->frequency <= 154000000) bs = 0x09; - if (params->frequency >= 161000000 && params->frequency <= 439000000) bs = 0x0a; - if (params->frequency >= 447000000 && params->frequency <= 863000000) bs = 0x08; - - pllbuf[0] = 0x61; - pllbuf[1] = div >> 8; - pllbuf[2] = div & 0xff; - pllbuf[3] = 0xcc; - pllbuf[4] = bs; - - return 5; -} - -static struct mt352_config samsung_tdtc9251dh0_config = { - .demod_address = 0x0f, - .demod_init = samsung_tdtc9251dh0_demod_init, -}; - -static int flexcop_fe_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name) -{ - struct flexcop_device *fc = fe->dvb->priv; - return request_firmware(fw, name, fc->dev); -} - -static struct lgdt330x_config air2pc_atsc_hd5000_config = { - .demod_address = 0x59, - .demod_chip = LGDT3303, - .serial_mpeg = 0x04, - .clock_polarity_flip = 1, -}; - -static struct nxt200x_config samsung_tbmv_config = { - .demod_address = 0x0a, -}; - -static struct bcm3510_config air2pc_atsc_first_gen_config = { - .demod_address = 0x0f, - .request_firmware = flexcop_fe_request_firmware, -}; - -static int skystar23_samsung_tbdu18132_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params) -{ - u8 buf[4]; - u32 div; - struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; - struct flexcop_device *fc = fe->dvb->priv; - div = (params->frequency + (125/2)) / 125; buf[0] = (div >> 8) & 0x7f; @@ -354,24 +175,405 @@ static int skystar23_samsung_tbdu18132_tuner_set_params(struct dvb_frontend* fe, return 0; } -static struct mt312_config skystar23_samsung_tbdu18132_config = { +static int skystar2_rev23_attach(struct flexcop_device *fc, + struct i2c_adapter *i2c) +{ + fc->fe = dvb_attach(mt312_attach, &skystar23_samsung_tbdu18132_config, i2c); + if (fc->fe != NULL) { + struct dvb_frontend_ops *ops = &fc->fe->ops; + ops->tuner_ops.set_params = + skystar23_samsung_tbdu18132_tuner_set_params; + ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd; + ops->diseqc_send_burst = flexcop_diseqc_send_burst; + ops->set_tone = flexcop_set_tone; + ops->set_voltage = flexcop_set_voltage; + fc->fe_sleep = ops->sleep; + ops->sleep = flexcop_sleep; + return 1; + } + return 0; +} +#endif - .demod_address = 0x0e, +/* SkyStar2 DVB-S rev 2.6 */ +#if defined(CONFIG_DVB_STV0299_MODULE) +static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend *fe, + u32 srate, u32 ratio) +{ + u8 aclk = 0; + u8 bclk = 0; + + if (srate < 1500000) { + aclk = 0xb7; bclk = 0x47; + } else if (srate < 3000000) { + aclk = 0xb7; bclk = 0x4b; + } else if (srate < 7000000) { + aclk = 0xb7; bclk = 0x4f; + } else if (srate < 14000000) { + aclk = 0xb7; bclk = 0x53; + } else if (srate < 30000000) { + aclk = 0xb6; bclk = 0x53; + } else if (srate < 45000000) { + aclk = 0xb4; bclk = 0x51; + } + + stv0299_writereg(fe, 0x13, aclk); + stv0299_writereg(fe, 0x14, bclk); + stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff); + stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff); + stv0299_writereg(fe, 0x21, ratio & 0xf0); + return 0; +} + +static int samsung_tbmu24112_tuner_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + u8 buf[4]; + u32 div; + struct i2c_msg msg = { + .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; + struct flexcop_device *fc = fe->dvb->priv; + div = params->frequency / 125; + + buf[0] = (div >> 8) & 0x7f; + buf[1] = div & 0xff; + buf[2] = 0x84; /* 0xC4 */ + buf[3] = 0x08; + + if (params->frequency < 1500000) + buf[3] |= 0x10; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&fc->fc_i2c_adap[0].i2c_adap, &msg, 1) != 1) + return -EIO; + return 0; +} + +static u8 samsung_tbmu24112_inittab[] = { + 0x01, 0x15, + 0x02, 0x30, + 0x03, 0x00, + 0x04, 0x7D, + 0x05, 0x35, + 0x06, 0x02, + 0x07, 0x00, + 0x08, 0xC3, + 0x0C, 0x00, + 0x0D, 0x81, + 0x0E, 0x23, + 0x0F, 0x12, + 0x10, 0x7E, + 0x11, 0x84, + 0x12, 0xB9, + 0x13, 0x88, + 0x14, 0x89, + 0x15, 0xC9, + 0x16, 0x00, + 0x17, 0x5C, + 0x18, 0x00, + 0x19, 0x00, + 0x1A, 0x00, + 0x1C, 0x00, + 0x1D, 0x00, + 0x1E, 0x00, + 0x1F, 0x3A, + 0x20, 0x2E, + 0x21, 0x80, + 0x22, 0xFF, + 0x23, 0xC1, + 0x28, 0x00, + 0x29, 0x1E, + 0x2A, 0x14, + 0x2B, 0x0F, + 0x2C, 0x09, + 0x2D, 0x05, + 0x31, 0x1F, + 0x32, 0x19, + 0x33, 0xFE, + 0x34, 0x93, + 0xff, 0xff, }; +static struct stv0299_config samsung_tbmu24112_config = { + .demod_address = 0x68, + .inittab = samsung_tbmu24112_inittab, + .mclk = 88000000UL, + .invert = 0, + .skip_reinit = 0, + .lock_output = STV0299_LOCKOUTPUT_LK, + .volt13_op0_op1 = STV0299_VOLT13_OP1, + .min_delay_ms = 100, + .set_symbol_rate = samsung_tbmu24112_set_symbol_rate, +}; + +static int skystar2_rev26_attach(struct flexcop_device *fc, + struct i2c_adapter *i2c) +{ + fc->fe = dvb_attach(stv0299_attach, &samsung_tbmu24112_config, i2c); + if (fc->fe != NULL) { + struct dvb_frontend_ops *ops = &fc->fe->ops; + ops->tuner_ops.set_params = samsung_tbmu24112_tuner_set_params; + ops->set_voltage = flexcop_set_voltage; + fc->fe_sleep = ops->sleep; + ops->sleep = flexcop_sleep; + return 1; + } + return 0; +} +#endif + +/* SkyStar2 DVB-S rev 2.7 */ +#if defined(CONFIG_DVB_S5H1420_MODULE) +static struct s5h1420_config skystar2_rev2_7_s5h1420_config = { + .demod_address = 0x53, + .invert = 1, + .repeated_start_workaround = 1, + .serial_mpeg = 1, +}; + +static struct itd1000_config skystar2_rev2_7_itd1000_config = { + .i2c_address = 0x61, +}; + +static int skystar2_rev27_attach(struct flexcop_device *fc, + struct i2c_adapter *i2c) +{ + flexcop_ibi_value r108; + struct i2c_adapter *i2c_tuner; + + /* enable no_base_addr - no repeated start when reading */ + fc->fc_i2c_adap[0].no_base_addr = 1; + fc->fe = dvb_attach(s5h1420_attach, &skystar2_rev2_7_s5h1420_config, + i2c); + if (!fc->fe) + goto fail; + + i2c_tuner = s5h1420_get_tuner_i2c_adapter(fc->fe); + if (!i2c_tuner) + goto fail; + + fc->fe_sleep = fc->fe->ops.sleep; + fc->fe->ops.sleep = flexcop_sleep; + + /* enable no_base_addr - no repeated start when reading */ + fc->fc_i2c_adap[2].no_base_addr = 1; + if (!dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap, + 0x08, 1, 1)) { + err("ISL6421 could NOT be attached"); + goto fail_isl; + } + info("ISL6421 successfully attached"); + + /* the ITD1000 requires a lower i2c clock - is it a problem ? */ + r108.raw = 0x00000506; + fc->write_ibi_reg(fc, tw_sm_c_108, r108); + if (!dvb_attach(itd1000_attach, fc->fe, i2c_tuner, + &skystar2_rev2_7_itd1000_config)) { + err("ITD1000 could NOT be attached"); + /* Should i2c clock be restored? */ + goto fail_isl; + } + info("ITD1000 successfully attached"); + + return 1; + +fail_isl: + fc->fc_i2c_adap[2].no_base_addr = 0; +fail: + /* for the next devices we need it again */ + fc->fc_i2c_adap[0].no_base_addr = 0; + return 0; +} +#endif + +/* SkyStar2 rev 2.8 */ +#if defined(CONFIG_DVB_CX24123_MODULE) +static struct cx24123_config skystar2_rev2_8_cx24123_config = { + .demod_address = 0x55, + .dont_use_pll = 1, + .agc_callback = cx24113_agc_callback, +}; + +static const struct cx24113_config skystar2_rev2_8_cx24113_config = { + .i2c_addr = 0x54, + .xtal_khz = 10111, +}; + +static int skystar2_rev28_attach(struct flexcop_device *fc, + struct i2c_adapter *i2c) +{ + struct i2c_adapter *i2c_tuner; + + fc->fe = dvb_attach(cx24123_attach, &skystar2_rev2_8_cx24123_config, + i2c); + if (!fc->fe) + return 0; + + i2c_tuner = cx24123_get_tuner_i2c_adapter(fc->fe);; + if (!i2c_tuner) + return 0; + + if (!dvb_attach(cx24113_attach, fc->fe, &skystar2_rev2_8_cx24113_config, + i2c_tuner)) { + err("CX24113 could NOT be attached"); + return 0; + } + info("CX24113 successfully attached"); + + fc->fc_i2c_adap[2].no_base_addr = 1; + if (!dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap, + 0x08, 0, 0)) { + err("ISL6421 could NOT be attached"); + fc->fc_i2c_adap[2].no_base_addr = 0; + return 0; + } + info("ISL6421 successfully attached"); + /* TODO on i2c_adap[1] addr 0x11 (EEPROM) there seems to be an + * IR-receiver (PIC16F818) - but the card has no input for that ??? */ + return 1; +} +#endif + +/* AirStar DVB-T */ +#if defined(CONFIG_DVB_MT352_MODULE) +static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend *fe) +{ + static u8 mt352_clock_config[] = { 0x89, 0x18, 0x2d }; + static u8 mt352_reset[] = { 0x50, 0x80 }; + static u8 mt352_adc_ctl_1_cfg[] = { 0x8E, 0x40 }; + static u8 mt352_agc_cfg[] = { 0x67, 0x28, 0xa1 }; + static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 }; + + mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config)); + udelay(2000); + mt352_write(fe, mt352_reset, sizeof(mt352_reset)); + mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); + mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg)); + mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg)); + return 0; +} + +static int samsung_tdtc9251dh0_calc_regs(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params, u8* pllbuf, int buf_len) +{ + u32 div; + unsigned char bs = 0; + + if (buf_len < 5) + return -EINVAL; + +#define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */ + div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; + if (params->frequency >= 48000000 && params->frequency <= 154000000) \ + bs = 0x09; + if (params->frequency >= 161000000 && params->frequency <= 439000000) \ + bs = 0x0a; + if (params->frequency >= 447000000 && params->frequency <= 863000000) \ + bs = 0x08; + + pllbuf[0] = 0x61; + pllbuf[1] = div >> 8; + pllbuf[2] = div & 0xff; + pllbuf[3] = 0xcc; + pllbuf[4] = bs; + return 5; +} + +static struct mt352_config samsung_tdtc9251dh0_config = { + .demod_address = 0x0f, + .demod_init = samsung_tdtc9251dh0_demod_init, +}; + +static int airstar_dvbt_attach(struct flexcop_device *fc, + struct i2c_adapter *i2c) +{ + fc->fe = dvb_attach(mt352_attach, &samsung_tdtc9251dh0_config, i2c); + if (fc->fe != NULL) { + fc->fe->ops.tuner_ops.calc_regs = samsung_tdtc9251dh0_calc_regs; + return 1; + } + return 0; +} +#endif + +/* AirStar ATSC 1st generation */ +#if defined(CONFIG_DVB_BCM3510_MODULE) +static int flexcop_fe_request_firmware(struct dvb_frontend *fe, + const struct firmware **fw, char* name) +{ + struct flexcop_device *fc = fe->dvb->priv; + return request_firmware(fw, name, fc->dev); +} + +static struct bcm3510_config air2pc_atsc_first_gen_config = { + .demod_address = 0x0f, + .request_firmware = flexcop_fe_request_firmware, +}; + +static int airstar_atsc1_attach(struct flexcop_device *fc, + struct i2c_adapter *i2c) +{ + fc->fe = dvb_attach(bcm3510_attach, &air2pc_atsc_first_gen_config, i2c); + return fc->fe != NULL; +} +#endif + +/* AirStar ATSC 2nd generation */ +#if defined(CONFIG_DVB_NXT200X_MODULE) +static struct nxt200x_config samsung_tbmv_config = { + .demod_address = 0x0a, +}; + +static int airstar_atsc2_attach(struct flexcop_device *fc, + struct i2c_adapter *i2c) +{ + fc->fe = dvb_attach(nxt200x_attach, &samsung_tbmv_config, i2c); + if (!fc->fe) + return 0; + + return !!dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL, + DVB_PLL_SAMSUNG_TBMV); +} +#endif + +/* AirStar ATSC 3rd generation */ +#if defined(CONFIG_DVB_LGDT330X_MODULE) +static struct lgdt330x_config air2pc_atsc_hd5000_config = { + .demod_address = 0x59, + .demod_chip = LGDT3303, + .serial_mpeg = 0x04, + .clock_polarity_flip = 1, +}; + +static int airstar_atsc3_attach(struct flexcop_device *fc, + struct i2c_adapter *i2c) +{ + fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, i2c); + if (!fc->fe) + return 0; + + return !!dvb_attach(simple_tuner_attach, fc->fe, i2c, 0x61, + TUNER_LG_TDVS_H06XF); +} +#endif + +/* CableStar2 DVB-C */ +#if defined(CONFIG_DVB_STV0297_MODULE) static int alps_tdee4_stv0297_tuner_set_params(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fep) + struct dvb_frontend_parameters *fep) { struct flexcop_device *fc = fe->dvb->priv; u8 buf[4]; u16 div; int ret; -/* 62.5 kHz * 10 */ +/* 62.5 kHz * 10 */ #define REF_FREQ 625 #define FREQ_OFFSET 36125 - div = ((fep->frequency/1000 + FREQ_OFFSET ) * 10) / REF_FREQ; // 4 MHz = 4000 KHz + div = ((fep->frequency/1000 + FREQ_OFFSET) * 10) / REF_FREQ; +/* 4 MHz = 4000 KHz */ buf[0] = (u8)( div >> 8) & 0x7f; buf[1] = (u8) div & 0xff; @@ -384,11 +586,11 @@ static int alps_tdee4_stv0297_tuner_set_params(struct dvb_frontend* fe, * AGD = 1, R3 R2 R1 R0 = 0 1 0 1 => byte 4 = 1**10101 = 0x95 */ buf[2] = 0x95; -// Range(MHz) C1 * RE RTS BS4 BS3 BS2 BS1 Byte 5 -// 47 - 153 0 * 0 0 0 0 0 1 0x01 -// 153 - 430 0 * 0 0 0 0 1 0 0x02 -// 430 - 822 0 * 0 0 1 0 0 0 0x08 -// 822 - 862 1 * 0 0 1 0 0 0 0x88 +/* Range(MHz) C1 * RE RTS BS4 BS3 BS2 BS1 Byte 5 + * 47 - 153 0 * 0 0 0 0 0 1 0x01 + * 153 - 430 0 * 0 0 0 0 1 0 0x02 + * 430 - 822 0 * 0 0 1 0 0 0 0x08 + * 822 - 862 1 * 0 0 1 0 0 0 0x88 */ if (fep->frequency <= 153000000) buf[3] = 0x01; else if (fep->frequency <= 430000000) buf[3] = 0x02; @@ -397,11 +599,11 @@ static int alps_tdee4_stv0297_tuner_set_params(struct dvb_frontend* fe, if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); - deb_tuner("tuner buffer for %d Hz: %x %x %x %x\n",fep->frequency, buf[0],buf[1],buf[2],buf[3]); + deb_tuner("tuner buffer for %d Hz: %x %x %x %x\n", fep->frequency, + buf[0], buf[1], buf[2], buf[3]); ret = fc->i2c_request(&fc->fc_i2c_adap[2], - FC_WRITE, 0x61, buf[0], &buf[1], 3); + FC_WRITE, 0x61, buf[0], &buf[1], 3); deb_tuner("tuner write returned: %d\n",ret); - return ret; } @@ -481,182 +683,73 @@ static u8 alps_tdee4_stv0297_inittab[] = { static struct stv0297_config alps_tdee4_stv0297_config = { .demod_address = 0x1c, .inittab = alps_tdee4_stv0297_inittab, -// .invert = 1, -// .pll_set = alps_tdee4_stv0297_pll_set, }; - -/* SkyStar2 rev2.7 (a/u) */ -static struct s5h1420_config skystar2_rev2_7_s5h1420_config = { - .demod_address = 0x53, - .invert = 1, - .repeated_start_workaround = 1, - .serial_mpeg = 1, -}; - -static struct itd1000_config skystar2_rev2_7_itd1000_config = { - .i2c_address = 0x61, -}; - -/* SkyStar2 rev2.8 */ -static struct cx24123_config skystar2_rev2_8_cx24123_config = { - .demod_address = 0x55, - .dont_use_pll = 1, - .agc_callback = cx24113_agc_callback, -}; - -static const struct cx24113_config skystar2_rev2_8_cx24113_config = { - .i2c_addr = 0x54, - .xtal_khz = 10111, -}; - -/* try to figure out the frontend, each card/box can have on of the following list */ -int flexcop_frontend_init(struct flexcop_device *fc) +static int cablestar2_attach(struct flexcop_device *fc, + struct i2c_adapter *i2c) { - struct dvb_frontend_ops *ops; - struct i2c_adapter *i2c = &fc->fc_i2c_adap[0].i2c_adap; - struct i2c_adapter *i2c_tuner; - - /* enable no_base_addr - no repeated start when reading */ - fc->fc_i2c_adap[0].no_base_addr = 1; - fc->fe = dvb_attach(s5h1420_attach, &skystar2_rev2_7_s5h1420_config, i2c); - if (fc->fe != NULL) { - flexcop_ibi_value r108; - i2c_tuner = s5h1420_get_tuner_i2c_adapter(fc->fe); - ops = &fc->fe->ops; - - fc->fe_sleep = ops->sleep; - ops->sleep = flexcop_sleep; - - fc->dev_type = FC_SKY_REV27; - - /* enable no_base_addr - no repeated start when reading */ - fc->fc_i2c_adap[2].no_base_addr = 1; - if (dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap, 0x08, 1, 1) == NULL) - err("ISL6421 could NOT be attached"); - else - info("ISL6421 successfully attached"); - - /* the ITD1000 requires a lower i2c clock - it slows down the stuff for everyone - but is it a problem ? */ - r108.raw = 0x00000506; - fc->write_ibi_reg(fc, tw_sm_c_108, r108); - if (i2c_tuner) { - if (dvb_attach(itd1000_attach, fc->fe, i2c_tuner, &skystar2_rev2_7_itd1000_config) == NULL) - err("ITD1000 could NOT be attached"); - else - info("ITD1000 successfully attached"); - } - goto fe_found; - } - fc->fc_i2c_adap[0].no_base_addr = 0; /* for the next devices we need it again */ - - /* try the sky v2.8 (cx24123, isl6421) */ - fc->fe = dvb_attach(cx24123_attach, - &skystar2_rev2_8_cx24123_config, i2c); - if (fc->fe != NULL) { - i2c_tuner = cx24123_get_tuner_i2c_adapter(fc->fe); - if (i2c_tuner != NULL) { - if (dvb_attach(cx24113_attach, fc->fe, - &skystar2_rev2_8_cx24113_config, - i2c_tuner) == NULL) - err("CX24113 could NOT be attached"); - else - info("CX24113 successfully attached"); - } - - fc->dev_type = FC_SKY_REV28; - - fc->fc_i2c_adap[2].no_base_addr = 1; - if (dvb_attach(isl6421_attach, fc->fe, - &fc->fc_i2c_adap[2].i2c_adap, 0x08, 0, 0) == NULL) - err("ISL6421 could NOT be attached"); - else - info("ISL6421 successfully attached"); - - /* TODO on i2c_adap[1] addr 0x11 (EEPROM) there seems to be an - * IR-receiver (PIC16F818) - but the card has no input for - * that ??? */ - - goto fe_found; - } - - /* try the sky v2.6 (stv0299/Samsung tbmu24112(sl1935)) */ - fc->fe = dvb_attach(stv0299_attach, &samsung_tbmu24112_config, i2c); - if (fc->fe != NULL) { - ops = &fc->fe->ops; - - ops->tuner_ops.set_params = samsung_tbmu24112_tuner_set_params; - - ops->set_voltage = flexcop_set_voltage; - - fc->fe_sleep = ops->sleep; - ops->sleep = flexcop_sleep; - - fc->dev_type = FC_SKY_REV26; - goto fe_found; - } - - /* try the air dvb-t (mt352/Samsung tdtc9251dh0(??)) */ - fc->fe = dvb_attach(mt352_attach, &samsung_tdtc9251dh0_config, i2c); - if (fc->fe != NULL) { - fc->dev_type = FC_AIR_DVBT; - fc->fe->ops.tuner_ops.calc_regs = samsung_tdtc9251dh0_calc_regs; - goto fe_found; - } - - /* try the air atsc 2nd generation (nxt2002) */ - fc->fe = dvb_attach(nxt200x_attach, &samsung_tbmv_config, i2c); - if (fc->fe != NULL) { - fc->dev_type = FC_AIR_ATSC2; - dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL, DVB_PLL_SAMSUNG_TBMV); - goto fe_found; - } - - fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, i2c); - if (fc->fe != NULL) { - fc->dev_type = FC_AIR_ATSC3; - dvb_attach(simple_tuner_attach, fc->fe, i2c, 0x61, - TUNER_LG_TDVS_H06XF); - goto fe_found; - } - - /* try the air atsc 1nd generation (bcm3510)/panasonic ct10s */ - fc->fe = dvb_attach(bcm3510_attach, &air2pc_atsc_first_gen_config, i2c); - if (fc->fe != NULL) { - fc->dev_type = FC_AIR_ATSC1; - goto fe_found; - } - - /* try the cable dvb (stv0297) */ fc->fc_i2c_adap[0].no_base_addr = 1; fc->fe = dvb_attach(stv0297_attach, &alps_tdee4_stv0297_config, i2c); - if (fc->fe != NULL) { - fc->dev_type = FC_CABLE; - fc->fe->ops.tuner_ops.set_params = alps_tdee4_stv0297_tuner_set_params; - goto fe_found; + if (!fc->fe) { + /* Reset for next frontend to try */ + fc->fc_i2c_adap[0].no_base_addr = 0; + return 0; } - fc->fc_i2c_adap[0].no_base_addr = 0; + fc->fe->ops.tuner_ops.set_params = alps_tdee4_stv0297_tuner_set_params; + return 1; +} +#endif - /* try the sky v2.3 (vp310/Samsung tbdu18132(tsa5059)) */ - fc->fe = dvb_attach(mt312_attach, - &skystar23_samsung_tbdu18132_config, i2c); - if (fc->fe != NULL) { - ops = &fc->fe->ops; +static struct { + flexcop_device_type_t type; + int (*attach)(struct flexcop_device *, struct i2c_adapter *); +} flexcop_frontends[] = { +#if defined(CONFIG_DVB_S5H1420_MODULE) + { FC_SKY_REV27, skystar2_rev27_attach }, +#endif +#if defined(CONFIG_DVB_CX24123_MODULE) + { FC_SKY_REV28, skystar2_rev28_attach }, +#endif +#if defined(CONFIG_DVB_STV0299_MODULE) + { FC_SKY_REV26, skystar2_rev26_attach }, +#endif +#if defined(CONFIG_DVB_MT352_MODULE) + { FC_AIR_DVBT, airstar_dvbt_attach }, +#endif +#if defined(CONFIG_DVB_NXT200X_MODULE) + { FC_AIR_ATSC2, airstar_atsc2_attach }, +#endif +#if defined(CONFIG_DVB_LGDT330X_MODULE) + { FC_AIR_ATSC3, airstar_atsc3_attach }, +#endif +#if defined(CONFIG_DVB_BCM3510_MODULE) + { FC_AIR_ATSC1, airstar_atsc1_attach }, +#endif +#if defined(CONFIG_DVB_STV0297_MODULE) + { FC_CABLE, cablestar2_attach }, +#endif +#if defined(CONFIG_DVB_MT312_MODULE) + { FC_SKY_REV23, skystar2_rev23_attach }, +#endif +}; - ops->tuner_ops.set_params = skystar23_samsung_tbdu18132_tuner_set_params; - - ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd; - ops->diseqc_send_burst = flexcop_diseqc_send_burst; - ops->set_tone = flexcop_set_tone; - ops->set_voltage = flexcop_set_voltage; - - fc->fe_sleep = ops->sleep; - ops->sleep = flexcop_sleep; - - fc->dev_type = FC_SKY_REV23; - goto fe_found; +/* try to figure out the frontend */ +int flexcop_frontend_init(struct flexcop_device *fc) +{ + int i; + for (i = 0; i < ARRAY_SIZE(flexcop_frontends); i++) { + /* type needs to be set before, because of some workarounds + * done based on the probed card type */ + fc->dev_type = flexcop_frontends[i].type; + if (flexcop_frontends[i].attach(fc, &fc->fc_i2c_adap[0].i2c_adap)) + goto fe_found; + /* Clean up partially attached frontend */ + if (fc->fe) { + dvb_frontend_detach(fc->fe); + fc->fe = NULL; + } } - + fc->dev_type = FC_UNK; err("no frontend driver found for this B2C2/FlexCop adapter"); return -ENODEV; @@ -664,9 +757,7 @@ fe_found: info("found '%s' .", fc->fe->ops.info.name); if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) { err("frontend registration failed!"); - ops = &fc->fe->ops; - if (ops->release != NULL) - ops->release(fc->fe); + dvb_frontend_detach(fc->fe); fc->fe = NULL; return -EINVAL; } @@ -680,6 +771,5 @@ void flexcop_frontend_exit(struct flexcop_device *fc) dvb_unregister_frontend(fc->fe); dvb_frontend_detach(fc->fe); } - fc->init_state &= ~FC_STATE_FE_INIT; } diff --git a/drivers/media/dvb/b2c2/flexcop-i2c.c b/drivers/media/dvb/b2c2/flexcop-i2c.c index e2bed5076485..fd1df2352764 100644 --- a/drivers/media/dvb/b2c2/flexcop-i2c.c +++ b/drivers/media/dvb/b2c2/flexcop-i2c.c @@ -200,7 +200,7 @@ static int flexcop_master_xfer(struct i2c_adapter *i2c_adap, msgs[i].buf[0], &msgs[i].buf[1], msgs[i].len - 1); if (ret < 0) { - err("i2c master_xfer failed"); + deb_i2c("i2c master_xfer failed"); break; } } diff --git a/drivers/media/dvb/b2c2/flexcop-misc.c b/drivers/media/dvb/b2c2/flexcop-misc.c index e56627d2f0f4..f06f3a9070f5 100644 --- a/drivers/media/dvb/b2c2/flexcop-misc.c +++ b/drivers/media/dvb/b2c2/flexcop-misc.c @@ -46,16 +46,16 @@ static const char *flexcop_revision_names[] = { }; static const char *flexcop_device_names[] = { - "Unknown device", - "Air2PC/AirStar 2 DVB-T", - "Air2PC/AirStar 2 ATSC 1st generation", - "Air2PC/AirStar 2 ATSC 2nd generation", - "Sky2PC/SkyStar 2 DVB-S", - "Sky2PC/SkyStar 2 DVB-S (old version)", - "Cable2PC/CableStar 2 DVB-C", - "Air2PC/AirStar 2 ATSC 3rd generation (HD5000)", - "Sky2PC/SkyStar 2 DVB-S rev 2.7a/u", - "Sky2PC/SkyStar 2 DVB-S rev 2.8", + [FC_UNK] = "Unknown device", + [FC_CABLE] = "Cable2PC/CableStar 2 DVB-C", + [FC_AIR_DVBT] = "Air2PC/AirStar 2 DVB-T", + [FC_AIR_ATSC1] = "Air2PC/AirStar 2 ATSC 1st generation", + [FC_AIR_ATSC2] = "Air2PC/AirStar 2 ATSC 2nd generation", + [FC_AIR_ATSC3] = "Air2PC/AirStar 2 ATSC 3rd generation (HD5000)", + [FC_SKY_REV23] = "Sky2PC/SkyStar 2 DVB-S rev 2.3 (old version)", + [FC_SKY_REV26] = "Sky2PC/SkyStar 2 DVB-S rev 2.6", + [FC_SKY_REV27] = "Sky2PC/SkyStar 2 DVB-S rev 2.7a/u", + [FC_SKY_REV28] = "Sky2PC/SkyStar 2 DVB-S rev 2.8", }; static const char *flexcop_bus_names[] = { diff --git a/drivers/media/dvb/bt8xx/bt878.c b/drivers/media/dvb/bt8xx/bt878.c index 56d8fab688bb..a24c125331f0 100644 --- a/drivers/media/dvb/bt8xx/bt878.c +++ b/drivers/media/dvb/bt8xx/bt878.c @@ -508,12 +508,6 @@ static int __devinit bt878_probe(struct pci_dev *dev, pci_set_master(dev); pci_set_drvdata(dev, bt); -/* if(init_bt878(btv) < 0) { - bt878_remove(dev); - return -EIO; - } -*/ - if ((result = bt878_mem_alloc(bt))) { printk(KERN_ERR "bt878: failed to allocate memory!\n"); goto fail2; @@ -579,7 +573,7 @@ static struct pci_driver bt878_pci_driver = { .name = "bt878", .id_table = bt878_pci_tbl, .probe = bt878_probe, - .remove = bt878_remove, + .remove = __devexit_p(bt878_remove), }; static int bt878_pci_driver_registered; diff --git a/drivers/media/dvb/dm1105/dm1105.c b/drivers/media/dvb/dm1105/dm1105.c index 971a8b18f6dd..4dbd7d4185af 100644 --- a/drivers/media/dvb/dm1105/dm1105.c +++ b/drivers/media/dvb/dm1105/dm1105.c @@ -51,6 +51,9 @@ #ifndef PCI_VENDOR_ID_TRIGEM #define PCI_VENDOR_ID_TRIGEM 0x109f #endif +#ifndef PCI_VENDOR_ID_AXESS +#define PCI_VENDOR_ID_AXESS 0x195d +#endif #ifndef PCI_DEVICE_ID_DM1105 #define PCI_DEVICE_ID_DM1105 0x036f #endif @@ -60,6 +63,9 @@ #ifndef PCI_DEVICE_ID_DW2004 #define PCI_DEVICE_ID_DW2004 0x2004 #endif +#ifndef PCI_DEVICE_ID_DM05 +#define PCI_DEVICE_ID_DM05 0x1105 +#endif /* ----------------------------------------------- */ /* sdmc dm1105 registers */ @@ -150,6 +156,11 @@ #define DM1105_LNB_13V 0x00010100 #define DM1105_LNB_18V 0x00000100 +/* GPIO's for LNB power control for Axess DM05 */ +#define DM05_LNB_MASK 0x00000000 +#define DM05_LNB_13V 0x00020000 +#define DM05_LNB_18V 0x00030000 + static int ir_debug; module_param(ir_debug, int, 0644); MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding"); @@ -188,6 +199,8 @@ struct dm1105dvb { /* irq */ struct work_struct work; + struct workqueue_struct *wq; + char wqn[16]; /* dma */ dma_addr_t dma_addr; @@ -313,15 +326,25 @@ static inline struct dm1105dvb *frontend_to_dm1105dvb(struct dvb_frontend *fe) static int dm1105dvb_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) { struct dm1105dvb *dm1105dvb = frontend_to_dm1105dvb(fe); + u32 lnb_mask, lnb_13v, lnb_18v; - if (voltage == SEC_VOLTAGE_18) { - outl(DM1105_LNB_MASK, dm_io_mem(DM1105_GPIOCTR)); - outl(DM1105_LNB_18V, dm_io_mem(DM1105_GPIOVAL)); - } else { - /*LNB ON-13V by default!*/ - outl(DM1105_LNB_MASK, dm_io_mem(DM1105_GPIOCTR)); - outl(DM1105_LNB_13V, dm_io_mem(DM1105_GPIOVAL)); - } + switch (dm1105dvb->pdev->subsystem_device) { + case PCI_DEVICE_ID_DM05: + lnb_mask = DM05_LNB_MASK; + lnb_13v = DM05_LNB_13V; + lnb_18v = DM05_LNB_18V; + break; + default: + lnb_mask = DM1105_LNB_MASK; + lnb_13v = DM1105_LNB_13V; + lnb_18v = DM1105_LNB_18V; + } + + outl(lnb_mask, dm_io_mem(DM1105_GPIOCTR)); + if (voltage == SEC_VOLTAGE_18) + outl(lnb_18v , dm_io_mem(DM1105_GPIOVAL)); + else + outl(lnb_13v, dm_io_mem(DM1105_GPIOVAL)); return 0; } @@ -440,7 +463,7 @@ static irqreturn_t dm1105dvb_irq(int irq, void *dev_id) case (INTSTS_TSIRQ | INTSTS_IR): dm1105dvb->nextwrp = inl(dm_io_mem(DM1105_WRP)) - inl(dm_io_mem(DM1105_STADR)); - schedule_work(&dm1105dvb->work); + queue_work(dm1105dvb->wq, &dm1105dvb->work); break; case INTSTS_IR: dm1105dvb->ir.ir_command = inl(dm_io_mem(DM1105_IRCODE)); @@ -567,46 +590,44 @@ static int __devinit frontend_init(struct dm1105dvb *dm1105dvb) int ret; switch (dm1105dvb->pdev->subsystem_device) { - case PCI_DEVICE_ID_DW2002: - dm1105dvb->fe = dvb_attach( - stv0299_attach, &sharp_z0194a_config, - &dm1105dvb->i2c_adap); - - if (dm1105dvb->fe) { - dm1105dvb->fe->ops.set_voltage = - dm1105dvb_set_voltage; - dvb_attach(dvb_pll_attach, dm1105dvb->fe, 0x60, - &dm1105dvb->i2c_adap, DVB_PLL_OPERA1); - } - - if (!dm1105dvb->fe) { - dm1105dvb->fe = dvb_attach( - stv0288_attach, &earda_config, - &dm1105dvb->i2c_adap); - if (dm1105dvb->fe) { - dm1105dvb->fe->ops.set_voltage = - dm1105dvb_set_voltage; - dvb_attach(stb6000_attach, dm1105dvb->fe, 0x61, - &dm1105dvb->i2c_adap); - } - } - - if (!dm1105dvb->fe) { - dm1105dvb->fe = dvb_attach( - si21xx_attach, &serit_config, - &dm1105dvb->i2c_adap); - if (dm1105dvb->fe) - dm1105dvb->fe->ops.set_voltage = - dm1105dvb_set_voltage; - } - break; case PCI_DEVICE_ID_DW2004: dm1105dvb->fe = dvb_attach( cx24116_attach, &serit_sp2633_config, &dm1105dvb->i2c_adap); if (dm1105dvb->fe) dm1105dvb->fe->ops.set_voltage = dm1105dvb_set_voltage; + break; + default: + dm1105dvb->fe = dvb_attach( + stv0299_attach, &sharp_z0194a_config, + &dm1105dvb->i2c_adap); + if (dm1105dvb->fe) { + dm1105dvb->fe->ops.set_voltage = + dm1105dvb_set_voltage; + dvb_attach(dvb_pll_attach, dm1105dvb->fe, 0x60, + &dm1105dvb->i2c_adap, DVB_PLL_OPERA1); + break; + } + + dm1105dvb->fe = dvb_attach( + stv0288_attach, &earda_config, + &dm1105dvb->i2c_adap); + if (dm1105dvb->fe) { + dm1105dvb->fe->ops.set_voltage = + dm1105dvb_set_voltage; + dvb_attach(stb6000_attach, dm1105dvb->fe, 0x61, + &dm1105dvb->i2c_adap); + break; + } + + dm1105dvb->fe = dvb_attach( + si21xx_attach, &serit_config, + &dm1105dvb->i2c_adap); + if (dm1105dvb->fe) + dm1105dvb->fe->ops.set_voltage = + dm1105dvb_set_voltage; + } if (!dm1105dvb->fe) { @@ -630,10 +651,17 @@ static void __devinit dm1105dvb_read_mac(struct dm1105dvb *dm1105dvb, u8 *mac) static u8 command[1] = { 0x28 }; struct i2c_msg msg[] = { - { .addr = IIC_24C01_addr >> 1, .flags = 0, - .buf = command, .len = 1 }, - { .addr = IIC_24C01_addr >> 1, .flags = I2C_M_RD, - .buf = mac, .len = 6 }, + { + .addr = IIC_24C01_addr >> 1, + .flags = 0, + .buf = command, + .len = 1 + }, { + .addr = IIC_24C01_addr >> 1, + .flags = I2C_M_RD, + .buf = mac, + .len = 6 + }, }; dm1105_i2c_xfer(&dm1105dvb->i2c_adap, msg , 2); @@ -752,14 +780,22 @@ static int __devinit dm1105_probe(struct pci_dev *pdev, dm1105_ir_init(dm1105dvb); INIT_WORK(&dm1105dvb->work, dm1105_dmx_buffer); + sprintf(dm1105dvb->wqn, "%s/%d", dvb_adapter->name, dvb_adapter->num); + dm1105dvb->wq = create_singlethread_workqueue(dm1105dvb->wqn); + if (!dm1105dvb->wq) + goto err_dvb_net; ret = request_irq(pdev->irq, dm1105dvb_irq, IRQF_SHARED, DRIVER_NAME, dm1105dvb); if (ret < 0) - goto err_free_irq; + goto err_workqueue; return 0; +err_workqueue: + destroy_workqueue(dm1105dvb->wq); +err_dvb_net: + dvb_net_release(&dm1105dvb->dvbnet); err_disconnect_frontend: dmx->disconnect_frontend(dmx); err_remove_mem_frontend: @@ -776,8 +812,6 @@ err_i2c_del_adapter: i2c_del_adapter(&dm1105dvb->i2c_adap); err_dm1105dvb_hw_exit: dm1105dvb_hw_exit(dm1105dvb); -err_free_irq: - free_irq(pdev->irq, dm1105dvb); err_pci_iounmap: pci_iounmap(pdev, dm1105dvb->io_mem); err_pci_release_regions: @@ -833,6 +867,11 @@ static struct pci_device_id dm1105_id_table[] __devinitdata = { .device = PCI_DEVICE_ID_DM1105, .subvendor = PCI_ANY_ID, .subdevice = PCI_DEVICE_ID_DW2004, + }, { + .vendor = PCI_VENDOR_ID_AXESS, + .device = PCI_DEVICE_ID_DM05, + .subvendor = PCI_VENDOR_ID_AXESS, + .subdevice = PCI_DEVICE_ID_DM05, }, { /* empty */ }, diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c index c35fbb8d8f4a..6d6121eb5d59 100644 --- a/drivers/media/dvb/dvb-core/dmxdev.c +++ b/drivers/media/dvb/dvb-core/dmxdev.c @@ -244,19 +244,13 @@ static ssize_t dvb_dvr_read(struct file *file, char __user *buf, size_t count, { struct dvb_device *dvbdev = file->private_data; struct dmxdev *dmxdev = dvbdev->priv; - int ret; - if (dmxdev->exit) { - mutex_unlock(&dmxdev->mutex); + if (dmxdev->exit) return -ENODEV; - } - //mutex_lock(&dmxdev->mutex); - ret = dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer, - file->f_flags & O_NONBLOCK, - buf, count, ppos); - //mutex_unlock(&dmxdev->mutex); - return ret; + return dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer, + file->f_flags & O_NONBLOCK, + buf, count, ppos); } static int dvb_dvr_set_buffer_size(struct dmxdev *dmxdev, diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c index e2eca0b1fe7c..cfe2768d24af 100644 --- a/drivers/media/dvb/dvb-core/dvb_demux.c +++ b/drivers/media/dvb/dvb-core/dvb_demux.c @@ -38,6 +38,16 @@ */ // #define DVB_DEMUX_SECTION_LOSS_LOG +static int dvb_demux_tscheck; +module_param(dvb_demux_tscheck, int, 0644); +MODULE_PARM_DESC(dvb_demux_tscheck, + "enable transport stream continuity and TEI check"); + +#define dprintk_tscheck(x...) do { \ + if (dvb_demux_tscheck && printk_ratelimit()) \ + printk(x); \ + } while (0) + /****************************************************************************** * static inlined helper functions ******************************************************************************/ @@ -376,6 +386,36 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf) u16 pid = ts_pid(buf); int dvr_done = 0; + if (dvb_demux_tscheck) { + if (!demux->cnt_storage) + demux->cnt_storage = vmalloc(MAX_PID + 1); + + if (!demux->cnt_storage) { + printk(KERN_WARNING "Couldn't allocate memory for TS/TEI check. Disabling it\n"); + dvb_demux_tscheck = 0; + goto no_dvb_demux_tscheck; + } + + /* check pkt counter */ + if (pid < MAX_PID) { + if (buf[1] & 0x80) + dprintk_tscheck("TEI detected. " + "PID=0x%x data1=0x%x\n", + pid, buf[1]); + + if ((buf[3] & 0xf) != demux->cnt_storage[pid]) + dprintk_tscheck("TS packet counter mismatch. " + "PID=0x%x expected 0x%x " + "got 0x%x\n", + pid, demux->cnt_storage[pid], + buf[3] & 0xf); + + demux->cnt_storage[pid] = ((buf[3] & 0xf) + 1)&0xf; + }; + /* end check */ + }; +no_dvb_demux_tscheck: + list_for_each_entry(feed, &demux->feed_list, list_head) { if ((feed->pid != pid) && (feed->pid != 0x2000)) continue; @@ -1160,6 +1200,7 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux) int i; struct dmx_demux *dmx = &dvbdemux->dmx; + dvbdemux->cnt_storage = NULL; dvbdemux->users = 0; dvbdemux->filter = vmalloc(dvbdemux->filternum * sizeof(struct dvb_demux_filter)); @@ -1226,6 +1267,7 @@ EXPORT_SYMBOL(dvb_dmx_init); void dvb_dmx_release(struct dvb_demux *dvbdemux) { + vfree(dvbdemux->cnt_storage); vfree(dvbdemux->filter); vfree(dvbdemux->feed); } diff --git a/drivers/media/dvb/dvb-core/dvb_demux.h b/drivers/media/dvb/dvb-core/dvb_demux.h index 2c5f915329ca..2fe05d03240d 100644 --- a/drivers/media/dvb/dvb-core/dvb_demux.h +++ b/drivers/media/dvb/dvb-core/dvb_demux.h @@ -42,6 +42,8 @@ #define DVB_DEMUX_MASK_MAX 18 +#define MAX_PID 0x1fff + struct dvb_demux_filter { struct dmx_section_filter filter; u8 maskandmode[DMX_MAX_FILTER_SIZE]; @@ -127,6 +129,8 @@ struct dvb_demux { struct mutex mutex; spinlock_t lock; + + uint8_t *cnt_storage; /* for TS continuity check */ }; int dvb_dmx_init(struct dvb_demux *dvbdemux); diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index ebc78157b9b8..f50ca7292a7d 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -543,6 +543,7 @@ restart: if (kthread_should_stop() || dvb_frontend_is_exiting(fe)) { /* got signal or quitting */ + fepriv->exit = 1; break; } @@ -656,6 +657,7 @@ restart: } fepriv->thread = NULL; + fepriv->exit = 0; mb(); dvb_frontend_wakeup(fe); diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c index a454ee8f1e43..479dd05762a5 100644 --- a/drivers/media/dvb/dvb-core/dvbdev.c +++ b/drivers/media/dvb/dvb-core/dvbdev.c @@ -447,6 +447,15 @@ static int dvb_uevent(struct device *dev, struct kobj_uevent_env *env) return 0; } +static char *dvb_nodename(struct device *dev) +{ + struct dvb_device *dvbdev = dev_get_drvdata(dev); + + return kasprintf(GFP_KERNEL, "dvb/adapter%d/%s%d", + dvbdev->adapter->num, dnames[dvbdev->type], dvbdev->id); +} + + static int __init init_dvbdev(void) { int retval; @@ -469,6 +478,7 @@ static int __init init_dvbdev(void) goto error; } dvb_class->dev_uevent = dvb_uevent; + dvb_class->nodename = dvb_nodename; return 0; error: diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index 60955a70d880..496c1a37034c 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -216,7 +216,7 @@ config DVB_USB_TTUSB2 help Say Y here to support the Pinnacle 400e DVB-S USB2.0 receiver. The firmware protocol used by this module is similar to the one used by the - old ttusb-driver - that's why the module is called dvb-usb-ttusb2.ko. + old ttusb-driver - that's why the module is called dvb-usb-ttusb2. config DVB_USB_DTT200U tristate "WideView WT-200U and WT-220U (pen) DVB-T USB2.0 support (Yakumo/Hama/Typhoon/Yuan)" @@ -261,6 +261,7 @@ config DVB_USB_DW2102 select DVB_STB6000 if !DVB_FE_CUSTOMISE select DVB_CX24116 if !DVB_FE_CUSTOMISE select DVB_SI21XX if !DVB_FE_CUSTOMISE + select DVB_TDA10021 if !DVB_FE_CUSTOMISE help Say Y here to support the DvbWorld DVB-S/S2 USB2.0 receivers and the TeVii S650. diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c index 53bfc8e42fb9..4cb31e7c13c2 100644 --- a/drivers/media/dvb/dvb-usb/af9015.c +++ b/drivers/media/dvb/dvb-usb/af9015.c @@ -40,7 +40,7 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); static DEFINE_MUTEX(af9015_usb_mutex); static struct af9015_config af9015_config; -static struct dvb_usb_device_properties af9015_properties[2]; +static struct dvb_usb_device_properties af9015_properties[3]; static int af9015_properties_count = ARRAY_SIZE(af9015_properties); static struct af9013_config af9015_af9013_config[] = { @@ -538,7 +538,7 @@ exit: /* dump eeprom */ static int af9015_eeprom_dump(struct dvb_usb_device *d) { - char buf[52], buf2[4]; + char buf[4+3*16+1], buf2[4]; u8 reg, val; for (reg = 0; ; reg++) { @@ -1261,7 +1261,11 @@ static struct usb_device_id af9015_usb_table[] = { {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_2)}, {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_3)}, {USB_DEVICE(USB_VID_AFATECH, USB_PID_TREKSTOR_DVBT)}, - {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850)}, +/* 20 */{USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850)}, + {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A805)}, + {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CONCEPTRONIC_CTVDIGRCU)}, + {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_MC810)}, + {USB_DEVICE(USB_VID_KYE, USB_PID_GENIUS_TVGO_DVB_T03)}, {0}, }; MODULE_DEVICE_TABLE(usb, af9015_usb_table); @@ -1321,7 +1325,7 @@ static struct dvb_usb_device_properties af9015_properties[] = { .i2c_algo = &af9015_i2c_algo, - .num_device_descs = 9, + .num_device_descs = 9, /* max 9 */ .devices = { { .name = "Afatech AF9015 DVB-T USB2.0 stick", @@ -1426,7 +1430,7 @@ static struct dvb_usb_device_properties af9015_properties[] = { .i2c_algo = &af9015_i2c_algo, - .num_device_descs = 9, + .num_device_descs = 9, /* max 9 */ .devices = { { .name = "Xtensions XD-380", @@ -1478,7 +1482,85 @@ static struct dvb_usb_device_properties af9015_properties[] = { .warm_ids = {NULL}, }, } - } + }, { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = DEVICE_SPECIFIC, + .download_firmware = af9015_download_firmware, + .firmware = "dvb-usb-af9015.fw", + .no_reconnect = 1, + + .size_of_priv = sizeof(struct af9015_state), \ + + .num_adapters = 2, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + + .pid_filter_count = 32, + .pid_filter = af9015_pid_filter, + .pid_filter_ctrl = af9015_pid_filter_ctrl, + + .frontend_attach = + af9015_af9013_frontend_attach, + .tuner_attach = af9015_tuner_attach, + .stream = { + .type = USB_BULK, + .count = 6, + .endpoint = 0x84, + }, + }, + { + .frontend_attach = + af9015_af9013_frontend_attach, + .tuner_attach = af9015_tuner_attach, + .stream = { + .type = USB_BULK, + .count = 6, + .endpoint = 0x85, + .u = { + .bulk = { + .buffersize = + TS_USB20_MAX_PACKET_SIZE, + } + } + }, + } + }, + + .identify_state = af9015_identify_state, + + .rc_query = af9015_rc_query, + .rc_interval = 150, + + .i2c_algo = &af9015_i2c_algo, + + .num_device_descs = 4, /* max 9 */ + .devices = { + { + .name = "AverMedia AVerTV Volar GPS 805 (A805)", + .cold_ids = {&af9015_usb_table[21], NULL}, + .warm_ids = {NULL}, + }, + { + .name = "Conceptronic USB2.0 DVB-T CTVDIGRCU " \ + "V3.0", + .cold_ids = {&af9015_usb_table[22], NULL}, + .warm_ids = {NULL}, + }, + { + .name = "KWorld Digial MC-810", + .cold_ids = {&af9015_usb_table[23], NULL}, + .warm_ids = {NULL}, + }, + { + .name = "Genius TVGo DVB-T03", + .cold_ids = {&af9015_usb_table[24], NULL}, + .warm_ids = {NULL}, + }, + } + }, }; static int af9015_usb_probe(struct usb_interface *intf, diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 8ddbadf62194..818b2ab584bf 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -1346,9 +1346,9 @@ static int dib0700_xc5000_tuner_callback(void *priv, int component, if (command == XC5000_TUNER_RESET) { /* Reset the tuner */ dib0700_set_gpio(adap->dev, GPIO1, GPIO_OUT, 0); - msleep(330); /* from Windows USB trace */ + msleep(10); dib0700_set_gpio(adap->dev, GPIO1, GPIO_OUT, 1); - msleep(330); /* from Windows USB trace */ + msleep(10); } else { err("xc5000: unknown tuner callback command: %d\n", command); return -EINVAL; @@ -1493,6 +1493,10 @@ struct usb_device_id dib0700_usb_id_table[] = { { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_TIGER_ATSC_B210) }, { USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_MC770) }, { USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_DTT) }, +/* 50 */{ USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_DTT_Dlx) }, + { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_H) }, + { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_T3) }, + { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_T5) }, { 0 } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); @@ -1692,7 +1696,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { }, }, - .num_device_descs = 11, + .num_device_descs = 12, .devices = { { "DiBcom STK7070P reference design", { &dib0700_usb_id_table[15], NULL }, @@ -1726,8 +1730,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { { &dib0700_usb_id_table[30], NULL }, { NULL }, }, - { "Terratec Cinergy T USB XXS", - { &dib0700_usb_id_table[33], NULL }, + { "Terratec Cinergy T USB XXS/ T3", + { &dib0700_usb_id_table[33], + &dib0700_usb_id_table[52], NULL }, { NULL }, }, { "Elgato EyeTV DTT", @@ -1738,6 +1743,10 @@ struct dvb_usb_device_properties dib0700_devices[] = { { &dib0700_usb_id_table[45], NULL }, { NULL }, }, + { "Elgato EyeTV Dtt Dlx PD378S", + { &dib0700_usb_id_table[50], NULL }, + { NULL }, + }, }, .rc_interval = DEFAULT_RC_INTERVAL, @@ -1784,8 +1793,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { { &dib0700_usb_id_table[36], NULL }, { NULL }, }, - { "Terratec Cinergy DT USB XS Diversity", - { &dib0700_usb_id_table[43], NULL }, + { "Terratec Cinergy DT USB XS Diversity/ T5", + { &dib0700_usb_id_table[43], + &dib0700_usb_id_table[53], NULL}, { NULL }, }, { "Sony PlayTV", @@ -1812,7 +1822,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { }, }, - .num_device_descs = 7, + .num_device_descs = 8, .devices = { { "Terratec Cinergy HT USB XE", { &dib0700_usb_id_table[27], NULL }, @@ -1842,6 +1852,11 @@ struct dvb_usb_device_properties dib0700_devices[] = { { &dib0700_usb_id_table[48], NULL }, { NULL }, }, + { "Leadtek WinFast DTV Dongle H", + { &dib0700_usb_id_table[51], NULL }, + { NULL }, + }, + }, .rc_interval = DEFAULT_RC_INTERVAL, .rc_key_map = dib0700_rc_keys, diff --git a/drivers/media/dvb/dvb-usb/dibusb-common.c b/drivers/media/dvb/dvb-usb/dibusb-common.c index 8ee6cd4da9e7..8dbad1ec53c4 100644 --- a/drivers/media/dvb/dvb-usb/dibusb-common.c +++ b/drivers/media/dvb/dvb-usb/dibusb-common.c @@ -133,14 +133,17 @@ static int dibusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num for (i = 0; i < num; i++) { /* write/read request */ - if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { + if (i+1 < num && (msg[i].flags & I2C_M_RD) == 0 + && (msg[i+1].flags & I2C_M_RD)) { if (dibusb_i2c_msg(d, msg[i].addr, msg[i].buf,msg[i].len, msg[i+1].buf,msg[i+1].len) < 0) break; i++; - } else + } else if ((msg[i].flags & I2C_M_RD) == 0) { if (dibusb_i2c_msg(d, msg[i].addr, msg[i].buf,msg[i].len,NULL,0) < 0) break; + } else + break; } mutex_unlock(&d->i2c_mutex); diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index f506c74119f3..9593b7289994 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -80,6 +80,7 @@ #define USB_PID_COMPRO_DVBU2000_UNK_WARM 0x010d #define USB_PID_COMPRO_VIDEOMATE_U500 0x1e78 #define USB_PID_COMPRO_VIDEOMATE_U500_PC 0x1e80 +#define USB_PID_CONCEPTRONIC_CTVDIGRCU 0xe397 #define USB_PID_CONEXANT_D680_DMB 0x86d6 #define USB_PID_DIBCOM_HOOK_DEFAULT 0x0064 #define USB_PID_DIBCOM_HOOK_DEFAULT_REENUM 0x0065 @@ -97,6 +98,7 @@ #define USB_PID_DPOSH_M9206_COLD 0x9206 #define USB_PID_DPOSH_M9206_WARM 0xa090 #define USB_PID_UNIWILL_STK7700P 0x6003 +#define USB_PID_GENIUS_TVGO_DVB_T03 0x4012 #define USB_PID_GRANDTEC_DVBT_USB_COLD 0x0fa0 #define USB_PID_GRANDTEC_DVBT_USB_WARM 0x0fa1 #define USB_PID_INTEL_CE9500 0x9500 @@ -104,6 +106,7 @@ #define USB_PID_KWORLD_395U 0xe396 #define USB_PID_KWORLD_395U_2 0xe39b #define USB_PID_KWORLD_395U_3 0xe395 +#define USB_PID_KWORLD_MC810 0xc810 #define USB_PID_KWORLD_PC160_2T 0xc160 #define USB_PID_KWORLD_VSTREAM_COLD 0x17de #define USB_PID_KWORLD_VSTREAM_WARM 0x17df @@ -171,6 +174,7 @@ #define USB_PID_AVERMEDIA_A309 0xa309 #define USB_PID_AVERMEDIA_A310 0xa310 #define USB_PID_AVERMEDIA_A850 0x850a +#define USB_PID_AVERMEDIA_A805 0xa805 #define USB_PID_TECHNOTREND_CONNECT_S2400 0x3006 #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY 0x005a #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY_2 0x0081 @@ -178,6 +182,8 @@ #define USB_PID_TERRATEC_CINERGY_HT_EXPRESS 0x0060 #define USB_PID_TERRATEC_CINERGY_T_EXPRESS 0x0062 #define USB_PID_TERRATEC_CINERGY_T_XXS 0x0078 +#define USB_PID_TERRATEC_T3 0x10a0 +#define USB_PID_TERRATEC_T5 0x10a1 #define USB_PID_PINNACLE_EXPRESSCARD_320CX 0x022e #define USB_PID_PINNACLE_PCTV2000E 0x022c #define USB_PID_PINNACLE_PCTV_DVB_T_FLASH 0x0228 @@ -222,6 +228,7 @@ #define USB_PID_WINFAST_DTV_DONGLE_COLD 0x6025 #define USB_PID_WINFAST_DTV_DONGLE_WARM 0x6026 #define USB_PID_WINFAST_DTV_DONGLE_STK7700P 0x6f00 +#define USB_PID_WINFAST_DTV_DONGLE_H 0x60f6 #define USB_PID_WINFAST_DTV_DONGLE_STK7700P_2 0x6f01 #define USB_PID_WINFAST_DTV_DONGLE_GOLD 0x6029 #define USB_PID_GENPIX_8PSK_REV_1_COLD 0x0200 @@ -251,5 +258,6 @@ #define USB_PID_MSI_DIGI_VOX_MINI_III 0x8807 #define USB_PID_SONY_PLAYTV 0x0003 #define USB_PID_ELGATO_EYETV_DTT 0x0021 +#define USB_PID_ELGATO_EYETV_DTT_Dlx 0x0020 #endif diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h index 2d5352e54dc0..e441d274e6c1 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb.h @@ -196,7 +196,7 @@ struct dvb_usb_device_properties { #define CYPRESS_FX2 3 int usb_ctrl; int (*download_firmware) (struct usb_device *, const struct firmware *); - const char firmware[FIRMWARE_NAME_MAX]; + const char *firmware; int no_reconnect; int size_of_priv; @@ -223,7 +223,7 @@ struct dvb_usb_device_properties { int generic_bulk_ctrl_endpoint; int num_device_descs; - struct dvb_usb_device_description devices[11]; + struct dvb_usb_device_description devices[12]; }; /** diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c index c65f273ff313..75de49c0d943 100644 --- a/drivers/media/dvb/dvb-usb/dw2102.c +++ b/drivers/media/dvb/dvb-usb/dw2102.c @@ -1,7 +1,7 @@ /* DVB USB framework compliant Linux driver for the -* DVBWorld DVB-S 2101, 2102, DVB-S2 2104 Card -* -* Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by) +* DVBWorld DVB-S 2101, 2102, DVB-S2 2104, DVB-C 3101, +* TeVii S600, S650 Cards +* Copyright (C) 2008,2009 Igor M. Liplianin (liplianin@me.by) * * 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 @@ -17,6 +17,7 @@ #include "stb6000.h" #include "eds1547.h" #include "cx24116.h" +#include "tda1002x.h" #ifndef USB_PID_DW2102 #define USB_PID_DW2102 0x2102 @@ -26,10 +27,18 @@ #define USB_PID_DW2104 0x2104 #endif +#ifndef USB_PID_DW3101 +#define USB_PID_DW3101 0x3101 +#endif + #ifndef USB_PID_CINERGY_S #define USB_PID_CINERGY_S 0x0064 #endif +#ifndef USB_PID_TEVII_S650 +#define USB_PID_TEVII_S650 0xd650 +#endif + #define DW210X_READ_MSG 0 #define DW210X_WRITE_MSG 1 @@ -40,18 +49,21 @@ #define DW2102_VOLTAGE_CTRL (0x1800) #define DW2102_RC_QUERY (0x1a00) -struct dw210x_state { - u32 last_key_pressed; -}; -struct dw210x_rc_keys { - u32 keycode; - u32 event; +struct dvb_usb_rc_keys_table { + struct dvb_usb_rc_key *rc_keys; + int rc_keys_size; }; /* debug */ static int dvb_usb_dw2102_debug; module_param_named(debug, dvb_usb_dw2102_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=info 2=xfer (or-able))." DVB_USB_DEBUG_STATUS); +MODULE_PARM_DESC(debug, "set debugging level (1=info 2=xfer 4=rc(or-able))." + DVB_USB_DEBUG_STATUS); + +/* keymaps */ +static int ir_keymap; +module_param_named(keymap, ir_keymap, int, 0644); +MODULE_PARM_DESC(keymap, "set keymap 0=default 1=dvbworld 2=tevii 3=tbs ..."); DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); @@ -79,7 +91,7 @@ static int dw210x_op_rw(struct usb_device *dev, u8 request, u16 value, static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) { -struct dvb_usb_device *d = i2c_get_adapdata(adap); + struct dvb_usb_device *d = i2c_get_adapdata(adap); int i = 0, ret = 0; u8 buf6[] = {0x2c, 0x05, 0xc0, 0, 0, 0, 0}; u16 value; @@ -205,6 +217,7 @@ static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap, mutex_unlock(&d->i2c_mutex); return num; } + static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) { struct dvb_usb_device *d = i2c_get_adapdata(adap); @@ -219,7 +232,7 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms case 2: { /* read */ /* first write first register number */ - u8 ibuf [msg[1].len + 2], obuf[3]; + u8 ibuf[msg[1].len + 2], obuf[3]; obuf[0] = 0xd0; obuf[1] = msg[0].len; obuf[2] = msg[0].buf[0]; @@ -293,7 +306,7 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i case 2: { /* read */ /* first write first register number */ - u8 ibuf [msg[1].len + 2], obuf[3]; + u8 ibuf[msg[1].len + 2], obuf[3]; obuf[0] = 0xaa; obuf[1] = msg[0].len; obuf[2] = msg[0].buf[0]; @@ -360,6 +373,69 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i return num; } +static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], + int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + int ret = 0, i; + + if (!d) + return -ENODEV; + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + switch (num) { + case 2: { + /* read */ + /* first write first register number */ + u8 ibuf[msg[1].len + 2], obuf[3]; + obuf[0] = msg[0].addr << 1; + obuf[1] = msg[0].len; + obuf[2] = msg[0].buf[0]; + ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, + obuf, msg[0].len + 2, DW210X_WRITE_MSG); + /* second read registers */ + ret = dw210x_op_rw(d->udev, 0xc3, 0x19 , 0, + ibuf, msg[1].len + 2, DW210X_READ_MSG); + memcpy(msg[1].buf, ibuf + 2, msg[1].len); + + break; + } + case 1: + switch (msg[0].addr) { + case 0x60: + case 0x0c: { + /* write to register */ + u8 obuf[msg[0].len + 2]; + obuf[0] = msg[0].addr << 1; + obuf[1] = msg[0].len; + memcpy(obuf + 2, msg[0].buf, msg[0].len); + ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, + obuf, msg[0].len + 2, DW210X_WRITE_MSG); + break; + } + case(DW2102_RC_QUERY): { + u8 ibuf[2]; + ret = dw210x_op_rw(d->udev, 0xb8, 0, 0, + ibuf, 2, DW210X_READ_MSG); + memcpy(msg[0].buf, ibuf , 2); + break; + } + } + + break; + } + + for (i = 0; i < num; i++) { + deb_xfer("%02x:%02x: %s ", i, msg[i].addr, + msg[i].flags == 0 ? ">>>" : "<<<"); + debug_dump(msg[i].buf, msg[i].len, deb_xfer); + } + + mutex_unlock(&d->i2c_mutex); + return num; +} + static u32 dw210x_i2c_func(struct i2c_adapter *adapter) { return I2C_FUNC_I2C; @@ -385,6 +461,11 @@ static struct i2c_algorithm dw2104_i2c_algo = { .functionality = dw210x_i2c_func, }; +static struct i2c_algorithm dw3101_i2c_algo = { + .master_xfer = dw3101_i2c_transfer, + .functionality = dw210x_i2c_func, +}; + static int dw210x_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) { int i; @@ -404,6 +485,7 @@ static int dw210x_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) debug_dump(eepromline, 16, deb_xfer); } } + memcpy(mac, eeprom + 8, 6); return 0; }; @@ -448,6 +530,11 @@ static struct si21xx_config serit_sp1511lhb_config = { }; +static struct tda10023_config dw3101_tda10023_config = { + .demod_address = 0x0c, + .invert = 1, +}; + static int dw2104_frontend_attach(struct dvb_usb_adapter *d) { if ((d->fe = dvb_attach(cx24116_attach, &dw2104_config, @@ -460,6 +547,7 @@ static int dw2104_frontend_attach(struct dvb_usb_adapter *d) } static struct dvb_usb_device_properties dw2102_properties; +static struct dvb_usb_device_properties dw2104_properties; static int dw2102_frontend_attach(struct dvb_usb_adapter *d) { @@ -497,6 +585,17 @@ static int dw2102_frontend_attach(struct dvb_usb_adapter *d) return -EIO; } +static int dw3101_frontend_attach(struct dvb_usb_adapter *d) +{ + d->fe = dvb_attach(tda10023_attach, &dw3101_tda10023_config, + &d->dev->i2c_adap, 0x48); + if (d->fe != NULL) { + info("Attached tda10023!\n"); + return 0; + } + return -EIO; +} + static int dw2102_tuner_attach(struct dvb_usb_adapter *adap) { dvb_attach(dvb_pll_attach, adap->fe, 0x60, @@ -512,6 +611,14 @@ static int dw2102_earda_tuner_attach(struct dvb_usb_adapter *adap) return 0; } +static int dw3101_tuner_attach(struct dvb_usb_adapter *adap) +{ + dvb_attach(dvb_pll_attach, adap->fe, 0x60, + &adap->dev->i2c_adap, DVB_PLL_TUA6034); + + return 0; +} + static struct dvb_usb_rc_key dw210x_rc_keys[] = { { 0xf8, 0x0a, KEY_Q }, /*power*/ { 0xf8, 0x0c, KEY_M }, /*mute*/ @@ -544,44 +651,147 @@ static struct dvb_usb_rc_key dw210x_rc_keys[] = { { 0xf8, 0x40, KEY_F }, /*full*/ { 0xf8, 0x1e, KEY_W }, /*tvmode*/ { 0xf8, 0x1b, KEY_B }, /*recall*/ - }; +static struct dvb_usb_rc_key tevii_rc_keys[] = { + { 0xf8, 0x0a, KEY_POWER }, + { 0xf8, 0x0c, KEY_MUTE }, + { 0xf8, 0x11, KEY_1 }, + { 0xf8, 0x12, KEY_2 }, + { 0xf8, 0x13, KEY_3 }, + { 0xf8, 0x14, KEY_4 }, + { 0xf8, 0x15, KEY_5 }, + { 0xf8, 0x16, KEY_6 }, + { 0xf8, 0x17, KEY_7 }, + { 0xf8, 0x18, KEY_8 }, + { 0xf8, 0x19, KEY_9 }, + { 0xf8, 0x10, KEY_0 }, + { 0xf8, 0x1c, KEY_MENU }, + { 0xf8, 0x0f, KEY_VOLUMEDOWN }, + { 0xf8, 0x1a, KEY_LAST }, + { 0xf8, 0x0e, KEY_OPEN }, + { 0xf8, 0x04, KEY_RECORD }, + { 0xf8, 0x09, KEY_VOLUMEUP }, + { 0xf8, 0x08, KEY_CHANNELUP }, + { 0xf8, 0x07, KEY_PVR }, + { 0xf8, 0x0b, KEY_TIME }, + { 0xf8, 0x02, KEY_RIGHT }, + { 0xf8, 0x03, KEY_LEFT }, + { 0xf8, 0x00, KEY_UP }, + { 0xf8, 0x1f, KEY_OK }, + { 0xf8, 0x01, KEY_DOWN }, + { 0xf8, 0x05, KEY_TUNER }, + { 0xf8, 0x06, KEY_CHANNELDOWN }, + { 0xf8, 0x40, KEY_PLAYPAUSE }, + { 0xf8, 0x1e, KEY_REWIND }, + { 0xf8, 0x1b, KEY_FAVORITES }, + { 0xf8, 0x1d, KEY_BACK }, + { 0xf8, 0x4d, KEY_FASTFORWARD }, + { 0xf8, 0x44, KEY_EPG }, + { 0xf8, 0x4c, KEY_INFO }, + { 0xf8, 0x41, KEY_AB }, + { 0xf8, 0x43, KEY_AUDIO }, + { 0xf8, 0x45, KEY_SUBTITLE }, + { 0xf8, 0x4a, KEY_LIST }, + { 0xf8, 0x46, KEY_F1 }, + { 0xf8, 0x47, KEY_F2 }, + { 0xf8, 0x5e, KEY_F3 }, + { 0xf8, 0x5c, KEY_F4 }, + { 0xf8, 0x52, KEY_F5 }, + { 0xf8, 0x5a, KEY_F6 }, + { 0xf8, 0x56, KEY_MODE }, + { 0xf8, 0x58, KEY_SWITCHVIDEOMODE }, +}; +static struct dvb_usb_rc_key tbs_rc_keys[] = { + { 0xf8, 0x84, KEY_POWER }, + { 0xf8, 0x94, KEY_MUTE }, + { 0xf8, 0x87, KEY_1 }, + { 0xf8, 0x86, KEY_2 }, + { 0xf8, 0x85, KEY_3 }, + { 0xf8, 0x8b, KEY_4 }, + { 0xf8, 0x8a, KEY_5 }, + { 0xf8, 0x89, KEY_6 }, + { 0xf8, 0x8f, KEY_7 }, + { 0xf8, 0x8e, KEY_8 }, + { 0xf8, 0x8d, KEY_9 }, + { 0xf8, 0x92, KEY_0 }, + { 0xf8, 0x96, KEY_CHANNELUP }, + { 0xf8, 0x91, KEY_CHANNELDOWN }, + { 0xf8, 0x93, KEY_VOLUMEUP }, + { 0xf8, 0x8c, KEY_VOLUMEDOWN }, + { 0xf8, 0x83, KEY_RECORD }, + { 0xf8, 0x98, KEY_PAUSE }, + { 0xf8, 0x99, KEY_OK }, + { 0xf8, 0x9a, KEY_SHUFFLE }, + { 0xf8, 0x81, KEY_UP }, + { 0xf8, 0x90, KEY_LEFT }, + { 0xf8, 0x82, KEY_RIGHT }, + { 0xf8, 0x88, KEY_DOWN }, + { 0xf8, 0x95, KEY_FAVORITES }, + { 0xf8, 0x97, KEY_SUBTITLE }, + { 0xf8, 0x9d, KEY_ZOOM }, + { 0xf8, 0x9f, KEY_EXIT }, + { 0xf8, 0x9e, KEY_MENU }, + { 0xf8, 0x9c, KEY_EPG }, + { 0xf8, 0x80, KEY_PREVIOUS }, + { 0xf8, 0x9b, KEY_MODE } +}; + +static struct dvb_usb_rc_keys_table keys_tables[] = { + { dw210x_rc_keys, ARRAY_SIZE(dw210x_rc_keys) }, + { tevii_rc_keys, ARRAY_SIZE(tevii_rc_keys) }, + { tbs_rc_keys, ARRAY_SIZE(tbs_rc_keys) }, +}; static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state) { - struct dw210x_state *st = d->priv; + struct dvb_usb_rc_key *keymap = d->props.rc_key_map; + int keymap_size = d->props.rc_key_map_size; u8 key[2]; - struct i2c_msg msg[] = { - {.addr = DW2102_RC_QUERY, .flags = I2C_M_RD, .buf = key, - .len = 2}, + struct i2c_msg msg = { + .addr = DW2102_RC_QUERY, + .flags = I2C_M_RD, + .buf = key, + .len = 2 }; int i; + /* override keymap */ + if ((ir_keymap > 0) && (ir_keymap <= ARRAY_SIZE(keys_tables))) { + keymap = keys_tables[ir_keymap - 1].rc_keys ; + keymap_size = keys_tables[ir_keymap - 1].rc_keys_size; + } *state = REMOTE_NO_KEY_PRESSED; - if (dw2102_i2c_transfer(&d->i2c_adap, msg, 1) == 1) { - for (i = 0; i < ARRAY_SIZE(dw210x_rc_keys); i++) { - if (dw210x_rc_keys[i].data == msg[0].buf[0]) { + if (dw2102_i2c_transfer(&d->i2c_adap, &msg, 1) == 1) { + for (i = 0; i < keymap_size ; i++) { + if (keymap[i].data == msg.buf[0]) { *state = REMOTE_KEY_PRESSED; - *event = dw210x_rc_keys[i].event; - st->last_key_pressed = - dw210x_rc_keys[i].event; + *event = keymap[i].event; break; } - st->last_key_pressed = 0; + } + + if ((*state) == REMOTE_KEY_PRESSED) + deb_rc("%s: found rc key: %x, %x, event: %x\n", + __func__, key[0], key[1], (*event)); + else if (key[0] != 0xff) + deb_rc("%s: unknown rc key: %x, %x\n", + __func__, key[0], key[1]); + } - /* info("key: %x %x\n",key[0],key[1]); */ + return 0; } static struct usb_device_id dw2102_table[] = { {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2102)}, {USB_DEVICE(USB_VID_CYPRESS, 0x2101)}, - {USB_DEVICE(USB_VID_CYPRESS, 0x2104)}, - {USB_DEVICE(0x9022, 0xd650)}, + {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2104)}, + {USB_DEVICE(0x9022, USB_PID_TEVII_S650)}, {USB_DEVICE(USB_VID_TERRATEC, USB_PID_CINERGY_S)}, + {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW3101)}, { } }; @@ -642,11 +852,16 @@ static int dw2102_load_firmware(struct usb_device *dev, } /* init registers */ switch (dev->descriptor.idProduct) { + case USB_PID_TEVII_S650: + dw2104_properties.rc_key_map = tevii_rc_keys; + dw2104_properties.rc_key_map_size = + ARRAY_SIZE(tevii_rc_keys); case USB_PID_DW2104: - case 0xd650: reset = 1; dw210x_op_rw(dev, 0xc4, 0x0000, 0, &reset, 1, DW210X_WRITE_MSG); + /* break omitted intentionally */ + case USB_PID_DW3101: reset = 0; dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0, DW210X_WRITE_MSG); @@ -690,6 +905,7 @@ static int dw2102_load_firmware(struct usb_device *dev, DW210X_READ_MSG); break; } + msleep(100); kfree(p); } @@ -700,7 +916,6 @@ static struct dvb_usb_device_properties dw2102_properties = { .caps = DVB_USB_IS_AN_I2C_ADAPTER, .usb_ctrl = DEVICE_SPECIFIC, .firmware = "dvb-usb-dw2102.fw", - .size_of_priv = sizeof(struct dw210x_state), .no_reconnect = 1, .i2c_algo = &dw2102_serit_i2c_algo, @@ -714,7 +929,7 @@ static struct dvb_usb_device_properties dw2102_properties = { .num_adapters = 1, .download_firmware = dw2102_load_firmware, .read_mac_address = dw210x_read_mac_address, - .adapter = { + .adapter = { { .frontend_attach = dw2102_frontend_attach, .streaming_ctrl = NULL, @@ -752,7 +967,6 @@ static struct dvb_usb_device_properties dw2104_properties = { .caps = DVB_USB_IS_AN_I2C_ADAPTER, .usb_ctrl = DEVICE_SPECIFIC, .firmware = "dvb-usb-dw2104.fw", - .size_of_priv = sizeof(struct dw210x_state), .no_reconnect = 1, .i2c_algo = &dw2104_i2c_algo, @@ -796,12 +1010,57 @@ static struct dvb_usb_device_properties dw2104_properties = { } }; +static struct dvb_usb_device_properties dw3101_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + .usb_ctrl = DEVICE_SPECIFIC, + .firmware = "dvb-usb-dw3101.fw", + .no_reconnect = 1, + + .i2c_algo = &dw3101_i2c_algo, + .rc_key_map = dw210x_rc_keys, + .rc_key_map_size = ARRAY_SIZE(dw210x_rc_keys), + .rc_interval = 150, + .rc_query = dw2102_rc_query, + + .generic_bulk_ctrl_endpoint = 0x81, + /* parameter for the MPEG2-data transfer */ + .num_adapters = 1, + .download_firmware = dw2102_load_firmware, + .read_mac_address = dw210x_read_mac_address, + .adapter = { + { + .frontend_attach = dw3101_frontend_attach, + .streaming_ctrl = NULL, + .tuner_attach = dw3101_tuner_attach, + .stream = { + .type = USB_BULK, + .count = 8, + .endpoint = 0x82, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + } + }, + .num_device_descs = 1, + .devices = { + { "DVBWorld DVB-C 3101 USB2.0", + {&dw2102_table[5], NULL}, + {NULL}, + }, + } +}; + static int dw2102_probe(struct usb_interface *intf, const struct usb_device_id *id) { if (0 == dvb_usb_device_init(intf, &dw2102_properties, THIS_MODULE, NULL, adapter_nr) || 0 == dvb_usb_device_init(intf, &dw2104_properties, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &dw3101_properties, THIS_MODULE, NULL, adapter_nr)) { return 0; } @@ -833,6 +1092,8 @@ module_init(dw2102_module_init); module_exit(dw2102_module_exit); MODULE_AUTHOR("Igor M. Liplianin (c) liplianin@me.by"); -MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104 USB2.0 device"); +MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104," + " DVB-C 3101 USB2.0," + " TeVii S600, S650 USB2.0 devices"); MODULE_VERSION("0.1"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/dw2102.h b/drivers/media/dvb/dvb-usb/dw2102.h index e3370734e95a..5cd0b0eb6ce1 100644 --- a/drivers/media/dvb/dvb-usb/dw2102.h +++ b/drivers/media/dvb/dvb-usb/dw2102.h @@ -5,4 +5,5 @@ #include "dvb-usb.h" #define deb_xfer(args...) dprintk(dvb_usb_dw2102_debug, 0x02, args) +#define deb_rc(args...) dprintk(dvb_usb_dw2102_debug, 0x04, args) #endif diff --git a/drivers/media/dvb/dvb-usb/gp8psk.c b/drivers/media/dvb/dvb-usb/gp8psk.c index 3dd6843864ed..afb444db43ad 100644 --- a/drivers/media/dvb/dvb-usb/gp8psk.c +++ b/drivers/media/dvb/dvb-usb/gp8psk.c @@ -223,7 +223,7 @@ static struct usb_device_id gp8psk_usb_table [] = { { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_1_WARM) }, { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_2) }, { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_1) }, - { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_CW3K) }, +/* { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_CW3K) }, */ { 0 }, }; MODULE_DEVICE_TABLE(usb, gp8psk_usb_table); @@ -254,7 +254,7 @@ static struct dvb_usb_device_properties gp8psk_properties = { .generic_bulk_ctrl_endpoint = 0x01, - .num_device_descs = 4, + .num_device_descs = 3, .devices = { { .name = "Genpix 8PSK-to-USB2 Rev.1 DVB-S receiver", .cold_ids = { &gp8psk_usb_table[0], NULL }, @@ -268,10 +268,6 @@ static struct dvb_usb_device_properties gp8psk_properties = { .cold_ids = { NULL }, .warm_ids = { &gp8psk_usb_table[3], NULL }, }, - { .name = "Genpix SkyWalker-CW3K DVB-S receiver", - .cold_ids = { NULL }, - .warm_ids = { &gp8psk_usb_table[4], NULL }, - }, { NULL }, } }; diff --git a/drivers/media/dvb/firewire/firedtv-1394.c b/drivers/media/dvb/firewire/firedtv-1394.c index 4e207658c5d9..2b6eeeab5b25 100644 --- a/drivers/media/dvb/firewire/firedtv-1394.c +++ b/drivers/media/dvb/firewire/firedtv-1394.c @@ -225,7 +225,7 @@ fail_free: static int node_remove(struct device *dev) { - struct firedtv *fdtv = dev->driver_data; + struct firedtv *fdtv = dev_get_drvdata(dev); fdtv_dvb_unregister(fdtv); @@ -242,7 +242,7 @@ static int node_remove(struct device *dev) static int node_update(struct unit_directory *ud) { - struct firedtv *fdtv = ud->device.driver_data; + struct firedtv *fdtv = dev_get_drvdata(&ud->device); if (fdtv->isochannel >= 0) cmp_establish_pp_connection(fdtv, fdtv->subunit, diff --git a/drivers/media/dvb/firewire/firedtv-dvb.c b/drivers/media/dvb/firewire/firedtv-dvb.c index 9d308dd32a5c..5742fde79d99 100644 --- a/drivers/media/dvb/firewire/firedtv-dvb.c +++ b/drivers/media/dvb/firewire/firedtv-dvb.c @@ -268,7 +268,7 @@ struct firedtv *fdtv_alloc(struct device *dev, if (!fdtv) return NULL; - dev->driver_data = fdtv; + dev_set_drvdata(dev, fdtv); fdtv->device = dev; fdtv->isochannel = -1; fdtv->voltage = 0xff; diff --git a/drivers/media/dvb/firewire/firedtv-rc.c b/drivers/media/dvb/firewire/firedtv-rc.c index 46a6324d7b73..27bca2e283df 100644 --- a/drivers/media/dvb/firewire/firedtv-rc.c +++ b/drivers/media/dvb/firewire/firedtv-rc.c @@ -18,7 +18,7 @@ #include "firedtv.h" /* fixed table with older keycodes, geared towards MythTV */ -const static u16 oldtable[] = { +static const u16 oldtable[] = { /* code from device: 0x4501...0x451f */ @@ -62,7 +62,7 @@ const static u16 oldtable[] = { }; /* user-modifiable table for a remote as sold in 2008 */ -const static u16 keytable[] = { +static const u16 keytable[] = { /* code from device: 0x0300...0x031f */ diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index 23e4cffeba38..be967ac09a39 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -35,6 +35,21 @@ config DVB_STB6100 A Silicon tuner from ST used in conjunction with the STB0899 demodulator. Say Y when you want to support this tuner. +config DVB_STV090x + tristate "STV0900/STV0903(A/B) based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + DVB-S/S2/DSS Multistandard Professional/Broadcast demodulators. + Say Y when you want to support these frontends. + +config DVB_STV6110x + tristate "STV6110/(A) based tuners" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A Silicon tuner that supports DVB-S and DVB-S2 modes + comment "DVB-S (satellite) frontends" depends on DVB_CORE @@ -506,6 +521,13 @@ config DVB_ISL6421 help An SEC control chip. +config DVB_ISL6423 + tristate "ISL6423 SEC controller" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A SEC controller chip from Intersil + config DVB_LGS8GL5 tristate "Silicon Legend LGS-8GL5 demodulator (OFDM)" depends on DVB_CORE && I2C diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index bc2b00abd106..832473c1e512 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -71,4 +71,6 @@ obj-$(CONFIG_DVB_STB6000) += stb6000.o obj-$(CONFIG_DVB_S921) += s921.o obj-$(CONFIG_DVB_STV6110) += stv6110.o obj-$(CONFIG_DVB_STV0900) += stv0900.o - +obj-$(CONFIG_DVB_STV090x) += stv090x.o +obj-$(CONFIG_DVB_STV6110x) += stv6110x.o +obj-$(CONFIG_DVB_ISL6423) += isl6423.o diff --git a/drivers/media/dvb/frontends/af9013.c b/drivers/media/dvb/frontends/af9013.c index b2b50fb4cfd3..136c5863d81b 100644 --- a/drivers/media/dvb/frontends/af9013.c +++ b/drivers/media/dvb/frontends/af9013.c @@ -1455,7 +1455,7 @@ static int af9013_download_firmware(struct af9013_state *state) af9013_ops.info.name); /* request the firmware, this will block and timeout */ - ret = request_firmware(&fw, fw_file, &state->i2c->dev); + ret = request_firmware(&fw, fw_file, state->i2c->dev.parent); if (ret) { err("did not find the firmware file. (%s) " "Please see linux/Documentation/dvb/ for more details" \ diff --git a/drivers/media/dvb/frontends/au8522_dig.c b/drivers/media/dvb/frontends/au8522_dig.c index 35731258bb0a..956b80f4979c 100644 --- a/drivers/media/dvb/frontends/au8522_dig.c +++ b/drivers/media/dvb/frontends/au8522_dig.c @@ -367,11 +367,90 @@ static struct { { 0x8231, 0x13 }, }; -/* QAM Modulation table */ +/* QAM64 Modulation table */ static struct { u16 reg; u16 data; -} QAM_mod_tab[] = { +} QAM64_mod_tab[] = { + { 0x00a3, 0x09 }, + { 0x00a4, 0x00 }, + { 0x0081, 0xc4 }, + { 0x00a5, 0x40 }, + { 0x00aa, 0x77 }, + { 0x00ad, 0x77 }, + { 0x00a6, 0x67 }, + { 0x0262, 0x20 }, + { 0x021c, 0x30 }, + { 0x00b8, 0x3e }, + { 0x00b9, 0xf0 }, + { 0x00ba, 0x01 }, + { 0x00bb, 0x18 }, + { 0x00bc, 0x50 }, + { 0x00bd, 0x00 }, + { 0x00be, 0xea }, + { 0x00bf, 0xef }, + { 0x00c0, 0xfc }, + { 0x00c1, 0xbd }, + { 0x00c2, 0x1f }, + { 0x00c3, 0xfc }, + { 0x00c4, 0xdd }, + { 0x00c5, 0xaf }, + { 0x00c6, 0x00 }, + { 0x00c7, 0x38 }, + { 0x00c8, 0x30 }, + { 0x00c9, 0x05 }, + { 0x00ca, 0x4a }, + { 0x00cb, 0xd0 }, + { 0x00cc, 0x01 }, + { 0x00cd, 0xd9 }, + { 0x00ce, 0x6f }, + { 0x00cf, 0xf9 }, + { 0x00d0, 0x70 }, + { 0x00d1, 0xdf }, + { 0x00d2, 0xf7 }, + { 0x00d3, 0xc2 }, + { 0x00d4, 0xdf }, + { 0x00d5, 0x02 }, + { 0x00d6, 0x9a }, + { 0x00d7, 0xd0 }, + { 0x0250, 0x0d }, + { 0x0251, 0xcd }, + { 0x0252, 0xe0 }, + { 0x0253, 0x05 }, + { 0x0254, 0xa7 }, + { 0x0255, 0xff }, + { 0x0256, 0xed }, + { 0x0257, 0x5b }, + { 0x0258, 0xae }, + { 0x0259, 0xe6 }, + { 0x025a, 0x3d }, + { 0x025b, 0x0f }, + { 0x025c, 0x0d }, + { 0x025d, 0xea }, + { 0x025e, 0xf2 }, + { 0x025f, 0x51 }, + { 0x0260, 0xf5 }, + { 0x0261, 0x06 }, + { 0x021a, 0x00 }, + { 0x0546, 0x40 }, + { 0x0210, 0xc7 }, + { 0x0211, 0xaa }, + { 0x0212, 0xab }, + { 0x0213, 0x02 }, + { 0x0502, 0x00 }, + { 0x0121, 0x04 }, + { 0x0122, 0x04 }, + { 0x052e, 0x10 }, + { 0x00a4, 0xca }, + { 0x00a7, 0x40 }, + { 0x0526, 0x01 }, +}; + +/* QAM256 Modulation table */ +static struct { + u16 reg; + u16 data; +} QAM256_mod_tab[] = { { 0x80a3, 0x09 }, { 0x80a4, 0x00 }, { 0x8081, 0xc4 }, @@ -464,12 +543,19 @@ static int au8522_enable_modulation(struct dvb_frontend *fe, au8522_set_if(fe, state->config->vsb_if); break; case QAM_64: - case QAM_256: - dprintk("%s() QAM 64/256\n", __func__); - for (i = 0; i < ARRAY_SIZE(QAM_mod_tab); i++) + dprintk("%s() QAM 64\n", __func__); + for (i = 0; i < ARRAY_SIZE(QAM64_mod_tab); i++) au8522_writereg(state, - QAM_mod_tab[i].reg, - QAM_mod_tab[i].data); + QAM64_mod_tab[i].reg, + QAM64_mod_tab[i].data); + au8522_set_if(fe, state->config->qam_if); + break; + case QAM_256: + dprintk("%s() QAM 256\n", __func__); + for (i = 0; i < ARRAY_SIZE(QAM256_mod_tab); i++) + au8522_writereg(state, + QAM256_mod_tab[i].reg, + QAM256_mod_tab[i].data); au8522_set_if(fe, state->config->qam_if); break; default: diff --git a/drivers/media/dvb/frontends/cx24116.c b/drivers/media/dvb/frontends/cx24116.c index 9b9f57264cef..2410d8b59b6b 100644 --- a/drivers/media/dvb/frontends/cx24116.c +++ b/drivers/media/dvb/frontends/cx24116.c @@ -492,7 +492,7 @@ static int cx24116_firmware_ondemand(struct dvb_frontend *fe) printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n", __func__, CX24116_DEFAULT_FIRMWARE); ret = request_firmware(&fw, CX24116_DEFAULT_FIRMWARE, - &state->i2c->dev); + state->i2c->dev.parent); printk(KERN_INFO "%s: Waiting for firmware upload(2)...\n", __func__); if (ret) { diff --git a/drivers/media/dvb/frontends/drx397xD.c b/drivers/media/dvb/frontends/drx397xD.c index 172f1f928f02..010075535221 100644 --- a/drivers/media/dvb/frontends/drx397xD.c +++ b/drivers/media/dvb/frontends/drx397xD.c @@ -123,10 +123,10 @@ static int drx_load_fw(struct drx397xD_state *s, enum fw_ix ix) } memset(&fw[ix].data[0], 0, sizeof(fw[0].data)); - if (request_firmware(&fw[ix].file, fw[ix].name, &s->i2c->dev) != 0) { + rc = request_firmware(&fw[ix].file, fw[ix].name, s->i2c->dev.parent); + if (rc != 0) { printk(KERN_ERR "%s: Firmware \"%s\" not available\n", mod_name, fw[ix].name); - rc = -ENOENT; goto exit_err; } diff --git a/drivers/media/dvb/frontends/isl6423.c b/drivers/media/dvb/frontends/isl6423.c new file mode 100644 index 000000000000..dca5bebfeeb5 --- /dev/null +++ b/drivers/media/dvb/frontends/isl6423.c @@ -0,0 +1,308 @@ +/* + Intersil ISL6423 SEC and LNB Power supply controller + + Copyright (C) Manu Abraham + + 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 +#include +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "isl6423.h" + +static unsigned int verbose; +module_param(verbose, int, 0644); +MODULE_PARM_DESC(verbose, "Set Verbosity level"); + +#define FE_ERROR 0 +#define FE_NOTICE 1 +#define FE_INFO 2 +#define FE_DEBUG 3 +#define FE_DEBUGREG 4 + +#define dprintk(__y, __z, format, arg...) do { \ + if (__z) { \ + if ((verbose > FE_ERROR) && (verbose > __y)) \ + printk(KERN_ERR "%s: " format "\n", __func__ , ##arg); \ + else if ((verbose > FE_NOTICE) && (verbose > __y)) \ + printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg); \ + else if ((verbose > FE_INFO) && (verbose > __y)) \ + printk(KERN_INFO "%s: " format "\n", __func__ , ##arg); \ + else if ((verbose > FE_DEBUG) && (verbose > __y)) \ + printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg); \ + } else { \ + if (verbose > __y) \ + printk(format, ##arg); \ + } \ +} while (0) + +struct isl6423_dev { + const struct isl6423_config *config; + struct i2c_adapter *i2c; + + u8 reg_3; + u8 reg_4; + + unsigned int verbose; +}; + +static int isl6423_write(struct isl6423_dev *isl6423, u8 reg) +{ + struct i2c_adapter *i2c = isl6423->i2c; + u8 addr = isl6423->config->addr; + int err = 0; + + struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = ®, .len = 1 }; + + dprintk(FE_DEBUG, 1, "write reg %02X", reg); + err = i2c_transfer(i2c, &msg, 1); + if (err < 0) + goto exit; + return 0; + +exit: + dprintk(FE_ERROR, 1, "I/O error <%d>", err); + return err; +} + +static int isl6423_set_modulation(struct dvb_frontend *fe) +{ + struct isl6423_dev *isl6423 = (struct isl6423_dev *) fe->sec_priv; + const struct isl6423_config *config = isl6423->config; + int err = 0; + u8 reg_2 = 0; + + reg_2 = 0x01 << 5; + + if (config->mod_extern) + reg_2 |= (1 << 3); + else + reg_2 |= (1 << 4); + + err = isl6423_write(isl6423, reg_2); + if (err < 0) + goto exit; + return 0; + +exit: + dprintk(FE_ERROR, 1, "I/O error <%d>", err); + return err; +} + +static int isl6423_voltage_boost(struct dvb_frontend *fe, long arg) +{ + struct isl6423_dev *isl6423 = (struct isl6423_dev *) fe->sec_priv; + u8 reg_3 = isl6423->reg_3; + u8 reg_4 = isl6423->reg_4; + int err = 0; + + if (arg) { + /* EN = 1, VSPEN = 1, VBOT = 1 */ + reg_4 |= (1 << 4); + reg_4 |= 0x1; + reg_3 |= (1 << 3); + } else { + /* EN = 1, VSPEN = 1, VBOT = 0 */ + reg_4 |= (1 << 4); + reg_4 &= ~0x1; + reg_3 |= (1 << 3); + } + err = isl6423_write(isl6423, reg_3); + if (err < 0) + goto exit; + + err = isl6423_write(isl6423, reg_4); + if (err < 0) + goto exit; + + isl6423->reg_3 = reg_3; + isl6423->reg_4 = reg_4; + + return 0; +exit: + dprintk(FE_ERROR, 1, "I/O error <%d>", err); + return err; +} + + +static int isl6423_set_voltage(struct dvb_frontend *fe, + enum fe_sec_voltage voltage) +{ + struct isl6423_dev *isl6423 = (struct isl6423_dev *) fe->sec_priv; + u8 reg_3 = isl6423->reg_3; + u8 reg_4 = isl6423->reg_4; + int err = 0; + + switch (voltage) { + case SEC_VOLTAGE_OFF: + /* EN = 0 */ + reg_4 &= ~(1 << 4); + break; + + case SEC_VOLTAGE_13: + /* EN = 1, VSPEN = 1, VTOP = 0, VBOT = 0 */ + reg_4 |= (1 << 4); + reg_4 &= ~0x3; + reg_3 |= (1 << 3); + break; + + case SEC_VOLTAGE_18: + /* EN = 1, VSPEN = 1, VTOP = 1, VBOT = 0 */ + reg_4 |= (1 << 4); + reg_4 |= 0x2; + reg_4 &= ~0x1; + reg_3 |= (1 << 3); + break; + + default: + break; + } + err = isl6423_write(isl6423, reg_3); + if (err < 0) + goto exit; + + err = isl6423_write(isl6423, reg_4); + if (err < 0) + goto exit; + + isl6423->reg_3 = reg_3; + isl6423->reg_4 = reg_4; + + return 0; +exit: + dprintk(FE_ERROR, 1, "I/O error <%d>", err); + return err; +} + +static int isl6423_set_current(struct dvb_frontend *fe) +{ + struct isl6423_dev *isl6423 = (struct isl6423_dev *) fe->sec_priv; + u8 reg_3 = isl6423->reg_3; + const struct isl6423_config *config = isl6423->config; + int err = 0; + + switch (config->current_max) { + case SEC_CURRENT_275m: + /* 275mA */ + /* ISELH = 0, ISELL = 0 */ + reg_3 &= ~0x3; + break; + + case SEC_CURRENT_515m: + /* 515mA */ + /* ISELH = 0, ISELL = 1 */ + reg_3 &= ~0x2; + reg_3 |= 0x1; + break; + + case SEC_CURRENT_635m: + /* 635mA */ + /* ISELH = 1, ISELL = 0 */ + reg_3 &= ~0x1; + reg_3 |= 0x2; + break; + + case SEC_CURRENT_800m: + /* 800mA */ + /* ISELH = 1, ISELL = 1 */ + reg_3 |= 0x3; + break; + } + + err = isl6423_write(isl6423, reg_3); + if (err < 0) + goto exit; + + switch (config->curlim) { + case SEC_CURRENT_LIM_ON: + /* DCL = 0 */ + reg_3 &= ~0x10; + break; + + case SEC_CURRENT_LIM_OFF: + /* DCL = 1 */ + reg_3 |= 0x10; + break; + } + + err = isl6423_write(isl6423, reg_3); + if (err < 0) + goto exit; + + isl6423->reg_3 = reg_3; + + return 0; +exit: + dprintk(FE_ERROR, 1, "I/O error <%d>", err); + return err; +} + +static void isl6423_release(struct dvb_frontend *fe) +{ + isl6423_set_voltage(fe, SEC_VOLTAGE_OFF); + + kfree(fe->sec_priv); + fe->sec_priv = NULL; +} + +struct dvb_frontend *isl6423_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + const struct isl6423_config *config) +{ + struct isl6423_dev *isl6423; + + isl6423 = kzalloc(sizeof(struct isl6423_dev), GFP_KERNEL); + if (!isl6423) + return NULL; + + isl6423->config = config; + isl6423->i2c = i2c; + fe->sec_priv = isl6423; + + /* SR3H = 0, SR3M = 1, SR3L = 0 */ + isl6423->reg_3 = 0x02 << 5; + /* SR4H = 0, SR4M = 1, SR4L = 1 */ + isl6423->reg_4 = 0x03 << 5; + + if (isl6423_set_current(fe)) + goto exit; + + if (isl6423_set_modulation(fe)) + goto exit; + + fe->ops.release_sec = isl6423_release; + fe->ops.set_voltage = isl6423_set_voltage; + fe->ops.enable_high_lnb_voltage = isl6423_voltage_boost; + isl6423->verbose = verbose; + + return fe; + +exit: + kfree(isl6423); + fe->sec_priv = NULL; + return NULL; +} +EXPORT_SYMBOL(isl6423_attach); + +MODULE_DESCRIPTION("ISL6423 SEC"); +MODULE_AUTHOR("Manu Abraham"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/isl6423.h b/drivers/media/dvb/frontends/isl6423.h new file mode 100644 index 000000000000..e1a37fba01ca --- /dev/null +++ b/drivers/media/dvb/frontends/isl6423.h @@ -0,0 +1,63 @@ +/* + Intersil ISL6423 SEC and LNB Power supply controller + + Copyright (C) Manu Abraham + + 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 __ISL_6423_H +#define __ISL_6423_H + +#include + +enum isl6423_current { + SEC_CURRENT_275m = 0, + SEC_CURRENT_515m, + SEC_CURRENT_635m, + SEC_CURRENT_800m, +}; + +enum isl6423_curlim { + SEC_CURRENT_LIM_ON = 1, + SEC_CURRENT_LIM_OFF +}; + +struct isl6423_config { + enum isl6423_current current_max; + enum isl6423_curlim curlim; + u8 addr; + u8 mod_extern; +}; + +#if defined(CONFIG_DVB_ISL6423) || (defined(CONFIG_DVB_ISL6423_MODULE) && defined(MODULE)) + + +extern struct dvb_frontend *isl6423_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + const struct isl6423_config *config); + +#else +static inline struct dvb_frontend *isl6423_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + const struct isl6423_config *config) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} + +#endif /* CONFIG_DVB_ISL6423 */ + +#endif /* __ISL_6423_H */ diff --git a/drivers/media/dvb/frontends/lgdt3305.c b/drivers/media/dvb/frontends/lgdt3305.c index d92d0557a80b..fde8c59700fb 100644 --- a/drivers/media/dvb/frontends/lgdt3305.c +++ b/drivers/media/dvb/frontends/lgdt3305.c @@ -19,6 +19,7 @@ * */ +#include #include #include "dvb_math.h" #include "lgdt3305.h" @@ -496,27 +497,15 @@ static int lgdt3305_set_if(struct lgdt3305_state *state, nco = if_freq_khz / 10; -#define LGDT3305_64BIT_DIVISION_ENABLED 0 - /* FIXME: 64bit division disabled to avoid linking error: - * WARNING: "__udivdi3" [lgdt3305.ko] undefined! - */ switch (param->u.vsb.modulation) { case VSB_8: -#if LGDT3305_64BIT_DIVISION_ENABLED nco <<= 24; - nco /= 625; -#else - nco *= ((1 << 24) / 625); -#endif + do_div(nco, 625); break; case QAM_64: case QAM_256: -#if LGDT3305_64BIT_DIVISION_ENABLED nco <<= 28; - nco /= 625; -#else - nco *= ((1 << 28) / 625); -#endif + do_div(nco, 625); break; default: return -EINVAL; diff --git a/drivers/media/dvb/frontends/lgs8gxx.c b/drivers/media/dvb/frontends/lgs8gxx.c index f9785dfe735b..fde27645bbed 100644 --- a/drivers/media/dvb/frontends/lgs8gxx.c +++ b/drivers/media/dvb/frontends/lgs8gxx.c @@ -37,14 +37,14 @@ } while (0) static int debug; -static int fake_signal_str; +static int fake_signal_str = 1; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); module_param(fake_signal_str, int, 0644); MODULE_PARM_DESC(fake_signal_str, "fake signal strength for LGS8913." -"Signal strength calculation is slow.(default:off)."); +"Signal strength calculation is slow.(default:on)."); /* LGS8GXX internal helper functions */ @@ -610,7 +610,7 @@ static int lgs8gxx_read_signal_agc(struct lgs8gxx_state *priv, u16 *signal) else cat = 0; - *signal = cat; + *signal = cat * 65535 / 5; return 0; } @@ -630,8 +630,8 @@ static int lgs8913_read_signal_strength(struct lgs8gxx_state *priv, u16 *signal) if (fake_signal_str) { if ((t & 0xC0) == 0xC0) { - dprintk("Fake signal strength as 50\n"); - *signal = 0x32; + dprintk("Fake signal strength\n"); + *signal = 0x7FFF; } else *signal = 0; return 0; diff --git a/drivers/media/dvb/frontends/lnbp21.c b/drivers/media/dvb/frontends/lnbp21.c index 1dcc56f32bff..71f607fe8fc7 100644 --- a/drivers/media/dvb/frontends/lnbp21.c +++ b/drivers/media/dvb/frontends/lnbp21.c @@ -133,7 +133,7 @@ static struct dvb_frontend *lnbx2x_attach(struct dvb_frontend *fe, /* override frontend ops */ fe->ops.set_voltage = lnbp21_set_voltage; fe->ops.enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage; - printk(KERN_INFO "LNBx2x attached on addr=%x", lnbp21->i2c_addr); + printk(KERN_INFO "LNBx2x attached on addr=%x\n", lnbp21->i2c_addr); return fe; } diff --git a/drivers/media/dvb/frontends/mt312.c b/drivers/media/dvb/frontends/mt312.c index 5ac9b15920f8..a621f727935f 100644 --- a/drivers/media/dvb/frontends/mt312.c +++ b/drivers/media/dvb/frontends/mt312.c @@ -77,7 +77,7 @@ static int mt312_read(struct mt312_state *state, const enum mt312_reg_addr reg, ret = i2c_transfer(state->i2c, msg, 2); if (ret != 2) { - printk(KERN_ERR "%s: ret == %d\n", __func__, ret); + printk(KERN_DEBUG "%s: ret == %d\n", __func__, ret); return -EREMOTEIO; } diff --git a/drivers/media/dvb/frontends/nxt200x.c b/drivers/media/dvb/frontends/nxt200x.c index a8429ebfa8a2..eac20650499f 100644 --- a/drivers/media/dvb/frontends/nxt200x.c +++ b/drivers/media/dvb/frontends/nxt200x.c @@ -879,7 +879,8 @@ static int nxt2002_init(struct dvb_frontend* fe) /* request the firmware, this will block until someone uploads it */ printk("nxt2002: Waiting for firmware upload (%s)...\n", NXT2002_DEFAULT_FIRMWARE); - ret = request_firmware(&fw, NXT2002_DEFAULT_FIRMWARE, &state->i2c->dev); + ret = request_firmware(&fw, NXT2002_DEFAULT_FIRMWARE, + state->i2c->dev.parent); printk("nxt2002: Waiting for firmware upload(2)...\n"); if (ret) { printk("nxt2002: No firmware uploaded (timeout or file not found?)\n"); @@ -943,7 +944,8 @@ static int nxt2004_init(struct dvb_frontend* fe) /* request the firmware, this will block until someone uploads it */ printk("nxt2004: Waiting for firmware upload (%s)...\n", NXT2004_DEFAULT_FIRMWARE); - ret = request_firmware(&fw, NXT2004_DEFAULT_FIRMWARE, &state->i2c->dev); + ret = request_firmware(&fw, NXT2004_DEFAULT_FIRMWARE, + state->i2c->dev.parent); printk("nxt2004: Waiting for firmware upload(2)...\n"); if (ret) { printk("nxt2004: No firmware uploaded (timeout or file not found?)\n"); diff --git a/drivers/media/dvb/frontends/or51132.c b/drivers/media/dvb/frontends/or51132.c index 5ed32544de39..8133ea3cddd7 100644 --- a/drivers/media/dvb/frontends/or51132.c +++ b/drivers/media/dvb/frontends/or51132.c @@ -340,7 +340,7 @@ static int or51132_set_parameters(struct dvb_frontend* fe, } printk("or51132: Waiting for firmware upload(%s)...\n", fwname); - ret = request_firmware(&fw, fwname, &state->i2c->dev); + ret = request_firmware(&fw, fwname, state->i2c->dev.parent); if (ret) { printk(KERN_WARNING "or51132: No firmware up" "loaded(timeout or file not found?)\n"); diff --git a/drivers/media/dvb/frontends/stv0900.h b/drivers/media/dvb/frontends/stv0900.h index 8a1332c2031d..bf4e9b633044 100644 --- a/drivers/media/dvb/frontends/stv0900.h +++ b/drivers/media/dvb/frontends/stv0900.h @@ -29,6 +29,11 @@ #include #include "dvb_frontend.h" +struct stv0900_reg { + u16 addr; + u8 val; +}; + struct stv0900_config { u8 demod_address; u32 xtal; @@ -38,7 +43,7 @@ struct stv0900_config { u8 path1_mode; u8 path2_mode; - + struct stv0900_reg *ts_config_regs; u8 tun1_maddress;/* 0, 1, 2, 3 for 0xc0, 0xc2, 0xc4, 0xc6 */ u8 tun2_maddress; u8 tun1_adc;/* 1 for stv6110, 2 for stb6100 */ diff --git a/drivers/media/dvb/frontends/stv0900_core.c b/drivers/media/dvb/frontends/stv0900_core.c index 8499bcf7f251..1da045fbb4ef 100644 --- a/drivers/media/dvb/frontends/stv0900_core.c +++ b/drivers/media/dvb/frontends/stv0900_core.c @@ -149,31 +149,31 @@ void stv0900_write_reg(struct stv0900_internal *i_params, u16 reg_addr, dprintk(KERN_ERR "%s: i2c error %d\n", __func__, ret); } -u8 stv0900_read_reg(struct stv0900_internal *i_params, u16 reg_addr) +u8 stv0900_read_reg(struct stv0900_internal *i_params, u16 reg) { - u8 data[2]; int ret; - struct i2c_msg i2cmsg = { - .addr = i_params->i2c_addr, - .flags = 0, - .len = 2, - .buf = data, + u8 b0[] = { MSB(reg), LSB(reg) }; + u8 buf = 0; + struct i2c_msg msg[] = { + { + .addr = i_params->i2c_addr, + .flags = 0, + .buf = b0, + .len = 2, + }, { + .addr = i_params->i2c_addr, + .flags = I2C_M_RD, + .buf = &buf, + .len = 1, + }, }; - data[0] = MSB(reg_addr); - data[1] = LSB(reg_addr); + ret = i2c_transfer(i_params->i2c_adap, msg, 2); + if (ret != 2) + dprintk(KERN_ERR "%s: i2c error %d, reg[0x%02x]\n", + __func__, ret, reg); - ret = i2c_transfer(i_params->i2c_adap, &i2cmsg, 1); - if (ret != 1) - dprintk(KERN_ERR "%s: i2c error %d\n", __func__, ret); - - i2cmsg.flags = I2C_M_RD; - i2cmsg.len = 1; - ret = i2c_transfer(i_params->i2c_adap, &i2cmsg, 1); - if (ret != 1) - dprintk(KERN_ERR "%s: i2c error %d\n", __func__, ret); - - return data[0]; + return buf; } void extract_mask_pos(u32 label, u8 *mask, u8 *pos) @@ -712,6 +712,44 @@ static s32 stv0900_carr_get_quality(struct dvb_frontend *fe, return c_n; } +static int stv0900_read_ucblocks(struct dvb_frontend *fe, u32 * ucblocks) +{ + struct stv0900_state *state = fe->demodulator_priv; + struct stv0900_internal *i_params = state->internal; + enum fe_stv0900_demod_num demod = state->demod; + u8 err_val1, err_val0; + s32 err_field1, err_field0; + u32 header_err_val = 0; + + *ucblocks = 0x0; + if (stv0900_get_standard(fe, demod) == STV0900_DVBS2_STANDARD) { + /* DVB-S2 delineator errors count */ + + /* retreiving number for errnous headers */ + dmd_reg(err_field0, R0900_P1_BBFCRCKO0, + R0900_P2_BBFCRCKO0); + dmd_reg(err_field1, R0900_P1_BBFCRCKO1, + R0900_P2_BBFCRCKO1); + + err_val1 = stv0900_read_reg(i_params, err_field1); + err_val0 = stv0900_read_reg(i_params, err_field0); + header_err_val = (err_val1<<8) | err_val0; + + /* retreiving number for errnous packets */ + dmd_reg(err_field0, R0900_P1_UPCRCKO0, + R0900_P2_UPCRCKO0); + dmd_reg(err_field1, R0900_P1_UPCRCKO1, + R0900_P2_UPCRCKO1); + + err_val1 = stv0900_read_reg(i_params, err_field1); + err_val0 = stv0900_read_reg(i_params, err_field0); + *ucblocks = (err_val1<<8) | err_val0; + *ucblocks += header_err_val; + } + + return 0; +} + static int stv0900_read_snr(struct dvb_frontend *fe, u16 *snr) { *snr = stv0900_carr_get_quality(fe, @@ -1355,7 +1393,7 @@ static enum fe_stv0900_error stv0900_init_internal(struct dvb_frontend *fe, struct stv0900_state *state = fe->demodulator_priv; enum fe_stv0900_error error = STV0900_NO_ERROR; enum fe_stv0900_error demodError = STV0900_NO_ERROR; - int selosci; + int selosci, i; struct stv0900_inode *temp_int = find_inode(state->i2c_adap, state->config->demod_address); @@ -1402,7 +1440,23 @@ static enum fe_stv0900_error stv0900_init_internal(struct dvb_frontend *fe, stv0900_write_bits(state->internal, F0900_P1_ROLLOFF_CONTROL, p_init->rolloff); stv0900_write_bits(state->internal, F0900_P2_ROLLOFF_CONTROL, p_init->rolloff); - stv0900_set_ts_parallel_serial(state->internal, p_init->path1_ts_clock, p_init->path2_ts_clock); + state->internal->ts_config = p_init->ts_config; + if (state->internal->ts_config == NULL) + stv0900_set_ts_parallel_serial(state->internal, + p_init->path1_ts_clock, + p_init->path2_ts_clock); + else { + for (i = 0; state->internal->ts_config[i].addr != 0xffff; i++) + stv0900_write_reg(state->internal, + state->internal->ts_config[i].addr, + state->internal->ts_config[i].val); + + stv0900_write_bits(state->internal, F0900_P2_RST_HWARE, 1); + stv0900_write_bits(state->internal, F0900_P2_RST_HWARE, 0); + stv0900_write_bits(state->internal, F0900_P1_RST_HWARE, 1); + stv0900_write_bits(state->internal, F0900_P1_RST_HWARE, 0); + } + stv0900_write_bits(state->internal, F0900_P1_TUN_MADDRESS, p_init->tun1_maddress); switch (p_init->tuner1_adc) { case 1: @@ -1882,6 +1936,7 @@ static struct dvb_frontend_ops stv0900_ops = { .read_ber = stv0900_read_ber, .read_signal_strength = stv0900_read_signal_strength, .read_snr = stv0900_read_snr, + .read_ucblocks = stv0900_read_ucblocks, }; struct dvb_frontend *stv0900_attach(const struct stv0900_config *config, @@ -1915,6 +1970,7 @@ struct dvb_frontend *stv0900_attach(const struct stv0900_config *config, init_params.tun1_iq_inversion = STV0900_IQ_NORMAL; init_params.tuner1_adc = config->tun1_adc; init_params.path2_ts_clock = config->path2_mode; + init_params.ts_config = config->ts_config_regs; init_params.tun2_maddress = config->tun2_maddress; init_params.tuner2_adc = config->tun2_adc; init_params.tun2_iq_inversion = STV0900_IQ_SWAPPED; diff --git a/drivers/media/dvb/frontends/stv0900_priv.h b/drivers/media/dvb/frontends/stv0900_priv.h index 762d5af62d7a..5ed7a145c7d3 100644 --- a/drivers/media/dvb/frontends/stv0900_priv.h +++ b/drivers/media/dvb/frontends/stv0900_priv.h @@ -60,8 +60,6 @@ } \ } while (0) -#define dmd_choose(a, b) (demod = STV0900_DEMOD_2 ? b : a)) - static int stvdebug; #define dprintk(args...) \ @@ -273,6 +271,7 @@ struct stv0900_init_params{ /* IQ from the tuner2 to the demod */ enum stv0900_iq_inversion tun2_iq_inversion; + struct stv0900_reg *ts_config; }; struct stv0900_search_params { @@ -365,6 +364,7 @@ struct stv0900_internal{ u8 i2c_addr; u8 clkmode;/* 0 for CLKI, 2 for XTALI */ u8 chip_id; + struct stv0900_reg *ts_config; enum fe_stv0900_error errs; int dmds_used; }; diff --git a/drivers/media/dvb/frontends/stv090x.c b/drivers/media/dvb/frontends/stv090x.c new file mode 100644 index 000000000000..488bdfb34fb3 --- /dev/null +++ b/drivers/media/dvb/frontends/stv090x.c @@ -0,0 +1,4302 @@ +/* + STV0900/0903 Multistandard Broadcast Frontend driver + Copyright (C) Manu Abraham + + Copyright (C) ST Microelectronics + + 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 +#include +#include +#include +#include + +#include +#include "dvb_frontend.h" + +#include "stv6110x.h" /* for demodulator internal modes */ + +#include "stv090x_reg.h" +#include "stv090x.h" +#include "stv090x_priv.h" + +static unsigned int verbose; +module_param(verbose, int, 0644); + +struct mutex demod_lock; + +/* DVBS1 and DSS C/N Lookup table */ +static const struct stv090x_tab stv090x_s1cn_tab[] = { + { 0, 8917 }, /* 0.0dB */ + { 5, 8801 }, /* 0.5dB */ + { 10, 8667 }, /* 1.0dB */ + { 15, 8522 }, /* 1.5dB */ + { 20, 8355 }, /* 2.0dB */ + { 25, 8175 }, /* 2.5dB */ + { 30, 7979 }, /* 3.0dB */ + { 35, 7763 }, /* 3.5dB */ + { 40, 7530 }, /* 4.0dB */ + { 45, 7282 }, /* 4.5dB */ + { 50, 7026 }, /* 5.0dB */ + { 55, 6781 }, /* 5.5dB */ + { 60, 6514 }, /* 6.0dB */ + { 65, 6241 }, /* 6.5dB */ + { 70, 5965 }, /* 7.0dB */ + { 75, 5690 }, /* 7.5dB */ + { 80, 5424 }, /* 8.0dB */ + { 85, 5161 }, /* 8.5dB */ + { 90, 4902 }, /* 9.0dB */ + { 95, 4654 }, /* 9.5dB */ + { 100, 4417 }, /* 10.0dB */ + { 105, 4186 }, /* 10.5dB */ + { 110, 3968 }, /* 11.0dB */ + { 115, 3757 }, /* 11.5dB */ + { 120, 3558 }, /* 12.0dB */ + { 125, 3366 }, /* 12.5dB */ + { 130, 3185 }, /* 13.0dB */ + { 135, 3012 }, /* 13.5dB */ + { 140, 2850 }, /* 14.0dB */ + { 145, 2698 }, /* 14.5dB */ + { 150, 2550 }, /* 15.0dB */ + { 160, 2283 }, /* 16.0dB */ + { 170, 2042 }, /* 17.0dB */ + { 180, 1827 }, /* 18.0dB */ + { 190, 1636 }, /* 19.0dB */ + { 200, 1466 }, /* 20.0dB */ + { 210, 1315 }, /* 21.0dB */ + { 220, 1181 }, /* 22.0dB */ + { 230, 1064 }, /* 23.0dB */ + { 240, 960 }, /* 24.0dB */ + { 250, 869 }, /* 25.0dB */ + { 260, 792 }, /* 26.0dB */ + { 270, 724 }, /* 27.0dB */ + { 280, 665 }, /* 28.0dB */ + { 290, 616 }, /* 29.0dB */ + { 300, 573 }, /* 30.0dB */ + { 310, 537 }, /* 31.0dB */ + { 320, 507 }, /* 32.0dB */ + { 330, 483 }, /* 33.0dB */ + { 400, 398 }, /* 40.0dB */ + { 450, 381 }, /* 45.0dB */ + { 500, 377 } /* 50.0dB */ +}; + +/* DVBS2 C/N Lookup table */ +static const struct stv090x_tab stv090x_s2cn_tab[] = { + { -30, 13348 }, /* -3.0dB */ + { -20, 12640 }, /* -2d.0B */ + { -10, 11883 }, /* -1.0dB */ + { 0, 11101 }, /* -0.0dB */ + { 5, 10718 }, /* 0.5dB */ + { 10, 10339 }, /* 1.0dB */ + { 15, 9947 }, /* 1.5dB */ + { 20, 9552 }, /* 2.0dB */ + { 25, 9183 }, /* 2.5dB */ + { 30, 8799 }, /* 3.0dB */ + { 35, 8422 }, /* 3.5dB */ + { 40, 8062 }, /* 4.0dB */ + { 45, 7707 }, /* 4.5dB */ + { 50, 7353 }, /* 5.0dB */ + { 55, 7025 }, /* 5.5dB */ + { 60, 6684 }, /* 6.0dB */ + { 65, 6331 }, /* 6.5dB */ + { 70, 6036 }, /* 7.0dB */ + { 75, 5727 }, /* 7.5dB */ + { 80, 5437 }, /* 8.0dB */ + { 85, 5164 }, /* 8.5dB */ + { 90, 4902 }, /* 9.0dB */ + { 95, 4653 }, /* 9.5dB */ + { 100, 4408 }, /* 10.0dB */ + { 105, 4187 }, /* 10.5dB */ + { 110, 3961 }, /* 11.0dB */ + { 115, 3751 }, /* 11.5dB */ + { 120, 3558 }, /* 12.0dB */ + { 125, 3368 }, /* 12.5dB */ + { 130, 3191 }, /* 13.0dB */ + { 135, 3017 }, /* 13.5dB */ + { 140, 2862 }, /* 14.0dB */ + { 145, 2710 }, /* 14.5dB */ + { 150, 2565 }, /* 15.0dB */ + { 160, 2300 }, /* 16.0dB */ + { 170, 2058 }, /* 17.0dB */ + { 180, 1849 }, /* 18.0dB */ + { 190, 1663 }, /* 19.0dB */ + { 200, 1495 }, /* 20.0dB */ + { 210, 1349 }, /* 21.0dB */ + { 220, 1222 }, /* 22.0dB */ + { 230, 1110 }, /* 23.0dB */ + { 240, 1011 }, /* 24.0dB */ + { 250, 925 }, /* 25.0dB */ + { 260, 853 }, /* 26.0dB */ + { 270, 789 }, /* 27.0dB */ + { 280, 734 }, /* 28.0dB */ + { 290, 690 }, /* 29.0dB */ + { 300, 650 }, /* 30.0dB */ + { 310, 619 }, /* 31.0dB */ + { 320, 593 }, /* 32.0dB */ + { 330, 571 }, /* 33.0dB */ + { 400, 498 }, /* 40.0dB */ + { 450, 484 }, /* 45.0dB */ + { 500, 481 } /* 50.0dB */ +}; + +/* RF level C/N lookup table */ +static const struct stv090x_tab stv090x_rf_tab[] = { + { -5, 0xcaa1 }, /* -5dBm */ + { -10, 0xc229 }, /* -10dBm */ + { -15, 0xbb08 }, /* -15dBm */ + { -20, 0xb4bc }, /* -20dBm */ + { -25, 0xad5a }, /* -25dBm */ + { -30, 0xa298 }, /* -30dBm */ + { -35, 0x98a8 }, /* -35dBm */ + { -40, 0x8389 }, /* -40dBm */ + { -45, 0x59be }, /* -45dBm */ + { -50, 0x3a14 }, /* -50dBm */ + { -55, 0x2d11 }, /* -55dBm */ + { -60, 0x210d }, /* -60dBm */ + { -65, 0xa14f }, /* -65dBm */ + { -70, 0x07aa } /* -70dBm */ +}; + + +static struct stv090x_reg stv0900_initval[] = { + + { STV090x_OUTCFG, 0x00 }, + { STV090x_MODECFG, 0xff }, + { STV090x_AGCRF1CFG, 0x11 }, + { STV090x_AGCRF2CFG, 0x13 }, + { STV090x_TSGENERAL1X, 0x14 }, + { STV090x_TSTTNR2, 0x21 }, + { STV090x_TSTTNR4, 0x21 }, + { STV090x_P2_DISTXCTL, 0x22 }, + { STV090x_P2_F22TX, 0xc0 }, + { STV090x_P2_F22RX, 0xc0 }, + { STV090x_P2_DISRXCTL, 0x00 }, + { STV090x_P2_DMDCFGMD, 0xF9 }, + { STV090x_P2_DEMOD, 0x08 }, + { STV090x_P2_DMDCFG3, 0xc4 }, + { STV090x_P2_CARFREQ, 0xed }, + { STV090x_P2_LDT, 0xd0 }, + { STV090x_P2_LDT2, 0xb8 }, + { STV090x_P2_TMGCFG, 0xd2 }, + { STV090x_P2_TMGTHRISE, 0x20 }, + { STV090x_P1_TMGCFG, 0xd2 }, + + { STV090x_P2_TMGTHFALL, 0x00 }, + { STV090x_P2_FECSPY, 0x88 }, + { STV090x_P2_FSPYDATA, 0x3a }, + { STV090x_P2_FBERCPT4, 0x00 }, + { STV090x_P2_FSPYBER, 0x10 }, + { STV090x_P2_ERRCTRL1, 0x35 }, + { STV090x_P2_ERRCTRL2, 0xc1 }, + { STV090x_P2_CFRICFG, 0xf8 }, + { STV090x_P2_NOSCFG, 0x1c }, + { STV090x_P2_DMDTOM, 0x20 }, + { STV090x_P2_CORRELMANT, 0x70 }, + { STV090x_P2_CORRELABS, 0x88 }, + { STV090x_P2_AGC2O, 0x5b }, + { STV090x_P2_AGC2REF, 0x38 }, + { STV090x_P2_CARCFG, 0xe4 }, + { STV090x_P2_ACLC, 0x1A }, + { STV090x_P2_BCLC, 0x09 }, + { STV090x_P2_CARHDR, 0x08 }, + { STV090x_P2_KREFTMG, 0xc1 }, + { STV090x_P2_SFRUPRATIO, 0xf0 }, + { STV090x_P2_SFRLOWRATIO, 0x70 }, + { STV090x_P2_SFRSTEP, 0x58 }, + { STV090x_P2_TMGCFG2, 0x01 }, + { STV090x_P2_CAR2CFG, 0x26 }, + { STV090x_P2_BCLC2S2Q, 0x86 }, + { STV090x_P2_BCLC2S28, 0x86 }, + { STV090x_P2_SMAPCOEF7, 0x77 }, + { STV090x_P2_SMAPCOEF6, 0x85 }, + { STV090x_P2_SMAPCOEF5, 0x77 }, + { STV090x_P2_TSCFGL, 0x20 }, + { STV090x_P2_DMDCFG2, 0x3b }, + { STV090x_P2_MODCODLST0, 0xff }, + { STV090x_P2_MODCODLST1, 0xff }, + { STV090x_P2_MODCODLST2, 0xff }, + { STV090x_P2_MODCODLST3, 0xff }, + { STV090x_P2_MODCODLST4, 0xff }, + { STV090x_P2_MODCODLST5, 0xff }, + { STV090x_P2_MODCODLST6, 0xff }, + { STV090x_P2_MODCODLST7, 0xcc }, + { STV090x_P2_MODCODLST8, 0xcc }, + { STV090x_P2_MODCODLST9, 0xcc }, + { STV090x_P2_MODCODLSTA, 0xcc }, + { STV090x_P2_MODCODLSTB, 0xcc }, + { STV090x_P2_MODCODLSTC, 0xcc }, + { STV090x_P2_MODCODLSTD, 0xcc }, + { STV090x_P2_MODCODLSTE, 0xcc }, + { STV090x_P2_MODCODLSTF, 0xcf }, + { STV090x_P1_DISTXCTL, 0x22 }, + { STV090x_P1_F22TX, 0xc0 }, + { STV090x_P1_F22RX, 0xc0 }, + { STV090x_P1_DISRXCTL, 0x00 }, + { STV090x_P1_DMDCFGMD, 0xf9 }, + { STV090x_P1_DEMOD, 0x08 }, + { STV090x_P1_DMDCFG3, 0xc4 }, + { STV090x_P1_DMDTOM, 0x20 }, + { STV090x_P1_CARFREQ, 0xed }, + { STV090x_P1_LDT, 0xd0 }, + { STV090x_P1_LDT2, 0xb8 }, + { STV090x_P1_TMGCFG, 0xd2 }, + { STV090x_P1_TMGTHRISE, 0x20 }, + { STV090x_P1_TMGTHFALL, 0x00 }, + { STV090x_P1_SFRUPRATIO, 0xf0 }, + { STV090x_P1_SFRLOWRATIO, 0x70 }, + { STV090x_P1_TSCFGL, 0x20 }, + { STV090x_P1_FECSPY, 0x88 }, + { STV090x_P1_FSPYDATA, 0x3a }, + { STV090x_P1_FBERCPT4, 0x00 }, + { STV090x_P1_FSPYBER, 0x10 }, + { STV090x_P1_ERRCTRL1, 0x35 }, + { STV090x_P1_ERRCTRL2, 0xc1 }, + { STV090x_P1_CFRICFG, 0xf8 }, + { STV090x_P1_NOSCFG, 0x1c }, + { STV090x_P1_CORRELMANT, 0x70 }, + { STV090x_P1_CORRELABS, 0x88 }, + { STV090x_P1_AGC2O, 0x5b }, + { STV090x_P1_AGC2REF, 0x38 }, + { STV090x_P1_CARCFG, 0xe4 }, + { STV090x_P1_ACLC, 0x1A }, + { STV090x_P1_BCLC, 0x09 }, + { STV090x_P1_CARHDR, 0x08 }, + { STV090x_P1_KREFTMG, 0xc1 }, + { STV090x_P1_SFRSTEP, 0x58 }, + { STV090x_P1_TMGCFG2, 0x01 }, + { STV090x_P1_CAR2CFG, 0x26 }, + { STV090x_P1_BCLC2S2Q, 0x86 }, + { STV090x_P1_BCLC2S28, 0x86 }, + { STV090x_P1_SMAPCOEF7, 0x77 }, + { STV090x_P1_SMAPCOEF6, 0x85 }, + { STV090x_P1_SMAPCOEF5, 0x77 }, + { STV090x_P1_DMDCFG2, 0x3b }, + { STV090x_P1_MODCODLST0, 0xff }, + { STV090x_P1_MODCODLST1, 0xff }, + { STV090x_P1_MODCODLST2, 0xff }, + { STV090x_P1_MODCODLST3, 0xff }, + { STV090x_P1_MODCODLST4, 0xff }, + { STV090x_P1_MODCODLST5, 0xff }, + { STV090x_P1_MODCODLST6, 0xff }, + { STV090x_P1_MODCODLST7, 0xcc }, + { STV090x_P1_MODCODLST8, 0xcc }, + { STV090x_P1_MODCODLST9, 0xcc }, + { STV090x_P1_MODCODLSTA, 0xcc }, + { STV090x_P1_MODCODLSTB, 0xcc }, + { STV090x_P1_MODCODLSTC, 0xcc }, + { STV090x_P1_MODCODLSTD, 0xcc }, + { STV090x_P1_MODCODLSTE, 0xcc }, + { STV090x_P1_MODCODLSTF, 0xcf }, + { STV090x_GENCFG, 0x1d }, + { STV090x_NBITER_NF4, 0x37 }, + { STV090x_NBITER_NF5, 0x29 }, + { STV090x_NBITER_NF6, 0x37 }, + { STV090x_NBITER_NF7, 0x33 }, + { STV090x_NBITER_NF8, 0x31 }, + { STV090x_NBITER_NF9, 0x2f }, + { STV090x_NBITER_NF10, 0x39 }, + { STV090x_NBITER_NF11, 0x3a }, + { STV090x_NBITER_NF12, 0x29 }, + { STV090x_NBITER_NF13, 0x37 }, + { STV090x_NBITER_NF14, 0x33 }, + { STV090x_NBITER_NF15, 0x2f }, + { STV090x_NBITER_NF16, 0x39 }, + { STV090x_NBITER_NF17, 0x3a }, + { STV090x_NBITERNOERR, 0x04 }, + { STV090x_GAINLLR_NF4, 0x0C }, + { STV090x_GAINLLR_NF5, 0x0F }, + { STV090x_GAINLLR_NF6, 0x11 }, + { STV090x_GAINLLR_NF7, 0x14 }, + { STV090x_GAINLLR_NF8, 0x17 }, + { STV090x_GAINLLR_NF9, 0x19 }, + { STV090x_GAINLLR_NF10, 0x20 }, + { STV090x_GAINLLR_NF11, 0x21 }, + { STV090x_GAINLLR_NF12, 0x0D }, + { STV090x_GAINLLR_NF13, 0x0F }, + { STV090x_GAINLLR_NF14, 0x13 }, + { STV090x_GAINLLR_NF15, 0x1A }, + { STV090x_GAINLLR_NF16, 0x1F }, + { STV090x_GAINLLR_NF17, 0x21 }, + { STV090x_RCCFGH, 0x20 }, + { STV090x_P1_FECM, 0x01 }, /* disable DSS modes */ + { STV090x_P2_FECM, 0x01 }, /* disable DSS modes */ + { STV090x_P1_PRVIT, 0x2F }, /* disable PR 6/7 */ + { STV090x_P2_PRVIT, 0x2F }, /* disable PR 6/7 */ +}; + +static struct stv090x_reg stv0903_initval[] = { + { STV090x_OUTCFG, 0x00 }, + { STV090x_AGCRF1CFG, 0x11 }, + { STV090x_STOPCLK1, 0x48 }, + { STV090x_STOPCLK2, 0x14 }, + { STV090x_TSTTNR1, 0x27 }, + { STV090x_TSTTNR2, 0x21 }, + { STV090x_P1_DISTXCTL, 0x22 }, + { STV090x_P1_F22TX, 0xc0 }, + { STV090x_P1_F22RX, 0xc0 }, + { STV090x_P1_DISRXCTL, 0x00 }, + { STV090x_P1_DMDCFGMD, 0xF9 }, + { STV090x_P1_DEMOD, 0x08 }, + { STV090x_P1_DMDCFG3, 0xc4 }, + { STV090x_P1_CARFREQ, 0xed }, + { STV090x_P1_TNRCFG2, 0x82 }, + { STV090x_P1_LDT, 0xd0 }, + { STV090x_P1_LDT2, 0xb8 }, + { STV090x_P1_TMGCFG, 0xd2 }, + { STV090x_P1_TMGTHRISE, 0x20 }, + { STV090x_P1_TMGTHFALL, 0x00 }, + { STV090x_P1_SFRUPRATIO, 0xf0 }, + { STV090x_P1_SFRLOWRATIO, 0x70 }, + { STV090x_P1_TSCFGL, 0x20 }, + { STV090x_P1_FECSPY, 0x88 }, + { STV090x_P1_FSPYDATA, 0x3a }, + { STV090x_P1_FBERCPT4, 0x00 }, + { STV090x_P1_FSPYBER, 0x10 }, + { STV090x_P1_ERRCTRL1, 0x35 }, + { STV090x_P1_ERRCTRL2, 0xc1 }, + { STV090x_P1_CFRICFG, 0xf8 }, + { STV090x_P1_NOSCFG, 0x1c }, + { STV090x_P1_DMDTOM, 0x20 }, + { STV090x_P1_CORRELMANT, 0x70 }, + { STV090x_P1_CORRELABS, 0x88 }, + { STV090x_P1_AGC2O, 0x5b }, + { STV090x_P1_AGC2REF, 0x38 }, + { STV090x_P1_CARCFG, 0xe4 }, + { STV090x_P1_ACLC, 0x1A }, + { STV090x_P1_BCLC, 0x09 }, + { STV090x_P1_CARHDR, 0x08 }, + { STV090x_P1_KREFTMG, 0xc1 }, + { STV090x_P1_SFRSTEP, 0x58 }, + { STV090x_P1_TMGCFG2, 0x01 }, + { STV090x_P1_CAR2CFG, 0x26 }, + { STV090x_P1_BCLC2S2Q, 0x86 }, + { STV090x_P1_BCLC2S28, 0x86 }, + { STV090x_P1_SMAPCOEF7, 0x77 }, + { STV090x_P1_SMAPCOEF6, 0x85 }, + { STV090x_P1_SMAPCOEF5, 0x77 }, + { STV090x_P1_DMDCFG2, 0x3b }, + { STV090x_P1_MODCODLST0, 0xff }, + { STV090x_P1_MODCODLST1, 0xff }, + { STV090x_P1_MODCODLST2, 0xff }, + { STV090x_P1_MODCODLST3, 0xff }, + { STV090x_P1_MODCODLST4, 0xff }, + { STV090x_P1_MODCODLST5, 0xff }, + { STV090x_P1_MODCODLST6, 0xff }, + { STV090x_P1_MODCODLST7, 0xcc }, + { STV090x_P1_MODCODLST8, 0xcc }, + { STV090x_P1_MODCODLST9, 0xcc }, + { STV090x_P1_MODCODLSTA, 0xcc }, + { STV090x_P1_MODCODLSTB, 0xcc }, + { STV090x_P1_MODCODLSTC, 0xcc }, + { STV090x_P1_MODCODLSTD, 0xcc }, + { STV090x_P1_MODCODLSTE, 0xcc }, + { STV090x_P1_MODCODLSTF, 0xcf }, + { STV090x_GENCFG, 0x1c }, + { STV090x_NBITER_NF4, 0x37 }, + { STV090x_NBITER_NF5, 0x29 }, + { STV090x_NBITER_NF6, 0x37 }, + { STV090x_NBITER_NF7, 0x33 }, + { STV090x_NBITER_NF8, 0x31 }, + { STV090x_NBITER_NF9, 0x2f }, + { STV090x_NBITER_NF10, 0x39 }, + { STV090x_NBITER_NF11, 0x3a }, + { STV090x_NBITER_NF12, 0x29 }, + { STV090x_NBITER_NF13, 0x37 }, + { STV090x_NBITER_NF14, 0x33 }, + { STV090x_NBITER_NF15, 0x2f }, + { STV090x_NBITER_NF16, 0x39 }, + { STV090x_NBITER_NF17, 0x3a }, + { STV090x_NBITERNOERR, 0x04 }, + { STV090x_GAINLLR_NF4, 0x0C }, + { STV090x_GAINLLR_NF5, 0x0F }, + { STV090x_GAINLLR_NF6, 0x11 }, + { STV090x_GAINLLR_NF7, 0x14 }, + { STV090x_GAINLLR_NF8, 0x17 }, + { STV090x_GAINLLR_NF9, 0x19 }, + { STV090x_GAINLLR_NF10, 0x20 }, + { STV090x_GAINLLR_NF11, 0x21 }, + { STV090x_GAINLLR_NF12, 0x0D }, + { STV090x_GAINLLR_NF13, 0x0F }, + { STV090x_GAINLLR_NF14, 0x13 }, + { STV090x_GAINLLR_NF15, 0x1A }, + { STV090x_GAINLLR_NF16, 0x1F }, + { STV090x_GAINLLR_NF17, 0x21 }, + { STV090x_RCCFGH, 0x20 }, + { STV090x_P1_FECM, 0x01 }, /*disable the DSS mode */ + { STV090x_P1_PRVIT, 0x2f } /*disable puncture rate 6/7*/ +}; + +static struct stv090x_reg stv0900_cut20_val[] = { + + { STV090x_P2_DMDCFG3, 0xe8 }, + { STV090x_P2_DMDCFG4, 0x10 }, + { STV090x_P2_CARFREQ, 0x38 }, + { STV090x_P2_CARHDR, 0x20 }, + { STV090x_P2_KREFTMG, 0x5a }, + { STV090x_P2_SMAPCOEF7, 0x06 }, + { STV090x_P2_SMAPCOEF6, 0x00 }, + { STV090x_P2_SMAPCOEF5, 0x04 }, + { STV090x_P2_NOSCFG, 0x0c }, + { STV090x_P1_DMDCFG3, 0xe8 }, + { STV090x_P1_DMDCFG4, 0x10 }, + { STV090x_P1_CARFREQ, 0x38 }, + { STV090x_P1_CARHDR, 0x20 }, + { STV090x_P1_KREFTMG, 0x5a }, + { STV090x_P1_SMAPCOEF7, 0x06 }, + { STV090x_P1_SMAPCOEF6, 0x00 }, + { STV090x_P1_SMAPCOEF5, 0x04 }, + { STV090x_P1_NOSCFG, 0x0c }, + { STV090x_GAINLLR_NF4, 0x21 }, + { STV090x_GAINLLR_NF5, 0x21 }, + { STV090x_GAINLLR_NF6, 0x20 }, + { STV090x_GAINLLR_NF7, 0x1F }, + { STV090x_GAINLLR_NF8, 0x1E }, + { STV090x_GAINLLR_NF9, 0x1E }, + { STV090x_GAINLLR_NF10, 0x1D }, + { STV090x_GAINLLR_NF11, 0x1B }, + { STV090x_GAINLLR_NF12, 0x20 }, + { STV090x_GAINLLR_NF13, 0x20 }, + { STV090x_GAINLLR_NF14, 0x20 }, + { STV090x_GAINLLR_NF15, 0x20 }, + { STV090x_GAINLLR_NF16, 0x20 }, + { STV090x_GAINLLR_NF17, 0x21 }, +}; + +static struct stv090x_reg stv0903_cut20_val[] = { + { STV090x_P1_DMDCFG3, 0xe8 }, + { STV090x_P1_DMDCFG4, 0x10 }, + { STV090x_P1_CARFREQ, 0x38 }, + { STV090x_P1_CARHDR, 0x20 }, + { STV090x_P1_KREFTMG, 0x5a }, + { STV090x_P1_SMAPCOEF7, 0x06 }, + { STV090x_P1_SMAPCOEF6, 0x00 }, + { STV090x_P1_SMAPCOEF5, 0x04 }, + { STV090x_P1_NOSCFG, 0x0c }, + { STV090x_GAINLLR_NF4, 0x21 }, + { STV090x_GAINLLR_NF5, 0x21 }, + { STV090x_GAINLLR_NF6, 0x20 }, + { STV090x_GAINLLR_NF7, 0x1F }, + { STV090x_GAINLLR_NF8, 0x1E }, + { STV090x_GAINLLR_NF9, 0x1E }, + { STV090x_GAINLLR_NF10, 0x1D }, + { STV090x_GAINLLR_NF11, 0x1B }, + { STV090x_GAINLLR_NF12, 0x20 }, + { STV090x_GAINLLR_NF13, 0x20 }, + { STV090x_GAINLLR_NF14, 0x20 }, + { STV090x_GAINLLR_NF15, 0x20 }, + { STV090x_GAINLLR_NF16, 0x20 }, + { STV090x_GAINLLR_NF17, 0x21 } +}; + +/* Cut 2.0 Long Frame Tracking CR loop */ +static struct stv090x_long_frame_crloop stv090x_s2_crl_cut20[] = { + /* MODCOD 2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */ + { STV090x_QPSK_12, 0x1f, 0x3f, 0x1e, 0x3f, 0x3d, 0x1f, 0x3d, 0x3e, 0x3d, 0x1e }, + { STV090x_QPSK_35, 0x2f, 0x3f, 0x2e, 0x2f, 0x3d, 0x0f, 0x0e, 0x2e, 0x3d, 0x0e }, + { STV090x_QPSK_23, 0x2f, 0x3f, 0x2e, 0x2f, 0x0e, 0x0f, 0x0e, 0x1e, 0x3d, 0x3d }, + { STV090x_QPSK_34, 0x3f, 0x3f, 0x3e, 0x1f, 0x0e, 0x3e, 0x0e, 0x1e, 0x3d, 0x3d }, + { STV090x_QPSK_45, 0x3f, 0x3f, 0x3e, 0x1f, 0x0e, 0x3e, 0x0e, 0x1e, 0x3d, 0x3d }, + { STV090x_QPSK_56, 0x3f, 0x3f, 0x3e, 0x1f, 0x0e, 0x3e, 0x0e, 0x1e, 0x3d, 0x3d }, + { STV090x_QPSK_89, 0x3f, 0x3f, 0x3e, 0x1f, 0x1e, 0x3e, 0x0e, 0x1e, 0x3d, 0x3d }, + { STV090x_QPSK_910, 0x3f, 0x3f, 0x3e, 0x1f, 0x1e, 0x3e, 0x0e, 0x1e, 0x3d, 0x3d }, + { STV090x_8PSK_35, 0x3c, 0x3e, 0x1c, 0x2e, 0x0c, 0x1e, 0x2b, 0x2d, 0x1b, 0x1d }, + { STV090x_8PSK_23, 0x1d, 0x3e, 0x3c, 0x2e, 0x2c, 0x1e, 0x0c, 0x2d, 0x2b, 0x1d }, + { STV090x_8PSK_34, 0x0e, 0x3e, 0x3d, 0x2e, 0x0d, 0x1e, 0x2c, 0x2d, 0x0c, 0x1d }, + { STV090x_8PSK_56, 0x2e, 0x3e, 0x1e, 0x2e, 0x2d, 0x1e, 0x3c, 0x2d, 0x2c, 0x1d }, + { STV090x_8PSK_89, 0x3e, 0x3e, 0x1e, 0x2e, 0x3d, 0x1e, 0x0d, 0x2d, 0x3c, 0x1d }, + { STV090x_8PSK_910, 0x3e, 0x3e, 0x1e, 0x2e, 0x3d, 0x1e, 0x1d, 0x2d, 0x0d, 0x1d } +}; + +/* Cut 3.0 Long Frame Tracking CR loop */ +static struct stv090x_long_frame_crloop stv090x_s2_crl_cut30[] = { + /* MODCOD 2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */ + { STV090x_QPSK_12, 0x3c, 0x2c, 0x0c, 0x2c, 0x1b, 0x2c, 0x1b, 0x1c, 0x0b, 0x3b }, + { STV090x_QPSK_35, 0x0d, 0x0d, 0x0c, 0x0d, 0x1b, 0x3c, 0x1b, 0x1c, 0x0b, 0x3b }, + { STV090x_QPSK_23, 0x1d, 0x0d, 0x0c, 0x1d, 0x2b, 0x3c, 0x1b, 0x1c, 0x0b, 0x3b }, + { STV090x_QPSK_34, 0x1d, 0x1d, 0x0c, 0x1d, 0x2b, 0x3c, 0x1b, 0x1c, 0x0b, 0x3b }, + { STV090x_QPSK_45, 0x2d, 0x1d, 0x1c, 0x1d, 0x2b, 0x3c, 0x2b, 0x0c, 0x1b, 0x3b }, + { STV090x_QPSK_56, 0x2d, 0x1d, 0x1c, 0x1d, 0x2b, 0x3c, 0x2b, 0x0c, 0x1b, 0x3b }, + { STV090x_QPSK_89, 0x3d, 0x2d, 0x1c, 0x1d, 0x3b, 0x3c, 0x2b, 0x0c, 0x1b, 0x3b }, + { STV090x_QPSK_910, 0x3d, 0x2d, 0x1c, 0x1d, 0x3b, 0x3c, 0x2b, 0x0c, 0x1b, 0x3b }, + { STV090x_8PSK_35, 0x39, 0x29, 0x39, 0x19, 0x19, 0x19, 0x19, 0x19, 0x09, 0x19 }, + { STV090x_8PSK_23, 0x2a, 0x39, 0x1a, 0x0a, 0x39, 0x0a, 0x29, 0x39, 0x29, 0x0a }, + { STV090x_8PSK_34, 0x2b, 0x3a, 0x1b, 0x1b, 0x3a, 0x1b, 0x1a, 0x0b, 0x1a, 0x3a }, + { STV090x_8PSK_56, 0x0c, 0x1b, 0x3b, 0x3b, 0x1b, 0x3b, 0x3a, 0x3b, 0x3a, 0x1b }, + { STV090x_8PSK_89, 0x0d, 0x3c, 0x2c, 0x2c, 0x2b, 0x0c, 0x0b, 0x3b, 0x0b, 0x1b }, + { STV090x_8PSK_910, 0x0d, 0x0d, 0x2c, 0x3c, 0x3b, 0x1c, 0x0b, 0x3b, 0x0b, 0x1b } +}; + +/* Cut 2.0 Long Frame Tracking CR Loop */ +static struct stv090x_long_frame_crloop stv090x_s2_apsk_crl_cut20[] = { + /* MODCOD 2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */ + { STV090x_16APSK_23, 0x0c, 0x0c, 0x0c, 0x0c, 0x1d, 0x0c, 0x3c, 0x0c, 0x2c, 0x0c }, + { STV090x_16APSK_34, 0x0c, 0x0c, 0x0c, 0x0c, 0x0e, 0x0c, 0x2d, 0x0c, 0x1d, 0x0c }, + { STV090x_16APSK_45, 0x0c, 0x0c, 0x0c, 0x0c, 0x1e, 0x0c, 0x3d, 0x0c, 0x2d, 0x0c }, + { STV090x_16APSK_56, 0x0c, 0x0c, 0x0c, 0x0c, 0x1e, 0x0c, 0x3d, 0x0c, 0x2d, 0x0c }, + { STV090x_16APSK_89, 0x0c, 0x0c, 0x0c, 0x0c, 0x2e, 0x0c, 0x0e, 0x0c, 0x3d, 0x0c }, + { STV090x_16APSK_910, 0x0c, 0x0c, 0x0c, 0x0c, 0x2e, 0x0c, 0x0e, 0x0c, 0x3d, 0x0c }, + { STV090x_32APSK_34, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c }, + { STV090x_32APSK_45, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c }, + { STV090x_32APSK_56, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c }, + { STV090x_32APSK_89, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c }, + { STV090x_32APSK_910, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c } +}; + +/* Cut 3.0 Long Frame Tracking CR Loop */ +static struct stv090x_long_frame_crloop stv090x_s2_apsk_crl_cut30[] = { + /* MODCOD 2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */ + { STV090x_16APSK_23, 0x0a, 0x0a, 0x0a, 0x0a, 0x1a, 0x0a, 0x3a, 0x0a, 0x2a, 0x0a }, + { STV090x_16APSK_34, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0a, 0x3b, 0x0a, 0x1b, 0x0a }, + { STV090x_16APSK_45, 0x0a, 0x0a, 0x0a, 0x0a, 0x1b, 0x0a, 0x3b, 0x0a, 0x2b, 0x0a }, + { STV090x_16APSK_56, 0x0a, 0x0a, 0x0a, 0x0a, 0x1b, 0x0a, 0x3b, 0x0a, 0x2b, 0x0a }, + { STV090x_16APSK_89, 0x0a, 0x0a, 0x0a, 0x0a, 0x2b, 0x0a, 0x0c, 0x0a, 0x3b, 0x0a }, + { STV090x_16APSK_910, 0x0a, 0x0a, 0x0a, 0x0a, 0x2b, 0x0a, 0x0c, 0x0a, 0x3b, 0x0a }, + { STV090x_32APSK_34, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a }, + { STV090x_32APSK_45, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a }, + { STV090x_32APSK_56, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a }, + { STV090x_32APSK_89, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a }, + { STV090x_32APSK_910, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a } +}; + +static struct stv090x_long_frame_crloop stv090x_s2_lowqpsk_crl_cut20[] = { + /* MODCOD 2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */ + { STV090x_QPSK_14, 0x0f, 0x3f, 0x0e, 0x3f, 0x2d, 0x2f, 0x2d, 0x1f, 0x3d, 0x3e }, + { STV090x_QPSK_13, 0x0f, 0x3f, 0x0e, 0x3f, 0x2d, 0x2f, 0x3d, 0x0f, 0x3d, 0x2e }, + { STV090x_QPSK_25, 0x1f, 0x3f, 0x1e, 0x3f, 0x3d, 0x1f, 0x3d, 0x3e, 0x3d, 0x2e } +}; + +static struct stv090x_long_frame_crloop stv090x_s2_lowqpsk_crl_cut30[] = { + /* MODCOD 2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */ + { STV090x_QPSK_14, 0x0c, 0x3c, 0x0b, 0x3c, 0x2a, 0x2c, 0x2a, 0x1c, 0x3a, 0x3b }, + { STV090x_QPSK_13, 0x0c, 0x3c, 0x0b, 0x3c, 0x2a, 0x2c, 0x3a, 0x0c, 0x3a, 0x2b }, + { STV090x_QPSK_25, 0x1c, 0x3c, 0x1b, 0x3c, 0x3a, 0x1c, 0x3a, 0x3b, 0x3a, 0x2b } +}; + +/* Cut 2.0 Short Frame Tracking CR Loop */ +static struct stv090x_short_frame_crloop stv090x_s2_short_crl_cut20[] = { + /* MODCOD 2M 5M 10M 20M 30M */ + { STV090x_QPSK, 0x2f, 0x2e, 0x0e, 0x0e, 0x3d }, + { STV090x_8PSK, 0x3e, 0x0e, 0x2d, 0x0d, 0x3c }, + { STV090x_16APSK, 0x1e, 0x1e, 0x1e, 0x3d, 0x2d }, + { STV090x_32APSK, 0x1e, 0x1e, 0x1e, 0x3d, 0x2d } +}; + +/* Cut 3.0 Short Frame Tracking CR Loop */ +static struct stv090x_short_frame_crloop stv090x_s2_short_crl_cut30[] = { + /* MODCOD 2M 5M 10M 20M 30M */ + { STV090x_QPSK, 0x2C, 0x2B, 0x0B, 0x0B, 0x3A }, + { STV090x_8PSK, 0x3B, 0x0B, 0x2A, 0x0A, 0x39 }, + { STV090x_16APSK, 0x1B, 0x1B, 0x1B, 0x3A, 0x2A }, + { STV090x_32APSK, 0x1B, 0x1B, 0x1B, 0x3A, 0x2A } +}; + +static inline s32 comp2(s32 __x, s32 __width) +{ + if (__width == 32) + return __x; + else + return (__x >= (1 << (__width - 1))) ? (__x - (1 << __width)) : __x; +} + +static int stv090x_read_reg(struct stv090x_state *state, unsigned int reg) +{ + const struct stv090x_config *config = state->config; + int ret; + + u8 b0[] = { reg >> 8, reg & 0xff }; + u8 buf; + + struct i2c_msg msg[] = { + { .addr = config->address, .flags = 0, .buf = b0, .len = 2 }, + { .addr = config->address, .flags = I2C_M_RD, .buf = &buf, .len = 1 } + }; + + ret = i2c_transfer(state->i2c, msg, 2); + if (ret != 2) { + if (ret != -ERESTARTSYS) + dprintk(FE_ERROR, 1, + "Read error, Reg=[0x%02x], Status=%d", + reg, ret); + + return ret < 0 ? ret : -EREMOTEIO; + } + if (unlikely(*state->verbose >= FE_DEBUGREG)) + dprintk(FE_ERROR, 1, "Reg=[0x%02x], data=%02x", + reg, buf); + + return (unsigned int) buf; +} + +static int stv090x_write_regs(struct stv090x_state *state, unsigned int reg, u8 *data, u32 count) +{ + const struct stv090x_config *config = state->config; + int ret; + u8 buf[2 + count]; + struct i2c_msg i2c_msg = { .addr = config->address, .flags = 0, .buf = buf, .len = 2 + count }; + + buf[0] = reg >> 8; + buf[1] = reg & 0xff; + memcpy(&buf[2], data, count); + + if (unlikely(*state->verbose >= FE_DEBUGREG)) { + int i; + + printk(KERN_DEBUG "%s [0x%04x]:", __func__, reg); + for (i = 0; i < count; i++) + printk(" %02x", data[i]); + printk("\n"); + } + + ret = i2c_transfer(state->i2c, &i2c_msg, 1); + if (ret != 1) { + if (ret != -ERESTARTSYS) + dprintk(FE_ERROR, 1, "Reg=[0x%04x], Data=[0x%02x ...], Count=%u, Status=%d", + reg, data[0], count, ret); + return ret < 0 ? ret : -EREMOTEIO; + } + + return 0; +} + +static int stv090x_write_reg(struct stv090x_state *state, unsigned int reg, u8 data) +{ + return stv090x_write_regs(state, reg, &data, 1); +} + +static int stv090x_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + struct stv090x_state *state = fe->demodulator_priv; + u32 reg; + + reg = STV090x_READ_DEMOD(state, I2CRPT); + if (enable) { + dprintk(FE_DEBUG, 1, "Enable Gate"); + STV090x_SETFIELD_Px(reg, I2CT_ON_FIELD, 1); + if (STV090x_WRITE_DEMOD(state, I2CRPT, reg) < 0) + goto err; + + } else { + dprintk(FE_DEBUG, 1, "Disable Gate"); + STV090x_SETFIELD_Px(reg, I2CT_ON_FIELD, 0); + if ((STV090x_WRITE_DEMOD(state, I2CRPT, reg)) < 0) + goto err; + } + return 0; +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static void stv090x_get_lock_tmg(struct stv090x_state *state) +{ + switch (state->algo) { + case STV090x_BLIND_SEARCH: + dprintk(FE_DEBUG, 1, "Blind Search"); + if (state->srate <= 1500000) { /*10Msps< SR <=15Msps*/ + state->DemodTimeout = 1500; + state->FecTimeout = 400; + } else if (state->srate <= 5000000) { /*10Msps< SR <=15Msps*/ + state->DemodTimeout = 1000; + state->FecTimeout = 300; + } else { /*SR >20Msps*/ + state->DemodTimeout = 700; + state->FecTimeout = 100; + } + break; + + case STV090x_COLD_SEARCH: + case STV090x_WARM_SEARCH: + default: + dprintk(FE_DEBUG, 1, "Normal Search"); + if (state->srate <= 1000000) { /*SR <=1Msps*/ + state->DemodTimeout = 4500; + state->FecTimeout = 1700; + } else if (state->srate <= 2000000) { /*1Msps < SR <= 2Msps */ + state->DemodTimeout = 2500; + state->FecTimeout = 1100; + } else if (state->srate <= 5000000) { /*2Msps < SR <= 5Msps */ + state->DemodTimeout = 1000; + state->FecTimeout = 550; + } else if (state->srate <= 10000000) { /*5Msps < SR <= 10Msps */ + state->DemodTimeout = 700; + state->FecTimeout = 250; + } else if (state->srate <= 20000000) { /*10Msps < SR <= 20Msps */ + state->DemodTimeout = 400; + state->FecTimeout = 130; + } else { /*SR >20Msps*/ + state->DemodTimeout = 300; + state->FecTimeout = 100; + } + break; + } + + if (state->algo == STV090x_WARM_SEARCH) + state->DemodTimeout /= 2; +} + +static int stv090x_set_srate(struct stv090x_state *state, u32 srate) +{ + u32 sym; + + if (srate > 60000000) { + sym = (srate << 4); /* SR * 2^16 / master_clk */ + sym /= (state->mclk >> 12); + } else if (srate > 6000000) { + sym = (srate << 6); + sym /= (state->mclk >> 10); + } else { + sym = (srate << 9); + sym /= (state->mclk >> 7); + } + + if (STV090x_WRITE_DEMOD(state, SFRINIT1, (sym >> 8) & 0x7f) < 0) /* MSB */ + goto err; + if (STV090x_WRITE_DEMOD(state, SFRINIT0, (sym & 0xff)) < 0) /* LSB */ + goto err; + + return 0; +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static int stv090x_set_max_srate(struct stv090x_state *state, u32 clk, u32 srate) +{ + u32 sym; + + srate = 105 * (srate / 100); + if (srate > 60000000) { + sym = (srate << 4); /* SR * 2^16 / master_clk */ + sym /= (state->mclk >> 12); + } else if (srate > 6000000) { + sym = (srate << 6); + sym /= (state->mclk >> 10); + } else { + sym = (srate << 9); + sym /= (state->mclk >> 7); + } + + if (sym < 0x7fff) { + if (STV090x_WRITE_DEMOD(state, SFRUP1, (sym >> 8) & 0x7f) < 0) /* MSB */ + goto err; + if (STV090x_WRITE_DEMOD(state, SFRUP0, sym & 0xff) < 0) /* LSB */ + goto err; + } else { + if (STV090x_WRITE_DEMOD(state, SFRUP1, 0x7f) < 0) /* MSB */ + goto err; + if (STV090x_WRITE_DEMOD(state, SFRUP0, 0xff) < 0) /* LSB */ + goto err; + } + + return 0; +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static int stv090x_set_min_srate(struct stv090x_state *state, u32 clk, u32 srate) +{ + u32 sym; + + srate = 95 * (srate / 100); + if (srate > 60000000) { + sym = (srate << 4); /* SR * 2^16 / master_clk */ + sym /= (state->mclk >> 12); + } else if (srate > 6000000) { + sym = (srate << 6); + sym /= (state->mclk >> 10); + } else { + sym = (srate << 9); + sym /= (state->mclk >> 7); + } + + if (STV090x_WRITE_DEMOD(state, SFRLOW1, ((sym >> 8) & 0xff)) < 0) /* MSB */ + goto err; + if (STV090x_WRITE_DEMOD(state, SFRLOW0, (sym & 0xff)) < 0) /* LSB */ + goto err; + return 0; +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static u32 stv090x_car_width(u32 srate, enum stv090x_rolloff rolloff) +{ + u32 ro; + + switch (rolloff) { + case STV090x_RO_20: + ro = 20; + break; + case STV090x_RO_25: + ro = 25; + break; + case STV090x_RO_35: + default: + ro = 35; + break; + } + + return srate + (srate * ro) / 100; +} + +static int stv090x_set_vit_thacq(struct stv090x_state *state) +{ + if (STV090x_WRITE_DEMOD(state, VTH12, 0x96) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, VTH23, 0x64) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, VTH34, 0x36) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, VTH56, 0x23) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, VTH67, 0x1e) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, VTH78, 0x19) < 0) + goto err; + return 0; +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static int stv090x_set_vit_thtracq(struct stv090x_state *state) +{ + if (STV090x_WRITE_DEMOD(state, VTH12, 0xd0) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, VTH23, 0x7d) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, VTH34, 0x53) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, VTH56, 0x2f) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, VTH67, 0x24) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, VTH78, 0x1f) < 0) + goto err; + return 0; +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static int stv090x_set_viterbi(struct stv090x_state *state) +{ + switch (state->search_mode) { + case STV090x_SEARCH_AUTO: + if (STV090x_WRITE_DEMOD(state, FECM, 0x10) < 0) /* DVB-S and DVB-S2 */ + goto err; + if (STV090x_WRITE_DEMOD(state, PRVIT, 0x3f) < 0) /* all puncture rate */ + goto err; + break; + case STV090x_SEARCH_DVBS1: + if (STV090x_WRITE_DEMOD(state, FECM, 0x00) < 0) /* disable DSS */ + goto err; + switch (state->fec) { + case STV090x_PR12: + if (STV090x_WRITE_DEMOD(state, PRVIT, 0x01) < 0) + goto err; + break; + + case STV090x_PR23: + if (STV090x_WRITE_DEMOD(state, PRVIT, 0x02) < 0) + goto err; + break; + + case STV090x_PR34: + if (STV090x_WRITE_DEMOD(state, PRVIT, 0x04) < 0) + goto err; + break; + + case STV090x_PR56: + if (STV090x_WRITE_DEMOD(state, PRVIT, 0x08) < 0) + goto err; + break; + + case STV090x_PR78: + if (STV090x_WRITE_DEMOD(state, PRVIT, 0x20) < 0) + goto err; + break; + + default: + if (STV090x_WRITE_DEMOD(state, PRVIT, 0x2f) < 0) /* all */ + goto err; + break; + } + break; + case STV090x_SEARCH_DSS: + if (STV090x_WRITE_DEMOD(state, FECM, 0x80) < 0) + goto err; + switch (state->fec) { + case STV090x_PR12: + if (STV090x_WRITE_DEMOD(state, PRVIT, 0x01) < 0) + goto err; + break; + + case STV090x_PR23: + if (STV090x_WRITE_DEMOD(state, PRVIT, 0x02) < 0) + goto err; + break; + + case STV090x_PR67: + if (STV090x_WRITE_DEMOD(state, PRVIT, 0x10) < 0) + goto err; + break; + + default: + if (STV090x_WRITE_DEMOD(state, PRVIT, 0x13) < 0) /* 1/2, 2/3, 6/7 */ + goto err; + break; + } + break; + default: + break; + } + return 0; +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static int stv090x_stop_modcod(struct stv090x_state *state) +{ + if (STV090x_WRITE_DEMOD(state, MODCODLST0, 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST1, 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST2, 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST3, 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST4, 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST5, 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST6, 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST7, 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST8, 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST9, 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLSTA, 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLSTB, 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLSTC, 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLSTD, 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLSTE, 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLSTF, 0xff) < 0) + goto err; + return 0; +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static int stv090x_activate_modcod(struct stv090x_state *state) +{ + if (STV090x_WRITE_DEMOD(state, MODCODLST0, 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST1, 0xfc) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST2, 0xcc) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST3, 0xcc) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST4, 0xcc) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST5, 0xcc) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST6, 0xcc) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST7, 0xcc) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST8, 0xcc) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST9, 0xcc) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLSTA, 0xcc) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLSTB, 0xcc) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLSTC, 0xcc) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLSTD, 0xcc) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLSTE, 0xcc) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLSTF, 0xcf) < 0) + goto err; + + return 0; +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static int stv090x_activate_modcod_single(struct stv090x_state *state) +{ + + if (STV090x_WRITE_DEMOD(state, MODCODLST0, 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST1, 0xf0) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST2, 0x00) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST3, 0x00) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST4, 0x00) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST5, 0x00) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST6, 0x00) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST7, 0x00) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST8, 0x00) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST9, 0x00) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLSTA, 0x00) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLSTB, 0x00) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLSTC, 0x00) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLSTD, 0x00) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLSTE, 0x00) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLSTF, 0x0f) < 0) + goto err; + + return 0; + +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static int stv090x_vitclk_ctl(struct stv090x_state *state, int enable) +{ + u32 reg; + + switch (state->demod) { + case STV090x_DEMODULATOR_0: + mutex_lock(&demod_lock); + reg = stv090x_read_reg(state, STV090x_STOPCLK2); + STV090x_SETFIELD(reg, STOP_CLKVIT1_FIELD, enable); + if (stv090x_write_reg(state, STV090x_STOPCLK2, reg) < 0) + goto err; + mutex_unlock(&demod_lock); + break; + + case STV090x_DEMODULATOR_1: + mutex_lock(&demod_lock); + reg = stv090x_read_reg(state, STV090x_STOPCLK2); + STV090x_SETFIELD(reg, STOP_CLKVIT2_FIELD, enable); + if (stv090x_write_reg(state, STV090x_STOPCLK2, reg) < 0) + goto err; + mutex_unlock(&demod_lock); + break; + + default: + dprintk(FE_ERROR, 1, "Wrong demodulator!"); + break; + } + return 0; +err: + mutex_unlock(&demod_lock); + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static int stv090x_dvbs_track_crl(struct stv090x_state *state) +{ + if (state->dev_ver >= 0x30) { + /* Set ACLC BCLC optimised value vs SR */ + if (state->srate >= 15000000) { + if (STV090x_WRITE_DEMOD(state, ACLC, 0x2b) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, BCLC, 0x1a) < 0) + goto err; + } else if ((state->srate >= 7000000) && (15000000 > state->srate)) { + if (STV090x_WRITE_DEMOD(state, ACLC, 0x0c) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, BCLC, 0x1b) < 0) + goto err; + } else if (state->srate < 7000000) { + if (STV090x_WRITE_DEMOD(state, ACLC, 0x2c) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, BCLC, 0x1c) < 0) + goto err; + } + + } else { + /* Cut 2.0 */ + if (STV090x_WRITE_DEMOD(state, ACLC, 0x1a) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, BCLC, 0x09) < 0) + goto err; + } + return 0; +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static int stv090x_delivery_search(struct stv090x_state *state) +{ + u32 reg; + + switch (state->search_mode) { + case STV090x_SEARCH_DVBS1: + case STV090x_SEARCH_DSS: + reg = STV090x_READ_DEMOD(state, DMDCFGMD); + STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 1); + STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 0); + if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0) + goto err; + + /* Activate Viterbi decoder in legacy search, + * do not use FRESVIT1, might impact VITERBI2 + */ + if (stv090x_vitclk_ctl(state, 0) < 0) + goto err; + + if (stv090x_dvbs_track_crl(state) < 0) + goto err; + + if (STV090x_WRITE_DEMOD(state, CAR2CFG, 0x22) < 0) /* disable DVB-S2 */ + goto err; + + if (stv090x_set_vit_thacq(state) < 0) + goto err; + if (stv090x_set_viterbi(state) < 0) + goto err; + break; + + case STV090x_SEARCH_DVBS2: + reg = STV090x_READ_DEMOD(state, DMDCFGMD); + STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 0); + STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 0); + if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0) + goto err; + STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 1); + STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 1); + if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0) + goto err; + + if (stv090x_vitclk_ctl(state, 1) < 0) + goto err; + + if (STV090x_WRITE_DEMOD(state, ACLC, 0x1a) < 0) /* stop DVB-S CR loop */ + goto err; + if (STV090x_WRITE_DEMOD(state, BCLC, 0x09) < 0) + goto err; + + if (state->dev_ver <= 0x20) { + /* enable S2 carrier loop */ + if (STV090x_WRITE_DEMOD(state, CAR2CFG, 0x26) < 0) + goto err; + } else { + /* > Cut 3: Stop carrier 3 */ + if (STV090x_WRITE_DEMOD(state, CAR2CFG, 0x66) < 0) + goto err; + } + + if (state->demod_mode != STV090x_SINGLE) { + /* Cut 2: enable link during search */ + if (stv090x_activate_modcod(state) < 0) + goto err; + } else { + /* Single demodulator + * Authorize SHORT and LONG frames, + * QPSK, 8PSK, 16APSK and 32APSK + */ + if (stv090x_activate_modcod_single(state) < 0) + goto err; + } + + break; + + case STV090x_SEARCH_AUTO: + default: + /* enable DVB-S2 and DVB-S2 in Auto MODE */ + reg = STV090x_READ_DEMOD(state, DMDCFGMD); + STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 1); + STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 1); + if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0) + goto err; + + if (stv090x_vitclk_ctl(state, 0) < 0) + goto err; + + if (stv090x_dvbs_track_crl(state) < 0) + goto err; + + if (state->dev_ver <= 0x20) { + /* enable S2 carrier loop */ + if (STV090x_WRITE_DEMOD(state, CAR2CFG, 0x26) < 0) + goto err; + } else { + /* > Cut 3: Stop carrier 3 */ + if (STV090x_WRITE_DEMOD(state, CAR2CFG, 0x66) < 0) + goto err; + } + + if (state->demod_mode != STV090x_SINGLE) { + /* Cut 2: enable link during search */ + if (stv090x_activate_modcod(state) < 0) + goto err; + } else { + /* Single demodulator + * Authorize SHORT and LONG frames, + * QPSK, 8PSK, 16APSK and 32APSK + */ + if (stv090x_activate_modcod_single(state) < 0) + goto err; + } + + if (state->srate >= 2000000) { + /* Srate >= 2MSPS, Viterbi threshold to acquire */ + if (stv090x_set_vit_thacq(state) < 0) + goto err; + } else { + /* Srate < 2MSPS, Reset Viterbi thresholdto track + * and then re-acquire + */ + if (stv090x_set_vit_thtracq(state) < 0) + goto err; + } + + if (stv090x_set_viterbi(state) < 0) + goto err; + break; + } + return 0; +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static int stv090x_start_search(struct stv090x_state *state) +{ + u32 reg, freq_abs; + s16 freq; + + /* Reset demodulator */ + reg = STV090x_READ_DEMOD(state, DMDISTATE); + STV090x_SETFIELD_Px(reg, I2C_DEMOD_MODE_FIELD, 0x1f); + if (STV090x_WRITE_DEMOD(state, DMDISTATE, reg) < 0) + goto err; + + if (state->dev_ver <= 0x20) { + if (state->srate <= 5000000) { + if (STV090x_WRITE_DEMOD(state, CARCFG, 0x44) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, CFRUP1, 0x0f) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, CFRUP1, 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, CFRLOW1, 0xf0) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, CFRLOW0, 0x00) < 0) + goto err; + + /*enlarge the timing bandwith for Low SR*/ + if (STV090x_WRITE_DEMOD(state, RTCS2, 0x68) < 0) + goto err; + } else { + /* If the symbol rate is >5 Msps + Set The carrier search up and low to auto mode */ + if (STV090x_WRITE_DEMOD(state, CARCFG, 0xc4) < 0) + goto err; + /*reduce the timing bandwith for high SR*/ + if (STV090x_WRITE_DEMOD(state, RTCS2, 0x44) < 0) + goto err; + } + } else { + /* >= Cut 3 */ + if (state->srate <= 5000000) { + /* enlarge the timing bandwith for Low SR */ + STV090x_WRITE_DEMOD(state, RTCS2, 0x68); + } else { + /* reduce timing bandwith for high SR */ + STV090x_WRITE_DEMOD(state, RTCS2, 0x44); + } + + /* Set CFR min and max to manual mode */ + STV090x_WRITE_DEMOD(state, CARCFG, 0x46); + + if (state->algo == STV090x_WARM_SEARCH) { + /* WARM Start + * CFR min = -1MHz, + * CFR max = +1MHz + */ + freq_abs = 1000 << 16; + freq_abs /= (state->mclk / 1000); + freq = (s16) freq_abs; + } else { + /* COLD Start + * CFR min =- (SearchRange / 2 + 600KHz) + * CFR max = +(SearchRange / 2 + 600KHz) + * (600KHz for the tuner step size) + */ + freq_abs = (state->search_range / 2000) + 600; + freq_abs = freq_abs << 16; + freq_abs /= (state->mclk / 1000); + freq = (s16) freq_abs; + } + + if (STV090x_WRITE_DEMOD(state, CFRUP1, MSB(freq)) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, CFRUP1, LSB(freq)) < 0) + goto err; + + freq *= -1; + + if (STV090x_WRITE_DEMOD(state, CFRLOW1, MSB(freq)) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, CFRLOW0, LSB(freq)) < 0) + goto err; + + } + + if (STV090x_WRITE_DEMOD(state, CFRINIT1, 0) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, CFRINIT0, 0) < 0) + goto err; + + if (state->dev_ver >= 0x20) { + if (STV090x_WRITE_DEMOD(state, EQUALCFG, 0x41) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, FFECFG, 0x41) < 0) + goto err; + + if ((state->search_mode == STV090x_DVBS1) || + (state->search_mode == STV090x_DSS) || + (state->search_mode == STV090x_SEARCH_AUTO)) { + + if (STV090x_WRITE_DEMOD(state, VITSCALE, 0x82) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, VAVSRVIT, 0x00) < 0) + goto err; + } + } + + if (STV090x_WRITE_DEMOD(state, SFRSTEP, 0x00) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, TMGTHRISE, 0xe0) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, TMGTHFALL, 0xc0) < 0) + goto err; + + reg = STV090x_READ_DEMOD(state, DMDCFGMD); + STV090x_SETFIELD_Px(reg, SCAN_ENABLE_FIELD, 0); + STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 0); + if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0) + goto err; + reg = STV090x_READ_DEMOD(state, DMDCFG2); + STV090x_SETFIELD_Px(reg, S1S2_SEQUENTIAL_FIELD, 0x0); + if (STV090x_WRITE_DEMOD(state, DMDCFG2, reg) < 0) + goto err; + + if (state->dev_ver >= 0x20) { + /*Frequency offset detector setting*/ + if (state->srate < 2000000) { + if (state->dev_ver <= 0x20) { + /* Cut 2 */ + if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x39) < 0) + goto err; + } else { + /* Cut 2 */ + if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x89) < 0) + goto err; + } + if (STV090x_WRITE_DEMOD(state, CARHDR, 0x40) < 0) + goto err; + } + + if (state->srate < 10000000) { + if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x4c) < 0) + goto err; + } else { + if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x4b) < 0) + goto err; + } + } else { + if (state->srate < 10000000) { + if (STV090x_WRITE_DEMOD(state, CARFREQ, 0xef) < 0) + goto err; + } else { + if (STV090x_WRITE_DEMOD(state, CARFREQ, 0xed) < 0) + goto err; + } + } + + switch (state->algo) { + case STV090x_WARM_SEARCH: + /* The symbol rate and the exact + * carrier Frequency are known + */ + if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x18) < 0) + goto err; + break; + + case STV090x_COLD_SEARCH: + /* The symbol rate is known */ + if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x15) < 0) + goto err; + break; + + default: + break; + } + return 0; +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static int stv090x_get_agc2_min_level(struct stv090x_state *state) +{ + u32 agc2_min = 0, agc2 = 0, freq_init, freq_step, reg; + s32 i, j, steps, dir; + + if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x38) < 0) + goto err; + reg = STV090x_READ_DEMOD(state, DMDCFGMD); + STV090x_SETFIELD_Px(reg, SCAN_ENABLE_FIELD, 1); + STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 1); + if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0) + goto err; + + if (STV090x_WRITE_DEMOD(state, SFRUP1, 0x83) < 0) /* SR = 65 Msps Max */ + goto err; + if (STV090x_WRITE_DEMOD(state, SFRUP0, 0xc0) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, SFRLOW1, 0x82) < 0) /* SR= 400 ksps Min */ + goto err; + if (STV090x_WRITE_DEMOD(state, SFRLOW0, 0xa0) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, DMDTOM, 0x00) < 0) /* stop acq @ coarse carrier state */ + goto err; + if (stv090x_set_srate(state, 1000000) < 0) + goto err; + + steps = -1 + state->search_range / 1000000; + steps /= 2; + steps = (2 * steps) + 1; + if (steps < 0) + steps = 1; + + dir = 1; + freq_step = (1000000 * 256) / (state->mclk / 256); + freq_init = 0; + + for (i = 0; i < steps; i++) { + if (dir > 0) + freq_init = freq_init + (freq_step * i); + else + freq_init = freq_init - (freq_step * i); + + dir = -1; + + if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x5c) < 0) /* Demod RESET */ + goto err; + if (STV090x_WRITE_DEMOD(state, CFRINIT1, (freq_init >> 8) & 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, CFRINIT0, freq_init & 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x58) < 0) /* Demod RESET */ + goto err; + msleep(10); + for (j = 0; j < 10; j++) { + agc2 += STV090x_READ_DEMOD(state, AGC2I1) << 8; + agc2 |= STV090x_READ_DEMOD(state, AGC2I0); + } + agc2 /= 10; + agc2_min = 0xffff; + if (agc2 < 0xffff) + agc2_min = agc2; + } + + return agc2_min; +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static u32 stv090x_get_srate(struct stv090x_state *state, u32 clk) +{ + u8 r3, r2, r1, r0; + s32 srate, int_1, int_2, tmp_1, tmp_2; + + r3 = STV090x_READ_DEMOD(state, SFR3); + r2 = STV090x_READ_DEMOD(state, SFR2); + r1 = STV090x_READ_DEMOD(state, SFR1); + r0 = STV090x_READ_DEMOD(state, SFR0); + + srate = ((r3 << 24) | (r2 << 16) | (r1 << 8) | r0); + + int_1 = clk >> 16; + int_2 = srate >> 16; + + tmp_1 = clk % 0x10000; + tmp_2 = srate % 0x10000; + + srate = (int_1 * int_2) + + ((int_1 * tmp_2) >> 16) + + ((int_2 * tmp_1) >> 16); + + return srate; +} + +static u32 stv090x_srate_srch_coarse(struct stv090x_state *state) +{ + struct dvb_frontend *fe = &state->frontend; + + int tmg_lock = 0, i; + s32 tmg_cpt = 0, dir = 1, steps, cur_step = 0, freq; + u32 srate_coarse = 0, agc2 = 0, car_step = 1200, reg; + + reg = STV090x_READ_DEMOD(state, DMDISTATE); + STV090x_SETFIELD_Px(reg, I2C_DEMOD_MODE_FIELD, 0x1f); /* Demod RESET */ + if (STV090x_WRITE_DEMOD(state, DMDISTATE, reg) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, TMGCFG, 0x12) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, TMGTHRISE, 0xf0) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, TMGTHFALL, 0xe0) < 0) + goto err; + reg = STV090x_READ_DEMOD(state, DMDCFGMD); + STV090x_SETFIELD_Px(reg, SCAN_ENABLE_FIELD, 1); + STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 1); + if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0) + goto err; + + if (STV090x_WRITE_DEMOD(state, SFRUP1, 0x83) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, SFRUP0, 0xc0) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, SFRLOW1, 0x82) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, SFRLOW0, 0xa0) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, DMDTOM, 0x00) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x60) < 0) + goto err; + + if (state->dev_ver >= 0x30) { + if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x99) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, SFRSTEP, 0x95) < 0) + goto err; + + } else if (state->dev_ver >= 0x20) { + if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x6a) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, SFRSTEP, 0x95) < 0) + goto err; + } + + if (state->srate <= 2000000) + car_step = 1000; + else if (state->srate <= 5000000) + car_step = 2000; + else if (state->srate <= 12000000) + car_step = 3000; + else + car_step = 5000; + + steps = -1 + ((state->search_range / 1000) / car_step); + steps /= 2; + steps = (2 * steps) + 1; + if (steps < 0) + steps = 1; + else if (steps > 10) { + steps = 11; + car_step = (state->search_range / 1000) / 10; + } + cur_step = 0; + dir = 1; + freq = state->frequency; + + while ((!tmg_lock) && (cur_step < steps)) { + if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x5f) < 0) /* Demod RESET */ + goto err; + reg = STV090x_READ_DEMOD(state, DMDISTATE); + STV090x_SETFIELD_Px(reg, I2C_DEMOD_MODE_FIELD, 0x00); /* trigger acquisition */ + if (STV090x_WRITE_DEMOD(state, DMDISTATE, reg) < 0) + goto err; + msleep(50); + for (i = 0; i < 10; i++) { + reg = STV090x_READ_DEMOD(state, DSTATUS); + if (STV090x_GETFIELD_Px(reg, TMGLOCK_QUALITY_FIELD) >= 2) + tmg_cpt++; + agc2 += STV090x_READ_DEMOD(state, AGC2I1) << 8; + agc2 |= STV090x_READ_DEMOD(state, AGC2I0); + } + agc2 /= 10; + srate_coarse = stv090x_get_srate(state, state->mclk); + cur_step++; + dir *= -1; + if ((tmg_cpt >= 5) && (agc2 < 0x1f00) && (srate_coarse < 55000000) && (srate_coarse > 850000)) + tmg_lock = 1; + else if (cur_step < steps) { + if (dir > 0) + freq += cur_step * car_step; + else + freq -= cur_step * car_step; + + /* Setup tuner */ + if (stv090x_i2c_gate_ctrl(fe, 1) < 0) + goto err; + + if (state->config->tuner_set_frequency) { + if (state->config->tuner_set_frequency(fe, state->frequency) < 0) + goto err; + } + + if (state->config->tuner_set_bandwidth) { + if (state->config->tuner_set_bandwidth(fe, state->tuner_bw) < 0) + goto err; + } + + if (stv090x_i2c_gate_ctrl(fe, 0) < 0) + goto err; + + msleep(50); + + if (stv090x_i2c_gate_ctrl(fe, 1) < 0) + goto err; + + if (state->config->tuner_get_status) { + if (state->config->tuner_get_status(fe, ®) < 0) + goto err; + } + + if (reg) + dprintk(FE_DEBUG, 1, "Tuner phase locked"); + else + dprintk(FE_DEBUG, 1, "Tuner unlocked"); + + if (stv090x_i2c_gate_ctrl(fe, 0) < 0) + goto err; + + } + } + if (!tmg_lock) + srate_coarse = 0; + else + srate_coarse = stv090x_get_srate(state, state->mclk); + + return srate_coarse; +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static u32 stv090x_srate_srch_fine(struct stv090x_state *state) +{ + u32 srate_coarse, freq_coarse, sym, reg; + + srate_coarse = stv090x_get_srate(state, state->mclk); + freq_coarse = STV090x_READ_DEMOD(state, CFR2) << 8; + freq_coarse |= STV090x_READ_DEMOD(state, CFR1); + sym = 13 * (srate_coarse / 10); /* SFRUP = SFR + 30% */ + + if (sym < state->srate) + srate_coarse = 0; + else { + if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0) /* Demod RESET */ + goto err; + if (STV090x_WRITE_DEMOD(state, TMGCFG2, 0x01) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, TMGTHRISE, 0x20) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, TMGTHFALL, 0x00) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, TMGCFG, 0xd2) < 0) + goto err; + reg = STV090x_READ_DEMOD(state, DMDCFGMD); + STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 0x00); + if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0) + goto err; + + if (state->dev_ver >= 0x30) { + if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x79) < 0) + goto err; + } else if (state->dev_ver >= 0x20) { + if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x49) < 0) + goto err; + } + + if (srate_coarse > 3000000) { + sym = 13 * (srate_coarse / 10); /* SFRUP = SFR + 30% */ + sym = (sym / 1000) * 65536; + sym /= (state->mclk / 1000); + if (STV090x_WRITE_DEMOD(state, SFRUP1, (sym >> 8) & 0x7f) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, SFRUP0, sym & 0xff) < 0) + goto err; + sym = 10 * (srate_coarse / 13); /* SFRLOW = SFR - 30% */ + sym = (sym / 1000) * 65536; + sym /= (state->mclk / 1000); + if (STV090x_WRITE_DEMOD(state, SFRLOW1, (sym >> 8) & 0x7f) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, SFRLOW0, sym & 0xff) < 0) + goto err; + sym = (srate_coarse / 1000) * 65536; + sym /= (state->mclk / 1000); + if (STV090x_WRITE_DEMOD(state, SFRINIT1, (sym >> 8) & 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, SFRINIT0, sym & 0xff) < 0) + goto err; + } else { + sym = 13 * (srate_coarse / 10); /* SFRUP = SFR + 30% */ + sym = (sym / 100) * 65536; + sym /= (state->mclk / 100); + if (STV090x_WRITE_DEMOD(state, SFRUP1, (sym >> 8) & 0x7f) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, SFRUP0, sym & 0xff) < 0) + goto err; + sym = 10 * (srate_coarse / 14); /* SFRLOW = SFR - 30% */ + sym = (sym / 100) * 65536; + sym /= (state->mclk / 100); + if (STV090x_WRITE_DEMOD(state, SFRLOW1, (sym >> 8) & 0x7f) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, SFRLOW0, sym & 0xff) < 0) + goto err; + sym = (srate_coarse / 100) * 65536; + sym /= (state->mclk / 100); + if (STV090x_WRITE_DEMOD(state, SFRINIT1, (sym >> 8) & 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, SFRINIT0, sym & 0xff) < 0) + goto err; + } + if (STV090x_WRITE_DEMOD(state, DMDTOM, 0x20) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, CFRINIT1, (freq_coarse >> 8) & 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, CFRINIT0, freq_coarse & 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x15) < 0) /* trigger acquisition */ + goto err; + } + + return srate_coarse; + +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static int stv090x_get_dmdlock(struct stv090x_state *state, s32 timeout) +{ + s32 timer = 0, lock = 0; + u32 reg; + u8 stat; + + while ((timer < timeout) && (!lock)) { + reg = STV090x_READ_DEMOD(state, DMDSTATE); + stat = STV090x_GETFIELD_Px(reg, HEADER_MODE_FIELD); + + switch (stat) { + case 0: /* searching */ + case 1: /* first PLH detected */ + default: + dprintk(FE_DEBUG, 1, "Demodulator searching .."); + lock = 0; + break; + case 2: /* DVB-S2 mode */ + case 3: /* DVB-S1/legacy mode */ + reg = STV090x_READ_DEMOD(state, DSTATUS); + lock = STV090x_GETFIELD_Px(reg, LOCK_DEFINITIF_FIELD); + break; + } + + if (!lock) + msleep(10); + else + dprintk(FE_DEBUG, 1, "Demodulator acquired LOCK"); + + timer += 10; + } + return lock; +} + +static int stv090x_blind_search(struct stv090x_state *state) +{ + u32 agc2, reg, srate_coarse; + s32 timeout_dmd = 500, cpt_fail, agc2_ovflw, i; + u8 k_ref, k_max, k_min; + int coarse_fail, lock; + + k_max = 120; + k_min = 30; + + agc2 = stv090x_get_agc2_min_level(state); + + if (agc2 > STV090x_SEARCH_AGC2_TH(state->dev_ver)) { + lock = 0; + } else { + + if (state->dev_ver <= 0x20) { + if (STV090x_WRITE_DEMOD(state, CARCFG, 0xc4) < 0) + goto err; + } else { + /* > Cut 3 */ + if (STV090x_WRITE_DEMOD(state, CARCFG, 0x06) < 0) + goto err; + } + + if (STV090x_WRITE_DEMOD(state, RTCS2, 0x44) < 0) + goto err; + + if (state->dev_ver >= 0x20) { + if (STV090x_WRITE_DEMOD(state, EQUALCFG, 0x41) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, FFECFG, 0x41) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, VITSCALE, 0x82) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, VAVSRVIT, 0x00) < 0) /* set viterbi hysteresis */ + goto err; + } + + k_ref = k_max; + do { + if (STV090x_WRITE_DEMOD(state, KREFTMG, k_ref) < 0) + goto err; + if (stv090x_srate_srch_coarse(state) != 0) { + srate_coarse = stv090x_srate_srch_fine(state); + if (srate_coarse != 0) { + stv090x_get_lock_tmg(state); + lock = stv090x_get_dmdlock(state, timeout_dmd); + } else { + lock = 0; + } + } else { + cpt_fail = 0; + agc2_ovflw = 0; + for (i = 0; i < 10; i++) { + agc2 = STV090x_READ_DEMOD(state, AGC2I1) << 8; + agc2 |= STV090x_READ_DEMOD(state, AGC2I0); + if (agc2 >= 0xff00) + agc2_ovflw++; + reg = STV090x_READ_DEMOD(state, DSTATUS2); + if ((STV090x_GETFIELD_Px(reg, CFR_OVERFLOW_FIELD) == 0x01) && + (STV090x_GETFIELD_Px(reg, DEMOD_DELOCK_FIELD) == 0x01)) + + cpt_fail++; + } + if ((cpt_fail > 7) || (agc2_ovflw > 7)) + coarse_fail = 1; + + lock = 0; + } + k_ref -= 30; + } while ((k_ref >= k_min) && (!lock) && (!coarse_fail)); + } + + return lock; + +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static int stv090x_chk_tmg(struct stv090x_state *state) +{ + u32 reg; + s32 tmg_cpt = 0, i; + u8 freq, tmg_thh, tmg_thl; + int tmg_lock; + + freq = STV090x_READ_DEMOD(state, CARFREQ); + tmg_thh = STV090x_READ_DEMOD(state, TMGTHRISE); + tmg_thl = STV090x_READ_DEMOD(state, TMGTHFALL); + if (STV090x_WRITE_DEMOD(state, TMGTHRISE, 0x20) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, TMGTHFALL, 0x00) < 0) + goto err; + + reg = STV090x_READ_DEMOD(state, DMDCFGMD); + STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 0x00); /* stop carrier offset search */ + if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, RTC, 0x80) < 0) + goto err; + + if (STV090x_WRITE_DEMOD(state, RTCS2, 0x40) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x00) < 0) + goto err; + + if (STV090x_WRITE_DEMOD(state, CFRINIT1, 0x00) < 0) /* set car ofset to 0 */ + goto err; + if (STV090x_WRITE_DEMOD(state, CFRINIT0, 0x00) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x65) < 0) + goto err; + + if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x18) < 0) /* trigger acquisition */ + goto err; + msleep(10); + + for (i = 0; i < 10; i++) { + reg = STV090x_READ_DEMOD(state, DSTATUS); + if (STV090x_GETFIELD_Px(reg, TMGLOCK_QUALITY_FIELD) >= 2) + tmg_cpt++; + msleep(1); + } + if (tmg_cpt >= 3) + tmg_lock = 1; + + if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x38) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, RTC, 0x88) < 0) /* DVB-S1 timing */ + goto err; + if (STV090x_WRITE_DEMOD(state, RTCS2, 0x68) < 0) /* DVB-S2 timing */ + goto err; + + if (STV090x_WRITE_DEMOD(state, CARFREQ, freq) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, TMGTHRISE, tmg_thh) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, TMGTHFALL, tmg_thl) < 0) + goto err; + + return tmg_lock; + +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static int stv090x_get_coldlock(struct stv090x_state *state, s32 timeout_dmd) +{ + struct dvb_frontend *fe = &state->frontend; + + u32 reg; + s32 car_step, steps, cur_step, dir, freq, timeout_lock; + int lock = 0; + + if (state->srate >= 10000000) + timeout_lock = timeout_dmd / 3; + else + timeout_lock = timeout_dmd / 2; + + lock = stv090x_get_dmdlock(state, timeout_lock); /* cold start wait */ + if (!lock) { + if (state->srate >= 10000000) { + if (stv090x_chk_tmg(state)) { + if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x15) < 0) + goto err; + lock = stv090x_get_dmdlock(state, timeout_dmd); + } else { + lock = 0; + } + } else { + if (state->srate <= 4000000) + car_step = 1000; + else if (state->srate <= 7000000) + car_step = 2000; + else if (state->srate <= 10000000) + car_step = 3000; + else + car_step = 5000; + + steps = (state->search_range / 1000) / car_step; + steps /= 2; + steps = 2 * (steps + 1); + if (steps < 0) + steps = 2; + else if (steps > 12) + steps = 12; + + cur_step = 1; + dir = 1; + + if (!lock) { + freq = state->frequency; + state->tuner_bw = stv090x_car_width(state->srate, state->rolloff) + state->srate; + while ((cur_step <= steps) && (!lock)) { + if (dir > 0) + freq += cur_step * car_step; + else + freq -= cur_step * car_step; + + /* Setup tuner */ + if (stv090x_i2c_gate_ctrl(fe, 1) < 0) + goto err; + + if (state->config->tuner_set_frequency) { + if (state->config->tuner_set_frequency(fe, state->frequency) < 0) + goto err; + } + + if (state->config->tuner_set_bandwidth) { + if (state->config->tuner_set_bandwidth(fe, state->tuner_bw) < 0) + goto err; + } + + if (stv090x_i2c_gate_ctrl(fe, 0) < 0) + goto err; + + msleep(50); + + if (stv090x_i2c_gate_ctrl(fe, 1) < 0) + goto err; + + if (state->config->tuner_get_status) { + if (state->config->tuner_get_status(fe, ®) < 0) + goto err; + } + + if (reg) + dprintk(FE_DEBUG, 1, "Tuner phase locked"); + else + dprintk(FE_DEBUG, 1, "Tuner unlocked"); + + if (stv090x_i2c_gate_ctrl(fe, 0) < 0) + goto err; + + STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1c); + if (state->delsys == STV090x_DVBS2) { + reg = STV090x_READ_DEMOD(state, DMDCFGMD); + STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 0); + STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 0); + if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0) + goto err; + STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 1); + STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 1); + if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0) + goto err; + } + if (STV090x_WRITE_DEMOD(state, CFRINIT1, 0x00) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, CFRINIT0, 0x00) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x15) < 0) + goto err; + lock = stv090x_get_dmdlock(state, (timeout_dmd / 3)); + + dir *= -1; + cur_step++; + } + } + } + } + + return lock; + +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static int stv090x_get_loop_params(struct stv090x_state *state, s32 *freq_inc, s32 *timeout_sw, s32 *steps) +{ + s32 timeout, inc, steps_max, srate, car_max; + + srate = state->srate; + car_max = state->search_range / 1000; + car_max += car_max / 10; + car_max = 65536 * (car_max / 2); + car_max /= (state->mclk / 1000); + + if (car_max > 0x4000) + car_max = 0x4000 ; /* maxcarrier should be<= +-1/4 Mclk */ + + inc = srate; + inc /= state->mclk / 1000; + inc *= 256; + inc *= 256; + inc /= 1000; + + switch (state->search_mode) { + case STV090x_SEARCH_DVBS1: + case STV090x_SEARCH_DSS: + inc *= 3; /* freq step = 3% of srate */ + timeout = 20; + break; + + case STV090x_SEARCH_DVBS2: + inc *= 4; + timeout = 25; + break; + + case STV090x_SEARCH_AUTO: + default: + inc *= 3; + timeout = 25; + break; + } + inc /= 100; + if ((inc > car_max) || (inc < 0)) + inc = car_max / 2; /* increment <= 1/8 Mclk */ + + timeout *= 27500; /* 27.5 Msps reference */ + if (srate > 0) + timeout /= (srate / 1000); + + if ((timeout > 100) || (timeout < 0)) + timeout = 100; + + steps_max = (car_max / inc) + 1; /* min steps = 3 */ + if ((steps_max > 100) || (steps_max < 0)) { + steps_max = 100; /* max steps <= 100 */ + inc = car_max / steps_max; + } + *freq_inc = inc; + *timeout_sw = timeout; + *steps = steps_max; + + return 0; +} + +static int stv090x_chk_signal(struct stv090x_state *state) +{ + s32 offst_car, agc2, car_max; + int no_signal; + + offst_car = STV090x_READ_DEMOD(state, CFR2) << 8; + offst_car |= STV090x_READ_DEMOD(state, CFR1); + offst_car = comp2(offst_car, 16); + + agc2 = STV090x_READ_DEMOD(state, AGC2I1) << 8; + agc2 |= STV090x_READ_DEMOD(state, AGC2I0); + car_max = state->search_range / 1000; + + car_max += (car_max / 10); /* 10% margin */ + car_max = (65536 * car_max / 2); + car_max /= state->mclk / 1000; + + if (car_max > 0x4000) + car_max = 0x4000; + + if ((agc2 > 0x2000) || (offst_car > 2 * car_max) || (offst_car < -2 * car_max)) { + no_signal = 1; + dprintk(FE_DEBUG, 1, "No Signal"); + } else { + no_signal = 0; + dprintk(FE_DEBUG, 1, "Found Signal"); + } + + return no_signal; +} + +static int stv090x_search_car_loop(struct stv090x_state *state, s32 inc, s32 timeout, int zigzag, s32 steps_max) +{ + int no_signal, lock = 0; + s32 cpt_step = 0, offst_freq, car_max; + u32 reg; + + car_max = state->search_range / 1000; + car_max += (car_max / 10); + car_max = (65536 * car_max / 2); + car_max /= (state->mclk / 1000); + if (car_max > 0x4000) + car_max = 0x4000; + + if (zigzag) + offst_freq = 0; + else + offst_freq = -car_max + inc; + + do { + if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1c) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, CFRINIT1, ((offst_freq / 256) & 0xff)) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, CFRINIT0, offst_freq & 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x18) < 0) + goto err; + + reg = STV090x_READ_DEMOD(state, PDELCTRL1); + STV090x_SETFIELD_Px(reg, ALGOSWRST_FIELD, 0x1); /* stop DVB-S2 packet delin */ + if (STV090x_WRITE_DEMOD(state, PDELCTRL1, reg) < 0) + goto err; + + if (zigzag) { + if (offst_freq >= 0) + offst_freq = -offst_freq - 2 * inc; + else + offst_freq = -offst_freq; + } else { + offst_freq += 2 * inc; + } + + cpt_step++; + + lock = stv090x_get_dmdlock(state, timeout); + no_signal = stv090x_chk_signal(state); + + } while ((!lock) && + (!no_signal) && + ((offst_freq - inc) < car_max) && + ((offst_freq + inc) > -car_max) && + (cpt_step < steps_max)); + + reg = STV090x_READ_DEMOD(state, PDELCTRL1); + STV090x_SETFIELD_Px(reg, ALGOSWRST_FIELD, 0); + if (STV090x_WRITE_DEMOD(state, PDELCTRL1, reg) < 0) + goto err; + + return lock; +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static int stv090x_sw_algo(struct stv090x_state *state) +{ + int no_signal, zigzag, lock = 0; + u32 reg; + + s32 dvbs2_fly_wheel; + s32 inc, timeout_step, trials, steps_max; + + /* get params */ + stv090x_get_loop_params(state, &inc, &timeout_step, &steps_max); + + switch (state->search_mode) { + case STV090x_SEARCH_DVBS1: + case STV090x_SEARCH_DSS: + /* accelerate the frequency detector */ + if (state->dev_ver >= 0x20) { + if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x3B) < 0) + goto err; + } + + if (STV090x_WRITE_DEMOD(state, DMDCFGMD, 0x49) < 0) + goto err; + zigzag = 0; + break; + + case STV090x_SEARCH_DVBS2: + if (state->dev_ver >= 0x20) { + if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x79) < 0) + goto err; + } + + if (STV090x_WRITE_DEMOD(state, DMDCFGMD, 0x89) < 0) + goto err; + zigzag = 1; + break; + + case STV090x_SEARCH_AUTO: + default: + /* accelerate the frequency detector */ + if (state->dev_ver >= 0x20) { + if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x3b) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x79) < 0) + goto err; + } + + if (STV090x_WRITE_DEMOD(state, DMDCFGMD, 0xc9) < 0) + goto err; + zigzag = 0; + break; + } + + trials = 0; + do { + lock = stv090x_search_car_loop(state, inc, timeout_step, zigzag, steps_max); + no_signal = stv090x_chk_signal(state); + trials++; + + /*run the SW search 2 times maximum*/ + if (lock || no_signal || (trials == 2)) { + /*Check if the demod is not losing lock in DVBS2*/ + if (state->dev_ver >= 0x20) { + if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x49) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x9e) < 0) + goto err; + } + + reg = STV090x_READ_DEMOD(state, DMDSTATE); + if ((lock) && (STV090x_GETFIELD_Px(reg, HEADER_MODE_FIELD) == STV090x_DVBS2)) { + /*Check if the demod is not losing lock in DVBS2*/ + msleep(timeout_step); + reg = STV090x_READ_DEMOD(state, DMDFLYW); + dvbs2_fly_wheel = STV090x_GETFIELD_Px(reg, FLYWHEEL_CPT_FIELD); + if (dvbs2_fly_wheel < 0xd) { /*if correct frames is decrementing */ + msleep(timeout_step); + reg = STV090x_READ_DEMOD(state, DMDFLYW); + dvbs2_fly_wheel = STV090x_GETFIELD_Px(reg, FLYWHEEL_CPT_FIELD); + } + if (dvbs2_fly_wheel < 0xd) { + /*FALSE lock, The demod is loosing lock */ + lock = 0; + if (trials < 2) { + if (state->dev_ver >= 0x20) { + if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x79) < 0) + goto err; + } + + if (STV090x_WRITE_DEMOD(state, DMDCFGMD, 0x89) < 0) + goto err; + } + } + } + } + } while ((!lock) && (trials < 2) && (!no_signal)); + + return lock; +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static enum stv090x_delsys stv090x_get_std(struct stv090x_state *state) +{ + u32 reg; + enum stv090x_delsys delsys; + + reg = STV090x_READ_DEMOD(state, DMDSTATE); + if (STV090x_GETFIELD_Px(reg, HEADER_MODE_FIELD) == 2) + delsys = STV090x_DVBS2; + else if (STV090x_GETFIELD_Px(reg, HEADER_MODE_FIELD) == 3) { + reg = STV090x_READ_DEMOD(state, FECM); + if (STV090x_GETFIELD_Px(reg, DSS_DVB_FIELD) == 1) + delsys = STV090x_DSS; + else + delsys = STV090x_DVBS1; + } else { + delsys = STV090x_ERROR; + } + + return delsys; +} + +/* in Hz */ +static s32 stv090x_get_car_freq(struct stv090x_state *state, u32 mclk) +{ + s32 derot, int_1, int_2, tmp_1, tmp_2; + + derot = STV090x_READ_DEMOD(state, CFR2) << 16; + derot |= STV090x_READ_DEMOD(state, CFR1) << 8; + derot |= STV090x_READ_DEMOD(state, CFR0); + + derot = comp2(derot, 24); + int_1 = state->mclk >> 12; + int_2 = derot >> 12; + + /* carrier_frequency = MasterClock * Reg / 2^24 */ + tmp_1 = state->mclk % 0x1000; + tmp_2 = derot % 0x1000; + + derot = (int_1 * int_2) + + ((int_1 * tmp_2) >> 12) + + ((int_1 * tmp_1) >> 12); + + return derot; +} + +static int stv090x_get_viterbi(struct stv090x_state *state) +{ + u32 reg, rate; + + reg = STV090x_READ_DEMOD(state, VITCURPUN); + rate = STV090x_GETFIELD_Px(reg, VIT_CURPUN_FIELD); + + switch (rate) { + case 13: + state->fec = STV090x_PR12; + break; + + case 18: + state->fec = STV090x_PR23; + break; + + case 21: + state->fec = STV090x_PR34; + break; + + case 24: + state->fec = STV090x_PR56; + break; + + case 25: + state->fec = STV090x_PR67; + break; + + case 26: + state->fec = STV090x_PR78; + break; + + default: + state->fec = STV090x_PRERR; + break; + } + + return 0; +} + +static enum stv090x_signal_state stv090x_get_sig_params(struct stv090x_state *state) +{ + struct dvb_frontend *fe = &state->frontend; + + u8 tmg; + u32 reg; + s32 i = 0, offst_freq; + + msleep(5); + + if (state->algo == STV090x_BLIND_SEARCH) { + tmg = STV090x_READ_DEMOD(state, TMGREG2); + STV090x_WRITE_DEMOD(state, SFRSTEP, 0x5c); + while ((i <= 50) && (tmg != 0) && (tmg != 0xff)) { + tmg = STV090x_READ_DEMOD(state, TMGREG2); + msleep(5); + i += 5; + } + } + state->delsys = stv090x_get_std(state); + + if (stv090x_i2c_gate_ctrl(fe, 1) < 0) + goto err; + + if (state->config->tuner_get_frequency) { + if (state->config->tuner_get_frequency(fe, &state->frequency) < 0) + goto err; + } + + if (stv090x_i2c_gate_ctrl(fe, 0) < 0) + goto err; + + offst_freq = stv090x_get_car_freq(state, state->mclk) / 1000; + state->frequency += offst_freq; + + if (stv090x_get_viterbi(state) < 0) + goto err; + + reg = STV090x_READ_DEMOD(state, DMDMODCOD); + state->modcod = STV090x_GETFIELD_Px(reg, DEMOD_MODCOD_FIELD); + state->pilots = STV090x_GETFIELD_Px(reg, DEMOD_TYPE_FIELD) & 0x01; + state->frame_len = STV090x_GETFIELD_Px(reg, DEMOD_TYPE_FIELD) >> 1; + reg = STV090x_READ_DEMOD(state, TMGOBS); + state->rolloff = STV090x_GETFIELD_Px(reg, ROLLOFF_STATUS_FIELD); + reg = STV090x_READ_DEMOD(state, FECM); + state->inversion = STV090x_GETFIELD_Px(reg, IQINV_FIELD); + + if ((state->algo == STV090x_BLIND_SEARCH) || (state->srate < 10000000)) { + + if (stv090x_i2c_gate_ctrl(fe, 1) < 0) + goto err; + + if (state->config->tuner_get_frequency) { + if (state->config->tuner_get_frequency(fe, &state->frequency) < 0) + goto err; + } + + if (stv090x_i2c_gate_ctrl(fe, 0) < 0) + goto err; + + if (abs(offst_freq) <= ((state->search_range / 2000) + 500)) + return STV090x_RANGEOK; + else if (abs(offst_freq) <= (stv090x_car_width(state->srate, state->rolloff) / 2000)) + return STV090x_RANGEOK; + else + return STV090x_OUTOFRANGE; /* Out of Range */ + } else { + if (abs(offst_freq) <= ((state->search_range / 2000) + 500)) + return STV090x_RANGEOK; + else + return STV090x_OUTOFRANGE; + } + + return STV090x_OUTOFRANGE; +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static u32 stv090x_get_tmgoffst(struct stv090x_state *state, u32 srate) +{ + s32 offst_tmg; + + offst_tmg = STV090x_READ_DEMOD(state, TMGREG2) << 16; + offst_tmg |= STV090x_READ_DEMOD(state, TMGREG1) << 8; + offst_tmg |= STV090x_READ_DEMOD(state, TMGREG0); + + offst_tmg = comp2(offst_tmg, 24); /* 2's complement */ + if (!offst_tmg) + offst_tmg = 1; + + offst_tmg = ((s32) srate * 10) / ((s32) 0x1000000 / offst_tmg); + offst_tmg /= 320; + + return offst_tmg; +} + +static u8 stv090x_optimize_carloop(struct stv090x_state *state, enum stv090x_modcod modcod, s32 pilots) +{ + u8 aclc = 0x29; + s32 i; + struct stv090x_long_frame_crloop *car_loop, *car_loop_qpsk_low, *car_loop_apsk_low; + + if (state->dev_ver == 0x20) { + car_loop = stv090x_s2_crl_cut20; + car_loop_qpsk_low = stv090x_s2_lowqpsk_crl_cut20; + car_loop_apsk_low = stv090x_s2_apsk_crl_cut20; + } else { + /* >= Cut 3 */ + car_loop = stv090x_s2_crl_cut30; + car_loop_qpsk_low = stv090x_s2_lowqpsk_crl_cut30; + car_loop_apsk_low = stv090x_s2_apsk_crl_cut30; + } + + if (modcod < STV090x_QPSK_12) { + i = 0; + while ((i < 3) && (modcod != car_loop_qpsk_low[i].modcod)) + i++; + + if (i >= 3) + i = 2; + + } else { + i = 0; + while ((i < 14) && (modcod != car_loop[i].modcod)) + i++; + + if (i >= 14) { + i = 0; + while ((i < 11) && (modcod != car_loop_apsk_low[i].modcod)) + i++; + + if (i >= 11) + i = 10; + } + } + + if (modcod <= STV090x_QPSK_25) { + if (pilots) { + if (state->srate <= 3000000) + aclc = car_loop_qpsk_low[i].crl_pilots_on_2; + else if (state->srate <= 7000000) + aclc = car_loop_qpsk_low[i].crl_pilots_on_5; + else if (state->srate <= 15000000) + aclc = car_loop_qpsk_low[i].crl_pilots_on_10; + else if (state->srate <= 25000000) + aclc = car_loop_qpsk_low[i].crl_pilots_on_20; + else + aclc = car_loop_qpsk_low[i].crl_pilots_on_30; + } else { + if (state->srate <= 3000000) + aclc = car_loop_qpsk_low[i].crl_pilots_off_2; + else if (state->srate <= 7000000) + aclc = car_loop_qpsk_low[i].crl_pilots_off_5; + else if (state->srate <= 15000000) + aclc = car_loop_qpsk_low[i].crl_pilots_off_10; + else if (state->srate <= 25000000) + aclc = car_loop_qpsk_low[i].crl_pilots_off_20; + else + aclc = car_loop_qpsk_low[i].crl_pilots_off_30; + } + + } else if (modcod <= STV090x_8PSK_910) { + if (pilots) { + if (state->srate <= 3000000) + aclc = car_loop[i].crl_pilots_on_2; + else if (state->srate <= 7000000) + aclc = car_loop[i].crl_pilots_on_5; + else if (state->srate <= 15000000) + aclc = car_loop[i].crl_pilots_on_10; + else if (state->srate <= 25000000) + aclc = car_loop[i].crl_pilots_on_20; + else + aclc = car_loop[i].crl_pilots_on_30; + } else { + if (state->srate <= 3000000) + aclc = car_loop[i].crl_pilots_off_2; + else if (state->srate <= 7000000) + aclc = car_loop[i].crl_pilots_off_5; + else if (state->srate <= 15000000) + aclc = car_loop[i].crl_pilots_off_10; + else if (state->srate <= 25000000) + aclc = car_loop[i].crl_pilots_off_20; + else + aclc = car_loop[i].crl_pilots_off_30; + } + } else { /* 16APSK and 32APSK */ + if (state->srate <= 3000000) + aclc = car_loop_apsk_low[i].crl_pilots_on_2; + else if (state->srate <= 7000000) + aclc = car_loop_apsk_low[i].crl_pilots_on_5; + else if (state->srate <= 15000000) + aclc = car_loop_apsk_low[i].crl_pilots_on_10; + else if (state->srate <= 25000000) + aclc = car_loop_apsk_low[i].crl_pilots_on_20; + else + aclc = car_loop_apsk_low[i].crl_pilots_on_30; + } + + return aclc; +} + +static u8 stv090x_optimize_carloop_short(struct stv090x_state *state) +{ + struct stv090x_short_frame_crloop *short_crl = NULL; + s32 index = 0; + u8 aclc = 0x0b; + + switch (state->modulation) { + case STV090x_QPSK: + default: + index = 0; + break; + case STV090x_8PSK: + index = 1; + break; + case STV090x_16APSK: + index = 2; + break; + case STV090x_32APSK: + index = 3; + break; + } + + if (state->dev_ver >= 0x30) { + /* Cut 3.0 and up */ + short_crl = stv090x_s2_short_crl_cut30; + } else { + /* Cut 2.0 and up: we don't support cuts older than 2.0 */ + short_crl = stv090x_s2_short_crl_cut20; + } + + if (state->srate <= 3000000) + aclc = short_crl[index].crl_2; + else if (state->srate <= 7000000) + aclc = short_crl[index].crl_5; + else if (state->srate <= 15000000) + aclc = short_crl[index].crl_10; + else if (state->srate <= 25000000) + aclc = short_crl[index].crl_20; + else + aclc = short_crl[index].crl_30; + + return aclc; +} + +static int stv090x_optimize_track(struct stv090x_state *state) +{ + struct dvb_frontend *fe = &state->frontend; + + enum stv090x_rolloff rolloff; + enum stv090x_modcod modcod; + + s32 srate, pilots, aclc, f_1, f_0, i = 0, blind_tune = 0; + u32 reg; + + srate = stv090x_get_srate(state, state->mclk); + srate += stv090x_get_tmgoffst(state, srate); + + switch (state->delsys) { + case STV090x_DVBS1: + case STV090x_DSS: + if (state->algo == STV090x_SEARCH_AUTO) { + reg = STV090x_READ_DEMOD(state, DMDCFGMD); + STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 1); + STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 0); + if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0) + goto err; + } + reg = STV090x_READ_DEMOD(state, DEMOD); + STV090x_SETFIELD_Px(reg, ROLLOFF_CONTROL_FIELD, state->rolloff); + STV090x_SETFIELD_Px(reg, MANUAL_SXROLLOFF_FIELD, 0x01); + if (STV090x_WRITE_DEMOD(state, DEMOD, reg) < 0) + goto err; + + if (state->dev_ver >= 0x30) { + if (stv090x_get_viterbi(state) < 0) + goto err; + + if (state->fec == STV090x_PR12) { + if (STV090x_WRITE_DEMOD(state, GAUSSR0, 0x98) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, CCIR0, 0x18) < 0) + goto err; + } else { + if (STV090x_WRITE_DEMOD(state, GAUSSR0, 0x18) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, CCIR0, 0x18) < 0) + goto err; + } + } + + if (STV090x_WRITE_DEMOD(state, ERRCTRL1, 0x75) < 0) + goto err; + break; + + case STV090x_DVBS2: + reg = STV090x_READ_DEMOD(state, DMDCFGMD); + STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 0); + STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 1); + if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, ACLC, 0) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, BCLC, 0) < 0) + goto err; + if (state->frame_len == STV090x_LONG_FRAME) { + reg = STV090x_READ_DEMOD(state, DMDMODCOD); + modcod = STV090x_GETFIELD_Px(reg, DEMOD_MODCOD_FIELD); + pilots = STV090x_GETFIELD_Px(reg, DEMOD_TYPE_FIELD) & 0x01; + aclc = stv090x_optimize_carloop(state, modcod, pilots); + if (modcod <= STV090x_QPSK_910) { + STV090x_WRITE_DEMOD(state, ACLC2S2Q, aclc); + } else if (modcod <= STV090x_8PSK_910) { + if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, 0x2a) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, ACLC2S28, aclc) < 0) + goto err; + } + if ((state->demod_mode == STV090x_SINGLE) && (modcod > STV090x_8PSK_910)) { + if (modcod <= STV090x_16APSK_910) { + if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, 0x2a) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, ACLC2S216A, aclc) < 0) + goto err; + } else { + if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, 0x2a) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, ACLC2S232A, aclc) < 0) + goto err; + } + } + } else { + /*Carrier loop setting for short frame*/ + aclc = stv090x_optimize_carloop_short(state); + if (state->modulation == STV090x_QPSK) { + if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, aclc) < 0) + goto err; + } else if (state->modulation == STV090x_8PSK) { + if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, 0x2a) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, ACLC2S28, aclc) < 0) + goto err; + } else if (state->modulation == STV090x_16APSK) { + if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, 0x2a) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, ACLC2S216A, aclc) < 0) + goto err; + } else if (state->modulation == STV090x_32APSK) { + if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, 0x2a) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, ACLC2S232A, aclc) < 0) + goto err; + } + } + + STV090x_WRITE_DEMOD(state, ERRCTRL1, 0x67); /* PER */ + break; + + case STV090x_UNKNOWN: + default: + reg = STV090x_READ_DEMOD(state, DMDCFGMD); + STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 1); + STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 1); + if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0) + goto err; + break; + } + + f_1 = STV090x_READ_DEMOD(state, CFR2); + f_0 = STV090x_READ_DEMOD(state, CFR1); + reg = STV090x_READ_DEMOD(state, TMGOBS); + rolloff = STV090x_GETFIELD_Px(reg, ROLLOFF_STATUS_FIELD); + + if (state->algo == STV090x_BLIND_SEARCH) { + STV090x_WRITE_DEMOD(state, SFRSTEP, 0x00); + reg = STV090x_READ_DEMOD(state, DMDCFGMD); + STV090x_SETFIELD_Px(reg, SCAN_ENABLE_FIELD, 0x00); + STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 0x00); + if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, TMGCFG2, 0xc1) < 0) + goto err; + + if (stv090x_set_srate(state, srate) < 0) + goto err; + blind_tune = 1; + } + + if (state->dev_ver >= 0x20) { + if ((state->search_mode == STV090x_SEARCH_DVBS1) || + (state->search_mode == STV090x_SEARCH_DSS) || + (state->search_mode == STV090x_SEARCH_AUTO)) { + + if (STV090x_WRITE_DEMOD(state, VAVSRVIT, 0x0a) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, VITSCALE, 0x00) < 0) + goto err; + } + } + + if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x38) < 0) + goto err; + + /* AUTO tracking MODE */ + if (STV090x_WRITE_DEMOD(state, SFRUP1, 0x80) < 0) + goto err; + /* AUTO tracking MODE */ + if (STV090x_WRITE_DEMOD(state, SFRLOW1, 0x80) < 0) + goto err; + + if ((state->dev_ver >= 0x20) || (blind_tune == 1) || (state->srate < 10000000)) { + /* update initial carrier freq with the found freq offset */ + if (STV090x_WRITE_DEMOD(state, CFRINIT1, f_1) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, CFRINIT0, f_0) < 0) + goto err; + state->tuner_bw = stv090x_car_width(srate, state->rolloff) + 10000000; + + if ((state->dev_ver >= 0x20) || (blind_tune == 1)) { + + if (state->algo != STV090x_WARM_SEARCH) { + + if (stv090x_i2c_gate_ctrl(fe, 1) < 0) + goto err; + + if (state->config->tuner_set_bandwidth) { + if (state->config->tuner_set_bandwidth(fe, state->tuner_bw) < 0) + goto err; + } + + if (stv090x_i2c_gate_ctrl(fe, 0) < 0) + goto err; + + } + } + if ((state->algo == STV090x_BLIND_SEARCH) || (state->srate < 10000000)) + msleep(50); /* blind search: wait 50ms for SR stabilization */ + else + msleep(5); + + stv090x_get_lock_tmg(state); + + if (!(stv090x_get_dmdlock(state, (state->DemodTimeout / 2)))) { + if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, CFRINIT1, f_1) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, CFRINIT0, f_0) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x18) < 0) + goto err; + + i = 0; + + while ((!(stv090x_get_dmdlock(state, (state->DemodTimeout / 2)))) && (i <= 2)) { + + if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, CFRINIT1, f_1) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, CFRINIT0, f_0) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x18) < 0) + goto err; + i++; + } + } + + } + + if (state->dev_ver >= 0x20) { + if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x49) < 0) + goto err; + } + + if ((state->delsys == STV090x_DVBS1) || (state->delsys == STV090x_DSS)) + stv090x_set_vit_thtracq(state); + + return 0; +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static int stv090x_get_feclock(struct stv090x_state *state, s32 timeout) +{ + s32 timer = 0, lock = 0, stat; + u32 reg; + + while ((timer < timeout) && (!lock)) { + reg = STV090x_READ_DEMOD(state, DMDSTATE); + stat = STV090x_GETFIELD_Px(reg, HEADER_MODE_FIELD); + + switch (stat) { + case 0: /* searching */ + case 1: /* first PLH detected */ + default: + lock = 0; + break; + + case 2: /* DVB-S2 mode */ + reg = STV090x_READ_DEMOD(state, PDELSTATUS1); + lock = STV090x_GETFIELD_Px(reg, PKTDELIN_LOCK_FIELD); + break; + + case 3: /* DVB-S1/legacy mode */ + reg = STV090x_READ_DEMOD(state, VSTATUSVIT); + lock = STV090x_GETFIELD_Px(reg, LOCKEDVIT_FIELD); + break; + } + if (!lock) { + msleep(10); + timer += 10; + } + } + return lock; +} + +static int stv090x_get_lock(struct stv090x_state *state, s32 timeout_dmd, s32 timeout_fec) +{ + u32 reg; + s32 timer = 0; + int lock; + + lock = stv090x_get_dmdlock(state, timeout_dmd); + if (lock) + lock = stv090x_get_feclock(state, timeout_fec); + + if (lock) { + lock = 0; + + while ((timer < timeout_fec) && (!lock)) { + reg = STV090x_READ_DEMOD(state, TSSTATUS); + lock = STV090x_GETFIELD_Px(reg, TSFIFO_LINEOK_FIELD); + msleep(1); + timer++; + } + } + + return lock; +} + +static int stv090x_set_s2rolloff(struct stv090x_state *state) +{ + u32 reg; + + if (state->dev_ver <= 0x20) { + /* rolloff to auto mode if DVBS2 */ + reg = STV090x_READ_DEMOD(state, DEMOD); + STV090x_SETFIELD_Px(reg, MANUAL_SXROLLOFF_FIELD, 0x00); + if (STV090x_WRITE_DEMOD(state, DEMOD, reg) < 0) + goto err; + } else { + /* DVB-S2 rolloff to auto mode if DVBS2 */ + reg = STV090x_READ_DEMOD(state, DEMOD); + STV090x_SETFIELD_Px(reg, MANUAL_S2ROLLOFF_FIELD, 0x00); + if (STV090x_WRITE_DEMOD(state, DEMOD, reg) < 0) + goto err; + } + return 0; +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + + +static enum stv090x_signal_state stv090x_algo(struct stv090x_state *state) +{ + struct dvb_frontend *fe = &state->frontend; + enum stv090x_signal_state signal_state = STV090x_NOCARRIER; + u32 reg; + s32 timeout_dmd = 500, timeout_fec = 50, agc1_power, power_iq = 0, i; + int lock = 0, low_sr = 0, no_signal = 0; + + reg = STV090x_READ_DEMOD(state, TSCFGH); + STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 1); /* Stop path 1 stream merger */ + if (STV090x_WRITE_DEMOD(state, TSCFGH, reg) < 0) + goto err; + + if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x5c) < 0) /* Demod stop */ + goto err; + + if (state->dev_ver >= 0x20) { + if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x9e) < 0) /* cut 2.0 */ + goto err; + } + + stv090x_get_lock_tmg(state); + + if (state->algo == STV090x_BLIND_SEARCH) { + state->tuner_bw = 2 * 36000000; /* wide bw for unknown srate */ + if (STV090x_WRITE_DEMOD(state, TMGCFG2, 0xc0) < 0) /* wider srate scan */ + goto err; + if (STV090x_WRITE_DEMOD(state, CORRELMANT, 0x70) < 0) + goto err; + if (stv090x_set_srate(state, 1000000) < 0) /* inital srate = 1Msps */ + goto err; + } else { + /* known srate */ + if (STV090x_WRITE_DEMOD(state, DMDTOM, 0x20) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, TMGCFG, 0xd2) < 0) + goto err; + + if (state->srate < 2000000) { + /* SR < 2MSPS */ + if (STV090x_WRITE_DEMOD(state, CORRELMANT, 0x63) < 0) + goto err; + } else { + /* SR >= 2Msps */ + if (STV090x_WRITE_DEMOD(state, CORRELMANT, 0x70) < 0) + goto err; + } + + if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x38) < 0) + goto err; + + if (state->dev_ver >= 0x20) { + if (STV090x_WRITE_DEMOD(state, KREFTMG, 0x5a) < 0) + goto err; + if (state->algo == STV090x_COLD_SEARCH) + state->tuner_bw = (15 * (stv090x_car_width(state->srate, state->rolloff) + 10000000)) / 10; + else if (state->algo == STV090x_WARM_SEARCH) + state->tuner_bw = stv090x_car_width(state->srate, state->rolloff) + 10000000; + } + + /* if cold start or warm (Symbolrate is known) + * use a Narrow symbol rate scan range + */ + if (STV090x_WRITE_DEMOD(state, TMGCFG2, 0xc1) < 0) /* narrow srate scan */ + goto err; + + if (stv090x_set_srate(state, state->srate) < 0) + goto err; + + if (stv090x_set_max_srate(state, state->mclk, state->srate) < 0) + goto err; + if (stv090x_set_min_srate(state, state->mclk, state->srate) < 0) + goto err; + + if (state->srate >= 10000000) + low_sr = 0; + else + low_sr = 1; + } + + /* Setup tuner */ + if (stv090x_i2c_gate_ctrl(fe, 1) < 0) + goto err; + + if (state->config->tuner_set_bbgain) { + if (state->config->tuner_set_bbgain(fe, 10) < 0) /* 10dB */ + goto err; + } + + if (state->config->tuner_set_frequency) { + if (state->config->tuner_set_frequency(fe, state->frequency) < 0) + goto err; + } + + if (state->config->tuner_set_bandwidth) { + if (state->config->tuner_set_bandwidth(fe, state->tuner_bw) < 0) + goto err; + } + + if (stv090x_i2c_gate_ctrl(fe, 0) < 0) + goto err; + + msleep(50); + + if (stv090x_i2c_gate_ctrl(fe, 1) < 0) + goto err; + + if (state->config->tuner_get_status) { + if (state->config->tuner_get_status(fe, ®) < 0) + goto err; + } + + if (reg) + dprintk(FE_DEBUG, 1, "Tuner phase locked"); + else + dprintk(FE_DEBUG, 1, "Tuner unlocked"); + + if (stv090x_i2c_gate_ctrl(fe, 0) < 0) + goto err; + + msleep(10); + agc1_power = MAKEWORD16(STV090x_READ_DEMOD(state, AGCIQIN1), + STV090x_READ_DEMOD(state, AGCIQIN0)); + + if (agc1_power == 0) { + /* If AGC1 integrator value is 0 + * then read POWERI, POWERQ + */ + for (i = 0; i < 5; i++) { + power_iq += (STV090x_READ_DEMOD(state, POWERI) + + STV090x_READ_DEMOD(state, POWERQ)) >> 1; + } + power_iq /= 5; + } + + if ((agc1_power == 0) && (power_iq < STV090x_IQPOWER_THRESHOLD)) { + dprintk(FE_ERROR, 1, "No Signal: POWER_IQ=0x%02x", power_iq); + lock = 0; + + } else { + reg = STV090x_READ_DEMOD(state, DEMOD); + STV090x_SETFIELD_Px(reg, SPECINV_CONTROL_FIELD, state->inversion); + + if (state->dev_ver <= 0x20) { + /* rolloff to auto mode if DVBS2 */ + STV090x_SETFIELD_Px(reg, MANUAL_SXROLLOFF_FIELD, 1); + } else { + /* DVB-S2 rolloff to auto mode if DVBS2 */ + STV090x_SETFIELD_Px(reg, MANUAL_S2ROLLOFF_FIELD, 1); + } + if (STV090x_WRITE_DEMOD(state, DEMOD, reg) < 0) + goto err; + + if (stv090x_delivery_search(state) < 0) + goto err; + + if (state->algo != STV090x_BLIND_SEARCH) { + if (stv090x_start_search(state) < 0) + goto err; + } + } + + /* need to check for AGC1 state */ + + + + if (state->algo == STV090x_BLIND_SEARCH) + lock = stv090x_blind_search(state); + + else if (state->algo == STV090x_COLD_SEARCH) + lock = stv090x_get_coldlock(state, timeout_dmd); + + else if (state->algo == STV090x_WARM_SEARCH) + lock = stv090x_get_dmdlock(state, timeout_dmd); + + if ((!lock) && (state->algo == STV090x_COLD_SEARCH)) { + if (!low_sr) { + if (stv090x_chk_tmg(state)) + lock = stv090x_sw_algo(state); + } + } + + if (lock) + signal_state = stv090x_get_sig_params(state); + + if ((lock) && (signal_state == STV090x_RANGEOK)) { /* signal within Range */ + stv090x_optimize_track(state); + + if (state->dev_ver >= 0x20) { + /* >= Cut 2.0 :release TS reset after + * demod lock and optimized Tracking + */ + reg = STV090x_READ_DEMOD(state, TSCFGH); + STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0); /* release merger reset */ + if (STV090x_WRITE_DEMOD(state, TSCFGH, reg) < 0) + goto err; + + msleep(3); + + STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 1); /* merger reset */ + if (STV090x_WRITE_DEMOD(state, TSCFGH, reg) < 0) + goto err; + + STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0); /* release merger reset */ + if (STV090x_WRITE_DEMOD(state, TSCFGH, reg) < 0) + goto err; + } + + if (stv090x_get_lock(state, timeout_fec, timeout_fec)) { + lock = 1; + if (state->delsys == STV090x_DVBS2) { + stv090x_set_s2rolloff(state); + + reg = STV090x_READ_DEMOD(state, PDELCTRL2); + STV090x_SETFIELD_Px(reg, RESET_UPKO_COUNT, 1); + if (STV090x_WRITE_DEMOD(state, PDELCTRL2, reg) < 0) + goto err; + /* Reset DVBS2 packet delinator error counter */ + reg = STV090x_READ_DEMOD(state, PDELCTRL2); + STV090x_SETFIELD_Px(reg, RESET_UPKO_COUNT, 0); + if (STV090x_WRITE_DEMOD(state, PDELCTRL2, reg) < 0) + goto err; + + if (STV090x_WRITE_DEMOD(state, ERRCTRL1, 0x67) < 0) /* PER */ + goto err; + } else { + if (STV090x_WRITE_DEMOD(state, ERRCTRL1, 0x75) < 0) + goto err; + } + /* Reset the Total packet counter */ + if (STV090x_WRITE_DEMOD(state, FBERCPT4, 0x00) < 0) + goto err; + /* Reset the packet Error counter2 */ + if (STV090x_WRITE_DEMOD(state, ERRCTRL2, 0xc1) < 0) + goto err; + } else { + lock = 0; + signal_state = STV090x_NODATA; + no_signal = stv090x_chk_signal(state); + } + } + return signal_state; + +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static enum dvbfe_search stv090x_search(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) +{ + struct stv090x_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *props = &fe->dtv_property_cache; + + state->delsys = props->delivery_system; + state->frequency = p->frequency; + state->srate = p->u.qpsk.symbol_rate; + state->search_mode = STV090x_SEARCH_AUTO; + state->algo = STV090x_COLD_SEARCH; + state->fec = STV090x_PRERR; + state->search_range = 2000000; + + if (stv090x_algo(state) == STV090x_RANGEOK) { + dprintk(FE_DEBUG, 1, "Search success!"); + return DVBFE_ALGO_SEARCH_SUCCESS; + } else { + dprintk(FE_DEBUG, 1, "Search failed!"); + return DVBFE_ALGO_SEARCH_FAILED; + } + + return DVBFE_ALGO_SEARCH_ERROR; +} + +/* FIXME! */ +static int stv090x_read_status(struct dvb_frontend *fe, enum fe_status *status) +{ + struct stv090x_state *state = fe->demodulator_priv; + u32 reg; + u8 search_state; + + reg = STV090x_READ_DEMOD(state, DMDSTATE); + search_state = STV090x_GETFIELD_Px(reg, HEADER_MODE_FIELD); + + switch (search_state) { + case 0: /* searching */ + case 1: /* first PLH detected */ + default: + dprintk(FE_DEBUG, 1, "Status: Unlocked (Searching ..)"); + *status = 0; + break; + + case 2: /* DVB-S2 mode */ + dprintk(FE_DEBUG, 1, "Delivery system: DVB-S2"); + reg = STV090x_READ_DEMOD(state, DSTATUS); + if (STV090x_GETFIELD_Px(reg, LOCK_DEFINITIF_FIELD)) { + reg = STV090x_READ_DEMOD(state, TSSTATUS); + if (STV090x_GETFIELD_Px(reg, TSFIFO_LINEOK_FIELD)) { + *status = FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; + } + } + break; + + case 3: /* DVB-S1/legacy mode */ + dprintk(FE_DEBUG, 1, "Delivery system: DVB-S"); + reg = STV090x_READ_DEMOD(state, DSTATUS); + if (STV090x_GETFIELD_Px(reg, LOCK_DEFINITIF_FIELD)) { + reg = STV090x_READ_DEMOD(state, VSTATUSVIT); + if (STV090x_GETFIELD_Px(reg, LOCKEDVIT_FIELD)) { + reg = STV090x_READ_DEMOD(state, TSSTATUS); + if (STV090x_GETFIELD_Px(reg, TSFIFO_LINEOK_FIELD)) { + *status = FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; + } + } + } + break; + } + + return 0; +} + +static int stv090x_read_per(struct dvb_frontend *fe, u32 *per) +{ + struct stv090x_state *state = fe->demodulator_priv; + + s32 count_4, count_3, count_2, count_1, count_0, count; + u32 reg, h, m, l; + enum fe_status status; + + stv090x_read_status(fe, &status); + if (!(status & FE_HAS_LOCK)) { + *per = 1 << 23; /* Max PER */ + } else { + /* Counter 2 */ + reg = STV090x_READ_DEMOD(state, ERRCNT22); + h = STV090x_GETFIELD_Px(reg, ERR_CNT2_FIELD); + + reg = STV090x_READ_DEMOD(state, ERRCNT21); + m = STV090x_GETFIELD_Px(reg, ERR_CNT21_FIELD); + + reg = STV090x_READ_DEMOD(state, ERRCNT20); + l = STV090x_GETFIELD_Px(reg, ERR_CNT20_FIELD); + + *per = ((h << 16) | (m << 8) | l); + + count_4 = STV090x_READ_DEMOD(state, FBERCPT4); + count_3 = STV090x_READ_DEMOD(state, FBERCPT3); + count_2 = STV090x_READ_DEMOD(state, FBERCPT2); + count_1 = STV090x_READ_DEMOD(state, FBERCPT1); + count_0 = STV090x_READ_DEMOD(state, FBERCPT0); + + if ((!count_4) && (!count_3)) { + count = (count_2 & 0xff) << 16; + count |= (count_1 & 0xff) << 8; + count |= count_0 & 0xff; + } else { + count = 1 << 24; + } + if (count == 0) + *per = 1; + } + if (STV090x_WRITE_DEMOD(state, FBERCPT4, 0) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, ERRCTRL2, 0xc1) < 0) + goto err; + + return 0; +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static int stv090x_table_lookup(const struct stv090x_tab *tab, int max, int val) +{ + int res = 0; + int min = 0, med; + + if (val < tab[min].read) + res = tab[min].real; + else if (val >= tab[max].read) + res = tab[max].real; + else { + while ((max - min) > 1) { + med = (max + min) / 2; + if (val >= tab[min].read && val < tab[med].read) + max = med; + else + min = med; + } + res = ((val - tab[min].read) * + (tab[max].real - tab[min].real) / + (tab[max].read - tab[min].read)) + + tab[min].real; + } + + return res; +} + +static int stv090x_read_signal_strength(struct dvb_frontend *fe, u16 *strength) +{ + struct stv090x_state *state = fe->demodulator_priv; + u32 reg; + s32 agc; + + reg = STV090x_READ_DEMOD(state, AGCIQIN1); + agc = STV090x_GETFIELD_Px(reg, AGCIQ_VALUE_FIELD); + + *strength = stv090x_table_lookup(stv090x_rf_tab, ARRAY_SIZE(stv090x_rf_tab) - 1, agc); + if (agc > stv090x_rf_tab[0].read) + *strength = 5; + else if (agc < stv090x_rf_tab[ARRAY_SIZE(stv090x_rf_tab) - 1].read) + *strength = -100; + + return 0; +} + +static int stv090x_read_cnr(struct dvb_frontend *fe, u16 *cnr) +{ + struct stv090x_state *state = fe->demodulator_priv; + u32 reg_0, reg_1, reg, i; + s32 val_0, val_1, val = 0; + u8 lock_f; + + switch (state->delsys) { + case STV090x_DVBS2: + reg = STV090x_READ_DEMOD(state, DSTATUS); + lock_f = STV090x_GETFIELD_Px(reg, LOCK_DEFINITIF_FIELD); + if (lock_f) { + msleep(5); + for (i = 0; i < 16; i++) { + reg_1 = STV090x_READ_DEMOD(state, NNOSPLHT1); + val_1 = STV090x_GETFIELD_Px(reg_1, NOSPLHT_NORMED_FIELD); + reg_0 = STV090x_READ_DEMOD(state, NNOSPLHT0); + val_0 = STV090x_GETFIELD_Px(reg_1, NOSPLHT_NORMED_FIELD); + val += MAKEWORD16(val_1, val_0); + msleep(1); + } + val /= 16; + *cnr = stv090x_table_lookup(stv090x_s2cn_tab, ARRAY_SIZE(stv090x_s2cn_tab) - 1, val); + if (val < stv090x_s2cn_tab[ARRAY_SIZE(stv090x_s2cn_tab) - 1].read) + *cnr = 1000; + } + break; + + case STV090x_DVBS1: + case STV090x_DSS: + reg = STV090x_READ_DEMOD(state, DSTATUS); + lock_f = STV090x_GETFIELD_Px(reg, LOCK_DEFINITIF_FIELD); + if (lock_f) { + msleep(5); + for (i = 0; i < 16; i++) { + reg_1 = STV090x_READ_DEMOD(state, NOSDATAT1); + val_1 = STV090x_GETFIELD_Px(reg_1, NOSDATAT_UNNORMED_FIELD); + reg_0 = STV090x_READ_DEMOD(state, NOSDATAT0); + val_0 = STV090x_GETFIELD_Px(reg_1, NOSDATAT_UNNORMED_FIELD); + val += MAKEWORD16(val_1, val_0); + msleep(1); + } + val /= 16; + *cnr = stv090x_table_lookup(stv090x_s1cn_tab, ARRAY_SIZE(stv090x_s1cn_tab) - 1, val); + if (val < stv090x_s2cn_tab[ARRAY_SIZE(stv090x_s1cn_tab) - 1].read) + *cnr = 1000; + } + break; + default: + break; + } + + return 0; +} + +static int stv090x_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) +{ + struct stv090x_state *state = fe->demodulator_priv; + u32 reg; + + reg = STV090x_READ_DEMOD(state, DISTXCTL); + switch (tone) { + case SEC_TONE_ON: + STV090x_SETFIELD_Px(reg, DISTX_MODE_FIELD, 0); + STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 1); + if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0) + goto err; + STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 0); + if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0) + goto err; + break; + + case SEC_TONE_OFF: + STV090x_SETFIELD_Px(reg, DISTX_MODE_FIELD, 0); + STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 1); + if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0) + goto err; + break; + default: + return -EINVAL; + } + + return 0; +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + + +static enum dvbfe_algo stv090x_frontend_algo(struct dvb_frontend *fe) +{ + return DVBFE_ALGO_CUSTOM; +} + +static int stv090x_send_diseqc_msg(struct dvb_frontend *fe, struct dvb_diseqc_master_cmd *cmd) +{ + struct stv090x_state *state = fe->demodulator_priv; + u32 reg, idle = 0, fifo_full = 1; + int i; + + reg = STV090x_READ_DEMOD(state, DISTXCTL); + + STV090x_SETFIELD_Px(reg, DISTX_MODE_FIELD, 2); + STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 1); + if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0) + goto err; + STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 0); + if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0) + goto err; + + STV090x_SETFIELD_Px(reg, DIS_PRECHARGE_FIELD, 1); + if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0) + goto err; + + for (i = 0; i < cmd->msg_len; i++) { + + while (fifo_full) { + reg = STV090x_READ_DEMOD(state, DISTXSTATUS); + fifo_full = STV090x_GETFIELD_Px(reg, FIFO_FULL_FIELD); + } + + if (STV090x_WRITE_DEMOD(state, DISTXDATA, cmd->msg[i]) < 0) + goto err; + } + reg = STV090x_READ_DEMOD(state, DISTXCTL); + STV090x_SETFIELD_Px(reg, DIS_PRECHARGE_FIELD, 0); + if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0) + goto err; + + i = 0; + + while ((!idle) && (i < 10)) { + reg = STV090x_READ_DEMOD(state, DISTXSTATUS); + idle = STV090x_GETFIELD_Px(reg, TX_IDLE_FIELD); + msleep(10); + i++; + } + + return 0; +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static int stv090x_send_diseqc_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t burst) +{ + struct stv090x_state *state = fe->demodulator_priv; + u32 reg, idle = 0, fifo_full = 1; + u8 mode, value; + int i; + + reg = STV090x_READ_DEMOD(state, DISTXCTL); + + if (burst == SEC_MINI_A) { + mode = 3; + value = 0x00; + } else { + mode = 2; + value = 0xFF; + } + + STV090x_SETFIELD_Px(reg, DISTX_MODE_FIELD, mode); + STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 1); + if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0) + goto err; + STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 0); + if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0) + goto err; + + STV090x_SETFIELD_Px(reg, DIS_PRECHARGE_FIELD, 1); + if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0) + goto err; + + while (fifo_full) { + reg = STV090x_READ_DEMOD(state, DISTXSTATUS); + fifo_full = STV090x_GETFIELD_Px(reg, FIFO_FULL_FIELD); + } + + if (STV090x_WRITE_DEMOD(state, DISTXDATA, value) < 0) + goto err; + + reg = STV090x_READ_DEMOD(state, DISTXCTL); + STV090x_SETFIELD_Px(reg, DIS_PRECHARGE_FIELD, 0); + if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0) + goto err; + + i = 0; + + while ((!idle) && (i < 10)) { + reg = STV090x_READ_DEMOD(state, DISTXSTATUS); + idle = STV090x_GETFIELD_Px(reg, TX_IDLE_FIELD); + msleep(10); + i++; + } + + return 0; +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static int stv090x_recv_slave_reply(struct dvb_frontend *fe, struct dvb_diseqc_slave_reply *reply) +{ + struct stv090x_state *state = fe->demodulator_priv; + u32 reg = 0, i = 0, rx_end = 0; + + while ((rx_end != 1) && (i < 10)) { + msleep(10); + i++; + reg = STV090x_READ_DEMOD(state, DISRX_ST0); + rx_end = STV090x_GETFIELD_Px(reg, RX_END_FIELD); + } + + if (rx_end) { + reply->msg_len = STV090x_GETFIELD_Px(reg, FIFO_BYTENBR_FIELD); + for (i = 0; i < reply->msg_len; i++) + reply->msg[i] = STV090x_READ_DEMOD(state, DISRXDATA); + } + + return 0; +} + +static int stv090x_sleep(struct dvb_frontend *fe) +{ + struct stv090x_state *state = fe->demodulator_priv; + u32 reg; + + dprintk(FE_DEBUG, 1, "Set %s to sleep", + state->device == STV0900 ? "STV0900" : "STV0903"); + + reg = stv090x_read_reg(state, STV090x_SYNTCTRL); + STV090x_SETFIELD(reg, STANDBY_FIELD, 0x01); + if (stv090x_write_reg(state, STV090x_SYNTCTRL, reg) < 0) + goto err; + + reg = stv090x_read_reg(state, STV090x_TSTTNR1); + STV090x_SETFIELD(reg, ADC1_PON_FIELD, 0); + if (stv090x_write_reg(state, STV090x_TSTTNR1, reg) < 0) + goto err; + + return 0; +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static int stv090x_wakeup(struct dvb_frontend *fe) +{ + struct stv090x_state *state = fe->demodulator_priv; + u32 reg; + + dprintk(FE_DEBUG, 1, "Wake %s from standby", + state->device == STV0900 ? "STV0900" : "STV0903"); + + reg = stv090x_read_reg(state, STV090x_SYNTCTRL); + STV090x_SETFIELD(reg, STANDBY_FIELD, 0x00); + if (stv090x_write_reg(state, STV090x_SYNTCTRL, reg) < 0) + goto err; + + reg = stv090x_read_reg(state, STV090x_TSTTNR1); + STV090x_SETFIELD(reg, ADC1_PON_FIELD, 1); + if (stv090x_write_reg(state, STV090x_TSTTNR1, reg) < 0) + goto err; + + return 0; +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static void stv090x_release(struct dvb_frontend *fe) +{ + struct stv090x_state *state = fe->demodulator_priv; + + kfree(state); +} + +static int stv090x_ldpc_mode(struct stv090x_state *state, enum stv090x_mode ldpc_mode) +{ + u32 reg = 0; + + switch (ldpc_mode) { + case STV090x_DUAL: + default: + if ((state->demod_mode != STV090x_DUAL) || (STV090x_GETFIELD(reg, DDEMOD_FIELD) != 1)) { + /* set LDPC to dual mode */ + if (stv090x_write_reg(state, STV090x_GENCFG, 0x1d) < 0) + goto err; + + state->demod_mode = STV090x_DUAL; + + reg = stv090x_read_reg(state, STV090x_TSTRES0); + STV090x_SETFIELD(reg, FRESFEC_FIELD, 0x1); + if (stv090x_write_reg(state, STV090x_TSTRES0, reg) < 0) + goto err; + STV090x_SETFIELD(reg, FRESFEC_FIELD, 0x0); + if (stv090x_write_reg(state, STV090x_TSTRES0, reg) < 0) + goto err; + + if (STV090x_WRITE_DEMOD(state, MODCODLST0, 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST1, 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST2, 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST3, 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST4, 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST5, 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST6, 0xff) < 0) + goto err; + + if (STV090x_WRITE_DEMOD(state, MODCODLST7, 0xcc) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST8, 0xcc) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLST9, 0xcc) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLSTA, 0xcc) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLSTB, 0xcc) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLSTC, 0xcc) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLSTD, 0xcc) < 0) + goto err; + + if (STV090x_WRITE_DEMOD(state, MODCODLSTE, 0xff) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, MODCODLSTF, 0xcf) < 0) + goto err; + } + break; + + case STV090x_SINGLE: + if (stv090x_stop_modcod(state) < 0) + goto err; + if (stv090x_activate_modcod_single(state) < 0) + goto err; + + if (state->demod == STV090x_DEMODULATOR_1) { + if (stv090x_write_reg(state, STV090x_GENCFG, 0x06) < 0) /* path 2 */ + goto err; + } else { + if (stv090x_write_reg(state, STV090x_GENCFG, 0x04) < 0) /* path 1 */ + goto err; + } + + reg = stv090x_read_reg(state, STV090x_TSTRES0); + STV090x_SETFIELD(reg, FRESFEC_FIELD, 0x1); + if (stv090x_write_reg(state, STV090x_TSTRES0, reg) < 0) + goto err; + STV090x_SETFIELD(reg, FRESFEC_FIELD, 0x0); + if (stv090x_write_reg(state, STV090x_TSTRES0, reg) < 0) + goto err; + + reg = STV090x_READ_DEMOD(state, PDELCTRL1); + STV090x_SETFIELD_Px(reg, ALGOSWRST_FIELD, 0x01); + if (STV090x_WRITE_DEMOD(state, PDELCTRL1, reg) < 0) + goto err; + STV090x_SETFIELD_Px(reg, ALGOSWRST_FIELD, 0x00); + if (STV090x_WRITE_DEMOD(state, PDELCTRL1, reg) < 0) + goto err; + break; + } + + return 0; +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +/* return (Hz), clk in Hz*/ +static u32 stv090x_get_mclk(struct stv090x_state *state) +{ + const struct stv090x_config *config = state->config; + u32 div, reg; + u8 ratio; + + div = stv090x_read_reg(state, STV090x_NCOARSE); + reg = stv090x_read_reg(state, STV090x_SYNTCTRL); + ratio = STV090x_GETFIELD(reg, SELX1RATIO_FIELD) ? 4 : 6; + + return (div + 1) * config->xtal / ratio; /* kHz */ +} + +static int stv090x_set_mclk(struct stv090x_state *state, u32 mclk, u32 clk) +{ + const struct stv090x_config *config = state->config; + u32 reg, div, clk_sel; + + reg = stv090x_read_reg(state, STV090x_SYNTCTRL); + clk_sel = ((STV090x_GETFIELD(reg, SELX1RATIO_FIELD) == 1) ? 4 : 6); + + div = ((clk_sel * mclk) / config->xtal) - 1; + + reg = stv090x_read_reg(state, STV090x_NCOARSE); + STV090x_SETFIELD(reg, M_DIV_FIELD, div); + if (stv090x_write_reg(state, STV090x_NCOARSE, reg) < 0) + goto err; + + state->mclk = stv090x_get_mclk(state); + + /*Set the DiseqC frequency to 22KHz */ + div = state->mclk / 704000; + if (STV090x_WRITE_DEMOD(state, F22TX, div) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, F22RX, div) < 0) + goto err; + + return 0; +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static int stv090x_set_tspath(struct stv090x_state *state) +{ + u32 reg; + + if (state->dev_ver >= 0x20) { + switch (state->config->ts1_mode) { + case STV090x_TSMODE_PARALLEL_PUNCTURED: + case STV090x_TSMODE_DVBCI: + switch (state->config->ts2_mode) { + case STV090x_TSMODE_SERIAL_PUNCTURED: + case STV090x_TSMODE_SERIAL_CONTINUOUS: + default: + stv090x_write_reg(state, STV090x_TSGENERAL, 0x00); + break; + + case STV090x_TSMODE_PARALLEL_PUNCTURED: + case STV090x_TSMODE_DVBCI: + if (stv090x_write_reg(state, STV090x_TSGENERAL, 0x06) < 0) /* Mux'd stream mode */ + goto err; + reg = stv090x_read_reg(state, STV090x_P1_TSCFGM); + STV090x_SETFIELD_Px(reg, TSFIFO_MANSPEED_FIELD, 3); + if (stv090x_write_reg(state, STV090x_P1_TSCFGM, reg) < 0) + goto err; + reg = stv090x_read_reg(state, STV090x_P2_TSCFGM); + STV090x_SETFIELD_Px(reg, TSFIFO_MANSPEED_FIELD, 3); + if (stv090x_write_reg(state, STV090x_P2_TSCFGM, reg) < 0) + goto err; + if (stv090x_write_reg(state, STV090x_P1_TSSPEED, 0x14) < 0) + goto err; + if (stv090x_write_reg(state, STV090x_P2_TSSPEED, 0x28) < 0) + goto err; + break; + } + break; + + case STV090x_TSMODE_SERIAL_PUNCTURED: + case STV090x_TSMODE_SERIAL_CONTINUOUS: + default: + switch (state->config->ts2_mode) { + case STV090x_TSMODE_SERIAL_PUNCTURED: + case STV090x_TSMODE_SERIAL_CONTINUOUS: + default: + if (stv090x_write_reg(state, STV090x_TSGENERAL, 0x0c) < 0) + goto err; + break; + + case STV090x_TSMODE_PARALLEL_PUNCTURED: + case STV090x_TSMODE_DVBCI: + if (stv090x_write_reg(state, STV090x_TSGENERAL, 0x0a) < 0) + goto err; + break; + } + break; + } + } else { + switch (state->config->ts1_mode) { + case STV090x_TSMODE_PARALLEL_PUNCTURED: + case STV090x_TSMODE_DVBCI: + switch (state->config->ts2_mode) { + case STV090x_TSMODE_SERIAL_PUNCTURED: + case STV090x_TSMODE_SERIAL_CONTINUOUS: + default: + stv090x_write_reg(state, STV090x_TSGENERAL1X, 0x10); + break; + + case STV090x_TSMODE_PARALLEL_PUNCTURED: + case STV090x_TSMODE_DVBCI: + stv090x_write_reg(state, STV090x_TSGENERAL1X, 0x16); + reg = stv090x_read_reg(state, STV090x_P1_TSCFGM); + STV090x_SETFIELD_Px(reg, TSFIFO_MANSPEED_FIELD, 3); + if (stv090x_write_reg(state, STV090x_P1_TSCFGM, reg) < 0) + goto err; + reg = stv090x_read_reg(state, STV090x_P1_TSCFGM); + STV090x_SETFIELD_Px(reg, TSFIFO_MANSPEED_FIELD, 0); + if (stv090x_write_reg(state, STV090x_P1_TSCFGM, reg) < 0) + goto err; + if (stv090x_write_reg(state, STV090x_P1_TSSPEED, 0x14) < 0) + goto err; + if (stv090x_write_reg(state, STV090x_P2_TSSPEED, 0x28) < 0) + goto err; + break; + } + break; + + case STV090x_TSMODE_SERIAL_PUNCTURED: + case STV090x_TSMODE_SERIAL_CONTINUOUS: + default: + switch (state->config->ts2_mode) { + case STV090x_TSMODE_SERIAL_PUNCTURED: + case STV090x_TSMODE_SERIAL_CONTINUOUS: + default: + stv090x_write_reg(state, STV090x_TSGENERAL1X, 0x14); + break; + + case STV090x_TSMODE_PARALLEL_PUNCTURED: + case STV090x_TSMODE_DVBCI: + stv090x_write_reg(state, STV090x_TSGENERAL1X, 0x12); + break; + } + break; + } + } + + switch (state->config->ts1_mode) { + case STV090x_TSMODE_PARALLEL_PUNCTURED: + reg = stv090x_read_reg(state, STV090x_P1_TSCFGH); + STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x00); + STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x00); + if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0) + goto err; + break; + + case STV090x_TSMODE_DVBCI: + reg = stv090x_read_reg(state, STV090x_P1_TSCFGH); + STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x00); + STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x01); + if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0) + goto err; + break; + + case STV090x_TSMODE_SERIAL_PUNCTURED: + reg = stv090x_read_reg(state, STV090x_P1_TSCFGH); + STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x01); + STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x00); + if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0) + goto err; + break; + + case STV090x_TSMODE_SERIAL_CONTINUOUS: + reg = stv090x_read_reg(state, STV090x_P1_TSCFGH); + STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x01); + STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x01); + if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0) + goto err; + break; + + default: + break; + } + + switch (state->config->ts2_mode) { + case STV090x_TSMODE_PARALLEL_PUNCTURED: + reg = stv090x_read_reg(state, STV090x_P2_TSCFGH); + STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x00); + STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x00); + if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0) + goto err; + break; + + case STV090x_TSMODE_DVBCI: + reg = stv090x_read_reg(state, STV090x_P2_TSCFGH); + STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x00); + STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x01); + if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0) + goto err; + break; + + case STV090x_TSMODE_SERIAL_PUNCTURED: + reg = stv090x_read_reg(state, STV090x_P2_TSCFGH); + STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x01); + STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x00); + if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0) + goto err; + break; + + case STV090x_TSMODE_SERIAL_CONTINUOUS: + reg = stv090x_read_reg(state, STV090x_P2_TSCFGH); + STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x01); + STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x01); + if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0) + goto err; + break; + + default: + break; + } + reg = stv090x_read_reg(state, STV090x_P2_TSCFGH); + STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0x01); + if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0) + goto err; + STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0x00); + if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0) + goto err; + + reg = stv090x_read_reg(state, STV090x_P1_TSCFGH); + STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0x01); + if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0) + goto err; + STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0x00); + if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0) + goto err; + + return 0; +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static int stv090x_init(struct dvb_frontend *fe) +{ + struct stv090x_state *state = fe->demodulator_priv; + const struct stv090x_config *config = state->config; + u32 reg; + + if (stv090x_wakeup(fe) < 0) { + dprintk(FE_ERROR, 1, "Error waking device"); + goto err; + } + + if (stv090x_ldpc_mode(state, state->demod_mode) < 0) + goto err; + + reg = STV090x_READ_DEMOD(state, TNRCFG2); + STV090x_SETFIELD_Px(reg, TUN_IQSWAP_FIELD, state->inversion); + if (STV090x_WRITE_DEMOD(state, TNRCFG2, reg) < 0) + goto err; + reg = STV090x_READ_DEMOD(state, DEMOD); + STV090x_SETFIELD_Px(reg, ROLLOFF_CONTROL_FIELD, state->rolloff); + if (STV090x_WRITE_DEMOD(state, DEMOD, reg) < 0) + goto err; + + if (stv090x_i2c_gate_ctrl(fe, 1) < 0) + goto err; + + if (config->tuner_set_mode) { + if (config->tuner_set_mode(fe, TUNER_WAKE) < 0) + goto err; + } + + if (config->tuner_init) { + if (config->tuner_init(fe) < 0) + goto err; + } + + if (stv090x_i2c_gate_ctrl(fe, 0) < 0) + goto err; + + if (stv090x_set_tspath(state) < 0) + goto err; + + return 0; +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static int stv090x_setup(struct dvb_frontend *fe) +{ + struct stv090x_state *state = fe->demodulator_priv; + const struct stv090x_config *config = state->config; + const struct stv090x_reg *stv090x_initval = NULL; + const struct stv090x_reg *stv090x_cut20_val = NULL; + unsigned long t1_size = 0, t2_size = 0; + u32 reg = 0; + + int i; + + if (state->device == STV0900) { + dprintk(FE_DEBUG, 1, "Initializing STV0900"); + stv090x_initval = stv0900_initval; + t1_size = ARRAY_SIZE(stv0900_initval); + stv090x_cut20_val = stv0900_cut20_val; + t2_size = ARRAY_SIZE(stv0900_cut20_val); + } else if (state->device == STV0903) { + dprintk(FE_DEBUG, 1, "Initializing STV0903"); + stv090x_initval = stv0903_initval; + t1_size = ARRAY_SIZE(stv0903_initval); + stv090x_cut20_val = stv0903_cut20_val; + t2_size = ARRAY_SIZE(stv0903_cut20_val); + } + + /* STV090x init */ + if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x5c) < 0) /* Stop Demod */ + goto err; + + msleep(5); + + if (STV090x_WRITE_DEMOD(state, TNRCFG, 0x6c) < 0) /* check register ! (No Tuner Mode) */ + goto err; + + STV090x_SETFIELD_Px(reg, ENARPT_LEVEL_FIELD, config->repeater_level); + if (STV090x_WRITE_DEMOD(state, I2CRPT, reg) < 0) /* repeater OFF */ + goto err; + + if (stv090x_write_reg(state, STV090x_NCOARSE, 0x13) < 0) /* set PLL divider */ + goto err; + msleep(5); + if (stv090x_write_reg(state, STV090x_I2CCFG, 0x08) < 0) /* 1/41 oversampling */ + goto err; + if (stv090x_write_reg(state, STV090x_SYNTCTRL, 0x20 | config->clk_mode) < 0) /* enable PLL */ + goto err; + msleep(5); + + /* write initval */ + dprintk(FE_DEBUG, 1, "Setting up initial values"); + for (i = 0; i < t1_size; i++) { + if (stv090x_write_reg(state, stv090x_initval[i].addr, stv090x_initval[i].data) < 0) + goto err; + } + + state->dev_ver = stv090x_read_reg(state, STV090x_MID); + if (state->dev_ver >= 0x20) { + if (stv090x_write_reg(state, STV090x_TSGENERAL, 0x0c) < 0) + goto err; + + /* write cut20_val*/ + dprintk(FE_DEBUG, 1, "Setting up Cut 2.0 initial values"); + for (i = 0; i < t2_size; i++) { + if (stv090x_write_reg(state, stv090x_cut20_val[i].addr, stv090x_cut20_val[i].data) < 0) + goto err; + } + + } else if (state->dev_ver < 0x20) { + dprintk(FE_ERROR, 1, "ERROR: Unsupported Cut: 0x%02x!", + state->dev_ver); + + goto err; + } else if (state->dev_ver > 0x30) { + /* we shouldn't bail out from here */ + dprintk(FE_ERROR, 1, "INFO: Cut: 0x%02x probably incomplete support!", + state->dev_ver); + } + + if (stv090x_write_reg(state, STV090x_TSTRES0, 0x80) < 0) + goto err; + if (stv090x_write_reg(state, STV090x_TSTRES0, 0x00) < 0) + goto err; + + stv090x_set_mclk(state, 135000000, config->xtal); /* 135 Mhz */ + msleep(5); + if (stv090x_write_reg(state, STV090x_SYNTCTRL, 0x20 | config->clk_mode) < 0) + goto err; + stv090x_get_mclk(state); + + return 0; +err: + dprintk(FE_ERROR, 1, "I/O error"); + return -1; +} + +static struct dvb_frontend_ops stv090x_ops = { + + .info = { + .name = "STV090x Multistandard", + .type = FE_QPSK, + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_stepsize = 0, + .frequency_tolerance = 0, + .symbol_rate_min = 1000000, + .symbol_rate_max = 45000000, + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_AUTO | + FE_CAN_QPSK | + FE_CAN_2G_MODULATION + }, + + .release = stv090x_release, + .init = stv090x_init, + + .sleep = stv090x_sleep, + .get_frontend_algo = stv090x_frontend_algo, + + .i2c_gate_ctrl = stv090x_i2c_gate_ctrl, + + .diseqc_send_master_cmd = stv090x_send_diseqc_msg, + .diseqc_send_burst = stv090x_send_diseqc_burst, + .diseqc_recv_slave_reply = stv090x_recv_slave_reply, + .set_tone = stv090x_set_tone, + + .search = stv090x_search, + .read_status = stv090x_read_status, + .read_ber = stv090x_read_per, + .read_signal_strength = stv090x_read_signal_strength, + .read_snr = stv090x_read_cnr +}; + + +struct dvb_frontend *stv090x_attach(const struct stv090x_config *config, + struct i2c_adapter *i2c, + enum stv090x_demodulator demod) +{ + struct stv090x_state *state = NULL; + + state = kzalloc(sizeof (struct stv090x_state), GFP_KERNEL); + if (state == NULL) + goto error; + + state->verbose = &verbose; + state->config = config; + state->i2c = i2c; + state->frontend.ops = stv090x_ops; + state->frontend.demodulator_priv = state; + state->demod = demod; + state->demod_mode = config->demod_mode; /* Single or Dual mode */ + state->device = config->device; + state->rolloff = STV090x_RO_35; /* default */ + + if (state->demod == STV090x_DEMODULATOR_0) + mutex_init(&demod_lock); + + if (stv090x_sleep(&state->frontend) < 0) { + dprintk(FE_ERROR, 1, "Error putting device to sleep"); + goto error; + } + + if (stv090x_setup(&state->frontend) < 0) { + dprintk(FE_ERROR, 1, "Error setting up device"); + goto error; + } + if (stv090x_wakeup(&state->frontend) < 0) { + dprintk(FE_ERROR, 1, "Error waking device"); + goto error; + } + + dprintk(FE_ERROR, 1, "Attaching %s demodulator(%d) Cut=0x%02x\n", + state->device == STV0900 ? "STV0900" : "STV0903", + demod, + state->dev_ver); + + return &state->frontend; + +error: + kfree(state); + return NULL; +} +EXPORT_SYMBOL(stv090x_attach); +MODULE_PARM_DESC(verbose, "Set Verbosity level"); +MODULE_AUTHOR("Manu Abraham"); +MODULE_DESCRIPTION("STV090x Multi-Std Broadcast frontend"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/stv090x.h b/drivers/media/dvb/frontends/stv090x.h new file mode 100644 index 000000000000..e968c98bb70f --- /dev/null +++ b/drivers/media/dvb/frontends/stv090x.h @@ -0,0 +1,106 @@ +/* + STV0900/0903 Multistandard Broadcast Frontend driver + Copyright (C) Manu Abraham + + Copyright (C) ST Microelectronics + + 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 __STV090x_H +#define __STV090x_H + +enum stv090x_demodulator { + STV090x_DEMODULATOR_0 = 1, + STV090x_DEMODULATOR_1 +}; + +enum stv090x_device { + STV0903 = 0, + STV0900, +}; + +enum stv090x_mode { + STV090x_DUAL = 0, + STV090x_SINGLE +}; + +enum stv090x_tsmode { + STV090x_TSMODE_SERIAL_PUNCTURED = 1, + STV090x_TSMODE_SERIAL_CONTINUOUS, + STV090x_TSMODE_PARALLEL_PUNCTURED, + STV090x_TSMODE_DVBCI +}; + +enum stv090x_clkmode { + STV090x_CLK_INT = 0, /* Clk i/p = CLKI */ + STV090x_CLK_EXT = 2 /* Clk i/p = XTALI */ +}; + +enum stv090x_i2crpt { + STV090x_RPTLEVEL_256 = 0, + STV090x_RPTLEVEL_128 = 1, + STV090x_RPTLEVEL_64 = 2, + STV090x_RPTLEVEL_32 = 3, + STV090x_RPTLEVEL_16 = 4, + STV090x_RPTLEVEL_8 = 5, + STV090x_RPTLEVEL_4 = 6, + STV090x_RPTLEVEL_2 = 7, +}; + +struct stv090x_config { + enum stv090x_device device; + enum stv090x_mode demod_mode; + enum stv090x_clkmode clk_mode; + + u32 xtal; /* default: 8000000 */ + u8 address; /* default: 0x68 */ + + u32 ref_clk; /* default: 16000000 FIXME to tuner config */ + + u8 ts1_mode; + u8 ts2_mode; + + enum stv090x_i2crpt repeater_level; + + int (*tuner_init) (struct dvb_frontend *fe); + int (*tuner_set_mode) (struct dvb_frontend *fe, enum tuner_mode mode); + int (*tuner_set_frequency) (struct dvb_frontend *fe, u32 frequency); + int (*tuner_get_frequency) (struct dvb_frontend *fe, u32 *frequency); + int (*tuner_set_bandwidth) (struct dvb_frontend *fe, u32 bandwidth); + int (*tuner_get_bandwidth) (struct dvb_frontend *fe, u32 *bandwidth); + int (*tuner_set_bbgain) (struct dvb_frontend *fe, u32 gain); + int (*tuner_get_bbgain) (struct dvb_frontend *fe, u32 *gain); + int (*tuner_set_refclk) (struct dvb_frontend *fe, u32 refclk); + int (*tuner_get_status) (struct dvb_frontend *fe, u32 *status); +}; + +#if defined(CONFIG_DVB_STV090x) || (defined(CONFIG_DVB_STV090x_MODULE) && defined(MODULE)) + +extern struct dvb_frontend *stv090x_attach(const struct stv090x_config *config, + struct i2c_adapter *i2c, + enum stv090x_demodulator demod); +#else + +static inline struct dvb_frontend *stv090x_attach(const struct stv090x_config *config, + struct i2c_adapter *i2c, + enum stv090x_demodulator demod) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif /* CONFIG_DVB_STV090x */ + +#endif /* __STV090x_H */ diff --git a/drivers/media/dvb/frontends/stv090x_priv.h b/drivers/media/dvb/frontends/stv090x_priv.h new file mode 100644 index 000000000000..5a4a01740d88 --- /dev/null +++ b/drivers/media/dvb/frontends/stv090x_priv.h @@ -0,0 +1,269 @@ +/* + STV0900/0903 Multistandard Broadcast Frontend driver + Copyright (C) Manu Abraham + + Copyright (C) ST Microelectronics + + 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 __STV090x_PRIV_H +#define __STV090x_PRIV_H + +#include "dvb_frontend.h" + +#define FE_ERROR 0 +#define FE_NOTICE 1 +#define FE_INFO 2 +#define FE_DEBUG 3 +#define FE_DEBUGREG 4 + +#define dprintk(__y, __z, format, arg...) do { \ + if (__z) { \ + if ((verbose > FE_ERROR) && (verbose > __y)) \ + printk(KERN_ERR "%s: " format "\n", __func__ , ##arg); \ + else if ((verbose > FE_NOTICE) && (verbose > __y)) \ + printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg); \ + else if ((verbose > FE_INFO) && (verbose > __y)) \ + printk(KERN_INFO "%s: " format "\n", __func__ , ##arg); \ + else if ((verbose > FE_DEBUG) && (verbose > __y)) \ + printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg); \ + } else { \ + if (verbose > __y) \ + printk(format, ##arg); \ + } \ +} while (0) + +#define STV090x_READ_DEMOD(__state, __reg) (( \ + (__state)->demod == STV090x_DEMODULATOR_1) ? \ + stv090x_read_reg(__state, STV090x_P2_##__reg) : \ + stv090x_read_reg(__state, STV090x_P1_##__reg)) + +#define STV090x_WRITE_DEMOD(__state, __reg, __data) (( \ + (__state)->demod == STV090x_DEMODULATOR_1) ? \ + stv090x_write_reg(__state, STV090x_P2_##__reg, __data) :\ + stv090x_write_reg(__state, STV090x_P1_##__reg, __data)) + +#define STV090x_ADDR_OFFST(__state, __x) (( \ + (__state->demod) == STV090x_DEMODULATOR_1) ? \ + STV090x_P1_##__x : \ + STV090x_P2_##__x) + + +#define STV090x_SETFIELD(mask, bitf, val) (mask = (mask & (~(((1 << STV090x_WIDTH_##bitf) - 1) <<\ + STV090x_OFFST_##bitf))) | \ + (val << STV090x_OFFST_##bitf)) + +#define STV090x_GETFIELD(val, bitf) ((val >> STV090x_OFFST_##bitf) & ((1 << STV090x_WIDTH_##bitf) - 1)) + + +#define STV090x_SETFIELD_Px(mask, bitf, val) (mask = (mask & (~(((1 << STV090x_WIDTH_Px_##bitf) - 1) <<\ + STV090x_OFFST_Px_##bitf))) | \ + (val << STV090x_OFFST_Px_##bitf)) + +#define STV090x_GETFIELD_Px(val, bitf) ((val >> STV090x_OFFST_Px_##bitf) & ((1 << STV090x_WIDTH_Px_##bitf) - 1)) + +#define MAKEWORD16(__a, __b) (((__a) << 8) | (__b)) + +#define MSB(__x) ((__x >> 8) & 0xff) +#define LSB(__x) (__x & 0xff) + + +#define STV090x_IQPOWER_THRESHOLD 30 +#define STV090x_SEARCH_AGC2_TH_CUT20 700 +#define STV090x_SEARCH_AGC2_TH_CUT30 1200 + +#define STV090x_SEARCH_AGC2_TH(__ver) \ + ((__ver <= 0x20) ? \ + STV090x_SEARCH_AGC2_TH_CUT20 : \ + STV090x_SEARCH_AGC2_TH_CUT30) + +enum stv090x_signal_state { + STV090x_NOCARRIER, + STV090x_NODATA, + STV090x_DATAOK, + STV090x_RANGEOK, + STV090x_OUTOFRANGE +}; + +enum stv090x_fec { + STV090x_PR12 = 0, + STV090x_PR23, + STV090x_PR34, + STV090x_PR45, + STV090x_PR56, + STV090x_PR67, + STV090x_PR78, + STV090x_PR89, + STV090x_PR910, + STV090x_PRERR +}; + +enum stv090x_modulation { + STV090x_QPSK, + STV090x_8PSK, + STV090x_16APSK, + STV090x_32APSK, + STV090x_UNKNOWN +}; + +enum stv090x_frame { + STV090x_LONG_FRAME, + STV090x_SHORT_FRAME +}; + +enum stv090x_pilot { + STV090x_PILOTS_OFF, + STV090x_PILOTS_ON +}; + +enum stv090x_rolloff { + STV090x_RO_35, + STV090x_RO_25, + STV090x_RO_20 +}; + +enum stv090x_inversion { + STV090x_IQ_AUTO, + STV090x_IQ_NORMAL, + STV090x_IQ_SWAP +}; + +enum stv090x_modcod { + STV090x_DUMMY_PLF = 0, + STV090x_QPSK_14, + STV090x_QPSK_13, + STV090x_QPSK_25, + STV090x_QPSK_12, + STV090x_QPSK_35, + STV090x_QPSK_23, + STV090x_QPSK_34, + STV090x_QPSK_45, + STV090x_QPSK_56, + STV090x_QPSK_89, + STV090x_QPSK_910, + STV090x_8PSK_35, + STV090x_8PSK_23, + STV090x_8PSK_34, + STV090x_8PSK_56, + STV090x_8PSK_89, + STV090x_8PSK_910, + STV090x_16APSK_23, + STV090x_16APSK_34, + STV090x_16APSK_45, + STV090x_16APSK_56, + STV090x_16APSK_89, + STV090x_16APSK_910, + STV090x_32APSK_34, + STV090x_32APSK_45, + STV090x_32APSK_56, + STV090x_32APSK_89, + STV090x_32APSK_910, + STV090x_MODCODE_UNKNOWN +}; + +enum stv090x_search { + STV090x_SEARCH_DSS = 0, + STV090x_SEARCH_DVBS1, + STV090x_SEARCH_DVBS2, + STV090x_SEARCH_AUTO +}; + +enum stv090x_algo { + STV090x_BLIND_SEARCH, + STV090x_COLD_SEARCH, + STV090x_WARM_SEARCH +}; + +enum stv090x_delsys { + STV090x_ERROR = 0, + STV090x_DVBS1 = 1, + STV090x_DVBS2, + STV090x_DSS +}; + +struct stv090x_long_frame_crloop { + enum stv090x_modcod modcod; + + u8 crl_pilots_on_2; + u8 crl_pilots_off_2; + u8 crl_pilots_on_5; + u8 crl_pilots_off_5; + u8 crl_pilots_on_10; + u8 crl_pilots_off_10; + u8 crl_pilots_on_20; + u8 crl_pilots_off_20; + u8 crl_pilots_on_30; + u8 crl_pilots_off_30; +}; + +struct stv090x_short_frame_crloop { + enum stv090x_modulation modulation; + + u8 crl_2; /* SR < 3M */ + u8 crl_5; /* 3 < SR <= 7M */ + u8 crl_10; /* 7 < SR <= 15M */ + u8 crl_20; /* 10 < SR <= 25M */ + u8 crl_30; /* 10 < SR <= 45M */ +}; + +struct stv090x_reg { + u16 addr; + u8 data; +}; + +struct stv090x_tab { + s32 real; + s32 read; +}; + +struct stv090x_state { + enum stv090x_device device; + enum stv090x_demodulator demod; + enum stv090x_mode demod_mode; + u32 dev_ver; + + struct i2c_adapter *i2c; + const struct stv090x_config *config; + struct dvb_frontend frontend; + + u32 *verbose; /* Cached module verbosity */ + + enum stv090x_delsys delsys; + enum stv090x_fec fec; + enum stv090x_modulation modulation; + enum stv090x_modcod modcod; + enum stv090x_search search_mode; + enum stv090x_frame frame_len; + enum stv090x_pilot pilots; + enum stv090x_rolloff rolloff; + enum stv090x_inversion inversion; + enum stv090x_algo algo; + + u32 frequency; + u32 srate; + + s32 mclk; /* Masterclock Divider factor */ + s32 tuner_bw; + + u32 tuner_refclk; + + s32 search_range; + + s32 DemodTimeout; + s32 FecTimeout; +}; + +#endif /* __STV090x_PRIV_H */ diff --git a/drivers/media/dvb/frontends/stv090x_reg.h b/drivers/media/dvb/frontends/stv090x_reg.h new file mode 100644 index 000000000000..57b6abbbd32d --- /dev/null +++ b/drivers/media/dvb/frontends/stv090x_reg.h @@ -0,0 +1,2373 @@ +/* + STV0900/0903 Multistandard Broadcast Frontend driver + Copyright (C) Manu Abraham + + Copyright (C) ST Microelectronics + + 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 __STV090x_REG_H +#define __STV090x_REG_H + +#define STV090x_MID 0xf100 +#define STV090x_OFFST_MCHIP_IDENT_FIELD 4 +#define STV090x_WIDTH_MCHIP_IDENT_FIELD 4 +#define STV090x_OFFST_MRELEASE_FIELD 0 +#define STV090x_WIDTH_MRELEASE_FIELD 4 + +#define STV090x_DACR1 0xf113 +#define STV090x_OFFST_DACR1_MODE_FIELD 5 +#define STV090x_WIDTH_DACR1_MODE_FIELD 3 +#define STV090x_OFFST_DACR1_VALUE_FIELD 0 +#define STV090x_WIDTH_DACR1_VALUE_FIELD 4 + +#define STV090x_DACR2 0xf114 +#define STV090x_OFFST_DACR2_VALUE_FIELD 0 +#define STV090x_WIDTH_DACR2_VALUE_FIELD 8 + +#define STV090x_OUTCFG 0xf11c +#define STV090x_OFFST_OUTSERRS1_HZ_FIELD 6 +#define STV090x_WIDTH_OUTSERRS1_HZ_FIELD 1 +#define STV090x_OFFST_OUTSERRS2_HZ_FIELD 5 +#define STV090x_WIDTH_OUTSERRS2_HZ_FIELD 1 +#define STV090x_OFFST_OUTSERRS3_HZ_FIELD 4 +#define STV090x_WIDTH_OUTPARRS3_HZ_FIELD 1 +#define STV090x_OFFST_OUTPARRS3_HZ_FIELD 3 +#define STV090x_WIDTH_OUTPARRS3_HZ_FIELD 1 + +#define STV090x_MODECFG 0xf11d + +#define STV090x_IRQSTATUS3 0xf120 +#define STV090x_OFFST_SPLL_LOCK_FIELD 5 +#define STV090x_WIDTH_SPLL_LOCK_FIELD 1 +#define STV090x_OFFST_SSTREAM_LCK_3_FIELD 4 +#define STV090x_WIDTH_SSTREAM_LCK_3_FIELD 1 +#define STV090x_OFFST_SSTREAM_LCK_2_FIELD 3 +#define STV090x_WIDTH_SSTREAM_LCK_2_FIELD 1 +#define STV090x_OFFST_SSTREAM_LCK_1_FIELD 2 +#define STV090x_WIDTH_SSTREAM_LCK_1_FIELD 1 +#define STV090x_OFFST_SDVBS1_PRF_2_FIELD 1 +#define STV090x_WIDTH_SDVBS1_PRF_2_FIELD 1 +#define STV090x_OFFST_SDVBS1_PRF_1_FIELD 0 +#define STV090x_WIDTH_SDVBS1_PRF_1_FIELD 1 + +#define STV090x_IRQSTATUS2 0xf121 +#define STV090x_OFFST_SSPY_ENDSIM_3_FIELD 7 +#define STV090x_WIDTH_SSPY_ENDSIM_3_FIELD 1 +#define STV090x_OFFST_SSPY_ENDSIM_2_FIELD 6 +#define STV090x_WIDTH_SSPY_ENDSIM_2_FIELD 1 +#define STV090x_OFFST_SSPY_ENDSIM_1_FIELD 5 +#define STV090x_WIDTH_SSPY_ENDSIM_1_FIELD 1 +#define STV090x_OFFST_SPKTDEL_ERROR_2_FIELD 4 +#define STV090x_WIDTH_SPKTDEL_ERROR_2_FIELD 1 +#define STV090x_OFFST_SPKTDEL_LOCKB_2_FIELD 3 +#define STV090x_WIDTH_SPKTDEL_LOCKB_2_FIELD 1 +#define STV090x_OFFST_SPKTDEL_LOCK_2_FIELD 2 +#define STV090x_WIDTH_SPKTDEL_LOCK_2_FIELD 1 +#define STV090x_OFFST_SPKTDEL_ERROR_1_FIELD 1 +#define STV090x_WIDTH_SPKTDEL_ERROR_1_FIELD 1 +#define STV090x_OFFST_SPKTDEL_LOCKB_1_FIELD 0 +#define STV090x_WIDTH_SPKTDEL_LOCKB_1_FIELD 1 + +#define STV090x_IRQSTATUS1 0xf122 +#define STV090x_OFFST_SPKTDEL_LOCK_1_FIELD 7 +#define STV090x_WIDTH_SPKTDEL_LOCK_1_FIELD 1 +#define STV090x_OFFST_SDEMOD_LOCKB_2_FIELD 2 +#define STV090x_WIDTH_SDEMOD_LOCKB_2_FIELD 1 +#define STV090x_OFFST_SDEMOD_LOCK_2_FIELD 1 +#define STV090x_WIDTH_SDEMOD_LOCK_2_FIELD 1 +#define STV090x_OFFST_SDEMOD_IRQ_2_FIELD 0 +#define STV090x_WIDTH_SDEMOD_IRQ_2_FIELD 1 + +#define STV090x_IRQSTATUS0 0xf123 +#define STV090x_OFFST_SDEMOD_LOCKB_1_FIELD 7 +#define STV090x_WIDTH_SDEMOD_LOCKB_1_FIELD 1 +#define STV090x_OFFST_SDEMOD_LOCK_1_FIELD 6 +#define STV090x_WIDTH_SDEMOD_LOCK_1_FIELD 1 +#define STV090x_OFFST_SDEMOD_IRQ_1_FIELD 5 +#define STV090x_WIDTH_SDEMOD_IRQ_1_FIELD 1 +#define STV090x_OFFST_SBCH_ERRFLAG_FIELD 4 +#define STV090x_WIDTH_SBCH_ERRFLAG_FIELD 1 +#define STV090x_OFFST_SDISEQC2RX_IRQ_FIELD 3 +#define STV090x_WIDTH_SDISEQC2RX_IRQ_FIELD 1 +#define STV090x_OFFST_SDISEQC2TX_IRQ_FIELD 2 +#define STV090x_WIDTH_SDISEQC2TX_IRQ_FIELD 1 +#define STV090x_OFFST_SDISEQC1RX_IRQ_FIELD 1 +#define STV090x_WIDTH_SDISEQC1RX_IRQ_FIELD 1 +#define STV090x_OFFST_SDISEQC1TX_IRQ_FIELD 0 +#define STV090x_WIDTH_SDISEQC1TX_IRQ_FIELD 1 + +#define STV090x_IRQMASK3 0xf124 +#define STV090x_OFFST_MPLL_LOCK_FIELD 5 +#define STV090x_WIDTH_MPLL_LOCK_FIELD 1 +#define STV090x_OFFST_MSTREAM_LCK_3_FIELD 2 +#define STV090x_WIDTH_MSTREAM_LCK_3_FIELD 3 +#define STV090x_OFFST_MSTREAM_LCK_2_FIELD 2 +#define STV090x_WIDTH_MSTREAM_LCK_2_FIELD 3 +#define STV090x_OFFST_MSTREAM_LCK_1_FIELD 2 +#define STV090x_WIDTH_MSTREAM_LCK_1_FIELD 3 +#define STV090x_OFFST_MDVBS1_PRF_2_FIELD 1 +#define STV090x_WIDTH_MDVBS1_PRF_2_FIELD 1 +#define STV090x_OFFST_MDVBS1_PRF_1_FIELD 0 +#define STV090x_WIDTH_MDVBS1_PRF_1_FIELD 1 + +#define STV090x_IRQMASK2 0xf125 +#define STV090x_OFFST_MSPY_ENDSIM_3_FIELD 5 +#define STV090x_WIDTH_MSPY_ENDSIM_3_FIELD 3 +#define STV090x_OFFST_MSPY_ENDSIM_2_FIELD 5 +#define STV090x_WIDTH_MSPY_ENDSIM_2_FIELD 3 +#define STV090x_OFFST_MSPY_ENDSIM_1_FIELD 5 +#define STV090x_WIDTH_MSPY_ENDSIM_1_FIELD 3 +#define STV090x_OFFST_MPKTDEL_ERROR_2_FIELD 4 +#define STV090x_WIDTH_MPKTDEL_ERROR_2_FIELD 1 +#define STV090x_OFFST_MPKTDEL_LOCKB_2_FIELD 3 +#define STV090x_WIDTH_MPKTDEL_LOCKB_2_FIELD 1 +#define STV090x_OFFST_MPKTDEL_LOCK_2_FIELD 2 +#define STV090x_WIDTH_MPKTDEL_LOCK_2_FIELD 1 +#define STV090x_OFFST_MPKTDEL_ERROR_1_FIELD 1 +#define STV090x_WIDTH_MPKTDEL_ERROR_1_FIELD 1 +#define STV090x_OFFST_MPKTDEL_LOCKB_1_FIELD 0 +#define STV090x_WIDTH_MPKTDEL_LOCKB_1_FIELD 1 + +#define STV090x_IRQMASK1 0xf126 +#define STV090x_OFFST_MPKTDEL_LOCK_1_FIELD 7 +#define STV090x_WIDTH_MPKTDEL_LOCK_1_FIELD 1 +#define STV090x_OFFST_MEXTPINB2_FIELD 6 +#define STV090x_WIDTH_MEXTPINB2_FIELD 1 +#define STV090x_OFFST_MEXTPIN2_FIELD 5 +#define STV090x_WIDTH_MEXTPIN2_FIELD 1 +#define STV090x_OFFST_MEXTPINB1_FIELD 4 +#define STV090x_WIDTH_MEXTPINB1_FIELD 1 +#define STV090x_OFFST_MEXTPIN1_FIELD 3 +#define STV090x_WIDTH_MEXTPIN1_FIELD 1 +#define STV090x_OFFST_MDEMOD_LOCKB_2_FIELD 2 +#define STV090x_WIDTH_MDEMOD_LOCKB_2_FIELD 1 +#define STV090x_OFFST_MDEMOD_LOCK_2_FIELD 1 +#define STV090x_WIDTH_MDEMOD_LOCK_2_FIELD 1 +#define STV090x_OFFST_MDEMOD_IRQ_2_FIELD 0 +#define STV090x_WIDTH_MDEMOD_IRQ_2_FIELD 1 + +#define STV090x_IRQMASK0 0xf127 +#define STV090x_OFFST_MDEMOD_LOCKB_1_FIELD 7 +#define STV090x_WIDTH_MDEMOD_LOCKB_1_FIELD 1 +#define STV090x_OFFST_MDEMOD_LOCK_1_FIELD 6 +#define STV090x_WIDTH_MDEMOD_LOCK_1_FIELD 1 +#define STV090x_OFFST_MDEMOD_IRQ_1_FIELD 5 +#define STV090x_WIDTH_MDEMOD_IRQ_1_FIELD 1 +#define STV090x_OFFST_MBCH_ERRFLAG_FIELD 4 +#define STV090x_WIDTH_MBCH_ERRFLAG_FIELD 1 +#define STV090x_OFFST_MDISEQC2RX_IRQ_FIELD 3 +#define STV090x_WIDTH_MDISEQC2RX_IRQ_FIELD 1 +#define STV090x_OFFST_MDISEQC2TX_IRQ_FIELD 2 +#define STV090x_WIDTH_MDISEQC2TX_IRQ_FIELD 1 +#define STV090x_OFFST_MDISEQC1RX_IRQ_FIELD 1 +#define STV090x_WIDTH_MDISEQC1RX_IRQ_FIELD 1 +#define STV090x_OFFST_MDISEQC1TX_IRQ_FIELD 0 +#define STV090x_WIDTH_MDISEQC1TX_IRQ_FIELD 1 + +#define STV090x_I2CCFG 0xf129 +#define STV090x_OFFST_12C_FASTMODE_FIELD 3 +#define STV090x_WIDTH_12C_FASTMODE_FIELD 1 +#define STV090x_OFFST_12CADDR_INC_FIELD 0 +#define STV090x_WIDTH_12CADDR_INC_FIELD 2 + +#define STV090x_Px_I2CRPT(__x) (0xf12a + (__x - 1) * 0x1) +#define STV090x_P1_I2CRPT STV090x_Px_I2CRPT(1) +#define STV090x_P2_I2CRPT STV090x_Px_I2CRPT(2) +#define STV090x_OFFST_Px_I2CT_ON_FIELD 7 +#define STV090x_WIDTH_Px_I2CT_ON_FIELD 1 +#define STV090x_OFFST_Px_ENARPT_LEVEL_FIELD 4 +#define STV090x_WIDTH_Px_ENARPT_LEVEL_FIELD 3 +#define STV090x_OFFST_Px_SCLT_DELAY_FIELD 3 +#define STV090x_WIDTH_Px_SCLT_DELAY_FIELD 1 +#define STV090x_OFFST_Px_STOP_ENABLE_FIELD 2 +#define STV090x_WIDTH_Px_STOP_ENABLE_FIELD 1 +#define STV090x_OFFST_Px_STOP_SDAT2SDA_FIELD 1 +#define STV090x_WIDTH_Px_STOP_SDAT2SDA_FIELD 1 + +#define STV090x_CLKI2CFG 0xf140 +#define STV090x_OFFST_CLKI2_OPD_FIELD 7 +#define STV090x_WIDTH_CLKI2_OPD_FIELD 1 +#define STV090x_OFFST_CLKI2_CONFIG_FIELD 1 +#define STV090x_WIDTH_CLKI2_CONFIG_FIELD 6 +#define STV090x_OFFST_CLKI2_XOR_FIELD 0 +#define STV090x_WIDTH_CLKI2_XOR_FIELD 1 + +#define STV090x_GPIOxCFG(__x) (0xf141 + (__x - 1)) +#define STV090x_GPIO1CFG STV090x_GPIOxCFG(1) +#define STV090x_GPIO2CFG STV090x_GPIOxCFG(2) +#define STV090x_GPIO3CFG STV090x_GPIOxCFG(3) +#define STV090x_GPIO4CFG STV090x_GPIOxCFG(4) +#define STV090x_GPIO5CFG STV090x_GPIOxCFG(5) +#define STV090x_GPIO6CFG STV090x_GPIOxCFG(6) +#define STV090x_GPIO7CFG STV090x_GPIOxCFG(7) +#define STV090x_GPIO8CFG STV090x_GPIOxCFG(8) +#define STV090x_GPIO9CFG STV090x_GPIOxCFG(9) +#define STV090x_GPIO10CFG STV090x_GPIOxCFG(10) +#define STV090x_GPIO11CFG STV090x_GPIOxCFG(11) +#define STV090x_GPIO12CFG STV090x_GPIOxCFG(12) +#define STV090x_GPIO13CFG STV090x_GPIOxCFG(13) +#define STV090x_OFFST_GPIOx_OPD_FIELD 7 +#define STV090x_WIDTH_GPIOx_OPD_FIELD 1 +#define STV090x_OFFST_GPIOx_CONFIG_FIELD 1 +#define STV090x_WIDTH_GPIOx_CONFIG_FIELD 6 +#define STV090x_OFFST_GPIOx_XOR_FIELD 0 +#define STV090x_WIDTH_GPIOx_XOR_FIELD 1 + +#define STV090x_CSxCFG(__x) (0xf14e + __x * 0x1) +#define STV090x_CS0CFG STV090x_CSxCFG(0) +#define STV090x_CS1CFG STV090x_CSxCFG(1) +#define STV090x_OFFST_CSX_OPD_FIELD 7 +#define STV090x_WIDTH_CSX_OPD_FIELD 1 +#define STV090x_OFFST_CSX_CONFIG_FIELD 1 +#define STV090x_WIDTH_CSX_CONFIG_FIELD 6 +#define STV090x_OFFST_CSX_XOR_FIELD 0 +#define STV090x_WIDTH_CSX_XOR_FIELD 1 + + +#define STV090x_STDBYCFG 0xf150 +#define STV090x_OFFST_STDBY_OPD_FIELD 7 +#define STV090x_WIDTH_STDBY_OPD_FIELD 1 +#define STV090x_OFFST_STDBY_CONFIG_FIELD 1 +#define STV090x_WIDTH_STDBY_CONFIG_FIELD 6 +#define STV090x_OFFST_STDBY_XOR_FIELD 0 +#define STV090x_WIDTH_STDBY_XOR_FIELD 1 + +#define STV090x_DIRCLKCFG 0xf151 +#define STV090x_OFFST_DIRCLK_OPD_FIELD 7 +#define STV090x_WIDTH_DIRCLK_OPD_FIELD 1 +#define STV090x_OFFST_DIRCLK_CONFIG_FIELD 1 +#define STV090x_WIDTH_DIRCLK_CONFIG_FIELD 6 +#define STV090x_OFFST_DIRCLK_XOR_FIELD 0 +#define STV090x_WIDTH_DIRCLK_XOR_FIELD 1 + + +#define STV090x_AGCRFxCFG(__x) (0xf152 + (__x - 1) * 0x4) +#define STV090x_AGCRF1CFG STV090x_AGCRFxCFG(1) +#define STV090x_AGCRF2CFG STV090x_AGCRFxCFG(2) +#define STV090x_OFFST_AGCRFx_OPD_FIELD 7 +#define STV090x_WIDTH_AGCRFx_OPD_FIELD 1 +#define STV090x_OFFST_AGCRFx_CONFIG_FIELD 1 +#define STV090x_WIDTH_AGCRFx_CONFIG_FIELD 6 +#define STV090x_OFFST_AGCRFx_XOR_FIELD 0 +#define STV090x_WIDTH_AGCRFx_XOR_FIELD 1 + +#define STV090x_SDATxCFG(__x) (0xf153 + (__x - 1) * 0x4) +#define STV090x_SDAT1CFG STV090x_SDATxCFG(1) +#define STV090x_SDAT2CFG STV090x_SDATxCFG(2) +#define STV090x_OFFST_SDATx_OPD_FIELD 7 +#define STV090x_WIDTH_SDATx_OPD_FIELD 1 +#define STV090x_OFFST_SDATx_CONFIG_FIELD 1 +#define STV090x_WIDTH_SDATx_CONFIG_FIELD 6 +#define STV090x_OFFST_SDATx_XOR_FIELD 0 +#define STV090x_WIDTH_SDATx_XOR_FIELD 1 + +#define STV090x_SCLTxCFG(__x) (0xf154 + (__x - 1) * 0x4) +#define STV090x_SCLT1CFG STV090x_SCLTxCFG(1) +#define STV090x_SCLT2CFG STV090x_SCLTxCFG(2) +#define STV090x_OFFST_SCLTx_OPD_FIELD 7 +#define STV090x_WIDTH_SCLTx_OPD_FIELD 1 +#define STV090x_OFFST_SCLTx_CONFIG_FIELD 1 +#define STV090x_WIDTH_SCLTx_CONFIG_FIELD 6 +#define STV090x_OFFST_SCLTx_XOR_FIELD 0 +#define STV090x_WIDTH_SCLTx_XOR_FIELD 1 + +#define STV090x_DISEQCOxCFG(__x) (0xf155 + (__x - 1) * 0x4) +#define STV090x_DISEQCO1CFG STV090x_DISEQCOxCFG(1) +#define STV090x_DISEQCO2CFG STV090x_DISEQCOxCFG(2) +#define STV090x_OFFST_DISEQCOx_OPD_FIELD 7 +#define STV090x_WIDTH_DISEQCOx_OPD_FIELD 1 +#define STV090x_OFFST_DISEQCOx_CONFIG_FIELD 1 +#define STV090x_WIDTH_DISEQCOx_CONFIG_FIELD 6 +#define STV090x_OFFST_DISEQCOx_XOR_FIELD 0 +#define STV090x_WIDTH_DISEQCOx_XOR_FIELD 1 + +#define STV090x_CLKOUT27CFG 0xf15a +#define STV090x_OFFST_CLKOUT27_OPD_FIELD 7 +#define STV090x_WIDTH_CLKOUT27_OPD_FIELD 1 +#define STV090x_OFFST_CLKOUT27_CONFIG_FIELD 1 +#define STV090x_WIDTH_CLKOUT27_CONFIG_FIELD 6 +#define STV090x_OFFST_CLKOUT27_XOR_FIELD 0 +#define STV090x_WIDTH_CLKOUT27_XOR_FIELD 1 + +#define STV090x_ERRORxCFG(__x) (0xf15b + (__x - 1) * 0x5) +#define STV090x_ERROR1CFG STV090x_ERRORxCFG(1) +#define STV090x_ERROR2CFG STV090x_ERRORxCFG(2) +#define STV090x_ERROR3CFG STV090x_ERRORxCFG(3) +#define STV090x_OFFST_ERRORx_OPD_FIELD 7 +#define STV090x_WIDTH_ERRORx_OPD_FIELD 1 +#define STV090x_OFFST_ERRORx_CONFIG_FIELD 1 +#define STV090x_WIDTH_ERRORx_CONFIG_FIELD 6 +#define STV090x_OFFST_ERRORx_XOR_FIELD 0 +#define STV090x_WIDTH_ERRORx_XOR_FIELD 1 + +#define STV090x_DPNxCFG(__x) (0xf15c + (__x - 1) * 0x5) +#define STV090x_DPN1CFG STV090x_DPNxCFG(1) +#define STV090x_DPN2CFG STV090x_DPNxCFG(2) +#define STV090x_DPN3CFG STV090x_DPNxCFG(3) +#define STV090x_OFFST_DPNx_OPD_FIELD 7 +#define STV090x_WIDTH_DPNx_OPD_FIELD 1 +#define STV090x_OFFST_DPNx_CONFIG_FIELD 1 +#define STV090x_WIDTH_DPNx_CONFIG_FIELD 6 +#define STV090x_OFFST_DPNx_XOR_FIELD 0 +#define STV090x_WIDTH_DPNx_XOR_FIELD 1 + +#define STV090x_STROUTxCFG(__x) (0xf15d + (__x - 1) * 0x5) +#define STV090x_STROUT1CFG STV090x_STROUTxCFG(1) +#define STV090x_STROUT2CFG STV090x_STROUTxCFG(2) +#define STV090x_STROUT3CFG STV090x_STROUTxCFG(3) +#define STV090x_OFFST_STROUTx_OPD_FIELD 7 +#define STV090x_WIDTH_STROUTx_OPD_FIELD 1 +#define STV090x_OFFST_STROUTx_CONFIG_FIELD 1 +#define STV090x_WIDTH_STROUTx_CONFIG_FIELD 6 +#define STV090x_OFFST_STROUTx_XOR_FIELD 0 +#define STV090x_WIDTH_STROUTx_XOR_FIELD 1 + +#define STV090x_CLKOUTxCFG(__x) (0xf15e + (__x - 1) * 0x5) +#define STV090x_CLKOUT1CFG STV090x_CLKOUTxCFG(1) +#define STV090x_CLKOUT2CFG STV090x_CLKOUTxCFG(2) +#define STV090x_CLKOUT3CFG STV090x_CLKOUTxCFG(3) +#define STV090x_OFFST_CLKOUTx_OPD_FIELD 7 +#define STV090x_WIDTH_CLKOUTx_OPD_FIELD 1 +#define STV090x_OFFST_CLKOUTx_CONFIG_FIELD 1 +#define STV090x_WIDTH_CLKOUTx_CONFIG_FIELD 6 +#define STV090x_OFFST_CLKOUTx_XOR_FIELD 0 +#define STV090x_WIDTH_CLKOUTx_XOR_FIELD 1 + +#define STV090x_DATAxCFG(__x) (0xf15f + (__x - 71) * 0x5) +#define STV090x_DATA71CFG STV090x_DATAxCFG(71) +#define STV090x_DATA72CFG STV090x_DATAxCFG(72) +#define STV090x_DATA73CFG STV090x_DATAxCFG(73) +#define STV090x_OFFST_DATAx_OPD_FIELD 7 +#define STV090x_WIDTH_DATAx_OPD_FIELD 1 +#define STV090x_OFFST_DATAx_CONFIG_FIELD 1 +#define STV090x_WIDTH_DATAx_CONFIG_FIELD 6 +#define STV090x_OFFST_DATAx_XOR_FIELD 0 +#define STV090x_WIDTH_DATAx_XOR_FIELD 1 + +#define STV090x_NCOARSE 0xf1b3 +#define STV090x_OFFST_M_DIV_FIELD 0 +#define STV090x_WIDTH_M_DIV_FIELD 8 + +#define STV090x_SYNTCTRL 0xf1b6 +#define STV090x_OFFST_STANDBY_FIELD 7 +#define STV090x_WIDTH_STANDBY_FIELD 1 +#define STV090x_OFFST_BYPASSPLLCORE_FIELD 6 +#define STV090x_WIDTH_BYPASSPLLCORE_FIELD 1 +#define STV090x_OFFST_SELX1RATIO_FIELD 5 +#define STV090x_WIDTH_SELX1RATIO_FIELD 1 +#define STV090x_OFFST_STOP_PLL_FIELD 3 +#define STV090x_WIDTH_SELX1RATIO_FIELD 1 +#define STV090x_OFFST_BYPASSPLLFSK_FIELD 2 +#define STV090x_WIDTH_BYPASSPLLFSK_FIELD 1 +#define STV090x_OFFST_SELOSCI_FIELD 1 +#define STV090x_WIDTH_SELOSCI_FIELD 1 +#define STV090x_OFFST_BYPASSPLLADC_FIELD 0 +#define STV090x_WIDTH_BYPASSPLLADC_FIELD 1 + +#define STV090x_FILTCTRL 0xf1b7 +#define STV090x_OFFST_INV_CLK135_FIELD 7 +#define STV090x_WIDTH_INV_CLK135_FIELD 1 +#define STV090x_OFFST_SEL_FSKCKDIV_FIELD 2 +#define STV090x_WIDTH_SEL_FSKCKDIV_FIELD 1 +#define STV090x_OFFST_INV_CLKFSK_FIELD 1 +#define STV090x_WIDTH_INV_CLKFSK_FIELD 1 +#define STV090x_OFFST_BYPASS_APPLI_FIELD 0 +#define STV090x_WIDTH_BYPASS_APPLI_FIELD 1 + +#define STV090x_PLLSTAT 0xf1b8 +#define STV090x_OFFST_PLLLOCK_FIELD 0 +#define STV090x_WIDTH_PLLLOCK_FIELD 1 + +#define STV090x_STOPCLK1 0xf1c2 +#define STV090x_OFFST_STOP_CLKPKDT2_FIELD 6 +#define STV090x_WIDTH_STOP_CLKPKDT2_FIELD 1 +#define STV090x_OFFST_STOP_CLKPKDT1_FIELD 5 +#define STV090x_WIDTH_STOP_CLKPKDT1_FIELD 1 +#define STV090x_OFFST_STOP_CLKFEC_FIELD 4 +#define STV090x_WIDTH_STOP_CLKFEC_FIELD 1 +#define STV090x_OFFST_STOP_CLKADCI2_FIELD 3 +#define STV090x_WIDTH_STOP_CLKADCI2_FIELD 1 +#define STV090x_OFFST_INV_CLKADCI2_FIELD 2 +#define STV090x_WIDTH_INV_CLKADCI2_FIELD 1 +#define STV090x_OFFST_STOP_CLKADCI1_FIELD 1 +#define STV090x_WIDTH_STOP_CLKADCI1_FIELD 1 +#define STV090x_OFFST_INV_CLKADCI1_FIELD 0 +#define STV090x_WIDTH_INV_CLKADCI1_FIELD 1 + +#define STV090x_STOPCLK2 0xf1c3 +#define STV090x_OFFST_STOP_CLKSAMP2_FIELD 4 +#define STV090x_WIDTH_STOP_CLKSAMP2_FIELD 1 +#define STV090x_OFFST_STOP_CLKSAMP1_FIELD 3 +#define STV090x_WIDTH_STOP_CLKSAMP1_FIELD 1 +#define STV090x_OFFST_STOP_CLKVIT2_FIELD 2 +#define STV090x_WIDTH_STOP_CLKVIT2_FIELD 1 +#define STV090x_OFFST_STOP_CLKVIT1_FIELD 1 +#define STV090x_WIDTH_STOP_CLKVIT1_FIELD 1 +#define STV090x_OFFST_STOP_CLKTS_FIELD 0 +#define STV090x_WIDTH_STOP_CLKTS_FIELD 1 + +#define STV090x_TSTTNR0 0xf1df +#define STV090x_OFFST_SEL_FSK_FIELD 7 +#define STV090x_WIDTH_SEL_FSK_FIELD 1 +#define STV090x_OFFST_FSK_PON_FIELD 2 +#define STV090x_WIDTH_FSK_PON_FIELD 1 + +#define STV090x_TSTTNR1 0xf1e0 +#define STV090x_OFFST_ADC1_PON_FIELD 1 +#define STV090x_WIDTH_ADC1_PON_FIELD 1 +#define STV090x_OFFST_ADC1_INMODE_FIELD 0 +#define STV090x_WIDTH_ADC1_INMODE_FIELD 1 + +#define STV090x_TSTTNR2 0xf1e1 +#define STV090x_OFFST_DISEQC1_PON_FIELD 5 +#define STV090x_WIDTH_DISEQC1_PON_FIELD 1 + +#define STV090x_TSTTNR3 0xf1e2 +#define STV090x_OFFST_ADC2_PON_FIELD 1 +#define STV090x_WIDTH_ADC2_PON_FIELD 1 +#define STV090x_OFFST_ADC2_INMODE_FIELD 0 +#define STV090x_WIDTH_ADC2_INMODE_FIELD 1 + +#define STV090x_TSTTNR4 0xf1e3 +#define STV090x_OFFST_DISEQC2_PON_FIELD 5 +#define STV090x_WIDTH_DISEQC2_PON_FIELD 1 + +#define STV090x_FSKTFC2 0xf170 +#define STV090x_OFFST_FSKT_KMOD_FIELD 2 +#define STV090x_WIDTH_FSKT_KMOD_FIELD 6 +#define STV090x_OFFST_FSKT_CAR_FIELD 0 +#define STV090x_WIDTH_FSKT_CAR_FIELD 2 + +#define STV090x_FSKTFC1 0xf171 +#define STV090x_OFFST_FSKTC1_CAR_FIELD 0 +#define STV090x_WIDTH_FSKTC1_CAR_FIELD 8 + +#define STV090x_FSKTFC0 0xf172 +#define STV090x_OFFST_FSKTC0_CAR_FIELD 0 +#define STV090x_WIDTH_FSKTC0_CAR_FIELD 8 + +#define STV090x_FSKTDELTAF1 0xf173 +#define STV090x_OFFST_FSKTF1_DELTAF_FIELD 0 +#define STV090x_WIDTH_FSKTF1_DELTAF_FIELD 4 + +#define STV090x_FSKTDELTAF0 0xf174 +#define STV090x_OFFST_FSKTF0_DELTAF_FIELD 0 +#define STV090x_WIDTH_FSKTF0_DELTAF_FIELD 8 + +#define STV090x_FSKTCTRL 0xf175 +#define STV090x_OFFST_FSKT_EN_SGN_FIELD 6 +#define STV090x_WIDTH_FSKT_EN_SGN_FIELD 1 +#define STV090x_OFFST_FSKT_MOD_SGN_FIELD 5 +#define STV090x_WIDTH_FSKT_MOD_SGN_FIELD 1 +#define STV090x_OFFST_FSKT_MOD_EN_FIELD 2 +#define STV090x_WIDTH_FSKT_MOD_EN_FIELD 3 +#define STV090x_OFFST_FSKT_DACMODE_FIELD 0 +#define STV090x_WIDTH_FSKT_DACMODE_FIELD 2 + +#define STV090x_FSKRFC2 0xf176 +#define STV090x_OFFST_FSKRC2_DETSGN_FIELD 6 +#define STV090x_WIDTH_FSKRC2_DETSGN_FIELD 1 +#define STV090x_OFFST_FSKRC2_OUTSGN_FIELD 5 +#define STV090x_WIDTH_FSKRC2_OUTSGN_FIELD 1 +#define STV090x_OFFST_FSKRC2_KAGC_FIELD 2 +#define STV090x_WIDTH_FSKRC2_KAGC_FIELD 3 +#define STV090x_OFFST_FSKRC2_CAR_FIELD 0 +#define STV090x_WIDTH_FSKRC2_CAR_FIELD 2 + +#define STV090x_FSKRFC1 0xf177 +#define STV090x_OFFST_FSKRC1_CAR_FIELD 0 +#define STV090x_WIDTH_FSKRC1_CAR_FIELD 8 + +#define STV090x_FSKRFC0 0xf178 +#define STV090x_OFFST_FSKRC0_CAR_FIELD 0 +#define STV090x_WIDTH_FSKRC0_CAR_FIELD 8 + +#define STV090x_FSKRK1 0xf179 +#define STV090x_OFFST_FSKR_K1_EXP_FIELD 5 +#define STV090x_WIDTH_FSKR_K1_EXP_FIELD 3 +#define STV090x_OFFST_FSKR_K1_MANT_FIELD 0 +#define STV090x_WIDTH_FSKR_K1_MANT_FIELD 5 + +#define STV090x_FSKRK2 0xf17a +#define STV090x_OFFST_FSKR_K2_EXP_FIELD 5 +#define STV090x_WIDTH_FSKR_K2_EXP_FIELD 3 +#define STV090x_OFFST_FSKR_K2_MANT_FIELD 0 +#define STV090x_WIDTH_FSKR_K2_MANT_FIELD 5 + +#define STV090x_FSKRAGCR 0xf17b +#define STV090x_OFFST_FSKR_OUTCTL_FIELD 6 +#define STV090x_WIDTH_FSKR_OUTCTL_FIELD 2 +#define STV090x_OFFST_FSKR_AGC_REF_FIELD 0 +#define STV090x_WIDTH_FSKR_AGC_REF_FIELD 6 + +#define STV090x_FSKRAGC 0xf17c +#define STV090x_OFFST_FSKR_AGC_ACCU_FIELD 0 +#define STV090x_WIDTH_FSKR_AGC_ACCU_FIELD 8 + +#define STV090x_FSKRALPHA 0xf17d +#define STV090x_OFFST_FSKR_ALPHA_EXP_FIELD 2 +#define STV090x_WIDTH_FSKR_ALPHA_EXP_FIELD 3 +#define STV090x_OFFST_FSKR_ALPHA_M_FIELD 0 +#define STV090x_WIDTH_FSKR_ALPHA_M_FIELD 2 + +#define STV090x_FSKRPLTH1 0xf17e +#define STV090x_OFFST_FSKR_BETA_FIELD 4 +#define STV090x_WIDTH_FSKR_BETA_FIELD 4 +#define STV090x_OFFST_FSKR_PLL_TRESH1_FIELD 0 +#define STV090x_WIDTH_FSKR_PLL_TRESH1_FIELD 4 + +#define STV090x_FSKRPLTH0 0xf17f +#define STV090x_OFFST_FSKR_PLL_TRESH0_FIELD 0 +#define STV090x_WIDTH_FSKR_PLL_TRESH0_FIELD 8 + +#define STV090x_FSKRDF1 0xf180 +#define STV090x_OFFST_FSKR_DELTAF1_FIELD 0 +#define STV090x_WIDTH_FSKR_DELTAF1_FIELD 5 + +#define STV090x_FSKRDF0 0xf181 +#define STV090x_OFFST_FSKR_DELTAF0_FIELD 0 +#define STV090x_WIDTH_FSKR_DELTAF0_FIELD 8 + +#define STV090x_FSKRSTEPP 0xf182 +#define STV090x_OFFST_FSKR_STEP_PLUS_FIELD 0 +#define STV090x_WIDTH_FSKR_STEP_PLUS_FIELD 8 + +#define STV090x_FSKRSTEPM 0xf183 +#define STV090x_OFFST_FSKR_STEP_MINUS_FIELD 0 +#define STV090x_WIDTH_FSKR_STEP_MINUS_FIELD 8 + +#define STV090x_FSKRDET1 0xf184 +#define STV090x_OFFST_FSKR_CARDET1_ACCU_FIELD 0 +#define STV090x_WIDTH_FSKR_CARDET1_ACCU_FIELD 4 + +#define STV090x_FSKRDET0 0xf185 +#define STV090x_OFFST_FSKR_CARDET0_ACCU_FIELD 0 +#define STV090x_WIDTH_FSKR_CARDET0_ACCU_FIELD 8 + +#define STV090x_FSKRDTH1 0xf186 +#define STV090x_OFFST_FSKR_CARLOSS_THRESH1_FIELD 4 +#define STV090x_WIDTH_FSKR_CARLOSS_THRESH1_FIELD 4 +#define STV090x_OFFST_FSKR_CARDET_THRESH1_FIELD 0 +#define STV090x_WIDTH_FSKR_CARDET_THRESH1_FIELD 4 + +#define STV090x_FSKRDTH0 0xf187 +#define STV090x_OFFST_FSKR_CARDET_THRESH0_FIELD 0 +#define STV090x_WIDTH_FSKR_CARDET_THRESH0_FIELD 8 + +#define STV090x_FSKRLOSS 0xf188 +#define STV090x_OFFST_FSKR_CARLOSS_THRESH_FIELD 0 +#define STV090x_WIDTH_FSKR_CARLOSS_THRESH_FIELD 8 + +#define STV090x_Px_DISTXCTL(__x) (0xF1A0 - (__x - 1) * 0x10) +#define STV090x_P1_DISTXCTL STV090x_Px_DISTXCTL(1) +#define STV090x_P2_DISTXCTL STV090x_Px_DISTXCTL(2) +#define STV090x_OFFST_Px_TIM_OFF_FIELD 7 +#define STV090x_WIDTH_Px_TIM_OFF_FIELD 1 +#define STV090x_OFFST_Px_DISEQC_RESET_FIELD 6 +#define STV090x_WIDTH_Px_DISEQC_RESET_FIELD 1 +#define STV090x_OFFST_Px_TIM_CMD_FIELD 4 +#define STV090x_WIDTH_Px_TIM_CMD_FIELD 2 +#define STV090x_OFFST_Px_DIS_PRECHARGE_FIELD 3 +#define STV090x_WIDTH_Px_DIS_PRECHARGE_FIELD 1 +#define STV090x_OFFST_Px_DISTX_MODE_FIELD 0 +#define STV090x_WIDTH_Px_DISTX_MODE_FIELD 3 + +#define STV090x_Px_DISRXCTL(__x) (0xf1a1 - (__x - 1) * 0x10) +#define STV090x_P1_DISRXCTL STV090x_Px_DISRXCTL(1) +#define STV090x_P2_DISRXCTL STV090x_Px_DISRXCTL(2) +#define STV090x_OFFST_Px_RECEIVER_ON_FIELD 7 +#define STV090x_WIDTH_Px_RECEIVER_ON_FIELD 1 +#define STV090x_OFFST_Px_IGNO_SHORT22K_FIELD 6 +#define STV090x_WIDTH_Px_IGNO_SHORT22K_FIELD 1 +#define STV090x_OFFST_Px_ONECHIP_TRX_FIELD 5 +#define STV090x_WIDTH_Px_ONECHIP_TRX_FIELD 1 +#define STV090x_OFFST_Px_EXT_ENVELOP_FIELD 4 +#define STV090x_WIDTH_Px_EXT_ENVELOP_FIELD 1 +#define STV090x_OFFST_Px_PIN_SELECT_FIELD 2 +#define STV090x_WIDTH_Px_PIN_SELECT_FIELD 2 +#define STV090x_OFFST_Px_IRQ_RXEND_FIELD 1 +#define STV090x_WIDTH_Px_IRQ_RXEND_FIELD 1 +#define STV090x_OFFST_Px_IRQ_4NBYTES_FIELD 0 +#define STV090x_WIDTH_Px_IRQ_4NBYTES_FIELD 1 + +#define STV090x_Px_DISRX_ST0(__x) (0xf1a4 - (__x - 1) * 0x10) +#define STV090x_P1_DISRX_ST0 STV090x_Px_DISRX_ST0(1) +#define STV090x_P2_DISRX_ST0 STV090x_Px_DISRX_ST0(2) +#define STV090x_OFFST_Px_RX_END_FIELD 7 +#define STV090x_WIDTH_Px_RX_END_FIELD 1 +#define STV090x_OFFST_Px_RX_ACTIVE_FIELD 6 +#define STV090x_WIDTH_Px_RX_ACTIVE_FIELD 1 +#define STV090x_OFFST_Px_SHORT_22KHZ_FIELD 5 +#define STV090x_WIDTH_Px_SHORT_22KHZ_FIELD 1 +#define STV090x_OFFST_Px_CONT_TONE_FIELD 4 +#define STV090x_WIDTH_Px_CONT_TONE_FIELD 1 +#define STV090x_OFFST_Px_FIFO_4BREADY_FIELD 3 +#define STV090x_WIDTH_Px_FIFO_4BREADY_FIELD 2 +#define STV090x_OFFST_Px_FIFO_EMPTY_FIELD 2 +#define STV090x_WIDTH_Px_FIFO_EMPTY_FIELD 1 +#define STV090x_OFFST_Px_ABORT_DISRX_FIELD 0 +#define STV090x_WIDTH_Px_ABORT_DISRX_FIELD 1 + +#define STV090x_Px_DISRX_ST1(__x) (0xf1a5 - (__x - 1) * 0x10) +#define STV090x_P1_DISRX_ST1 STV090x_Px_DISRX_ST1(1) +#define STV090x_P2_DISRX_ST1 STV090x_Px_DISRX_ST1(2) +#define STV090x_OFFST_Px_RX_FAIL_FIELD 7 +#define STV090x_WIDTH_Px_RX_FAIL_FIELD 1 +#define STV090x_OFFST_Px_FIFO_PARITYFAIL_FIELD 6 +#define STV090x_WIDTH_Px_FIFO_PARITYFAIL_FIELD 1 +#define STV090x_OFFST_Px_RX_NONBYTE_FIELD 5 +#define STV090x_WIDTH_Px_RX_NONBYTE_FIELD 1 +#define STV090x_OFFST_Px_FIFO_OVERFLOW_FIELD 4 +#define STV090x_WIDTH_Px_FIFO_OVERFLOW_FIELD 1 +#define STV090x_OFFST_Px_FIFO_BYTENBR_FIELD 0 +#define STV090x_WIDTH_Px_FIFO_BYTENBR_FIELD 4 + +#define STV090x_Px_DISRXDATA(__x) (0xf1a6 - (__x - 1) * 0x10) +#define STV090x_P1_DISRXDATA STV090x_Px_DISRXDATA(1) +#define STV090x_P2_DISRXDATA STV090x_Px_DISRXDATA(2) +#define STV090x_OFFST_Px_DISRX_DATA_FIELD 0 +#define STV090x_WIDTH_Px_DISRX_DATA_FIELD 8 + +#define STV090x_Px_DISTXDATA(__x) (0xf1a7 - (__x - 1) * 0x10) +#define STV090x_P1_DISTXDATA STV090x_Px_DISTXDATA(1) +#define STV090x_P2_DISTXDATA STV090x_Px_DISTXDATA(2) +#define STV090x_OFFST_Px_DISEQC_FIFO_FIELD 0 +#define STV090x_WIDTH_Px_DISEQC_FIFO_FIELD 8 + +#define STV090x_Px_DISTXSTATUS(__x) (0xf1a8 - (__x - 1) * 0x10) +#define STV090x_P1_DISTXSTATUS STV090x_Px_DISTXSTATUS(1) +#define STV090x_P2_DISTXSTATUS STV090x_Px_DISTXSTATUS(2) +#define STV090x_OFFST_Px_TX_FAIL_FIELD 7 +#define STV090x_WIDTH_Px_TX_FAIL_FIELD 1 +#define STV090x_OFFST_Px_FIFO_FULL_FIELD 6 +#define STV090x_WIDTH_Px_FIFO_FULL_FIELD 1 +#define STV090x_OFFST_Px_TX_IDLE_FIELD 5 +#define STV090x_WIDTH_Px_TX_IDLE_FIELD 1 +#define STV090x_OFFST_Px_GAP_BURST_FIELD 4 +#define STV090x_WIDTH_Px_GAP_BURST_FIELD 1 +#define STV090x_OFFST_Px_TXFIFO_BYTES_FIELD 0 +#define STV090x_WIDTH_Px_TXFIFO_BYTES_FIELD 4 + +#define STV090x_Px_F22TX(__x) (0xf1a9 - (__x - 1) * 0x10) +#define STV090x_P1_F22TX STV090x_Px_F22TX(1) +#define STV090x_P2_F22TX STV090x_Px_F22TX(2) +#define STV090x_OFFST_Px_F22_REG_FIELD 0 +#define STV090x_WIDTH_Px_F22_REG_FIELD 8 + +#define STV090x_Px_F22RX(__x) (0xf1aa - (__x - 1) * 0x10) +#define STV090x_P1_F22RX STV090x_Px_F22RX(1) +#define STV090x_P2_F22RX STV090x_Px_F22RX(2) +#define STV090x_OFFST_Px_F22RX_REG_FIELD 0 +#define STV090x_WIDTH_Px_F22RX_REG_FIELD 8 + +#define STV090x_Px_ACRPRESC(__x) (0xf1ac - (__x - 1) * 0x10) +#define STV090x_P1_ACRPRESC STV090x_Px_ACRPRESC(1) +#define STV090x_P2_ACRPRESC STV090x_Px_ACRPRESC(2) +#define STV090x_OFFST_Px_ACR_PRESC_FIELD 0 +#define STV090x_WIDTH_Px_ACR_PRESC_FIELD 3 + +#define STV090x_Px_ACRDIV(__x) (0xf1ad - (__x - 1) * 0x10) +#define STV090x_P1_ACRDIV STV090x_Px_ACRDIV(1) +#define STV090x_P2_ACRDIV STV090x_Px_ACRDIV(2) +#define STV090x_OFFST_Px_ACR_DIV_FIELD 0 +#define STV090x_WIDTH_Px_ACR_DIV_FIELD 8 + +#define STV090x_Px_IQCONST(__x) (0xF400 - (__x - 1) * 0x200) +#define STV090x_P1_IQCONST STV090x_Px_IQCONST(1) +#define STV090x_P2_IQCONST STV090x_Px_IQCONST(2) +#define STV090x_OFFST_Px_CONSTEL_SELECT_FIELD 5 +#define STV090x_WIDTH_Px_CONSTEL_SELECT_FIELD 2 + +#define STV090x_Px_NOSCFG(__x) (0xF401 - (__x - 1) * 0x200) +#define STV090x_P1_NOSCFG STV090x_Px_NOSCFG(1) +#define STV090x_P2_NOSCFG STV090x_Px_NOSCFG(2) +#define STV090x_OFFST_Px_NOSPLH_BETA_FIELD 3 +#define STV090x_WIDTH_Px_NOSPLH_BETA_FIELD 2 +#define STV090x_OFFST_Px_NOSDATA_BETA_FIELD 0 +#define STV090x_WIDTH_Px_NOSDATA_BETA_FIELD 3 + +#define STV090x_Px_ISYMB(__x) (0xF402 - (__x - 1) * 0x200) +#define STV090x_P1_ISYMB STV090x_Px_ISYMB(1) +#define STV090x_P2_ISYMB STV090x_Px_ISYMB(2) +#define STV090x_OFFST_Px_I_SYMBOL_FIELD 0 +#define STV090x_WIDTH_Px_I_SYMBOL_FIELD 8 + +#define STV090x_Px_QSYMB(__x) (0xF403 - (__x - 1) * 0x200) +#define STV090x_P1_QSYMB STV090x_Px_QSYMB(1) +#define STV090x_P2_QSYMB STV090x_Px_QSYMB(2) +#define STV090x_OFFST_Px_Q_SYMBOL_FIELD 0 +#define STV090x_WIDTH_Px_Q_SYMBOL_FIELD 8 + +#define STV090x_Px_AGC1CFG(__x) (0xF404 - (__x - 1) * 0x200) +#define STV090x_P1_AGC1CFG STV090x_Px_AGC1CFG(1) +#define STV090x_P2_AGC1CFG STV090x_Px_AGC1CFG(2) +#define STV090x_OFFST_Px_DC_FROZEN_FIELD 7 +#define STV090x_WIDTH_Px_DC_FROZEN_FIELD 1 +#define STV090x_OFFST_Px_DC_CORRECT_FIELD 6 +#define STV090x_WIDTH_Px_DC_CORRECT_FIELD 1 +#define STV090x_OFFST_Px_AMM_FROZEN_FIELD 5 +#define STV090x_WIDTH_Px_AMM_FROZEN_FIELD 1 +#define STV090x_OFFST_Px_AMM_CORRECT_FIELD 4 +#define STV090x_WIDTH_Px_AMM_CORRECT_FIELD 1 +#define STV090x_OFFST_Px_QUAD_FROZEN_FIELD 3 +#define STV090x_WIDTH_Px_QUAD_FROZEN_FIELD 1 +#define STV090x_OFFST_Px_QUAD_CORRECT_FIELD 2 +#define STV090x_WIDTH_Px_QUAD_CORRECT_FIELD 1 + +#define STV090x_Px_AGC1CN(__x) (0xF406 - (__x - 1) * 0x200) +#define STV090x_P1_AGC1CN STV090x_Px_AGC1CN(1) +#define STV090x_P2_AGC1CN STV090x_Px_AGC1CN(2) +#define STV090x_WIDTH_Px_AGC1_LOCKED_FIELD 7 +#define STV090x_OFFST_Px_AGC1_LOCKED_FIELD 1 +#define STV090x_OFFST_Px_AGC1_MINPOWER_FIELD 4 +#define STV090x_WIDTH_Px_AGC1_MINPOWER_FIELD 1 +#define STV090x_OFFST_Px_AGCOUT_FAST_FIELD 3 +#define STV090x_WIDTH_Px_AGCOUT_FAST_FIELD 1 +#define STV090x_OFFST_Px_AGCIQ_BETA_FIELD 0 +#define STV090x_WIDTH_Px_AGCIQ_BETA_FIELD 3 + +#define STV090x_Px_AGC1REF(__x) (0xF407 - (__x - 1) * 0x200) +#define STV090x_P1_AGC1REF STV090x_Px_AGC1REF(1) +#define STV090x_P2_AGC1REF STV090x_Px_AGC1REF(2) +#define STV090x_OFFST_Px_AGCIQ_REF_FIELD 0 +#define STV090x_WIDTH_Px_AGCIQ_REF_FIELD 8 + +#define STV090x_Px_IDCCOMP(__x) (0xF408 - (__x - 1) * 0x200) +#define STV090x_P1_IDCCOMP STV090x_Px_IDCCOMP(1) +#define STV090x_P2_IDCCOMP STV090x_Px_IDCCOMP(2) +#define STV090x_OFFST_Px_IAVERAGE_ADJ_FIELD 0 +#define STV090x_WIDTH_Px_IAVERAGE_ADJ_FIELD 8 + +#define STV090x_Px_QDCCOMP(__x) (0xF409 - (__x - 1) * 0x200) +#define STV090x_P1_QDCCOMP STV090x_Px_QDCCOMP(1) +#define STV090x_P2_QDCCOMP STV090x_Px_QDCCOMP(2) +#define STV090x_OFFST_Px_QAVERAGE_ADJ_FIELD 0 +#define STV090x_WIDTH_Px_QAVERAGE_ADJ_FIELD 8 + +#define STV090x_Px_POWERI(__x) (0xF40A - (__x - 1) * 0x200) +#define STV090x_P1_POWERI STV090x_Px_POWERI(1) +#define STV090x_P2_POWERI STV090x_Px_POWERI(2) +#define STV090x_OFFST_Px_POWER_I_FIELD 0 +#define STV090x_WIDTH_Px_POWER_I_FIELD 8 + +#define STV090x_Px_POWERQ(__x) (0xF40B - (__x - 1) * 0x200) +#define STV090x_P1_POWERQ STV090x_Px_POWERQ(1) +#define STV090x_P2_POWERQ STV090x_Px_POWERQ(2) +#define STV090x_OFFST_Px_POWER_Q_FIELD 0 +#define STV090x_WIDTH_Px_POWER_Q_FIELD 8 + +#define STV090x_Px_AGC1AMM(__x) (0xF40C - (__x - 1) * 0x200) +#define STV090x_P1_AGC1AMM STV090x_Px_AGC1AMM(1) +#define STV090x_P2_AGC1AMM STV090x_Px_AGC1AMM(2) +#define STV090x_OFFST_Px_AMM_VALUE_FIELD 0 +#define STV090x_WIDTH_Px_AMM_VALUE_FIELD 8 + +#define STV090x_Px_AGC1QUAD(__x) (0xF40D - (__x - 1) * 0x200) +#define STV090x_P1_AGC1QUAD STV090x_Px_AGC1QUAD(1) +#define STV090x_P2_AGC1QUAD STV090x_Px_AGC1QUAD(2) +#define STV090x_OFFST_Px_QUAD_VALUE_FIELD 0 +#define STV090x_WIDTH_Px_QUAD_VALUE_FIELD 8 + +#define STV090x_Px_AGCIQINy(__x, __y) (0xF40F - (__x-1) * 0x200 - __y * 0x1) +#define STV090x_P1_AGCIQIN0 STV090x_Px_AGCIQINy(1, 0) +#define STV090x_P1_AGCIQIN1 STV090x_Px_AGCIQINy(1, 1) +#define STV090x_P2_AGCIQIN0 STV090x_Px_AGCIQINy(2, 0) +#define STV090x_P2_AGCIQIN1 STV090x_Px_AGCIQINy(2, 1) +#define STV090x_OFFST_Px_AGCIQ_VALUE_FIELD 0 +#define STV090x_WIDTH_Px_AGCIQ_VALUE_FIELD 8 + +#define STV090x_Px_DEMOD(__x) (0xF410 - (__x - 1) * 0x200) +#define STV090x_P1_DEMOD STV090x_Px_DEMOD(1) +#define STV090x_P2_DEMOD STV090x_Px_DEMOD(2) +#define STV090x_OFFST_Px_MANUAL_S2ROLLOFF_FIELD 7 +#define STV090x_WIDTH_Px_MANUAL_S2ROLLOFF_FIELD 1 +#define STV090x_OFFST_Px_DEMOD_STOP_FIELD 6 +#define STV090x_WIDTH_Px_DEMOD_STOP_FIELD 1 +#define STV090x_OFFST_Px_SPECINV_CONTROL_FIELD 4 +#define STV090x_WIDTH_Px_SPECINV_CONTROL_FIELD 2 +#define STV090x_OFFST_Px_FORCE_ENASAMP_FIELD 3 +#define STV090x_WIDTH_Px_FORCE_ENASAMP_FIELD 1 +#define STV090x_OFFST_Px_MANUAL_SXROLLOFF_FIELD 2 +#define STV090x_WIDTH_Px_MANUAL_SXROLLOFF_FIELD 1 +#define STV090x_OFFST_Px_ROLLOFF_CONTROL_FIELD 0 +#define STV090x_WIDTH_Px_ROLLOFF_CONTROL_FIELD 2 + +#define STV090x_Px_DMDMODCOD(__x) (0xF411 - (__x - 1) * 0x200) +#define STV090x_P1_DMDMODCOD STV090x_Px_DMDMODCOD(1) +#define STV090x_P2_DMDMODCOD STV090x_Px_DMDMODCOD(2) +#define STV090x_OFFST_Px_MANUAL_MODCOD_FIELD 7 +#define STV090x_WIDTH_Px_MANUAL_MODCOD_FIELD 1 +#define STV090x_OFFST_Px_DEMOD_MODCOD_FIELD 2 +#define STV090x_WIDTH_Px_DEMOD_MODCOD_FIELD 5 +#define STV090x_OFFST_Px_DEMOD_TYPE_FIELD 0 +#define STV090x_WIDTH_Px_DEMOD_TYPE_FIELD 2 + +#define STV090x_Px_DSTATUS(__x) (0xF412 - (__x - 1) * 0x200) +#define STV090x_P1_DSTATUS STV090x_Px_DSTATUS(1) +#define STV090x_P2_DSTATUS STV090x_Px_DSTATUS(2) +#define STV090x_OFFST_Px_CAR_LOCK_FIELD 7 +#define STV090x_WIDTH_Px_CAR_LOCK_FIELD 1 +#define STV090x_OFFST_Px_TMGLOCK_QUALITY_FIELD 5 +#define STV090x_WIDTH_Px_TMGLOCK_QUALITY_FIELD 2 +#define STV090x_OFFST_Px_LOCK_DEFINITIF_FIELD 3 +#define STV090x_WIDTH_Px_LOCK_DEFINITIF_FIELD 1 + +#define STV090x_Px_DSTATUS2(__x) (0xF413 - (__x - 1) * 0x200) +#define STV090x_P1_DSTATUS2 STV090x_Px_DSTATUS2(1) +#define STV090x_P2_DSTATUS2 STV090x_Px_DSTATUS2(2) +#define STV090x_OFFST_Px_DEMOD_DELOCK_FIELD 7 +#define STV090x_WIDTH_Px_DEMOD_DELOCK_FIELD 1 +#define STV090x_OFFST_Px_AGC1_NOSIGNALACK_FIELD 3 +#define STV090x_WIDTH_Px_AGC1_NOSIGNALACK_FIELD 1 +#define STV090x_OFFST_Px_AGC2_OVERFLOW_FIELD 2 +#define STV090x_WIDTH_Px_AGC2_OVERFLOW_FIELD 1 +#define STV090x_OFFST_Px_CFR_OVERFLOW_FIELD 1 +#define STV090x_WIDTH_Px_CFR_OVERFLOW_FIELD 1 +#define STV090x_OFFST_Px_GAMMA_OVERUNDER_FIELD 0 +#define STV090x_WIDTH_Px_GAMMA_OVERUNDER_FIELD 1 + +#define STV090x_Px_DMDCFGMD(__x) (0xF414 - (__x - 1) * 0x200) +#define STV090x_P1_DMDCFGMD STV090x_Px_DMDCFGMD(1) +#define STV090x_P2_DMDCFGMD STV090x_Px_DMDCFGMD(2) +#define STV090x_OFFST_Px_DVBS2_ENABLE_FIELD 7 +#define STV090x_WIDTH_Px_DVBS2_ENABLE_FIELD 1 +#define STV090x_OFFST_Px_DVBS1_ENABLE_FIELD 6 +#define STV090x_WIDTH_Px_DVBS1_ENABLE_FIELD 1 +#define STV090x_OFFST_Px_CFR_AUTOSCAN_FIELD 5 /* check */ +#define STV090x_WIDTH_Px_CFR_AUTOSCAN_FIELD 1 +#define STV090x_OFFST_Px_SCAN_ENABLE_FIELD 4 /* check */ +#define STV090x_WIDTH_Px_SCAN_ENABLE_FIELD 1 +#define STV090x_OFFST_Px_TUN_AUTOSCAN_FIELD 3 +#define STV090x_WIDTH_Px_TUN_AUTOSCAN_FIELD 1 +#define STV090x_OFFST_Px_NOFORCE_RELOCK_FIELD 2 +#define STV090x_WIDTH_Px_NOFORCE_RELOCK_FIELD 1 +#define STV090x_OFFST_Px_TUN_RNG_FIELD 0 +#define STV090x_WIDTH_Px_TUN_RNG_FIELD 2 + +#define STV090x_Px_DMDCFG2(__x) (0xF415 - (__x - 1) * 0x200) +#define STV090x_P1_DMDCFG2 STV090x_Px_DMDCFG2(1) +#define STV090x_P2_DMDCFG2 STV090x_Px_DMDCFG2(2) +#define STV090x_OFFST_Px_S1S2_SEQUENTIAL_FIELD 6 +#define STV090x_WIDTH_Px_S1S2_SEQUENTIAL_FIELD 1 + +#define STV090x_Px_DMDISTATE(__x) (0xF416 - (__x - 1) * 0x200) +#define STV090x_P1_DMDISTATE STV090x_Px_DMDISTATE(1) +#define STV090x_P2_DMDISTATE STV090x_Px_DMDISTATE(2) +#define STV090x_OFFST_Px_I2C_DEMOD_MODE_FIELD 0 +#define STV090x_WIDTH_Px_I2C_DEMOD_MODE_FIELD 5 + +#define STV090x_Px_DMDTOM(__x) (0xF417 - (__x - 1) * 0x200) /* check */ +#define STV090x_P1_DMDTOM STV090x_Px_DMDTOM(1) +#define STV090x_P2_DMDTOM STV090x_Px_DMDTOM(2) + +#define STV090x_Px_DMDSTATE(__x) (0xF41B - (__x - 1) * 0x200) +#define STV090x_P1_DMDSTATE STV090x_Px_DMDSTATE(1) +#define STV090x_P2_DMDSTATE STV090x_Px_DMDSTATE(2) +#define STV090x_OFFST_Px_HEADER_MODE_FIELD 5 +#define STV090x_WIDTH_Px_HEADER_MODE_FIELD 2 + +#define STV090x_Px_DMDFLYW(__x) (0xF41C - (__x - 1) * 0x200) +#define STV090x_P1_DMDFLYW STV090x_Px_DMDFLYW(1) +#define STV090x_P2_DMDFLYW STV090x_Px_DMDFLYW(2) +#define STV090x_OFFST_Px_I2C_IRQVAL_FIELD 4 +#define STV090x_WIDTH_Px_I2C_IRQVAL_FIELD 4 +#define STV090x_OFFST_Px_FLYWHEEL_CPT_FIELD 0 /* check */ +#define STV090x_WIDTH_Px_FLYWHEEL_CPT_FIELD 4 + +#define STV090x_Px_DSTATUS3(__x) (0xF41D - (__x - 1) * 0x200) +#define STV090x_P1_DSTATUS3 STV090x_Px_DSTATUS3(1) +#define STV090x_P2_DSTATUS3 STV090x_Px_DSTATUS3(2) +#define STV090x_OFFST_Px_DEMOD_CFGMODE_FIELD 5 +#define STV090x_WIDTH_Px_DEMOD_CFGMODE_FIELD 2 + +#define STV090x_Px_DMDCFG3(__x) (0xF41E - (__x - 1) * 0x200) +#define STV090x_P1_DMDCFG3 STV090x_Px_DMDCFG3(1) +#define STV090x_P2_DMDCFG3 STV090x_Px_DMDCFG3(2) +#define STV090x_OFFST_Px_NOSTOP_FIFOFULL_FIELD 3 +#define STV090x_WIDTH_Px_NOSTOP_FIFOFULL_FIELD 1 + +#define STV090x_Px_DMDCFG4(__x) (0xf41f - (__x - 1) * 0x200) +#define STV090x_P1_DMDCFG4 STV090x_Px_DMDCFG4(1) +#define STV090x_P2_DMDCFG4 STV090x_Px_DMDCFG4(2) + +#define STV090x_Px_CORRELMANT(__x) (0xF420 - (__x - 1) * 0x200) +#define STV090x_P1_CORRELMANT STV090x_Px_CORRELMANT(1) +#define STV090x_P2_CORRELMANT STV090x_Px_CORRELMANT(2) +#define STV090x_OFFST_Px_CORREL_MANT_FIELD 0 +#define STV090x_WIDTH_Px_CORREL_MANT_FIELD 8 + +#define STV090x_Px_CORRELABS(__x) (0xF421 - (__x - 1) * 0x200) +#define STV090x_P1_CORRELABS STV090x_Px_CORRELABS(1) +#define STV090x_P2_CORRELABS STV090x_Px_CORRELABS(2) +#define STV090x_OFFST_Px_CORREL_ABS_FIELD 0 +#define STV090x_WIDTH_Px_CORREL_ABS_FIELD 8 + +#define STV090x_Px_CORRELEXP(__x) (0xF422 - (__x - 1) * 0x200) +#define STV090x_P1_CORRELEXP STV090x_Px_CORRELEXP(1) +#define STV090x_P2_CORRELEXP STV090x_Px_CORRELEXP(2) +#define STV090x_OFFST_Px_CORREL_ABSEXP_FIELD 4 +#define STV090x_WIDTH_Px_CORREL_ABSEXP_FIELD 4 +#define STV090x_OFFST_Px_CORREL_EXP_FIELD 0 +#define STV090x_WIDTH_Px_CORREL_EXP_FIELD 4 + +#define STV090x_Px_PLHMODCOD(__x) (0xF424 - (__x - 1) * 0x200) +#define STV090x_P1_PLHMODCOD STV090x_Px_PLHMODCOD(1) +#define STV090x_P2_PLHMODCOD STV090x_Px_PLHMODCOD(2) +#define STV090x_OFFST_Px_SPECINV_DEMOD_FIELD 7 +#define STV090x_WIDTH_Px_SPECINV_DEMOD_FIELD 1 +#define STV090x_OFFST_Px_PLH_MODCOD_FIELD 2 +#define STV090x_WIDTH_Px_PLH_MODCOD_FIELD 5 +#define STV090x_OFFST_Px_PLH_TYPE_FIELD 0 +#define STV090x_WIDTH_Px_PLH_TYPE_FIELD 2 + +#define STV090x_Px_AGCK32(__x) (0xf42b - (__x - 1) * 0x200) +#define STV090x_P1_AGCK32 STV090x_Px_AGCK32(1) +#define STV090x_P2_AGCK32 STV090x_Px_AGCK32(2) + +#define STV090x_Px_AGC2O(__x) (0xF42C - (__x - 1) * 0x200) +#define STV090x_P1_AGC2O STV090x_Px_AGC2O(1) +#define STV090x_P2_AGC2O STV090x_Px_AGC2O(2) + +#define STV090x_Px_AGC2REF(__x) (0xF42D - (__x - 1) * 0x200) +#define STV090x_P1_AGC2REF STV090x_Px_AGC2REF(1) +#define STV090x_P2_AGC2REF STV090x_Px_AGC2REF(2) +#define STV090x_OFFST_Px_AGC2_REF_FIELD 0 +#define STV090x_WIDTH_Px_AGC2_REF_FIELD 8 + +#define STV090x_Px_AGC1ADJ(__x) (0xF42E - (__x - 1) * 0x200) +#define STV090x_P1_AGC1ADJ STV090x_Px_AGC1ADJ(1) +#define STV090x_P2_AGC1ADJ STV090x_Px_AGC1ADJ(2) +#define STV090x_OFFST_Px_AGC1_ADJUSTED_FIELD 0 +#define STV090x_WIDTH_Px_AGC1_ADJUSTED_FIELD 7 + +#define STV090x_Px_AGC2Iy(__x, __y) (0xF437 - (__x - 1) * 0x200 - __y * 0x1) +#define STV090x_P1_AGC2I0 STV090x_Px_AGC2Iy(1, 0) +#define STV090x_P1_AGC2I1 STV090x_Px_AGC2Iy(1, 1) +#define STV090x_P2_AGC2I0 STV090x_Px_AGC2Iy(2, 0) +#define STV090x_P2_AGC2I1 STV090x_Px_AGC2Iy(2, 1) +#define STV090x_OFFST_Px_AGC2_INTEGRATOR_FIELD 0 +#define STV090x_WIDTH_Px_AGC2_INTEGRATOR_FIELD 8 + +#define STV090x_Px_CARCFG(__x) (0xF438 - (__x - 1) * 0x200) +#define STV090x_P1_CARCFG STV090x_Px_CARCFG(1) +#define STV090x_P2_CARCFG STV090x_Px_CARCFG(2) +#define STV090x_OFFST_Px_EN_CAR2CENTER_FIELD 5 +#define STV090x_WIDTH_Px_EN_CAR2CENTER_FIELD 1 +#define STV090x_OFFST_Px_ROTATON_FIELD 2 +#define STV090x_WIDTH_Px_ROTATON_FIELD 1 +#define STV090x_OFFST_Px_PH_DET_ALGO_FIELD 0 +#define STV090x_WIDTH_Px_PH_DET_ALGO_FIELD 2 + +#define STV090x_Px_ACLC(__x) (0xF439 - (__x - 1) * 0x200) +#define STV090x_P1_ACLC STV090x_Px_ACLC(1) +#define STV090x_P2_ACLC STV090x_Px_ACLC(2) +#define STV090x_OFFST_Px_CAR_ALPHA_MANT_FIELD 4 +#define STV090x_WIDTH_Px_CAR_ALPHA_MANT_FIELD 2 +#define STV090x_OFFST_Px_CAR_ALPHA_EXP_FIELD 0 +#define STV090x_WIDTH_Px_CAR_ALPHA_EXP_FIELD 4 + +#define STV090x_Px_BCLC(__x) (0xF43A - (__x - 1) * 0x200) +#define STV090x_P1_BCLC STV090x_Px_BCLC(1) +#define STV090x_P2_BCLC STV090x_Px_BCLC(2) +#define STV090x_OFFST_Px_CAR_BETA_MANT_FIELD 4 +#define STV090x_WIDTH_Px_CAR_BETA_MANT_FIELD 2 +#define STV090x_OFFST_Px_CAR_BETA_EXP_FIELD 0 +#define STV090x_WIDTH_Px_CAR_BETA_EXP_FIELD 4 + +#define STV090x_Px_CARFREQ(__x) (0xF43D - (__x - 1) * 0x200) +#define STV090x_P1_CARFREQ STV090x_Px_CARFREQ(1) +#define STV090x_P2_CARFREQ STV090x_Px_CARFREQ(2) +#define STV090x_OFFST_Px_KC_COARSE_EXP_FIELD 4 +#define STV090x_WIDTH_Px_KC_COARSE_EXP_FIELD 4 +#define STV090x_OFFST_Px_BETA_FREQ_FIELD 0 +#define STV090x_WIDTH_Px_BETA_FREQ_FIELD 4 + +#define STV090x_Px_CARHDR(__x) (0xF43E - (__x - 1) * 0x200) +#define STV090x_P1_CARHDR STV090x_Px_CARHDR(1) +#define STV090x_P2_CARHDR STV090x_Px_CARHDR(2) +#define STV090x_OFFST_Px_FREQ_HDR_FIELD 0 +#define STV090x_WIDTH_Px_FREQ_HDR_FIELD 8 + +#define STV090x_Px_LDT(__x) (0xF43F - (__x - 1) * 0x200) +#define STV090x_P1_LDT STV090x_Px_LDT(1) +#define STV090x_P2_LDT STV090x_Px_LDT(2) +#define STV090x_OFFST_Px_CARLOCK_THRES_FIELD 0 +#define STV090x_WIDTH_Px_CARLOCK_THRES_FIELD 8 + +#define STV090x_Px_LDT2(__x) (0xF440 - (__x - 1) * 0x200) +#define STV090x_P1_LDT2 STV090x_Px_LDT2(1) +#define STV090x_P2_LDT2 STV090x_Px_LDT2(2) +#define STV090x_OFFST_Px_CARLOCK_THRES2_FIELD 0 +#define STV090x_WIDTH_Px_CARLOCK_THRES2_FIELD 8 + +#define STV090x_Px_CFRICFG(__x) (0xF441 - (__x - 1) * 0x200) +#define STV090x_P1_CFRICFG STV090x_Px_CFRICFG(1) +#define STV090x_P2_CFRICFG STV090x_Px_CFRICFG(2) +#define STV090x_OFFST_Px_NEG_CFRSTEP_FIELD 0 +#define STV090x_WIDTH_Px_NEG_CFRSTEP_FIELD 1 + +#define STV090x_Pn_CFRUPy(__x, __y) (0xF443 - (__x - 1) * 0x200 - __y * 0x1) +#define STV090x_P1_CFRUP0 STV090x_Pn_CFRUPy(1, 0) +#define STV090x_P1_CFRUP1 STV090x_Pn_CFRUPy(1, 1) +#define STV090x_P2_CFRUP0 STV090x_Pn_CFRUPy(2, 0) +#define STV090x_P2_CFRUP1 STV090x_Pn_CFRUPy(2, 1) +#define STV090x_OFFST_Px_CFR_UP_FIELD 0 +#define STV090x_WIDTH_Px_CFR_UP_FIELD 8 + +#define STV090x_Pn_CFRLOWy(__x, __y) (0xF447 - (__x - 1) * 0x200 - __y * 0x1) +#define STV090x_P1_CFRLOW0 STV090x_Pn_CFRLOWy(1, 0) +#define STV090x_P1_CFRLOW1 STV090x_Pn_CFRLOWy(1, 1) +#define STV090x_P2_CFRLOW0 STV090x_Pn_CFRLOWy(2, 0) +#define STV090x_P2_CFRLOW1 STV090x_Pn_CFRLOWy(2, 1) +#define STV090x_OFFST_Px_CFR_LOW_FIELD 0 +#define STV090x_WIDTH_Px_CFR_LOW_FIELD 8 + +#define STV090x_Pn_CFRINITy(__x, __y) (0xF449 - (__x - 1) * 0x200 - __y * 0x1) +#define STV090x_P1_CFRINIT0 STV090x_Pn_CFRINITy(1, 0) +#define STV090x_P1_CFRINIT1 STV090x_Pn_CFRINITy(1, 1) +#define STV090x_P2_CFRINIT0 STV090x_Pn_CFRINITy(2, 0) +#define STV090x_P2_CFRINIT1 STV090x_Pn_CFRINITy(2, 1) +#define STV090x_OFFST_Px_CFR_INIT_FIELD 0 +#define STV090x_WIDTH_Px_CFR_INIT_FIELD 8 + +#define STV090x_Px_CFRINC1(__x) (0xF44A - (__x - 1) * 0x200) +#define STV090x_P1_CFRINC1 STV090x_Px_CFRINC1(1) +#define STV090x_P2_CFRINC1 STV090x_Px_CFRINC1(2) +#define STV090x_OFFST_Px_CFR_INC1_FIELD 0 +#define STV090x_WIDTH_Px_CFR_INC1_FIELD 7 + +#define STV090x_Px_CFRINC0(__x) (0xF44B - (__x - 1) * 0x200) +#define STV090x_P1_CFRINC0 STV090x_Px_CFRINC0(1) +#define STV090x_P2_CFRINC0 STV090x_Px_CFRINC0(2) +#define STV090x_OFFST_Px_CFR_INC0_FIELD 4 +#define STV090x_WIDTH_Px_CFR_INC0_FIELD 4 + +#define STV090x_Pn_CFRy(__x, __y) (0xF44E - (__x - 1) * 0x200 - __y * 0x1) +#define STV090x_P1_CFR0 STV090x_Pn_CFRy(1, 0) +#define STV090x_P1_CFR1 STV090x_Pn_CFRy(1, 1) +#define STV090x_P1_CFR2 STV090x_Pn_CFRy(1, 2) +#define STV090x_P2_CFR0 STV090x_Pn_CFRy(2, 0) +#define STV090x_P2_CFR1 STV090x_Pn_CFRy(2, 1) +#define STV090x_P2_CFR2 STV090x_Pn_CFRy(2, 2) +#define STV090x_OFFST_Px_CAR_FREQ_FIELD 0 +#define STV090x_WIDTH_Px_CAR_FREQ_FIELD 8 + +#define STV090x_Px_LDI(__x) (0xF44F - (__x - 1) * 0x200) +#define STV090x_P1_LDI STV090x_Px_LDI(1) +#define STV090x_P2_LDI STV090x_Px_LDI(2) +#define STV090x_OFFST_Px_LOCK_DET_INTEGR_FIELD 0 +#define STV090x_WIDTH_Px_LOCK_DET_INTEGR_FIELD 8 + +#define STV090x_Px_TMGCFG(__x) (0xF450 - (__x - 1) * 0x200) +#define STV090x_P1_TMGCFG STV090x_Px_TMGCFG(1) +#define STV090x_P2_TMGCFG STV090x_Px_TMGCFG(2) +#define STV090x_OFFST_Px_TMGLOCK_BETA_FIELD 6 +#define STV090x_WIDTH_Px_TMGLOCK_BETA_FIELD 2 +#define STV090x_OFFST_Px_DO_TIMING_FIELD 4 +#define STV090x_WIDTH_Px_DO_TIMING_FIELD 1 +#define STV090x_OFFST_Px_TMG_MINFREQ_FIELD 0 +#define STV090x_WIDTH_Px_TMG_MINFREQ_FIELD 2 + +#define STV090x_Px_RTC(__x) (0xF451 - (__x - 1) * 0x200) +#define STV090x_P1_RTC STV090x_Px_RTC(1) +#define STV090x_P2_RTC STV090x_Px_RTC(2) +#define STV090x_OFFST_Px_TMGALPHA_EXP_FIELD 4 +#define STV090x_WIDTH_Px_TMGALPHA_EXP_FIELD 4 +#define STV090x_OFFST_Px_TMGBETA_EXP_FIELD 0 +#define STV090x_WIDTH_Px_TMGBETA_EXP_FIELD 4 + +#define STV090x_Px_RTCS2(__x) (0xF452 - (__x - 1) * 0x200) +#define STV090x_P1_RTCS2 STV090x_Px_RTCS2(1) +#define STV090x_P2_RTCS2 STV090x_Px_RTCS2(2) +#define STV090x_OFFST_Px_TMGALPHAS2_EXP_FIELD 4 +#define STV090x_WIDTH_Px_TMGALPHAS2_EXP_FIELD 4 +#define STV090x_OFFST_Px_TMGBETAS2_EXP_FIELD 0 +#define STV090x_WIDTH_Px_TMGBETAS2_EXP_FIELD 4 + +#define STV090x_Px_TMGTHRISE(__x) (0xF453 - (__x - 1) * 0x200) +#define STV090x_P1_TMGTHRISE STV090x_Px_TMGTHRISE(1) +#define STV090x_P2_TMGTHRISE STV090x_Px_TMGTHRISE(2) +#define STV090x_OFFST_Px_TMGLOCK_THRISE_FIELD 0 +#define STV090x_WIDTH_Px_TMGLOCK_THRISE_FIELD 8 + +#define STV090x_Px_TMGTHFALL(__x) (0xF454 - (__x - 1) * 0x200) +#define STV090x_P1_TMGTHFALL STV090x_Px_TMGTHFALL(1) +#define STV090x_P2_TMGTHFALL STV090x_Px_TMGTHFALL(2) +#define STV090x_OFFST_Px_TMGLOCK_THFALL_FIELD 0 +#define STV090x_WIDTH_Px_TMGLOCK_THFALL_FIELD 8 + +#define STV090x_Px_SFRUPRATIO(__x) (0xF455 - (__x - 1) * 0x200) +#define STV090x_P1_SFRUPRATIO STV090x_Px_SFRUPRATIO(1) +#define STV090x_P2_SFRUPRATIO STV090x_Px_SFRUPRATIO(2) +#define STV090x_OFFST_Px_SFR_UPRATIO_FIELD 0 +#define STV090x_WIDTH_Px_SFR_UPRATIO_FIELD 8 + +#define STV090x_Px_SFRLOWRATIO(__x) (0xF456 - (__x - 1) * 0x200) +#define STV090x_P1_SFRLOWRATIO STV090x_Px_SFRLOWRATIO(1) +#define STV090x_P2_SFRLOWRATIO STV090x_Px_SFRLOWRATIO(2) +#define STV090x_OFFST_Px_SFR_LOWRATIO_FIELD 0 +#define STV090x_WIDTH_Px_SFR_LOWRATIO_FIELD 8 + +#define STV090x_Px_KREFTMG(__x) (0xF458 - (__x - 1) * 0x200) +#define STV090x_P1_KREFTMG STV090x_Px_KREFTMG(1) +#define STV090x_P2_KREFTMG STV090x_Px_KREFTMG(2) +#define STV090x_OFFST_Px_KREF_TMG_FIELD 0 +#define STV090x_WIDTH_Px_KREF_TMG_FIELD 8 + +#define STV090x_Px_SFRSTEP(__x) (0xF459 - (__x - 1) * 0x200) +#define STV090x_P1_SFRSTEP STV090x_Px_SFRSTEP(1) +#define STV090x_P2_SFRSTEP STV090x_Px_SFRSTEP(2) +#define STV090x_OFFST_Px_SFR_SCANSTEP_FIELD 4 +#define STV090x_WIDTH_Px_SFR_SCANSTEP_FIELD 4 +#define STV090x_OFFST_Px_SFR_CENTERSTEP_FIELD 0 +#define STV090x_WIDTH_Px_SFR_CENTERSTEP_FIELD 4 + +#define STV090x_Px_TMGCFG2(__x) (0xF45A - (__x - 1) * 0x200) +#define STV090x_P1_TMGCFG2 STV090x_Px_TMGCFG2(1) +#define STV090x_P2_TMGCFG2 STV090x_Px_TMGCFG2(2) +#define STV090x_OFFST_Px_SFRRATIO_FINE_FIELD 0 +#define STV090x_WIDTH_Px_SFRRATIO_FINE_FIELD 1 + +#define STV090x_Px_SFRINIT1(__x) (0xF45E - (__x - 1) * 0x200) +#define STV090x_P1_SFRINIT1 STV090x_Px_SFRINIT1(1) +#define STV090x_P2_SFRINIT1 STV090x_Px_SFRINIT1(2) +#define STV090x_OFFST_Px_SFR_INIT_FIELD 0 +#define STV090x_WIDTH_Px_SFR_INIT_FIELD 8 + +#define STV090x_Px_SFRINIT0(__x) (0xF45F - (__x - 1) * 0x200) +#define STV090x_P1_SFRINIT0 STV090x_Px_SFRINIT0(1) +#define STV090x_P2_SFRINIT0 STV090x_Px_SFRINIT0(2) +#define STV090x_OFFST_Px_SFR_INIT_FIELD 0 +#define STV090x_WIDTH_Px_SFR_INIT_FIELD 8 + +#define STV090x_Px_SFRUP1(__x) (0xF460 - (__x - 1) * 0x200) +#define STV090x_P1_SFRUP1 STV090x_Px_SFRUP1(1) +#define STV090x_P2_SFRUP1 STV090x_Px_SFRUP1(2) +#define STV090x_OFFST_Px_SYMB_FREQ_UP1_FIELD 0 +#define STV090x_WIDTH_Px_SYMB_FREQ_UP1_FIELD 7 + +#define STV090x_Px_SFRUP0(__x) (0xF461 - (__x - 1) * 0x200) +#define STV090x_P1_SFRUP0 STV090x_Px_SFRUP0(1) +#define STV090x_P2_SFRUP0 STV090x_Px_SFRUP0(2) +#define STV090x_OFFST_Px_SYMB_FREQ_UP0_FIELD 0 +#define STV090x_WIDTH_Px_SYMB_FREQ_UP0_FIELD 8 + +#define STV090x_Px_SFRLOW1(__x) (0xF462 - (__x - 1) * 0x200) +#define STV090x_P1_SFRLOW1 STV090x_Px_SFRLOW1(1) +#define STV090x_P2_SFRLOW1 STV090x_Px_SFRLOW1(2) +#define STV090x_OFFST_Px_SYMB_FREQ_LOW1_FIELD 0 +#define STV090x_WIDTH_Px_SYMB_FREQ_LOW1_FIELD 7 + +#define STV090x_Px_SFRLOW0(__x) (0xF463 - (__x - 1) * 0x200) +#define STV090x_P1_SFRLOW0 STV090x_Px_SFRLOW0(1) +#define STV090x_P2_SFRLOW0 STV090x_Px_SFRLOW0(2) +#define STV090x_OFFST_Px_SYMB_FREQ_LOW0_FIELD 0 +#define STV090x_WIDTH_Px_SYMB_FREQ_LOW0_FIELD 8 + +#define STV090x_Px_SFRy(__x, __y) (0xF464 - (__x-1) * 0x200 + (3 - __y)) +#define STV090x_P1_SFR0 STV090x_Px_SFRy(1, 0) +#define STV090x_P1_SFR1 STV090x_Px_SFRy(1, 1) +#define STV090x_P1_SFR2 STV090x_Px_SFRy(1, 2) +#define STV090x_P1_SFR3 STV090x_Px_SFRy(1, 3) +#define STV090x_P2_SFR0 STV090x_Px_SFRy(2, 0) +#define STV090x_P2_SFR1 STV090x_Px_SFRy(2, 1) +#define STV090x_P2_SFR2 STV090x_Px_SFRy(2, 2) +#define STV090x_P2_SFR3 STV090x_Px_SFRy(2, 3) +#define STV090x_OFFST_Px_SYMB_FREQ_FIELD 0 +#define STV090x_WIDTH_Px_SYMB_FREQ_FIELD 32 + +#define STV090x_Px_TMGREG2(__x) (0xF468 - (__x - 1) * 0x200) +#define STV090x_P1_TMGREG2 STV090x_Px_TMGREG2(1) +#define STV090x_P2_TMGREG2 STV090x_Px_TMGREG2(2) +#define STV090x_OFFST_Px_TMGREG_FIELD 0 +#define STV090x_WIDTH_Px_TMGREG_FIELD 8 + +#define STV090x_Px_TMGREG1(__x) (0xF469 - (__x - 1) * 0x200) +#define STV090x_P1_TMGREG1 STV090x_Px_TMGREG1(1) +#define STV090x_P2_TMGREG1 STV090x_Px_TMGREG1(2) +#define STV090x_OFFST_Px_TMGREG_FIELD 0 +#define STV090x_WIDTH_Px_TMGREG_FIELD 8 + +#define STV090x_Px_TMGREG0(__x) (0xF46A - (__x - 1) * 0x200) +#define STV090x_P1_TMGREG0 STV090x_Px_TMGREG0(1) +#define STV090x_P2_TMGREG0 STV090x_Px_TMGREG0(2) +#define STV090x_OFFST_Px_TMGREG_FIELD 0 +#define STV090x_WIDTH_Px_TMGREG_FIELD 8 + +#define STV090x_Px_TMGLOCKy(__x, __y) (0xF46C - (__x - 1) * 0x200 - __y * 0x1) +#define STV090x_P1_TMGLOCK0 STV090x_Px_TMGLOCKy(1, 0) +#define STV090x_P1_TMGLOCK1 STV090x_Px_TMGLOCKy(1, 1) +#define STV090x_P2_TMGLOCK0 STV090x_Px_TMGLOCKy(2, 0) +#define STV090x_P2_TMGLOCK1 STV090x_Px_TMGLOCKy(2, 1) +#define STV090x_OFFST_Px_TMGLOCK_LEVEL_FIELD 0 +#define STV090x_WIDTH_Px_TMGLOCK_LEVEL_FIELD 8 + +#define STV090x_Px_TMGOBS(__x) (0xF46D - (__x - 1) * 0x200) +#define STV090x_P1_TMGOBS STV090x_Px_TMGOBS(1) +#define STV090x_P2_TMGOBS STV090x_Px_TMGOBS(2) +#define STV090x_OFFST_Px_ROLLOFF_STATUS_FIELD 6 +#define STV090x_WIDTH_Px_ROLLOFF_STATUS_FIELD 2 + +#define STV090x_Px_EQUALCFG(__x) (0xF46F - (__x - 1) * 0x200) +#define STV090x_P1_EQUALCFG STV090x_Px_EQUALCFG(1) +#define STV090x_P2_EQUALCFG STV090x_Px_EQUALCFG(2) +#define STV090x_OFFST_Px_EQUAL_ON_FIELD 6 +#define STV090x_WIDTH_Px_EQUAL_ON_FIELD 1 +#define STV090x_OFFST_Px_MU_EQUALDFE_FIELD 0 +#define STV090x_WIDTH_Px_MU_EQUALDFE_FIELD 3 + +#define STV090x_Px_EQUAIy(__x, __y) (0xf470 - (__x - 1) * 0x200 + (__y - 1)) +#define STV090x_P1_EQUAI1 STV090x_Px_EQUAIy(1, 1) +#define STV090x_P1_EQUAI2 STV090x_Px_EQUAIy(1, 2) +#define STV090x_P1_EQUAI3 STV090x_Px_EQUAIy(1, 3) +#define STV090x_P1_EQUAI4 STV090x_Px_EQUAIy(1, 4) +#define STV090x_P1_EQUAI5 STV090x_Px_EQUAIy(1, 5) +#define STV090x_P1_EQUAI6 STV090x_Px_EQUAIy(1, 6) +#define STV090x_P1_EQUAI7 STV090x_Px_EQUAIy(1, 7) +#define STV090x_P1_EQUAI8 STV090x_Px_EQUAIy(1, 8) + +#define STV090x_P2_EQUAI1 STV090x_Px_EQUAIy(2, 1) +#define STV090x_P2_EQUAI2 STV090x_Px_EQUAIy(2, 2) +#define STV090x_P2_EQUAI3 STV090x_Px_EQUAIy(2, 3) +#define STV090x_P2_EQUAI4 STV090x_Px_EQUAIy(2, 4) +#define STV090x_P2_EQUAI5 STV090x_Px_EQUAIy(2, 5) +#define STV090x_P2_EQUAI6 STV090x_Px_EQUAIy(2, 6) +#define STV090x_P2_EQUAI7 STV090x_Px_EQUAIy(2, 7) +#define STV090x_P2_EQUAI8 STV090x_Px_EQUAIy(2, 8) +#define STV090x_OFFST_Px_EQUA_ACCIy_FIELD 0 +#define STV090x_WIDTH_Px_EQUA_ACCIy_FIELD 8 + +#define STV090x_Px_EQUAQy(__x, __y) (0xf471 - (__x - 1) * 0x200 + (__y - 1)) +#define STV090x_P1_EQUAQ1 STV090x_Px_EQUAQy(1, 1) +#define STV090x_P1_EQUAQ2 STV090x_Px_EQUAQy(1, 2) +#define STV090x_P1_EQUAQ3 STV090x_Px_EQUAQy(1, 3) +#define STV090x_P1_EQUAQ4 STV090x_Px_EQUAQy(1, 4) +#define STV090x_P1_EQUAQ5 STV090x_Px_EQUAQy(1, 5) +#define STV090x_P1_EQUAQ6 STV090x_Px_EQUAQy(1, 6) +#define STV090x_P1_EQUAQ7 STV090x_Px_EQUAQy(1, 7) +#define STV090x_P1_EQUAQ8 STV090x_Px_EQUAQy(1, 8) + +#define STV090x_P2_EQUAQ1 STV090x_Px_EQUAQy(2, 1) +#define STV090x_P2_EQUAQ2 STV090x_Px_EQUAQy(2, 2) +#define STV090x_P2_EQUAQ3 STV090x_Px_EQUAQy(2, 3) +#define STV090x_P2_EQUAQ4 STV090x_Px_EQUAQy(2, 4) +#define STV090x_P2_EQUAQ5 STV090x_Px_EQUAQy(2, 5) +#define STV090x_P2_EQUAQ6 STV090x_Px_EQUAQy(2, 6) +#define STV090x_P2_EQUAQ7 STV090x_Px_EQUAQy(2, 7) +#define STV090x_P2_EQUAQ8 STV090x_Px_EQUAQy(2, 8) +#define STV090x_OFFST_Px_EQUA_ACCQy_FIELD 0 +#define STV090x_WIDTH_Px_EQUA_ACCQy_FIELD 8 + +#define STV090x_Px_NNOSDATATy(__x, __y) (0xf481 - (__x - 1) * 0x200 - __y * 0x1) +#define STV090x_P1_NNOSDATAT0 STV090x_Px_NNOSDATATy(1, 0) +#define STV090x_P1_NNOSDATAT1 STV090x_Px_NNOSDATATy(1, 1) +#define STV090x_P2_NNOSDATAT0 STV090x_Px_NNOSDATATy(2, 0) +#define STV090x_P2_NNOSDATAT1 STV090x_Px_NNOSDATATy(2, 1) +#define STV090x_OFFST_Px_NOSDATAT_NORMED_FIELD 0 +#define STV090x_WIDTH_Px_NOSDATAT_NORMED_FIELD 8 + +#define STV090x_Px_NNOSDATAy(__x, __y) (0xf483 - (__x - 1) * 0x200 - __y * 0x1) +#define STV090x_P1_NNOSDATA0 STV090x_Px_NNOSDATAy(1, 0) +#define STV090x_P1_NNOSDATA1 STV090x_Px_NNOSDATAy(1, 1) +#define STV090x_P2_NNOSDATA0 STV090x_Px_NNOSDATAy(2, 0) +#define STV090x_P2_NNOSDATA1 STV090x_Px_NNOSDATAy(2, 1) +#define STV090x_OFFST_Px_NOSDATA_NORMED_FIELD 0 +#define STV090x_WIDTH_Px_NOSDATA_NORMED_FIELD 8 + +#define STV090x_Px_NNOSPLHTy(__x, __y) (0xf485 - (__x - 1) * 0x200 - __y * 0x1) +#define STV090x_P1_NNOSPLHT0 STV090x_Px_NNOSPLHTy(1, 0) +#define STV090x_P1_NNOSPLHT1 STV090x_Px_NNOSPLHTy(1, 1) +#define STV090x_P2_NNOSPLHT0 STV090x_Px_NNOSPLHTy(2, 0) +#define STV090x_P2_NNOSPLHT1 STV090x_Px_NNOSPLHTy(2, 1) +#define STV090x_OFFST_Px_NOSPLHT_NORMED_FIELD 0 +#define STV090x_WIDTH_Px_NOSPLHT_NORMED_FIELD 8 + +#define STV090x_Px_NNOSPLHy(__x, __y) (0xf487 - (__x - 1) * 0x200 - __y * 0x1) +#define STV090x_P1_NNOSPLH0 STV090x_Px_NNOSPLHy(1, 0) +#define STV090x_P1_NNOSPLH1 STV090x_Px_NNOSPLHy(1, 1) +#define STV090x_P2_NNOSPLH0 STV090x_Px_NNOSPLHy(2, 0) +#define STV090x_P2_NNOSPLH1 STV090x_Px_NNOSPLHy(2, 1) +#define STV090x_OFFST_Px_NOSPLH_NORMED_FIELD 0 +#define STV090x_WIDTH_Px_NOSPLH_NORMED_FIELD 8 + +#define STV090x_Px_NOSDATATy(__x, __y) (0xf489 - (__x - 1) * 0x200 - __y * 0x1) +#define STV090x_P1_NOSDATAT0 STV090x_Px_NOSDATATy(1, 0) +#define STV090x_P1_NOSDATAT1 STV090x_Px_NOSDATATy(1, 1) +#define STV090x_P2_NOSDATAT0 STV090x_Px_NOSDATATy(2, 0) +#define STV090x_P2_NOSDATAT1 STV090x_Px_NOSDATATy(2, 1) +#define STV090x_OFFST_Px_NOSDATAT_UNNORMED_FIELD 0 +#define STV090x_WIDTH_Px_NOSDATAT_UNNORMED_FIELD 8 + +#define STV090x_Px_NOSDATAy(__x, __y) (0xf48b - (__x - 1) * 0x200 - __y * 0x1) +#define STV090x_P1_NOSDATA0 STV090x_Px_NOSDATAy(1, 0) +#define STV090x_P1_NOSDATA1 STV090x_Px_NOSDATAy(1, 1) +#define STV090x_P2_NOSDATA0 STV090x_Px_NOSDATAy(2, 0) +#define STV090x_P2_NOSDATA1 STV090x_Px_NOSDATAy(2, 1) +#define STV090x_OFFST_Px_NOSDATA_UNNORMED_FIELD 0 +#define STV090x_WIDTH_Px_NOSDATA_UNNORMED_FIELD 8 + +#define STV090x_Px_NOSPLHTy(__x, __y) (0xf48d - (__x - 1) * 0x200 - __y * 0x1) +#define STV090x_P1_NOSPLHT0 STV090x_Px_NOSPLHTy(1, 0) +#define STV090x_P1_NOSPLHT1 STV090x_Px_NOSPLHTy(1, 1) +#define STV090x_P2_NOSPLHT0 STV090x_Px_NOSPLHTy(2, 0) +#define STV090x_P2_NOSPLHT1 STV090x_Px_NOSPLHTy(2, 1) +#define STV090x_OFFST_Px_NOSPLHT_UNNORMED_FIELD 0 +#define STV090x_WIDTH_Px_NOSPLHT_UNNORMED_FIELD 8 + +#define STV090x_Px_NOSPLHy(__x, __y) (0xf48f - (__x - 1) * 0x200 - __y * 0x1) +#define STv090x_P1_NOSPLH0 STV090x_Px_NOSPLHy(1, 0) +#define STv090x_P1_NOSPLH1 STV090x_Px_NOSPLHy(1, 1) +#define STv090x_P2_NOSPLH0 STV090x_Px_NOSPLHy(2, 0) +#define STv090x_P2_NOSPLH1 STV090x_Px_NOSPLHy(2, 1) +#define STV090x_OFFST_Px_NOSPLH_UNNORMED_FIELD 0 +#define STV090x_WIDTH_Px_NOSPLH_UNNORMED_FIELD 8 + +#define STV090x_Px_CAR2CFG(__x) (0xf490 - (__x - 1) * 0x200) +#define STV090x_P1_CAR2CFG STV090x_Px_CAR2CFG(1) +#define STV090x_P2_CAR2CFG STV090x_Px_CAR2CFG(2) +#define STV090x_OFFST_Px_PN4_SELECT_FIELD 6 +#define STV090x_WIDTH_Px_PN4_SELECT_FIELD 1 +#define STV090x_OFFST_Px_CFR2_STOPDVBS1_FIELD 5 +#define STV090x_WIDTH_Px_CFR2_STOPDVBS1_FIELD 1 +#define STV090x_OFFST_Px_ROTA2ON_FIELD 2 +#define STV090x_WIDTH_Px_ROTA2ON_FIELD 1 +#define STV090x_OFFST_Px_PH_DET_ALGO2_FIELD 0 +#define STV090x_WIDTH_Px_PH_DET_ALGO2_FIELD 2 + +#define STV090x_Px_ACLC2(__x) (0xf491 - (__x - 1) * 0x200) +#define STV090x_P1_ACLC2 STV090x_Px_ACLC2(1) +#define STV090x_P2_ACLC2 STV090x_Px_ACLC2(2) +#define STV090x_OFFST_Px_CAR2_ALPHA_MANT_FIELD 4 +#define STV090x_WIDTH_Px_CAR2_ALPHA_MANT_FIELD 2 +#define STV090x_OFFST_Px_CAR2_ALPHA_EXP_FIELD 0 +#define STV090x_WIDTH_Px_CAR2_ALPHA_EXP_FIELD 4 + +#define STV090x_Px_BCLC2(__x) (0xf492 - (__x - 1) * 0x200) +#define STV090x_P1_BCLC2 STV090x_Px_BCLC2(1) +#define STV090x_P2_BCLC2 STV090x_Px_BCLC2(2) +#define STV090x_OFFST_Px_CAR2_BETA_MANT_FIELD 4 +#define STV090x_WIDTH_Px_CAR2_BETA_MANT_FIELD 2 +#define STV090x_OFFST_Px_CAR2_BETA_EXP_FIELD 0 +#define STV090x_WIDTH_Px_CAR2_BETA_EXP_FIELD 4 + +#define STV090x_Px_ACLC2S2Q(__x) (0xf497 - (__x - 1) * 0x200) +#define STV090x_P1_ACLC2S2Q STV090x_Px_ACLC2S2Q(1) +#define STV090x_P2_ACLC2S2Q STV090x_Px_ACLC2S2Q(2) +#define STV090x_OFFST_Px_ENAB_SPSKSYMB_FIELD 7 +#define STV090x_WIDTH_Px_ENAB_SPSKSYMB_FIELD 1 +#define STV090x_OFFST_Px_CAR2S2_Q_ALPH_M_FIELD 4 +#define STV090x_WIDTH_Px_CAR2S2_Q_ALPH_M_FIELD 2 +#define STV090x_OFFST_Px_CAR2S2_Q_ALPH_E_FIELD 0 +#define STV090x_WIDTH_Px_CAR2S2_Q_ALPH_E_FIELD 4 + +#define STV090x_Px_ACLC2S28(__x) (0xf498 - (__x - 1) * 0x200) +#define STV090x_P1_ACLC2S28 STV090x_Px_ACLC2S28(1) +#define STV090x_P2_ACLC2S28 STV090x_Px_ACLC2S28(2) +#define STV090x_OFFST_Px_CAR2S2_8_ALPH_M_FIELD 4 +#define STV090x_WIDTH_Px_CAR2S2_8_ALPH_M_FIELD 2 +#define STV090x_OFFST_Px_CAR2S2_8_ALPH_E_FIELD 0 +#define STV090x_WIDTH_Px_CAR2S2_8_ALPH_E_FIELD 4 + +#define STV090x_Px_ACLC2S216A(__x) (0xf499 - (__x - 1) * 0x200) +#define STV090x_P1_ACLC2S216A STV090x_Px_ACLC2S216A(1) +#define STV090x_P2_ACLC2S216A STV090x_Px_ACLC2S216A(2) +#define STV090x_OFFST_Px_CAR2S2_16A_ALPH_M_FIELD 4 +#define STV090x_WIDTH_Px_CAR2S2_16A_ALPH_M_FIELD 2 +#define STV090x_OFFST_Px_CAR2S2_16A_ALPH_E_FIELD 0 +#define STV090x_WIDTH_Px_CAR2S2_16A_ALPH_E_FIELD 4 + +#define STV090x_Px_ACLC2S232A(__x) (0xf499 - (__x - 1) * 0x200) +#define STV090x_P1_ACLC2S232A STV090x_Px_ACLC2S232A(1) +#define STV090x_P2_ACLC2S232A STV090x_Px_ACLC2S232A(2) +#define STV090x_OFFST_Px_CAR2S2_32A_ALPH_M_FIELD 4 +#define STV090x_WIDTH_Px_CAR2S2_32A_ALPH_M_FIELD 2 +#define STV090x_OFFST_Px_CAR2S2_32A_ALPH_E_FIELD 0 +#define STV090x_WIDTH_Px_CAR2S2_32A_ALPH_E_FIELD 4 + +#define STV090x_Px_BCLC2S2Q(__x) (0xf49c - (__x - 1) * 0x200) +#define STV090x_P1_BCLC2S2Q STV090x_Px_BCLC2S2Q(1) +#define STV090x_P2_BCLC2S2Q STV090x_Px_BCLC2S2Q(2) +#define STV090x_OFFST_Px_CAR2S2_Q_BETA_M_FIELD 4 +#define STV090x_WIDTH_Px_CAR2S2_Q_BETA_M_FIELD 2 +#define STV090x_OFFST_Px_CAR2S2_Q_BETA_E_FIELD 0 +#define STV090x_WIDTH_Px_CAR2S2_Q_BETA_E_FIELD 4 + +#define STV090x_Px_BCLC2S28(__x) (0xf49d - (__x - 1) * 0x200) +#define STV090x_P1_BCLC2S28 STV090x_Px_BCLC2S28(1) +#define STV090x_P2_BCLC2S28 STV090x_Px_BCLC2S28(1) +#define STV090x_OFFST_Px_CAR2S2_8_BETA_M_FIELD 4 +#define STV090x_WIDTH_Px_CAR2S2_8_BETA_M_FIELD 2 +#define STV090x_OFFST_Px_CAR2S2_8_BETA_E_FIELD 0 +#define STV090x_WIDTH_Px_CAR2S2_8_BETA_E_FIELD 4 + +#define STV090x_Px_BCLC2S216A(__x) (0xf49d - (__x - 1) * 0x200) +#define STV090x_P1_BCLC2S216A STV090x_Px_BCLC2S216A(1) +#define STV090x_P2_BCLC2S216A STV090x_Px_BCLC2S216A(1) +#define STV090x_OFFST_Px_CAR2S2_16A_BETA_M_FIELD 4 +#define STV090x_WIDTH_Px_CAR2S2_16A_BETA_M_FIELD 2 +#define STV090x_OFFST_Px_CAR2S2_16A_BETA_E_FIELD 0 +#define STV090x_WIDTH_Px_CAR2S2_16A_BETA_E_FIELD 4 + +#define STV090x_Px_BCLC2S232A(__x) (0xf49d - (__x - 1) * 0x200) +#define STV090x_P1_BCLC2S232A STV090x_Px_BCLC2S232A(1) +#define STV090x_P2_BCLC2S232A STV090x_Px_BCLC2S232A(1) +#define STV090x_OFFST_Px_CAR2S2_32A_BETA_M_FIELD 4 +#define STV090x_WIDTH_Px_CAR2S2_32A_BETA_M_FIELD 2 +#define STV090x_OFFST_Px_CAR2S2_32A_BETA_E_FIELD 0 +#define STV090x_WIDTH_Px_CAR2S2_32A_BETA_E_FIELD 4 + +#define STV090x_Px_PLROOT2(__x) (0xf4ac - (__x - 1) * 0x200) +#define STV090x_P1_PLROOT2 STV090x_Px_PLROOT2(1) +#define STV090x_P2_PLROOT2 STV090x_Px_PLROOT2(2) +#define STV090x_OFFST_Px_PLSCRAMB_MODE_FIELD 2 +#define STV090x_WIDTH_Px_PLSCRAMB_MODE_FIELD 2 +#define STV090x_OFFST_Px_PLSCRAMB_ROOT_FIELD 0 +#define STV090x_WIDTH_Px_PLSCRAMB_ROOT_FIELD 2 + +#define STV090x_Px_PLROOT1(__x) (0xf4ad - (__x - 1) * 0x200) +#define STV090x_P1_PLROOT1 STV090x_Px_PLROOT1(1) +#define STV090x_P2_PLROOT1 STV090x_Px_PLROOT1(2) +#define STV090x_OFFST_Px_PLSCRAMB_ROOT1_FIELD 0 +#define STV090x_WIDTH_Px_PLSCRAMB_ROOT1_FIELD 8 + +#define STV090x_Px_PLROOT0(__x) (0xf4ae - (__x - 1) * 0x200) +#define STV090x_P1_PLROOT0 STV090x_Px_PLROOT0(1) +#define STV090x_P2_PLROOT0 STV090x_Px_PLROOT0(2) +#define STV090x_OFFST_Px_PLSCRAMB_ROOT0_FIELD 0 +#define STV090x_WIDTH_Px_PLSCRAMB_ROOT0_FIELD 8 + +#define STV090x_Px_MODCODLST0(__x) (0xf4b0 - (__x - 1) * 0x200) /* check */ +#define STV090x_P1_MODCODLST0 STV090x_Px_MODCODLST0(1) +#define STV090x_P2_MODCODLST0 STV090x_Px_MODCODLST0(2) + +#define STV090x_Px_MODCODLST1(__x) (0xf4b1 - (__x - 1) * 0x200) +#define STV090x_P1_MODCODLST1 STV090x_Px_MODCODLST1(1) +#define STV090x_P2_MODCODLST1 STV090x_Px_MODCODLST1(2) +#define STV090x_OFFST_Px_DIS_MODCOD29_FIELD 4 +#define STV090x_WIDTH_Px_DIS_MODCOD29T_FIELD 4 +#define STV090x_OFFST_Px_DIS_32PSK_9_10_FIELD 0 +#define STV090x_WIDTH_Px_DIS_32PSK_9_10_FIELD 4 + +#define STV090x_Px_MODCODLST2(__x) (0xf4b2 - (__x - 1) * 0x200) +#define STV090x_P1_MODCODLST2 STV090x_Px_MODCODLST2(1) +#define STV090x_P2_MODCODLST2 STV090x_Px_MODCODLST2(2) +#define STV090x_OFFST_Px_DIS_32PSK_8_9_FIELD 4 +#define STV090x_WIDTH_Px_DIS_32PSK_8_9_FIELD 4 +#define STV090x_OFFST_Px_DIS_32PSK_5_6_FIELD 0 +#define STV090x_WIDTH_Px_DIS_32PSK_5_6_FIELD 4 + +#define STV090x_Px_MODCODLST3(__x) (0xf4b3 - (__x - 1) * 0x200) +#define STV090x_P1_MODCODLST3 STV090x_Px_MODCODLST3(1) +#define STV090x_P2_MODCODLST3 STV090x_Px_MODCODLST3(2) +#define STV090x_OFFST_Px_DIS_32PSK_4_5_FIELD 4 +#define STV090x_WIDTH_Px_DIS_32PSK_4_5_FIELD 4 +#define STV090x_OFFST_Px_DIS_32PSK_3_4_FIELD 0 +#define STV090x_WIDTH_Px_DIS_32PSK_3_4_FIELD 4 + +#define STV090x_Px_MODCODLST4(__x) (0xf4b4 - (__x - 1) * 0x200) +#define STV090x_P1_MODCODLST4 STV090x_Px_MODCODLST4(1) +#define STV090x_P2_MODCODLST4 STV090x_Px_MODCODLST4(2) +#define STV090x_OFFST_Px_DIS_16PSK_9_10_FIELD 4 +#define STV090x_WIDTH_Px_DIS_16PSK_9_10_FIELD 4 +#define STV090x_OFFST_Px_DIS_16PSK_8_9_FIELD 0 +#define STV090x_WIDTH_Px_DIS_16PSK_8_9_FIELD 4 + +#define STV090x_Px_MODCODLST5(__x) (0xf4b5 - (__x - 1) * 0x200) +#define STV090x_P1_MODCODLST5 STV090x_Px_MODCODLST5(1) +#define STV090x_P2_MODCODLST5 STV090x_Px_MODCODLST5(2) +#define STV090x_OFFST_Px_DIS_16PSK_5_6_FIELD 4 +#define STV090x_WIDTH_Px_DIS_16PSK_5_6_FIELD 4 +#define STV090x_OFFST_Px_DIS_16PSK_4_5_FIELD 0 +#define STV090x_WIDTH_Px_DIS_16PSK_4_5_FIELD 4 + +#define STV090x_Px_MODCODLST6(__x) (0xf4b6 - (__x - 1) * 0x200) +#define STV090x_P1_MODCODLST6 STV090x_Px_MODCODLST6(1) +#define STV090x_P2_MODCODLST6 STV090x_Px_MODCODLST6(2) +#define STV090x_OFFST_Px_DIS_16PSK_3_4_FIELD 4 +#define STV090x_WIDTH_Px_DIS_16PSK_3_4_FIELD 4 +#define STV090x_OFFST_Px_DIS_16PSK_2_3_FIELD 0 +#define STV090x_WIDTH_Px_DIS_16PSK_2_3_FIELD 4 + +#define STV090x_Px_MODCODLST7(__x) (0xf4b7 - (__x - 1) * 0x200) +#define STV090x_P1_MODCODLST7 STV090x_Px_MODCODLST7(1) +#define STV090x_P2_MODCODLST7 STV090x_Px_MODCODLST7(2) +#define STV090x_OFFST_Px_DIS_8P_9_10_FIELD 4 +#define STV090x_WIDTH_Px_DIS_8P_9_10_FIELD 4 +#define STV090x_OFFST_Px_DIS_8P_8_9_FIELD 0 +#define STV090x_WIDTH_Px_DIS_8P_8_9_FIELD 4 + +#define STV090x_Px_MODCODLST8(__x) (0xf4b8 - (__x - 1) * 0x200) +#define STV090x_P1_MODCODLST8 STV090x_Px_MODCODLST8(1) +#define STV090x_P2_MODCODLST8 STV090x_Px_MODCODLST8(2) +#define STV090x_OFFST_Px_DIS_8P_5_6_FIELD 4 +#define STV090x_WIDTH_Px_DIS_8P_5_6_FIELD 4 +#define STV090x_OFFST_Px_DIS_8P_3_4_FIELD 0 +#define STV090x_WIDTH_Px_DIS_8P_3_4_FIELD 4 + +#define STV090x_Px_MODCODLST9(__x) (0xf4b9 - (__x - 1) * 0x200) +#define STV090x_P1_MODCODLST9 STV090x_Px_MODCODLST9(1) +#define STV090x_P2_MODCODLST9 STV090x_Px_MODCODLST9(2) +#define STV090x_OFFST_Px_DIS_8P_2_3_FIELD 4 +#define STV090x_WIDTH_Px_DIS_8P_2_3_FIELD 4 +#define STV090x_OFFST_Px_DIS_8P_3_5_FIELD 0 +#define STV090x_WIDTH_Px_DIS_8P_3_5_FIELD 4 + +#define STV090x_Px_MODCODLSTA(__x) (0xf4ba - (__x - 1) * 0x200) +#define STV090x_P1_MODCODLSTA STV090x_Px_MODCODLSTA(1) +#define STV090x_P2_MODCODLSTA STV090x_Px_MODCODLSTA(2) +#define STV090x_OFFST_Px_DIS_QP_9_10_FIELD 4 +#define STV090x_WIDTH_Px_DIS_QP_9_10_FIELD 4 +#define STV090x_OFFST_Px_DIS_QP_8_9_FIELD 0 +#define STV090x_WIDTH_Px_DIS_QP_8_9_FIELD 4 + +#define STV090x_Px_MODCODLSTB(__x) (0xf4bb - (__x - 1) * 0x200) +#define STV090x_P1_MODCODLSTB STV090x_Px_MODCODLSTB(1) +#define STV090x_P2_MODCODLSTB STV090x_Px_MODCODLSTB(2) +#define STV090x_OFFST_Px_DIS_QP_5_6_FIELD 4 +#define STV090x_WIDTH_Px_DIS_QP_5_6_FIELD 4 +#define STV090x_OFFST_Px_DIS_QP_4_5_FIELD 0 +#define STV090x_WIDTH_Px_DIS_QP_4_5_FIELD 4 + +#define STV090x_Px_MODCODLSTC(__x) (0xf4bc - (__x - 1) * 0x200) +#define STV090x_P1_MODCODLSTC STV090x_Px_MODCODLSTC(1) +#define STV090x_P2_MODCODLSTC STV090x_Px_MODCODLSTC(2) +#define STV090x_OFFST_Px_DIS_QP_3_4_FIELD 4 +#define STV090x_WIDTH_Px_DIS_QP_3_4_FIELD 4 +#define STV090x_OFFST_Px_DIS_QP_2_3_FIELD 0 +#define STV090x_WIDTH_Px_DIS_QP_2_3_FIELD 4 + +#define STV090x_Px_MODCODLSTD(__x) (0xf4bd - (__x - 1) * 0x200) +#define STV090x_P1_MODCODLSTD STV090x_Px_MODCODLSTD(1) +#define STV090x_P2_MODCODLSTD STV090x_Px_MODCODLSTD(2) +#define STV090x_OFFST_Px_DIS_QP_3_5_FIELD 4 +#define STV090x_WIDTH_Px_DIS_QP_3_5_FIELD 4 +#define STV090x_OFFST_Px_DIS_QP_1_2_FIELD 0 +#define STV090x_WIDTH_Px_DIS_QP_1_2_FIELD 4 + +#define STV090x_Px_MODCODLSTE(__x) (0xf4be - (__x - 1) * 0x200) +#define STV090x_P1_MODCODLSTE STV090x_Px_MODCODLSTE(1) +#define STV090x_P2_MODCODLSTE STV090x_Px_MODCODLSTE(2) +#define STV090x_OFFST_Px_DIS_QP_2_5_FIELD 4 +#define STV090x_WIDTH_Px_DIS_QP_2_5_FIELD 4 +#define STV090x_OFFST_Px_DIS_QP_1_3_FIELD 0 +#define STV090x_WIDTH_Px_DIS_QP_1_3_FIELD 4 + +#define STV090x_Px_MODCODLSTF(__x) (0xf4bf - (__x - 1) * 0x200) +#define STV090x_P1_MODCODLSTF STV090x_Px_MODCODLSTF(1) +#define STV090x_P2_MODCODLSTF STV090x_Px_MODCODLSTF(2) +#define STV090x_OFFST_Px_DIS_QP_1_4_FIELD 4 +#define STV090x_WIDTH_Px_DIS_QP_1_4_FIELD 4 + +#define STV090x_Px_GAUSSR0(__x) (0xf4c0 - (__x - 1) * 0x200) +#define STV090x_P1_GAUSSR0 STV090x_Px_GAUSSR0(1) +#define STV090x_P2_GAUSSR0 STV090x_Px_GAUSSR0(2) +#define STV090x_OFFST_Px_EN_CCIMODE_FIELD 7 +#define STV090x_WIDTH_Px_EN_CCIMODE_FIELD 1 +#define STV090x_OFFST_Px_R0_GAUSSIEN_FIELD 0 +#define STV090x_WIDTH_Px_R0_GAUSSIEN_FIELD 7 + +#define STV090x_Px_CCIR0(__x) (0xf4c1 - (__x - 1) * 0x200) +#define STV090x_P1_CCIR0 STV090x_Px_CCIR0(1) +#define STV090x_P2_CCIR0 STV090x_Px_CCIR0(2) +#define STV090x_OFFST_Px_CCIDETECT_PLH_FIELD 7 +#define STV090x_WIDTH_Px_CCIDETECT_PLH_FIELD 1 +#define STV090x_OFFST_Px_R0_CCI_FIELD 0 +#define STV090x_WIDTH_Px_R0_CCI_FIELD 7 + +#define STV090x_Px_CCIQUANT(__x) (0xf4c2 - (__x - 1) * 0x200) +#define STV090x_P1_CCIQUANT STV090x_Px_CCIQUANT(1) +#define STV090x_P2_CCIQUANT STV090x_Px_CCIQUANT(2) +#define STV090x_OFFST_Px_CCI_BETA_FIELD 5 +#define STV090x_WIDTH_Px_CCI_BETA_FIELD 3 +#define STV090x_OFFST_Px_CCI_QUANT_FIELD 0 +#define STV090x_WIDTH_Px_CCI_QUANT_FIELD 5 + +#define STV090x_Px_CCITHRESH(__x) (0xf4c3 - (__x - 1) * 0x200) +#define STV090x_P1_CCITHRESH STV090x_Px_CCITHRESH(1) +#define STV090x_P2_CCITHRESH STV090x_Px_CCITHRESH(2) +#define STV090x_OFFST_Px_CCI_THRESHOLD_FIELD 0 +#define STV090x_WIDTH_Px_CCI_THRESHOLD_FIELD 8 + +#define STV090x_Px_CCIACC(__x) (0xf4c4 - (__x - 1) * 0x200) +#define STV090x_P1_CCIACC STV090x_Px_CCIACC(1) +#define STV090x_P2_CCIACC STV090x_Px_CCIACC(1) +#define STV090x_OFFST_Px_CCI_VALUE_FIELD 0 +#define STV090x_WIDTH_Px_CCI_VALUE_FIELD 8 + +#define STV090x_Px_DMDRESCFG(__x) (0xF4C6 - (__x - 1) * 0x200) +#define STV090x_P1_DMDRESCFG STV090x_Px_DMDRESCFG(1) +#define STV090x_P2_DMDRESCFG STV090x_Px_DMDRESCFG(2) +#define STV090x_OFFST_Px_DMDRES_RESET_FIELD 7 +#define STV090x_WIDTH_Px_DMDRES_RESET_FIELD 1 + +#define STV090x_Px_DMDRESADR(__x) (0xF4C7 - (__x - 1) * 0x200) +#define STV090x_P1_DMDRESADR STV090x_Px_DMDRESADR(1) +#define STV090x_P2_DMDRESADR STV090x_Px_DMDRESADR(2) +#define STV090x_OFFST_Px_DMDRES_RESNBR_FIELD 0 +#define STV090x_WIDTH_Px_DMDRES_RESNBR_FIELD 4 + +#define STV090x_Px_DMDRESDATAy(__x, __y) (0xF4C8 - (__x - 1) * 0x200 + (7 - __y)) +#define STV090x_P1_DMDRESDATA0 STV090x_Px_DMDRESDATAy(1, 0) +#define STV090x_P1_DMDRESDATA1 STV090x_Px_DMDRESDATAy(1, 1) +#define STV090x_P1_DMDRESDATA2 STV090x_Px_DMDRESDATAy(1, 2) +#define STV090x_P1_DMDRESDATA3 STV090x_Px_DMDRESDATAy(1, 3) +#define STV090x_P1_DMDRESDATA4 STV090x_Px_DMDRESDATAy(1, 4) +#define STV090x_P1_DMDRESDATA5 STV090x_Px_DMDRESDATAy(1, 5) +#define STV090x_P1_DMDRESDATA6 STV090x_Px_DMDRESDATAy(1, 6) +#define STV090x_P1_DMDRESDATA7 STV090x_Px_DMDRESDATAy(1, 7) +#define STV090x_P2_DMDRESDATA0 STV090x_Px_DMDRESDATAy(2, 0) +#define STV090x_P2_DMDRESDATA1 STV090x_Px_DMDRESDATAy(2, 1) +#define STV090x_P2_DMDRESDATA2 STV090x_Px_DMDRESDATAy(2, 2) +#define STV090x_P2_DMDRESDATA3 STV090x_Px_DMDRESDATAy(2, 3) +#define STV090x_P2_DMDRESDATA4 STV090x_Px_DMDRESDATAy(2, 4) +#define STV090x_P2_DMDRESDATA5 STV090x_Px_DMDRESDATAy(2, 5) +#define STV090x_P2_DMDRESDATA6 STV090x_Px_DMDRESDATAy(2, 6) +#define STV090x_P2_DMDRESDATA7 STV090x_Px_DMDRESDATAy(2, 7) +#define STV090x_OFFST_Px_DMDRES_DATA_FIELD 0 +#define STV090x_WIDTH_Px_DMDRES_DATA_FIELD 8 + +#define STV090x_Px_FFEIy(__x, __y) (0xf4d0 - (__x - 1) * 0x200 + 0x2 * (__y - 1)) +#define STV090x_P1_FFEI1 STV090x_Px_FFEIy(1, 1) +#define STV090x_P1_FFEI2 STV090x_Px_FFEIy(1, 2) +#define STV090x_P1_FFEI3 STV090x_Px_FFEIy(1, 3) +#define STV090x_P1_FFEI4 STV090x_Px_FFEIy(1, 4) +#define STV090x_P2_FFEI1 STV090x_Px_FFEIy(2, 1) +#define STV090x_P2_FFEI2 STV090x_Px_FFEIy(2, 2) +#define STV090x_P2_FFEI3 STV090x_Px_FFEIy(2, 3) +#define STV090x_P2_FFEI4 STV090x_Px_FFEIy(2, 4) +#define STV090x_OFFST_Px_FFE_ACCIy_FIELD 0 +#define STV090x_WIDTH_Px_FFE_ACCIy_FIELD 8 + +#define STV090x_Px_FFEQy(__x, __y) (0xf4d1 - (__x - 1) * 0x200 + 0x2 * (__y - 1)) +#define STV090x_P1_FFEQ1 STV090x_Px_FFEQy(1, 1) +#define STV090x_P1_FFEQ2 STV090x_Px_FFEQy(1, 2) +#define STV090x_P1_FFEQ3 STV090x_Px_FFEQy(1, 3) +#define STV090x_P1_FFEQ4 STV090x_Px_FFEQy(1, 4) +#define STV090x_P2_FFEQ1 STV090x_Px_FFEQy(2, 1) +#define STV090x_P2_FFEQ2 STV090x_Px_FFEQy(2, 2) +#define STV090x_P2_FFEQ3 STV090x_Px_FFEQy(2, 3) +#define STV090x_P2_FFEQ4 STV090x_Px_FFEQy(2, 4) +#define STV090x_OFFST_Px_FFE_ACCQy_FIELD 0 +#define STV090x_WIDTH_Px_FFE_ACCQy_FIELD 8 + +#define STV090x_Px_FFECFG(__x) (0xf4d8 - (__x - 1) * 0x200) +#define STV090x_P1_FFECFG STV090x_Px_FFECFG(1) +#define STV090x_P2_FFECFG STV090x_Px_FFECFG(2) +#define STV090x_OFFST_Px_EQUALFFE_ON_FIELD 6 +#define STV090x_WIDTH_Px_EQUALFFE_ON_FIELD 1 + +#define STV090x_Px_SMAPCOEF7(__x) (0xf500 - (__x - 1) * 0x200) +#define STV090x_P1_SMAPCOEF7 STV090x_Px_SMAPCOEF7(1) +#define STV090x_P2_SMAPCOEF7 STV090x_Px_SMAPCOEF7(2) +#define STV090x_OFFST_Px_DIS_QSCALE_FIELD 7 +#define STV090x_WIDTH_Px_DIS_QSCALE_FIELD 1 +#define STV090x_OFFST_Px_SMAPCOEF_Q_LLR12_FIELD 0 +#define STV090x_WIDTH_Px_SMAPCOEF_Q_LLR12_FIELD 7 + +#define STV090x_Px_SMAPCOEF6(__x) (0xf501 - (__x - 1) * 0x200) +#define STV090x_P1_SMAPCOEF6 STV090x_Px_SMAPCOEF6(1) +#define STV090x_P2_SMAPCOEF6 STV090x_Px_SMAPCOEF6(2) +#define STV090x_OFFST_Px_ADJ_8PSKLLR1_FIELD 2 +#define STV090x_WIDTH_Px_ADJ_8PSKLLR1_FIELD 1 +#define STV090x_OFFST_Px_OLD_8PSKLLR1_FIELD 1 +#define STV090x_WIDTH_Px_OLD_8PSKLLR1_FIELD 1 +#define STV090x_OFFST_Px_DIS_AB8PSK_FIELD 0 +#define STV090x_WIDTH_Px_DIS_AB8PSK_FIELD 1 + +#define STV090x_Px_SMAPCOEF5(__x) (0xf502 - (__x - 1) * 0x200) +#define STV090x_P1_SMAPCOEF5 STV090x_Px_SMAPCOEF5(1) +#define STV090x_P2_SMAPCOEF5 STV090x_Px_SMAPCOEF5(2) +#define STV090x_OFFST_Px_DIS_8SCALE_FIELD 7 +#define STV090x_WIDTH_Px_DIS_8SCALE_FIELD 1 +#define STV090x_OFFST_Px_SMAPCOEF_8P_LLR23_FIELD 0 +#define STV090x_WIDTH_Px_SMAPCOEF_8P_LLR23_FIELD 7 + +#define STV090x_Px_DMDPLHSTAT(__x) (0xF520 - (__x - 1) * 0x200) +#define STV090x_P1_DMDPLHSTAT STV090x_Px_DMDPLHSTAT(1) +#define STV090x_P2_DMDPLHSTAT STV090x_Px_DMDPLHSTAT(2) +#define STV090x_OFFST_Px_PLH_STATISTIC_FIELD 0 +#define STV090x_WIDTH_Px_PLH_STATISTIC_FIELD 8 + +#define STV090x_Px_LOCKTIMEy(__x, __y) (0xF525 - (__x - 1) * 0x200 - __y * 0x1) +#define STV090x_P1_LOCKTIME0 STV090x_Px_LOCKTIMEy(1, 0) +#define STV090x_P1_LOCKTIME1 STV090x_Px_LOCKTIMEy(1, 1) +#define STV090x_P1_LOCKTIME2 STV090x_Px_LOCKTIMEy(1, 2) +#define STV090x_P1_LOCKTIME3 STV090x_Px_LOCKTIMEy(1, 3) +#define STV090x_P2_LOCKTIME0 STV090x_Px_LOCKTIMEy(2, 0) +#define STV090x_P2_LOCKTIME1 STV090x_Px_LOCKTIMEy(2, 1) +#define STV090x_P2_LOCKTIME2 STV090x_Px_LOCKTIMEy(2, 2) +#define STV090x_P2_LOCKTIME3 STV090x_Px_LOCKTIMEy(2, 3) +#define STV090x_OFFST_Px_DEMOD_LOCKTIME_FIELD 0 +#define STV090x_WIDTH_Px_DEMOD_LOCKTIME_FIELD 8 + +#define STV090x_Px_TNRCFG(__x) (0xf4e0 - (__x - 1) * 0x200) /* check */ +#define STV090x_P1_TNRCFG STV090x_Px_TNRCFG(1) +#define STV090x_P2_TNRCFG STV090x_Px_TNRCFG(2) + +#define STV090x_Px_TNRCFG2(__x) (0xf4e1 - (__x - 1) * 0x200) +#define STV090x_P1_TNRCFG2 STV090x_Px_TNRCFG2(1) +#define STV090x_P2_TNRCFG2 STV090x_Px_TNRCFG2(2) +#define STV090x_OFFST_Px_TUN_IQSWAP_FIELD 7 +#define STV090x_WIDTH_Px_TUN_IQSWAP_FIELD 1 + +#define STV090x_Px_VITSCALE(__x) (0xf532 - (__x - 1) * 0x200) +#define STV090x_P1_VITSCALE STV090x_Px_VITSCALE(1) +#define STV090x_P2_VITSCALE STV090x_Px_VITSCALE(2) +#define STV090x_OFFST_Px_NVTH_NOSRANGE_FIELD 7 +#define STV090x_WIDTH_Px_NVTH_NOSRANGE_FIELD 1 +#define STV090x_OFFST_Px_VERROR_MAXMODE_FIELD 6 +#define STV090x_WIDTH_Px_VERROR_MAXMODE_FIELD 1 +#define STV090x_OFFST_Px_NSLOWSN_LOCKED_FIELD 3 +#define STV090x_WIDTH_Px_NSLOWSN_LOCKED_FIELD 1 +#define STV090x_OFFST_Px_DIS_RSFLOCK_FIELD 1 +#define STV090x_WIDTH_Px_DIS_RSFLOCK_FIELD 1 + +#define STV090x_Px_FECM(__x) (0xf533 - (__x - 1) * 0x200) +#define STV090x_P1_FECM STV090x_Px_FECM(1) +#define STV090x_P2_FECM STV090x_Px_FECM(2) +#define STV090x_OFFST_Px_DSS_DVB_FIELD 7 +#define STV090x_WIDTH_Px_DSS_DVB_FIELD 1 +#define STV090x_OFFST_Px_DSS_SRCH_FIELD 4 +#define STV090x_WIDTH_Px_DSS_SRCH_FIELD 1 +#define STV090x_OFFST_Px_SYNCVIT_FIELD 1 +#define STV090x_WIDTH_Px_SYNCVIT_FIELD 1 +#define STV090x_OFFST_Px_IQINV_FIELD 0 +#define STV090x_WIDTH_Px_IQINV_FIELD 1 + +#define STV090x_Px_VTH12(__x) (0xf534 - (__x - 1) * 0x200) +#define STV090x_P1_VTH12 STV090x_Px_VTH12(1) +#define STV090x_P2_VTH12 STV090x_Px_VTH12(2) +#define STV090x_OFFST_Px_VTH12_FIELD 0 +#define STV090x_WIDTH_Px_VTH12_FIELD 8 + +#define STV090x_Px_VTH23(__x) (0xf535 - (__x - 1) * 0x200) +#define STV090x_P1_VTH23 STV090x_Px_VTH23(1) +#define STV090x_P2_VTH23 STV090x_Px_VTH23(2) +#define STV090x_OFFST_Px_VTH23_FIELD 0 +#define STV090x_WIDTH_Px_VTH23_FIELD 8 + +#define STV090x_Px_VTH34(__x) (0xf536 - (__x - 1) * 0x200) +#define STV090x_P1_VTH34 STV090x_Px_VTH34(1) +#define STV090x_P2_VTH34 STV090x_Px_VTH34(2) +#define STV090x_OFFST_Px_VTH34_FIELD 0 +#define STV090x_WIDTH_Px_VTH34_FIELD 8 + +#define STV090x_Px_VTH56(__x) (0xf537 - (__x - 1) * 0x200) +#define STV090x_P1_VTH56 STV090x_Px_VTH56(1) +#define STV090x_P2_VTH56 STV090x_Px_VTH56(2) +#define STV090x_OFFST_Px_VTH56_FIELD 0 +#define STV090x_WIDTH_Px_VTH56_FIELD 8 + +#define STV090x_Px_VTH67(__x) (0xf538 - (__x - 1) * 0x200) +#define STV090x_P1_VTH67 STV090x_Px_VTH67(1) +#define STV090x_P2_VTH67 STV090x_Px_VTH67(2) +#define STV090x_OFFST_Px_VTH67_FIELD 0 +#define STV090x_WIDTH_Px_VTH67_FIELD 8 + +#define STV090x_Px_VTH78(__x) (0xf539 - (__x - 1) * 0x200) +#define STV090x_P1_VTH78 STV090x_Px_VTH78(1) +#define STV090x_P2_VTH78 STV090x_Px_VTH78(2) +#define STV090x_OFFST_Px_VTH78_FIELD 0 +#define STV090x_WIDTH_Px_VTH78_FIELD 8 + +#define STV090x_Px_VITCURPUN(__x) (0xf53a - (__x - 1) * 0x200) +#define STV090x_P1_VITCURPUN STV090x_Px_VITCURPUN(1) +#define STV090x_P2_VITCURPUN STV090x_Px_VITCURPUN(2) +#define STV090x_OFFST_Px_VIT_CURPUN_FIELD 0 +#define STV090x_WIDTH_Px_VIT_CURPUN_FIELD 5 + +#define STV090x_Px_VERROR(__x) (0xf53b - (__x - 1) * 0x200) +#define STV090x_P1_VERROR STV090x_Px_VERROR(1) +#define STV090x_P2_VERROR STV090x_Px_VERROR(2) +#define STV090x_OFFST_Px_REGERR_VIT_FIELD 0 +#define STV090x_WIDTH_Px_REGERR_VIT_FIELD 8 + +#define STV090x_Px_PRVIT(__x) (0xf53c - (__x - 1) * 0x200) +#define STV090x_P1_PRVIT STV090x_Px_PRVIT(1) +#define STV090x_P2_PRVIT STV090x_Px_PRVIT(2) +#define STV090x_OFFST_Px_DIS_VTHLOCK_FIELD 6 +#define STV090x_WIDTH_Px_DIS_VTHLOCK_FIELD 1 +#define STV090x_OFFST_Px_E7_8VIT_FIELD 5 +#define STV090x_WIDTH_Px_E7_8VIT_FIELD 1 +#define STV090x_OFFST_Px_E6_7VIT_FIELD 4 +#define STV090x_WIDTH_Px_E6_7VIT_FIELD 1 +#define STV090x_OFFST_Px_E5_6VIT_FIELD 3 +#define STV090x_WIDTH_Px_E5_6VIT_FIELD 1 +#define STV090x_OFFST_Px_E3_4VIT_FIELD 2 +#define STV090x_WIDTH_Px_E3_4VIT_FIELD 1 +#define STV090x_OFFST_Px_E2_3VIT_FIELD 1 +#define STV090x_WIDTH_Px_E2_3VIT_FIELD 1 +#define STV090x_OFFST_Px_E1_2VIT_FIELD 0 +#define STV090x_WIDTH_Px_E1_2VIT_FIELD 1 + +#define STV090x_Px_VAVSRVIT(__x) (0xf53d - (__x - 1) * 0x200) +#define STV090x_P1_VAVSRVIT STV090x_Px_VAVSRVIT(1) +#define STV090x_P2_VAVSRVIT STV090x_Px_VAVSRVIT(2) +#define STV090x_OFFST_Px_SNVIT_FIELD 4 +#define STV090x_WIDTH_Px_SNVIT_FIELD 2 +#define STV090x_OFFST_Px_TOVVIT_FIELD 2 +#define STV090x_WIDTH_Px_TOVVIT_FIELD 2 +#define STV090x_OFFST_Px_HYPVIT_FIELD 0 +#define STV090x_WIDTH_Px_HYPVIT_FIELD 2 + +#define STV090x_Px_VSTATUSVIT(__x) (0xf53e - (__x - 1) * 0x200) +#define STV090x_P1_VSTATUSVIT STV090x_Px_VSTATUSVIT(1) +#define STV090x_P2_VSTATUSVIT STV090x_Px_VSTATUSVIT(2) +#define STV090x_OFFST_Px_PRFVIT_FIELD 4 +#define STV090x_WIDTH_Px_PRFVIT_FIELD 1 +#define STV090x_OFFST_Px_LOCKEDVIT_FIELD 3 +#define STV090x_WIDTH_Px_LOCKEDVIT_FIELD 1 + +#define STV090x_Px_VTHINUSE(__x) (0xf53f - (__x - 1) * 0x200) +#define STV090x_P1_VTHINUSE STV090x_Px_VTHINUSE(1) +#define STV090x_P2_VTHINUSE STV090x_Px_VTHINUSE(2) +#define STV090x_OFFST_Px_VIT_INUSE_FIELD 0 +#define STV090x_WIDTH_Px_VIT_INUSE_FIELD 8 + +#define STV090x_Px_KDIV12(__x) (0xf540 - (__x - 1) * 0x200) +#define STV090x_P1_KDIV12 STV090x_Px_KDIV12(1) +#define STV090x_P2_KDIV12 STV090x_Px_KDIV12(2) +#define STV090x_OFFST_Px_K_DIVIDER_12_FIELD 0 +#define STV090x_WIDTH_Px_K_DIVIDER_12_FIELD 7 + +#define STV090x_Px_KDIV23(__x) (0xf541 - (__x - 1) * 0x200) +#define STV090x_P1_KDIV23 STV090x_Px_KDIV23(1) +#define STV090x_P2_KDIV23 STV090x_Px_KDIV23(2) +#define STV090x_OFFST_Px_K_DIVIDER_23_FIELD 0 +#define STV090x_WIDTH_Px_K_DIVIDER_23_FIELD 7 + +#define STV090x_Px_KDIV34(__x) (0xf542 - (__x - 1) * 0x200) +#define STV090x_P1_KDIV34 STV090x_Px_KDIV34(1) +#define STV090x_P2_KDIV34 STV090x_Px_KDIV34(2) +#define STV090x_OFFST_Px_K_DIVIDER_34_FIELD 0 +#define STV090x_WIDTH_Px_K_DIVIDER_34_FIELD 7 + +#define STV090x_Px_KDIV56(__x) (0xf543 - (__x - 1) * 0x200) +#define STV090x_P1_KDIV56 STV090x_Px_KDIV56(1) +#define STV090x_P2_KDIV56 STV090x_Px_KDIV56(2) +#define STV090x_OFFST_Px_K_DIVIDER_56_FIELD 0 +#define STV090x_WIDTH_Px_K_DIVIDER_56_FIELD 7 + +#define STV090x_Px_KDIV67(__x) (0xf544 - (__x - 1) * 0x200) +#define STV090x_P1_KDIV67 STV090x_Px_KDIV67(1) +#define STV090x_P2_KDIV67 STV090x_Px_KDIV67(2) +#define STV090x_OFFST_Px_K_DIVIDER_67_FIELD 0 +#define STV090x_WIDTH_Px_K_DIVIDER_67_FIELD 7 + +#define STV090x_Px_KDIV78(__x) (0xf545 - (__x - 1) * 0x200) +#define STV090x_P1_KDIV78 STV090x_Px_KDIV78(1) +#define STV090x_P2_KDIV78 STV090x_Px_KDIV78(2) +#define STV090x_OFFST_Px_K_DIVIDER_78_FIELD 0 +#define STV090x_WIDTH_Px_K_DIVIDER_78_FIELD 7 + +#define STV090x_Px_PDELCTRL1(__x) (0xf550 - (__x - 1) * 0x200) +#define STV090x_P1_PDELCTRL1 STV090x_Px_PDELCTRL1(1) +#define STV090x_P2_PDELCTRL1 STV090x_Px_PDELCTRL1(2) +#define STV090x_OFFST_Px_INV_MISMASK_FIELD 7 +#define STV090x_WIDTH_Px_INV_MISMASK_FIELD 1 +#define STV090x_OFFST_Px_FILTER_EN_FIELD 5 +#define STV090x_WIDTH_Px_FILTER_EN_FIELD 1 +#define STV090x_OFFST_Px_EN_MIS00_FIELD 1 +#define STV090x_WIDTH_Px_EN_MIS00_FIELD 1 +#define STV090x_OFFST_Px_ALGOSWRST_FIELD 0 +#define STV090x_WIDTH_Px_ALGOSWRST_FIELD 1 + +#define STV090x_Px_PDELCTRL2(__x) (0xf551 - (__x - 1) * 0x200) +#define STV090x_P1_PDELCTRL2 STV090x_Px_PDELCTRL2(1) +#define STV090x_P2_PDELCTRL2 STV090x_Px_PDELCTRL2(2) +#define STV090x_OFFST_Px_FORCE_CONTINUOUS 7 +#define STV090x_WIDTH_Px_FORCE_CONTINUOUS 1 +#define STV090x_OFFST_Px_RESET_UPKO_COUNT 6 +#define STV090x_WIDTH_Px_RESET_UPKO_COUNT 1 +#define STV090x_OFFST_Px_USER_PKTDELIN_NB 5 +#define STV090x_WIDTH_Px_USER_PKTDELIN_NB 1 +#define STV090x_OFFST_Px_FORCE_LOCKED 4 +#define STV090x_WIDTH_Px_FORCE_LOCKED 1 +#define STV090x_OFFST_Px_DATA_UNBBSCRAM 3 +#define STV090x_WIDTH_Px_DATA_UNBBSCRAM 1 +#define STV090x_OFFST_Px_FORCE_LONGPACKET 2 +#define STV090x_WIDTH_Px_FORCE_LONGPACKET 1 +#define STV090x_OFFST_Px_FRAME_MODE_FIELD 1 +#define STV090x_WIDTH_Px_FRAME_MODE_FIELD 1 + +#define STV090x_Px_HYSTTHRESH(__x) (0xf554 - (__x - 1) * 0x200) +#define STV090x_P1_HYSTTHRESH STV090x_Px_HYSTTHRESH(1) +#define STV090x_P2_HYSTTHRESH STV090x_Px_HYSTTHRESH(2) +#define STV090x_OFFST_Px_UNLCK_THRESH_FIELD 4 +#define STV090x_WIDTH_Px_UNLCK_THRESH_FIELD 4 +#define STV090x_OFFST_Px_DELIN_LCK_THRESH_FIELD 0 +#define STV090x_WIDTH_Px_DELIN_LCK_THRESH_FIELD 4 + +#define STV090x_Px_ISIENTRY(__x) (0xf55e - (__x - 1) * 0x200) +#define STV090x_P1_ISIENTRY STV090x_Px_ISIENTRY(1) +#define STV090x_P2_ISIENTRY STV090x_Px_ISIENTRY(2) +#define STV090x_OFFST_Px_ISI_ENTRY_FIELD 0 +#define STV090x_WIDTH_Px_ISI_ENTRY_FIELD 8 + +#define STV090x_Px_ISIBITENA(__x) (0xf55f - (__x - 1) * 0x200) +#define STV090x_P1_ISIBITENA STV090x_Px_ISIBITENA(1) +#define STV090x_P2_ISIBITENA STV090x_Px_ISIBITENA(2) +#define STV090x_OFFST_Px_ISI_BIT_EN_FIELD 0 +#define STV090x_WIDTH_Px_ISI_BIT_EN_FIELD 8 + +#define STV090x_Px_MATSTRy(__x, __y) (0xf561 - (__x - 1) * 0x200 - __y * 0x1) +#define STV090x_P1_MATSTR0 STV090x_Px_MATSTRy(1, 0) +#define STV090x_P1_MATSTR1 STV090x_Px_MATSTRy(1, 1) +#define STV090x_P2_MATSTR0 STV090x_Px_MATSTRy(2, 0) +#define STV090x_P2_MATSTR1 STV090x_Px_MATSTRy(2, 1) +#define STV090x_OFFST_Px_MATYPE_CURRENT_FIELD 0 +#define STV090x_WIDTH_Px_MATYPE_CURRENT_FIELD 8 + +#define STV090x_Px_UPLSTRy(__x, __y) (0xf563 - (__x - 1) * 0x200 - __y * 0x1) +#define STV090x_P1_UPLSTR0 STV090x_Px_UPLSTRy(1, 0) +#define STV090x_P1_UPLSTR1 STV090x_Px_UPLSTRy(1, 1) +#define STV090x_P2_UPLSTR0 STV090x_Px_UPLSTRy(2, 0) +#define STV090x_P2_UPLSTR1 STV090x_Px_UPLSTRy(2, 1) +#define STV090x_OFFST_Px_UPL_CURRENT_FIELD 0 +#define STV090x_WIDTH_Px_UPL_CURRENT_FIELD 8 + +#define STV090x_Px_DFLSTRy(__x, __y) (0xf565 - (__x - 1) * 0x200 - __y * 0x1) +#define STV090x_P1_DFLSTR0 STV090x_Px_DFLSTRy(1, 0) +#define STV090x_P1_DFLSTR1 STV090x_Px_DFLSTRy(1, 1) +#define STV090x_P2_DFLSTR0 STV090x_Px_DFLSTRy(2, 0) +#define STV090x_P2_DFLSTR1 STV090x_Px_DFLSTRy(2, 1) +#define STV090x_OFFST_Px_DFL_CURRENT_FIELD 0 +#define STV090x_WIDTH_Px_DFL_CURRENT_FIELD 8 + +#define STV090x_Px_SYNCSTR(__x) (0xf566 - (__x - 1) * 0x200) +#define STV090x_P1_SYNCSTR STV090x_Px_SYNCSTR(1) +#define STV090x_P2_SYNCSTR STV090x_Px_SYNCSTR(2) +#define STV090x_OFFST_Px_SYNC_CURRENT_FIELD 0 +#define STV090x_WIDTH_Px_SYNC_CURRENT_FIELD 8 + +#define STV090x_Px_SYNCDSTRy(__x, __y) (0xf568 - (__x - 1) * 0x200 - __y * 0x1) +#define STV090x_P1_SYNCDSTR0 STV090x_Px_SYNCDSTRy(1, 0) +#define STV090x_P1_SYNCDSTR1 STV090x_Px_SYNCDSTRy(1, 1) +#define STV090x_P2_SYNCDSTR0 STV090x_Px_SYNCDSTRy(2, 0) +#define STV090x_P2_SYNCDSTR1 STV090x_Px_SYNCDSTRy(2, 1) +#define STV090x_OFFST_Px_SYNCD_CURRENT_FIELD 0 +#define STV090x_WIDTH_Px_SYNCD_CURRENT_FIELD 8 + +#define STV090x_Px_PDELSTATUS1(__x) (0xf569 - (__x - 1) * 0x200) +#define STV090x_P1_PDELSTATUS1 STV090x_Px_PDELSTATUS1(1) +#define STV090x_P2_PDELSTATUS1 STV090x_Px_PDELSTATUS1(2) +#define STV090x_OFFST_Px_PKTDELIN_LOCK_FIELD 1 +#define STV090x_WIDTH_Px_PKTDELIN_LOCK_FIELD 1 +#define STV090x_OFFST_Px_FIRST_LOCK_FIELD 0 +#define STV090x_WIDTH_Px_FIRST_LOCK_FIELD 1 + +#define STV090x_Px_PDELSTATUS2(__x) (0xf56a - (__x - 1) * 0x200) +#define STV090x_P1_PDELSTATUS2 STV090x_Px_PDELSTATUS2(1) +#define STV090x_P2_PDELSTATUS2 STV090x_Px_PDELSTATUS2(2) +#define STV090x_OFFST_Px_FRAME_MODCOD_FIELD 2 +#define STV090x_WIDTH_Px_FRAME_MODCOD_FIELD 5 +#define STV090x_OFFST_Px_FRAME_TYPE_FIELD 0 +#define STV090x_WIDTH_Px_FRAME_TYPE_FIELD 2 + +#define STV090x_Px_BBFCRCKO1(__x) (0xf56b - (__x - 1) * 0x200) +#define STV090x_P1_BBFCRCKO1 STV090x_Px_BBFCRCKO1(1) +#define STV090x_P2_BBFCRCKO1 STV090x_Px_BBFCRCKO1(2) +#define STV090x_OFFST_Px_BBHCRC_KOCNT_FIELD 0 +#define STV090x_WIDTH_Px_BBHCRC_KOCNT_FIELD 8 + +#define STV090x_Px_BBFCRCKO0(__x) (0xf56c - (__x - 1) * 0x200) +#define STV090x_P1_BBFCRCKO0 STV090x_Px_BBFCRCKO0(1) +#define STV090x_P2_BBFCRCKO0 STV090x_Px_BBFCRCKO0(2) +#define STV090x_OFFST_Px_BBHCRC_KOCNT_FIELD 0 +#define STV090x_WIDTH_Px_BBHCRC_KOCNT_FIELD 8 + +#define STV090x_Px_UPCRCKO1(__x) (0xf56d - (__x - 1) * 0x200) +#define STV090x_P1_UPCRCKO1 STV090x_Px_UPCRCKO1(1) +#define STV090x_P2_UPCRCKO1 STV090x_Px_UPCRCKO1(2) +#define STV090x_OFFST_Px_PKTCRC_KOCNT_FIELD 0 +#define STV090x_WIDTH_Px_PKTCRC_KOCNT_FIELD 8 + +#define STV090x_Px_UPCRCKO0(__x) (0xf56e - (__x - 1) * 0x200) +#define STV090x_P1_UPCRCKO0 STV090x_Px_UPCRCKO0(1) +#define STV090x_P2_UPCRCKO0 STV090x_Px_UPCRCKO0(2) +#define STV090x_OFFST_Px_PKTCRC_KOCNT_FIELD 0 +#define STV090x_WIDTH_Px_PKTCRC_KOCNT_FIELD 8 + +#define STV090x_NBITER_NFx(__x) (0xFA03 + (__x - 4) * 0x1) +#define STV090x_NBITER_NF4 STV090x_NBITER_NFx(4) +#define STV090x_NBITER_NF5 STV090x_NBITER_NFx(5) +#define STV090x_NBITER_NF6 STV090x_NBITER_NFx(6) +#define STV090x_NBITER_NF7 STV090x_NBITER_NFx(7) +#define STV090x_NBITER_NF8 STV090x_NBITER_NFx(8) +#define STV090x_NBITER_NF9 STV090x_NBITER_NFx(9) +#define STV090x_NBITER_NF10 STV090x_NBITER_NFx(10) +#define STV090x_NBITER_NF11 STV090x_NBITER_NFx(11) +#define STV090x_NBITER_NF12 STV090x_NBITER_NFx(12) +#define STV090x_NBITER_NF13 STV090x_NBITER_NFx(13) +#define STV090x_NBITER_NF14 STV090x_NBITER_NFx(14) +#define STV090x_NBITER_NF15 STV090x_NBITER_NFx(15) +#define STV090x_NBITER_NF16 STV090x_NBITER_NFx(16) +#define STV090x_NBITER_NF17 STV090x_NBITER_NFx(17) + +#define STV090x_NBITERNOERR 0xFA3F +#define STV090x_OFFST_NBITER_STOP_CRIT_FIELD 0 +#define STV090x_WIDTH_NBITER_STOP_CRIT_FIELD 4 + +#define STV090x_GAINLLR_NFx(__x) (0xFA43 + (__x - 4) * 0x1) +#define STV090x_GAINLLR_NF4 STV090x_GAINLLR_NFx(4) +#define STV090x_OFFST_GAINLLR_NF_QP_1_2_FIELD 0 +#define STV090x_WIDTH_GAINLLR_NF_QP_1_2_FIELD 7 + +#define STV090x_GAINLLR_NF5 STV090x_GAINLLR_NFx(5) +#define STV090x_OFFST_GAINLLR_NF_QP_3_5_FIELD 0 +#define STV090x_WIDTH_GAINLLR_NF_QP_3_5_FIELD 7 + +#define STV090x_GAINLLR_NF6 STV090x_GAINLLR_NFx(6) +#define STV090x_OFFST_GAINLLR_NF_QP_2_3_FIELD 0 +#define STV090x_WIDTH_GAINLLR_NF_QP_2_3_FIELD 7 + +#define STV090x_GAINLLR_NF7 STV090x_GAINLLR_NFx(7) +#define STV090x_OFFST_GAINLLR_NF_QP_3_4_FIELD 0 +#define STV090x_WIDTH_GAINLLR_NF_QP_3_4_FIELD 7 + +#define STV090x_GAINLLR_NF8 STV090x_GAINLLR_NFx(8) +#define STV090x_OFFST_GAINLLR_NF_QP_4_5_FIELD 0 +#define STV090x_WIDTH_GAINLLR_NF_QP_4_5_FIELD 7 + +#define STV090x_GAINLLR_NF9 STV090x_GAINLLR_NFx(9) +#define STV090x_OFFST_GAINLLR_NF_QP_5_6_FIELD 0 +#define STV090x_WIDTH_GAINLLR_NF_QP_5_6_FIELD 7 + +#define STV090x_GAINLLR_NF10 STV090x_GAINLLR_NFx(10) +#define STV090x_OFFST_GAINLLR_NF_QP_8_9_FIELD 0 +#define STV090x_WIDTH_GAINLLR_NF_QP_8_9_FIELD 7 + +#define STV090x_GAINLLR_NF11 STV090x_GAINLLR_NFx(11) +#define STV090x_OFFST_GAINLLR_NF_QP_9_10_FIELD 0 +#define STV090x_WIDTH_GAINLLR_NF_QP_9_10_FIELD 7 + +#define STV090x_GAINLLR_NF12 STV090x_GAINLLR_NFx(12) +#define STV090x_OFFST_GAINLLR_NF_8P_3_5_FIELD 0 +#define STV090x_WIDTH_GAINLLR_NF_8P_3_5_FIELD 7 + +#define STV090x_GAINLLR_NF13 STV090x_GAINLLR_NFx(13) +#define STV090x_OFFST_GAINLLR_NF_8P_2_3_FIELD 0 +#define STV090x_WIDTH_GAINLLR_NF_8P_2_3_FIELD 7 + +#define STV090x_GAINLLR_NF14 STV090x_GAINLLR_NFx(14) +#define STV090x_OFFST_GAINLLR_NF_8P_3_4_FIELD 0 +#define STV090x_WIDTH_GAINLLR_NF_8P_3_4_FIELD 7 + +#define STV090x_GAINLLR_NF15 STV090x_GAINLLR_NFx(15) +#define STV090x_OFFST_GAINLLR_NF_8P_5_6_FIELD 0 +#define STV090x_WIDTH_GAINLLR_NF_8P_5_6_FIELD 7 + +#define STV090x_GAINLLR_NF16 STV090x_GAINLLR_NFx(16) +#define STV090x_OFFST_GAINLLR_NF_8P_8_9_FIELD 0 +#define STV090x_WIDTH_GAINLLR_NF_8P_8_9_FIELD 7 + +#define STV090x_GAINLLR_NF17 STV090x_GAINLLR_NFx(17) +#define STV090x_OFFST_GAINLLR_NF_8P_9_10_FIELD 0 +#define STV090x_WIDTH_GAINLLR_NF_8P_9_10_FIELD 7 + +#define STV090x_GENCFG 0xFA86 +#define STV090x_OFFST_BROADCAST_FIELD 4 +#define STV090x_WIDTH_BROADCAST_FIELD 1 +#define STV090x_OFFST_PRIORITY_FIELD 1 +#define STV090x_WIDTH_PRIORITY_FIELD 1 +#define STV090x_OFFST_DDEMOD_FIELD 0 +#define STV090x_WIDTH_DDEMOD_FIELD 1 + +#define STV090x_LDPCERRx(__x) (0xFA97 - (__x * 0x1)) +#define STV090x_LDPCERR0 STV090x_LDPCERRx(0) +#define STV090x_LDPCERR1 STV090x_LDPCERRx(1) +#define STV090x_OFFST_Px_LDPC_ERRORS_COUNTER_FIELD 0 +#define STV090x_WIDTH_Px_LDPC_ERRORS_COUNTER_FIELD 8 + +#define STV090x_BCHERR 0xFA98 +#define STV090x_OFFST_Px_ERRORFLAG_FIELD 4 +#define STV090x_WIDTH_Px_ERRORFLAG_FIELD 1 +#define STV090x_OFFST_Px_BCH_ERRORS_COUNTER_FIELD 0 +#define STV090x_WIDTH_Px_BCH_ERRORS_COUNTER_FIELD 4 + +#define STV090x_Px_TSSTATEM(__x) (0xF570 - (__x - 1) * 0x200) +#define STV090x_P1_TSSTATEM STV090x_Px_TSSTATEM(1) +#define STV090x_P2_TSSTATEM STV090x_Px_TSSTATEM(2) +#define STV090x_OFFST_Px_TSDIL_ON_FIELD 7 +#define STV090x_WIDTH_Px_TSDIL_ON_FIELD 1 +#define STV090x_OFFST_Px_TSRS_ON_FIELD 5 +#define STV090x_WIDTH_Px_TSRS_ON_FIELD 1 + +#define STV090x_Px_TSCFGH(__x) (0xF572 - (__x - 1) * 0x200) +#define STV090x_P1_TSCFGH STV090x_Px_TSCFGH(1) +#define STV090x_P2_TSCFGH STV090x_Px_TSCFGH(2) +#define STV090x_OFFST_Px_TSFIFO_DVBCI_FIELD 7 +#define STV090x_WIDTH_Px_TSFIFO_DVBCI_FIELD 1 +#define STV090x_OFFST_Px_TSFIFO_SERIAL_FIELD 6 +#define STV090x_WIDTH_Px_TSFIFO_SERIAL_FIELD 1 +#define STV090x_OFFST_Px_TSFIFO_TEIUPDATE_FIELD 5 +#define STV090x_WIDTH_Px_TSFIFO_TEIUPDATE_FIELD 1 +#define STV090x_OFFST_Px_TSFIFO_DUTY50_FIELD 4 +#define STV090x_WIDTH_Px_TSFIFO_DUTY50_FIELD 1 +#define STV090x_OFFST_Px_TSFIFO_HSGNLOUT_FIELD 3 +#define STV090x_WIDTH_Px_TSFIFO_HSGNLOUT_FIELD 1 +#define STV090x_OFFST_Px_TSFIFO_ERRORMODE_FIELD 1 +#define STV090x_WIDTH_Px_TSFIFO_ERRORMODE_FIELD 2 +#define STV090x_OFFST_Px_RST_HWARE_FIELD 0 +#define STV090x_WIDTH_Px_RST_HWARE_FIELD 1 + +#define STV090x_Px_TSCFGM(__x) (0xF573 - (__x - 1) * 0x200) +#define STV090x_P1_TSCFGM STV090x_Px_TSCFGM(1) +#define STV090x_P2_TSCFGM STV090x_Px_TSCFGM(2) +#define STV090x_OFFST_Px_TSFIFO_MANSPEED_FIELD 6 +#define STV090x_WIDTH_Px_TSFIFO_MANSPEED_FIELD 2 +#define STV090x_OFFST_Px_TSFIFO_PERMDATA_FIELD 5 +#define STV090x_WIDTH_Px_TSFIFO_PERMDATA_FIELD 1 +#define STV090x_OFFST_Px_TSFIFO_INVDATA_FIELD 0 +#define STV090x_WIDTH_Px_TSFIFO_INVDATA_FIELD 1 + +#define STV090x_Px_TSCFGL(__x) (0xF574 - (__x - 1) * 0x200) +#define STV090x_P1_TSCFGL STV090x_Px_TSCFGL(1) +#define STV090x_P2_TSCFGL STV090x_Px_TSCFGL(2) +#define STV090x_OFFST_Px_TSFIFO_BCLKDEL1CK_FIELD 6 +#define STV090x_WIDTH_Px_TSFIFO_BCLKDEL1CK_FIELD 2 +#define STV090x_OFFST_Px_BCHERROR_MODE_FIELD 4 +#define STV090x_WIDTH_Px_BCHERROR_MODE_FIELD 2 +#define STV090x_OFFST_Px_TSFIFO_NSGNL2DATA_FIELD 3 +#define STV090x_WIDTH_Px_TSFIFO_NSGNL2DATA_FIELD 1 +#define STV090x_OFFST_Px_TSFIFO_EMBINDVB_FIELD 2 +#define STV090x_WIDTH_Px_TSFIFO_EMBINDVB_FIELD 1 +#define STV090x_OFFST_Px_TSFIFO_DPUNACT_FIELD 1 +#define STV090x_WIDTH_Px_TSFIFO_DPUNACT_FIELD 1 + +#define STV090x_Px_TSINSDELH(__x) (0xF576 - (__x - 1) * 0x200) +#define STV090x_P1_TSINSDELH STV090x_Px_TSINSDELH(1) +#define STV090x_P2_TSINSDELH STV090x_Px_TSINSDELH(2) +#define STV090x_OFFST_Px_TSDEL_SYNCBYTE_FIELD 7 +#define STV090x_WIDTH_Px_TSDEL_SYNCBYTE_FIELD 1 +#define STV090x_OFFST_Px_TSDEL_XXHEADER_FIELD 6 +#define STV090x_WIDTH_Px_TSDEL_XXHEADER_FIELD 1 + +#define STV090x_Px_TSSPEED(__x) (0xF580 - (__x - 1) * 0x200) +#define STV090x_P1_TSSPEED STV090x_Px_TSSPEED(1) +#define STV090x_P2_TSSPEED STV090x_Px_TSSPEED(2) +#define STV090x_OFFST_Px_TSFIFO_OUTSPEED_FIELD 0 +#define STV090x_WIDTH_Px_TSFIFO_OUTSPEED_FIELD 8 + +#define STV090x_Px_TSSTATUS(__x) (0xF581 - (__x - 1) * 0x200) +#define STV090x_P1_TSSTATUS STV090x_Px_TSSTATUS(1) +#define STV090x_P2_TSSTATUS STV090x_Px_TSSTATUS(2) +#define STV090x_OFFST_Px_TSFIFO_LINEOK_FIELD 7 +#define STV090x_WIDTH_Px_TSFIFO_LINEOK_FIELD 1 +#define STV090x_OFFST_Px_TSFIFO_ERROR_FIELD 6 +#define STV090x_WIDTH_Px_TSFIFO_ERROR_FIELD 1 + +#define STV090x_Px_TSSTATUS2(__x) (0xF582 - (__x - 1) * 0x200) +#define STV090x_P1_TSSTATUS2 STV090x_Px_TSSTATUS2(1) +#define STV090x_P2_TSSTATUS2 STV090x_Px_TSSTATUS2(2) +#define STV090x_OFFST_Px_TSFIFO_DEMODSEL_FIELD 7 +#define STV090x_WIDTH_Px_TSFIFO_DEMODSEL_FIELD 1 +#define STV090x_OFFST_Px_TSFIFOSPEED_STORE_FIELD 6 +#define STV090x_WIDTH_Px_TSFIFOSPEED_STORE_FIELD 1 +#define STV090x_OFFST_Px_DILXX_RESET_FIELD 5 +#define STV090x_WIDTH_Px_DILXX_RESET_FIELD 1 +#define STV090x_OFFST_Px_TSSERIAL_IMPOS_FIELD 5 +#define STV090x_WIDTH_Px_TSSERIAL_IMPOS_FIELD 1 +#define STV090x_OFFST_Px_SCRAMBDETECT_FIELD 1 +#define STV090x_WIDTH_Px_SCRAMBDETECT_FIELD 1 + +#define STV090x_Px_TSBITRATEy(__x, __y) (0xF584 - (__x - 1) * 0x200 - __y * 0x1) +#define STV090x_P1_TSBITRATE0 STV090x_Px_TSBITRATEy(1, 0) +#define STV090x_P1_TSBITRATE1 STV090x_Px_TSBITRATEy(1, 1) +#define STV090x_P2_TSBITRATE0 STV090x_Px_TSBITRATEy(2, 0) +#define STV090x_P2_TSBITRATE1 STV090x_Px_TSBITRATEy(2, 1) +#define STV090x_OFFST_Px_TSFIFO_BITRATE_FIELD 7 +#define STV090x_WIDTH_Px_TSFIFO_BITRATE_FIELD 8 + +#define STV090x_Px_ERRCTRL1(__x) (0xF598 - (__x - 1) * 0x200) +#define STV090x_P1_ERRCTRL1 STV090x_Px_ERRCTRL1(1) +#define STV090x_P2_ERRCTRL1 STV090x_Px_ERRCTRL1(2) +#define STV090x_OFFST_Px_ERR_SOURCE_FIELD 4 +#define STV090x_WIDTH_Px_ERR_SOURCE_FIELD 4 +#define STV090x_OFFST_Px_NUM_EVENT_FIELD 0 +#define STV090x_WIDTH_Px_NUM_EVENT_FIELD 3 + +#define STV090x_Px_ERRCNT12(__x) (0xF599 - (__x - 1) * 0x200) +#define STV090x_P1_ERRCNT12 STV090x_Px_ERRCNT12(1) +#define STV090x_P2_ERRCNT12 STV090x_Px_ERRCNT12(2) +#define STV090x_OFFST_Px_ERRCNT1_OLDVALUE_FIELD 7 +#define STV090x_WIDTH_Px_ERRCNT1_OLDVALUE_FIELD 1 +#define STV090x_OFFST_Px_ERR_CNT12_FIELD 0 +#define STV090x_WIDTH_Px_ERR_CNT12_FIELD 7 + +#define STV090x_Px_ERRCNT11(__x) (0xF59A - (__x - 1) * 0x200) +#define STV090x_P1_ERRCNT11 STV090x_Px_ERRCNT11(1) +#define STV090x_P2_ERRCNT11 STV090x_Px_ERRCNT11(2) +#define STV090x_OFFST_Px_ERR_CNT11_FIELD 0 +#define STV090x_WIDTH_Px_ERR_CNT11_FIELD 8 + +#define STV090x_Px_ERRCNT10(__x) (0xF59B - (__x - 1) * 0x200) +#define STV090x_P1_ERRCNT10 STV090x_Px_ERRCNT10(1) +#define STV090x_P2_ERRCNT10 STV090x_Px_ERRCNT10(2) +#define STV090x_OFFST_Px_ERR_CNT10_FIELD 0 +#define STV090x_WIDTH_Px_ERR_CNT10_FIELD 8 + +#define STV090x_Px_ERRCTRL2(__x) (0xF59C - (__x - 1) * 0x200) +#define STV090x_P1_ERRCTRL2 STV090x_Px_ERRCTRL2(1) +#define STV090x_P2_ERRCTRL2 STV090x_Px_ERRCTRL2(2) +#define STV090x_OFFST_Px_ERR_SOURCE2_FIELD 4 +#define STV090x_WIDTH_Px_ERR_SOURCE2_FIELD 4 +#define STV090x_OFFST_Px_NUM_EVENT2_FIELD 0 +#define STV090x_WIDTH_Px_NUM_EVENT2_FIELD 3 + +#define STV090x_Px_ERRCNT22(__x) (0xF59D - (__x - 1) * 0x200) +#define STV090x_P1_ERRCNT22 STV090x_Px_ERRCNT22(1) +#define STV090x_P2_ERRCNT22 STV090x_Px_ERRCNT22(2) +#define STV090x_OFFST_Px_ERRCNT2_OLDVALUE_FIELD 7 +#define STV090x_WIDTH_Px_ERRCNT2_OLDVALUE_FIELD 1 +#define STV090x_OFFST_Px_ERR_CNT2_FIELD 0 +#define STV090x_WIDTH_Px_ERR_CNT2_FIELD 7 + +#define STV090x_Px_ERRCNT21(__x) (0xF59E - (__x - 1) * 0x200) +#define STV090x_P1_ERRCNT21 STV090x_Px_ERRCNT21(1) +#define STV090x_P2_ERRCNT21 STV090x_Px_ERRCNT21(2) +#define STV090x_OFFST_Px_ERR_CNT21_FIELD 0 +#define STV090x_WIDTH_Px_ERR_CNT21_FIELD 8 + +#define STV090x_Px_ERRCNT20(__x) (0xF59F - (__x - 1) * 0x200) +#define STV090x_P1_ERRCNT20 STV090x_Px_ERRCNT20(1) +#define STV090x_P2_ERRCNT20 STV090x_Px_ERRCNT20(2) +#define STV090x_OFFST_Px_ERR_CNT20_FIELD 0 +#define STV090x_WIDTH_Px_ERR_CNT20_FIELD 8 + +#define STV090x_Px_FECSPY(__x) (0xF5A0 - (__x - 1) * 0x200) +#define STV090x_P1_FECSPY STV090x_Px_FECSPY(1) +#define STV090x_P2_FECSPY STV090x_Px_FECSPY(2) +#define STV090x_OFFST_Px_SPY_ENABLE_FIELD 7 +#define STV090x_WIDTH_Px_SPY_ENABLE_FIELD 1 +#define STV090x_OFFST_Px_BERMETER_DATAMAODE_FIELD 2 +#define STV090x_WIDTH_Px_BERMETER_DATAMAODE_FIELD 2 + +#define STV090x_Px_FSPYCFG(__x) (0xF5A1 - (__x - 1) * 0x200) +#define STV090x_P1_FSPYCFG STV090x_Px_FSPYCFG(1) +#define STV090x_P2_FSPYCFG STV090x_Px_FSPYCFG(2) +#define STV090x_OFFST_Px_RST_ON_ERROR_FIELD 5 +#define STV090x_WIDTH_Px_RST_ON_ERROR_FIELD 1 +#define STV090x_OFFST_Px_ONE_SHOT_FIELD 4 +#define STV090x_WIDTH_Px_ONE_SHOT_FIELD 1 +#define STV090x_OFFST_Px_I2C_MODE_FIELD 2 +#define STV090x_WIDTH_Px_I2C_MODE_FIELD 2 + +#define STV090x_Px_FSPYDATA(__x) (0xF5A2 - (__x - 1) * 0x200) +#define STV090x_P1_FSPYDATA STV090x_Px_FSPYDATA(1) +#define STV090x_P2_FSPYDATA STV090x_Px_FSPYDATA(2) +#define STV090x_OFFST_Px_SPY_STUFFING_FIELD 7 +#define STV090x_WIDTH_Px_SPY_STUFFING_FIELD 1 +#define STV090x_OFFST_Px_SPY_CNULLPKT_FIELD 5 +#define STV090x_WIDTH_Px_SPY_CNULLPKT_FIELD 1 +#define STV090x_OFFST_Px_SPY_OUTDATA_MODE_FIELD 0 +#define STV090x_WIDTH_Px_SPY_OUTDATA_MODE_FIELD 5 + +#define STV090x_Px_FSPYOUT(__x) (0xF5A3 - (__x - 1) * 0x200) +#define STV090x_P1_FSPYOUT STV090x_Px_FSPYOUT(1) +#define STV090x_P2_FSPYOUT STV090x_Px_FSPYOUT(2) +#define STV090x_OFFST_Px_FSPY_DIRECT_FIELD 7 +#define STV090x_WIDTH_Px_FSPY_DIRECT_FIELD 1 +#define STV090x_OFFST_Px_STUFF_MODE_FIELD 0 +#define STV090x_WIDTH_Px_STUFF_MODE_FIELD 3 + +#define STV090x_Px_FSTATUS(__x) (0xF5A4 - (__x - 1) * 0x200) +#define STV090x_P1_FSTATUS STV090x_Px_FSTATUS(1) +#define STV090x_P2_FSTATUS STV090x_Px_FSTATUS(2) +#define STV090x_OFFST_Px_SPY_ENDSIM_FIELD 7 +#define STV090x_WIDTH_Px_SPY_ENDSIM_FIELD 1 +#define STV090x_OFFST_Px_VALID_SIM_FIELD 6 +#define STV090x_WIDTH_Px_VALID_SIM_FIELD 1 +#define STV090x_OFFST_Px_FOUND_SIGNAL_FIELD 5 +#define STV090x_WIDTH_Px_FOUND_SIGNAL_FIELD 1 +#define STV090x_OFFST_Px_DSS_SYNCBYTE_FIELD 4 +#define STV090x_WIDTH_Px_DSS_SYNCBYTE_FIELD 1 +#define STV090x_OFFST_Px_RESULT_STATE_FIELD 0 +#define STV090x_WIDTH_Px_RESULT_STATE_FIELD 4 + +#define STV090x_Px_FBERCPT4(__x) (0xF5A8 - (__x - 1) * 0x200) +#define STV090x_P1_FBERCPT4 STV090x_Px_FBERCPT4(1) +#define STV090x_P2_FBERCPT4 STV090x_Px_FBERCPT4(2) +#define STV090x_OFFST_Px_FBERMETER_CPT_FIELD 0 +#define STV090x_WIDTH_Px_FBERMETER_CPT_FIELD 8 + +#define STV090x_Px_FBERCPT3(__x) (0xF5A9 - (__x - 1) * 0x200) +#define STV090x_P1_FBERCPT3 STV090x_Px_FBERCPT3(1) +#define STV090x_P2_FBERCPT3 STV090x_Px_FBERCPT3(2) +#define STV090x_OFFST_Px_FBERMETER_CPT_FIELD 0 +#define STV090x_WIDTH_Px_FBERMETER_CPT_FIELD 8 + +#define STV090x_Px_FBERCPT2(__x) (0xF5AA - (__x - 1) * 0x200) +#define STV090x_P1_FBERCPT2 STV090x_Px_FBERCPT2(1) +#define STV090x_P2_FBERCPT2 STV090x_Px_FBERCPT2(2) +#define STV090x_OFFST_Px_FBERMETER_CPT_FIELD 0 +#define STV090x_WIDTH_Px_FBERMETER_CPT_FIELD 8 + +#define STV090x_Px_FBERCPT1(__x) (0xF5AB - (__x - 1) * 0x200) +#define STV090x_P1_FBERCPT1 STV090x_Px_FBERCPT1(1) +#define STV090x_P2_FBERCPT1 STV090x_Px_FBERCPT1(2) +#define STV090x_OFFST_Px_FBERMETER_CPT_FIELD 0 +#define STV090x_WIDTH_Px_FBERMETER_CPT_FIELD 8 + +#define STV090x_Px_FBERCPT0(__x) (0xF5AC - (__x - 1) * 0x200) +#define STV090x_P1_FBERCPT0 STV090x_Px_FBERCPT0(1) +#define STV090x_P2_FBERCPT0 STV090x_Px_FBERCPT0(2) +#define STV090x_OFFST_Px_FBERMETER_CPT_FIELD 0 +#define STV090x_WIDTH_Px_FBERMETER_CPT_FIELD 8 + +#define STV090x_Px_FBERERRy(__x, __y) (0xF5AF - (__x - 1) * 0x200 - __y * 0x1) +#define STV090x_P1_FBERERR0 STV090x_Px_FBERERRy(1, 0) +#define STV090x_P1_FBERERR1 STV090x_Px_FBERERRy(1, 1) +#define STV090x_P1_FBERERR2 STV090x_Px_FBERERRy(1, 2) +#define STV090x_P2_FBERERR0 STV090x_Px_FBERERRy(2, 0) +#define STV090x_P2_FBERERR1 STV090x_Px_FBERERRy(2, 1) +#define STV090x_P2_FBERERR2 STV090x_Px_FBERERRy(2, 2) +#define STV090x_OFFST_Px_FBERMETER_CPT_ERR_FIELD 0 +#define STV090x_WIDTH_Px_FBERMETER_CPT_ERR_FIELD 8 + +#define STV090x_Px_FSPYBER(__x) (0xF5B2 - (__x - 1) * 0x200) +#define STV090x_P1_FSPYBER STV090x_Px_FSPYBER(1) +#define STV090x_P2_FSPYBER STV090x_Px_FSPYBER(2) +#define STV090x_OFFST_Px_FSPYBER_SYNCBYTE_FIELD 4 +#define STV090x_WIDTH_Px_FSPYBER_SYNCBYTE_FIELD 1 +#define STV090x_OFFST_Px_FSPYBER_UNSYNC_FIELD 3 +#define STV090x_WIDTH_Px_FSPYBER_UNSYNC_FIELD 1 +#define STV090x_OFFST_Px_FSPYBER_CTIME_FIELD 0 +#define STV090x_WIDTH_Px_FSPYBER_CTIME_FIELD 3 + +#define STV090x_RCCFGH 0xf600 + +#define STV090x_TSGENERAL 0xF630 +#define STV090x_OFFST_Px_MUXSTREAM_OUT_FIELD 3 +#define STV090x_WIDTH_Px_MUXSTREAM_OUT_FIELD 1 +#define STV090x_OFFST_Px_TSFIFO_PERMPARAL_FIELD 1 +#define STV090x_WIDTH_Px_TSFIFO_PERMPARAL_FIELD 2 + +#define STV090x_TSGENERAL1X 0xf670 +#define STV090x_CFGEXT 0xfa80 + +#define STV090x_TSTRES0 0xFF11 +#define STV090x_OFFST_FRESFEC_FIELD 7 +#define STV090x_WIDTH_FRESFEC_FIELD 1 + +#define STV090x_Px_TSTDISRX(__x) (0xFF67 - (__x - 1) * 0x2) +#define STV090x_P1_TSTDISRX STV090x_Px_TSTDISRX(1) +#define STV090x_P2_TSTDISRX STV090x_Px_TSTDISRX(2) +#define STV090x_OFFST_Px_TSTDISRX_SELECT_FIELD 3 +#define STV090x_WIDTH_Px_TSTDISRX_SELECT_FIELD 1 + +#endif /* __STV090x_REG_H */ diff --git a/drivers/media/dvb/frontends/stv6110x.c b/drivers/media/dvb/frontends/stv6110x.c new file mode 100644 index 000000000000..3d8a2e01c9c4 --- /dev/null +++ b/drivers/media/dvb/frontends/stv6110x.c @@ -0,0 +1,373 @@ +/* + STV6110(A) Silicon tuner driver + + Copyright (C) Manu Abraham + + Copyright (C) ST Microelectronics + + 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 +#include +#include +#include + +#include "dvb_frontend.h" + +#include "stv6110x_reg.h" +#include "stv6110x.h" +#include "stv6110x_priv.h" + +static unsigned int verbose; +module_param(verbose, int, 0644); +MODULE_PARM_DESC(verbose, "Set Verbosity level"); + +static u8 stv6110x_regs[] = {0x07, 0x11, 0xdc, 0x85, 0x17, 0x01, 0xe6, 0x1e}; + +static int stv6110x_read_reg(struct stv6110x_state *stv6110x, u8 reg, u8 *data) +{ + int ret; + const struct stv6110x_config *config = stv6110x->config; + u8 b0[] = { reg }; + u8 b1[] = { 0 }; + struct i2c_msg msg[] = { + { .addr = config->addr, .flags = 0, .buf = b0, .len = 1 }, + { .addr = config->addr, .flags = I2C_M_RD, .buf = b1, .len = 1 } + }; + + ret = i2c_transfer(stv6110x->i2c, msg, 2); + if (ret != 2) { + dprintk(FE_ERROR, 1, "I/O Error"); + return -EREMOTEIO; + } + *data = b1[0]; + + return 0; +} + +static int stv6110x_write_reg(struct stv6110x_state *stv6110x, u8 reg, u8 data) +{ + int ret; + const struct stv6110x_config *config = stv6110x->config; + u8 buf[] = { reg, data }; + struct i2c_msg msg = { .addr = config->addr, .flags = 0, . buf = buf, .len = 2 }; + + ret = i2c_transfer(stv6110x->i2c, &msg, 1); + if (ret != 1) { + dprintk(FE_ERROR, 1, "I/O Error"); + return -EREMOTEIO; + } + + return 0; +} + +static int stv6110x_init(struct dvb_frontend *fe) +{ + struct stv6110x_state *stv6110x = fe->tuner_priv; + int ret; + u8 i; + + for (i = 0; i < ARRAY_SIZE(stv6110x_regs); i++) { + ret = stv6110x_write_reg(stv6110x, i, stv6110x_regs[i]); + if (ret < 0) { + dprintk(FE_ERROR, 1, "Initialization failed"); + return -1; + } + } + + return 0; +} + +static int stv6110x_set_frequency(struct dvb_frontend *fe, u32 frequency) +{ + struct stv6110x_state *stv6110x = fe->tuner_priv; + u32 rDiv, divider; + s32 pVal, pCalc, rDivOpt = 0; + u8 i; + + STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_K, (REFCLOCK_MHz - 16)); + + if (frequency <= 1023000) { + STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_DIV4SEL, 1); + STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_PRESC32_ON, 0); + pVal = 40; + } else if (frequency <= 1300000) { + STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_DIV4SEL, 1); + STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_PRESC32_ON, 1); + pVal = 40; + } else if (frequency <= 2046000) { + STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_DIV4SEL, 0); + STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_PRESC32_ON, 0); + pVal = 20; + } else { + STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_DIV4SEL, 0); + STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_PRESC32_ON, 1); + pVal = 20; + } + + for (rDiv = 0; rDiv <= 3; rDiv++) { + pCalc = (REFCLOCK_kHz / 100) / R_DIV(rDiv); + + if ((abs((s32)(pCalc - pVal))) < (abs((s32)(1000 - pVal)))) + rDivOpt = rDiv; + } + + divider = (frequency * R_DIV(rDivOpt) * pVal) / REFCLOCK_kHz; + divider = (divider + 5) / 10; + + STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_R_DIV, rDivOpt); + STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_N_DIV_11_8, MSB(divider)); + STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG0], TNG0_N_DIV_7_0, LSB(divider)); + + /* VCO Auto calibration */ + STV6110x_SETFIELD(stv6110x_regs[STV6110x_STAT1], STAT1_CALVCO_STRT, 1); + + stv6110x_write_reg(stv6110x, STV6110x_CTRL1, stv6110x_regs[STV6110x_CTRL1]); + stv6110x_write_reg(stv6110x, STV6110x_TNG1, stv6110x_regs[STV6110x_TNG1]); + stv6110x_write_reg(stv6110x, STV6110x_TNG0, stv6110x_regs[STV6110x_TNG0]); + stv6110x_write_reg(stv6110x, STV6110x_STAT1, stv6110x_regs[STV6110x_STAT1]); + + for (i = 0; i < TRIALS; i++) { + stv6110x_read_reg(stv6110x, STV6110x_STAT1, &stv6110x_regs[STV6110x_STAT1]); + if (!STV6110x_GETFIELD(STAT1_CALVCO_STRT, stv6110x_regs[STV6110x_STAT1])) + break; + msleep(1); + } + + return 0; +} + +static int stv6110x_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct stv6110x_state *stv6110x = fe->tuner_priv; + + stv6110x_read_reg(stv6110x, STV6110x_TNG1, &stv6110x_regs[STV6110x_TNG1]); + stv6110x_read_reg(stv6110x, STV6110x_TNG0, &stv6110x_regs[STV6110x_TNG0]); + + *frequency = (MAKEWORD16(STV6110x_GETFIELD(TNG1_N_DIV_11_8, stv6110x_regs[STV6110x_TNG1]), + STV6110x_GETFIELD(TNG0_N_DIV_7_0, stv6110x_regs[STV6110x_TNG0]))) * REFCLOCK_kHz; + + *frequency /= (1 << (STV6110x_GETFIELD(TNG1_R_DIV, stv6110x_regs[STV6110x_TNG1]) + + STV6110x_GETFIELD(TNG1_DIV4SEL, stv6110x_regs[STV6110x_TNG1]))); + + *frequency >>= 2; + + return 0; +} + +static int stv6110x_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth) +{ + struct stv6110x_state *stv6110x = fe->tuner_priv; + u32 halfbw; + u8 i; + + halfbw = bandwidth >> 1; + + if (halfbw > 36000000) + STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL3], CTRL3_CF, 31); /* LPF */ + else if (halfbw < 5000000) + STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL3], CTRL3_CF, 0); /* LPF */ + else + STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL3], CTRL3_CF, ((halfbw / 1000000) - 5)); /* LPF */ + + + STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL3], CTRL3_RCCLK_OFF, 0x0); /* cal. clk activated */ + STV6110x_SETFIELD(stv6110x_regs[STV6110x_STAT1], STAT1_CALRC_STRT, 0x1); /* LPF auto cal */ + + stv6110x_write_reg(stv6110x, STV6110x_CTRL3, stv6110x_regs[STV6110x_CTRL3]); + stv6110x_write_reg(stv6110x, STV6110x_STAT1, stv6110x_regs[STV6110x_STAT1]); + + for (i = 0; i < TRIALS; i++) { + stv6110x_read_reg(stv6110x, STV6110x_STAT1, &stv6110x_regs[STV6110x_STAT1]); + if (!STV6110x_GETFIELD(STAT1_CALRC_STRT, stv6110x_regs[STV6110x_STAT1])) + break; + msleep(1); + } + STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL3], CTRL3_RCCLK_OFF, 0x1); /* cal. done */ + stv6110x_write_reg(stv6110x, STV6110x_CTRL3, stv6110x_regs[STV6110x_CTRL3]); + + return 0; +} + +static int stv6110x_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + struct stv6110x_state *stv6110x = fe->tuner_priv; + + stv6110x_read_reg(stv6110x, STV6110x_CTRL3, &stv6110x_regs[STV6110x_CTRL3]); + *bandwidth = (STV6110x_GETFIELD(CTRL3_CF, stv6110x_regs[STV6110x_CTRL3]) + 5) * 2000000; + + return 0; +} + +static int stv6110x_set_refclock(struct dvb_frontend *fe, u32 refclock) +{ + struct stv6110x_state *stv6110x = fe->tuner_priv; + + /* setup divider */ + switch (refclock) { + default: + case 1: + STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL2], CTRL2_CO_DIV, 0); + break; + case 2: + STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL2], CTRL2_CO_DIV, 1); + break; + case 4: + STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL2], CTRL2_CO_DIV, 2); + break; + case 8: + case 0: + STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL2], CTRL2_CO_DIV, 3); + break; + } + stv6110x_write_reg(stv6110x, STV6110x_CTRL2, stv6110x_regs[STV6110x_CTRL2]); + + return 0; +} + +static int stv6110x_get_bbgain(struct dvb_frontend *fe, u32 *gain) +{ + struct stv6110x_state *stv6110x = fe->tuner_priv; + + stv6110x_read_reg(stv6110x, STV6110x_CTRL2, &stv6110x_regs[STV6110x_CTRL2]); + *gain = 2 * STV6110x_GETFIELD(CTRL2_BBGAIN, stv6110x_regs[STV6110x_CTRL2]); + + return 0; +} + +static int stv6110x_set_bbgain(struct dvb_frontend *fe, u32 gain) +{ + struct stv6110x_state *stv6110x = fe->tuner_priv; + + STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL2], CTRL2_BBGAIN, gain / 2); + stv6110x_write_reg(stv6110x, STV6110x_CTRL2, stv6110x_regs[STV6110x_CTRL2]); + + return 0; +} + +static int stv6110x_set_mode(struct dvb_frontend *fe, enum tuner_mode mode) +{ + struct stv6110x_state *stv6110x = fe->tuner_priv; + int ret; + + switch (mode) { + case TUNER_SLEEP: + STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_SYN, 0); + STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_RX, 0); + STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_LPT, 0); + break; + + case TUNER_WAKE: + STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_SYN, 1); + STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_RX, 1); + STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_LPT, 1); + break; + } + + ret = stv6110x_write_reg(stv6110x, STV6110x_CTRL1, stv6110x_regs[STV6110x_CTRL1]); + if (ret < 0) { + dprintk(FE_ERROR, 1, "I/O Error"); + return -EIO; + } + + return 0; +} + +static int stv6110x_sleep(struct dvb_frontend *fe) +{ + return stv6110x_set_mode(fe, TUNER_SLEEP); +} + +static int stv6110x_get_status(struct dvb_frontend *fe, u32 *status) +{ + struct stv6110x_state *stv6110x = fe->tuner_priv; + + stv6110x_read_reg(stv6110x, STV6110x_STAT1, &stv6110x_regs[STV6110x_STAT1]); + + if (STV6110x_GETFIELD(STAT1_LOCK, stv6110x_regs[STV6110x_STAT1])) + *status = TUNER_PHASELOCKED; + else + *status = 0; + + return 0; +} + + +static int stv6110x_release(struct dvb_frontend *fe) +{ + struct stv6110x_state *stv6110x = fe->tuner_priv; + + fe->tuner_priv = NULL; + kfree(stv6110x); + + return 0; +} + +static struct dvb_tuner_ops stv6110x_ops = { + .info = { + .name = "STV6110(A) Silicon Tuner", + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_step = 0, + }, + + .init = stv6110x_init, + .sleep = stv6110x_sleep, + .release = stv6110x_release +}; + +static struct stv6110x_devctl stv6110x_ctl = { + .tuner_init = stv6110x_init, + .tuner_set_mode = stv6110x_set_mode, + .tuner_set_frequency = stv6110x_set_frequency, + .tuner_get_frequency = stv6110x_get_frequency, + .tuner_set_bandwidth = stv6110x_set_bandwidth, + .tuner_get_bandwidth = stv6110x_get_bandwidth, + .tuner_set_bbgain = stv6110x_set_bbgain, + .tuner_get_bbgain = stv6110x_get_bbgain, + .tuner_set_refclk = stv6110x_set_refclock, + .tuner_get_status = stv6110x_get_status, +}; + +struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe, + const struct stv6110x_config *config, + struct i2c_adapter *i2c) +{ + struct stv6110x_state *stv6110x; + + stv6110x = kzalloc(sizeof (struct stv6110x_state), GFP_KERNEL); + if (stv6110x == NULL) + goto error; + + stv6110x->i2c = i2c; + stv6110x->config = config; + stv6110x->devctl = &stv6110x_ctl; + + fe->tuner_priv = stv6110x; + fe->ops.tuner_ops = stv6110x_ops; + + printk("%s: Attaching STV6110x \n", __func__); + return stv6110x->devctl; + +error: + kfree(stv6110x); + return NULL; +} +EXPORT_SYMBOL(stv6110x_attach); + +MODULE_AUTHOR("Manu Abraham"); +MODULE_DESCRIPTION("STV6110x Silicon tuner"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/stv6110x.h b/drivers/media/dvb/frontends/stv6110x.h new file mode 100644 index 000000000000..a38257080e01 --- /dev/null +++ b/drivers/media/dvb/frontends/stv6110x.h @@ -0,0 +1,71 @@ +/* + STV6110(A) Silicon tuner driver + + Copyright (C) Manu Abraham + + Copyright (C) ST Microelectronics + + 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 __STV6110x_H +#define __STV6110x_H + +struct stv6110x_config { + u8 addr; + u32 refclk; +}; + +enum tuner_mode { + TUNER_SLEEP = 1, + TUNER_WAKE, +}; + +enum tuner_status { + TUNER_PHASELOCKED = 1, +}; + +struct stv6110x_devctl { + int (*tuner_init) (struct dvb_frontend *fe); + int (*tuner_set_mode) (struct dvb_frontend *fe, enum tuner_mode mode); + int (*tuner_set_frequency) (struct dvb_frontend *fe, u32 frequency); + int (*tuner_get_frequency) (struct dvb_frontend *fe, u32 *frequency); + int (*tuner_set_bandwidth) (struct dvb_frontend *fe, u32 bandwidth); + int (*tuner_get_bandwidth) (struct dvb_frontend *fe, u32 *bandwidth); + int (*tuner_set_bbgain) (struct dvb_frontend *fe, u32 gain); + int (*tuner_get_bbgain) (struct dvb_frontend *fe, u32 *gain); + int (*tuner_set_refclk) (struct dvb_frontend *fe, u32 refclk); + int (*tuner_get_status) (struct dvb_frontend *fe, u32 *status); +}; + + +#if defined(CONFIG_DVB_STV6110x) || (defined(CONFIG_DVB_STV6110x_MODULE) && defined(MODULE)) + +extern struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe, + const struct stv6110x_config *config, + struct i2c_adapter *i2c); + +#else +static inline struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe, + const struct stv6110x_config *config, + struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} + +#endif /* CONFIG_DVB_STV6110x */ + +#endif /* __STV6110x_H */ diff --git a/drivers/media/dvb/frontends/stv6110x_priv.h b/drivers/media/dvb/frontends/stv6110x_priv.h new file mode 100644 index 000000000000..7260da633d49 --- /dev/null +++ b/drivers/media/dvb/frontends/stv6110x_priv.h @@ -0,0 +1,75 @@ +/* + STV6110(A) Silicon tuner driver + + Copyright (C) Manu Abraham + + Copyright (C) ST Microelectronics + + 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 __STV6110x_PRIV_H +#define __STV6110x_PRIV_H + +#define FE_ERROR 0 +#define FE_NOTICE 1 +#define FE_INFO 2 +#define FE_DEBUG 3 +#define FE_DEBUGREG 4 + +#define dprintk(__y, __z, format, arg...) do { \ + if (__z) { \ + if ((verbose > FE_ERROR) && (verbose > __y)) \ + printk(KERN_ERR "%s: " format "\n", __func__ , ##arg); \ + else if ((verbose > FE_NOTICE) && (verbose > __y)) \ + printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg); \ + else if ((verbose > FE_INFO) && (verbose > __y)) \ + printk(KERN_INFO "%s: " format "\n", __func__ , ##arg); \ + else if ((verbose > FE_DEBUG) && (verbose > __y)) \ + printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg); \ + } else { \ + if (verbose > __y) \ + printk(format, ##arg); \ + } \ +} while (0) + + +#define STV6110x_SETFIELD(mask, bitf, val) \ + (mask = (mask & (~(((1 << STV6110x_WIDTH_##bitf) - 1) << \ + STV6110x_OFFST_##bitf))) | \ + (val << STV6110x_OFFST_##bitf)) + +#define STV6110x_GETFIELD(bitf, val) \ + ((val >> STV6110x_OFFST_##bitf) & \ + ((1 << STV6110x_WIDTH_##bitf) - 1)) + +#define MAKEWORD16(a, b) (((a) << 8) | (b)) + +#define LSB(x) ((x & 0xff)) +#define MSB(y) ((y >> 8) & 0xff) + +#define TRIALS 10 +#define R_DIV(__div) (1 << (__div + 1)) +#define REFCLOCK_kHz (stv6110x->config->refclk / 1000) +#define REFCLOCK_MHz (stv6110x->config->refclk / 1000000) + +struct stv6110x_state { + struct i2c_adapter *i2c; + const struct stv6110x_config *config; + + struct stv6110x_devctl *devctl; +}; + +#endif /* __STV6110x_PRIV_H */ diff --git a/drivers/media/dvb/frontends/stv6110x_reg.h b/drivers/media/dvb/frontends/stv6110x_reg.h new file mode 100644 index 000000000000..93e5c70e5fd8 --- /dev/null +++ b/drivers/media/dvb/frontends/stv6110x_reg.h @@ -0,0 +1,82 @@ +/* + STV6110(A) Silicon tuner driver + + Copyright (C) Manu Abraham + + Copyright (C) ST Microelectronics + + 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 __STV6110x_REG_H +#define __STV6110x_REG_H + +#define STV6110x_CTRL1 0x00 +#define STV6110x_OFFST_CTRL1_K 3 +#define STV6110x_WIDTH_CTRL1_K 5 +#define STV6110x_OFFST_CTRL1_LPT 2 +#define STV6110x_WIDTH_CTRL1_LPT 1 +#define STV6110x_OFFST_CTRL1_RX 1 +#define STV6110x_WIDTH_CTRL1_RX 1 +#define STV6110x_OFFST_CTRL1_SYN 0 +#define STV6110x_WIDTH_CTRL1_SYN 1 + +#define STV6110x_CTRL2 0x01 +#define STV6110x_OFFST_CTRL2_CO_DIV 6 +#define STV6110x_WIDTH_CTRL2_CO_DIV 2 +#define STV6110x_OFFST_CTRL2_RSVD 5 +#define STV6110x_WIDTH_CTRL2_RSVD 1 +#define STV6110x_OFFST_CTRL2_REFOUT_SEL 4 +#define STV6110x_WIDTH_CTRL2_REFOUT_SEL 1 +#define STV6110x_OFFST_CTRL2_BBGAIN 0 +#define STV6110x_WIDTH_CTRL2_BBGAIN 4 + +#define STV6110x_TNG0 0x02 +#define STV6110x_OFFST_TNG0_N_DIV_7_0 0 +#define STV6110x_WIDTH_TNG0_N_DIV_7_0 8 + +#define STV6110x_TNG1 0x03 +#define STV6110x_OFFST_TNG1_R_DIV 6 +#define STV6110x_WIDTH_TNG1_R_DIV 2 +#define STV6110x_OFFST_TNG1_PRESC32_ON 5 +#define STV6110x_WIDTH_TNG1_PRESC32_ON 1 +#define STV6110x_OFFST_TNG1_DIV4SEL 4 +#define STV6110x_WIDTH_TNG1_DIV4SEL 1 +#define STV6110x_OFFST_TNG1_N_DIV_11_8 0 +#define STV6110x_WIDTH_TNG1_N_DIV_11_8 4 + + +#define STV6110x_CTRL3 0x04 +#define STV6110x_OFFST_CTRL3_DCLOOP_OFF 7 +#define STV6110x_WIDTH_CTRL3_DCLOOP_OFF 1 +#define STV6110x_OFFST_CTRL3_RCCLK_OFF 6 +#define STV6110x_WIDTH_CTRL3_RCCLK_OFF 1 +#define STV6110x_OFFST_CTRL3_ICP 5 +#define STV6110x_WIDTH_CTRL3_ICP 1 +#define STV6110x_OFFST_CTRL3_CF 0 +#define STV6110x_WIDTH_CTRL3_CF 5 + +#define STV6110x_STAT1 0x05 +#define STV6110x_OFFST_STAT1_CALVCO_STRT 2 +#define STV6110x_WIDTH_STAT1_CALVCO_STRT 1 +#define STV6110x_OFFST_STAT1_CALRC_STRT 1 +#define STV6110x_WIDTH_STAT1_CALRC_STRT 1 +#define STV6110x_OFFST_STAT1_LOCK 0 +#define STV6110x_WIDTH_STAT1_LOCK 1 + +#define STV6110x_STAT2 0x06 +#define STV6110x_STAT3 0x07 + +#endif /* __STV6110x_REG_H */ diff --git a/drivers/media/dvb/frontends/tda10048.c b/drivers/media/dvb/frontends/tda10048.c index 2a8bbcd44cd0..cc8862ce4aae 100644 --- a/drivers/media/dvb/frontends/tda10048.c +++ b/drivers/media/dvb/frontends/tda10048.c @@ -1,7 +1,7 @@ /* NXP TDA10048HN DVB OFDM demodulator driver - Copyright (C) 2008 Steven Toth + Copyright (C) 2009 Steven Toth 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 @@ -25,6 +25,7 @@ #include #include #include +#include #include "dvb_frontend.h" #include "dvb_math.h" #include "tda10048.h" @@ -138,11 +139,20 @@ struct tda10048_state { struct i2c_adapter *i2c; - /* configuration settings */ - const struct tda10048_config *config; + /* We'll cache and update the attach config settings */ + struct tda10048_config config; struct dvb_frontend frontend; int fwloaded; + + u32 freq_if_hz; + u32 xtal_hz; + u32 pll_mfactor; + u32 pll_nfactor; + u32 pll_pfactor; + u32 sample_freq; + + enum fe_bandwidth bandwidth; }; static struct init_tab { @@ -192,12 +202,27 @@ static struct init_tab { { TDA10048_CONF_C4_2, 0x04 }, }; +static struct pll_tab { + u32 clk_freq_khz; + u32 if_freq_khz; + u8 m, n, p; +} pll_tab[] = { + { TDA10048_CLK_4000, TDA10048_IF_36130, 10, 0, 0 }, + { TDA10048_CLK_16000, TDA10048_IF_3300, 10, 3, 0 }, + { TDA10048_CLK_16000, TDA10048_IF_3500, 10, 3, 0 }, + { TDA10048_CLK_16000, TDA10048_IF_3800, 10, 3, 0 }, + { TDA10048_CLK_16000, TDA10048_IF_4000, 10, 3, 0 }, + { TDA10048_CLK_16000, TDA10048_IF_4300, 10, 3, 0 }, + { TDA10048_CLK_16000, TDA10048_IF_36130, 10, 3, 0 }, +}; + static int tda10048_writereg(struct tda10048_state *state, u8 reg, u8 data) { + struct tda10048_config *config = &state->config; int ret; u8 buf[] = { reg, data }; struct i2c_msg msg = { - .addr = state->config->demod_address, + .addr = config->demod_address, .flags = 0, .buf = buf, .len = 2 }; dprintk(2, "%s(reg = 0x%02x, data = 0x%02x)\n", __func__, reg, data); @@ -212,13 +237,14 @@ static int tda10048_writereg(struct tda10048_state *state, u8 reg, u8 data) static u8 tda10048_readreg(struct tda10048_state *state, u8 reg) { + struct tda10048_config *config = &state->config; int ret; u8 b0[] = { reg }; u8 b1[] = { 0 }; struct i2c_msg msg[] = { - { .addr = state->config->demod_address, + { .addr = config->demod_address, .flags = 0, .buf = b0, .len = 1 }, - { .addr = state->config->demod_address, + { .addr = config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; dprintk(2, "%s(reg = 0x%02x)\n", __func__, reg); @@ -235,6 +261,7 @@ static u8 tda10048_readreg(struct tda10048_state *state, u8 reg) static int tda10048_writeregbulk(struct tda10048_state *state, u8 reg, const u8 *data, u16 len) { + struct tda10048_config *config = &state->config; int ret = -EREMOTEIO; struct i2c_msg msg; u8 *buf; @@ -250,7 +277,7 @@ static int tda10048_writeregbulk(struct tda10048_state *state, u8 reg, *buf = reg; memcpy(buf + 1, data, len); - msg.addr = state->config->demod_address; + msg.addr = config->demod_address; msg.flags = 0; msg.buf = buf; msg.len = len + 1; @@ -271,14 +298,206 @@ error: return ret; } +static int tda10048_set_phy2(struct dvb_frontend *fe, u32 sample_freq_hz, + u32 if_hz) +{ + struct tda10048_state *state = fe->demodulator_priv; + u64 t; + + dprintk(1, "%s()\n", __func__); + + if (sample_freq_hz == 0) + return -EINVAL; + + if (if_hz < (sample_freq_hz / 2)) { + /* PHY2 = (if2/fs) * 2^15 */ + t = if_hz; + t *= 10; + t *= 32768; + do_div(t, sample_freq_hz); + t += 5; + do_div(t, 10); + } else { + /* PHY2 = ((IF1-fs)/fs) * 2^15 */ + t = sample_freq_hz - if_hz; + t *= 10; + t *= 32768; + do_div(t, sample_freq_hz); + t += 5; + do_div(t, 10); + t = ~t + 1; + } + + tda10048_writereg(state, TDA10048_FREQ_PHY2_LSB, (u8)t); + tda10048_writereg(state, TDA10048_FREQ_PHY2_MSB, (u8)(t >> 8)); + + return 0; +} + +static int tda10048_set_wref(struct dvb_frontend *fe, u32 sample_freq_hz, + u32 bw) +{ + struct tda10048_state *state = fe->demodulator_priv; + u64 t, z; + u32 b = 8000000; + + dprintk(1, "%s()\n", __func__); + + if (sample_freq_hz == 0) + return -EINVAL; + + if (bw == BANDWIDTH_6_MHZ) + b = 6000000; + else + if (bw == BANDWIDTH_7_MHZ) + b = 7000000; + + /* WREF = (B / (7 * fs)) * 2^31 */ + t = b * 10; + /* avoid warning: this decimal constant is unsigned only in ISO C90 */ + /* t *= 2147483648 on 32bit platforms */ + t *= (2048 * 1024); + t *= 1024; + z = 7 * sample_freq_hz; + do_div(t, z); + t += 5; + do_div(t, 10); + + tda10048_writereg(state, TDA10048_TIME_WREF_LSB, (u8)t); + tda10048_writereg(state, TDA10048_TIME_WREF_MID1, (u8)(t >> 8)); + tda10048_writereg(state, TDA10048_TIME_WREF_MID2, (u8)(t >> 16)); + tda10048_writereg(state, TDA10048_TIME_WREF_MSB, (u8)(t >> 24)); + + return 0; +} + +static int tda10048_set_invwref(struct dvb_frontend *fe, u32 sample_freq_hz, + u32 bw) +{ + struct tda10048_state *state = fe->demodulator_priv; + u64 t; + u32 b = 8000000; + + dprintk(1, "%s()\n", __func__); + + if (sample_freq_hz == 0) + return -EINVAL; + + if (bw == BANDWIDTH_6_MHZ) + b = 6000000; + else + if (bw == BANDWIDTH_7_MHZ) + b = 7000000; + + /* INVWREF = ((7 * fs) / B) * 2^5 */ + t = sample_freq_hz; + t *= 7; + t *= 32; + t *= 10; + do_div(t, b); + t += 5; + do_div(t, 10); + + tda10048_writereg(state, TDA10048_TIME_INVWREF_LSB, (u8)t); + tda10048_writereg(state, TDA10048_TIME_INVWREF_MSB, (u8)(t >> 8)); + + return 0; +} + +static int tda10048_set_bandwidth(struct dvb_frontend *fe, + enum fe_bandwidth bw) +{ + struct tda10048_state *state = fe->demodulator_priv; + dprintk(1, "%s(bw=%d)\n", __func__, bw); + + /* Bandwidth setting may need to be adjusted */ + switch (bw) { + case BANDWIDTH_6_MHZ: + case BANDWIDTH_7_MHZ: + case BANDWIDTH_8_MHZ: + tda10048_set_wref(fe, state->sample_freq, bw); + tda10048_set_invwref(fe, state->sample_freq, bw); + break; + default: + printk(KERN_ERR "%s() invalid bandwidth\n", __func__); + return -EINVAL; + } + + state->bandwidth = bw; + + return 0; +} + +static int tda10048_set_if(struct dvb_frontend *fe, enum fe_bandwidth bw) +{ + struct tda10048_state *state = fe->demodulator_priv; + struct tda10048_config *config = &state->config; + int i; + u32 if_freq_khz; + + dprintk(1, "%s(bw = %d)\n", __func__, bw); + + /* based on target bandwidth and clk we calculate pll factors */ + switch (bw) { + case BANDWIDTH_6_MHZ: + if_freq_khz = config->dtv6_if_freq_khz; + break; + case BANDWIDTH_7_MHZ: + if_freq_khz = config->dtv7_if_freq_khz; + break; + case BANDWIDTH_8_MHZ: + if_freq_khz = config->dtv8_if_freq_khz; + break; + default: + printk(KERN_ERR "%s() no default\n", __func__); + return -EINVAL; + } + + for (i = 0; i < ARRAY_SIZE(pll_tab); i++) { + if ((pll_tab[i].clk_freq_khz == config->clk_freq_khz) && + (pll_tab[i].if_freq_khz == if_freq_khz)) { + + state->freq_if_hz = pll_tab[i].if_freq_khz * 1000; + state->xtal_hz = pll_tab[i].clk_freq_khz * 1000; + state->pll_mfactor = pll_tab[i].m; + state->pll_nfactor = pll_tab[i].n; + state->pll_pfactor = pll_tab[i].p; + break; + } + } + if (i == ARRAY_SIZE(pll_tab)) { + printk(KERN_ERR "%s() Incorrect attach settings\n", + __func__); + return -EINVAL; + } + + dprintk(1, "- freq_if_hz = %d\n", state->freq_if_hz); + dprintk(1, "- xtal_hz = %d\n", state->xtal_hz); + dprintk(1, "- pll_mfactor = %d\n", state->pll_mfactor); + dprintk(1, "- pll_nfactor = %d\n", state->pll_nfactor); + dprintk(1, "- pll_pfactor = %d\n", state->pll_pfactor); + + /* Calculate the sample frequency */ + state->sample_freq = state->xtal_hz * (state->pll_mfactor + 45); + state->sample_freq /= (state->pll_nfactor + 1); + state->sample_freq /= (state->pll_pfactor + 4); + dprintk(1, "- sample_freq = %d\n", state->sample_freq); + + /* Update the I/F */ + tda10048_set_phy2(fe, state->sample_freq, state->freq_if_hz); + + return 0; +} + static int tda10048_firmware_upload(struct dvb_frontend *fe) { struct tda10048_state *state = fe->demodulator_priv; + struct tda10048_config *config = &state->config; const struct firmware *fw; int ret; int pos = 0; int cnt; - u8 wlen = state->config->fwbulkwritelen; + u8 wlen = config->fwbulkwritelen; if ((wlen != TDA10048_BULKWRITE_200) && (wlen != TDA10048_BULKWRITE_50)) wlen = TDA10048_BULKWRITE_200; @@ -289,7 +508,7 @@ static int tda10048_firmware_upload(struct dvb_frontend *fe) TDA10048_DEFAULT_FIRMWARE); ret = request_firmware(&fw, TDA10048_DEFAULT_FIRMWARE, - &state->i2c->dev); + state->i2c->dev.parent); if (ret) { printk(KERN_ERR "%s: Upload failed. (file not found?)\n", __func__); @@ -484,8 +703,12 @@ static int tda10048_get_tps(struct tda10048_state *state, static int tda10048_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) { struct tda10048_state *state = fe->demodulator_priv; + struct tda10048_config *config = &state->config; dprintk(1, "%s(%d)\n", __func__, enable); + if (config->disable_gate_access) + return 0; + if (enable) return tda10048_writereg(state, TDA10048_CONF_C4_1, tda10048_readreg(state, TDA10048_CONF_C4_1) | 0x02); @@ -523,6 +746,12 @@ static int tda10048_set_frontend(struct dvb_frontend *fe, dprintk(1, "%s(frequency=%d)\n", __func__, p->frequency); + /* Update the I/F pll's if the bandwidth changes */ + if (p->u.ofdm.bandwidth != state->bandwidth) { + tda10048_set_if(fe, p->u.ofdm.bandwidth); + tda10048_set_bandwidth(fe, p->u.ofdm.bandwidth); + } + if (fe->ops.tuner_ops.set_params) { if (fe->ops.i2c_gate_ctrl) @@ -544,6 +773,7 @@ static int tda10048_set_frontend(struct dvb_frontend *fe, static int tda10048_init(struct dvb_frontend *fe) { struct tda10048_state *state = fe->demodulator_priv; + struct tda10048_config *config = &state->config; int ret = 0, i; dprintk(1, "%s()\n", __func__); @@ -556,10 +786,14 @@ static int tda10048_init(struct dvb_frontend *fe) ret = tda10048_firmware_upload(fe); /* Set either serial or parallel */ - tda10048_output_mode(fe, state->config->output_mode); + tda10048_output_mode(fe, config->output_mode); - /* set inversion */ - tda10048_set_inversion(fe, state->config->inversion); + /* Set inversion */ + tda10048_set_inversion(fe, config->inversion); + + /* Establish default RF values */ + tda10048_set_if(fe, BANDWIDTH_8_MHZ); + tda10048_set_bandwidth(fe, BANDWIDTH_8_MHZ); /* Ensure we leave the gate closed */ tda10048_i2c_gate_ctrl(fe, 0); @@ -812,6 +1046,45 @@ static void tda10048_release(struct dvb_frontend *fe) kfree(state); } +static void tda10048_establish_defaults(struct dvb_frontend *fe) +{ + struct tda10048_state *state = fe->demodulator_priv; + struct tda10048_config *config = &state->config; + + /* Validate/default the config */ + if (config->dtv6_if_freq_khz == 0) { + config->dtv6_if_freq_khz = TDA10048_IF_4300; + printk(KERN_WARNING "%s() tda10048_config.dtv6_if_freq_khz " + "is not set (defaulting to %d)\n", + __func__, + config->dtv6_if_freq_khz); + } + + if (config->dtv7_if_freq_khz == 0) { + config->dtv7_if_freq_khz = TDA10048_IF_4300; + printk(KERN_WARNING "%s() tda10048_config.dtv7_if_freq_khz " + "is not set (defaulting to %d)\n", + __func__, + config->dtv7_if_freq_khz); + } + + if (config->dtv8_if_freq_khz == 0) { + config->dtv8_if_freq_khz = TDA10048_IF_4300; + printk(KERN_WARNING "%s() tda10048_config.dtv8_if_freq_khz " + "is not set (defaulting to %d)\n", + __func__, + config->dtv8_if_freq_khz); + } + + if (config->clk_freq_khz == 0) { + config->clk_freq_khz = TDA10048_CLK_16000; + printk(KERN_WARNING "%s() tda10048_config.clk_freq_khz " + "is not set (defaulting to %d)\n", + __func__, + config->clk_freq_khz); + } +} + static struct dvb_frontend_ops tda10048_ops; struct dvb_frontend *tda10048_attach(const struct tda10048_config *config, @@ -826,10 +1099,11 @@ struct dvb_frontend *tda10048_attach(const struct tda10048_config *config, if (state == NULL) goto error; - /* setup the state */ - state->config = config; + /* setup the state and clone the config */ + memcpy(&state->config, config, sizeof(*config)); state->i2c = i2c; state->fwloaded = 0; + state->bandwidth = BANDWIDTH_8_MHZ; /* check if the demod is present */ if (tda10048_readreg(state, TDA10048_IDENTITY) != 0x048) @@ -840,6 +1114,17 @@ struct dvb_frontend *tda10048_attach(const struct tda10048_config *config, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; + /* Establish any defaults the the user didn't pass */ + tda10048_establish_defaults(&state->frontend); + + /* Set the xtal and freq defaults */ + if (tda10048_set_if(&state->frontend, BANDWIDTH_8_MHZ) != 0) + goto error; + + /* Default bandwidth */ + if (tda10048_set_bandwidth(&state->frontend, BANDWIDTH_8_MHZ) != 0) + goto error; + /* Leave the gate closed */ tda10048_i2c_gate_ctrl(&state->frontend, 0); diff --git a/drivers/media/dvb/frontends/tda10048.h b/drivers/media/dvb/frontends/tda10048.h index 0457b24601fa..8828ceaf74bb 100644 --- a/drivers/media/dvb/frontends/tda10048.h +++ b/drivers/media/dvb/frontends/tda10048.h @@ -1,7 +1,7 @@ /* NXP TDA10048HN DVB OFDM demodulator driver - Copyright (C) 2008 Steven Toth + Copyright (C) 2009 Steven Toth 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 @@ -43,6 +43,25 @@ struct tda10048_config { #define TDA10048_INVERSION_OFF 0 #define TDA10048_INVERSION_ON 1 u8 inversion; + +#define TDA10048_IF_3300 3300 +#define TDA10048_IF_3500 3500 +#define TDA10048_IF_3800 3800 +#define TDA10048_IF_4000 4000 +#define TDA10048_IF_4300 4300 +#define TDA10048_IF_4500 4500 +#define TDA10048_IF_4750 4750 +#define TDA10048_IF_36130 36130 + u16 dtv6_if_freq_khz; + u16 dtv7_if_freq_khz; + u16 dtv8_if_freq_khz; + +#define TDA10048_CLK_4000 4000 +#define TDA10048_CLK_16000 16000 + u16 clk_freq_khz; + + /* Disable I2C gate access */ + u8 disable_gate_access; }; #if defined(CONFIG_DVB_TDA10048) || \ diff --git a/drivers/media/dvb/siano/Makefile b/drivers/media/dvb/siano/Makefile index bcf93f4828b2..c6644d909433 100644 --- a/drivers/media/dvb/siano/Makefile +++ b/drivers/media/dvb/siano/Makefile @@ -1,4 +1,4 @@ -sms1xxx-objs := smscoreapi.o sms-cards.o +sms1xxx-objs := smscoreapi.o sms-cards.o smsendian.o smsir.o obj-$(CONFIG_DVB_SIANO_SMS1XXX) += sms1xxx.o obj-$(CONFIG_DVB_SIANO_SMS1XXX) += smsusb.o diff --git a/drivers/media/dvb/siano/sms-cards.c b/drivers/media/dvb/siano/sms-cards.c index 63e4d0ec6583..d8b15d583bde 100644 --- a/drivers/media/dvb/siano/sms-cards.c +++ b/drivers/media/dvb/siano/sms-cards.c @@ -18,6 +18,7 @@ */ #include "sms-cards.h" +#include "smsir.h" static int sms_dbg; module_param_named(cards_dbg, sms_dbg, int, 0644); @@ -30,17 +31,14 @@ static struct sms_board sms_boards[] = { [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", @@ -65,6 +63,9 @@ static struct sms_board sms_boards[] = { .name = "Hauppauge WinTV MiniStick", .type = SMS_NOVA_B0, .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw", + .board_cfg.leds_power = 26, + .board_cfg.led0 = 27, + .board_cfg.led1 = 28, .led_power = 26, .led_lo = 27, .led_hi = 28, @@ -74,7 +75,9 @@ static struct sms_board sms_boards[] = { .type = SMS_NOVA_B0, .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw", .lna_ctrl = 29, + .board_cfg.foreign_lna0_ctrl = 29, .rf_switch = 17, + .board_cfg.rf_switch_uhf = 17, }, [SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2] = { .name = "Hauppauge WinTV MiniCard", @@ -82,6 +85,16 @@ static struct sms_board sms_boards[] = { .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw", .lna_ctrl = -1, }, + [SMS1XXX_BOARD_SIANO_NICE] = { + /* 11 */ + .name = "Siano Nice Digital Receiver", + .type = SMS_NOVA_B0, + }, + [SMS1XXX_BOARD_SIANO_VENICE] = { + /* 12 */ + .name = "Siano Venice Digital Receiver", + .type = SMS_VEGA, + }, }; struct sms_board *sms_get_board(int id) @@ -91,12 +104,179 @@ struct sms_board *sms_get_board(int id) return &sms_boards[id]; } EXPORT_SYMBOL_GPL(sms_get_board); +static inline void sms_gpio_assign_11xx_default_led_config( + struct smscore_gpio_config *pGpioConfig) { + pGpioConfig->Direction = SMS_GPIO_DIRECTION_OUTPUT; + pGpioConfig->InputCharacteristics = + SMS_GPIO_INPUT_CHARACTERISTICS_NORMAL; + pGpioConfig->OutputDriving = SMS_GPIO_OUTPUT_DRIVING_4mA; + pGpioConfig->OutputSlewRate = SMS_GPIO_OUTPUT_SLEW_RATE_0_45_V_NS; + pGpioConfig->PullUpDown = SMS_GPIO_PULL_UP_DOWN_NONE; +} + +int sms_board_event(struct smscore_device_t *coredev, + enum SMS_BOARD_EVENTS gevent) { + int board_id = smscore_get_board_id(coredev); + struct sms_board *board = sms_get_board(board_id); + struct smscore_gpio_config MyGpioConfig; + + sms_gpio_assign_11xx_default_led_config(&MyGpioConfig); + + switch (gevent) { + case BOARD_EVENT_POWER_INIT: /* including hotplug */ + switch (board_id) { + case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM: + /* set I/O and turn off all LEDs */ + smscore_gpio_configure(coredev, + board->board_cfg.leds_power, + &MyGpioConfig); + smscore_gpio_set_level(coredev, + board->board_cfg.leds_power, 0); + smscore_gpio_configure(coredev, board->board_cfg.led0, + &MyGpioConfig); + smscore_gpio_set_level(coredev, + board->board_cfg.led0, 0); + smscore_gpio_configure(coredev, board->board_cfg.led1, + &MyGpioConfig); + smscore_gpio_set_level(coredev, + board->board_cfg.led1, 0); + break; + case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2: + case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD: + /* set I/O and turn off LNA */ + smscore_gpio_configure(coredev, + board->board_cfg.foreign_lna0_ctrl, + &MyGpioConfig); + smscore_gpio_set_level(coredev, + board->board_cfg.foreign_lna0_ctrl, + 0); + break; + } + break; /* BOARD_EVENT_BIND */ + + case BOARD_EVENT_POWER_SUSPEND: + switch (board_id) { + case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM: + smscore_gpio_set_level(coredev, + board->board_cfg.leds_power, 0); + smscore_gpio_set_level(coredev, + board->board_cfg.led0, 0); + smscore_gpio_set_level(coredev, + board->board_cfg.led1, 0); + break; + case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2: + case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD: + smscore_gpio_set_level(coredev, + board->board_cfg.foreign_lna0_ctrl, + 0); + break; + } + break; /* BOARD_EVENT_POWER_SUSPEND */ + + case BOARD_EVENT_POWER_RESUME: + switch (board_id) { + case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM: + smscore_gpio_set_level(coredev, + board->board_cfg.leds_power, 1); + smscore_gpio_set_level(coredev, + board->board_cfg.led0, 1); + smscore_gpio_set_level(coredev, + board->board_cfg.led1, 0); + break; + case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2: + case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD: + smscore_gpio_set_level(coredev, + board->board_cfg.foreign_lna0_ctrl, + 1); + break; + } + break; /* BOARD_EVENT_POWER_RESUME */ + + case BOARD_EVENT_BIND: + switch (board_id) { + case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM: + smscore_gpio_set_level(coredev, + board->board_cfg.leds_power, 1); + smscore_gpio_set_level(coredev, + board->board_cfg.led0, 1); + smscore_gpio_set_level(coredev, + board->board_cfg.led1, 0); + break; + case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2: + case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD: + smscore_gpio_set_level(coredev, + board->board_cfg.foreign_lna0_ctrl, + 1); + break; + } + break; /* BOARD_EVENT_BIND */ + + case BOARD_EVENT_SCAN_PROG: + break; /* BOARD_EVENT_SCAN_PROG */ + case BOARD_EVENT_SCAN_COMP: + break; /* BOARD_EVENT_SCAN_COMP */ + case BOARD_EVENT_EMERGENCY_WARNING_SIGNAL: + break; /* BOARD_EVENT_EMERGENCY_WARNING_SIGNAL */ + case BOARD_EVENT_FE_LOCK: + switch (board_id) { + case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM: + smscore_gpio_set_level(coredev, + board->board_cfg.led1, 1); + break; + } + break; /* BOARD_EVENT_FE_LOCK */ + case BOARD_EVENT_FE_UNLOCK: + switch (board_id) { + case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM: + smscore_gpio_set_level(coredev, + board->board_cfg.led1, 0); + break; + } + break; /* BOARD_EVENT_FE_UNLOCK */ + case BOARD_EVENT_DEMOD_LOCK: + break; /* BOARD_EVENT_DEMOD_LOCK */ + case BOARD_EVENT_DEMOD_UNLOCK: + break; /* BOARD_EVENT_DEMOD_UNLOCK */ + case BOARD_EVENT_RECEPTION_MAX_4: + break; /* BOARD_EVENT_RECEPTION_MAX_4 */ + case BOARD_EVENT_RECEPTION_3: + break; /* BOARD_EVENT_RECEPTION_3 */ + case BOARD_EVENT_RECEPTION_2: + break; /* BOARD_EVENT_RECEPTION_2 */ + case BOARD_EVENT_RECEPTION_1: + break; /* BOARD_EVENT_RECEPTION_1 */ + case BOARD_EVENT_RECEPTION_LOST_0: + break; /* BOARD_EVENT_RECEPTION_LOST_0 */ + case BOARD_EVENT_MULTIPLEX_OK: + switch (board_id) { + case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM: + smscore_gpio_set_level(coredev, + board->board_cfg.led1, 1); + break; + } + break; /* BOARD_EVENT_MULTIPLEX_OK */ + case BOARD_EVENT_MULTIPLEX_ERRORS: + switch (board_id) { + case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM: + smscore_gpio_set_level(coredev, + board->board_cfg.led1, 0); + break; + } + break; /* BOARD_EVENT_MULTIPLEX_ERRORS */ + + default: + sms_err("Unknown SMS board event"); + break; + } + return 0; +} +EXPORT_SYMBOL_GPL(sms_board_event); static int sms_set_gpio(struct smscore_device_t *coredev, int pin, int enable) { int lvl, ret; u32 gpio; - struct smscore_gpio_config gpioconfig = { + struct smscore_config_gpio gpioconfig = { .direction = SMS_GPIO_DIRECTION_OUTPUT, .pullupdown = SMS_GPIO_PULLUPDOWN_NONE, .inputcharacteristics = SMS_GPIO_INPUTCHARACTERISTICS_NORMAL, diff --git a/drivers/media/dvb/siano/sms-cards.h b/drivers/media/dvb/siano/sms-cards.h index 64d74c59c33f..38f062f6ad68 100644 --- a/drivers/media/dvb/siano/sms-cards.h +++ b/drivers/media/dvb/siano/sms-cards.h @@ -22,6 +22,7 @@ #include #include "smscoreapi.h" +#include "smsir.h" #define SMS_BOARD_UNKNOWN 0 #define SMS1XXX_BOARD_SIANO_STELLAR 1 @@ -34,10 +35,47 @@ #define SMS1XXX_BOARD_HAUPPAUGE_WINDHAM 8 #define SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD 9 #define SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2 10 +#define SMS1XXX_BOARD_SIANO_NICE 11 +#define SMS1XXX_BOARD_SIANO_VENICE 12 + +struct sms_board_gpio_cfg { + int lna_vhf_exist; + int lna_vhf_ctrl; + int lna_uhf_exist; + int lna_uhf_ctrl; + int lna_uhf_d_ctrl; + int lna_sband_exist; + int lna_sband_ctrl; + int lna_sband_d_ctrl; + int foreign_lna0_ctrl; + int foreign_lna1_ctrl; + int foreign_lna2_ctrl; + int rf_switch_vhf; + int rf_switch_uhf; + int rf_switch_sband; + int leds_power; + int led0; + int led1; + int led2; + int led3; + int led4; + int ir; + int eeprom_wp; + int mrc_sense; + int mrc_pdn_resetn; + int mrc_gp0; /* mrcs spi int */ + int mrc_gp1; + int mrc_gp2; + int mrc_gp3; + int mrc_gp4; + int host_spi_gsp_ts_int; +}; struct sms_board { enum sms_device_type_st type; char *name, *fw[DEVICE_MODE_MAX]; + struct sms_board_gpio_cfg board_cfg; + enum ir_kb_type ir_kb_type; /* gpios */ int led_power, led_hi, led_lo, lna_ctrl, rf_switch; @@ -45,6 +83,32 @@ struct sms_board { struct sms_board *sms_get_board(int id); +extern struct smscore_device_t *coredev; + +enum SMS_BOARD_EVENTS { + BOARD_EVENT_POWER_INIT, + BOARD_EVENT_POWER_SUSPEND, + BOARD_EVENT_POWER_RESUME, + BOARD_EVENT_BIND, + BOARD_EVENT_SCAN_PROG, + BOARD_EVENT_SCAN_COMP, + BOARD_EVENT_EMERGENCY_WARNING_SIGNAL, + BOARD_EVENT_FE_LOCK, + BOARD_EVENT_FE_UNLOCK, + BOARD_EVENT_DEMOD_LOCK, + BOARD_EVENT_DEMOD_UNLOCK, + BOARD_EVENT_RECEPTION_MAX_4, + BOARD_EVENT_RECEPTION_3, + BOARD_EVENT_RECEPTION_2, + BOARD_EVENT_RECEPTION_1, + BOARD_EVENT_RECEPTION_LOST_0, + BOARD_EVENT_MULTIPLEX_OK, + BOARD_EVENT_MULTIPLEX_ERRORS +}; + +int sms_board_event(struct smscore_device_t *coredev, + enum SMS_BOARD_EVENTS gevent); + int sms_board_setup(struct smscore_device_t *coredev); #define SMS_LED_OFF 0 diff --git a/drivers/media/dvb/siano/smscoreapi.c b/drivers/media/dvb/siano/smscoreapi.c index 7bd4d1dee2b3..a246903c3341 100644 --- a/drivers/media/dvb/siano/smscoreapi.c +++ b/drivers/media/dvb/siano/smscoreapi.c @@ -30,9 +30,13 @@ #include #include +#include +#include #include "smscoreapi.h" #include "sms-cards.h" +#include "smsir.h" +#include "smsendian.h" static int sms_dbg; module_param_named(debug, sms_dbg, int, 0644); @@ -58,42 +62,6 @@ struct smscore_client_t { 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; - int led_state; -}; - void smscore_set_board_id(struct smscore_device_t *core, int id) { core->board_id = id; @@ -384,6 +352,13 @@ int smscore_register_device(struct smsdevice_params_t *params, init_completion(&dev->init_device_done); init_completion(&dev->reload_start_done); init_completion(&dev->resume_done); + init_completion(&dev->gpio_configuration_done); + init_completion(&dev->gpio_set_level_done); + init_completion(&dev->gpio_get_level_done); + init_completion(&dev->ir_init_done); + + /* Buffer management */ + init_waitqueue_head(&dev->buffer_mng_waitq); /* alloc common buffer */ dev->common_buffer_size = params->buffer_size * params->num_buffers; @@ -439,6 +414,71 @@ int smscore_register_device(struct smsdevice_params_t *params, } EXPORT_SYMBOL_GPL(smscore_register_device); + +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(SMS_PROTOCOL_MAX_RAOUNDTRIP_MS)) ? + 0 : -ETIME; +} + +/** + * Starts & enables IR operations + * + * @return 0 on success, < 0 on error. + */ +static int smscore_init_ir(struct smscore_device_t *coredev) +{ + int ir_io; + int rc; + void *buffer; + + coredev->ir.input_dev = NULL; + ir_io = sms_get_board(smscore_get_board_id(coredev))->board_cfg.ir; + if (ir_io) {/* only if IR port exist we use IR sub-module */ + sms_info("IR loading"); + rc = sms_ir_init(coredev); + + if (rc != 0) + sms_err("Error initialization DTV IR sub-module"); + else { + buffer = kmalloc(sizeof(struct SmsMsgData_ST2) + + SMS_DMA_ALIGNMENT, + GFP_KERNEL | GFP_DMA); + if (buffer) { + struct SmsMsgData_ST2 *msg = + (struct SmsMsgData_ST2 *) + SMS_ALIGN_ADDRESS(buffer); + + SMS_INIT_MSG(&msg->xMsgHeader, + MSG_SMS_START_IR_REQ, + sizeof(struct SmsMsgData_ST2)); + msg->msgData[0] = coredev->ir.controller; + msg->msgData[1] = coredev->ir.timeout; + + smsendian_handle_tx_message( + (struct SmsMsgHdr_ST2 *)msg); + rc = smscore_sendrequest_and_wait(coredev, msg, + msg->xMsgHeader. msgLength, + &coredev->ir_init_done); + + kfree(buffer); + } else + sms_err + ("Sending IR initialization message failed"); + } + } else + sms_info("IR port has not been detected"); + + return 0; +} + /** * sets initial device mode and notifies client hotplugs that device is ready * @@ -459,6 +499,7 @@ int smscore_start_device(struct smscore_device_t *coredev) kmutex_lock(&g_smscore_deviceslock); rc = smscore_notify_callbacks(coredev, coredev->device, 1); + smscore_init_ir(coredev); sms_info("device %p started, rc %d", coredev, rc); @@ -468,29 +509,19 @@ int smscore_start_device(struct smscore_device_t *coredev) } EXPORT_SYMBOL_GPL(smscore_start_device); -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; + u32 mem_address; u8 *payload = firmware->Payload; int rc = 0; + firmware->StartAddress = le32_to_cpu(firmware->StartAddress); + firmware->Length = le32_to_cpu(firmware->Length); + + mem_address = firmware->StartAddress; sms_info("loading FW to addr 0x%x size %d", mem_address, firmware->Length); @@ -657,6 +688,9 @@ void smscore_unregister_device(struct smscore_device_t *coredev) kmutex_lock(&g_smscore_deviceslock); + /* Release input device (IR) resources */ + sms_ir_exit(coredev); + smscore_notify_clients(coredev); smscore_notify_callbacks(coredev, NULL, 0); @@ -664,7 +698,9 @@ void smscore_unregister_device(struct smscore_device_t *coredev) * onresponse must no longer be called */ while (1) { - while ((cb = smscore_getbuffer(coredev))) { + while (!list_empty(&coredev->buffers)) { + cb = (struct smscore_buffer_t *) coredev->buffers.next; + list_del(&cb->entry); kfree(cb); num_buffers++; } @@ -685,8 +721,10 @@ void smscore_unregister_device(struct smscore_device_t *coredev) if (coredev->common_buffer) dma_free_coherent(NULL, coredev->common_buffer_size, - coredev->common_buffer, - coredev->common_buffer_phys); + coredev->common_buffer, coredev->common_buffer_phys); + + if (coredev->fw_buf != NULL) + kfree(coredev->fw_buf); list_del(&coredev->entry); kfree(coredev); @@ -746,7 +784,7 @@ static char *smscore_fw_lkup[][SMS_NUM_OF_DEVICE_TYPES] = { /*BDA*/ {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"}, /*ISDBT*/ - {"none", "isdbt_nova_12mhz.inp", "dvb_nova_12mhz.inp", "none"}, + {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"}, /*ISDBTBDA*/ {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"}, /*CMMB*/ @@ -870,7 +908,7 @@ int smscore_set_device_mode(struct smscore_device_t *coredev, int mode) coredev->device_flags &= ~SMS_DEVICE_NOT_READY; } - if (rc != 0) + if (rc < 0) sms_err("return error code %d.", rc); return rc; } @@ -940,14 +978,11 @@ smscore_client_t *smscore_find_client(struct smscore_device_t *coredev, * */ 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); + struct smscore_buffer_t *cb) { + struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) ((u8 *) cb->p + + cb->offset); + struct smscore_client_t *client; int rc = -EBUSY; - static unsigned long last_sample_time; /* = 0; */ static int data_total; /* = 0; */ unsigned long time_now = jiffies_to_msecs(jiffies); @@ -965,6 +1000,16 @@ void smscore_onresponse(struct smscore_device_t *coredev, } data_total += cb->size; + /* Do we need to re-route? */ + if ((phdr->msgType == MSG_SMS_HO_PER_SLICES_IND) || + (phdr->msgType == MSG_SMS_TRANSMISSION_IND)) { + if (coredev->mode == DEVICE_MODE_DVBT_BDA) + phdr->msgDstId = DVBT_BDA_CONTROL_MSG_ID; + } + + + client = smscore_find_client(coredev, phdr->msgType, phdr->msgDstId); + /* If no client registered for type & id, * check for control client where type is not registered */ if (client) @@ -1009,6 +1054,35 @@ void smscore_onresponse(struct smscore_device_t *coredev, case MSG_SMS_SLEEP_RESUME_COMP_IND: complete(&coredev->resume_done); break; + case MSG_SMS_GPIO_CONFIG_EX_RES: + sms_debug("MSG_SMS_GPIO_CONFIG_EX_RES"); + complete(&coredev->gpio_configuration_done); + break; + case MSG_SMS_GPIO_SET_LEVEL_RES: + sms_debug("MSG_SMS_GPIO_SET_LEVEL_RES"); + complete(&coredev->gpio_set_level_done); + break; + case MSG_SMS_GPIO_GET_LEVEL_RES: + { + u32 *msgdata = (u32 *) phdr; + coredev->gpio_get_res = msgdata[1]; + sms_debug("MSG_SMS_GPIO_GET_LEVEL_RES gpio level %d", + coredev->gpio_get_res); + complete(&coredev->gpio_get_level_done); + break; + } + case MSG_SMS_START_IR_RES: + complete(&coredev->ir_init_done); + break; + case MSG_SMS_IR_SAMPLES_IND: + sms_ir_event(coredev, + (const char *) + ((char *)phdr + + sizeof(struct SmsMsgHdr_ST)), + (int)phdr->msgLength + - sizeof(struct SmsMsgHdr_ST)); + break; + default: break; } @@ -1030,12 +1104,24 @@ struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev) struct smscore_buffer_t *cb = NULL; unsigned long flags; + DEFINE_WAIT(wait); + spin_lock_irqsave(&coredev->bufferslock, flags); - if (!list_empty(&coredev->buffers)) { - cb = (struct smscore_buffer_t *) coredev->buffers.next; - list_del(&cb->entry); - } + /* This function must return a valid buffer, since the buffer list is + * finite, we check that there is an available buffer, if not, we wait + * until such buffer become available. + */ + + prepare_to_wait(&coredev->buffer_mng_waitq, &wait, TASK_INTERRUPTIBLE); + + if (list_empty(&coredev->buffers)) + schedule(); + + finish_wait(&coredev->buffer_mng_waitq, &wait); + + cb = (struct smscore_buffer_t *) coredev->buffers.next; + list_del(&cb->entry); spin_unlock_irqrestore(&coredev->bufferslock, flags); @@ -1052,8 +1138,8 @@ EXPORT_SYMBOL_GPL(smscore_getbuffer); * */ void smscore_putbuffer(struct smscore_device_t *coredev, - struct smscore_buffer_t *cb) -{ + struct smscore_buffer_t *cb) { + wake_up_interruptible(&coredev->buffer_mng_waitq); list_add_locked(&cb->entry, &coredev->buffers, &coredev->bufferslock); } EXPORT_SYMBOL_GPL(smscore_putbuffer); @@ -1210,8 +1296,9 @@ int smsclient_sendrequest(struct smscore_client_t *client, EXPORT_SYMBOL_GPL(smsclient_sendrequest); +/* old GPIO managments implementation */ int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin, - struct smscore_gpio_config *pinconfig) + struct smscore_config_gpio *pinconfig) { struct { struct SmsMsgHdr_ST hdr; @@ -1280,6 +1367,238 @@ int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level) &msg, sizeof(msg)); } +/* new GPIO managment implementation */ +static int GetGpioPinParams(u32 PinNum, u32 *pTranslatedPinNum, + u32 *pGroupNum, u32 *pGroupCfg) { + + *pGroupCfg = 1; + + if (PinNum >= 0 && PinNum <= 1) { + *pTranslatedPinNum = 0; + *pGroupNum = 9; + *pGroupCfg = 2; + } else if (PinNum >= 2 && PinNum <= 6) { + *pTranslatedPinNum = 2; + *pGroupNum = 0; + *pGroupCfg = 2; + } else if (PinNum >= 7 && PinNum <= 11) { + *pTranslatedPinNum = 7; + *pGroupNum = 1; + } else if (PinNum >= 12 && PinNum <= 15) { + *pTranslatedPinNum = 12; + *pGroupNum = 2; + *pGroupCfg = 3; + } else if (PinNum == 16) { + *pTranslatedPinNum = 16; + *pGroupNum = 23; + } else if (PinNum >= 17 && PinNum <= 24) { + *pTranslatedPinNum = 17; + *pGroupNum = 3; + } else if (PinNum == 25) { + *pTranslatedPinNum = 25; + *pGroupNum = 6; + } else if (PinNum >= 26 && PinNum <= 28) { + *pTranslatedPinNum = 26; + *pGroupNum = 4; + } else if (PinNum == 29) { + *pTranslatedPinNum = 29; + *pGroupNum = 5; + *pGroupCfg = 2; + } else if (PinNum == 30) { + *pTranslatedPinNum = 30; + *pGroupNum = 8; + } else if (PinNum == 31) { + *pTranslatedPinNum = 31; + *pGroupNum = 17; + } else + return -1; + + *pGroupCfg <<= 24; + + return 0; +} + +int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum, + struct smscore_gpio_config *pGpioConfig) { + + u32 totalLen; + u32 TranslatedPinNum = 0; + u32 GroupNum = 0; + u32 ElectricChar; + u32 groupCfg; + void *buffer; + int rc; + + struct SetGpioMsg { + struct SmsMsgHdr_ST xMsgHeader; + u32 msgData[6]; + } *pMsg; + + + if (PinNum > MAX_GPIO_PIN_NUMBER) + return -EINVAL; + + if (pGpioConfig == NULL) + return -EINVAL; + + totalLen = sizeof(struct SmsMsgHdr_ST) + (sizeof(u32) * 6); + + buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT, + GFP_KERNEL | GFP_DMA); + if (!buffer) + return -ENOMEM; + + pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer); + + pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; + pMsg->xMsgHeader.msgDstId = HIF_TASK; + pMsg->xMsgHeader.msgFlags = 0; + pMsg->xMsgHeader.msgLength = (u16) totalLen; + pMsg->msgData[0] = PinNum; + + if (!(coredev->device_flags & SMS_DEVICE_FAMILY2)) { + pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_CONFIG_REQ; + if (GetGpioPinParams(PinNum, &TranslatedPinNum, &GroupNum, + &groupCfg) != 0) + return -EINVAL; + + pMsg->msgData[1] = TranslatedPinNum; + pMsg->msgData[2] = GroupNum; + ElectricChar = (pGpioConfig->PullUpDown) + | (pGpioConfig->InputCharacteristics << 2) + | (pGpioConfig->OutputSlewRate << 3) + | (pGpioConfig->OutputDriving << 4); + pMsg->msgData[3] = ElectricChar; + pMsg->msgData[4] = pGpioConfig->Direction; + pMsg->msgData[5] = groupCfg; + } else { + pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_CONFIG_EX_REQ; + pMsg->msgData[1] = pGpioConfig->PullUpDown; + pMsg->msgData[2] = pGpioConfig->OutputSlewRate; + pMsg->msgData[3] = pGpioConfig->OutputDriving; + pMsg->msgData[4] = pGpioConfig->Direction; + pMsg->msgData[5] = 0; + } + + smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg); + rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen, + &coredev->gpio_configuration_done); + + if (rc != 0) { + if (rc == -ETIME) + sms_err("smscore_gpio_configure timeout"); + else + sms_err("smscore_gpio_configure error"); + } + kfree(buffer); + + return rc; +} + +int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum, + u8 NewLevel) { + + u32 totalLen; + int rc; + void *buffer; + + struct SetGpioMsg { + struct SmsMsgHdr_ST xMsgHeader; + u32 msgData[3]; /* keep it 3 ! */ + } *pMsg; + + if ((NewLevel > 1) || (PinNum > MAX_GPIO_PIN_NUMBER) || + (PinNum > MAX_GPIO_PIN_NUMBER)) + return -EINVAL; + + totalLen = sizeof(struct SmsMsgHdr_ST) + + (3 * sizeof(u32)); /* keep it 3 ! */ + + buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT, + GFP_KERNEL | GFP_DMA); + if (!buffer) + return -ENOMEM; + + pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer); + + pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; + pMsg->xMsgHeader.msgDstId = HIF_TASK; + pMsg->xMsgHeader.msgFlags = 0; + pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_SET_LEVEL_REQ; + pMsg->xMsgHeader.msgLength = (u16) totalLen; + pMsg->msgData[0] = PinNum; + pMsg->msgData[1] = NewLevel; + + /* Send message to SMS */ + smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg); + rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen, + &coredev->gpio_set_level_done); + + if (rc != 0) { + if (rc == -ETIME) + sms_err("smscore_gpio_set_level timeout"); + else + sms_err("smscore_gpio_set_level error"); + } + kfree(buffer); + + return rc; +} + +int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 PinNum, + u8 *level) { + + u32 totalLen; + int rc; + void *buffer; + + struct SetGpioMsg { + struct SmsMsgHdr_ST xMsgHeader; + u32 msgData[2]; + } *pMsg; + + + if (PinNum > MAX_GPIO_PIN_NUMBER) + return -EINVAL; + + totalLen = sizeof(struct SmsMsgHdr_ST) + (2 * sizeof(u32)); + + buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT, + GFP_KERNEL | GFP_DMA); + if (!buffer) + return -ENOMEM; + + pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer); + + pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; + pMsg->xMsgHeader.msgDstId = HIF_TASK; + pMsg->xMsgHeader.msgFlags = 0; + pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_GET_LEVEL_REQ; + pMsg->xMsgHeader.msgLength = (u16) totalLen; + pMsg->msgData[0] = PinNum; + pMsg->msgData[1] = 0; + + /* Send message to SMS */ + smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg); + rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen, + &coredev->gpio_get_level_done); + + if (rc != 0) { + if (rc == -ETIME) + sms_err("smscore_gpio_get_level timeout"); + else + sms_err("smscore_gpio_get_level error"); + } + kfree(buffer); + + /* Its a race between other gpio_get_level() and the copy of the single + * global 'coredev->gpio_get_res' to the function's variable 'level' + */ + *level = coredev->gpio_get_res; + + return rc; +} + static int __init smscore_module_init(void) { int rc = 0; @@ -1291,24 +1610,11 @@ static int __init smscore_module_init(void) INIT_LIST_HEAD(&g_smscore_registry); kmutex_init(&g_smscore_registrylock); - - - - - - return rc; - sms_debug("rc %d", rc); - return rc; } static void __exit smscore_module_exit(void) { - - - - - kmutex_lock(&g_smscore_deviceslock); while (!list_empty(&g_smscore_notifyees)) { struct smscore_device_notifyee_t *notifyee = diff --git a/drivers/media/dvb/siano/smscoreapi.h b/drivers/media/dvb/siano/smscoreapi.h index 548de9056e8b..f1108c64e895 100644 --- a/drivers/media/dvb/siano/smscoreapi.h +++ b/drivers/media/dvb/siano/smscoreapi.h @@ -1,26 +1,26 @@ -/* - * 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 2 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__ +Siano Mobile Silicon, Inc. +MDTV receiver kernel modules. +Copyright (C) 2006-2008, Uri Shkolnik, Anatoly Greenblat + +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, see . + +****************************************************************/ + +#ifndef __SMS_CORE_API_H__ +#define __SMS_CORE_API_H__ #include #include @@ -28,14 +28,13 @@ #include #include #include -#include #include +#include +#include -#include "dmxdev.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" +#include +#include "smsir.h" #define kmutex_init(_p_) mutex_init(_p_) #define kmutex_lock(_p_) mutex_lock(_p_) @@ -46,13 +45,14 @@ #define min(a, b) (((a) < (b)) ? (a) : (b)) #endif -#define SMS_ALLOC_ALIGNMENT 128 -#define SMS_DMA_ALIGNMENT 16 +#define SMS_PROTOCOL_MAX_RAOUNDTRIP_MS (10000) +#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_FAMILY2 1 +#define SMS_ROM_NO_RESPONSE 2 #define SMS_DEVICE_NOT_READY 0x8000000 enum sms_device_type_st { @@ -83,13 +83,13 @@ 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; + int size; + int offset; /* private members, read-only for clients */ - void *p; - dma_addr_t phys; - unsigned long offset_in_common; + void *p; + dma_addr_t phys; + unsigned long offset_in_common; }; struct smsdevice_params_t { @@ -116,10 +116,63 @@ struct smsclient_params_t { int data_type; onresponse_t onresponse_handler; onremove_t onremove_handler; - void *context; }; +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; + + /* host <--> device messages */ + struct completion version_ex_done, data_download_done, trigger_done; + struct completion init_device_done, reload_start_done, resume_done; + struct completion gpio_configuration_done, gpio_set_level_done; + struct completion gpio_get_level_done, ir_init_done; + + /* Buffer management */ + wait_queue_head_t buffer_mng_waitq; + + /* GPIO */ + int gpio_get_res; + + /* Target hardware board */ + int board_id; + + /* Firmware */ + u8 *fw_buf; + u32 fw_buf_size; + + /* Infrared (IR) */ + struct ir_t ir; + + int led_state; +}; + /* GPIO definitions for antenna frequency domain control (SMS8021) */ #define SMS_ANTENNA_GPIO_0 1 #define SMS_ANTENNA_GPIO_1 0 @@ -154,18 +207,15 @@ struct smsclient_params_t { #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_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_HO_PER_SLICES_IND 630 +#define MSG_SMS_SET_ANTENNA_CONFIG_REQ 651 +#define MSG_SMS_SET_ANTENNA_CONFIG_RES 652 +#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 @@ -190,14 +240,31 @@ struct smsclient_params_t { #define MSG_SMS_GPIO_CONFIG_EX_RES 713 #define MSG_SMS_ISDBT_TUNE_REQ 776 #define MSG_SMS_ISDBT_TUNE_RES 777 +#define MSG_SMS_TRANSMISSION_IND 782 +#define MSG_SMS_START_IR_REQ 800 +#define MSG_SMS_START_IR_RES 801 +#define MSG_SMS_IR_SAMPLES_IND 802 +#define MSG_SMS_SIGNAL_DETECTED_IND 827 +#define MSG_SMS_NO_SIGNAL_IND 828 #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_DVB3_EVENTS { + DVB3_EVENT_INIT = 0, + DVB3_EVENT_SLEEP, + DVB3_EVENT_HOTPLUG, + DVB3_EVENT_FE_LOCK, + DVB3_EVENT_FE_UNLOCK, + DVB3_EVENT_UNC_OK, + DVB3_EVENT_UNC_ERR +}; + enum SMS_DEVICE_MODE { DEVICE_MODE_NONE = -1, DEVICE_MODE_DVBT = 0, @@ -221,8 +288,13 @@ struct SmsMsgHdr_ST { }; struct SmsMsgData_ST { - struct SmsMsgHdr_ST xMsgHeader; - u32 msgData[1]; + struct SmsMsgHdr_ST xMsgHeader; + u32 msgData[1]; +}; + +struct SmsMsgData_ST2 { + struct SmsMsgHdr_ST xMsgHeader; + u32 msgData[2]; }; struct SmsDataDownload_ST { @@ -238,11 +310,12 @@ struct SmsVersionRes_ST { 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 + /* FirmwareId 0xFF if ROM, otherwise the + * value indicated by SMSHOSTLIB_DEVICE_MODES_E */ + u8 FirmwareId; + /* SupportedProtocols Bitwise OR combination of * supported protocols */ + u8 SupportedProtocols; u8 VersionMajor; u8 VersionMinor; @@ -264,86 +337,219 @@ struct SmsFirmware_ST { u8 Payload[1]; }; -struct SMSHOSTLIB_STATISTICS_ST { - u32 Reserved; /* Reserved */ +/* Statistics information returned as response for + * SmsHostApiGetStatistics_Req */ +struct SMSHOSTLIB_STATISTICS_S { + 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 */ + 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 */ + 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 */ + /* Transmission parameters */ + u32 Frequency; /* Frequency in Hz */ + u32 Bandwidth; /* Bandwidth in MHz, valid only for DVB-T/H */ + u32 TransmissionMode; /* Transmission Mode, for DAB modes 1-4, + for DVB-T/H FFT mode carriers in Kilos */ + u32 ModemState; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET, + valid only for DVB-T/H */ + u32 GuardInterval; /* Guard Interval from + SMSHOSTLIB_GUARD_INTERVALS_ET, valid only for DVB-T/H */ + u32 CodeRate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET, + valid only for DVB-T/H */ + u32 LPCodeRate; /* Low Priority Code Rate from + SMSHOSTLIB_CODE_RATE_ET, valid only for DVB-T/H */ + u32 Hierarchy; /* Hierarchy from SMSHOSTLIB_HIERARCHY_ET, + valid only for DVB-T/H */ + u32 Constellation; /* Constellation from + SMSHOSTLIB_CONSTELLATION_ET, valid only for DVB-T/H */ /* 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 */ - + u32 BurstSize; /* Current burst size in bytes, + valid only for DVB-H */ + u32 BurstDuration; /* Current burst duration in mSec, + valid only for DVB-H */ + u32 BurstCycleTime; /* Current burst cycle time in mSec, + valid only for DVB-H */ + u32 CalculatedBurstCycleTime;/* Current burst cycle time in mSec, + as calculated by demodulator, valid only for DVB-H */ + u32 NumOfRows; /* Number of rows in MPE table, + valid only for DVB-H */ + u32 NumOfPaddCols; /* Number of padding columns in MPE table, + valid only for DVB-H */ + u32 NumOfPunctCols; /* Number of puncturing columns in MPE table, + valid only for DVB-H */ + 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. */ + u32 BERErrorCount; /* Number of errornous SYNC bits. */ + u32 BERBitCount; /* Total number of SYNC bits. */ /* Interface information */ - u32 SmsToHostTxErrors; /* Total number of transmission errors. */ + u32 SmsToHostTxErrors; /* Total number of transmission errors. */ /* DAB/T-DMB */ - u32 PreBER; /* DAB/T-DMB only: Pre Viterbi BER [1E-5] */ + 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 */ + u32 CellId; /* TPS Cell ID in bits 15..0, bits 31..16 zero; + if set to 0xFFFFFFFF cell_id not yet recovered */ + u32 DvbhSrvIndHP; /* DVB-H service indication info, bit 1 - + Time Slicing indicator, bit 0 - MPE-FEC indicator */ + u32 DvbhSrvIndLP; /* DVB-H service indication info, bit 1 - + Time Slicing indicator, bit 0 - MPE-FEC indicator */ + u32 NumMPEReceived; /* DVB-H, Num MPE section received */ + + u32 ReservedFields[10]; /* Reserved */ }; -struct SmsMsgStatisticsInfo_ST { - u32 RequestResult; +struct PID_STATISTICS_DATA_S { + struct PID_BURST_S { + u32 size; + u32 padding_cols; + u32 punct_cols; + u32 duration; + u32 cycle; + u32 calc_cycle; + } burst; - struct SMSHOSTLIB_STATISTICS_ST Stat; + u32 tot_tbl_cnt; + u32 invalid_tbl_cnt; + u32 tot_cor_tbl; +}; - /* Split the calc of the SNR in DAB */ - u32 Signal; /* dB */ - u32 Noise; /* dB */ +struct PID_DATA_S { + u32 pid; + u32 num_rows; + struct PID_STATISTICS_DATA_S pid_statistics; +}; +#define CORRECT_STAT_RSSI(_stat) ((_stat).RSSI *= -1) +#define CORRECT_STAT_BANDWIDTH(_stat) (_stat.Bandwidth = 8 - _stat.Bandwidth) +#define CORRECT_STAT_TRANSMISSON_MODE(_stat) \ + if (_stat.TransmissionMode == 0) \ + _stat.TransmissionMode = 2; \ + else if (_stat.TransmissionMode == 1) \ + _stat.TransmissionMode = 8; \ + else \ + _stat.TransmissionMode = 4; + +struct TRANSMISSION_STATISTICS_S { + u32 Frequency; /* Frequency in Hz */ + u32 Bandwidth; /* Bandwidth in MHz */ + u32 TransmissionMode; /* FFT mode carriers in Kilos */ + u32 GuardInterval; /* Guard Interval from + SMSHOSTLIB_GUARD_INTERVALS_ET */ + u32 CodeRate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET */ + u32 LPCodeRate; /* Low Priority Code Rate from + SMSHOSTLIB_CODE_RATE_ET */ + u32 Hierarchy; /* Hierarchy from SMSHOSTLIB_HIERARCHY_ET */ + u32 Constellation; /* Constellation from + SMSHOSTLIB_CONSTELLATION_ET */ + + /* 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 */ + u32 DvbhSrvIndHP; /* DVB-H service indication info, bit 1 - + Time Slicing indicator, bit 0 - MPE-FEC indicator */ + u32 DvbhSrvIndLP; /* DVB-H service indication info, bit 1 - + Time Slicing indicator, bit 0 - MPE-FEC indicator */ + u32 IsDemodLocked; /* 0 - not locked, 1 - locked */ +}; + +struct RECEPTION_STATISTICS_S { + u32 IsRfLocked; /* 0 - not locked, 1 - locked */ + u32 IsDemodLocked; /* 0 - not locked, 1 - locked */ + u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */ + + u32 ModemState; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET */ + s32 SNR; /* dB */ + u32 BER; /* Post Viterbi BER [1E-5] */ + u32 BERErrorCount; /* Number of erronous SYNC bits. */ + u32 BERBitCount; /* Total number of SYNC bits. */ + u32 TS_PER; /* Transport stream PER, + 0xFFFFFFFF indicate N/A */ + 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 */ + u32 ErrorTSPackets; /* Number of erroneous + transport-stream packets */ + u32 TotalTSPackets; /* Total number of transport-stream packets */ + + s32 MRC_SNR; /* dB */ + s32 MRC_RSSI; /* dBm */ + s32 MRC_InBandPwr; /* In band power in dBM */ }; -struct smscore_gpio_config { +/* Statistics information returned as response for + * SmsHostApiGetStatisticsEx_Req for DVB applications, SMS1100 and up */ +struct SMSHOSTLIB_STATISTICS_DVB_S { + /* Reception */ + struct RECEPTION_STATISTICS_S ReceptionData; + + /* Transmission parameters */ + struct TRANSMISSION_STATISTICS_S TransmissionData; + + /* Burst parameters, valid only for DVB-H */ +#define SRVM_MAX_PID_FILTERS 8 + struct PID_DATA_S PidData[SRVM_MAX_PID_FILTERS]; +}; + +struct SRVM_SIGNAL_STATUS_S { + u32 result; + u32 snr; + u32 tsPackets; + u32 etsPackets; + u32 constellation; + u32 hpCode; + u32 tpsSrvIndLP; + u32 tpsSrvIndHP; + u32 cellId; + u32 reason; + + s32 inBandPower; + u32 requestId; +}; + +struct SMSHOSTLIB_I2C_REQ_ST { + u32 DeviceAddress; /* I2c device address */ + u32 WriteCount; /* number of bytes to write */ + u32 ReadCount; /* number of bytes to read */ + u8 Data[1]; +}; + +struct SMSHOSTLIB_I2C_RES_ST { + u32 Status; /* non-zero value in case of failure */ + u32 ReadCount; /* number of bytes read */ + u8 Data[1]; +}; + + +struct smscore_config_gpio { #define SMS_GPIO_DIRECTION_INPUT 0 #define SMS_GPIO_DIRECTION_OUTPUT 1 u8 direction; @@ -369,6 +575,47 @@ struct smscore_gpio_config { u8 outputdriving; }; +struct smscore_gpio_config { +#define SMS_GPIO_DIRECTION_INPUT 0 +#define SMS_GPIO_DIRECTION_OUTPUT 1 + u8 Direction; + +#define SMS_GPIO_PULL_UP_DOWN_NONE 0 +#define SMS_GPIO_PULL_UP_DOWN_PULLDOWN 1 +#define SMS_GPIO_PULL_UP_DOWN_PULLUP 2 +#define SMS_GPIO_PULL_UP_DOWN_KEEPER 3 + u8 PullUpDown; + +#define SMS_GPIO_INPUT_CHARACTERISTICS_NORMAL 0 +#define SMS_GPIO_INPUT_CHARACTERISTICS_SCHMITT 1 + u8 InputCharacteristics; + +#define SMS_GPIO_OUTPUT_SLEW_RATE_SLOW 1 /* 10xx */ +#define SMS_GPIO_OUTPUT_SLEW_RATE_FAST 0 /* 10xx */ + + +#define SMS_GPIO_OUTPUT_SLEW_RATE_0_45_V_NS 0 /* 11xx */ +#define SMS_GPIO_OUTPUT_SLEW_RATE_0_9_V_NS 1 /* 11xx */ +#define SMS_GPIO_OUTPUT_SLEW_RATE_1_7_V_NS 2 /* 11xx */ +#define SMS_GPIO_OUTPUT_SLEW_RATE_3_3_V_NS 3 /* 11xx */ + u8 OutputSlewRate; + +#define SMS_GPIO_OUTPUT_DRIVING_S_4mA 0 /* 10xx */ +#define SMS_GPIO_OUTPUT_DRIVING_S_8mA 1 /* 10xx */ +#define SMS_GPIO_OUTPUT_DRIVING_S_12mA 2 /* 10xx */ +#define SMS_GPIO_OUTPUT_DRIVING_S_16mA 3 /* 10xx */ + +#define SMS_GPIO_OUTPUT_DRIVING_1_5mA 0 /* 11xx */ +#define SMS_GPIO_OUTPUT_DRIVING_2_8mA 1 /* 11xx */ +#define SMS_GPIO_OUTPUT_DRIVING_4mA 2 /* 11xx */ +#define SMS_GPIO_OUTPUT_DRIVING_7mA 3 /* 11xx */ +#define SMS_GPIO_OUTPUT_DRIVING_10mA 4 /* 11xx */ +#define SMS_GPIO_OUTPUT_DRIVING_11mA 5 /* 11xx */ +#define SMS_GPIO_OUTPUT_DRIVING_14mA 6 /* 11xx */ +#define SMS_GPIO_OUTPUT_DRIVING_16mA 7 /* 11xx */ + u8 OutputDriving; +}; + extern void smscore_registry_setmode(char *devpath, int mode); extern int smscore_registry_getmode(char *devpath); @@ -410,10 +657,19 @@ 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); +/* old GPIO managment */ int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin, - struct smscore_gpio_config *pinconfig); + struct smscore_config_gpio *pinconfig); int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level); +/* new GPIO managment */ +extern int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum, + struct smscore_gpio_config *pGpioConfig); +extern int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum, + u8 NewLevel); +extern int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 PinNum, + u8 *level); + void smscore_set_board_id(struct smscore_device_t *core, int id); int smscore_get_board_id(struct smscore_device_t *core); @@ -442,4 +698,4 @@ int smscore_led_state(struct smscore_device_t *core, int led); dprintk(KERN_DEBUG, DBG_ADV, fmt, ##arg) -#endif /* __smscoreapi_h__ */ +#endif /* __SMS_CORE_API_H__ */ diff --git a/drivers/media/dvb/siano/smsdvb.c b/drivers/media/dvb/siano/smsdvb.c index ba080b95befb..3ee1c3902c56 100644 --- a/drivers/media/dvb/siano/smsdvb.c +++ b/drivers/media/dvb/siano/smsdvb.c @@ -1,28 +1,34 @@ -/* - * Driver for the Siano SMS1xxx USB dongle - * - * Author: Uri Shkolni - * - * 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 2 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. - */ +/**************************************************************** + +Siano Mobile Silicon, Inc. +MDTV receiver kernel modules. +Copyright (C) 2006-2008, Uri Shkolnik + +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, see . + +****************************************************************/ #include #include +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" + #include "smscoreapi.h" +#include "smsendian.h" #include "sms-cards.h" DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); @@ -39,12 +45,15 @@ struct smsdvb_client_t { struct dvb_frontend frontend; fe_status_t fe_status; - int fe_ber, fe_snr, fe_unc, fe_signal_strength; - struct completion tune_done, stat_done; + struct completion tune_done; /* todo: save freq/band instead whole struct */ struct dvb_frontend_parameters fe_params; + + struct SMSHOSTLIB_STATISTICS_DVB_S sms_stat_dvb; + int event_fe_state; + int event_unc_state; }; static struct list_head g_smsdvb_clients; @@ -54,11 +63,69 @@ static int sms_dbg; module_param_named(debug, sms_dbg, int, 0644); MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))"); +/* Events that may come from DVB v3 adapter */ +static void sms_board_dvb3_event(struct smsdvb_client_t *client, + enum SMS_DVB3_EVENTS event) { + + struct smscore_device_t *coredev = client->coredev; + switch (event) { + case DVB3_EVENT_INIT: + sms_debug("DVB3_EVENT_INIT"); + sms_board_event(coredev, BOARD_EVENT_BIND); + break; + case DVB3_EVENT_SLEEP: + sms_debug("DVB3_EVENT_SLEEP"); + sms_board_event(coredev, BOARD_EVENT_POWER_SUSPEND); + break; + case DVB3_EVENT_HOTPLUG: + sms_debug("DVB3_EVENT_HOTPLUG"); + sms_board_event(coredev, BOARD_EVENT_POWER_INIT); + break; + case DVB3_EVENT_FE_LOCK: + if (client->event_fe_state != DVB3_EVENT_FE_LOCK) { + client->event_fe_state = DVB3_EVENT_FE_LOCK; + sms_debug("DVB3_EVENT_FE_LOCK"); + sms_board_event(coredev, BOARD_EVENT_FE_LOCK); + } + break; + case DVB3_EVENT_FE_UNLOCK: + if (client->event_fe_state != DVB3_EVENT_FE_UNLOCK) { + client->event_fe_state = DVB3_EVENT_FE_UNLOCK; + sms_debug("DVB3_EVENT_FE_UNLOCK"); + sms_board_event(coredev, BOARD_EVENT_FE_UNLOCK); + } + break; + case DVB3_EVENT_UNC_OK: + if (client->event_unc_state != DVB3_EVENT_UNC_OK) { + client->event_unc_state = DVB3_EVENT_UNC_OK; + sms_debug("DVB3_EVENT_UNC_OK"); + sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_OK); + } + break; + case DVB3_EVENT_UNC_ERR: + if (client->event_unc_state != DVB3_EVENT_UNC_ERR) { + client->event_unc_state = DVB3_EVENT_UNC_ERR; + sms_debug("DVB3_EVENT_UNC_ERR"); + sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_ERRORS); + } + break; + + default: + sms_err("Unknown dvb3 api event"); + break; + } +} + 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); + struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) (((u8 *) cb->p) + + cb->offset); + u32 *pMsgData = (u32 *) phdr + 1; + /*u32 MsgDataLen = phdr->msgLength - sizeof(struct SmsMsgHdr_ST);*/ + bool is_status_update = false; + + smsendian_handle_rx_message((struct SmsMsgData_ST *) phdr); switch (phdr->msgType) { case MSG_SMS_DVBT_BDA_DATA: @@ -70,43 +137,110 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb) complete(&client->tune_done); break; - case MSG_SMS_GET_STATISTICS_RES: - { - struct SmsMsgStatisticsInfo_ST *p = - (struct SmsMsgStatisticsInfo_ST *)(phdr + 1); + case MSG_SMS_SIGNAL_DETECTED_IND: + sms_info("MSG_SMS_SIGNAL_DETECTED_IND"); + client->sms_stat_dvb.TransmissionData.IsDemodLocked = true; + is_status_update = true; + break; - if (p->Stat.IsDemodLocked) { - client->fe_status = FE_HAS_SIGNAL | - FE_HAS_CARRIER | - FE_HAS_VITERBI | - FE_HAS_SYNC | - FE_HAS_LOCK; + case MSG_SMS_NO_SIGNAL_IND: + sms_info("MSG_SMS_NO_SIGNAL_IND"); + client->sms_stat_dvb.TransmissionData.IsDemodLocked = false; + is_status_update = true; + break; - client->fe_snr = p->Stat.SNR; - client->fe_ber = p->Stat.BER; - client->fe_unc = p->Stat.BERErrorCount; + case MSG_SMS_TRANSMISSION_IND: { + sms_info("MSG_SMS_TRANSMISSION_IND"); - 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; + pMsgData++; + memcpy(&client->sms_stat_dvb.TransmissionData, pMsgData, + sizeof(struct TRANSMISSION_STATISTICS_S)); + + /* Mo need to correct guard interval + * (as opposed to old statistics message). + */ + CORRECT_STAT_BANDWIDTH(client->sms_stat_dvb.TransmissionData); + CORRECT_STAT_TRANSMISSON_MODE( + client->sms_stat_dvb.TransmissionData); + is_status_update = true; + break; + } + case MSG_SMS_HO_PER_SLICES_IND: { + struct RECEPTION_STATISTICS_S *pReceptionData = + &client->sms_stat_dvb.ReceptionData; + struct SRVM_SIGNAL_STATUS_S SignalStatusData; + + /*sms_info("MSG_SMS_HO_PER_SLICES_IND");*/ + pMsgData++; + SignalStatusData.result = pMsgData[0]; + SignalStatusData.snr = pMsgData[1]; + SignalStatusData.inBandPower = (s32) pMsgData[2]; + SignalStatusData.tsPackets = pMsgData[3]; + SignalStatusData.etsPackets = pMsgData[4]; + SignalStatusData.constellation = pMsgData[5]; + SignalStatusData.hpCode = pMsgData[6]; + SignalStatusData.tpsSrvIndLP = pMsgData[7] & 0x03; + SignalStatusData.tpsSrvIndHP = pMsgData[8] & 0x03; + SignalStatusData.cellId = pMsgData[9] & 0xFFFF; + SignalStatusData.reason = pMsgData[10]; + SignalStatusData.requestId = pMsgData[11]; + pReceptionData->IsRfLocked = pMsgData[16]; + pReceptionData->IsDemodLocked = pMsgData[17]; + pReceptionData->ModemState = pMsgData[12]; + pReceptionData->SNR = pMsgData[1]; + pReceptionData->BER = pMsgData[13]; + pReceptionData->RSSI = pMsgData[14]; + CORRECT_STAT_RSSI(client->sms_stat_dvb.ReceptionData); + + pReceptionData->InBandPwr = (s32) pMsgData[2]; + pReceptionData->CarrierOffset = (s32) pMsgData[15]; + pReceptionData->TotalTSPackets = pMsgData[3]; + pReceptionData->ErrorTSPackets = pMsgData[4]; + + /* TS PER */ + if ((SignalStatusData.tsPackets + SignalStatusData.etsPackets) + > 0) { + pReceptionData->TS_PER = (SignalStatusData.etsPackets + * 100) / (SignalStatusData.tsPackets + + SignalStatusData.etsPackets); } else { - client->fe_status = 0; - client->fe_snr = - client->fe_ber = - client->fe_unc = - client->fe_signal_strength = 0; + pReceptionData->TS_PER = 0; } - complete(&client->stat_done); - break; - } } + pReceptionData->BERBitCount = pMsgData[18]; + pReceptionData->BERErrorCount = pMsgData[19]; + pReceptionData->MRC_SNR = pMsgData[20]; + pReceptionData->MRC_InBandPwr = pMsgData[21]; + pReceptionData->MRC_RSSI = pMsgData[22]; + + is_status_update = true; + break; + } + } smscore_putbuffer(client->coredev, cb); + if (is_status_update) { + if (client->sms_stat_dvb.ReceptionData.IsDemodLocked) { + client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER + | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; + sms_board_dvb3_event(client, DVB3_EVENT_FE_LOCK); + if (client->sms_stat_dvb.ReceptionData.ErrorTSPackets + == 0) + sms_board_dvb3_event(client, DVB3_EVENT_UNC_OK); + else + sms_board_dvb3_event(client, + DVB3_EVENT_UNC_ERR); + + } else { + /*client->fe_status = + (phdr->msgType == MSG_SMS_NO_SIGNAL_IND) ? + 0 : FE_HAS_SIGNAL;*/ + client->fe_status = 0; + sms_board_dvb3_event(client, DVB3_EVENT_FE_UNLOCK); + } + } + return 0; } @@ -149,6 +283,7 @@ static int smsdvb_start_feed(struct dvb_demux_feed *feed) PidMsg.xMsgHeader.msgLength = sizeof(PidMsg); PidMsg.msgData[0] = feed->pid; + smsendian_handle_tx_message((struct SmsMsgHdr_ST *)&PidMsg); return smsclient_sendrequest(client->smsclient, &PidMsg, sizeof(PidMsg)); } @@ -169,6 +304,7 @@ static int smsdvb_stop_feed(struct dvb_demux_feed *feed) PidMsg.xMsgHeader.msgLength = sizeof(PidMsg); PidMsg.msgData[0] = feed->pid; + smsendian_handle_tx_message((struct SmsMsgHdr_ST *)&PidMsg); return smsclient_sendrequest(client->smsclient, &PidMsg, sizeof(PidMsg)); } @@ -177,7 +313,10 @@ 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); + int rc; + + smsendian_handle_tx_message((struct SmsMsgHdr_ST *)buffer); + rc = smsclient_sendrequest(client->smsclient, buffer, size); if (rc < 0) return rc; @@ -186,83 +325,61 @@ static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client, 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 }; - int ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), - &client->stat_done); - if (ret < 0) - return ret; - - if (client->fe_status & FE_HAS_LOCK) - sms_board_led_feedback(client->coredev, - (client->fe_unc == 0) ? - SMS_LED_HI : SMS_LED_LO); - else - sms_board_led_feedback(client->coredev, SMS_LED_OFF); - return ret; -} - 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); + struct smsdvb_client_t *client; + client = container_of(fe, struct smsdvb_client_t, frontend); - if (!rc) - *stat = client->fe_status; + *stat = client->fe_status; - return rc; + return 0; } 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); + struct smsdvb_client_t *client; + client = container_of(fe, struct smsdvb_client_t, frontend); - if (!rc) - *ber = client->fe_ber; + *ber = client->sms_stat_dvb.ReceptionData.BER; - return rc; + return 0; } 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); + struct smsdvb_client_t *client; + client = container_of(fe, struct smsdvb_client_t, frontend); - if (!rc) - *strength = client->fe_signal_strength; + if (client->sms_stat_dvb.ReceptionData.InBandPwr < -95) + *strength = 0; + else if (client->sms_stat_dvb.ReceptionData.InBandPwr > -29) + *strength = 100; + else + *strength = + (client->sms_stat_dvb.ReceptionData.InBandPwr + + 95) * 3 / 2; - return rc; + return 0; } 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); + struct smsdvb_client_t *client; + client = container_of(fe, struct smsdvb_client_t, frontend); - if (!rc) - *snr = client->fe_snr; + *snr = client->sms_stat_dvb.ReceptionData.SNR; - return rc; + return 0; } static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) { - struct smsdvb_client_t *client = - container_of(fe, struct smsdvb_client_t, frontend); - int rc = smsdvb_send_statistics_request(client); + struct smsdvb_client_t *client; + client = container_of(fe, struct smsdvb_client_t, frontend); - if (!rc) - *ucblocks = client->fe_unc; + *ucblocks = client->sms_stat_dvb.ReceptionData.ErrorTSPackets; - return rc; + return 0; } static int smsdvb_get_tune_settings(struct dvb_frontend *fe, @@ -286,12 +403,15 @@ static int smsdvb_set_frontend(struct dvb_frontend *fe, struct SmsMsgHdr_ST Msg; u32 Data[3]; } Msg; - int ret; - 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; + client->fe_status = FE_HAS_SIGNAL; + client->event_fe_state = -1; + client->event_unc_state = -1; + + 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; @@ -307,24 +427,6 @@ static int smsdvb_set_frontend(struct dvb_frontend *fe, default: return -EINVAL; } - /* Disable LNA, if any. An error is returned if no LNA is present */ - ret = sms_board_lna_control(client->coredev, 0); - if (ret == 0) { - fe_status_t status; - - /* tune with LNA off at first */ - ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), - &client->tune_done); - - smsdvb_read_status(fe, &status); - - if (status & FE_HAS_LOCK) - return ret; - - /* previous tune didnt lock - enable LNA and tune again */ - sms_board_lna_control(client->coredev, 1); - } - return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), &client->tune_done); } @@ -349,8 +451,7 @@ static int smsdvb_init(struct dvb_frontend *fe) struct smsdvb_client_t *client = container_of(fe, struct smsdvb_client_t, frontend); - sms_board_power(client->coredev, 1); - + sms_board_dvb3_event(client, DVB3_EVENT_INIT); return 0; } @@ -359,8 +460,7 @@ static int smsdvb_sleep(struct dvb_frontend *fe) struct smsdvb_client_t *client = container_of(fe, struct smsdvb_client_t, frontend); - sms_board_led_feedback(client->coredev, SMS_LED_OFF); - sms_board_power(client->coredev, 0); + sms_board_dvb3_event(client, DVB3_EVENT_SLEEP); return 0; } @@ -485,7 +585,6 @@ static int smsdvb_hotplug(struct smscore_device_t *coredev, client->coredev = coredev; init_completion(&client->tune_done); - init_completion(&client->stat_done); kmutex_lock(&g_smsdvb_clientslock); @@ -493,8 +592,11 @@ static int smsdvb_hotplug(struct smscore_device_t *coredev, kmutex_unlock(&g_smsdvb_clientslock); - sms_info("success"); + client->event_fe_state = -1; + client->event_unc_state = -1; + sms_board_dvb3_event(client, DVB3_EVENT_HOTPLUG); + sms_info("success"); sms_board_setup(coredev); return 0; @@ -547,5 +649,5 @@ module_init(smsdvb_module_init); module_exit(smsdvb_module_exit); MODULE_DESCRIPTION("SMS DVB subsystem adaptation module"); -MODULE_AUTHOR("Siano Mobile Silicon, INC. (uris@siano-ms.com)"); +MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/siano/smsendian.c b/drivers/media/dvb/siano/smsendian.c new file mode 100644 index 000000000000..457b6d02ef85 --- /dev/null +++ b/drivers/media/dvb/siano/smsendian.c @@ -0,0 +1,102 @@ +/**************************************************************** + + Siano Mobile Silicon, Inc. + MDTV receiver kernel modules. + Copyright (C) 2006-2009, Uri Shkolnik + + 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, see . + + ****************************************************************/ + +#include + +#include "smsendian.h" +#include "smscoreapi.h" + +void smsendian_handle_tx_message(void *buffer) +{ +#ifdef __BIG_ENDIAN + struct SmsMsgData_ST *msg = (struct SmsMsgData_ST *)buffer; + int i; + int msgWords; + + switch (msg->xMsgHeader.msgType) { + case MSG_SMS_DATA_DOWNLOAD_REQ: + { + msg->msgData[0] = le32_to_cpu(msg->msgData[0]); + break; + } + + default: + msgWords = (msg->xMsgHeader.msgLength - + sizeof(struct SmsMsgHdr_ST))/4; + + for (i = 0; i < msgWords; i++) + msg->msgData[i] = le32_to_cpu(msg->msgData[i]); + + break; + } +#endif /* __BIG_ENDIAN */ +} +EXPORT_SYMBOL_GPL(smsendian_handle_tx_message); + +void smsendian_handle_rx_message(void *buffer) +{ +#ifdef __BIG_ENDIAN + struct SmsMsgData_ST *msg = (struct SmsMsgData_ST *)buffer; + int i; + int msgWords; + + switch (msg->xMsgHeader.msgType) { + case MSG_SMS_GET_VERSION_EX_RES: + { + struct SmsVersionRes_ST *ver = + (struct SmsVersionRes_ST *) msg; + ver->ChipModel = le16_to_cpu(ver->ChipModel); + break; + } + + case MSG_SMS_DVBT_BDA_DATA: + case MSG_SMS_DAB_CHANNEL: + case MSG_SMS_DATA_MSG: + { + break; + } + + default: + { + msgWords = (msg->xMsgHeader.msgLength - + sizeof(struct SmsMsgHdr_ST))/4; + + for (i = 0; i < msgWords; i++) + msg->msgData[i] = le32_to_cpu(msg->msgData[i]); + + break; + } + } +#endif /* __BIG_ENDIAN */ +} +EXPORT_SYMBOL_GPL(smsendian_handle_rx_message); + +void smsendian_handle_message_header(void *msg) +{ +#ifdef __BIG_ENDIAN + struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *)msg; + + phdr->msgType = le16_to_cpu(phdr->msgType); + phdr->msgLength = le16_to_cpu(phdr->msgLength); + phdr->msgFlags = le16_to_cpu(phdr->msgFlags); +#endif /* __BIG_ENDIAN */ +} +EXPORT_SYMBOL_GPL(smsendian_handle_message_header); diff --git a/drivers/media/dvb/siano/smsendian.h b/drivers/media/dvb/siano/smsendian.h new file mode 100644 index 000000000000..1624d6fd367b --- /dev/null +++ b/drivers/media/dvb/siano/smsendian.h @@ -0,0 +1,32 @@ +/**************************************************************** + +Siano Mobile Silicon, Inc. +MDTV receiver kernel modules. +Copyright (C) 2006-2009, Uri Shkolnik + +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, see . + +****************************************************************/ + +#ifndef __SMS_ENDIAN_H__ +#define __SMS_ENDIAN_H__ + +#include + +extern void smsendian_handle_tx_message(void *buffer); +extern void smsendian_handle_rx_message(void *buffer); +extern void smsendian_handle_message_header(void *msg); + +#endif /* __SMS_ENDIAN_H__ */ + diff --git a/drivers/media/dvb/siano/smsir.c b/drivers/media/dvb/siano/smsir.c new file mode 100644 index 000000000000..e3d776feeaca --- /dev/null +++ b/drivers/media/dvb/siano/smsir.c @@ -0,0 +1,301 @@ +/**************************************************************** + + Siano Mobile Silicon, Inc. + MDTV receiver kernel modules. + Copyright (C) 2006-2009, Uri Shkolnik + + 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, see . + + ****************************************************************/ + + +#include +#include + +#include "smscoreapi.h" +#include "smsir.h" +#include "sms-cards.h" + +/* In order to add new IR remote control - + * 1) Add it to the @ smsir,h, + * 2) Add its map to keyboard_layout_maps below + * 3) Set your board (sms-cards sub-module) to use it + */ + +static struct keyboard_layout_map_t keyboard_layout_maps[] = { + [SMS_IR_KB_DEFAULT_TV] = { + .ir_protocol = IR_RC5, + .rc5_kbd_address = KEYBOARD_ADDRESS_TV1, + .keyboard_layout_map = { + KEY_0, KEY_1, KEY_2, + KEY_3, KEY_4, KEY_5, + KEY_6, KEY_7, KEY_8, + KEY_9, 0, 0, KEY_POWER, + KEY_MUTE, 0, 0, + KEY_VOLUMEUP, KEY_VOLUMEDOWN, + KEY_BRIGHTNESSUP, + KEY_BRIGHTNESSDOWN, KEY_CHANNELUP, + KEY_CHANNELDOWN, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + } + }, + [SMS_IR_KB_HCW_SILVER] = { + .ir_protocol = IR_RC5, + .rc5_kbd_address = KEYBOARD_ADDRESS_LIGHTING1, + .keyboard_layout_map = { + KEY_0, KEY_1, KEY_2, + KEY_3, KEY_4, KEY_5, + KEY_6, KEY_7, KEY_8, + KEY_9, KEY_TEXT, KEY_RED, + KEY_RADIO, KEY_MENU, + KEY_SUBTITLE, + KEY_MUTE, KEY_VOLUMEUP, + KEY_VOLUMEDOWN, KEY_PREVIOUS, 0, + KEY_UP, KEY_DOWN, KEY_LEFT, + KEY_RIGHT, KEY_VIDEO, KEY_AUDIO, + KEY_MHP, KEY_EPG, KEY_TV, + 0, KEY_NEXTSONG, KEY_EXIT, + KEY_CHANNELUP, KEY_CHANNELDOWN, + KEY_CHANNEL, 0, + KEY_PREVIOUSSONG, KEY_ENTER, + KEY_SLEEP, 0, 0, KEY_BLUE, + 0, 0, 0, 0, KEY_GREEN, 0, + KEY_PAUSE, 0, KEY_REWIND, + 0, KEY_FASTFORWARD, KEY_PLAY, + KEY_STOP, KEY_RECORD, + KEY_YELLOW, 0, 0, KEY_SELECT, + KEY_ZOOM, KEY_POWER, 0, 0 + } + }, + { } /* Terminating entry */ +}; + +u32 ir_pos; +u32 ir_word; +u32 ir_toggle; + +#define RC5_PUSH_BIT(dst, bit, pos) \ + { dst <<= 1; dst |= bit; pos++; } + + +static void sms_ir_rc5_event(struct smscore_device_t *coredev, + u32 toggle, u32 addr, u32 cmd) +{ + bool toggle_changed; + u16 keycode; + + sms_log("IR RC5 word: address %d, command %d, toggle %d", + addr, cmd, toggle); + + toggle_changed = ir_toggle != toggle; + /* keep toggle */ + ir_toggle = toggle; + + if (addr != + keyboard_layout_maps[coredev->ir.ir_kb_type].rc5_kbd_address) + return; /* Check for valid address */ + + keycode = + keyboard_layout_maps + [coredev->ir.ir_kb_type].keyboard_layout_map[cmd]; + + if (!toggle_changed && + (keycode != KEY_VOLUMEUP && keycode != KEY_VOLUMEDOWN)) + return; /* accept only repeated volume, reject other keys */ + + sms_log("kernel input keycode (from ir) %d", keycode); + input_report_key(coredev->ir.input_dev, keycode, 1); + input_sync(coredev->ir.input_dev); + +} + +/* decode raw bit pattern to RC5 code */ +/* taken from ir-functions.c */ +static u32 ir_rc5_decode(unsigned int code) +{ +/* unsigned int org_code = code;*/ + unsigned int pair; + unsigned int rc5 = 0; + int i; + + for (i = 0; i < 14; ++i) { + pair = code & 0x3; + code >>= 2; + + rc5 <<= 1; + switch (pair) { + case 0: + case 2: + break; + case 1: + rc5 |= 1; + break; + case 3: +/* dprintk(1, "ir-common: ir_rc5_decode(%x) bad code\n", org_code);*/ + sms_log("bad code"); + return 0; + } + } +/* + dprintk(1, "ir-common: code=%x, rc5=%x, start=%x, + toggle=%x, address=%x, " + "instr=%x\n", rc5, org_code, RC5_START(rc5), + RC5_TOGGLE(rc5), RC5_ADDR(rc5), RC5_INSTR(rc5)); +*/ + return rc5; +} + +static void sms_rc5_parse_word(struct smscore_device_t *coredev) +{ + #define RC5_START(x) (((x)>>12)&3) + #define RC5_TOGGLE(x) (((x)>>11)&1) + #define RC5_ADDR(x) (((x)>>6)&0x1F) + #define RC5_INSTR(x) ((x)&0x3F) + + int i, j; + u32 rc5_word = 0; + + /* Reverse the IR word direction */ + for (i = 0 ; i < 28 ; i++) + RC5_PUSH_BIT(rc5_word, (ir_word>>i)&1, j) + + rc5_word = ir_rc5_decode(rc5_word); + /* sms_log("temp = 0x%x, rc5_code = 0x%x", ir_word, rc5_word); */ + + sms_ir_rc5_event(coredev, + RC5_TOGGLE(rc5_word), + RC5_ADDR(rc5_word), + RC5_INSTR(rc5_word)); +} + + +static void sms_rc5_accumulate_bits(struct smscore_device_t *coredev, + s32 ir_sample) +{ + #define RC5_TIME_GRANULARITY 200 + #define RC5_DEF_BIT_TIME 889 + #define RC5_MAX_SAME_BIT_CONT 4 + #define RC5_WORD_LEN 27 /* 28 bit */ + + u32 i, j; + s32 delta_time; + u32 time = (ir_sample > 0) ? ir_sample : (0-ir_sample); + u32 level = (ir_sample < 0) ? 0 : 1; + + for (i = RC5_MAX_SAME_BIT_CONT; i > 0; i--) { + delta_time = time - (i*RC5_DEF_BIT_TIME) + RC5_TIME_GRANULARITY; + if (delta_time < 0) + continue; /* not so many consecutive bits */ + if (delta_time > (2 * RC5_TIME_GRANULARITY)) { + /* timeout */ + if (ir_pos == (RC5_WORD_LEN-1)) + /* complete last bit */ + RC5_PUSH_BIT(ir_word, level, ir_pos) + + if (ir_pos == RC5_WORD_LEN) + sms_rc5_parse_word(coredev); + else if (ir_pos) /* timeout within a word */ + sms_log("IR error parsing a word"); + + ir_pos = 0; + ir_word = 0; + /* sms_log("timeout %d", time); */ + break; + } + /* The time is within the range of this number of bits */ + for (j = 0 ; j < i ; j++) + RC5_PUSH_BIT(ir_word, level, ir_pos) + + break; + } +} + +void sms_ir_event(struct smscore_device_t *coredev, const char *buf, int len) +{ + #define IR_DATA_RECEIVE_MAX_LEN 520 /* 128*4 + 4 + 4 */ + u32 i; + enum ir_protocol ir_protocol = + keyboard_layout_maps[coredev->ir.ir_kb_type] + .ir_protocol; + s32 *samples; + int count = len>>2; + + samples = (s32 *)buf; +/* sms_log("IR buffer received, length = %d", count);*/ + + for (i = 0; i < count; i++) + if (ir_protocol == IR_RC5) + sms_rc5_accumulate_bits(coredev, samples[i]); + /* IR_RCMM not implemented */ +} + +int sms_ir_init(struct smscore_device_t *coredev) +{ + struct input_dev *input_dev; + + sms_log("Allocating input device"); + input_dev = input_allocate_device(); + if (!input_dev) { + sms_err("Not enough memory"); + return -ENOMEM; + } + + coredev->ir.input_dev = input_dev; + coredev->ir.ir_kb_type = + sms_get_board(smscore_get_board_id(coredev))->ir_kb_type; + coredev->ir.keyboard_layout_map = + keyboard_layout_maps[coredev->ir.ir_kb_type]. + keyboard_layout_map; + sms_log("IR remote keyboard type is %d", coredev->ir.ir_kb_type); + + coredev->ir.controller = 0; /* Todo: vega/nova SPI number */ + coredev->ir.timeout = IR_DEFAULT_TIMEOUT; + sms_log("IR port %d, timeout %d ms", + coredev->ir.controller, coredev->ir.timeout); + + snprintf(coredev->ir.name, + IR_DEV_NAME_MAX_LEN, + "SMS IR w/kbd type %d", + coredev->ir.ir_kb_type); + input_dev->name = coredev->ir.name; + input_dev->phys = coredev->ir.name; + input_dev->dev.parent = coredev->device; + + /* Key press events only */ + input_dev->evbit[0] = BIT_MASK(EV_KEY); + input_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0); + + sms_log("Input device (IR) %s is set for key events", input_dev->name); + + if (input_register_device(input_dev)) { + sms_err("Failed to register device"); + input_free_device(input_dev); + return -EACCES; + } + + return 0; +} + +void sms_ir_exit(struct smscore_device_t *coredev) +{ + if (coredev->ir.input_dev) + input_unregister_device(coredev->ir.input_dev); + + sms_log(""); +} + diff --git a/drivers/media/dvb/siano/smsir.h b/drivers/media/dvb/siano/smsir.h new file mode 100644 index 000000000000..b7d703e2d338 --- /dev/null +++ b/drivers/media/dvb/siano/smsir.h @@ -0,0 +1,93 @@ +/**************************************************************** + +Siano Mobile Silicon, Inc. +MDTV receiver kernel modules. +Copyright (C) 2006-2009, Uri Shkolnik + +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, see . + +****************************************************************/ + +#ifndef __SMS_IR_H__ +#define __SMS_IR_H__ + +#include + +#define IR_DEV_NAME_MAX_LEN 23 /* "SMS IR kbd type nn\0" */ +#define IR_KEYBOARD_LAYOUT_SIZE 64 +#define IR_DEFAULT_TIMEOUT 100 + +enum ir_kb_type { + SMS_IR_KB_DEFAULT_TV, + SMS_IR_KB_HCW_SILVER +}; + +enum rc5_keyboard_address { + KEYBOARD_ADDRESS_TV1 = 0, + KEYBOARD_ADDRESS_TV2 = 1, + KEYBOARD_ADDRESS_TELETEXT = 2, + KEYBOARD_ADDRESS_VIDEO = 3, + KEYBOARD_ADDRESS_LV1 = 4, + KEYBOARD_ADDRESS_VCR1 = 5, + KEYBOARD_ADDRESS_VCR2 = 6, + KEYBOARD_ADDRESS_EXPERIMENTAL = 7, + KEYBOARD_ADDRESS_SAT1 = 8, + KEYBOARD_ADDRESS_CAMERA = 9, + KEYBOARD_ADDRESS_SAT2 = 10, + KEYBOARD_ADDRESS_CDV = 12, + KEYBOARD_ADDRESS_CAMCORDER = 13, + KEYBOARD_ADDRESS_PRE_AMP = 16, + KEYBOARD_ADDRESS_TUNER = 17, + KEYBOARD_ADDRESS_RECORDER1 = 18, + KEYBOARD_ADDRESS_PRE_AMP1 = 19, + KEYBOARD_ADDRESS_CD_PLAYER = 20, + KEYBOARD_ADDRESS_PHONO = 21, + KEYBOARD_ADDRESS_SATA = 22, + KEYBOARD_ADDRESS_RECORDER2 = 23, + KEYBOARD_ADDRESS_CDR = 26, + KEYBOARD_ADDRESS_LIGHTING = 29, + KEYBOARD_ADDRESS_LIGHTING1 = 30, /* KEYBOARD_ADDRESS_HCW_SILVER */ + KEYBOARD_ADDRESS_PHONE = 31, + KEYBOARD_ADDRESS_NOT_RC5 = 0xFFFF +}; + +enum ir_protocol { + IR_RC5, + IR_RCMM +}; + +struct keyboard_layout_map_t { + enum ir_protocol ir_protocol; + enum rc5_keyboard_address rc5_kbd_address; + u16 keyboard_layout_map[IR_KEYBOARD_LAYOUT_SIZE]; +}; + +struct smscore_device_t; + +struct ir_t { + struct input_dev *input_dev; + enum ir_kb_type ir_kb_type; + char name[IR_DEV_NAME_MAX_LEN+1]; + u16 *keyboard_layout_map; + u32 timeout; + u32 controller; +}; + +int sms_ir_init(struct smscore_device_t *coredev); +void sms_ir_exit(struct smscore_device_t *coredev); +void sms_ir_event(struct smscore_device_t *coredev, + const char *buf, int len); + +#endif /* __SMS_IR_H__ */ + diff --git a/drivers/media/dvb/siano/smssdio.c b/drivers/media/dvb/siano/smssdio.c new file mode 100644 index 000000000000..dfaa49a53f32 --- /dev/null +++ b/drivers/media/dvb/siano/smssdio.c @@ -0,0 +1,357 @@ +/* + * smssdio.c - Siano 1xxx SDIO interface driver + * + * Copyright 2008 Pierre Ossman + * + * Based on code by Siano Mobile Silicon, Inc., + * Copyright (C) 2006-2008, Uri Shkolnik + * + * 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 hardware is a bit odd in that all transfers should be done + * to/from the SMSSDIO_DATA register, yet the "increase address" bit + * always needs to be set. + * + * Also, buffers from the card are always aligned to 128 byte + * boundaries. + */ + +/* + * General cleanup notes: + * + * - only typedefs should be name *_t + * + * - use ERR_PTR and friends for smscore_register_device() + * + * - smscore_getbuffer should zero fields + * + * Fix stop command + */ + +#include +#include +#include +#include +#include +#include + +#include "smscoreapi.h" +#include "sms-cards.h" + +/* Registers */ + +#define SMSSDIO_DATA 0x00 +#define SMSSDIO_INT 0x04 + +static const struct sdio_device_id smssdio_ids[] = { + {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_STELLAR), + .driver_data = SMS1XXX_BOARD_SIANO_STELLAR}, + {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_NOVA_A0), + .driver_data = SMS1XXX_BOARD_SIANO_NOVA_A}, + {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_NOVA_B0), + .driver_data = SMS1XXX_BOARD_SIANO_NOVA_B}, + {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_VEGA_A0), + .driver_data = SMS1XXX_BOARD_SIANO_VEGA}, + {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_VENICE), + .driver_data = SMS1XXX_BOARD_SIANO_VEGA}, + { /* end: all zeroes */ }, +}; + +MODULE_DEVICE_TABLE(sdio, smssdio_ids); + +struct smssdio_device { + struct sdio_func *func; + + struct smscore_device_t *coredev; + + struct smscore_buffer_t *split_cb; +}; + +/*******************************************************************/ +/* Siano core callbacks */ +/*******************************************************************/ + +static int smssdio_sendrequest(void *context, void *buffer, size_t size) +{ + int ret; + struct smssdio_device *smsdev; + + smsdev = context; + + sdio_claim_host(smsdev->func); + + while (size >= smsdev->func->cur_blksize) { + ret = sdio_write_blocks(smsdev->func, SMSSDIO_DATA, buffer, 1); + if (ret) + goto out; + + buffer += smsdev->func->cur_blksize; + size -= smsdev->func->cur_blksize; + } + + if (size) { + ret = sdio_write_bytes(smsdev->func, SMSSDIO_DATA, + buffer, size); + } + +out: + sdio_release_host(smsdev->func); + + return ret; +} + +/*******************************************************************/ +/* SDIO callbacks */ +/*******************************************************************/ + +static void smssdio_interrupt(struct sdio_func *func) +{ + int ret, isr; + + struct smssdio_device *smsdev; + struct smscore_buffer_t *cb; + struct SmsMsgHdr_ST *hdr; + size_t size; + + smsdev = sdio_get_drvdata(func); + + /* + * The interrupt register has no defined meaning. It is just + * a way of turning of the level triggered interrupt. + */ + isr = sdio_readb(func, SMSSDIO_INT, &ret); + if (ret) { + dev_err(&smsdev->func->dev, + "Unable to read interrupt register!\n"); + return; + } + + if (smsdev->split_cb == NULL) { + cb = smscore_getbuffer(smsdev->coredev); + if (!cb) { + dev_err(&smsdev->func->dev, + "Unable to allocate data buffer!\n"); + return; + } + + ret = sdio_read_blocks(smsdev->func, cb->p, SMSSDIO_DATA, 1); + if (ret) { + dev_err(&smsdev->func->dev, + "Error %d reading initial block!\n", ret); + return; + } + + hdr = cb->p; + + if (hdr->msgFlags & MSG_HDR_FLAG_SPLIT_MSG) { + smsdev->split_cb = cb; + return; + } + + size = hdr->msgLength - smsdev->func->cur_blksize; + } else { + cb = smsdev->split_cb; + hdr = cb->p; + + size = hdr->msgLength - sizeof(struct SmsMsgHdr_ST); + + smsdev->split_cb = NULL; + } + + if (hdr->msgLength > smsdev->func->cur_blksize) { + void *buffer; + + size = ALIGN(size, 128); + buffer = cb->p + hdr->msgLength; + + BUG_ON(smsdev->func->cur_blksize != 128); + + /* + * First attempt to transfer all of it in one go... + */ + ret = sdio_read_blocks(smsdev->func, buffer, + SMSSDIO_DATA, size / 128); + if (ret && ret != -EINVAL) { + smscore_putbuffer(smsdev->coredev, cb); + dev_err(&smsdev->func->dev, + "Error %d reading data from card!\n", ret); + return; + } + + /* + * ..then fall back to one block at a time if that is + * not possible... + * + * (we have to do this manually because of the + * problem with the "increase address" bit) + */ + if (ret == -EINVAL) { + while (size) { + ret = sdio_read_blocks(smsdev->func, + buffer, SMSSDIO_DATA, 1); + if (ret) { + smscore_putbuffer(smsdev->coredev, cb); + dev_err(&smsdev->func->dev, + "Error %d reading " + "data from card!\n", ret); + return; + } + + buffer += smsdev->func->cur_blksize; + if (size > smsdev->func->cur_blksize) + size -= smsdev->func->cur_blksize; + else + size = 0; + } + } + } + + cb->size = hdr->msgLength; + cb->offset = 0; + + smscore_onresponse(smsdev->coredev, cb); +} + +static int smssdio_probe(struct sdio_func *func, + const struct sdio_device_id *id) +{ + int ret; + + int board_id; + struct smssdio_device *smsdev; + struct smsdevice_params_t params; + + board_id = id->driver_data; + + smsdev = kzalloc(sizeof(struct smssdio_device), GFP_KERNEL); + if (!smsdev) + return -ENOMEM; + + smsdev->func = func; + + memset(¶ms, 0, sizeof(struct smsdevice_params_t)); + + params.device = &func->dev; + params.buffer_size = 0x5000; /* ?? */ + params.num_buffers = 22; /* ?? */ + params.context = smsdev; + + snprintf(params.devpath, sizeof(params.devpath), + "sdio\\%s", sdio_func_id(func)); + + params.sendrequest_handler = smssdio_sendrequest; + + params.device_type = sms_get_board(board_id)->type; + + if (params.device_type != SMS_STELLAR) + params.flags |= SMS_DEVICE_FAMILY2; + else { + /* + * FIXME: Stellar needs special handling... + */ + ret = -ENODEV; + goto free; + } + + ret = smscore_register_device(¶ms, &smsdev->coredev); + if (ret < 0) + goto free; + + smscore_set_board_id(smsdev->coredev, board_id); + + sdio_claim_host(func); + + ret = sdio_enable_func(func); + if (ret) + goto release; + + ret = sdio_set_block_size(func, 128); + if (ret) + goto disable; + + ret = sdio_claim_irq(func, smssdio_interrupt); + if (ret) + goto disable; + + sdio_set_drvdata(func, smsdev); + + sdio_release_host(func); + + ret = smscore_start_device(smsdev->coredev); + if (ret < 0) + goto reclaim; + + return 0; + +reclaim: + sdio_claim_host(func); + sdio_release_irq(func); +disable: + sdio_disable_func(func); +release: + sdio_release_host(func); + smscore_unregister_device(smsdev->coredev); +free: + kfree(smsdev); + + return ret; +} + +static void smssdio_remove(struct sdio_func *func) +{ + struct smssdio_device *smsdev; + + smsdev = sdio_get_drvdata(func); + + /* FIXME: racy! */ + if (smsdev->split_cb) + smscore_putbuffer(smsdev->coredev, smsdev->split_cb); + + smscore_unregister_device(smsdev->coredev); + + sdio_claim_host(func); + sdio_release_irq(func); + sdio_disable_func(func); + sdio_release_host(func); + + kfree(smsdev); +} + +static struct sdio_driver smssdio_driver = { + .name = "smssdio", + .id_table = smssdio_ids, + .probe = smssdio_probe, + .remove = smssdio_remove, +}; + +/*******************************************************************/ +/* Module functions */ +/*******************************************************************/ + +int smssdio_module_init(void) +{ + int ret = 0; + + printk(KERN_INFO "smssdio: Siano SMS1xxx SDIO driver\n"); + printk(KERN_INFO "smssdio: Copyright Pierre Ossman\n"); + + ret = sdio_register_driver(&smssdio_driver); + + return ret; +} + +void smssdio_module_exit(void) +{ + sdio_unregister_driver(&smssdio_driver); +} + +module_init(smssdio_module_init); +module_exit(smssdio_module_exit); + +MODULE_DESCRIPTION("Siano SMS1xxx SDIO driver"); +MODULE_AUTHOR("Pierre Ossman"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/siano/smsusb.c b/drivers/media/dvb/siano/smsusb.c index 71c65f544c07..cb8a358b7310 100644 --- a/drivers/media/dvb/siano/smsusb.c +++ b/drivers/media/dvb/siano/smsusb.c @@ -1,23 +1,23 @@ -/* - * 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 2 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. - */ +/**************************************************************** + +Siano Mobile Silicon, Inc. +MDTV receiver kernel modules. +Copyright (C) 2005-2009, Uri Shkolnik, Anatoly Greenblat + +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, see . + +****************************************************************/ #include #include @@ -26,6 +26,7 @@ #include "smscoreapi.h" #include "sms-cards.h" +#include "smsendian.h" static int sms_dbg; module_param_named(debug, sms_dbg, int, 0644); @@ -64,15 +65,16 @@ 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", + if (urb->status == -ESHUTDOWN) { + sms_err("error, urb status %d (-ESHUTDOWN), %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 > 0) && (urb->status == 0)) { + struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *)surb->cb->p; + smsendian_handle_message_header(phdr); if (urb->actual_length >= phdr->msgLength) { surb->cb->size = phdr->msgLength; @@ -109,7 +111,10 @@ static void smsusb_onresponse(struct urb *urb) "msglen %d actual %d", phdr->msgLength, urb->actual_length); } - } + } else + sms_err("error, urb status %d, %d bytes", + urb->status, urb->actual_length); + exit_and_resubmit: smsusb_submit_urb(dev, surb); @@ -176,6 +181,7 @@ static int smsusb_sendrequest(void *context, void *buffer, size_t size) struct smsusb_device_t *dev = (struct smsusb_device_t *) context; int dummy; + smsendian_handle_message_header((struct SmsMsgHdr_ST *)buffer); return usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 2), buffer, size, &dummy, 1000); } @@ -333,8 +339,8 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id) case SMS_VEGA: dev->buffer_size = USB2_BUFFER_SIZE; dev->response_alignment = - dev->udev->ep_in[1]->desc.wMaxPacketSize - - sizeof(struct SmsMsgHdr_ST); + le16_to_cpu(dev->udev->ep_in[1]->desc.wMaxPacketSize) - + sizeof(struct SmsMsgHdr_ST); params.flags |= SMS_DEVICE_FAMILY2; break; @@ -479,7 +485,6 @@ static int smsusb_resume(struct usb_interface *intf) } 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), @@ -490,7 +495,6 @@ struct usb_device_id smsusb_id_table[] = { .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), @@ -521,8 +525,13 @@ struct usb_device_id smsusb_id_table[] = { .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, { USB_DEVICE(0x2040, 0x5590), .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, - { } /* Terminating entry */ -}; + { USB_DEVICE(0x187f, 0x0202), + .driver_info = SMS1XXX_BOARD_SIANO_NICE }, + { USB_DEVICE(0x187f, 0x0301), + .driver_info = SMS1XXX_BOARD_SIANO_VENICE }, + { } /* Terminating entry */ + }; + MODULE_DEVICE_TABLE(usb, smsusb_id_table); static struct usb_driver smsusb_driver = { @@ -548,14 +557,14 @@ int smsusb_module_init(void) void smsusb_module_exit(void) { - sms_debug(""); /* Regular USB Cleanup */ usb_deregister(&smsusb_driver); + sms_info("end"); } module_init(smsusb_module_init); module_exit(smsusb_module_exit); -MODULE_DESCRIPTION("Driver for the Siano SMS1XXX USB dongle"); +MODULE_DESCRIPTION("Driver for the Siano SMS1xxx USB dongle"); MODULE_AUTHOR("Siano Mobile Silicon, INC. (uris@siano-ms.com)"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c index e4d0900d5121..53884814161c 100644 --- a/drivers/media/dvb/ttpci/av7110_av.c +++ b/drivers/media/dvb/ttpci/av7110_av.c @@ -89,6 +89,7 @@ static void p_to_t(u8 const *buf, long int length, u16 pid, u8 *counter, struct dvb_demux_feed *feed); +static int write_ts_to_decoder(struct av7110 *av7110, int type, const u8 *buf, size_t len); int av7110_record_cb(struct dvb_filter_pes2ts *p2t, u8 *buf, size_t len) @@ -192,8 +193,6 @@ int av7110_av_start_play(struct av7110 *av7110, int av) ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AV_PES, 0); break; } - if (!ret) - ret = av7110->playing; return ret; } @@ -437,6 +436,45 @@ static void play_audio_cb(u8 *buf, int count, void *priv) aux_ring_buffer_write(&av7110->aout, buf, count); } + +#define FREE_COND_TS (dvb_ringbuffer_free(rb) >= 4096) + +static ssize_t ts_play(struct av7110 *av7110, const char __user *buf, + unsigned long count, int nonblock, int type) +{ + struct dvb_ringbuffer *rb; + u8 *kb; + unsigned long todo = count; + + dprintk(2, "%s: type %d cnt %lu\n", __func__, type, count); + + rb = (type) ? &av7110->avout : &av7110->aout; + kb = av7110->kbuf[type]; + + if (!kb) + return -ENOBUFS; + + if (nonblock && !FREE_COND_TS) + return -EWOULDBLOCK; + + while (todo >= TS_SIZE) { + if (!FREE_COND_TS) { + if (nonblock) + return count - todo; + if (wait_event_interruptible(rb->queue, FREE_COND_TS)) + return count - todo; + } + if (copy_from_user(kb, buf, TS_SIZE)) + return -EFAULT; + write_ts_to_decoder(av7110, type, kb, TS_SIZE); + todo -= TS_SIZE; + buf += TS_SIZE; + } + + return count - todo; +} + + #define FREE_COND (dvb_ringbuffer_free(&av7110->avout) >= 20 * 1024 && \ dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024) @@ -780,11 +818,37 @@ static void p_to_t(u8 const *buf, long int length, u16 pid, u8 *counter, } +static int write_ts_to_decoder(struct av7110 *av7110, int type, const u8 *buf, size_t len) +{ + struct ipack *ipack = &av7110->ipack[type]; + + if (buf[1] & TRANS_ERROR) { + av7110_ipack_reset(ipack); + return -1; + } + + if (!(buf[3] & PAYLOAD)) + return -1; + + if (buf[1] & PAY_START) + av7110_ipack_flush(ipack); + + if (buf[3] & ADAPT_FIELD) { + len -= buf[4] + 1; + buf += buf[4] + 1; + if (!len) + return 0; + } + + av7110_ipack_instant_repack(buf + 4, len - 4, ipack); + return 0; +} + + int av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t len) { struct dvb_demux *demux = feed->demux; struct av7110 *av7110 = (struct av7110 *) demux->priv; - struct ipack *ipack = &av7110->ipack[feed->pes_type]; dprintk(2, "av7110:%p, \n", av7110); @@ -804,20 +868,7 @@ int av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t l return -1; } - if (!(buf[3] & 0x10)) /* no payload? */ - return -1; - if (buf[1] & 0x40) - av7110_ipack_flush(ipack); - - if (buf[3] & 0x20) { /* adaptation field? */ - len -= buf[4] + 1; - buf += buf[4] + 1; - if (!len) - return 0; - } - - av7110_ipack_instant_repack(buf + 4, len - 4, &av7110->ipack[feed->pes_type]); - return 0; + return write_ts_to_decoder(av7110, feed->pes_type, buf, len); } @@ -916,6 +967,7 @@ static ssize_t dvb_video_write(struct file *file, const char __user *buf, { struct dvb_device *dvbdev = file->private_data; struct av7110 *av7110 = dvbdev->priv; + unsigned char c; dprintk(2, "av7110:%p, \n", av7110); @@ -925,7 +977,12 @@ static ssize_t dvb_video_write(struct file *file, const char __user *buf, if (av7110->videostate.stream_source != VIDEO_SOURCE_MEMORY) return -EPERM; - return dvb_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 1); + if (get_user(c, buf)) + return -EFAULT; + if (c == 0x47 && count % TS_SIZE == 0) + return ts_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 1); + else + return dvb_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 1); } static unsigned int dvb_audio_poll(struct file *file, poll_table *wait) @@ -952,6 +1009,7 @@ static ssize_t dvb_audio_write(struct file *file, const char __user *buf, { struct dvb_device *dvbdev = file->private_data; struct av7110 *av7110 = dvbdev->priv; + unsigned char c; dprintk(2, "av7110:%p, \n", av7110); @@ -959,7 +1017,13 @@ static ssize_t dvb_audio_write(struct file *file, const char __user *buf, printk(KERN_ERR "not audio source memory\n"); return -EPERM; } - return dvb_aplay(av7110, buf, count, file->f_flags & O_NONBLOCK, 0); + + if (get_user(c, buf)) + return -EFAULT; + if (c == 0x47 && count % TS_SIZE == 0) + return ts_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 0); + else + return dvb_aplay(av7110, buf, count, file->f_flags & O_NONBLOCK, 0); } static u8 iframe_header[] = { 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x80, 0x00, 0x00 }; @@ -1062,7 +1126,6 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file, if (ret) break; } - if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY) { if (av7110->playing == RP_AV) { ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0); @@ -1122,20 +1185,16 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file, case VIDEO_SET_DISPLAY_FORMAT: { video_displayformat_t format = (video_displayformat_t) arg; - switch (format) { case VIDEO_PAN_SCAN: av7110->display_panscan = VID_PAN_SCAN_PREF; break; - case VIDEO_LETTER_BOX: av7110->display_panscan = VID_VC_AND_PS_PREF; break; - case VIDEO_CENTER_CUT_OUT: av7110->display_panscan = VID_CENTRE_CUT_PREF; break; - default: ret = -EINVAL; } @@ -1183,7 +1242,8 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file, case VIDEO_SLOWMOTION: if (av7110->playing&RP_VIDEO) { - ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Slow, 2, 0, 0); + if (av7110->trickmode != TRICK_SLOW) + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Slow, 2, 0, 0); if (!ret) ret = vidcom(av7110, AV_VIDEO_CMD_SLOW, arg); } else { @@ -1207,7 +1267,6 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file, case VIDEO_CLEAR_BUFFER: dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout); av7110_ipack_reset(&av7110->ipack[1]); - if (av7110->playing == RP_AV) { ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AV_PES, 0); @@ -1228,13 +1287,13 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file, break; case VIDEO_SET_STREAMTYPE: - break; default: ret = -ENOIOCTLCMD; break; } + return ret; } @@ -1309,7 +1368,6 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file, case AUDIO_CHANNEL_SELECT: av7110->audiostate.channel_select = (audio_channel_select_t) arg; - switch(av7110->audiostate.channel_select) { case AUDIO_STEREO: ret = audcom(av7110, AUDIO_CMD_STEREO); @@ -1320,7 +1378,6 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file, msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0220); } break; - case AUDIO_MONO_LEFT: ret = audcom(av7110, AUDIO_CMD_MONO_L); if (!ret) { @@ -1330,7 +1387,6 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file, msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0200); } break; - case AUDIO_MONO_RIGHT: ret = audcom(av7110, AUDIO_CMD_MONO_R); if (!ret) { @@ -1340,7 +1396,6 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file, msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0210); } break; - default: ret = -EINVAL; break; @@ -1366,21 +1421,24 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file, ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AV_PES, 0); break; - case AUDIO_SET_ID: + case AUDIO_SET_ID: break; + case AUDIO_SET_MIXER: { struct audio_mixer *amix = (struct audio_mixer *)parg; - ret = av7110_set_volume(av7110, amix->volume_left, amix->volume_right); break; } + case AUDIO_SET_STREAMTYPE: break; + default: ret = -ENOIOCTLCMD; } + return ret; } diff --git a/drivers/media/dvb/ttpci/av7110_hw.c b/drivers/media/dvb/ttpci/av7110_hw.c index 5e3f88911a1d..e162691b515d 100644 --- a/drivers/media/dvb/ttpci/av7110_hw.c +++ b/drivers/media/dvb/ttpci/av7110_hw.c @@ -1089,7 +1089,7 @@ int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc) else { int i, len = dc->x0-dc->color+1; u8 __user *colors = (u8 __user *)dc->data; - u8 r, g, b, blend; + u8 r, g = 0, b = 0, blend = 0; ret = 0; for (i = 0; iindex); if (av7110->analog_tuner_flags) { - if (i->index < 0 || i->index >= 4) + if (i->index >= 4) return -EINVAL; } else { if (i->index != 0) diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c index 855fe74b640b..8ea915227674 100644 --- a/drivers/media/dvb/ttpci/budget-av.c +++ b/drivers/media/dvb/ttpci/budget-av.c @@ -1413,7 +1413,7 @@ static struct v4l2_input knc1_inputs[KNC1_INPUTS] = { static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i) { dprintk(1, "VIDIOC_ENUMINPUT %d.\n", i->index); - if (i->index < 0 || i->index >= KNC1_INPUTS) + if (i->index >= KNC1_INPUTS) return -EINVAL; memcpy(i, &knc1_inputs[i->index], sizeof(struct v4l2_input)); return 0; diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c index 83e9e7750c8c..e48380c48990 100644 --- a/drivers/media/dvb/ttpci/budget.c +++ b/drivers/media/dvb/ttpci/budget.c @@ -47,6 +47,9 @@ #include "bsru6.h" #include "bsbe1.h" #include "tdhd1.h" +#include "stv6110x.h" +#include "stv090x.h" +#include "isl6423.h" static int diseqc_method; module_param(diseqc_method, int, 0444); @@ -425,6 +428,44 @@ static u8 read_pwm(struct budget* budget) return pwm; } +static struct stv090x_config tt1600_stv090x_config = { + .device = STV0903, + .demod_mode = STV090x_SINGLE, + .clk_mode = STV090x_CLK_EXT, + + .xtal = 27000000, + .address = 0x68, + .ref_clk = 27000000, + + .ts1_mode = STV090x_TSMODE_DVBCI, + .ts2_mode = STV090x_TSMODE_SERIAL_CONTINUOUS, + + .repeater_level = STV090x_RPTLEVEL_16, + + .tuner_init = NULL, + .tuner_set_mode = NULL, + .tuner_set_frequency = NULL, + .tuner_get_frequency = NULL, + .tuner_set_bandwidth = NULL, + .tuner_get_bandwidth = NULL, + .tuner_set_bbgain = NULL, + .tuner_get_bbgain = NULL, + .tuner_set_refclk = NULL, + .tuner_get_status = NULL, +}; + +static struct stv6110x_config tt1600_stv6110x_config = { + .addr = 0x60, + .refclk = 27000000, +}; + +static struct isl6423_config tt1600_isl6423_config = { + .current_max = SEC_CURRENT_515m, + .curlim = SEC_CURRENT_LIM_ON, + .mod_extern = 1, + .addr = 0x08, +}; + static void frontend_init(struct budget *budget) { (void)alps_bsbe1_config; /* avoid warning */ @@ -566,6 +607,48 @@ static void frontend_init(struct budget *budget) } break; } + + case 0x101c: { /* TT S2-1600 */ + struct stv6110x_devctl *ctl; + saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTLO); + msleep(50); + saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTHI); + msleep(250); + + budget->dvb_frontend = dvb_attach(stv090x_attach, + &tt1600_stv090x_config, + &budget->i2c_adap, + STV090x_DEMODULATOR_0); + + if (budget->dvb_frontend) { + + ctl = dvb_attach(stv6110x_attach, + budget->dvb_frontend, + &tt1600_stv6110x_config, + &budget->i2c_adap); + + tt1600_stv090x_config.tuner_init = ctl->tuner_init; + tt1600_stv090x_config.tuner_set_mode = ctl->tuner_set_mode; + tt1600_stv090x_config.tuner_set_frequency = ctl->tuner_set_frequency; + tt1600_stv090x_config.tuner_get_frequency = ctl->tuner_get_frequency; + tt1600_stv090x_config.tuner_set_bandwidth = ctl->tuner_set_bandwidth; + tt1600_stv090x_config.tuner_get_bandwidth = ctl->tuner_get_bandwidth; + tt1600_stv090x_config.tuner_set_bbgain = ctl->tuner_set_bbgain; + tt1600_stv090x_config.tuner_get_bbgain = ctl->tuner_get_bbgain; + tt1600_stv090x_config.tuner_set_refclk = ctl->tuner_set_refclk; + tt1600_stv090x_config.tuner_get_status = ctl->tuner_get_status; + + dvb_attach(isl6423_attach, + budget->dvb_frontend, + &budget->i2c_adap, + &tt1600_isl6423_config); + + } else { + dvb_frontend_detach(budget->dvb_frontend); + budget->dvb_frontend = NULL; + } + } + break; } if (budget->dvb_frontend == NULL) { @@ -641,6 +724,7 @@ MAKE_BUDGET_INFO(ttbc, "TT-Budget/WinTV-NOVA-C PCI", BUDGET_TT); MAKE_BUDGET_INFO(ttbt, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT); MAKE_BUDGET_INFO(satel, "SATELCO Multimedia PCI", BUDGET_TT_HW_DISEQC); MAKE_BUDGET_INFO(ttbs1401, "TT-Budget-S-1401 PCI", BUDGET_TT); +MAKE_BUDGET_INFO(tt1600, "TT-Budget S2-1600 PCI", BUDGET_TT); MAKE_BUDGET_INFO(fsacs0, "Fujitsu Siemens Activy Budget-S PCI (rev GR/grundig frontend)", BUDGET_FS_ACTIVY); MAKE_BUDGET_INFO(fsacs1, "Fujitsu Siemens Activy Budget-S PCI (rev AL/alps frontend)", BUDGET_FS_ACTIVY); MAKE_BUDGET_INFO(fsact, "Fujitsu Siemens Activy Budget-T PCI (rev GR/Grundig frontend)", BUDGET_FS_ACTIVY); @@ -653,6 +737,7 @@ static struct pci_device_id pci_tbl[] = { MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013), MAKE_EXTENSION_PCI(ttbs, 0x13c2, 0x1016), MAKE_EXTENSION_PCI(ttbs1401, 0x13c2, 0x1018), + MAKE_EXTENSION_PCI(tt1600, 0x13c2, 0x101c), MAKE_EXTENSION_PCI(fsacs1,0x1131, 0x4f60), MAKE_EXTENSION_PCI(fsacs0,0x1131, 0x4f61), MAKE_EXTENSION_PCI(fsact1, 0x1131, 0x5f60), diff --git a/drivers/media/radio/dsbr100.c b/drivers/media/radio/dsbr100.c index 613576202294..ed9cd7ad0604 100644 --- a/drivers/media/radio/dsbr100.c +++ b/drivers/media/radio/dsbr100.c @@ -33,6 +33,10 @@ History: + Version 0.46: + Removed usb_dsbr100_open/close calls and radio->users counter. Also, + radio->muted changed to radio->status and suspend/resume calls updated. + Version 0.45: Converted to v4l2_device. @@ -100,8 +104,8 @@ */ #include /* for KERNEL_VERSION MACRO */ -#define DRIVER_VERSION "v0.45" -#define RADIO_VERSION KERNEL_VERSION(0, 4, 5) +#define DRIVER_VERSION "v0.46" +#define RADIO_VERSION KERNEL_VERSION(0, 4, 6) #define DRIVER_AUTHOR "Markus Demleitner " #define DRIVER_DESC "D-Link DSB-R100 USB FM radio driver" @@ -121,13 +125,15 @@ devices, that would be 76 and 91. */ #define FREQ_MAX 108.0 #define FREQ_MUL 16000 +/* defines for radio->status */ +#define STARTED 0 +#define STOPPED 1 + #define videodev_to_radio(d) container_of(d, struct dsbr100_device, videodev) static int usb_dsbr100_probe(struct usb_interface *intf, const struct usb_device_id *id); static void usb_dsbr100_disconnect(struct usb_interface *intf); -static int usb_dsbr100_open(struct file *file); -static int usb_dsbr100_close(struct file *file); static int usb_dsbr100_suspend(struct usb_interface *intf, pm_message_t message); static int usb_dsbr100_resume(struct usb_interface *intf); @@ -145,9 +151,8 @@ struct dsbr100_device { struct mutex lock; /* buffer locking */ int curfreq; int stereo; - int users; int removed; - int muted; + int status; }; static struct usb_device_id usb_dsbr100_device_table [] = { @@ -201,7 +206,7 @@ static int dsbr100_start(struct dsbr100_device *radio) goto usb_control_msg_failed; } - radio->muted = 0; + radio->status = STARTED; mutex_unlock(&radio->lock); return (radio->transfer_buffer)[0]; @@ -244,7 +249,7 @@ static int dsbr100_stop(struct dsbr100_device *radio) goto usb_control_msg_failed; } - radio->muted = 1; + radio->status = STOPPED; mutex_unlock(&radio->lock); return (radio->transfer_buffer)[0]; @@ -258,12 +263,12 @@ usb_control_msg_failed: } /* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */ -static int dsbr100_setfreq(struct dsbr100_device *radio, int freq) +static int dsbr100_setfreq(struct dsbr100_device *radio) { int retval; int request; + int freq = (radio->curfreq / 16 * 80) / 1000 + 856; - freq = (freq / 16 * 80) / 1000 + 856; mutex_lock(&radio->lock); retval = usb_control_msg(radio->usbdev, @@ -431,7 +436,7 @@ static int vidioc_s_frequency(struct file *file, void *priv, radio->curfreq = f->frequency; mutex_unlock(&radio->lock); - retval = dsbr100_setfreq(radio, radio->curfreq); + retval = dsbr100_setfreq(radio); if (retval < 0) dev_warn(&radio->usbdev->dev, "Set frequency failed\n"); return 0; @@ -473,7 +478,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv, switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: - ctrl->value = radio->muted; + ctrl->value = radio->status; return 0; } return -EINVAL; @@ -543,65 +548,27 @@ static int vidioc_s_audio(struct file *file, void *priv, return 0; } -static int usb_dsbr100_open(struct file *file) -{ - struct dsbr100_device *radio = video_drvdata(file); - int retval; - - lock_kernel(); - radio->users = 1; - radio->muted = 1; - - retval = dsbr100_start(radio); - if (retval < 0) { - dev_warn(&radio->usbdev->dev, - "Radio did not start up properly\n"); - radio->users = 0; - unlock_kernel(); - return -EIO; - } - - retval = dsbr100_setfreq(radio, radio->curfreq); - if (retval < 0) - dev_warn(&radio->usbdev->dev, - "set frequency failed\n"); - - unlock_kernel(); - return 0; -} - -static int usb_dsbr100_close(struct file *file) -{ - struct dsbr100_device *radio = video_drvdata(file); - int retval; - - if (!radio) - return -ENODEV; - - mutex_lock(&radio->lock); - radio->users = 0; - mutex_unlock(&radio->lock); - - if (!radio->removed) { - retval = dsbr100_stop(radio); - if (retval < 0) { - dev_warn(&radio->usbdev->dev, - "dsbr100_stop failed\n"); - } - - } - return 0; -} - /* Suspend device - stop device. */ static int usb_dsbr100_suspend(struct usb_interface *intf, pm_message_t message) { struct dsbr100_device *radio = usb_get_intfdata(intf); int retval; - retval = dsbr100_stop(radio); - if (retval < 0) - dev_warn(&intf->dev, "dsbr100_stop failed\n"); + if (radio->status == STARTED) { + retval = dsbr100_stop(radio); + if (retval < 0) + dev_warn(&intf->dev, "dsbr100_stop failed\n"); + + /* After dsbr100_stop() status set to STOPPED. + * If we want driver to start radio on resume + * we set status equal to STARTED. + * On resume we will check status and run radio if needed. + */ + + mutex_lock(&radio->lock); + radio->status = STARTED; + mutex_unlock(&radio->lock); + } dev_info(&intf->dev, "going into suspend..\n"); @@ -614,9 +581,11 @@ static int usb_dsbr100_resume(struct usb_interface *intf) struct dsbr100_device *radio = usb_get_intfdata(intf); int retval; - retval = dsbr100_start(radio); - if (retval < 0) - dev_warn(&intf->dev, "dsbr100_start failed\n"); + if (radio->status == STARTED) { + retval = dsbr100_start(radio); + if (retval < 0) + dev_warn(&intf->dev, "dsbr100_start failed\n"); + } dev_info(&intf->dev, "coming out of suspend..\n"); @@ -636,8 +605,6 @@ static void usb_dsbr100_video_device_release(struct video_device *videodev) /* File system interface */ static const struct v4l2_file_operations usb_dsbr100_fops = { .owner = THIS_MODULE, - .open = usb_dsbr100_open, - .release = usb_dsbr100_close, .ioctl = video_ioctl2, }; @@ -695,9 +662,9 @@ static int usb_dsbr100_probe(struct usb_interface *intf, mutex_init(&radio->lock); radio->removed = 0; - radio->users = 0; radio->usbdev = interface_to_usbdev(intf); radio->curfreq = FREQ_MIN * FREQ_MUL; + radio->status = STOPPED; video_set_drvdata(&radio->videodev, radio); diff --git a/drivers/media/radio/radio-mr800.c b/drivers/media/radio/radio-mr800.c index cab19d05e02f..837467f93805 100644 --- a/drivers/media/radio/radio-mr800.c +++ b/drivers/media/radio/radio-mr800.c @@ -64,6 +64,7 @@ #include #include #include /* for KERNEL_VERSION MACRO */ +#include /* driver and module definitions */ #define DRIVER_AUTHOR "Alexey Klimov " diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c index 5cf6c45b91fe..49c4aab95dab 100644 --- a/drivers/media/radio/radio-sf16fmi.c +++ b/drivers/media/radio/radio-sf16fmi.c @@ -49,7 +49,6 @@ struct fmi int io; int curvol; /* 1 or 0 */ unsigned long curfreq; /* freq in kHz */ - __u32 flags; struct mutex lock; }; @@ -57,7 +56,7 @@ static struct fmi fmi_card; static struct pnp_dev *dev; /* freq is in 1/16 kHz to internal number, hw precision is 50 kHz */ -/* It is only useful to give freq in intervall of 800 (=0.05Mhz), +/* It is only useful to give freq in interval of 800 (=0.05Mhz), * other bits will be truncated, e.g 92.7400016 -> 92.7, but * 92.7400017 -> 92.75 */ @@ -142,7 +141,6 @@ static int vidioc_querycap(struct file *file, void *priv, static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { - int mult; struct fmi *fmi = video_drvdata(file); if (v->index > 0) @@ -150,11 +148,10 @@ static int vidioc_g_tuner(struct file *file, void *priv, strlcpy(v->name, "FM", sizeof(v->name)); v->type = V4L2_TUNER_RADIO; - mult = (fmi->flags & V4L2_TUNER_CAP_LOW) ? 1 : 1000; - v->rangelow = RSF16_MINFREQ / mult; - v->rangehigh = RSF16_MAXFREQ / mult; + v->rangelow = RSF16_MINFREQ; + v->rangehigh = RSF16_MAXFREQ; v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; - v->capability = fmi->flags & V4L2_TUNER_CAP_LOW; + v->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LOW; v->audmode = V4L2_TUNER_MODE_STEREO; v->signal = fmi_getsigstr(fmi); return 0; @@ -171,8 +168,6 @@ static int vidioc_s_frequency(struct file *file, void *priv, { struct fmi *fmi = video_drvdata(file); - if (!(fmi->flags & V4L2_TUNER_CAP_LOW)) - f->frequency *= 1000; if (f->frequency < RSF16_MINFREQ || f->frequency > RSF16_MAXFREQ) return -EINVAL; @@ -189,8 +184,6 @@ static int vidioc_g_frequency(struct file *file, void *priv, f->type = V4L2_TUNER_RADIO; f->frequency = fmi->curfreq; - if (!(fmi->flags & V4L2_TUNER_CAP_LOW)) - f->frequency /= 1000; return 0; } @@ -347,7 +340,6 @@ static int __init fmi_init(void) return res; } - fmi->flags = V4L2_TUNER_CAP_LOW; strlcpy(fmi->vdev.name, v4l2_dev->name, sizeof(fmi->vdev.name)); fmi->vdev.v4l2_dev = v4l2_dev; fmi->vdev.fops = &fmi_fops; diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c index 935ff9bcdfcc..a11414f648d4 100644 --- a/drivers/media/radio/radio-sf16fmr2.c +++ b/drivers/media/radio/radio-sf16fmr2.c @@ -61,13 +61,12 @@ struct fmr2 int stereo; /* card is producing stereo audio */ unsigned long curfreq; /* freq in kHz */ int card_type; - u32 flags; }; static struct fmr2 fmr2_card; /* hw precision is 12.5 kHz - * It is only useful to give freq in intervall of 200 (=0.0125Mhz), + * It is only useful to give freq in interval of 200 (=0.0125Mhz), * other bits will be truncated */ #define RSF16_ENCODE(x) ((x) / 200 + 856) @@ -221,7 +220,6 @@ static int vidioc_querycap(struct file *file, void *priv, static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { - int mult; struct fmr2 *fmr2 = video_drvdata(file); if (v->index > 0) @@ -230,13 +228,12 @@ static int vidioc_g_tuner(struct file *file, void *priv, strlcpy(v->name, "FM", sizeof(v->name)); v->type = V4L2_TUNER_RADIO; - mult = (fmr2->flags & V4L2_TUNER_CAP_LOW) ? 1 : 1000; - v->rangelow = RSF16_MINFREQ / mult; - v->rangehigh = RSF16_MAXFREQ / mult; - v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; - v->capability = fmr2->flags&V4L2_TUNER_CAP_LOW; - v->audmode = fmr2->stereo ? V4L2_TUNER_MODE_STEREO: - V4L2_TUNER_MODE_MONO; + v->rangelow = RSF16_MINFREQ; + v->rangehigh = RSF16_MAXFREQ; + v->rxsubchans = fmr2->stereo ? V4L2_TUNER_SUB_STEREO : + V4L2_TUNER_SUB_MONO; + v->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LOW; + v->audmode = V4L2_TUNER_MODE_STEREO; mutex_lock(&fmr2->lock); v->signal = fmr2_getsigstr(fmr2); mutex_unlock(&fmr2->lock); @@ -254,8 +251,6 @@ static int vidioc_s_frequency(struct file *file, void *priv, { struct fmr2 *fmr2 = video_drvdata(file); - if (!(fmr2->flags & V4L2_TUNER_CAP_LOW)) - f->frequency *= 1000; if (f->frequency < RSF16_MINFREQ || f->frequency > RSF16_MAXFREQ) return -EINVAL; @@ -279,8 +274,6 @@ static int vidioc_g_frequency(struct file *file, void *priv, f->type = V4L2_TUNER_RADIO; f->frequency = fmr2->curfreq; - if (!(fmr2->flags & V4L2_TUNER_CAP_LOW)) - f->frequency /= 1000; return 0; } @@ -406,7 +399,6 @@ static int __init fmr2_init(void) strlcpy(v4l2_dev->name, "sf16fmr2", sizeof(v4l2_dev->name)); fmr2->io = io; fmr2->stereo = 1; - fmr2->flags = V4L2_TUNER_CAP_LOW; mutex_init(&fmr2->lock); if (!request_region(fmr2->io, 2, "sf16fmr2")) { diff --git a/drivers/media/radio/radio-si470x.c b/drivers/media/radio/radio-si470x.c index bd945d04dc90..640421ceb24a 100644 --- a/drivers/media/radio/radio-si470x.c +++ b/drivers/media/radio/radio-si470x.c @@ -1214,7 +1214,6 @@ static int si470x_fops_release(struct file *file) usb_autopm_put_interface(radio->intf); } -unlock: mutex_unlock(&radio->disconnect_lock); done: diff --git a/drivers/media/radio/radio-tea5764.c b/drivers/media/radio/radio-tea5764.c index 393623818ade..3cd76dddb6aa 100644 --- a/drivers/media/radio/radio-tea5764.c +++ b/drivers/media/radio/radio-tea5764.c @@ -322,7 +322,9 @@ static int vidioc_g_tuner(struct file *file, void *priv, v->rangehigh = FREQ_MAX * FREQ_MUL; v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; if (r->tunchk & TEA5764_TUNCHK_STEREO) - v->rxsubchans = V4L2_TUNER_SUB_STEREO; + v->rxsubchans = V4L2_TUNER_SUB_STEREO; + else + v->rxsubchans = V4L2_TUNER_SUB_MONO; v->audmode = tea5764_get_audout_mode(radio); v->signal = TEA5764_TUNCHK_LEVEL(r->tunchk) * 0xffff / 0xf; v->afc = TEA5764_TUNCHK_IFCNT(r->tunchk); diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 9d48da2fb013..061e147f6f26 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -440,6 +440,24 @@ config VIDEO_ADV7175 To compile this driver as a module, choose M here: the module will be called adv7175. +config VIDEO_THS7303 + tristate "THS7303 Video Amplifier" + depends on I2C + help + Support for TI THS7303 video amplifier + + To compile this driver as a module, choose M here: the + module will be called ths7303. + +config VIDEO_ADV7343 + tristate "ADV7343 video encoder" + depends on I2C + help + Support for Analog Devices I2C bus based ADV7343 encoder. + + To compile this driver as a module, choose M here: the + module will be called adv7343. + comment "Video improvement chips" config VIDEO_UPD64031A @@ -694,7 +712,7 @@ config VIDEO_CAFE_CCIC config SOC_CAMERA tristate "SoC camera support" - depends on VIDEO_V4L2 && HAS_DMA + depends on VIDEO_V4L2 && HAS_DMA && I2C select VIDEOBUF_GEN help SoC Camera is a common API to several cameras, not connecting @@ -758,10 +776,14 @@ config VIDEO_MX1 ---help--- This is a v4l2 driver for the i.MX1/i.MXL CMOS Sensor Interface +config MX3_VIDEO + bool + config VIDEO_MX3 tristate "i.MX3x Camera Sensor Interface driver" depends on VIDEO_DEV && MX3_IPU && SOC_CAMERA select VIDEOBUF_DMA_CONTIG + select MX3_VIDEO ---help--- This is a v4l2 driver for the i.MX3x Camera Sensor Interface @@ -844,9 +866,13 @@ config USB_W9968CF module will be called w9968cf. config USB_OV511 - tristate "USB OV511 Camera support" + tristate "USB OV511 Camera support (DEPRECATED)" depends on VIDEO_V4L1 ---help--- + This driver is DEPRECATED please use the gspca ov519 module + instead. Note that for the ov511 / ov518 support of the gspca module + you need atleast version 0.6.0 of libv4l. + Say Y here if you want to connect this type of camera to your computer's USB port. See for more information and for a list of supported cameras. diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 3f1a0350a569..7fb3add1b387 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -12,6 +12,8 @@ omap2cam-objs := omap24xxcam.o omap24xxcam-dma.o videodev-objs := v4l2-dev.o v4l2-ioctl.o v4l2-device.o +# V4L2 core modules + obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-int-device.o ifeq ($(CONFIG_COMPAT),y) obj-$(CONFIG_VIDEO_DEV) += v4l2-compat-ioctl32.o @@ -23,21 +25,15 @@ ifeq ($(CONFIG_VIDEO_V4L1_COMPAT),y) obj-$(CONFIG_VIDEO_DEV) += v4l1-compat.o endif -obj-$(CONFIG_VIDEO_TUNER) += tuner.o +# All i2c modules must come first: -obj-$(CONFIG_VIDEO_BT848) += bt8xx/ -obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o +obj-$(CONFIG_VIDEO_TUNER) += tuner.o obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o obj-$(CONFIG_VIDEO_TDA7432) += tda7432.o obj-$(CONFIG_VIDEO_TDA9875) += tda9875.o - obj-$(CONFIG_VIDEO_SAA6588) += saa6588.o obj-$(CONFIG_VIDEO_SAA5246A) += saa5246a.o obj-$(CONFIG_VIDEO_SAA5249) += saa5249.o -obj-$(CONFIG_VIDEO_CQCAM) += c-qcam.o -obj-$(CONFIG_VIDEO_BWQCAM) += bw-qcam.o -obj-$(CONFIG_VIDEO_W9966) += w9966.o - obj-$(CONFIG_VIDEO_TDA9840) += tda9840.o obj-$(CONFIG_VIDEO_TEA6415C) += tea6415c.o obj-$(CONFIG_VIDEO_TEA6420) += tea6420.o @@ -49,16 +45,47 @@ obj-$(CONFIG_VIDEO_SAA7185) += saa7185.o obj-$(CONFIG_VIDEO_SAA7191) += saa7191.o obj-$(CONFIG_VIDEO_ADV7170) += adv7170.o obj-$(CONFIG_VIDEO_ADV7175) += adv7175.o +obj-$(CONFIG_VIDEO_ADV7343) += adv7343.o obj-$(CONFIG_VIDEO_VPX3220) += vpx3220.o obj-$(CONFIG_VIDEO_BT819) += bt819.o obj-$(CONFIG_VIDEO_BT856) += bt856.o obj-$(CONFIG_VIDEO_BT866) += bt866.o obj-$(CONFIG_VIDEO_KS0127) += ks0127.o +obj-$(CONFIG_VIDEO_THS7303) += ths7303.o +obj-$(CONFIG_VIDEO_VINO) += indycam.o +obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o +obj-$(CONFIG_VIDEO_TVP514X) += tvp514x.o +obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o +obj-$(CONFIG_VIDEO_CS5345) += cs5345.o +obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o +obj-$(CONFIG_VIDEO_M52790) += m52790.o +obj-$(CONFIG_VIDEO_TLV320AIC23B) += tlv320aic23b.o +obj-$(CONFIG_VIDEO_WM8775) += wm8775.o +obj-$(CONFIG_VIDEO_WM8739) += wm8739.o +obj-$(CONFIG_VIDEO_VP27SMPX) += vp27smpx.o +obj-$(CONFIG_VIDEO_CX25840) += cx25840/ +obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o +obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o +obj-$(CONFIG_VIDEO_OV7670) += ov7670.o +obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o +obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o +obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o +obj-$(CONFIG_SOC_CAMERA_MT9M111) += mt9m111.o +obj-$(CONFIG_SOC_CAMERA_MT9T031) += mt9t031.o +obj-$(CONFIG_SOC_CAMERA_MT9V022) += mt9v022.o +obj-$(CONFIG_SOC_CAMERA_OV772X) += ov772x.o +obj-$(CONFIG_SOC_CAMERA_TW9910) += tw9910.o + +# And now the v4l2 drivers: + +obj-$(CONFIG_VIDEO_BT848) += bt8xx/ obj-$(CONFIG_VIDEO_ZORAN) += zoran/ - +obj-$(CONFIG_VIDEO_CQCAM) += c-qcam.o +obj-$(CONFIG_VIDEO_BWQCAM) += bw-qcam.o +obj-$(CONFIG_VIDEO_W9966) += w9966.o obj-$(CONFIG_VIDEO_PMS) += pms.o -obj-$(CONFIG_VIDEO_VINO) += vino.o indycam.o +obj-$(CONFIG_VIDEO_VINO) += vino.o obj-$(CONFIG_VIDEO_STRADIS) += stradis.o obj-$(CONFIG_VIDEO_CPIA) += cpia.o obj-$(CONFIG_VIDEO_CPIA_PP) += cpia_pp.o @@ -69,17 +96,7 @@ obj-$(CONFIG_VIDEO_CX88) += cx88/ obj-$(CONFIG_VIDEO_EM28XX) += em28xx/ obj-$(CONFIG_VIDEO_CX231XX) += cx231xx/ obj-$(CONFIG_VIDEO_USBVISION) += usbvision/ -obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o -obj-$(CONFIG_VIDEO_TVP514X) += tvp514x.o obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/ -obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o -obj-$(CONFIG_VIDEO_CS5345) += cs5345.o -obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o -obj-$(CONFIG_VIDEO_M52790) += m52790.o -obj-$(CONFIG_VIDEO_TLV320AIC23B) += tlv320aic23b.o -obj-$(CONFIG_VIDEO_WM8775) += wm8775.o -obj-$(CONFIG_VIDEO_WM8739) += wm8739.o -obj-$(CONFIG_VIDEO_VP27SMPX) += vp27smpx.o obj-$(CONFIG_VIDEO_OVCAMCHIP) += ovcamchip/ obj-$(CONFIG_VIDEO_CPIA2) += cpia2/ obj-$(CONFIG_VIDEO_MXB) += mxb.o @@ -92,19 +109,12 @@ 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 -obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o obj-$(CONFIG_VIDEO_M32R_AR_M64278) += arv.o -obj-$(CONFIG_VIDEO_CX25840) += cx25840/ -obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o -obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o obj-$(CONFIG_VIDEO_CAFE_CCIC) += cafe_ccic.o -obj-$(CONFIG_VIDEO_OV7670) += ov7670.o - -obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o obj-$(CONFIG_USB_DABUSB) += dabusb.o obj-$(CONFIG_USB_OV511) += ov511.o @@ -134,24 +144,21 @@ obj-$(CONFIG_VIDEO_CX18) += cx18/ obj-$(CONFIG_VIDEO_VIVI) += vivi.o obj-$(CONFIG_VIDEO_CX23885) += cx23885/ +obj-$(CONFIG_VIDEO_OMAP2) += omap2cam.o +obj-$(CONFIG_SOC_CAMERA) += soc_camera.o +obj-$(CONFIG_SOC_CAMERA_PLATFORM) += soc_camera_platform.o +# soc-camera host drivers have to be linked after camera drivers obj-$(CONFIG_VIDEO_MX1) += mx1_camera.o obj-$(CONFIG_VIDEO_MX3) += mx3_camera.o obj-$(CONFIG_VIDEO_PXA27x) += pxa_camera.o obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o -obj-$(CONFIG_VIDEO_OMAP2) += omap2cam.o -obj-$(CONFIG_SOC_CAMERA) += soc_camera.o -obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o -obj-$(CONFIG_SOC_CAMERA_MT9M111) += mt9m111.o -obj-$(CONFIG_SOC_CAMERA_MT9T031) += mt9t031.o -obj-$(CONFIG_SOC_CAMERA_MT9V022) += mt9v022.o -obj-$(CONFIG_SOC_CAMERA_OV772X) += ov772x.o -obj-$(CONFIG_SOC_CAMERA_PLATFORM) += soc_camera_platform.o -obj-$(CONFIG_SOC_CAMERA_TW9910) += tw9910.o obj-$(CONFIG_VIDEO_AU0828) += au0828/ obj-$(CONFIG_USB_VIDEO_CLASS) += uvc/ +obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o + EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core EXTRA_CFLAGS += -Idrivers/media/dvb/frontends EXTRA_CFLAGS += -Idrivers/media/common/tuners diff --git a/drivers/media/video/adv7343.c b/drivers/media/video/adv7343.c new file mode 100644 index 000000000000..30f5caf5dda5 --- /dev/null +++ b/drivers/media/video/adv7343.c @@ -0,0 +1,534 @@ +/* + * adv7343 - ADV7343 Video Encoder Driver + * + * The encoder hardware does not support SECAM. + * + * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.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 version 2. + * + * This program is distributed .as is. WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "adv7343_regs.h" + +MODULE_DESCRIPTION("ADV7343 video encoder driver"); +MODULE_LICENSE("GPL"); + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Debug level 0-1"); + +struct adv7343_state { + struct v4l2_subdev sd; + u8 reg00; + u8 reg01; + u8 reg02; + u8 reg35; + u8 reg80; + u8 reg82; + int bright; + int hue; + int gain; + u32 output; + v4l2_std_id std; +}; + +static inline struct adv7343_state *to_state(struct v4l2_subdev *sd) +{ + return container_of(sd, struct adv7343_state, sd); +} + +static inline int adv7343_write(struct v4l2_subdev *sd, u8 reg, u8 value) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + return i2c_smbus_write_byte_data(client, reg, value); +} + +static const u8 adv7343_init_reg_val[] = { + ADV7343_SOFT_RESET, ADV7343_SOFT_RESET_DEFAULT, + ADV7343_POWER_MODE_REG, ADV7343_POWER_MODE_REG_DEFAULT, + + ADV7343_HD_MODE_REG1, ADV7343_HD_MODE_REG1_DEFAULT, + ADV7343_HD_MODE_REG2, ADV7343_HD_MODE_REG2_DEFAULT, + ADV7343_HD_MODE_REG3, ADV7343_HD_MODE_REG3_DEFAULT, + ADV7343_HD_MODE_REG4, ADV7343_HD_MODE_REG4_DEFAULT, + ADV7343_HD_MODE_REG5, ADV7343_HD_MODE_REG5_DEFAULT, + ADV7343_HD_MODE_REG6, ADV7343_HD_MODE_REG6_DEFAULT, + ADV7343_HD_MODE_REG7, ADV7343_HD_MODE_REG7_DEFAULT, + + ADV7343_SD_MODE_REG1, ADV7343_SD_MODE_REG1_DEFAULT, + ADV7343_SD_MODE_REG2, ADV7343_SD_MODE_REG2_DEFAULT, + ADV7343_SD_MODE_REG3, ADV7343_SD_MODE_REG3_DEFAULT, + ADV7343_SD_MODE_REG4, ADV7343_SD_MODE_REG4_DEFAULT, + ADV7343_SD_MODE_REG5, ADV7343_SD_MODE_REG5_DEFAULT, + ADV7343_SD_MODE_REG6, ADV7343_SD_MODE_REG6_DEFAULT, + ADV7343_SD_MODE_REG7, ADV7343_SD_MODE_REG7_DEFAULT, + ADV7343_SD_MODE_REG8, ADV7343_SD_MODE_REG8_DEFAULT, + + ADV7343_SD_HUE_REG, ADV7343_SD_HUE_REG_DEFAULT, + ADV7343_SD_CGMS_WSS0, ADV7343_SD_CGMS_WSS0_DEFAULT, + ADV7343_SD_BRIGHTNESS_WSS, ADV7343_SD_BRIGHTNESS_WSS_DEFAULT, +}; + +/* + * 2^32 + * FSC(reg) = FSC (HZ) * -------- + * 27000000 + */ +static const struct adv7343_std_info stdinfo[] = { + { + /* FSC(Hz) = 3,579,545.45 Hz */ + SD_STD_NTSC, 569408542, V4L2_STD_NTSC, + }, { + /* FSC(Hz) = 3,575,611.00 Hz */ + SD_STD_PAL_M, 568782678, V4L2_STD_PAL_M, + }, { + /* FSC(Hz) = 3,582,056.00 */ + SD_STD_PAL_N, 569807903, V4L2_STD_PAL_Nc, + }, { + /* FSC(Hz) = 4,433,618.75 Hz */ + SD_STD_PAL_N, 705268427, V4L2_STD_PAL_N, + }, { + /* FSC(Hz) = 4,433,618.75 Hz */ + SD_STD_PAL_BDGHI, 705268427, V4L2_STD_PAL, + }, { + /* FSC(Hz) = 4,433,618.75 Hz */ + SD_STD_NTSC, 705268427, V4L2_STD_NTSC_443, + }, { + /* FSC(Hz) = 4,433,618.75 Hz */ + SD_STD_PAL_M, 705268427, V4L2_STD_PAL_60, + }, +}; + +static int adv7343_setstd(struct v4l2_subdev *sd, v4l2_std_id std) +{ + struct adv7343_state *state = to_state(sd); + struct adv7343_std_info *std_info; + int output_idx, num_std; + char *fsc_ptr; + u8 reg, val; + int err = 0; + int i = 0; + + output_idx = state->output; + + std_info = (struct adv7343_std_info *)stdinfo; + num_std = ARRAY_SIZE(stdinfo); + + for (i = 0; i < num_std; i++) { + if (std_info[i].stdid & std) + break; + } + + if (i == num_std) { + v4l2_dbg(1, debug, sd, + "Invalid std or std is not supported: %llx\n", + (unsigned long long)std); + return -EINVAL; + } + + /* Set the standard */ + val = state->reg80 & (~(SD_STD_MASK)); + val |= std_info[i].standard_val3; + err = adv7343_write(sd, ADV7343_SD_MODE_REG1, val); + if (err < 0) + goto setstd_exit; + + state->reg80 = val; + + /* Configure the input mode register */ + val = state->reg01 & (~((u8) INPUT_MODE_MASK)); + val |= SD_INPUT_MODE; + err = adv7343_write(sd, ADV7343_MODE_SELECT_REG, val); + if (err < 0) + goto setstd_exit; + + state->reg01 = val; + + /* Program the sub carrier frequency registers */ + fsc_ptr = (unsigned char *)&std_info[i].fsc_val; + reg = ADV7343_FSC_REG0; + for (i = 0; i < 4; i++, reg++, fsc_ptr++) { + err = adv7343_write(sd, reg, *fsc_ptr); + if (err < 0) + goto setstd_exit; + } + + val = state->reg80; + + /* Filter settings */ + if (std & (V4L2_STD_NTSC | V4L2_STD_NTSC_443)) + val &= 0x03; + else if (std & ~V4L2_STD_SECAM) + val |= 0x04; + + err = adv7343_write(sd, ADV7343_SD_MODE_REG1, val); + if (err < 0) + goto setstd_exit; + + state->reg80 = val; + +setstd_exit: + if (err != 0) + v4l2_err(sd, "Error setting std, write failed\n"); + + return err; +} + +static int adv7343_setoutput(struct v4l2_subdev *sd, u32 output_type) +{ + struct adv7343_state *state = to_state(sd); + unsigned char val; + int err = 0; + + if (output_type > ADV7343_SVIDEO_ID) { + v4l2_dbg(1, debug, sd, + "Invalid output type or output type not supported:%d\n", + output_type); + return -EINVAL; + } + + /* Enable Appropriate DAC */ + val = state->reg00 & 0x03; + + if (output_type == ADV7343_COMPOSITE_ID) + val |= ADV7343_COMPOSITE_POWER_VALUE; + else if (output_type == ADV7343_COMPONENT_ID) + val |= ADV7343_COMPONENT_POWER_VALUE; + else + val |= ADV7343_SVIDEO_POWER_VALUE; + + err = adv7343_write(sd, ADV7343_POWER_MODE_REG, val); + if (err < 0) + goto setoutput_exit; + + state->reg00 = val; + + /* Enable YUV output */ + val = state->reg02 | YUV_OUTPUT_SELECT; + err = adv7343_write(sd, ADV7343_MODE_REG0, val); + if (err < 0) + goto setoutput_exit; + + state->reg02 = val; + + /* configure SD DAC Output 2 and SD DAC Output 1 bit to zero */ + val = state->reg82 & (SD_DAC_1_DI & SD_DAC_2_DI); + err = adv7343_write(sd, ADV7343_SD_MODE_REG2, val); + if (err < 0) + goto setoutput_exit; + + state->reg82 = val; + + /* configure ED/HD Color DAC Swap and ED/HD RGB Input Enable bit to + * zero */ + val = state->reg35 & (HD_RGB_INPUT_DI & HD_DAC_SWAP_DI); + err = adv7343_write(sd, ADV7343_HD_MODE_REG6, val); + if (err < 0) + goto setoutput_exit; + + state->reg35 = val; + +setoutput_exit: + if (err != 0) + v4l2_err(sd, "Error setting output, write failed\n"); + + return err; +} + +static int adv7343_log_status(struct v4l2_subdev *sd) +{ + struct adv7343_state *state = to_state(sd); + + v4l2_info(sd, "Standard: %llx\n", (unsigned long long)state->std); + v4l2_info(sd, "Output: %s\n", (state->output == 0) ? "Composite" : + ((state->output == 1) ? "Component" : "S-Video")); + return 0; +} + +static int adv7343_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) +{ + switch (qc->id) { + case V4L2_CID_BRIGHTNESS: + return v4l2_ctrl_query_fill(qc, ADV7343_BRIGHTNESS_MIN, + ADV7343_BRIGHTNESS_MAX, 1, + ADV7343_BRIGHTNESS_DEF); + case V4L2_CID_HUE: + return v4l2_ctrl_query_fill(qc, ADV7343_HUE_MIN, + ADV7343_HUE_MAX, 1 , + ADV7343_HUE_DEF); + case V4L2_CID_GAIN: + return v4l2_ctrl_query_fill(qc, ADV7343_GAIN_MIN, + ADV7343_GAIN_MAX, 1, + ADV7343_GAIN_DEF); + default: + break; + } + + return 0; +} + +static int adv7343_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct adv7343_state *state = to_state(sd); + int err = 0; + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + if (ctrl->value < ADV7343_BRIGHTNESS_MIN || + ctrl->value > ADV7343_BRIGHTNESS_MAX) { + v4l2_dbg(1, debug, sd, + "invalid brightness settings %d\n", + ctrl->value); + return -ERANGE; + } + + state->bright = ctrl->value; + err = adv7343_write(sd, ADV7343_SD_BRIGHTNESS_WSS, + state->bright); + break; + + case V4L2_CID_HUE: + if (ctrl->value < ADV7343_HUE_MIN || + ctrl->value > ADV7343_HUE_MAX) { + v4l2_dbg(1, debug, sd, "invalid hue settings %d\n", + ctrl->value); + return -ERANGE; + } + + state->hue = ctrl->value; + err = adv7343_write(sd, ADV7343_SD_HUE_REG, state->hue); + break; + + case V4L2_CID_GAIN: + if (ctrl->value < ADV7343_GAIN_MIN || + ctrl->value > ADV7343_GAIN_MAX) { + v4l2_dbg(1, debug, sd, "invalid gain settings %d\n", + ctrl->value); + return -ERANGE; + } + + if ((ctrl->value > POSITIVE_GAIN_MAX) && + (ctrl->value < NEGATIVE_GAIN_MIN)) { + v4l2_dbg(1, debug, sd, + "gain settings not within the specified range\n"); + return -ERANGE; + } + + state->gain = ctrl->value; + err = adv7343_write(sd, ADV7343_DAC2_OUTPUT_LEVEL, state->gain); + break; + + default: + return -EINVAL; + } + + if (err < 0) + v4l2_err(sd, "Failed to set the encoder controls\n"); + + return err; +} + +static int adv7343_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct adv7343_state *state = to_state(sd); + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + ctrl->value = state->bright; + break; + + case V4L2_CID_HUE: + ctrl->value = state->hue; + break; + + case V4L2_CID_GAIN: + ctrl->value = state->gain; + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int adv7343_g_chip_ident(struct v4l2_subdev *sd, + struct v4l2_dbg_chip_ident *chip) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7343, 0); +} + +static const struct v4l2_subdev_core_ops adv7343_core_ops = { + .log_status = adv7343_log_status, + .g_chip_ident = adv7343_g_chip_ident, + .g_ctrl = adv7343_g_ctrl, + .s_ctrl = adv7343_s_ctrl, + .queryctrl = adv7343_queryctrl, +}; + +static int adv7343_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std) +{ + struct adv7343_state *state = to_state(sd); + int err = 0; + + if (state->std == std) + return 0; + + err = adv7343_setstd(sd, std); + if (!err) + state->std = std; + + return err; +} + +static int adv7343_s_routing(struct v4l2_subdev *sd, + u32 input, u32 output, u32 config) +{ + struct adv7343_state *state = to_state(sd); + int err = 0; + + if (state->output == output) + return 0; + + err = adv7343_setoutput(sd, output); + if (!err) + state->output = output; + + return err; +} + +static const struct v4l2_subdev_video_ops adv7343_video_ops = { + .s_std_output = adv7343_s_std_output, + .s_routing = adv7343_s_routing, +}; + +static const struct v4l2_subdev_ops adv7343_ops = { + .core = &adv7343_core_ops, + .video = &adv7343_video_ops, +}; + +static int adv7343_initialize(struct v4l2_subdev *sd) +{ + struct adv7343_state *state = to_state(sd); + int err = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(adv7343_init_reg_val); i += 2) { + + err = adv7343_write(sd, adv7343_init_reg_val[i], + adv7343_init_reg_val[i+1]); + if (err) { + v4l2_err(sd, "Error initializing\n"); + return err; + } + } + + /* Configure for default video standard */ + err = adv7343_setoutput(sd, state->output); + if (err < 0) { + v4l2_err(sd, "Error setting output during init\n"); + return -EINVAL; + } + + err = adv7343_setstd(sd, state->std); + if (err < 0) { + v4l2_err(sd, "Error setting std during init\n"); + return -EINVAL; + } + + return err; +} + +static int adv7343_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct adv7343_state *state; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -ENODEV; + + v4l_info(client, "chip found @ 0x%x (%s)\n", + client->addr << 1, client->adapter->name); + + state = kzalloc(sizeof(struct adv7343_state), GFP_KERNEL); + if (state == NULL) + return -ENOMEM; + + state->reg00 = 0x80; + state->reg01 = 0x00; + state->reg02 = 0x20; + state->reg35 = 0x00; + state->reg80 = ADV7343_SD_MODE_REG1_DEFAULT; + state->reg82 = ADV7343_SD_MODE_REG2_DEFAULT; + + state->output = ADV7343_COMPOSITE_ID; + state->std = V4L2_STD_NTSC; + + v4l2_i2c_subdev_init(&state->sd, client, &adv7343_ops); + return adv7343_initialize(&state->sd); +} + +static int adv7343_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + + v4l2_device_unregister_subdev(sd); + kfree(to_state(sd)); + + return 0; +} + +static const struct i2c_device_id adv7343_id[] = { + {"adv7343", 0}, + {}, +}; + +MODULE_DEVICE_TABLE(i2c, adv7343_id); + +static struct i2c_driver adv7343_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "adv7343", + }, + .probe = adv7343_probe, + .remove = adv7343_remove, + .id_table = adv7343_id, +}; + +static __init int init_adv7343(void) +{ + return i2c_add_driver(&adv7343_driver); +} + +static __exit void exit_adv7343(void) +{ + i2c_del_driver(&adv7343_driver); +} + +module_init(init_adv7343); +module_exit(exit_adv7343); diff --git a/drivers/media/video/adv7343_regs.h b/drivers/media/video/adv7343_regs.h new file mode 100644 index 000000000000..3431045b33da --- /dev/null +++ b/drivers/media/video/adv7343_regs.h @@ -0,0 +1,185 @@ +/* + * ADV7343 encoder related structure and register definitions + * + * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.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 version 2. + * + * This program is distributed .as is. WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef ADV7343_REG_H +#define ADV7343_REGS_H + +struct adv7343_std_info { + u32 standard_val3; + u32 fsc_val; + v4l2_std_id stdid; +}; + +/* Register offset macros */ +#define ADV7343_POWER_MODE_REG (0x00) +#define ADV7343_MODE_SELECT_REG (0x01) +#define ADV7343_MODE_REG0 (0x02) + +#define ADV7343_DAC2_OUTPUT_LEVEL (0x0b) + +#define ADV7343_SOFT_RESET (0x17) + +#define ADV7343_HD_MODE_REG1 (0x30) +#define ADV7343_HD_MODE_REG2 (0x31) +#define ADV7343_HD_MODE_REG3 (0x32) +#define ADV7343_HD_MODE_REG4 (0x33) +#define ADV7343_HD_MODE_REG5 (0x34) +#define ADV7343_HD_MODE_REG6 (0x35) + +#define ADV7343_HD_MODE_REG7 (0x39) + +#define ADV7343_SD_MODE_REG1 (0x80) +#define ADV7343_SD_MODE_REG2 (0x82) +#define ADV7343_SD_MODE_REG3 (0x83) +#define ADV7343_SD_MODE_REG4 (0x84) +#define ADV7343_SD_MODE_REG5 (0x86) +#define ADV7343_SD_MODE_REG6 (0x87) +#define ADV7343_SD_MODE_REG7 (0x88) +#define ADV7343_SD_MODE_REG8 (0x89) + +#define ADV7343_FSC_REG0 (0x8C) +#define ADV7343_FSC_REG1 (0x8D) +#define ADV7343_FSC_REG2 (0x8E) +#define ADV7343_FSC_REG3 (0x8F) + +#define ADV7343_SD_CGMS_WSS0 (0x99) + +#define ADV7343_SD_HUE_REG (0xA0) +#define ADV7343_SD_BRIGHTNESS_WSS (0xA1) + +/* Default values for the registers */ +#define ADV7343_POWER_MODE_REG_DEFAULT (0x10) +#define ADV7343_HD_MODE_REG1_DEFAULT (0x3C) /* Changed Default + 720p EAVSAV code*/ +#define ADV7343_HD_MODE_REG2_DEFAULT (0x01) /* Changed Pixel data + valid */ +#define ADV7343_HD_MODE_REG3_DEFAULT (0x00) /* Color delay 0 clks */ +#define ADV7343_HD_MODE_REG4_DEFAULT (0xE8) /* Changed */ +#define ADV7343_HD_MODE_REG5_DEFAULT (0x08) +#define ADV7343_HD_MODE_REG6_DEFAULT (0x00) +#define ADV7343_HD_MODE_REG7_DEFAULT (0x00) +#define ADV7343_SD_MODE_REG8_DEFAULT (0x00) +#define ADV7343_SOFT_RESET_DEFAULT (0x02) +#define ADV7343_COMPOSITE_POWER_VALUE (0x80) +#define ADV7343_COMPONENT_POWER_VALUE (0x1C) +#define ADV7343_SVIDEO_POWER_VALUE (0x60) +#define ADV7343_SD_HUE_REG_DEFAULT (127) +#define ADV7343_SD_BRIGHTNESS_WSS_DEFAULT (0x03) + +#define ADV7343_SD_CGMS_WSS0_DEFAULT (0x10) + +#define ADV7343_SD_MODE_REG1_DEFAULT (0x00) +#define ADV7343_SD_MODE_REG2_DEFAULT (0xC9) +#define ADV7343_SD_MODE_REG3_DEFAULT (0x10) +#define ADV7343_SD_MODE_REG4_DEFAULT (0x01) +#define ADV7343_SD_MODE_REG5_DEFAULT (0x02) +#define ADV7343_SD_MODE_REG6_DEFAULT (0x0C) +#define ADV7343_SD_MODE_REG7_DEFAULT (0x04) +#define ADV7343_SD_MODE_REG8_DEFAULT (0x00) + +/* Bit masks for Mode Select Register */ +#define INPUT_MODE_MASK (0x70) +#define SD_INPUT_MODE (0x00) +#define HD_720P_INPUT_MODE (0x10) +#define HD_1080I_INPUT_MODE (0x10) + +/* Bit masks for Mode Register 0 */ +#define TEST_PATTERN_BLACK_BAR_EN (0x04) +#define YUV_OUTPUT_SELECT (0x20) +#define RGB_OUTPUT_SELECT (0xDF) + +/* Bit masks for DAC output levels */ +#define DAC_OUTPUT_LEVEL_MASK (0xFF) +#define POSITIVE_GAIN_MAX (0x40) +#define POSITIVE_GAIN_MIN (0x00) +#define NEGATIVE_GAIN_MAX (0xFF) +#define NEGATIVE_GAIN_MIN (0xC0) + +/* Bit masks for soft reset register */ +#define SOFT_RESET (0x02) + +/* Bit masks for HD Mode Register 1 */ +#define OUTPUT_STD_MASK (0x03) +#define OUTPUT_STD_SHIFT (0) +#define OUTPUT_STD_EIA0_2 (0x00) +#define OUTPUT_STD_EIA0_1 (0x01) +#define OUTPUT_STD_FULL (0x02) +#define EMBEDDED_SYNC (0x04) +#define EXTERNAL_SYNC (0xFB) +#define STD_MODE_SHIFT (3) +#define STD_MODE_MASK (0x1F) +#define STD_MODE_720P (0x05) +#define STD_MODE_720P_25 (0x08) +#define STD_MODE_720P_30 (0x07) +#define STD_MODE_720P_50 (0x06) +#define STD_MODE_1080I (0x0D) +#define STD_MODE_1080I_25fps (0x0E) +#define STD_MODE_1080P_24 (0x12) +#define STD_MODE_1080P_25 (0x10) +#define STD_MODE_1080P_30 (0x0F) +#define STD_MODE_525P (0x00) +#define STD_MODE_625P (0x03) + +/* Bit masks for SD Mode Register 1 */ +#define SD_STD_MASK (0x03) +#define SD_STD_NTSC (0x00) +#define SD_STD_PAL_BDGHI (0x01) +#define SD_STD_PAL_M (0x02) +#define SD_STD_PAL_N (0x03) +#define SD_LUMA_FLTR_MASK (0x7) +#define SD_LUMA_FLTR_SHIFT (0x2) +#define SD_CHROMA_FLTR_MASK (0x7) +#define SD_CHROMA_FLTR_SHIFT (0x5) + +/* Bit masks for SD Mode Register 2 */ +#define SD_PBPR_SSAF_EN (0x01) +#define SD_PBPR_SSAF_DI (0xFE) +#define SD_DAC_1_DI (0xFD) +#define SD_DAC_2_DI (0xFB) +#define SD_PEDESTAL_EN (0x08) +#define SD_PEDESTAL_DI (0xF7) +#define SD_SQUARE_PIXEL_EN (0x10) +#define SD_SQUARE_PIXEL_DI (0xEF) +#define SD_PIXEL_DATA_VALID (0x40) +#define SD_ACTIVE_EDGE_EN (0x80) +#define SD_ACTIVE_EDGE_DI (0x7F) + +/* Bit masks for HD Mode Register 6 */ +#define HD_RGB_INPUT_EN (0x02) +#define HD_RGB_INPUT_DI (0xFD) +#define HD_PBPR_SYNC_EN (0x04) +#define HD_PBPR_SYNC_DI (0xFB) +#define HD_DAC_SWAP_EN (0x08) +#define HD_DAC_SWAP_DI (0xF7) +#define HD_GAMMA_CURVE_A (0xEF) +#define HD_GAMMA_CURVE_B (0x10) +#define HD_GAMMA_EN (0x20) +#define HD_GAMMA_DI (0xDF) +#define HD_ADPT_FLTR_MODEB (0x40) +#define HD_ADPT_FLTR_MODEA (0xBF) +#define HD_ADPT_FLTR_EN (0x80) +#define HD_ADPT_FLTR_DI (0x7F) + +#define ADV7343_BRIGHTNESS_MAX (127) +#define ADV7343_BRIGHTNESS_MIN (0) +#define ADV7343_BRIGHTNESS_DEF (3) +#define ADV7343_HUE_MAX (255) +#define ADV7343_HUE_MIN (0) +#define ADV7343_HUE_DEF (127) +#define ADV7343_GAIN_MAX (255) +#define ADV7343_GAIN_MIN (0) +#define ADV7343_GAIN_DEF (0) + +#endif diff --git a/drivers/media/video/au0828/au0828-cards.c b/drivers/media/video/au0828/au0828-cards.c index 053bbe8c8e3a..830c4a933f63 100644 --- a/drivers/media/video/au0828/au0828-cards.c +++ b/drivers/media/video/au0828/au0828-cards.c @@ -136,9 +136,9 @@ int au0828_tuner_callback(void *priv, int component, int command, int arg) /* Tuner Reset Command from xc5000 */ /* Drive the tuner into reset and out */ au0828_clear(dev, REG_001, 2); - mdelay(200); + mdelay(10); au0828_set(dev, REG_001, 2); - mdelay(50); + mdelay(10); return 0; } else { printk(KERN_ERR diff --git a/drivers/media/video/au0828/au0828-core.c b/drivers/media/video/au0828/au0828-core.c index a1e4c0d769a6..3544a2f12f13 100644 --- a/drivers/media/video/au0828/au0828-core.c +++ b/drivers/media/video/au0828/au0828-core.c @@ -36,6 +36,11 @@ int au0828_debug; module_param_named(debug, au0828_debug, int, 0644); MODULE_PARM_DESC(debug, "enable debug messages"); +static unsigned int disable_usb_speed_check; +module_param(disable_usb_speed_check, int, 0444); +MODULE_PARM_DESC(disable_usb_speed_check, + "override min bandwidth requirement of 480M bps"); + #define _AU0828_BULKPIPE 0x03 #define _BULKPIPESIZE 0xffff @@ -181,6 +186,18 @@ static int au0828_usb_probe(struct usb_interface *interface, le16_to_cpu(usbdev->descriptor.idProduct), ifnum); + /* + * Make sure we have 480 Mbps of bandwidth, otherwise things like + * video stream wouldn't likely work, since 12 Mbps is generally + * not enough even for most Digital TV streams. + */ + if (usbdev->speed != USB_SPEED_HIGH && disable_usb_speed_check == 0) { + printk(KERN_ERR "au0828: Device initialization failed.\n"); + printk(KERN_ERR "au0828: Device must be connected to a " + "high-speed USB 2.0 port.\n"); + return -ENODEV; + } + dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (dev == NULL) { printk(KERN_ERR "%s() Unable to allocate memory\n", __func__); diff --git a/drivers/media/video/au0828/au0828-video.c b/drivers/media/video/au0828/au0828-video.c index 27bedc6c7791..51527d7b55a7 100644 --- a/drivers/media/video/au0828/au0828-video.c +++ b/drivers/media/video/au0828/au0828-video.c @@ -829,6 +829,9 @@ static int au0828_v4l2_close(struct file *filp) au0828_uninit_isoc(dev); + /* Save some power by putting tuner to sleep */ + v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_standby); + /* When close the device, set the usb intf0 into alt0 to free USB bandwidth */ ret = usb_set_interface(dev->usbdev, 0, 0); @@ -910,11 +913,6 @@ static int au0828_v4l2_mmap(struct file *filp, struct vm_area_struct *vma) rc = videobuf_mmap_mapper(&fh->vb_vidq, vma); - dprintk(2, "vma start=0x%08lx, size=%ld, ret=%d\n", - (unsigned long)vma->vm_start, - (unsigned long)vma->vm_end-(unsigned long)vma->vm_start, - rc); - return rc; } diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index 23b7499b3185..5eb1464af670 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -3152,6 +3152,7 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait) struct bttv_fh *fh = file->private_data; struct bttv_buffer *buf; enum v4l2_field field; + unsigned int rc = POLLERR; if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) { if (!check_alloc_btres(fh->btv,fh,RESOURCE_VBI)) @@ -3160,9 +3161,10 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait) } if (check_btres(fh,RESOURCE_VIDEO_STREAM)) { + mutex_lock(&fh->cap.vb_lock); /* streaming capture */ if (list_empty(&fh->cap.stream)) - return POLLERR; + goto err; buf = list_entry(fh->cap.stream.next,struct bttv_buffer,vb.stream); } else { /* read() capture */ @@ -3191,11 +3193,12 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait) poll_wait(file, &buf->vb.done, wait); if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR) - return POLLIN|POLLRDNORM; - return 0; + rc = POLLIN|POLLRDNORM; + else + rc = 0; err: mutex_unlock(&fh->cap.vb_lock); - return POLLERR; + return rc; } static int bttv_open(struct file *file) @@ -4166,7 +4169,6 @@ static struct video_device *vdev_init(struct bttv *btv, if (NULL == vfd) return NULL; *vfd = *template; - vfd->minor = -1; vfd->v4l2_dev = &btv->c.v4l2_dev; vfd->release = video_device_release; vfd->debug = bttv_debug; @@ -4629,7 +4631,7 @@ static int __init bttv_init_module(void) #endif if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME) gbuffers = 2; - if (gbufsize < 0 || gbufsize > BTTV_MAX_FBUF) + if (gbufsize > BTTV_MAX_FBUF) gbufsize = BTTV_MAX_FBUF; gbufsize = (gbufsize + PAGE_SIZE - 1) & PAGE_MASK; if (bttv_verbose) diff --git a/drivers/media/video/bt8xx/bttv-i2c.c b/drivers/media/video/bt8xx/bttv-i2c.c index a99d92fac3dc..ebd1ee9dc871 100644 --- a/drivers/media/video/bt8xx/bttv-i2c.c +++ b/drivers/media/video/bt8xx/bttv-i2c.c @@ -389,6 +389,27 @@ int __devinit init_bttv_i2c(struct bttv *btv) } if (0 == btv->i2c_rc && i2c_scan) do_i2c_scan(btv->c.v4l2_dev.name, &btv->i2c_client); + + /* Instantiate the IR receiver device, if present */ + if (0 == btv->i2c_rc) { + struct i2c_board_info info; + /* The external IR receiver is at i2c address 0x34 (0x35 for + reads). Future Hauppauge cards will have an internal + receiver at 0x30 (0x31 for reads). In theory, both can be + fitted, and Hauppauge suggest an external overrides an + internal. + + That's why we probe 0x1a (~0x34) first. CB + */ + const unsigned short addr_list[] = { + 0x1a, 0x18, 0x4b, 0x64, 0x30, + I2C_CLIENT_END + }; + + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "ir_video", I2C_NAME_SIZE); + i2c_new_probed_device(&btv->c.i2c_adap, &info, addr_list); + } return btv->i2c_rc; } diff --git a/drivers/media/video/cpia2/cpia2_v4l.c b/drivers/media/video/cpia2/cpia2_v4l.c index d4099f5312ac..0b4a8f309cfa 100644 --- a/drivers/media/video/cpia2/cpia2_v4l.c +++ b/drivers/media/video/cpia2/cpia2_v4l.c @@ -1064,7 +1064,7 @@ static int ioctl_querymenu(void *arg,struct camera_data *cam) switch(m->id) { case CPIA2_CID_FLICKER_MODE: - if(m->index < 0 || m->index >= NUM_FLICKER_CONTROLS) + if (m->index >= NUM_FLICKER_CONTROLS) return -EINVAL; strcpy(m->name, flicker_controls[m->index].name); @@ -1082,14 +1082,14 @@ static int ioctl_querymenu(void *arg,struct camera_data *cam) maximum = i; } } - if(m->index < 0 || m->index > maximum) + if (m->index > maximum) return -EINVAL; strcpy(m->name, framerate_controls[m->index].name); break; } case CPIA2_CID_LIGHTS: - if(m->index < 0 || m->index >= NUM_LIGHTS_CONTROLS) + if (m->index >= NUM_LIGHTS_CONTROLS) return -EINVAL; strcpy(m->name, lights_controls[m->index].name); diff --git a/drivers/media/video/cx18/cx18-audio.c b/drivers/media/video/cx18/cx18-audio.c index 7a8ad5963de8..35268923911c 100644 --- a/drivers/media/video/cx18/cx18-audio.c +++ b/drivers/media/video/cx18/cx18-audio.c @@ -26,14 +26,18 @@ #include "cx18-cards.h" #include "cx18-audio.h" -#define CX18_AUDIO_ENABLE 0xc72014 +#define CX18_AUDIO_ENABLE 0xc72014 +#define CX18_AI1_MUX_MASK 0x30 +#define CX18_AI1_MUX_I2S1 0x00 +#define CX18_AI1_MUX_I2S2 0x10 +#define CX18_AI1_MUX_843_I2S 0x20 /* Selects the audio input and output according to the current settings. */ int cx18_audio_set_io(struct cx18 *cx) { const struct cx18_card_audio_input *in; - u32 val; + u32 u, v; int err; /* Determine which input to use */ @@ -52,9 +56,37 @@ int cx18_audio_set_io(struct cx18 *cx) return err; /* FIXME - this internal mux should be abstracted to a subdev */ - val = cx18_read_reg(cx, CX18_AUDIO_ENABLE) & ~0x30; - val |= (in->audio_input > CX18_AV_AUDIO_SERIAL2) ? 0x20 : - (in->audio_input << 4); - cx18_write_reg_expect(cx, val | 0xb00, CX18_AUDIO_ENABLE, val, 0x30); + u = cx18_read_reg(cx, CX18_AUDIO_ENABLE); + v = u & ~CX18_AI1_MUX_MASK; + switch (in->audio_input) { + case CX18_AV_AUDIO_SERIAL1: + v |= CX18_AI1_MUX_I2S1; + break; + case CX18_AV_AUDIO_SERIAL2: + v |= CX18_AI1_MUX_I2S2; + break; + default: + v |= CX18_AI1_MUX_843_I2S; + break; + } + if (v == u) { + /* force a toggle of some AI1 MUX control bits */ + u &= ~CX18_AI1_MUX_MASK; + switch (in->audio_input) { + case CX18_AV_AUDIO_SERIAL1: + u |= CX18_AI1_MUX_843_I2S; + break; + case CX18_AV_AUDIO_SERIAL2: + u |= CX18_AI1_MUX_843_I2S; + break; + default: + u |= CX18_AI1_MUX_I2S1; + break; + } + cx18_write_reg_expect(cx, u | 0xb00, CX18_AUDIO_ENABLE, + u, CX18_AI1_MUX_MASK); + } + cx18_write_reg_expect(cx, v | 0xb00, CX18_AUDIO_ENABLE, + v, CX18_AI1_MUX_MASK); return 0; } diff --git a/drivers/media/video/cx18/cx18-av-core.c b/drivers/media/video/cx18/cx18-av-core.c index cf2bd888a429..536dedb23ba3 100644 --- a/drivers/media/video/cx18/cx18-av-core.c +++ b/drivers/media/video/cx18/cx18-av-core.c @@ -99,9 +99,39 @@ int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 and_mask, or_value); } -static void cx18_av_initialize(struct cx18 *cx) +static int cx18_av_init(struct v4l2_subdev *sd, u32 val) { - struct cx18_av_state *state = &cx->av_state; + struct cx18 *cx = v4l2_get_subdevdata(sd); + + /* + * The crystal freq used in calculations in this driver will be + * 28.636360 MHz. + * Aim to run the PLLs' VCOs near 400 MHz to minimze errors. + */ + + /* + * VDCLK Integer = 0x0f, Post Divider = 0x04 + * AIMCLK Integer = 0x0e, Post Divider = 0x16 + */ + cx18_av_write4(cx, CXADEC_PLL_CTRL1, 0x160e040f); + + /* VDCLK Fraction = 0x2be2fe */ + /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz before post divide */ + cx18_av_write4(cx, CXADEC_VID_PLL_FRAC, 0x002be2fe); + + /* AIMCLK Fraction = 0x05227ad */ + /* xtal * 0xe.2913d68/0x16 = 48000 * 384: 406 MHz pre post-div*/ + cx18_av_write4(cx, CXADEC_AUX_PLL_FRAC, 0x005227ad); + + /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x16 */ + cx18_av_write(cx, CXADEC_I2S_MCLK, 0x56); + return 0; +} + +static void cx18_av_initialize(struct v4l2_subdev *sd) +{ + struct cx18_av_state *state = to_cx18_av_state(sd); + struct cx18 *cx = v4l2_get_subdevdata(sd); u32 v; cx18_av_loadfw(cx); @@ -150,6 +180,26 @@ static void cx18_av_initialize(struct cx18 *cx) cx18_av_write4(cx, CXADEC_SOFT_RST_CTRL, 0x8000); cx18_av_write4(cx, CXADEC_SOFT_RST_CTRL, 0); + /* + * Disable Video Auto-config of the Analog Front End and Video PLL. + * + * Since we only use BT.656 pixel mode, which works for both 525 and 625 + * line systems, it's just easier for us to set registers + * 0x102 (CXADEC_CHIP_CTRL), 0x104-0x106 (CXADEC_AFE_CTRL), + * 0x108-0x109 (CXADEC_PLL_CTRL1), and 0x10c-0x10f (CXADEC_VID_PLL_FRAC) + * ourselves, than to run around cleaning up after the auto-config. + * + * (Note: my CX23418 chip doesn't seem to let the ACFG_DIS bit + * get set to 1, but OTOH, it doesn't seem to do AFE and VID PLL + * autoconfig either.) + * + * As a default, also turn off Dual mode for ADC2 and set ADC2 to CH3. + */ + cx18_av_and_or4(cx, CXADEC_CHIP_CTRL, 0xFFFBFFFF, 0x00120000); + + /* Setup the Video and and Aux/Audio PLLs */ + cx18_av_init(sd, 0); + /* set video to auto-detect */ /* Clear bits 11-12 to enable slow locking mode. Set autodetect mode */ /* set the comb notch = 1 */ @@ -176,12 +226,23 @@ static void cx18_av_initialize(struct cx18 *cx) /* EncSetSignalStd(dwDevNum, pEnc->dwSigStd); */ /* EncSetVideoInput(dwDevNum, pEnc->VidIndSelection); */ - v = cx18_av_read4(cx, CXADEC_AFE_CTRL); - v &= 0xFFFBFFFF; /* turn OFF bit 18 for droop_comp_ch1 */ - v &= 0xFFFF7FFF; /* turn OFF bit 9 for clamp_sel_ch1 */ - v &= 0xFFFFFFFE; /* turn OFF bit 0 for 12db_ch1 */ - /* v |= 0x00000001;*/ /* turn ON bit 0 for 12db_ch1 */ - cx18_av_write4(cx, CXADEC_AFE_CTRL, v); + /* + * Analog Front End (AFE) + * Default to luma on ch1/ADC1, chroma on ch2/ADC2, SIF on ch3/ADC2 + * bypass_ch[1-3] use filter + * droop_comp_ch[1-3] disable + * clamp_en_ch[1-3] disable + * aud_in_sel ADC2 + * luma_in_sel ADC1 + * chroma_in_sel ADC2 + * clamp_sel_ch[2-3] midcode + * clamp_sel_ch1 video decoder + * vga_sel_ch3 audio decoder + * vga_sel_ch[1-2] video decoder + * half_bw_ch[1-3] disable + * +12db_ch[1-3] disable + */ + cx18_av_and_or4(cx, CXADEC_AFE_CTRL, 0xFF000000, 0x00005D00); /* if(dwEnable && dw3DCombAvailable) { */ /* CxDevWrReg(CXADEC_SRC_COMB_CFG, 0x7728021F); */ @@ -195,50 +256,18 @@ static void cx18_av_initialize(struct cx18 *cx) static int cx18_av_reset(struct v4l2_subdev *sd, u32 val) { - struct cx18 *cx = v4l2_get_subdevdata(sd); - - cx18_av_initialize(cx); - return 0; -} - -static int cx18_av_init(struct v4l2_subdev *sd, u32 val) -{ - struct cx18 *cx = v4l2_get_subdevdata(sd); - - /* - * The crystal freq used in calculations in this driver will be - * 28.636360 MHz. - * Aim to run the PLLs' VCOs near 400 MHz to minimze errors. - */ - - /* - * VDCLK Integer = 0x0f, Post Divider = 0x04 - * AIMCLK Integer = 0x0e, Post Divider = 0x16 - */ - cx18_av_write4(cx, CXADEC_PLL_CTRL1, 0x160e040f); - - /* VDCLK Fraction = 0x2be2fe */ - /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz before post divide */ - cx18_av_write4(cx, CXADEC_VID_PLL_FRAC, 0x002be2fe); - - /* AIMCLK Fraction = 0x05227ad */ - /* xtal * 0xe.2913d68/0x16 = 48000 * 384: 406 MHz pre post-div*/ - cx18_av_write4(cx, CXADEC_AUX_PLL_FRAC, 0x005227ad); - - /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x16 */ - cx18_av_write(cx, CXADEC_I2S_MCLK, 0x56); + cx18_av_initialize(sd); return 0; } static int cx18_av_load_fw(struct v4l2_subdev *sd) { struct cx18_av_state *state = to_cx18_av_state(sd); - struct cx18 *cx = v4l2_get_subdevdata(sd); if (!state->is_initialized) { /* initialize on first use */ state->is_initialized = 1; - cx18_av_initialize(cx); + cx18_av_initialize(sd); } return 0; } @@ -248,8 +277,15 @@ void cx18_av_std_setup(struct cx18 *cx) struct cx18_av_state *state = &cx->av_state; struct v4l2_subdev *sd = &state->sd; v4l2_std_id std = state->std; + + /* + * Video ADC crystal clock to pixel clock SRC decimation ratio + * 28.636360 MHz/13.5 Mpps * 256 = 0x21f.07b + */ + const int src_decimation = 0x21f; + int hblank, hactive, burst, vblank, vactive, sc; - int vblank656, src_decimation; + int vblank656; int luma_lpf, uv_lpf, comb; u32 pll_int, pll_frac, pll_post; @@ -259,40 +295,96 @@ void cx18_av_std_setup(struct cx18 *cx) else cx18_av_write(cx, 0x49f, 0x14); + /* + * Note: At the end of a field, there are 3 sets of half line duration + * (double horizontal rate) pulses: + * + * 5 (625) or 6 (525) half-lines to blank for the vertical retrace + * 5 (625) or 6 (525) vertical sync pulses of half line duration + * 5 (625) or 6 (525) half-lines of equalization pulses + */ if (std & V4L2_STD_625_50) { - /* FIXME - revisit these for Sliced VBI */ + /* + * The following relationships of half line counts should hold: + * 625 = vblank656 + vactive + * 10 = vblank656 - vblank = vsync pulses + equalization pulses + * + * vblank656: half lines after line 625/mid-313 of blanked video + * vblank: half lines, after line 5/317, of blanked video + * vactive: half lines of active video + + * 5 half lines after the end of active video + * + * As far as I can tell: + * vblank656 starts counting from the falling edge of the first + * vsync pulse (start of line 1 or mid-313) + * vblank starts counting from the after the 5 vsync pulses and + * 5 or 4 equalization pulses (start of line 6 or 318) + * + * For 625 line systems the driver will extract VBI information + * from lines 6-23 and lines 318-335 (but the slicer can only + * handle 17 lines, not the 18 in the vblank region). + * In addition, we need vblank656 and vblank to be one whole + * line longer, to cover line 24 and 336, so the SAV/EAV RP + * codes get generated such that the encoder can actually + * extract line 23 & 335 (WSS). We'll lose 1 line in each field + * at the top of the screen. + * + * It appears the 5 half lines that happen after active + * video must be included in vactive (579 instead of 574), + * otherwise the colors get badly displayed in various regions + * of the screen. I guess the chroma comb filter gets confused + * without them (at least when a PVR-350 is the PAL source). + */ + vblank656 = 48; /* lines 1 - 24 & 313 - 336 */ + vblank = 38; /* lines 6 - 24 & 318 - 336 */ + vactive = 579; /* lines 24 - 313 & 337 - 626 */ + + /* + * For a 13.5 Mpps clock and 15,625 Hz line rate, a line is + * is 864 pixels = 720 active + 144 blanking. ITU-R BT.601 + * specifies 12 luma clock periods or ~ 0.9 * 13.5 Mpps after + * the end of active video to start a horizontal line, so that + * leaves 132 pixels of hblank to ignore. + */ hblank = 132; hactive = 720; - burst = 93; - vblank = 36; - vactive = 580; - vblank656 = 40; - src_decimation = 0x21f; + /* + * Burst gate delay (for 625 line systems) + * Hsync leading edge to color burst rise = 5.6 us + * Color burst width = 2.25 us + * Gate width = 4 pixel clocks + * (5.6 us + 2.25/2 us) * 13.5 Mpps + 4/2 clocks = 92.79 clocks + */ + burst = 93; luma_lpf = 2; if (std & V4L2_STD_PAL) { uv_lpf = 1; comb = 0x20; - sc = 688739; + /* sc = 4433618.75 * src_decimation/28636360 * 2^13 */ + sc = 688700; } else if (std == V4L2_STD_PAL_Nc) { uv_lpf = 1; comb = 0x20; - sc = 556453; + /* sc = 3582056.25 * src_decimation/28636360 * 2^13 */ + sc = 556422; } else { /* SECAM */ uv_lpf = 0; comb = 0; - sc = 672351; + /* (fr + fb)/2 = (4406260 + 4250000)/2 = 4328130 */ + /* sc = 4328130 * src_decimation/28636360 * 2^13 */ + sc = 672314; } } else { /* * The following relationships of half line counts should hold: - * 525 = vsync + vactive + vblank656 - * 12 = vblank656 - vblank + * 525 = prevsync + vblank656 + vactive + * 12 = vblank656 - vblank = vsync pulses + equalization pulses * - * vsync: always 6 half-lines of vsync pulses - * vactive: half lines of active video + * prevsync: 6 half-lines before the vsync pulses * vblank656: half lines, after line 3/mid-266, of blanked video * vblank: half lines, after line 9/272, of blanked video + * vactive: half lines of active video * * As far as I can tell: * vblank656 starts counting from the falling edge of the first @@ -319,20 +411,30 @@ void cx18_av_std_setup(struct cx18 *cx) luma_lpf = 1; uv_lpf = 1; - src_decimation = 0x21f; + /* + * Burst gate delay (for 525 line systems) + * Hsync leading edge to color burst rise = 5.3 us + * Color burst width = 2.5 us + * Gate width = 4 pixel clocks + * (5.3 us + 2.5/2 us) * 13.5 Mpps + 4/2 clocks = 90.425 clocks + */ if (std == V4L2_STD_PAL_60) { - burst = 0x5b; + burst = 90; luma_lpf = 2; comb = 0x20; - sc = 688739; + /* sc = 4433618.75 * src_decimation/28636360 * 2^13 */ + sc = 688700; } else if (std == V4L2_STD_PAL_M) { - burst = 0x61; + /* The 97 needs to be verified against PAL-M timings */ + burst = 97; comb = 0x20; - sc = 555452; + /* sc = 3575611.49 * src_decimation/28636360 * 2^13 */ + sc = 555421; } else { - burst = 0x5b; + burst = 90; comb = 0x66; - sc = 556063; + /* sc = 3579545.45.. * src_decimation/28636360 * 2^13 */ + sc = 556032; } } @@ -344,23 +446,26 @@ void cx18_av_std_setup(struct cx18 *cx) pll_int, pll_frac, pll_post); if (pll_post) { - int fin, fsc, pll; + int fsc, pll; + u64 tmp; pll = (28636360L * ((((u64)pll_int) << 25) + pll_frac)) >> 25; pll /= pll_post; - CX18_DEBUG_INFO_DEV(sd, "PLL = %d.%06d MHz\n", + CX18_DEBUG_INFO_DEV(sd, "Video PLL = %d.%06d MHz\n", pll / 1000000, pll % 1000000); - CX18_DEBUG_INFO_DEV(sd, "PLL/8 = %d.%06d MHz\n", + CX18_DEBUG_INFO_DEV(sd, "Pixel rate = %d.%06d Mpixel/sec\n", pll / 8000000, (pll / 8) % 1000000); - fin = ((u64)src_decimation * pll) >> 12; - CX18_DEBUG_INFO_DEV(sd, "ADC Sampling freq = %d.%06d MHz\n", - fin / 1000000, fin % 1000000); + CX18_DEBUG_INFO_DEV(sd, "ADC XTAL/pixel clock decimation ratio " + "= %d.%03d\n", src_decimation / 256, + ((src_decimation % 256) * 1000) / 256); - fsc = (((u64)sc) * pll) >> 24L; + tmp = 28636360 * (u64) sc; + do_div(tmp, src_decimation); + fsc = tmp >> 13; CX18_DEBUG_INFO_DEV(sd, - "Chroma sub-carrier freq = %d.%06d MHz\n", - fsc / 1000000, fsc % 1000000); + "Chroma sub-carrier initial freq = %d.%06d " + "MHz\n", fsc / 1000000, fsc % 1000000); CX18_DEBUG_INFO_DEV(sd, "hblank %i, hactive %i, vblank %i, " "vactive %i, vblank656 %i, src_dec %i, " @@ -470,16 +575,23 @@ static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input, { struct cx18_av_state *state = &cx->av_state; struct v4l2_subdev *sd = &state->sd; - u8 is_composite = (vid_input >= CX18_AV_COMPOSITE1 && - vid_input <= CX18_AV_COMPOSITE8); - u8 reg; - u8 v; + + enum analog_signal_type { + NONE, CVBS, Y, C, SIF, Pb, Pr + } ch[3] = {NONE, NONE, NONE}; + + u8 afe_mux_cfg; + u8 adc2_cfg; + u32 afe_cfg; + int i; CX18_DEBUG_INFO_DEV(sd, "decoder set video input %d, audio input %d\n", vid_input, aud_input); - if (is_composite) { - reg = 0xf0 + (vid_input - CX18_AV_COMPOSITE1); + if (vid_input >= CX18_AV_COMPOSITE1 && + vid_input <= CX18_AV_COMPOSITE8) { + afe_mux_cfg = 0xf0 + (vid_input - CX18_AV_COMPOSITE1); + ch[0] = CVBS; } else { int luma = vid_input & 0xf0; int chroma = vid_input & 0xf00; @@ -493,26 +605,45 @@ static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input, vid_input); return -EINVAL; } - reg = 0xf0 + ((luma - CX18_AV_SVIDEO_LUMA1) >> 4); + afe_mux_cfg = 0xf0 + ((luma - CX18_AV_SVIDEO_LUMA1) >> 4); + ch[0] = Y; if (chroma >= CX18_AV_SVIDEO_CHROMA7) { - reg &= 0x3f; - reg |= (chroma - CX18_AV_SVIDEO_CHROMA7) >> 2; + afe_mux_cfg &= 0x3f; + afe_mux_cfg |= (chroma - CX18_AV_SVIDEO_CHROMA7) >> 2; + ch[2] = C; } else { - reg &= 0xcf; - reg |= (chroma - CX18_AV_SVIDEO_CHROMA4) >> 4; + afe_mux_cfg &= 0xcf; + afe_mux_cfg |= (chroma - CX18_AV_SVIDEO_CHROMA4) >> 4; + ch[1] = C; } } + /* TODO: LeadTek WinFast DVR3100 H & WinFast PVR2100 can do Y/Pb/Pr */ switch (aud_input) { case CX18_AV_AUDIO_SERIAL1: case CX18_AV_AUDIO_SERIAL2: /* do nothing, use serial audio input */ break; - case CX18_AV_AUDIO4: reg &= ~0x30; break; - case CX18_AV_AUDIO5: reg &= ~0x30; reg |= 0x10; break; - case CX18_AV_AUDIO6: reg &= ~0x30; reg |= 0x20; break; - case CX18_AV_AUDIO7: reg &= ~0xc0; break; - case CX18_AV_AUDIO8: reg &= ~0xc0; reg |= 0x40; break; + case CX18_AV_AUDIO4: + afe_mux_cfg &= ~0x30; + ch[1] = SIF; + break; + case CX18_AV_AUDIO5: + afe_mux_cfg = (afe_mux_cfg & ~0x30) | 0x10; + ch[1] = SIF; + break; + case CX18_AV_AUDIO6: + afe_mux_cfg = (afe_mux_cfg & ~0x30) | 0x20; + ch[1] = SIF; + break; + case CX18_AV_AUDIO7: + afe_mux_cfg &= ~0xc0; + ch[2] = SIF; + break; + case CX18_AV_AUDIO8: + afe_mux_cfg = (afe_mux_cfg & ~0xc0) | 0x40; + ch[2] = SIF; + break; default: CX18_ERR_DEV(sd, "0x%04x is not a valid audio input!\n", @@ -520,24 +651,65 @@ static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input, return -EINVAL; } - cx18_av_write_expect(cx, 0x103, reg, reg, 0xf7); + /* Set up analog front end multiplexers */ + cx18_av_write_expect(cx, 0x103, afe_mux_cfg, afe_mux_cfg, 0xf7); /* Set INPUT_MODE to Composite (0) or S-Video (1) */ - cx18_av_and_or(cx, 0x401, ~0x6, is_composite ? 0 : 0x02); + cx18_av_and_or(cx, 0x401, ~0x6, ch[0] == CVBS ? 0 : 0x02); /* Set CH_SEL_ADC2 to 1 if input comes from CH3 */ - v = cx18_av_read(cx, 0x102); - if (reg & 0x80) - v &= ~0x2; + adc2_cfg = cx18_av_read(cx, 0x102); + if (ch[2] == NONE) + adc2_cfg &= ~0x2; /* No sig on CH3, set ADC2 to CH2 for input */ else - v |= 0x2; - /* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2 and CH3 */ - if ((reg & 0xc0) != 0xc0 && (reg & 0x30) != 0x30) - v |= 0x4; - else - v &= ~0x4; - cx18_av_write_expect(cx, 0x102, v, v, 0x17); + adc2_cfg |= 0x2; /* Signal on CH3, set ADC2 to CH3 for input */ - /*cx18_av_and_or4(cx, 0x104, ~0x001b4180, 0x00004180);*/ + /* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2 and CH3 */ + if (ch[1] != NONE && ch[2] != NONE) + adc2_cfg |= 0x4; /* Set dual mode */ + else + adc2_cfg &= ~0x4; /* Clear dual mode */ + cx18_av_write_expect(cx, 0x102, adc2_cfg, adc2_cfg, 0x17); + + /* Configure the analog front end */ + afe_cfg = cx18_av_read4(cx, CXADEC_AFE_CTRL); + afe_cfg &= 0xff000000; + afe_cfg |= 0x00005000; /* CHROMA_IN, AUD_IN: ADC2; LUMA_IN: ADC1 */ + if (ch[1] != NONE && ch[2] != NONE) + afe_cfg |= 0x00000030; /* half_bw_ch[2-3] since in dual mode */ + + for (i = 0; i < 3; i++) { + switch (ch[i]) { + default: + case NONE: + /* CLAMP_SEL = Fixed to midcode clamp level */ + afe_cfg |= (0x00000200 << i); + break; + case CVBS: + case Y: + if (i > 0) + afe_cfg |= 0x00002000; /* LUMA_IN_SEL: ADC2 */ + break; + case C: + case Pb: + case Pr: + /* CLAMP_SEL = Fixed to midcode clamp level */ + afe_cfg |= (0x00000200 << i); + if (i == 0 && ch[i] == C) + afe_cfg &= ~0x00001000; /* CHROMA_IN_SEL ADC1 */ + break; + case SIF: + /* + * VGA_GAIN_SEL = Audio Decoder + * CLAMP_SEL = Fixed to midcode clamp level + */ + afe_cfg |= (0x00000240 << i); + if (i == 0) + afe_cfg &= ~0x00004000; /* AUD_IN_SEL ADC1 */ + break; + } + } + + cx18_av_write4(cx, CXADEC_AFE_CTRL, afe_cfg); state->vid_input = vid_input; state->aud_input = aud_input; @@ -858,9 +1030,9 @@ static int cx18_av_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) * cx18_av_std_setup(), above standard values: * * 480 + 1 for 60 Hz systems - * 576 + 4 for 50 Hz systems + * 576 + 3 for 50 Hz systems */ - Vlines = pix->height + (is_50Hz ? 4 : 1); + Vlines = pix->height + (is_50Hz ? 3 : 1); /* * Invalid height and width scaling requests are: diff --git a/drivers/media/video/cx18/cx18-av-firmware.c b/drivers/media/video/cx18/cx18-av-firmware.c index 49a55cc8d839..b9e8cc5d264a 100644 --- a/drivers/media/video/cx18/cx18-av-firmware.c +++ b/drivers/media/video/cx18/cx18-av-firmware.c @@ -24,15 +24,63 @@ #include "cx18-io.h" #include -#define CX18_AUDIO_ENABLE 0xc72014 +#define CX18_AUDIO_ENABLE 0xc72014 +#define CX18_AI1_MUX_MASK 0x30 +#define CX18_AI1_MUX_I2S1 0x00 +#define CX18_AI1_MUX_I2S2 0x10 +#define CX18_AI1_MUX_843_I2S 0x20 +#define CX18_AI1_MUX_INVALID 0x30 + #define FWFILE "v4l-cx23418-dig.fw" +static int cx18_av_verifyfw(struct cx18 *cx, const struct firmware *fw) +{ + struct v4l2_subdev *sd = &cx->av_state.sd; + int ret = 0; + const u8 *data; + u32 size; + int addr; + u32 expected, dl_control; + + /* Ensure we put the 8051 in reset and enable firmware upload mode */ + dl_control = cx18_av_read4(cx, CXADEC_DL_CTL); + do { + dl_control &= 0x00ffffff; + dl_control |= 0x0f000000; + cx18_av_write4_noretry(cx, CXADEC_DL_CTL, dl_control); + dl_control = cx18_av_read4(cx, CXADEC_DL_CTL); + } while ((dl_control & 0xff000000) != 0x0f000000); + + /* Read and auto increment until at address 0x0000 */ + while (dl_control & 0x3fff) + dl_control = cx18_av_read4(cx, CXADEC_DL_CTL); + + data = fw->data; + size = fw->size; + for (addr = 0; addr < size; addr++) { + dl_control &= 0xffff3fff; /* ignore top 2 bits of address */ + expected = 0x0f000000 | ((u32)data[addr] << 16) | addr; + if (expected != dl_control) { + CX18_ERR_DEV(sd, "verification of %s firmware load " + "failed: expected %#010x got %#010x\n", + FWFILE, expected, dl_control); + ret = -EIO; + break; + } + dl_control = cx18_av_read4(cx, CXADEC_DL_CTL); + } + if (ret == 0) + CX18_INFO_DEV(sd, "verified load of %s firmware (%d bytes)\n", + FWFILE, size); + return ret; +} + int cx18_av_loadfw(struct cx18 *cx) { struct v4l2_subdev *sd = &cx->av_state.sd; const struct firmware *fw = NULL; u32 size; - u32 v; + u32 u, v; const u8 *ptr; int i; int retries1 = 0; @@ -95,6 +143,12 @@ int cx18_av_loadfw(struct cx18 *cx) } cx18_av_write4_expect(cx, CXADEC_DL_CTL, + 0x03000000 | fw->size, 0x03000000, 0x13000000); + + CX18_INFO_DEV(sd, "loaded %s firmware (%d bytes)\n", FWFILE, size); + + if (cx18_av_verifyfw(cx, fw) == 0) + cx18_av_write4_expect(cx, CXADEC_DL_CTL, 0x13000000 | fw->size, 0x13000000, 0x13000000); /* Output to the 416 */ @@ -135,6 +189,28 @@ int cx18_av_loadfw(struct cx18 *cx) cx18_write_reg_expect(cx, v & 0xFFFFFBFF, CX18_AUDIO_ENABLE, 0, 0x400); + /* Toggle the AI1 MUX */ + v = cx18_read_reg(cx, CX18_AUDIO_ENABLE); + u = v & CX18_AI1_MUX_MASK; + v &= ~CX18_AI1_MUX_MASK; + if (u == CX18_AI1_MUX_843_I2S || u == CX18_AI1_MUX_INVALID) { + /* Switch to I2S1 */ + v |= CX18_AI1_MUX_I2S1; + cx18_write_reg_expect(cx, v | 0xb00, CX18_AUDIO_ENABLE, + v, CX18_AI1_MUX_MASK); + /* Switch back to the A/V decoder core I2S output */ + v = (v & ~CX18_AI1_MUX_MASK) | CX18_AI1_MUX_843_I2S; + } else { + /* Switch to the A/V decoder core I2S output */ + v |= CX18_AI1_MUX_843_I2S; + cx18_write_reg_expect(cx, v | 0xb00, CX18_AUDIO_ENABLE, + v, CX18_AI1_MUX_MASK); + /* Switch back to I2S1 or I2S2 */ + v = (v & ~CX18_AI1_MUX_MASK) | u; + } + cx18_write_reg_expect(cx, v | 0xb00, CX18_AUDIO_ENABLE, + v, CX18_AI1_MUX_MASK); + /* Enable WW auto audio standard detection */ v = cx18_av_read4(cx, CXADEC_STD_DET_CTL); v |= 0xFF; /* Auto by default */ @@ -143,7 +219,5 @@ int cx18_av_loadfw(struct cx18 *cx) cx18_av_write4_expect(cx, CXADEC_STD_DET_CTL, v, v, 0x3F00FFFF); release_firmware(fw); - - CX18_INFO_DEV(sd, "loaded %s firmware (%d bytes)\n", FWFILE, size); return 0; } diff --git a/drivers/media/video/cx18/cx18-av-vbi.c b/drivers/media/video/cx18/cx18-av-vbi.c index 23b31670bf1d..a51732bcca4b 100644 --- a/drivers/media/video/cx18/cx18-av-vbi.c +++ b/drivers/media/video/cx18/cx18-av-vbi.c @@ -255,8 +255,8 @@ int cx18_av_vbi_s_fmt(struct cx18 *cx, struct v4l2_format *fmt) } cx18_av_write(cx, 0x43c, 0x16); - /* FIXME - should match vblank set in cx18_av_std_setup() */ - cx18_av_write(cx, 0x474, is_pal ? 0x2a : 26); + /* Should match vblank set in cx18_av_std_setup() */ + cx18_av_write(cx, 0x474, is_pal ? 38 : 26); return 0; } diff --git a/drivers/media/video/cx18/cx18-cards.c b/drivers/media/video/cx18/cx18-cards.c index 9bc221837847..c92a25036f0e 100644 --- a/drivers/media/video/cx18/cx18-cards.c +++ b/drivers/media/video/cx18/cx18-cards.c @@ -340,13 +340,12 @@ static const struct cx18_card cx18_card_toshiba_qosmio_dvbt = { static const struct cx18_card_pci_info cx18_pci_leadtek_pvr2100[] = { { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_LEADTEK, 0x6f27 }, /* PVR2100 */ - { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_LEADTEK, 0x6690 }, /* DVR3100 H */ { 0, 0, 0 } }; static const struct cx18_card cx18_card_leadtek_pvr2100 = { .type = CX18_CARD_LEADTEK_PVR2100, - .name = "Leadtek WinFast PVR2100/DVR3100 H", + .name = "Leadtek WinFast PVR2100", .comment = "Experimenters and photos needed for device to work well.\n" "\tTo help, mail the ivtv-devel list (www.ivtvdriver.org).\n", .v4l2_capabilities = CX18_CAP_ENCODER, @@ -365,15 +364,12 @@ static const struct cx18_card cx18_card_leadtek_pvr2100 = { { CX18_CARD_INPUT_LINE_IN1, CX18_AV_AUDIO_SERIAL1, 1 }, }, .tuners = { - /* XC3028 tuner */ + /* XC2028 tuner */ { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, }, .radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 2 }, .ddr = { - /* - * Pointer to proper DDR config values provided by - * Terry Wu - */ + /* Pointer to proper DDR config values provided by Terry Wu */ .chip_config = 0x303, .refresh = 0x3bb, .timing1 = 0x24220e83, @@ -392,6 +388,58 @@ static const struct cx18_card cx18_card_leadtek_pvr2100 = { /* ------------------------------------------------------------------------- */ +/* Leadtek WinFast DVR3100 H */ + +static const struct cx18_card_pci_info cx18_pci_leadtek_dvr3100h[] = { + { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_LEADTEK, 0x6690 }, /* DVR3100 H */ + { 0, 0, 0 } +}; + +static const struct cx18_card cx18_card_leadtek_dvr3100h = { + .type = CX18_CARD_LEADTEK_DVR3100H, + .name = "Leadtek WinFast DVR3100 H", + .comment = "Simultaneous DVB-T and Analog capture supported,\n" + "\texcept when capturing Analog from the antenna input.\n", + .v4l2_capabilities = CX18_CAP_ENCODER, + .hw_audio_ctrl = CX18_HW_418_AV, + .hw_muxer = CX18_HW_GPIO_MUX, + .hw_all = CX18_HW_418_AV | CX18_HW_TUNER | CX18_HW_GPIO_MUX | + CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL, + .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_COMPOSITE7 }, + }, + .audio_inputs = { + { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 0 }, + { CX18_CARD_INPUT_LINE_IN1, CX18_AV_AUDIO_SERIAL1, 1 }, + }, + .tuners = { + /* XC3028 tuner */ + { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, + }, + .radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 2 }, + .ddr = { + /* Pointer to proper DDR config values provided by Terry Wu */ + .chip_config = 0x303, + .refresh = 0x3bb, + .timing1 = 0x24220e83, + .timing2 = 0x1f, + .tune_lane = 0, + .initial_emrs = 0x2, + }, + .gpio_init.initial_value = 0x6, + .gpio_init.direction = 0x7, + .gpio_audio_input = { .mask = 0x7, + .tuner = 0x6, .linein = 0x2, .radio = 0x2 }, + .xceive_pin = 1, + .pci_list = cx18_pci_leadtek_dvr3100h, + .i2c = &cx18_i2c_std, +}; + +/* ------------------------------------------------------------------------- */ + static const struct cx18_card *cx18_card_list[] = { &cx18_card_hvr1600_esmt, &cx18_card_hvr1600_samsung, @@ -400,6 +448,7 @@ static const struct cx18_card *cx18_card_list[] = { &cx18_card_cnxt_raptor_pal, &cx18_card_toshiba_qosmio_dvbt, &cx18_card_leadtek_pvr2100, + &cx18_card_leadtek_dvr3100h, }; const struct cx18_card *cx18_get_card(u16 index) diff --git a/drivers/media/video/cx18/cx18-controls.c b/drivers/media/video/cx18/cx18-controls.c index 82fc2f9d4021..5136df198338 100644 --- a/drivers/media/video/cx18/cx18-controls.c +++ b/drivers/media/video/cx18/cx18-controls.c @@ -61,6 +61,8 @@ int cx18_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qctrl) switch (qctrl->id) { /* Standard V4L2 controls */ + case V4L2_CID_USER_CLASS: + return v4l2_ctrl_query_fill(qctrl, 0, 0, 0, 0); case V4L2_CID_BRIGHTNESS: case V4L2_CID_HUE: case V4L2_CID_SATURATION: @@ -176,8 +178,10 @@ static int cx18_setup_vbi_fmt(struct cx18 *cx, return -EBUSY; if (fmt != V4L2_MPEG_STREAM_VBI_FMT_IVTV || - type != V4L2_MPEG_STREAM_TYPE_MPEG2_PS) { - /* We don't do VBI insertion aside from IVTV format in a PS */ + !(type == V4L2_MPEG_STREAM_TYPE_MPEG2_PS || + type == V4L2_MPEG_STREAM_TYPE_MPEG2_DVD || + type == V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD)) { + /* Only IVTV fmt VBI insertion & only MPEG-2 PS type streams */ cx->vbi.insert_mpeg = V4L2_MPEG_STREAM_VBI_FMT_NONE; CX18_DEBUG_INFO("disabled insertion of sliced VBI data into " "the MPEG stream\n"); diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c index 49b1c3d7b1a8..92026e82e10e 100644 --- a/drivers/media/video/cx18/cx18-driver.c +++ b/drivers/media/video/cx18/cx18-driver.c @@ -30,6 +30,7 @@ #include "cx18-irq.h" #include "cx18-gpio.h" #include "cx18-firmware.h" +#include "cx18-queue.h" #include "cx18-streams.h" #include "cx18-av-core.h" #include "cx18-scb.h" @@ -151,7 +152,8 @@ MODULE_PARM_DESC(cardtype, "\t\t\t 4 = Yuan MPC718\n" "\t\t\t 5 = Conexant Raptor PAL/SECAM\n" "\t\t\t 6 = Toshiba Qosmio DVB-T/Analog\n" - "\t\t\t 7 = Leadtek WinFast PVR2100/DVR3100 H\n" + "\t\t\t 7 = Leadtek WinFast PVR2100\n" + "\t\t\t 8 = Leadtek WinFast DVR3100 H\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"); @@ -312,7 +314,7 @@ static void cx18_process_eeprom(struct cx18 *cx) CX18_INFO("Autodetected %s\n", cx->card_name); if (tv.tuner_type == TUNER_ABSENT) - CX18_ERR("tveeprom cannot autodetect tuner!"); + CX18_ERR("tveeprom cannot autodetect tuner!\n"); if (cx->options.tuner == -1) cx->options.tuner = tv.tuner_type; @@ -546,6 +548,40 @@ done: cx->card_i2c = cx->card->i2c; } +static int __devinit cx18_create_in_workq(struct cx18 *cx) +{ + snprintf(cx->in_workq_name, sizeof(cx->in_workq_name), "%s-in", + cx->v4l2_dev.name); + cx->in_work_queue = create_singlethread_workqueue(cx->in_workq_name); + if (cx->in_work_queue == NULL) { + CX18_ERR("Unable to create incoming mailbox handler thread\n"); + return -ENOMEM; + } + return 0; +} + +static int __devinit cx18_create_out_workq(struct cx18 *cx) +{ + snprintf(cx->out_workq_name, sizeof(cx->out_workq_name), "%s-out", + cx->v4l2_dev.name); + cx->out_work_queue = create_workqueue(cx->out_workq_name); + if (cx->out_work_queue == NULL) { + CX18_ERR("Unable to create outgoing mailbox handler threads\n"); + return -ENOMEM; + } + return 0; +} + +static void __devinit cx18_init_in_work_orders(struct cx18 *cx) +{ + int i; + for (i = 0; i < CX18_MAX_IN_WORK_ORDERS; i++) { + cx->in_work_order[i].cx = cx; + cx->in_work_order[i].str = cx->epu_debug_str; + INIT_WORK(&cx->in_work_order[i].work, cx18_in_work_handler); + } +} + /* Precondition: the cx18 structure has been memset to 0. Only the dev and instance fields have been filled in. No assumptions on the card type may be made here (see cx18_init_struct2 @@ -553,7 +589,7 @@ done: */ static int __devinit cx18_init_struct1(struct cx18 *cx) { - int i; + int ret; cx->base_addr = pci_resource_start(cx->pci_dev, 0); @@ -562,17 +598,17 @@ static int __devinit cx18_init_struct1(struct cx18 *cx) mutex_init(&cx->epu2apu_mb_lock); mutex_init(&cx->epu2cpu_mb_lock); - cx->work_queue = create_singlethread_workqueue(cx->v4l2_dev.name); - if (cx->work_queue == NULL) { - CX18_ERR("Unable to create work hander thread\n"); - return -ENOMEM; + ret = cx18_create_out_workq(cx); + if (ret) + return ret; + + ret = cx18_create_in_workq(cx); + if (ret) { + destroy_workqueue(cx->out_work_queue); + return ret; } - for (i = 0; i < CX18_MAX_EPU_WORK_ORDERS; i++) { - cx->epu_work_order[i].cx = cx; - cx->epu_work_order[i].str = cx->epu_debug_str; - INIT_WORK(&cx->epu_work_order[i].work, cx18_epu_work_handler); - } + cx18_init_in_work_orders(cx); /* start counting open_id at 1 */ cx->open_id = 1; @@ -759,17 +795,17 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev, retval = -ENODEV; goto err; } - if (cx18_init_struct1(cx)) { - retval = -ENOMEM; + + retval = cx18_init_struct1(cx); + if (retval) goto err; - } CX18_DEBUG_INFO("base addr: 0x%08x\n", cx->base_addr); /* PCI Device Setup */ retval = cx18_setup_pci(cx, pci_dev, pci_id); if (retval != 0) - goto free_workqueue; + goto free_workqueues; /* map io memory */ CX18_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n", @@ -943,8 +979,9 @@ free_map: cx18_iounmap(cx); free_mem: release_mem_region(cx->base_addr, CX18_MEM_SIZE); -free_workqueue: - destroy_workqueue(cx->work_queue); +free_workqueues: + destroy_workqueue(cx->in_work_queue); + destroy_workqueue(cx->out_work_queue); err: if (retval == 0) retval = -ENODEV; @@ -1053,11 +1090,19 @@ int cx18_init_on_first_open(struct cx18 *cx) return 0; } -static void cx18_cancel_epu_work_orders(struct cx18 *cx) +static void cx18_cancel_in_work_orders(struct cx18 *cx) { int i; - for (i = 0; i < CX18_MAX_EPU_WORK_ORDERS; i++) - cancel_work_sync(&cx->epu_work_order[i].work); + for (i = 0; i < CX18_MAX_IN_WORK_ORDERS; i++) + cancel_work_sync(&cx->in_work_order[i].work); +} + +static void cx18_cancel_out_work_orders(struct cx18 *cx) +{ + int i; + for (i = 0; i < CX18_MAX_STREAMS; i++) + if (&cx->streams[i].video_dev != NULL) + cancel_work_sync(&cx->streams[i].out_work_order); } static void cx18_remove(struct pci_dev *pci_dev) @@ -1073,15 +1118,20 @@ static void cx18_remove(struct pci_dev *pci_dev) if (atomic_read(&cx->tot_capturing) > 0) cx18_stop_all_captures(cx); - /* Interrupts */ + /* Stop interrupts that cause incoming work to be queued */ cx18_sw1_irq_disable(cx, IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU); + + /* Incoming work can cause outgoing work, so clean up incoming first */ + cx18_cancel_in_work_orders(cx); + cx18_cancel_out_work_orders(cx); + + /* Stop ack interrupts that may have been needed for work to finish */ cx18_sw2_irq_disable(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK); cx18_halt_firmware(cx); - cx18_cancel_epu_work_orders(cx); - - destroy_workqueue(cx->work_queue); + destroy_workqueue(cx->in_work_queue); + destroy_workqueue(cx->out_work_queue); cx18_streams_cleanup(cx, 1); diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h index ece4f281ef42..c6a1e907f63a 100644 --- a/drivers/media/video/cx18/cx18-driver.h +++ b/drivers/media/video/cx18/cx18-driver.h @@ -80,8 +80,9 @@ #define CX18_CARD_YUAN_MPC718 3 /* Yuan MPC718 */ #define CX18_CARD_CNXT_RAPTOR_PAL 4 /* Conexant Raptor PAL */ #define CX18_CARD_TOSHIBA_QOSMIO_DVBT 5 /* Toshiba Qosmio Interal DVB-T/Analog*/ -#define CX18_CARD_LEADTEK_PVR2100 6 /* Leadtek WinFast PVR2100/DVR3100 H */ -#define CX18_CARD_LAST 6 +#define CX18_CARD_LEADTEK_PVR2100 6 /* Leadtek WinFast PVR2100 */ +#define CX18_CARD_LEADTEK_DVR3100H 7 /* Leadtek WinFast DVR3100 H */ +#define CX18_CARD_LAST 7 #define CX18_ENC_STREAM_TYPE_MPG 0 #define CX18_ENC_STREAM_TYPE_TS 1 @@ -254,6 +255,7 @@ struct cx18_options { #define CX18_F_S_INTERNAL_USE 5 /* this stream is used internally (sliced VBI processing) */ #define CX18_F_S_STREAMOFF 7 /* signal end of stream EOS */ #define CX18_F_S_APPL_IO 8 /* this stream is used read/written by an application */ +#define CX18_F_S_STOPPING 9 /* telling the fw to stop capturing */ /* per-cx18, i_flags */ #define CX18_F_I_LOADED_FW 0 /* Loaded firmware 1st time */ @@ -285,6 +287,7 @@ struct cx18_queue { struct list_head list; atomic_t buffers; u32 bytesused; + spinlock_t lock; }; struct cx18_dvb { @@ -305,7 +308,7 @@ struct cx18_scb; /* forward reference */ #define CX18_MAX_MDL_ACKS 2 -#define CX18_MAX_EPU_WORK_ORDERS (CX18_MAX_FW_MDLS_PER_STREAM + 7) +#define CX18_MAX_IN_WORK_ORDERS (CX18_MAX_FW_MDLS_PER_STREAM + 7) /* CPU_DE_RELEASE_MDL can burst CX18_MAX_FW_MDLS_PER_STREAM orders in a group */ #define CX18_F_EWO_MB_STALE_UPON_RECEIPT 0x1 @@ -313,7 +316,7 @@ struct cx18_scb; /* forward reference */ #define CX18_F_EWO_MB_STALE \ (CX18_F_EWO_MB_STALE_UPON_RECEIPT | CX18_F_EWO_MB_STALE_WHILE_PROC) -struct cx18_epu_work_order { +struct cx18_in_work_order { struct work_struct work; atomic_t pending; struct cx18 *cx; @@ -337,7 +340,6 @@ struct cx18_stream { unsigned mdl_offset; u32 id; - struct mutex qlock; /* locks access to the queues */ unsigned long s_flags; /* status flags, see above */ int dma; /* can be PCI_DMA_TODEVICE, PCI_DMA_FROMDEVICE or @@ -353,6 +355,8 @@ struct cx18_stream { struct cx18_queue q_busy; /* busy buffers - in use by firmware */ struct cx18_queue q_full; /* full buffers - data for user apps */ + struct work_struct out_work_order; + /* DVB / Digital Transport */ struct cx18_dvb dvb; }; @@ -568,10 +572,14 @@ struct cx18 { u32 sw2_irq_mask; u32 hw2_irq_mask; - struct workqueue_struct *work_queue; - struct cx18_epu_work_order epu_work_order[CX18_MAX_EPU_WORK_ORDERS]; + struct workqueue_struct *in_work_queue; + char in_workq_name[11]; /* "cx18-NN-in" */ + struct cx18_in_work_order in_work_order[CX18_MAX_IN_WORK_ORDERS]; char epu_debug_str[256]; /* CX18_EPU_DEBUG is rare: use shared space */ + struct workqueue_struct *out_work_queue; + char out_workq_name[12]; /* "cx18-NN-out" */ + /* i2c */ struct i2c_adapter i2c_adap[2]; struct i2c_algo_bit_data i2c_algo[2]; diff --git a/drivers/media/video/cx18/cx18-dvb.c b/drivers/media/video/cx18/cx18-dvb.c index 3b86f57cd15a..6ea3fe623ef4 100644 --- a/drivers/media/video/cx18/cx18-dvb.c +++ b/drivers/media/video/cx18/cx18-dvb.c @@ -23,14 +23,20 @@ #include "cx18-version.h" #include "cx18-dvb.h" #include "cx18-io.h" +#include "cx18-queue.h" #include "cx18-streams.h" #include "cx18-cards.h" +#include "cx18-gpio.h" #include "s5h1409.h" #include "mxl5005s.h" +#include "zl10353.h" +#include "tuner-xc2028.h" DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); #define CX18_REG_DMUX_NUM_PORT_0_CONTROL 0xd5a000 +#define CX18_CLOCK_ENABLE2 0xc71024 +#define CX18_DMUX_CLK_MASK 0x0080 static struct mxl5005s_config hauppauge_hvr1600_tuner = { .i2c_address = 0xC6 >> 1, @@ -57,7 +63,15 @@ static struct s5h1409_config hauppauge_hvr1600_config = { .inversion = S5H1409_INVERSION_OFF, .status_mode = S5H1409_DEMODLOCKING, .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK +}; +/* Information/confirmation of proper config values provided by Terry Wu */ +static struct zl10353_config leadtek_dvr3100h_demod = { + .demod_address = 0x1e >> 1, /* Datasheet suggested straps */ + .if2 = 45600, /* 4.560 MHz IF from the XC3028 */ + .parallel_ts = 1, /* Not a serial TS */ + .no_tuner = 1, /* XC3028 is not behind the gate */ + .disable_i2c_gate_ctrl = 1, /* Disable the I2C gate */ }; static int dvb_register(struct cx18_stream *stream); @@ -98,6 +112,7 @@ static int cx18_dvb_start_feed(struct dvb_demux_feed *feed) cx18_write_reg(cx, v, CX18_REG_DMUX_NUM_PORT_0_CONTROL); break; + case CX18_CARD_LEADTEK_DVR3100H: default: /* Assumption - Parallel transport - Signalling * undefined or default. @@ -267,8 +282,7 @@ void cx18_dvb_unregister(struct cx18_stream *stream) } /* All the DVB attach calls go here, this function get's modified - * for each new card. No other function in this file needs - * to change. + * for each new card. cx18_dvb_start_feed() will also need changes. */ static int dvb_register(struct cx18_stream *stream) { @@ -289,6 +303,29 @@ static int dvb_register(struct cx18_stream *stream) ret = 0; } break; + case CX18_CARD_LEADTEK_DVR3100H: + dvb->fe = dvb_attach(zl10353_attach, + &leadtek_dvr3100h_demod, + &cx->i2c_adap[1]); + if (dvb->fe != NULL) { + struct dvb_frontend *fe; + struct xc2028_config cfg = { + .i2c_adap = &cx->i2c_adap[1], + .i2c_addr = 0xc2 >> 1, + .ctrl = NULL, + }; + static struct xc2028_ctrl ctrl = { + .fname = XC2028_DEFAULT_FIRMWARE, + .max_len = 64, + .demod = XC3028_FE_ZARLINK456, + .type = XC2028_AUTO, + }; + + fe = dvb_attach(xc2028_attach, dvb->fe, &cfg); + if (fe != NULL && fe->ops.tuner_ops.set_config != NULL) + fe->ops.tuner_ops.set_config(fe, &ctrl); + } + break; default: /* No Digital Tv Support */ break; @@ -299,6 +336,8 @@ static int dvb_register(struct cx18_stream *stream) return -1; } + dvb->fe->callback = cx18_reset_tuner_gpio; + ret = dvb_register_frontend(&dvb->dvb_adapter, dvb->fe); if (ret < 0) { if (dvb->fe->ops.release) @@ -306,5 +345,16 @@ static int dvb_register(struct cx18_stream *stream) return ret; } + /* + * The firmware seems to enable the TS DMUX clock + * under various circumstances. However, since we know we + * might use it, let's just turn it on ourselves here. + */ + cx18_write_reg_expect(cx, + (CX18_DMUX_CLK_MASK << 16) | CX18_DMUX_CLK_MASK, + CX18_CLOCK_ENABLE2, + CX18_DMUX_CLK_MASK, + (CX18_DMUX_CLK_MASK << 16) | CX18_DMUX_CLK_MASK); + return ret; } diff --git a/drivers/media/video/cx18/cx18-fileops.c b/drivers/media/video/cx18/cx18-fileops.c index b3889c0b2697..29969c18949c 100644 --- a/drivers/media/video/cx18/cx18-fileops.c +++ b/drivers/media/video/cx18/cx18-fileops.c @@ -265,8 +265,13 @@ static size_t cx18_copy_buf_to_user(struct cx18_stream *s, * an MPEG-2 Program Pack start code, and provide only * up to that point to the user, so it's easy to insert VBI data * the next time around. + * + * This will not work for an MPEG-2 TS and has only been + * verified by analysis to work for an MPEG-2 PS. Helen Buus + * pointed out this works for the CX23416 MPEG-2 DVD compatible + * stream, and research indicates both the MPEG 2 SVCD and DVD + * stream types use an MPEG-2 PS container. */ - /* FIXME - This only works for an MPEG-2 PS, not a TS */ /* * An MPEG-2 Program Stream (PS) is a series of * MPEG-2 Program Packs terminated by an diff --git a/drivers/media/video/cx18/cx18-mailbox.c b/drivers/media/video/cx18/cx18-mailbox.c index 2226e5791e99..afe46c3d4057 100644 --- a/drivers/media/video/cx18/cx18-mailbox.c +++ b/drivers/media/video/cx18/cx18-mailbox.c @@ -131,7 +131,7 @@ static void dump_mb(struct cx18 *cx, struct cx18_mailbox *mb, char *name) * Functions that run in a work_queue work handling context */ -static void epu_dma_done(struct cx18 *cx, struct cx18_epu_work_order *order) +static void epu_dma_done(struct cx18 *cx, struct cx18_in_work_order *order) { u32 handle, mdl_ack_count, id; struct cx18_mailbox *mb; @@ -191,29 +191,30 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_epu_work_order *order) if (buf == NULL) { CX18_WARN("Could not find buf %d for stream %s\n", id, s->name); - /* Put as many buffers as possible back into fw use */ - cx18_stream_load_fw_queue(s); continue; } - if (s->type == CX18_ENC_STREAM_TYPE_TS && s->dvb.enabled) { - CX18_DEBUG_HI_DMA("TS recv bytesused = %d\n", - buf->bytesused); - dvb_dmx_swfilter(&s->dvb.demux, buf->buf, - buf->bytesused); + CX18_DEBUG_HI_DMA("%s recv bytesused = %d\n", + s->name, buf->bytesused); + + if (s->type != CX18_ENC_STREAM_TYPE_TS) + cx18_enqueue(s, buf, &s->q_full); + else { + if (s->dvb.enabled) + dvb_dmx_swfilter(&s->dvb.demux, buf->buf, + buf->bytesused); + cx18_enqueue(s, buf, &s->q_free); } - /* Put as many buffers as possible back into fw use */ - cx18_stream_load_fw_queue(s); - /* Put back TS buffer, since it was removed from all queues */ - if (s->type == CX18_ENC_STREAM_TYPE_TS) - cx18_stream_put_buf_fw(s, buf); } + /* Put as many buffers as possible back into fw use */ + cx18_stream_load_fw_queue(s); + wake_up(&cx->dma_waitq); if (s->id != -1) wake_up(&s->waitq); } -static void epu_debug(struct cx18 *cx, struct cx18_epu_work_order *order) +static void epu_debug(struct cx18 *cx, struct cx18_in_work_order *order) { char *p; char *str = order->str; @@ -224,7 +225,7 @@ static void epu_debug(struct cx18 *cx, struct cx18_epu_work_order *order) CX18_INFO("FW version: %s\n", p - 1); } -static void epu_cmd(struct cx18 *cx, struct cx18_epu_work_order *order) +static void epu_cmd(struct cx18 *cx, struct cx18_in_work_order *order) { switch (order->rpu) { case CPU: @@ -253,18 +254,18 @@ static void epu_cmd(struct cx18 *cx, struct cx18_epu_work_order *order) } static -void free_epu_work_order(struct cx18 *cx, struct cx18_epu_work_order *order) +void free_in_work_order(struct cx18 *cx, struct cx18_in_work_order *order) { atomic_set(&order->pending, 0); } -void cx18_epu_work_handler(struct work_struct *work) +void cx18_in_work_handler(struct work_struct *work) { - struct cx18_epu_work_order *order = - container_of(work, struct cx18_epu_work_order, work); + struct cx18_in_work_order *order = + container_of(work, struct cx18_in_work_order, work); struct cx18 *cx = order->cx; epu_cmd(cx, order); - free_epu_work_order(cx, order); + free_in_work_order(cx, order); } @@ -272,7 +273,7 @@ void cx18_epu_work_handler(struct work_struct *work) * Functions that run in an interrupt handling context */ -static void mb_ack_irq(struct cx18 *cx, struct cx18_epu_work_order *order) +static void mb_ack_irq(struct cx18 *cx, struct cx18_in_work_order *order) { struct cx18_mailbox __iomem *ack_mb; u32 ack_irq, req; @@ -308,7 +309,7 @@ static void mb_ack_irq(struct cx18 *cx, struct cx18_epu_work_order *order) return; } -static int epu_dma_done_irq(struct cx18 *cx, struct cx18_epu_work_order *order) +static int epu_dma_done_irq(struct cx18 *cx, struct cx18_in_work_order *order) { u32 handle, mdl_ack_offset, mdl_ack_count; struct cx18_mailbox *mb; @@ -334,7 +335,7 @@ static int epu_dma_done_irq(struct cx18 *cx, struct cx18_epu_work_order *order) } static -int epu_debug_irq(struct cx18 *cx, struct cx18_epu_work_order *order) +int epu_debug_irq(struct cx18 *cx, struct cx18_in_work_order *order) { u32 str_offset; char *str = order->str; @@ -355,7 +356,7 @@ int epu_debug_irq(struct cx18 *cx, struct cx18_epu_work_order *order) } static inline -int epu_cmd_irq(struct cx18 *cx, struct cx18_epu_work_order *order) +int epu_cmd_irq(struct cx18 *cx, struct cx18_in_work_order *order) { int ret = -1; @@ -387,12 +388,12 @@ int epu_cmd_irq(struct cx18 *cx, struct cx18_epu_work_order *order) } static inline -struct cx18_epu_work_order *alloc_epu_work_order_irq(struct cx18 *cx) +struct cx18_in_work_order *alloc_in_work_order_irq(struct cx18 *cx) { int i; - struct cx18_epu_work_order *order = NULL; + struct cx18_in_work_order *order = NULL; - for (i = 0; i < CX18_MAX_EPU_WORK_ORDERS; i++) { + for (i = 0; i < CX18_MAX_IN_WORK_ORDERS; i++) { /* * We only need "pending" atomic to inspect its contents, * and need not do a check and set because: @@ -401,8 +402,8 @@ struct cx18_epu_work_order *alloc_epu_work_order_irq(struct cx18 *cx) * 2. "pending" is only set here, and we're serialized because * we're called in an IRQ handler context. */ - if (atomic_read(&cx->epu_work_order[i].pending) == 0) { - order = &cx->epu_work_order[i]; + if (atomic_read(&cx->in_work_order[i].pending) == 0) { + order = &cx->in_work_order[i]; atomic_set(&order->pending, 1); break; } @@ -414,7 +415,7 @@ void cx18_api_epu_cmd_irq(struct cx18 *cx, int rpu) { struct cx18_mailbox __iomem *mb; struct cx18_mailbox *order_mb; - struct cx18_epu_work_order *order; + struct cx18_in_work_order *order; int submit; switch (rpu) { @@ -428,7 +429,7 @@ void cx18_api_epu_cmd_irq(struct cx18 *cx, int rpu) return; } - order = alloc_epu_work_order_irq(cx); + order = alloc_in_work_order_irq(cx); if (order == NULL) { CX18_WARN("Unable to find blank work order form to schedule " "incoming mailbox command processing\n"); @@ -461,7 +462,7 @@ void cx18_api_epu_cmd_irq(struct cx18 *cx, int rpu) */ submit = epu_cmd_irq(cx, order); if (submit > 0) { - queue_work(cx->work_queue, &order->work); + queue_work(cx->in_work_queue, &order->work); } } @@ -478,9 +479,10 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[]) u32 __iomem *xpu_state; wait_queue_head_t *waitq; struct mutex *mb_lock; - long int timeout, ret; + unsigned long int t0, timeout, ret; int i; char argstr[MAX_MB_ARGUMENTS*11+1]; + DEFINE_WAIT(w); if (info == NULL) { CX18_WARN("unknown cmd %x\n", cmd); @@ -562,25 +564,49 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[]) CX18_DEBUG_HI_IRQ("sending interrupt SW1: %x to send %s\n", irq, info->name); + + /* So we don't miss the wakeup, prepare to wait before notifying fw */ + prepare_to_wait(waitq, &w, TASK_UNINTERRUPTIBLE); cx18_write_reg_expect(cx, irq, SW1_INT_SET, irq, irq); - ret = wait_event_timeout( - *waitq, - cx18_readl(cx, &mb->ack) == cx18_readl(cx, &mb->request), - timeout); + t0 = jiffies; + ack = cx18_readl(cx, &mb->ack); + if (ack != req) { + schedule_timeout(timeout); + ret = jiffies - t0; + ack = cx18_readl(cx, &mb->ack); + } else { + ret = jiffies - t0; + } - if (ret == 0) { - /* Timed out */ + finish_wait(waitq, &w); + + if (req != ack) { mutex_unlock(mb_lock); - CX18_DEBUG_WARN("sending %s timed out waiting %d msecs for RPU " - "acknowledgement\n", - info->name, jiffies_to_msecs(timeout)); + if (ret >= timeout) { + /* Timed out */ + CX18_DEBUG_WARN("sending %s timed out waiting %d msecs " + "for RPU acknowledgement\n", + info->name, jiffies_to_msecs(ret)); + } else { + CX18_DEBUG_WARN("woken up before mailbox ack was ready " + "after submitting %s to RPU. only " + "waited %d msecs on req %u but awakened" + " with unmatched ack %u\n", + info->name, + jiffies_to_msecs(ret), + req, ack); + } return -EINVAL; } - if (ret != timeout) + if (ret >= timeout) + CX18_DEBUG_WARN("failed to be awakened upon RPU acknowledgment " + "sending %s; timed out waiting %d msecs\n", + info->name, jiffies_to_msecs(ret)); + else CX18_DEBUG_HI_API("waited %u msecs for %s to be acked\n", - jiffies_to_msecs(timeout-ret), info->name); + jiffies_to_msecs(ret), info->name); /* Collect data returned by the XPU */ for (i = 0; i < MAX_MB_ARGUMENTS; i++) diff --git a/drivers/media/video/cx18/cx18-mailbox.h b/drivers/media/video/cx18/cx18-mailbox.h index ce2b6686aa00..e23aaac5b280 100644 --- a/drivers/media/video/cx18/cx18-mailbox.h +++ b/drivers/media/video/cx18/cx18-mailbox.h @@ -95,6 +95,6 @@ int cx18_api_func(void *priv, u32 cmd, int in, int out, void cx18_api_epu_cmd_irq(struct cx18 *cx, int rpu); -void cx18_epu_work_handler(struct work_struct *work); +void cx18_in_work_handler(struct work_struct *work); #endif diff --git a/drivers/media/video/cx18/cx18-queue.c b/drivers/media/video/cx18/cx18-queue.c index 3046b8e74345..fa1ed7897d97 100644 --- a/drivers/media/video/cx18/cx18-queue.c +++ b/drivers/media/video/cx18/cx18-queue.c @@ -23,8 +23,8 @@ */ #include "cx18-driver.h" -#include "cx18-streams.h" #include "cx18-queue.h" +#include "cx18-streams.h" #include "cx18-scb.h" void cx18_buf_swap(struct cx18_buffer *buf) @@ -53,13 +53,13 @@ struct cx18_queue *_cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf, buf->skipped = 0; } - mutex_lock(&s->qlock); - /* q_busy is restricted to a max buffer count imposed by firmware */ if (q == &s->q_busy && atomic_read(&q->buffers) >= CX18_MAX_FW_MDLS_PER_STREAM) q = &s->q_free; + spin_lock(&q->lock); + if (to_front) list_add(&buf->list, &q->list); /* LIFO */ else @@ -67,7 +67,7 @@ struct cx18_queue *_cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf, q->bytesused += buf->bytesused - buf->readpos; atomic_inc(&q->buffers); - mutex_unlock(&s->qlock); + spin_unlock(&q->lock); return q; } @@ -75,7 +75,7 @@ struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q) { struct cx18_buffer *buf = NULL; - mutex_lock(&s->qlock); + spin_lock(&q->lock); if (!list_empty(&q->list)) { buf = list_first_entry(&q->list, struct cx18_buffer, list); list_del_init(&buf->list); @@ -83,7 +83,7 @@ struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q) buf->skipped = 0; atomic_dec(&q->buffers); } - mutex_unlock(&s->qlock); + spin_unlock(&q->lock); return buf; } @@ -94,9 +94,23 @@ struct cx18_buffer *cx18_queue_get_buf(struct cx18_stream *s, u32 id, struct cx18_buffer *buf; struct cx18_buffer *tmp; struct cx18_buffer *ret = NULL; + LIST_HEAD(sweep_up); - mutex_lock(&s->qlock); + /* + * We don't have to acquire multiple q locks here, because we are + * serialized by the single threaded work handler. + * Buffers from the firmware will thus remain in order as + * they are moved from q_busy to q_full or to the dvb ring buffer. + */ + spin_lock(&s->q_busy.lock); list_for_each_entry_safe(buf, tmp, &s->q_busy.list, list) { + /* + * We should find what the firmware told us is done, + * right at the front of the queue. If we don't, we likely have + * missed a buffer done message from the firmware. + * Once we skip a buffer repeatedly, relative to the size of + * q_busy, we have high confidence we've missed it. + */ if (buf->id != id) { buf->skipped++; if (buf->skipped >= atomic_read(&s->q_busy.buffers)-1) { @@ -105,38 +119,41 @@ struct cx18_buffer *cx18_queue_get_buf(struct cx18_stream *s, u32 id, "times - it must have dropped out of " "rotation\n", s->name, buf->id, buf->skipped); - /* move it to q_free */ - list_move_tail(&buf->list, &s->q_free.list); - buf->bytesused = buf->readpos = buf->b_flags = - buf->skipped = 0; + /* Sweep it up to put it back into rotation */ + list_move_tail(&buf->list, &sweep_up); atomic_dec(&s->q_busy.buffers); - atomic_inc(&s->q_free.buffers); } continue; } - - buf->bytesused = bytesused; - /* Sync the buffer before we release the qlock */ - cx18_buf_sync_for_cpu(s, buf); - if (s->type == CX18_ENC_STREAM_TYPE_TS) { - /* - * TS doesn't use q_full. As we pull the buffer off of - * the queue here, the caller will have to put it back. - */ - list_del_init(&buf->list); - } else { - /* Move buffer from q_busy to q_full */ - list_move_tail(&buf->list, &s->q_full.list); - set_bit(CX18_F_B_NEED_BUF_SWAP, &buf->b_flags); - s->q_full.bytesused += buf->bytesused; - atomic_inc(&s->q_full.buffers); - } + /* + * We pull the desired buffer off of the queue here. Something + * will have to put it back on a queue later. + */ + list_del_init(&buf->list); atomic_dec(&s->q_busy.buffers); - ret = buf; break; } - mutex_unlock(&s->qlock); + spin_unlock(&s->q_busy.lock); + + /* + * We found the buffer for which we were looking. Get it ready for + * the caller to put on q_full or in the dvb ring buffer. + */ + if (ret != NULL) { + ret->bytesused = bytesused; + ret->skipped = 0; + /* readpos and b_flags were 0'ed when the buf went on q_busy */ + cx18_buf_sync_for_cpu(s, ret); + if (s->type != CX18_ENC_STREAM_TYPE_TS) + set_bit(CX18_F_B_NEED_BUF_SWAP, &ret->b_flags); + } + + /* Put any buffers the firmware is ignoring back into normal rotation */ + list_for_each_entry_safe(buf, tmp, &sweep_up, list) { + list_del_init(&buf->list); + cx18_enqueue(s, buf, &s->q_free); + } return ret; } @@ -148,7 +165,7 @@ static void cx18_queue_flush(struct cx18_stream *s, struct cx18_queue *q) if (q == &s->q_free) return; - mutex_lock(&s->qlock); + spin_lock(&q->lock); while (!list_empty(&q->list)) { buf = list_first_entry(&q->list, struct cx18_buffer, list); list_move_tail(&buf->list, &s->q_free.list); @@ -156,7 +173,7 @@ static void cx18_queue_flush(struct cx18_stream *s, struct cx18_queue *q) atomic_inc(&s->q_free.buffers); } cx18_queue_init(q); - mutex_unlock(&s->qlock); + spin_unlock(&q->lock); } void cx18_flush_queues(struct cx18_stream *s) diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c index 0932b76b2373..54d248e16d85 100644 --- a/drivers/media/video/cx18/cx18-streams.c +++ b/drivers/media/video/cx18/cx18-streams.c @@ -116,12 +116,16 @@ static void cx18_stream_init(struct cx18 *cx, int type) s->buffers = cx->stream_buffers[type]; s->buf_size = cx->stream_buf_size[type]; - mutex_init(&s->qlock); init_waitqueue_head(&s->waitq); s->id = -1; + spin_lock_init(&s->q_free.lock); cx18_queue_init(&s->q_free); + spin_lock_init(&s->q_busy.lock); cx18_queue_init(&s->q_busy); + spin_lock_init(&s->q_full.lock); cx18_queue_init(&s->q_full); + + INIT_WORK(&s->out_work_order, cx18_out_work_handler); } static int cx18_prep_dev(struct cx18 *cx, int type) @@ -367,9 +371,14 @@ static void cx18_vbi_setup(struct cx18_stream *s) * Tell the encoder to capture 21-4+1=18 lines per field, * since we want lines 10 through 21. * - * FIXME - revisit for 625/50 systems + * For 625/50 systems, according to the VIP 2 & BT.656 std: + * The EAV RP code's Field bit toggles on line 1, a few lines + * after the Vertcal Blank bit has already toggled. + * (We've actually set the digitizer so that the Field bit + * toggles on line 2.) Tell the encoder to capture 23-2+1=22 + * lines per field, since we want lines 6 through 23. */ - lines = cx->is_60hz ? (21 - 4 + 1) * 2 : 38; + lines = cx->is_60hz ? (21 - 4 + 1) * 2 : (23 - 2 + 1) * 2; } data[0] = s->handle; @@ -431,14 +440,16 @@ static void cx18_vbi_setup(struct cx18_stream *s) cx18_api(cx, CX18_CPU_SET_RAW_VBI_PARAM, 6, data); } -struct cx18_queue *cx18_stream_put_buf_fw(struct cx18_stream *s, - struct cx18_buffer *buf) +static +struct cx18_queue *_cx18_stream_put_buf_fw(struct cx18_stream *s, + struct cx18_buffer *buf) { struct cx18 *cx = s->cx; struct cx18_queue *q; /* Don't give it to the firmware, if we're not running a capture */ if (s->handle == CX18_INVALID_TASK_HANDLE || + test_bit(CX18_F_S_STOPPING, &s->s_flags) || !test_bit(CX18_F_S_STREAMING, &s->s_flags)) return cx18_enqueue(s, buf, &s->q_free); @@ -453,7 +464,8 @@ struct cx18_queue *cx18_stream_put_buf_fw(struct cx18_stream *s, return q; } -void cx18_stream_load_fw_queue(struct cx18_stream *s) +static +void _cx18_stream_load_fw_queue(struct cx18_stream *s) { struct cx18_queue *q; struct cx18_buffer *buf; @@ -467,11 +479,19 @@ void cx18_stream_load_fw_queue(struct cx18_stream *s) buf = cx18_dequeue(s, &s->q_free); if (buf == NULL) break; - q = cx18_stream_put_buf_fw(s, buf); + q = _cx18_stream_put_buf_fw(s, buf); } while (atomic_read(&s->q_busy.buffers) < CX18_MAX_FW_MDLS_PER_STREAM && q == &s->q_busy); } +void cx18_out_work_handler(struct work_struct *work) +{ + struct cx18_stream *s = + container_of(work, struct cx18_stream, out_work_order); + + _cx18_stream_load_fw_queue(s); +} + int cx18_start_v4l2_encode_stream(struct cx18_stream *s) { u32 data[MAX_MB_ARGUMENTS]; @@ -600,19 +620,20 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s) /* Init all the cpu_mdls for this stream */ cx18_flush_queues(s); - mutex_lock(&s->qlock); + spin_lock(&s->q_free.lock); list_for_each_entry(buf, &s->q_free.list, list) { cx18_writel(cx, buf->dma_handle, &cx->scb->cpu_mdl[buf->id].paddr); cx18_writel(cx, s->buf_size, &cx->scb->cpu_mdl[buf->id].length); } - mutex_unlock(&s->qlock); - cx18_stream_load_fw_queue(s); + spin_unlock(&s->q_free.lock); + _cx18_stream_load_fw_queue(s); /* begin_capture */ if (cx18_vapi(cx, CX18_CPU_CAPTURE_START, 1, s->handle)) { CX18_DEBUG_WARN("Error starting capture!\n"); /* Ensure we're really not capturing before releasing MDLs */ + set_bit(CX18_F_S_STOPPING, &s->s_flags); if (s->type == CX18_ENC_STREAM_TYPE_MPG) cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 2, s->handle, 1); else @@ -622,6 +643,7 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s) cx18_vapi(cx, CX18_CPU_DE_RELEASE_MDL, 1, s->handle); cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle); s->handle = CX18_INVALID_TASK_HANDLE; + clear_bit(CX18_F_S_STOPPING, &s->s_flags); if (atomic_read(&cx->tot_capturing) == 0) { set_bit(CX18_F_I_EOS, &cx->i_flags); cx18_write_reg(cx, 5, CX18_DSP0_INTERRUPT_MASK); @@ -666,6 +688,7 @@ int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end) if (atomic_read(&cx->tot_capturing) == 0) return 0; + set_bit(CX18_F_S_STOPPING, &s->s_flags); if (s->type == CX18_ENC_STREAM_TYPE_MPG) cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 2, s->handle, !gop_end); else @@ -689,6 +712,7 @@ int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end) cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle); s->handle = CX18_INVALID_TASK_HANDLE; + clear_bit(CX18_F_S_STOPPING, &s->s_flags); if (atomic_read(&cx->tot_capturing) > 0) return 0; diff --git a/drivers/media/video/cx18/cx18-streams.h b/drivers/media/video/cx18/cx18-streams.h index 420e0a172945..1afc3fd9d822 100644 --- a/drivers/media/video/cx18/cx18-streams.h +++ b/drivers/media/video/cx18/cx18-streams.h @@ -28,10 +28,24 @@ int cx18_streams_setup(struct cx18 *cx); int cx18_streams_register(struct cx18 *cx); void cx18_streams_cleanup(struct cx18 *cx, int unregister); +/* Related to submission of buffers to firmware */ +static inline void cx18_stream_load_fw_queue(struct cx18_stream *s) +{ + struct cx18 *cx = s->cx; + queue_work(cx->out_work_queue, &s->out_work_order); +} + +static inline void cx18_stream_put_buf_fw(struct cx18_stream *s, + struct cx18_buffer *buf) +{ + /* Put buf on q_free; the out work handler will move buf(s) to q_busy */ + cx18_enqueue(s, buf, &s->q_free); + cx18_stream_load_fw_queue(s); +} + +void cx18_out_work_handler(struct work_struct *work); + /* Capture related */ -void cx18_stream_load_fw_queue(struct cx18_stream *s); -struct cx18_queue *cx18_stream_put_buf_fw(struct cx18_stream *s, - struct cx18_buffer *buf); int cx18_start_v4l2_encode_stream(struct cx18_stream *s); int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end); diff --git a/drivers/media/video/cx18/cx18-version.h b/drivers/media/video/cx18/cx18-version.h index bd9bd44da791..45494b094e7f 100644 --- a/drivers/media/video/cx18/cx18-version.h +++ b/drivers/media/video/cx18/cx18-version.h @@ -24,7 +24,7 @@ #define CX18_DRIVER_NAME "cx18" #define CX18_DRIVER_VERSION_MAJOR 1 -#define CX18_DRIVER_VERSION_MINOR 1 +#define CX18_DRIVER_VERSION_MINOR 2 #define CX18_DRIVER_VERSION_PATCHLEVEL 0 #define CX18_VERSION __stringify(CX18_DRIVER_VERSION_MAJOR) "." __stringify(CX18_DRIVER_VERSION_MINOR) "." __stringify(CX18_DRIVER_VERSION_PATCHLEVEL) diff --git a/drivers/media/video/cx231xx/cx231xx-avcore.c b/drivers/media/video/cx231xx/cx231xx-avcore.c index 1be3881be991..28f48f41f218 100644 --- a/drivers/media/video/cx231xx/cx231xx-avcore.c +++ b/drivers/media/video/cx231xx/cx231xx-avcore.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include @@ -1053,22 +1052,13 @@ int cx231xx_set_audio_decoder_input(struct cx231xx *dev, /* Set resolution of the video */ int cx231xx_resolution_set(struct cx231xx *dev) { - int width, height; - u32 hscale, vscale; - int status = 0; - - width = dev->width; - height = dev->height; - - get_scale(dev, width, height, &hscale, &vscale); - /* set horzontal scale */ - status = vid_blk_write_word(dev, HSCALE_CTRL, hscale); + int status = vid_blk_write_word(dev, HSCALE_CTRL, dev->hscale); + if (status) + return status; /* set vertical scale */ - status = vid_blk_write_word(dev, VSCALE_CTRL, vscale); - - return status; + return vid_blk_write_word(dev, VSCALE_CTRL, dev->vscale); } /****************************************************************************** @@ -2056,7 +2046,7 @@ int cx231xx_initialize_stream_xfer(struct cx231xx *dev, u32 media_type) int cx231xx_capture_start(struct cx231xx *dev, int start, u8 media_type) { - int rc; + int rc = -1; u32 ep_mask = -1; struct pcb_config *pcb_config; diff --git a/drivers/media/video/cx231xx/cx231xx-cards.c b/drivers/media/video/cx231xx/cx231xx-cards.c index c8a32b1b5381..63d2239fd324 100644 --- a/drivers/media/video/cx231xx/cx231xx-cards.c +++ b/drivers/media/video/cx231xx/cx231xx-cards.c @@ -281,12 +281,12 @@ static void cx231xx_config_tuner(struct cx231xx *dev) } /* ----------------------------------------------------------------------- */ -void cx231xx_set_ir(struct cx231xx *dev, struct IR_i2c *ir) +void cx231xx_register_i2c_ir(struct cx231xx *dev) { - if (disable_ir) { - ir->get_key = NULL; + if (disable_ir) return; - } + + /* REVISIT: instantiate IR device */ /* detect & configure */ switch (dev->model) { diff --git a/drivers/media/video/cx231xx/cx231xx-i2c.c b/drivers/media/video/cx231xx/cx231xx-i2c.c index b4a03d813e00..33219dc4d649 100644 --- a/drivers/media/video/cx231xx/cx231xx-i2c.c +++ b/drivers/media/video/cx231xx/cx231xx-i2c.c @@ -424,34 +424,6 @@ static u32 functionality(struct i2c_adapter *adap) return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C; } -/* - * attach_inform() - * gets called when a device attaches to the i2c bus - * does some basic configuration - */ -static int attach_inform(struct i2c_client *client) -{ - struct cx231xx_i2c *bus = i2c_get_adapdata(client->adapter); - struct cx231xx *dev = bus->dev; - - switch (client->addr << 1) { - case 0x8e: - { - struct IR_i2c *ir = i2c_get_clientdata(client); - dprintk1(1, "attach_inform: IR detected (%s).\n", - ir->phys); - cx231xx_set_ir(dev, ir); - break; - } - break; - - default: - break; - } - - return 0; -} - static struct i2c_algorithm cx231xx_algo = { .master_xfer = cx231xx_i2c_xfer, .functionality = functionality, @@ -462,7 +434,6 @@ static struct i2c_adapter cx231xx_adap_template = { .name = "cx231xx", .id = I2C_HW_B_CX231XX, .algo = &cx231xx_algo, - .client_register = attach_inform, }; static struct i2c_client cx231xx_client_template = { @@ -537,6 +508,9 @@ int cx231xx_i2c_register(struct cx231xx_i2c *bus) if (0 == bus->i2c_rc) { if (i2c_scan) cx231xx_do_i2c_scan(dev, &bus->i2c_client); + + /* Instantiate the IR receiver device, if present */ + cx231xx_register_i2c_ir(dev); } else cx231xx_warn("%s: i2c bus %d register FAILED\n", dev->name, bus->nr); diff --git a/drivers/media/video/cx231xx/cx231xx-input.c b/drivers/media/video/cx231xx/cx231xx-input.c index 97e304c3c799..48f22fa38e6c 100644 --- a/drivers/media/video/cx231xx/cx231xx-input.c +++ b/drivers/media/video/cx231xx/cx231xx-input.c @@ -36,7 +36,7 @@ MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]"); #define i2cdprintk(fmt, arg...) \ if (ir_debug) { \ - printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg); \ + printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg); \ } #define dprintk(fmt, arg...) \ diff --git a/drivers/media/video/cx231xx/cx231xx-vbi.c b/drivers/media/video/cx231xx/cx231xx-vbi.c index 94180526909c..e97b8023a655 100644 --- a/drivers/media/video/cx231xx/cx231xx-vbi.c +++ b/drivers/media/video/cx231xx/cx231xx-vbi.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include diff --git a/drivers/media/video/cx231xx/cx231xx-video.c b/drivers/media/video/cx231xx/cx231xx-video.c index a23ae73fe634..609bae6098d3 100644 --- a/drivers/media/video/cx231xx/cx231xx-video.c +++ b/drivers/media/video/cx231xx/cx231xx-video.c @@ -893,9 +893,9 @@ static int check_dev(struct cx231xx *dev) return 0; } -void get_scale(struct cx231xx *dev, - unsigned int width, unsigned int height, - unsigned int *hscale, unsigned int *vscale) +static void get_scale(struct cx231xx *dev, + unsigned int width, unsigned int height, + unsigned int *hscale, unsigned int *vscale) { unsigned int maxw = norm_maxw(dev); unsigned int maxh = norm_maxh(dev); @@ -907,10 +907,6 @@ void get_scale(struct cx231xx *dev, *vscale = (((unsigned long)maxh) << 12) / height - 4096L; if (*vscale >= 0x4000) *vscale = 0x3fff; - - dev->hscale = *hscale; - dev->vscale = *vscale; - } /* ------------------------------------------------------------------ @@ -955,8 +951,8 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, { struct cx231xx_fh *fh = priv; struct cx231xx *dev = fh->dev; - int width = f->fmt.pix.width; - int height = f->fmt.pix.height; + unsigned int width = f->fmt.pix.width; + unsigned int height = f->fmt.pix.height; unsigned int maxw = norm_maxw(dev); unsigned int maxh = norm_maxh(dev); unsigned int hscale, vscale; @@ -971,17 +967,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, /* width must even because of the YUYV format height must be even because of interlacing */ - height &= 0xfffe; - width &= 0xfffe; - - if (unlikely(height < 32)) - height = 32; - if (unlikely(height > maxh)) - height = maxh; - if (unlikely(width < 48)) - width = 48; - if (unlikely(width > maxw)) - width = maxw; + v4l_bound_align_image(&width, 48, maxw, 1, &height, 32, maxh, 1, 0); get_scale(dev, width, height, &hscale, &vscale); diff --git a/drivers/media/video/cx231xx/cx231xx.h b/drivers/media/video/cx231xx/cx231xx.h index aa4a23ef491a..a0f823ac6b8d 100644 --- a/drivers/media/video/cx231xx/cx231xx.h +++ b/drivers/media/video/cx231xx/cx231xx.h @@ -722,9 +722,6 @@ int cx231xx_set_video_input_mux(struct cx231xx *dev, u8 input); int cx231xx_set_decoder_video_input(struct cx231xx *dev, u8 pin_type, u8 input); int cx231xx_do_mode_ctrl_overrides(struct cx231xx *dev); int cx231xx_set_audio_input(struct cx231xx *dev, u8 input); -void get_scale(struct cx231xx *dev, - unsigned int width, unsigned int height, - unsigned int *hscale, unsigned int *vscale); /* Provided by cx231xx-video.c */ int cx231xx_register_extension(struct cx231xx_ops *dev); @@ -738,7 +735,7 @@ extern void cx231xx_card_setup(struct cx231xx *dev); extern struct cx231xx_board cx231xx_boards[]; extern struct usb_device_id cx231xx_id_table[]; extern const unsigned int cx231xx_bcount; -void cx231xx_set_ir(struct cx231xx *dev, struct IR_i2c *ir); +void cx231xx_register_i2c_ir(struct cx231xx *dev); int cx231xx_tuner_callback(void *ptr, int component, int command, int arg); /* Provided by cx231xx-input.c */ diff --git a/drivers/media/video/cx2341x.c b/drivers/media/video/cx2341x.c index 8ded52946334..4c8e95853fa3 100644 --- a/drivers/media/video/cx2341x.c +++ b/drivers/media/video/cx2341x.c @@ -500,6 +500,8 @@ int cx2341x_ctrl_query(const struct cx2341x_mpeg_params *params, int err; switch (qctrl->id) { + case V4L2_CID_MPEG_CLASS: + return v4l2_ctrl_query_fill(qctrl, 0, 0, 0, 0); case V4L2_CID_MPEG_STREAM_TYPE: return v4l2_ctrl_query_fill(qctrl, V4L2_MPEG_STREAM_TYPE_MPEG2_PS, diff --git a/drivers/media/video/cx23885/cimax2.c b/drivers/media/video/cx23885/cimax2.c index 9a6536998d90..08582e58bdbf 100644 --- a/drivers/media/video/cx23885/cimax2.c +++ b/drivers/media/video/cx23885/cimax2.c @@ -312,7 +312,7 @@ static void netup_read_ci_status(struct work_struct *work) "TS config = %02x\n", __func__, state->ci_i2c_addr, 0, buf[0], buf[32]); - if (buf[0] && 1) + if (buf[0] & 1) state->status = DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY; else diff --git a/drivers/media/video/cx23885/cx23885-417.c b/drivers/media/video/cx23885/cx23885-417.c index 6f5df90af93e..2943bfd32a94 100644 --- a/drivers/media/video/cx23885/cx23885-417.c +++ b/drivers/media/video/cx23885/cx23885-417.c @@ -1742,7 +1742,6 @@ static struct video_device *cx23885_video_dev_alloc( if (NULL == vfd) return NULL; *vfd = *template; - vfd->minor = -1; snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name, type, cx23885_boards[tsport->dev->board].name); vfd->parent = &pci->dev; diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index 6d6293f7d428..ce29b5e34a11 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -181,6 +181,26 @@ struct cx23885_board cx23885_boards[] = { .portb = CX23885_MPEG_DVB, .portc = CX23885_MPEG_DVB, }, + [CX23885_BOARD_HAUPPAUGE_HVR1270] = { + .name = "Hauppauge WinTV-HVR1270", + .portc = CX23885_MPEG_DVB, + }, + [CX23885_BOARD_HAUPPAUGE_HVR1275] = { + .name = "Hauppauge WinTV-HVR1275", + .portc = CX23885_MPEG_DVB, + }, + [CX23885_BOARD_HAUPPAUGE_HVR1255] = { + .name = "Hauppauge WinTV-HVR1255", + .portc = CX23885_MPEG_DVB, + }, + [CX23885_BOARD_HAUPPAUGE_HVR1210] = { + .name = "Hauppauge WinTV-HVR1210", + .portc = CX23885_MPEG_DVB, + }, + [CX23885_BOARD_MYGICA_X8506] = { + .name = "Mygica X8506 DMB-TH", + .portb = CX23885_MPEG_DVB, + }, }; const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); @@ -280,6 +300,30 @@ struct cx23885_subid cx23885_subids[] = { .subvendor = 0x1b55, .subdevice = 0x2a2c, .card = CX23885_BOARD_NETUP_DUAL_DVBS2_CI, + }, { + .subvendor = 0x0070, + .subdevice = 0x2211, + .card = CX23885_BOARD_HAUPPAUGE_HVR1270, + }, { + .subvendor = 0x0070, + .subdevice = 0x2215, + .card = CX23885_BOARD_HAUPPAUGE_HVR1275, + }, { + .subvendor = 0x0070, + .subdevice = 0x2251, + .card = CX23885_BOARD_HAUPPAUGE_HVR1255, + }, { + .subvendor = 0x0070, + .subdevice = 0x2291, + .card = CX23885_BOARD_HAUPPAUGE_HVR1210, + }, { + .subvendor = 0x0070, + .subdevice = 0x2295, + .card = CX23885_BOARD_HAUPPAUGE_HVR1210, + }, { + .subvendor = 0x14f1, + .subdevice = 0x8651, + .card = CX23885_BOARD_MYGICA_X8506, }, }; const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids); @@ -321,6 +365,42 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) /* Make sure we support the board model */ switch (tv.model) { + case 22001: + /* WinTV-HVR1270 (PCIe, Retail, half height) + * ATSC/QAM and basic analog, IR Blast */ + case 22009: + /* WinTV-HVR1210 (PCIe, Retail, half height) + * DVB-T and basic analog, IR Blast */ + case 22011: + /* WinTV-HVR1270 (PCIe, Retail, half height) + * ATSC/QAM and basic analog, IR Recv */ + case 22019: + /* WinTV-HVR1210 (PCIe, Retail, half height) + * DVB-T and basic analog, IR Recv */ + case 22021: + /* WinTV-HVR1275 (PCIe, Retail, half height) + * ATSC/QAM and basic analog, IR Recv */ + case 22029: + /* WinTV-HVR1210 (PCIe, Retail, half height) + * DVB-T and basic analog, IR Recv */ + case 22101: + /* WinTV-HVR1270 (PCIe, Retail, full height) + * ATSC/QAM and basic analog, IR Blast */ + case 22109: + /* WinTV-HVR1210 (PCIe, Retail, full height) + * DVB-T and basic analog, IR Blast */ + case 22111: + /* WinTV-HVR1270 (PCIe, Retail, full height) + * ATSC/QAM and basic analog, IR Recv */ + case 22119: + /* WinTV-HVR1210 (PCIe, Retail, full height) + * DVB-T and basic analog, IR Recv */ + case 22121: + /* WinTV-HVR1275 (PCIe, Retail, full height) + * ATSC/QAM and basic analog, IR Recv */ + case 22129: + /* WinTV-HVR1210 (PCIe, Retail, full height) + * DVB-T and basic analog, IR Recv */ case 71009: /* WinTV-HVR1200 (PCIe, Retail, full height) * DVB-T and basic analog */ @@ -619,6 +699,30 @@ void cx23885_gpio_setup(struct cx23885_dev *dev) /* enable irq */ cx_write(GPIO_ISM, 0x00000000);/* INTERRUPTS active low*/ break; + case CX23885_BOARD_HAUPPAUGE_HVR1270: + case CX23885_BOARD_HAUPPAUGE_HVR1275: + case CX23885_BOARD_HAUPPAUGE_HVR1255: + case CX23885_BOARD_HAUPPAUGE_HVR1210: + /* GPIO-5 RF Control: 0 = RF1 Terrestrial, 1 = RF2 Cable */ + /* GPIO-6 I2C Gate which can isolate the demod from the bus */ + /* GPIO-9 Demod reset */ + + /* Put the parts into reset and back */ + cx23885_gpio_enable(dev, GPIO_9 | GPIO_6 | GPIO_5, 1); + cx23885_gpio_set(dev, GPIO_9 | GPIO_6 | GPIO_5); + cx23885_gpio_clear(dev, GPIO_9); + mdelay(20); + cx23885_gpio_set(dev, GPIO_9); + break; + case CX23885_BOARD_MYGICA_X8506: + /* GPIO-1 reset XC5000 */ + /* GPIO-2 reset LGS8GL5 */ + cx_set(GP0_IO, 0x00060000); + cx_clear(GP0_IO, 0x00000006); + mdelay(100); + cx_set(GP0_IO, 0x00060006); + mdelay(100); + break; } } @@ -631,6 +735,10 @@ int cx23885_ir_init(struct cx23885_dev *dev) case CX23885_BOARD_HAUPPAUGE_HVR1800: case CX23885_BOARD_HAUPPAUGE_HVR1200: case CX23885_BOARD_HAUPPAUGE_HVR1400: + case CX23885_BOARD_HAUPPAUGE_HVR1270: + case CX23885_BOARD_HAUPPAUGE_HVR1275: + case CX23885_BOARD_HAUPPAUGE_HVR1255: + case CX23885_BOARD_HAUPPAUGE_HVR1210: /* FIXME: Implement me */ break; case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP: @@ -666,6 +774,10 @@ void cx23885_card_setup(struct cx23885_dev *dev) case CX23885_BOARD_HAUPPAUGE_HVR1800lp: case CX23885_BOARD_HAUPPAUGE_HVR1200: case CX23885_BOARD_HAUPPAUGE_HVR1700: + case CX23885_BOARD_HAUPPAUGE_HVR1270: + case CX23885_BOARD_HAUPPAUGE_HVR1275: + case CX23885_BOARD_HAUPPAUGE_HVR1255: + case CX23885_BOARD_HAUPPAUGE_HVR1210: if (dev->i2c_bus[0].i2c_rc == 0) hauppauge_eeprom(dev, eeprom+0xc0); break; @@ -714,6 +826,11 @@ void cx23885_card_setup(struct cx23885_dev *dev) ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; break; + case CX23885_BOARD_MYGICA_X8506: + ts1->gen_ctrl_val = 0x5; /* Parallel */ + ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ + ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; + break; case CX23885_BOARD_HAUPPAUGE_HVR1250: case CX23885_BOARD_HAUPPAUGE_HVR1500: case CX23885_BOARD_HAUPPAUGE_HVR1500Q: @@ -723,6 +840,10 @@ void cx23885_card_setup(struct cx23885_dev *dev) case CX23885_BOARD_HAUPPAUGE_HVR1400: case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H: case CX23885_BOARD_COMPRO_VIDEOMATE_E650F: + case CX23885_BOARD_HAUPPAUGE_HVR1270: + case CX23885_BOARD_HAUPPAUGE_HVR1275: + case CX23885_BOARD_HAUPPAUGE_HVR1255: + case CX23885_BOARD_HAUPPAUGE_HVR1210: default: ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ ts2->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 beda42925ce7..bf7bb1c412fb 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -1700,9 +1700,13 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) } if (cx23885_boards[dev->board].cimax > 0 && - ((pci_status & PCI_MSK_GPIO0) || (pci_status & PCI_MSK_GPIO1))) - /* handled += cx23885_irq_gpio(dev, pci_status); */ - handled += netup_ci_slot_status(dev, pci_status); + ((pci_status & PCI_MSK_GPIO0) || + (pci_status & PCI_MSK_GPIO1))) { + + if (cx23885_boards[dev->board].cimax > 0) + handled += netup_ci_slot_status(dev, pci_status); + + } if (ts1_status) { if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) @@ -1729,6 +1733,88 @@ out: return IRQ_RETVAL(handled); } +static inline int encoder_on_portb(struct cx23885_dev *dev) +{ + return cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER; +} + +static inline int encoder_on_portc(struct cx23885_dev *dev) +{ + return cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER; +} + +/* Mask represents 32 different GPIOs, GPIO's are split into multiple + * registers depending on the board configuration (and whether the + * 417 encoder (wi it's own GPIO's) are present. Each GPIO bit will + * be pushed into the correct hardware register, regardless of the + * physical location. Certain registers are shared so we sanity check + * and report errors if we think we're tampering with a GPIo that might + * be assigned to the encoder (and used for the host bus). + * + * GPIO 2 thru 0 - On the cx23885 bridge + * GPIO 18 thru 3 - On the cx23417 host bus interface + * GPIO 23 thru 19 - On the cx25840 a/v core + */ +void cx23885_gpio_set(struct cx23885_dev *dev, u32 mask) +{ + if (mask & 0x7) + cx_set(GP0_IO, mask & 0x7); + + if (mask & 0x0007fff8) { + if (encoder_on_portb(dev) || encoder_on_portc(dev)) + printk(KERN_ERR + "%s: Setting GPIO on encoder ports\n", + dev->name); + cx_set(MC417_RWD, (mask & 0x0007fff8) >> 3); + } + + /* TODO: 23-19 */ + if (mask & 0x00f80000) + printk(KERN_INFO "%s: Unsupported\n", dev->name); +} + +void cx23885_gpio_clear(struct cx23885_dev *dev, u32 mask) +{ + if (mask & 0x00000007) + cx_clear(GP0_IO, mask & 0x7); + + if (mask & 0x0007fff8) { + if (encoder_on_portb(dev) || encoder_on_portc(dev)) + printk(KERN_ERR + "%s: Clearing GPIO moving on encoder ports\n", + dev->name); + cx_clear(MC417_RWD, (mask & 0x7fff8) >> 3); + } + + /* TODO: 23-19 */ + if (mask & 0x00f80000) + printk(KERN_INFO "%s: Unsupported\n", dev->name); +} + +void cx23885_gpio_enable(struct cx23885_dev *dev, u32 mask, int asoutput) +{ + if ((mask & 0x00000007) && asoutput) + cx_set(GP0_IO, (mask & 0x7) << 16); + else if ((mask & 0x00000007) && !asoutput) + cx_clear(GP0_IO, (mask & 0x7) << 16); + + if (mask & 0x0007fff8) { + if (encoder_on_portb(dev) || encoder_on_portc(dev)) + printk(KERN_ERR + "%s: Enabling GPIO on encoder ports\n", + dev->name); + } + + /* MC417_OEN is active low for output, write 1 for an input */ + if ((mask & 0x0007fff8) && asoutput) + cx_clear(MC417_OEN, (mask & 0x7fff8) >> 3); + + else if ((mask & 0x0007fff8) && !asoutput) + cx_set(MC417_OEN, (mask & 0x7fff8) >> 3); + + /* TODO: 23-19 */ +} + static int __devinit cx23885_initdev(struct pci_dev *pci_dev, const struct pci_device_id *pci_id) { diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index 1dc070da8652..48a975134ac5 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -45,12 +45,15 @@ #include "dibx000_common.h" #include "zl10353.h" #include "stv0900.h" +#include "stv0900_reg.h" #include "stv6110.h" #include "lnbh24.h" #include "cx24116.h" #include "cimax2.h" +#include "lgs8gxx.h" #include "netup-eeprom.h" #include "netup-init.h" +#include "lgdt3305.h" static unsigned int debug; @@ -122,7 +125,22 @@ static struct tda10048_config hauppauge_hvr1200_config = { .demod_address = 0x10 >> 1, .output_mode = TDA10048_SERIAL_OUTPUT, .fwbulkwritelen = TDA10048_BULKWRITE_200, - .inversion = TDA10048_INVERSION_ON + .inversion = TDA10048_INVERSION_ON, + .dtv6_if_freq_khz = TDA10048_IF_3300, + .dtv7_if_freq_khz = TDA10048_IF_3800, + .dtv8_if_freq_khz = TDA10048_IF_4300, + .clk_freq_khz = TDA10048_CLK_16000, +}; + +static struct tda10048_config hauppauge_hvr1210_config = { + .demod_address = 0x10 >> 1, + .output_mode = TDA10048_SERIAL_OUTPUT, + .fwbulkwritelen = TDA10048_BULKWRITE_200, + .inversion = TDA10048_INVERSION_ON, + .dtv6_if_freq_khz = TDA10048_IF_3300, + .dtv7_if_freq_khz = TDA10048_IF_3500, + .dtv8_if_freq_khz = TDA10048_IF_4000, + .clk_freq_khz = TDA10048_CLK_16000, }; static struct s5h1409_config hauppauge_ezqam_config = { @@ -194,6 +212,16 @@ static struct s5h1411_config dvico_s5h1411_config = { .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, }; +static struct s5h1411_config hcw_s5h1411_config = { + .output_mode = S5H1411_SERIAL_OUTPUT, + .gpio = S5H1411_GPIO_OFF, + .vsb_if = S5H1411_IF_44000, + .qam_if = S5H1411_IF_4000, + .inversion = S5H1411_INVERSION_ON, + .status_mode = S5H1411_DEMODLOCKING, + .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, +}; + static struct xc5000_config hauppauge_hvr1500q_tunerconfig = { .i2c_address = 0x61, .if_khz = 5380, @@ -215,15 +243,51 @@ static struct tda18271_std_map hauppauge_tda18271_std_map = { .if_lvl = 6, .rfagc_top = 0x37 }, }; +static struct tda18271_std_map hauppauge_hvr1200_tda18271_std_map = { + .dvbt_6 = { .if_freq = 3300, .agc_mode = 3, .std = 4, + .if_lvl = 1, .rfagc_top = 0x37, }, + .dvbt_7 = { .if_freq = 3800, .agc_mode = 3, .std = 5, + .if_lvl = 1, .rfagc_top = 0x37, }, + .dvbt_8 = { .if_freq = 4300, .agc_mode = 3, .std = 6, + .if_lvl = 1, .rfagc_top = 0x37, }, +}; + static struct tda18271_config hauppauge_tda18271_config = { .std_map = &hauppauge_tda18271_std_map, .gate = TDA18271_GATE_ANALOG, }; static struct tda18271_config hauppauge_hvr1200_tuner_config = { + .std_map = &hauppauge_hvr1200_tda18271_std_map, .gate = TDA18271_GATE_ANALOG, }; +static struct tda18271_config hauppauge_hvr1210_tuner_config = { + .gate = TDA18271_GATE_DIGITAL, +}; + +static struct tda18271_std_map hauppauge_hvr127x_std_map = { + .atsc_6 = { .if_freq = 3250, .agc_mode = 3, .std = 4, + .if_lvl = 1, .rfagc_top = 0x58 }, + .qam_6 = { .if_freq = 4000, .agc_mode = 3, .std = 5, + .if_lvl = 1, .rfagc_top = 0x58 }, +}; + +static struct tda18271_config hauppauge_hvr127x_config = { + .std_map = &hauppauge_hvr127x_std_map, +}; + +static struct lgdt3305_config hauppauge_lgdt3305_config = { + .i2c_addr = 0x0e, + .mpeg_mode = LGDT3305_MPEG_SERIAL, + .tpclk_edge = LGDT3305_TPCLK_FALLING_EDGE, + .tpvalid_polarity = LGDT3305_TP_VALID_HIGH, + .deny_i2c_rptr = 1, + .spectral_inversion = 1, + .qam_if_khz = 4000, + .vsb_if_khz = 3250, +}; + static struct dibx000_agc_config xc3028_agc_config = { BAND_VHF | BAND_UHF, /* band_caps */ @@ -317,13 +381,25 @@ static struct zl10353_config dvico_fusionhdtv_xc3028 = { .disable_i2c_gate_ctrl = 1, }; +static struct stv0900_reg stv0900_ts_regs[] = { + { R0900_TSGENERAL, 0x00 }, + { R0900_P1_TSSPEED, 0x40 }, + { R0900_P2_TSSPEED, 0x40 }, + { R0900_P1_TSCFGM, 0xc0 }, + { R0900_P2_TSCFGM, 0xc0 }, + { R0900_P1_TSCFGH, 0xe0 }, + { R0900_P2_TSCFGH, 0xe0 }, + { R0900_P1_TSCFGL, 0x20 }, + { R0900_P2_TSCFGL, 0x20 }, + { 0xffff, 0xff }, /* terminate */ +}; + static struct stv0900_config netup_stv0900_config = { .demod_address = 0x68, .xtal = 27000000, .clkmode = 3,/* 0-CLKI, 2-XTALI, else AUTO */ .diseqc_mode = 2,/* 2/3 PWM */ - .path1_mode = 2,/*Serial continues clock */ - .path2_mode = 2,/*Serial continues clock */ + .ts_config_regs = stv0900_ts_regs, .tun1_maddress = 0,/* 0x60 */ .tun2_maddress = 3,/* 0x63 */ .tun1_adc = 1,/* 1 Vpp */ @@ -368,10 +444,29 @@ static struct cx24116_config dvbworld_cx24116_config = { .demod_address = 0x05, }; +static struct lgs8gxx_config mygica_x8506_lgs8gl5_config = { + .prod = LGS8GXX_PROD_LGS8GL5, + .demod_address = 0x19, + .serial_ts = 0, + .ts_clk_pol = 1, + .ts_clk_gated = 1, + .if_clk_freq = 30400, /* 30.4 MHz */ + .if_freq = 5380, /* 5.38 MHz */ + .if_neg_center = 1, + .ext_adc = 0, + .adc_signed = 0, + .if_neg_edge = 0, +}; + +static struct xc5000_config mygica_x8506_xc5000_config = { + .i2c_address = 0x61, + .if_khz = 5380, +}; + static int dvb_register(struct cx23885_tsport *port) { struct cx23885_dev *dev = port->dev; - struct cx23885_i2c *i2c_bus = NULL; + struct cx23885_i2c *i2c_bus = NULL, *i2c_bus2 = NULL; struct videobuf_dvb_frontend *fe0; int ret; @@ -396,6 +491,29 @@ static int dvb_register(struct cx23885_tsport *port) &hauppauge_generic_tunerconfig, 0); } break; + case CX23885_BOARD_HAUPPAUGE_HVR1270: + case CX23885_BOARD_HAUPPAUGE_HVR1275: + i2c_bus = &dev->i2c_bus[0]; + fe0->dvb.frontend = dvb_attach(lgdt3305_attach, + &hauppauge_lgdt3305_config, + &i2c_bus->i2c_adap); + if (fe0->dvb.frontend != NULL) { + dvb_attach(tda18271_attach, fe0->dvb.frontend, + 0x60, &dev->i2c_bus[1].i2c_adap, + &hauppauge_hvr127x_config); + } + break; + case CX23885_BOARD_HAUPPAUGE_HVR1255: + i2c_bus = &dev->i2c_bus[0]; + fe0->dvb.frontend = dvb_attach(s5h1411_attach, + &hcw_s5h1411_config, + &i2c_bus->i2c_adap); + if (fe0->dvb.frontend != NULL) { + dvb_attach(tda18271_attach, fe0->dvb.frontend, + 0x60, &dev->i2c_bus[1].i2c_adap, + &hauppauge_tda18271_config); + } + break; case CX23885_BOARD_HAUPPAUGE_HVR1800: i2c_bus = &dev->i2c_bus[0]; switch (alt_tuner) { @@ -496,6 +614,17 @@ static int dvb_register(struct cx23885_tsport *port) &hauppauge_hvr1200_tuner_config); } break; + case CX23885_BOARD_HAUPPAUGE_HVR1210: + i2c_bus = &dev->i2c_bus[0]; + fe0->dvb.frontend = dvb_attach(tda10048_attach, + &hauppauge_hvr1210_config, + &i2c_bus->i2c_adap); + if (fe0->dvb.frontend != NULL) { + dvb_attach(tda18271_attach, fe0->dvb.frontend, + 0x60, &dev->i2c_bus[1].i2c_adap, + &hauppauge_hvr1210_tuner_config); + } + break; case CX23885_BOARD_HAUPPAUGE_HVR1400: i2c_bus = &dev->i2c_bus[0]; fe0->dvb.frontend = dvb_attach(dib7000p_attach, @@ -630,7 +759,8 @@ static int dvb_register(struct cx23885_tsport *port) if (!dvb_attach(lnbh24_attach, fe0->dvb.frontend, &i2c_bus->i2c_adap, - LNBH24_PCL, 0, 0x09)) + LNBH24_PCL, + LNBH24_TTX, 0x09)) printk(KERN_ERR "No LNBH24 found!\n"); @@ -650,7 +780,8 @@ static int dvb_register(struct cx23885_tsport *port) if (!dvb_attach(lnbh24_attach, fe0->dvb.frontend, &i2c_bus->i2c_adap, - LNBH24_PCL, 0, 0x0a)) + LNBH24_PCL, + LNBH24_TTX, 0x0a)) printk(KERN_ERR "No LNBH24 found!\n"); @@ -659,6 +790,19 @@ static int dvb_register(struct cx23885_tsport *port) break; } break; + case CX23885_BOARD_MYGICA_X8506: + i2c_bus = &dev->i2c_bus[0]; + i2c_bus2 = &dev->i2c_bus[1]; + fe0->dvb.frontend = dvb_attach(lgs8gxx_attach, + &mygica_x8506_lgs8gl5_config, + &i2c_bus->i2c_adap); + if (fe0->dvb.frontend != NULL) { + dvb_attach(xc5000_attach, + fe0->dvb.frontend, + &i2c_bus2->i2c_adap, + &mygica_x8506_xc5000_config); + } + break; default: printk(KERN_INFO "%s: The frontend of your DVB/ATSC card " " isn't supported yet\n", diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c index 3421bd12056a..384dec34134f 100644 --- a/drivers/media/video/cx23885/cx23885-i2c.c +++ b/drivers/media/video/cx23885/cx23885-i2c.c @@ -357,6 +357,18 @@ int cx23885_i2c_register(struct cx23885_i2c *bus) printk(KERN_WARNING "%s: i2c bus %d register FAILED\n", dev->name, bus->nr); + /* Instantiate the IR receiver device, if present */ + if (0 == bus->i2c_rc) { + struct i2c_board_info info; + const unsigned short addr_list[] = { + 0x6b, I2C_CLIENT_END + }; + + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "ir_video", I2C_NAME_SIZE); + i2c_new_probed_device(&bus->i2c_adap, &info, addr_list); + } + return bus->i2c_rc; } diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c index 68068c6d0987..70836af3ab48 100644 --- a/drivers/media/video/cx23885/cx23885-video.c +++ b/drivers/media/video/cx23885/cx23885-video.c @@ -796,6 +796,7 @@ static unsigned int video_poll(struct file *file, { struct cx23885_fh *fh = file->private_data; struct cx23885_buffer *buf; + unsigned int rc = POLLERR; if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) { if (!res_get(fh->dev, fh, RESOURCE_VBI)) @@ -803,23 +804,28 @@ static unsigned int video_poll(struct file *file, return videobuf_poll_stream(file, &fh->vbiq, wait); } + mutex_lock(&fh->vidq.vb_lock); if (res_check(fh, RESOURCE_VIDEO)) { /* streaming capture */ if (list_empty(&fh->vidq.stream)) - return POLLERR; + goto done; buf = list_entry(fh->vidq.stream.next, struct cx23885_buffer, vb.stream); } else { /* read() capture */ buf = (struct cx23885_buffer *)fh->vidq.read_buf; if (NULL == buf) - return POLLERR; + goto done; } poll_wait(file, &buf->vb.done, wait); if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR) - return POLLIN|POLLRDNORM; - return 0; + rc = POLLIN|POLLRDNORM; + else + rc = 0; +done: + mutex_unlock(&fh->vidq.vb_lock); + return rc; } static int video_release(struct file *file) @@ -957,15 +963,8 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, } f->fmt.pix.field = field; - if (f->fmt.pix.height < 32) - f->fmt.pix.height = 32; - if (f->fmt.pix.height > maxh) - f->fmt.pix.height = maxh; - if (f->fmt.pix.width < 48) - f->fmt.pix.width = 48; - if (f->fmt.pix.width > maxw) - f->fmt.pix.width = maxw; - f->fmt.pix.width &= ~0x03; + v4l_bound_align_image(&f->fmt.pix.width, 48, maxw, 2, + &f->fmt.pix.height, 32, maxh, 0, 0); f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3; f->fmt.pix.sizeimage = diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index 85642831ea8e..1a2ac518a3f1 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -71,6 +71,22 @@ #define CX23885_BOARD_TEVII_S470 15 #define CX23885_BOARD_DVBWORLD_2005 16 #define CX23885_BOARD_NETUP_DUAL_DVBS2_CI 17 +#define CX23885_BOARD_HAUPPAUGE_HVR1270 18 +#define CX23885_BOARD_HAUPPAUGE_HVR1275 19 +#define CX23885_BOARD_HAUPPAUGE_HVR1255 20 +#define CX23885_BOARD_HAUPPAUGE_HVR1210 21 +#define CX23885_BOARD_MYGICA_X8506 22 + +#define GPIO_0 0x00000001 +#define GPIO_1 0x00000002 +#define GPIO_2 0x00000004 +#define GPIO_3 0x00000008 +#define GPIO_4 0x00000010 +#define GPIO_5 0x00000020 +#define GPIO_6 0x00000040 +#define GPIO_7 0x00000080 +#define GPIO_8 0x00000100 +#define GPIO_9 0x00000200 /* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM B/G/H/LC */ #define CX23885_NORMS (\ @@ -422,6 +438,11 @@ extern int cx23885_restart_queue(struct cx23885_tsport *port, extern void cx23885_wakeup(struct cx23885_tsport *port, struct cx23885_dmaqueue *q, u32 count); +extern void cx23885_gpio_set(struct cx23885_dev *dev, u32 mask); +extern void cx23885_gpio_clear(struct cx23885_dev *dev, u32 mask); +extern void cx23885_gpio_enable(struct cx23885_dev *dev, u32 mask, + int asoutput); + /* ----------------------------------------------------------- */ /* cx23885-cards.c */ diff --git a/drivers/media/video/cx88/Makefile b/drivers/media/video/cx88/Makefile index b06b1275a9ec..5b7e26761f0a 100644 --- a/drivers/media/video/cx88/Makefile +++ b/drivers/media/video/cx88/Makefile @@ -1,5 +1,5 @@ cx88xx-objs := cx88-cards.o cx88-core.o cx88-i2c.o cx88-tvaudio.o \ - cx88-input.o + cx88-dsp.o cx88-input.o cx8800-objs := cx88-video.o cx88-vbi.o cx8802-objs := cx88-mpeg.o diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index 0ccdf36626e3..5a67445dd6ed 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c @@ -871,7 +871,7 @@ static struct pci_driver cx88_audio_pci_driver = { .name = "cx88_audio", .id_table = cx88_audio_pci_tbl, .probe = cx88_audio_initdev, - .remove = cx88_audio_finidev, + .remove = __devexit_p(cx88_audio_finidev), }; /**************************************************************************** @@ -881,7 +881,7 @@ static struct pci_driver cx88_audio_pci_driver = { /* * module init */ -static int cx88_audio_init(void) +static int __init cx88_audio_init(void) { printk(KERN_INFO "cx2388x alsa driver version %d.%d.%d loaded\n", (CX88_VERSION_CODE >> 16) & 0xff, @@ -897,9 +897,8 @@ static int cx88_audio_init(void) /* * module remove */ -static void cx88_audio_fini(void) +static void __exit cx88_audio_fini(void) { - pci_unregister_driver(&cx88_audio_pci_driver); } diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index 6bbbfc66bb4b..a5cc1c1fc2d6 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -1524,33 +1524,45 @@ static const struct cx88_board cx88_boards[] = { }, .mpeg = CX88_MPEG_DVB, }, + /* Terry Wu */ + /* TV Audio : set GPIO 2, 18, 19 value to 0, 1, 0 */ + /* FM Audio : set GPIO 2, 18, 19 value to 0, 0, 0 */ + /* Line-in Audio : set GPIO 2, 18, 19 value to 0, 1, 1 */ + /* Mute Audio : set GPIO 2 value to 1 */ [CX88_BOARD_WINFAST_TV2000_XP_GLOBAL] = { - .name = "Winfast TV2000 XP Global", + .name = "Leadtek TV2000 XP Global", .tuner_type = TUNER_XC2028, .tuner_addr = 0x61, + .radio_type = TUNER_XC2028, + .radio_addr = 0x61, .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, - .gpio0 = 0x0400, /* pin 2:mute = 0 (off?) */ + .gpio0 = 0x0400, /* pin 2 = 0 */ .gpio1 = 0x0000, - .gpio2 = 0x0800, /* pin 19:audio = 0 (tv) */ - + .gpio2 = 0x0C04, /* pin 18 = 1, pin 19 = 0 */ + .gpio3 = 0x0000, }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, - .gpio0 = 0x0400, /* probably? or 0x0404 to turn mute on */ + .gpio0 = 0x0400, /* pin 2 = 0 */ .gpio1 = 0x0000, - .gpio2 = 0x0808, /* pin 19:audio = 1 (line) */ - + .gpio2 = 0x0C0C, /* pin 18 = 1, pin 19 = 1 */ + .gpio3 = 0x0000, }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, + .gpio0 = 0x0400, /* pin 2 = 0 */ + .gpio1 = 0x0000, + .gpio2 = 0x0C0C, /* pin 18 = 1, pin 19 = 1 */ + .gpio3 = 0x0000, } }, .radio = { .type = CX88_RADIO, - .gpio0 = 0x004ff, - .gpio1 = 0x010ff, - .gpio2 = 0x0ff, + .gpio0 = 0x0400, /* pin 2 = 0 */ + .gpio1 = 0x0000, + .gpio2 = 0x0C00, /* pin 18 = 0, pin 19 = 0 */ + .gpio3 = 0x0000, }, }, [CX88_BOARD_POWERCOLOR_REAL_ANGEL] = { @@ -1969,6 +1981,54 @@ static const struct cx88_board cx88_boards[] = { }, .mpeg = CX88_MPEG_DVB, }, + [CX88_BOARD_HAUPPAUGE_IRONLY] = { + .name = "Hauppauge WinTV-IR Only", + .tuner_type = UNSET, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + }, + [CX88_BOARD_WINFAST_DTV1800H] = { + .name = "Leadtek WinFast DTV1800 Hybrid", + .tuner_type = TUNER_XC2028, + .radio_type = TUNER_XC2028, + .tuner_addr = 0x61, + .radio_addr = 0x61, + /* + * GPIO setting + * + * 2: mute (0=off,1=on) + * 12: tuner reset pin + * 13: audio source (0=tuner audio,1=line in) + * 14: FM (0=on,1=off ???) + */ + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x0400, /* pin 2 = 0 */ + .gpio1 = 0x6040, /* pin 13 = 0, pin 14 = 1 */ + .gpio2 = 0x0000, + }, { + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x0400, /* pin 2 = 0 */ + .gpio1 = 0x6060, /* pin 13 = 1, pin 14 = 1 */ + .gpio2 = 0x0000, + }, { + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x0400, /* pin 2 = 0 */ + .gpio1 = 0x6060, /* pin 13 = 1, pin 14 = 1 */ + .gpio2 = 0x0000, + } }, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0x0400, /* pin 2 = 0 */ + .gpio1 = 0x6000, /* pin 13 = 0, pin 14 = 0 */ + .gpio2 = 0x0000, + }, + .mpeg = CX88_MPEG_DVB, + }, }; /* ------------------------------------------------------------------ */ @@ -2382,6 +2442,49 @@ static const struct cx88_subid cx88_subids[] = { .subvendor = 0x153b, .subdevice = 0x1177, .card = CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII, + }, { + .subvendor = 0x0070, + .subdevice = 0x9290, + .card = CX88_BOARD_HAUPPAUGE_IRONLY, + }, { + .subvendor = 0x107d, + .subdevice = 0x6654, + .card = CX88_BOARD_WINFAST_DTV1800H, + }, { + /* PVR2000 PAL Model [107d:6630] */ + .subvendor = 0x107d, + .subdevice = 0x6630, + .card = CX88_BOARD_LEADTEK_PVR2000, + }, { + /* PVR2000 PAL Model [107d:6638] */ + .subvendor = 0x107d, + .subdevice = 0x6638, + .card = CX88_BOARD_LEADTEK_PVR2000, + }, { + /* PVR2000 NTSC Model [107d:6631] */ + .subvendor = 0x107d, + .subdevice = 0x6631, + .card = CX88_BOARD_LEADTEK_PVR2000, + }, { + /* PVR2000 NTSC Model [107d:6637] */ + .subvendor = 0x107d, + .subdevice = 0x6637, + .card = CX88_BOARD_LEADTEK_PVR2000, + }, { + /* PVR2000 NTSC Model [107d:663d] */ + .subvendor = 0x107d, + .subdevice = 0x663d, + .card = CX88_BOARD_LEADTEK_PVR2000, + }, { + /* DV2000 NTSC Model [107d:6621] */ + .subvendor = 0x107d, + .subdevice = 0x6621, + .card = CX88_BOARD_WINFAST_DV2000, + }, { + /* TV2000 XP Global [107d:6618] */ + .subvendor = 0x107d, + .subdevice = 0x6618, + .card = CX88_BOARD_WINFAST_TV2000_XP_GLOBAL, }, }; @@ -2390,12 +2493,6 @@ static const struct cx88_subid cx88_subids[] = { static void leadtek_eeprom(struct cx88_core *core, u8 *eeprom_data) { - /* This is just for the "Winfast 2000XP Expert" board ATM; I don't have data on - * any others. - * - * Byte 0 is 1 on the NTSC board. - */ - if (eeprom_data[4] != 0x7d || eeprom_data[5] != 0x10 || eeprom_data[7] != 0x66) { @@ -2403,8 +2500,19 @@ static void leadtek_eeprom(struct cx88_core *core, u8 *eeprom_data) return; } - core->board.tuner_type = (eeprom_data[6] == 0x13) ? - TUNER_PHILIPS_FM1236_MK3 : TUNER_PHILIPS_FM1216ME_MK3; + /* Terry Wu */ + switch (eeprom_data[6]) { + case 0x13: /* SSID 6613 for TV2000 XP Expert NTSC Model */ + case 0x21: /* SSID 6621 for DV2000 NTSC Model */ + case 0x31: /* SSID 6631 for PVR2000 NTSC Model */ + case 0x37: /* SSID 6637 for PVR2000 NTSC Model */ + case 0x3d: /* SSID 6637 for PVR2000 NTSC Model */ + core->board.tuner_type = TUNER_PHILIPS_FM1236_MK3; + break; + default: + core->board.tuner_type = TUNER_PHILIPS_FM1216ME_MK3; + break; + } info_printk(core, "Leadtek Winfast 2000XP Expert config: " "tuner=%d, eeprom[0]=0x%02x\n", @@ -2448,6 +2556,7 @@ static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data) case 90500: /* Nova-T-PCI (oem) */ case 90501: /* Nova-T-PCI (oem/IR) */ case 92000: /* Nova-SE2 (OEM, No Video or IR) */ + case 92900: /* WinTV-IROnly (No analog or digital Video inputs) */ case 94009: /* WinTV-HVR1100 (Video and IR Retail) */ case 94501: /* WinTV-HVR1100 (Video and IR OEM) */ case 96009: /* WinTV-HVR1300 (PAL Video, MPEG Video and IR RX) */ @@ -2579,6 +2688,23 @@ static int cx88_xc3028_geniatech_tuner_callback(struct cx88_core *core, return -EINVAL; } +static int cx88_xc3028_winfast1800h_callback(struct cx88_core *core, + int command, int arg) +{ + switch (command) { + case XC2028_TUNER_RESET: + /* GPIO 12 (xc3028 tuner reset) */ + cx_set(MO_GP1_IO, 0x1010); + mdelay(50); + cx_clear(MO_GP1_IO, 0x10); + mdelay(50); + cx_set(MO_GP1_IO, 0x10); + mdelay(50); + return 0; + } + return -EINVAL; +} + /* ------------------------------------------------------------------- */ /* some Divco specific stuff */ static int cx88_pv_8000gt_callback(struct cx88_core *core, @@ -2639,7 +2765,6 @@ static int cx88_xc2028_tuner_callback(struct cx88_core *core, { /* Board-specific callbacks */ switch (core->boardnr) { - case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL: case CX88_BOARD_POWERCOLOR_REAL_ANGEL: case CX88_BOARD_GENIATECH_X8000_MT: case CX88_BOARD_KWORLD_ATSC_120: @@ -2651,6 +2776,9 @@ static int cx88_xc2028_tuner_callback(struct cx88_core *core, case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO: case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO: return cx88_dvico_xc2028_callback(core, command, arg); + case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL: + case CX88_BOARD_WINFAST_DTV1800H: + return cx88_xc3028_winfast1800h_callback(core, command, arg); } switch (command) { @@ -2690,10 +2818,22 @@ static int cx88_xc5000_tuner_callback(struct cx88_core *core, switch (core->boardnr) { case CX88_BOARD_PINNACLE_PCTV_HD_800i: if (command == 0) { /* This is the reset command from xc5000 */ - /* Reset XC5000 tuner via SYS_RSTO_pin */ - cx_write(MO_SRST_IO, 0); - msleep(10); - cx_write(MO_SRST_IO, 1); + + /* djh - According to the engineer at PCTV Systems, + the xc5000 reset pin is supposed to be on GPIO12. + However, despite three nights of effort, pulling + that GPIO low didn't reset the xc5000. While + pulling MO_SRST_IO low does reset the xc5000, this + also resets in the s5h1409 being reset as well. + This causes tuning to always fail since the internal + state of the s5h1409 does not match the driver's + state. Given that the only two conditions in which + the driver performs a reset is during firmware load + and powering down the chip, I am taking out the + reset. We know that the chip is being reset + when the cx88 comes online, and not being able to + do power management for this board is worse than + not having any tuning at all. */ return 0; } else { err_printk(core, "xc5000: unknown tuner " @@ -2825,6 +2965,17 @@ static void cx88_card_setup_pre_i2c(struct cx88_core *core) cx_set(MO_GP0_IO, 0x00000080); /* 702 out of reset */ udelay(1000); break; + + case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL: + case CX88_BOARD_WINFAST_DTV1800H: + /* GPIO 12 (xc3028 tuner reset) */ + cx_set(MO_GP1_IO, 0x1010); + mdelay(50); + cx_clear(MO_GP1_IO, 0x10); + mdelay(50); + cx_set(MO_GP1_IO, 0x10); + mdelay(50); + break; } } @@ -2845,12 +2996,14 @@ void cx88_setup_xc3028(struct cx88_core *core, struct xc2028_ctrl *ctl) core->i2c_algo.udelay = 16; break; case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO: + case CX88_BOARD_WINFAST_DTV1800H: ctl->demod = XC3028_FE_ZARLINK456; break; case CX88_BOARD_KWORLD_ATSC_120: case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO: ctl->demod = XC3028_FE_OREN538; break; + case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL: case CX88_BOARD_PROLINK_PV_GLOBAL_XTREME: case CX88_BOARD_PROLINK_PV_8000GT: /* @@ -2894,6 +3047,8 @@ static void cx88_card_setup(struct cx88_core *core) if (0 == core->i2c_rc) gdi_eeprom(core, eeprom); break; + case CX88_BOARD_LEADTEK_PVR2000: + case CX88_BOARD_WINFAST_DV2000: case CX88_BOARD_WINFAST2000XP_EXPERT: if (0 == core->i2c_rc) leadtek_eeprom(core, eeprom); @@ -2907,6 +3062,7 @@ static void cx88_card_setup(struct cx88_core *core) case CX88_BOARD_HAUPPAUGE_HVR1300: case CX88_BOARD_HAUPPAUGE_HVR4000: case CX88_BOARD_HAUPPAUGE_HVR4000LITE: + case CX88_BOARD_HAUPPAUGE_IRONLY: if (0 == core->i2c_rc) hauppauge_eeprom(core, eeprom); break; diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index 0e149b22bd19..cf634606ba9a 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -231,7 +231,7 @@ cx88_free_buffer(struct videobuf_queue *q, struct cx88_buffer *buf) * can use the whole SDRAM for the DMA fifos. To simplify things, we * use a static memory layout. That surely will waste memory in case * we don't use all DMA channels at the same time (which will be the - * case most of the time). But that still gives us enougth FIFO space + * case most of the time). But that still gives us enough FIFO space * to be able to deal with insane long pci latencies ... * * FIFO space allocations: @@ -241,6 +241,7 @@ cx88_free_buffer(struct videobuf_queue *q, struct cx88_buffer *buf) * channel 24 (vbi) - 4.0k * channels 25+26 (audio) - 4.0k * channel 28 (mpeg) - 4.0k + * channel 27 (audio rds)- 3.0k * TOTAL = 29.0k * * Every channel has 160 bytes control data (64 bytes instruction @@ -337,6 +338,18 @@ struct sram_channel cx88_sram_channels[] = { .cnt1_reg = MO_DMA28_CNT1, .cnt2_reg = MO_DMA28_CNT2, }, + [SRAM_CH27] = { + .name = "audio rds", + .cmds_start = 0x1801C0, + .ctrl_start = 0x180860, + .cdt = 0x180860 + 64, + .fifo_start = 0x187400, + .fifo_size = 0x000C00, + .ptr1_reg = MO_DMA27_PTR1, + .ptr2_reg = MO_DMA27_PTR2, + .cnt1_reg = MO_DMA27_CNT1, + .cnt2_reg = MO_DMA27_CNT2, + }, }; int cx88_sram_channel_setup(struct cx88_core *core, @@ -598,6 +611,7 @@ int cx88_reset(struct cx88_core *core) cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH25], 128, 0); cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH26], 128, 0); cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH28], 188*4, 0); + cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH27], 128, 0); /* misc init ... */ cx_write(MO_INPUT_FORMAT, ((1 << 13) | // agc enable @@ -796,6 +810,8 @@ int cx88_start_audio_dma(struct cx88_core *core) /* constant 128 made buzz in analog Nicam-stereo for bigger fifo_size */ int bpl = cx88_sram_channels[SRAM_CH25].fifo_size/4; + int rds_bpl = cx88_sram_channels[SRAM_CH27].fifo_size/AUD_RDS_LINES; + /* If downstream RISC is enabled, bail out; ALSA is managing DMA */ if (cx_read(MO_AUD_DMACNTRL) & 0x10) return 0; @@ -803,12 +819,14 @@ int cx88_start_audio_dma(struct cx88_core *core) /* setup fifo + format */ cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH25], bpl, 0); cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH26], bpl, 0); + cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH27], + rds_bpl, 0); cx_write(MO_AUDD_LNGTH, bpl); /* fifo bpl size */ - cx_write(MO_AUDR_LNGTH, bpl); /* fifo bpl size */ + cx_write(MO_AUDR_LNGTH, rds_bpl); /* fifo bpl size */ - /* start dma */ - cx_write(MO_AUD_DMACNTRL, 0x0003); /* Up and Down fifo enable */ + /* enable Up, Down and Audio RDS fifo */ + cx_write(MO_AUD_DMACNTRL, 0x0007); return 0; } @@ -1010,7 +1028,6 @@ struct video_device *cx88_vdev_init(struct cx88_core *core, if (NULL == vfd) return NULL; *vfd = *template; - vfd->minor = -1; vfd->v4l2_dev = &core->v4l2_dev; vfd->parent = &pci->dev; vfd->release = video_device_release; diff --git a/drivers/media/video/cx88/cx88-dsp.c b/drivers/media/video/cx88/cx88-dsp.c new file mode 100644 index 000000000000..3e5eaf3fe2a6 --- /dev/null +++ b/drivers/media/video/cx88/cx88-dsp.c @@ -0,0 +1,312 @@ +/* + * + * Stereo and SAP detection for cx88 + * + * Copyright (c) 2009 Marton Balint + * + * 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 +#include +#include +#include + +#include "cx88.h" +#include "cx88-reg.h" + +#define INT_PI ((s32)(3.141592653589 * 32768.0)) + +#define compat_remainder(a, b) \ + ((float)(((s32)((a)*100))%((s32)((b)*100)))/100.0) + +#define baseband_freq(carrier, srate, tone) ((s32)( \ + (compat_remainder(carrier + tone, srate)) / srate * 2 * INT_PI)) + +/* We calculate the baseband frequencies of the carrier and the pilot tones + * based on the the sampling rate of the audio rds fifo. */ + +#define FREQ_A2_CARRIER baseband_freq(54687.5, 2689.36, 0.0) +#define FREQ_A2_DUAL baseband_freq(54687.5, 2689.36, 274.1) +#define FREQ_A2_STEREO baseband_freq(54687.5, 2689.36, 117.5) + +/* The frequencies below are from the reference driver. They probably need + * further adjustments, because they are not tested at all. You may even need + * to play a bit with the registers of the chip to select the proper signal + * for the input of the audio rds fifo, and measure it's sampling rate to + * calculate the proper baseband frequencies... */ + +#define FREQ_A2M_CARRIER ((s32)(2.114516 * 32768.0)) +#define FREQ_A2M_DUAL ((s32)(2.754916 * 32768.0)) +#define FREQ_A2M_STEREO ((s32)(2.462326 * 32768.0)) + +#define FREQ_EIAJ_CARRIER ((s32)(1.963495 * 32768.0)) /* 5pi/8 */ +#define FREQ_EIAJ_DUAL ((s32)(2.562118 * 32768.0)) +#define FREQ_EIAJ_STEREO ((s32)(2.601053 * 32768.0)) + +#define FREQ_BTSC_DUAL ((s32)(1.963495 * 32768.0)) /* 5pi/8 */ +#define FREQ_BTSC_DUAL_REF ((s32)(1.374446 * 32768.0)) /* 7pi/16 */ + +#define FREQ_BTSC_SAP ((s32)(2.471532 * 32768.0)) +#define FREQ_BTSC_SAP_REF ((s32)(1.730072 * 32768.0)) + +/* The spectrum of the signal should be empty between these frequencies. */ +#define FREQ_NOISE_START ((s32)(0.100000 * 32768.0)) +#define FREQ_NOISE_END ((s32)(1.200000 * 32768.0)) + +static unsigned int dsp_debug; +module_param(dsp_debug, int, 0644); +MODULE_PARM_DESC(dsp_debug, "enable audio dsp debug messages"); + +#define dprintk(level, fmt, arg...) if (dsp_debug >= level) \ + printk(KERN_DEBUG "%s/0: " fmt, core->name , ## arg) + +static s32 int_cos(u32 x) +{ + u32 t2, t4, t6, t8; + s32 ret; + u16 period = x / INT_PI; + if (period % 2) + return -int_cos(x - INT_PI); + x = x % INT_PI; + if (x > INT_PI/2) + return -int_cos(INT_PI/2 - (x % (INT_PI/2))); + /* Now x is between 0 and INT_PI/2. + * To calculate cos(x) we use it's Taylor polinom. */ + t2 = x*x/32768/2; + t4 = t2*x/32768*x/32768/3/4; + t6 = t4*x/32768*x/32768/5/6; + t8 = t6*x/32768*x/32768/7/8; + ret = 32768-t2+t4-t6+t8; + return ret; +} + +static u32 int_goertzel(s16 x[], u32 N, u32 freq) +{ + /* We use the Goertzel algorithm to determine the power of the + * given frequency in the signal */ + s32 s_prev = 0; + s32 s_prev2 = 0; + s32 coeff = 2*int_cos(freq); + u32 i; + + u64 tmp; + u32 divisor; + + for (i = 0; i < N; i++) { + s32 s = x[i] + ((s64)coeff*s_prev/32768) - s_prev2; + s_prev2 = s_prev; + s_prev = s; + } + + tmp = (s64)s_prev2 * s_prev2 + (s64)s_prev * s_prev - + (s64)coeff * s_prev2 * s_prev / 32768; + + /* XXX: N must be low enough so that N*N fits in s32. + * Else we need two divisions. */ + divisor = N * N; + do_div(tmp, divisor); + + return (u32) tmp; +} + +static u32 freq_magnitude(s16 x[], u32 N, u32 freq) +{ + u32 sum = int_goertzel(x, N, freq); + return (u32)int_sqrt(sum); +} + +static u32 noise_magnitude(s16 x[], u32 N, u32 freq_start, u32 freq_end) +{ + int i; + u32 sum = 0; + u32 freq_step; + int samples = 5; + + if (N > 192) { + /* The last 192 samples are enough for noise detection */ + x += (N-192); + N = 192; + } + + freq_step = (freq_end - freq_start) / (samples - 1); + + for (i = 0; i < samples; i++) { + sum += int_goertzel(x, N, freq_start); + freq_start += freq_step; + } + + return (u32)int_sqrt(sum / samples); +} + +static s32 detect_a2_a2m_eiaj(struct cx88_core *core, s16 x[], u32 N) +{ + s32 carrier, stereo, dual, noise; + s32 carrier_freq, stereo_freq, dual_freq; + s32 ret; + + switch (core->tvaudio) { + case WW_BG: + case WW_DK: + carrier_freq = FREQ_A2_CARRIER; + stereo_freq = FREQ_A2_STEREO; + dual_freq = FREQ_A2_DUAL; + break; + case WW_M: + carrier_freq = FREQ_A2M_CARRIER; + stereo_freq = FREQ_A2M_STEREO; + dual_freq = FREQ_A2M_DUAL; + break; + case WW_EIAJ: + carrier_freq = FREQ_EIAJ_CARRIER; + stereo_freq = FREQ_EIAJ_STEREO; + dual_freq = FREQ_EIAJ_DUAL; + break; + default: + printk(KERN_WARNING "%s/0: unsupported audio mode %d for %s\n", + core->name, core->tvaudio, __func__); + return UNSET; + } + + carrier = freq_magnitude(x, N, carrier_freq); + stereo = freq_magnitude(x, N, stereo_freq); + dual = freq_magnitude(x, N, dual_freq); + noise = noise_magnitude(x, N, FREQ_NOISE_START, FREQ_NOISE_END); + + dprintk(1, "detect a2/a2m/eiaj: carrier=%d, stereo=%d, dual=%d, " + "noise=%d\n", carrier, stereo, dual, noise); + + if (stereo > dual) + ret = V4L2_TUNER_SUB_STEREO; + else + ret = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; + + if (core->tvaudio == WW_EIAJ) { + /* EIAJ checks may need adjustments */ + if ((carrier > max(stereo, dual)*2) && + (carrier < max(stereo, dual)*6) && + (carrier > 20 && carrier < 200) && + (max(stereo, dual) > min(stereo, dual))) { + /* For EIAJ the carrier is always present, + so we probably don't need noise detection */ + return ret; + } + } else { + if ((carrier > max(stereo, dual)*2) && + (carrier < max(stereo, dual)*8) && + (carrier > 20 && carrier < 200) && + (noise < 10) && + (max(stereo, dual) > min(stereo, dual)*2)) { + return ret; + } + } + return V4L2_TUNER_SUB_MONO; +} + +static s32 detect_btsc(struct cx88_core *core, s16 x[], u32 N) +{ + s32 sap_ref = freq_magnitude(x, N, FREQ_BTSC_SAP_REF); + s32 sap = freq_magnitude(x, N, FREQ_BTSC_SAP); + s32 dual_ref = freq_magnitude(x, N, FREQ_BTSC_DUAL_REF); + s32 dual = freq_magnitude(x, N, FREQ_BTSC_DUAL); + dprintk(1, "detect btsc: dual_ref=%d, dual=%d, sap_ref=%d, sap=%d" + "\n", dual_ref, dual, sap_ref, sap); + /* FIXME: Currently not supported */ + return UNSET; +} + +static s16 *read_rds_samples(struct cx88_core *core, u32 *N) +{ + struct sram_channel *srch = &cx88_sram_channels[SRAM_CH27]; + s16 *samples; + + unsigned int i; + unsigned int bpl = srch->fifo_size/AUD_RDS_LINES; + unsigned int spl = bpl/4; + unsigned int sample_count = spl*(AUD_RDS_LINES-1); + + u32 current_address = cx_read(srch->ptr1_reg); + u32 offset = (current_address - srch->fifo_start + bpl); + + dprintk(1, "read RDS samples: current_address=%08x (offset=%08x), " + "sample_count=%d, aud_intstat=%08x\n", current_address, + current_address - srch->fifo_start, sample_count, + cx_read(MO_AUD_INTSTAT)); + + samples = kmalloc(sizeof(s16)*sample_count, GFP_KERNEL); + if (!samples) + return NULL; + + *N = sample_count; + + for (i = 0; i < sample_count; i++) { + offset = offset % (AUD_RDS_LINES*bpl); + samples[i] = cx_read(srch->fifo_start + offset); + offset += 4; + } + + if (dsp_debug >= 2) { + dprintk(2, "RDS samples dump: "); + for (i = 0; i < sample_count; i++) + printk("%hd ", samples[i]); + printk(".\n"); + } + + return samples; +} + +s32 cx88_dsp_detect_stereo_sap(struct cx88_core *core) +{ + s16 *samples; + u32 N = 0; + s32 ret = UNSET; + + /* If audio RDS fifo is disabled, we can't read the samples */ + if (!(cx_read(MO_AUD_DMACNTRL) & 0x04)) + return ret; + if (!(cx_read(AUD_CTL) & EN_FMRADIO_EN_RDS)) + return ret; + + /* Wait at least 500 ms after an audio standard change */ + if (time_before(jiffies, core->last_change + msecs_to_jiffies(500))) + return ret; + + samples = read_rds_samples(core, &N); + + if (!samples) + return ret; + + switch (core->tvaudio) { + case WW_BG: + case WW_DK: + ret = detect_a2_a2m_eiaj(core, samples, N); + break; + case WW_BTSC: + ret = detect_btsc(core, samples, N); + break; + } + + kfree(samples); + + if (UNSET != ret) + dprintk(1, "stereo/sap detection result:%s%s%s\n", + (ret & V4L2_TUNER_SUB_MONO) ? " mono" : "", + (ret & V4L2_TUNER_SUB_STEREO) ? " stereo" : "", + (ret & V4L2_TUNER_SUB_LANG2) ? " dual" : ""); + + return ret; +} +EXPORT_SYMBOL(cx88_dsp_detect_stereo_sap); + diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index 9389cf290c1b..c44e87600219 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -1014,6 +1014,7 @@ static int dvb_register(struct cx8802_dev *dev) } break; case CX88_BOARD_PINNACLE_HYBRID_PCTV: + case CX88_BOARD_WINFAST_DTV1800H: fe0->dvb.frontend = dvb_attach(zl10353_attach, &cx88_pinnacle_hybrid_pctv, &core->i2c_adap); diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c index 996b4ed5a4fc..ee1ca39db06a 100644 --- a/drivers/media/video/cx88/cx88-i2c.c +++ b/drivers/media/video/cx88/cx88-i2c.c @@ -180,6 +180,19 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci) do_i2c_scan(core->name,&core->i2c_client); } else printk("%s: i2c register FAILED\n", core->name); + + /* Instantiate the IR receiver device, if present */ + if (0 == core->i2c_rc) { + struct i2c_board_info info; + const unsigned short addr_list[] = { + 0x18, 0x6b, 0x71, + I2C_CLIENT_END + }; + + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "ir_video", I2C_NAME_SIZE); + i2c_new_probed_device(&core->i2c_adap, &info, addr_list); + } return core->i2c_rc; } diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index ec05312a9b62..d91f5c51206d 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c @@ -91,6 +91,8 @@ static void cx88_ir_handle_key(struct cx88_IR *ir) gpio=(gpio & 0x7fd) + (auxgpio & 0xef); break; case CX88_BOARD_WINFAST_DTV1000: + case CX88_BOARD_WINFAST_DTV1800H: + case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL: gpio = (gpio & 0x6ff) | ((cx_read(MO_GP1_IO) << 8) & 0x900); auxgpio = gpio; break; @@ -217,11 +219,13 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) case CX88_BOARD_HAUPPAUGE_HVR4000LITE: case CX88_BOARD_PCHDTV_HD3000: case CX88_BOARD_PCHDTV_HD5500: + case CX88_BOARD_HAUPPAUGE_IRONLY: ir_codes = ir_codes_hauppauge_new; ir_type = IR_TYPE_RC5; ir->sampling = 1; break; case CX88_BOARD_WINFAST_DTV2000H: + case CX88_BOARD_WINFAST_DTV1800H: ir_codes = ir_codes_winfast; ir->gpio_addr = MO_GP0_IO; ir->mask_keycode = 0x8f8; @@ -230,6 +234,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) break; case CX88_BOARD_WINFAST2000XP_EXPERT: case CX88_BOARD_WINFAST_DTV1000: + case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL: ir_codes = ir_codes_winfast; ir->gpio_addr = MO_GP0_IO; ir->mask_keycode = 0x8f8; @@ -459,6 +464,7 @@ void cx88_ir_irq(struct cx88_core *core) case CX88_BOARD_HAUPPAUGE_HVR4000LITE: case CX88_BOARD_PCHDTV_HD3000: case CX88_BOARD_PCHDTV_HD5500: + case CX88_BOARD_HAUPPAUGE_IRONLY: ircode = ir_decode_biphase(ir->samples, ir->scount, 5, 7); ir_dprintk("biphase decoded: %x\n", ircode); /* diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c index 7dd506b987fe..e8316cf7f32f 100644 --- a/drivers/media/video/cx88/cx88-tvaudio.c +++ b/drivers/media/video/cx88/cx88-tvaudio.c @@ -163,6 +163,8 @@ static void set_audio_finish(struct cx88_core *core, u32 ctl) /* unmute */ volume = cx_sread(SHADOW_AUD_VOL_CTL); cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, volume); + + core->last_change = jiffies; } /* ----------------------------------------------------------- */ @@ -745,6 +747,7 @@ void cx88_set_tvaudio(struct cx88_core *core) break; case WW_BG: case WW_DK: + case WW_M: case WW_I: case WW_L: /* prepare all dsp registers */ @@ -756,6 +759,7 @@ void cx88_set_tvaudio(struct cx88_core *core) if (0 == cx88_detect_nicam(core)) { /* fall back to fm / am mono */ set_audio_standard_A2(core, EN_A2_FORCE_MONO1); + core->audiomode_current = V4L2_TUNER_MODE_MONO; core->use_nicam = 0; } else { core->use_nicam = 1; @@ -787,6 +791,7 @@ void cx88_set_tvaudio(struct cx88_core *core) void cx88_newstation(struct cx88_core *core) { core->audiomode_manual = UNSET; + core->last_change = jiffies; } void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t) @@ -805,12 +810,50 @@ void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t) aud_ctl_names[cx_read(AUD_CTL) & 63]); core->astat = reg; -/* TODO - Reading from AUD_STATUS is not enough - for auto-detecting sap/dual-fm/nicam. - Add some code here later. -*/ + t->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_SAP | + V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2; + t->rxsubchans = UNSET; + t->audmode = V4L2_TUNER_MODE_MONO; + switch (mode) { + case 0: + t->audmode = V4L2_TUNER_MODE_STEREO; + break; + case 1: + t->audmode = V4L2_TUNER_MODE_LANG2; + break; + case 2: + t->audmode = V4L2_TUNER_MODE_MONO; + break; + case 3: + t->audmode = V4L2_TUNER_MODE_SAP; + break; + } + + switch (core->tvaudio) { + case WW_BTSC: + case WW_BG: + case WW_DK: + case WW_M: + case WW_EIAJ: + if (!core->use_nicam) { + t->rxsubchans = cx88_dsp_detect_stereo_sap(core); + break; + } + break; + default: + /* nothing */ + break; + } + + /* If software stereo detection is not supported... */ + if (UNSET == t->rxsubchans) { + t->rxsubchans = V4L2_TUNER_SUB_MONO; + /* If the hardware itself detected stereo, also return + stereo as an available subchannel */ + if (V4L2_TUNER_MODE_STEREO == t->audmode) + t->rxsubchans |= V4L2_TUNER_SUB_STEREO; + } return; } @@ -847,6 +890,7 @@ void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual) break; case WW_BG: case WW_DK: + case WW_M: case WW_I: case WW_L: if (1 == core->use_nicam) { @@ -872,20 +916,18 @@ void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual) set_audio_standard_A2(core, EN_A2_FORCE_MONO1); } else { /* TODO: Add A2 autodection */ + mask = 0x3f; switch (mode) { case V4L2_TUNER_MODE_MONO: case V4L2_TUNER_MODE_LANG1: - set_audio_standard_A2(core, - EN_A2_FORCE_MONO1); + ctl = EN_A2_FORCE_MONO1; break; case V4L2_TUNER_MODE_LANG2: - set_audio_standard_A2(core, - EN_A2_FORCE_MONO2); + ctl = EN_A2_FORCE_MONO2; break; case V4L2_TUNER_MODE_STEREO: case V4L2_TUNER_MODE_LANG1_LANG2: - set_audio_standard_A2(core, - EN_A2_FORCE_STEREO); + ctl = EN_A2_FORCE_STEREO; break; } } @@ -932,24 +974,39 @@ int cx88_audio_thread(void *data) break; try_to_freeze(); - /* just monitor the audio status for now ... */ - memset(&t, 0, sizeof(t)); - cx88_get_stereo(core, &t); + switch (core->tvaudio) { + case WW_BG: + case WW_DK: + case WW_M: + case WW_I: + case WW_L: + if (core->use_nicam) + goto hw_autodetect; - if (UNSET != core->audiomode_manual) - /* manually set, don't do anything. */ - continue; + /* just monitor the audio status for now ... */ + memset(&t, 0, sizeof(t)); + cx88_get_stereo(core, &t); - /* monitor signal */ - if (t.rxsubchans & V4L2_TUNER_SUB_STEREO) - mode = V4L2_TUNER_MODE_STEREO; - else - mode = V4L2_TUNER_MODE_MONO; - if (mode == core->audiomode_current) - continue; + if (UNSET != core->audiomode_manual) + /* manually set, don't do anything. */ + continue; - /* automatically switch to best available mode */ - cx88_set_stereo(core, mode, 0); + /* monitor signal and set stereo if available */ + if (t.rxsubchans & V4L2_TUNER_SUB_STEREO) + mode = V4L2_TUNER_MODE_STEREO; + else + mode = V4L2_TUNER_MODE_MONO; + if (mode == core->audiomode_current) + continue; + /* automatically switch to best available mode */ + cx88_set_stereo(core, mode, 0); + break; + default: +hw_autodetect: + /* stereo autodetection is supported by hardware so + we don't need to do it manually. Do nothing. */ + break; + } } dprintk("cx88: tvaudio thread exiting\n"); diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index b993d42fe73c..b12770848c00 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -869,6 +869,7 @@ video_poll(struct file *file, struct poll_table_struct *wait) { struct cx8800_fh *fh = file->private_data; struct cx88_buffer *buf; + unsigned int rc = POLLERR; if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) { if (!res_get(fh->dev,fh,RESOURCE_VBI)) @@ -876,22 +877,27 @@ video_poll(struct file *file, struct poll_table_struct *wait) return videobuf_poll_stream(file, &fh->vbiq, wait); } + mutex_lock(&fh->vidq.vb_lock); if (res_check(fh,RESOURCE_VIDEO)) { /* streaming capture */ if (list_empty(&fh->vidq.stream)) - return POLLERR; + goto done; buf = list_entry(fh->vidq.stream.next,struct cx88_buffer,vb.stream); } else { /* read() capture */ buf = (struct cx88_buffer*)fh->vidq.read_buf; if (NULL == buf) - return POLLERR; + goto done; } poll_wait(file, &buf->vb.done, wait); if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR) - return POLLIN|POLLRDNORM; - return 0; + rc = POLLIN|POLLRDNORM; + else + rc = 0; +done: + mutex_unlock(&fh->vidq.vb_lock); + return rc; } static int video_release(struct file *file) @@ -926,8 +932,10 @@ static int video_release(struct file *file) file->private_data = NULL; kfree(fh); + mutex_lock(&dev->core->lock); if(atomic_dec_and_test(&dev->core->users)) call_all(dev->core, tuner, s_standby); + mutex_unlock(&dev->core->lock); return 0; } @@ -1103,15 +1111,8 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, } f->fmt.pix.field = field; - if (f->fmt.pix.height < 32) - f->fmt.pix.height = 32; - if (f->fmt.pix.height > maxh) - f->fmt.pix.height = maxh; - if (f->fmt.pix.width < 48) - f->fmt.pix.width = 48; - if (f->fmt.pix.width > maxw) - f->fmt.pix.width = maxw; - f->fmt.pix.width &= ~0x03; + v4l_bound_align_image(&f->fmt.pix.width, 48, maxw, 2, + &f->fmt.pix.height, 32, maxh, 0, 0); f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3; f->fmt.pix.sizeimage = diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index 7724d168fc04..9d83762163f5 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -65,6 +65,8 @@ #define VBI_LINE_COUNT 17 #define VBI_LINE_LENGTH 2048 +#define AUD_RDS_LINES 4 + /* need "shadow" registers for some write-only ones ... */ #define SHADOW_AUD_VOL_CTL 1 #define SHADOW_AUD_BAL_CTL 2 @@ -132,6 +134,7 @@ struct cx88_ctrl { #define SRAM_CH25 4 /* audio */ #define SRAM_CH26 5 #define SRAM_CH28 6 /* mpeg */ +#define SRAM_CH27 7 /* audio rds */ /* more */ struct sram_channel { @@ -232,6 +235,8 @@ extern struct sram_channel cx88_sram_channels[]; #define CX88_BOARD_TBS_8910 77 #define CX88_BOARD_PROF_6200 78 #define CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII 79 +#define CX88_BOARD_HAUPPAUGE_IRONLY 80 +#define CX88_BOARD_WINFAST_DTV1800H 81 enum cx88_itype { CX88_VMUX_COMPOSITE1 = 1, @@ -350,6 +355,7 @@ struct cx88_core { u32 input; u32 astat; u32 use_nicam; + unsigned long last_change; /* IR remote control state */ struct cx88_IR *ir; @@ -652,6 +658,7 @@ extern void cx88_setup_xc3028(struct cx88_core *core, struct xc2028_ctrl *ctl); #define WW_I2SPT 8 #define WW_FM 9 #define WW_I2SADC 10 +#define WW_M 11 void cx88_set_tvaudio(struct cx88_core *core); void cx88_newstation(struct cx88_core *core); @@ -664,6 +671,11 @@ int cx8802_unregister_driver(struct cx8802_driver *drv); struct cx8802_dev *cx8802_get_device(int minor); struct cx8802_driver * cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board_type btype); +/* ----------------------------------------------------------- */ +/* cx88-dsp.c */ + +s32 cx88_dsp_detect_stereo_sap(struct cx88_core *core); + /* ----------------------------------------------------------- */ /* cx88-input.c */ diff --git a/drivers/media/video/dabusb.c b/drivers/media/video/dabusb.c index ba3709bec3f0..ec2f45dde164 100644 --- a/drivers/media/video/dabusb.c +++ b/drivers/media/video/dabusb.c @@ -747,8 +747,14 @@ static const struct file_operations dabusb_fops = .release = dabusb_release, }; +static char *dabusb_nodename(struct device *dev) +{ + return kasprintf(GFP_KERNEL, "usb/%s", dev_name(dev)); +} + static struct usb_class_driver dabusb_class = { .name = "dabusb%d", + .nodename = dabusb_nodename, .fops = &dabusb_fops, .minor_base = DABUSB_MINOR, }; diff --git a/drivers/media/video/em28xx/em28xx-audio.c b/drivers/media/video/em28xx/em28xx-audio.c index 0131322475bf..7bd8a70f0a0b 100644 --- a/drivers/media/video/em28xx/em28xx-audio.c +++ b/drivers/media/video/em28xx/em28xx-audio.c @@ -339,6 +339,11 @@ static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream) mutex_lock(&dev->lock); dev->adev.users--; em28xx_audio_analog_set(dev); + if (substream->runtime->dma_area) { + dprintk("freeing\n"); + vfree(substream->runtime->dma_area); + substream->runtime->dma_area = NULL; + } mutex_unlock(&dev->lock); return 0; diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 7c70738479dd..c43fdb9bc888 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -49,6 +49,11 @@ static unsigned int disable_ir; module_param(disable_ir, int, 0444); MODULE_PARM_DESC(disable_ir, "disable infrared remote support"); +static unsigned int disable_usb_speed_check; +module_param(disable_usb_speed_check, int, 0444); +MODULE_PARM_DESC(disable_usb_speed_check, + "override min bandwidth requirement of 480M bps"); + static unsigned int card[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; module_param_array(card, int, NULL, 0444); MODULE_PARM_DESC(card, "card type"); @@ -104,6 +109,24 @@ static struct em28xx_reg_seq em2880_msi_digivox_ad_analog[] = { /* Board - EM2870 Kworld 355u Analog - No input analog */ +/* Board - EM2882 Kworld 315U digital */ +static struct em28xx_reg_seq em2882_kworld_315u_digital[] = { + {EM28XX_R08_GPIO, 0xff, 0xff, 10}, + {EM28XX_R08_GPIO, 0xfe, 0xff, 10}, + {EM2880_R04_GPO, 0x04, 0xff, 10}, + {EM2880_R04_GPO, 0x0c, 0xff, 10}, + {EM28XX_R08_GPIO, 0x7e, 0xff, 10}, + { -1, -1, -1, -1}, +}; + +static struct em28xx_reg_seq em2882_kworld_315u_tuner_gpio[] = { + {EM2880_R04_GPO, 0x08, 0xff, 10}, + {EM2880_R04_GPO, 0x0c, 0xff, 10}, + {EM2880_R04_GPO, 0x08, 0xff, 10}, + {EM2880_R04_GPO, 0x0c, 0xff, 10}, + { -1, -1, -1, -1}, +}; + static struct em28xx_reg_seq kworld_330u_analog[] = { {EM28XX_R08_GPIO, 0x6d, ~EM_GPIO_4, 10}, {EM2880_R04_GPO, 0x00, 0xff, 10}, @@ -116,6 +139,24 @@ static struct em28xx_reg_seq kworld_330u_digital[] = { { -1, -1, -1, -1}, }; +/* Evga inDtube + GPIO0 - Enable digital power (s5h1409) - low to enable + GPIO1 - Enable analog power (tvp5150/emp202) - low to enable + GPIO4 - xc3028 reset + GOP3 - s5h1409 reset + */ +static struct em28xx_reg_seq evga_indtube_analog[] = { + {EM28XX_R08_GPIO, 0x79, 0xff, 60}, + { -1, -1, -1, -1}, +}; + +static struct em28xx_reg_seq evga_indtube_digital[] = { + {EM28XX_R08_GPIO, 0x7a, 0xff, 1}, + {EM2880_R04_GPO, 0x04, 0xff, 10}, + {EM2880_R04_GPO, 0x0c, 0xff, 1}, + { -1, -1, -1, -1}, +}; + /* Callback for the most boards */ static struct em28xx_reg_seq default_tuner_gpio[] = { {EM28XX_R08_GPIO, EM_GPIO_4, EM_GPIO_4, 10}, @@ -140,6 +181,16 @@ static struct em28xx_reg_seq compro_mute_gpio[] = { { -1, -1, -1, -1}, }; +/* Terratec AV350 */ +static struct em28xx_reg_seq terratec_av350_mute_gpio[] = { + {EM28XX_R08_GPIO, 0xff, 0x7f, 10}, + { -1, -1, -1, -1}, +}; + +static struct em28xx_reg_seq terratec_av350_unmute_gpio[] = { + {EM28XX_R08_GPIO, 0xff, 0xff, 10}, + { -1, -1, -1, -1}, +}; /* * Board definitions */ @@ -992,16 +1043,17 @@ struct em28xx_board em28xx_boards[] = { .amux = EM28XX_AMUX_LINE_IN, } }, }, - [EM2860_BOARD_POINTNIX_INTRAORAL_CAMERA] = { - .name = "PointNix Intra-Oral Camera", + [EM2860_BOARD_SAA711X_REFERENCE_DESIGN] = { + .name = "EM2860/SAA711X Reference Design", .has_snapshot_button = 1, - .tda9887_conf = TDA9887_PRESENT, .tuner_type = TUNER_ABSENT, .decoder = EM28XX_SAA711X, .input = { { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, - .amux = EM28XX_AMUX_VIDEO, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, } }, }, [EM2880_BOARD_MSI_DIGIVOX_AD] = { @@ -1095,6 +1147,63 @@ struct em28xx_board em28xx_boards[] = { .gpio = default_analog, } }, }, + [EM2882_BOARD_KWORLD_ATSC_315U] = { + .name = "KWorld ATSC 315U HDTV TV Box", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .tuner_type = TUNER_THOMSON_DTT761X, + .tuner_gpio = em2882_kworld_315u_tuner_gpio, + .tda9887_conf = TDA9887_PRESENT, + .decoder = EM28XX_SAA711X, + .has_dvb = 1, + .dvb_gpio = em2882_kworld_315u_digital, + .xclk = EM28XX_XCLK_FREQUENCY_12MHZ, + .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE, + /* Analog mode - still not ready */ + /*.input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = SAA7115_COMPOSITE2, + .amux = EM28XX_AMUX_VIDEO, + .gpio = em2882_kworld_315u_analog, + .aout = EM28XX_AOUT_PCM_IN | EM28XX_AOUT_PCM_STEREO, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = em2882_kworld_315u_analog1, + .aout = EM28XX_AOUT_PCM_IN | EM28XX_AOUT_PCM_STEREO, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = em2882_kworld_315u_analog1, + .aout = EM28XX_AOUT_PCM_IN | EM28XX_AOUT_PCM_STEREO, + } }, */ + }, + [EM2880_BOARD_EMPIRE_DUAL_TV] = { + .name = "Empire dual TV", + .tuner_type = TUNER_XC2028, + .tuner_gpio = default_tuner_gpio, + .has_dvb = 1, + .dvb_gpio = default_digital, + .mts_firmware = 1, + .decoder = EM28XX_TVP5150, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = EM28XX_AMUX_VIDEO, + .gpio = default_analog, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = default_analog, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = default_analog, + } }, + }, [EM2881_BOARD_DNT_DA2_HYBRID] = { .name = "DNT DA2 Hybrid", .valid = EM28XX_BOARD_NOT_VALIDATED, @@ -1322,6 +1431,69 @@ struct em28xx_board em28xx_boards[] = { .amux = EM28XX_AMUX_VIDEO, } }, }, + [EM2860_BOARD_TERRATEC_GRABBY] = { + .name = "Terratec Grabby", + .vchannels = 2, + .tuner_type = TUNER_ABSENT, + .decoder = EM28XX_SAA711X, + .xclk = EM28XX_XCLK_FREQUENCY_12MHZ, + .input = { { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = EM28XX_AMUX_VIDEO2, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = EM28XX_AMUX_VIDEO2, + } }, + }, + [EM2860_BOARD_TERRATEC_AV350] = { + .name = "Terratec AV350", + .vchannels = 2, + .tuner_type = TUNER_ABSENT, + .decoder = EM28XX_TVP5150, + .xclk = EM28XX_XCLK_FREQUENCY_12MHZ, + .mute_gpio = terratec_av350_mute_gpio, + .input = { { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = EM28XX_AUDIO_SRC_LINE, + .gpio = terratec_av350_unmute_gpio, + + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = EM28XX_AUDIO_SRC_LINE, + .gpio = terratec_av350_unmute_gpio, + } }, + }, + [EM2882_BOARD_EVGA_INDTUBE] = { + .name = "Evga inDtube", + .tuner_type = TUNER_XC2028, + .tuner_gpio = default_tuner_gpio, + .decoder = EM28XX_TVP5150, + .xclk = EM28XX_XCLK_FREQUENCY_12MHZ, /* NEC IR */ + .mts_firmware = 1, + .has_dvb = 1, + .dvb_gpio = evga_indtube_digital, + .ir_codes = ir_codes_evga_indtube, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = EM28XX_AMUX_VIDEO, + .gpio = evga_indtube_analog, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = evga_indtube_analog, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = evga_indtube_analog, + } }, + }, }; const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards); @@ -1355,6 +1527,8 @@ struct usb_device_id em28xx_id_table[] = { .driver_info = EM2880_BOARD_KWORLD_DVB_305U }, { USB_DEVICE(0xeb1a, 0xe310), .driver_info = EM2880_BOARD_MSI_DIGIVOX_AD }, + { USB_DEVICE(0xeb1a, 0xa313), + .driver_info = EM2882_BOARD_KWORLD_ATSC_315U }, { USB_DEVICE(0xeb1a, 0xa316), .driver_info = EM2883_BOARD_KWORLD_HYBRID_330U }, { USB_DEVICE(0xeb1a, 0xe320), @@ -1385,6 +1559,10 @@ struct usb_device_id em28xx_id_table[] = { .driver_info = EM2870_BOARD_TERRATEC_XS }, { USB_DEVICE(0x0ccd, 0x0047), .driver_info = EM2880_BOARD_TERRATEC_PRODIGY_XS }, + { USB_DEVICE(0x0ccd, 0x0084), + .driver_info = EM2860_BOARD_TERRATEC_AV350 }, + { USB_DEVICE(0x0ccd, 0x0096), + .driver_info = EM2860_BOARD_TERRATEC_GRABBY }, { USB_DEVICE(0x185b, 0x2870), .driver_info = EM2870_BOARD_COMPRO_VIDEOMATE }, { USB_DEVICE(0x185b, 0x2041), @@ -1437,13 +1615,15 @@ static struct em28xx_hash_table em28xx_eeprom_hash[] = { {0x6ce05a8f, EM2820_BOARD_PROLINK_PLAYTV_USB2, TUNER_YMEC_TVF_5533MF}, {0x72cc5a8b, EM2820_BOARD_PROLINK_PLAYTV_BOX4_USB2, TUNER_YMEC_TVF_5533MF}, {0x966a0441, EM2880_BOARD_KWORLD_DVB_310U, TUNER_XC2028}, + {0x9567eb1a, EM2880_BOARD_EMPIRE_DUAL_TV, TUNER_XC2028}, + {0xcee44a99, EM2882_BOARD_EVGA_INDTUBE, TUNER_XC2028}, }; /* I2C devicelist hash table for devices with generic USB IDs */ 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}, + {0x1ba50080, EM2860_BOARD_SAA711X_REFERENCE_DESIGN, TUNER_ABSENT}, {0xc51200e3, EM2820_BOARD_GADMEI_TVR200, TUNER_LG_PAL_NEW_TAPC}, }; @@ -1619,6 +1799,17 @@ void em28xx_pre_card_setup(struct em28xx *dev) em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfd); break; + case EM2882_BOARD_KWORLD_ATSC_315U: + em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xff); + msleep(10); + em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfe); + msleep(10); + em28xx_write_reg(dev, EM2880_R04_GPO, 0x00); + msleep(10); + em28xx_write_reg(dev, EM2880_R04_GPO, 0x08); + msleep(10); + break; + case EM2860_BOARD_KAIOMY_TVNPC_U2: em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x07", 1); em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); @@ -1664,6 +1855,7 @@ static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl) ctl->mts = em28xx_boards[dev->model].mts_firmware; switch (dev->model) { + case EM2880_BOARD_EMPIRE_DUAL_TV: case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: ctl->demod = XC3028_FE_ZARLINK456; break; @@ -1688,6 +1880,10 @@ static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl) ctl->demod = XC3028_FE_CHINA; ctl->fname = XC2028_DEFAULT_FIRMWARE; break; + case EM2882_BOARD_EVGA_INDTUBE: + ctl->demod = XC3028_FE_CHINA; + ctl->fname = XC3028L_DEFAULT_FIRMWARE; + break; default: ctl->demod = XC3028_FE_OREN538; } @@ -1835,12 +2031,20 @@ static int em28xx_hint_board(struct em28xx *dev) } /* ----------------------------------------------------------------------- */ -void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir) +void em28xx_register_i2c_ir(struct em28xx *dev) { - if (disable_ir) { - ir->get_key = NULL; - return ; - } + struct i2c_board_info info; + struct IR_i2c_init_data init_data; + const unsigned short addr_list[] = { + 0x30, 0x47, I2C_CLIENT_END + }; + + if (disable_ir) + return; + + memset(&info, 0, sizeof(struct i2c_board_info)); + memset(&init_data, 0, sizeof(struct IR_i2c_init_data)); + strlcpy(info.type, "ir_video", I2C_NAME_SIZE); /* detect & configure */ switch (dev->model) { @@ -1850,22 +2054,19 @@ void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir) break; case (EM2800_BOARD_TERRATEC_CINERGY_200): case (EM2820_BOARD_TERRATEC_CINERGY_250): - ir->ir_codes = ir_codes_em_terratec; - ir->get_key = em28xx_get_key_terratec; - snprintf(ir->c.name, sizeof(ir->c.name), - "i2c IR (EM28XX Terratec)"); + init_data.ir_codes = ir_codes_em_terratec; + init_data.get_key = em28xx_get_key_terratec; + init_data.name = "i2c IR (EM28XX Terratec)"; break; case (EM2820_BOARD_PINNACLE_USB_2): - ir->ir_codes = ir_codes_pinnacle_grey; - ir->get_key = em28xx_get_key_pinnacle_usb_grey; - snprintf(ir->c.name, sizeof(ir->c.name), - "i2c IR (EM28XX Pinnacle PCTV)"); + init_data.ir_codes = ir_codes_pinnacle_grey; + init_data.get_key = em28xx_get_key_pinnacle_usb_grey; + init_data.name = "i2c IR (EM28XX Pinnacle PCTV)"; break; case (EM2820_BOARD_HAUPPAUGE_WINTV_USB_2): - ir->ir_codes = ir_codes_hauppauge_new; - ir->get_key = em28xx_get_key_em_haup; - snprintf(ir->c.name, sizeof(ir->c.name), - "i2c IR (EM2840 Hauppauge)"); + init_data.ir_codes = ir_codes_hauppauge_new; + init_data.get_key = em28xx_get_key_em_haup; + init_data.name = "i2c IR (EM2840 Hauppauge)"; break; case (EM2820_BOARD_MSI_VOX_USB_2): break; @@ -1876,6 +2077,10 @@ void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir) case (EM2800_BOARD_GRABBEEX_USB2800): break; } + + if (init_data.name) + info.platform_data = &init_data; + i2c_new_probed_device(&dev->i2c_adap, &info, addr_list); } void em28xx_card_setup(struct em28xx *dev) @@ -1886,6 +2091,9 @@ void em28xx_card_setup(struct em28xx *dev) if (em28xx_boards[dev->model].tuner_addr) dev->tuner_addr = em28xx_boards[dev->model].tuner_addr; + if (em28xx_boards[dev->model].tda9887_conf) + dev->tda9887_conf = em28xx_boards[dev->model].tda9887_conf; + /* request some modules */ switch (dev->model) { case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2: @@ -1915,6 +2123,12 @@ void em28xx_card_setup(struct em28xx *dev) #endif break; } + case EM2882_BOARD_KWORLD_ATSC_315U: + em28xx_write_reg(dev, 0x0d, 0x42); + msleep(10); + em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfd); + msleep(10); + break; case EM2820_BOARD_KWORLD_PVRTV2800RF: /* GPIO enables sound on KWORLD PVR TV 2800RF */ em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xf9); @@ -1937,6 +2151,12 @@ void em28xx_card_setup(struct em28xx *dev) case EM2880_BOARD_MSI_DIGIVOX_AD: if (!em28xx_hint_board(dev)) em28xx_set_model(dev); + + /* In cases where we had to use a board hint, the call to + em28xx_set_mode() in em28xx_pre_card_setup() was a no-op, + so make the call now so the analog GPIOs are set properly + before probing the i2c bus. */ + em28xx_set_mode(dev, EM28XX_ANALOG_MODE); break; } @@ -2279,6 +2499,20 @@ static int em28xx_usb_probe(struct usb_interface *interface, ifnum, interface->altsetting->desc.bInterfaceNumber); + /* + * Make sure we have 480 Mbps of bandwidth, otherwise things like + * video stream wouldn't likely work, since 12 Mbps is generally + * not enough even for most Digital TV streams. + */ + if (udev->speed != USB_SPEED_HIGH && disable_usb_speed_check == 0) { + printk(DRIVER_NAME ": Device initialization failed.\n"); + printk(DRIVER_NAME ": Device must be connected to a high-speed" + " USB 2.0 port.\n"); + em28xx_devused &= ~(1<= EM28XX_MAXBOARDS) { printk(DRIVER_NAME ": Supports only %i em28xx boards.\n", EM28XX_MAXBOARDS); diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c index 192b76cdd5d7..c8d7ce8fbd36 100644 --- a/drivers/media/video/em28xx/em28xx-core.c +++ b/drivers/media/video/em28xx/em28xx-core.c @@ -500,18 +500,21 @@ int em28xx_audio_setup(struct em28xx *dev) /* See how this device is configured */ cfg = em28xx_read_reg(dev, EM28XX_R00_CHIPCFG); - if (cfg < 0) + em28xx_info("Config register raw data: 0x%02x\n", cfg); + if (cfg < 0) { + /* Register read error? */ cfg = EM28XX_CHIPCFG_AC97; /* Be conservative */ - else - em28xx_info("Config register raw data: 0x%02x\n", cfg); - - if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) == - EM28XX_CHIPCFG_I2S_3_SAMPRATES) { + } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) == 0x00) { + /* The device doesn't have vendor audio at all */ + dev->has_alsa_audio = 0; + dev->audio_mode.has_audio = 0; + return 0; + } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) == + EM28XX_CHIPCFG_I2S_3_SAMPRATES) { em28xx_info("I2S Audio (3 sample rates)\n"); dev->audio_mode.i2s_3rates = 1; - } - if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) == - EM28XX_CHIPCFG_I2S_5_SAMPRATES) { + } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) == + EM28XX_CHIPCFG_I2S_5_SAMPRATES) { em28xx_info("I2S Audio (5 sample rates)\n"); dev->audio_mode.i2s_5rates = 1; } @@ -938,7 +941,7 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets, dev->isoc_ctl.transfer_buffer = kzalloc(sizeof(void *)*num_bufs, GFP_KERNEL); if (!dev->isoc_ctl.transfer_buffer) { - em28xx_errdev("cannot allocate memory for usbtransfer\n"); + em28xx_errdev("cannot allocate memory for usb transfer\n"); kfree(dev->isoc_ctl.urb); return -ENOMEM; } @@ -1012,6 +1015,41 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets, } EXPORT_SYMBOL_GPL(em28xx_init_isoc); +/* Determine the packet size for the DVB stream for the given device + (underlying value programmed into the eeprom) */ +int em28xx_isoc_dvb_max_packetsize(struct em28xx *dev) +{ + unsigned int chip_cfg2; + unsigned int packet_size = 564; + + if (dev->chip_id == CHIP_ID_EM2874) { + /* FIXME - for now assume 564 like it was before, but the + em2874 code should be added to return the proper value... */ + packet_size = 564; + } else { + /* TS max packet size stored in bits 1-0 of R01 */ + chip_cfg2 = em28xx_read_reg(dev, EM28XX_R01_CHIPCFG2); + switch (chip_cfg2 & EM28XX_CHIPCFG2_TS_PACKETSIZE_MASK) { + case EM28XX_CHIPCFG2_TS_PACKETSIZE_188: + packet_size = 188; + break; + case EM28XX_CHIPCFG2_TS_PACKETSIZE_376: + packet_size = 376; + break; + case EM28XX_CHIPCFG2_TS_PACKETSIZE_564: + packet_size = 564; + break; + case EM28XX_CHIPCFG2_TS_PACKETSIZE_752: + packet_size = 752; + break; + } + } + + em28xx_coredbg("dvb max packet size=%d\n", packet_size); + return packet_size; +} +EXPORT_SYMBOL_GPL(em28xx_isoc_dvb_max_packetsize); + /* * em28xx_wake_i2c() * configure i2c attached devices diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c index fcd25511209b..e7b47c8da8f3 100644 --- a/drivers/media/video/em28xx/em28xx-dvb.c +++ b/drivers/media/video/em28xx/em28xx-dvb.c @@ -25,6 +25,8 @@ #include "em28xx.h" #include #include +#include +#include "tuner-simple.h" #include "lgdt330x.h" #include "zl10353.h" @@ -46,7 +48,6 @@ if (debug >= level) \ } while (0) #define EM28XX_DVB_NUM_BUFS 5 -#define EM28XX_DVB_MAX_PACKETSIZE 564 #define EM28XX_DVB_MAX_PACKETS 64 struct em28xx_dvb { @@ -142,14 +143,17 @@ static int start_streaming(struct em28xx_dvb *dvb) { int rc; struct em28xx *dev = dvb->adapter.priv; + int max_dvb_packet_size; usb_set_interface(dev->udev, 0, 1); rc = em28xx_set_mode(dev, EM28XX_DIGITAL_MODE); if (rc < 0) return rc; + max_dvb_packet_size = em28xx_isoc_dvb_max_packetsize(dev); + return em28xx_init_isoc(dev, EM28XX_DVB_MAX_PACKETS, - EM28XX_DVB_NUM_BUFS, EM28XX_DVB_MAX_PACKETSIZE, + EM28XX_DVB_NUM_BUFS, max_dvb_packet_size, dvb_isoc_copy); } @@ -431,6 +435,7 @@ static int dvb_init(struct em28xx *dev) case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: case EM2880_BOARD_TERRATEC_HYBRID_XS: case EM2880_BOARD_KWORLD_DVB_310U: + case EM2880_BOARD_EMPIRE_DUAL_TV: dvb->frontend = dvb_attach(zl10353_attach, &em28xx_zl10353_with_xc3028, &dev->i2c_adap); @@ -440,6 +445,7 @@ static int dvb_init(struct em28xx *dev) } break; case EM2883_BOARD_KWORLD_HYBRID_330U: + case EM2882_BOARD_EVGA_INDTUBE: dvb->frontend = dvb_attach(s5h1409_attach, &em28xx_s5h1409_with_xc3028, &dev->i2c_adap); @@ -448,6 +454,18 @@ static int dvb_init(struct em28xx *dev) goto out_free; } break; + case EM2882_BOARD_KWORLD_ATSC_315U: + dvb->frontend = dvb_attach(lgdt330x_attach, + &em2880_lgdt3303_dev, + &dev->i2c_adap); + if (dvb->frontend != NULL) { + if (!dvb_attach(simple_tuner_attach, dvb->frontend, + &dev->i2c_adap, 0x61, TUNER_THOMSON_DTT761X)) { + result = -EINVAL; + 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 diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c index f0bf1d960c75..2c86fcf089f5 100644 --- a/drivers/media/video/em28xx/em28xx-i2c.c +++ b/drivers/media/video/em28xx/em28xx-i2c.c @@ -451,27 +451,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 - * does some basic configuration - */ -static int attach_inform(struct i2c_client *client) -{ - struct em28xx *dev = client->adapter->algo_data; - struct IR_i2c *ir = i2c_get_clientdata(client); - - switch (client->addr << 1) { - case 0x60: - case 0x8e: - dprintk1(1, "attach_inform: IR detected (%s).\n", ir->phys); - em28xx_set_ir(dev, ir); - break; - } - - return 0; -} - static struct i2c_algorithm em28xx_algo = { .master_xfer = em28xx_i2c_xfer, .functionality = functionality, @@ -482,7 +461,6 @@ static struct i2c_adapter em28xx_adap_template = { .name = "em28xx", .id = I2C_HW_B_EM28XX, .algo = &em28xx_algo, - .client_register = attach_inform, }; static struct i2c_client em28xx_client_template = { @@ -575,6 +553,9 @@ int em28xx_i2c_register(struct em28xx *dev) if (i2c_scan) em28xx_do_i2c_scan(dev); + /* Instantiate the IR receiver device, if present */ + em28xx_register_i2c_ir(dev); + return 0; } diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c index a5abfd7a19f5..7a0fe3816e3d 100644 --- a/drivers/media/video/em28xx/em28xx-input.c +++ b/drivers/media/video/em28xx/em28xx-input.c @@ -40,7 +40,7 @@ MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]"); #define i2cdprintk(fmt, arg...) \ if (ir_debug) { \ - printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg); \ + printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg); \ } #define dprintk(fmt, arg...) \ @@ -85,7 +85,7 @@ int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) unsigned char b; /* poll IR chip */ - if (1 != i2c_master_recv(&ir->c, &b, 1)) { + if (1 != i2c_master_recv(ir->c, &b, 1)) { i2cdprintk("read error\n"); return -EIO; } @@ -114,7 +114,7 @@ int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) unsigned char code; /* poll IR chip */ - if (2 != i2c_master_recv(&ir->c, buf, 2)) + if (2 != i2c_master_recv(ir->c, buf, 2)) return -EIO; /* Does eliminate repeated parity code */ @@ -147,7 +147,7 @@ int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, /* poll IR chip */ - if (3 != i2c_master_recv(&ir->c, buf, 3)) { + if (3 != i2c_master_recv(ir->c, buf, 3)) { i2cdprintk("read error\n"); return -EIO; } diff --git a/drivers/media/video/em28xx/em28xx-reg.h b/drivers/media/video/em28xx/em28xx-reg.h index 24e39c56811e..a2676d63cfd0 100644 --- a/drivers/media/video/em28xx/em28xx-reg.h +++ b/drivers/media/video/em28xx/em28xx-reg.h @@ -27,6 +27,22 @@ #define EM28XX_CHIPCFG_AC97 0x10 #define EM28XX_CHIPCFG_AUDIOMASK 0x30 +#define EM28XX_R01_CHIPCFG2 0x01 + +/* em28xx Chip Configuration 2 0x01 */ +#define EM28XX_CHIPCFG2_TS_PRESENT 0x10 +#define EM28XX_CHIPCFG2_TS_REQ_INTERVAL_MASK 0x0c /* bits 3-2 */ +#define EM28XX_CHIPCFG2_TS_REQ_INTERVAL_1MF 0x00 +#define EM28XX_CHIPCFG2_TS_REQ_INTERVAL_2MF 0x04 +#define EM28XX_CHIPCFG2_TS_REQ_INTERVAL_4MF 0x08 +#define EM28XX_CHIPCFG2_TS_REQ_INTERVAL_8MF 0x0c +#define EM28XX_CHIPCFG2_TS_PACKETSIZE_MASK 0x03 /* bits 0-1 */ +#define EM28XX_CHIPCFG2_TS_PACKETSIZE_188 0x00 +#define EM28XX_CHIPCFG2_TS_PACKETSIZE_376 0x01 +#define EM28XX_CHIPCFG2_TS_PACKETSIZE_564 0x02 +#define EM28XX_CHIPCFG2_TS_PACKETSIZE_752 0x03 + + /* GPIO/GPO registers */ #define EM2880_R04_GPO 0x04 /* em2880-em2883 only */ #define EM28XX_R08_GPIO 0x08 /* em2820 or upper */ diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index 882796e84dbc..8fe1beecfffa 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -687,8 +687,8 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, { struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; - int width = f->fmt.pix.width; - int height = f->fmt.pix.height; + unsigned int width = f->fmt.pix.width; + unsigned int height = f->fmt.pix.height; unsigned int maxw = norm_maxw(dev); unsigned int maxh = norm_maxh(dev); unsigned int hscale, vscale; @@ -701,34 +701,20 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, return -EINVAL; } - /* width must even because of the YUYV format - height must be even because of interlacing */ - height &= 0xfffe; - width &= 0xfffe; - - if (unlikely(height < 32)) - height = 32; - if (unlikely(height > maxh)) - height = maxh; - if (unlikely(width < 48)) - width = 48; - if (unlikely(width > maxw)) - width = maxw; - if (dev->board.is_em2800) { /* the em2800 can only scale down to 50% */ - if (height % (maxh / 2)) - height = maxh; - if (width % (maxw / 2)) - width = maxw; - /* according to empiatech support */ - /* the MaxPacketSize is to small to support */ - /* framesizes larger than 640x480 @ 30 fps */ - /* or 640x576 @ 25 fps. As this would cut */ - /* of a part of the image we prefer */ - /* 360x576 or 360x480 for now */ + height = height > (3 * maxh / 4) ? maxh : maxh / 2; + width = width > (3 * maxw / 4) ? maxw : maxw / 2; + /* According to empiatech support the MaxPacketSize is too small + * to support framesizes larger than 640x480 @ 30 fps or 640x576 + * @ 25 fps. As this would cut of a part of the image we prefer + * 360x576 or 360x480 for now */ if (width == maxw && height == maxh) width /= 2; + } else { + /* width must even because of the YUYV format + height must be even because of interlacing */ + v4l_bound_align_image(&width, 48, maxw, 1, &height, 32, maxh, 1, 0); } get_scale(dev, width, height, &hscale, &vscale); diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index 4c4e58004f54..813ce45c2f99 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -58,7 +58,7 @@ #define EM2883_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 +#define EM2860_BOARD_SAA711X_REFERENCE_DESIGN 19 #define EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600 20 #define EM2800_BOARD_GRABBEEX_USB2800 21 #define EM2750_BOARD_UNKNOWN 22 @@ -102,6 +102,11 @@ #define EM2860_BOARD_KAIOMY_TVNPC_U2 63 #define EM2860_BOARD_EASYCAP 64 #define EM2820_BOARD_IODATA_GVMVP_SZ 65 +#define EM2880_BOARD_EMPIRE_DUAL_TV 66 +#define EM2860_BOARD_TERRATEC_GRABBY 67 +#define EM2860_BOARD_TERRATEC_AV350 68 +#define EM2882_BOARD_KWORLD_ATSC_315U 69 +#define EM2882_BOARD_EVGA_INDTUBE 70 /* Limits minimum and default number of buffers */ #define EM28XX_MIN_BUF 4 @@ -615,6 +620,7 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets, int num_bufs, int max_pkt_size, int (*isoc_copy) (struct em28xx *dev, struct urb *urb)); void em28xx_uninit_isoc(struct em28xx *dev); +int em28xx_isoc_dvb_max_packetsize(struct em28xx *dev); int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode); int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio); void em28xx_wake_i2c(struct em28xx *dev); @@ -639,7 +645,7 @@ extern void em28xx_card_setup(struct em28xx *dev); extern struct em28xx_board em28xx_boards[]; extern struct usb_device_id em28xx_id_table[]; extern const unsigned int em28xx_bcount; -void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir); +void em28xx_register_i2c_ir(struct em28xx *dev); int em28xx_tuner_callback(void *ptr, int component, int command, int arg); void em28xx_release_resources(struct em28xx *dev); diff --git a/drivers/media/video/gspca/finepix.c b/drivers/media/video/gspca/finepix.c index 00e6863ed666..480ec5c87d0e 100644 --- a/drivers/media/video/gspca/finepix.c +++ b/drivers/media/video/gspca/finepix.c @@ -168,6 +168,7 @@ static int sd_config(struct gspca_dev *gspca_dev, cam->cam_mode = fpix_mode; cam->nmodes = 1; + cam->bulk = 1; cam->bulk_size = FPIX_MAX_TRANSFER; INIT_WORK(&dev->work_struct, dostream); diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index a2741d7dccfe..1e89600986c8 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c @@ -1,7 +1,7 @@ /* * Main USB camera driver * - * V4L2 by Jean-Francois Moine + * Copyright (C) 2008-2009 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 @@ -47,7 +47,7 @@ MODULE_AUTHOR("Jean-Francois Moine "); MODULE_DESCRIPTION("GSPCA USB Camera Driver"); MODULE_LICENSE("GPL"); -#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 5, 0) +#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 6, 0) #ifdef GSPCA_DEBUG int gspca_debug = D_ERR | D_PROBE; @@ -441,7 +441,7 @@ static void destroy_urbs(struct gspca_dev *gspca_dev) * look for an input transfer endpoint in an alternate setting */ static struct usb_host_endpoint *alt_xfer(struct usb_host_interface *alt, - __u8 xfer) + int xfer) { struct usb_host_endpoint *ep; int i, attr; @@ -449,7 +449,8 @@ static struct usb_host_endpoint *alt_xfer(struct usb_host_interface *alt, for (i = 0; i < alt->desc.bNumEndpoints; i++) { ep = &alt->endpoint[i]; attr = ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; - if (attr == xfer) + if (attr == xfer + && ep->desc.wMaxPacketSize != 0) return ep; } return NULL; @@ -467,37 +468,28 @@ static struct usb_host_endpoint *get_ep(struct gspca_dev *gspca_dev) { struct usb_interface *intf; struct usb_host_endpoint *ep; - int i, ret; + int xfer, i, ret; intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface); ep = NULL; + xfer = gspca_dev->cam.bulk ? USB_ENDPOINT_XFER_BULK + : USB_ENDPOINT_XFER_ISOC; i = gspca_dev->alt; /* previous alt setting */ - - /* try isoc */ while (--i >= 0) { - ep = alt_xfer(&intf->altsetting[i], - USB_ENDPOINT_XFER_ISOC); + ep = alt_xfer(&intf->altsetting[i], xfer); if (ep) break; } - - /* if no isoc, try bulk (alt 0 only) */ if (ep == NULL) { - ep = alt_xfer(&intf->altsetting[0], - USB_ENDPOINT_XFER_BULK); - if (ep == NULL) { - err("no transfer endpoint found"); - return NULL; - } - i = 0; - gspca_dev->bulk = 1; + err("no transfer endpoint found"); + return NULL; } PDEBUG(D_STREAM, "use alt %d ep 0x%02x", i, ep->desc.bEndpointAddress); - if (i > 0) { + if (gspca_dev->nbalt > 1) { ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, i); if (ret < 0) { - err("set interface err %d", ret); + err("set alt %d err %d", i, ret); return NULL; } } @@ -517,13 +509,13 @@ static int create_urbs(struct gspca_dev *gspca_dev, /* calculate the packet size and the number of packets */ psize = le16_to_cpu(ep->desc.wMaxPacketSize); - if (!gspca_dev->bulk) { /* isoc */ + if (!gspca_dev->cam.bulk) { /* isoc */ /* 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; + npkt = gspca_dev->cam.npkt; + if (npkt == 0) + npkt = 32; /* default value */ bsize = psize * npkt; PDEBUG(D_STREAM, "isoc %d pkts size %d = bsize:%d", @@ -617,7 +609,7 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev) goto out; /* clear the bulk endpoint */ - if (gspca_dev->bulk) + if (gspca_dev->cam.bulk) usb_clear_halt(gspca_dev->dev, gspca_dev->urb[0]->pipe); @@ -630,7 +622,7 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev) gspca_dev->streaming = 1; /* some bulk transfers are started by the subdriver */ - if (gspca_dev->bulk && gspca_dev->cam.bulk_nurbs == 0) + if (gspca_dev->cam.bulk && gspca_dev->cam.bulk_nurbs == 0) break; /* submit the URBs */ @@ -661,6 +653,8 @@ static int gspca_set_alt0(struct gspca_dev *gspca_dev) { int ret; + if (gspca_dev->alt == 0) + return 0; ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, 0); if (ret < 0) PDEBUG(D_ERR|D_STREAM, "set alt 0 err %d", ret); @@ -869,6 +863,32 @@ out: return ret; } +static int vidioc_enum_framesizes(struct file *file, void *priv, + struct v4l2_frmsizeenum *fsize) +{ + struct gspca_dev *gspca_dev = priv; + int i; + __u32 index = 0; + + for (i = 0; i < gspca_dev->cam.nmodes; i++) { + if (fsize->pixel_format != + gspca_dev->cam.cam_mode[i].pixelformat) + continue; + + if (fsize->index == index) { + fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; + fsize->discrete.width = + gspca_dev->cam.cam_mode[i].width; + fsize->discrete.height = + gspca_dev->cam.cam_mode[i].height; + return 0; + } + index++; + } + + return -EINVAL; +} + static void gspca_release(struct video_device *vfd) { struct gspca_dev *gspca_dev = container_of(vfd, struct gspca_dev, vdev); @@ -989,43 +1009,52 @@ out: return ret; } +static const struct ctrl *get_ctrl(struct gspca_dev *gspca_dev, + int id) +{ + const struct ctrl *ctrls; + int i; + + for (i = 0, ctrls = gspca_dev->sd_desc->ctrls; + i < gspca_dev->sd_desc->nctrls; + i++, ctrls++) { + if (gspca_dev->ctrl_dis & (1 << i)) + continue; + if (id == ctrls->qctrl.id) + return ctrls; + } + return NULL; +} + static int vidioc_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *q_ctrl) { struct gspca_dev *gspca_dev = priv; - int i, ix; + const struct ctrl *ctrls; + int i; u32 id; - ix = -1; + ctrls = NULL; 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 (gspca_dev->ctrl_dis & (1 << i)) + continue; if (gspca_dev->sd_desc->ctrls[i].qctrl.id < id) continue; - if (ix < 0) { - ix = i; + if (ctrls && gspca_dev->sd_desc->ctrls[i].qctrl.id + > ctrls->qctrl.id) continue; - } - if (gspca_dev->sd_desc->ctrls[i].qctrl.id - > gspca_dev->sd_desc->ctrls[ix].qctrl.id) - continue; - ix = i; + ctrls = &gspca_dev->sd_desc->ctrls[i]; } + } else { + ctrls = get_ctrl(gspca_dev, id); } - for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) { - if (id == gspca_dev->sd_desc->ctrls[i].qctrl.id) { - ix = i; - break; - } - } - if (ix < 0) + if (ctrls == NULL) return -EINVAL; - memcpy(q_ctrl, &gspca_dev->sd_desc->ctrls[ix].qctrl, - sizeof *q_ctrl); - if (gspca_dev->ctrl_dis & (1 << ix)) - q_ctrl->flags |= V4L2_CTRL_FLAG_DISABLED; + memcpy(q_ctrl, ctrls, sizeof *q_ctrl); return 0; } @@ -1034,56 +1063,45 @@ static int vidioc_s_ctrl(struct file *file, void *priv, { struct gspca_dev *gspca_dev = priv; const struct ctrl *ctrls; - int i, ret; + int 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 (gspca_dev->ctrl_dis & (1 << i)) - return -EINVAL; - 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; - if (gspca_dev->present) - ret = ctrls->set(gspca_dev, ctrl->value); - else - ret = -ENODEV; - mutex_unlock(&gspca_dev->usb_lock); - return ret; - } - return -EINVAL; + ctrls = get_ctrl(gspca_dev, ctrl->id); + if (ctrls == NULL) + return -EINVAL; + + 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; + if (gspca_dev->present) + ret = ctrls->set(gspca_dev, ctrl->value); + else + ret = -ENODEV; + mutex_unlock(&gspca_dev->usb_lock); + return ret; } 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; + int 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 (gspca_dev->ctrl_dis & (1 << i)) - return -EINVAL; - if (mutex_lock_interruptible(&gspca_dev->usb_lock)) - return -ERESTARTSYS; - if (gspca_dev->present) - ret = ctrls->get(gspca_dev, &ctrl->value); - else - ret = -ENODEV; - mutex_unlock(&gspca_dev->usb_lock); - return ret; - } - return -EINVAL; + ctrls = get_ctrl(gspca_dev, ctrl->id); + if (ctrls == NULL) + return -EINVAL; + + if (mutex_lock_interruptible(&gspca_dev->usb_lock)) + return -ERESTARTSYS; + if (gspca_dev->present) + ret = ctrls->get(gspca_dev, &ctrl->value); + else + ret = -ENODEV; + mutex_unlock(&gspca_dev->usb_lock); + return ret; } /*fixme: have an audio flag in gspca_dev?*/ @@ -1864,6 +1882,7 @@ static const struct v4l2_ioctl_ops dev_ioctl_ops = { .vidioc_g_parm = vidioc_g_parm, .vidioc_s_parm = vidioc_s_parm, .vidioc_s_std = vidioc_s_std, + .vidioc_enum_framesizes = vidioc_enum_framesizes, #ifdef CONFIG_VIDEO_V4L1_COMPAT .vidiocgmbuf = vidiocgmbuf, #endif @@ -1943,7 +1962,7 @@ int gspca_dev_probe(struct usb_interface *intf, /* init video stuff */ memcpy(&gspca_dev->vdev, &gspca_template, sizeof gspca_template); - gspca_dev->vdev.parent = &dev->dev; + gspca_dev->vdev.parent = &intf->dev; gspca_dev->module = module; gspca_dev->present = 1; ret = video_register_device(&gspca_dev->vdev, diff --git a/drivers/media/video/gspca/gspca.h b/drivers/media/video/gspca/gspca.h index 58e8ff02136a..bd1faff88644 100644 --- a/drivers/media/video/gspca/gspca.h +++ b/drivers/media/video/gspca/gspca.h @@ -44,8 +44,6 @@ extern int gspca_debug; #define GSPCA_MAX_FRAMES 16 /* maximum number of video frame buffers */ /* image transfers */ #define MAX_NURBS 4 /* 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 { @@ -56,6 +54,9 @@ struct cam { * - cannot be > MAX_NURBS * - when 0 and bulk_size != 0 means * 1 URB and submit done by subdriver */ + u8 bulk; /* image transfer by 0:isoc / 1:bulk */ + u8 npkt; /* number of packets in an ISOC message + * 0 is the default value: 32 packets */ u32 input_flags; /* value for ENUM_INPUT status flags */ }; @@ -168,7 +169,6 @@ struct gspca_dev { __u8 iface; /* USB interface number */ __u8 alt; /* USB alternate setting */ __u8 nbalt; /* number of USB alternate settings */ - u8 bulk; /* image transfer by 0:isoc / 1:bulk */ }; int gspca_dev_probe(struct usb_interface *intf, diff --git a/drivers/media/video/gspca/m5602/Makefile b/drivers/media/video/gspca/m5602/Makefile index 9fa3644f4869..bf7a19a1e6d1 100644 --- a/drivers/media/video/gspca/m5602/Makefile +++ b/drivers/media/video/gspca/m5602/Makefile @@ -2,9 +2,10 @@ obj-$(CONFIG_USB_M5602) += gspca_m5602.o gspca_m5602-objs := m5602_core.o \ m5602_ov9650.o \ + m5602_ov7660.o \ m5602_mt9m111.o \ m5602_po1030.o \ m5602_s5k83a.o \ m5602_s5k4aa.o -EXTRA_CFLAGS += -Idrivers/media/video/gspca \ No newline at end of file +EXTRA_CFLAGS += -Idrivers/media/video/gspca diff --git a/drivers/media/video/gspca/m5602/m5602_bridge.h b/drivers/media/video/gspca/m5602/m5602_bridge.h index 8f1cea6fd3bf..1127a405c9b2 100644 --- a/drivers/media/video/gspca/m5602/m5602_bridge.h +++ b/drivers/media/video/gspca/m5602/m5602_bridge.h @@ -45,6 +45,15 @@ #define M5602_XB_SEN_CLK_DIV 0x15 #define M5602_XB_AUD_CLK_CTRL 0x16 #define M5602_XB_AUD_CLK_DIV 0x17 +#define M5602_OB_AC_LINK_STATE 0x22 +#define M5602_OB_PCM_SLOT_INDEX 0x24 +#define M5602_OB_GPIO_SLOT_INDEX 0x25 +#define M5602_OB_ACRX_STATUS_ADDRESS_H 0x28 +#define M5602_OB_ACRX_STATUS_DATA_L 0x29 +#define M5602_OB_ACRX_STATUS_DATA_H 0x2a +#define M5602_OB_ACTX_COMMAND_ADDRESS 0x31 +#define M5602_OB_ACRX_COMMAND_DATA_L 0x32 +#define M5602_OB_ACTX_COMMAND_DATA_H 0X33 #define M5602_XB_DEVCTR1 0x41 #define M5602_XB_EPSETR0 0x42 #define M5602_XB_EPAFCTR 0x47 @@ -77,7 +86,18 @@ #define M5602_XB_GPIO_EN_L 0x75 #define M5602_XB_GPIO_DAT 0x76 #define M5602_XB_GPIO_DIR 0x77 -#define M5602_XB_MISC_CTL 0x70 +#define M5602_XB_SEN_CLK_CONTROL 0x80 +#define M5602_XB_SEN_CLK_DIVISION 0x81 +#define M5602_XB_CPR_CLK_CONTROL 0x82 +#define M5602_XB_CPR_CLK_DIVISION 0x83 +#define M5602_XB_MCU_CLK_CONTROL 0x84 +#define M5602_XB_MCU_CLK_DIVISION 0x85 +#define M5602_XB_DCT_CLK_CONTROL 0x86 +#define M5602_XB_DCT_CLK_DIVISION 0x87 +#define M5602_XB_EC_CLK_CONTROL 0x88 +#define M5602_XB_EC_CLK_DIVISION 0x89 +#define M5602_XB_LBUF_CLK_CONTROL 0x8a +#define M5602_XB_LBUF_CLK_DIVISION 0x8b #define I2C_BUSY 0x80 @@ -128,10 +148,10 @@ struct sd { }; int m5602_read_bridge( - struct sd *sd, u8 address, u8 *i2c_data); + struct sd *sd, const u8 address, u8 *i2c_data); int m5602_write_bridge( - struct sd *sd, u8 address, u8 i2c_data); + struct sd *sd, const u8 address, const u8 i2c_data); int m5602_write_sensor(struct sd *sd, const u8 address, u8 *i2c_data, const u8 len); diff --git a/drivers/media/video/gspca/m5602/m5602_core.c b/drivers/media/video/gspca/m5602/m5602_core.c index 1aac2985fee6..8a5bba16ff32 100644 --- a/drivers/media/video/gspca/m5602/m5602_core.c +++ b/drivers/media/video/gspca/m5602/m5602_core.c @@ -17,6 +17,7 @@ */ #include "m5602_ov9650.h" +#include "m5602_ov7660.h" #include "m5602_mt9m111.h" #include "m5602_po1030.h" #include "m5602_s5k83a.h" @@ -35,7 +36,7 @@ static const __devinitdata struct usb_device_id m5602_table[] = { MODULE_DEVICE_TABLE(usb, m5602_table); /* Reads a byte from the m5602 */ -int m5602_read_bridge(struct sd *sd, u8 address, u8 *i2c_data) +int m5602_read_bridge(struct sd *sd, const u8 address, u8 *i2c_data) { int err; struct usb_device *udev = sd->gspca_dev.dev; @@ -56,7 +57,7 @@ int m5602_read_bridge(struct sd *sd, u8 address, u8 *i2c_data) } /* Writes a byte to to the m5602 */ -int m5602_write_bridge(struct sd *sd, u8 address, u8 i2c_data) +int m5602_write_bridge(struct sd *sd, const u8 address, const u8 i2c_data) { int err; struct usb_device *udev = sd->gspca_dev.dev; @@ -80,6 +81,17 @@ int m5602_write_bridge(struct sd *sd, u8 address, u8 i2c_data) return (err < 0) ? err : 0; } +int m5602_wait_for_i2c(struct sd *sd) +{ + int err; + u8 data; + + do { + err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, &data); + } while ((data & I2C_BUSY) && !err); + return err; +} + int m5602_read_sensor(struct sd *sd, const u8 address, u8 *i2c_data, const u8 len) { @@ -88,9 +100,7 @@ int m5602_read_sensor(struct sd *sd, const u8 address, if (!len || len > sd->sensor->i2c_regW) return -EINVAL; - do { - err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data); - } while ((*i2c_data & I2C_BUSY) && !err); + err = m5602_wait_for_i2c(sd); if (err < 0) return err; @@ -103,21 +113,25 @@ int m5602_read_sensor(struct sd *sd, const u8 address, if (err < 0) return err; + /* Sensors with registers that are of only + one byte width are differently read */ + + /* FIXME: This works with the ov9650, but has issues with the po1030 */ if (sd->sensor->i2c_regW == 1) { - err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, len); + err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 1); if (err < 0) return err; err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x08); - if (err < 0) - return err; } else { err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x18 + len); - if (err < 0) - return err; } for (i = 0; (i < len) && !err; i++) { + err = m5602_wait_for_i2c(sd); + if (err < 0) + return err; + err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i])); PDEBUG(D_CONF, "Reading sensor register " @@ -206,6 +220,11 @@ static int m5602_probe_sensor(struct sd *sd) if (!sd->sensor->probe(sd)) return 0; + /* Try the ov7660 */ + sd->sensor = &ov7660; + if (!sd->sensor->probe(sd)) + return 0; + /* Try the s5k83a */ sd->sensor = &s5k83a; if (!sd->sensor->probe(sd)) @@ -409,8 +428,9 @@ MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); module_param(force_sensor, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(force_sensor, - "force detection of sensor, " - "1 = OV9650, 2 = S5K83A, 3 = S5K4AA, 4 = MT9M111, 5 = PO1030"); + "forces detection of a sensor, " + "1 = OV9650, 2 = S5K83A, 3 = S5K4AA, " + "4 = MT9M111, 5 = PO1030, 6 = OV7660"); module_param(dump_bridge, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(dump_bridge, "Dumps all usb bridge registers at startup"); diff --git a/drivers/media/video/gspca/m5602/m5602_mt9m111.c b/drivers/media/video/gspca/m5602/m5602_mt9m111.c index 7d3f9e348ef4..8d071dff6944 100644 --- a/drivers/media/video/gspca/m5602/m5602_mt9m111.c +++ b/drivers/media/video/gspca/m5602/m5602_mt9m111.c @@ -18,6 +18,23 @@ #include "m5602_mt9m111.h" +static int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val); +static int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val); +static int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val); +static int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val); +static int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val); +static int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val); +static int mt9m111_set_auto_white_balance(struct gspca_dev *gspca_dev, + __s32 val); +static int mt9m111_get_auto_white_balance(struct gspca_dev *gspca_dev, + __s32 *val); +static int mt9m111_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val); +static int mt9m111_set_green_balance(struct gspca_dev *gspca_dev, __s32 val); +static int mt9m111_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val); +static int mt9m111_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val); +static int mt9m111_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val); +static int mt9m111_set_red_balance(struct gspca_dev *gspca_dev, __s32 val); + static struct v4l2_pix_format mt9m111_modes[] = { { 640, @@ -32,6 +49,7 @@ static struct v4l2_pix_format mt9m111_modes[] = { }; const static struct ctrl mt9m111_ctrls[] = { +#define VFLIP_IDX 0 { { .id = V4L2_CID_VFLIP, @@ -44,7 +62,9 @@ const static struct ctrl mt9m111_ctrls[] = { }, .set = mt9m111_set_vflip, .get = mt9m111_get_vflip - }, { + }, +#define HFLIP_IDX 1 + { { .id = V4L2_CID_HFLIP, .type = V4L2_CTRL_TYPE_BOOLEAN, @@ -56,7 +76,9 @@ const static struct ctrl mt9m111_ctrls[] = { }, .set = mt9m111_set_hflip, .get = mt9m111_get_hflip - }, { + }, +#define GAIN_IDX 2 + { { .id = V4L2_CID_GAIN, .type = V4L2_CTRL_TYPE_INTEGER, @@ -64,21 +86,80 @@ const static struct ctrl mt9m111_ctrls[] = { .minimum = 0, .maximum = (INITIAL_MAX_GAIN - 1) * 2 * 2 * 2, .step = 1, - .default_value = DEFAULT_GAIN, + .default_value = MT9M111_DEFAULT_GAIN, .flags = V4L2_CTRL_FLAG_SLIDER }, .set = mt9m111_set_gain, .get = mt9m111_get_gain - } + }, +#define AUTO_WHITE_BALANCE_IDX 3 + { + { + .id = V4L2_CID_AUTO_WHITE_BALANCE, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "auto white balance", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + .set = mt9m111_set_auto_white_balance, + .get = mt9m111_get_auto_white_balance + }, +#define GREEN_BALANCE_IDX 4 + { + { + .id = M5602_V4L2_CID_GREEN_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "green balance", + .minimum = 0x00, + .maximum = 0x7ff, + .step = 0x1, + .default_value = MT9M111_GREEN_GAIN_DEFAULT, + .flags = V4L2_CTRL_FLAG_SLIDER + }, + .set = mt9m111_set_green_balance, + .get = mt9m111_get_green_balance + }, +#define BLUE_BALANCE_IDX 5 + { + { + .id = V4L2_CID_BLUE_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "blue balance", + .minimum = 0x00, + .maximum = 0x7ff, + .step = 0x1, + .default_value = MT9M111_BLUE_GAIN_DEFAULT, + .flags = V4L2_CTRL_FLAG_SLIDER + }, + .set = mt9m111_set_blue_balance, + .get = mt9m111_get_blue_balance + }, +#define RED_BALANCE_IDX 5 + { + { + .id = V4L2_CID_RED_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "red balance", + .minimum = 0x00, + .maximum = 0x7ff, + .step = 0x1, + .default_value = MT9M111_RED_GAIN_DEFAULT, + .flags = V4L2_CTRL_FLAG_SLIDER + }, + .set = mt9m111_set_red_balance, + .get = mt9m111_get_red_balance + }, }; - static void mt9m111_dump_registers(struct sd *sd); int mt9m111_probe(struct sd *sd) { u8 data[2] = {0x00, 0x00}; int i; + s32 *sensor_settings; if (force_sensor) { if (force_sensor == MT9M111_SENSOR) { @@ -117,16 +198,27 @@ int mt9m111_probe(struct sd *sd) return -ENODEV; sensor_found: + sensor_settings = kmalloc(ARRAY_SIZE(mt9m111_ctrls) * sizeof(s32), + GFP_KERNEL); + if (!sensor_settings) + return -ENOMEM; + sd->gspca_dev.cam.cam_mode = mt9m111_modes; sd->gspca_dev.cam.nmodes = ARRAY_SIZE(mt9m111_modes); sd->desc->ctrls = mt9m111_ctrls; sd->desc->nctrls = ARRAY_SIZE(mt9m111_ctrls); + + for (i = 0; i < ARRAY_SIZE(mt9m111_ctrls); i++) + sensor_settings[i] = mt9m111_ctrls[i].qctrl.default_value; + sd->sensor_priv = sensor_settings; + return 0; } int mt9m111_init(struct sd *sd) { int i, err = 0; + s32 *sensor_settings = sd->sensor_priv; /* Init the sensor */ for (i = 0; i < ARRAY_SIZE(init_mt9m111) && !err; i++) { @@ -147,36 +239,154 @@ int mt9m111_init(struct sd *sd) if (dump_sensor) mt9m111_dump_registers(sd); - return (err < 0) ? err : 0; + err = mt9m111_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]); + if (err < 0) + return err; + + err = mt9m111_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]); + if (err < 0) + return err; + + err = mt9m111_set_green_balance(&sd->gspca_dev, + sensor_settings[GREEN_BALANCE_IDX]); + if (err < 0) + return err; + + err = mt9m111_set_blue_balance(&sd->gspca_dev, + sensor_settings[BLUE_BALANCE_IDX]); + if (err < 0) + return err; + + err = mt9m111_set_red_balance(&sd->gspca_dev, + sensor_settings[RED_BALANCE_IDX]); + if (err < 0) + return err; + + return mt9m111_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]); } -int mt9m111_power_down(struct sd *sd) +int mt9m111_start(struct sd *sd) { - return 0; -} + int i, err = 0; + u8 data[2]; + struct cam *cam = &sd->gspca_dev.cam; + s32 *sensor_settings = sd->sensor_priv; -int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) -{ - int err; - u8 data[2] = {0x00, 0x00}; - struct sd *sd = (struct sd *) gspca_dev; + int width = cam->cam_mode[sd->gspca_dev.curr_mode].width - 1; + int height = cam->cam_mode[sd->gspca_dev.curr_mode].height; - err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, - data, 2); - *val = data[0] & MT9M111_RMB_MIRROR_ROWS; - PDEBUG(D_V4L2, "Read vertical flip %d", *val); + for (i = 0; i < ARRAY_SIZE(start_mt9m111) && !err; i++) { + if (start_mt9m111[i][0] == BRIDGE) { + err = m5602_write_bridge(sd, + start_mt9m111[i][1], + start_mt9m111[i][2]); + } else { + data[0] = start_mt9m111[i][2]; + data[1] = start_mt9m111[i][3]; + err = m5602_write_sensor(sd, + start_mt9m111[i][1], data, 2); + } + } + if (err < 0) + return err; + err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height >> 8) & 0xff); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height & 0xff)); + if (err < 0) + return err; + + for (i = 0; i < 2 && !err; i++) + err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 2); + if (err < 0) + return err; + + for (i = 0; i < 2 && !err; i++) + err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, 0); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, + (width >> 8) & 0xff); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, width & 0xff); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0); + if (err < 0) + return err; + + switch (width) { + case 640: + PDEBUG(D_V4L2, "Configuring camera for VGA mode"); + data[0] = MT9M111_RMB_OVER_SIZED; + data[1] = MT9M111_RMB_ROW_SKIP_2X | + MT9M111_RMB_COLUMN_SKIP_2X | + (sensor_settings[VFLIP_IDX] << 0) | + (sensor_settings[HFLIP_IDX] << 1); + + err = m5602_write_sensor(sd, + MT9M111_SC_R_MODE_CONTEXT_B, data, 2); + break; + + case 320: + PDEBUG(D_V4L2, "Configuring camera for QVGA mode"); + data[0] = MT9M111_RMB_OVER_SIZED; + data[1] = MT9M111_RMB_ROW_SKIP_4X | + MT9M111_RMB_COLUMN_SKIP_4X | + (sensor_settings[VFLIP_IDX] << 0) | + (sensor_settings[HFLIP_IDX] << 1); + err = m5602_write_sensor(sd, + MT9M111_SC_R_MODE_CONTEXT_B, data, 2); + break; + } return err; } -int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val) +void mt9m111_disconnect(struct sd *sd) +{ + sd->sensor = NULL; + kfree(sd->sensor_priv); +} + +static int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[VFLIP_IDX]; + PDEBUG(D_V4L2, "Read vertical flip %d", *val); + + return 0; +} + +static int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val) { int err; u8 data[2] = {0x00, 0x00}; struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; PDEBUG(D_V4L2, "Set vertical flip to %d", val); + sensor_settings[VFLIP_IDX] = val; + + /* The mt9m111 is flipped by default */ + val = !val; + /* Set the correct page map */ err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2); if (err < 0) @@ -186,34 +396,37 @@ int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val) if (err < 0) return err; - data[0] = (data[0] & 0xfe) | val; + data[1] = (data[1] & 0xfe) | val; err = m5602_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2); return err; } -int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) +static int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) { - int err; - u8 data[2] = {0x00, 0x00}; struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; - err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, - data, 2); - *val = data[0] & MT9M111_RMB_MIRROR_COLS; + *val = sensor_settings[HFLIP_IDX]; PDEBUG(D_V4L2, "Read horizontal flip %d", *val); - return err; + return 0; } -int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val) +static int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val) { int err; u8 data[2] = {0x00, 0x00}; struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; PDEBUG(D_V4L2, "Set horizontal flip to %d", val); + sensor_settings[HFLIP_IDX] = val; + + /* The mt9m111 is flipped by default */ + val = !val; + /* Set the correct page map */ err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2); if (err < 0) @@ -223,36 +436,62 @@ int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val) if (err < 0) return err; - data[0] = (data[0] & 0xfd) | ((val << 1) & 0x02); + data[1] = (data[1] & 0xfd) | ((val << 1) & 0x02); err = m5602_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2); return err; } -int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val) +static int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val) { - int err, tmp; - u8 data[2] = {0x00, 0x00}; struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; - err = m5602_read_sensor(sd, MT9M111_SC_GLOBAL_GAIN, data, 2); - tmp = ((data[1] << 8) | data[0]); - - *val = ((tmp & (1 << 10)) * 2) | - ((tmp & (1 << 9)) * 2) | - ((tmp & (1 << 8)) * 2) | - (tmp & 0x7f); - + *val = sensor_settings[GAIN_IDX]; PDEBUG(D_V4L2, "Read gain %d", *val); + return 0; +} + +static int mt9m111_set_auto_white_balance(struct gspca_dev *gspca_dev, + __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + int err; + u8 data[2]; + + err = m5602_read_sensor(sd, MT9M111_CP_OPERATING_MODE_CTL, data, 2); + if (err < 0) + return err; + + sensor_settings[AUTO_WHITE_BALANCE_IDX] = val & 0x01; + data[1] = ((data[1] & 0xfd) | ((val & 0x01) << 1)); + + err = m5602_write_sensor(sd, MT9M111_CP_OPERATING_MODE_CTL, data, 2); + + PDEBUG(D_V4L2, "Set auto white balance %d", val); return err; } -int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val) +static int mt9m111_get_auto_white_balance(struct gspca_dev *gspca_dev, + __s32 *val) { + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[AUTO_WHITE_BALANCE_IDX]; + PDEBUG(D_V4L2, "Read auto white balance %d", *val); + return 0; +} + +static int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val) { int err, tmp; u8 data[2] = {0x00, 0x00}; struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + sensor_settings[GAIN_IDX] = val; /* Set the correct page map */ err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2); @@ -275,8 +514,8 @@ int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val) else tmp = val; - data[1] = (tmp & 0xff00) >> 8; - data[0] = (tmp & 0xff); + data[1] = (tmp & 0xff); + data[0] = (tmp & 0xff00) >> 8; PDEBUG(D_V4L2, "tmp=%d, data[1]=%d, data[0]=%d", tmp, data[1], data[0]); @@ -286,6 +525,89 @@ int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val) return err; } +static int mt9m111_set_green_balance(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + u8 data[2]; + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + sensor_settings[GREEN_BALANCE_IDX] = val; + data[1] = (val & 0xff); + data[0] = (val & 0xff00) >> 8; + + PDEBUG(D_V4L2, "Set green balance %d", val); + err = m5602_write_sensor(sd, MT9M111_SC_GREEN_1_GAIN, + data, 2); + if (err < 0) + return err; + + return m5602_write_sensor(sd, MT9M111_SC_GREEN_2_GAIN, + data, 2); +} + +static int mt9m111_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[GREEN_BALANCE_IDX]; + PDEBUG(D_V4L2, "Read green balance %d", *val); + return 0; +} + +static int mt9m111_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val) +{ + u8 data[2]; + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + sensor_settings[BLUE_BALANCE_IDX] = val; + data[1] = (val & 0xff); + data[0] = (val & 0xff00) >> 8; + + PDEBUG(D_V4L2, "Set blue balance %d", val); + + return m5602_write_sensor(sd, MT9M111_SC_BLUE_GAIN, + data, 2); +} + +static int mt9m111_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[BLUE_BALANCE_IDX]; + PDEBUG(D_V4L2, "Read blue balance %d", *val); + return 0; +} + +static int mt9m111_set_red_balance(struct gspca_dev *gspca_dev, __s32 val) +{ + u8 data[2]; + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + sensor_settings[RED_BALANCE_IDX] = val; + data[1] = (val & 0xff); + data[0] = (val & 0xff00) >> 8; + + PDEBUG(D_V4L2, "Set red balance %d", val); + + return m5602_write_sensor(sd, MT9M111_SC_RED_GAIN, + data, 2); +} + +static int mt9m111_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[RED_BALANCE_IDX]; + PDEBUG(D_V4L2, "Read red balance %d", *val); + return 0; +} + static void mt9m111_dump_registers(struct sd *sd) { u8 address, value[2] = {0x00, 0x00}; diff --git a/drivers/media/video/gspca/m5602/m5602_mt9m111.h b/drivers/media/video/gspca/m5602/m5602_mt9m111.h index 00c6db02bdb7..b3de77823091 100644 --- a/drivers/media/video/gspca/m5602/m5602_mt9m111.h +++ b/drivers/media/video/gspca/m5602/m5602_mt9m111.h @@ -37,7 +37,6 @@ #define MT9M111_SC_VBLANK_CONTEXT_A 0x08 #define MT9M111_SC_SHUTTER_WIDTH 0x09 #define MT9M111_SC_ROW_SPEED 0x0a - #define MT9M111_SC_EXTRA_DELAY 0x0b #define MT9M111_SC_SHUTTER_DELAY 0x0c #define MT9M111_SC_RESET 0x0d @@ -50,9 +49,6 @@ #define MT9M111_SC_GREEN_2_GAIN 0x2e #define MT9M111_SC_GLOBAL_GAIN 0x2f -#define MT9M111_RMB_MIRROR_ROWS (1 << 0) -#define MT9M111_RMB_MIRROR_COLS (1 << 1) - #define MT9M111_CONTEXT_CONTROL 0xc8 #define MT9M111_PAGE_MAP 0xf0 #define MT9M111_BYTEWISE_ADDRESS 0xf1 @@ -74,8 +70,37 @@ #define MT9M111_COLORPIPE 0x01 #define MT9M111_CAMERA_CONTROL 0x02 +#define MT9M111_RESET (1 << 0) +#define MT9M111_RESTART (1 << 1) +#define MT9M111_ANALOG_STANDBY (1 << 2) +#define MT9M111_CHIP_ENABLE (1 << 3) +#define MT9M111_CHIP_DISABLE (0 << 3) +#define MT9M111_OUTPUT_DISABLE (1 << 4) +#define MT9M111_SHOW_BAD_FRAMES (1 << 0) +#define MT9M111_RESTART_BAD_FRAMES (1 << 1) +#define MT9M111_SYNCHRONIZE_CHANGES (1 << 7) + +#define MT9M111_RMB_OVER_SIZED (1 << 0) +#define MT9M111_RMB_MIRROR_ROWS (1 << 0) +#define MT9M111_RMB_MIRROR_COLS (1 << 1) +#define MT9M111_RMB_ROW_SKIP_2X (1 << 2) +#define MT9M111_RMB_COLUMN_SKIP_2X (1 << 3) +#define MT9M111_RMB_ROW_SKIP_4X (1 << 4) +#define MT9M111_RMB_COLUMN_SKIP_4X (1 << 5) + +#define MT9M111_COLOR_MATRIX_BYPASS (1 << 4) +#define MT9M111_SEL_CONTEXT_B (1 << 3) + +#define MT9M111_TRISTATE_PIN_IN_STANDBY (1 << 1) +#define MT9M111_SOC_SOFT_STANDBY (1 << 0) + +#define MT9M111_2D_DEFECT_CORRECTION_ENABLE (1 << 0) + #define INITIAL_MAX_GAIN 64 -#define DEFAULT_GAIN 283 +#define MT9M111_DEFAULT_GAIN 283 +#define MT9M111_GREEN_GAIN_DEFAULT 0x20 +#define MT9M111_BLUE_GAIN_DEFAULT 0x20 +#define MT9M111_RED_GAIN_DEFAULT 0x20 /*****************************************************************************/ @@ -85,16 +110,10 @@ extern int dump_sensor; int mt9m111_probe(struct sd *sd); int mt9m111_init(struct sd *sd); -int mt9m111_power_down(struct sd *sd); +int mt9m111_start(struct sd *sd); +void mt9m111_disconnect(struct sd *sd); -int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val); -int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val); -int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val); -int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val); -int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val); -int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val); - -const static struct m5602_sensor mt9m111 = { +static const struct m5602_sensor mt9m111 = { .name = "MT9M111", .i2c_slave_id = 0xba, @@ -102,7 +121,8 @@ const static struct m5602_sensor mt9m111 = { .probe = mt9m111_probe, .init = mt9m111_init, - .power_down = mt9m111_power_down + .disconnect = mt9m111_disconnect, + .start = mt9m111_start, }; static const unsigned char preinit_mt9m111[][4] = @@ -117,7 +137,14 @@ static const unsigned char preinit_mt9m111[][4] = {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, - {SENSOR, MT9M111_SC_RESET, 0xff, 0xf7}, + {SENSOR, MT9M111_SC_RESET, + MT9M111_RESET | + MT9M111_RESTART | + MT9M111_ANALOG_STANDBY | + MT9M111_CHIP_DISABLE, + MT9M111_SHOW_BAD_FRAMES | + MT9M111_RESTART_BAD_FRAMES | + MT9M111_SYNCHRONIZE_CHANGES}, {BRIDGE, M5602_XB_GPIO_DIR, 0x05, 0x00}, {BRIDGE, M5602_XB_GPIO_DAT, 0x04, 0x00}, @@ -145,78 +172,42 @@ static const unsigned char init_mt9m111[][4] = {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, - {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d, 0x00}, - {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00, 0x00}, - {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, - {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, - {SENSOR, MT9M111_SC_RESET, 0xff, 0xff}, - {SENSOR, MT9M111_SC_RESET, 0xff, 0xff}, - {SENSOR, MT9M111_SC_RESET, 0xff, 0xde}, - {SENSOR, MT9M111_SC_RESET, 0xff, 0xff}, - {SENSOR, MT9M111_SC_RESET, 0xff, 0xf7}, - {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01}, - - {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xb3, 0x00}, - - {SENSOR, MT9M111_CP_GLOBAL_CLK_CONTROL, 0xff, 0xff}, - - {BRIDGE, M5602_XB_GPIO_DIR, 0x05, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT, 0x04, 0x00}, - {BRIDGE, M5602_XB_GPIO_EN_H, 0x3e, 0x00}, - {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3e, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02, 0x00}, - {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00}, - {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, - {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, - {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, - {BRIDGE, M5602_XB_GPIO_DIR, 0x07, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT, 0x0b, 0x00}, {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00}, {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x04, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3e, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x07, 0x00}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x0b, 0x00}, {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a, 0x00}, - {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, - {SENSOR, MT9M111_SC_RESET, 0x00, 0x05}, - {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, {SENSOR, MT9M111_SC_RESET, 0x00, 0x29}, {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, {SENSOR, MT9M111_SC_RESET, 0x00, 0x08}, {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01}, - {SENSOR, MT9M111_CP_OPERATING_MODE_CTL, 0x00, 0x10}, + {SENSOR, MT9M111_CP_OPERATING_MODE_CTL, 0x00, + MT9M111_CP_OPERATING_MODE_CTL}, {SENSOR, MT9M111_CP_LENS_CORRECTION_1, 0x04, 0x2a}, - {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_A, 0x00, 0x01}, - {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_B, 0x00, 0x01}, + {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_A, 0x00, + MT9M111_2D_DEFECT_CORRECTION_ENABLE}, + {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_B, 0x00, + MT9M111_2D_DEFECT_CORRECTION_ENABLE}, {SENSOR, MT9M111_CP_LUMA_OFFSET, 0x00, 0x00}, {SENSOR, MT9M111_CP_LUMA_CLIP, 0xff, 0x00}, {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_A, 0x14, 0x00}, {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_B, 0x14, 0x00}, - {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xcd, 0x00}, - {SENSOR, 0xcd, 0x00, 0x0e}, - {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xd0, 0x00}, {SENSOR, 0xd0, 0x00, 0x40}, + {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x02}, {SENSOR, MT9M111_CC_AUTO_EXPOSURE_PARAMETER_18, 0x00, 0x00}, - {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00}, - {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x07}, - {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00}, {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x03}, - {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, - {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00}, - {SENSOR, 0x33, 0x03, 0x49}, - {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00}, + {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, {SENSOR, 0x33, 0x03, 0x49}, {SENSOR, 0x34, 0xc0, 0x19}, {SENSOR, 0x3f, 0x20, 0x20}, @@ -245,708 +236,40 @@ static const unsigned char init_mt9m111[][4] = {SENSOR, 0x85, 0x48, 0x0e}, {SENSOR, 0x86, 0x5b, 0x02}, {SENSOR, 0x87, 0x00, 0x5c}, - {SENSOR, MT9M111_CONTEXT_CONTROL, 0x00, 0x08}, + {SENSOR, MT9M111_CONTEXT_CONTROL, 0x00, MT9M111_SEL_CONTEXT_B}, {SENSOR, 0x60, 0x00, 0x80}, {SENSOR, 0x61, 0x00, 0x00}, {SENSOR, 0x62, 0x00, 0x00}, {SENSOR, 0x63, 0x00, 0x00}, {SENSOR, 0x64, 0x00, 0x00}, - {SENSOR, MT9M111_SC_ROWSTART, 0x00, 0x0d}, - {SENSOR, MT9M111_SC_COLSTART, 0x00, 0x18}, - {SENSOR, MT9M111_SC_WINDOW_HEIGHT, 0x04, 0x04}, - {SENSOR, MT9M111_SC_WINDOW_WIDTH, 0x05, 0x08}, - {SENSOR, MT9M111_SC_HBLANK_CONTEXT_B, 0x01, 0x38}, - {SENSOR, MT9M111_SC_VBLANK_CONTEXT_B, 0x00, 0x11}, - {SENSOR, MT9M111_SC_HBLANK_CONTEXT_A, 0x01, 0x38}, - {SENSOR, MT9M111_SC_VBLANK_CONTEXT_A, 0x00, 0x11}, - {SENSOR, MT9M111_SC_R_MODE_CONTEXT_B, 0x01, 0x03}, - {SENSOR, MT9M111_SC_R_MODE_CONTEXT_A, 0x01, 0x03}, + {SENSOR, MT9M111_SC_ROWSTART, 0x00, 0x0d}, /* 13 */ + {SENSOR, MT9M111_SC_COLSTART, 0x00, 0x12}, /* 18 */ + {SENSOR, MT9M111_SC_WINDOW_HEIGHT, 0x04, 0x00}, /* 1024 */ + {SENSOR, MT9M111_SC_WINDOW_WIDTH, 0x05, 0x10}, /* 1296 */ + {SENSOR, MT9M111_SC_HBLANK_CONTEXT_B, 0x01, 0x60}, /* 352 */ + {SENSOR, MT9M111_SC_VBLANK_CONTEXT_B, 0x00, 0x11}, /* 17 */ + {SENSOR, MT9M111_SC_HBLANK_CONTEXT_A, 0x01, 0x60}, /* 352 */ + {SENSOR, MT9M111_SC_VBLANK_CONTEXT_A, 0x00, 0x11}, /* 17 */ + {SENSOR, MT9M111_SC_R_MODE_CONTEXT_A, 0x01, 0x0f}, /* 271 */ {SENSOR, 0x30, 0x04, 0x00}, - - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, - {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, - {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, - {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00}, - {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x05, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x07, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xa0, 0x00}, - {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, - {SENSOR, MT9M111_SC_SHUTTER_WIDTH, 0x01, 0xf4}, - {SENSOR, MT9M111_SC_GLOBAL_GAIN, 0x00, 0xea}, - - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, - {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, - {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, - {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00}, - {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x05, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x07, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, - - {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, - {SENSOR, MT9M111_SC_RESET, 0x00, 0x09}, - {SENSOR, MT9M111_SC_RESET, 0x00, 0x29}, - {SENSOR, MT9M111_SC_RESET, 0x00, 0x08}, - {SENSOR, MT9M111_SC_RESET, 0x00, 0x0c}, - {SENSOR, MT9M111_SC_RESET, 0x00, 0x04}, - {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01}, - {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xb3, 0x00}, - {SENSOR, MT9M111_CP_GLOBAL_CLK_CONTROL, 0x00, 0x03}, - {BRIDGE, M5602_XB_GPIO_DIR, 0x05, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT, 0x04, 0x00}, - {BRIDGE, M5602_XB_GPIO_EN_H, 0x3e, 0x00}, - {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3e, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02, 0x00}, - {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00}, - {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, - {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, - {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, - {BRIDGE, M5602_XB_GPIO_DIR, 0x07, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT, 0x0b, 0x00}, - {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00}, - {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00}, - {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a, 0x00}, - - {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, - {SENSOR, MT9M111_SC_RESET, 0x00, 0x05}, - {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, - {SENSOR, MT9M111_SC_RESET, 0x00, 0x29}, - {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, - {SENSOR, MT9M111_SC_RESET, 0x00, 0x08}, - {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01}, - {SENSOR, MT9M111_CP_OPERATING_MODE_CTL, 0x00, 0x10}, - {SENSOR, MT9M111_CP_LENS_CORRECTION_1, 0x04, 0x2a}, - {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_A, 0x00, 0x01}, - {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_B, 0x00, 0x01}, - {SENSOR, MT9M111_CP_LUMA_OFFSET, 0x00, 0x00}, - {SENSOR, MT9M111_CP_LUMA_CLIP, 0xff, 0x00}, - {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_A, 0x14, 0x00}, - {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_B, 0x14, 0x00}, - - {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xcd, 0x00}, - {SENSOR, 0xcd, 0x00, 0x0e}, - {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xd0, 0x00}, - {SENSOR, 0xd0, 0x00, 0x40}, - {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x02}, - {SENSOR, MT9M111_CC_AUTO_EXPOSURE_PARAMETER_18, 0x00, 0x00}, - {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00}, - {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x07}, - {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00}, - {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x03}, - {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, - {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00}, - {SENSOR, 0x33, 0x03, 0x49}, - {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00}, - - {SENSOR, 0x33, 0x03, 0x49}, - {SENSOR, 0x34, 0xc0, 0x19}, - {SENSOR, 0x3f, 0x20, 0x20}, - {SENSOR, 0x40, 0x20, 0x20}, - {SENSOR, 0x5a, 0xc0, 0x0a}, - {SENSOR, 0x70, 0x7b, 0x0a}, - {SENSOR, 0x71, 0xff, 0x00}, - {SENSOR, 0x72, 0x19, 0x0e}, - {SENSOR, 0x73, 0x18, 0x0f}, - {SENSOR, 0x74, 0x57, 0x32}, - {SENSOR, 0x75, 0x56, 0x34}, - {SENSOR, 0x76, 0x73, 0x35}, - {SENSOR, 0x77, 0x30, 0x12}, - {SENSOR, 0x78, 0x79, 0x02}, - {SENSOR, 0x79, 0x75, 0x06}, - {SENSOR, 0x7a, 0x77, 0x0a}, - {SENSOR, 0x7b, 0x78, 0x09}, - {SENSOR, 0x7c, 0x7d, 0x06}, - {SENSOR, 0x7d, 0x31, 0x10}, - {SENSOR, 0x7e, 0x00, 0x7e}, - {SENSOR, 0x80, 0x59, 0x04}, - {SENSOR, 0x81, 0x59, 0x04}, - {SENSOR, 0x82, 0x57, 0x0a}, - {SENSOR, 0x83, 0x58, 0x0b}, - {SENSOR, 0x84, 0x47, 0x0c}, - {SENSOR, 0x85, 0x48, 0x0e}, - {SENSOR, 0x86, 0x5b, 0x02}, - {SENSOR, 0x87, 0x00, 0x5c}, - {SENSOR, MT9M111_CONTEXT_CONTROL, 0x00, 0x08}, - {SENSOR, 0x60, 0x00, 0x80}, - {SENSOR, 0x61, 0x00, 0x00}, - {SENSOR, 0x62, 0x00, 0x00}, - {SENSOR, 0x63, 0x00, 0x00}, - {SENSOR, 0x64, 0x00, 0x00}, - - {SENSOR, MT9M111_SC_ROWSTART, 0x00, 0x0d}, - {SENSOR, MT9M111_SC_COLSTART, 0x00, 0x18}, - {SENSOR, MT9M111_SC_WINDOW_HEIGHT, 0x04, 0x04}, - {SENSOR, MT9M111_SC_WINDOW_WIDTH, 0x05, 0x08}, - {SENSOR, MT9M111_SC_HBLANK_CONTEXT_B, 0x01, 0x38}, - {SENSOR, MT9M111_SC_VBLANK_CONTEXT_B, 0x00, 0x11}, - {SENSOR, MT9M111_SC_HBLANK_CONTEXT_A, 0x01, 0x38}, - {SENSOR, MT9M111_SC_VBLANK_CONTEXT_A, 0x00, 0x11}, - {SENSOR, MT9M111_SC_R_MODE_CONTEXT_B, 0x01, 0x03}, - {SENSOR, MT9M111_SC_R_MODE_CONTEXT_A, 0x01, 0x03}, - {SENSOR, 0x30, 0x04, 0x00}, - - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, - {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, - {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, - {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00}, - {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x05, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x07, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xa0, 0x00}, - {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, - {SENSOR, MT9M111_SC_SHUTTER_WIDTH, 0x01, 0xf4}, - {SENSOR, MT9M111_SC_GLOBAL_GAIN, 0x00, 0xea}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, - - {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, - {SENSOR, MT9M111_SC_RESET, 0x00, 0x09}, - {SENSOR, MT9M111_SC_RESET, 0x00, 0x29}, - {SENSOR, MT9M111_SC_RESET, 0x00, 0x08}, - {SENSOR, MT9M111_SC_RESET, 0x00, 0x0c}, - {SENSOR, MT9M111_SC_RESET, 0x00, 0x04}, - {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01}, - - {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xb3, 0x00}, - {SENSOR, MT9M111_CP_GLOBAL_CLK_CONTROL, 0x00, 0x03}, - {BRIDGE, M5602_XB_GPIO_DIR, 0x05, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT, 0x04, 0x00}, - {BRIDGE, M5602_XB_GPIO_EN_H, 0x3e, 0x00}, - {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3e, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02, 0x00}, - {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00}, - {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, - {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, - {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, - {BRIDGE, M5602_XB_GPIO_DIR, 0x07, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT, 0x0b, 0x00}, - {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00}, - {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00}, - {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a, 0x00}, - - {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, - {SENSOR, MT9M111_SC_RESET, 0x00, 0x05}, - {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, - {SENSOR, MT9M111_SC_RESET, 0x00, 0x29}, - {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, - {SENSOR, MT9M111_SC_RESET, 0x00, 0x08}, - {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01}, - {SENSOR, MT9M111_CP_OPERATING_MODE_CTL, 0x00, 0x10}, - {SENSOR, MT9M111_CP_LENS_CORRECTION_1, 0x04, 0x2a}, - {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_A, 0x00, 0x01}, - {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_B, 0x00, 0x01}, - {SENSOR, MT9M111_CP_LUMA_OFFSET, 0x00, 0x00}, - {SENSOR, MT9M111_CP_LUMA_CLIP, 0xff, 0x00}, - {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_A, 0x14, 0x00}, - {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_B, 0x14, 0x00}, - - {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xcd, 0x00}, - {SENSOR, 0xcd, 0x00, 0x0e}, - {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xd0, 0x00}, - {SENSOR, 0xd0, 0x00, 0x40}, - {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x02}, - {SENSOR, MT9M111_CC_AUTO_EXPOSURE_PARAMETER_18, 0x00, 0x00}, - {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00}, - {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x07}, - {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00}, - {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x03}, - {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, - {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00}, - {SENSOR, 0x33, 0x03, 0x49}, - {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00}, - - {SENSOR, 0x33, 0x03, 0x49}, - {SENSOR, 0x34, 0xc0, 0x19}, - {SENSOR, 0x3f, 0x20, 0x20}, - {SENSOR, 0x40, 0x20, 0x20}, - {SENSOR, 0x5a, 0xc0, 0x0a}, - {SENSOR, 0x70, 0x7b, 0x0a}, - {SENSOR, 0x71, 0xff, 0x00}, - {SENSOR, 0x72, 0x19, 0x0e}, - {SENSOR, 0x73, 0x18, 0x0f}, - {SENSOR, 0x74, 0x57, 0x32}, - {SENSOR, 0x75, 0x56, 0x34}, - {SENSOR, 0x76, 0x73, 0x35}, - {SENSOR, 0x77, 0x30, 0x12}, - {SENSOR, 0x78, 0x79, 0x02}, - {SENSOR, 0x79, 0x75, 0x06}, - {SENSOR, 0x7a, 0x77, 0x0a}, - {SENSOR, 0x7b, 0x78, 0x09}, - {SENSOR, 0x7c, 0x7d, 0x06}, - {SENSOR, 0x7d, 0x31, 0x10}, - {SENSOR, 0x7e, 0x00, 0x7e}, - {SENSOR, 0x80, 0x59, 0x04}, - {SENSOR, 0x81, 0x59, 0x04}, - {SENSOR, 0x82, 0x57, 0x0a}, - {SENSOR, 0x83, 0x58, 0x0b}, - {SENSOR, 0x84, 0x47, 0x0c}, - {SENSOR, 0x85, 0x48, 0x0e}, - {SENSOR, 0x86, 0x5b, 0x02}, - {SENSOR, 0x87, 0x00, 0x5c}, - {SENSOR, MT9M111_CONTEXT_CONTROL, 0x00, 0x08}, - {SENSOR, 0x60, 0x00, 0x80}, - {SENSOR, 0x61, 0x00, 0x00}, - {SENSOR, 0x62, 0x00, 0x00}, - {SENSOR, 0x63, 0x00, 0x00}, - {SENSOR, 0x64, 0x00, 0x00}, - - {SENSOR, MT9M111_SC_ROWSTART, 0x00, 0x0d}, - {SENSOR, MT9M111_SC_COLSTART, 0x00, 0x18}, - {SENSOR, MT9M111_SC_WINDOW_HEIGHT, 0x04, 0x04}, - {SENSOR, MT9M111_SC_WINDOW_WIDTH, 0x05, 0x08}, - {SENSOR, MT9M111_SC_HBLANK_CONTEXT_B, 0x01, 0x38}, - {SENSOR, MT9M111_SC_VBLANK_CONTEXT_B, 0x00, 0x11}, - {SENSOR, MT9M111_SC_HBLANK_CONTEXT_A, 0x01, 0x38}, - {SENSOR, MT9M111_SC_VBLANK_CONTEXT_A, 0x00, 0x11}, - {SENSOR, MT9M111_SC_R_MODE_CONTEXT_B, 0x01, 0x03}, - {SENSOR, MT9M111_SC_R_MODE_CONTEXT_A, 0x01, 0x03}, - {SENSOR, 0x30, 0x04, 0x00}, - - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, - {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, - {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, - {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00}, - {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x05, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x07, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xa0, 0x00}, - {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, - {SENSOR, MT9M111_SC_SHUTTER_WIDTH, 0x01, 0xf4}, - {SENSOR, MT9M111_SC_GLOBAL_GAIN, 0x00, 0xea}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, - {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, - {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, - {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00}, - {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, - {SENSOR, MT9M111_SC_RESET, 0x00, 0x09}, - {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, - {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00}, - {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, - {SENSOR, MT9M111_SC_RESET, 0x00, 0x29}, - {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, - {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00}, - {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, - {SENSOR, MT9M111_SC_RESET, 0x00, 0x08}, - {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, - {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00}, - {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, - {SENSOR, MT9M111_SC_RESET, 0x00, 0x0c}, - {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, - {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00}, - {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, - {SENSOR, MT9M111_SC_RESET, 0x00, 0x04}, - {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01}, - {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, - {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xb3, 0x00}, - {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, - {SENSOR, MT9M111_CP_GLOBAL_CLK_CONTROL, 0x00, 0x03}, - {BRIDGE, M5602_XB_GPIO_DIR, 0x05, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT, 0x04, 0x00}, - {BRIDGE, M5602_XB_GPIO_EN_H, 0x3e, 0x00}, - {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3e, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02, 0x00}, - {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00}, - {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, - {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, - {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, - {BRIDGE, M5602_XB_GPIO_DIR, 0x07, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT, 0x0b, 0x00}, - {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00}, - {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00}, - {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a, 0x00}, - {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, - {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, - {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00}, - {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, - {SENSOR, MT9M111_SC_RESET, 0x00, 0x05}, - {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, - {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, - {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00}, - {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, - {SENSOR, MT9M111_SC_RESET, 0x00, 0x29}, - {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, - {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, - {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00}, - {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, - - {SENSOR, MT9M111_SC_RESET, 0x00, 0x08}, - {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01}, - {SENSOR, MT9M111_CP_OPERATING_MODE_CTL, 0x00, 0x10}, - {SENSOR, MT9M111_CP_LENS_CORRECTION_1, 0x04, 0x2a}, - {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_A, 0x00, 0x01}, - {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_B, 0x00, 0x01}, - {SENSOR, MT9M111_CP_LUMA_OFFSET, 0x00, 0x00}, - {SENSOR, MT9M111_CP_LUMA_CLIP, 0xff, 0x00}, - {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_A, 0x14, 0x00}, - {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_B, 0x14, 0x00}, - - {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, - {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xcd, 0x00}, - {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, - {SENSOR, 0xcd, 0x00, 0x0e}, - {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, - {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xd0, 0x00}, - {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, - {SENSOR, 0xd0, 0x00, 0x40}, - {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x02}, - {SENSOR, MT9M111_CC_AUTO_EXPOSURE_PARAMETER_18, 0x00, 0x00}, - {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, - {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00}, - {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, - {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x07}, - {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, - {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00}, - {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, - {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x03}, - {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, - {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, - {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00}, - {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, - {SENSOR, 0x33, 0x03, 0x49}, - {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, - {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00}, - {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, - - {SENSOR, 0x33, 0x03, 0x49}, - {SENSOR, 0x34, 0xc0, 0x19}, - {SENSOR, 0x3f, 0x20, 0x20}, - {SENSOR, 0x40, 0x20, 0x20}, - {SENSOR, 0x5a, 0xc0, 0x0a}, - {SENSOR, 0x70, 0x7b, 0x0a}, - {SENSOR, 0x71, 0xff, 0x00}, - {SENSOR, 0x72, 0x19, 0x0e}, - {SENSOR, 0x73, 0x18, 0x0f}, - {SENSOR, 0x74, 0x57, 0x32}, - {SENSOR, 0x75, 0x56, 0x34}, - {SENSOR, 0x76, 0x73, 0x35}, - {SENSOR, 0x77, 0x30, 0x12}, - {SENSOR, 0x78, 0x79, 0x02}, - {SENSOR, 0x79, 0x75, 0x06}, - {SENSOR, 0x7a, 0x77, 0x0a}, - {SENSOR, 0x7b, 0x78, 0x09}, - {SENSOR, 0x7c, 0x7d, 0x06}, - {SENSOR, 0x7d, 0x31, 0x10}, - {SENSOR, 0x7e, 0x00, 0x7e}, - {SENSOR, 0x80, 0x59, 0x04}, - {SENSOR, 0x81, 0x59, 0x04}, - {SENSOR, 0x82, 0x57, 0x0a}, - {SENSOR, 0x83, 0x58, 0x0b}, - {SENSOR, 0x84, 0x47, 0x0c}, - {SENSOR, 0x85, 0x48, 0x0e}, - {SENSOR, 0x86, 0x5b, 0x02}, - {SENSOR, 0x87, 0x00, 0x5c}, - {SENSOR, MT9M111_CONTEXT_CONTROL, 0x00, 0x08}, - {SENSOR, 0x60, 0x00, 0x80}, - {SENSOR, 0x61, 0x00, 0x00}, - {SENSOR, 0x62, 0x00, 0x00}, - {SENSOR, 0x63, 0x00, 0x00}, - {SENSOR, 0x64, 0x00, 0x00}, - {SENSOR, MT9M111_SC_ROWSTART, 0x00, 0x0d}, - {SENSOR, MT9M111_SC_COLSTART, 0x00, 0x12}, - {SENSOR, MT9M111_SC_WINDOW_HEIGHT, 0x04, 0x00}, - {SENSOR, MT9M111_SC_WINDOW_WIDTH, 0x05, 0x10}, - {SENSOR, MT9M111_SC_HBLANK_CONTEXT_B, 0x01, 0x60}, - {SENSOR, MT9M111_SC_VBLANK_CONTEXT_B, 0x00, 0x11}, - {SENSOR, MT9M111_SC_HBLANK_CONTEXT_A, 0x01, 0x60}, - {SENSOR, MT9M111_SC_VBLANK_CONTEXT_A, 0x00, 0x11}, - {SENSOR, MT9M111_SC_R_MODE_CONTEXT_B, 0x01, 0x0f}, - {SENSOR, MT9M111_SC_R_MODE_CONTEXT_A, 0x01, 0x0f}, - {SENSOR, 0x30, 0x04, 0x00}, - - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, - {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, - {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, - {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00}, - {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0xe3, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x87, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, - - {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, - {SENSOR, MT9M111_SC_SHUTTER_WIDTH, 0x01, 0x90}, - {SENSOR, MT9M111_SC_GLOBAL_GAIN, 0x00, 0xe6}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, - {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, - {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, - {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00}, - {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, - {SENSOR, MT9M111_SC_RESET, 0x00, 0x09}, - {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, - {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00}, - {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, - {SENSOR, MT9M111_SC_RESET, 0x00, 0x29}, - {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, - {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00}, - {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, - {SENSOR, MT9M111_SC_RESET, 0x00, 0x08}, - {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, - {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00}, - {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, - {SENSOR, MT9M111_SC_RESET, 0x00, 0x0c}, - {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, - {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00}, - {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, - {SENSOR, MT9M111_SC_RESET, 0x00, 0x04}, - {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01}, - {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, - {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xb3, 0x00}, - {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, - {SENSOR, MT9M111_CP_GLOBAL_CLK_CONTROL, 0x00, 0x03}, - - {BRIDGE, M5602_XB_GPIO_DIR, 0x05, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT, 0x04, 0x00}, - {BRIDGE, M5602_XB_GPIO_EN_H, 0x3e, 0x00}, - {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3e, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02, 0x00}, - {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00}, - {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, - {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, - {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, - {BRIDGE, M5602_XB_GPIO_DIR, 0x07, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT, 0x0b, 0x00}, - {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00}, - {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00}, - {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a, 0x00}, - {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, - {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, - {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00}, - {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, - {SENSOR, MT9M111_SC_RESET, 0x00, 0x05}, - {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, - {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, - {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00}, - {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, - {SENSOR, MT9M111_SC_RESET, 0x00, 0x29}, - {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, - {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, - {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00}, - {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, - {SENSOR, MT9M111_SC_RESET, 0x00, 0x08}, - {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01}, - {SENSOR, MT9M111_CP_OPERATING_MODE_CTL, 0x00, 0x10}, - {SENSOR, MT9M111_CP_LENS_CORRECTION_1, 0x04, 0x2a}, - {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_A, 0x00, 0x01}, - {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_B, 0x00, 0x01}, - {SENSOR, MT9M111_CP_LUMA_OFFSET, 0x00, 0x00}, - {SENSOR, MT9M111_CP_LUMA_CLIP, 0xff, 0x00}, - {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_A, 0x14, 0x00}, - {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_B, 0x14, 0x00}, - - {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, - {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xcd, 0x00}, - {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, - {SENSOR, 0xcd, 0x00, 0x0e}, - {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, - {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xd0, 0x00}, - {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, - {SENSOR, 0xd0, 0x00, 0x40}, - {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x02}, - {SENSOR, MT9M111_CC_AUTO_EXPOSURE_PARAMETER_18, 0x00, 0x00}, - {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, - {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00}, - {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, - {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x07}, - {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, - {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00}, - {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, - {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x03}, - {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, - - {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, - {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00}, - {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, - {SENSOR, 0x33, 0x03, 0x49}, - {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00}, - {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00}, - {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00}, - - {SENSOR, 0x33, 0x03, 0x49}, - {SENSOR, 0x34, 0xc0, 0x19}, - {SENSOR, 0x3f, 0x20, 0x20}, - {SENSOR, 0x40, 0x20, 0x20}, - {SENSOR, 0x5a, 0xc0, 0x0a}, - {SENSOR, 0x70, 0x7b, 0x0a}, - {SENSOR, 0x71, 0xff, 0x00}, - {SENSOR, 0x72, 0x19, 0x0e}, - {SENSOR, 0x73, 0x18, 0x0f}, - {SENSOR, 0x74, 0x57, 0x32}, - {SENSOR, 0x75, 0x56, 0x34}, - {SENSOR, 0x76, 0x73, 0x35}, - {SENSOR, 0x77, 0x30, 0x12}, - {SENSOR, 0x78, 0x79, 0x02}, - {SENSOR, 0x79, 0x75, 0x06}, - {SENSOR, 0x7a, 0x77, 0x0a}, - {SENSOR, 0x7b, 0x78, 0x09}, - {SENSOR, 0x7c, 0x7d, 0x06}, - {SENSOR, 0x7d, 0x31, 0x10}, - {SENSOR, 0x7e, 0x00, 0x7e}, - {SENSOR, 0x80, 0x59, 0x04}, - {SENSOR, 0x81, 0x59, 0x04}, - {SENSOR, 0x82, 0x57, 0x0a}, - {SENSOR, 0x83, 0x58, 0x0b}, - {SENSOR, 0x84, 0x47, 0x0c}, - {SENSOR, 0x85, 0x48, 0x0e}, - {SENSOR, 0x86, 0x5b, 0x02}, - {SENSOR, 0x87, 0x00, 0x5c}, - {SENSOR, MT9M111_CONTEXT_CONTROL, 0x00, 0x08}, - {SENSOR, 0x60, 0x00, 0x80}, - {SENSOR, 0x61, 0x00, 0x00}, - {SENSOR, 0x62, 0x00, 0x00}, - {SENSOR, 0x63, 0x00, 0x00}, - {SENSOR, 0x64, 0x00, 0x00}, - - {SENSOR, MT9M111_SC_ROWSTART, 0x00, 0x0d}, - {SENSOR, MT9M111_SC_COLSTART, 0x00, 0x12}, - {SENSOR, MT9M111_SC_WINDOW_HEIGHT, 0x04, 0x00}, - {SENSOR, MT9M111_SC_WINDOW_WIDTH, 0x05, 0x10}, - {SENSOR, MT9M111_SC_HBLANK_CONTEXT_B, 0x01, 0x60}, - {SENSOR, MT9M111_SC_VBLANK_CONTEXT_B, 0x00, 0x11}, - {SENSOR, MT9M111_SC_HBLANK_CONTEXT_A, 0x01, 0x60}, - {SENSOR, MT9M111_SC_VBLANK_CONTEXT_A, 0x00, 0x11}, - {SENSOR, MT9M111_SC_R_MODE_CONTEXT_B, 0x01, 0x0f}, - {SENSOR, MT9M111_SC_R_MODE_CONTEXT_A, 0x01, 0x0f}, - {SENSOR, 0x30, 0x04, 0x00}, - - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, - {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, - {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, - {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00}, - {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0xe0, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00}, /* 639*/ - {BRIDGE, M5602_XB_HSYNC_PARA, 0x7f, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, - - {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00}, /* Set number of blank rows chosen to 400 */ {SENSOR, MT9M111_SC_SHUTTER_WIDTH, 0x01, 0x90}, - /* Set the global gain to 283 (of 512) */ - {SENSOR, MT9M111_SC_GLOBAL_GAIN, 0x03, 0x63} +}; + +static const unsigned char start_mt9m111[][4] = +{ + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, + {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00}, + {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, }; #endif diff --git a/drivers/media/video/gspca/m5602/m5602_ov7660.c b/drivers/media/video/gspca/m5602/m5602_ov7660.c new file mode 100644 index 000000000000..7aafeb7cfa07 --- /dev/null +++ b/drivers/media/video/gspca/m5602/m5602_ov7660.c @@ -0,0 +1,227 @@ +/* + * Driver for the ov7660 sensor + * + * Copyright (C) 2009 Erik Andrén + * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project. + * Copyright (C) 2005 m5603x Linux Driver Project + * + * Portions of code to USB interface and ALi driver software, + * Copyright (c) 2006 Willem Duinker + * v4l2 interface modeled after the V4L2 driver + * for SN9C10x PC Camera Controllers + * + * 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. + * + */ + +#include "m5602_ov7660.h" + +static int ov7660_get_gain(struct gspca_dev *gspca_dev, __s32 *val); +static int ov7660_set_gain(struct gspca_dev *gspca_dev, __s32 val); + +const static struct ctrl ov7660_ctrls[] = { +#define GAIN_IDX 1 + { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "gain", + .minimum = 0x00, + .maximum = 0xff, + .step = 0x1, + .default_value = OV7660_DEFAULT_GAIN, + .flags = V4L2_CTRL_FLAG_SLIDER + }, + .set = ov7660_set_gain, + .get = ov7660_get_gain + }, +}; + +static struct v4l2_pix_format ov7660_modes[] = { + { + 640, + 480, + V4L2_PIX_FMT_SBGGR8, + V4L2_FIELD_NONE, + .sizeimage = + 640 * 480, + .bytesperline = 640, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0 + } +}; + +static void ov7660_dump_registers(struct sd *sd); + +int ov7660_probe(struct sd *sd) +{ + int err = 0, i; + u8 prod_id = 0, ver_id = 0; + + s32 *sensor_settings; + + if (force_sensor) { + if (force_sensor == OV7660_SENSOR) { + info("Forcing an %s sensor", ov7660.name); + goto sensor_found; + } + /* If we want to force another sensor, + don't try to probe this one */ + return -ENODEV; + } + + /* Do the preinit */ + for (i = 0; i < ARRAY_SIZE(preinit_ov7660) && !err; i++) { + u8 data[2]; + + if (preinit_ov7660[i][0] == BRIDGE) { + err = m5602_write_bridge(sd, + preinit_ov7660[i][1], + preinit_ov7660[i][2]); + } else { + data[0] = preinit_ov7660[i][2]; + err = m5602_write_sensor(sd, + preinit_ov7660[i][1], data, 1); + } + } + if (err < 0) + return err; + + if (m5602_read_sensor(sd, OV7660_PID, &prod_id, 1)) + return -ENODEV; + + if (m5602_read_sensor(sd, OV7660_VER, &ver_id, 1)) + return -ENODEV; + + info("Sensor reported 0x%x%x", prod_id, ver_id); + + if ((prod_id == 0x76) && (ver_id == 0x60)) { + info("Detected a ov7660 sensor"); + goto sensor_found; + } + return -ENODEV; + +sensor_found: + sensor_settings = kmalloc( + ARRAY_SIZE(ov7660_ctrls) * sizeof(s32), GFP_KERNEL); + if (!sensor_settings) + return -ENOMEM; + + sd->gspca_dev.cam.cam_mode = ov7660_modes; + sd->gspca_dev.cam.nmodes = ARRAY_SIZE(ov7660_modes); + sd->desc->ctrls = ov7660_ctrls; + sd->desc->nctrls = ARRAY_SIZE(ov7660_ctrls); + + for (i = 0; i < ARRAY_SIZE(ov7660_ctrls); i++) + sensor_settings[i] = ov7660_ctrls[i].qctrl.default_value; + sd->sensor_priv = sensor_settings; + + return 0; +} + +int ov7660_init(struct sd *sd) +{ + int i, err = 0; + s32 *sensor_settings = sd->sensor_priv; + + /* Init the sensor */ + for (i = 0; i < ARRAY_SIZE(init_ov7660); i++) { + u8 data[2]; + + if (init_ov7660[i][0] == BRIDGE) { + err = m5602_write_bridge(sd, + init_ov7660[i][1], + init_ov7660[i][2]); + } else { + data[0] = init_ov7660[i][2]; + err = m5602_write_sensor(sd, + init_ov7660[i][1], data, 1); + } + } + + if (dump_sensor) + ov7660_dump_registers(sd); + + err = ov7660_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]); + if (err < 0) + return err; + + return err; +} + +int ov7660_start(struct sd *sd) +{ + return 0; +} + +int ov7660_stop(struct sd *sd) +{ + return 0; +} + +void ov7660_disconnect(struct sd *sd) +{ + ov7660_stop(sd); + + sd->sensor = NULL; + kfree(sd->sensor_priv); +} + +static int ov7660_get_gain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[GAIN_IDX]; + PDEBUG(D_V4L2, "Read gain %d", *val); + return 0; +} + +static int ov7660_set_gain(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + u8 i2c_data; + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + PDEBUG(D_V4L2, "Setting gain to %d", val); + + sensor_settings[GAIN_IDX] = val; + + err = m5602_write_sensor(sd, OV7660_GAIN, &i2c_data, 1); + return err; +} + +static void ov7660_dump_registers(struct sd *sd) +{ + int address; + info("Dumping the ov7660 register state"); + for (address = 0; address < 0xa9; address++) { + u8 value; + m5602_read_sensor(sd, address, &value, 1); + info("register 0x%x contains 0x%x", + address, value); + } + + info("ov7660 register state dump complete"); + + info("Probing for which registers that are read/write"); + for (address = 0; address < 0xff; address++) { + u8 old_value, ctrl_value; + u8 test_value[2] = {0xff, 0xff}; + + m5602_read_sensor(sd, address, &old_value, 1); + m5602_write_sensor(sd, address, test_value, 1); + m5602_read_sensor(sd, address, &ctrl_value, 1); + + if (ctrl_value == test_value[0]) + info("register 0x%x is writeable", address); + else + info("register 0x%x is read only", address); + + /* Restore original value */ + m5602_write_sensor(sd, address, &old_value, 1); + } +} diff --git a/drivers/media/video/gspca/m5602/m5602_ov7660.h b/drivers/media/video/gspca/m5602/m5602_ov7660.h new file mode 100644 index 000000000000..3f2c169a93ea --- /dev/null +++ b/drivers/media/video/gspca/m5602/m5602_ov7660.h @@ -0,0 +1,279 @@ +/* + * Driver for the ov7660 sensor + * + * Copyright (C) 2009 Erik Andrén + * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project. + * Copyright (C) 2005 m5603x Linux Driver Project + * + * Portions of code to USB interface and ALi driver software, + * Copyright (c) 2006 Willem Duinker + * v4l2 interface modeled after the V4L2 driver + * for SN9C10x PC Camera Controllers + * + * 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. + * + */ + +#ifndef M5602_OV7660_H_ +#define M5602_OV7660_H_ + +#include "m5602_sensor.h" + +#define OV7660_GAIN 0x00 +#define OV7660_BLUE_GAIN 0x01 +#define OV7660_RED_GAIN 0x02 +#define OV7660_VREF 0x03 +#define OV7660_COM1 0x04 +#define OV7660_BAVE 0x05 +#define OV7660_GEAVE 0x06 +#define OV7660_AECHH 0x07 +#define OV7660_RAVE 0x08 +#define OV7660_COM2 0x09 +#define OV7660_PID 0x0a +#define OV7660_VER 0x0b +#define OV7660_COM3 0x0c +#define OV7660_COM4 0x0d +#define OV7660_COM5 0x0e +#define OV7660_COM6 0x0f +#define OV7660_AECH 0x10 +#define OV7660_CLKRC 0x11 +#define OV7660_COM7 0x12 +#define OV7660_COM8 0x13 +#define OV7660_COM9 0x14 +#define OV7660_COM10 0x15 +#define OV7660_RSVD16 0x16 +#define OV7660_HSTART 0x17 +#define OV7660_HSTOP 0x18 +#define OV7660_VSTART 0x19 +#define OV7660_VSTOP 0x1a +#define OV7660_PSHFT 0x1b +#define OV7660_MIDH 0x1c +#define OV7660_MIDL 0x1d +#define OV7660_MVFP 0x1e +#define OV7660_LAEC 0x1f +#define OV7660_BOS 0x20 +#define OV7660_GBOS 0x21 +#define OV7660_GROS 0x22 +#define OV7660_ROS 0x23 +#define OV7660_AEW 0x24 +#define OV7660_AEB 0x25 +#define OV7660_VPT 0x26 +#define OV7660_BBIAS 0x27 +#define OV7660_GbBIAS 0x28 +#define OV7660_RSVD29 0x29 +#define OV7660_RBIAS 0x2c +#define OV7660_HREF 0x32 +#define OV7660_ADC 0x37 +#define OV7660_OFON 0x39 +#define OV7660_TSLB 0x3a +#define OV7660_COM12 0x3c +#define OV7660_COM13 0x3d +#define OV7660_LCC1 0x62 +#define OV7660_LCC2 0x63 +#define OV7660_LCC3 0x64 +#define OV7660_LCC4 0x65 +#define OV7660_LCC5 0x66 +#define OV7660_HV 0x69 +#define OV7660_RSVDA1 0xa1 + +#define OV7660_DEFAULT_GAIN 0x0e +#define OV7660_DEFAULT_RED_GAIN 0x80 +#define OV7660_DEFAULT_BLUE_GAIN 0x80 +#define OV7660_DEFAULT_SATURATION 0x00 +#define OV7660_DEFAULT_EXPOSURE 0x20 + +/* Kernel module parameters */ +extern int force_sensor; +extern int dump_sensor; + +int ov7660_probe(struct sd *sd); +int ov7660_init(struct sd *sd); +int ov7660_start(struct sd *sd); +int ov7660_stop(struct sd *sd); +void ov7660_disconnect(struct sd *sd); + +const static struct m5602_sensor ov7660 = { + .name = "ov7660", + .i2c_slave_id = 0x42, + .i2c_regW = 1, + .probe = ov7660_probe, + .init = ov7660_init, + .start = ov7660_start, + .stop = ov7660_stop, + .disconnect = ov7660_disconnect, +}; + +static const unsigned char preinit_ov7660[][4] = +{ + {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02}, + {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d}, + {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x03}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x03}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c}, + + {SENSOR, OV7660_OFON, 0x0c}, + {SENSOR, OV7660_COM2, 0x11}, + {SENSOR, OV7660_COM7, 0x05}, + + {BRIDGE, M5602_XB_GPIO_DIR, 0x01}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x04}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, + {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06}, + {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x08}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x05}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, + {BRIDGE, M5602_XB_GPIO_EN_L, 0x00} +}; + +static const unsigned char init_ov7660[][4] = +{ + {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02}, + {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d}, + {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x03}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x03}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c}, + + {SENSOR, OV7660_OFON, 0x0c}, + {SENSOR, OV7660_COM2, 0x11}, + {SENSOR, OV7660_COM7, 0x05}, + + {BRIDGE, M5602_XB_GPIO_DIR, 0x01}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x04}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, + {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06}, + {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x08}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x05}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, + {BRIDGE, M5602_XB_GPIO_EN_L, 0x00}, + + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x02}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, + + {SENSOR, OV7660_AECH, OV7660_DEFAULT_EXPOSURE}, + {SENSOR, OV7660_COM1, 0x00}, + + {BRIDGE, M5602_XB_GPIO_DIR, 0x01}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x04}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, + {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06}, + {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x08}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, + + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x05}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, + {BRIDGE, M5602_XB_GPIO_EN_L, 0x00}, + + {SENSOR, OV7660_COM7, 0x80}, + {SENSOR, OV7660_CLKRC, 0x80}, + {SENSOR, OV7660_BLUE_GAIN, 0x80}, + {SENSOR, OV7660_RED_GAIN, 0x80}, + {SENSOR, OV7660_COM9, 0x4c}, + {SENSOR, OV7660_OFON, 0x43}, + {SENSOR, OV7660_COM12, 0x28}, + {SENSOR, OV7660_COM8, 0x00}, + {SENSOR, OV7660_COM10, 0x40}, + {SENSOR, OV7660_HSTART, 0x0c}, + {SENSOR, OV7660_HSTOP, 0x61}, + {SENSOR, OV7660_HREF, 0xa4}, + {SENSOR, OV7660_PSHFT, 0x0b}, + {SENSOR, OV7660_VSTART, 0x01}, + {SENSOR, OV7660_VSTOP, 0x7a}, + {SENSOR, OV7660_VREF, 0x00}, + {SENSOR, OV7660_COM7, 0x05}, + {SENSOR, OV7660_COM6, 0x4b}, + {SENSOR, OV7660_BBIAS, 0x98}, + {SENSOR, OV7660_GbBIAS, 0x98}, + {SENSOR, OV7660_RSVD29, 0x98}, + {SENSOR, OV7660_RBIAS, 0x98}, + {SENSOR, OV7660_COM1, 0x00}, + {SENSOR, OV7660_AECH, 0x00}, + {SENSOR, OV7660_AECHH, 0x00}, + {SENSOR, OV7660_ADC, 0x04}, + {SENSOR, OV7660_COM13, 0x00}, + {SENSOR, OV7660_RSVDA1, 0x23}, + {SENSOR, OV7660_TSLB, 0x0d}, + {SENSOR, OV7660_HV, 0x80}, + {SENSOR, OV7660_LCC1, 0x00}, + {SENSOR, OV7660_LCC2, 0x00}, + {SENSOR, OV7660_LCC3, 0x10}, + {SENSOR, OV7660_LCC4, 0x40}, + {SENSOR, OV7660_LCC5, 0x01}, + + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c}, + {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81}, + {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82}, + {BRIDGE, M5602_XB_SIG_INI, 0x01}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x08}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x01}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0xe0}, /* 480 */ + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x02}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x27}, /* 39 */ + {BRIDGE, M5602_XB_VSYNC_PARA, 0x02}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0xa7}, /* 679 */ + {BRIDGE, M5602_XB_SIG_INI, 0x00}, + + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, + + {SENSOR, OV7660_AECH, 0x20}, + {SENSOR, OV7660_COM1, 0x00}, + {SENSOR, OV7660_OFON, 0x0c}, + {SENSOR, OV7660_COM2, 0x11}, + {SENSOR, OV7660_COM7, 0x05}, + {SENSOR, OV7660_BLUE_GAIN, 0x80}, + {SENSOR, OV7660_RED_GAIN, 0x80}, + + {BRIDGE, M5602_XB_GPIO_DIR, 0x01}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x04}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, + {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06}, + {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x08}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0} +}; + +#endif diff --git a/drivers/media/video/gspca/m5602/m5602_ov9650.c b/drivers/media/video/gspca/m5602/m5602_ov9650.c index fc4548fd441d..c2739d6605a1 100644 --- a/drivers/media/video/gspca/m5602/m5602_ov9650.c +++ b/drivers/media/video/gspca/m5602/m5602_ov9650.c @@ -18,12 +18,69 @@ #include "m5602_ov9650.h" +static int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val); +static int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val); +static int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val); +static int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val); +static int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val); +static int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val); +static int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val); +static int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val); +static int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val); +static int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val); +static int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val); +static int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val); +static int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev, + __s32 *val); +static int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev, + __s32 val); +static int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val); +static int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val); +static int ov9650_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val); +static int ov9650_set_auto_exposure(struct gspca_dev *gspca_dev, __s32 val); + /* Vertically and horizontally flips the image if matched, needed for machines where the sensor is mounted upside down */ static const struct dmi_system_id ov9650_flip_dmi_table[] = { { + .ident = "ASUS A6Ja", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "A6J") + } + }, + { + .ident = "ASUS A6JC", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "A6JC") + } + }, + { + .ident = "ASUS A6K", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "A6K") + } + }, + { + .ident = "ASUS A6Kt", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "A6Kt") + } + }, + { + .ident = "ASUS A6VA", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "A6VA") + } + }, + { + .ident = "ASUS A6VC", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), @@ -38,24 +95,10 @@ static } }, { - .ident = "ASUS A6JC", + .ident = "ASUS A7V", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "A6JC") - } - }, - { - .ident = "ASUS A6Ja", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "A6J") - } - }, - { - .ident = "ASUS A6Kt", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "A6Kt") + DMI_MATCH(DMI_PRODUCT_NAME, "A7V") } }, { @@ -68,7 +111,7 @@ static {} }; -const static struct ctrl ov9650_ctrls[] = { +static const struct ctrl ov9650_ctrls[] = { #define EXPOSURE_IDX 0 { { @@ -102,6 +145,7 @@ const static struct ctrl ov9650_ctrls[] = { #define RED_BALANCE_IDX 2 { { + .id = V4L2_CID_RED_BALANCE, .type = V4L2_CTRL_TYPE_INTEGER, .name = "red balance", .minimum = 0x00, @@ -116,6 +160,7 @@ const static struct ctrl ov9650_ctrls[] = { #define BLUE_BALANCE_IDX 3 { { + .id = V4L2_CID_BLUE_BALANCE, .type = V4L2_CTRL_TYPE_INTEGER, .name = "blue balance", .minimum = 0x00, @@ -182,7 +227,22 @@ const static struct ctrl ov9650_ctrls[] = { }, .set = ov9650_set_auto_gain, .get = ov9650_get_auto_gain + }, +#define AUTO_EXPOSURE_IDX 8 + { + { + .id = V4L2_CID_EXPOSURE_AUTO, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "auto exposure", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1 + }, + .set = ov9650_set_auto_exposure, + .get = ov9650_get_auto_exposure } + }; static struct v4l2_pix_format ov9650_modes[] = { @@ -289,12 +349,6 @@ sensor_found: for (i = 0; i < ARRAY_SIZE(ov9650_ctrls); i++) sensor_settings[i] = ov9650_ctrls[i].qctrl.default_value; sd->sensor_priv = sensor_settings; - - if (dmi_check_system(ov9650_flip_dmi_table) && !err) { - info("vflip quirk active"); - sensor_settings[VFLIP_IDX] = 1; - } - return 0; } @@ -316,7 +370,8 @@ int ov9650_init(struct sd *sd) err = m5602_write_bridge(sd, init_ov9650[i][1], data); } - err = ov9650_set_exposure(&sd->gspca_dev, sensor_settings[EXPOSURE_IDX]); + err = ov9650_set_exposure(&sd->gspca_dev, + sensor_settings[EXPOSURE_IDX]); if (err < 0) return err; @@ -324,11 +379,13 @@ int ov9650_init(struct sd *sd) if (err < 0) return err; - err = ov9650_set_red_balance(&sd->gspca_dev, sensor_settings[RED_BALANCE_IDX]); + err = ov9650_set_red_balance(&sd->gspca_dev, + sensor_settings[RED_BALANCE_IDX]); if (err < 0) return err; - err = ov9650_set_blue_balance(&sd->gspca_dev, sensor_settings[BLUE_BALANCE_IDX]); + err = ov9650_set_blue_balance(&sd->gspca_dev, + sensor_settings[BLUE_BALANCE_IDX]); if (err < 0) return err; @@ -340,11 +397,18 @@ int ov9650_init(struct sd *sd) if (err < 0) return err; - err = ov9650_set_auto_white_balance(&sd->gspca_dev, sensor_settings[AUTO_WHITE_BALANCE_IDX]); + err = ov9650_set_auto_exposure(&sd->gspca_dev, + sensor_settings[AUTO_EXPOSURE_IDX]); if (err < 0) return err; - err = ov9650_set_auto_gain(&sd->gspca_dev, sensor_settings[AUTO_GAIN_CTRL_IDX]); + err = ov9650_set_auto_white_balance(&sd->gspca_dev, + sensor_settings[AUTO_WHITE_BALANCE_IDX]); + if (err < 0) + return err; + + err = ov9650_set_auto_gain(&sd->gspca_dev, + sensor_settings[AUTO_GAIN_CTRL_IDX]); return err; } @@ -360,7 +424,10 @@ int ov9650_start(struct sd *sd) int ver_offs = cam->cam_mode[sd->gspca_dev.curr_mode].priv; int hor_offs = OV9650_LEFT_OFFSET; - if (sensor_settings[VFLIP_IDX]) + if ((!dmi_check_system(ov9650_flip_dmi_table) && + sensor_settings[VFLIP_IDX]) || + (dmi_check_system(ov9650_flip_dmi_table) && + !sensor_settings[VFLIP_IDX])) ver_offs--; if (width <= 320) @@ -406,6 +473,14 @@ int ov9650_start(struct sd *sd) if (err < 0) return err; + err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 2); + if (err < 0) + return err; + err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, (hor_offs >> 8) & 0xff); if (err < 0) @@ -425,6 +500,10 @@ int ov9650_start(struct sd *sd) if (err < 0) return err; + err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0); + if (err < 0) + return err; + switch (width) { case 640: PDEBUG(D_V4L2, "Configuring camera for VGA mode"); @@ -467,32 +546,15 @@ int ov9650_stop(struct sd *sd) return m5602_write_sensor(sd, OV9650_COM2, &data, 1); } -int ov9650_power_down(struct sd *sd) -{ - int i, err = 0; - for (i = 0; i < ARRAY_SIZE(power_down_ov9650) && !err; i++) { - u8 data = power_down_ov9650[i][2]; - if (power_down_ov9650[i][0] == SENSOR) - err = m5602_write_sensor(sd, - power_down_ov9650[i][1], &data, 1); - else - err = m5602_write_bridge(sd, power_down_ov9650[i][1], - data); - } - - return err; -} - void ov9650_disconnect(struct sd *sd) { ov9650_stop(sd); - ov9650_power_down(sd); sd->sensor = NULL; kfree(sd->sensor_priv); } -int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) +static int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; s32 *sensor_settings = sd->sensor_priv; @@ -502,7 +564,7 @@ int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) return 0; } -int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val) +static int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; s32 *sensor_settings = sd->sensor_priv; @@ -532,7 +594,7 @@ int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val) return err; } -int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val) +static int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; s32 *sensor_settings = sd->sensor_priv; @@ -542,7 +604,7 @@ int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val) return 0; } -int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val) +static int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val) { int err; u8 i2c_data; @@ -573,7 +635,7 @@ int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val) return err; } -int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val) +static int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; s32 *sensor_settings = sd->sensor_priv; @@ -583,7 +645,7 @@ int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val) return 0; } -int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val) +static int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val) { int err; u8 i2c_data; @@ -599,7 +661,7 @@ int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val) return err; } -int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val) +static int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; s32 *sensor_settings = sd->sensor_priv; @@ -610,7 +672,7 @@ int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val) return 0; } -int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val) +static int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val) { int err; u8 i2c_data; @@ -626,7 +688,7 @@ int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val) return err; } -int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) +static int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; s32 *sensor_settings = sd->sensor_priv; @@ -636,7 +698,7 @@ int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) return 0; } -int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val) +static int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val) { int err; u8 i2c_data; @@ -646,13 +708,20 @@ int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val) PDEBUG(D_V4L2, "Set horizontal flip to %d", val); sensor_settings[HFLIP_IDX] = val; - i2c_data = ((val & 0x01) << 5) | (sensor_settings[VFLIP_IDX] << 4); + + if (!dmi_check_system(ov9650_flip_dmi_table)) + i2c_data = ((val & 0x01) << 5) | + (sensor_settings[VFLIP_IDX] << 4); + else + i2c_data = ((val & 0x01) << 5) | + (!sensor_settings[VFLIP_IDX] << 4); + err = m5602_write_sensor(sd, OV9650_MVFP, &i2c_data, 1); return err; } -int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) +static int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; s32 *sensor_settings = sd->sensor_priv; @@ -663,7 +732,7 @@ int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) return 0; } -int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val) +static int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val) { int err; u8 i2c_data; @@ -673,6 +742,9 @@ int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val) PDEBUG(D_V4L2, "Set vertical flip to %d", val); sensor_settings[VFLIP_IDX] = val; + if (dmi_check_system(ov9650_flip_dmi_table)) + val = !val; + i2c_data = ((val & 0x01) << 4) | (sensor_settings[VFLIP_IDX] << 5); err = m5602_write_sensor(sd, OV9650_MVFP, &i2c_data, 1); if (err < 0) @@ -685,48 +757,38 @@ int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val) return err; } -int ov9650_get_brightness(struct gspca_dev *gspca_dev, __s32 *val) +static int ov9650_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; s32 *sensor_settings = sd->sensor_priv; - *val = sensor_settings[GAIN_IDX]; - PDEBUG(D_V4L2, "Read gain %d", *val); - + *val = sensor_settings[AUTO_EXPOSURE_IDX]; + PDEBUG(D_V4L2, "Read auto exposure control %d", *val); return 0; } -int ov9650_set_brightness(struct gspca_dev *gspca_dev, __s32 val) +static int ov9650_set_auto_exposure(struct gspca_dev *gspca_dev, + __s32 val) { int err; u8 i2c_data; struct sd *sd = (struct sd *) gspca_dev; s32 *sensor_settings = sd->sensor_priv; - PDEBUG(D_V4L2, "Set gain to %d", val); + PDEBUG(D_V4L2, "Set auto exposure control to %d", val); - sensor_settings[GAIN_IDX] = val; - - /* Read the OV9650_VREF register first to avoid - corrupting the VREF high and low bits */ - err = m5602_read_sensor(sd, OV9650_VREF, &i2c_data, 1); + sensor_settings[AUTO_EXPOSURE_IDX] = val; + err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1); if (err < 0) return err; - /* Mask away all uninteresting bits */ - i2c_data = ((val & 0x0300) >> 2) | (i2c_data & 0x3F); - err = m5602_write_sensor(sd, OV9650_VREF, &i2c_data, 1); - if (err < 0) - return err; + i2c_data = ((i2c_data & 0xfe) | ((val & 0x01) << 0)); - /* The 8 LSBs */ - i2c_data = val & 0xff; - err = m5602_write_sensor(sd, OV9650_GAIN, &i2c_data, 1); - - return err; + return m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1); } -int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev, __s32 *val) +static int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev, + __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; s32 *sensor_settings = sd->sensor_priv; @@ -735,7 +797,8 @@ int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev, __s32 *val) return 0; } -int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev, __s32 val) +static int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev, + __s32 val) { int err; u8 i2c_data; @@ -755,7 +818,7 @@ int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev, __s32 val) return err; } -int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val) +static int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; s32 *sensor_settings = sd->sensor_priv; @@ -765,7 +828,7 @@ int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val) return 0; } -int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val) +static int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val) { int err; u8 i2c_data; @@ -780,9 +843,8 @@ int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val) return err; i2c_data = ((i2c_data & 0xfb) | ((val & 0x01) << 2)); - err = m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1); - return err; + return m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1); } static void ov9650_dump_registers(struct sd *sd) diff --git a/drivers/media/video/gspca/m5602/m5602_ov9650.h b/drivers/media/video/gspca/m5602/m5602_ov9650.h index fcc54e4c0f4f..c98c40d69e05 100644 --- a/drivers/media/video/gspca/m5602/m5602_ov9650.h +++ b/drivers/media/video/gspca/m5602/m5602_ov9650.h @@ -120,6 +120,10 @@ #define OV9650_SOFT_SLEEP (1 << 4) #define OV9650_OUTPUT_DRIVE_2X (1 << 0) +#define OV9650_DENOISE_ENABLE (1 << 5) +#define OV9650_WHITE_PIXEL_ENABLE (1 << 1) +#define OV9650_WHITE_PIXEL_OPTION (1 << 0) + #define OV9650_LEFT_OFFSET 0x62 #define GAIN_DEFAULT 0x14 @@ -137,29 +141,9 @@ int ov9650_probe(struct sd *sd); int ov9650_init(struct sd *sd); int ov9650_start(struct sd *sd); int ov9650_stop(struct sd *sd); -int ov9650_power_down(struct sd *sd); void ov9650_disconnect(struct sd *sd); -int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val); -int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val); -int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val); -int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val); -int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val); -int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val); -int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val); -int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val); -int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val); -int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val); -int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val); -int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val); -int ov9650_get_brightness(struct gspca_dev *gspca_dev, __s32 *val); -int ov9650_set_brightness(struct gspca_dev *gspca_dev, __s32 val); -int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev, __s32 *val); -int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev, __s32 val); -int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val); -int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val); - -const static struct m5602_sensor ov9650 = { +static const struct m5602_sensor ov9650 = { .name = "OV9650", .i2c_slave_id = 0x60, .i2c_regW = 1, @@ -167,7 +151,6 @@ const static struct m5602_sensor ov9650 = { .init = ov9650_init, .start = ov9650_start, .stop = ov9650_stop, - .power_down = ov9650_power_down, .disconnect = ov9650_disconnect, }; @@ -219,7 +202,7 @@ static const unsigned char init_ov9650[][3] = /* Reset chip */ {SENSOR, OV9650_COM7, OV9650_REGISTER_RESET}, /* One extra reset is needed in order to make the sensor behave - properly when resuming from ram */ + properly when resuming from ram, could be a timing issue */ {SENSOR, OV9650_COM7, OV9650_REGISTER_RESET}, /* Enable double clock */ @@ -229,8 +212,7 @@ static const unsigned char init_ov9650[][3] = /* Set fast AGC/AEC algorithm with unlimited step size */ {SENSOR, OV9650_COM8, OV9650_FAST_AGC_AEC | - OV9650_AEC_UNLIM_STEP_SIZE | - OV9650_AWB_EN | OV9650_AGC_EN}, + OV9650_AEC_UNLIM_STEP_SIZE}, {SENSOR, OV9650_CHLF, 0x10}, {SENSOR, OV9650_ARBLM, 0xbf}, @@ -301,8 +283,11 @@ static const unsigned char init_ov9650[][3] = {SENSOR, OV9650_VREF, 0x10}, {SENSOR, OV9650_ADC, 0x04}, {SENSOR, OV9650_HV, 0x40}, + /* Enable denoise, and white-pixel erase */ - {SENSOR, OV9650_COM22, 0x23}, + {SENSOR, OV9650_COM22, OV9650_DENOISE_ENABLE | + OV9650_WHITE_PIXEL_ENABLE | + OV9650_WHITE_PIXEL_OPTION}, /* Enable VARIOPIXEL */ {SENSOR, OV9650_COM3, OV9650_VARIOPIXEL}, @@ -312,26 +297,6 @@ static const unsigned char init_ov9650[][3] = {SENSOR, OV9650_COM2, OV9650_SOFT_SLEEP | OV9650_OUTPUT_DRIVE_2X}, }; -static const unsigned char power_down_ov9650[][3] = -{ - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, - {SENSOR, OV9650_COM7, 0x80}, - {SENSOR, OV9650_OFON, 0xf4}, - {SENSOR, OV9650_MVFP, 0x80}, - {SENSOR, OV9650_DBLV, 0x3f}, - {SENSOR, OV9650_RSVD36, 0x49}, - {SENSOR, OV9650_COM7, 0x05}, - - {BRIDGE, M5602_XB_GPIO_DIR, 0x05}, - {BRIDGE, M5602_XB_GPIO_DAT, 0x04}, - {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, - {BRIDGE, M5602_XB_GPIO_EN_L, 0x06}, - {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, -}; - static const unsigned char res_init_ov9650[][3] = { {SENSOR, OV9650_COM2, OV9650_OUTPUT_DRIVE_2X}, diff --git a/drivers/media/video/gspca/m5602/m5602_po1030.c b/drivers/media/video/gspca/m5602/m5602_po1030.c index eaddf488bad1..8d74d8065b79 100644 --- a/drivers/media/video/gspca/m5602/m5602_po1030.c +++ b/drivers/media/video/gspca/m5602/m5602_po1030.c @@ -18,6 +18,29 @@ #include "m5602_po1030.h" +static int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val); +static int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val); +static int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val); +static int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val); +static int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val); +static int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val); +static int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val); +static int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val); +static int po1030_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val); +static int po1030_set_green_balance(struct gspca_dev *gspca_dev, __s32 val); +static int po1030_get_hflip(struct gspca_dev *gspca_dev, __s32 *val); +static int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val); +static int po1030_get_vflip(struct gspca_dev *gspca_dev, __s32 *val); +static int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val); +static int po1030_set_auto_white_balance(struct gspca_dev *gspca_dev, + __s32 val); +static int po1030_get_auto_white_balance(struct gspca_dev *gspca_dev, + __s32 *val); +static int po1030_set_auto_exposure(struct gspca_dev *gspca_dev, + __s32 val); +static int po1030_get_auto_exposure(struct gspca_dev *gspca_dev, + __s32 *val); + static struct v4l2_pix_format po1030_modes[] = { { 640, @@ -27,11 +50,12 @@ static struct v4l2_pix_format po1030_modes[] = { .sizeimage = 640 * 480, .bytesperline = 640, .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 0 + .priv = 2 } }; -const static struct ctrl po1030_ctrls[] = { +static const struct ctrl po1030_ctrls[] = { +#define GAIN_IDX 0 { { .id = V4L2_CID_GAIN, @@ -45,7 +69,9 @@ const static struct ctrl po1030_ctrls[] = { }, .set = po1030_set_gain, .get = po1030_get_gain - }, { + }, +#define EXPOSURE_IDX 1 + { { .id = V4L2_CID_EXPOSURE, .type = V4L2_CTRL_TYPE_INTEGER, @@ -58,7 +84,9 @@ const static struct ctrl po1030_ctrls[] = { }, .set = po1030_set_exposure, .get = po1030_get_exposure - }, { + }, +#define RED_BALANCE_IDX 2 + { { .id = V4L2_CID_RED_BALANCE, .type = V4L2_CTRL_TYPE_INTEGER, @@ -71,7 +99,9 @@ const static struct ctrl po1030_ctrls[] = { }, .set = po1030_set_red_balance, .get = po1030_get_red_balance - }, { + }, +#define BLUE_BALANCE_IDX 3 + { { .id = V4L2_CID_BLUE_BALANCE, .type = V4L2_CTRL_TYPE_INTEGER, @@ -84,7 +114,9 @@ const static struct ctrl po1030_ctrls[] = { }, .set = po1030_set_blue_balance, .get = po1030_get_blue_balance - }, { + }, +#define HFLIP_IDX 4 + { { .id = V4L2_CID_HFLIP, .type = V4L2_CTRL_TYPE_BOOLEAN, @@ -96,7 +128,9 @@ const static struct ctrl po1030_ctrls[] = { }, .set = po1030_set_hflip, .get = po1030_get_hflip - }, { + }, +#define VFLIP_IDX 5 + { { .id = V4L2_CID_VFLIP, .type = V4L2_CTRL_TYPE_BOOLEAN, @@ -108,14 +142,58 @@ const static struct ctrl po1030_ctrls[] = { }, .set = po1030_set_vflip, .get = po1030_get_vflip - } + }, +#define AUTO_WHITE_BALANCE_IDX 6 + { + { + .id = V4L2_CID_AUTO_WHITE_BALANCE, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "auto white balance", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + .set = po1030_set_auto_white_balance, + .get = po1030_get_auto_white_balance + }, +#define AUTO_EXPOSURE_IDX 7 + { + { + .id = V4L2_CID_EXPOSURE_AUTO, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "auto exposure", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + .set = po1030_set_auto_exposure, + .get = po1030_get_auto_exposure + }, +#define GREEN_BALANCE_IDX 8 + { + { + .id = M5602_V4L2_CID_GREEN_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "green balance", + .minimum = 0x00, + .maximum = 0xff, + .step = 0x1, + .default_value = PO1030_GREEN_GAIN_DEFAULT, + .flags = V4L2_CTRL_FLAG_SLIDER + }, + .set = po1030_set_green_balance, + .get = po1030_get_green_balance + }, }; static void po1030_dump_registers(struct sd *sd); int po1030_probe(struct sd *sd) { - u8 prod_id = 0, ver_id = 0, i; + u8 dev_id_h = 0, i; + s32 *sensor_settings; if (force_sensor) { if (force_sensor == PO1030_SENSOR) { @@ -139,28 +217,36 @@ int po1030_probe(struct sd *sd) m5602_write_bridge(sd, preinit_po1030[i][1], data); } - if (m5602_read_sensor(sd, 0x3, &prod_id, 1)) + if (m5602_read_sensor(sd, PO1030_DEVID_H, &dev_id_h, 1)) return -ENODEV; - if (m5602_read_sensor(sd, 0x4, &ver_id, 1)) - return -ENODEV; - - if ((prod_id == 0x02) && (ver_id == 0xef)) { + if (dev_id_h == 0x30) { info("Detected a po1030 sensor"); goto sensor_found; } return -ENODEV; sensor_found: + sensor_settings = kmalloc( + ARRAY_SIZE(po1030_ctrls) * sizeof(s32), GFP_KERNEL); + if (!sensor_settings) + return -ENOMEM; + sd->gspca_dev.cam.cam_mode = po1030_modes; sd->gspca_dev.cam.nmodes = ARRAY_SIZE(po1030_modes); sd->desc->ctrls = po1030_ctrls; sd->desc->nctrls = ARRAY_SIZE(po1030_ctrls); + + for (i = 0; i < ARRAY_SIZE(po1030_ctrls); i++) + sensor_settings[i] = po1030_ctrls[i].qctrl.default_value; + sd->sensor_priv = sensor_settings; + return 0; } int po1030_init(struct sd *sd) { + s32 *sensor_settings = sd->sensor_priv; int i, err = 0; /* Init the sensor */ @@ -185,47 +271,206 @@ int po1030_init(struct sd *sd) return -EINVAL; } } + if (err < 0) + return err; if (dump_sensor) po1030_dump_registers(sd); - return err; -} - -int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 i2c_data; - int err; - - err = m5602_read_sensor(sd, PO1030_REG_INTEGLINES_H, - &i2c_data, 1); + err = po1030_set_exposure(&sd->gspca_dev, + sensor_settings[EXPOSURE_IDX]); if (err < 0) return err; - *val = (i2c_data << 8); - err = m5602_read_sensor(sd, PO1030_REG_INTEGLINES_M, - &i2c_data, 1); - *val |= i2c_data; + err = po1030_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]); + if (err < 0) + return err; - PDEBUG(D_V4L2, "Exposure read as %d", *val); + err = po1030_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]); + if (err < 0) + return err; + err = po1030_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]); + if (err < 0) + return err; + + err = po1030_set_red_balance(&sd->gspca_dev, + sensor_settings[RED_BALANCE_IDX]); + if (err < 0) + return err; + + err = po1030_set_blue_balance(&sd->gspca_dev, + sensor_settings[BLUE_BALANCE_IDX]); + if (err < 0) + return err; + + err = po1030_set_green_balance(&sd->gspca_dev, + sensor_settings[GREEN_BALANCE_IDX]); + if (err < 0) + return err; + + err = po1030_set_auto_white_balance(&sd->gspca_dev, + sensor_settings[AUTO_WHITE_BALANCE_IDX]); + if (err < 0) + return err; + + err = po1030_set_auto_exposure(&sd->gspca_dev, + sensor_settings[AUTO_EXPOSURE_IDX]); return err; } -int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val) +int po1030_start(struct sd *sd) +{ + struct cam *cam = &sd->gspca_dev.cam; + int i, err = 0; + int width = cam->cam_mode[sd->gspca_dev.curr_mode].width; + int height = cam->cam_mode[sd->gspca_dev.curr_mode].height; + int ver_offs = cam->cam_mode[sd->gspca_dev.curr_mode].priv; + u8 data; + + switch (width) { + case 320: + data = PO1030_SUBSAMPLING; + err = m5602_write_sensor(sd, PO1030_CONTROL3, &data, 1); + if (err < 0) + return err; + + data = ((width + 3) >> 8) & 0xff; + err = m5602_write_sensor(sd, PO1030_WINDOWWIDTH_H, &data, 1); + if (err < 0) + return err; + + data = (width + 3) & 0xff; + err = m5602_write_sensor(sd, PO1030_WINDOWWIDTH_L, &data, 1); + if (err < 0) + return err; + + data = ((height + 1) >> 8) & 0xff; + err = m5602_write_sensor(sd, PO1030_WINDOWHEIGHT_H, &data, 1); + if (err < 0) + return err; + + data = (height + 1) & 0xff; + err = m5602_write_sensor(sd, PO1030_WINDOWHEIGHT_L, &data, 1); + + height += 6; + width -= 1; + break; + + case 640: + data = 0; + err = m5602_write_sensor(sd, PO1030_CONTROL3, &data, 1); + if (err < 0) + return err; + + data = ((width + 7) >> 8) & 0xff; + err = m5602_write_sensor(sd, PO1030_WINDOWWIDTH_H, &data, 1); + if (err < 0) + return err; + + data = (width + 7) & 0xff; + err = m5602_write_sensor(sd, PO1030_WINDOWWIDTH_L, &data, 1); + if (err < 0) + return err; + + data = ((height + 3) >> 8) & 0xff; + err = m5602_write_sensor(sd, PO1030_WINDOWHEIGHT_H, &data, 1); + if (err < 0) + return err; + + data = (height + 3) & 0xff; + err = m5602_write_sensor(sd, PO1030_WINDOWHEIGHT_L, &data, 1); + + height += 12; + width -= 2; + break; + } + err = m5602_write_bridge(sd, M5602_XB_SENSOR_TYPE, 0x0c); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_LINE_OF_FRAME_H, 0x81); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_PIX_OF_LINE_H, 0x82); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0x01); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, + ((ver_offs >> 8) & 0xff)); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (ver_offs & 0xff)); + if (err < 0) + return err; + + for (i = 0; i < 2 && !err; i++) + err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height >> 8) & 0xff); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height & 0xff)); + if (err < 0) + return err; + + for (i = 0; i < 2 && !err; i++) + err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0); + + for (i = 0; i < 2 && !err; i++) + err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0); + + for (i = 0; i < 2 && !err; i++) + err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, 0); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, (width >> 8) & 0xff); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, (width & 0xff)); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0); + return err; +} + +static int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[EXPOSURE_IDX]; + PDEBUG(D_V4L2, "Exposure read as %d", *val); + return 0; +} + +static int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; u8 i2c_data; int err; + sensor_settings[EXPOSURE_IDX] = val; PDEBUG(D_V4L2, "Set exposure to %d", val & 0xffff); i2c_data = ((val & 0xff00) >> 8); PDEBUG(D_V4L2, "Set exposure to high byte to 0x%x", i2c_data); - err = m5602_write_sensor(sd, PO1030_REG_INTEGLINES_H, + err = m5602_write_sensor(sd, PO1030_INTEGLINES_H, &i2c_data, 1); if (err < 0) return err; @@ -233,167 +478,256 @@ int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val) i2c_data = (val & 0xff); PDEBUG(D_V4L2, "Set exposure to low byte to 0x%x", i2c_data); - err = m5602_write_sensor(sd, PO1030_REG_INTEGLINES_M, + err = m5602_write_sensor(sd, PO1030_INTEGLINES_M, &i2c_data, 1); return err; } -int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val) +static int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[GAIN_IDX]; + PDEBUG(D_V4L2, "Read global gain %d", *val); + return 0; +} + +static int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; u8 i2c_data; int err; - err = m5602_read_sensor(sd, PO1030_REG_GLOBALGAIN, - &i2c_data, 1); - *val = i2c_data; - PDEBUG(D_V4L2, "Read global gain %d", *val); + sensor_settings[GAIN_IDX] = val; + i2c_data = val & 0xff; + PDEBUG(D_V4L2, "Set global gain to %d", i2c_data); + err = m5602_write_sensor(sd, PO1030_GLOBALGAIN, + &i2c_data, 1); return err; } -int po1030_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) +static int po1030_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; - u8 i2c_data; - int err; - - err = m5602_read_sensor(sd, PO1030_REG_CONTROL2, - &i2c_data, 1); - - *val = (i2c_data >> 7) & 0x01 ; + s32 *sensor_settings = sd->sensor_priv; + *val = sensor_settings[HFLIP_IDX]; PDEBUG(D_V4L2, "Read hflip %d", *val); - return err; + return 0; } -int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val) +static int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; u8 i2c_data; int err; + sensor_settings[HFLIP_IDX] = val; + PDEBUG(D_V4L2, "Set hflip %d", val); - err = m5602_read_sensor(sd, PO1030_REG_CONTROL2, &i2c_data, 1); + err = m5602_read_sensor(sd, PO1030_CONTROL2, &i2c_data, 1); if (err < 0) return err; i2c_data = (0x7f & i2c_data) | ((val & 0x01) << 7); - err = m5602_write_sensor(sd, PO1030_REG_CONTROL2, + err = m5602_write_sensor(sd, PO1030_CONTROL2, &i2c_data, 1); return err; } -int po1030_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) +static int po1030_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; - u8 i2c_data; - int err; - - err = m5602_read_sensor(sd, PO1030_REG_GLOBALGAIN, - &i2c_data, 1); - - *val = (i2c_data >> 6) & 0x01; + s32 *sensor_settings = sd->sensor_priv; + *val = sensor_settings[VFLIP_IDX]; PDEBUG(D_V4L2, "Read vflip %d", *val); - return err; + return 0; } -int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val) +static int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; u8 i2c_data; int err; + sensor_settings[VFLIP_IDX] = val; + PDEBUG(D_V4L2, "Set vflip %d", val); - err = m5602_read_sensor(sd, PO1030_REG_CONTROL2, &i2c_data, 1); + err = m5602_read_sensor(sd, PO1030_CONTROL2, &i2c_data, 1); if (err < 0) return err; i2c_data = (i2c_data & 0xbf) | ((val & 0x01) << 6); - err = m5602_write_sensor(sd, PO1030_REG_CONTROL2, + err = m5602_write_sensor(sd, PO1030_CONTROL2, &i2c_data, 1); return err; } -int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val) +static int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; - u8 i2c_data; - int err; + s32 *sensor_settings = sd->sensor_priv; - i2c_data = val & 0xff; - PDEBUG(D_V4L2, "Set global gain to %d", i2c_data); - err = m5602_write_sensor(sd, PO1030_REG_GLOBALGAIN, - &i2c_data, 1); - return err; -} - -int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 i2c_data; - int err; - - err = m5602_read_sensor(sd, PO1030_REG_RED_GAIN, - &i2c_data, 1); - *val = i2c_data; + *val = sensor_settings[RED_BALANCE_IDX]; PDEBUG(D_V4L2, "Read red gain %d", *val); - return err; + return 0; } -int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val) +static int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; u8 i2c_data; int err; + sensor_settings[RED_BALANCE_IDX] = val; + i2c_data = val & 0xff; PDEBUG(D_V4L2, "Set red gain to %d", i2c_data); - err = m5602_write_sensor(sd, PO1030_REG_RED_GAIN, + err = m5602_write_sensor(sd, PO1030_RED_GAIN, &i2c_data, 1); return err; } -int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val) +static int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; - u8 i2c_data; - int err; + s32 *sensor_settings = sd->sensor_priv; - err = m5602_read_sensor(sd, PO1030_REG_BLUE_GAIN, - &i2c_data, 1); - *val = i2c_data; + *val = sensor_settings[BLUE_BALANCE_IDX]; PDEBUG(D_V4L2, "Read blue gain %d", *val); - return err; + return 0; } -int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val) +static int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; u8 i2c_data; int err; + + sensor_settings[BLUE_BALANCE_IDX] = val; + i2c_data = val & 0xff; PDEBUG(D_V4L2, "Set blue gain to %d", i2c_data); - err = m5602_write_sensor(sd, PO1030_REG_BLUE_GAIN, + err = m5602_write_sensor(sd, PO1030_BLUE_GAIN, &i2c_data, 1); return err; } -int po1030_power_down(struct sd *sd) +static int po1030_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val) { + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[GREEN_BALANCE_IDX]; + PDEBUG(D_V4L2, "Read green gain %d", *val); + return 0; } +static int po1030_set_green_balance(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + u8 i2c_data; + int err; + + sensor_settings[GREEN_BALANCE_IDX] = val; + i2c_data = val & 0xff; + PDEBUG(D_V4L2, "Set green gain to %d", i2c_data); + + err = m5602_write_sensor(sd, PO1030_GREEN_1_GAIN, + &i2c_data, 1); + if (err < 0) + return err; + + return m5602_write_sensor(sd, PO1030_GREEN_2_GAIN, + &i2c_data, 1); +} + +static int po1030_get_auto_white_balance(struct gspca_dev *gspca_dev, + __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[AUTO_WHITE_BALANCE_IDX]; + PDEBUG(D_V4L2, "Auto white balancing is %d", *val); + + return 0; +} + +static int po1030_set_auto_white_balance(struct gspca_dev *gspca_dev, + __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + u8 i2c_data; + int err; + + sensor_settings[AUTO_WHITE_BALANCE_IDX] = val; + + err = m5602_read_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1); + if (err < 0) + return err; + + PDEBUG(D_V4L2, "Set auto white balance to %d", val); + i2c_data = (i2c_data & 0xfe) | (val & 0x01); + err = m5602_write_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1); + return err; +} + +static int po1030_get_auto_exposure(struct gspca_dev *gspca_dev, + __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[AUTO_EXPOSURE_IDX]; + PDEBUG(D_V4L2, "Auto exposure is %d", *val); + return 0; +} + +static int po1030_set_auto_exposure(struct gspca_dev *gspca_dev, + __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + u8 i2c_data; + int err; + + sensor_settings[AUTO_EXPOSURE_IDX] = val; + err = m5602_read_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1); + if (err < 0) + return err; + + PDEBUG(D_V4L2, "Set auto exposure to %d", val); + i2c_data = (i2c_data & 0xfd) | ((val & 0x01) << 1); + return m5602_write_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1); +} + +void po1030_disconnect(struct sd *sd) +{ + sd->sensor = NULL; + kfree(sd->sensor_priv); +} + static void po1030_dump_registers(struct sd *sd) { int address; diff --git a/drivers/media/video/gspca/m5602/m5602_po1030.h b/drivers/media/video/gspca/m5602/m5602_po1030.h index c10b12335818..1ea380b2bbe7 100644 --- a/drivers/media/video/gspca/m5602/m5602_po1030.h +++ b/drivers/media/video/gspca/m5602/m5602_po1030.h @@ -25,98 +25,123 @@ /*****************************************************************************/ -#define PO1030_REG_DEVID_H 0x00 -#define PO1030_REG_DEVID_L 0x01 -#define PO1030_REG_FRAMEWIDTH_H 0x04 -#define PO1030_REG_FRAMEWIDTH_L 0x05 -#define PO1030_REG_FRAMEHEIGHT_H 0x06 -#define PO1030_REG_FRAMEHEIGHT_L 0x07 -#define PO1030_REG_WINDOWX_H 0x08 -#define PO1030_REG_WINDOWX_L 0x09 -#define PO1030_REG_WINDOWY_H 0x0a -#define PO1030_REG_WINDOWY_L 0x0b -#define PO1030_REG_WINDOWWIDTH_H 0x0c -#define PO1030_REG_WINDOWWIDTH_L 0x0d -#define PO1030_REG_WINDOWHEIGHT_H 0x0e -#define PO1030_REG_WINDOWHEIGHT_L 0x0f +#define PO1030_DEVID_H 0x00 +#define PO1030_DEVID_L 0x01 +#define PO1030_FRAMEWIDTH_H 0x04 +#define PO1030_FRAMEWIDTH_L 0x05 +#define PO1030_FRAMEHEIGHT_H 0x06 +#define PO1030_FRAMEHEIGHT_L 0x07 +#define PO1030_WINDOWX_H 0x08 +#define PO1030_WINDOWX_L 0x09 +#define PO1030_WINDOWY_H 0x0a +#define PO1030_WINDOWY_L 0x0b +#define PO1030_WINDOWWIDTH_H 0x0c +#define PO1030_WINDOWWIDTH_L 0x0d +#define PO1030_WINDOWHEIGHT_H 0x0e +#define PO1030_WINDOWHEIGHT_L 0x0f -#define PO1030_REG_GLOBALIBIAS 0x12 -#define PO1030_REG_PIXELIBIAS 0x13 +#define PO1030_GLOBALIBIAS 0x12 +#define PO1030_PIXELIBIAS 0x13 -#define PO1030_REG_GLOBALGAIN 0x15 -#define PO1030_REG_RED_GAIN 0x16 -#define PO1030_REG_GREEN_1_GAIN 0x17 -#define PO1030_REG_BLUE_GAIN 0x18 -#define PO1030_REG_GREEN_2_GAIN 0x19 +#define PO1030_GLOBALGAIN 0x15 +#define PO1030_RED_GAIN 0x16 +#define PO1030_GREEN_1_GAIN 0x17 +#define PO1030_BLUE_GAIN 0x18 +#define PO1030_GREEN_2_GAIN 0x19 -#define PO1030_REG_INTEGLINES_H 0x1a -#define PO1030_REG_INTEGLINES_M 0x1b -#define PO1030_REG_INTEGLINES_L 0x1c +#define PO1030_INTEGLINES_H 0x1a +#define PO1030_INTEGLINES_M 0x1b +#define PO1030_INTEGLINES_L 0x1c -#define PO1030_REG_CONTROL1 0x1d -#define PO1030_REG_CONTROL2 0x1e -#define PO1030_REG_CONTROL3 0x1f -#define PO1030_REG_CONTROL4 0x20 +#define PO1030_CONTROL1 0x1d +#define PO1030_CONTROL2 0x1e +#define PO1030_CONTROL3 0x1f +#define PO1030_CONTROL4 0x20 -#define PO1030_REG_PERIOD50_H 0x23 -#define PO1030_REG_PERIOD50_L 0x24 -#define PO1030_REG_PERIOD60_H 0x25 -#define PO1030_REG_PERIOD60_L 0x26 -#define PO1030_REG_REGCLK167 0x27 -#define PO1030_REG_DELTA50 0x28 -#define PO1030_REG_DELTA60 0x29 +#define PO1030_PERIOD50_H 0x23 +#define PO1030_PERIOD50_L 0x24 +#define PO1030_PERIOD60_H 0x25 +#define PO1030_PERIOD60_L 0x26 +#define PO1030_REGCLK167 0x27 +#define PO1030_FLICKER_DELTA50 0x28 +#define PO1030_FLICKERDELTA60 0x29 -#define PO1030_REG_ADCOFFSET 0x2c +#define PO1030_ADCOFFSET 0x2c /* Gamma Correction Coeffs */ -#define PO1030_REG_GC0 0x2d -#define PO1030_REG_GC1 0x2e -#define PO1030_REG_GC2 0x2f -#define PO1030_REG_GC3 0x30 -#define PO1030_REG_GC4 0x31 -#define PO1030_REG_GC5 0x32 -#define PO1030_REG_GC6 0x33 -#define PO1030_REG_GC7 0x34 +#define PO1030_GC0 0x2d +#define PO1030_GC1 0x2e +#define PO1030_GC2 0x2f +#define PO1030_GC3 0x30 +#define PO1030_GC4 0x31 +#define PO1030_GC5 0x32 +#define PO1030_GC6 0x33 +#define PO1030_GC7 0x34 /* Color Transform Matrix */ -#define PO1030_REG_CT0 0x35 -#define PO1030_REG_CT1 0x36 -#define PO1030_REG_CT2 0x37 -#define PO1030_REG_CT3 0x38 -#define PO1030_REG_CT4 0x39 -#define PO1030_REG_CT5 0x3a -#define PO1030_REG_CT6 0x3b -#define PO1030_REG_CT7 0x3c -#define PO1030_REG_CT8 0x3d +#define PO1030_CT0 0x35 +#define PO1030_CT1 0x36 +#define PO1030_CT2 0x37 +#define PO1030_CT3 0x38 +#define PO1030_CT4 0x39 +#define PO1030_CT5 0x3a +#define PO1030_CT6 0x3b +#define PO1030_CT7 0x3c +#define PO1030_CT8 0x3d -#define PO1030_REG_AUTOCTRL1 0x3e -#define PO1030_REG_AUTOCTRL2 0x3f +#define PO1030_AUTOCTRL1 0x3e +#define PO1030_AUTOCTRL2 0x3f -#define PO1030_REG_YTARGET 0x40 -#define PO1030_REG_GLOBALGAINMIN 0x41 -#define PO1030_REG_GLOBALGAINMAX 0x42 +#define PO1030_YTARGET 0x40 +#define PO1030_GLOBALGAINMIN 0x41 +#define PO1030_GLOBALGAINMAX 0x42 + +#define PO1030_AWB_RED_TUNING 0x47 +#define PO1030_AWB_BLUE_TUNING 0x48 /* Output format control */ -#define PO1030_REG_OUTFORMCTRL1 0x5a -#define PO1030_REG_OUTFORMCTRL2 0x5b -#define PO1030_REG_OUTFORMCTRL3 0x5c -#define PO1030_REG_OUTFORMCTRL4 0x5d -#define PO1030_REG_OUTFORMCTRL5 0x5e +#define PO1030_OUTFORMCTRL1 0x5a +#define PO1030_OUTFORMCTRL2 0x5b +#define PO1030_OUTFORMCTRL3 0x5c +#define PO1030_OUTFORMCTRL4 0x5d +#define PO1030_OUTFORMCTRL5 0x5e -/* Imaging coefficients */ -#define PO1030_REG_YBRIGHT 0x73 -#define PO1030_REG_YCONTRAST 0x74 -#define PO1030_REG_YSATURATION 0x75 +#define PO1030_EDGE_ENH_OFF 0x5f +#define PO1030_EGA 0x60 -#define PO1030_HFLIP (1 << 7) -#define PO1030_VFLIP (1 << 6) +#define PO1030_Cb_U_GAIN 0x63 +#define PO1030_Cr_V_GAIN 0x64 + +#define PO1030_YCONTRAST 0x74 +#define PO1030_YSATURATION 0x75 + +#define PO1030_HFLIP (1 << 7) +#define PO1030_VFLIP (1 << 6) + +#define PO1030_HREF_ENABLE (1 << 6) + +#define PO1030_RAW_RGB_BAYER 0x4 + +#define PO1030_FRAME_EQUAL (1 << 3) +#define PO1030_AUTO_SUBSAMPLING (1 << 4) + +#define PO1030_WEIGHT_WIN_2X (1 << 3) + +#define PO1030_SHUTTER_MODE (1 << 6) +#define PO1030_AUTO_SUBSAMPLING (1 << 4) +#define PO1030_FRAME_EQUAL (1 << 3) + +#define PO1030_SENSOR_RESET (1 << 5) + +#define PO1030_SUBSAMPLING (1 << 6) /*****************************************************************************/ #define PO1030_GLOBAL_GAIN_DEFAULT 0x12 #define PO1030_EXPOSURE_DEFAULT 0x0085 -#define PO1030_BLUE_GAIN_DEFAULT 0x40 -#define PO1030_RED_GAIN_DEFAULT 0x40 +#define PO1030_BLUE_GAIN_DEFAULT 0x36 +#define PO1030_RED_GAIN_DEFAULT 0x36 +#define PO1030_GREEN_GAIN_DEFAULT 0x40 /*****************************************************************************/ @@ -126,20 +151,8 @@ extern int dump_sensor; int po1030_probe(struct sd *sd); int po1030_init(struct sd *sd); -int po1030_power_down(struct sd *sd); - -int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val); -int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val); -int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val); -int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val); -int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val); -int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val); -int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val); -int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val); -int po1030_get_hflip(struct gspca_dev *gspca_dev, __s32 *val); -int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val); -int po1030_get_vflip(struct gspca_dev *gspca_dev, __s32 *val); -int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val); +int po1030_start(struct sd *sd); +void po1030_disconnect(struct sd *sd); static const struct m5602_sensor po1030 = { .name = "PO1030", @@ -149,7 +162,8 @@ static const struct m5602_sensor po1030 = { .probe = po1030_probe, .init = po1030_init, - .power_down = po1030_power_down, + .start = po1030_start, + .disconnect = po1030_disconnect, }; static const unsigned char preinit_po1030[][3] = @@ -159,248 +173,103 @@ static const unsigned char preinit_po1030[][3] = {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, - {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d}, {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00}, - {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c}, - - {SENSOR, PO1030_REG_AUTOCTRL2, 0x24}, - + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, {BRIDGE, M5602_XB_GPIO_DIR, 0x05}, {BRIDGE, M5602_XB_GPIO_DAT, 0x04}, {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06}, {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, - {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, - {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c}, - {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81}, - {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82}, - {BRIDGE, M5602_XB_SIG_INI, 0x01}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x02}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x01}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0xec}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x02}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x02}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x87}, - {BRIDGE, M5602_XB_SIG_INI, 0x00}, - {SENSOR, PO1030_REG_AUTOCTRL2, 0x24}, + {SENSOR, PO1030_AUTOCTRL2, PO1030_SENSOR_RESET | (1 << 2)}, - {BRIDGE, M5602_XB_GPIO_DIR, 0x05}, - {BRIDGE, M5602_XB_GPIO_DAT, 0x04}, - {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, - {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06}, - {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02}, {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04}, {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, - {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c}, {BRIDGE, M5602_XB_GPIO_DIR, 0x05}, {BRIDGE, M5602_XB_GPIO_DAT, 0x00} }; -static const unsigned char init_po1030[][4] = +static const unsigned char init_po1030[][3] = { {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02}, {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0}, - /*sequence 1*/ {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, - {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d}, - {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00}, - {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c}, - /*end of sequence 1*/ - /*sequence 2 (same as stop sequence)*/ - {SENSOR, PO1030_REG_AUTOCTRL2, 0x24}, - {BRIDGE, M5602_XB_GPIO_DIR, 0x05}, - {BRIDGE, M5602_XB_GPIO_DAT, 0x04}, - {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, - {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06}, - {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02}, - - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, - /*end of sequence 2*/ - - /*sequence 5*/ - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, - {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, - {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c}, - {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81}, - {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82}, - {BRIDGE, M5602_XB_SIG_INI, 0x01}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x02}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x01}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0xec}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x02}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x02}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x87}, - {BRIDGE, M5602_XB_SIG_INI, 0x00}, - /*end of sequence 5*/ - - /*sequence 2 stop */ - {SENSOR, PO1030_REG_AUTOCTRL2, 0x24}, + {SENSOR, PO1030_AUTOCTRL2, PO1030_SENSOR_RESET | (1 << 2)}, {BRIDGE, M5602_XB_GPIO_DIR, 0x05}, {BRIDGE, M5602_XB_GPIO_DAT, 0x04}, {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, - {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06}, - {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, - /*end of sequence 2 stop */ - -/* --------------------------------- - * end of init - begin of start - * --------------------------------- */ - - /*sequence 3*/ - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, - {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, - {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c}, - /*end of sequence 3*/ - /*sequence 4*/ - {BRIDGE, M5602_XB_GPIO_DIR, 0x05}, - {BRIDGE, M5602_XB_GPIO_DAT, 0x00}, - {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, {BRIDGE, M5602_XB_GPIO_EN_L, 0x00}, + {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06}, + {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, + {BRIDGE, M5602_XB_GPIO_DIR, 0x05}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x00}, - {SENSOR, PO1030_REG_AUTOCTRL2, 0x04}, + {SENSOR, PO1030_AUTOCTRL2, 0x04}, - /* Set the width to 751 */ - {SENSOR, PO1030_REG_FRAMEWIDTH_H, 0x02}, - {SENSOR, PO1030_REG_FRAMEWIDTH_L, 0xef}, + {SENSOR, PO1030_OUTFORMCTRL2, PO1030_RAW_RGB_BAYER}, + {SENSOR, PO1030_AUTOCTRL1, PO1030_WEIGHT_WIN_2X}, - /* Set the height to 540 */ - {SENSOR, PO1030_REG_FRAMEHEIGHT_H, 0x02}, - {SENSOR, PO1030_REG_FRAMEHEIGHT_L, 0x1c}, - - /* Set the x window to 1 */ - {SENSOR, PO1030_REG_WINDOWX_H, 0x00}, - {SENSOR, PO1030_REG_WINDOWX_L, 0x01}, - - /* Set the y window to 1 */ - {SENSOR, PO1030_REG_WINDOWY_H, 0x00}, - {SENSOR, PO1030_REG_WINDOWY_L, 0x01}, - - {SENSOR, PO1030_REG_WINDOWWIDTH_H, 0x02}, - {SENSOR, PO1030_REG_WINDOWWIDTH_L, 0x87}, - {SENSOR, PO1030_REG_WINDOWHEIGHT_H, 0x01}, - {SENSOR, PO1030_REG_WINDOWHEIGHT_L, 0xe3}, - - {SENSOR, PO1030_REG_OUTFORMCTRL2, 0x04}, - {SENSOR, PO1030_REG_OUTFORMCTRL2, 0x04}, - {SENSOR, PO1030_REG_AUTOCTRL1, 0x08}, - {SENSOR, PO1030_REG_CONTROL2, 0x03}, + {SENSOR, PO1030_CONTROL2, 0x03}, {SENSOR, 0x21, 0x90}, - {SENSOR, PO1030_REG_YTARGET, 0x60}, + {SENSOR, PO1030_YTARGET, 0x60}, {SENSOR, 0x59, 0x13}, - {SENSOR, PO1030_REG_OUTFORMCTRL1, 0x40}, - {SENSOR, 0x5f, 0x00}, - {SENSOR, 0x60, 0x80}, + {SENSOR, PO1030_OUTFORMCTRL1, PO1030_HREF_ENABLE}, + {SENSOR, PO1030_EDGE_ENH_OFF, 0x00}, + {SENSOR, PO1030_EGA, 0x80}, {SENSOR, 0x78, 0x14}, {SENSOR, 0x6f, 0x01}, - {SENSOR, PO1030_REG_CONTROL1, 0x18}, - {SENSOR, PO1030_REG_GLOBALGAINMAX, 0x14}, - {SENSOR, 0x63, 0x38}, - {SENSOR, 0x64, 0x38}, - {SENSOR, PO1030_REG_CONTROL1, 0x58}, - {SENSOR, PO1030_REG_RED_GAIN, 0x30}, - {SENSOR, PO1030_REG_GREEN_1_GAIN, 0x30}, - {SENSOR, PO1030_REG_BLUE_GAIN, 0x30}, - {SENSOR, PO1030_REG_GREEN_2_GAIN, 0x30}, - {SENSOR, PO1030_REG_GC0, 0x10}, - {SENSOR, PO1030_REG_GC1, 0x20}, - {SENSOR, PO1030_REG_GC2, 0x40}, - {SENSOR, PO1030_REG_GC3, 0x60}, - {SENSOR, PO1030_REG_GC4, 0x80}, - {SENSOR, PO1030_REG_GC5, 0xa0}, - {SENSOR, PO1030_REG_GC6, 0xc0}, - {SENSOR, PO1030_REG_GC7, 0xff}, - /*end of sequence 4*/ - /*sequence 5*/ - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, - {BRIDGE, M5602_XB_ADC_CTRL, 0xc0}, - {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c}, - {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81}, - {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82}, - {BRIDGE, M5602_XB_SIG_INI, 0x01}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x02}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x01}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0xec}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x02}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x7e}, - {BRIDGE, M5602_XB_SIG_INI, 0x00}, - /*end of sequence 5*/ + {SENSOR, PO1030_GLOBALGAINMAX, 0x14}, + {SENSOR, PO1030_Cb_U_GAIN, 0x38}, + {SENSOR, PO1030_Cr_V_GAIN, 0x38}, + {SENSOR, PO1030_CONTROL1, PO1030_SHUTTER_MODE | + PO1030_AUTO_SUBSAMPLING | + PO1030_FRAME_EQUAL}, + {SENSOR, PO1030_GC0, 0x10}, + {SENSOR, PO1030_GC1, 0x20}, + {SENSOR, PO1030_GC2, 0x40}, + {SENSOR, PO1030_GC3, 0x60}, + {SENSOR, PO1030_GC4, 0x80}, + {SENSOR, PO1030_GC5, 0xa0}, + {SENSOR, PO1030_GC6, 0xc0}, + {SENSOR, PO1030_GC7, 0xff}, - /*sequence 6*/ - /* Changing 40 in f0 the image becomes green in bayer mode and red in - * rgb mode */ - {SENSOR, PO1030_REG_RED_GAIN, PO1030_RED_GAIN_DEFAULT}, - /* in changing 40 in f0 the image becomes green in bayer mode and red in - * rgb mode */ - {SENSOR, PO1030_REG_BLUE_GAIN, PO1030_BLUE_GAIN_DEFAULT}, + /* Set the width to 751 */ + {SENSOR, PO1030_FRAMEWIDTH_H, 0x02}, + {SENSOR, PO1030_FRAMEWIDTH_L, 0xef}, + + /* Set the height to 540 */ + {SENSOR, PO1030_FRAMEHEIGHT_H, 0x02}, + {SENSOR, PO1030_FRAMEHEIGHT_L, 0x1c}, + + /* Set the x window to 1 */ + {SENSOR, PO1030_WINDOWX_H, 0x00}, + {SENSOR, PO1030_WINDOWX_L, 0x01}, + + /* Set the y window to 1 */ + {SENSOR, PO1030_WINDOWY_H, 0x00}, + {SENSOR, PO1030_WINDOWY_L, 0x01}, /* with a very low lighted environment increase the exposure but * decrease the FPS (Frame Per Second) */ {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00}, {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, - /* Controls high exposure more than SENSOR_LOW_EXPOSURE, use only in - * low lighted environment (f0 is more than ff ?)*/ - {SENSOR, PO1030_REG_INTEGLINES_H, ((PO1030_EXPOSURE_DEFAULT >> 2) - & 0xff)}, - - /* Controls middle exposure, use only in high lighted environment */ - {SENSOR, PO1030_REG_INTEGLINES_M, PO1030_EXPOSURE_DEFAULT & 0xff}, - - /* Controls clarity (not sure) */ - {SENSOR, PO1030_REG_INTEGLINES_L, 0x00}, - /* Controls gain (the image is more lighted) */ - {SENSOR, PO1030_REG_GLOBALGAIN, PO1030_GLOBAL_GAIN_DEFAULT}, - - /* Sets the width */ - {SENSOR, PO1030_REG_FRAMEWIDTH_H, 0x02}, - {SENSOR, PO1030_REG_FRAMEWIDTH_L, 0xef} - /*end of sequence 6*/ + {BRIDGE, M5602_XB_GPIO_DIR, 0x05}, + {BRIDGE, M5602_XB_GPIO_DAT, 0x00}, + {BRIDGE, M5602_XB_GPIO_EN_H, 0x06}, + {BRIDGE, M5602_XB_GPIO_EN_L, 0x00}, }; #endif diff --git a/drivers/media/video/gspca/m5602/m5602_s5k4aa.c b/drivers/media/video/gspca/m5602/m5602_s5k4aa.c index 4306d596056d..191bcd718979 100644 --- a/drivers/media/video/gspca/m5602/m5602_s5k4aa.c +++ b/drivers/media/video/gspca/m5602/m5602_s5k4aa.c @@ -18,6 +18,19 @@ #include "m5602_s5k4aa.h" +static int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val); +static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val); +static int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val); +static int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val); +static int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val); +static int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val); +static int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val); +static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val); +static int s5k4aa_get_noise(struct gspca_dev *gspca_dev, __s32 *val); +static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val); +static int s5k4aa_get_brightness(struct gspca_dev *gspca_dev, __s32 *val); +static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val); + static const struct dmi_system_id s5k4aa_vflip_dmi_table[] = { @@ -46,6 +59,18 @@ static DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"), DMI_MATCH(DMI_PRODUCT_NAME, "GX700/GX705/EX700") } + }, { + .ident = "MSI L735", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"), + DMI_MATCH(DMI_PRODUCT_NAME, "MS-1717X") + } + }, { + .ident = "Lenovo Y300", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "L3000 Y300"), + DMI_MATCH(DMI_PRODUCT_NAME, "Y300") + } }, { } }; @@ -61,10 +86,22 @@ static struct v4l2_pix_format s5k4aa_modes[] = { .bytesperline = 640, .colorspace = V4L2_COLORSPACE_SRGB, .priv = 0 + }, + { + 1280, + 1024, + V4L2_PIX_FMT_SBGGR8, + V4L2_FIELD_NONE, + .sizeimage = + 1280 * 1024, + .bytesperline = 1280, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0 } }; -const static struct ctrl s5k4aa_ctrls[] = { +static const struct ctrl s5k4aa_ctrls[] = { +#define VFLIP_IDX 0 { { .id = V4L2_CID_VFLIP, @@ -77,8 +114,9 @@ const static struct ctrl s5k4aa_ctrls[] = { }, .set = s5k4aa_set_vflip, .get = s5k4aa_get_vflip - - }, { + }, +#define HFLIP_IDX 1 + { { .id = V4L2_CID_HFLIP, .type = V4L2_CTRL_TYPE_BOOLEAN, @@ -90,8 +128,9 @@ const static struct ctrl s5k4aa_ctrls[] = { }, .set = s5k4aa_set_hflip, .get = s5k4aa_get_hflip - - }, { + }, +#define GAIN_IDX 2 + { { .id = V4L2_CID_GAIN, .type = V4L2_CTRL_TYPE_INTEGER, @@ -99,12 +138,14 @@ const static struct ctrl s5k4aa_ctrls[] = { .minimum = 0, .maximum = 127, .step = 1, - .default_value = 0xa0, + .default_value = S5K4AA_DEFAULT_GAIN, .flags = V4L2_CTRL_FLAG_SLIDER }, .set = s5k4aa_set_gain, .get = s5k4aa_get_gain - }, { + }, +#define EXPOSURE_IDX 3 + { { .id = V4L2_CID_EXPOSURE, .type = V4L2_CTRL_TYPE_INTEGER, @@ -117,7 +158,36 @@ const static struct ctrl s5k4aa_ctrls[] = { }, .set = s5k4aa_set_exposure, .get = s5k4aa_get_exposure - } + }, +#define NOISE_SUPP_IDX 4 + { + { + .id = V4L2_CID_PRIVATE_BASE, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Noise suppression (smoothing)", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + }, + .set = s5k4aa_set_noise, + .get = s5k4aa_get_noise + }, +#define BRIGHTNESS_IDX 5 + { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 0x1f, + .step = 1, + .default_value = S5K4AA_DEFAULT_BRIGHTNESS, + }, + .set = s5k4aa_set_brightness, + .get = s5k4aa_get_brightness + }, + }; static void s5k4aa_dump_registers(struct sd *sd); @@ -127,6 +197,7 @@ int s5k4aa_probe(struct sd *sd) u8 prod_id[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; const u8 expected_prod_id[6] = {0x00, 0x10, 0x00, 0x4b, 0x33, 0x75}; int i, err = 0; + s32 *sensor_settings; if (force_sensor) { if (force_sensor == S5K4AA_SENSOR) { @@ -185,10 +256,20 @@ int s5k4aa_probe(struct sd *sd) info("Detected a s5k4aa sensor"); sensor_found: + sensor_settings = kmalloc( + ARRAY_SIZE(s5k4aa_ctrls) * sizeof(s32), GFP_KERNEL); + if (!sensor_settings) + return -ENOMEM; + sd->gspca_dev.cam.cam_mode = s5k4aa_modes; sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k4aa_modes); sd->desc->ctrls = s5k4aa_ctrls; sd->desc->nctrls = ARRAY_SIZE(s5k4aa_ctrls); + + for (i = 0; i < ARRAY_SIZE(s5k4aa_ctrls); i++) + sensor_settings[i] = s5k4aa_ctrls[i].qctrl.default_value; + sd->sensor_priv = sensor_settings; + return 0; } @@ -197,9 +278,45 @@ int s5k4aa_start(struct sd *sd) int i, err = 0; u8 data[2]; struct cam *cam = &sd->gspca_dev.cam; + s32 *sensor_settings = sd->sensor_priv; + + switch (cam->cam_mode[sd->gspca_dev.curr_mode].width) { + case 1280: + PDEBUG(D_V4L2, "Configuring camera for SXGA mode"); + + for (i = 0; i < ARRAY_SIZE(SXGA_s5k4aa); i++) { + switch (SXGA_s5k4aa[i][0]) { + case BRIDGE: + err = m5602_write_bridge(sd, + SXGA_s5k4aa[i][1], + SXGA_s5k4aa[i][2]); + break; + + case SENSOR: + data[0] = SXGA_s5k4aa[i][2]; + err = m5602_write_sensor(sd, + SXGA_s5k4aa[i][1], + data, 1); + break; + + case SENSOR_LONG: + data[0] = SXGA_s5k4aa[i][2]; + data[1] = SXGA_s5k4aa[i][3]; + err = m5602_write_sensor(sd, + SXGA_s5k4aa[i][1], + data, 2); + break; + + default: + err("Invalid stream command, exiting init"); + return -EINVAL; + } + } + err = s5k4aa_set_noise(&sd->gspca_dev, 0); + if (err < 0) + return err; + break; - switch (cam->cam_mode[sd->gspca_dev.curr_mode].width) - { case 640: PDEBUG(D_V4L2, "Configuring camera for VGA mode"); @@ -231,8 +348,37 @@ int s5k4aa_start(struct sd *sd) return -EINVAL; } } + err = s5k4aa_set_noise(&sd->gspca_dev, 1); + if (err < 0) + return err; + break; } - return err; + if (err < 0) + return err; + + err = s5k4aa_set_exposure(&sd->gspca_dev, + sensor_settings[EXPOSURE_IDX]); + if (err < 0) + return err; + + err = s5k4aa_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]); + if (err < 0) + return err; + + err = s5k4aa_set_brightness(&sd->gspca_dev, + sensor_settings[BRIGHTNESS_IDX]); + if (err < 0) + return err; + + err = s5k4aa_set_noise(&sd->gspca_dev, sensor_settings[NOISE_SUPP_IDX]); + if (err < 0) + return err; + + err = s5k4aa_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]); + if (err < 0) + return err; + + return s5k4aa_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]); } int s5k4aa_init(struct sd *sd) @@ -270,62 +416,28 @@ int s5k4aa_init(struct sd *sd) if (dump_sensor) s5k4aa_dump_registers(sd); - if (!err && dmi_check_system(s5k4aa_vflip_dmi_table)) { - u8 data = 0x02; - info("vertical flip quirk active"); - m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); - m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1); - data |= S5K4AA_RM_V_FLIP; - data &= ~S5K4AA_RM_H_FLIP; - m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1); - - /* Decrement COLSTART to preserve color order (BGGR) */ - m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1); - data--; - m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1); - - /* Increment ROWSTART to preserve color order (BGGR) */ - m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1); - data++; - m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1); - } - - return (err < 0) ? err : 0; -} - -int s5k4aa_power_down(struct sd *sd) -{ - return 0; -} - -int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 data = S5K4AA_PAGE_MAP_2; - int err; - - err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); - if (err < 0) - return err; - - err = m5602_read_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1); - if (err < 0) - return err; - - *val = data << 8; - err = m5602_read_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1); - *val |= data; - PDEBUG(D_V4L2, "Read exposure %d", *val); - return err; } -int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val) +static int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[EXPOSURE_IDX]; + PDEBUG(D_V4L2, "Read exposure %d", *val); + + return 0; +} + +static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; u8 data = S5K4AA_PAGE_MAP_2; int err; + sensor_settings[EXPOSURE_IDX] = val; PDEBUG(D_V4L2, "Set exposure to %d", val); err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); if (err < 0) @@ -340,29 +452,26 @@ int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val) return err; } -int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) +static int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; - u8 data = S5K4AA_PAGE_MAP_2; - int err; + s32 *sensor_settings = sd->sensor_priv; - err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); - if (err < 0) - return err; - - err = m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); - *val = (data & S5K4AA_RM_V_FLIP) >> 7; + *val = sensor_settings[VFLIP_IDX]; PDEBUG(D_V4L2, "Read vertical flip %d", *val); - return err; + return 0; } -int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val) +static int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; u8 data = S5K4AA_PAGE_MAP_2; int err; + sensor_settings[VFLIP_IDX] = val; + PDEBUG(D_V4L2, "Set vertical flip to %d", val); err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); if (err < 0) @@ -370,56 +479,48 @@ int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val) err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1); if (err < 0) return err; - data = ((data & ~S5K4AA_RM_V_FLIP) - | ((val & 0x01) << 7)); + + err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1); + if (err < 0) + return err; + + if (dmi_check_system(s5k4aa_vflip_dmi_table)) + val = !val; + + data = ((data & ~S5K4AA_RM_V_FLIP) | ((val & 0x01) << 7)); err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1); if (err < 0) return err; - if (val) { - err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1); - if (err < 0) - return err; - - data++; - err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1); - } else { - err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1); - if (err < 0) - return err; - - data--; - err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1); - } - + err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1); + if (err < 0) + return err; + data = (data & 0xfe) | !val; + err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1); return err; } -int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) +static int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; - u8 data = S5K4AA_PAGE_MAP_2; - int err; + s32 *sensor_settings = sd->sensor_priv; - err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); - if (err < 0) - return err; - - err = m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); - *val = (data & S5K4AA_RM_H_FLIP) >> 6; + *val = sensor_settings[HFLIP_IDX]; PDEBUG(D_V4L2, "Read horizontal flip %d", *val); - return err; + return 0; } -int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val) +static int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; u8 data = S5K4AA_PAGE_MAP_2; int err; - PDEBUG(D_V4L2, "Set horizontal flip to %d", - val); + sensor_settings[HFLIP_IDX] = val; + + PDEBUG(D_V4L2, "Set horizontal flip to %d", val); err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); if (err < 0) return err; @@ -427,64 +528,118 @@ int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val) if (err < 0) return err; + err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1); + if (err < 0) + return err; + + if (dmi_check_system(s5k4aa_vflip_dmi_table)) + val = !val; + data = ((data & ~S5K4AA_RM_H_FLIP) | ((val & 0x01) << 6)); err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1); if (err < 0) return err; - if (val) { - err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1); - if (err < 0) - return err; - data++; - err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1); - if (err < 0) - return err; - } else { - err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1); - if (err < 0) - return err; - data--; - err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1); - } - - return err; -} - -int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 data = S5K4AA_PAGE_MAP_2; - int err; - - err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); + err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1); if (err < 0) return err; - - err = m5602_read_sensor(sd, S5K4AA_GAIN_2, &data, 1); - *val = data; - PDEBUG(D_V4L2, "Read gain %d", *val); - + data = (data & 0xfe) | !val; + err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1); return err; } -int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val) +static int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[GAIN_IDX]; + PDEBUG(D_V4L2, "Read gain %d", *val); + return 0; +} + +static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; u8 data = S5K4AA_PAGE_MAP_2; int err; + sensor_settings[GAIN_IDX] = val; + PDEBUG(D_V4L2, "Set gain to %d", val); err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); if (err < 0) return err; data = val & 0xff; - err = m5602_write_sensor(sd, S5K4AA_GAIN_2, &data, 1); + err = m5602_write_sensor(sd, S5K4AA_GAIN, &data, 1); return err; } +static int s5k4aa_get_brightness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[BRIGHTNESS_IDX]; + PDEBUG(D_V4L2, "Read brightness %d", *val); + return 0; +} + +static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + u8 data = S5K4AA_PAGE_MAP_2; + int err; + + sensor_settings[BRIGHTNESS_IDX] = val; + + PDEBUG(D_V4L2, "Set brightness to %d", val); + err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); + if (err < 0) + return err; + + data = val & 0xff; + return m5602_write_sensor(sd, S5K4AA_BRIGHTNESS, &data, 1); +} + +static int s5k4aa_get_noise(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[NOISE_SUPP_IDX]; + PDEBUG(D_V4L2, "Read noise %d", *val); + return 0; +} + +static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + u8 data = S5K4AA_PAGE_MAP_2; + int err; + + sensor_settings[NOISE_SUPP_IDX] = val; + + PDEBUG(D_V4L2, "Set noise to %d", val); + err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); + if (err < 0) + return err; + + data = val & 0x01; + return m5602_write_sensor(sd, S5K4AA_NOISE_SUPP, &data, 1); +} + +void s5k4aa_disconnect(struct sd *sd) +{ + sd->sensor = NULL; + kfree(sd->sensor_priv); +} + static void s5k4aa_dump_registers(struct sd *sd) { int address; diff --git a/drivers/media/video/gspca/m5602/m5602_s5k4aa.h b/drivers/media/video/gspca/m5602/m5602_s5k4aa.h index ca854d4f9475..4440da4e7f0f 100644 --- a/drivers/media/video/gspca/m5602/m5602_s5k4aa.h +++ b/drivers/media/video/gspca/m5602/m5602_s5k4aa.h @@ -47,8 +47,9 @@ #define S5K4AA_H_BLANK_LO__ 0x1e #define S5K4AA_EXPOSURE_HI 0x17 #define S5K4AA_EXPOSURE_LO 0x18 -#define S5K4AA_GAIN_1 0x1f /* (digital?) gain : 5 bits */ -#define S5K4AA_GAIN_2 0x20 /* (analogue?) gain : 7 bits */ +#define S5K4AA_BRIGHTNESS 0x1f /* (digital?) gain : 5 bits */ +#define S5K4AA_GAIN 0x20 /* (analogue?) gain : 7 bits */ +#define S5K4AA_NOISE_SUPP 0x37 #define S5K4AA_RM_ROW_SKIP_4X 0x08 #define S5K4AA_RM_ROW_SKIP_2X 0x04 @@ -57,6 +58,9 @@ #define S5K4AA_RM_H_FLIP 0x40 #define S5K4AA_RM_V_FLIP 0x80 +#define S5K4AA_DEFAULT_GAIN 0x5f +#define S5K4AA_DEFAULT_BRIGHTNESS 0x10 + /*****************************************************************************/ /* Kernel module parameters */ @@ -66,25 +70,17 @@ extern int dump_sensor; int s5k4aa_probe(struct sd *sd); int s5k4aa_init(struct sd *sd); int s5k4aa_start(struct sd *sd); -int s5k4aa_power_down(struct sd *sd); - -int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val); -int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val); -int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val); -int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val); -int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val); -int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val); -int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val); -int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val); +void s5k4aa_disconnect(struct sd *sd); static const struct m5602_sensor s5k4aa = { .name = "S5K4AA", + .i2c_slave_id = 0x5a, + .i2c_regW = 2, + .probe = s5k4aa_probe, .init = s5k4aa_init, .start = s5k4aa_start, - .power_down = s5k4aa_power_down, - .i2c_slave_id = 0x5a, - .i2c_regW = 2, + .disconnect = s5k4aa_disconnect, }; static const unsigned char preinit_s5k4aa[][4] = @@ -179,85 +175,8 @@ static const unsigned char init_s5k4aa[][4] = {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00}, {SENSOR, 0x0c, 0x05, 0x00}, {SENSOR, 0x02, 0x0e, 0x00}, - {SENSOR, S5K4AA_GAIN_1, 0x0f, 0x00}, - {SENSOR, S5K4AA_GAIN_2, 0x00, 0x00}, - {SENSOR, S5K4AA_GLOBAL_GAIN__, 0x01, 0x00}, - {SENSOR, 0x11, 0x00, 0x00}, - {SENSOR, 0x12, 0x00, 0x00}, - {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00}, {SENSOR, S5K4AA_READ_MODE, 0xa0, 0x00}, {SENSOR, 0x37, 0x00, 0x00}, - {SENSOR, S5K4AA_ROWSTART_HI, 0x00, 0x00}, - {SENSOR, S5K4AA_ROWSTART_LO, 0x2a, 0x00}, - {SENSOR, S5K4AA_COLSTART_HI, 0x00, 0x00}, - {SENSOR, S5K4AA_COLSTART_LO, 0x0b, 0x00}, - {SENSOR, S5K4AA_WINDOW_HEIGHT_HI, 0x03, 0x00}, - {SENSOR, S5K4AA_WINDOW_HEIGHT_LO, 0xc4, 0x00}, - {SENSOR, S5K4AA_WINDOW_WIDTH_HI, 0x05, 0x00}, - {SENSOR, S5K4AA_WINDOW_WIDTH_LO, 0x08, 0x00}, - {SENSOR, S5K4AA_H_BLANK_HI__, 0x00, 0x00}, - {SENSOR, S5K4AA_H_BLANK_LO__, 0x48, 0x00}, - {SENSOR, S5K4AA_EXPOSURE_HI, 0x00, 0x00}, - {SENSOR, S5K4AA_EXPOSURE_LO, 0x43, 0x00}, - {SENSOR, 0x11, 0x04, 0x00}, - {SENSOR, 0x12, 0xc3, 0x00}, - {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00}, - - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, - {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, - {BRIDGE, M5602_XB_SENSOR_TYPE, 0x08, 0x00}, - {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00}, - {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - /* VSYNC_PARA, VSYNC_PARA : img height 480 = 0x01e0 */ - {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0xe0, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, - /* HSYNC_PARA, HSYNC_PARA : img width 640 = 0x0280 */ - {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x80, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xa0, 0x00}, /* 48 MHz */ - - {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00}, - {SENSOR, S5K4AA_READ_MODE, S5K4AA_RM_H_FLIP | S5K4AA_RM_ROW_SKIP_2X - | S5K4AA_RM_COL_SKIP_2X, 0x00}, - /* 0x37 : Fix image stability when light is too bright and improves - * image quality in 640x480, but worsens it in 1280x1024 */ - {SENSOR, 0x37, 0x01, 0x00}, - /* ROWSTART_HI, ROWSTART_LO : 10 + (1024-960)/2 = 42 = 0x002a */ - {SENSOR, S5K4AA_ROWSTART_HI, 0x00, 0x00}, - {SENSOR, S5K4AA_ROWSTART_LO, 0x2a, 0x00}, - {SENSOR, S5K4AA_COLSTART_HI, 0x00, 0x00}, - {SENSOR, S5K4AA_COLSTART_LO, 0x0c, 0x00}, - /* window_height_hi, window_height_lo : 960 = 0x03c0 */ - {SENSOR, S5K4AA_WINDOW_HEIGHT_HI, 0x03, 0x00}, - {SENSOR, S5K4AA_WINDOW_HEIGHT_LO, 0xc0, 0x00}, - /* window_width_hi, window_width_lo : 1280 = 0x0500 */ - {SENSOR, S5K4AA_WINDOW_WIDTH_HI, 0x05, 0x00}, - {SENSOR, S5K4AA_WINDOW_WIDTH_LO, 0x00, 0x00}, - {SENSOR, S5K4AA_H_BLANK_HI__, 0x00, 0x00}, - {SENSOR, S5K4AA_H_BLANK_LO__, 0xa8, 0x00}, /* helps to sync... */ - {SENSOR, S5K4AA_EXPOSURE_HI, 0x01, 0x00}, - {SENSOR, S5K4AA_EXPOSURE_LO, 0x00, 0x00}, - {SENSOR, 0x11, 0x04, 0x00}, - {SENSOR, 0x12, 0xc3, 0x00}, - {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00}, - {SENSOR, 0x02, 0x0e, 0x00}, - {SENSOR_LONG, S5K4AA_GLOBAL_GAIN__, 0x0f, 0x00}, - {SENSOR, S5K4AA_GAIN_1, 0x0b, 0x00}, - {SENSOR, S5K4AA_GAIN_2, 0xa0, 0x00} }; static const unsigned char VGA_s5k4aa[][4] = @@ -297,7 +216,7 @@ static const unsigned char VGA_s5k4aa[][4] = {SENSOR, 0x37, 0x01, 0x00}, /* ROWSTART_HI, ROWSTART_LO : 10 + (1024-960)/2 = 42 = 0x002a */ {SENSOR, S5K4AA_ROWSTART_HI, 0x00, 0x00}, - {SENSOR, S5K4AA_ROWSTART_LO, 0x2a, 0x00}, + {SENSOR, S5K4AA_ROWSTART_LO, 0x29, 0x00}, {SENSOR, S5K4AA_COLSTART_HI, 0x00, 0x00}, {SENSOR, S5K4AA_COLSTART_LO, 0x0c, 0x00}, /* window_height_hi, window_height_lo : 960 = 0x03c0 */ @@ -314,9 +233,57 @@ static const unsigned char VGA_s5k4aa[][4] = {SENSOR, 0x12, 0xc3, 0x00}, {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00}, {SENSOR, 0x02, 0x0e, 0x00}, - {SENSOR_LONG, S5K4AA_GLOBAL_GAIN__, 0x0f, 0x00}, - {SENSOR, S5K4AA_GAIN_1, 0x0b, 0x00}, - {SENSOR, S5K4AA_GAIN_2, 0xa0, 0x00} }; +static const unsigned char SXGA_s5k4aa[][4] = +{ + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, + {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, + {BRIDGE, M5602_XB_SENSOR_TYPE, 0x08, 0x00}, + {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00}, + {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + /* VSYNC_PARA, VSYNC_PARA : img height 1024 = 0x0400 */ + {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, + /* HSYNC_PARA, HSYNC_PARA : img width 1280 = 0x0500 */ + {BRIDGE, M5602_XB_HSYNC_PARA, 0x05, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, + {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xa0, 0x00}, /* 48 MHz */ + + {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00}, + {SENSOR, S5K4AA_READ_MODE, S5K4AA_RM_H_FLIP, 0x00}, + {SENSOR, 0x37, 0x01, 0x00}, + {SENSOR, S5K4AA_ROWSTART_HI, 0x00, 0x00}, + {SENSOR, S5K4AA_ROWSTART_LO, 0x09, 0x00}, + {SENSOR, S5K4AA_COLSTART_HI, 0x00, 0x00}, + {SENSOR, S5K4AA_COLSTART_LO, 0x0a, 0x00}, + {SENSOR, S5K4AA_WINDOW_HEIGHT_HI, 0x04, 0x00}, + {SENSOR, S5K4AA_WINDOW_HEIGHT_LO, 0x00, 0x00}, + {SENSOR, S5K4AA_WINDOW_WIDTH_HI, 0x05, 0x00}, + {SENSOR, S5K4AA_WINDOW_WIDTH_LO, 0x00, 0x00}, + {SENSOR, S5K4AA_H_BLANK_HI__, 0x01, 0x00}, + {SENSOR, S5K4AA_H_BLANK_LO__, 0xa8, 0x00}, + {SENSOR, S5K4AA_EXPOSURE_HI, 0x01, 0x00}, + {SENSOR, S5K4AA_EXPOSURE_LO, 0x00, 0x00}, + {SENSOR, 0x11, 0x04, 0x00}, + {SENSOR, 0x12, 0xc3, 0x00}, + {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00}, + {SENSOR, 0x02, 0x0e, 0x00}, +}; + + #endif diff --git a/drivers/media/video/gspca/m5602/m5602_s5k83a.c b/drivers/media/video/gspca/m5602/m5602_s5k83a.c index 42c86aa4dc8d..7127321ace8c 100644 --- a/drivers/media/video/gspca/m5602/m5602_s5k83a.c +++ b/drivers/media/video/gspca/m5602/m5602_s5k83a.c @@ -16,8 +16,20 @@ * */ +#include #include "m5602_s5k83a.h" +static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val); +static int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val); +static int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val); +static int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val); +static int s5k83a_set_exposure(struct gspca_dev *gspca_dev, __s32 val); +static int s5k83a_get_exposure(struct gspca_dev *gspca_dev, __s32 *val); +static int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val); +static int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val); +static int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val); +static int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val); + static struct v4l2_pix_format s5k83a_modes[] = { { 640, @@ -32,7 +44,24 @@ static struct v4l2_pix_format s5k83a_modes[] = { } }; -const static struct ctrl s5k83a_ctrls[] = { +static const struct ctrl s5k83a_ctrls[] = { +#define GAIN_IDX 0 + { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "gain", + .minimum = 0x00, + .maximum = 0xff, + .step = 0x01, + .default_value = S5K83A_DEFAULT_GAIN, + .flags = V4L2_CTRL_FLAG_SLIDER + }, + .set = s5k83a_set_gain, + .get = s5k83a_get_gain + + }, +#define BRIGHTNESS_IDX 1 { { .id = V4L2_CID_BRIGHTNESS, @@ -45,55 +74,47 @@ const static struct ctrl s5k83a_ctrls[] = { .flags = V4L2_CTRL_FLAG_SLIDER }, .set = s5k83a_set_brightness, - .get = s5k83a_get_brightness - - }, { + .get = s5k83a_get_brightness, + }, +#define EXPOSURE_IDX 2 + { { - .id = V4L2_CID_WHITENESS, + .id = V4L2_CID_EXPOSURE, .type = V4L2_CTRL_TYPE_INTEGER, - .name = "whiteness", + .name = "exposure", .minimum = 0x00, - .maximum = 0xff, + .maximum = S5K83A_MAXIMUM_EXPOSURE, .step = 0x01, - .default_value = S5K83A_DEFAULT_WHITENESS, + .default_value = S5K83A_DEFAULT_EXPOSURE, .flags = V4L2_CTRL_FLAG_SLIDER }, - .set = s5k83a_set_whiteness, - .get = s5k83a_get_whiteness, - }, { + .set = s5k83a_set_exposure, + .get = s5k83a_get_exposure + }, +#define HFLIP_IDX 3 + { { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "gain", - .minimum = 0x00, - .maximum = S5K83A_MAXIMUM_GAIN, - .step = 0x01, - .default_value = S5K83A_DEFAULT_GAIN, - .flags = V4L2_CTRL_FLAG_SLIDER - }, - .set = s5k83a_set_gain, - .get = s5k83a_get_gain - }, { - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "horizontal flip", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0 + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "horizontal flip", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0 }, .set = s5k83a_set_hflip, .get = s5k83a_get_hflip - }, { + }, +#define VFLIP_IDX 4 + { { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "vertical flip", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0 + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "vertical flip", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0 }, .set = s5k83a_set_vflip, .get = s5k83a_get_vflip @@ -101,9 +122,14 @@ const static struct ctrl s5k83a_ctrls[] = { }; static void s5k83a_dump_registers(struct sd *sd); +static int s5k83a_get_rotation(struct sd *sd, u8 *reg_data); +static int s5k83a_set_led_indication(struct sd *sd, u8 val); +static int s5k83a_set_flip_real(struct gspca_dev *gspca_dev, + __s32 vflip, __s32 hflip); int s5k83a_probe(struct sd *sd) { + struct s5k83a_priv *sens_priv; u8 prod_id = 0, ver_id = 0; int i, err = 0; @@ -145,16 +171,36 @@ int s5k83a_probe(struct sd *sd) info("Detected a s5k83a sensor"); sensor_found: + sens_priv = kmalloc( + sizeof(struct s5k83a_priv), GFP_KERNEL); + if (!sens_priv) + return -ENOMEM; + + sens_priv->settings = + kmalloc(sizeof(s32)*ARRAY_SIZE(s5k83a_ctrls), GFP_KERNEL); + if (!sens_priv->settings) + return -ENOMEM; + sd->gspca_dev.cam.cam_mode = s5k83a_modes; sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k83a_modes); sd->desc->ctrls = s5k83a_ctrls; sd->desc->nctrls = ARRAY_SIZE(s5k83a_ctrls); + + /* null the pointer! thread is't running now */ + sens_priv->rotation_thread = NULL; + + for (i = 0; i < ARRAY_SIZE(s5k83a_ctrls); i++) + sens_priv->settings[i] = s5k83a_ctrls[i].qctrl.default_value; + + sd->sensor_priv = sens_priv; return 0; } int s5k83a_init(struct sd *sd) { int i, err = 0; + s32 *sensor_settings = + ((struct s5k83a_priv *) sd->sensor_priv)->settings; for (i = 0; i < ARRAY_SIZE(init_s5k83a) && !err; i++) { u8 data[2] = {0x00, 0x00}; @@ -187,24 +233,329 @@ int s5k83a_init(struct sd *sd) if (dump_sensor) s5k83a_dump_registers(sd); - return (err < 0) ? err : 0; + err = s5k83a_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]); + if (err < 0) + return err; + + err = s5k83a_set_brightness(&sd->gspca_dev, + sensor_settings[BRIGHTNESS_IDX]); + if (err < 0) + return err; + + err = s5k83a_set_exposure(&sd->gspca_dev, + sensor_settings[EXPOSURE_IDX]); + if (err < 0) + return err; + + err = s5k83a_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]); + if (err < 0) + return err; + + err = s5k83a_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]); + + return err; +} + +static int rotation_thread_function(void *data) +{ + struct sd *sd = (struct sd *) data; + struct s5k83a_priv *sens_priv = sd->sensor_priv; + u8 reg, previous_rotation = 0; + __s32 vflip, hflip; + + set_current_state(TASK_INTERRUPTIBLE); + while (!schedule_timeout(100)) { + if (mutex_lock_interruptible(&sd->gspca_dev.usb_lock)) + break; + + s5k83a_get_rotation(sd, ®); + if (previous_rotation != reg) { + previous_rotation = reg; + info("Camera was flipped"); + + s5k83a_get_vflip((struct gspca_dev *) sd, &vflip); + s5k83a_get_hflip((struct gspca_dev *) sd, &hflip); + + if (reg) { + vflip = !vflip; + hflip = !hflip; + } + s5k83a_set_flip_real((struct gspca_dev *) sd, + vflip, hflip); + } + + mutex_unlock(&sd->gspca_dev.usb_lock); + set_current_state(TASK_INTERRUPTIBLE); + } + + /* return to "front" flip */ + if (previous_rotation) { + s5k83a_get_vflip((struct gspca_dev *) sd, &vflip); + s5k83a_get_hflip((struct gspca_dev *) sd, &hflip); + s5k83a_set_flip_real((struct gspca_dev *) sd, vflip, hflip); + } + + sens_priv->rotation_thread = NULL; + return 0; } int s5k83a_start(struct sd *sd) { + int i, err = 0; + struct s5k83a_priv *sens_priv = sd->sensor_priv; + + /* Create another thread, polling the GPIO ports of the camera to check + if it got rotated. This is how the windows driver does it so we have + to assume that there is no better way of accomplishing this */ + sens_priv->rotation_thread = kthread_create(rotation_thread_function, + sd, "rotation thread"); + wake_up_process(sens_priv->rotation_thread); + + /* Preinit the sensor */ + for (i = 0; i < ARRAY_SIZE(start_s5k83a) && !err; i++) { + u8 data[2] = {start_s5k83a[i][2], start_s5k83a[i][3]}; + if (start_s5k83a[i][0] == SENSOR) + err = m5602_write_sensor(sd, start_s5k83a[i][1], + data, 2); + else + err = m5602_write_bridge(sd, start_s5k83a[i][1], + data[0]); + } + if (err < 0) + return err; + return s5k83a_set_led_indication(sd, 1); } int s5k83a_stop(struct sd *sd) { + struct s5k83a_priv *sens_priv = sd->sensor_priv; + + if (sens_priv->rotation_thread) + kthread_stop(sens_priv->rotation_thread); + return s5k83a_set_led_indication(sd, 0); } -int s5k83a_power_down(struct sd *sd) +void s5k83a_disconnect(struct sd *sd) { + struct s5k83a_priv *sens_priv = sd->sensor_priv; + + s5k83a_stop(sd); + + sd->sensor = NULL; + kfree(sens_priv->settings); + kfree(sens_priv); +} + +static int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct s5k83a_priv *sens_priv = sd->sensor_priv; + + *val = sens_priv->settings[GAIN_IDX]; return 0; } +static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + u8 data[2]; + struct sd *sd = (struct sd *) gspca_dev; + struct s5k83a_priv *sens_priv = sd->sensor_priv; + + sens_priv->settings[GAIN_IDX] = val; + + data[0] = 0x00; + data[1] = 0x20; + err = m5602_write_sensor(sd, 0x14, data, 2); + if (err < 0) + return err; + + data[0] = 0x01; + data[1] = 0x00; + err = m5602_write_sensor(sd, 0x0d, data, 2); + if (err < 0) + return err; + + /* FIXME: This is not sane, we need to figure out the composition + of these registers */ + data[0] = val >> 3; /* gain, high 5 bits */ + data[1] = val >> 1; /* gain, high 7 bits */ + err = m5602_write_sensor(sd, S5K83A_GAIN, data, 2); + + return err; +} + +static int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct s5k83a_priv *sens_priv = sd->sensor_priv; + + *val = sens_priv->settings[BRIGHTNESS_IDX]; + return 0; +} + +static int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + u8 data[1]; + struct sd *sd = (struct sd *) gspca_dev; + struct s5k83a_priv *sens_priv = sd->sensor_priv; + + sens_priv->settings[BRIGHTNESS_IDX] = val; + data[0] = val; + err = m5602_write_sensor(sd, S5K83A_BRIGHTNESS, data, 1); + return err; +} + +static int s5k83a_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct s5k83a_priv *sens_priv = sd->sensor_priv; + + *val = sens_priv->settings[EXPOSURE_IDX]; + return 0; +} + +static int s5k83a_set_exposure(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + u8 data[2]; + struct sd *sd = (struct sd *) gspca_dev; + struct s5k83a_priv *sens_priv = sd->sensor_priv; + + sens_priv->settings[EXPOSURE_IDX] = val; + data[0] = 0; + data[1] = val; + err = m5602_write_sensor(sd, S5K83A_EXPOSURE, data, 2); + return err; +} + +static int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct s5k83a_priv *sens_priv = sd->sensor_priv; + + *val = sens_priv->settings[VFLIP_IDX]; + return 0; +} + +static int s5k83a_set_flip_real(struct gspca_dev *gspca_dev, + __s32 vflip, __s32 hflip) +{ + int err; + u8 data[1]; + struct sd *sd = (struct sd *) gspca_dev; + + data[0] = 0x05; + err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1); + if (err < 0) + return err; + + /* six bit is vflip, seven is hflip */ + data[0] = S5K83A_FLIP_MASK; + data[0] = (vflip) ? data[0] | 0x40 : data[0]; + data[0] = (hflip) ? data[0] | 0x80 : data[0]; + + err = m5602_write_sensor(sd, S5K83A_FLIP, data, 1); + if (err < 0) + return err; + + data[0] = (vflip) ? 0x0b : 0x0a; + err = m5602_write_sensor(sd, S5K83A_VFLIP_TUNE, data, 1); + if (err < 0) + return err; + + data[0] = (hflip) ? 0x0a : 0x0b; + err = m5602_write_sensor(sd, S5K83A_HFLIP_TUNE, data, 1); + return err; +} + +static int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + u8 reg; + __s32 hflip; + struct sd *sd = (struct sd *) gspca_dev; + struct s5k83a_priv *sens_priv = sd->sensor_priv; + + sens_priv->settings[VFLIP_IDX] = val; + + s5k83a_get_hflip(gspca_dev, &hflip); + + err = s5k83a_get_rotation(sd, ®); + if (err < 0) + return err; + if (reg) { + val = !val; + hflip = !hflip; + } + + err = s5k83a_set_flip_real(gspca_dev, val, hflip); + return err; +} + +static int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct s5k83a_priv *sens_priv = sd->sensor_priv; + + *val = sens_priv->settings[HFLIP_IDX]; + return 0; +} + +static int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + u8 reg; + __s32 vflip; + struct sd *sd = (struct sd *) gspca_dev; + struct s5k83a_priv *sens_priv = sd->sensor_priv; + + sens_priv->settings[HFLIP_IDX] = val; + + s5k83a_get_vflip(gspca_dev, &vflip); + + err = s5k83a_get_rotation(sd, ®); + if (err < 0) + return err; + if (reg) { + val = !val; + vflip = !vflip; + } + + err = s5k83a_set_flip_real(gspca_dev, vflip, val); + return err; +} + +static int s5k83a_set_led_indication(struct sd *sd, u8 val) +{ + int err = 0; + u8 data[1]; + + err = m5602_read_bridge(sd, M5602_XB_GPIO_DAT, data); + if (err < 0) + return err; + + if (val) + data[0] = data[0] | S5K83A_GPIO_LED_MASK; + else + data[0] = data[0] & ~S5K83A_GPIO_LED_MASK; + + err = m5602_write_bridge(sd, M5602_XB_GPIO_DAT, data[0]); + + return err; +} + +/* Get camera rotation on Acer notebooks */ +static int s5k83a_get_rotation(struct sd *sd, u8 *reg_data) +{ + int err = m5602_read_bridge(sd, M5602_XB_GPIO_DAT, reg_data); + *reg_data = (*reg_data & S5K83A_GPIO_ROTATION_MASK) ? 0 : 1; + return err; +} + static void s5k83a_dump_registers(struct sd *sd) { int address; @@ -226,7 +577,7 @@ static void s5k83a_dump_registers(struct sd *sd) for (page = 0; page < 16; page++) { m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1); info("Probing for which registers that are read/write " - "for page 0x%x", page); + "for page 0x%x", page); for (address = 0; address <= 0xff; address++) { u8 old_val, ctrl_val, test_val = 0xff; @@ -246,213 +597,3 @@ static void s5k83a_dump_registers(struct sd *sd) info("Read/write register probing complete"); m5602_write_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1); } - -int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val) -{ - int err; - u8 data[2]; - struct sd *sd = (struct sd *) gspca_dev; - - err = m5602_read_sensor(sd, S5K83A_BRIGHTNESS, data, 2); - if (err < 0) - return err; - - data[1] = data[1] << 1; - *val = data[1]; - - return err; -} - -int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val) -{ - int err; - u8 data[2]; - struct sd *sd = (struct sd *) gspca_dev; - - data[0] = 0x00; - data[1] = 0x20; - err = m5602_write_sensor(sd, 0x14, data, 2); - if (err < 0) - return err; - - data[0] = 0x01; - data[1] = 0x00; - err = m5602_write_sensor(sd, 0x0d, data, 2); - if (err < 0) - return err; - - /* FIXME: This is not sane, we need to figure out the composition - of these registers */ - data[0] = val >> 3; /* brightness, high 5 bits */ - data[1] = val >> 1; /* brightness, high 7 bits */ - err = m5602_write_sensor(sd, S5K83A_BRIGHTNESS, data, 2); - - return err; -} - -int s5k83a_get_whiteness(struct gspca_dev *gspca_dev, __s32 *val) -{ - int err; - u8 data; - struct sd *sd = (struct sd *) gspca_dev; - - err = m5602_read_sensor(sd, S5K83A_WHITENESS, &data, 1); - if (err < 0) - return err; - - *val = data; - - return err; -} - -int s5k83a_set_whiteness(struct gspca_dev *gspca_dev, __s32 val) -{ - int err; - u8 data[1]; - struct sd *sd = (struct sd *) gspca_dev; - - data[0] = val; - err = m5602_write_sensor(sd, S5K83A_WHITENESS, data, 1); - - return err; -} - -int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val) -{ - int err; - u8 data[2]; - struct sd *sd = (struct sd *) gspca_dev; - - err = m5602_read_sensor(sd, S5K83A_GAIN, data, 2); - if (err < 0) - return err; - - data[1] = data[1] & 0x3f; - if (data[1] > S5K83A_MAXIMUM_GAIN) - data[1] = S5K83A_MAXIMUM_GAIN; - - *val = data[1]; - - return err; -} - -int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val) -{ - int err; - u8 data[2]; - struct sd *sd = (struct sd *) gspca_dev; - - data[0] = 0; - data[1] = val; - err = m5602_write_sensor(sd, S5K83A_GAIN, data, 2); - return err; -} - -int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) -{ - int err; - u8 data[1]; - struct sd *sd = (struct sd *) gspca_dev; - - data[0] = 0x05; - err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1); - if (err < 0) - return err; - - err = m5602_read_sensor(sd, S5K83A_FLIP, data, 1); - *val = (data[0] | 0x40) ? 1 : 0; - - return err; -} - -int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val) -{ - int err; - u8 data[1]; - struct sd *sd = (struct sd *) gspca_dev; - - data[0] = 0x05; - err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1); - if (err < 0) - return err; - - err = m5602_read_sensor(sd, S5K83A_FLIP, data, 1); - if (err < 0) - return err; - - /* set or zero six bit, seven is hflip */ - data[0] = (val) ? (data[0] & 0x80) | 0x40 | S5K83A_FLIP_MASK - : (data[0] & 0x80) | S5K83A_FLIP_MASK; - err = m5602_write_sensor(sd, S5K83A_FLIP, data, 1); - if (err < 0) - return err; - - data[0] = (val) ? 0x0b : 0x0a; - err = m5602_write_sensor(sd, S5K83A_VFLIP_TUNE, data, 1); - - return err; -} - -int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) -{ - int err; - u8 data[1]; - struct sd *sd = (struct sd *) gspca_dev; - - data[0] = 0x05; - err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1); - if (err < 0) - return err; - - err = m5602_read_sensor(sd, S5K83A_FLIP, data, 1); - *val = (data[0] | 0x80) ? 1 : 0; - - return err; -} - -int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val) -{ - int err; - u8 data[1]; - struct sd *sd = (struct sd *) gspca_dev; - - data[0] = 0x05; - err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1); - if (err < 0) - return err; - - err = m5602_read_sensor(sd, S5K83A_FLIP, data, 1); - if (err < 0) - return err; - - /* set or zero seven bit, six is vflip */ - data[0] = (val) ? (data[0] & 0x40) | 0x80 | S5K83A_FLIP_MASK - : (data[0] & 0x40) | S5K83A_FLIP_MASK; - err = m5602_write_sensor(sd, S5K83A_FLIP, data, 1); - if (err < 0) - return err; - - data[0] = (val) ? 0x0a : 0x0b; - err = m5602_write_sensor(sd, S5K83A_HFLIP_TUNE, data, 1); - - return err; -} - -int s5k83a_set_led_indication(struct sd *sd, u8 val) -{ - int err = 0; - u8 data[1]; - - err = m5602_read_bridge(sd, M5602_XB_GPIO_DAT, data); - if (err < 0) - return err; - - if (val) - data[0] = data[0] | S5K83A_GPIO_LED_MASK; - else - data[0] = data[0] & ~S5K83A_GPIO_LED_MASK; - - err = m5602_write_bridge(sd, M5602_XB_GPIO_DAT, data[0]); - - return (err < 0) ? err : 0; -} diff --git a/drivers/media/video/gspca/m5602/m5602_s5k83a.h b/drivers/media/video/gspca/m5602/m5602_s5k83a.h index 819ab25272be..7814b078acde 100644 --- a/drivers/media/video/gspca/m5602/m5602_s5k83a.h +++ b/drivers/media/video/gspca/m5602/m5602_s5k83a.h @@ -21,20 +21,21 @@ #include "m5602_sensor.h" -#define S5K83A_FLIP 0x01 -#define S5K83A_HFLIP_TUNE 0x03 -#define S5K83A_VFLIP_TUNE 0x05 -#define S5K83A_WHITENESS 0x0a -#define S5K83A_GAIN 0x18 -#define S5K83A_BRIGHTNESS 0x1b -#define S5K83A_PAGE_MAP 0xec +#define S5K83A_FLIP 0x01 +#define S5K83A_HFLIP_TUNE 0x03 +#define S5K83A_VFLIP_TUNE 0x05 +#define S5K83A_BRIGHTNESS 0x0a +#define S5K83A_EXPOSURE 0x18 +#define S5K83A_GAIN 0x1b +#define S5K83A_PAGE_MAP 0xec -#define S5K83A_DEFAULT_BRIGHTNESS 0x71 -#define S5K83A_DEFAULT_WHITENESS 0x7e -#define S5K83A_DEFAULT_GAIN 0x00 -#define S5K83A_MAXIMUM_GAIN 0x3c -#define S5K83A_FLIP_MASK 0x10 +#define S5K83A_DEFAULT_GAIN 0x71 +#define S5K83A_DEFAULT_BRIGHTNESS 0x7e +#define S5K83A_DEFAULT_EXPOSURE 0x00 +#define S5K83A_MAXIMUM_EXPOSURE 0x3c +#define S5K83A_FLIP_MASK 0x10 #define S5K83A_GPIO_LED_MASK 0x10 +#define S5K83A_GPIO_ROTATION_MASK 0x40 /*****************************************************************************/ @@ -46,20 +47,7 @@ int s5k83a_probe(struct sd *sd); int s5k83a_init(struct sd *sd); int s5k83a_start(struct sd *sd); int s5k83a_stop(struct sd *sd); -int s5k83a_power_down(struct sd *sd); - -int s5k83a_set_led_indication(struct sd *sd, u8 val); - -int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val); -int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val); -int s5k83a_set_whiteness(struct gspca_dev *gspca_dev, __s32 val); -int s5k83a_get_whiteness(struct gspca_dev *gspca_dev, __s32 *val); -int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val); -int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val); -int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val); -int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val); -int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val); -int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val); +void s5k83a_disconnect(struct sd *sd); static const struct m5602_sensor s5k83a = { .name = "S5K83A", @@ -67,11 +55,18 @@ static const struct m5602_sensor s5k83a = { .init = s5k83a_init, .start = s5k83a_start, .stop = s5k83a_stop, - .power_down = s5k83a_power_down, + .disconnect = s5k83a_disconnect, .i2c_slave_id = 0x5a, .i2c_regW = 2, }; +struct s5k83a_priv { + /* We use another thread periodically + probing the orientation of the camera */ + struct task_struct *rotation_thread; + s32 *settings; +}; + static const unsigned char preinit_s5k83a[][4] = { {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00}, @@ -108,8 +103,6 @@ static const unsigned char preinit_s5k83a[][4] = {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00}, {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00}, {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00}, - - {SENSOR, S5K83A_PAGE_MAP, 0x00, 0x00} }; /* This could probably be considerably shortened. @@ -117,173 +110,6 @@ static const unsigned char preinit_s5k83a[][4] = */ static const unsigned char init_s5k83a[][4] = { - {SENSOR, S5K83A_PAGE_MAP, 0x04, 0x00}, - {SENSOR, 0xaf, 0x01, 0x00}, - {SENSOR, S5K83A_PAGE_MAP, 0x00, 0x00}, - {SENSOR, 0x7b, 0xff, 0x00}, - {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00}, - {SENSOR, 0x01, 0x50, 0x00}, - {SENSOR, 0x12, 0x20, 0x00}, - {SENSOR, 0x17, 0x40, 0x00}, - {SENSOR, S5K83A_BRIGHTNESS, 0x0f, 0x00}, - {SENSOR, 0x1c, 0x00, 0x00}, - {SENSOR, 0x02, 0x70, 0x00}, - {SENSOR, 0x03, 0x0b, 0x00}, - {SENSOR, 0x04, 0xf0, 0x00}, - {SENSOR, 0x05, 0x0b, 0x00}, - {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00}, - - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, - {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, - {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, - {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00}, - {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0xe4, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x87, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, - - {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00}, - {SENSOR, 0x06, 0x71, 0x00}, - {SENSOR, 0x07, 0xe8, 0x00}, - {SENSOR, 0x08, 0x02, 0x00}, - {SENSOR, 0x09, 0x88, 0x00}, - {SENSOR, 0x14, 0x00, 0x00}, - {SENSOR, 0x15, 0x20, 0x00}, - {SENSOR, 0x19, 0x00, 0x00}, - {SENSOR, 0x1a, 0x98, 0x00}, - {SENSOR, 0x0f, 0x02, 0x00}, - {SENSOR, 0x10, 0xe5, 0x00}, - {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00}, - {SENSOR_LONG, 0x14, 0x00, 0x20}, - {SENSOR_LONG, 0x0d, 0x00, 0x7d}, - {SENSOR_LONG, 0x1b, 0x0d, 0x05}, - - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, - {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, - {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, - {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00}, - {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0xe4, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x87, 0x00}, - - {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, - {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00}, - {BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00}, - {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3f, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00}, - {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00}, - {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0xb0, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0x80, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, - {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, - {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, - {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00}, - {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00}, - {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT, 0x1c, 0x00}, - {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00}, - {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00}, - {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00}, - {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00}, - {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00}, - - {SENSOR, S5K83A_PAGE_MAP, 0x04, 0x00}, - {SENSOR, 0xaf, 0x01, 0x00}, - {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00}, - /* ff ( init value )is very dark) || 71 and f0 better */ - {SENSOR, 0x7b, 0xff, 0x00}, - {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00}, - {SENSOR, 0x01, 0x50, 0x00}, - {SENSOR, 0x12, 0x20, 0x00}, - {SENSOR, 0x17, 0x40, 0x00}, - {SENSOR, S5K83A_BRIGHTNESS, 0x0f, 0x00}, - {SENSOR, 0x1c, 0x00, 0x00}, - {SENSOR, 0x02, 0x70, 0x00}, - /* some values like 0x10 give a blue-purple image */ - {SENSOR, 0x03, 0x0b, 0x00}, - {SENSOR, 0x04, 0xf0, 0x00}, - {SENSOR, 0x05, 0x0b, 0x00}, - {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00}, - - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00}, - /* under 80 don't work, highter depend on value */ - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, - - {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, - {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, - {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00}, - {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0xe4, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x7f, 0x00}, - - {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, - - {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00}, - {SENSOR, 0x06, 0x71, 0x00}, - {SENSOR, 0x07, 0xe8, 0x00}, - {SENSOR, 0x08, 0x02, 0x00}, - {SENSOR, 0x09, 0x88, 0x00}, - {SENSOR, 0x14, 0x00, 0x00}, - {SENSOR, 0x15, 0x20, 0x00}, - {SENSOR, 0x19, 0x00, 0x00}, - {SENSOR, 0x1a, 0x98, 0x00}, - {SENSOR, 0x0f, 0x02, 0x00}, - {SENSOR, 0x10, 0xe5, 0x00}, - {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00}, - {SENSOR_LONG, 0x14, 0x00, 0x20}, - {SENSOR_LONG, 0x0d, 0x00, 0x7d}, - {SENSOR_LONG, 0x1b, 0x0d, 0x05}, - /* The following sequence is useless after a clean boot but is necessary after resume from suspend */ {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, @@ -320,14 +146,28 @@ static const unsigned char init_s5k83a[][4] = {SENSOR, 0x01, 0x50, 0x00}, {SENSOR, 0x12, 0x20, 0x00}, {SENSOR, 0x17, 0x40, 0x00}, - {SENSOR, S5K83A_BRIGHTNESS, 0x0f, 0x00}, {SENSOR, 0x1c, 0x00, 0x00}, {SENSOR, 0x02, 0x70, 0x00}, {SENSOR, 0x03, 0x0b, 0x00}, {SENSOR, 0x04, 0xf0, 0x00}, {SENSOR, 0x05, 0x0b, 0x00}, - {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00}, + {SENSOR, 0x06, 0x71, 0x00}, + {SENSOR, 0x07, 0xe8, 0x00}, /* 488 */ + {SENSOR, 0x08, 0x02, 0x00}, + {SENSOR, 0x09, 0x88, 0x00}, /* 648 */ + {SENSOR, 0x14, 0x00, 0x00}, + {SENSOR, 0x15, 0x20, 0x00}, /* 32 */ + {SENSOR, 0x19, 0x00, 0x00}, + {SENSOR, 0x1a, 0x98, 0x00}, /* 152 */ + {SENSOR, 0x0f, 0x02, 0x00}, + {SENSOR, 0x10, 0xe5, 0x00}, /* 741 */ + /* normal colors + (this is value after boot, but after tries can be different) */ + {SENSOR, 0x00, 0x06, 0x00}, +}; +static const unsigned char start_s5k83a[][4] = +{ {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00}, {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, @@ -340,7 +180,7 @@ static const unsigned char init_s5k83a[][4] = {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0xe4, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0xe4, 0x00}, /* 484 */ {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, @@ -348,50 +188,10 @@ static const unsigned char init_s5k83a[][4] = {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x7f, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x7f, 0x00}, /* 639 */ {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, - - {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00}, - {SENSOR, 0x06, 0x71, 0x00}, - {SENSOR, 0x07, 0xe8, 0x00}, - {SENSOR, 0x08, 0x02, 0x00}, - {SENSOR, 0x09, 0x88, 0x00}, - {SENSOR, 0x14, 0x00, 0x00}, - {SENSOR, 0x15, 0x20, 0x00}, - {SENSOR, 0x19, 0x00, 0x00}, - {SENSOR, 0x1a, 0x98, 0x00}, - {SENSOR, 0x0f, 0x02, 0x00}, - - {SENSOR, 0x10, 0xe5, 0x00}, - {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00}, - {SENSOR_LONG, 0x14, 0x00, 0x20}, - {SENSOR_LONG, 0x0d, 0x00, 0x7d}, - {SENSOR_LONG, 0x1b, 0x0d, 0x05}, - - /* normal colors - (this is value after boot, but after tries can be different) */ - {SENSOR, 0x00, 0x06, 0x00}, - - /* set default brightness */ - {SENSOR_LONG, 0x14, 0x00, 0x20}, - {SENSOR_LONG, 0x0d, 0x01, 0x00}, - {SENSOR_LONG, 0x1b, S5K83A_DEFAULT_BRIGHTNESS >> 3, - S5K83A_DEFAULT_BRIGHTNESS >> 1}, - - /* set default whiteness */ - {SENSOR, S5K83A_WHITENESS, S5K83A_DEFAULT_WHITENESS, 0x00}, - - /* set default gain */ - {SENSOR_LONG, 0x18, 0x00, S5K83A_DEFAULT_GAIN}, - - /* set default flip */ - {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00}, - {SENSOR, S5K83A_FLIP, 0x00 | S5K83A_FLIP_MASK, 0x00}, - {SENSOR, S5K83A_HFLIP_TUNE, 0x0b, 0x00}, - {SENSOR, S5K83A_VFLIP_TUNE, 0x0a, 0x00} - }; #endif diff --git a/drivers/media/video/gspca/m5602/m5602_sensor.h b/drivers/media/video/gspca/m5602/m5602_sensor.h index 0d3026936f2e..edff4f1f586f 100644 --- a/drivers/media/video/gspca/m5602/m5602_sensor.h +++ b/drivers/media/video/gspca/m5602/m5602_sensor.h @@ -21,13 +21,17 @@ #include "m5602_bridge.h" +#define M5602_V4L2_CID_GREEN_BALANCE (V4L2_CID_PRIVATE_BASE + 0) +#define M5602_V4L2_CID_NOISE_SUPPRESION (V4L2_CID_PRIVATE_BASE + 1) + /* Enumerates all supported sensors */ enum sensors { OV9650_SENSOR = 1, S5K83A_SENSOR = 2, S5K4AA_SENSOR = 3, MT9M111_SENSOR = 4, - PO1030_SENSOR = 5 + PO1030_SENSOR = 5, + OV7660_SENSOR = 6, }; /* Enumerates all possible instruction types */ @@ -61,9 +65,6 @@ struct m5602_sensor { /* Executed when the device is disconnected */ void (*disconnect)(struct sd *sd); - - /* Performs a power down sequence */ - int (*power_down)(struct sd *sd); }; #endif diff --git a/drivers/media/video/gspca/mr97310a.c b/drivers/media/video/gspca/mr97310a.c index 2a901a4a6f00..30132513400c 100644 --- a/drivers/media/video/gspca/mr97310a.c +++ b/drivers/media/video/gspca/mr97310a.c @@ -321,6 +321,7 @@ static const struct sd_desc sd_desc = { /* -- module initialisation -- */ static const __devinitdata struct usb_device_id device_table[] = { {USB_DEVICE(0x08ca, 0x0111)}, + {USB_DEVICE(0x093a, 0x010f)}, {} }; MODULE_DEVICE_TABLE(usb, device_table); @@ -347,8 +348,11 @@ static struct usb_driver sd_driver = { /* -- module insert / remove -- */ static int __init sd_mod_init(void) { - if (usb_register(&sd_driver) < 0) - return -1; + int ret; + + ret = usb_register(&sd_driver); + if (ret < 0) + return ret; PDEBUG(D_PROBE, "registered"); return 0; } diff --git a/drivers/media/video/gspca/ov519.c b/drivers/media/video/gspca/ov519.c index 1fff37b79891..2f6e135d94bc 100644 --- a/drivers/media/video/gspca/ov519.c +++ b/drivers/media/video/gspca/ov519.c @@ -50,6 +50,19 @@ static int i2c_detect_tries = 10; struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ + __u8 packet_nr; + + char bridge; +#define BRIDGE_OV511 0 +#define BRIDGE_OV511PLUS 1 +#define BRIDGE_OV518 2 +#define BRIDGE_OV518PLUS 3 +#define BRIDGE_OV519 4 +#define BRIDGE_MASK 7 + + char invert_led; +#define BRIDGE_INVERT_LED 8 + /* Determined by sensor type */ __u8 sif; @@ -58,22 +71,25 @@ struct sd { __u8 colors; __u8 hflip; __u8 vflip; + __u8 autobrightness; + __u8 freq; __u8 stopped; /* Streaming is temporarily paused */ - __u8 frame_rate; /* current Framerate (OV519 only) */ - __u8 clockdiv; /* clockdiv override for OV519 only */ + __u8 frame_rate; /* current Framerate */ + __u8 clockdiv; /* clockdiv override */ 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_OV7640 5 -#define SEN_OV7670 6 -#define SEN_OV76BE 7 -#define SEN_OV8610 8 +#define SEN_OV66308AF 3 +#define SEN_OV7610 4 +#define SEN_OV7620 5 +#define SEN_OV7640 6 +#define SEN_OV7670 7 +#define SEN_OV76BE 8 +#define SEN_OV8610 9 }; /* V4L2 controls supported by the driver */ @@ -87,8 +103,17 @@ static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val); static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val); static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val); static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setautobrightness(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getautobrightness(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 void setbrightness(struct gspca_dev *gspca_dev); +static void setcontrast(struct gspca_dev *gspca_dev); +static void setcolors(struct gspca_dev *gspca_dev); +static void setautobrightness(struct sd *sd); +static void setfreq(struct sd *sd); -static struct ctrl sd_ctrls[] = { +static const struct ctrl sd_ctrls[] = { { { .id = V4L2_CID_BRIGHTNESS, @@ -131,7 +156,7 @@ static struct ctrl sd_ctrls[] = { .set = sd_setcolors, .get = sd_getcolors, }, -/* next controls work with ov7670 only */ +/* The flip controls work with ov7670 only */ #define HFLIP_IDX 3 { { @@ -162,9 +187,54 @@ static struct ctrl sd_ctrls[] = { .set = sd_setvflip, .get = sd_getvflip, }, +#define AUTOBRIGHT_IDX 5 + { + { + .id = V4L2_CID_AUTOBRIGHTNESS, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Auto Brightness", + .minimum = 0, + .maximum = 1, + .step = 1, +#define AUTOBRIGHT_DEF 1 + .default_value = AUTOBRIGHT_DEF, + }, + .set = sd_setautobrightness, + .get = sd_getautobrightness, + }, +#define FREQ_IDX 6 + { + { + .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 0 + .default_value = FREQ_DEF, + }, + .set = sd_setfreq, + .get = sd_getfreq, + }, +#define OV7670_FREQ_IDX 7 + { + { + .id = V4L2_CID_POWER_LINE_FREQUENCY, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Light frequency filter", + .minimum = 0, + .maximum = 3, /* 0: 0, 1: 50Hz, 2:60Hz 3: Auto Hz */ + .step = 1, +#define OV7670_FREQ_DEF 3 + .default_value = OV7670_FREQ_DEF, + }, + .set = sd_setfreq, + .get = sd_getfreq, + }, }; -static const struct v4l2_pix_format vga_mode[] = { +static const struct v4l2_pix_format ov519_vga_mode[] = { {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, .bytesperline = 320, .sizeimage = 320 * 240 * 3 / 8 + 590, @@ -176,12 +246,22 @@ static const struct v4l2_pix_format vga_mode[] = { .colorspace = V4L2_COLORSPACE_JPEG, .priv = 0}, }; -static const struct v4l2_pix_format sif_mode[] = { +static const struct v4l2_pix_format ov519_sif_mode[] = { + {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 160 * 120 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 3}, {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, .bytesperline = 176, .sizeimage = 176 * 144 * 3 / 8 + 590, .colorspace = V4L2_COLORSPACE_JPEG, .priv = 1}, + {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, @@ -189,6 +269,123 @@ static const struct v4l2_pix_format sif_mode[] = { .priv = 0}, }; +/* Note some of the sizeimage values for the ov511 / ov518 may seem + larger then necessary, however they need to be this big as the ov511 / + ov518 always fills the entire isoc frame, using 0 padding bytes when + it doesn't have any data. So with low framerates the amount of data + transfered can become quite large (libv4l will remove all the 0 padding + in userspace). */ +static const struct v4l2_pix_format ov518_vga_mode[] = { + {320, 240, V4L2_PIX_FMT_OV518, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 3, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 1}, + {640, 480, V4L2_PIX_FMT_OV518, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480 * 2, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 0}, +}; +static const struct v4l2_pix_format ov518_sif_mode[] = { + {160, 120, V4L2_PIX_FMT_OV518, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 70000, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 3}, + {176, 144, V4L2_PIX_FMT_OV518, V4L2_FIELD_NONE, + .bytesperline = 176, + .sizeimage = 70000, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 1}, + {320, 240, V4L2_PIX_FMT_OV518, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 3, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 2}, + {352, 288, V4L2_PIX_FMT_OV518, V4L2_FIELD_NONE, + .bytesperline = 352, + .sizeimage = 352 * 288 * 3, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 0}, +}; + +static const struct v4l2_pix_format ov511_vga_mode[] = { + {320, 240, V4L2_PIX_FMT_OV511, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 3, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 1}, + {640, 480, V4L2_PIX_FMT_OV511, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480 * 2, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 0}, +}; +static const struct v4l2_pix_format ov511_sif_mode[] = { + {160, 120, V4L2_PIX_FMT_OV511, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 70000, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 3}, + {176, 144, V4L2_PIX_FMT_OV511, V4L2_FIELD_NONE, + .bytesperline = 176, + .sizeimage = 70000, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 1}, + {320, 240, V4L2_PIX_FMT_OV511, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 3, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 2}, + {352, 288, V4L2_PIX_FMT_OV511, V4L2_FIELD_NONE, + .bytesperline = 352, + .sizeimage = 352 * 288 * 3, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 0}, +}; + +/* Registers common to OV511 / OV518 */ +#define R51x_FIFO_PSIZE 0x30 /* 2 bytes wide w/ OV518(+) */ +#define R51x_SYS_RESET 0x50 + /* Reset type flags */ + #define OV511_RESET_OMNICE 0x08 +#define R51x_SYS_INIT 0x53 +#define R51x_SYS_SNAP 0x52 +#define R51x_SYS_CUST_ID 0x5F +#define R51x_COMP_LUT_BEGIN 0x80 + +/* OV511 Camera interface register numbers */ +#define R511_CAM_DELAY 0x10 +#define R511_CAM_EDGE 0x11 +#define R511_CAM_PXCNT 0x12 +#define R511_CAM_LNCNT 0x13 +#define R511_CAM_PXDIV 0x14 +#define R511_CAM_LNDIV 0x15 +#define R511_CAM_UV_EN 0x16 +#define R511_CAM_LINE_MODE 0x17 +#define R511_CAM_OPTS 0x18 + +#define R511_SNAP_FRAME 0x19 +#define R511_SNAP_PXCNT 0x1A +#define R511_SNAP_LNCNT 0x1B +#define R511_SNAP_PXDIV 0x1C +#define R511_SNAP_LNDIV 0x1D +#define R511_SNAP_UV_EN 0x1E +#define R511_SNAP_UV_EN 0x1E +#define R511_SNAP_OPTS 0x1F + +#define R511_DRAM_FLOW_CTL 0x20 +#define R511_FIFO_OPTS 0x31 +#define R511_I2C_CTL 0x40 +#define R511_SYS_LED_CTL 0x55 /* OV511+ only */ +#define R511_COMP_EN 0x78 +#define R511_COMP_LUT_EN 0x79 + +/* OV518 Camera interface register numbers */ +#define R518_GPIO_OUT 0x56 /* OV518(+) only */ +#define R518_GPIO_CTL 0x57 /* OV518(+) only */ + /* OV519 Camera interface register numbers */ #define OV519_R10_H_SIZE 0x10 #define OV519_R11_V_SIZE 0x11 @@ -224,6 +421,8 @@ static const struct v4l2_pix_format sif_mode[] = { /* OV7610 registers */ #define OV7610_REG_GAIN 0x00 /* gain setting (5:0) */ +#define OV7610_REG_BLUE 0x01 /* blue channel balance */ +#define OV7610_REG_RED 0x02 /* red channel balance */ #define OV7610_REG_SAT 0x03 /* saturation */ #define OV8610_REG_HUE 0x04 /* 04 reserved */ #define OV7610_REG_CNT 0x05 /* Y contrast */ @@ -330,7 +529,7 @@ static const struct ov_i2c_regvals norm_6x20[] = { { 0x28, 0x05 }, { 0x2a, 0x04 }, /* Disable framerate adjust */ /* { 0x2b, 0xac }, * Framerate; Set 2a[7] first */ - { 0x2d, 0x99 }, + { 0x2d, 0x85 }, { 0x33, 0xa0 }, /* Color Processing Parameter */ { 0x34, 0xd2 }, /* Max A/D range */ { 0x38, 0x8b }, @@ -363,7 +562,7 @@ static const struct ov_i2c_regvals norm_6x30[] = { { 0x07, 0x2d }, /* Sharpness */ { 0x0c, 0x20 }, { 0x0d, 0x20 }, - { 0x0e, 0x20 }, + { 0x0e, 0xa0 }, /* Was 0x20, bit7 enables a 2x gain which we need */ { 0x0f, 0x05 }, { 0x10, 0x9a }, { 0x11, 0x00 }, /* Pixel clock = fastest */ @@ -505,7 +704,7 @@ static const struct ov_i2c_regvals norm_7620[] = { { 0x23, 0x00 }, { 0x26, 0xa2 }, { 0x27, 0xea }, - { 0x28, 0x20 }, + { 0x28, 0x22 }, /* Was 0x20, bit1 enables a 2x gain which we need */ { 0x29, 0x00 }, { 0x2a, 0x10 }, { 0x2b, 0x00 }, @@ -846,11 +1045,12 @@ static unsigned char ov7670_abs_to_sm(unsigned char v) static int reg_w(struct sd *sd, __u16 index, __u8 value) { int ret; + int req = (sd->bridge <= BRIDGE_OV511PLUS) ? 2 : 1; 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) */ + req, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, index, sd->gspca_dev.usb_buf, 1, 500); @@ -864,10 +1064,11 @@ static int reg_w(struct sd *sd, __u16 index, __u8 value) static int reg_r(struct sd *sd, __u16 index) { int ret; + int req = (sd->bridge <= BRIDGE_OV511PLUS) ? 3 : 1; ret = usb_control_msg(sd->gspca_dev.dev, usb_rcvctrlpipe(sd->gspca_dev.dev, 0), - 1, /* REQ_IO */ + req, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, index, sd->gspca_dev.usb_buf, 1, 500); @@ -923,12 +1124,149 @@ static int reg_w_mask(struct sd *sd, return reg_w(sd, index, value); } +/* + * Writes multiple (n) byte value to a single register. Only valid with certain + * registers (0x30 and 0xc4 - 0xce). + */ +static int ov518_reg_w32(struct sd *sd, __u16 index, u32 value, int n) +{ + int ret; + + *((u32 *)sd->gspca_dev.usb_buf) = __cpu_to_le32(value); + + ret = usb_control_msg(sd->gspca_dev.dev, + usb_sndctrlpipe(sd->gspca_dev.dev, 0), + 1 /* REG_IO */, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, index, + sd->gspca_dev.usb_buf, n, 500); + if (ret < 0) + PDEBUG(D_ERR, "Write reg32 [%02x] %08x failed", index, value); + return ret; +} + +static int ov511_i2c_w(struct sd *sd, __u8 reg, __u8 value) +{ + int rc, retries; + + PDEBUG(D_USBO, "i2c 0x%02x -> [0x%02x]", value, reg); + + /* Three byte write cycle */ + for (retries = 6; ; ) { + /* 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, R511_I2C_CTL, 0x01); + if (rc < 0) + return rc; + + do + rc = reg_r(sd, R511_I2C_CTL); + while (rc > 0 && ((rc & 1) == 0)); /* Retry until idle */ + + if (rc < 0) + return rc; + + if ((rc & 2) == 0) /* Ack? */ + break; + if (--retries < 0) { + PDEBUG(D_USBO, "i2c write retries exhausted"); + return -1; + } + } + + return 0; +} + +static int ov511_i2c_r(struct sd *sd, __u8 reg) +{ + int rc, value, retries; + + /* Two byte write cycle */ + for (retries = 6; ; ) { + /* 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, R511_I2C_CTL, 0x03); + if (rc < 0) + return rc; + + do + rc = reg_r(sd, R511_I2C_CTL); + while (rc > 0 && ((rc & 1) == 0)); /* Retry until idle */ + + if (rc < 0) + return rc; + + if ((rc & 2) == 0) /* Ack? */ + break; + + /* I2C abort */ + reg_w(sd, R511_I2C_CTL, 0x10); + + if (--retries < 0) { + PDEBUG(D_USBI, "i2c write retries exhausted"); + return -1; + } + } + + /* Two byte read cycle */ + for (retries = 6; ; ) { + /* Initiate 2-byte read cycle */ + rc = reg_w(sd, R511_I2C_CTL, 0x05); + if (rc < 0) + return rc; + + do + rc = reg_r(sd, R511_I2C_CTL); + while (rc > 0 && ((rc & 1) == 0)); /* Retry until idle */ + + if (rc < 0) + return rc; + + if ((rc & 2) == 0) /* Ack? */ + break; + + /* I2C abort */ + rc = reg_w(sd, R511_I2C_CTL, 0x10); + if (rc < 0) + return rc; + + if (--retries < 0) { + PDEBUG(D_USBI, "i2c read retries exhausted"); + return -1; + } + } + + value = reg_r(sd, R51x_I2C_DATA); + + PDEBUG(D_USBI, "i2c [0x%02X] -> 0x%02X", reg, value); + + /* This is needed to make i2c_w() work */ + rc = reg_w(sd, R511_I2C_CTL, 0x05); + if (rc < 0) + return rc; + + return 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, +static int ov518_i2c_w(struct sd *sd, __u8 reg, __u8 value) { @@ -963,7 +1301,7 @@ static int i2c_w(struct sd *sd, * 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) +static int ov518_i2c_r(struct sd *sd, __u8 reg) { int rc, value; @@ -986,6 +1324,34 @@ static int i2c_r(struct sd *sd, __u8 reg) return value; } +static int i2c_w(struct sd *sd, __u8 reg, __u8 value) +{ + switch (sd->bridge) { + case BRIDGE_OV511: + case BRIDGE_OV511PLUS: + return ov511_i2c_w(sd, reg, value); + case BRIDGE_OV518: + case BRIDGE_OV518PLUS: + case BRIDGE_OV519: + return ov518_i2c_w(sd, reg, value); + } + return -1; /* Should never happen */ +} + +static int i2c_r(struct sd *sd, __u8 reg) +{ + switch (sd->bridge) { + case BRIDGE_OV511: + case BRIDGE_OV511PLUS: + return ov511_i2c_r(sd, reg); + case BRIDGE_OV518: + case BRIDGE_OV518PLUS: + case BRIDGE_OV519: + return ov518_i2c_r(sd, reg); + } + return -1; /* Should never happen */ +} + /* 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 @@ -1014,20 +1380,47 @@ static inline int ov51x_stop(struct sd *sd) { PDEBUG(D_STREAM, "stopping"); sd->stopped = 1; - return reg_w(sd, OV519_SYS_RESET1, 0x0f); + switch (sd->bridge) { + case BRIDGE_OV511: + case BRIDGE_OV511PLUS: + return reg_w(sd, R51x_SYS_RESET, 0x3d); + case BRIDGE_OV518: + case BRIDGE_OV518PLUS: + return reg_w_mask(sd, R51x_SYS_RESET, 0x3a, 0x3a); + case BRIDGE_OV519: + return reg_w(sd, OV519_SYS_RESET1, 0x0f); + } + + return 0; } /* 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) { + int rc; + PDEBUG(D_STREAM, "restarting"); if (!sd->stopped) return 0; sd->stopped = 0; /* Reinitialize the stream */ - return reg_w(sd, OV519_SYS_RESET1, 0x00); + switch (sd->bridge) { + case BRIDGE_OV511: + case BRIDGE_OV511PLUS: + return reg_w(sd, R51x_SYS_RESET, 0x00); + case BRIDGE_OV518: + case BRIDGE_OV518PLUS: + rc = reg_w(sd, 0x2f, 0x80); + if (rc < 0) + return rc; + return reg_w(sd, R51x_SYS_RESET, 0x00); + case BRIDGE_OV519: + return reg_w(sd, OV519_SYS_RESET1, 0x00); + } + + return 0; } /* This does an initial reset of an OmniVision sensor and ensures that I2C @@ -1138,7 +1531,6 @@ static int ov8xx0_configure(struct sd *sd) } /* Set sensor-specific vars */ -/* sd->sif = 0; already done */ return 0; } @@ -1175,15 +1567,13 @@ static int ov7xx0_configure(struct sd *sd) } } else if ((rc & 3) == 1) { /* I don't know what's different about the 76BE yet. */ - if (i2c_r(sd, 0x15) & 1) + if (i2c_r(sd, 0x15) & 1) { PDEBUG(D_PROBE, "Sensor is an OV7620AE"); - else + sd->sensor = SEN_OV7620; + } 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; + sd->sensor = SEN_OV76BE; + } } else if ((rc & 3) == 0) { /* try to read product id registers */ high = i2c_r(sd, 0x0a); @@ -1229,7 +1619,6 @@ static int ov7xx0_configure(struct sd *sd) } /* Set sensor-specific vars */ -/* sd->sif = 0; already done */ return 0; } @@ -1258,13 +1647,14 @@ static int ov6xx0_configure(struct sd *sd) break; case 0x01: sd->sensor = SEN_OV6620; + PDEBUG(D_PROBE, "Sensor is an OV6620"); break; case 0x02: sd->sensor = SEN_OV6630; PDEBUG(D_PROBE, "Sensor is an OV66308AE"); break; case 0x03: - sd->sensor = SEN_OV6630; + sd->sensor = SEN_OV66308AF; PDEBUG(D_PROBE, "Sensor is an OV66308AF"); break; case 0x90: @@ -1287,16 +1677,276 @@ static int ov6xx0_configure(struct sd *sd) /* Turns on or off the LED. Only has an effect with OV511+/OV518(+)/OV519 */ static void ov51x_led_control(struct sd *sd, int on) { - reg_w_mask(sd, OV519_GPIO_DATA_OUT0, !on, 1); /* 0 / 1 */ + if (sd->invert_led) + on = !on; + + switch (sd->bridge) { + /* OV511 has no LED control */ + case BRIDGE_OV511PLUS: + reg_w(sd, R511_SYS_LED_CTL, on ? 1 : 0); + break; + case BRIDGE_OV518: + case BRIDGE_OV518PLUS: + reg_w_mask(sd, R518_GPIO_OUT, on ? 0x02 : 0x00, 0x02); + break; + case BRIDGE_OV519: + reg_w_mask(sd, OV519_GPIO_DATA_OUT0, !on, 1); /* 0 / 1 */ + break; + } } -/* this function is called at probe time */ -static int sd_config(struct gspca_dev *gspca_dev, - const struct usb_device_id *id) +static int ov51x_upload_quan_tables(struct sd *sd) +{ + const unsigned char yQuanTable511[] = { + 0, 1, 1, 2, 2, 3, 3, 4, + 1, 1, 1, 2, 2, 3, 4, 4, + 1, 1, 2, 2, 3, 4, 4, 4, + 2, 2, 2, 3, 4, 4, 4, 4, + 2, 2, 3, 4, 4, 5, 5, 5, + 3, 3, 4, 4, 5, 5, 5, 5, + 3, 4, 4, 4, 5, 5, 5, 5, + 4, 4, 4, 4, 5, 5, 5, 5 + }; + + const unsigned char uvQuanTable511[] = { + 0, 2, 2, 3, 4, 4, 4, 4, + 2, 2, 2, 4, 4, 4, 4, 4, + 2, 2, 3, 4, 4, 4, 4, 4, + 3, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4 + }; + + /* OV518 quantization tables are 8x4 (instead of 8x8) */ + const unsigned char yQuanTable518[] = { + 5, 4, 5, 6, 6, 7, 7, 7, + 5, 5, 5, 5, 6, 7, 7, 7, + 6, 6, 6, 6, 7, 7, 7, 8, + 7, 7, 6, 7, 7, 7, 8, 8 + }; + + const unsigned char uvQuanTable518[] = { + 6, 6, 6, 7, 7, 7, 7, 7, + 6, 6, 6, 7, 7, 7, 7, 7, + 6, 6, 6, 7, 7, 7, 7, 8, + 7, 7, 7, 7, 7, 7, 8, 8 + }; + + const unsigned char *pYTable, *pUVTable; + unsigned char val0, val1; + int i, size, rc, reg = R51x_COMP_LUT_BEGIN; + + PDEBUG(D_PROBE, "Uploading quantization tables"); + + if (sd->bridge == BRIDGE_OV511 || sd->bridge == BRIDGE_OV511PLUS) { + pYTable = yQuanTable511; + pUVTable = uvQuanTable511; + size = 32; + } else { + pYTable = yQuanTable518; + pUVTable = uvQuanTable518; + size = 16; + } + + for (i = 0; i < size; i++) { + val0 = *pYTable++; + val1 = *pYTable++; + val0 &= 0x0f; + val1 &= 0x0f; + val0 |= val1 << 4; + rc = reg_w(sd, reg, val0); + if (rc < 0) + return rc; + + val0 = *pUVTable++; + val1 = *pUVTable++; + val0 &= 0x0f; + val1 &= 0x0f; + val0 |= val1 << 4; + rc = reg_w(sd, reg + size, val0); + if (rc < 0) + return rc; + + reg++; + } + + return 0; +} + +/* This initializes the OV511/OV511+ and the sensor */ +static int ov511_configure(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - struct cam *cam; + int rc; + /* For 511 and 511+ */ + const struct ov_regvals init_511[] = { + { R51x_SYS_RESET, 0x7f }, + { R51x_SYS_INIT, 0x01 }, + { R51x_SYS_RESET, 0x7f }, + { R51x_SYS_INIT, 0x01 }, + { R51x_SYS_RESET, 0x3f }, + { R51x_SYS_INIT, 0x01 }, + { R51x_SYS_RESET, 0x3d }, + }; + + const struct ov_regvals norm_511[] = { + { R511_DRAM_FLOW_CTL, 0x01 }, + { R51x_SYS_SNAP, 0x00 }, + { R51x_SYS_SNAP, 0x02 }, + { R51x_SYS_SNAP, 0x00 }, + { R511_FIFO_OPTS, 0x1f }, + { R511_COMP_EN, 0x00 }, + { R511_COMP_LUT_EN, 0x03 }, + }; + + const struct ov_regvals norm_511_p[] = { + { R511_DRAM_FLOW_CTL, 0xff }, + { R51x_SYS_SNAP, 0x00 }, + { R51x_SYS_SNAP, 0x02 }, + { R51x_SYS_SNAP, 0x00 }, + { R511_FIFO_OPTS, 0xff }, + { R511_COMP_EN, 0x00 }, + { R511_COMP_LUT_EN, 0x03 }, + }; + + const struct ov_regvals compress_511[] = { + { 0x70, 0x1f }, + { 0x71, 0x05 }, + { 0x72, 0x06 }, + { 0x73, 0x06 }, + { 0x74, 0x14 }, + { 0x75, 0x03 }, + { 0x76, 0x04 }, + { 0x77, 0x04 }, + }; + + PDEBUG(D_PROBE, "Device custom id %x", reg_r(sd, R51x_SYS_CUST_ID)); + + rc = write_regvals(sd, init_511, ARRAY_SIZE(init_511)); + if (rc < 0) + return rc; + + switch (sd->bridge) { + case BRIDGE_OV511: + rc = write_regvals(sd, norm_511, ARRAY_SIZE(norm_511)); + if (rc < 0) + return rc; + break; + case BRIDGE_OV511PLUS: + rc = write_regvals(sd, norm_511_p, ARRAY_SIZE(norm_511_p)); + if (rc < 0) + return rc; + break; + } + + /* Init compression */ + rc = write_regvals(sd, compress_511, ARRAY_SIZE(compress_511)); + if (rc < 0) + return rc; + + rc = ov51x_upload_quan_tables(sd); + if (rc < 0) { + PDEBUG(D_ERR, "Error uploading quantization tables"); + return rc; + } + + return 0; +} + +/* This initializes the OV518/OV518+ and the sensor */ +static int ov518_configure(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int rc; + + /* For 518 and 518+ */ + const struct ov_regvals init_518[] = { + { R51x_SYS_RESET, 0x40 }, + { R51x_SYS_INIT, 0xe1 }, + { R51x_SYS_RESET, 0x3e }, + { R51x_SYS_INIT, 0xe1 }, + { R51x_SYS_RESET, 0x00 }, + { R51x_SYS_INIT, 0xe1 }, + { 0x46, 0x00 }, + { 0x5d, 0x03 }, + }; + + const struct ov_regvals norm_518[] = { + { R51x_SYS_SNAP, 0x02 }, /* Reset */ + { R51x_SYS_SNAP, 0x01 }, /* Enable */ + { 0x31, 0x0f }, + { 0x5d, 0x03 }, + { 0x24, 0x9f }, + { 0x25, 0x90 }, + { 0x20, 0x00 }, + { 0x51, 0x04 }, + { 0x71, 0x19 }, + { 0x2f, 0x80 }, + }; + + const struct ov_regvals norm_518_p[] = { + { R51x_SYS_SNAP, 0x02 }, /* Reset */ + { R51x_SYS_SNAP, 0x01 }, /* Enable */ + { 0x31, 0x0f }, + { 0x5d, 0x03 }, + { 0x24, 0x9f }, + { 0x25, 0x90 }, + { 0x20, 0x60 }, + { 0x51, 0x02 }, + { 0x71, 0x19 }, + { 0x40, 0xff }, + { 0x41, 0x42 }, + { 0x46, 0x00 }, + { 0x33, 0x04 }, + { 0x21, 0x19 }, + { 0x3f, 0x10 }, + { 0x2f, 0x80 }, + }; + + /* First 5 bits of custom ID reg are a revision ID on OV518 */ + PDEBUG(D_PROBE, "Device revision %d", + 0x1F & reg_r(sd, R51x_SYS_CUST_ID)); + + rc = write_regvals(sd, init_518, ARRAY_SIZE(init_518)); + if (rc < 0) + return rc; + + /* Set LED GPIO pin to output mode */ + rc = reg_w_mask(sd, R518_GPIO_CTL, 0x00, 0x02); + if (rc < 0) + return rc; + + switch (sd->bridge) { + case BRIDGE_OV518: + rc = write_regvals(sd, norm_518, ARRAY_SIZE(norm_518)); + if (rc < 0) + return rc; + break; + case BRIDGE_OV518PLUS: + rc = write_regvals(sd, norm_518_p, ARRAY_SIZE(norm_518_p)); + if (rc < 0) + return rc; + break; + } + + rc = ov51x_upload_quan_tables(sd); + if (rc < 0) { + PDEBUG(D_ERR, "Error uploading quantization tables"); + return rc; + } + + rc = reg_w(sd, 0x2f, 0x80); + if (rc < 0) + return rc; + + return 0; +} + +static int ov519_configure(struct sd *sd) +{ static const struct ov_regvals init_519[] = { { 0x5a, 0x6d }, /* EnableSystem */ { 0x53, 0x9b }, @@ -1313,8 +1963,37 @@ static int sd_config(struct gspca_dev *gspca_dev, /* windows reads 0x55 at this point*/ }; - if (write_regvals(sd, init_519, ARRAY_SIZE(init_519))) + return write_regvals(sd, init_519, ARRAY_SIZE(init_519)); +} + +/* 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 ret = 0; + + sd->bridge = id->driver_info & BRIDGE_MASK; + sd->invert_led = id->driver_info & BRIDGE_INVERT_LED; + + switch (sd->bridge) { + case BRIDGE_OV511: + case BRIDGE_OV511PLUS: + ret = ov511_configure(gspca_dev); + break; + case BRIDGE_OV518: + case BRIDGE_OV518PLUS: + ret = ov518_configure(gspca_dev); + break; + case BRIDGE_OV519: + ret = ov519_configure(sd); + break; + } + + if (ret) goto error; + ov51x_led_control(sd, 0); /* turn LED off */ /* Test for 76xx */ @@ -1360,21 +2039,60 @@ static int sd_config(struct gspca_dev *gspca_dev, } cam = &gspca_dev->cam; - if (!sd->sif) { - cam->cam_mode = vga_mode; - cam->nmodes = ARRAY_SIZE(vga_mode); - } else { - cam->cam_mode = sif_mode; - cam->nmodes = ARRAY_SIZE(sif_mode); + switch (sd->bridge) { + case BRIDGE_OV511: + case BRIDGE_OV511PLUS: + if (!sd->sif) { + cam->cam_mode = ov511_vga_mode; + cam->nmodes = ARRAY_SIZE(ov511_vga_mode); + } else { + cam->cam_mode = ov511_sif_mode; + cam->nmodes = ARRAY_SIZE(ov511_sif_mode); + } + break; + case BRIDGE_OV518: + case BRIDGE_OV518PLUS: + if (!sd->sif) { + cam->cam_mode = ov518_vga_mode; + cam->nmodes = ARRAY_SIZE(ov518_vga_mode); + } else { + cam->cam_mode = ov518_sif_mode; + cam->nmodes = ARRAY_SIZE(ov518_sif_mode); + } + break; + case BRIDGE_OV519: + if (!sd->sif) { + cam->cam_mode = ov519_vga_mode; + cam->nmodes = ARRAY_SIZE(ov519_vga_mode); + } else { + cam->cam_mode = ov519_sif_mode; + cam->nmodes = ARRAY_SIZE(ov519_sif_mode); + } + break; } sd->brightness = BRIGHTNESS_DEF; - sd->contrast = CONTRAST_DEF; + if (sd->sensor == SEN_OV6630 || sd->sensor == SEN_OV66308AF) + sd->contrast = 200; /* The default is too low for the ov6630 */ + else + sd->contrast = CONTRAST_DEF; sd->colors = COLOR_DEF; sd->hflip = HFLIP_DEF; sd->vflip = VFLIP_DEF; - if (sd->sensor != SEN_OV7670) - gspca_dev->ctrl_dis = (1 << HFLIP_IDX) - | (1 << VFLIP_IDX); + sd->autobrightness = AUTOBRIGHT_DEF; + if (sd->sensor == SEN_OV7670) { + sd->freq = OV7670_FREQ_DEF; + gspca_dev->ctrl_dis = 1 << FREQ_IDX; + } else { + sd->freq = FREQ_DEF; + gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX) | + (1 << OV7670_FREQ_IDX); + } + if (sd->sensor == SEN_OV7640 || sd->sensor == SEN_OV7670) + gspca_dev->ctrl_dis |= 1 << AUTOBRIGHT_IDX; + /* OV8610 Frequency filter control should work but needs testing */ + if (sd->sensor == SEN_OV8610) + gspca_dev->ctrl_dis |= 1 << FREQ_IDX; + return 0; error: PDEBUG(D_ERR, "OV519 Config failed"); @@ -1393,6 +2111,7 @@ static int sd_init(struct gspca_dev *gspca_dev) return -EIO; break; case SEN_OV6630: + case SEN_OV66308AF: if (write_i2c_regvals(sd, norm_6x30, ARRAY_SIZE(norm_6x30))) return -EIO; break; @@ -1401,6 +2120,8 @@ static int sd_init(struct gspca_dev *gspca_dev) /* case SEN_OV76BE: */ if (write_i2c_regvals(sd, norm_7610, ARRAY_SIZE(norm_7610))) return -EIO; + if (i2c_w_mask(sd, 0x0e, 0x00, 0x40)) + return -EIO; break; case SEN_OV7620: if (write_i2c_regvals(sd, norm_7620, ARRAY_SIZE(norm_7620))) @@ -1422,6 +2143,248 @@ static int sd_init(struct gspca_dev *gspca_dev) return 0; } +/* Set up the OV511/OV511+ with the given image parameters. + * + * Do not put any sensor-specific code in here (including I2C I/O functions) + */ +static int ov511_mode_init_regs(struct sd *sd) +{ + int hsegs, vsegs, packet_size, fps, needed; + int interlaced = 0; + struct usb_host_interface *alt; + struct usb_interface *intf; + + intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface); + alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt); + if (!alt) { + PDEBUG(D_ERR, "Couldn't get altsetting"); + return -EIO; + } + + packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); + reg_w(sd, R51x_FIFO_PSIZE, packet_size >> 5); + + reg_w(sd, R511_CAM_UV_EN, 0x01); + reg_w(sd, R511_SNAP_UV_EN, 0x01); + reg_w(sd, R511_SNAP_OPTS, 0x03); + + /* Here I'm assuming that snapshot size == image size. + * I hope that's always true. --claudio + */ + hsegs = (sd->gspca_dev.width >> 3) - 1; + vsegs = (sd->gspca_dev.height >> 3) - 1; + + reg_w(sd, R511_CAM_PXCNT, hsegs); + reg_w(sd, R511_CAM_LNCNT, vsegs); + reg_w(sd, R511_CAM_PXDIV, 0x00); + reg_w(sd, R511_CAM_LNDIV, 0x00); + + /* YUV420, low pass filter on */ + reg_w(sd, R511_CAM_OPTS, 0x03); + + /* Snapshot additions */ + reg_w(sd, R511_SNAP_PXCNT, hsegs); + reg_w(sd, R511_SNAP_LNCNT, vsegs); + reg_w(sd, R511_SNAP_PXDIV, 0x00); + reg_w(sd, R511_SNAP_LNDIV, 0x00); + + /******** Set the framerate ********/ + if (frame_rate > 0) + sd->frame_rate = frame_rate; + + switch (sd->sensor) { + case SEN_OV6620: + /* No framerate control, doesn't like higher rates yet */ + sd->clockdiv = 3; + break; + + /* Note once the FIXME's in mode_init_ov_sensor_regs() are fixed + for more sensors we need to do this for them too */ + case SEN_OV7620: + case SEN_OV7640: + case SEN_OV76BE: + if (sd->gspca_dev.width == 320) + interlaced = 1; + /* Fall through */ + case SEN_OV6630: + case SEN_OV7610: + case SEN_OV7670: + switch (sd->frame_rate) { + case 30: + case 25: + /* Not enough bandwidth to do 640x480 @ 30 fps */ + if (sd->gspca_dev.width != 640) { + sd->clockdiv = 0; + break; + } + /* Fall through for 640x480 case */ + default: +/* case 20: */ +/* case 15: */ + sd->clockdiv = 1; + break; + case 10: + sd->clockdiv = 2; + break; + case 5: + sd->clockdiv = 5; + break; + } + if (interlaced) { + sd->clockdiv = (sd->clockdiv + 1) * 2 - 1; + /* Higher then 10 does not work */ + if (sd->clockdiv > 10) + sd->clockdiv = 10; + } + break; + + case SEN_OV8610: + /* No framerate control ?? */ + sd->clockdiv = 0; + break; + } + + /* Check if we have enough bandwidth to disable compression */ + fps = (interlaced ? 60 : 30) / (sd->clockdiv + 1) + 1; + needed = fps * sd->gspca_dev.width * sd->gspca_dev.height * 3 / 2; + /* 1400 is a conservative estimate of the max nr of isoc packets/sec */ + if (needed > 1400 * packet_size) { + /* Enable Y and UV quantization and compression */ + reg_w(sd, R511_COMP_EN, 0x07); + reg_w(sd, R511_COMP_LUT_EN, 0x03); + } else { + reg_w(sd, R511_COMP_EN, 0x06); + reg_w(sd, R511_COMP_LUT_EN, 0x00); + } + + reg_w(sd, R51x_SYS_RESET, OV511_RESET_OMNICE); + reg_w(sd, R51x_SYS_RESET, 0); + + return 0; +} + +/* Sets up the OV518/OV518+ with the given image parameters + * + * OV518 needs a completely different approach, until we can figure out what + * the individual registers do. Also, only 15 FPS is supported now. + * + * Do not put any sensor-specific code in here (including I2C I/O functions) + */ +static int ov518_mode_init_regs(struct sd *sd) +{ + int hsegs, vsegs, packet_size; + struct usb_host_interface *alt; + struct usb_interface *intf; + + intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface); + alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt); + if (!alt) { + PDEBUG(D_ERR, "Couldn't get altsetting"); + return -EIO; + } + + packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); + ov518_reg_w32(sd, R51x_FIFO_PSIZE, packet_size & ~7, 2); + + /******** Set the mode ********/ + + reg_w(sd, 0x2b, 0); + reg_w(sd, 0x2c, 0); + reg_w(sd, 0x2d, 0); + reg_w(sd, 0x2e, 0); + reg_w(sd, 0x3b, 0); + reg_w(sd, 0x3c, 0); + reg_w(sd, 0x3d, 0); + reg_w(sd, 0x3e, 0); + + if (sd->bridge == BRIDGE_OV518) { + /* Set 8-bit (YVYU) input format */ + reg_w_mask(sd, 0x20, 0x08, 0x08); + + /* Set 12-bit (4:2:0) output format */ + reg_w_mask(sd, 0x28, 0x80, 0xf0); + reg_w_mask(sd, 0x38, 0x80, 0xf0); + } else { + reg_w(sd, 0x28, 0x80); + reg_w(sd, 0x38, 0x80); + } + + hsegs = sd->gspca_dev.width / 16; + vsegs = sd->gspca_dev.height / 4; + + reg_w(sd, 0x29, hsegs); + reg_w(sd, 0x2a, vsegs); + + reg_w(sd, 0x39, hsegs); + reg_w(sd, 0x3a, vsegs); + + /* Windows driver does this here; who knows why */ + reg_w(sd, 0x2f, 0x80); + + /******** Set the framerate ********/ + sd->clockdiv = 1; + + /* Mode independent, but framerate dependent, regs */ + /* 0x51: Clock divider; Only works on some cams which use 2 crystals */ + reg_w(sd, 0x51, 0x04); + reg_w(sd, 0x22, 0x18); + reg_w(sd, 0x23, 0xff); + + if (sd->bridge == BRIDGE_OV518PLUS) { + switch (sd->sensor) { + case SEN_OV7620: + if (sd->gspca_dev.width == 320) { + reg_w(sd, 0x20, 0x00); + reg_w(sd, 0x21, 0x19); + } else { + reg_w(sd, 0x20, 0x60); + reg_w(sd, 0x21, 0x1f); + } + break; + default: + reg_w(sd, 0x21, 0x19); + } + } else + reg_w(sd, 0x71, 0x17); /* Compression-related? */ + + /* FIXME: Sensor-specific */ + /* Bit 5 is what matters here. Of course, it is "reserved" */ + i2c_w(sd, 0x54, 0x23); + + reg_w(sd, 0x2f, 0x80); + + if (sd->bridge == BRIDGE_OV518PLUS) { + reg_w(sd, 0x24, 0x94); + reg_w(sd, 0x25, 0x90); + ov518_reg_w32(sd, 0xc4, 400, 2); /* 190h */ + ov518_reg_w32(sd, 0xc6, 540, 2); /* 21ch */ + ov518_reg_w32(sd, 0xc7, 540, 2); /* 21ch */ + ov518_reg_w32(sd, 0xc8, 108, 2); /* 6ch */ + ov518_reg_w32(sd, 0xca, 131098, 3); /* 2001ah */ + ov518_reg_w32(sd, 0xcb, 532, 2); /* 214h */ + ov518_reg_w32(sd, 0xcc, 2400, 2); /* 960h */ + ov518_reg_w32(sd, 0xcd, 32, 2); /* 20h */ + ov518_reg_w32(sd, 0xce, 608, 2); /* 260h */ + } else { + reg_w(sd, 0x24, 0x9f); + reg_w(sd, 0x25, 0x90); + ov518_reg_w32(sd, 0xc4, 400, 2); /* 190h */ + ov518_reg_w32(sd, 0xc6, 381, 2); /* 17dh */ + ov518_reg_w32(sd, 0xc7, 381, 2); /* 17dh */ + ov518_reg_w32(sd, 0xc8, 128, 2); /* 80h */ + ov518_reg_w32(sd, 0xca, 183331, 3); /* 2cc23h */ + ov518_reg_w32(sd, 0xcb, 746, 2); /* 2eah */ + ov518_reg_w32(sd, 0xcc, 1750, 2); /* 6d6h */ + ov518_reg_w32(sd, 0xcd, 45, 2); /* 2dh */ + ov518_reg_w32(sd, 0xce, 851, 2); /* 353h */ + } + + reg_w(sd, 0x2f, 0x80); + + return 0; +} + + /* Sets up the OV519 with the given image parameters * * OV519 needs a completely different approach, until we can figure out what @@ -1492,7 +2455,11 @@ static int ov519_mode_init_regs(struct sd *sd) reg_w(sd, OV519_R10_H_SIZE, sd->gspca_dev.width >> 4); reg_w(sd, OV519_R11_V_SIZE, sd->gspca_dev.height >> 3); - reg_w(sd, OV519_R12_X_OFFSETL, 0x00); + if (sd->sensor == SEN_OV7670 && + sd->gspca_dev.cam.cam_mode[sd->gspca_dev.curr_mode].priv) + reg_w(sd, OV519_R12_X_OFFSETL, 0x04); + else + reg_w(sd, OV519_R12_X_OFFSETL, 0x00); reg_w(sd, OV519_R13_X_OFFSETH, 0x00); reg_w(sd, OV519_R14_Y_OFFSETL, 0x00); reg_w(sd, OV519_R15_Y_OFFSETH, 0x00); @@ -1584,7 +2551,7 @@ static int mode_init_ov_sensor_regs(struct sd *sd) int qvga; gspca_dev = &sd->gspca_dev; - qvga = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; + qvga = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv & 1; /******** Mode (VGA/QVGA) and sensor specific regs ********/ switch (sd->sensor) { @@ -1596,21 +2563,16 @@ static int mode_init_ov_sensor_regs(struct sd *sd) i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20); break; case SEN_OV7620: -/* i2c_w(sd, 0x2b, 0x00); */ + case SEN_OV76BE: 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, 0x67, qvga ? 0xb0 : 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); */ @@ -1629,6 +2591,7 @@ static int mode_init_ov_sensor_regs(struct sd *sd) break; case SEN_OV6620: case SEN_OV6630: + case SEN_OV66308AF: i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20); break; default: @@ -1636,10 +2599,6 @@ static int mode_init_ov_sensor_regs(struct sd *sd) } /******** Palette-specific regs ********/ - 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 @@ -1649,25 +2608,12 @@ static int mode_init_ov_sensor_regs(struct sd *sd) /* OV7640 is 8-bit only */ - if (sd->sensor != SEN_OV6630 && sd->sensor != SEN_OV7640) + if (sd->sensor != SEN_OV6630 && sd->sensor != SEN_OV66308AF && + 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, sd->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 { - i2c_w(sd, 0x11, sd->clockdiv); - } + i2c_w(sd, 0x11, sd->clockdiv); /******** Special Features ********/ /* no evidence this is possible with OV7670, either */ @@ -1711,13 +2657,14 @@ static void sethvflip(struct sd *sd) static int set_ov_sensor_window(struct sd *sd) { struct gspca_dev *gspca_dev; - int qvga; + int qvga, crop; int hwsbase, hwebase, vwsbase, vwebase, hwscale, vwscale; int ret, hstart, hstop, vstop, vstart; __u8 v; gspca_dev = &sd->gspca_dev; - qvga = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; + qvga = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv & 1; + crop = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv & 2; /* The different sensor ICs handle setting up of window differently. * IF YOU SET IT WRONG, YOU WILL GET ALL ZERO ISOC DATA FROM OV51x!! */ @@ -1736,10 +2683,20 @@ static int set_ov_sensor_window(struct sd *sd) break; case SEN_OV6620: case SEN_OV6630: + case SEN_OV66308AF: hwsbase = 0x38; hwebase = 0x3a; vwsbase = 0x05; vwebase = 0x06; + if (sd->sensor == SEN_OV66308AF && qvga) + /* HDG: this fixes U and V getting swapped */ + hwsbase++; + if (crop) { + hwsbase += 8; + hwebase += 8; + vwsbase += 11; + vwebase += 11; + } break; case SEN_OV7620: hwsbase = 0x2f; /* From 7620.SET (spec is wrong) */ @@ -1763,6 +2720,7 @@ static int set_ov_sensor_window(struct sd *sd) switch (sd->sensor) { case SEN_OV6620: case SEN_OV6630: + case SEN_OV66308AF: if (qvga) { /* QCIF */ hwscale = 0; vwscale = 0; @@ -1815,7 +2773,7 @@ static int set_ov_sensor_window(struct sd *sd) if (qvga) { /* QVGA from ov7670.c by * Jonathan Corbet */ hstart = 164; - hstop = 20; + hstop = 28; vstart = 14; vstop = 494; } else { /* VGA */ @@ -1841,7 +2799,6 @@ static int set_ov_sensor_window(struct sd *sd) msleep(10); /* need to sleep between read and write to * same reg! */ i2c_w(sd, OV7670_REG_VREF, v); - sethvflip(sd); } else { i2c_w(sd, 0x17, hwsbase); i2c_w(sd, 0x18, hwebase + (sd->gspca_dev.width >> hwscale)); @@ -1855,15 +2812,35 @@ static int set_ov_sensor_window(struct sd *sd) static int sd_start(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - int ret; + int ret = 0; - ret = ov519_mode_init_regs(sd); + switch (sd->bridge) { + case BRIDGE_OV511: + case BRIDGE_OV511PLUS: + ret = ov511_mode_init_regs(sd); + break; + case BRIDGE_OV518: + case BRIDGE_OV518PLUS: + ret = ov518_mode_init_regs(sd); + break; + case BRIDGE_OV519: + ret = ov519_mode_init_regs(sd); + break; + } if (ret < 0) goto out; + ret = set_ov_sensor_window(sd); if (ret < 0) goto out; + setcontrast(gspca_dev); + setbrightness(gspca_dev); + setcolors(gspca_dev); + sethvflip(sd); + setautobrightness(sd); + setfreq(sd); + ret = ov51x_restart(sd); if (ret < 0) goto out; @@ -1882,7 +2859,95 @@ static void sd_stopN(struct gspca_dev *gspca_dev) ov51x_led_control(sd, 0); } -static void sd_pkt_scan(struct gspca_dev *gspca_dev, +static void ov511_pkt_scan(struct gspca_dev *gspca_dev, + struct gspca_frame *frame, /* target */ + __u8 *in, /* isoc packet */ + int len) /* iso packet length */ +{ + struct sd *sd = (struct sd *) gspca_dev; + + /* SOF/EOF packets have 1st to 8th bytes zeroed and the 9th + * byte non-zero. The EOF packet has image width/height in the + * 10th and 11th bytes. The 9th byte is given as follows: + * + * bit 7: EOF + * 6: compression enabled + * 5: 422/420/400 modes + * 4: 422/420/400 modes + * 3: 1 + * 2: snapshot button on + * 1: snapshot frame + * 0: even/odd field + */ + if (!(in[0] | in[1] | in[2] | in[3] | in[4] | in[5] | in[6] | in[7]) && + (in[8] & 0x08)) { + if (in[8] & 0x80) { + /* Frame end */ + if ((in[9] + 1) * 8 != gspca_dev->width || + (in[10] + 1) * 8 != gspca_dev->height) { + PDEBUG(D_ERR, "Invalid frame size, got: %dx%d," + " requested: %dx%d\n", + (in[9] + 1) * 8, (in[10] + 1) * 8, + gspca_dev->width, gspca_dev->height); + gspca_dev->last_packet_type = DISCARD_PACKET; + return; + } + /* Add 11 byte footer to frame, might be usefull */ + gspca_frame_add(gspca_dev, LAST_PACKET, frame, in, 11); + return; + } else { + /* Frame start */ + gspca_frame_add(gspca_dev, FIRST_PACKET, frame, in, 0); + sd->packet_nr = 0; + } + } + + /* Ignore the packet number */ + len--; + + /* intermediate packet */ + gspca_frame_add(gspca_dev, INTER_PACKET, frame, in, len); +} + +static void ov518_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; + + /* A false positive here is likely, until OVT gives me + * the definitive SOF/EOF format */ + if ((!(data[0] | data[1] | data[2] | data[3] | data[5])) && data[6]) { + gspca_frame_add(gspca_dev, LAST_PACKET, frame, data, 0); + gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, 0); + sd->packet_nr = 0; + } + + if (gspca_dev->last_packet_type == DISCARD_PACKET) + return; + + /* Does this device use packet numbers ? */ + if (len & 7) { + len--; + if (sd->packet_nr == data[len]) + sd->packet_nr++; + /* The last few packets of the frame (which are all 0's + except that they may contain part of the footer), are + numbered 0 */ + else if (sd->packet_nr == 0 || data[len]) { + PDEBUG(D_ERR, "Invalid packet nr: %d (expect: %d)", + (int)data[len], (int)sd->packet_nr); + gspca_dev->last_packet_type = DISCARD_PACKET; + return; + } + } + + /* intermediate packet */ + gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len); +} + +static void ov519_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame, /* target */ __u8 *data, /* isoc packet */ int len) /* iso packet length */ @@ -1926,6 +2991,28 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, data, len); } +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 (sd->bridge) { + case BRIDGE_OV511: + case BRIDGE_OV511PLUS: + ov511_pkt_scan(gspca_dev, frame, data, len); + break; + case BRIDGE_OV518: + case BRIDGE_OV518PLUS: + ov518_pkt_scan(gspca_dev, frame, data, len); + break; + case BRIDGE_OV519: + ov519_pkt_scan(gspca_dev, frame, data, len); + break; + } +} + /* -- management routines -- */ static void setbrightness(struct gspca_dev *gspca_dev) @@ -1940,13 +3027,13 @@ static void setbrightness(struct gspca_dev *gspca_dev) case SEN_OV76BE: case SEN_OV6620: case SEN_OV6630: + case SEN_OV66308AF: 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) */ + if (!sd->autobrightness) i2c_w(sd, OV7610_REG_BRT, val); break; case SEN_OV7670: @@ -1969,7 +3056,9 @@ static void setcontrast(struct gspca_dev *gspca_dev) i2c_w(sd, OV7610_REG_CNT, val); break; case SEN_OV6630: + case SEN_OV66308AF: i2c_w_mask(sd, OV7610_REG_CNT, val >> 4, 0x0f); + break; case SEN_OV8610: { static const __u8 ctab[] = { 0x03, 0x09, 0x0b, 0x0f, 0x53, 0x6f, 0x35, 0x7f @@ -2012,6 +3101,7 @@ static void setcolors(struct gspca_dev *gspca_dev) case SEN_OV76BE: case SEN_OV6620: case SEN_OV6630: + case SEN_OV66308AF: i2c_w(sd, OV7610_REG_SAT, val); break; case SEN_OV7620: @@ -2032,6 +3122,72 @@ static void setcolors(struct gspca_dev *gspca_dev) } } +static void setautobrightness(struct sd *sd) +{ + if (sd->sensor == SEN_OV7640 || sd->sensor == SEN_OV7670) + return; + + i2c_w_mask(sd, 0x2d, sd->autobrightness ? 0x10 : 0x00, 0x10); +} + +static void setfreq(struct sd *sd) +{ + if (sd->sensor == SEN_OV7670) { + switch (sd->freq) { + case 0: /* Banding filter disabled */ + i2c_w_mask(sd, OV7670_REG_COM8, 0, OV7670_COM8_BFILT); + break; + case 1: /* 50 hz */ + i2c_w_mask(sd, OV7670_REG_COM8, OV7670_COM8_BFILT, + OV7670_COM8_BFILT); + i2c_w_mask(sd, OV7670_REG_COM11, 0x08, 0x18); + break; + case 2: /* 60 hz */ + i2c_w_mask(sd, OV7670_REG_COM8, OV7670_COM8_BFILT, + OV7670_COM8_BFILT); + i2c_w_mask(sd, OV7670_REG_COM11, 0x00, 0x18); + break; + case 3: /* Auto hz */ + i2c_w_mask(sd, OV7670_REG_COM8, OV7670_COM8_BFILT, + OV7670_COM8_BFILT); + i2c_w_mask(sd, OV7670_REG_COM11, OV7670_COM11_HZAUTO, + 0x18); + break; + } + } else { + switch (sd->freq) { + case 0: /* Banding filter disabled */ + i2c_w_mask(sd, 0x2d, 0x00, 0x04); + i2c_w_mask(sd, 0x2a, 0x00, 0x80); + break; + case 1: /* 50 hz (filter on and framerate adj) */ + i2c_w_mask(sd, 0x2d, 0x04, 0x04); + i2c_w_mask(sd, 0x2a, 0x80, 0x80); + /* 20 fps -> 16.667 fps */ + if (sd->sensor == SEN_OV6620 || + sd->sensor == SEN_OV6630 || + sd->sensor == SEN_OV66308AF) + i2c_w(sd, 0x2b, 0x5e); + else + i2c_w(sd, 0x2b, 0xac); + break; + case 2: /* 60 hz (filter on, ...) */ + i2c_w_mask(sd, 0x2d, 0x04, 0x04); + if (sd->sensor == SEN_OV6620 || + sd->sensor == SEN_OV6630 || + sd->sensor == SEN_OV66308AF) { + /* 20 fps -> 15 fps */ + i2c_w_mask(sd, 0x2a, 0x80, 0x80); + i2c_w(sd, 0x2b, 0xa8); + } else { + /* no framerate adj. */ + i2c_w_mask(sd, 0x2a, 0x00, 0x80); + } + break; + } + } +} + static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; @@ -2122,6 +3278,71 @@ static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val) return 0; } +static int sd_setautobrightness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->autobrightness = val; + if (gspca_dev->streaming) + setautobrightness(sd); + return 0; +} + +static int sd_getautobrightness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->autobrightness; + 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(sd); + 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_querymenu(struct gspca_dev *gspca_dev, + struct v4l2_querymenu *menu) +{ + struct sd *sd = (struct sd *) gspca_dev; + + 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; + case 3: + if (sd->sensor != SEN_OV7670) + return -EINVAL; + + strcpy((char *) menu->name, "Automatic"); + return 0; + } + break; + } + return -EINVAL; +} + /* sub-driver description */ static const struct sd_desc sd_desc = { .name = MODULE_NAME, @@ -2132,23 +3353,31 @@ static const struct sd_desc sd_desc = { .start = sd_start, .stopN = sd_stopN, .pkt_scan = sd_pkt_scan, + .querymenu = sd_querymenu, }; /* -- module initialisation -- */ static const __devinitdata struct usb_device_id device_table[] = { - {USB_DEVICE(0x041e, 0x4052)}, - {USB_DEVICE(0x041e, 0x405f)}, - {USB_DEVICE(0x041e, 0x4060)}, - {USB_DEVICE(0x041e, 0x4061)}, - {USB_DEVICE(0x041e, 0x4064)}, - {USB_DEVICE(0x041e, 0x4068)}, - {USB_DEVICE(0x045e, 0x028c)}, - {USB_DEVICE(0x054c, 0x0154)}, - {USB_DEVICE(0x054c, 0x0155)}, - {USB_DEVICE(0x05a9, 0x0519)}, - {USB_DEVICE(0x05a9, 0x0530)}, - {USB_DEVICE(0x05a9, 0x4519)}, - {USB_DEVICE(0x05a9, 0x8519)}, + {USB_DEVICE(0x041e, 0x4052), .driver_info = BRIDGE_OV519 }, + {USB_DEVICE(0x041e, 0x405f), .driver_info = BRIDGE_OV519 }, + {USB_DEVICE(0x041e, 0x4060), .driver_info = BRIDGE_OV519 }, + {USB_DEVICE(0x041e, 0x4061), .driver_info = BRIDGE_OV519 }, + {USB_DEVICE(0x041e, 0x4064), + .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED }, + {USB_DEVICE(0x041e, 0x4068), + .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED }, + {USB_DEVICE(0x045e, 0x028c), .driver_info = BRIDGE_OV519 }, + {USB_DEVICE(0x054c, 0x0154), .driver_info = BRIDGE_OV519 }, + {USB_DEVICE(0x054c, 0x0155), .driver_info = BRIDGE_OV519 }, + {USB_DEVICE(0x05a9, 0x0511), .driver_info = BRIDGE_OV511 }, + {USB_DEVICE(0x05a9, 0x0518), .driver_info = BRIDGE_OV518 }, + {USB_DEVICE(0x05a9, 0x0519), .driver_info = BRIDGE_OV519 }, + {USB_DEVICE(0x05a9, 0x0530), .driver_info = BRIDGE_OV519 }, + {USB_DEVICE(0x05a9, 0x4519), .driver_info = BRIDGE_OV519 }, + {USB_DEVICE(0x05a9, 0x8519), .driver_info = BRIDGE_OV519 }, + {USB_DEVICE(0x05a9, 0xa511), .driver_info = BRIDGE_OV511PLUS }, + {USB_DEVICE(0x05a9, 0xa518), .driver_info = BRIDGE_OV518PLUS }, + {USB_DEVICE(0x0813, 0x0002), .driver_info = BRIDGE_OV511PLUS }, {} }; diff --git a/drivers/media/video/gspca/ov534.c b/drivers/media/video/gspca/ov534.c index 19e0bc60de14..4b528b372911 100644 --- a/drivers/media/video/gspca/ov534.c +++ b/drivers/media/video/gspca/ov534.c @@ -60,10 +60,23 @@ struct sd { static struct ctrl sd_ctrls[] = { }; -static const struct v4l2_pix_format vga_mode[] = { +static const struct v4l2_pix_format vga_yuyv_mode[] = { {640, 480, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, .bytesperline = 640 * 2, .sizeimage = 640 * 480 * 2, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, +}; + +static const struct v4l2_pix_format vga_jpeg_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}, }; @@ -244,7 +257,7 @@ static const u8 bridge_init_ov965x[][2] = { }; static const u8 sensor_init_ov965x[][2] = { - {0x12, 0x80}, /* com7 - reset */ + {0x12, 0x80}, /* com7 - SSCB reset */ {0x00, 0x00}, /* gain */ {0x01, 0x80}, /* blue */ {0x02, 0x80}, /* red */ @@ -254,10 +267,10 @@ static const u8 sensor_init_ov965x[][2] = { {0x0e, 0x61}, /* com5 */ {0x0f, 0x42}, /* com6 */ {0x11, 0x00}, /* clkrc */ - {0x12, 0x02}, /* com7 */ + {0x12, 0x02}, /* com7 - 15fps VGA YUYV */ {0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */ {0x14, 0x28}, /* com9 */ - {0x16, 0x24}, /* rsvd16 */ + {0x16, 0x24}, /* reg16 */ {0x17, 0x1d}, /* hstart*/ {0x18, 0xbd}, /* hstop */ {0x19, 0x01}, /* vstrt */ @@ -269,24 +282,24 @@ static const u8 sensor_init_ov965x[][2] = { {0x27, 0x08}, /* bbias */ {0x28, 0x08}, /* gbbias */ {0x29, 0x15}, /* gr com */ - {0x2a, 0x00}, - {0x2b, 0x00}, + {0x2a, 0x00}, /* exhch */ + {0x2b, 0x00}, /* exhcl */ {0x2c, 0x08}, /* rbias */ {0x32, 0xff}, /* href */ {0x33, 0x00}, /* chlf */ - {0x34, 0x3f}, /* arblm */ - {0x35, 0x00}, /* rsvd35 */ - {0x36, 0xf8}, /* rsvd36 */ - {0x38, 0x72}, /* acom38 */ - {0x39, 0x57}, /* ofon */ - {0x3a, 0x80}, /* tslb */ - {0x3b, 0xc4}, + {0x34, 0x3f}, /* aref1 */ + {0x35, 0x00}, /* aref2 */ + {0x36, 0xf8}, /* aref3 */ + {0x38, 0x72}, /* adc2 */ + {0x39, 0x57}, /* aref4 */ + {0x3a, 0x80}, /* tslb - yuyv */ + {0x3b, 0xc4}, /* com11 - night mode 1/4 frame rate */ {0x3d, 0x99}, /* com13 */ - {0x3f, 0xc1}, + {0x3f, 0xc1}, /* edge */ {0x40, 0xc0}, /* com15 */ {0x41, 0x40}, /* com16 */ - {0x42, 0xc0}, - {0x43, 0x0a}, + {0x42, 0xc0}, /* com17 */ + {0x43, 0x0a}, /* rsvd */ {0x44, 0xf0}, {0x45, 0x46}, {0x46, 0x62}, @@ -297,22 +310,22 @@ static const u8 sensor_init_ov965x[][2] = { {0x4c, 0x7f}, {0x4d, 0x7f}, {0x4e, 0x7f}, - {0x4f, 0x98}, + {0x4f, 0x98}, /* matrix */ {0x50, 0x98}, {0x51, 0x00}, {0x52, 0x28}, {0x53, 0x70}, {0x54, 0x98}, - {0x58, 0x1a}, - {0x59, 0x85}, + {0x58, 0x1a}, /* matrix coef sign */ + {0x59, 0x85}, /* AWB control */ {0x5a, 0xa9}, {0x5b, 0x64}, {0x5c, 0x84}, {0x5d, 0x53}, {0x5e, 0x0e}, - {0x5f, 0xf0}, - {0x60, 0xf0}, - {0x61, 0xf0}, + {0x5f, 0xf0}, /* AWB blue limit */ + {0x60, 0xf0}, /* AWB red limit */ + {0x61, 0xf0}, /* AWB green limit */ {0x62, 0x00}, /* lcc1 */ {0x63, 0x00}, /* lcc2 */ {0x64, 0x02}, /* lcc3 */ @@ -324,15 +337,15 @@ static const u8 sensor_init_ov965x[][2] = { {0x6d, 0x55}, {0x6e, 0x00}, {0x6f, 0x9d}, - {0x70, 0x21}, + {0x70, 0x21}, /* dnsth */ {0x71, 0x78}, - {0x72, 0x00}, - {0x73, 0x01}, - {0x74, 0x3a}, - {0x75, 0x35}, + {0x72, 0x00}, /* poidx */ + {0x73, 0x01}, /* pckdv */ + {0x74, 0x3a}, /* xindx */ + {0x75, 0x35}, /* yindx */ {0x76, 0x01}, {0x77, 0x02}, - {0x7a, 0x12}, + {0x7a, 0x12}, /* gamma curve */ {0x7b, 0x08}, {0x7c, 0x16}, {0x7d, 0x30}, @@ -349,33 +362,33 @@ static const u8 sensor_init_ov965x[][2] = { {0x88, 0xe6}, {0x89, 0xf2}, {0x8a, 0x03}, - {0x8c, 0x89}, + {0x8c, 0x89}, /* com19 */ {0x14, 0x28}, /* com9 */ {0x90, 0x7d}, {0x91, 0x7b}, - {0x9d, 0x03}, - {0x9e, 0x04}, + {0x9d, 0x03}, /* lcc6 */ + {0x9e, 0x04}, /* lcc7 */ {0x9f, 0x7a}, {0xa0, 0x79}, {0xa1, 0x40}, /* aechm */ - {0xa4, 0x50}, + {0xa4, 0x50}, /* com21 */ {0xa5, 0x68}, /* com26 */ - {0xa6, 0x4a}, - {0xa8, 0xc1}, /* acoma8 */ - {0xa9, 0xef}, /* acoma9 */ + {0xa6, 0x4a}, /* AWB green */ + {0xa8, 0xc1}, /* refa8 */ + {0xa9, 0xef}, /* refa9 */ {0xaa, 0x92}, {0xab, 0x04}, - {0xac, 0x80}, + {0xac, 0x80}, /* black level control */ {0xad, 0x80}, {0xae, 0x80}, {0xaf, 0x80}, {0xb2, 0xf2}, {0xb3, 0x20}, - {0xb4, 0x20}, + {0xb4, 0x20}, /* ctrlb4 */ {0xb5, 0x00}, {0xb6, 0xaf}, {0xbb, 0xae}, - {0xbc, 0x7f}, + {0xbc, 0x7f}, /* ADC channel offsets */ {0xdb, 0x7f}, {0xbe, 0x7f}, {0xbf, 0x7f}, @@ -384,7 +397,7 @@ static const u8 sensor_init_ov965x[][2] = { {0xc2, 0x01}, {0xc3, 0x4e}, {0xc6, 0x85}, - {0xc7, 0x80}, + {0xc7, 0x80}, /* com24 */ {0xc9, 0xe0}, {0xca, 0xe8}, {0xcb, 0xf0}, @@ -399,11 +412,11 @@ static const u8 sensor_init_ov965x[][2] = { {0x58, 0x1a}, {0xff, 0x41}, /* read 41, write ff 00 */ {0x41, 0x40}, /* com16 */ - {0xc5, 0x03}, - {0x6a, 0x02}, + {0xc5, 0x03}, /* 60 Hz banding filter */ + {0x6a, 0x02}, /* 50 Hz banding filter */ - {0x12, 0x62}, /* com7 - VGA + CIF */ - {0x36, 0xfa}, /* rsvd36 */ + {0x12, 0x62}, /* com7 - 30fps VGA YUV */ + {0x36, 0xfa}, /* aref3 */ {0x69, 0x0a}, /* hv */ {0x8c, 0x89}, /* com22 */ {0x14, 0x28}, /* com9 */ @@ -442,8 +455,8 @@ static const u8 bridge_init_ov965x_2[][2] = { {0x52, 0x3c}, {0x53, 0x00}, {0x54, 0x00}, - {0x55, 0x00}, - {0x57, 0x00}, + {0x55, 0x00}, /* brightness */ + {0x57, 0x00}, /* contrast 2 */ {0x5c, 0x00}, {0x5a, 0xa0}, {0x5b, 0x78}, @@ -489,9 +502,66 @@ static const u8 sensor_init_ov965x_2[][2] = { {0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */ }; +static const u8 sensor_start_ov965x[][2] = { + {0x12, 0x62}, /* com7 - 30fps VGA YUV */ + {0x36, 0xfa}, /* aref3 */ + {0x69, 0x0a}, /* hv */ + {0x8c, 0x89}, /* com22 */ + {0x14, 0x28}, /* com9 */ + {0x3e, 0x0c}, /* com14 */ + {0x41, 0x40}, /* com16 */ + {0x72, 0x00}, + {0x73, 0x00}, + {0x74, 0x3a}, + {0x75, 0x35}, + {0x76, 0x01}, + {0xc7, 0x80}, /* com24 */ + {0x03, 0x12}, /* vref */ + {0x17, 0x16}, /* hstart */ + {0x18, 0x02}, /* hstop */ + {0x19, 0x01}, /* vstrt */ + {0x1a, 0x3d}, /* vstop */ + {0x32, 0xff}, /* href */ + {0xc0, 0xaa}, + {} +}; + static const u8 bridge_start_ov965x[][2] = { + {0x94, 0xaa}, + {0xf1, 0x60}, + {0xe5, 0x04}, + {0xc0, 0x50}, + {0xc1, 0x3c}, + {0x8c, 0x00}, + {0x8d, 0x1c}, + {0x34, 0x05}, + {} +}; + +static const u8 bridge_start_ov965x_vga[][2] = { + {0xc2, 0x0c}, + {0xc3, 0xf9}, + {0xda, 0x01}, + {0x50, 0x00}, + {0x51, 0xa0}, + {0x52, 0x3c}, + {0x53, 0x00}, + {0x54, 0x00}, + {0x55, 0x00}, + {0x57, 0x00}, + {0x5c, 0x00}, + {0x5a, 0xa0}, + {0x5b, 0x78}, + {0x35, 0x02}, + {0xd9, 0x10}, + {0x94, 0x11}, + {} +}; + +static const u8 bridge_start_ov965x_cif[][2] = { {0xc2, 0x4c}, {0xc3, 0xf9}, + {0xda, 0x00}, {0x50, 0x00}, {0x51, 0xa0}, {0x52, 0x78}, @@ -500,30 +570,54 @@ static const u8 bridge_start_ov965x[][2] = { {0x55, 0x00}, {0x57, 0x00}, {0x5c, 0x00}, - {0x5a, 0x28}, - {0x5b, 0x1e}, - {0x35, 0x00}, - {0xd9, 0x21}, + {0x5a, 0x50}, + {0x5b, 0x3c}, + {0x35, 0x02}, + {0xd9, 0x10}, {0x94, 0x11}, + {} }; -static const u8 sensor_start_ov965x[][2] = { - {0x3b, 0xe4}, +static const u8 sensor_start_ov965x_vga[][2] = { + {0x3b, 0xc4}, /* com11 - night mode 1/4 frame rate */ + {0x1e, 0x04}, /* mvfp */ + {0x13, 0xe0}, /* com8 */ + {0x00, 0x00}, + {0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */ + {0x11, 0x03}, /* clkrc */ + {0x6b, 0x5a}, /* dblv */ + {0x6a, 0x05}, /* 50 Hz banding filter */ + {0xc5, 0x07}, /* 60 Hz banding filter */ + {0xa2, 0x4b}, /* bd50 */ + {0xa3, 0x3e}, /* bd60 */ + + {0x2d, 0x00}, /* advfl */ + {} +}; + +static const u8 sensor_start_ov965x_cif[][2] = { + {0x3b, 0xe4}, /* com11 - night mode 1/4 frame rate */ {0x1e, 0x04}, /* mvfp */ {0x13, 0xe0}, /* com8 */ {0x00, 0x00}, {0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */ {0x11, 0x01}, /* clkrc */ {0x6b, 0x5a}, /* dblv */ - {0x6a, 0x02}, - {0xc5, 0x03}, - {0xa2, 0x96}, - {0xa3, 0x7d}, + {0x6a, 0x02}, /* 50 Hz banding filter */ + {0xc5, 0x03}, /* 60 Hz banding filter */ + {0xa2, 0x96}, /* bd50 */ + {0xa3, 0x7d}, /* bd60 */ + {0xff, 0x13}, /* read 13, write ff 00 */ {0x13, 0xe7}, - {0x3a, 0x80}, + {0x3a, 0x80}, /* tslb - yuyv */ + {} +}; + +static const u8 sensor_start_ov965x_2[][2] = { {0xff, 0x42}, /* read 42, write ff 00 */ - {0x42, 0xc1}, + {0x42, 0xc1}, /* com17 - 50 Hz filter */ + {} }; @@ -705,11 +799,17 @@ static int sd_config(struct gspca_dev *gspca_dev, cam = &gspca_dev->cam; - cam->cam_mode = vga_mode; - cam->nmodes = ARRAY_SIZE(vga_mode); + if (sd->sensor == SENSOR_OV772X) { + cam->cam_mode = vga_yuyv_mode; + cam->nmodes = ARRAY_SIZE(vga_yuyv_mode); - cam->bulk_size = 16384; - cam->bulk_nurbs = 2; + cam->bulk = 1; + cam->bulk_size = 16384; + cam->bulk_nurbs = 2; + } else { /* ov965x */ + cam->cam_mode = vga_jpeg_mode; + cam->nmodes = ARRAY_SIZE(vga_jpeg_mode); + } return 0; } @@ -778,6 +878,7 @@ static int sd_init(struct gspca_dev *gspca_dev) static int sd_start(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; + int mode; switch (sd->sensor) { case SENSOR_OV772X: @@ -786,13 +887,28 @@ static int sd_start(struct gspca_dev *gspca_dev) break; default: /* case SENSOR_OV965X: */ - reg_w_array(gspca_dev, bridge_start_ov965x, - ARRAY_SIZE(bridge_start_ov965x)); + sccb_w_array(gspca_dev, sensor_start_ov965x, ARRAY_SIZE(sensor_start_ov965x)); + reg_w_array(gspca_dev, bridge_start_ov965x, + ARRAY_SIZE(bridge_start_ov965x)); + mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; + if (mode != 0) { /* 320x240 */ + reg_w_array(gspca_dev, bridge_start_ov965x_cif, + ARRAY_SIZE(bridge_start_ov965x_cif)); + sccb_w_array(gspca_dev, sensor_start_ov965x_cif, + ARRAY_SIZE(sensor_start_ov965x_cif)); + } else { /* 640x480 */ + reg_w_array(gspca_dev, bridge_start_ov965x_vga, + ARRAY_SIZE(bridge_start_ov965x_vga)); + sccb_w_array(gspca_dev, sensor_start_ov965x_vga, + ARRAY_SIZE(sensor_start_ov965x_vga)); + } + sccb_w_array(gspca_dev, sensor_start_ov965x_2, + ARRAY_SIZE(sensor_start_ov965x_2)); + ov534_reg_write(gspca_dev, 0xe0, 0x00); ov534_reg_write(gspca_dev, 0xe0, 0x00); ov534_set_led(gspca_dev, 1); -/*fixme: other sensor start omitted*/ } return 0; } @@ -832,9 +948,11 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame, __u32 this_pts; u16 this_fid; int remaining_len = len; + int payload_len; + payload_len = gspca_dev->cam.bulk ? 2048 : 2040; do { - len = min(remaining_len, 2040); /*fixme: was 2048*/ + len = min(remaining_len, payload_len); /* Payloads are prefixed with a UVC-style header. We consider a frame to start when the FID toggles, or the PTS @@ -864,30 +982,27 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame, /* If PTS or FID has changed, start a new frame. */ if (this_pts != sd->last_pts || this_fid != sd->last_fid) { - gspca_frame_add(gspca_dev, FIRST_PACKET, frame, - NULL, 0); + if (gspca_dev->last_packet_type == INTER_PACKET) + frame = gspca_frame_add(gspca_dev, + LAST_PACKET, frame, + NULL, 0); sd->last_pts = this_pts; sd->last_fid = this_fid; - } - - /* Add the data from this payload */ - gspca_frame_add(gspca_dev, INTER_PACKET, frame, + gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data + 12, len - 12); - /* If this packet is marked as EOF, end the frame */ - if (data[1] & UVC_STREAM_EOF) { + } else if (data[1] & UVC_STREAM_EOF) { sd->last_pts = 0; - - if (frame->data_end - frame->data != - gspca_dev->width * gspca_dev->height * 2) { - PDEBUG(D_PACK, "short frame"); - goto discard; - } - frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame, - NULL, 0); + data + 12, len - 12); + } else { + + /* Add the data from this payload */ + gspca_frame_add(gspca_dev, INTER_PACKET, frame, + data + 12, len - 12); } + /* Done this payload */ goto scan_next; diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c index 153d0a91d4b5..cf3af8de6e97 100644 --- a/drivers/media/video/gspca/sonixb.c +++ b/drivers/media/video/gspca/sonixb.c @@ -877,6 +877,8 @@ static int sd_config(struct gspca_dev *gspca_dev, cam->cam_mode = sif_mode; cam->nmodes = ARRAY_SIZE(sif_mode); } + cam->npkt = 36; /* 36 packets per ISOC message */ + sd->brightness = BRIGHTNESS_DEF; sd->gain = GAIN_DEF; sd->exposure = EXPOSURE_DEF; diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c index c72e19d3ac37..0d02f41fa7d0 100644 --- a/drivers/media/video/gspca/sonixj.c +++ b/drivers/media/video/gspca/sonixj.c @@ -46,6 +46,7 @@ struct sd { u8 gamma; u8 vflip; /* ov7630/ov7648 only */ u8 infrared; /* mt9v111 only */ + u8 freq; /* ov76xx only */ u8 quality; /* image quality */ #define QUALITY_MIN 60 #define QUALITY_MAX 95 @@ -62,7 +63,6 @@ struct sd { #define BRIDGE_SN9C105 1 #define BRIDGE_SN9C110 2 #define BRIDGE_SN9C120 3 -#define BRIDGE_SN9C325 4 u8 sensor; /* Type of image sensor chip */ #define SENSOR_HV7131R 0 #define SENSOR_MI0360 1 @@ -97,8 +97,11 @@ static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val); static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val); static int sd_setinfrared(struct gspca_dev *gspca_dev, __s32 val); static int sd_getinfrared(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[] = { +#define BRIGHTNESS_IDX 0 { { .id = V4L2_CID_BRIGHTNESS, @@ -114,6 +117,7 @@ static struct ctrl sd_ctrls[] = { .set = sd_setbrightness, .get = sd_getbrightness, }, +#define CONTRAST_IDX 1 { { .id = V4L2_CID_CONTRAST, @@ -129,20 +133,22 @@ static struct ctrl sd_ctrls[] = { .set = sd_setcontrast, .get = sd_getcontrast, }, +#define COLOR_IDX 2 { { .id = V4L2_CID_SATURATION, .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Color", + .name = "Saturation", .minimum = 0, .maximum = 40, .step = 1, -#define COLOR_DEF 32 +#define COLOR_DEF 25 .default_value = COLOR_DEF, }, .set = sd_setcolors, .get = sd_getcolors, }, +#define BLUE_BALANCE_IDX 3 { { .id = V4L2_CID_BLUE_BALANCE, @@ -157,6 +163,7 @@ static struct ctrl sd_ctrls[] = { .set = sd_setblue_balance, .get = sd_getblue_balance, }, +#define RED_BALANCE_IDX 4 { { .id = V4L2_CID_RED_BALANCE, @@ -171,6 +178,7 @@ static struct ctrl sd_ctrls[] = { .set = sd_setred_balance, .get = sd_getred_balance, }, +#define GAMMA_IDX 5 { { .id = V4L2_CID_GAMMA, @@ -185,7 +193,7 @@ static struct ctrl sd_ctrls[] = { .set = sd_setgamma, .get = sd_getgamma, }, -#define AUTOGAIN_IDX 5 +#define AUTOGAIN_IDX 6 { { .id = V4L2_CID_AUTOGAIN, @@ -201,7 +209,7 @@ static struct ctrl sd_ctrls[] = { .get = sd_getautogain, }, /* ov7630/ov7648 only */ -#define VFLIP_IDX 6 +#define VFLIP_IDX 7 { { .id = V4L2_CID_VFLIP, @@ -210,14 +218,14 @@ static struct ctrl sd_ctrls[] = { .minimum = 0, .maximum = 1, .step = 1, -#define VFLIP_DEF 0 /* vflip def = 1 for ov7630 */ +#define VFLIP_DEF 0 .default_value = VFLIP_DEF, }, .set = sd_setvflip, .get = sd_getvflip, }, /* mt9v111 only */ -#define INFRARED_IDX 7 +#define INFRARED_IDX 8 { { .id = V4L2_CID_INFRARED, @@ -232,28 +240,44 @@ static struct ctrl sd_ctrls[] = { .set = sd_setinfrared, .get = sd_getinfrared, }, +/* ov7630/ov7648/ov7660 only */ +#define FREQ_IDX 9 + { + { + .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 2 + .default_value = FREQ_DEF, + }, + .set = sd_setfreq, + .get = sd_getfreq, + }, }; /* table of the disabled controls */ static __u32 ctrl_dis[] = { - (1 << INFRARED_IDX) | (1 << VFLIP_IDX), + (1 << INFRARED_IDX) | (1 << VFLIP_IDX) | (1 << FREQ_IDX), /* SENSOR_HV7131R 0 */ - (1 << INFRARED_IDX) | (1 << VFLIP_IDX), + (1 << INFRARED_IDX) | (1 << VFLIP_IDX) | (1 << FREQ_IDX), /* SENSOR_MI0360 1 */ - (1 << INFRARED_IDX) | (1 << VFLIP_IDX), + (1 << INFRARED_IDX) | (1 << VFLIP_IDX) | (1 << FREQ_IDX), /* SENSOR_MO4000 2 */ - (1 << VFLIP_IDX), + (1 << VFLIP_IDX) | (1 << FREQ_IDX), /* SENSOR_MT9V111 3 */ - (1 << INFRARED_IDX) | (1 << VFLIP_IDX), + (1 << INFRARED_IDX) | (1 << VFLIP_IDX) | (1 << FREQ_IDX), /* SENSOR_OM6802 4 */ - (1 << AUTOGAIN_IDX) | (1 << INFRARED_IDX), + (1 << INFRARED_IDX), /* SENSOR_OV7630 5 */ (1 << INFRARED_IDX), /* SENSOR_OV7648 6 */ (1 << AUTOGAIN_IDX) | (1 << INFRARED_IDX) | (1 << VFLIP_IDX), /* SENSOR_OV7660 7 */ - (1 << AUTOGAIN_IDX) | (1 << INFRARED_IDX) | (1 << VFLIP_IDX), - /* SENSOR_SP80708 8 */ + (1 << AUTOGAIN_IDX) | (1 << INFRARED_IDX) | (1 << VFLIP_IDX) | + (1 << FREQ_IDX), /* SENSOR_SP80708 8 */ }; static const struct v4l2_pix_format vga_mode[] = { @@ -269,7 +293,8 @@ static const struct v4l2_pix_format vga_mode[] = { .priv = 1}, {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, .bytesperline = 640, - .sizeimage = 640 * 480 * 3 / 8 + 590, + /* Note 3 / 8 is not large enough, not even 5 / 8 is ?! */ + .sizeimage = 640 * 480 * 3 / 4 + 590, .colorspace = V4L2_COLORSPACE_JPEG, .priv = 0}, }; @@ -354,9 +379,9 @@ static const u8 sn_ov7648[0x1c] = { static const u8 sn_ov7660[0x1c] = { /* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ - 0x00, 0x61, 0x40, 0x00, 0x1a, 0x20, 0x20, 0x20, + 0x00, 0x61, 0x40, 0x00, 0x1a, 0x00, 0x00, 0x00, /* reg8 reg9 rega regb regc regd rege regf */ - 0x81, 0x21, 0x07, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x81, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ 0x03, 0x00, 0x01, 0x01, 0x08, 0x28, 0x1e, 0x20, /* reg18 reg19 reg1a reg1b */ @@ -605,7 +630,9 @@ static const u8 ov7630_sensor_init[][8] = { /* win: i2c_r from 00 to 80 */ {0xd1, 0x21, 0x03, 0x80, 0x10, 0x20, 0x80, 0x10}, {0xb1, 0x21, 0x0c, 0x20, 0x20, 0x00, 0x00, 0x10}, - {0xd1, 0x21, 0x11, 0x00, 0x48, 0xc0, 0x00, 0x10}, +/* HDG: 0x11 was 0x00 change to 0x01 for better exposure (15 fps instead of 30) + 0x13 was 0xc0 change to 0xc3 for auto gain and exposure */ + {0xd1, 0x21, 0x11, 0x01, 0x48, 0xc3, 0x00, 0x10}, {0xb1, 0x21, 0x15, 0x80, 0x03, 0x00, 0x00, 0x10}, {0xd1, 0x21, 0x17, 0x1b, 0xbd, 0x05, 0xf6, 0x10}, {0xa1, 0x21, 0x1b, 0x04, 0x00, 0x00, 0x00, 0x10}, @@ -639,9 +666,8 @@ static const u8 ov7630_sensor_init[][8] = { {0xa1, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10}, {0xb1, 0x21, 0x01, 0x80, 0x80, 0x00, 0x00, 0x10}, /* */ - {0xa1, 0x21, 0x11, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x21, 0x2a, 0x88, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x21, 0x2b, 0x34, 0x00, 0x00, 0x00, 0x10}, +/* {0xa1, 0x21, 0x2a, 0x88, 0x00, 0x00, 0x00, 0x10}, * set by setfreq */ +/* {0xa1, 0x21, 0x2b, 0x34, 0x00, 0x00, 0x00, 0x10}, * set by setfreq */ /* */ {0xa1, 0x21, 0x10, 0x83, 0x00, 0x00, 0x00, 0x10}, /* {0xb1, 0x21, 0x01, 0x88, 0x70, 0x00, 0x00, 0x10}, */ @@ -674,7 +700,7 @@ static const u8 ov7648_sensor_init[][8] = { {0xd1, 0x21, 0x21, 0x86, 0x00, 0xde, 0xa0, 0x10}, /* {0xd1, 0x21, 0x25, 0x80, 0x32, 0xfe, 0xa0, 0x10}, jfm done */ /* {0xd1, 0x21, 0x29, 0x00, 0x91, 0x00, 0x88, 0x10}, jfm done */ - {0xb1, 0x21, 0x2d, 0x85, 0x00, 0x00, 0x00, 0x10}, +/* {0xb1, 0x21, 0x2d, 0x85, 0x00, 0x00, 0x00, 0x10}, set by setfreq */ /*...*/ /* {0xa1, 0x21, 0x12, 0x08, 0x00, 0x00, 0x00, 0x10}, jfm done */ /* {0xa1, 0x21, 0x75, 0x06, 0x00, 0x00, 0x00, 0x10}, * COMN @@ -757,6 +783,7 @@ static const u8 ov7660_sensor_init[][8] = { {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}, /* DM_LNL/H */ + {0xb1, 0x21, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x10}, /****** (some exchanges in the win trace) ******/ {0xa1, 0x21, 0x1e, 0x01, 0x00, 0x00, 0x00, 0x10}, /* MVFP */ /* bits[3..0]reserved */ @@ -1065,9 +1092,9 @@ static int configure_gpio(struct gspca_dev *gspca_dev, struct sd *sd = (struct sd *) gspca_dev; const u8 *reg9a; static const u8 reg9a_def[] = - {0x08, 0x40, 0x20, 0x10, 0x00, 0x04}; - static const u8 reg9a_sn9c325[] = - {0x0a, 0x40, 0x38, 0x30, 0x00, 0x20}; + {0x00, 0x40, 0x20, 0x00, 0x00, 0x00}; + static const u8 reg9a_spec[] = + {0x00, 0x40, 0x38, 0x30, 0x00, 0x20}; static const u8 regd4[] = {0x60, 0x00, 0x00}; reg_w1(gspca_dev, 0xf1, 0x00); @@ -1077,9 +1104,10 @@ static int configure_gpio(struct gspca_dev *gspca_dev, 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 len was 3 */ - switch (sd->bridge) { - case BRIDGE_SN9C325: - reg9a = reg9a_sn9c325; + switch (sd->sensor) { + case SENSOR_OV7660: + case SENSOR_SP80708: + reg9a = reg9a_spec; break; default: reg9a = reg9a_def; @@ -1104,7 +1132,6 @@ static int configure_gpio(struct gspca_dev *gspca_dev, reg_w1(gspca_dev, 0x17, 0x64); reg_w1(gspca_dev, 0x01, 0x42); break; -/*jfm: from win trace */ case SENSOR_OV7630: reg_w1(gspca_dev, 0x01, 0x61); reg_w1(gspca_dev, 0x17, 0xe2); @@ -1114,18 +1141,15 @@ static int configure_gpio(struct gspca_dev *gspca_dev, case SENSOR_OV7648: reg_w1(gspca_dev, 0x01, 0x63); reg_w1(gspca_dev, 0x17, 0x20); + reg_w1(gspca_dev, 0x01, 0x62); reg_w1(gspca_dev, 0x01, 0x42); break; -/*jfm: from win trace */ case SENSOR_OV7660: - if (sd->bridge == BRIDGE_SN9C120) { - reg_w1(gspca_dev, 0x01, 0x61); - reg_w1(gspca_dev, 0x17, 0x20); - reg_w1(gspca_dev, 0x01, 0x60); - reg_w1(gspca_dev, 0x01, 0x40); - break; - } - /* fall thru */ + reg_w1(gspca_dev, 0x01, 0x61); + reg_w1(gspca_dev, 0x17, 0x20); + reg_w1(gspca_dev, 0x01, 0x60); + reg_w1(gspca_dev, 0x01, 0x40); + break; case SENSOR_SP80708: reg_w1(gspca_dev, 0x01, 0x63); reg_w1(gspca_dev, 0x17, 0x20); @@ -1134,6 +1158,9 @@ static int configure_gpio(struct gspca_dev *gspca_dev, mdelay(100); reg_w1(gspca_dev, 0x02, 0x62); break; +/* case SENSOR_HV7131R: */ +/* case SENSOR_MI0360: */ +/* case SENSOR_MO4000: */ default: reg_w1(gspca_dev, 0x01, 0x43); reg_w1(gspca_dev, 0x17, 0x61); @@ -1280,6 +1307,7 @@ static int sd_config(struct gspca_dev *gspca_dev, cam = &gspca_dev->cam; cam->cam_mode = vga_mode; cam->nmodes = ARRAY_SIZE(vga_mode); + cam->npkt = 24; /* 24 packets per ISOC message */ sd->bridge = id->driver_info >> 16; sd->sensor = id->driver_info >> 8; @@ -1293,11 +1321,9 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->gamma = GAMMA_DEF; sd->autogain = AUTOGAIN_DEF; sd->ag_cnt = -1; - if (sd->sensor != SENSOR_OV7630) - sd->vflip = 0; - else - sd->vflip = 1; + sd->vflip = VFLIP_DEF; sd->infrared = INFRARED_DEF; + sd->freq = FREQ_DEF; sd->quality = QUALITY_DEF; sd->jpegqual = 80; @@ -1568,7 +1594,7 @@ static void setautogain(struct gspca_dev *gspca_dev) else comb = 0xa0; if (sd->autogain) - comb |= 0x02; + comb |= 0x03; i2c_w1(&sd->gspca_dev, 0x13, comb); return; } @@ -1584,12 +1610,15 @@ static void setvflip(struct sd *sd) { u8 comn; - if (sd->sensor == SENSOR_OV7630) + if (sd->sensor == SENSOR_OV7630) { comn = 0x02; - else + if (!sd->vflip) + comn |= 0x80; + } else { comn = 0x06; - if (sd->vflip) - comn |= 0x80; + if (sd->vflip) + comn |= 0x80; + } i2c_w1(&sd->gspca_dev, 0x75, comn); } @@ -1601,6 +1630,58 @@ static void setinfrared(struct sd *sd) sd->infrared ? 0x66 : 0x64); } +static void setfreq(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (sd->sensor == SENSOR_OV7660) { + switch (sd->freq) { + case 0: /* Banding filter disabled */ + i2c_w1(gspca_dev, 0x13, 0xdf); + break; + case 1: /* 50 hz */ + i2c_w1(gspca_dev, 0x13, 0xff); + i2c_w1(gspca_dev, 0x3b, 0x0a); + break; + case 2: /* 60 hz */ + i2c_w1(gspca_dev, 0x13, 0xff); + i2c_w1(gspca_dev, 0x3b, 0x02); + break; + } + } else { + u8 reg2a = 0, reg2b = 0, reg2d = 0; + + /* Get reg2a / reg2d base values */ + switch (sd->sensor) { + case SENSOR_OV7630: + reg2a = 0x08; + reg2d = 0x01; + break; + case SENSOR_OV7648: + reg2a = 0x11; + reg2d = 0x81; + break; + } + + switch (sd->freq) { + case 0: /* Banding filter disabled */ + break; + case 1: /* 50 hz (filter on and framerate adj) */ + reg2a |= 0x80; + reg2b = 0xac; + reg2d |= 0x04; + break; + case 2: /* 60 hz (filter on, no framerate adj) */ + reg2a |= 0x80; + reg2d |= 0x04; + break; + } + i2c_w1(gspca_dev, 0x2a, reg2a); + i2c_w1(gspca_dev, 0x2b, reg2b); + i2c_w1(gspca_dev, 0x2d, reg2d); + } +} + static void setjpegqual(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; @@ -1683,13 +1764,9 @@ static int sd_start(struct gspca_dev *gspca_dev) case SENSOR_OV7648: reg17 = 0x20; break; -/*jfm: from win trace */ case SENSOR_OV7660: - if (sd->bridge == BRIDGE_SN9C120) { - reg17 = 0xa0; - break; - } - /* fall thru */ + reg17 = 0xa0; + break; default: reg17 = 0x60; break; @@ -1714,16 +1791,17 @@ static int sd_start(struct gspca_dev *gspca_dev) reg_w1(gspca_dev, 0x9a, 0x0a); reg_w1(gspca_dev, 0x99, 0x60); break; + case SENSOR_OV7660: + reg_w1(gspca_dev, 0x9a, 0x05); + if (sd->bridge == BRIDGE_SN9C105) + reg_w1(gspca_dev, 0x99, 0xff); + else + reg_w1(gspca_dev, 0x99, 0x5b); + break; case SENSOR_SP80708: reg_w1(gspca_dev, 0x9a, 0x05); reg_w1(gspca_dev, 0x99, 0x59); break; - case SENSOR_OV7660: - if (sd->bridge == BRIDGE_SN9C120) { - reg_w1(gspca_dev, 0x9a, 0x05); - break; - } - /* fall thru */ default: reg_w1(gspca_dev, 0x9a, 0x08); reg_w1(gspca_dev, 0x99, 0x59); @@ -1830,6 +1908,7 @@ static int sd_start(struct gspca_dev *gspca_dev) setbrightness(gspca_dev); setcontrast(gspca_dev); setautogain(gspca_dev); + setfreq(gspca_dev); return 0; } @@ -2133,6 +2212,24 @@ static int sd_getinfrared(struct gspca_dev *gspca_dev, __s32 *val) 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_set_jcomp(struct gspca_dev *gspca_dev, struct v4l2_jpegcompression *jcomp) { @@ -2161,6 +2258,27 @@ static int sd_get_jcomp(struct gspca_dev *gspca_dev, 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, @@ -2175,6 +2293,7 @@ static const struct sd_desc sd_desc = { .dq_callback = do_autogain, .get_jcomp = sd_get_jcomp, .set_jcomp = sd_set_jcomp, + .querymenu = sd_querymenu, }; /* -- module initialisation -- */ @@ -2193,6 +2312,7 @@ static const __devinitdata struct usb_device_id device_table[] = { {USB_DEVICE(0x0471, 0x0328), BSI(SN9C105, MI0360, 0x5d)}, {USB_DEVICE(0x0471, 0x0330), BSI(SN9C105, MI0360, 0x5d)}, {USB_DEVICE(0x06f8, 0x3004), BSI(SN9C105, OV7660, 0x21)}, + {USB_DEVICE(0x06f8, 0x3008), BSI(SN9C105, OV7660, 0x21)}, {USB_DEVICE(0x0c45, 0x6040), BSI(SN9C102P, HV7131R, 0x11)}, /* bw600.inf: {USB_DEVICE(0x0c45, 0x6040), BSI(SN9C102P, MI0360, 0x5d)}, */ @@ -2211,7 +2331,12 @@ static const __devinitdata struct usb_device_id device_table[] = { #if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE {USB_DEVICE(0x0c45, 0x60fe), BSI(SN9C105, OV7630, 0x21)}, #endif + {USB_DEVICE(0x0c45, 0x6100), BSI(SN9C120, MI0360, 0x5d)}, /*sn9c128*/ /* {USB_DEVICE(0x0c45, 0x6108), BSI(SN9C120, OM6801, 0x??)}, */ + {USB_DEVICE(0x0c45, 0x610a), BSI(SN9C120, OV7648, 0x21)}, /*sn9c128*/ + {USB_DEVICE(0x0c45, 0x610b), BSI(SN9C120, OV7660, 0x21)}, /*sn9c128*/ + {USB_DEVICE(0x0c45, 0x610c), BSI(SN9C120, HV7131R, 0x11)}, /*sn9c128*/ + {USB_DEVICE(0x0c45, 0x610e), BSI(SN9C120, OV7630, 0x21)}, /*sn9c128*/ /* {USB_DEVICE(0x0c45, 0x6122), BSI(SN9C110, ICM105C, 0x??)}, */ /* {USB_DEVICE(0x0c45, 0x6123), BSI(SN9C110, SanyoCCD, 0x??)}, */ {USB_DEVICE(0x0c45, 0x6128), BSI(SN9C110, OM6802, 0x21)}, /*sn9c325?*/ @@ -2229,7 +2354,7 @@ static const __devinitdata struct usb_device_id device_table[] = { {USB_DEVICE(0x0c45, 0x613b), BSI(SN9C120, OV7660, 0x21)}, #endif {USB_DEVICE(0x0c45, 0x613c), BSI(SN9C120, HV7131R, 0x11)}, -/* {USB_DEVICE(0x0c45, 0x613e), BSI(SN9C120, OV7630, 0x??)}, */ + {USB_DEVICE(0x0c45, 0x613e), BSI(SN9C120, OV7630, 0x21)}, {USB_DEVICE(0x0c45, 0x6143), BSI(SN9C120, SP80708, 0x18)}, {} }; diff --git a/drivers/media/video/gspca/spca500.c b/drivers/media/video/gspca/spca500.c index 6f38fa6d86b6..8806b2ff82be 100644 --- a/drivers/media/video/gspca/spca500.c +++ b/drivers/media/video/gspca/spca500.c @@ -32,9 +32,6 @@ MODULE_LICENSE("GPL"); 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; @@ -906,7 +903,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, { 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 */ @@ -930,22 +926,19 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, } /* 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); + i = 0; + do { + if (data[i] == 0xff) { + gspca_frame_add(gspca_dev, INTER_PACKET, frame, + data, i + 1); + len -= i; + data += i; + *data = 0x00; + i = 0; + } + i++; + } while (i < len); + gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len); } static void setbrightness(struct gspca_dev *gspca_dev) diff --git a/drivers/media/video/gspca/spca505.c b/drivers/media/video/gspca/spca505.c index 2acec58b1b97..ea8c9fe2e961 100644 --- a/drivers/media/video/gspca/spca505.c +++ b/drivers/media/video/gspca/spca505.c @@ -637,19 +637,19 @@ static int sd_config(struct gspca_dev *gspca_dev, cam->nmodes = ARRAY_SIZE(vga_mode) - 1; sd->brightness = BRIGHTNESS_DEF; - 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 probe and resume time */ static int sd_init(struct gspca_dev *gspca_dev) { + struct sd *sd = (struct sd *) gspca_dev; + + if (write_vector(gspca_dev, + sd->subtype == Nxultra + ? spca505b_init_data + : spca505_init_data)) + return -EIO; return 0; } diff --git a/drivers/media/video/gspca/spca508.c b/drivers/media/video/gspca/spca508.c index adacf8437661..2ed2669bac3e 100644 --- a/drivers/media/video/gspca/spca508.c +++ b/drivers/media/video/gspca/spca508.c @@ -1,7 +1,7 @@ /* * SPCA508 chip based cameras subdriver * - * V4L2 by Jean-Francois Moine + * Copyright (C) 2009 Jean-Francois Moine * * 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 @@ -30,9 +30,9 @@ MODULE_LICENSE("GPL"); struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ - unsigned char brightness; + u8 brightness; - char subtype; + u8 subtype; #define CreativeVista 0 #define HamaUSBSightcam 1 #define HamaUSBSightcam2 2 @@ -86,58 +86,34 @@ static const struct v4l2_pix_format sif_mode[] = { }; /* 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[][2] = { - /* line URB value, index */ - /* 44274 1804 */ {0x0000, 0x870b}, + {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 */ + {0x0020, 0x8112}, /* Video drop enable, ISO streaming disable */ + {0x0003, 0x8111}, /* Reset compression & memory */ + {0x0000, 0x8110}, /* Disable all outputs */ + /* READ {0x0000, 0x8114} -> 0000: 00 */ + {0x0000, 0x8114}, /* SW GPIO data */ + {0x0008, 0x8110}, /* Enable charge pump output */ + {0x0002, 0x8116}, /* 200 kHz pump clock */ + /* UNKNOWN DIRECTION (URB_FUNCTION_SELECT_INTERFACE:) */ + {0x0003, 0x8111}, /* Reset compression & memory */ + {0x0000, 0x8111}, /* Normal mode (not reset) */ + {0x0098, 0x8110}, + /* Enable charge pump output, sync.serial,external 2x clock */ + {0x000d, 0x8114}, /* SW GPIO data */ + {0x0002, 0x8116}, /* 200 kHz pump clock */ + {0x0020, 0x8112}, /* Video drop enable, ISO streaming disable */ /* --------------------------------------- */ - /* 44740 1819 */ {0x000f, 0x8402}, - /* memory bank */ - /* 44765 1820 */ {0x0000, 0x8403}, - /* ... address */ + {0x000f, 0x8402}, /* memory bank */ + {0x0000, 0x8403}, /* ... address */ /* --------------------------------------- */ /* 0x88__ is Synchronous Serial Interface. */ /* TBD: This table could be expressed more compactly */ @@ -145,446 +121,384 @@ static const u16 spca508_init_data[][2] = /* 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 */ + {0x00c0, 0x8804}, /* SSI slave addr */ + {0x0008, 0x8802}, /* 375 Khz SSI clock */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, /* 375 Khz SSI clock */ + {0x0012, 0x8801}, /* SSI reg addr */ + {0x0080, 0x8800}, /* SSI data to write */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, /* 375 Khz SSI clock */ + {0x0012, 0x8801}, /* SSI reg addr */ + {0x0000, 0x8800}, /* SSI data to write */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, /* 375 Khz SSI clock */ + {0x0011, 0x8801}, /* SSI reg addr */ + {0x0040, 0x8800}, /* SSI data to write */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x0013, 0x8801}, + {0x0000, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x0014, 0x8801}, + {0x0000, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x0015, 0x8801}, + {0x0001, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x0016, 0x8801}, + {0x0003, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x0017, 0x8801}, + {0x0036, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x0018, 0x8801}, + {0x00ec, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x001a, 0x8801}, + {0x0094, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x001b, 0x8801}, + {0x0000, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x0027, 0x8801}, + {0x00a2, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x0028, 0x8801}, + {0x0040, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x002a, 0x8801}, + {0x0084, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x002b, 0x8801}, + {0x00a8, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x002c, 0x8801}, + {0x00fe, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x002d, 0x8801}, + {0x0003, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x0038, 0x8801}, + {0x0083, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x0033, 0x8801}, + {0x0081, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x0034, 0x8801}, + {0x004a, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x0039, 0x8801}, + {0x0000, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x0010, 0x8801}, + {0x00a8, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x0006, 0x8801}, + {0x0058, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x0000, 0x8801}, + {0x0004, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x0040, 0x8801}, + {0x0080, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x0041, 0x8801}, + {0x000c, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x0042, 0x8801}, + {0x000c, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x0043, 0x8801}, + {0x0028, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x0044, 0x8801}, + {0x0080, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x0045, 0x8801}, + {0x0020, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x0046, 0x8801}, + {0x0020, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x0047, 0x8801}, + {0x0080, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x0048, 0x8801}, + {0x004c, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x0049, 0x8801}, + {0x0084, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x004a, 0x8801}, + {0x0084, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x0008, 0x8802}, + {0x004b, 0x8801}, + {0x0084, 0x8800}, + /* READ { 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 */ + {0x0012, 0x8700}, /* Clock speed 48Mhz/(2+2)/2= 6 Mhz */ + {0x0000, 0x8701}, /* CKx1 clock delay adj */ + {0x0000, 0x8701}, /* CKx1 clock delay adj */ + {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, + {0x0080, 0x8600}, /* Line memory read counter (L) */ + {0x0001, 0x8606}, /* reserved */ + {0x0064, 0x8607}, /* Line memory read counter (H) 0x6480=25,728 */ + {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 */ + {0x0000, 0x8602}, /* optical black level for user settng = 0 */ + {0x0080, 0x8600}, /* Line memory read counter (L) */ + {0x000a, 0x8603}, /* optical black level calc mode: + * auto; optical black offset = 10 */ + {0x00df, 0x865b}, /* Horiz offset for valid pixels (L)=0xdf */ + {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 */ + {0x0058, 0x865d}, /* Horiz valid pixels (*4) (L) = 352 */ + {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 */ + {0x0015, 0x8608}, /* A11 Coef ... */ + {0x0030, 0x8609}, + {0x00fb, 0x860a}, + {0x003e, 0x860b}, + {0x00ce, 0x860c}, + {0x00f4, 0x860d}, + {0x00eb, 0x860e}, + {0x00dc, 0x860f}, + {0x0039, 0x8610}, + {0x0001, 0x8611}, /* R offset for white balance ... */ + {0x0000, 0x8612}, + {0x0001, 0x8613}, + {0x0000, 0x8614}, + {0x005b, 0x8651}, /* R gain for white balance ... */ + {0x0040, 0x8652}, + {0x0060, 0x8653}, + {0x0040, 0x8654}, + {0x0000, 0x8655}, + {0x0001, 0x863f}, /* Fixed gamma correction enable, USB control, + * lum filter disable, lum noise clip disable */ + {0x00a1, 0x8656}, /* Window1 size 256x256, Windows2 size 64x64, + * gamma look-up disable, + * new edge enhancement enable */ + {0x0018, 0x8657}, /* Edge gain high thresh */ + {0x0020, 0x8658}, /* Edge gain low thresh */ + {0x000a, 0x8659}, /* Edge bandwidth high threshold */ + {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}, + {0x0030, 0x8112}, /* Video drop enable, ISO streaming enable */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0xa908, 0x8802}, + {0x0034, 0x8801}, /* SSI reg addr */ + {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 { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0x1f08, 0x8802}, + {0x0006, 0x8801}, + {0x0080, 0x8800}, + /* READ { 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 */ + /* READ { 0x0000, 0x8608 } -> 0000: 15 */ + /* READ { 0x0000, 0x8609 } -> 0000: 30 */ + /* READ { 0x0000, 0x860a } -> 0000: fb */ + /* READ { 0x0000, 0x860b } -> 0000: 3e */ + /* READ { 0x0000, 0x860c } -> 0000: ce */ + /* READ { 0x0000, 0x860d } -> 0000: f4 */ + /* READ { 0x0000, 0x860e } -> 0000: eb */ + /* READ { 0x0000, 0x860f } -> 0000: dc */ + /* READ { 0x0000, 0x8610 } -> 0000: 39 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 08 */ + {0xb008, 0x8802}, + {0x0006, 0x8801}, + {0x007d, 0x8800}, + /* READ { 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}, + {0x0015, 0x8608}, + {0x0030, 0x8609}, + {0xfffb, 0x860a}, + {0x003e, 0x860b}, + {0xffce, 0x860c}, + {0xfff4, 0x860d}, + {0xffeb, 0x860e}, + {0xffdc, 0x860f}, + {0x0039, 0x8610}, + {0x0018, 0x8657}, - /* 52039 2116 */ {0x0000, 0x8508}, - /* Disable compression. */ + {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 */ + {0x0021, 0x8508}, * Enable compression. */ + {0x0032, 0x850b}, /* compression stuff */ + {0x0003, 0x8509}, /* compression stuff */ + {0x0011, 0x850a}, /* compression stuff */ + {0x0021, 0x850d}, /* compression stuff */ + {0x0010, 0x850c}, /* compression stuff */ + {0x0003, 0x8500}, /* *** Video mode: 160x120 */ + {0x0001, 0x8501}, /* Hardware-dominated snap control */ + {0x0061, 0x8656}, /* Window1 size 128x128, Windows2 size 128x128, + * gamma look-up disable, + * new edge enhancement enable */ + {0x0018, 0x8617}, /* Window1 start X (*2) */ + {0x0008, 0x8618}, /* Window1 start Y (*2) */ + {0x0061, 0x8656}, /* Window1 size 128x128, Windows2 size 128x128, + * gamma look-up disable, + * new edge enhancement enable */ + {0x0058, 0x8619}, /* Window2 start X (*2) */ + {0x0008, 0x861a}, /* Window2 start Y (*2) */ + {0x00ff, 0x8615}, /* High lum thresh for white balance */ + {0x0000, 0x8616}, /* Low lum thresh for white balance */ + {0x0012, 0x8700}, /* Clock speed 48Mhz/(2+2)/2= 6 Mhz */ + {0x0012, 0x8700}, /* Clock speed 48Mhz/(2+2)/2= 6 Mhz */ + /* READ { 0x0000, 0x8656 } -> 0000: 61 */ + {0x0028, 0x8802}, /* 375 Khz SSI clock, SSI r/w sync with VSYNC */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 28 */ + {0x1f28, 0x8802}, /* 375 Khz SSI clock, SSI r/w sync with VSYNC */ + {0x0010, 0x8801}, /* SSI reg addr */ + {0x003e, 0x8800}, /* SSI data to write */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + {0x0028, 0x8802}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 28 */ + {0x1f28, 0x8802}, + {0x0000, 0x8801}, + {0x001f, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + {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 */ + {0x0023, 0x8700}, /* Clock speed 48Mhz/(3+2)/4= 2.4 Mhz */ + {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}, + {0x0028, 0x8802}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 28 */ + {0x1f28, 0x8802}, + {0x0010, 0x8801}, + {0x007b, 0x8800}, + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + {0x002f, 0x8651}, /* R gain for white balance ... */ + {0x0080, 0x8653}, + /* READ { 0x0000, 0x8655 } -> 0000: 00 */ + {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) ) */ + {0x0030, 0x8112}, /* Video drop enable, ISO streaming enable */ + {0x0020, 0x8112}, /* Video drop enable, ISO streaming disable */ + /* UNKNOWN DIRECTION (URB_FUNCTION_SELECT_INTERFACE: (ALT=0) ) */ {} }; @@ -592,27 +506,27 @@ static const u16 spca508_init_data[][2] = * Initialization data for Intel EasyPC Camera CS110 */ static const u16 spca508cs110_init_data[][2] = { - {0x0000, 0x870b}, /* Reset CTL3 */ - {0x0003, 0x8111}, /* Soft Reset compression, memory, TG & CDSP */ - {0x0000, 0x8111}, /* Normal operation on reset */ + {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 */ + {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 */ + {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 */ + {0x000a, 0x8805}, /* a - NWG: Dunno what this is about */ {0x0000, 0x8800}, {0x0010, 0x8802}, @@ -646,459 +560,459 @@ static const u16 spca508cs110_init_data[][2] = { {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) */ + {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 */ + {0x0006, 0x8660}, /* Nibble data + input order */ - {0x000a, 0x8602}, /* Optical black level set to 0x0a */ -/* 1945 */ {0x0000, 0x8603}, /* Optical black level Offset */ + {0x000a, 0x8602}, /* Optical black level set to 0x0a */ + {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 */ +/* {0x0000, 0x8611}, * 0 R Offset for white Balance */ +/* {0x0000, 0x8612}, * 1 Gr Offset for white Balance */ +/* {0x0000, 0x8613}, * 1f B Offset for white Balance */ +/* {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) */ + {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*** */ + {0x0000, 0x8655}, + /* High bits for white balance*****brightness control*** */ {} }; static const u16 spca508_sightcam_init_data[][2] = { /* This line seems to setup the frame/canvas */ - /*368 */ {0x000f, 0x8402}, + {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}, + {0x0090, 0x8110}, + {0x0001, 0x8114}, + {0x0001, 0x8114}, + {0x0001, 0x8114}, + {0x0003, 0x8114}, + {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}, + {0x0001, 0x8801}, + {0x0004, 0x8800}, + {0x0003, 0x8801}, + {0x00e0, 0x8800}, + {0x0004, 0x8801}, + {0x00b4, 0x8800}, + {0x0005, 0x8801}, + {0x0000, 0x8800}, - /*448 */ {0x0006, 0x8801}, - /*449 */ {0x00e0, 0x8800}, - /*451 */ {0x0007, 0x8801}, - /*452 */ {0x000c, 0x8800}, + {0x0006, 0x8801}, + {0x00e0, 0x8800}, + {0x0007, 0x8801}, + {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}, + {0x0014, 0x8801}, + {0x0008, 0x8800}, + {0x0015, 0x8801}, + {0x0067, 0x8800}, + {0x0016, 0x8801}, + {0x0000, 0x8800}, + {0x0017, 0x8801}, + {0x0020, 0x8800}, + {0x0018, 0x8801}, + {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}, + {0x001e, 0x8801}, + {0x00ea, 0x8800}, + {0x001f, 0x8801}, + {0x0001, 0x8800}, + {0x0003, 0x8801}, + {0x00e0, 0x8800}, /* seems to place the colors ontop of each other #1 */ - /*517 */ {0x0006, 0x8704}, - /*518 */ {0x0001, 0x870c}, - /*519 */ {0x0016, 0x8600}, - /*520 */ {0x0002, 0x8606}, + {0x0006, 0x8704}, + {0x0001, 0x870c}, + {0x0016, 0x8600}, + {0x0002, 0x8606}, /* if not included the pictures becomes _very_ dark */ - /*521 */ {0x0064, 0x8607}, - /*522 */ {0x003a, 0x8601}, - /*523 */ {0x0000, 0x8602}, + {0x0064, 0x8607}, + {0x003a, 0x8601}, + {0x0000, 0x8602}, /* seems to place the colors ontop of each other #2 */ - /*524 */ {0x0016, 0x8600}, - /*525 */ {0x0018, 0x8617}, - /*526 */ {0x0008, 0x8618}, - /*527 */ {0x00a1, 0x8656}, + {0x0016, 0x8600}, + {0x0018, 0x8617}, + {0x0008, 0x8618}, + {0x00a1, 0x8656}, /* webcam won't start if not included */ - /*528 */ {0x0007, 0x865b}, - /*529 */ {0x0001, 0x865c}, - /*530 */ {0x0058, 0x865d}, - /*531 */ {0x0048, 0x865e}, + {0x0007, 0x865b}, + {0x0001, 0x865c}, + {0x0058, 0x865d}, + {0x0048, 0x865e}, /* adjusts the colors */ - /*541 */ {0x0049, 0x8651}, - /*542 */ {0x0040, 0x8652}, - /*543 */ {0x004c, 0x8653}, - /*544 */ {0x0040, 0x8654}, + {0x0049, 0x8651}, + {0x0040, 0x8652}, + {0x004c, 0x8653}, + {0x0040, 0x8654}, {} }; static const u16 spca508_sightcam2_init_data[][2] = { -/* 35 */ {0x0020, 0x8112}, + {0x0020, 0x8112}, -/* 36 */ {0x000f, 0x8402}, -/* 37 */ {0x0000, 0x8403}, + {0x000f, 0x8402}, + {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}, + {0x0008, 0x8201}, + {0x0008, 0x8200}, + {0x0001, 0x8200}, + {0x0009, 0x8201}, + {0x0008, 0x8200}, + {0x0001, 0x8200}, + {0x000a, 0x8201}, + {0x0008, 0x8200}, + {0x0001, 0x8200}, + {0x000b, 0x8201}, + {0x0008, 0x8200}, + {0x0001, 0x8200}, + {0x000c, 0x8201}, + {0x0008, 0x8200}, + {0x0001, 0x8200}, + {0x000d, 0x8201}, + {0x0008, 0x8200}, + {0x0001, 0x8200}, + {0x000e, 0x8201}, + {0x0008, 0x8200}, + {0x0001, 0x8200}, + {0x0007, 0x8201}, + {0x0008, 0x8200}, + {0x0001, 0x8200}, + {0x000f, 0x8201}, + {0x0008, 0x8200}, + {0x0001, 0x8200}, -/* 84 */ {0x0018, 0x8660}, -/* 85 */ {0x0010, 0x8201}, + {0x0018, 0x8660}, + {0x0010, 0x8201}, -/* 86 */ {0x0008, 0x8200}, -/* 87 */ {0x0001, 0x8200}, -/* 90 */ {0x0011, 0x8201}, -/* 91 */ {0x0008, 0x8200}, -/* 92 */ {0x0001, 0x8200}, + {0x0008, 0x8200}, + {0x0001, 0x8200}, + {0x0011, 0x8201}, + {0x0008, 0x8200}, + {0x0001, 0x8200}, -/* 95 */ {0x0000, 0x86b0}, -/* 96 */ {0x0034, 0x86b1}, -/* 97 */ {0x0000, 0x86b2}, -/* 98 */ {0x0049, 0x86b3}, -/* 99 */ {0x0000, 0x86b4}, -/* 100 */ {0x0000, 0x86b4}, + {0x0000, 0x86b0}, + {0x0034, 0x86b1}, + {0x0000, 0x86b2}, + {0x0049, 0x86b3}, + {0x0000, 0x86b4}, + {0x0000, 0x86b4}, -/* 101 */ {0x0012, 0x8201}, -/* 102 */ {0x0008, 0x8200}, -/* 103 */ {0x0001, 0x8200}, -/* 106 */ {0x0013, 0x8201}, -/* 107 */ {0x0008, 0x8200}, -/* 108 */ {0x0001, 0x8200}, + {0x0012, 0x8201}, + {0x0008, 0x8200}, + {0x0001, 0x8200}, + {0x0013, 0x8201}, + {0x0008, 0x8200}, + {0x0001, 0x8200}, -/* 111 */ {0x0001, 0x86b0}, -/* 112 */ {0x00aa, 0x86b1}, -/* 113 */ {0x0000, 0x86b2}, -/* 114 */ {0x00e4, 0x86b3}, -/* 115 */ {0x0000, 0x86b4}, -/* 116 */ {0x0000, 0x86b4}, + {0x0001, 0x86b0}, + {0x00aa, 0x86b1}, + {0x0000, 0x86b2}, + {0x00e4, 0x86b3}, + {0x0000, 0x86b4}, + {0x0000, 0x86b4}, -/* 118 */ {0x0018, 0x8660}, + {0x0018, 0x8660}, -/* 119 */ {0x0090, 0x8110}, -/* 120 */ {0x0001, 0x8114}, -/* 121 */ {0x0001, 0x8114}, -/* 122 */ {0x0001, 0x8114}, -/* 123 */ {0x0003, 0x8114}, + {0x0090, 0x8110}, + {0x0001, 0x8114}, + {0x0001, 0x8114}, + {0x0001, 0x8114}, + {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}, + {0x0080, 0x8804}, + {0x0003, 0x8801}, + {0x0012, 0x8800}, + {0x0004, 0x8801}, + {0x0005, 0x8800}, + {0x0005, 0x8801}, + {0x0000, 0x8800}, + {0x0006, 0x8801}, + {0x0000, 0x8800}, + {0x0007, 0x8801}, + {0x0000, 0x8800}, + {0x0008, 0x8801}, + {0x0005, 0x8800}, + {0x000a, 0x8700}, + {0x000e, 0x8801}, + {0x0004, 0x8800}, + {0x0005, 0x8801}, + {0x0047, 0x8800}, + {0x0006, 0x8801}, + {0x0000, 0x8800}, + {0x0007, 0x8801}, + {0x00c0, 0x8800}, + {0x0008, 0x8801}, + {0x0003, 0x8800}, + {0x0013, 0x8801}, + {0x0001, 0x8800}, + {0x0009, 0x8801}, + {0x0000, 0x8800}, + {0x000a, 0x8801}, + {0x0000, 0x8800}, + {0x000b, 0x8801}, + {0x0000, 0x8800}, + {0x000c, 0x8801}, + {0x0000, 0x8800}, + {0x000e, 0x8801}, + {0x0004, 0x8800}, + {0x000f, 0x8801}, + {0x0000, 0x8800}, + {0x0010, 0x8801}, + {0x0006, 0x8800}, + {0x0011, 0x8801}, + {0x0006, 0x8800}, + {0x0012, 0x8801}, + {0x0000, 0x8800}, + {0x0013, 0x8801}, + {0x0001, 0x8800}, -/* 224 */ {0x000a, 0x8700}, -/* 225 */ {0x0000, 0x8702}, -/* 226 */ {0x0000, 0x8703}, -/* 227 */ {0x00c2, 0x8704}, -/* 228 */ {0x0001, 0x870c}, + {0x000a, 0x8700}, + {0x0000, 0x8702}, + {0x0000, 0x8703}, + {0x00c2, 0x8704}, + {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}, + {0x0044, 0x8600}, + {0x0002, 0x8606}, + {0x0064, 0x8607}, + {0x003a, 0x8601}, + {0x0008, 0x8602}, + {0x0044, 0x8600}, + {0x0018, 0x8617}, + {0x0008, 0x8618}, + {0x00a1, 0x8656}, + {0x0004, 0x865b}, + {0x0002, 0x865c}, + {0x0058, 0x865d}, + {0x0048, 0x865e}, + {0x0012, 0x8608}, + {0x002c, 0x8609}, + {0x0002, 0x860a}, + {0x002c, 0x860b}, + {0x00db, 0x860c}, + {0x00f9, 0x860d}, + {0x00f1, 0x860e}, + {0x00e3, 0x860f}, + {0x002c, 0x8610}, + {0x006c, 0x8651}, + {0x0041, 0x8652}, + {0x0059, 0x8653}, + {0x0040, 0x8654}, + {0x00fa, 0x8611}, + {0x00ff, 0x8612}, + {0x00f8, 0x8613}, + {0x0000, 0x8614}, + {0x0001, 0x863f}, + {0x0000, 0x8640}, + {0x0026, 0x8641}, + {0x0045, 0x8642}, + {0x0060, 0x8643}, + {0x0075, 0x8644}, + {0x0088, 0x8645}, + {0x009b, 0x8646}, + {0x00b0, 0x8647}, + {0x00c5, 0x8648}, + {0x00d2, 0x8649}, + {0x00dc, 0x864a}, + {0x00e5, 0x864b}, + {0x00eb, 0x864c}, + {0x00f0, 0x864d}, + {0x00f6, 0x864e}, + {0x00fa, 0x864f}, + {0x00ff, 0x8650}, + {0x0060, 0x8657}, + {0x0010, 0x8658}, + {0x0018, 0x8659}, + {0x0005, 0x865a}, + {0x0018, 0x8660}, + {0x0003, 0x8509}, + {0x0011, 0x850a}, + {0x0032, 0x850b}, + {0x0010, 0x850c}, + {0x0021, 0x850d}, + {0x0001, 0x8500}, + {0x0000, 0x8508}, + {0x0012, 0x8608}, + {0x002c, 0x8609}, + {0x0002, 0x860a}, + {0x0039, 0x860b}, + {0x00d0, 0x860c}, + {0x00f7, 0x860d}, + {0x00ed, 0x860e}, + {0x00db, 0x860f}, + {0x0039, 0x8610}, + {0x0012, 0x8657}, + {0x000c, 0x8619}, + {0x0004, 0x861a}, + {0x00a1, 0x8656}, + {0x00c8, 0x8615}, + {0x0032, 0x8616}, -/* 306 */ {0x0030, 0x8112}, -/* 313 */ {0x0020, 0x8112}, -/* 314 */ {0x0020, 0x8112}, -/* 315 */ {0x000f, 0x8402}, -/* 316 */ {0x0000, 0x8403}, + {0x0030, 0x8112}, + {0x0020, 0x8112}, + {0x0020, 0x8112}, + {0x000f, 0x8402}, + {0x0000, 0x8403}, -/* 317 */ {0x0090, 0x8110}, -/* 318 */ {0x0001, 0x8114}, -/* 319 */ {0x0001, 0x8114}, -/* 320 */ {0x0001, 0x8114}, -/* 321 */ {0x0003, 0x8114}, -/* 322 */ {0x0080, 0x8804}, + {0x0090, 0x8110}, + {0x0001, 0x8114}, + {0x0001, 0x8114}, + {0x0001, 0x8114}, + {0x0003, 0x8114}, + {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}, + {0x0003, 0x8801}, + {0x0012, 0x8800}, + {0x0004, 0x8801}, + {0x0005, 0x8800}, + {0x0005, 0x8801}, + {0x0047, 0x8800}, + {0x0006, 0x8801}, + {0x0000, 0x8800}, + {0x0007, 0x8801}, + {0x00c0, 0x8800}, + {0x0008, 0x8801}, + {0x0003, 0x8800}, + {0x000a, 0x8700}, + {0x000e, 0x8801}, + {0x0004, 0x8800}, + {0x0005, 0x8801}, + {0x0047, 0x8800}, + {0x0006, 0x8801}, + {0x0000, 0x8800}, + {0x0007, 0x8801}, + {0x00c0, 0x8800}, + {0x0008, 0x8801}, + {0x0003, 0x8800}, + {0x0013, 0x8801}, + {0x0001, 0x8800}, + {0x0009, 0x8801}, + {0x0000, 0x8800}, + {0x000a, 0x8801}, + {0x0000, 0x8800}, + {0x000b, 0x8801}, + {0x0000, 0x8800}, + {0x000c, 0x8801}, + {0x0000, 0x8800}, + {0x000e, 0x8801}, + {0x0004, 0x8800}, + {0x000f, 0x8801}, + {0x0000, 0x8800}, + {0x0010, 0x8801}, + {0x0006, 0x8800}, + {0x0011, 0x8801}, + {0x0006, 0x8800}, + {0x0012, 0x8801}, + {0x0000, 0x8800}, + {0x0013, 0x8801}, + {0x0001, 0x8800}, + {0x000a, 0x8700}, + {0x0000, 0x8702}, + {0x0000, 0x8703}, + {0x00c2, 0x8704}, + {0x0001, 0x870c}, + {0x0044, 0x8600}, + {0x0002, 0x8606}, + {0x0064, 0x8607}, + {0x003a, 0x8601}, + {0x0008, 0x8602}, + {0x0044, 0x8600}, + {0x0018, 0x8617}, + {0x0008, 0x8618}, + {0x00a1, 0x8656}, + {0x0004, 0x865b}, + {0x0002, 0x865c}, + {0x0058, 0x865d}, + {0x0048, 0x865e}, + {0x0012, 0x8608}, + {0x002c, 0x8609}, + {0x0002, 0x860a}, + {0x002c, 0x860b}, + {0x00db, 0x860c}, + {0x00f9, 0x860d}, + {0x00f1, 0x860e}, + {0x00e3, 0x860f}, + {0x002c, 0x8610}, + {0x006c, 0x8651}, + {0x0041, 0x8652}, + {0x0059, 0x8653}, + {0x0040, 0x8654}, + {0x00fa, 0x8611}, + {0x00ff, 0x8612}, + {0x00f8, 0x8613}, + {0x0000, 0x8614}, + {0x0001, 0x863f}, + {0x0000, 0x8640}, + {0x0026, 0x8641}, + {0x0045, 0x8642}, + {0x0060, 0x8643}, + {0x0075, 0x8644}, + {0x0088, 0x8645}, + {0x009b, 0x8646}, + {0x00b0, 0x8647}, + {0x00c5, 0x8648}, + {0x00d2, 0x8649}, + {0x00dc, 0x864a}, + {0x00e5, 0x864b}, + {0x00eb, 0x864c}, + {0x00f0, 0x864d}, + {0x00f6, 0x864e}, + {0x00fa, 0x864f}, + {0x00ff, 0x8650}, + {0x0060, 0x8657}, + {0x0010, 0x8658}, + {0x0018, 0x8659}, + {0x0005, 0x865a}, + {0x0018, 0x8660}, + {0x0003, 0x8509}, + {0x0011, 0x850a}, + {0x0032, 0x850b}, + {0x0010, 0x850c}, + {0x0021, 0x850d}, + {0x0001, 0x8500}, + {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}, + {0x0012, 0x8608}, + {0x002c, 0x8609}, + {0x0002, 0x860a}, + {0x0039, 0x860b}, + {0x00d0, 0x860c}, + {0x00f7, 0x860d}, + {0x00ed, 0x860e}, + {0x00db, 0x860f}, + {0x0039, 0x8610}, + {0x0012, 0x8657}, + {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}, */ +/* {0x0030, 0x8112}, */ {} }; @@ -1109,14 +1023,14 @@ static const u16 spca508_vista_init_data[][2] = { {0x0008, 0x8200}, /* Clear register */ {0x0000, 0x870b}, /* Reset CTL3 */ {0x0020, 0x8112}, /* Video Drop packet enable */ - {0x0003, 0x8111}, /* Soft Reset compression, memory, TG & CDSP */ + {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 */ + {0x0090, 0x8110}, /* Enable: SSI output, External 2X clock output */ {0x0020, 0x8112}, {0x0000, 0x8114}, {0x0001, 0x8114}, @@ -1129,191 +1043,143 @@ static const u16 spca508_vista_init_data[][2] = { {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 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 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 { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0, 0x0001, 0x8803 } -> - 0000: 00 */ - /* READ { 0, 0x0001, 0x8802 } -> - 0000: 10 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 10 */ {0x0010, 0x8802}, {0x0009, 0x8801}, {0x0042, 0x8805}, {0x0001, 0x8800}, - /* READ { 0, 0x0001, 0x8803 } -> - 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0, 0x0001, 0x8803 } -> - 0000: 00 */ - /* READ { 0, 0x0001, 0x8802 } -> - 0000: 10 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 10 */ {0x0010, 0x8802}, {0x003c, 0x8801}, {0x0001, 0x8805}, {0x0000, 0x8800}, - /* READ { 0, 0x0001, 0x8803 } -> - 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0, 0x0001, 0x8803 } -> - 0000: 00 */ - /* READ { 0, 0x0001, 0x8802 } -> - 0000: 10 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 10 */ {0x0010, 0x8802}, {0x0001, 0x8801}, {0x000a, 0x8805}, {0x0000, 0x8800}, - /* READ { 0, 0x0001, 0x8803 } -> - 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0, 0x0001, 0x8803 } -> - 0000: 00 */ - /* READ { 0, 0x0001, 0x8802 } -> - 0000: 10 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 10 */ {0x0010, 0x8802}, {0x0002, 0x8801}, {0x0000, 0x8805}, {0x0000, 0x8800}, - /* READ { 0, 0x0001, 0x8803 } -> - 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0, 0x0001, 0x8803 } -> - 0000: 00 */ - /* READ { 0, 0x0001, 0x8802 } -> - 0000: 10 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 10 */ {0x0010, 0x8802}, {0x0003, 0x8801}, {0x0027, 0x8805}, {0x0001, 0x8800}, - /* READ { 0, 0x0001, 0x8803 } -> - 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0, 0x0001, 0x8803 } -> - 0000: 00 */ - /* READ { 0, 0x0001, 0x8802 } -> - 0000: 10 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 10 */ {0x0010, 0x8802}, {0x0004, 0x8801}, {0x0065, 0x8805}, {0x0001, 0x8800}, - /* READ { 0, 0x0001, 0x8803 } -> - 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0, 0x0001, 0x8803 } -> - 0000: 00 */ - /* READ { 0, 0x0001, 0x8802 } -> - 0000: 10 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 10 */ {0x0010, 0x8802}, {0x0005, 0x8801}, {0x0003, 0x8805}, {0x0000, 0x8800}, - /* READ { 0, 0x0001, 0x8803 } -> - 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0, 0x0001, 0x8803 } -> - 0000: 00 */ - /* READ { 0, 0x0001, 0x8802 } -> - 0000: 10 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 10 */ {0x0010, 0x8802}, {0x0006, 0x8801}, {0x001c, 0x8805}, {0x0000, 0x8800}, - /* READ { 0, 0x0001, 0x8803 } -> - 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0, 0x0001, 0x8803 } -> - 0000: 00 */ - /* READ { 0, 0x0001, 0x8802 } -> - 0000: 10 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 10 */ {0x0010, 0x8802}, {0x0007, 0x8801}, {0x002a, 0x8805}, {0x0000, 0x8800}, - /* READ { 0, 0x0001, 0x8803 } -> - 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0, 0x0001, 0x8803 } -> - 0000: 00 */ - /* READ { 0, 0x0001, 0x8802 } -> - 0000: 10 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 10 */ {0x0010, 0x8802}, {0x000e, 0x8801}, {0x0000, 0x8805}, {0x0000, 0x8800}, - /* READ { 0, 0x0001, 0x8803 } -> - 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0, 0x0001, 0x8803 } -> - 0000: 00 */ - /* READ { 0, 0x0001, 0x8802 } -> - 0000: 10 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 10 */ {0x0010, 0x8802}, {0x0028, 0x8801}, {0x002e, 0x8805}, {0x0000, 0x8800}, - /* READ { 0, 0x0001, 0x8803 } -> - 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0, 0x0001, 0x8803 } -> - 0000: 00 */ - /* READ { 0, 0x0001, 0x8802 } -> - 0000: 10 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 10 */ {0x0010, 0x8802}, {0x0039, 0x8801}, {0x0013, 0x8805}, {0x0000, 0x8800}, - /* READ { 0, 0x0001, 0x8803 } -> - 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0, 0x0001, 0x8803 } -> - 0000: 00 */ - /* READ { 0, 0x0001, 0x8802 } -> - 0000: 10 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 10 */ {0x0010, 0x8802}, {0x003b, 0x8801}, {0x000c, 0x8805}, {0x0000, 0x8800}, - /* READ { 0, 0x0001, 0x8803 } -> - 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0, 0x0001, 0x8803 } -> - 0000: 00 */ - /* READ { 0, 0x0001, 0x8802 } -> - 0000: 10 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 10 */ {0x0010, 0x8802}, {0x0035, 0x8801}, {0x0028, 0x8805}, {0x0000, 0x8800}, - /* READ { 0, 0x0001, 0x8803 } -> - 0000: 00 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ - /* READ { 0, 0x0001, 0x8803 } -> - 0000: 00 */ - /* READ { 0, 0x0001, 0x8802 } -> - 0000: 10 */ + /* READ { 0x0001, 0x8803 } -> 0000: 00 */ + /* READ { 0x0001, 0x8802 } -> 0000: 10 */ {0x0010, 0x8802}, {0x0009, 0x8801}, {0x0042, 0x8805}, {0x0001, 0x8800}, - /* READ { 0, 0x0001, 0x8803 } -> - 0000: 00 */ + /* READ { 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 */ + {0x0001, 0x8606}, /* 1 Line memory Read Counter (H) Result: (d)410 */ {0x0023, 0x8601}, {0x0010, 0x8602}, {0x000a, 0x8603}, - {0x009A, 0x8600}, + {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) */ @@ -1329,7 +1195,7 @@ static const u16 spca508_vista_init_data[][2] = { {0x0005, 0x860a}, /* ... */ {0x0025, 0x860b}, {0x00e1, 0x860c}, - {0x00fa, 0x860D}, + {0x00fa, 0x860d}, {0x00f4, 0x860e}, {0x00e8, 0x860f}, {0x0025, 0x8610}, /* A33 Coef. */ @@ -1344,11 +1210,12 @@ static const u16 spca508_vista_init_data[][2] = { {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 */ + {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 */ + {0x000a, 0x8659}, /* Edge bandwidth high threshold */ {0x0005, 0x865a}, /* Edge bandwidth low threshold */ {0x0064, 0x8607}, /* UV filter enable */ @@ -1384,29 +1251,20 @@ static const u16 spca508_vista_init_data[][2] = { {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 */ + /* READ { 0x0000, 0x8608 } -> 0000: 13 */ + /* READ { 0x0000, 0x8609 } -> 0000: 28 */ + /* READ { 0x0000, 0x8610 } -> 0000: 05 */ + /* READ { 0x0000, 0x8611 } -> 0000: 25 */ + /* READ { 0x0000, 0x8612 } -> 0000: e1 */ + /* READ { 0x0000, 0x8613 } -> 0000: fa */ + /* READ { 0x0000, 0x8614 } -> 0000: f4 */ + /* READ { 0x0000, 0x8615 } -> 0000: e8 */ + /* READ { 0x0000, 0x8616 } -> 0000: 25 */ {} }; static int reg_write(struct usb_device *dev, - __u16 index, __u16 value) + u16 index, u16 value) { int ret; @@ -1425,7 +1283,7 @@ static int reg_write(struct usb_device *dev, /* read 1 byte */ /* returns: negative is error, pos or zero is data */ static int reg_read(struct gspca_dev *gspca_dev, - __u16 index) /* wIndex */ + u16 index) /* wIndex */ { int ret; @@ -1447,16 +1305,16 @@ static int reg_read(struct gspca_dev *gspca_dev, } static int write_vector(struct gspca_dev *gspca_dev, - const u16 data[][2]) + const u16 (*data)[2]) { struct usb_device *dev = gspca_dev->dev; - int ret, i = 0; + int ret; - while (data[i][1] != 0) { - ret = reg_write(dev, data[i][1], data[i][0]); + while ((*data)[1] != 0) { + ret = reg_write(dev, (*data)[1], (*data)[0]); if (ret < 0) return ret; - i++; + data++; } return 0; } @@ -1468,6 +1326,15 @@ static int sd_config(struct gspca_dev *gspca_dev, struct sd *sd = (struct sd *) gspca_dev; struct cam *cam; int data1, data2; + const u16 (*init_data)[2]; + static const u16 (*(init_data_tb[]))[2] = { + spca508_vista_init_data, /* CreativeVista 0 */ + spca508_sightcam_init_data, /* HamaUSBSightcam 1 */ + spca508_sightcam2_init_data, /* HamaUSBSightcam2 2 */ + spca508cs110_init_data, /* IntelEasyPCCamera 3 */ + spca508cs110_init_data, /* MicroInnovationIC200 4 */ + spca508_init_data, /* ViewQuestVQ110 5 */ + }; /* Read from global register the USB product and vendor IDs, just to * prove that we can communicate with the device. This works, which @@ -1491,37 +1358,13 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->subtype = id->driver_info; 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 */ + init_data = init_data_tb[sd->subtype]; + return write_vector(gspca_dev, init_data); } /* this function is called at probe and resume time */ static int sd_init(struct gspca_dev *gspca_dev) { -/* write_vector(gspca_dev, spca508_open_data); */ return 0; } @@ -1529,7 +1372,7 @@ static int sd_start(struct gspca_dev *gspca_dev) { int mode; - mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; + mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; reg_write(gspca_dev->dev, 0x8500, mode); switch (mode) { case 0: @@ -1554,7 +1397,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev) static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame, /* target */ - __u8 *data, /* isoc packet */ + u8 *data, /* isoc packet */ int len) /* iso packet length */ { switch (data[0]) { @@ -1567,7 +1410,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, data, len); break; case 0xff: /* drop */ -/* gspca_dev->last_packet_type = DISCARD_PACKET; */ break; default: data += 1; @@ -1581,7 +1423,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, static void setbrightness(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - __u8 brightness = sd->brightness; + u8 brightness = sd->brightness; /* MX seem contrast */ reg_write(gspca_dev->dev, 0x8651, brightness); diff --git a/drivers/media/video/gspca/spca561.c b/drivers/media/video/gspca/spca561.c index c99c5e34e211..27e82b35f3e7 100644 --- a/drivers/media/video/gspca/spca561.c +++ b/drivers/media/video/gspca/spca561.c @@ -34,8 +34,8 @@ struct sd { __u16 exposure; /* rev12a only */ #define EXPOSURE_MIN 1 -#define EXPOSURE_DEF 200 -#define EXPOSURE_MAX (4095 - 900) /* see set_exposure */ +#define EXPOSURE_DEF 700 /* == 10 fps */ +#define EXPOSURE_MAX (2047 + 325) /* see setexposure */ __u8 contrast; /* rev72a only */ #define CONTRAST_MIN 0x00 @@ -48,9 +48,9 @@ struct sd { #define BRIGHTNESS_MAX 0x3f __u8 white; -#define WHITE_MIN 1 -#define WHITE_DEF 0x40 -#define WHITE_MAX 0x7f +#define HUE_MIN 1 +#define HUE_DEF 0x40 +#define HUE_MAX 0x7f __u8 autogain; #define AUTOGAIN_MIN 0 @@ -58,9 +58,9 @@ struct sd { #define AUTOGAIN_MAX 1 __u8 gain; /* rev12a only */ -#define GAIN_MIN 0x0 -#define GAIN_DEF 0x24 -#define GAIN_MAX 0x24 +#define GAIN_MIN 0 +#define GAIN_DEF 63 +#define GAIN_MAX 255 #define EXPO12A_DEF 3 __u8 expo12a; /* expo/gain? for rev 12a */ @@ -461,7 +461,7 @@ static int sd_config(struct gspca_dev *gspca_dev, } sd->brightness = BRIGHTNESS_DEF; sd->contrast = CONTRAST_DEF; - sd->white = WHITE_DEF; + sd->white = HUE_DEF; sd->exposure = EXPOSURE_DEF; sd->autogain = AUTOGAIN_DEF; sd->gain = GAIN_DEF; @@ -549,8 +549,7 @@ static void setcontrast(struct gspca_dev *gspca_dev) static void setexposure(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - int expo; - int clock_divider; + int i, expo = 0; /* Register 0x8309 controls exposure for the spca561, the basic exposure setting goes from 1-2047, where 1 is completely @@ -564,16 +563,22 @@ static void setexposure(struct gspca_dev *gspca_dev) configure a divider for the base framerate which us used at the exposure setting of 1-300. These bits configure the base framerate according to the following formula: fps = 60 / (value + 2) */ - if (sd->exposure < 2048) { - expo = sd->exposure; - clock_divider = 0; - } else { - /* Add 900 to make the 0 setting of the second part of the - exposure equal to the 2047 setting of the first part. */ - expo = (sd->exposure - 2048) + 900; - clock_divider = 3; + + /* We choose to use the high bits setting the fixed framerate divisor + asap, as setting high basic exposure setting without the fixed + divider in combination with high gains makes the cam stop */ + int table[] = { 0, 450, 550, 625, EXPOSURE_MAX }; + + for (i = 0; i < ARRAY_SIZE(table) - 1; i++) { + if (sd->exposure <= table[i + 1]) { + expo = sd->exposure - table[i]; + if (i) + expo += 300; + expo |= i << 11; + break; + } } - expo |= clock_divider << 11; + gspca_dev->usb_buf[0] = expo; gspca_dev->usb_buf[1] = expo >> 8; reg_w_buf(gspca_dev, 0x8309, 2); @@ -584,7 +589,16 @@ static void setgain(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - gspca_dev->usb_buf[0] = sd->gain; + /* gain reg low 6 bits 0-63 gain, bit 6 and 7, both double the + sensitivity when set, so 31 + one of them set == 63, and 15 + with both of them set == 63 */ + if (sd->gain < 64) + gspca_dev->usb_buf[0] = sd->gain; + else if (sd->gain < 128) + gspca_dev->usb_buf[0] = (sd->gain / 2) | 0x40; + else + gspca_dev->usb_buf[0] = (sd->gain / 4) | 0xC0; + gspca_dev->usb_buf[1] = 0; reg_w_buf(gspca_dev, 0x8335, 2); } @@ -629,8 +643,7 @@ static int sd_start_12a(struct gspca_dev *gspca_dev) reg_w_buf(gspca_dev, 0x8391, 8); reg_w_buf(gspca_dev, 0x8390, 8); setwhite(gspca_dev); - setautogain(gspca_dev); -/* setgain(gspca_dev); */ + setgain(gspca_dev); setexposure(gspca_dev); return 0; } @@ -762,18 +775,6 @@ static void do_autogain(struct gspca_dev *gspca_dev) i2c_write(gspca_dev, expotimes | pixelclk, 0x09); } break; - case Rev012A: - reg_r(gspca_dev, 0x8330, 2); - if (gspca_dev->usb_buf[1] > 0x08) { - gspca_dev->usb_buf[0] = ++sd->expo12a; - gspca_dev->usb_buf[1] = 0; - reg_w_buf(gspca_dev, 0x8339, 2); - } else if (gspca_dev->usb_buf[1] < 0x02) { - gspca_dev->usb_buf[0] = --sd->expo12a; - gspca_dev->usb_buf[1] = 0; - reg_w_buf(gspca_dev, 0x8339, 2); - } - break; } } @@ -928,13 +929,13 @@ static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val) static struct ctrl sd_ctrls_12a[] = { { { - .id = V4L2_CID_DO_WHITE_BALANCE, + .id = V4L2_CID_HUE, .type = V4L2_CTRL_TYPE_INTEGER, - .name = "White Balance", - .minimum = WHITE_MIN, - .maximum = WHITE_MAX, + .name = "Hue", + .minimum = HUE_MIN, + .maximum = HUE_MAX, .step = 1, - .default_value = WHITE_DEF, + .default_value = HUE_DEF, }, .set = sd_setwhite, .get = sd_getwhite, @@ -952,19 +953,6 @@ static struct ctrl sd_ctrls_12a[] = { .set = sd_setexposure, .get = sd_getexposure, }, - { - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Auto Gain", - .minimum = AUTOGAIN_MIN, - .maximum = AUTOGAIN_MAX, - .step = 1, - .default_value = AUTOGAIN_DEF, - }, - .set = sd_setautogain, - .get = sd_getautogain, - }, { { .id = V4L2_CID_GAIN, @@ -983,13 +971,13 @@ static struct ctrl sd_ctrls_12a[] = { static struct ctrl sd_ctrls_72a[] = { { { - .id = V4L2_CID_DO_WHITE_BALANCE, + .id = V4L2_CID_HUE, .type = V4L2_CTRL_TYPE_INTEGER, - .name = "White Balance", - .minimum = WHITE_MIN, - .maximum = WHITE_MAX, + .name = "Hue", + .minimum = HUE_MIN, + .maximum = HUE_MAX, .step = 1, - .default_value = WHITE_DEF, + .default_value = HUE_DEF, }, .set = sd_setwhite, .get = sd_getwhite, @@ -1046,7 +1034,6 @@ static const struct sd_desc sd_desc_12a = { .stopN = sd_stopN, .stop0 = sd_stop0, .pkt_scan = sd_pkt_scan, -/* .dq_callback = do_autogain, * fixme */ }; static const struct sd_desc sd_desc_72a = { .name = MODULE_NAME, diff --git a/drivers/media/video/gspca/sq905.c b/drivers/media/video/gspca/sq905.c index 2e1cdf068fda..715a68f0156e 100644 --- a/drivers/media/video/gspca/sq905.c +++ b/drivers/media/video/gspca/sq905.c @@ -309,6 +309,7 @@ static int sd_config(struct gspca_dev *gspca_dev, struct sd *dev = (struct sd *) gspca_dev; /* We don't use the buffer gspca allocates so make it small. */ + cam->bulk = 1; cam->bulk_size = 64; INIT_WORK(&dev->work_struct, sq905_dostream); diff --git a/drivers/media/video/gspca/sq905c.c b/drivers/media/video/gspca/sq905c.c index 0bcb74a1b143..916892505432 100644 --- a/drivers/media/video/gspca/sq905c.c +++ b/drivers/media/video/gspca/sq905c.c @@ -206,6 +206,7 @@ static int sd_config(struct gspca_dev *gspca_dev, cam->nmodes = 1; /* We don't use the buffer gspca allocates so make it small. */ cam->bulk_size = 32; + cam->bulk = 1; INIT_WORK(&dev->work_struct, sq905c_dostream); return 0; } diff --git a/drivers/media/video/gspca/stv06xx/Makefile b/drivers/media/video/gspca/stv06xx/Makefile index feeaa94ab588..2f3c3a606ce4 100644 --- a/drivers/media/video/gspca/stv06xx/Makefile +++ b/drivers/media/video/gspca/stv06xx/Makefile @@ -3,7 +3,8 @@ obj-$(CONFIG_USB_STV06XX) += gspca_stv06xx.o gspca_stv06xx-objs := stv06xx.o \ stv06xx_vv6410.o \ stv06xx_hdcs.o \ - stv06xx_pb0100.o + stv06xx_pb0100.o \ + stv06xx_st6422.o EXTRA_CFLAGS += -Idrivers/media/video/gspca diff --git a/drivers/media/video/gspca/stv06xx/stv06xx.c b/drivers/media/video/gspca/stv06xx/stv06xx.c index 9dff2e65b116..0da8e0de0456 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx.c +++ b/drivers/media/video/gspca/stv06xx/stv06xx.c @@ -92,11 +92,10 @@ static int stv06xx_write_sensor_finish(struct sd *sd) { int err = 0; - if (IS_850(sd)) { + if (sd->bridge == BRIDGE_STV610) { struct usb_device *udev = sd->gspca_dev.dev; __u8 *buf = sd->gspca_dev.usb_buf; - /* Quickam Web needs an extra packet */ buf[0] = 0; err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x04, 0x40, 0x1704, 0, buf, 1, @@ -253,7 +252,7 @@ static int stv06xx_init(struct gspca_dev *gspca_dev) err = sd->sensor->init(sd); - if (dump_sensor) + if (dump_sensor && sd->sensor->dump) sd->sensor->dump(sd); return (err < 0) ? err : 0; @@ -293,8 +292,6 @@ static void stv06xx_stopN(struct gspca_dev *gspca_dev) goto out; err = sd->sensor->stop(sd); - if (err < 0) - goto out; out: if (err < 0) @@ -320,6 +317,8 @@ static void stv06xx_pkt_scan(struct gspca_dev *gspca_dev, __u8 *data, /* isoc packet */ int len) /* iso packet length */ { + struct sd *sd = (struct sd *) gspca_dev; + PDEBUG(D_PACK, "Packet of length %d arrived", len); /* A packet may contain several frames @@ -345,14 +344,29 @@ static void stv06xx_pkt_scan(struct gspca_dev *gspca_dev, if (len < chunk_len) { PDEBUG(D_ERR, "URB packet length is smaller" " than the specified chunk length"); + gspca_dev->last_packet_type = DISCARD_PACKET; return; } + /* First byte seem to be 02=data 2nd byte is unknown??? */ + if (sd->bridge == BRIDGE_ST6422 && (id & 0xFF00) == 0x0200) + goto frame_data; + switch (id) { case 0x0200: case 0x4200: +frame_data: PDEBUG(D_PACK, "Frame data packet detected"); + if (sd->to_skip) { + int skip = (sd->to_skip < chunk_len) ? + sd->to_skip : chunk_len; + data += skip; + len -= skip; + chunk_len -= skip; + sd->to_skip -= skip; + } + gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, chunk_len); break; @@ -367,6 +381,9 @@ static void stv06xx_pkt_scan(struct gspca_dev *gspca_dev, gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, 0); + if (sd->bridge == BRIDGE_ST6422) + sd->to_skip = gspca_dev->width * 4; + if (chunk_len) PDEBUG(D_ERR, "Chunk length is " "non-zero on a SOF"); @@ -397,8 +414,12 @@ static void stv06xx_pkt_scan(struct gspca_dev *gspca_dev, /* Unknown chunk with 2 bytes of data, occurs 2-3 times per USB interrupt */ break; + case 0x42ff: + PDEBUG(D_PACK, "Chunk 0x42ff detected"); + /* Special chunk seen sometimes on the ST6422 */ + break; default: - PDEBUG(D_PACK, "Unknown chunk %d detected", id); + PDEBUG(D_PACK, "Unknown chunk 0x%04x detected", id); /* Unknown chunk */ } data += chunk_len; @@ -430,11 +451,16 @@ static int stv06xx_config(struct gspca_dev *gspca_dev, cam = &gspca_dev->cam; sd->desc = sd_desc; + sd->bridge = id->driver_info; gspca_dev->sd_desc = &sd->desc; if (dump_bridge) stv06xx_dump_bridge(sd); + sd->sensor = &stv06xx_sensor_st6422; + if (!sd->sensor->probe(sd)) + return 0; + sd->sensor = &stv06xx_sensor_vv6410; if (!sd->sensor->probe(sd)) return 0; @@ -459,9 +485,20 @@ static int stv06xx_config(struct gspca_dev *gspca_dev, /* -- module initialisation -- */ static const __devinitdata struct usb_device_id device_table[] = { - {USB_DEVICE(0x046d, 0x0840)}, /* QuickCam Express */ - {USB_DEVICE(0x046d, 0x0850)}, /* LEGO cam / QuickCam Web */ - {USB_DEVICE(0x046d, 0x0870)}, /* Dexxa WebCam USB */ + /* QuickCam Express */ + {USB_DEVICE(0x046d, 0x0840), .driver_info = BRIDGE_STV600 }, + /* LEGO cam / QuickCam Web */ + {USB_DEVICE(0x046d, 0x0850), .driver_info = BRIDGE_STV610 }, + /* Dexxa WebCam USB */ + {USB_DEVICE(0x046d, 0x0870), .driver_info = BRIDGE_STV602 }, + /* QuickCam Messenger */ + {USB_DEVICE(0x046D, 0x08F0), .driver_info = BRIDGE_ST6422 }, + /* QuickCam Communicate */ + {USB_DEVICE(0x046D, 0x08F5), .driver_info = BRIDGE_ST6422 }, + /* QuickCam Messenger (new) */ + {USB_DEVICE(0x046D, 0x08F6), .driver_info = BRIDGE_ST6422 }, + /* QuickCam Messenger (new) */ + {USB_DEVICE(0x046D, 0x08DA), .driver_info = BRIDGE_ST6422 }, {} }; MODULE_DEVICE_TABLE(usb, device_table); diff --git a/drivers/media/video/gspca/stv06xx/stv06xx.h b/drivers/media/video/gspca/stv06xx/stv06xx.h index 1207e7d17f14..9df7137fe67e 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx.h +++ b/drivers/media/video/gspca/stv06xx/stv06xx.h @@ -93,6 +93,17 @@ struct sd { /* Sensor private data */ void *sensor_priv; + + /* The first 4 lines produced by the stv6422 are no good, this keeps + track of how many bytes we still need to skip during a frame */ + int to_skip; + + /* Bridge / Camera type */ + u8 bridge; + #define BRIDGE_STV600 0 + #define BRIDGE_STV602 1 + #define BRIDGE_STV610 2 + #define BRIDGE_ST6422 3 /* With integrated sensor */ }; int stv06xx_write_bridge(struct sd *sd, u16 address, u16 i2c_data); diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c index b16903814203..3039ec208f3a 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c +++ b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c @@ -434,7 +434,7 @@ static int hdcs_probe_1x00(struct sd *sd) hdcs->exp.er = 100; /* - * Frame rate on HDCS-1000 0x46D:0x840 depends on PSMP: + * Frame rate on HDCS-1000 with STV600 depends on PSMP: * 4 = doesn't work at all * 5 = 7.8 fps, * 6 = 6.9 fps, @@ -443,7 +443,7 @@ static int hdcs_probe_1x00(struct sd *sd) * 15 = 4.4 fps, * 31 = 2.8 fps * - * Frame rate on HDCS-1000 0x46D:0x870 depends on PSMP: + * Frame rate on HDCS-1000 with STV602 depends on PSMP: * 15 = doesn't work at all * 18 = doesn't work at all * 19 = 7.3 fps @@ -453,7 +453,7 @@ static int hdcs_probe_1x00(struct sd *sd) * 24 = 6.3 fps * 30 = 5.4 fps */ - hdcs->psmp = IS_870(sd) ? 20 : 5; + hdcs->psmp = (sd->bridge == BRIDGE_STV602) ? 20 : 5; sd->sensor_priv = hdcs; @@ -530,7 +530,7 @@ static int hdcs_init(struct sd *sd) int i, err = 0; /* Set the STV0602AA in STV0600 emulation mode */ - if (IS_870(sd)) + if (sd->bridge == BRIDGE_STV602) stv06xx_write_bridge(sd, STV_STV0600_EMULATION, 1); /* Execute the bridge init */ @@ -558,7 +558,7 @@ static int hdcs_init(struct sd *sd) return err; /* Set PGA sample duration - (was 0x7E for IS_870, but caused slow framerate with HDCS-1020) */ + (was 0x7E for the STV602, but caused slow framerate with HDCS-1020) */ if (IS_1020(sd)) err = stv06xx_write_sensor(sd, HDCS_TCTRL, (HDCS_ADC_START_SIG_DUR << 6) | hdcs->psmp); diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h b/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h index e88c42f7d2f8..934b9cebc1ab 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h +++ b/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h @@ -32,14 +32,13 @@ #include "stv06xx.h" -#define IS_850(sd) ((sd)->gspca_dev.dev->descriptor.idProduct == 0x850) -#define IS_870(sd) ((sd)->gspca_dev.dev->descriptor.idProduct == 0x870) #define IS_1020(sd) ((sd)->sensor == &stv06xx_sensor_hdcs1020) extern const struct stv06xx_sensor stv06xx_sensor_vv6410; extern const struct stv06xx_sensor stv06xx_sensor_hdcs1x00; extern const struct stv06xx_sensor stv06xx_sensor_hdcs1020; extern const struct stv06xx_sensor stv06xx_sensor_pb0100; +extern const struct stv06xx_sensor stv06xx_sensor_st6422; struct stv06xx_sensor { /* Defines the name of a sensor */ diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c b/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c new file mode 100644 index 000000000000..87cb5b9ddfa7 --- /dev/null +++ b/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c @@ -0,0 +1,453 @@ +/* + * Support for the sensor part which is integrated (I think) into the + * st6422 stv06xx alike bridge, as its integrated there are no i2c writes + * but instead direct bridge writes. + * + * Copyright (c) 2009 Hans de Goede + * + * Strongly based on qc-usb-messenger, which is: + * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher + * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland + * Copyright (c) 2002, 2003 Tuukka Toivonen + * + * 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 "stv06xx_st6422.h" + +static struct v4l2_pix_format st6422_mode[] = { + /* Note we actually get 124 lines of data, of which we skip the 4st + 4 as they are garbage */ + { + 162, + 120, + V4L2_PIX_FMT_SGRBG8, + V4L2_FIELD_NONE, + .sizeimage = 162 * 120, + .bytesperline = 162, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1 + }, + /* Note we actually get 248 lines of data, of which we skip the 4st + 4 as they are garbage, and we tell the app it only gets the + first 240 of the 244 lines it actually gets, so that it ignores + the last 4. */ + { + 324, + 240, + V4L2_PIX_FMT_SGRBG8, + V4L2_FIELD_NONE, + .sizeimage = 324 * 244, + .bytesperline = 324, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0 + }, +}; + +static const struct ctrl st6422_ctrl[] = { +#define BRIGHTNESS_IDX 0 + { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 31, + .step = 1, + .default_value = 3 + }, + .set = st6422_set_brightness, + .get = st6422_get_brightness + }, +#define CONTRAST_IDX 1 + { + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = 0, + .maximum = 15, + .step = 1, + .default_value = 11 + }, + .set = st6422_set_contrast, + .get = st6422_get_contrast + }, +#define GAIN_IDX 2 + { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 64 + }, + .set = st6422_set_gain, + .get = st6422_get_gain + }, +#define EXPOSURE_IDX 3 + { + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure", + .minimum = 0, + .maximum = 1023, + .step = 1, + .default_value = 256 + }, + .set = st6422_set_exposure, + .get = st6422_get_exposure + }, +}; + +static int st6422_probe(struct sd *sd) +{ + int i; + s32 *sensor_settings; + + if (sd->bridge != BRIDGE_ST6422) + return -ENODEV; + + info("st6422 sensor detected"); + + sensor_settings = kmalloc(ARRAY_SIZE(st6422_ctrl) * sizeof(s32), + GFP_KERNEL); + if (!sensor_settings) + return -ENOMEM; + + sd->gspca_dev.cam.cam_mode = st6422_mode; + sd->gspca_dev.cam.nmodes = ARRAY_SIZE(st6422_mode); + sd->desc.ctrls = st6422_ctrl; + sd->desc.nctrls = ARRAY_SIZE(st6422_ctrl); + sd->sensor_priv = sensor_settings; + + for (i = 0; i < sd->desc.nctrls; i++) + sensor_settings[i] = st6422_ctrl[i].qctrl.default_value; + + return 0; +} + +static int st6422_init(struct sd *sd) +{ + int err = 0, i; + + const u16 st6422_bridge_init[][2] = { + { STV_ISO_ENABLE, 0x00 }, /* disable capture */ + { 0x1436, 0x00 }, + { 0x1432, 0x03 }, /* 0x00-0x1F brightness */ + { 0x143a, 0xF9 }, /* 0x00-0x0F contrast */ + { 0x0509, 0x38 }, /* R */ + { 0x050a, 0x38 }, /* G */ + { 0x050b, 0x38 }, /* B */ + { 0x050c, 0x2A }, + { 0x050d, 0x01 }, + + + { 0x1431, 0x00 }, /* 0x00-0x07 ??? */ + { 0x1433, 0x34 }, /* 160x120, 0x00-0x01 night filter */ + { 0x1438, 0x18 }, /* 640x480 */ +/* 18 bayes */ +/* 10 compressed? */ + + { 0x1439, 0x00 }, +/* antiflimmer?? 0xa2 ger perfekt bild mot monitor */ + + { 0x143b, 0x05 }, + { 0x143c, 0x00 }, /* 0x00-0x01 - ??? */ + + +/* shutter time 0x0000-0x03FF */ +/* low value give good picures on moving objects (but requires much light) */ +/* high value gives good picures in darkness (but tends to be overexposed) */ + { 0x143e, 0x01 }, + { 0x143d, 0x00 }, + + { 0x1442, 0xe2 }, +/* write: 1x1x xxxx */ +/* read: 1x1x xxxx */ +/* bit 5 == button pressed and hold if 0 */ +/* write 0xe2,0xea */ + +/* 0x144a */ +/* 0x00 init */ +/* bit 7 == button has been pressed, but not handled */ + +/* interrupt */ +/* if(urb->iso_frame_desc[i].status == 0x80) { */ +/* if(urb->iso_frame_desc[i].status == 0x88) { */ + + { 0x1500, 0xd0 }, + { 0x1500, 0xd0 }, + { 0x1500, 0x50 }, /* 0x00 - 0xFF 0x80 == compr ? */ + + { 0x1501, 0xaf }, +/* high val-> ljus area blir morkare. */ +/* low val -> ljus area blir ljusare. */ + { 0x1502, 0xc2 }, +/* high val-> ljus area blir morkare. */ +/* low val -> ljus area blir ljusare. */ + { 0x1503, 0x45 }, +/* high val-> ljus area blir morkare. */ +/* low val -> ljus area blir ljusare. */ + + { 0x1505, 0x02 }, +/* 2 : 324x248 80352 bytes */ +/* 7 : 248x162 40176 bytes */ +/* c+f: 162*124 20088 bytes */ + + { 0x150e, 0x8e }, + { 0x150f, 0x37 }, + { 0x15c0, 0x00 }, + { 0x15c1, 1023 }, /* 160x120, ISOC_PACKET_SIZE */ + { 0x15c3, 0x08 }, /* 0x04/0x14 ... test pictures ??? */ + + + { 0x143f, 0x01 }, /* commit settings */ + + }; + + for (i = 0; i < ARRAY_SIZE(st6422_bridge_init) && !err; i++) { + err = stv06xx_write_bridge(sd, st6422_bridge_init[i][0], + st6422_bridge_init[i][1]); + } + + return err; +} + +static void st6422_disconnect(struct sd *sd) +{ + sd->sensor = NULL; + kfree(sd->sensor_priv); +} + +static int st6422_start(struct sd *sd) +{ + int err, packet_size; + struct cam *cam = &sd->gspca_dev.cam; + s32 *sensor_settings = sd->sensor_priv; + struct usb_host_interface *alt; + struct usb_interface *intf; + + intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface); + alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt); + if (!alt) { + PDEBUG(D_ERR, "Couldn't get altsetting"); + return -EIO; + } + + packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); + err = stv06xx_write_bridge(sd, 0x15c1, packet_size); + if (err < 0) + return err; + + if (cam->cam_mode[sd->gspca_dev.curr_mode].priv) + err = stv06xx_write_bridge(sd, 0x1505, 0x0f); + else + err = stv06xx_write_bridge(sd, 0x1505, 0x02); + if (err < 0) + return err; + + err = st6422_set_brightness(&sd->gspca_dev, + sensor_settings[BRIGHTNESS_IDX]); + if (err < 0) + return err; + + err = st6422_set_contrast(&sd->gspca_dev, + sensor_settings[CONTRAST_IDX]); + if (err < 0) + return err; + + err = st6422_set_exposure(&sd->gspca_dev, + sensor_settings[EXPOSURE_IDX]); + if (err < 0) + return err; + + err = st6422_set_gain(&sd->gspca_dev, + sensor_settings[GAIN_IDX]); + if (err < 0) + return err; + + PDEBUG(D_STREAM, "Starting stream"); + + return 0; +} + +static int st6422_stop(struct sd *sd) +{ + PDEBUG(D_STREAM, "Halting stream"); + + return 0; +} + +static int st6422_get_brightness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[BRIGHTNESS_IDX]; + + PDEBUG(D_V4L2, "Read brightness %d", *val); + + return 0; +} + +static int st6422_set_brightness(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + sensor_settings[BRIGHTNESS_IDX] = val; + + if (!gspca_dev->streaming) + return 0; + + /* val goes from 0 -> 31 */ + PDEBUG(D_V4L2, "Set brightness to %d", val); + err = stv06xx_write_bridge(sd, 0x1432, val); + if (err < 0) + return err; + + /* commit settings */ + err = stv06xx_write_bridge(sd, 0x143f, 0x01); + return (err < 0) ? err : 0; +} + +static int st6422_get_contrast(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[CONTRAST_IDX]; + + PDEBUG(D_V4L2, "Read contrast %d", *val); + + return 0; +} + +static int st6422_set_contrast(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + sensor_settings[CONTRAST_IDX] = val; + + if (!gspca_dev->streaming) + return 0; + + /* Val goes from 0 -> 15 */ + PDEBUG(D_V4L2, "Set contrast to %d\n", val); + err = stv06xx_write_bridge(sd, 0x143a, 0xf0 | val); + if (err < 0) + return err; + + /* commit settings */ + err = stv06xx_write_bridge(sd, 0x143f, 0x01); + return (err < 0) ? err : 0; +} + +static int st6422_get_gain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[GAIN_IDX]; + + PDEBUG(D_V4L2, "Read gain %d", *val); + + return 0; +} + +static int st6422_set_gain(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + sensor_settings[GAIN_IDX] = val; + + if (!gspca_dev->streaming) + return 0; + + PDEBUG(D_V4L2, "Set gain to %d", val); + + /* Set red, green, blue, gain */ + err = stv06xx_write_bridge(sd, 0x0509, val); + if (err < 0) + return err; + + err = stv06xx_write_bridge(sd, 0x050a, val); + if (err < 0) + return err; + + err = stv06xx_write_bridge(sd, 0x050b, val); + if (err < 0) + return err; + + /* 2 mystery writes */ + err = stv06xx_write_bridge(sd, 0x050c, 0x2a); + if (err < 0) + return err; + + err = stv06xx_write_bridge(sd, 0x050d, 0x01); + if (err < 0) + return err; + + /* commit settings */ + err = stv06xx_write_bridge(sd, 0x143f, 0x01); + return (err < 0) ? err : 0; +} + +static int st6422_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[EXPOSURE_IDX]; + + PDEBUG(D_V4L2, "Read exposure %d", *val); + + return 0; +} + +static int st6422_set_exposure(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + sensor_settings[EXPOSURE_IDX] = val; + + if (!gspca_dev->streaming) + return 0; + + PDEBUG(D_V4L2, "Set exposure to %d\n", val); + err = stv06xx_write_bridge(sd, 0x143d, val & 0xff); + if (err < 0) + return err; + + err = stv06xx_write_bridge(sd, 0x143e, val >> 8); + if (err < 0) + return err; + + /* commit settings */ + err = stv06xx_write_bridge(sd, 0x143f, 0x01); + return (err < 0) ? err : 0; +} diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_st6422.h b/drivers/media/video/gspca/stv06xx/stv06xx_st6422.h new file mode 100644 index 000000000000..b2d45fe50522 --- /dev/null +++ b/drivers/media/video/gspca/stv06xx/stv06xx_st6422.h @@ -0,0 +1,59 @@ +/* + * Support for the sensor part which is integrated (I think) into the + * st6422 stv06xx alike bridge, as its integrated there are no i2c writes + * but instead direct bridge writes. + * + * Copyright (c) 2009 Hans de Goede + * + * Strongly based on qc-usb-messenger, which is: + * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher + * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland + * Copyright (c) 2002, 2003 Tuukka Toivonen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef STV06XX_ST6422_H_ +#define STV06XX_ST6422_H_ + +#include "stv06xx_sensor.h" + +static int st6422_probe(struct sd *sd); +static int st6422_start(struct sd *sd); +static int st6422_init(struct sd *sd); +static int st6422_stop(struct sd *sd); +static void st6422_disconnect(struct sd *sd); + +/* V4L2 controls supported by the driver */ +static int st6422_get_brightness(struct gspca_dev *gspca_dev, __s32 *val); +static int st6422_set_brightness(struct gspca_dev *gspca_dev, __s32 val); +static int st6422_get_contrast(struct gspca_dev *gspca_dev, __s32 *val); +static int st6422_set_contrast(struct gspca_dev *gspca_dev, __s32 val); +static int st6422_get_gain(struct gspca_dev *gspca_dev, __s32 *val); +static int st6422_set_gain(struct gspca_dev *gspca_dev, __s32 val); +static int st6422_get_exposure(struct gspca_dev *gspca_dev, __s32 *val); +static int st6422_set_exposure(struct gspca_dev *gspca_dev, __s32 val); + +const struct stv06xx_sensor stv06xx_sensor_st6422 = { + .name = "ST6422", + .init = st6422_init, + .probe = st6422_probe, + .start = st6422_start, + .stop = st6422_stop, + .disconnect = st6422_disconnect, +}; + +#endif diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c index 69c77c932fc0..11a0c002f5dc 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c +++ b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c @@ -80,12 +80,26 @@ static const struct ctrl vv6410_ctrl[] = { .minimum = 0, .maximum = 15, .step = 1, - .default_value = 0 + .default_value = 10 }, .set = vv6410_set_analog_gain, .get = vv6410_get_analog_gain + }, +#define EXPOSURE_IDX 3 + { + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "exposure", + .minimum = 0, + .maximum = 32768, + .step = 1, + .default_value = 20000 + }, + .set = vv6410_set_exposure, + .get = vv6410_get_exposure } -}; + }; static int vv6410_probe(struct sd *sd) { @@ -121,6 +135,7 @@ static int vv6410_probe(struct sd *sd) static int vv6410_init(struct sd *sd) { int err = 0, i; + s32 *sensor_settings = sd->sensor_priv; for (i = 0; i < ARRAY_SIZE(stv_bridge_init); i++) { /* if NULL then len contains single value */ @@ -142,6 +157,16 @@ static int vv6410_init(struct sd *sd) err = stv06xx_write_sensor_bytes(sd, (u8 *) vv6410_sensor_init, ARRAY_SIZE(vv6410_sensor_init)); + if (err < 0) + return err; + + err = vv6410_set_exposure(&sd->gspca_dev, + sensor_settings[EXPOSURE_IDX]); + if (err < 0) + return err; + + err = vv6410_set_analog_gain(&sd->gspca_dev, + sensor_settings[GAIN_IDX]); return (err < 0) ? err : 0; } @@ -318,3 +343,50 @@ static int vv6410_set_analog_gain(struct gspca_dev *gspca_dev, __s32 val) return (err < 0) ? err : 0; } + +static int vv6410_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + + *val = sensor_settings[EXPOSURE_IDX]; + + PDEBUG(D_V4L2, "Read exposure %d", *val); + + return 0; +} + +static int vv6410_set_exposure(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + struct sd *sd = (struct sd *) gspca_dev; + s32 *sensor_settings = sd->sensor_priv; + unsigned int fine, coarse; + + sensor_settings[EXPOSURE_IDX] = val; + + val = (val * val >> 14) + val / 4; + + fine = val % VV6410_CIF_LINELENGTH; + coarse = min(512, val / VV6410_CIF_LINELENGTH); + + PDEBUG(D_V4L2, "Set coarse exposure to %d, fine expsure to %d", + coarse, fine); + + err = stv06xx_write_sensor(sd, VV6410_FINEH, fine >> 8); + if (err < 0) + goto out; + + err = stv06xx_write_sensor(sd, VV6410_FINEL, fine & 0xff); + if (err < 0) + goto out; + + err = stv06xx_write_sensor(sd, VV6410_COARSEH, coarse >> 8); + if (err < 0) + goto out; + + err = stv06xx_write_sensor(sd, VV6410_COARSEL, coarse & 0xff); + +out: + return err; +} diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h index 95ac55891bd4..487d40555343 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h +++ b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h @@ -173,6 +173,8 @@ #define VV6410_SUBSAMPLE 0x01 #define VV6410_CROP_TO_QVGA 0x02 +#define VV6410_CIF_LINELENGTH 415 + static int vv6410_probe(struct sd *sd); static int vv6410_start(struct sd *sd); static int vv6410_init(struct sd *sd); @@ -187,6 +189,8 @@ static int vv6410_get_vflip(struct gspca_dev *gspca_dev, __s32 *val); static int vv6410_set_vflip(struct gspca_dev *gspca_dev, __s32 val); static int vv6410_get_analog_gain(struct gspca_dev *gspca_dev, __s32 *val); static int vv6410_set_analog_gain(struct gspca_dev *gspca_dev, __s32 val); +static int vv6410_get_exposure(struct gspca_dev *gspca_dev, __s32 *val); +static int vv6410_set_exposure(struct gspca_dev *gspca_dev, __s32 val); const struct stv06xx_sensor stv06xx_sensor_vv6410 = { .name = "ST VV6410", @@ -242,12 +246,6 @@ static const u8 vv6410_sensor_init[][2] = { /* Pre-clock generator divide off */ {VV6410_DATAFORMAT, BIT(7) | BIT(0)}, - /* Exposure registers */ - {VV6410_FINEH, VV6410_FINE_EXPOSURE >> 8}, - {VV6410_FINEL, VV6410_FINE_EXPOSURE & 0xff}, - {VV6410_COARSEH, VV6410_COARSE_EXPOSURE >> 8}, - {VV6410_COARSEL, VV6410_COARSE_EXPOSURE & 0xff}, - {VV6410_ANALOGGAIN, 0xf0 | VV6410_DEFAULT_GAIN}, {VV6410_CLKDIV, VV6410_CLK_DIV_2}, /* System registers */ diff --git a/drivers/media/video/gspca/sunplus.c b/drivers/media/video/gspca/sunplus.c index c2b8c10c075a..9623f294bdac 100644 --- a/drivers/media/video/gspca/sunplus.c +++ b/drivers/media/video/gspca/sunplus.c @@ -32,9 +32,6 @@ MODULE_LICENSE("GPL"); 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; @@ -1103,7 +1100,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, { 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 */ @@ -1177,22 +1173,19 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, } /* 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); + i = 0; + do { + if (data[i] == 0xff) { + gspca_frame_add(gspca_dev, INTER_PACKET, frame, + data, i + 1); + len -= i; + data += i; + *data = 0x00; + i = 0; + } + i++; + } while (i < len); + gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len); } static void setbrightness(struct gspca_dev *gspca_dev) diff --git a/drivers/media/video/gspca/t613.c b/drivers/media/video/gspca/t613.c index f63e37e2e4fd..404214b8cd2b 100644 --- a/drivers/media/video/gspca/t613.c +++ b/drivers/media/video/gspca/t613.c @@ -697,7 +697,7 @@ static int sd_init(struct gspca_dev *gspca_dev) return -EINVAL; } - if (sd->sensor != SENSOR_OTHER) { + if (sd->sensor == SENSOR_OM6802) { reg_w_buf(gspca_dev, n1, sizeof n1); i = 5; while (--i >= 0) { diff --git a/drivers/media/video/gspca/vc032x.c b/drivers/media/video/gspca/vc032x.c index e4e933c400bc..26dd155efcc3 100644 --- a/drivers/media/video/gspca/vc032x.c +++ b/drivers/media/video/gspca/vc032x.c @@ -42,7 +42,7 @@ struct sd { char bridge; #define BRIDGE_VC0321 0 #define BRIDGE_VC0323 1 - char sensor; + u8 sensor; #define SENSOR_HV7131R 0 #define SENSOR_MI0360 1 #define SENSOR_MI1310_SOC 2 @@ -159,17 +159,17 @@ static const struct v4l2_pix_format vc0323_mode[] = { .priv = 2}, }; static const struct v4l2_pix_format bi_mode[] = { - {320, 240, V4L2_PIX_FMT_YVYU, V4L2_FIELD_NONE, + {320, 240, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, .bytesperline = 320, .sizeimage = 320 * 240 * 2, .colorspace = V4L2_COLORSPACE_SRGB, .priv = 2}, - {640, 480, V4L2_PIX_FMT_YVYU, V4L2_FIELD_NONE, + {640, 480, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, .bytesperline = 640, .sizeimage = 640 * 480 * 2, .colorspace = V4L2_COLORSPACE_SRGB, .priv = 1}, - {1280, 1024, V4L2_PIX_FMT_YVYU, V4L2_FIELD_NONE, + {1280, 1024, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, .bytesperline = 1280, .sizeimage = 1280 * 1024 * 2, .colorspace = V4L2_COLORSPACE_SRGB, @@ -2453,6 +2453,17 @@ static int sd_config(struct gspca_dev *gspca_dev, struct usb_device *dev = gspca_dev->dev; struct cam *cam; int sensor; + static u8 npkt[] = { /* number of packets per ISOC message */ + 64, /* HV7131R 0 */ + 32, /* MI0360 1 */ + 32, /* MI1310_SOC 2 */ + 64, /* MI1320 3 */ + 128, /* MI1320_SOC 4 */ + 32, /* OV7660 5 */ + 64, /* OV7670 6 */ + 128, /* PO1200 7 */ + 128, /* PO3130NC 8 */ + }; cam = &gspca_dev->cam; sd->bridge = id->driver_info; @@ -2508,6 +2519,8 @@ static int sd_config(struct gspca_dev *gspca_dev, case SENSOR_MI1320_SOC: cam->cam_mode = bi_mode; cam->nmodes = ARRAY_SIZE(bi_mode); + cam->input_flags = V4L2_IN_ST_VFLIP | + V4L2_IN_ST_HFLIP; break; default: cam->cam_mode = vc0323_mode; @@ -2515,6 +2528,7 @@ static int sd_config(struct gspca_dev *gspca_dev, break; } } + cam->npkt = npkt[sd->sensor]; sd->hflip = HFLIP_DEF; sd->vflip = VFLIP_DEF; diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c index 4fe01d8b6c87..08422d315e68 100644 --- a/drivers/media/video/gspca/zc3xx.c +++ b/drivers/media/video/gspca/zc3xx.c @@ -6307,7 +6307,7 @@ static __u16 i2c_read(struct gspca_dev *gspca_dev, retbyte = reg_r_i(gspca_dev, 0x0091); /* read status */ retval = reg_r_i(gspca_dev, 0x0095); /* read Lowbyte */ retval |= reg_r_i(gspca_dev, 0x0096) << 8; /* read Hightbyte */ - PDEBUG(D_USBO, "i2c r [%02x] -> %04x (%02x)", + PDEBUG(D_USBI, "i2c r [%02x] -> %04x (%02x)", reg, retval, retbyte); return retval; } @@ -6868,7 +6868,6 @@ static const struct sensor_by_chipset_revision chipset_revision_sensor[] = { {0x8001, 0x13}, {0x8000, 0x14}, /* CS2102K */ {0x8400, 0x15}, /* TAS5130K */ - {0x4001, 0x16}, /* ADCM2700 */ }; static int vga_3wr_probe(struct gspca_dev *gspca_dev) @@ -6904,12 +6903,15 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev) retword |= reg_r(gspca_dev, 0x000a); PDEBUG(D_PROBE, "probe 3wr vga 1 0x%04x", retword); reg_r(gspca_dev, 0x0010); - /* this is tested only once anyway */ - for (i = 0; i < ARRAY_SIZE(chipset_revision_sensor); i++) { - if (chipset_revision_sensor[i].revision == retword) { - sd->chip_revision = retword; - send_unknown(dev, SENSOR_PB0330); - return chipset_revision_sensor[i].internal_sensor_id; + /* value 0x4001 is meaningless */ + if (retword != 0x4001) { + for (i = 0; i < ARRAY_SIZE(chipset_revision_sensor); i++) { + if (chipset_revision_sensor[i].revision == retword) { + sd->chip_revision = retword; + send_unknown(dev, SENSOR_PB0330); + return chipset_revision_sensor[i] + .internal_sensor_id; + } } } @@ -6980,12 +6982,12 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev) reg_w(dev, 0x01, 0x0001); reg_w(dev, 0x03, 0x0012); reg_w(dev, 0x01, 0x0012); - reg_w(dev, 0x05, 0x0001); + reg_w(dev, 0x05, 0x0012); reg_w(dev, 0xd3, 0x008b); retword = i2c_read(gspca_dev, 0x01); if (retword != 0) { PDEBUG(D_PROBE, "probe 3wr vga type 0a ? ret: %04x", retword); - return retword; + return 0x16; /* adcm2700 (6100/6200) */ } return -1; } diff --git a/drivers/media/video/hdpvr/hdpvr-video.c b/drivers/media/video/hdpvr/hdpvr-video.c index 3e6ffee8dfed..ccd47f57f42c 100644 --- a/drivers/media/video/hdpvr/hdpvr-video.c +++ b/drivers/media/video/hdpvr/hdpvr-video.c @@ -181,7 +181,7 @@ static int hdpvr_submit_buffers(struct hdpvr_device *dev) buff_list); if (buf->status != BUFSTAT_AVAILABLE) { v4l2_err(&dev->v4l2_dev, - "buffer not marked as availbale\n"); + "buffer not marked as available\n"); ret = -EFAULT; goto err; } diff --git a/drivers/media/video/hexium_gemini.c b/drivers/media/video/hexium_gemini.c index 8e1463ee1b64..71c211402eb5 100644 --- a/drivers/media/video/hexium_gemini.c +++ b/drivers/media/video/hexium_gemini.c @@ -224,7 +224,7 @@ static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i) { DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index)); - if (i->index < 0 || i->index >= HEXIUM_INPUTS) + if (i->index >= HEXIUM_INPUTS) return -EINVAL; memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input)); diff --git a/drivers/media/video/hexium_orion.c b/drivers/media/video/hexium_orion.c index 2bc39f628455..39d65ca41c62 100644 --- a/drivers/media/video/hexium_orion.c +++ b/drivers/media/video/hexium_orion.c @@ -325,7 +325,7 @@ static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i) { DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index)); - if (i->index < 0 || i->index >= HEXIUM_INPUTS) + if (i->index >= HEXIUM_INPUTS) return -EINVAL; memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input)); diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c index 092c7da0f37a..86f2fefe1edf 100644 --- a/drivers/media/video/ir-kbd-i2c.c +++ b/drivers/media/video/ir-kbd-i2c.c @@ -74,7 +74,7 @@ static int get_key_haup_common(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw, int start, range, toggle, dev, code, ircode; /* poll IR chip */ - if (size != i2c_master_recv(&ir->c,buf,size)) + if (size != i2c_master_recv(ir->c, buf, size)) return -EIO; /* split rc5 data block ... */ @@ -137,7 +137,7 @@ static int get_key_pixelview(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) unsigned char b; /* poll IR chip */ - if (1 != i2c_master_recv(&ir->c,&b,1)) { + if (1 != i2c_master_recv(ir->c, &b, 1)) { dprintk(1,"read error\n"); return -EIO; } @@ -151,7 +151,7 @@ static int get_key_pv951(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) unsigned char b; /* poll IR chip */ - if (1 != i2c_master_recv(&ir->c,&b,1)) { + if (1 != i2c_master_recv(ir->c, &b, 1)) { dprintk(1,"read error\n"); return -EIO; } @@ -171,7 +171,7 @@ static int get_key_fusionhdtv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) unsigned char buf[4]; /* poll IR chip */ - if (4 != i2c_master_recv(&ir->c,buf,4)) { + if (4 != i2c_master_recv(ir->c, buf, 4)) { dprintk(1,"read error\n"); return -EIO; } @@ -195,7 +195,7 @@ static int get_key_knc1(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) unsigned char b; /* poll IR chip */ - if (1 != i2c_master_recv(&ir->c,&b,1)) { + if (1 != i2c_master_recv(ir->c, &b, 1)) { dprintk(1,"read error\n"); return -EIO; } @@ -222,12 +222,12 @@ static int get_key_avermedia_cardbus(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) { unsigned char subaddr, key, keygroup; - struct i2c_msg msg[] = { { .addr = ir->c.addr, .flags = 0, + struct i2c_msg msg[] = { { .addr = ir->c->addr, .flags = 0, .buf = &subaddr, .len = 1}, - { .addr = ir->c.addr, .flags = I2C_M_RD, + { .addr = ir->c->addr, .flags = I2C_M_RD, .buf = &key, .len = 1} }; subaddr = 0x0d; - if (2 != i2c_transfer(ir->c.adapter, msg, 2)) { + if (2 != i2c_transfer(ir->c->adapter, msg, 2)) { dprintk(1, "read error\n"); return -EIO; } @@ -237,7 +237,7 @@ static int get_key_avermedia_cardbus(struct IR_i2c *ir, subaddr = 0x0b; msg[1].buf = &keygroup; - if (2 != i2c_transfer(ir->c.adapter, msg, 2)) { + if (2 != i2c_transfer(ir->c->adapter, msg, 2)) { dprintk(1, "read error\n"); return -EIO; } @@ -286,7 +286,7 @@ static void ir_work(struct work_struct *work) /* MSI TV@nywhere Plus requires more frequent polling otherwise it will miss some keypresses */ - if (ir->c.adapter->id == I2C_HW_SAA7134 && ir->c.addr == 0x30) + if (ir->c->adapter->id == I2C_HW_SAA7134 && ir->c->addr == 0x30) polling_interval = 50; ir_key_poll(ir); @@ -295,34 +295,15 @@ static void ir_work(struct work_struct *work) /* ----------------------------------------------------------------------- */ -static int ir_attach(struct i2c_adapter *adap, int addr, - unsigned short flags, int kind); -static int ir_detach(struct i2c_client *client); -static int ir_probe(struct i2c_adapter *adap); - -static struct i2c_driver driver = { - .driver = { - .name = "ir-kbd-i2c", - }, - .id = I2C_DRIVERID_INFRARED, - .attach_adapter = ir_probe, - .detach_client = ir_detach, -}; - -static struct i2c_client client_template = -{ - .name = "unset", - .driver = &driver -}; - -static int ir_attach(struct i2c_adapter *adap, int addr, - unsigned short flags, int kind) +static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) { IR_KEYTAB_TYPE *ir_codes = NULL; - char *name; + const char *name = NULL; int ir_type; struct IR_i2c *ir; struct input_dev *input_dev; + struct i2c_adapter *adap = client->adapter; + unsigned short addr = client->addr; int err; ir = kzalloc(sizeof(struct IR_i2c),GFP_KERNEL); @@ -332,13 +313,9 @@ static int ir_attach(struct i2c_adapter *adap, int addr, goto err_out_free; } - ir->c = client_template; + ir->c = client; ir->input = input_dev; - - ir->c.adapter = adap; - ir->c.addr = addr; - - i2c_set_clientdata(&ir->c, ir); + i2c_set_clientdata(client, ir); switch(addr) { case 0x64: @@ -403,44 +380,46 @@ static int ir_attach(struct i2c_adapter *adap, int addr, ir_codes = ir_codes_avermedia_cardbus; break; default: - /* shouldn't happen */ - printk(DEVNAME ": Huh? unknown i2c address (0x%02x)?\n", addr); + dprintk(1, DEVNAME ": Unsupported i2c address 0x%02x\n", addr); + err = -ENODEV; + goto err_out_free; + } + + /* Let the caller override settings */ + if (client->dev.platform_data) { + const struct IR_i2c_init_data *init_data = + client->dev.platform_data; + + ir_codes = init_data->ir_codes; + name = init_data->name; + ir->get_key = init_data->get_key; + } + + /* Make sure we are all setup before going on */ + if (!name || !ir->get_key || !ir_codes) { + dprintk(1, DEVNAME ": Unsupported device at address 0x%02x\n", + addr); err = -ENODEV; goto err_out_free; } /* Sets name */ - snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (%s)", name); + snprintf(ir->name, sizeof(ir->name), "i2c IR (%s)", name); ir->ir_codes = ir_codes; - /* register i2c device - * At device register, IR codes may be changed to be - * board dependent. - */ - err = i2c_attach_client(&ir->c); - if (err) - goto err_out_free; - - /* If IR not supported or disabled, unregisters driver */ - if (ir->get_key == NULL) { - err = -ENODEV; - goto err_out_detach; - } - - /* Phys addr can only be set after attaching (for ir->c.dev) */ snprintf(ir->phys, sizeof(ir->phys), "%s/%s/ir0", - dev_name(&ir->c.adapter->dev), - dev_name(&ir->c.dev)); + dev_name(&adap->dev), + dev_name(&client->dev)); /* init + register input device */ ir_input_init(input_dev, &ir->ir, ir_type, ir->ir_codes); input_dev->id.bustype = BUS_I2C; - input_dev->name = ir->c.name; + input_dev->name = ir->name; input_dev->phys = ir->phys; err = input_register_device(ir->input); if (err) - goto err_out_detach; + goto err_out_free; printk(DEVNAME ": %s detected at %s [%s]\n", ir->input->name, ir->input->phys, adap->name); @@ -451,135 +430,42 @@ static int ir_attach(struct i2c_adapter *adap, int addr, return 0; - err_out_detach: - i2c_detach_client(&ir->c); err_out_free: input_free_device(input_dev); kfree(ir); return err; } -static int ir_detach(struct i2c_client *client) +static int ir_remove(struct i2c_client *client) { struct IR_i2c *ir = i2c_get_clientdata(client); /* kill outstanding polls */ cancel_delayed_work_sync(&ir->work); - /* unregister devices */ + /* unregister device */ input_unregister_device(ir->input); - i2c_detach_client(&ir->c); /* free memory */ kfree(ir); return 0; } -static int ir_probe(struct i2c_adapter *adap) -{ +static const struct i2c_device_id ir_kbd_id[] = { + /* Generic entry for any IR receiver */ + { "ir_video", 0 }, + /* IR device specific entries could be added here */ + { } +}; - /* The external IR receiver is at i2c address 0x34 (0x35 for - reads). Future Hauppauge cards will have an internal - receiver at 0x30 (0x31 for reads). In theory, both can be - fitted, and Hauppauge suggest an external overrides an - internal. - - That's why we probe 0x1a (~0x34) first. CB - */ - - static const int probe_bttv[] = { 0x1a, 0x18, 0x4b, 0x64, 0x30, -1}; - static const int probe_saa7134[] = { 0x7a, 0x47, 0x71, 0x2d, -1 }; - static const int probe_em28XX[] = { 0x30, 0x47, -1 }; - static const int probe_cx88[] = { 0x18, 0x6b, 0x71, -1 }; - static const int probe_cx23885[] = { 0x6b, -1 }; - const int *probe; - struct i2c_msg msg = { - .flags = I2C_M_RD, - .len = 0, - .buf = NULL, - }; - int i, rc; - - switch (adap->id) { - case I2C_HW_B_BT848: - probe = probe_bttv; - break; - case I2C_HW_B_CX2341X: - probe = probe_bttv; - break; - case I2C_HW_SAA7134: - probe = probe_saa7134; - break; - case I2C_HW_B_EM28XX: - probe = probe_em28XX; - break; - case I2C_HW_B_CX2388x: - probe = probe_cx88; - break; - case I2C_HW_B_CX23885: - probe = probe_cx23885; - break; - default: - return 0; - } - - for (i = 0; -1 != probe[i]; i++) { - msg.addr = probe[i]; - rc = i2c_transfer(adap, &msg, 1); - dprintk(1,"probe 0x%02x @ %s: %s\n", - probe[i], adap->name, - (1 == rc) ? "yes" : "no"); - if (1 == rc) { - ir_attach(adap, probe[i], 0, 0); - return 0; - } - } - - /* Special case for MSI TV@nywhere Plus remote */ - if (adap->id == I2C_HW_SAA7134) { - u8 temp; - - /* MSI TV@nywhere Plus controller doesn't seem to - respond to probes unless we read something from - an existing device. Weird... */ - - msg.addr = 0x50; - rc = i2c_transfer(adap, &msg, 1); - dprintk(1, "probe 0x%02x @ %s: %s\n", - msg.addr, adap->name, - (1 == rc) ? "yes" : "no"); - - /* Now do the probe. The controller does not respond - to 0-byte reads, so we use a 1-byte read instead. */ - msg.addr = 0x30; - msg.len = 1; - msg.buf = &temp; - rc = i2c_transfer(adap, &msg, 1); - dprintk(1, "probe 0x%02x @ %s: %s\n", - msg.addr, adap->name, - (1 == rc) ? "yes" : "no"); - if (1 == rc) - ir_attach(adap, msg.addr, 0, 0); - } - - /* Special case for AVerMedia Cardbus remote */ - if (adap->id == I2C_HW_SAA7134) { - unsigned char subaddr, data; - struct i2c_msg msg[] = { { .addr = 0x40, .flags = 0, - .buf = &subaddr, .len = 1}, - { .addr = 0x40, .flags = I2C_M_RD, - .buf = &data, .len = 1} }; - subaddr = 0x0d; - rc = i2c_transfer(adap, msg, 2); - dprintk(1, "probe 0x%02x/0x%02x @ %s: %s\n", - msg[0].addr, subaddr, adap->name, - (2 == rc) ? "yes" : "no"); - if (2 == rc) - ir_attach(adap, msg[0].addr, 0, 0); - } - - return 0; -} +static struct i2c_driver driver = { + .driver = { + .name = "ir-kbd-i2c", + }, + .probe = ir_probe, + .remove = ir_remove, + .id_table = ir_kbd_id, +}; /* ----------------------------------------------------------------------- */ diff --git a/drivers/media/video/ivtv/ivtv-controls.c b/drivers/media/video/ivtv/ivtv-controls.c index 84995bcf4a75..a3b77ed3f089 100644 --- a/drivers/media/video/ivtv/ivtv-controls.c +++ b/drivers/media/video/ivtv/ivtv-controls.c @@ -60,6 +60,8 @@ int ivtv_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qctrl) switch (qctrl->id) { /* Standard V4L2 controls */ + case V4L2_CID_USER_CLASS: + return v4l2_ctrl_query_fill(qctrl, 0, 0, 0, 0); case V4L2_CID_BRIGHTNESS: case V4L2_CID_HUE: case V4L2_CID_SATURATION: diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index db2ac9a99acd..558f8a837ff4 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -455,7 +455,7 @@ static void ivtv_process_eeprom(struct ivtv *itv) break; } if (tv.tuner_type == TUNER_ABSENT) - IVTV_ERR("tveeprom cannot autodetect tuner!"); + IVTV_ERR("tveeprom cannot autodetect tuner!\n"); if (itv->options.tuner == -1) itv->options.tuner = tv.tuner_type; @@ -946,17 +946,14 @@ static int __devinit ivtv_probe(struct pci_dev *pdev, if (itv == NULL) return -ENOMEM; itv->pdev = pdev; - itv->instance = atomic_inc_return(&ivtv_instance) - 1; + itv->instance = v4l2_device_set_name(&itv->v4l2_dev, "ivtv", + &ivtv_instance); retval = v4l2_device_register(&pdev->dev, &itv->v4l2_dev); if (retval) { kfree(itv); return retval; } - /* "ivtv + PCI ID" is a bit of a mouthful, so use - "ivtv + instance" instead. */ - snprintf(itv->v4l2_dev.name, sizeof(itv->v4l2_dev.name), - "ivtv%d", itv->instance); IVTV_INFO("Initializing card %d\n", itv->instance); ivtv_process_options(itv); diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c index 9e3d32b8004c..e52aa322b134 100644 --- a/drivers/media/video/ivtv/ivtv-i2c.c +++ b/drivers/media/video/ivtv/ivtv-i2c.c @@ -579,9 +579,11 @@ static struct i2c_client ivtv_i2c_client_template = { .name = "ivtv internal", }; -/* init + register i2c algo-bit adapter */ +/* init + register i2c adapter + instantiate IR receiver */ int init_ivtv_i2c(struct ivtv *itv) { + int retval; + IVTV_DEBUG_I2C("i2c init\n"); /* Sanity checks for the I2C hardware arrays. They must be the @@ -619,9 +621,37 @@ int init_ivtv_i2c(struct ivtv *itv) ivtv_setsda(itv, 1); if (itv->options.newi2c > 0) - return i2c_add_adapter(&itv->i2c_adap); + retval = i2c_add_adapter(&itv->i2c_adap); else - return i2c_bit_add_bus(&itv->i2c_adap); + retval = i2c_bit_add_bus(&itv->i2c_adap); + + /* Instantiate the IR receiver device, if present */ + if (retval == 0) { + struct i2c_board_info info; + /* The external IR receiver is at i2c address 0x34 (0x35 for + reads). Future Hauppauge cards will have an internal + receiver at 0x30 (0x31 for reads). In theory, both can be + fitted, and Hauppauge suggest an external overrides an + internal. + + That's why we probe 0x1a (~0x34) first. CB + */ + const unsigned short addr_list[] = { + 0x1a, /* Hauppauge IR external */ + 0x18, /* Hauppauge IR internal */ + 0x71, /* Hauppauge IR (PVR150) */ + 0x64, /* Pixelview IR */ + 0x30, /* KNC ONE IR */ + 0x6b, /* Adaptec IR */ + I2C_CLIENT_END + }; + + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "ir_video", I2C_NAME_SIZE); + i2c_new_probed_device(&itv->i2c_adap, &info, addr_list); + } + + return retval; } void exit_ivtv_i2c(struct ivtv *itv) diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index c342a9fe983e..99f3c39a118b 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -709,7 +709,7 @@ static int ivtv_itvc(struct ivtv *itv, unsigned int cmd, void *arg) 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) + else if (regs->reg < IVTV_ENCODER_SIZE) reg_start = itv->enc_mem; else return -EINVAL; diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c index 684f62fa7897..4d794b42d6cd 100644 --- a/drivers/media/video/mt9m001.c +++ b/drivers/media/video/mt9m001.c @@ -75,53 +75,50 @@ struct mt9m001 { unsigned char autoexposure; }; -static int reg_read(struct soc_camera_device *icd, const u8 reg) +static int reg_read(struct i2c_client *client, const u8 reg) { - struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd); - struct i2c_client *client = mt9m001->client; s32 data = i2c_smbus_read_word_data(client, reg); return data < 0 ? data : swab16(data); } -static int reg_write(struct soc_camera_device *icd, const u8 reg, +static int reg_write(struct i2c_client *client, const u8 reg, const u16 data) { - struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd); - return i2c_smbus_write_word_data(mt9m001->client, reg, swab16(data)); + return i2c_smbus_write_word_data(client, reg, swab16(data)); } -static int reg_set(struct soc_camera_device *icd, const u8 reg, +static int reg_set(struct i2c_client *client, const u8 reg, const u16 data) { int ret; - ret = reg_read(icd, reg); + ret = reg_read(client, reg); if (ret < 0) return ret; - return reg_write(icd, reg, ret | data); + return reg_write(client, reg, ret | data); } -static int reg_clear(struct soc_camera_device *icd, const u8 reg, +static int reg_clear(struct i2c_client *client, const u8 reg, const u16 data) { int ret; - ret = reg_read(icd, reg); + ret = reg_read(client, reg); if (ret < 0) return ret; - return reg_write(icd, reg, ret & ~data); + return reg_write(client, reg, ret & ~data); } static int mt9m001_init(struct soc_camera_device *icd) { - struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd); - struct soc_camera_link *icl = mt9m001->client->dev.platform_data; + struct i2c_client *client = to_i2c_client(icd->control); + struct soc_camera_link *icl = client->dev.platform_data; int ret; dev_dbg(icd->vdev->parent, "%s\n", __func__); if (icl->power) { - ret = icl->power(&mt9m001->client->dev, 1); + ret = icl->power(&client->dev, 1); if (ret < 0) { dev_err(icd->vdev->parent, "Platform failed to power-on the camera.\n"); @@ -131,49 +128,53 @@ static int mt9m001_init(struct soc_camera_device *icd) /* The camera could have been already on, we reset it additionally */ if (icl->reset) - ret = icl->reset(&mt9m001->client->dev); + ret = icl->reset(&client->dev); else ret = -ENODEV; if (ret < 0) { /* Either no platform reset, or platform reset failed */ - ret = reg_write(icd, MT9M001_RESET, 1); + ret = reg_write(client, MT9M001_RESET, 1); if (!ret) - ret = reg_write(icd, MT9M001_RESET, 0); + ret = reg_write(client, MT9M001_RESET, 0); } /* Disable chip, synchronous option update */ if (!ret) - ret = reg_write(icd, MT9M001_OUTPUT_CONTROL, 0); + ret = reg_write(client, MT9M001_OUTPUT_CONTROL, 0); return ret; } static int mt9m001_release(struct soc_camera_device *icd) { - struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd); - struct soc_camera_link *icl = mt9m001->client->dev.platform_data; + struct i2c_client *client = to_i2c_client(icd->control); + struct soc_camera_link *icl = client->dev.platform_data; /* Disable the chip */ - reg_write(icd, MT9M001_OUTPUT_CONTROL, 0); + reg_write(client, MT9M001_OUTPUT_CONTROL, 0); if (icl->power) - icl->power(&mt9m001->client->dev, 0); + icl->power(&client->dev, 0); return 0; } static int mt9m001_start_capture(struct soc_camera_device *icd) { + struct i2c_client *client = to_i2c_client(icd->control); + /* Switch to master "normal" mode */ - if (reg_write(icd, MT9M001_OUTPUT_CONTROL, 2) < 0) + if (reg_write(client, MT9M001_OUTPUT_CONTROL, 2) < 0) return -EIO; return 0; } static int mt9m001_stop_capture(struct soc_camera_device *icd) { + struct i2c_client *client = to_i2c_client(icd->control); + /* Stop sensor readout */ - if (reg_write(icd, MT9M001_OUTPUT_CONTROL, 0) < 0) + if (reg_write(client, MT9M001_OUTPUT_CONTROL, 0) < 0) return -EIO; return 0; } @@ -222,28 +223,29 @@ static unsigned long mt9m001_query_bus_param(struct soc_camera_device *icd) static int mt9m001_set_crop(struct soc_camera_device *icd, struct v4l2_rect *rect) { + struct i2c_client *client = to_i2c_client(icd->control); struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd); int ret; const u16 hblank = 9, vblank = 25; /* Blanking and start values - default... */ - ret = reg_write(icd, MT9M001_HORIZONTAL_BLANKING, hblank); + ret = reg_write(client, MT9M001_HORIZONTAL_BLANKING, hblank); if (!ret) - ret = reg_write(icd, MT9M001_VERTICAL_BLANKING, vblank); + ret = reg_write(client, MT9M001_VERTICAL_BLANKING, vblank); /* The caller provides a supported format, as verified per * call to icd->try_fmt() */ if (!ret) - ret = reg_write(icd, MT9M001_COLUMN_START, rect->left); + ret = reg_write(client, MT9M001_COLUMN_START, rect->left); if (!ret) - ret = reg_write(icd, MT9M001_ROW_START, rect->top); + ret = reg_write(client, MT9M001_ROW_START, rect->top); if (!ret) - ret = reg_write(icd, MT9M001_WINDOW_WIDTH, rect->width - 1); + ret = reg_write(client, MT9M001_WINDOW_WIDTH, rect->width - 1); if (!ret) - ret = reg_write(icd, MT9M001_WINDOW_HEIGHT, + ret = reg_write(client, MT9M001_WINDOW_HEIGHT, rect->height + icd->y_skip_top - 1); if (!ret && mt9m001->autoexposure) { - ret = reg_write(icd, MT9M001_SHUTTER_WIDTH, + ret = reg_write(client, MT9M001_SHUTTER_WIDTH, rect->height + icd->y_skip_top + vblank); if (!ret) { const struct v4l2_queryctrl *qctrl = @@ -278,15 +280,9 @@ static int mt9m001_try_fmt(struct soc_camera_device *icd, { struct v4l2_pix_format *pix = &f->fmt.pix; - if (pix->height < 32 + icd->y_skip_top) - pix->height = 32 + icd->y_skip_top; - if (pix->height > 1024 + icd->y_skip_top) - pix->height = 1024 + icd->y_skip_top; - if (pix->width < 48) - pix->width = 48; - if (pix->width > 1280) - pix->width = 1280; - pix->width &= ~0x01; /* has to be even, unsure why was ~3 */ + v4l_bound_align_image(&pix->width, 48, 1280, 1, + &pix->height, 32 + icd->y_skip_top, + 1024 + icd->y_skip_top, 0, 0); return 0; } @@ -312,16 +308,16 @@ static int mt9m001_get_chip_id(struct soc_camera_device *icd, static int mt9m001_get_register(struct soc_camera_device *icd, struct v4l2_dbg_register *reg) { - struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd); + struct i2c_client *client = to_i2c_client(icd->control); if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) return -EINVAL; - if (reg->match.addr != mt9m001->client->addr) + if (reg->match.addr != client->addr) return -ENODEV; reg->size = 2; - reg->val = reg_read(icd, reg->reg); + reg->val = reg_read(client, reg->reg); if (reg->val > 0xffff) return -EIO; @@ -332,15 +328,15 @@ static int mt9m001_get_register(struct soc_camera_device *icd, static int mt9m001_set_register(struct soc_camera_device *icd, struct v4l2_dbg_register *reg) { - struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd); + struct i2c_client *client = to_i2c_client(icd->control); if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) return -EINVAL; - if (reg->match.addr != mt9m001->client->addr) + if (reg->match.addr != client->addr) return -ENODEV; - if (reg_write(icd, reg->reg, reg->val) < 0) + if (reg_write(client, reg->reg, reg->val) < 0) return -EIO; return 0; @@ -416,12 +412,13 @@ static struct soc_camera_ops mt9m001_ops = { static int mt9m001_get_control(struct soc_camera_device *icd, struct v4l2_control *ctrl) { + struct i2c_client *client = to_i2c_client(icd->control); struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd); int data; switch (ctrl->id) { case V4L2_CID_VFLIP: - data = reg_read(icd, MT9M001_READ_OPTIONS2); + data = reg_read(client, MT9M001_READ_OPTIONS2); if (data < 0) return -EIO; ctrl->value = !!(data & 0x8000); @@ -435,6 +432,7 @@ static int mt9m001_get_control(struct soc_camera_device *icd, struct v4l2_contro static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_control *ctrl) { + struct i2c_client *client = to_i2c_client(icd->control); struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd); const struct v4l2_queryctrl *qctrl; int data; @@ -447,9 +445,9 @@ static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_contro switch (ctrl->id) { case V4L2_CID_VFLIP: if (ctrl->value) - data = reg_set(icd, MT9M001_READ_OPTIONS2, 0x8000); + data = reg_set(client, MT9M001_READ_OPTIONS2, 0x8000); else - data = reg_clear(icd, MT9M001_READ_OPTIONS2, 0x8000); + data = reg_clear(client, MT9M001_READ_OPTIONS2, 0x8000); if (data < 0) return -EIO; break; @@ -463,7 +461,7 @@ static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_contro data = ((ctrl->value - qctrl->minimum) * 8 + range / 2) / range; dev_dbg(&icd->dev, "Setting gain %d\n", data); - data = reg_write(icd, MT9M001_GLOBAL_GAIN, data); + data = reg_write(client, MT9M001_GLOBAL_GAIN, data); if (data < 0) return -EIO; } else { @@ -481,8 +479,8 @@ static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_contro data = ((gain - 64) * 7 + 28) / 56 + 96; dev_dbg(&icd->dev, "Setting gain from %d to %d\n", - reg_read(icd, MT9M001_GLOBAL_GAIN), data); - data = reg_write(icd, MT9M001_GLOBAL_GAIN, data); + reg_read(client, MT9M001_GLOBAL_GAIN), data); + data = reg_write(client, MT9M001_GLOBAL_GAIN, data); if (data < 0) return -EIO; } @@ -500,8 +498,8 @@ static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_contro range / 2) / range + 1; dev_dbg(&icd->dev, "Setting shutter width from %d to %lu\n", - reg_read(icd, MT9M001_SHUTTER_WIDTH), shutter); - if (reg_write(icd, MT9M001_SHUTTER_WIDTH, shutter) < 0) + reg_read(client, MT9M001_SHUTTER_WIDTH), shutter); + if (reg_write(client, MT9M001_SHUTTER_WIDTH, shutter) < 0) return -EIO; icd->exposure = ctrl->value; mt9m001->autoexposure = 0; @@ -510,7 +508,7 @@ static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_contro case V4L2_CID_EXPOSURE_AUTO: if (ctrl->value) { const u16 vblank = 25; - if (reg_write(icd, MT9M001_SHUTTER_WIDTH, icd->height + + if (reg_write(client, MT9M001_SHUTTER_WIDTH, icd->height + icd->y_skip_top + vblank) < 0) return -EIO; qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE); @@ -529,8 +527,9 @@ static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_contro * this wasn't our capture interface, so, we wait for the right one */ static int mt9m001_video_probe(struct soc_camera_device *icd) { + struct i2c_client *client = to_i2c_client(icd->control); struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd); - struct soc_camera_link *icl = mt9m001->client->dev.platform_data; + struct soc_camera_link *icl = client->dev.platform_data; s32 data; int ret; unsigned long flags; @@ -542,11 +541,11 @@ static int mt9m001_video_probe(struct soc_camera_device *icd) return -ENODEV; /* Enable the chip */ - data = reg_write(icd, MT9M001_CHIP_ENABLE, 1); + data = reg_write(client, MT9M001_CHIP_ENABLE, 1); dev_dbg(&icd->dev, "write: %d\n", data); /* Read out the chip version register */ - data = reg_read(icd, MT9M001_CHIP_VERSION); + data = reg_read(client, MT9M001_CHIP_VERSION); /* must be 0x8411 or 0x8421 for colour sensor and 8431 for bw */ switch (data) { @@ -604,10 +603,13 @@ ei2c: static void mt9m001_video_remove(struct soc_camera_device *icd) { struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd); + struct soc_camera_link *icl = mt9m001->client->dev.platform_data; dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9m001->client->addr, icd->dev.parent, icd->vdev); soc_camera_video_stop(icd); + if (icl->free_bus) + icl->free_bus(icl); } static int mt9m001_probe(struct i2c_client *client, diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c index cdd1ddb51388..fc5e2de03766 100644 --- a/drivers/media/video/mt9m111.c +++ b/drivers/media/video/mt9m111.c @@ -113,10 +113,10 @@ * mt9m111: Camera control register addresses (0x200..0x2ff not implemented) */ -#define reg_read(reg) mt9m111_reg_read(icd, MT9M111_##reg) -#define reg_write(reg, val) mt9m111_reg_write(icd, MT9M111_##reg, (val)) -#define reg_set(reg, val) mt9m111_reg_set(icd, MT9M111_##reg, (val)) -#define reg_clear(reg, val) mt9m111_reg_clear(icd, MT9M111_##reg, (val)) +#define reg_read(reg) mt9m111_reg_read(client, MT9M111_##reg) +#define reg_write(reg, val) mt9m111_reg_write(client, MT9M111_##reg, (val)) +#define reg_set(reg, val) mt9m111_reg_set(client, MT9M111_##reg, (val)) +#define reg_clear(reg, val) mt9m111_reg_clear(client, MT9M111_##reg, (val)) #define MT9M111_MIN_DARK_ROWS 8 #define MT9M111_MIN_DARK_COLS 24 @@ -184,58 +184,55 @@ static int reg_page_map_set(struct i2c_client *client, const u16 reg) return ret; } -static int mt9m111_reg_read(struct soc_camera_device *icd, const u16 reg) +static int mt9m111_reg_read(struct i2c_client *client, const u16 reg) { - struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); - struct i2c_client *client = mt9m111->client; int ret; ret = reg_page_map_set(client, reg); if (!ret) ret = swab16(i2c_smbus_read_word_data(client, (reg & 0xff))); - dev_dbg(&icd->dev, "read reg.%03x -> %04x\n", reg, ret); + dev_dbg(&client->dev, "read reg.%03x -> %04x\n", reg, ret); return ret; } -static int mt9m111_reg_write(struct soc_camera_device *icd, const u16 reg, +static int mt9m111_reg_write(struct i2c_client *client, const u16 reg, const u16 data) { - struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); - struct i2c_client *client = mt9m111->client; int ret; ret = reg_page_map_set(client, reg); if (!ret) - ret = i2c_smbus_write_word_data(mt9m111->client, (reg & 0xff), + ret = i2c_smbus_write_word_data(client, (reg & 0xff), swab16(data)); - dev_dbg(&icd->dev, "write reg.%03x = %04x -> %d\n", reg, data, ret); + dev_dbg(&client->dev, "write reg.%03x = %04x -> %d\n", reg, data, ret); return ret; } -static int mt9m111_reg_set(struct soc_camera_device *icd, const u16 reg, +static int mt9m111_reg_set(struct i2c_client *client, const u16 reg, const u16 data) { int ret; - ret = mt9m111_reg_read(icd, reg); + ret = mt9m111_reg_read(client, reg); if (ret >= 0) - ret = mt9m111_reg_write(icd, reg, ret | data); + ret = mt9m111_reg_write(client, reg, ret | data); return ret; } -static int mt9m111_reg_clear(struct soc_camera_device *icd, const u16 reg, +static int mt9m111_reg_clear(struct i2c_client *client, const u16 reg, const u16 data) { int ret; - ret = mt9m111_reg_read(icd, reg); - return mt9m111_reg_write(icd, reg, ret & ~data); + ret = mt9m111_reg_read(client, reg); + return mt9m111_reg_write(client, reg, ret & ~data); } static int mt9m111_set_context(struct soc_camera_device *icd, enum mt9m111_context ctxt) { + struct i2c_client *client = to_i2c_client(icd->control); int valB = MT9M111_CTXT_CTRL_RESTART | MT9M111_CTXT_CTRL_DEFECTCOR_B | MT9M111_CTXT_CTRL_RESIZE_B | MT9M111_CTXT_CTRL_CTRL2_B | MT9M111_CTXT_CTRL_GAMMA_B | MT9M111_CTXT_CTRL_READ_MODE_B @@ -252,6 +249,7 @@ static int mt9m111_set_context(struct soc_camera_device *icd, static int mt9m111_setup_rect(struct soc_camera_device *icd, struct v4l2_rect *rect) { + struct i2c_client *client = to_i2c_client(icd->control); struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); int ret, is_raw_format; int width = rect->width; @@ -296,6 +294,7 @@ static int mt9m111_setup_rect(struct soc_camera_device *icd, static int mt9m111_setup_pixfmt(struct soc_camera_device *icd, u16 outfmt) { + struct i2c_client *client = to_i2c_client(icd->control); int ret; ret = reg_write(OUTPUT_FORMAT_CTRL2_A, outfmt); @@ -357,12 +356,13 @@ static int mt9m111_setfmt_yuv(struct soc_camera_device *icd) static int mt9m111_enable(struct soc_camera_device *icd) { + struct i2c_client *client = to_i2c_client(icd->control); struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); - struct soc_camera_link *icl = mt9m111->client->dev.platform_data; + struct soc_camera_link *icl = client->dev.platform_data; int ret; if (icl->power) { - ret = icl->power(&mt9m111->client->dev, 1); + ret = icl->power(&client->dev, 1); if (ret < 0) { dev_err(icd->vdev->parent, "Platform failed to power-on the camera.\n"); @@ -378,8 +378,9 @@ static int mt9m111_enable(struct soc_camera_device *icd) static int mt9m111_disable(struct soc_camera_device *icd) { + struct i2c_client *client = to_i2c_client(icd->control); struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); - struct soc_camera_link *icl = mt9m111->client->dev.platform_data; + struct soc_camera_link *icl = client->dev.platform_data; int ret; ret = reg_clear(RESET, MT9M111_RESET_CHIP_ENABLE); @@ -387,15 +388,15 @@ static int mt9m111_disable(struct soc_camera_device *icd) mt9m111->powered = 0; if (icl->power) - icl->power(&mt9m111->client->dev, 0); + icl->power(&client->dev, 0); return ret; } static int mt9m111_reset(struct soc_camera_device *icd) { - struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); - struct soc_camera_link *icl = mt9m111->client->dev.platform_data; + struct i2c_client *client = to_i2c_client(icd->control); + struct soc_camera_link *icl = client->dev.platform_data; int ret; ret = reg_set(RESET, MT9M111_RESET_RESET_MODE); @@ -406,7 +407,7 @@ static int mt9m111_reset(struct soc_camera_device *icd) | MT9M111_RESET_RESET_SOC); if (icl->reset) - icl->reset(&mt9m111->client->dev); + icl->reset(&client->dev); return ret; } @@ -562,15 +563,14 @@ static int mt9m111_get_register(struct soc_camera_device *icd, struct v4l2_dbg_register *reg) { int val; - - struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); + struct i2c_client *client = to_i2c_client(icd->control); if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff) return -EINVAL; - if (reg->match.addr != mt9m111->client->addr) + if (reg->match.addr != client->addr) return -ENODEV; - val = mt9m111_reg_read(icd, reg->reg); + val = mt9m111_reg_read(client, reg->reg); reg->size = 2; reg->val = (u64)val; @@ -583,15 +583,15 @@ static int mt9m111_get_register(struct soc_camera_device *icd, static int mt9m111_set_register(struct soc_camera_device *icd, struct v4l2_dbg_register *reg) { - struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); + struct i2c_client *client = to_i2c_client(icd->control); if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff) return -EINVAL; - if (reg->match.addr != mt9m111->client->addr) + if (reg->match.addr != client->addr) return -ENODEV; - if (mt9m111_reg_write(icd, reg->reg, reg->val) < 0) + if (mt9m111_reg_write(client, reg->reg, reg->val) < 0) return -EIO; return 0; @@ -672,6 +672,7 @@ static struct soc_camera_ops mt9m111_ops = { static int mt9m111_set_flip(struct soc_camera_device *icd, int flip, int mask) { + struct i2c_client *client = to_i2c_client(icd->control); struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); int ret; @@ -692,6 +693,7 @@ static int mt9m111_set_flip(struct soc_camera_device *icd, int flip, int mask) static int mt9m111_get_global_gain(struct soc_camera_device *icd) { + struct i2c_client *client = to_i2c_client(icd->control); int data; data = reg_read(GLOBAL_GAIN); @@ -703,6 +705,7 @@ static int mt9m111_get_global_gain(struct soc_camera_device *icd) static int mt9m111_set_global_gain(struct soc_camera_device *icd, int gain) { + struct i2c_client *client = to_i2c_client(icd->control); u16 val; if (gain > 63 * 2 * 2) @@ -721,6 +724,7 @@ static int mt9m111_set_global_gain(struct soc_camera_device *icd, int gain) static int mt9m111_set_autoexposure(struct soc_camera_device *icd, int on) { + struct i2c_client *client = to_i2c_client(icd->control); struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); int ret; @@ -737,6 +741,7 @@ static int mt9m111_set_autoexposure(struct soc_camera_device *icd, int on) static int mt9m111_set_autowhitebalance(struct soc_camera_device *icd, int on) { + struct i2c_client *client = to_i2c_client(icd->control); struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); int ret; @@ -754,6 +759,7 @@ static int mt9m111_set_autowhitebalance(struct soc_camera_device *icd, int on) static int mt9m111_get_control(struct soc_camera_device *icd, struct v4l2_control *ctrl) { + struct i2c_client *client = to_i2c_client(icd->control); struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); int data; @@ -898,6 +904,7 @@ static int mt9m111_release(struct soc_camera_device *icd) */ static int mt9m111_video_probe(struct soc_camera_device *icd) { + struct i2c_client *client = to_i2c_client(icd->control); struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); s32 data; int ret; diff --git a/drivers/media/video/mt9t031.c b/drivers/media/video/mt9t031.c index 2b0927bfd217..4207fb342670 100644 --- a/drivers/media/video/mt9t031.c +++ b/drivers/media/video/mt9t031.c @@ -76,64 +76,61 @@ struct mt9t031 { u16 yskip; }; -static int reg_read(struct soc_camera_device *icd, const u8 reg) +static int reg_read(struct i2c_client *client, const u8 reg) { - struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd); - struct i2c_client *client = mt9t031->client; s32 data = i2c_smbus_read_word_data(client, reg); return data < 0 ? data : swab16(data); } -static int reg_write(struct soc_camera_device *icd, const u8 reg, +static int reg_write(struct i2c_client *client, const u8 reg, const u16 data) { - struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd); - return i2c_smbus_write_word_data(mt9t031->client, reg, swab16(data)); + return i2c_smbus_write_word_data(client, reg, swab16(data)); } -static int reg_set(struct soc_camera_device *icd, const u8 reg, +static int reg_set(struct i2c_client *client, const u8 reg, const u16 data) { int ret; - ret = reg_read(icd, reg); + ret = reg_read(client, reg); if (ret < 0) return ret; - return reg_write(icd, reg, ret | data); + return reg_write(client, reg, ret | data); } -static int reg_clear(struct soc_camera_device *icd, const u8 reg, +static int reg_clear(struct i2c_client *client, const u8 reg, const u16 data) { int ret; - ret = reg_read(icd, reg); + ret = reg_read(client, reg); if (ret < 0) return ret; - return reg_write(icd, reg, ret & ~data); + return reg_write(client, reg, ret & ~data); } -static int set_shutter(struct soc_camera_device *icd, const u32 data) +static int set_shutter(struct i2c_client *client, const u32 data) { int ret; - ret = reg_write(icd, MT9T031_SHUTTER_WIDTH_UPPER, data >> 16); + ret = reg_write(client, MT9T031_SHUTTER_WIDTH_UPPER, data >> 16); if (ret >= 0) - ret = reg_write(icd, MT9T031_SHUTTER_WIDTH, data & 0xffff); + ret = reg_write(client, MT9T031_SHUTTER_WIDTH, data & 0xffff); return ret; } -static int get_shutter(struct soc_camera_device *icd, u32 *data) +static int get_shutter(struct i2c_client *client, u32 *data) { int ret; - ret = reg_read(icd, MT9T031_SHUTTER_WIDTH_UPPER); + ret = reg_read(client, MT9T031_SHUTTER_WIDTH_UPPER); *data = ret << 16; if (ret >= 0) - ret = reg_read(icd, MT9T031_SHUTTER_WIDTH); + ret = reg_read(client, MT9T031_SHUTTER_WIDTH); *data |= ret & 0xffff; return ret < 0 ? ret : 0; @@ -141,12 +138,12 @@ static int get_shutter(struct soc_camera_device *icd, u32 *data) static int mt9t031_init(struct soc_camera_device *icd) { - struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd); - struct soc_camera_link *icl = mt9t031->client->dev.platform_data; + struct i2c_client *client = to_i2c_client(icd->control); + struct soc_camera_link *icl = client->dev.platform_data; int ret; if (icl->power) { - ret = icl->power(&mt9t031->client->dev, 1); + ret = icl->power(&client->dev, 1); if (ret < 0) { dev_err(icd->vdev->parent, "Platform failed to power-on the camera.\n"); @@ -155,44 +152,48 @@ static int mt9t031_init(struct soc_camera_device *icd) } /* Disable chip output, synchronous option update */ - ret = reg_write(icd, MT9T031_RESET, 1); + ret = reg_write(client, MT9T031_RESET, 1); if (ret >= 0) - ret = reg_write(icd, MT9T031_RESET, 0); + ret = reg_write(client, MT9T031_RESET, 0); if (ret >= 0) - ret = reg_clear(icd, MT9T031_OUTPUT_CONTROL, 2); + ret = reg_clear(client, MT9T031_OUTPUT_CONTROL, 2); if (ret < 0 && icl->power) - icl->power(&mt9t031->client->dev, 0); + icl->power(&client->dev, 0); return ret >= 0 ? 0 : -EIO; } static int mt9t031_release(struct soc_camera_device *icd) { - struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd); - struct soc_camera_link *icl = mt9t031->client->dev.platform_data; + struct i2c_client *client = to_i2c_client(icd->control); + struct soc_camera_link *icl = client->dev.platform_data; /* Disable the chip */ - reg_clear(icd, MT9T031_OUTPUT_CONTROL, 2); + reg_clear(client, MT9T031_OUTPUT_CONTROL, 2); if (icl->power) - icl->power(&mt9t031->client->dev, 0); + icl->power(&client->dev, 0); return 0; } static int mt9t031_start_capture(struct soc_camera_device *icd) { + struct i2c_client *client = to_i2c_client(icd->control); + /* Switch to master "normal" mode */ - if (reg_set(icd, MT9T031_OUTPUT_CONTROL, 2) < 0) + if (reg_set(client, MT9T031_OUTPUT_CONTROL, 2) < 0) return -EIO; return 0; } static int mt9t031_stop_capture(struct soc_camera_device *icd) { + struct i2c_client *client = to_i2c_client(icd->control); + /* Stop sensor readout */ - if (reg_clear(icd, MT9T031_OUTPUT_CONTROL, 2) < 0) + if (reg_clear(client, MT9T031_OUTPUT_CONTROL, 2) < 0) return -EIO; return 0; } @@ -200,14 +201,16 @@ static int mt9t031_stop_capture(struct soc_camera_device *icd) static int mt9t031_set_bus_param(struct soc_camera_device *icd, unsigned long flags) { + struct i2c_client *client = to_i2c_client(icd->control); + /* The caller should have queried our parameters, check anyway */ if (flags & ~MT9T031_BUS_PARAM) return -EINVAL; if (flags & SOCAM_PCLK_SAMPLE_FALLING) - reg_clear(icd, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000); + reg_clear(client, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000); else - reg_set(icd, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000); + reg_set(client, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000); return 0; } @@ -235,6 +238,7 @@ static void recalculate_limits(struct soc_camera_device *icd, static int mt9t031_set_params(struct soc_camera_device *icd, struct v4l2_rect *rect, u16 xskip, u16 yskip) { + struct i2c_client *client = to_i2c_client(icd->control); struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd); int ret; u16 xbin, ybin, width, height, left, top; @@ -277,22 +281,22 @@ static int mt9t031_set_params(struct soc_camera_device *icd, } /* Disable register update, reconfigure atomically */ - ret = reg_set(icd, MT9T031_OUTPUT_CONTROL, 1); + ret = reg_set(client, MT9T031_OUTPUT_CONTROL, 1); if (ret < 0) return ret; /* Blanking and start values - default... */ - ret = reg_write(icd, MT9T031_HORIZONTAL_BLANKING, hblank); + ret = reg_write(client, MT9T031_HORIZONTAL_BLANKING, hblank); if (ret >= 0) - ret = reg_write(icd, MT9T031_VERTICAL_BLANKING, vblank); + ret = reg_write(client, MT9T031_VERTICAL_BLANKING, vblank); if (yskip != mt9t031->yskip || xskip != mt9t031->xskip) { /* Binning, skipping */ if (ret >= 0) - ret = reg_write(icd, MT9T031_COLUMN_ADDRESS_MODE, + ret = reg_write(client, MT9T031_COLUMN_ADDRESS_MODE, ((xbin - 1) << 4) | (xskip - 1)); if (ret >= 0) - ret = reg_write(icd, MT9T031_ROW_ADDRESS_MODE, + ret = reg_write(client, MT9T031_ROW_ADDRESS_MODE, ((ybin - 1) << 4) | (yskip - 1)); } dev_dbg(&icd->dev, "new physical left %u, top %u\n", left, top); @@ -300,16 +304,16 @@ static int mt9t031_set_params(struct soc_camera_device *icd, /* The caller provides a supported format, as guaranteed by * icd->try_fmt_cap(), soc_camera_s_crop() and soc_camera_cropcap() */ if (ret >= 0) - ret = reg_write(icd, MT9T031_COLUMN_START, left); + ret = reg_write(client, MT9T031_COLUMN_START, left); if (ret >= 0) - ret = reg_write(icd, MT9T031_ROW_START, top); + ret = reg_write(client, MT9T031_ROW_START, top); if (ret >= 0) - ret = reg_write(icd, MT9T031_WINDOW_WIDTH, width - 1); + ret = reg_write(client, MT9T031_WINDOW_WIDTH, width - 1); if (ret >= 0) - ret = reg_write(icd, MT9T031_WINDOW_HEIGHT, + ret = reg_write(client, MT9T031_WINDOW_HEIGHT, height + icd->y_skip_top - 1); if (ret >= 0 && mt9t031->autoexposure) { - ret = set_shutter(icd, height + icd->y_skip_top + vblank); + ret = set_shutter(client, height + icd->y_skip_top + vblank); if (ret >= 0) { const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank; const struct v4l2_queryctrl *qctrl = @@ -324,7 +328,7 @@ static int mt9t031_set_params(struct soc_camera_device *icd, /* Re-enable register update, commit all changes */ if (ret >= 0) - ret = reg_clear(icd, MT9T031_OUTPUT_CONTROL, 1); + ret = reg_clear(client, MT9T031_OUTPUT_CONTROL, 1); return ret < 0 ? ret : 0; } @@ -381,17 +385,9 @@ static int mt9t031_try_fmt(struct soc_camera_device *icd, { struct v4l2_pix_format *pix = &f->fmt.pix; - if (pix->height < MT9T031_MIN_HEIGHT) - pix->height = MT9T031_MIN_HEIGHT; - if (pix->height > MT9T031_MAX_HEIGHT) - pix->height = MT9T031_MAX_HEIGHT; - if (pix->width < MT9T031_MIN_WIDTH) - pix->width = MT9T031_MIN_WIDTH; - if (pix->width > MT9T031_MAX_WIDTH) - pix->width = MT9T031_MAX_WIDTH; - - pix->width &= ~0x01; /* has to be even */ - pix->height &= ~0x01; /* has to be even */ + v4l_bound_align_image( + &pix->width, MT9T031_MIN_WIDTH, MT9T031_MAX_WIDTH, 1, + &pix->height, MT9T031_MIN_HEIGHT, MT9T031_MAX_HEIGHT, 1, 0); return 0; } @@ -417,15 +413,15 @@ static int mt9t031_get_chip_id(struct soc_camera_device *icd, static int mt9t031_get_register(struct soc_camera_device *icd, struct v4l2_dbg_register *reg) { - struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd); + struct i2c_client *client = to_i2c_client(icd->control); if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) return -EINVAL; - if (reg->match.addr != mt9t031->client->addr) + if (reg->match.addr != client->addr) return -ENODEV; - reg->val = reg_read(icd, reg->reg); + reg->val = reg_read(client, reg->reg); if (reg->val > 0xffff) return -EIO; @@ -436,15 +432,15 @@ static int mt9t031_get_register(struct soc_camera_device *icd, static int mt9t031_set_register(struct soc_camera_device *icd, struct v4l2_dbg_register *reg) { - struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd); + struct i2c_client *client = to_i2c_client(icd->control); if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) return -EINVAL; - if (reg->match.addr != mt9t031->client->addr) + if (reg->match.addr != client->addr) return -ENODEV; - if (reg_write(icd, reg->reg, reg->val) < 0) + if (reg_write(client, reg->reg, reg->val) < 0) return -EIO; return 0; @@ -528,18 +524,19 @@ static struct soc_camera_ops mt9t031_ops = { static int mt9t031_get_control(struct soc_camera_device *icd, struct v4l2_control *ctrl) { + struct i2c_client *client = to_i2c_client(icd->control); struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd); int data; switch (ctrl->id) { case V4L2_CID_VFLIP: - data = reg_read(icd, MT9T031_READ_MODE_2); + data = reg_read(client, MT9T031_READ_MODE_2); if (data < 0) return -EIO; ctrl->value = !!(data & 0x8000); break; case V4L2_CID_HFLIP: - data = reg_read(icd, MT9T031_READ_MODE_2); + data = reg_read(client, MT9T031_READ_MODE_2); if (data < 0) return -EIO; ctrl->value = !!(data & 0x4000); @@ -553,6 +550,7 @@ static int mt9t031_get_control(struct soc_camera_device *icd, struct v4l2_contro static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_control *ctrl) { + struct i2c_client *client = to_i2c_client(icd->control); struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd); const struct v4l2_queryctrl *qctrl; int data; @@ -565,17 +563,17 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro switch (ctrl->id) { case V4L2_CID_VFLIP: if (ctrl->value) - data = reg_set(icd, MT9T031_READ_MODE_2, 0x8000); + data = reg_set(client, MT9T031_READ_MODE_2, 0x8000); else - data = reg_clear(icd, MT9T031_READ_MODE_2, 0x8000); + data = reg_clear(client, MT9T031_READ_MODE_2, 0x8000); if (data < 0) return -EIO; break; case V4L2_CID_HFLIP: if (ctrl->value) - data = reg_set(icd, MT9T031_READ_MODE_2, 0x4000); + data = reg_set(client, MT9T031_READ_MODE_2, 0x4000); else - data = reg_clear(icd, MT9T031_READ_MODE_2, 0x4000); + data = reg_clear(client, MT9T031_READ_MODE_2, 0x4000); if (data < 0) return -EIO; break; @@ -589,7 +587,7 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro data = ((ctrl->value - qctrl->minimum) * 8 + range / 2) / range; dev_dbg(&icd->dev, "Setting gain %d\n", data); - data = reg_write(icd, MT9T031_GLOBAL_GAIN, data); + data = reg_write(client, MT9T031_GLOBAL_GAIN, data); if (data < 0) return -EIO; } else { @@ -609,8 +607,8 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro data = (((gain - 64 + 7) * 32) & 0xff00) | 0x60; dev_dbg(&icd->dev, "Setting gain from 0x%x to 0x%x\n", - reg_read(icd, MT9T031_GLOBAL_GAIN), data); - data = reg_write(icd, MT9T031_GLOBAL_GAIN, data); + reg_read(client, MT9T031_GLOBAL_GAIN), data); + data = reg_write(client, MT9T031_GLOBAL_GAIN, data); if (data < 0) return -EIO; } @@ -628,10 +626,10 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro range / 2) / range + 1; u32 old; - get_shutter(icd, &old); + get_shutter(client, &old); dev_dbg(&icd->dev, "Setting shutter width from %u to %u\n", old, shutter); - if (set_shutter(icd, shutter) < 0) + if (set_shutter(client, shutter) < 0) return -EIO; icd->exposure = ctrl->value; mt9t031->autoexposure = 0; @@ -641,7 +639,7 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro if (ctrl->value) { const u16 vblank = MT9T031_VERTICAL_BLANK; const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank; - if (set_shutter(icd, icd->height + + if (set_shutter(client, icd->height + icd->y_skip_top + vblank) < 0) return -EIO; qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE); @@ -661,6 +659,7 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro * this wasn't our capture interface, so, we wait for the right one */ static int mt9t031_video_probe(struct soc_camera_device *icd) { + struct i2c_client *client = to_i2c_client(icd->control); struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd); s32 data; int ret; @@ -672,11 +671,11 @@ static int mt9t031_video_probe(struct soc_camera_device *icd) return -ENODEV; /* Enable the chip */ - data = reg_write(icd, MT9T031_CHIP_ENABLE, 1); + data = reg_write(client, MT9T031_CHIP_ENABLE, 1); dev_dbg(&icd->dev, "write: %d\n", data); /* Read out the chip version register */ - data = reg_read(icd, MT9T031_CHIP_VERSION); + data = reg_read(client, MT9T031_CHIP_VERSION); switch (data) { case 0x1621: diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c index 4d3b4813c322..dbdcc86ae50d 100644 --- a/drivers/media/video/mt9v022.c +++ b/drivers/media/video/mt9v022.c @@ -91,51 +91,49 @@ struct mt9v022 { u16 chip_control; }; -static int reg_read(struct soc_camera_device *icd, const u8 reg) +static int reg_read(struct i2c_client *client, const u8 reg) { - struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); - struct i2c_client *client = mt9v022->client; s32 data = i2c_smbus_read_word_data(client, reg); return data < 0 ? data : swab16(data); } -static int reg_write(struct soc_camera_device *icd, const u8 reg, +static int reg_write(struct i2c_client *client, const u8 reg, const u16 data) { - struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); - return i2c_smbus_write_word_data(mt9v022->client, reg, swab16(data)); + return i2c_smbus_write_word_data(client, reg, swab16(data)); } -static int reg_set(struct soc_camera_device *icd, const u8 reg, +static int reg_set(struct i2c_client *client, const u8 reg, const u16 data) { int ret; - ret = reg_read(icd, reg); + ret = reg_read(client, reg); if (ret < 0) return ret; - return reg_write(icd, reg, ret | data); + return reg_write(client, reg, ret | data); } -static int reg_clear(struct soc_camera_device *icd, const u8 reg, +static int reg_clear(struct i2c_client *client, const u8 reg, const u16 data) { int ret; - ret = reg_read(icd, reg); + ret = reg_read(client, reg); if (ret < 0) return ret; - return reg_write(icd, reg, ret & ~data); + return reg_write(client, reg, ret & ~data); } static int mt9v022_init(struct soc_camera_device *icd) { + struct i2c_client *client = to_i2c_client(icd->control); struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); - struct soc_camera_link *icl = mt9v022->client->dev.platform_data; + struct soc_camera_link *icl = client->dev.platform_data; int ret; if (icl->power) { - ret = icl->power(&mt9v022->client->dev, 1); + ret = icl->power(&client->dev, 1); if (ret < 0) { dev_err(icd->vdev->parent, "Platform failed to power-on the camera.\n"); @@ -148,27 +146,27 @@ static int mt9v022_init(struct soc_camera_device *icd) * if available. Soft reset is done in video_probe(). */ if (icl->reset) - icl->reset(&mt9v022->client->dev); + icl->reset(&client->dev); /* Almost the default mode: master, parallel, simultaneous, and an * undocumented bit 0x200, which is present in table 7, but not in 8, * plus snapshot mode to disable scan for now */ mt9v022->chip_control |= 0x10; - ret = reg_write(icd, MT9V022_CHIP_CONTROL, mt9v022->chip_control); + ret = reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control); if (!ret) - ret = reg_write(icd, MT9V022_READ_MODE, 0x300); + ret = reg_write(client, MT9V022_READ_MODE, 0x300); /* All defaults */ if (!ret) /* AEC, AGC on */ - ret = reg_set(icd, MT9V022_AEC_AGC_ENABLE, 0x3); + ret = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x3); if (!ret) - ret = reg_write(icd, MT9V022_MAX_TOTAL_SHUTTER_WIDTH, 480); + ret = reg_write(client, MT9V022_MAX_TOTAL_SHUTTER_WIDTH, 480); if (!ret) /* default - auto */ - ret = reg_clear(icd, MT9V022_BLACK_LEVEL_CALIB_CTRL, 1); + ret = reg_clear(client, MT9V022_BLACK_LEVEL_CALIB_CTRL, 1); if (!ret) - ret = reg_write(icd, MT9V022_DIGITAL_TEST_PATTERN, 0); + ret = reg_write(client, MT9V022_DIGITAL_TEST_PATTERN, 0); return ret; } @@ -186,10 +184,11 @@ static int mt9v022_release(struct soc_camera_device *icd) static int mt9v022_start_capture(struct soc_camera_device *icd) { + struct i2c_client *client = to_i2c_client(icd->control); struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); /* Switch to master "normal" mode */ mt9v022->chip_control &= ~0x10; - if (reg_write(icd, MT9V022_CHIP_CONTROL, + if (reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control) < 0) return -EIO; return 0; @@ -197,10 +196,11 @@ static int mt9v022_start_capture(struct soc_camera_device *icd) static int mt9v022_stop_capture(struct soc_camera_device *icd) { + struct i2c_client *client = to_i2c_client(icd->control); struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); /* Switch to snapshot mode */ mt9v022->chip_control |= 0x10; - if (reg_write(icd, MT9V022_CHIP_CONTROL, + if (reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control) < 0) return -EIO; return 0; @@ -209,8 +209,9 @@ static int mt9v022_stop_capture(struct soc_camera_device *icd) static int mt9v022_set_bus_param(struct soc_camera_device *icd, unsigned long flags) { + struct i2c_client *client = to_i2c_client(icd->control); struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); - struct soc_camera_link *icl = mt9v022->client->dev.platform_data; + struct soc_camera_link *icl = client->dev.platform_data; unsigned int width_flag = flags & SOCAM_DATAWIDTH_MASK; int ret; u16 pixclk = 0; @@ -243,14 +244,14 @@ static int mt9v022_set_bus_param(struct soc_camera_device *icd, if (!(flags & SOCAM_VSYNC_ACTIVE_HIGH)) pixclk |= 0x2; - ret = reg_write(icd, MT9V022_PIXCLK_FV_LV, pixclk); + ret = reg_write(client, MT9V022_PIXCLK_FV_LV, pixclk); if (ret < 0) return ret; if (!(flags & SOCAM_MASTER)) mt9v022->chip_control &= ~0x8; - ret = reg_write(icd, MT9V022_CHIP_CONTROL, mt9v022->chip_control); + ret = reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control); if (ret < 0) return ret; @@ -282,35 +283,36 @@ static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd) static int mt9v022_set_crop(struct soc_camera_device *icd, struct v4l2_rect *rect) { + struct i2c_client *client = to_i2c_client(icd->control); int ret; /* Like in example app. Contradicts the datasheet though */ - ret = reg_read(icd, MT9V022_AEC_AGC_ENABLE); + ret = reg_read(client, MT9V022_AEC_AGC_ENABLE); if (ret >= 0) { if (ret & 1) /* Autoexposure */ - ret = reg_write(icd, MT9V022_MAX_TOTAL_SHUTTER_WIDTH, + ret = reg_write(client, MT9V022_MAX_TOTAL_SHUTTER_WIDTH, rect->height + icd->y_skip_top + 43); else - ret = reg_write(icd, MT9V022_TOTAL_SHUTTER_WIDTH, + ret = reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, rect->height + icd->y_skip_top + 43); } /* Setup frame format: defaults apart from width and height */ if (!ret) - ret = reg_write(icd, MT9V022_COLUMN_START, rect->left); + ret = reg_write(client, MT9V022_COLUMN_START, rect->left); if (!ret) - ret = reg_write(icd, MT9V022_ROW_START, rect->top); + ret = reg_write(client, MT9V022_ROW_START, rect->top); if (!ret) /* Default 94, Phytec driver says: * "width + horizontal blank >= 660" */ - ret = reg_write(icd, MT9V022_HORIZONTAL_BLANKING, + ret = reg_write(client, MT9V022_HORIZONTAL_BLANKING, rect->width > 660 - 43 ? 43 : 660 - rect->width); if (!ret) - ret = reg_write(icd, MT9V022_VERTICAL_BLANKING, 45); + ret = reg_write(client, MT9V022_VERTICAL_BLANKING, 45); if (!ret) - ret = reg_write(icd, MT9V022_WINDOW_WIDTH, rect->width); + ret = reg_write(client, MT9V022_WINDOW_WIDTH, rect->width); if (!ret) - ret = reg_write(icd, MT9V022_WINDOW_HEIGHT, + ret = reg_write(client, MT9V022_WINDOW_HEIGHT, rect->height + icd->y_skip_top); if (ret < 0) @@ -362,15 +364,9 @@ static int mt9v022_try_fmt(struct soc_camera_device *icd, { struct v4l2_pix_format *pix = &f->fmt.pix; - if (pix->height < 32 + icd->y_skip_top) - pix->height = 32 + icd->y_skip_top; - if (pix->height > 480 + icd->y_skip_top) - pix->height = 480 + icd->y_skip_top; - if (pix->width < 48) - pix->width = 48; - if (pix->width > 752) - pix->width = 752; - pix->width &= ~0x03; /* ? */ + v4l_bound_align_image(&pix->width, 48, 752, 2 /* ? */, + &pix->height, 32 + icd->y_skip_top, + 480 + icd->y_skip_top, 0, 0); return 0; } @@ -396,16 +392,16 @@ static int mt9v022_get_chip_id(struct soc_camera_device *icd, static int mt9v022_get_register(struct soc_camera_device *icd, struct v4l2_dbg_register *reg) { - struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); + struct i2c_client *client = to_i2c_client(icd->control); if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) return -EINVAL; - if (reg->match.addr != mt9v022->client->addr) + if (reg->match.addr != client->addr) return -ENODEV; reg->size = 2; - reg->val = reg_read(icd, reg->reg); + reg->val = reg_read(client, reg->reg); if (reg->val > 0xffff) return -EIO; @@ -416,15 +412,15 @@ static int mt9v022_get_register(struct soc_camera_device *icd, static int mt9v022_set_register(struct soc_camera_device *icd, struct v4l2_dbg_register *reg) { - struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); + struct i2c_client *client = to_i2c_client(icd->control); if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) return -EINVAL; - if (reg->match.addr != mt9v022->client->addr) + if (reg->match.addr != client->addr) return -ENODEV; - if (reg_write(icd, reg->reg, reg->val) < 0) + if (reg_write(client, reg->reg, reg->val) < 0) return -EIO; return 0; @@ -517,29 +513,30 @@ static struct soc_camera_ops mt9v022_ops = { static int mt9v022_get_control(struct soc_camera_device *icd, struct v4l2_control *ctrl) { + struct i2c_client *client = to_i2c_client(icd->control); int data; switch (ctrl->id) { case V4L2_CID_VFLIP: - data = reg_read(icd, MT9V022_READ_MODE); + data = reg_read(client, MT9V022_READ_MODE); if (data < 0) return -EIO; ctrl->value = !!(data & 0x10); break; case V4L2_CID_HFLIP: - data = reg_read(icd, MT9V022_READ_MODE); + data = reg_read(client, MT9V022_READ_MODE); if (data < 0) return -EIO; ctrl->value = !!(data & 0x20); break; case V4L2_CID_EXPOSURE_AUTO: - data = reg_read(icd, MT9V022_AEC_AGC_ENABLE); + data = reg_read(client, MT9V022_AEC_AGC_ENABLE); if (data < 0) return -EIO; ctrl->value = !!(data & 0x1); break; case V4L2_CID_AUTOGAIN: - data = reg_read(icd, MT9V022_AEC_AGC_ENABLE); + data = reg_read(client, MT9V022_AEC_AGC_ENABLE); if (data < 0) return -EIO; ctrl->value = !!(data & 0x2); @@ -552,6 +549,7 @@ static int mt9v022_set_control(struct soc_camera_device *icd, struct v4l2_control *ctrl) { int data; + struct i2c_client *client = to_i2c_client(icd->control); const struct v4l2_queryctrl *qctrl; qctrl = soc_camera_find_qctrl(&mt9v022_ops, ctrl->id); @@ -562,17 +560,17 @@ static int mt9v022_set_control(struct soc_camera_device *icd, switch (ctrl->id) { case V4L2_CID_VFLIP: if (ctrl->value) - data = reg_set(icd, MT9V022_READ_MODE, 0x10); + data = reg_set(client, MT9V022_READ_MODE, 0x10); else - data = reg_clear(icd, MT9V022_READ_MODE, 0x10); + data = reg_clear(client, MT9V022_READ_MODE, 0x10); if (data < 0) return -EIO; break; case V4L2_CID_HFLIP: if (ctrl->value) - data = reg_set(icd, MT9V022_READ_MODE, 0x20); + data = reg_set(client, MT9V022_READ_MODE, 0x20); else - data = reg_clear(icd, MT9V022_READ_MODE, 0x20); + data = reg_clear(client, MT9V022_READ_MODE, 0x20); if (data < 0) return -EIO; break; @@ -593,12 +591,12 @@ static int mt9v022_set_control(struct soc_camera_device *icd, /* The user wants to set gain manually, hope, she * knows, what she's doing... Switch AGC off. */ - if (reg_clear(icd, MT9V022_AEC_AGC_ENABLE, 0x2) < 0) + if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0) return -EIO; dev_info(&icd->dev, "Setting gain from %d to %lu\n", - reg_read(icd, MT9V022_ANALOG_GAIN), gain); - if (reg_write(icd, MT9V022_ANALOG_GAIN, gain) < 0) + reg_read(client, MT9V022_ANALOG_GAIN), gain); + if (reg_write(client, MT9V022_ANALOG_GAIN, gain) < 0) return -EIO; icd->gain = ctrl->value; } @@ -614,13 +612,13 @@ static int mt9v022_set_control(struct soc_camera_device *icd, /* The user wants to set shutter width manually, hope, * she knows, what she's doing... Switch AEC off. */ - if (reg_clear(icd, MT9V022_AEC_AGC_ENABLE, 0x1) < 0) + if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1) < 0) return -EIO; dev_dbg(&icd->dev, "Shutter width from %d to %lu\n", - reg_read(icd, MT9V022_TOTAL_SHUTTER_WIDTH), + reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH), shutter); - if (reg_write(icd, MT9V022_TOTAL_SHUTTER_WIDTH, + if (reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, shutter) < 0) return -EIO; icd->exposure = ctrl->value; @@ -628,17 +626,17 @@ static int mt9v022_set_control(struct soc_camera_device *icd, break; case V4L2_CID_AUTOGAIN: if (ctrl->value) - data = reg_set(icd, MT9V022_AEC_AGC_ENABLE, 0x2); + data = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x2); else - data = reg_clear(icd, MT9V022_AEC_AGC_ENABLE, 0x2); + data = reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2); if (data < 0) return -EIO; break; case V4L2_CID_EXPOSURE_AUTO: if (ctrl->value) - data = reg_set(icd, MT9V022_AEC_AGC_ENABLE, 0x1); + data = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x1); else - data = reg_clear(icd, MT9V022_AEC_AGC_ENABLE, 0x1); + data = reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1); if (data < 0) return -EIO; break; @@ -650,8 +648,9 @@ static int mt9v022_set_control(struct soc_camera_device *icd, * this wasn't our capture interface, so, we wait for the right one */ static int mt9v022_video_probe(struct soc_camera_device *icd) { + struct i2c_client *client = to_i2c_client(icd->control); struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); - struct soc_camera_link *icl = mt9v022->client->dev.platform_data; + struct soc_camera_link *icl = client->dev.platform_data; s32 data; int ret; unsigned long flags; @@ -661,7 +660,7 @@ static int mt9v022_video_probe(struct soc_camera_device *icd) return -ENODEV; /* Read out the chip version register */ - data = reg_read(icd, MT9V022_CHIP_VERSION); + data = reg_read(client, MT9V022_CHIP_VERSION); /* must be 0x1311 or 0x1313 */ if (data != 0x1311 && data != 0x1313) { @@ -672,12 +671,12 @@ static int mt9v022_video_probe(struct soc_camera_device *icd) } /* Soft reset */ - ret = reg_write(icd, MT9V022_RESET, 1); + ret = reg_write(client, MT9V022_RESET, 1); if (ret < 0) goto ei2c; /* 15 clock cycles */ udelay(200); - if (reg_read(icd, MT9V022_RESET)) { + if (reg_read(client, MT9V022_RESET)) { dev_err(&icd->dev, "Resetting MT9V022 failed!\n"); goto ei2c; } @@ -685,11 +684,11 @@ static int mt9v022_video_probe(struct soc_camera_device *icd) /* Set monochrome or colour sensor type */ if (sensor_type && (!strcmp("colour", sensor_type) || !strcmp("color", sensor_type))) { - ret = reg_write(icd, MT9V022_PIXEL_OPERATION_MODE, 4 | 0x11); + ret = reg_write(client, MT9V022_PIXEL_OPERATION_MODE, 4 | 0x11); mt9v022->model = V4L2_IDENT_MT9V022IX7ATC; icd->formats = mt9v022_colour_formats; } else { - ret = reg_write(icd, MT9V022_PIXEL_OPERATION_MODE, 0x11); + ret = reg_write(client, MT9V022_PIXEL_OPERATION_MODE, 0x11); mt9v022->model = V4L2_IDENT_MT9V022IX7ATM; icd->formats = mt9v022_monochrome_formats; } @@ -735,10 +734,13 @@ ei2c: static void mt9v022_video_remove(struct soc_camera_device *icd) { struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); + struct soc_camera_link *icl = mt9v022->client->dev.platform_data; dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9v022->client->addr, icd->dev.parent, icd->vdev); soc_camera_video_stop(icd); + if (icl->free_bus) + icl->free_bus(icl); } static int mt9v022_probe(struct i2c_client *client, diff --git a/drivers/media/video/mx1_camera.c b/drivers/media/video/mx1_camera.c index 86fab56c5a20..2d075205bdfe 100644 --- a/drivers/media/video/mx1_camera.c +++ b/drivers/media/video/mx1_camera.c @@ -102,10 +102,10 @@ struct mx1_buffer { * Interface. If anyone ever builds hardware to enable more than * one camera, they will have to modify this driver too */ struct mx1_camera_dev { + struct soc_camera_host soc_host; struct soc_camera_device *icd; struct mx1_camera_pdata *pdata; struct mx1_buffer *active; - struct device *dev; struct resource *res; struct clk *clk; struct list_head capture; @@ -219,7 +219,7 @@ static int mx1_camera_setup_dma(struct mx1_camera_dev *pcdev) int ret; if (unlikely(!pcdev->active)) { - dev_err(pcdev->dev, "DMA End IRQ with no active buffer\n"); + dev_err(pcdev->soc_host.dev, "DMA End IRQ with no active buffer\n"); return -EFAULT; } @@ -229,7 +229,7 @@ static int mx1_camera_setup_dma(struct mx1_camera_dev *pcdev) vbuf->size, pcdev->res->start + CSIRXR, DMA_MODE_READ); if (unlikely(ret)) - dev_err(pcdev->dev, "Failed to setup DMA sg list\n"); + dev_err(pcdev->soc_host.dev, "Failed to setup DMA sg list\n"); return ret; } @@ -338,14 +338,14 @@ static void mx1_camera_dma_irq(int channel, void *data) imx_dma_disable(channel); if (unlikely(!pcdev->active)) { - dev_err(pcdev->dev, "DMA End IRQ with no active buffer\n"); + dev_err(pcdev->soc_host.dev, "DMA End IRQ with no active buffer\n"); goto out; } vb = &pcdev->active->vb; buf = container_of(vb, struct mx1_buffer, vb); WARN_ON(buf->inwork || list_empty(&vb->queue)); - dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, + dev_dbg(pcdev->soc_host.dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, vb, vb->baddr, vb->bsize); mx1_camera_wakeup(pcdev, vb, buf); @@ -366,7 +366,7 @@ static void mx1_camera_init_videobuf(struct videobuf_queue *q, struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct mx1_camera_dev *pcdev = ici->priv; - videobuf_queue_dma_contig_init(q, &mx1_videobuf_ops, pcdev->dev, + videobuf_queue_dma_contig_init(q, &mx1_videobuf_ops, ici->dev, &pcdev->lock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE, @@ -385,7 +385,7 @@ static int mclk_get_divisor(struct mx1_camera_dev *pcdev) * they get a nice Oops */ div = (lcdclk + 2 * mclk - 1) / (2 * mclk) - 1; - dev_dbg(pcdev->dev, "System clock %lukHz, target freq %dkHz, " + dev_dbg(pcdev->soc_host.dev, "System clock %lukHz, target freq %dkHz, " "divisor %lu\n", lcdclk / 1000, mclk / 1000, div); return div; @@ -395,7 +395,7 @@ static void mx1_camera_activate(struct mx1_camera_dev *pcdev) { unsigned int csicr1 = CSICR1_EN; - dev_dbg(pcdev->dev, "Activate device\n"); + dev_dbg(pcdev->soc_host.dev, "Activate device\n"); clk_enable(pcdev->clk); @@ -411,7 +411,7 @@ static void mx1_camera_activate(struct mx1_camera_dev *pcdev) static void mx1_camera_deactivate(struct mx1_camera_dev *pcdev) { - dev_dbg(pcdev->dev, "Deactivate device\n"); + dev_dbg(pcdev->soc_host.dev, "Deactivate device\n"); /* Disable all CSI interface */ __raw_writel(0x00, pcdev->base + CSICR1); @@ -550,7 +550,7 @@ static int mx1_camera_set_fmt(struct soc_camera_device *icd, xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); if (!xlate) { - dev_warn(&ici->dev, "Format %x not found\n", pix->pixelformat); + dev_warn(ici->dev, "Format %x not found\n", pix->pixelformat); return -EINVAL; } @@ -633,12 +633,6 @@ static struct soc_camera_host_ops mx1_soc_camera_host_ops = { .querycap = mx1_camera_querycap, }; -/* Should be allocated dynamically too, but we have only one. */ -static struct soc_camera_host mx1_soc_camera_host = { - .drv_name = DRIVER_NAME, - .ops = &mx1_soc_camera_host_ops, -}; - static struct fiq_handler fh = { .name = "csi_sof" }; @@ -673,7 +667,6 @@ static int __init mx1_camera_probe(struct platform_device *pdev) goto exit_put_clk; } - dev_set_drvdata(&pdev->dev, pcdev); pcdev->res = res; pcdev->clk = clk; @@ -707,16 +700,15 @@ static int __init mx1_camera_probe(struct platform_device *pdev) } pcdev->irq = irq; pcdev->base = base; - pcdev->dev = &pdev->dev; /* request dma */ pcdev->dma_chan = imx_dma_request_by_prio(DRIVER_NAME, DMA_PRIO_HIGH); if (pcdev->dma_chan < 0) { - dev_err(pcdev->dev, "Can't request DMA for MX1 CSI\n"); + dev_err(&pdev->dev, "Can't request DMA for MX1 CSI\n"); err = -EBUSY; goto exit_iounmap; } - dev_dbg(pcdev->dev, "got DMA channel %d\n", pcdev->dma_chan); + dev_dbg(&pdev->dev, "got DMA channel %d\n", pcdev->dma_chan); imx_dma_setup_handlers(pcdev->dma_chan, mx1_camera_dma_irq, NULL, pcdev); @@ -729,7 +721,7 @@ static int __init mx1_camera_probe(struct platform_device *pdev) /* request irq */ err = claim_fiq(&fh); if (err) { - dev_err(pcdev->dev, "Camera interrupt register failed \n"); + dev_err(&pdev->dev, "Camera interrupt register failed \n"); goto exit_free_dma; } @@ -746,10 +738,12 @@ static int __init mx1_camera_probe(struct platform_device *pdev) mxc_set_irq_fiq(irq, 1); enable_fiq(irq); - mx1_soc_camera_host.priv = pcdev; - mx1_soc_camera_host.dev.parent = &pdev->dev; - mx1_soc_camera_host.nr = pdev->id; - err = soc_camera_host_register(&mx1_soc_camera_host); + pcdev->soc_host.drv_name = DRIVER_NAME; + pcdev->soc_host.ops = &mx1_soc_camera_host_ops; + pcdev->soc_host.priv = pcdev; + pcdev->soc_host.dev = &pdev->dev; + pcdev->soc_host.nr = pdev->id; + err = soc_camera_host_register(&pcdev->soc_host); if (err) goto exit_free_irq; @@ -777,7 +771,9 @@ exit: static int __exit mx1_camera_remove(struct platform_device *pdev) { - struct mx1_camera_dev *pcdev = platform_get_drvdata(pdev); + struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev); + struct mx1_camera_dev *pcdev = container_of(soc_host, + struct mx1_camera_dev, soc_host); struct resource *res; imx_dma_free(pcdev->dma_chan); @@ -787,7 +783,7 @@ static int __exit mx1_camera_remove(struct platform_device *pdev) clk_put(pcdev->clk); - soc_camera_host_unregister(&mx1_soc_camera_host); + soc_camera_host_unregister(soc_host); iounmap(pcdev->base); diff --git a/drivers/media/video/mx3_camera.c b/drivers/media/video/mx3_camera.c index 2d0781118eb0..e605c076ed89 100644 --- a/drivers/media/video/mx3_camera.c +++ b/drivers/media/video/mx3_camera.c @@ -87,7 +87,6 @@ struct mx3_camera_buffer { * @soc_host: embedded soc_host object */ struct mx3_camera_dev { - struct device *dev; /* * i.MX3x is only supposed to handle one camera on its Camera Sensor * Interface. If anyone ever builds hardware to enable more than one @@ -431,7 +430,7 @@ static void mx3_camera_init_videobuf(struct videobuf_queue *q, struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct mx3_camera_dev *mx3_cam = ici->priv; - videobuf_queue_dma_contig_init(q, &mx3_videobuf_ops, mx3_cam->dev, + videobuf_queue_dma_contig_init(q, &mx3_videobuf_ops, ici->dev, &mx3_cam->lock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE, @@ -599,7 +598,8 @@ static int test_platform_param(struct mx3_camera_dev *mx3_cam, *flags |= SOCAM_DATAWIDTH_4; break; default: - dev_info(mx3_cam->dev, "Unsupported bus width %d\n", buswidth); + dev_info(mx3_cam->soc_host.dev, "Unsupported bus width %d\n", + buswidth); return -EINVAL; } @@ -614,7 +614,7 @@ static int mx3_camera_try_bus_param(struct soc_camera_device *icd, unsigned long bus_flags, camera_flags; int ret = test_platform_param(mx3_cam, depth, &bus_flags); - dev_dbg(&ici->dev, "requested bus width %d bit: %d\n", depth, ret); + dev_dbg(ici->dev, "requested bus width %d bit: %d\n", depth, ret); if (ret < 0) return ret; @@ -637,7 +637,7 @@ static bool chan_filter(struct dma_chan *chan, void *arg) if (!rq) return false; - pdata = rq->mx3_cam->dev->platform_data; + pdata = rq->mx3_cam->soc_host.dev->platform_data; return rq->id == chan->chan_id && pdata->dma_dev == chan->device->dev; @@ -697,7 +697,7 @@ static int mx3_camera_get_formats(struct soc_camera_device *icd, int idx, xlate->cam_fmt = icd->formats + idx; xlate->buswidth = buswidth; xlate++; - dev_dbg(&ici->dev, "Providing format %s using %s\n", + dev_dbg(ici->dev, "Providing format %s using %s\n", mx3_camera_formats[0].name, icd->formats[idx].name); } @@ -709,7 +709,7 @@ static int mx3_camera_get_formats(struct soc_camera_device *icd, int idx, xlate->cam_fmt = icd->formats + idx; xlate->buswidth = buswidth; xlate++; - dev_dbg(&ici->dev, "Providing format %s using %s\n", + dev_dbg(ici->dev, "Providing format %s using %s\n", mx3_camera_formats[0].name, icd->formats[idx].name); } @@ -722,7 +722,7 @@ passthrough: xlate->cam_fmt = icd->formats + idx; xlate->buswidth = buswidth; xlate++; - dev_dbg(&ici->dev, + dev_dbg(ici->dev, "Providing format %s in pass-through mode\n", icd->formats[idx].name); } @@ -829,7 +829,7 @@ static int mx3_camera_set_fmt(struct soc_camera_device *icd, xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); if (!xlate) { - dev_warn(&ici->dev, "Format %x not found\n", pix->pixelformat); + dev_warn(ici->dev, "Format %x not found\n", pix->pixelformat); return -EINVAL; } @@ -866,7 +866,7 @@ static int mx3_camera_try_fmt(struct soc_camera_device *icd, xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); if (pixfmt && !xlate) { - dev_warn(&ici->dev, "Format %x not found\n", pixfmt); + dev_warn(ici->dev, "Format %x not found\n", pixfmt); return -EINVAL; } @@ -933,11 +933,11 @@ static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); if (!xlate) { - dev_warn(&ici->dev, "Format %x not found\n", pixfmt); + dev_warn(ici->dev, "Format %x not found\n", pixfmt); return -EINVAL; } - dev_dbg(&ici->dev, "requested bus width %d bit: %d\n", + dev_dbg(ici->dev, "requested bus width %d bit: %d\n", icd->buswidth, ret); if (ret < 0) @@ -947,7 +947,7 @@ static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) common_flags = soc_camera_bus_param_compatible(camera_flags, bus_flags); if (!common_flags) { - dev_dbg(&ici->dev, "no common flags: camera %lx, host %lx\n", + dev_dbg(ici->dev, "no common flags: camera %lx, host %lx\n", camera_flags, bus_flags); return -EINVAL; } @@ -1054,7 +1054,7 @@ static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) csi_reg_write(mx3_cam, sens_conf | dw, CSI_SENS_CONF); - dev_dbg(&ici->dev, "Set SENS_CONF to %x\n", sens_conf | dw); + dev_dbg(ici->dev, "Set SENS_CONF to %x\n", sens_conf | dw); return 0; } @@ -1074,7 +1074,7 @@ static struct soc_camera_host_ops mx3_soc_camera_host_ops = { .set_bus_param = mx3_camera_set_bus_param, }; -static int mx3_camera_probe(struct platform_device *pdev) +static int __devinit mx3_camera_probe(struct platform_device *pdev) { struct mx3_camera_dev *mx3_cam; struct resource *res; @@ -1102,8 +1102,6 @@ static int mx3_camera_probe(struct platform_device *pdev) goto eclkget; } - dev_set_drvdata(&pdev->dev, mx3_cam); - mx3_cam->pdata = pdev->dev.platform_data; mx3_cam->platform_flags = mx3_cam->pdata->flags; if (!(mx3_cam->platform_flags & (MX3_CAMERA_DATAWIDTH_4 | @@ -1135,14 +1133,14 @@ static int mx3_camera_probe(struct platform_device *pdev) } mx3_cam->base = base; - mx3_cam->dev = &pdev->dev; soc_host = &mx3_cam->soc_host; soc_host->drv_name = MX3_CAM_DRV_NAME; soc_host->ops = &mx3_soc_camera_host_ops; soc_host->priv = mx3_cam; - soc_host->dev.parent = &pdev->dev; + soc_host->dev = &pdev->dev; soc_host->nr = pdev->id; + err = soc_camera_host_register(soc_host); if (err) goto ecamhostreg; @@ -1165,11 +1163,13 @@ egetres: static int __devexit mx3_camera_remove(struct platform_device *pdev) { - struct mx3_camera_dev *mx3_cam = platform_get_drvdata(pdev); + struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev); + struct mx3_camera_dev *mx3_cam = container_of(soc_host, + struct mx3_camera_dev, soc_host); clk_put(mx3_cam->clk); - soc_camera_host_unregister(&mx3_cam->soc_host); + soc_camera_host_unregister(soc_host); iounmap(mx3_cam->base); @@ -1194,11 +1194,11 @@ static struct platform_driver mx3_camera_driver = { .name = MX3_CAM_DRV_NAME, }, .probe = mx3_camera_probe, - .remove = __exit_p(mx3_camera_remove), + .remove = __devexit_p(mx3_camera_remove), }; -static int __devinit mx3_camera_init(void) +static int __init mx3_camera_init(void) { return platform_driver_register(&mx3_camera_driver); } diff --git a/drivers/media/video/mxb.c b/drivers/media/video/mxb.c index 3be5a71bdac2..35890e8b2431 100644 --- a/drivers/media/video/mxb.c +++ b/drivers/media/video/mxb.c @@ -453,7 +453,7 @@ static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *vc) static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i) { DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index)); - if (i->index < 0 || i->index >= MXB_INPUTS) + if (i->index >= MXB_INPUTS) return -EINVAL; memcpy(i, &mxb_inputs[i->index], sizeof(struct v4l2_input)); return 0; @@ -616,7 +616,7 @@ static int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a) struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; struct mxb *mxb = (struct mxb *)dev->ext_priv; - if (a->index < 0 || a->index > MXB_INPUTS) { + if (a->index > MXB_INPUTS) { DEB_D(("VIDIOC_G_AUDIO %d out of range.\n", a->index)); return -EINVAL; } diff --git a/drivers/media/video/ov511.c b/drivers/media/video/ov511.c index 9af5532db142..0bc2cf573c76 100644 --- a/drivers/media/video/ov511.c +++ b/drivers/media/video/ov511.c @@ -112,6 +112,8 @@ static int framedrop = -1; static int fastset; static int force_palette; static int backlight; +/* Bitmask marking allocated devices from 0 to OV511_MAX_UNIT_VIDEO */ +static unsigned long ov511_devused; static int unit_video[OV511_MAX_UNIT_VIDEO]; static int remove_zeros; static int mirror; @@ -209,8 +211,6 @@ static const int i2c_detect_tries = 5; static struct usb_device_id device_table [] = { { USB_DEVICE(VEND_OMNIVISION, PROD_OV511) }, { USB_DEVICE(VEND_OMNIVISION, PROD_OV511PLUS) }, - { USB_DEVICE(VEND_OMNIVISION, PROD_OV518) }, - { USB_DEVICE(VEND_OMNIVISION, PROD_OV518PLUS) }, { USB_DEVICE(VEND_MATTEL, PROD_ME2CAM) }, { } /* Terminating entry */ }; @@ -5720,7 +5720,7 @@ ov51x_probe(struct usb_interface *intf, const struct usb_device_id *id) struct usb_device *dev = interface_to_usbdev(intf); struct usb_interface_descriptor *idesc; struct usb_ov511 *ov; - int i; + int i, rc, nr; PDEBUG(1, "probing for device..."); @@ -5845,33 +5845,41 @@ ov51x_probe(struct usb_interface *intf, const struct usb_device_id *id) ov->vdev->parent = &intf->dev; video_set_drvdata(ov->vdev, ov); - for (i = 0; i < OV511_MAX_UNIT_VIDEO; i++) { - /* Minor 0 cannot be specified; assume user wants autodetect */ - if (unit_video[i] == 0) - break; + mutex_lock(&ov->lock); - if (video_register_device(ov->vdev, VFL_TYPE_GRABBER, - unit_video[i]) >= 0) { - break; - } - } + /* Check to see next free device and mark as used */ + nr = find_first_zero_bit(&ov511_devused, OV511_MAX_UNIT_VIDEO); - /* Use the next available one */ - if ((ov->vdev->minor == -1) && - video_register_device(ov->vdev, VFL_TYPE_GRABBER, -1) < 0) { + /* Registers device */ + if (unit_video[nr] != 0) + rc = video_register_device(ov->vdev, VFL_TYPE_GRABBER, + unit_video[nr]); + else + rc = video_register_device(ov->vdev, VFL_TYPE_GRABBER, -1); + + if (rc < 0) { err("video_register_device failed"); + mutex_unlock(&ov->lock); goto error; } + /* Mark device as used */ + ov511_devused |= 1 << nr; + ov->nr = nr; + dev_info(&intf->dev, "Device at %s registered to minor %d\n", ov->usb_path, ov->vdev->minor); usb_set_intfdata(intf, ov); if (ov_create_sysfs(ov->vdev)) { err("ov_create_sysfs failed"); + ov511_devused &= ~(1 << nr); + mutex_unlock(&ov->lock); goto error; } + mutex_lock(&ov->lock); + return 0; error: @@ -5906,10 +5914,16 @@ ov51x_disconnect(struct usb_interface *intf) PDEBUG(3, ""); + mutex_lock(&ov->lock); usb_set_intfdata (intf, NULL); - if (!ov) + if (!ov) { + mutex_unlock(&ov->lock); return; + } + + /* Free device number */ + ov511_devused &= ~(1 << ov->nr); if (ov->vdev) video_unregister_device(ov->vdev); @@ -5927,6 +5941,7 @@ ov51x_disconnect(struct usb_interface *intf) ov->streaming = 0; ov51x_unlink_isoc(ov); + mutex_unlock(&ov->lock); ov->dev = NULL; diff --git a/drivers/media/video/ov511.h b/drivers/media/video/ov511.h index 70d99e52329d..c450c92468da 100644 --- a/drivers/media/video/ov511.h +++ b/drivers/media/video/ov511.h @@ -494,6 +494,9 @@ struct usb_ov511 { int has_decoder; /* Device has a video decoder */ int pal; /* Device is designed for PAL resolution */ + /* ov511 device number ID */ + int nr; /* Stores a device number */ + /* I2C interface */ struct mutex i2c_lock; /* Protect I2C controller regs */ unsigned char primary_i2c_slave; /* I2C write id of sensor */ diff --git a/drivers/media/video/ov772x.c b/drivers/media/video/ov772x.c index c0d911252862..0bce255168bd 100644 --- a/drivers/media/video/ov772x.c +++ b/drivers/media/video/ov772x.c @@ -1067,10 +1067,12 @@ static int ov772x_probe(struct i2c_client *client, struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); int ret; - info = client->dev.platform_data; - if (!info) + if (!client->dev.platform_data) return -EINVAL; + info = container_of(client->dev.platform_data, + struct ov772x_camera_info, link); + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { dev_err(&adapter->dev, "I2C-Adapter doesn't support " diff --git a/drivers/media/video/pvrusb2/pvrusb2-audio.c b/drivers/media/video/pvrusb2/pvrusb2-audio.c index 10ef1a2c13ea..416933ca607d 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-audio.c +++ b/drivers/media/video/pvrusb2/pvrusb2-audio.c @@ -48,11 +48,13 @@ static const int routing_scheme0[] = { MSP_DSP_IN_SCART), }; -static const struct routing_scheme routing_schemes[] = { - [PVR2_ROUTING_SCHEME_HAUPPAUGE] = { - .def = routing_scheme0, - .cnt = ARRAY_SIZE(routing_scheme0), - }, +static const struct routing_scheme routing_def0 = { + .def = routing_scheme0, + .cnt = ARRAY_SIZE(routing_scheme0), +}; + +static const struct routing_scheme *routing_schemes[] = { + [PVR2_ROUTING_SCHEME_HAUPPAUGE] = &routing_def0, }; void pvr2_msp3400_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd) @@ -65,7 +67,7 @@ void pvr2_msp3400_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd) pvr2_trace(PVR2_TRACE_CHIPS, "subdev msp3400 v4l2 set_stereo"); if ((sid < ARRAY_SIZE(routing_schemes)) && - ((sp = routing_schemes + sid) != NULL) && + ((sp = routing_schemes[sid]) != NULL) && (hdw->input_val >= 0) && (hdw->input_val < sp->cnt)) { input = sp->def[hdw->input_val]; diff --git a/drivers/media/video/pvrusb2/pvrusb2-cs53l32a.c b/drivers/media/video/pvrusb2/pvrusb2-cs53l32a.c index 9023adf3fdcc..68980e19409f 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-cs53l32a.c +++ b/drivers/media/video/pvrusb2/pvrusb2-cs53l32a.c @@ -49,11 +49,13 @@ static const int routing_scheme1[] = { [PVR2_CVAL_INPUT_SVIDEO] = 0, }; -static const struct routing_scheme routing_schemes[] = { - [PVR2_ROUTING_SCHEME_ONAIR] = { - .def = routing_scheme1, - .cnt = ARRAY_SIZE(routing_scheme1), - }, +static const struct routing_scheme routing_def1 = { + .def = routing_scheme1, + .cnt = ARRAY_SIZE(routing_scheme1), +}; + +static const struct routing_scheme *routing_schemes[] = { + [PVR2_ROUTING_SCHEME_ONAIR] = &routing_def1, }; @@ -65,12 +67,11 @@ void pvr2_cs53l32a_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd) u32 input; pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 set_input(%d)", hdw->input_val); - if ((sid < ARRAY_SIZE(routing_schemes)) && - ((sp = routing_schemes + sid) != NULL) && - (hdw->input_val >= 0) && - (hdw->input_val < sp->cnt)) { - input = sp->def[hdw->input_val]; - } else { + sp = (sid < ARRAY_SIZE(routing_schemes)) ? + routing_schemes[sid] : NULL; + if ((sp == NULL) || + (hdw->input_val < 0) || + (hdw->input_val >= sp->cnt)) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, "*** WARNING *** subdev v4l2 set_input:" " Invalid routing scheme (%u)" @@ -78,6 +79,7 @@ void pvr2_cs53l32a_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd) sid, hdw->input_val); return; } + input = sp->def[hdw->input_val]; sd->ops->audio->s_routing(sd, input, 0, 0); } } diff --git a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c index 05e52358ae49..82c135835753 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c +++ b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c @@ -68,6 +68,11 @@ static const struct routing_scheme_item routing_scheme0[] = { }, }; +static const struct routing_scheme routing_def0 = { + .def = routing_scheme0, + .cnt = ARRAY_SIZE(routing_scheme0), +}; + /* Specific to gotview device */ static const struct routing_scheme_item routing_schemegv[] = { [PVR2_CVAL_INPUT_TV] = { @@ -90,15 +95,14 @@ static const struct routing_scheme_item routing_schemegv[] = { }, }; -static const struct routing_scheme routing_schemes[] = { - [PVR2_ROUTING_SCHEME_HAUPPAUGE] = { - .def = routing_scheme0, - .cnt = ARRAY_SIZE(routing_scheme0), - }, - [PVR2_ROUTING_SCHEME_GOTVIEW] = { - .def = routing_schemegv, - .cnt = ARRAY_SIZE(routing_schemegv), - }, +static const struct routing_scheme routing_defgv = { + .def = routing_schemegv, + .cnt = ARRAY_SIZE(routing_schemegv), +}; + +static const struct routing_scheme *routing_schemes[] = { + [PVR2_ROUTING_SCHEME_HAUPPAUGE] = &routing_def0, + [PVR2_ROUTING_SCHEME_GOTVIEW] = &routing_defgv, }; void pvr2_cx25840_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd) @@ -110,13 +114,11 @@ void pvr2_cx25840_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd) const struct routing_scheme *sp; unsigned int sid = hdw->hdw_desc->signal_routing_scheme; - if ((sid < ARRAY_SIZE(routing_schemes)) && - ((sp = routing_schemes + sid) != NULL) && - (hdw->input_val >= 0) && - (hdw->input_val < sp->cnt)) { - vid_input = sp->def[hdw->input_val].vid; - aud_input = sp->def[hdw->input_val].aud; - } else { + sp = (sid < ARRAY_SIZE(routing_schemes)) ? + routing_schemes[sid] : NULL; + if ((sp == NULL) || + (hdw->input_val < 0) || + (hdw->input_val >= sp->cnt)) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, "*** WARNING *** subdev cx2584x set_input:" " Invalid routing scheme (%u)" @@ -124,7 +126,8 @@ void pvr2_cx25840_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd) sid, hdw->input_val); return; } - + vid_input = sp->def[hdw->input_val].vid; + aud_input = sp->def[hdw->input_val].aud; pvr2_trace(PVR2_TRACE_CHIPS, "subdev cx2584x set_input vid=0x%x aud=0x%x", vid_input, aud_input); diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/drivers/media/video/pvrusb2/pvrusb2-devattr.c index 1cb6a260e8b0..336a20eded0f 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-devattr.c +++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.c @@ -71,6 +71,7 @@ static const struct pvr2_device_desc pvr2_device_29xxx = { .flag_has_svideo = !0, .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE, .led_scheme = PVR2_LED_SCHEME_HAUPPAUGE, + .ir_scheme = PVR2_IR_SCHEME_29XXX, }; @@ -284,6 +285,11 @@ static struct tda10048_config hauppauge_tda10048_config = { .output_mode = TDA10048_PARALLEL_OUTPUT, .fwbulkwritelen = TDA10048_BULKWRITE_50, .inversion = TDA10048_INVERSION_ON, + .dtv6_if_freq_khz = TDA10048_IF_3300, + .dtv7_if_freq_khz = TDA10048_IF_3800, + .dtv8_if_freq_khz = TDA10048_IF_4300, + .clk_freq_khz = TDA10048_CLK_16000, + .disable_gate_access = 1, }; static struct tda829x_config tda829x_no_probe = { diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.h b/drivers/media/video/pvrusb2/pvrusb2-devattr.h index 3e553389cbc3..ea04ecf8aa39 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-devattr.h +++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.h @@ -69,6 +69,7 @@ struct pvr2_string_table { #define PVR2_ROUTING_SCHEME_HAUPPAUGE 0 #define PVR2_ROUTING_SCHEME_GOTVIEW 1 #define PVR2_ROUTING_SCHEME_ONAIR 2 +#define PVR2_ROUTING_SCHEME_AV400 3 #define PVR2_DIGITAL_SCHEME_NONE 0 #define PVR2_DIGITAL_SCHEME_HAUPPAUGE 1 @@ -78,8 +79,10 @@ struct pvr2_string_table { #define PVR2_LED_SCHEME_HAUPPAUGE 1 #define PVR2_IR_SCHEME_NONE 0 -#define PVR2_IR_SCHEME_24XXX 1 -#define PVR2_IR_SCHEME_ZILOG 2 +#define PVR2_IR_SCHEME_24XXX 1 /* FX2-controlled IR */ +#define PVR2_IR_SCHEME_ZILOG 2 /* HVR-1950 style (must be taken out of reset) */ +#define PVR2_IR_SCHEME_24XXX_MCE 3 /* 24xxx MCE device */ +#define PVR2_IR_SCHEME_29XXX 4 /* Original 29xxx device */ /* This describes a particular hardware type (except for the USB device ID which must live in a separate structure due to environmental @@ -162,19 +165,9 @@ struct pvr2_device_desc { ensure that it is found. */ unsigned int flag_has_wm8775:1; - /* Indicate any specialized IR scheme that might need to be - supported by this driver. If not set, then it is assumed that - IR can work without help from the driver (which is frequently - the case). This is otherwise set to one of - PVR2_IR_SCHEME_xxxx. For "xxxx", the value "24XXX" indicates a - Hauppauge 24xxx class device which has an FPGA-hosted IR - receiver that can only be reached via FX2 command codes. In - that case the pvrusb2 driver will emulate the behavior of the - older 29xxx device's IR receiver (a "virtual" I2C chip) in terms - of those command codes. For the value "ZILOG", we're dealing - with an IR chip that must be taken out of reset via another FX2 - command code (which is the case for HVR-1950 devices). */ - unsigned int ir_scheme:2; + /* Indicate IR scheme of hardware. If not set, then it is assumed + that IR can work without any help from the driver. */ + unsigned int ir_scheme:3; /* These bits define which kinds of sources the device can handle. Note: Digital tuner presence is inferred by the diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h index 5d75eb5211b1..5b152ff20bd0 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h @@ -200,6 +200,9 @@ struct pvr2_hdw { int i2c_cx25840_hack_state; int i2c_linked; + /* IR related */ + unsigned int ir_scheme_active; /* IR scheme as seen from the outside */ + /* Frequency table */ unsigned int freqTable[FREQTABLE_SIZE]; unsigned int freqProgSlot; diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index add3395d3248..cbc388729d77 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -85,8 +85,8 @@ 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; +/* US Broadcast channel 3 (61.25 MHz), to help with testing */ +static int default_tv_freq = 61250000L; /* 104.3 MHz, a usable FM station for my area */ static int default_radio_freq = 104300000L; @@ -142,6 +142,15 @@ static const unsigned char *module_i2c_addresses[] = { }; +static const char *ir_scheme_names[] = { + [PVR2_IR_SCHEME_NONE] = "none", + [PVR2_IR_SCHEME_29XXX] = "29xxx", + [PVR2_IR_SCHEME_24XXX] = "24xxx (29xxx emulation)", + [PVR2_IR_SCHEME_24XXX_MCE] = "24xxx (MCE device)", + [PVR2_IR_SCHEME_ZILOG] = "Zilog", +}; + + /* Define the list of additional controls we'll dynamically construct based on query of the cx2341x module. */ struct pvr2_mpeg_ids { @@ -1978,6 +1987,34 @@ static unsigned int pvr2_copy_i2c_addr_list( } +static void pvr2_hdw_cx25840_vbi_hack(struct pvr2_hdw *hdw) +{ + /* + Mike Isely 19-Nov-2006 - This bit of nuttiness + for cx25840 causes that module to correctly set up its video + scaling. This is really a problem in the cx25840 module itself, + but we work around it here. The problem has not been seen in + ivtv because there VBI is supported and set up. We don't do VBI + here (at least not yet) and thus we never attempted to even set + it up. + */ + struct v4l2_format fmt; + if (hdw->decoder_client_id != PVR2_CLIENT_ID_CX25840) { + /* We're not using a cx25840 so don't enable the hack */ + return; + } + + pvr2_trace(PVR2_TRACE_INIT, + "Module ID %u:" + " Executing cx25840 VBI hack", + hdw->decoder_client_id); + memset(&fmt, 0, sizeof(fmt)); + fmt.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE; + v4l2_device_call_all(&hdw->v4l2_dev, hdw->decoder_client_id, + video, s_fmt, &fmt); +} + + static int pvr2_hdw_load_subdev(struct pvr2_hdw *hdw, const struct pvr2_device_client_desc *cd) { @@ -2069,30 +2106,6 @@ static int pvr2_hdw_load_subdev(struct pvr2_hdw *hdw, /* client-specific setup... */ switch (mid) { case PVR2_CLIENT_ID_CX25840: - hdw->decoder_client_id = mid; - { - /* - Mike Isely 19-Nov-2006 - This - bit of nuttiness for cx25840 causes that module - to correctly set up its video scaling. This is - really a problem in the cx25840 module itself, - but we work around it here. The problem has not - been seen in ivtv because there VBI is supported - and set up. We don't do VBI here (at least not - yet) and thus we never attempted to even set it - up. - */ - struct v4l2_format fmt; - pvr2_trace(PVR2_TRACE_INIT, - "Module ID %u:" - " Executing cx25840 VBI hack", - mid); - memset(&fmt, 0, sizeof(fmt)); - fmt.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE; - v4l2_device_call_all(&hdw->v4l2_dev, mid, - video, s_fmt, &fmt); - } - break; case PVR2_CLIENT_ID_SAA7115: hdw->decoder_client_id = mid; break; @@ -2170,7 +2183,7 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw) } /* Take the IR chip out of reset, if appropriate */ - if (hdw->hdw_desc->ir_scheme == PVR2_IR_SCHEME_ZILOG) { + if (hdw->ir_scheme_active == PVR2_IR_SCHEME_ZILOG) { pvr2_issue_simple_cmd(hdw, FX2CMD_HCW_ZILOG_RESET | (1 << 8) | @@ -2193,6 +2206,8 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw) cptr->info->set_value(cptr,~0,cptr->info->default_value); } + pvr2_hdw_cx25840_vbi_hack(hdw); + /* Set up special default values for the television and radio frequencies here. It's not really important what these defaults are, but I set them to something usable in the Chicago area just @@ -2451,6 +2466,7 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, GFP_KERNEL); if (!hdw->controls) goto fail; hdw->hdw_desc = hdw_desc; + hdw->ir_scheme_active = hdw->hdw_desc->ir_scheme; for (idx = 0; idx < hdw->control_cnt; idx++) { cptr = hdw->controls + idx; cptr->hdw = hdw; @@ -2944,6 +2960,7 @@ static void pvr2_subdev_update(struct pvr2_hdw *hdw) vs = hdw->std_mask_cur; v4l2_device_call_all(&hdw->v4l2_dev, 0, core, s_std, vs); + pvr2_hdw_cx25840_vbi_hack(hdw); } hdw->tuner_signal_stale = !0; hdw->cropcap_stale = !0; @@ -4066,6 +4083,7 @@ int pvr2_hdw_cmd_decoder_reset(struct pvr2_hdw *hdw) if (hdw->decoder_client_id) { v4l2_device_call_all(&hdw->v4l2_dev, hdw->decoder_client_id, core, reset, 0); + pvr2_hdw_cx25840_vbi_hack(hdw); return 0; } pvr2_trace(PVR2_TRACE_INIT, @@ -4809,6 +4827,12 @@ static unsigned int pvr2_hdw_report_unlocked(struct pvr2_hdw *hdw,int which, stats.buffers_processed, stats.buffers_failed); } + case 6: { + unsigned int id = hdw->ir_scheme_active; + return scnprintf(buf, acnt, "ir scheme: id=%d %s", id, + (id >= ARRAY_SIZE(ir_scheme_names) ? + "?" : ir_scheme_names[id])); + } default: break; } return 0; @@ -4825,65 +4849,35 @@ static unsigned int pvr2_hdw_report_clients(struct pvr2_hdw *hdw, unsigned int tcnt = 0; unsigned int ccnt; struct i2c_client *client; - struct list_head *item; - void *cd; const char *p; unsigned int id; - ccnt = scnprintf(buf, acnt, "Associated v4l2-subdev drivers:"); + ccnt = scnprintf(buf, acnt, "Associated v4l2-subdev drivers and I2C clients:\n"); tcnt += ccnt; v4l2_device_for_each_subdev(sd, &hdw->v4l2_dev) { id = sd->grp_id; p = NULL; if (id < ARRAY_SIZE(module_names)) p = module_names[id]; if (p) { - ccnt = scnprintf(buf + tcnt, acnt - tcnt, " %s", p); + ccnt = scnprintf(buf + tcnt, acnt - tcnt, " %s:", p); tcnt += ccnt; } else { ccnt = scnprintf(buf + tcnt, acnt - tcnt, - " (unknown id=%u)", id); + " (unknown id=%u):", id); + tcnt += ccnt; + } + client = v4l2_get_subdevdata(sd); + if (client) { + ccnt = scnprintf(buf + tcnt, acnt - tcnt, + " %s @ %02x\n", client->name, + client->addr); + tcnt += ccnt; + } else { + ccnt = scnprintf(buf + tcnt, acnt - tcnt, + " no i2c client\n"); tcnt += ccnt; } } - ccnt = scnprintf(buf + tcnt, acnt - tcnt, "\n"); - tcnt += ccnt; - - ccnt = scnprintf(buf + tcnt, acnt - tcnt, "I2C clients:\n"); - tcnt += ccnt; - - mutex_lock(&hdw->i2c_adap.clist_lock); - list_for_each(item, &hdw->i2c_adap.clients) { - client = list_entry(item, struct i2c_client, list); - ccnt = scnprintf(buf + tcnt, acnt - tcnt, - " %s: i2c=%02x", client->name, client->addr); - tcnt += ccnt; - cd = i2c_get_clientdata(client); - v4l2_device_for_each_subdev(sd, &hdw->v4l2_dev) { - if (cd == sd) { - id = sd->grp_id; - p = NULL; - if (id < ARRAY_SIZE(module_names)) { - p = module_names[id]; - } - if (p) { - ccnt = scnprintf(buf + tcnt, - acnt - tcnt, - " subdev=%s", p); - tcnt += ccnt; - } else { - ccnt = scnprintf(buf + tcnt, - acnt - tcnt, - " subdev= id %u)", - id); - tcnt += ccnt; - } - break; - } - } - ccnt = scnprintf(buf + tcnt, acnt - tcnt, "\n"); - tcnt += ccnt; - } - mutex_unlock(&hdw->i2c_adap.clist_lock); return tcnt; } diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c index 9af282f9e765..610bd848df24 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c +++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c @@ -42,6 +42,18 @@ static int ir_mode[PVR_NUM] = { [0 ... PVR_NUM-1] = 1 }; module_param_array(ir_mode, int, NULL, 0444); MODULE_PARM_DESC(ir_mode,"specify: 0=disable IR reception, 1=normal IR"); +static int pvr2_disable_ir_video; +module_param_named(disable_autoload_ir_video, pvr2_disable_ir_video, + int, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(disable_autoload_ir_video, + "1=do not try to autoload ir_video IR receiver"); + +/* Mapping of IR schemes to known I2C addresses - if any */ +static const unsigned char ir_video_addresses[] = { + [PVR2_IR_SCHEME_29XXX] = 0x18, + [PVR2_IR_SCHEME_24XXX] = 0x18, +}; + static int pvr2_i2c_write(struct pvr2_hdw *hdw, /* Context */ u8 i2c_addr, /* I2C address we're talking to */ u8 *data, /* Data to write */ @@ -559,6 +571,31 @@ static void do_i2c_scan(struct pvr2_hdw *hdw) printk(KERN_INFO "%s: i2c scan done.\n", hdw->name); } +static void pvr2_i2c_register_ir(struct pvr2_hdw *hdw) +{ + struct i2c_board_info info; + unsigned char addr = 0; + if (pvr2_disable_ir_video) { + pvr2_trace(PVR2_TRACE_INFO, + "Automatic binding of ir_video has been disabled."); + return; + } + if (hdw->ir_scheme_active < ARRAY_SIZE(ir_video_addresses)) { + addr = ir_video_addresses[hdw->ir_scheme_active]; + } + if (!addr) { + /* The device either doesn't support I2C-based IR or we + don't know (yet) how to operate IR on the device. */ + return; + } + pvr2_trace(PVR2_TRACE_INFO, + "Binding ir_video to i2c address 0x%02x.", addr); + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "ir_video", I2C_NAME_SIZE); + info.addr = addr; + i2c_new_device(&hdw->i2c_adap, &info); +} + void pvr2_i2c_core_init(struct pvr2_hdw *hdw) { unsigned int idx; @@ -574,7 +611,9 @@ void pvr2_i2c_core_init(struct pvr2_hdw *hdw) printk(KERN_INFO "%s: IR disabled\n",hdw->name); hdw->i2c_func[0x18] = i2c_black_hole; } else if (ir_mode[hdw->unit_number] == 1) { - if (hdw->hdw_desc->ir_scheme == PVR2_IR_SCHEME_24XXX) { + if (hdw->ir_scheme_active == PVR2_IR_SCHEME_24XXX) { + /* Set up translation so that our IR looks like a + 29xxx device */ hdw->i2c_func[0x18] = i2c_24xxx_ir; } } @@ -597,15 +636,23 @@ void pvr2_i2c_core_init(struct pvr2_hdw *hdw) i2c_add_adapter(&hdw->i2c_adap); if (hdw->i2c_func[0x18] == i2c_24xxx_ir) { /* Probe for a different type of IR receiver on this - device. If present, disable the emulated IR receiver. */ + device. This is really the only way to differentiate + older 24xxx devices from 24xxx variants that include an + IR blaster. If the IR blaster is present, the IR + receiver is part of that chip and thus we must disable + the emulated IR receiver. */ if (do_i2c_probe(hdw, 0x71)) { pvr2_trace(PVR2_TRACE_INFO, "Device has newer IR hardware;" " disabling unneeded virtual IR device"); hdw->i2c_func[0x18] = NULL; + /* Remember that this is a different device... */ + hdw->ir_scheme_active = PVR2_IR_SCHEME_24XXX_MCE; } } if (i2c_scan) do_i2c_scan(hdw); + + pvr2_i2c_register_ir(hdw); } void pvr2_i2c_core_done(struct pvr2_hdw *hdw) diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c index 299c1cbc3832..6c23456e0bda 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c +++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c @@ -539,7 +539,7 @@ static void class_dev_destroy(struct pvr2_sysfs *sfp) &sfp->attr_unit_number); } pvr2_sysfs_trace("Destroying class_dev id=%p",sfp->class_dev); - sfp->class_dev->driver_data = NULL; + dev_set_drvdata(sfp->class_dev, NULL); device_unregister(sfp->class_dev); sfp->class_dev = NULL; } @@ -549,7 +549,7 @@ static ssize_t v4l_minor_number_show(struct device *class_dev, struct device_attribute *attr, char *buf) { struct pvr2_sysfs *sfp; - sfp = (struct pvr2_sysfs *)class_dev->driver_data; + sfp = dev_get_drvdata(class_dev); if (!sfp) return -EINVAL; return scnprintf(buf,PAGE_SIZE,"%d\n", pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw, @@ -561,7 +561,7 @@ static ssize_t bus_info_show(struct device *class_dev, struct device_attribute *attr, char *buf) { struct pvr2_sysfs *sfp; - sfp = (struct pvr2_sysfs *)class_dev->driver_data; + sfp = dev_get_drvdata(class_dev); if (!sfp) return -EINVAL; return scnprintf(buf,PAGE_SIZE,"%s\n", pvr2_hdw_get_bus_info(sfp->channel.hdw)); @@ -572,7 +572,7 @@ static ssize_t hdw_name_show(struct device *class_dev, struct device_attribute *attr, char *buf) { struct pvr2_sysfs *sfp; - sfp = (struct pvr2_sysfs *)class_dev->driver_data; + sfp = dev_get_drvdata(class_dev); if (!sfp) return -EINVAL; return scnprintf(buf,PAGE_SIZE,"%s\n", pvr2_hdw_get_type(sfp->channel.hdw)); @@ -583,7 +583,7 @@ static ssize_t hdw_desc_show(struct device *class_dev, struct device_attribute *attr, char *buf) { struct pvr2_sysfs *sfp; - sfp = (struct pvr2_sysfs *)class_dev->driver_data; + sfp = dev_get_drvdata(class_dev); if (!sfp) return -EINVAL; return scnprintf(buf,PAGE_SIZE,"%s\n", pvr2_hdw_get_desc(sfp->channel.hdw)); @@ -595,7 +595,7 @@ static ssize_t v4l_radio_minor_number_show(struct device *class_dev, char *buf) { struct pvr2_sysfs *sfp; - sfp = (struct pvr2_sysfs *)class_dev->driver_data; + sfp = dev_get_drvdata(class_dev); if (!sfp) return -EINVAL; return scnprintf(buf,PAGE_SIZE,"%d\n", pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw, @@ -607,7 +607,7 @@ static ssize_t unit_number_show(struct device *class_dev, struct device_attribute *attr, char *buf) { struct pvr2_sysfs *sfp; - sfp = (struct pvr2_sysfs *)class_dev->driver_data; + sfp = dev_get_drvdata(class_dev); if (!sfp) return -EINVAL; return scnprintf(buf,PAGE_SIZE,"%d\n", pvr2_hdw_get_unit_number(sfp->channel.hdw)); @@ -635,7 +635,7 @@ static void class_dev_create(struct pvr2_sysfs *sfp, class_dev->parent = &usb_dev->dev; sfp->class_dev = class_dev; - class_dev->driver_data = sfp; + dev_set_drvdata(class_dev, sfp); ret = device_register(class_dev); if (ret) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, @@ -792,7 +792,7 @@ static ssize_t debuginfo_show(struct device *class_dev, struct device_attribute *attr, char *buf) { struct pvr2_sysfs *sfp; - sfp = (struct pvr2_sysfs *)class_dev->driver_data; + sfp = dev_get_drvdata(class_dev); if (!sfp) return -EINVAL; pvr2_hdw_trigger_module_log(sfp->channel.hdw); return pvr2_debugifc_print_info(sfp->channel.hdw,buf,PAGE_SIZE); @@ -803,7 +803,7 @@ static ssize_t debugcmd_show(struct device *class_dev, struct device_attribute *attr, char *buf) { struct pvr2_sysfs *sfp; - sfp = (struct pvr2_sysfs *)class_dev->driver_data; + sfp = dev_get_drvdata(class_dev); if (!sfp) return -EINVAL; return pvr2_debugifc_print_status(sfp->channel.hdw,buf,PAGE_SIZE); } @@ -816,7 +816,7 @@ static ssize_t debugcmd_store(struct device *class_dev, struct pvr2_sysfs *sfp; int ret; - sfp = (struct pvr2_sysfs *)class_dev->driver_data; + sfp = dev_get_drvdata(class_dev); if (!sfp) return -EINVAL; ret = pvr2_debugifc_docmd(sfp->channel.hdw,buf,count); diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c index 9e0f2b07b93b..2d8825e5b1be 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c @@ -90,7 +90,7 @@ static struct v4l2_capability pvr_capability ={ .driver = "pvrusb2", .card = "Hauppauge WinTV pvr-usb2", .bus_info = "usb", - .version = KERNEL_VERSION(0,8,0), + .version = KERNEL_VERSION(0, 9, 0), .capabilities = (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_RADIO | V4L2_CAP_READWRITE), @@ -267,7 +267,7 @@ static long pvr2_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) memset(&tmp,0,sizeof(tmp)); tmp.index = vi->index; ret = 0; - if ((vi->index < 0) || (vi->index >= fh->input_cnt)) { + if (vi->index >= fh->input_cnt) { ret = -EINVAL; break; } @@ -331,7 +331,7 @@ static long pvr2_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) case VIDIOC_S_INPUT: { struct v4l2_input *vi = (struct v4l2_input *)arg; - if ((vi->index < 0) || (vi->index >= fh->input_cnt)) { + if (vi->index >= fh->input_cnt) { ret = -ERANGE; break; } diff --git a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c index d2fe7c8f2c3a..4c96cf48c796 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c +++ b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c @@ -54,6 +54,11 @@ static const int routing_scheme0[] = { [PVR2_CVAL_INPUT_SVIDEO] = SAA7115_SVIDEO2, }; +static const struct routing_scheme routing_def0 = { + .def = routing_scheme0, + .cnt = ARRAY_SIZE(routing_scheme0), +}; + static const int routing_scheme1[] = { [PVR2_CVAL_INPUT_TV] = SAA7115_COMPOSITE4, [PVR2_CVAL_INPUT_RADIO] = SAA7115_COMPOSITE5, @@ -61,15 +66,14 @@ static const int routing_scheme1[] = { [PVR2_CVAL_INPUT_SVIDEO] = SAA7115_SVIDEO2, /* or SVIDEO0, it seems */ }; -static const struct routing_scheme routing_schemes[] = { - [PVR2_ROUTING_SCHEME_HAUPPAUGE] = { - .def = routing_scheme0, - .cnt = ARRAY_SIZE(routing_scheme0), - }, - [PVR2_ROUTING_SCHEME_ONAIR] = { - .def = routing_scheme1, - .cnt = ARRAY_SIZE(routing_scheme1), - }, +static const struct routing_scheme routing_def1 = { + .def = routing_scheme1, + .cnt = ARRAY_SIZE(routing_scheme1), +}; + +static const struct routing_scheme *routing_schemes[] = { + [PVR2_ROUTING_SCHEME_HAUPPAUGE] = &routing_def0, + [PVR2_ROUTING_SCHEME_ONAIR] = &routing_def1, }; void pvr2_saa7115_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd) @@ -81,12 +85,12 @@ void pvr2_saa7115_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd) pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 set_input(%d)", hdw->input_val); - if ((sid < ARRAY_SIZE(routing_schemes)) && - ((sp = routing_schemes + sid) != NULL) && - (hdw->input_val >= 0) && - (hdw->input_val < sp->cnt)) { - input = sp->def[hdw->input_val]; - } else { + + sp = (sid < ARRAY_SIZE(routing_schemes)) ? + routing_schemes[sid] : NULL; + if ((sp == NULL) || + (hdw->input_val < 0) || + (hdw->input_val >= sp->cnt)) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, "*** WARNING *** subdev v4l2 set_input:" " Invalid routing scheme (%u)" @@ -94,6 +98,7 @@ void pvr2_saa7115_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd) sid, hdw->input_val); return; } + input = sp->def[hdw->input_val]; sd->ops->video->s_routing(sd, input, 0, 0); } } diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index 7c542caf248e..db25c3034c11 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c @@ -601,7 +601,7 @@ static void pwc_snapshot_button(struct pwc_device *pdev, int down) #ifdef CONFIG_USB_PWC_INPUT_EVDEV if (pdev->button_dev) { - input_report_key(pdev->button_dev, BTN_0, down); + input_report_key(pdev->button_dev, KEY_CAMERA, down); input_sync(pdev->button_dev); } #endif @@ -1783,7 +1783,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id return -ENOMEM; } memcpy(pdev->vdev, &pwc_template, sizeof(pwc_template)); - pdev->vdev->parent = &(udev->dev); + pdev->vdev->parent = &intf->dev; strcpy(pdev->vdev->name, name); video_set_drvdata(pdev->vdev, pdev); @@ -1847,7 +1847,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id usb_to_input_id(pdev->udev, &pdev->button_dev->id); pdev->button_dev->dev.parent = &pdev->udev->dev; pdev->button_dev->evbit[0] = BIT_MASK(EV_KEY); - pdev->button_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0); + pdev->button_dev->keybit[BIT_WORD(KEY_CAMERA)] = BIT_MASK(KEY_CAMERA); rc = input_register_device(pdev->button_dev); if (rc) { diff --git a/drivers/media/video/pwc/pwc-v4l.c b/drivers/media/video/pwc/pwc-v4l.c index bc0a464295c5..2876ce084510 100644 --- a/drivers/media/video/pwc/pwc-v4l.c +++ b/drivers/media/video/pwc/pwc-v4l.c @@ -1107,7 +1107,7 @@ long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg) return -EINVAL; if (buf->memory != V4L2_MEMORY_MMAP) return -EINVAL; - if (buf->index < 0 || buf->index >= pwc_mbufs) + if (buf->index >= pwc_mbufs) return -EINVAL; buf->flags |= V4L2_BUF_FLAG_QUEUED; diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c index c639845460ff..46e0d8ad880f 100644 --- a/drivers/media/video/pxa_camera.c +++ b/drivers/media/video/pxa_camera.c @@ -162,13 +162,6 @@ CICR0_PERRM | CICR0_QDM | CICR0_CDM | CICR0_SOFM | \ CICR0_EOFM | CICR0_FOM) -/* - * YUV422P picture size should be a multiple of 16, so the heuristic aligns - * height, width on 4 byte boundaries to reach the 16 multiple for the size. - */ -#define YUV422P_X_Y_ALIGN 4 -#define YUV422P_SIZE_ALIGN YUV422P_X_Y_ALIGN * YUV422P_X_Y_ALIGN - /* * Structures */ @@ -202,7 +195,7 @@ struct pxa_buffer { }; struct pxa_camera_dev { - struct device *dev; + struct soc_camera_host soc_host; /* PXA27x is only supposed to handle one camera on its Quick Capture * interface. If anyone ever builds hardware to enable more than * one camera, they will have to modify this driver too */ @@ -261,7 +254,6 @@ static void free_buffer(struct videobuf_queue *vq, struct pxa_buffer *buf) { struct soc_camera_device *icd = vq->priv_data; struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct pxa_camera_dev *pcdev = ici->priv; struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); int i; @@ -278,7 +270,7 @@ static void free_buffer(struct videobuf_queue *vq, struct pxa_buffer *buf) for (i = 0; i < ARRAY_SIZE(buf->dmas); i++) { if (buf->dmas[i].sg_cpu) - dma_free_coherent(pcdev->dev, buf->dmas[i].sg_size, + dma_free_coherent(ici->dev, buf->dmas[i].sg_size, buf->dmas[i].sg_cpu, buf->dmas[i].sg_dma); buf->dmas[i].sg_cpu = NULL; @@ -338,14 +330,14 @@ static int pxa_init_dma_channel(struct pxa_camera_dev *pcdev, int dma_len = 0, xfer_len = 0; if (pxa_dma->sg_cpu) - dma_free_coherent(pcdev->dev, pxa_dma->sg_size, + dma_free_coherent(pcdev->soc_host.dev, pxa_dma->sg_size, pxa_dma->sg_cpu, pxa_dma->sg_dma); sglen = calculate_dma_sglen(*sg_first, dma->sglen, *sg_first_ofs, size); pxa_dma->sg_size = (sglen + 1) * sizeof(struct pxa_dma_desc); - pxa_dma->sg_cpu = dma_alloc_coherent(pcdev->dev, pxa_dma->sg_size, + pxa_dma->sg_cpu = dma_alloc_coherent(pcdev->soc_host.dev, pxa_dma->sg_size, &pxa_dma->sg_dma, GFP_KERNEL); if (!pxa_dma->sg_cpu) return -ENOMEM; @@ -353,7 +345,7 @@ static int pxa_init_dma_channel(struct pxa_camera_dev *pcdev, pxa_dma->sglen = sglen; offset = *sg_first_ofs; - dev_dbg(pcdev->dev, "DMA: sg_first=%p, sglen=%d, ofs=%d, dma.desc=%x\n", + dev_dbg(pcdev->soc_host.dev, "DMA: sg_first=%p, sglen=%d, ofs=%d, dma.desc=%x\n", *sg_first, sglen, *sg_first_ofs, pxa_dma->sg_dma); @@ -376,7 +368,7 @@ static int pxa_init_dma_channel(struct pxa_camera_dev *pcdev, pxa_dma->sg_cpu[i].ddadr = pxa_dma->sg_dma + (i + 1) * sizeof(struct pxa_dma_desc); - dev_vdbg(pcdev->dev, "DMA: desc.%08x->@phys=0x%08x, len=%d\n", + dev_vdbg(pcdev->soc_host.dev, "DMA: desc.%08x->@phys=0x%08x, len=%d\n", pxa_dma->sg_dma + i * sizeof(struct pxa_dma_desc), sg_dma_address(sg) + offset, xfer_len); offset = 0; @@ -488,7 +480,7 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq, ret = pxa_init_dma_channel(pcdev, buf, dma, 0, CIBR0, size_y, &sg, &next_ofs); if (ret) { - dev_err(pcdev->dev, + dev_err(pcdev->soc_host.dev, "DMA initialization for Y/RGB failed\n"); goto fail; } @@ -498,7 +490,7 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq, ret = pxa_init_dma_channel(pcdev, buf, dma, 1, CIBR1, size_u, &sg, &next_ofs); if (ret) { - dev_err(pcdev->dev, + dev_err(pcdev->soc_host.dev, "DMA initialization for U failed\n"); goto fail_u; } @@ -508,7 +500,7 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq, ret = pxa_init_dma_channel(pcdev, buf, dma, 2, CIBR2, size_v, &sg, &next_ofs); if (ret) { - dev_err(pcdev->dev, + dev_err(pcdev->soc_host.dev, "DMA initialization for V failed\n"); goto fail_v; } @@ -522,10 +514,10 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq, return 0; fail_v: - dma_free_coherent(pcdev->dev, buf->dmas[1].sg_size, + dma_free_coherent(pcdev->soc_host.dev, buf->dmas[1].sg_size, buf->dmas[1].sg_cpu, buf->dmas[1].sg_dma); fail_u: - dma_free_coherent(pcdev->dev, buf->dmas[0].sg_size, + dma_free_coherent(pcdev->soc_host.dev, buf->dmas[0].sg_size, buf->dmas[0].sg_cpu, buf->dmas[0].sg_dma); fail: free_buffer(vq, buf); @@ -549,7 +541,7 @@ static void pxa_dma_start_channels(struct pxa_camera_dev *pcdev) active = pcdev->active; for (i = 0; i < pcdev->channels; i++) { - dev_dbg(pcdev->dev, "%s (channel=%d) ddadr=%08x\n", __func__, + dev_dbg(pcdev->soc_host.dev, "%s (channel=%d) ddadr=%08x\n", __func__, i, active->dmas[i].sg_dma); DDADR(pcdev->dma_chans[i]) = active->dmas[i].sg_dma; DCSR(pcdev->dma_chans[i]) = DCSR_RUN; @@ -561,7 +553,7 @@ static void pxa_dma_stop_channels(struct pxa_camera_dev *pcdev) int i; for (i = 0; i < pcdev->channels; i++) { - dev_dbg(pcdev->dev, "%s (channel=%d)\n", __func__, i); + dev_dbg(pcdev->soc_host.dev, "%s (channel=%d)\n", __func__, i); DCSR(pcdev->dma_chans[i]) = 0; } } @@ -597,7 +589,7 @@ static void pxa_camera_start_capture(struct pxa_camera_dev *pcdev) { unsigned long cicr0, cifr; - dev_dbg(pcdev->dev, "%s\n", __func__); + dev_dbg(pcdev->soc_host.dev, "%s\n", __func__); /* Reset the FIFOs */ cifr = __raw_readl(pcdev->base + CIFR) | CIFR_RESET_F; __raw_writel(cifr, pcdev->base + CIFR); @@ -617,7 +609,7 @@ static void pxa_camera_stop_capture(struct pxa_camera_dev *pcdev) __raw_writel(cicr0, pcdev->base + CICR0); pcdev->active = NULL; - dev_dbg(pcdev->dev, "%s\n", __func__); + dev_dbg(pcdev->soc_host.dev, "%s\n", __func__); } static void pxa_videobuf_queue(struct videobuf_queue *vq, @@ -686,7 +678,7 @@ static void pxa_camera_wakeup(struct pxa_camera_dev *pcdev, do_gettimeofday(&vb->ts); vb->field_count++; wake_up(&vb->done); - dev_dbg(pcdev->dev, "%s dequeud buffer (vb=0x%p)\n", __func__, vb); + dev_dbg(pcdev->soc_host.dev, "%s dequeud buffer (vb=0x%p)\n", __func__, vb); if (list_empty(&pcdev->capture)) { pxa_camera_stop_capture(pcdev); @@ -722,7 +714,7 @@ static void pxa_camera_check_link_miss(struct pxa_camera_dev *pcdev) for (i = 0; i < pcdev->channels; i++) if (DDADR(pcdev->dma_chans[i]) != DDADR_STOP) is_dma_stopped = 0; - dev_dbg(pcdev->dev, "%s : top queued buffer=%p, dma_stopped=%d\n", + dev_dbg(pcdev->soc_host.dev, "%s : top queued buffer=%p, dma_stopped=%d\n", __func__, pcdev->active, is_dma_stopped); if (pcdev->active && is_dma_stopped) pxa_camera_start_capture(pcdev); @@ -747,12 +739,12 @@ static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev, overrun |= CISR_IFO_1 | CISR_IFO_2; if (status & DCSR_BUSERR) { - dev_err(pcdev->dev, "DMA Bus Error IRQ!\n"); + dev_err(pcdev->soc_host.dev, "DMA Bus Error IRQ!\n"); goto out; } if (!(status & (DCSR_ENDINTR | DCSR_STARTINTR))) { - dev_err(pcdev->dev, "Unknown DMA IRQ source, " + dev_err(pcdev->soc_host.dev, "Unknown DMA IRQ source, " "status: 0x%08x\n", status); goto out; } @@ -776,7 +768,7 @@ static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev, buf = container_of(vb, struct pxa_buffer, vb); WARN_ON(buf->inwork || list_empty(&vb->queue)); - dev_dbg(pcdev->dev, "%s channel=%d %s%s(vb=0x%p) dma.desc=%x\n", + dev_dbg(pcdev->soc_host.dev, "%s channel=%d %s%s(vb=0x%p) dma.desc=%x\n", __func__, channel, status & DCSR_STARTINTR ? "SOF " : "", status & DCSR_ENDINTR ? "EOF " : "", vb, DDADR(channel)); @@ -787,7 +779,7 @@ static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev, */ if (camera_status & overrun && !list_is_last(pcdev->capture.next, &pcdev->capture)) { - dev_dbg(pcdev->dev, "FIFO overrun! CISR: %x\n", + dev_dbg(pcdev->soc_host.dev, "FIFO overrun! CISR: %x\n", camera_status); pxa_camera_stop_capture(pcdev); pxa_camera_start_capture(pcdev); @@ -854,7 +846,7 @@ static u32 mclk_get_divisor(struct pxa_camera_dev *pcdev) /* mclk <= ciclk / 4 (27.4.2) */ if (mclk > lcdclk / 4) { mclk = lcdclk / 4; - dev_warn(pcdev->dev, "Limiting master clock to %lu\n", mclk); + dev_warn(pcdev->soc_host.dev, "Limiting master clock to %lu\n", mclk); } /* We verify mclk != 0, so if anyone breaks it, here comes their Oops */ @@ -864,7 +856,7 @@ static u32 mclk_get_divisor(struct pxa_camera_dev *pcdev) if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN) pcdev->mclk = lcdclk / (2 * (div + 1)); - dev_dbg(pcdev->dev, "LCD clock %luHz, target freq %luHz, " + dev_dbg(pcdev->soc_host.dev, "LCD clock %luHz, target freq %luHz, " "divisor %u\n", lcdclk, mclk, div); return div; @@ -884,12 +876,12 @@ static void pxa_camera_activate(struct pxa_camera_dev *pcdev) struct pxacamera_platform_data *pdata = pcdev->pdata; u32 cicr4 = 0; - dev_dbg(pcdev->dev, "Registered platform device at %p data %p\n", + dev_dbg(pcdev->soc_host.dev, "Registered platform device at %p data %p\n", pcdev, pdata); if (pdata && pdata->init) { - dev_dbg(pcdev->dev, "%s: Init gpios\n", __func__); - pdata->init(pcdev->dev); + dev_dbg(pcdev->soc_host.dev, "%s: Init gpios\n", __func__); + pdata->init(pcdev->soc_host.dev); } /* disable all interrupts */ @@ -931,7 +923,7 @@ static irqreturn_t pxa_camera_irq(int irq, void *data) struct videobuf_buffer *vb; status = __raw_readl(pcdev->base + CISR); - dev_dbg(pcdev->dev, "Camera interrupt status 0x%lx\n", status); + dev_dbg(pcdev->soc_host.dev, "Camera interrupt status 0x%lx\n", status); if (!status) return IRQ_NONE; @@ -1259,7 +1251,7 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx, xlate->cam_fmt = icd->formats + idx; xlate->buswidth = buswidth; xlate++; - dev_dbg(&ici->dev, "Providing format %s using %s\n", + dev_dbg(ici->dev, "Providing format %s using %s\n", pxa_camera_formats[0].name, icd->formats[idx].name); } @@ -1274,7 +1266,7 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx, xlate->cam_fmt = icd->formats + idx; xlate->buswidth = buswidth; xlate++; - dev_dbg(&ici->dev, "Providing format %s packed\n", + dev_dbg(ici->dev, "Providing format %s packed\n", icd->formats[idx].name); } break; @@ -1286,7 +1278,7 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx, xlate->cam_fmt = icd->formats + idx; xlate->buswidth = icd->formats[idx].depth; xlate++; - dev_dbg(&ici->dev, + dev_dbg(ici->dev, "Providing format %s in pass-through mode\n", icd->formats[idx].name); } @@ -1315,11 +1307,11 @@ static int pxa_camera_set_crop(struct soc_camera_device *icd, icd->sense = NULL; if (ret < 0) { - dev_warn(&ici->dev, "Failed to crop to %ux%u@%u:%u\n", + dev_warn(ici->dev, "Failed to crop to %ux%u@%u:%u\n", rect->width, rect->height, rect->left, rect->top); } else if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) { if (sense.pixel_clock > sense.pixel_clock_max) { - dev_err(&ici->dev, + dev_err(ici->dev, "pixel clock %lu set by the camera too high!", sense.pixel_clock); return -EIO; @@ -1347,7 +1339,7 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd, xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); if (!xlate) { - dev_warn(&ici->dev, "Format %x not found\n", pix->pixelformat); + dev_warn(ici->dev, "Format %x not found\n", pix->pixelformat); return -EINVAL; } @@ -1363,11 +1355,11 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd, icd->sense = NULL; if (ret < 0) { - dev_warn(&ici->dev, "Failed to configure for format %x\n", + dev_warn(ici->dev, "Failed to configure for format %x\n", pix->pixelformat); } else if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) { if (sense.pixel_clock > sense.pixel_clock_max) { - dev_err(&ici->dev, + dev_err(ici->dev, "pixel clock %lu set by the camera too high!", sense.pixel_clock); return -EIO; @@ -1395,32 +1387,19 @@ static int pxa_camera_try_fmt(struct soc_camera_device *icd, xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); if (!xlate) { - dev_warn(&ici->dev, "Format %x not found\n", pixfmt); + dev_warn(ici->dev, "Format %x not found\n", pixfmt); return -EINVAL; } - /* limit to pxa hardware capabilities */ - if (pix->height < 32) - pix->height = 32; - if (pix->height > 2048) - pix->height = 2048; - if (pix->width < 48) - pix->width = 48; - if (pix->width > 2048) - pix->width = 2048; - pix->width &= ~0x01; - /* - * YUV422P planar format requires images size to be a 16 bytes - * multiple. If not, zeros will be inserted between Y and U planes, and - * U and V planes, and YUV422P standard would be violated. + * Limit to pxa hardware capabilities. YUV422P planar format requires + * images size to be a multiple of 16 bytes. If not, zeros will be + * inserted between Y and U planes, and U and V planes, which violates + * the YUV422P standard. */ - if (xlate->host_fmt->fourcc == V4L2_PIX_FMT_YUV422P) { - if (!IS_ALIGNED(pix->width * pix->height, YUV422P_SIZE_ALIGN)) - pix->height = ALIGN(pix->height, YUV422P_X_Y_ALIGN); - if (!IS_ALIGNED(pix->width * pix->height, YUV422P_SIZE_ALIGN)) - pix->width = ALIGN(pix->width, YUV422P_X_Y_ALIGN); - } + v4l_bound_align_image(&pix->width, 48, 2048, 1, + &pix->height, 32, 2048, 0, + xlate->host_fmt->fourcc == V4L2_PIX_FMT_YUV422P ? 4 : 0); pix->bytesperline = pix->width * DIV_ROUND_UP(xlate->host_fmt->depth, 8); @@ -1552,13 +1531,7 @@ static struct soc_camera_host_ops pxa_soc_camera_host_ops = { .set_bus_param = pxa_camera_set_bus_param, }; -/* 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, - .ops = &pxa_soc_camera_host_ops, -}; - -static int pxa_camera_probe(struct platform_device *pdev) +static int __devinit pxa_camera_probe(struct platform_device *pdev) { struct pxa_camera_dev *pcdev; struct resource *res; @@ -1586,7 +1559,6 @@ static int pxa_camera_probe(struct platform_device *pdev) goto exit_kfree; } - dev_set_drvdata(&pdev->dev, pcdev); pcdev->res = res; pcdev->pdata = pdev->dev.platform_data; @@ -1607,7 +1579,6 @@ static int pxa_camera_probe(struct platform_device *pdev) pcdev->mclk = 20000000; } - pcdev->dev = &pdev->dev; pcdev->mclk_divisor = mclk_get_divisor(pcdev); INIT_LIST_HEAD(&pcdev->capture); @@ -1616,13 +1587,13 @@ static int pxa_camera_probe(struct platform_device *pdev) /* * Request the regions. */ - if (!request_mem_region(res->start, res->end - res->start + 1, + if (!request_mem_region(res->start, resource_size(res), PXA_CAM_DRV_NAME)) { err = -EBUSY; goto exit_clk; } - base = ioremap(res->start, res->end - res->start + 1); + base = ioremap(res->start, resource_size(res)); if (!base) { err = -ENOMEM; goto exit_release; @@ -1634,29 +1605,29 @@ static int pxa_camera_probe(struct platform_device *pdev) err = pxa_request_dma("CI_Y", DMA_PRIO_HIGH, pxa_camera_dma_irq_y, pcdev); if (err < 0) { - dev_err(pcdev->dev, "Can't request DMA for Y\n"); + dev_err(&pdev->dev, "Can't request DMA for Y\n"); goto exit_iounmap; } pcdev->dma_chans[0] = err; - dev_dbg(pcdev->dev, "got DMA channel %d\n", pcdev->dma_chans[0]); + dev_dbg(&pdev->dev, "got DMA channel %d\n", pcdev->dma_chans[0]); err = pxa_request_dma("CI_U", DMA_PRIO_HIGH, pxa_camera_dma_irq_u, pcdev); if (err < 0) { - dev_err(pcdev->dev, "Can't request DMA for U\n"); + dev_err(&pdev->dev, "Can't request DMA for U\n"); goto exit_free_dma_y; } pcdev->dma_chans[1] = err; - dev_dbg(pcdev->dev, "got DMA channel (U) %d\n", pcdev->dma_chans[1]); + dev_dbg(&pdev->dev, "got DMA channel (U) %d\n", pcdev->dma_chans[1]); err = pxa_request_dma("CI_V", DMA_PRIO_HIGH, pxa_camera_dma_irq_v, pcdev); if (err < 0) { - dev_err(pcdev->dev, "Can't request DMA for V\n"); + dev_err(&pdev->dev, "Can't request DMA for V\n"); goto exit_free_dma_u; } pcdev->dma_chans[2] = err; - dev_dbg(pcdev->dev, "got DMA channel (V) %d\n", pcdev->dma_chans[2]); + dev_dbg(&pdev->dev, "got DMA channel (V) %d\n", pcdev->dma_chans[2]); DRCMR(68) = pcdev->dma_chans[0] | DRCMR_MAPVLD; DRCMR(69) = pcdev->dma_chans[1] | DRCMR_MAPVLD; @@ -1666,14 +1637,17 @@ static int pxa_camera_probe(struct platform_device *pdev) err = request_irq(pcdev->irq, pxa_camera_irq, 0, PXA_CAM_DRV_NAME, pcdev); if (err) { - dev_err(pcdev->dev, "Camera interrupt register failed \n"); + dev_err(&pdev->dev, "Camera interrupt register failed \n"); goto exit_free_dma; } - pxa_soc_camera_host.priv = pcdev; - pxa_soc_camera_host.dev.parent = &pdev->dev; - pxa_soc_camera_host.nr = pdev->id; - err = soc_camera_host_register(&pxa_soc_camera_host); + pcdev->soc_host.drv_name = PXA_CAM_DRV_NAME; + pcdev->soc_host.ops = &pxa_soc_camera_host_ops; + pcdev->soc_host.priv = pcdev; + pcdev->soc_host.dev = &pdev->dev; + pcdev->soc_host.nr = pdev->id; + + err = soc_camera_host_register(&pcdev->soc_host); if (err) goto exit_free_irq; @@ -1690,7 +1664,7 @@ exit_free_dma_y: exit_iounmap: iounmap(base); exit_release: - release_mem_region(res->start, res->end - res->start + 1); + release_mem_region(res->start, resource_size(res)); exit_clk: clk_put(pcdev->clk); exit_kfree: @@ -1701,7 +1675,9 @@ exit: static int __devexit pxa_camera_remove(struct platform_device *pdev) { - struct pxa_camera_dev *pcdev = platform_get_drvdata(pdev); + struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev); + struct pxa_camera_dev *pcdev = container_of(soc_host, + struct pxa_camera_dev, soc_host); struct resource *res; clk_put(pcdev->clk); @@ -1711,12 +1687,12 @@ static int __devexit pxa_camera_remove(struct platform_device *pdev) pxa_free_dma(pcdev->dma_chans[2]); free_irq(pcdev->irq, pcdev); - soc_camera_host_unregister(&pxa_soc_camera_host); + soc_camera_host_unregister(soc_host); iounmap(pcdev->base); res = pcdev->res; - release_mem_region(res->start, res->end - res->start + 1); + release_mem_region(res->start, resource_size(res)); kfree(pcdev); @@ -1730,11 +1706,11 @@ static struct platform_driver pxa_camera_driver = { .name = PXA_CAM_DRV_NAME, }, .probe = pxa_camera_probe, - .remove = __exit_p(pxa_camera_remove), + .remove = __devexit_p(pxa_camera_remove), }; -static int __devinit pxa_camera_init(void) +static int __init pxa_camera_init(void) { return platform_driver_register(&pxa_camera_driver); } diff --git a/drivers/media/video/s2255drv.c b/drivers/media/video/s2255drv.c index 30f4698be90a..6be845ccc7d7 100644 --- a/drivers/media/video/s2255drv.c +++ b/drivers/media/video/s2255drv.c @@ -77,6 +77,8 @@ #define MAX_CHANNELS 4 #define S2255_MARKER_FRAME 0x2255DA4AL #define S2255_MARKER_RESPONSE 0x2255ACACL +#define S2255_RESPONSE_SETMODE 0x01 +#define S2255_RESPONSE_FW 0x10 #define S2255_USB_XFER_SIZE (16 * 1024) #define MAX_CHANNELS 4 #define MAX_PIPE_BUFFERS 1 @@ -107,6 +109,8 @@ #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) */ +/* SCALE_4CIFSI is the 2 fields interpolated into one */ +#define SCALE_4CIFSI 4 /* 640x480(NTSC) or 704x576(PAL) high quality */ #define COLOR_YUVPL 1 /* YUV planar */ #define COLOR_YUVPK 2 /* YUV packed */ @@ -178,9 +182,6 @@ struct s2255_bufferi { struct s2255_dmaqueue { struct list_head active; - /* thread for acquisition */ - struct task_struct *kthread; - int frame; struct s2255_dev *dev; int channel; }; @@ -210,16 +211,11 @@ 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 */ @@ -239,13 +235,13 @@ struct s2255_dev { 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]; /* jpeg compression */ struct v4l2_jpegcompression jc[MAX_CHANNELS]; + /* capture parameters (for high quality mode full size) */ + struct v4l2_captureparm cap_parm[MAX_CHANNELS]; const struct s2255_fmt *cur_fmt[MAX_CHANNELS]; int cur_frame[MAX_CHANNELS]; int last_frame[MAX_CHANNELS]; @@ -297,9 +293,10 @@ struct s2255_fh { int resources[MAX_CHANNELS]; }; -#define CUR_USB_FWVER 774 /* current cypress EEPROM firmware version */ +/* current cypress EEPROM firmware version */ +#define S2255_CUR_USB_FWVER ((3 << 8) | 6) #define S2255_MAJOR_VERSION 1 -#define S2255_MINOR_VERSION 13 +#define S2255_MINOR_VERSION 14 #define S2255_RELEASE 0 #define S2255_VERSION KERNEL_VERSION(S2255_MAJOR_VERSION, \ S2255_MINOR_VERSION, \ @@ -1027,9 +1024,16 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, 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 + if (fh->height > norm_minh(fh->dev->vdev[fh->channel])) { + if (fh->dev->cap_parm[fh->channel].capturemode & + V4L2_MODE_HIGHQUALITY) { + fh->mode.scale = SCALE_4CIFSI; + dprintk(2, "scale 4CIFSI\n"); + } else { + fh->mode.scale = SCALE_4CIFS; + dprintk(2, "scale 4CIFS\n"); + } + } else fh->mode.scale = SCALE_2CIFS; } else { @@ -1130,6 +1134,7 @@ static u32 get_transfer_size(struct s2255_mode *mode) if (mode->format == FORMAT_NTSC) { switch (mode->scale) { case SCALE_4CIFS: + case SCALE_4CIFSI: linesPerFrame = NUM_LINES_4CIFS_NTSC * 2; pixelsPerLine = LINE_SZ_4CIFS_NTSC; break; @@ -1147,6 +1152,7 @@ static u32 get_transfer_size(struct s2255_mode *mode) } else if (mode->format == FORMAT_PAL) { switch (mode->scale) { case SCALE_4CIFS: + case SCALE_4CIFSI: linesPerFrame = NUM_LINES_4CIFS_PAL * 2; pixelsPerLine = LINE_SZ_4CIFS_PAL; break; @@ -1502,6 +1508,33 @@ static int vidioc_s_jpegcomp(struct file *file, void *priv, dprintk(2, "setting jpeg quality %d\n", jc->quality); return 0; } + +static int vidioc_g_parm(struct file *file, void *priv, + struct v4l2_streamparm *sp) +{ + struct s2255_fh *fh = priv; + struct s2255_dev *dev = fh->dev; + if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + sp->parm.capture.capturemode = dev->cap_parm[fh->channel].capturemode; + dprintk(2, "getting parm %d\n", sp->parm.capture.capturemode); + return 0; +} + +static int vidioc_s_parm(struct file *file, void *priv, + struct v4l2_streamparm *sp) +{ + struct s2255_fh *fh = priv; + struct s2255_dev *dev = fh->dev; + + if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + dev->cap_parm[fh->channel].capturemode = sp->parm.capture.capturemode; + dprintk(2, "setting param capture mode %d\n", + sp->parm.capture.capturemode); + return 0; +} static int s2255_open(struct file *file) { int minor = video_devdata(file)->minor; @@ -1793,6 +1826,8 @@ static const struct v4l2_ioctl_ops s2255_ioctl_ops = { #endif .vidioc_s_jpegcomp = vidioc_s_jpegcomp, .vidioc_g_jpegcomp = vidioc_g_jpegcomp, + .vidioc_s_parm = vidioc_s_parm, + .vidioc_g_parm = vidioc_g_parm, }; static struct video_device template = { @@ -1818,7 +1853,6 @@ static int s2255_probe_v4l(struct s2255_dev *dev) 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)); @@ -1839,7 +1873,9 @@ static int s2255_probe_v4l(struct s2255_dev *dev) return ret; } } - printk(KERN_INFO "Sensoray 2255 V4L driver\n"); + printk(KERN_INFO "Sensoray 2255 V4L driver Revision: %d.%d\n", + S2255_MAJOR_VERSION, + S2255_MINOR_VERSION); return ret; } @@ -1929,14 +1965,14 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info) if (!(cc >= 0 && cc < MAX_CHANNELS)) break; switch (pdword[2]) { - case 0x01: + case S2255_RESPONSE_SETMODE: /* check if channel valid */ /* set mode ready */ dev->setmode_ready[cc] = 1; wake_up(&dev->wait_setmode[cc]); dprintk(5, "setmode ready %d\n", cc); break; - case 0x10: + case S2255_RESPONSE_FW: dev->chn_ready |= (1 << cc); if ((dev->chn_ready & 0x0f) != 0x0f) @@ -2172,10 +2208,15 @@ static int s2255_board_init(struct s2255_dev *dev) /* 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) + printk(KERN_INFO "2255 usb firmware version %d.%d\n", + (fw_ver >> 8) & 0xff, + fw_ver & 0xff); + + if (fw_ver < S2255_CUR_USB_FWVER) dev_err(&dev->udev->dev, - "usb firmware not up to date %d\n", fw_ver); + "usb firmware not up to date %d.%d\n", + (fw_ver >> 8) & 0xff, + fw_ver & 0xff); for (j = 0; j < MAX_CHANNELS; j++) { dev->b_acquire[j] = 0; @@ -2240,8 +2281,10 @@ static void read_pipe_completion(struct urb *purb) return; } status = purb->status; - if (status != 0) { - dprintk(2, "read_pipe_completion: err\n"); + /* if shutting down, do not resubmit, exit immediately */ + if (status == -ESHUTDOWN) { + dprintk(2, "read_pipe_completion: err shutdown\n"); + pipe_info->err_count++; return; } @@ -2250,9 +2293,13 @@ static void read_pipe_completion(struct urb *purb) return; } - s2255_read_video_callback(dev, pipe_info); + if (status == 0) + s2255_read_video_callback(dev, pipe_info); + else { + pipe_info->err_count++; + dprintk(1, "s2255drv: failed URB %d\n", status); + } - 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, @@ -2264,7 +2311,6 @@ static void read_pipe_completion(struct urb *purb) 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"); @@ -2283,8 +2329,7 @@ static int s2255_start_readpipe(struct s2255_dev *dev) 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->err_count = 0; pipe_info->stream_urb = usb_alloc_urb(0, GFP_KERNEL); if (!pipe_info->stream_urb) { dev_err(&dev->udev->dev, @@ -2298,7 +2343,6 @@ static int s2255_start_readpipe(struct s2255_dev *dev) 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) { @@ -2403,8 +2447,6 @@ static void s2255_stop_readpipe(struct s2255_dev *dev) if (pipe_info->state == 0) continue; pipe_info->state = 0; - pipe_info->prev_state = 1; - } } @@ -2542,7 +2584,9 @@ static int s2255_probe(struct usb_interface *interface, s2255_probe_v4l(dev); usb_reset_device(dev->udev); /* load 2255 board specific */ - s2255_board_init(dev); + retval = s2255_board_init(dev); + if (retval) + goto error; dprintk(4, "before probe done %p\n", dev); spin_lock_init(&dev->slock); diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig index 0ba68987bfce..5bcce092e804 100644 --- a/drivers/media/video/saa7134/Kconfig +++ b/drivers/media/video/saa7134/Kconfig @@ -44,6 +44,7 @@ config VIDEO_SAA7134_DVB select DVB_LNBP21 if !DVB_FE_CUSTOMISE select DVB_ZL10353 if !DVB_FE_CUSTOMISE select DVB_LGDT3305 if !DVB_FE_CUSTOMISE + select DVB_TDA10048 if !DVB_FE_CUSTOMISE select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE ---help--- diff --git a/drivers/media/video/saa7134/Makefile b/drivers/media/video/saa7134/Makefile index 3dbaa19a6d00..604158a8c235 100644 --- a/drivers/media/video/saa7134/Makefile +++ b/drivers/media/video/saa7134/Makefile @@ -3,8 +3,7 @@ saa7134-objs := saa7134-cards.o saa7134-core.o saa7134-i2c.o \ saa7134-ts.o saa7134-tvaudio.o saa7134-vbi.o \ saa7134-video.o saa7134-input.o -obj-$(CONFIG_VIDEO_SAA7134) += saa7134.o saa7134-empress.o \ - saa6752hs.o +obj-$(CONFIG_VIDEO_SAA7134) += saa6752hs.o saa7134.o saa7134-empress.o obj-$(CONFIG_VIDEO_SAA7134_ALSA) += saa7134-alsa.o diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index fdb19449d269..06861b782b95 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -1669,6 +1669,39 @@ struct saa7134_board saa7134_boards[] = { .amux = LINE1, }, }, + [SAA7134_BOARD_AVERMEDIA_CARDBUS_501] = { + /* Oldrich Jedlicka */ + .name = "AVerMedia Cardbus TV/Radio (E501R)", + .audio_clock = 0x187de7, + .tuner_type = TUNER_ALPS_TSBE5_PAL, + .radio_type = TUNER_TEA5767, + .tuner_addr = 0x61, + .radio_addr = 0x60, + .tda9887_conf = TDA9887_PRESENT, + .gpiomask = 0x08000000, + .inputs = { { + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + .gpio = 0x08000000, + }, { + .name = name_comp1, + .vmux = 3, + .amux = LINE1, + .gpio = 0x08000000, + }, { + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + .gpio = 0x08000000, + } }, + .radio = { + .name = name_radio, + .amux = LINE2, + .gpio = 0x00000000, + }, + }, [SAA7134_BOARD_CINERGY400_CARDBUS] = { .name = "Terratec Cinergy 400 mobile", .audio_clock = 0x187de7, @@ -3331,13 +3364,15 @@ struct saa7134_board saa7134_boards[] = { }, }, [SAA7134_BOARD_HAUPPAUGE_HVR1110R3] = { - .name = "Hauppauge WinTV-HVR1110r3", + .name = "Hauppauge WinTV-HVR1110r3 DVB-T/Hybrid", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_TDA8290, .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tuner_config = 3, + .mpeg = SAA7134_MPEG_DVB, + .ts_type = SAA7134_MPEG_TS_SERIAL, .gpiomask = 0x0800100, /* GPIO 21 is an INPUT */ .inputs = {{ .name = name_tv, @@ -4006,7 +4041,7 @@ struct saa7134_board saa7134_boards[] = { [SAA7134_BOARD_BEHOLD_505FM] = { /* Beholder Intl. Ltd. 2008 */ /*Dmitry Belimov */ - .name = "Beholder BeholdTV 505 FM/RDS", + .name = "Beholder BeholdTV 505 FM", .audio_clock = 0x00200000, .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, .radio_type = UNSET, @@ -4014,6 +4049,40 @@ struct saa7134_board saa7134_boards[] = { .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, .gpiomask = 0x00008000, + .inputs = {{ + .name = name_tv, + .vmux = 3, + .amux = LINE2, + .tv = 1, + }, { + .name = name_comp1, + .vmux = 1, + .amux = LINE1, + }, { + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + } }, + .mute = { + .name = name_mute, + .amux = LINE1, + }, + .radio = { + .name = name_radio, + .amux = LINE2, + }, + }, + [SAA7134_BOARD_BEHOLD_505RDS] = { + /* Beholder Intl. Ltd. 2008 */ + /*Dmitry Belimov */ + .name = "Beholder BeholdTV 505 RDS", + .audio_clock = 0x00200000, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, /* FIXME to MK5 */ + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .gpiomask = 0x00008000, .inputs = {{ .name = name_tv, .vmux = 3, @@ -4040,7 +4109,7 @@ struct saa7134_board saa7134_boards[] = { [SAA7134_BOARD_BEHOLD_507_9FM] = { /* Beholder Intl. Ltd. 2008 */ /*Dmitry Belimov */ - .name = "Beholder BeholdTV 507 FM/RDS / BeholdTV 509 FM", + .name = "Beholder BeholdTV 507 FM / BeholdTV 509 FM", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, .radio_type = UNSET, @@ -4067,6 +4136,66 @@ struct saa7134_board saa7134_boards[] = { .amux = LINE2, }, }, + [SAA7134_BOARD_BEHOLD_507RDS_MK5] = { + /* Beholder Intl. Ltd. 2008 */ + /*Dmitry Belimov */ + .name = "Beholder BeholdTV 507 RDS", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, /* FIXME to MK5 */ + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .gpiomask = 0x00008000, + .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, + }, + }, + [SAA7134_BOARD_BEHOLD_507RDS_MK3] = { + /* Beholder Intl. Ltd. 2008 */ + /*Dmitry Belimov */ + .name = "Beholder BeholdTV 507 RDS", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .gpiomask = 0x00008000, + .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, + }, + }, [SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM] = { /* Beholder Intl. Ltd. 2008 */ /*Dmitry Belimov */ @@ -4101,15 +4230,211 @@ struct saa7134_board saa7134_boards[] = { .gpio = 0x000A8000, }, }, - [SAA7134_BOARD_BEHOLD_607_9FM] = { + [SAA7134_BOARD_BEHOLD_607FM_MK3] = { /* Andrey Melnikoff */ - .name = "Beholder BeholdTV 607 / BeholdTV 609", + .name = "Beholder BeholdTV 607 FM", .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, + }, + }, + [SAA7134_BOARD_BEHOLD_609FM_MK3] = { + /* Andrey Melnikoff */ + .name = "Beholder BeholdTV 609 FM", + .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, + }, + }, + [SAA7134_BOARD_BEHOLD_607FM_MK5] = { + /* Andrey Melnikoff */ + .name = "Beholder BeholdTV 607 FM", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, /* FIXME to MK5 */ + .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, + }, + }, + [SAA7134_BOARD_BEHOLD_609FM_MK5] = { + /* Andrey Melnikoff */ + .name = "Beholder BeholdTV 609 FM", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, /* FIXME to MK5 */ + .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, + }, + }, + [SAA7134_BOARD_BEHOLD_607RDS_MK3] = { + /* Andrey Melnikoff */ + .name = "Beholder BeholdTV 607 RDS", + .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, + }, + }, + [SAA7134_BOARD_BEHOLD_609RDS_MK3] = { + /* Andrey Melnikoff */ + .name = "Beholder BeholdTV 609 RDS", + .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, + }, + }, + [SAA7134_BOARD_BEHOLD_607RDS_MK5] = { + /* Andrey Melnikoff */ + .name = "Beholder BeholdTV 607 RDS", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, /* FIXME to MK5 */ + .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, + }, + }, + [SAA7134_BOARD_BEHOLD_609RDS_MK5] = { + /* Andrey Melnikoff */ + .name = "Beholder BeholdTV 609 RDS", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, /* FIXME to MK5 */ + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, .inputs = {{ .name = name_tv, .vmux = 3, @@ -4133,6 +4458,7 @@ struct saa7134_board saa7134_boards[] = { /* Igor Kuznetsov */ /* Andrey Melnikoff */ /* Beholder Intl. Ltd. Dmitry Belimov */ + /* Alexey Osipov */ .name = "Beholder BeholdTV M6", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, @@ -4207,10 +4533,10 @@ struct saa7134_board saa7134_boards[] = { /* Igor Kuznetsov */ /* Andrey Melnikoff */ /* Beholder Intl. Ltd. Dmitry Belimov */ + /* Alexey Osipov */ .name = "Beholder BeholdTV M6 Extra", .audio_clock = 0x00187de7, - /* FIXME: Must be PHILIPS_FM1216ME_MK5*/ - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, /* FIXME to MK5 */ .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, @@ -4465,7 +4791,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 = 3, @@ -4753,6 +5078,44 @@ struct saa7134_board saa7134_boards[] = { .gpio = 0x01, }, }, + [SAA7134_BOARD_AVERMEDIA_STUDIO_507UA] = { + /* Andy Shevchenko */ + .name = "Avermedia AVerTV Studio 507UA", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, /* Should be MK5 */ + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .gpiomask = 0x03, + .inputs = { { + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + .gpio = 0x00, + }, { + .name = name_comp1, + .vmux = 3, + .amux = LINE1, + .gpio = 0x00, + }, { + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + .gpio = 0x00, + } }, + .radio = { + .name = name_radio, + .amux = LINE2, + .gpio = 0x01, + }, + .mute = { + .name = name_mute, + .amux = LINE1, + .gpio = 0x00, + }, + }, }; const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards); @@ -5027,6 +5390,13 @@ struct pci_device_id saa7134_pci_tbl[] = { .subdevice = 0xd6ee, .driver_data = SAA7134_BOARD_AVERMEDIA_CARDBUS, },{ + /* AVerMedia CardBus */ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x1461, /* Avermedia Technologies Inc */ + .subdevice = 0xb7e9, + .driver_data = SAA7134_BOARD_AVERMEDIA_CARDBUS_501, + }, { /* TransGear 3000TV */ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7130, @@ -5440,6 +5810,12 @@ struct pci_device_id saa7134_pci_tbl[] = { .subdevice = 0x9715, .driver_data = SAA7134_BOARD_AVERMEDIA_STUDIO_507, },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x1461, /* Avermedia Technologies Inc */ + .subdevice = 0xa11b, + .driver_data = SAA7134_BOARD_AVERMEDIA_STUDIO_507UA, + }, { .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x1043, @@ -5643,18 +6019,12 @@ struct pci_device_id saa7134_pci_tbl[] = { .subvendor = 0x0000, .subdevice = 0x4090, .driver_data = SAA7134_BOARD_BEHOLD_409, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x0000, - .subdevice = 0x5051, - .driver_data = SAA7134_BOARD_BEHOLD_505FM, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7130, .subvendor = 0x0000, .subdevice = 0x505B, - .driver_data = SAA7134_BOARD_BEHOLD_505FM, + .driver_data = SAA7134_BOARD_BEHOLD_505RDS, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7130, @@ -5666,13 +6036,13 @@ struct pci_device_id saa7134_pci_tbl[] = { .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x0000, .subdevice = 0x5071, - .driver_data = SAA7134_BOARD_BEHOLD_507_9FM, + .driver_data = SAA7134_BOARD_BEHOLD_507RDS_MK3, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x0000, .subdevice = 0x507B, - .driver_data = SAA7134_BOARD_BEHOLD_507_9FM, + .driver_data = SAA7134_BOARD_BEHOLD_507RDS_MK5, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, @@ -5696,49 +6066,49 @@ struct pci_device_id saa7134_pci_tbl[] = { .device = PCI_DEVICE_ID_PHILIPS_SAA7134, .subvendor = 0x5ace, .subdevice = 0x6070, - .driver_data = SAA7134_BOARD_BEHOLD_607_9FM, + .driver_data = SAA7134_BOARD_BEHOLD_607FM_MK3, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, .subvendor = 0x5ace, .subdevice = 0x6071, - .driver_data = SAA7134_BOARD_BEHOLD_607_9FM, + .driver_data = SAA7134_BOARD_BEHOLD_607FM_MK5, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, .subvendor = 0x5ace, .subdevice = 0x6072, - .driver_data = SAA7134_BOARD_BEHOLD_607_9FM, + .driver_data = SAA7134_BOARD_BEHOLD_607RDS_MK3, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, .subvendor = 0x5ace, .subdevice = 0x6073, - .driver_data = SAA7134_BOARD_BEHOLD_607_9FM, + .driver_data = SAA7134_BOARD_BEHOLD_607RDS_MK5, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x5ace, .subdevice = 0x6090, - .driver_data = SAA7134_BOARD_BEHOLD_607_9FM, + .driver_data = SAA7134_BOARD_BEHOLD_609FM_MK3, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x5ace, .subdevice = 0x6091, - .driver_data = SAA7134_BOARD_BEHOLD_607_9FM, + .driver_data = SAA7134_BOARD_BEHOLD_609FM_MK5, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x5ace, .subdevice = 0x6092, - .driver_data = SAA7134_BOARD_BEHOLD_607_9FM, + .driver_data = SAA7134_BOARD_BEHOLD_609RDS_MK3, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x5ace, .subdevice = 0x6093, - .driver_data = SAA7134_BOARD_BEHOLD_607_9FM, + .driver_data = SAA7134_BOARD_BEHOLD_609RDS_MK5, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, @@ -5829,6 +6199,12 @@ struct pci_device_id saa7134_pci_tbl[] = { .subvendor = 0x1461, /* Avermedia Technologies Inc */ .subdevice = 0xf636, .driver_data = SAA7134_BOARD_AVERMEDIA_M103, + }, { + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x1461, /* Avermedia Technologies Inc */ + .subdevice = 0xf736, + .driver_data = SAA7134_BOARD_AVERMEDIA_M103, }, { .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, @@ -6114,7 +6490,6 @@ int saa7134_board_init1(struct saa7134_dev *dev) case SAA7134_BOARD_VIDEOMATE_DVBT_300: case SAA7134_BOARD_VIDEOMATE_DVBT_200: case SAA7134_BOARD_VIDEOMATE_DVBT_200A: - case SAA7134_BOARD_VIDEOMATE_T750: case SAA7134_BOARD_MANLI_MTV001: case SAA7134_BOARD_MANLI_MTV002: case SAA7134_BOARD_BEHOLD_409FM: @@ -6142,7 +6517,10 @@ int saa7134_board_init1(struct saa7134_dev *dev) case SAA7134_BOARD_BEHOLD_407FM: case SAA7134_BOARD_BEHOLD_409: case SAA7134_BOARD_BEHOLD_505FM: + case SAA7134_BOARD_BEHOLD_505RDS: case SAA7134_BOARD_BEHOLD_507_9FM: + case SAA7134_BOARD_BEHOLD_507RDS_MK3: + case SAA7134_BOARD_BEHOLD_507RDS_MK5: case SAA7134_BOARD_GENIUS_TVGO_A11MCE: case SAA7134_BOARD_REAL_ANGEL_220: case SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG: @@ -6196,6 +6574,16 @@ int saa7134_board_init1(struct saa7134_dev *dev) saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0xffffffff, 0xffffffff); msleep(10); break; + case SAA7134_BOARD_AVERMEDIA_CARDBUS_501: + /* power-down tuner chip */ + saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x08400000, 0x08400000); + saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x08400000, 0); + msleep(10); + saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x08400000, 0x08400000); + saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x08400000, 0x08400000); + msleep(10); + dev->has_remote = SAA7134_REMOTE_I2C; + break; case SAA7134_BOARD_AVERMEDIA_CARDBUS_506: saa7134_set_gpio(dev, 23, 0); msleep(10); @@ -6253,7 +6641,14 @@ int saa7134_board_init1(struct saa7134_dev *dev) case SAA7134_BOARD_UPMOST_PURPLE_TV: case SAA7134_BOARD_MSI_TVATANYWHERE_PLUS: case SAA7134_BOARD_HAUPPAUGE_HVR1110: - case SAA7134_BOARD_BEHOLD_607_9FM: + case SAA7134_BOARD_BEHOLD_607FM_MK3: + case SAA7134_BOARD_BEHOLD_607FM_MK5: + case SAA7134_BOARD_BEHOLD_609FM_MK3: + case SAA7134_BOARD_BEHOLD_609FM_MK5: + case SAA7134_BOARD_BEHOLD_607RDS_MK3: + case SAA7134_BOARD_BEHOLD_607RDS_MK5: + case SAA7134_BOARD_BEHOLD_609RDS_MK3: + case SAA7134_BOARD_BEHOLD_609RDS_MK5: case SAA7134_BOARD_BEHOLD_M6: case SAA7134_BOARD_BEHOLD_M63: case SAA7134_BOARD_BEHOLD_M6_EXTRA: @@ -6635,6 +7030,7 @@ int saa7134_board_init2(struct saa7134_dev *dev) switch (dev->board) { case SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM: + case SAA7134_BOARD_AVERMEDIA_CARDBUS_501: { struct v4l2_priv_tun_config tea5767_cfg; struct tea5767_ctrl ctl; diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index 2def6fec814b..94a023a14bbc 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -331,6 +331,10 @@ void saa7134_buffer_next(struct saa7134_dev *dev, dprintk("buffer_next %p\n",NULL); saa7134_set_dmabits(dev); del_timer(&q->timeout); + + if (card_has_mpeg(dev)) + if (dev->ts_started) + saa7134_ts_stop(dev); } } @@ -416,6 +420,19 @@ int saa7134_set_dmabits(struct saa7134_dev *dev) ctrl |= SAA7134_MAIN_CTRL_TE5; irq |= SAA7134_IRQ1_INTE_RA2_1 | SAA7134_IRQ1_INTE_RA2_0; + + /* dma: setup channel 5 (= TS) */ + + saa_writeb(SAA7134_TS_DMA0, (dev->ts.nr_packets - 1) & 0xff); + saa_writeb(SAA7134_TS_DMA1, + ((dev->ts.nr_packets - 1) >> 8) & 0xff); + /* TSNOPIT=0, TSCOLAP=0 */ + saa_writeb(SAA7134_TS_DMA2, + (((dev->ts.nr_packets - 1) >> 16) & 0x3f) | 0x00); + saa_writel(SAA7134_RS_PITCH(5), TS_PACKET_SIZE); + saa_writel(SAA7134_RS_CONTROL(5), SAA7134_RS_CONTROL_BURST_16 | + SAA7134_RS_CONTROL_ME | + (dev->ts.pt_ts.dma >> 12)); } /* set task conditions + field handling */ @@ -775,7 +792,6 @@ static struct video_device *vdev_init(struct saa7134_dev *dev, if (NULL == vfd) return NULL; *vfd = *template; - vfd->minor = -1; vfd->v4l2_dev = &dev->v4l2_dev; vfd->release = video_device_release; vfd->debug = video_debug; diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index 4eff1ca8593c..31930f26ffc7 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c @@ -48,6 +48,7 @@ #include "isl6405.h" #include "lnbp21.h" #include "tuner-simple.h" +#include "tda10048.h" #include "tda18271.h" #include "lgdt3305.h" #include "tda8290.h" @@ -978,6 +979,18 @@ static struct lgdt3305_config hcw_lgdt3305_config = { .vsb_if_khz = 3250, }; +static struct tda10048_config hcw_tda10048_config = { + .demod_address = 0x10 >> 1, + .output_mode = TDA10048_SERIAL_OUTPUT, + .fwbulkwritelen = TDA10048_BULKWRITE_200, + .inversion = TDA10048_INVERSION_ON, + .dtv6_if_freq_khz = TDA10048_IF_3300, + .dtv7_if_freq_khz = TDA10048_IF_3500, + .dtv8_if_freq_khz = TDA10048_IF_4000, + .clk_freq_khz = TDA10048_CLK_16000, + .disable_gate_access = 1, +}; + static struct tda18271_std_map hauppauge_tda18271_std_map = { .atsc_6 = { .if_freq = 3250, .agc_mode = 3, .std = 4, .if_lvl = 1, .rfagc_top = 0x58, }, @@ -1106,6 +1119,19 @@ static int dvb_init(struct saa7134_dev *dev) &tda827x_cfg_2) < 0) goto dettach_frontend; break; + case SAA7134_BOARD_HAUPPAUGE_HVR1110R3: + fe0->dvb.frontend = dvb_attach(tda10048_attach, + &hcw_tda10048_config, + &dev->i2c_adap); + if (fe0->dvb.frontend != NULL) { + dvb_attach(tda829x_attach, fe0->dvb.frontend, + &dev->i2c_adap, 0x4b, + &tda829x_no_probe); + dvb_attach(tda18271_attach, fe0->dvb.frontend, + 0x60, &dev->i2c_adap, + &hcw_tda18271_config); + } + break; case SAA7134_BOARD_PHILIPS_TIGER: if (configure_tda827x_fe(dev, &philips_tiger_config, &tda827x_cfg_0) < 0) diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c index 9db3472667e5..add1757f8930 100644 --- a/drivers/media/video/saa7134/saa7134-empress.c +++ b/drivers/media/video/saa7134/saa7134-empress.c @@ -255,6 +255,16 @@ static int empress_s_fmt_vid_cap(struct file *file, void *priv, return 0; } +static int empress_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct saa7134_dev *dev = file->private_data; + + f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; + f->fmt.pix.sizeimage = TS_PACKET_SIZE * dev->ts.nr_packets; + + return 0; +} static int empress_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *p) @@ -450,6 +460,7 @@ static const struct v4l2_file_operations ts_fops = static const struct v4l2_ioctl_ops ts_ioctl_ops = { .vidioc_querycap = empress_querycap, .vidioc_enum_fmt_vid_cap = empress_enum_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = empress_try_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, @@ -491,11 +502,8 @@ static void empress_signal_update(struct work_struct *work) if (dev->nosignal) { dprintk("no video signal\n"); - ts_reset_encoder(dev); } else { dprintk("video signal acquired\n"); - if (atomic_read(&dev->empress_users)) - ts_init_encoder(dev); } } diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c index f3e285aa2fb4..8096dace5f6c 100644 --- a/drivers/media/video/saa7134/saa7134-i2c.c +++ b/drivers/media/video/saa7134/saa7134-i2c.c @@ -259,7 +259,7 @@ static int saa7134_i2c_xfer(struct i2c_adapter *i2c_adap, /* workaround for a saa7134 i2c bug * needed to talk to the mt352 demux * thanks to pinnacle for the hint */ - int quirk = 0xfd; + int quirk = 0xfe; d1printk(" [%02x quirk]",quirk); i2c_send_byte(dev,START,quirk); i2c_recv_byte(dev); @@ -321,33 +321,6 @@ static u32 functionality(struct i2c_adapter *adap) return I2C_FUNC_SMBUS_EMUL; } -static int attach_inform(struct i2c_client *client) -{ - struct saa7134_dev *dev = client->adapter->algo_data; - - d1printk( "%s i2c attach [addr=0x%x,client=%s]\n", - client->driver->driver.name, client->addr, client->name); - - /* Am I an i2c remote control? */ - - switch (client->addr) { - case 0x7a: - case 0x47: - case 0x71: - case 0x2d: - case 0x30: - { - struct IR_i2c *ir = i2c_get_clientdata(client); - d1printk("%s i2c IR detected (%s).\n", - client->driver->driver.name, ir->phys); - saa7134_set_i2c_ir(dev,ir); - break; - } - } - - return 0; -} - static struct i2c_algorithm saa7134_algo = { .master_xfer = saa7134_i2c_xfer, .functionality = functionality, @@ -358,7 +331,6 @@ static struct i2c_adapter saa7134_adap_template = { .name = "saa7134", .id = I2C_HW_SAA7134, .algo = &saa7134_algo, - .client_register = attach_inform, }; static struct i2c_client saa7134_client_template = { @@ -433,6 +405,9 @@ int saa7134_i2c_register(struct saa7134_dev *dev) saa7134_i2c_eeprom(dev,dev->eedata,sizeof(dev->eedata)); if (i2c_scan) do_i2c_scan(dev->name,&dev->i2c_client); + + /* Instantiate the IR receiver device, if present */ + saa7134_probe_i2c_ir(dev); return 0; } diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index 8a106d36e723..6e219c2db841 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -60,7 +60,7 @@ MODULE_PARM_DESC(disable_other_ir, "disable full codes of " #define dprintk(fmt, arg...) if (ir_debug) \ printk(KERN_DEBUG "%s/ir: " fmt, dev->name , ## arg) #define i2cdprintk(fmt, arg...) if (ir_debug) \ - printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg) + printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg) /* Helper functions for RC5 and NEC decoding at GPIO16 or GPIO18 */ static int saa7134_rc5_irq(struct saa7134_dev *dev); @@ -134,10 +134,10 @@ static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, u32 *ir_key, int gpio; /* is needed to access GPIO. Used by the saa_readl macro. */ - struct saa7134_dev *dev = ir->c.adapter->algo_data; + struct saa7134_dev *dev = ir->c->adapter->algo_data; if (dev == NULL) { dprintk("get_key_msi_tvanywhere_plus: " - "gir->c.adapter->algo_data is NULL!\n"); + "gir->c->adapter->algo_data is NULL!\n"); return -EIO; } @@ -156,7 +156,7 @@ static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, u32 *ir_key, /* GPIO says there is a button press. Get it. */ - if (1 != i2c_master_recv(&ir->c, &b, 1)) { + if (1 != i2c_master_recv(ir->c, &b, 1)) { i2cdprintk("read error\n"); return -EIO; } @@ -179,7 +179,7 @@ static int get_key_purpletv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) unsigned char b; /* poll IR chip */ - if (1 != i2c_master_recv(&ir->c,&b,1)) { + if (1 != i2c_master_recv(ir->c, &b, 1)) { i2cdprintk("read error\n"); return -EIO; } @@ -202,7 +202,7 @@ static int get_key_hvr1110(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) unsigned char buf[5], cod4, code3, code4; /* poll IR chip */ - if (5 != i2c_master_recv(&ir->c,buf,5)) + if (5 != i2c_master_recv(ir->c, buf, 5)) return -EIO; cod4 = buf[4]; @@ -224,7 +224,7 @@ static int get_key_beholdm6xx(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) unsigned char data[12]; u32 gpio; - struct saa7134_dev *dev = ir->c.adapter->algo_data; + struct saa7134_dev *dev = ir->c->adapter->algo_data; /* rising SAA7134_GPIO_GPRESCAN reads the status */ saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); @@ -235,9 +235,9 @@ static int get_key_beholdm6xx(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) if (0x400000 & ~gpio) return 0; /* No button press */ - ir->c.addr = 0x5a >> 1; + ir->c->addr = 0x5a >> 1; - if (12 != i2c_master_recv(&ir->c, data, 12)) { + if (12 != i2c_master_recv(ir->c, data, 12)) { i2cdprintk("read error\n"); return -EIO; } @@ -267,7 +267,7 @@ static int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw, unsigned int start = 0,parity = 0,code = 0; /* poll IR chip */ - if (4 != i2c_master_recv(&ir->c, b, 4)) { + if (4 != i2c_master_recv(ir->c, b, 4)) { i2cdprintk("read error\n"); return -EIO; } @@ -447,6 +447,7 @@ int saa7134_input_init1(struct saa7134_dev *dev) case SAA7134_BOARD_AVERMEDIA_STUDIO_305: case SAA7134_BOARD_AVERMEDIA_STUDIO_307: case SAA7134_BOARD_AVERMEDIA_STUDIO_507: + case SAA7134_BOARD_AVERMEDIA_STUDIO_507UA: case SAA7134_BOARD_AVERMEDIA_GO_007_FM: case SAA7134_BOARD_AVERMEDIA_M102: case SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS: @@ -506,7 +507,10 @@ int saa7134_input_init1(struct saa7134_dev *dev) case SAA7134_BOARD_BEHOLD_407FM: case SAA7134_BOARD_BEHOLD_409: case SAA7134_BOARD_BEHOLD_505FM: + case SAA7134_BOARD_BEHOLD_505RDS: case SAA7134_BOARD_BEHOLD_507_9FM: + case SAA7134_BOARD_BEHOLD_507RDS_MK3: + case SAA7134_BOARD_BEHOLD_507RDS_MK5: ir_codes = ir_codes_manli; mask_keycode = 0x003f00; mask_keyup = 0x004000; @@ -678,55 +682,101 @@ void saa7134_input_fini(struct saa7134_dev *dev) dev->remote = NULL; } -void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir) +void saa7134_probe_i2c_ir(struct saa7134_dev *dev) { + struct i2c_board_info info; + struct IR_i2c_init_data init_data; + const unsigned short addr_list[] = { + 0x7a, 0x47, 0x71, 0x2d, + I2C_CLIENT_END + }; + + struct i2c_msg msg_msi = { + .addr = 0x50, + .flags = I2C_M_RD, + .len = 0, + .buf = NULL, + }; + + int rc; + if (disable_ir) { - dprintk("Found supported i2c remote, but IR has been disabled\n"); - ir->get_key=NULL; + dprintk("IR has been disabled, not probing for i2c remote\n"); return; } + memset(&info, 0, sizeof(struct i2c_board_info)); + memset(&init_data, 0, sizeof(struct IR_i2c_init_data)); + strlcpy(info.type, "ir_video", I2C_NAME_SIZE); + switch (dev->board) { case SAA7134_BOARD_PINNACLE_PCTV_110i: case SAA7134_BOARD_PINNACLE_PCTV_310i: - snprintf(ir->c.name, sizeof(ir->c.name), "Pinnacle PCTV"); + init_data.name = "Pinnacle PCTV"; if (pinnacle_remote == 0) { - ir->get_key = get_key_pinnacle_color; - ir->ir_codes = ir_codes_pinnacle_color; + init_data.get_key = get_key_pinnacle_color; + init_data.ir_codes = ir_codes_pinnacle_color; } else { - ir->get_key = get_key_pinnacle_grey; - ir->ir_codes = ir_codes_pinnacle_grey; + init_data.get_key = get_key_pinnacle_grey; + init_data.ir_codes = ir_codes_pinnacle_grey; } break; case SAA7134_BOARD_UPMOST_PURPLE_TV: - snprintf(ir->c.name, sizeof(ir->c.name), "Purple TV"); - ir->get_key = get_key_purpletv; - ir->ir_codes = ir_codes_purpletv; + init_data.name = "Purple TV"; + init_data.get_key = get_key_purpletv; + init_data.ir_codes = ir_codes_purpletv; break; case SAA7134_BOARD_MSI_TVATANYWHERE_PLUS: - snprintf(ir->c.name, sizeof(ir->c.name), "MSI TV@nywhere Plus"); - ir->get_key = get_key_msi_tvanywhere_plus; - ir->ir_codes = ir_codes_msi_tvanywhere_plus; + init_data.name = "MSI TV@nywhere Plus"; + init_data.get_key = get_key_msi_tvanywhere_plus; + init_data.ir_codes = ir_codes_msi_tvanywhere_plus; + info.addr = 0x30; + /* MSI TV@nywhere Plus controller doesn't seem to + respond to probes unless we read something from + an existing device. Weird... + REVISIT: might no longer be needed */ + rc = i2c_transfer(&dev->i2c_adap, &msg_msi, 1); + dprintk(KERN_DEBUG "probe 0x%02x @ %s: %s\n", + msg_msi.addr, dev->i2c_adap.name, + (1 == rc) ? "yes" : "no"); break; case SAA7134_BOARD_HAUPPAUGE_HVR1110: - snprintf(ir->c.name, sizeof(ir->c.name), "HVR 1110"); - ir->get_key = get_key_hvr1110; - ir->ir_codes = ir_codes_hauppauge_new; + init_data.name = "HVR 1110"; + init_data.get_key = get_key_hvr1110; + init_data.ir_codes = ir_codes_hauppauge_new; break; - case SAA7134_BOARD_BEHOLD_607_9FM: + case SAA7134_BOARD_BEHOLD_607FM_MK3: + case SAA7134_BOARD_BEHOLD_607FM_MK5: + case SAA7134_BOARD_BEHOLD_609FM_MK3: + case SAA7134_BOARD_BEHOLD_609FM_MK5: + case SAA7134_BOARD_BEHOLD_607RDS_MK3: + case SAA7134_BOARD_BEHOLD_607RDS_MK5: + case SAA7134_BOARD_BEHOLD_609RDS_MK3: + case SAA7134_BOARD_BEHOLD_609RDS_MK5: 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; - ir->ir_codes = ir_codes_behold; + init_data.name = "BeholdTV"; + init_data.get_key = get_key_beholdm6xx; + init_data.ir_codes = ir_codes_behold; break; - default: - dprintk("Shouldn't get here: Unknown board %x for I2C IR?\n",dev->board); + case SAA7134_BOARD_AVERMEDIA_CARDBUS_501: + case SAA7134_BOARD_AVERMEDIA_CARDBUS_506: + info.addr = 0x40; break; } + if (init_data.name) + info.platform_data = &init_data; + /* No need to probe if address is known */ + if (info.addr) { + i2c_new_device(&dev->i2c_adap, &info); + return; + } + + /* Address not known, fallback to probing */ + i2c_new_probed_device(&dev->i2c_adap, &info, addr_list); } static int saa7134_rc5_irq(struct saa7134_dev *dev) diff --git a/drivers/media/video/saa7134/saa7134-ts.c b/drivers/media/video/saa7134/saa7134-ts.c index cc8b923afbc0..3fa652279ac0 100644 --- a/drivers/media/video/saa7134/saa7134-ts.c +++ b/drivers/media/video/saa7134/saa7134-ts.c @@ -65,35 +65,10 @@ static int buffer_activate(struct saa7134_dev *dev, /* start DMA */ saa7134_set_dmabits(dev); - mod_timer(&dev->ts_q.timeout, jiffies+BUFFER_TIMEOUT); + mod_timer(&dev->ts_q.timeout, jiffies+TS_BUFFER_TIMEOUT); - if (dev->ts_state == SAA7134_TS_BUFF_DONE) { - /* Clear TS cache */ - dev->buff_cnt = 0; - saa_writeb(SAA7134_TS_SERIAL1, 0x00); - saa_writeb(SAA7134_TS_SERIAL1, 0x03); - saa_writeb(SAA7134_TS_SERIAL1, 0x00); - saa_writeb(SAA7134_TS_SERIAL1, 0x01); - - /* TS clock non-inverted */ - saa_writeb(SAA7134_TS_SERIAL1, 0x00); - - /* Start TS stream */ - switch (saa7134_boards[dev->board].ts_type) { - case SAA7134_MPEG_TS_PARALLEL: - saa_writeb(SAA7134_TS_SERIAL0, 0x40); - saa_writeb(SAA7134_TS_PARALLEL, 0xec); - break; - case SAA7134_MPEG_TS_SERIAL: - saa_writeb(SAA7134_TS_SERIAL0, 0xd8); - saa_writeb(SAA7134_TS_PARALLEL, 0x6c); - saa_writeb(SAA7134_TS_PARALLEL_SERIAL, 0xbc); - saa_writeb(SAA7134_TS_SERIAL1, 0x02); - break; - } - - dev->ts_state = SAA7134_TS_STARTED; - } + if (!dev->ts_started) + saa7134_ts_start(dev); return 0; } @@ -104,7 +79,6 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, struct saa7134_dev *dev = q->priv_data; struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb); unsigned int lines, llength, size; - u32 control; int err; dprintk("buffer_prepare [%p,%s]\n",buf,v4l2_field_names[field]); @@ -121,8 +95,11 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, } if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); + dprintk("buffer_prepare: needs_init\n"); + buf->vb.width = llength; buf->vb.height = lines; buf->vb.size = size; @@ -139,23 +116,6 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, goto oops; } - dev->buff_cnt++; - - if (dev->buff_cnt == dev->ts.nr_bufs) { - dev->ts_state = SAA7134_TS_BUFF_DONE; - /* dma: setup channel 5 (= TS) */ - control = SAA7134_RS_CONTROL_BURST_16 | - SAA7134_RS_CONTROL_ME | - (buf->pt->dma >> 12); - - saa_writeb(SAA7134_TS_DMA0, (lines - 1) & 0xff); - saa_writeb(SAA7134_TS_DMA1, ((lines - 1) >> 8) & 0xff); - /* TSNOPIT=0, TSCOLAP=0 */ - saa_writeb(SAA7134_TS_DMA2, (((lines - 1) >> 16) & 0x3f) | 0x00); - saa_writel(SAA7134_RS_PITCH(5), TS_PACKET_SIZE); - saa_writel(SAA7134_RS_CONTROL(5), control); - } - buf->vb.state = VIDEOBUF_PREPARED; buf->activate = buffer_activate; buf->vb.field = field; @@ -175,8 +135,7 @@ buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) if (0 == *count) *count = dev->ts.nr_bufs; *count = saa7134_buffer_count(*size,*count); - dev->buff_cnt = 0; - dev->ts_state = SAA7134_TS_STOPPED; + return 0; } @@ -193,11 +152,9 @@ static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb) struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb); struct saa7134_dev *dev = q->priv_data; - if (dev->ts_state == SAA7134_TS_STARTED) { - /* Stop TS transport */ - saa_writeb(SAA7134_TS_PARALLEL, 0x6c); - dev->ts_state = SAA7134_TS_STOPPED; - } + if (dev->ts_started) + saa7134_ts_stop(dev); + saa7134_dma_free(q,buf); } @@ -214,7 +171,7 @@ EXPORT_SYMBOL_GPL(saa7134_ts_qops); static unsigned int tsbufs = 8; module_param(tsbufs, int, 0444); -MODULE_PARM_DESC(tsbufs,"number of ts buffers, range 2-32"); +MODULE_PARM_DESC(tsbufs, "number of ts buffers for read/write IO, range 2-32"); static unsigned int ts_nr_packets = 64; module_param(ts_nr_packets, int, 0444); @@ -256,6 +213,7 @@ int saa7134_ts_init1(struct saa7134_dev *dev) dev->ts_q.timeout.data = (unsigned long)(&dev->ts_q); dev->ts_q.dev = dev; dev->ts_q.need_two = 1; + dev->ts_started = 0; saa7134_pgtable_alloc(dev->pci,&dev->ts.pt_ts); /* init TS hw */ @@ -264,13 +222,67 @@ int saa7134_ts_init1(struct saa7134_dev *dev) return 0; } +/* Function for stop TS */ +int saa7134_ts_stop(struct saa7134_dev *dev) +{ + dprintk("TS stop\n"); + + BUG_ON(!dev->ts_started); + + /* Stop TS stream */ + switch (saa7134_boards[dev->board].ts_type) { + case SAA7134_MPEG_TS_PARALLEL: + saa_writeb(SAA7134_TS_PARALLEL, 0x6c); + dev->ts_started = 0; + break; + case SAA7134_MPEG_TS_SERIAL: + saa_writeb(SAA7134_TS_SERIAL0, 0x40); + dev->ts_started = 0; + break; + } + return 0; +} + +/* Function for start TS */ +int saa7134_ts_start(struct saa7134_dev *dev) +{ + dprintk("TS start\n"); + + BUG_ON(dev->ts_started); + + saa_writeb(SAA7134_TS_SERIAL1, 0x00); + saa_writeb(SAA7134_TS_SERIAL1, 0x03); + saa_writeb(SAA7134_TS_SERIAL1, 0x00); + saa_writeb(SAA7134_TS_SERIAL1, 0x01); + + /* TS clock non-inverted */ + saa_writeb(SAA7134_TS_SERIAL1, 0x00); + + /* Start TS stream */ + switch (saa7134_boards[dev->board].ts_type) { + case SAA7134_MPEG_TS_PARALLEL: + saa_writeb(SAA7134_TS_SERIAL0, 0x40); + saa_writeb(SAA7134_TS_PARALLEL, 0xec); + break; + case SAA7134_MPEG_TS_SERIAL: + saa_writeb(SAA7134_TS_SERIAL0, 0xd8); + saa_writeb(SAA7134_TS_PARALLEL, 0x6c); + saa_writeb(SAA7134_TS_PARALLEL_SERIAL, 0xbc); + saa_writeb(SAA7134_TS_SERIAL1, 0x02); + break; + } + + dev->ts_started = 1; + + return 0; +} + int saa7134_ts_fini(struct saa7134_dev *dev) { saa7134_pgtable_free(dev->pci,&dev->ts.pt_ts); return 0; } - void saa7134_irq_ts_done(struct saa7134_dev *dev, unsigned long status) { enum v4l2_field field; diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 493cad941460..ba87128542e0 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -1057,6 +1057,7 @@ static int buffer_prepare(struct videobuf_queue *q, buf->vb.field = field; buf->fmt = fh->fmt; buf->pt = &fh->pt_cap; + dev->video_q.curr = NULL; err = videobuf_iolock(q,&buf->vb,&dev->ovbuf); if (err) @@ -1423,11 +1424,13 @@ video_poll(struct file *file, struct poll_table_struct *wait) { struct saa7134_fh *fh = file->private_data; struct videobuf_buffer *buf = NULL; + unsigned int rc = 0; if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) return videobuf_poll_stream(file, &fh->vbi, wait); if (res_check(fh,RESOURCE_VIDEO)) { + mutex_lock(&fh->cap.vb_lock); if (!list_empty(&fh->cap.stream)) buf = list_entry(fh->cap.stream.next, struct videobuf_buffer, stream); } else { @@ -1446,13 +1449,14 @@ video_poll(struct file *file, struct poll_table_struct *wait) } if (!buf) - return POLLERR; + goto err; poll_wait(file, &buf->done, wait); if (buf->state == VIDEOBUF_DONE || buf->state == VIDEOBUF_ERROR) - return POLLIN|POLLRDNORM; - return 0; + rc = POLLIN|POLLRDNORM; + mutex_unlock(&fh->cap.vb_lock); + return rc; err: mutex_unlock(&fh->cap.vb_lock); @@ -1636,15 +1640,8 @@ static int saa7134_try_fmt_vid_cap(struct file *file, void *priv, } f->fmt.pix.field = field; - if (f->fmt.pix.width < 48) - f->fmt.pix.width = 48; - if (f->fmt.pix.height < 32) - f->fmt.pix.height = 32; - if (f->fmt.pix.width > maxw) - f->fmt.pix.width = maxw; - if (f->fmt.pix.height > maxh) - f->fmt.pix.height = maxh; - f->fmt.pix.width &= ~0x03; + v4l_bound_align_image(&f->fmt.pix.width, 48, maxw, 2, + &f->fmt.pix.height, 32, maxh, 0, 0); f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3; f->fmt.pix.sizeimage = diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 0cbaf90d4874..82268848f26a 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -252,7 +252,7 @@ struct saa7134_format { #define SAA7134_BOARD_BEHOLD_505FM 126 #define SAA7134_BOARD_BEHOLD_507_9FM 127 #define SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM 128 -#define SAA7134_BOARD_BEHOLD_607_9FM 129 +#define SAA7134_BOARD_BEHOLD_607FM_MK3 129 #define SAA7134_BOARD_BEHOLD_M6 130 #define SAA7134_BOARD_TWINHAN_DTV_DVB_3056 131 #define SAA7134_BOARD_GENIUS_TVGO_A11MCE 132 @@ -280,6 +280,18 @@ struct saa7134_format { #define SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS 154 #define SAA7134_BOARD_HAUPPAUGE_HVR1120 155 #define SAA7134_BOARD_HAUPPAUGE_HVR1110R3 156 +#define SAA7134_BOARD_AVERMEDIA_STUDIO_507UA 157 +#define SAA7134_BOARD_AVERMEDIA_CARDBUS_501 158 +#define SAA7134_BOARD_BEHOLD_505RDS 159 +#define SAA7134_BOARD_BEHOLD_507RDS_MK3 160 +#define SAA7134_BOARD_BEHOLD_507RDS_MK5 161 +#define SAA7134_BOARD_BEHOLD_607FM_MK5 162 +#define SAA7134_BOARD_BEHOLD_609FM_MK3 163 +#define SAA7134_BOARD_BEHOLD_609FM_MK5 164 +#define SAA7134_BOARD_BEHOLD_607RDS_MK3 165 +#define SAA7134_BOARD_BEHOLD_607RDS_MK5 166 +#define SAA7134_BOARD_BEHOLD_609RDS_MK3 167 +#define SAA7134_BOARD_BEHOLD_609RDS_MK5 168 #define SAA7134_MAXBOARDS 32 #define SAA7134_INPUT_MAX 8 @@ -364,6 +376,7 @@ struct saa7134_board { #define INTERLACE_OFF 2 #define BUFFER_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */ +#define TS_BUFFER_TIMEOUT msecs_to_jiffies(1000) /* 1 second */ struct saa7134_dev; struct saa7134_dma; @@ -480,12 +493,6 @@ struct saa7134_mpeg_ops { void (*signal_change)(struct saa7134_dev *dev); }; -enum saa7134_ts_status { - SAA7134_TS_STOPPED, - SAA7134_TS_BUFF_DONE, - SAA7134_TS_STARTED, -}; - /* global device status */ struct saa7134_dev { struct list_head devlist; @@ -580,8 +587,7 @@ struct saa7134_dev { /* SAA7134_MPEG_* */ struct saa7134_ts ts; struct saa7134_dmaqueue ts_q; - enum saa7134_ts_status ts_state; - unsigned int buff_cnt; + int ts_started; struct saa7134_mpeg_ops *mops; /* SAA7134_MPEG_EMPRESS only */ @@ -739,6 +745,9 @@ void saa7134_ts_unregister(struct saa7134_mpeg_ops *ops); int saa7134_ts_init_hw(struct saa7134_dev *dev); +int saa7134_ts_start(struct saa7134_dev *dev); +int saa7134_ts_stop(struct saa7134_dev *dev); + /* ----------------------------------------------------------- */ /* saa7134-vbi.c */ @@ -786,7 +795,7 @@ void saa7134_irq_oss_done(struct saa7134_dev *dev, unsigned long status); int saa7134_input_init1(struct saa7134_dev *dev); void saa7134_input_fini(struct saa7134_dev *dev); void saa7134_input_irq(struct saa7134_dev *dev); -void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir); +void saa7134_probe_i2c_ir(struct saa7134_dev *dev); void saa7134_ir_start(struct saa7134_dev *dev, struct card_ir *ir); void saa7134_ir_stop(struct saa7134_dev *dev); diff --git a/drivers/media/video/se401.c b/drivers/media/video/se401.c index 5990ab38a124..c8f05297d0f0 100644 --- a/drivers/media/video/se401.c +++ b/drivers/media/video/se401.c @@ -38,7 +38,7 @@ static const char version[] = "0.24"; static int flickerless; static int video_nr = -1; -static struct usb_device_id device_table [] = { +static struct usb_device_id device_table[] = { { USB_DEVICE(0x03e8, 0x0004) },/* Endpoints/Aox SE401 */ { USB_DEVICE(0x0471, 0x030b) },/* Philips PCVC665K */ { USB_DEVICE(0x047d, 0x5001) },/* Kensington 67014 */ @@ -53,7 +53,8 @@ MODULE_AUTHOR("Jeroen Vreeken "); MODULE_DESCRIPTION("SE401 USB Camera Driver"); MODULE_LICENSE("GPL"); module_param(flickerless, int, 0); -MODULE_PARM_DESC(flickerless, "Net frequency to adjust exposure time to (0/50/60)"); +MODULE_PARM_DESC(flickerless, + "Net frequency to adjust exposure time to (0/50/60)"); module_param(video_nr, int, 0); static struct usb_driver se401_driver; @@ -78,8 +79,8 @@ static void *rvmalloc(unsigned long size) adr = (unsigned long) mem; while (size > 0) { SetPageReserved(vmalloc_to_page((void *)adr)); - adr += PAGE_SIZE; - size -= PAGE_SIZE; + adr += PAGE_SIZE; + size -= PAGE_SIZE; } return mem; @@ -95,8 +96,8 @@ static void rvfree(void *mem, unsigned long size) adr = (unsigned long) mem; while ((long) size > 0) { ClearPageReserved(vmalloc_to_page((void *)adr)); - adr += PAGE_SIZE; - size -= PAGE_SIZE; + adr += PAGE_SIZE; + size -= PAGE_SIZE; } vfree(mem); } @@ -112,7 +113,7 @@ static void rvfree(void *mem, unsigned long size) static int se401_sndctrl(int set, struct usb_se401 *se401, unsigned short req, unsigned short value, unsigned char *cp, int size) { - return usb_control_msg ( + return usb_control_msg( se401->dev, set ? usb_sndctrlpipe(se401->dev, 0) : usb_rcvctrlpipe(se401->dev, 0), req, @@ -132,7 +133,7 @@ static int se401_set_feature(struct usb_se401 *se401, unsigned short selector, and the param in index, but in the logs of the windows driver they do this the other way around... */ - return usb_control_msg ( + return usb_control_msg( se401->dev, usb_sndctrlpipe(se401->dev, 0), SE401_REQ_SET_EXT_FEATURE, @@ -152,7 +153,7 @@ static unsigned short se401_get_feature(struct usb_se401 *se401, wrong here to.... */ unsigned char cp[2]; - usb_control_msg ( + usb_control_msg( se401->dev, usb_rcvctrlpipe(se401->dev, 0), SE401_REQ_GET_EXT_FEATURE, @@ -175,46 +176,51 @@ static unsigned short se401_get_feature(struct usb_se401 *se401, static int se401_send_pict(struct usb_se401 *se401) { - se401_set_feature(se401, HV7131_REG_TITL, se401->expose_l);/* integration time low */ - se401_set_feature(se401, HV7131_REG_TITM, se401->expose_m);/* integration time mid */ - se401_set_feature(se401, HV7131_REG_TITU, se401->expose_h);/* integration time mid */ - se401_set_feature(se401, HV7131_REG_ARLV, se401->resetlevel);/* reset level value */ - se401_set_feature(se401, HV7131_REG_ARCG, se401->rgain);/* red color gain */ - se401_set_feature(se401, HV7131_REG_AGCG, se401->ggain);/* green color gain */ - se401_set_feature(se401, HV7131_REG_ABCG, se401->bgain);/* blue color gain */ + /* integration time low */ + se401_set_feature(se401, HV7131_REG_TITL, se401->expose_l); + /* integration time mid */ + se401_set_feature(se401, HV7131_REG_TITM, se401->expose_m); + /* integration time mid */ + se401_set_feature(se401, HV7131_REG_TITU, se401->expose_h); + /* reset level value */ + se401_set_feature(se401, HV7131_REG_ARLV, se401->resetlevel); + /* red color gain */ + se401_set_feature(se401, HV7131_REG_ARCG, se401->rgain); + /* green color gain */ + se401_set_feature(se401, HV7131_REG_AGCG, se401->ggain); + /* blue color gain */ + se401_set_feature(se401, HV7131_REG_ABCG, se401->bgain); return 0; } static void se401_set_exposure(struct usb_se401 *se401, int brightness) { - int integration=brightness<<5; + int integration = brightness << 5; - if (flickerless==50) { - integration=integration-integration%106667; - } - if (flickerless==60) { - integration=integration-integration%88889; - } - se401->brightness=integration>>5; - se401->expose_h=(integration>>16)&0xff; - se401->expose_m=(integration>>8)&0xff; - se401->expose_l=integration&0xff; + if (flickerless == 50) + integration = integration-integration % 106667; + if (flickerless == 60) + integration = integration-integration % 88889; + se401->brightness = integration >> 5; + se401->expose_h = (integration >> 16) & 0xff; + se401->expose_m = (integration >> 8) & 0xff; + se401->expose_l = integration & 0xff; } static int se401_get_pict(struct usb_se401 *se401, struct video_picture *p) { - p->brightness=se401->brightness; - if (se401->enhance) { - p->whiteness=32768; - } else { - p->whiteness=0; - } - p->colour=65535; - p->contrast=65535; - p->hue=se401->rgain<<10; - p->palette=se401->palette; - p->depth=3; /* rgb24 */ + p->brightness = se401->brightness; + if (se401->enhance) + p->whiteness = 32768; + else + p->whiteness = 0; + + p->colour = 65535; + p->contrast = 65535; + p->hue = se401->rgain << 10; + p->palette = se401->palette; + p->depth = 3; /* rgb24 */ return 0; } @@ -223,20 +229,19 @@ static int se401_set_pict(struct usb_se401 *se401, struct video_picture *p) { if (p->palette != VIDEO_PALETTE_RGB24) return 1; - se401->palette=p->palette; - if (p->hue!=se401->hue) { - se401->rgain= p->hue>>10; - se401->bgain= 0x40-(p->hue>>10); - se401->hue=p->hue; + se401->palette = p->palette; + if (p->hue != se401->hue) { + se401->rgain = p->hue >> 10; + se401->bgain = 0x40-(p->hue >> 10); + se401->hue = p->hue; } - if (p->brightness!=se401->brightness) { + if (p->brightness != se401->brightness) se401_set_exposure(se401, p->brightness); - } - if (p->whiteness>=32768) { - se401->enhance=1; - } else { - se401->enhance=0; - } + + if (p->whiteness >= 32768) + se401->enhance = 1; + else + se401->enhance = 0; se401_send_pict(se401); se401_send_pict(se401); return 0; @@ -249,7 +254,7 @@ static int se401_set_pict(struct usb_se401 *se401, struct video_picture *p) static void se401_auto_resetlevel(struct usb_se401 *se401) { unsigned int ahrc, alrc; - int oldreset=se401->resetlevel; + int oldreset = se401->resetlevel; /* For some reason this normally read-only register doesn't get reset to zero after reading them just once... @@ -258,24 +263,24 @@ static void se401_auto_resetlevel(struct usb_se401 *se401) se401_get_feature(se401, HV7131_REG_HIREFNOL); se401_get_feature(se401, HV7131_REG_LOREFNOH); se401_get_feature(se401, HV7131_REG_LOREFNOL); - ahrc=256*se401_get_feature(se401, HV7131_REG_HIREFNOH) + + ahrc = 256*se401_get_feature(se401, HV7131_REG_HIREFNOH) + se401_get_feature(se401, HV7131_REG_HIREFNOL); - alrc=256*se401_get_feature(se401, HV7131_REG_LOREFNOH) + + alrc = 256*se401_get_feature(se401, HV7131_REG_LOREFNOH) + se401_get_feature(se401, HV7131_REG_LOREFNOL); /* Not an exact science, but it seems to work pretty well... */ if (alrc > 10) { - while (alrc>=10 && se401->resetlevel < 63) { + while (alrc >= 10 && se401->resetlevel < 63) { se401->resetlevel++; - alrc /=2; + alrc /= 2; } } else if (ahrc > 20) { - while (ahrc>=20 && se401->resetlevel > 0) { + while (ahrc >= 20 && se401->resetlevel > 0) { se401->resetlevel--; - ahrc /=2; + ahrc /= 2; } } - if (se401->resetlevel!=oldreset) + if (se401->resetlevel != oldreset) se401_set_feature(se401, HV7131_REG_ARLV, se401->resetlevel); return; @@ -300,21 +305,22 @@ static void se401_button_irq(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", __func__, urb->status); + dbg("%s - urb shutting down with status: %d", + __func__, urb->status); return; default: - dbg("%s - nonzero urb status received: %d", __func__, urb->status); + dbg("%s - nonzero urb status received: %d", + __func__, urb->status); goto exit; } - if (urb->actual_length >=2) { + if (urb->actual_length >= 2) if (se401->button) - se401->buttonpressed=1; - } + se401->buttonpressed = 1; exit: - status = usb_submit_urb (urb, GFP_ATOMIC); + status = usb_submit_urb(urb, GFP_ATOMIC); if (status) - err ("%s - usb_submit_urb failed with result %d", + err("%s - usb_submit_urb failed with result %d", __func__, status); } @@ -336,55 +342,52 @@ static void se401_video_irq(struct urb *urb) keeps sending them forever... */ if (length && !urb->status) { - se401->nullpackets=0; - switch(se401->scratch[se401->scratch_next].state) { - case BUFFER_READY: - case BUFFER_BUSY: { - se401->dropped++; - break; - } - case BUFFER_UNUSED: { - memcpy(se401->scratch[se401->scratch_next].data, (unsigned char *)urb->transfer_buffer, length); - se401->scratch[se401->scratch_next].state=BUFFER_READY; - se401->scratch[se401->scratch_next].offset=se401->bayeroffset; - se401->scratch[se401->scratch_next].length=length; - if (waitqueue_active(&se401->wq)) { - wake_up_interruptible(&se401->wq); - } - se401->scratch_overflow=0; - se401->scratch_next++; - if (se401->scratch_next>=SE401_NUMSCRATCH) - se401->scratch_next=0; - break; - } - } - se401->bayeroffset+=length; - if (se401->bayeroffset>=se401->cheight*se401->cwidth) { - se401->bayeroffset=0; + se401->nullpackets = 0; + switch (se401->scratch[se401->scratch_next].state) { + case BUFFER_READY: + case BUFFER_BUSY: + se401->dropped++; + break; + case BUFFER_UNUSED: + memcpy(se401->scratch[se401->scratch_next].data, + (unsigned char *)urb->transfer_buffer, length); + se401->scratch[se401->scratch_next].state + = BUFFER_READY; + se401->scratch[se401->scratch_next].offset + = se401->bayeroffset; + se401->scratch[se401->scratch_next].length = length; + if (waitqueue_active(&se401->wq)) + wake_up_interruptible(&se401->wq); + se401->scratch_overflow = 0; + se401->scratch_next++; + if (se401->scratch_next >= SE401_NUMSCRATCH) + se401->scratch_next = 0; + break; } + se401->bayeroffset += length; + if (se401->bayeroffset >= se401->cheight * se401->cwidth) + se401->bayeroffset = 0; } else { se401->nullpackets++; - if (se401->nullpackets > SE401_MAX_NULLPACKETS) { - if (waitqueue_active(&se401->wq)) { + if (se401->nullpackets > SE401_MAX_NULLPACKETS) + if (waitqueue_active(&se401->wq)) wake_up_interruptible(&se401->wq); - } - } } /* Resubmit urb for new data */ - urb->status=0; - urb->dev=se401->dev; - if(usb_submit_urb(urb, GFP_KERNEL)) + urb->status = 0; + urb->dev = se401->dev; + if (usb_submit_urb(urb, GFP_KERNEL)) dev_info(&urb->dev->dev, "urb burned down\n"); return; } static void se401_send_size(struct usb_se401 *se401, int width, int height) { - int i=0; - int mode=0x03; /* No compression */ - int sendheight=height; - int sendwidth=width; + int i = 0; + int mode = 0x03; /* No compression */ + int sendheight = height; + int sendwidth = width; /* JangGu compression can only be used with the camera supported sizes, but bayer seems to work with any size that fits on the sensor. @@ -392,18 +395,21 @@ static void se401_send_size(struct usb_se401 *se401, int width, int height) 4 or 16 times subcapturing, if not we use uncompressed bayer data but this will result in cutouts of the maximum size.... */ - while (isizes && !(se401->width[i]==width && se401->height[i]==height)) + while (i < se401->sizes && !(se401->width[i] == width && + se401->height[i] == height)) i++; - while (isizes) { - if (se401->width[i]==width*2 && se401->height[i]==height*2) { - sendheight=se401->height[i]; - sendwidth=se401->width[i]; - mode=0x40; + while (i < se401->sizes) { + if (se401->width[i] == width * 2 && + se401->height[i] == height * 2) { + sendheight = se401->height[i]; + sendwidth = se401->width[i]; + mode = 0x40; } - if (se401->width[i]==width*4 && se401->height[i]==height*4) { - sendheight=se401->height[i]; - sendwidth=se401->width[i]; - mode=0x42; + if (se401->width[i] == width * 4 && + se401->height[i] == height * 4) { + sendheight = se401->height[i]; + sendwidth = se401->width[i]; + mode = 0x42; } i++; } @@ -412,13 +418,10 @@ static void se401_send_size(struct usb_se401 *se401, int width, int height) se401_sndctrl(1, se401, SE401_REQ_SET_HEIGHT, sendheight, NULL, 0); se401_set_feature(se401, SE401_OPERATINGMODE, mode); - if (mode==0x03) { - se401->format=FMT_BAYER; - } else { - se401->format=FMT_JANGGU; - } - - return; + if (mode == 0x03) + se401->format = FMT_BAYER; + else + se401->format = FMT_JANGGU; } /* @@ -429,29 +432,31 @@ static void se401_send_size(struct usb_se401 *se401, int width, int height) static int se401_start_stream(struct usb_se401 *se401) { struct urb *urb; - int err=0, i; - se401->streaming=1; + int err = 0, i; + se401->streaming = 1; se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 1, NULL, 0); se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0); /* Set picture settings */ - se401_set_feature(se401, HV7131_REG_MODE_B, 0x05);/*windowed + pix intg */ + /* windowed + pix intg */ + se401_set_feature(se401, HV7131_REG_MODE_B, 0x05); se401_send_pict(se401); se401_send_size(se401, se401->cwidth, se401->cheight); - se401_sndctrl(1, se401, SE401_REQ_START_CONTINUOUS_CAPTURE, 0, NULL, 0); + se401_sndctrl(1, se401, SE401_REQ_START_CONTINUOUS_CAPTURE, + 0, NULL, 0); /* Do some memory allocation */ - for (i=0; iframe[i].data=se401->fbuf + i * se401->maxframesize; - se401->frame[i].curpix=0; + for (i = 0; i < SE401_NUMFRAMES; i++) { + se401->frame[i].data = se401->fbuf + i * se401->maxframesize; + se401->frame[i].curpix = 0; } - for (i=0; isbuf[i].data=kmalloc(SE401_PACKETSIZE, GFP_KERNEL); + for (i = 0; i < SE401_NUMSBUF; i++) { + se401->sbuf[i].data = kmalloc(SE401_PACKETSIZE, GFP_KERNEL); if (!se401->sbuf[i].data) { - for(i = i - 1; i >= 0; i--) { + for (i = i - 1; i >= 0; i--) { kfree(se401->sbuf[i].data); se401->sbuf[i].data = NULL; } @@ -459,26 +464,26 @@ static int se401_start_stream(struct usb_se401 *se401) } } - se401->bayeroffset=0; - se401->scratch_next=0; - se401->scratch_use=0; - se401->scratch_overflow=0; - for (i=0; iscratch[i].data=kmalloc(SE401_PACKETSIZE, GFP_KERNEL); + se401->bayeroffset = 0; + se401->scratch_next = 0; + se401->scratch_use = 0; + se401->scratch_overflow = 0; + for (i = 0; i < SE401_NUMSCRATCH; i++) { + se401->scratch[i].data = kmalloc(SE401_PACKETSIZE, GFP_KERNEL); if (!se401->scratch[i].data) { - for(i = i - 1; i >= 0; i--) { + for (i = i - 1; i >= 0; i--) { kfree(se401->scratch[i].data); se401->scratch[i].data = NULL; } goto nomem_sbuf; } - se401->scratch[i].state=BUFFER_UNUSED; + se401->scratch[i].state = BUFFER_UNUSED; } - for (i=0; i= 0; i--) { + for (i = 0; i < SE401_NUMSBUF; i++) { + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) { + for (i = i - 1; i >= 0; i--) { usb_kill_urb(se401->urb[i]); usb_free_urb(se401->urb[i]); se401->urb[i] = NULL; @@ -492,24 +497,24 @@ static int se401_start_stream(struct usb_se401 *se401) se401_video_irq, se401); - se401->urb[i]=urb; + se401->urb[i] = urb; - err=usb_submit_urb(se401->urb[i], GFP_KERNEL); - if(err) + err = usb_submit_urb(se401->urb[i], GFP_KERNEL); + if (err) err("urb burned down"); } - se401->framecount=0; + se401->framecount = 0; return 0; nomem_scratch: - for (i=0; iscratch[i].data); se401->scratch[i].data = NULL; } nomem_sbuf: - for (i=0; isbuf[i].data); se401->sbuf[i].data = NULL; } @@ -523,22 +528,23 @@ static int se401_stop_stream(struct usb_se401 *se401) if (!se401->streaming || !se401->dev) return 1; - se401->streaming=0; + se401->streaming = 0; se401_sndctrl(1, se401, SE401_REQ_STOP_CONTINUOUS_CAPTURE, 0, NULL, 0); se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 0, NULL, 0); se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 0, NULL, 0); - for (i=0; iurb[i]) { - usb_kill_urb(se401->urb[i]); - usb_free_urb(se401->urb[i]); - se401->urb[i]=NULL; - kfree(se401->sbuf[i].data); - } - for (i=0; iurb[i]) { + usb_kill_urb(se401->urb[i]); + usb_free_urb(se401->urb[i]); + se401->urb[i] = NULL; + kfree(se401->sbuf[i].data); + } + for (i = 0; i < SE401_NUMSCRATCH; i++) { kfree(se401->scratch[i].data); - se401->scratch[i].data=NULL; + se401->scratch[i].data = NULL; } return 0; @@ -546,9 +552,9 @@ static int se401_stop_stream(struct usb_se401 *se401) static int se401_set_size(struct usb_se401 *se401, int width, int height) { - int wasstreaming=se401->streaming; + int wasstreaming = se401->streaming; /* Check to see if we need to change */ - if (se401->cwidth==width && se401->cheight==height) + if (se401->cwidth == width && se401->cheight == height) return 0; /* Check for a valid mode */ @@ -556,16 +562,16 @@ static int se401_set_size(struct usb_se401 *se401, int width, int height) return 1; if ((width & 1) || (height & 1)) return 1; - if (width>se401->width[se401->sizes-1]) + if (width > se401->width[se401->sizes-1]) return 1; - if (height>se401->height[se401->sizes-1]) + if (height > se401->height[se401->sizes-1]) return 1; /* Stop a current stream and start it again at the new size */ if (wasstreaming) se401_stop_stream(se401); - se401->cwidth=width; - se401->cheight=height; + se401->cwidth = width; + se401->cheight = height; if (wasstreaming) se401_start_stream(se401); return 0; @@ -586,68 +592,68 @@ static int se401_set_size(struct usb_se401 *se401, int width, int height) static inline void enhance_picture(unsigned char *frame, int len) { while (len--) { - *frame=(((*frame^255)*(*frame^255))/255)^255; + *frame = (((*frame^255)*(*frame^255))/255)^255; frame++; } } static inline void decode_JangGu_integrate(struct usb_se401 *se401, int data) { - struct se401_frame *frame=&se401->frame[se401->curframe]; - int linelength=se401->cwidth*3; + struct se401_frame *frame = &se401->frame[se401->curframe]; + int linelength = se401->cwidth * 3; if (frame->curlinepix >= linelength) { - frame->curlinepix=0; - frame->curline+=linelength; + frame->curlinepix = 0; + frame->curline += linelength; } /* First three are absolute, all others relative. * Format is rgb from right to left (mirrorred image), * we flip it to get bgr from left to right. */ - if (frame->curlinepix < 3) { - *(frame->curline-frame->curlinepix)=1+data*4; - } else { - *(frame->curline-frame->curlinepix)= - *(frame->curline-frame->curlinepix+3)+data*4; - } + if (frame->curlinepix < 3) + *(frame->curline-frame->curlinepix) = 1 + data * 4; + else + *(frame->curline-frame->curlinepix) = + *(frame->curline-frame->curlinepix + 3) + data * 4; frame->curlinepix++; } -static inline void decode_JangGu_vlc (struct usb_se401 *se401, unsigned char *data, int bit_exp, int packetlength) +static inline void decode_JangGu_vlc(struct usb_se401 *se401, + unsigned char *data, int bit_exp, int packetlength) { - int pos=0; - int vlc_cod=0; - int vlc_size=0; - int vlc_data=0; + int pos = 0; + int vlc_cod = 0; + int vlc_size = 0; + int vlc_data = 0; int bit_cur; int bit; - data+=4; + data += 4; while (pos < packetlength) { - bit_cur=8; + bit_cur = 8; while (bit_cur && bit_exp) { - bit=((*data)>>(bit_cur-1))&1; + bit = ((*data) >> (bit_cur-1))&1; if (!vlc_cod) { if (bit) { vlc_size++; } else { - if (!vlc_size) { + if (!vlc_size) decode_JangGu_integrate(se401, 0); - } else { - vlc_cod=2; - vlc_data=0; + else { + vlc_cod = 2; + vlc_data = 0; } } } else { - if (vlc_cod==2) { + if (vlc_cod == 2) { if (!bit) - vlc_data = -(1<data; - int len=buffer->length; - int bit_exp=0, pix_exp=0, frameinfo=0, packetlength=0, size; - int datapos=0; + unsigned char *data = buffer->data; + int len = buffer->length; + int bit_exp = 0, pix_exp = 0, frameinfo = 0, packetlength = 0, size; + int datapos = 0; /* New image? */ if (!se401->frame[se401->curframe].curpix) { - se401->frame[se401->curframe].curlinepix=0; - se401->frame[se401->curframe].curline= + se401->frame[se401->curframe].curlinepix = 0; + se401->frame[se401->curframe].curline = se401->frame[se401->curframe].data+ - se401->cwidth*3-1; - if (se401->frame[se401->curframe].grabstate==FRAME_READY) - se401->frame[se401->curframe].grabstate=FRAME_GRABBING; - se401->vlcdatapos=0; + se401->cwidth * 3 - 1; + if (se401->frame[se401->curframe].grabstate == FRAME_READY) + se401->frame[se401->curframe].grabstate = FRAME_GRABBING; + se401->vlcdatapos = 0; } while (datapos < len) { - size=1024-se401->vlcdatapos; + size = 1024 - se401->vlcdatapos; if (size+datapos > len) - size=len-datapos; + size = len-datapos; memcpy(se401->vlcdata+se401->vlcdatapos, data+datapos, size); - se401->vlcdatapos+=size; - packetlength=0; + se401->vlcdatapos += size; + packetlength = 0; if (se401->vlcdatapos >= 4) { - bit_exp=se401->vlcdata[3]+(se401->vlcdata[2]<<8); - pix_exp=se401->vlcdata[1]+((se401->vlcdata[0]&0x3f)<<8); - frameinfo=se401->vlcdata[0]&0xc0; - packetlength=((bit_exp+47)>>4)<<1; + bit_exp = se401->vlcdata[3] + (se401->vlcdata[2] << 8); + pix_exp = se401->vlcdata[1] + + ((se401->vlcdata[0] & 0x3f) << 8); + frameinfo = se401->vlcdata[0] & 0xc0; + packetlength = ((bit_exp + 47) >> 4) << 1; if (packetlength > 1024) { - se401->vlcdatapos=0; - datapos=len; - packetlength=0; + se401->vlcdatapos = 0; + datapos = len; + packetlength = 0; se401->error++; - se401->frame[se401->curframe].curpix=0; + se401->frame[se401->curframe].curpix = 0; } } if (packetlength && se401->vlcdatapos >= packetlength) { - decode_JangGu_vlc(se401, se401->vlcdata, bit_exp, packetlength); - se401->frame[se401->curframe].curpix+=pix_exp*3; - datapos+=size-(se401->vlcdatapos-packetlength); - se401->vlcdatapos=0; - if (se401->frame[se401->curframe].curpix>=se401->cwidth*se401->cheight*3) { - if (se401->frame[se401->curframe].curpix==se401->cwidth*se401->cheight*3) { - if (se401->frame[se401->curframe].grabstate==FRAME_GRABBING) { - se401->frame[se401->curframe].grabstate=FRAME_DONE; + decode_JangGu_vlc(se401, se401->vlcdata, bit_exp, + packetlength); + se401->frame[se401->curframe].curpix += pix_exp * 3; + datapos += size-(se401->vlcdatapos-packetlength); + se401->vlcdatapos = 0; + if (se401->frame[se401->curframe].curpix >= se401->cwidth * se401->cheight * 3) { + if (se401->frame[se401->curframe].curpix == se401->cwidth * se401->cheight * 3) { + if (se401->frame[se401->curframe].grabstate == FRAME_GRABBING) { + se401->frame[se401->curframe].grabstate = FRAME_DONE; se401->framecount++; se401->readcount++; } - if (se401->frame[(se401->curframe+1)&(SE401_NUMFRAMES-1)].grabstate==FRAME_READY) { - se401->curframe=(se401->curframe+1) & (SE401_NUMFRAMES-1); - } - } else { + if (se401->frame[(se401->curframe + 1) & (SE401_NUMFRAMES - 1)].grabstate == FRAME_READY) + se401->curframe = (se401->curframe + 1) & (SE401_NUMFRAMES - 1); + } else se401->error++; - } - se401->frame[se401->curframe].curpix=0; - datapos=len; + se401->frame[se401->curframe].curpix = 0; + datapos = len; } - } else { - datapos+=size; - } + } else + datapos += size; } } -static inline void decode_bayer (struct usb_se401 *se401, struct se401_scratch *buffer) +static inline void decode_bayer(struct usb_se401 *se401, + struct se401_scratch *buffer) { - unsigned char *data=buffer->data; - int len=buffer->length; - int offset=buffer->offset; - int datasize=se401->cwidth*se401->cheight; - struct se401_frame *frame=&se401->frame[se401->curframe]; - - unsigned char *framedata=frame->data, *curline, *nextline; - int width=se401->cwidth; - int blineoffset=0, bline; - int linelength=width*3, i; + unsigned char *data = buffer->data; + int len = buffer->length; + int offset = buffer->offset; + int datasize = se401->cwidth * se401->cheight; + struct se401_frame *frame = &se401->frame[se401->curframe]; + unsigned char *framedata = frame->data, *curline, *nextline; + int width = se401->cwidth; + int blineoffset = 0, bline; + int linelength = width * 3, i; - if (frame->curpix==0) { - if (frame->grabstate==FRAME_READY) { - frame->grabstate=FRAME_GRABBING; - } - frame->curline=framedata+linelength; - frame->curlinepix=0; + if (frame->curpix == 0) { + if (frame->grabstate == FRAME_READY) + frame->grabstate = FRAME_GRABBING; + + frame->curline = framedata + linelength; + frame->curlinepix = 0; } - if (offset!=frame->curpix) { + if (offset != frame->curpix) { /* Regard frame as lost :( */ - frame->curpix=0; + frame->curpix = 0; se401->error++; return; } /* Check if we have to much data */ - if (frame->curpix+len > datasize) { - len=datasize-frame->curpix; - } - if (se401->cheight%4) - blineoffset=1; - bline=frame->curpix/se401->cwidth+blineoffset; + if (frame->curpix + len > datasize) + len = datasize-frame->curpix; - curline=frame->curline; - nextline=curline+linelength; - if (nextline >= framedata+datasize*3) - nextline=curline; + if (se401->cheight % 4) + blineoffset = 1; + bline = frame->curpix / se401->cwidth+blineoffset; + + curline = frame->curline; + nextline = curline + linelength; + if (nextline >= framedata+datasize * 3) + nextline = curline; while (len) { - if (frame->curlinepix>=width) { - frame->curlinepix-=width; - bline=frame->curpix/width+blineoffset; - curline+=linelength*2; - nextline+=linelength*2; - if (curline >= framedata+datasize*3) { + if (frame->curlinepix >= width) { + frame->curlinepix -= width; + bline = frame->curpix / width + blineoffset; + curline += linelength*2; + nextline += linelength*2; + if (curline >= framedata+datasize * 3) { frame->curlinepix++; - curline-=3; - nextline-=3; + curline -= 3; + nextline -= 3; len--; data++; frame->curpix++; } if (nextline >= framedata+datasize*3) - nextline=curline; + nextline = curline; } - if ((bline&1)) { - if ((frame->curlinepix&1)) { - *(curline+2)=*data; - *(curline-1)=*data; - *(nextline+2)=*data; - *(nextline-1)=*data; + if (bline & 1) { + if (frame->curlinepix & 1) { + *(curline + 2) = *data; + *(curline - 1) = *data; + *(nextline + 2) = *data; + *(nextline - 1) = *data; } else { - *(curline+1)= - (*(curline+1)+*data)/2; - *(curline-2)= - (*(curline-2)+*data)/2; - *(nextline+1)=*data; - *(nextline-2)=*data; + *(curline + 1) = + (*(curline + 1) + *data) / 2; + *(curline-2) = + (*(curline - 2) + *data) / 2; + *(nextline + 1) = *data; + *(nextline - 2) = *data; } } else { - if ((frame->curlinepix&1)) { - *(curline+1)= - (*(curline+1)+*data)/2; - *(curline-2)= - (*(curline-2)+*data)/2; - *(nextline+1)=*data; - *(nextline-2)=*data; + if (frame->curlinepix & 1) { + *(curline + 1) = + (*(curline + 1) + *data) / 2; + *(curline - 2) = + (*(curline - 2) + *data) / 2; + *(nextline + 1) = *data; + *(nextline - 2) = *data; } else { - *curline=*data; - *(curline-3)=*data; - *nextline=*data; - *(nextline-3)=*data; + *curline = *data; + *(curline - 3) = *data; + *nextline = *data; + *(nextline - 3) = *data; } } frame->curlinepix++; - curline-=3; - nextline-=3; + curline -= 3; + nextline -= 3; len--; data++; frame->curpix++; } - frame->curline=curline; + frame->curline = curline; - if (frame->curpix>=datasize) { + if (frame->curpix >= datasize) { /* Fix the top line */ - framedata+=linelength; - for (i=0; icheight; i++) { - *framedata=*(framedata+3); - *(framedata+1)=*(framedata+4); - *(framedata+2)=*(framedata+5); - framedata+=linelength; + for (i = 0; i < se401->cheight; i++) { + *framedata = *(framedata + 3); + *(framedata + 1) = *(framedata + 4); + *(framedata + 2) = *(framedata + 5); + framedata += linelength; } - frame->curpix=0; - frame->grabstate=FRAME_DONE; + frame->curpix = 0; + frame->grabstate = FRAME_DONE; se401->framecount++; se401->readcount++; - if (se401->frame[(se401->curframe+1)&(SE401_NUMFRAMES-1)].grabstate==FRAME_READY) { - se401->curframe=(se401->curframe+1) & (SE401_NUMFRAMES-1); + if (se401->frame[(se401->curframe + 1) & + (SE401_NUMFRAMES - 1)].grabstate == FRAME_READY) { + se401->curframe = (se401->curframe+1) & + (SE401_NUMFRAMES-1); } } } @@ -845,72 +853,76 @@ static inline void decode_bayer (struct usb_se401 *se401, struct se401_scratch * static int se401_newframe(struct usb_se401 *se401, int framenr) { DECLARE_WAITQUEUE(wait, current); - int errors=0; + int errors = 0; while (se401->streaming && - (se401->frame[framenr].grabstate==FRAME_READY || - se401->frame[framenr].grabstate==FRAME_GRABBING) ) { - if(!se401->frame[framenr].curpix) { + (se401->frame[framenr].grabstate == FRAME_READY || + se401->frame[framenr].grabstate == FRAME_GRABBING)) { + if (!se401->frame[framenr].curpix) errors++; - } + wait_interruptible( - se401->scratch[se401->scratch_use].state!=BUFFER_READY, - &se401->wq, - &wait - ); + se401->scratch[se401->scratch_use].state != BUFFER_READY, + &se401->wq, &wait); if (se401->nullpackets > SE401_MAX_NULLPACKETS) { - se401->nullpackets=0; + se401->nullpackets = 0; dev_info(&se401->dev->dev, - "too many null length packets, restarting capture\n"); + "too many null length packets, restarting capture\n"); se401_stop_stream(se401); se401_start_stream(se401); } else { - if (se401->scratch[se401->scratch_use].state!=BUFFER_READY) { - se401->frame[framenr].grabstate=FRAME_ERROR; + if (se401->scratch[se401->scratch_use].state != + BUFFER_READY) { + se401->frame[framenr].grabstate = FRAME_ERROR; return -EIO; } - se401->scratch[se401->scratch_use].state=BUFFER_BUSY; - if (se401->format==FMT_JANGGU) { - decode_JangGu(se401, &se401->scratch[se401->scratch_use]); - } else { - decode_bayer(se401, &se401->scratch[se401->scratch_use]); - } - se401->scratch[se401->scratch_use].state=BUFFER_UNUSED; + se401->scratch[se401->scratch_use].state = BUFFER_BUSY; + if (se401->format == FMT_JANGGU) + decode_JangGu(se401, + &se401->scratch[se401->scratch_use]); + else + decode_bayer(se401, + &se401->scratch[se401->scratch_use]); + + se401->scratch[se401->scratch_use].state = + BUFFER_UNUSED; se401->scratch_use++; - if (se401->scratch_use>=SE401_NUMSCRATCH) - se401->scratch_use=0; + if (se401->scratch_use >= SE401_NUMSCRATCH) + se401->scratch_use = 0; if (errors > SE401_MAX_ERRORS) { - errors=0; + errors = 0; dev_info(&se401->dev->dev, - "too many errors, restarting capture\n"); + "too many errors, restarting capture\n"); se401_stop_stream(se401); se401_start_stream(se401); } } } - if (se401->frame[framenr].grabstate==FRAME_DONE) + if (se401->frame[framenr].grabstate == FRAME_DONE) if (se401->enhance) - enhance_picture(se401->frame[framenr].data, se401->cheight*se401->cwidth*3); + enhance_picture(se401->frame[framenr].data, + se401->cheight * se401->cwidth * 3); return 0; } -static void usb_se401_remove_disconnected (struct usb_se401 *se401) +static void usb_se401_remove_disconnected(struct usb_se401 *se401) { int i; se401->dev = NULL; - for (i=0; iurb[i]) { usb_kill_urb(se401->urb[i]); usb_free_urb(se401->urb[i]); se401->urb[i] = NULL; kfree(se401->sbuf[i].data); } - for (i=0; iscratch[i].data); - } + if (se401->inturb) { usb_kill_urb(se401->inturb); usb_free_urb(se401->inturb); @@ -965,11 +977,11 @@ static int se401_close(struct file *file) dev_info(&se401->dev->dev, "device unregistered\n"); usb_se401_remove_disconnected(se401); } else { - for (i=0; iframe[i].grabstate=FRAME_UNUSED; + for (i = 0; i < SE401_NUMFRAMES; i++) + se401->frame[i].grabstate = FRAME_UNUSED; if (se401->streaming) se401_stop_stream(se401); - se401->user=0; + se401->user = 0; } file->private_data = NULL; return 0; @@ -1065,7 +1077,7 @@ static long se401_do_ioctl(struct file *file, unsigned int cmd, void *arg) memset(vm, 0, sizeof(*vm)); vm->size = SE401_NUMFRAMES * se401->maxframesize; vm->frames = SE401_NUMFRAMES; - for (i=0; ioffsets[i] = se401->maxframesize * i; return 0; } @@ -1083,16 +1095,16 @@ static long se401_do_ioctl(struct file *file, unsigned int cmd, void *arg) /* Is this according to the v4l spec??? */ if (se401_set_size(se401, vm->width, vm->height)) return -EINVAL; - se401->frame[vm->frame].grabstate=FRAME_READY; + se401->frame[vm->frame].grabstate = FRAME_READY; if (!se401->streaming) se401_start_stream(se401); /* Set the picture properties */ - if (se401->framecount==0) + if (se401->framecount == 0) se401_send_pict(se401); /* Calibrate the reset level after a few frames. */ - if (se401->framecount%20==1) + if (se401->framecount % 20 == 1) se401_auto_resetlevel(se401); return 0; @@ -1100,13 +1112,13 @@ static long se401_do_ioctl(struct file *file, unsigned int cmd, void *arg) case VIDIOCSYNC: { int *frame = arg; - int ret=0; + int ret = 0; - if(*frame <0 || *frame >= SE401_NUMFRAMES) + if (*frame < 0 || *frame >= SE401_NUMFRAMES) return -EINVAL; - ret=se401_newframe(se401, *frame); - se401->frame[*frame].grabstate=FRAME_UNUSED; + ret = se401_newframe(se401, *frame); + se401->frame[*frame].grabstate = FRAME_UNUSED; return ret; } case VIDIOCGFBUF: @@ -1147,36 +1159,36 @@ static long se401_ioctl(struct file *file, static ssize_t se401_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { - int realcount=count, ret=0; + int realcount = count, ret = 0; struct video_device *dev = file->private_data; struct usb_se401 *se401 = (struct usb_se401 *)dev; - if (se401->dev == NULL) + if (se401->dev == NULL) return -EIO; if (realcount > se401->cwidth*se401->cheight*3) - realcount=se401->cwidth*se401->cheight*3; + realcount = se401->cwidth*se401->cheight*3; /* Shouldn't happen: */ - if (se401->frame[0].grabstate==FRAME_GRABBING) + if (se401->frame[0].grabstate == FRAME_GRABBING) return -EBUSY; - se401->frame[0].grabstate=FRAME_READY; - se401->frame[1].grabstate=FRAME_UNUSED; - se401->curframe=0; + se401->frame[0].grabstate = FRAME_READY; + se401->frame[1].grabstate = FRAME_UNUSED; + se401->curframe = 0; if (!se401->streaming) se401_start_stream(se401); /* Set the picture properties */ - if (se401->framecount==0) + if (se401->framecount == 0) se401_send_pict(se401); /* Calibrate the reset level after a few frames. */ - if (se401->framecount%20==1) + if (se401->framecount%20 == 1) se401_auto_resetlevel(se401); - ret=se401_newframe(se401, 0); + ret = se401_newframe(se401, 0); - se401->frame[0].grabstate=FRAME_UNUSED; + se401->frame[0].grabstate = FRAME_UNUSED; if (ret) return ret; if (copy_to_user(buf, se401->frame[0].data, realcount)) @@ -1195,11 +1207,12 @@ static int se401_mmap(struct file *file, struct vm_area_struct *vma) mutex_lock(&se401->lock); - if (se401->dev == NULL) { + if (se401->dev == NULL) { mutex_unlock(&se401->lock); return -EIO; } - if (size > (((SE401_NUMFRAMES * se401->maxframesize) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) { + if (size > (((SE401_NUMFRAMES * se401->maxframesize) + PAGE_SIZE - 1) + & ~(PAGE_SIZE - 1))) { mutex_unlock(&se401->lock); return -EINVAL; } @@ -1210,10 +1223,10 @@ static int se401_mmap(struct file *file, struct vm_area_struct *vma) mutex_unlock(&se401->lock); return -EAGAIN; } - start += PAGE_SIZE; - pos += PAGE_SIZE; + start += PAGE_SIZE; + pos += PAGE_SIZE; if (size > PAGE_SIZE) - size -= PAGE_SIZE; + size -= PAGE_SIZE; else size = 0; } @@ -1223,7 +1236,7 @@ static int se401_mmap(struct file *file, struct vm_area_struct *vma) } static const struct v4l2_file_operations se401_fops = { - .owner = THIS_MODULE, + .owner = THIS_MODULE, .open = se401_open, .release = se401_close, .read = se401_read, @@ -1241,71 +1254,76 @@ static struct video_device se401_template = { /***************************/ static int se401_init(struct usb_se401 *se401, int button) { - int i=0, rc; + int i = 0, rc; unsigned char cp[0x40]; char temp[200]; + int slen; /* led on */ se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0); /* get camera descriptor */ - rc=se401_sndctrl(0, se401, SE401_REQ_GET_CAMERA_DESCRIPTOR, 0, cp, sizeof(cp)); - if (cp[1]!=0x41) { + rc = se401_sndctrl(0, se401, SE401_REQ_GET_CAMERA_DESCRIPTOR, 0, + cp, sizeof(cp)); + if (cp[1] != 0x41) { err("Wrong descriptor type"); return 1; } - sprintf (temp, "ExtraFeatures: %d", cp[3]); + slen = snprintf(temp, 200, "ExtraFeatures: %d", cp[3]); - se401->sizes=cp[4]+cp[5]*256; - se401->width=kmalloc(se401->sizes*sizeof(int), GFP_KERNEL); + se401->sizes = cp[4] + cp[5] * 256; + se401->width = kmalloc(se401->sizes*sizeof(int), GFP_KERNEL); if (!se401->width) return 1; - se401->height=kmalloc(se401->sizes*sizeof(int), GFP_KERNEL); + se401->height = kmalloc(se401->sizes*sizeof(int), GFP_KERNEL); if (!se401->height) { kfree(se401->width); return 1; } - for (i=0; isizes; i++) { - se401->width[i]=cp[6+i*4+0]+cp[6+i*4+1]*256; - se401->height[i]=cp[6+i*4+2]+cp[6+i*4+3]*256; + for (i = 0; i < se401->sizes; i++) { + se401->width[i] = cp[6 + i * 4 + 0] + cp[6 + i*4 + 1] * 256; + se401->height[i] = cp[6 + i * 4 + 2] + cp[6 + i * 4 + 3] * 256; } - sprintf (temp, "%s Sizes:", temp); - for (i=0; isizes; i++) { - sprintf(temp, "%s %dx%d", temp, se401->width[i], se401->height[i]); + slen += snprintf(temp + slen, 200 - slen, " Sizes:"); + for (i = 0; i < se401->sizes; i++) { + slen += snprintf(temp + slen, 200 - slen, + " %dx%d", se401->width[i], se401->height[i]); } dev_info(&se401->dev->dev, "%s\n", temp); - se401->maxframesize=se401->width[se401->sizes-1]*se401->height[se401->sizes-1]*3; + se401->maxframesize = se401->width[se401->sizes-1] * + se401->height[se401->sizes - 1] * 3; - rc=se401_sndctrl(0, se401, SE401_REQ_GET_WIDTH, 0, cp, sizeof(cp)); - se401->cwidth=cp[0]+cp[1]*256; - rc=se401_sndctrl(0, se401, SE401_REQ_GET_HEIGHT, 0, cp, sizeof(cp)); - se401->cheight=cp[0]+cp[1]*256; + rc = se401_sndctrl(0, se401, SE401_REQ_GET_WIDTH, 0, cp, sizeof(cp)); + se401->cwidth = cp[0]+cp[1]*256; + rc = se401_sndctrl(0, se401, SE401_REQ_GET_HEIGHT, 0, cp, sizeof(cp)); + se401->cheight = cp[0]+cp[1]*256; if (!(cp[2] & SE401_FORMAT_BAYER)) { err("Bayer format not supported!"); return 1; } /* set output mode (BAYER) */ - se401_sndctrl(1, se401, SE401_REQ_SET_OUTPUT_MODE, SE401_FORMAT_BAYER, NULL, 0); + se401_sndctrl(1, se401, SE401_REQ_SET_OUTPUT_MODE, + SE401_FORMAT_BAYER, NULL, 0); - rc=se401_sndctrl(0, se401, SE401_REQ_GET_BRT, 0, cp, sizeof(cp)); - se401->brightness=cp[0]+cp[1]*256; + rc = se401_sndctrl(0, se401, SE401_REQ_GET_BRT, 0, cp, sizeof(cp)); + se401->brightness = cp[0]+cp[1]*256; /* some default values */ - se401->resetlevel=0x2d; - se401->rgain=0x20; - se401->ggain=0x20; - se401->bgain=0x20; + se401->resetlevel = 0x2d; + se401->rgain = 0x20; + se401->ggain = 0x20; + se401->bgain = 0x20; se401_set_exposure(se401, 20000); - se401->palette=VIDEO_PALETTE_RGB24; - se401->enhance=1; - se401->dropped=0; - se401->error=0; - se401->framecount=0; - se401->readcount=0; + se401->palette = VIDEO_PALETTE_RGB24; + se401->enhance = 1; + se401->dropped = 0; + se401->error = 0; + se401->framecount = 0; + se401->readcount = 0; /* Start interrupt transfers for snapshot button */ if (button) { - se401->inturb=usb_alloc_urb(0, GFP_KERNEL); + se401->inturb = usb_alloc_urb(0, GFP_KERNEL); if (!se401->inturb) { dev_info(&se401->dev->dev, "Allocation of inturb failed\n"); @@ -1323,7 +1341,7 @@ static int se401_init(struct usb_se401 *se401, int button) return 1; } } else - se401->inturb=NULL; + se401->inturb = NULL; /* Flash the led */ se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 1, NULL, 0); @@ -1340,8 +1358,8 @@ static int se401_probe(struct usb_interface *intf, struct usb_device *dev = interface_to_usbdev(intf); struct usb_interface_descriptor *interface; struct usb_se401 *se401; - char *camera_name=NULL; - int button=1; + char *camera_name = NULL; + int button = 1; /* We don't handle multi-config cameras */ if (dev->descriptor.bNumConfigurations != 1) @@ -1350,22 +1368,22 @@ static int se401_probe(struct usb_interface *intf, interface = &intf->cur_altsetting->desc; /* Is it an se401? */ - if (le16_to_cpu(dev->descriptor.idVendor) == 0x03e8 && - le16_to_cpu(dev->descriptor.idProduct) == 0x0004) { - camera_name="Endpoints/Aox SE401"; - } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x0471 && - le16_to_cpu(dev->descriptor.idProduct) == 0x030b) { - camera_name="Philips PCVC665K"; - } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d && - le16_to_cpu(dev->descriptor.idProduct) == 0x5001) { - camera_name="Kensington VideoCAM 67014"; - } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d && - le16_to_cpu(dev->descriptor.idProduct) == 0x5002) { - camera_name="Kensington VideoCAM 6701(5/7)"; - } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d && - le16_to_cpu(dev->descriptor.idProduct) == 0x5003) { - camera_name="Kensington VideoCAM 67016"; - button=0; + if (le16_to_cpu(dev->descriptor.idVendor) == 0x03e8 && + le16_to_cpu(dev->descriptor.idProduct) == 0x0004) { + camera_name = "Endpoints/Aox SE401"; + } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x0471 && + le16_to_cpu(dev->descriptor.idProduct) == 0x030b) { + camera_name = "Philips PCVC665K"; + } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d && + le16_to_cpu(dev->descriptor.idProduct) == 0x5001) { + camera_name = "Kensington VideoCAM 67014"; + } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d && + le16_to_cpu(dev->descriptor.idProduct) == 0x5002) { + camera_name = "Kensington VideoCAM 6701(5/7)"; + } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d && + le16_to_cpu(dev->descriptor.idProduct) == 0x5003) { + camera_name = "Kensington VideoCAM 67016"; + button = 0; } else return -ENODEV; @@ -1378,7 +1396,8 @@ static int se401_probe(struct usb_interface *intf, /* We found one */ dev_info(&intf->dev, "SE401 camera found: %s\n", camera_name); - if ((se401 = kzalloc(sizeof(*se401), GFP_KERNEL)) == NULL) { + se401 = kzalloc(sizeof(*se401), GFP_KERNEL); + if (se401 == NULL) { err("couldn't kmalloc se401 struct"); return -ENOMEM; } @@ -1396,12 +1415,14 @@ static int se401_probe(struct usb_interface *intf, } memcpy(&se401->vdev, &se401_template, sizeof(se401_template)); - memcpy(se401->vdev.name, se401->camera_name, strlen(se401->camera_name)); + memcpy(se401->vdev.name, se401->camera_name, + strlen(se401->camera_name)); init_waitqueue_head(&se401->wq); mutex_init(&se401->lock); wmb(); - if (video_register_device(&se401->vdev, VFL_TYPE_GRABBER, video_nr) < 0) { + if (video_register_device(&se401->vdev, + VFL_TYPE_GRABBER, video_nr) < 0) { kfree(se401); err("video_register_device failed"); return -EIO; @@ -1409,20 +1430,20 @@ static int se401_probe(struct usb_interface *intf, dev_info(&intf->dev, "registered new video device: video%d\n", se401->vdev.num); - usb_set_intfdata (intf, se401); + usb_set_intfdata(intf, se401); return 0; } static void se401_disconnect(struct usb_interface *intf) { - struct usb_se401 *se401 = usb_get_intfdata (intf); + struct usb_se401 *se401 = usb_get_intfdata(intf); - usb_set_intfdata (intf, NULL); + usb_set_intfdata(intf, NULL); if (se401) { video_unregister_device(&se401->vdev); - if (!se401->user){ + if (!se401->user) usb_se401_remove_disconnected(se401); - } else { + else { se401->frame[0].grabstate = FRAME_ERROR; se401->frame[0].grabstate = FRAME_ERROR; @@ -1435,10 +1456,10 @@ static void se401_disconnect(struct usb_interface *intf) } static struct usb_driver se401_driver = { - .name = "se401", - .id_table = device_table, - .probe = se401_probe, - .disconnect = se401_disconnect, + .name = "se401", + .id_table = device_table, + .probe = se401_probe, + .disconnect = se401_disconnect, }; @@ -1451,9 +1472,10 @@ static struct usb_driver se401_driver = { static int __init usb_se401_init(void) { - printk(KERN_INFO "SE401 usb camera driver version %s registering\n", version); + printk(KERN_INFO "SE401 usb camera driver version %s registering\n", + version); if (flickerless) - if (flickerless!=50 && flickerless!=60) { + if (flickerless != 50 && flickerless != 60) { printk(KERN_ERR "Invallid flickerless value, use 0, 50 or 60.\n"); return -1; } diff --git a/drivers/media/video/se401.h b/drivers/media/video/se401.h index 2ce685db5d8b..bf7d2e9765b0 100644 --- a/drivers/media/video/se401.h +++ b/drivers/media/video/se401.h @@ -2,7 +2,7 @@ #ifndef __LINUX_se401_H #define __LINUX_se401_H -#include +#include #include #include #include @@ -12,9 +12,10 @@ #ifdef se401_DEBUG # define PDEBUG(level, fmt, args...) \ -if (debug >= level) info("[" __PRETTY_FUNCTION__ ":%d] " fmt, __LINE__ , ## args) +if (debug >= level) \ + info("[" __PRETTY_FUNCTION__ ":%d] " fmt, __LINE__ , ## args) #else -# define PDEBUG(level, fmt, args...) do {} while(0) +# define PDEBUG(level, fmt, args...) do {} while (0) #endif /* An almost drop-in replacement for sleep_on_interruptible */ diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index b5e37a530c62..0db88a53d92c 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c @@ -81,7 +81,6 @@ struct sh_mobile_ceu_buffer { }; struct sh_mobile_ceu_dev { - struct device *dev; struct soc_camera_host ici; struct soc_camera_device *icd; @@ -617,7 +616,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx, xlate->cam_fmt = icd->formats + idx; xlate->buswidth = icd->formats[idx].depth; xlate++; - dev_dbg(&ici->dev, "Providing format %s using %s\n", + dev_dbg(ici->dev, "Providing format %s using %s\n", sh_mobile_ceu_formats[k].name, icd->formats[idx].name); } @@ -630,7 +629,7 @@ add_single_format: xlate->cam_fmt = icd->formats + idx; xlate->buswidth = icd->formats[idx].depth; xlate++; - dev_dbg(&ici->dev, + dev_dbg(ici->dev, "Providing format %s in pass-through mode\n", icd->formats[idx].name); } @@ -657,7 +656,7 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); if (!xlate) { - dev_warn(&ici->dev, "Format %x not found\n", pixfmt); + dev_warn(ici->dev, "Format %x not found\n", pixfmt); return -EINVAL; } @@ -684,22 +683,14 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); if (!xlate) { - dev_warn(&ici->dev, "Format %x not found\n", pixfmt); + dev_warn(ici->dev, "Format %x not found\n", pixfmt); return -EINVAL; } /* 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; + v4l_bound_align_image(&f->fmt.pix.width, 2, 2560, 1, + &f->fmt.pix.height, 4, 1920, 2, 0); f->fmt.pix.bytesperline = f->fmt.pix.width * DIV_ROUND_UP(xlate->host_fmt->depth, 8); @@ -782,7 +773,7 @@ static void sh_mobile_ceu_init_videobuf(struct videobuf_queue *q, videobuf_queue_dma_contig_init(q, &sh_mobile_ceu_videobuf_ops, - &ici->dev, &pcdev->lock, + ici->dev, &pcdev->lock, V4L2_BUF_TYPE_VIDEO_CAPTURE, pcdev->is_interlaced ? V4L2_FIELD_INTERLACED : V4L2_FIELD_NONE, @@ -829,7 +820,6 @@ static int sh_mobile_ceu_probe(struct platform_device *pdev) goto exit; } - platform_set_drvdata(pdev, pcdev); INIT_LIST_HEAD(&pcdev->capture); spin_lock_init(&pcdev->lock); @@ -840,7 +830,7 @@ static int sh_mobile_ceu_probe(struct platform_device *pdev) goto exit_kfree; } - base = ioremap_nocache(res->start, res->end - res->start + 1); + base = ioremap_nocache(res->start, resource_size(res)); if (!base) { err = -ENXIO; dev_err(&pdev->dev, "Unable to ioremap CEU registers.\n"); @@ -850,13 +840,12 @@ static int sh_mobile_ceu_probe(struct platform_device *pdev) 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, + resource_size(res), DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE); if (!err) { @@ -865,7 +854,7 @@ static int sh_mobile_ceu_probe(struct platform_device *pdev) goto exit_iounmap; } - pcdev->video_limit = (res->end - res->start) + 1; + pcdev->video_limit = resource_size(res); } /* request irq */ @@ -885,7 +874,7 @@ static int sh_mobile_ceu_probe(struct platform_device *pdev) } pcdev->ici.priv = pcdev; - pcdev->ici.dev.parent = &pdev->dev; + pcdev->ici.dev = &pdev->dev; pcdev->ici.nr = pdev->id; pcdev->ici.drv_name = dev_name(&pdev->dev); pcdev->ici.ops = &sh_mobile_ceu_host_ops; @@ -913,9 +902,11 @@ exit: static int sh_mobile_ceu_remove(struct platform_device *pdev) { - struct sh_mobile_ceu_dev *pcdev = platform_get_drvdata(pdev); + struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev); + struct sh_mobile_ceu_dev *pcdev = container_of(soc_host, + struct sh_mobile_ceu_dev, ici); - soc_camera_host_unregister(&pcdev->ici); + soc_camera_host_unregister(soc_host); clk_put(pcdev->clk); free_irq(pcdev->irq, pcdev); if (platform_get_resource(pdev, IORESOURCE_MEM, 1)) diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index 0e890cc23377..16f595d4337a 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c @@ -16,19 +16,21 @@ * published by the Free Software Foundation. */ -#include -#include #include -#include #include +#include +#include +#include +#include #include +#include #include -#include -#include -#include -#include #include +#include +#include +#include +#include /* Default to VGA resolution */ #define DEFAULT_WIDTH 640 @@ -279,7 +281,7 @@ static int soc_camera_set_fmt(struct soc_camera_file *icf, return ret; } else if (!icd->current_fmt || icd->current_fmt->fourcc != pix->pixelformat) { - dev_err(&ici->dev, + dev_err(ici->dev, "Host driver hasn't set up current format correctly!\n"); return -EINVAL; } @@ -794,7 +796,7 @@ static void scan_add_host(struct soc_camera_host *ici) list_for_each_entry(icd, &devices, list) { if (icd->iface == ici->nr) { - icd->dev.parent = &ici->dev; + icd->dev.parent = ici->dev; device_register_link(icd); } } @@ -818,7 +820,7 @@ static int scan_add_device(struct soc_camera_device *icd) list_for_each_entry(ici, &hosts, list) { if (icd->iface == ici->nr) { ret = 1; - icd->dev.parent = &ici->dev; + icd->dev.parent = ici->dev; break; } } @@ -952,7 +954,6 @@ static void dummy_release(struct device *dev) int soc_camera_host_register(struct soc_camera_host *ici) { - int ret; struct soc_camera_host *ix; if (!ici || !ici->ops || @@ -965,12 +966,10 @@ int soc_camera_host_register(struct soc_camera_host *ici) !ici->ops->reqbufs || !ici->ops->add || !ici->ops->remove || - !ici->ops->poll) + !ici->ops->poll || + !ici->dev) return -EINVAL; - /* Number might be equal to the platform device ID */ - dev_set_name(&ici->dev, "camera_host%d", ici->nr); - mutex_lock(&list_lock); list_for_each_entry(ix, &hosts, list) { if (ix->nr == ici->nr) { @@ -979,26 +978,14 @@ int soc_camera_host_register(struct soc_camera_host *ici) } } + dev_set_drvdata(ici->dev, ici); + list_add_tail(&ici->list, &hosts); mutex_unlock(&list_lock); - ici->dev.release = dummy_release; - - ret = device_register(&ici->dev); - - if (ret) - goto edevr; - scan_add_host(ici); return 0; - -edevr: - mutex_lock(&list_lock); - list_del(&ici->list); - mutex_unlock(&list_lock); - - return ret; } EXPORT_SYMBOL(soc_camera_host_register); @@ -1012,7 +999,7 @@ void soc_camera_host_unregister(struct soc_camera_host *ici) list_del(&ici->list); list_for_each_entry(icd, &devices, list) { - if (icd->dev.parent == &ici->dev) { + if (icd->dev.parent == ici->dev) { device_unregister(&icd->dev); /* Not before device_unregister(), .remove * needs parent to call ici->ops->remove() */ @@ -1023,7 +1010,7 @@ void soc_camera_host_unregister(struct soc_camera_host *ici) mutex_unlock(&list_lock); - device_unregister(&ici->dev); + dev_set_drvdata(ici->dev, NULL); } EXPORT_SYMBOL(soc_camera_host_unregister); @@ -1130,7 +1117,7 @@ int soc_camera_video_start(struct soc_camera_device *icd) vdev = video_device_alloc(); if (!vdev) goto evidallocd; - dev_dbg(&ici->dev, "Allocated video_device %p\n", vdev); + dev_dbg(ici->dev, "Allocated video_device %p\n", vdev); strlcpy(vdev->name, ici->drv_name, sizeof(vdev->name)); @@ -1174,6 +1161,57 @@ void soc_camera_video_stop(struct soc_camera_device *icd) } EXPORT_SYMBOL(soc_camera_video_stop); +static int __devinit soc_camera_pdrv_probe(struct platform_device *pdev) +{ + struct soc_camera_link *icl = pdev->dev.platform_data; + struct i2c_adapter *adap; + struct i2c_client *client; + + if (!icl) + return -EINVAL; + + adap = i2c_get_adapter(icl->i2c_adapter_id); + if (!adap) { + dev_warn(&pdev->dev, "Cannot get adapter #%d. No driver?\n", + icl->i2c_adapter_id); + /* -ENODEV and -ENXIO do not produce an error on probe()... */ + return -ENOENT; + } + + icl->board_info->platform_data = icl; + client = i2c_new_device(adap, icl->board_info); + if (!client) { + i2c_put_adapter(adap); + return -ENOMEM; + } + + platform_set_drvdata(pdev, client); + + return 0; +} + +static int __devexit soc_camera_pdrv_remove(struct platform_device *pdev) +{ + struct i2c_client *client = platform_get_drvdata(pdev); + + if (!client) + return -ENODEV; + + i2c_unregister_device(client); + i2c_put_adapter(client->adapter); + + return 0; +} + +static struct platform_driver __refdata soc_camera_pdrv = { + .probe = soc_camera_pdrv_probe, + .remove = __devexit_p(soc_camera_pdrv_remove), + .driver = { + .name = "soc-camera-pdrv", + .owner = THIS_MODULE, + }, +}; + static int __init soc_camera_init(void) { int ret = bus_register(&soc_camera_bus_type); @@ -1183,8 +1221,14 @@ static int __init soc_camera_init(void) if (ret) goto edrvr; + ret = platform_driver_register(&soc_camera_pdrv); + if (ret) + goto epdr; + return 0; +epdr: + driver_unregister(&ic_drv); edrvr: bus_unregister(&soc_camera_bus_type); return ret; @@ -1192,6 +1236,7 @@ edrvr: static void __exit soc_camera_exit(void) { + platform_driver_unregister(&soc_camera_pdrv); driver_unregister(&ic_drv); bus_unregister(&soc_camera_bus_type); } @@ -1202,3 +1247,4 @@ module_exit(soc_camera_exit); MODULE_DESCRIPTION("Image capture bus driver"); MODULE_AUTHOR("Guennadi Liakhovetski "); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:soc-camera-pdrv"); diff --git a/drivers/media/video/stk-webcam.c b/drivers/media/video/stk-webcam.c index 1a6d39cbd6f3..2e5937047278 100644 --- a/drivers/media/video/stk-webcam.c +++ b/drivers/media/video/stk-webcam.c @@ -1137,7 +1137,7 @@ static int stk_vidioc_querybuf(struct file *filp, struct stk_camera *dev = priv; struct stk_sio_buffer *sbuf; - if (buf->index < 0 || buf->index >= dev->n_sbufs) + if (buf->index >= dev->n_sbufs) return -EINVAL; sbuf = dev->sio_bufs + buf->index; *buf = sbuf->v4lbuf; @@ -1154,7 +1154,7 @@ static int stk_vidioc_qbuf(struct file *filp, if (buf->memory != V4L2_MEMORY_MMAP) return -EINVAL; - if (buf->index < 0 || buf->index >= dev->n_sbufs) + if (buf->index >= dev->n_sbufs) return -EINVAL; sbuf = dev->sio_bufs + buf->index; if (sbuf->v4lbuf.flags & V4L2_BUF_FLAG_QUEUED) diff --git a/drivers/media/video/tcm825x.c b/drivers/media/video/tcm825x.c index b30c49248217..b90e9da3167d 100644 --- a/drivers/media/video/tcm825x.c +++ b/drivers/media/video/tcm825x.c @@ -878,7 +878,7 @@ static int tcm825x_probe(struct i2c_client *client, return rval; } -static int __exit tcm825x_remove(struct i2c_client *client) +static int tcm825x_remove(struct i2c_client *client) { struct tcm825x_sensor *sensor = i2c_get_clientdata(client); @@ -902,7 +902,7 @@ static struct i2c_driver tcm825x_i2c_driver = { .name = TCM825X_NAME, }, .probe = tcm825x_probe, - .remove = __exit_p(tcm825x_remove), + .remove = tcm825x_remove, .id_table = tcm825x_id, }; diff --git a/drivers/media/video/tda7432.c b/drivers/media/video/tda7432.c index 005f8a468031..80f1cee23fa5 100644 --- a/drivers/media/video/tda7432.c +++ b/drivers/media/video/tda7432.c @@ -20,20 +20,6 @@ * loudness - set between 0 and 15 for varying degrees of loudness effect * * maxvol - set maximium volume to +20db (1), default is 0db(0) - * - * - * Revision: 0.7 - maxvol module parm to set maximium volume 0db or +20db - * store if muted so we can return it - * change balance only if flaged to - * Revision: 0.6 - added tone controls - * Revision: 0.5 - Fixed odd balance problem - * Revision: 0.4 - added muting - * Revision: 0.3 - Fixed silly reversed volume controls. :) - * Revision: 0.2 - Cleaned up #defines - * fixed volume control - * Added I2C_DRIVERID_TDA7432 - * added loudness insmod control - * Revision: 0.1 - initial version */ #include diff --git a/drivers/media/video/tea6415c.c b/drivers/media/video/tea6415c.c index d4a9ed45764b..1585839bd0bd 100644 --- a/drivers/media/video/tea6415c.c +++ b/drivers/media/video/tea6415c.c @@ -141,7 +141,6 @@ static const struct v4l2_subdev_ops tea6415c_ops = { .video = &tea6415c_video_ops, }; -/* this function is called by i2c_probe */ static int tea6415c_probe(struct i2c_client *client, const struct i2c_device_id *id) { diff --git a/drivers/media/video/tea6420.c b/drivers/media/video/tea6420.c index ced6eadf347a..0446524d3543 100644 --- a/drivers/media/video/tea6420.c +++ b/drivers/media/video/tea6420.c @@ -112,7 +112,6 @@ static const struct v4l2_subdev_ops tea6420_ops = { .audio = &tea6420_audio_ops, }; -/* this function is called by i2c_probe */ static int tea6420_probe(struct i2c_client *client, const struct i2c_device_id *id) { diff --git a/drivers/media/video/ths7303.c b/drivers/media/video/ths7303.c new file mode 100644 index 000000000000..21781f8a0e8e --- /dev/null +++ b/drivers/media/video/ths7303.c @@ -0,0 +1,151 @@ +/* + * ths7303- THS7303 Video Amplifier driver + * + * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.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 version 2. + * + * This program is distributed .as is. WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +MODULE_DESCRIPTION("TI THS7303 video amplifier driver"); +MODULE_AUTHOR("Chaithrika U S"); +MODULE_LICENSE("GPL"); + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Debug level 0-1"); + +/* following function is used to set ths7303 */ +static int ths7303_setvalue(struct v4l2_subdev *sd, v4l2_std_id std) +{ + int err = 0; + u8 val; + struct i2c_client *client; + + client = v4l2_get_subdevdata(sd); + + if (std & (V4L2_STD_ALL & ~V4L2_STD_SECAM)) { + val = 0x02; + v4l2_dbg(1, debug, sd, "setting value for SDTV format\n"); + } else { + val = 0x00; + v4l2_dbg(1, debug, sd, "disabling all channels\n"); + } + + err |= i2c_smbus_write_byte_data(client, 0x01, val); + err |= i2c_smbus_write_byte_data(client, 0x02, val); + err |= i2c_smbus_write_byte_data(client, 0x03, val); + + if (err) + v4l2_err(sd, "write failed\n"); + + return err; +} + +static int ths7303_s_std_output(struct v4l2_subdev *sd, v4l2_std_id norm) +{ + return ths7303_setvalue(sd, norm); +} + +static int ths7303_g_chip_ident(struct v4l2_subdev *sd, + struct v4l2_dbg_chip_ident *chip) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_THS7303, 0); +} + +static const struct v4l2_subdev_video_ops ths7303_video_ops = { + .s_std_output = ths7303_s_std_output, +}; + +static const struct v4l2_subdev_core_ops ths7303_core_ops = { + .g_chip_ident = ths7303_g_chip_ident, +}; + +static const struct v4l2_subdev_ops ths7303_ops = { + .core = &ths7303_core_ops, + .video = &ths7303_video_ops, +}; + +static int ths7303_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct v4l2_subdev *sd; + v4l2_std_id std_id = V4L2_STD_NTSC; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -ENODEV; + + v4l_info(client, "chip found @ 0x%x (%s)\n", + client->addr << 1, client->adapter->name); + + sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL); + if (sd == NULL) + return -ENOMEM; + + v4l2_i2c_subdev_init(sd, client, &ths7303_ops); + + return ths7303_setvalue(sd, std_id); +} + +static int ths7303_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + + v4l2_device_unregister_subdev(sd); + kfree(sd); + + return 0; +} + +static const struct i2c_device_id ths7303_id[] = { + {"ths7303", 0}, + {}, +}; + +MODULE_DEVICE_TABLE(i2c, ths7303_id); + +static struct i2c_driver ths7303_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "ths7303", + }, + .probe = ths7303_probe, + .remove = ths7303_remove, + .id_table = ths7303_id, +}; + +static int __init ths7303_init(void) +{ + return i2c_add_driver(&ths7303_driver); +} + +static void __exit ths7303_exit(void) +{ + i2c_del_driver(&ths7303_driver); +} + +module_init(ths7303_init); +module_exit(ths7303_exit); + diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 78c377a399cb..537594211a90 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -309,32 +309,6 @@ static void set_freq(struct i2c_client *c, unsigned long freq) } } -static void tuner_i2c_address_check(struct tuner *t) -{ - if ((t->type == UNSET || t->type == TUNER_ABSENT) || - ((t->i2c->addr < 0x64) || (t->i2c->addr > 0x6f))) - return; - - /* We already know that the XC5000 can only be located at - * i2c address 0x61, 0x62, 0x63 or 0x64 */ - if ((t->type == TUNER_XC5000) && - ((t->i2c->addr <= 0x64)) && (t->i2c->addr >= 0x61)) - return; - - tuner_warn("====================== WARNING! ======================\n"); - tuner_warn("Support for tuners in i2c address range 0x64 thru 0x6f\n"); - tuner_warn("will soon be dropped. This message indicates that your\n"); - tuner_warn("hardware has a %s tuner at i2c address 0x%02x.\n", - t->name, t->i2c->addr); - tuner_warn("To ensure continued support for your device, please\n"); - tuner_warn("send a copy of this message, along with full dmesg\n"); - tuner_warn("output to v4l-dvb-maintainer@linuxtv.org\n"); - tuner_warn("Please use subject line: \"obsolete tuner i2c address.\"\n"); - tuner_warn("driver: %s, addr: 0x%02x, type: %d (%s)\n", - t->i2c->adapter->name, t->i2c->addr, t->type, t->name); - tuner_warn("====================== WARNING! ======================\n"); -} - static struct xc5000_config xc5000_cfg; static void set_type(struct i2c_client *c, unsigned int type, @@ -438,18 +412,12 @@ static void set_type(struct i2c_client *c, unsigned int type, break; case TUNER_XC5000: { - struct dvb_tuner_ops *xc_tuner_ops; - xc5000_cfg.i2c_address = t->i2c->addr; /* if_khz will be set when the digital dvb_attach() occurs */ xc5000_cfg.if_khz = 0; if (!dvb_attach(xc5000_attach, &t->fe, t->i2c->adapter, &xc5000_cfg)) goto attach_failed; - - xc_tuner_ops = &t->fe.ops.tuner_ops; - if (xc_tuner_ops->init) - xc_tuner_ops->init(&t->fe); break; } default: @@ -490,7 +458,6 @@ static void set_type(struct i2c_client *c, unsigned int type, tuner_dbg("%s %s I2C addr 0x%02x with type %d used for 0x%02x\n", c->adapter->name, c->driver->driver.name, c->addr << 1, type, t->mode_mask); - tuner_i2c_address_check(t); return; attach_failed: diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c index e24a38c7fa46..ac02808106c1 100644 --- a/drivers/media/video/tveeprom.c +++ b/drivers/media/video/tveeprom.c @@ -184,7 +184,7 @@ hauppauge_tuner[] = { TUNER_ABSENT, "Silicon TDA8275C1 8290 FM"}, { TUNER_ABSENT, "Thompson DTT757"}, /* 80-89 */ - { TUNER_PHILIPS_FM1216ME_MK3, "Philips FQ1216LME MK3"}, + { TUNER_PHILIPS_FQ1216LME_MK3, "Philips FQ1216LME MK3"}, { TUNER_LG_PAL_NEW_TAPC, "LG TAPC G701D"}, { TUNER_LG_NTSC_NEW_TAPC, "LG TAPC H791F"}, { TUNER_LG_PAL_NEW_TAPC, "TCL 2002MB 3"}, @@ -210,7 +210,7 @@ hauppauge_tuner[] = { TUNER_TEA5767, "Philips TEA5768HL FM Radio"}, { TUNER_ABSENT, "Panasonic ENV57H12D5"}, { TUNER_PHILIPS_FM1236_MK3, "TCL MFNM05-4"}, - { TUNER_ABSENT, "TCL MNM05-4"}, + { TUNER_PHILIPS_FM1236_MK3, "TCL MNM05-4"}, { TUNER_PHILIPS_FM1216ME_MK3, "TCL MPE05-2"}, { TUNER_ABSENT, "TCL MQNM05-4"}, { TUNER_ABSENT, "LG TAPC-W701D"}, @@ -229,7 +229,7 @@ hauppauge_tuner[] = { TUNER_ABSENT, "Samsung THPD5222FG30A"}, /* 120-129 */ { TUNER_XC2028, "Xceive XC3028"}, - { TUNER_ABSENT, "Philips FQ1216LME MK5"}, + { TUNER_PHILIPS_FQ1216LME_MK3, "Philips FQ1216LME MK5"}, { TUNER_ABSENT, "Philips FQD1216LME"}, { TUNER_ABSENT, "Conexant CX24118A"}, { TUNER_ABSENT, "TCL DMF11WIP"}, diff --git a/drivers/media/video/tvp514x.c b/drivers/media/video/tvp514x.c index 4262e60b8116..3750f7fadb12 100644 --- a/drivers/media/video/tvp514x.c +++ b/drivers/media/video/tvp514x.c @@ -692,7 +692,7 @@ static int ioctl_s_routing(struct v4l2_int_device *s, break; /* Input detected */ } - if ((current_std == STD_INVALID) || (try_count <= 0)) + if ((current_std == STD_INVALID) || (try_count < 0)) return -EINVAL; decoder->current_std = current_std; diff --git a/drivers/media/video/tw9910.c b/drivers/media/video/tw9910.c index a39947643992..aa5065ea09ed 100644 --- a/drivers/media/video/tw9910.c +++ b/drivers/media/video/tw9910.c @@ -875,10 +875,12 @@ static int tw9910_probe(struct i2c_client *client, const struct tw9910_scale_ctrl *scale; int i, ret; - info = client->dev.platform_data; - if (!info) + if (!client->dev.platform_data) return -EINVAL; + info = container_of(client->dev.platform_data, + struct tw9910_video_info, link); + if (!i2c_check_functionality(to_i2c_adapter(client->dev.parent), I2C_FUNC_SMBUS_BYTE_DATA)) { dev_err(&client->dev, diff --git a/drivers/media/video/usbvideo/Kconfig b/drivers/media/video/usbvideo/Kconfig index e4cb99c1f94b..adb1c044ad7d 100644 --- a/drivers/media/video/usbvideo/Kconfig +++ b/drivers/media/video/usbvideo/Kconfig @@ -38,10 +38,13 @@ config USB_KONICAWC module will be called konicawc. config USB_QUICKCAM_MESSENGER - tristate "USB Logitech Quickcam Messenger" + tristate "USB Logitech Quickcam Messenger (DEPRECATED)" depends on VIDEO_V4L1 select VIDEO_USBVIDEO ---help--- + This driver is DEPRECATED please use the gspca stv06xx module + instead. + Say Y or M here to enable support for the USB Logitech Quickcam Messenger webcam. diff --git a/drivers/media/video/usbvideo/konicawc.c b/drivers/media/video/usbvideo/konicawc.c index 900ec2129ca1..31d57f2d09e1 100644 --- a/drivers/media/video/usbvideo/konicawc.c +++ b/drivers/media/video/usbvideo/konicawc.c @@ -240,7 +240,7 @@ static void konicawc_register_input(struct konicawc *cam, struct usb_device *dev input_dev->dev.parent = &dev->dev; input_dev->evbit[0] = BIT_MASK(EV_KEY); - input_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0); + input_dev->keybit[BIT_WORD(KEY_CAMERA)] = BIT_MASK(KEY_CAMERA); error = input_register_device(cam->input); if (error) { @@ -263,7 +263,7 @@ static void konicawc_unregister_input(struct konicawc *cam) static void konicawc_report_buttonstat(struct konicawc *cam) { if (cam->input) { - input_report_key(cam->input, BTN_0, cam->buttonsts); + input_report_key(cam->input, KEY_CAMERA, cam->buttonsts); input_sync(cam->input); } } diff --git a/drivers/media/video/usbvideo/quickcam_messenger.c b/drivers/media/video/usbvideo/quickcam_messenger.c index fd112f0b9d35..803d3e4e29a2 100644 --- a/drivers/media/video/usbvideo/quickcam_messenger.c +++ b/drivers/media/video/usbvideo/quickcam_messenger.c @@ -103,7 +103,7 @@ static void qcm_register_input(struct qcm *cam, struct usb_device *dev) input_dev->dev.parent = &dev->dev; input_dev->evbit[0] = BIT_MASK(EV_KEY); - input_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0); + input_dev->keybit[BIT_WORD(KEY_CAMERA)] = BIT_MASK(KEY_CAMERA); error = input_register_device(cam->input); if (error) { @@ -126,7 +126,7 @@ static void qcm_unregister_input(struct qcm *cam) static void qcm_report_buttonstat(struct qcm *cam) { if (cam->input) { - input_report_key(cam->input, BTN_0, cam->button_sts); + input_report_key(cam->input, KEY_CAMERA, cam->button_sts); input_sync(cam->input); } } diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c index 8bc03b9e1315..6ba16abeebdd 100644 --- a/drivers/media/video/usbvision/usbvision-core.c +++ b/drivers/media/video/usbvision/usbvision-core.c @@ -390,10 +390,9 @@ int usbvision_scratch_alloc(struct usb_usbvision *usbvision) void usbvision_scratch_free(struct usb_usbvision *usbvision) { - if (usbvision->scratch != NULL) { - vfree(usbvision->scratch); - usbvision->scratch = NULL; - } + vfree(usbvision->scratch); + usbvision->scratch = NULL; + } /* @@ -506,10 +505,9 @@ int usbvision_decompress_alloc(struct usb_usbvision *usbvision) */ void usbvision_decompress_free(struct usb_usbvision *usbvision) { - if (usbvision->IntraFrameBuffer != NULL) { - vfree(usbvision->IntraFrameBuffer); - usbvision->IntraFrameBuffer = NULL; - } + vfree(usbvision->IntraFrameBuffer); + usbvision->IntraFrameBuffer = NULL; + } /************************************************************ diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c index d7056a5b7f9b..90b58914f984 100644 --- a/drivers/media/video/usbvision/usbvision-video.c +++ b/drivers/media/video/usbvision/usbvision-video.c @@ -541,7 +541,7 @@ static int vidioc_enum_input (struct file *file, void *priv, struct usb_usbvision *usbvision = video_drvdata(file); int chan; - if ((vi->index >= usbvision->video_inputs) || (vi->index < 0) ) + if (vi->index >= usbvision->video_inputs) return -EINVAL; if (usbvision->have_tuner) { chan = vi->index; @@ -1794,7 +1794,7 @@ static struct usb_driver usbvision_driver = { .name = "usbvision", .id_table = usbvision_table, .probe = usbvision_probe, - .disconnect = usbvision_disconnect + .disconnect = __devexit_p(usbvision_disconnect), }; /* diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c index 0d7e38d6ff6a..36a6ba92df27 100644 --- a/drivers/media/video/uvc/uvc_ctrl.c +++ b/drivers/media/video/uvc/uvc_ctrl.c @@ -1372,21 +1372,19 @@ end: } /* - * Prune an entity of its bogus controls. This currently includes processing - * unit auto controls for which no corresponding manual control is available. - * Such auto controls make little sense if any, and are known to crash at - * least the SiGma Micro webcam. + * Prune an entity of its bogus controls using a blacklist. Bogus controls + * are currently the ones that crash the camera or unconditionally return an + * error when queried. */ static void -uvc_ctrl_prune_entity(struct uvc_entity *entity) +uvc_ctrl_prune_entity(struct uvc_device *dev, struct uvc_entity *entity) { static const struct { - u8 idx_manual; - u8 idx_auto; + struct usb_device_id id; + u8 index; } blacklist[] = { - { 2, 11 }, /* Hue */ - { 6, 12 }, /* White Balance Temperature */ - { 7, 13 }, /* White Balance Component */ + { { USB_DEVICE(0x1c4f, 0x3000) }, 6 }, /* WB Temperature */ + { { USB_DEVICE(0x5986, 0x0241) }, 2 }, /* Hue */ }; u8 *controls; @@ -1400,19 +1398,17 @@ uvc_ctrl_prune_entity(struct uvc_entity *entity) size = entity->processing.bControlSize; for (i = 0; i < ARRAY_SIZE(blacklist); ++i) { - if (blacklist[i].idx_auto >= 8 * size || - blacklist[i].idx_manual >= 8 * size) + if (!usb_match_id(dev->intf, &blacklist[i].id)) continue; - if (!uvc_test_bit(controls, blacklist[i].idx_auto) || - uvc_test_bit(controls, blacklist[i].idx_manual)) + if (blacklist[i].index >= 8 * size || + !uvc_test_bit(controls, blacklist[i].index)) continue; - uvc_trace(UVC_TRACE_CONTROL, "Auto control %u/%u has no " - "matching manual control, removing it.\n", entity->id, - blacklist[i].idx_auto); + uvc_trace(UVC_TRACE_CONTROL, "%u/%u control is black listed, " + "removing it.\n", entity->id, blacklist[i].index); - uvc_clear_bit(controls, blacklist[i].idx_auto); + uvc_clear_bit(controls, blacklist[i].index); } } @@ -1442,8 +1438,7 @@ int uvc_ctrl_init_device(struct uvc_device *dev) bControlSize = entity->camera.bControlSize; } - if (dev->quirks & UVC_QUIRK_PRUNE_CONTROLS) - uvc_ctrl_prune_entity(entity); + uvc_ctrl_prune_entity(dev, entity); for (i = 0; i < bControlSize; ++i) ncontrols += hweight8(bmControls[i]); diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c index 507dc85646b2..89927b7aec28 100644 --- a/drivers/media/video/uvc/uvc_driver.c +++ b/drivers/media/video/uvc/uvc_driver.c @@ -289,10 +289,8 @@ static int uvc_parse_format(struct uvc_device *dev, struct uvc_format_desc *fmtdesc; struct uvc_frame *frame; const unsigned char *start = buffer; - unsigned char *_buffer; unsigned int interval; unsigned int i, n; - int _buflen; __u8 ftype; format->type = buffer[2]; @@ -303,7 +301,7 @@ static int uvc_parse_format(struct uvc_device *dev, case VS_FORMAT_FRAME_BASED: n = buffer[2] == VS_FORMAT_UNCOMPRESSED ? 27 : 28; if (buflen < n) { - uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming" + uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming " "interface %d FORMAT error\n", dev->udev->devnum, alts->desc.bInterfaceNumber); @@ -338,7 +336,7 @@ static int uvc_parse_format(struct uvc_device *dev, case VS_FORMAT_MJPEG: if (buflen < 11) { - uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming" + uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming " "interface %d FORMAT error\n", dev->udev->devnum, alts->desc.bInterfaceNumber); @@ -354,7 +352,7 @@ static int uvc_parse_format(struct uvc_device *dev, case VS_FORMAT_DV: if (buflen < 9) { - uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming" + uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming " "interface %d FORMAT error\n", dev->udev->devnum, alts->desc.bInterfaceNumber); @@ -372,7 +370,7 @@ static int uvc_parse_format(struct uvc_device *dev, strlcpy(format->name, "HD-DV", sizeof format->name); break; default: - uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming" + uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming " "interface %d: unknown DV format %u\n", dev->udev->devnum, alts->desc.bInterfaceNumber, buffer[8]); @@ -401,7 +399,7 @@ static int uvc_parse_format(struct uvc_device *dev, case VS_FORMAT_STREAM_BASED: /* Not supported yet. */ default: - uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming" + uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming " "interface %d unsupported format %u\n", dev->udev->devnum, alts->desc.bInterfaceNumber, buffer[2]); @@ -413,20 +411,11 @@ static int uvc_parse_format(struct uvc_device *dev, buflen -= buffer[0]; buffer += buffer[0]; - /* Count the number of frame descriptors to test the bFrameIndex - * field when parsing the descriptors. We can't rely on the - * bNumFrameDescriptors field as some cameras don't initialize it - * properly. - */ - for (_buflen = buflen, _buffer = buffer; - _buflen > 2 && _buffer[2] == ftype; - _buflen -= _buffer[0], _buffer += _buffer[0]) - format->nframes++; - /* Parse the frame descriptors. Only uncompressed, MJPEG and frame * based formats have frame descriptors. */ while (buflen > 2 && buffer[2] == ftype) { + frame = &format->frame[format->nframes]; if (ftype != VS_FRAME_FRAME_BASED) n = buflen > 25 ? buffer[25] : 0; else @@ -435,22 +424,12 @@ static int uvc_parse_format(struct uvc_device *dev, n = n ? n : 3; if (buflen < 26 + 4*n) { - uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming" + uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming " "interface %d FRAME error\n", dev->udev->devnum, alts->desc.bInterfaceNumber); return -EINVAL; } - if (buffer[3] - 1 >= format->nframes) { - uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming" - "interface %d frame index %u out of range\n", - dev->udev->devnum, alts->desc.bInterfaceNumber, - buffer[3]); - return -EINVAL; - } - - frame = &format->frame[buffer[3] - 1]; - frame->bFrameIndex = buffer[3]; frame->bmCapabilities = buffer[4]; frame->wWidth = get_unaligned_le16(&buffer[5]); @@ -507,6 +486,7 @@ static int uvc_parse_format(struct uvc_device *dev, 10000000/frame->dwDefaultFrameInterval, (100000000/frame->dwDefaultFrameInterval)%10); + format->nframes++; buflen -= buffer[0]; buffer += buffer[0]; } @@ -518,7 +498,7 @@ static int uvc_parse_format(struct uvc_device *dev, if (buflen > 2 && buffer[2] == VS_COLORFORMAT) { if (buflen < 6) { - uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming" + uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming " "interface %d COLORFORMAT error\n", dev->udev->devnum, alts->desc.bInterfaceNumber); @@ -664,7 +644,7 @@ static int uvc_parse_streaming(struct uvc_device *dev, _buflen = buflen; /* Count the format and frame descriptors. */ - while (_buflen > 2) { + while (_buflen > 2 && _buffer[1] == CS_INTERFACE) { switch (_buffer[2]) { case VS_FORMAT_UNCOMPRESSED: case VS_FORMAT_MJPEG: @@ -729,7 +709,7 @@ static int uvc_parse_streaming(struct uvc_device *dev, streaming->nformats = nformats; /* Parse the format descriptors. */ - while (buflen > 2) { + while (buflen > 2 && buffer[1] == CS_INTERFACE) { switch (buffer[2]) { case VS_FORMAT_UNCOMPRESSED: case VS_FORMAT_MJPEG: @@ -1316,7 +1296,7 @@ static int uvc_scan_chain_forward(struct uvc_video_device *video, continue; if (forward->extension.bNrInPins != 1) { - uvc_trace(UVC_TRACE_DESCR, "Extension unit %d has" + uvc_trace(UVC_TRACE_DESCR, "Extension unit %d has " "more than 1 input pin.\n", entity->id); return -1; } @@ -1614,6 +1594,7 @@ static int uvc_probe(struct usb_interface *intf, INIT_LIST_HEAD(&dev->entities); INIT_LIST_HEAD(&dev->streaming); kref_init(&dev->kref); + atomic_set(&dev->users, 0); dev->udev = usb_get_dev(udev); dev->intf = usb_get_intf(intf); @@ -1927,7 +1908,7 @@ static struct usb_device_id uvc_ids[] = { .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = UVC_QUIRK_STREAM_NO_FID }, - /* Lenovo Thinkpad SL500 */ + /* Lenovo Thinkpad SL400/SL500 */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, .idVendor = 0x17ef, @@ -1936,6 +1917,15 @@ static struct usb_device_id uvc_ids[] = { .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = UVC_QUIRK_STREAM_NO_FID }, + /* Aveo Technology USB 2.0 Camera */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x1871, + .idProduct = 0x0306, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_QUIRK_PROBE_EXTRAFIELDS }, /* Ecamm Pico iMage */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, @@ -1945,6 +1935,15 @@ static struct usb_device_id uvc_ids[] = { .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = UVC_QUIRK_PROBE_EXTRAFIELDS }, + /* FSC WebCam V30S */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x18ec, + .idProduct = 0x3288, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_QUIRK_PROBE_MINMAX }, /* Bodelin ProScopeHR */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_DEV_HI @@ -1965,8 +1964,7 @@ static struct usb_device_id uvc_ids[] = { .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = UVC_QUIRK_PROBE_MINMAX - | UVC_QUIRK_IGNORE_SELECTOR_UNIT - | UVC_QUIRK_PRUNE_CONTROLS }, + | UVC_QUIRK_IGNORE_SELECTOR_UNIT }, /* Generic USB Video Class */ { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) }, {} diff --git a/drivers/media/video/uvc/uvc_queue.c b/drivers/media/video/uvc/uvc_queue.c index 0155752e4a5a..f854698c4061 100644 --- a/drivers/media/video/uvc/uvc_queue.c +++ b/drivers/media/video/uvc/uvc_queue.c @@ -172,6 +172,20 @@ int uvc_free_buffers(struct uvc_video_queue *queue) return 0; } +/* + * Check if buffers have been allocated. + */ +int uvc_queue_allocated(struct uvc_video_queue *queue) +{ + int allocated; + + mutex_lock(&queue->mutex); + allocated = queue->count != 0; + mutex_unlock(&queue->mutex); + + return allocated; +} + static void __uvc_query_buffer(struct uvc_buffer *buf, struct v4l2_buffer *v4l2_buf) { diff --git a/drivers/media/video/uvc/uvc_status.c b/drivers/media/video/uvc/uvc_status.c index 21d87124986b..f152a9903862 100644 --- a/drivers/media/video/uvc/uvc_status.c +++ b/drivers/media/video/uvc/uvc_status.c @@ -194,7 +194,7 @@ int uvc_status_init(struct uvc_device *dev) dev->status, UVC_MAX_STATUS_SIZE, uvc_status_complete, dev, interval); - return usb_submit_urb(dev->int_urb, GFP_KERNEL); + return 0; } void uvc_status_cleanup(struct uvc_device *dev) @@ -205,15 +205,30 @@ void uvc_status_cleanup(struct uvc_device *dev) uvc_input_cleanup(dev); } -int uvc_status_suspend(struct uvc_device *dev) +int uvc_status_start(struct uvc_device *dev) +{ + if (dev->int_urb == NULL) + return 0; + + return usb_submit_urb(dev->int_urb, GFP_KERNEL); +} + +void uvc_status_stop(struct uvc_device *dev) { usb_kill_urb(dev->int_urb); +} + +int uvc_status_suspend(struct uvc_device *dev) +{ + if (atomic_read(&dev->users)) + usb_kill_urb(dev->int_urb); + return 0; } int uvc_status_resume(struct uvc_device *dev) { - if (dev->int_urb == NULL) + if (dev->int_urb == NULL || atomic_read(&dev->users) == 0) return 0; 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 2a80caa54fb4..5e77cad29690 100644 --- a/drivers/media/video/uvc/uvc_v4l2.c +++ b/drivers/media/video/uvc/uvc_v4l2.c @@ -46,6 +46,8 @@ static int uvc_v4l2_query_menu(struct uvc_video_device *video, struct uvc_menu_info *menu_info; struct uvc_control_mapping *mapping; struct uvc_control *ctrl; + u32 index = query_menu->index; + u32 id = query_menu->id; ctrl = uvc_find_control(video, query_menu->id, &mapping); if (ctrl == NULL || mapping->v4l2_type != V4L2_CTRL_TYPE_MENU) @@ -54,6 +56,10 @@ static int uvc_v4l2_query_menu(struct uvc_video_device *video, if (query_menu->index >= mapping->menu_count) return -EINVAL; + memset(query_menu, 0, sizeof(*query_menu)); + query_menu->id = id; + query_menu->index = index; + menu_info = &mapping->menu_info[query_menu->index]; strlcpy(query_menu->name, menu_info->name, sizeof query_menu->name); return 0; @@ -245,7 +251,7 @@ static int uvc_v4l2_set_format(struct uvc_video_device *video, if (fmt->type != video->streaming->type) return -EINVAL; - if (uvc_queue_streaming(&video->queue)) + if (uvc_queue_allocated(&video->queue)) return -EBUSY; ret = uvc_v4l2_try_format(video, fmt, &probe, &format, &frame); @@ -433,6 +439,15 @@ static int uvc_v4l2_open(struct file *file) goto done; } + if (atomic_inc_return(&video->dev->users) == 1) { + if ((ret = uvc_status_start(video->dev)) < 0) { + usb_autopm_put_interface(video->dev->intf); + atomic_dec(&video->dev->users); + kfree(handle); + goto done; + } + } + handle->device = video; handle->state = UVC_HANDLE_PASSIVE; file->private_data = handle; @@ -467,6 +482,9 @@ static int uvc_v4l2_release(struct file *file) kfree(handle); file->private_data = NULL; + if (atomic_dec_return(&video->dev->users) == 0) + uvc_status_stop(video->dev); + usb_autopm_put_interface(video->dev->intf); kref_put(&video->dev->kref, uvc_delete); return 0; @@ -512,7 +530,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) memset(&xctrl, 0, sizeof xctrl); xctrl.id = ctrl->id; - uvc_ctrl_begin(video); + ret = uvc_ctrl_begin(video); + if (ret < 0) + return ret; + ret = uvc_ctrl_get(video, &xctrl); uvc_ctrl_rollback(video); if (ret >= 0) @@ -529,7 +550,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) xctrl.id = ctrl->id; xctrl.value = ctrl->value; - uvc_ctrl_begin(video); + ret = uvc_ctrl_begin(video); + if (ret < 0) + return ret; + ret = uvc_ctrl_set(video, &xctrl); if (ret < 0) { uvc_ctrl_rollback(video); @@ -548,7 +572,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) struct v4l2_ext_control *ctrl = ctrls->controls; unsigned int i; - uvc_ctrl_begin(video); + ret = uvc_ctrl_begin(video); + if (ret < 0) + return ret; + for (i = 0; i < ctrls->count; ++ctrl, ++i) { ret = uvc_ctrl_get(video, ctrl); if (ret < 0) { @@ -648,7 +675,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) case VIDIOC_S_INPUT: { - u8 input = *(u32 *)arg + 1; + u32 input = *(u32 *)arg + 1; if ((ret = uvc_acquire_privileges(handle)) < 0) return ret; @@ -660,7 +687,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) break; } - if (input > video->selector->selector.bNrInPins) + if (input == 0 || input > video->selector->selector.bNrInPins) return -EINVAL; return uvc_query_ctrl(video->dev, SET_CUR, video->selector->id, diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c index 6ce974d7362f..01b633c73480 100644 --- a/drivers/media/video/uvc/uvc_video.c +++ b/drivers/media/video/uvc/uvc_video.c @@ -65,7 +65,8 @@ static void uvc_fixup_video_ctrl(struct uvc_video_device *video, struct uvc_streaming_control *ctrl) { struct uvc_format *format; - struct uvc_frame *frame; + struct uvc_frame *frame = NULL; + unsigned int i; if (ctrl->bFormatIndex <= 0 || ctrl->bFormatIndex > video->streaming->nformats) @@ -73,11 +74,15 @@ static void uvc_fixup_video_ctrl(struct uvc_video_device *video, format = &video->streaming->format[ctrl->bFormatIndex - 1]; - if (ctrl->bFrameIndex <= 0 || - ctrl->bFrameIndex > format->nframes) - return; + for (i = 0; i < format->nframes; ++i) { + if (format->frame[i].bFrameIndex == ctrl->bFrameIndex) { + frame = &format->frame[i]; + break; + } + } - frame = &format->frame[ctrl->bFrameIndex - 1]; + if (frame == NULL) + return; if (!(format->flags & UVC_FMT_FLAG_COMPRESSED) || (ctrl->dwMaxVideoFrameSize == 0 && @@ -1089,7 +1094,7 @@ int uvc_video_init(struct uvc_video_device *video) /* Zero bFrameIndex might be correct. Stream-based formats (including * MPEG-2 TS and DV) do not support frames but have a dummy frame * descriptor with bFrameIndex set to zero. If the default frame - * descriptor is not found, use the first avalable frame. + * descriptor is not found, use the first available frame. */ for (i = format->nframes; i > 0; --i) { frame = &format->frame[i-1]; diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h index e5014e668f99..3c78d3c1e4c0 100644 --- a/drivers/media/video/uvc/uvcvideo.h +++ b/drivers/media/video/uvc/uvcvideo.h @@ -313,7 +313,6 @@ struct uvc_xu_control { #define UVC_QUIRK_BUILTIN_ISIGHT 0x00000008 #define UVC_QUIRK_STREAM_NO_FID 0x00000010 #define UVC_QUIRK_IGNORE_SELECTOR_UNIT 0x00000020 -#define UVC_QUIRK_PRUNE_CONTROLS 0x00000040 #define UVC_QUIRK_FIX_BANDWIDTH 0x00000080 /* Format flags */ @@ -634,6 +633,7 @@ struct uvc_device { enum uvc_device_state state; struct kref kref; struct list_head list; + atomic_t users; /* Video control interface */ __u16 uvc_version; @@ -747,6 +747,7 @@ extern struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue, struct uvc_buffer *buf); extern unsigned int uvc_queue_poll(struct uvc_video_queue *queue, struct file *file, poll_table *wait); +extern int uvc_queue_allocated(struct uvc_video_queue *queue); static inline int uvc_queue_streaming(struct uvc_video_queue *queue) { return queue->flags & UVC_QUEUE_STREAMING; @@ -770,6 +771,8 @@ extern int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit, /* Status */ extern int uvc_status_init(struct uvc_device *dev); extern void uvc_status_cleanup(struct uvc_device *dev); +extern int uvc_status_start(struct uvc_device *dev); +extern void uvc_status_stop(struct uvc_device *dev); extern int uvc_status_suspend(struct uvc_device *dev); extern int uvc_status_resume(struct uvc_device *dev); diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c index f576ef66b807..b91d66a767d7 100644 --- a/drivers/media/video/v4l2-common.c +++ b/drivers/media/video/v4l2-common.c @@ -746,6 +746,7 @@ void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client, const struct v4l2_subdev_ops *ops) { v4l2_subdev_init(sd, ops); + sd->flags |= V4L2_SUBDEV_FL_IS_I2C; /* the owner is the same as the i2c_client's driver owner */ sd->owner = client->driver->driver.owner; /* i2c_client and v4l2_subdev point to one another */ @@ -801,6 +802,17 @@ struct v4l2_subdev *v4l2_i2c_new_subdev(struct v4l2_device *v4l2_dev, /* Decrease the module use count to match the first try_module_get. */ module_put(client->driver->driver.owner); + if (sd) { + /* We return errors from v4l2_subdev_call only if we have the + callback as the .s_config is not mandatory */ + int err = v4l2_subdev_call(sd, core, s_config, 0, NULL); + + if (err && err != -ENOIOCTLCMD) { + v4l2_device_unregister_subdev(sd); + sd = NULL; + } + } + error: /* If we have a client but no subdev, then something went wrong and we must unregister the client. */ @@ -851,6 +863,17 @@ struct v4l2_subdev *v4l2_i2c_new_probed_subdev(struct v4l2_device *v4l2_dev, /* Decrease the module use count to match the first try_module_get. */ module_put(client->driver->driver.owner); + if (sd) { + /* We return errors from v4l2_subdev_call only if we have the + callback as the .s_config is not mandatory */ + int err = v4l2_subdev_call(sd, core, s_config, 0, NULL); + + if (err && err != -ENOIOCTLCMD) { + v4l2_device_unregister_subdev(sd); + sd = NULL; + } + } + error: /* If we have a client but no subdev, then something went wrong and we must unregister the client. */ @@ -871,6 +894,89 @@ struct v4l2_subdev *v4l2_i2c_new_probed_subdev_addr(struct v4l2_device *v4l2_dev } EXPORT_SYMBOL_GPL(v4l2_i2c_new_probed_subdev_addr); +/* Load an i2c sub-device. */ +struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev, + struct i2c_adapter *adapter, const char *module_name, + struct i2c_board_info *info, const unsigned short *probe_addrs) +{ + struct v4l2_subdev *sd = NULL; + struct i2c_client *client; + + BUG_ON(!v4l2_dev); + + if (module_name) + request_module(module_name); + + /* Create the i2c client */ + if (info->addr == 0 && probe_addrs) + client = i2c_new_probed_device(adapter, info, probe_addrs); + else + client = i2c_new_device(adapter, info); + + /* Note: by loading the module first we are certain that c->driver + will be set if the driver was found. If the module was not loaded + first, then the i2c core tries to delay-load the module for us, + and then c->driver is still NULL until the module is finally + loaded. This delay-load mechanism doesn't work if other drivers + want to use the i2c device, so explicitly loading the module + is the best alternative. */ + if (client == NULL || client->driver == NULL) + goto error; + + /* Lock the module so we can safely get the v4l2_subdev pointer */ + if (!try_module_get(client->driver->driver.owner)) + goto error; + sd = i2c_get_clientdata(client); + + /* Register with the v4l2_device which increases the module's + use count as well. */ + if (v4l2_device_register_subdev(v4l2_dev, sd)) + sd = NULL; + /* Decrease the module use count to match the first try_module_get. */ + module_put(client->driver->driver.owner); + + if (sd) { + /* We return errors from v4l2_subdev_call only if we have the + callback as the .s_config is not mandatory */ + int err = v4l2_subdev_call(sd, core, s_config, + info->irq, info->platform_data); + + if (err && err != -ENOIOCTLCMD) { + v4l2_device_unregister_subdev(sd); + sd = NULL; + } + } + +error: + /* If we have a client but no subdev, then something went wrong and + we must unregister the client. */ + if (client && sd == NULL) + i2c_unregister_device(client); + return sd; +} +EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev_board); + +struct v4l2_subdev *v4l2_i2c_new_subdev_cfg(struct v4l2_device *v4l2_dev, + struct i2c_adapter *adapter, + const char *module_name, const char *client_type, + int irq, void *platform_data, + u8 addr, const unsigned short *probe_addrs) +{ + struct i2c_board_info info; + + /* Setup the i2c board info with the device type and + the device address. */ + memset(&info, 0, sizeof(info)); + strlcpy(info.type, client_type, sizeof(info.type)); + info.addr = addr; + info.irq = irq; + info.platform_data = platform_data; + + return v4l2_i2c_new_subdev_board(v4l2_dev, adapter, module_name, + &info, probe_addrs); +} +EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev_cfg); + /* Return i2c client address of v4l2_subdev. */ unsigned short v4l2_i2c_subdev_addr(struct v4l2_subdev *sd) { @@ -897,8 +1003,7 @@ const unsigned short *v4l2_i2c_tuner_addrs(enum v4l2_i2c_tuner_type type) }; static const unsigned short tv_addrs[] = { 0x42, 0x43, 0x4a, 0x4b, /* tda8290 */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x60, 0x61, 0x62, 0x63, 0x64, I2C_CLIENT_END }; @@ -916,4 +1021,78 @@ const unsigned short *v4l2_i2c_tuner_addrs(enum v4l2_i2c_tuner_type type) } EXPORT_SYMBOL_GPL(v4l2_i2c_tuner_addrs); -#endif +#endif /* defined(CONFIG_I2C) */ + +/* Clamp x to be between min and max, aligned to a multiple of 2^align. min + * and max don't have to be aligned, but there must be at least one valid + * value. E.g., min=17,max=31,align=4 is not allowed as there are no multiples + * of 16 between 17 and 31. */ +static unsigned int clamp_align(unsigned int x, unsigned int min, + unsigned int max, unsigned int align) +{ + /* Bits that must be zero to be aligned */ + unsigned int mask = ~((1 << align) - 1); + + /* Round to nearest aligned value */ + if (align) + x = (x + (1 << (align - 1))) & mask; + + /* Clamp to aligned value of min and max */ + if (x < min) + x = (min + ~mask) & mask; + else if (x > max) + x = max & mask; + + return x; +} + +/* Bound an image to have a width between wmin and wmax, and height between + * hmin and hmax, inclusive. Additionally, the width will be a multiple of + * 2^walign, the height will be a multiple of 2^halign, and the overall size + * (width*height) will be a multiple of 2^salign. The image may be shrunk + * or enlarged to fit the alignment constraints. + * + * The width or height maximum must not be smaller than the corresponding + * minimum. The alignments must not be so high there are no possible image + * sizes within the allowed bounds. wmin and hmin must be at least 1 + * (don't use 0). If you don't care about a certain alignment, specify 0, + * as 2^0 is 1 and one byte alignment is equivalent to no alignment. If + * you only want to adjust downward, specify a maximum that's the same as + * the initial value. + */ +void v4l_bound_align_image(u32 *w, unsigned int wmin, unsigned int wmax, + unsigned int walign, + u32 *h, unsigned int hmin, unsigned int hmax, + unsigned int halign, unsigned int salign) +{ + *w = clamp_align(*w, wmin, wmax, walign); + *h = clamp_align(*h, hmin, hmax, halign); + + /* Usually we don't need to align the size and are done now. */ + if (!salign) + return; + + /* How much alignment do we have? */ + walign = __ffs(*w); + halign = __ffs(*h); + /* Enough to satisfy the image alignment? */ + if (walign + halign < salign) { + /* Max walign where there is still a valid width */ + unsigned int wmaxa = __fls(wmax ^ (wmin - 1)); + /* Max halign where there is still a valid height */ + unsigned int hmaxa = __fls(hmax ^ (hmin - 1)); + + /* up the smaller alignment until we have enough */ + do { + if (halign >= hmaxa || + (walign <= halign && walign < wmaxa)) { + *w = clamp_align(*w, wmin, wmax, walign + 1); + walign = __ffs(*w); + } else { + *h = clamp_align(*h, hmin, hmax, halign + 1); + halign = __ffs(*h); + } + } while (halign + walign < salign); + } +} +EXPORT_SYMBOL_GPL(v4l_bound_align_image); diff --git a/drivers/media/video/v4l2-device.c b/drivers/media/video/v4l2-device.c index 94aa485ade52..0d06e7cbd5b3 100644 --- a/drivers/media/video/v4l2-device.c +++ b/drivers/media/video/v4l2-device.c @@ -49,6 +49,22 @@ int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev) } EXPORT_SYMBOL_GPL(v4l2_device_register); +int v4l2_device_set_name(struct v4l2_device *v4l2_dev, const char *basename, + atomic_t *instance) +{ + int num = atomic_inc_return(instance) - 1; + int len = strlen(basename); + + if (basename[len - 1] >= '0' && basename[len - 1] <= '9') + snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), + "%s-%d", basename, num); + else + snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), + "%s%d", basename, num); + return num; +} +EXPORT_SYMBOL_GPL(v4l2_device_set_name); + void v4l2_device_disconnect(struct v4l2_device *v4l2_dev) { if (v4l2_dev->dev) { @@ -67,8 +83,21 @@ void v4l2_device_unregister(struct v4l2_device *v4l2_dev) v4l2_device_disconnect(v4l2_dev); /* Unregister subdevs */ - list_for_each_entry_safe(sd, next, &v4l2_dev->subdevs, list) + list_for_each_entry_safe(sd, next, &v4l2_dev->subdevs, list) { v4l2_device_unregister_subdev(sd); +#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) + if (sd->flags & V4L2_SUBDEV_FL_IS_I2C) { + struct i2c_client *client = v4l2_get_subdevdata(sd); + + /* We need to unregister the i2c client explicitly. + We cannot rely on i2c_del_adapter to always + unregister clients for us, since if the i2c bus + is a platform bus, then it is never deleted. */ + if (client) + i2c_unregister_device(client); + } +#endif + } } EXPORT_SYMBOL_GPL(v4l2_device_unregister); diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c index b7b05842cf28..f1ccf98c0a6f 100644 --- a/drivers/media/video/videobuf-core.c +++ b/drivers/media/video/videobuf-core.c @@ -118,6 +118,7 @@ void videobuf_queue_core_init(struct videobuf_queue *q, void *priv, struct videobuf_qtype_ops *int_ops) { + BUG_ON(!q); memset(q, 0, sizeof(*q)); q->irqlock = irqlock; q->dev = dev; @@ -439,6 +440,7 @@ int videobuf_reqbufs(struct videobuf_queue *q, } req->count = retval; + retval = 0; done: mutex_unlock(&q->vb_lock); @@ -454,7 +456,7 @@ int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b) dprintk(1, "querybuf: Wrong type.\n"); goto done; } - if (unlikely(b->index < 0 || b->index >= VIDEO_MAX_FRAME)) { + if (unlikely(b->index >= VIDEO_MAX_FRAME)) { dprintk(1, "querybuf: index out of range.\n"); goto done; } @@ -495,7 +497,7 @@ int videobuf_qbuf(struct videobuf_queue *q, dprintk(1, "qbuf: Wrong type.\n"); goto done; } - if (b->index < 0 || b->index >= VIDEO_MAX_FRAME) { + if (b->index >= VIDEO_MAX_FRAME) { dprintk(1, "qbuf: index out of range.\n"); goto done; } diff --git a/drivers/media/video/videobuf-dma-contig.c b/drivers/media/video/videobuf-dma-contig.c index 6109fb5f34e2..d09ce83a9429 100644 --- a/drivers/media/video/videobuf-dma-contig.c +++ b/drivers/media/video/videobuf-dma-contig.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -25,6 +26,7 @@ struct videobuf_dma_contig_memory { void *vaddr; dma_addr_t dma_handle; unsigned long size; + int is_userptr; }; #define MAGIC_DC_MEM 0x0733ac61 @@ -108,6 +110,82 @@ static struct vm_operations_struct videobuf_vm_ops = { .close = videobuf_vm_close, }; +/** + * videobuf_dma_contig_user_put() - reset pointer to user space buffer + * @mem: per-buffer private videobuf-dma-contig data + * + * This function resets the user space pointer + */ +static void videobuf_dma_contig_user_put(struct videobuf_dma_contig_memory *mem) +{ + mem->is_userptr = 0; + mem->dma_handle = 0; + mem->size = 0; +} + +/** + * videobuf_dma_contig_user_get() - setup user space memory pointer + * @mem: per-buffer private videobuf-dma-contig data + * @vb: video buffer to map + * + * This function validates and sets up a pointer to user space memory. + * Only physically contiguous pfn-mapped memory is accepted. + * + * Returns 0 if successful. + */ +static int videobuf_dma_contig_user_get(struct videobuf_dma_contig_memory *mem, + struct videobuf_buffer *vb) +{ + struct mm_struct *mm = current->mm; + struct vm_area_struct *vma; + unsigned long prev_pfn, this_pfn; + unsigned long pages_done, user_address; + int ret; + + mem->size = PAGE_ALIGN(vb->size); + mem->is_userptr = 0; + ret = -EINVAL; + + down_read(&mm->mmap_sem); + + vma = find_vma(mm, vb->baddr); + if (!vma) + goto out_up; + + if ((vb->baddr + mem->size) > vma->vm_end) + goto out_up; + + pages_done = 0; + prev_pfn = 0; /* kill warning */ + user_address = vb->baddr; + + while (pages_done < (mem->size >> PAGE_SHIFT)) { + ret = follow_pfn(vma, user_address, &this_pfn); + if (ret) + break; + + if (pages_done == 0) + mem->dma_handle = this_pfn << PAGE_SHIFT; + else if (this_pfn != (prev_pfn + 1)) + ret = -EFAULT; + + if (ret) + break; + + prev_pfn = this_pfn; + user_address += PAGE_SIZE; + pages_done++; + } + + if (!ret) + mem->is_userptr = 1; + + out_up: + up_read(¤t->mm->mmap_sem); + + return ret; +} + static void *__videobuf_alloc(size_t size) { struct videobuf_dma_contig_memory *mem; @@ -154,12 +232,11 @@ static int __videobuf_iolock(struct videobuf_queue *q, 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. - */ + /* handle pointer from user space */ if (vb->baddr) - return -EINVAL; + return videobuf_dma_contig_user_get(mem, vb); + /* allocate memory for the read() method */ mem->size = PAGE_ALIGN(vb->size); mem->vaddr = dma_alloc_coherent(q->dev, mem->size, &mem->dma_handle, GFP_KERNEL); @@ -182,19 +259,6 @@ static int __videobuf_iolock(struct videobuf_queue *q, 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; @@ -356,7 +420,6 @@ static struct videobuf_qtype_ops qops = { .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, @@ -400,7 +463,7 @@ void videobuf_dma_contig_free(struct videobuf_queue *q, So, it should free memory only if the memory were allocated for read() operation. */ - if ((buf->memory != V4L2_MEMORY_USERPTR) || buf->baddr) + if (buf->memory != V4L2_MEMORY_USERPTR) return; if (!mem) @@ -408,6 +471,13 @@ void videobuf_dma_contig_free(struct videobuf_queue *q, MAGIC_CHECK(mem->magic, MAGIC_DC_MEM); + /* handle user space pointer case */ + if (buf->baddr) { + videobuf_dma_contig_user_put(mem); + return; + } + + /* read() method */ dma_free_coherent(q->dev, mem->size, mem->vaddr, mem->dma_handle); mem->vaddr = NULL; } diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c index da1790e57a86..a8dd22ace3fb 100644 --- a/drivers/media/video/videobuf-dma-sg.c +++ b/drivers/media/video/videobuf-dma-sg.c @@ -58,9 +58,10 @@ videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages) struct page *pg; int i; - sglist = kcalloc(nr_pages, sizeof(struct scatterlist), GFP_KERNEL); + sglist = vmalloc(nr_pages * sizeof(*sglist)); if (NULL == sglist) return NULL; + memset(sglist, 0, nr_pages * sizeof(*sglist)); sg_init_table(sglist, nr_pages); for (i = 0; i < nr_pages; i++, virt += PAGE_SIZE) { pg = vmalloc_to_page(virt); @@ -72,7 +73,7 @@ videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages) return sglist; err: - kfree(sglist); + vfree(sglist); return NULL; } @@ -84,7 +85,7 @@ videobuf_pages_to_sg(struct page **pages, int nr_pages, int offset) if (NULL == pages[0]) return NULL; - sglist = kmalloc(nr_pages * sizeof(*sglist), GFP_KERNEL); + sglist = vmalloc(nr_pages * sizeof(*sglist)); if (NULL == sglist) return NULL; sg_init_table(sglist, nr_pages); @@ -104,12 +105,12 @@ videobuf_pages_to_sg(struct page **pages, int nr_pages, int offset) nopage: dprintk(2,"sgl: oops - no page\n"); - kfree(sglist); + vfree(sglist); return NULL; highmem: dprintk(2,"sgl: oops - highmem page\n"); - kfree(sglist); + vfree(sglist); return NULL; } @@ -230,7 +231,7 @@ int videobuf_dma_map(struct videobuf_queue* q, struct videobuf_dmabuf *dma) (dma->vmalloc,dma->nr_pages); } if (dma->bus_addr) { - dma->sglist = kmalloc(sizeof(struct scatterlist), GFP_KERNEL); + dma->sglist = vmalloc(sizeof(*dma->sglist)); if (NULL != dma->sglist) { dma->sglen = 1; sg_dma_address(&dma->sglist[0]) = dma->bus_addr & PAGE_MASK; @@ -248,10 +249,10 @@ int videobuf_dma_map(struct videobuf_queue* q, struct videobuf_dmabuf *dma) if (0 == dma->sglen) { printk(KERN_WARNING "%s: videobuf_map_sg failed\n",__func__); - kfree(dma->sglist); + vfree(dma->sglist); dma->sglist = NULL; dma->sglen = 0; - return -EIO; + return -ENOMEM; } } return 0; @@ -274,7 +275,7 @@ int videobuf_dma_unmap(struct videobuf_queue* q,struct videobuf_dmabuf *dma) dma_unmap_sg(q->dev, dma->sglist, dma->nr_pages, dma->direction); - kfree(dma->sglist); + vfree(dma->sglist); dma->sglist = NULL; dma->sglen = 0; return 0; diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c index 43e0998adb53..97b082fe4473 100644 --- a/drivers/media/video/vino.c +++ b/drivers/media/video/vino.c @@ -868,9 +868,9 @@ static void vino_sync_buffer(struct vino_framebuffer *fb) dprintk("vino_sync_buffer():\n"); for (i = 0; i < fb->desc_table.page_count; i++) - dma_sync_single(NULL, - fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i], - PAGE_SIZE, DMA_FROM_DEVICE); + dma_sync_single_for_cpu(NULL, + fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i], + PAGE_SIZE, DMA_FROM_DEVICE); } /* Framebuffer fifo functions (need to be locked externally) */ diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index fbfefae7886f..cd7266858462 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -883,15 +883,8 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, maxh = norm_maxh(); f->fmt.pix.field = field; - if (f->fmt.pix.height < 32) - f->fmt.pix.height = 32; - if (f->fmt.pix.height > maxh) - f->fmt.pix.height = maxh; - if (f->fmt.pix.width < 48) - f->fmt.pix.width = 48; - if (f->fmt.pix.width > maxw) - f->fmt.pix.width = maxw; - f->fmt.pix.width &= ~0x03; + v4l_bound_align_image(&f->fmt.pix.width, 48, maxw, 2, + &f->fmt.pix.height, 32, maxh, 0, 0); f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3; f->fmt.pix.sizeimage = diff --git a/drivers/media/video/w9968cf.c b/drivers/media/video/w9968cf.c index f59b2bd07e89..6c3f23e31b5c 100644 --- a/drivers/media/video/w9968cf.c +++ b/drivers/media/video/w9968cf.c @@ -460,7 +460,7 @@ static int w9968cf_set_picture(struct w9968cf_device*, struct video_picture); static int w9968cf_set_window(struct w9968cf_device*, struct video_window); static int w9968cf_postprocess_frame(struct w9968cf_device*, struct w9968cf_frame_t*); -static int w9968cf_adjust_window_size(struct w9968cf_device*, u16* w, u16* h); +static int w9968cf_adjust_window_size(struct w9968cf_device*, u32 *w, u32 *h); static void w9968cf_init_framelist(struct w9968cf_device*); static void w9968cf_push_frame(struct w9968cf_device*, u8 f_num); static void w9968cf_pop_frame(struct w9968cf_device*,struct w9968cf_frame_t**); @@ -1763,8 +1763,7 @@ w9968cf_set_window(struct w9968cf_device* cam, struct video_window win) #define UNSC(x) ((x) >> 10) /* Make sure we are using a supported resolution */ - if ((err = w9968cf_adjust_window_size(cam, (u16*)&win.width, - (u16*)&win.height))) + if ((err = w9968cf_adjust_window_size(cam, &win.width, &win.height))) goto error; /* Scaling factors */ @@ -1914,12 +1913,9 @@ error: Return 0 on success, -1 otherwise. --------------------------------------------------------------------------*/ static int -w9968cf_adjust_window_size(struct w9968cf_device* cam, u16* width, u16* height) +w9968cf_adjust_window_size(struct w9968cf_device *cam, u32 *width, u32 *height) { - u16 maxw, maxh; - - if ((*width < cam->minwidth) || (*height < cam->minheight)) - return -ERANGE; + unsigned int maxw, maxh, align; maxw = cam->upscaling && !(cam->vpp_flag & VPP_DECOMPRESSION) && w9968cf_vpp ? max((u16)W9968CF_MAX_WIDTH, cam->maxwidth) @@ -1927,16 +1923,10 @@ w9968cf_adjust_window_size(struct w9968cf_device* cam, u16* width, u16* height) maxh = cam->upscaling && !(cam->vpp_flag & VPP_DECOMPRESSION) && w9968cf_vpp ? max((u16)W9968CF_MAX_HEIGHT, cam->maxheight) : cam->maxheight; + align = (cam->vpp_flag & VPP_DECOMPRESSION) ? 4 : 0; - if (*width > maxw) - *width = maxw; - if (*height > maxh) - *height = maxh; - - if (cam->vpp_flag & VPP_DECOMPRESSION) { - *width &= ~15L; /* multiple of 16 */ - *height &= ~15L; - } + v4l_bound_align_image(width, cam->minwidth, maxw, align, + height, cam->minheight, maxh, align, 0); PDBGG("Window size adjusted w=%u, h=%u ", *width, *height) @@ -3043,8 +3033,8 @@ static long w9968cf_v4l_ioctl(struct file *filp, if (win.clipcount != 0 || win.flags != 0) return -EINVAL; - if ((err = w9968cf_adjust_window_size(cam, (u16*)&win.width, - (u16*)&win.height))) { + if ((err = w9968cf_adjust_window_size(cam, &win.width, + &win.height))) { DBG(4, "Resolution not supported (%ux%u). " "VIDIOCSWIN failed", win.width, win.height) return err; @@ -3116,6 +3106,7 @@ static long w9968cf_v4l_ioctl(struct file *filp, { struct video_mmap mmap; struct w9968cf_frame_t* fr; + u32 w, h; int err = 0; if (copy_from_user(&mmap, arg, sizeof(mmap))) @@ -3164,8 +3155,10 @@ static long w9968cf_v4l_ioctl(struct file *filp, } } - if ((err = w9968cf_adjust_window_size(cam, (u16*)&mmap.width, - (u16*)&mmap.height))) { + w = mmap.width; h = mmap.height; + err = w9968cf_adjust_window_size(cam, &w, &h); + mmap.width = w; mmap.height = h; + if (err) { DBG(4, "Resolution not supported (%dx%d). " "VIDIOCMCAPTURE failed", mmap.width, mmap.height) diff --git a/drivers/media/video/zoran/zoran_card.c b/drivers/media/video/zoran/zoran_card.c index ea6c577b0eb3..03dc2f3cf84a 100644 --- a/drivers/media/video/zoran/zoran_card.c +++ b/drivers/media/video/zoran/zoran_card.c @@ -1022,7 +1022,7 @@ zr36057_init (struct zoran *zr) zr->vbuf_bytesperline = 0; /* Avoid nonsense settings from user for default input/norm */ - if (default_norm < 0 && default_norm > 2) + if (default_norm < 0 || default_norm > 2) default_norm = 0; if (default_norm == 0) { zr->norm = V4L2_STD_PAL; @@ -1477,7 +1477,7 @@ static struct pci_driver zoran_driver = { .name = "zr36067", .id_table = zr36067_pci_tbl, .probe = zoran_probe, - .remove = zoran_remove, + .remove = __devexit_p(zoran_remove), }; static int __init zoran_init(void) diff --git a/drivers/media/video/zoran/zoran_driver.c b/drivers/media/video/zoran/zoran_driver.c index 643cccaa1aab..3d7df32a3d87 100644 --- a/drivers/media/video/zoran/zoran_driver.c +++ b/drivers/media/video/zoran/zoran_driver.c @@ -2088,16 +2088,10 @@ static int zoran_try_fmt_vid_cap(struct file *file, void *__fh, return -EINVAL; } - bpp = (zoran_formats[i].depth + 7) / 8; - fmt->fmt.pix.width &= ~((bpp == 2) ? 1 : 3); - if (fmt->fmt.pix.width > BUZ_MAX_WIDTH) - fmt->fmt.pix.width = BUZ_MAX_WIDTH; - if (fmt->fmt.pix.width < BUZ_MIN_WIDTH) - fmt->fmt.pix.width = BUZ_MIN_WIDTH; - if (fmt->fmt.pix.height > BUZ_MAX_HEIGHT) - fmt->fmt.pix.height = BUZ_MAX_HEIGHT; - if (fmt->fmt.pix.height < BUZ_MIN_HEIGHT) - fmt->fmt.pix.height = BUZ_MIN_HEIGHT; + bpp = DIV_ROUND_UP(zoran_formats[i].depth, 8); + v4l_bound_align_image( + &fmt->fmt.pix.width, BUZ_MIN_WIDTH, BUZ_MAX_WIDTH, bpp == 2 ? 1 : 2, + &fmt->fmt.pix.height, BUZ_MIN_HEIGHT, BUZ_MAX_HEIGHT, 0, 0); mutex_unlock(&zr->resource_lock); return 0; diff --git a/drivers/media/video/zr364xx.c b/drivers/media/video/zr364xx.c index ac169c9eb18d..fc976f42f432 100644 --- a/drivers/media/video/zr364xx.c +++ b/drivers/media/video/zr364xx.c @@ -882,9 +882,11 @@ static void zr364xx_disconnect(struct usb_interface *intf) video_unregister_device(cam->vdev); cam->vdev = NULL; kfree(cam->buffer); - if (cam->framebuf) - vfree(cam->framebuf); + cam->buffer = NULL; + vfree(cam->framebuf); + cam->framebuf = NULL; kfree(cam); + cam = NULL; } diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c index de143deb06f0..7847bbc1440d 100644 --- a/drivers/memstick/core/mspro_block.c +++ b/drivers/memstick/core/mspro_block.c @@ -672,15 +672,14 @@ try_again: msb->req_sg); if (!msb->seg_count) { - chunk = __blk_end_request(msb->block_req, -ENOMEM, - blk_rq_cur_bytes(msb->block_req)); + chunk = __blk_end_request_cur(msb->block_req, -ENOMEM); continue; } - t_sec = msb->block_req->sector << 9; + t_sec = blk_rq_pos(msb->block_req) << 9; sector_div(t_sec, msb->page_size); - count = msb->block_req->nr_sectors << 9; + count = blk_rq_bytes(msb->block_req); count /= msb->page_size; param.system = msb->system; @@ -705,8 +704,8 @@ try_again: return 0; } - dev_dbg(&card->dev, "elv_next\n"); - msb->block_req = elv_next_request(msb->queue); + dev_dbg(&card->dev, "blk_fetch\n"); + msb->block_req = blk_fetch_request(msb->queue); if (!msb->block_req) { dev_dbg(&card->dev, "issue end\n"); return -EAGAIN; @@ -745,7 +744,7 @@ static int mspro_block_complete_req(struct memstick_dev *card, int error) t_len *= msb->page_size; } } else - t_len = msb->block_req->nr_sectors << 9; + t_len = blk_rq_bytes(msb->block_req); dev_dbg(&card->dev, "transferred %x (%d)\n", t_len, error); @@ -825,8 +824,8 @@ static void mspro_block_submit_req(struct request_queue *q) return; if (msb->eject) { - while ((req = elv_next_request(q)) != NULL) - __blk_end_request(req, -ENODEV, blk_rq_bytes(req)); + while ((req = blk_fetch_request(q)) != NULL) + __blk_end_request_all(req, -ENODEV); return; } @@ -1243,7 +1242,7 @@ static int mspro_block_init_disk(struct memstick_dev *card) sprintf(msb->disk->disk_name, "mspblk%d", disk_id); - blk_queue_hardsect_size(msb->queue, msb->page_size); + blk_queue_logical_block_size(msb->queue, msb->page_size); capacity = be16_to_cpu(sys_info->user_block_count); capacity *= be16_to_cpu(sys_info->block_size); diff --git a/drivers/message/fusion/lsi/mpi_history.txt b/drivers/message/fusion/lsi/mpi_history.txt index 693e4b511354..fa9249b4971a 100644 --- a/drivers/message/fusion/lsi/mpi_history.txt +++ b/drivers/message/fusion/lsi/mpi_history.txt @@ -130,7 +130,7 @@ mpi_ioc.h * 08-08-01 01.02.01 Original release for v1.2 work. * New format for FWVersion and ProductId in * MSG_IOC_FACTS_REPLY and MPI_FW_HEADER. - * 08-31-01 01.02.02 Addded event MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE and + * 08-31-01 01.02.02 Added event MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE and * related structure and defines. * Added event MPI_EVENT_ON_BUS_TIMER_EXPIRED. * Added MPI_IOCINIT_FLAGS_DISCARD_FW_IMAGE. @@ -190,7 +190,7 @@ mpi_ioc.h * 10-11-06 01.05.12 Added MPI_IOCFACTS_EXCEPT_METADATA_UNSUPPORTED. * Added MaxInitiators field to PortFacts reply. * Added SAS Device Status Change ReasonCode for - * asynchronous notificaiton. + * asynchronous notification. * Added MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE and event * data structure. * Added new ImageType values for FWDownload and FWUpload @@ -623,7 +623,7 @@ mpi_fc.h * 11-02-00 01.01.01 Original release for post 1.0 work * 12-04-00 01.01.02 Added messages for Common Transport Send and * Primitive Send. - * 01-09-01 01.01.03 Modifed some of the new flags to have an MPI prefix + * 01-09-01 01.01.03 Modified some of the new flags to have an MPI prefix * and modified the FcPrimitiveSend flags. * 01-25-01 01.01.04 Move InitiatorIndex in LinkServiceRsp reply to a larger * field. diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index 5d496a99e034..5d0ba4f5924c 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -146,7 +146,6 @@ static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS]; static MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS]; static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS]; -static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq); /* * Driver Callback Index's @@ -159,7 +158,8 @@ static u8 last_drv_idx; * Forward protos... */ static irqreturn_t mpt_interrupt(int irq, void *bus_id); -static int mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply); +static int mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, + MPT_FRAME_HDR *reply); static int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req, int replyBytes, u16 *u16reply, int maxwait, int sleepFlag); @@ -190,9 +190,9 @@ static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum); static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum); static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc); static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc); -static void mpt_timer_expired(unsigned long data); static void mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc); -static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch); +static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch, + int sleepFlag); static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp); static int mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag); static int mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init); @@ -207,8 +207,8 @@ static int procmpt_iocinfo_read(char *buf, char **start, off_t offset, #endif static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc); -//int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag); -static int ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply, int *evHandlers); +static int ProcessEventNotification(MPT_ADAPTER *ioc, + EventNotificationReply_t *evReply, int *evHandlers); static void mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf); static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info); static void mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info); @@ -276,6 +276,56 @@ mpt_get_cb_idx(MPT_DRIVER_CLASS dclass) return 0; } +/** + * mpt_is_discovery_complete - determine if discovery has completed + * @ioc: per adatper instance + * + * Returns 1 when discovery completed, else zero. + */ +static int +mpt_is_discovery_complete(MPT_ADAPTER *ioc) +{ + ConfigExtendedPageHeader_t hdr; + CONFIGPARMS cfg; + SasIOUnitPage0_t *buffer; + dma_addr_t dma_handle; + int rc = 0; + + memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t)); + memset(&cfg, 0, sizeof(CONFIGPARMS)); + hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION; + hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; + hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT; + cfg.cfghdr.ehdr = &hdr; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + + if ((mpt_config(ioc, &cfg))) + goto out; + if (!hdr.ExtPageLength) + goto out; + + buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4, + &dma_handle); + if (!buffer) + goto out; + + cfg.physAddr = dma_handle; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + + if ((mpt_config(ioc, &cfg))) + goto out_free_consistent; + + if (!(buffer->PhyData[0].PortFlags & + MPI_SAS_IOUNIT0_PORT_FLAGS_DISCOVERY_IN_PROGRESS)) + rc = 1; + + out_free_consistent: + pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, + buffer, dma_handle); + out: + return rc; +} + /** * mpt_fault_reset_work - work performed on workq after ioc fault * @work: input argument, used to derive ioc @@ -290,7 +340,7 @@ mpt_fault_reset_work(struct work_struct *work) int rc; unsigned long flags; - if (ioc->diagPending || !ioc->active) + if (ioc->ioc_reset_in_progress || !ioc->active) goto out; ioc_raw_state = mpt_GetIocState(ioc, 0); @@ -307,6 +357,12 @@ mpt_fault_reset_work(struct work_struct *work) printk(MYIOC_s_WARN_FMT "IOC is in FAULT state after " "reset (%04xh)\n", ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK); + } else if (ioc->bus_type == SAS && ioc->sas_discovery_quiesce_io) { + if ((mpt_is_discovery_complete(ioc))) { + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "clearing " + "discovery_quiesce_io flag\n", ioc->name)); + ioc->sas_discovery_quiesce_io = 0; + } } out: @@ -317,11 +373,11 @@ mpt_fault_reset_work(struct work_struct *work) ioc = ioc->alt_ioc; /* rearm the timer */ - spin_lock_irqsave(&ioc->fault_reset_work_lock, flags); + spin_lock_irqsave(&ioc->taskmgmt_lock, flags); if (ioc->reset_work_q) queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work, msecs_to_jiffies(MPT_POLLING_INTERVAL)); - spin_unlock_irqrestore(&ioc->fault_reset_work_lock, flags); + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); } @@ -501,9 +557,9 @@ mpt_interrupt(int irq, void *bus_id) /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** - * mpt_base_reply - MPT base driver's callback routine + * mptbase_reply - MPT base driver's callback routine * @ioc: Pointer to MPT_ADAPTER structure - * @mf: Pointer to original MPT request frame + * @req: Pointer to original MPT request frame * @reply: Pointer to MPT reply frame (NULL if TurboReply) * * MPT base driver's callback routine; all base driver @@ -514,122 +570,49 @@ mpt_interrupt(int irq, void *bus_id) * should be freed, or 0 if it shouldn't. */ static int -mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply) +mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply) { + EventNotificationReply_t *pEventReply; + u8 event; + int evHandlers; int freereq = 1; - u8 func; - dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply() called\n", ioc->name)); -#ifdef CONFIG_FUSION_LOGGING - if ((ioc->debug_level & MPT_DEBUG_MSG_FRAME) && - !(reply->u.hdr.MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) { - dmfprintk(ioc, printk(MYIOC_s_INFO_FMT ": Original request frame (@%p) header\n", - ioc->name, mf)); - DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)mf); - } -#endif - - func = reply->u.hdr.Function; - dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply, Function=%02Xh\n", - ioc->name, func)); - - if (func == MPI_FUNCTION_EVENT_NOTIFICATION) { - EventNotificationReply_t *pEvReply = (EventNotificationReply_t *) reply; - int evHandlers = 0; - int results; - - results = ProcessEventNotification(ioc, pEvReply, &evHandlers); - if (results != evHandlers) { - /* CHECKME! Any special handling needed here? */ - devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "Called %d event handlers, sum results = %d\n", - ioc->name, evHandlers, results)); - } - - /* - * Hmmm... It seems that EventNotificationReply is an exception - * to the rule of one reply per request. - */ - if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) { + switch (reply->u.hdr.Function) { + case MPI_FUNCTION_EVENT_NOTIFICATION: + pEventReply = (EventNotificationReply_t *)reply; + evHandlers = 0; + ProcessEventNotification(ioc, pEventReply, &evHandlers); + event = le32_to_cpu(pEventReply->Event) & 0xFF; + if (pEventReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) freereq = 0; - } else { - devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p returns Request frame\n", - ioc->name, pEvReply)); + if (event != MPI_EVENT_EVENT_CHANGE) + break; + case MPI_FUNCTION_CONFIG: + case MPI_FUNCTION_SAS_IO_UNIT_CONTROL: + ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD; + if (reply) { + ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_RF_VALID; + memcpy(ioc->mptbase_cmds.reply, reply, + min(MPT_DEFAULT_FRAME_SIZE, + 4 * reply->u.reply.MsgLength)); } - -#ifdef CONFIG_PROC_FS -// LogEvent(ioc, pEvReply); -#endif - - } else if (func == MPI_FUNCTION_EVENT_ACK) { - dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply, EventAck reply received\n", - ioc->name)); - } else if (func == MPI_FUNCTION_CONFIG) { - CONFIGPARMS *pCfg; - unsigned long flags; - - dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "config_complete (mf=%p,mr=%p)\n", - ioc->name, mf, reply)); - - pCfg = * ((CONFIGPARMS **)((u8 *) mf + ioc->req_sz - sizeof(void *))); - - if (pCfg) { - /* disable timer and remove from linked list */ - del_timer(&pCfg->timer); - - spin_lock_irqsave(&ioc->FreeQlock, flags); - list_del(&pCfg->linkage); - spin_unlock_irqrestore(&ioc->FreeQlock, flags); - - /* - * If IOC Status is SUCCESS, save the header - * and set the status code to GOOD. - */ - pCfg->status = MPT_CONFIG_ERROR; - if (reply) { - ConfigReply_t *pReply = (ConfigReply_t *)reply; - u16 status; - - status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK; - dcprintk(ioc, printk(MYIOC_s_NOTE_FMT " IOCStatus=%04xh, IOCLogInfo=%08xh\n", - ioc->name, status, le32_to_cpu(pReply->IOCLogInfo))); - - pCfg->status = status; - if (status == MPI_IOCSTATUS_SUCCESS) { - if ((pReply->Header.PageType & - MPI_CONFIG_PAGETYPE_MASK) == - MPI_CONFIG_PAGETYPE_EXTENDED) { - pCfg->cfghdr.ehdr->ExtPageLength = - le16_to_cpu(pReply->ExtPageLength); - pCfg->cfghdr.ehdr->ExtPageType = - pReply->ExtPageType; - } - pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion; - - /* If this is a regular header, save PageLength. */ - /* LMP Do this better so not using a reserved field! */ - pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength; - pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber; - pCfg->cfghdr.hdr->PageType = pReply->Header.PageType; - } - } - - /* - * Wake up the original calling thread - */ - pCfg->wait_done = 1; - wake_up(&mpt_waitq); - } - } else if (func == MPI_FUNCTION_SAS_IO_UNIT_CONTROL) { - /* we should be always getting a reply frame */ - memcpy(ioc->persist_reply_frame, reply, - min(MPT_DEFAULT_FRAME_SIZE, - 4*reply->u.reply.MsgLength)); - del_timer(&ioc->persist_timer); - ioc->persist_wait_done = 1; - wake_up(&mpt_waitq); - } else { - printk(MYIOC_s_ERR_FMT "Unexpected msg function (=%02Xh) reply received!\n", - ioc->name, func); + if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) { + ioc->mptbase_cmds.status &= ~MPT_MGMT_STATUS_PENDING; + complete(&ioc->mptbase_cmds.done); + } else + freereq = 0; + if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_FREE_MF) + freereq = 1; + break; + case MPI_FUNCTION_EVENT_ACK: + devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "EventAck reply received\n", ioc->name)); + break; + default: + printk(MYIOC_s_ERR_FMT + "Unexpected msg function (=%02Xh) reply received!\n", + ioc->name, reply->u.hdr.Function); + break; } /* @@ -988,17 +971,21 @@ mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf) /* Put Request back on FreeQ! */ spin_lock_irqsave(&ioc->FreeQlock, flags); - mf->u.frame.linkage.arg1 = 0xdeadbeaf; /* signature to know if this mf is freed */ + if (cpu_to_le32(mf->u.frame.linkage.arg1) == 0xdeadbeaf) + goto out; + /* signature to know if this mf is freed */ + mf->u.frame.linkage.arg1 = cpu_to_le32(0xdeadbeaf); list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ); #ifdef MFCNT ioc->mfcnt--; #endif + out: spin_unlock_irqrestore(&ioc->FreeQlock, flags); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** - * mpt_add_sge - Place a simple SGE at address pAddr. + * mpt_add_sge - Place a simple 32 bit SGE at address pAddr. * @pAddr: virtual address for SGE * @flagslength: SGE flags and data transfer length * @dma_addr: Physical address @@ -1006,23 +993,116 @@ mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf) * This routine places a MPT request frame back on the MPT adapter's * FreeQ. */ -void -mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr) +static void +mpt_add_sge(void *pAddr, u32 flagslength, dma_addr_t dma_addr) { - if (sizeof(dma_addr_t) == sizeof(u64)) { - SGESimple64_t *pSge = (SGESimple64_t *) pAddr; + SGESimple32_t *pSge = (SGESimple32_t *) pAddr; + pSge->FlagsLength = cpu_to_le32(flagslength); + pSge->Address = cpu_to_le32(dma_addr); +} + +/** + * mpt_add_sge_64bit - Place a simple 64 bit SGE at address pAddr. + * @pAddr: virtual address for SGE + * @flagslength: SGE flags and data transfer length + * @dma_addr: Physical address + * + * This routine places a MPT request frame back on the MPT adapter's + * FreeQ. + **/ +static void +mpt_add_sge_64bit(void *pAddr, u32 flagslength, dma_addr_t dma_addr) +{ + SGESimple64_t *pSge = (SGESimple64_t *) pAddr; + pSge->Address.Low = cpu_to_le32 + (lower_32_bits((unsigned long)(dma_addr))); + pSge->Address.High = cpu_to_le32 + (upper_32_bits((unsigned long)dma_addr)); + pSge->FlagsLength = cpu_to_le32 + ((flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING)); +} + +/** + * mpt_add_sge_64bit_1078 - Place a simple 64 bit SGE at address pAddr (1078 workaround). + * @pAddr: virtual address for SGE + * @flagslength: SGE flags and data transfer length + * @dma_addr: Physical address + * + * This routine places a MPT request frame back on the MPT adapter's + * FreeQ. + **/ +static void +mpt_add_sge_64bit_1078(void *pAddr, u32 flagslength, dma_addr_t dma_addr) +{ + SGESimple64_t *pSge = (SGESimple64_t *) pAddr; + u32 tmp; + + pSge->Address.Low = cpu_to_le32 + (lower_32_bits((unsigned long)(dma_addr))); + tmp = (u32)(upper_32_bits((unsigned long)dma_addr)); + + /* + * 1078 errata workaround for the 36GB limitation + */ + if ((((u64)dma_addr + MPI_SGE_LENGTH(flagslength)) >> 32) == 9) { + flagslength |= + MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_LOCAL_ADDRESS); + tmp |= (1<<31); + if (mpt_debug_level & MPT_DEBUG_36GB_MEM) + printk(KERN_DEBUG "1078 P0M2 addressing for " + "addr = 0x%llx len = %d\n", + (unsigned long long)dma_addr, + MPI_SGE_LENGTH(flagslength)); + } + + pSge->Address.High = cpu_to_le32(tmp); + pSge->FlagsLength = cpu_to_le32( + (flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING)); +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mpt_add_chain - Place a 32 bit chain SGE at address pAddr. + * @pAddr: virtual address for SGE + * @next: nextChainOffset value (u32's) + * @length: length of next SGL segment + * @dma_addr: Physical address + * + */ +static void +mpt_add_chain(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr) +{ + SGEChain32_t *pChain = (SGEChain32_t *) pAddr; + pChain->Length = cpu_to_le16(length); + pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT; + pChain->NextChainOffset = next; + pChain->Address = cpu_to_le32(dma_addr); +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mpt_add_chain_64bit - Place a 64 bit chain SGE at address pAddr. + * @pAddr: virtual address for SGE + * @next: nextChainOffset value (u32's) + * @length: length of next SGL segment + * @dma_addr: Physical address + * + */ +static void +mpt_add_chain_64bit(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr) +{ + SGEChain64_t *pChain = (SGEChain64_t *) pAddr; u32 tmp = dma_addr & 0xFFFFFFFF; - pSge->FlagsLength = cpu_to_le32(flagslength); - pSge->Address.Low = cpu_to_le32(tmp); - tmp = (u32) ((u64)dma_addr >> 32); - pSge->Address.High = cpu_to_le32(tmp); + pChain->Length = cpu_to_le16(length); + pChain->Flags = (MPI_SGE_FLAGS_CHAIN_ELEMENT | + MPI_SGE_FLAGS_64_BIT_ADDRESSING); - } else { - SGESimple32_t *pSge = (SGESimple32_t *) pAddr; - pSge->FlagsLength = cpu_to_le32(flagslength); - pSge->Address = cpu_to_le32(dma_addr); - } + pChain->NextChainOffset = next; + + pChain->Address.Low = cpu_to_le32(tmp); + tmp = (u32)(upper_32_bits((unsigned long)dma_addr)); + pChain->Address.High = cpu_to_le32(tmp); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -1225,7 +1305,7 @@ mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init) } flags_length = flags_length << MPI_SGE_FLAGS_SHIFT; flags_length |= ioc->HostPageBuffer_sz; - mpt_add_sge(psge, flags_length, ioc->HostPageBuffer_dma); + ioc->add_sge(psge, flags_length, ioc->HostPageBuffer_dma); ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE; return 0; @@ -1534,21 +1614,42 @@ mpt_mapresources(MPT_ADAPTER *ioc) pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); - if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) - && !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) { - dinitprintk(ioc, printk(MYIOC_s_INFO_FMT - ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n", - ioc->name)); - } else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) - && !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) { - dinitprintk(ioc, printk(MYIOC_s_INFO_FMT - ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n", - ioc->name)); + if (sizeof(dma_addr_t) > 4) { + const uint64_t required_mask = dma_get_required_mask + (&pdev->dev); + if (required_mask > DMA_BIT_MASK(32) + && !pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) + && !pci_set_consistent_dma_mask(pdev, + DMA_BIT_MASK(64))) { + ioc->dma_mask = DMA_BIT_MASK(64); + dinitprintk(ioc, printk(MYIOC_s_INFO_FMT + ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n", + ioc->name)); + } else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) + && !pci_set_consistent_dma_mask(pdev, + DMA_BIT_MASK(32))) { + ioc->dma_mask = DMA_BIT_MASK(32); + dinitprintk(ioc, printk(MYIOC_s_INFO_FMT + ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n", + ioc->name)); + } else { + printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n", + ioc->name, pci_name(pdev)); + return r; + } } else { - printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n", - ioc->name, pci_name(pdev)); - pci_release_selected_regions(pdev, ioc->bars); - return r; + if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) + && !pci_set_consistent_dma_mask(pdev, + DMA_BIT_MASK(32))) { + ioc->dma_mask = DMA_BIT_MASK(32); + dinitprintk(ioc, printk(MYIOC_s_INFO_FMT + ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n", + ioc->name)); + } else { + printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n", + ioc->name, pci_name(pdev)); + return r; + } } mem_phys = msize = 0; @@ -1632,6 +1733,7 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) ioc->id = mpt_ids++; sprintf(ioc->name, "ioc%d", ioc->id); + dinitprintk(ioc, printk(KERN_WARNING MYNAM ": mpt_adapter_install\n")); /* * set initial debug level @@ -1650,14 +1752,36 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) return r; } + /* + * Setting up proper handlers for scatter gather handling + */ + if (ioc->dma_mask == DMA_BIT_MASK(64)) { + if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) + ioc->add_sge = &mpt_add_sge_64bit_1078; + else + ioc->add_sge = &mpt_add_sge_64bit; + ioc->add_chain = &mpt_add_chain_64bit; + ioc->sg_addr_size = 8; + } else { + ioc->add_sge = &mpt_add_sge; + ioc->add_chain = &mpt_add_chain; + ioc->sg_addr_size = 4; + } + ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size; + ioc->alloc_total = sizeof(MPT_ADAPTER); ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */ ioc->reply_sz = MPT_REPLY_FRAME_SIZE; ioc->pcidev = pdev; - ioc->diagPending = 0; - spin_lock_init(&ioc->diagLock); - spin_lock_init(&ioc->initializing_hba_lock); + + spin_lock_init(&ioc->taskmgmt_lock); + mutex_init(&ioc->internal_cmds.mutex); + init_completion(&ioc->internal_cmds.done); + mutex_init(&ioc->mptbase_cmds.mutex); + init_completion(&ioc->mptbase_cmds.done); + mutex_init(&ioc->taskmgmt_cmds.mutex); + init_completion(&ioc->taskmgmt_cmds.done); /* Initialize the event logging. */ @@ -1670,16 +1794,13 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) ioc->mfcnt = 0; #endif + ioc->sh = NULL; ioc->cached_fw = NULL; /* Initilize SCSI Config Data structure */ memset(&ioc->spi_data, 0, sizeof(SpiCfgData)); - /* Initialize the running configQ head. - */ - INIT_LIST_HEAD(&ioc->configQ); - /* Initialize the fc rport list head. */ INIT_LIST_HEAD(&ioc->fc_rports); @@ -1690,9 +1811,8 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) /* Initialize workqueue */ INIT_DELAYED_WORK(&ioc->fault_reset_work, mpt_fault_reset_work); - spin_lock_init(&ioc->fault_reset_work_lock); - snprintf(ioc->reset_work_q_name, sizeof(ioc->reset_work_q_name), + snprintf(ioc->reset_work_q_name, MPT_KOBJ_NAME_LEN, "mpt_poll_%d", ioc->id); ioc->reset_work_q = create_singlethread_workqueue(ioc->reset_work_q_name); @@ -1767,11 +1887,14 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) case MPI_MANUFACTPAGE_DEVID_SAS1064: case MPI_MANUFACTPAGE_DEVID_SAS1068: ioc->errata_flag_1064 = 1; + ioc->bus_type = SAS; + break; case MPI_MANUFACTPAGE_DEVID_SAS1064E: case MPI_MANUFACTPAGE_DEVID_SAS1068E: case MPI_MANUFACTPAGE_DEVID_SAS1078: ioc->bus_type = SAS; + break; } @@ -1813,6 +1936,11 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) */ mpt_detect_bound_ports(ioc, pdev); + INIT_LIST_HEAD(&ioc->fw_event_list); + spin_lock_init(&ioc->fw_event_lock); + snprintf(ioc->fw_event_q_name, MPT_KOBJ_NAME_LEN, "mpt/%d", ioc->id); + ioc->fw_event_q = create_singlethread_workqueue(ioc->fw_event_q_name); + if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP, CAN_SLEEP)) != 0){ printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n", @@ -1885,13 +2013,18 @@ mpt_detach(struct pci_dev *pdev) /* * Stop polling ioc for fault condition */ - spin_lock_irqsave(&ioc->fault_reset_work_lock, flags); + spin_lock_irqsave(&ioc->taskmgmt_lock, flags); wq = ioc->reset_work_q; ioc->reset_work_q = NULL; - spin_unlock_irqrestore(&ioc->fault_reset_work_lock, flags); + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); cancel_delayed_work(&ioc->fault_reset_work); destroy_workqueue(wq); + spin_lock_irqsave(&ioc->fw_event_lock, flags); + wq = ioc->fw_event_q; + ioc->fw_event_q = NULL; + spin_unlock_irqrestore(&ioc->fw_event_lock, flags); + destroy_workqueue(wq); sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name); remove_proc_entry(pname, NULL); @@ -1994,6 +2127,21 @@ mpt_resume(struct pci_dev *pdev) if (err) return err; + if (ioc->dma_mask == DMA_BIT_MASK(64)) { + if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) + ioc->add_sge = &mpt_add_sge_64bit_1078; + else + ioc->add_sge = &mpt_add_sge_64bit; + ioc->add_chain = &mpt_add_chain_64bit; + ioc->sg_addr_size = 8; + } else { + + ioc->add_sge = &mpt_add_sge; + ioc->add_chain = &mpt_add_chain; + ioc->sg_addr_size = 4; + } + ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size; + printk(MYIOC_s_INFO_FMT "pci-resume: ioc-state=0x%x,doorbell=0x%x\n", ioc->name, (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT), CHIPREG_READ32(&ioc->chip->Doorbell)); @@ -2091,12 +2239,16 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) ioc->active = 0; if (ioc->alt_ioc) { - if (ioc->alt_ioc->active) + if (ioc->alt_ioc->active || + reason == MPT_HOSTEVENT_IOC_RECOVER) { reset_alt_ioc_active = 1; - - /* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */ - CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF); - ioc->alt_ioc->active = 0; + /* Disable alt-IOC's reply interrupts + * (and FreeQ) for a bit + **/ + CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, + 0xFFFFFFFF); + ioc->alt_ioc->active = 0; + } } hard = 1; @@ -2117,9 +2269,11 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) } } else { - printk(MYIOC_s_WARN_FMT "NOT READY!\n", ioc->name); + printk(MYIOC_s_WARN_FMT + "NOT READY WARNING!\n", ioc->name); } - return -1; + ret = -1; + goto out; } /* hard_reset_done = 0 if a soft reset was performed @@ -2129,7 +2283,9 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0) alt_ioc_ready = 1; else - printk(MYIOC_s_WARN_FMT "alt_ioc not ready!\n", ioc->alt_ioc->name); + printk(MYIOC_s_WARN_FMT + ": alt-ioc Not ready WARNING!\n", + ioc->alt_ioc->name); } for (ii=0; ii<5; ii++) { @@ -2150,7 +2306,8 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) if (alt_ioc_ready) { if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) { dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc)); + "Initial Alt IocFacts failed rc=%x\n", + ioc->name, rc)); /* Retry - alt IOC was initialized once */ rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason); @@ -2194,16 +2351,20 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) IRQF_SHARED, ioc->name, ioc); if (rc < 0) { printk(MYIOC_s_ERR_FMT "Unable to allocate " - "interrupt %d!\n", ioc->name, ioc->pcidev->irq); + "interrupt %d!\n", + ioc->name, ioc->pcidev->irq); if (ioc->msi_enable) pci_disable_msi(ioc->pcidev); - return -EBUSY; + ret = -EBUSY; + goto out; } irq_allocated = 1; ioc->pci_irq = ioc->pcidev->irq; pci_set_master(ioc->pcidev); /* ?? */ - dprintk(ioc, printk(MYIOC_s_INFO_FMT "installed at interrupt " - "%d\n", ioc->name, ioc->pcidev->irq)); + pci_set_drvdata(ioc->pcidev, ioc); + dinitprintk(ioc, printk(MYIOC_s_INFO_FMT + "installed at interrupt %d\n", ioc->name, + ioc->pcidev->irq)); } } @@ -2212,17 +2373,22 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) * init as upper addresses are needed for init. * If fails, continue with alt-ioc processing */ + dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "PrimeIocFifos\n", + ioc->name)); if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0)) ret = -3; /* May need to check/upload firmware & data here! * If fails, continue with alt-ioc processing */ + dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "SendIocInit\n", + ioc->name)); if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0)) ret = -4; // NEW! if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) { - printk(MYIOC_s_WARN_FMT ": alt_ioc (%d) FIFO mgmt alloc!\n", + printk(MYIOC_s_WARN_FMT + ": alt-ioc (%d) FIFO mgmt alloc WARNING!\n", ioc->alt_ioc->name, rc); alt_ioc_ready = 0; reset_alt_ioc_active = 0; @@ -2232,8 +2398,9 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) { alt_ioc_ready = 0; reset_alt_ioc_active = 0; - printk(MYIOC_s_WARN_FMT "alt_ioc (%d) init failure!\n", - ioc->alt_ioc->name, rc); + printk(MYIOC_s_WARN_FMT + ": alt-ioc: (%d) init failure WARNING!\n", + ioc->alt_ioc->name, rc); } } @@ -2269,28 +2436,36 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) } } + /* Enable MPT base driver management of EventNotification + * and EventAck handling. + */ + if ((ret == 0) && (!ioc->facts.EventState)) { + dinitprintk(ioc, printk(MYIOC_s_INFO_FMT + "SendEventNotification\n", + ioc->name)); + ret = SendEventNotification(ioc, 1, sleepFlag); /* 1=Enable */ + } + + if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState) + rc = SendEventNotification(ioc->alt_ioc, 1, sleepFlag); + if (ret == 0) { /* Enable! (reply interrupt) */ CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM); ioc->active = 1; } - - if (reset_alt_ioc_active && ioc->alt_ioc) { - /* (re)Enable alt-IOC! (reply interrupt) */ - dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "alt_ioc reply irq re-enabled\n", - ioc->alt_ioc->name)); - CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM); - ioc->alt_ioc->active = 1; + if (rc == 0) { /* alt ioc */ + if (reset_alt_ioc_active && ioc->alt_ioc) { + /* (re)Enable alt-IOC! (reply interrupt) */ + dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "alt-ioc" + "reply irq re-enabled\n", + ioc->alt_ioc->name)); + CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, + MPI_HIM_DIM); + ioc->alt_ioc->active = 1; + } } - /* Enable MPT base driver management of EventNotification - * and EventAck handling. - */ - if ((ret == 0) && (!ioc->facts.EventState)) - (void) SendEventNotification(ioc, 1); /* 1=Enable EventNotification */ - - if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState) - (void) SendEventNotification(ioc->alt_ioc, 1); /* 1=Enable EventNotification */ /* Add additional "reason" check before call to GetLanConfigPages * (combined with GetIoUnitPage2 call). This prevents a somewhat @@ -2306,8 +2481,9 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) mutex_init(&ioc->raid_data.inactive_list_mutex); INIT_LIST_HEAD(&ioc->raid_data.inactive_list); - if (ioc->bus_type == SAS) { + switch (ioc->bus_type) { + case SAS: /* clear persistency table */ if(ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) { @@ -2321,8 +2497,15 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) */ mpt_findImVolumes(ioc); - } else if (ioc->bus_type == FC) { - if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) && + /* Check, and possibly reset, the coalescing value + */ + mpt_read_ioc_pg_1(ioc); + + break; + + case FC: + if ((ioc->pfacts[0].ProtocolFlags & + MPI_PORTFACTS_PROTOCOL_LAN) && (ioc->lan_cnfg_page0.Header.PageLength == 0)) { /* * Pre-fetch the ports LAN MAC address! @@ -2331,11 +2514,14 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) (void) GetLanConfigPages(ioc); a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow; dprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n", - ioc->name, a[5], a[4], a[3], a[2], a[1], a[0])); - + "LanAddr = %02X:%02X:%02X" + ":%02X:%02X:%02X\n", + ioc->name, a[5], a[4], + a[3], a[2], a[1], a[0])); } - } else { + break; + + case SPI: /* Get NVRAM and adapter maximums from SPP 0 and 2 */ mpt_GetScsiPortSettings(ioc, 0); @@ -2354,6 +2540,8 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) mpt_read_ioc_pg_1(ioc); mpt_read_ioc_pg_4(ioc); + + break; } GetIoUnitPage2(ioc); @@ -2435,16 +2623,20 @@ mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev) if (_pcidev == peer) { /* Paranoia checks */ if (ioc->alt_ioc != NULL) { - printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n", - ioc->name, ioc->alt_ioc->name); + printk(MYIOC_s_WARN_FMT + "Oops, already bound (%s <==> %s)!\n", + ioc->name, ioc->name, ioc->alt_ioc->name); break; } else if (ioc_srch->alt_ioc != NULL) { - printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n", - ioc_srch->name, ioc_srch->alt_ioc->name); + printk(MYIOC_s_WARN_FMT + "Oops, already bound (%s <==> %s)!\n", + ioc_srch->name, ioc_srch->name, + ioc_srch->alt_ioc->name); break; } - dprintk(ioc, printk(MYIOC_s_INFO_FMT "FOUND! binding to %s\n", - ioc->name, ioc_srch->name)); + dprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "FOUND! binding %s <==> %s\n", + ioc->name, ioc->name, ioc_srch->name)); ioc_srch->alt_ioc = ioc; ioc->alt_ioc = ioc_srch; } @@ -2464,8 +2656,8 @@ mpt_adapter_disable(MPT_ADAPTER *ioc) int ret; if (ioc->cached_fw != NULL) { - ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: Pushing FW onto " - "adapter\n", __func__, ioc->name)); + ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: Pushing FW onto adapter\n", __func__, ioc->name)); if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *) ioc->cached_fw, CAN_SLEEP)) < 0) { printk(MYIOC_s_WARN_FMT @@ -2474,11 +2666,30 @@ mpt_adapter_disable(MPT_ADAPTER *ioc) } } + /* + * Put the controller into ready state (if its not already) + */ + if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY) { + if (!SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, + CAN_SLEEP)) { + if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY) + printk(MYIOC_s_ERR_FMT "%s: IOC msg unit " + "reset failed to put ioc in ready state!\n", + ioc->name, __func__); + } else + printk(MYIOC_s_ERR_FMT "%s: IOC msg unit reset " + "failed!\n", ioc->name, __func__); + } + + /* Disable adapter interrupts! */ + synchronize_irq(ioc->pcidev->irq); CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF); ioc->active = 0; + /* Clear any lingering interrupt */ CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); + CHIPREG_READ32(&ioc->chip->IntStatus); if (ioc->alloc != NULL) { sz = ioc->alloc_sz; @@ -2538,19 +2749,22 @@ mpt_adapter_disable(MPT_ADAPTER *ioc) if((ret = mpt_host_page_access_control(ioc, MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) { printk(MYIOC_s_ERR_FMT - "host page buffers free failed (%d)!\n", - ioc->name, ret); + ": %s: host page buffers free failed (%d)!\n", + ioc->name, __func__, ret); } - dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "HostPageBuffer free @ %p, sz=%d bytes\n", - ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz)); + dexitprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "HostPageBuffer free @ %p, sz=%d bytes\n", + ioc->name, ioc->HostPageBuffer, + ioc->HostPageBuffer_sz)); pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz, ioc->HostPageBuffer, ioc->HostPageBuffer_dma); ioc->HostPageBuffer = NULL; ioc->HostPageBuffer_sz = 0; ioc->alloc_total -= ioc->HostPageBuffer_sz; } -} + pci_set_drvdata(ioc->pcidev, NULL); +} /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_adapter_dispose - Free all resources associated with an MPT adapter @@ -2690,8 +2904,12 @@ MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag) } /* Is it already READY? */ - if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY) + if (!statefault && + ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)) { + dinitprintk(ioc, printk(MYIOC_s_INFO_FMT + "IOC is in READY state\n", ioc->name)); return 0; + } /* * Check to see if IOC is in FAULT state. @@ -2764,8 +2982,9 @@ MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag) ii++; cntdn--; if (!cntdn) { - printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n", - ioc->name, (int)((ii+5)/HZ)); + printk(MYIOC_s_ERR_FMT + "Wait IOC_READY state (0x%x) timeout(%d)!\n", + ioc->name, ioc_state, (int)((ii+5)/HZ)); return -ETIME; } @@ -2778,9 +2997,8 @@ MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag) } if (statefault < 3) { - printk(MYIOC_s_INFO_FMT "Recovered from %s\n", - ioc->name, - statefault==1 ? "stuck handshake" : "IOC FAULT"); + printk(MYIOC_s_INFO_FMT "Recovered from %s\n", ioc->name, + statefault == 1 ? "stuck handshake" : "IOC FAULT"); } return hard_reset_done; @@ -2833,8 +3051,9 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason) /* IOC *must* NOT be in RESET state! */ if (ioc->last_state == MPI_IOC_STATE_RESET) { - printk(MYIOC_s_ERR_FMT "Can't get IOCFacts NOT READY! (%08x)\n", - ioc->name, ioc->last_state ); + printk(KERN_ERR MYNAM + ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n", + ioc->name, ioc->last_state); return -44; } @@ -2896,7 +3115,7 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason) * Old: u16{Major(4),Minor(4),SubMinor(8)} * New: u32{Major(8),Minor(8),Unit(8),Dev(8)} */ - if (facts->MsgVersion < 0x0102) { + if (facts->MsgVersion < MPI_VERSION_01_02) { /* * Handle old FC f/w style, convert to new... */ @@ -2908,9 +3127,11 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason) facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word); facts->ProductID = le16_to_cpu(facts->ProductID); + if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK) > MPI_FW_HEADER_PID_PROD_TARGET_SCSI) ioc->ir_firmware = 1; + facts->CurrentHostMfaHighAddr = le32_to_cpu(facts->CurrentHostMfaHighAddr); facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits); @@ -2926,7 +3147,7 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason) * to 14 in MPI-1.01.0x. */ if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 && - facts->MsgVersion > 0x0100) { + facts->MsgVersion > MPI_VERSION_01_00) { facts->FWImageSize = le32_to_cpu(facts->FWImageSize); } @@ -3108,6 +3329,7 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepFlag) ioc_init.MaxDevices = (U8)ioc->devices_per_bus; ioc_init.MaxBuses = (U8)ioc->number_of_buses; + dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n", ioc->name, ioc->facts.MsgVersion)); if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) { @@ -3122,7 +3344,7 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepFlag) } ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */ - if (sizeof(dma_addr_t) == sizeof(u64)) { + if (ioc->sg_addr_size == sizeof(u64)) { /* Save the upper 32-bits of the request * (reply) and sense buffers. */ @@ -3325,11 +3547,10 @@ mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag) FWUpload_t *prequest; FWUploadReply_t *preply; FWUploadTCSGE_t *ptcsge; - int sgeoffset; u32 flagsLength; int ii, sz, reply_sz; int cmdStatus; - + int request_size; /* If the image size is 0, we are done. */ if ((sz = ioc->facts.FWImageSize) == 0) @@ -3364,42 +3585,41 @@ mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag) ptcsge->ImageSize = cpu_to_le32(sz); ptcsge++; - sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t); - flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz; - mpt_add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma); - - sgeoffset += sizeof(u32) + sizeof(dma_addr_t); - dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": Sending FW Upload (req @ %p) sgeoffset=%d \n", - ioc->name, prequest, sgeoffset)); + ioc->add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma); + request_size = offsetof(FWUpload_t, SGL) + sizeof(FWUploadTCSGE_t) + + ioc->SGE_size; + dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending FW Upload " + " (req @ %p) fw_size=%d mf_request_size=%d\n", ioc->name, prequest, + ioc->facts.FWImageSize, request_size)); DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest); - ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest, - reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag); + ii = mpt_handshake_req_reply_wait(ioc, request_size, (u32 *)prequest, + reply_sz, (u16 *)preply, 65 /*seconds*/, sleepFlag); - dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Upload completed rc=%x \n", ioc->name, ii)); + dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Upload completed " + "rc=%x \n", ioc->name, ii)); cmdStatus = -EFAULT; if (ii == 0) { /* Handshake transfer was complete and successful. * Check the Reply Frame. */ - int status, transfer_sz; - status = le16_to_cpu(preply->IOCStatus); - if (status == MPI_IOCSTATUS_SUCCESS) { - transfer_sz = le32_to_cpu(preply->ActualImageSize); - if (transfer_sz == sz) + int status; + status = le16_to_cpu(preply->IOCStatus) & + MPI_IOCSTATUS_MASK; + if (status == MPI_IOCSTATUS_SUCCESS && + ioc->facts.FWImageSize == + le32_to_cpu(preply->ActualImageSize)) cmdStatus = 0; - } } dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n", ioc->name, cmdStatus)); if (cmdStatus) { - - ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": fw upload failed, freeing image \n", - ioc->name)); + ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed, " + "freeing image \n", ioc->name)); mpt_free_fw_memory(ioc); } kfree(prequest); @@ -3723,6 +3943,10 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag) CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) { + + if (!ignore) + return 0; + drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset " "address=%p\n", ioc->name, __func__, &ioc->chip->Doorbell, &ioc->chip->Reset_1078)); @@ -3740,6 +3964,7 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag) "looking for READY STATE: doorbell=%x" " count=%d\n", ioc->name, doorbell, count)); + if (doorbell == MPI_IOC_STATE_READY) { return 1; } @@ -3890,6 +4115,10 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag) doorbell = CHIPREG_READ32(&ioc->chip->Doorbell); doorbell &= MPI_IOC_STATE_MASK; + drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "looking for READY STATE: doorbell=%x" + " count=%d\n", ioc->name, doorbell, count)); + if (doorbell == MPI_IOC_STATE_READY) { break; } @@ -3901,6 +4130,11 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag) mdelay (1000); } } + + if (doorbell != MPI_IOC_STATE_READY) + printk(MYIOC_s_ERR_FMT "Failed to come READY " + "after reset! IocState=%x", ioc->name, + doorbell); } } @@ -4019,8 +4253,9 @@ SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag) if (sleepFlag != CAN_SLEEP) count *= 10; - printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n", - ioc->name, (int)((count+5)/HZ)); + printk(MYIOC_s_ERR_FMT + "Wait IOC_READY state (0x%x) timeout(%d)!\n", + ioc->name, state, (int)((count+5)/HZ)); return -ETIME; } @@ -4090,24 +4325,29 @@ initChainBuffers(MPT_ADAPTER *ioc) * num_sge = num sge in request frame + last chain buffer * scale = num sge per chain buffer if no chain element */ - scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32)); - if (sizeof(dma_addr_t) == sizeof(u64)) - num_sge = scale + (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32)); + scale = ioc->req_sz / ioc->SGE_size; + if (ioc->sg_addr_size == sizeof(u64)) + num_sge = scale + (ioc->req_sz - 60) / ioc->SGE_size; else - num_sge = 1+ scale + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32)); + num_sge = 1 + scale + (ioc->req_sz - 64) / ioc->SGE_size; - if (sizeof(dma_addr_t) == sizeof(u64)) { + if (ioc->sg_addr_size == sizeof(u64)) { numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale + - (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32)); + (ioc->req_sz - 60) / ioc->SGE_size; } else { - numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale + - (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32)); + numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + + scale + (ioc->req_sz - 64) / ioc->SGE_size; } dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n", ioc->name, num_sge, numSGE)); - if ( numSGE > MPT_SCSI_SG_DEPTH ) - numSGE = MPT_SCSI_SG_DEPTH; + if (ioc->bus_type == FC) { + if (numSGE > MPT_SCSI_FC_SG_DEPTH) + numSGE = MPT_SCSI_FC_SG_DEPTH; + } else { + if (numSGE > MPT_SCSI_SG_DEPTH) + numSGE = MPT_SCSI_SG_DEPTH; + } num_chain = 1; while (numSGE - num_sge > 0) { @@ -4161,12 +4401,42 @@ PrimeIocFifos(MPT_ADAPTER *ioc) dma_addr_t alloc_dma; u8 *mem; int i, reply_sz, sz, total_size, num_chain; + u64 dma_mask; + + dma_mask = 0; /* Prime reply FIFO... */ if (ioc->reply_frames == NULL) { if ( (num_chain = initChainBuffers(ioc)) < 0) return -1; + /* + * 1078 errata workaround for the 36GB limitation + */ + if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078 && + ioc->dma_mask > DMA_BIT_MASK(35)) { + if (!pci_set_dma_mask(ioc->pcidev, DMA_BIT_MASK(32)) + && !pci_set_consistent_dma_mask(ioc->pcidev, + DMA_BIT_MASK(32))) { + dma_mask = DMA_BIT_MASK(35); + d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "setting 35 bit addressing for " + "Request/Reply/Chain and Sense Buffers\n", + ioc->name)); + } else { + /*Reseting DMA mask to 64 bit*/ + pci_set_dma_mask(ioc->pcidev, + DMA_BIT_MASK(64)); + pci_set_consistent_dma_mask(ioc->pcidev, + DMA_BIT_MASK(64)); + + printk(MYIOC_s_ERR_FMT + "failed setting 35 bit addressing for " + "Request/Reply/Chain and Sense Buffers\n", + ioc->name); + return -1; + } + } total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth); dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n", @@ -4305,9 +4575,16 @@ PrimeIocFifos(MPT_ADAPTER *ioc) alloc_dma += ioc->reply_sz; } + if (dma_mask == DMA_BIT_MASK(35) && !pci_set_dma_mask(ioc->pcidev, + ioc->dma_mask) && !pci_set_consistent_dma_mask(ioc->pcidev, + ioc->dma_mask)) + d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "restoring 64 bit addressing\n", ioc->name)); + return 0; out_fail: + if (ioc->alloc != NULL) { sz = ioc->alloc_sz; pci_free_consistent(ioc->pcidev, @@ -4324,6 +4601,13 @@ out_fail: ioc->sense_buf_pool, ioc->sense_buf_pool_dma); ioc->sense_buf_pool = NULL; } + + if (dma_mask == DMA_BIT_MASK(35) && !pci_set_dma_mask(ioc->pcidev, + DMA_BIT_MASK(64)) && !pci_set_consistent_dma_mask(ioc->pcidev, + DMA_BIT_MASK(64))) + d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "restoring 64 bit addressing\n", ioc->name)); + return -1; } @@ -4759,7 +5043,14 @@ mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode) SasIoUnitControlReply_t *sasIoUnitCntrReply; MPT_FRAME_HDR *mf = NULL; MPIHeader_t *mpi_hdr; + int ret = 0; + unsigned long timeleft; + mutex_lock(&ioc->mptbase_cmds.mutex); + + /* init the internal cmd struct */ + memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE); + INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status) /* insure garbage is not sent to fw */ switch(persist_opcode) { @@ -4769,17 +5060,19 @@ mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode) break; default: - return -1; - break; + ret = -1; + goto out; } - printk("%s: persist_opcode=%x\n",__func__, persist_opcode); + printk(KERN_DEBUG "%s: persist_opcode=%x\n", + __func__, persist_opcode); /* Get a MF for this command. */ if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) { - printk("%s: no msg frames!\n",__func__); - return -1; + printk(KERN_DEBUG "%s: no msg frames!\n", __func__); + ret = -1; + goto out; } mpi_hdr = (MPIHeader_t *) mf; @@ -4789,27 +5082,42 @@ mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode) sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext; sasIoUnitCntrReq->Operation = persist_opcode; - init_timer(&ioc->persist_timer); - ioc->persist_timer.data = (unsigned long) ioc; - ioc->persist_timer.function = mpt_timer_expired; - ioc->persist_timer.expires = jiffies + HZ*10 /* 10 sec */; - ioc->persist_wait_done=0; - add_timer(&ioc->persist_timer); mpt_put_msg_frame(mpt_base_index, ioc, mf); - wait_event(mpt_waitq, ioc->persist_wait_done); - - sasIoUnitCntrReply = - (SasIoUnitControlReply_t *)ioc->persist_reply_frame; - if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) { - printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n", - __func__, - sasIoUnitCntrReply->IOCStatus, - sasIoUnitCntrReply->IOCLogInfo); - return -1; + timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done, 10*HZ); + if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + ret = -ETIME; + printk(KERN_DEBUG "%s: failed\n", __func__); + if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) + goto out; + if (!timeleft) { + printk(KERN_DEBUG "%s: Issuing Reset from %s!!\n", + ioc->name, __func__); + mpt_HardResetHandler(ioc, CAN_SLEEP); + mpt_free_msg_frame(ioc, mf); + } + goto out; } - printk("%s: success\n",__func__); - return 0; + if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) { + ret = -1; + goto out; + } + + sasIoUnitCntrReply = + (SasIoUnitControlReply_t *)ioc->mptbase_cmds.reply; + if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) { + printk(KERN_DEBUG "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n", + __func__, sasIoUnitCntrReply->IOCStatus, + sasIoUnitCntrReply->IOCLogInfo); + printk(KERN_DEBUG "%s: failed\n", __func__); + ret = -1; + } else + printk(KERN_DEBUG "%s: success\n", __func__); + out: + + CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status) + mutex_unlock(&ioc->mptbase_cmds.mutex); + return ret; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -5394,17 +5702,20 @@ mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id) * -ENOMEM if pci_alloc failed **/ int -mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t phys_disk) +mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, + RaidPhysDiskPage0_t *phys_disk) { - CONFIGPARMS cfg; - ConfigPageHeader_t hdr; + CONFIGPARMS cfg; + ConfigPageHeader_t hdr; dma_addr_t dma_handle; pRaidPhysDiskPage0_t buffer = NULL; int rc; memset(&cfg, 0 , sizeof(CONFIGPARMS)); memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); + memset(phys_disk, 0, sizeof(RaidPhysDiskPage0_t)); + hdr.PageVersion = MPI_RAIDPHYSDISKPAGE0_PAGEVERSION; hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK; cfg.cfghdr.hdr = &hdr; cfg.physAddr = -1; @@ -5450,6 +5761,161 @@ mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t return rc; } +/** + * mpt_raid_phys_disk_get_num_paths - returns number paths associated to this phys_num + * @ioc: Pointer to a Adapter Structure + * @phys_disk_num: io unit unique phys disk num generated by the ioc + * + * Return: + * returns number paths + **/ +int +mpt_raid_phys_disk_get_num_paths(MPT_ADAPTER *ioc, u8 phys_disk_num) +{ + CONFIGPARMS cfg; + ConfigPageHeader_t hdr; + dma_addr_t dma_handle; + pRaidPhysDiskPage1_t buffer = NULL; + int rc; + + memset(&cfg, 0 , sizeof(CONFIGPARMS)); + memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); + + hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION; + hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK; + hdr.PageNumber = 1; + cfg.cfghdr.hdr = &hdr; + cfg.physAddr = -1; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + + if (mpt_config(ioc, &cfg) != 0) { + rc = 0; + goto out; + } + + if (!hdr.PageLength) { + rc = 0; + goto out; + } + + buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, + &dma_handle); + + if (!buffer) { + rc = 0; + goto out; + } + + cfg.physAddr = dma_handle; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + cfg.pageAddr = phys_disk_num; + + if (mpt_config(ioc, &cfg) != 0) { + rc = 0; + goto out; + } + + rc = buffer->NumPhysDiskPaths; + out: + + if (buffer) + pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer, + dma_handle); + + return rc; +} +EXPORT_SYMBOL(mpt_raid_phys_disk_get_num_paths); + +/** + * mpt_raid_phys_disk_pg1 - returns phys disk page 1 + * @ioc: Pointer to a Adapter Structure + * @phys_disk_num: io unit unique phys disk num generated by the ioc + * @phys_disk: requested payload data returned + * + * Return: + * 0 on success + * -EFAULT if read of config page header fails or data pointer not NULL + * -ENOMEM if pci_alloc failed + **/ +int +mpt_raid_phys_disk_pg1(MPT_ADAPTER *ioc, u8 phys_disk_num, + RaidPhysDiskPage1_t *phys_disk) +{ + CONFIGPARMS cfg; + ConfigPageHeader_t hdr; + dma_addr_t dma_handle; + pRaidPhysDiskPage1_t buffer = NULL; + int rc; + int i; + __le64 sas_address; + + memset(&cfg, 0 , sizeof(CONFIGPARMS)); + memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); + rc = 0; + + hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION; + hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK; + hdr.PageNumber = 1; + cfg.cfghdr.hdr = &hdr; + cfg.physAddr = -1; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + + if (mpt_config(ioc, &cfg) != 0) { + rc = -EFAULT; + goto out; + } + + if (!hdr.PageLength) { + rc = -EFAULT; + goto out; + } + + buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, + &dma_handle); + + if (!buffer) { + rc = -ENOMEM; + goto out; + } + + cfg.physAddr = dma_handle; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + cfg.pageAddr = phys_disk_num; + + if (mpt_config(ioc, &cfg) != 0) { + rc = -EFAULT; + goto out; + } + + phys_disk->NumPhysDiskPaths = buffer->NumPhysDiskPaths; + phys_disk->PhysDiskNum = phys_disk_num; + for (i = 0; i < phys_disk->NumPhysDiskPaths; i++) { + phys_disk->Path[i].PhysDiskID = buffer->Path[i].PhysDiskID; + phys_disk->Path[i].PhysDiskBus = buffer->Path[i].PhysDiskBus; + phys_disk->Path[i].OwnerIdentifier = + buffer->Path[i].OwnerIdentifier; + phys_disk->Path[i].Flags = le16_to_cpu(buffer->Path[i].Flags); + memcpy(&sas_address, &buffer->Path[i].WWID, sizeof(__le64)); + sas_address = le64_to_cpu(sas_address); + memcpy(&phys_disk->Path[i].WWID, &sas_address, sizeof(__le64)); + memcpy(&sas_address, + &buffer->Path[i].OwnerWWID, sizeof(__le64)); + sas_address = le64_to_cpu(sas_address); + memcpy(&phys_disk->Path[i].OwnerWWID, + &sas_address, sizeof(__le64)); + } + + out: + + if (buffer) + pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer, + dma_handle); + + return rc; +} +EXPORT_SYMBOL(mpt_raid_phys_disk_pg1); + + /** * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes * @ioc: Pointer to a Adapter Strucutre @@ -5775,30 +6241,28 @@ mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc) * SendEventNotification - Send EventNotification (on or off) request to adapter * @ioc: Pointer to MPT_ADAPTER structure * @EvSwitch: Event switch flags + * @sleepFlag: Specifies whether the process can sleep */ static int -SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch) +SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch, int sleepFlag) { - EventNotification_t *evnp; + EventNotification_t evn; + MPIDefaultReply_t reply_buf; - evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc); - if (evnp == NULL) { - devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n", - ioc->name)); - return 0; - } - memset(evnp, 0, sizeof(*evnp)); + memset(&evn, 0, sizeof(EventNotification_t)); + memset(&reply_buf, 0, sizeof(MPIDefaultReply_t)); - devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventNotification (%d) request %p\n", ioc->name, EvSwitch, evnp)); + evn.Function = MPI_FUNCTION_EVENT_NOTIFICATION; + evn.Switch = EvSwitch; + evn.MsgContext = cpu_to_le32(mpt_base_index << 16); - evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION; - evnp->ChainOffset = 0; - evnp->MsgFlags = 0; - evnp->Switch = EvSwitch; + devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "Sending EventNotification (%d) request %p\n", + ioc->name, EvSwitch, &evn)); - mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)evnp); - - return 0; + return mpt_handshake_req_reply_wait(ioc, sizeof(EventNotification_t), + (u32 *)&evn, sizeof(MPIDefaultReply_t), (u16 *)&reply_buf, 30, + sleepFlag); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -5814,7 +6278,7 @@ SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp) if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) { dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n", - ioc->name,__func__)); + ioc->name, __func__)); return -1; } @@ -5851,12 +6315,19 @@ int mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg) { Config_t *pReq; + ConfigReply_t *pReply; ConfigExtendedPageHeader_t *pExtHdr = NULL; MPT_FRAME_HDR *mf; - unsigned long flags; - int ii, rc; + int ii; int flagsLength; - int in_isr; + long timeout; + int ret; + u8 page_type = 0, extend_page; + unsigned long timeleft; + unsigned long flags; + int in_isr; + u8 issue_hard_reset = 0; + u8 retry_count = 0; /* Prevent calling wait_event() (below), if caller happens * to be in ISR context, because that is fatal! @@ -5866,15 +6337,43 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg) dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n", ioc->name)); return -EPERM; + } + + /* don't send a config page during diag reset */ + spin_lock_irqsave(&ioc->taskmgmt_lock, flags); + if (ioc->ioc_reset_in_progress) { + dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: busy with host reset\n", ioc->name, __func__)); + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + return -EBUSY; } + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + + /* don't send if no chance of success */ + if (!ioc->active || + mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_OPERATIONAL) { + dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: ioc not operational, %d, %xh\n", + ioc->name, __func__, ioc->active, + mpt_GetIocState(ioc, 0))); + return -EFAULT; + } + + retry_config: + mutex_lock(&ioc->mptbase_cmds.mutex); + /* init the internal cmd struct */ + memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE); + INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status) /* Get and Populate a free Frame */ if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) { - dcprintk(ioc, printk(MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n", - ioc->name)); - return -EAGAIN; + dcprintk(ioc, printk(MYIOC_s_WARN_FMT + "mpt_config: no msg frames!\n", ioc->name)); + ret = -EAGAIN; + goto out; } + pReq = (Config_t *)mf; pReq->Action = pCfg->action; pReq->Reserved = 0; @@ -5900,7 +6399,9 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg) pReq->ExtPageType = pExtHdr->ExtPageType; pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; - /* Page Length must be treated as a reserved field for the extended header. */ + /* Page Length must be treated as a reserved field for the + * extended header. + */ pReq->Header.PageLength = 0; } @@ -5913,78 +6414,91 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg) else flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ; - if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) { + if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == + MPI_CONFIG_PAGETYPE_EXTENDED) { flagsLength |= pExtHdr->ExtPageLength * 4; - - dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Config request type %d, page %d and action %d\n", - ioc->name, pReq->ExtPageType, pReq->Header.PageNumber, pReq->Action)); - } - else { + page_type = pReq->ExtPageType; + extend_page = 1; + } else { flagsLength |= pCfg->cfghdr.hdr->PageLength * 4; - - dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Config request type %d, page %d and action %d\n", - ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action)); + page_type = pReq->Header.PageType; + extend_page = 0; } - mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr); + dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "Sending Config request type 0x%x, page 0x%x and action %d\n", + ioc->name, page_type, pReq->Header.PageNumber, pReq->Action)); - /* Append pCfg pointer to end of mf - */ - *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg; - - /* Initalize the timer - */ - init_timer_on_stack(&pCfg->timer); - pCfg->timer.data = (unsigned long) ioc; - pCfg->timer.function = mpt_timer_expired; - pCfg->wait_done = 0; - - /* Set the timer; ensure 10 second minimum */ - if (pCfg->timeout < 10) - pCfg->timer.expires = jiffies + HZ*10; - else - pCfg->timer.expires = jiffies + HZ*pCfg->timeout; - - /* Add to end of Q, set timer and then issue this command */ - spin_lock_irqsave(&ioc->FreeQlock, flags); - list_add_tail(&pCfg->linkage, &ioc->configQ); - spin_unlock_irqrestore(&ioc->FreeQlock, flags); - - add_timer(&pCfg->timer); + ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr); + timeout = (pCfg->timeout < 15) ? HZ*15 : HZ*pCfg->timeout; mpt_put_msg_frame(mpt_base_index, ioc, mf); - wait_event(mpt_waitq, pCfg->wait_done); + timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done, + timeout); + if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + ret = -ETIME; + dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "Failed Sending Config request type 0x%x, page 0x%x," + " action %d, status %xh, time left %ld\n\n", + ioc->name, page_type, pReq->Header.PageNumber, + pReq->Action, ioc->mptbase_cmds.status, timeleft)); + if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) + goto out; + if (!timeleft) + issue_hard_reset = 1; + goto out; + } - /* mf has been freed - do not access */ + if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) { + ret = -1; + goto out; + } + pReply = (ConfigReply_t *)ioc->mptbase_cmds.reply; + ret = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK; + if (ret == MPI_IOCSTATUS_SUCCESS) { + if (extend_page) { + pCfg->cfghdr.ehdr->ExtPageLength = + le16_to_cpu(pReply->ExtPageLength); + pCfg->cfghdr.ehdr->ExtPageType = + pReply->ExtPageType; + } + pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion; + pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength; + pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber; + pCfg->cfghdr.hdr->PageType = pReply->Header.PageType; - rc = pCfg->status; + } - return rc; -} + if (retry_count) + printk(MYIOC_s_INFO_FMT "Retry completed " + "ret=0x%x timeleft=%ld\n", + ioc->name, ret, timeleft); -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/** - * mpt_timer_expired - Callback for timer process. - * Used only internal config functionality. - * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long - */ -static void -mpt_timer_expired(unsigned long data) -{ - MPT_ADAPTER *ioc = (MPT_ADAPTER *) data; + dcprintk(ioc, printk(KERN_DEBUG "IOCStatus=%04xh, IOCLogInfo=%08xh\n", + ret, le32_to_cpu(pReply->IOCLogInfo))); - dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired! \n", ioc->name)); +out: - /* Perform a FW reload */ - if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) - printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name); + CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status) + mutex_unlock(&ioc->mptbase_cmds.mutex); + if (issue_hard_reset) { + issue_hard_reset = 0; + printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n", + ioc->name, __func__); + mpt_HardResetHandler(ioc, CAN_SLEEP); + mpt_free_msg_frame(ioc, mf); + /* attempt one retry for a timed out command */ + if (!retry_count) { + printk(MYIOC_s_INFO_FMT + "Attempting Retry Config request" + " type 0x%x, page 0x%x," + " action %d\n", ioc->name, page_type, + pCfg->cfghdr.hdr->PageNumber, pCfg->action); + retry_count++; + goto retry_config; + } + } + return ret; - /* No more processing. - * Hard reset clean-up will wake up - * process and free all resources. - */ - dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired complete!\n", ioc->name)); - - return; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -5998,41 +6512,34 @@ mpt_timer_expired(unsigned long data) static int mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) { - CONFIGPARMS *pCfg; - unsigned long flags; - - dprintk(ioc, printk(MYIOC_s_DEBUG_FMT - ": IOC %s_reset routed to MPT base driver!\n", - ioc->name, reset_phase==MPT_IOC_SETUP_RESET ? "setup" : ( - reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"))); - - if (reset_phase == MPT_IOC_SETUP_RESET) { - ; - } else if (reset_phase == MPT_IOC_PRE_RESET) { - /* If the internal config Q is not empty - - * delete timer. MF resources will be freed when - * the FIFO's are primed. - */ - spin_lock_irqsave(&ioc->FreeQlock, flags); - list_for_each_entry(pCfg, &ioc->configQ, linkage) - del_timer(&pCfg->timer); - spin_unlock_irqrestore(&ioc->FreeQlock, flags); - - } else { - CONFIGPARMS *pNext; - - /* Search the configQ for internal commands. - * Flush the Q, and wake up all suspended threads. - */ - spin_lock_irqsave(&ioc->FreeQlock, flags); - list_for_each_entry_safe(pCfg, pNext, &ioc->configQ, linkage) { - list_del(&pCfg->linkage); - - pCfg->status = MPT_CONFIG_ERROR; - pCfg->wait_done = 1; - wake_up(&mpt_waitq); + switch (reset_phase) { + case MPT_IOC_SETUP_RESET: + ioc->taskmgmt_quiesce_io = 1; + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__)); + break; + case MPT_IOC_PRE_RESET: + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__)); + break; + case MPT_IOC_POST_RESET: + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__)); +/* wake up mptbase_cmds */ + if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) { + ioc->mptbase_cmds.status |= + MPT_MGMT_STATUS_DID_IOCRESET; + complete(&ioc->mptbase_cmds.done); } - spin_unlock_irqrestore(&ioc->FreeQlock, flags); +/* wake up taskmgmt_cmds */ + if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) { + ioc->taskmgmt_cmds.status |= + MPT_MGMT_STATUS_DID_IOCRESET; + complete(&ioc->taskmgmt_cmds.done); + } + break; + default: + break; } return 1; /* currently means nothing really */ @@ -6344,6 +6851,59 @@ mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int sh *size = y; } +/** + * mpt_set_taskmgmt_in_progress_flag - set flags associated with task managment + * @ioc: Pointer to MPT_ADAPTER structure + * + * Returns 0 for SUCCESS or -1 if FAILED. + * + * If -1 is return, then it was not possible to set the flags + **/ +int +mpt_set_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc) +{ + unsigned long flags; + int retval; + + spin_lock_irqsave(&ioc->taskmgmt_lock, flags); + if (ioc->ioc_reset_in_progress || ioc->taskmgmt_in_progress || + (ioc->alt_ioc && ioc->alt_ioc->taskmgmt_in_progress)) { + retval = -1; + goto out; + } + retval = 0; + ioc->taskmgmt_in_progress = 1; + ioc->taskmgmt_quiesce_io = 1; + if (ioc->alt_ioc) { + ioc->alt_ioc->taskmgmt_in_progress = 1; + ioc->alt_ioc->taskmgmt_quiesce_io = 1; + } + out: + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + return retval; +} +EXPORT_SYMBOL(mpt_set_taskmgmt_in_progress_flag); + +/** + * mpt_clear_taskmgmt_in_progress_flag - clear flags associated with task managment + * @ioc: Pointer to MPT_ADAPTER structure + * + **/ +void +mpt_clear_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc) +{ + unsigned long flags; + + spin_lock_irqsave(&ioc->taskmgmt_lock, flags); + ioc->taskmgmt_in_progress = 0; + ioc->taskmgmt_quiesce_io = 0; + if (ioc->alt_ioc) { + ioc->alt_ioc->taskmgmt_in_progress = 0; + ioc->alt_ioc->taskmgmt_quiesce_io = 0; + } + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); +} +EXPORT_SYMBOL(mpt_clear_taskmgmt_in_progress_flag); /** @@ -6397,7 +6957,9 @@ int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag) { int rc; + u8 cb_idx; unsigned long flags; + unsigned long time_count; dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name)); #ifdef MFCNT @@ -6410,14 +6972,15 @@ mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag) /* Reset the adapter. Prevent more than 1 call to * mpt_do_ioc_recovery at any instant in time. */ - spin_lock_irqsave(&ioc->diagLock, flags); - if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){ - spin_unlock_irqrestore(&ioc->diagLock, flags); + spin_lock_irqsave(&ioc->taskmgmt_lock, flags); + if (ioc->ioc_reset_in_progress) { + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); return 0; - } else { - ioc->diagPending = 1; } - spin_unlock_irqrestore(&ioc->diagLock, flags); + ioc->ioc_reset_in_progress = 1; + if (ioc->alt_ioc) + ioc->alt_ioc->ioc_reset_in_progress = 1; + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); /* FIXME: If do_ioc_recovery fails, repeat.... */ @@ -6427,47 +6990,57 @@ mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag) * Prevents timeouts occurring during a diagnostic reset...very bad. * For all other protocol drivers, this is a no-op. */ - { - u8 cb_idx; - int r = 0; - - for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { - if (MptResetHandlers[cb_idx]) { - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling IOC reset_setup handler #%d\n", - ioc->name, cb_idx)); - r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET); - if (ioc->alt_ioc) { - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling alt-%s setup reset handler #%d\n", - ioc->name, ioc->alt_ioc->name, cb_idx)); - r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_SETUP_RESET); - } - } + for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { + if (MptResetHandlers[cb_idx]) { + mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET); + if (ioc->alt_ioc) + mpt_signal_reset(cb_idx, ioc->alt_ioc, + MPT_IOC_SETUP_RESET); } } - if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) { - printk(MYIOC_s_WARN_FMT "Cannot recover rc = %d!\n", ioc->name, rc); + time_count = jiffies; + rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag); + if (rc != 0) { + printk(KERN_WARNING MYNAM + ": WARNING - (%d) Cannot recover %s\n", rc, ioc->name); + } else { + if (ioc->hard_resets < -1) + ioc->hard_resets++; } - ioc->reload_fw = 0; - if (ioc->alt_ioc) - ioc->alt_ioc->reload_fw = 0; - spin_lock_irqsave(&ioc->diagLock, flags); - ioc->diagPending = 0; - if (ioc->alt_ioc) - ioc->alt_ioc->diagPending = 0; - spin_unlock_irqrestore(&ioc->diagLock, flags); + spin_lock_irqsave(&ioc->taskmgmt_lock, flags); + ioc->ioc_reset_in_progress = 0; + ioc->taskmgmt_quiesce_io = 0; + ioc->taskmgmt_in_progress = 0; + if (ioc->alt_ioc) { + ioc->alt_ioc->ioc_reset_in_progress = 0; + ioc->alt_ioc->taskmgmt_quiesce_io = 0; + ioc->alt_ioc->taskmgmt_in_progress = 0; + } + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler rc = %d!\n", ioc->name, rc)); + dtmprintk(ioc, + printk(MYIOC_s_DEBUG_FMT + "HardResetHandler: completed (%d seconds): %s\n", ioc->name, + jiffies_to_msecs(jiffies - time_count)/1000, ((rc == 0) ? + "SUCCESS" : "FAILED"))); return rc; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +#ifdef CONFIG_FUSION_LOGGING static void -EventDescriptionStr(u8 event, u32 evData0, char *evStr) +mpt_display_event_info(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply) { char *ds = NULL; + u32 evData0; + int ii; + u8 event; + char *evStr = ioc->evStr; + + event = le32_to_cpu(pEventReply->Event) & 0xFF; + evData0 = le32_to_cpu(pEventReply->Data[0]); switch(event) { case MPI_EVENT_NONE: @@ -6501,9 +7074,9 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr) if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP) ds = "Loop State(LIP) Change"; else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE) - ds = "Loop State(LPE) Change"; /* ??? */ + ds = "Loop State(LPE) Change"; else - ds = "Loop State(LPB) Change"; /* ??? */ + ds = "Loop State(LPB) Change"; break; case MPI_EVENT_LOGOUT: ds = "Logout"; @@ -6703,28 +7276,65 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr) } case MPI_EVENT_IR2: { + u8 id = (u8)(evData0); + u8 channel = (u8)(evData0 >> 8); + u8 phys_num = (u8)(evData0 >> 24); u8 ReasonCode = (u8)(evData0 >> 16); + switch (ReasonCode) { case MPI_EVENT_IR2_RC_LD_STATE_CHANGED: - ds = "IR2: LD State Changed"; + snprintf(evStr, EVENT_DESCR_STR_SZ, + "IR2: LD State Changed: " + "id=%d channel=%d phys_num=%d", + id, channel, phys_num); break; case MPI_EVENT_IR2_RC_PD_STATE_CHANGED: - ds = "IR2: PD State Changed"; + snprintf(evStr, EVENT_DESCR_STR_SZ, + "IR2: PD State Changed " + "id=%d channel=%d phys_num=%d", + id, channel, phys_num); break; case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL: - ds = "IR2: Bad Block Table Full"; + snprintf(evStr, EVENT_DESCR_STR_SZ, + "IR2: Bad Block Table Full: " + "id=%d channel=%d phys_num=%d", + id, channel, phys_num); break; case MPI_EVENT_IR2_RC_PD_INSERTED: - ds = "IR2: PD Inserted"; + snprintf(evStr, EVENT_DESCR_STR_SZ, + "IR2: PD Inserted: " + "id=%d channel=%d phys_num=%d", + id, channel, phys_num); break; case MPI_EVENT_IR2_RC_PD_REMOVED: - ds = "IR2: PD Removed"; + snprintf(evStr, EVENT_DESCR_STR_SZ, + "IR2: PD Removed: " + "id=%d channel=%d phys_num=%d", + id, channel, phys_num); break; case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED: - ds = "IR2: Foreign CFG Detected"; + snprintf(evStr, EVENT_DESCR_STR_SZ, + "IR2: Foreign CFG Detected: " + "id=%d channel=%d phys_num=%d", + id, channel, phys_num); break; case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR: - ds = "IR2: Rebuild Medium Error"; + snprintf(evStr, EVENT_DESCR_STR_SZ, + "IR2: Rebuild Medium Error: " + "id=%d channel=%d phys_num=%d", + id, channel, phys_num); + break; + case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED: + snprintf(evStr, EVENT_DESCR_STR_SZ, + "IR2: Dual Port Added: " + "id=%d channel=%d phys_num=%d", + id, channel, phys_num); + break; + case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED: + snprintf(evStr, EVENT_DESCR_STR_SZ, + "IR2: Dual Port Removed: " + "id=%d channel=%d phys_num=%d", + id, channel, phys_num); break; default: ds = "IR2"; @@ -6760,13 +7370,18 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr) case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE: { u8 reason = (u8)(evData0); - u8 port_num = (u8)(evData0 >> 8); - u16 handle = le16_to_cpu(evData0 >> 16); - snprintf(evStr, EVENT_DESCR_STR_SZ, - "SAS Initiator Device Status Change: reason=0x%02x " - "port=%d handle=0x%04x", - reason, port_num, handle); + switch (reason) { + case MPI_EVENT_SAS_INIT_RC_ADDED: + ds = "SAS Initiator Status Change: Added"; + break; + case MPI_EVENT_SAS_INIT_RC_REMOVED: + ds = "SAS Initiator Status Change: Deleted"; + break; + default: + ds = "SAS Initiator Status Change"; + break; + } break; } @@ -6814,6 +7429,24 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr) break; } + case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE: + { + u8 reason = (u8)(evData0); + + switch (reason) { + case MPI_EVENT_SAS_EXP_RC_ADDED: + ds = "Expander Status Change: Added"; + break; + case MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING: + ds = "Expander Status Change: Deleted"; + break; + default: + ds = "Expander Status Change"; + break; + } + break; + } + /* * MPT base "custom" events may be added here... */ @@ -6823,8 +7456,20 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr) } if (ds) strncpy(evStr, ds, EVENT_DESCR_STR_SZ); -} + + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "MPT event:(%02Xh) : %s\n", + ioc->name, event, evStr)); + + devtverboseprintk(ioc, printk(KERN_DEBUG MYNAM + ": Event data:\n")); + for (ii = 0; ii < le16_to_cpu(pEventReply->EventDataLength); ii++) + devtverboseprintk(ioc, printk(" %08x", + le32_to_cpu(pEventReply->Data[ii]))); + devtverboseprintk(ioc, printk(KERN_DEBUG "\n")); +} +#endif /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * ProcessEventNotification - Route EventNotificationReply to all event handlers @@ -6841,37 +7486,24 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply { u16 evDataLen; u32 evData0 = 0; -// u32 evCtx; int ii; u8 cb_idx; int r = 0; int handlers = 0; - char evStr[EVENT_DESCR_STR_SZ]; u8 event; /* * Do platform normalization of values */ event = le32_to_cpu(pEventReply->Event) & 0xFF; -// evCtx = le32_to_cpu(pEventReply->EventContext); evDataLen = le16_to_cpu(pEventReply->EventDataLength); if (evDataLen) { evData0 = le32_to_cpu(pEventReply->Data[0]); } - EventDescriptionStr(event, evData0, evStr); - devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event:(%02Xh) : %s\n", - ioc->name, - event, - evStr)); - #ifdef CONFIG_FUSION_LOGGING - devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT - ": Event data:\n", ioc->name)); - for (ii = 0; ii < evDataLen; ii++) - devtverboseprintk(ioc, printk(" %08x", - le32_to_cpu(pEventReply->Data[ii]))); - devtverboseprintk(ioc, printk("\n")); + if (evDataLen) + mpt_display_event_info(ioc, pEventReply); #endif /* @@ -6926,8 +7558,9 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply */ for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { if (MptEvHandlers[cb_idx]) { - devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Routing Event to event handler #%d\n", - ioc->name, cb_idx)); + devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "Routing Event to event handler #%d\n", + ioc->name, cb_idx)); r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply); handlers++; } @@ -7011,8 +7644,6 @@ mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info) switch (info) { case 0x00010000: desc = "bug! MID not found"; - if (ioc->reload_fw == 0) - ioc->reload_fw++; break; case 0x00020000: @@ -7613,7 +8244,6 @@ EXPORT_SYMBOL(mpt_get_msg_frame); EXPORT_SYMBOL(mpt_put_msg_frame); EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri); EXPORT_SYMBOL(mpt_free_msg_frame); -EXPORT_SYMBOL(mpt_add_sge); EXPORT_SYMBOL(mpt_send_handshake_request); EXPORT_SYMBOL(mpt_verify_adapter); EXPORT_SYMBOL(mpt_GetIocState); @@ -7650,7 +8280,7 @@ fusion_init(void) /* Register ourselves (mptbase) in order to facilitate * EventNotification handling. */ - mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER); + mpt_base_index = mpt_register(mptbase_reply, MPTBASE_DRIVER); /* Register for hard reset handling callbacks. */ diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h index b3e981d2a506..1c8514dc31ca 100644 --- a/drivers/message/fusion/mptbase.h +++ b/drivers/message/fusion/mptbase.h @@ -76,8 +76,8 @@ #define COPYRIGHT "Copyright (c) 1999-2008 " MODULEAUTHOR #endif -#define MPT_LINUX_VERSION_COMMON "3.04.07" -#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.07" +#define MPT_LINUX_VERSION_COMMON "3.04.10" +#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.09" #define WHAT_MAGIC_STRING "@" "(" "#" ")" #define show_mptmod_ver(s,ver) \ @@ -104,6 +104,7 @@ #endif #define MPT_NAME_LENGTH 32 +#define MPT_KOBJ_NAME_LEN 20 #define MPT_PROCFS_MPTBASEDIR "mpt" /* chg it to "driver/fusion" ? */ @@ -134,6 +135,7 @@ #define MPT_COALESCING_TIMEOUT 0x10 + /* * SCSI transfer rate defines. */ @@ -161,10 +163,10 @@ /* * Set the MAX_SGE value based on user input. */ -#ifdef CONFIG_FUSION_MAX_SGE -#if CONFIG_FUSION_MAX_SGE < 16 +#ifdef CONFIG_FUSION_MAX_SGE +#if CONFIG_FUSION_MAX_SGE < 16 #define MPT_SCSI_SG_DEPTH 16 -#elif CONFIG_FUSION_MAX_SGE > 128 +#elif CONFIG_FUSION_MAX_SGE > 128 #define MPT_SCSI_SG_DEPTH 128 #else #define MPT_SCSI_SG_DEPTH CONFIG_FUSION_MAX_SGE @@ -173,6 +175,18 @@ #define MPT_SCSI_SG_DEPTH 40 #endif +#ifdef CONFIG_FUSION_MAX_FC_SGE +#if CONFIG_FUSION_MAX_FC_SGE < 16 +#define MPT_SCSI_FC_SG_DEPTH 16 +#elif CONFIG_FUSION_MAX_FC_SGE > 256 +#define MPT_SCSI_FC_SG_DEPTH 256 +#else +#define MPT_SCSI_FC_SG_DEPTH CONFIG_FUSION_MAX_FC_SGE +#endif +#else +#define MPT_SCSI_FC_SG_DEPTH 40 +#endif + /* debug print string length used for events and iocstatus */ # define EVENT_DESCR_STR_SZ 100 @@ -431,38 +445,36 @@ do { \ * IOCTL structure and associated defines */ -#define MPT_IOCTL_STATUS_DID_IOCRESET 0x01 /* IOC Reset occurred on the current*/ -#define MPT_IOCTL_STATUS_RF_VALID 0x02 /* The Reply Frame is VALID */ -#define MPT_IOCTL_STATUS_TIMER_ACTIVE 0x04 /* The timer is running */ -#define MPT_IOCTL_STATUS_SENSE_VALID 0x08 /* Sense data is valid */ -#define MPT_IOCTL_STATUS_COMMAND_GOOD 0x10 /* Command Status GOOD */ -#define MPT_IOCTL_STATUS_TMTIMER_ACTIVE 0x20 /* The TM timer is running */ -#define MPT_IOCTL_STATUS_TM_FAILED 0x40 /* User TM request failed */ - #define MPTCTL_RESET_OK 0x01 /* Issue Bus Reset */ -typedef struct _MPT_IOCTL { - struct _MPT_ADAPTER *ioc; - u8 ReplyFrame[MPT_DEFAULT_FRAME_SIZE]; /* reply frame data */ - u8 sense[MPT_SENSE_BUFFER_ALLOC]; - int wait_done; /* wake-up value for this ioc */ - u8 rsvd; - u8 status; /* current command status */ - u8 reset; /* 1 if bus reset allowed */ - u8 id; /* target for reset */ - struct mutex ioctl_mutex; -} MPT_IOCTL; +#define MPT_MGMT_STATUS_RF_VALID 0x01 /* The Reply Frame is VALID */ +#define MPT_MGMT_STATUS_COMMAND_GOOD 0x02 /* Command Status GOOD */ +#define MPT_MGMT_STATUS_PENDING 0x04 /* command is pending */ +#define MPT_MGMT_STATUS_DID_IOCRESET 0x08 /* IOC Reset occurred + on the current*/ +#define MPT_MGMT_STATUS_SENSE_VALID 0x10 /* valid sense info */ +#define MPT_MGMT_STATUS_TIMER_ACTIVE 0x20 /* obsolete */ +#define MPT_MGMT_STATUS_FREE_MF 0x40 /* free the mf from + complete routine */ -#define MPT_SAS_MGMT_STATUS_RF_VALID 0x02 /* The Reply Frame is VALID */ -#define MPT_SAS_MGMT_STATUS_COMMAND_GOOD 0x10 /* Command Status GOOD */ -#define MPT_SAS_MGMT_STATUS_TM_FAILED 0x40 /* User TM request failed */ +#define INITIALIZE_MGMT_STATUS(status) \ + status = MPT_MGMT_STATUS_PENDING; +#define CLEAR_MGMT_STATUS(status) \ + status = 0; +#define CLEAR_MGMT_PENDING_STATUS(status) \ + status &= ~MPT_MGMT_STATUS_PENDING; +#define SET_MGMT_MSG_CONTEXT(msg_context, value) \ + msg_context = value; -typedef struct _MPT_SAS_MGMT { +typedef struct _MPT_MGMT { struct mutex mutex; struct completion done; u8 reply[MPT_DEFAULT_FRAME_SIZE]; /* reply frame data */ + u8 sense[MPT_SENSE_BUFFER_ALLOC]; u8 status; /* current command status */ -}MPT_SAS_MGMT; + int completion_code; + u32 msg_context; +} MPT_MGMT; /* * Event Structure and define @@ -564,6 +576,10 @@ struct mptfc_rport_info u8 flags; }; +typedef void (*MPT_ADD_SGE)(void *pAddr, u32 flagslength, dma_addr_t dma_addr); +typedef void (*MPT_ADD_CHAIN)(void *pAddr, u8 next, u16 length, + dma_addr_t dma_addr); + /* * Adapter Structure - pci_dev specific. Maximum: MPT_MAX_ADAPTERS */ @@ -573,6 +589,10 @@ typedef struct _MPT_ADAPTER int pci_irq; /* This irq */ char name[MPT_NAME_LENGTH]; /* "iocN" */ char prod_name[MPT_NAME_LENGTH]; /* "LSIFC9x9" */ +#ifdef CONFIG_FUSION_LOGGING + /* used in mpt_display_event_info */ + char evStr[EVENT_DESCR_STR_SZ]; +#endif char board_name[16]; char board_assembly[16]; char board_tracer[16]; @@ -600,6 +620,10 @@ typedef struct _MPT_ADAPTER int reply_depth; /* Num Allocated reply frames */ int reply_sz; /* Reply frame size */ int num_chain; /* Number of chain buffers */ + MPT_ADD_SGE add_sge; /* Pointer to add_sge + function */ + MPT_ADD_CHAIN add_chain; /* Pointer to add_chain + function */ /* Pool of buffers for chaining. ReqToChain * and ChainToChain track index of chain buffers. * ChainBuffer (DMA) virt/phys addresses. @@ -640,11 +664,8 @@ typedef struct _MPT_ADAPTER RaidCfgData raid_data; /* Raid config. data */ SasCfgData sas_data; /* Sas config. data */ FcCfgData fc_data; /* Fc config. data */ - MPT_IOCTL *ioctl; /* ioctl data pointer */ struct proc_dir_entry *ioc_dentry; struct _MPT_ADAPTER *alt_ioc; /* ptr to 929 bound adapter port */ - spinlock_t diagLock; /* diagnostic reset lock */ - int diagPending; u32 biosVersion; /* BIOS version from IO Unit Page 2 */ int eventTypes; /* Event logging parameters */ int eventContext; /* Next event context */ @@ -652,7 +673,6 @@ typedef struct _MPT_ADAPTER struct _mpt_ioctl_events *events; /* pointer to event log */ u8 *cached_fw; /* Pointer to FW */ dma_addr_t cached_fw_dma; - struct list_head configQ; /* linked list of config. requests */ int hs_reply_idx; #ifndef MFCNT u32 pad0; @@ -665,9 +685,6 @@ typedef struct _MPT_ADAPTER IOCFactsReply_t facts; PortFactsReply_t pfacts[2]; FCPortPage0_t fc_port_page0[2]; - struct timer_list persist_timer; /* persist table timer */ - int persist_wait_done; /* persist completion flag */ - u8 persist_reply_frame[MPT_DEFAULT_FRAME_SIZE]; /* persist reply */ LANPage0_t lan_cnfg_page0; LANPage1_t lan_cnfg_page1; @@ -682,23 +699,44 @@ typedef struct _MPT_ADAPTER int aen_event_read_flag; /* flag to indicate event log was read*/ u8 FirstWhoInit; u8 upload_fw; /* If set, do a fw upload */ - u8 reload_fw; /* Force a FW Reload on next reset */ u8 NBShiftFactor; /* NB Shift Factor based on Block Size (Facts) */ u8 pad1[4]; u8 DoneCtx; u8 TaskCtx; u8 InternalCtx; - spinlock_t initializing_hba_lock; - int initializing_hba_lock_flag; struct list_head list; struct net_device *netdev; struct list_head sas_topology; struct mutex sas_topology_mutex; + + struct workqueue_struct *fw_event_q; + struct list_head fw_event_list; + spinlock_t fw_event_lock; + u8 fw_events_off; /* if '1', then ignore events */ + char fw_event_q_name[MPT_KOBJ_NAME_LEN]; + struct mutex sas_discovery_mutex; u8 sas_discovery_runtime; u8 sas_discovery_ignore_events; + + /* port_info object for the host */ + struct mptsas_portinfo *hba_port_info; + u64 hba_port_sas_addr; + u16 hba_port_num_phy; + struct list_head sas_device_info_list; + struct mutex sas_device_info_mutex; + u8 old_sas_discovery_protocal; + u8 sas_discovery_quiesce_io; int sas_index; /* index refrencing */ - MPT_SAS_MGMT sas_mgmt; + MPT_MGMT sas_mgmt; + MPT_MGMT mptbase_cmds; /* for sending config pages */ + MPT_MGMT internal_cmds; + MPT_MGMT taskmgmt_cmds; + MPT_MGMT ioctl_cmds; + spinlock_t taskmgmt_lock; /* diagnostic reset lock */ + int taskmgmt_in_progress; + u8 taskmgmt_quiesce_io; + u8 ioc_reset_in_progress; struct work_struct sas_persist_task; struct work_struct fc_setup_reset_work; @@ -707,15 +745,27 @@ typedef struct _MPT_ADAPTER u8 fc_link_speed[2]; spinlock_t fc_rescan_work_lock; struct work_struct fc_rescan_work; - char fc_rescan_work_q_name[20]; + char fc_rescan_work_q_name[MPT_KOBJ_NAME_LEN]; struct workqueue_struct *fc_rescan_work_q; + + /* driver forced bus resets count */ + unsigned long hard_resets; + /* fw/external bus resets count */ + unsigned long soft_resets; + /* cmd timeouts */ + unsigned long timeouts; + struct scsi_cmnd **ScsiLookup; spinlock_t scsi_lookup_lock; - - char reset_work_q_name[20]; + u64 dma_mask; + u32 broadcast_aen_busy; + char reset_work_q_name[MPT_KOBJ_NAME_LEN]; struct workqueue_struct *reset_work_q; struct delayed_work fault_reset_work; - spinlock_t fault_reset_work_lock; + + u8 sg_addr_size; + u8 in_rescan; + u8 SGE_size; } MPT_ADAPTER; @@ -753,13 +803,14 @@ typedef struct _mpt_sge { dma_addr_t Address; } MptSge_t; -#define mpt_addr_size() \ - ((sizeof(dma_addr_t) == sizeof(u64)) ? MPI_SGE_FLAGS_64_BIT_ADDRESSING : \ - MPI_SGE_FLAGS_32_BIT_ADDRESSING) -#define mpt_msg_flags() \ - ((sizeof(dma_addr_t) == sizeof(u64)) ? MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_64 : \ - MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_32) +#define mpt_msg_flags(ioc) \ + (ioc->sg_addr_size == sizeof(u64)) ? \ + MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_64 : \ + MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_32 + +#define MPT_SGE_FLAGS_64_BIT_ADDRESSING \ + (MPI_SGE_FLAGS_64_BIT_ADDRESSING << MPI_SGE_FLAGS_SHIFT) /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* @@ -835,22 +886,14 @@ typedef struct _MPT_SCSI_HOST { /* Pool of memory for holding SCpnts before doing * OS callbacks. freeQ is the free pool. */ - u8 tmPending; - u8 resetPending; u8 negoNvram; /* DV disabled, nego NVRAM */ u8 pad1; - u8 tmState; u8 rsvd[2]; MPT_FRAME_HDR *cmdPtr; /* Ptr to nonOS request */ struct scsi_cmnd *abortSCpnt; MPT_LOCAL_REPLY localReply; /* internal cmd reply struct */ - unsigned long hard_resets; /* driver forced bus resets count */ - unsigned long soft_resets; /* fw/external bus resets count */ - unsigned long timeouts; /* cmd timeouts */ ushort sel_timeout[MPT_MAX_FC_DEVICES]; char *info_kbuf; - wait_queue_head_t scandv_waitq; - int scandv_wait_done; long last_queue_full; u16 tm_iocstatus; u16 spi_pending; @@ -870,21 +913,16 @@ struct scsi_cmnd; * Generic structure passed to the base mpt_config function. */ typedef struct _x_config_parms { - struct list_head linkage; /* linked list */ - struct timer_list timer; /* timer function for this request */ union { ConfigExtendedPageHeader_t *ehdr; ConfigPageHeader_t *hdr; } cfghdr; dma_addr_t physAddr; - int wait_done; /* wait for this request */ u32 pageAddr; /* properly formatted */ + u16 status; u8 action; u8 dir; u8 timeout; /* seconds */ - u8 pad1; - u16 status; - u16 pad2; } CONFIGPARMS; /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -909,7 +947,6 @@ extern MPT_FRAME_HDR *mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc); extern void mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf); extern void mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf); extern void mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf); -extern void mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr); extern int mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag); extern int mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp); @@ -922,6 +959,12 @@ extern void mpt_free_fw_memory(MPT_ADAPTER *ioc); extern int mpt_findImVolumes(MPT_ADAPTER *ioc); extern int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode); extern int mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t phys_disk); +extern int mpt_raid_phys_disk_pg1(MPT_ADAPTER *ioc, u8 phys_disk_num, + pRaidPhysDiskPage1_t phys_disk); +extern int mpt_raid_phys_disk_get_num_paths(MPT_ADAPTER *ioc, + u8 phys_disk_num); +extern int mpt_set_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc); +extern void mpt_clear_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc); extern void mpt_halt_firmware(MPT_ADAPTER *ioc); @@ -959,7 +1002,6 @@ extern int mpt_fwfault_debug; #define MPT_SGE_FLAGS_END_OF_BUFFER (0x40000000) #define MPT_SGE_FLAGS_LOCAL_ADDRESS (0x08000000) #define MPT_SGE_FLAGS_DIRECTION (0x04000000) -#define MPT_SGE_FLAGS_ADDRESSING (mpt_addr_size() << MPI_SGE_FLAGS_SHIFT) #define MPT_SGE_FLAGS_END_OF_LIST (0x01000000) #define MPT_SGE_FLAGS_TRANSACTION_ELEMENT (0x00000000) @@ -972,14 +1014,12 @@ extern int mpt_fwfault_debug; MPT_SGE_FLAGS_END_OF_BUFFER | \ MPT_SGE_FLAGS_END_OF_LIST | \ MPT_SGE_FLAGS_SIMPLE_ELEMENT | \ - MPT_SGE_FLAGS_ADDRESSING | \ MPT_TRANSFER_IOC_TO_HOST) #define MPT_SGE_FLAGS_SSIMPLE_WRITE \ (MPT_SGE_FLAGS_LAST_ELEMENT | \ MPT_SGE_FLAGS_END_OF_BUFFER | \ MPT_SGE_FLAGS_END_OF_LIST | \ MPT_SGE_FLAGS_SIMPLE_ELEMENT | \ - MPT_SGE_FLAGS_ADDRESSING | \ MPT_TRANSFER_HOST_TO_IOC) /*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c index c63817117c0a..9b2e2198aee9 100644 --- a/drivers/message/fusion/mptctl.c +++ b/drivers/message/fusion/mptctl.c @@ -84,6 +84,7 @@ MODULE_VERSION(my_VERSION); /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ static u8 mptctl_id = MPT_MAX_PROTOCOL_DRIVERS; +static u8 mptctl_taskmgmt_id = MPT_MAX_PROTOCOL_DRIVERS; static DECLARE_WAIT_QUEUE_HEAD ( mptctl_wait ); @@ -127,10 +128,7 @@ static MptSge_t *kbuf_alloc_2_sgl(int bytes, u32 dir, int sge_offset, int *frags struct buflist **blp, dma_addr_t *sglbuf_dma, MPT_ADAPTER *ioc); static void kfree_sgl(MptSge_t *sgl, dma_addr_t sgl_dma, struct buflist *buflist, MPT_ADAPTER *ioc); -static void mptctl_timeout_expired (MPT_IOCTL *ioctl); -static int mptctl_bus_reset(MPT_IOCTL *ioctl); -static int mptctl_set_tm_flags(MPT_SCSI_HOST *hd); -static void mptctl_free_tm_flags(MPT_ADAPTER *ioc); +static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function); /* * Reset Handler cleanup function @@ -183,10 +181,10 @@ mptctl_syscall_down(MPT_ADAPTER *ioc, int nonblock) int rc = 0; if (nonblock) { - if (!mutex_trylock(&ioc->ioctl->ioctl_mutex)) + if (!mutex_trylock(&ioc->ioctl_cmds.mutex)) rc = -EAGAIN; } else { - if (mutex_lock_interruptible(&ioc->ioctl->ioctl_mutex)) + if (mutex_lock_interruptible(&ioc->ioctl_cmds.mutex)) rc = -ERESTARTSYS; } return rc; @@ -202,99 +200,78 @@ mptctl_syscall_down(MPT_ADAPTER *ioc, int nonblock) static int mptctl_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply) { - char *sense_data; - int sz, req_index; - u16 iocStatus; - u8 cmd; + char *sense_data; + int req_index; + int sz; - if (req) - cmd = req->u.hdr.Function; - else - return 1; - dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\tcompleting mpi function (0x%02X), req=%p, " - "reply=%p\n", ioc->name, req->u.hdr.Function, req, reply)); + if (!req) + return 0; - if (ioc->ioctl) { + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "completing mpi function " + "(0x%02X), req=%p, reply=%p\n", ioc->name, req->u.hdr.Function, + req, reply)); - if (reply==NULL) { + /* + * Handling continuation of the same reply. Processing the first + * reply, and eating the other replys that come later. + */ + if (ioc->ioctl_cmds.msg_context != req->u.hdr.MsgContext) + goto out_continuation; - dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_reply() NULL Reply " - "Function=%x!\n", ioc->name, cmd)); + ioc->ioctl_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD; - ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD; - ioc->ioctl->reset &= ~MPTCTL_RESET_OK; + if (!reply) + goto out; - /* We are done, issue wake up - */ - ioc->ioctl->wait_done = 1; - wake_up (&mptctl_wait); - return 1; + ioc->ioctl_cmds.status |= MPT_MGMT_STATUS_RF_VALID; + sz = min(ioc->reply_sz, 4*reply->u.reply.MsgLength); + memcpy(ioc->ioctl_cmds.reply, reply, sz); - } + if (reply->u.reply.IOCStatus || reply->u.reply.IOCLogInfo) + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "iocstatus (0x%04X), loginfo (0x%08X)\n", ioc->name, + le16_to_cpu(reply->u.reply.IOCStatus), + le32_to_cpu(reply->u.reply.IOCLogInfo))); - /* Copy the reply frame (which much exist - * for non-SCSI I/O) to the IOC structure. - */ - memcpy(ioc->ioctl->ReplyFrame, reply, - min(ioc->reply_sz, 4*reply->u.reply.MsgLength)); - ioc->ioctl->status |= MPT_IOCTL_STATUS_RF_VALID; + if ((req->u.hdr.Function == MPI_FUNCTION_SCSI_IO_REQUEST) || + (req->u.hdr.Function == + MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) { - /* Set the command status to GOOD if IOC Status is GOOD - * OR if SCSI I/O cmd and data underrun or recovered error. - */ - iocStatus = le16_to_cpu(reply->u.reply.IOCStatus) & MPI_IOCSTATUS_MASK; - if (iocStatus == MPI_IOCSTATUS_SUCCESS) - ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD; + if (reply->u.sreply.SCSIStatus || reply->u.sreply.SCSIState) + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "scsi_status (0x%02x), scsi_state (0x%02x), " + "tag = (0x%04x), transfer_count (0x%08x)\n", ioc->name, + reply->u.sreply.SCSIStatus, + reply->u.sreply.SCSIState, + le16_to_cpu(reply->u.sreply.TaskTag), + le32_to_cpu(reply->u.sreply.TransferCount))); - if (iocStatus || reply->u.reply.IOCLogInfo) - dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\tiocstatus (0x%04X), " - "loginfo (0x%08X)\n", ioc->name, - iocStatus, - le32_to_cpu(reply->u.reply.IOCLogInfo))); - - if ((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) || - (cmd == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) { - - if (reply->u.sreply.SCSIStatus || reply->u.sreply.SCSIState) - dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "\tscsi_status (0x%02x), scsi_state (0x%02x), " - "tag = (0x%04x), transfer_count (0x%08x)\n", ioc->name, - reply->u.sreply.SCSIStatus, - reply->u.sreply.SCSIState, - le16_to_cpu(reply->u.sreply.TaskTag), - le32_to_cpu(reply->u.sreply.TransferCount))); - - ioc->ioctl->reset &= ~MPTCTL_RESET_OK; - - if ((iocStatus == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN) || - (iocStatus == MPI_IOCSTATUS_SCSI_RECOVERED_ERROR)) { - ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD; - } - } - - /* Copy the sense data - if present - */ - if ((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) && - (reply->u.sreply.SCSIState & - MPI_SCSI_STATE_AUTOSENSE_VALID)){ + if (reply->u.sreply.SCSIState & + MPI_SCSI_STATE_AUTOSENSE_VALID) { sz = req->u.scsireq.SenseBufferLength; req_index = le16_to_cpu(req->u.frame.hwhdr.msgctxu.fld.req_idx); - sense_data = - ((u8 *)ioc->sense_buf_pool + + sense_data = ((u8 *)ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC)); - memcpy(ioc->ioctl->sense, sense_data, sz); - ioc->ioctl->status |= MPT_IOCTL_STATUS_SENSE_VALID; + memcpy(ioc->ioctl_cmds.sense, sense_data, sz); + ioc->ioctl_cmds.status |= MPT_MGMT_STATUS_SENSE_VALID; } - - if (cmd == MPI_FUNCTION_SCSI_TASK_MGMT) - mptctl_free_tm_flags(ioc); - - /* We are done, issue wake up - */ - ioc->ioctl->wait_done = 1; - wake_up (&mptctl_wait); } + + out: + /* We are done, issue wake up + */ + if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_PENDING) { + if (req->u.hdr.Function == MPI_FUNCTION_SCSI_TASK_MGMT) + mpt_clear_taskmgmt_in_progress_flag(ioc); + ioc->ioctl_cmds.status &= ~MPT_MGMT_STATUS_PENDING; + complete(&ioc->ioctl_cmds.done); + } + + out_continuation: + if (reply && (reply->u.reply.MsgFlags & + MPI_MSGFLAGS_CONTINUATION_REPLY)) + return 0; return 1; } @@ -304,30 +281,66 @@ mptctl_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply) * Expecting an interrupt, however timed out. * */ -static void mptctl_timeout_expired (MPT_IOCTL *ioctl) +static void +mptctl_timeout_expired(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf) { - int rc = 1; + unsigned long flags; - if (ioctl == NULL) + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": %s\n", + ioc->name, __func__)); + + if (mpt_fwfault_debug) + mpt_halt_firmware(ioc); + + spin_lock_irqsave(&ioc->taskmgmt_lock, flags); + if (ioc->ioc_reset_in_progress) { + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + CLEAR_MGMT_PENDING_STATUS(ioc->ioctl_cmds.status) + mpt_free_msg_frame(ioc, mf); return; - dctlprintk(ioctl->ioc, - printk(MYIOC_s_DEBUG_FMT ": Timeout Expired! Host %d\n", - ioctl->ioc->name, ioctl->ioc->id)); - - ioctl->wait_done = 0; - if (ioctl->reset & MPTCTL_RESET_OK) - rc = mptctl_bus_reset(ioctl); - - if (rc) { - /* Issue a reset for this device. - * The IOC is not responding. - */ - dctlprintk(ioctl->ioc, printk(MYIOC_s_DEBUG_FMT "Calling HardReset! \n", - ioctl->ioc->name)); - mpt_HardResetHandler(ioctl->ioc, CAN_SLEEP); } - return; + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + + if (!mptctl_bus_reset(ioc, mf->u.hdr.Function)) + return; + + /* Issue a reset for this device. + * The IOC is not responding. + */ + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling HardReset! \n", + ioc->name)); + CLEAR_MGMT_PENDING_STATUS(ioc->ioctl_cmds.status) + mpt_HardResetHandler(ioc, CAN_SLEEP); + mpt_free_msg_frame(ioc, mf); +} + +static int +mptctl_taskmgmt_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) +{ + if (!mf) + return 0; + + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "TaskMgmt completed (mf=%p, mr=%p)\n", + ioc->name, mf, mr)); + + ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD; + + if (!mr) + goto out; + + ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID; + memcpy(ioc->taskmgmt_cmds.reply, mr, + min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength)); + out: + if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) { + mpt_clear_taskmgmt_in_progress_flag(ioc); + ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING; + complete(&ioc->taskmgmt_cmds.done); + return 1; + } + return 0; } /* mptctl_bus_reset @@ -335,133 +348,150 @@ static void mptctl_timeout_expired (MPT_IOCTL *ioctl) * Bus reset code. * */ -static int mptctl_bus_reset(MPT_IOCTL *ioctl) +static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function) { MPT_FRAME_HDR *mf; SCSITaskMgmt_t *pScsiTm; - MPT_SCSI_HOST *hd; + SCSITaskMgmtReply_t *pScsiTmReply; int ii; - int retval=0; + int retval; + unsigned long timeout; + unsigned long time_count; + u16 iocstatus; - - ioctl->reset &= ~MPTCTL_RESET_OK; - - if (ioctl->ioc->sh == NULL) + /* bus reset is only good for SCSI IO, RAID PASSTHRU */ + if (!(function == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) || + (function == MPI_FUNCTION_SCSI_IO_REQUEST)) { + dtmprintk(ioc, printk(MYIOC_s_WARN_FMT + "TaskMgmt, not SCSI_IO!!\n", ioc->name)); return -EPERM; + } - hd = shost_priv(ioctl->ioc->sh); - if (hd == NULL) + mutex_lock(&ioc->taskmgmt_cmds.mutex); + if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) { + mutex_unlock(&ioc->taskmgmt_cmds.mutex); return -EPERM; + } - /* Single threading .... - */ - if (mptctl_set_tm_flags(hd) != 0) - return -EPERM; + retval = 0; /* Send request */ - if ((mf = mpt_get_msg_frame(mptctl_id, ioctl->ioc)) == NULL) { - dtmprintk(ioctl->ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt, no msg frames!!\n", - ioctl->ioc->name)); - - mptctl_free_tm_flags(ioctl->ioc); - return -ENOMEM; + mf = mpt_get_msg_frame(mptctl_taskmgmt_id, ioc); + if (mf == NULL) { + dtmprintk(ioc, printk(MYIOC_s_WARN_FMT + "TaskMgmt, no msg frames!!\n", ioc->name)); + mpt_clear_taskmgmt_in_progress_flag(ioc); + retval = -ENOMEM; + goto mptctl_bus_reset_done; } - dtmprintk(ioctl->ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt request @ %p\n", - ioctl->ioc->name, mf)); + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n", + ioc->name, mf)); pScsiTm = (SCSITaskMgmt_t *) mf; - pScsiTm->TargetID = ioctl->id; - pScsiTm->Bus = hd->port; /* 0 */ - pScsiTm->ChainOffset = 0; + memset(pScsiTm, 0, sizeof(SCSITaskMgmt_t)); pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT; - pScsiTm->Reserved = 0; pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS; - pScsiTm->Reserved1 = 0; pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION; - + pScsiTm->TargetID = 0; + pScsiTm->Bus = 0; + pScsiTm->ChainOffset = 0; + pScsiTm->Reserved = 0; + pScsiTm->Reserved1 = 0; + pScsiTm->TaskMsgContext = 0; for (ii= 0; ii < 8; ii++) pScsiTm->LUN[ii] = 0; - for (ii=0; ii < 7; ii++) pScsiTm->Reserved2[ii] = 0; - pScsiTm->TaskMsgContext = 0; - dtmprintk(ioctl->ioc, printk(MYIOC_s_DEBUG_FMT - "mptctl_bus_reset: issued.\n", ioctl->ioc->name)); + switch (ioc->bus_type) { + case FC: + timeout = 40; + break; + case SAS: + timeout = 30; + break; + case SPI: + default: + timeout = 2; + break; + } - DBG_DUMP_TM_REQUEST_FRAME(ioctl->ioc, (u32 *)mf); + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "TaskMgmt type=%d timeout=%ld\n", + ioc->name, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, timeout)); - ioctl->wait_done=0; - - if ((ioctl->ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) && - (ioctl->ioc->facts.MsgVersion >= MPI_VERSION_01_05)) - mpt_put_msg_frame_hi_pri(mptctl_id, ioctl->ioc, mf); + INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status) + CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status) + time_count = jiffies; + if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) && + (ioc->facts.MsgVersion >= MPI_VERSION_01_05)) + mpt_put_msg_frame_hi_pri(mptctl_taskmgmt_id, ioc, mf); else { - retval = mpt_send_handshake_request(mptctl_id, ioctl->ioc, - sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP); + retval = mpt_send_handshake_request(mptctl_taskmgmt_id, ioc, + sizeof(SCSITaskMgmt_t), (u32 *)pScsiTm, CAN_SLEEP); if (retval != 0) { - dfailprintk(ioctl->ioc, printk(MYIOC_s_ERR_FMT "_send_handshake FAILED!" - " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd, - hd->ioc, mf)); + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "TaskMgmt send_handshake FAILED!" + " (ioc %p, mf %p, rc=%d) \n", ioc->name, + ioc, mf, retval)); + mpt_clear_taskmgmt_in_progress_flag(ioc); goto mptctl_bus_reset_done; } } /* Now wait for the command to complete */ - ii = wait_event_timeout(mptctl_wait, - ioctl->wait_done == 1, - HZ*5 /* 5 second timeout */); + ii = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done, timeout*HZ); + if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "TaskMgmt failed\n", ioc->name)); + mpt_free_msg_frame(ioc, mf); + mpt_clear_taskmgmt_in_progress_flag(ioc); + if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) + retval = 0; + else + retval = -1; /* return failure */ + goto mptctl_bus_reset_done; + } - if(ii <=0 && (ioctl->wait_done != 1 )) { - mpt_free_msg_frame(hd->ioc, mf); - ioctl->wait_done = 0; + if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) { + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "TaskMgmt failed\n", ioc->name)); + retval = -1; /* return failure */ + goto mptctl_bus_reset_done; + } + + pScsiTmReply = (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply; + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "TaskMgmt fw_channel = %d, fw_id = %d, task_type=0x%02X, " + "iocstatus=0x%04X\n\tloginfo=0x%08X, response_code=0x%02X, " + "term_cmnds=%d\n", ioc->name, pScsiTmReply->Bus, + pScsiTmReply->TargetID, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, + le16_to_cpu(pScsiTmReply->IOCStatus), + le32_to_cpu(pScsiTmReply->IOCLogInfo), + pScsiTmReply->ResponseCode, + le32_to_cpu(pScsiTmReply->TerminationCount))); + + iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK; + + if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED || + iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED || + iocstatus == MPI_IOCSTATUS_SUCCESS) + retval = 0; + else { + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "TaskMgmt failed\n", ioc->name)); retval = -1; /* return failure */ } -mptctl_bus_reset_done: - mptctl_free_tm_flags(ioctl->ioc); + mptctl_bus_reset_done: + mutex_unlock(&ioc->taskmgmt_cmds.mutex); + CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status) return retval; } -static int -mptctl_set_tm_flags(MPT_SCSI_HOST *hd) { - unsigned long flags; - - spin_lock_irqsave(&hd->ioc->FreeQlock, flags); - - if (hd->tmState == TM_STATE_NONE) { - hd->tmState = TM_STATE_IN_PROGRESS; - hd->tmPending = 1; - spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); - } else { - spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); - return -EBUSY; - } - - return 0; -} - -static void -mptctl_free_tm_flags(MPT_ADAPTER *ioc) -{ - MPT_SCSI_HOST * hd; - unsigned long flags; - - hd = shost_priv(ioc->sh); - if (hd == NULL) - return; - - spin_lock_irqsave(&ioc->FreeQlock, flags); - - hd->tmState = TM_STATE_NONE; - hd->tmPending = 0; - spin_unlock_irqrestore(&ioc->FreeQlock, flags); - - return; -} /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* mptctl_ioc_reset @@ -473,22 +503,23 @@ mptctl_free_tm_flags(MPT_ADAPTER *ioc) static int mptctl_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) { - MPT_IOCTL *ioctl = ioc->ioctl; - dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC %s_reset routed to IOCTL driver!\n", ioc->name, - reset_phase==MPT_IOC_SETUP_RESET ? "setup" : ( - reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"))); - - if(ioctl == NULL) - return 1; - switch(reset_phase) { case MPT_IOC_SETUP_RESET: - ioctl->status |= MPT_IOCTL_STATUS_DID_IOCRESET; - break; - case MPT_IOC_POST_RESET: - ioctl->status &= ~MPT_IOCTL_STATUS_DID_IOCRESET; + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__)); break; case MPT_IOC_PRE_RESET: + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__)); + break; + case MPT_IOC_POST_RESET: + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__)); + if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_PENDING) { + ioc->ioctl_cmds.status |= MPT_MGMT_STATUS_DID_IOCRESET; + complete(&ioc->ioctl_cmds.done); + } + break; default: break; } @@ -642,7 +673,7 @@ __mptctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) else ret = -EINVAL; - mutex_unlock(&iocp->ioctl->ioctl_mutex); + mutex_unlock(&iocp->ioctl_cmds.mutex); return ret; } @@ -758,6 +789,7 @@ mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen) int sge_offset = 0; u16 iocstat; pFWDownloadReply_t ReplyMsg = NULL; + unsigned long timeleft; if (mpt_verify_adapter(ioc, &iocp) < 0) { printk(KERN_DEBUG MYNAM "ioctl_fwdl - ioc%d not found!\n", @@ -841,8 +873,9 @@ mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen) * 96 8 * 64 4 */ - maxfrags = (iocp->req_sz - sizeof(MPIHeader_t) - sizeof(FWDownloadTCSGE_t)) - / (sizeof(dma_addr_t) + sizeof(u32)); + maxfrags = (iocp->req_sz - sizeof(MPIHeader_t) - + sizeof(FWDownloadTCSGE_t)) + / iocp->SGE_size; if (numfrags > maxfrags) { ret = -EMLINK; goto fwdl_out; @@ -870,7 +903,7 @@ mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen) if (nib == 0 || nib == 3) { ; } else if (sgIn->Address) { - mpt_add_sge(sgOut, sgIn->FlagsLength, sgIn->Address); + iocp->add_sge(sgOut, sgIn->FlagsLength, sgIn->Address); n++; if (copy_from_user(bl->kptr, ufwbuf+fw_bytes_copied, bl->len)) { printk(MYIOC_s_ERR_FMT "%s@%d::_ioctl_fwdl - " @@ -882,7 +915,7 @@ mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen) } sgIn++; bl++; - sgOut += (sizeof(dma_addr_t) + sizeof(u32)); + sgOut += iocp->SGE_size; } DBG_DUMP_FW_DOWNLOAD(iocp, (u32 *)mf, numfrags); @@ -891,16 +924,30 @@ mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen) * Finally, perform firmware download. */ ReplyMsg = NULL; + SET_MGMT_MSG_CONTEXT(iocp->ioctl_cmds.msg_context, dlmsg->MsgContext); + INITIALIZE_MGMT_STATUS(iocp->ioctl_cmds.status) mpt_put_msg_frame(mptctl_id, iocp, mf); /* Now wait for the command to complete */ - ret = wait_event_timeout(mptctl_wait, - iocp->ioctl->wait_done == 1, - HZ*60); +retry_wait: + timeleft = wait_for_completion_timeout(&iocp->ioctl_cmds.done, HZ*60); + if (!(iocp->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + ret = -ETIME; + printk(MYIOC_s_WARN_FMT "%s: failed\n", iocp->name, __func__); + if (iocp->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) { + mpt_free_msg_frame(iocp, mf); + goto fwdl_out; + } + if (!timeleft) + mptctl_timeout_expired(iocp, mf); + else + goto retry_wait; + goto fwdl_out; + } - if(ret <=0 && (iocp->ioctl->wait_done != 1 )) { - /* Now we need to reset the board */ - mptctl_timeout_expired(iocp->ioctl); + if (!(iocp->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID)) { + printk(MYIOC_s_WARN_FMT "%s: failed\n", iocp->name, __func__); + mpt_free_msg_frame(iocp, mf); ret = -ENODATA; goto fwdl_out; } @@ -908,7 +955,7 @@ mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen) if (sgl) kfree_sgl(sgl, sgl_dma, buflist, iocp); - ReplyMsg = (pFWDownloadReply_t)iocp->ioctl->ReplyFrame; + ReplyMsg = (pFWDownloadReply_t)iocp->ioctl_cmds.reply; iocstat = le16_to_cpu(ReplyMsg->IOCStatus) & MPI_IOCSTATUS_MASK; if (iocstat == MPI_IOCSTATUS_SUCCESS) { printk(MYIOC_s_INFO_FMT "F/W update successfull!\n", iocp->name); @@ -932,6 +979,9 @@ mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen) return 0; fwdl_out: + + CLEAR_MGMT_STATUS(iocp->ioctl_cmds.status); + SET_MGMT_MSG_CONTEXT(iocp->ioctl_cmds.msg_context, 0); kfree_sgl(sgl, sgl_dma, buflist, iocp); return ret; } @@ -1003,7 +1053,7 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, int sge_offset, int *frags, * */ sgl = sglbuf; - sg_spill = ((ioc->req_sz - sge_offset)/(sizeof(dma_addr_t) + sizeof(u32))) - 1; + sg_spill = ((ioc->req_sz - sge_offset)/ioc->SGE_size) - 1; while (bytes_allocd < bytes) { this_alloc = min(alloc_sz, bytes-bytes_allocd); buflist[buflist_ent].len = this_alloc; @@ -1024,8 +1074,9 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, int sge_offset, int *frags, dma_addr_t dma_addr; bytes_allocd += this_alloc; - sgl->FlagsLength = (0x10000000|MPT_SGE_FLAGS_ADDRESSING|sgdir|this_alloc); - dma_addr = pci_map_single(ioc->pcidev, buflist[buflist_ent].kptr, this_alloc, dir); + sgl->FlagsLength = (0x10000000|sgdir|this_alloc); + dma_addr = pci_map_single(ioc->pcidev, + buflist[buflist_ent].kptr, this_alloc, dir); sgl->Address = dma_addr; fragcnt++; @@ -1771,7 +1822,10 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) int msgContext; u16 req_idx; ulong timeout; + unsigned long timeleft; struct scsi_device *sdev; + unsigned long flags; + u8 function; /* bufIn and bufOut are used for user to kernel space transfers */ @@ -1784,24 +1838,23 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) __FILE__, __LINE__, iocnum); return -ENODEV; } - if (!ioc->ioctl) { + + spin_lock_irqsave(&ioc->taskmgmt_lock, flags); + if (ioc->ioc_reset_in_progress) { + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); printk(KERN_ERR MYNAM "%s@%d::mptctl_do_mpt_command - " - "No memory available during driver init.\n", - __FILE__, __LINE__); - return -ENOMEM; - } else if (ioc->ioctl->status & MPT_IOCTL_STATUS_DID_IOCRESET) { - printk(KERN_ERR MYNAM "%s@%d::mptctl_do_mpt_command - " - "Busy with IOC Reset \n", __FILE__, __LINE__); + "Busy with diagnostic reset\n", __FILE__, __LINE__); return -EBUSY; } + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); /* Verify that the final request frame will not be too large. */ sz = karg.dataSgeOffset * 4; if (karg.dataInSize > 0) - sz += sizeof(dma_addr_t) + sizeof(u32); + sz += ioc->SGE_size; if (karg.dataOutSize > 0) - sz += sizeof(dma_addr_t) + sizeof(u32); + sz += ioc->SGE_size; if (sz > ioc->req_sz) { printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - " @@ -1827,10 +1880,12 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - " "Unable to read MF from mpt_ioctl_command struct @ %p\n", ioc->name, __FILE__, __LINE__, mfPtr); + function = -1; rc = -EFAULT; goto done_free_mem; } hdr->MsgContext = cpu_to_le32(msgContext); + function = hdr->Function; /* Verify that this request is allowed. @@ -1838,7 +1893,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sending mpi function (0x%02X), req=%p\n", ioc->name, hdr->Function, mf)); - switch (hdr->Function) { + switch (function) { case MPI_FUNCTION_IOC_FACTS: case MPI_FUNCTION_PORT_FACTS: karg.dataOutSize = karg.dataInSize = 0; @@ -1893,7 +1948,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) } pScsiReq->MsgFlags &= ~MPI_SCSIIO_MSGFLGS_SENSE_WIDTH; - pScsiReq->MsgFlags |= mpt_msg_flags(); + pScsiReq->MsgFlags |= mpt_msg_flags(ioc); /* verify that app has not requested @@ -1935,8 +1990,6 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) pScsiReq->Control = cpu_to_le32(scsidir | qtag); pScsiReq->DataLength = cpu_to_le32(dataSize); - ioc->ioctl->reset = MPTCTL_RESET_OK; - ioc->ioctl->id = pScsiReq->TargetID; } else { printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - " @@ -1979,7 +2032,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) int dataSize; pScsiReq->MsgFlags &= ~MPI_SCSIIO_MSGFLGS_SENSE_WIDTH; - pScsiReq->MsgFlags |= mpt_msg_flags(); + pScsiReq->MsgFlags |= mpt_msg_flags(ioc); /* verify that app has not requested @@ -2014,8 +2067,6 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) pScsiReq->Control = cpu_to_le32(scsidir | qtag); pScsiReq->DataLength = cpu_to_le32(dataSize); - ioc->ioctl->reset = MPTCTL_RESET_OK; - ioc->ioctl->id = pScsiReq->TargetID; } else { printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - " "SCSI driver is not loaded. \n", @@ -2026,20 +2077,17 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) break; case MPI_FUNCTION_SCSI_TASK_MGMT: - { - MPT_SCSI_HOST *hd = NULL; - if ((ioc->sh == NULL) || ((hd = shost_priv(ioc->sh)) == NULL)) { - printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - " - "SCSI driver not loaded or SCSI host not found. \n", - ioc->name, __FILE__, __LINE__); - rc = -EFAULT; - goto done_free_mem; - } else if (mptctl_set_tm_flags(hd) != 0) { - rc = -EPERM; - goto done_free_mem; - } - } + { + SCSITaskMgmt_t *pScsiTm; + pScsiTm = (SCSITaskMgmt_t *)mf; + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "\tTaskType=0x%x MsgFlags=0x%x " + "TaskMsgContext=0x%x id=%d channel=%d\n", + ioc->name, pScsiTm->TaskType, le32_to_cpu + (pScsiTm->TaskMsgContext), pScsiTm->MsgFlags, + pScsiTm->TargetID, pScsiTm->Bus)); break; + } case MPI_FUNCTION_IOC_INIT: { @@ -2123,8 +2171,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) if (karg.dataInSize > 0) { flagsLength = ( MPI_SGE_FLAGS_SIMPLE_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER | - MPI_SGE_FLAGS_DIRECTION | - mpt_addr_size() ) + MPI_SGE_FLAGS_DIRECTION) << MPI_SGE_FLAGS_SHIFT; } else { flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE; @@ -2141,8 +2188,8 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) /* Set up this SGE. * Copy to MF and to sglbuf */ - mpt_add_sge(psge, flagsLength, dma_addr_out); - psge += (sizeof(u32) + sizeof(dma_addr_t)); + ioc->add_sge(psge, flagsLength, dma_addr_out); + psge += ioc->SGE_size; /* Copy user data to kernel space. */ @@ -2175,18 +2222,25 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) /* Set up this SGE * Copy to MF and to sglbuf */ - mpt_add_sge(psge, flagsLength, dma_addr_in); + ioc->add_sge(psge, flagsLength, dma_addr_in); } } } else { /* Add a NULL SGE */ - mpt_add_sge(psge, flagsLength, (dma_addr_t) -1); + ioc->add_sge(psge, flagsLength, (dma_addr_t) -1); } - ioc->ioctl->wait_done = 0; + SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, hdr->MsgContext); + INITIALIZE_MGMT_STATUS(ioc->ioctl_cmds.status) if (hdr->Function == MPI_FUNCTION_SCSI_TASK_MGMT) { + mutex_lock(&ioc->taskmgmt_cmds.mutex); + if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) { + mutex_unlock(&ioc->taskmgmt_cmds.mutex); + goto done_free_mem; + } + DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf); if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) && @@ -2197,10 +2251,11 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) sizeof(SCSITaskMgmt_t), (u32*)mf, CAN_SLEEP); if (rc != 0) { dfailprintk(ioc, printk(MYIOC_s_ERR_FMT - "_send_handshake FAILED! (ioc %p, mf %p)\n", + "send_handshake FAILED! (ioc %p, mf %p)\n", ioc->name, ioc, mf)); - mptctl_free_tm_flags(ioc); + mpt_clear_taskmgmt_in_progress_flag(ioc); rc = -ENODATA; + mutex_unlock(&ioc->taskmgmt_cmds.mutex); goto done_free_mem; } } @@ -2210,36 +2265,47 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) /* Now wait for the command to complete */ timeout = (karg.timeout > 0) ? karg.timeout : MPT_IOCTL_DEFAULT_TIMEOUT; - timeout = wait_event_timeout(mptctl_wait, - ioc->ioctl->wait_done == 1, - HZ*timeout); - - if(timeout <=0 && (ioc->ioctl->wait_done != 1 )) { - /* Now we need to reset the board */ - - if (hdr->Function == MPI_FUNCTION_SCSI_TASK_MGMT) - mptctl_free_tm_flags(ioc); - - mptctl_timeout_expired(ioc->ioctl); - rc = -ENODATA; +retry_wait: + timeleft = wait_for_completion_timeout(&ioc->ioctl_cmds.done, + HZ*timeout); + if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + rc = -ETIME; + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "%s: TIMED OUT!\n", + ioc->name, __func__)); + if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) { + if (function == MPI_FUNCTION_SCSI_TASK_MGMT) + mutex_unlock(&ioc->taskmgmt_cmds.mutex); + goto done_free_mem; + } + if (!timeleft) { + if (function == MPI_FUNCTION_SCSI_TASK_MGMT) + mutex_unlock(&ioc->taskmgmt_cmds.mutex); + mptctl_timeout_expired(ioc, mf); + mf = NULL; + } else + goto retry_wait; goto done_free_mem; } + if (function == MPI_FUNCTION_SCSI_TASK_MGMT) + mutex_unlock(&ioc->taskmgmt_cmds.mutex); + + mf = NULL; /* If a valid reply frame, copy to the user. * Offset 2: reply length in U32's */ - if (ioc->ioctl->status & MPT_IOCTL_STATUS_RF_VALID) { + if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) { if (karg.maxReplyBytes < ioc->reply_sz) { - sz = min(karg.maxReplyBytes, 4*ioc->ioctl->ReplyFrame[2]); + sz = min(karg.maxReplyBytes, + 4*ioc->ioctl_cmds.reply[2]); } else { - sz = min(ioc->reply_sz, 4*ioc->ioctl->ReplyFrame[2]); + sz = min(ioc->reply_sz, 4*ioc->ioctl_cmds.reply[2]); } - if (sz > 0) { if (copy_to_user(karg.replyFrameBufPtr, - &ioc->ioctl->ReplyFrame, sz)){ + ioc->ioctl_cmds.reply, sz)){ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - " "Unable to write out reply frame %p\n", @@ -2252,10 +2318,11 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) /* If valid sense data, copy to user. */ - if (ioc->ioctl->status & MPT_IOCTL_STATUS_SENSE_VALID) { + if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_SENSE_VALID) { sz = min(karg.maxSenseBytes, MPT_SENSE_BUFFER_SIZE); if (sz > 0) { - if (copy_to_user(karg.senseDataPtr, ioc->ioctl->sense, sz)) { + if (copy_to_user(karg.senseDataPtr, + ioc->ioctl_cmds.sense, sz)) { printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - " "Unable to write sense data to user %p\n", ioc->name, __FILE__, __LINE__, @@ -2269,7 +2336,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) /* If the overall status is _GOOD and data in, copy data * to user. */ - if ((ioc->ioctl->status & MPT_IOCTL_STATUS_COMMAND_GOOD) && + if ((ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD) && (karg.dataInSize > 0) && (bufIn.kptr)) { if (copy_to_user(karg.dataInBufPtr, @@ -2284,9 +2351,8 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) done_free_mem: - ioc->ioctl->status &= ~(MPT_IOCTL_STATUS_COMMAND_GOOD | - MPT_IOCTL_STATUS_SENSE_VALID | - MPT_IOCTL_STATUS_RF_VALID ); + CLEAR_MGMT_STATUS(ioc->ioctl_cmds.status) + SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, 0); /* Free the allocated memory. */ @@ -2336,6 +2402,8 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size) ToolboxIstwiReadWriteRequest_t *IstwiRWRequest; MPT_FRAME_HDR *mf = NULL; MPIHeader_t *mpi_hdr; + unsigned long timeleft; + int retval; /* Reset long to int. Should affect IA64 and SPARC only */ @@ -2466,9 +2534,9 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size) MPT_SCSI_HOST *hd = shost_priv(ioc->sh); if (hd && (cim_rev == 1)) { - karg.hard_resets = hd->hard_resets; - karg.soft_resets = hd->soft_resets; - karg.timeouts = hd->timeouts; + karg.hard_resets = ioc->hard_resets; + karg.soft_resets = ioc->soft_resets; + karg.timeouts = ioc->timeouts; } } @@ -2476,8 +2544,8 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size) * Gather ISTWI(Industry Standard Two Wire Interface) Data */ if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) { - dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n", - ioc->name,__func__)); + dfailprintk(ioc, printk(MYIOC_s_WARN_FMT + "%s, no msg frames!!\n", ioc->name, __func__)); goto out; } @@ -2498,22 +2566,29 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size) pbuf = pci_alloc_consistent(ioc->pcidev, 4, &buf_dma); if (!pbuf) goto out; - mpt_add_sge((char *)&IstwiRWRequest->SGL, + ioc->add_sge((char *)&IstwiRWRequest->SGL, (MPT_SGE_FLAGS_SSIMPLE_READ|4), buf_dma); - ioc->ioctl->wait_done = 0; + retval = 0; + SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, + IstwiRWRequest->MsgContext); + INITIALIZE_MGMT_STATUS(ioc->ioctl_cmds.status) mpt_put_msg_frame(mptctl_id, ioc, mf); - rc = wait_event_timeout(mptctl_wait, - ioc->ioctl->wait_done == 1, - HZ*MPT_IOCTL_DEFAULT_TIMEOUT /* 10 sec */); - - if(rc <=0 && (ioc->ioctl->wait_done != 1 )) { - /* - * Now we need to reset the board - */ - mpt_free_msg_frame(ioc, mf); - mptctl_timeout_expired(ioc->ioctl); +retry_wait: + timeleft = wait_for_completion_timeout(&ioc->ioctl_cmds.done, + HZ*MPT_IOCTL_DEFAULT_TIMEOUT); + if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + retval = -ETIME; + printk(MYIOC_s_WARN_FMT "%s: failed\n", ioc->name, __func__); + if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) { + mpt_free_msg_frame(ioc, mf); + goto out; + } + if (!timeleft) + mptctl_timeout_expired(ioc, mf); + else + goto retry_wait; goto out; } @@ -2526,10 +2601,13 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size) * bays have drives in them * pbuf[3] = Checksum (0x100 = (byte0 + byte2 + byte3) */ - if (ioc->ioctl->status & MPT_IOCTL_STATUS_RF_VALID) + if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) karg.rsvd = *(u32 *)pbuf; out: + CLEAR_MGMT_STATUS(ioc->ioctl_cmds.status) + SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, 0); + if (pbuf) pci_free_consistent(ioc->pcidev, 4, pbuf, buf_dma); @@ -2753,7 +2831,7 @@ compat_mptfwxfer_ioctl(struct file *filp, unsigned int cmd, ret = mptctl_do_fw_download(kfw.iocnum, kfw.bufp, kfw.fwlen); - mutex_unlock(&iocp->ioctl->ioctl_mutex); + mutex_unlock(&iocp->ioctl_cmds.mutex); return ret; } @@ -2807,7 +2885,7 @@ compat_mpt_command(struct file *filp, unsigned int cmd, */ ret = mptctl_do_mpt_command (karg, &uarg->MF); - mutex_unlock(&iocp->ioctl->ioctl_mutex); + mutex_unlock(&iocp->ioctl_cmds.mutex); return ret; } @@ -2859,21 +2937,10 @@ static long compat_mpctl_ioctl(struct file *f, unsigned int cmd, unsigned long a static int mptctl_probe(struct pci_dev *pdev, const struct pci_device_id *id) { - MPT_IOCTL *mem; MPT_ADAPTER *ioc = pci_get_drvdata(pdev); - /* - * Allocate and inite a MPT_IOCTL structure - */ - mem = kzalloc(sizeof(MPT_IOCTL), GFP_KERNEL); - if (!mem) { - mptctl_remove(pdev); - return -ENOMEM; - } - - ioc->ioctl = mem; - ioc->ioctl->ioc = ioc; - mutex_init(&ioc->ioctl->ioctl_mutex); + mutex_init(&ioc->ioctl_cmds.mutex); + init_completion(&ioc->ioctl_cmds.done); return 0; } @@ -2887,9 +2954,6 @@ mptctl_probe(struct pci_dev *pdev, const struct pci_device_id *id) static void mptctl_remove(struct pci_dev *pdev) { - MPT_ADAPTER *ioc = pci_get_drvdata(pdev); - - kfree ( ioc->ioctl ); } static struct mpt_pci_driver mptctl_driver = { @@ -2929,6 +2993,7 @@ static int __init mptctl_init(void) goto out_fail; } + mptctl_taskmgmt_id = mpt_register(mptctl_taskmgmt_reply, MPTCTL_DRIVER); mpt_reset_register(mptctl_id, mptctl_ioc_reset); mpt_event_register(mptctl_id, mptctl_event_process); @@ -2953,6 +3018,7 @@ static void mptctl_exit(void) /* De-register callback handler from base module */ mpt_deregister(mptctl_id); + mpt_reset_deregister(mptctl_taskmgmt_id); mpt_device_driver_deregister(MPTCTL_DRIVER); diff --git a/drivers/message/fusion/mptdebug.h b/drivers/message/fusion/mptdebug.h index 510b9f492093..28e478879284 100644 --- a/drivers/message/fusion/mptdebug.h +++ b/drivers/message/fusion/mptdebug.h @@ -58,6 +58,7 @@ #define MPT_DEBUG_FC 0x00080000 #define MPT_DEBUG_SAS 0x00100000 #define MPT_DEBUG_SAS_WIDE 0x00200000 +#define MPT_DEBUG_36GB_MEM 0x00400000 /* * CONFIG_FUSION_LOGGING - enabled in Kconfig @@ -135,6 +136,8 @@ #define dsaswideprintk(IOC, CMD) \ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SAS_WIDE) +#define d36memprintk(IOC, CMD) \ + MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_36GB_MEM) /* diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c index c3c24fdf9fb6..e61df133a59e 100644 --- a/drivers/message/fusion/mptfc.c +++ b/drivers/message/fusion/mptfc.c @@ -1251,17 +1251,15 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id) * A slightly different algorithm is required for * 64bit SGEs. */ - scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32)); - if (sizeof(dma_addr_t) == sizeof(u64)) { + scale = ioc->req_sz/ioc->SGE_size; + if (ioc->sg_addr_size == sizeof(u64)) { numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale + - (ioc->req_sz - 60) / (sizeof(dma_addr_t) + - sizeof(u32)); + (ioc->req_sz - 60) / ioc->SGE_size; } else { numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale + - (ioc->req_sz - 64) / (sizeof(dma_addr_t) + - sizeof(u32)); + (ioc->req_sz - 64) / ioc->SGE_size; } if (numSGE < sh->sg_tablesize) { @@ -1292,9 +1290,6 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id) /* Clear the TM flags */ - hd->tmPending = 0; - hd->tmState = TM_STATE_NONE; - hd->resetPending = 0; hd->abortSCpnt = NULL; /* Clear the pointer used to store @@ -1312,8 +1307,6 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id) hd->timer.data = (unsigned long) hd; hd->timer.function = mptscsih_timer_expired; - init_waitqueue_head(&hd->scandv_waitq); - hd->scandv_wait_done = 0; hd->last_queue_full = 0; sh->transportt = mptfc_transport_template; diff --git a/drivers/message/fusion/mptlan.c b/drivers/message/fusion/mptlan.c index c2804f26cb44..a9e48e28b1dc 100644 --- a/drivers/message/fusion/mptlan.c +++ b/drivers/message/fusion/mptlan.c @@ -703,7 +703,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev) printk (KERN_ERR "%s: no tx context available: %u\n", __func__, priv->mpt_txfidx_tail); - return 1; + return NETDEV_TX_BUSY; } mf = mpt_get_msg_frame(LanCtx, mpt_dev); @@ -713,7 +713,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev) printk (KERN_ERR "%s: Unable to alloc request frame\n", __func__); - return 1; + return NETDEV_TX_BUSY; } ctx = priv->mpt_txfidx[priv->mpt_txfidx_tail--]; diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index a9019f081b97..55ff25244af4 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -93,8 +93,37 @@ static u8 mptsasDoneCtx = MPT_MAX_PROTOCOL_DRIVERS; static u8 mptsasTaskCtx = MPT_MAX_PROTOCOL_DRIVERS; static u8 mptsasInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; /* Used only for internal commands */ static u8 mptsasMgmtCtx = MPT_MAX_PROTOCOL_DRIVERS; +static u8 mptsasDeviceResetCtx = MPT_MAX_PROTOCOL_DRIVERS; -static void mptsas_hotplug_work(struct work_struct *work); +static void mptsas_firmware_event_work(struct work_struct *work); +static void mptsas_send_sas_event(struct fw_event_work *fw_event); +static void mptsas_send_raid_event(struct fw_event_work *fw_event); +static void mptsas_send_ir2_event(struct fw_event_work *fw_event); +static void mptsas_parse_device_info(struct sas_identify *identify, + struct mptsas_devinfo *device_info); +static inline void mptsas_set_rphy(MPT_ADAPTER *ioc, + struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy); +static struct mptsas_phyinfo *mptsas_find_phyinfo_by_sas_address + (MPT_ADAPTER *ioc, u64 sas_address); +static int mptsas_sas_device_pg0(MPT_ADAPTER *ioc, + struct mptsas_devinfo *device_info, u32 form, u32 form_specific); +static int mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, + struct mptsas_enclosure *enclosure, u32 form, u32 form_specific); +static int mptsas_add_end_device(MPT_ADAPTER *ioc, + struct mptsas_phyinfo *phy_info); +static void mptsas_del_end_device(MPT_ADAPTER *ioc, + struct mptsas_phyinfo *phy_info); +static void mptsas_send_link_status_event(struct fw_event_work *fw_event); +static struct mptsas_portinfo *mptsas_find_portinfo_by_sas_address + (MPT_ADAPTER *ioc, u64 sas_address); +static void mptsas_expander_delete(MPT_ADAPTER *ioc, + struct mptsas_portinfo *port_info, u8 force); +static void mptsas_send_expander_event(struct fw_event_work *fw_event); +static void mptsas_not_responding_devices(MPT_ADAPTER *ioc); +static void mptsas_scan_sas_topology(MPT_ADAPTER *ioc); +static void mptsas_broadcast_primative_work(struct fw_event_work *fw_event); +static void mptsas_handle_queue_full_event(struct fw_event_work *fw_event); +static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id); static void mptsas_print_phy_data(MPT_ADAPTER *ioc, MPI_SAS_IO_UNIT0_PHY_DATA *phy_data) @@ -218,6 +247,115 @@ static void mptsas_print_expander_pg1(MPT_ADAPTER *ioc, SasExpanderPage1_t *pg1) le16_to_cpu(pg1->AttachedDevHandle))); } +/* inhibit sas firmware event handling */ +static void +mptsas_fw_event_off(MPT_ADAPTER *ioc) +{ + unsigned long flags; + + spin_lock_irqsave(&ioc->fw_event_lock, flags); + ioc->fw_events_off = 1; + ioc->sas_discovery_quiesce_io = 0; + spin_unlock_irqrestore(&ioc->fw_event_lock, flags); + +} + +/* enable sas firmware event handling */ +static void +mptsas_fw_event_on(MPT_ADAPTER *ioc) +{ + unsigned long flags; + + spin_lock_irqsave(&ioc->fw_event_lock, flags); + ioc->fw_events_off = 0; + spin_unlock_irqrestore(&ioc->fw_event_lock, flags); +} + +/* queue a sas firmware event */ +static void +mptsas_add_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event, + unsigned long delay) +{ + unsigned long flags; + + spin_lock_irqsave(&ioc->fw_event_lock, flags); + list_add_tail(&fw_event->list, &ioc->fw_event_list); + INIT_DELAYED_WORK(&fw_event->work, mptsas_firmware_event_work); + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: add (fw_event=0x%p)\n", + ioc->name, __func__, fw_event)); + queue_delayed_work(ioc->fw_event_q, &fw_event->work, + delay); + spin_unlock_irqrestore(&ioc->fw_event_lock, flags); +} + +/* requeue a sas firmware event */ +static void +mptsas_requeue_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event, + unsigned long delay) +{ + unsigned long flags; + spin_lock_irqsave(&ioc->fw_event_lock, flags); + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: reschedule task " + "(fw_event=0x%p)\n", ioc->name, __func__, fw_event)); + fw_event->retries++; + queue_delayed_work(ioc->fw_event_q, &fw_event->work, + msecs_to_jiffies(delay)); + spin_unlock_irqrestore(&ioc->fw_event_lock, flags); +} + +/* free memory assoicated to a sas firmware event */ +static void +mptsas_free_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event) +{ + unsigned long flags; + + spin_lock_irqsave(&ioc->fw_event_lock, flags); + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: kfree (fw_event=0x%p)\n", + ioc->name, __func__, fw_event)); + list_del(&fw_event->list); + kfree(fw_event); + spin_unlock_irqrestore(&ioc->fw_event_lock, flags); +} + +/* walk the firmware event queue, and either stop or wait for + * outstanding events to complete */ +static void +mptsas_cleanup_fw_event_q(MPT_ADAPTER *ioc) +{ + struct fw_event_work *fw_event, *next; + struct mptsas_target_reset_event *target_reset_list, *n; + u8 flush_q; + MPT_SCSI_HOST *hd = shost_priv(ioc->sh); + + /* flush the target_reset_list */ + if (!list_empty(&hd->target_reset_list)) { + list_for_each_entry_safe(target_reset_list, n, + &hd->target_reset_list, list) { + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: removing target reset for id=%d\n", + ioc->name, __func__, + target_reset_list->sas_event_data.TargetID)); + list_del(&target_reset_list->list); + kfree(target_reset_list); + } + } + + if (list_empty(&ioc->fw_event_list) || + !ioc->fw_event_q || in_interrupt()) + return; + + flush_q = 0; + list_for_each_entry_safe(fw_event, next, &ioc->fw_event_list, list) { + if (cancel_delayed_work(&fw_event->work)) + mptsas_free_fw_event(ioc, fw_event); + else + flush_q = 1; + } + if (flush_q) + flush_workqueue(ioc->fw_event_q); +} + + static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy) { struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); @@ -230,20 +368,6 @@ static inline MPT_ADAPTER *rphy_to_ioc(struct sas_rphy *rphy) return ((MPT_SCSI_HOST *)shost->hostdata)->ioc; } -static struct mptsas_portinfo * -mptsas_get_hba_portinfo(MPT_ADAPTER *ioc) -{ - struct list_head *head = &ioc->sas_topology; - struct mptsas_portinfo *pi = NULL; - - /* always the first entry on sas_topology list */ - - if (!list_empty(head)) - pi = list_entry(head->next, struct mptsas_portinfo, list); - - return pi; -} - /* * mptsas_find_portinfo_by_handle * @@ -265,6 +389,38 @@ mptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle) return rc; } +/** + * mptsas_find_portinfo_by_sas_address - + * @ioc: Pointer to MPT_ADAPTER structure + * @handle: + * + * This function should be called with the sas_topology_mutex already held + * + **/ +static struct mptsas_portinfo * +mptsas_find_portinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address) +{ + struct mptsas_portinfo *port_info, *rc = NULL; + int i; + + if (sas_address >= ioc->hba_port_sas_addr && + sas_address < (ioc->hba_port_sas_addr + + ioc->hba_port_num_phy)) + return ioc->hba_port_info; + + mutex_lock(&ioc->sas_topology_mutex); + list_for_each_entry(port_info, &ioc->sas_topology, list) + for (i = 0; i < port_info->num_phys; i++) + if (port_info->phy_info[i].identify.sas_address == + sas_address) { + rc = port_info; + goto out; + } + out: + mutex_unlock(&ioc->sas_topology_mutex); + return rc; +} + /* * Returns true if there is a scsi end device */ @@ -308,6 +464,7 @@ mptsas_port_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo_details * port_detai if(phy_info->port_details != port_details) continue; memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo)); + mptsas_set_rphy(ioc, phy_info, NULL); phy_info->port_details = NULL; } kfree(port_details); @@ -379,6 +536,285 @@ starget) phy_info->port_details->starget = starget; } +/** + * mptsas_add_device_component - + * @ioc: Pointer to MPT_ADAPTER structure + * @channel: fw mapped id's + * @id: + * @sas_address: + * @device_info: + * + **/ +static void +mptsas_add_device_component(MPT_ADAPTER *ioc, u8 channel, u8 id, + u64 sas_address, u32 device_info, u16 slot, u64 enclosure_logical_id) +{ + struct mptsas_device_info *sas_info, *next; + struct scsi_device *sdev; + struct scsi_target *starget; + struct sas_rphy *rphy; + + /* + * Delete all matching devices out of the list + */ + mutex_lock(&ioc->sas_device_info_mutex); + list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list, + list) { + if (!sas_info->is_logical_volume && + (sas_info->sas_address == sas_address || + (sas_info->fw.channel == channel && + sas_info->fw.id == id))) { + list_del(&sas_info->list); + kfree(sas_info); + } + } + + sas_info = kzalloc(sizeof(struct mptsas_device_info), GFP_KERNEL); + if (!sas_info) + goto out; + + /* + * Set Firmware mapping + */ + sas_info->fw.id = id; + sas_info->fw.channel = channel; + + sas_info->sas_address = sas_address; + sas_info->device_info = device_info; + sas_info->slot = slot; + sas_info->enclosure_logical_id = enclosure_logical_id; + INIT_LIST_HEAD(&sas_info->list); + list_add_tail(&sas_info->list, &ioc->sas_device_info_list); + + /* + * Set OS mapping + */ + shost_for_each_device(sdev, ioc->sh) { + starget = scsi_target(sdev); + rphy = dev_to_rphy(starget->dev.parent); + if (rphy->identify.sas_address == sas_address) { + sas_info->os.id = starget->id; + sas_info->os.channel = starget->channel; + } + } + + out: + mutex_unlock(&ioc->sas_device_info_mutex); + return; +} + +/** + * mptsas_add_device_component_by_fw - + * @ioc: Pointer to MPT_ADAPTER structure + * @channel: fw mapped id's + * @id: + * + **/ +static void +mptsas_add_device_component_by_fw(MPT_ADAPTER *ioc, u8 channel, u8 id) +{ + struct mptsas_devinfo sas_device; + struct mptsas_enclosure enclosure_info; + int rc; + + rc = mptsas_sas_device_pg0(ioc, &sas_device, + (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << + MPI_SAS_DEVICE_PGAD_FORM_SHIFT), + (channel << 8) + id); + if (rc) + return; + + memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure)); + mptsas_sas_enclosure_pg0(ioc, &enclosure_info, + (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE << + MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), + sas_device.handle_enclosure); + + mptsas_add_device_component(ioc, sas_device.channel, + sas_device.id, sas_device.sas_address, sas_device.device_info, + sas_device.slot, enclosure_info.enclosure_logical_id); +} + +/** + * mptsas_add_device_component_starget_ir - Handle Integrated RAID, adding each individual device to list + * @ioc: Pointer to MPT_ADAPTER structure + * @channel: fw mapped id's + * @id: + * + **/ +static void +mptsas_add_device_component_starget_ir(MPT_ADAPTER *ioc, + struct scsi_target *starget) +{ + CONFIGPARMS cfg; + ConfigPageHeader_t hdr; + dma_addr_t dma_handle; + pRaidVolumePage0_t buffer = NULL; + int i; + RaidPhysDiskPage0_t phys_disk; + struct mptsas_device_info *sas_info, *next; + + memset(&cfg, 0 , sizeof(CONFIGPARMS)); + memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); + hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME; + /* assumption that all volumes on channel = 0 */ + cfg.pageAddr = starget->id; + cfg.cfghdr.hdr = &hdr; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + cfg.timeout = 10; + + if (mpt_config(ioc, &cfg) != 0) + goto out; + + if (!hdr.PageLength) + goto out; + + buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, + &dma_handle); + + if (!buffer) + goto out; + + cfg.physAddr = dma_handle; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + + if (mpt_config(ioc, &cfg) != 0) + goto out; + + if (!buffer->NumPhysDisks) + goto out; + + /* + * Adding entry for hidden components + */ + for (i = 0; i < buffer->NumPhysDisks; i++) { + + if (mpt_raid_phys_disk_pg0(ioc, + buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0) + continue; + + mptsas_add_device_component_by_fw(ioc, phys_disk.PhysDiskBus, + phys_disk.PhysDiskID); + + mutex_lock(&ioc->sas_device_info_mutex); + list_for_each_entry(sas_info, &ioc->sas_device_info_list, + list) { + if (!sas_info->is_logical_volume && + (sas_info->fw.channel == phys_disk.PhysDiskBus && + sas_info->fw.id == phys_disk.PhysDiskID)) { + sas_info->is_hidden_raid_component = 1; + sas_info->volume_id = starget->id; + } + } + mutex_unlock(&ioc->sas_device_info_mutex); + + } + + /* + * Delete all matching devices out of the list + */ + mutex_lock(&ioc->sas_device_info_mutex); + list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list, + list) { + if (sas_info->is_logical_volume && sas_info->fw.id == + starget->id) { + list_del(&sas_info->list); + kfree(sas_info); + } + } + + sas_info = kzalloc(sizeof(struct mptsas_device_info), GFP_KERNEL); + if (sas_info) { + sas_info->fw.id = starget->id; + sas_info->os.id = starget->id; + sas_info->os.channel = starget->channel; + sas_info->is_logical_volume = 1; + INIT_LIST_HEAD(&sas_info->list); + list_add_tail(&sas_info->list, &ioc->sas_device_info_list); + } + mutex_unlock(&ioc->sas_device_info_mutex); + + out: + if (buffer) + pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer, + dma_handle); +} + +/** + * mptsas_add_device_component_starget - + * @ioc: Pointer to MPT_ADAPTER structure + * @starget: + * + **/ +static void +mptsas_add_device_component_starget(MPT_ADAPTER *ioc, + struct scsi_target *starget) +{ + VirtTarget *vtarget; + struct sas_rphy *rphy; + struct mptsas_phyinfo *phy_info = NULL; + struct mptsas_enclosure enclosure_info; + + rphy = dev_to_rphy(starget->dev.parent); + vtarget = starget->hostdata; + phy_info = mptsas_find_phyinfo_by_sas_address(ioc, + rphy->identify.sas_address); + if (!phy_info) + return; + + memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure)); + mptsas_sas_enclosure_pg0(ioc, &enclosure_info, + (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE << + MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), + phy_info->attached.handle_enclosure); + + mptsas_add_device_component(ioc, phy_info->attached.channel, + phy_info->attached.id, phy_info->attached.sas_address, + phy_info->attached.device_info, + phy_info->attached.slot, enclosure_info.enclosure_logical_id); +} + +/** + * mptsas_del_device_component_by_os - Once a device has been removed, we mark the entry in the list as being cached + * @ioc: Pointer to MPT_ADAPTER structure + * @channel: os mapped id's + * @id: + * + **/ +static void +mptsas_del_device_component_by_os(MPT_ADAPTER *ioc, u8 channel, u8 id) +{ + struct mptsas_device_info *sas_info, *next; + + /* + * Set is_cached flag + */ + list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list, + list) { + if (sas_info->os.channel == channel && sas_info->os.id == id) + sas_info->is_cached = 1; + } +} + +/** + * mptsas_del_device_components - Cleaning the list + * @ioc: Pointer to MPT_ADAPTER structure + * + **/ +static void +mptsas_del_device_components(MPT_ADAPTER *ioc) +{ + struct mptsas_device_info *sas_info, *next; + + mutex_lock(&ioc->sas_device_info_mutex); + list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list, + list) { + list_del(&sas_info->list); + kfree(sas_info); + } + mutex_unlock(&ioc->sas_device_info_mutex); +} + /* * mptsas_setup_wide_ports @@ -434,8 +870,8 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) * Forming a port */ if (!port_details) { - port_details = kzalloc(sizeof(*port_details), - GFP_KERNEL); + port_details = kzalloc(sizeof(struct + mptsas_portinfo_details), GFP_KERNEL); if (!port_details) goto out; port_details->num_phys = 1; @@ -523,15 +959,62 @@ mptsas_find_vtarget(MPT_ADAPTER *ioc, u8 channel, u8 id) VirtTarget *vtarget = NULL; shost_for_each_device(sdev, ioc->sh) { - if ((vdevice = sdev->hostdata) == NULL) + vdevice = sdev->hostdata; + if ((vdevice == NULL) || + (vdevice->vtarget == NULL)) + continue; + if ((vdevice->vtarget->tflags & + MPT_TARGET_FLAGS_RAID_COMPONENT || + vdevice->vtarget->raidVolume)) continue; if (vdevice->vtarget->id == id && - vdevice->vtarget->channel == channel) + vdevice->vtarget->channel == channel) vtarget = vdevice->vtarget; } return vtarget; } +static void +mptsas_queue_device_delete(MPT_ADAPTER *ioc, + MpiEventDataSasDeviceStatusChange_t *sas_event_data) +{ + struct fw_event_work *fw_event; + int sz; + + sz = offsetof(struct fw_event_work, event_data) + + sizeof(MpiEventDataSasDeviceStatusChange_t); + fw_event = kzalloc(sz, GFP_ATOMIC); + if (!fw_event) { + printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", + ioc->name, __func__, __LINE__); + return; + } + memcpy(fw_event->event_data, sas_event_data, + sizeof(MpiEventDataSasDeviceStatusChange_t)); + fw_event->event = MPI_EVENT_SAS_DEVICE_STATUS_CHANGE; + fw_event->ioc = ioc; + mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1)); +} + +static void +mptsas_queue_rescan(MPT_ADAPTER *ioc) +{ + struct fw_event_work *fw_event; + int sz; + + sz = offsetof(struct fw_event_work, event_data); + fw_event = kzalloc(sz, GFP_ATOMIC); + if (!fw_event) { + printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", + ioc->name, __func__, __LINE__); + return; + } + fw_event->event = -1; + fw_event->ioc = ioc; + mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1)); +} + + /** * mptsas_target_reset * @@ -550,13 +1033,21 @@ mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id) { MPT_FRAME_HDR *mf; SCSITaskMgmt_t *pScsiTm; - - if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) { - dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames @%d!!\n", - ioc->name,__func__, __LINE__)); + if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) return 0; + + + mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc); + if (mf == NULL) { + dfailprintk(ioc, printk(MYIOC_s_WARN_FMT + "%s, no msg frames @%d!!\n", ioc->name, + __func__, __LINE__)); + goto out_fail; } + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n", + ioc->name, mf)); + /* Format the Request */ pScsiTm = (SCSITaskMgmt_t *) mf; @@ -569,9 +1060,18 @@ mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id) DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf); - mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf); + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "TaskMgmt type=%d (sas device delete) fw_channel = %d fw_id = %d)\n", + ioc->name, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, channel, id)); + + mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf); return 1; + + out_fail: + + mpt_clear_taskmgmt_in_progress_flag(ioc); + return 0; } /** @@ -602,11 +1102,12 @@ mptsas_target_reset_queue(MPT_ADAPTER *ioc, vtarget->deleted = 1; /* block IO */ - target_reset_list = kzalloc(sizeof(*target_reset_list), + target_reset_list = kzalloc(sizeof(struct mptsas_target_reset_event), GFP_ATOMIC); if (!target_reset_list) { - dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n", - ioc->name,__func__, __LINE__)); + dfailprintk(ioc, printk(MYIOC_s_WARN_FMT + "%s, failed to allocate mem @%d..!!\n", + ioc->name, __func__, __LINE__)); return; } @@ -614,84 +1115,101 @@ mptsas_target_reset_queue(MPT_ADAPTER *ioc, sizeof(*sas_event_data)); list_add_tail(&target_reset_list->list, &hd->target_reset_list); - if (hd->resetPending) - return; + target_reset_list->time_count = jiffies; if (mptsas_target_reset(ioc, channel, id)) { target_reset_list->target_reset_issued = 1; - hd->resetPending = 1; } } /** - * mptsas_dev_reset_complete - * - * Completion for TARGET_RESET after NOT_RESPONDING_EVENT, - * enable work queue to finish off removing device from upper layers. - * then send next TARGET_RESET in the queue. - * - * @ioc + * mptsas_taskmgmt_complete - complete SAS task management function + * @ioc: Pointer to MPT_ADAPTER structure * + * Completion for TARGET_RESET after NOT_RESPONDING_EVENT, enable work + * queue to finish off removing device from upper layers. then send next + * TARGET_RESET in the queue. **/ -static void -mptsas_dev_reset_complete(MPT_ADAPTER *ioc) +static int +mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) { MPT_SCSI_HOST *hd = shost_priv(ioc->sh); struct list_head *head = &hd->target_reset_list; - struct mptsas_target_reset_event *target_reset_list; - struct mptsas_hotplug_event *ev; - EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data; u8 id, channel; - __le64 sas_address; + struct mptsas_target_reset_event *target_reset_list; + SCSITaskMgmtReply_t *pScsiTmReply; + + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed: " + "(mf = %p, mr = %p)\n", ioc->name, mf, mr)); + + pScsiTmReply = (SCSITaskMgmtReply_t *)mr; + if (pScsiTmReply) { + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "\tTaskMgmt completed: fw_channel = %d, fw_id = %d,\n" + "\ttask_type = 0x%02X, iocstatus = 0x%04X " + "loginfo = 0x%08X,\n\tresponse_code = 0x%02X, " + "term_cmnds = %d\n", ioc->name, + pScsiTmReply->Bus, pScsiTmReply->TargetID, + pScsiTmReply->TaskType, + le16_to_cpu(pScsiTmReply->IOCStatus), + le32_to_cpu(pScsiTmReply->IOCLogInfo), + pScsiTmReply->ResponseCode, + le32_to_cpu(pScsiTmReply->TerminationCount))); + + if (pScsiTmReply->ResponseCode) + mptscsih_taskmgmt_response_code(ioc, + pScsiTmReply->ResponseCode); + } + + if (pScsiTmReply && (pScsiTmReply->TaskType == + MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK || pScsiTmReply->TaskType == + MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET)) { + ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD; + ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID; + memcpy(ioc->taskmgmt_cmds.reply, mr, + min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength)); + if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) { + ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING; + complete(&ioc->taskmgmt_cmds.done); + return 1; + } + return 0; + } + + mpt_clear_taskmgmt_in_progress_flag(ioc); if (list_empty(head)) - return; + return 1; - target_reset_list = list_entry(head->next, struct mptsas_target_reset_event, list); + target_reset_list = list_entry(head->next, + struct mptsas_target_reset_event, list); - sas_event_data = &target_reset_list->sas_event_data; - id = sas_event_data->TargetID; - channel = sas_event_data->Bus; - hd->resetPending = 0; + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "TaskMgmt: completed (%d seconds)\n", + ioc->name, jiffies_to_msecs(jiffies - + target_reset_list->time_count)/1000)); + + id = pScsiTmReply->TargetID; + channel = pScsiTmReply->Bus; + target_reset_list->time_count = jiffies; /* * retry target reset */ if (!target_reset_list->target_reset_issued) { - if (mptsas_target_reset(ioc, channel, id)) { + if (mptsas_target_reset(ioc, channel, id)) target_reset_list->target_reset_issued = 1; - hd->resetPending = 1; - } - return; + return 1; } /* * enable work queue to remove device from upper layers */ list_del(&target_reset_list->list); + if ((mptsas_find_vtarget(ioc, channel, id)) && !ioc->fw_events_off) + mptsas_queue_device_delete(ioc, + &target_reset_list->sas_event_data); - ev = kzalloc(sizeof(*ev), GFP_ATOMIC); - if (!ev) { - dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n", - ioc->name,__func__, __LINE__)); - return; - } - - INIT_WORK(&ev->work, mptsas_hotplug_work); - ev->ioc = ioc; - ev->handle = le16_to_cpu(sas_event_data->DevHandle); - ev->parent_handle = - le16_to_cpu(sas_event_data->ParentDevHandle); - ev->channel = channel; - ev->id =id; - ev->phy_id = sas_event_data->PhyNum; - memcpy(&sas_address, &sas_event_data->SASAddress, - sizeof(__le64)); - ev->sas_address = le64_to_cpu(sas_address); - ev->device_info = le32_to_cpu(sas_event_data->DeviceInfo); - ev->event_type = MPTSAS_DEL_DEVICE; - schedule_work(&ev->work); - kfree(target_reset_list); /* * issue target reset to next device in the queue @@ -699,34 +1217,19 @@ mptsas_dev_reset_complete(MPT_ADAPTER *ioc) head = &hd->target_reset_list; if (list_empty(head)) - return; + return 1; target_reset_list = list_entry(head->next, struct mptsas_target_reset_event, list); - sas_event_data = &target_reset_list->sas_event_data; - id = sas_event_data->TargetID; - channel = sas_event_data->Bus; + id = target_reset_list->sas_event_data.TargetID; + channel = target_reset_list->sas_event_data.Bus; + target_reset_list->time_count = jiffies; - if (mptsas_target_reset(ioc, channel, id)) { + if (mptsas_target_reset(ioc, channel, id)) target_reset_list->target_reset_issued = 1; - hd->resetPending = 1; - } -} -/** - * mptsas_taskmgmt_complete - * - * @ioc - * @mf - * @mr - * - **/ -static int -mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) -{ - mptsas_dev_reset_complete(ioc); - return mptscsih_taskmgmt_complete(ioc, mf, mr); + return 1; } /** @@ -740,37 +1243,59 @@ static int mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) { MPT_SCSI_HOST *hd; - struct mptsas_target_reset_event *target_reset_list, *n; int rc; rc = mptscsih_ioc_reset(ioc, reset_phase); + if ((ioc->bus_type != SAS) || (!rc)) + return rc; - if (ioc->bus_type != SAS) - goto out; - - if (reset_phase != MPT_IOC_POST_RESET) - goto out; - - if (!ioc->sh || !ioc->sh->hostdata) - goto out; hd = shost_priv(ioc->sh); if (!hd->ioc) goto out; - if (list_empty(&hd->target_reset_list)) - goto out; - - /* flush the target_reset_list */ - list_for_each_entry_safe(target_reset_list, n, - &hd->target_reset_list, list) { - list_del(&target_reset_list->list); - kfree(target_reset_list); + switch (reset_phase) { + case MPT_IOC_SETUP_RESET: + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__)); + mptsas_fw_event_off(ioc); + break; + case MPT_IOC_PRE_RESET: + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__)); + break; + case MPT_IOC_POST_RESET: + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__)); + if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) { + ioc->sas_mgmt.status |= MPT_MGMT_STATUS_DID_IOCRESET; + complete(&ioc->sas_mgmt.done); + } + mptsas_cleanup_fw_event_q(ioc); + mptsas_queue_rescan(ioc); + mptsas_fw_event_on(ioc); + break; + default: + break; } out: return rc; } + +/** + * enum device_state - + * @DEVICE_RETRY: need to retry the TUR + * @DEVICE_ERROR: TUR return error, don't add device + * @DEVICE_READY: device can be added + * + */ +enum device_state{ + DEVICE_RETRY, + DEVICE_ERROR, + DEVICE_READY, +}; + static int mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure, u32 form, u32 form_specific) @@ -836,15 +1361,308 @@ mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure, return error; } +/** + * mptsas_add_end_device - report a new end device to sas transport layer + * @ioc: Pointer to MPT_ADAPTER structure + * @phy_info: decribes attached device + * + * return (0) success (1) failure + * + **/ +static int +mptsas_add_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info) +{ + struct sas_rphy *rphy; + struct sas_port *port; + struct sas_identify identify; + char *ds = NULL; + u8 fw_id; + + if (!phy_info) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: exit at line=%d\n", ioc->name, + __func__, __LINE__)); + return 1; + } + + fw_id = phy_info->attached.id; + + if (mptsas_get_rphy(phy_info)) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: fw_id=%d exit at line=%d\n", ioc->name, + __func__, fw_id, __LINE__)); + return 2; + } + + port = mptsas_get_port(phy_info); + if (!port) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: fw_id=%d exit at line=%d\n", ioc->name, + __func__, fw_id, __LINE__)); + return 3; + } + + if (phy_info->attached.device_info & + MPI_SAS_DEVICE_INFO_SSP_TARGET) + ds = "ssp"; + if (phy_info->attached.device_info & + MPI_SAS_DEVICE_INFO_STP_TARGET) + ds = "stp"; + if (phy_info->attached.device_info & + MPI_SAS_DEVICE_INFO_SATA_DEVICE) + ds = "sata"; + + printk(MYIOC_s_INFO_FMT "attaching %s device: fw_channel %d, fw_id %d," + " phy %d, sas_addr 0x%llx\n", ioc->name, ds, + phy_info->attached.channel, phy_info->attached.id, + phy_info->attached.phy_id, (unsigned long long) + phy_info->attached.sas_address); + + mptsas_parse_device_info(&identify, &phy_info->attached); + rphy = sas_end_device_alloc(port); + if (!rphy) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: fw_id=%d exit at line=%d\n", ioc->name, + __func__, fw_id, __LINE__)); + return 5; /* non-fatal: an rphy can be added later */ + } + + rphy->identify = identify; + if (sas_rphy_add(rphy)) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: fw_id=%d exit at line=%d\n", ioc->name, + __func__, fw_id, __LINE__)); + sas_rphy_free(rphy); + return 6; + } + mptsas_set_rphy(ioc, phy_info, rphy); + return 0; +} + +/** + * mptsas_del_end_device - report a deleted end device to sas transport layer + * @ioc: Pointer to MPT_ADAPTER structure + * @phy_info: decribes attached device + * + **/ +static void +mptsas_del_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info) +{ + struct sas_rphy *rphy; + struct sas_port *port; + struct mptsas_portinfo *port_info; + struct mptsas_phyinfo *phy_info_parent; + int i; + char *ds = NULL; + u8 fw_id; + u64 sas_address; + + if (!phy_info) + return; + + fw_id = phy_info->attached.id; + sas_address = phy_info->attached.sas_address; + + if (!phy_info->port_details) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: fw_id=%d exit at line=%d\n", ioc->name, + __func__, fw_id, __LINE__)); + return; + } + rphy = mptsas_get_rphy(phy_info); + if (!rphy) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: fw_id=%d exit at line=%d\n", ioc->name, + __func__, fw_id, __LINE__)); + return; + } + + if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_INITIATOR + || phy_info->attached.device_info + & MPI_SAS_DEVICE_INFO_SMP_INITIATOR + || phy_info->attached.device_info + & MPI_SAS_DEVICE_INFO_STP_INITIATOR) + ds = "initiator"; + if (phy_info->attached.device_info & + MPI_SAS_DEVICE_INFO_SSP_TARGET) + ds = "ssp"; + if (phy_info->attached.device_info & + MPI_SAS_DEVICE_INFO_STP_TARGET) + ds = "stp"; + if (phy_info->attached.device_info & + MPI_SAS_DEVICE_INFO_SATA_DEVICE) + ds = "sata"; + + dev_printk(KERN_DEBUG, &rphy->dev, MYIOC_s_FMT + "removing %s device: fw_channel %d, fw_id %d, phy %d," + "sas_addr 0x%llx\n", ioc->name, ds, phy_info->attached.channel, + phy_info->attached.id, phy_info->attached.phy_id, + (unsigned long long) sas_address); + + port = mptsas_get_port(phy_info); + if (!port) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: fw_id=%d exit at line=%d\n", ioc->name, + __func__, fw_id, __LINE__)); + return; + } + port_info = phy_info->portinfo; + phy_info_parent = port_info->phy_info; + for (i = 0; i < port_info->num_phys; i++, phy_info_parent++) { + if (!phy_info_parent->phy) + continue; + if (phy_info_parent->attached.sas_address != + sas_address) + continue; + dev_printk(KERN_DEBUG, &phy_info_parent->phy->dev, + MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n", + ioc->name, phy_info_parent->phy_id, + phy_info_parent->phy); + sas_port_delete_phy(port, phy_info_parent->phy); + } + + dev_printk(KERN_DEBUG, &port->dev, MYIOC_s_FMT + "delete port %d, sas_addr (0x%llx)\n", ioc->name, + port->port_identifier, (unsigned long long)sas_address); + sas_port_delete(port); + mptsas_set_port(ioc, phy_info, NULL); + mptsas_port_delete(ioc, phy_info->port_details); +} + +struct mptsas_phyinfo * +mptsas_refreshing_device_handles(MPT_ADAPTER *ioc, + struct mptsas_devinfo *sas_device) +{ + struct mptsas_phyinfo *phy_info; + struct mptsas_portinfo *port_info; + int i; + + phy_info = mptsas_find_phyinfo_by_sas_address(ioc, + sas_device->sas_address); + if (!phy_info) + goto out; + port_info = phy_info->portinfo; + if (!port_info) + goto out; + mutex_lock(&ioc->sas_topology_mutex); + for (i = 0; i < port_info->num_phys; i++) { + if (port_info->phy_info[i].attached.sas_address != + sas_device->sas_address) + continue; + port_info->phy_info[i].attached.channel = sas_device->channel; + port_info->phy_info[i].attached.id = sas_device->id; + port_info->phy_info[i].attached.sas_address = + sas_device->sas_address; + port_info->phy_info[i].attached.handle = sas_device->handle; + port_info->phy_info[i].attached.handle_parent = + sas_device->handle_parent; + port_info->phy_info[i].attached.handle_enclosure = + sas_device->handle_enclosure; + } + mutex_unlock(&ioc->sas_topology_mutex); + out: + return phy_info; +} + +/** + * mptsas_firmware_event_work - work thread for processing fw events + * @work: work queue payload containing info describing the event + * Context: user + * + */ +static void +mptsas_firmware_event_work(struct work_struct *work) +{ + struct fw_event_work *fw_event = + container_of(work, struct fw_event_work, work.work); + MPT_ADAPTER *ioc = fw_event->ioc; + + /* special rescan topology handling */ + if (fw_event->event == -1) { + if (ioc->in_rescan) { + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: rescan ignored as it is in progress\n", + ioc->name, __func__)); + return; + } + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: rescan after " + "reset\n", ioc->name, __func__)); + ioc->in_rescan = 1; + mptsas_not_responding_devices(ioc); + mptsas_scan_sas_topology(ioc); + ioc->in_rescan = 0; + mptsas_free_fw_event(ioc, fw_event); + return; + } + + /* events handling turned off during host reset */ + if (ioc->fw_events_off) { + mptsas_free_fw_event(ioc, fw_event); + return; + } + + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: fw_event=(0x%p), " + "event = (0x%02x)\n", ioc->name, __func__, fw_event, + (fw_event->event & 0xFF))); + + switch (fw_event->event) { + case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: + mptsas_send_sas_event(fw_event); + break; + case MPI_EVENT_INTEGRATED_RAID: + mptsas_send_raid_event(fw_event); + break; + case MPI_EVENT_IR2: + mptsas_send_ir2_event(fw_event); + break; + case MPI_EVENT_PERSISTENT_TABLE_FULL: + mptbase_sas_persist_operation(ioc, + MPI_SAS_OP_CLEAR_NOT_PRESENT); + mptsas_free_fw_event(ioc, fw_event); + break; + case MPI_EVENT_SAS_BROADCAST_PRIMITIVE: + mptsas_broadcast_primative_work(fw_event); + break; + case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE: + mptsas_send_expander_event(fw_event); + break; + case MPI_EVENT_SAS_PHY_LINK_STATUS: + mptsas_send_link_status_event(fw_event); + break; + case MPI_EVENT_QUEUE_FULL: + mptsas_handle_queue_full_event(fw_event); + break; + } +} + + + static int mptsas_slave_configure(struct scsi_device *sdev) { + struct Scsi_Host *host = sdev->host; + MPT_SCSI_HOST *hd = shost_priv(host); + MPT_ADAPTER *ioc = hd->ioc; + VirtDevice *vdevice = sdev->hostdata; - if (sdev->channel == MPTSAS_RAID_CHANNEL) + if (vdevice->vtarget->deleted) { + sdev_printk(KERN_INFO, sdev, "clearing deleted flag\n"); + vdevice->vtarget->deleted = 0; + } + + /* + * RAID volumes placed beyond the last expected port. + * Ignore sending sas mode pages in that case.. + */ + if (sdev->channel == MPTSAS_RAID_CHANNEL) { + mptsas_add_device_component_starget_ir(ioc, scsi_target(sdev)); goto out; + } sas_read_port_mode_page(sdev); + mptsas_add_device_component_starget(ioc, scsi_target(sdev)); + out: return mptscsih_slave_configure(sdev); } @@ -875,9 +1693,18 @@ mptsas_target_alloc(struct scsi_target *starget) * RAID volumes placed beyond the last expected port. */ if (starget->channel == MPTSAS_RAID_CHANNEL) { - for (i=0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) - if (id == ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID) - channel = ioc->raid_data.pIocPg2->RaidVolume[i].VolumeBus; + if (!ioc->raid_data.pIocPg2) { + kfree(vtarget); + return -ENXIO; + } + for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) { + if (id == ioc->raid_data.pIocPg2-> + RaidVolume[i].VolumeID) { + channel = ioc->raid_data.pIocPg2-> + RaidVolume[i].VolumeBus; + } + } + vtarget->raidVolume = 1; goto out; } @@ -926,11 +1753,18 @@ mptsas_target_destroy(struct scsi_target *starget) struct sas_rphy *rphy; struct mptsas_portinfo *p; int i; - MPT_ADAPTER *ioc = hd->ioc; + MPT_ADAPTER *ioc = hd->ioc; + VirtTarget *vtarget; if (!starget->hostdata) return; + vtarget = starget->hostdata; + + mptsas_del_device_component_by_os(ioc, starget->channel, + starget->id); + + if (starget->channel == MPTSAS_RAID_CHANNEL) goto out; @@ -940,12 +1774,21 @@ mptsas_target_destroy(struct scsi_target *starget) if (p->phy_info[i].attached.sas_address != rphy->identify.sas_address) continue; + + starget_printk(KERN_INFO, starget, MYIOC_s_FMT + "delete device: fw_channel %d, fw_id %d, phy %d, " + "sas_addr 0x%llx\n", ioc->name, + p->phy_info[i].attached.channel, + p->phy_info[i].attached.id, + p->phy_info[i].attached.phy_id, (unsigned long long) + p->phy_info[i].attached.sas_address); + mptsas_set_starget(&p->phy_info[i], NULL); - goto out; } } out: + vtarget->starget = NULL; kfree(starget->hostdata); starget->hostdata = NULL; } @@ -1008,6 +1851,8 @@ mptsas_slave_alloc(struct scsi_device *sdev) static int mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) { + MPT_SCSI_HOST *hd; + MPT_ADAPTER *ioc; VirtDevice *vdevice = SCpnt->device->hostdata; if (!vdevice || !vdevice->vtarget || vdevice->vtarget->deleted) { @@ -1016,6 +1861,12 @@ mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) return 0; } + hd = shost_priv(SCpnt->device->host); + ioc = hd->ioc; + + if (ioc->sas_discovery_quiesce_io) + return SCSI_MLQUEUE_HOST_BUSY; + // scsi_print_command(SCpnt); return mptscsih_qcmd(SCpnt,done); @@ -1114,14 +1965,19 @@ static int mptsas_get_linkerrors(struct sas_phy *phy) static int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply) { - ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_COMMAND_GOOD; + ioc->sas_mgmt.status |= MPT_MGMT_STATUS_COMMAND_GOOD; if (reply != NULL) { - ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_RF_VALID; + ioc->sas_mgmt.status |= MPT_MGMT_STATUS_RF_VALID; memcpy(ioc->sas_mgmt.reply, reply, min(ioc->reply_sz, 4 * reply->u.reply.MsgLength)); } - complete(&ioc->sas_mgmt.done); - return 1; + + if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) { + ioc->sas_mgmt.status &= ~MPT_MGMT_STATUS_PENDING; + complete(&ioc->sas_mgmt.done); + return 1; + } + return 0; } static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset) @@ -1160,6 +2016,7 @@ static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset) MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET; req->PhyNum = phy->identify.phy_identifier; + INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status) mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf); timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, @@ -1174,7 +2031,7 @@ static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset) /* a reply frame is expected */ if ((ioc->sas_mgmt.status & - MPT_IOCTL_STATUS_RF_VALID) == 0) { + MPT_MGMT_STATUS_RF_VALID) == 0) { error = -ENXIO; goto out_unlock; } @@ -1191,6 +2048,7 @@ static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset) error = 0; out_unlock: + CLEAR_MGMT_STATUS(ioc->sas_mgmt.status) mutex_unlock(&ioc->sas_mgmt.mutex); out: return error; @@ -1277,8 +2135,8 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, /* do we need to support multiple segments? */ if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) { printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u %u, rsp %u %u\n", - ioc->name, __func__, req->bio->bi_vcnt, req->data_len, - rsp->bio->bi_vcnt, rsp->data_len); + ioc->name, __func__, req->bio->bi_vcnt, blk_rq_bytes(req), + rsp->bio->bi_vcnt, blk_rq_bytes(rsp)); return -EINVAL; } @@ -1295,7 +2153,7 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, smpreq = (SmpPassthroughRequest_t *)mf; memset(smpreq, 0, sizeof(*smpreq)); - smpreq->RequestDataLength = cpu_to_le16(req->data_len - 4); + smpreq->RequestDataLength = cpu_to_le16(blk_rq_bytes(req) - 4); smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH; if (rphy) @@ -1304,7 +2162,7 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, struct mptsas_portinfo *port_info; mutex_lock(&ioc->sas_topology_mutex); - port_info = mptsas_get_hba_portinfo(ioc); + port_info = ioc->hba_port_info; if (port_info && port_info->phy_info) sas_address = port_info->phy_info[0].phy->identify.sas_address; @@ -1319,26 +2177,32 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, /* request */ flagsLength = (MPI_SGE_FLAGS_SIMPLE_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER | - MPI_SGE_FLAGS_DIRECTION | - mpt_addr_size()) << MPI_SGE_FLAGS_SHIFT; - flagsLength |= (req->data_len - 4); + MPI_SGE_FLAGS_DIRECTION) + << MPI_SGE_FLAGS_SHIFT; + flagsLength |= (blk_rq_bytes(req) - 4); dma_addr_out = pci_map_single(ioc->pcidev, bio_data(req->bio), - req->data_len, PCI_DMA_BIDIRECTIONAL); + blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL); if (!dma_addr_out) goto put_mf; - mpt_add_sge(psge, flagsLength, dma_addr_out); - psge += (sizeof(u32) + sizeof(dma_addr_t)); + ioc->add_sge(psge, flagsLength, dma_addr_out); + psge += ioc->SGE_size; /* response */ - flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ; - flagsLength |= rsp->data_len + 4; + flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT | + MPI_SGE_FLAGS_SYSTEM_ADDRESS | + MPI_SGE_FLAGS_IOC_TO_HOST | + MPI_SGE_FLAGS_END_OF_BUFFER; + + flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT; + flagsLength |= blk_rq_bytes(rsp) + 4; dma_addr_in = pci_map_single(ioc->pcidev, bio_data(rsp->bio), - rsp->data_len, PCI_DMA_BIDIRECTIONAL); + blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL); if (!dma_addr_in) goto unmap; - mpt_add_sge(psge, flagsLength, dma_addr_in); + ioc->add_sge(psge, flagsLength, dma_addr_in); + INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status) mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf); timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ); @@ -1351,30 +2215,32 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, } mf = NULL; - if (ioc->sas_mgmt.status & MPT_IOCTL_STATUS_RF_VALID) { + if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) { SmpPassthroughReply_t *smprep; smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply; memcpy(req->sense, smprep, sizeof(*smprep)); req->sense_len = sizeof(*smprep); - req->data_len = 0; - rsp->data_len -= smprep->ResponseDataLength; + req->resid_len = 0; + rsp->resid_len -= smprep->ResponseDataLength; } else { - printk(MYIOC_s_ERR_FMT "%s: smp passthru reply failed to be returned\n", + printk(MYIOC_s_ERR_FMT + "%s: smp passthru reply failed to be returned\n", ioc->name, __func__); ret = -ENXIO; } unmap: if (dma_addr_out) - pci_unmap_single(ioc->pcidev, dma_addr_out, req->data_len, + pci_unmap_single(ioc->pcidev, dma_addr_out, blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL); if (dma_addr_in) - pci_unmap_single(ioc->pcidev, dma_addr_in, rsp->data_len, + pci_unmap_single(ioc->pcidev, dma_addr_in, blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL); put_mf: if (mf) mpt_free_msg_frame(ioc, mf); out_unlock: + CLEAR_MGMT_STATUS(ioc->sas_mgmt.status) mutex_unlock(&ioc->sas_mgmt.mutex); out: return ret; @@ -1438,7 +2304,7 @@ mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) port_info->num_phys = buffer->NumPhys; port_info->phy_info = kcalloc(port_info->num_phys, - sizeof(*port_info->phy_info),GFP_KERNEL); + sizeof(struct mptsas_phyinfo), GFP_KERNEL); if (!port_info->phy_info) { error = -ENOMEM; goto out_free_consistent; @@ -1600,10 +2466,6 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info, __le64 sas_address; int error=0; - if (ioc->sas_discovery_runtime && - mptsas_is_end_device(device_info)) - goto out; - hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION; hdr.ExtPageLength = 0; hdr.PageNumber = 0; @@ -1644,6 +2506,7 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info, mptsas_print_device_pg0(ioc, buffer); + memset(device_info, 0, sizeof(struct mptsas_devinfo)); device_info->handle = le16_to_cpu(buffer->DevHandle); device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle); device_info->handle_enclosure = @@ -1675,7 +2538,9 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info, SasExpanderPage0_t *buffer; dma_addr_t dma_handle; int i, error; + __le64 sas_address; + memset(port_info, 0, sizeof(struct mptsas_portinfo)); hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION; hdr.ExtPageLength = 0; hdr.PageNumber = 0; @@ -1721,18 +2586,23 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info, } /* save config data */ - port_info->num_phys = buffer->NumPhys; + port_info->num_phys = (buffer->NumPhys) ? buffer->NumPhys : 1; port_info->phy_info = kcalloc(port_info->num_phys, - sizeof(*port_info->phy_info),GFP_KERNEL); + sizeof(struct mptsas_phyinfo), GFP_KERNEL); if (!port_info->phy_info) { error = -ENOMEM; goto out_free_consistent; } + memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64)); for (i = 0; i < port_info->num_phys; i++) { port_info->phy_info[i].portinfo = port_info; port_info->phy_info[i].handle = le16_to_cpu(buffer->DevHandle); + port_info->phy_info[i].identify.sas_address = + le64_to_cpu(sas_address); + port_info->phy_info[i].identify.handle_parent = + le16_to_cpu(buffer->ParentDevHandle); } out_free_consistent: @@ -1752,11 +2622,7 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, dma_addr_t dma_handle; int error=0; - if (ioc->sas_discovery_runtime && - mptsas_is_end_device(&phy_info->attached)) - goto out; - - hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION; + hdr.PageVersion = MPI_SASEXPANDER1_PAGEVERSION; hdr.ExtPageLength = 0; hdr.PageNumber = 1; hdr.Reserved1 = 0; @@ -1791,6 +2657,12 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; error = mpt_config(ioc, &cfg); + + if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) { + error = -ENODEV; + goto out; + } + if (error) goto out_free_consistent; @@ -2010,16 +2882,21 @@ static int mptsas_probe_one_phy(struct device *dev, goto out; } mptsas_set_port(ioc, phy_info, port); - dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "sas_port_alloc: port=%p dev=%p port_id=%d\n", - ioc->name, port, dev, port->port_identifier)); + devtprintk(ioc, dev_printk(KERN_DEBUG, &port->dev, + MYIOC_s_FMT "add port %d, sas_addr (0x%llx)\n", + ioc->name, port->port_identifier, + (unsigned long long)phy_info-> + attached.sas_address)); } - dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_port_add_phy: phy_id=%d\n", - ioc->name, phy_info->phy_id)); + dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "sas_port_add_phy: phy_id=%d\n", + ioc->name, phy_info->phy_id)); sas_port_add_phy(port, phy_info->phy); phy_info->sas_port_add_phy = 0; + devtprintk(ioc, dev_printk(KERN_DEBUG, &phy_info->phy->dev, + MYIOC_s_FMT "add phy %d, phy-obj (0x%p)\n", ioc->name, + phy_info->phy_id, phy_info->phy)); } - if (!mptsas_get_rphy(phy_info) && port && !port->rphy) { struct sas_rphy *rphy; @@ -2032,18 +2909,17 @@ static int mptsas_probe_one_phy(struct device *dev, * the adding/removing of devices that occur * after start of day. */ - if (ioc->sas_discovery_runtime && - mptsas_is_end_device(&phy_info->attached)) - goto out; + if (mptsas_is_end_device(&phy_info->attached) && + phy_info->attached.handle_parent) { + goto out; + } mptsas_parse_device_info(&identify, &phy_info->attached); if (scsi_is_host_device(parent)) { struct mptsas_portinfo *port_info; int i; - mutex_lock(&ioc->sas_topology_mutex); - port_info = mptsas_get_hba_portinfo(ioc); - mutex_unlock(&ioc->sas_topology_mutex); + port_info = ioc->hba_port_info; for (i = 0; i < port_info->num_phys; i++) if (port_info->phy_info[i].identify.sas_address == @@ -2102,7 +2978,7 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc) struct mptsas_portinfo *port_info, *hba; int error = -ENOMEM, i; - hba = kzalloc(sizeof(*port_info), GFP_KERNEL); + hba = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL); if (! hba) goto out; @@ -2112,9 +2988,10 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc) mptsas_sas_io_unit_pg1(ioc); mutex_lock(&ioc->sas_topology_mutex); - port_info = mptsas_get_hba_portinfo(ioc); + port_info = ioc->hba_port_info; if (!port_info) { - port_info = hba; + ioc->hba_port_info = port_info = hba; + ioc->hba_port_num_phy = port_info->num_phys; list_add_tail(&port_info->list, &ioc->sas_topology); } else { for (i = 0; i < hba->num_phys; i++) { @@ -2130,15 +3007,22 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc) hba = NULL; } mutex_unlock(&ioc->sas_topology_mutex); +#if defined(CPQ_CIM) + ioc->num_ports = port_info->num_phys; +#endif for (i = 0; i < port_info->num_phys; i++) { mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i], (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER << MPI_SAS_PHY_PGAD_FORM_SHIFT), i); - + port_info->phy_info[i].identify.handle = + port_info->phy_info[i].handle; mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify, (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << MPI_SAS_DEVICE_PGAD_FORM_SHIFT), - port_info->phy_info[i].handle); + port_info->phy_info[i].identify.handle); + if (!ioc->hba_port_sas_addr) + ioc->hba_port_sas_addr = + port_info->phy_info[i].identify.sas_address; port_info->phy_info[i].identify.phy_id = port_info->phy_info[i].phy_id = i; if (port_info->phy_info[i].attached.handle) @@ -2163,247 +3047,720 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc) return error; } -static int -mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle) +static void +mptsas_expander_refresh(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) { - struct mptsas_portinfo *port_info, *p, *ex; - struct device *parent; - struct sas_rphy *rphy; - int error = -ENOMEM, i, j; - - ex = kzalloc(sizeof(*port_info), GFP_KERNEL); - if (!ex) - goto out; - - error = mptsas_sas_expander_pg0(ioc, ex, - (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE << - MPI_SAS_EXPAND_PGAD_FORM_SHIFT), *handle); - if (error) - goto out_free_port_info; - - *handle = ex->phy_info[0].handle; - - mutex_lock(&ioc->sas_topology_mutex); - port_info = mptsas_find_portinfo_by_handle(ioc, *handle); - if (!port_info) { - port_info = ex; - list_add_tail(&port_info->list, &ioc->sas_topology); - } else { - for (i = 0; i < ex->num_phys; i++) { - port_info->phy_info[i].handle = - ex->phy_info[i].handle; - port_info->phy_info[i].port_id = - ex->phy_info[i].port_id; - } - kfree(ex->phy_info); - kfree(ex); - ex = NULL; - } - mutex_unlock(&ioc->sas_topology_mutex); + struct mptsas_portinfo *parent; + struct device *parent_dev; + struct sas_rphy *rphy; + int i; + u64 sas_address; /* expander sas address */ + u32 handle; + handle = port_info->phy_info[0].handle; + sas_address = port_info->phy_info[0].identify.sas_address; for (i = 0; i < port_info->num_phys; i++) { mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i], - (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM << - MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + *handle); + (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM << + MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + handle); - if (port_info->phy_info[i].identify.handle) { - mptsas_sas_device_pg0(ioc, - &port_info->phy_info[i].identify, - (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << - MPI_SAS_DEVICE_PGAD_FORM_SHIFT), - port_info->phy_info[i].identify.handle); - port_info->phy_info[i].identify.phy_id = - port_info->phy_info[i].phy_id; - } + mptsas_sas_device_pg0(ioc, + &port_info->phy_info[i].identify, + (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << + MPI_SAS_DEVICE_PGAD_FORM_SHIFT), + port_info->phy_info[i].identify.handle); + port_info->phy_info[i].identify.phy_id = + port_info->phy_info[i].phy_id; if (port_info->phy_info[i].attached.handle) { mptsas_sas_device_pg0(ioc, - &port_info->phy_info[i].attached, - (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << - MPI_SAS_DEVICE_PGAD_FORM_SHIFT), - port_info->phy_info[i].attached.handle); + &port_info->phy_info[i].attached, + (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << + MPI_SAS_DEVICE_PGAD_FORM_SHIFT), + port_info->phy_info[i].attached.handle); port_info->phy_info[i].attached.phy_id = port_info->phy_info[i].phy_id; } } - parent = &ioc->sh->shost_gendev; - for (i = 0; i < port_info->num_phys; i++) { - mutex_lock(&ioc->sas_topology_mutex); - list_for_each_entry(p, &ioc->sas_topology, list) { - for (j = 0; j < p->num_phys; j++) { - if (port_info->phy_info[i].identify.handle != - p->phy_info[j].attached.handle) - continue; - rphy = mptsas_get_rphy(&p->phy_info[j]); - parent = &rphy->dev; - } - } + mutex_lock(&ioc->sas_topology_mutex); + parent = mptsas_find_portinfo_by_handle(ioc, + port_info->phy_info[0].identify.handle_parent); + if (!parent) { mutex_unlock(&ioc->sas_topology_mutex); + return; } + for (i = 0, parent_dev = NULL; i < parent->num_phys && !parent_dev; + i++) { + if (parent->phy_info[i].attached.sas_address == sas_address) { + rphy = mptsas_get_rphy(&parent->phy_info[i]); + parent_dev = &rphy->dev; + } + } + mutex_unlock(&ioc->sas_topology_mutex); mptsas_setup_wide_ports(ioc, port_info); - for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++) - mptsas_probe_one_phy(parent, &port_info->phy_info[i], + mptsas_probe_one_phy(parent_dev, &port_info->phy_info[i], ioc->sas_index, 0); - - return 0; - - out_free_port_info: - if (ex) { - kfree(ex->phy_info); - kfree(ex); - } - out: - return error; } -/* - * mptsas_delete_expander_phys - * - * - * This will traverse topology, and remove expanders - * that are no longer present - */ static void -mptsas_delete_expander_phys(MPT_ADAPTER *ioc) +mptsas_expander_event_add(MPT_ADAPTER *ioc, + MpiEventDataSasExpanderStatusChange_t *expander_data) { - struct mptsas_portinfo buffer; - struct mptsas_portinfo *port_info, *n, *parent; - struct mptsas_phyinfo *phy_info; - struct sas_port * port; + struct mptsas_portinfo *port_info; int i; - u64 expander_sas_address; + __le64 sas_address; + + port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL); + if (!port_info) + BUG(); + port_info->num_phys = (expander_data->NumPhys) ? + expander_data->NumPhys : 1; + port_info->phy_info = kcalloc(port_info->num_phys, + sizeof(struct mptsas_phyinfo), GFP_KERNEL); + if (!port_info->phy_info) + BUG(); + memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64)); + for (i = 0; i < port_info->num_phys; i++) { + port_info->phy_info[i].portinfo = port_info; + port_info->phy_info[i].handle = + le16_to_cpu(expander_data->DevHandle); + port_info->phy_info[i].identify.sas_address = + le64_to_cpu(sas_address); + port_info->phy_info[i].identify.handle_parent = + le16_to_cpu(expander_data->ParentDevHandle); + } mutex_lock(&ioc->sas_topology_mutex); - list_for_each_entry_safe(port_info, n, &ioc->sas_topology, list) { + list_add_tail(&port_info->list, &ioc->sas_topology); + mutex_unlock(&ioc->sas_topology_mutex); - if (!(port_info->phy_info[0].identify.device_info & - MPI_SAS_DEVICE_INFO_SMP_TARGET)) + printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, " + "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys, + (unsigned long long)sas_address); + + mptsas_expander_refresh(ioc, port_info); +} + +/** + * mptsas_delete_expander_siblings - remove siblings attached to expander + * @ioc: Pointer to MPT_ADAPTER structure + * @parent: the parent port_info object + * @expander: the expander port_info object + **/ +static void +mptsas_delete_expander_siblings(MPT_ADAPTER *ioc, struct mptsas_portinfo + *parent, struct mptsas_portinfo *expander) +{ + struct mptsas_phyinfo *phy_info; + struct mptsas_portinfo *port_info; + struct sas_rphy *rphy; + int i; + + phy_info = expander->phy_info; + for (i = 0; i < expander->num_phys; i++, phy_info++) { + rphy = mptsas_get_rphy(phy_info); + if (!rphy) continue; + if (rphy->identify.device_type == SAS_END_DEVICE) + mptsas_del_end_device(ioc, phy_info); + } - if (mptsas_sas_expander_pg0(ioc, &buffer, - (MPI_SAS_EXPAND_PGAD_FORM_HANDLE << - MPI_SAS_EXPAND_PGAD_FORM_SHIFT), - port_info->phy_info[0].handle)) { - + phy_info = expander->phy_info; + for (i = 0; i < expander->num_phys; i++, phy_info++) { + rphy = mptsas_get_rphy(phy_info); + if (!rphy) + continue; + if (rphy->identify.device_type == + MPI_SAS_DEVICE_INFO_EDGE_EXPANDER || + rphy->identify.device_type == + MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER) { + port_info = mptsas_find_portinfo_by_sas_address(ioc, + rphy->identify.sas_address); + if (!port_info) + continue; + if (port_info == parent) /* backlink rphy */ + continue; /* - * Obtain the port_info instance to the parent port - */ - parent = mptsas_find_portinfo_by_handle(ioc, - port_info->phy_info[0].identify.handle_parent); - - if (!parent) - goto next_port; - - expander_sas_address = - port_info->phy_info[0].identify.sas_address; - - /* - * Delete rphys in the parent that point - * to this expander. The transport layer will - * cleanup all the children. - */ - phy_info = parent->phy_info; - for (i = 0; i < parent->num_phys; i++, phy_info++) { - port = mptsas_get_port(phy_info); - if (!port) - continue; - if (phy_info->attached.sas_address != - expander_sas_address) - continue; - dsaswideprintk(ioc, - dev_printk(KERN_DEBUG, &port->dev, - MYIOC_s_FMT "delete port (%d)\n", ioc->name, - port->port_identifier)); - sas_port_delete(port); - mptsas_port_delete(ioc, phy_info->port_details); - } - next_port: - - phy_info = port_info->phy_info; - for (i = 0; i < port_info->num_phys; i++, phy_info++) - mptsas_port_delete(ioc, phy_info->port_details); - - list_del(&port_info->list); - kfree(port_info->phy_info); - kfree(port_info); + Delete this expander even if the expdevpage is exists + because the parent expander is already deleted + */ + mptsas_expander_delete(ioc, port_info, 1); } - /* - * Free this memory allocated from inside - * mptsas_sas_expander_pg0 - */ + } +} + + +/** + * mptsas_expander_delete - remove this expander + * @ioc: Pointer to MPT_ADAPTER structure + * @port_info: expander port_info struct + * @force: Flag to forcefully delete the expander + * + **/ + +static void mptsas_expander_delete(MPT_ADAPTER *ioc, + struct mptsas_portinfo *port_info, u8 force) +{ + + struct mptsas_portinfo *parent; + int i; + u64 expander_sas_address; + struct mptsas_phyinfo *phy_info; + struct mptsas_portinfo buffer; + struct mptsas_portinfo_details *port_details; + struct sas_port *port; + + if (!port_info) + return; + + /* see if expander is still there before deleting */ + mptsas_sas_expander_pg0(ioc, &buffer, + (MPI_SAS_EXPAND_PGAD_FORM_HANDLE << + MPI_SAS_EXPAND_PGAD_FORM_SHIFT), + port_info->phy_info[0].identify.handle); + + if (buffer.num_phys) { kfree(buffer.phy_info); + if (!force) + return; + } + + + /* + * Obtain the port_info instance to the parent port + */ + port_details = NULL; + expander_sas_address = + port_info->phy_info[0].identify.sas_address; + parent = mptsas_find_portinfo_by_handle(ioc, + port_info->phy_info[0].identify.handle_parent); + mptsas_delete_expander_siblings(ioc, parent, port_info); + if (!parent) + goto out; + + /* + * Delete rphys in the parent that point + * to this expander. + */ + phy_info = parent->phy_info; + port = NULL; + for (i = 0; i < parent->num_phys; i++, phy_info++) { + if (!phy_info->phy) + continue; + if (phy_info->attached.sas_address != + expander_sas_address) + continue; + if (!port) { + port = mptsas_get_port(phy_info); + port_details = phy_info->port_details; + } + dev_printk(KERN_DEBUG, &phy_info->phy->dev, + MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n", ioc->name, + phy_info->phy_id, phy_info->phy); + sas_port_delete_phy(port, phy_info->phy); + } + if (port) { + dev_printk(KERN_DEBUG, &port->dev, + MYIOC_s_FMT "delete port %d, sas_addr (0x%llx)\n", + ioc->name, port->port_identifier, + (unsigned long long)expander_sas_address); + sas_port_delete(port); + mptsas_port_delete(ioc, port_details); + } + out: + + printk(MYIOC_s_INFO_FMT "delete expander: num_phys %d, " + "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys, + (unsigned long long)expander_sas_address); + + /* + * free link + */ + list_del(&port_info->list); + kfree(port_info->phy_info); + kfree(port_info); +} + + +/** + * mptsas_send_expander_event - expanders events + * @ioc: Pointer to MPT_ADAPTER structure + * @expander_data: event data + * + * + * This function handles adding, removing, and refreshing + * device handles within the expander objects. + */ +static void +mptsas_send_expander_event(struct fw_event_work *fw_event) +{ + MPT_ADAPTER *ioc; + MpiEventDataSasExpanderStatusChange_t *expander_data; + struct mptsas_portinfo *port_info; + __le64 sas_address; + int i; + + ioc = fw_event->ioc; + expander_data = (MpiEventDataSasExpanderStatusChange_t *) + fw_event->event_data; + memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64)); + port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address); + + if (expander_data->ReasonCode == MPI_EVENT_SAS_EXP_RC_ADDED) { + if (port_info) { + for (i = 0; i < port_info->num_phys; i++) { + port_info->phy_info[i].portinfo = port_info; + port_info->phy_info[i].handle = + le16_to_cpu(expander_data->DevHandle); + port_info->phy_info[i].identify.sas_address = + le64_to_cpu(sas_address); + port_info->phy_info[i].identify.handle_parent = + le16_to_cpu(expander_data->ParentDevHandle); + } + mptsas_expander_refresh(ioc, port_info); + } else if (!port_info && expander_data->NumPhys) + mptsas_expander_event_add(ioc, expander_data); + } else if (expander_data->ReasonCode == + MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING) + mptsas_expander_delete(ioc, port_info, 0); + + mptsas_free_fw_event(ioc, fw_event); +} + + +/** + * mptsas_expander_add - + * @ioc: Pointer to MPT_ADAPTER structure + * @handle: + * + */ +struct mptsas_portinfo * +mptsas_expander_add(MPT_ADAPTER *ioc, u16 handle) +{ + struct mptsas_portinfo buffer, *port_info; + int i; + + if ((mptsas_sas_expander_pg0(ioc, &buffer, + (MPI_SAS_EXPAND_PGAD_FORM_HANDLE << + MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle))) + return NULL; + + port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_ATOMIC); + if (!port_info) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: exit at line=%d\n", ioc->name, + __func__, __LINE__)); + return NULL; + } + port_info->num_phys = buffer.num_phys; + port_info->phy_info = buffer.phy_info; + for (i = 0; i < port_info->num_phys; i++) + port_info->phy_info[i].portinfo = port_info; + mutex_lock(&ioc->sas_topology_mutex); + list_add_tail(&port_info->list, &ioc->sas_topology); + mutex_unlock(&ioc->sas_topology_mutex); + printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, " + "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys, + (unsigned long long)buffer.phy_info[0].identify.sas_address); + mptsas_expander_refresh(ioc, port_info); + return port_info; +} + +static void +mptsas_send_link_status_event(struct fw_event_work *fw_event) +{ + MPT_ADAPTER *ioc; + MpiEventDataSasPhyLinkStatus_t *link_data; + struct mptsas_portinfo *port_info; + struct mptsas_phyinfo *phy_info = NULL; + __le64 sas_address; + u8 phy_num; + u8 link_rate; + + ioc = fw_event->ioc; + link_data = (MpiEventDataSasPhyLinkStatus_t *)fw_event->event_data; + + memcpy(&sas_address, &link_data->SASAddress, sizeof(__le64)); + sas_address = le64_to_cpu(sas_address); + link_rate = link_data->LinkRates >> 4; + phy_num = link_data->PhyNum; + + port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address); + if (port_info) { + phy_info = &port_info->phy_info[phy_num]; + if (phy_info) + phy_info->negotiated_link_rate = link_rate; + } + + if (link_rate == MPI_SAS_IOUNIT0_RATE_1_5 || + link_rate == MPI_SAS_IOUNIT0_RATE_3_0) { + + if (!port_info) { + if (ioc->old_sas_discovery_protocal) { + port_info = mptsas_expander_add(ioc, + le16_to_cpu(link_data->DevHandle)); + if (port_info) + goto out; + } + goto out; + } + + if (port_info == ioc->hba_port_info) + mptsas_probe_hba_phys(ioc); + else + mptsas_expander_refresh(ioc, port_info); + } else if (phy_info && phy_info->phy) { + if (link_rate == MPI_SAS_IOUNIT0_RATE_PHY_DISABLED) + phy_info->phy->negotiated_linkrate = + SAS_PHY_DISABLED; + else if (link_rate == + MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION) + phy_info->phy->negotiated_linkrate = + SAS_LINK_RATE_FAILED; + else + phy_info->phy->negotiated_linkrate = + SAS_LINK_RATE_UNKNOWN; + } + out: + mptsas_free_fw_event(ioc, fw_event); +} + +static void +mptsas_not_responding_devices(MPT_ADAPTER *ioc) +{ + struct mptsas_portinfo buffer, *port_info; + struct mptsas_device_info *sas_info; + struct mptsas_devinfo sas_device; + u32 handle; + VirtTarget *vtarget = NULL; + struct mptsas_phyinfo *phy_info; + u8 found_expander; + int retval, retry_count; + unsigned long flags; + + mpt_findImVolumes(ioc); + + spin_lock_irqsave(&ioc->taskmgmt_lock, flags); + if (ioc->ioc_reset_in_progress) { + dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: exiting due to a parallel reset \n", ioc->name, + __func__)); + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + return; + } + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + + /* devices, logical volumes */ + mutex_lock(&ioc->sas_device_info_mutex); + redo_device_scan: + list_for_each_entry(sas_info, &ioc->sas_device_info_list, list) { + if (sas_info->is_cached) + continue; + if (!sas_info->is_logical_volume) { + sas_device.handle = 0; + retry_count = 0; +retry_page: + retval = mptsas_sas_device_pg0(ioc, &sas_device, + (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID + << MPI_SAS_DEVICE_PGAD_FORM_SHIFT), + (sas_info->fw.channel << 8) + + sas_info->fw.id); + + if (sas_device.handle) + continue; + if (retval == -EBUSY) { + spin_lock_irqsave(&ioc->taskmgmt_lock, flags); + if (ioc->ioc_reset_in_progress) { + dfailprintk(ioc, + printk(MYIOC_s_DEBUG_FMT + "%s: exiting due to reset\n", + ioc->name, __func__)); + spin_unlock_irqrestore + (&ioc->taskmgmt_lock, flags); + mutex_unlock(&ioc-> + sas_device_info_mutex); + return; + } + spin_unlock_irqrestore(&ioc->taskmgmt_lock, + flags); + } + + if (retval && (retval != -ENODEV)) { + if (retry_count < 10) { + retry_count++; + goto retry_page; + } else { + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: Config page retry exceeded retry " + "count deleting device 0x%llx\n", + ioc->name, __func__, + sas_info->sas_address)); + } + } + + /* delete device */ + vtarget = mptsas_find_vtarget(ioc, + sas_info->fw.channel, sas_info->fw.id); + + if (vtarget) + vtarget->deleted = 1; + + phy_info = mptsas_find_phyinfo_by_sas_address(ioc, + sas_info->sas_address); + + if (phy_info) { + mptsas_del_end_device(ioc, phy_info); + goto redo_device_scan; + } + } else + mptsas_volume_delete(ioc, sas_info->fw.id); + } + mutex_unlock(&ioc->sas_device_info_mutex); + + /* expanders */ + mutex_lock(&ioc->sas_topology_mutex); + redo_expander_scan: + list_for_each_entry(port_info, &ioc->sas_topology, list) { + + if (port_info->phy_info && + (!(port_info->phy_info[0].identify.device_info & + MPI_SAS_DEVICE_INFO_SMP_TARGET))) + continue; + found_expander = 0; + handle = 0xFFFF; + while (!mptsas_sas_expander_pg0(ioc, &buffer, + (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE << + MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle) && + !found_expander) { + + handle = buffer.phy_info[0].handle; + if (buffer.phy_info[0].identify.sas_address == + port_info->phy_info[0].identify.sas_address) { + found_expander = 1; + } + kfree(buffer.phy_info); + } + + if (!found_expander) { + mptsas_expander_delete(ioc, port_info, 0); + goto redo_expander_scan; + } } mutex_unlock(&ioc->sas_topology_mutex); } -/* - * Start of day discovery - */ +/** + * mptsas_probe_expanders - adding expanders + * @ioc: Pointer to MPT_ADAPTER structure + * + **/ +static void +mptsas_probe_expanders(MPT_ADAPTER *ioc) +{ + struct mptsas_portinfo buffer, *port_info; + u32 handle; + int i; + + handle = 0xFFFF; + while (!mptsas_sas_expander_pg0(ioc, &buffer, + (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE << + MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)) { + + handle = buffer.phy_info[0].handle; + port_info = mptsas_find_portinfo_by_sas_address(ioc, + buffer.phy_info[0].identify.sas_address); + + if (port_info) { + /* refreshing handles */ + for (i = 0; i < buffer.num_phys; i++) { + port_info->phy_info[i].handle = handle; + port_info->phy_info[i].identify.handle_parent = + buffer.phy_info[0].identify.handle_parent; + } + mptsas_expander_refresh(ioc, port_info); + kfree(buffer.phy_info); + continue; + } + + port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL); + if (!port_info) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: exit at line=%d\n", ioc->name, + __func__, __LINE__)); + return; + } + port_info->num_phys = buffer.num_phys; + port_info->phy_info = buffer.phy_info; + for (i = 0; i < port_info->num_phys; i++) + port_info->phy_info[i].portinfo = port_info; + mutex_lock(&ioc->sas_topology_mutex); + list_add_tail(&port_info->list, &ioc->sas_topology); + mutex_unlock(&ioc->sas_topology_mutex); + printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, " + "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys, + (unsigned long long)buffer.phy_info[0].identify.sas_address); + mptsas_expander_refresh(ioc, port_info); + } +} + +static void +mptsas_probe_devices(MPT_ADAPTER *ioc) +{ + u16 handle; + struct mptsas_devinfo sas_device; + struct mptsas_phyinfo *phy_info; + + handle = 0xFFFF; + while (!(mptsas_sas_device_pg0(ioc, &sas_device, + MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE, handle))) { + + handle = sas_device.handle; + + if ((sas_device.device_info & + (MPI_SAS_DEVICE_INFO_SSP_TARGET | + MPI_SAS_DEVICE_INFO_STP_TARGET | + MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0) + continue; + + phy_info = mptsas_refreshing_device_handles(ioc, &sas_device); + if (!phy_info) + continue; + + if (mptsas_get_rphy(phy_info)) + continue; + + mptsas_add_end_device(ioc, phy_info); + } +} + +/** + * mptsas_scan_sas_topology - + * @ioc: Pointer to MPT_ADAPTER structure + * @sas_address: + * + **/ static void mptsas_scan_sas_topology(MPT_ADAPTER *ioc) { - u32 handle = 0xFFFF; + struct scsi_device *sdev; int i; - mutex_lock(&ioc->sas_discovery_mutex); mptsas_probe_hba_phys(ioc); - while (!mptsas_probe_expander_phys(ioc, &handle)) - ; + mptsas_probe_expanders(ioc); + mptsas_probe_devices(ioc); + /* Reporting RAID volumes. */ - if (!ioc->ir_firmware) - goto out; - if (!ioc->raid_data.pIocPg2) - goto out; - if (!ioc->raid_data.pIocPg2->NumActiveVolumes) - goto out; + if (!ioc->ir_firmware || !ioc->raid_data.pIocPg2 || + !ioc->raid_data.pIocPg2->NumActiveVolumes) + return; for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) { + sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, + ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0); + if (sdev) { + scsi_device_put(sdev); + continue; + } + printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, " + "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, + ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID); scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL, ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0); } +} + + +static void +mptsas_handle_queue_full_event(struct fw_event_work *fw_event) +{ + MPT_ADAPTER *ioc; + EventDataQueueFull_t *qfull_data; + struct mptsas_device_info *sas_info; + struct scsi_device *sdev; + int depth; + int id = -1; + int channel = -1; + int fw_id, fw_channel; + u16 current_depth; + + + ioc = fw_event->ioc; + qfull_data = (EventDataQueueFull_t *)fw_event->event_data; + fw_id = qfull_data->TargetID; + fw_channel = qfull_data->Bus; + current_depth = le16_to_cpu(qfull_data->CurrentDepth); + + /* if hidden raid component, look for the volume id */ + mutex_lock(&ioc->sas_device_info_mutex); + if (mptscsih_is_phys_disk(ioc, fw_channel, fw_id)) { + list_for_each_entry(sas_info, &ioc->sas_device_info_list, + list) { + if (sas_info->is_cached || + sas_info->is_logical_volume) + continue; + if (sas_info->is_hidden_raid_component && + (sas_info->fw.channel == fw_channel && + sas_info->fw.id == fw_id)) { + id = sas_info->volume_id; + channel = MPTSAS_RAID_CHANNEL; + goto out; + } + } + } else { + list_for_each_entry(sas_info, &ioc->sas_device_info_list, + list) { + if (sas_info->is_cached || + sas_info->is_hidden_raid_component || + sas_info->is_logical_volume) + continue; + if (sas_info->fw.channel == fw_channel && + sas_info->fw.id == fw_id) { + id = sas_info->os.id; + channel = sas_info->os.channel; + goto out; + } + } + + } + out: - mutex_unlock(&ioc->sas_discovery_mutex); + mutex_unlock(&ioc->sas_device_info_mutex); + + if (id != -1) { + shost_for_each_device(sdev, ioc->sh) { + if (sdev->id == id && sdev->channel == channel) { + if (current_depth > sdev->queue_depth) { + sdev_printk(KERN_INFO, sdev, + "strange observation, the queue " + "depth is (%d) meanwhile fw queue " + "depth (%d)\n", sdev->queue_depth, + current_depth); + continue; + } + depth = scsi_track_queue_full(sdev, + current_depth - 1); + if (depth > 0) + sdev_printk(KERN_INFO, sdev, + "Queue depth reduced to (%d)\n", + depth); + else if (depth < 0) + sdev_printk(KERN_INFO, sdev, + "Tagged Command Queueing is being " + "disabled\n"); + else if (depth == 0) + sdev_printk(KERN_INFO, sdev, + "Queue depth not changed yet\n"); + } + } + } + + mptsas_free_fw_event(ioc, fw_event); } -/* - * Work queue thread to handle Runtime discovery - * Mere purpose is the hot add/delete of expanders - *(Mutex UNLOCKED) - */ -static void -__mptsas_discovery_work(MPT_ADAPTER *ioc) -{ - u32 handle = 0xFFFF; - - ioc->sas_discovery_runtime=1; - mptsas_delete_expander_phys(ioc); - mptsas_probe_hba_phys(ioc); - while (!mptsas_probe_expander_phys(ioc, &handle)) - ; - ioc->sas_discovery_runtime=0; -} - -/* - * Work queue thread to handle Runtime discovery - * Mere purpose is the hot add/delete of expanders - *(Mutex LOCKED) - */ -static void -mptsas_discovery_work(struct work_struct *work) -{ - struct mptsas_discovery_event *ev = - container_of(work, struct mptsas_discovery_event, work); - MPT_ADAPTER *ioc = ev->ioc; - - mutex_lock(&ioc->sas_discovery_mutex); - __mptsas_discovery_work(ioc); - mutex_unlock(&ioc->sas_discovery_mutex); - kfree(ev); -} static struct mptsas_phyinfo * mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address) @@ -2429,69 +3786,80 @@ mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address) return phy_info; } +/** + * mptsas_find_phyinfo_by_phys_disk_num - + * @ioc: Pointer to MPT_ADAPTER structure + * @phys_disk_num: + * @channel: + * @id: + * + **/ static struct mptsas_phyinfo * -mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u8 channel, u8 id) +mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 phys_disk_num, + u8 channel, u8 id) { - struct mptsas_portinfo *port_info; struct mptsas_phyinfo *phy_info = NULL; + struct mptsas_portinfo *port_info; + RaidPhysDiskPage1_t *phys_disk = NULL; + int num_paths; + u64 sas_address = 0; int i; - mutex_lock(&ioc->sas_topology_mutex); - list_for_each_entry(port_info, &ioc->sas_topology, list) { - for (i = 0; i < port_info->num_phys; i++) { - if (!mptsas_is_end_device( - &port_info->phy_info[i].attached)) - continue; - if (port_info->phy_info[i].attached.id != id) - continue; - if (port_info->phy_info[i].attached.channel != channel) - continue; - phy_info = &port_info->phy_info[i]; - break; + phy_info = NULL; + if (!ioc->raid_data.pIocPg3) + return NULL; + /* dual port support */ + num_paths = mpt_raid_phys_disk_get_num_paths(ioc, phys_disk_num); + if (!num_paths) + goto out; + phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) + + (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL); + if (!phys_disk) + goto out; + mpt_raid_phys_disk_pg1(ioc, phys_disk_num, phys_disk); + for (i = 0; i < num_paths; i++) { + if ((phys_disk->Path[i].Flags & 1) != 0) + /* entry no longer valid */ + continue; + if ((id == phys_disk->Path[i].PhysDiskID) && + (channel == phys_disk->Path[i].PhysDiskBus)) { + memcpy(&sas_address, &phys_disk->Path[i].WWID, + sizeof(u64)); + phy_info = mptsas_find_phyinfo_by_sas_address(ioc, + sas_address); + goto out; } } - mutex_unlock(&ioc->sas_topology_mutex); - return phy_info; -} -static struct mptsas_phyinfo * -mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 channel, u8 id) -{ - struct mptsas_portinfo *port_info; - struct mptsas_phyinfo *phy_info = NULL; - int i; + out: + kfree(phys_disk); + if (phy_info) + return phy_info; + /* + * Extra code to handle RAID0 case, where the sas_address is not updated + * in phys_disk_page_1 when hotswapped + */ mutex_lock(&ioc->sas_topology_mutex); list_for_each_entry(port_info, &ioc->sas_topology, list) { - for (i = 0; i < port_info->num_phys; i++) { + for (i = 0; i < port_info->num_phys && !phy_info; i++) { if (!mptsas_is_end_device( &port_info->phy_info[i].attached)) continue; if (port_info->phy_info[i].attached.phys_disk_num == ~0) continue; - if (port_info->phy_info[i].attached.phys_disk_num != id) - continue; - if (port_info->phy_info[i].attached.channel != channel) - continue; - phy_info = &port_info->phy_info[i]; - break; + if ((port_info->phy_info[i].attached.phys_disk_num == + phys_disk_num) && + (port_info->phy_info[i].attached.id == id) && + (port_info->phy_info[i].attached.channel == + channel)) + phy_info = &port_info->phy_info[i]; } } mutex_unlock(&ioc->sas_topology_mutex); return phy_info; } -/* - * Work queue thread to clear the persitency table - */ -static void -mptsas_persist_clear_table(struct work_struct *work) -{ - MPT_ADAPTER *ioc = container_of(work, MPT_ADAPTER, sas_persist_task); - - mptbase_sas_persist_operation(ioc, MPI_SAS_OP_CLEAR_NOT_PRESENT); -} - static void mptsas_reprobe_lun(struct scsi_device *sdev, void *data) { @@ -2517,7 +3885,8 @@ mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id) pRaidVolumePage0_t buffer = NULL; RaidPhysDiskPage0_t phys_disk; int i; - struct mptsas_hotplug_event *ev; + struct mptsas_phyinfo *phy_info; + struct mptsas_devinfo sas_device; memset(&cfg, 0 , sizeof(CONFIGPARMS)); memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); @@ -2557,20 +3926,16 @@ mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id) buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0) continue; - ev = kzalloc(sizeof(*ev), GFP_ATOMIC); - if (!ev) { - printk(MYIOC_s_WARN_FMT "mptsas: lost hotplug event\n", ioc->name); - goto out; - } + if (mptsas_sas_device_pg0(ioc, &sas_device, + (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << + MPI_SAS_DEVICE_PGAD_FORM_SHIFT), + (phys_disk.PhysDiskBus << 8) + + phys_disk.PhysDiskID)) + continue; - INIT_WORK(&ev->work, mptsas_hotplug_work); - ev->ioc = ioc; - ev->id = phys_disk.PhysDiskID; - ev->channel = phys_disk.PhysDiskBus; - ev->phys_disk_num_valid = 1; - ev->phys_disk_num = phys_disk.PhysDiskNum; - ev->event_type = MPTSAS_ADD_DEVICE; - schedule_work(&ev->work); + phy_info = mptsas_find_phyinfo_by_sas_address(ioc, + sas_device.sas_address); + mptsas_add_end_device(ioc, phy_info); } out: @@ -2582,417 +3947,386 @@ mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id) * Work queue thread to handle SAS hotplug events */ static void -mptsas_hotplug_work(struct work_struct *work) +mptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event, + struct mptsas_hotplug_event *hot_plug_info) { - struct mptsas_hotplug_event *ev = - container_of(work, struct mptsas_hotplug_event, work); - - MPT_ADAPTER *ioc = ev->ioc; struct mptsas_phyinfo *phy_info; - struct sas_rphy *rphy; - struct sas_port *port; - struct scsi_device *sdev; struct scsi_target * starget; - struct sas_identify identify; - char *ds = NULL; struct mptsas_devinfo sas_device; VirtTarget *vtarget; - VirtDevice *vdevice; + int i; - mutex_lock(&ioc->sas_discovery_mutex); - switch (ev->event_type) { - case MPTSAS_DEL_DEVICE: + switch (hot_plug_info->event_type) { - phy_info = NULL; - if (ev->phys_disk_num_valid) { - if (ev->hidden_raid_component){ - if (mptsas_sas_device_pg0(ioc, &sas_device, - (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << - MPI_SAS_DEVICE_PGAD_FORM_SHIFT), - (ev->channel << 8) + ev->id)) { - dfailprintk(ioc, printk(MYIOC_s_ERR_FMT - "%s: exit at line=%d\n", ioc->name, - __func__, __LINE__)); - break; - } - phy_info = mptsas_find_phyinfo_by_sas_address( - ioc, sas_device.sas_address); - }else - phy_info = mptsas_find_phyinfo_by_phys_disk_num( - ioc, ev->channel, ev->phys_disk_num); - } + case MPTSAS_ADD_PHYSDISK: - if (!phy_info) - phy_info = mptsas_find_phyinfo_by_target(ioc, - ev->channel, ev->id); - - /* - * Sanity checks, for non-existing phys and remote rphys. - */ - if (!phy_info){ - dfailprintk(ioc, printk(MYIOC_s_ERR_FMT - "%s: exit at line=%d\n", ioc->name, - __func__, __LINE__)); + if (!ioc->raid_data.pIocPg2) break; - } - if (!phy_info->port_details) { - dfailprintk(ioc, printk(MYIOC_s_ERR_FMT - "%s: exit at line=%d\n", ioc->name, - __func__, __LINE__)); - break; - } - rphy = mptsas_get_rphy(phy_info); - if (!rphy) { - dfailprintk(ioc, printk(MYIOC_s_ERR_FMT - "%s: exit at line=%d\n", ioc->name, - __func__, __LINE__)); - break; - } - port = mptsas_get_port(phy_info); - if (!port) { - dfailprintk(ioc, printk(MYIOC_s_ERR_FMT - "%s: exit at line=%d\n", ioc->name, - __func__, __LINE__)); - break; - } - - starget = mptsas_get_starget(phy_info); - if (starget) { - vtarget = starget->hostdata; - - if (!vtarget) { - dfailprintk(ioc, printk(MYIOC_s_ERR_FMT - "%s: exit at line=%d\n", ioc->name, - __func__, __LINE__)); - break; - } - - /* - * Handling RAID components - */ - if (ev->phys_disk_num_valid && - ev->hidden_raid_component) { - printk(MYIOC_s_INFO_FMT - "RAID Hidding: channel=%d, id=%d, " - "physdsk %d \n", ioc->name, ev->channel, - ev->id, ev->phys_disk_num); - vtarget->id = ev->phys_disk_num; - vtarget->tflags |= - MPT_TARGET_FLAGS_RAID_COMPONENT; - mptsas_reprobe_target(starget, 1); - phy_info->attached.phys_disk_num = - ev->phys_disk_num; - break; + for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) { + if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == + hot_plug_info->id) { + printk(MYIOC_s_WARN_FMT "firmware bug: unable " + "to add hidden disk - target_id matchs " + "volume_id\n", ioc->name); + mptsas_free_fw_event(ioc, fw_event); + return; } } + mpt_findImVolumes(ioc); - if (phy_info->attached.device_info & - MPI_SAS_DEVICE_INFO_SSP_TARGET) - ds = "ssp"; - if (phy_info->attached.device_info & - MPI_SAS_DEVICE_INFO_STP_TARGET) - ds = "stp"; - if (phy_info->attached.device_info & - MPI_SAS_DEVICE_INFO_SATA_DEVICE) - ds = "sata"; - - printk(MYIOC_s_INFO_FMT - "removing %s device, channel %d, id %d, phy %d\n", - ioc->name, ds, ev->channel, ev->id, phy_info->phy_id); - dev_printk(KERN_DEBUG, &port->dev, MYIOC_s_FMT - "delete port (%d)\n", ioc->name, port->port_identifier); - sas_port_delete(port); - mptsas_port_delete(ioc, phy_info->port_details); - break; case MPTSAS_ADD_DEVICE: + memset(&sas_device, 0, sizeof(struct mptsas_devinfo)); + mptsas_sas_device_pg0(ioc, &sas_device, + (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << + MPI_SAS_DEVICE_PGAD_FORM_SHIFT), + (hot_plug_info->channel << 8) + + hot_plug_info->id); - if (ev->phys_disk_num_valid) - mpt_findImVolumes(ioc); + if (!sas_device.handle) + return; + + phy_info = mptsas_refreshing_device_handles(ioc, &sas_device); + if (!phy_info) + break; + + if (mptsas_get_rphy(phy_info)) + break; + + mptsas_add_end_device(ioc, phy_info); + break; + + case MPTSAS_DEL_DEVICE: + phy_info = mptsas_find_phyinfo_by_sas_address(ioc, + hot_plug_info->sas_address); + mptsas_del_end_device(ioc, phy_info); + break; + + case MPTSAS_DEL_PHYSDISK: + + mpt_findImVolumes(ioc); + + phy_info = mptsas_find_phyinfo_by_phys_disk_num( + ioc, hot_plug_info->phys_disk_num, + hot_plug_info->channel, + hot_plug_info->id); + mptsas_del_end_device(ioc, phy_info); + break; + + case MPTSAS_ADD_PHYSDISK_REPROBE: - /* - * Refresh sas device pg0 data - */ if (mptsas_sas_device_pg0(ioc, &sas_device, (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << MPI_SAS_DEVICE_PGAD_FORM_SHIFT), - (ev->channel << 8) + ev->id)) { - dfailprintk(ioc, printk(MYIOC_s_ERR_FMT - "%s: exit at line=%d\n", ioc->name, - __func__, __LINE__)); + (hot_plug_info->channel << 8) + hot_plug_info->id)) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: fw_id=%d exit at line=%d\n", ioc->name, + __func__, hot_plug_info->id, __LINE__)); break; } - __mptsas_discovery_work(ioc); + phy_info = mptsas_find_phyinfo_by_sas_address( + ioc, sas_device.sas_address); - phy_info = mptsas_find_phyinfo_by_sas_address(ioc, - sas_device.sas_address); - - if (!phy_info || !phy_info->port_details) { + if (!phy_info) { dfailprintk(ioc, printk(MYIOC_s_ERR_FMT - "%s: exit at line=%d\n", ioc->name, - __func__, __LINE__)); + "%s: fw_id=%d exit at line=%d\n", ioc->name, + __func__, hot_plug_info->id, __LINE__)); break; } starget = mptsas_get_starget(phy_info); - if (starget && (!ev->hidden_raid_component)){ + if (!starget) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: fw_id=%d exit at line=%d\n", ioc->name, + __func__, hot_plug_info->id, __LINE__)); + break; + } - vtarget = starget->hostdata; + vtarget = starget->hostdata; + if (!vtarget) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: fw_id=%d exit at line=%d\n", ioc->name, + __func__, hot_plug_info->id, __LINE__)); + break; + } - if (!vtarget) { + mpt_findImVolumes(ioc); + + starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Hidding: " + "fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n", + ioc->name, hot_plug_info->channel, hot_plug_info->id, + hot_plug_info->phys_disk_num, (unsigned long long) + sas_device.sas_address); + + vtarget->id = hot_plug_info->phys_disk_num; + vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT; + phy_info->attached.phys_disk_num = hot_plug_info->phys_disk_num; + mptsas_reprobe_target(starget, 1); + break; + + case MPTSAS_DEL_PHYSDISK_REPROBE: + + if (mptsas_sas_device_pg0(ioc, &sas_device, + (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << + MPI_SAS_DEVICE_PGAD_FORM_SHIFT), + (hot_plug_info->channel << 8) + hot_plug_info->id)) { dfailprintk(ioc, printk(MYIOC_s_ERR_FMT - "%s: exit at line=%d\n", ioc->name, - __func__, __LINE__)); - break; - } - /* - * Handling RAID components - */ - if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) { - printk(MYIOC_s_INFO_FMT - "RAID Exposing: channel=%d, id=%d, " - "physdsk %d \n", ioc->name, ev->channel, - ev->id, ev->phys_disk_num); - vtarget->tflags &= - ~MPT_TARGET_FLAGS_RAID_COMPONENT; - vtarget->id = ev->id; - mptsas_reprobe_target(starget, 0); - phy_info->attached.phys_disk_num = ~0; - } + "%s: fw_id=%d exit at line=%d\n", + ioc->name, __func__, + hot_plug_info->id, __LINE__)); break; } - if (mptsas_get_rphy(phy_info)) { + phy_info = mptsas_find_phyinfo_by_sas_address(ioc, + sas_device.sas_address); + if (!phy_info) { dfailprintk(ioc, printk(MYIOC_s_ERR_FMT - "%s: exit at line=%d\n", ioc->name, - __func__, __LINE__)); - if (ev->channel) printk("%d\n", __LINE__); + "%s: fw_id=%d exit at line=%d\n", ioc->name, + __func__, hot_plug_info->id, __LINE__)); break; } - port = mptsas_get_port(phy_info); - if (!port) { + starget = mptsas_get_starget(phy_info); + if (!starget) { dfailprintk(ioc, printk(MYIOC_s_ERR_FMT - "%s: exit at line=%d\n", ioc->name, - __func__, __LINE__)); + "%s: fw_id=%d exit at line=%d\n", ioc->name, + __func__, hot_plug_info->id, __LINE__)); break; } - memcpy(&phy_info->attached, &sas_device, - sizeof(struct mptsas_devinfo)); - if (phy_info->attached.device_info & - MPI_SAS_DEVICE_INFO_SSP_TARGET) - ds = "ssp"; - if (phy_info->attached.device_info & - MPI_SAS_DEVICE_INFO_STP_TARGET) - ds = "stp"; - if (phy_info->attached.device_info & - MPI_SAS_DEVICE_INFO_SATA_DEVICE) - ds = "sata"; - - printk(MYIOC_s_INFO_FMT - "attaching %s device, channel %d, id %d, phy %d\n", - ioc->name, ds, ev->channel, ev->id, ev->phy_id); - - mptsas_parse_device_info(&identify, &phy_info->attached); - rphy = sas_end_device_alloc(port); - if (!rphy) { + vtarget = starget->hostdata; + if (!vtarget) { dfailprintk(ioc, printk(MYIOC_s_ERR_FMT - "%s: exit at line=%d\n", ioc->name, - __func__, __LINE__)); - break; /* non-fatal: an rphy can be added later */ - } - - rphy->identify = identify; - if (sas_rphy_add(rphy)) { - dfailprintk(ioc, printk(MYIOC_s_ERR_FMT - "%s: exit at line=%d\n", ioc->name, - __func__, __LINE__)); - sas_rphy_free(rphy); + "%s: fw_id=%d exit at line=%d\n", ioc->name, + __func__, hot_plug_info->id, __LINE__)); break; } - mptsas_set_rphy(ioc, phy_info, rphy); + + if (!(vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: fw_id=%d exit at line=%d\n", ioc->name, + __func__, hot_plug_info->id, __LINE__)); + break; + } + + mpt_findImVolumes(ioc); + + starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Exposing:" + " fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n", + ioc->name, hot_plug_info->channel, hot_plug_info->id, + hot_plug_info->phys_disk_num, (unsigned long long) + sas_device.sas_address); + + vtarget->tflags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT; + vtarget->id = hot_plug_info->id; + phy_info->attached.phys_disk_num = ~0; + mptsas_reprobe_target(starget, 0); + mptsas_add_device_component_by_fw(ioc, + hot_plug_info->channel, hot_plug_info->id); break; + case MPTSAS_ADD_RAID: - sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, - ev->id, 0); - if (sdev) { - scsi_device_put(sdev); - break; - } - printk(MYIOC_s_INFO_FMT - "attaching raid volume, channel %d, id %d\n", - ioc->name, MPTSAS_RAID_CHANNEL, ev->id); - scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL, ev->id, 0); + mpt_findImVolumes(ioc); + printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, " + "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, + hot_plug_info->id); + scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL, + hot_plug_info->id, 0); break; + case MPTSAS_DEL_RAID: - sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, - ev->id, 0); - if (!sdev) - break; - printk(MYIOC_s_INFO_FMT - "removing raid volume, channel %d, id %d\n", - ioc->name, MPTSAS_RAID_CHANNEL, ev->id); - vdevice = sdev->hostdata; - scsi_remove_device(sdev); - scsi_device_put(sdev); + mpt_findImVolumes(ioc); + printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, " + "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, + hot_plug_info->id); + scsi_remove_device(hot_plug_info->sdev); + scsi_device_put(hot_plug_info->sdev); break; + case MPTSAS_ADD_INACTIVE_VOLUME: + + mpt_findImVolumes(ioc); mptsas_adding_inactive_raid_components(ioc, - ev->channel, ev->id); + hot_plug_info->channel, hot_plug_info->id); break; - case MPTSAS_IGNORE_EVENT: + default: break; } - mutex_unlock(&ioc->sas_discovery_mutex); - kfree(ev); + mptsas_free_fw_event(ioc, fw_event); } static void -mptsas_send_sas_event(MPT_ADAPTER *ioc, - EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data) +mptsas_send_sas_event(struct fw_event_work *fw_event) { - struct mptsas_hotplug_event *ev; - u32 device_info = le32_to_cpu(sas_event_data->DeviceInfo); - __le64 sas_address; + MPT_ADAPTER *ioc; + struct mptsas_hotplug_event hot_plug_info; + EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data; + u32 device_info; + u64 sas_address; + + ioc = fw_event->ioc; + sas_event_data = (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *) + fw_event->event_data; + device_info = le32_to_cpu(sas_event_data->DeviceInfo); if ((device_info & - (MPI_SAS_DEVICE_INFO_SSP_TARGET | - MPI_SAS_DEVICE_INFO_STP_TARGET | - MPI_SAS_DEVICE_INFO_SATA_DEVICE )) == 0) + (MPI_SAS_DEVICE_INFO_SSP_TARGET | + MPI_SAS_DEVICE_INFO_STP_TARGET | + MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0) { + mptsas_free_fw_event(ioc, fw_event); return; + } + + if (sas_event_data->ReasonCode == + MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED) { + mptbase_sas_persist_operation(ioc, + MPI_SAS_OP_CLEAR_NOT_PRESENT); + mptsas_free_fw_event(ioc, fw_event); + return; + } switch (sas_event_data->ReasonCode) { case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING: - - mptsas_target_reset_queue(ioc, sas_event_data); - break; - case MPI_EVENT_SAS_DEV_STAT_RC_ADDED: - ev = kzalloc(sizeof(*ev), GFP_ATOMIC); - if (!ev) { - printk(MYIOC_s_WARN_FMT "lost hotplug event\n", ioc->name); - break; - } - - INIT_WORK(&ev->work, mptsas_hotplug_work); - ev->ioc = ioc; - ev->handle = le16_to_cpu(sas_event_data->DevHandle); - ev->parent_handle = - le16_to_cpu(sas_event_data->ParentDevHandle); - ev->channel = sas_event_data->Bus; - ev->id = sas_event_data->TargetID; - ev->phy_id = sas_event_data->PhyNum; + memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event)); + hot_plug_info.handle = le16_to_cpu(sas_event_data->DevHandle); + hot_plug_info.channel = sas_event_data->Bus; + hot_plug_info.id = sas_event_data->TargetID; + hot_plug_info.phy_id = sas_event_data->PhyNum; memcpy(&sas_address, &sas_event_data->SASAddress, - sizeof(__le64)); - ev->sas_address = le64_to_cpu(sas_address); - ev->device_info = device_info; - + sizeof(u64)); + hot_plug_info.sas_address = le64_to_cpu(sas_address); + hot_plug_info.device_info = device_info; if (sas_event_data->ReasonCode & MPI_EVENT_SAS_DEV_STAT_RC_ADDED) - ev->event_type = MPTSAS_ADD_DEVICE; + hot_plug_info.event_type = MPTSAS_ADD_DEVICE; else - ev->event_type = MPTSAS_DEL_DEVICE; - schedule_work(&ev->work); + hot_plug_info.event_type = MPTSAS_DEL_DEVICE; + mptsas_hotplug_work(ioc, fw_event, &hot_plug_info); break; + case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED: - /* - * Persistent table is full. - */ - INIT_WORK(&ioc->sas_persist_task, - mptsas_persist_clear_table); - schedule_work(&ioc->sas_persist_task); + mptbase_sas_persist_operation(ioc, + MPI_SAS_OP_CLEAR_NOT_PRESENT); + mptsas_free_fw_event(ioc, fw_event); break; - /* - * TODO, handle other events - */ + case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA: - case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED: + /* TODO */ case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET: - case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL: - case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL: - case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL: - case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL: + /* TODO */ default: + mptsas_free_fw_event(ioc, fw_event); break; } } + static void -mptsas_send_raid_event(MPT_ADAPTER *ioc, - EVENT_DATA_RAID *raid_event_data) +mptsas_send_raid_event(struct fw_event_work *fw_event) { - struct mptsas_hotplug_event *ev; - int status = le32_to_cpu(raid_event_data->SettingsStatus); - int state = (status >> 8) & 0xff; + MPT_ADAPTER *ioc; + EVENT_DATA_RAID *raid_event_data; + struct mptsas_hotplug_event hot_plug_info; + int status; + int state; + struct scsi_device *sdev = NULL; + VirtDevice *vdevice = NULL; + RaidPhysDiskPage0_t phys_disk; - if (ioc->bus_type != SAS) - return; + ioc = fw_event->ioc; + raid_event_data = (EVENT_DATA_RAID *)fw_event->event_data; + status = le32_to_cpu(raid_event_data->SettingsStatus); + state = (status >> 8) & 0xff; - ev = kzalloc(sizeof(*ev), GFP_ATOMIC); - if (!ev) { - printk(MYIOC_s_WARN_FMT "lost hotplug event\n", ioc->name); - return; + memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event)); + hot_plug_info.id = raid_event_data->VolumeID; + hot_plug_info.channel = raid_event_data->VolumeBus; + hot_plug_info.phys_disk_num = raid_event_data->PhysDiskNum; + + if (raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_DELETED || + raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_CREATED || + raid_event_data->ReasonCode == + MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED) { + sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, + hot_plug_info.id, 0); + hot_plug_info.sdev = sdev; + if (sdev) + vdevice = sdev->hostdata; } - INIT_WORK(&ev->work, mptsas_hotplug_work); - ev->ioc = ioc; - ev->id = raid_event_data->VolumeID; - ev->channel = raid_event_data->VolumeBus; - ev->event_type = MPTSAS_IGNORE_EVENT; + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: " + "ReasonCode=%02x\n", ioc->name, __func__, + raid_event_data->ReasonCode)); switch (raid_event_data->ReasonCode) { case MPI_EVENT_RAID_RC_PHYSDISK_DELETED: - ev->phys_disk_num_valid = 1; - ev->phys_disk_num = raid_event_data->PhysDiskNum; - ev->event_type = MPTSAS_ADD_DEVICE; + hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK_REPROBE; break; case MPI_EVENT_RAID_RC_PHYSDISK_CREATED: - ev->phys_disk_num_valid = 1; - ev->phys_disk_num = raid_event_data->PhysDiskNum; - ev->hidden_raid_component = 1; - ev->event_type = MPTSAS_DEL_DEVICE; + hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK_REPROBE; break; case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED: switch (state) { case MPI_PD_STATE_ONLINE: case MPI_PD_STATE_NOT_COMPATIBLE: - ev->phys_disk_num_valid = 1; - ev->phys_disk_num = raid_event_data->PhysDiskNum; - ev->hidden_raid_component = 1; - ev->event_type = MPTSAS_ADD_DEVICE; + mpt_raid_phys_disk_pg0(ioc, + raid_event_data->PhysDiskNum, &phys_disk); + hot_plug_info.id = phys_disk.PhysDiskID; + hot_plug_info.channel = phys_disk.PhysDiskBus; + hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK; break; + case MPI_PD_STATE_FAILED: case MPI_PD_STATE_MISSING: case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST: case MPI_PD_STATE_FAILED_AT_HOST_REQUEST: case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON: - ev->phys_disk_num_valid = 1; - ev->phys_disk_num = raid_event_data->PhysDiskNum; - ev->event_type = MPTSAS_DEL_DEVICE; + hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK; break; default: break; } break; case MPI_EVENT_RAID_RC_VOLUME_DELETED: - ev->event_type = MPTSAS_DEL_RAID; + if (!sdev) + break; + vdevice->vtarget->deleted = 1; /* block IO */ + hot_plug_info.event_type = MPTSAS_DEL_RAID; break; case MPI_EVENT_RAID_RC_VOLUME_CREATED: - ev->event_type = MPTSAS_ADD_RAID; + if (sdev) { + scsi_device_put(sdev); + break; + } + hot_plug_info.event_type = MPTSAS_ADD_RAID; break; case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED: + if (!(status & MPI_RAIDVOL0_STATUS_FLAG_ENABLED)) { + if (!sdev) + break; + vdevice->vtarget->deleted = 1; /* block IO */ + hot_plug_info.event_type = MPTSAS_DEL_RAID; + break; + } switch (state) { case MPI_RAIDVOL0_STATUS_STATE_FAILED: case MPI_RAIDVOL0_STATUS_STATE_MISSING: - ev->event_type = MPTSAS_DEL_RAID; + if (!sdev) + break; + vdevice->vtarget->deleted = 1; /* block IO */ + hot_plug_info.event_type = MPTSAS_DEL_RAID; break; case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL: case MPI_RAIDVOL0_STATUS_STATE_DEGRADED: - ev->event_type = MPTSAS_ADD_RAID; + if (sdev) { + scsi_device_put(sdev); + break; + } + hot_plug_info.event_type = MPTSAS_ADD_RAID; break; default: break; @@ -3001,32 +4335,188 @@ mptsas_send_raid_event(MPT_ADAPTER *ioc, default: break; } - schedule_work(&ev->work); + + if (hot_plug_info.event_type != MPTSAS_IGNORE_EVENT) + mptsas_hotplug_work(ioc, fw_event, &hot_plug_info); + else + mptsas_free_fw_event(ioc, fw_event); } -static void -mptsas_send_discovery_event(MPT_ADAPTER *ioc, - EVENT_DATA_SAS_DISCOVERY *discovery_data) +/** + * mptsas_issue_tm - send mptsas internal tm request + * @ioc: Pointer to MPT_ADAPTER structure + * @type: Task Management type + * @channel: channel number for task management + * @id: Logical Target ID for reset (if appropriate) + * @lun: Logical unit for reset (if appropriate) + * @task_context: Context for the task to be aborted + * @timeout: timeout for task management control + * + * return 0 on success and -1 on failure: + * + */ +static int +mptsas_issue_tm(MPT_ADAPTER *ioc, u8 type, u8 channel, u8 id, u64 lun, + int task_context, ulong timeout, u8 *issue_reset) { - struct mptsas_discovery_event *ev; + MPT_FRAME_HDR *mf; + SCSITaskMgmt_t *pScsiTm; + int retval; + unsigned long timeleft; - /* - * DiscoveryStatus - * - * This flag will be non-zero when firmware - * kicks off discovery, and return to zero - * once its completed. - */ - if (discovery_data->DiscoveryStatus) - return; + *issue_reset = 0; + mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc); + if (mf == NULL) { + retval = -1; /* return failure */ + dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "TaskMgmt request: no " + "msg frames!!\n", ioc->name)); + goto out; + } - ev = kzalloc(sizeof(*ev), GFP_ATOMIC); - if (!ev) + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request: mr = %p, " + "task_type = 0x%02X,\n\t timeout = %ld, fw_channel = %d, " + "fw_id = %d, lun = %lld,\n\t task_context = 0x%x\n", ioc->name, mf, + type, timeout, channel, id, (unsigned long long)lun, + task_context)); + + pScsiTm = (SCSITaskMgmt_t *) mf; + memset(pScsiTm, 0, sizeof(SCSITaskMgmt_t)); + pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT; + pScsiTm->TaskType = type; + pScsiTm->MsgFlags = 0; + pScsiTm->TargetID = id; + pScsiTm->Bus = channel; + pScsiTm->ChainOffset = 0; + pScsiTm->Reserved = 0; + pScsiTm->Reserved1 = 0; + pScsiTm->TaskMsgContext = task_context; + int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN); + + INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status) + CLEAR_MGMT_STATUS(ioc->internal_cmds.status) + retval = 0; + mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf); + + /* Now wait for the command to complete */ + timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done, + timeout*HZ); + if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + retval = -1; /* return failure */ + dtmprintk(ioc, printk(MYIOC_s_ERR_FMT + "TaskMgmt request: TIMED OUT!(mr=%p)\n", ioc->name, mf)); + mpt_free_msg_frame(ioc, mf); + if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) + goto out; + *issue_reset = 1; + goto out; + } + + if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) { + retval = -1; /* return failure */ + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "TaskMgmt request: failed with no reply\n", ioc->name)); + goto out; + } + + out: + CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status) + return retval; +} + +/** + * mptsas_broadcast_primative_work - Handle broadcast primitives + * @work: work queue payload containing info describing the event + * + * this will be handled in workqueue context. + */ +static void +mptsas_broadcast_primative_work(struct fw_event_work *fw_event) +{ + MPT_ADAPTER *ioc = fw_event->ioc; + MPT_FRAME_HDR *mf; + VirtDevice *vdevice; + int ii; + struct scsi_cmnd *sc; + SCSITaskMgmtReply_t *pScsiTmReply; + u8 issue_reset; + int task_context; + u8 channel, id; + int lun; + u32 termination_count; + u32 query_count; + + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s - enter\n", ioc->name, __func__)); + + mutex_lock(&ioc->taskmgmt_cmds.mutex); + if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) { + mutex_unlock(&ioc->taskmgmt_cmds.mutex); + mptsas_requeue_fw_event(ioc, fw_event, 1000); return; - INIT_WORK(&ev->work, mptsas_discovery_work); - ev->ioc = ioc; - schedule_work(&ev->work); -}; + } + + issue_reset = 0; + termination_count = 0; + query_count = 0; + mpt_findImVolumes(ioc); + pScsiTmReply = (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply; + + for (ii = 0; ii < ioc->req_depth; ii++) { + if (ioc->fw_events_off) + goto out; + sc = mptscsih_get_scsi_lookup(ioc, ii); + if (!sc) + continue; + mf = MPT_INDEX_2_MFPTR(ioc, ii); + if (!mf) + continue; + task_context = mf->u.frame.hwhdr.msgctxu.MsgContext; + vdevice = sc->device->hostdata; + if (!vdevice || !vdevice->vtarget) + continue; + if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) + continue; /* skip hidden raid components */ + if (vdevice->vtarget->raidVolume) + continue; /* skip hidden raid components */ + channel = vdevice->vtarget->channel; + id = vdevice->vtarget->id; + lun = vdevice->lun; + if (mptsas_issue_tm(ioc, MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK, + channel, id, (u64)lun, task_context, 30, &issue_reset)) + goto out; + query_count++; + termination_count += + le32_to_cpu(pScsiTmReply->TerminationCount); + if ((pScsiTmReply->IOCStatus == MPI_IOCSTATUS_SUCCESS) && + (pScsiTmReply->ResponseCode == + MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED || + pScsiTmReply->ResponseCode == + MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC)) + continue; + if (mptsas_issue_tm(ioc, + MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET, + channel, id, (u64)lun, 0, 30, &issue_reset)) + goto out; + termination_count += + le32_to_cpu(pScsiTmReply->TerminationCount); + } + + out: + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s - exit, query_count = %d termination_count = %d\n", + ioc->name, __func__, query_count, termination_count)); + + ioc->broadcast_aen_busy = 0; + mpt_clear_taskmgmt_in_progress_flag(ioc); + mutex_unlock(&ioc->taskmgmt_cmds.mutex); + + if (issue_reset) { + printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n", + ioc->name, __func__); + mpt_HardResetHandler(ioc, CAN_SLEEP); + } + mptsas_free_fw_event(ioc, fw_event); +} /* * mptsas_send_ir2_event - handle exposing hidden disk when @@ -3037,76 +4527,159 @@ mptsas_send_discovery_event(MPT_ADAPTER *ioc, * */ static void -mptsas_send_ir2_event(MPT_ADAPTER *ioc, PTR_MPI_EVENT_DATA_IR2 ir2_data) +mptsas_send_ir2_event(struct fw_event_work *fw_event) { - struct mptsas_hotplug_event *ev; + MPT_ADAPTER *ioc; + struct mptsas_hotplug_event hot_plug_info; + MPI_EVENT_DATA_IR2 *ir2_data; + u8 reasonCode; + RaidPhysDiskPage0_t phys_disk; - if (ir2_data->ReasonCode != - MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED) + ioc = fw_event->ioc; + ir2_data = (MPI_EVENT_DATA_IR2 *)fw_event->event_data; + reasonCode = ir2_data->ReasonCode; + + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: " + "ReasonCode=%02x\n", ioc->name, __func__, reasonCode)); + + memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event)); + hot_plug_info.id = ir2_data->TargetID; + hot_plug_info.channel = ir2_data->Bus; + switch (reasonCode) { + case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED: + hot_plug_info.event_type = MPTSAS_ADD_INACTIVE_VOLUME; + break; + case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED: + hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum; + hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK; + break; + case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED: + hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum; + mpt_raid_phys_disk_pg0(ioc, + ir2_data->PhysDiskNum, &phys_disk); + hot_plug_info.id = phys_disk.PhysDiskID; + hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK; + break; + default: + mptsas_free_fw_event(ioc, fw_event); return; - - ev = kzalloc(sizeof(*ev), GFP_ATOMIC); - if (!ev) - return; - - INIT_WORK(&ev->work, mptsas_hotplug_work); - ev->ioc = ioc; - ev->id = ir2_data->TargetID; - ev->channel = ir2_data->Bus; - ev->event_type = MPTSAS_ADD_INACTIVE_VOLUME; - - schedule_work(&ev->work); -}; + } + mptsas_hotplug_work(ioc, fw_event, &hot_plug_info); +} static int mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply) { - int rc=1; - u8 event = le32_to_cpu(reply->Event) & 0xFF; + u32 event = le32_to_cpu(reply->Event); + int sz, event_data_sz; + struct fw_event_work *fw_event; + unsigned long delay; - if (!ioc->sh) - goto out; - - /* - * sas_discovery_ignore_events - * - * This flag is to prevent anymore processing of - * sas events once mptsas_remove function is called. - */ - if (ioc->sas_discovery_ignore_events) { - rc = mptscsih_event_process(ioc, reply); - goto out; - } + /* events turned off due to host reset or driver unloading */ + if (ioc->fw_events_off) + return 0; + delay = msecs_to_jiffies(1); switch (event) { + case MPI_EVENT_SAS_BROADCAST_PRIMITIVE: + { + EVENT_DATA_SAS_BROADCAST_PRIMITIVE *broadcast_event_data = + (EVENT_DATA_SAS_BROADCAST_PRIMITIVE *)reply->Data; + if (broadcast_event_data->Primitive != + MPI_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT) + return 0; + if (ioc->broadcast_aen_busy) + return 0; + ioc->broadcast_aen_busy = 1; + break; + } case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: - mptsas_send_sas_event(ioc, - (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data); + { + EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data = + (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data; + + if (sas_event_data->ReasonCode == + MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING) { + mptsas_target_reset_queue(ioc, sas_event_data); + return 0; + } break; + } + case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE: + { + MpiEventDataSasExpanderStatusChange_t *expander_data = + (MpiEventDataSasExpanderStatusChange_t *)reply->Data; + + if (ioc->old_sas_discovery_protocal) + return 0; + + if (expander_data->ReasonCode == + MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING && + ioc->device_missing_delay) + delay = HZ * ioc->device_missing_delay; + break; + } + case MPI_EVENT_SAS_DISCOVERY: + { + u32 discovery_status; + EventDataSasDiscovery_t *discovery_data = + (EventDataSasDiscovery_t *)reply->Data; + + discovery_status = le32_to_cpu(discovery_data->DiscoveryStatus); + ioc->sas_discovery_quiesce_io = discovery_status ? 1 : 0; + if (ioc->old_sas_discovery_protocal && !discovery_status) + mptsas_queue_rescan(ioc); + return 0; + } case MPI_EVENT_INTEGRATED_RAID: - mptsas_send_raid_event(ioc, - (EVENT_DATA_RAID *)reply->Data); - break; case MPI_EVENT_PERSISTENT_TABLE_FULL: - INIT_WORK(&ioc->sas_persist_task, - mptsas_persist_clear_table); - schedule_work(&ioc->sas_persist_task); - break; - case MPI_EVENT_SAS_DISCOVERY: - mptsas_send_discovery_event(ioc, - (EVENT_DATA_SAS_DISCOVERY *)reply->Data); - break; case MPI_EVENT_IR2: - mptsas_send_ir2_event(ioc, - (PTR_MPI_EVENT_DATA_IR2)reply->Data); + case MPI_EVENT_SAS_PHY_LINK_STATUS: + case MPI_EVENT_QUEUE_FULL: break; default: - rc = mptscsih_event_process(ioc, reply); - break; + return 0; } - out: - return rc; + event_data_sz = ((reply->MsgLength * 4) - + offsetof(EventNotificationReply_t, Data)); + sz = offsetof(struct fw_event_work, event_data) + event_data_sz; + fw_event = kzalloc(sz, GFP_ATOMIC); + if (!fw_event) { + printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", ioc->name, + __func__, __LINE__); + return 0; + } + memcpy(fw_event->event_data, reply->Data, event_data_sz); + fw_event->event = event; + fw_event->ioc = ioc; + mptsas_add_fw_event(ioc, fw_event, delay); + return 0; +} + +/* Delete a volume when no longer listed in ioc pg2 + */ +static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id) +{ + struct scsi_device *sdev; + int i; + + sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, id, 0); + if (!sdev) + return; + if (!ioc->raid_data.pIocPg2) + goto out; + if (!ioc->raid_data.pIocPg2->NumActiveVolumes) + goto out; + for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) + if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == id) + goto release_sdev; + out: + printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, " + "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, id); + scsi_remove_device(sdev); + release_sdev: + scsi_device_put(sdev); } static int @@ -3128,6 +4701,7 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) return r; ioc = pci_get_drvdata(pdev); + mptsas_fw_event_off(ioc); ioc->DoneCtx = mptsasDoneCtx; ioc->TaskCtx = mptsasTaskCtx; ioc->InternalCtx = mptsasInternalCtx; @@ -3211,17 +4785,15 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) * A slightly different algorithm is required for * 64bit SGEs. */ - scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32)); - if (sizeof(dma_addr_t) == sizeof(u64)) { + scale = ioc->req_sz/ioc->SGE_size; + if (ioc->sg_addr_size == sizeof(u64)) { numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale + - (ioc->req_sz - 60) / (sizeof(dma_addr_t) + - sizeof(u32)); + (ioc->req_sz - 60) / ioc->SGE_size; } else { numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale + - (ioc->req_sz - 64) / (sizeof(dma_addr_t) + - sizeof(u32)); + (ioc->req_sz - 64) / ioc->SGE_size; } if (numSGE < sh->sg_tablesize) { @@ -3251,9 +4823,6 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) /* Clear the TM flags */ - hd->tmPending = 0; - hd->tmState = TM_STATE_NONE; - hd->resetPending = 0; hd->abortSCpnt = NULL; /* Clear the pointer used to store @@ -3273,10 +4842,11 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) ioc->sas_data.ptClear = mpt_pt_clear; - init_waitqueue_head(&hd->scandv_waitq); - hd->scandv_wait_done = 0; hd->last_queue_full = 0; INIT_LIST_HEAD(&hd->target_reset_list); + INIT_LIST_HEAD(&ioc->sas_device_info_list); + mutex_init(&ioc->sas_device_info_mutex); + spin_unlock_irqrestore(&ioc->FreeQlock, flags); if (ioc->sas_data.ptClear==1) { @@ -3291,8 +4861,11 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto out_mptsas_probe; } + /* older firmware doesn't support expander events */ + if ((ioc->facts.HeaderVersion >> 8) < 0xE) + ioc->old_sas_discovery_protocal = 1; mptsas_scan_sas_topology(ioc); - + mptsas_fw_event_on(ioc); return 0; out_mptsas_probe: @@ -3301,12 +4874,25 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) return error; } +void +mptsas_shutdown(struct pci_dev *pdev) +{ + MPT_ADAPTER *ioc = pci_get_drvdata(pdev); + + mptsas_fw_event_off(ioc); + mptsas_cleanup_fw_event_q(ioc); +} + static void __devexit mptsas_remove(struct pci_dev *pdev) { MPT_ADAPTER *ioc = pci_get_drvdata(pdev); struct mptsas_portinfo *p, *n; int i; + mptsas_shutdown(pdev); + + mptsas_del_device_components(ioc); + ioc->sas_discovery_ignore_events = 1; sas_remove_host(ioc->sh); @@ -3315,11 +4901,12 @@ static void __devexit mptsas_remove(struct pci_dev *pdev) list_del(&p->list); for (i = 0 ; i < p->num_phys ; i++) mptsas_port_delete(ioc, p->phy_info[i].port_details); + kfree(p->phy_info); kfree(p); } mutex_unlock(&ioc->sas_topology_mutex); - + ioc->hba_port_info = NULL; mptscsih_remove(pdev); } @@ -3344,7 +4931,7 @@ static struct pci_driver mptsas_driver = { .id_table = mptsas_pci_table, .probe = mptsas_probe, .remove = __devexit_p(mptsas_remove), - .shutdown = mptscsih_shutdown, + .shutdown = mptsas_shutdown, #ifdef CONFIG_PM .suspend = mptscsih_suspend, .resume = mptscsih_resume, @@ -3364,10 +4951,12 @@ mptsas_init(void) return -ENODEV; mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER); - mptsasTaskCtx = mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER); + mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER); mptsasInternalCtx = mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER); mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER); + mptsasDeviceResetCtx = + mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER); mpt_event_register(mptsasDoneCtx, mptsas_event_process); mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset); @@ -3392,6 +4981,7 @@ mptsas_exit(void) mpt_deregister(mptsasInternalCtx); mpt_deregister(mptsasTaskCtx); mpt_deregister(mptsasDoneCtx); + mpt_deregister(mptsasDeviceResetCtx); } module_init(mptsas_init); diff --git a/drivers/message/fusion/mptsas.h b/drivers/message/fusion/mptsas.h index 2b544e0877e6..953c2bfcf6aa 100644 --- a/drivers/message/fusion/mptsas.h +++ b/drivers/message/fusion/mptsas.h @@ -53,6 +53,7 @@ struct mptsas_target_reset_event { struct list_head list; EVENT_DATA_SAS_DEVICE_STATUS_CHANGE sas_event_data; u8 target_reset_issued; + unsigned long time_count; }; enum mptsas_hotplug_action { @@ -60,12 +61,37 @@ enum mptsas_hotplug_action { MPTSAS_DEL_DEVICE, MPTSAS_ADD_RAID, MPTSAS_DEL_RAID, + MPTSAS_ADD_PHYSDISK, + MPTSAS_ADD_PHYSDISK_REPROBE, + MPTSAS_DEL_PHYSDISK, + MPTSAS_DEL_PHYSDISK_REPROBE, MPTSAS_ADD_INACTIVE_VOLUME, MPTSAS_IGNORE_EVENT, }; +struct mptsas_mapping{ + u8 id; + u8 channel; +}; + +struct mptsas_device_info { + struct list_head list; + struct mptsas_mapping os; /* operating system mapping*/ + struct mptsas_mapping fw; /* firmware mapping */ + u64 sas_address; + u32 device_info; /* specific bits for devices */ + u16 slot; /* enclosure slot id */ + u64 enclosure_logical_id; /*enclosure address */ + u8 is_logical_volume; /* is this logical volume */ + /* this belongs to volume */ + u8 is_hidden_raid_component; + /* this valid when is_hidden_raid_component set */ + u8 volume_id; + /* cached data for a removed device */ + u8 is_cached; +}; + struct mptsas_hotplug_event { - struct work_struct work; MPT_ADAPTER *ioc; enum mptsas_hotplug_action event_type; u64 sas_address; @@ -73,11 +99,18 @@ struct mptsas_hotplug_event { u8 id; u32 device_info; u16 handle; - u16 parent_handle; u8 phy_id; - u8 phys_disk_num_valid; /* hrc (hidden raid component) */ u8 phys_disk_num; /* hrc - unique index*/ - u8 hidden_raid_component; /* hrc - don't expose*/ + struct scsi_device *sdev; +}; + +struct fw_event_work { + struct list_head list; + struct delayed_work work; + MPT_ADAPTER *ioc; + u32 event; + u8 retries; + u8 event_data[1]; }; struct mptsas_discovery_event { diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index e62c6bc4ad33..8440f78f6969 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -80,7 +80,7 @@ MODULE_VERSION(my_VERSION); /* * Other private/forward protos... */ -static struct scsi_cmnd * mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i); +struct scsi_cmnd *mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i); static struct scsi_cmnd * mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i); static void mptscsih_set_scsi_lookup(MPT_ADAPTER *ioc, int i, struct scsi_cmnd *scmd); static int SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *scmd); @@ -92,18 +92,24 @@ static int mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt, SCSIIORequest_t *pReq, int req_idx); static void mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx); static void mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply); -static int mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd); -static int mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout ); -static int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout); +int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, + int lun, int ctx2abort, ulong timeout); int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset); int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply); +void +mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code); +static int mptscsih_get_completion_code(MPT_ADAPTER *ioc, + MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply); int mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r); static int mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd); static void mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice); +static int +mptscsih_taskmgmt_reply(MPT_ADAPTER *ioc, u8 type, + SCSITaskMgmtReply_t *pScsiTmReply); void mptscsih_remove(struct pci_dev *); void mptscsih_shutdown(struct pci_dev *); #ifdef CONFIG_PM @@ -113,69 +119,6 @@ int mptscsih_resume(struct pci_dev *pdev); #define SNS_LEN(scp) SCSI_SENSE_BUFFERSIZE -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/** - * mptscsih_add_sge - Place a simple SGE at address pAddr. - * @pAddr: virtual address for SGE - * @flagslength: SGE flags and data transfer length - * @dma_addr: Physical address - * - * This routine places a MPT request frame back on the MPT adapter's - * FreeQ. - */ -static inline void -mptscsih_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr) -{ - if (sizeof(dma_addr_t) == sizeof(u64)) { - SGESimple64_t *pSge = (SGESimple64_t *) pAddr; - u32 tmp = dma_addr & 0xFFFFFFFF; - - pSge->FlagsLength = cpu_to_le32(flagslength); - pSge->Address.Low = cpu_to_le32(tmp); - tmp = (u32) ((u64)dma_addr >> 32); - pSge->Address.High = cpu_to_le32(tmp); - - } else { - SGESimple32_t *pSge = (SGESimple32_t *) pAddr; - pSge->FlagsLength = cpu_to_le32(flagslength); - pSge->Address = cpu_to_le32(dma_addr); - } -} /* mptscsih_add_sge() */ - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/** - * mptscsih_add_chain - Place a chain SGE at address pAddr. - * @pAddr: virtual address for SGE - * @next: nextChainOffset value (u32's) - * @length: length of next SGL segment - * @dma_addr: Physical address - * - * This routine places a MPT request frame back on the MPT adapter's - * FreeQ. - */ -static inline void -mptscsih_add_chain(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr) -{ - if (sizeof(dma_addr_t) == sizeof(u64)) { - SGEChain64_t *pChain = (SGEChain64_t *) pAddr; - u32 tmp = dma_addr & 0xFFFFFFFF; - - pChain->Length = cpu_to_le16(length); - pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size(); - - pChain->NextChainOffset = next; - - pChain->Address.Low = cpu_to_le32(tmp); - tmp = (u32) ((u64)dma_addr >> 32); - pChain->Address.High = cpu_to_le32(tmp); - } else { - SGEChain32_t *pChain = (SGEChain32_t *) pAddr; - pChain->Length = cpu_to_le16(length); - pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size(); - pChain->NextChainOffset = next; - pChain->Address = cpu_to_le32(dma_addr); - } -} /* mptscsih_add_chain() */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* @@ -281,10 +224,10 @@ mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt, */ nextSGEset: - numSgeSlots = ((frm_sz - sgeOffset) / (sizeof(u32) + sizeof(dma_addr_t)) ); + numSgeSlots = ((frm_sz - sgeOffset) / ioc->SGE_size); numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots; - sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | MPT_SGE_FLAGS_ADDRESSING | sgdir; + sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | sgdir; /* Get first (num - 1) SG elements * Skip any SG entries with a length of 0 @@ -293,17 +236,19 @@ nextSGEset: for (ii=0; ii < (numSgeThisFrame-1); ii++) { thisxfer = sg_dma_len(sg); if (thisxfer == 0) { - sg = sg_next(sg); /* Get next SG element from the OS */ + /* Get next SG element from the OS */ + sg = sg_next(sg); sg_done++; continue; } v2 = sg_dma_address(sg); - mptscsih_add_sge(psge, sgflags | thisxfer, v2); + ioc->add_sge(psge, sgflags | thisxfer, v2); - sg = sg_next(sg); /* Get next SG element from the OS */ - psge += (sizeof(u32) + sizeof(dma_addr_t)); - sgeOffset += (sizeof(u32) + sizeof(dma_addr_t)); + /* Get next SG element from the OS */ + sg = sg_next(sg); + psge += ioc->SGE_size; + sgeOffset += ioc->SGE_size; sg_done++; } @@ -320,12 +265,8 @@ nextSGEset: thisxfer = sg_dma_len(sg); v2 = sg_dma_address(sg); - mptscsih_add_sge(psge, sgflags | thisxfer, v2); - /* - sg = sg_next(sg); - psge += (sizeof(u32) + sizeof(dma_addr_t)); - */ - sgeOffset += (sizeof(u32) + sizeof(dma_addr_t)); + ioc->add_sge(psge, sgflags | thisxfer, v2); + sgeOffset += ioc->SGE_size; sg_done++; if (chainSge) { @@ -334,7 +275,8 @@ nextSGEset: * Update the chain element * Offset and Length fields. */ - mptscsih_add_chain((char *)chainSge, 0, sgeOffset, ioc->ChainBufferDMA + chain_dma_off); + ioc->add_chain((char *)chainSge, 0, sgeOffset, + ioc->ChainBufferDMA + chain_dma_off); } else { /* The current buffer is the original MF * and there is no Chain buffer. @@ -367,7 +309,7 @@ nextSGEset: * set properly). */ if (sg_done) { - u32 *ptmp = (u32 *) (psge - (sizeof(u32) + sizeof(dma_addr_t))); + u32 *ptmp = (u32 *) (psge - ioc->SGE_size); sgflags = le32_to_cpu(*ptmp); sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT; *ptmp = cpu_to_le32(sgflags); @@ -381,8 +323,9 @@ nextSGEset: * Old chain element is now complete. */ u8 nextChain = (u8) (sgeOffset >> 2); - sgeOffset += (sizeof(u32) + sizeof(dma_addr_t)); - mptscsih_add_chain((char *)chainSge, nextChain, sgeOffset, ioc->ChainBufferDMA + chain_dma_off); + sgeOffset += ioc->SGE_size; + ioc->add_chain((char *)chainSge, nextChain, sgeOffset, + ioc->ChainBufferDMA + chain_dma_off); } else { /* The original MF buffer requires a chain buffer - * set the offset. @@ -592,14 +535,15 @@ mptscsih_info_scsiio(MPT_ADAPTER *ioc, struct scsi_cmnd *sc, SCSIIOReply_t * pSc } scsi_print_command(sc); - printk(MYIOC_s_DEBUG_FMT "\tfw_channel = %d, fw_id = %d\n", - ioc->name, pScsiReply->Bus, pScsiReply->TargetID); + printk(MYIOC_s_DEBUG_FMT "\tfw_channel = %d, fw_id = %d, lun = %d\n", + ioc->name, pScsiReply->Bus, pScsiReply->TargetID, sc->device->lun); printk(MYIOC_s_DEBUG_FMT "\trequest_len = %d, underflow = %d, " "resid = %d\n", ioc->name, scsi_bufflen(sc), sc->underflow, scsi_get_resid(sc)); printk(MYIOC_s_DEBUG_FMT "\ttag = %d, transfer_count = %d, " "sc->result = %08X\n", ioc->name, le16_to_cpu(pScsiReply->TaskTag), le32_to_cpu(pScsiReply->TransferCount), sc->result); + printk(MYIOC_s_DEBUG_FMT "\tiocstatus = %s (0x%04x), " "scsi_status = %s (0x%02x), scsi_state = (0x%02x)\n", ioc->name, desc, ioc_status, desc1, pScsiReply->SCSIStatus, @@ -654,16 +598,14 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); req_idx_MR = (mr != NULL) ? le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx) : req_idx; + + /* Special case, where already freed message frame is received from + * Firmware. It happens with Resetting IOC. + * Return immediately. Do not care + */ if ((req_idx != req_idx_MR) || - (mf->u.frame.linkage.arg1 == 0xdeadbeaf)) { - printk(MYIOC_s_ERR_FMT "Received a mf that was already freed\n", - ioc->name); - printk (MYIOC_s_ERR_FMT - "req_idx=%x req_idx_MR=%x mf=%p mr=%p sc=%p\n", - ioc->name, req_idx, req_idx_MR, mf, mr, - mptscsih_get_scsi_lookup(ioc, req_idx_MR)); + (le32_to_cpu(mf->u.frame.linkage.arg1) == 0xdeadbeaf)) return 0; - } sc = mptscsih_getclear_scsi_lookup(ioc, req_idx); if (sc == NULL) { @@ -810,12 +752,16 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) */ case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */ - case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */ /* Linux handles an unsolicited DID_RESET better * than an unsolicited DID_ABORT. */ sc->result = DID_RESET << 16; + case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */ + if (ioc->bus_type == FC) + sc->result = DID_ERROR << 16; + else + sc->result = DID_RESET << 16; break; case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */ @@ -992,9 +938,9 @@ mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd) scsi_dma_unmap(sc); sc->result = DID_RESET << 16; sc->host_scribble = NULL; - sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT - "completing cmds: fw_channel %d, fw_id %d, sc=%p," - " mf = %p, idx=%x\n", ioc->name, channel, id, sc, mf, ii); + dtmprintk(ioc, sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT + "completing cmds: fw_channel %d, fw_id %d, sc=%p, mf = %p, " + "idx=%x\n", ioc->name, channel, id, sc, mf, ii)); sc->scsi_done(sc); } } @@ -1053,9 +999,11 @@ mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice) scsi_dma_unmap(sc); sc->host_scribble = NULL; sc->result = DID_NO_CONNECT << 16; - sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT "completing cmds: fw_channel %d," - "fw_id %d, sc=%p, mf = %p, idx=%x\n", ioc->name, vdevice->vtarget->channel, - vdevice->vtarget->id, sc, mf, ii); + dtmprintk(ioc, sdev_printk(KERN_INFO, sc->device, + MYIOC_s_FMT "completing cmds: fw_channel %d, " + "fw_id %d, sc=%p, mf = %p, idx=%x\n", ioc->name, + vdevice->vtarget->channel, vdevice->vtarget->id, + sc, mf, ii)); sc->scsi_done(sc); spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); } @@ -1346,7 +1294,6 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) MPT_FRAME_HDR *mf; SCSIIORequest_t *pScsiReq; VirtDevice *vdevice = SCpnt->device->hostdata; - int lun; u32 datalen; u32 scsictl; u32 scsidir; @@ -1357,13 +1304,12 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) hd = shost_priv(SCpnt->device->host); ioc = hd->ioc; - lun = SCpnt->device->lun; SCpnt->scsi_done = done; dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "qcmd: SCpnt=%p, done()=%p\n", ioc->name, SCpnt, done)); - if (hd->resetPending) { + if (ioc->taskmgmt_quiesce_io) { dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n", ioc->name, SCpnt)); return SCSI_MLQUEUE_HOST_BUSY; @@ -1422,7 +1368,7 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) pScsiReq->CDBLength = SCpnt->cmd_len; pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE; pScsiReq->Reserved = 0; - pScsiReq->MsgFlags = mpt_msg_flags(); + pScsiReq->MsgFlags = mpt_msg_flags(ioc); int_to_scsilun(SCpnt->device->lun, (struct scsi_lun *)pScsiReq->LUN); pScsiReq->Control = cpu_to_le32(scsictl); @@ -1448,7 +1394,8 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) */ if (datalen == 0) { /* Add a NULL SGE */ - mptscsih_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0, + ioc->add_sge((char *)&pScsiReq->SGL, + MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1); } else { /* Add a 32 or 64 bit SGE */ @@ -1526,120 +1473,6 @@ mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx) * Reset Handling */ -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/** - * mptscsih_TMHandler - Generic handler for SCSI Task Management. - * @hd: Pointer to MPT SCSI HOST structure - * @type: Task Management type - * @channel: channel number for task management - * @id: Logical Target ID for reset (if appropriate) - * @lun: Logical Unit for reset (if appropriate) - * @ctx2abort: Context for the task to be aborted (if appropriate) - * @timeout: timeout for task management control - * - * Fall through to mpt_HardResetHandler if: not operational, too many - * failed TM requests or handshake failure. - * - * Remark: Currently invoked from a non-interrupt thread (_bh). - * - * Note: With old EH code, at most 1 SCSI TaskMgmt function per IOC - * will be active. - * - * Returns 0 for SUCCESS, or %FAILED. - **/ -int -mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout) -{ - MPT_ADAPTER *ioc; - int rc = -1; - u32 ioc_raw_state; - unsigned long flags; - - ioc = hd->ioc; - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler Entered!\n", ioc->name)); - - // SJR - CHECKME - Can we avoid this here? - // (mpt_HardResetHandler has this check...) - spin_lock_irqsave(&ioc->diagLock, flags); - if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)) { - spin_unlock_irqrestore(&ioc->diagLock, flags); - return FAILED; - } - spin_unlock_irqrestore(&ioc->diagLock, flags); - - /* Wait a fixed amount of time for the TM pending flag to be cleared. - * If we time out and not bus reset, then we return a FAILED status - * to the caller. - * The call to mptscsih_tm_pending_wait() will set the pending flag - * if we are - * successful. Otherwise, reload the FW. - */ - if (mptscsih_tm_pending_wait(hd) == FAILED) { - if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) { - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler abort: " - "Timed out waiting for last TM (%d) to complete! \n", - ioc->name, hd->tmPending)); - return FAILED; - } else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) { - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler target " - "reset: Timed out waiting for last TM (%d) " - "to complete! \n", ioc->name, - hd->tmPending)); - return FAILED; - } else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) { - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler bus reset: " - "Timed out waiting for last TM (%d) to complete! \n", - ioc->name, hd->tmPending)); - return FAILED; - } - } else { - spin_lock_irqsave(&ioc->FreeQlock, flags); - hd->tmPending |= (1 << type); - spin_unlock_irqrestore(&ioc->FreeQlock, flags); - } - - ioc_raw_state = mpt_GetIocState(ioc, 0); - - if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) { - printk(MYIOC_s_WARN_FMT - "TM Handler for type=%x: IOC Not operational (0x%x)!\n", - ioc->name, type, ioc_raw_state); - printk(MYIOC_s_WARN_FMT " Issuing HardReset!!\n", ioc->name); - if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0) - printk(MYIOC_s_WARN_FMT "TMHandler: HardReset " - "FAILED!!\n", ioc->name); - return FAILED; - } - - if (ioc_raw_state & MPI_DOORBELL_ACTIVE) { - printk(MYIOC_s_WARN_FMT - "TM Handler for type=%x: ioc_state: " - "DOORBELL_ACTIVE (0x%x)!\n", - ioc->name, type, ioc_raw_state); - return FAILED; - } - - /* Isse the Task Mgmt request. - */ - if (hd->hard_resets < -1) - hd->hard_resets++; - - rc = mptscsih_IssueTaskMgmt(hd, type, channel, id, lun, - ctx2abort, timeout); - if (rc) - printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n", - ioc->name); - else - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Issue of TaskMgmt Successful!\n", - ioc->name)); - - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "TMHandler rc = %d!\n", ioc->name, rc)); - - return rc; -} - - /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mptscsih_IssueTaskMgmt - Generic send Task Management function. @@ -1659,23 +1492,60 @@ mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int c * Returns 0 for SUCCESS, or FAILED. * **/ -static int -mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout) +int +mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, + int ctx2abort, ulong timeout) { MPT_FRAME_HDR *mf; SCSITaskMgmt_t *pScsiTm; int ii; int retval; MPT_ADAPTER *ioc = hd->ioc; + unsigned long timeleft; + u8 issue_hard_reset; + u32 ioc_raw_state; + unsigned long time_count; + + issue_hard_reset = 0; + ioc_raw_state = mpt_GetIocState(ioc, 0); + + if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) { + printk(MYIOC_s_WARN_FMT + "TaskMgmt type=%x: IOC Not operational (0x%x)!\n", + ioc->name, type, ioc_raw_state); + printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n", + ioc->name, __func__); + if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0) + printk(MYIOC_s_WARN_FMT "TaskMgmt HardReset " + "FAILED!!\n", ioc->name); + return 0; + } + + if (ioc_raw_state & MPI_DOORBELL_ACTIVE) { + printk(MYIOC_s_WARN_FMT + "TaskMgmt type=%x: ioc_state: " + "DOORBELL_ACTIVE (0x%x)!\n", + ioc->name, type, ioc_raw_state); + return FAILED; + } + + mutex_lock(&ioc->taskmgmt_cmds.mutex); + if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) { + mf = NULL; + retval = FAILED; + goto out; + } /* Return Fail to calling function if no message frames available. */ if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) { - dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n", - ioc->name)); - return FAILED; + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "TaskMgmt no msg frames!!\n", ioc->name)); + retval = FAILED; + mpt_clear_taskmgmt_in_progress_flag(ioc); + goto out; } - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt request @ %p\n", + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n", ioc->name, mf)); /* Format the Request @@ -1699,11 +1569,14 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, i pScsiTm->TaskMsgContext = ctx2abort; - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt: ctx2abort (0x%08x) " - "type=%d\n", ioc->name, ctx2abort, type)); + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt: ctx2abort (0x%08x) " + "task_type = 0x%02X, timeout = %ld\n", ioc->name, ctx2abort, + type, timeout)); DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)pScsiTm); + INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status) + time_count = jiffies; if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) && (ioc->facts.MsgVersion >= MPI_VERSION_01_05)) mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf); @@ -1711,47 +1584,50 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, i retval = mpt_send_handshake_request(ioc->TaskCtx, ioc, sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP); if (retval) { - dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "send_handshake FAILED!" - " (hd %p, ioc %p, mf %p, rc=%d) \n", ioc->name, hd, - ioc, mf, retval)); - goto fail_out; + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "TaskMgmt handshake FAILED!(mf=%p, rc=%d) \n", + ioc->name, mf, retval)); + mpt_free_msg_frame(ioc, mf); + mpt_clear_taskmgmt_in_progress_flag(ioc); + goto out; } } - if(mptscsih_tm_wait_for_completion(hd, timeout) == FAILED) { - dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "task management request TIMED OUT!" - " (hd %p, ioc %p, mf %p) \n", ioc->name, hd, - ioc, mf)); - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling HardReset! \n", - ioc->name)); - retval = mpt_HardResetHandler(ioc, CAN_SLEEP); - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "rc=%d \n", - ioc->name, retval)); - goto fail_out; + timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done, + timeout*HZ); + if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + retval = FAILED; + dtmprintk(ioc, printk(MYIOC_s_ERR_FMT + "TaskMgmt TIMED OUT!(mf=%p)\n", ioc->name, mf)); + mpt_clear_taskmgmt_in_progress_flag(ioc); + if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) + goto out; + issue_hard_reset = 1; + goto out; } - /* - * Handle success case, see if theres a non-zero ioc_status. - */ - if (hd->tm_iocstatus == MPI_IOCSTATUS_SUCCESS || - hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED || - hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED) - retval = 0; - else - retval = FAILED; + retval = mptscsih_taskmgmt_reply(ioc, type, + (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply); + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "TaskMgmt completed (%d seconds)\n", + ioc->name, jiffies_to_msecs(jiffies - time_count)/1000)); + + out: + + CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status) + if (issue_hard_reset) { + printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n", + ioc->name, __func__); + retval = mpt_HardResetHandler(ioc, CAN_SLEEP); + mpt_free_msg_frame(ioc, mf); + } + + retval = (retval == 0) ? 0 : FAILED; + mutex_unlock(&ioc->taskmgmt_cmds.mutex); return retval; - - fail_out: - - /* - * Free task management mf, and corresponding tm flags - */ - mpt_free_msg_frame(ioc, mf); - hd->tmPending = 0; - hd->tmState = TM_STATE_NONE; - return FAILED; } +EXPORT_SYMBOL(mptscsih_IssueTaskMgmt); static int mptscsih_get_tm_timeout(MPT_ADAPTER *ioc) @@ -1838,13 +1714,8 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) goto out; } - if (hd->resetPending) { - retval = FAILED; - goto out; - } - - if (hd->timeouts < -1) - hd->timeouts++; + if (ioc->timeouts < -1) + ioc->timeouts++; if (mpt_fwfault_debug) mpt_halt_firmware(ioc); @@ -1861,22 +1732,30 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) hd->abortSCpnt = SCpnt; - retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK, - vdevice->vtarget->channel, vdevice->vtarget->id, vdevice->lun, - ctx2abort, mptscsih_get_tm_timeout(ioc)); + retval = mptscsih_IssueTaskMgmt(hd, + MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK, + vdevice->vtarget->channel, + vdevice->vtarget->id, vdevice->lun, + ctx2abort, mptscsih_get_tm_timeout(ioc)); if (SCPNT_TO_LOOKUP_IDX(ioc, SCpnt) == scpnt_idx && - SCpnt->serial_number == sn) + SCpnt->serial_number == sn) { + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "task abort: command still in active list! (sc=%p)\n", + ioc->name, SCpnt)); retval = FAILED; + } else { + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "task abort: command cleared from active list! (sc=%p)\n", + ioc->name, SCpnt)); + retval = SUCCESS; + } out: printk(MYIOC_s_INFO_FMT "task abort: %s (sc=%p)\n", - ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt); + ioc->name, ((retval == SUCCESS) ? "SUCCESS" : "FAILED"), SCpnt); - if (retval == 0) - return SUCCESS; - else - return FAILED; + return retval; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -1909,14 +1788,9 @@ mptscsih_dev_reset(struct scsi_cmnd * SCpnt) ioc->name, SCpnt); scsi_print_command(SCpnt); - if (hd->resetPending) { - retval = FAILED; - goto out; - } - vdevice = SCpnt->device->hostdata; if (!vdevice || !vdevice->vtarget) { - retval = 0; + retval = SUCCESS; goto out; } @@ -1927,9 +1801,11 @@ mptscsih_dev_reset(struct scsi_cmnd * SCpnt) goto out; } - retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, - vdevice->vtarget->channel, vdevice->vtarget->id, 0, 0, - mptscsih_get_tm_timeout(ioc)); + retval = mptscsih_IssueTaskMgmt(hd, + MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, + vdevice->vtarget->channel, + vdevice->vtarget->id, 0, 0, + mptscsih_get_tm_timeout(ioc)); out: printk (MYIOC_s_INFO_FMT "target reset: %s (sc=%p)\n", @@ -1972,12 +1848,16 @@ mptscsih_bus_reset(struct scsi_cmnd * SCpnt) ioc->name, SCpnt); scsi_print_command(SCpnt); - if (hd->timeouts < -1) - hd->timeouts++; + if (ioc->timeouts < -1) + ioc->timeouts++; vdevice = SCpnt->device->hostdata; - retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, - vdevice->vtarget->channel, 0, 0, 0, mptscsih_get_tm_timeout(ioc)); + if (!vdevice || !vdevice->vtarget) + return SUCCESS; + retval = mptscsih_IssueTaskMgmt(hd, + MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, + vdevice->vtarget->channel, 0, 0, 0, + mptscsih_get_tm_timeout(ioc)); printk(MYIOC_s_INFO_FMT "bus reset: %s (sc=%p)\n", ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt); @@ -2001,8 +1881,9 @@ int mptscsih_host_reset(struct scsi_cmnd *SCpnt) { MPT_SCSI_HOST * hd; - int retval; + int status = SUCCESS; MPT_ADAPTER *ioc; + int retval; /* If we can't locate the host to reset, then we failed. */ if ((hd = shost_priv(SCpnt->device->host)) == NULL){ @@ -2021,86 +1902,71 @@ mptscsih_host_reset(struct scsi_cmnd *SCpnt) /* If our attempts to reset the host failed, then return a failed * status. The host will be taken off line by the SCSI mid-layer. */ - if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0) { - retval = FAILED; - } else { - /* Make sure TM pending is cleared and TM state is set to - * NONE. - */ - retval = 0; - hd->tmPending = 0; - hd->tmState = TM_STATE_NONE; - } + retval = mpt_HardResetHandler(ioc, CAN_SLEEP); + if (retval < 0) + status = FAILED; + else + status = SUCCESS; printk(MYIOC_s_INFO_FMT "host reset: %s (sc=%p)\n", ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt); + return status; +} + +static int +mptscsih_taskmgmt_reply(MPT_ADAPTER *ioc, u8 type, + SCSITaskMgmtReply_t *pScsiTmReply) +{ + u16 iocstatus; + u32 termination_count; + int retval; + + if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) { + retval = FAILED; + goto out; + } + + DBG_DUMP_TM_REPLY_FRAME(ioc, (u32 *)pScsiTmReply); + + iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK; + termination_count = le32_to_cpu(pScsiTmReply->TerminationCount); + + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "TaskMgmt fw_channel = %d, fw_id = %d, task_type = 0x%02X,\n" + "\tiocstatus = 0x%04X, loginfo = 0x%08X, response_code = 0x%02X,\n" + "\tterm_cmnds = %d\n", ioc->name, pScsiTmReply->Bus, + pScsiTmReply->TargetID, type, le16_to_cpu(pScsiTmReply->IOCStatus), + le32_to_cpu(pScsiTmReply->IOCLogInfo), pScsiTmReply->ResponseCode, + termination_count)); + + if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 && + pScsiTmReply->ResponseCode) + mptscsih_taskmgmt_response_code(ioc, + pScsiTmReply->ResponseCode); + + if (iocstatus == MPI_IOCSTATUS_SUCCESS) { + retval = 0; + goto out; + } + + retval = FAILED; + if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) { + if (termination_count == 1) + retval = 0; + goto out; + } + + if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED || + iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED) + retval = 0; + + out: return retval; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/** - * mptscsih_tm_pending_wait - wait for pending task management request to complete - * @hd: Pointer to MPT host structure. - * - * Returns {SUCCESS,FAILED}. - */ -static int -mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd) -{ - unsigned long flags; - int loop_count = 4 * 10; /* Wait 10 seconds */ - int status = FAILED; - MPT_ADAPTER *ioc = hd->ioc; - - do { - spin_lock_irqsave(&ioc->FreeQlock, flags); - if (hd->tmState == TM_STATE_NONE) { - hd->tmState = TM_STATE_IN_PROGRESS; - hd->tmPending = 1; - spin_unlock_irqrestore(&ioc->FreeQlock, flags); - status = SUCCESS; - break; - } - spin_unlock_irqrestore(&ioc->FreeQlock, flags); - msleep(250); - } while (--loop_count); - - return status; -} - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/** - * mptscsih_tm_wait_for_completion - wait for completion of TM task - * @hd: Pointer to MPT host structure. - * @timeout: timeout value - * - * Returns {SUCCESS,FAILED}. - */ -static int -mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout ) -{ - unsigned long flags; - int loop_count = 4 * timeout; - int status = FAILED; - MPT_ADAPTER *ioc = hd->ioc; - - do { - spin_lock_irqsave(&ioc->FreeQlock, flags); - if(hd->tmPending == 0) { - status = SUCCESS; - spin_unlock_irqrestore(&ioc->FreeQlock, flags); - break; - } - spin_unlock_irqrestore(&ioc->FreeQlock, flags); - msleep(250); - } while (--loop_count); - - return status; -} - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -static void +void mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code) { char *desc; @@ -2134,6 +2000,7 @@ mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code) printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n", ioc->name, response_code, desc); } +EXPORT_SYMBOL(mptscsih_taskmgmt_response_code); /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** @@ -2150,97 +2017,28 @@ mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code) * Returns 1 indicating alloc'd request frame ptr should be freed. **/ int -mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) +mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, + MPT_FRAME_HDR *mr) { - SCSITaskMgmtReply_t *pScsiTmReply; - SCSITaskMgmt_t *pScsiTmReq; - MPT_SCSI_HOST *hd; - unsigned long flags; - u16 iocstatus; - u8 tmType; - u32 termination_count; + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "TaskMgmt completed (mf=%p, mr=%p)\n", ioc->name, mf, mr)); - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed (mf=%p,mr=%p)\n", - ioc->name, mf, mr)); - if (!ioc->sh) { - dtmprintk(ioc, printk(MYIOC_s_WARN_FMT - "TaskMgmt Complete: NULL Scsi Host Ptr\n", ioc->name)); - return 1; - } + ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD; - if (mr == NULL) { - dtmprintk(ioc, printk(MYIOC_s_WARN_FMT - "ERROR! TaskMgmt Reply: NULL Request %p\n", ioc->name, mf)); - return 1; - } - - hd = shost_priv(ioc->sh); - pScsiTmReply = (SCSITaskMgmtReply_t*)mr; - pScsiTmReq = (SCSITaskMgmt_t*)mf; - tmType = pScsiTmReq->TaskType; - iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK; - termination_count = le32_to_cpu(pScsiTmReply->TerminationCount); - - if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 && - pScsiTmReply->ResponseCode) - mptscsih_taskmgmt_response_code(ioc, - pScsiTmReply->ResponseCode); - DBG_DUMP_TM_REPLY_FRAME(ioc, (u32 *)pScsiTmReply); - -#ifdef CONFIG_FUSION_LOGGING - if ((ioc->debug_level & MPT_DEBUG_REPLY) || - (ioc->debug_level & MPT_DEBUG_TM )) - printk("%s: ha=%d [%d:%d:0] task_type=0x%02X " - "iocstatus=0x%04X\n\tloginfo=0x%08X response_code=0x%02X " - "term_cmnds=%d\n", __func__, ioc->id, pScsiTmReply->Bus, - pScsiTmReply->TargetID, pScsiTmReq->TaskType, - le16_to_cpu(pScsiTmReply->IOCStatus), - le32_to_cpu(pScsiTmReply->IOCLogInfo),pScsiTmReply->ResponseCode, - le32_to_cpu(pScsiTmReply->TerminationCount)); -#endif - if (!iocstatus) { - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT " TaskMgmt SUCCESS\n", ioc->name)); - hd->abortSCpnt = NULL; + if (!mr) goto out; - } - - /* Error? (anything non-zero?) */ - - /* clear flags and continue. - */ - switch (tmType) { - - case MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK: - if (termination_count == 1) - iocstatus = MPI_IOCSTATUS_SCSI_TASK_TERMINATED; - hd->abortSCpnt = NULL; - break; - - case MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS: - - /* If an internal command is present - * or the TM failed - reload the FW. - * FC FW may respond FAILED to an ABORT - */ - if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED || - hd->cmdPtr) - if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) - printk(MYIOC_s_WARN_FMT " Firmware Reload FAILED!!\n", ioc->name); - break; - - case MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET: - default: - break; - } + ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID; + memcpy(ioc->taskmgmt_cmds.reply, mr, + min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength)); out: - spin_lock_irqsave(&ioc->FreeQlock, flags); - hd->tmPending = 0; - hd->tmState = TM_STATE_NONE; - hd->tm_iocstatus = iocstatus; - spin_unlock_irqrestore(&ioc->FreeQlock, flags); - - return 1; + if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) { + mpt_clear_taskmgmt_in_progress_flag(ioc); + ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING; + complete(&ioc->taskmgmt_cmds.done); + return 1; + } + return 0; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -2290,8 +2088,10 @@ int mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id) { struct inactive_raid_component_info *component_info; - int i; + int i, j; + RaidPhysDiskPage1_t *phys_disk; int rc = 0; + int num_paths; if (!ioc->raid_data.pIocPg3) goto out; @@ -2303,6 +2103,45 @@ mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id) } } + if (ioc->bus_type != SAS) + goto out; + + /* + * Check if dual path + */ + for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) { + num_paths = mpt_raid_phys_disk_get_num_paths(ioc, + ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum); + if (num_paths < 2) + continue; + phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) + + (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL); + if (!phys_disk) + continue; + if ((mpt_raid_phys_disk_pg1(ioc, + ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum, + phys_disk))) { + kfree(phys_disk); + continue; + } + for (j = 0; j < num_paths; j++) { + if ((phys_disk->Path[j].Flags & + MPI_RAID_PHYSDISK1_FLAG_INVALID)) + continue; + if ((phys_disk->Path[j].Flags & + MPI_RAID_PHYSDISK1_FLAG_BROKEN)) + continue; + if ((id == phys_disk->Path[j].PhysDiskID) && + (channel == phys_disk->Path[j].PhysDiskBus)) { + rc = 1; + kfree(phys_disk); + goto out; + } + } + kfree(phys_disk); + } + + /* * Check inactive list for matching phys disks */ @@ -2327,8 +2166,10 @@ u8 mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id) { struct inactive_raid_component_info *component_info; - int i; + int i, j; + RaidPhysDiskPage1_t *phys_disk; int rc = -ENXIO; + int num_paths; if (!ioc->raid_data.pIocPg3) goto out; @@ -2340,6 +2181,44 @@ mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id) } } + if (ioc->bus_type != SAS) + goto out; + + /* + * Check if dual path + */ + for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) { + num_paths = mpt_raid_phys_disk_get_num_paths(ioc, + ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum); + if (num_paths < 2) + continue; + phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) + + (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL); + if (!phys_disk) + continue; + if ((mpt_raid_phys_disk_pg1(ioc, + ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum, + phys_disk))) { + kfree(phys_disk); + continue; + } + for (j = 0; j < num_paths; j++) { + if ((phys_disk->Path[j].Flags & + MPI_RAID_PHYSDISK1_FLAG_INVALID)) + continue; + if ((phys_disk->Path[j].Flags & + MPI_RAID_PHYSDISK1_FLAG_BROKEN)) + continue; + if ((id == phys_disk->Path[j].PhysDiskID) && + (channel == phys_disk->Path[j].PhysDiskBus)) { + rc = phys_disk->PhysDiskNum; + kfree(phys_disk); + goto out; + } + } + kfree(phys_disk); + } + /* * Check inactive list for matching phys disks */ @@ -2457,7 +2336,6 @@ mptscsih_slave_configure(struct scsi_device *sdev) sdev->ppr, sdev->inquiry_len)); vdevice->configured_lun = 1; - mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH); dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Queue depth=%d, tflags=%x\n", @@ -2469,6 +2347,7 @@ mptscsih_slave_configure(struct scsi_device *sdev) ioc->name, vtarget->negoFlags, vtarget->maxOffset, vtarget->minSyncFactor)); + mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH); dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "tagged %d, simple %d, ordered %d\n", ioc->name,sdev->tagged_supported, sdev->simple_tags, @@ -2542,15 +2421,13 @@ mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR } /** - * mptscsih_get_scsi_lookup + * mptscsih_get_scsi_lookup - retrieves scmd entry * @ioc: Pointer to MPT_ADAPTER structure * @i: index into the array * - * retrieves scmd entry from ScsiLookup[] array list - * * Returns the scsi_cmd pointer - **/ -static struct scsi_cmnd * + */ +struct scsi_cmnd * mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i) { unsigned long flags; @@ -2562,15 +2439,15 @@ mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i) return scmd; } +EXPORT_SYMBOL(mptscsih_get_scsi_lookup); /** - * mptscsih_getclear_scsi_lookup + * mptscsih_getclear_scsi_lookup - retrieves and clears scmd entry from ScsiLookup[] array list * @ioc: Pointer to MPT_ADAPTER structure * @i: index into the array * - * retrieves and clears scmd entry from ScsiLookup[] array list - * * Returns the scsi_cmd pointer + * **/ static struct scsi_cmnd * mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i) @@ -2635,94 +2512,33 @@ int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) { MPT_SCSI_HOST *hd; - unsigned long flags; - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT - ": IOC %s_reset routed to SCSI host driver!\n", - ioc->name, reset_phase==MPT_IOC_SETUP_RESET ? "setup" : ( - reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"))); - - /* If a FW reload request arrives after base installed but - * before all scsi hosts have been attached, then an alt_ioc - * may have a NULL sh pointer. - */ if (ioc->sh == NULL || shost_priv(ioc->sh) == NULL) return 0; - else - hd = shost_priv(ioc->sh); - if (reset_phase == MPT_IOC_SETUP_RESET) { - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Setup-Diag Reset\n", ioc->name)); - - /* Clean Up: - * 1. Set Hard Reset Pending Flag - * All new commands go to doneQ - */ - hd->resetPending = 1; - - } else if (reset_phase == MPT_IOC_PRE_RESET) { - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Pre-Diag Reset\n", ioc->name)); - - /* 2. Flush running commands - * Clean ScsiLookup (and associated memory) - * AND clean mytaskQ - */ - - /* 2b. Reply to OS all known outstanding I/O commands. - */ + hd = shost_priv(ioc->sh); + switch (reset_phase) { + case MPT_IOC_SETUP_RESET: + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__)); + break; + case MPT_IOC_PRE_RESET: + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__)); mptscsih_flush_running_cmds(hd); - - /* 2c. If there was an internal command that - * has not completed, configuration or io request, - * free these resources. - */ - if (hd->cmdPtr) { - del_timer(&hd->timer); - mpt_free_msg_frame(ioc, hd->cmdPtr); + break; + case MPT_IOC_POST_RESET: + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__)); + if (ioc->internal_cmds.status & MPT_MGMT_STATUS_PENDING) { + ioc->internal_cmds.status |= + MPT_MGMT_STATUS_DID_IOCRESET; + complete(&ioc->internal_cmds.done); } - - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Pre-Reset complete.\n", ioc->name)); - - } else { - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Post-Diag Reset\n", ioc->name)); - - /* Once a FW reload begins, all new OS commands are - * redirected to the doneQ w/ a reset status. - * Init all control structures. - */ - - /* 2. Chain Buffer initialization - */ - - /* 4. Renegotiate to all devices, if SPI - */ - - /* 5. Enable new commands to be posted - */ - spin_lock_irqsave(&ioc->FreeQlock, flags); - hd->tmPending = 0; - spin_unlock_irqrestore(&ioc->FreeQlock, flags); - hd->resetPending = 0; - hd->tmState = TM_STATE_NONE; - - /* 6. If there was an internal command, - * wake this process up. - */ - if (hd->cmdPtr) { - /* - * Wake up the original calling thread - */ - hd->pLocal = &hd->localReply; - hd->pLocal->completion = MPT_SCANDV_DID_RESET; - hd->scandv_wait_done = 1; - wake_up(&hd->scandv_waitq); - hd->cmdPtr = NULL; - } - - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Post-Reset complete.\n", ioc->name)); - + break; + default: + break; } - return 1; /* currently means nothing really */ } @@ -2730,55 +2546,16 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply) { - MPT_SCSI_HOST *hd; u8 event = le32_to_cpu(pEvReply->Event) & 0xFF; - devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n", - ioc->name, event)); + devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "MPT event (=%02Xh) routed to SCSI host driver!\n", + ioc->name, event)); - if (ioc->sh == NULL || - ((hd = shost_priv(ioc->sh)) == NULL)) - return 1; - - switch (event) { - case MPI_EVENT_UNIT_ATTENTION: /* 03 */ - /* FIXME! */ - break; - case MPI_EVENT_IOC_BUS_RESET: /* 04 */ - case MPI_EVENT_EXT_BUS_RESET: /* 05 */ - if (hd && (ioc->bus_type == SPI) && (hd->soft_resets < -1)) - hd->soft_resets++; - break; - case MPI_EVENT_LOGOUT: /* 09 */ - /* FIXME! */ - break; - - case MPI_EVENT_RESCAN: /* 06 */ - break; - - /* - * CHECKME! Don't think we need to do - * anything for these, but... - */ - case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */ - case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */ - /* - * CHECKME! Falling thru... - */ - break; - - case MPI_EVENT_INTEGRATED_RAID: /* 0B */ - break; - - case MPI_EVENT_NONE: /* 00 */ - case MPI_EVENT_LOG_DATA: /* 01 */ - case MPI_EVENT_STATE_CHANGE: /* 02 */ - case MPI_EVENT_EVENT_CHANGE: /* 0A */ - default: - dprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": Ignoring event (=%02Xh)\n", - ioc->name, event)); - break; - } + if ((event == MPI_EVENT_IOC_BUS_RESET || + event == MPI_EVENT_EXT_BUS_RESET) && + (ioc->bus_type == SPI) && (ioc->soft_resets < -1)) + ioc->soft_resets++; return 1; /* currently means nothing really */ } @@ -2809,153 +2586,44 @@ mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply) * Used ONLY for DV and other internal commands. */ int -mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) +mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, + MPT_FRAME_HDR *reply) { - MPT_SCSI_HOST *hd; SCSIIORequest_t *pReq; - int completionCode; + SCSIIOReply_t *pReply; + u8 cmd; u16 req_idx; + u8 *sense_data; + int sz; - hd = shost_priv(ioc->sh); + ioc->internal_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD; + ioc->internal_cmds.completion_code = MPT_SCANDV_GOOD; + if (!reply) + goto out; - if ((mf == NULL) || - (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) { - printk(MYIOC_s_ERR_FMT - "ScanDvComplete, %s req frame ptr! (=%p)\n", - ioc->name, mf?"BAD":"NULL", (void *) mf); - goto wakeup; + pReply = (SCSIIOReply_t *) reply; + pReq = (SCSIIORequest_t *) req; + ioc->internal_cmds.completion_code = + mptscsih_get_completion_code(ioc, req, reply); + ioc->internal_cmds.status |= MPT_MGMT_STATUS_RF_VALID; + memcpy(ioc->internal_cmds.reply, reply, + min(MPT_DEFAULT_FRAME_SIZE, 4 * reply->u.reply.MsgLength)); + cmd = reply->u.hdr.Function; + if (((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) || + (cmd == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) && + (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID)) { + req_idx = le16_to_cpu(req->u.frame.hwhdr.msgctxu.fld.req_idx); + sense_data = ((u8 *)ioc->sense_buf_pool + + (req_idx * MPT_SENSE_BUFFER_ALLOC)); + sz = min_t(int, pReq->SenseBufferLength, + MPT_SENSE_BUFFER_ALLOC); + memcpy(ioc->internal_cmds.sense, sense_data, sz); } - - del_timer(&hd->timer); - req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); - mptscsih_set_scsi_lookup(ioc, req_idx, NULL); - pReq = (SCSIIORequest_t *) mf; - - if (mf != hd->cmdPtr) { - printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p, idx=%d)\n", - ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx); - } - hd->cmdPtr = NULL; - - ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n", - ioc->name, mf, mr, req_idx)); - - hd->pLocal = &hd->localReply; - hd->pLocal->scsiStatus = 0; - - /* If target struct exists, clear sense valid flag. - */ - if (mr == NULL) { - completionCode = MPT_SCANDV_GOOD; - } else { - SCSIIOReply_t *pReply; - u16 status; - u8 scsi_status; - - pReply = (SCSIIOReply_t *) mr; - - status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK; - scsi_status = pReply->SCSIStatus; - - - switch(status) { - - case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */ - completionCode = MPT_SCANDV_SELECTION_TIMEOUT; - break; - - case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */ - case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */ - case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */ - case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */ - completionCode = MPT_SCANDV_DID_RESET; - break; - - case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */ - case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */ - case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */ - if (pReply->Function == MPI_FUNCTION_CONFIG) { - ConfigReply_t *pr = (ConfigReply_t *)mr; - completionCode = MPT_SCANDV_GOOD; - hd->pLocal->header.PageVersion = pr->Header.PageVersion; - hd->pLocal->header.PageLength = pr->Header.PageLength; - hd->pLocal->header.PageNumber = pr->Header.PageNumber; - hd->pLocal->header.PageType = pr->Header.PageType; - - } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) { - /* If the RAID Volume request is successful, - * return GOOD, else indicate that - * some type of error occurred. - */ - MpiRaidActionReply_t *pr = (MpiRaidActionReply_t *)mr; - if (le16_to_cpu(pr->ActionStatus) == MPI_RAID_ACTION_ASTATUS_SUCCESS) - completionCode = MPT_SCANDV_GOOD; - else - completionCode = MPT_SCANDV_SOME_ERROR; - memcpy(hd->pLocal->sense, pr, sizeof(hd->pLocal->sense)); - - } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) { - u8 *sense_data; - int sz; - - /* save sense data in global structure - */ - completionCode = MPT_SCANDV_SENSE; - hd->pLocal->scsiStatus = scsi_status; - sense_data = ((u8 *)ioc->sense_buf_pool + - (req_idx * MPT_SENSE_BUFFER_ALLOC)); - - sz = min_t(int, pReq->SenseBufferLength, - SCSI_STD_SENSE_BYTES); - memcpy(hd->pLocal->sense, sense_data, sz); - - ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT " Check Condition, sense ptr %p\n", - ioc->name, sense_data)); - } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) { - if (pReq->CDB[0] == INQUIRY) - completionCode = MPT_SCANDV_ISSUE_SENSE; - else - completionCode = MPT_SCANDV_DID_RESET; - } - else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS) - completionCode = MPT_SCANDV_DID_RESET; - else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED) - completionCode = MPT_SCANDV_DID_RESET; - else { - completionCode = MPT_SCANDV_GOOD; - hd->pLocal->scsiStatus = scsi_status; - } - break; - - case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */ - if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED) - completionCode = MPT_SCANDV_DID_RESET; - else - completionCode = MPT_SCANDV_SOME_ERROR; - break; - - default: - completionCode = MPT_SCANDV_SOME_ERROR; - break; - - } /* switch(status) */ - - } /* end of address reply case */ - - hd->pLocal->completion = completionCode; - - /* MF and RF are freed in mpt_interrupt - */ -wakeup: - /* Free Chain buffers (will never chain) in scan or dv */ - //mptscsih_freeChainBuffers(ioc, req_idx); - - /* - * Wake up the original calling thread - */ - hd->scandv_wait_done = 1; - wake_up(&hd->scandv_waitq); - + out: + if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_PENDING)) + return 0; + ioc->internal_cmds.status &= ~MPT_MGMT_STATUS_PENDING; + complete(&ioc->internal_cmds.done); return 1; } @@ -3004,6 +2672,95 @@ mptscsih_timer_expired(unsigned long data) return; } +/** + * mptscsih_get_completion_code - + * @ioc: Pointer to MPT_ADAPTER structure + * @req: Pointer to original MPT request frame + * @reply: Pointer to MPT reply frame (NULL if TurboReply) + * + **/ +static int +mptscsih_get_completion_code(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, + MPT_FRAME_HDR *reply) +{ + SCSIIOReply_t *pReply; + MpiRaidActionReply_t *pr; + u8 scsi_status; + u16 status; + int completion_code; + + pReply = (SCSIIOReply_t *)reply; + status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK; + scsi_status = pReply->SCSIStatus; + + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh," + "IOCLogInfo=%08xh\n", ioc->name, status, pReply->SCSIState, + scsi_status, le32_to_cpu(pReply->IOCLogInfo))); + + switch (status) { + + case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */ + completion_code = MPT_SCANDV_SELECTION_TIMEOUT; + break; + + case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */ + case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */ + case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */ + case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */ + completion_code = MPT_SCANDV_DID_RESET; + break; + + case MPI_IOCSTATUS_BUSY: + case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: + completion_code = MPT_SCANDV_BUSY; + break; + + case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */ + case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */ + case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */ + if (pReply->Function == MPI_FUNCTION_CONFIG) { + completion_code = MPT_SCANDV_GOOD; + } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) { + pr = (MpiRaidActionReply_t *)reply; + if (le16_to_cpu(pr->ActionStatus) == + MPI_RAID_ACTION_ASTATUS_SUCCESS) + completion_code = MPT_SCANDV_GOOD; + else + completion_code = MPT_SCANDV_SOME_ERROR; + } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) + completion_code = MPT_SCANDV_SENSE; + else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) { + if (req->u.scsireq.CDB[0] == INQUIRY) + completion_code = MPT_SCANDV_ISSUE_SENSE; + else + completion_code = MPT_SCANDV_DID_RESET; + } else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS) + completion_code = MPT_SCANDV_DID_RESET; + else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED) + completion_code = MPT_SCANDV_DID_RESET; + else if (scsi_status == MPI_SCSI_STATUS_BUSY) + completion_code = MPT_SCANDV_BUSY; + else + completion_code = MPT_SCANDV_GOOD; + break; + + case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */ + if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED) + completion_code = MPT_SCANDV_DID_RESET; + else + completion_code = MPT_SCANDV_SOME_ERROR; + break; + default: + completion_code = MPT_SCANDV_SOME_ERROR; + break; + + } /* switch(status) */ + + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT + " completionCode set to %08xh\n", ioc->name, completion_code)); + return completion_code; +} /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** @@ -3030,22 +2787,27 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io) { MPT_FRAME_HDR *mf; SCSIIORequest_t *pScsiReq; - SCSIIORequest_t ReqCopy; int my_idx, ii, dir; - int rc, cmdTimeout; - int in_isr; + int timeout; char cmdLen; char CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; - char cmd = io->cmd; - MPT_ADAPTER *ioc = hd->ioc; + u8 cmd = io->cmd; + MPT_ADAPTER *ioc = hd->ioc; + int ret = 0; + unsigned long timeleft; + unsigned long flags; - in_isr = in_interrupt(); - if (in_isr) { - dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Internal SCSI IO request not allowed in ISR context!\n", - ioc->name)); - return -EPERM; + /* don't send internal command during diag reset */ + spin_lock_irqsave(&ioc->taskmgmt_lock, flags); + if (ioc->ioc_reset_in_progress) { + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: busy with host reset\n", ioc->name, __func__)); + return MPT_SCANDV_BUSY; } + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + mutex_lock(&ioc->internal_cmds.mutex); /* Set command specific information */ @@ -3055,13 +2817,13 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io) dir = MPI_SCSIIO_CONTROL_READ; CDB[0] = cmd; CDB[4] = io->size; - cmdTimeout = 10; + timeout = 10; break; case TEST_UNIT_READY: cmdLen = 6; dir = MPI_SCSIIO_CONTROL_READ; - cmdTimeout = 10; + timeout = 10; break; case START_STOP: @@ -3069,7 +2831,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io) dir = MPI_SCSIIO_CONTROL_READ; CDB[0] = cmd; CDB[4] = 1; /*Spin up the disk */ - cmdTimeout = 15; + timeout = 15; break; case REQUEST_SENSE: @@ -3077,7 +2839,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io) CDB[0] = cmd; CDB[4] = io->size; dir = MPI_SCSIIO_CONTROL_READ; - cmdTimeout = 10; + timeout = 10; break; case READ_BUFFER: @@ -3096,7 +2858,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io) CDB[6] = (io->size >> 16) & 0xFF; CDB[7] = (io->size >> 8) & 0xFF; CDB[8] = io->size & 0xFF; - cmdTimeout = 10; + timeout = 10; break; case WRITE_BUFFER: @@ -3111,21 +2873,21 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io) CDB[6] = (io->size >> 16) & 0xFF; CDB[7] = (io->size >> 8) & 0xFF; CDB[8] = io->size & 0xFF; - cmdTimeout = 10; + timeout = 10; break; case RESERVE: cmdLen = 6; dir = MPI_SCSIIO_CONTROL_READ; CDB[0] = cmd; - cmdTimeout = 10; + timeout = 10; break; case RELEASE: cmdLen = 6; dir = MPI_SCSIIO_CONTROL_READ; CDB[0] = cmd; - cmdTimeout = 10; + timeout = 10; break; case SYNCHRONIZE_CACHE: @@ -3133,20 +2895,23 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io) dir = MPI_SCSIIO_CONTROL_READ; CDB[0] = cmd; // CDB[1] = 0x02; /* set immediate bit */ - cmdTimeout = 10; + timeout = 10; break; default: /* Error Case */ - return -EFAULT; + ret = -EFAULT; + goto out; } /* Get and Populate a free Frame + * MsgContext set in mpt_get_msg_frame call */ if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) { - dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "No msg frames!\n", - ioc->name)); - return -EBUSY; + dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: No msg frames!\n", + ioc->name, __func__)); + ret = MPT_SCANDV_BUSY; + goto out; } pScsiReq = (SCSIIORequest_t *) mf; @@ -3172,7 +2937,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io) pScsiReq->Reserved = 0; - pScsiReq->MsgFlags = mpt_msg_flags(); + pScsiReq->MsgFlags = mpt_msg_flags(ioc); /* MsgContext set in mpt_get_msg_fram call */ int_to_scsilun(io->lun, (struct scsi_lun *)pScsiReq->LUN); @@ -3184,74 +2949,58 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io) if (cmd == REQUEST_SENSE) { pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED); - ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Untagged! 0x%2x\n", - ioc->name, cmd)); + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: Untagged! 0x%02x\n", ioc->name, __func__, cmd)); } - for (ii=0; ii < 16; ii++) + for (ii = 0; ii < 16; ii++) pScsiReq->CDB[ii] = CDB[ii]; pScsiReq->DataLength = cpu_to_le32(io->size); pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma + (my_idx * MPT_SENSE_BUFFER_ALLOC)); - ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Command 0x%x for (%d:%d:%d)\n", - ioc->name, cmd, io->channel, io->id, io->lun)); + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: Sending Command 0x%02x for fw_channel=%d fw_id=%d lun=%d\n", + ioc->name, __func__, cmd, io->channel, io->id, io->lun)); - if (dir == MPI_SCSIIO_CONTROL_READ) { - mpt_add_sge((char *) &pScsiReq->SGL, - MPT_SGE_FLAGS_SSIMPLE_READ | io->size, - io->data_dma); - } else { - mpt_add_sge((char *) &pScsiReq->SGL, - MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size, - io->data_dma); - } + if (dir == MPI_SCSIIO_CONTROL_READ) + ioc->add_sge((char *) &pScsiReq->SGL, + MPT_SGE_FLAGS_SSIMPLE_READ | io->size, io->data_dma); + else + ioc->add_sge((char *) &pScsiReq->SGL, + MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size, io->data_dma); - /* The ISR will free the request frame, but we need - * the information to initialize the target. Duplicate. - */ - memcpy(&ReqCopy, pScsiReq, sizeof(SCSIIORequest_t)); - - /* Issue this command after: - * finish init - * add timer - * Wait until the reply has been received - * ScsiScanDvCtx callback function will - * set hd->pLocal; - * set scandv_wait_done and call wake_up - */ - hd->pLocal = NULL; - hd->timer.expires = jiffies + HZ*cmdTimeout; - hd->scandv_wait_done = 0; - - /* Save cmd pointer, for resource free if timeout or - * FW reload occurs - */ - hd->cmdPtr = mf; - - add_timer(&hd->timer); + INITIALIZE_MGMT_STATUS(ioc->internal_cmds.status) mpt_put_msg_frame(ioc->InternalCtx, ioc, mf); - wait_event(hd->scandv_waitq, hd->scandv_wait_done); - - if (hd->pLocal) { - rc = hd->pLocal->completion; - hd->pLocal->skip = 0; - - /* Always set fatal error codes in some cases. - */ - if (rc == MPT_SCANDV_SELECTION_TIMEOUT) - rc = -ENXIO; - else if (rc == MPT_SCANDV_SOME_ERROR) - rc = -rc; - } else { - rc = -EFAULT; - /* This should never happen. */ - ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "_do_cmd: Null pLocal!!!\n", - ioc->name)); + timeleft = wait_for_completion_timeout(&ioc->internal_cmds.done, + timeout*HZ); + if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + ret = MPT_SCANDV_DID_RESET; + dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: TIMED OUT for cmd=0x%02x\n", ioc->name, __func__, + cmd)); + if (ioc->internal_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) { + mpt_free_msg_frame(ioc, mf); + goto out; + } + if (!timeleft) { + printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n", + ioc->name, __func__); + mpt_HardResetHandler(ioc, CAN_SLEEP); + mpt_free_msg_frame(ioc, mf); + } + goto out; } - return rc; + ret = ioc->internal_cmds.completion_code; + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: success, rc=0x%02x\n", + ioc->name, __func__, ret)); + + out: + CLEAR_MGMT_STATUS(ioc->internal_cmds.status) + mutex_unlock(&ioc->internal_cmds.mutex); + return ret; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -3491,6 +3240,7 @@ struct device_attribute *mptscsih_host_attrs[] = { &dev_attr_debug_level, NULL, }; + EXPORT_SYMBOL(mptscsih_host_attrs); EXPORT_SYMBOL(mptscsih_remove); @@ -3516,6 +3266,5 @@ EXPORT_SYMBOL(mptscsih_event_process); EXPORT_SYMBOL(mptscsih_ioc_reset); EXPORT_SYMBOL(mptscsih_change_queue_depth); EXPORT_SYMBOL(mptscsih_timer_expired); -EXPORT_SYMBOL(mptscsih_TMHandler); /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ diff --git a/drivers/message/fusion/mptscsih.h b/drivers/message/fusion/mptscsih.h index 319aa3033371..eb3f677528ac 100644 --- a/drivers/message/fusion/mptscsih.h +++ b/drivers/message/fusion/mptscsih.h @@ -60,6 +60,7 @@ #define MPT_SCANDV_SELECTION_TIMEOUT (0x00000008) #define MPT_SCANDV_ISSUE_SENSE (0x00000010) #define MPT_SCANDV_FALLBACK (0x00000020) +#define MPT_SCANDV_BUSY (0x00000040) #define MPT_SCANDV_MAX_RETRIES (10) @@ -89,6 +90,7 @@ #endif + typedef struct _internal_cmd { char *data; /* data pointer */ dma_addr_t data_dma; /* data dma address */ @@ -112,6 +114,8 @@ extern int mptscsih_resume(struct pci_dev *pdev); extern int mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, int func); extern const char * mptscsih_info(struct Scsi_Host *SChost); extern int mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)); +extern int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, + u8 id, int lun, int ctx2abort, ulong timeout); extern void mptscsih_slave_destroy(struct scsi_device *device); extern int mptscsih_slave_configure(struct scsi_device *device); extern int mptscsih_abort(struct scsi_cmnd * SCpnt); @@ -126,7 +130,8 @@ extern int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pE extern int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset); extern int mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth); extern void mptscsih_timer_expired(unsigned long data); -extern int mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout); extern u8 mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id); extern int mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id); extern struct device_attribute *mptscsih_host_attrs[]; +extern struct scsi_cmnd *mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i); +extern void mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code); diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c index 61620144e49c..c5b808fd55ba 100644 --- a/drivers/message/fusion/mptspi.c +++ b/drivers/message/fusion/mptspi.c @@ -300,7 +300,7 @@ mptspi_writeIOCPage4(MPT_SCSI_HOST *hd, u8 channel , u8 id) flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE | (IOCPage4Ptr->Header.PageLength + ii) * 4; - mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma); + ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma); ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "writeIOCPage4: MaxSEP=%d ActiveSEP=%d id=%d bus=%d\n", @@ -614,19 +614,24 @@ static void mptspi_read_parameters(struct scsi_target *starget) spi_width(starget) = (nego & MPI_SCSIDEVPAGE0_NP_WIDE) ? 1 : 0; } -static int +int mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, u8 channel, u8 id) { + MPT_ADAPTER *ioc = hd->ioc; MpiRaidActionRequest_t *pReq; MPT_FRAME_HDR *mf; - MPT_ADAPTER *ioc = hd->ioc; + int ret; + unsigned long timeleft; + + mutex_lock(&ioc->internal_cmds.mutex); /* Get and Populate a free Frame */ if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) { - ddvprintk(ioc, printk(MYIOC_s_WARN_FMT "_do_raid: no msg frames!\n", - ioc->name)); - return -EAGAIN; + dfailprintk(hd->ioc, printk(MYIOC_s_WARN_FMT + "%s: no msg frames!\n", ioc->name, __func__)); + ret = -EAGAIN; + goto out; } pReq = (MpiRaidActionRequest_t *)mf; if (quiesce) @@ -643,29 +648,36 @@ mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, u8 channel, u8 id) pReq->Reserved2 = 0; pReq->ActionDataWord = 0; /* Reserved for this action */ - mpt_add_sge((char *)&pReq->ActionDataSGE, + ioc->add_sge((char *)&pReq->ActionDataSGE, MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1); ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RAID Volume action=%x channel=%d id=%d\n", ioc->name, pReq->Action, channel, id)); - hd->pLocal = NULL; - hd->timer.expires = jiffies + HZ*10; /* 10 second timeout */ - hd->scandv_wait_done = 0; - - /* Save cmd pointer, for resource free if timeout or - * FW reload occurs - */ - hd->cmdPtr = mf; - - add_timer(&hd->timer); + INITIALIZE_MGMT_STATUS(ioc->internal_cmds.status) mpt_put_msg_frame(ioc->InternalCtx, ioc, mf); - wait_event(hd->scandv_waitq, hd->scandv_wait_done); + timeleft = wait_for_completion_timeout(&ioc->internal_cmds.done, 10*HZ); + if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + ret = -ETIME; + dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: TIMED OUT!\n", + ioc->name, __func__)); + if (ioc->internal_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) + goto out; + if (!timeleft) { + printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n", + ioc->name, __func__); + mpt_HardResetHandler(ioc, CAN_SLEEP); + mpt_free_msg_frame(ioc, mf); + } + goto out; + } - if ((hd->pLocal == NULL) || (hd->pLocal->completion != 0)) - return -1; + ret = ioc->internal_cmds.completion_code; - return 0; + out: + CLEAR_MGMT_STATUS(ioc->internal_cmds.status) + mutex_unlock(&ioc->internal_cmds.mutex); + return ret; } static void mptspi_dv_device(struct _MPT_SCSI_HOST *hd, @@ -1423,17 +1435,15 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id) * A slightly different algorithm is required for * 64bit SGEs. */ - scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32)); - if (sizeof(dma_addr_t) == sizeof(u64)) { + scale = ioc->req_sz/ioc->SGE_size; + if (ioc->sg_addr_size == sizeof(u64)) { numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale + - (ioc->req_sz - 60) / (sizeof(dma_addr_t) + - sizeof(u32)); + (ioc->req_sz - 60) / ioc->SGE_size; } else { numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale + - (ioc->req_sz - 64) / (sizeof(dma_addr_t) + - sizeof(u32)); + (ioc->req_sz - 64) / ioc->SGE_size; } if (numSGE < sh->sg_tablesize) { @@ -1464,9 +1474,6 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id) /* Clear the TM flags */ - hd->tmPending = 0; - hd->tmState = TM_STATE_NONE; - hd->resetPending = 0; hd->abortSCpnt = NULL; /* Clear the pointer used to store @@ -1493,8 +1500,6 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id) mpt_saf_te)); ioc->spi_data.noQas = 0; - init_waitqueue_head(&hd->scandv_waitq); - hd->scandv_wait_done = 0; hd->last_queue_full = 0; hd->spi_pending = 0; @@ -1514,7 +1519,7 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id) * issue internal bus reset */ if (ioc->spi_data.bus_reset) - mptscsih_TMHandler(hd, + mptscsih_IssueTaskMgmt(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, 0, 0, 0, 0, 5); diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c index a443e136dc41..335d4c78a775 100644 --- a/drivers/message/i2o/i2o_block.c +++ b/drivers/message/i2o/i2o_block.c @@ -426,15 +426,9 @@ static void i2o_block_end_request(struct request *req, int error, struct request_queue *q = req->q; unsigned long flags; - if (blk_end_request(req, error, nr_bytes)) { - int leftover = (req->hard_nr_sectors << KERNEL_SECTOR_SHIFT); - - if (blk_pc_request(req)) - leftover = req->data_len; - + if (blk_end_request(req, error, nr_bytes)) if (error) - blk_end_request(req, -EIO, leftover); - } + blk_end_request_all(req, -EIO); spin_lock_irqsave(q->queue_lock, flags); @@ -761,7 +755,7 @@ static int i2o_block_transfer(struct request *req) break; case CACHE_SMARTFETCH: - if (req->nr_sectors > 16) + if (blk_rq_sectors(req) > 16) ctl_flags = 0x201F0008; else ctl_flags = 0x001F0000; @@ -781,13 +775,13 @@ static int i2o_block_transfer(struct request *req) ctl_flags = 0x001F0010; break; case CACHE_SMARTBACK: - if (req->nr_sectors > 16) + if (blk_rq_sectors(req) > 16) ctl_flags = 0x001F0004; else ctl_flags = 0x001F0010; break; case CACHE_SMARTTHROUGH: - if (req->nr_sectors > 16) + if (blk_rq_sectors(req) > 16) ctl_flags = 0x001F0004; else ctl_flags = 0x001F0010; @@ -800,8 +794,9 @@ static int i2o_block_transfer(struct request *req) if (c->adaptec) { u8 cmd[10]; u32 scsi_flags; - u16 hwsec = queue_hardsect_size(req->q) >> KERNEL_SECTOR_SHIFT; + u16 hwsec; + hwsec = queue_logical_block_size(req->q) >> KERNEL_SECTOR_SHIFT; memset(cmd, 0, 10); sgl_offset = SGL_OFFSET_12; @@ -827,22 +822,22 @@ static int i2o_block_transfer(struct request *req) *mptr++ = cpu_to_le32(scsi_flags); - *((u32 *) & cmd[2]) = cpu_to_be32(req->sector * hwsec); - *((u16 *) & cmd[7]) = cpu_to_be16(req->nr_sectors * hwsec); + *((u32 *) & cmd[2]) = cpu_to_be32(blk_rq_pos(req) * hwsec); + *((u16 *) & cmd[7]) = cpu_to_be16(blk_rq_sectors(req) * hwsec); memcpy(mptr, cmd, 10); mptr += 4; - *mptr++ = cpu_to_le32(req->nr_sectors << KERNEL_SECTOR_SHIFT); + *mptr++ = cpu_to_le32(blk_rq_bytes(req)); } else #endif { msg->u.head[1] = cpu_to_le32(cmd | HOST_TID << 12 | tid); *mptr++ = cpu_to_le32(ctl_flags); - *mptr++ = cpu_to_le32(req->nr_sectors << KERNEL_SECTOR_SHIFT); + *mptr++ = cpu_to_le32(blk_rq_bytes(req)); *mptr++ = - cpu_to_le32((u32) (req->sector << KERNEL_SECTOR_SHIFT)); + cpu_to_le32((u32) (blk_rq_pos(req) << KERNEL_SECTOR_SHIFT)); *mptr++ = - cpu_to_le32(req->sector >> (32 - KERNEL_SECTOR_SHIFT)); + cpu_to_le32(blk_rq_pos(req) >> (32 - KERNEL_SECTOR_SHIFT)); } if (!i2o_block_sglist_alloc(c, ireq, &mptr)) { @@ -883,7 +878,7 @@ static void i2o_block_request_fn(struct request_queue *q) struct request *req; while (!blk_queue_plugged(q)) { - req = elv_next_request(q); + req = blk_peek_request(q); if (!req) break; @@ -896,7 +891,7 @@ static void i2o_block_request_fn(struct request_queue *q) if (queue_depth < I2O_BLOCK_MAX_OPEN_REQUESTS) { if (!i2o_block_transfer(req)) { - blkdev_dequeue_request(req); + blk_start_request(req); continue; } else osm_info("transfer error\n"); @@ -922,8 +917,10 @@ static void i2o_block_request_fn(struct request_queue *q) blk_stop_queue(q); break; } - } else - end_request(req, 0); + } else { + blk_start_request(req); + __blk_end_request_all(req, -EIO); + } } }; @@ -1082,7 +1079,7 @@ static int i2o_block_probe(struct device *dev) */ if (!i2o_parm_field_get(i2o_dev, 0x0004, 1, &blocksize, 4) || !i2o_parm_field_get(i2o_dev, 0x0000, 3, &blocksize, 4)) { - blk_queue_hardsect_size(queue, le32_to_cpu(blocksize)); + blk_queue_logical_block_size(queue, le32_to_cpu(blocksize)); } else osm_warn("unable to get blocksize of %s\n", gd->disk_name); diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index ee3927ab11e0..491ac0f800d2 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -30,6 +30,7 @@ config MFD_SM501_GPIO config MFD_ASIC3 bool "Support for Compaq ASIC3" depends on GENERIC_HARDIRQS && GPIOLIB && ARM + select MFD_CORE ---help--- This driver supports the ASIC3 multifunction chip found on many PDAs (mainly iPAQ and HTC based ones) @@ -152,7 +153,7 @@ config MFD_WM8400 depends on I2C help Support for the Wolfson Microelecronics WM8400 PMIC and audio - CODEC. This driver adds provides common support for accessing + CODEC. This driver provides common support for accessing the device, additional drivers must be enabled in order to use the functionality of the device. @@ -241,6 +242,27 @@ config PCF50633_GPIO Say yes here if you want to include support GPIO for pins on the PCF50633 chip. +config AB3100_CORE + tristate "ST-Ericsson AB3100 Mixed Signal Circuit core functions" + depends on I2C + default y if ARCH_U300 + help + Select this to enable the AB3100 Mixed Signal IC core + functionality. This connects to a AB3100 on the I2C bus + and expose a number of symbols needed for dependent devices + to read and write registers and subscribe to events from + this multi-functional IC. This is needed to use other features + of the AB3100 such as battery-backed RTC, charging control, + LEDs, vibrator, system power and temperature, power management + and ALSA sound. + +config EZX_PCAP + bool "PCAP Support" + depends on GENERIC_HARDIRQS && SPI_MASTER + help + This enables the PCAP ASIC present on EZX Phones. This is + needed for MMC, TouchScreen, Sound, USB, etc.. + endmenu menu "Multimedia Capabilities Port drivers" diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 3afb5192e4da..6f8a9a1af20b 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -26,6 +26,8 @@ obj-$(CONFIG_TWL4030_CORE) += twl4030-core.o twl4030-irq.o obj-$(CONFIG_MFD_CORE) += mfd-core.o +obj-$(CONFIG_EZX_PCAP) += ezx-pcap.o + obj-$(CONFIG_MCP) += mcp-core.o obj-$(CONFIG_MCP_SA11X0) += mcp-sa11x0.o obj-$(CONFIG_MCP_UCB1200) += ucb1x00-core.o @@ -40,4 +42,5 @@ obj-$(CONFIG_PMIC_DA903X) += da903x.o obj-$(CONFIG_MFD_PCF50633) += pcf50633-core.o obj-$(CONFIG_PCF50633_ADC) += pcf50633-adc.o -obj-$(CONFIG_PCF50633_GPIO) += pcf50633-gpio.o \ No newline at end of file +obj-$(CONFIG_PCF50633_GPIO) += pcf50633-gpio.o +obj-$(CONFIG_AB3100_CORE) += ab3100-core.o diff --git a/drivers/mfd/ab3100-core.c b/drivers/mfd/ab3100-core.c new file mode 100644 index 000000000000..13e7d7bfe85f --- /dev/null +++ b/drivers/mfd/ab3100-core.c @@ -0,0 +1,991 @@ +/* + * Copyright (C) 2007-2009 ST-Ericsson + * License terms: GNU General Public License (GPL) version 2 + * Low-level core for exclusive access to the AB3100 IC on the I2C bus + * and some basic chip-configuration. + * Author: Linus Walleij + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* These are the only registers inside AB3100 used in this main file */ + +/* Interrupt event registers */ +#define AB3100_EVENTA1 0x21 +#define AB3100_EVENTA2 0x22 +#define AB3100_EVENTA3 0x23 + +/* AB3100 DAC converter registers */ +#define AB3100_DIS 0x00 +#define AB3100_D0C 0x01 +#define AB3100_D1C 0x02 +#define AB3100_D2C 0x03 +#define AB3100_D3C 0x04 + +/* Chip ID register */ +#define AB3100_CID 0x20 + +/* AB3100 interrupt registers */ +#define AB3100_IMRA1 0x24 +#define AB3100_IMRA2 0x25 +#define AB3100_IMRA3 0x26 +#define AB3100_IMRB1 0x2B +#define AB3100_IMRB2 0x2C +#define AB3100_IMRB3 0x2D + +/* System Power Monitoring and control registers */ +#define AB3100_MCA 0x2E +#define AB3100_MCB 0x2F + +/* SIM power up */ +#define AB3100_SUP 0x50 + +/* + * I2C communication + * + * The AB3100 is usually assigned address 0x48 (7-bit) + * The chip is defined in the platform i2c_board_data section. + */ +static unsigned short normal_i2c[] = { 0x48, I2C_CLIENT_END }; +I2C_CLIENT_INSMOD_1(ab3100); + +u8 ab3100_get_chip_type(struct ab3100 *ab3100) +{ + u8 chip = ABUNKNOWN; + + switch (ab3100->chip_id & 0xf0) { + case 0xa0: + chip = AB3000; + break; + case 0xc0: + chip = AB3100; + break; + } + return chip; +} +EXPORT_SYMBOL(ab3100_get_chip_type); + +int ab3100_set_register(struct ab3100 *ab3100, u8 reg, u8 regval) +{ + u8 regandval[2] = {reg, regval}; + int err; + + err = mutex_lock_interruptible(&ab3100->access_mutex); + if (err) + return err; + + /* + * A two-byte write message with the first byte containing the register + * number and the second byte containing the value to be written + * effectively sets a register in the AB3100. + */ + err = i2c_master_send(ab3100->i2c_client, regandval, 2); + if (err < 0) { + dev_err(ab3100->dev, + "write error (write register): %d\n", + err); + } else if (err != 2) { + dev_err(ab3100->dev, + "write error (write register) " + "%d bytes transferred (expected 2)\n", + err); + err = -EIO; + } else { + /* All is well */ + err = 0; + } + mutex_unlock(&ab3100->access_mutex); + return 0; +} +EXPORT_SYMBOL(ab3100_set_register); + +/* + * The test registers exist at an I2C bus address up one + * from the ordinary base. They are not supposed to be used + * in production code, but sometimes you have to do that + * anyway. It's currently only used from this file so declare + * it static and do not export. + */ +static int ab3100_set_test_register(struct ab3100 *ab3100, + u8 reg, u8 regval) +{ + u8 regandval[2] = {reg, regval}; + int err; + + err = mutex_lock_interruptible(&ab3100->access_mutex); + if (err) + return err; + + err = i2c_master_send(ab3100->testreg_client, regandval, 2); + if (err < 0) { + dev_err(ab3100->dev, + "write error (write test register): %d\n", + err); + } else if (err != 2) { + dev_err(ab3100->dev, + "write error (write test register) " + "%d bytes transferred (expected 2)\n", + err); + err = -EIO; + } else { + /* All is well */ + err = 0; + } + mutex_unlock(&ab3100->access_mutex); + + return err; +} + +int ab3100_get_register(struct ab3100 *ab3100, u8 reg, u8 *regval) +{ + int err; + + err = mutex_lock_interruptible(&ab3100->access_mutex); + if (err) + return err; + + /* + * AB3100 require an I2C "stop" command between each message, else + * it will not work. The only way of achieveing this with the + * message transport layer is to send the read and write messages + * separately. + */ + err = i2c_master_send(ab3100->i2c_client, ®, 1); + if (err < 0) { + dev_err(ab3100->dev, + "write error (send register address): %d\n", + err); + goto get_reg_out_unlock; + } else if (err != 1) { + dev_err(ab3100->dev, + "write error (send register address) " + "%d bytes transferred (expected 1)\n", + err); + err = -EIO; + goto get_reg_out_unlock; + } else { + /* All is well */ + err = 0; + } + + err = i2c_master_recv(ab3100->i2c_client, regval, 1); + if (err < 0) { + dev_err(ab3100->dev, + "write error (read register): %d\n", + err); + goto get_reg_out_unlock; + } else if (err != 1) { + dev_err(ab3100->dev, + "write error (read register) " + "%d bytes transferred (expected 1)\n", + err); + err = -EIO; + goto get_reg_out_unlock; + } else { + /* All is well */ + err = 0; + } + + get_reg_out_unlock: + mutex_unlock(&ab3100->access_mutex); + return err; +} +EXPORT_SYMBOL(ab3100_get_register); + +int ab3100_get_register_page(struct ab3100 *ab3100, + u8 first_reg, u8 *regvals, u8 numregs) +{ + int err; + + if (ab3100->chip_id == 0xa0 || + ab3100->chip_id == 0xa1) + /* These don't support paged reads */ + return -EIO; + + err = mutex_lock_interruptible(&ab3100->access_mutex); + if (err) + return err; + + /* + * Paged read also require an I2C "stop" command. + */ + err = i2c_master_send(ab3100->i2c_client, &first_reg, 1); + if (err < 0) { + dev_err(ab3100->dev, + "write error (send first register address): %d\n", + err); + goto get_reg_page_out_unlock; + } else if (err != 1) { + dev_err(ab3100->dev, + "write error (send first register address) " + "%d bytes transferred (expected 1)\n", + err); + err = -EIO; + goto get_reg_page_out_unlock; + } + + err = i2c_master_recv(ab3100->i2c_client, regvals, numregs); + if (err < 0) { + dev_err(ab3100->dev, + "write error (read register page): %d\n", + err); + goto get_reg_page_out_unlock; + } else if (err != numregs) { + dev_err(ab3100->dev, + "write error (read register page) " + "%d bytes transferred (expected %d)\n", + err, numregs); + err = -EIO; + goto get_reg_page_out_unlock; + } + + /* All is well */ + err = 0; + + get_reg_page_out_unlock: + mutex_unlock(&ab3100->access_mutex); + return err; +} +EXPORT_SYMBOL(ab3100_get_register_page); + +int ab3100_mask_and_set_register(struct ab3100 *ab3100, + u8 reg, u8 andmask, u8 ormask) +{ + u8 regandval[2] = {reg, 0}; + int err; + + err = mutex_lock_interruptible(&ab3100->access_mutex); + if (err) + return err; + + /* First read out the target register */ + err = i2c_master_send(ab3100->i2c_client, ®, 1); + if (err < 0) { + dev_err(ab3100->dev, + "write error (maskset send address): %d\n", + err); + goto get_maskset_unlock; + } else if (err != 1) { + dev_err(ab3100->dev, + "write error (maskset send address) " + "%d bytes transferred (expected 1)\n", + err); + err = -EIO; + goto get_maskset_unlock; + } + + err = i2c_master_recv(ab3100->i2c_client, ®andval[1], 1); + if (err < 0) { + dev_err(ab3100->dev, + "write error (maskset read register): %d\n", + err); + goto get_maskset_unlock; + } else if (err != 1) { + dev_err(ab3100->dev, + "write error (maskset read register) " + "%d bytes transferred (expected 1)\n", + err); + err = -EIO; + goto get_maskset_unlock; + } + + /* Modify the register */ + regandval[1] &= andmask; + regandval[1] |= ormask; + + /* Write the register */ + err = i2c_master_send(ab3100->i2c_client, regandval, 2); + if (err < 0) { + dev_err(ab3100->dev, + "write error (write register): %d\n", + err); + goto get_maskset_unlock; + } else if (err != 2) { + dev_err(ab3100->dev, + "write error (write register) " + "%d bytes transferred (expected 2)\n", + err); + err = -EIO; + goto get_maskset_unlock; + } + + /* All is well */ + err = 0; + + get_maskset_unlock: + mutex_unlock(&ab3100->access_mutex); + return err; +} +EXPORT_SYMBOL(ab3100_mask_and_set_register); + +/* + * Register a simple callback for handling any AB3100 events. + */ +int ab3100_event_register(struct ab3100 *ab3100, + struct notifier_block *nb) +{ + return blocking_notifier_chain_register(&ab3100->event_subscribers, + nb); +} +EXPORT_SYMBOL(ab3100_event_register); + +/* + * Remove a previously registered callback. + */ +int ab3100_event_unregister(struct ab3100 *ab3100, + struct notifier_block *nb) +{ + return blocking_notifier_chain_unregister(&ab3100->event_subscribers, + nb); +} +EXPORT_SYMBOL(ab3100_event_unregister); + + +int ab3100_event_registers_startup_state_get(struct ab3100 *ab3100, + u32 *fatevent) +{ + if (!ab3100->startup_events_read) + return -EAGAIN; /* Try again later */ + *fatevent = ab3100->startup_events; + return 0; +} +EXPORT_SYMBOL(ab3100_event_registers_startup_state_get); + +/* Interrupt handling worker */ +static void ab3100_work(struct work_struct *work) +{ + struct ab3100 *ab3100 = container_of(work, struct ab3100, work); + u8 event_regs[3]; + u32 fatevent; + int err; + + err = ab3100_get_register_page(ab3100, AB3100_EVENTA1, + event_regs, 3); + if (err) + goto err_event_wq; + + fatevent = (event_regs[0] << 16) | + (event_regs[1] << 8) | + event_regs[2]; + + if (!ab3100->startup_events_read) { + ab3100->startup_events = fatevent; + ab3100->startup_events_read = true; + } + /* + * The notified parties will have to mask out the events + * they're interested in and react to them. They will be + * notified on all events, then they use the fatevent value + * to determine if they're interested. + */ + blocking_notifier_call_chain(&ab3100->event_subscribers, + fatevent, NULL); + + dev_dbg(ab3100->dev, + "IRQ Event: 0x%08x\n", fatevent); + + /* By now the IRQ should be acked and deasserted so enable it again */ + enable_irq(ab3100->i2c_client->irq); + return; + + err_event_wq: + dev_dbg(ab3100->dev, + "error in event workqueue\n"); + /* Enable the IRQ anyway, what choice do we have? */ + enable_irq(ab3100->i2c_client->irq); + return; +} + +static irqreturn_t ab3100_irq_handler(int irq, void *data) +{ + struct ab3100 *ab3100 = data; + /* + * Disable the IRQ and dispatch a worker to handle the + * event. Since the chip resides on I2C this is slow + * stuff and we will re-enable the interrupts once th + * worker has finished. + */ + disable_irq(ab3100->i2c_client->irq); + schedule_work(&ab3100->work); + return IRQ_HANDLED; +} + +#ifdef CONFIG_DEBUG_FS +/* + * Some debugfs entries only exposed if we're using debug + */ +static int ab3100_registers_print(struct seq_file *s, void *p) +{ + struct ab3100 *ab3100 = s->private; + u8 value; + u8 reg; + + seq_printf(s, "AB3100 registers:\n"); + + for (reg = 0; reg < 0xff; reg++) { + ab3100_get_register(ab3100, reg, &value); + seq_printf(s, "[0x%x]: 0x%x\n", reg, value); + } + return 0; +} + +static int ab3100_registers_open(struct inode *inode, struct file *file) +{ + return single_open(file, ab3100_registers_print, inode->i_private); +} + +static const struct file_operations ab3100_registers_fops = { + .open = ab3100_registers_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +struct ab3100_get_set_reg_priv { + struct ab3100 *ab3100; + bool mode; +}; + +static int ab3100_get_set_reg_open_file(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static int ab3100_get_set_reg(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ab3100_get_set_reg_priv *priv = file->private_data; + struct ab3100 *ab3100 = priv->ab3100; + char buf[32]; + int buf_size; + int regp; + unsigned long user_reg; + int err; + int i = 0; + + /* Get userspace string and assure termination */ + buf_size = min(count, (sizeof(buf)-1)); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + buf[buf_size] = 0; + + /* + * The idea is here to parse a string which is either + * "0xnn" for reading a register, or "0xaa 0xbb" for + * writing 0xbb to the register 0xaa. First move past + * whitespace and then begin to parse the register. + */ + while ((i < buf_size) && (buf[i] == ' ')) + i++; + regp = i; + + /* + * Advance pointer to end of string then terminate + * the register string. This is needed to satisfy + * the strict_strtoul() function. + */ + while ((i < buf_size) && (buf[i] != ' ')) + i++; + buf[i] = '\0'; + + err = strict_strtoul(&buf[regp], 16, &user_reg); + if (err) + return err; + if (user_reg > 0xff) + return -EINVAL; + + /* Either we read or we write a register here */ + if (!priv->mode) { + /* Reading */ + u8 reg = (u8) user_reg; + u8 regvalue; + + ab3100_get_register(ab3100, reg, ®value); + + dev_info(ab3100->dev, + "debug read AB3100 reg[0x%02x]: 0x%02x\n", + reg, regvalue); + } else { + int valp; + unsigned long user_value; + u8 reg = (u8) user_reg; + u8 value; + u8 regvalue; + + /* + * Writing, we need some value to write to + * the register so keep parsing the string + * from userspace. + */ + i++; + while ((i < buf_size) && (buf[i] == ' ')) + i++; + valp = i; + while ((i < buf_size) && (buf[i] != ' ')) + i++; + buf[i] = '\0'; + + err = strict_strtoul(&buf[valp], 16, &user_value); + if (err) + return err; + if (user_reg > 0xff) + return -EINVAL; + + value = (u8) user_value; + ab3100_set_register(ab3100, reg, value); + ab3100_get_register(ab3100, reg, ®value); + + dev_info(ab3100->dev, + "debug write reg[0x%02x] with 0x%02x, " + "after readback: 0x%02x\n", + reg, value, regvalue); + } + return buf_size; +} + +static const struct file_operations ab3100_get_set_reg_fops = { + .open = ab3100_get_set_reg_open_file, + .write = ab3100_get_set_reg, +}; + +static struct dentry *ab3100_dir; +static struct dentry *ab3100_reg_file; +static struct ab3100_get_set_reg_priv ab3100_get_priv; +static struct dentry *ab3100_get_reg_file; +static struct ab3100_get_set_reg_priv ab3100_set_priv; +static struct dentry *ab3100_set_reg_file; + +static void ab3100_setup_debugfs(struct ab3100 *ab3100) +{ + int err; + + ab3100_dir = debugfs_create_dir("ab3100", NULL); + if (!ab3100_dir) + goto exit_no_debugfs; + + ab3100_reg_file = debugfs_create_file("registers", + S_IRUGO, ab3100_dir, ab3100, + &ab3100_registers_fops); + if (!ab3100_reg_file) { + err = -ENOMEM; + goto exit_destroy_dir; + } + + ab3100_get_priv.ab3100 = ab3100; + ab3100_get_priv.mode = false; + ab3100_get_reg_file = debugfs_create_file("get_reg", + S_IWUGO, ab3100_dir, &ab3100_get_priv, + &ab3100_get_set_reg_fops); + if (!ab3100_get_reg_file) { + err = -ENOMEM; + goto exit_destroy_reg; + } + + ab3100_set_priv.ab3100 = ab3100; + ab3100_set_priv.mode = true; + ab3100_set_reg_file = debugfs_create_file("set_reg", + S_IWUGO, ab3100_dir, &ab3100_set_priv, + &ab3100_get_set_reg_fops); + if (!ab3100_set_reg_file) { + err = -ENOMEM; + goto exit_destroy_get_reg; + } + return; + + exit_destroy_get_reg: + debugfs_remove(ab3100_get_reg_file); + exit_destroy_reg: + debugfs_remove(ab3100_reg_file); + exit_destroy_dir: + debugfs_remove(ab3100_dir); + exit_no_debugfs: + return; +} +static inline void ab3100_remove_debugfs(void) +{ + debugfs_remove(ab3100_set_reg_file); + debugfs_remove(ab3100_get_reg_file); + debugfs_remove(ab3100_reg_file); + debugfs_remove(ab3100_dir); +} +#else +static inline void ab3100_setup_debugfs(struct ab3100 *ab3100) +{ +} +static inline void ab3100_remove_debugfs(void) +{ +} +#endif + +/* + * Basic set-up, datastructure creation/destruction and I2C interface. + * This sets up a default config in the AB3100 chip so that it + * will work as expected. + */ + +struct ab3100_init_setting { + u8 abreg; + u8 setting; +}; + +static const struct ab3100_init_setting __initdata +ab3100_init_settings[] = { + { + .abreg = AB3100_MCA, + .setting = 0x01 + }, { + .abreg = AB3100_MCB, + .setting = 0x30 + }, { + .abreg = AB3100_IMRA1, + .setting = 0x00 + }, { + .abreg = AB3100_IMRA2, + .setting = 0xFF + }, { + .abreg = AB3100_IMRA3, + .setting = 0x01 + }, { + .abreg = AB3100_IMRB1, + .setting = 0xFF + }, { + .abreg = AB3100_IMRB2, + .setting = 0xFF + }, { + .abreg = AB3100_IMRB3, + .setting = 0xFF + }, { + .abreg = AB3100_SUP, + .setting = 0x00 + }, { + .abreg = AB3100_DIS, + .setting = 0xF0 + }, { + .abreg = AB3100_D0C, + .setting = 0x00 + }, { + .abreg = AB3100_D1C, + .setting = 0x00 + }, { + .abreg = AB3100_D2C, + .setting = 0x00 + }, { + .abreg = AB3100_D3C, + .setting = 0x00 + }, +}; + +static int __init ab3100_setup(struct ab3100 *ab3100) +{ + int err = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(ab3100_init_settings); i++) { + err = ab3100_set_register(ab3100, + ab3100_init_settings[i].abreg, + ab3100_init_settings[i].setting); + if (err) + goto exit_no_setup; + } + + /* + * Special trick to make the AB3100 use the 32kHz clock (RTC) + * bit 3 in test registe 0x02 is a special, undocumented test + * register bit that only exist in AB3100 P1E + */ + if (ab3100->chip_id == 0xc4) { + dev_warn(ab3100->dev, + "AB3100 P1E variant detected, " + "forcing chip to 32KHz\n"); + err = ab3100_set_test_register(ab3100, 0x02, 0x08); + } + + exit_no_setup: + return err; +} + +/* + * Here we define all the platform devices that appear + * as children of the AB3100. These are regular platform + * devices with the IORESOURCE_IO .start and .end set + * to correspond to the internal AB3100 register range + * mapping to the corresponding subdevice. + */ + +#define AB3100_DEVICE(devname, devid) \ +static struct platform_device ab3100_##devname##_device = { \ + .name = devid, \ + .id = -1, \ +} + +/* + * This lists all the subdevices and corresponding register + * ranges. + */ +AB3100_DEVICE(dac, "ab3100-dac"); +AB3100_DEVICE(leds, "ab3100-leds"); +AB3100_DEVICE(power, "ab3100-power"); +AB3100_DEVICE(regulators, "ab3100-regulators"); +AB3100_DEVICE(sim, "ab3100-sim"); +AB3100_DEVICE(uart, "ab3100-uart"); +AB3100_DEVICE(rtc, "ab3100-rtc"); +AB3100_DEVICE(charger, "ab3100-charger"); +AB3100_DEVICE(boost, "ab3100-boost"); +AB3100_DEVICE(adc, "ab3100-adc"); +AB3100_DEVICE(fuelgauge, "ab3100-fuelgauge"); +AB3100_DEVICE(vibrator, "ab3100-vibrator"); +AB3100_DEVICE(otp, "ab3100-otp"); +AB3100_DEVICE(codec, "ab3100-codec"); + +static struct platform_device * +ab3100_platform_devs[] = { + &ab3100_dac_device, + &ab3100_leds_device, + &ab3100_power_device, + &ab3100_regulators_device, + &ab3100_sim_device, + &ab3100_uart_device, + &ab3100_rtc_device, + &ab3100_charger_device, + &ab3100_boost_device, + &ab3100_adc_device, + &ab3100_fuelgauge_device, + &ab3100_vibrator_device, + &ab3100_otp_device, + &ab3100_codec_device, +}; + +struct ab_family_id { + u8 id; + char *name; +}; + +static const struct ab_family_id ids[] __initdata = { + /* AB3100 */ + { + .id = 0xc0, + .name = "P1A" + }, { + .id = 0xc1, + .name = "P1B" + }, { + .id = 0xc2, + .name = "P1C" + }, { + .id = 0xc3, + .name = "P1D" + }, { + .id = 0xc4, + .name = "P1E" + }, { + .id = 0xc5, + .name = "P1F/R1A" + }, { + .id = 0xc6, + .name = "P1G/R1A" + }, { + .id = 0xc7, + .name = "P2A/R2A" + }, { + .id = 0xc8, + .name = "P2B/R2B" + }, + /* AB3000 variants, not supported */ + { + .id = 0xa0 + }, { + .id = 0xa1 + }, { + .id = 0xa2 + }, { + .id = 0xa3 + }, { + .id = 0xa4 + }, { + .id = 0xa5 + }, { + .id = 0xa6 + }, { + .id = 0xa7 + }, + /* Terminator */ + { + .id = 0x00, + }, +}; + +static int __init ab3100_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct ab3100 *ab3100; + int err; + int i; + + ab3100 = kzalloc(sizeof(struct ab3100), GFP_KERNEL); + if (!ab3100) { + dev_err(&client->dev, "could not allocate AB3100 device\n"); + return -ENOMEM; + } + + /* Initialize data structure */ + mutex_init(&ab3100->access_mutex); + BLOCKING_INIT_NOTIFIER_HEAD(&ab3100->event_subscribers); + + ab3100->i2c_client = client; + ab3100->dev = &ab3100->i2c_client->dev; + + i2c_set_clientdata(client, ab3100); + + /* Read chip ID register */ + err = ab3100_get_register(ab3100, AB3100_CID, + &ab3100->chip_id); + if (err) { + dev_err(&client->dev, + "could not communicate with the AB3100 analog " + "baseband chip\n"); + goto exit_no_detect; + } + + for (i = 0; ids[i].id != 0x0; i++) { + if (ids[i].id == ab3100->chip_id) { + if (ids[i].name != NULL) { + snprintf(&ab3100->chip_name[0], + sizeof(ab3100->chip_name) - 1, + "AB3100 %s", + ids[i].name); + break; + } else { + dev_err(&client->dev, + "AB3000 is not supported\n"); + goto exit_no_detect; + } + } + } + + if (ids[i].id == 0x0) { + dev_err(&client->dev, "unknown analog baseband chip id: 0x%x\n", + ab3100->chip_id); + dev_err(&client->dev, "accepting it anyway. Please update " + "the driver.\n"); + goto exit_no_detect; + } + + dev_info(&client->dev, "Detected chip: %s\n", + &ab3100->chip_name[0]); + + /* Attach a second dummy i2c_client to the test register address */ + ab3100->testreg_client = i2c_new_dummy(client->adapter, + client->addr + 1); + if (!ab3100->testreg_client) { + err = -ENOMEM; + goto exit_no_testreg_client; + } + + strlcpy(ab3100->testreg_client->name, id->name, + sizeof(ab3100->testreg_client->name)); + + err = ab3100_setup(ab3100); + if (err) + goto exit_no_setup; + + INIT_WORK(&ab3100->work, ab3100_work); + + /* This real unpredictable IRQ is of course sampled for entropy */ + err = request_irq(client->irq, ab3100_irq_handler, + IRQF_DISABLED | IRQF_SAMPLE_RANDOM, + "AB3100 IRQ", ab3100); + if (err) + goto exit_no_irq; + + /* Set parent and a pointer back to the container in device data */ + for (i = 0; i < ARRAY_SIZE(ab3100_platform_devs); i++) { + ab3100_platform_devs[i]->dev.parent = + &client->dev; + platform_set_drvdata(ab3100_platform_devs[i], ab3100); + } + + /* Register the platform devices */ + platform_add_devices(ab3100_platform_devs, + ARRAY_SIZE(ab3100_platform_devs)); + + ab3100_setup_debugfs(ab3100); + + return 0; + + exit_no_irq: + exit_no_setup: + i2c_unregister_device(ab3100->testreg_client); + exit_no_testreg_client: + exit_no_detect: + kfree(ab3100); + return err; +} + +static int __exit ab3100_remove(struct i2c_client *client) +{ + struct ab3100 *ab3100 = i2c_get_clientdata(client); + int i; + + /* Unregister subdevices */ + for (i = 0; i < ARRAY_SIZE(ab3100_platform_devs); i++) + platform_device_unregister(ab3100_platform_devs[i]); + + ab3100_remove_debugfs(); + i2c_unregister_device(ab3100->testreg_client); + + /* + * At this point, all subscribers should have unregistered + * their notifiers so deactivate IRQ + */ + free_irq(client->irq, ab3100); + kfree(ab3100); + return 0; +} + +static const struct i2c_device_id ab3100_id[] = { + { "ab3100", ab3100 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ab3100_id); + +static struct i2c_driver ab3100_driver = { + .driver = { + .name = "ab3100", + .owner = THIS_MODULE, + }, + .id_table = ab3100_id, + .probe = ab3100_probe, + .remove = __exit_p(ab3100_remove), +}; + +static int __init ab3100_i2c_init(void) +{ + return i2c_add_driver(&ab3100_driver); +} + +static void __exit ab3100_i2c_exit(void) +{ + i2c_del_driver(&ab3100_driver); +} + +subsys_initcall(ab3100_i2c_init); +module_exit(ab3100_i2c_exit); + +MODULE_AUTHOR("Linus Walleij "); +MODULE_DESCRIPTION("AB3100 core driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c index 9e485459f63b..63a2a6632106 100644 --- a/drivers/mfd/asic3.c +++ b/drivers/mfd/asic3.c @@ -17,6 +17,7 @@ */ #include +#include #include #include #include @@ -24,6 +25,51 @@ #include #include +#include +#include +#include + +enum { + ASIC3_CLOCK_SPI, + ASIC3_CLOCK_OWM, + ASIC3_CLOCK_PWM0, + ASIC3_CLOCK_PWM1, + ASIC3_CLOCK_LED0, + ASIC3_CLOCK_LED1, + ASIC3_CLOCK_LED2, + ASIC3_CLOCK_SD_HOST, + ASIC3_CLOCK_SD_BUS, + ASIC3_CLOCK_SMBUS, + ASIC3_CLOCK_EX0, + ASIC3_CLOCK_EX1, +}; + +struct asic3_clk { + int enabled; + unsigned int cdex; + unsigned long rate; +}; + +#define INIT_CDEX(_name, _rate) \ + [ASIC3_CLOCK_##_name] = { \ + .cdex = CLOCK_CDEX_##_name, \ + .rate = _rate, \ + } + +struct asic3_clk asic3_clk_init[] __initdata = { + INIT_CDEX(SPI, 0), + INIT_CDEX(OWM, 5000000), + INIT_CDEX(PWM0, 0), + INIT_CDEX(PWM1, 0), + INIT_CDEX(LED0, 0), + INIT_CDEX(LED1, 0), + INIT_CDEX(LED2, 0), + INIT_CDEX(SD_HOST, 24576000), + INIT_CDEX(SD_BUS, 12288000), + INIT_CDEX(SMBUS, 0), + INIT_CDEX(EX0, 32768), + INIT_CDEX(EX1, 24576000), +}; struct asic3 { void __iomem *mapping; @@ -34,6 +80,8 @@ struct asic3 { u16 irq_bothedge[4]; struct gpio_chip gpio; struct device *dev; + + struct asic3_clk clocks[ARRAY_SIZE(asic3_clk_init)]; }; static int asic3_gpio_get(struct gpio_chip *chip, unsigned offset); @@ -52,6 +100,21 @@ static inline u32 asic3_read_register(struct asic3 *asic, (reg >> asic->bus_shift)); } +void asic3_set_register(struct asic3 *asic, u32 reg, u32 bits, bool set) +{ + unsigned long flags; + u32 val; + + spin_lock_irqsave(&asic->lock, flags); + val = asic3_read_register(asic, reg); + if (set) + val |= bits; + else + val &= ~bits; + asic3_write_register(asic, reg, val); + spin_unlock_irqrestore(&asic->lock, flags); +} + /* IRQs */ #define MAX_ASIC_ISR_LOOPS 20 #define ASIC3_GPIO_BASE_INCR \ @@ -525,6 +588,240 @@ static int asic3_gpio_remove(struct platform_device *pdev) return gpiochip_remove(&asic->gpio); } +static int asic3_clk_enable(struct asic3 *asic, struct asic3_clk *clk) +{ + unsigned long flags; + u32 cdex; + + spin_lock_irqsave(&asic->lock, flags); + if (clk->enabled++ == 0) { + cdex = asic3_read_register(asic, ASIC3_OFFSET(CLOCK, CDEX)); + cdex |= clk->cdex; + asic3_write_register(asic, ASIC3_OFFSET(CLOCK, CDEX), cdex); + } + spin_unlock_irqrestore(&asic->lock, flags); + + return 0; +} + +static void asic3_clk_disable(struct asic3 *asic, struct asic3_clk *clk) +{ + unsigned long flags; + u32 cdex; + + WARN_ON(clk->enabled == 0); + + spin_lock_irqsave(&asic->lock, flags); + if (--clk->enabled == 0) { + cdex = asic3_read_register(asic, ASIC3_OFFSET(CLOCK, CDEX)); + cdex &= ~clk->cdex; + asic3_write_register(asic, ASIC3_OFFSET(CLOCK, CDEX), cdex); + } + spin_unlock_irqrestore(&asic->lock, flags); +} + +/* MFD cells (SPI, PWM, LED, DS1WM, MMC) */ +static struct ds1wm_driver_data ds1wm_pdata = { + .active_high = 1, +}; + +static struct resource ds1wm_resources[] = { + { + .start = ASIC3_OWM_BASE, + .end = ASIC3_OWM_BASE + 0x13, + .flags = IORESOURCE_MEM, + }, + { + .start = ASIC3_IRQ_OWM, + .start = ASIC3_IRQ_OWM, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE, + }, +}; + +static int ds1wm_enable(struct platform_device *pdev) +{ + struct asic3 *asic = dev_get_drvdata(pdev->dev.parent); + + /* Turn on external clocks and the OWM clock */ + asic3_clk_enable(asic, &asic->clocks[ASIC3_CLOCK_EX0]); + asic3_clk_enable(asic, &asic->clocks[ASIC3_CLOCK_EX1]); + asic3_clk_enable(asic, &asic->clocks[ASIC3_CLOCK_OWM]); + msleep(1); + + /* Reset and enable DS1WM */ + asic3_set_register(asic, ASIC3_OFFSET(EXTCF, RESET), + ASIC3_EXTCF_OWM_RESET, 1); + msleep(1); + asic3_set_register(asic, ASIC3_OFFSET(EXTCF, RESET), + ASIC3_EXTCF_OWM_RESET, 0); + msleep(1); + asic3_set_register(asic, ASIC3_OFFSET(EXTCF, SELECT), + ASIC3_EXTCF_OWM_EN, 1); + msleep(1); + + return 0; +} + +static int ds1wm_disable(struct platform_device *pdev) +{ + struct asic3 *asic = dev_get_drvdata(pdev->dev.parent); + + asic3_set_register(asic, ASIC3_OFFSET(EXTCF, SELECT), + ASIC3_EXTCF_OWM_EN, 0); + + asic3_clk_disable(asic, &asic->clocks[ASIC3_CLOCK_OWM]); + asic3_clk_disable(asic, &asic->clocks[ASIC3_CLOCK_EX0]); + asic3_clk_disable(asic, &asic->clocks[ASIC3_CLOCK_EX1]); + + return 0; +} + +static struct mfd_cell asic3_cell_ds1wm = { + .name = "ds1wm", + .enable = ds1wm_enable, + .disable = ds1wm_disable, + .driver_data = &ds1wm_pdata, + .num_resources = ARRAY_SIZE(ds1wm_resources), + .resources = ds1wm_resources, +}; + +static struct tmio_mmc_data asic3_mmc_data = { + .hclk = 24576000, +}; + +static struct resource asic3_mmc_resources[] = { + { + .start = ASIC3_SD_CTRL_BASE, + .end = ASIC3_SD_CTRL_BASE + 0x3ff, + .flags = IORESOURCE_MEM, + }, + { + .start = ASIC3_SD_CONFIG_BASE, + .end = ASIC3_SD_CONFIG_BASE + 0x1ff, + .flags = IORESOURCE_MEM, + }, + { + .start = 0, + .end = 0, + .flags = IORESOURCE_IRQ, + }, +}; + +static int asic3_mmc_enable(struct platform_device *pdev) +{ + struct asic3 *asic = dev_get_drvdata(pdev->dev.parent); + + /* Not sure if it must be done bit by bit, but leaving as-is */ + asic3_set_register(asic, ASIC3_OFFSET(SDHWCTRL, SDCONF), + ASIC3_SDHWCTRL_LEVCD, 1); + asic3_set_register(asic, ASIC3_OFFSET(SDHWCTRL, SDCONF), + ASIC3_SDHWCTRL_LEVWP, 1); + asic3_set_register(asic, ASIC3_OFFSET(SDHWCTRL, SDCONF), + ASIC3_SDHWCTRL_SUSPEND, 0); + asic3_set_register(asic, ASIC3_OFFSET(SDHWCTRL, SDCONF), + ASIC3_SDHWCTRL_PCLR, 0); + + asic3_clk_enable(asic, &asic->clocks[ASIC3_CLOCK_EX0]); + /* CLK32 used for card detection and for interruption detection + * when HCLK is stopped. + */ + asic3_clk_enable(asic, &asic->clocks[ASIC3_CLOCK_EX1]); + msleep(1); + + /* HCLK 24.576 MHz, BCLK 12.288 MHz: */ + asic3_write_register(asic, ASIC3_OFFSET(CLOCK, SEL), + CLOCK_SEL_CX | CLOCK_SEL_SD_HCLK_SEL); + + asic3_clk_enable(asic, &asic->clocks[ASIC3_CLOCK_SD_HOST]); + asic3_clk_enable(asic, &asic->clocks[ASIC3_CLOCK_SD_BUS]); + msleep(1); + + asic3_set_register(asic, ASIC3_OFFSET(EXTCF, SELECT), + ASIC3_EXTCF_SD_MEM_ENABLE, 1); + + /* Enable SD card slot 3.3V power supply */ + asic3_set_register(asic, ASIC3_OFFSET(SDHWCTRL, SDCONF), + ASIC3_SDHWCTRL_SDPWR, 1); + + return 0; +} + +static int asic3_mmc_disable(struct platform_device *pdev) +{ + struct asic3 *asic = dev_get_drvdata(pdev->dev.parent); + + /* Put in suspend mode */ + asic3_set_register(asic, ASIC3_OFFSET(SDHWCTRL, SDCONF), + ASIC3_SDHWCTRL_SUSPEND, 1); + + /* Disable clocks */ + asic3_clk_disable(asic, &asic->clocks[ASIC3_CLOCK_SD_HOST]); + asic3_clk_disable(asic, &asic->clocks[ASIC3_CLOCK_SD_BUS]); + asic3_clk_disable(asic, &asic->clocks[ASIC3_CLOCK_EX0]); + asic3_clk_disable(asic, &asic->clocks[ASIC3_CLOCK_EX1]); + return 0; +} + +static struct mfd_cell asic3_cell_mmc = { + .name = "tmio-mmc", + .enable = asic3_mmc_enable, + .disable = asic3_mmc_disable, + .driver_data = &asic3_mmc_data, + .num_resources = ARRAY_SIZE(asic3_mmc_resources), + .resources = asic3_mmc_resources, +}; + +static int __init asic3_mfd_probe(struct platform_device *pdev, + struct resource *mem) +{ + struct asic3 *asic = platform_get_drvdata(pdev); + struct resource *mem_sdio; + int irq, ret; + + mem_sdio = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!mem_sdio) + dev_dbg(asic->dev, "no SDIO MEM resource\n"); + + irq = platform_get_irq(pdev, 1); + if (irq < 0) + dev_dbg(asic->dev, "no SDIO IRQ resource\n"); + + /* DS1WM */ + asic3_set_register(asic, ASIC3_OFFSET(EXTCF, SELECT), + ASIC3_EXTCF_OWM_SMB, 0); + + ds1wm_resources[0].start >>= asic->bus_shift; + ds1wm_resources[0].end >>= asic->bus_shift; + + asic3_cell_ds1wm.platform_data = &asic3_cell_ds1wm; + asic3_cell_ds1wm.data_size = sizeof(asic3_cell_ds1wm); + + /* MMC */ + asic3_mmc_resources[0].start >>= asic->bus_shift; + asic3_mmc_resources[0].end >>= asic->bus_shift; + asic3_mmc_resources[1].start >>= asic->bus_shift; + asic3_mmc_resources[1].end >>= asic->bus_shift; + + asic3_cell_mmc.platform_data = &asic3_cell_mmc; + asic3_cell_mmc.data_size = sizeof(asic3_cell_mmc); + + ret = mfd_add_devices(&pdev->dev, pdev->id, + &asic3_cell_ds1wm, 1, mem, asic->irq_base); + if (ret < 0) + goto out; + + if (mem_sdio && (irq >= 0)) + ret = mfd_add_devices(&pdev->dev, pdev->id, + &asic3_cell_mmc, 1, mem_sdio, irq); + + out: + return ret; +} + +static void asic3_mfd_remove(struct platform_device *pdev) +{ + mfd_remove_devices(&pdev->dev); +} /* Core */ static int __init asic3_probe(struct platform_device *pdev) @@ -533,7 +830,6 @@ static int __init asic3_probe(struct platform_device *pdev) struct asic3 *asic; struct resource *mem; unsigned long clksel; - int map_size; int ret = 0; asic = kzalloc(sizeof(struct asic3), GFP_KERNEL); @@ -553,8 +849,7 @@ static int __init asic3_probe(struct platform_device *pdev) goto out_free; } - map_size = mem->end - mem->start + 1; - asic->mapping = ioremap(mem->start, map_size); + asic->mapping = ioremap(mem->start, resource_size(mem)); if (!asic->mapping) { ret = -ENOMEM; dev_err(asic->dev, "Couldn't ioremap\n"); @@ -564,7 +859,7 @@ static int __init asic3_probe(struct platform_device *pdev) asic->irq_base = pdata->irq_base; /* calculate bus shift from mem resource */ - asic->bus_shift = 2 - (map_size >> 12); + asic->bus_shift = 2 - (resource_size(mem) >> 12); clksel = 0; asic3_write_register(asic, ASIC3_OFFSET(CLOCK, SEL), clksel); @@ -590,6 +885,13 @@ static int __init asic3_probe(struct platform_device *pdev) goto out_irq; } + /* Making a per-device copy is only needed for the + * theoretical case of multiple ASIC3s on one board: + */ + memcpy(asic->clocks, asic3_clk_init, sizeof(asic3_clk_init)); + + asic3_mfd_probe(pdev, mem); + dev_info(asic->dev, "ASIC3 Core driver\n"); return 0; @@ -611,6 +913,8 @@ static int asic3_remove(struct platform_device *pdev) int ret; struct asic3 *asic = platform_get_drvdata(pdev); + asic3_mfd_remove(pdev); + ret = asic3_gpio_remove(pdev); if (ret < 0) return ret; diff --git a/drivers/mfd/da903x.c b/drivers/mfd/da903x.c index 7283d88656af..e5ffe5617393 100644 --- a/drivers/mfd/da903x.c +++ b/drivers/mfd/da903x.c @@ -561,7 +561,7 @@ static int __init da903x_init(void) { return i2c_add_driver(&da903x_driver); } -module_init(da903x_init); +subsys_initcall(da903x_init); static void __exit da903x_exit(void) { diff --git a/drivers/mfd/ezx-pcap.c b/drivers/mfd/ezx-pcap.c new file mode 100644 index 000000000000..671a7efe86a8 --- /dev/null +++ b/drivers/mfd/ezx-pcap.c @@ -0,0 +1,505 @@ +/* + * Driver for Motorola PCAP2 as present in EZX phones + * + * Copyright (C) 2006 Harald Welte + * Copyright (C) 2009 Daniel Ribeiro + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#define PCAP_ADC_MAXQ 8 +struct pcap_adc_request { + u8 bank; + u8 ch[2]; + u32 flags; + void (*callback)(void *, u16[]); + void *data; +}; + +struct pcap_adc_sync_request { + u16 res[2]; + struct completion completion; +}; + +struct pcap_chip { + struct spi_device *spi; + + /* IO */ + u32 buf; + struct mutex io_mutex; + + /* IRQ */ + unsigned int irq_base; + u32 msr; + struct work_struct isr_work; + struct work_struct msr_work; + struct workqueue_struct *workqueue; + + /* ADC */ + struct pcap_adc_request *adc_queue[PCAP_ADC_MAXQ]; + u8 adc_head; + u8 adc_tail; + struct mutex adc_mutex; +}; + +/* IO */ +static int ezx_pcap_putget(struct pcap_chip *pcap, u32 *data) +{ + struct spi_transfer t; + struct spi_message m; + int status; + + memset(&t, 0, sizeof t); + spi_message_init(&m); + t.len = sizeof(u32); + spi_message_add_tail(&t, &m); + + pcap->buf = *data; + t.tx_buf = (u8 *) &pcap->buf; + t.rx_buf = (u8 *) &pcap->buf; + status = spi_sync(pcap->spi, &m); + + if (status == 0) + *data = pcap->buf; + + return status; +} + +int ezx_pcap_write(struct pcap_chip *pcap, u8 reg_num, u32 value) +{ + int ret; + + mutex_lock(&pcap->io_mutex); + value &= PCAP_REGISTER_VALUE_MASK; + value |= PCAP_REGISTER_WRITE_OP_BIT + | (reg_num << PCAP_REGISTER_ADDRESS_SHIFT); + ret = ezx_pcap_putget(pcap, &value); + mutex_unlock(&pcap->io_mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(ezx_pcap_write); + +int ezx_pcap_read(struct pcap_chip *pcap, u8 reg_num, u32 *value) +{ + int ret; + + mutex_lock(&pcap->io_mutex); + *value = PCAP_REGISTER_READ_OP_BIT + | (reg_num << PCAP_REGISTER_ADDRESS_SHIFT); + + ret = ezx_pcap_putget(pcap, value); + mutex_unlock(&pcap->io_mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(ezx_pcap_read); + +/* IRQ */ +static inline unsigned int irq2pcap(struct pcap_chip *pcap, int irq) +{ + return 1 << (irq - pcap->irq_base); +} + +int pcap_to_irq(struct pcap_chip *pcap, int irq) +{ + return pcap->irq_base + irq; +} +EXPORT_SYMBOL_GPL(pcap_to_irq); + +static void pcap_mask_irq(unsigned int irq) +{ + struct pcap_chip *pcap = get_irq_chip_data(irq); + + pcap->msr |= irq2pcap(pcap, irq); + queue_work(pcap->workqueue, &pcap->msr_work); +} + +static void pcap_unmask_irq(unsigned int irq) +{ + struct pcap_chip *pcap = get_irq_chip_data(irq); + + pcap->msr &= ~irq2pcap(pcap, irq); + queue_work(pcap->workqueue, &pcap->msr_work); +} + +static struct irq_chip pcap_irq_chip = { + .name = "pcap", + .mask = pcap_mask_irq, + .unmask = pcap_unmask_irq, +}; + +static void pcap_msr_work(struct work_struct *work) +{ + struct pcap_chip *pcap = container_of(work, struct pcap_chip, msr_work); + + ezx_pcap_write(pcap, PCAP_REG_MSR, pcap->msr); +} + +static void pcap_isr_work(struct work_struct *work) +{ + struct pcap_chip *pcap = container_of(work, struct pcap_chip, isr_work); + struct pcap_platform_data *pdata = pcap->spi->dev.platform_data; + u32 msr, isr, int_sel, service; + int irq; + + ezx_pcap_read(pcap, PCAP_REG_MSR, &msr); + ezx_pcap_read(pcap, PCAP_REG_ISR, &isr); + + /* We cant service/ack irqs that are assigned to port 2 */ + if (!(pdata->config & PCAP_SECOND_PORT)) { + ezx_pcap_read(pcap, PCAP_REG_INT_SEL, &int_sel); + isr &= ~int_sel; + } + ezx_pcap_write(pcap, PCAP_REG_ISR, isr); + + local_irq_disable(); + service = isr & ~msr; + + for (irq = pcap->irq_base; service; service >>= 1, irq++) { + if (service & 1) { + struct irq_desc *desc = irq_to_desc(irq); + + if (WARN(!desc, KERN_WARNING + "Invalid PCAP IRQ %d\n", irq)) + break; + + if (desc->status & IRQ_DISABLED) + note_interrupt(irq, desc, IRQ_NONE); + else + desc->handle_irq(irq, desc); + } + } + local_irq_enable(); +} + +static void pcap_irq_handler(unsigned int irq, struct irq_desc *desc) +{ + struct pcap_chip *pcap = get_irq_data(irq); + + desc->chip->ack(irq); + queue_work(pcap->workqueue, &pcap->isr_work); + return; +} + +/* ADC */ +static void pcap_disable_adc(struct pcap_chip *pcap) +{ + u32 tmp; + + ezx_pcap_read(pcap, PCAP_REG_ADC, &tmp); + tmp &= ~(PCAP_ADC_ADEN|PCAP_ADC_BATT_I_ADC|PCAP_ADC_BATT_I_POLARITY); + ezx_pcap_write(pcap, PCAP_REG_ADC, tmp); +} + +static void pcap_adc_trigger(struct pcap_chip *pcap) +{ + u32 tmp; + u8 head; + + mutex_lock(&pcap->adc_mutex); + head = pcap->adc_head; + if (!pcap->adc_queue[head]) { + /* queue is empty, save power */ + pcap_disable_adc(pcap); + mutex_unlock(&pcap->adc_mutex); + return; + } + mutex_unlock(&pcap->adc_mutex); + + /* start conversion on requested bank */ + tmp = pcap->adc_queue[head]->flags | PCAP_ADC_ADEN; + + if (pcap->adc_queue[head]->bank == PCAP_ADC_BANK_1) + tmp |= PCAP_ADC_AD_SEL1; + + ezx_pcap_write(pcap, PCAP_REG_ADC, tmp); + ezx_pcap_write(pcap, PCAP_REG_ADR, PCAP_ADR_ASC); +} + +static irqreturn_t pcap_adc_irq(int irq, void *_pcap) +{ + struct pcap_chip *pcap = _pcap; + struct pcap_adc_request *req; + u16 res[2]; + u32 tmp; + + mutex_lock(&pcap->adc_mutex); + req = pcap->adc_queue[pcap->adc_head]; + + if (WARN(!req, KERN_WARNING "adc irq without pending request\n")) + return IRQ_HANDLED; + + /* read requested channels results */ + ezx_pcap_read(pcap, PCAP_REG_ADC, &tmp); + tmp &= ~(PCAP_ADC_ADA1_MASK | PCAP_ADC_ADA2_MASK); + tmp |= (req->ch[0] << PCAP_ADC_ADA1_SHIFT); + tmp |= (req->ch[1] << PCAP_ADC_ADA2_SHIFT); + ezx_pcap_write(pcap, PCAP_REG_ADC, tmp); + ezx_pcap_read(pcap, PCAP_REG_ADR, &tmp); + res[0] = (tmp & PCAP_ADR_ADD1_MASK) >> PCAP_ADR_ADD1_SHIFT; + res[1] = (tmp & PCAP_ADR_ADD2_MASK) >> PCAP_ADR_ADD2_SHIFT; + + pcap->adc_queue[pcap->adc_head] = NULL; + pcap->adc_head = (pcap->adc_head + 1) & (PCAP_ADC_MAXQ - 1); + mutex_unlock(&pcap->adc_mutex); + + /* pass the results and release memory */ + req->callback(req->data, res); + kfree(req); + + /* trigger next conversion (if any) on queue */ + pcap_adc_trigger(pcap); + + return IRQ_HANDLED; +} + +int pcap_adc_async(struct pcap_chip *pcap, u8 bank, u32 flags, u8 ch[], + void *callback, void *data) +{ + struct pcap_adc_request *req; + + /* This will be freed after we have a result */ + req = kmalloc(sizeof(struct pcap_adc_request), GFP_KERNEL); + if (!req) + return -ENOMEM; + + req->bank = bank; + req->flags = flags; + req->ch[0] = ch[0]; + req->ch[1] = ch[1]; + req->callback = callback; + req->data = data; + + mutex_lock(&pcap->adc_mutex); + if (pcap->adc_queue[pcap->adc_tail]) { + mutex_unlock(&pcap->adc_mutex); + kfree(req); + return -EBUSY; + } + pcap->adc_queue[pcap->adc_tail] = req; + pcap->adc_tail = (pcap->adc_tail + 1) & (PCAP_ADC_MAXQ - 1); + mutex_unlock(&pcap->adc_mutex); + + /* start conversion */ + pcap_adc_trigger(pcap); + + return 0; +} +EXPORT_SYMBOL_GPL(pcap_adc_async); + +static void pcap_adc_sync_cb(void *param, u16 res[]) +{ + struct pcap_adc_sync_request *req = param; + + req->res[0] = res[0]; + req->res[1] = res[1]; + complete(&req->completion); +} + +int pcap_adc_sync(struct pcap_chip *pcap, u8 bank, u32 flags, u8 ch[], + u16 res[]) +{ + struct pcap_adc_sync_request sync_data; + int ret; + + init_completion(&sync_data.completion); + ret = pcap_adc_async(pcap, bank, flags, ch, pcap_adc_sync_cb, + &sync_data); + if (ret) + return ret; + wait_for_completion(&sync_data.completion); + res[0] = sync_data.res[0]; + res[1] = sync_data.res[1]; + + return 0; +} +EXPORT_SYMBOL_GPL(pcap_adc_sync); + +/* subdevs */ +static int pcap_remove_subdev(struct device *dev, void *unused) +{ + platform_device_unregister(to_platform_device(dev)); + return 0; +} + +static int __devinit pcap_add_subdev(struct pcap_chip *pcap, + struct pcap_subdev *subdev) +{ + struct platform_device *pdev; + + pdev = platform_device_alloc(subdev->name, subdev->id); + pdev->dev.parent = &pcap->spi->dev; + pdev->dev.platform_data = subdev->platform_data; + platform_set_drvdata(pdev, pcap); + + return platform_device_add(pdev); +} + +static int __devexit ezx_pcap_remove(struct spi_device *spi) +{ + struct pcap_chip *pcap = dev_get_drvdata(&spi->dev); + struct pcap_platform_data *pdata = spi->dev.platform_data; + int i, adc_irq; + + /* remove all registered subdevs */ + device_for_each_child(&spi->dev, NULL, pcap_remove_subdev); + + /* cleanup ADC */ + adc_irq = pcap_to_irq(pcap, (pdata->config & PCAP_SECOND_PORT) ? + PCAP_IRQ_ADCDONE2 : PCAP_IRQ_ADCDONE); + free_irq(adc_irq, pcap); + mutex_lock(&pcap->adc_mutex); + for (i = 0; i < PCAP_ADC_MAXQ; i++) + kfree(pcap->adc_queue[i]); + mutex_unlock(&pcap->adc_mutex); + + /* cleanup irqchip */ + for (i = pcap->irq_base; i < (pcap->irq_base + PCAP_NIRQS); i++) + set_irq_chip_and_handler(i, NULL, NULL); + + destroy_workqueue(pcap->workqueue); + + kfree(pcap); + + return 0; +} + +static int __devinit ezx_pcap_probe(struct spi_device *spi) +{ + struct pcap_platform_data *pdata = spi->dev.platform_data; + struct pcap_chip *pcap; + int i, adc_irq; + int ret = -ENODEV; + + /* platform data is required */ + if (!pdata) + goto ret; + + pcap = kzalloc(sizeof(*pcap), GFP_KERNEL); + if (!pcap) { + ret = -ENOMEM; + goto ret; + } + + mutex_init(&pcap->io_mutex); + mutex_init(&pcap->adc_mutex); + INIT_WORK(&pcap->isr_work, pcap_isr_work); + INIT_WORK(&pcap->msr_work, pcap_msr_work); + dev_set_drvdata(&spi->dev, pcap); + + /* setup spi */ + spi->bits_per_word = 32; + spi->mode = SPI_MODE_0 | (pdata->config & PCAP_CS_AH ? SPI_CS_HIGH : 0); + ret = spi_setup(spi); + if (ret) + goto free_pcap; + + pcap->spi = spi; + + /* setup irq */ + pcap->irq_base = pdata->irq_base; + pcap->workqueue = create_singlethread_workqueue("pcapd"); + if (!pcap->workqueue) { + dev_err(&spi->dev, "cant create pcap thread\n"); + goto free_pcap; + } + + /* redirect interrupts to AP, except adcdone2 */ + if (!(pdata->config & PCAP_SECOND_PORT)) + ezx_pcap_write(pcap, PCAP_REG_INT_SEL, + (1 << PCAP_IRQ_ADCDONE2)); + + /* setup irq chip */ + for (i = pcap->irq_base; i < (pcap->irq_base + PCAP_NIRQS); i++) { + set_irq_chip_and_handler(i, &pcap_irq_chip, handle_simple_irq); + set_irq_chip_data(i, pcap); +#ifdef CONFIG_ARM + set_irq_flags(i, IRQF_VALID); +#else + set_irq_noprobe(i); +#endif + } + + /* mask/ack all PCAP interrupts */ + ezx_pcap_write(pcap, PCAP_REG_MSR, PCAP_MASK_ALL_INTERRUPT); + ezx_pcap_write(pcap, PCAP_REG_ISR, PCAP_CLEAR_INTERRUPT_REGISTER); + pcap->msr = PCAP_MASK_ALL_INTERRUPT; + + set_irq_type(spi->irq, IRQ_TYPE_EDGE_RISING); + set_irq_data(spi->irq, pcap); + set_irq_chained_handler(spi->irq, pcap_irq_handler); + set_irq_wake(spi->irq, 1); + + /* ADC */ + adc_irq = pcap_to_irq(pcap, (pdata->config & PCAP_SECOND_PORT) ? + PCAP_IRQ_ADCDONE2 : PCAP_IRQ_ADCDONE); + + ret = request_irq(adc_irq, pcap_adc_irq, 0, "ADC", pcap); + if (ret) + goto free_irqchip; + + /* setup subdevs */ + for (i = 0; i < pdata->num_subdevs; i++) { + ret = pcap_add_subdev(pcap, &pdata->subdevs[i]); + if (ret) + goto remove_subdevs; + } + + /* board specific quirks */ + if (pdata->init) + pdata->init(pcap); + + return 0; + +remove_subdevs: + device_for_each_child(&spi->dev, NULL, pcap_remove_subdev); +/* free_adc: */ + free_irq(adc_irq, pcap); +free_irqchip: + for (i = pcap->irq_base; i < (pcap->irq_base + PCAP_NIRQS); i++) + set_irq_chip_and_handler(i, NULL, NULL); +/* destroy_workqueue: */ + destroy_workqueue(pcap->workqueue); +free_pcap: + kfree(pcap); +ret: + return ret; +} + +static struct spi_driver ezxpcap_driver = { + .probe = ezx_pcap_probe, + .remove = __devexit_p(ezx_pcap_remove), + .driver = { + .name = "ezx-pcap", + .owner = THIS_MODULE, + }, +}; + +static int __init ezx_pcap_init(void) +{ + return spi_register_driver(&ezxpcap_driver); +} + +static void __exit ezx_pcap_exit(void) +{ + spi_unregister_driver(&ezxpcap_driver); +} + +module_init(ezx_pcap_init); +module_exit(ezx_pcap_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Daniel Ribeiro / Harald Welte"); +MODULE_DESCRIPTION("Motorola PCAP2 ASIC Driver"); diff --git a/drivers/mfd/htc-pasic3.c b/drivers/mfd/htc-pasic3.c index 386da1566fcc..cb73051e43db 100644 --- a/drivers/mfd/htc-pasic3.c +++ b/drivers/mfd/htc-pasic3.c @@ -35,7 +35,7 @@ struct pasic3_data { */ void pasic3_write_register(struct device *dev, u32 reg, u8 val) { - struct pasic3_data *asic = dev->driver_data; + struct pasic3_data *asic = dev_get_drvdata(dev); int bus_shift = asic->bus_shift; void __iomem *addr = asic->mapping + (REG_ADDR << bus_shift); void __iomem *data = asic->mapping + (REG_DATA << bus_shift); @@ -50,7 +50,7 @@ EXPORT_SYMBOL(pasic3_write_register); /* for leds-pasic3 */ */ u8 pasic3_read_register(struct device *dev, u32 reg) { - struct pasic3_data *asic = dev->driver_data; + struct pasic3_data *asic = dev_get_drvdata(dev); int bus_shift = asic->bus_shift; void __iomem *addr = asic->mapping + (REG_ADDR << bus_shift); void __iomem *data = asic->mapping + (REG_DATA << bus_shift); diff --git a/drivers/mfd/pcf50633-core.c b/drivers/mfd/pcf50633-core.c index 11a6248cc1c1..8d3c38bf9714 100644 --- a/drivers/mfd/pcf50633-core.c +++ b/drivers/mfd/pcf50633-core.c @@ -618,7 +618,7 @@ static int __devinit pcf50633_probe(struct i2c_client *client, pdev->dev.parent = pcf->dev; pdev->dev.platform_data = &pdata->reg_init_data[i]; - pdev->dev.driver_data = pcf; + dev_set_drvdata(&pdev->dev, pcf); pcf->regulator_pdev[i] = pdev; platform_device_add(pdev); @@ -705,5 +705,5 @@ MODULE_DESCRIPTION("I2C chip driver for NXP PCF50633 PMU"); MODULE_AUTHOR("Harald Welte "); MODULE_LICENSE("GPL"); -module_init(pcf50633_init); +subsys_initcall(pcf50633_init); module_exit(pcf50633_exit); diff --git a/drivers/mfd/pcf50633-gpio.c b/drivers/mfd/pcf50633-gpio.c index 2fa2eca5c9cc..9ab19a8f669d 100644 --- a/drivers/mfd/pcf50633-gpio.c +++ b/drivers/mfd/pcf50633-gpio.c @@ -15,6 +15,7 @@ */ #include +#include #include #include @@ -116,3 +117,5 @@ int pcf50633_gpio_power_supply_set(struct pcf50633 *pcf, return pcf50633_reg_set_bit_mask(pcf, reg, mask, val); } EXPORT_SYMBOL_GPL(pcf50633_gpio_power_supply_set); + +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c index e9f4323dd2cb..0a255c1f1ce7 100644 --- a/drivers/mfd/t7l66xb.c +++ b/drivers/mfd/t7l66xb.c @@ -108,6 +108,10 @@ static int t7l66xb_mmc_disable(struct platform_device *mmc) /*--------------------------------------------------------------------------*/ +static struct tmio_mmc_data t7166xb_mmc_data = { + .hclk = 24000000, +}; + static const struct resource t7l66xb_mmc_resources[] = { { .start = 0x800, @@ -149,6 +153,7 @@ static struct mfd_cell t7l66xb_cells[] = { .name = "tmio-mmc", .enable = t7l66xb_mmc_enable, .disable = t7l66xb_mmc_disable, + .driver_data = &t7166xb_mmc_data, .num_resources = ARRAY_SIZE(t7l66xb_mmc_resources), .resources = t7l66xb_mmc_resources, }, diff --git a/drivers/mfd/tc6387xb.c b/drivers/mfd/tc6387xb.c index 43222c12fec1..3280ab33f88a 100644 --- a/drivers/mfd/tc6387xb.c +++ b/drivers/mfd/tc6387xb.c @@ -75,6 +75,10 @@ static int tc6387xb_mmc_disable(struct platform_device *mmc) /*--------------------------------------------------------------------------*/ +static struct tmio_mmc_data tc6387xb_mmc_data = { + .hclk = 24000000, +}; + static struct resource tc6387xb_mmc_resources[] = { { .start = 0x800, @@ -98,6 +102,7 @@ static struct mfd_cell tc6387xb_cells[] = { .name = "tmio-mmc", .enable = tc6387xb_mmc_enable, .disable = tc6387xb_mmc_disable, + .driver_data = &tc6387xb_mmc_data, .num_resources = ARRAY_SIZE(tc6387xb_mmc_resources), .resources = tc6387xb_mmc_resources, }, diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c index 77a12fc8045e..1429a7341a9a 100644 --- a/drivers/mfd/tc6393xb.c +++ b/drivers/mfd/tc6393xb.c @@ -136,6 +136,10 @@ static int tc6393xb_nand_enable(struct platform_device *nand) return 0; } +static struct tmio_mmc_data tc6393xb_mmc_data = { + .hclk = 24000000, +}; + static struct resource __devinitdata tc6393xb_nand_resources[] = { { .start = 0x1000, @@ -351,6 +355,7 @@ static struct mfd_cell __devinitdata tc6393xb_cells[] = { }, [TC6393XB_CELL_MMC] = { .name = "tmio-mmc", + .driver_data = &tc6393xb_mmc_data, .num_resources = ARRAY_SIZE(tc6393xb_mmc_resources), .resources = tc6393xb_mmc_resources, }, diff --git a/drivers/mfd/twl4030-core.c b/drivers/mfd/twl4030-core.c index ec90e953adce..ca54996ffd0e 100644 --- a/drivers/mfd/twl4030-core.c +++ b/drivers/mfd/twl4030-core.c @@ -101,6 +101,12 @@ #define twl_has_usb() false #endif +#if defined(CONFIG_TWL4030_WATCHDOG) || \ + defined(CONFIG_TWL4030_WATCHDOG_MODULE) +#define twl_has_watchdog() true +#else +#define twl_has_watchdog() false +#endif /* Triton Core internal information (BEGIN) */ @@ -526,6 +532,12 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features) usb_transceiver = child; } + if (twl_has_watchdog()) { + child = add_child(0, "twl4030_wdt", NULL, 0, false, 0, 0); + if (IS_ERR(child)) + return PTR_ERR(child); + } + if (twl_has_regulator()) { /* child = add_regulator(TWL4030_REG_VPLL1, pdata->vpll1); @@ -647,7 +659,7 @@ static inline int __init unprotect_pm_master(void) return e; } -static void __init clocks_init(struct device *dev) +static void clocks_init(struct device *dev) { int e = 0; struct clk *osc; diff --git a/drivers/mfd/twl4030-irq.c b/drivers/mfd/twl4030-irq.c index aca2670afd78..bae61b22501c 100644 --- a/drivers/mfd/twl4030-irq.c +++ b/drivers/mfd/twl4030-irq.c @@ -255,7 +255,7 @@ static int twl4030_irq_thread(void *data) * thread. All we do here is acknowledge and mask the interrupt and wakeup * the kernel thread. */ -static void handle_twl4030_pih(unsigned int irq, irq_desc_t *desc) +static void handle_twl4030_pih(unsigned int irq, struct irq_desc *desc) { /* Acknowledge, clear *AND* mask the interrupt... */ desc->chip->ack(irq); diff --git a/drivers/mfd/ucb1400_core.c b/drivers/mfd/ucb1400_core.c index 178159e264ce..78c2135c5de6 100644 --- a/drivers/mfd/ucb1400_core.c +++ b/drivers/mfd/ucb1400_core.c @@ -23,6 +23,26 @@ #include #include +unsigned int ucb1400_adc_read(struct snd_ac97 *ac97, u16 adc_channel, + int adcsync) +{ + unsigned int val; + + if (adcsync) + adc_channel |= UCB_ADC_SYNC_ENA; + + ucb1400_reg_write(ac97, UCB_ADC_CR, UCB_ADC_ENA | adc_channel); + ucb1400_reg_write(ac97, UCB_ADC_CR, UCB_ADC_ENA | adc_channel | + UCB_ADC_START); + + while (!((val = ucb1400_reg_read(ac97, UCB_ADC_DATA)) + & UCB_ADC_DAT_VALID)) + schedule_timeout_uninterruptible(1); + + return val & UCB_ADC_DAT_MASK; +} +EXPORT_SYMBOL_GPL(ucb1400_adc_read); + static int ucb1400_core_probe(struct device *dev) { int err; diff --git a/drivers/mfd/wm8350-regmap.c b/drivers/mfd/wm8350-regmap.c index 9a4cc954cb7c..7ccc1eab98ab 100644 --- a/drivers/mfd/wm8350-regmap.c +++ b/drivers/mfd/wm8350-regmap.c @@ -3186,7 +3186,7 @@ const struct wm8350_reg_access wm8350_reg_io_map[] = { /* read write volatile */ { 0xFFFF, 0xFFFF, 0xFFFF }, /* R0 - Reset/ID */ { 0x7CFF, 0x0C00, 0x7FFF }, /* R1 - ID */ - { 0x0000, 0x0000, 0x0000 }, /* R2 */ + { 0x007F, 0x0000, 0x0000 }, /* R2 - ROM Mask ID */ { 0xBE3B, 0xBE3B, 0x8000 }, /* R3 - System Control 1 */ { 0xFEF7, 0xFEF7, 0xF800 }, /* R4 - System Control 2 */ { 0x80FF, 0x80FF, 0x8000 }, /* R5 - System Hibernate */ @@ -3411,7 +3411,7 @@ const struct wm8350_reg_access wm8350_reg_io_map[] = { { 0x0000, 0x0000, 0x0000 }, /* R224 */ { 0x8F3F, 0x0000, 0xFFFF }, /* R225 - DCDC/LDO status */ { 0x0000, 0x0000, 0xFFFF }, /* R226 - Charger status */ - { 0x0000, 0x0000, 0xFFFF }, /* R227 */ + { 0x34FE, 0x0000, 0xFFFF }, /* R227 */ { 0x0000, 0x0000, 0x0000 }, /* R228 */ { 0x0000, 0x0000, 0x0000 }, /* R229 */ { 0xFFFF, 0x1FFF, 0xFFFF }, /* R230 - GPIO Pin Status */ diff --git a/drivers/mfd/wm8400-core.c b/drivers/mfd/wm8400-core.c index cf30d06a0104..ecfc8bbe89b9 100644 --- a/drivers/mfd/wm8400-core.c +++ b/drivers/mfd/wm8400-core.c @@ -265,7 +265,7 @@ static int wm8400_init(struct wm8400 *wm8400, mutex_init(&wm8400->io_lock); - wm8400->dev->driver_data = wm8400; + dev_set_drvdata(wm8400->dev, wm8400); /* Check that this is actually a WM8400 */ ret = wm8400->read_dev(wm8400->io_data, WM8400_RESET_ID, 1, ®); @@ -460,7 +460,7 @@ static int __init wm8400_module_init(void) return ret; } -module_init(wm8400_module_init); +subsys_initcall(wm8400_module_init); static void __exit wm8400_module_exit(void) { diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 6d1ac180f6ee..68ab39d7cb35 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -235,5 +235,6 @@ config ISL29003 source "drivers/misc/c2port/Kconfig" source "drivers/misc/eeprom/Kconfig" +source "drivers/misc/cb710/Kconfig" endif # MISC_DEVICES diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 7871f05dcb9b..36f733cd60e6 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -21,3 +21,4 @@ obj-$(CONFIG_HP_ILO) += hpilo.o obj-$(CONFIG_ISL29003) += isl29003.o obj-$(CONFIG_C2PORT) += c2port/ obj-y += eeprom/ +obj-y += cb710/ diff --git a/drivers/misc/c2port/core.c b/drivers/misc/c2port/core.c index 0207dd59090d..b5346b4db91a 100644 --- a/drivers/misc/c2port/core.c +++ b/drivers/misc/c2port/core.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -891,6 +892,7 @@ struct c2port_device *c2port_device_register(char *name, return ERR_PTR(-EINVAL); c2dev = kmalloc(sizeof(struct c2port_device), GFP_KERNEL); + kmemcheck_annotate_bitfield(c2dev, flags); if (unlikely(!c2dev)) return ERR_PTR(-ENOMEM); diff --git a/drivers/misc/cb710/Kconfig b/drivers/misc/cb710/Kconfig new file mode 100644 index 000000000000..22429b8b1068 --- /dev/null +++ b/drivers/misc/cb710/Kconfig @@ -0,0 +1,25 @@ +config CB710_CORE + tristate "ENE CB710/720 Flash memory card reader support" + depends on PCI + help + This option enables support for PCI ENE CB710/720 Flash memory card + reader found in some laptops (ie. some versions of HP Compaq nx9500). + + You will also have to select some flash card format drivers (MMC/SD, + MemoryStick). + + This driver can also be built as a module. If so, the module + will be called cb710. + +config CB710_DEBUG + bool "Enable driver debugging" + depends on CB710_CORE != n + default n + help + This is an option for use by developers; most people should + say N here. This adds a lot of debugging output to dmesg. + +config CB710_DEBUG_ASSUMPTIONS + bool + depends on CB710_CORE != n + default y diff --git a/drivers/misc/cb710/Makefile b/drivers/misc/cb710/Makefile new file mode 100644 index 000000000000..7b80cbf1a609 --- /dev/null +++ b/drivers/misc/cb710/Makefile @@ -0,0 +1,8 @@ +ifeq ($(CONFIG_CB710_DEBUG),y) + EXTRA_CFLAGS += -DDEBUG +endif + +obj-$(CONFIG_CB710_CORE) += cb710.o + +cb710-y := core.o sgbuf2.o +cb710-$(CONFIG_CB710_DEBUG) += debug.o diff --git a/drivers/misc/cb710/core.c b/drivers/misc/cb710/core.c new file mode 100644 index 000000000000..b14eab0f2ba5 --- /dev/null +++ b/drivers/misc/cb710/core.c @@ -0,0 +1,357 @@ +/* + * cb710/core.c + * + * Copyright by MichaÅ‚ MirosÅ‚aw, 2008-2009 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include + +static DEFINE_IDA(cb710_ida); +static DEFINE_SPINLOCK(cb710_ida_lock); + +void cb710_pci_update_config_reg(struct pci_dev *pdev, + int reg, uint32_t mask, uint32_t xor) +{ + u32 rval; + + pci_read_config_dword(pdev, reg, &rval); + rval = (rval & mask) ^ xor; + pci_write_config_dword(pdev, reg, rval); +} +EXPORT_SYMBOL_GPL(cb710_pci_update_config_reg); + +/* Some magic writes based on Windows driver init code */ +static int __devinit cb710_pci_configure(struct pci_dev *pdev) +{ + unsigned int devfn = PCI_DEVFN(PCI_SLOT(pdev->devfn), 0); + struct pci_dev *pdev0 = pci_get_slot(pdev->bus, devfn); + u32 val; + + cb710_pci_update_config_reg(pdev, 0x48, + ~0x000000FF, 0x0000003F); + + pci_read_config_dword(pdev, 0x48, &val); + if (val & 0x80000000) + return 0; + + if (!pdev0) + return -ENODEV; + + if (pdev0->vendor == PCI_VENDOR_ID_ENE + && pdev0->device == PCI_DEVICE_ID_ENE_720) { + cb710_pci_update_config_reg(pdev0, 0x8C, + ~0x00F00000, 0x00100000); + cb710_pci_update_config_reg(pdev0, 0xB0, + ~0x08000000, 0x08000000); + } + + cb710_pci_update_config_reg(pdev0, 0x8C, + ~0x00000F00, 0x00000200); + cb710_pci_update_config_reg(pdev0, 0x90, + ~0x00060000, 0x00040000); + + pci_dev_put(pdev0); + + return 0; +} + +static irqreturn_t cb710_irq_handler(int irq, void *data) +{ + struct cb710_chip *chip = data; + struct cb710_slot *slot = &chip->slot[0]; + irqreturn_t handled = IRQ_NONE; + unsigned nr; + + spin_lock(&chip->irq_lock); /* incl. smp_rmb() */ + + for (nr = chip->slots; nr; ++slot, --nr) { + cb710_irq_handler_t handler_func = slot->irq_handler; + if (handler_func && handler_func(slot)) + handled = IRQ_HANDLED; + } + + spin_unlock(&chip->irq_lock); + + return handled; +} + +static void cb710_release_slot(struct device *dev) +{ +#ifdef CONFIG_CB710_DEBUG_ASSUMPTIONS + struct cb710_slot *slot = cb710_pdev_to_slot(to_platform_device(dev)); + struct cb710_chip *chip = cb710_slot_to_chip(slot); + + /* slot struct can be freed now */ + atomic_dec(&chip->slot_refs_count); +#endif +} + +static int __devinit cb710_register_slot(struct cb710_chip *chip, + unsigned slot_mask, unsigned io_offset, const char *name) +{ + int nr = chip->slots; + struct cb710_slot *slot = &chip->slot[nr]; + int err; + + dev_dbg(cb710_chip_dev(chip), + "register: %s.%d; slot %d; mask %d; IO offset: 0x%02X\n", + name, chip->platform_id, nr, slot_mask, io_offset); + + /* slot->irq_handler == NULL here; this needs to be + * seen before platform_device_register() */ + ++chip->slots; + smp_wmb(); + + slot->iobase = chip->iobase + io_offset; + slot->pdev.name = name; + slot->pdev.id = chip->platform_id; + slot->pdev.dev.parent = &chip->pdev->dev; + slot->pdev.dev.release = cb710_release_slot; + + err = platform_device_register(&slot->pdev); + +#ifdef CONFIG_CB710_DEBUG_ASSUMPTIONS + atomic_inc(&chip->slot_refs_count); +#endif + + if (err) { + /* device_initialize() called from platform_device_register() + * wants this on error path */ + platform_device_put(&slot->pdev); + + /* slot->irq_handler == NULL here anyway, so no lock needed */ + --chip->slots; + return err; + } + + chip->slot_mask |= slot_mask; + + return 0; +} + +static void cb710_unregister_slot(struct cb710_chip *chip, + unsigned slot_mask) +{ + int nr = chip->slots - 1; + + if (!(chip->slot_mask & slot_mask)) + return; + + platform_device_unregister(&chip->slot[nr].pdev); + + /* complementary to spin_unlock() in cb710_set_irq_handler() */ + smp_rmb(); + BUG_ON(chip->slot[nr].irq_handler != NULL); + + /* slot->irq_handler == NULL here, so no lock needed */ + --chip->slots; + chip->slot_mask &= ~slot_mask; +} + +void cb710_set_irq_handler(struct cb710_slot *slot, + cb710_irq_handler_t handler) +{ + struct cb710_chip *chip = cb710_slot_to_chip(slot); + unsigned long flags; + + spin_lock_irqsave(&chip->irq_lock, flags); + slot->irq_handler = handler; + spin_unlock_irqrestore(&chip->irq_lock, flags); +} +EXPORT_SYMBOL_GPL(cb710_set_irq_handler); + +#ifdef CONFIG_PM + +static int cb710_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct cb710_chip *chip = pci_get_drvdata(pdev); + + free_irq(pdev->irq, chip); + pci_save_state(pdev); + pci_disable_device(pdev); + if (state.event & PM_EVENT_SLEEP) + pci_set_power_state(pdev, PCI_D3cold); + return 0; +} + +static int cb710_resume(struct pci_dev *pdev) +{ + struct cb710_chip *chip = pci_get_drvdata(pdev); + int err; + + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + err = pcim_enable_device(pdev); + if (err) + return err; + + return devm_request_irq(&pdev->dev, pdev->irq, + cb710_irq_handler, IRQF_SHARED, KBUILD_MODNAME, chip); +} + +#endif /* CONFIG_PM */ + +static int __devinit cb710_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct cb710_chip *chip; + unsigned long flags; + u32 val; + int err; + int n = 0; + + err = cb710_pci_configure(pdev); + if (err) + return err; + + /* this is actually magic... */ + pci_read_config_dword(pdev, 0x48, &val); + if (!(val & 0x80000000)) { + pci_write_config_dword(pdev, 0x48, val|0x71000000); + pci_read_config_dword(pdev, 0x48, &val); + } + + dev_dbg(&pdev->dev, "PCI config[0x48] = 0x%08X\n", val); + if (!(val & 0x70000000)) + return -ENODEV; + val = (val >> 28) & 7; + if (val & CB710_SLOT_MMC) + ++n; + if (val & CB710_SLOT_MS) + ++n; + if (val & CB710_SLOT_SM) + ++n; + + chip = devm_kzalloc(&pdev->dev, + sizeof(*chip) + n * sizeof(*chip->slot), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + err = pcim_enable_device(pdev); + if (err) + return err; + + err = pcim_iomap_regions(pdev, 0x0001, KBUILD_MODNAME); + if (err) + return err; + + chip->pdev = pdev; + chip->iobase = pcim_iomap_table(pdev)[0]; + + pci_set_drvdata(pdev, chip); + + err = devm_request_irq(&pdev->dev, pdev->irq, + cb710_irq_handler, IRQF_SHARED, KBUILD_MODNAME, chip); + if (err) + return err; + + do { + if (!ida_pre_get(&cb710_ida, GFP_KERNEL)) + return -ENOMEM; + + spin_lock_irqsave(&cb710_ida_lock, flags); + err = ida_get_new(&cb710_ida, &chip->platform_id); + spin_unlock_irqrestore(&cb710_ida_lock, flags); + + if (err && err != -EAGAIN) + return err; + } while (err); + + + dev_info(&pdev->dev, "id %d, IO 0x%p, IRQ %d\n", + chip->platform_id, chip->iobase, pdev->irq); + + if (val & CB710_SLOT_MMC) { /* MMC/SD slot */ + err = cb710_register_slot(chip, + CB710_SLOT_MMC, 0x00, "cb710-mmc"); + if (err) + return err; + } + + if (val & CB710_SLOT_MS) { /* MemoryStick slot */ + err = cb710_register_slot(chip, + CB710_SLOT_MS, 0x40, "cb710-ms"); + if (err) + goto unreg_mmc; + } + + if (val & CB710_SLOT_SM) { /* SmartMedia slot */ + err = cb710_register_slot(chip, + CB710_SLOT_SM, 0x60, "cb710-sm"); + if (err) + goto unreg_ms; + } + + return 0; +unreg_ms: + cb710_unregister_slot(chip, CB710_SLOT_MS); +unreg_mmc: + cb710_unregister_slot(chip, CB710_SLOT_MMC); + +#ifdef CONFIG_CB710_DEBUG_ASSUMPTIONS + BUG_ON(atomic_read(&chip->slot_refs_count) != 0); +#endif + return err; +} + +static void __devexit cb710_remove_one(struct pci_dev *pdev) +{ + struct cb710_chip *chip = pci_get_drvdata(pdev); + unsigned long flags; + + cb710_unregister_slot(chip, CB710_SLOT_SM); + cb710_unregister_slot(chip, CB710_SLOT_MS); + cb710_unregister_slot(chip, CB710_SLOT_MMC); +#ifdef CONFIG_CB710_DEBUG_ASSUMPTIONS + BUG_ON(atomic_read(&chip->slot_refs_count) != 0); +#endif + + spin_lock_irqsave(&cb710_ida_lock, flags); + ida_remove(&cb710_ida, chip->platform_id); + spin_unlock_irqrestore(&cb710_ida_lock, flags); +} + +static const struct pci_device_id cb710_pci_tbl[] = { + { PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_CB710_FLASH, + PCI_ANY_ID, PCI_ANY_ID, }, + { 0, } +}; + +static struct pci_driver cb710_driver = { + .name = KBUILD_MODNAME, + .id_table = cb710_pci_tbl, + .probe = cb710_probe, + .remove = __devexit_p(cb710_remove_one), +#ifdef CONFIG_PM + .suspend = cb710_suspend, + .resume = cb710_resume, +#endif +}; + +static int __init cb710_init_module(void) +{ + return pci_register_driver(&cb710_driver); +} + +static void __exit cb710_cleanup_module(void) +{ + pci_unregister_driver(&cb710_driver); + ida_destroy(&cb710_ida); +} + +module_init(cb710_init_module); +module_exit(cb710_cleanup_module); + +MODULE_AUTHOR("MichaÅ‚ MirosÅ‚aw "); +MODULE_DESCRIPTION("ENE CB710 memory card reader driver"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, cb710_pci_tbl); diff --git a/drivers/misc/cb710/debug.c b/drivers/misc/cb710/debug.c new file mode 100644 index 000000000000..02358d086e03 --- /dev/null +++ b/drivers/misc/cb710/debug.c @@ -0,0 +1,119 @@ +/* + * cb710/debug.c + * + * Copyright by MichaÅ‚ MirosÅ‚aw, 2008-2009 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include + +#define CB710_REG_COUNT 0x80 + +static const u16 allow[CB710_REG_COUNT/16] = { + 0xFFF0, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFF0, 0xFFFF, 0xFFFF, 0xFFFF, +}; +static const char *const prefix[ARRAY_SIZE(allow)] = { + "MMC", "MMC", "MMC", "MMC", + "MS?", "MS?", "SM?", "SM?" +}; + +static inline int allow_reg_read(unsigned block, unsigned offset, unsigned bits) +{ + unsigned mask = (1 << bits/8) - 1; + offset *= bits/8; + return ((allow[block] >> offset) & mask) == mask; +} + +#define CB710_READ_REGS_TEMPLATE(t) \ +static void cb710_read_regs_##t(void __iomem *iobase, \ + u##t *reg, unsigned select) \ +{ \ + unsigned i, j; \ + \ + for (i = 0; i < ARRAY_SIZE(allow); ++i, reg += 16/(t/8)) { \ + if (!(select & (1 << i))) \ + continue; \ + \ + for (j = 0; j < 0x10/(t/8); ++j) { \ + if (!allow_reg_read(i, j, t)) \ + continue; \ + reg[j] = ioread##t(iobase \ + + (i << 4) + (j * (t/8))); \ + } \ + } \ +} + +static const char cb710_regf_8[] = "%02X"; +static const char cb710_regf_16[] = "%04X"; +static const char cb710_regf_32[] = "%08X"; +static const char cb710_xes[] = "xxxxxxxx"; + +#define CB710_DUMP_REGS_TEMPLATE(t) \ +static void cb710_dump_regs_##t(struct device *dev, \ + const u##t *reg, unsigned select) \ +{ \ + const char *const xp = &cb710_xes[8 - t/4]; \ + const char *const format = cb710_regf_##t; \ + \ + char msg[100], *p; \ + unsigned i, j; \ + \ + for (i = 0; i < ARRAY_SIZE(allow); ++i, reg += 16/(t/8)) { \ + if (!(select & (1 << i))) \ + continue; \ + p = msg; \ + for (j = 0; j < 0x10/(t/8); ++j) { \ + *p++ = ' '; \ + if (j == 8/(t/8)) \ + *p++ = ' '; \ + if (allow_reg_read(i, j, t)) \ + p += sprintf(p, format, reg[j]); \ + else \ + p += sprintf(p, "%s", xp); \ + } \ + dev_dbg(dev, "%s 0x%02X %s\n", prefix[i], i << 4, msg); \ + } \ +} + +#define CB710_READ_AND_DUMP_REGS_TEMPLATE(t) \ +static void cb710_read_and_dump_regs_##t(struct cb710_chip *chip, \ + unsigned select) \ +{ \ + u##t regs[CB710_REG_COUNT/sizeof(u##t)]; \ + \ + memset(®s, 0, sizeof(regs)); \ + cb710_read_regs_##t(chip->iobase, regs, select); \ + cb710_dump_regs_##t(cb710_chip_dev(chip), regs, select); \ +} + +#define CB710_REG_ACCESS_TEMPLATES(t) \ + CB710_READ_REGS_TEMPLATE(t) \ + CB710_DUMP_REGS_TEMPLATE(t) \ + CB710_READ_AND_DUMP_REGS_TEMPLATE(t) + +CB710_REG_ACCESS_TEMPLATES(8) +CB710_REG_ACCESS_TEMPLATES(16) +CB710_REG_ACCESS_TEMPLATES(32) + +void cb710_dump_regs(struct cb710_chip *chip, unsigned select) +{ + if (!(select & CB710_DUMP_REGS_MASK)) + select = CB710_DUMP_REGS_ALL; + if (!(select & CB710_DUMP_ACCESS_MASK)) + select |= CB710_DUMP_ACCESS_8; + + if (select & CB710_DUMP_ACCESS_32) + cb710_read_and_dump_regs_32(chip, select); + if (select & CB710_DUMP_ACCESS_16) + cb710_read_and_dump_regs_16(chip, select); + if (select & CB710_DUMP_ACCESS_8) + cb710_read_and_dump_regs_8(chip, select); +} +EXPORT_SYMBOL_GPL(cb710_dump_regs); + diff --git a/drivers/misc/cb710/sgbuf2.c b/drivers/misc/cb710/sgbuf2.c new file mode 100644 index 000000000000..d38a7acdb6ec --- /dev/null +++ b/drivers/misc/cb710/sgbuf2.c @@ -0,0 +1,150 @@ +/* + * cb710/sgbuf2.c + * + * Copyright by MichaÅ‚ MirosÅ‚aw, 2008-2009 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include + +static bool sg_dwiter_next(struct sg_mapping_iter *miter) +{ + if (sg_miter_next(miter)) { + miter->consumed = 0; + return true; + } else + return false; +} + +static bool sg_dwiter_is_at_end(struct sg_mapping_iter *miter) +{ + return miter->length == miter->consumed && !sg_dwiter_next(miter); +} + +static uint32_t sg_dwiter_read_buffer(struct sg_mapping_iter *miter) +{ + size_t len, left = 4; + uint32_t data; + void *addr = &data; + + do { + len = min(miter->length - miter->consumed, left); + memcpy(addr, miter->addr + miter->consumed, len); + miter->consumed += len; + left -= len; + if (!left) + return data; + addr += len; + } while (sg_dwiter_next(miter)); + + memset(addr, 0, left); + return data; +} + +static inline bool needs_unaligned_copy(const void *ptr) +{ +#ifdef HAVE_EFFICIENT_UNALIGNED_ACCESS + return false; +#else + return ((ptr - NULL) & 3) != 0; +#endif +} + +static bool sg_dwiter_get_next_block(struct sg_mapping_iter *miter, uint32_t **ptr) +{ + size_t len; + + if (sg_dwiter_is_at_end(miter)) + return true; + + len = miter->length - miter->consumed; + + if (likely(len >= 4 && !needs_unaligned_copy( + miter->addr + miter->consumed))) { + *ptr = miter->addr + miter->consumed; + miter->consumed += 4; + return true; + } + + return false; +} + +/** + * cb710_sg_dwiter_read_next_block() - get next 32-bit word from sg buffer + * @miter: sg mapping iterator used for reading + * + * Description: + * Returns 32-bit word starting at byte pointed to by @miter@ + * handling any alignment issues. Bytes past the buffer's end + * are not accessed (read) but are returned as zeroes. @miter@ + * is advanced by 4 bytes or to the end of buffer whichever is + * closer. + * + * Context: + * Same requirements as in sg_miter_next(). + * + * Returns: + * 32-bit word just read. + */ +uint32_t cb710_sg_dwiter_read_next_block(struct sg_mapping_iter *miter) +{ + uint32_t *ptr = NULL; + + if (likely(sg_dwiter_get_next_block(miter, &ptr))) + return ptr ? *ptr : 0; + + return sg_dwiter_read_buffer(miter); +} +EXPORT_SYMBOL_GPL(cb710_sg_dwiter_read_next_block); + +static void sg_dwiter_write_slow(struct sg_mapping_iter *miter, uint32_t data) +{ + size_t len, left = 4; + void *addr = &data; + + do { + len = min(miter->length - miter->consumed, left); + memcpy(miter->addr, addr, len); + miter->consumed += len; + left -= len; + if (!left) + return; + addr += len; + flush_kernel_dcache_page(miter->page); + } while (sg_dwiter_next(miter)); +} + +/** + * cb710_sg_dwiter_write_next_block() - write next 32-bit word to sg buffer + * @miter: sg mapping iterator used for writing + * + * Description: + * Writes 32-bit word starting at byte pointed to by @miter@ + * handling any alignment issues. Bytes which would be written + * past the buffer's end are silently discarded. @miter@ is + * advanced by 4 bytes or to the end of buffer whichever is closer. + * + * Context: + * Same requirements as in sg_miter_next(). + */ +void cb710_sg_dwiter_write_next_block(struct sg_mapping_iter *miter, uint32_t data) +{ + uint32_t *ptr = NULL; + + if (likely(sg_dwiter_get_next_block(miter, &ptr))) { + if (ptr) + *ptr = data; + else + return; + } else + sg_dwiter_write_slow(miter, data); + + if (miter->length == miter->consumed) + flush_kernel_dcache_page(miter->page); +} +EXPORT_SYMBOL_GPL(cb710_sg_dwiter_write_next_block); + diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig index 89fec052f3b4..9118613af321 100644 --- a/drivers/misc/eeprom/Kconfig +++ b/drivers/misc/eeprom/Kconfig @@ -48,6 +48,20 @@ config EEPROM_LEGACY This driver can also be built as a module. If so, the module will be called eeprom. +config EEPROM_MAX6875 + tristate "Maxim MAX6874/5 power supply supervisor" + depends on I2C && EXPERIMENTAL + help + If you say yes here you get read-only support for the user EEPROM of + the Maxim MAX6874/5 EEPROM-programmable, quad power-supply + sequencer/supervisor. + + All other features of this chip should be accessed via i2c-dev. + + This driver can also be built as a module. If so, the module + will be called max6875. + + config EEPROM_93CX6 tristate "EEPROM 93CX6 support" help diff --git a/drivers/misc/eeprom/Makefile b/drivers/misc/eeprom/Makefile index 539dd8f88128..df3d68ffa9d1 100644 --- a/drivers/misc/eeprom/Makefile +++ b/drivers/misc/eeprom/Makefile @@ -1,4 +1,5 @@ obj-$(CONFIG_EEPROM_AT24) += at24.o obj-$(CONFIG_EEPROM_AT25) += at25.o obj-$(CONFIG_EEPROM_LEGACY) += eeprom.o +obj-$(CONFIG_EEPROM_MAX6875) += max6875.o obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o diff --git a/drivers/i2c/chips/max6875.c b/drivers/misc/eeprom/max6875.c similarity index 99% rename from drivers/i2c/chips/max6875.c rename to drivers/misc/eeprom/max6875.c index 033d9d81ec8a..3c0c58eed347 100644 --- a/drivers/i2c/chips/max6875.c +++ b/drivers/misc/eeprom/max6875.c @@ -3,7 +3,7 @@ Copyright (C) 2005 Ben Gardner - Based on i2c/chips/eeprom.c + Based on eeprom.c The MAX6875 has a bank of registers and two banks of EEPROM. Address ranges are defined as follows: diff --git a/drivers/misc/sgi-gru/Makefile b/drivers/misc/sgi-gru/Makefile index bcd8136d2f98..7c4c306dfa8a 100644 --- a/drivers/misc/sgi-gru/Makefile +++ b/drivers/misc/sgi-gru/Makefile @@ -3,5 +3,5 @@ ifdef CONFIG_SGI_GRU_DEBUG endif obj-$(CONFIG_SGI_GRU) := gru.o -gru-y := grufile.o grumain.o grufault.o grutlbpurge.o gruprocfs.o grukservices.o gruhandles.o +gru-y := grufile.o grumain.o grufault.o grutlbpurge.o gruprocfs.o grukservices.o gruhandles.o grukdump.o diff --git a/drivers/misc/sgi-gru/gru_instructions.h b/drivers/misc/sgi-gru/gru_instructions.h index 3fde33c1e8f3..3c9c06618e6a 100644 --- a/drivers/misc/sgi-gru/gru_instructions.h +++ b/drivers/misc/sgi-gru/gru_instructions.h @@ -81,6 +81,8 @@ struct control_block_extended_exc_detail { int exopc; long exceptdet0; int exceptdet1; + int cbrstate; + int cbrexecstatus; }; /* @@ -107,7 +109,8 @@ struct gru_instruction_bits { unsigned char reserved2: 2; unsigned char istatus: 2; unsigned char isubstatus:4; - unsigned char reserved3: 2; + unsigned char reserved3: 1; + unsigned char tlb_fault_color: 1; /* DW 1 */ unsigned long idef4; /* 42 bits: TRi1, BufSize */ /* DW 2-6 */ @@ -250,17 +253,37 @@ struct gru_instruction { #define CBE_CAUSE_HA_RESPONSE_FATAL (1 << 13) #define CBE_CAUSE_HA_RESPONSE_NON_FATAL (1 << 14) #define CBE_CAUSE_ADDRESS_SPACE_DECODE_ERROR (1 << 15) -#define CBE_CAUSE_RESPONSE_DATA_ERROR (1 << 16) -#define CBE_CAUSE_PROTOCOL_STATE_DATA_ERROR (1 << 17) +#define CBE_CAUSE_PROTOCOL_STATE_DATA_ERROR (1 << 16) +#define CBE_CAUSE_RA_RESPONSE_DATA_ERROR (1 << 17) +#define CBE_CAUSE_HA_RESPONSE_DATA_ERROR (1 << 18) + +/* CBE cbrexecstatus bits */ +#define CBR_EXS_ABORT_OCC_BIT 0 +#define CBR_EXS_INT_OCC_BIT 1 +#define CBR_EXS_PENDING_BIT 2 +#define CBR_EXS_QUEUED_BIT 3 +#define CBR_EXS_TLB_INVAL_BIT 4 +#define CBR_EXS_EXCEPTION_BIT 5 + +#define CBR_EXS_ABORT_OCC (1 << CBR_EXS_ABORT_OCC_BIT) +#define CBR_EXS_INT_OCC (1 << CBR_EXS_INT_OCC_BIT) +#define CBR_EXS_PENDING (1 << CBR_EXS_PENDING_BIT) +#define CBR_EXS_QUEUED (1 << CBR_EXS_QUEUED_BIT) +#define CBR_TLB_INVAL (1 << CBR_EXS_TLB_INVAL_BIT) +#define CBR_EXS_EXCEPTION (1 << CBR_EXS_EXCEPTION_BIT) /* * Exceptions are retried for the following cases. If any OTHER bits are set * in ecause, the exception is not retryable. */ -#define EXCEPTION_RETRY_BITS (CBE_CAUSE_RESPONSE_DATA_ERROR | \ - CBE_CAUSE_RA_REQUEST_TIMEOUT | \ +#define EXCEPTION_RETRY_BITS (CBE_CAUSE_EXECUTION_HW_ERROR | \ CBE_CAUSE_TLBHW_ERROR | \ - CBE_CAUSE_HA_REQUEST_TIMEOUT) + CBE_CAUSE_RA_REQUEST_TIMEOUT | \ + CBE_CAUSE_RA_RESPONSE_NON_FATAL | \ + CBE_CAUSE_HA_RESPONSE_NON_FATAL | \ + CBE_CAUSE_RA_RESPONSE_DATA_ERROR | \ + CBE_CAUSE_HA_RESPONSE_DATA_ERROR \ + ) /* Message queue head structure */ union gru_mesqhead { @@ -600,9 +623,11 @@ static inline int gru_get_cb_substatus(void *cb) return cbs->isubstatus; } -/* Check the status of a CB. If the CB is in UPM mode, call the - * OS to handle the UPM status. - * Returns the CB status field value (0 for normal completion) +/* + * User interface to check an instruction status. UPM and exceptions + * are handled automatically. However, this function does NOT wait + * for an active instruction to complete. + * */ static inline int gru_check_status(void *cb) { @@ -610,34 +635,31 @@ static inline int gru_check_status(void *cb) int ret; ret = cbs->istatus; - if (ret == CBS_CALL_OS) + if (ret != CBS_ACTIVE) ret = gru_check_status_proc(cb); return ret; } -/* Wait for CB to complete. - * Returns the CB status field value (0 for normal completion) +/* + * User interface (via inline function) to wait for an instruction + * to complete. Completion status (IDLE or EXCEPTION is returned + * to the user. Exception due to hardware errors are automatically + * retried before returning an exception. + * */ static inline int gru_wait(void *cb) { - struct gru_control_block_status *cbs = (void *)cb; - int ret = cbs->istatus; - - if (ret != CBS_IDLE) - ret = gru_wait_proc(cb); - return ret; + return gru_wait_proc(cb); } -/* Wait for CB to complete. Aborts program if error. (Note: error does NOT +/* + * Wait for CB to complete. Aborts program if error. (Note: error does NOT * mean TLB mis - only fatal errors such as memory parity error or user * bugs will cause termination. */ static inline void gru_wait_abort(void *cb) { - struct gru_control_block_status *cbs = (void *)cb; - - if (cbs->istatus != CBS_IDLE) - gru_wait_abort_proc(cb); + gru_wait_abort_proc(cb); } diff --git a/drivers/misc/sgi-gru/grufault.c b/drivers/misc/sgi-gru/grufault.c index ab118558552e..679e01778286 100644 --- a/drivers/misc/sgi-gru/grufault.c +++ b/drivers/misc/sgi-gru/grufault.c @@ -166,7 +166,8 @@ static inline struct gru_state *irq_to_gru(int irq) * the GRU, atomic operations must be used to clear bits. */ static void get_clear_fault_map(struct gru_state *gru, - struct gru_tlb_fault_map *map) + struct gru_tlb_fault_map *imap, + struct gru_tlb_fault_map *dmap) { unsigned long i, k; struct gru_tlb_fault_map *tfm; @@ -177,7 +178,11 @@ static void get_clear_fault_map(struct gru_state *gru, k = tfm->fault_bits[i]; if (k) k = xchg(&tfm->fault_bits[i], 0UL); - map->fault_bits[i] = k; + imap->fault_bits[i] = k; + k = tfm->done_bits[i]; + if (k) + k = xchg(&tfm->done_bits[i], 0UL); + dmap->fault_bits[i] = k; } /* @@ -334,6 +339,12 @@ static int gru_try_dropin(struct gru_thread_state *gts, * Might be a hardware race OR a stupid user. Ignore FMM because FMM * is a transient state. */ + if (tfh->status != TFHSTATUS_EXCEPTION) { + gru_flush_cache(tfh); + if (tfh->status != TFHSTATUS_EXCEPTION) + goto failnoexception; + STAT(tfh_stale_on_fault); + } if (tfh->state == TFHSTATE_IDLE) goto failidle; if (tfh->state == TFHSTATE_MISS_FMM && cb) @@ -401,8 +412,17 @@ failfmm: gru_dbg(grudev, "FAILED fmm tfh: 0x%p, state %d\n", tfh, tfh->state); return 0; +failnoexception: + /* TFH status did not show exception pending */ + gru_flush_cache(tfh); + if (cb) + gru_flush_cache(cb); + STAT(tlb_dropin_fail_no_exception); + gru_dbg(grudev, "FAILED non-exception tfh: 0x%p, status %d, state %d\n", tfh, tfh->status, tfh->state); + return 0; + failidle: - /* TFH was idle - no miss pending */ + /* TFH state was idle - no miss pending */ gru_flush_cache(tfh); if (cb) gru_flush_cache(cb); @@ -438,7 +458,7 @@ failactive: irqreturn_t gru_intr(int irq, void *dev_id) { struct gru_state *gru; - struct gru_tlb_fault_map map; + struct gru_tlb_fault_map imap, dmap; struct gru_thread_state *gts; struct gru_tlb_fault_handle *tfh = NULL; int cbrnum, ctxnum; @@ -451,11 +471,15 @@ irqreturn_t gru_intr(int irq, void *dev_id) raw_smp_processor_id(), irq); return IRQ_NONE; } - get_clear_fault_map(gru, &map); - gru_dbg(grudev, "irq %d, gru %x, map 0x%lx\n", irq, gru->gs_gid, - map.fault_bits[0]); + get_clear_fault_map(gru, &imap, &dmap); - for_each_cbr_in_tfm(cbrnum, map.fault_bits) { + for_each_cbr_in_tfm(cbrnum, dmap.fault_bits) { + complete(gru->gs_blade->bs_async_wq); + gru_dbg(grudev, "gid %d, cbr_done %d, done %d\n", + gru->gs_gid, cbrnum, gru->gs_blade->bs_async_wq->done); + } + + for_each_cbr_in_tfm(cbrnum, imap.fault_bits) { tfh = get_tfh_by_index(gru, cbrnum); prefetchw(tfh); /* Helps on hdw, required for emulator */ @@ -472,7 +496,9 @@ irqreturn_t gru_intr(int irq, void *dev_id) * This is running in interrupt context. Trylock the mmap_sem. * If it fails, retry the fault in user context. */ - if (down_read_trylock(>s->ts_mm->mmap_sem)) { + if (!gts->ts_force_cch_reload && + down_read_trylock(>s->ts_mm->mmap_sem)) { + gts->ustats.fmm_tlbdropin++; gru_try_dropin(gts, tfh, NULL); up_read(>s->ts_mm->mmap_sem); } else { @@ -491,6 +517,7 @@ static int gru_user_dropin(struct gru_thread_state *gts, struct gru_mm_struct *gms = gts->ts_gms; int ret; + gts->ustats.upm_tlbdropin++; while (1) { wait_event(gms->ms_wait_queue, atomic_read(&gms->ms_range_active) == 0); @@ -546,8 +573,8 @@ int gru_handle_user_call_os(unsigned long cb) * CCH may contain stale data if ts_force_cch_reload is set. */ if (gts->ts_gru && gts->ts_force_cch_reload) { - gru_update_cch(gts, 0); gts->ts_force_cch_reload = 0; + gru_update_cch(gts, 0); } ret = -EAGAIN; @@ -589,20 +616,26 @@ int gru_get_exception_detail(unsigned long arg) } else if (gts->ts_gru) { cbrnum = thread_cbr_number(gts, ucbnum); cbe = get_cbe_by_index(gts->ts_gru, cbrnum); - prefetchw(cbe);/* Harmless on hardware, required for emulator */ + gru_flush_cache(cbe); /* CBE not coherent */ excdet.opc = cbe->opccpy; excdet.exopc = cbe->exopccpy; excdet.ecause = cbe->ecause; excdet.exceptdet0 = cbe->idef1upd; excdet.exceptdet1 = cbe->idef3upd; + excdet.cbrstate = cbe->cbrstate; + excdet.cbrexecstatus = cbe->cbrexecstatus; + gru_flush_cache(cbe); ret = 0; } else { ret = -EAGAIN; } gru_unlock_gts(gts); - gru_dbg(grudev, "address 0x%lx, ecause 0x%x\n", excdet.cb, - excdet.ecause); + gru_dbg(grudev, + "cb 0x%lx, op %d, exopc %d, cbrstate %d, cbrexecstatus 0x%x, ecause 0x%x, " + "exdet0 0x%lx, exdet1 0x%x\n", + excdet.cb, excdet.opc, excdet.exopc, excdet.cbrstate, excdet.cbrexecstatus, + excdet.ecause, excdet.exceptdet0, excdet.exceptdet1); if (!ret && copy_to_user((void __user *)arg, &excdet, sizeof(excdet))) ret = -EFAULT; return ret; @@ -627,7 +660,7 @@ static int gru_unload_all_contexts(void) if (gts && mutex_trylock(>s->ts_ctxlock)) { spin_unlock(&gru->gs_lock); gru_unload_context(gts, 1); - gru_unlock_gts(gts); + mutex_unlock(>s->ts_ctxlock); spin_lock(&gru->gs_lock); } } @@ -669,6 +702,7 @@ int gru_user_flush_tlb(unsigned long arg) { struct gru_thread_state *gts; struct gru_flush_tlb_req req; + struct gru_mm_struct *gms; STAT(user_flush_tlb); if (copy_from_user(&req, (void __user *)arg, sizeof(req))) @@ -681,8 +715,34 @@ int gru_user_flush_tlb(unsigned long arg) if (!gts) return -EINVAL; - gru_flush_tlb_range(gts->ts_gms, req.vaddr, req.len); + gms = gts->ts_gms; gru_unlock_gts(gts); + gru_flush_tlb_range(gms, req.vaddr, req.len); + + return 0; +} + +/* + * Fetch GSEG statisticss + */ +long gru_get_gseg_statistics(unsigned long arg) +{ + struct gru_thread_state *gts; + struct gru_get_gseg_statistics_req req; + + if (copy_from_user(&req, (void __user *)arg, sizeof(req))) + return -EFAULT; + + gts = gru_find_lock_gts(req.gseg); + if (gts) { + memcpy(&req.stats, >s->ustats, sizeof(gts->ustats)); + gru_unlock_gts(gts); + } else { + memset(&req.stats, 0, sizeof(gts->ustats)); + } + + if (copy_to_user((void __user *)arg, &req, sizeof(req))) + return -EFAULT; return 0; } @@ -691,18 +751,34 @@ int gru_user_flush_tlb(unsigned long arg) * Register the current task as the user of the GSEG slice. * Needed for TLB fault interrupt targeting. */ -int gru_set_task_slice(long address) +int gru_set_context_option(unsigned long arg) { struct gru_thread_state *gts; + struct gru_set_context_option_req req; + int ret = 0; - STAT(set_task_slice); - gru_dbg(grudev, "address 0x%lx\n", address); - gts = gru_alloc_locked_gts(address); + STAT(set_context_option); + if (copy_from_user(&req, (void __user *)arg, sizeof(req))) + return -EFAULT; + gru_dbg(grudev, "op %d, gseg 0x%lx, value1 0x%lx\n", req.op, req.gseg, req.val1); + + gts = gru_alloc_locked_gts(req.gseg); if (!gts) return -EINVAL; - gts->ts_tgid_owner = current->tgid; + switch (req.op) { + case sco_gseg_owner: + /* Register the current task as the GSEG owner */ + gts->ts_tgid_owner = current->tgid; + break; + case sco_cch_req_slice: + /* Set the CCH slice option */ + gts->ts_cch_req_slice = req.val1 & 3; + break; + default: + ret = -EINVAL; + } gru_unlock_gts(gts); - return 0; + return ret; } diff --git a/drivers/misc/sgi-gru/grufile.c b/drivers/misc/sgi-gru/grufile.c index bbefe77c67a9..fa2d93a9fb8d 100644 --- a/drivers/misc/sgi-gru/grufile.c +++ b/drivers/misc/sgi-gru/grufile.c @@ -46,6 +46,7 @@ struct gru_blade_state *gru_base[GRU_MAX_BLADES] __read_mostly; unsigned long gru_start_paddr __read_mostly; +void *gru_start_vaddr __read_mostly; unsigned long gru_end_paddr __read_mostly; unsigned int gru_max_gids __read_mostly; struct gru_stats_s gru_stats; @@ -135,11 +136,9 @@ static int gru_create_new_context(unsigned long arg) if (copy_from_user(&req, (void __user *)arg, sizeof(req))) return -EFAULT; - if (req.data_segment_bytes == 0 || - req.data_segment_bytes > max_user_dsr_bytes) + if (req.data_segment_bytes > max_user_dsr_bytes) return -EINVAL; - if (!req.control_blocks || !req.maximum_thread_count || - req.control_blocks > max_user_cbrs) + if (req.control_blocks > max_user_cbrs || !req.maximum_thread_count) return -EINVAL; if (!(req.options & GRU_OPT_MISS_MASK)) @@ -183,41 +182,6 @@ static long gru_get_config_info(unsigned long arg) return 0; } -/* - * Get GRU chiplet status - */ -static long gru_get_chiplet_status(unsigned long arg) -{ - struct gru_state *gru; - struct gru_chiplet_info info; - - if (copy_from_user(&info, (void __user *)arg, sizeof(info))) - return -EFAULT; - - if (info.node == -1) - info.node = numa_node_id(); - if (info.node >= num_possible_nodes() || - info.chiplet >= GRU_CHIPLETS_PER_HUB || - info.node < 0 || info.chiplet < 0) - return -EINVAL; - - info.blade = uv_node_to_blade_id(info.node); - gru = get_gru(info.blade, info.chiplet); - - info.total_dsr_bytes = GRU_NUM_DSR_BYTES; - info.total_cbr = GRU_NUM_CB; - info.total_user_dsr_bytes = GRU_NUM_DSR_BYTES - - gru->gs_reserved_dsr_bytes; - info.total_user_cbr = GRU_NUM_CB - gru->gs_reserved_cbrs; - info.free_user_dsr_bytes = hweight64(gru->gs_dsr_map) * - GRU_DSR_AU_BYTES; - info.free_user_cbr = hweight64(gru->gs_cbr_map) * GRU_CBR_AU_SIZE; - - if (copy_to_user((void __user *)arg, &info, sizeof(info))) - return -EFAULT; - return 0; -} - /* * gru_file_unlocked_ioctl * @@ -234,8 +198,8 @@ static long gru_file_unlocked_ioctl(struct file *file, unsigned int req, case GRU_CREATE_CONTEXT: err = gru_create_new_context(arg); break; - case GRU_SET_TASK_SLICE: - err = gru_set_task_slice(arg); + case GRU_SET_CONTEXT_OPTION: + err = gru_set_context_option(arg); break; case GRU_USER_GET_EXCEPTION_DETAIL: err = gru_get_exception_detail(arg); @@ -243,18 +207,24 @@ static long gru_file_unlocked_ioctl(struct file *file, unsigned int req, case GRU_USER_UNLOAD_CONTEXT: err = gru_user_unload_context(arg); break; - case GRU_GET_CHIPLET_STATUS: - err = gru_get_chiplet_status(arg); - break; case GRU_USER_FLUSH_TLB: err = gru_user_flush_tlb(arg); break; case GRU_USER_CALL_OS: err = gru_handle_user_call_os(arg); break; + case GRU_GET_GSEG_STATISTICS: + err = gru_get_gseg_statistics(arg); + break; + case GRU_KTEST: + err = gru_ktest(arg); + break; case GRU_GET_CONFIG_INFO: err = gru_get_config_info(arg); break; + case GRU_DUMP_CHIPLET_STATE: + err = gru_dump_chiplet_request(arg); + break; } return err; } @@ -282,7 +252,6 @@ static void gru_init_chiplet(struct gru_state *gru, unsigned long paddr, gru_dbg(grudev, "bid %d, nid %d, gid %d, vaddr %p (0x%lx)\n", bid, nid, gru->gs_gid, gru->gs_gru_base_vaddr, gru->gs_gru_base_paddr); - gru_kservices_init(gru); } static int gru_init_tables(unsigned long gru_base_paddr, void *gru_base_vaddr) @@ -302,13 +271,14 @@ static int gru_init_tables(unsigned long gru_base_paddr, void *gru_base_vaddr) pnode = uv_node_to_pnode(nid); if (bid < 0 || gru_base[bid]) continue; - page = alloc_pages_node(nid, GFP_KERNEL, order); + page = alloc_pages_exact_node(nid, GFP_KERNEL, order); if (!page) goto fail; gru_base[bid] = page_address(page); memset(gru_base[bid], 0, sizeof(struct gru_blade_state)); gru_base[bid]->bs_lru_gru = &gru_base[bid]->bs_grus[0]; spin_lock_init(&gru_base[bid]->bs_lock); + init_rwsem(&gru_base[bid]->bs_kgts_sema); dsrbytes = 0; cbrs = 0; @@ -372,7 +342,6 @@ static int __init gru_init(void) { int ret, irq, chip; char id[10]; - void *gru_start_vaddr; if (!is_uv_system()) return 0; @@ -422,6 +391,7 @@ static int __init gru_init(void) printk(KERN_ERR "%s: init tables failed\n", GRU_DRIVER_ID_STR); goto exit3; } + gru_kservices_init(); printk(KERN_INFO "%s: v%s\n", GRU_DRIVER_ID_STR, GRU_DRIVER_VERSION_STR); @@ -440,7 +410,7 @@ exit1: static void __exit gru_exit(void) { - int i, bid, gid; + int i, bid; int order = get_order(sizeof(struct gru_state) * GRU_CHIPLETS_PER_BLADE); @@ -449,10 +419,7 @@ static void __exit gru_exit(void) for (i = 0; i < GRU_CHIPLETS_PER_BLADE; i++) free_irq(IRQ_GRU + i, NULL); - - foreach_gid(gid) - gru_kservices_exit(GID_TO_GRU(gid)); - + gru_kservices_exit(); for (bid = 0; bid < GRU_MAX_BLADES; bid++) free_pages((unsigned long)gru_base[bid], order); diff --git a/drivers/misc/sgi-gru/gruhandles.c b/drivers/misc/sgi-gru/gruhandles.c index 9b7ccb328697..37e7cfc53b9c 100644 --- a/drivers/misc/sgi-gru/gruhandles.c +++ b/drivers/misc/sgi-gru/gruhandles.c @@ -57,7 +57,7 @@ static void start_instruction(void *h) static int wait_instruction_complete(void *h, enum mcs_op opc) { int status; - cycles_t start_time = get_cycles(); + unsigned long start_time = get_cycles(); while (1) { cpu_relax(); @@ -65,25 +65,16 @@ static int wait_instruction_complete(void *h, enum mcs_op opc) if (status != CCHSTATUS_ACTIVE) break; if (GRU_OPERATION_TIMEOUT < (get_cycles() - start_time)) - panic("GRU %p is malfunctioning\n", h); + panic("GRU %p is malfunctioning: start %ld, end %ld\n", + h, start_time, (unsigned long)get_cycles()); } if (gru_options & OPT_STATS) update_mcs_stats(opc, get_cycles() - start_time); return status; } -int cch_allocate(struct gru_context_configuration_handle *cch, - int asidval, int sizeavail, unsigned long cbrmap, - unsigned long dsrmap) +int cch_allocate(struct gru_context_configuration_handle *cch) { - int i; - - for (i = 0; i < 8; i++) { - cch->asid[i] = (asidval++); - cch->sizeavail[i] = sizeavail; - } - cch->dsr_allocation_map = dsrmap; - cch->cbr_allocation_map = cbrmap; cch->opc = CCHOP_ALLOCATE; start_instruction(cch); return wait_instruction_complete(cch, cchop_allocate); diff --git a/drivers/misc/sgi-gru/gruhandles.h b/drivers/misc/sgi-gru/gruhandles.h index 1ed74d7508c8..f44112242d00 100644 --- a/drivers/misc/sgi-gru/gruhandles.h +++ b/drivers/misc/sgi-gru/gruhandles.h @@ -39,7 +39,6 @@ #define GRU_NUM_CBE 128 #define GRU_NUM_TFH 128 #define GRU_NUM_CCH 16 -#define GRU_NUM_GSH 1 /* Maximum resource counts that can be reserved by user programs */ #define GRU_NUM_USER_CBR GRU_NUM_CBE @@ -56,7 +55,6 @@ #define GRU_CBE_BASE (GRU_MCS_BASE + 0x10000) #define GRU_TFH_BASE (GRU_MCS_BASE + 0x18000) #define GRU_CCH_BASE (GRU_MCS_BASE + 0x20000) -#define GRU_GSH_BASE (GRU_MCS_BASE + 0x30000) /* User gseg constants */ #define GRU_GSEG_STRIDE (4 * 1024 * 1024) @@ -251,15 +249,15 @@ struct gru_tlb_fault_handle { unsigned int fill1:9; unsigned int status:2; - unsigned int fill2:1; - unsigned int color:1; + unsigned int fill2:2; unsigned int state:3; unsigned int fill3:1; - unsigned int cause:7; /* DW 0 - high 32 */ + unsigned int cause:6; + unsigned int cb_int:1; unsigned int fill4:1; - unsigned int indexway:12; + unsigned int indexway:12; /* DW 0 - high 32 */ unsigned int fill5:4; unsigned int ctxnum:4; @@ -457,21 +455,7 @@ enum gru_cbr_state { CBRSTATE_BUSY_INTERRUPT, }; -/* CBE cbrexecstatus bits */ -#define CBR_EXS_ABORT_OCC_BIT 0 -#define CBR_EXS_INT_OCC_BIT 1 -#define CBR_EXS_PENDING_BIT 2 -#define CBR_EXS_QUEUED_BIT 3 -#define CBR_EXS_TLBHW_BIT 4 -#define CBR_EXS_EXCEPTION_BIT 5 - -#define CBR_EXS_ABORT_OCC (1 << CBR_EXS_ABORT_OCC_BIT) -#define CBR_EXS_INT_OCC (1 << CBR_EXS_INT_OCC_BIT) -#define CBR_EXS_PENDING (1 << CBR_EXS_PENDING_BIT) -#define CBR_EXS_QUEUED (1 << CBR_EXS_QUEUED_BIT) -#define CBR_EXS_TLBHW (1 << CBR_EXS_TLBHW_BIT) -#define CBR_EXS_EXCEPTION (1 << CBR_EXS_EXCEPTION_BIT) - +/* CBE cbrexecstatus bits - defined in gru_instructions.h*/ /* CBE ecause bits - defined in gru_instructions.h */ /* @@ -495,9 +479,7 @@ enum gru_cbr_state { /* minimum TLB purge count to ensure a full purge */ #define GRUMAXINVAL 1024UL -int cch_allocate(struct gru_context_configuration_handle *cch, - int asidval, int sizeavail, unsigned long cbrmap, unsigned long dsrmap); - +int cch_allocate(struct gru_context_configuration_handle *cch); int cch_start(struct gru_context_configuration_handle *cch); int cch_interrupt(struct gru_context_configuration_handle *cch); int cch_deallocate(struct gru_context_configuration_handle *cch); diff --git a/drivers/misc/sgi-gru/grukdump.c b/drivers/misc/sgi-gru/grukdump.c new file mode 100644 index 000000000000..55eabfa85585 --- /dev/null +++ b/drivers/misc/sgi-gru/grukdump.c @@ -0,0 +1,232 @@ +/* + * SN Platform GRU Driver + * + * Dump GRU State + * + * 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 +#include +#include +#include +#include +#include +#include +#include "gru.h" +#include "grutables.h" +#include "gruhandles.h" +#include "grulib.h" + +#define CCH_LOCK_ATTEMPTS 10 + +static int gru_user_copy_handle(void __user **dp, void *s) +{ + if (copy_to_user(*dp, s, GRU_HANDLE_BYTES)) + return -1; + *dp += GRU_HANDLE_BYTES; + return 0; +} + +static int gru_dump_context_data(void *grubase, + struct gru_context_configuration_handle *cch, + void __user *ubuf, int ctxnum, int dsrcnt) +{ + void *cb, *cbe, *tfh, *gseg; + int i, scr; + + gseg = grubase + ctxnum * GRU_GSEG_STRIDE; + cb = gseg + GRU_CB_BASE; + cbe = grubase + GRU_CBE_BASE; + tfh = grubase + GRU_TFH_BASE; + + for_each_cbr_in_allocation_map(i, &cch->cbr_allocation_map, scr) { + if (gru_user_copy_handle(&ubuf, cb)) + goto fail; + if (gru_user_copy_handle(&ubuf, tfh + i * GRU_HANDLE_STRIDE)) + goto fail; + if (gru_user_copy_handle(&ubuf, cbe + i * GRU_HANDLE_STRIDE)) + goto fail; + cb += GRU_HANDLE_STRIDE; + } + if (dsrcnt) + memcpy(ubuf, gseg + GRU_DS_BASE, dsrcnt * GRU_HANDLE_STRIDE); + return 0; + +fail: + return -EFAULT; +} + +static int gru_dump_tfm(struct gru_state *gru, + void __user *ubuf, void __user *ubufend) +{ + struct gru_tlb_fault_map *tfm; + int i, ret, bytes; + + bytes = GRU_NUM_TFM * GRU_CACHE_LINE_BYTES; + if (bytes > ubufend - ubuf) + ret = -EFBIG; + + for (i = 0; i < GRU_NUM_TFM; i++) { + tfm = get_tfm(gru->gs_gru_base_vaddr, i); + if (gru_user_copy_handle(&ubuf, tfm)) + goto fail; + } + return GRU_NUM_TFM * GRU_CACHE_LINE_BYTES; + +fail: + return -EFAULT; +} + +static int gru_dump_tgh(struct gru_state *gru, + void __user *ubuf, void __user *ubufend) +{ + struct gru_tlb_global_handle *tgh; + int i, ret, bytes; + + bytes = GRU_NUM_TGH * GRU_CACHE_LINE_BYTES; + if (bytes > ubufend - ubuf) + ret = -EFBIG; + + for (i = 0; i < GRU_NUM_TGH; i++) { + tgh = get_tgh(gru->gs_gru_base_vaddr, i); + if (gru_user_copy_handle(&ubuf, tgh)) + goto fail; + } + return GRU_NUM_TGH * GRU_CACHE_LINE_BYTES; + +fail: + return -EFAULT; +} + +static int gru_dump_context(struct gru_state *gru, int ctxnum, + void __user *ubuf, void __user *ubufend, char data_opt, + char lock_cch) +{ + struct gru_dump_context_header hdr; + struct gru_dump_context_header __user *uhdr = ubuf; + struct gru_context_configuration_handle *cch, *ubufcch; + struct gru_thread_state *gts; + int try, cch_locked, cbrcnt = 0, dsrcnt = 0, bytes = 0, ret = 0; + void *grubase; + + memset(&hdr, 0, sizeof(hdr)); + grubase = gru->gs_gru_base_vaddr; + cch = get_cch(grubase, ctxnum); + for (try = 0; try < CCH_LOCK_ATTEMPTS; try++) { + cch_locked = trylock_cch_handle(cch); + if (cch_locked) + break; + msleep(1); + } + + ubuf += sizeof(hdr); + ubufcch = ubuf; + if (gru_user_copy_handle(&ubuf, cch)) + goto fail; + if (cch_locked) + ubufcch->delresp = 0; + bytes = sizeof(hdr) + GRU_CACHE_LINE_BYTES; + + if (cch_locked || !lock_cch) { + gts = gru->gs_gts[ctxnum]; + if (gts && gts->ts_vma) { + hdr.pid = gts->ts_tgid_owner; + hdr.vaddr = gts->ts_vma->vm_start; + } + if (cch->state != CCHSTATE_INACTIVE) { + cbrcnt = hweight64(cch->cbr_allocation_map) * + GRU_CBR_AU_SIZE; + dsrcnt = data_opt ? hweight32(cch->dsr_allocation_map) * + GRU_DSR_AU_CL : 0; + } + bytes += (3 * cbrcnt + dsrcnt) * GRU_CACHE_LINE_BYTES; + if (bytes > ubufend - ubuf) + ret = -EFBIG; + else + ret = gru_dump_context_data(grubase, cch, ubuf, ctxnum, + dsrcnt); + + } + if (cch_locked) + unlock_cch_handle(cch); + if (ret) + return ret; + + hdr.magic = GRU_DUMP_MAGIC; + hdr.gid = gru->gs_gid; + hdr.ctxnum = ctxnum; + hdr.cbrcnt = cbrcnt; + hdr.dsrcnt = dsrcnt; + hdr.cch_locked = cch_locked; + if (!ret && copy_to_user((void __user *)uhdr, &hdr, sizeof(hdr))) + ret = -EFAULT; + + return ret ? ret : bytes; + +fail: + unlock_cch_handle(cch); + return -EFAULT; +} + +int gru_dump_chiplet_request(unsigned long arg) +{ + struct gru_state *gru; + struct gru_dump_chiplet_state_req req; + void __user *ubuf; + void __user *ubufend; + int ctxnum, ret, cnt = 0; + + if (copy_from_user(&req, (void __user *)arg, sizeof(req))) + return -EFAULT; + + /* Currently, only dump by gid is implemented */ + if (req.gid >= gru_max_gids || req.gid < 0) + return -EINVAL; + + gru = GID_TO_GRU(req.gid); + ubuf = req.buf; + ubufend = req.buf + req.buflen; + + ret = gru_dump_tfm(gru, ubuf, ubufend); + if (ret < 0) + goto fail; + ubuf += ret; + + ret = gru_dump_tgh(gru, ubuf, ubufend); + if (ret < 0) + goto fail; + ubuf += ret; + + for (ctxnum = 0; ctxnum < GRU_NUM_CCH; ctxnum++) { + if (req.ctxnum == ctxnum || req.ctxnum < 0) { + ret = gru_dump_context(gru, ctxnum, ubuf, ubufend, + req.data_opt, req.lock_cch); + if (ret < 0) + goto fail; + ubuf += ret; + cnt++; + } + } + + if (copy_to_user((void __user *)arg, &req, sizeof(req))) + return -EFAULT; + return cnt; + +fail: + return ret; +} diff --git a/drivers/misc/sgi-gru/grukservices.c b/drivers/misc/sgi-gru/grukservices.c index d8bd7d84a7cf..eedbf9c32760 100644 --- a/drivers/misc/sgi-gru/grukservices.c +++ b/drivers/misc/sgi-gru/grukservices.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "gru.h" #include "grulib.h" #include "grutables.h" @@ -45,18 +46,66 @@ * resources. This will likely be replaced when we better understand the * kernel/user requirements. * - * At boot time, the kernel permanently reserves a fixed number of - * CBRs/DSRs for each cpu to use. The resources are all taken from - * the GRU chiplet 1 on the blade. This leaves the full set of resources - * of chiplet 0 available to be allocated to a single user. + * Blade percpu resources reserved for kernel use. These resources are + * reserved whenever the the kernel context for the blade is loaded. Note + * that the kernel context is not guaranteed to be always available. It is + * loaded on demand & can be stolen by a user if the user demand exceeds the + * kernel demand. The kernel can always reload the kernel context but + * a SLEEP may be required!!!. + * + * Async Overview: + * + * Each blade has one "kernel context" that owns GRU kernel resources + * located on the blade. Kernel drivers use GRU resources in this context + * for sending messages, zeroing memory, etc. + * + * The kernel context is dynamically loaded on demand. If it is not in + * use by the kernel, the kernel context can be unloaded & given to a user. + * The kernel context will be reloaded when needed. This may require that + * a context be stolen from a user. + * NOTE: frequent unloading/reloading of the kernel context is + * expensive. We are depending on batch schedulers, cpusets, sane + * drivers or some other mechanism to prevent the need for frequent + * stealing/reloading. + * + * The kernel context consists of two parts: + * - 1 CB & a few DSRs that are reserved for each cpu on the blade. + * Each cpu has it's own private resources & does not share them + * with other cpus. These resources are used serially, ie, + * locked, used & unlocked on each call to a function in + * grukservices. + * (Now that we have dynamic loading of kernel contexts, I + * may rethink this & allow sharing between cpus....) + * + * - Additional resources can be reserved long term & used directly + * by UV drivers located in the kernel. Drivers using these GRU + * resources can use asynchronous GRU instructions that send + * interrupts on completion. + * - these resources must be explicitly locked/unlocked + * - locked resources prevent (obviously) the kernel + * context from being unloaded. + * - drivers using these resource directly issue their own + * GRU instruction and must wait/check completion. + * + * When these resources are reserved, the caller can optionally + * associate a wait_queue with the resources and use asynchronous + * GRU instructions. When an async GRU instruction completes, the + * driver will do a wakeup on the event. + * */ -/* Blade percpu resources PERMANENTLY reserved for kernel use */ + +#define ASYNC_HAN_TO_BID(h) ((h) - 1) +#define ASYNC_BID_TO_HAN(b) ((b) + 1) +#define ASYNC_HAN_TO_BS(h) gru_base[ASYNC_HAN_TO_BID(h)] +#define KCB_TO_GID(cb) ((cb - gru_start_vaddr) / \ + (GRU_SIZE * GRU_CHIPLETS_PER_BLADE)) +#define KCB_TO_BS(cb) gru_base[KCB_TO_GID(cb)] + #define GRU_NUM_KERNEL_CBR 1 #define GRU_NUM_KERNEL_DSR_BYTES 256 #define GRU_NUM_KERNEL_DSR_CL (GRU_NUM_KERNEL_DSR_BYTES / \ GRU_CACHE_LINE_BYTES) -#define KERNEL_CTXNUM 15 /* GRU instruction attributes for all instructions */ #define IMA IMA_CB_DELAY @@ -98,6 +147,108 @@ struct message_header { #define HSTATUS(mq, h) ((mq) + offsetof(struct message_queue, hstatus[h])) +/* + * Reload the blade's kernel context into a GRU chiplet. Called holding + * the bs_kgts_sema for READ. Will steal user contexts if necessary. + */ +static void gru_load_kernel_context(struct gru_blade_state *bs, int blade_id) +{ + struct gru_state *gru; + struct gru_thread_state *kgts; + void *vaddr; + int ctxnum, ncpus; + + up_read(&bs->bs_kgts_sema); + down_write(&bs->bs_kgts_sema); + + if (!bs->bs_kgts) + bs->bs_kgts = gru_alloc_gts(NULL, 0, 0, 0, 0); + kgts = bs->bs_kgts; + + if (!kgts->ts_gru) { + STAT(load_kernel_context); + ncpus = uv_blade_nr_possible_cpus(blade_id); + kgts->ts_cbr_au_count = GRU_CB_COUNT_TO_AU( + GRU_NUM_KERNEL_CBR * ncpus + bs->bs_async_cbrs); + kgts->ts_dsr_au_count = GRU_DS_BYTES_TO_AU( + GRU_NUM_KERNEL_DSR_BYTES * ncpus + + bs->bs_async_dsr_bytes); + while (!gru_assign_gru_context(kgts, blade_id)) { + msleep(1); + gru_steal_context(kgts, blade_id); + } + gru_load_context(kgts); + gru = bs->bs_kgts->ts_gru; + vaddr = gru->gs_gru_base_vaddr; + ctxnum = kgts->ts_ctxnum; + bs->kernel_cb = get_gseg_base_address_cb(vaddr, ctxnum, 0); + bs->kernel_dsr = get_gseg_base_address_ds(vaddr, ctxnum, 0); + } + downgrade_write(&bs->bs_kgts_sema); +} + +/* + * Free all kernel contexts that are not currently in use. + * Returns 0 if all freed, else number of inuse context. + */ +static int gru_free_kernel_contexts(void) +{ + struct gru_blade_state *bs; + struct gru_thread_state *kgts; + int bid, ret = 0; + + for (bid = 0; bid < GRU_MAX_BLADES; bid++) { + bs = gru_base[bid]; + if (!bs) + continue; + if (down_write_trylock(&bs->bs_kgts_sema)) { + kgts = bs->bs_kgts; + if (kgts && kgts->ts_gru) + gru_unload_context(kgts, 0); + kfree(kgts); + bs->bs_kgts = NULL; + up_write(&bs->bs_kgts_sema); + } else { + ret++; + } + } + return ret; +} + +/* + * Lock & load the kernel context for the specified blade. + */ +static struct gru_blade_state *gru_lock_kernel_context(int blade_id) +{ + struct gru_blade_state *bs; + + STAT(lock_kernel_context); + bs = gru_base[blade_id]; + + down_read(&bs->bs_kgts_sema); + if (!bs->bs_kgts || !bs->bs_kgts->ts_gru) + gru_load_kernel_context(bs, blade_id); + return bs; + +} + +/* + * Unlock the kernel context for the specified blade. Context is not + * unloaded but may be stolen before next use. + */ +static void gru_unlock_kernel_context(int blade_id) +{ + struct gru_blade_state *bs; + + bs = gru_base[blade_id]; + up_read(&bs->bs_kgts_sema); + STAT(unlock_kernel_context); +} + +/* + * Reserve & get pointers to the DSR/CBRs reserved for the current cpu. + * - returns with preemption disabled + */ static int gru_get_cpu_resources(int dsr_bytes, void **cb, void **dsr) { struct gru_blade_state *bs; @@ -105,30 +256,148 @@ static int gru_get_cpu_resources(int dsr_bytes, void **cb, void **dsr) BUG_ON(dsr_bytes > GRU_NUM_KERNEL_DSR_BYTES); preempt_disable(); - bs = gru_base[uv_numa_blade_id()]; + bs = gru_lock_kernel_context(uv_numa_blade_id()); lcpu = uv_blade_processor_id(); *cb = bs->kernel_cb + lcpu * GRU_HANDLE_STRIDE; *dsr = bs->kernel_dsr + lcpu * GRU_NUM_KERNEL_DSR_BYTES; return 0; } +/* + * Free the current cpus reserved DSR/CBR resources. + */ static void gru_free_cpu_resources(void *cb, void *dsr) { + gru_unlock_kernel_context(uv_numa_blade_id()); preempt_enable(); } +/* + * Reserve GRU resources to be used asynchronously. + * Note: currently supports only 1 reservation per blade. + * + * input: + * blade_id - blade on which resources should be reserved + * cbrs - number of CBRs + * dsr_bytes - number of DSR bytes needed + * output: + * handle to identify resource + * (0 = async resources already reserved) + */ +unsigned long gru_reserve_async_resources(int blade_id, int cbrs, int dsr_bytes, + struct completion *cmp) +{ + struct gru_blade_state *bs; + struct gru_thread_state *kgts; + int ret = 0; + + bs = gru_base[blade_id]; + + down_write(&bs->bs_kgts_sema); + + /* Verify no resources already reserved */ + if (bs->bs_async_dsr_bytes + bs->bs_async_cbrs) + goto done; + bs->bs_async_dsr_bytes = dsr_bytes; + bs->bs_async_cbrs = cbrs; + bs->bs_async_wq = cmp; + kgts = bs->bs_kgts; + + /* Resources changed. Unload context if already loaded */ + if (kgts && kgts->ts_gru) + gru_unload_context(kgts, 0); + ret = ASYNC_BID_TO_HAN(blade_id); + +done: + up_write(&bs->bs_kgts_sema); + return ret; +} + +/* + * Release async resources previously reserved. + * + * input: + * han - handle to identify resources + */ +void gru_release_async_resources(unsigned long han) +{ + struct gru_blade_state *bs = ASYNC_HAN_TO_BS(han); + + down_write(&bs->bs_kgts_sema); + bs->bs_async_dsr_bytes = 0; + bs->bs_async_cbrs = 0; + bs->bs_async_wq = NULL; + up_write(&bs->bs_kgts_sema); +} + +/* + * Wait for async GRU instructions to complete. + * + * input: + * han - handle to identify resources + */ +void gru_wait_async_cbr(unsigned long han) +{ + struct gru_blade_state *bs = ASYNC_HAN_TO_BS(han); + + wait_for_completion(bs->bs_async_wq); + mb(); +} + +/* + * Lock previous reserved async GRU resources + * + * input: + * han - handle to identify resources + * output: + * cb - pointer to first CBR + * dsr - pointer to first DSR + */ +void gru_lock_async_resource(unsigned long han, void **cb, void **dsr) +{ + struct gru_blade_state *bs = ASYNC_HAN_TO_BS(han); + int blade_id = ASYNC_HAN_TO_BID(han); + int ncpus; + + gru_lock_kernel_context(blade_id); + ncpus = uv_blade_nr_possible_cpus(blade_id); + if (cb) + *cb = bs->kernel_cb + ncpus * GRU_HANDLE_STRIDE; + if (dsr) + *dsr = bs->kernel_dsr + ncpus * GRU_NUM_KERNEL_DSR_BYTES; +} + +/* + * Unlock previous reserved async GRU resources + * + * input: + * han - handle to identify resources + */ +void gru_unlock_async_resource(unsigned long han) +{ + int blade_id = ASYNC_HAN_TO_BID(han); + + gru_unlock_kernel_context(blade_id); +} + +/*----------------------------------------------------------------------*/ int gru_get_cb_exception_detail(void *cb, struct control_block_extended_exc_detail *excdet) { struct gru_control_block_extended *cbe; + struct gru_blade_state *bs; + int cbrnum; - cbe = get_cbe(GRUBASE(cb), get_cb_number(cb)); - prefetchw(cbe); /* Harmless on hardware, required for emulator */ + bs = KCB_TO_BS(cb); + cbrnum = thread_cbr_number(bs->bs_kgts, get_cb_number(cb)); + cbe = get_cbe(GRUBASE(cb), cbrnum); + gru_flush_cache(cbe); /* CBE not coherent */ excdet->opc = cbe->opccpy; excdet->exopc = cbe->exopccpy; excdet->ecause = cbe->ecause; excdet->exceptdet0 = cbe->idef1upd; excdet->exceptdet1 = cbe->idef3upd; + gru_flush_cache(cbe); return 0; } @@ -167,13 +436,13 @@ static int gru_retry_exception(void *cb) int retry = EXCEPTION_RETRY_LIMIT; while (1) { - if (gru_get_cb_message_queue_substatus(cb)) - break; if (gru_wait_idle_or_exception(gen) == CBS_IDLE) return CBS_IDLE; - + if (gru_get_cb_message_queue_substatus(cb)) + return CBS_EXCEPTION; gru_get_cb_exception_detail(cb, &excdet); - if (excdet.ecause & ~EXCEPTION_RETRY_BITS) + if ((excdet.ecause & ~EXCEPTION_RETRY_BITS) || + (excdet.cbrexecstatus & CBR_EXS_ABORT_OCC)) break; if (retry-- == 0) break; @@ -416,6 +685,29 @@ static void send_message_queue_interrupt(struct gru_message_queue_desc *mqd) mqd->interrupt_vector); } +/* + * Handle a PUT failure. Note: if message was a 2-line message, one of the + * lines might have successfully have been written. Before sending the + * message, "present" must be cleared in BOTH lines to prevent the receiver + * from prematurely seeing the full message. + */ +static int send_message_put_nacked(void *cb, struct gru_message_queue_desc *mqd, + void *mesg, int lines) +{ + unsigned long m; + + m = mqd->mq_gpa + (gru_get_amo_value_head(cb) << 6); + if (lines == 2) { + gru_vset(cb, m, 0, XTYPE_CL, lines, 1, IMA); + if (gru_wait(cb) != CBS_IDLE) + return MQE_UNEXPECTED_CB_ERR; + } + gru_vstore(cb, m, gru_get_tri(mesg), XTYPE_CL, lines, 1, IMA); + if (gru_wait(cb) != CBS_IDLE) + return MQE_UNEXPECTED_CB_ERR; + send_message_queue_interrupt(mqd); + return MQE_OK; +} /* * Handle a gru_mesq failure. Some of these failures are software recoverable @@ -425,7 +717,6 @@ static int send_message_failure(void *cb, struct gru_message_queue_desc *mqd, void *mesg, int lines) { int substatus, ret = 0; - unsigned long m; substatus = gru_get_cb_message_queue_substatus(cb); switch (substatus) { @@ -447,14 +738,7 @@ static int send_message_failure(void *cb, struct gru_message_queue_desc *mqd, break; case CBSS_PUT_NACKED: STAT(mesq_send_put_nacked); - m = mqd->mq_gpa + (gru_get_amo_value_head(cb) << 6); - gru_vstore(cb, m, gru_get_tri(mesg), XTYPE_CL, lines, 1, IMA); - if (gru_wait(cb) == CBS_IDLE) { - ret = MQE_OK; - send_message_queue_interrupt(mqd); - } else { - ret = MQE_UNEXPECTED_CB_ERR; - } + ret = send_message_put_nacked(cb, mqd, mesg, lines); break; default: BUG(); @@ -597,115 +881,177 @@ EXPORT_SYMBOL_GPL(gru_copy_gpa); /* ------------------- KERNEL QUICKTESTS RUN AT STARTUP ----------------*/ /* Temp - will delete after we gain confidence in the GRU */ -static __cacheline_aligned unsigned long word0; -static __cacheline_aligned unsigned long word1; -static int quicktest(struct gru_state *gru) +static int quicktest0(unsigned long arg) { + unsigned long word0; + unsigned long word1; void *cb; - void *ds; + void *dsr; unsigned long *p; + int ret = -EIO; - cb = get_gseg_base_address_cb(gru->gs_gru_base_vaddr, KERNEL_CTXNUM, 0); - ds = get_gseg_base_address_ds(gru->gs_gru_base_vaddr, KERNEL_CTXNUM, 0); - p = ds; + if (gru_get_cpu_resources(GRU_CACHE_LINE_BYTES, &cb, &dsr)) + return MQE_BUG_NO_RESOURCES; + p = dsr; word0 = MAGIC; + word1 = 0; - gru_vload(cb, uv_gpa(&word0), 0, XTYPE_DW, 1, 1, IMA); - if (gru_wait(cb) != CBS_IDLE) - BUG(); - - if (*(unsigned long *)ds != MAGIC) - BUG(); - gru_vstore(cb, uv_gpa(&word1), 0, XTYPE_DW, 1, 1, IMA); - if (gru_wait(cb) != CBS_IDLE) - BUG(); - - if (word0 != word1 || word0 != MAGIC) { - printk - ("GRU quicktest err: gid %d, found 0x%lx, expected 0x%lx\n", - gru->gs_gid, word1, MAGIC); - BUG(); /* ZZZ should not be fatal */ + gru_vload(cb, uv_gpa(&word0), gru_get_tri(dsr), XTYPE_DW, 1, 1, IMA); + if (gru_wait(cb) != CBS_IDLE) { + printk(KERN_DEBUG "GRU quicktest0: CBR failure 1\n"); + goto done; } + if (*p != MAGIC) { + printk(KERN_DEBUG "GRU: quicktest0 bad magic 0x%lx\n", *p); + goto done; + } + gru_vstore(cb, uv_gpa(&word1), gru_get_tri(dsr), XTYPE_DW, 1, 1, IMA); + if (gru_wait(cb) != CBS_IDLE) { + printk(KERN_DEBUG "GRU quicktest0: CBR failure 2\n"); + goto done; + } + + if (word0 != word1 || word1 != MAGIC) { + printk(KERN_DEBUG + "GRU quicktest0 err: found 0x%lx, expected 0x%lx\n", + word1, MAGIC); + goto done; + } + ret = 0; + +done: + gru_free_cpu_resources(cb, dsr); + return ret; +} + +#define ALIGNUP(p, q) ((void *)(((unsigned long)(p) + (q) - 1) & ~(q - 1))) + +static int quicktest1(unsigned long arg) +{ + struct gru_message_queue_desc mqd; + void *p, *mq; + unsigned long *dw; + int i, ret = -EIO; + char mes[GRU_CACHE_LINE_BYTES], *m; + + /* Need 1K cacheline aligned that does not cross page boundary */ + p = kmalloc(4096, 0); + mq = ALIGNUP(p, 1024); + memset(mes, 0xee, sizeof(mes)); + dw = mq; + + gru_create_message_queue(&mqd, mq, 8 * GRU_CACHE_LINE_BYTES, 0, 0, 0); + for (i = 0; i < 6; i++) { + mes[8] = i; + do { + ret = gru_send_message_gpa(&mqd, mes, sizeof(mes)); + } while (ret == MQE_CONGESTION); + if (ret) + break; + } + if (ret != MQE_QUEUE_FULL || i != 4) + goto done; + + for (i = 0; i < 6; i++) { + m = gru_get_next_message(&mqd); + if (!m || m[8] != i) + break; + gru_free_message(&mqd, m); + } + ret = (i == 4) ? 0 : -EIO; + +done: + kfree(p); + return ret; +} + +static int quicktest2(unsigned long arg) +{ + static DECLARE_COMPLETION(cmp); + unsigned long han; + int blade_id = 0; + int numcb = 4; + int ret = 0; + unsigned long *buf; + void *cb0, *cb; + int i, k, istatus, bytes; + + bytes = numcb * 4 * 8; + buf = kmalloc(bytes, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + ret = -EBUSY; + han = gru_reserve_async_resources(blade_id, numcb, 0, &cmp); + if (!han) + goto done; + + gru_lock_async_resource(han, &cb0, NULL); + memset(buf, 0xee, bytes); + for (i = 0; i < numcb; i++) + gru_vset(cb0 + i * GRU_HANDLE_STRIDE, uv_gpa(&buf[i * 4]), 0, + XTYPE_DW, 4, 1, IMA_INTERRUPT); + + ret = 0; + for (k = 0; k < numcb; k++) { + gru_wait_async_cbr(han); + for (i = 0; i < numcb; i++) { + cb = cb0 + i * GRU_HANDLE_STRIDE; + istatus = gru_check_status(cb); + if (istatus == CBS_ACTIVE) + continue; + if (istatus == CBS_EXCEPTION) + ret = -EFAULT; + else if (buf[i] || buf[i + 1] || buf[i + 2] || + buf[i + 3]) + ret = -EIO; + } + } + BUG_ON(cmp.done); + + gru_unlock_async_resource(han); + gru_release_async_resources(han); +done: + kfree(buf); + return ret; +} + +/* + * Debugging only. User hook for various kernel tests + * of driver & gru. + */ +int gru_ktest(unsigned long arg) +{ + int ret = -EINVAL; + + switch (arg & 0xff) { + case 0: + ret = quicktest0(arg); + break; + case 1: + ret = quicktest1(arg); + break; + case 2: + ret = quicktest2(arg); + break; + case 99: + ret = gru_free_kernel_contexts(); + break; + } + return ret; + +} + +int gru_kservices_init(void) +{ return 0; } - -int gru_kservices_init(struct gru_state *gru) +void gru_kservices_exit(void) { - struct gru_blade_state *bs; - struct gru_context_configuration_handle *cch; - unsigned long cbr_map, dsr_map; - int err, num, cpus_possible; - - /* - * Currently, resources are reserved ONLY on the second chiplet - * on each blade. This leaves ALL resources on chiplet 0 available - * for user code. - */ - bs = gru->gs_blade; - if (gru != &bs->bs_grus[1]) - return 0; - - cpus_possible = uv_blade_nr_possible_cpus(gru->gs_blade_id); - - num = GRU_NUM_KERNEL_CBR * cpus_possible; - cbr_map = gru_reserve_cb_resources(gru, GRU_CB_COUNT_TO_AU(num), NULL); - gru->gs_reserved_cbrs += num; - - num = GRU_NUM_KERNEL_DSR_BYTES * cpus_possible; - dsr_map = gru_reserve_ds_resources(gru, GRU_DS_BYTES_TO_AU(num), NULL); - gru->gs_reserved_dsr_bytes += num; - - gru->gs_active_contexts++; - __set_bit(KERNEL_CTXNUM, &gru->gs_context_map); - cch = get_cch(gru->gs_gru_base_vaddr, KERNEL_CTXNUM); - - bs->kernel_cb = get_gseg_base_address_cb(gru->gs_gru_base_vaddr, - KERNEL_CTXNUM, 0); - bs->kernel_dsr = get_gseg_base_address_ds(gru->gs_gru_base_vaddr, - KERNEL_CTXNUM, 0); - - lock_cch_handle(cch); - cch->tfm_fault_bit_enable = 0; - cch->tlb_int_enable = 0; - cch->tfm_done_bit_enable = 0; - cch->unmap_enable = 1; - err = cch_allocate(cch, 0, 0, cbr_map, dsr_map); - if (err) { - gru_dbg(grudev, - "Unable to allocate kernel CCH: gid %d, err %d\n", - gru->gs_gid, err); + if (gru_free_kernel_contexts()) BUG(); - } - if (cch_start(cch)) { - gru_dbg(grudev, "Unable to start kernel CCH: gid %d, err %d\n", - gru->gs_gid, err); - BUG(); - } - unlock_cch_handle(cch); - - if (gru_options & GRU_QUICKLOOK) - quicktest(gru); - return 0; -} - -void gru_kservices_exit(struct gru_state *gru) -{ - struct gru_context_configuration_handle *cch; - struct gru_blade_state *bs; - - bs = gru->gs_blade; - if (gru != &bs->bs_grus[1]) - return; - - cch = get_cch(gru->gs_gru_base_vaddr, KERNEL_CTXNUM); - lock_cch_handle(cch); - if (cch_interrupt_sync(cch)) - BUG(); - if (cch_deallocate(cch)) - BUG(); - unlock_cch_handle(cch); } diff --git a/drivers/misc/sgi-gru/grukservices.h b/drivers/misc/sgi-gru/grukservices.h index 747ed315d56f..d60d34bca44d 100644 --- a/drivers/misc/sgi-gru/grukservices.h +++ b/drivers/misc/sgi-gru/grukservices.h @@ -146,4 +146,55 @@ extern void *gru_get_next_message(struct gru_message_queue_desc *mqd); extern int gru_copy_gpa(unsigned long dest_gpa, unsigned long src_gpa, unsigned int bytes); +/* + * Reserve GRU resources to be used asynchronously. + * + * input: + * blade_id - blade on which resources should be reserved + * cbrs - number of CBRs + * dsr_bytes - number of DSR bytes needed + * cmp - completion structure for waiting for + * async completions + * output: + * handle to identify resource + * (0 = no resources) + */ +extern unsigned long gru_reserve_async_resources(int blade_id, int cbrs, int dsr_bytes, + struct completion *cmp); + +/* + * Release async resources previously reserved. + * + * input: + * han - handle to identify resources + */ +extern void gru_release_async_resources(unsigned long han); + +/* + * Wait for async GRU instructions to complete. + * + * input: + * han - handle to identify resources + */ +extern void gru_wait_async_cbr(unsigned long han); + +/* + * Lock previous reserved async GRU resources + * + * input: + * han - handle to identify resources + * output: + * cb - pointer to first CBR + * dsr - pointer to first DSR + */ +extern void gru_lock_async_resource(unsigned long han, void **cb, void **dsr); + +/* + * Unlock previous reserved async GRU resources + * + * input: + * han - handle to identify resources + */ +extern void gru_unlock_async_resource(unsigned long han); + #endif /* __GRU_KSERVICES_H_ */ diff --git a/drivers/misc/sgi-gru/grulib.h b/drivers/misc/sgi-gru/grulib.h index e56e196a6998..889bc442a3e8 100644 --- a/drivers/misc/sgi-gru/grulib.h +++ b/drivers/misc/sgi-gru/grulib.h @@ -32,8 +32,8 @@ /* Set Number of Request Blocks */ #define GRU_CREATE_CONTEXT _IOWR(GRU_IOCTL_NUM, 1, void *) -/* Register task as using the slice */ -#define GRU_SET_TASK_SLICE _IOWR(GRU_IOCTL_NUM, 5, void *) +/* Set Context Options */ +#define GRU_SET_CONTEXT_OPTION _IOWR(GRU_IOCTL_NUM, 4, void *) /* Fetch exception detail */ #define GRU_USER_GET_EXCEPTION_DETAIL _IOWR(GRU_IOCTL_NUM, 6, void *) @@ -44,8 +44,11 @@ /* For user unload context */ #define GRU_USER_UNLOAD_CONTEXT _IOWR(GRU_IOCTL_NUM, 9, void *) -/* For fetching GRU chiplet status */ -#define GRU_GET_CHIPLET_STATUS _IOWR(GRU_IOCTL_NUM, 10, void *) +/* For dumpping GRU chiplet state */ +#define GRU_DUMP_CHIPLET_STATE _IOWR(GRU_IOCTL_NUM, 11, void *) + +/* For getting gseg statistics */ +#define GRU_GET_GSEG_STATISTICS _IOWR(GRU_IOCTL_NUM, 12, void *) /* For user TLB flushing (primarily for tests) */ #define GRU_USER_FLUSH_TLB _IOWR(GRU_IOCTL_NUM, 50, void *) @@ -53,8 +56,26 @@ /* Get some config options (primarily for tests & emulator) */ #define GRU_GET_CONFIG_INFO _IOWR(GRU_IOCTL_NUM, 51, void *) +/* Various kernel self-tests */ +#define GRU_KTEST _IOWR(GRU_IOCTL_NUM, 52, void *) + #define CONTEXT_WINDOW_BYTES(th) (GRU_GSEG_PAGESIZE * (th)) #define THREAD_POINTER(p, th) (p + GRU_GSEG_PAGESIZE * (th)) +#define GSEG_START(cb) ((void *)((unsigned long)(cb) & ~(GRU_GSEG_PAGESIZE - 1))) + +/* + * Statictics kept on a per-GTS basis. + */ +struct gts_statistics { + unsigned long fmm_tlbdropin; + unsigned long upm_tlbdropin; + unsigned long context_stolen; +}; + +struct gru_get_gseg_statistics_req { + unsigned long gseg; + struct gts_statistics stats; +}; /* * Structure used to pass TLB flush parameters to the driver @@ -74,6 +95,16 @@ struct gru_unload_context_req { unsigned long gseg; }; +/* + * Structure used to set context options + */ +enum {sco_gseg_owner, sco_cch_req_slice}; +struct gru_set_context_option_req { + unsigned long gseg; + int op; + unsigned long val1; +}; + /* * Structure used to pass TLB flush parameters to the driver */ @@ -83,6 +114,36 @@ struct gru_flush_tlb_req { size_t len; }; +/* + * Structure used to pass TLB flush parameters to the driver + */ +enum {dcs_pid, dcs_gid}; +struct gru_dump_chiplet_state_req { + unsigned int op; + unsigned int gid; + int ctxnum; + char data_opt; + char lock_cch; + pid_t pid; + void *buf; + size_t buflen; + /* ---- output --- */ + unsigned int num_contexts; +}; + +#define GRU_DUMP_MAGIC 0x3474ab6c +struct gru_dump_context_header { + unsigned int magic; + unsigned int gid; + unsigned char ctxnum; + unsigned char cbrcnt; + unsigned char dsrcnt; + pid_t pid; + unsigned long vaddr; + int cch_locked; + unsigned long data[0]; +}; + /* * GRU configuration info (temp - for testing) */ diff --git a/drivers/misc/sgi-gru/grumain.c b/drivers/misc/sgi-gru/grumain.c index ec3f7a17d221..3bc643dad606 100644 --- a/drivers/misc/sgi-gru/grumain.c +++ b/drivers/misc/sgi-gru/grumain.c @@ -3,11 +3,21 @@ * * DRIVER TABLE MANAGER + GRU CONTEXT LOAD/UNLOAD * - * 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) 2008 Silicon Graphics, Inc. All Rights Reserved. * - * 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 @@ -96,7 +106,7 @@ static int gru_reset_asid_limit(struct gru_state *gru, int asid) gid = gru->gs_gid; again: for (i = 0; i < GRU_NUM_CCH; i++) { - if (!gru->gs_gts[i]) + if (!gru->gs_gts[i] || is_kernel_context(gru->gs_gts[i])) continue; inuse_asid = gru->gs_gts[i]->ts_gms->ms_asids[gid].mt_asid; gru_dbg(grudev, "gid %d, gts %p, gms %p, inuse 0x%x, cxt %d\n", @@ -150,7 +160,7 @@ static unsigned long reserve_resources(unsigned long *p, int n, int mmax, unsigned long bits = 0; int i; - do { + while (n--) { i = find_first_bit(p, mmax); if (i == mmax) BUG(); @@ -158,7 +168,7 @@ static unsigned long reserve_resources(unsigned long *p, int n, int mmax, __set_bit(i, &bits); if (idx) *idx++ = i; - } while (--n); + } return bits; } @@ -299,38 +309,39 @@ static struct gru_thread_state *gru_find_current_gts_nolock(struct gru_vma_data /* * Allocate a thread state structure. */ -static struct gru_thread_state *gru_alloc_gts(struct vm_area_struct *vma, - struct gru_vma_data *vdata, - int tsid) +struct gru_thread_state *gru_alloc_gts(struct vm_area_struct *vma, + int cbr_au_count, int dsr_au_count, int options, int tsid) { struct gru_thread_state *gts; int bytes; - bytes = DSR_BYTES(vdata->vd_dsr_au_count) + - CBR_BYTES(vdata->vd_cbr_au_count); + bytes = DSR_BYTES(dsr_au_count) + CBR_BYTES(cbr_au_count); bytes += sizeof(struct gru_thread_state); - gts = kzalloc(bytes, GFP_KERNEL); + gts = kmalloc(bytes, GFP_KERNEL); if (!gts) return NULL; STAT(gts_alloc); + memset(gts, 0, sizeof(struct gru_thread_state)); /* zero out header */ atomic_set(>s->ts_refcnt, 1); mutex_init(>s->ts_ctxlock); - gts->ts_cbr_au_count = vdata->vd_cbr_au_count; - gts->ts_dsr_au_count = vdata->vd_dsr_au_count; - gts->ts_user_options = vdata->vd_user_options; + gts->ts_cbr_au_count = cbr_au_count; + gts->ts_dsr_au_count = dsr_au_count; + gts->ts_user_options = options; gts->ts_tsid = tsid; - gts->ts_user_options = vdata->vd_user_options; gts->ts_ctxnum = NULLCTX; - gts->ts_mm = current->mm; - gts->ts_vma = vma; gts->ts_tlb_int_select = -1; - gts->ts_gms = gru_register_mmu_notifier(); + gts->ts_cch_req_slice = -1; gts->ts_sizeavail = GRU_SIZEAVAIL(PAGE_SHIFT); - if (!gts->ts_gms) - goto err; + if (vma) { + gts->ts_mm = current->mm; + gts->ts_vma = vma; + gts->ts_gms = gru_register_mmu_notifier(); + if (!gts->ts_gms) + goto err; + } - gru_dbg(grudev, "alloc vdata %p, new gts %p\n", vdata, gts); + gru_dbg(grudev, "alloc gts %p\n", gts); return gts; err: @@ -381,7 +392,8 @@ struct gru_thread_state *gru_alloc_thread_state(struct vm_area_struct *vma, struct gru_vma_data *vdata = vma->vm_private_data; struct gru_thread_state *gts, *ngts; - gts = gru_alloc_gts(vma, vdata, tsid); + gts = gru_alloc_gts(vma, vdata->vd_cbr_au_count, vdata->vd_dsr_au_count, + vdata->vd_user_options, tsid); if (!gts) return NULL; @@ -458,7 +470,8 @@ static void gru_prefetch_context(void *gseg, void *cb, void *cbe, } static void gru_load_context_data(void *save, void *grubase, int ctxnum, - unsigned long cbrmap, unsigned long dsrmap) + unsigned long cbrmap, unsigned long dsrmap, + int data_valid) { void *gseg, *cb, *cbe; unsigned long length; @@ -471,12 +484,22 @@ static void gru_load_context_data(void *save, void *grubase, int ctxnum, gru_prefetch_context(gseg, cb, cbe, cbrmap, length); for_each_cbr_in_allocation_map(i, &cbrmap, scr) { - save += gru_copy_handle(cb, save); - save += gru_copy_handle(cbe + i * GRU_HANDLE_STRIDE, save); + if (data_valid) { + save += gru_copy_handle(cb, save); + save += gru_copy_handle(cbe + i * GRU_HANDLE_STRIDE, + save); + } else { + memset(cb, 0, GRU_CACHE_LINE_BYTES); + memset(cbe + i * GRU_HANDLE_STRIDE, 0, + GRU_CACHE_LINE_BYTES); + } cb += GRU_HANDLE_STRIDE; } - memcpy(gseg + GRU_DS_BASE, save, length); + if (data_valid) + memcpy(gseg + GRU_DS_BASE, save, length); + else + memset(gseg + GRU_DS_BASE, 0, length); } static void gru_unload_context_data(void *save, void *grubase, int ctxnum, @@ -506,7 +529,8 @@ void gru_unload_context(struct gru_thread_state *gts, int savestate) struct gru_context_configuration_handle *cch; int ctxnum = gts->ts_ctxnum; - zap_vma_ptes(gts->ts_vma, UGRUADDR(gts), GRU_GSEG_PAGESIZE); + if (!is_kernel_context(gts)) + zap_vma_ptes(gts->ts_vma, UGRUADDR(gts), GRU_GSEG_PAGESIZE); cch = get_cch(gru->gs_gru_base_vaddr, ctxnum); gru_dbg(grudev, "gts %p\n", gts); @@ -514,11 +538,14 @@ void gru_unload_context(struct gru_thread_state *gts, int savestate) if (cch_interrupt_sync(cch)) BUG(); - gru_unload_mm_tracker(gru, gts); - if (savestate) + if (!is_kernel_context(gts)) + gru_unload_mm_tracker(gru, gts); + if (savestate) { gru_unload_context_data(gts->ts_gdata, gru->gs_gru_base_vaddr, ctxnum, gts->ts_cbr_map, gts->ts_dsr_map); + gts->ts_data_valid = 1; + } if (cch_deallocate(cch)) BUG(); @@ -526,24 +553,22 @@ void gru_unload_context(struct gru_thread_state *gts, int savestate) unlock_cch_handle(cch); gru_free_gru_context(gts); - STAT(unload_context); } /* * Load a GRU context by copying it from the thread data structure in memory * to the GRU. */ -static void gru_load_context(struct gru_thread_state *gts) +void gru_load_context(struct gru_thread_state *gts) { struct gru_state *gru = gts->ts_gru; struct gru_context_configuration_handle *cch; - int err, asid, ctxnum = gts->ts_ctxnum; + int i, err, asid, ctxnum = gts->ts_ctxnum; gru_dbg(grudev, "gts %p\n", gts); cch = get_cch(gru->gs_gru_base_vaddr, ctxnum); lock_cch_handle(cch); - asid = gru_load_mm_tracker(gru, gts); cch->tfm_fault_bit_enable = (gts->ts_user_options == GRU_OPT_MISS_FMM_POLL || gts->ts_user_options == GRU_OPT_MISS_FMM_INTR); @@ -552,9 +577,32 @@ static void gru_load_context(struct gru_thread_state *gts) gts->ts_tlb_int_select = gru_cpu_fault_map_id(); cch->tlb_int_select = gts->ts_tlb_int_select; } + if (gts->ts_cch_req_slice >= 0) { + cch->req_slice_set_enable = 1; + cch->req_slice = gts->ts_cch_req_slice; + } else { + cch->req_slice_set_enable =0; + } cch->tfm_done_bit_enable = 0; - err = cch_allocate(cch, asid, gts->ts_sizeavail, gts->ts_cbr_map, - gts->ts_dsr_map); + cch->dsr_allocation_map = gts->ts_dsr_map; + cch->cbr_allocation_map = gts->ts_cbr_map; + + if (is_kernel_context(gts)) { + cch->unmap_enable = 1; + cch->tfm_done_bit_enable = 1; + cch->cb_int_enable = 1; + } else { + cch->unmap_enable = 0; + cch->tfm_done_bit_enable = 0; + cch->cb_int_enable = 0; + asid = gru_load_mm_tracker(gru, gts); + for (i = 0; i < 8; i++) { + cch->asid[i] = asid + i; + cch->sizeavail[i] = gts->ts_sizeavail; + } + } + + err = cch_allocate(cch); if (err) { gru_dbg(grudev, "err %d: cch %p, gts %p, cbr 0x%lx, dsr 0x%lx\n", @@ -563,13 +611,11 @@ static void gru_load_context(struct gru_thread_state *gts) } gru_load_context_data(gts->ts_gdata, gru->gs_gru_base_vaddr, ctxnum, - gts->ts_cbr_map, gts->ts_dsr_map); + gts->ts_cbr_map, gts->ts_dsr_map, gts->ts_data_valid); if (cch_start(cch)) BUG(); unlock_cch_handle(cch); - - STAT(load_context); } /* @@ -599,6 +645,9 @@ int gru_update_cch(struct gru_thread_state *gts, int force_unload) cch->sizeavail[i] = gts->ts_sizeavail; gts->ts_tlb_int_select = gru_cpu_fault_map_id(); cch->tlb_int_select = gru_cpu_fault_map_id(); + cch->tfm_fault_bit_enable = + (gts->ts_user_options == GRU_OPT_MISS_FMM_POLL + || gts->ts_user_options == GRU_OPT_MISS_FMM_INTR); } else { for (i = 0; i < 8; i++) cch->asid[i] = 0; @@ -642,7 +691,28 @@ static int gru_retarget_intr(struct gru_thread_state *gts) #define next_gru(b, g) (((g) < &(b)->bs_grus[GRU_CHIPLETS_PER_BLADE - 1]) ? \ ((g)+1) : &(b)->bs_grus[0]) -static void gru_steal_context(struct gru_thread_state *gts) +static int is_gts_stealable(struct gru_thread_state *gts, + struct gru_blade_state *bs) +{ + if (is_kernel_context(gts)) + return down_write_trylock(&bs->bs_kgts_sema); + else + return mutex_trylock(>s->ts_ctxlock); +} + +static void gts_stolen(struct gru_thread_state *gts, + struct gru_blade_state *bs) +{ + if (is_kernel_context(gts)) { + up_write(&bs->bs_kgts_sema); + STAT(steal_kernel_context); + } else { + mutex_unlock(>s->ts_ctxlock); + STAT(steal_user_context); + } +} + +void gru_steal_context(struct gru_thread_state *gts, int blade_id) { struct gru_blade_state *blade; struct gru_state *gru, *gru0; @@ -652,8 +722,7 @@ static void gru_steal_context(struct gru_thread_state *gts) cbr = gts->ts_cbr_au_count; dsr = gts->ts_dsr_au_count; - preempt_disable(); - blade = gru_base[uv_numa_blade_id()]; + blade = gru_base[blade_id]; spin_lock(&blade->bs_lock); ctxnum = next_ctxnum(blade->bs_lru_ctxnum); @@ -676,7 +745,7 @@ static void gru_steal_context(struct gru_thread_state *gts) * success are high. If trylock fails, try to steal a * different GSEG. */ - if (ngts && mutex_trylock(&ngts->ts_ctxlock)) + if (ngts && is_gts_stealable(ngts, blade)) break; ngts = NULL; flag = 1; @@ -690,13 +759,12 @@ static void gru_steal_context(struct gru_thread_state *gts) blade->bs_lru_gru = gru; blade->bs_lru_ctxnum = ctxnum; spin_unlock(&blade->bs_lock); - preempt_enable(); if (ngts) { - STAT(steal_context); + gts->ustats.context_stolen++; ngts->ts_steal_jiffies = jiffies; - gru_unload_context(ngts, 1); - mutex_unlock(&ngts->ts_ctxlock); + gru_unload_context(ngts, is_kernel_context(ngts) ? 0 : 1); + gts_stolen(ngts, blade); } else { STAT(steal_context_failed); } @@ -710,17 +778,17 @@ static void gru_steal_context(struct gru_thread_state *gts) /* * Scan the GRUs on the local blade & assign a GRU context. */ -static struct gru_state *gru_assign_gru_context(struct gru_thread_state *gts) +struct gru_state *gru_assign_gru_context(struct gru_thread_state *gts, + int blade) { struct gru_state *gru, *grux; int i, max_active_contexts; - preempt_disable(); again: gru = NULL; max_active_contexts = GRU_NUM_CCH; - for_each_gru_on_blade(grux, uv_numa_blade_id(), i) { + for_each_gru_on_blade(grux, blade, i) { if (check_gru_resources(grux, gts->ts_cbr_au_count, gts->ts_dsr_au_count, max_active_contexts)) { @@ -760,7 +828,6 @@ again: STAT(assign_context_failed); } - preempt_enable(); return gru; } @@ -775,6 +842,7 @@ int gru_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { struct gru_thread_state *gts; unsigned long paddr, vaddr; + int blade_id; vaddr = (unsigned long)vmf->virtual_address; gru_dbg(grudev, "vma %p, vaddr 0x%lx (0x%lx)\n", @@ -789,8 +857,10 @@ int gru_fault(struct vm_area_struct *vma, struct vm_fault *vmf) again: mutex_lock(>s->ts_ctxlock); preempt_disable(); + blade_id = uv_numa_blade_id(); + if (gts->ts_gru) { - if (gts->ts_gru->gs_blade_id != uv_numa_blade_id()) { + if (gts->ts_gru->gs_blade_id != blade_id) { STAT(migrated_nopfn_unload); gru_unload_context(gts, 1); } else { @@ -800,12 +870,15 @@ again: } if (!gts->ts_gru) { - if (!gru_assign_gru_context(gts)) { - mutex_unlock(>s->ts_ctxlock); + STAT(load_user_context); + if (!gru_assign_gru_context(gts, blade_id)) { preempt_enable(); + mutex_unlock(>s->ts_ctxlock); + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(GRU_ASSIGN_DELAY); /* true hack ZZZ */ + blade_id = uv_numa_blade_id(); if (gts->ts_steal_jiffies + GRU_STEAL_DELAY < jiffies) - gru_steal_context(gts); + gru_steal_context(gts, blade_id); goto again; } gru_load_context(gts); @@ -815,8 +888,8 @@ again: vma->vm_page_prot); } - mutex_unlock(>s->ts_ctxlock); preempt_enable(); + mutex_unlock(>s->ts_ctxlock); return VM_FAULT_NOPAGE; } diff --git a/drivers/misc/sgi-gru/gruprocfs.c b/drivers/misc/sgi-gru/gruprocfs.c index ee74821b171c..9cbf95bedce6 100644 --- a/drivers/misc/sgi-gru/gruprocfs.c +++ b/drivers/misc/sgi-gru/gruprocfs.c @@ -51,9 +51,12 @@ static int statistics_show(struct seq_file *s, void *p) printstat(s, assign_context); printstat(s, assign_context_failed); printstat(s, free_context); - printstat(s, load_context); - printstat(s, unload_context); - printstat(s, steal_context); + printstat(s, load_user_context); + printstat(s, load_kernel_context); + printstat(s, lock_kernel_context); + printstat(s, unlock_kernel_context); + printstat(s, steal_user_context); + printstat(s, steal_kernel_context); printstat(s, steal_context_failed); printstat(s, nopfn); printstat(s, break_cow); @@ -70,7 +73,7 @@ static int statistics_show(struct seq_file *s, void *p) printstat(s, user_flush_tlb); printstat(s, user_unload_context); printstat(s, user_exception); - printstat(s, set_task_slice); + printstat(s, set_context_option); printstat(s, migrate_check); printstat(s, migrated_retarget); printstat(s, migrated_unload); @@ -84,6 +87,9 @@ static int statistics_show(struct seq_file *s, void *p) printstat(s, tlb_dropin_fail_range_active); printstat(s, tlb_dropin_fail_idle); printstat(s, tlb_dropin_fail_fmm); + printstat(s, tlb_dropin_fail_no_exception); + printstat(s, tlb_dropin_fail_no_exception_war); + printstat(s, tfh_stale_on_fault); printstat(s, mmu_invalidate_range); printstat(s, mmu_invalidate_page); printstat(s, mmu_clear_flush_young); @@ -158,8 +164,7 @@ static ssize_t options_write(struct file *file, const char __user *userbuf, unsigned long val; char buf[80]; - if (copy_from_user - (buf, userbuf, count < sizeof(buf) ? count : sizeof(buf))) + if (strncpy_from_user(buf, userbuf, sizeof(buf) - 1) < 0) return -EFAULT; buf[count - 1] = '\0'; if (!strict_strtoul(buf, 10, &val)) diff --git a/drivers/misc/sgi-gru/grutables.h b/drivers/misc/sgi-gru/grutables.h index bf1eeb7553ed..34ab3d453919 100644 --- a/drivers/misc/sgi-gru/grutables.h +++ b/drivers/misc/sgi-gru/grutables.h @@ -148,11 +148,13 @@ #include #include #include "gru.h" +#include "grulib.h" #include "gruhandles.h" extern struct gru_stats_s gru_stats; extern struct gru_blade_state *gru_base[]; extern unsigned long gru_start_paddr, gru_end_paddr; +extern void *gru_start_vaddr; extern unsigned int gru_max_gids; #define GRU_MAX_BLADES MAX_NUMNODES @@ -174,9 +176,12 @@ struct gru_stats_s { atomic_long_t assign_context; atomic_long_t assign_context_failed; atomic_long_t free_context; - atomic_long_t load_context; - atomic_long_t unload_context; - atomic_long_t steal_context; + atomic_long_t load_user_context; + atomic_long_t load_kernel_context; + atomic_long_t lock_kernel_context; + atomic_long_t unlock_kernel_context; + atomic_long_t steal_user_context; + atomic_long_t steal_kernel_context; atomic_long_t steal_context_failed; atomic_long_t nopfn; atomic_long_t break_cow; @@ -193,7 +198,7 @@ struct gru_stats_s { atomic_long_t user_flush_tlb; atomic_long_t user_unload_context; atomic_long_t user_exception; - atomic_long_t set_task_slice; + atomic_long_t set_context_option; atomic_long_t migrate_check; atomic_long_t migrated_retarget; atomic_long_t migrated_unload; @@ -207,6 +212,9 @@ struct gru_stats_s { atomic_long_t tlb_dropin_fail_range_active; atomic_long_t tlb_dropin_fail_idle; atomic_long_t tlb_dropin_fail_fmm; + atomic_long_t tlb_dropin_fail_no_exception; + atomic_long_t tlb_dropin_fail_no_exception_war; + atomic_long_t tfh_stale_on_fault; atomic_long_t mmu_invalidate_range; atomic_long_t mmu_invalidate_page; atomic_long_t mmu_clear_flush_young; @@ -253,7 +261,6 @@ extern struct mcs_op_statistic mcs_op_statistics[mcsop_last]; #define OPT_DPRINT 1 #define OPT_STATS 2 -#define GRU_QUICKLOOK 4 #define IRQ_GRU 110 /* Starting IRQ number for interrupts */ @@ -373,6 +380,7 @@ struct gru_thread_state { required for contest */ unsigned char ts_cbr_au_count;/* Number of CBR resources required for contest */ + char ts_cch_req_slice;/* CCH packet slice */ char ts_blade; /* If >= 0, migrate context if ref from diferent blade */ char ts_force_cch_reload; @@ -380,6 +388,9 @@ struct gru_thread_state { after migration */ char ts_cbr_idx[GRU_CBR_AU];/* CBR numbers of each allocated CB */ + int ts_data_valid; /* Indicates if ts_gdata has + valid data */ + struct gts_statistics ustats; /* User statistics */ unsigned long ts_gdata[0]; /* save area for GRU data (CB, DS, CBE) */ }; @@ -452,6 +463,14 @@ struct gru_blade_state { reserved cb */ void *kernel_dsr; /* First kernel reserved DSR */ + struct rw_semaphore bs_kgts_sema; /* lock for kgts */ + struct gru_thread_state *bs_kgts; /* GTS for kernel use */ + + /* ---- the following are used for managing kernel async GRU CBRs --- */ + int bs_async_dsr_bytes; /* DSRs for async */ + int bs_async_cbrs; /* CBRs AU for async */ + struct completion *bs_async_wq; + /* ---- the following are protected by the bs_lock spinlock ---- */ spinlock_t bs_lock; /* lock used for stealing contexts */ @@ -552,6 +571,12 @@ struct gru_blade_state { /* Lock hierarchy checking enabled only in emulator */ +/* 0 = lock failed, 1 = locked */ +static inline int __trylock_handle(void *h) +{ + return !test_and_set_bit(1, h); +} + static inline void __lock_handle(void *h) { while (test_and_set_bit(1, h)) @@ -563,6 +588,11 @@ static inline void __unlock_handle(void *h) clear_bit(1, h); } +static inline int trylock_cch_handle(struct gru_context_configuration_handle *cch) +{ + return __trylock_handle(cch); +} + static inline void lock_cch_handle(struct gru_context_configuration_handle *cch) { __lock_handle(cch); @@ -584,6 +614,11 @@ static inline void unlock_tgh_handle(struct gru_tlb_global_handle *tgh) __unlock_handle(tgh); } +static inline int is_kernel_context(struct gru_thread_state *gts) +{ + return !gts->ts_mm; +} + /*----------------------------------------------------------------------------- * Function prototypes & externs */ @@ -598,24 +633,32 @@ extern struct gru_thread_state *gru_find_thread_state(struct vm_area_struct *vma, int tsid); extern struct gru_thread_state *gru_alloc_thread_state(struct vm_area_struct *vma, int tsid); +extern struct gru_state *gru_assign_gru_context(struct gru_thread_state *gts, + int blade); +extern void gru_load_context(struct gru_thread_state *gts); +extern void gru_steal_context(struct gru_thread_state *gts, int blade_id); extern void gru_unload_context(struct gru_thread_state *gts, int savestate); extern int gru_update_cch(struct gru_thread_state *gts, int force_unload); extern void gts_drop(struct gru_thread_state *gts); extern void gru_tgh_flush_init(struct gru_state *gru); -extern int gru_kservices_init(struct gru_state *gru); -extern void gru_kservices_exit(struct gru_state *gru); +extern int gru_kservices_init(void); +extern void gru_kservices_exit(void); +extern int gru_dump_chiplet_request(unsigned long arg); +extern long gru_get_gseg_statistics(unsigned long arg); extern irqreturn_t gru_intr(int irq, void *dev_id); extern int gru_handle_user_call_os(unsigned long address); extern int gru_user_flush_tlb(unsigned long arg); extern int gru_user_unload_context(unsigned long arg); extern int gru_get_exception_detail(unsigned long arg); -extern int gru_set_task_slice(long address); +extern int gru_set_context_option(unsigned long address); extern int gru_cpu_fault_map_id(void); extern struct vm_area_struct *gru_find_vma(unsigned long vaddr); extern void gru_flush_all_tlb(struct gru_state *gru); extern int gru_proc_init(void); extern void gru_proc_exit(void); +extern struct gru_thread_state *gru_alloc_gts(struct vm_area_struct *vma, + int cbr_au_count, int dsr_au_count, int options, int tsid); extern unsigned long gru_reserve_cb_resources(struct gru_state *gru, int cbr_au_count, char *cbmap); extern unsigned long gru_reserve_ds_resources(struct gru_state *gru, @@ -624,6 +667,7 @@ extern int gru_fault(struct vm_area_struct *, struct vm_fault *vmf); extern struct gru_mm_struct *gru_register_mmu_notifier(void); extern void gru_drop_mmu_notifier(struct gru_mm_struct *gms); +extern int gru_ktest(unsigned long arg); extern void gru_flush_tlb_range(struct gru_mm_struct *gms, unsigned long start, unsigned long len); diff --git a/drivers/misc/sgi-xp/xpc_uv.c b/drivers/misc/sgi-xp/xpc_uv.c index 9172fcdee4e2..c76677afda1b 100644 --- a/drivers/misc/sgi-xp/xpc_uv.c +++ b/drivers/misc/sgi-xp/xpc_uv.c @@ -232,7 +232,7 @@ xpc_create_gru_mq_uv(unsigned int mq_size, int cpu, char *irq_name, mq->mmr_blade = uv_cpu_to_blade_id(cpu); nid = cpu_to_node(cpu); - page = alloc_pages_node(nid, GFP_KERNEL | __GFP_ZERO | GFP_THISNODE, + page = alloc_pages_exact_node(nid, GFP_KERNEL | __GFP_ZERO | GFP_THISNODE, pg_order); if (page == NULL) { dev_err(xpc_part, "xpc_create_gru_mq_uv() failed to alloc %d " diff --git a/drivers/misc/sgi-xp/xpnet.c b/drivers/misc/sgi-xp/xpnet.c index 6faefcffcb53..8d1c60a3f0df 100644 --- a/drivers/misc/sgi-xp/xpnet.c +++ b/drivers/misc/sgi-xp/xpnet.c @@ -450,7 +450,8 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) "packet\n", sizeof(struct xpnet_pending_msg)); dev->stats.tx_errors++; - return -ENOMEM; + dev_kfree_skb(skb); + return NETDEV_TX_OK; } /* get the beginning of the first cacheline and end of last */ diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index b25e9b6516ae..adc205c49fbf 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -147,7 +147,8 @@ struct mmc_blk_request { static u32 mmc_sd_num_wr_blocks(struct mmc_card *card) { int err; - __be32 blocks; + u32 result; + __be32 *blocks; struct mmc_request mrq; struct mmc_command cmd; @@ -199,14 +200,21 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card) mrq.cmd = &cmd; mrq.data = &data; - sg_init_one(&sg, &blocks, 4); + blocks = kmalloc(4, GFP_KERNEL); + if (!blocks) + return (u32)-1; + + sg_init_one(&sg, blocks, 4); mmc_wait_for_req(card->host, &mrq); - if (cmd.error || data.error) - return (u32)-1; + result = ntohl(*blocks); + kfree(blocks); - return ntohl(blocks); + if (cmd.error || data.error) + result = (u32)-1; + + return result; } static u32 get_card_status(struct mmc_card *card, struct request *req) @@ -243,7 +251,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) brq.mrq.cmd = &brq.cmd; brq.mrq.data = &brq.data; - brq.cmd.arg = req->sector; + brq.cmd.arg = blk_rq_pos(req); if (!mmc_card_blockaddr(card)) brq.cmd.arg <<= 9; brq.cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; @@ -251,7 +259,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) brq.stop.opcode = MMC_STOP_TRANSMISSION; brq.stop.arg = 0; brq.stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC; - brq.data.blocks = req->nr_sectors; + brq.data.blocks = blk_rq_sectors(req); /* * The block layer doesn't support all sector count @@ -301,7 +309,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) * Adjust the sg list so it is the same size as the * request. */ - if (brq.data.blocks != req->nr_sectors) { + if (brq.data.blocks != blk_rq_sectors(req)) { int i, data_size = brq.data.blocks << 9; struct scatterlist *sg; @@ -352,8 +360,8 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) printk(KERN_ERR "%s: error %d transferring data," " sector %u, nr %u, card status %#x\n", req->rq_disk->disk_name, brq.data.error, - (unsigned)req->sector, - (unsigned)req->nr_sectors, status); + (unsigned)blk_rq_pos(req), + (unsigned)blk_rq_sectors(req), status); } if (brq.stop.error) { @@ -521,7 +529,7 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card) sprintf(md->disk->disk_name, "mmcblk%d", devidx); - blk_queue_hardsect_size(md->queue.queue, 512); + blk_queue_logical_block_size(md->queue.queue, 512); if (!mmc_card_sd(card) && mmc_card_blockaddr(card)) { /* diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c index 7a72e75d5c67..49e582356c65 100644 --- a/drivers/mmc/card/queue.c +++ b/drivers/mmc/card/queue.c @@ -55,7 +55,7 @@ static int mmc_queue_thread(void *d) spin_lock_irq(q->queue_lock); set_current_state(TASK_INTERRUPTIBLE); if (!blk_queue_plugged(q)) - req = elv_next_request(q); + req = blk_fetch_request(q); mq->req = req; spin_unlock_irq(q->queue_lock); @@ -88,16 +88,11 @@ static void mmc_request(struct request_queue *q) { struct mmc_queue *mq = q->queuedata; struct request *req; - int ret; if (!mq) { printk(KERN_ERR "MMC: killing requests for dead queue\n"); - while ((req = elv_next_request(q)) != NULL) { - do { - ret = __blk_end_request(req, -EIO, - blk_rq_cur_bytes(req)); - } while (ret); - } + while ((req = blk_fetch_request(q)) != NULL) + __blk_end_request_all(req, -EIO); return; } diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 264911732756..d84c880fac84 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -708,7 +708,13 @@ static void mmc_power_up(struct mmc_host *host) */ mmc_delay(10); - host->ios.clock = host->f_min; + if (host->f_min > 400000) { + pr_warning("%s: Minimum clock frequency too high for " + "identification mode\n", mmc_hostname(host)); + host->ios.clock = host->f_min; + } else + host->ios.clock = 400000; + host->ios.power_mode = MMC_POWER_ON; mmc_set_ios(host); @@ -855,61 +861,72 @@ void mmc_rescan(struct work_struct *work) mmc_bus_get(host); - if (host->bus_ops == NULL) { - /* - * Only we can add a new handler, so it's safe to - * release the lock here. - */ - mmc_bus_put(host); - - if (host->ops->get_cd && host->ops->get_cd(host) == 0) - goto out; - - mmc_claim_host(host); - - mmc_power_up(host); - mmc_go_idle(host); - - mmc_send_if_cond(host, host->ocr_avail); - - /* - * First we search for SDIO... - */ - err = mmc_send_io_op_cond(host, 0, &ocr); - if (!err) { - if (mmc_attach_sdio(host, ocr)) - mmc_power_off(host); - goto out; - } - - /* - * ...then normal SD... - */ - err = mmc_send_app_op_cond(host, 0, &ocr); - if (!err) { - if (mmc_attach_sd(host, ocr)) - mmc_power_off(host); - goto out; - } - - /* - * ...and finally MMC. - */ - err = mmc_send_op_cond(host, 0, &ocr); - if (!err) { - if (mmc_attach_mmc(host, ocr)) - mmc_power_off(host); - goto out; - } - - mmc_release_host(host); - mmc_power_off(host); - } else { - if (host->bus_ops->detect && !host->bus_dead) - host->bus_ops->detect(host); - + /* if there is a card registered, check whether it is still present */ + if ((host->bus_ops != NULL) && host->bus_ops->detect && !host->bus_dead) + host->bus_ops->detect(host); + + mmc_bus_put(host); + + + mmc_bus_get(host); + + /* if there still is a card present, stop here */ + if (host->bus_ops != NULL) { mmc_bus_put(host); + goto out; } + + /* detect a newly inserted card */ + + /* + * Only we can add a new handler, so it's safe to + * release the lock here. + */ + mmc_bus_put(host); + + if (host->ops->get_cd && host->ops->get_cd(host) == 0) + goto out; + + mmc_claim_host(host); + + mmc_power_up(host); + mmc_go_idle(host); + + mmc_send_if_cond(host, host->ocr_avail); + + /* + * First we search for SDIO... + */ + err = mmc_send_io_op_cond(host, 0, &ocr); + if (!err) { + if (mmc_attach_sdio(host, ocr)) + mmc_power_off(host); + goto out; + } + + /* + * ...then normal SD... + */ + err = mmc_send_app_op_cond(host, 0, &ocr); + if (!err) { + if (mmc_attach_sd(host, ocr)) + mmc_power_off(host); + goto out; + } + + /* + * ...and finally MMC. + */ + err = mmc_send_op_cond(host, 0, &ocr); + if (!err) { + if (mmc_attach_mmc(host, ocr)) + mmc_power_off(host); + goto out; + } + + mmc_release_host(host); + mmc_power_off(host); + out: if (host->caps & MMC_CAP_NEEDS_POLL) mmc_schedule_delayed_work(&host->detect, HZ); diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index b4cf691f3f64..891ef18bd77b 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -83,6 +83,42 @@ config MMC_SDHCI_OF If unsure, say N. +config MMC_SDHCI_PLTFM + tristate "SDHCI support on the platform specific bus" + depends on MMC_SDHCI + help + This selects the platform specific bus support for Secure Digital Host + Controller Interface. + + If you have a controller with this interface, say Y or M here. + + If unsure, say N. + +config MMC_SDHCI_S3C + tristate "SDHCI support on Samsung S3C SoC" + depends on MMC_SDHCI && (PLAT_S3C24XX || PLAT_S3C64XX) + help + This selects the Secure Digital Host Controller Interface (SDHCI) + often referrered to as the HSMMC block in some of the Samsung S3C + range of SoC. + + Note, due to the problems with DMA, the DMA support is only + available with CONFIG_EXPERIMENTAL is selected. + + If you have a controller with this interface, say Y or M here. + + If unsure, say N. + +config MMC_SDHCI_S3C_DMA + bool "DMA support on S3C SDHCI" + depends on MMC_SDHCI_S3C && EXPERIMENTAL + help + Enable DMA support on the Samsung S3C SDHCI glue. The DMA + has proved to be problematic if the controller encounters + certain errors, and thus should be treated with care. + + YMMV. + config MMC_OMAP tristate "TI OMAP Multimedia Card Interface support" depends on ARCH_OMAP @@ -155,7 +191,7 @@ config MMC_ATMELMCI_DMA config MMC_IMX tristate "Motorola i.MX Multimedia Card Interface support" - depends on ARCH_IMX + depends on ARCH_MX1 help This selects the Motorola i.MX Multimedia card Interface. If you have a i.MX platform with a Multimedia Card slot, @@ -237,7 +273,31 @@ config MMC_SDRICOH_CS config MMC_TMIO tristate "Toshiba Mobile IO Controller (TMIO) MMC/SD function support" - depends on MFD_TMIO + depends on MFD_TMIO || MFD_ASIC3 help This provides support for the SD/MMC cell found in TC6393XB, - T7L66XB and also ipaq ASIC3 + T7L66XB and also HTC ASIC3 + +config MMC_CB710 + tristate "ENE CB710 MMC/SD Interface support" + depends on PCI + select CB710_CORE + help + This option enables support for MMC/SD part of ENE CB710/720 Flash + memory card reader found in some laptops (ie. some versions of + HP Compaq nx9500). + + This driver can also be built as a module. If so, the module + will be called cb710-mmc. + +config MMC_VIA_SDMMC + tristate "VIA SD/MMC Card Reader Driver" + depends on PCI + help + This selects the VIA SD/MMC Card Reader driver, say Y or M here. + VIA provides one multi-functional card reader which integrated into + some motherboards manufactured by VIA. This card reader supports + SD/MMC/SDHC. + If you have a controller with this interface, say Y or M here. + + If unsure, say N. diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index 970a997620e1..cf153f628457 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -14,6 +14,8 @@ obj-$(CONFIG_MMC_SDHCI) += sdhci.o obj-$(CONFIG_MMC_SDHCI_PCI) += sdhci-pci.o obj-$(CONFIG_MMC_RICOH_MMC) += ricoh_mmc.o obj-$(CONFIG_MMC_SDHCI_OF) += sdhci-of.o +obj-$(CONFIG_MMC_SDHCI_PLTFM) += sdhci-pltfm.o +obj-$(CONFIG_MMC_SDHCI_S3C) += sdhci-s3c.o obj-$(CONFIG_MMC_WBSD) += wbsd.o obj-$(CONFIG_MMC_AU1X) += au1xmmc.o obj-$(CONFIG_MMC_OMAP) += omap.o @@ -29,4 +31,9 @@ endif obj-$(CONFIG_MMC_S3C) += s3cmci.o obj-$(CONFIG_MMC_SDRICOH_CS) += sdricoh_cs.o obj-$(CONFIG_MMC_TMIO) += tmio_mmc.o +obj-$(CONFIG_MMC_CB710) += cb710-mmc.o +obj-$(CONFIG_MMC_VIA_SDMMC) += via-sdmmc.o +ifeq ($(CONFIG_CB710_DEBUG),y) + CFLAGS-cb710-mmc += -DDEBUG +endif diff --git a/drivers/mmc/host/atmel-mci-regs.h b/drivers/mmc/host/atmel-mci-regs.h index b58364ed6bba..fc8a0fe7c5c5 100644 --- a/drivers/mmc/host/atmel-mci-regs.h +++ b/drivers/mmc/host/atmel-mci-regs.h @@ -7,6 +7,12 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ + +/* + * Superset of MCI IP registers integrated in Atmel AVR32 and AT91 Processors + * Registers and bitfields marked with [2] are only available in MCI2 + */ + #ifndef __DRIVERS_MMC_ATMEL_MCI_H__ #define __DRIVERS_MMC_ATMEL_MCI_H__ @@ -14,11 +20,17 @@ #define MCI_CR 0x0000 /* Control */ # define MCI_CR_MCIEN ( 1 << 0) /* MCI Enable */ # define MCI_CR_MCIDIS ( 1 << 1) /* MCI Disable */ +# define MCI_CR_PWSEN ( 1 << 2) /* Power Save Enable */ +# define MCI_CR_PWSDIS ( 1 << 3) /* Power Save Disable */ # define MCI_CR_SWRST ( 1 << 7) /* Software Reset */ #define MCI_MR 0x0004 /* Mode */ # define MCI_MR_CLKDIV(x) ((x) << 0) /* Clock Divider */ +# define MCI_MR_PWSDIV(x) ((x) << 8) /* Power Saving Divider */ # define MCI_MR_RDPROOF ( 1 << 11) /* Read Proof */ # define MCI_MR_WRPROOF ( 1 << 12) /* Write Proof */ +# define MCI_MR_PDCFBYTE ( 1 << 13) /* Force Byte Transfer */ +# define MCI_MR_PDCPADV ( 1 << 14) /* Padding Value */ +# define MCI_MR_PDCMODE ( 1 << 15) /* PDC-oriented Mode */ #define MCI_DTOR 0x0008 /* Data Timeout */ # define MCI_DTOCYC(x) ((x) << 0) /* Data Timeout Cycles */ # define MCI_DTOMUL(x) ((x) << 4) /* Data Timeout Multiplier */ @@ -28,6 +40,7 @@ # define MCI_SDCSEL_MASK ( 3 << 0) # define MCI_SDCBUS_1BIT ( 0 << 6) /* 1-bit data bus */ # define MCI_SDCBUS_4BIT ( 2 << 6) /* 4-bit data bus */ +# define MCI_SDCBUS_8BIT ( 3 << 6) /* 8-bit data bus[2] */ # define MCI_SDCBUS_MASK ( 3 << 6) #define MCI_ARGR 0x0010 /* Command Argument */ #define MCI_CMDR 0x0014 /* Command */ @@ -56,6 +69,9 @@ #define MCI_BLKR 0x0018 /* Block */ # define MCI_BCNT(x) ((x) << 0) /* Data Block Count */ # define MCI_BLKLEN(x) ((x) << 16) /* Data Block Length */ +#define MCI_CSTOR 0x001c /* Completion Signal Timeout[2] */ +# define MCI_CSTOCYC(x) ((x) << 0) /* CST cycles */ +# define MCI_CSTOMUL(x) ((x) << 4) /* CST multiplier */ #define MCI_RSPR 0x0020 /* Response 0 */ #define MCI_RSPR1 0x0024 /* Response 1 */ #define MCI_RSPR2 0x0028 /* Response 2 */ @@ -83,7 +99,24 @@ # define MCI_DTOE ( 1 << 22) /* Data Time-Out Error */ # define MCI_OVRE ( 1 << 30) /* RX Overrun Error */ # define MCI_UNRE ( 1 << 31) /* TX Underrun Error */ +#define MCI_DMA 0x0050 /* DMA Configuration[2] */ +# define MCI_DMA_OFFSET(x) ((x) << 0) /* DMA Write Buffer Offset */ +# define MCI_DMA_CHKSIZE(x) ((x) << 4) /* DMA Channel Read and Write Chunk Size */ +# define MCI_DMAEN ( 1 << 8) /* DMA Hardware Handshaking Enable */ +#define MCI_CFG 0x0054 /* Configuration[2] */ +# define MCI_CFG_FIFOMODE_1DATA ( 1 << 0) /* MCI Internal FIFO control mode */ +# define MCI_CFG_FERRCTRL_COR ( 1 << 4) /* Flow Error flag reset control mode */ +# define MCI_CFG_HSMODE ( 1 << 8) /* High Speed Mode */ +# define MCI_CFG_LSYNC ( 1 << 12) /* Synchronize on the last block */ +#define MCI_WPMR 0x00e4 /* Write Protection Mode[2] */ +# define MCI_WP_EN ( 1 << 0) /* WP Enable */ +# define MCI_WP_KEY (0x4d4349 << 8) /* WP Key */ +#define MCI_WPSR 0x00e8 /* Write Protection Status[2] */ +# define MCI_GET_WP_VS(x) ((x) & 0x0f) +# define MCI_GET_WP_VSRC(x) (((x) >> 8) & 0xffff) +#define MCI_FIFO_APERTURE 0x0200 /* FIFO Aperture[2] */ +/* This is not including the FIFO Aperture on MCI2 */ #define MCI_REGS_SIZE 0x100 /* Register access macros */ diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index cf6a100bb38f..5e10d3663ab5 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -177,6 +177,7 @@ struct atmel_mci { * available. * @wp_pin: GPIO pin used for card write protect sending, or negative * if not available. + * @detect_is_active_high: The state of the detect pin when it is active. * @detect_timer: Timer used for debouncing @detect_pin interrupts. */ struct atmel_mci_slot { @@ -196,6 +197,7 @@ struct atmel_mci_slot { int detect_pin; int wp_pin; + bool detect_is_active_high; struct timer_list detect_timer; }; @@ -574,6 +576,7 @@ atmci_submit_data_dma(struct atmel_mci *host, struct mmc_data *data) struct scatterlist *sg; unsigned int i; enum dma_data_direction direction; + unsigned int sglen; /* * We don't do DMA on "complex" transfers, i.e. with @@ -603,11 +606,14 @@ atmci_submit_data_dma(struct atmel_mci *host, struct mmc_data *data) else direction = DMA_TO_DEVICE; + sglen = dma_map_sg(&host->pdev->dev, data->sg, data->sg_len, direction); + if (sglen != data->sg_len) + goto unmap_exit; desc = chan->device->device_prep_slave_sg(chan, data->sg, data->sg_len, direction, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc) - return -ENOMEM; + goto unmap_exit; host->dma.data_desc = desc; desc->callback = atmci_dma_complete; @@ -618,6 +624,9 @@ atmci_submit_data_dma(struct atmel_mci *host, struct mmc_data *data) chan->device->device_issue_pending(chan); return 0; +unmap_exit: + dma_unmap_sg(&host->pdev->dev, data->sg, sglen, direction); + return -ENOMEM; } #else /* CONFIG_MMC_ATMELMCI_DMA */ @@ -924,7 +933,8 @@ static int atmci_get_cd(struct mmc_host *mmc) struct atmel_mci_slot *slot = mmc_priv(mmc); if (gpio_is_valid(slot->detect_pin)) { - present = !gpio_get_value(slot->detect_pin); + present = !(gpio_get_value(slot->detect_pin) ^ + slot->detect_is_active_high); dev_dbg(&mmc->class_dev, "card is %spresent\n", present ? "" : "not "); } @@ -1028,7 +1038,8 @@ static void atmci_detect_change(unsigned long data) return; enable_irq(gpio_to_irq(slot->detect_pin)); - present = !gpio_get_value(slot->detect_pin); + present = !(gpio_get_value(slot->detect_pin) ^ + slot->detect_is_active_high); present_old = test_bit(ATMCI_CARD_PRESENT, &slot->flags); dev_vdbg(&slot->mmc->class_dev, "detect change: %d (was %d)\n", @@ -1456,6 +1467,7 @@ static int __init atmci_init_slot(struct atmel_mci *host, slot->host = host; slot->detect_pin = slot_data->detect_pin; slot->wp_pin = slot_data->wp_pin; + slot->detect_is_active_high = slot_data->detect_is_active_high; slot->sdc_reg = sdc_reg; mmc->ops = &atmci_ops; @@ -1477,7 +1489,8 @@ static int __init atmci_init_slot(struct atmel_mci *host, if (gpio_request(slot->detect_pin, "mmc_detect")) { dev_dbg(&mmc->class_dev, "no detect pin available\n"); slot->detect_pin = -EBUSY; - } else if (gpio_get_value(slot->detect_pin)) { + } else if (gpio_get_value(slot->detect_pin) ^ + slot->detect_is_active_high) { clear_bit(ATMCI_CARD_PRESENT, &slot->flags); } } diff --git a/drivers/mmc/host/cb710-mmc.c b/drivers/mmc/host/cb710-mmc.c new file mode 100644 index 000000000000..11efefb1af51 --- /dev/null +++ b/drivers/mmc/host/cb710-mmc.c @@ -0,0 +1,804 @@ +/* + * cb710/mmc.c + * + * Copyright by MichaÅ‚ MirosÅ‚aw, 2008-2009 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include "cb710-mmc.h" + +static const u8 cb710_clock_divider_log2[8] = { +/* 1, 2, 4, 8, 16, 32, 128, 512 */ + 0, 1, 2, 3, 4, 5, 7, 9 +}; +#define CB710_MAX_DIVIDER_IDX \ + (ARRAY_SIZE(cb710_clock_divider_log2) - 1) + +static const u8 cb710_src_freq_mhz[16] = { + 33, 10, 20, 25, 30, 35, 40, 45, + 50, 55, 60, 65, 70, 75, 80, 85 +}; + +static void cb710_mmc_set_clock(struct mmc_host *mmc, int hz) +{ + struct cb710_slot *slot = cb710_mmc_to_slot(mmc); + struct pci_dev *pdev = cb710_slot_to_chip(slot)->pdev; + u32 src_freq_idx; + u32 divider_idx; + int src_hz; + + /* this is magic, unverifiable for me, unless I get + * MMC card with cables connected to bus signals */ + pci_read_config_dword(pdev, 0x48, &src_freq_idx); + src_freq_idx = (src_freq_idx >> 16) & 0xF; + src_hz = cb710_src_freq_mhz[src_freq_idx] * 1000000; + + for (divider_idx = 0; divider_idx < CB710_MAX_DIVIDER_IDX; ++divider_idx) { + if (hz >= src_hz >> cb710_clock_divider_log2[divider_idx]) + break; + } + + if (src_freq_idx) + divider_idx |= 0x8; + + cb710_pci_update_config_reg(pdev, 0x40, ~0xF0000000, divider_idx << 28); + + dev_dbg(cb710_slot_dev(slot), + "clock set to %d Hz, wanted %d Hz; flag = %d\n", + src_hz >> cb710_clock_divider_log2[divider_idx & 7], + hz, (divider_idx & 8) != 0); +} + +static void __cb710_mmc_enable_irq(struct cb710_slot *slot, + unsigned short enable, unsigned short mask) +{ + /* clear global IE + * - it gets set later if any interrupt sources are enabled */ + mask |= CB710_MMC_IE_IRQ_ENABLE; + + /* look like interrupt is fired whenever + * WORD[0x0C] & WORD[0x10] != 0; + * -> bit 15 port 0x0C seems to be global interrupt enable + */ + + enable = (cb710_read_port_16(slot, CB710_MMC_IRQ_ENABLE_PORT) + & ~mask) | enable; + + if (enable) + enable |= CB710_MMC_IE_IRQ_ENABLE; + + cb710_write_port_16(slot, CB710_MMC_IRQ_ENABLE_PORT, enable); +} + +static void cb710_mmc_enable_irq(struct cb710_slot *slot, + unsigned short enable, unsigned short mask) +{ + struct cb710_mmc_reader *reader = mmc_priv(cb710_slot_to_mmc(slot)); + unsigned long flags; + + spin_lock_irqsave(&reader->irq_lock, flags); + /* this is the only thing irq_lock protects */ + __cb710_mmc_enable_irq(slot, enable, mask); + spin_unlock_irqrestore(&reader->irq_lock, flags); +} + +static void cb710_mmc_reset_events(struct cb710_slot *slot) +{ + cb710_write_port_8(slot, CB710_MMC_STATUS0_PORT, 0xFF); + cb710_write_port_8(slot, CB710_MMC_STATUS1_PORT, 0xFF); + cb710_write_port_8(slot, CB710_MMC_STATUS2_PORT, 0xFF); +} + +static int cb710_mmc_is_card_inserted(struct cb710_slot *slot) +{ + return cb710_read_port_8(slot, CB710_MMC_STATUS3_PORT) + & CB710_MMC_S3_CARD_DETECTED; +} + +static void cb710_mmc_enable_4bit_data(struct cb710_slot *slot, int enable) +{ + dev_dbg(cb710_slot_dev(slot), "configuring %d-data-line%s mode\n", + enable ? 4 : 1, enable ? "s" : ""); + if (enable) + cb710_modify_port_8(slot, CB710_MMC_CONFIG1_PORT, + CB710_MMC_C1_4BIT_DATA_BUS, 0); + else + cb710_modify_port_8(slot, CB710_MMC_CONFIG1_PORT, + 0, CB710_MMC_C1_4BIT_DATA_BUS); +} + +static int cb710_check_event(struct cb710_slot *slot, u8 what) +{ + u16 status; + + status = cb710_read_port_16(slot, CB710_MMC_STATUS_PORT); + + if (status & CB710_MMC_S0_FIFO_UNDERFLOW) { + /* it is just a guess, so log it */ + dev_dbg(cb710_slot_dev(slot), + "CHECK : ignoring bit 6 in status %04X\n", status); + cb710_write_port_8(slot, CB710_MMC_STATUS0_PORT, + CB710_MMC_S0_FIFO_UNDERFLOW); + status &= ~CB710_MMC_S0_FIFO_UNDERFLOW; + } + + if (status & CB710_MMC_STATUS_ERROR_EVENTS) { + dev_dbg(cb710_slot_dev(slot), + "CHECK : returning EIO on status %04X\n", status); + cb710_write_port_8(slot, CB710_MMC_STATUS0_PORT, status & 0xFF); + cb710_write_port_8(slot, CB710_MMC_STATUS1_PORT, + CB710_MMC_S1_RESET); + return -EIO; + } + + /* 'what' is a bit in MMC_STATUS1 */ + if ((status >> 8) & what) { + cb710_write_port_8(slot, CB710_MMC_STATUS1_PORT, what); + return 1; + } + + return 0; +} + +static int cb710_wait_for_event(struct cb710_slot *slot, u8 what) +{ + int err = 0; + unsigned limit = 2000000; /* FIXME: real timeout */ + +#ifdef CONFIG_CB710_DEBUG + u32 e, x; + e = cb710_read_port_32(slot, CB710_MMC_STATUS_PORT); +#endif + + while (!(err = cb710_check_event(slot, what))) { + if (!--limit) { + cb710_dump_regs(cb710_slot_to_chip(slot), + CB710_DUMP_REGS_MMC); + err = -ETIMEDOUT; + break; + } + udelay(1); + } + +#ifdef CONFIG_CB710_DEBUG + x = cb710_read_port_32(slot, CB710_MMC_STATUS_PORT); + + limit = 2000000 - limit; + if (limit > 100) + dev_dbg(cb710_slot_dev(slot), + "WAIT10: waited %d loops, what %d, entry val %08X, exit val %08X\n", + limit, what, e, x); +#endif + return err < 0 ? err : 0; +} + + +static int cb710_wait_while_busy(struct cb710_slot *slot, uint8_t mask) +{ + unsigned limit = 500000; /* FIXME: real timeout */ + int err = 0; + +#ifdef CONFIG_CB710_DEBUG + u32 e, x; + e = cb710_read_port_32(slot, CB710_MMC_STATUS_PORT); +#endif + + while (cb710_read_port_8(slot, CB710_MMC_STATUS2_PORT) & mask) { + if (!--limit) { + cb710_dump_regs(cb710_slot_to_chip(slot), + CB710_DUMP_REGS_MMC); + err = -ETIMEDOUT; + break; + } + udelay(1); + } + +#ifdef CONFIG_CB710_DEBUG + x = cb710_read_port_32(slot, CB710_MMC_STATUS_PORT); + + limit = 500000 - limit; + if (limit > 100) + dev_dbg(cb710_slot_dev(slot), + "WAIT12: waited %d loops, mask %02X, entry val %08X, exit val %08X\n", + limit, mask, e, x); +#endif + return 0; +} + +static void cb710_mmc_set_transfer_size(struct cb710_slot *slot, + size_t count, size_t blocksize) +{ + cb710_wait_while_busy(slot, CB710_MMC_S2_BUSY_20); + cb710_write_port_32(slot, CB710_MMC_TRANSFER_SIZE_PORT, + ((count - 1) << 16)|(blocksize - 1)); + + dev_vdbg(cb710_slot_dev(slot), "set up for %zu block%s of %zu bytes\n", + count, count == 1 ? "" : "s", blocksize); +} + +static void cb710_mmc_fifo_hack(struct cb710_slot *slot) +{ + /* without this, received data is prepended with 8-bytes of zeroes */ + u32 r1, r2; + int ok = 0; + + r1 = cb710_read_port_32(slot, CB710_MMC_DATA_PORT); + r2 = cb710_read_port_32(slot, CB710_MMC_DATA_PORT); + if (cb710_read_port_8(slot, CB710_MMC_STATUS0_PORT) + & CB710_MMC_S0_FIFO_UNDERFLOW) { + cb710_write_port_8(slot, CB710_MMC_STATUS0_PORT, + CB710_MMC_S0_FIFO_UNDERFLOW); + ok = 1; + } + + dev_dbg(cb710_slot_dev(slot), + "FIFO-read-hack: expected STATUS0 bit was %s\n", + ok ? "set." : "NOT SET!"); + dev_dbg(cb710_slot_dev(slot), + "FIFO-read-hack: dwords ignored: %08X %08X - %s\n", + r1, r2, (r1|r2) ? "BAD (NOT ZERO)!" : "ok"); +} + +static int cb710_mmc_receive_pio(struct cb710_slot *slot, + struct sg_mapping_iter *miter, size_t dw_count) +{ + if (!(cb710_read_port_8(slot, CB710_MMC_STATUS2_PORT) & CB710_MMC_S2_FIFO_READY)) { + int err = cb710_wait_for_event(slot, + CB710_MMC_S1_PIO_TRANSFER_DONE); + if (err) + return err; + } + + cb710_sg_dwiter_write_from_io(miter, + slot->iobase + CB710_MMC_DATA_PORT, dw_count); + + return 0; +} + +static bool cb710_is_transfer_size_supported(struct mmc_data *data) +{ + return !(data->blksz & 15 && (data->blocks != 1 || data->blksz != 8)); +} + +static int cb710_mmc_receive(struct cb710_slot *slot, struct mmc_data *data) +{ + struct sg_mapping_iter miter; + size_t len, blocks = data->blocks; + int err = 0; + + /* TODO: I don't know how/if the hardware handles non-16B-boundary blocks + * except single 8B block */ + if (unlikely(data->blksz & 15 && (data->blocks != 1 || data->blksz != 8))) + return -EINVAL; + + sg_miter_start(&miter, data->sg, data->sg_len, 0); + + cb710_modify_port_8(slot, CB710_MMC_CONFIG2_PORT, + 15, CB710_MMC_C2_READ_PIO_SIZE_MASK); + + cb710_mmc_fifo_hack(slot); + + while (blocks-- > 0) { + len = data->blksz; + + while (len >= 16) { + err = cb710_mmc_receive_pio(slot, &miter, 4); + if (err) + goto out; + len -= 16; + } + + if (!len) + continue; + + cb710_modify_port_8(slot, CB710_MMC_CONFIG2_PORT, + len - 1, CB710_MMC_C2_READ_PIO_SIZE_MASK); + + len = (len >= 8) ? 4 : 2; + err = cb710_mmc_receive_pio(slot, &miter, len); + if (err) + goto out; + } +out: + cb710_sg_miter_stop_writing(&miter); + return err; +} + +static int cb710_mmc_send(struct cb710_slot *slot, struct mmc_data *data) +{ + struct sg_mapping_iter miter; + size_t len, blocks = data->blocks; + int err = 0; + + /* TODO: I don't know how/if the hardware handles multiple + * non-16B-boundary blocks */ + if (unlikely(data->blocks > 1 && data->blksz & 15)) + return -EINVAL; + + sg_miter_start(&miter, data->sg, data->sg_len, 0); + + cb710_modify_port_8(slot, CB710_MMC_CONFIG2_PORT, + 0, CB710_MMC_C2_READ_PIO_SIZE_MASK); + + while (blocks-- > 0) { + len = (data->blksz + 15) >> 4; + do { + if (!(cb710_read_port_8(slot, CB710_MMC_STATUS2_PORT) + & CB710_MMC_S2_FIFO_EMPTY)) { + err = cb710_wait_for_event(slot, + CB710_MMC_S1_PIO_TRANSFER_DONE); + if (err) + goto out; + } + cb710_sg_dwiter_read_to_io(&miter, + slot->iobase + CB710_MMC_DATA_PORT, 4); + } while (--len); + } +out: + sg_miter_stop(&miter); + return err; +} + +static u16 cb710_encode_cmd_flags(struct cb710_mmc_reader *reader, + struct mmc_command *cmd) +{ + unsigned int flags = cmd->flags; + u16 cb_flags = 0; + + /* Windows driver returned 0 for commands for which no response + * is expected. It happened that there were only two such commands + * used: MMC_GO_IDLE_STATE and MMC_GO_INACTIVE_STATE so it might + * as well be a bug in that driver. + * + * Original driver set bit 14 for MMC/SD application + * commands. There's no difference 'on the wire' and + * it apparently works without it anyway. + */ + + switch (flags & MMC_CMD_MASK) { + case MMC_CMD_AC: cb_flags = CB710_MMC_CMD_AC; break; + case MMC_CMD_ADTC: cb_flags = CB710_MMC_CMD_ADTC; break; + case MMC_CMD_BC: cb_flags = CB710_MMC_CMD_BC; break; + case MMC_CMD_BCR: cb_flags = CB710_MMC_CMD_BCR; break; + } + + if (flags & MMC_RSP_BUSY) + cb_flags |= CB710_MMC_RSP_BUSY; + + cb_flags |= cmd->opcode << CB710_MMC_CMD_CODE_SHIFT; + + if (cmd->data && (cmd->data->flags & MMC_DATA_READ)) + cb_flags |= CB710_MMC_DATA_READ; + + if (flags & MMC_RSP_PRESENT) { + /* Windows driver set 01 at bits 4,3 except for + * MMC_SET_BLOCKLEN where it set 10. Maybe the + * hardware can do something special about this + * command? The original driver looks buggy/incomplete + * anyway so we ignore this for now. + * + * I assume that 00 here means no response is expected. + */ + cb_flags |= CB710_MMC_RSP_PRESENT; + + if (flags & MMC_RSP_136) + cb_flags |= CB710_MMC_RSP_136; + if (!(flags & MMC_RSP_CRC)) + cb_flags |= CB710_MMC_RSP_NO_CRC; + } + + return cb_flags; +} + +static void cb710_receive_response(struct cb710_slot *slot, + struct mmc_command *cmd) +{ + unsigned rsp_opcode, wanted_opcode; + + /* Looks like final byte with CRC is always stripped (same as SDHCI) */ + if (cmd->flags & MMC_RSP_136) { + u32 resp[4]; + + resp[0] = cb710_read_port_32(slot, CB710_MMC_RESPONSE3_PORT); + resp[1] = cb710_read_port_32(slot, CB710_MMC_RESPONSE2_PORT); + resp[2] = cb710_read_port_32(slot, CB710_MMC_RESPONSE1_PORT); + resp[3] = cb710_read_port_32(slot, CB710_MMC_RESPONSE0_PORT); + rsp_opcode = resp[0] >> 24; + + cmd->resp[0] = (resp[0] << 8)|(resp[1] >> 24); + cmd->resp[1] = (resp[1] << 8)|(resp[2] >> 24); + cmd->resp[2] = (resp[2] << 8)|(resp[3] >> 24); + cmd->resp[3] = (resp[3] << 8); + } else { + rsp_opcode = cb710_read_port_32(slot, CB710_MMC_RESPONSE1_PORT) & 0x3F; + cmd->resp[0] = cb710_read_port_32(slot, CB710_MMC_RESPONSE0_PORT); + } + + wanted_opcode = (cmd->flags & MMC_RSP_OPCODE) ? cmd->opcode : 0x3F; + if (rsp_opcode != wanted_opcode) + cmd->error = -EILSEQ; +} + +static int cb710_mmc_transfer_data(struct cb710_slot *slot, + struct mmc_data *data) +{ + int error, to; + + if (data->flags & MMC_DATA_READ) + error = cb710_mmc_receive(slot, data); + else + error = cb710_mmc_send(slot, data); + + to = cb710_wait_for_event(slot, CB710_MMC_S1_DATA_TRANSFER_DONE); + if (!error) + error = to; + + if (!error) + data->bytes_xfered = data->blksz * data->blocks; + return error; +} + +static int cb710_mmc_command(struct mmc_host *mmc, struct mmc_command *cmd) +{ + struct cb710_slot *slot = cb710_mmc_to_slot(mmc); + struct cb710_mmc_reader *reader = mmc_priv(mmc); + struct mmc_data *data = cmd->data; + + u16 cb_cmd = cb710_encode_cmd_flags(reader, cmd); + dev_dbg(cb710_slot_dev(slot), "cmd request: 0x%04X\n", cb_cmd); + + if (data) { + if (!cb710_is_transfer_size_supported(data)) { + data->error = -EINVAL; + return -1; + } + cb710_mmc_set_transfer_size(slot, data->blocks, data->blksz); + } + + cb710_wait_while_busy(slot, CB710_MMC_S2_BUSY_20|CB710_MMC_S2_BUSY_10); + cb710_write_port_16(slot, CB710_MMC_CMD_TYPE_PORT, cb_cmd); + cb710_wait_while_busy(slot, CB710_MMC_S2_BUSY_20); + cb710_write_port_32(slot, CB710_MMC_CMD_PARAM_PORT, cmd->arg); + cb710_mmc_reset_events(slot); + cb710_wait_while_busy(slot, CB710_MMC_S2_BUSY_20); + cb710_modify_port_8(slot, CB710_MMC_CONFIG0_PORT, 0x01, 0); + + cmd->error = cb710_wait_for_event(slot, CB710_MMC_S1_COMMAND_SENT); + if (cmd->error) + return -1; + + if (cmd->flags & MMC_RSP_PRESENT) { + cb710_receive_response(slot, cmd); + if (cmd->error) + return -1; + } + + if (data) + data->error = cb710_mmc_transfer_data(slot, data); + return 0; +} + +static void cb710_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) +{ + struct cb710_slot *slot = cb710_mmc_to_slot(mmc); + struct cb710_mmc_reader *reader = mmc_priv(mmc); + + WARN_ON(reader->mrq != NULL); + + reader->mrq = mrq; + cb710_mmc_enable_irq(slot, CB710_MMC_IE_TEST_MASK, 0); + + if (cb710_mmc_is_card_inserted(slot)) { + if (!cb710_mmc_command(mmc, mrq->cmd) && mrq->stop) + cb710_mmc_command(mmc, mrq->stop); + mdelay(1); + } else { + mrq->cmd->error = -ENOMEDIUM; + } + + tasklet_schedule(&reader->finish_req_tasklet); +} + +static int cb710_mmc_powerup(struct cb710_slot *slot) +{ +#ifdef CONFIG_CB710_DEBUG + struct cb710_chip *chip = cb710_slot_to_chip(slot); +#endif + int err; + + /* a lot of magic; see comment in cb710_mmc_set_clock() */ + dev_dbg(cb710_slot_dev(slot), "bus powerup\n"); + cb710_dump_regs(chip, CB710_DUMP_REGS_MMC); + err = cb710_wait_while_busy(slot, CB710_MMC_S2_BUSY_20); + if (unlikely(err)) + return err; + cb710_modify_port_8(slot, CB710_MMC_CONFIG1_PORT, 0x80, 0); + cb710_modify_port_8(slot, CB710_MMC_CONFIG3_PORT, 0x80, 0); + cb710_dump_regs(chip, CB710_DUMP_REGS_MMC); + mdelay(1); + dev_dbg(cb710_slot_dev(slot), "after delay 1\n"); + cb710_dump_regs(chip, CB710_DUMP_REGS_MMC); + err = cb710_wait_while_busy(slot, CB710_MMC_S2_BUSY_20); + if (unlikely(err)) + return err; + cb710_modify_port_8(slot, CB710_MMC_CONFIG1_PORT, 0x09, 0); + cb710_dump_regs(chip, CB710_DUMP_REGS_MMC); + mdelay(1); + dev_dbg(cb710_slot_dev(slot), "after delay 2\n"); + cb710_dump_regs(chip, CB710_DUMP_REGS_MMC); + err = cb710_wait_while_busy(slot, CB710_MMC_S2_BUSY_20); + if (unlikely(err)) + return err; + cb710_modify_port_8(slot, CB710_MMC_CONFIG1_PORT, 0, 0x08); + cb710_dump_regs(chip, CB710_DUMP_REGS_MMC); + mdelay(2); + dev_dbg(cb710_slot_dev(slot), "after delay 3\n"); + cb710_dump_regs(chip, CB710_DUMP_REGS_MMC); + cb710_modify_port_8(slot, CB710_MMC_CONFIG0_PORT, 0x06, 0); + cb710_modify_port_8(slot, CB710_MMC_CONFIG1_PORT, 0x70, 0); + cb710_modify_port_8(slot, CB710_MMC_CONFIG2_PORT, 0x80, 0); + cb710_modify_port_8(slot, CB710_MMC_CONFIG3_PORT, 0x03, 0); + cb710_dump_regs(chip, CB710_DUMP_REGS_MMC); + err = cb710_wait_while_busy(slot, CB710_MMC_S2_BUSY_20); + if (unlikely(err)) + return err; + /* This port behaves weird: quick byte reads of 0x08,0x09 return + * 0xFF,0x00 after writing 0xFFFF to 0x08; it works correctly when + * read/written from userspace... What am I missing here? + * (it doesn't depend on write-to-read delay) */ + cb710_write_port_16(slot, CB710_MMC_CONFIGB_PORT, 0xFFFF); + cb710_modify_port_8(slot, CB710_MMC_CONFIG0_PORT, 0x06, 0); + cb710_dump_regs(chip, CB710_DUMP_REGS_MMC); + dev_dbg(cb710_slot_dev(slot), "bus powerup finished\n"); + + return cb710_check_event(slot, 0); +} + +static void cb710_mmc_powerdown(struct cb710_slot *slot) +{ + cb710_modify_port_8(slot, CB710_MMC_CONFIG1_PORT, 0, 0x81); + cb710_modify_port_8(slot, CB710_MMC_CONFIG3_PORT, 0, 0x80); +} + +static void cb710_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct cb710_slot *slot = cb710_mmc_to_slot(mmc); + struct cb710_mmc_reader *reader = mmc_priv(mmc); + int err; + + cb710_mmc_set_clock(mmc, ios->clock); + + if (!cb710_mmc_is_card_inserted(slot)) { + dev_dbg(cb710_slot_dev(slot), + "no card inserted - ignoring bus powerup request\n"); + ios->power_mode = MMC_POWER_OFF; + } + + if (ios->power_mode != reader->last_power_mode) + switch (ios->power_mode) { + case MMC_POWER_ON: + err = cb710_mmc_powerup(slot); + if (err) { + dev_warn(cb710_slot_dev(slot), + "powerup failed (%d)- retrying\n", err); + cb710_mmc_powerdown(slot); + udelay(1); + err = cb710_mmc_powerup(slot); + if (err) + dev_warn(cb710_slot_dev(slot), + "powerup retry failed (%d) - expect errors\n", + err); + } + reader->last_power_mode = MMC_POWER_ON; + break; + case MMC_POWER_OFF: + cb710_mmc_powerdown(slot); + reader->last_power_mode = MMC_POWER_OFF; + break; + case MMC_POWER_UP: + default: + /* ignore */; + } + + cb710_mmc_enable_4bit_data(slot, ios->bus_width != MMC_BUS_WIDTH_1); + + cb710_mmc_enable_irq(slot, CB710_MMC_IE_TEST_MASK, 0); +} + +static int cb710_mmc_get_ro(struct mmc_host *mmc) +{ + struct cb710_slot *slot = cb710_mmc_to_slot(mmc); + + return cb710_read_port_8(slot, CB710_MMC_STATUS3_PORT) + & CB710_MMC_S3_WRITE_PROTECTED; +} + +static int cb710_mmc_irq_handler(struct cb710_slot *slot) +{ + struct mmc_host *mmc = cb710_slot_to_mmc(slot); + struct cb710_mmc_reader *reader = mmc_priv(mmc); + u32 status, config1, config2, irqen; + + status = cb710_read_port_32(slot, CB710_MMC_STATUS_PORT); + irqen = cb710_read_port_32(slot, CB710_MMC_IRQ_ENABLE_PORT); + config2 = cb710_read_port_32(slot, CB710_MMC_CONFIGB_PORT); + config1 = cb710_read_port_32(slot, CB710_MMC_CONFIG_PORT); + + dev_dbg(cb710_slot_dev(slot), "interrupt; status: %08X, " + "ie: %08X, c2: %08X, c1: %08X\n", + status, irqen, config2, config1); + + if (status & (CB710_MMC_S1_CARD_CHANGED << 8)) { + /* ack the event */ + cb710_write_port_8(slot, CB710_MMC_STATUS1_PORT, + CB710_MMC_S1_CARD_CHANGED); + if ((irqen & CB710_MMC_IE_CISTATUS_MASK) + == CB710_MMC_IE_CISTATUS_MASK) + mmc_detect_change(mmc, HZ/5); + } else { + dev_dbg(cb710_slot_dev(slot), "unknown interrupt (test)\n"); + spin_lock(&reader->irq_lock); + __cb710_mmc_enable_irq(slot, 0, CB710_MMC_IE_TEST_MASK); + spin_unlock(&reader->irq_lock); + } + + return 1; +} + +static void cb710_mmc_finish_request_tasklet(unsigned long data) +{ + struct mmc_host *mmc = (void *)data; + struct cb710_mmc_reader *reader = mmc_priv(mmc); + struct mmc_request *mrq = reader->mrq; + + reader->mrq = NULL; + mmc_request_done(mmc, mrq); +} + +static const struct mmc_host_ops cb710_mmc_host = { + .request = cb710_mmc_request, + .set_ios = cb710_mmc_set_ios, + .get_ro = cb710_mmc_get_ro +}; + +#ifdef CONFIG_PM + +static int cb710_mmc_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct cb710_slot *slot = cb710_pdev_to_slot(pdev); + struct mmc_host *mmc = cb710_slot_to_mmc(slot); + int err; + + err = mmc_suspend_host(mmc, state); + if (err) + return err; + + cb710_mmc_enable_irq(slot, 0, ~0); + return 0; +} + +static int cb710_mmc_resume(struct platform_device *pdev) +{ + struct cb710_slot *slot = cb710_pdev_to_slot(pdev); + struct mmc_host *mmc = cb710_slot_to_mmc(slot); + + cb710_mmc_enable_irq(slot, 0, ~0); + + return mmc_resume_host(mmc); +} + +#endif /* CONFIG_PM */ + +static int __devinit cb710_mmc_init(struct platform_device *pdev) +{ + struct cb710_slot *slot = cb710_pdev_to_slot(pdev); + struct cb710_chip *chip = cb710_slot_to_chip(slot); + struct mmc_host *mmc; + struct cb710_mmc_reader *reader; + int err; + u32 val; + + mmc = mmc_alloc_host(sizeof(*reader), cb710_slot_dev(slot)); + if (!mmc) + return -ENOMEM; + + dev_set_drvdata(&pdev->dev, mmc); + + /* harmless (maybe) magic */ + pci_read_config_dword(chip->pdev, 0x48, &val); + val = cb710_src_freq_mhz[(val >> 16) & 0xF]; + dev_dbg(cb710_slot_dev(slot), "source frequency: %dMHz\n", val); + val *= 1000000; + + mmc->ops = &cb710_mmc_host; + mmc->f_max = val; + mmc->f_min = val >> cb710_clock_divider_log2[CB710_MAX_DIVIDER_IDX]; + mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34; + mmc->caps = MMC_CAP_4_BIT_DATA; + + reader = mmc_priv(mmc); + + tasklet_init(&reader->finish_req_tasklet, + cb710_mmc_finish_request_tasklet, (unsigned long)mmc); + spin_lock_init(&reader->irq_lock); + cb710_dump_regs(chip, CB710_DUMP_REGS_MMC); + + cb710_mmc_enable_irq(slot, 0, ~0); + cb710_set_irq_handler(slot, cb710_mmc_irq_handler); + + err = mmc_add_host(mmc); + if (unlikely(err)) + goto err_free_mmc; + + dev_dbg(cb710_slot_dev(slot), "mmc_hostname is %s\n", + mmc_hostname(mmc)); + + cb710_mmc_enable_irq(slot, CB710_MMC_IE_CARD_INSERTION_STATUS, 0); + + return 0; + +err_free_mmc: + dev_dbg(cb710_slot_dev(slot), "mmc_add_host() failed: %d\n", err); + + mmc_free_host(mmc); + return err; +} + +static int __devexit cb710_mmc_exit(struct platform_device *pdev) +{ + struct cb710_slot *slot = cb710_pdev_to_slot(pdev); + struct mmc_host *mmc = cb710_slot_to_mmc(slot); + struct cb710_mmc_reader *reader = mmc_priv(mmc); + + cb710_mmc_enable_irq(slot, 0, CB710_MMC_IE_CARD_INSERTION_STATUS); + + mmc_remove_host(mmc); + + /* IRQs should be disabled now, but let's stay on the safe side */ + cb710_mmc_enable_irq(slot, 0, ~0); + cb710_set_irq_handler(slot, NULL); + + /* clear config ports - just in case */ + cb710_write_port_32(slot, CB710_MMC_CONFIG_PORT, 0); + cb710_write_port_16(slot, CB710_MMC_CONFIGB_PORT, 0); + + tasklet_kill(&reader->finish_req_tasklet); + + mmc_free_host(mmc); + return 0; +} + +static struct platform_driver cb710_mmc_driver = { + .driver.name = "cb710-mmc", + .probe = cb710_mmc_init, + .remove = __devexit_p(cb710_mmc_exit), +#ifdef CONFIG_PM + .suspend = cb710_mmc_suspend, + .resume = cb710_mmc_resume, +#endif +}; + +static int __init cb710_mmc_init_module(void) +{ + return platform_driver_register(&cb710_mmc_driver); +} + +static void __exit cb710_mmc_cleanup_module(void) +{ + platform_driver_unregister(&cb710_mmc_driver); +} + +module_init(cb710_mmc_init_module); +module_exit(cb710_mmc_cleanup_module); + +MODULE_AUTHOR("MichaÅ‚ MirosÅ‚aw "); +MODULE_DESCRIPTION("ENE CB710 memory card reader driver - MMC/SD part"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:cb710-mmc"); diff --git a/drivers/mmc/host/cb710-mmc.h b/drivers/mmc/host/cb710-mmc.h new file mode 100644 index 000000000000..e845c776bdd7 --- /dev/null +++ b/drivers/mmc/host/cb710-mmc.h @@ -0,0 +1,104 @@ +/* + * cb710/cb710-mmc.h + * + * Copyright by MichaÅ‚ MirosÅ‚aw, 2008-2009 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef LINUX_CB710_MMC_H +#define LINUX_CB710_MMC_H + +#include + +/* per-MMC-reader structure */ +struct cb710_mmc_reader { + struct tasklet_struct finish_req_tasklet; + struct mmc_request *mrq; + spinlock_t irq_lock; + unsigned char last_power_mode; +}; + +/* some device struct walking */ + +static inline struct mmc_host *cb710_slot_to_mmc(struct cb710_slot *slot) +{ + return dev_get_drvdata(&slot->pdev.dev); +} + +static inline struct cb710_slot *cb710_mmc_to_slot(struct mmc_host *mmc) +{ + struct platform_device *pdev = container_of(mmc_dev(mmc), + struct platform_device, dev); + return cb710_pdev_to_slot(pdev); +} + +/* registers (this might be all wrong ;) */ + +#define CB710_MMC_DATA_PORT 0x00 + +#define CB710_MMC_CONFIG_PORT 0x04 +#define CB710_MMC_CONFIG0_PORT 0x04 +#define CB710_MMC_CONFIG1_PORT 0x05 +#define CB710_MMC_C1_4BIT_DATA_BUS 0x40 +#define CB710_MMC_CONFIG2_PORT 0x06 +#define CB710_MMC_C2_READ_PIO_SIZE_MASK 0x0F /* N-1 */ +#define CB710_MMC_CONFIG3_PORT 0x07 + +#define CB710_MMC_CONFIGB_PORT 0x08 + +#define CB710_MMC_IRQ_ENABLE_PORT 0x0C +#define CB710_MMC_IE_TEST_MASK 0x00BF +#define CB710_MMC_IE_CARD_INSERTION_STATUS 0x1000 +#define CB710_MMC_IE_IRQ_ENABLE 0x8000 +#define CB710_MMC_IE_CISTATUS_MASK \ + (CB710_MMC_IE_CARD_INSERTION_STATUS|CB710_MMC_IE_IRQ_ENABLE) + +#define CB710_MMC_STATUS_PORT 0x10 +#define CB710_MMC_STATUS_ERROR_EVENTS 0x60FF +#define CB710_MMC_STATUS0_PORT 0x10 +#define CB710_MMC_S0_FIFO_UNDERFLOW 0x40 +#define CB710_MMC_STATUS1_PORT 0x11 +#define CB710_MMC_S1_COMMAND_SENT 0x01 +#define CB710_MMC_S1_DATA_TRANSFER_DONE 0x02 +#define CB710_MMC_S1_PIO_TRANSFER_DONE 0x04 +#define CB710_MMC_S1_CARD_CHANGED 0x10 +#define CB710_MMC_S1_RESET 0x20 +#define CB710_MMC_STATUS2_PORT 0x12 +#define CB710_MMC_S2_FIFO_READY 0x01 +#define CB710_MMC_S2_FIFO_EMPTY 0x02 +#define CB710_MMC_S2_BUSY_10 0x10 +#define CB710_MMC_S2_BUSY_20 0x20 +#define CB710_MMC_STATUS3_PORT 0x13 +#define CB710_MMC_S3_CARD_DETECTED 0x02 +#define CB710_MMC_S3_WRITE_PROTECTED 0x04 + +#define CB710_MMC_CMD_TYPE_PORT 0x14 +#define CB710_MMC_RSP_TYPE_MASK 0x0007 +#define CB710_MMC_RSP_R1 (0) +#define CB710_MMC_RSP_136 (5) +#define CB710_MMC_RSP_NO_CRC (2) +#define CB710_MMC_RSP_PRESENT_MASK 0x0018 +#define CB710_MMC_RSP_NONE (0 << 3) +#define CB710_MMC_RSP_PRESENT (1 << 3) +#define CB710_MMC_RSP_PRESENT_X (2 << 3) +#define CB710_MMC_CMD_TYPE_MASK 0x0060 +#define CB710_MMC_CMD_BC (0 << 5) +#define CB710_MMC_CMD_BCR (1 << 5) +#define CB710_MMC_CMD_AC (2 << 5) +#define CB710_MMC_CMD_ADTC (3 << 5) +#define CB710_MMC_DATA_READ 0x0080 +#define CB710_MMC_CMD_CODE_MASK 0x3F00 +#define CB710_MMC_CMD_CODE_SHIFT 8 +#define CB710_MMC_IS_APP_CMD 0x4000 +#define CB710_MMC_RSP_BUSY 0x8000 + +#define CB710_MMC_CMD_PARAM_PORT 0x18 +#define CB710_MMC_TRANSFER_SIZE_PORT 0x1C +#define CB710_MMC_RESPONSE0_PORT 0x20 +#define CB710_MMC_RESPONSE1_PORT 0x24 +#define CB710_MMC_RESPONSE2_PORT 0x28 +#define CB710_MMC_RESPONSE3_PORT 0x2C + +#endif /* LINUX_CB710_MMC_H */ diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c index f48349d18c92..240608cc7ae9 100644 --- a/drivers/mmc/host/mmc_spi.c +++ b/drivers/mmc/host/mmc_spi.c @@ -97,6 +97,14 @@ */ #define r1b_timeout (HZ * 3) +/* One of the critical speed parameters is the amount of data which may + * be transfered in one command. If this value is too low, the SD card + * controller has to do multiple partial block writes (argggh!). With + * today (2008) SD cards there is little speed gain if we transfer more + * than 64 KBytes at a time. So use this value until there is any indication + * that we should do more here. + */ +#define MMC_SPI_BLOCKSATONCE 128 /****************************************************************************/ @@ -327,15 +335,16 @@ checkstatus: /* Status byte: the entire seven-bit R1 response. */ if (cmd->resp[0] != 0) { - if ((R1_SPI_PARAMETER | R1_SPI_ADDRESS - | R1_SPI_ILLEGAL_COMMAND) + if ((R1_SPI_PARAMETER | R1_SPI_ADDRESS) & cmd->resp[0]) - value = -EINVAL; + value = -EFAULT; /* Bad address */ + else if (R1_SPI_ILLEGAL_COMMAND & cmd->resp[0]) + value = -ENOSYS; /* Function not implemented */ else if (R1_SPI_COM_CRC & cmd->resp[0]) - value = -EILSEQ; + value = -EILSEQ; /* Illegal byte sequence */ else if ((R1_SPI_ERASE_SEQ | R1_SPI_ERASE_RESET) & cmd->resp[0]) - value = -EIO; + value = -EIO; /* I/O error */ /* else R1_SPI_IDLE, "it's resetting" */ } @@ -1366,6 +1375,10 @@ static int mmc_spi_probe(struct spi_device *spi) mmc->ops = &mmc_spi_ops; mmc->max_blk_size = MMC_SPI_BLOCKSIZE; + mmc->max_hw_segs = MMC_SPI_BLOCKSATONCE; + mmc->max_phys_segs = MMC_SPI_BLOCKSATONCE; + mmc->max_req_size = MMC_SPI_BLOCKSATONCE * MMC_SPI_BLOCKSIZE; + mmc->max_blk_count = MMC_SPI_BLOCKSATONCE; mmc->caps = MMC_CAP_SPI; diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 7d4febdab286..e1aa8471ab1c 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -546,7 +546,7 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) host->mclk = clk_get_rate(host->clk); DBG(host, "eventual mclk rate: %u Hz\n", host->mclk); } - host->base = ioremap(dev->res.start, SZ_4K); + host->base = ioremap(dev->res.start, resource_size(&dev->res)); if (!host->base) { ret = -ENOMEM; goto clk_disable; diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index f4cbe473670e..bc14bb1b0579 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -746,8 +746,6 @@ static int mxcmci_probe(struct platform_device *pdev) } mmc->f_min = clk_get_rate(host->clk) >> 16; - if (mmc->f_min < 400000) - mmc->f_min = 400000; mmc->f_max = clk_get_rate(host->clk) >> 1; /* recommended in data sheet */ diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index dceb5ee3bda0..e7a331de5733 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -1593,7 +1593,6 @@ static int mmc_omap_resume(struct platform_device *pdev) #endif static struct platform_driver mmc_omap_driver = { - .probe = mmc_omap_probe, .remove = mmc_omap_remove, .suspend = mmc_omap_suspend, .resume = mmc_omap_resume, @@ -1605,7 +1604,7 @@ static struct platform_driver mmc_omap_driver = { static int __init mmc_omap_init(void) { - return platform_driver_register(&mmc_omap_driver); + return platform_driver_probe(&mmc_omap_driver, mmc_omap_probe); } static void __exit mmc_omap_exit(void) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index c40cb96255a2..1cf9cfb3b64f 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -1073,7 +1073,6 @@ static int __init omap_mmc_probe(struct platform_device *pdev) mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; mmc->max_seg_size = mmc->max_req_size; - mmc->ocr_avail = mmc_slot(host).ocr_mask; mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED; if (pdata->slots[host->slot_id].wires >= 8) @@ -1110,13 +1109,14 @@ static int __init omap_mmc_probe(struct platform_device *pdev) goto err_irq; } + /* initialize power supplies, gpios, etc */ if (pdata->init != NULL) { if (pdata->init(&pdev->dev) != 0) { - dev_dbg(mmc_dev(host->mmc), - "Unable to configure MMC IRQs\n"); + dev_dbg(mmc_dev(host->mmc), "late init error\n"); goto err_irq_cd_init; } } + mmc->ocr_avail = mmc_slot(host).ocr_mask; /* Request IRQ for card detect */ if ((mmc_slot(host).card_detect_irq)) { diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index 430095725f9f..d7d7109ef47e 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c @@ -27,6 +27,7 @@ #include #include #include +#include #include @@ -67,8 +68,42 @@ struct pxamci_host { unsigned int dma_dir; unsigned int dma_drcmrrx; unsigned int dma_drcmrtx; + + struct regulator *vcc; }; +static inline void pxamci_init_ocr(struct pxamci_host *host) +{ +#ifdef CONFIG_REGULATOR + host->vcc = regulator_get(mmc_dev(host->mmc), "vmmc"); + + if (IS_ERR(host->vcc)) + host->vcc = NULL; + else { + host->mmc->ocr_avail = mmc_regulator_get_ocrmask(host->vcc); + if (host->pdata && host->pdata->ocr_mask) + dev_warn(mmc_dev(host->mmc), + "ocr_mask/setpower will not be used\n"); + } +#endif + if (host->vcc == NULL) { + /* fall-back to platform data */ + host->mmc->ocr_avail = host->pdata ? + host->pdata->ocr_mask : + MMC_VDD_32_33 | MMC_VDD_33_34; + } +} + +static inline void pxamci_set_power(struct pxamci_host *host, unsigned int vdd) +{ +#ifdef CONFIG_REGULATOR + if (host->vcc) + mmc_regulator_set_ocr(host->vcc, vdd); +#endif + if (!host->vcc && host->pdata && host->pdata->setpower) + host->pdata->setpower(mmc_dev(host->mmc), vdd); +} + static void pxamci_stop_clock(struct pxamci_host *host) { if (readl(host->base + MMC_STAT) & STAT_CLK_EN) { @@ -438,8 +473,7 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) if (host->power_mode != ios->power_mode) { host->power_mode = ios->power_mode; - if (host->pdata && host->pdata->setpower) - host->pdata->setpower(mmc_dev(mmc), ios->vdd); + pxamci_set_power(host, ios->vdd); if (ios->power_mode == MMC_POWER_ON) host->cmdat |= CMDAT_INIT; @@ -562,9 +596,8 @@ static int pxamci_probe(struct platform_device *pdev) mmc->f_max = (cpu_is_pxa300() || cpu_is_pxa310()) ? 26000000 : host->clkrate; - mmc->ocr_avail = host->pdata ? - host->pdata->ocr_mask : - MMC_VDD_32_33|MMC_VDD_33_34; + pxamci_init_ocr(host); + mmc->caps = 0; host->cmdat = 0; if (!cpu_is_pxa25x()) { @@ -661,6 +694,9 @@ static int pxamci_remove(struct platform_device *pdev) if (mmc) { struct pxamci_host *host = mmc_priv(mmc); + if (host->vcc) + regulator_put(host->vcc); + if (host->pdata && host->pdata->exit) host->pdata->exit(&pdev->dev, mmc); diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c index 2db166b7096f..8c08cd7efa7f 100644 --- a/drivers/mmc/host/s3cmci.c +++ b/drivers/mmc/host/s3cmci.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -789,11 +790,11 @@ static void s3cmci_dma_setup(struct s3cmci_host *host, last_source = source; - s3c2410_dma_devconfig(host->dma, source, 3, + s3c2410_dma_devconfig(host->dma, source, host->mem->start + host->sdidata); if (!setup_ok) { - s3c2410_dma_config(host->dma, 4, 0); + s3c2410_dma_config(host->dma, 4); s3c2410_dma_set_buffdone_fn(host->dma, s3cmci_dma_done_callback); s3c2410_dma_setflags(host->dma, S3C2410_DMAF_AUTOSTART); @@ -1121,7 +1122,7 @@ static void s3cmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) case MMC_POWER_OFF: default: s3c2410_gpio_setpin(S3C2410_GPE5, 0); - s3c2410_gpio_cfgpin(S3C2410_GPE5, S3C2410_GPE5_OUTP); + s3c2410_gpio_cfgpin(S3C2410_GPE5, S3C2410_GPIO_OUTPUT); if (host->is2440) mci_con |= S3C2440_SDICON_SDRESET; diff --git a/drivers/mmc/host/sdhci-of.c b/drivers/mmc/host/sdhci-of.c index 128c614d11aa..d79fa55c3b89 100644 --- a/drivers/mmc/host/sdhci-of.c +++ b/drivers/mmc/host/sdhci-of.c @@ -250,6 +250,9 @@ static int __devinit sdhci_of_probe(struct of_device *ofdev, host->ops = &sdhci_of_data->ops; } + if (of_get_property(np, "sdhci,1-bit-only", NULL)) + host->quirks |= SDHCI_QUIRK_FORCE_1_BIT_DATA; + clk = of_get_property(np, "clock-frequency", &size); if (clk && size == sizeof(*clk) && *clk) of_host->clock = *clk; diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index 65be27995d5c..2f15cc17d887 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -284,6 +284,18 @@ static const struct sdhci_pci_fixes sdhci_jmicron = { .resume = jmicron_resume, }; +static int via_probe(struct sdhci_pci_chip *chip) +{ + if (chip->pdev->revision == 0x10) + chip->quirks |= SDHCI_QUIRK_DELAY_AFTER_POWER; + + return 0; +} + +static const struct sdhci_pci_fixes sdhci_via = { + .probe = via_probe, +}; + static const struct pci_device_id pci_ids[] __devinitdata = { { .vendor = PCI_VENDOR_ID_RICOH, @@ -349,6 +361,14 @@ static const struct pci_device_id pci_ids[] __devinitdata = { .driver_data = (kernel_ulong_t)&sdhci_jmicron, }, + { + .vendor = PCI_VENDOR_ID_VIA, + .device = 0x95d0, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = (kernel_ulong_t)&sdhci_via, + }, + { /* Generic SD host controller */ PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00) }, diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c new file mode 100644 index 000000000000..297f40ae6ad5 --- /dev/null +++ b/drivers/mmc/host/sdhci-pltfm.c @@ -0,0 +1,168 @@ +/* + * sdhci-pltfm.c Support for SDHCI platform devices + * Copyright (c) 2009 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* Supports: + * SDHCI platform devices + * + * Inspired by sdhci-pci.c, by Pierre Ossman + */ + +#include +#include +#include + +#include + +#include + +#include "sdhci.h" + +/*****************************************************************************\ + * * + * SDHCI core callbacks * + * * +\*****************************************************************************/ + +static struct sdhci_ops sdhci_pltfm_ops = { +}; + +/*****************************************************************************\ + * * + * Device probing/removal * + * * +\*****************************************************************************/ + +static int __devinit sdhci_pltfm_probe(struct platform_device *pdev) +{ + struct sdhci_host *host; + struct resource *iomem; + int ret; + + BUG_ON(pdev == NULL); + + iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!iomem) { + ret = -ENOMEM; + goto err; + } + + if (resource_size(iomem) != 0x100) + dev_err(&pdev->dev, "Invalid iomem size. You may " + "experience problems.\n"); + + if (pdev->dev.parent) + host = sdhci_alloc_host(pdev->dev.parent, 0); + else + host = sdhci_alloc_host(&pdev->dev, 0); + + if (IS_ERR(host)) { + ret = PTR_ERR(host); + goto err; + } + + host->hw_name = "platform"; + host->ops = &sdhci_pltfm_ops; + host->irq = platform_get_irq(pdev, 0); + + if (!request_mem_region(iomem->start, resource_size(iomem), + mmc_hostname(host->mmc))) { + dev_err(&pdev->dev, "cannot request region\n"); + ret = -EBUSY; + goto err_request; + } + + host->ioaddr = ioremap(iomem->start, resource_size(iomem)); + if (!host->ioaddr) { + dev_err(&pdev->dev, "failed to remap registers\n"); + ret = -ENOMEM; + goto err_remap; + } + + ret = sdhci_add_host(host); + if (ret) + goto err_add_host; + + platform_set_drvdata(pdev, host); + + return 0; + +err_add_host: + iounmap(host->ioaddr); +err_remap: + release_mem_region(iomem->start, resource_size(iomem)); +err_request: + sdhci_free_host(host); +err: + printk(KERN_ERR"Probing of sdhci-pltfm failed: %d\n", ret); + return ret; +} + +static int __devexit sdhci_pltfm_remove(struct platform_device *pdev) +{ + struct sdhci_host *host = platform_get_drvdata(pdev); + struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + int dead; + u32 scratch; + + dead = 0; + scratch = readl(host->ioaddr + SDHCI_INT_STATUS); + if (scratch == (u32)-1) + dead = 1; + + sdhci_remove_host(host, dead); + iounmap(host->ioaddr); + release_mem_region(iomem->start, resource_size(iomem)); + sdhci_free_host(host); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static struct platform_driver sdhci_pltfm_driver = { + .driver = { + .name = "sdhci", + .owner = THIS_MODULE, + }, + .probe = sdhci_pltfm_probe, + .remove = __devexit_p(sdhci_pltfm_remove), +}; + +/*****************************************************************************\ + * * + * Driver init/exit * + * * +\*****************************************************************************/ + +static int __init sdhci_drv_init(void) +{ + return platform_driver_register(&sdhci_pltfm_driver); +} + +static void __exit sdhci_drv_exit(void) +{ + platform_driver_unregister(&sdhci_pltfm_driver); +} + +module_init(sdhci_drv_init); +module_exit(sdhci_drv_exit); + +MODULE_DESCRIPTION("Secure Digital Host Controller Interface platform driver"); +MODULE_AUTHOR("Mocean Laboratories "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:sdhci"); + diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c new file mode 100644 index 000000000000..50997d2a63e7 --- /dev/null +++ b/drivers/mmc/host/sdhci-s3c.c @@ -0,0 +1,428 @@ +/* linux/drivers/mmc/host/sdhci-s3c.c + * + * Copyright 2008 Openmoko Inc. + * Copyright 2008 Simtec Electronics + * Ben Dooks + * http://armlinux.simtec.co.uk/ + * + * SDHCI (HSMMC) support for Samsung SoC + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "sdhci.h" + +#define MAX_BUS_CLK (4) + +/** + * struct sdhci_s3c - S3C SDHCI instance + * @host: The SDHCI host created + * @pdev: The platform device we where created from. + * @ioarea: The resource created when we claimed the IO area. + * @pdata: The platform data for this controller. + * @cur_clk: The index of the current bus clock. + * @clk_io: The clock for the internal bus interface. + * @clk_bus: The clocks that are available for the SD/MMC bus clock. + */ +struct sdhci_s3c { + struct sdhci_host *host; + struct platform_device *pdev; + struct resource *ioarea; + struct s3c_sdhci_platdata *pdata; + unsigned int cur_clk; + + struct clk *clk_io; + struct clk *clk_bus[MAX_BUS_CLK]; +}; + +static inline struct sdhci_s3c *to_s3c(struct sdhci_host *host) +{ + return sdhci_priv(host); +} + +/** + * get_curclk - convert ctrl2 register to clock source number + * @ctrl2: Control2 register value. + */ +static u32 get_curclk(u32 ctrl2) +{ + ctrl2 &= S3C_SDHCI_CTRL2_SELBASECLK_MASK; + ctrl2 >>= S3C_SDHCI_CTRL2_SELBASECLK_SHIFT; + + return ctrl2; +} + +static void sdhci_s3c_check_sclk(struct sdhci_host *host) +{ + struct sdhci_s3c *ourhost = to_s3c(host); + u32 tmp = readl(host->ioaddr + S3C_SDHCI_CONTROL2); + + if (get_curclk(tmp) != ourhost->cur_clk) { + dev_dbg(&ourhost->pdev->dev, "restored ctrl2 clock setting\n"); + + tmp &= ~S3C_SDHCI_CTRL2_SELBASECLK_MASK; + tmp |= ourhost->cur_clk << S3C_SDHCI_CTRL2_SELBASECLK_SHIFT; + writel(tmp, host->ioaddr + 0x80); + } +} + +/** + * sdhci_s3c_get_max_clk - callback to get maximum clock frequency. + * @host: The SDHCI host instance. + * + * Callback to return the maximum clock rate acheivable by the controller. +*/ +static unsigned int sdhci_s3c_get_max_clk(struct sdhci_host *host) +{ + struct sdhci_s3c *ourhost = to_s3c(host); + struct clk *busclk; + unsigned int rate, max; + int clk; + + /* note, a reset will reset the clock source */ + + sdhci_s3c_check_sclk(host); + + for (max = 0, clk = 0; clk < MAX_BUS_CLK; clk++) { + busclk = ourhost->clk_bus[clk]; + if (!busclk) + continue; + + rate = clk_get_rate(busclk); + if (rate > max) + max = rate; + } + + return max; +} + +static unsigned int sdhci_s3c_get_timeout_clk(struct sdhci_host *host) +{ + return sdhci_s3c_get_max_clk(host) / 1000000; +} + +/** + * sdhci_s3c_consider_clock - consider one the bus clocks for current setting + * @ourhost: Our SDHCI instance. + * @src: The source clock index. + * @wanted: The clock frequency wanted. + */ +static unsigned int sdhci_s3c_consider_clock(struct sdhci_s3c *ourhost, + unsigned int src, + unsigned int wanted) +{ + unsigned long rate; + struct clk *clksrc = ourhost->clk_bus[src]; + int div; + + if (!clksrc) + return UINT_MAX; + + rate = clk_get_rate(clksrc); + + for (div = 1; div < 256; div *= 2) { + if ((rate / div) <= wanted) + break; + } + + dev_dbg(&ourhost->pdev->dev, "clk %d: rate %ld, want %d, got %ld\n", + src, rate, wanted, rate / div); + + return (wanted - (rate / div)); +} + +/** + * sdhci_s3c_set_clock - callback on clock change + * @host: The SDHCI host being changed + * @clock: The clock rate being requested. + * + * When the card's clock is going to be changed, look at the new frequency + * and find the best clock source to go with it. +*/ +static void sdhci_s3c_set_clock(struct sdhci_host *host, unsigned int clock) +{ + struct sdhci_s3c *ourhost = to_s3c(host); + unsigned int best = UINT_MAX; + unsigned int delta; + int best_src = 0; + int src; + u32 ctrl; + + /* don't bother if the clock is going off. */ + if (clock == 0) + return; + + for (src = 0; src < MAX_BUS_CLK; src++) { + delta = sdhci_s3c_consider_clock(ourhost, src, clock); + if (delta < best) { + best = delta; + best_src = src; + } + } + + dev_dbg(&ourhost->pdev->dev, + "selected source %d, clock %d, delta %d\n", + best_src, clock, best); + + /* select the new clock source */ + + if (ourhost->cur_clk != best_src) { + struct clk *clk = ourhost->clk_bus[best_src]; + + /* turn clock off to card before changing clock source */ + writew(0, host->ioaddr + SDHCI_CLOCK_CONTROL); + + ourhost->cur_clk = best_src; + host->max_clk = clk_get_rate(clk); + host->timeout_clk = sdhci_s3c_get_timeout_clk(host); + + ctrl = readl(host->ioaddr + S3C_SDHCI_CONTROL2); + ctrl &= ~S3C_SDHCI_CTRL2_SELBASECLK_MASK; + ctrl |= best_src << S3C_SDHCI_CTRL2_SELBASECLK_SHIFT; + writel(ctrl, host->ioaddr + S3C_SDHCI_CONTROL2); + } + + /* reconfigure the hardware for new clock rate */ + + { + struct mmc_ios ios; + + ios.clock = clock; + + if (ourhost->pdata->cfg_card) + (ourhost->pdata->cfg_card)(ourhost->pdev, host->ioaddr, + &ios, NULL); + } +} + +static struct sdhci_ops sdhci_s3c_ops = { + .get_max_clock = sdhci_s3c_get_max_clk, + .get_timeout_clock = sdhci_s3c_get_timeout_clk, + .set_clock = sdhci_s3c_set_clock, +}; + +static int __devinit sdhci_s3c_probe(struct platform_device *pdev) +{ + struct s3c_sdhci_platdata *pdata = pdev->dev.platform_data; + struct device *dev = &pdev->dev; + struct sdhci_host *host; + struct sdhci_s3c *sc; + struct resource *res; + int ret, irq, ptr, clks; + + if (!pdata) { + dev_err(dev, "no device data specified\n"); + return -ENOENT; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(dev, "no irq specified\n"); + return irq; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "no memory specified\n"); + return -ENOENT; + } + + host = sdhci_alloc_host(dev, sizeof(struct sdhci_s3c)); + if (IS_ERR(host)) { + dev_err(dev, "sdhci_alloc_host() failed\n"); + return PTR_ERR(host); + } + + sc = sdhci_priv(host); + + sc->host = host; + sc->pdev = pdev; + sc->pdata = pdata; + + platform_set_drvdata(pdev, host); + + sc->clk_io = clk_get(dev, "hsmmc"); + if (IS_ERR(sc->clk_io)) { + dev_err(dev, "failed to get io clock\n"); + ret = PTR_ERR(sc->clk_io); + goto err_io_clk; + } + + /* enable the local io clock and keep it running for the moment. */ + clk_enable(sc->clk_io); + + for (clks = 0, ptr = 0; ptr < MAX_BUS_CLK; ptr++) { + struct clk *clk; + char *name = pdata->clocks[ptr]; + + if (name == NULL) + continue; + + clk = clk_get(dev, name); + if (IS_ERR(clk)) { + dev_err(dev, "failed to get clock %s\n", name); + continue; + } + + clks++; + sc->clk_bus[ptr] = clk; + clk_enable(clk); + + dev_info(dev, "clock source %d: %s (%ld Hz)\n", + ptr, name, clk_get_rate(clk)); + } + + if (clks == 0) { + dev_err(dev, "failed to find any bus clocks\n"); + ret = -ENOENT; + goto err_no_busclks; + } + + sc->ioarea = request_mem_region(res->start, resource_size(res), + mmc_hostname(host->mmc)); + if (!sc->ioarea) { + dev_err(dev, "failed to reserve register area\n"); + ret = -ENXIO; + goto err_req_regs; + } + + host->ioaddr = ioremap_nocache(res->start, resource_size(res)); + if (!host->ioaddr) { + dev_err(dev, "failed to map registers\n"); + ret = -ENXIO; + goto err_req_regs; + } + + /* Ensure we have minimal gpio selected CMD/CLK/Detect */ + if (pdata->cfg_gpio) + pdata->cfg_gpio(pdev, pdata->max_width); + + host->hw_name = "samsung-hsmmc"; + host->ops = &sdhci_s3c_ops; + host->quirks = 0; + host->irq = irq; + + /* Setup quirks for the controller */ + + /* Currently with ADMA enabled we are getting some length + * interrupts that are not being dealt with, do disable + * ADMA until this is sorted out. */ + host->quirks |= SDHCI_QUIRK_BROKEN_ADMA; + host->quirks |= SDHCI_QUIRK_32BIT_ADMA_SIZE; + +#ifndef CONFIG_MMC_SDHCI_S3C_DMA + + /* we currently see overruns on errors, so disable the SDMA + * support as well. */ + host->quirks |= SDHCI_QUIRK_BROKEN_DMA; + + /* PIO currently has problems with multi-block IO */ + host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK; + +#endif /* CONFIG_MMC_SDHCI_S3C_DMA */ + + /* It seems we do not get an DATA transfer complete on non-busy + * transfers, not sure if this is a problem with this specific + * SDHCI block, or a missing configuration that needs to be set. */ + host->quirks |= SDHCI_QUIRK_NO_BUSY_IRQ; + + host->quirks |= (SDHCI_QUIRK_32BIT_DMA_ADDR | + SDHCI_QUIRK_32BIT_DMA_SIZE); + + ret = sdhci_add_host(host); + if (ret) { + dev_err(dev, "sdhci_add_host() failed\n"); + goto err_add_host; + } + + return 0; + + err_add_host: + release_resource(sc->ioarea); + kfree(sc->ioarea); + + err_req_regs: + for (ptr = 0; ptr < MAX_BUS_CLK; ptr++) { + clk_disable(sc->clk_bus[ptr]); + clk_put(sc->clk_bus[ptr]); + } + + err_no_busclks: + clk_disable(sc->clk_io); + clk_put(sc->clk_io); + + err_io_clk: + sdhci_free_host(host); + + return ret; +} + +static int __devexit sdhci_s3c_remove(struct platform_device *pdev) +{ + return 0; +} + +#ifdef CONFIG_PM + +static int sdhci_s3c_suspend(struct platform_device *dev, pm_message_t pm) +{ + struct sdhci_host *host = platform_get_drvdata(dev); + + sdhci_suspend_host(host, pm); + return 0; +} + +static int sdhci_s3c_resume(struct platform_device *dev) +{ + struct sdhci_host *host = platform_get_drvdata(dev); + + sdhci_resume_host(host); + return 0; +} + +#else +#define sdhci_s3c_suspend NULL +#define sdhci_s3c_resume NULL +#endif + +static struct platform_driver sdhci_s3c_driver = { + .probe = sdhci_s3c_probe, + .remove = __devexit_p(sdhci_s3c_remove), + .suspend = sdhci_s3c_suspend, + .resume = sdhci_s3c_resume, + .driver = { + .owner = THIS_MODULE, + .name = "s3c-sdhci", + }, +}; + +static int __init sdhci_s3c_init(void) +{ + return platform_driver_register(&sdhci_s3c_driver); +} + +static void __exit sdhci_s3c_exit(void) +{ + platform_driver_unregister(&sdhci_s3c_driver); +} + +module_init(sdhci_s3c_init); +module_exit(sdhci_s3c_exit); + +MODULE_DESCRIPTION("Samsung SDHCI (HSMMC) glue"); +MODULE_AUTHOR("Ben Dooks, "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:s3c-sdhci"); diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 9234be2226e7..6779b4ecab18 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -78,6 +78,11 @@ static void sdhci_dumpregs(struct sdhci_host *host) sdhci_readl(host, SDHCI_CAPABILITIES), sdhci_readl(host, SDHCI_MAX_CURRENT)); + if (host->flags & SDHCI_USE_ADMA) + printk(KERN_DEBUG DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x\n", + readl(host->ioaddr + SDHCI_ADMA_ERROR), + readl(host->ioaddr + SDHCI_ADMA_ADDRESS)); + printk(KERN_DEBUG DRIVER_NAME ": ===========================================\n"); } @@ -579,7 +584,7 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_data *data) * longer to time out, but that's much better than having a too-short * timeout value. */ - if ((host->quirks & SDHCI_QUIRK_BROKEN_TIMEOUT_VAL)) + if (host->quirks & SDHCI_QUIRK_BROKEN_TIMEOUT_VAL) return 0xE; /* timeout in us */ @@ -1005,12 +1010,34 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power) { u8 pwr; - if (host->power == power) + if (power == (unsigned short)-1) + pwr = 0; + else { + switch (1 << power) { + case MMC_VDD_165_195: + pwr = SDHCI_POWER_180; + break; + case MMC_VDD_29_30: + case MMC_VDD_30_31: + pwr = SDHCI_POWER_300; + break; + case MMC_VDD_32_33: + case MMC_VDD_33_34: + pwr = SDHCI_POWER_330; + break; + default: + BUG(); + } + } + + if (host->pwr == pwr) return; - if (power == (unsigned short)-1) { + host->pwr = pwr; + + if (pwr == 0) { sdhci_writeb(host, 0, SDHCI_POWER_CONTROL); - goto out; + return; } /* @@ -1020,35 +1047,23 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power) if (!(host->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE)) sdhci_writeb(host, 0, SDHCI_POWER_CONTROL); - pwr = SDHCI_POWER_ON; - - switch (1 << power) { - case MMC_VDD_165_195: - pwr |= SDHCI_POWER_180; - break; - case MMC_VDD_29_30: - case MMC_VDD_30_31: - pwr |= SDHCI_POWER_300; - break; - case MMC_VDD_32_33: - case MMC_VDD_33_34: - pwr |= SDHCI_POWER_330; - break; - default: - BUG(); - } - /* * At least the Marvell CaFe chip gets confused if we set the voltage * and set turn on power at the same time, so set the voltage first. */ - if ((host->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER)) - sdhci_writeb(host, pwr & ~SDHCI_POWER_ON, SDHCI_POWER_CONTROL); + if (host->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER) + sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); + + pwr |= SDHCI_POWER_ON; sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); -out: - host->power = power; + /* + * Some controllers need an extra 10ms delay of 10ms before they + * can apply clock after applying power + */ + if (host->quirks & SDHCI_QUIRK_DELAY_AFTER_POWER) + mdelay(10); } /*****************************************************************************\ @@ -1374,6 +1389,35 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask) sdhci_finish_command(host); } +#ifdef DEBUG +static void sdhci_show_adma_error(struct sdhci_host *host) +{ + const char *name = mmc_hostname(host->mmc); + u8 *desc = host->adma_desc; + __le32 *dma; + __le16 *len; + u8 attr; + + sdhci_dumpregs(host); + + while (true) { + dma = (__le32 *)(desc + 4); + len = (__le16 *)(desc + 2); + attr = *desc; + + DBG("%s: %p: DMA 0x%08x, LEN 0x%04x, Attr=0x%02x\n", + name, desc, le32_to_cpu(*dma), le16_to_cpu(*len), attr); + + desc += 8; + + if (attr & 2) + break; + } +} +#else +static void sdhci_show_adma_error(struct sdhci_host *host) { } +#endif + static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) { BUG_ON(intmask == 0); @@ -1403,8 +1447,11 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) host->data->error = -ETIMEDOUT; else if (intmask & (SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_END_BIT)) host->data->error = -EILSEQ; - else if (intmask & SDHCI_INT_ADMA_ERROR) + else if (intmask & SDHCI_INT_ADMA_ERROR) { + printk(KERN_ERR "%s: ADMA error\n", mmc_hostname(host->mmc)); + sdhci_show_adma_error(host); host->data->error = -EIO; + } if (host->data->error) sdhci_finish_data(host); @@ -1721,7 +1768,10 @@ int sdhci_add_host(struct sdhci_host *host) mmc->ops = &sdhci_ops; mmc->f_min = host->max_clk / 256; mmc->f_max = host->max_clk; - mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ; + mmc->caps = MMC_CAP_SDIO_IRQ; + + if (!(host->quirks & SDHCI_QUIRK_FORCE_1_BIT_DATA)) + mmc->caps |= MMC_CAP_4_BIT_DATA; if (caps & SDHCI_CAN_DO_HISPD) mmc->caps |= MMC_CAP_SD_HIGHSPEED; @@ -1794,7 +1844,7 @@ int sdhci_add_host(struct sdhci_host *host) /* * Maximum block count. */ - mmc->max_blk_count = 65535; + mmc->max_blk_count = (host->quirks & SDHCI_QUIRK_NO_MULTIBLOCK) ? 1 : 65535; /* * Init tasklets. diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 65c6f996bbd3..831ddf7dcb49 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -226,6 +226,12 @@ struct sdhci_host { #define SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET (1<<19) /* Controller has to be forced to use block size of 2048 bytes */ #define SDHCI_QUIRK_FORCE_BLK_SZ_2048 (1<<20) +/* Controller cannot do multi-block transfers */ +#define SDHCI_QUIRK_NO_MULTIBLOCK (1<<21) +/* Controller can only handle 1-bit data transfers */ +#define SDHCI_QUIRK_FORCE_1_BIT_DATA (1<<22) +/* Controller needs 10ms delay between applying power and clock */ +#define SDHCI_QUIRK_DELAY_AFTER_POWER (1<<23) int irq; /* Device IRQ */ void __iomem * ioaddr; /* Mapped address */ @@ -255,7 +261,7 @@ struct sdhci_host { unsigned int timeout_clk; /* Timeout freq (KHz) */ unsigned int clock; /* Current clock (MHz) */ - unsigned short power; /* Current voltage */ + u8 pwr; /* Current voltage */ struct mmc_request *mrq; /* Current request */ struct mmc_command *cmd; /* Current command */ diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c index 63fbd5b7d312..91991b460c45 100644 --- a/drivers/mmc/host/tmio_mmc.c +++ b/drivers/mmc/host/tmio_mmc.c @@ -10,7 +10,7 @@ * * Driver for the MMC / SD / SDIO cell found in: * - * TC6393XB TC6391XB TC6387XB T7L66XB + * TC6393XB TC6391XB TC6387XB T7L66XB ASIC3 * * This driver draws mainly on scattered spec sheets, Reverse engineering * of the toshiba e800 SD driver and some parts of the 2.4 ASIC3 driver (4 bit @@ -35,69 +35,47 @@ #include "tmio_mmc.h" -/* - * Fixme - documentation conflicts on what the clock values are for the - * various dividers. - * One document I have says that its a divisor of a 24MHz clock, another 33. - * This probably depends on HCLK for a given platform, so we may need to - * require HCLK be passed to us from the MFD core. - * - */ - static void tmio_mmc_set_clock(struct tmio_mmc_host *host, int new_clock) { - void __iomem *cnf = host->cnf; - void __iomem *ctl = host->ctl; u32 clk = 0, clock; if (new_clock) { - for (clock = 46875, clk = 0x100; new_clock >= (clock<<1); ) { + for (clock = host->mmc->f_min, clk = 0x80000080; + new_clock >= (clock<<1); clk >>= 1) clock <<= 1; - clk >>= 1; - } - if (clk & 0x1) - clk = 0x20000; - - clk >>= 2; - tmio_iowrite8((clk & 0x8000) ? 0 : 1, cnf + CNF_SD_CLK_MODE); clk |= 0x100; } - tmio_iowrite16(clk, ctl + CTL_SD_CARD_CLK_CTL); + sd_config_write8(host, CNF_SD_CLK_MODE, clk >> 22); + sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clk & 0x1ff); } static void tmio_mmc_clk_stop(struct tmio_mmc_host *host) { - void __iomem *ctl = host->ctl; - - tmio_iowrite16(0x0000, ctl + CTL_CLK_AND_WAIT_CTL); + sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0000); msleep(10); - tmio_iowrite16(tmio_ioread16(ctl + CTL_SD_CARD_CLK_CTL) & ~0x0100, - ctl + CTL_SD_CARD_CLK_CTL); + sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~0x0100 & + sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); msleep(10); } static void tmio_mmc_clk_start(struct tmio_mmc_host *host) { - void __iomem *ctl = host->ctl; - - tmio_iowrite16(tmio_ioread16(ctl + CTL_SD_CARD_CLK_CTL) | 0x0100, - ctl + CTL_SD_CARD_CLK_CTL); + sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, 0x0100 | + sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); msleep(10); - tmio_iowrite16(0x0100, ctl + CTL_CLK_AND_WAIT_CTL); + sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0100); msleep(10); } static void reset(struct tmio_mmc_host *host) { - void __iomem *ctl = host->ctl; - /* FIXME - should we set stop clock reg here */ - tmio_iowrite16(0x0000, ctl + CTL_RESET_SD); - tmio_iowrite16(0x0000, ctl + CTL_RESET_SDIO); + sd_ctrl_write16(host, CTL_RESET_SD, 0x0000); + sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0000); msleep(10); - tmio_iowrite16(0x0001, ctl + CTL_RESET_SD); - tmio_iowrite16(0x0001, ctl + CTL_RESET_SDIO); + sd_ctrl_write16(host, CTL_RESET_SD, 0x0001); + sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0001); msleep(10); } @@ -129,13 +107,12 @@ tmio_mmc_finish_request(struct tmio_mmc_host *host) static int tmio_mmc_start_command(struct tmio_mmc_host *host, struct mmc_command *cmd) { - void __iomem *ctl = host->ctl; struct mmc_data *data = host->data; int c = cmd->opcode; /* Command 12 is handled by hardware */ if (cmd->opcode == 12 && !cmd->arg) { - tmio_iowrite16(0x001, ctl + CTL_STOP_INTERNAL_ACTION); + sd_ctrl_write16(host, CTL_STOP_INTERNAL_ACTION, 0x001); return 0; } @@ -160,18 +137,18 @@ tmio_mmc_start_command(struct tmio_mmc_host *host, struct mmc_command *cmd) if (data) { c |= DATA_PRESENT; if (data->blocks > 1) { - tmio_iowrite16(0x100, ctl + CTL_STOP_INTERNAL_ACTION); + sd_ctrl_write16(host, CTL_STOP_INTERNAL_ACTION, 0x100); c |= TRANSFER_MULTI; } if (data->flags & MMC_DATA_READ) c |= TRANSFER_READ; } - enable_mmc_irqs(ctl, TMIO_MASK_CMD); + enable_mmc_irqs(host, TMIO_MASK_CMD); /* Fire off the command */ - tmio_iowrite32(cmd->arg, ctl + CTL_ARG_REG); - tmio_iowrite16(c, ctl + CTL_SD_CMD); + sd_ctrl_write32(host, CTL_ARG_REG, cmd->arg); + sd_ctrl_write16(host, CTL_SD_CMD, c); return 0; } @@ -183,7 +160,6 @@ tmio_mmc_start_command(struct tmio_mmc_host *host, struct mmc_command *cmd) */ static inline void tmio_mmc_pio_irq(struct tmio_mmc_host *host) { - void __iomem *ctl = host->ctl; struct mmc_data *data = host->data; unsigned short *buf; unsigned int count; @@ -206,9 +182,9 @@ static inline void tmio_mmc_pio_irq(struct tmio_mmc_host *host) /* Transfer the data */ if (data->flags & MMC_DATA_READ) - tmio_ioread16_rep(ctl + CTL_SD_DATA_PORT, buf, count >> 1); + sd_ctrl_read16_rep(host, CTL_SD_DATA_PORT, buf, count >> 1); else - tmio_iowrite16_rep(ctl + CTL_SD_DATA_PORT, buf, count >> 1); + sd_ctrl_write16_rep(host, CTL_SD_DATA_PORT, buf, count >> 1); host->sg_off += count; @@ -222,7 +198,6 @@ static inline void tmio_mmc_pio_irq(struct tmio_mmc_host *host) static inline void tmio_mmc_data_irq(struct tmio_mmc_host *host) { - void __iomem *ctl = host->ctl; struct mmc_data *data = host->data; struct mmc_command *stop; @@ -251,13 +226,13 @@ static inline void tmio_mmc_data_irq(struct tmio_mmc_host *host) */ if (data->flags & MMC_DATA_READ) - disable_mmc_irqs(ctl, TMIO_MASK_READOP); + disable_mmc_irqs(host, TMIO_MASK_READOP); else - disable_mmc_irqs(ctl, TMIO_MASK_WRITEOP); + disable_mmc_irqs(host, TMIO_MASK_WRITEOP); if (stop) { if (stop->opcode == 12 && !stop->arg) - tmio_iowrite16(0x000, ctl + CTL_STOP_INTERNAL_ACTION); + sd_ctrl_write16(host, CTL_STOP_INTERNAL_ACTION, 0x000); else BUG(); } @@ -268,9 +243,8 @@ static inline void tmio_mmc_data_irq(struct tmio_mmc_host *host) static inline void tmio_mmc_cmd_irq(struct tmio_mmc_host *host, unsigned int stat) { - void __iomem *ctl = host->ctl, *addr; struct mmc_command *cmd = host->cmd; - int i; + int i, addr; if (!host->cmd) { pr_debug("Spurious CMD irq\n"); @@ -284,8 +258,8 @@ static inline void tmio_mmc_cmd_irq(struct tmio_mmc_host *host, * modify the order of the response for short response command types. */ - for (i = 3, addr = ctl + CTL_RESPONSE ; i >= 0 ; i--, addr += 4) - cmd->resp[i] = tmio_ioread32(addr); + for (i = 3, addr = CTL_RESPONSE ; i >= 0 ; i--, addr += 4) + cmd->resp[i] = sd_ctrl_read32(host, addr); if (cmd->flags & MMC_RSP_136) { cmd->resp[0] = (cmd->resp[0] << 8) | (cmd->resp[1] >> 24); @@ -307,9 +281,9 @@ static inline void tmio_mmc_cmd_irq(struct tmio_mmc_host *host, */ if (host->data && !cmd->error) { if (host->data->flags & MMC_DATA_READ) - enable_mmc_irqs(ctl, TMIO_MASK_READOP); + enable_mmc_irqs(host, TMIO_MASK_READOP); else - enable_mmc_irqs(ctl, TMIO_MASK_WRITEOP); + enable_mmc_irqs(host, TMIO_MASK_WRITEOP); } else { tmio_mmc_finish_request(host); } @@ -321,20 +295,19 @@ static inline void tmio_mmc_cmd_irq(struct tmio_mmc_host *host, static irqreturn_t tmio_mmc_irq(int irq, void *devid) { struct tmio_mmc_host *host = devid; - void __iomem *ctl = host->ctl; unsigned int ireg, irq_mask, status; pr_debug("MMC IRQ begin\n"); - status = tmio_ioread32(ctl + CTL_STATUS); - irq_mask = tmio_ioread32(ctl + CTL_IRQ_MASK); + status = sd_ctrl_read32(host, CTL_STATUS); + irq_mask = sd_ctrl_read32(host, CTL_IRQ_MASK); ireg = status & TMIO_MASK_IRQ & ~irq_mask; pr_debug_status(status); pr_debug_status(ireg); if (!ireg) { - disable_mmc_irqs(ctl, status & ~irq_mask); + disable_mmc_irqs(host, status & ~irq_mask); pr_debug("tmio_mmc: Spurious irq, disabling! " "0x%08x 0x%08x 0x%08x\n", status, irq_mask, ireg); @@ -346,7 +319,7 @@ static irqreturn_t tmio_mmc_irq(int irq, void *devid) while (ireg) { /* Card insert / remove attempts */ if (ireg & (TMIO_STAT_CARD_INSERT | TMIO_STAT_CARD_REMOVE)) { - ack_mmc_irqs(ctl, TMIO_STAT_CARD_INSERT | + ack_mmc_irqs(host, TMIO_STAT_CARD_INSERT | TMIO_STAT_CARD_REMOVE); mmc_detect_change(host->mmc, 0); } @@ -358,25 +331,25 @@ static irqreturn_t tmio_mmc_irq(int irq, void *devid) /* Command completion */ if (ireg & TMIO_MASK_CMD) { - ack_mmc_irqs(ctl, TMIO_MASK_CMD); + ack_mmc_irqs(host, TMIO_MASK_CMD); tmio_mmc_cmd_irq(host, status); } /* Data transfer */ if (ireg & (TMIO_STAT_RXRDY | TMIO_STAT_TXRQ)) { - ack_mmc_irqs(ctl, TMIO_STAT_RXRDY | TMIO_STAT_TXRQ); + ack_mmc_irqs(host, TMIO_STAT_RXRDY | TMIO_STAT_TXRQ); tmio_mmc_pio_irq(host); } /* Data transfer completion */ if (ireg & TMIO_STAT_DATAEND) { - ack_mmc_irqs(ctl, TMIO_STAT_DATAEND); + ack_mmc_irqs(host, TMIO_STAT_DATAEND); tmio_mmc_data_irq(host); } /* Check status - keep going until we've handled it all */ - status = tmio_ioread32(ctl + CTL_STATUS); - irq_mask = tmio_ioread32(ctl + CTL_IRQ_MASK); + status = sd_ctrl_read32(host, CTL_STATUS); + irq_mask = sd_ctrl_read32(host, CTL_IRQ_MASK); ireg = status & TMIO_MASK_IRQ & ~irq_mask; pr_debug("Status at end of loop: %08x\n", status); @@ -391,8 +364,6 @@ out: static int tmio_mmc_start_data(struct tmio_mmc_host *host, struct mmc_data *data) { - void __iomem *ctl = host->ctl; - pr_debug("setup data transfer: blocksize %08x nr_blocks %d\n", data->blksz, data->blocks); @@ -407,8 +378,8 @@ static int tmio_mmc_start_data(struct tmio_mmc_host *host, host->data = data; /* Set transfer length / blocksize */ - tmio_iowrite16(data->blksz, ctl + CTL_SD_XFER_LEN); - tmio_iowrite16(data->blocks, ctl + CTL_XFER_BLK_COUNT); + sd_ctrl_write16(host, CTL_SD_XFER_LEN, data->blksz); + sd_ctrl_write16(host, CTL_XFER_BLK_COUNT, data->blocks); return 0; } @@ -449,8 +420,6 @@ fail: static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { struct tmio_mmc_host *host = mmc_priv(mmc); - void __iomem *cnf = host->cnf; - void __iomem *ctl = host->ctl; if (ios->clock) tmio_mmc_set_clock(host, ios->clock); @@ -458,12 +427,12 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) /* Power sequence - OFF -> ON -> UP */ switch (ios->power_mode) { case MMC_POWER_OFF: /* power down SD bus */ - tmio_iowrite8(0x00, cnf + CNF_PWR_CTL_2); + sd_config_write8(host, CNF_PWR_CTL_2, 0x00); tmio_mmc_clk_stop(host); break; case MMC_POWER_ON: /* power up SD bus */ - tmio_iowrite8(0x02, cnf + CNF_PWR_CTL_2); + sd_config_write8(host, CNF_PWR_CTL_2, 0x02); break; case MMC_POWER_UP: /* start bus clock */ tmio_mmc_clk_start(host); @@ -472,10 +441,10 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) switch (ios->bus_width) { case MMC_BUS_WIDTH_1: - tmio_iowrite16(0x80e0, ctl + CTL_SD_MEM_CARD_OPT); + sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x80e0); break; case MMC_BUS_WIDTH_4: - tmio_iowrite16(0x00e0, ctl + CTL_SD_MEM_CARD_OPT); + sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x00e0); break; } @@ -486,9 +455,8 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) static int tmio_mmc_get_ro(struct mmc_host *mmc) { struct tmio_mmc_host *host = mmc_priv(mmc); - void __iomem *ctl = host->ctl; - return (tmio_ioread16(ctl + CTL_STATUS) & TMIO_STAT_WRPROTECT) ? 0 : 1; + return (sd_ctrl_read16(host, CTL_STATUS) & TMIO_STAT_WRPROTECT) ? 0 : 1; } static struct mmc_host_ops tmio_mmc_ops = { @@ -518,13 +486,8 @@ static int tmio_mmc_resume(struct platform_device *dev) struct mfd_cell *cell = (struct mfd_cell *)dev->dev.platform_data; struct mmc_host *mmc = platform_get_drvdata(dev); struct tmio_mmc_host *host = mmc_priv(mmc); - void __iomem *cnf = host->cnf; int ret = 0; - /* Enable the MMC/SD Control registers */ - tmio_iowrite16(SDCREN, cnf + CNF_CMD); - tmio_iowrite32(dev->resource[0].start & 0xfffe, cnf + CNF_CTL_BASE); - /* Tell the MFD core we are ready to be enabled */ if (cell->enable) { ret = cell->enable(dev); @@ -532,6 +495,11 @@ static int tmio_mmc_resume(struct platform_device *dev) goto out; } + /* Enable the MMC/SD Control registers */ + sd_config_write16(host, CNF_CMD, SDCREN); + sd_config_write32(host, CNF_CTL_BASE, + (dev->resource[0].start >> host->bus_shift) & 0xfffe); + mmc_resume_host(mmc); out: @@ -545,20 +513,25 @@ out: static int __devinit tmio_mmc_probe(struct platform_device *dev) { struct mfd_cell *cell = (struct mfd_cell *)dev->dev.platform_data; + struct tmio_mmc_data *pdata; struct resource *res_ctl, *res_cnf; struct tmio_mmc_host *host; struct mmc_host *mmc; - int ret = -ENOMEM; + int ret = -EINVAL; if (dev->num_resources != 3) goto out; res_ctl = platform_get_resource(dev, IORESOURCE_MEM, 0); res_cnf = platform_get_resource(dev, IORESOURCE_MEM, 1); - if (!res_ctl || !res_cnf) { - ret = -EINVAL; + if (!res_ctl || !res_cnf) goto out; - } + + pdata = cell->driver_data; + if (!pdata || !pdata->hclk) + goto out; + + ret = -ENOMEM; mmc = mmc_alloc_host(sizeof(struct tmio_mmc_host), &dev->dev); if (!mmc) @@ -568,6 +541,9 @@ static int __devinit tmio_mmc_probe(struct platform_device *dev) host->mmc = mmc; platform_set_drvdata(dev, mmc); + /* SD control register space size is 0x200, 0x400 for bus_shift=1 */ + host->bus_shift = resource_size(res_ctl) >> 10; + host->ctl = ioremap(res_ctl->start, resource_size(res_ctl)); if (!host->ctl) goto host_free; @@ -578,15 +554,10 @@ static int __devinit tmio_mmc_probe(struct platform_device *dev) mmc->ops = &tmio_mmc_ops; mmc->caps = MMC_CAP_4_BIT_DATA; - mmc->f_min = 46875; /* 24000000 / 512 */ - mmc->f_max = 24000000; + mmc->f_max = pdata->hclk; + mmc->f_min = mmc->f_max / 512; mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; - /* Enable the MMC/SD Control registers */ - tmio_iowrite16(SDCREN, host->cnf + CNF_CMD); - tmio_iowrite32(dev->resource[0].start & 0xfffe, - host->cnf + CNF_CTL_BASE); - /* Tell the MFD core we are ready to be enabled */ if (cell->enable) { ret = cell->enable(dev); @@ -594,14 +565,19 @@ static int __devinit tmio_mmc_probe(struct platform_device *dev) goto unmap_cnf; } + /* Enable the MMC/SD Control registers */ + sd_config_write16(host, CNF_CMD, SDCREN); + sd_config_write32(host, CNF_CTL_BASE, + (dev->resource[0].start >> host->bus_shift) & 0xfffe); + /* Disable SD power during suspend */ - tmio_iowrite8(0x01, host->cnf + CNF_PWR_CTL_3); + sd_config_write8(host, CNF_PWR_CTL_3, 0x01); /* The below is required but why? FIXME */ - tmio_iowrite8(0x1f, host->cnf + CNF_STOP_CLK_CTL); + sd_config_write8(host, CNF_STOP_CLK_CTL, 0x1f); /* Power down SD bus*/ - tmio_iowrite8(0x0, host->cnf + CNF_PWR_CTL_2); + sd_config_write8(host, CNF_PWR_CTL_2, 0x00); tmio_mmc_clk_stop(host); reset(host); @@ -612,22 +588,20 @@ static int __devinit tmio_mmc_probe(struct platform_device *dev) else goto unmap_cnf; - disable_mmc_irqs(host->ctl, TMIO_MASK_ALL); + disable_mmc_irqs(host, TMIO_MASK_ALL); - ret = request_irq(host->irq, tmio_mmc_irq, IRQF_DISABLED, "tmio-mmc", - host); + ret = request_irq(host->irq, tmio_mmc_irq, IRQF_DISABLED | + IRQF_TRIGGER_FALLING, "tmio-mmc", host); if (ret) goto unmap_cnf; - set_irq_type(host->irq, IRQ_TYPE_EDGE_FALLING); - mmc_add_host(mmc); printk(KERN_INFO "%s at 0x%08lx irq %d\n", mmc_hostname(host->mmc), (unsigned long)host->ctl, host->irq); /* Unmask the IRQs we want to know about */ - enable_mmc_irqs(host->ctl, TMIO_MASK_IRQ); + enable_mmc_irqs(host, TMIO_MASK_IRQ); return 0; diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index 9c831ab2ece6..9fa998594974 100644 --- a/drivers/mmc/host/tmio_mmc.h +++ b/drivers/mmc/host/tmio_mmc.h @@ -83,34 +83,36 @@ TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT) #define TMIO_MASK_IRQ (TMIO_MASK_READOP | TMIO_MASK_WRITEOP | TMIO_MASK_CMD) -#define enable_mmc_irqs(ctl, i) \ + +#define enable_mmc_irqs(host, i) \ do { \ u32 mask;\ - mask = tmio_ioread32((ctl) + CTL_IRQ_MASK); \ + mask = sd_ctrl_read32((host), CTL_IRQ_MASK); \ mask &= ~((i) & TMIO_MASK_IRQ); \ - tmio_iowrite32(mask, (ctl) + CTL_IRQ_MASK); \ + sd_ctrl_write32((host), CTL_IRQ_MASK, mask); \ } while (0) -#define disable_mmc_irqs(ctl, i) \ +#define disable_mmc_irqs(host, i) \ do { \ u32 mask;\ - mask = tmio_ioread32((ctl) + CTL_IRQ_MASK); \ + mask = sd_ctrl_read32((host), CTL_IRQ_MASK); \ mask |= ((i) & TMIO_MASK_IRQ); \ - tmio_iowrite32(mask, (ctl) + CTL_IRQ_MASK); \ + sd_ctrl_write32((host), CTL_IRQ_MASK, mask); \ } while (0) -#define ack_mmc_irqs(ctl, i) \ +#define ack_mmc_irqs(host, i) \ do { \ u32 mask;\ - mask = tmio_ioread32((ctl) + CTL_STATUS); \ + mask = sd_ctrl_read32((host), CTL_STATUS); \ mask &= ~((i) & TMIO_MASK_IRQ); \ - tmio_iowrite32(mask, (ctl) + CTL_STATUS); \ + sd_ctrl_write32((host), CTL_STATUS, mask); \ } while (0) struct tmio_mmc_host { void __iomem *cnf; void __iomem *ctl; + unsigned long bus_shift; struct mmc_command *cmd; struct mmc_request *mrq; struct mmc_data *data; @@ -123,6 +125,63 @@ struct tmio_mmc_host { unsigned int sg_off; }; +#include + +static inline u16 sd_ctrl_read16(struct tmio_mmc_host *host, int addr) +{ + return readw(host->ctl + (addr << host->bus_shift)); +} + +static inline void sd_ctrl_read16_rep(struct tmio_mmc_host *host, int addr, + u16 *buf, int count) +{ + readsw(host->ctl + (addr << host->bus_shift), buf, count); +} + +static inline u32 sd_ctrl_read32(struct tmio_mmc_host *host, int addr) +{ + return readw(host->ctl + (addr << host->bus_shift)) | + readw(host->ctl + ((addr + 2) << host->bus_shift)) << 16; +} + +static inline void sd_ctrl_write16(struct tmio_mmc_host *host, int addr, + u16 val) +{ + writew(val, host->ctl + (addr << host->bus_shift)); +} + +static inline void sd_ctrl_write16_rep(struct tmio_mmc_host *host, int addr, + u16 *buf, int count) +{ + writesw(host->ctl + (addr << host->bus_shift), buf, count); +} + +static inline void sd_ctrl_write32(struct tmio_mmc_host *host, int addr, + u32 val) +{ + writew(val, host->ctl + (addr << host->bus_shift)); + writew(val >> 16, host->ctl + ((addr + 2) << host->bus_shift)); +} + +static inline void sd_config_write8(struct tmio_mmc_host *host, int addr, + u8 val) +{ + writeb(val, host->cnf + (addr << host->bus_shift)); +} + +static inline void sd_config_write16(struct tmio_mmc_host *host, int addr, + u16 val) +{ + writew(val, host->cnf + (addr << host->bus_shift)); +} + +static inline void sd_config_write32(struct tmio_mmc_host *host, int addr, + u32 val) +{ + writew(val, host->cnf + (addr << host->bus_shift)); + writew(val >> 16, host->cnf + ((addr + 2) << host->bus_shift)); +} + #include #include diff --git a/drivers/mmc/host/via-sdmmc.c b/drivers/mmc/host/via-sdmmc.c new file mode 100644 index 000000000000..632858a94376 --- /dev/null +++ b/drivers/mmc/host/via-sdmmc.c @@ -0,0 +1,1362 @@ +/* + * drivers/mmc/host/via-sdmmc.c - VIA SD/MMC Card Reader driver + * Copyright (c) 2008, VIA Technologies 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. + */ + +#include +#include +#include +#include + +#include + +#define DRV_NAME "via_sdmmc" + +#define PCI_DEVICE_ID_VIA_9530 0x9530 + +#define VIA_CRDR_SDC_OFF 0x200 +#define VIA_CRDR_DDMA_OFF 0x400 +#define VIA_CRDR_PCICTRL_OFF 0x600 + +#define VIA_CRDR_MIN_CLOCK 375000 +#define VIA_CRDR_MAX_CLOCK 48000000 + +/* + * PCI registers + */ + +#define VIA_CRDR_PCI_WORK_MODE 0x40 +#define VIA_CRDR_PCI_DBG_MODE 0x41 + +/* + * SDC MMIO Registers + */ + +#define VIA_CRDR_SDCTRL 0x0 +#define VIA_CRDR_SDCTRL_START 0x01 +#define VIA_CRDR_SDCTRL_WRITE 0x04 +#define VIA_CRDR_SDCTRL_SINGLE_WR 0x10 +#define VIA_CRDR_SDCTRL_SINGLE_RD 0x20 +#define VIA_CRDR_SDCTRL_MULTI_WR 0x30 +#define VIA_CRDR_SDCTRL_MULTI_RD 0x40 +#define VIA_CRDR_SDCTRL_STOP 0x70 + +#define VIA_CRDR_SDCTRL_RSP_NONE 0x0 +#define VIA_CRDR_SDCTRL_RSP_R1 0x10000 +#define VIA_CRDR_SDCTRL_RSP_R2 0x20000 +#define VIA_CRDR_SDCTRL_RSP_R3 0x30000 +#define VIA_CRDR_SDCTRL_RSP_R1B 0x90000 + +#define VIA_CRDR_SDCARG 0x4 + +#define VIA_CRDR_SDBUSMODE 0x8 +#define VIA_CRDR_SDMODE_4BIT 0x02 +#define VIA_CRDR_SDMODE_CLK_ON 0x40 + +#define VIA_CRDR_SDBLKLEN 0xc +/* + * Bit 0 -Bit 10 : Block length. So, the maximum block length should be 2048. + * Bit 11 - Bit 13 : Reserved. + * GPIDET : Select GPI pin to detect card, GPI means CR_CD# in top design. + * INTEN : Enable SD host interrupt. + * Bit 16 - Bit 31 : Block count. So, the maximun block count should be 65536. + */ +#define VIA_CRDR_SDBLKLEN_GPIDET 0x2000 +#define VIA_CRDR_SDBLKLEN_INTEN 0x8000 +#define VIA_CRDR_MAX_BLOCK_COUNT 65536 +#define VIA_CRDR_MAX_BLOCK_LENGTH 2048 + +#define VIA_CRDR_SDRESP0 0x10 +#define VIA_CRDR_SDRESP1 0x14 +#define VIA_CRDR_SDRESP2 0x18 +#define VIA_CRDR_SDRESP3 0x1c + +#define VIA_CRDR_SDCURBLKCNT 0x20 + +#define VIA_CRDR_SDINTMASK 0x24 +/* + * MBDIE : Multiple Blocks transfer Done Interrupt Enable + * BDDIE : Block Data transfer Done Interrupt Enable + * CIRIE : Card Insertion or Removal Interrupt Enable + * CRDIE : Command-Response transfer Done Interrupt Enable + * CRTOIE : Command-Response response TimeOut Interrupt Enable + * ASCRDIE : Auto Stop Command-Response transfer Done Interrupt Enable + * DTIE : Data access Timeout Interrupt Enable + * SCIE : reSponse CRC error Interrupt Enable + * RCIE : Read data CRC error Interrupt Enable + * WCIE : Write data CRC error Interrupt Enable + */ +#define VIA_CRDR_SDINTMASK_MBDIE 0x10 +#define VIA_CRDR_SDINTMASK_BDDIE 0x20 +#define VIA_CRDR_SDINTMASK_CIRIE 0x80 +#define VIA_CRDR_SDINTMASK_CRDIE 0x200 +#define VIA_CRDR_SDINTMASK_CRTOIE 0x400 +#define VIA_CRDR_SDINTMASK_ASCRDIE 0x800 +#define VIA_CRDR_SDINTMASK_DTIE 0x1000 +#define VIA_CRDR_SDINTMASK_SCIE 0x2000 +#define VIA_CRDR_SDINTMASK_RCIE 0x4000 +#define VIA_CRDR_SDINTMASK_WCIE 0x8000 + +#define VIA_CRDR_SDACTIVE_INTMASK \ + (VIA_CRDR_SDINTMASK_MBDIE | VIA_CRDR_SDINTMASK_CIRIE \ + | VIA_CRDR_SDINTMASK_CRDIE | VIA_CRDR_SDINTMASK_CRTOIE \ + | VIA_CRDR_SDINTMASK_DTIE | VIA_CRDR_SDINTMASK_SCIE \ + | VIA_CRDR_SDINTMASK_RCIE | VIA_CRDR_SDINTMASK_WCIE) + +#define VIA_CRDR_SDSTATUS 0x28 +/* + * CECC : Reserved + * WP : SD card Write Protect status + * SLOTD : Reserved + * SLOTG : SD SLOT status(Gpi pin status) + * MBD : Multiple Blocks transfer Done interrupt status + * BDD : Block Data transfer Done interrupt status + * CD : Reserved + * CIR : Card Insertion or Removal interrupt detected on GPI pin + * IO : Reserved + * CRD : Command-Response transfer Done interrupt status + * CRTO : Command-Response response TimeOut interrupt status + * ASCRDIE : Auto Stop Command-Response transfer Done interrupt status + * DT : Data access Timeout interrupt status + * SC : reSponse CRC error interrupt status + * RC : Read data CRC error interrupt status + * WC : Write data CRC error interrupt status + */ +#define VIA_CRDR_SDSTS_CECC 0x01 +#define VIA_CRDR_SDSTS_WP 0x02 +#define VIA_CRDR_SDSTS_SLOTD 0x04 +#define VIA_CRDR_SDSTS_SLOTG 0x08 +#define VIA_CRDR_SDSTS_MBD 0x10 +#define VIA_CRDR_SDSTS_BDD 0x20 +#define VIA_CRDR_SDSTS_CD 0x40 +#define VIA_CRDR_SDSTS_CIR 0x80 +#define VIA_CRDR_SDSTS_IO 0x100 +#define VIA_CRDR_SDSTS_CRD 0x200 +#define VIA_CRDR_SDSTS_CRTO 0x400 +#define VIA_CRDR_SDSTS_ASCRDIE 0x800 +#define VIA_CRDR_SDSTS_DT 0x1000 +#define VIA_CRDR_SDSTS_SC 0x2000 +#define VIA_CRDR_SDSTS_RC 0x4000 +#define VIA_CRDR_SDSTS_WC 0x8000 + +#define VIA_CRDR_SDSTS_IGN_MASK\ + (VIA_CRDR_SDSTS_BDD | VIA_CRDR_SDSTS_ASCRDIE | VIA_CRDR_SDSTS_IO) +#define VIA_CRDR_SDSTS_INT_MASK \ + (VIA_CRDR_SDSTS_MBD | VIA_CRDR_SDSTS_BDD | VIA_CRDR_SDSTS_CD \ + | VIA_CRDR_SDSTS_CIR | VIA_CRDR_SDSTS_IO | VIA_CRDR_SDSTS_CRD \ + | VIA_CRDR_SDSTS_CRTO | VIA_CRDR_SDSTS_ASCRDIE | VIA_CRDR_SDSTS_DT \ + | VIA_CRDR_SDSTS_SC | VIA_CRDR_SDSTS_RC | VIA_CRDR_SDSTS_WC) +#define VIA_CRDR_SDSTS_W1C_MASK \ + (VIA_CRDR_SDSTS_CECC | VIA_CRDR_SDSTS_MBD | VIA_CRDR_SDSTS_BDD \ + | VIA_CRDR_SDSTS_CD | VIA_CRDR_SDSTS_CIR | VIA_CRDR_SDSTS_CRD \ + | VIA_CRDR_SDSTS_CRTO | VIA_CRDR_SDSTS_ASCRDIE | VIA_CRDR_SDSTS_DT \ + | VIA_CRDR_SDSTS_SC | VIA_CRDR_SDSTS_RC | VIA_CRDR_SDSTS_WC) +#define VIA_CRDR_SDSTS_CMD_MASK \ + (VIA_CRDR_SDSTS_CRD | VIA_CRDR_SDSTS_CRTO | VIA_CRDR_SDSTS_SC) +#define VIA_CRDR_SDSTS_DATA_MASK\ + (VIA_CRDR_SDSTS_MBD | VIA_CRDR_SDSTS_DT \ + | VIA_CRDR_SDSTS_RC | VIA_CRDR_SDSTS_WC) + +#define VIA_CRDR_SDSTATUS2 0x2a +/* + * CFE : Enable SD host automatic Clock FReezing + */ +#define VIA_CRDR_SDSTS_CFE 0x80 + +#define VIA_CRDR_SDRSPTMO 0x2C + +#define VIA_CRDR_SDCLKSEL 0x30 + +#define VIA_CRDR_SDEXTCTRL 0x34 +#define VIS_CRDR_SDEXTCTRL_AUTOSTOP_SD 0x01 +#define VIS_CRDR_SDEXTCTRL_SHIFT_9 0x02 +#define VIS_CRDR_SDEXTCTRL_MMC_8BIT 0x04 +#define VIS_CRDR_SDEXTCTRL_RELD_BLK 0x08 +#define VIS_CRDR_SDEXTCTRL_BAD_CMDA 0x10 +#define VIS_CRDR_SDEXTCTRL_BAD_DATA 0x20 +#define VIS_CRDR_SDEXTCTRL_AUTOSTOP_SPI 0x40 +#define VIA_CRDR_SDEXTCTRL_HISPD 0x80 +/* 0x38-0xFF reserved */ + +/* + * Data DMA Control Registers + */ + +#define VIA_CRDR_DMABASEADD 0x0 +#define VIA_CRDR_DMACOUNTER 0x4 + +#define VIA_CRDR_DMACTRL 0x8 +/* + * DIR :Transaction Direction + * 0 : From card to memory + * 1 : From memory to card + */ +#define VIA_CRDR_DMACTRL_DIR 0x100 +#define VIA_CRDR_DMACTRL_ENIRQ 0x10000 +#define VIA_CRDR_DMACTRL_SFTRST 0x1000000 + +#define VIA_CRDR_DMASTS 0xc + +#define VIA_CRDR_DMASTART 0x10 +/*0x14-0xFF reserved*/ + +/* + * PCI Control Registers + */ + +/*0x0 - 0x1 reserved*/ +#define VIA_CRDR_PCICLKGATT 0x2 +/* + * SFTRST : + * 0 : Soft reset all the controller and it will be de-asserted automatically + * 1 : Soft reset is de-asserted + */ +#define VIA_CRDR_PCICLKGATT_SFTRST 0x01 +/* + * 3V3 : Pad power select + * 0 : 1.8V + * 1 : 3.3V + * NOTE : No mater what the actual value should be, this bit always + * read as 0. This is a hardware bug. + */ +#define VIA_CRDR_PCICLKGATT_3V3 0x10 +/* + * PAD_PWRON : Pad Power on/off select + * 0 : Power off + * 1 : Power on + * NOTE : No mater what the actual value should be, this bit always + * read as 0. This is a hardware bug. + */ +#define VIA_CRDR_PCICLKGATT_PAD_PWRON 0x20 + +#define VIA_CRDR_PCISDCCLK 0x5 + +#define VIA_CRDR_PCIDMACLK 0x7 +#define VIA_CRDR_PCIDMACLK_SDC 0x2 + +#define VIA_CRDR_PCIINTCTRL 0x8 +#define VIA_CRDR_PCIINTCTRL_SDCIRQEN 0x04 + +#define VIA_CRDR_PCIINTSTATUS 0x9 +#define VIA_CRDR_PCIINTSTATUS_SDC 0x04 + +#define VIA_CRDR_PCITMOCTRL 0xa +#define VIA_CRDR_PCITMOCTRL_NO 0x0 +#define VIA_CRDR_PCITMOCTRL_32US 0x1 +#define VIA_CRDR_PCITMOCTRL_256US 0x2 +#define VIA_CRDR_PCITMOCTRL_1024US 0x3 +#define VIA_CRDR_PCITMOCTRL_256MS 0x4 +#define VIA_CRDR_PCITMOCTRL_512MS 0x5 +#define VIA_CRDR_PCITMOCTRL_1024MS 0x6 + +/*0xB-0xFF reserved*/ + +enum PCI_HOST_CLK_CONTROL { + PCI_CLK_375K = 0x03, + PCI_CLK_8M = 0x04, + PCI_CLK_12M = 0x00, + PCI_CLK_16M = 0x05, + PCI_CLK_24M = 0x01, + PCI_CLK_33M = 0x06, + PCI_CLK_48M = 0x02 +}; + +struct sdhcreg { + u32 sdcontrol_reg; + u32 sdcmdarg_reg; + u32 sdbusmode_reg; + u32 sdblklen_reg; + u32 sdresp_reg[4]; + u32 sdcurblkcnt_reg; + u32 sdintmask_reg; + u32 sdstatus_reg; + u32 sdrsptmo_reg; + u32 sdclksel_reg; + u32 sdextctrl_reg; +}; + +struct pcictrlreg { + u8 reserve[2]; + u8 pciclkgat_reg; + u8 pcinfcclk_reg; + u8 pcimscclk_reg; + u8 pcisdclk_reg; + u8 pcicaclk_reg; + u8 pcidmaclk_reg; + u8 pciintctrl_reg; + u8 pciintstatus_reg; + u8 pcitmoctrl_reg; + u8 Resv; +}; + +struct via_crdr_mmc_host { + struct mmc_host *mmc; + struct mmc_request *mrq; + struct mmc_command *cmd; + struct mmc_data *data; + + void __iomem *mmiobase; + void __iomem *sdhc_mmiobase; + void __iomem *ddma_mmiobase; + void __iomem *pcictrl_mmiobase; + + struct pcictrlreg pm_pcictrl_reg; + struct sdhcreg pm_sdhc_reg; + + struct work_struct carddet_work; + struct tasklet_struct finish_tasklet; + + struct timer_list timer; + spinlock_t lock; + u8 power; + int reject; + unsigned int quirks; +}; + +/* some devices need a very long delay for power to stabilize */ +#define VIA_CRDR_QUIRK_300MS_PWRDELAY 0x0001 + +static struct pci_device_id via_ids[] = { + {PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_9530, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0,}, + {0,} +}; + +MODULE_DEVICE_TABLE(pci, via_ids); + +static void via_print_sdchc(struct via_crdr_mmc_host *host) +{ + void __iomem *addrbase = host->sdhc_mmiobase; + + pr_debug("SDC MMIO Registers:\n"); + pr_debug("SDCONTROL=%08x, SDCMDARG=%08x, SDBUSMODE=%08x\n", + readl(addrbase + VIA_CRDR_SDCTRL), + readl(addrbase + VIA_CRDR_SDCARG), + readl(addrbase + VIA_CRDR_SDBUSMODE)); + pr_debug("SDBLKLEN=%08x, SDCURBLKCNT=%08x, SDINTMASK=%08x\n", + readl(addrbase + VIA_CRDR_SDBLKLEN), + readl(addrbase + VIA_CRDR_SDCURBLKCNT), + readl(addrbase + VIA_CRDR_SDINTMASK)); + pr_debug("SDSTATUS=%08x, SDCLKSEL=%08x, SDEXTCTRL=%08x\n", + readl(addrbase + VIA_CRDR_SDSTATUS), + readl(addrbase + VIA_CRDR_SDCLKSEL), + readl(addrbase + VIA_CRDR_SDEXTCTRL)); +} + +static void via_print_pcictrl(struct via_crdr_mmc_host *host) +{ + void __iomem *addrbase = host->pcictrl_mmiobase; + + pr_debug("PCI Control Registers:\n"); + pr_debug("PCICLKGATT=%02x, PCISDCCLK=%02x, PCIDMACLK=%02x\n", + readb(addrbase + VIA_CRDR_PCICLKGATT), + readb(addrbase + VIA_CRDR_PCISDCCLK), + readb(addrbase + VIA_CRDR_PCIDMACLK)); + pr_debug("PCIINTCTRL=%02x, PCIINTSTATUS=%02x\n", + readb(addrbase + VIA_CRDR_PCIINTCTRL), + readb(addrbase + VIA_CRDR_PCIINTSTATUS)); +} + +static void via_save_pcictrlreg(struct via_crdr_mmc_host *host) +{ + struct pcictrlreg *pm_pcictrl_reg; + void __iomem *addrbase; + + pm_pcictrl_reg = &(host->pm_pcictrl_reg); + addrbase = host->pcictrl_mmiobase; + + pm_pcictrl_reg->pciclkgat_reg = readb(addrbase + VIA_CRDR_PCICLKGATT); + pm_pcictrl_reg->pciclkgat_reg |= + VIA_CRDR_PCICLKGATT_3V3 | VIA_CRDR_PCICLKGATT_PAD_PWRON; + pm_pcictrl_reg->pcisdclk_reg = readb(addrbase + VIA_CRDR_PCISDCCLK); + pm_pcictrl_reg->pcidmaclk_reg = readb(addrbase + VIA_CRDR_PCIDMACLK); + pm_pcictrl_reg->pciintctrl_reg = readb(addrbase + VIA_CRDR_PCIINTCTRL); + pm_pcictrl_reg->pciintstatus_reg = + readb(addrbase + VIA_CRDR_PCIINTSTATUS); + pm_pcictrl_reg->pcitmoctrl_reg = readb(addrbase + VIA_CRDR_PCITMOCTRL); +} + +static void via_restore_pcictrlreg(struct via_crdr_mmc_host *host) +{ + struct pcictrlreg *pm_pcictrl_reg; + void __iomem *addrbase; + + pm_pcictrl_reg = &(host->pm_pcictrl_reg); + addrbase = host->pcictrl_mmiobase; + + writeb(pm_pcictrl_reg->pciclkgat_reg, addrbase + VIA_CRDR_PCICLKGATT); + writeb(pm_pcictrl_reg->pcisdclk_reg, addrbase + VIA_CRDR_PCISDCCLK); + writeb(pm_pcictrl_reg->pcidmaclk_reg, addrbase + VIA_CRDR_PCIDMACLK); + writeb(pm_pcictrl_reg->pciintctrl_reg, addrbase + VIA_CRDR_PCIINTCTRL); + writeb(pm_pcictrl_reg->pciintstatus_reg, + addrbase + VIA_CRDR_PCIINTSTATUS); + writeb(pm_pcictrl_reg->pcitmoctrl_reg, addrbase + VIA_CRDR_PCITMOCTRL); +} + +static void via_save_sdcreg(struct via_crdr_mmc_host *host) +{ + struct sdhcreg *pm_sdhc_reg; + void __iomem *addrbase; + + pm_sdhc_reg = &(host->pm_sdhc_reg); + addrbase = host->sdhc_mmiobase; + + pm_sdhc_reg->sdcontrol_reg = readl(addrbase + VIA_CRDR_SDCTRL); + pm_sdhc_reg->sdcmdarg_reg = readl(addrbase + VIA_CRDR_SDCARG); + pm_sdhc_reg->sdbusmode_reg = readl(addrbase + VIA_CRDR_SDBUSMODE); + pm_sdhc_reg->sdblklen_reg = readl(addrbase + VIA_CRDR_SDBLKLEN); + pm_sdhc_reg->sdcurblkcnt_reg = readl(addrbase + VIA_CRDR_SDCURBLKCNT); + pm_sdhc_reg->sdintmask_reg = readl(addrbase + VIA_CRDR_SDINTMASK); + pm_sdhc_reg->sdstatus_reg = readl(addrbase + VIA_CRDR_SDSTATUS); + pm_sdhc_reg->sdrsptmo_reg = readl(addrbase + VIA_CRDR_SDRSPTMO); + pm_sdhc_reg->sdclksel_reg = readl(addrbase + VIA_CRDR_SDCLKSEL); + pm_sdhc_reg->sdextctrl_reg = readl(addrbase + VIA_CRDR_SDEXTCTRL); +} + +static void via_restore_sdcreg(struct via_crdr_mmc_host *host) +{ + struct sdhcreg *pm_sdhc_reg; + void __iomem *addrbase; + + pm_sdhc_reg = &(host->pm_sdhc_reg); + addrbase = host->sdhc_mmiobase; + + writel(pm_sdhc_reg->sdcontrol_reg, addrbase + VIA_CRDR_SDCTRL); + writel(pm_sdhc_reg->sdcmdarg_reg, addrbase + VIA_CRDR_SDCARG); + writel(pm_sdhc_reg->sdbusmode_reg, addrbase + VIA_CRDR_SDBUSMODE); + writel(pm_sdhc_reg->sdblklen_reg, addrbase + VIA_CRDR_SDBLKLEN); + writel(pm_sdhc_reg->sdcurblkcnt_reg, addrbase + VIA_CRDR_SDCURBLKCNT); + writel(pm_sdhc_reg->sdintmask_reg, addrbase + VIA_CRDR_SDINTMASK); + writel(pm_sdhc_reg->sdstatus_reg, addrbase + VIA_CRDR_SDSTATUS); + writel(pm_sdhc_reg->sdrsptmo_reg, addrbase + VIA_CRDR_SDRSPTMO); + writel(pm_sdhc_reg->sdclksel_reg, addrbase + VIA_CRDR_SDCLKSEL); + writel(pm_sdhc_reg->sdextctrl_reg, addrbase + VIA_CRDR_SDEXTCTRL); +} + +static void via_pwron_sleep(struct via_crdr_mmc_host *sdhost) +{ + if (sdhost->quirks & VIA_CRDR_QUIRK_300MS_PWRDELAY) + msleep(300); + else + msleep(3); +} + +static void via_set_ddma(struct via_crdr_mmc_host *host, + dma_addr_t dmaaddr, u32 count, int dir, int enirq) +{ + void __iomem *addrbase; + u32 ctrl_data = 0; + + if (enirq) + ctrl_data |= VIA_CRDR_DMACTRL_ENIRQ; + + if (dir) + ctrl_data |= VIA_CRDR_DMACTRL_DIR; + + addrbase = host->ddma_mmiobase; + + writel(dmaaddr, addrbase + VIA_CRDR_DMABASEADD); + writel(count, addrbase + VIA_CRDR_DMACOUNTER); + writel(ctrl_data, addrbase + VIA_CRDR_DMACTRL); + writel(0x01, addrbase + VIA_CRDR_DMASTART); + + /* It seems that our DMA can not work normally with 375kHz clock */ + /* FIXME: don't brute-force 8MHz but use PIO at 375kHz !! */ + addrbase = host->pcictrl_mmiobase; + if (readb(addrbase + VIA_CRDR_PCISDCCLK) == PCI_CLK_375K) { + dev_info(host->mmc->parent, "forcing card speed to 8MHz\n"); + writeb(PCI_CLK_8M, addrbase + VIA_CRDR_PCISDCCLK); + } +} + +static void via_sdc_preparedata(struct via_crdr_mmc_host *host, + struct mmc_data *data) +{ + void __iomem *addrbase; + u32 blk_reg; + int count; + + WARN_ON(host->data); + + /* Sanity checks */ + BUG_ON(data->blksz > host->mmc->max_blk_size); + BUG_ON(data->blocks > host->mmc->max_blk_count); + + host->data = data; + + count = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, + ((data->flags & MMC_DATA_READ) ? + PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE)); + BUG_ON(count != 1); + + via_set_ddma(host, sg_dma_address(data->sg), sg_dma_len(data->sg), + (data->flags & MMC_DATA_WRITE) ? 1 : 0, 1); + + addrbase = host->sdhc_mmiobase; + + blk_reg = data->blksz - 1; + blk_reg |= VIA_CRDR_SDBLKLEN_GPIDET | VIA_CRDR_SDBLKLEN_INTEN; + blk_reg |= (data->blocks) << 16; + + writel(blk_reg, addrbase + VIA_CRDR_SDBLKLEN); +} + +static void via_sdc_get_response(struct via_crdr_mmc_host *host, + struct mmc_command *cmd) +{ + void __iomem *addrbase = host->sdhc_mmiobase; + u32 dwdata0 = readl(addrbase + VIA_CRDR_SDRESP0); + u32 dwdata1 = readl(addrbase + VIA_CRDR_SDRESP1); + u32 dwdata2 = readl(addrbase + VIA_CRDR_SDRESP2); + u32 dwdata3 = readl(addrbase + VIA_CRDR_SDRESP3); + + if (cmd->flags & MMC_RSP_136) { + cmd->resp[0] = ((u8) (dwdata1)) | + (((u8) (dwdata0 >> 24)) << 8) | + (((u8) (dwdata0 >> 16)) << 16) | + (((u8) (dwdata0 >> 8)) << 24); + + cmd->resp[1] = ((u8) (dwdata2)) | + (((u8) (dwdata1 >> 24)) << 8) | + (((u8) (dwdata1 >> 16)) << 16) | + (((u8) (dwdata1 >> 8)) << 24); + + cmd->resp[2] = ((u8) (dwdata3)) | + (((u8) (dwdata2 >> 24)) << 8) | + (((u8) (dwdata2 >> 16)) << 16) | + (((u8) (dwdata2 >> 8)) << 24); + + cmd->resp[3] = 0xff | + ((((u8) (dwdata3 >> 24))) << 8) | + (((u8) (dwdata3 >> 16)) << 16) | + (((u8) (dwdata3 >> 8)) << 24); + } else { + dwdata0 >>= 8; + cmd->resp[0] = ((dwdata0 & 0xff) << 24) | + (((dwdata0 >> 8) & 0xff) << 16) | + (((dwdata0 >> 16) & 0xff) << 8) | (dwdata1 & 0xff); + + dwdata1 >>= 8; + cmd->resp[1] = ((dwdata1 & 0xff) << 24) | + (((dwdata1 >> 8) & 0xff) << 16) | + (((dwdata1 >> 16) & 0xff) << 8); + } +} + +static void via_sdc_send_command(struct via_crdr_mmc_host *host, + struct mmc_command *cmd) +{ + void __iomem *addrbase; + struct mmc_data *data; + u32 cmdctrl = 0; + + WARN_ON(host->cmd); + + data = cmd->data; + mod_timer(&host->timer, jiffies + HZ); + host->cmd = cmd; + + /*Command index*/ + cmdctrl = cmd->opcode << 8; + + /*Response type*/ + switch (mmc_resp_type(cmd)) { + case MMC_RSP_NONE: + cmdctrl |= VIA_CRDR_SDCTRL_RSP_NONE; + break; + case MMC_RSP_R1: + cmdctrl |= VIA_CRDR_SDCTRL_RSP_R1; + break; + case MMC_RSP_R1B: + cmdctrl |= VIA_CRDR_SDCTRL_RSP_R1B; + break; + case MMC_RSP_R2: + cmdctrl |= VIA_CRDR_SDCTRL_RSP_R2; + break; + case MMC_RSP_R3: + cmdctrl |= VIA_CRDR_SDCTRL_RSP_R3; + break; + default: + pr_err("%s: cmd->flag is not valid\n", mmc_hostname(host->mmc)); + break; + } + + if (!(cmd->data)) + goto nodata; + + via_sdc_preparedata(host, data); + + /*Command control*/ + if (data->blocks > 1) { + if (data->flags & MMC_DATA_WRITE) { + cmdctrl |= VIA_CRDR_SDCTRL_WRITE; + cmdctrl |= VIA_CRDR_SDCTRL_MULTI_WR; + } else { + cmdctrl |= VIA_CRDR_SDCTRL_MULTI_RD; + } + } else { + if (data->flags & MMC_DATA_WRITE) { + cmdctrl |= VIA_CRDR_SDCTRL_WRITE; + cmdctrl |= VIA_CRDR_SDCTRL_SINGLE_WR; + } else { + cmdctrl |= VIA_CRDR_SDCTRL_SINGLE_RD; + } + } + +nodata: + if (cmd == host->mrq->stop) + cmdctrl |= VIA_CRDR_SDCTRL_STOP; + + cmdctrl |= VIA_CRDR_SDCTRL_START; + + addrbase = host->sdhc_mmiobase; + writel(cmd->arg, addrbase + VIA_CRDR_SDCARG); + writel(cmdctrl, addrbase + VIA_CRDR_SDCTRL); +} + +static void via_sdc_finish_data(struct via_crdr_mmc_host *host) +{ + struct mmc_data *data; + + BUG_ON(!host->data); + + data = host->data; + host->data = NULL; + + if (data->error) + data->bytes_xfered = 0; + else + data->bytes_xfered = data->blocks * data->blksz; + + dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, + ((data->flags & MMC_DATA_READ) ? + PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE)); + + if (data->stop) + via_sdc_send_command(host, data->stop); + else + tasklet_schedule(&host->finish_tasklet); +} + +static void via_sdc_finish_command(struct via_crdr_mmc_host *host) +{ + via_sdc_get_response(host, host->cmd); + + host->cmd->error = 0; + + if (!host->cmd->data) + tasklet_schedule(&host->finish_tasklet); + + host->cmd = NULL; +} + +static void via_sdc_request(struct mmc_host *mmc, struct mmc_request *mrq) +{ + void __iomem *addrbase; + struct via_crdr_mmc_host *host; + unsigned long flags; + u16 status; + + host = mmc_priv(mmc); + + spin_lock_irqsave(&host->lock, flags); + + addrbase = host->pcictrl_mmiobase; + writeb(VIA_CRDR_PCIDMACLK_SDC, addrbase + VIA_CRDR_PCIDMACLK); + + status = readw(host->sdhc_mmiobase + VIA_CRDR_SDSTATUS); + status &= VIA_CRDR_SDSTS_W1C_MASK; + writew(status, host->sdhc_mmiobase + VIA_CRDR_SDSTATUS); + + WARN_ON(host->mrq != NULL); + host->mrq = mrq; + + status = readw(host->sdhc_mmiobase + VIA_CRDR_SDSTATUS); + if (!(status & VIA_CRDR_SDSTS_SLOTG) || host->reject) { + host->mrq->cmd->error = -ENOMEDIUM; + tasklet_schedule(&host->finish_tasklet); + } else { + via_sdc_send_command(host, mrq->cmd); + } + + mmiowb(); + spin_unlock_irqrestore(&host->lock, flags); +} + +static void via_sdc_set_power(struct via_crdr_mmc_host *host, + unsigned short power, unsigned int on) +{ + unsigned long flags; + u8 gatt; + + spin_lock_irqsave(&host->lock, flags); + + host->power = (1 << power); + + gatt = readb(host->pcictrl_mmiobase + VIA_CRDR_PCICLKGATT); + if (host->power == MMC_VDD_165_195) + gatt &= ~VIA_CRDR_PCICLKGATT_3V3; + else + gatt |= VIA_CRDR_PCICLKGATT_3V3; + if (on) + gatt |= VIA_CRDR_PCICLKGATT_PAD_PWRON; + else + gatt &= ~VIA_CRDR_PCICLKGATT_PAD_PWRON; + writeb(gatt, host->pcictrl_mmiobase + VIA_CRDR_PCICLKGATT); + + mmiowb(); + spin_unlock_irqrestore(&host->lock, flags); + + via_pwron_sleep(host); +} + +static void via_sdc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct via_crdr_mmc_host *host; + unsigned long flags; + void __iomem *addrbase; + u32 org_data, sdextctrl; + u8 clock; + + host = mmc_priv(mmc); + + spin_lock_irqsave(&host->lock, flags); + + addrbase = host->sdhc_mmiobase; + org_data = readl(addrbase + VIA_CRDR_SDBUSMODE); + sdextctrl = readl(addrbase + VIA_CRDR_SDEXTCTRL); + + if (ios->bus_width == MMC_BUS_WIDTH_1) + org_data &= ~VIA_CRDR_SDMODE_4BIT; + else + org_data |= VIA_CRDR_SDMODE_4BIT; + + if (ios->power_mode == MMC_POWER_OFF) + org_data &= ~VIA_CRDR_SDMODE_CLK_ON; + else + org_data |= VIA_CRDR_SDMODE_CLK_ON; + + if (ios->timing == MMC_TIMING_SD_HS) + sdextctrl |= VIA_CRDR_SDEXTCTRL_HISPD; + else + sdextctrl &= ~VIA_CRDR_SDEXTCTRL_HISPD; + + writel(org_data, addrbase + VIA_CRDR_SDBUSMODE); + writel(sdextctrl, addrbase + VIA_CRDR_SDEXTCTRL); + + if (ios->clock >= 48000000) + clock = PCI_CLK_48M; + else if (ios->clock >= 33000000) + clock = PCI_CLK_33M; + else if (ios->clock >= 24000000) + clock = PCI_CLK_24M; + else if (ios->clock >= 16000000) + clock = PCI_CLK_16M; + else if (ios->clock >= 12000000) + clock = PCI_CLK_12M; + else if (ios->clock >= 8000000) + clock = PCI_CLK_8M; + else + clock = PCI_CLK_375K; + + addrbase = host->pcictrl_mmiobase; + if (readb(addrbase + VIA_CRDR_PCISDCCLK) != clock) + writeb(clock, addrbase + VIA_CRDR_PCISDCCLK); + + mmiowb(); + spin_unlock_irqrestore(&host->lock, flags); + + if (ios->power_mode != MMC_POWER_OFF) + via_sdc_set_power(host, ios->vdd, 1); + else + via_sdc_set_power(host, ios->vdd, 0); +} + +static int via_sdc_get_ro(struct mmc_host *mmc) +{ + struct via_crdr_mmc_host *host; + unsigned long flags; + u16 status; + + host = mmc_priv(mmc); + + spin_lock_irqsave(&host->lock, flags); + + status = readw(host->sdhc_mmiobase + VIA_CRDR_SDSTATUS); + + spin_unlock_irqrestore(&host->lock, flags); + + return !(status & VIA_CRDR_SDSTS_WP); +} + +static const struct mmc_host_ops via_sdc_ops = { + .request = via_sdc_request, + .set_ios = via_sdc_set_ios, + .get_ro = via_sdc_get_ro, +}; + +static void via_reset_pcictrl(struct via_crdr_mmc_host *host) +{ + void __iomem *addrbase; + unsigned long flags; + u8 gatt; + + addrbase = host->pcictrl_mmiobase; + + spin_lock_irqsave(&host->lock, flags); + + via_save_pcictrlreg(host); + via_save_sdcreg(host); + + spin_unlock_irqrestore(&host->lock, flags); + + gatt = VIA_CRDR_PCICLKGATT_PAD_PWRON; + if (host->power == MMC_VDD_165_195) + gatt &= VIA_CRDR_PCICLKGATT_3V3; + else + gatt |= VIA_CRDR_PCICLKGATT_3V3; + writeb(gatt, host->pcictrl_mmiobase + VIA_CRDR_PCICLKGATT); + via_pwron_sleep(host); + gatt |= VIA_CRDR_PCICLKGATT_SFTRST; + writeb(gatt, host->pcictrl_mmiobase + VIA_CRDR_PCICLKGATT); + msleep(3); + + spin_lock_irqsave(&host->lock, flags); + + via_restore_pcictrlreg(host); + via_restore_sdcreg(host); + + mmiowb(); + spin_unlock_irqrestore(&host->lock, flags); +} + +static void via_sdc_cmd_isr(struct via_crdr_mmc_host *host, u16 intmask) +{ + BUG_ON(intmask == 0); + + if (!host->cmd) { + pr_err("%s: Got command interrupt 0x%x even " + "though no command operation was in progress.\n", + mmc_hostname(host->mmc), intmask); + return; + } + + if (intmask & VIA_CRDR_SDSTS_CRTO) + host->cmd->error = -ETIMEDOUT; + else if (intmask & VIA_CRDR_SDSTS_SC) + host->cmd->error = -EILSEQ; + + if (host->cmd->error) + tasklet_schedule(&host->finish_tasklet); + else if (intmask & VIA_CRDR_SDSTS_CRD) + via_sdc_finish_command(host); +} + +static void via_sdc_data_isr(struct via_crdr_mmc_host *host, u16 intmask) +{ + BUG_ON(intmask == 0); + + if (intmask & VIA_CRDR_SDSTS_DT) + host->data->error = -ETIMEDOUT; + else if (intmask & (VIA_CRDR_SDSTS_RC | VIA_CRDR_SDSTS_WC)) + host->data->error = -EILSEQ; + + via_sdc_finish_data(host); +} + +static irqreturn_t via_sdc_isr(int irq, void *dev_id) +{ + struct via_crdr_mmc_host *sdhost = dev_id; + void __iomem *addrbase; + u8 pci_status; + u16 sd_status; + irqreturn_t result; + + if (!sdhost) + return IRQ_NONE; + + spin_lock(&sdhost->lock); + + addrbase = sdhost->pcictrl_mmiobase; + pci_status = readb(addrbase + VIA_CRDR_PCIINTSTATUS); + if (!(pci_status & VIA_CRDR_PCIINTSTATUS_SDC)) { + result = IRQ_NONE; + goto out; + } + + addrbase = sdhost->sdhc_mmiobase; + sd_status = readw(addrbase + VIA_CRDR_SDSTATUS); + sd_status &= VIA_CRDR_SDSTS_INT_MASK; + sd_status &= ~VIA_CRDR_SDSTS_IGN_MASK; + if (!sd_status) { + result = IRQ_NONE; + goto out; + } + + if (sd_status & VIA_CRDR_SDSTS_CIR) { + writew(sd_status & VIA_CRDR_SDSTS_CIR, + addrbase + VIA_CRDR_SDSTATUS); + + schedule_work(&sdhost->carddet_work); + } + + sd_status &= ~VIA_CRDR_SDSTS_CIR; + if (sd_status & VIA_CRDR_SDSTS_CMD_MASK) { + writew(sd_status & VIA_CRDR_SDSTS_CMD_MASK, + addrbase + VIA_CRDR_SDSTATUS); + via_sdc_cmd_isr(sdhost, sd_status & VIA_CRDR_SDSTS_CMD_MASK); + } + if (sd_status & VIA_CRDR_SDSTS_DATA_MASK) { + writew(sd_status & VIA_CRDR_SDSTS_DATA_MASK, + addrbase + VIA_CRDR_SDSTATUS); + via_sdc_data_isr(sdhost, sd_status & VIA_CRDR_SDSTS_DATA_MASK); + } + + sd_status &= ~(VIA_CRDR_SDSTS_CMD_MASK | VIA_CRDR_SDSTS_DATA_MASK); + if (sd_status) { + pr_err("%s: Unexpected interrupt 0x%x\n", + mmc_hostname(sdhost->mmc), sd_status); + writew(sd_status, addrbase + VIA_CRDR_SDSTATUS); + } + + result = IRQ_HANDLED; + + mmiowb(); +out: + spin_unlock(&sdhost->lock); + + return result; +} + +static void via_sdc_timeout(unsigned long ulongdata) +{ + struct via_crdr_mmc_host *sdhost; + unsigned long flags; + + sdhost = (struct via_crdr_mmc_host *)ulongdata; + + spin_lock_irqsave(&sdhost->lock, flags); + + if (sdhost->mrq) { + pr_err("%s: Timeout waiting for hardware interrupt." + "cmd:0x%x\n", mmc_hostname(sdhost->mmc), + sdhost->mrq->cmd->opcode); + + if (sdhost->data) { + writel(VIA_CRDR_DMACTRL_SFTRST, + sdhost->ddma_mmiobase + VIA_CRDR_DMACTRL); + sdhost->data->error = -ETIMEDOUT; + via_sdc_finish_data(sdhost); + } else { + if (sdhost->cmd) + sdhost->cmd->error = -ETIMEDOUT; + else + sdhost->mrq->cmd->error = -ETIMEDOUT; + tasklet_schedule(&sdhost->finish_tasklet); + } + } + + mmiowb(); + spin_unlock_irqrestore(&sdhost->lock, flags); +} + +static void via_sdc_tasklet_finish(unsigned long param) +{ + struct via_crdr_mmc_host *host; + unsigned long flags; + struct mmc_request *mrq; + + host = (struct via_crdr_mmc_host *)param; + + spin_lock_irqsave(&host->lock, flags); + + del_timer(&host->timer); + mrq = host->mrq; + host->mrq = NULL; + host->cmd = NULL; + host->data = NULL; + + spin_unlock_irqrestore(&host->lock, flags); + + mmc_request_done(host->mmc, mrq); +} + +static void via_sdc_card_detect(struct work_struct *work) +{ + struct via_crdr_mmc_host *host; + void __iomem *addrbase; + unsigned long flags; + u16 status; + + host = container_of(work, struct via_crdr_mmc_host, carddet_work); + + addrbase = host->ddma_mmiobase; + writel(VIA_CRDR_DMACTRL_SFTRST, addrbase + VIA_CRDR_DMACTRL); + + spin_lock_irqsave(&host->lock, flags); + + addrbase = host->pcictrl_mmiobase; + writeb(VIA_CRDR_PCIDMACLK_SDC, addrbase + VIA_CRDR_PCIDMACLK); + + addrbase = host->sdhc_mmiobase; + status = readw(addrbase + VIA_CRDR_SDSTATUS); + if (!(status & VIA_CRDR_SDSTS_SLOTG)) { + if (host->mrq) { + pr_err("%s: Card removed during transfer!\n", + mmc_hostname(host->mmc)); + host->mrq->cmd->error = -ENOMEDIUM; + tasklet_schedule(&host->finish_tasklet); + } + + mmiowb(); + spin_unlock_irqrestore(&host->lock, flags); + + via_reset_pcictrl(host); + + spin_lock_irqsave(&host->lock, flags); + } + + mmiowb(); + spin_unlock_irqrestore(&host->lock, flags); + + via_print_pcictrl(host); + via_print_sdchc(host); + + mmc_detect_change(host->mmc, msecs_to_jiffies(500)); +} + +static void via_init_mmc_host(struct via_crdr_mmc_host *host) +{ + struct mmc_host *mmc = host->mmc; + void __iomem *addrbase; + u32 lenreg; + u32 status; + + init_timer(&host->timer); + host->timer.data = (unsigned long)host; + host->timer.function = via_sdc_timeout; + + spin_lock_init(&host->lock); + + mmc->f_min = VIA_CRDR_MIN_CLOCK; + mmc->f_max = VIA_CRDR_MAX_CLOCK; + mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; + mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED; + mmc->ops = &via_sdc_ops; + + /*Hardware cannot do scatter lists*/ + mmc->max_hw_segs = 1; + mmc->max_phys_segs = 1; + + mmc->max_blk_size = VIA_CRDR_MAX_BLOCK_LENGTH; + mmc->max_blk_count = VIA_CRDR_MAX_BLOCK_COUNT; + + mmc->max_seg_size = mmc->max_blk_size * mmc->max_blk_count; + mmc->max_req_size = mmc->max_seg_size; + + INIT_WORK(&host->carddet_work, via_sdc_card_detect); + + tasklet_init(&host->finish_tasklet, via_sdc_tasklet_finish, + (unsigned long)host); + + addrbase = host->sdhc_mmiobase; + writel(0x0, addrbase + VIA_CRDR_SDINTMASK); + msleep(1); + + lenreg = VIA_CRDR_SDBLKLEN_GPIDET | VIA_CRDR_SDBLKLEN_INTEN; + writel(lenreg, addrbase + VIA_CRDR_SDBLKLEN); + + status = readw(addrbase + VIA_CRDR_SDSTATUS); + status &= VIA_CRDR_SDSTS_W1C_MASK; + writew(status, addrbase + VIA_CRDR_SDSTATUS); + + status = readw(addrbase + VIA_CRDR_SDSTATUS2); + status |= VIA_CRDR_SDSTS_CFE; + writew(status, addrbase + VIA_CRDR_SDSTATUS2); + + writeb(0x0, addrbase + VIA_CRDR_SDEXTCTRL); + + writel(VIA_CRDR_SDACTIVE_INTMASK, addrbase + VIA_CRDR_SDINTMASK); + msleep(1); +} + +static int __devinit via_sd_probe(struct pci_dev *pcidev, + const struct pci_device_id *id) +{ + struct mmc_host *mmc; + struct via_crdr_mmc_host *sdhost; + u32 base, len; + u8 rev, gatt; + int ret; + + pci_read_config_byte(pcidev, PCI_CLASS_REVISION, &rev); + pr_info(DRV_NAME + ": VIA SDMMC controller found at %s [%04x:%04x] (rev %x)\n", + pci_name(pcidev), (int)pcidev->vendor, (int)pcidev->device, + (int)rev); + + ret = pci_enable_device(pcidev); + if (ret) + return ret; + + ret = pci_request_regions(pcidev, DRV_NAME); + if (ret) + goto disable; + + pci_write_config_byte(pcidev, VIA_CRDR_PCI_WORK_MODE, 0); + pci_write_config_byte(pcidev, VIA_CRDR_PCI_DBG_MODE, 0); + + mmc = mmc_alloc_host(sizeof(struct via_crdr_mmc_host), &pcidev->dev); + if (!mmc) { + ret = -ENOMEM; + goto release; + } + + sdhost = mmc_priv(mmc); + sdhost->mmc = mmc; + dev_set_drvdata(&pcidev->dev, sdhost); + + len = pci_resource_len(pcidev, 0); + base = pci_resource_start(pcidev, 0); + sdhost->mmiobase = ioremap_nocache(base, len); + if (!sdhost->mmiobase) { + ret = -ENOMEM; + goto free_mmc_host; + } + + sdhost->sdhc_mmiobase = + sdhost->mmiobase + VIA_CRDR_SDC_OFF; + sdhost->ddma_mmiobase = + sdhost->mmiobase + VIA_CRDR_DDMA_OFF; + sdhost->pcictrl_mmiobase = + sdhost->mmiobase + VIA_CRDR_PCICTRL_OFF; + + sdhost->power = MMC_VDD_165_195; + + gatt = VIA_CRDR_PCICLKGATT_3V3 | VIA_CRDR_PCICLKGATT_PAD_PWRON; + writeb(gatt, sdhost->pcictrl_mmiobase + VIA_CRDR_PCICLKGATT); + via_pwron_sleep(sdhost); + gatt |= VIA_CRDR_PCICLKGATT_SFTRST; + writeb(gatt, sdhost->pcictrl_mmiobase + VIA_CRDR_PCICLKGATT); + msleep(3); + + via_init_mmc_host(sdhost); + + ret = + request_irq(pcidev->irq, via_sdc_isr, IRQF_SHARED, DRV_NAME, + sdhost); + if (ret) + goto unmap; + + writeb(VIA_CRDR_PCIINTCTRL_SDCIRQEN, + sdhost->pcictrl_mmiobase + VIA_CRDR_PCIINTCTRL); + writeb(VIA_CRDR_PCITMOCTRL_1024MS, + sdhost->pcictrl_mmiobase + VIA_CRDR_PCITMOCTRL); + + /* device-specific quirks */ + if (pcidev->subsystem_vendor == PCI_VENDOR_ID_LENOVO && + pcidev->subsystem_device == 0x3891) + sdhost->quirks = VIA_CRDR_QUIRK_300MS_PWRDELAY; + + mmc_add_host(mmc); + + return 0; + +unmap: + iounmap(sdhost->mmiobase); +free_mmc_host: + dev_set_drvdata(&pcidev->dev, NULL); + mmc_free_host(mmc); +release: + pci_release_regions(pcidev); +disable: + pci_disable_device(pcidev); + + return ret; +} + +static void __devexit via_sd_remove(struct pci_dev *pcidev) +{ + struct via_crdr_mmc_host *sdhost = pci_get_drvdata(pcidev); + unsigned long flags; + u8 gatt; + + spin_lock_irqsave(&sdhost->lock, flags); + + /* Ensure we don't accept more commands from mmc layer */ + sdhost->reject = 1; + + /* Disable generating further interrupts */ + writeb(0x0, sdhost->pcictrl_mmiobase + VIA_CRDR_PCIINTCTRL); + mmiowb(); + + if (sdhost->mrq) { + printk(KERN_ERR "%s: Controller removed during " + "transfer\n", mmc_hostname(sdhost->mmc)); + + /* make sure all DMA is stopped */ + writel(VIA_CRDR_DMACTRL_SFTRST, + sdhost->ddma_mmiobase + VIA_CRDR_DMACTRL); + mmiowb(); + sdhost->mrq->cmd->error = -ENOMEDIUM; + if (sdhost->mrq->stop) + sdhost->mrq->stop->error = -ENOMEDIUM; + tasklet_schedule(&sdhost->finish_tasklet); + } + spin_unlock_irqrestore(&sdhost->lock, flags); + + mmc_remove_host(sdhost->mmc); + + free_irq(pcidev->irq, sdhost); + + del_timer_sync(&sdhost->timer); + + tasklet_kill(&sdhost->finish_tasklet); + + /* switch off power */ + gatt = readb(sdhost->pcictrl_mmiobase + VIA_CRDR_PCICLKGATT); + gatt &= ~VIA_CRDR_PCICLKGATT_PAD_PWRON; + writeb(gatt, sdhost->pcictrl_mmiobase + VIA_CRDR_PCICLKGATT); + + iounmap(sdhost->mmiobase); + dev_set_drvdata(&pcidev->dev, NULL); + mmc_free_host(sdhost->mmc); + pci_release_regions(pcidev); + pci_disable_device(pcidev); + + pr_info(DRV_NAME + ": VIA SDMMC controller at %s [%04x:%04x] has been removed\n", + pci_name(pcidev), (int)pcidev->vendor, (int)pcidev->device); +} + +#ifdef CONFIG_PM + +static void via_init_sdc_pm(struct via_crdr_mmc_host *host) +{ + struct sdhcreg *pm_sdhcreg; + void __iomem *addrbase; + u32 lenreg; + u16 status; + + pm_sdhcreg = &(host->pm_sdhc_reg); + addrbase = host->sdhc_mmiobase; + + writel(0x0, addrbase + VIA_CRDR_SDINTMASK); + + lenreg = VIA_CRDR_SDBLKLEN_GPIDET | VIA_CRDR_SDBLKLEN_INTEN; + writel(lenreg, addrbase + VIA_CRDR_SDBLKLEN); + + status = readw(addrbase + VIA_CRDR_SDSTATUS); + status &= VIA_CRDR_SDSTS_W1C_MASK; + writew(status, addrbase + VIA_CRDR_SDSTATUS); + + status = readw(addrbase + VIA_CRDR_SDSTATUS2); + status |= VIA_CRDR_SDSTS_CFE; + writew(status, addrbase + VIA_CRDR_SDSTATUS2); + + writel(pm_sdhcreg->sdcontrol_reg, addrbase + VIA_CRDR_SDCTRL); + writel(pm_sdhcreg->sdcmdarg_reg, addrbase + VIA_CRDR_SDCARG); + writel(pm_sdhcreg->sdintmask_reg, addrbase + VIA_CRDR_SDINTMASK); + writel(pm_sdhcreg->sdrsptmo_reg, addrbase + VIA_CRDR_SDRSPTMO); + writel(pm_sdhcreg->sdclksel_reg, addrbase + VIA_CRDR_SDCLKSEL); + writel(pm_sdhcreg->sdextctrl_reg, addrbase + VIA_CRDR_SDEXTCTRL); + + via_print_pcictrl(host); + via_print_sdchc(host); +} + +static int via_sd_suspend(struct pci_dev *pcidev, pm_message_t state) +{ + struct via_crdr_mmc_host *host; + int ret = 0; + + host = pci_get_drvdata(pcidev); + + via_save_pcictrlreg(host); + via_save_sdcreg(host); + + ret = mmc_suspend_host(host->mmc, state); + + pci_save_state(pcidev); + pci_enable_wake(pcidev, pci_choose_state(pcidev, state), 0); + pci_disable_device(pcidev); + pci_set_power_state(pcidev, pci_choose_state(pcidev, state)); + + return ret; +} + +static int via_sd_resume(struct pci_dev *pcidev) +{ + struct via_crdr_mmc_host *sdhost; + int ret = 0; + u8 gatt; + + sdhost = pci_get_drvdata(pcidev); + + gatt = VIA_CRDR_PCICLKGATT_PAD_PWRON; + if (sdhost->power == MMC_VDD_165_195) + gatt &= ~VIA_CRDR_PCICLKGATT_3V3; + else + gatt |= VIA_CRDR_PCICLKGATT_3V3; + writeb(gatt, sdhost->pcictrl_mmiobase + VIA_CRDR_PCICLKGATT); + via_pwron_sleep(sdhost); + gatt |= VIA_CRDR_PCICLKGATT_SFTRST; + writeb(gatt, sdhost->pcictrl_mmiobase + VIA_CRDR_PCICLKGATT); + msleep(3); + + msleep(100); + + pci_set_power_state(pcidev, PCI_D0); + pci_restore_state(pcidev); + ret = pci_enable_device(pcidev); + if (ret) + return ret; + + via_restore_pcictrlreg(sdhost); + via_init_sdc_pm(sdhost); + + ret = mmc_resume_host(sdhost->mmc); + + return ret; +} + +#else /* CONFIG_PM */ + +#define via_sd_suspend NULL +#define via_sd_resume NULL + +#endif /* CONFIG_PM */ + +static struct pci_driver via_sd_driver = { + .name = DRV_NAME, + .id_table = via_ids, + .probe = via_sd_probe, + .remove = __devexit_p(via_sd_remove), + .suspend = via_sd_suspend, + .resume = via_sd_resume, +}; + +static int __init via_sd_drv_init(void) +{ + pr_info(DRV_NAME ": VIA SD/MMC Card Reader driver " + "(C) 2008 VIA Technologies, Inc.\n"); + + return pci_register_driver(&via_sd_driver); +} + +static void __exit via_sd_drv_exit(void) +{ + pci_unregister_driver(&via_sd_driver); +} + +module_init(via_sd_drv_init); +module_exit(via_sd_drv_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("VIA Technologies Inc."); +MODULE_DESCRIPTION("VIA SD/MMC Card Interface driver"); diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index 7d04fb9ddcaa..b8e35a0b4d72 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -154,7 +154,8 @@ config MTD_AFS_PARTS You will still need the parsing functions to be called by the driver for your particular device. It won't happen automatically. The - 'armflash' map driver (CONFIG_MTD_ARMFLASH) does this, for example. + 'armflash' map driver (CONFIG_MTD_ARM_INTEGRATOR) does this, for + example. config MTD_OF_PARTS tristate "Flash partition map based on OF description" diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index c240454fd113..8664feebc93b 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -46,6 +46,7 @@ #define MANUFACTURER_INTEL 0x0089 #define I82802AB 0x00ad #define I82802AC 0x00ac +#define PF38F4476 0x881c #define MANUFACTURER_ST 0x0020 #define M50LPW080 0x002F #define M50FLW080A 0x0080 @@ -315,10 +316,20 @@ static struct cfi_fixup fixup_table[] = { { 0, 0, NULL, NULL } }; +static void cfi_fixup_major_minor(struct cfi_private *cfi, + struct cfi_pri_intelext *extp) +{ + if (cfi->mfr == MANUFACTURER_INTEL && + cfi->id == PF38F4476 && extp->MinorVersion == '3') + extp->MinorVersion = '1'; +} + static inline struct cfi_pri_intelext * read_pri_intelext(struct map_info *map, __u16 adr) { + struct cfi_private *cfi = map->fldrv_priv; struct cfi_pri_intelext *extp; + unsigned int extra_size = 0; unsigned int extp_size = sizeof(*extp); again: @@ -326,6 +337,8 @@ read_pri_intelext(struct map_info *map, __u16 adr) if (!extp) return NULL; + cfi_fixup_major_minor(cfi, extp); + if (extp->MajorVersion != '1' || (extp->MinorVersion < '0' || extp->MinorVersion > '5')) { printk(KERN_ERR " Unknown Intel/Sharp Extended Query " @@ -340,19 +353,24 @@ read_pri_intelext(struct map_info *map, __u16 adr) extp->BlkStatusRegMask = le16_to_cpu(extp->BlkStatusRegMask); extp->ProtRegAddr = le16_to_cpu(extp->ProtRegAddr); - if (extp->MajorVersion == '1' && extp->MinorVersion >= '3') { - unsigned int extra_size = 0; - int nb_parts, i; + if (extp->MinorVersion >= '0') { + extra_size = 0; /* Protection Register info */ extra_size += (extp->NumProtectionFields - 1) * sizeof(struct cfi_intelext_otpinfo); + } + if (extp->MinorVersion >= '1') { /* Burst Read info */ extra_size += 2; if (extp_size < sizeof(*extp) + extra_size) goto need_more; - extra_size += extp->extra[extra_size-1]; + extra_size += extp->extra[extra_size - 1]; + } + + if (extp->MinorVersion >= '3') { + int nb_parts, i; /* Number of hardware-partitions */ extra_size += 1; diff --git a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c index e824b9b9b056..ccc4cfc7e4b5 100644 --- a/drivers/mtd/chips/jedec_probe.c +++ b/drivers/mtd/chips/jedec_probe.c @@ -166,6 +166,7 @@ #define SST39LF040 0x00D7 #define SST39SF010A 0x00B5 #define SST39SF020A 0x00B6 +#define SST39SF040 0x00B7 #define SST49LF004B 0x0060 #define SST49LF040B 0x0050 #define SST49LF008A 0x005a @@ -1391,6 +1392,18 @@ static const struct amd_flash_info jedec_table[] = { .regions = { ERASEINFO(0x01000,64), } + }, { + .mfr_id = MANUFACTURER_SST, + .dev_id = SST39SF040, + .name = "SST 39SF040", + .devtypes = CFI_DEVICETYPE_X8, + .uaddr = MTD_UADDR_0x5555_0x2AAA, + .dev_size = SIZE_512KiB, + .cmd_set = P_ID_AMD_STD, + .nr_regions = 1, + .regions = { + ERASEINFO(0x01000,128), + } }, { .mfr_id = MANUFACTURER_SST, .dev_id = SST49LF040B, diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig index 6fde0a2e3567..325fab92a62c 100644 --- a/drivers/mtd/devices/Kconfig +++ b/drivers/mtd/devices/Kconfig @@ -49,7 +49,7 @@ config MTD_MS02NV If you want to compile this driver as a module ( = code which can be inserted in and removed from the running kernel whenever you want), say M here and read . - The module will be called ms02-nv.ko. + The module will be called ms02-nv. config MTD_DATAFLASH tristate "Support for AT45xxx DataFlash" diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index cc6369ea67dd..59c46126a5ce 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -500,6 +500,9 @@ static struct flash_info __devinitdata m25p_data [] = { { "at26df161a", 0x1f4601, 0, 64 * 1024, 32, SECT_4K, }, { "at26df321", 0x1f4701, 0, 64 * 1024, 64, SECT_4K, }, + /* Macronix */ + { "mx25l12805d", 0xc22018, 0, 64 * 1024, 256, }, + /* Spansion -- single (large) sector size only, at least * for the chips listed here (without boot sectors). */ @@ -528,6 +531,7 @@ static struct flash_info __devinitdata m25p_data [] = { { "m25p64", 0x202017, 0, 64 * 1024, 128, }, { "m25p128", 0x202018, 0, 256 * 1024, 64, }, + { "m45pe10", 0x204011, 0, 64 * 1024, 2, }, { "m45pe80", 0x204014, 0, 64 * 1024, 16, }, { "m45pe16", 0x204015, 0, 64 * 1024, 32, }, diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index 82923bd2d9c5..0b98654d8eed 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -105,15 +105,6 @@ config MSP_FLASH_MAP_LIMIT default "0x02000000" depends on MSP_FLASH_MAP_LIMIT_32M -config MTD_PMC_MSP_RAMROOT - tristate "Embedded RAM block device for root on PMC-Sierra MSP" - depends on PMC_MSP_EMBEDDED_ROOTFS && \ - (MTD_BLOCK || MTD_BLOCK_RO) && \ - MTD_RAM - help - This provides support for the embedded root file system - on PMC MSP devices. This memory is mapped as a MTD block device. - config MTD_SUN_UFLASH tristate "Sun Microsystems userflash support" depends on SPARC && MTD_CFI && PCI @@ -270,7 +261,7 @@ config MTD_ALCHEMY config MTD_DILNETPC tristate "CFI Flash device mapped on DIL/Net PC" - depends on X86 && MTD_CONCAT && MTD_PARTITIONS && MTD_CFI_INTELEXT + depends on X86 && MTD_CONCAT && MTD_PARTITIONS && MTD_CFI_INTELEXT && BROKEN help MTD map driver for SSV DIL/Net PC Boards "DNP" and "ADNP". For details, see @@ -501,7 +492,7 @@ config MTD_BFIN_ASYNC If compiled as a module, it will be called bfin-async-flash. config MTD_UCLINUX - tristate "Generic uClinux RAM/ROM filesystem support" + bool "Generic uClinux RAM/ROM filesystem support" depends on MTD_PARTITIONS && MTD_RAM && !MMU help Map driver to support image based filesystems for uClinux. diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile index 2dbc1bec8488..8bae7f9850c0 100644 --- a/drivers/mtd/maps/Makefile +++ b/drivers/mtd/maps/Makefile @@ -25,7 +25,6 @@ obj-$(CONFIG_MTD_OCTAGON) += octagon-5066.o obj-$(CONFIG_MTD_PHYSMAP) += physmap.o obj-$(CONFIG_MTD_PHYSMAP_OF) += physmap_of.o obj-$(CONFIG_MTD_PMC_MSP_EVM) += pmcmsp-flash.o -obj-$(CONFIG_MTD_PMC_MSP_RAMROOT)+= pmcmsp-ramroot.o obj-$(CONFIG_MTD_PCMCIA) += pcmciamtd.o obj-$(CONFIG_MTD_RPXLITE) += rpxlite.o obj-$(CONFIG_MTD_TQM8XXL) += tqm8xxl.o diff --git a/drivers/mtd/maps/bfin-async-flash.c b/drivers/mtd/maps/bfin-async-flash.c index 576611f605db..365c77b1b871 100644 --- a/drivers/mtd/maps/bfin-async-flash.c +++ b/drivers/mtd/maps/bfin-async-flash.c @@ -40,6 +40,9 @@ struct async_state { uint32_t flash_ambctl0, flash_ambctl1; uint32_t save_ambctl0, save_ambctl1; unsigned long irq_flags; +#ifdef CONFIG_MTD_PARTITIONS + struct mtd_partition *parts; +#endif }; static void switch_to_flash(struct async_state *state) @@ -170,6 +173,7 @@ static int __devinit bfin_flash_probe(struct platform_device *pdev) if (ret > 0) { pr_devinit(KERN_NOTICE DRIVER_NAME ": Using commandline partition definition\n"); add_mtd_partitions(state->mtd, pdata->parts, ret); + state->parts = pdata->parts; } else if (pdata->nr_parts) { pr_devinit(KERN_NOTICE DRIVER_NAME ": Using board partition definition\n"); @@ -193,6 +197,7 @@ static int __devexit bfin_flash_remove(struct platform_device *pdev) gpio_free(state->enet_flash_pin); #ifdef CONFIG_MTD_PARTITIONS del_mtd_partitions(state->mtd); + kfree(state->parts); #endif map_destroy(state->mtd); kfree(state); diff --git a/drivers/mtd/maps/integrator-flash.c b/drivers/mtd/maps/integrator-flash.c index c9681a339a59..b08a798ee254 100644 --- a/drivers/mtd/maps/integrator-flash.c +++ b/drivers/mtd/maps/integrator-flash.c @@ -36,27 +36,33 @@ #include #include #include +#include #include #include #include -#ifdef CONFIG_ARCH_P720T -#define FLASH_BASE (0x04000000) -#define FLASH_SIZE (64*1024*1024) -#endif +#define SUBDEV_NAME_SIZE (BUS_ID_SIZE + 2) + +struct armflash_subdev_info { + char name[SUBDEV_NAME_SIZE]; + struct mtd_info *mtd; + struct map_info map; + struct flash_platform_data *plat; +}; struct armflash_info { - struct flash_platform_data *plat; struct resource *res; struct mtd_partition *parts; struct mtd_info *mtd; - struct map_info map; + int nr_subdev; + struct armflash_subdev_info subdev[0]; }; static void armflash_set_vpp(struct map_info *map, int on) { - struct armflash_info *info = container_of(map, struct armflash_info, map); + struct armflash_subdev_info *info = + container_of(map, struct armflash_subdev_info, map); if (info->plat && info->plat->set_vpp) info->plat->set_vpp(on); @@ -64,32 +70,17 @@ static void armflash_set_vpp(struct map_info *map, int on) static const char *probes[] = { "cmdlinepart", "RedBoot", "afs", NULL }; -static int armflash_probe(struct platform_device *dev) +static int armflash_subdev_probe(struct armflash_subdev_info *subdev, + struct resource *res) { - struct flash_platform_data *plat = dev->dev.platform_data; - struct resource *res = dev->resource; - unsigned int size = res->end - res->start + 1; - struct armflash_info *info; - int err; + struct flash_platform_data *plat = subdev->plat; + resource_size_t size = res->end - res->start + 1; void __iomem *base; + int err = 0; - info = kzalloc(sizeof(struct armflash_info), GFP_KERNEL); - if (!info) { - err = -ENOMEM; - goto out; - } - - info->plat = plat; - if (plat && plat->init) { - err = plat->init(); - if (err) - goto no_resource; - } - - info->res = request_mem_region(res->start, size, "armflash"); - if (!info->res) { + if (!request_mem_region(res->start, size, subdev->name)) { err = -EBUSY; - goto no_resource; + goto out; } base = ioremap(res->start, size); @@ -101,27 +92,132 @@ static int armflash_probe(struct platform_device *dev) /* * look for CFI based flash parts fitted to this board */ - info->map.size = size; - info->map.bankwidth = plat->width; - info->map.phys = res->start; - info->map.virt = base; - info->map.name = dev_name(&dev->dev); - info->map.set_vpp = armflash_set_vpp; + subdev->map.size = size; + subdev->map.bankwidth = plat->width; + subdev->map.phys = res->start; + subdev->map.virt = base; + subdev->map.name = subdev->name; + subdev->map.set_vpp = armflash_set_vpp; - simple_map_init(&info->map); + simple_map_init(&subdev->map); /* * Also, the CFI layer automatically works out what size * of chips we have, and does the necessary identification * for us automatically. */ - info->mtd = do_map_probe(plat->map_name, &info->map); - if (!info->mtd) { + subdev->mtd = do_map_probe(plat->map_name, &subdev->map); + if (!subdev->mtd) { err = -ENXIO; goto no_device; } - info->mtd->owner = THIS_MODULE; + subdev->mtd->owner = THIS_MODULE; + + /* Successful? */ + if (err == 0) + return err; + + if (subdev->mtd) + map_destroy(subdev->mtd); + no_device: + iounmap(base); + no_mem: + release_mem_region(res->start, size); + out: + return err; +} + +static void armflash_subdev_remove(struct armflash_subdev_info *subdev) +{ + if (subdev->mtd) + map_destroy(subdev->mtd); + if (subdev->map.virt) + iounmap(subdev->map.virt); + release_mem_region(subdev->map.phys, subdev->map.size); +} + +static int armflash_probe(struct platform_device *dev) +{ + struct flash_platform_data *plat = dev->dev.platform_data; + unsigned int size; + struct armflash_info *info; + int i, nr, err; + + /* Count the number of devices */ + for (nr = 0; ; nr++) + if (!platform_get_resource(dev, IORESOURCE_MEM, nr)) + break; + if (nr == 0) { + err = -ENODEV; + goto out; + } + + size = sizeof(struct armflash_info) + + sizeof(struct armflash_subdev_info) * nr; + info = kzalloc(size, GFP_KERNEL); + if (!info) { + err = -ENOMEM; + goto out; + } + + if (plat && plat->init) { + err = plat->init(); + if (err) + goto no_resource; + } + + for (i = 0; i < nr; i++) { + struct armflash_subdev_info *subdev = &info->subdev[i]; + struct resource *res; + + res = platform_get_resource(dev, IORESOURCE_MEM, i); + if (!res) + break; + + if (nr == 1) + /* No MTD concatenation, just use the default name */ + snprintf(subdev->name, SUBDEV_NAME_SIZE, "%s", + dev_name(&dev->dev)); + else + snprintf(subdev->name, SUBDEV_NAME_SIZE, "%s-%d", + dev_name(&dev->dev), i); + subdev->plat = plat; + + err = armflash_subdev_probe(subdev, res); + if (err) + break; + } + info->nr_subdev = i; + + if (err) + goto subdev_err; + + if (info->nr_subdev == 1) + info->mtd = info->subdev[0].mtd; + else if (info->nr_subdev > 1) { +#ifdef CONFIG_MTD_CONCAT + struct mtd_info *cdev[info->nr_subdev]; + + /* + * We detected multiple devices. Concatenate them together. + */ + for (i = 0; i < info->nr_subdev; i++) + cdev[i] = info->subdev[i].mtd; + + info->mtd = mtd_concat_create(cdev, info->nr_subdev, + dev_name(&dev->dev)); + if (info->mtd == NULL) + err = -ENXIO; +#else + printk(KERN_ERR "armflash: multiple devices found but " + "MTD concat support disabled.\n"); + err = -ENXIO; +#endif + } + + if (err < 0) + goto cleanup; err = parse_mtd_partitions(info->mtd, probes, &info->parts, 0); if (err > 0) { @@ -131,28 +227,30 @@ static int armflash_probe(struct platform_device *dev) "mtd partition registration failed: %d\n", err); } - if (err == 0) + if (err == 0) { platform_set_drvdata(dev, info); + return err; + } /* - * If we got an error, free all resources. + * We got an error, free all resources. */ - if (err < 0) { - if (info->mtd) { - del_mtd_partitions(info->mtd); - map_destroy(info->mtd); - } - kfree(info->parts); - - no_device: - iounmap(base); - no_mem: - release_mem_region(res->start, size); - no_resource: - if (plat && plat->exit) - plat->exit(); - kfree(info); + cleanup: + if (info->mtd) { + del_mtd_partitions(info->mtd); +#ifdef CONFIG_MTD_CONCAT + if (info->mtd != info->subdev[0].mtd) + mtd_concat_destroy(info->mtd); +#endif } + kfree(info->parts); + subdev_err: + for (i = info->nr_subdev - 1; i >= 0; i--) + armflash_subdev_remove(&info->subdev[i]); + no_resource: + if (plat && plat->exit) + plat->exit(); + kfree(info); out: return err; } @@ -160,22 +258,26 @@ static int armflash_probe(struct platform_device *dev) static int armflash_remove(struct platform_device *dev) { struct armflash_info *info = platform_get_drvdata(dev); + struct flash_platform_data *plat = dev->dev.platform_data; + int i; platform_set_drvdata(dev, NULL); if (info) { if (info->mtd) { del_mtd_partitions(info->mtd); - map_destroy(info->mtd); +#ifdef CONFIG_MTD_CONCAT + if (info->mtd != info->subdev[0].mtd) + mtd_concat_destroy(info->mtd); +#endif } kfree(info->parts); - iounmap(info->map.virt); - release_resource(info->res); - kfree(info->res); + for (i = info->nr_subdev - 1; i >= 0; i--) + armflash_subdev_remove(&info->subdev[i]); - if (info->plat && info->plat->exit) - info->plat->exit(); + if (plat && plat->exit) + plat->exit(); kfree(info); } diff --git a/drivers/mtd/maps/physmap.c b/drivers/mtd/maps/physmap.c index 29a901157352..380648e9051a 100644 --- a/drivers/mtd/maps/physmap.c +++ b/drivers/mtd/maps/physmap.c @@ -195,42 +195,6 @@ err_out: } #ifdef CONFIG_PM -static int physmap_flash_suspend(struct platform_device *dev, pm_message_t state) -{ - struct physmap_flash_info *info = platform_get_drvdata(dev); - int ret = 0; - int i; - - for (i = 0; i < MAX_RESOURCES && info->mtd[i]; i++) - if (info->mtd[i]->suspend) { - ret = info->mtd[i]->suspend(info->mtd[i]); - if (ret) - goto fail; - } - - return 0; -fail: - for (--i; i >= 0; --i) - if (info->mtd[i]->suspend) { - BUG_ON(!info->mtd[i]->resume); - info->mtd[i]->resume(info->mtd[i]); - } - - return ret; -} - -static int physmap_flash_resume(struct platform_device *dev) -{ - struct physmap_flash_info *info = platform_get_drvdata(dev); - int i; - - for (i = 0; i < MAX_RESOURCES && info->mtd[i]; i++) - if (info->mtd[i]->resume) - info->mtd[i]->resume(info->mtd[i]); - - return 0; -} - static void physmap_flash_shutdown(struct platform_device *dev) { struct physmap_flash_info *info = platform_get_drvdata(dev); @@ -242,16 +206,12 @@ static void physmap_flash_shutdown(struct platform_device *dev) info->mtd[i]->resume(info->mtd[i]); } #else -#define physmap_flash_suspend NULL -#define physmap_flash_resume NULL #define physmap_flash_shutdown NULL #endif static struct platform_driver physmap_flash_driver = { .probe = physmap_flash_probe, .remove = physmap_flash_remove, - .suspend = physmap_flash_suspend, - .resume = physmap_flash_resume, .shutdown = physmap_flash_shutdown, .driver = { .name = "physmap-flash", diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c index c83a60fada53..39d357b2eb47 100644 --- a/drivers/mtd/maps/physmap_of.c +++ b/drivers/mtd/maps/physmap_of.c @@ -20,16 +20,23 @@ #include #include #include +#include #include #include +struct of_flash_list { + struct mtd_info *mtd; + struct map_info map; + struct resource *res; +}; + struct of_flash { - struct mtd_info *mtd; - struct map_info map; - struct resource *res; + struct mtd_info *cmtd; #ifdef CONFIG_MTD_PARTITIONS struct mtd_partition *parts; #endif + int list_size; /* number of elements in of_flash_list */ + struct of_flash_list list[0]; }; #ifdef CONFIG_MTD_PARTITIONS @@ -88,30 +95,44 @@ static int parse_obsolete_partitions(struct of_device *dev, static int of_flash_remove(struct of_device *dev) { struct of_flash *info; + int i; info = dev_get_drvdata(&dev->dev); if (!info) return 0; dev_set_drvdata(&dev->dev, NULL); - if (info->mtd) { +#ifdef CONFIG_MTD_CONCAT + if (info->cmtd != info->list[0].mtd) { + del_mtd_device(info->cmtd); + mtd_concat_destroy(info->cmtd); + } +#endif + + if (info->cmtd) { if (OF_FLASH_PARTS(info)) { - del_mtd_partitions(info->mtd); + del_mtd_partitions(info->cmtd); kfree(OF_FLASH_PARTS(info)); } else { - del_mtd_device(info->mtd); + del_mtd_device(info->cmtd); } - map_destroy(info->mtd); } - if (info->map.virt) - iounmap(info->map.virt); + for (i = 0; i < info->list_size; i++) { + if (info->list[i].mtd) + map_destroy(info->list[i].mtd); - if (info->res) { - release_resource(info->res); - kfree(info->res); + if (info->list[i].map.virt) + iounmap(info->list[i].map.virt); + + if (info->list[i].res) { + release_resource(info->list[i].res); + kfree(info->list[i].res); + } } + kfree(info); + return 0; } @@ -164,68 +185,130 @@ static int __devinit of_flash_probe(struct of_device *dev, const char *probe_type = match->data; const u32 *width; int err; + int i; + int count; + const u32 *p; + int reg_tuple_size; + struct mtd_info **mtd_list = NULL; - err = -ENXIO; - if (of_address_to_resource(dp, 0, &res)) { - dev_err(&dev->dev, "Can't get IO address from device tree\n"); + reg_tuple_size = (of_n_addr_cells(dp) + of_n_size_cells(dp)) * sizeof(u32); + + /* + * Get number of "reg" tuples. Scan for MTD devices on area's + * described by each "reg" region. This makes it possible (including + * the concat support) to support the Intel P30 48F4400 chips which + * consists internally of 2 non-identical NOR chips on one die. + */ + p = of_get_property(dp, "reg", &count); + if (count % reg_tuple_size != 0) { + dev_err(&dev->dev, "Malformed reg property on %s\n", + dev->node->full_name); + err = -EINVAL; goto err_out; } - - dev_dbg(&dev->dev, "of_flash device: %.8llx-%.8llx\n", - (unsigned long long)res.start, (unsigned long long)res.end); + count /= reg_tuple_size; err = -ENOMEM; - info = kzalloc(sizeof(*info), GFP_KERNEL); + info = kzalloc(sizeof(struct of_flash) + + sizeof(struct of_flash_list) * count, GFP_KERNEL); + if (!info) + goto err_out; + + mtd_list = kzalloc(sizeof(struct mtd_info) * count, GFP_KERNEL); if (!info) goto err_out; dev_set_drvdata(&dev->dev, info); - err = -EBUSY; - info->res = request_mem_region(res.start, res.end - res.start + 1, - dev_name(&dev->dev)); - if (!info->res) - goto err_out; + for (i = 0; i < count; i++) { + err = -ENXIO; + if (of_address_to_resource(dp, i, &res)) { + dev_err(&dev->dev, "Can't get IO address from device" + " tree\n"); + goto err_out; + } - err = -ENXIO; - width = of_get_property(dp, "bank-width", NULL); - if (!width) { - dev_err(&dev->dev, "Can't get bank width from device tree\n"); - goto err_out; + dev_dbg(&dev->dev, "of_flash device: %.8llx-%.8llx\n", + (unsigned long long)res.start, + (unsigned long long)res.end); + + err = -EBUSY; + info->list[i].res = request_mem_region(res.start, res.end - + res.start + 1, + dev_name(&dev->dev)); + if (!info->list[i].res) + goto err_out; + + err = -ENXIO; + width = of_get_property(dp, "bank-width", NULL); + if (!width) { + dev_err(&dev->dev, "Can't get bank width from device" + " tree\n"); + goto err_out; + } + + info->list[i].map.name = dev_name(&dev->dev); + info->list[i].map.phys = res.start; + info->list[i].map.size = res.end - res.start + 1; + info->list[i].map.bankwidth = *width; + + err = -ENOMEM; + info->list[i].map.virt = ioremap(info->list[i].map.phys, + info->list[i].map.size); + if (!info->list[i].map.virt) { + dev_err(&dev->dev, "Failed to ioremap() flash" + " region\n"); + goto err_out; + } + + simple_map_init(&info->list[i].map); + + if (probe_type) { + info->list[i].mtd = do_map_probe(probe_type, + &info->list[i].map); + } else { + info->list[i].mtd = obsolete_probe(dev, + &info->list[i].map); + } + mtd_list[i] = info->list[i].mtd; + + err = -ENXIO; + if (!info->list[i].mtd) { + dev_err(&dev->dev, "do_map_probe() failed\n"); + goto err_out; + } else { + info->list_size++; + } + info->list[i].mtd->owner = THIS_MODULE; + info->list[i].mtd->dev.parent = &dev->dev; } - info->map.name = dev_name(&dev->dev); - info->map.phys = res.start; - info->map.size = res.end - res.start + 1; - info->map.bankwidth = *width; - - err = -ENOMEM; - info->map.virt = ioremap(info->map.phys, info->map.size); - if (!info->map.virt) { - dev_err(&dev->dev, "Failed to ioremap() flash region\n"); - goto err_out; + err = 0; + if (info->list_size == 1) { + info->cmtd = info->list[0].mtd; + } else if (info->list_size > 1) { + /* + * We detected multiple devices. Concatenate them together. + */ +#ifdef CONFIG_MTD_CONCAT + info->cmtd = mtd_concat_create(mtd_list, info->list_size, + dev_name(&dev->dev)); + if (info->cmtd == NULL) + err = -ENXIO; +#else + printk(KERN_ERR "physmap_of: multiple devices " + "found but MTD concat support disabled.\n"); + err = -ENXIO; +#endif } - - simple_map_init(&info->map); - - if (probe_type) - info->mtd = do_map_probe(probe_type, &info->map); - else - info->mtd = obsolete_probe(dev, &info->map); - - err = -ENXIO; - if (!info->mtd) { - dev_err(&dev->dev, "do_map_probe() failed\n"); + if (err) goto err_out; - } - info->mtd->owner = THIS_MODULE; - info->mtd->dev.parent = &dev->dev; #ifdef CONFIG_MTD_PARTITIONS /* First look for RedBoot table or partitions on the command * line, these take precedence over device tree information */ - err = parse_mtd_partitions(info->mtd, part_probe_types, - &info->parts, 0); + err = parse_mtd_partitions(info->cmtd, part_probe_types, + &info->parts, 0); if (err < 0) return err; @@ -244,15 +327,19 @@ static int __devinit of_flash_probe(struct of_device *dev, } if (err > 0) - add_mtd_partitions(info->mtd, info->parts, err); + add_mtd_partitions(info->cmtd, info->parts, err); else #endif - add_mtd_device(info->mtd); + add_mtd_device(info->cmtd); + + kfree(mtd_list); return 0; err_out: + kfree(mtd_list); of_flash_remove(dev); + return err; } diff --git a/drivers/mtd/maps/pmcmsp-ramroot.c b/drivers/mtd/maps/pmcmsp-ramroot.c deleted file mode 100644 index 30de5c0c09a9..000000000000 --- a/drivers/mtd/maps/pmcmsp-ramroot.c +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Mapping of the rootfs in a physical region of memory - * - * Copyright (C) 2005-2007 PMC-Sierra Inc. - * Author: Andrew Hughes, Andrew_Hughes@pmc-sierra.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 -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -static struct mtd_info *rr_mtd; - -struct map_info rr_map = { - .name = "ramroot", - .bankwidth = 4, -}; - -static int __init init_rrmap(void) -{ - void *ramroot_start; - unsigned long ramroot_size; - - /* Check for supported rootfs types */ - if (get_ramroot(&ramroot_start, &ramroot_size)) { - rr_map.phys = CPHYSADDR(ramroot_start); - rr_map.size = ramroot_size; - - printk(KERN_NOTICE - "PMC embedded root device: 0x%08lx @ 0x%08lx\n", - rr_map.size, (unsigned long)rr_map.phys); - } else { - printk(KERN_ERR - "init_rrmap: no supported embedded rootfs detected!\n"); - return -ENXIO; - } - - /* Map rootfs to I/O space for block device driver */ - rr_map.virt = ioremap(rr_map.phys, rr_map.size); - if (!rr_map.virt) { - printk(KERN_ERR "Failed to ioremap\n"); - return -EIO; - } - - simple_map_init(&rr_map); - - rr_mtd = do_map_probe("map_ram", &rr_map); - if (rr_mtd) { - rr_mtd->owner = THIS_MODULE; - - add_mtd_device(rr_mtd); - - return 0; - } - - iounmap(rr_map.virt); - return -ENXIO; -} - -static void __exit cleanup_rrmap(void) -{ - del_mtd_device(rr_mtd); - map_destroy(rr_mtd); - - iounmap(rr_map.virt); - rr_map.virt = NULL; -} - -MODULE_AUTHOR("PMC-Sierra, Inc"); -MODULE_DESCRIPTION("MTD map driver for embedded PMC-Sierra MSP filesystem"); -MODULE_LICENSE("GPL"); - -module_init(init_rrmap); -module_exit(cleanup_rrmap); diff --git a/drivers/mtd/maps/pxa2xx-flash.c b/drivers/mtd/maps/pxa2xx-flash.c index 572d32fdf38a..643aa06b599e 100644 --- a/drivers/mtd/maps/pxa2xx-flash.c +++ b/drivers/mtd/maps/pxa2xx-flash.c @@ -140,24 +140,6 @@ static int __devexit pxa2xx_flash_remove(struct platform_device *dev) } #ifdef CONFIG_PM -static int pxa2xx_flash_suspend(struct platform_device *dev, pm_message_t state) -{ - struct pxa2xx_flash_info *info = platform_get_drvdata(dev); - int ret = 0; - - if (info->mtd && info->mtd->suspend) - ret = info->mtd->suspend(info->mtd); - return ret; -} - -static int pxa2xx_flash_resume(struct platform_device *dev) -{ - struct pxa2xx_flash_info *info = platform_get_drvdata(dev); - - if (info->mtd && info->mtd->resume) - info->mtd->resume(info->mtd); - return 0; -} static void pxa2xx_flash_shutdown(struct platform_device *dev) { struct pxa2xx_flash_info *info = platform_get_drvdata(dev); @@ -166,8 +148,6 @@ static void pxa2xx_flash_shutdown(struct platform_device *dev) info->mtd->resume(info->mtd); } #else -#define pxa2xx_flash_suspend NULL -#define pxa2xx_flash_resume NULL #define pxa2xx_flash_shutdown NULL #endif @@ -178,8 +158,6 @@ static struct platform_driver pxa2xx_flash_driver = { }, .probe = pxa2xx_flash_probe, .remove = __devexit_p(pxa2xx_flash_remove), - .suspend = pxa2xx_flash_suspend, - .resume = pxa2xx_flash_resume, .shutdown = pxa2xx_flash_shutdown, }; diff --git a/drivers/mtd/maps/rbtx4939-flash.c b/drivers/mtd/maps/rbtx4939-flash.c index d39f0adac846..83ed64512c5e 100644 --- a/drivers/mtd/maps/rbtx4939-flash.c +++ b/drivers/mtd/maps/rbtx4939-flash.c @@ -145,25 +145,6 @@ err_out: } #ifdef CONFIG_PM -static int rbtx4939_flash_suspend(struct platform_device *dev, - pm_message_t state) -{ - struct rbtx4939_flash_info *info = platform_get_drvdata(dev); - - if (info->mtd->suspend) - return info->mtd->suspend(info->mtd); - return 0; -} - -static int rbtx4939_flash_resume(struct platform_device *dev) -{ - struct rbtx4939_flash_info *info = platform_get_drvdata(dev); - - if (info->mtd->resume) - info->mtd->resume(info->mtd); - return 0; -} - static void rbtx4939_flash_shutdown(struct platform_device *dev) { struct rbtx4939_flash_info *info = platform_get_drvdata(dev); @@ -173,16 +154,12 @@ static void rbtx4939_flash_shutdown(struct platform_device *dev) info->mtd->resume(info->mtd); } #else -#define rbtx4939_flash_suspend NULL -#define rbtx4939_flash_resume NULL #define rbtx4939_flash_shutdown NULL #endif static struct platform_driver rbtx4939_flash_driver = { .probe = rbtx4939_flash_probe, .remove = rbtx4939_flash_remove, - .suspend = rbtx4939_flash_suspend, - .resume = rbtx4939_flash_resume, .shutdown = rbtx4939_flash_shutdown, .driver = { .name = "rbtx4939-flash", diff --git a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c index 05e9362dc7f0..c6210f5118d1 100644 --- a/drivers/mtd/maps/sa1100-flash.c +++ b/drivers/mtd/maps/sa1100-flash.c @@ -415,25 +415,6 @@ static int __exit sa1100_mtd_remove(struct platform_device *pdev) } #ifdef CONFIG_PM -static int sa1100_mtd_suspend(struct platform_device *dev, pm_message_t state) -{ - struct sa_info *info = platform_get_drvdata(dev); - int ret = 0; - - if (info) - ret = info->mtd->suspend(info->mtd); - - return ret; -} - -static int sa1100_mtd_resume(struct platform_device *dev) -{ - struct sa_info *info = platform_get_drvdata(dev); - if (info) - info->mtd->resume(info->mtd); - return 0; -} - static void sa1100_mtd_shutdown(struct platform_device *dev) { struct sa_info *info = platform_get_drvdata(dev); @@ -441,16 +422,12 @@ static void sa1100_mtd_shutdown(struct platform_device *dev) info->mtd->resume(info->mtd); } #else -#define sa1100_mtd_suspend NULL -#define sa1100_mtd_resume NULL #define sa1100_mtd_shutdown NULL #endif static struct platform_driver sa1100_mtd_driver = { .probe = sa1100_mtd_probe, .remove = __exit_p(sa1100_mtd_remove), - .suspend = sa1100_mtd_suspend, - .resume = sa1100_mtd_resume, .shutdown = sa1100_mtd_shutdown, .driver = { .name = "sa1100-mtd", diff --git a/drivers/mtd/maps/uclinux.c b/drivers/mtd/maps/uclinux.c index 81756e397711..d4314fb88212 100644 --- a/drivers/mtd/maps/uclinux.c +++ b/drivers/mtd/maps/uclinux.c @@ -22,15 +22,19 @@ /****************************************************************************/ +extern char _ebss; + struct map_info uclinux_ram_map = { .name = "RAM", + .phys = (unsigned long)&_ebss, + .size = 0, }; -struct mtd_info *uclinux_ram_mtdinfo; +static struct mtd_info *uclinux_ram_mtdinfo; /****************************************************************************/ -struct mtd_partition uclinux_romfs[] = { +static struct mtd_partition uclinux_romfs[] = { { .name = "ROMfs" } }; @@ -38,7 +42,7 @@ struct mtd_partition uclinux_romfs[] = { /****************************************************************************/ -int uclinux_point(struct mtd_info *mtd, loff_t from, size_t len, +static int uclinux_point(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, void **virt, resource_size_t *phys) { struct map_info *map = mtd->priv; @@ -55,12 +59,10 @@ static int __init uclinux_mtd_init(void) { struct mtd_info *mtd; struct map_info *mapp; - extern char _ebss; - unsigned long addr = (unsigned long) &_ebss; mapp = &uclinux_ram_map; - mapp->phys = addr; - mapp->size = PAGE_ALIGN(ntohl(*((unsigned long *)(addr + 8)))); + if (!mapp->size) + mapp->size = PAGE_ALIGN(ntohl(*((unsigned long *)(mapp->phys + 8)))); mapp->bankwidth = 4; printk("uclinux[mtd]: RAM probe address=0x%x size=0x%x\n", diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index a49a9c8f2cb1..c3f62654b6df 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c @@ -47,40 +47,41 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr, unsigned long block, nsect; char *buf; - block = req->sector << 9 >> tr->blkshift; - nsect = req->current_nr_sectors << 9 >> tr->blkshift; + block = blk_rq_pos(req) << 9 >> tr->blkshift; + nsect = blk_rq_cur_bytes(req) >> tr->blkshift; buf = req->buffer; if (req->cmd_type == REQ_TYPE_LINUX_BLOCK && req->cmd[0] == REQ_LB_OP_DISCARD) - return !tr->discard(dev, block, nsect); + return tr->discard(dev, block, nsect); if (!blk_fs_request(req)) - return 0; + return -EIO; - if (req->sector + req->current_nr_sectors > get_capacity(req->rq_disk)) - return 0; + if (blk_rq_pos(req) + blk_rq_cur_sectors(req) > + get_capacity(req->rq_disk)) + return -EIO; switch(rq_data_dir(req)) { case READ: for (; nsect > 0; nsect--, block++, buf += tr->blksize) if (tr->readsect(dev, block, buf)) - return 0; - return 1; + return -EIO; + return 0; case WRITE: if (!tr->writesect) - return 0; + return -EIO; for (; nsect > 0; nsect--, block++, buf += tr->blksize) if (tr->writesect(dev, block, buf)) - return 0; - return 1; + return -EIO; + return 0; default: printk(KERN_NOTICE "Unknown request %u\n", rq_data_dir(req)); - return 0; + return -EIO; } } @@ -88,19 +89,18 @@ static int mtd_blktrans_thread(void *arg) { struct mtd_blktrans_ops *tr = arg; struct request_queue *rq = tr->blkcore_priv->rq; + struct request *req = NULL; /* we might get involved when memory gets low, so use PF_MEMALLOC */ current->flags |= PF_MEMALLOC; spin_lock_irq(rq->queue_lock); + while (!kthread_should_stop()) { - struct request *req; struct mtd_blktrans_dev *dev; - int res = 0; + int res; - req = elv_next_request(rq); - - if (!req) { + if (!req && !(req = blk_fetch_request(rq))) { set_current_state(TASK_INTERRUPTIBLE); spin_unlock_irq(rq->queue_lock); schedule(); @@ -119,8 +119,13 @@ static int mtd_blktrans_thread(void *arg) spin_lock_irq(rq->queue_lock); - end_request(req, res); + if (!__blk_end_request_cur(req, res)) + req = NULL; } + + if (req) + __blk_end_request_all(req, -EIO); + spin_unlock_irq(rq->queue_lock); return 0; @@ -286,7 +291,7 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) gd->private_data = new; new->blkcore_priv = gd; gd->queue = tr->blkcore_priv->rq; - gd->driverfs_dev = new->mtd->dev.parent; + gd->driverfs_dev = &new->mtd->dev; if (new->readonly) set_disk_ro(gd, 1); @@ -373,7 +378,7 @@ int register_mtd_blktrans(struct mtd_blktrans_ops *tr) } tr->blkcore_priv->rq->queuedata = tr; - blk_queue_hardsect_size(tr->blkcore_priv->rq, tr->blksize); + blk_queue_logical_block_size(tr->blkcore_priv->rq, tr->blksize); if (tr->discard) blk_queue_set_discard(tr->blkcore_priv->rq, blktrans_discard_request); diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index 763d3f0a1f42..5b081cb84351 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -355,6 +356,100 @@ static int otp_select_filemode(struct mtd_file_info *mfi, int mode) # define otp_select_filemode(f,m) -EOPNOTSUPP #endif +static int mtd_do_writeoob(struct file *file, struct mtd_info *mtd, + uint64_t start, uint32_t length, void __user *ptr, + uint32_t __user *retp) +{ + struct mtd_oob_ops ops; + uint32_t retlen; + int ret = 0; + + if (!(file->f_mode & FMODE_WRITE)) + return -EPERM; + + if (length > 4096) + return -EINVAL; + + if (!mtd->write_oob) + ret = -EOPNOTSUPP; + else + ret = access_ok(VERIFY_READ, ptr, length) ? 0 : EFAULT; + + if (ret) + return ret; + + ops.ooblen = length; + ops.ooboffs = start & (mtd->oobsize - 1); + ops.datbuf = NULL; + ops.mode = MTD_OOB_PLACE; + + if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs)) + return -EINVAL; + + ops.oobbuf = kmalloc(length, GFP_KERNEL); + if (!ops.oobbuf) + return -ENOMEM; + + if (copy_from_user(ops.oobbuf, ptr, length)) { + kfree(ops.oobbuf); + return -EFAULT; + } + + start &= ~((uint64_t)mtd->oobsize - 1); + ret = mtd->write_oob(mtd, start, &ops); + + if (ops.oobretlen > 0xFFFFFFFFU) + ret = -EOVERFLOW; + retlen = ops.oobretlen; + if (copy_to_user(retp, &retlen, sizeof(length))) + ret = -EFAULT; + + kfree(ops.oobbuf); + return ret; +} + +static int mtd_do_readoob(struct mtd_info *mtd, uint64_t start, + uint32_t length, void __user *ptr, uint32_t __user *retp) +{ + struct mtd_oob_ops ops; + int ret = 0; + + if (length > 4096) + return -EINVAL; + + if (!mtd->read_oob) + ret = -EOPNOTSUPP; + else + ret = access_ok(VERIFY_WRITE, ptr, + length) ? 0 : -EFAULT; + if (ret) + return ret; + + ops.ooblen = length; + ops.ooboffs = start & (mtd->oobsize - 1); + ops.datbuf = NULL; + ops.mode = MTD_OOB_PLACE; + + if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs)) + return -EINVAL; + + ops.oobbuf = kmalloc(length, GFP_KERNEL); + if (!ops.oobbuf) + return -ENOMEM; + + start &= ~((uint64_t)mtd->oobsize - 1); + ret = mtd->read_oob(mtd, start, &ops); + + if (put_user(ops.oobretlen, retp)) + ret = -EFAULT; + else if (ops.oobretlen && copy_to_user(ptr, ops.oobbuf, + ops.oobretlen)) + ret = -EFAULT; + + kfree(ops.oobbuf); + return ret; +} + static int mtd_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg) { @@ -417,6 +512,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file, break; case MEMERASE: + case MEMERASE64: { struct erase_info *erase; @@ -427,20 +523,32 @@ static int mtd_ioctl(struct inode *inode, struct file *file, if (!erase) ret = -ENOMEM; else { - struct erase_info_user einfo; - wait_queue_head_t waitq; DECLARE_WAITQUEUE(wait, current); init_waitqueue_head(&waitq); - if (copy_from_user(&einfo, argp, - sizeof(struct erase_info_user))) { - kfree(erase); - return -EFAULT; + if (cmd == MEMERASE64) { + struct erase_info_user64 einfo64; + + if (copy_from_user(&einfo64, argp, + sizeof(struct erase_info_user64))) { + kfree(erase); + return -EFAULT; + } + erase->addr = einfo64.start; + erase->len = einfo64.length; + } else { + struct erase_info_user einfo32; + + if (copy_from_user(&einfo32, argp, + sizeof(struct erase_info_user))) { + kfree(erase); + return -EFAULT; + } + erase->addr = einfo32.start; + erase->len = einfo32.length; } - erase->addr = einfo.start; - erase->len = einfo.length; erase->mtd = mtd; erase->callback = mtdchar_erase_callback; erase->priv = (unsigned long)&waitq; @@ -474,100 +582,56 @@ static int mtd_ioctl(struct inode *inode, struct file *file, case MEMWRITEOOB: { struct mtd_oob_buf buf; - struct mtd_oob_ops ops; - struct mtd_oob_buf __user *user_buf = argp; - uint32_t retlen; + struct mtd_oob_buf __user *buf_user = argp; - if(!(file->f_mode & FMODE_WRITE)) - return -EPERM; - - if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf))) - return -EFAULT; - - if (buf.length > 4096) - return -EINVAL; - - if (!mtd->write_oob) - ret = -EOPNOTSUPP; - else - ret = access_ok(VERIFY_READ, buf.ptr, - buf.length) ? 0 : EFAULT; - - if (ret) - return ret; - - ops.ooblen = buf.length; - ops.ooboffs = buf.start & (mtd->oobsize - 1); - ops.datbuf = NULL; - ops.mode = MTD_OOB_PLACE; - - if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs)) - return -EINVAL; - - ops.oobbuf = kmalloc(buf.length, GFP_KERNEL); - if (!ops.oobbuf) - return -ENOMEM; - - if (copy_from_user(ops.oobbuf, buf.ptr, buf.length)) { - kfree(ops.oobbuf); - return -EFAULT; - } - - buf.start &= ~(mtd->oobsize - 1); - ret = mtd->write_oob(mtd, buf.start, &ops); - - if (ops.oobretlen > 0xFFFFFFFFU) - ret = -EOVERFLOW; - retlen = ops.oobretlen; - if (copy_to_user(&user_buf->length, &retlen, sizeof(buf.length))) + /* NOTE: writes return length to buf_user->length */ + if (copy_from_user(&buf, argp, sizeof(buf))) ret = -EFAULT; - - kfree(ops.oobbuf); + else + ret = mtd_do_writeoob(file, mtd, buf.start, buf.length, + buf.ptr, &buf_user->length); break; - } case MEMREADOOB: { struct mtd_oob_buf buf; - struct mtd_oob_ops ops; + struct mtd_oob_buf __user *buf_user = argp; - if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf))) - return -EFAULT; - - if (buf.length > 4096) - return -EINVAL; - - if (!mtd->read_oob) - ret = -EOPNOTSUPP; + /* NOTE: writes return length to buf_user->start */ + if (copy_from_user(&buf, argp, sizeof(buf))) + ret = -EFAULT; else - ret = access_ok(VERIFY_WRITE, buf.ptr, - buf.length) ? 0 : -EFAULT; - if (ret) - return ret; + ret = mtd_do_readoob(mtd, buf.start, buf.length, + buf.ptr, &buf_user->start); + break; + } - ops.ooblen = buf.length; - ops.ooboffs = buf.start & (mtd->oobsize - 1); - ops.datbuf = NULL; - ops.mode = MTD_OOB_PLACE; + case MEMWRITEOOB64: + { + struct mtd_oob_buf64 buf; + struct mtd_oob_buf64 __user *buf_user = argp; - if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs)) - return -EINVAL; - - ops.oobbuf = kmalloc(buf.length, GFP_KERNEL); - if (!ops.oobbuf) - return -ENOMEM; - - buf.start &= ~(mtd->oobsize - 1); - ret = mtd->read_oob(mtd, buf.start, &ops); - - if (put_user(ops.oobretlen, (uint32_t __user *)argp)) - ret = -EFAULT; - else if (ops.oobretlen && copy_to_user(buf.ptr, ops.oobbuf, - ops.oobretlen)) + if (copy_from_user(&buf, argp, sizeof(buf))) ret = -EFAULT; + else + ret = mtd_do_writeoob(file, mtd, buf.start, buf.length, + (void __user *)(uintptr_t)buf.usr_ptr, + &buf_user->length); + break; + } - kfree(ops.oobbuf); + case MEMREADOOB64: + { + struct mtd_oob_buf64 buf; + struct mtd_oob_buf64 __user *buf_user = argp; + + if (copy_from_user(&buf, argp, sizeof(buf))) + ret = -EFAULT; + else + ret = mtd_do_readoob(mtd, buf.start, buf.length, + (void __user *)(uintptr_t)buf.usr_ptr, + &buf_user->length); break; } @@ -758,6 +822,68 @@ static int mtd_ioctl(struct inode *inode, struct file *file, return ret; } /* memory_ioctl */ +#ifdef CONFIG_COMPAT + +struct mtd_oob_buf32 { + u_int32_t start; + u_int32_t length; + compat_caddr_t ptr; /* unsigned char* */ +}; + +#define MEMWRITEOOB32 _IOWR('M', 3, struct mtd_oob_buf32) +#define MEMREADOOB32 _IOWR('M', 4, struct mtd_oob_buf32) + +static long mtd_compat_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct inode *inode = file->f_path.dentry->d_inode; + struct mtd_file_info *mfi = file->private_data; + struct mtd_info *mtd = mfi->mtd; + void __user *argp = compat_ptr(arg); + int ret = 0; + + lock_kernel(); + + switch (cmd) { + case MEMWRITEOOB32: + { + struct mtd_oob_buf32 buf; + struct mtd_oob_buf32 __user *buf_user = argp; + + if (copy_from_user(&buf, argp, sizeof(buf))) + ret = -EFAULT; + else + ret = mtd_do_writeoob(file, mtd, buf.start, + buf.length, compat_ptr(buf.ptr), + &buf_user->length); + break; + } + + case MEMREADOOB32: + { + struct mtd_oob_buf32 buf; + struct mtd_oob_buf32 __user *buf_user = argp; + + /* NOTE: writes return length to buf->start */ + if (copy_from_user(&buf, argp, sizeof(buf))) + ret = -EFAULT; + else + ret = mtd_do_readoob(mtd, buf.start, + buf.length, compat_ptr(buf.ptr), + &buf_user->start); + break; + } + default: + ret = mtd_ioctl(inode, file, cmd, (unsigned long)argp); + } + + unlock_kernel(); + + return ret; +} + +#endif /* CONFIG_COMPAT */ + /* * try to determine where a shared mapping can be made * - only supported for NOMMU at the moment (MMU can't doesn't copy private @@ -817,6 +943,9 @@ static const struct file_operations mtd_fops = { .read = mtd_read, .write = mtd_write, .ioctl = mtd_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = mtd_compat_ioctl, +#endif .open = mtd_open, .release = mtd_close, .mmap = mtd_mmap, diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index bccb4b1ffc46..fac54a3fa3f1 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -23,8 +23,15 @@ #include "mtdcore.h" +static int mtd_cls_suspend(struct device *dev, pm_message_t state); +static int mtd_cls_resume(struct device *dev); -static struct class *mtd_class; +static struct class mtd_class = { + .name = "mtd", + .owner = THIS_MODULE, + .suspend = mtd_cls_suspend, + .resume = mtd_cls_resume, +}; /* These are exported solely for the purpose of mtd_blkdevs.c. You should not use them for _anything_ else */ @@ -52,7 +59,26 @@ static void mtd_release(struct device *dev) /* remove /dev/mtdXro node if needed */ if (index) - device_destroy(mtd_class, index + 1); + device_destroy(&mtd_class, index + 1); +} + +static int mtd_cls_suspend(struct device *dev, pm_message_t state) +{ + struct mtd_info *mtd = dev_to_mtd(dev); + + if (mtd->suspend) + return mtd->suspend(mtd); + else + return 0; +} + +static int mtd_cls_resume(struct device *dev) +{ + struct mtd_info *mtd = dev_to_mtd(dev); + + if (mtd->resume) + mtd->resume(mtd); + return 0; } static ssize_t mtd_type_show(struct device *dev, @@ -269,7 +295,7 @@ int add_mtd_device(struct mtd_info *mtd) * physical device. */ mtd->dev.type = &mtd_devtype; - mtd->dev.class = mtd_class; + mtd->dev.class = &mtd_class; mtd->dev.devt = MTD_DEVT(i); dev_set_name(&mtd->dev, "mtd%d", i); if (device_register(&mtd->dev) != 0) { @@ -278,7 +304,7 @@ int add_mtd_device(struct mtd_info *mtd) } if (MTD_DEVT(i)) - device_create(mtd_class, mtd->dev.parent, + device_create(&mtd_class, mtd->dev.parent, MTD_DEVT(i) + 1, NULL, "mtd%dro", i); @@ -604,11 +630,12 @@ done: static int __init init_mtd(void) { - mtd_class = class_create(THIS_MODULE, "mtd"); + int ret; + ret = class_register(&mtd_class); - if (IS_ERR(mtd_class)) { - pr_err("Error creating mtd class.\n"); - return PTR_ERR(mtd_class); + if (ret) { + pr_err("Error registering mtd class: %d\n", ret); + return ret; } #ifdef CONFIG_PROC_FS if ((proc_mtd = create_proc_entry( "mtd", 0, NULL ))) @@ -623,7 +650,7 @@ static void __exit cleanup_mtd(void) if (proc_mtd) remove_proc_entry( "mtd", NULL); #endif /* CONFIG_PROC_FS */ - class_destroy(mtd_class); + class_unregister(&mtd_class); } module_init(init_mtd); diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 29675edb44b4..349fcbe5cc0f 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -27,9 +27,7 @@ struct mtd_part { struct mtd_info mtd; struct mtd_info *master; uint64_t offset; - int index; struct list_head list; - int registered; }; /* @@ -321,8 +319,7 @@ int del_mtd_partitions(struct mtd_info *master) list_for_each_entry_safe(slave, next, &mtd_partitions, list) if (slave->master == master) { list_del(&slave->list); - if (slave->registered) - del_mtd_device(&slave->mtd); + del_mtd_device(&slave->mtd); kfree(slave); } @@ -395,7 +392,7 @@ static struct mtd_part *add_one_partition(struct mtd_info *master, slave->mtd.get_fact_prot_info = part_get_fact_prot_info; if (master->sync) slave->mtd.sync = part_sync; - if (!partno && master->suspend && master->resume) { + if (!partno && !master->dev.class && master->suspend && master->resume) { slave->mtd.suspend = part_suspend; slave->mtd.resume = part_resume; } @@ -412,7 +409,6 @@ static struct mtd_part *add_one_partition(struct mtd_info *master, slave->mtd.erase = part_erase; slave->master = master; slave->offset = part->offset; - slave->index = partno; if (slave->offset == MTDPART_OFS_APPEND) slave->offset = cur_offset; @@ -500,15 +496,9 @@ static struct mtd_part *add_one_partition(struct mtd_info *master, } out_register: - if (part->mtdp) { - /* store the object pointer (caller may or may not register it*/ - *part->mtdp = &slave->mtd; - slave->registered = 0; - } else { - /* register our partition */ - add_mtd_device(&slave->mtd); - slave->registered = 1; - } + /* register our partition */ + add_mtd_device(&slave->mtd); + return slave; } diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 890936d0275e..ce96c091f01b 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -74,6 +74,12 @@ config MTD_NAND_AMS_DELTA help Support for NAND flash on Amstrad E3 (Delta). +config MTD_NAND_OMAP2 + tristate "NAND Flash device on OMAP2 and OMAP3" + depends on ARM && MTD_NAND && (ARCH_OMAP2 || ARCH_OMAP3) + help + Support for NAND flash on Texas Instruments OMAP2 and OMAP3 platforms. + config MTD_NAND_TS7250 tristate "NAND Flash device on TS-7250 board" depends on MACH_TS72XX @@ -139,27 +145,27 @@ config MTD_NAND_PPCHAMELEONEVB This enables the NAND flash driver on the PPChameleon EVB Board. config MTD_NAND_S3C2410 - tristate "NAND Flash support for S3C2410/S3C2440 SoC" - depends on ARCH_S3C2410 + tristate "NAND Flash support for Samsung S3C SoCs" + depends on ARCH_S3C2410 || ARCH_S3C64XX help - This enables the NAND flash controller on the S3C2410 and S3C2440 + This enables the NAND flash controller on the S3C24xx and S3C64xx SoCs No board specific support is done by this driver, each board must advertise a platform_device for the driver to attach. config MTD_NAND_S3C2410_DEBUG - bool "S3C2410 NAND driver debug" + bool "Samsung S3C NAND driver debug" depends on MTD_NAND_S3C2410 help - Enable debugging of the S3C2410 NAND driver + Enable debugging of the S3C NAND driver config MTD_NAND_S3C2410_HWECC - bool "S3C2410 NAND Hardware ECC" + bool "Samsung S3C NAND Hardware ECC" depends on MTD_NAND_S3C2410 help - Enable the use of the S3C2410's internal ECC generator when - using NAND. Early versions of the chip have had problems with + Enable the use of the controller's internal ECC generator when + using NAND. Early versions of the chips have had problems with incorrect ECC generation, and if using these, the default of software ECC is preferable. @@ -171,7 +177,7 @@ config MTD_NAND_NDFC NDFC Nand Flash Controllers are integrated in IBM/AMCC's 4xx SoCs config MTD_NAND_S3C2410_CLKSTOP - bool "S3C2410 NAND IDLE clock stop" + bool "Samsung S3C NAND IDLE clock stop" depends on MTD_NAND_S3C2410 default n help @@ -260,7 +266,7 @@ config MTD_NAND_BASLER_EXCITE help This enables the driver for the NAND flash device found on the Basler eXcite Smart Camera. If built as a module, the driver - will be named "excite_nandflash.ko". + will be named excite_nandflash. config MTD_NAND_CAFE tristate "NAND support for OLPC CAFÉ chip" @@ -282,7 +288,7 @@ config MTD_NAND_CS553X controller is enabled for NAND, and currently requires that the controller be in MMIO mode. - If you say "m", the module will be called "cs553x_nand.ko". + If you say "m", the module will be called cs553x_nand. config MTD_NAND_ATMEL tristate "Support for NAND Flash / SmartMedia on AT91 and AVR32" diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index d33860ac42c3..f3a786b3cff3 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -25,6 +25,7 @@ obj-$(CONFIG_MTD_NAND_CS553X) += cs553x_nand.o obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o obj-$(CONFIG_MTD_NAND_ATMEL) += atmel_nand.o obj-$(CONFIG_MTD_NAND_GPIO) += gpio.o +obj-$(CONFIG_MTD_NAND_OMAP2) += omap2.o obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o obj-$(CONFIG_MTD_NAND_BASLER_EXCITE) += excite_nandflash.o obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 47a33cec3793..2802992b39da 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -47,6 +48,9 @@ #define no_ecc 0 #endif +static int on_flash_bbt = 0; +module_param(on_flash_bbt, int, 0); + /* Register access macros */ #define ecc_readl(add, reg) \ __raw_readl(add + ATMEL_ECC_##reg) @@ -459,12 +463,17 @@ static int __init atmel_nand_probe(struct platform_device *pdev) if (host->board->det_pin) { if (gpio_get_value(host->board->det_pin)) { - printk("No SmartMedia card inserted.\n"); + printk(KERN_INFO "No SmartMedia card inserted.\n"); res = ENXIO; goto err_no_card; } } + if (on_flash_bbt) { + printk(KERN_INFO "atmel_nand: Use On Flash BBT\n"); + nand_chip->options |= NAND_USE_FLASH_BBT; + } + /* first scan to find the device and get the page size */ if (nand_scan_ident(mtd, 1)) { res = -ENXIO; diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c index 4c2a67ca801e..8506e7e606fd 100644 --- a/drivers/mtd/nand/bf5xx_nand.c +++ b/drivers/mtd/nand/bf5xx_nand.c @@ -458,7 +458,7 @@ static irqreturn_t bf5xx_nand_dma_irq(int irq, void *dev_id) return IRQ_HANDLED; } -static int bf5xx_nand_dma_rw(struct mtd_info *mtd, +static void bf5xx_nand_dma_rw(struct mtd_info *mtd, uint8_t *buf, int is_read) { struct bf5xx_nand_info *info = mtd_to_nand_info(mtd); @@ -496,11 +496,20 @@ static int bf5xx_nand_dma_rw(struct mtd_info *mtd, /* setup DMA register with Blackfin DMA API */ set_dma_config(CH_NFC, 0x0); set_dma_start_addr(CH_NFC, (unsigned long) buf); + +/* The DMAs have different size on BF52x and BF54x */ +#ifdef CONFIG_BF52x + set_dma_x_count(CH_NFC, (page_size >> 1)); + set_dma_x_modify(CH_NFC, 2); + val = DI_EN | WDSIZE_16; +#endif + +#ifdef CONFIG_BF54x set_dma_x_count(CH_NFC, (page_size >> 2)); set_dma_x_modify(CH_NFC, 4); - - /* setup write or read operation */ val = DI_EN | WDSIZE_32; +#endif + /* setup write or read operation */ if (is_read) val |= WNR; set_dma_config(CH_NFC, val); @@ -512,8 +521,6 @@ static int bf5xx_nand_dma_rw(struct mtd_info *mtd, else bfin_write_NFC_PGCTL(0x2); wait_for_completion(&info->dma_completion); - - return 0; } static void bf5xx_nand_dma_read_buf(struct mtd_info *mtd, diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c index 02700f769b8a..0fad6487e6f4 100644 --- a/drivers/mtd/nand/davinci_nand.c +++ b/drivers/mtd/nand/davinci_nand.c @@ -44,7 +44,7 @@ * and some flavors of secondary chipselect (e.g. based on A12) as used * with multichip packages. * - * The 1-bit ECC hardware is supported, but not yet the newer 4-bit ECC + * The 1-bit ECC hardware is supported, as well as the newer 4-bit ECC * available on chips like the DM355 and OMAP-L137 and needed with the * more error-prone MLC NAND chips. * @@ -54,11 +54,14 @@ struct davinci_nand_info { struct mtd_info mtd; struct nand_chip chip; + struct nand_ecclayout ecclayout; struct device *dev; struct clk *clk; bool partitioned; + bool is_readmode; + void __iomem *base; void __iomem *vaddr; @@ -73,6 +76,7 @@ struct davinci_nand_info { }; static DEFINE_SPINLOCK(davinci_nand_lock); +static bool ecc4_busy; #define to_davinci_nand(m) container_of(m, struct davinci_nand_info, mtd) @@ -217,6 +221,192 @@ static int nand_davinci_correct_1bit(struct mtd_info *mtd, u_char *dat, /*----------------------------------------------------------------------*/ +/* + * 4-bit hardware ECC ... context maintained over entire AEMIF + * + * This is a syndrome engine, but we avoid NAND_ECC_HW_SYNDROME + * since that forces use of a problematic "infix OOB" layout. + * Among other things, it trashes manufacturer bad block markers. + * Also, and specific to this hardware, it ECC-protects the "prepad" + * in the OOB ... while having ECC protection for parts of OOB would + * seem useful, the current MTD stack sometimes wants to update the + * OOB without recomputing ECC. + */ + +static void nand_davinci_hwctl_4bit(struct mtd_info *mtd, int mode) +{ + struct davinci_nand_info *info = to_davinci_nand(mtd); + unsigned long flags; + u32 val; + + spin_lock_irqsave(&davinci_nand_lock, flags); + + /* Start 4-bit ECC calculation for read/write */ + val = davinci_nand_readl(info, NANDFCR_OFFSET); + val &= ~(0x03 << 4); + val |= (info->core_chipsel << 4) | BIT(12); + davinci_nand_writel(info, NANDFCR_OFFSET, val); + + info->is_readmode = (mode == NAND_ECC_READ); + + spin_unlock_irqrestore(&davinci_nand_lock, flags); +} + +/* Read raw ECC code after writing to NAND. */ +static void +nand_davinci_readecc_4bit(struct davinci_nand_info *info, u32 code[4]) +{ + const u32 mask = 0x03ff03ff; + + code[0] = davinci_nand_readl(info, NAND_4BIT_ECC1_OFFSET) & mask; + code[1] = davinci_nand_readl(info, NAND_4BIT_ECC2_OFFSET) & mask; + code[2] = davinci_nand_readl(info, NAND_4BIT_ECC3_OFFSET) & mask; + code[3] = davinci_nand_readl(info, NAND_4BIT_ECC4_OFFSET) & mask; +} + +/* Terminate read ECC; or return ECC (as bytes) of data written to NAND. */ +static int nand_davinci_calculate_4bit(struct mtd_info *mtd, + const u_char *dat, u_char *ecc_code) +{ + struct davinci_nand_info *info = to_davinci_nand(mtd); + u32 raw_ecc[4], *p; + unsigned i; + + /* After a read, terminate ECC calculation by a dummy read + * of some 4-bit ECC register. ECC covers everything that + * was read; correct() just uses the hardware state, so + * ecc_code is not needed. + */ + if (info->is_readmode) { + davinci_nand_readl(info, NAND_4BIT_ECC1_OFFSET); + return 0; + } + + /* Pack eight raw 10-bit ecc values into ten bytes, making + * two passes which each convert four values (in upper and + * lower halves of two 32-bit words) into five bytes. The + * ROM boot loader uses this same packing scheme. + */ + nand_davinci_readecc_4bit(info, raw_ecc); + for (i = 0, p = raw_ecc; i < 2; i++, p += 2) { + *ecc_code++ = p[0] & 0xff; + *ecc_code++ = ((p[0] >> 8) & 0x03) | ((p[0] >> 14) & 0xfc); + *ecc_code++ = ((p[0] >> 22) & 0x0f) | ((p[1] << 4) & 0xf0); + *ecc_code++ = ((p[1] >> 4) & 0x3f) | ((p[1] >> 10) & 0xc0); + *ecc_code++ = (p[1] >> 18) & 0xff; + } + + return 0; +} + +/* Correct up to 4 bits in data we just read, using state left in the + * hardware plus the ecc_code computed when it was first written. + */ +static int nand_davinci_correct_4bit(struct mtd_info *mtd, + u_char *data, u_char *ecc_code, u_char *null) +{ + int i; + struct davinci_nand_info *info = to_davinci_nand(mtd); + unsigned short ecc10[8]; + unsigned short *ecc16; + u32 syndrome[4]; + unsigned num_errors, corrected; + + /* All bytes 0xff? It's an erased page; ignore its ECC. */ + for (i = 0; i < 10; i++) { + if (ecc_code[i] != 0xff) + goto compare; + } + return 0; + +compare: + /* Unpack ten bytes into eight 10 bit values. We know we're + * little-endian, and use type punning for less shifting/masking. + */ + if (WARN_ON(0x01 & (unsigned) ecc_code)) + return -EINVAL; + ecc16 = (unsigned short *)ecc_code; + + ecc10[0] = (ecc16[0] >> 0) & 0x3ff; + ecc10[1] = ((ecc16[0] >> 10) & 0x3f) | ((ecc16[1] << 6) & 0x3c0); + ecc10[2] = (ecc16[1] >> 4) & 0x3ff; + ecc10[3] = ((ecc16[1] >> 14) & 0x3) | ((ecc16[2] << 2) & 0x3fc); + ecc10[4] = (ecc16[2] >> 8) | ((ecc16[3] << 8) & 0x300); + ecc10[5] = (ecc16[3] >> 2) & 0x3ff; + ecc10[6] = ((ecc16[3] >> 12) & 0xf) | ((ecc16[4] << 4) & 0x3f0); + ecc10[7] = (ecc16[4] >> 6) & 0x3ff; + + /* Tell ECC controller about the expected ECC codes. */ + for (i = 7; i >= 0; i--) + davinci_nand_writel(info, NAND_4BIT_ECC_LOAD_OFFSET, ecc10[i]); + + /* Allow time for syndrome calculation ... then read it. + * A syndrome of all zeroes 0 means no detected errors. + */ + davinci_nand_readl(info, NANDFSR_OFFSET); + nand_davinci_readecc_4bit(info, syndrome); + if (!(syndrome[0] | syndrome[1] | syndrome[2] | syndrome[3])) + return 0; + + /* Start address calculation, and wait for it to complete. + * We _could_ start reading more data while this is working, + * to speed up the overall page read. + */ + davinci_nand_writel(info, NANDFCR_OFFSET, + davinci_nand_readl(info, NANDFCR_OFFSET) | BIT(13)); + for (;;) { + u32 fsr = davinci_nand_readl(info, NANDFSR_OFFSET); + + switch ((fsr >> 8) & 0x0f) { + case 0: /* no error, should not happen */ + return 0; + case 1: /* five or more errors detected */ + return -EIO; + case 2: /* error addresses computed */ + case 3: + num_errors = 1 + ((fsr >> 16) & 0x03); + goto correct; + default: /* still working on it */ + cpu_relax(); + continue; + } + } + +correct: + /* correct each error */ + for (i = 0, corrected = 0; i < num_errors; i++) { + int error_address, error_value; + + if (i > 1) { + error_address = davinci_nand_readl(info, + NAND_ERR_ADD2_OFFSET); + error_value = davinci_nand_readl(info, + NAND_ERR_ERRVAL2_OFFSET); + } else { + error_address = davinci_nand_readl(info, + NAND_ERR_ADD1_OFFSET); + error_value = davinci_nand_readl(info, + NAND_ERR_ERRVAL1_OFFSET); + } + + if (i & 1) { + error_address >>= 16; + error_value >>= 16; + } + error_address &= 0x3ff; + error_address = (512 + 7) - error_address; + + if (error_address < 512) { + data[error_address] ^= error_value; + corrected++; + } + } + + return corrected; +} + +/*----------------------------------------------------------------------*/ + /* * NOTE: NAND boot requires ALE == EM_A[1], CLE == EM_A[2], so that's * how these chips are normally wired. This translates to both 8 and 16 @@ -294,6 +484,23 @@ static void __init nand_dm6446evm_flash_init(struct davinci_nand_info *info) /*----------------------------------------------------------------------*/ +/* An ECC layout for using 4-bit ECC with small-page flash, storing + * ten ECC bytes plus the manufacturer's bad block marker byte, and + * and not overlapping the default BBT markers. + */ +static struct nand_ecclayout hwecc4_small __initconst = { + .eccbytes = 10, + .eccpos = { 0, 1, 2, 3, 4, + /* offset 5 holds the badblock marker */ + 6, 7, + 13, 14, 15, }, + .oobfree = { + {.offset = 8, .length = 5, }, + {.offset = 16, }, + }, +}; + + static int __init nand_davinci_probe(struct platform_device *pdev) { struct davinci_nand_pdata *pdata = pdev->dev.platform_data; @@ -306,6 +513,10 @@ static int __init nand_davinci_probe(struct platform_device *pdev) uint32_t val; nand_ecc_modes_t ecc_mode; + /* insist on board-specific configuration */ + if (!pdata) + return -ENODEV; + /* which external chipselect will we be managing? */ if (pdev->id < 0 || pdev->id > 3) return -ENODEV; @@ -351,7 +562,7 @@ static int __init nand_davinci_probe(struct platform_device *pdev) info->chip.select_chip = nand_davinci_select_chip; /* options such as NAND_USE_FLASH_BBT or 16-bit widths */ - info->chip.options = pdata ? pdata->options : 0; + info->chip.options = pdata->options; info->ioaddr = (uint32_t __force) vaddr; @@ -360,14 +571,8 @@ static int __init nand_davinci_probe(struct platform_device *pdev) info->mask_chipsel = pdata->mask_chipsel; /* use nandboot-capable ALE/CLE masks by default */ - if (pdata && pdata->mask_ale) - info->mask_ale = pdata->mask_cle; - else - info->mask_ale = MASK_ALE; - if (pdata && pdata->mask_cle) - info->mask_cle = pdata->mask_cle; - else - info->mask_cle = MASK_CLE; + info->mask_ale = pdata->mask_cle ? : MASK_ALE; + info->mask_cle = pdata->mask_cle ? : MASK_CLE; /* Set address of hardware control function */ info->chip.cmd_ctrl = nand_davinci_hwcontrol; @@ -377,30 +582,44 @@ static int __init nand_davinci_probe(struct platform_device *pdev) info->chip.read_buf = nand_davinci_read_buf; info->chip.write_buf = nand_davinci_write_buf; - /* use board-specific ECC config; else, the best available */ - if (pdata) - ecc_mode = pdata->ecc_mode; - else - ecc_mode = NAND_ECC_HW; + /* Use board-specific ECC config */ + ecc_mode = pdata->ecc_mode; + ret = -EINVAL; switch (ecc_mode) { case NAND_ECC_NONE: case NAND_ECC_SOFT: + pdata->ecc_bits = 0; break; case NAND_ECC_HW: - info->chip.ecc.calculate = nand_davinci_calculate_1bit; - info->chip.ecc.correct = nand_davinci_correct_1bit; - info->chip.ecc.hwctl = nand_davinci_hwctl_1bit; - info->chip.ecc.size = 512; - info->chip.ecc.bytes = 3; - break; - case NAND_ECC_HW_SYNDROME: - /* FIXME implement */ - info->chip.ecc.size = 512; - info->chip.ecc.bytes = 10; + if (pdata->ecc_bits == 4) { + /* No sanity checks: CPUs must support this, + * and the chips may not use NAND_BUSWIDTH_16. + */ - dev_warn(&pdev->dev, "4-bit ECC nyet supported\n"); - /* FALL THROUGH */ + /* No sharing 4-bit hardware between chipselects yet */ + spin_lock_irq(&davinci_nand_lock); + if (ecc4_busy) + ret = -EBUSY; + else + ecc4_busy = true; + spin_unlock_irq(&davinci_nand_lock); + + if (ret == -EBUSY) + goto err_ecc; + + info->chip.ecc.calculate = nand_davinci_calculate_4bit; + info->chip.ecc.correct = nand_davinci_correct_4bit; + info->chip.ecc.hwctl = nand_davinci_hwctl_4bit; + info->chip.ecc.bytes = 10; + } else { + info->chip.ecc.calculate = nand_davinci_calculate_1bit; + info->chip.ecc.correct = nand_davinci_correct_1bit; + info->chip.ecc.hwctl = nand_davinci_hwctl_1bit; + info->chip.ecc.bytes = 3; + } + info->chip.ecc.size = 512; + break; default: ret = -EINVAL; goto err_ecc; @@ -441,12 +660,56 @@ static int __init nand_davinci_probe(struct platform_device *pdev) spin_unlock_irq(&davinci_nand_lock); /* Scan to find existence of the device(s) */ - ret = nand_scan(&info->mtd, pdata->mask_chipsel ? 2 : 1); + ret = nand_scan_ident(&info->mtd, pdata->mask_chipsel ? 2 : 1); if (ret < 0) { dev_dbg(&pdev->dev, "no NAND chip(s) found\n"); goto err_scan; } + /* Update ECC layout if needed ... for 1-bit HW ECC, the default + * is OK, but it allocates 6 bytes when only 3 are needed (for + * each 512 bytes). For the 4-bit HW ECC, that default is not + * usable: 10 bytes are needed, not 6. + */ + if (pdata->ecc_bits == 4) { + int chunks = info->mtd.writesize / 512; + + if (!chunks || info->mtd.oobsize < 16) { + dev_dbg(&pdev->dev, "too small\n"); + ret = -EINVAL; + goto err_scan; + } + + /* For small page chips, preserve the manufacturer's + * badblock marking data ... and make sure a flash BBT + * table marker fits in the free bytes. + */ + if (chunks == 1) { + info->ecclayout = hwecc4_small; + info->ecclayout.oobfree[1].length = + info->mtd.oobsize - 16; + goto syndrome_done; + } + + /* For large page chips we'll be wanting to use a + * not-yet-implemented mode that reads OOB data + * before reading the body of the page, to avoid + * the "infix OOB" model of NAND_ECC_HW_SYNDROME + * (and preserve manufacturer badblock markings). + */ + dev_warn(&pdev->dev, "no 4-bit ECC support yet " + "for large page NAND\n"); + ret = -EIO; + goto err_scan; + +syndrome_done: + info->chip.ecc.layout = &info->ecclayout; + } + + ret = nand_scan_tail(&info->mtd); + if (ret < 0) + goto err_scan; + if (mtd_has_partitions()) { struct mtd_partition *mtd_parts = NULL; int mtd_parts_nb = 0; @@ -455,22 +718,11 @@ static int __init nand_davinci_probe(struct platform_device *pdev) static const char *probes[] __initconst = { "cmdlinepart", NULL }; - const char *master_name; - - /* Set info->mtd.name = 0 temporarily */ - master_name = info->mtd.name; - info->mtd.name = (char *)0; - - /* info->mtd.name == 0, means: don't bother checking - */ mtd_parts_nb = parse_mtd_partitions(&info->mtd, probes, &mtd_parts, 0); - - /* Restore info->mtd.name */ - info->mtd.name = master_name; } - if (mtd_parts_nb <= 0 && pdata) { + if (mtd_parts_nb <= 0) { mtd_parts = pdata->parts; mtd_parts_nb = pdata->nr_parts; } @@ -483,7 +735,7 @@ static int __init nand_davinci_probe(struct platform_device *pdev) info->partitioned = true; } - } else if (pdata && pdata->nr_parts) { + } else if (pdata->nr_parts) { dev_warn(&pdev->dev, "ignoring %d default partitions on %s\n", pdata->nr_parts, info->mtd.name); } @@ -509,6 +761,11 @@ err_scan: err_clk_enable: clk_put(info->clk); + spin_lock_irq(&davinci_nand_lock); + if (ecc_mode == NAND_ECC_HW_SYNDROME) + ecc4_busy = false; + spin_unlock_irq(&davinci_nand_lock); + err_ecc: err_clk: err_ioremap: @@ -532,6 +789,11 @@ static int __exit nand_davinci_remove(struct platform_device *pdev) else status = del_mtd_device(&info->mtd); + spin_lock_irq(&davinci_nand_lock); + if (info->chip.ecc.mode == NAND_ECC_HW_SYNDROME) + ecc4_busy = false; + spin_unlock_irq(&davinci_nand_lock); + iounmap(info->base); iounmap(info->vaddr); diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 40c26080ecda..76beea40d2cf 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -138,7 +138,14 @@ static struct nand_ecclayout nand_hw_eccoob_8 = { static struct nand_ecclayout nand_hw_eccoob_16 = { .eccbytes = 5, .eccpos = {6, 7, 8, 9, 10}, - .oobfree = {{0, 6}, {12, 4}, } + .oobfree = {{0, 5}, {11, 5}, } +}; + +static struct nand_ecclayout nand_hw_eccoob_64 = { + .eccbytes = 20, + .eccpos = {6, 7, 8, 9, 10, 22, 23, 24, 25, 26, + 38, 39, 40, 41, 42, 54, 55, 56, 57, 58}, + .oobfree = {{2, 4}, {11, 10}, {27, 10}, {43, 10}, {59, 5}, } }; #ifdef CONFIG_MTD_PARTITIONS @@ -192,7 +199,7 @@ static void wait_op_done(struct mxc_nand_host *host, int max_retries, } udelay(1); } - if (max_retries <= 0) + if (max_retries < 0) DEBUG(MTD_DEBUG_LEVEL0, "%s(%d): INT not set\n", __func__, param); } @@ -795,9 +802,13 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, send_addr(host, (page_addr & 0xff), false); if (host->pagesize_2k) { - send_addr(host, (page_addr >> 8) & 0xFF, false); - if (mtd->size >= 0x40000000) + if (mtd->size >= 0x10000000) { + /* paddr_8 - paddr_15 */ + send_addr(host, (page_addr >> 8) & 0xff, false); send_addr(host, (page_addr >> 16) & 0xff, true); + } else + /* paddr_8 - paddr_15 */ + send_addr(host, (page_addr >> 8) & 0xff, true); } else { /* One more address cycle for higher density devices */ if (mtd->size >= 0x4000000) { @@ -923,7 +934,6 @@ static int __init mxcnd_probe(struct platform_device *pdev) this->ecc.mode = NAND_ECC_HW; this->ecc.size = 512; this->ecc.bytes = 3; - this->ecc.layout = &nand_hw_eccoob_8; tmp = readw(host->regs + NFC_CONFIG1); tmp |= NFC_ECC_EN; writew(tmp, host->regs + NFC_CONFIG1); @@ -957,12 +967,44 @@ static int __init mxcnd_probe(struct platform_device *pdev) this->ecc.layout = &nand_hw_eccoob_16; } - host->pagesize_2k = 0; + /* first scan to find the device and get the page size */ + if (nand_scan_ident(mtd, 1)) { + err = -ENXIO; + goto escan; + } - /* Scan to find existence of the device */ - if (nand_scan(mtd, 1)) { - DEBUG(MTD_DEBUG_LEVEL0, - "MXC_ND: Unable to find any NAND device.\n"); + host->pagesize_2k = (mtd->writesize == 2048) ? 1 : 0; + + if (this->ecc.mode == NAND_ECC_HW) { + switch (mtd->oobsize) { + case 8: + this->ecc.layout = &nand_hw_eccoob_8; + break; + case 16: + this->ecc.layout = &nand_hw_eccoob_16; + break; + case 64: + this->ecc.layout = &nand_hw_eccoob_64; + break; + default: + /* page size not handled by HW ECC */ + /* switching back to soft ECC */ + this->ecc.size = 512; + this->ecc.bytes = 3; + this->ecc.layout = &nand_hw_eccoob_8; + this->ecc.mode = NAND_ECC_SOFT; + this->ecc.calculate = NULL; + this->ecc.correct = NULL; + this->ecc.hwctl = NULL; + tmp = readw(host->regs + NFC_CONFIG1); + tmp &= ~NFC_ECC_EN; + writew(tmp, host->regs + NFC_CONFIG1); + break; + } + } + + /* second phase scan */ + if (nand_scan_tail(mtd)) { err = -ENXIO; goto escan; } @@ -985,7 +1027,7 @@ static int __init mxcnd_probe(struct platform_device *pdev) return 0; escan: - free_irq(host->irq, NULL); + free_irq(host->irq, host); eirq: iounmap(host->regs); eres: @@ -1005,7 +1047,7 @@ static int __devexit mxcnd_remove(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); nand_release(&host->mtd); - free_irq(host->irq, NULL); + free_irq(host->irq, host); iounmap(host->regs); kfree(host); diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 3d7ed432fa41..8c21b89d2d0c 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2756,7 +2756,8 @@ int nand_scan_tail(struct mtd_info *mtd) * the out of band area */ chip->ecc.layout->oobavail = 0; - for (i = 0; chip->ecc.layout->oobfree[i].length; i++) + for (i = 0; chip->ecc.layout->oobfree[i].length + && i < ARRAY_SIZE(chip->ecc.layout->oobfree); i++) chip->ecc.layout->oobavail += chip->ecc.layout->oobfree[i].length; mtd->oobavail = chip->ecc.layout->oobavail; diff --git a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c index 868147acce2c..c0cb87d6d16e 100644 --- a/drivers/mtd/nand/nand_ecc.c +++ b/drivers/mtd/nand/nand_ecc.c @@ -428,8 +428,8 @@ EXPORT_SYMBOL(nand_calculate_ecc); int nand_correct_data(struct mtd_info *mtd, unsigned char *buf, unsigned char *read_ecc, unsigned char *calc_ecc) { - unsigned char b0, b1, b2; - unsigned char byte_addr, bit_addr; + unsigned char b0, b1, b2, bit_addr; + unsigned int byte_addr; /* 256 or 512 bytes/ecc */ const uint32_t eccsize_mult = (((struct nand_chip *)mtd->priv)->ecc.size) >> 8; diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c new file mode 100644 index 000000000000..0cd76f89f4b0 --- /dev/null +++ b/drivers/mtd/nand/omap2.c @@ -0,0 +1,776 @@ +/* + * Copyright © 2004 Texas Instruments, Jian Zhang + * Copyright © 2004 Micron Technology Inc. + * Copyright © 2004 David Brownell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#define GPMC_IRQ_STATUS 0x18 +#define GPMC_ECC_CONFIG 0x1F4 +#define GPMC_ECC_CONTROL 0x1F8 +#define GPMC_ECC_SIZE_CONFIG 0x1FC +#define GPMC_ECC1_RESULT 0x200 + +#define DRIVER_NAME "omap2-nand" + +/* size (4 KiB) for IO mapping */ +#define NAND_IO_SIZE SZ_4K + +#define NAND_WP_OFF 0 +#define NAND_WP_BIT 0x00000010 +#define WR_RD_PIN_MONITORING 0x00600000 + +#define GPMC_BUF_FULL 0x00000001 +#define GPMC_BUF_EMPTY 0x00000000 + +#define NAND_Ecc_P1e (1 << 0) +#define NAND_Ecc_P2e (1 << 1) +#define NAND_Ecc_P4e (1 << 2) +#define NAND_Ecc_P8e (1 << 3) +#define NAND_Ecc_P16e (1 << 4) +#define NAND_Ecc_P32e (1 << 5) +#define NAND_Ecc_P64e (1 << 6) +#define NAND_Ecc_P128e (1 << 7) +#define NAND_Ecc_P256e (1 << 8) +#define NAND_Ecc_P512e (1 << 9) +#define NAND_Ecc_P1024e (1 << 10) +#define NAND_Ecc_P2048e (1 << 11) + +#define NAND_Ecc_P1o (1 << 16) +#define NAND_Ecc_P2o (1 << 17) +#define NAND_Ecc_P4o (1 << 18) +#define NAND_Ecc_P8o (1 << 19) +#define NAND_Ecc_P16o (1 << 20) +#define NAND_Ecc_P32o (1 << 21) +#define NAND_Ecc_P64o (1 << 22) +#define NAND_Ecc_P128o (1 << 23) +#define NAND_Ecc_P256o (1 << 24) +#define NAND_Ecc_P512o (1 << 25) +#define NAND_Ecc_P1024o (1 << 26) +#define NAND_Ecc_P2048o (1 << 27) + +#define TF(value) (value ? 1 : 0) + +#define P2048e(a) (TF(a & NAND_Ecc_P2048e) << 0) +#define P2048o(a) (TF(a & NAND_Ecc_P2048o) << 1) +#define P1e(a) (TF(a & NAND_Ecc_P1e) << 2) +#define P1o(a) (TF(a & NAND_Ecc_P1o) << 3) +#define P2e(a) (TF(a & NAND_Ecc_P2e) << 4) +#define P2o(a) (TF(a & NAND_Ecc_P2o) << 5) +#define P4e(a) (TF(a & NAND_Ecc_P4e) << 6) +#define P4o(a) (TF(a & NAND_Ecc_P4o) << 7) + +#define P8e(a) (TF(a & NAND_Ecc_P8e) << 0) +#define P8o(a) (TF(a & NAND_Ecc_P8o) << 1) +#define P16e(a) (TF(a & NAND_Ecc_P16e) << 2) +#define P16o(a) (TF(a & NAND_Ecc_P16o) << 3) +#define P32e(a) (TF(a & NAND_Ecc_P32e) << 4) +#define P32o(a) (TF(a & NAND_Ecc_P32o) << 5) +#define P64e(a) (TF(a & NAND_Ecc_P64e) << 6) +#define P64o(a) (TF(a & NAND_Ecc_P64o) << 7) + +#define P128e(a) (TF(a & NAND_Ecc_P128e) << 0) +#define P128o(a) (TF(a & NAND_Ecc_P128o) << 1) +#define P256e(a) (TF(a & NAND_Ecc_P256e) << 2) +#define P256o(a) (TF(a & NAND_Ecc_P256o) << 3) +#define P512e(a) (TF(a & NAND_Ecc_P512e) << 4) +#define P512o(a) (TF(a & NAND_Ecc_P512o) << 5) +#define P1024e(a) (TF(a & NAND_Ecc_P1024e) << 6) +#define P1024o(a) (TF(a & NAND_Ecc_P1024o) << 7) + +#define P8e_s(a) (TF(a & NAND_Ecc_P8e) << 0) +#define P8o_s(a) (TF(a & NAND_Ecc_P8o) << 1) +#define P16e_s(a) (TF(a & NAND_Ecc_P16e) << 2) +#define P16o_s(a) (TF(a & NAND_Ecc_P16o) << 3) +#define P1e_s(a) (TF(a & NAND_Ecc_P1e) << 4) +#define P1o_s(a) (TF(a & NAND_Ecc_P1o) << 5) +#define P2e_s(a) (TF(a & NAND_Ecc_P2e) << 6) +#define P2o_s(a) (TF(a & NAND_Ecc_P2o) << 7) + +#define P4e_s(a) (TF(a & NAND_Ecc_P4e) << 0) +#define P4o_s(a) (TF(a & NAND_Ecc_P4o) << 1) + +#ifdef CONFIG_MTD_PARTITIONS +static const char *part_probes[] = { "cmdlinepart", NULL }; +#endif + +struct omap_nand_info { + struct nand_hw_control controller; + struct omap_nand_platform_data *pdata; + struct mtd_info mtd; + struct mtd_partition *parts; + struct nand_chip nand; + struct platform_device *pdev; + + int gpmc_cs; + unsigned long phys_base; + void __iomem *gpmc_cs_baseaddr; + void __iomem *gpmc_baseaddr; +}; + +/** + * omap_nand_wp - This function enable or disable the Write Protect feature + * @mtd: MTD device structure + * @mode: WP ON/OFF + */ +static void omap_nand_wp(struct mtd_info *mtd, int mode) +{ + struct omap_nand_info *info = container_of(mtd, + struct omap_nand_info, mtd); + + unsigned long config = __raw_readl(info->gpmc_baseaddr + GPMC_CONFIG); + + if (mode) + config &= ~(NAND_WP_BIT); /* WP is ON */ + else + config |= (NAND_WP_BIT); /* WP is OFF */ + + __raw_writel(config, (info->gpmc_baseaddr + GPMC_CONFIG)); +} + +/** + * omap_hwcontrol - hardware specific access to control-lines + * @mtd: MTD device structure + * @cmd: command to device + * @ctrl: + * NAND_NCE: bit 0 -> don't care + * NAND_CLE: bit 1 -> Command Latch + * NAND_ALE: bit 2 -> Address Latch + * + * NOTE: boards may use different bits for these!! + */ +static void omap_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) +{ + struct omap_nand_info *info = container_of(mtd, + struct omap_nand_info, mtd); + switch (ctrl) { + case NAND_CTRL_CHANGE | NAND_CTRL_CLE: + info->nand.IO_ADDR_W = info->gpmc_cs_baseaddr + + GPMC_CS_NAND_COMMAND; + info->nand.IO_ADDR_R = info->gpmc_cs_baseaddr + + GPMC_CS_NAND_DATA; + break; + + case NAND_CTRL_CHANGE | NAND_CTRL_ALE: + info->nand.IO_ADDR_W = info->gpmc_cs_baseaddr + + GPMC_CS_NAND_ADDRESS; + info->nand.IO_ADDR_R = info->gpmc_cs_baseaddr + + GPMC_CS_NAND_DATA; + break; + + case NAND_CTRL_CHANGE | NAND_NCE: + info->nand.IO_ADDR_W = info->gpmc_cs_baseaddr + + GPMC_CS_NAND_DATA; + info->nand.IO_ADDR_R = info->gpmc_cs_baseaddr + + GPMC_CS_NAND_DATA; + break; + } + + if (cmd != NAND_CMD_NONE) + __raw_writeb(cmd, info->nand.IO_ADDR_W); +} + +/** + * omap_read_buf16 - read data from NAND controller into buffer + * @mtd: MTD device structure + * @buf: buffer to store date + * @len: number of bytes to read + */ +static void omap_read_buf16(struct mtd_info *mtd, u_char *buf, int len) +{ + struct nand_chip *nand = mtd->priv; + + __raw_readsw(nand->IO_ADDR_R, buf, len / 2); +} + +/** + * omap_write_buf16 - write buffer to NAND controller + * @mtd: MTD device structure + * @buf: data buffer + * @len: number of bytes to write + */ +static void omap_write_buf16(struct mtd_info *mtd, const u_char * buf, int len) +{ + struct omap_nand_info *info = container_of(mtd, + struct omap_nand_info, mtd); + u16 *p = (u16 *) buf; + + /* FIXME try bursts of writesw() or DMA ... */ + len >>= 1; + + while (len--) { + writew(*p++, info->nand.IO_ADDR_W); + + while (GPMC_BUF_EMPTY == (readl(info->gpmc_baseaddr + + GPMC_STATUS) & GPMC_BUF_FULL)) + ; + } +} +/** + * omap_verify_buf - Verify chip data against buffer + * @mtd: MTD device structure + * @buf: buffer containing the data to compare + * @len: number of bytes to compare + */ +static int omap_verify_buf(struct mtd_info *mtd, const u_char * buf, int len) +{ + struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, + mtd); + u16 *p = (u16 *) buf; + + len >>= 1; + while (len--) { + if (*p++ != cpu_to_le16(readw(info->nand.IO_ADDR_R))) + return -EFAULT; + } + + return 0; +} + +#ifdef CONFIG_MTD_NAND_OMAP_HWECC +/** + * omap_hwecc_init - Initialize the HW ECC for NAND flash in GPMC controller + * @mtd: MTD device structure + */ +static void omap_hwecc_init(struct mtd_info *mtd) +{ + struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, + mtd); + struct nand_chip *chip = mtd->priv; + unsigned long val = 0x0; + + /* Read from ECC Control Register */ + val = __raw_readl(info->gpmc_baseaddr + GPMC_ECC_CONTROL); + /* Clear all ECC | Enable Reg1 */ + val = ((0x00000001<<8) | 0x00000001); + __raw_writel(val, info->gpmc_baseaddr + GPMC_ECC_CONTROL); + + /* Read from ECC Size Config Register */ + val = __raw_readl(info->gpmc_baseaddr + GPMC_ECC_SIZE_CONFIG); + /* ECCSIZE1=512 | Select eccResultsize[0-3] */ + val = ((((chip->ecc.size >> 1) - 1) << 22) | (0x0000000F)); + __raw_writel(val, info->gpmc_baseaddr + GPMC_ECC_SIZE_CONFIG); +} + +/** + * gen_true_ecc - This function will generate true ECC value + * @ecc_buf: buffer to store ecc code + * + * This generated true ECC value can be used when correcting + * data read from NAND flash memory core + */ +static void gen_true_ecc(u8 *ecc_buf) +{ + u32 tmp = ecc_buf[0] | (ecc_buf[1] << 16) | + ((ecc_buf[2] & 0xF0) << 20) | ((ecc_buf[2] & 0x0F) << 8); + + ecc_buf[0] = ~(P64o(tmp) | P64e(tmp) | P32o(tmp) | P32e(tmp) | + P16o(tmp) | P16e(tmp) | P8o(tmp) | P8e(tmp)); + ecc_buf[1] = ~(P1024o(tmp) | P1024e(tmp) | P512o(tmp) | P512e(tmp) | + P256o(tmp) | P256e(tmp) | P128o(tmp) | P128e(tmp)); + ecc_buf[2] = ~(P4o(tmp) | P4e(tmp) | P2o(tmp) | P2e(tmp) | P1o(tmp) | + P1e(tmp) | P2048o(tmp) | P2048e(tmp)); +} + +/** + * omap_compare_ecc - Detect (2 bits) and correct (1 bit) error in data + * @ecc_data1: ecc code from nand spare area + * @ecc_data2: ecc code from hardware register obtained from hardware ecc + * @page_data: page data + * + * This function compares two ECC's and indicates if there is an error. + * If the error can be corrected it will be corrected to the buffer. + */ +static int omap_compare_ecc(u8 *ecc_data1, /* read from NAND memory */ + u8 *ecc_data2, /* read from register */ + u8 *page_data) +{ + uint i; + u8 tmp0_bit[8], tmp1_bit[8], tmp2_bit[8]; + u8 comp0_bit[8], comp1_bit[8], comp2_bit[8]; + u8 ecc_bit[24]; + u8 ecc_sum = 0; + u8 find_bit = 0; + uint find_byte = 0; + int isEccFF; + + isEccFF = ((*(u32 *)ecc_data1 & 0xFFFFFF) == 0xFFFFFF); + + gen_true_ecc(ecc_data1); + gen_true_ecc(ecc_data2); + + for (i = 0; i <= 2; i++) { + *(ecc_data1 + i) = ~(*(ecc_data1 + i)); + *(ecc_data2 + i) = ~(*(ecc_data2 + i)); + } + + for (i = 0; i < 8; i++) { + tmp0_bit[i] = *ecc_data1 % 2; + *ecc_data1 = *ecc_data1 / 2; + } + + for (i = 0; i < 8; i++) { + tmp1_bit[i] = *(ecc_data1 + 1) % 2; + *(ecc_data1 + 1) = *(ecc_data1 + 1) / 2; + } + + for (i = 0; i < 8; i++) { + tmp2_bit[i] = *(ecc_data1 + 2) % 2; + *(ecc_data1 + 2) = *(ecc_data1 + 2) / 2; + } + + for (i = 0; i < 8; i++) { + comp0_bit[i] = *ecc_data2 % 2; + *ecc_data2 = *ecc_data2 / 2; + } + + for (i = 0; i < 8; i++) { + comp1_bit[i] = *(ecc_data2 + 1) % 2; + *(ecc_data2 + 1) = *(ecc_data2 + 1) / 2; + } + + for (i = 0; i < 8; i++) { + comp2_bit[i] = *(ecc_data2 + 2) % 2; + *(ecc_data2 + 2) = *(ecc_data2 + 2) / 2; + } + + for (i = 0; i < 6; i++) + ecc_bit[i] = tmp2_bit[i + 2] ^ comp2_bit[i + 2]; + + for (i = 0; i < 8; i++) + ecc_bit[i + 6] = tmp0_bit[i] ^ comp0_bit[i]; + + for (i = 0; i < 8; i++) + ecc_bit[i + 14] = tmp1_bit[i] ^ comp1_bit[i]; + + ecc_bit[22] = tmp2_bit[0] ^ comp2_bit[0]; + ecc_bit[23] = tmp2_bit[1] ^ comp2_bit[1]; + + for (i = 0; i < 24; i++) + ecc_sum += ecc_bit[i]; + + switch (ecc_sum) { + case 0: + /* Not reached because this function is not called if + * ECC values are equal + */ + return 0; + + case 1: + /* Uncorrectable error */ + DEBUG(MTD_DEBUG_LEVEL0, "ECC UNCORRECTED_ERROR 1\n"); + return -1; + + case 11: + /* UN-Correctable error */ + DEBUG(MTD_DEBUG_LEVEL0, "ECC UNCORRECTED_ERROR B\n"); + return -1; + + case 12: + /* Correctable error */ + find_byte = (ecc_bit[23] << 8) + + (ecc_bit[21] << 7) + + (ecc_bit[19] << 6) + + (ecc_bit[17] << 5) + + (ecc_bit[15] << 4) + + (ecc_bit[13] << 3) + + (ecc_bit[11] << 2) + + (ecc_bit[9] << 1) + + ecc_bit[7]; + + find_bit = (ecc_bit[5] << 2) + (ecc_bit[3] << 1) + ecc_bit[1]; + + DEBUG(MTD_DEBUG_LEVEL0, "Correcting single bit ECC error at " + "offset: %d, bit: %d\n", find_byte, find_bit); + + page_data[find_byte] ^= (1 << find_bit); + + return 0; + default: + if (isEccFF) { + if (ecc_data2[0] == 0 && + ecc_data2[1] == 0 && + ecc_data2[2] == 0) + return 0; + } + DEBUG(MTD_DEBUG_LEVEL0, "UNCORRECTED_ERROR default\n"); + return -1; + } +} + +/** + * omap_correct_data - Compares the ECC read with HW generated ECC + * @mtd: MTD device structure + * @dat: page data + * @read_ecc: ecc read from nand flash + * @calc_ecc: ecc read from HW ECC registers + * + * Compares the ecc read from nand spare area with ECC registers values + * and if ECC's mismached, it will call 'omap_compare_ecc' for error detection + * and correction. + */ +static int omap_correct_data(struct mtd_info *mtd, u_char *dat, + u_char *read_ecc, u_char *calc_ecc) +{ + struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, + mtd); + int blockCnt = 0, i = 0, ret = 0; + + /* Ex NAND_ECC_HW12_2048 */ + if ((info->nand.ecc.mode == NAND_ECC_HW) && + (info->nand.ecc.size == 2048)) + blockCnt = 4; + else + blockCnt = 1; + + for (i = 0; i < blockCnt; i++) { + if (memcmp(read_ecc, calc_ecc, 3) != 0) { + ret = omap_compare_ecc(read_ecc, calc_ecc, dat); + if (ret < 0) + return ret; + } + read_ecc += 3; + calc_ecc += 3; + dat += 512; + } + return 0; +} + +/** + * omap_calcuate_ecc - Generate non-inverted ECC bytes. + * @mtd: MTD device structure + * @dat: The pointer to data on which ecc is computed + * @ecc_code: The ecc_code buffer + * + * Using noninverted ECC can be considered ugly since writing a blank + * page ie. padding will clear the ECC bytes. This is no problem as long + * nobody is trying to write data on the seemingly unused page. Reading + * an erased page will produce an ECC mismatch between generated and read + * ECC bytes that has to be dealt with separately. + */ +static int omap_calculate_ecc(struct mtd_info *mtd, const u_char *dat, + u_char *ecc_code) +{ + struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, + mtd); + unsigned long val = 0x0; + unsigned long reg; + + /* Start Reading from HW ECC1_Result = 0x200 */ + reg = (unsigned long)(info->gpmc_baseaddr + GPMC_ECC1_RESULT); + val = __raw_readl(reg); + *ecc_code++ = val; /* P128e, ..., P1e */ + *ecc_code++ = val >> 16; /* P128o, ..., P1o */ + /* P2048o, P1024o, P512o, P256o, P2048e, P1024e, P512e, P256e */ + *ecc_code++ = ((val >> 8) & 0x0f) | ((val >> 20) & 0xf0); + reg += 4; + + return 0; +} + +/** + * omap_enable_hwecc - This function enables the hardware ecc functionality + * @mtd: MTD device structure + * @mode: Read/Write mode + */ +static void omap_enable_hwecc(struct mtd_info *mtd, int mode) +{ + struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, + mtd); + struct nand_chip *chip = mtd->priv; + unsigned int dev_width = (chip->options & NAND_BUSWIDTH_16) ? 1 : 0; + unsigned long val = __raw_readl(info->gpmc_baseaddr + GPMC_ECC_CONFIG); + + switch (mode) { + case NAND_ECC_READ: + __raw_writel(0x101, info->gpmc_baseaddr + GPMC_ECC_CONTROL); + /* (ECC 16 or 8 bit col) | ( CS ) | ECC Enable */ + val = (dev_width << 7) | (info->gpmc_cs << 1) | (0x1); + break; + case NAND_ECC_READSYN: + __raw_writel(0x100, info->gpmc_baseaddr + GPMC_ECC_CONTROL); + /* (ECC 16 or 8 bit col) | ( CS ) | ECC Enable */ + val = (dev_width << 7) | (info->gpmc_cs << 1) | (0x1); + break; + case NAND_ECC_WRITE: + __raw_writel(0x101, info->gpmc_baseaddr + GPMC_ECC_CONTROL); + /* (ECC 16 or 8 bit col) | ( CS ) | ECC Enable */ + val = (dev_width << 7) | (info->gpmc_cs << 1) | (0x1); + break; + default: + DEBUG(MTD_DEBUG_LEVEL0, "Error: Unrecognized Mode[%d]!\n", + mode); + break; + } + + __raw_writel(val, info->gpmc_baseaddr + GPMC_ECC_CONFIG); +} +#endif + +/** + * omap_wait - wait until the command is done + * @mtd: MTD device structure + * @chip: NAND Chip structure + * + * Wait function is called during Program and erase operations and + * the way it is called from MTD layer, we should wait till the NAND + * chip is ready after the programming/erase operation has completed. + * + * Erase can take up to 400ms and program up to 20ms according to + * general NAND and SmartMedia specs + */ +static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip) +{ + struct nand_chip *this = mtd->priv; + struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, + mtd); + unsigned long timeo = jiffies; + int status, state = this->state; + + if (state == FL_ERASING) + timeo += (HZ * 400) / 1000; + else + timeo += (HZ * 20) / 1000; + + this->IO_ADDR_W = (void *) info->gpmc_cs_baseaddr + + GPMC_CS_NAND_COMMAND; + this->IO_ADDR_R = (void *) info->gpmc_cs_baseaddr + GPMC_CS_NAND_DATA; + + __raw_writeb(NAND_CMD_STATUS & 0xFF, this->IO_ADDR_W); + + while (time_before(jiffies, timeo)) { + status = __raw_readb(this->IO_ADDR_R); + if (!(status & 0x40)) + break; + } + return status; +} + +/** + * omap_dev_ready - calls the platform specific dev_ready function + * @mtd: MTD device structure + */ +static int omap_dev_ready(struct mtd_info *mtd) +{ + struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, + mtd); + unsigned int val = __raw_readl(info->gpmc_baseaddr + GPMC_IRQ_STATUS); + + if ((val & 0x100) == 0x100) { + /* Clear IRQ Interrupt */ + val |= 0x100; + val &= ~(0x0); + __raw_writel(val, info->gpmc_baseaddr + GPMC_IRQ_STATUS); + } else { + unsigned int cnt = 0; + while (cnt++ < 0x1FF) { + if ((val & 0x100) == 0x100) + return 0; + val = __raw_readl(info->gpmc_baseaddr + + GPMC_IRQ_STATUS); + } + } + + return 1; +} + +static int __devinit omap_nand_probe(struct platform_device *pdev) +{ + struct omap_nand_info *info; + struct omap_nand_platform_data *pdata; + int err; + unsigned long val; + + + pdata = pdev->dev.platform_data; + if (pdata == NULL) { + dev_err(&pdev->dev, "platform data missing\n"); + return -ENODEV; + } + + info = kzalloc(sizeof(struct omap_nand_info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + platform_set_drvdata(pdev, info); + + spin_lock_init(&info->controller.lock); + init_waitqueue_head(&info->controller.wq); + + info->pdev = pdev; + + info->gpmc_cs = pdata->cs; + info->gpmc_baseaddr = pdata->gpmc_baseaddr; + info->gpmc_cs_baseaddr = pdata->gpmc_cs_baseaddr; + + info->mtd.priv = &info->nand; + info->mtd.name = dev_name(&pdev->dev); + info->mtd.owner = THIS_MODULE; + + err = gpmc_cs_request(info->gpmc_cs, NAND_IO_SIZE, &info->phys_base); + if (err < 0) { + dev_err(&pdev->dev, "Cannot request GPMC CS\n"); + goto out_free_info; + } + + /* Enable RD PIN Monitoring Reg */ + if (pdata->dev_ready) { + val = gpmc_cs_read_reg(info->gpmc_cs, GPMC_CS_CONFIG1); + val |= WR_RD_PIN_MONITORING; + gpmc_cs_write_reg(info->gpmc_cs, GPMC_CS_CONFIG1, val); + } + + val = gpmc_cs_read_reg(info->gpmc_cs, GPMC_CS_CONFIG7); + val &= ~(0xf << 8); + val |= (0xc & 0xf) << 8; + gpmc_cs_write_reg(info->gpmc_cs, GPMC_CS_CONFIG7, val); + + /* NAND write protect off */ + omap_nand_wp(&info->mtd, NAND_WP_OFF); + + if (!request_mem_region(info->phys_base, NAND_IO_SIZE, + pdev->dev.driver->name)) { + err = -EBUSY; + goto out_free_cs; + } + + info->nand.IO_ADDR_R = ioremap(info->phys_base, NAND_IO_SIZE); + if (!info->nand.IO_ADDR_R) { + err = -ENOMEM; + goto out_release_mem_region; + } + info->nand.controller = &info->controller; + + info->nand.IO_ADDR_W = info->nand.IO_ADDR_R; + info->nand.cmd_ctrl = omap_hwcontrol; + + /* REVISIT: only supports 16-bit NAND flash */ + + info->nand.read_buf = omap_read_buf16; + info->nand.write_buf = omap_write_buf16; + info->nand.verify_buf = omap_verify_buf; + + /* + * If RDY/BSY line is connected to OMAP then use the omap ready + * funcrtion and the generic nand_wait function which reads the status + * register after monitoring the RDY/BSY line.Otherwise use a standard + * chip delay which is slightly more than tR (AC Timing) of the NAND + * device and read status register until you get a failure or success + */ + if (pdata->dev_ready) { + info->nand.dev_ready = omap_dev_ready; + info->nand.chip_delay = 0; + } else { + info->nand.waitfunc = omap_wait; + info->nand.chip_delay = 50; + } + + info->nand.options |= NAND_SKIP_BBTSCAN; + if ((gpmc_cs_read_reg(info->gpmc_cs, GPMC_CS_CONFIG1) & 0x3000) + == 0x1000) + info->nand.options |= NAND_BUSWIDTH_16; + +#ifdef CONFIG_MTD_NAND_OMAP_HWECC + info->nand.ecc.bytes = 3; + info->nand.ecc.size = 512; + info->nand.ecc.calculate = omap_calculate_ecc; + info->nand.ecc.hwctl = omap_enable_hwecc; + info->nand.ecc.correct = omap_correct_data; + info->nand.ecc.mode = NAND_ECC_HW; + + /* init HW ECC */ + omap_hwecc_init(&info->mtd); +#else + info->nand.ecc.mode = NAND_ECC_SOFT; +#endif + + /* DIP switches on some boards change between 8 and 16 bit + * bus widths for flash. Try the other width if the first try fails. + */ + if (nand_scan(&info->mtd, 1)) { + info->nand.options ^= NAND_BUSWIDTH_16; + if (nand_scan(&info->mtd, 1)) { + err = -ENXIO; + goto out_release_mem_region; + } + } + +#ifdef CONFIG_MTD_PARTITIONS + err = parse_mtd_partitions(&info->mtd, part_probes, &info->parts, 0); + if (err > 0) + add_mtd_partitions(&info->mtd, info->parts, err); + else if (pdata->parts) + add_mtd_partitions(&info->mtd, pdata->parts, pdata->nr_parts); + else +#endif + add_mtd_device(&info->mtd); + + platform_set_drvdata(pdev, &info->mtd); + + return 0; + +out_release_mem_region: + release_mem_region(info->phys_base, NAND_IO_SIZE); +out_free_cs: + gpmc_cs_free(info->gpmc_cs); +out_free_info: + kfree(info); + + return err; +} + +static int omap_nand_remove(struct platform_device *pdev) +{ + struct mtd_info *mtd = platform_get_drvdata(pdev); + struct omap_nand_info *info = mtd->priv; + + platform_set_drvdata(pdev, NULL); + /* Release NAND device, its internal structures and partitions */ + nand_release(&info->mtd); + iounmap(info->nand.IO_ADDR_R); + kfree(&info->mtd); + return 0; +} + +static struct platform_driver omap_nand_driver = { + .probe = omap_nand_probe, + .remove = omap_nand_remove, + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init omap_nand_init(void) +{ + printk(KERN_INFO "%s driver initializing\n", DRIVER_NAME); + return platform_driver_register(&omap_nand_driver); +} + +static void __exit omap_nand_exit(void) +{ + platform_driver_unregister(&omap_nand_driver); +} + +module_init(omap_nand_init); +module_exit(omap_nand_exit); + +MODULE_ALIAS(DRIVER_NAME); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Glue layer for NAND flash on TI OMAP boards"); diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/orion_nand.c index c2dfd3ea353d..7ad972229db4 100644 --- a/drivers/mtd/nand/orion_nand.c +++ b/drivers/mtd/nand/orion_nand.c @@ -47,6 +47,28 @@ static void orion_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl writeb(cmd, nc->IO_ADDR_W + offs); } +static void orion_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +{ + struct nand_chip *chip = mtd->priv; + void __iomem *io_base = chip->IO_ADDR_R; + uint64_t *buf64; + int i = 0; + + while (len && (unsigned long)buf & 7) { + *buf++ = readb(io_base); + len--; + } + buf64 = (uint64_t *)buf; + while (i < len/8) { + uint64_t x; + asm ("ldrd\t%0, [%1]" : "=r" (x) : "r" (io_base)); + buf64[i++] = x; + } + i *= 8; + while (i < len) + buf[i++] = readb(io_base); +} + static int __init orion_nand_probe(struct platform_device *pdev) { struct mtd_info *mtd; @@ -83,6 +105,7 @@ static int __init orion_nand_probe(struct platform_device *pdev) nc->priv = board; nc->IO_ADDR_R = nc->IO_ADDR_W = io_base; nc->cmd_ctrl = orion_nand_cmd_ctrl; + nc->read_buf = orion_nand_read_buf; nc->ecc.mode = NAND_ECC_SOFT; if (board->chip_delay) diff --git a/drivers/mtd/nand/plat_nand.c b/drivers/mtd/nand/plat_nand.c index 86e1d08eee00..4e16c6f5bdd5 100644 --- a/drivers/mtd/nand/plat_nand.c +++ b/drivers/mtd/nand/plat_nand.c @@ -61,6 +61,8 @@ static int __devinit plat_nand_probe(struct platform_device *pdev) data->chip.cmd_ctrl = pdata->ctrl.cmd_ctrl; data->chip.dev_ready = pdata->ctrl.dev_ready; data->chip.select_chip = pdata->ctrl.select_chip; + data->chip.write_buf = pdata->ctrl.write_buf; + data->chip.read_buf = pdata->ctrl.read_buf; data->chip.chip_delay = pdata->chip.chip_delay; data->chip.options |= pdata->chip.options; @@ -70,6 +72,13 @@ static int __devinit plat_nand_probe(struct platform_device *pdev) platform_set_drvdata(pdev, data); + /* Handle any platform specific setup */ + if (pdata->ctrl.probe) { + res = pdata->ctrl.probe(pdev); + if (res) + goto out; + } + /* Scan to find existance of the device */ if (nand_scan(&data->mtd, 1)) { res = -ENXIO; @@ -86,6 +95,8 @@ static int __devinit plat_nand_probe(struct platform_device *pdev) return 0; } } + if (pdata->chip.set_parts) + pdata->chip.set_parts(data->mtd.size, &pdata->chip); if (pdata->chip.partitions) { data->parts = pdata->chip.partitions; res = add_mtd_partitions(&data->mtd, data->parts, @@ -99,6 +110,8 @@ static int __devinit plat_nand_probe(struct platform_device *pdev) nand_release(&data->mtd); out: + if (pdata->ctrl.remove) + pdata->ctrl.remove(pdev); platform_set_drvdata(pdev, NULL); iounmap(data->io_base); kfree(data); @@ -111,15 +124,15 @@ out: static int __devexit plat_nand_remove(struct platform_device *pdev) { struct plat_nand_data *data = platform_get_drvdata(pdev); -#ifdef CONFIG_MTD_PARTITIONS struct platform_nand_data *pdata = pdev->dev.platform_data; -#endif nand_release(&data->mtd); #ifdef CONFIG_MTD_PARTITIONS if (data->parts && data->parts != pdata->chip.partitions) kfree(data->parts); #endif + if (pdata->ctrl.remove) + pdata->ctrl.remove(pdev); iounmap(data->io_base); kfree(data); @@ -128,7 +141,7 @@ static int __devexit plat_nand_remove(struct platform_device *pdev) static struct platform_driver plat_nand_driver = { .probe = plat_nand_probe, - .remove = plat_nand_remove, + .remove = __devexit_p(plat_nand_remove), .driver = { .name = "gen_nand", .owner = THIS_MODULE, diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index 8e375d5fe231..11dc7e69c4fb 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c @@ -74,6 +74,14 @@ static struct nand_ecclayout nand_hw_eccoob = { struct s3c2410_nand_info; +/** + * struct s3c2410_nand_mtd - driver MTD structure + * @mtd: The MTD instance to pass to the MTD layer. + * @chip: The NAND chip information. + * @set: The platform information supplied for this set of NAND chips. + * @info: Link back to the hardware information. + * @scan_res: The result from calling nand_scan_ident(). +*/ struct s3c2410_nand_mtd { struct mtd_info mtd; struct nand_chip chip; @@ -90,6 +98,21 @@ enum s3c_cpu_type { /* overview of the s3c2410 nand state */ +/** + * struct s3c2410_nand_info - NAND controller state. + * @mtds: An array of MTD instances on this controoler. + * @platform: The platform data for this board. + * @device: The platform device we bound to. + * @area: The IO area resource that came from request_mem_region(). + * @clk: The clock resource for this controller. + * @regs: The area mapped for the hardware registers described by @area. + * @sel_reg: Pointer to the register controlling the NAND selection. + * @sel_bit: The bit in @sel_reg to select the NAND chip. + * @mtd_count: The number of MTDs created from this controller. + * @save_sel: The contents of @sel_reg to be saved over suspend. + * @clk_rate: The clock rate from @clk. + * @cpu_type: The exact type of this controller. + */ struct s3c2410_nand_info { /* mtd info */ struct nand_hw_control controller; @@ -145,12 +168,19 @@ static inline int allow_clk_stop(struct s3c2410_nand_info *info) #define NS_IN_KHZ 1000000 +/** + * s3c_nand_calc_rate - calculate timing data. + * @wanted: The cycle time in nanoseconds. + * @clk: The clock rate in kHz. + * @max: The maximum divider value. + * + * Calculate the timing value from the given parameters. + */ static int s3c_nand_calc_rate(int wanted, unsigned long clk, int max) { int result; - result = (wanted * clk) / NS_IN_KHZ; - result++; + result = DIV_ROUND_UP((wanted * clk), NS_IN_KHZ); pr_debug("result %d from %ld, %d\n", result, clk, wanted); @@ -169,13 +199,21 @@ static int s3c_nand_calc_rate(int wanted, unsigned long clk, int max) /* controller setup */ +/** + * s3c2410_nand_setrate - setup controller timing information. + * @info: The controller instance. + * + * Given the information supplied by the platform, calculate and set + * the necessary timing registers in the hardware to generate the + * necessary timing cycles to the hardware. + */ static int s3c2410_nand_setrate(struct s3c2410_nand_info *info) { struct s3c2410_platform_nand *plat = info->platform; int tacls_max = (info->cpu_type == TYPE_S3C2412) ? 8 : 4; int tacls, twrph0, twrph1; unsigned long clkrate = clk_get_rate(info->clk); - unsigned long set, cfg, mask; + unsigned long uninitialized_var(set), cfg, uninitialized_var(mask); unsigned long flags; /* calculate the timing information for the controller */ @@ -215,9 +253,9 @@ static int s3c2410_nand_setrate(struct s3c2410_nand_info *info) case TYPE_S3C2440: case TYPE_S3C2412: - mask = (S3C2410_NFCONF_TACLS(tacls_max - 1) | - S3C2410_NFCONF_TWRPH0(7) | - S3C2410_NFCONF_TWRPH1(7)); + mask = (S3C2440_NFCONF_TACLS(tacls_max - 1) | + S3C2440_NFCONF_TWRPH0(7) | + S3C2440_NFCONF_TWRPH1(7)); set = S3C2440_NFCONF_TACLS(tacls - 1); set |= S3C2440_NFCONF_TWRPH0(twrph0 - 1); @@ -225,14 +263,9 @@ static int s3c2410_nand_setrate(struct s3c2410_nand_info *info) break; default: - /* keep compiler happy */ - mask = 0; - set = 0; BUG(); } - dev_dbg(info->device, "NF_CONF is 0x%lx\n", cfg); - local_irq_save(flags); cfg = readl(info->regs + S3C2410_NFCONF); @@ -242,9 +275,18 @@ static int s3c2410_nand_setrate(struct s3c2410_nand_info *info) local_irq_restore(flags); + dev_dbg(info->device, "NF_CONF is 0x%lx\n", cfg); + return 0; } +/** + * s3c2410_nand_inithw - basic hardware initialisation + * @info: The hardware state. + * + * Do the basic initialisation of the hardware, using s3c2410_nand_setrate() + * to setup the hardware access speeds and set the controller to be enabled. +*/ static int s3c2410_nand_inithw(struct s3c2410_nand_info *info) { int ret; @@ -268,8 +310,19 @@ static int s3c2410_nand_inithw(struct s3c2410_nand_info *info) return 0; } -/* select chip */ - +/** + * s3c2410_nand_select_chip - select the given nand chip + * @mtd: The MTD instance for this chip. + * @chip: The chip number. + * + * This is called by the MTD layer to either select a given chip for the + * @mtd instance, or to indicate that the access has finished and the + * chip can be de-selected. + * + * The routine ensures that the nFCE line is correctly setup, and any + * platform specific selection code is called to route nFCE to the specific + * chip. + */ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip) { struct s3c2410_nand_info *info; @@ -530,7 +583,16 @@ static void s3c2410_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) static void s3c2440_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) { struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); - readsl(info->regs + S3C2440_NFDATA, buf, len / 4); + + readsl(info->regs + S3C2440_NFDATA, buf, len >> 2); + + /* cleanup if we've got less than a word to do */ + if (len & 3) { + buf += len & ~3; + + for (; len & 3; len--) + *buf++ = readb(info->regs + S3C2440_NFDATA); + } } static void s3c2410_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) @@ -542,7 +604,16 @@ static void s3c2410_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int static void s3c2440_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) { struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); - writesl(info->regs + S3C2440_NFDATA, buf, len / 4); + + writesl(info->regs + S3C2440_NFDATA, buf, len >> 2); + + /* cleanup any fractional write */ + if (len & 3) { + buf += len & ~3; + + for (; len & 3; len--, buf++) + writeb(*buf, info->regs + S3C2440_NFDATA); + } } /* cpufreq driver support */ @@ -593,7 +664,7 @@ static inline void s3c2410_nand_cpufreq_deregister(struct s3c2410_nand_info *inf /* device management functions */ -static int s3c2410_nand_remove(struct platform_device *pdev) +static int s3c24xx_nand_remove(struct platform_device *pdev) { struct s3c2410_nand_info *info = to_nand_info(pdev); @@ -645,17 +716,31 @@ static int s3c2410_nand_remove(struct platform_device *pdev) } #ifdef CONFIG_MTD_PARTITIONS +const char *part_probes[] = { "cmdlinepart", NULL }; static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info, struct s3c2410_nand_mtd *mtd, struct s3c2410_nand_set *set) { + struct mtd_partition *part_info; + int nr_part = 0; + if (set == NULL) return add_mtd_device(&mtd->mtd); - if (set->nr_partitions > 0 && set->partitions != NULL) { - return add_mtd_partitions(&mtd->mtd, set->partitions, set->nr_partitions); + if (set->nr_partitions == 0) { + mtd->mtd.name = set->name; + nr_part = parse_mtd_partitions(&mtd->mtd, part_probes, + &part_info, 0); + } else { + if (set->nr_partitions > 0 && set->partitions != NULL) { + nr_part = set->nr_partitions; + part_info = set->partitions; + } } + if (nr_part > 0 && part_info) + return add_mtd_partitions(&mtd->mtd, part_info, nr_part); + return add_mtd_device(&mtd->mtd); } #else @@ -667,11 +752,16 @@ static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info, } #endif -/* s3c2410_nand_init_chip +/** + * s3c2410_nand_init_chip - initialise a single instance of an chip + * @info: The base NAND controller the chip is on. + * @nmtd: The new controller MTD instance to fill in. + * @set: The information passed from the board specific platform data. * - * init a single instance of an chip -*/ - + * Initialise the given @nmtd from the information in @info and @set. This + * readies the structure for use with the MTD layer functions by ensuring + * all pointers are setup and the necessary control routines selected. + */ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, struct s3c2410_nand_mtd *nmtd, struct s3c2410_nand_set *set) @@ -757,14 +847,40 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, if (set->disable_ecc) chip->ecc.mode = NAND_ECC_NONE; + + switch (chip->ecc.mode) { + case NAND_ECC_NONE: + dev_info(info->device, "NAND ECC disabled\n"); + break; + case NAND_ECC_SOFT: + dev_info(info->device, "NAND soft ECC\n"); + break; + case NAND_ECC_HW: + dev_info(info->device, "NAND hardware ECC\n"); + break; + default: + dev_info(info->device, "NAND ECC UNKNOWN\n"); + break; + } + + /* If you use u-boot BBT creation code, specifying this flag will + * let the kernel fish out the BBT from the NAND, and also skip the + * full NAND scan that can take 1/2s or so. Little things... */ + if (set->flash_bbt) + chip->options |= NAND_USE_FLASH_BBT | NAND_SKIP_BBTSCAN; } -/* s3c2410_nand_update_chip +/** + * s3c2410_nand_update_chip - post probe update + * @info: The controller instance. + * @nmtd: The driver version of the MTD instance. * - * post-probe chip update, to change any items, such as the - * layout for large page nand - */ - + * This routine is called after the chip probe has succesfully completed + * and the relevant per-chip information updated. This call ensure that + * we update the internal state accordingly. + * + * The internal state is currently limited to the ECC state information. +*/ static void s3c2410_nand_update_chip(struct s3c2410_nand_info *info, struct s3c2410_nand_mtd *nmtd) { @@ -773,33 +889,33 @@ static void s3c2410_nand_update_chip(struct s3c2410_nand_info *info, dev_dbg(info->device, "chip %p => page shift %d\n", chip, chip->page_shift); - if (hardware_ecc) { + if (chip->ecc.mode != NAND_ECC_HW) + return; + /* change the behaviour depending on wether we are using * the large or small page nand device */ - if (chip->page_shift > 10) { - chip->ecc.size = 256; - chip->ecc.bytes = 3; - } else { - chip->ecc.size = 512; - chip->ecc.bytes = 3; - chip->ecc.layout = &nand_hw_eccoob; - } + if (chip->page_shift > 10) { + chip->ecc.size = 256; + chip->ecc.bytes = 3; + } else { + chip->ecc.size = 512; + chip->ecc.bytes = 3; + chip->ecc.layout = &nand_hw_eccoob; } } -/* s3c2410_nand_probe +/* s3c24xx_nand_probe * * called by device layer when it finds a device matching * one our driver can handled. This code checks to see if * it can allocate all necessary resources then calls the * nand layer to look for devices */ - -static int s3c24xx_nand_probe(struct platform_device *pdev, - enum s3c_cpu_type cpu_type) +static int s3c24xx_nand_probe(struct platform_device *pdev) { struct s3c2410_platform_nand *plat = to_nand_plat(pdev); + enum s3c_cpu_type cpu_type; struct s3c2410_nand_info *info; struct s3c2410_nand_mtd *nmtd; struct s3c2410_nand_set *sets; @@ -809,6 +925,8 @@ static int s3c24xx_nand_probe(struct platform_device *pdev, int nr_sets; int setno; + cpu_type = platform_get_device_id(pdev)->driver_data; + pr_debug("s3c2410_nand_probe(%p)\n", pdev); info = kmalloc(sizeof(*info), GFP_KERNEL); @@ -922,7 +1040,7 @@ static int s3c24xx_nand_probe(struct platform_device *pdev, return 0; exit_error: - s3c2410_nand_remove(pdev); + s3c24xx_nand_remove(pdev); if (err == 0) err = -EINVAL; @@ -983,50 +1101,33 @@ static int s3c24xx_nand_resume(struct platform_device *dev) /* driver device registration */ -static int s3c2410_nand_probe(struct platform_device *dev) -{ - return s3c24xx_nand_probe(dev, TYPE_S3C2410); -} - -static int s3c2440_nand_probe(struct platform_device *dev) -{ - return s3c24xx_nand_probe(dev, TYPE_S3C2440); -} - -static int s3c2412_nand_probe(struct platform_device *dev) -{ - return s3c24xx_nand_probe(dev, TYPE_S3C2412); -} - -static struct platform_driver s3c2410_nand_driver = { - .probe = s3c2410_nand_probe, - .remove = s3c2410_nand_remove, - .suspend = s3c24xx_nand_suspend, - .resume = s3c24xx_nand_resume, - .driver = { - .name = "s3c2410-nand", - .owner = THIS_MODULE, +static struct platform_device_id s3c24xx_driver_ids[] = { + { + .name = "s3c2410-nand", + .driver_data = TYPE_S3C2410, + }, { + .name = "s3c2440-nand", + .driver_data = TYPE_S3C2440, + }, { + .name = "s3c2412-nand", + .driver_data = TYPE_S3C2412, + }, { + .name = "s3c6400-nand", + .driver_data = TYPE_S3C2412, /* compatible with 2412 */ }, + { } }; -static struct platform_driver s3c2440_nand_driver = { - .probe = s3c2440_nand_probe, - .remove = s3c2410_nand_remove, - .suspend = s3c24xx_nand_suspend, - .resume = s3c24xx_nand_resume, - .driver = { - .name = "s3c2440-nand", - .owner = THIS_MODULE, - }, -}; +MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids); -static struct platform_driver s3c2412_nand_driver = { - .probe = s3c2412_nand_probe, - .remove = s3c2410_nand_remove, +static struct platform_driver s3c24xx_nand_driver = { + .probe = s3c24xx_nand_probe, + .remove = s3c24xx_nand_remove, .suspend = s3c24xx_nand_suspend, .resume = s3c24xx_nand_resume, + .id_table = s3c24xx_driver_ids, .driver = { - .name = "s3c2412-nand", + .name = "s3c24xx-nand", .owner = THIS_MODULE, }, }; @@ -1035,16 +1136,12 @@ static int __init s3c2410_nand_init(void) { printk("S3C24XX NAND Driver, (c) 2004 Simtec Electronics\n"); - platform_driver_register(&s3c2412_nand_driver); - platform_driver_register(&s3c2440_nand_driver); - return platform_driver_register(&s3c2410_nand_driver); + return platform_driver_register(&s3c24xx_nand_driver); } static void __exit s3c2410_nand_exit(void) { - platform_driver_unregister(&s3c2412_nand_driver); - platform_driver_unregister(&s3c2440_nand_driver); - platform_driver_unregister(&s3c2410_nand_driver); + platform_driver_unregister(&s3c24xx_nand_driver); } module_init(s3c2410_nand_init); @@ -1053,6 +1150,3 @@ module_exit(s3c2410_nand_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Ben Dooks "); MODULE_DESCRIPTION("S3C24XX MTD NAND driver"); -MODULE_ALIAS("platform:s3c2410-nand"); -MODULE_ALIAS("platform:s3c2412-nand"); -MODULE_ALIAS("platform:s3c2440-nand"); diff --git a/drivers/mtd/nand/txx9ndfmc.c b/drivers/mtd/nand/txx9ndfmc.c index 812479264896..488088eff2ca 100644 --- a/drivers/mtd/nand/txx9ndfmc.c +++ b/drivers/mtd/nand/txx9ndfmc.c @@ -64,7 +64,7 @@ struct txx9ndfmc_priv { struct nand_chip chip; struct mtd_info mtd; int cs; - char mtdname[BUS_ID_SIZE + 2]; + const char *mtdname; }; #define MAX_TXX9NDFMC_DEV 4 @@ -334,16 +334,23 @@ static int __init txx9ndfmc_probe(struct platform_device *dev) if (plat->ch_mask != 1) { txx9_priv->cs = i; - sprintf(txx9_priv->mtdname, "%s.%u", - dev_name(&dev->dev), i); + txx9_priv->mtdname = kasprintf(GFP_KERNEL, "%s.%u", + dev_name(&dev->dev), i); } else { txx9_priv->cs = -1; - strcpy(txx9_priv->mtdname, dev_name(&dev->dev)); + txx9_priv->mtdname = kstrdup(dev_name(&dev->dev), + GFP_KERNEL); + } + if (!txx9_priv->mtdname) { + kfree(txx9_priv); + dev_err(&dev->dev, "Unable to allocate MTD name.\n"); + continue; } if (plat->wide_mask & (1 << i)) chip->options |= NAND_BUSWIDTH_16; if (nand_scan(mtd, 1)) { + kfree(txx9_priv->mtdname); kfree(txx9_priv); continue; } @@ -385,6 +392,7 @@ static int __exit txx9ndfmc_remove(struct platform_device *dev) kfree(drvdata->parts[i]); #endif del_mtd_device(mtd); + kfree(txx9_priv->mtdname); kfree(txx9_priv); } return 0; diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c index f2e9de1414df..38d656b9b2ee 100644 --- a/drivers/mtd/onenand/omap2.c +++ b/drivers/mtd/onenand/omap2.c @@ -39,7 +39,6 @@ #include #include #include -#include #include @@ -566,7 +565,7 @@ int omap2_onenand_rephase(void) NULL, __adjust_timing); } -static void __devexit omap2_onenand_shutdown(struct platform_device *pdev) +static void omap2_onenand_shutdown(struct platform_device *pdev) { struct omap2_onenand *c = dev_get_drvdata(&pdev->dev); @@ -778,7 +777,7 @@ static int __devexit omap2_onenand_remove(struct platform_device *pdev) static struct platform_driver omap2_onenand_driver = { .probe = omap2_onenand_probe, - .remove = omap2_onenand_remove, + .remove = __devexit_p(omap2_onenand_remove), .shutdown = omap2_onenand_shutdown, .driver = { .name = DRIVER_NAME, diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 30d6999e5f9f..6e829095ea9d 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -9,6 +9,10 @@ * auto-placement support, read-while load support, various fixes * Copyright (C) Nokia Corporation, 2007 * + * Vishak G , Rohit Hagargundgi + * Flex-OneNAND support + * Copyright (C) Samsung Electronics, 2008 + * * 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. @@ -16,6 +20,7 @@ #include #include +#include #include #include #include @@ -27,6 +32,38 @@ #include +/* Default Flex-OneNAND boundary and lock respectively */ +static int flex_bdry[MAX_DIES * 2] = { -1, 0, -1, 0 }; + +module_param_array(flex_bdry, int, NULL, 0400); +MODULE_PARM_DESC(flex_bdry, "SLC Boundary information for Flex-OneNAND" + "Syntax:flex_bdry=DIE_BDRY,LOCK,..." + "DIE_BDRY: SLC boundary of the die" + "LOCK: Locking information for SLC boundary" + " : 0->Set boundary in unlocked status" + " : 1->Set boundary in locked status"); + +/** + * onenand_oob_128 - oob info for Flex-Onenand with 4KB page + * For now, we expose only 64 out of 80 ecc bytes + */ +static struct nand_ecclayout onenand_oob_128 = { + .eccbytes = 64, + .eccpos = { + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 102, 103, 104, 105 + }, + .oobfree = { + {2, 4}, {18, 4}, {34, 4}, {50, 4}, + {66, 4}, {82, 4}, {98, 4}, {114, 4} + } +}; + /** * onenand_oob_64 - oob info for large (2KB) page */ @@ -65,6 +102,14 @@ static const unsigned char ffchars[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 48 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 64 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 80 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 96 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 112 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 128 */ }; /** @@ -170,6 +215,70 @@ static int onenand_buffer_address(int dataram1, int sectors, int count) return ((bsa << ONENAND_BSA_SHIFT) | bsc); } +/** + * flexonenand_block- For given address return block number + * @param this - OneNAND device structure + * @param addr - Address for which block number is needed + */ +static unsigned flexonenand_block(struct onenand_chip *this, loff_t addr) +{ + unsigned boundary, blk, die = 0; + + if (ONENAND_IS_DDP(this) && addr >= this->diesize[0]) { + die = 1; + addr -= this->diesize[0]; + } + + boundary = this->boundary[die]; + + blk = addr >> (this->erase_shift - 1); + if (blk > boundary) + blk = (blk + boundary + 1) >> 1; + + blk += die ? this->density_mask : 0; + return blk; +} + +inline unsigned onenand_block(struct onenand_chip *this, loff_t addr) +{ + if (!FLEXONENAND(this)) + return addr >> this->erase_shift; + return flexonenand_block(this, addr); +} + +/** + * flexonenand_addr - Return address of the block + * @this: OneNAND device structure + * @block: Block number on Flex-OneNAND + * + * Return address of the block + */ +static loff_t flexonenand_addr(struct onenand_chip *this, int block) +{ + loff_t ofs = 0; + int die = 0, boundary; + + if (ONENAND_IS_DDP(this) && block >= this->density_mask) { + block -= this->density_mask; + die = 1; + ofs = this->diesize[0]; + } + + boundary = this->boundary[die]; + ofs += (loff_t)block << (this->erase_shift - 1); + if (block > (boundary + 1)) + ofs += (loff_t)(block - boundary - 1) << (this->erase_shift - 1); + return ofs; +} + +loff_t onenand_addr(struct onenand_chip *this, int block) +{ + if (!FLEXONENAND(this)) + return (loff_t)block << this->erase_shift; + return flexonenand_addr(this, block); +} +EXPORT_SYMBOL(onenand_addr); + /** * onenand_get_density - [DEFAULT] Get OneNAND density * @param dev_id OneNAND device ID @@ -182,6 +291,22 @@ static inline int onenand_get_density(int dev_id) return (density & ONENAND_DEVICE_DENSITY_MASK); } +/** + * flexonenand_region - [Flex-OneNAND] Return erase region of addr + * @param mtd MTD device structure + * @param addr address whose erase region needs to be identified + */ +int flexonenand_region(struct mtd_info *mtd, loff_t addr) +{ + int i; + + for (i = 0; i < mtd->numeraseregions; i++) + if (addr < mtd->eraseregions[i].offset) + break; + return i - 1; +} +EXPORT_SYMBOL(flexonenand_region); + /** * onenand_command - [DEFAULT] Send command to OneNAND device * @param mtd MTD device structure @@ -207,16 +332,28 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le page = -1; break; - case ONENAND_CMD_ERASE: - case ONENAND_CMD_BUFFERRAM: - case ONENAND_CMD_OTP_ACCESS: - block = (int) (addr >> this->erase_shift); + case FLEXONENAND_CMD_PI_ACCESS: + /* addr contains die index */ + block = addr * this->density_mask; page = -1; break; + case ONENAND_CMD_ERASE: + case ONENAND_CMD_BUFFERRAM: + case ONENAND_CMD_OTP_ACCESS: + block = onenand_block(this, addr); + page = -1; + break; + + case FLEXONENAND_CMD_READ_PI: + cmd = ONENAND_CMD_READ; + block = addr * this->density_mask; + page = 0; + break; + default: - block = (int) (addr >> this->erase_shift); - page = (int) (addr >> this->page_shift); + block = onenand_block(this, addr); + page = (int) (addr - onenand_addr(this, block)) >> this->page_shift; if (ONENAND_IS_2PLANE(this)) { /* Make the even block number */ @@ -236,7 +373,7 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le value = onenand_bufferram_address(this, block); this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2); - if (ONENAND_IS_2PLANE(this)) + if (ONENAND_IS_MLC(this) || ONENAND_IS_2PLANE(this)) /* It is always BufferRAM0 */ ONENAND_SET_BUFFERRAM0(this); else @@ -258,13 +395,18 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le if (page != -1) { /* Now we use page size operation */ - int sectors = 4, count = 4; + int sectors = 0, count = 0; int dataram; switch (cmd) { + case FLEXONENAND_CMD_RECOVER_LSB: case ONENAND_CMD_READ: case ONENAND_CMD_READOOB: - dataram = ONENAND_SET_NEXT_BUFFERRAM(this); + if (ONENAND_IS_MLC(this)) + /* It is always BufferRAM0 */ + dataram = ONENAND_SET_BUFFERRAM0(this); + else + dataram = ONENAND_SET_NEXT_BUFFERRAM(this); break; default: @@ -292,6 +434,30 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le return 0; } +/** + * onenand_read_ecc - return ecc status + * @param this onenand chip structure + */ +static inline int onenand_read_ecc(struct onenand_chip *this) +{ + int ecc, i, result = 0; + + if (!FLEXONENAND(this)) + return this->read_word(this->base + ONENAND_REG_ECC_STATUS); + + for (i = 0; i < 4; i++) { + ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS + i); + if (likely(!ecc)) + continue; + if (ecc & FLEXONENAND_UNCORRECTABLE_ERROR) + return ONENAND_ECC_2BIT_ALL; + else + result = ONENAND_ECC_1BIT_ALL; + } + + return result; +} + /** * onenand_wait - [DEFAULT] wait until the command is done * @param mtd MTD device structure @@ -331,14 +497,14 @@ static int onenand_wait(struct mtd_info *mtd, int state) * power off recovery (POR) test, it should read ECC status first */ if (interrupt & ONENAND_INT_READ) { - int ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS); + int ecc = onenand_read_ecc(this); if (ecc) { if (ecc & ONENAND_ECC_2BIT_ALL) { printk(KERN_ERR "onenand_wait: ECC error = 0x%04x\n", ecc); mtd->ecc_stats.failed++; return -EBADMSG; } else if (ecc & ONENAND_ECC_1BIT_ALL) { - printk(KERN_INFO "onenand_wait: correctable ECC error = 0x%04x\n", ecc); + printk(KERN_DEBUG "onenand_wait: correctable ECC error = 0x%04x\n", ecc); mtd->ecc_stats.corrected++; } } @@ -656,7 +822,7 @@ static int onenand_check_bufferram(struct mtd_info *mtd, loff_t addr) if (found && ONENAND_IS_DDP(this)) { /* Select DataRAM for DDP */ - int block = (int) (addr >> this->erase_shift); + int block = onenand_block(this, addr); int value = onenand_bufferram_address(this, block); this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2); } @@ -815,6 +981,149 @@ static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf, int col return 0; } +/** + * onenand_recover_lsb - [Flex-OneNAND] Recover LSB page data + * @param mtd MTD device structure + * @param addr address to recover + * @param status return value from onenand_wait / onenand_bbt_wait + * + * MLC NAND Flash cell has paired pages - LSB page and MSB page. LSB page has + * lower page address and MSB page has higher page address in paired pages. + * If power off occurs during MSB page program, the paired LSB page data can + * become corrupt. LSB page recovery read is a way to read LSB page though page + * data are corrupted. When uncorrectable error occurs as a result of LSB page + * read after power up, issue LSB page recovery read. + */ +static int onenand_recover_lsb(struct mtd_info *mtd, loff_t addr, int status) +{ + struct onenand_chip *this = mtd->priv; + int i; + + /* Recovery is only for Flex-OneNAND */ + if (!FLEXONENAND(this)) + return status; + + /* check if we failed due to uncorrectable error */ + if (status != -EBADMSG && status != ONENAND_BBT_READ_ECC_ERROR) + return status; + + /* check if address lies in MLC region */ + i = flexonenand_region(mtd, addr); + if (mtd->eraseregions[i].erasesize < (1 << this->erase_shift)) + return status; + + /* We are attempting to reread, so decrement stats.failed + * which was incremented by onenand_wait due to read failure + */ + printk(KERN_INFO "onenand_recover_lsb: Attempting to recover from uncorrectable read\n"); + mtd->ecc_stats.failed--; + + /* Issue the LSB page recovery command */ + this->command(mtd, FLEXONENAND_CMD_RECOVER_LSB, addr, this->writesize); + return this->wait(mtd, FL_READING); +} + +/** + * onenand_mlc_read_ops_nolock - MLC OneNAND read main and/or out-of-band + * @param mtd MTD device structure + * @param from offset to read from + * @param ops: oob operation description structure + * + * MLC OneNAND / Flex-OneNAND has 4KB page size and 4KB dataram. + * So, read-while-load is not present. + */ +static int onenand_mlc_read_ops_nolock(struct mtd_info *mtd, loff_t from, + struct mtd_oob_ops *ops) +{ + struct onenand_chip *this = mtd->priv; + struct mtd_ecc_stats stats; + size_t len = ops->len; + size_t ooblen = ops->ooblen; + u_char *buf = ops->datbuf; + u_char *oobbuf = ops->oobbuf; + int read = 0, column, thislen; + int oobread = 0, oobcolumn, thisooblen, oobsize; + int ret = 0; + int writesize = this->writesize; + + DEBUG(MTD_DEBUG_LEVEL3, "onenand_mlc_read_ops_nolock: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); + + if (ops->mode == MTD_OOB_AUTO) + oobsize = this->ecclayout->oobavail; + else + oobsize = mtd->oobsize; + + oobcolumn = from & (mtd->oobsize - 1); + + /* Do not allow reads past end of device */ + if (from + len > mtd->size) { + printk(KERN_ERR "onenand_mlc_read_ops_nolock: Attempt read beyond end of device\n"); + ops->retlen = 0; + ops->oobretlen = 0; + return -EINVAL; + } + + stats = mtd->ecc_stats; + + while (read < len) { + cond_resched(); + + thislen = min_t(int, writesize, len - read); + + column = from & (writesize - 1); + if (column + thislen > writesize) + thislen = writesize - column; + + if (!onenand_check_bufferram(mtd, from)) { + this->command(mtd, ONENAND_CMD_READ, from, writesize); + + ret = this->wait(mtd, FL_READING); + if (unlikely(ret)) + ret = onenand_recover_lsb(mtd, from, ret); + onenand_update_bufferram(mtd, from, !ret); + if (ret == -EBADMSG) + ret = 0; + } + + this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen); + if (oobbuf) { + thisooblen = oobsize - oobcolumn; + thisooblen = min_t(int, thisooblen, ooblen - oobread); + + if (ops->mode == MTD_OOB_AUTO) + onenand_transfer_auto_oob(mtd, oobbuf, oobcolumn, thisooblen); + else + this->read_bufferram(mtd, ONENAND_SPARERAM, oobbuf, oobcolumn, thisooblen); + oobread += thisooblen; + oobbuf += thisooblen; + oobcolumn = 0; + } + + read += thislen; + if (read == len) + break; + + from += thislen; + buf += thislen; + } + + /* + * Return success, if no ECC failures, else -EBADMSG + * fs driver will take care of that, because + * retlen == desired len and result == -EBADMSG + */ + ops->retlen = read; + ops->oobretlen = oobread; + + if (ret) + return ret; + + if (mtd->ecc_stats.failed - stats.failed) + return -EBADMSG; + + return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0; +} + /** * onenand_read_ops_nolock - [OneNAND Interface] OneNAND read main and/or out-of-band * @param mtd MTD device structure @@ -962,7 +1271,7 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from, size_t len = ops->ooblen; mtd_oob_mode_t mode = ops->mode; u_char *buf = ops->oobbuf; - int ret = 0; + int ret = 0, readcmd; from += ops->ooboffs; @@ -993,17 +1302,22 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from, stats = mtd->ecc_stats; + readcmd = ONENAND_IS_MLC(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB; + while (read < len) { cond_resched(); thislen = oobsize - column; thislen = min_t(int, thislen, len); - this->command(mtd, ONENAND_CMD_READOOB, from, mtd->oobsize); + this->command(mtd, readcmd, from, mtd->oobsize); onenand_update_bufferram(mtd, from, 0); ret = this->wait(mtd, FL_READING); + if (unlikely(ret)) + ret = onenand_recover_lsb(mtd, from, ret); + if (ret && ret != -EBADMSG) { printk(KERN_ERR "onenand_read_oob_nolock: read failed = 0x%x\n", ret); break; @@ -1053,6 +1367,7 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from, static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { + struct onenand_chip *this = mtd->priv; struct mtd_oob_ops ops = { .len = len, .ooblen = 0, @@ -1062,7 +1377,9 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, int ret; onenand_get_device(mtd, FL_READING); - ret = onenand_read_ops_nolock(mtd, from, &ops); + ret = ONENAND_IS_MLC(this) ? + onenand_mlc_read_ops_nolock(mtd, from, &ops) : + onenand_read_ops_nolock(mtd, from, &ops); onenand_release_device(mtd); *retlen = ops.retlen; @@ -1080,6 +1397,7 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, static int onenand_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) { + struct onenand_chip *this = mtd->priv; int ret; switch (ops->mode) { @@ -1094,7 +1412,9 @@ static int onenand_read_oob(struct mtd_info *mtd, loff_t from, onenand_get_device(mtd, FL_READING); if (ops->datbuf) - ret = onenand_read_ops_nolock(mtd, from, ops); + ret = ONENAND_IS_MLC(this) ? + onenand_mlc_read_ops_nolock(mtd, from, ops) : + onenand_read_ops_nolock(mtd, from, ops); else ret = onenand_read_oob_nolock(mtd, from, ops); onenand_release_device(mtd); @@ -1128,11 +1448,11 @@ static int onenand_bbt_wait(struct mtd_info *mtd, int state) ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS); if (interrupt & ONENAND_INT_READ) { - int ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS); + int ecc = onenand_read_ecc(this); if (ecc & ONENAND_ECC_2BIT_ALL) { printk(KERN_INFO "onenand_bbt_wait: ecc error = 0x%04x" ", controller error 0x%04x\n", ecc, ctrl); - return ONENAND_BBT_READ_ERROR; + return ONENAND_BBT_READ_ECC_ERROR; } } else { printk(KERN_ERR "onenand_bbt_wait: read timeout!" @@ -1163,7 +1483,7 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from, { struct onenand_chip *this = mtd->priv; int read = 0, thislen, column; - int ret = 0; + int ret = 0, readcmd; size_t len = ops->ooblen; u_char *buf = ops->oobbuf; @@ -1183,17 +1503,22 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from, column = from & (mtd->oobsize - 1); + readcmd = ONENAND_IS_MLC(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB; + while (read < len) { cond_resched(); thislen = mtd->oobsize - column; thislen = min_t(int, thislen, len); - this->command(mtd, ONENAND_CMD_READOOB, from, mtd->oobsize); + this->command(mtd, readcmd, from, mtd->oobsize); onenand_update_bufferram(mtd, from, 0); - ret = onenand_bbt_wait(mtd, FL_READING); + ret = this->bbt_wait(mtd, FL_READING); + if (unlikely(ret)) + ret = onenand_recover_lsb(mtd, from, ret); + if (ret) break; @@ -1230,9 +1555,11 @@ static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to { struct onenand_chip *this = mtd->priv; u_char *oob_buf = this->oob_buf; - int status, i; + int status, i, readcmd; - this->command(mtd, ONENAND_CMD_READOOB, to, mtd->oobsize); + readcmd = ONENAND_IS_MLC(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB; + + this->command(mtd, readcmd, to, mtd->oobsize); onenand_update_bufferram(mtd, to, 0); status = this->wait(mtd, FL_READING); if (status) @@ -1633,7 +1960,7 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to, { struct onenand_chip *this = mtd->priv; int column, ret = 0, oobsize; - int written = 0; + int written = 0, oobcmd; u_char *oobbuf; size_t len = ops->ooblen; const u_char *buf = ops->oobbuf; @@ -1675,6 +2002,8 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to, oobbuf = this->oob_buf; + oobcmd = ONENAND_IS_MLC(this) ? ONENAND_CMD_PROG : ONENAND_CMD_PROGOOB; + /* Loop until all data write */ while (written < len) { int thislen = min_t(int, oobsize, len - written); @@ -1692,7 +2021,14 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to, memcpy(oobbuf + column, buf, thislen); this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize); - this->command(mtd, ONENAND_CMD_PROGOOB, to, mtd->oobsize); + if (ONENAND_IS_MLC(this)) { + /* Set main area of DataRAM to 0xff*/ + memset(this->page_buf, 0xff, mtd->writesize); + this->write_bufferram(mtd, ONENAND_DATARAM, + this->page_buf, 0, mtd->writesize); + } + + this->command(mtd, oobcmd, to, mtd->oobsize); onenand_update_bufferram(mtd, to, 0); if (ONENAND_IS_2PLANE(this)) { @@ -1815,41 +2151,57 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr) { struct onenand_chip *this = mtd->priv; unsigned int block_size; - loff_t addr; - int len; - int ret = 0; + loff_t addr = instr->addr; + loff_t len = instr->len; + int ret = 0, i; + struct mtd_erase_region_info *region = NULL; + loff_t region_end = 0; DEBUG(MTD_DEBUG_LEVEL3, "onenand_erase: start = 0x%012llx, len = %llu\n", (unsigned long long) instr->addr, (unsigned long long) instr->len); - block_size = (1 << this->erase_shift); - - /* Start address must align on block boundary */ - if (unlikely(instr->addr & (block_size - 1))) { - printk(KERN_ERR "onenand_erase: Unaligned address\n"); + /* Do not allow erase past end of device */ + if (unlikely((len + addr) > mtd->size)) { + printk(KERN_ERR "onenand_erase: Erase past end of device\n"); return -EINVAL; } + if (FLEXONENAND(this)) { + /* Find the eraseregion of this address */ + i = flexonenand_region(mtd, addr); + region = &mtd->eraseregions[i]; + + block_size = region->erasesize; + region_end = region->offset + region->erasesize * region->numblocks; + + /* Start address within region must align on block boundary. + * Erase region's start offset is always block start address. + */ + if (unlikely((addr - region->offset) & (block_size - 1))) { + printk(KERN_ERR "onenand_erase: Unaligned address\n"); + return -EINVAL; + } + } else { + block_size = 1 << this->erase_shift; + + /* Start address must align on block boundary */ + if (unlikely(addr & (block_size - 1))) { + printk(KERN_ERR "onenand_erase: Unaligned address\n"); + return -EINVAL; + } + } + /* Length must align on block boundary */ - if (unlikely(instr->len & (block_size - 1))) { + if (unlikely(len & (block_size - 1))) { printk(KERN_ERR "onenand_erase: Length not block aligned\n"); return -EINVAL; } - /* Do not allow erase past end of device */ - if (unlikely((instr->len + instr->addr) > mtd->size)) { - printk(KERN_ERR "onenand_erase: Erase past end of device\n"); - return -EINVAL; - } - instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN; /* Grab the lock and see if the device is available */ onenand_get_device(mtd, FL_ERASING); /* Loop throught the pages */ - len = instr->len; - addr = instr->addr; - instr->state = MTD_ERASING; while (len) { @@ -1869,7 +2221,8 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr) ret = this->wait(mtd, FL_ERASING); /* Check, if it is write protected */ if (ret) { - printk(KERN_ERR "onenand_erase: Failed erase, block %d\n", (unsigned) (addr >> this->erase_shift)); + printk(KERN_ERR "onenand_erase: Failed erase, block %d\n", + onenand_block(this, addr)); instr->state = MTD_ERASE_FAILED; instr->fail_addr = addr; goto erase_exit; @@ -1877,6 +2230,22 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr) len -= block_size; addr += block_size; + + if (addr == region_end) { + if (!len) + break; + region++; + + block_size = region->erasesize; + region_end = region->offset + region->erasesize * region->numblocks; + + if (len & (block_size - 1)) { + /* FIXME: This should be handled at MTD partitioning level. */ + printk(KERN_ERR "onenand_erase: Unaligned address\n"); + goto erase_exit; + } + } + } instr->state = MTD_ERASE_DONE; @@ -1955,13 +2324,17 @@ static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) int block; /* Get block number */ - block = ((int) ofs) >> bbm->bbt_erase_shift; + block = onenand_block(this, ofs); if (bbm->bbt) bbm->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1); /* We write two bytes, so we dont have to mess with 16 bit access */ ofs += mtd->oobsize + (bbm->badblockpos & ~0x01); - return onenand_write_oob_nolock(mtd, ofs, &ops); + /* FIXME : What to do when marking SLC block in partition + * with MLC erasesize? For now, it is not advisable to + * create partitions containing both SLC and MLC regions. + */ + return onenand_write_oob_nolock(mtd, ofs, &ops); } /** @@ -2005,8 +2378,8 @@ static int onenand_do_lock_cmd(struct mtd_info *mtd, loff_t ofs, size_t len, int int start, end, block, value, status; int wp_status_mask; - start = ofs >> this->erase_shift; - end = len >> this->erase_shift; + start = onenand_block(this, ofs); + end = onenand_block(this, ofs + len) - 1; if (cmd == ONENAND_CMD_LOCK) wp_status_mask = ONENAND_WP_LS; @@ -2018,7 +2391,7 @@ static int onenand_do_lock_cmd(struct mtd_info *mtd, loff_t ofs, size_t len, int /* Set start block address */ this->write_word(start, this->base + ONENAND_REG_START_BLOCK_ADDRESS); /* Set end block address */ - this->write_word(start + end - 1, this->base + ONENAND_REG_END_BLOCK_ADDRESS); + this->write_word(end, this->base + ONENAND_REG_END_BLOCK_ADDRESS); /* Write lock command */ this->command(mtd, cmd, 0, 0); @@ -2039,7 +2412,7 @@ static int onenand_do_lock_cmd(struct mtd_info *mtd, loff_t ofs, size_t len, int } /* Block lock scheme */ - for (block = start; block < start + end; block++) { + for (block = start; block < end + 1; block++) { /* Set block address */ value = onenand_block_address(this, block); this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1); @@ -2147,7 +2520,7 @@ static void onenand_unlock_all(struct mtd_info *mtd) { struct onenand_chip *this = mtd->priv; loff_t ofs = 0; - size_t len = this->chipsize; + loff_t len = mtd->size; if (this->options & ONENAND_HAS_UNLOCK_ALL) { /* Set start block address */ @@ -2163,12 +2536,16 @@ static void onenand_unlock_all(struct mtd_info *mtd) & ONENAND_CTRL_ONGO) continue; + /* Don't check lock status */ + if (this->options & ONENAND_SKIP_UNLOCK_CHECK) + return; + /* Check lock status */ if (onenand_check_lock_status(this)) return; /* Workaround for all block unlock in DDP */ - if (ONENAND_IS_DDP(this)) { + if (ONENAND_IS_DDP(this) && !FLEXONENAND(this)) { /* All blocks on another chip */ ofs = this->chipsize >> 1; len = this->chipsize >> 1; @@ -2210,7 +2587,9 @@ static int do_otp_read(struct mtd_info *mtd, loff_t from, size_t len, this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0); this->wait(mtd, FL_OTPING); - ret = onenand_read_ops_nolock(mtd, from, &ops); + ret = ONENAND_IS_MLC(this) ? + onenand_mlc_read_ops_nolock(mtd, from, &ops) : + onenand_read_ops_nolock(mtd, from, &ops); /* Exit OTP access mode */ this->command(mtd, ONENAND_CMD_RESET, 0, 0); @@ -2277,21 +2656,32 @@ static int do_otp_lock(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { struct onenand_chip *this = mtd->priv; - struct mtd_oob_ops ops = { - .mode = MTD_OOB_PLACE, - .ooblen = len, - .oobbuf = buf, - .ooboffs = 0, - }; + struct mtd_oob_ops ops; int ret; /* Enter OTP access mode */ this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0); this->wait(mtd, FL_OTPING); - ret = onenand_write_oob_nolock(mtd, from, &ops); - - *retlen = ops.oobretlen; + if (FLEXONENAND(this)) { + /* + * For Flex-OneNAND, we write lock mark to 1st word of sector 4 of + * main area of page 49. + */ + ops.len = mtd->writesize; + ops.ooblen = 0; + ops.datbuf = buf; + ops.oobbuf = NULL; + ret = onenand_write_ops_nolock(mtd, mtd->writesize * 49, &ops); + *retlen = ops.retlen; + } else { + ops.mode = MTD_OOB_PLACE; + ops.ooblen = len; + ops.oobbuf = buf; + ops.ooboffs = 0; + ret = onenand_write_oob_nolock(mtd, from, &ops); + *retlen = ops.oobretlen; + } /* Exit OTP access mode */ this->command(mtd, ONENAND_CMD_RESET, 0, 0); @@ -2475,27 +2865,34 @@ static int onenand_lock_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len) { struct onenand_chip *this = mtd->priv; - u_char *oob_buf = this->oob_buf; + u_char *buf = FLEXONENAND(this) ? this->page_buf : this->oob_buf; size_t retlen; int ret; - memset(oob_buf, 0xff, mtd->oobsize); + memset(buf, 0xff, FLEXONENAND(this) ? this->writesize + : mtd->oobsize); /* * Note: OTP lock operation * OTP block : 0xXXFC * 1st block : 0xXXF3 (If chip support) * Both : 0xXXF0 (If chip support) */ - oob_buf[ONENAND_OTP_LOCK_OFFSET] = 0xFC; + if (FLEXONENAND(this)) + buf[FLEXONENAND_OTP_LOCK_OFFSET] = 0xFC; + else + buf[ONENAND_OTP_LOCK_OFFSET] = 0xFC; /* * Write lock mark to 8th word of sector0 of page0 of the spare0. * We write 16 bytes spare area instead of 2 bytes. + * For Flex-OneNAND, we write lock mark to 1st word of sector 4 of + * main area of page 49. */ - from = 0; - len = 16; - ret = onenand_otp_walk(mtd, from, len, &retlen, oob_buf, do_otp_lock, MTD_OTP_USER); + from = 0; + len = FLEXONENAND(this) ? mtd->writesize : 16; + + ret = onenand_otp_walk(mtd, from, len, &retlen, buf, do_otp_lock, MTD_OTP_USER); return ret ? : retlen; } @@ -2542,6 +2939,14 @@ static void onenand_check_features(struct mtd_info *mtd) break; } + if (ONENAND_IS_MLC(this)) + this->options &= ~ONENAND_HAS_2PLANE; + + if (FLEXONENAND(this)) { + this->options &= ~ONENAND_HAS_CONT_LOCK; + this->options |= ONENAND_HAS_UNLOCK_ALL; + } + if (this->options & ONENAND_HAS_CONT_LOCK) printk(KERN_DEBUG "Lock scheme is Continuous Lock\n"); if (this->options & ONENAND_HAS_UNLOCK_ALL) @@ -2559,14 +2964,16 @@ static void onenand_check_features(struct mtd_info *mtd) */ static void onenand_print_device_info(int device, int version) { - int vcc, demuxed, ddp, density; + int vcc, demuxed, ddp, density, flexonenand; vcc = device & ONENAND_DEVICE_VCC_MASK; demuxed = device & ONENAND_DEVICE_IS_DEMUX; ddp = device & ONENAND_DEVICE_IS_DDP; density = onenand_get_density(device); - printk(KERN_INFO "%sOneNAND%s %dMB %sV 16-bit (0x%02x)\n", - demuxed ? "" : "Muxed ", + flexonenand = device & DEVICE_IS_FLEXONENAND; + printk(KERN_INFO "%s%sOneNAND%s %dMB %sV 16-bit (0x%02x)\n", + demuxed ? "" : "Muxed ", + flexonenand ? "Flex-" : "", ddp ? "(DDP)" : "", (16 << density), vcc ? "2.65/3.3" : "1.8", @@ -2576,6 +2983,7 @@ static void onenand_print_device_info(int device, int version) static const struct onenand_manufacturers onenand_manuf_ids[] = { {ONENAND_MFR_SAMSUNG, "Samsung"}, + {ONENAND_MFR_NUMONYX, "Numonyx"}, }; /** @@ -2604,6 +3012,261 @@ static int onenand_check_maf(int manuf) return (i == size); } +/** +* flexonenand_get_boundary - Reads the SLC boundary +* @param onenand_info - onenand info structure +**/ +static int flexonenand_get_boundary(struct mtd_info *mtd) +{ + struct onenand_chip *this = mtd->priv; + unsigned die, bdry; + int ret, syscfg, locked; + + /* Disable ECC */ + syscfg = this->read_word(this->base + ONENAND_REG_SYS_CFG1); + this->write_word((syscfg | 0x0100), this->base + ONENAND_REG_SYS_CFG1); + + for (die = 0; die < this->dies; die++) { + this->command(mtd, FLEXONENAND_CMD_PI_ACCESS, die, 0); + this->wait(mtd, FL_SYNCING); + + this->command(mtd, FLEXONENAND_CMD_READ_PI, die, 0); + ret = this->wait(mtd, FL_READING); + + bdry = this->read_word(this->base + ONENAND_DATARAM); + if ((bdry >> FLEXONENAND_PI_UNLOCK_SHIFT) == 3) + locked = 0; + else + locked = 1; + this->boundary[die] = bdry & FLEXONENAND_PI_MASK; + + this->command(mtd, ONENAND_CMD_RESET, 0, 0); + ret = this->wait(mtd, FL_RESETING); + + printk(KERN_INFO "Die %d boundary: %d%s\n", die, + this->boundary[die], locked ? "(Locked)" : "(Unlocked)"); + } + + /* Enable ECC */ + this->write_word(syscfg, this->base + ONENAND_REG_SYS_CFG1); + return 0; +} + +/** + * flexonenand_get_size - Fill up fields in onenand_chip and mtd_info + * boundary[], diesize[], mtd->size, mtd->erasesize + * @param mtd - MTD device structure + */ +static void flexonenand_get_size(struct mtd_info *mtd) +{ + struct onenand_chip *this = mtd->priv; + int die, i, eraseshift, density; + int blksperdie, maxbdry; + loff_t ofs; + + density = onenand_get_density(this->device_id); + blksperdie = ((loff_t)(16 << density) << 20) >> (this->erase_shift); + blksperdie >>= ONENAND_IS_DDP(this) ? 1 : 0; + maxbdry = blksperdie - 1; + eraseshift = this->erase_shift - 1; + + mtd->numeraseregions = this->dies << 1; + + /* This fills up the device boundary */ + flexonenand_get_boundary(mtd); + die = ofs = 0; + i = -1; + for (; die < this->dies; die++) { + if (!die || this->boundary[die-1] != maxbdry) { + i++; + mtd->eraseregions[i].offset = ofs; + mtd->eraseregions[i].erasesize = 1 << eraseshift; + mtd->eraseregions[i].numblocks = + this->boundary[die] + 1; + ofs += mtd->eraseregions[i].numblocks << eraseshift; + eraseshift++; + } else { + mtd->numeraseregions -= 1; + mtd->eraseregions[i].numblocks += + this->boundary[die] + 1; + ofs += (this->boundary[die] + 1) << (eraseshift - 1); + } + if (this->boundary[die] != maxbdry) { + i++; + mtd->eraseregions[i].offset = ofs; + mtd->eraseregions[i].erasesize = 1 << eraseshift; + mtd->eraseregions[i].numblocks = maxbdry ^ + this->boundary[die]; + ofs += mtd->eraseregions[i].numblocks << eraseshift; + eraseshift--; + } else + mtd->numeraseregions -= 1; + } + + /* Expose MLC erase size except when all blocks are SLC */ + mtd->erasesize = 1 << this->erase_shift; + if (mtd->numeraseregions == 1) + mtd->erasesize >>= 1; + + printk(KERN_INFO "Device has %d eraseregions\n", mtd->numeraseregions); + for (i = 0; i < mtd->numeraseregions; i++) + printk(KERN_INFO "[offset: 0x%08x, erasesize: 0x%05x," + " numblocks: %04u]\n", + (unsigned int) mtd->eraseregions[i].offset, + mtd->eraseregions[i].erasesize, + mtd->eraseregions[i].numblocks); + + for (die = 0, mtd->size = 0; die < this->dies; die++) { + this->diesize[die] = (loff_t)blksperdie << this->erase_shift; + this->diesize[die] -= (loff_t)(this->boundary[die] + 1) + << (this->erase_shift - 1); + mtd->size += this->diesize[die]; + } +} + +/** + * flexonenand_check_blocks_erased - Check if blocks are erased + * @param mtd_info - mtd info structure + * @param start - first erase block to check + * @param end - last erase block to check + * + * Converting an unerased block from MLC to SLC + * causes byte values to change. Since both data and its ECC + * have changed, reads on the block give uncorrectable error. + * This might lead to the block being detected as bad. + * + * Avoid this by ensuring that the block to be converted is + * erased. + */ +static int flexonenand_check_blocks_erased(struct mtd_info *mtd, int start, int end) +{ + struct onenand_chip *this = mtd->priv; + int i, ret; + int block; + struct mtd_oob_ops ops = { + .mode = MTD_OOB_PLACE, + .ooboffs = 0, + .ooblen = mtd->oobsize, + .datbuf = NULL, + .oobbuf = this->oob_buf, + }; + loff_t addr; + + printk(KERN_DEBUG "Check blocks from %d to %d\n", start, end); + + for (block = start; block <= end; block++) { + addr = flexonenand_addr(this, block); + if (onenand_block_isbad_nolock(mtd, addr, 0)) + continue; + + /* + * Since main area write results in ECC write to spare, + * it is sufficient to check only ECC bytes for change. + */ + ret = onenand_read_oob_nolock(mtd, addr, &ops); + if (ret) + return ret; + + for (i = 0; i < mtd->oobsize; i++) + if (this->oob_buf[i] != 0xff) + break; + + if (i != mtd->oobsize) { + printk(KERN_WARNING "Block %d not erased.\n", block); + return 1; + } + } + + return 0; +} + +/** + * flexonenand_set_boundary - Writes the SLC boundary + * @param mtd - mtd info structure + */ +int flexonenand_set_boundary(struct mtd_info *mtd, int die, + int boundary, int lock) +{ + struct onenand_chip *this = mtd->priv; + int ret, density, blksperdie, old, new, thisboundary; + loff_t addr; + + /* Change only once for SDP Flex-OneNAND */ + if (die && (!ONENAND_IS_DDP(this))) + return 0; + + /* boundary value of -1 indicates no required change */ + if (boundary < 0 || boundary == this->boundary[die]) + return 0; + + density = onenand_get_density(this->device_id); + blksperdie = ((16 << density) << 20) >> this->erase_shift; + blksperdie >>= ONENAND_IS_DDP(this) ? 1 : 0; + + if (boundary >= blksperdie) { + printk(KERN_ERR "flexonenand_set_boundary: Invalid boundary value. " + "Boundary not changed.\n"); + return -EINVAL; + } + + /* Check if converting blocks are erased */ + old = this->boundary[die] + (die * this->density_mask); + new = boundary + (die * this->density_mask); + ret = flexonenand_check_blocks_erased(mtd, min(old, new) + 1, max(old, new)); + if (ret) { + printk(KERN_ERR "flexonenand_set_boundary: Please erase blocks before boundary change\n"); + return ret; + } + + this->command(mtd, FLEXONENAND_CMD_PI_ACCESS, die, 0); + this->wait(mtd, FL_SYNCING); + + /* Check is boundary is locked */ + this->command(mtd, FLEXONENAND_CMD_READ_PI, die, 0); + ret = this->wait(mtd, FL_READING); + + thisboundary = this->read_word(this->base + ONENAND_DATARAM); + if ((thisboundary >> FLEXONENAND_PI_UNLOCK_SHIFT) != 3) { + printk(KERN_ERR "flexonenand_set_boundary: boundary locked\n"); + ret = 1; + goto out; + } + + printk(KERN_INFO "flexonenand_set_boundary: Changing die %d boundary: %d%s\n", + die, boundary, lock ? "(Locked)" : "(Unlocked)"); + + addr = die ? this->diesize[0] : 0; + + boundary &= FLEXONENAND_PI_MASK; + boundary |= lock ? 0 : (3 << FLEXONENAND_PI_UNLOCK_SHIFT); + + this->command(mtd, ONENAND_CMD_ERASE, addr, 0); + ret = this->wait(mtd, FL_ERASING); + if (ret) { + printk(KERN_ERR "flexonenand_set_boundary: Failed PI erase for Die %d\n", die); + goto out; + } + + this->write_word(boundary, this->base + ONENAND_DATARAM); + this->command(mtd, ONENAND_CMD_PROG, addr, 0); + ret = this->wait(mtd, FL_WRITING); + if (ret) { + printk(KERN_ERR "flexonenand_set_boundary: Failed PI write for Die %d\n", die); + goto out; + } + + this->command(mtd, FLEXONENAND_CMD_PI_UPDATE, die, 0); + ret = this->wait(mtd, FL_WRITING); +out: + this->write_word(ONENAND_CMD_RESET, this->base + ONENAND_REG_COMMAND); + this->wait(mtd, FL_RESETING); + if (!ret) + /* Recalculate device size on boundary change*/ + flexonenand_get_size(mtd); + + return ret; +} + /** * onenand_probe - [OneNAND Interface] Probe the OneNAND device * @param mtd MTD device structure @@ -2621,7 +3284,7 @@ static int onenand_probe(struct mtd_info *mtd) /* Save system configuration 1 */ syscfg = this->read_word(this->base + ONENAND_REG_SYS_CFG1); /* Clear Sync. Burst Read mode to read BootRAM */ - this->write_word((syscfg & ~ONENAND_SYS_CFG1_SYNC_READ), this->base + ONENAND_REG_SYS_CFG1); + this->write_word((syscfg & ~ONENAND_SYS_CFG1_SYNC_READ & ~ONENAND_SYS_CFG1_SYNC_WRITE), this->base + ONENAND_REG_SYS_CFG1); /* Send the command for reading device ID from BootRAM */ this->write_word(ONENAND_CMD_READID, this->base + ONENAND_BOOTRAM); @@ -2646,6 +3309,7 @@ static int onenand_probe(struct mtd_info *mtd) maf_id = this->read_word(this->base + ONENAND_REG_MANUFACTURER_ID); dev_id = this->read_word(this->base + ONENAND_REG_DEVICE_ID); ver_id = this->read_word(this->base + ONENAND_REG_VERSION_ID); + this->technology = this->read_word(this->base + ONENAND_REG_TECHNOLOGY); /* Check OneNAND device */ if (maf_id != bram_maf_id || dev_id != bram_dev_id) @@ -2657,29 +3321,55 @@ static int onenand_probe(struct mtd_info *mtd) this->version_id = ver_id; density = onenand_get_density(dev_id); + if (FLEXONENAND(this)) { + this->dies = ONENAND_IS_DDP(this) ? 2 : 1; + /* Maximum possible erase regions */ + mtd->numeraseregions = this->dies << 1; + mtd->eraseregions = kzalloc(sizeof(struct mtd_erase_region_info) + * (this->dies << 1), GFP_KERNEL); + if (!mtd->eraseregions) + return -ENOMEM; + } + + /* + * For Flex-OneNAND, chipsize represents maximum possible device size. + * mtd->size represents the actual device size. + */ this->chipsize = (16 << density) << 20; - /* Set density mask. it is used for DDP */ - if (ONENAND_IS_DDP(this)) - this->density_mask = (1 << (density + 6)); - else - this->density_mask = 0; /* OneNAND page size & block size */ /* The data buffer size is equal to page size */ mtd->writesize = this->read_word(this->base + ONENAND_REG_DATA_BUFFER_SIZE); + /* We use the full BufferRAM */ + if (ONENAND_IS_MLC(this)) + mtd->writesize <<= 1; + mtd->oobsize = mtd->writesize >> 5; /* Pages per a block are always 64 in OneNAND */ mtd->erasesize = mtd->writesize << 6; + /* + * Flex-OneNAND SLC area has 64 pages per block. + * Flex-OneNAND MLC area has 128 pages per block. + * Expose MLC erase size to find erase_shift and page_mask. + */ + if (FLEXONENAND(this)) + mtd->erasesize <<= 1; this->erase_shift = ffs(mtd->erasesize) - 1; this->page_shift = ffs(mtd->writesize) - 1; this->page_mask = (1 << (this->erase_shift - this->page_shift)) - 1; + /* Set density mask. it is used for DDP */ + if (ONENAND_IS_DDP(this)) + this->density_mask = this->chipsize >> (this->erase_shift + 1); /* It's real page size */ this->writesize = mtd->writesize; /* REVIST: Multichip handling */ - mtd->size = this->chipsize; + if (FLEXONENAND(this)) + flexonenand_get_size(mtd); + else + mtd->size = this->chipsize; /* Check OneNAND features */ onenand_check_features(mtd); @@ -2734,7 +3424,7 @@ static void onenand_resume(struct mtd_info *mtd) */ int onenand_scan(struct mtd_info *mtd, int maxchips) { - int i; + int i, ret; struct onenand_chip *this = mtd->priv; if (!this->read_word) @@ -2746,6 +3436,10 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) this->command = onenand_command; if (!this->wait) onenand_setup_wait(mtd); + if (!this->bbt_wait) + this->bbt_wait = onenand_bbt_wait; + if (!this->unlock_all) + this->unlock_all = onenand_unlock_all; if (!this->read_bufferram) this->read_bufferram = onenand_read_bufferram; @@ -2796,6 +3490,10 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) * Allow subpage writes up to oobsize. */ switch (mtd->oobsize) { + case 128: + this->ecclayout = &onenand_oob_128; + mtd->subpage_sft = 0; + break; case 64: this->ecclayout = &onenand_oob_64; mtd->subpage_sft = 2; @@ -2859,9 +3557,18 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) mtd->owner = THIS_MODULE; /* Unlock whole block */ - onenand_unlock_all(mtd); + this->unlock_all(mtd); - return this->scan_bbt(mtd); + ret = this->scan_bbt(mtd); + if ((!FLEXONENAND(this)) || ret) + return ret; + + /* Change Flex-OneNAND boundaries if required */ + for (i = 0; i < MAX_DIES; i++) + flexonenand_set_boundary(mtd, i, flex_bdry[2 * i], + flex_bdry[(2 * i) + 1]); + + return 0; } /** @@ -2890,6 +3597,7 @@ void onenand_release(struct mtd_info *mtd) kfree(this->page_buf); if (this->options & ONENAND_OOBBUF_ALLOC) kfree(this->oob_buf); + kfree(mtd->eraseregions); } EXPORT_SYMBOL_GPL(onenand_scan); diff --git a/drivers/mtd/onenand/onenand_bbt.c b/drivers/mtd/onenand/onenand_bbt.c index 2f53b51c6805..a91fcac1af01 100644 --- a/drivers/mtd/onenand/onenand_bbt.c +++ b/drivers/mtd/onenand/onenand_bbt.c @@ -63,6 +63,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr loff_t from; size_t readlen, ooblen; struct mtd_oob_ops ops; + int rgn; printk(KERN_INFO "Scanning device for bad blocks\n"); @@ -76,7 +77,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr /* Note that numblocks is 2 * (real numblocks) here; * see i += 2 below as it makses shifting and masking less painful */ - numblocks = mtd->size >> (bbm->bbt_erase_shift - 1); + numblocks = this->chipsize >> (bbm->bbt_erase_shift - 1); startblock = 0; from = 0; @@ -106,7 +107,12 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr } } i += 2; - from += (1 << bbm->bbt_erase_shift); + + if (FLEXONENAND(this)) { + rgn = flexonenand_region(mtd, from); + from += mtd->eraseregions[rgn].erasesize; + } else + from += (1 << bbm->bbt_erase_shift); } return 0; @@ -143,7 +149,7 @@ static int onenand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt) uint8_t res; /* Get block number * 2 */ - block = (int) (offs >> (bbm->bbt_erase_shift - 1)); + block = (int) (onenand_block(this, offs) << 1); res = (bbm->bbt[block >> 3] >> (block & 0x06)) & 0x03; DEBUG(MTD_DEBUG_LEVEL2, "onenand_isbad_bbt: bbt info for offs 0x%08x: (block %d) 0x%02x\n", @@ -178,7 +184,7 @@ int onenand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) struct bbm_info *bbm = this->bbm; int len, ret = 0; - len = mtd->size >> (this->erase_shift + 2); + len = this->chipsize >> (this->erase_shift + 2); /* Allocate memory (2bit per block) and clear the memory bad block table */ bbm->bbt = kzalloc(len, GFP_KERNEL); if (!bbm->bbt) { diff --git a/drivers/mtd/onenand/onenand_sim.c b/drivers/mtd/onenand/onenand_sim.c index d64200b7c94b..f6e3c8aebd3a 100644 --- a/drivers/mtd/onenand/onenand_sim.c +++ b/drivers/mtd/onenand/onenand_sim.c @@ -6,6 +6,10 @@ * Copyright © 2005-2007 Samsung Electronics * Kyungmin Park * + * Vishak G , Rohit Hagargundgi + * Flex-OneNAND simulator support + * Copyright (C) Samsung Electronics, 2008 + * * 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. @@ -24,16 +28,38 @@ #ifndef CONFIG_ONENAND_SIM_MANUFACTURER #define CONFIG_ONENAND_SIM_MANUFACTURER 0xec #endif + #ifndef CONFIG_ONENAND_SIM_DEVICE_ID #define CONFIG_ONENAND_SIM_DEVICE_ID 0x04 #endif + +#define CONFIG_FLEXONENAND ((CONFIG_ONENAND_SIM_DEVICE_ID >> 9) & 1) + #ifndef CONFIG_ONENAND_SIM_VERSION_ID #define CONFIG_ONENAND_SIM_VERSION_ID 0x1e #endif +#ifndef CONFIG_ONENAND_SIM_TECHNOLOGY_ID +#define CONFIG_ONENAND_SIM_TECHNOLOGY_ID CONFIG_FLEXONENAND +#endif + +/* Initial boundary values for Flex-OneNAND Simulator */ +#ifndef CONFIG_FLEXONENAND_SIM_DIE0_BOUNDARY +#define CONFIG_FLEXONENAND_SIM_DIE0_BOUNDARY 0x01 +#endif + +#ifndef CONFIG_FLEXONENAND_SIM_DIE1_BOUNDARY +#define CONFIG_FLEXONENAND_SIM_DIE1_BOUNDARY 0x01 +#endif + static int manuf_id = CONFIG_ONENAND_SIM_MANUFACTURER; static int device_id = CONFIG_ONENAND_SIM_DEVICE_ID; static int version_id = CONFIG_ONENAND_SIM_VERSION_ID; +static int technology_id = CONFIG_ONENAND_SIM_TECHNOLOGY_ID; +static int boundary[] = { + CONFIG_FLEXONENAND_SIM_DIE0_BOUNDARY, + CONFIG_FLEXONENAND_SIM_DIE1_BOUNDARY, +}; struct onenand_flash { void __iomem *base; @@ -57,12 +83,18 @@ struct onenand_flash { (writew(v, this->base + ONENAND_REG_WP_STATUS)) /* It has all 0xff chars */ -#define MAX_ONENAND_PAGESIZE (2048 + 64) +#define MAX_ONENAND_PAGESIZE (4096 + 128) static unsigned char *ffchars; +#if CONFIG_FLEXONENAND +#define PARTITION_NAME "Flex-OneNAND simulator partition" +#else +#define PARTITION_NAME "OneNAND simulator partition" +#endif + static struct mtd_partition os_partitions[] = { { - .name = "OneNAND simulator partition", + .name = PARTITION_NAME, .offset = 0, .size = MTDPART_SIZ_FULL, }, @@ -104,6 +136,7 @@ static void onenand_lock_handle(struct onenand_chip *this, int cmd) switch (cmd) { case ONENAND_CMD_UNLOCK: + case ONENAND_CMD_UNLOCK_ALL: if (block_lock_scheme) ONENAND_SET_WP_STATUS(ONENAND_WP_US, this); else @@ -228,10 +261,12 @@ static void onenand_data_handle(struct onenand_chip *this, int cmd, { struct mtd_info *mtd = &info->mtd; struct onenand_flash *flash = this->priv; - int main_offset, spare_offset; + int main_offset, spare_offset, die = 0; void __iomem *src; void __iomem *dest; unsigned int i; + static int pi_operation; + int erasesize, rgn; if (dataram) { main_offset = mtd->writesize; @@ -241,10 +276,27 @@ static void onenand_data_handle(struct onenand_chip *this, int cmd, spare_offset = 0; } + if (pi_operation) { + die = readw(this->base + ONENAND_REG_START_ADDRESS2); + die >>= ONENAND_DDP_SHIFT; + } + switch (cmd) { + case FLEXONENAND_CMD_PI_ACCESS: + pi_operation = 1; + break; + + case ONENAND_CMD_RESET: + pi_operation = 0; + break; + case ONENAND_CMD_READ: src = ONENAND_CORE(flash) + offset; dest = ONENAND_MAIN_AREA(this, main_offset); + if (pi_operation) { + writew(boundary[die], this->base + ONENAND_DATARAM); + break; + } memcpy(dest, src, mtd->writesize); /* Fall through */ @@ -257,6 +309,10 @@ static void onenand_data_handle(struct onenand_chip *this, int cmd, case ONENAND_CMD_PROG: src = ONENAND_MAIN_AREA(this, main_offset); dest = ONENAND_CORE(flash) + offset; + if (pi_operation) { + boundary[die] = readw(this->base + ONENAND_DATARAM); + break; + } /* To handle partial write */ for (i = 0; i < (1 << mtd->subpage_sft); i++) { int off = i * this->subpagesize; @@ -284,9 +340,18 @@ static void onenand_data_handle(struct onenand_chip *this, int cmd, break; case ONENAND_CMD_ERASE: - memset(ONENAND_CORE(flash) + offset, 0xff, mtd->erasesize); + if (pi_operation) + break; + + if (FLEXONENAND(this)) { + rgn = flexonenand_region(mtd, offset); + erasesize = mtd->eraseregions[rgn].erasesize; + } else + erasesize = mtd->erasesize; + + memset(ONENAND_CORE(flash) + offset, 0xff, erasesize); memset(ONENAND_CORE_SPARE(flash, this, offset), 0xff, - (mtd->erasesize >> 5)); + (erasesize >> 5)); break; default: @@ -339,7 +404,7 @@ static void onenand_command_handle(struct onenand_chip *this, int cmd) } if (block != -1) - offset += block << this->erase_shift; + offset = onenand_addr(this, block); if (page != -1) offset += page << this->page_shift; @@ -390,6 +455,7 @@ static int __init flash_init(struct onenand_flash *flash) } density = device_id >> ONENAND_DEVICE_DENSITY_SHIFT; + density &= ONENAND_DEVICE_DENSITY_MASK; size = ((16 << 20) << density); ONENAND_CORE(flash) = vmalloc(size + (size >> 5)); @@ -405,8 +471,9 @@ static int __init flash_init(struct onenand_flash *flash) writew(manuf_id, flash->base + ONENAND_REG_MANUFACTURER_ID); writew(device_id, flash->base + ONENAND_REG_DEVICE_ID); writew(version_id, flash->base + ONENAND_REG_VERSION_ID); + writew(technology_id, flash->base + ONENAND_REG_TECHNOLOGY); - if (density < 2) + if (density < 2 && (!CONFIG_FLEXONENAND)) buffer_size = 0x0400; /* 1KiB page */ else buffer_size = 0x0800; /* 2KiB page */ diff --git a/drivers/mtd/ubi/Kconfig b/drivers/mtd/ubi/Kconfig index 3f063108e95f..b1cd7a1a2191 100644 --- a/drivers/mtd/ubi/Kconfig +++ b/drivers/mtd/ubi/Kconfig @@ -49,15 +49,16 @@ config MTD_UBI_BEB_RESERVE reserved. Leave the default value if unsure. config MTD_UBI_GLUEBI - bool "Emulate MTD devices" + tristate "MTD devices emulation driver (gluebi)" default n depends on MTD_UBI help - This option enables MTD devices emulation on top of UBI volumes: for - each UBI volumes an MTD device is created, and all I/O to this MTD - device is redirected to the UBI volume. This is handy to make - MTD-oriented software (like JFFS2) work on top of UBI. Do not enable - this if no legacy software will be used. + This option enables gluebi - an additional driver which emulates MTD + devices on top of UBI volumes: for each UBI volumes an MTD device is + created, and all I/O to this MTD device is redirected to the UBI + volume. This is handy to make MTD-oriented software (like JFFS2) + work on top of UBI. Do not enable this unless you use legacy + software. source "drivers/mtd/ubi/Kconfig.debug" endmenu diff --git a/drivers/mtd/ubi/Makefile b/drivers/mtd/ubi/Makefile index dd834e04151b..c9302a5452b0 100644 --- a/drivers/mtd/ubi/Makefile +++ b/drivers/mtd/ubi/Makefile @@ -4,4 +4,4 @@ ubi-y += vtbl.o vmt.o upd.o build.o cdev.o kapi.o eba.o io.o wl.o scan.o ubi-y += misc.o ubi-$(CONFIG_MTD_UBI_DEBUG) += debug.o -ubi-$(CONFIG_MTD_UBI_GLUEBI) += gluebi.o +obj-$(CONFIG_MTD_UBI_GLUEBI) += gluebi.o diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 4048db83aef6..286ed594e5a0 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -41,6 +41,7 @@ #include #include #include +#include #include "ubi.h" /* Maximum length of the 'mtd=' parameter */ @@ -121,6 +122,94 @@ static struct device_attribute dev_bgt_enabled = static struct device_attribute dev_mtd_num = __ATTR(mtd_num, S_IRUGO, dev_attribute_show, NULL); +/** + * ubi_volume_notify - send a volume change notification. + * @ubi: UBI device description object + * @vol: volume description object of the changed volume + * @ntype: notification type to send (%UBI_VOLUME_ADDED, etc) + * + * This is a helper function which notifies all subscribers about a volume + * change event (creation, removal, re-sizing, re-naming, updating). Returns + * zero in case of success and a negative error code in case of failure. + */ +int ubi_volume_notify(struct ubi_device *ubi, struct ubi_volume *vol, int ntype) +{ + struct ubi_notification nt; + + ubi_do_get_device_info(ubi, &nt.di); + ubi_do_get_volume_info(ubi, vol, &nt.vi); + return blocking_notifier_call_chain(&ubi_notifiers, ntype, &nt); +} + +/** + * ubi_notify_all - send a notification to all volumes. + * @ubi: UBI device description object + * @ntype: notification type to send (%UBI_VOLUME_ADDED, etc) + * @nb: the notifier to call + * + * This function walks all volumes of UBI device @ubi and sends the @ntype + * notification for each volume. If @nb is %NULL, then all registered notifiers + * are called, otherwise only the @nb notifier is called. Returns the number of + * sent notifications. + */ +int ubi_notify_all(struct ubi_device *ubi, int ntype, struct notifier_block *nb) +{ + struct ubi_notification nt; + int i, count = 0; + + ubi_do_get_device_info(ubi, &nt.di); + + mutex_lock(&ubi->device_mutex); + for (i = 0; i < ubi->vtbl_slots; i++) { + /* + * Since the @ubi->device is locked, and we are not going to + * change @ubi->volumes, we do not have to lock + * @ubi->volumes_lock. + */ + if (!ubi->volumes[i]) + continue; + + ubi_do_get_volume_info(ubi, ubi->volumes[i], &nt.vi); + if (nb) + nb->notifier_call(nb, ntype, &nt); + else + blocking_notifier_call_chain(&ubi_notifiers, ntype, + &nt); + count += 1; + } + mutex_unlock(&ubi->device_mutex); + + return count; +} + +/** + * ubi_enumerate_volumes - send "add" notification for all existing volumes. + * @nb: the notifier to call + * + * This function walks all UBI devices and volumes and sends the + * %UBI_VOLUME_ADDED notification for each volume. If @nb is %NULL, then all + * registered notifiers are called, otherwise only the @nb notifier is called. + * Returns the number of sent notifications. + */ +int ubi_enumerate_volumes(struct notifier_block *nb) +{ + int i, count = 0; + + /* + * Since the @ubi_devices_mutex is locked, and we are not going to + * change @ubi_devices, we do not have to lock @ubi_devices_lock. + */ + for (i = 0; i < UBI_MAX_DEVICES; i++) { + struct ubi_device *ubi = ubi_devices[i]; + + if (!ubi) + continue; + count += ubi_notify_all(ubi, UBI_VOLUME_ADDED, nb); + } + + return count; +} + /** * ubi_get_device - get UBI device. * @ubi_num: UBI device number @@ -380,7 +469,7 @@ static void free_user_volumes(struct ubi_device *ubi) * @ubi: UBI device description object * * This function returns zero in case of success and a negative error code in - * case of failure. Note, this function destroys all volumes if it failes. + * case of failure. Note, this function destroys all volumes if it fails. */ static int uif_init(struct ubi_device *ubi) { @@ -632,6 +721,15 @@ static int io_init(struct ubi_device *ubi) return -EINVAL; } + /* + * Set maximum amount of physical erroneous eraseblocks to be 10%. + * Erroneous PEB are those which have read errors. + */ + ubi->max_erroneous = ubi->peb_count / 10; + if (ubi->max_erroneous < 16) + ubi->max_erroneous = 16; + dbg_msg("max_erroneous %d", ubi->max_erroneous); + /* * It may happen that EC and VID headers are situated in one minimal * I/O unit. In this case we can only accept this UBI image in @@ -725,6 +823,34 @@ static int autoresize(struct ubi_device *ubi, int vol_id) return 0; } +/** + * ubi_reboot_notifier - halt UBI transactions immediately prior to a reboot. + * @n: reboot notifier object + * @state: SYS_RESTART, SYS_HALT, or SYS_POWER_OFF + * @cmd: pointer to command string for RESTART2 + * + * This function stops the UBI background thread so that the flash device + * remains quiescent when Linux restarts the system. Any queued work will be + * discarded, but this function will block until do_work() finishes if an + * operation is already in progress. + * + * This function solves a real-life problem observed on NOR flashes when an + * PEB erase operation starts, then the system is rebooted before the erase is + * finishes, and the boot loader gets confused and dies. So we prefer to finish + * the ongoing operation before rebooting. + */ +static int ubi_reboot_notifier(struct notifier_block *n, unsigned long state, + void *cmd) +{ + struct ubi_device *ubi; + + ubi = container_of(n, struct ubi_device, reboot_notifier); + if (ubi->bgt_thread) + kthread_stop(ubi->bgt_thread); + ubi_sync(ubi->ubi_num); + return NOTIFY_DONE; +} + /** * ubi_attach_mtd_dev - attach an MTD device. * @mtd: MTD device description object @@ -806,8 +932,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset) mutex_init(&ubi->buf_mutex); mutex_init(&ubi->ckvol_mutex); - mutex_init(&ubi->mult_mutex); - mutex_init(&ubi->volumes_mutex); + mutex_init(&ubi->device_mutex); spin_lock_init(&ubi->volumes_lock); ubi_msg("attaching mtd%d to ubi%d", mtd->index, ubi_num); @@ -825,7 +950,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset) if (!ubi->peb_buf2) goto out_free; -#ifdef CONFIG_MTD_UBI_DEBUG +#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID mutex_init(&ubi->dbg_buf_mutex); ubi->dbg_peb_buf = vmalloc(ubi->peb_size); if (!ubi->dbg_peb_buf) @@ -872,11 +997,23 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset) ubi->beb_rsvd_pebs); ubi_msg("max/mean erase counter: %d/%d", ubi->max_ec, ubi->mean_ec); + /* + * The below lock makes sure we do not race with 'ubi_thread()' which + * checks @ubi->thread_enabled. Otherwise we may fail to wake it up. + */ + spin_lock(&ubi->wl_lock); if (!DBG_DISABLE_BGT) ubi->thread_enabled = 1; wake_up_process(ubi->bgt_thread); + spin_unlock(&ubi->wl_lock); + + /* Flash device priority is 0 - UBI needs to shut down first */ + ubi->reboot_notifier.priority = 1; + ubi->reboot_notifier.notifier_call = ubi_reboot_notifier; + register_reboot_notifier(&ubi->reboot_notifier); ubi_devices[ubi_num] = ubi; + ubi_notify_all(ubi, UBI_VOLUME_ADDED, NULL); return ubi_num; out_uif: @@ -892,7 +1029,7 @@ out_detach: out_free: vfree(ubi->peb_buf1); vfree(ubi->peb_buf2); -#ifdef CONFIG_MTD_UBI_DEBUG +#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID vfree(ubi->dbg_peb_buf); #endif kfree(ubi); @@ -919,13 +1056,13 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway) if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES) return -EINVAL; - spin_lock(&ubi_devices_lock); - ubi = ubi_devices[ubi_num]; - if (!ubi) { - spin_unlock(&ubi_devices_lock); + ubi = ubi_get_device(ubi_num); + if (!ubi) return -EINVAL; - } + spin_lock(&ubi_devices_lock); + put_device(&ubi->dev); + ubi->ref_count -= 1; if (ubi->ref_count) { if (!anyway) { spin_unlock(&ubi_devices_lock); @@ -939,12 +1076,14 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway) spin_unlock(&ubi_devices_lock); ubi_assert(ubi_num == ubi->ubi_num); + ubi_notify_all(ubi, UBI_VOLUME_REMOVED, NULL); dbg_msg("detaching mtd%d from ubi%d", ubi->mtd->index, ubi_num); /* * Before freeing anything, we have to stop the background thread to * prevent it from doing anything on this device while we are freeing. */ + unregister_reboot_notifier(&ubi->reboot_notifier); if (ubi->bgt_thread) kthread_stop(ubi->bgt_thread); @@ -961,7 +1100,7 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway) put_mtd_device(ubi->mtd); vfree(ubi->peb_buf1); vfree(ubi->peb_buf2); -#ifdef CONFIG_MTD_UBI_DEBUG +#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID vfree(ubi->dbg_peb_buf); #endif ubi_msg("mtd%d is detached from ubi%d", ubi->mtd->index, ubi->ubi_num); diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c index f8e0f68f2186..f237ddbb2713 100644 --- a/drivers/mtd/ubi/cdev.c +++ b/drivers/mtd/ubi/cdev.c @@ -113,7 +113,8 @@ static int vol_cdev_open(struct inode *inode, struct file *file) else mode = UBI_READONLY; - dbg_gen("open volume %d, mode %d", vol_id, mode); + dbg_gen("open device %d, volume %d, mode %d", + ubi_num, vol_id, mode); desc = ubi_open_volume(ubi_num, vol_id, mode); if (IS_ERR(desc)) @@ -128,7 +129,8 @@ static int vol_cdev_release(struct inode *inode, struct file *file) struct ubi_volume_desc *desc = file->private_data; struct ubi_volume *vol = desc->vol; - dbg_gen("release volume %d, mode %d", vol->vol_id, desc->mode); + dbg_gen("release device %d, volume %d, mode %d", + vol->ubi->ubi_num, vol->vol_id, desc->mode); if (vol->updating) { ubi_warn("update of volume %d not finished, volume is damaged", @@ -393,7 +395,7 @@ static ssize_t vol_cdev_write(struct file *file, const char __user *buf, vol->corrupted = 1; } vol->checked = 1; - ubi_gluebi_updated(vol); + ubi_volume_notify(ubi, vol, UBI_VOLUME_UPDATED); revoke_exclusive(desc, UBI_READWRITE); } @@ -558,7 +560,7 @@ static long vol_cdev_ioctl(struct file *file, unsigned int cmd, break; } - /* Set volume property command*/ + /* Set volume property command */ case UBI_IOCSETPROP: { struct ubi_set_prop_req req; @@ -571,9 +573,9 @@ static long vol_cdev_ioctl(struct file *file, unsigned int cmd, } switch (req.property) { case UBI_PROP_DIRECT_WRITE: - mutex_lock(&ubi->volumes_mutex); + mutex_lock(&ubi->device_mutex); desc->vol->direct_writes = !!req.value; - mutex_unlock(&ubi->volumes_mutex); + mutex_unlock(&ubi->device_mutex); break; default: err = -EINVAL; @@ -810,9 +812,9 @@ static int rename_volumes(struct ubi_device *ubi, re->desc->vol->vol_id, re->desc->vol->name); } - mutex_lock(&ubi->volumes_mutex); + mutex_lock(&ubi->device_mutex); err = ubi_rename_volumes(ubi, &rename_list); - mutex_unlock(&ubi->volumes_mutex); + mutex_unlock(&ubi->device_mutex); out_free: list_for_each_entry_safe(re, re1, &rename_list, list) { @@ -856,9 +858,9 @@ static long ubi_cdev_ioctl(struct file *file, unsigned int cmd, if (err) break; - mutex_lock(&ubi->volumes_mutex); + mutex_lock(&ubi->device_mutex); err = ubi_create_volume(ubi, &req); - mutex_unlock(&ubi->volumes_mutex); + mutex_unlock(&ubi->device_mutex); if (err) break; @@ -887,9 +889,9 @@ static long ubi_cdev_ioctl(struct file *file, unsigned int cmd, break; } - mutex_lock(&ubi->volumes_mutex); + mutex_lock(&ubi->device_mutex); err = ubi_remove_volume(desc, 0); - mutex_unlock(&ubi->volumes_mutex); + mutex_unlock(&ubi->device_mutex); /* * The volume is deleted (unless an error occurred), and the @@ -926,9 +928,9 @@ static long ubi_cdev_ioctl(struct file *file, unsigned int cmd, pebs = div_u64(req.bytes + desc->vol->usable_leb_size - 1, desc->vol->usable_leb_size); - mutex_lock(&ubi->volumes_mutex); + mutex_lock(&ubi->device_mutex); err = ubi_resize_volume(desc, pebs); - mutex_unlock(&ubi->volumes_mutex); + mutex_unlock(&ubi->device_mutex); ubi_close_volume(desc); break; } @@ -952,9 +954,7 @@ static long ubi_cdev_ioctl(struct file *file, unsigned int cmd, break; } - mutex_lock(&ubi->mult_mutex); err = rename_volumes(ubi, req); - mutex_unlock(&ubi->mult_mutex); kfree(req); break; } diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index 25def348e5ba..0f2034c3ed2f 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c @@ -419,8 +419,9 @@ retry: * not implemented. */ if (err == UBI_IO_BAD_VID_HDR) { - ubi_warn("bad VID header at PEB %d, LEB" - "%d:%d", pnum, vol_id, lnum); + ubi_warn("corrupted VID header at PEB " + "%d, LEB %d:%d", pnum, vol_id, + lnum); err = -EBADMSG; } else ubi_ro_mode(ubi); @@ -939,6 +940,33 @@ write_error: goto retry; } +/** + * is_error_sane - check whether a read error is sane. + * @err: code of the error happened during reading + * + * This is a helper function for 'ubi_eba_copy_leb()' which is called when we + * cannot read data from the target PEB (an error @err happened). If the error + * code is sane, then we treat this error as non-fatal. Otherwise the error is + * fatal and UBI will be switched to R/O mode later. + * + * The idea is that we try not to switch to R/O mode if the read error is + * something which suggests there was a real read problem. E.g., %-EIO. Or a + * memory allocation failed (-%ENOMEM). Otherwise, it is safer to switch to R/O + * mode, simply because we do not know what happened at the MTD level, and we + * cannot handle this. E.g., the underlying driver may have become crazy, and + * it is safer to switch to R/O mode to preserve the data. + * + * And bear in mind, this is about reading from the target PEB, i.e. the PEB + * which we have just written. + */ +static int is_error_sane(int err) +{ + if (err == -EIO || err == -ENOMEM || err == UBI_IO_BAD_VID_HDR || + err == -ETIMEDOUT) + return 0; + return 1; +} + /** * ubi_eba_copy_leb - copy logical eraseblock. * @ubi: UBI device description object @@ -950,12 +978,7 @@ write_error: * physical eraseblock @to. The @vid_hdr buffer may be changed by this * function. Returns: * o %0 in case of success; - * o %1 if the operation was canceled because the volume is being deleted - * or because the PEB was put meanwhile; - * o %2 if the operation was canceled because there was a write error to the - * target PEB; - * o %-EAGAIN if the operation was canceled because a bit-flip was detected - * in the target PEB; + * o %MOVE_CANCEL_RACE, %MOVE_TARGET_WR_ERR, %MOVE_CANCEL_BITFLIPS, etc; * o a negative error code in case of failure. */ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, @@ -968,7 +991,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, vol_id = be32_to_cpu(vid_hdr->vol_id); lnum = be32_to_cpu(vid_hdr->lnum); - dbg_eba("copy LEB %d:%d, PEB %d to PEB %d", vol_id, lnum, from, to); + dbg_wl("copy LEB %d:%d, PEB %d to PEB %d", vol_id, lnum, from, to); if (vid_hdr->vol_type == UBI_VID_STATIC) { data_size = be32_to_cpu(vid_hdr->data_size); @@ -986,13 +1009,12 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, * be locked in 'ubi_wl_put_peb()' and wait for the WL worker to finish. */ vol = ubi->volumes[idx]; + spin_unlock(&ubi->volumes_lock); if (!vol) { /* No need to do further work, cancel */ - dbg_eba("volume %d is being removed, cancel", vol_id); - spin_unlock(&ubi->volumes_lock); - return 1; + dbg_wl("volume %d is being removed, cancel", vol_id); + return MOVE_CANCEL_RACE; } - spin_unlock(&ubi->volumes_lock); /* * We do not want anybody to write to this logical eraseblock while we @@ -1004,12 +1026,13 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, * (@from). This task locks the LEB and goes sleep in the * 'ubi_wl_put_peb()' function on the @ubi->move_mutex. In turn, we are * holding @ubi->move_mutex and go sleep on the LEB lock. So, if the - * LEB is already locked, we just do not move it and return %1. + * LEB is already locked, we just do not move it and return + * %MOVE_CANCEL_RACE, which means that UBI will re-try, but later. */ err = leb_write_trylock(ubi, vol_id, lnum); if (err) { - dbg_eba("contention on LEB %d:%d, cancel", vol_id, lnum); - return err; + dbg_wl("contention on LEB %d:%d, cancel", vol_id, lnum); + return MOVE_CANCEL_RACE; } /* @@ -1018,25 +1041,26 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, * cancel it. */ if (vol->eba_tbl[lnum] != from) { - dbg_eba("LEB %d:%d is no longer mapped to PEB %d, mapped to " - "PEB %d, cancel", vol_id, lnum, from, - vol->eba_tbl[lnum]); - err = 1; + dbg_wl("LEB %d:%d is no longer mapped to PEB %d, mapped to " + "PEB %d, cancel", vol_id, lnum, from, + vol->eba_tbl[lnum]); + err = MOVE_CANCEL_RACE; goto out_unlock_leb; } /* * OK, now the LEB is locked and we can safely start moving it. Since - * this function utilizes the @ubi->peb1_buf buffer which is shared - * with some other functions, so lock the buffer by taking the + * this function utilizes the @ubi->peb_buf1 buffer which is shared + * with some other functions - we lock the buffer by taking the * @ubi->buf_mutex. */ mutex_lock(&ubi->buf_mutex); - dbg_eba("read %d bytes of data", aldata_size); + dbg_wl("read %d bytes of data", aldata_size); err = ubi_io_read_data(ubi, ubi->peb_buf1, from, 0, aldata_size); if (err && err != UBI_IO_BITFLIPS) { ubi_warn("error %d while reading data from PEB %d", err, from); + err = MOVE_SOURCE_RD_ERR; goto out_unlock_buf; } @@ -1059,7 +1083,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, cond_resched(); /* - * It may turn out to me that the whole @from physical eraseblock + * It may turn out to be that the whole @from physical eraseblock * contains only 0xFF bytes. Then we have to only write the VID header * and do not write any data. This also means we should not set * @vid_hdr->copy_flag, @vid_hdr->data_size, and @vid_hdr->data_crc. @@ -1074,7 +1098,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, err = ubi_io_write_vid_hdr(ubi, to, vid_hdr); if (err) { if (err == -EIO) - err = 2; + err = MOVE_TARGET_WR_ERR; goto out_unlock_buf; } @@ -1083,10 +1107,13 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, /* Read the VID header back and check if it was written correctly */ err = ubi_io_read_vid_hdr(ubi, to, vid_hdr, 1); if (err) { - if (err != UBI_IO_BITFLIPS) - ubi_warn("cannot read VID header back from PEB %d", to); - else - err = -EAGAIN; + if (err != UBI_IO_BITFLIPS) { + ubi_warn("error %d while reading VID header back from " + "PEB %d", err, to); + if (is_error_sane(err)) + err = MOVE_TARGET_RD_ERR; + } else + err = MOVE_CANCEL_BITFLIPS; goto out_unlock_buf; } @@ -1094,7 +1121,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, err = ubi_io_write_data(ubi, ubi->peb_buf1, to, 0, aldata_size); if (err) { if (err == -EIO) - err = 2; + err = MOVE_TARGET_WR_ERR; goto out_unlock_buf; } @@ -1107,11 +1134,13 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, err = ubi_io_read_data(ubi, ubi->peb_buf2, to, 0, aldata_size); if (err) { - if (err != UBI_IO_BITFLIPS) - ubi_warn("cannot read data back from PEB %d", - to); - else - err = -EAGAIN; + if (err != UBI_IO_BITFLIPS) { + ubi_warn("error %d while reading data back " + "from PEB %d", err, to); + if (is_error_sane(err)) + err = MOVE_TARGET_RD_ERR; + } else + err = MOVE_CANCEL_BITFLIPS; goto out_unlock_buf; } diff --git a/drivers/mtd/ubi/gluebi.c b/drivers/mtd/ubi/gluebi.c index 49cd55ade9c8..95aaac03f938 100644 --- a/drivers/mtd/ubi/gluebi.c +++ b/drivers/mtd/ubi/gluebi.c @@ -19,17 +19,71 @@ */ /* - * This file includes implementation of fake MTD devices for each UBI volume. - * This sounds strange, but it is in fact quite useful to make MTD-oriented - * software (including all the legacy software) to work on top of UBI. + * This is a small driver which implements fake MTD devices on top of UBI + * volumes. This sounds strange, but it is in fact quite useful to make + * MTD-oriented software (including all the legacy software) work on top of + * UBI. * * Gluebi emulates MTD devices of "MTD_UBIVOLUME" type. Their minimal I/O unit - * size (mtd->writesize) is equivalent to the UBI minimal I/O unit. The + * size (@mtd->writesize) is equivalent to the UBI minimal I/O unit. The * eraseblock size is equivalent to the logical eraseblock size of the volume. */ +#include +#include +#include #include -#include "ubi.h" +#include +#include +#include +#include +#include "ubi-media.h" + +#define err_msg(fmt, ...) \ + printk(KERN_DEBUG "gluebi (pid %d): %s: " fmt "\n", \ + current->pid, __func__, ##__VA_ARGS__) + +/** + * struct gluebi_device - a gluebi device description data structure. + * @mtd: emulated MTD device description object + * @refcnt: gluebi device reference count + * @desc: UBI volume descriptor + * @ubi_num: UBI device number this gluebi device works on + * @vol_id: ID of UBI volume this gluebi device works on + * @list: link in a list of gluebi devices + */ +struct gluebi_device { + struct mtd_info mtd; + int refcnt; + struct ubi_volume_desc *desc; + int ubi_num; + int vol_id; + struct list_head list; +}; + +/* List of all gluebi devices */ +static LIST_HEAD(gluebi_devices); +static DEFINE_MUTEX(devices_mutex); + +/** + * find_gluebi_nolock - find a gluebi device. + * @ubi_num: UBI device number + * @vol_id: volume ID + * + * This function seraches for gluebi device corresponding to UBI device + * @ubi_num and UBI volume @vol_id. Returns the gluebi device description + * object in case of success and %NULL in case of failure. The caller has to + * have the &devices_mutex locked. + */ +static struct gluebi_device *find_gluebi_nolock(int ubi_num, int vol_id) +{ + struct gluebi_device *gluebi; + + list_for_each_entry(gluebi, &gluebi_devices, list) + if (gluebi->ubi_num == ubi_num && gluebi->vol_id == vol_id) + return gluebi; + return NULL; +} /** * gluebi_get_device - get MTD device reference. @@ -41,15 +95,18 @@ */ static int gluebi_get_device(struct mtd_info *mtd) { - struct ubi_volume *vol; + struct gluebi_device *gluebi; + int ubi_mode = UBI_READONLY; - vol = container_of(mtd, struct ubi_volume, gluebi_mtd); + if (!try_module_get(THIS_MODULE)) + return -ENODEV; - /* - * We do not introduce locks for gluebi reference count because the - * get_device()/put_device() calls are already serialized at MTD. - */ - if (vol->gluebi_refcount > 0) { + if (mtd->flags & MTD_WRITEABLE) + ubi_mode = UBI_READWRITE; + + gluebi = container_of(mtd, struct gluebi_device, mtd); + mutex_lock(&devices_mutex); + if (gluebi->refcnt > 0) { /* * The MTD device is already referenced and this is just one * more reference. MTD allows many users to open the same @@ -58,7 +115,8 @@ static int gluebi_get_device(struct mtd_info *mtd) * open the UBI volume again - just increase the reference * counter and return. */ - vol->gluebi_refcount += 1; + gluebi->refcnt += 1; + mutex_unlock(&devices_mutex); return 0; } @@ -66,11 +124,15 @@ static int gluebi_get_device(struct mtd_info *mtd) * This is the first reference to this UBI volume via the MTD device * interface. Open the corresponding volume in read-write mode. */ - vol->gluebi_desc = ubi_open_volume(vol->ubi->ubi_num, vol->vol_id, - UBI_READWRITE); - if (IS_ERR(vol->gluebi_desc)) - return PTR_ERR(vol->gluebi_desc); - vol->gluebi_refcount += 1; + gluebi->desc = ubi_open_volume(gluebi->ubi_num, gluebi->vol_id, + ubi_mode); + if (IS_ERR(gluebi->desc)) { + mutex_unlock(&devices_mutex); + module_put(THIS_MODULE); + return PTR_ERR(gluebi->desc); + } + gluebi->refcnt += 1; + mutex_unlock(&devices_mutex); return 0; } @@ -83,13 +145,15 @@ static int gluebi_get_device(struct mtd_info *mtd) */ static void gluebi_put_device(struct mtd_info *mtd) { - struct ubi_volume *vol; + struct gluebi_device *gluebi; - vol = container_of(mtd, struct ubi_volume, gluebi_mtd); - vol->gluebi_refcount -= 1; - ubi_assert(vol->gluebi_refcount >= 0); - if (vol->gluebi_refcount == 0) - ubi_close_volume(vol->gluebi_desc); + gluebi = container_of(mtd, struct gluebi_device, mtd); + mutex_lock(&devices_mutex); + gluebi->refcnt -= 1; + if (gluebi->refcnt == 0) + ubi_close_volume(gluebi->desc); + module_put(THIS_MODULE); + mutex_unlock(&devices_mutex); } /** @@ -107,16 +171,12 @@ static int gluebi_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, unsigned char *buf) { int err = 0, lnum, offs, total_read; - struct ubi_volume *vol; - struct ubi_device *ubi; - - dbg_gen("read %zd bytes from offset %lld", len, from); + struct gluebi_device *gluebi; if (len < 0 || from < 0 || from + len > mtd->size) return -EINVAL; - vol = container_of(mtd, struct ubi_volume, gluebi_mtd); - ubi = vol->ubi; + gluebi = container_of(mtd, struct gluebi_device, mtd); lnum = div_u64_rem(from, mtd->erasesize, &offs); total_read = len; @@ -126,7 +186,7 @@ static int gluebi_read(struct mtd_info *mtd, loff_t from, size_t len, if (to_read > total_read) to_read = total_read; - err = ubi_eba_read_leb(ubi, vol, lnum, buf, offs, to_read, 0); + err = ubi_read(gluebi->desc, lnum, buf, offs, to_read); if (err) break; @@ -152,21 +212,17 @@ static int gluebi_read(struct mtd_info *mtd, loff_t from, size_t len, * case of failure. */ static int gluebi_write(struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const u_char *buf) + size_t *retlen, const u_char *buf) { int err = 0, lnum, offs, total_written; - struct ubi_volume *vol; - struct ubi_device *ubi; - - dbg_gen("write %zd bytes to offset %lld", len, to); + struct gluebi_device *gluebi; if (len < 0 || to < 0 || len + to > mtd->size) return -EINVAL; - vol = container_of(mtd, struct ubi_volume, gluebi_mtd); - ubi = vol->ubi; + gluebi = container_of(mtd, struct gluebi_device, mtd); - if (ubi->ro_mode) + if (!(mtd->flags & MTD_WRITEABLE)) return -EROFS; lnum = div_u64_rem(to, mtd->erasesize, &offs); @@ -181,8 +237,7 @@ static int gluebi_write(struct mtd_info *mtd, loff_t to, size_t len, if (to_write > total_written) to_write = total_written; - err = ubi_eba_write_leb(ubi, vol, lnum, buf, offs, to_write, - UBI_UNKNOWN); + err = ubi_write(gluebi->desc, lnum, buf, offs, to_write); if (err) break; @@ -207,41 +262,36 @@ static int gluebi_write(struct mtd_info *mtd, loff_t to, size_t len, static int gluebi_erase(struct mtd_info *mtd, struct erase_info *instr) { int err, i, lnum, count; - struct ubi_volume *vol; - struct ubi_device *ubi; - - dbg_gen("erase %llu bytes at offset %llu", (unsigned long long)instr->len, - (unsigned long long)instr->addr); + struct gluebi_device *gluebi; if (instr->addr < 0 || instr->addr > mtd->size - mtd->erasesize) return -EINVAL; - if (instr->len < 0 || instr->addr + instr->len > mtd->size) return -EINVAL; - if (mtd_mod_by_ws(instr->addr, mtd) || mtd_mod_by_ws(instr->len, mtd)) return -EINVAL; lnum = mtd_div_by_eb(instr->addr, mtd); count = mtd_div_by_eb(instr->len, mtd); - vol = container_of(mtd, struct ubi_volume, gluebi_mtd); - ubi = vol->ubi; + gluebi = container_of(mtd, struct gluebi_device, mtd); - if (ubi->ro_mode) + if (!(mtd->flags & MTD_WRITEABLE)) return -EROFS; - for (i = 0; i < count; i++) { - err = ubi_eba_unmap_leb(ubi, vol, lnum + i); + for (i = 0; i < count - 1; i++) { + err = ubi_leb_unmap(gluebi->desc, lnum + i); if (err) goto out_err; } - /* * MTD erase operations are synchronous, so we have to make sure the * physical eraseblock is wiped out. + * + * Thus, perform leb_erase instead of leb_unmap operation - leb_erase + * will wait for the end of operations */ - err = ubi_wl_flush(ubi); + err = ubi_leb_erase(gluebi->desc, lnum + i); if (err) goto out_err; @@ -256,28 +306,38 @@ out_err: } /** - * ubi_create_gluebi - initialize gluebi for an UBI volume. - * @ubi: UBI device description object - * @vol: volume description object + * gluebi_create - create a gluebi device for an UBI volume. + * @di: UBI device description object + * @vi: UBI volume description object * - * This function is called when an UBI volume is created in order to create + * This function is called when a new UBI volume is created in order to create * corresponding fake MTD device. Returns zero in case of success and a * negative error code in case of failure. */ -int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol) +static int gluebi_create(struct ubi_device_info *di, + struct ubi_volume_info *vi) { - struct mtd_info *mtd = &vol->gluebi_mtd; + struct gluebi_device *gluebi, *g; + struct mtd_info *mtd; - mtd->name = kmemdup(vol->name, vol->name_len + 1, GFP_KERNEL); - if (!mtd->name) + gluebi = kzalloc(sizeof(struct gluebi_device), GFP_KERNEL); + if (!gluebi) return -ENOMEM; + mtd = &gluebi->mtd; + mtd->name = kmemdup(vi->name, vi->name_len + 1, GFP_KERNEL); + if (!mtd->name) { + kfree(gluebi); + return -ENOMEM; + } + + gluebi->vol_id = vi->vol_id; mtd->type = MTD_UBIVOLUME; - if (!ubi->ro_mode) + if (!di->ro_mode) mtd->flags = MTD_WRITEABLE; - mtd->writesize = ubi->min_io_size; mtd->owner = THIS_MODULE; - mtd->erasesize = vol->usable_leb_size; + mtd->writesize = di->min_io_size; + mtd->erasesize = vi->usable_leb_size; mtd->read = gluebi_read; mtd->write = gluebi_write; mtd->erase = gluebi_erase; @@ -285,60 +345,196 @@ int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol) mtd->put_device = gluebi_put_device; /* - * In case of dynamic volume, MTD device size is just volume size. In + * In case of dynamic a volume, MTD device size is just volume size. In * case of a static volume the size is equivalent to the amount of data * bytes. */ - if (vol->vol_type == UBI_DYNAMIC_VOLUME) - mtd->size = (long long)vol->usable_leb_size * vol->reserved_pebs; + if (vi->vol_type == UBI_DYNAMIC_VOLUME) + mtd->size = (unsigned long long)vi->usable_leb_size * vi->size; else - mtd->size = vol->used_bytes; + mtd->size = vi->used_bytes; + + /* Just a sanity check - make sure this gluebi device does not exist */ + mutex_lock(&devices_mutex); + g = find_gluebi_nolock(vi->ubi_num, vi->vol_id); + if (g) + err_msg("gluebi MTD device %d form UBI device %d volume %d " + "already exists", g->mtd.index, vi->ubi_num, + vi->vol_id); + mutex_unlock(&devices_mutex); if (add_mtd_device(mtd)) { - ubi_err("cannot not add MTD device"); + err_msg("cannot add MTD device"); kfree(mtd->name); + kfree(gluebi); return -ENFILE; } - dbg_gen("added mtd%d (\"%s\"), size %llu, EB size %u", - mtd->index, mtd->name, (unsigned long long)mtd->size, mtd->erasesize); + mutex_lock(&devices_mutex); + list_add_tail(&gluebi->list, &gluebi_devices); + mutex_unlock(&devices_mutex); return 0; } /** - * ubi_destroy_gluebi - close gluebi for an UBI volume. - * @vol: volume description object + * gluebi_remove - remove a gluebi device. + * @vi: UBI volume description object * - * This function is called when an UBI volume is removed in order to remove + * This function is called when an UBI volume is removed and it removes * corresponding fake MTD device. Returns zero in case of success and a * negative error code in case of failure. */ -int ubi_destroy_gluebi(struct ubi_volume *vol) +static int gluebi_remove(struct ubi_volume_info *vi) { - int err; - struct mtd_info *mtd = &vol->gluebi_mtd; + int err = 0; + struct mtd_info *mtd; + struct gluebi_device *gluebi; - dbg_gen("remove mtd%d", mtd->index); - err = del_mtd_device(mtd); + mutex_lock(&devices_mutex); + gluebi = find_gluebi_nolock(vi->ubi_num, vi->vol_id); + if (!gluebi) { + err_msg("got remove notification for unknown UBI device %d " + "volume %d", vi->ubi_num, vi->vol_id); + err = -ENOENT; + } else if (gluebi->refcnt) + err = -EBUSY; + else + list_del(&gluebi->list); + mutex_unlock(&devices_mutex); if (err) return err; + + mtd = &gluebi->mtd; + err = del_mtd_device(mtd); + if (err) { + err_msg("cannot remove fake MTD device %d, UBI device %d, " + "volume %d, error %d", mtd->index, gluebi->ubi_num, + gluebi->vol_id, err); + mutex_lock(&devices_mutex); + list_add_tail(&gluebi->list, &gluebi_devices); + mutex_unlock(&devices_mutex); + return err; + } + kfree(mtd->name); + kfree(gluebi); return 0; } /** - * ubi_gluebi_updated - UBI volume was updated notifier. - * @vol: volume description object + * gluebi_updated - UBI volume was updated notifier. + * @vi: volume info structure * - * This function is called every time an UBI volume is updated. This function - * does nothing if volume @vol is dynamic, and changes MTD device size if the + * This function is called every time an UBI volume is updated. It does nothing + * if te volume @vol is dynamic, and changes MTD device size if the * volume is static. This is needed because static volumes cannot be read past - * data they contain. + * data they contain. This function returns zero in case of success and a + * negative error code in case of error. */ -void ubi_gluebi_updated(struct ubi_volume *vol) +static int gluebi_updated(struct ubi_volume_info *vi) { - struct mtd_info *mtd = &vol->gluebi_mtd; + struct gluebi_device *gluebi; - if (vol->vol_type == UBI_STATIC_VOLUME) - mtd->size = vol->used_bytes; + mutex_lock(&devices_mutex); + gluebi = find_gluebi_nolock(vi->ubi_num, vi->vol_id); + if (!gluebi) { + mutex_unlock(&devices_mutex); + err_msg("got update notification for unknown UBI device %d " + "volume %d", vi->ubi_num, vi->vol_id); + return -ENOENT; + } + + if (vi->vol_type == UBI_STATIC_VOLUME) + gluebi->mtd.size = vi->used_bytes; + mutex_unlock(&devices_mutex); + return 0; } + +/** + * gluebi_resized - UBI volume was re-sized notifier. + * @vi: volume info structure + * + * This function is called every time an UBI volume is re-size. It changes the + * corresponding fake MTD device size. This function returns zero in case of + * success and a negative error code in case of error. + */ +static int gluebi_resized(struct ubi_volume_info *vi) +{ + struct gluebi_device *gluebi; + + mutex_lock(&devices_mutex); + gluebi = find_gluebi_nolock(vi->ubi_num, vi->vol_id); + if (!gluebi) { + mutex_unlock(&devices_mutex); + err_msg("got update notification for unknown UBI device %d " + "volume %d", vi->ubi_num, vi->vol_id); + return -ENOENT; + } + gluebi->mtd.size = vi->used_bytes; + mutex_unlock(&devices_mutex); + return 0; +} + +/** + * gluebi_notify - UBI notification handler. + * @nb: registered notifier block + * @l: notification type + * @ptr: pointer to the &struct ubi_notification object + */ +static int gluebi_notify(struct notifier_block *nb, unsigned long l, + void *ns_ptr) +{ + struct ubi_notification *nt = ns_ptr; + + switch (l) { + case UBI_VOLUME_ADDED: + gluebi_create(&nt->di, &nt->vi); + break; + case UBI_VOLUME_REMOVED: + gluebi_remove(&nt->vi); + break; + case UBI_VOLUME_RESIZED: + gluebi_resized(&nt->vi); + break; + case UBI_VOLUME_UPDATED: + gluebi_updated(&nt->vi); + break; + default: + break; + } + return NOTIFY_OK; +} + +static struct notifier_block gluebi_notifier = { + .notifier_call = gluebi_notify, +}; + +static int __init ubi_gluebi_init(void) +{ + return ubi_register_volume_notifier(&gluebi_notifier, 0); +} + +static void __exit ubi_gluebi_exit(void) +{ + struct gluebi_device *gluebi, *g; + + list_for_each_entry_safe(gluebi, g, &gluebi_devices, list) { + int err; + struct mtd_info *mtd = &gluebi->mtd; + + err = del_mtd_device(mtd); + if (err) + err_msg("error %d while removing gluebi MTD device %d, " + "UBI device %d, volume %d - ignoring", err, + mtd->index, gluebi->ubi_num, gluebi->vol_id); + kfree(mtd->name); + kfree(gluebi); + } + ubi_unregister_volume_notifier(&gluebi_notifier); +} + +module_init(ubi_gluebi_init); +module_exit(ubi_gluebi_exit); +MODULE_DESCRIPTION("MTD emulation layer over UBI volumes"); +MODULE_AUTHOR("Artem Bityutskiy, Joern Engel"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c index fe81039f2a7c..effaff28bab1 100644 --- a/drivers/mtd/ubi/io.c +++ b/drivers/mtd/ubi/io.c @@ -100,6 +100,7 @@ static int paranoid_check_vid_hdr(const struct ubi_device *ubi, int pnum, const struct ubi_vid_hdr *vid_hdr); static int paranoid_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len); +static int paranoid_check_empty(struct ubi_device *ubi, int pnum); #else #define paranoid_check_not_bad(ubi, pnum) 0 #define paranoid_check_peb_ec_hdr(ubi, pnum) 0 @@ -107,6 +108,7 @@ static int paranoid_check_all_ff(struct ubi_device *ubi, int pnum, int offset, #define paranoid_check_peb_vid_hdr(ubi, pnum) 0 #define paranoid_check_vid_hdr(ubi, pnum, vid_hdr) 0 #define paranoid_check_all_ff(ubi, pnum, offset, len) 0 +#define paranoid_check_empty(ubi, pnum) 0 #endif /** @@ -670,11 +672,6 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum, if (read_err != -EBADMSG && check_pattern(ec_hdr, 0xFF, UBI_EC_HDR_SIZE)) { /* The physical eraseblock is supposedly empty */ - - /* - * The below is just a paranoid check, it has to be - * compiled out if paranoid checks are disabled. - */ err = paranoid_check_all_ff(ubi, pnum, 0, ubi->peb_size); if (err) @@ -902,7 +899,7 @@ bad: * o %UBI_IO_BITFLIPS if the CRC is correct, but bit-flips were detected * and corrected by the flash driver; this is harmless but may indicate that * this eraseblock may become bad soon; - * o %UBI_IO_BAD_VID_HRD if the volume identifier header is corrupted (a CRC + * o %UBI_IO_BAD_VID_HDR if the volume identifier header is corrupted (a CRC * error detected); * o %UBI_IO_PEB_FREE if the physical eraseblock is free (i.e., there is no VID * header there); @@ -955,8 +952,7 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum, * The below is just a paranoid check, it has to be * compiled out if paranoid checks are disabled. */ - err = paranoid_check_all_ff(ubi, pnum, ubi->leb_start, - ubi->leb_size); + err = paranoid_check_empty(ubi, pnum); if (err) return err > 0 ? UBI_IO_BAD_VID_HDR : err; @@ -1280,4 +1276,74 @@ error: return err; } +/** + * paranoid_check_empty - whether a PEB is empty. + * @ubi: UBI device description object + * @pnum: the physical eraseblock number to check + * + * This function makes sure PEB @pnum is empty, which means it contains only + * %0xFF data bytes. Returns zero if the PEB is empty, %1 if not, and a + * negative error code in case of failure. + * + * Empty PEBs have the EC header, and do not have the VID header. The caller of + * this function should have already made sure the PEB does not have the VID + * header. However, this function re-checks that, because it is possible that + * the header and data has already been written to the PEB. + * + * Let's consider a possible scenario. Suppose there are 2 tasks - A and B. + * Task A is in 'wear_leveling_worker()'. It is reading VID header of PEB X to + * find which LEB it corresponds to. PEB X is currently unmapped, and has no + * VID header. Task B is trying to write to PEB X. + * + * Task A: in 'ubi_io_read_vid_hdr()': reads the VID header from PEB X. The + * read data contain all 0xFF bytes; + * Task B: writes VID header and some data to PEB X; + * Task A: assumes PEB X is empty, calls 'paranoid_check_empty()'. And if we + * do not re-read the VID header, and do not cancel the checking if it + * is there, we fail. + */ +static int paranoid_check_empty(struct ubi_device *ubi, int pnum) +{ + int err, offs = ubi->vid_hdr_aloffset, len = ubi->vid_hdr_alsize; + size_t read; + uint32_t magic; + const struct ubi_vid_hdr *vid_hdr; + + mutex_lock(&ubi->dbg_buf_mutex); + err = ubi->mtd->read(ubi->mtd, offs, len, &read, ubi->dbg_peb_buf); + if (err && err != -EUCLEAN) { + ubi_err("error %d while reading %d bytes from PEB %d:%d, " + "read %zd bytes", err, len, pnum, offs, read); + goto error; + } + + vid_hdr = ubi->dbg_peb_buf; + magic = be32_to_cpu(vid_hdr->magic); + if (magic == UBI_VID_HDR_MAGIC) + /* The PEB contains VID header, so it is not empty */ + goto out; + + err = check_pattern(ubi->dbg_peb_buf, 0xFF, len); + if (err == 0) { + ubi_err("flash region at PEB %d:%d, length %d does not " + "contain all 0xFF bytes", pnum, offs, len); + goto fail; + } + +out: + mutex_unlock(&ubi->dbg_buf_mutex); + return 0; + +fail: + ubi_err("paranoid check failed for PEB %d", pnum); + ubi_msg("hex dump of the %d-%d region", offs, offs + len); + print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, + ubi->dbg_peb_buf, len, 1); + err = 1; +error: + ubi_dbg_dump_stack(); + mutex_unlock(&ubi->dbg_buf_mutex); + return err; +} + #endif /* CONFIG_MTD_UBI_DEBUG_PARANOID */ diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c index 4abbe573fa40..88a72e9c8beb 100644 --- a/drivers/mtd/ubi/kapi.c +++ b/drivers/mtd/ubi/kapi.c @@ -25,6 +25,24 @@ #include #include "ubi.h" +/** + * ubi_do_get_device_info - get information about UBI device. + * @ubi: UBI device description object + * @di: the information is stored here + * + * This function is the same as 'ubi_get_device_info()', but it assumes the UBI + * device is locked and cannot disappear. + */ +void ubi_do_get_device_info(struct ubi_device *ubi, struct ubi_device_info *di) +{ + di->ubi_num = ubi->ubi_num; + di->leb_size = ubi->leb_size; + di->min_io_size = ubi->min_io_size; + di->ro_mode = ubi->ro_mode; + di->cdev = ubi->cdev.dev; +} +EXPORT_SYMBOL_GPL(ubi_do_get_device_info); + /** * ubi_get_device_info - get information about UBI device. * @ubi_num: UBI device number @@ -39,33 +57,24 @@ int ubi_get_device_info(int ubi_num, struct ubi_device_info *di) if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES) return -EINVAL; - ubi = ubi_get_device(ubi_num); if (!ubi) return -ENODEV; - - di->ubi_num = ubi->ubi_num; - di->leb_size = ubi->leb_size; - di->min_io_size = ubi->min_io_size; - di->ro_mode = ubi->ro_mode; - di->cdev = ubi->cdev.dev; - + ubi_do_get_device_info(ubi, di); ubi_put_device(ubi); return 0; } EXPORT_SYMBOL_GPL(ubi_get_device_info); /** - * ubi_get_volume_info - get information about UBI volume. - * @desc: volume descriptor + * ubi_do_get_volume_info - get information about UBI volume. + * @ubi: UBI device description object + * @vol: volume description object * @vi: the information is stored here */ -void ubi_get_volume_info(struct ubi_volume_desc *desc, - struct ubi_volume_info *vi) +void ubi_do_get_volume_info(struct ubi_device *ubi, struct ubi_volume *vol, + struct ubi_volume_info *vi) { - const struct ubi_volume *vol = desc->vol; - const struct ubi_device *ubi = vol->ubi; - vi->vol_id = vol->vol_id; vi->ubi_num = ubi->ubi_num; vi->size = vol->reserved_pebs; @@ -79,6 +88,17 @@ void ubi_get_volume_info(struct ubi_volume_desc *desc, vi->name = vol->name; vi->cdev = vol->cdev.dev; } + +/** + * ubi_get_volume_info - get information about UBI volume. + * @desc: volume descriptor + * @vi: the information is stored here + */ +void ubi_get_volume_info(struct ubi_volume_desc *desc, + struct ubi_volume_info *vi) +{ + ubi_do_get_volume_info(desc->vol->ubi, desc->vol, vi); +} EXPORT_SYMBOL_GPL(ubi_get_volume_info); /** @@ -106,7 +126,7 @@ struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode) struct ubi_device *ubi; struct ubi_volume *vol; - dbg_gen("open device %d volume %d, mode %d", ubi_num, vol_id, mode); + dbg_gen("open device %d, volume %d, mode %d", ubi_num, vol_id, mode); if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES) return ERR_PTR(-EINVAL); @@ -196,6 +216,8 @@ out_free: kfree(desc); out_put_ubi: ubi_put_device(ubi); + dbg_err("cannot open device %d, volume %d, error %d", + ubi_num, vol_id, err); return ERR_PTR(err); } EXPORT_SYMBOL_GPL(ubi_open_volume); @@ -215,7 +237,7 @@ struct ubi_volume_desc *ubi_open_volume_nm(int ubi_num, const char *name, struct ubi_device *ubi; struct ubi_volume_desc *ret; - dbg_gen("open volume %s, mode %d", name, mode); + dbg_gen("open device %d, volume %s, mode %d", ubi_num, name, mode); if (!name) return ERR_PTR(-EINVAL); @@ -266,7 +288,8 @@ void ubi_close_volume(struct ubi_volume_desc *desc) struct ubi_volume *vol = desc->vol; struct ubi_device *ubi = vol->ubi; - dbg_gen("close volume %d, mode %d", vol->vol_id, desc->mode); + dbg_gen("close device %d, volume %d, mode %d", + ubi->ubi_num, vol->vol_id, desc->mode); spin_lock(&ubi->volumes_lock); switch (desc->mode) { @@ -558,7 +581,7 @@ int ubi_leb_unmap(struct ubi_volume_desc *desc, int lnum) EXPORT_SYMBOL_GPL(ubi_leb_unmap); /** - * ubi_leb_map - map logical erasblock to a physical eraseblock. + * ubi_leb_map - map logical eraseblock to a physical eraseblock. * @desc: volume descriptor * @lnum: logical eraseblock number * @dtype: expected data type @@ -656,3 +679,59 @@ int ubi_sync(int ubi_num) return 0; } EXPORT_SYMBOL_GPL(ubi_sync); + +BLOCKING_NOTIFIER_HEAD(ubi_notifiers); + +/** + * ubi_register_volume_notifier - register a volume notifier. + * @nb: the notifier description object + * @ignore_existing: if non-zero, do not send "added" notification for all + * already existing volumes + * + * This function registers a volume notifier, which means that + * 'nb->notifier_call()' will be invoked when an UBI volume is created, + * removed, re-sized, re-named, or updated. The first argument of the function + * is the notification type. The second argument is pointer to a + * &struct ubi_notification object which describes the notification event. + * Using UBI API from the volume notifier is prohibited. + * + * This function returns zero in case of success and a negative error code + * in case of failure. + */ +int ubi_register_volume_notifier(struct notifier_block *nb, + int ignore_existing) +{ + int err; + + err = blocking_notifier_chain_register(&ubi_notifiers, nb); + if (err != 0) + return err; + if (ignore_existing) + return 0; + + /* + * We are going to walk all UBI devices and all volumes, and + * notify the user about existing volumes by the %UBI_VOLUME_ADDED + * event. We have to lock the @ubi_devices_mutex to make sure UBI + * devices do not disappear. + */ + mutex_lock(&ubi_devices_mutex); + ubi_enumerate_volumes(nb); + mutex_unlock(&ubi_devices_mutex); + + return err; +} +EXPORT_SYMBOL_GPL(ubi_register_volume_notifier); + +/** + * ubi_unregister_volume_notifier - unregister the volume notifier. + * @nb: the notifier description object + * + * This function unregisters volume notifier @nm and returns zero in case of + * success and a negative error code in case of failure. + */ +int ubi_unregister_volume_notifier(struct notifier_block *nb) +{ + return blocking_notifier_chain_unregister(&ubi_notifiers, nb); +} +EXPORT_SYMBOL_GPL(ubi_unregister_volume_notifier); diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h index c055511bb1b2..28acd133c997 100644 --- a/drivers/mtd/ubi/ubi.h +++ b/drivers/mtd/ubi/ubi.h @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -100,6 +101,28 @@ enum { UBI_IO_BITFLIPS }; +/* + * Return codes of the 'ubi_eba_copy_leb()' function. + * + * MOVE_CANCEL_RACE: canceled because the volume is being deleted, the source + * PEB was put meanwhile, or there is I/O on the source PEB + * MOVE_SOURCE_RD_ERR: canceled because there was a read error from the source + * PEB + * MOVE_TARGET_RD_ERR: canceled because there was a read error from the target + * PEB + * MOVE_TARGET_WR_ERR: canceled because there was a write error to the target + * PEB + * MOVE_CANCEL_BITFLIPS: canceled because a bit-flip was detected in the + * target PEB + */ +enum { + MOVE_CANCEL_RACE = 1, + MOVE_SOURCE_RD_ERR, + MOVE_TARGET_RD_ERR, + MOVE_TARGET_WR_ERR, + MOVE_CANCEL_BITFLIPS, +}; + /** * struct ubi_wl_entry - wear-leveling entry. * @u.rb: link in the corresponding (free/used) RB-tree @@ -208,10 +231,6 @@ struct ubi_volume_desc; * @changing_leb: %1 if the atomic LEB change ioctl command is in progress * @direct_writes: %1 if direct writes are enabled for this volume * - * @gluebi_desc: gluebi UBI volume descriptor - * @gluebi_refcount: reference count of the gluebi MTD device - * @gluebi_mtd: MTD device description object of the gluebi MTD device - * * The @corrupted field indicates that the volume's contents is corrupted. * Since UBI protects only static volumes, this field is not relevant to * dynamic volumes - it is user's responsibility to assure their data @@ -255,17 +274,6 @@ struct ubi_volume { unsigned int updating:1; unsigned int changing_leb:1; unsigned int direct_writes:1; - -#ifdef CONFIG_MTD_UBI_GLUEBI - /* - * Gluebi-related stuff may be compiled out. - * Note: this should not be built into UBI but should be a separate - * ubimtd driver which works on top of UBI and emulates MTD devices. - */ - struct ubi_volume_desc *gluebi_desc; - int gluebi_refcount; - struct mtd_info gluebi_mtd; -#endif }; /** @@ -305,9 +313,9 @@ struct ubi_wl_entry; * @vtbl_slots: how many slots are available in the volume table * @vtbl_size: size of the volume table in bytes * @vtbl: in-RAM volume table copy - * @volumes_mutex: protects on-flash volume table and serializes volume - * changes, like creation, deletion, update, re-size, - * re-name and set property + * @device_mutex: protects on-flash volume table and serializes volume + * creation, deletion, update, re-size, re-name and set + * property * * @max_ec: current highest erase counter value * @mean_ec: current mean erase counter value @@ -318,14 +326,15 @@ struct ubi_wl_entry; * @alc_mutex: serializes "atomic LEB change" operations * * @used: RB-tree of used physical eraseblocks + * @erroneous: RB-tree of erroneous used physical eraseblocks * @free: RB-tree of free physical eraseblocks * @scrub: RB-tree of physical eraseblocks which need scrubbing * @pq: protection queue (contain physical eraseblocks which are temporarily * protected from the wear-leveling worker) * @pq_head: protection queue head * @wl_lock: protects the @used, @free, @pq, @pq_head, @lookuptbl, @move_from, - * @move_to, @move_to_put @erase_pending, @wl_scheduled and @works - * fields + * @move_to, @move_to_put @erase_pending, @wl_scheduled, @works, + * @erroneous, and @erroneous_peb_count fields * @move_mutex: serializes eraseblock moves * @work_sem: synchronizes the WL worker with use tasks * @wl_scheduled: non-zero if the wear-leveling was scheduled @@ -339,12 +348,15 @@ struct ubi_wl_entry; * @bgt_thread: background thread description object * @thread_enabled: if the background thread is enabled * @bgt_name: background thread name + * @reboot_notifier: notifier to terminate background thread before rebooting * * @flash_size: underlying MTD device size (in bytes) * @peb_count: count of physical eraseblocks on the MTD device * @peb_size: physical eraseblock size * @bad_peb_count: count of bad physical eraseblocks * @good_peb_count: count of good physical eraseblocks + * @erroneous_peb_count: count of erroneous physical eraseblocks in @erroneous + * @max_erroneous: maximum allowed amount of erroneous physical eraseblocks * @min_io_size: minimal input/output unit size of the underlying MTD device * @hdrs_min_io_size: minimal I/O unit size used for VID and EC headers * @ro_mode: if the UBI device is in read-only mode @@ -366,7 +378,6 @@ struct ubi_wl_entry; * @peb_buf2: another buffer of PEB size used for different purposes * @buf_mutex: protects @peb_buf1 and @peb_buf2 * @ckvol_mutex: serializes static volume checking when opening - * @mult_mutex: serializes operations on multiple volumes, like re-naming * @dbg_peb_buf: buffer of PEB size used for debugging * @dbg_buf_mutex: protects @dbg_peb_buf */ @@ -389,7 +400,7 @@ struct ubi_device { int vtbl_slots; int vtbl_size; struct ubi_vtbl_record *vtbl; - struct mutex volumes_mutex; + struct mutex device_mutex; int max_ec; /* Note, mean_ec is not updated run-time - should be fixed */ @@ -403,6 +414,7 @@ struct ubi_device { /* Wear-leveling sub-system's stuff */ struct rb_root used; + struct rb_root erroneous; struct rb_root free; struct rb_root scrub; struct list_head pq[UBI_PROT_QUEUE_LEN]; @@ -420,6 +432,7 @@ struct ubi_device { struct task_struct *bgt_thread; int thread_enabled; char bgt_name[sizeof(UBI_BGT_NAME_PATTERN)+2]; + struct notifier_block reboot_notifier; /* I/O sub-system's stuff */ long long flash_size; @@ -427,6 +440,8 @@ struct ubi_device { int peb_size; int bad_peb_count; int good_peb_count; + int erroneous_peb_count; + int max_erroneous; int min_io_size; int hdrs_min_io_size; int ro_mode; @@ -444,8 +459,7 @@ struct ubi_device { void *peb_buf2; struct mutex buf_mutex; struct mutex ckvol_mutex; - struct mutex mult_mutex; -#ifdef CONFIG_MTD_UBI_DEBUG +#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID void *dbg_peb_buf; struct mutex dbg_buf_mutex; #endif @@ -457,6 +471,7 @@ extern const struct file_operations ubi_cdev_operations; extern const struct file_operations ubi_vol_cdev_operations; extern struct class *ubi_class; extern struct mutex ubi_devices_mutex; +extern struct blocking_notifier_head ubi_notifiers; /* vtbl.c */ int ubi_change_vtbl_record(struct ubi_device *ubi, int idx, @@ -489,17 +504,6 @@ int ubi_calc_data_len(const struct ubi_device *ubi, const void *buf, int ubi_check_volume(struct ubi_device *ubi, int vol_id); void ubi_calculate_reserved(struct ubi_device *ubi); -/* gluebi.c */ -#ifdef CONFIG_MTD_UBI_GLUEBI -int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol); -int ubi_destroy_gluebi(struct ubi_volume *vol); -void ubi_gluebi_updated(struct ubi_volume *vol); -#else -#define ubi_create_gluebi(ubi, vol) 0 -#define ubi_destroy_gluebi(vol) 0 -#define ubi_gluebi_updated(vol) -#endif - /* eba.c */ int ubi_eba_unmap_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum); @@ -549,6 +553,16 @@ struct ubi_device *ubi_get_device(int ubi_num); void ubi_put_device(struct ubi_device *ubi); struct ubi_device *ubi_get_by_major(int major); int ubi_major2num(int major); +int ubi_volume_notify(struct ubi_device *ubi, struct ubi_volume *vol, + int ntype); +int ubi_notify_all(struct ubi_device *ubi, int ntype, + struct notifier_block *nb); +int ubi_enumerate_volumes(struct notifier_block *nb); + +/* kapi.c */ +void ubi_do_get_device_info(struct ubi_device *ubi, struct ubi_device_info *di); +void ubi_do_get_volume_info(struct ubi_device *ubi, struct ubi_volume *vol, + struct ubi_volume_info *vi); /* * ubi_rb_for_each_entry - walk an RB-tree. diff --git a/drivers/mtd/ubi/upd.c b/drivers/mtd/ubi/upd.c index 6b4d1ae891ae..74fdc40c8627 100644 --- a/drivers/mtd/ubi/upd.c +++ b/drivers/mtd/ubi/upd.c @@ -68,10 +68,10 @@ static int set_update_marker(struct ubi_device *ubi, struct ubi_volume *vol) sizeof(struct ubi_vtbl_record)); vtbl_rec.upd_marker = 1; - mutex_lock(&ubi->volumes_mutex); + mutex_lock(&ubi->device_mutex); err = ubi_change_vtbl_record(ubi, vol->vol_id, &vtbl_rec); - mutex_unlock(&ubi->volumes_mutex); vol->upd_marker = 1; + mutex_unlock(&ubi->device_mutex); return err; } @@ -109,10 +109,10 @@ static int clear_update_marker(struct ubi_device *ubi, struct ubi_volume *vol, vol->last_eb_bytes = vol->usable_leb_size; } - mutex_lock(&ubi->volumes_mutex); + mutex_lock(&ubi->device_mutex); err = ubi_change_vtbl_record(ubi, vol->vol_id, &vtbl_rec); - mutex_unlock(&ubi->volumes_mutex); vol->upd_marker = 0; + mutex_unlock(&ubi->device_mutex); return err; } diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c index df5483562b7a..ab64cb56df6e 100644 --- a/drivers/mtd/ubi/vmt.c +++ b/drivers/mtd/ubi/vmt.c @@ -198,7 +198,7 @@ static void volume_sysfs_close(struct ubi_volume *vol) * %UBI_VOL_NUM_AUTO, this function automatically assign ID to the new volume * and saves it in @req->vol_id. Returns zero in case of success and a negative * error code in case of failure. Note, the caller has to have the - * @ubi->volumes_mutex locked. + * @ubi->device_mutex locked. */ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) { @@ -232,8 +232,8 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) req->vol_id = vol_id; } - dbg_gen("volume ID %d, %llu bytes, type %d, name %s", - vol_id, (unsigned long long)req->bytes, + dbg_gen("create device %d, volume %d, %llu bytes, type %d, name %s", + ubi->ubi_num, vol_id, (unsigned long long)req->bytes, (int)req->vol_type, req->name); /* Ensure that this volume does not exist */ @@ -317,10 +317,6 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) goto out_mapping; } - err = ubi_create_gluebi(ubi, vol); - if (err) - goto out_cdev; - vol->dev.release = vol_release; vol->dev.parent = &ubi->dev; vol->dev.devt = dev; @@ -330,7 +326,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) err = device_register(&vol->dev); if (err) { ubi_err("cannot register device"); - goto out_gluebi; + goto out_cdev; } err = volume_sysfs_init(ubi, vol); @@ -358,7 +354,9 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) ubi->vol_count += 1; spin_unlock(&ubi->volumes_lock); - err = paranoid_check_volumes(ubi); + ubi_volume_notify(ubi, vol, UBI_VOLUME_ADDED); + if (paranoid_check_volumes(ubi)) + dbg_err("check failed while creating volume %d", vol_id); return err; out_sysfs: @@ -373,10 +371,6 @@ out_sysfs: do_free = 0; get_device(&vol->dev); volume_sysfs_close(vol); -out_gluebi: - if (ubi_destroy_gluebi(vol)) - dbg_err("cannot destroy gluebi for volume %d:%d", - ubi->ubi_num, vol_id); out_cdev: cdev_del(&vol->cdev); out_mapping: @@ -403,7 +397,7 @@ out_unlock: * * This function removes volume described by @desc. The volume has to be opened * in "exclusive" mode. Returns zero in case of success and a negative error - * code in case of failure. The caller has to have the @ubi->volumes_mutex + * code in case of failure. The caller has to have the @ubi->device_mutex * locked. */ int ubi_remove_volume(struct ubi_volume_desc *desc, int no_vtbl) @@ -412,7 +406,7 @@ int ubi_remove_volume(struct ubi_volume_desc *desc, int no_vtbl) struct ubi_device *ubi = vol->ubi; int i, err, vol_id = vol->vol_id, reserved_pebs = vol->reserved_pebs; - dbg_gen("remove UBI volume %d", vol_id); + dbg_gen("remove device %d, volume %d", ubi->ubi_num, vol_id); ubi_assert(desc->mode == UBI_EXCLUSIVE); ubi_assert(vol == ubi->volumes[vol_id]); @@ -431,10 +425,6 @@ int ubi_remove_volume(struct ubi_volume_desc *desc, int no_vtbl) ubi->volumes[vol_id] = NULL; spin_unlock(&ubi->volumes_lock); - err = ubi_destroy_gluebi(vol); - if (err) - goto out_err; - if (!no_vtbl) { err = ubi_change_vtbl_record(ubi, vol_id, NULL); if (err) @@ -465,8 +455,10 @@ int ubi_remove_volume(struct ubi_volume_desc *desc, int no_vtbl) ubi->vol_count -= 1; spin_unlock(&ubi->volumes_lock); - if (!no_vtbl) - err = paranoid_check_volumes(ubi); + ubi_volume_notify(ubi, vol, UBI_VOLUME_REMOVED); + if (!no_vtbl && paranoid_check_volumes(ubi)) + dbg_err("check failed while removing volume %d", vol_id); + return err; out_err: @@ -485,7 +477,7 @@ out_unlock: * * This function re-sizes the volume and returns zero in case of success, and a * negative error code in case of failure. The caller has to have the - * @ubi->volumes_mutex locked. + * @ubi->device_mutex locked. */ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs) { @@ -498,8 +490,8 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs) if (ubi->ro_mode) return -EROFS; - dbg_gen("re-size volume %d to from %d to %d PEBs", - vol_id, vol->reserved_pebs, reserved_pebs); + dbg_gen("re-size device %d, volume %d to from %d to %d PEBs", + ubi->ubi_num, vol_id, vol->reserved_pebs, reserved_pebs); if (vol->vol_type == UBI_STATIC_VOLUME && reserved_pebs < vol->used_ebs) { @@ -587,7 +579,9 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs) (long long)vol->used_ebs * vol->usable_leb_size; } - err = paranoid_check_volumes(ubi); + ubi_volume_notify(ubi, vol, UBI_VOLUME_RESIZED); + if (paranoid_check_volumes(ubi)) + dbg_err("check failed while re-sizing volume %d", vol_id); return err; out_acc: @@ -632,11 +626,12 @@ int ubi_rename_volumes(struct ubi_device *ubi, struct list_head *rename_list) vol->name_len = re->new_name_len; memcpy(vol->name, re->new_name, re->new_name_len + 1); spin_unlock(&ubi->volumes_lock); + ubi_volume_notify(ubi, vol, UBI_VOLUME_RENAMED); } } - if (!err) - err = paranoid_check_volumes(ubi); + if (!err && paranoid_check_volumes(ubi)) + ; return err; } @@ -667,10 +662,6 @@ int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol) return err; } - err = ubi_create_gluebi(ubi, vol); - if (err) - goto out_cdev; - vol->dev.release = vol_release; vol->dev.parent = &ubi->dev; vol->dev.devt = dev; @@ -678,21 +669,19 @@ int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol) dev_set_name(&vol->dev, "%s_%d", ubi->ubi_name, vol->vol_id); err = device_register(&vol->dev); if (err) - goto out_gluebi; + goto out_cdev; err = volume_sysfs_init(ubi, vol); if (err) { cdev_del(&vol->cdev); - err = ubi_destroy_gluebi(vol); volume_sysfs_close(vol); return err; } - err = paranoid_check_volumes(ubi); + if (paranoid_check_volumes(ubi)) + dbg_err("check failed while adding volume %d", vol_id); return err; -out_gluebi: - err = ubi_destroy_gluebi(vol); out_cdev: cdev_del(&vol->cdev); return err; @@ -708,12 +697,9 @@ out_cdev: */ void ubi_free_volume(struct ubi_device *ubi, struct ubi_volume *vol) { - int err; - dbg_gen("free volume %d", vol->vol_id); ubi->volumes[vol->vol_id] = NULL; - err = ubi_destroy_gluebi(vol); cdev_del(&vol->cdev); volume_sysfs_close(vol); } @@ -868,6 +854,7 @@ fail: if (vol) ubi_dbg_dump_vol_info(vol); ubi_dbg_dump_vtbl_record(&ubi->vtbl[vol_id], vol_id); + dump_stack(); spin_unlock(&ubi->volumes_lock); return -EINVAL; } diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index 891534f8210d..2b2472300610 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -55,8 +55,8 @@ * * As it was said, for the UBI sub-system all physical eraseblocks are either * "free" or "used". Free eraseblock are kept in the @wl->free RB-tree, while - * used eraseblocks are kept in @wl->used or @wl->scrub RB-trees, or - * (temporarily) in the @wl->pq queue. + * used eraseblocks are kept in @wl->used, @wl->erroneous, or @wl->scrub + * RB-trees, as well as (temporarily) in the @wl->pq queue. * * When the WL sub-system returns a physical eraseblock, the physical * eraseblock is protected from being moved for some "time". For this reason, @@ -83,6 +83,8 @@ * used. The former state corresponds to the @wl->free tree. The latter state * is split up on several sub-states: * o the WL movement is allowed (@wl->used tree); + * o the WL movement is disallowed (@wl->erroneous) because the PEB is + * erroneous - e.g., there was a read error; * o the WL movement is temporarily prohibited (@wl->pq queue); * o scrubbing is needed (@wl->scrub tree). * @@ -653,7 +655,8 @@ static int schedule_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, int cancel) { - int err, scrubbing = 0, torture = 0; + int err, scrubbing = 0, torture = 0, protect = 0, erroneous = 0; + int vol_id = -1, uninitialized_var(lnum); struct ubi_wl_entry *e1, *e2; struct ubi_vid_hdr *vid_hdr; @@ -738,68 +741,78 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, /* * We are trying to move PEB without a VID header. UBI * always write VID headers shortly after the PEB was - * given, so we have a situation when it did not have - * chance to write it down because it was preempted. - * Just re-schedule the work, so that next time it will - * likely have the VID header in place. + * given, so we have a situation when it has not yet + * had a chance to write it, because it was preempted. + * So add this PEB to the protection queue so far, + * because presumably more data will be written there + * (including the missing VID header), and then we'll + * move it. */ dbg_wl("PEB %d has no VID header", e1->pnum); + protect = 1; goto out_not_moved; } ubi_err("error %d while reading VID header from PEB %d", err, e1->pnum); - if (err > 0) - err = -EIO; goto out_error; } + vol_id = be32_to_cpu(vid_hdr->vol_id); + lnum = be32_to_cpu(vid_hdr->lnum); + err = ubi_eba_copy_leb(ubi, e1->pnum, e2->pnum, vid_hdr); if (err) { - if (err == -EAGAIN) + if (err == MOVE_CANCEL_RACE) { + /* + * The LEB has not been moved because the volume is + * being deleted or the PEB has been put meanwhile. We + * should prevent this PEB from being selected for + * wear-leveling movement again, so put it to the + * protection queue. + */ + protect = 1; goto out_not_moved; - if (err < 0) - goto out_error; - if (err == 2) { - /* Target PEB write error, torture it */ + } + + if (err == MOVE_CANCEL_BITFLIPS || err == MOVE_TARGET_WR_ERR || + err == MOVE_TARGET_RD_ERR) { + /* + * Target PEB had bit-flips or write error - torture it. + */ torture = 1; goto out_not_moved; } - /* - * The LEB has not been moved because the volume is being - * deleted or the PEB has been put meanwhile. We should prevent - * this PEB from being selected for wear-leveling movement - * again, so put it to the protection queue. - */ + if (err == MOVE_SOURCE_RD_ERR) { + /* + * An error happened while reading the source PEB. Do + * not switch to R/O mode in this case, and give the + * upper layers a possibility to recover from this, + * e.g. by unmapping corresponding LEB. Instead, just + * put this PEB to the @ubi->erroneous list to prevent + * UBI from trying to move it over and over again. + */ + if (ubi->erroneous_peb_count > ubi->max_erroneous) { + ubi_err("too many erroneous eraseblocks (%d)", + ubi->erroneous_peb_count); + goto out_error; + } + erroneous = 1; + goto out_not_moved; + } - dbg_wl("canceled moving PEB %d", e1->pnum); - ubi_assert(err == 1); - - ubi_free_vid_hdr(ubi, vid_hdr); - vid_hdr = NULL; - - spin_lock(&ubi->wl_lock); - prot_queue_add(ubi, e1); - ubi_assert(!ubi->move_to_put); - ubi->move_from = ubi->move_to = NULL; - ubi->wl_scheduled = 0; - spin_unlock(&ubi->wl_lock); - - e1 = NULL; - err = schedule_erase(ubi, e2, 0); - if (err) + if (err < 0) goto out_error; - mutex_unlock(&ubi->move_mutex); - return 0; + + ubi_assert(0); } /* The PEB has been successfully moved */ - ubi_free_vid_hdr(ubi, vid_hdr); - vid_hdr = NULL; if (scrubbing) - ubi_msg("scrubbed PEB %d, data moved to PEB %d", - e1->pnum, e2->pnum); + ubi_msg("scrubbed PEB %d (LEB %d:%d), data moved to PEB %d", + e1->pnum, vol_id, lnum, e2->pnum); + ubi_free_vid_hdr(ubi, vid_hdr); spin_lock(&ubi->wl_lock); if (!ubi->move_to_put) { @@ -812,8 +825,10 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, err = schedule_erase(ubi, e1, 0); if (err) { - e1 = NULL; - goto out_error; + kmem_cache_free(ubi_wl_entry_slab, e1); + if (e2) + kmem_cache_free(ubi_wl_entry_slab, e2); + goto out_ro; } if (e2) { @@ -821,10 +836,13 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, * Well, the target PEB was put meanwhile, schedule it for * erasure. */ - dbg_wl("PEB %d was put meanwhile, erase", e2->pnum); + dbg_wl("PEB %d (LEB %d:%d) was put meanwhile, erase", + e2->pnum, vol_id, lnum); err = schedule_erase(ubi, e2, 0); - if (err) - goto out_error; + if (err) { + kmem_cache_free(ubi_wl_entry_slab, e2); + goto out_ro; + } } dbg_wl("done"); @@ -837,11 +855,19 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, * have been changed, schedule it for erasure. */ out_not_moved: - dbg_wl("canceled moving PEB %d", e1->pnum); - ubi_free_vid_hdr(ubi, vid_hdr); - vid_hdr = NULL; + if (vol_id != -1) + dbg_wl("cancel moving PEB %d (LEB %d:%d) to PEB %d (%d)", + e1->pnum, vol_id, lnum, e2->pnum, err); + else + dbg_wl("cancel moving PEB %d to PEB %d (%d)", + e1->pnum, e2->pnum, err); spin_lock(&ubi->wl_lock); - if (scrubbing) + if (protect) + prot_queue_add(ubi, e1); + else if (erroneous) { + wl_tree_add(e1, &ubi->erroneous); + ubi->erroneous_peb_count += 1; + } else if (scrubbing) wl_tree_add(e1, &ubi->scrub); else wl_tree_add(e1, &ubi->used); @@ -850,32 +876,36 @@ out_not_moved: ubi->wl_scheduled = 0; spin_unlock(&ubi->wl_lock); - e1 = NULL; + ubi_free_vid_hdr(ubi, vid_hdr); err = schedule_erase(ubi, e2, torture); - if (err) - goto out_error; - + if (err) { + kmem_cache_free(ubi_wl_entry_slab, e2); + goto out_ro; + } mutex_unlock(&ubi->move_mutex); return 0; out_error: - ubi_err("error %d while moving PEB %d to PEB %d", - err, e1->pnum, e2->pnum); - - ubi_free_vid_hdr(ubi, vid_hdr); + if (vol_id != -1) + ubi_err("error %d while moving PEB %d to PEB %d", + err, e1->pnum, e2->pnum); + else + ubi_err("error %d while moving PEB %d (LEB %d:%d) to PEB %d", + err, e1->pnum, vol_id, lnum, e2->pnum); spin_lock(&ubi->wl_lock); ubi->move_from = ubi->move_to = NULL; ubi->move_to_put = ubi->wl_scheduled = 0; spin_unlock(&ubi->wl_lock); - if (e1) - kmem_cache_free(ubi_wl_entry_slab, e1); - if (e2) - kmem_cache_free(ubi_wl_entry_slab, e2); - ubi_ro_mode(ubi); + ubi_free_vid_hdr(ubi, vid_hdr); + kmem_cache_free(ubi_wl_entry_slab, e1); + kmem_cache_free(ubi_wl_entry_slab, e2); +out_ro: + ubi_ro_mode(ubi); mutex_unlock(&ubi->move_mutex); - return err; + ubi_assert(err != 0); + return err < 0 ? err : -EIO; out_cancel: ubi->wl_scheduled = 0; @@ -1015,7 +1045,7 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, /* * If this is not %-EIO, we have no idea what to do. Scheduling * this physical eraseblock for erasure again would cause - * errors again and again. Well, lets switch to RO mode. + * errors again and again. Well, lets switch to R/O mode. */ goto out_ro; } @@ -1043,10 +1073,9 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, ubi_err("no reserved physical eraseblocks"); goto out_ro; } - spin_unlock(&ubi->volumes_lock); - ubi_msg("mark PEB %d as bad", pnum); + ubi_msg("mark PEB %d as bad", pnum); err = ubi_io_mark_bad(ubi, pnum); if (err) goto out_ro; @@ -1056,7 +1085,9 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, ubi->bad_peb_count += 1; ubi->good_peb_count -= 1; ubi_calculate_reserved(ubi); - if (ubi->beb_rsvd_pebs == 0) + if (ubi->beb_rsvd_pebs) + ubi_msg("%d PEBs left in the reserve", ubi->beb_rsvd_pebs); + else ubi_warn("last PEB from the reserved pool was used"); spin_unlock(&ubi->volumes_lock); @@ -1125,6 +1156,13 @@ retry: } else if (in_wl_tree(e, &ubi->scrub)) { paranoid_check_in_wl_tree(e, &ubi->scrub); rb_erase(&e->u.rb, &ubi->scrub); + } else if (in_wl_tree(e, &ubi->erroneous)) { + paranoid_check_in_wl_tree(e, &ubi->erroneous); + rb_erase(&e->u.rb, &ubi->erroneous); + ubi->erroneous_peb_count -= 1; + ubi_assert(ubi->erroneous_peb_count >= 0); + /* Erroneous PEBs should be tortured */ + torture = 1; } else { err = prot_queue_del(ubi, e->pnum); if (err) { @@ -1373,7 +1411,7 @@ int ubi_wl_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si) struct ubi_scan_leb *seb, *tmp; struct ubi_wl_entry *e; - ubi->used = ubi->free = ubi->scrub = RB_ROOT; + ubi->used = ubi->erroneous = ubi->free = ubi->scrub = RB_ROOT; spin_lock_init(&ubi->wl_lock); mutex_init(&ubi->move_mutex); init_rwsem(&ubi->work_sem); @@ -1511,6 +1549,7 @@ void ubi_wl_close(struct ubi_device *ubi) cancel_pending(ubi); protection_queue_destroy(ubi); tree_destroy(&ubi->used); + tree_destroy(&ubi->erroneous); tree_destroy(&ubi->free); tree_destroy(&ubi->scrub); kfree(ubi->lookuptbl); diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c index 1c5344aa57cc..367bec63620c 100644 --- a/drivers/net/3c501.c +++ b/drivers/net/3c501.c @@ -281,7 +281,7 @@ static int __init el1_probe1(struct net_device *dev, int ioaddr) autoirq = probe_irq_off(irq_mask); if (autoirq == 0) { - printk(KERN_WARNING "%s probe at %#x failed to detect IRQ line.\n", + pr_warning("%s probe at %#x failed to detect IRQ line.\n", mname, ioaddr); release_region(ioaddr, EL1_IO_EXTENT); return -EAGAIN; @@ -297,16 +297,16 @@ static int __init el1_probe1(struct net_device *dev, int ioaddr) if (autoirq) dev->irq = autoirq; - printk(KERN_INFO "%s: %s EtherLink at %#lx, using %sIRQ %d.\n", + pr_info("%s: %s EtherLink at %#lx, using %sIRQ %d.\n", dev->name, mname, dev->base_addr, autoirq ? "auto":"assigned ", dev->irq); #ifdef CONFIG_IP_MULTICAST - printk(KERN_WARNING "WARNING: Use of the 3c501 in a multicast kernel is NOT recommended.\n"); + pr_warning("WARNING: Use of the 3c501 in a multicast kernel is NOT recommended.\n"); #endif if (el_debug) - printk(KERN_DEBUG "%s", version); + pr_debug("%s", version); lp = netdev_priv(dev); memset(lp, 0, sizeof(struct net_local)); @@ -343,7 +343,7 @@ static int el_open(struct net_device *dev) unsigned long flags; if (el_debug > 2) - printk(KERN_DEBUG "%s: Doing el_open()...", dev->name); + pr_debug("%s: Doing el_open()...\n", dev->name); retval = request_irq(dev->irq, &el_interrupt, 0, dev->name, dev); if (retval) @@ -374,7 +374,7 @@ static void el_timeout(struct net_device *dev) int ioaddr = dev->base_addr; if (el_debug) - printk(KERN_DEBUG "%s: transmit timed out, txsr %#2x axsr=%02x rxsr=%02x.\n", + pr_debug("%s: transmit timed out, txsr %#2x axsr=%02x rxsr=%02x.\n", dev->name, inb(TX_STATUS), inb(AX_STATUS), inb(RX_STATUS)); dev->stats.tx_errors++; @@ -483,14 +483,13 @@ static int el_start_xmit(struct sk_buff *skb, struct net_device *dev) lp->loading = 0; dev->trans_start = jiffies; if (el_debug > 2) - printk(KERN_DEBUG " queued xmit.\n"); + pr_debug(" queued xmit.\n"); dev_kfree_skb(skb); return 0; } /* A receive upset our load, despite our best efforts */ if (el_debug > 2) - printk(KERN_DEBUG "%s: burped during tx load.\n", - dev->name); + pr_debug("%s: burped during tx load.\n", dev->name); spin_lock_irqsave(&lp->lock, flags); } while (1); } @@ -540,11 +539,10 @@ static irqreturn_t el_interrupt(int irq, void *dev_id) */ if (el_debug > 3) - printk(KERN_DEBUG "%s: el_interrupt() aux=%#02x", - dev->name, axsr); + pr_debug("%s: el_interrupt() aux=%#02x\n", dev->name, axsr); if (lp->loading == 1 && !lp->txing) - printk(KERN_WARNING "%s: Inconsistent state loading while not in tx\n", + pr_warning("%s: Inconsistent state loading while not in tx\n", dev->name); if (lp->txing) { @@ -555,19 +553,17 @@ static irqreturn_t el_interrupt(int irq, void *dev_id) int txsr = inb(TX_STATUS); if (lp->loading == 1) { - if (el_debug > 2) { - printk(KERN_DEBUG "%s: Interrupt while loading [", - dev->name); - printk(" txsr=%02x gp=%04x rp=%04x]\n", - txsr, inw(GP_LOW), inw(RX_LOW)); - } + if (el_debug > 2) + pr_debug("%s: Interrupt while loading [txsr=%02x gp=%04x rp=%04x]\n", + dev->name, txsr, inw(GP_LOW), inw(RX_LOW)); + /* Force a reload */ lp->loading = 2; spin_unlock(&lp->lock); goto out; } if (el_debug > 6) - printk(KERN_DEBUG " txsr=%02x gp=%04x rp=%04x", + pr_debug("%s: txsr=%02x gp=%04x rp=%04x\n", dev->name, txsr, inw(GP_LOW), inw(RX_LOW)); if ((axsr & 0x80) && (txsr & TX_READY) == 0) { @@ -576,7 +572,7 @@ static irqreturn_t el_interrupt(int irq, void *dev_id) * on trying or reset immediately ? */ if (el_debug > 1) - printk(KERN_DEBUG "%s: Unusual interrupt during Tx, txsr=%02x axsr=%02x gp=%03x rp=%03x.\n", + pr_debug("%s: Unusual interrupt during Tx, txsr=%02x axsr=%02x gp=%03x rp=%03x.\n", dev->name, txsr, axsr, inw(ioaddr + EL1_DATAPTR), inw(ioaddr + EL1_RXPTR)); @@ -587,7 +583,7 @@ static irqreturn_t el_interrupt(int irq, void *dev_id) * Timed out */ if (el_debug) - printk(KERN_DEBUG "%s: Transmit failed 16 times, Ethernet jammed?\n", dev->name); + pr_debug("%s: Transmit failed 16 times, Ethernet jammed?\n", dev->name); outb(AX_SYS, AX_CMD); lp->txing = 0; dev->stats.tx_aborted_errors++; @@ -598,7 +594,7 @@ static irqreturn_t el_interrupt(int irq, void *dev_id) */ if (el_debug > 6) - printk(KERN_DEBUG " retransmitting after a collision.\n"); + pr_debug("%s: retransmitting after a collision.\n", dev->name); /* * Poor little chip can't reset its own start * pointer @@ -616,9 +612,8 @@ static irqreturn_t el_interrupt(int irq, void *dev_id) */ dev->stats.tx_packets++; if (el_debug > 6) - printk(KERN_DEBUG " Tx succeeded %s\n", - (txsr & TX_RDY) ? "." : - "but tx is busy!"); + pr_debug("%s: Tx succeeded %s\n", dev->name, + (txsr & TX_RDY) ? "." : "but tx is busy!"); /* * This is safe the interrupt is atomic WRT itself. */ @@ -633,7 +628,8 @@ static irqreturn_t el_interrupt(int irq, void *dev_id) int rxsr = inb(RX_STATUS); if (el_debug > 5) - printk(KERN_DEBUG " rxsr=%02x txsr=%02x rp=%04x", rxsr, inb(TX_STATUS), inw(RX_LOW)); + pr_debug("%s: rxsr=%02x txsr=%02x rp=%04x\n", + dev->name, rxsr, inb(TX_STATUS), inw(RX_LOW)); /* * Just reading rx_status fixes most errors. */ @@ -643,7 +639,7 @@ static irqreturn_t el_interrupt(int irq, void *dev_id) /* Handled to avoid board lock-up. */ dev->stats.rx_length_errors++; if (el_debug > 5) - printk(KERN_DEBUG " runt.\n"); + pr_debug("%s: runt.\n", dev->name); } else if (rxsr & RX_GOOD) { /* * Receive worked. @@ -654,12 +650,10 @@ static irqreturn_t el_interrupt(int irq, void *dev_id) * Nothing? Something is broken! */ if (el_debug > 2) - printk(KERN_DEBUG "%s: No packet seen, rxsr=%02x **resetting 3c501***\n", + pr_debug("%s: No packet seen, rxsr=%02x **resetting 3c501***\n", dev->name, rxsr); el_reset(dev); } - if (el_debug > 3) - printk(KERN_DEBUG ".\n"); } /* @@ -695,11 +689,11 @@ static void el_receive(struct net_device *dev) pkt_len = inw(RX_LOW); if (el_debug > 4) - printk(KERN_DEBUG " el_receive %d.\n", pkt_len); + pr_debug(" el_receive %d.\n", pkt_len); if (pkt_len < 60 || pkt_len > 1536) { if (el_debug) - printk(KERN_DEBUG "%s: bogus packet, length=%d\n", + pr_debug("%s: bogus packet, length=%d\n", dev->name, pkt_len); dev->stats.rx_over_errors++; return; @@ -718,8 +712,7 @@ static void el_receive(struct net_device *dev) outw(0x00, GP_LOW); if (skb == NULL) { - printk(KERN_INFO "%s: Memory squeeze, dropping packet.\n", - dev->name); + pr_info("%s: Memory squeeze, dropping packet.\n", dev->name); dev->stats.rx_dropped++; return; } else { @@ -753,7 +746,7 @@ static void el_reset(struct net_device *dev) int ioaddr = dev->base_addr; if (el_debug > 2) - printk(KERN_INFO "3c501 reset..."); + pr_info("3c501 reset...\n"); outb(AX_RESET, AX_CMD); /* Reset the chip */ /* Aux control, irq and loopback enabled */ outb(AX_LOOP, AX_CMD); @@ -787,7 +780,7 @@ static int el1_close(struct net_device *dev) int ioaddr = dev->base_addr; if (el_debug > 2) - printk(KERN_INFO "%s: Shutting down Ethernet card at %#x.\n", + pr_info("%s: Shutting down Ethernet card at %#x.\n", dev->name, ioaddr); netif_stop_queue(dev); diff --git a/drivers/net/3c503.c b/drivers/net/3c503.c index 4f08bd995836..134638a9759f 100644 --- a/drivers/net/3c503.c +++ b/drivers/net/3c503.c @@ -234,16 +234,16 @@ el2_probe1(struct net_device *dev, int ioaddr) } if (ei_debug && version_printed++ == 0) - printk(version); + pr_debug("%s", version); dev->base_addr = ioaddr; - printk("%s: 3c503 at i/o base %#3x, node ", dev->name, ioaddr); + pr_info("%s: 3c503 at i/o base %#3x, node ", dev->name, ioaddr); /* Retrieve and print the ethernet address. */ for (i = 0; i < 6; i++) dev->dev_addr[i] = inb(ioaddr + i); - printk("%pM", dev->dev_addr); + pr_cont("%pM", dev->dev_addr); /* Map the 8390 back into the window. */ outb(ECNTRL_THIN, ioaddr + 0x406); @@ -256,7 +256,8 @@ el2_probe1(struct net_device *dev, int ioaddr) outb_p(E8390_PAGE0, ioaddr + E8390_CMD); /* Probe for, turn on and clear the board's shared memory. */ - if (ei_debug > 2) printk(" memory jumpers %2.2x ", membase_reg); + if (ei_debug > 2) + pr_cont(" memory jumpers %2.2x ", membase_reg); outb(EGACFR_NORM, ioaddr + 0x405); /* Enable RAM */ /* This should be probed for (or set via an ioctl()) at run-time. @@ -268,7 +269,7 @@ el2_probe1(struct net_device *dev, int ioaddr) #else ei_status.interface_num = dev->mem_end & 0xf; #endif - printk(", using %sternal xcvr.\n", ei_status.interface_num == 0 ? "in" : "ex"); + pr_cont(", using %sternal xcvr.\n", ei_status.interface_num == 0 ? "in" : "ex"); if ((membase_reg & 0xf0) == 0) { dev->mem_start = 0; @@ -292,7 +293,7 @@ el2_probe1(struct net_device *dev, int ioaddr) writel(test_val, mem_base + i); if (readl(mem_base) != 0xba5eba5e || readl(mem_base + i) != test_val) { - printk("3c503: memory failure or memory address conflict.\n"); + pr_warning("3c503: memory failure or memory address conflict.\n"); dev->mem_start = 0; ei_status.name = "3c503-PIO"; iounmap(mem_base); @@ -344,7 +345,7 @@ el2_probe1(struct net_device *dev, int ioaddr) if (dev->irq == 2) dev->irq = 9; else if (dev->irq > 5 && dev->irq != 9) { - printk("3c503: configured interrupt %d invalid, will use autoIRQ.\n", + pr_warning("3c503: configured interrupt %d invalid, will use autoIRQ.\n", dev->irq); dev->irq = 0; } @@ -359,7 +360,7 @@ el2_probe1(struct net_device *dev, int ioaddr) goto out1; if (dev->mem_start) - printk("%s: %s - %dkB RAM, 8kB shared mem window at %#6lx-%#6lx.\n", + pr_info("%s: %s - %dkB RAM, 8kB shared mem window at %#6lx-%#6lx.\n", dev->name, ei_status.name, (wordlength+1)<<3, dev->mem_start, dev->mem_end-1); @@ -367,7 +368,7 @@ el2_probe1(struct net_device *dev, int ioaddr) { ei_status.tx_start_page = EL2_MB1_START_PG; ei_status.rx_start_page = EL2_MB1_START_PG + TX_PAGES; - printk("\n%s: %s, %dkB RAM, using programmed I/O (REJUMPER for SHARED MEMORY).\n", + pr_info("%s: %s, %dkB RAM, using programmed I/O (REJUMPER for SHARED MEMORY).\n", dev->name, ei_status.name, (wordlength+1)<<3); } release_region(ioaddr + 0x400, 8); @@ -435,15 +436,16 @@ static void el2_reset_8390(struct net_device *dev) { if (ei_debug > 1) { - printk("%s: Resetting the 3c503 board...", dev->name); - printk("%#lx=%#02x %#lx=%#02x %#lx=%#02x...", E33G_IDCFR, inb(E33G_IDCFR), + pr_debug("%s: Resetting the 3c503 board...", dev->name); + pr_cont(" %#lx=%#02x %#lx=%#02x %#lx=%#02x...", E33G_IDCFR, inb(E33G_IDCFR), E33G_CNTRL, inb(E33G_CNTRL), E33G_GACFR, inb(E33G_GACFR)); } outb_p(ECNTRL_RESET|ECNTRL_THIN, E33G_CNTRL); ei_status.txing = 0; outb_p(ei_status.interface_num==0 ? ECNTRL_THIN : ECNTRL_AUI, E33G_CNTRL); el2_init_card(dev); - if (ei_debug > 1) printk("done\n"); + if (ei_debug > 1) + pr_cont("done\n"); } /* Initialize the 3c503 GA registers after a reset. */ @@ -529,7 +531,7 @@ el2_block_output(struct net_device *dev, int count, { if(!boguscount--) { - printk("%s: FIFO blocked in el2_block_output.\n", dev->name); + pr_notice("%s: FIFO blocked in el2_block_output.\n", dev->name); el2_reset_8390(dev); goto blocked; } @@ -581,7 +583,7 @@ el2_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_pag { if(!boguscount--) { - printk("%s: FIFO blocked in el2_get_8390_hdr.\n", dev->name); + pr_notice("%s: FIFO blocked in el2_get_8390_hdr.\n", dev->name); memset(hdr, 0x00, sizeof(struct e8390_pkt_hdr)); el2_reset_8390(dev); goto blocked; @@ -645,7 +647,7 @@ el2_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring { if(!boguscount--) { - printk("%s: FIFO blocked in el2_block_input.\n", dev->name); + pr_notice("%s: FIFO blocked in el2_block_input.\n", dev->name); el2_reset_8390(dev); goto blocked; } @@ -707,7 +709,7 @@ init_module(void) for (this_dev = 0; this_dev < MAX_EL2_CARDS; this_dev++) { if (io[this_dev] == 0) { if (this_dev != 0) break; /* only autoprobe 1st one */ - printk(KERN_NOTICE "3c503.c: Presently autoprobing (not recommended) for a single card.\n"); + pr_notice("3c503.c: Presently autoprobing (not recommended) for a single card.\n"); } dev = alloc_eip_netdev(); if (!dev) @@ -720,7 +722,7 @@ init_module(void) continue; } free_netdev(dev); - printk(KERN_WARNING "3c503.c: No 3c503 card found (i/o = 0x%x).\n", io[this_dev]); + pr_warning("3c503.c: No 3c503 card found (i/o = 0x%x).\n", io[this_dev]); break; } if (found) diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c index 2de1c9cd7bde..f71b35402755 100644 --- a/drivers/net/3c505.c +++ b/drivers/net/3c505.c @@ -126,26 +126,25 @@ * *********************************************************/ -static const char filename[] = __FILE__; +#define filename __FILE__ -static const char timeout_msg[] = "*** timeout at %s:%s (line %d) ***\n"; +#define timeout_msg "*** timeout at %s:%s (line %d) ***\n" #define TIMEOUT_MSG(lineno) \ - printk(timeout_msg, filename,__func__,(lineno)) + pr_notice(timeout_msg, filename, __func__, (lineno)) -static const char invalid_pcb_msg[] = -"*** invalid pcb length %d at %s:%s (line %d) ***\n"; +#define invalid_pcb_msg "*** invalid pcb length %d at %s:%s (line %d) ***\n" #define INVALID_PCB_MSG(len) \ - printk(invalid_pcb_msg, (len),filename,__func__,__LINE__) + pr_notice(invalid_pcb_msg, (len), filename, __func__, __LINE__) -static char search_msg[] __initdata = KERN_INFO "%s: Looking for 3c505 adapter at address %#x..."; +#define search_msg "%s: Looking for 3c505 adapter at address %#x..." -static char stilllooking_msg[] __initdata = "still looking..."; +#define stilllooking_msg "still looking..." -static char found_msg[] __initdata = "found.\n"; +#define found_msg "found.\n" -static char notfound_msg[] __initdata = "not found (reason = %d)\n"; +#define notfound_msg "not found (reason = %d)\n" -static char couldnot_msg[] __initdata = KERN_INFO "%s: 3c505 not found\n"; +#define couldnot_msg "%s: 3c505 not found\n" /********************************************************* * @@ -284,7 +283,7 @@ static inline void adapter_reset(struct net_device *dev) outb_control(orig_hcr, dev); if (!start_receive(dev, &adapter->tx_pcb)) - printk(KERN_ERR "%s: start receive command failed \n", dev->name); + pr_err("%s: start receive command failed\n", dev->name); } /* Check to make sure that a DMA transfer hasn't timed out. This should @@ -296,7 +295,9 @@ static inline void check_3c505_dma(struct net_device *dev) elp_device *adapter = netdev_priv(dev); if (adapter->dmaing && time_after(jiffies, adapter->current_dma.start_time + 10)) { unsigned long flags, f; - printk(KERN_ERR "%s: DMA %s timed out, %d bytes left\n", dev->name, adapter->current_dma.direction ? "download" : "upload", get_dma_residue(dev->dma)); + pr_err("%s: DMA %s timed out, %d bytes left\n", dev->name, + adapter->current_dma.direction ? "download" : "upload", + get_dma_residue(dev->dma)); spin_lock_irqsave(&adapter->lock, flags); adapter->dmaing = 0; adapter->busy = 0; @@ -321,7 +322,7 @@ static inline bool send_pcb_slow(unsigned int base_addr, unsigned char byte) if (inb_status(base_addr) & HCRE) return false; } - printk(KERN_WARNING "3c505: send_pcb_slow timed out\n"); + pr_warning("3c505: send_pcb_slow timed out\n"); return true; } @@ -333,7 +334,7 @@ static inline bool send_pcb_fast(unsigned int base_addr, unsigned char byte) if (inb_status(base_addr) & HCRE) return false; } - printk(KERN_WARNING "3c505: send_pcb_fast timed out\n"); + pr_warning("3c505: send_pcb_fast timed out\n"); return true; } @@ -386,7 +387,7 @@ static bool send_pcb(struct net_device *dev, pcb_struct * pcb) /* Avoid contention */ if (test_and_set_bit(1, &adapter->send_pcb_semaphore)) { if (elp_debug >= 3) { - printk(KERN_DEBUG "%s: send_pcb entered while threaded\n", dev->name); + pr_debug("%s: send_pcb entered while threaded\n", dev->name); } return false; } @@ -424,14 +425,15 @@ static bool send_pcb(struct net_device *dev, pcb_struct * pcb) case ASF_PCB_NAK: #ifdef ELP_DEBUG - printk(KERN_DEBUG "%s: send_pcb got NAK\n", dev->name); + pr_debug("%s: send_pcb got NAK\n", dev->name); #endif goto abort; } } if (elp_debug >= 1) - printk(KERN_DEBUG "%s: timeout waiting for PCB acknowledge (status %02x)\n", dev->name, inb_status(dev->base_addr)); + pr_debug("%s: timeout waiting for PCB acknowledge (status %02x)\n", + dev->name, inb_status(dev->base_addr)); goto abort; sti_abort: @@ -481,7 +483,7 @@ static bool receive_pcb(struct net_device *dev, pcb_struct * pcb) while (((stat = get_status(dev->base_addr)) & ACRF) == 0 && time_before(jiffies, timeout)); if (time_after_eq(jiffies, timeout)) { TIMEOUT_MSG(__LINE__); - printk(KERN_INFO "%s: status %02x\n", dev->name, stat); + pr_info("%s: status %02x\n", dev->name, stat); return false; } pcb->length = inb_command(dev->base_addr); @@ -518,7 +520,7 @@ static bool receive_pcb(struct net_device *dev, pcb_struct * pcb) /* safety check total length vs data length */ if (total_length != (pcb->length + 2)) { if (elp_debug >= 2) - printk(KERN_WARNING "%s: mangled PCB received\n", dev->name); + pr_warning("%s: mangled PCB received\n", dev->name); set_hsf(dev, HSF_PCB_NAK); return false; } @@ -527,7 +529,7 @@ static bool receive_pcb(struct net_device *dev, pcb_struct * pcb) if (test_and_set_bit(0, (void *) &adapter->busy)) { if (backlog_next(adapter->rx_backlog.in) == adapter->rx_backlog.out) { set_hsf(dev, HSF_PCB_NAK); - printk(KERN_WARNING "%s: PCB rejected, transfer in progress and backlog full\n", dev->name); + pr_warning("%s: PCB rejected, transfer in progress and backlog full\n", dev->name); pcb->command = 0; return true; } else { @@ -552,7 +554,7 @@ static bool start_receive(struct net_device *dev, pcb_struct * tx_pcb) elp_device *adapter = netdev_priv(dev); if (elp_debug >= 3) - printk(KERN_DEBUG "%s: restarting receiver\n", dev->name); + pr_debug("%s: restarting receiver\n", dev->name); tx_pcb->command = CMD_RECEIVE_PACKET; tx_pcb->length = sizeof(struct Rcv_pkt); tx_pcb->data.rcv_pkt.buf_seg @@ -586,7 +588,7 @@ static void receive_packet(struct net_device *dev, int len) skb = dev_alloc_skb(rlen + 2); if (!skb) { - printk(KERN_WARNING "%s: memory squeeze, dropping packet\n", dev->name); + pr_warning("%s: memory squeeze, dropping packet\n", dev->name); target = adapter->dma_buffer; adapter->current_dma.target = NULL; /* FIXME: stats */ @@ -604,7 +606,8 @@ static void receive_packet(struct net_device *dev, int len) /* if this happens, we die */ if (test_and_set_bit(0, (void *) &adapter->dmaing)) - printk(KERN_ERR "%s: rx blocked, DMA in progress, dir %d\n", dev->name, adapter->current_dma.direction); + pr_err("%s: rx blocked, DMA in progress, dir %d\n", + dev->name, adapter->current_dma.direction); adapter->current_dma.direction = 0; adapter->current_dma.length = rlen; @@ -623,14 +626,14 @@ static void receive_packet(struct net_device *dev, int len) release_dma_lock(flags); if (elp_debug >= 3) { - printk(KERN_DEBUG "%s: rx DMA transfer started\n", dev->name); + pr_debug("%s: rx DMA transfer started\n", dev->name); } if (adapter->rx_active) adapter->rx_active--; if (!adapter->busy) - printk(KERN_WARNING "%s: receive_packet called, busy not set.\n", dev->name); + pr_warning("%s: receive_packet called, busy not set.\n", dev->name); } /****************************************************** @@ -655,12 +658,13 @@ static irqreturn_t elp_interrupt(int irq, void *dev_id) * has a DMA transfer finished? */ if (inb_status(dev->base_addr) & DONE) { - if (!adapter->dmaing) { - printk(KERN_WARNING "%s: phantom DMA completed\n", dev->name); - } - if (elp_debug >= 3) { - printk(KERN_DEBUG "%s: %s DMA complete, status %02x\n", dev->name, adapter->current_dma.direction ? "tx" : "rx", inb_status(dev->base_addr)); - } + if (!adapter->dmaing) + pr_warning("%s: phantom DMA completed\n", dev->name); + + if (elp_debug >= 3) + pr_debug("%s: %s DMA complete, status %02x\n", dev->name, + adapter->current_dma.direction ? "tx" : "rx", + inb_status(dev->base_addr)); outb_control(adapter->hcr_val & ~(DMAE | TCEN | DIR), dev); if (adapter->current_dma.direction) { @@ -682,7 +686,7 @@ static irqreturn_t elp_interrupt(int irq, void *dev_id) int t = adapter->rx_backlog.length[adapter->rx_backlog.out]; adapter->rx_backlog.out = backlog_next(adapter->rx_backlog.out); if (elp_debug >= 2) - printk(KERN_DEBUG "%s: receiving backlogged packet (%d)\n", dev->name, t); + pr_debug("%s: receiving backlogged packet (%d)\n", dev->name, t); receive_packet(dev, t); } else { adapter->busy = 0; @@ -713,21 +717,23 @@ static irqreturn_t elp_interrupt(int irq, void *dev_id) len = adapter->irx_pcb.data.rcv_resp.pkt_len; dlen = adapter->irx_pcb.data.rcv_resp.buf_len; if (adapter->irx_pcb.data.rcv_resp.timeout != 0) { - printk(KERN_ERR "%s: interrupt - packet not received correctly\n", dev->name); + pr_err("%s: interrupt - packet not received correctly\n", dev->name); } else { if (elp_debug >= 3) { - printk(KERN_DEBUG "%s: interrupt - packet received of length %i (%i)\n", dev->name, len, dlen); + pr_debug("%s: interrupt - packet received of length %i (%i)\n", + dev->name, len, dlen); } if (adapter->irx_pcb.command == 0xff) { if (elp_debug >= 2) - printk(KERN_DEBUG "%s: adding packet to backlog (len = %d)\n", dev->name, dlen); + pr_debug("%s: adding packet to backlog (len = %d)\n", + dev->name, dlen); adapter->rx_backlog.length[adapter->rx_backlog.in] = dlen; adapter->rx_backlog.in = backlog_next(adapter->rx_backlog.in); } else { receive_packet(dev, dlen); } if (elp_debug >= 3) - printk(KERN_DEBUG "%s: packet received\n", dev->name); + pr_debug("%s: packet received\n", dev->name); } break; @@ -737,7 +743,7 @@ static irqreturn_t elp_interrupt(int irq, void *dev_id) case CMD_CONFIGURE_82586_RESPONSE: adapter->got[CMD_CONFIGURE_82586] = 1; if (elp_debug >= 3) - printk(KERN_DEBUG "%s: interrupt - configure response received\n", dev->name); + pr_debug("%s: interrupt - configure response received\n", dev->name); break; /* @@ -746,7 +752,7 @@ static irqreturn_t elp_interrupt(int irq, void *dev_id) case CMD_CONFIGURE_ADAPTER_RESPONSE: adapter->got[CMD_CONFIGURE_ADAPTER_MEMORY] = 1; if (elp_debug >= 3) - printk(KERN_DEBUG "%s: Adapter memory configuration %s.\n", dev->name, + pr_debug("%s: Adapter memory configuration %s.\n", dev->name, adapter->irx_pcb.data.failed ? "failed" : "succeeded"); break; @@ -756,7 +762,7 @@ static irqreturn_t elp_interrupt(int irq, void *dev_id) case CMD_LOAD_MULTICAST_RESPONSE: adapter->got[CMD_LOAD_MULTICAST_LIST] = 1; if (elp_debug >= 3) - printk(KERN_DEBUG "%s: Multicast address list loading %s.\n", dev->name, + pr_debug("%s: Multicast address list loading %s.\n", dev->name, adapter->irx_pcb.data.failed ? "failed" : "succeeded"); break; @@ -766,7 +772,7 @@ static irqreturn_t elp_interrupt(int irq, void *dev_id) case CMD_SET_ADDRESS_RESPONSE: adapter->got[CMD_SET_STATION_ADDRESS] = 1; if (elp_debug >= 3) - printk(KERN_DEBUG "%s: Ethernet address setting %s.\n", dev->name, + pr_debug("%s: Ethernet address setting %s.\n", dev->name, adapter->irx_pcb.data.failed ? "failed" : "succeeded"); break; @@ -783,7 +789,7 @@ static irqreturn_t elp_interrupt(int irq, void *dev_id) dev->stats.rx_over_errors += adapter->irx_pcb.data.netstat.err_res; adapter->got[CMD_NETWORK_STATISTICS] = 1; if (elp_debug >= 3) - printk(KERN_DEBUG "%s: interrupt - statistics response received\n", dev->name); + pr_debug("%s: interrupt - statistics response received\n", dev->name); break; /* @@ -791,17 +797,17 @@ static irqreturn_t elp_interrupt(int irq, void *dev_id) */ case CMD_TRANSMIT_PACKET_COMPLETE: if (elp_debug >= 3) - printk(KERN_DEBUG "%s: interrupt - packet sent\n", dev->name); + pr_debug("%s: interrupt - packet sent\n", dev->name); if (!netif_running(dev)) break; switch (adapter->irx_pcb.data.xmit_resp.c_stat) { case 0xffff: dev->stats.tx_aborted_errors++; - printk(KERN_INFO "%s: transmit timed out, network cable problem?\n", dev->name); + pr_info("%s: transmit timed out, network cable problem?\n", dev->name); break; case 0xfffe: dev->stats.tx_fifo_errors++; - printk(KERN_INFO "%s: transmit timed out, FIFO underrun\n", dev->name); + pr_info("%s: transmit timed out, FIFO underrun\n", dev->name); break; } netif_wake_queue(dev); @@ -811,11 +817,12 @@ static irqreturn_t elp_interrupt(int irq, void *dev_id) * some unknown PCB */ default: - printk(KERN_DEBUG "%s: unknown PCB received - %2.2x\n", dev->name, adapter->irx_pcb.command); + pr_debug("%s: unknown PCB received - %2.2x\n", + dev->name, adapter->irx_pcb.command); break; } } else { - printk(KERN_WARNING "%s: failed to read PCB on interrupt\n", dev->name); + pr_warning("%s: failed to read PCB on interrupt\n", dev->name); adapter_reset(dev); } } @@ -844,13 +851,13 @@ static int elp_open(struct net_device *dev) int retval; if (elp_debug >= 3) - printk(KERN_DEBUG "%s: request to open device\n", dev->name); + pr_debug("%s: request to open device\n", dev->name); /* * make sure we actually found the device */ if (adapter == NULL) { - printk(KERN_ERR "%s: Opening a non-existent physical device\n", dev->name); + pr_err("%s: Opening a non-existent physical device\n", dev->name); return -EAGAIN; } /* @@ -880,17 +887,17 @@ static int elp_open(struct net_device *dev) * install our interrupt service routine */ if ((retval = request_irq(dev->irq, &elp_interrupt, 0, dev->name, dev))) { - printk(KERN_ERR "%s: could not allocate IRQ%d\n", dev->name, dev->irq); + pr_err("%s: could not allocate IRQ%d\n", dev->name, dev->irq); return retval; } if ((retval = request_dma(dev->dma, dev->name))) { free_irq(dev->irq, dev); - printk(KERN_ERR "%s: could not allocate DMA%d channel\n", dev->name, dev->dma); + pr_err("%s: could not allocate DMA%d channel\n", dev->name, dev->dma); return retval; } adapter->dma_buffer = (void *) dma_mem_alloc(DMA_BUFFER_SIZE); if (!adapter->dma_buffer) { - printk(KERN_ERR "%s: could not allocate DMA buffer\n", dev->name); + pr_err("%s: could not allocate DMA buffer\n", dev->name); free_dma(dev->dma); free_irq(dev->irq, dev); return -ENOMEM; @@ -906,7 +913,7 @@ static int elp_open(struct net_device *dev) * configure adapter memory: we need 10 multicast addresses, default==0 */ if (elp_debug >= 3) - printk(KERN_DEBUG "%s: sending 3c505 memory configuration command\n", dev->name); + pr_debug("%s: sending 3c505 memory configuration command\n", dev->name); adapter->tx_pcb.command = CMD_CONFIGURE_ADAPTER_MEMORY; adapter->tx_pcb.data.memconf.cmd_q = 10; adapter->tx_pcb.data.memconf.rcv_q = 20; @@ -917,7 +924,7 @@ static int elp_open(struct net_device *dev) adapter->tx_pcb.length = sizeof(struct Memconf); adapter->got[CMD_CONFIGURE_ADAPTER_MEMORY] = 0; if (!send_pcb(dev, &adapter->tx_pcb)) - printk(KERN_ERR "%s: couldn't send memory configuration command\n", dev->name); + pr_err("%s: couldn't send memory configuration command\n", dev->name); else { unsigned long timeout = jiffies + TIMEOUT; while (adapter->got[CMD_CONFIGURE_ADAPTER_MEMORY] == 0 && time_before(jiffies, timeout)); @@ -930,13 +937,13 @@ static int elp_open(struct net_device *dev) * configure adapter to receive broadcast messages and wait for response */ if (elp_debug >= 3) - printk(KERN_DEBUG "%s: sending 82586 configure command\n", dev->name); + pr_debug("%s: sending 82586 configure command\n", dev->name); adapter->tx_pcb.command = CMD_CONFIGURE_82586; adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_BROAD; adapter->tx_pcb.length = 2; adapter->got[CMD_CONFIGURE_82586] = 0; if (!send_pcb(dev, &adapter->tx_pcb)) - printk(KERN_ERR "%s: couldn't send 82586 configure command\n", dev->name); + pr_err("%s: couldn't send 82586 configure command\n", dev->name); else { unsigned long timeout = jiffies + TIMEOUT; while (adapter->got[CMD_CONFIGURE_82586] == 0 && time_before(jiffies, timeout)); @@ -952,7 +959,7 @@ static int elp_open(struct net_device *dev) */ prime_rx(dev); if (elp_debug >= 3) - printk(KERN_DEBUG "%s: %d receive PCBs active\n", dev->name, adapter->rx_active); + pr_debug("%s: %d receive PCBs active\n", dev->name, adapter->rx_active); /* * device is now officially open! @@ -982,7 +989,7 @@ static bool send_packet(struct net_device *dev, struct sk_buff *skb) if (test_and_set_bit(0, (void *) &adapter->busy)) { if (elp_debug >= 2) - printk(KERN_DEBUG "%s: transmit blocked\n", dev->name); + pr_debug("%s: transmit blocked\n", dev->name); return false; } @@ -1004,7 +1011,7 @@ static bool send_packet(struct net_device *dev, struct sk_buff *skb) } /* if this happens, we die */ if (test_and_set_bit(0, (void *) &adapter->dmaing)) - printk(KERN_DEBUG "%s: tx: DMA %d in progress\n", dev->name, adapter->current_dma.direction); + pr_debug("%s: tx: DMA %d in progress\n", dev->name, adapter->current_dma.direction); adapter->current_dma.direction = 1; adapter->current_dma.start_time = jiffies; @@ -1030,7 +1037,7 @@ static bool send_packet(struct net_device *dev, struct sk_buff *skb) release_dma_lock(flags); if (elp_debug >= 3) - printk(KERN_DEBUG "%s: DMA transfer started\n", dev->name); + pr_debug("%s: DMA transfer started\n", dev->name); return true; } @@ -1044,9 +1051,10 @@ static void elp_timeout(struct net_device *dev) int stat; stat = inb_status(dev->base_addr); - printk(KERN_WARNING "%s: transmit timed out, lost %s?\n", dev->name, (stat & ACRF) ? "interrupt" : "command"); + pr_warning("%s: transmit timed out, lost %s?\n", dev->name, + (stat & ACRF) ? "interrupt" : "command"); if (elp_debug >= 1) - printk(KERN_DEBUG "%s: status %#02x\n", dev->name, stat); + pr_debug("%s: status %#02x\n", dev->name, stat); dev->trans_start = jiffies; dev->stats.tx_dropped++; netif_wake_queue(dev); @@ -1068,7 +1076,7 @@ static int elp_start_xmit(struct sk_buff *skb, struct net_device *dev) check_3c505_dma(dev); if (elp_debug >= 3) - printk(KERN_DEBUG "%s: request to send packet of length %d\n", dev->name, (int) skb->len); + pr_debug("%s: request to send packet of length %d\n", dev->name, (int) skb->len); netif_stop_queue(dev); @@ -1077,13 +1085,13 @@ static int elp_start_xmit(struct sk_buff *skb, struct net_device *dev) */ if (!send_packet(dev, skb)) { if (elp_debug >= 2) { - printk(KERN_DEBUG "%s: failed to transmit packet\n", dev->name); + pr_debug("%s: failed to transmit packet\n", dev->name); } spin_unlock_irqrestore(&adapter->lock, flags); - return 1; + return NETDEV_TX_BUSY; } if (elp_debug >= 3) - printk(KERN_DEBUG "%s: packet of length %d sent\n", dev->name, (int) skb->len); + pr_debug("%s: packet of length %d sent\n", dev->name, (int) skb->len); /* * start the transmit timeout @@ -1107,7 +1115,7 @@ static struct net_device_stats *elp_get_stats(struct net_device *dev) elp_device *adapter = netdev_priv(dev); if (elp_debug >= 3) - printk(KERN_DEBUG "%s: request for stats\n", dev->name); + pr_debug("%s: request for stats\n", dev->name); /* If the device is closed, just return the latest stats we have, - we cannot ask from the adapter without interrupts */ @@ -1119,7 +1127,7 @@ static struct net_device_stats *elp_get_stats(struct net_device *dev) adapter->tx_pcb.length = 0; adapter->got[CMD_NETWORK_STATISTICS] = 0; if (!send_pcb(dev, &adapter->tx_pcb)) - printk(KERN_ERR "%s: couldn't send get statistics command\n", dev->name); + pr_err("%s: couldn't send get statistics command\n", dev->name); else { unsigned long timeout = jiffies + TIMEOUT; while (adapter->got[CMD_NETWORK_STATISTICS] == 0 && time_before(jiffies, timeout)); @@ -1169,7 +1177,7 @@ static int elp_close(struct net_device *dev) elp_device *adapter = netdev_priv(dev); if (elp_debug >= 3) - printk(KERN_DEBUG "%s: request to close device\n", dev->name); + pr_debug("%s: request to close device\n", dev->name); netif_stop_queue(dev); @@ -1213,7 +1221,7 @@ static void elp_set_mc_list(struct net_device *dev) unsigned long flags; if (elp_debug >= 3) - printk(KERN_DEBUG "%s: request to set multicast list\n", dev->name); + pr_debug("%s: request to set multicast list\n", dev->name); spin_lock_irqsave(&adapter->lock, flags); @@ -1228,7 +1236,7 @@ static void elp_set_mc_list(struct net_device *dev) } adapter->got[CMD_LOAD_MULTICAST_LIST] = 0; if (!send_pcb(dev, &adapter->tx_pcb)) - printk(KERN_ERR "%s: couldn't send set_multicast command\n", dev->name); + pr_err("%s: couldn't send set_multicast command\n", dev->name); else { unsigned long timeout = jiffies + TIMEOUT; while (adapter->got[CMD_LOAD_MULTICAST_LIST] == 0 && time_before(jiffies, timeout)); @@ -1247,14 +1255,14 @@ static void elp_set_mc_list(struct net_device *dev) * and wait for response */ if (elp_debug >= 3) - printk(KERN_DEBUG "%s: sending 82586 configure command\n", dev->name); + pr_debug("%s: sending 82586 configure command\n", dev->name); adapter->tx_pcb.command = CMD_CONFIGURE_82586; adapter->tx_pcb.length = 2; adapter->got[CMD_CONFIGURE_82586] = 0; if (!send_pcb(dev, &adapter->tx_pcb)) { spin_unlock_irqrestore(&adapter->lock, flags); - printk(KERN_ERR "%s: couldn't send 82586 configure command\n", dev->name); + pr_err("%s: couldn't send 82586 configure command\n", dev->name); } else { unsigned long timeout = jiffies + TIMEOUT; @@ -1283,17 +1291,17 @@ static int __init elp_sense(struct net_device *dev) orig_HSR = inb_status(addr); if (elp_debug > 0) - printk(search_msg, name, addr); + pr_debug(search_msg, name, addr); if (orig_HSR == 0xff) { if (elp_debug > 0) - printk(notfound_msg, 1); + pr_cont(notfound_msg, 1); goto out; } /* Wait for a while; the adapter may still be booting up */ if (elp_debug > 0) - printk(stilllooking_msg); + pr_cont(stilllooking_msg); if (orig_HSR & DIR) { /* If HCR.DIR is up, we pull it down. HSR.DIR should follow. */ @@ -1301,7 +1309,7 @@ static int __init elp_sense(struct net_device *dev) msleep(300); if (inb_status(addr) & DIR) { if (elp_debug > 0) - printk(notfound_msg, 2); + pr_cont(notfound_msg, 2); goto out; } } else { @@ -1310,7 +1318,7 @@ static int __init elp_sense(struct net_device *dev) msleep(300); if (!(inb_status(addr) & DIR)) { if (elp_debug > 0) - printk(notfound_msg, 3); + pr_cont(notfound_msg, 3); goto out; } } @@ -1318,7 +1326,7 @@ static int __init elp_sense(struct net_device *dev) * It certainly looks like a 3c505. */ if (elp_debug > 0) - printk(found_msg); + pr_cont(found_msg); return 0; out: @@ -1349,7 +1357,7 @@ static int __init elp_autodetect(struct net_device *dev) /* could not find an adapter */ if (elp_debug > 0) - printk(couldnot_msg, dev->name); + pr_debug(couldnot_msg, dev->name); return 0; /* Because of this, the layer above will return -ENODEV */ } @@ -1424,16 +1432,16 @@ static int __init elplus_setup(struct net_device *dev) /* Nope, it's ignoring the command register. This means that * either it's still booting up, or it's died. */ - printk(KERN_ERR "%s: command register wouldn't drain, ", dev->name); + pr_err("%s: command register wouldn't drain, ", dev->name); if ((inb_status(dev->base_addr) & 7) == 3) { /* If the adapter status is 3, it *could* still be booting. * Give it the benefit of the doubt for 10 seconds. */ - printk("assuming 3c505 still starting\n"); + pr_cont("assuming 3c505 still starting\n"); timeout = jiffies + 10*HZ; while (time_before(jiffies, timeout) && (inb_status(dev->base_addr) & 7)); if (inb_status(dev->base_addr) & 7) { - printk(KERN_ERR "%s: 3c505 failed to start\n", dev->name); + pr_err("%s: 3c505 failed to start\n", dev->name); } else { okay = 1; /* It started */ } @@ -1441,7 +1449,7 @@ static int __init elplus_setup(struct net_device *dev) /* Otherwise, it must just be in a strange * state. We probably need to kick it. */ - printk("3c505 is sulking\n"); + pr_cont("3c505 is sulking\n"); } } for (tries = 0; tries < 5 && okay; tries++) { @@ -1454,18 +1462,19 @@ static int __init elplus_setup(struct net_device *dev) adapter->tx_pcb.length = 0; cookie = probe_irq_on(); if (!send_pcb(dev, &adapter->tx_pcb)) { - printk(KERN_ERR "%s: could not send first PCB\n", dev->name); + pr_err("%s: could not send first PCB\n", dev->name); probe_irq_off(cookie); continue; } if (!receive_pcb(dev, &adapter->rx_pcb)) { - printk(KERN_ERR "%s: could not read first PCB\n", dev->name); + pr_err("%s: could not read first PCB\n", dev->name); probe_irq_off(cookie); continue; } if ((adapter->rx_pcb.command != CMD_ADDRESS_RESPONSE) || (adapter->rx_pcb.length != 6)) { - printk(KERN_ERR "%s: first PCB wrong (%d, %d)\n", dev->name, adapter->rx_pcb.command, adapter->rx_pcb.length); + pr_err("%s: first PCB wrong (%d, %d)\n", dev->name, + adapter->rx_pcb.command, adapter->rx_pcb.length); probe_irq_off(cookie); continue; } @@ -1474,32 +1483,32 @@ static int __init elplus_setup(struct net_device *dev) /* It's broken. Do a hard reset to re-initialise the board, * and try again. */ - printk(KERN_INFO "%s: resetting adapter\n", dev->name); + pr_info("%s: resetting adapter\n", dev->name); outb_control(adapter->hcr_val | FLSH | ATTN, dev); outb_control(adapter->hcr_val & ~(FLSH | ATTN), dev); } - printk(KERN_ERR "%s: failed to initialise 3c505\n", dev->name); + pr_err("%s: failed to initialise 3c505\n", dev->name); goto out; okay: if (dev->irq) { /* Is there a preset IRQ? */ int rpt = probe_irq_off(cookie); if (dev->irq != rpt) { - printk(KERN_WARNING "%s: warning, irq %d configured but %d detected\n", dev->name, dev->irq, rpt); + pr_warning("%s: warning, irq %d configured but %d detected\n", dev->name, dev->irq, rpt); } /* if dev->irq == probe_irq_off(cookie), all is well */ } else /* No preset IRQ; just use what we can detect */ dev->irq = probe_irq_off(cookie); switch (dev->irq) { /* Legal, sane? */ case 0: - printk(KERN_ERR "%s: IRQ probe failed: check 3c505 jumpers.\n", + pr_err("%s: IRQ probe failed: check 3c505 jumpers.\n", dev->name); goto out; case 1: case 6: case 8: case 13: - printk(KERN_ERR "%s: Impossible IRQ %d reported by probe_irq_off().\n", + pr_err("%s: Impossible IRQ %d reported by probe_irq_off().\n", dev->name, dev->irq); goto out; } @@ -1521,7 +1530,7 @@ static int __init elplus_setup(struct net_device *dev) dev->dma = dev->mem_start & 7; } else { - printk(KERN_WARNING "%s: warning, DMA channel not specified, using default\n", dev->name); + pr_warning("%s: warning, DMA channel not specified, using default\n", dev->name); dev->dma = ELP_DMA; } } @@ -1529,11 +1538,8 @@ static int __init elplus_setup(struct net_device *dev) /* * print remainder of startup message */ - printk(KERN_INFO "%s: 3c505 at %#lx, irq %d, dma %d, " - "addr %pM, ", - dev->name, dev->base_addr, dev->irq, dev->dma, - dev->dev_addr); - + pr_info("%s: 3c505 at %#lx, irq %d, dma %d, addr %pM, ", + dev->name, dev->base_addr, dev->irq, dev->dma, dev->dev_addr); /* * read more information from the adapter */ @@ -1544,9 +1550,10 @@ static int __init elplus_setup(struct net_device *dev) !receive_pcb(dev, &adapter->rx_pcb) || (adapter->rx_pcb.command != CMD_ADAPTER_INFO_RESPONSE) || (adapter->rx_pcb.length != 10)) { - printk("not responding to second PCB\n"); + pr_cont("not responding to second PCB\n"); } - printk("rev %d.%d, %dk\n", adapter->rx_pcb.data.info.major_vers, adapter->rx_pcb.data.info.minor_vers, adapter->rx_pcb.data.info.RAM_sz); + pr_cont("rev %d.%d, %dk\n", adapter->rx_pcb.data.info.major_vers, + adapter->rx_pcb.data.info.minor_vers, adapter->rx_pcb.data.info.RAM_sz); /* * reconfigure the adapter memory to better suit our purposes @@ -1563,10 +1570,10 @@ static int __init elplus_setup(struct net_device *dev) !receive_pcb(dev, &adapter->rx_pcb) || (adapter->rx_pcb.command != CMD_CONFIGURE_ADAPTER_RESPONSE) || (adapter->rx_pcb.length != 2)) { - printk(KERN_ERR "%s: could not configure adapter memory\n", dev->name); + pr_err("%s: could not configure adapter memory\n", dev->name); } if (adapter->rx_pcb.data.configure) { - printk(KERN_ERR "%s: adapter configuration failed\n", dev->name); + pr_err("%s: adapter configuration failed\n", dev->name); } dev->netdev_ops = &elp_netdev_ops; @@ -1631,17 +1638,17 @@ int __init init_module(void) dev->dma = dma[this_dev]; } else { dev->dma = ELP_DMA; - printk(KERN_WARNING "3c505.c: warning, using default DMA channel,\n"); + pr_warning("3c505.c: warning, using default DMA channel,\n"); } if (io[this_dev] == 0) { if (this_dev) { free_netdev(dev); break; } - printk(KERN_NOTICE "3c505.c: module autoprobe not recommended, give io=xx.\n"); + pr_notice("3c505.c: module autoprobe not recommended, give io=xx.\n"); } if (elplus_setup(dev) != 0) { - printk(KERN_WARNING "3c505.c: Failed to register card at 0x%x.\n", io[this_dev]); + pr_warning("3c505.c: Failed to register card at 0x%x.\n", io[this_dev]); free_netdev(dev); break; } diff --git a/drivers/net/3c507.c b/drivers/net/3c507.c index fbbaf826deff..96b86659381a 100644 --- a/drivers/net/3c507.c +++ b/drivers/net/3c507.c @@ -364,7 +364,7 @@ static const struct net_device_ops netdev_ops = { static int __init el16_probe1(struct net_device *dev, int ioaddr) { - static unsigned char init_ID_done, version_printed; + static unsigned char init_ID_done; int i, irq, irqval, retval; struct net_local *lp; @@ -391,10 +391,7 @@ static int __init el16_probe1(struct net_device *dev, int ioaddr) goto out; } - if (net_debug && version_printed++ == 0) - printk(version); - - printk("%s: 3c507 at %#x,", dev->name, ioaddr); + pr_info("%s: 3c507 at %#x,", dev->name, ioaddr); /* We should make a few more checks here, like the first three octets of the S.A. for the manufacturer's code. */ @@ -403,7 +400,8 @@ static int __init el16_probe1(struct net_device *dev, int ioaddr) irqval = request_irq(irq, &el16_interrupt, 0, DRV_NAME, dev); if (irqval) { - printk(KERN_ERR "3c507: unable to get IRQ %d (irqval=%d).\n", irq, irqval); + pr_cont("\n"); + pr_err("3c507: unable to get IRQ %d (irqval=%d).\n", irq, irqval); retval = -EAGAIN; goto out; } @@ -414,7 +412,7 @@ static int __init el16_probe1(struct net_device *dev, int ioaddr) outb(0x01, ioaddr + MISC_CTRL); for (i = 0; i < 6; i++) dev->dev_addr[i] = inb(ioaddr + i); - printk(" %pM", dev->dev_addr); + pr_cont(" %pM", dev->dev_addr); if (mem_start) net_debug = mem_start & 7; @@ -443,18 +441,18 @@ static int __init el16_probe1(struct net_device *dev, int ioaddr) dev->if_port = (inb(ioaddr + ROM_CONFIG) & 0x80) ? 1 : 0; dev->irq = inb(ioaddr + IRQ_CONFIG) & 0x0f; - printk(", IRQ %d, %sternal xcvr, memory %#lx-%#lx.\n", dev->irq, + pr_cont(", IRQ %d, %sternal xcvr, memory %#lx-%#lx.\n", dev->irq, dev->if_port ? "ex" : "in", dev->mem_start, dev->mem_end-1); if (net_debug) - printk(version); + pr_debug("%s", version); lp = netdev_priv(dev); memset(lp, 0, sizeof(*lp)); spin_lock_init(&lp->lock); lp->base = ioremap(dev->mem_start, RX_BUF_END); if (!lp->base) { - printk(KERN_ERR "3c507: unable to remap memory\n"); + pr_err("3c507: unable to remap memory\n"); retval = -EAGAIN; goto out1; } @@ -488,20 +486,20 @@ static void el16_tx_timeout (struct net_device *dev) void __iomem *shmem = lp->base; if (net_debug > 1) - printk ("%s: transmit timed out, %s? ", dev->name, + pr_debug("%s: transmit timed out, %s? ", dev->name, readw(shmem + iSCB_STATUS) & 0x8000 ? "IRQ conflict" : "network cable problem"); /* Try to restart the adaptor. */ if (lp->last_restart == dev->stats.tx_packets) { if (net_debug > 1) - printk ("Resetting board.\n"); + pr_cont("Resetting board.\n"); /* Completely reset the adaptor. */ init_82586_mem (dev); lp->tx_pkts_in_ring = 0; } else { /* Issue the channel attention signal and hope it "gets better". */ if (net_debug > 1) - printk ("Kicking board.\n"); + pr_cont("Kicking board.\n"); writew(0xf000 | CUC_START | RX_START, shmem + iSCB_CMD); outb (0, ioaddr + SIGNAL_CA); /* Issue channel-attn. */ lp->last_restart = dev->stats.tx_packets; @@ -553,7 +551,8 @@ static irqreturn_t el16_interrupt(int irq, void *dev_id) void __iomem *shmem; if (dev == NULL) { - printk ("net_interrupt(): irq %d for unknown device.\n", irq); + pr_err("%s: net_interrupt(): irq %d for unknown device.\n", + dev->name, irq); return IRQ_NONE; } @@ -566,7 +565,7 @@ static irqreturn_t el16_interrupt(int irq, void *dev_id) status = readw(shmem+iSCB_STATUS); if (net_debug > 4) { - printk("%s: 3c507 interrupt, status %4.4x.\n", dev->name, status); + pr_debug("%s: 3c507 interrupt, status %4.4x.\n", dev->name, status); } /* Disable the 82586's input to the interrupt line. */ @@ -577,7 +576,7 @@ static irqreturn_t el16_interrupt(int irq, void *dev_id) unsigned short tx_status = readw(shmem+lp->tx_reap); if (!(tx_status & 0x8000)) { if (net_debug > 5) - printk("Tx command incomplete (%#x).\n", lp->tx_reap); + pr_debug("Tx command incomplete (%#x).\n", lp->tx_reap); break; } /* Tx unsuccessful or some interesting status bit set. */ @@ -591,7 +590,7 @@ static irqreturn_t el16_interrupt(int irq, void *dev_id) } dev->stats.tx_packets++; if (net_debug > 5) - printk("Reaped %x, Tx status %04x.\n" , lp->tx_reap, tx_status); + pr_debug("Reaped %x, Tx status %04x.\n" , lp->tx_reap, tx_status); lp->tx_reap += TX_BUF_SIZE; if (lp->tx_reap > RX_BUF_START - TX_BUF_SIZE) lp->tx_reap = TX_BUF_START; @@ -606,7 +605,7 @@ static irqreturn_t el16_interrupt(int irq, void *dev_id) if (status & 0x4000) { /* Packet received. */ if (net_debug > 5) - printk("Received packet, rx_head %04x.\n", lp->rx_head); + pr_debug("Received packet, rx_head %04x.\n", lp->rx_head); el16_rx(dev); } @@ -615,7 +614,7 @@ static irqreturn_t el16_interrupt(int irq, void *dev_id) if ((status & 0x0700) != 0x0200 && netif_running(dev)) { if (net_debug) - printk("%s: Command unit stopped, status %04x, restarting.\n", + pr_debug("%s: Command unit stopped, status %04x, restarting.\n", dev->name, status); /* If this ever occurs we should really re-write the idle loop, reset the Tx list, and do a complete restart of the command unit. @@ -627,7 +626,7 @@ static irqreturn_t el16_interrupt(int irq, void *dev_id) /* The Rx unit is not ready, it must be hung. Restart the receiver by initializing the rx buffers, and issuing an Rx start command. */ if (net_debug) - printk("%s: Rx unit stopped, status %04x, restarting.\n", + pr_debug("%s: Rx unit stopped, status %04x, restarting.\n", dev->name, status); init_rx_bufs(dev); writew(RX_BUF_START,shmem+iSCB_RFA); @@ -753,9 +752,8 @@ static void init_82586_mem(struct net_device *dev) int boguscnt = 50; while (readw(shmem+iSCB_STATUS) == 0) if (--boguscnt == 0) { - printk("%s: i82586 initialization timed out with status %04x, " - "cmd %04x.\n", dev->name, - readw(shmem+iSCB_STATUS), readw(shmem+iSCB_CMD)); + pr_warning("%s: i82586 initialization timed out with status %04x, cmd %04x.\n", + dev->name, readw(shmem+iSCB_STATUS), readw(shmem+iSCB_CMD)); break; } /* Issue channel-attn -- the 82586 won't start. */ @@ -765,7 +763,7 @@ static void init_82586_mem(struct net_device *dev) /* Disable loopback and enable interrupts. */ outb(0x84, ioaddr + MISC_CTRL); if (net_debug > 4) - printk("%s: Initialized 82586, status %04x.\n", dev->name, + pr_debug("%s: Initialized 82586, status %04x.\n", dev->name, readw(shmem+iSCB_STATUS)); return; } @@ -810,7 +808,7 @@ static void hardware_send_packet(struct net_device *dev, void *buf, short length lp->tx_head = TX_BUF_START; if (net_debug > 4) { - printk("%s: 3c507 @%x send length = %d, tx_block %3x, next %3x.\n", + pr_debug("%s: 3c507 @%x send length = %d, tx_block %3x, next %3x.\n", dev->name, ioaddr, length, tx_block, lp->tx_head); } @@ -838,7 +836,7 @@ static void el16_rx(struct net_device *dev) if (rfd_cmd != 0 || data_buffer_addr != rx_head + 22 || (pkt_len & 0xC000) != 0xC000) { - printk(KERN_ERR "%s: Rx frame at %#x corrupted, " + pr_err("%s: Rx frame at %#x corrupted, " "status %04x cmd %04x next %04x " "data-buf @%04x %04x.\n", dev->name, rx_head, frame_status, rfd_cmd, @@ -858,8 +856,7 @@ static void el16_rx(struct net_device *dev) pkt_len &= 0x3fff; skb = dev_alloc_skb(pkt_len+2); if (skb == NULL) { - printk(KERN_ERR "%s: Memory squeeze, " - "dropping packet.\n", + pr_err("%s: Memory squeeze, dropping packet.\n", dev->name); dev->stats.rx_dropped++; break; @@ -926,7 +923,7 @@ MODULE_PARM_DESC(irq, "(ignored)"); int __init init_module(void) { if (io == 0) - printk("3c507: You should not use auto-probing with insmod!\n"); + pr_notice("3c507: You should not use auto-probing with insmod!\n"); dev_3c507 = el16_probe(-1); return IS_ERR(dev_3c507) ? PTR_ERR(dev_3c507) : 0; } diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index 682aad897081..d2137efbd455 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -257,7 +257,7 @@ static int el3_isa_id_sequence(__be16 *phys_addr) && !memcmp(phys_addr, el3_devs[i]->dev_addr, ETH_ALEN)) { if (el3_debug > 3) - printk(KERN_DEBUG "3c509 with address %02x %02x %02x %02x %02x %02x was found by ISAPnP\n", + pr_debug("3c509 with address %02x %02x %02x %02x %02x %02x was found by ISAPnP\n", phys_addr[0] & 0xff, phys_addr[0] >> 8, phys_addr[1] & 0xff, phys_addr[1] >> 8, phys_addr[2] & 0xff, phys_addr[2] >> 8); @@ -578,19 +578,18 @@ static int __devinit el3_common_init(struct net_device *dev) err = register_netdev(dev); if (err) { - printk(KERN_ERR "Failed to register 3c5x9 at %#3.3lx, IRQ %d.\n", + pr_err("Failed to register 3c5x9 at %#3.3lx, IRQ %d.\n", dev->base_addr, dev->irq); release_region(dev->base_addr, EL3_IO_EXTENT); return err; } - printk(KERN_INFO "%s: 3c5x9 found at %#3.3lx, %s port, " - "address %pM, IRQ %d.\n", + pr_info("%s: 3c5x9 found at %#3.3lx, %s port, address %pM, IRQ %d.\n", dev->name, dev->base_addr, if_names[(dev->if_port & 0x03)], dev->dev_addr, dev->irq); if (el3_debug > 0) - printk(KERN_INFO "%s", version); + pr_info("%s", version); return 0; } @@ -629,8 +628,8 @@ static int __init el3_mca_probe(struct device *device) irq = pos5 & 0x0f; - printk(KERN_INFO "3c529: found %s at slot %d\n", - el3_mca_adapter_names[mdev->index], slot + 1); + pr_info("3c529: found %s at slot %d\n", + el3_mca_adapter_names[mdev->index], slot + 1); /* claim the slot */ strncpy(mdev->name, el3_mca_adapter_names[mdev->index], @@ -642,7 +641,7 @@ static int __init el3_mca_probe(struct device *device) irq = mca_device_transform_irq(mdev, irq); ioaddr = mca_device_transform_ioport(mdev, ioaddr); if (el3_debug > 2) { - printk(KERN_DEBUG "3c529: irq %d ioaddr 0x%x ifport %d\n", irq, ioaddr, if_port); + pr_debug("3c529: irq %d ioaddr 0x%x ifport %d\n", irq, ioaddr, if_port); } EL3WINDOW(0); for (i = 0; i < 3; i++) @@ -657,11 +656,11 @@ static int __init el3_mca_probe(struct device *device) netdev_boot_setup_check(dev); el3_dev_fill(dev, phys_addr, ioaddr, irq, if_port, EL3_MCA); - device->driver_data = dev; + dev_set_drvdata(device, dev); err = el3_common_init(dev); if (err) { - device->driver_data = NULL; + dev_set_drvdata(device, NULL); free_netdev(dev); return -ENOMEM; } @@ -725,12 +724,12 @@ static int __init el3_eisa_probe (struct device *device) /* This remove works for all device types. * - * The net dev must be stored in the driver_data field */ + * The net dev must be stored in the driver data field */ static int __devexit el3_device_remove (struct device *device) { struct net_device *dev; - dev = device->driver_data; + dev = dev_get_drvdata(device); el3_common_remove (dev); return 0; @@ -765,7 +764,7 @@ static ushort id_read_eeprom(int index) word = (word << 1) + (inb(id_port) & 0x01); if (el3_debug > 3) - printk(KERN_DEBUG " 3c509 EEPROM word %d %#4.4x.\n", index, word); + pr_debug(" 3c509 EEPROM word %d %#4.4x.\n", index, word); return word; } @@ -787,13 +786,13 @@ el3_open(struct net_device *dev) EL3WINDOW(0); if (el3_debug > 3) - printk(KERN_DEBUG "%s: Opening, IRQ %d status@%x %4.4x.\n", dev->name, + pr_debug("%s: Opening, IRQ %d status@%x %4.4x.\n", dev->name, dev->irq, ioaddr + EL3_STATUS, inw(ioaddr + EL3_STATUS)); el3_up(dev); if (el3_debug > 3) - printk(KERN_DEBUG "%s: Opened 3c509 IRQ %d status %4.4x.\n", + pr_debug("%s: Opened 3c509 IRQ %d status %4.4x.\n", dev->name, dev->irq, inw(ioaddr + EL3_STATUS)); return 0; @@ -805,8 +804,7 @@ el3_tx_timeout (struct net_device *dev) int ioaddr = dev->base_addr; /* Transmitter timeout, serious problems. */ - printk(KERN_WARNING "%s: transmit timed out, Tx_status %2.2x status %4.4x " - "Tx FIFO room %d.\n", + pr_warning("%s: transmit timed out, Tx_status %2.2x status %4.4x Tx FIFO room %d.\n", dev->name, inb(ioaddr + TX_STATUS), inw(ioaddr + EL3_STATUS), inw(ioaddr + TX_FREE)); dev->stats.tx_errors++; @@ -830,7 +828,7 @@ el3_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_bytes += skb->len; if (el3_debug > 4) { - printk(KERN_DEBUG "%s: el3_start_xmit(length = %u) called, status %4.4x.\n", + pr_debug("%s: el3_start_xmit(length = %u) called, status %4.4x.\n", dev->name, skb->len, inw(ioaddr + EL3_STATUS)); } #if 0 @@ -839,7 +837,7 @@ el3_start_xmit(struct sk_buff *skb, struct net_device *dev) ushort status = inw(ioaddr + EL3_STATUS); if (status & 0x0001 /* IRQ line active, missed one. */ && inw(ioaddr + EL3_STATUS) & 1) { /* Make sure. */ - printk(KERN_DEBUG "%s: Missed interrupt, status then %04x now %04x" + pr_debug("%s: Missed interrupt, status then %04x now %04x" " Tx %2.2x Rx %4.4x.\n", dev->name, status, inw(ioaddr + EL3_STATUS), inb(ioaddr + TX_STATUS), inw(ioaddr + RX_STATUS)); @@ -913,7 +911,7 @@ el3_interrupt(int irq, void *dev_id) if (el3_debug > 4) { status = inw(ioaddr + EL3_STATUS); - printk(KERN_DEBUG "%s: interrupt, status %4.4x.\n", dev->name, status); + pr_debug("%s: interrupt, status %4.4x.\n", dev->name, status); } while ((status = inw(ioaddr + EL3_STATUS)) & @@ -924,7 +922,7 @@ el3_interrupt(int irq, void *dev_id) if (status & TxAvailable) { if (el3_debug > 5) - printk(KERN_DEBUG " TX room bit was handled.\n"); + pr_debug(" TX room bit was handled.\n"); /* There's room in the FIFO for a full-sized packet. */ outw(AckIntr | TxAvailable, ioaddr + EL3_CMD); netif_wake_queue (dev); @@ -962,7 +960,7 @@ el3_interrupt(int irq, void *dev_id) } if (--i < 0) { - printk(KERN_ERR "%s: Infinite loop in interrupt, status %4.4x.\n", + pr_err("%s: Infinite loop in interrupt, status %4.4x.\n", dev->name, status); /* Clear all interrupts. */ outw(AckIntr | 0xFF, ioaddr + EL3_CMD); @@ -973,7 +971,7 @@ el3_interrupt(int irq, void *dev_id) } if (el3_debug > 4) { - printk(KERN_DEBUG "%s: exiting interrupt, status %4.4x.\n", dev->name, + pr_debug("%s: exiting interrupt, status %4.4x.\n", dev->name, inw(ioaddr + EL3_STATUS)); } spin_unlock(&lp->lock); @@ -1021,7 +1019,7 @@ static void update_stats(struct net_device *dev) int ioaddr = dev->base_addr; if (el3_debug > 5) - printk(" Updating the statistics.\n"); + pr_debug(" Updating the statistics.\n"); /* Turn off statistics updates while reading. */ outw(StatsDisable, ioaddr + EL3_CMD); /* Switch to the stats window, and read everything. */ @@ -1051,7 +1049,7 @@ el3_rx(struct net_device *dev) short rx_status; if (el3_debug > 5) - printk(" In rx_packet(), status %4.4x, rx_status %4.4x.\n", + pr_debug(" In rx_packet(), status %4.4x, rx_status %4.4x.\n", inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS)); while ((rx_status = inw(ioaddr + RX_STATUS)) > 0) { if (rx_status & 0x4000) { /* Error, update stats. */ @@ -1073,7 +1071,7 @@ el3_rx(struct net_device *dev) skb = dev_alloc_skb(pkt_len+5); if (el3_debug > 4) - printk("Receiving packet size %d status %4.4x.\n", + pr_debug("Receiving packet size %d status %4.4x.\n", pkt_len, rx_status); if (skb != NULL) { skb_reserve(skb, 2); /* Align IP on 16 byte */ @@ -1092,12 +1090,12 @@ el3_rx(struct net_device *dev) outw(RxDiscard, ioaddr + EL3_CMD); dev->stats.rx_dropped++; if (el3_debug) - printk("%s: Couldn't allocate a sk_buff of size %d.\n", + pr_debug("%s: Couldn't allocate a sk_buff of size %d.\n", dev->name, pkt_len); } inw(ioaddr + EL3_STATUS); /* Delay. */ while (inw(ioaddr + EL3_STATUS) & 0x1000) - printk(KERN_DEBUG " Waiting for 3c509 to discard packet, status %x.\n", + pr_debug(" Waiting for 3c509 to discard packet, status %x.\n", inw(ioaddr + EL3_STATUS) ); } @@ -1118,7 +1116,7 @@ set_multicast_list(struct net_device *dev) static int old; if (old != dev->mc_count) { old = dev->mc_count; - printk("%s: Setting Rx mode to %d addresses.\n", dev->name, dev->mc_count); + pr_debug("%s: Setting Rx mode to %d addresses.\n", dev->name, dev->mc_count); } } spin_lock_irqsave(&lp->lock, flags); @@ -1141,7 +1139,7 @@ el3_close(struct net_device *dev) struct el3_private *lp = netdev_priv(dev); if (el3_debug > 2) - printk("%s: Shutting down ethercard.\n", dev->name); + pr_debug("%s: Shutting down ethercard.\n", dev->name); el3_down(dev); @@ -1388,30 +1386,30 @@ el3_up(struct net_device *dev) EL3WINDOW(4); net_diag = inw(ioaddr + WN4_NETDIAG); net_diag = (net_diag | FD_ENABLE); /* temporarily assume full-duplex will be set */ - printk("%s: ", dev->name); + pr_info("%s: ", dev->name); switch (dev->if_port & 0x0c) { case 12: /* force full-duplex mode if 3c5x9b */ if (sw_info & 0x000f) { - printk("Forcing 3c5x9b full-duplex mode"); + pr_cont("Forcing 3c5x9b full-duplex mode"); break; } case 8: /* set full-duplex mode based on eeprom config setting */ if ((sw_info & 0x000f) && (sw_info & 0x8000)) { - printk("Setting 3c5x9b full-duplex mode (from EEPROM configuration bit)"); + pr_cont("Setting 3c5x9b full-duplex mode (from EEPROM configuration bit)"); break; } default: /* xcvr=(0 || 4) OR user has an old 3c5x9 non "B" model */ - printk("Setting 3c5x9/3c5x9B half-duplex mode"); + pr_cont("Setting 3c5x9/3c5x9B half-duplex mode"); net_diag = (net_diag & ~FD_ENABLE); /* disable full duplex */ } outw(net_diag, ioaddr + WN4_NETDIAG); - printk(" if_port: %d, sw_info: %4.4x\n", dev->if_port, sw_info); + pr_cont(" if_port: %d, sw_info: %4.4x\n", dev->if_port, sw_info); if (el3_debug > 3) - printk("%s: 3c5x9 net diag word is now: %4.4x.\n", dev->name, net_diag); + pr_debug("%s: 3c5x9 net diag word is now: %4.4x.\n", dev->name, net_diag); /* Enable link beat and jabber check. */ outw(inw(ioaddr + WN4_MEDIA) | MEDIA_TP, ioaddr + WN4_MEDIA); } @@ -1455,7 +1453,7 @@ el3_suspend(struct device *pdev, pm_message_t state) struct el3_private *lp; int ioaddr; - dev = pdev->driver_data; + dev = dev_get_drvdata(pdev); lp = netdev_priv(dev); ioaddr = dev->base_addr; @@ -1479,7 +1477,7 @@ el3_resume(struct device *pdev) struct el3_private *lp; int ioaddr; - dev = pdev->driver_data; + dev = dev_get_drvdata(pdev); lp = netdev_priv(dev); ioaddr = dev->base_addr; @@ -1539,7 +1537,7 @@ static int __init el3_init_module(void) } if (id_port >= 0x200) { id_port = 0; - printk(KERN_ERR "No I/O port available for 3c509 activation.\n"); + pr_err("No I/O port available for 3c509 activation.\n"); } else { ret = isa_register_driver(&el3_isa_driver, EL3_MAX_CARDS); if (!ret) diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c index 167bf23066ea..3e00fa8ea65f 100644 --- a/drivers/net/3c515.c +++ b/drivers/net/3c515.c @@ -420,7 +420,7 @@ int init_module(void) if (debug >= 0) corkscrew_debug = debug; if (corkscrew_debug) - printk(version); + pr_debug("%s", version); while (corkscrew_scan(-1)) found++; return found ? 0 : -ENODEV; @@ -437,7 +437,7 @@ struct net_device *tc515_probe(int unit) if (corkscrew_debug > 0 && !printed) { printed = 1; - printk(version); + pr_debug("%s", version); } return dev; @@ -516,7 +516,7 @@ static struct net_device *corkscrew_scan(int unit) if (pnp_device_attach(idev) < 0) continue; if (pnp_activate_dev(idev) < 0) { - printk("pnp activate failed (out of resources?)\n"); + pr_warning("pnp activate failed (out of resources?)\n"); pnp_device_detach(idev); continue; } @@ -531,9 +531,9 @@ static struct net_device *corkscrew_scan(int unit) continue; } if(corkscrew_debug) - printk ("ISAPNP reports %s at i/o 0x%x, irq %d\n", + pr_debug("ISAPNP reports %s at i/o 0x%x, irq %d\n", (char*) corkscrew_isapnp_adapters[i].driver_data, ioaddr, irq); - printk(KERN_INFO "3c515 Resource configuration register %#4.4x, DCR %4.4x.\n", + pr_info("3c515 Resource configuration register %#4.4x, DCR %4.4x.\n", inl(ioaddr + 0x2002), inw(ioaddr + 0x2000)); /* irq = inw(ioaddr + 0x2002) & 15; */ /* Use the irq from isapnp */ SET_NETDEV_DEV(dev, &idev->dev); @@ -552,7 +552,7 @@ no_pnp: if (!check_device(ioaddr)) continue; - printk(KERN_INFO "3c515 Resource configuration register %#4.4x, DCR %4.4x.\n", + pr_info("3c515 Resource configuration register %#4.4x, DCR %4.4x.\n", inl(ioaddr + 0x2002), inw(ioaddr + 0x2000)); err = corkscrew_setup(dev, ioaddr, NULL, cards_found++); if (!err) @@ -625,7 +625,7 @@ static int corkscrew_setup(struct net_device *dev, int ioaddr, list_add(&vp->list, &root_corkscrew_dev); #endif - printk(KERN_INFO "%s: 3Com %s at %#3x,", dev->name, vp->product_name, ioaddr); + pr_info("%s: 3Com %s at %#3x,", dev->name, vp->product_name, ioaddr); spin_lock_init(&vp->lock); @@ -648,19 +648,19 @@ static int corkscrew_setup(struct net_device *dev, int ioaddr, } checksum = (checksum ^ (checksum >> 8)) & 0xff; if (checksum != 0x00) - printk(" ***INVALID CHECKSUM %4.4x*** ", checksum); - printk(" %pM", dev->dev_addr); + pr_cont(" ***INVALID CHECKSUM %4.4x*** ", checksum); + pr_cont(" %pM", dev->dev_addr); if (eeprom[16] == 0x11c7) { /* Corkscrew */ if (request_dma(dev->dma, "3c515")) { - printk(", DMA %d allocation failed", dev->dma); + pr_cont(", DMA %d allocation failed", dev->dma); dev->dma = 0; } else - printk(", DMA %d", dev->dma); + pr_cont(", DMA %d", dev->dma); } - printk(", IRQ %d\n", dev->irq); + pr_cont(", IRQ %d\n", dev->irq); /* Tell them about an invalid IRQ. */ if (corkscrew_debug && (dev->irq <= 0 || dev->irq > 15)) - printk(KERN_WARNING " *** Warning: this IRQ is unlikely to work! ***\n"); + pr_warning(" *** Warning: this IRQ is unlikely to work! ***\n"); { char *ram_split[] = { "5:3", "3:1", "1:1", "3:5" }; @@ -669,9 +669,9 @@ static int corkscrew_setup(struct net_device *dev, int ioaddr, vp->available_media = inw(ioaddr + Wn3_Options); config = inl(ioaddr + Wn3_Config); if (corkscrew_debug > 1) - printk(KERN_INFO " Internal config register is %4.4x, transceivers %#x.\n", + pr_info(" Internal config register is %4.4x, transceivers %#x.\n", config, inw(ioaddr + Wn3_Options)); - printk(KERN_INFO " %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n", + pr_info(" %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n", 8 << config & Ram_size, config & Ram_width ? "word" : "byte", ram_split[(config & Ram_split) >> Ram_split_shift], @@ -682,7 +682,7 @@ static int corkscrew_setup(struct net_device *dev, int ioaddr, dev->if_port = vp->default_media; } if (vp->media_override != 7) { - printk(KERN_INFO " Media override to transceiver type %d (%s).\n", + pr_info(" Media override to transceiver type %d (%s).\n", vp->media_override, media_tbl[vp->media_override].name); dev->if_port = vp->media_override; @@ -718,7 +718,7 @@ static int corkscrew_open(struct net_device *dev) if (vp->media_override != 7) { if (corkscrew_debug > 1) - printk(KERN_INFO "%s: Media override to transceiver %d (%s).\n", + pr_info("%s: Media override to transceiver %d (%s).\n", dev->name, vp->media_override, media_tbl[vp->media_override].name); dev->if_port = vp->media_override; @@ -729,7 +729,7 @@ static int corkscrew_open(struct net_device *dev) dev->if_port = media_tbl[dev->if_port].next; if (corkscrew_debug > 1) - printk("%s: Initial media type %s.\n", + pr_debug("%s: Initial media type %s.\n", dev->name, media_tbl[dev->if_port].name); init_timer(&vp->timer); @@ -744,7 +744,7 @@ static int corkscrew_open(struct net_device *dev) outl(config, ioaddr + Wn3_Config); if (corkscrew_debug > 1) { - printk("%s: corkscrew_open() InternalConfig %8.8x.\n", + pr_debug("%s: corkscrew_open() InternalConfig %8.8x.\n", dev->name, config); } @@ -777,7 +777,7 @@ static int corkscrew_open(struct net_device *dev) if (corkscrew_debug > 1) { EL3WINDOW(4); - printk("%s: corkscrew_open() irq %d media status %4.4x.\n", + pr_debug("%s: corkscrew_open() irq %d media status %4.4x.\n", dev->name, dev->irq, inw(ioaddr + Wn4_Media)); } @@ -814,8 +814,7 @@ static int corkscrew_open(struct net_device *dev) if (vp->full_bus_master_rx) { /* Boomerang bus master. */ vp->cur_rx = vp->dirty_rx = 0; if (corkscrew_debug > 2) - printk("%s: Filling in the Rx ring.\n", - dev->name); + pr_debug("%s: Filling in the Rx ring.\n", dev->name); for (i = 0; i < RX_RING_SIZE; i++) { struct sk_buff *skb; if (i < (RX_RING_SIZE - 1)) @@ -877,7 +876,7 @@ static void corkscrew_timer(unsigned long data) int ok = 0; if (corkscrew_debug > 1) - printk("%s: Media selection timer tick happened, %s.\n", + pr_debug("%s: Media selection timer tick happened, %s.\n", dev->name, media_tbl[dev->if_port].name); spin_lock_irqsave(&vp->lock, flags); @@ -894,12 +893,12 @@ static void corkscrew_timer(unsigned long data) if (media_status & Media_LnkBeat) { ok = 1; if (corkscrew_debug > 1) - printk("%s: Media %s has link beat, %x.\n", + pr_debug("%s: Media %s has link beat, %x.\n", dev->name, media_tbl[dev->if_port].name, media_status); } else if (corkscrew_debug > 1) - printk("%s: Media %s is has no link beat, %x.\n", + pr_debug("%s: Media %s is has no link beat, %x.\n", dev->name, media_tbl[dev->if_port].name, media_status); @@ -907,7 +906,7 @@ static void corkscrew_timer(unsigned long data) break; default: /* Other media types handled by Tx timeouts. */ if (corkscrew_debug > 1) - printk("%s: Media %s is has no indication, %x.\n", + pr_debug("%s: Media %s is has no indication, %x.\n", dev->name, media_tbl[dev->if_port].name, media_status); @@ -925,12 +924,12 @@ static void corkscrew_timer(unsigned long data) if (dev->if_port == 8) { /* Go back to default. */ dev->if_port = vp->default_media; if (corkscrew_debug > 1) - printk("%s: Media selection failing, using default %s port.\n", + pr_debug("%s: Media selection failing, using default %s port.\n", dev->name, media_tbl[dev->if_port].name); } else { if (corkscrew_debug > 1) - printk("%s: Media selection failed, now trying %s port.\n", + pr_debug("%s: Media selection failed, now trying %s port.\n", dev->name, media_tbl[dev->if_port].name); vp->timer.expires = jiffies + media_tbl[dev->if_port].wait; @@ -953,7 +952,7 @@ static void corkscrew_timer(unsigned long data) spin_unlock_irqrestore(&vp->lock, flags); if (corkscrew_debug > 1) - printk("%s: Media selection timer finished, %s.\n", + pr_debug("%s: Media selection timer finished, %s.\n", dev->name, media_tbl[dev->if_port].name); #endif /* AUTOMEDIA */ @@ -966,23 +965,21 @@ static void corkscrew_timeout(struct net_device *dev) struct corkscrew_private *vp = netdev_priv(dev); int ioaddr = dev->base_addr; - printk(KERN_WARNING - "%s: transmit timed out, tx_status %2.2x status %4.4x.\n", + pr_warning("%s: transmit timed out, tx_status %2.2x status %4.4x.\n", dev->name, inb(ioaddr + TxStatus), inw(ioaddr + EL3_STATUS)); /* Slight code bloat to be user friendly. */ if ((inb(ioaddr + TxStatus) & 0x88) == 0x88) - printk(KERN_WARNING - "%s: Transmitter encountered 16 collisions -- network" + pr_warning("%s: Transmitter encountered 16 collisions --" " network cable problem?\n", dev->name); #ifndef final_version - printk(" Flags; bus-master %d, full %d; dirty %d current %d.\n", + pr_debug(" Flags; bus-master %d, full %d; dirty %d current %d.\n", vp->full_bus_master_tx, vp->tx_full, vp->dirty_tx, vp->cur_tx); - printk(" Down list %8.8x vs. %p.\n", inl(ioaddr + DownListPtr), + pr_debug(" Down list %8.8x vs. %p.\n", inl(ioaddr + DownListPtr), &vp->tx_ring[0]); for (i = 0; i < TX_RING_SIZE; i++) { - printk(" %d: %p length %8.8x status %8.8x\n", i, + pr_debug(" %d: %p length %8.8x status %8.8x\n", i, &vp->tx_ring[i], vp->tx_ring[i].length, vp->tx_ring[i].status); } @@ -1017,13 +1014,13 @@ static int corkscrew_start_xmit(struct sk_buff *skb, int i; if (vp->tx_full) /* No room to transmit with */ - return 1; + return NETDEV_TX_BUSY; if (vp->cur_tx != 0) prev_entry = &vp->tx_ring[(vp->cur_tx - 1) % TX_RING_SIZE]; else prev_entry = NULL; if (corkscrew_debug > 3) - printk("%s: Trying to send a packet, Tx index %d.\n", + pr_debug("%s: Trying to send a packet, Tx index %d.\n", dev->name, vp->cur_tx); /* vp->tx_full = 1; */ vp->tx_skbuff[entry] = skb; @@ -1102,7 +1099,7 @@ static int corkscrew_start_xmit(struct sk_buff *skb, while (--i > 0 && (tx_status = inb(ioaddr + TxStatus)) > 0) { if (tx_status & 0x3C) { /* A Tx-disabling error occurred. */ if (corkscrew_debug > 2) - printk("%s: Tx error, status %2.2x.\n", + pr_debug("%s: Tx error, status %2.2x.\n", dev->name, tx_status); if (tx_status & 0x04) dev->stats.tx_fifo_errors++; @@ -1143,7 +1140,7 @@ static irqreturn_t corkscrew_interrupt(int irq, void *dev_id) status = inw(ioaddr + EL3_STATUS); if (corkscrew_debug > 4) - printk("%s: interrupt, status %4.4x, timer %d.\n", + pr_debug("%s: interrupt, status %4.4x, timer %d.\n", dev->name, status, latency); if ((status & 0xE000) != 0xE000) { static int donedidthis; @@ -1151,7 +1148,7 @@ static irqreturn_t corkscrew_interrupt(int irq, void *dev_id) Ignore a single early interrupt, but don't hang the machine for other interrupt problems. */ if (donedidthis++ > 100) { - printk(KERN_ERR "%s: Bogus interrupt, bailing. Status %4.4x, start=%d.\n", + pr_err("%s: Bogus interrupt, bailing. Status %4.4x, start=%d.\n", dev->name, status, netif_running(dev)); free_irq(dev->irq, dev); dev->irq = -1; @@ -1160,14 +1157,14 @@ static irqreturn_t corkscrew_interrupt(int irq, void *dev_id) do { if (corkscrew_debug > 5) - printk("%s: In interrupt loop, status %4.4x.\n", + pr_debug("%s: In interrupt loop, status %4.4x.\n", dev->name, status); if (status & RxComplete) corkscrew_rx(dev); if (status & TxAvailable) { if (corkscrew_debug > 5) - printk(" TX room bit was handled.\n"); + pr_debug(" TX room bit was handled.\n"); /* There's room in the FIFO for a full-sized packet. */ outw(AckIntr | TxAvailable, ioaddr + EL3_CMD); netif_wake_queue(dev); @@ -1212,19 +1209,20 @@ static irqreturn_t corkscrew_interrupt(int irq, void *dev_id) if (status & StatsFull) { /* Empty statistics. */ static int DoneDidThat; if (corkscrew_debug > 4) - printk("%s: Updating stats.\n", dev->name); + pr_debug("%s: Updating stats.\n", dev->name); update_stats(ioaddr, dev); /* DEBUG HACK: Disable statistics as an interrupt source. */ /* This occurs when we have the wrong media type! */ if (DoneDidThat == 0 && inw(ioaddr + EL3_STATUS) & StatsFull) { int win, reg; - printk("%s: Updating stats failed, disabling stats as an" - " interrupt source.\n", dev->name); + pr_notice("%s: Updating stats failed, disabling stats as an interrupt source.\n", + dev->name); for (win = 0; win < 8; win++) { EL3WINDOW(win); - printk("\n Vortex window %d:", win); + pr_notice("Vortex window %d:", win); for (reg = 0; reg < 16; reg++) - printk(" %2.2x", inb(ioaddr + reg)); + pr_cont(" %2.2x", inb(ioaddr + reg)); + pr_cont("\n"); } EL3WINDOW(7); outw(SetIntrEnb | TxAvailable | @@ -1246,9 +1244,8 @@ static irqreturn_t corkscrew_interrupt(int irq, void *dev_id) } if (--i < 0) { - printk(KERN_ERR "%s: Too much work in interrupt, status %4.4x. " - "Disabling functions (%4.4x).\n", dev->name, - status, SetStatusEnb | ((~status) & 0x7FE)); + pr_err("%s: Too much work in interrupt, status %4.4x. Disabling functions (%4.4x).\n", + dev->name, status, SetStatusEnb | ((~status) & 0x7FE)); /* Disable all pending interrupts. */ outw(SetStatusEnb | ((~status) & 0x7FE), ioaddr + EL3_CMD); outw(AckIntr | 0x7FF, ioaddr + EL3_CMD); @@ -1262,7 +1259,7 @@ static irqreturn_t corkscrew_interrupt(int irq, void *dev_id) spin_unlock(&lp->lock); if (corkscrew_debug > 4) - printk("%s: exiting interrupt, status %4.4x.\n", dev->name, status); + pr_debug("%s: exiting interrupt, status %4.4x.\n", dev->name, status); return IRQ_HANDLED; } @@ -1273,13 +1270,13 @@ static int corkscrew_rx(struct net_device *dev) short rx_status; if (corkscrew_debug > 5) - printk(" In rx_packet(), status %4.4x, rx_status %4.4x.\n", + pr_debug(" In rx_packet(), status %4.4x, rx_status %4.4x.\n", inw(ioaddr + EL3_STATUS), inw(ioaddr + RxStatus)); while ((rx_status = inw(ioaddr + RxStatus)) > 0) { if (rx_status & 0x4000) { /* Error, update stats. */ unsigned char rx_error = inb(ioaddr + RxErrors); if (corkscrew_debug > 2) - printk(" Rx error: status %2.2x.\n", + pr_debug(" Rx error: status %2.2x.\n", rx_error); dev->stats.rx_errors++; if (rx_error & 0x01) @@ -1299,7 +1296,7 @@ static int corkscrew_rx(struct net_device *dev) skb = dev_alloc_skb(pkt_len + 5 + 2); if (corkscrew_debug > 4) - printk("Receiving packet size %d status %4.4x.\n", + pr_debug("Receiving packet size %d status %4.4x.\n", pkt_len, rx_status); if (skb != NULL) { skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ @@ -1318,7 +1315,7 @@ static int corkscrew_rx(struct net_device *dev) break; continue; } else if (corkscrew_debug) - printk("%s: Couldn't allocate a sk_buff of size %d.\n", dev->name, pkt_len); + pr_debug("%s: Couldn't allocate a sk_buff of size %d.\n", dev->name, pkt_len); } outw(RxDiscard, ioaddr + EL3_CMD); dev->stats.rx_dropped++; @@ -1338,13 +1335,13 @@ static int boomerang_rx(struct net_device *dev) int rx_status; if (corkscrew_debug > 5) - printk(" In boomerang_rx(), status %4.4x, rx_status %4.4x.\n", + pr_debug(" In boomerang_rx(), status %4.4x, rx_status %4.4x.\n", inw(ioaddr + EL3_STATUS), inw(ioaddr + RxStatus)); while ((rx_status = vp->rx_ring[entry].status) & RxDComplete) { if (rx_status & RxDError) { /* Error, update stats. */ unsigned char rx_error = rx_status >> 16; if (corkscrew_debug > 2) - printk(" Rx error: status %2.2x.\n", + pr_debug(" Rx error: status %2.2x.\n", rx_error); dev->stats.rx_errors++; if (rx_error & 0x01) @@ -1364,7 +1361,7 @@ static int boomerang_rx(struct net_device *dev) dev->stats.rx_bytes += pkt_len; if (corkscrew_debug > 4) - printk("Receiving packet size %d status %4.4x.\n", + pr_debug("Receiving packet size %d status %4.4x.\n", pkt_len, rx_status); /* Check if the packet is long enough to just accept without @@ -1385,7 +1382,7 @@ static int boomerang_rx(struct net_device *dev) temp = skb_put(skb, pkt_len); /* Remove this checking code for final release. */ if (isa_bus_to_virt(vp->rx_ring[entry].addr) != temp) - printk("%s: Warning -- the skbuff addresses do not match" + pr_warning("%s: Warning -- the skbuff addresses do not match" " in boomerang_rx: %p vs. %p / %p.\n", dev->name, isa_bus_to_virt(vp-> @@ -1427,12 +1424,11 @@ static int corkscrew_close(struct net_device *dev) netif_stop_queue(dev); if (corkscrew_debug > 1) { - printk("%s: corkscrew_close() status %4.4x, Tx status %2.2x.\n", + pr_debug("%s: corkscrew_close() status %4.4x, Tx status %2.2x.\n", dev->name, inw(ioaddr + EL3_STATUS), inb(ioaddr + TxStatus)); - printk("%s: corkscrew close stats: rx_nocopy %d rx_copy %d" - " tx_queued %d.\n", dev->name, rx_nocopy, rx_copy, - queued_packet); + pr_debug("%s: corkscrew close stats: rx_nocopy %d rx_copy %d tx_queued %d.\n", + dev->name, rx_nocopy, rx_copy, queued_packet); } del_timer(&vp->timer); @@ -1534,7 +1530,7 @@ static void set_rx_mode(struct net_device *dev) if (dev->flags & IFF_PROMISC) { if (corkscrew_debug > 3) - printk("%s: Setting promiscuous mode.\n", + pr_debug("%s: Setting promiscuous mode.\n", dev->name); new_mode = SetRxFilter | RxStation | RxMulticast | RxBroadcast | RxProm; } else if ((dev->mc_list) || (dev->flags & IFF_ALLMULTI)) { diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c index 8f734d74b513..cdd955c4014c 100644 --- a/drivers/net/3c523.c +++ b/drivers/net/3c523.c @@ -176,7 +176,7 @@ sizeof(nop_cmd) = 8; if(!p->scb->cmd) break; \ DELAY_16(); \ if(i == 1023) { \ - printk(KERN_WARNING "%s:%d: scb_cmd timed out .. resetting i82586\n",\ + pr_warning("%s:%d: scb_cmd timed out .. resetting i82586\n",\ dev->name,__LINE__); \ elmc_id_reset586(); } } } @@ -291,7 +291,7 @@ static int elmc_open(struct net_device *dev) ret = request_irq(dev->irq, &elmc_interrupt, IRQF_SHARED | IRQF_SAMPLE_RANDOM, dev->name, dev); if (ret) { - printk(KERN_ERR "%s: couldn't get irq %d\n", dev->name, dev->irq); + pr_err("%s: couldn't get irq %d\n", dev->name, dev->irq); elmc_id_reset586(); return ret; } @@ -371,9 +371,9 @@ static void alloc586(struct net_device *dev) DELAY(2); - if (p->iscp->busy) { - printk(KERN_ERR "%s: Init-Problems (alloc).\n", dev->name); - } + if (p->iscp->busy) + pr_err("%s: Init-Problems (alloc).\n", dev->name); + memset((char *) p->scb, 0, sizeof(struct scb_struct)); } @@ -470,7 +470,7 @@ static int __init do_elmc_probe(struct net_device *dev) mca_set_adapter_procfn(slot, (MCA_ProcFn) elmc_getinfo, dev); /* if we get this far, adapter has been found - carry on */ - printk(KERN_INFO "%s: 3c523 adapter found in slot %d\n", dev->name, slot + 1); + pr_info("%s: 3c523 adapter found in slot %d\n", dev->name, slot + 1); /* Now we extract configuration info from the card. The 3c523 provides information in two of the POS registers, but @@ -507,7 +507,7 @@ static int __init do_elmc_probe(struct net_device *dev) memset(pr, 0, sizeof(struct priv)); pr->slot = slot; - printk(KERN_INFO "%s: 3Com 3c523 Rev 0x%x at %#lx\n", dev->name, (int) revision, + pr_info("%s: 3Com 3c523 Rev 0x%x at %#lx\n", dev->name, (int) revision, dev->base_addr); /* Determine if we're using the on-board transceiver (i.e. coax) or @@ -529,7 +529,7 @@ static int __init do_elmc_probe(struct net_device *dev) size = 0x4000; /* check for 16K mem */ if (!check586(dev, dev->mem_start, size)) { - printk(KERN_ERR "%s: memprobe, Can't find memory at 0x%lx!\n", dev->name, + pr_err("%s: memprobe, Can't find memory at 0x%lx!\n", dev->name, dev->mem_start); retval = -ENODEV; goto err_out; @@ -546,7 +546,7 @@ static int __init do_elmc_probe(struct net_device *dev) pr->num_recv_buffs = NUM_RECV_BUFFS_16; /* dump all the assorted information */ - printk(KERN_INFO "%s: IRQ %d, %sternal xcvr, memory %#lx-%#lx.\n", dev->name, + pr_info("%s: IRQ %d, %sternal xcvr, memory %#lx-%#lx.\n", dev->name, dev->irq, dev->if_port ? "ex" : "in", dev->mem_start, dev->mem_end - 1); @@ -555,7 +555,7 @@ static int __init do_elmc_probe(struct net_device *dev) for (i = 0; i < 6; i++) dev->dev_addr[i] = inb(dev->base_addr + i); - printk(KERN_INFO "%s: hardware address %pM\n", + pr_info("%s: hardware address %pM\n", dev->name, dev->dev_addr); dev->netdev_ops = &netdev_ops; @@ -660,7 +660,7 @@ static int init586(struct net_device *dev) } if ((cfg_cmd->cmd_status & (STAT_OK | STAT_COMPL)) != (STAT_COMPL | STAT_OK)) { - printk(KERN_WARNING "%s (elmc): configure command failed: %x\n", dev->name, cfg_cmd->cmd_status); + pr_warning("%s (elmc): configure command failed: %x\n", dev->name, cfg_cmd->cmd_status); return 1; } /* @@ -686,7 +686,8 @@ static int init586(struct net_device *dev) } if ((ias_cmd->cmd_status & (STAT_OK | STAT_COMPL)) != (STAT_OK | STAT_COMPL)) { - printk(KERN_WARNING "%s (elmc): individual address setup command failed: %04x\n", dev->name, ias_cmd->cmd_status); + pr_warning("%s (elmc): individual address setup command failed: %04x\n", + dev->name, ias_cmd->cmd_status); return 1; } /* @@ -707,7 +708,7 @@ static int init586(struct net_device *dev) s = jiffies; while (!(tdr_cmd->cmd_status & STAT_COMPL)) { if (time_after(jiffies, s + 30*HZ/100)) { - printk(KERN_WARNING "%s: %d Problems while running the TDR.\n", dev->name, __LINE__); + pr_warning("%s: %d Problems while running the TDR.\n", dev->name, __LINE__); result = 1; break; } @@ -723,14 +724,14 @@ static int init586(struct net_device *dev) if (result & TDR_LNK_OK) { /* empty */ } else if (result & TDR_XCVR_PRB) { - printk(KERN_WARNING "%s: TDR: Transceiver problem!\n", dev->name); + pr_warning("%s: TDR: Transceiver problem!\n", dev->name); } else if (result & TDR_ET_OPN) { - printk(KERN_WARNING "%s: TDR: No correct termination %d clocks away.\n", dev->name, result & TDR_TIMEMASK); + pr_warning("%s: TDR: No correct termination %d clocks away.\n", dev->name, result & TDR_TIMEMASK); } else if (result & TDR_ET_SRT) { if (result & TDR_TIMEMASK) /* time == 0 -> strange :-) */ - printk(KERN_WARNING "%s: TDR: Detected a short circuit %d clocks away.\n", dev->name, result & TDR_TIMEMASK); + pr_warning("%s: TDR: Detected a short circuit %d clocks away.\n", dev->name, result & TDR_TIMEMASK); } else { - printk(KERN_WARNING "%s: TDR: Unknown status %04x\n", dev->name, result); + pr_warning("%s: TDR: Unknown status %04x\n", dev->name, result); } } /* @@ -774,11 +775,11 @@ static int init586(struct net_device *dev) /* I don't understand this: do we really need memory after the init? */ int len = ((char *) p->iscp - (char *) ptr - 8) / 6; if (len <= 0) { - printk(KERN_ERR "%s: Ooooops, no memory for MC-Setup!\n", dev->name); + pr_err("%s: Ooooops, no memory for MC-Setup!\n", dev->name); } else { if (len < num_addrs) { num_addrs = len; - printk(KERN_WARNING "%s: Sorry, can only apply %d MC-Address(es).\n", + pr_warning("%s: Sorry, can only apply %d MC-Address(es).\n", dev->name, num_addrs); } mc_cmd = (struct mcsetup_cmd_struct *) ptr; @@ -799,7 +800,7 @@ static int init586(struct net_device *dev) break; } if (!(mc_cmd->cmd_status & STAT_COMPL)) { - printk(KERN_WARNING "%s: Can't apply multicast-address-list.\n", dev->name); + pr_warning("%s: Can't apply multicast-address-list.\n", dev->name); } } } @@ -812,7 +813,7 @@ static int init586(struct net_device *dev) p->xmit_buffs[i] = (struct tbd_struct *) ptr; /* TBD */ ptr = (char *) ptr + sizeof(struct tbd_struct); if ((void *) ptr > (void *) p->iscp) { - printk(KERN_ERR "%s: not enough shared-mem for your configuration!\n", dev->name); + pr_err("%s: not enough shared-mem for your configuration!\n", dev->name); return 1; } memset((char *) (p->xmit_cmds[i]), 0, sizeof(struct transmit_cmd_struct)); @@ -936,7 +937,8 @@ elmc_interrupt(int irq, void *dev_id) if (stat & STAT_CNA) { /* CU went 'not ready' */ if (netif_running(dev)) { - printk(KERN_WARNING "%s: oops! CU has left active state. stat: %04x/%04x.\n", dev->name, (int) stat, (int) p->scb->status); + pr_warning("%s: oops! CU has left active state. stat: %04x/%04x.\n", + dev->name, (int) stat, (int) p->scb->status); } } #endif @@ -951,7 +953,8 @@ elmc_interrupt(int irq, void *dev_id) p->scb->cmd = RUC_RESUME; elmc_attn586(); } else { - printk(KERN_WARNING "%s: Receiver-Unit went 'NOT READY': %04x/%04x.\n", dev->name, (int) stat, (int) p->scb->status); + pr_warning("%s: Receiver-Unit went 'NOT READY': %04x/%04x.\n", + dev->name, (int) stat, (int) p->scb->status); elmc_rnr_int(dev); } } @@ -995,11 +998,11 @@ static void elmc_rcv_int(struct net_device *dev) dev->stats.rx_dropped++; } } else { - printk(KERN_WARNING "%s: received oversized frame.\n", dev->name); + pr_warning("%s: received oversized frame.\n", dev->name); dev->stats.rx_dropped++; } } else { /* frame !(ok), only with 'save-bad-frames' */ - printk(KERN_WARNING "%s: oops! rfd-error-status: %04x\n", dev->name, status); + pr_warning("%s: oops! rfd-error-status: %04x\n", dev->name, status); dev->stats.rx_errors++; } p->rfd_top->status = 0; @@ -1028,7 +1031,7 @@ static void elmc_rnr_int(struct net_device *dev) alloc_rfa(dev, (char *) p->rfd_first); startrecv586(dev); /* restart RU */ - printk(KERN_WARNING "%s: Receive-Unit restarted. Status: %04x\n", dev->name, p->scb->status); + pr_warning("%s: Receive-Unit restarted. Status: %04x\n", dev->name, p->scb->status); } @@ -1043,7 +1046,7 @@ static void elmc_xmt_int(struct net_device *dev) status = p->xmit_cmds[p->xmit_last]->cmd_status; if (!(status & STAT_COMPL)) { - printk(KERN_WARNING "%s: strange .. xmit-int without a 'COMPLETE'\n", dev->name); + pr_warning("%s: strange .. xmit-int without a 'COMPLETE'\n", dev->name); } if (status & STAT_OK) { dev->stats.tx_packets++; @@ -1051,18 +1054,18 @@ static void elmc_xmt_int(struct net_device *dev) } else { dev->stats.tx_errors++; if (status & TCMD_LATECOLL) { - printk(KERN_WARNING "%s: late collision detected.\n", dev->name); + pr_warning("%s: late collision detected.\n", dev->name); dev->stats.collisions++; } else if (status & TCMD_NOCARRIER) { dev->stats.tx_carrier_errors++; - printk(KERN_WARNING "%s: no carrier detected.\n", dev->name); + pr_warning("%s: no carrier detected.\n", dev->name); } else if (status & TCMD_LOSTCTS) { - printk(KERN_WARNING "%s: loss of CTS detected.\n", dev->name); + pr_warning("%s: loss of CTS detected.\n", dev->name); } else if (status & TCMD_UNDERRUN) { dev->stats.tx_fifo_errors++; - printk(KERN_WARNING "%s: DMA underrun detected.\n", dev->name); + pr_warning("%s: DMA underrun detected.\n", dev->name); } else if (status & TCMD_MAXCOLL) { - printk(KERN_WARNING "%s: Max. collisions exceeded.\n", dev->name); + pr_warning("%s: Max. collisions exceeded.\n", dev->name); dev->stats.collisions += 16; } } @@ -1099,10 +1102,11 @@ static void elmc_timeout(struct net_device *dev) struct priv *p = netdev_priv(dev); /* COMMAND-UNIT active? */ if (p->scb->status & CU_ACTIVE) { -#ifdef DEBUG - printk("%s: strange ... timeout with CU active?!?\n", dev->name); - printk("%s: X0: %04x N0: %04x N1: %04x %d\n", dev->name, (int) p->xmit_cmds[0]->cmd_status, (int) p->nop_cmds[0]->cmd_status, (int) p->nop_cmds[1]->cmd_status, (int) p->nop_point); -#endif + pr_debug("%s: strange ... timeout with CU active?!?\n", dev->name); + pr_debug("%s: X0: %04x N0: %04x N1: %04x %d\n", dev->name, + (int)p->xmit_cmds[0]->cmd_status, + (int)p->nop_cmds[0]->cmd_status, + (int)p->nop_cmds[1]->cmd_status, (int)p->nop_point); p->scb->cmd = CUC_ABORT; elmc_attn586(); WAIT_4_SCB_CMD(); @@ -1112,10 +1116,10 @@ static void elmc_timeout(struct net_device *dev) WAIT_4_SCB_CMD(); netif_wake_queue(dev); } else { -#ifdef DEBUG - printk("%s: xmitter timed out, try to restart! stat: %04x\n", dev->name, p->scb->status); - printk("%s: command-stats: %04x %04x\n", dev->name, p->xmit_cmds[0]->cmd_status, p->xmit_cmds[1]->cmd_status); -#endif + pr_debug("%s: xmitter timed out, try to restart! stat: %04x\n", + dev->name, p->scb->status); + pr_debug("%s: command-stats: %04x %04x\n", dev->name, + p->xmit_cmds[0]->cmd_status, p->xmit_cmds[1]->cmd_status); elmc_close(dev); elmc_open(dev); } @@ -1162,7 +1166,7 @@ static int elmc_send_packet(struct sk_buff *skb, struct net_device *dev) break; } if (i == 15) { - printk(KERN_WARNING "%s: Can't start transmit-command.\n", dev->name); + pr_warning("%s: Can't start transmit-command.\n", dev->name); } } #else @@ -1287,11 +1291,12 @@ int __init init_module(void) free_netdev(dev); if (io[this_dev]==0) break; - printk(KERN_WARNING "3c523.c: No 3c523 card found at io=%#x\n",io[this_dev]); + pr_warning("3c523.c: No 3c523 card found at io=%#x\n",io[this_dev]); } if(found==0) { - if(io[0]==0) printk(KERN_NOTICE "3c523.c: No 3c523 cards found\n"); + if (io[0]==0) + pr_notice("3c523.c: No 3c523 cards found\n"); return -ENXIO; } else return 0; } diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c index b61073c42bf8..aaa8a9f405d4 100644 --- a/drivers/net/3c527.c +++ b/drivers/net/3c527.c @@ -125,8 +125,6 @@ static const char* cardname = DRV_NAME; #define NET_DEBUG 2 #endif -#undef DEBUG_IRQ - static unsigned int mc32_debug = NET_DEBUG; /* The number of low I/O ports used by the ethercard. */ @@ -351,15 +349,15 @@ static int __init mc32_probe1(struct net_device *dev, int slot) /* Time to play MCA games */ if (mc32_debug && version_printed++ == 0) - printk(KERN_DEBUG "%s", version); + pr_debug("%s", version); - printk(KERN_INFO "%s: %s found in slot %d:", dev->name, cardname, slot); + pr_info("%s: %s found in slot %d: ", dev->name, cardname, slot); POS = mca_read_stored_pos(slot, 2); if(!(POS&1)) { - printk(" disabled.\n"); + pr_cont("disabled.\n"); return -ENODEV; } @@ -370,7 +368,7 @@ static int __init mc32_probe1(struct net_device *dev, int slot) POS = mca_read_stored_pos(slot, 4); if(!(POS&1)) { - printk("memory window disabled.\n"); + pr_cont("memory window disabled.\n"); return -ENODEV; } @@ -379,7 +377,7 @@ static int __init mc32_probe1(struct net_device *dev, int slot) i=(POS>>4)&3; if(i==3) { - printk("invalid memory window.\n"); + pr_cont("invalid memory window.\n"); return -ENODEV; } @@ -392,11 +390,11 @@ static int __init mc32_probe1(struct net_device *dev, int slot) if(!request_region(dev->base_addr, MC32_IO_EXTENT, cardname)) { - printk("io 0x%3lX, which is busy.\n", dev->base_addr); + pr_cont("io 0x%3lX, which is busy.\n", dev->base_addr); return -EBUSY; } - printk("io 0x%3lX irq %d mem 0x%lX (%dK)\n", + pr_cont("io 0x%3lX irq %d mem 0x%lX (%dK)\n", dev->base_addr, dev->irq, dev->mem_start, i/1024); @@ -416,7 +414,7 @@ static int __init mc32_probe1(struct net_device *dev, int slot) dev->dev_addr[i] = mca_read_pos(slot,3); } - printk("%s: Address %pM", dev->name, dev->dev_addr); + pr_info("%s: Address %pM ", dev->name, dev->dev_addr); mca_write_pos(slot, 6, 0); mca_write_pos(slot, 7, 0); @@ -424,9 +422,9 @@ static int __init mc32_probe1(struct net_device *dev, int slot) POS = mca_read_stored_pos(slot, 4); if(POS&2) - printk(" : BNC port selected.\n"); + pr_cont(": BNC port selected.\n"); else - printk(" : AUI port selected.\n"); + pr_cont(": AUI port selected.\n"); POS=inb(dev->base_addr+HOST_CTRL); POS|=HOST_CTRL_ATTN|HOST_CTRL_RESET; @@ -447,7 +445,7 @@ static int __init mc32_probe1(struct net_device *dev, int slot) err = request_irq(dev->irq, &mc32_interrupt, IRQF_SHARED | IRQF_SAMPLE_RANDOM, DRV_NAME, dev); if (err) { release_region(dev->base_addr, MC32_IO_EXTENT); - printk(KERN_ERR "%s: unable to get IRQ %d.\n", DRV_NAME, dev->irq); + pr_err("%s: unable to get IRQ %d.\n", DRV_NAME, dev->irq); goto err_exit_ports; } @@ -463,7 +461,7 @@ static int __init mc32_probe1(struct net_device *dev, int slot) i++; if(i == 1000) { - printk(KERN_ERR "%s: failed to boot adapter.\n", dev->name); + pr_err("%s: failed to boot adapter.\n", dev->name); err = -ENODEV; goto err_exit_irq; } @@ -475,10 +473,10 @@ static int __init mc32_probe1(struct net_device *dev, int slot) if(base>0) { if(base < 0x0C) - printk(KERN_ERR "%s: %s%s.\n", dev->name, failures[base-1], + pr_err("%s: %s%s.\n", dev->name, failures[base-1], base<0x0A?" test failure":""); else - printk(KERN_ERR "%s: unknown failure %d.\n", dev->name, base); + pr_err("%s: unknown failure %d.\n", dev->name, base); err = -ENODEV; goto err_exit_irq; } @@ -494,7 +492,7 @@ static int __init mc32_probe1(struct net_device *dev, int slot) udelay(50); if(n>100) { - printk(KERN_ERR "%s: mailbox read fail (%d).\n", dev->name, i); + pr_err("%s: mailbox read fail (%d).\n", dev->name, i); err = -ENODEV; goto err_exit_irq; } @@ -527,7 +525,7 @@ static int __init mc32_probe1(struct net_device *dev, int slot) init_completion(&lp->execution_cmd); init_completion(&lp->xceiver_cmd); - printk("%s: Firmware Rev %d. %d RX buffers, %d TX buffers. Base of 0x%08X.\n", + pr_info("%s: Firmware Rev %d. %d RX buffers, %d TX buffers. Base of 0x%08X.\n", dev->name, lp->exec_box->data[12], lp->rx_len, lp->tx_len, lp->base); dev->netdev_ops = &netdev_ops; @@ -939,7 +937,7 @@ static int mc32_open(struct net_device *dev) */ if(mc32_command(dev, 8, descnumbuffs, 4)) { - printk("%s: %s rejected our buffer configuration!\n", + pr_info("%s: %s rejected our buffer configuration!\n", dev->name, cardname); mc32_close(dev); return -ENOBUFS; @@ -995,7 +993,7 @@ static int mc32_open(struct net_device *dev) static void mc32_timeout(struct net_device *dev) { - printk(KERN_WARNING "%s: transmit timed out?\n", dev->name); + pr_warning("%s: transmit timed out?\n", dev->name); /* Try to restart the adaptor. */ netif_wake_queue(dev); } @@ -1032,7 +1030,7 @@ static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); if(atomic_read(&lp->tx_count)==0) { - return 1; + return NETDEV_TX_BUSY; } if (skb_padto(skb, ETH_ZLEN)) { @@ -1335,11 +1333,9 @@ static irqreturn_t mc32_interrupt(int irq, void *dev_id) { status=inb(ioaddr+HOST_CMD); -#ifdef DEBUG_IRQ - printk("Status TX%d RX%d EX%d OV%d BC%d\n", + pr_debug("Status TX%d RX%d EX%d OV%d BC%d\n", (status&7), (status>>3)&7, (status>>6)&1, (status>>7)&1, boguscount); -#endif switch(status&7) { @@ -1354,7 +1350,7 @@ static irqreturn_t mc32_interrupt(int irq, void *dev_id) complete(&lp->xceiver_cmd); break; default: - printk("%s: strange tx ack %d\n", dev->name, status&7); + pr_notice("%s: strange tx ack %d\n", dev->name, status&7); } status>>=3; switch(status&7) @@ -1376,7 +1372,7 @@ static irqreturn_t mc32_interrupt(int irq, void *dev_id) mc32_start_transceiver(dev); break; default: - printk("%s: strange rx ack %d\n", + pr_notice("%s: strange rx ack %d\n", dev->name, status&7); } status>>=3; diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index c56698402420..c34aee91250b 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -828,14 +828,14 @@ static int vortex_resume(struct pci_dev *pdev) pci_restore_state(pdev); err = pci_enable_device(pdev); if (err) { - printk(KERN_WARNING "%s: Could not enable device \n", + pr_warning("%s: Could not enable device\n", dev->name); return err; } pci_set_master(pdev); if (request_irq(dev->irq, vp->full_bus_master_rx ? &boomerang_interrupt : &vortex_interrupt, IRQF_SHARED, dev->name, dev)) { - printk(KERN_WARNING "%s: Could not reserve IRQ %d\n", dev->name, dev->irq); + pr_warning("%s: Could not reserve IRQ %d\n", dev->name, dev->irq); pci_disable_device(pdev); return -EBUSY; } @@ -894,7 +894,7 @@ static int __devexit vortex_eisa_remove(struct device *device) dev = eisa_get_drvdata(edev); if (!dev) { - printk("vortex_eisa_remove called for Compaq device!\n"); + pr_err("vortex_eisa_remove called for Compaq device!\n"); BUG(); } @@ -1051,7 +1051,7 @@ static int __devinit vortex_probe1(struct device *gendev, struct eisa_device *edev = NULL; if (!printed_version) { - printk (version); + pr_info("%s", version); printed_version = 1; } @@ -1068,7 +1068,7 @@ static int __devinit vortex_probe1(struct device *gendev, dev = alloc_etherdev(sizeof(*vp)); retval = -ENOMEM; if (!dev) { - printk (KERN_ERR PFX "unable to allocate etherdev, aborting\n"); + pr_err(PFX "unable to allocate etherdev, aborting\n"); goto out; } SET_NETDEV_DEV(dev, gendev); @@ -1100,9 +1100,9 @@ static int __devinit vortex_probe1(struct device *gendev, print_info = (vortex_debug > 1); if (print_info) - printk (KERN_INFO "See Documentation/networking/vortex.txt\n"); + pr_info("See Documentation/networking/vortex.txt\n"); - printk(KERN_INFO "%s: 3Com %s %s at %p.\n", + pr_info("%s: 3Com %s %s at %p.\n", print_name, pdev ? "PCI" : "EISA", vci->name, @@ -1144,10 +1144,9 @@ static int __devinit vortex_probe1(struct device *gendev, chip only. */ pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency); if (pci_latency < new_latency) { - printk(KERN_INFO "%s: Overriding PCI latency" - " timer (CFLT) setting of %d, new value is %d.\n", + pr_info("%s: Overriding PCI latency timer (CFLT) setting of %d, new value is %d.\n", print_name, pci_latency, new_latency); - pci_write_config_byte(pdev, PCI_LATENCY_TIMER, new_latency); + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, new_latency); } } } @@ -1236,17 +1235,17 @@ static int __devinit vortex_probe1(struct device *gendev, checksum = (checksum ^ (checksum >> 8)) & 0xff; } if ((checksum != 0x00) && !(vci->drv_flags & IS_TORNADO)) - printk(" ***INVALID CHECKSUM %4.4x*** ", checksum); + pr_cont(" ***INVALID CHECKSUM %4.4x*** ", checksum); for (i = 0; i < 3; i++) ((__be16 *)dev->dev_addr)[i] = htons(eeprom[i + 10]); memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); if (print_info) - printk(" %pM", dev->dev_addr); + pr_cont(" %pM", dev->dev_addr); /* Unfortunately an all zero eeprom passes the checksum and this gets found in the wild in failure cases. Crypto is hard 8) */ if (!is_valid_ether_addr(dev->dev_addr)) { retval = -EINVAL; - printk(KERN_ERR "*** EEPROM MAC address is invalid.\n"); + pr_err("*** EEPROM MAC address is invalid.\n"); goto free_ring; /* With every pack */ } EL3WINDOW(2); @@ -1254,17 +1253,17 @@ static int __devinit vortex_probe1(struct device *gendev, iowrite8(dev->dev_addr[i], ioaddr + i); if (print_info) - printk(", IRQ %d\n", dev->irq); + pr_cont(", IRQ %d\n", dev->irq); /* Tell them about an invalid IRQ. */ if (dev->irq <= 0 || dev->irq >= nr_irqs) - printk(KERN_WARNING " *** Warning: IRQ %d is unlikely to work! ***\n", + pr_warning(" *** Warning: IRQ %d is unlikely to work! ***\n", dev->irq); EL3WINDOW(4); step = (ioread8(ioaddr + Wn4_NetDiag) & 0x1e) >> 1; if (print_info) { - printk(KERN_INFO " product code %02x%02x rev %02x.%d date %02d-" - "%02d-%02d\n", eeprom[6]&0xff, eeprom[6]>>8, eeprom[0x14], + pr_info(" product code %02x%02x rev %02x.%d date %02d-%02d-%02d\n", + eeprom[6]&0xff, eeprom[6]>>8, eeprom[0x14], step, (eeprom[4]>>5) & 15, eeprom[4] & 31, eeprom[4]>>9); } @@ -1279,8 +1278,7 @@ static int __devinit vortex_probe1(struct device *gendev, } if (print_info) { - printk(KERN_INFO "%s: CardBus functions mapped " - "%16.16llx->%p\n", + pr_info("%s: CardBus functions mapped %16.16llx->%p\n", print_name, (unsigned long long)pci_resource_start(pdev, 2), vp->cb_fn_base); @@ -1307,7 +1305,7 @@ static int __devinit vortex_probe1(struct device *gendev, if (vp->info1 & 0x8000) { vp->full_duplex = 1; if (print_info) - printk(KERN_INFO "Full duplex capable\n"); + pr_info("Full duplex capable\n"); } { @@ -1319,9 +1317,9 @@ static int __devinit vortex_probe1(struct device *gendev, vp->available_media = 0x40; config = ioread32(ioaddr + Wn3_Config); if (print_info) { - printk(KERN_DEBUG " Internal config register is %4.4x, " - "transceivers %#x.\n", config, ioread16(ioaddr + Wn3_Options)); - printk(KERN_INFO " %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n", + pr_debug(" Internal config register is %4.4x, transceivers %#x.\n", + config, ioread16(ioaddr + Wn3_Options)); + pr_info(" %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n", 8 << RAM_SIZE(config), RAM_WIDTH(config) ? "word" : "byte", ram_split[RAM_SPLIT(config)], @@ -1336,7 +1334,7 @@ static int __devinit vortex_probe1(struct device *gendev, } if (vp->media_override != 7) { - printk(KERN_INFO "%s: Media override to transceiver type %d (%s).\n", + pr_info("%s: Media override to transceiver type %d (%s).\n", print_name, vp->media_override, media_tbl[vp->media_override].name); dev->if_port = vp->media_override; @@ -1369,8 +1367,8 @@ static int __devinit vortex_probe1(struct device *gendev, if (mii_status && mii_status != 0xffff) { vp->phys[phy_idx++] = phyx; if (print_info) { - printk(KERN_INFO " MII transceiver found at address %d," - " status %4x.\n", phyx, mii_status); + pr_info(" MII transceiver found at address %d, status %4x.\n", + phyx, mii_status); } if ((mii_status & 0x0040) == 0) mii_preamble_required++; @@ -1378,7 +1376,7 @@ static int __devinit vortex_probe1(struct device *gendev, } mii_preamble_required--; if (phy_idx == 0) { - printk(KERN_WARNING" ***WARNING*** No MII transceivers found!\n"); + pr_warning(" ***WARNING*** No MII transceivers found!\n"); vp->phys[0] = 24; } else { vp->advertising = mdio_read(dev, vp->phys[0], MII_ADVERTISE); @@ -1394,7 +1392,7 @@ static int __devinit vortex_probe1(struct device *gendev, if (vp->capabilities & CapBusMaster) { vp->full_bus_master_tx = 1; if (print_info) { - printk(KERN_INFO " Enabling bus-master transmits and %s receives.\n", + pr_info(" Enabling bus-master transmits and %s receives.\n", (vp->info2 & 1) ? "early" : "whole-frame" ); } vp->full_bus_master_rx = (vp->info2 & 1) ? 1 : 2; @@ -1414,7 +1412,7 @@ static int __devinit vortex_probe1(struct device *gendev, dev->netdev_ops = &vortex_netdev_ops; if (print_info) { - printk(KERN_INFO "%s: scatter/gather %sabled. h/w checksums %sabled\n", + pr_info("%s: scatter/gather %sabled. h/w checksums %sabled\n", print_name, (dev->features & NETIF_F_SG) ? "en":"dis", (dev->features & NETIF_F_IP_CSUM) ? "en":"dis"); @@ -1442,7 +1440,7 @@ free_region: if (vp->must_free_region) release_region(dev->base_addr, vci->io_size); free_netdev(dev); - printk(KERN_ERR PFX "vortex_probe1 fails. Returns %d\n", retval); + pr_err(PFX "vortex_probe1 fails. Returns %d\n", retval); out: return retval; } @@ -1464,13 +1462,13 @@ issue_and_wait(struct net_device *dev, int cmd) for (i = 0; i < 100000; i++) { if (!(ioread16(ioaddr + EL3_STATUS) & CmdInProgress)) { if (vortex_debug > 1) - printk(KERN_INFO "%s: command 0x%04x took %d usecs\n", + pr_info("%s: command 0x%04x took %d usecs\n", dev->name, cmd, i * 10); return; } udelay(10); } - printk(KERN_ERR "%s: command 0x%04x did not complete! Status=0x%x\n", + pr_err("%s: command 0x%04x did not complete! Status=0x%x\n", dev->name, cmd, ioread16(ioaddr + EL3_STATUS)); } @@ -1480,7 +1478,7 @@ vortex_set_duplex(struct net_device *dev) struct vortex_private *vp = netdev_priv(dev); void __iomem *ioaddr = vp->ioaddr; - printk(KERN_INFO "%s: setting %s-duplex.\n", + pr_info("%s: setting %s-duplex.\n", dev->name, (vp->full_duplex) ? "full" : "half"); EL3WINDOW(3); @@ -1522,7 +1520,7 @@ vortex_up(struct net_device *dev) pci_restore_state(VORTEX_PCI(vp)); err = pci_enable_device(VORTEX_PCI(vp)); if (err) { - printk(KERN_WARNING "%s: Could not enable device \n", + pr_warning("%s: Could not enable device\n", dev->name); goto err_out; } @@ -1533,14 +1531,14 @@ vortex_up(struct net_device *dev) config = ioread32(ioaddr + Wn3_Config); if (vp->media_override != 7) { - printk(KERN_INFO "%s: Media override to transceiver %d (%s).\n", + pr_info("%s: Media override to transceiver %d (%s).\n", dev->name, vp->media_override, media_tbl[vp->media_override].name); dev->if_port = vp->media_override; } else if (vp->autoselect) { if (vp->has_nway) { if (vortex_debug > 1) - printk(KERN_INFO "%s: using NWAY device table, not %d\n", + pr_info("%s: using NWAY device table, not %d\n", dev->name, dev->if_port); dev->if_port = XCVR_NWAY; } else { @@ -1549,13 +1547,13 @@ vortex_up(struct net_device *dev) while (! (vp->available_media & media_tbl[dev->if_port].mask)) dev->if_port = media_tbl[dev->if_port].next; if (vortex_debug > 1) - printk(KERN_INFO "%s: first available media type: %s\n", + pr_info("%s: first available media type: %s\n", dev->name, media_tbl[dev->if_port].name); } } else { dev->if_port = vp->default_media; if (vortex_debug > 1) - printk(KERN_INFO "%s: using default media %s\n", + pr_info("%s: using default media %s\n", dev->name, media_tbl[dev->if_port].name); } @@ -1570,13 +1568,13 @@ vortex_up(struct net_device *dev) vp->rx_oom_timer.function = rx_oom_timer; if (vortex_debug > 1) - printk(KERN_DEBUG "%s: Initial media type %s.\n", + pr_debug("%s: Initial media type %s.\n", dev->name, media_tbl[dev->if_port].name); vp->full_duplex = vp->mii.force_media; config = BFINS(config, dev->if_port, 20, 4); if (vortex_debug > 6) - printk(KERN_DEBUG "vortex_up(): writing 0x%x to InternalConfig\n", config); + pr_debug("vortex_up(): writing 0x%x to InternalConfig\n", config); iowrite32(config, ioaddr + Wn3_Config); if (dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) { @@ -1602,7 +1600,7 @@ vortex_up(struct net_device *dev) if (vortex_debug > 1) { EL3WINDOW(4); - printk(KERN_DEBUG "%s: vortex_up() irq %d media status %4.4x.\n", + pr_debug("%s: vortex_up() irq %d media status %4.4x.\n", dev->name, dev->irq, ioread16(ioaddr + Wn4_Media)); } @@ -1704,13 +1702,13 @@ vortex_open(struct net_device *dev) /* Use the now-standard shared IRQ implementation. */ if ((retval = request_irq(dev->irq, vp->full_bus_master_rx ? &boomerang_interrupt : &vortex_interrupt, IRQF_SHARED, dev->name, dev))) { - printk(KERN_ERR "%s: Could not reserve IRQ %d\n", dev->name, dev->irq); + pr_err("%s: Could not reserve IRQ %d\n", dev->name, dev->irq); goto err; } if (vp->full_bus_master_rx) { /* Boomerang bus master. */ if (vortex_debug > 2) - printk(KERN_DEBUG "%s: Filling in the Rx ring.\n", dev->name); + pr_debug("%s: Filling in the Rx ring.\n", dev->name); for (i = 0; i < RX_RING_SIZE; i++) { struct sk_buff *skb; vp->rx_ring[i].next = cpu_to_le32(vp->rx_ring_dma + sizeof(struct boom_rx_desc) * (i+1)); @@ -1728,7 +1726,7 @@ vortex_open(struct net_device *dev) } if (i != RX_RING_SIZE) { int j; - printk(KERN_EMERG "%s: no memory for rx ring\n", dev->name); + pr_emerg("%s: no memory for rx ring\n", dev->name); for (j = 0; j < i; j++) { if (vp->rx_skbuff[j]) { dev_kfree_skb(vp->rx_skbuff[j]); @@ -1750,7 +1748,7 @@ err_free_irq: free_irq(dev->irq, dev); err: if (vortex_debug > 1) - printk(KERN_ERR "%s: vortex_open() fails: returning %d\n", dev->name, retval); + pr_err("%s: vortex_open() fails: returning %d\n", dev->name, retval); out: return retval; } @@ -1766,9 +1764,9 @@ vortex_timer(unsigned long data) int media_status, old_window; if (vortex_debug > 2) { - printk(KERN_DEBUG "%s: Media selection timer tick happened, %s.\n", + pr_debug("%s: Media selection timer tick happened, %s.\n", dev->name, media_tbl[dev->if_port].name); - printk(KERN_DEBUG "dev->watchdog_timeo=%d\n", dev->watchdog_timeo); + pr_debug("dev->watchdog_timeo=%d\n", dev->watchdog_timeo); } disable_irq_lockdep(dev->irq); @@ -1781,12 +1779,12 @@ vortex_timer(unsigned long data) netif_carrier_on(dev); ok = 1; if (vortex_debug > 1) - printk(KERN_DEBUG "%s: Media %s has link beat, %x.\n", + pr_debug("%s: Media %s has link beat, %x.\n", dev->name, media_tbl[dev->if_port].name, media_status); } else { netif_carrier_off(dev); if (vortex_debug > 1) { - printk(KERN_DEBUG "%s: Media %s has no link beat, %x.\n", + pr_debug("%s: Media %s has no link beat, %x.\n", dev->name, media_tbl[dev->if_port].name, media_status); } } @@ -1802,7 +1800,7 @@ vortex_timer(unsigned long data) break; default: /* Other media types handled by Tx timeouts. */ if (vortex_debug > 1) - printk(KERN_DEBUG "%s: Media %s has no indication, %x.\n", + pr_debug("%s: Media %s has no indication, %x.\n", dev->name, media_tbl[dev->if_port].name, media_status); ok = 1; } @@ -1822,13 +1820,11 @@ vortex_timer(unsigned long data) if (dev->if_port == XCVR_Default) { /* Go back to default. */ dev->if_port = vp->default_media; if (vortex_debug > 1) - printk(KERN_DEBUG "%s: Media selection failing, using default " - "%s port.\n", + pr_debug("%s: Media selection failing, using default %s port.\n", dev->name, media_tbl[dev->if_port].name); } else { if (vortex_debug > 1) - printk(KERN_DEBUG "%s: Media selection failed, now trying " - "%s port.\n", + pr_debug("%s: Media selection failed, now trying %s port.\n", dev->name, media_tbl[dev->if_port].name); next_tick = media_tbl[dev->if_port].wait; } @@ -1843,13 +1839,13 @@ vortex_timer(unsigned long data) iowrite16(dev->if_port == XCVR_10base2 ? StartCoax : StopCoax, ioaddr + EL3_CMD); if (vortex_debug > 1) - printk(KERN_DEBUG "wrote 0x%08x to Wn3_Config\n", config); + pr_debug("wrote 0x%08x to Wn3_Config\n", config); /* AKPM: FIXME: Should reset Rx & Tx here. P60 of 3c90xc.pdf */ } leave_media_alone: if (vortex_debug > 2) - printk(KERN_DEBUG "%s: Media selection timer finished, %s.\n", + pr_debug("%s: Media selection timer finished, %s.\n", dev->name, media_tbl[dev->if_port].name); EL3WINDOW(old_window); @@ -1865,21 +1861,21 @@ static void vortex_tx_timeout(struct net_device *dev) struct vortex_private *vp = netdev_priv(dev); void __iomem *ioaddr = vp->ioaddr; - printk(KERN_ERR "%s: transmit timed out, tx_status %2.2x status %4.4x.\n", + pr_err("%s: transmit timed out, tx_status %2.2x status %4.4x.\n", dev->name, ioread8(ioaddr + TxStatus), ioread16(ioaddr + EL3_STATUS)); EL3WINDOW(4); - printk(KERN_ERR " diagnostics: net %04x media %04x dma %08x fifo %04x\n", + pr_err(" diagnostics: net %04x media %04x dma %08x fifo %04x\n", ioread16(ioaddr + Wn4_NetDiag), ioread16(ioaddr + Wn4_Media), ioread32(ioaddr + PktStatus), ioread16(ioaddr + Wn4_FIFODiag)); /* Slight code bloat to be user friendly. */ if ((ioread8(ioaddr + TxStatus) & 0x88) == 0x88) - printk(KERN_ERR "%s: Transmitter encountered 16 collisions --" + pr_err("%s: Transmitter encountered 16 collisions --" " network cable problem?\n", dev->name); if (ioread16(ioaddr + EL3_STATUS) & IntLatch) { - printk(KERN_ERR "%s: Interrupt posted but not delivered --" + pr_err("%s: Interrupt posted but not delivered --" " IRQ blocked by another device?\n", dev->name); /* Bad idea here.. but we might as well handle a few events. */ { @@ -1903,7 +1899,7 @@ static void vortex_tx_timeout(struct net_device *dev) dev->stats.tx_errors++; if (vp->full_bus_master_tx) { - printk(KERN_DEBUG "%s: Resetting the Tx ring pointer.\n", dev->name); + pr_debug("%s: Resetting the Tx ring pointer.\n", dev->name); if (vp->cur_tx - vp->dirty_tx > 0 && ioread32(ioaddr + DownListPtr) == 0) iowrite32(vp->tx_ring_dma + (vp->dirty_tx % TX_RING_SIZE) * sizeof(struct boom_tx_desc), ioaddr + DownListPtr); @@ -1938,7 +1934,7 @@ vortex_error(struct net_device *dev, int status) unsigned char tx_status = 0; if (vortex_debug > 2) { - printk(KERN_ERR "%s: vortex_error(), status=0x%x\n", dev->name, status); + pr_err("%s: vortex_error(), status=0x%x\n", dev->name, status); } if (status & TxComplete) { /* Really "TxError" for us. */ @@ -1946,10 +1942,10 @@ vortex_error(struct net_device *dev, int status) /* Presumably a tx-timeout. We must merely re-enable. */ if (vortex_debug > 2 || (tx_status != 0x88 && vortex_debug > 0)) { - printk(KERN_ERR "%s: Transmit error, Tx status register %2.2x.\n", + pr_err("%s: Transmit error, Tx status register %2.2x.\n", dev->name, tx_status); if (tx_status == 0x82) { - printk(KERN_ERR "Probably a duplex mismatch. See " + pr_err("Probably a duplex mismatch. See " "Documentation/networking/vortex.txt\n"); } dump_tx_ring(dev); @@ -1975,13 +1971,13 @@ vortex_error(struct net_device *dev, int status) if (status & StatsFull) { /* Empty statistics. */ static int DoneDidThat; if (vortex_debug > 4) - printk(KERN_DEBUG "%s: Updating stats.\n", dev->name); + pr_debug("%s: Updating stats.\n", dev->name); update_stats(ioaddr, dev); /* HACK: Disable statistics as an interrupt source. */ /* This occurs when we have the wrong media type! */ if (DoneDidThat == 0 && ioread16(ioaddr + EL3_STATUS) & StatsFull) { - printk(KERN_WARNING "%s: Updating statistics failed, disabling " + pr_warning("%s: Updating statistics failed, disabling " "stats as an interrupt source.\n", dev->name); EL3WINDOW(5); iowrite16(SetIntrEnb | (ioread16(ioaddr + 10) & ~StatsFull), ioaddr + EL3_CMD); @@ -1998,7 +1994,7 @@ vortex_error(struct net_device *dev, int status) u16 fifo_diag; EL3WINDOW(4); fifo_diag = ioread16(ioaddr + Wn4_FIFODiag); - printk(KERN_ERR "%s: Host error, FIFO diagnostic register %4.4x.\n", + pr_err("%s: Host error, FIFO diagnostic register %4.4x.\n", dev->name, fifo_diag); /* Adapter failure requires Tx/Rx reset and reinit. */ if (vp->full_bus_master_tx) { @@ -2006,7 +2002,7 @@ vortex_error(struct net_device *dev, int status) /* 0x80000000 PCI master abort. */ /* 0x40000000 PCI target abort. */ if (vortex_debug) - printk(KERN_ERR "%s: PCI bus error, bus status %8.8x\n", dev->name, bus_status); + pr_err("%s: PCI bus error, bus status %8.8x\n", dev->name, bus_status); /* In this case, blow the card away */ /* Must not enter D3 or we can't legally issue the reset! */ @@ -2075,7 +2071,7 @@ vortex_start_xmit(struct sk_buff *skb, struct net_device *dev) while (--i > 0 && (tx_status = ioread8(ioaddr + TxStatus)) > 0) { if (tx_status & 0x3C) { /* A Tx-disabling error occurred. */ if (vortex_debug > 2) - printk(KERN_DEBUG "%s: Tx error, status %2.2x.\n", + pr_debug("%s: Tx error, status %2.2x.\n", dev->name, tx_status); if (tx_status & 0x04) dev->stats.tx_fifo_errors++; if (tx_status & 0x38) dev->stats.tx_aborted_errors++; @@ -2101,17 +2097,17 @@ boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev) unsigned long flags; if (vortex_debug > 6) { - printk(KERN_DEBUG "boomerang_start_xmit()\n"); - printk(KERN_DEBUG "%s: Trying to send a packet, Tx index %d.\n", + pr_debug("boomerang_start_xmit()\n"); + pr_debug("%s: Trying to send a packet, Tx index %d.\n", dev->name, vp->cur_tx); } if (vp->cur_tx - vp->dirty_tx >= TX_RING_SIZE) { if (vortex_debug > 0) - printk(KERN_WARNING "%s: BUG! Tx Ring full, refusing to send buffer.\n", + pr_warning("%s: BUG! Tx Ring full, refusing to send buffer.\n", dev->name); netif_stop_queue(dev); - return 1; + return NETDEV_TX_BUSY; } vp->tx_skbuff[entry] = skb; @@ -2204,7 +2200,7 @@ vortex_interrupt(int irq, void *dev_id) status = ioread16(ioaddr + EL3_STATUS); if (vortex_debug > 6) - printk("vortex_interrupt(). status=0x%4x\n", status); + pr_debug("vortex_interrupt(). status=0x%4x\n", status); if ((status & IntLatch) == 0) goto handler_exit; /* No interrupt: shared IRQs cause this */ @@ -2219,19 +2215,19 @@ vortex_interrupt(int irq, void *dev_id) goto handler_exit; if (vortex_debug > 4) - printk(KERN_DEBUG "%s: interrupt, status %4.4x, latency %d ticks.\n", + pr_debug("%s: interrupt, status %4.4x, latency %d ticks.\n", dev->name, status, ioread8(ioaddr + Timer)); do { if (vortex_debug > 5) - printk(KERN_DEBUG "%s: In interrupt loop, status %4.4x.\n", + pr_debug("%s: In interrupt loop, status %4.4x.\n", dev->name, status); if (status & RxComplete) vortex_rx(dev); if (status & TxAvailable) { if (vortex_debug > 5) - printk(KERN_DEBUG " TX room bit was handled.\n"); + pr_debug(" TX room bit was handled.\n"); /* There's room in the FIFO for a full-sized packet. */ iowrite16(AckIntr | TxAvailable, ioaddr + EL3_CMD); netif_wake_queue (dev); @@ -2263,8 +2259,8 @@ vortex_interrupt(int irq, void *dev_id) } if (--work_done < 0) { - printk(KERN_WARNING "%s: Too much work in interrupt, status " - "%4.4x.\n", dev->name, status); + pr_warning("%s: Too much work in interrupt, status %4.4x.\n", + dev->name, status); /* Disable all pending interrupts. */ do { vp->deferred |= status; @@ -2281,7 +2277,7 @@ vortex_interrupt(int irq, void *dev_id) } while ((status = ioread16(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete)); if (vortex_debug > 4) - printk(KERN_DEBUG "%s: exiting interrupt, status %4.4x.\n", + pr_debug("%s: exiting interrupt, status %4.4x.\n", dev->name, status); handler_exit: spin_unlock(&vp->lock); @@ -2313,14 +2309,14 @@ boomerang_interrupt(int irq, void *dev_id) status = ioread16(ioaddr + EL3_STATUS); if (vortex_debug > 6) - printk(KERN_DEBUG "boomerang_interrupt. status=0x%4x\n", status); + pr_debug("boomerang_interrupt. status=0x%4x\n", status); if ((status & IntLatch) == 0) goto handler_exit; /* No interrupt: shared IRQs can cause this */ if (status == 0xffff) { /* h/w no longer present (hotplug)? */ if (vortex_debug > 1) - printk(KERN_DEBUG "boomerang_interrupt(1): status = 0xffff\n"); + pr_debug("boomerang_interrupt(1): status = 0xffff\n"); goto handler_exit; } @@ -2330,16 +2326,16 @@ boomerang_interrupt(int irq, void *dev_id) } if (vortex_debug > 4) - printk(KERN_DEBUG "%s: interrupt, status %4.4x, latency %d ticks.\n", + pr_debug("%s: interrupt, status %4.4x, latency %d ticks.\n", dev->name, status, ioread8(ioaddr + Timer)); do { if (vortex_debug > 5) - printk(KERN_DEBUG "%s: In interrupt loop, status %4.4x.\n", + pr_debug("%s: In interrupt loop, status %4.4x.\n", dev->name, status); if (status & UpComplete) { iowrite16(AckIntr | UpComplete, ioaddr + EL3_CMD); if (vortex_debug > 5) - printk(KERN_DEBUG "boomerang_interrupt->boomerang_rx\n"); + pr_debug("boomerang_interrupt->boomerang_rx\n"); boomerang_rx(dev); } @@ -2374,7 +2370,7 @@ boomerang_interrupt(int irq, void *dev_id) dev_kfree_skb_irq(skb); vp->tx_skbuff[entry] = NULL; } else { - printk(KERN_DEBUG "boomerang_interrupt: no skb!\n"); + pr_debug("boomerang_interrupt: no skb!\n"); } /* dev->stats.tx_packets++; Counted below. */ dirty_tx++; @@ -2382,7 +2378,7 @@ boomerang_interrupt(int irq, void *dev_id) vp->dirty_tx = dirty_tx; if (vp->cur_tx - dirty_tx <= TX_RING_SIZE - 1) { if (vortex_debug > 6) - printk(KERN_DEBUG "boomerang_interrupt: wake queue\n"); + pr_debug("boomerang_interrupt: wake queue\n"); netif_wake_queue (dev); } } @@ -2392,8 +2388,8 @@ boomerang_interrupt(int irq, void *dev_id) vortex_error(dev, status); if (--work_done < 0) { - printk(KERN_WARNING "%s: Too much work in interrupt, status " - "%4.4x.\n", dev->name, status); + pr_warning("%s: Too much work in interrupt, status %4.4x.\n", + dev->name, status); /* Disable all pending interrupts. */ do { vp->deferred |= status; @@ -2413,7 +2409,7 @@ boomerang_interrupt(int irq, void *dev_id) } while ((status = ioread16(ioaddr + EL3_STATUS)) & IntLatch); if (vortex_debug > 4) - printk(KERN_DEBUG "%s: exiting interrupt, status %4.4x.\n", + pr_debug("%s: exiting interrupt, status %4.4x.\n", dev->name, status); handler_exit: spin_unlock(&vp->lock); @@ -2428,13 +2424,13 @@ static int vortex_rx(struct net_device *dev) short rx_status; if (vortex_debug > 5) - printk(KERN_DEBUG "vortex_rx(): status %4.4x, rx_status %4.4x.\n", + pr_debug("vortex_rx(): status %4.4x, rx_status %4.4x.\n", ioread16(ioaddr+EL3_STATUS), ioread16(ioaddr+RxStatus)); while ((rx_status = ioread16(ioaddr + RxStatus)) > 0) { if (rx_status & 0x4000) { /* Error, update stats. */ unsigned char rx_error = ioread8(ioaddr + RxErrors); if (vortex_debug > 2) - printk(KERN_DEBUG " Rx error: status %2.2x.\n", rx_error); + pr_debug(" Rx error: status %2.2x.\n", rx_error); dev->stats.rx_errors++; if (rx_error & 0x01) dev->stats.rx_over_errors++; if (rx_error & 0x02) dev->stats.rx_length_errors++; @@ -2448,7 +2444,7 @@ static int vortex_rx(struct net_device *dev) skb = dev_alloc_skb(pkt_len + 5); if (vortex_debug > 4) - printk(KERN_DEBUG "Receiving packet size %d status %4.4x.\n", + pr_debug("Receiving packet size %d status %4.4x.\n", pkt_len, rx_status); if (skb != NULL) { skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ @@ -2478,8 +2474,8 @@ static int vortex_rx(struct net_device *dev) break; continue; } else if (vortex_debug > 0) - printk(KERN_NOTICE "%s: No memory to allocate a sk_buff of " - "size %d.\n", dev->name, pkt_len); + pr_notice("%s: No memory to allocate a sk_buff of size %d.\n", + dev->name, pkt_len); dev->stats.rx_dropped++; } issue_and_wait(dev, RxDiscard); @@ -2498,7 +2494,7 @@ boomerang_rx(struct net_device *dev) int rx_work_limit = vp->dirty_rx + RX_RING_SIZE - vp->cur_rx; if (vortex_debug > 5) - printk(KERN_DEBUG "boomerang_rx(): status %4.4x\n", ioread16(ioaddr+EL3_STATUS)); + pr_debug("boomerang_rx(): status %4.4x\n", ioread16(ioaddr+EL3_STATUS)); while ((rx_status = le32_to_cpu(vp->rx_ring[entry].status)) & RxDComplete){ if (--rx_work_limit < 0) @@ -2506,7 +2502,7 @@ boomerang_rx(struct net_device *dev) if (rx_status & RxDError) { /* Error, update stats. */ unsigned char rx_error = rx_status >> 16; if (vortex_debug > 2) - printk(KERN_DEBUG " Rx error: status %2.2x.\n", rx_error); + pr_debug(" Rx error: status %2.2x.\n", rx_error); dev->stats.rx_errors++; if (rx_error & 0x01) dev->stats.rx_over_errors++; if (rx_error & 0x02) dev->stats.rx_length_errors++; @@ -2520,7 +2516,7 @@ boomerang_rx(struct net_device *dev) dma_addr_t dma = le32_to_cpu(vp->rx_ring[entry].addr); if (vortex_debug > 4) - printk(KERN_DEBUG "Receiving packet size %d status %4.4x.\n", + pr_debug("Receiving packet size %d status %4.4x.\n", pkt_len, rx_status); /* Check if the packet is long enough to just accept without @@ -2566,7 +2562,7 @@ boomerang_rx(struct net_device *dev) if (skb == NULL) { static unsigned long last_jif; if (time_after(jiffies, last_jif + 10 * HZ)) { - printk(KERN_WARNING "%s: memory shortage\n", dev->name); + pr_warning("%s: memory shortage\n", dev->name); last_jif = jiffies; } if ((vp->cur_rx - vp->dirty_rx) == RX_RING_SIZE) @@ -2598,7 +2594,7 @@ rx_oom_timer(unsigned long arg) if ((vp->cur_rx - vp->dirty_rx) == RX_RING_SIZE) /* This test is redundant, but makes me feel good */ boomerang_rx(dev); if (vortex_debug > 1) { - printk(KERN_DEBUG "%s: rx_oom_timer %s\n", dev->name, + pr_debug("%s: rx_oom_timer %s\n", dev->name, ((vp->cur_rx - vp->dirty_rx) != RX_RING_SIZE) ? "succeeded" : "retrying"); } spin_unlock_irq(&vp->lock); @@ -2655,9 +2651,9 @@ vortex_close(struct net_device *dev) vortex_down(dev, 1); if (vortex_debug > 1) { - printk(KERN_DEBUG"%s: vortex_close() status %4.4x, Tx status %2.2x.\n", + pr_debug("%s: vortex_close() status %4.4x, Tx status %2.2x.\n", dev->name, ioread16(ioaddr + EL3_STATUS), ioread8(ioaddr + TxStatus)); - printk(KERN_DEBUG "%s: vortex close stats: rx_nocopy %d rx_copy %d" + pr_debug("%s: vortex close stats: rx_nocopy %d rx_copy %d" " tx_queued %d Rx pre-checksummed %d.\n", dev->name, vp->rx_nocopy, vp->rx_copy, vp->queued_packet, vp->rx_csumhits); } @@ -2666,8 +2662,7 @@ vortex_close(struct net_device *dev) if (vp->rx_csumhits && (vp->drv_flags & HAS_HWCKSM) == 0 && (vp->card_idx >= MAX_UNITS || hw_checksums[vp->card_idx] == -1)) { - printk(KERN_WARNING "%s supports hardware checksums, and we're " - "not using them!\n", dev->name); + pr_warning("%s supports hardware checksums, and we're not using them!\n", dev->name); } #endif @@ -2717,16 +2712,16 @@ dump_tx_ring(struct net_device *dev) int i; int stalled = ioread32(ioaddr + PktStatus) & 0x04; /* Possible racy. But it's only debug stuff */ - printk(KERN_ERR " Flags; bus-master %d, dirty %d(%d) current %d(%d)\n", + pr_err(" Flags; bus-master %d, dirty %d(%d) current %d(%d)\n", vp->full_bus_master_tx, vp->dirty_tx, vp->dirty_tx % TX_RING_SIZE, vp->cur_tx, vp->cur_tx % TX_RING_SIZE); - printk(KERN_ERR " Transmit list %8.8x vs. %p.\n", + pr_err(" Transmit list %8.8x vs. %p.\n", ioread32(ioaddr + DownListPtr), &vp->tx_ring[vp->dirty_tx % TX_RING_SIZE]); issue_and_wait(dev, DownStall); for (i = 0; i < TX_RING_SIZE; i++) { - printk(KERN_ERR " %d: @%p length %8.8x status %8.8x\n", i, + pr_err(" %d: @%p length %8.8x status %8.8x\n", i, &vp->tx_ring[i], #if DO_ZEROCOPY le32_to_cpu(vp->tx_ring[i].frag[0].length), @@ -2970,7 +2965,7 @@ static void set_rx_mode(struct net_device *dev) if (dev->flags & IFF_PROMISC) { if (vortex_debug > 3) - printk(KERN_NOTICE "%s: Setting promiscuous mode.\n", dev->name); + pr_notice("%s: Setting promiscuous mode.\n", dev->name); new_mode = SetRxFilter|RxStation|RxMulticast|RxBroadcast|RxProm; } else if ((dev->mc_list) || (dev->flags & IFF_ALLMULTI)) { new_mode = SetRxFilter|RxStation|RxMulticast|RxBroadcast; @@ -3145,8 +3140,7 @@ static void acpi_set_WOL(struct net_device *dev) iowrite16(RxEnable, ioaddr + EL3_CMD); if (pci_enable_wake(VORTEX_PCI(vp), PCI_D3hot, 1)) { - printk(KERN_INFO "%s: WOL not supported.\n", - pci_name(VORTEX_PCI(vp))); + pr_info("%s: WOL not supported.\n", pci_name(VORTEX_PCI(vp))); vp->enable_wol = 0; return; @@ -3164,7 +3158,7 @@ static void __devexit vortex_remove_one(struct pci_dev *pdev) struct vortex_private *vp; if (!dev) { - printk("vortex_remove_one called for Compaq device!\n"); + pr_err("vortex_remove_one called for Compaq device!\n"); BUG(); } diff --git a/drivers/net/7990.c b/drivers/net/7990.c index 7a331acc34ad..69f5b7d298a6 100644 --- a/drivers/net/7990.c +++ b/drivers/net/7990.c @@ -541,7 +541,7 @@ int lance_start_xmit (struct sk_buff *skb, struct net_device *dev) unsigned long flags; if (!TX_BUFFS_AVAIL) - return -1; + return NETDEV_TX_LOCKED; netif_stop_queue (dev); diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index 02330f3d5a55..50efde11ea6c 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -471,8 +471,7 @@ static void cp_rx_err_acct (struct cp_private *cp, unsigned rx_tail, u32 status, u32 len) { if (netif_msg_rx_err (cp)) - printk (KERN_DEBUG - "%s: rx err, slot %d status 0x%x len %d\n", + pr_debug("%s: rx err, slot %d status 0x%x len %d\n", cp->dev->name, rx_tail, status, len); cp->dev->stats.rx_errors++; if (status & RxErrFrame) @@ -547,7 +546,7 @@ rx_status_loop: } if (netif_msg_rx_status(cp)) - printk(KERN_DEBUG "%s: rx slot %d status 0x%x len %d\n", + pr_debug("%s: rx slot %d status 0x%x len %d\n", dev->name, rx_tail, status, len); buflen = cp->rx_buf_sz + NET_IP_ALIGN; @@ -626,7 +625,7 @@ static irqreturn_t cp_interrupt (int irq, void *dev_instance) return IRQ_NONE; if (netif_msg_intr(cp)) - printk(KERN_DEBUG "%s: intr, status %04x cmd %02x cpcmd %04x\n", + pr_debug("%s: intr, status %04x cmd %02x cpcmd %04x\n", dev->name, status, cpr8(Cmd), cpr16(CpCmd)); cpw16(IntrStatus, status & ~cp_rx_intr_mask); @@ -658,7 +657,7 @@ static irqreturn_t cp_interrupt (int irq, void *dev_instance) pci_read_config_word(cp->pdev, PCI_STATUS, &pci_status); pci_write_config_word(cp->pdev, PCI_STATUS, pci_status); - printk(KERN_ERR "%s: PCI bus error, status=%04x, PCI status=%04x\n", + pr_err("%s: PCI bus error, status=%04x, PCI status=%04x\n", dev->name, status, pci_status); /* TODO: reset hardware */ @@ -705,7 +704,7 @@ static void cp_tx (struct cp_private *cp) if (status & LastFrag) { if (status & (TxError | TxFIFOUnder)) { if (netif_msg_tx_err(cp)) - printk(KERN_DEBUG "%s: tx err, status 0x%x\n", + pr_debug("%s: tx err, status 0x%x\n", cp->dev->name, status); cp->dev->stats.tx_errors++; if (status & TxOWC) @@ -722,7 +721,7 @@ static void cp_tx (struct cp_private *cp) cp->dev->stats.tx_packets++; cp->dev->stats.tx_bytes += skb->len; if (netif_msg_tx_done(cp)) - printk(KERN_DEBUG "%s: tx done, slot %d\n", cp->dev->name, tx_tail); + pr_debug("%s: tx done, slot %d\n", cp->dev->name, tx_tail); } dev_kfree_skb_irq(skb); } @@ -755,9 +754,9 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev) if (TX_BUFFS_AVAIL(cp) <= (skb_shinfo(skb)->nr_frags + 1)) { netif_stop_queue(dev); spin_unlock_irqrestore(&cp->lock, intr_flags); - printk(KERN_ERR PFX "%s: BUG! Tx Ring full when queue awake!\n", + pr_err(PFX "%s: BUG! Tx Ring full when queue awake!\n", dev->name); - return 1; + return NETDEV_TX_BUSY; } #if CP_VLAN_TAG_USED @@ -882,7 +881,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev) } cp->tx_head = entry; if (netif_msg_tx_queued(cp)) - printk(KERN_DEBUG "%s: tx queued, slot %d, skblen %d\n", + pr_debug("%s: tx queued, slot %d, skblen %d\n", dev->name, entry, skb->len); if (TX_BUFFS_AVAIL(cp) <= (MAX_SKB_FRAGS + 1)) netif_stop_queue(dev); @@ -996,7 +995,7 @@ static void cp_reset_hw (struct cp_private *cp) schedule_timeout_uninterruptible(10); } - printk(KERN_ERR "%s: hardware reset timeout\n", cp->dev->name); + pr_err("%s: hardware reset timeout\n", cp->dev->name); } static inline void cp_start_hw (struct cp_private *cp) @@ -1166,7 +1165,7 @@ static int cp_open (struct net_device *dev) int rc; if (netif_msg_ifup(cp)) - printk(KERN_DEBUG "%s: enabling interface\n", dev->name); + pr_debug("%s: enabling interface\n", dev->name); rc = cp_alloc_rings(cp); if (rc) @@ -1201,7 +1200,7 @@ static int cp_close (struct net_device *dev) napi_disable(&cp->napi); if (netif_msg_ifdown(cp)) - printk(KERN_DEBUG "%s: disabling interface\n", dev->name); + pr_debug("%s: disabling interface\n", dev->name); spin_lock_irqsave(&cp->lock, flags); @@ -1224,7 +1223,7 @@ static void cp_tx_timeout(struct net_device *dev) unsigned long flags; int rc; - printk(KERN_WARNING "%s: Transmit timeout, status %2x %4x %4x %4x\n", + pr_warning("%s: Transmit timeout, status %2x %4x %4x %4x\n", dev->name, cpr8(Cmd), cpr16(CpCmd), cpr16(IntrStatus), cpr16(IntrMask)); @@ -1873,7 +1872,7 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) #ifndef MODULE static int version_printed; if (version_printed++ == 0) - printk("%s", version); + pr_info("%s", version); #endif if (pdev->vendor == PCI_VENDOR_ID_REALTEK && @@ -1995,8 +1994,7 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) goto err_out_iomap; - printk (KERN_INFO "%s: RTL-8139C+ at 0x%lx, " - "%pM, IRQ %d\n", + pr_info("%s: RTL-8139C+ at 0x%lx, %pM, IRQ %d\n", dev->name, dev->base_addr, dev->dev_addr, @@ -2113,7 +2111,7 @@ static struct pci_driver cp_driver = { static int __init cp_init (void) { #ifdef MODULE - printk("%s", version); + pr_info("%s", version); #endif return pci_register_driver(&cp_driver); } diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index 1fc45431a620..8ae72ec14456 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -126,19 +126,12 @@ #undef RTL8139_NDEBUG -#if RTL8139_DEBUG -/* note: prints function name for you */ -# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __func__ , ## args) -#else -# define DPRINTK(fmt, args...) -#endif - #ifdef RTL8139_NDEBUG # define assert(expr) do {} while (0) #else # define assert(expr) \ if(unlikely(!(expr))) { \ - printk(KERN_ERR "Assertion failed! %s,%s,%s,line=%d\n", \ + pr_err("Assertion failed! %s,%s,%s,line=%d\n", \ #expr, __FILE__, __func__, __LINE__); \ } #endif @@ -784,8 +777,8 @@ static __devinit struct net_device * rtl8139_init_board (struct pci_dev *pdev) /* set this immediately, we need to know before * we talk to the chip directly */ - DPRINTK("PIO region size == 0x%02X\n", pio_len); - DPRINTK("MMIO region size == 0x%02lX\n", mmio_len); + pr_debug("PIO region size == 0x%02lX\n", pio_len); + pr_debug("MMIO region size == 0x%02lX\n", mmio_len); retry: if (use_io) { @@ -865,19 +858,17 @@ retry: } /* if unknown chip, assume array element #0, original RTL-8139 in this case */ - dev_printk (KERN_DEBUG, &pdev->dev, - "unknown chip version, assuming RTL-8139\n"); - dev_printk (KERN_DEBUG, &pdev->dev, - "TxConfig = 0x%lx\n", RTL_R32 (TxConfig)); + dev_dbg(&pdev->dev, "unknown chip version, assuming RTL-8139\n"); + dev_dbg(&pdev->dev, "TxConfig = 0x%lx\n", RTL_R32 (TxConfig)); tp->chipset = 0; match: - DPRINTK ("chipset id (%d) == index %d, '%s'\n", + pr_debug("chipset id (%d) == index %d, '%s'\n", version, i, rtl_chip_info[i].name); if (tp->chipset >= CH_8139B) { u8 new_tmp8 = tmp8 = RTL_R8 (Config1); - DPRINTK("PCI PM wakeup\n"); + pr_debug("PCI PM wakeup\n"); if ((rtl_chip_info[tp->chipset].flags & HasLWake) && (tmp8 & LWAKE)) new_tmp8 &= ~LWAKE; @@ -896,7 +887,7 @@ match: } } } else { - DPRINTK("Old chip wakeup\n"); + pr_debug("Old chip wakeup\n"); tmp8 = RTL_R8 (Config1); tmp8 &= ~(SLEEP | PWRDN); RTL_W8 (Config1, tmp8); @@ -949,7 +940,7 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, { static int printed_version; if (!printed_version++) - printk (KERN_INFO RTL8139_DRIVER_NAME "\n"); + pr_info(RTL8139_DRIVER_NAME "\n"); } #endif @@ -965,7 +956,7 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, pdev->device == PCI_DEVICE_ID_REALTEK_8139 && pdev->subsystem_vendor == PCI_VENDOR_ID_ATHEROS && pdev->subsystem_device == PCI_DEVICE_ID_REALTEK_8139) { - printk(KERN_INFO "8139too: OQO Model 2 detected. Forcing PIO\n"); + pr_info("8139too: OQO Model 2 detected. Forcing PIO\n"); use_io = 1; } @@ -1018,21 +1009,20 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, tp->mii.reg_num_mask = 0x1f; /* dev is fully set up and ready to use now */ - DPRINTK("about to register device named %s (%p)...\n", dev->name, dev); + pr_debug("about to register device named %s (%p)...\n", dev->name, dev); i = register_netdev (dev); if (i) goto err_out; pci_set_drvdata (pdev, dev); - printk (KERN_INFO "%s: %s at 0x%lx, " - "%pM, IRQ %d\n", + pr_info("%s: %s at 0x%lx, %pM, IRQ %d\n", dev->name, board_info[ent->driver_data].name, dev->base_addr, dev->dev_addr, dev->irq); - printk (KERN_DEBUG "%s: Identified 8139 chip type '%s'\n", + pr_debug("%s: Identified 8139 chip type '%s'\n", dev->name, rtl_chip_info[tp->chipset].name); /* Find the connected MII xcvrs. @@ -1046,14 +1036,12 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, if (mii_status != 0xffff && mii_status != 0x0000) { u16 advertising = mdio_read(dev, phy, 4); tp->phys[phy_idx++] = phy; - printk(KERN_INFO "%s: MII transceiver %d status 0x%4.4x " - "advertising %4.4x.\n", + pr_info("%s: MII transceiver %d status 0x%4.4x advertising %4.4x.\n", dev->name, phy, mii_status, advertising); } } if (phy_idx == 0) { - printk(KERN_INFO "%s: No MII transceivers found! Assuming SYM " - "transceiver.\n", + pr_info("%s: No MII transceivers found! Assuming SYM transceiver.\n", dev->name); tp->phys[0] = 32; } @@ -1073,13 +1061,13 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, if (board_idx < MAX_UNITS && full_duplex[board_idx] > 0) tp->mii.full_duplex = full_duplex[board_idx]; if (tp->mii.full_duplex) { - printk(KERN_INFO "%s: Media type forced to Full Duplex.\n", dev->name); + pr_info("%s: Media type forced to Full Duplex.\n", dev->name); /* Changing the MII-advertised media because might prevent re-connection. */ tp->mii.force_media = 1; } if (tp->default_port) { - printk(KERN_INFO " Forcing %dMbps %s-duplex operation.\n", + pr_info(" Forcing %dMbps %s-duplex operation.\n", (option & 0x20 ? 100 : 10), (option & 0x10 ? "full" : "half")); mdio_write(dev, tp->phys[0], 0, @@ -1342,7 +1330,7 @@ static int rtl8139_open (struct net_device *dev) netif_start_queue (dev); if (netif_msg_ifup(tp)) - printk(KERN_DEBUG "%s: rtl8139_open() ioaddr %#llx IRQ %d" + pr_debug("%s: rtl8139_open() ioaddr %#llx IRQ %d" " GP Pins %2.2x %s-duplex.\n", dev->name, (unsigned long long)pci_resource_start (tp->pci_dev, 1), dev->irq, RTL_R8 (MediaStatus), @@ -1404,7 +1392,7 @@ static void rtl8139_hw_start (struct net_device *dev) RTL_W8 (Config3, RTL_R8 (Config3) & ~Cfg3_Magic); } - DPRINTK("init buffer addresses\n"); + pr_debug("init buffer addresses\n"); /* Lock Config[01234] and BMCR register writes */ RTL_W8 (Cfg9346, Cfg9346_Lock); @@ -1566,14 +1554,13 @@ static inline void rtl8139_thread_iter (struct net_device *dev, tp->mii.full_duplex = duplex; if (mii_lpa) { - printk (KERN_INFO - "%s: Setting %s-duplex based on MII #%d link" + pr_info("%s: Setting %s-duplex based on MII #%d link" " partner ability of %4.4x.\n", dev->name, tp->mii.full_duplex ? "full" : "half", tp->phys[0], mii_lpa); } else { - printk(KERN_INFO"%s: media is unconnected, link down, or incompatible connection\n", + pr_info("%s: media is unconnected, link down, or incompatible connection\n", dev->name); } #if 0 @@ -1588,11 +1575,11 @@ static inline void rtl8139_thread_iter (struct net_device *dev, rtl8139_tune_twister (dev, tp); - DPRINTK ("%s: Media selection tick, Link partner %4.4x.\n", + pr_debug("%s: Media selection tick, Link partner %4.4x.\n", dev->name, RTL_R16 (NWayLPAR)); - DPRINTK ("%s: Other registers are IntMask %4.4x IntStatus %4.4x\n", + pr_debug("%s: Other registers are IntMask %4.4x IntStatus %4.4x\n", dev->name, RTL_R16 (IntrMask), RTL_R16 (IntrStatus)); - DPRINTK ("%s: Chip config %2.2x %2.2x.\n", + pr_debug("%s: Chip config %2.2x %2.2x.\n", dev->name, RTL_R8 (Config0), RTL_R8 (Config1)); } @@ -1652,14 +1639,14 @@ static void rtl8139_tx_timeout_task (struct work_struct *work) int i; u8 tmp8; - printk (KERN_DEBUG "%s: Transmit timeout, status %2.2x %4.4x %4.4x " - "media %2.2x.\n", dev->name, RTL_R8 (ChipCmd), + pr_debug("%s: Transmit timeout, status %2.2x %4.4x %4.4x media %2.2x.\n", + dev->name, RTL_R8 (ChipCmd), RTL_R16(IntrStatus), RTL_R16(IntrMask), RTL_R8(MediaStatus)); /* Emit info to figure out what went wrong. */ - printk (KERN_DEBUG "%s: Tx queue start entry %ld dirty entry %ld.\n", + pr_debug("%s: Tx queue start entry %ld dirty entry %ld.\n", dev->name, tp->cur_tx, tp->dirty_tx); for (i = 0; i < NUM_TX_DESC; i++) - printk (KERN_DEBUG "%s: Tx descriptor %d is %8.8lx.%s\n", + pr_debug("%s: Tx descriptor %d is %8.8lx.%s\n", dev->name, i, RTL_R32 (TxStatus0 + (i * 4)), i == tp->dirty_tx % NUM_TX_DESC ? " (queue head)" : ""); @@ -1741,7 +1728,7 @@ static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&tp->lock, flags); if (netif_msg_tx_queued(tp)) - printk (KERN_DEBUG "%s: Queued Tx packet size %u to slot %d.\n", + pr_debug("%s: Queued Tx packet size %u to slot %d.\n", dev->name, len, entry); return 0; @@ -1772,7 +1759,7 @@ static void rtl8139_tx_interrupt (struct net_device *dev, if (txstatus & (TxOutOfWindow | TxAborted)) { /* There was an major error, log it. */ if (netif_msg_tx_err(tp)) - printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n", + pr_debug("%s: Transmit error, Tx status %8.8x.\n", dev->name, txstatus); dev->stats.tx_errors++; if (txstatus & TxAborted) { @@ -1803,7 +1790,7 @@ static void rtl8139_tx_interrupt (struct net_device *dev, #ifndef RTL8139_NDEBUG if (tp->cur_tx - dirty_tx > NUM_TX_DESC) { - printk (KERN_ERR "%s: Out-of-sync dirty pointer, %ld vs. %ld.\n", + pr_err("%s: Out-of-sync dirty pointer, %ld vs. %ld.\n", dev->name, dirty_tx, tp->cur_tx); dirty_tx += NUM_TX_DESC; } @@ -1828,12 +1815,12 @@ static void rtl8139_rx_err (u32 rx_status, struct net_device *dev, #endif if (netif_msg_rx_err (tp)) - printk(KERN_DEBUG "%s: Ethernet frame had errors, status %8.8x.\n", + pr_debug("%s: Ethernet frame had errors, status %8.8x.\n", dev->name, rx_status); dev->stats.rx_errors++; if (!(rx_status & RxStatusOK)) { if (rx_status & RxTooLong) { - DPRINTK ("%s: Oversized Ethernet frame, status %4.4x!\n", + pr_debug("%s: Oversized Ethernet frame, status %4.4x!\n", dev->name, rx_status); /* A.C.: The chip hangs here. */ } @@ -1866,7 +1853,7 @@ static void rtl8139_rx_err (u32 rx_status, struct net_device *dev, break; } if (tmp_work <= 0) - printk (KERN_WARNING PFX "rx stop wait too long\n"); + pr_warning(PFX "rx stop wait too long\n"); /* restart receive */ tmp_work = 200; while (--tmp_work > 0) { @@ -1877,7 +1864,7 @@ static void rtl8139_rx_err (u32 rx_status, struct net_device *dev, break; } if (tmp_work <= 0) - printk (KERN_WARNING PFX "tx/rx enable wait too long\n"); + pr_warning(PFX "tx/rx enable wait too long\n"); /* and reinitialize all rx related registers */ RTL_W8_F (Cfg9346, Cfg9346_Unlock); @@ -1888,7 +1875,7 @@ static void rtl8139_rx_err (u32 rx_status, struct net_device *dev, RTL_W32 (RxConfig, tp->rx_config); tp->cur_rx = 0; - DPRINTK("init buffer addresses\n"); + pr_debug("init buffer addresses\n"); /* Lock Config[01234] and BMCR register writes */ RTL_W8 (Cfg9346, Cfg9346_Lock); @@ -1942,7 +1929,7 @@ static int rtl8139_rx(struct net_device *dev, struct rtl8139_private *tp, unsigned int cur_rx = tp->cur_rx; unsigned int rx_size = 0; - DPRINTK ("%s: In rtl8139_rx(), current %4.4x BufAddr %4.4x," + pr_debug("%s: In rtl8139_rx(), current %4.4x BufAddr %4.4x," " free to %4.4x, Cmd %2.2x.\n", dev->name, (u16)cur_rx, RTL_R16 (RxBufAddr), RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd)); @@ -1962,17 +1949,17 @@ static int rtl8139_rx(struct net_device *dev, struct rtl8139_private *tp, pkt_size = rx_size - 4; if (netif_msg_rx_status(tp)) - printk(KERN_DEBUG "%s: rtl8139_rx() status %4.4x, size %4.4x," + pr_debug("%s: rtl8139_rx() status %4.4x, size %4.4x," " cur %4.4x.\n", dev->name, rx_status, rx_size, cur_rx); #if RTL8139_DEBUG > 2 { int i; - DPRINTK ("%s: Frame contents ", dev->name); + pr_debug("%s: Frame contents ", dev->name); for (i = 0; i < 70; i++) - printk (" %2.2x", + pr_cont(" %2.2x", rx_ring[ring_offset + i]); - printk (".\n"); + pr_cont(".\n"); } #endif @@ -1984,12 +1971,12 @@ static int rtl8139_rx(struct net_device *dev, struct rtl8139_private *tp, if (!tp->fifo_copy_timeout) tp->fifo_copy_timeout = jiffies + 2; else if (time_after(jiffies, tp->fifo_copy_timeout)) { - DPRINTK ("%s: hung FIFO. Reset.", dev->name); + pr_debug("%s: hung FIFO. Reset.", dev->name); rx_size = 0; goto no_early_rx; } if (netif_msg_intr(tp)) { - printk(KERN_DEBUG "%s: fifo copy in progress.", + pr_debug("%s: fifo copy in progress.", dev->name); } tp->xstats.early_rx++; @@ -2033,8 +2020,7 @@ no_early_rx: netif_receive_skb (skb); } else { if (net_ratelimit()) - printk (KERN_WARNING - "%s: Memory squeeze, dropping packet.\n", + pr_warning("%s: Memory squeeze, dropping packet.\n", dev->name); dev->stats.rx_dropped++; } @@ -2049,12 +2035,10 @@ no_early_rx: if (unlikely(!received || rx_size == 0xfff0)) rtl8139_isr_ack(tp); -#if RTL8139_DEBUG > 1 - DPRINTK ("%s: Done rtl8139_rx(), current %4.4x BufAddr %4.4x," + pr_debug("%s: Done rtl8139_rx(), current %4.4x BufAddr %4.4x," " free to %4.4x, Cmd %2.2x.\n", dev->name, cur_rx, RTL_R16 (RxBufAddr), RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd)); -#endif tp->cur_rx = cur_rx; @@ -2075,7 +2059,7 @@ static void rtl8139_weird_interrupt (struct net_device *dev, void __iomem *ioaddr, int status, int link_changed) { - DPRINTK ("%s: Abnormal interrupt, status %8.8x.\n", + pr_debug("%s: Abnormal interrupt, status %8.8x.\n", dev->name, status); assert (dev != NULL); @@ -2104,7 +2088,7 @@ static void rtl8139_weird_interrupt (struct net_device *dev, pci_read_config_word (tp->pci_dev, PCI_STATUS, &pci_cmd_status); pci_write_config_word (tp->pci_dev, PCI_STATUS, pci_cmd_status); - printk (KERN_ERR "%s: PCI Bus error %4.4x.\n", + pr_err("%s: PCI Bus error %4.4x.\n", dev->name, pci_cmd_status); } } @@ -2198,7 +2182,7 @@ static irqreturn_t rtl8139_interrupt (int irq, void *dev_instance) out: spin_unlock (&tp->lock); - DPRINTK ("%s: exiting interrupt, intr_status=%#4.4x.\n", + pr_debug("%s: exiting interrupt, intr_status=%#4.4x.\n", dev->name, RTL_R16 (IntrStatus)); return IRQ_RETVAL(handled); } @@ -2249,7 +2233,7 @@ static int rtl8139_close (struct net_device *dev) napi_disable(&tp->napi); if (netif_msg_ifdown(tp)) - printk(KERN_DEBUG "%s: Shutting down ethercard, status was 0x%4.4x.\n", + pr_debug("%s: Shutting down ethercard, status was 0x%4.4x.\n", dev->name, RTL_R16 (IntrStatus)); spin_lock_irqsave (&tp->lock, flags); @@ -2292,11 +2276,11 @@ static int rtl8139_close (struct net_device *dev) other threads or interrupts aren't messing with the 8139. */ static void rtl8139_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { - struct rtl8139_private *np = netdev_priv(dev); - void __iomem *ioaddr = np->mmio_addr; + struct rtl8139_private *tp = netdev_priv(dev); + void __iomem *ioaddr = tp->mmio_addr; - spin_lock_irq(&np->lock); - if (rtl_chip_info[np->chipset].flags & HasLWake) { + spin_lock_irq(&tp->lock); + if (rtl_chip_info[tp->chipset].flags & HasLWake) { u8 cfg3 = RTL_R8 (Config3); u8 cfg5 = RTL_R8 (Config5); @@ -2317,7 +2301,7 @@ static void rtl8139_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) if (cfg5 & Cfg5_BWF) wol->wolopts |= WAKE_BCAST; } - spin_unlock_irq(&np->lock); + spin_unlock_irq(&tp->lock); } @@ -2326,19 +2310,19 @@ static void rtl8139_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) aren't messing with the 8139. */ static int rtl8139_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { - struct rtl8139_private *np = netdev_priv(dev); - void __iomem *ioaddr = np->mmio_addr; + struct rtl8139_private *tp = netdev_priv(dev); + void __iomem *ioaddr = tp->mmio_addr; u32 support; u8 cfg3, cfg5; - support = ((rtl_chip_info[np->chipset].flags & HasLWake) + support = ((rtl_chip_info[tp->chipset].flags & HasLWake) ? (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_MCAST | WAKE_BCAST) : 0); if (wol->wolopts & ~support) return -EINVAL; - spin_lock_irq(&np->lock); + spin_lock_irq(&tp->lock); cfg3 = RTL_R8 (Config3) & ~(Cfg3_LinkUp | Cfg3_Magic); if (wol->wolopts & WAKE_PHY) cfg3 |= Cfg3_LinkUp; @@ -2359,87 +2343,87 @@ static int rtl8139_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) if (wol->wolopts & WAKE_BCAST) cfg5 |= Cfg5_BWF; RTL_W8 (Config5, cfg5); /* need not unlock via Cfg9346 */ - spin_unlock_irq(&np->lock); + spin_unlock_irq(&tp->lock); return 0; } static void rtl8139_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - struct rtl8139_private *np = netdev_priv(dev); + struct rtl8139_private *tp = netdev_priv(dev); strcpy(info->driver, DRV_NAME); strcpy(info->version, DRV_VERSION); - strcpy(info->bus_info, pci_name(np->pci_dev)); - info->regdump_len = np->regs_len; + strcpy(info->bus_info, pci_name(tp->pci_dev)); + info->regdump_len = tp->regs_len; } static int rtl8139_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { - struct rtl8139_private *np = netdev_priv(dev); - spin_lock_irq(&np->lock); - mii_ethtool_gset(&np->mii, cmd); - spin_unlock_irq(&np->lock); + struct rtl8139_private *tp = netdev_priv(dev); + spin_lock_irq(&tp->lock); + mii_ethtool_gset(&tp->mii, cmd); + spin_unlock_irq(&tp->lock); return 0; } static int rtl8139_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { - struct rtl8139_private *np = netdev_priv(dev); + struct rtl8139_private *tp = netdev_priv(dev); int rc; - spin_lock_irq(&np->lock); - rc = mii_ethtool_sset(&np->mii, cmd); - spin_unlock_irq(&np->lock); + spin_lock_irq(&tp->lock); + rc = mii_ethtool_sset(&tp->mii, cmd); + spin_unlock_irq(&tp->lock); return rc; } static int rtl8139_nway_reset(struct net_device *dev) { - struct rtl8139_private *np = netdev_priv(dev); - return mii_nway_restart(&np->mii); + struct rtl8139_private *tp = netdev_priv(dev); + return mii_nway_restart(&tp->mii); } static u32 rtl8139_get_link(struct net_device *dev) { - struct rtl8139_private *np = netdev_priv(dev); - return mii_link_ok(&np->mii); + struct rtl8139_private *tp = netdev_priv(dev); + return mii_link_ok(&tp->mii); } static u32 rtl8139_get_msglevel(struct net_device *dev) { - struct rtl8139_private *np = netdev_priv(dev); - return np->msg_enable; + struct rtl8139_private *tp = netdev_priv(dev); + return tp->msg_enable; } static void rtl8139_set_msglevel(struct net_device *dev, u32 datum) { - struct rtl8139_private *np = netdev_priv(dev); - np->msg_enable = datum; + struct rtl8139_private *tp = netdev_priv(dev); + tp->msg_enable = datum; } static int rtl8139_get_regs_len(struct net_device *dev) { - struct rtl8139_private *np; + struct rtl8139_private *tp; /* TODO: we are too slack to do reg dumping for pio, for now */ if (use_io) return 0; - np = netdev_priv(dev); - return np->regs_len; + tp = netdev_priv(dev); + return tp->regs_len; } static void rtl8139_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *regbuf) { - struct rtl8139_private *np; + struct rtl8139_private *tp; /* TODO: we are too slack to do reg dumping for pio, for now */ if (use_io) return; - np = netdev_priv(dev); + tp = netdev_priv(dev); regs->version = RTL_REGS_VER; - spin_lock_irq(&np->lock); - memcpy_fromio(regbuf, np->mmio_addr, regs->len); - spin_unlock_irq(&np->lock); + spin_lock_irq(&tp->lock); + memcpy_fromio(regbuf, tp->mmio_addr, regs->len); + spin_unlock_irq(&tp->lock); } static int rtl8139_get_sset_count(struct net_device *dev, int sset) @@ -2454,12 +2438,12 @@ static int rtl8139_get_sset_count(struct net_device *dev, int sset) static void rtl8139_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *data) { - struct rtl8139_private *np = netdev_priv(dev); + struct rtl8139_private *tp = netdev_priv(dev); - data[0] = np->xstats.early_rx; - data[1] = np->xstats.tx_buf_mapped; - data[2] = np->xstats.tx_timeouts; - data[3] = np->xstats.rx_lost_in_ring; + data[0] = tp->xstats.early_rx; + data[1] = tp->xstats.tx_buf_mapped; + data[2] = tp->xstats.tx_timeouts; + data[3] = tp->xstats.rx_lost_in_ring; } static void rtl8139_get_strings(struct net_device *dev, u32 stringset, u8 *data) @@ -2486,15 +2470,15 @@ static const struct ethtool_ops rtl8139_ethtool_ops = { static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - struct rtl8139_private *np = netdev_priv(dev); + struct rtl8139_private *tp = netdev_priv(dev); int rc; if (!netif_running(dev)) return -EINVAL; - spin_lock_irq(&np->lock); - rc = generic_mii_ioctl(&np->mii, if_mii(rq), cmd, NULL); - spin_unlock_irq(&np->lock); + spin_lock_irq(&tp->lock); + rc = generic_mii_ioctl(&tp->mii, if_mii(rq), cmd, NULL); + spin_unlock_irq(&tp->lock); return rc; } @@ -2527,7 +2511,7 @@ static void __set_rx_mode (struct net_device *dev) int i, rx_mode; u32 tmp; - DPRINTK ("%s: rtl8139_set_rx_mode(%4.4x) done -- Rx config %8.8lx.\n", + pr_debug("%s: rtl8139_set_rx_mode(%4.4x) done -- Rx config %8.8lx.\n", dev->name, dev->flags, RTL_R32 (RxConfig)); /* Note: do not reorder, GCC is clever about common statements. */ @@ -2643,7 +2627,7 @@ static int __init rtl8139_init_module (void) * even if no 8139 board is found. */ #ifdef MODULE - printk (KERN_INFO RTL8139_DRIVER_NAME "\n"); + pr_info(RTL8139_DRIVER_NAME "\n"); #endif return pci_register_driver(&rtl8139_pci_driver); diff --git a/drivers/net/82596.c b/drivers/net/82596.c index cca94b9c08ae..77547545509b 100644 --- a/drivers/net/82596.c +++ b/drivers/net/82596.c @@ -122,13 +122,13 @@ static char version[] __initdata = #define ISCP_BUSY 0x00010000 #define MACH_IS_APRICOT 0 #else -#define WSWAPrfd(x) ((struct i596_rfd *)(x)) -#define WSWAPrbd(x) ((struct i596_rbd *)(x)) -#define WSWAPiscp(x) ((struct i596_iscp *)(x)) -#define WSWAPscb(x) ((struct i596_scb *)(x)) -#define WSWAPcmd(x) ((struct i596_cmd *)(x)) -#define WSWAPtbd(x) ((struct i596_tbd *)(x)) -#define WSWAPchar(x) ((char *)(x)) +#define WSWAPrfd(x) ((struct i596_rfd *)((long)x)) +#define WSWAPrbd(x) ((struct i596_rbd *)((long)x)) +#define WSWAPiscp(x) ((struct i596_iscp *)((long)x)) +#define WSWAPscb(x) ((struct i596_scb *)((long)x)) +#define WSWAPcmd(x) ((struct i596_cmd *)((long)x)) +#define WSWAPtbd(x) ((struct i596_tbd *)((long)x)) +#define WSWAPchar(x) ((char *)((long)x)) #define ISCP_BUSY 0x0001 #define MACH_IS_APRICOT 1 #endif diff --git a/drivers/net/8390.c b/drivers/net/8390.c index ec3e22e6306f..21153dea8ebe 100644 --- a/drivers/net/8390.c +++ b/drivers/net/8390.c @@ -74,14 +74,8 @@ EXPORT_SYMBOL(ei_netdev_ops); struct net_device *__alloc_ei_netdev(int size) { struct net_device *dev = ____alloc_ei_netdev(size); -#ifdef CONFIG_COMPAT_NET_DEV_OPS - if (dev) { - dev->hard_start_xmit = ei_start_xmit; - dev->get_stats = ei_get_stats; - dev->set_multicast_list = ei_set_multicast_list; - dev->tx_timeout = ei_tx_timeout; - } -#endif + if (dev) + dev->netdev_ops = &ei_netdev_ops; return dev; } EXPORT_SYMBOL(__alloc_ei_netdev); diff --git a/drivers/net/8390p.c b/drivers/net/8390p.c index da863c91d1d0..d225c291fd93 100644 --- a/drivers/net/8390p.c +++ b/drivers/net/8390p.c @@ -79,14 +79,8 @@ EXPORT_SYMBOL(eip_netdev_ops); struct net_device *__alloc_eip_netdev(int size) { struct net_device *dev = ____alloc_ei_netdev(size); -#ifdef CONFIG_COMPAT_NET_DEV_OPS - if (dev) { - dev->hard_start_xmit = eip_start_xmit; - dev->get_stats = eip_get_stats; - dev->set_multicast_list = eip_set_multicast_list; - dev->tx_timeout = eip_tx_timeout; - } -#endif + if (dev) + dev->netdev_ops = &eip_netdev_ops; return dev; } EXPORT_SYMBOL(__alloc_eip_netdev); @@ -97,16 +91,15 @@ void NS8390p_init(struct net_device *dev, int startp) } EXPORT_SYMBOL(NS8390p_init); -#if defined(MODULE) - -int init_module(void) +static int __init NS8390p_init_module(void) { return 0; } -void cleanup_module(void) +static void __exit NS8390p_cleanup_module(void) { } -#endif /* MODULE */ +module_init(NS8390p_init_module); +module_exit(NS8390p_cleanup_module); MODULE_LICENSE("GPL"); diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 214a92d1ef75..c155bd3ec9f1 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1,4 +1,3 @@ - # # Network device configuration # @@ -26,15 +25,6 @@ menuconfig NETDEVICES # that for each of the symbols. if NETDEVICES -config COMPAT_NET_DEV_OPS - default y - bool "Enable older network device API compatibility" - ---help--- - This option enables kernel compatibility with older network devices - that do not use net_device_ops interface. - - If unsure, say Y. - config IFB tristate "Intermediate Functional Block support" depends on NET_CLS_ACT @@ -526,15 +516,16 @@ config STNIC config SH_ETH tristate "Renesas SuperH Ethernet support" depends on SUPERH && \ - (CPU_SUBTYPE_SH7710 || CPU_SUBTYPE_SH7712 || CPU_SUBTYPE_SH7763 || \ - CPU_SUBTYPE_SH7619) + (CPU_SUBTYPE_SH7710 || CPU_SUBTYPE_SH7712 || \ + CPU_SUBTYPE_SH7763 || CPU_SUBTYPE_SH7619 || \ + CPU_SUBTYPE_SH7724) select CRC32 select MII select MDIO_BITBANG select PHYLIB help Renesas SuperH Ethernet device driver. - This driver support SH7710, SH7712, SH7763 and SH7619. + This driver support SH7710, SH7712, SH7763, SH7619, and SH7724. config SUNLANCE tristate "Sun LANCE support" @@ -927,6 +918,16 @@ config NET_NETX To compile this driver as a module, choose M here. The module will be called netx-eth. +config TI_DAVINCI_EMAC + tristate "TI DaVinci EMAC Support" + depends on ARM && ARCH_DAVINCI + select PHYLIB + help + This driver supports TI's DaVinci Ethernet . + + To compile this driver as a module, choose M here: the module + will be called davinci_emac_driver. This is recommended. + config DM9000 tristate "DM9000 support" depends on ARM || BLACKFIN || MIPS @@ -1000,7 +1001,7 @@ config SMC911X config SMSC911X tristate "SMSC LAN911x/LAN921x families embedded ethernet support" - depends on ARM || SUPERH + depends on ARM || SUPERH || BLACKFIN select CRC32 select MII select PHYLIB @@ -1722,6 +1723,12 @@ config TLAN Please email feedback to . +config KS8842 + tristate "Micrel KSZ8842" + depends on HAS_IOMEM + help + This platform driver is for Micrel KSZ8842 chip. + config VIA_RHINE tristate "VIA Rhine support" depends on NET_PCI && PCI @@ -1858,8 +1865,8 @@ config 68360_ENET the Motorola 68360 processor. config FEC - bool "FEC ethernet controller (of ColdFire CPUs)" - depends on M523x || M527x || M5272 || M528x || M520x || M532x || MACH_MX27 + bool "FEC ethernet controller (of ColdFire and some i.MX CPUs)" + depends on M523x || M527x || M5272 || M528x || M520x || M532x || MACH_MX27 || ARCH_MX35 help Say Y here if you want to use the built-in 10/100 Fast ethernet controller on some Motorola ColdFire and Freescale i.MX processors. @@ -1880,7 +1887,7 @@ config FEC_MPC52xx ---help--- This option enables support for the MPC5200's on-chip Fast Ethernet Controller - If compiled as module, it will be called 'fec_mpc52xx.ko'. + If compiled as module, it will be called fec_mpc52xx. config FEC_MPC52xx_MDIO bool "MPC52xx FEC MDIO bus driver" @@ -1892,7 +1899,7 @@ config FEC_MPC52xx_MDIO (Motorola? industry standard). If your board uses an external PHY connected to FEC, enable this. If not sure, enable. - If compiled as module, it will be called 'fec_mpc52xx_phy.ko'. + If compiled as module, it will be called fec_mpc52xx_phy. config NE_H8300 tristate "NE2000 compatible support for H8/300" @@ -2200,7 +2207,7 @@ config SKGE_DEBUG depends on SKGE && DEBUG_FS help This option adds the ability to dump driver state for debugging. - The file debugfs/skge/ethX displays the state of the internal + The file /sys/kernel/debug/skge/ethX displays the state of the internal transmit and receive rings. If unsure, say N. @@ -2226,7 +2233,7 @@ config SKY2_DEBUG depends on SKY2 && DEBUG_FS help This option adds the ability to dump driver state for debugging. - The file debugfs/sky2/ethX displays the state of the internal + The file /sys/kernel/debug/sky2/ethX displays the state of the internal transmit and receive rings. If unsure, say N. @@ -2264,6 +2271,18 @@ config BNX2 To compile this driver as a module, choose M here: the module will be called bnx2. This is recommended. +config CNIC + tristate "Broadcom CNIC support" + depends on PCI + select BNX2 + select UIO + help + This driver supports offload features of Broadcom NetXtremeII + gigabit Ethernet cards. + + To compile this driver as a module, choose M here: the module + will be called cnic. This is recommended. + config SPIDER_NET tristate "Spider Gigabit Ethernet driver" depends on PCI && (PPC_IBM_CELL_BLADE || PPC_CELLEB) @@ -2351,7 +2370,7 @@ config UGETH_TX_ON_DEMAND config MV643XX_ETH tristate "Marvell Discovery (643XX) and Orion ethernet support" - depends on MV64360 || MV64X60 || (PPC_MULTIPLATFORM && PPC32) || PLAT_ORION + depends on MV64X60 || PPC32 || PLAT_ORION select INET_LRO select PHYLIB help @@ -2362,6 +2381,14 @@ config MV643XX_ETH Some boards that use the Discovery chipset are the Momenco Ocelot C and Jaguar ATX and Pegasos II. +config XILINX_LL_TEMAC + tristate "Xilinx LL TEMAC (LocalLink Tri-mode Ethernet MAC) driver" + select PHYLIB + depends on PPC_DCR_NATIVE + help + This driver supports the Xilinx 10/100/1000 LocalLink TEMAC + core used in Xilinx Spartan and Virtex FPGAs + config QLA3XXX tristate "QLogic QLA3XXX Network Driver Support" depends on PCI @@ -2417,6 +2444,17 @@ config JME To compile this driver as a module, choose M here. The module will be called jme. +config S6GMAC + tristate "S6105 GMAC ethernet support" + depends on XTENSA_VARIANT_S6000 + select PHYLIB + help + This driver supports the on chip ethernet device on the + S6105 xtensa processor. + + To compile this driver as a module, choose M here. The module + will be called s6gmac. + endif # NETDEV_1000 # @@ -2435,10 +2473,14 @@ menuconfig NETDEV_10000 if NETDEV_10000 +config MDIO + tristate + config CHELSIO_T1 tristate "Chelsio 10Gb Ethernet support" depends on PCI select CRC32 + select MDIO help This driver supports Chelsio gigabit and 10-gigabit Ethernet cards. More information about adapter features and @@ -2471,6 +2513,7 @@ config CHELSIO_T3 tristate "Chelsio Communications T3 10Gb Ethernet support" depends on CHELSIO_T3_DEPENDS select FW_LOADER + select MDIO help This driver supports Chelsio T3-based gigabit and 10Gb Ethernet adapters. @@ -2506,6 +2549,7 @@ config ENIC config IXGBE tristate "Intel(R) 10GbE PCI Express adapters support" depends on PCI && INET + select MDIO ---help--- This driver supports Intel(R) 10GbE PCI Express family of adapters. For more information on how to identify your adapter, go @@ -2668,6 +2712,7 @@ config TEHUTI config BNX2X tristate "Broadcom NetXtremeII 10Gb support" depends on PCI + select FW_LOADER select ZLIB_INFLATE select LIBCRC32C help @@ -2704,6 +2749,8 @@ source "drivers/net/wan/Kconfig" source "drivers/atm/Kconfig" +source "drivers/ieee802154/Kconfig" + source "drivers/s390/net/Kconfig" config XEN_NETDEV_FRONTEND diff --git a/drivers/net/Makefile b/drivers/net/Makefile index a1c25cb4669f..4b58a59f211b 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -2,6 +2,8 @@ # Makefile for the Linux network (ethercard) device drivers. # +obj-$(CONFIG_TI_DAVINCI_EMAC) += davinci_emac.o + obj-$(CONFIG_E1000) += e1000/ obj-$(CONFIG_E1000E) += e1000e/ obj-$(CONFIG_IBM_NEW_EMAC) += ibm_newemac/ @@ -73,6 +75,7 @@ obj-$(CONFIG_STNIC) += stnic.o 8390.o obj-$(CONFIG_FEALNX) += fealnx.o obj-$(CONFIG_TIGON3) += tg3.o obj-$(CONFIG_BNX2) += bnx2.o +obj-$(CONFIG_CNIC) += cnic.o obj-$(CONFIG_BNX2X) += bnx2x.o bnx2x-objs := bnx2x_main.o bnx2x_link.o spidernet-y += spider_net.o spider_net_ethtool.o @@ -84,6 +87,7 @@ obj-$(CONFIG_TC35815) += tc35815.o obj-$(CONFIG_SKGE) += skge.o obj-$(CONFIG_SKY2) += sky2.o obj-$(CONFIG_SKFP) += skfp/ +obj-$(CONFIG_KS8842) += ks8842.o obj-$(CONFIG_VIA_RHINE) += via-rhine.o obj-$(CONFIG_VIA_VELOCITY) += via-velocity.o obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o @@ -95,6 +99,7 @@ obj-$(CONFIG_SH_ETH) += sh_eth.o # obj-$(CONFIG_MII) += mii.o +obj-$(CONFIG_MDIO) += mdio.o obj-$(CONFIG_PHYLIB) += phy/ obj-$(CONFIG_SUNDANCE) += sundance.o @@ -134,6 +139,8 @@ obj-$(CONFIG_AX88796) += ax88796.o obj-$(CONFIG_TSI108_ETH) += tsi108_eth.o obj-$(CONFIG_MV643XX_ETH) += mv643xx_eth.o +ll_temac-objs := ll_temac_main.o ll_temac_mdio.o +obj-$(CONFIG_XILINX_LL_TEMAC) += ll_temac.o obj-$(CONFIG_QLA3XXX) += qla3xxx.o obj-$(CONFIG_QLGE) += qlge/ @@ -238,6 +245,7 @@ obj-$(CONFIG_XTENSA_XT2000_SONIC) += xtsonic.o obj-$(CONFIG_DNET) += dnet.o obj-$(CONFIG_MACB) += macb.o +obj-$(CONFIG_S6GMAC) += s6gmac.o obj-$(CONFIG_ARM) += arm/ obj-$(CONFIG_DEV_APPLETALK) += appletalk/ diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c index 02f64d578641..85a18175730b 100644 --- a/drivers/net/a2065.c +++ b/drivers/net/a2065.c @@ -564,7 +564,7 @@ static int lance_start_xmit (struct sk_buff *skb, struct net_device *dev) if (!TX_BUFFS_AVAIL){ local_irq_restore(flags); - return -1; + return NETDEV_TX_LOCKED; } #ifdef DEBUG_DRIVER diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c index 57bc71527850..08419ee10290 100644 --- a/drivers/net/acenic.c +++ b/drivers/net/acenic.c @@ -2573,7 +2573,6 @@ restart: netif_wake_queue(dev); } - dev->trans_start = jiffies; return NETDEV_TX_OK; overflow: diff --git a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c index da64ba88d7f8..78cea5e80b1d 100644 --- a/drivers/net/appletalk/ipddp.c +++ b/drivers/net/appletalk/ipddp.c @@ -39,6 +39,7 @@ static const char version[] = KERN_INFO "ipddp.c:v0.01 8/28/97 Bradford W. Johnson \n"; static struct ipddp_route *ipddp_route_list; +static DEFINE_SPINLOCK(ipddp_route_lock); #ifdef CONFIG_IPDDP_ENCAP static int ipddp_mode = IPDDP_ENCAP; @@ -50,7 +51,7 @@ static int ipddp_mode = IPDDP_DECAP; static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev); static int ipddp_create(struct ipddp_route *new_rt); static int ipddp_delete(struct ipddp_route *rt); -static struct ipddp_route* ipddp_find_route(struct ipddp_route *rt); +static struct ipddp_route* __ipddp_find_route(struct ipddp_route *rt); static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); static const struct net_device_ops ipddp_netdev_ops = { @@ -71,6 +72,7 @@ static struct net_device * __init ipddp_init(void) if (!dev) return ERR_PTR(-ENOMEM); + dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; strcpy(dev->name, "ipddp%d"); if (version_printed++ == 0) @@ -113,11 +115,13 @@ static struct net_device * __init ipddp_init(void) */ static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev) { - __be32 paddr = ((struct rtable*)skb->dst)->rt_gateway; + __be32 paddr = skb_rtable(skb)->rt_gateway; struct ddpehdr *ddp; struct ipddp_route *rt; struct atalk_addr *our_addr; + spin_lock(&ipddp_route_lock); + /* * Find appropriate route to use, based only on IP number. */ @@ -126,8 +130,10 @@ static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev) if(rt->ip == paddr) break; } - if(rt == NULL) + if(rt == NULL) { + spin_unlock(&ipddp_route_lock); return 0; + } our_addr = atalk_find_dev_addr(rt->dev); @@ -173,6 +179,8 @@ static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev) if(aarp_send_ddp(rt->dev, skb, &rt->at, NULL) < 0) dev_kfree_skb(skb); + spin_unlock(&ipddp_route_lock); + return 0; } @@ -195,7 +203,9 @@ static int ipddp_create(struct ipddp_route *new_rt) return -ENETUNREACH; } - if (ipddp_find_route(rt)) { + spin_lock_bh(&ipddp_route_lock); + if (__ipddp_find_route(rt)) { + spin_unlock_bh(&ipddp_route_lock); kfree(rt); return -EEXIST; } @@ -203,6 +213,8 @@ static int ipddp_create(struct ipddp_route *new_rt) rt->next = ipddp_route_list; ipddp_route_list = rt; + spin_unlock_bh(&ipddp_route_lock); + return 0; } @@ -215,6 +227,7 @@ static int ipddp_delete(struct ipddp_route *rt) struct ipddp_route **r = &ipddp_route_list; struct ipddp_route *tmp; + spin_lock_bh(&ipddp_route_lock); while((tmp = *r) != NULL) { if(tmp->ip == rt->ip @@ -222,19 +235,21 @@ static int ipddp_delete(struct ipddp_route *rt) && tmp->at.s_node == rt->at.s_node) { *r = tmp->next; + spin_unlock_bh(&ipddp_route_lock); kfree(tmp); return 0; } r = &tmp->next; } + spin_unlock_bh(&ipddp_route_lock); return (-ENOENT); } /* * Find a routing entry, we only return a FULL match */ -static struct ipddp_route* ipddp_find_route(struct ipddp_route *rt) +static struct ipddp_route* __ipddp_find_route(struct ipddp_route *rt) { struct ipddp_route *f; @@ -252,7 +267,7 @@ static struct ipddp_route* ipddp_find_route(struct ipddp_route *rt) static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { struct ipddp_route __user *rt = ifr->ifr_data; - struct ipddp_route rcp; + struct ipddp_route rcp, rcp2, *rp; if(!capable(CAP_NET_ADMIN)) return -EPERM; @@ -266,9 +281,19 @@ static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) return (ipddp_create(&rcp)); case SIOCFINDIPDDPRT: - if(copy_to_user(rt, ipddp_find_route(&rcp), sizeof(struct ipddp_route))) - return -EFAULT; - return 0; + spin_lock_bh(&ipddp_route_lock); + rp = __ipddp_find_route(&rcp); + if (rp) + memcpy(&rcp2, rp, sizeof(rcp2)); + spin_unlock_bh(&ipddp_route_lock); + + if (rp) { + if (copy_to_user(rt, &rcp2, + sizeof(struct ipddp_route))) + return -EFAULT; + return 0; + } else + return -ENOENT; case SIOCDELIPDDPRT: return (ipddp_delete(&rcp)); diff --git a/drivers/net/appletalk/ltpc.c b/drivers/net/appletalk/ltpc.c index 78cc71469136..b642647170be 100644 --- a/drivers/net/appletalk/ltpc.c +++ b/drivers/net/appletalk/ltpc.c @@ -1220,7 +1220,7 @@ static int __init ltpc_setup(char *str) if (ints[0] > 2) { dma = ints[3]; } - /* ignore any other paramters */ + /* ignore any other parameters */ } return 1; } diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c index 7f4bc8ae5462..2e7419a61191 100644 --- a/drivers/net/arm/at91_ether.c +++ b/drivers/net/arm/at91_ether.c @@ -829,7 +829,7 @@ static int at91ether_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; } else { printk(KERN_ERR "at91_ether.c: at91ether_start_xmit() called, but device is busy!\n"); - return 1; /* if we return anything but zero, dev.c:1055 calls kfree_skb(skb) + return NETDEV_TX_BUSY; /* if we return anything but zero, dev.c:1055 calls kfree_skb(skb) on this skb, he also reports -ENETDOWN and printk's, so either we free and return(0) or don't free and return 1 */ } diff --git a/drivers/net/arm/ep93xx_eth.c b/drivers/net/arm/ep93xx_eth.c index b72b3d639f6e..fbf4645417d4 100644 --- a/drivers/net/arm/ep93xx_eth.c +++ b/drivers/net/arm/ep93xx_eth.c @@ -253,7 +253,7 @@ static int ep93xx_rx(struct net_device *dev, int processed, int budget) skb = dev_alloc_skb(length + 2); if (likely(skb != NULL)) { skb_reserve(skb, 2); - dma_sync_single(NULL, ep->descs->rdesc[entry].buf_addr, + dma_sync_single_for_cpu(NULL, ep->descs->rdesc[entry].buf_addr, length, DMA_FROM_DEVICE); skb_copy_to_linear_data(skb, ep->rx_buf[entry], length); skb_put(skb, length); @@ -331,7 +331,7 @@ static int ep93xx_xmit(struct sk_buff *skb, struct net_device *dev) ep->descs->tdesc[entry].tdesc1 = TDESC1_EOF | (entry << 16) | (skb->len & 0xfff); skb_copy_and_csum_dev(skb, ep->tx_buf[entry]); - dma_sync_single(NULL, ep->descs->tdesc[entry].buf_addr, + dma_sync_single_for_cpu(NULL, ep->descs->tdesc[entry].buf_addr, skb->len, DMA_TO_DEVICE); dev_kfree_skb(skb); diff --git a/drivers/net/arm/ether3.c b/drivers/net/arm/ether3.c index ec8a1ae1e887..455037134aa3 100644 --- a/drivers/net/arm/ether3.c +++ b/drivers/net/arm/ether3.c @@ -526,7 +526,7 @@ ether3_sendpacket(struct sk_buff *skb, struct net_device *dev) if (priv(dev)->tx_tail == next_ptr) { local_irq_restore(flags); - return 1; /* unable to queue */ + return NETDEV_TX_BUSY; /* unable to queue */ } dev->trans_start = jiffies; diff --git a/drivers/net/arm/ixp4xx_eth.c b/drivers/net/arm/ixp4xx_eth.c index a740053d3af3..6f42ad728915 100644 --- a/drivers/net/arm/ixp4xx_eth.c +++ b/drivers/net/arm/ixp4xx_eth.c @@ -456,7 +456,8 @@ static inline void queue_put_desc(unsigned int queue, u32 phys, debug_desc(phys, desc); BUG_ON(phys & 0x1F); qmgr_put_entry(queue, phys); - BUG_ON(qmgr_stat_overflow(queue)); + /* Don't check for queue overflow here, we've allocated sufficient + length and queues >= 32 don't support this check anyway. */ } @@ -512,8 +513,8 @@ static int eth_poll(struct napi_struct *napi, int budget) #endif napi_complete(napi); qmgr_enable_irq(rxq); - if (!qmgr_stat_empty(rxq) && - napi_reschedule(napi)) { + if (!qmgr_stat_below_low_watermark(rxq) && + napi_reschedule(napi)) { /* not empty again */ #if DEBUG_RX printk(KERN_DEBUG "%s: eth_poll" " napi_reschedule successed\n", @@ -561,8 +562,8 @@ static int eth_poll(struct napi_struct *napi, int budget) dma_unmap_single(&dev->dev, desc->data - NET_IP_ALIGN, RX_BUFF_SIZE, DMA_FROM_DEVICE); #else - dma_sync_single(&dev->dev, desc->data - NET_IP_ALIGN, - RX_BUFF_SIZE, DMA_FROM_DEVICE); + dma_sync_single_for_cpu(&dev->dev, desc->data - NET_IP_ALIGN, + RX_BUFF_SIZE, DMA_FROM_DEVICE); memcpy_swab32((u32 *)skb->data, (u32 *)port->rx_buff_tab[n], ALIGN(NET_IP_ALIGN + desc->pkt_len, 4) / 4); #endif @@ -630,9 +631,9 @@ static void eth_txdone_irq(void *unused) port->tx_buff_tab[n_desc] = NULL; } - start = qmgr_stat_empty(port->plat->txreadyq); + start = qmgr_stat_below_low_watermark(port->plat->txreadyq); queue_put_desc(port->plat->txreadyq, phys, desc); - if (start) { + if (start) { /* TX-ready queue was empty */ #if DEBUG_TX printk(KERN_DEBUG "%s: eth_txdone_irq xmit ready\n", port->netdev->name); @@ -708,13 +709,14 @@ static int eth_xmit(struct sk_buff *skb, struct net_device *dev) queue_put_desc(TX_QUEUE(port->id), tx_desc_phys(port, n), desc); dev->trans_start = jiffies; - if (qmgr_stat_empty(txreadyq)) { + if (qmgr_stat_below_low_watermark(txreadyq)) { /* empty */ #if DEBUG_TX printk(KERN_DEBUG "%s: eth_xmit queue full\n", dev->name); #endif netif_stop_queue(dev); /* we could miss TX ready interrupt */ - if (!qmgr_stat_empty(txreadyq)) { + /* really empty in fact */ + if (!qmgr_stat_below_low_watermark(txreadyq)) { #if DEBUG_TX printk(KERN_DEBUG "%s: eth_xmit ready again\n", dev->name); @@ -814,29 +816,29 @@ static int request_queues(struct port *port) int err; err = qmgr_request_queue(RXFREE_QUEUE(port->id), RX_DESCS, 0, 0, - "%s:RX-free", port->netdev->name); + "%s:RX-free", port->netdev->name); if (err) return err; err = qmgr_request_queue(port->plat->rxq, RX_DESCS, 0, 0, - "%s:RX", port->netdev->name); + "%s:RX", port->netdev->name); if (err) goto rel_rxfree; err = qmgr_request_queue(TX_QUEUE(port->id), TX_DESCS, 0, 0, - "%s:TX", port->netdev->name); + "%s:TX", port->netdev->name); if (err) goto rel_rx; err = qmgr_request_queue(port->plat->txreadyq, TX_DESCS, 0, 0, - "%s:TX-ready", port->netdev->name); + "%s:TX-ready", port->netdev->name); if (err) goto rel_tx; /* TX-done queue handles skbs sent out by the NPEs */ if (!ports_open) { err = qmgr_request_queue(TXDONE_QUEUE, TXDONE_QUEUE_LEN, 0, 0, - "%s:TX-done", DRV_NAME); + "%s:TX-done", DRV_NAME); if (err) goto rel_txready; } @@ -1149,7 +1151,7 @@ static int __devinit eth_init_one(struct platform_device *pdev) struct net_device *dev; struct eth_plat_info *plat = pdev->dev.platform_data; u32 regs_phys; - char phy_id[BUS_ID_SIZE]; + char phy_id[MII_BUS_ID_SIZE + 3]; int err; if (!(dev = alloc_etherdev(sizeof(struct port)))) @@ -1207,7 +1209,7 @@ static int __devinit eth_init_one(struct platform_device *pdev) __raw_writel(DEFAULT_CORE_CNTRL, &port->regs->core_control); udelay(50); - snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT, "0", plat->phy); + snprintf(phy_id, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, "0", plat->phy); port->phydev = phy_connect(dev, phy_id, &ixp4xx_adjust_link, 0, PHY_INTERFACE_MODE_MII); if ((err = IS_ERR(port->phydev))) diff --git a/drivers/net/atl1c/atl1c_ethtool.c b/drivers/net/atl1c/atl1c_ethtool.c index 45c5b7332cd3..e4afbd628c23 100644 --- a/drivers/net/atl1c/atl1c_ethtool.c +++ b/drivers/net/atl1c/atl1c_ethtool.c @@ -271,7 +271,7 @@ static int atl1c_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) struct atl1c_adapter *adapter = netdev_priv(netdev); if (wol->wolopts & (WAKE_ARP | WAKE_MAGICSECURE | - WAKE_MCAST | WAKE_BCAST | WAKE_MCAST)) + WAKE_UCAST | WAKE_BCAST | WAKE_MCAST)) return -EOPNOTSUPP; /* these settings will always override what we currently have */ adapter->wol = 0; diff --git a/drivers/net/atl1c/atl1c_main.c b/drivers/net/atl1c/atl1c_main.c index 83a12125b94e..cd547a205fb9 100644 --- a/drivers/net/atl1c/atl1c_main.c +++ b/drivers/net/atl1c/atl1c_main.c @@ -163,6 +163,24 @@ static inline void atl1c_irq_reset(struct atl1c_adapter *adapter) atl1c_irq_enable(adapter); } +/* + * atl1c_wait_until_idle - wait up to AT_HW_MAX_IDLE_DELAY reads + * of the idle status register until the device is actually idle + */ +static u32 atl1c_wait_until_idle(struct atl1c_hw *hw) +{ + int timeout; + u32 data; + + for (timeout = 0; timeout < AT_HW_MAX_IDLE_DELAY; timeout++) { + AT_READ_REG(hw, REG_IDLE_STATUS, &data); + if ((data & IDLE_STATUS_MASK) == 0) + return 0; + msleep(1); + } + return data; +} + /* * atl1c_phy_config - Timer Call-back * @data: pointer to netdev cast into an unsigned long @@ -220,11 +238,11 @@ static void atl1c_check_link_status(struct atl1c_adapter *adapter) /* link down */ if (netif_carrier_ok(netdev)) { hw->hibernate = true; - atl1c_set_aspm(hw, false); if (atl1c_stop_mac(hw) != 0) if (netif_msg_hw(adapter)) dev_warn(&pdev->dev, "stop mac failed\n"); + atl1c_set_aspm(hw, false); } netif_carrier_off(netdev); } else { @@ -240,10 +258,10 @@ static void atl1c_check_link_status(struct atl1c_adapter *adapter) adapter->link_duplex != duplex) { adapter->link_speed = speed; adapter->link_duplex = duplex; + atl1c_set_aspm(hw, true); atl1c_enable_tx_ctrl(hw); atl1c_enable_rx_ctrl(hw); atl1c_setup_mac_ctrl(adapter); - atl1c_set_aspm(hw, true); if (netif_msg_link(adapter)) dev_info(&pdev->dev, "%s: %s NIC Link is Up<%d Mbps %s>\n", @@ -1106,7 +1124,6 @@ static void atl1c_configure_dma(struct atl1c_adapter *adapter) static int atl1c_stop_mac(struct atl1c_hw *hw) { u32 data; - int timeout; AT_READ_REG(hw, REG_RXQ_CTRL, &data); data &= ~(RXQ1_CTRL_EN | RXQ2_CTRL_EN | @@ -1117,25 +1134,13 @@ static int atl1c_stop_mac(struct atl1c_hw *hw) data &= ~TXQ_CTRL_EN; AT_WRITE_REG(hw, REG_TWSI_CTRL, data); - for (timeout = 0; timeout < AT_HW_MAX_IDLE_DELAY; timeout++) { - AT_READ_REG(hw, REG_IDLE_STATUS, &data); - if ((data & (IDLE_STATUS_RXQ_NO_IDLE | - IDLE_STATUS_TXQ_NO_IDLE)) == 0) - break; - msleep(1); - } + atl1c_wait_until_idle(hw); AT_READ_REG(hw, REG_MAC_CTRL, &data); data &= ~(MAC_CTRL_TX_EN | MAC_CTRL_RX_EN); AT_WRITE_REG(hw, REG_MAC_CTRL, data); - for (timeout = 0; timeout < AT_HW_MAX_IDLE_DELAY; timeout++) { - AT_READ_REG(hw, REG_IDLE_STATUS, &data); - if ((data & IDLE_STATUS_MASK) == 0) - return 0; - msleep(1); - } - return data; + return (int)atl1c_wait_until_idle(hw); } static void atl1c_enable_rx_ctrl(struct atl1c_hw *hw) @@ -1178,8 +1183,6 @@ static int atl1c_reset_mac(struct atl1c_hw *hw) { struct atl1c_adapter *adapter = (struct atl1c_adapter *)hw->adapter; struct pci_dev *pdev = adapter->pdev; - u32 idle_status_data = 0; - int timeout = 0; int ret; AT_WRITE_REG(hw, REG_IMR, 0); @@ -1198,15 +1201,10 @@ static int atl1c_reset_mac(struct atl1c_hw *hw) AT_WRITE_FLUSH(hw); msleep(10); /* Wait at least 10ms for All module to be Idle */ - for (timeout = 0; timeout < AT_HW_MAX_IDLE_DELAY; timeout++) { - AT_READ_REG(hw, REG_IDLE_STATUS, &idle_status_data); - if ((idle_status_data & IDLE_STATUS_MASK) == 0) - break; - msleep(1); - } - if (timeout >= AT_HW_MAX_IDLE_DELAY) { + + if (atl1c_wait_until_idle(hw)) { dev_err(&pdev->dev, - "MAC state machine cann't be idle since" + "MAC state machine can't be idle since" " disabled for 10ms second\n"); return -1; } @@ -1242,9 +1240,7 @@ static void atl1c_set_aspm(struct atl1c_hw *hw, bool linkup) AT_READ_REG(hw, REG_PM_CTRL, &pm_ctrl_data); - pm_ctrl_data &= PM_CTRL_SERDES_PD_EX_L1; - pm_ctrl_data |= ~PM_CTRL_SERDES_BUDS_RX_L1_EN; - pm_ctrl_data |= ~PM_CTRL_SERDES_L1_EN; + pm_ctrl_data &= ~PM_CTRL_SERDES_PD_EX_L1; pm_ctrl_data &= ~(PM_CTRL_L1_ENTRY_TIMER_MASK << PM_CTRL_L1_ENTRY_TIMER_SHIFT); @@ -1254,19 +1250,11 @@ static void atl1c_set_aspm(struct atl1c_hw *hw, bool linkup) pm_ctrl_data |= PM_CTRL_SERDES_PLL_L1_EN; pm_ctrl_data &= ~PM_CTRL_CLK_SWH_L1; - if (hw->ctrl_flags & ATL1C_ASPM_L1_SUPPORT) { - pm_ctrl_data |= AT_ASPM_L1_TIMER << - PM_CTRL_L1_ENTRY_TIMER_SHIFT; - pm_ctrl_data |= PM_CTRL_ASPM_L1_EN; - } else - pm_ctrl_data &= ~PM_CTRL_ASPM_L1_EN; - - if (hw->ctrl_flags & ATL1C_ASPM_L0S_SUPPORT) - pm_ctrl_data |= PM_CTRL_ASPM_L0S_EN; - else - pm_ctrl_data &= ~PM_CTRL_ASPM_L0S_EN; - + pm_ctrl_data |= PM_CTRL_SERDES_BUDS_RX_L1_EN; + pm_ctrl_data |= PM_CTRL_SERDES_L1_EN; } else { + pm_ctrl_data &= ~PM_CTRL_SERDES_BUDS_RX_L1_EN; + pm_ctrl_data &= ~PM_CTRL_SERDES_L1_EN; pm_ctrl_data &= ~PM_CTRL_ASPM_L0S_EN; pm_ctrl_data &= ~PM_CTRL_SERDES_PLL_L1_EN; @@ -2123,7 +2111,6 @@ static int atl1c_xmit_frame(struct sk_buff *skb, struct net_device *netdev) atl1c_tx_map(adapter, skb, tpd, type); atl1c_tx_queue(adapter, skb, tpd, type); - netdev->trans_start = jiffies; spin_unlock_irqrestore(&adapter->tx_lock, flags); return NETDEV_TX_OK; } diff --git a/drivers/net/atl1e/atl1e.h b/drivers/net/atl1e/atl1e.h index 2bf63b4368e2..ba48220df16a 100644 --- a/drivers/net/atl1e/atl1e.h +++ b/drivers/net/atl1e/atl1e.h @@ -429,7 +429,6 @@ struct atl1e_adapter { struct mii_if_info mii; /* MII interface info */ struct atl1e_hw hw; struct atl1e_hw_stats hw_stats; - struct net_device_stats net_stats; bool have_msi; u32 wol; diff --git a/drivers/net/atl1e/atl1e_main.c b/drivers/net/atl1e/atl1e_main.c index 1342418fb209..9fc6d6d9060e 100644 --- a/drivers/net/atl1e/atl1e_main.c +++ b/drivers/net/atl1e/atl1e_main.c @@ -1154,7 +1154,7 @@ static struct net_device_stats *atl1e_get_stats(struct net_device *netdev) { struct atl1e_adapter *adapter = netdev_priv(netdev); struct atl1e_hw_stats *hw_stats = &adapter->hw_stats; - struct net_device_stats *net_stats = &adapter->net_stats; + struct net_device_stats *net_stats = &netdev->stats; net_stats->rx_packets = hw_stats->rx_ok; net_stats->tx_packets = hw_stats->tx_ok; @@ -1182,7 +1182,7 @@ static struct net_device_stats *atl1e_get_stats(struct net_device *netdev) net_stats->tx_aborted_errors = hw_stats->tx_abort_col; net_stats->tx_window_errors = hw_stats->tx_late_col; - return &adapter->net_stats; + return net_stats; } static void atl1e_update_hw_stats(struct atl1e_adapter *adapter) @@ -1310,7 +1310,7 @@ static irqreturn_t atl1e_intr(int irq, void *data) /* link event */ if (status & (ISR_GPHY | ISR_MANUAL)) { - adapter->net_stats.tx_carrier_errors++; + netdev->stats.tx_carrier_errors++; atl1e_link_chg_event(adapter); break; } @@ -1602,7 +1602,7 @@ static u16 atl1e_cal_tdp_req(const struct sk_buff *skb) } if (skb_is_gso(skb)) { - if (skb->protocol == ntohs(ETH_P_IP) || + if (skb->protocol == htons(ETH_P_IP) || (skb_shinfo(skb)->gso_type == SKB_GSO_TCPV6)) { proto_hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); @@ -1795,8 +1795,7 @@ static void atl1e_tx_map(struct atl1e_adapter *adapter, memcpy(use_tpd, tpd, sizeof(struct atl1e_tpd_desc)); tx_buffer = atl1e_get_tx_buffer(adapter, use_tpd); - if (tx_buffer->skb) - BUG(); + BUG_ON(tx_buffer->skb); tx_buffer->skb = NULL; tx_buffer->length = @@ -1879,7 +1878,7 @@ static int atl1e_xmit_frame(struct sk_buff *skb, struct net_device *netdev) TPD_VLAN_SHIFT; } - if (skb->protocol == ntohs(ETH_P_8021Q)) + if (skb->protocol == htons(ETH_P_8021Q)) tpd->word3 |= 1 << TPD_VL_TAGGED_SHIFT; if (skb_network_offset(skb) != ETH_HLEN) @@ -1895,7 +1894,7 @@ static int atl1e_xmit_frame(struct sk_buff *skb, struct net_device *netdev) atl1e_tx_map(adapter, skb, tpd); atl1e_tx_queue(adapter, tpd_req, tpd); - netdev->trans_start = jiffies; + netdev->trans_start = jiffies; /* NETIF_F_LLTX driver :( */ spin_unlock_irqrestore(&adapter->tx_lock, flags); return NETDEV_TX_OK; } diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c index 4e817126e280..94d7325caf4f 100644 --- a/drivers/net/atlx/atl1.c +++ b/drivers/net/atlx/atl1.c @@ -2213,8 +2213,7 @@ static void atl1_tx_map(struct atl1_adapter *adapter, struct sk_buff *skb, nr_frags = skb_shinfo(skb)->nr_frags; next_to_use = atomic_read(&tpd_ring->next_to_use); buffer_info = &tpd_ring->buffer_info[next_to_use]; - if (unlikely(buffer_info->skb)) - BUG(); + BUG_ON(buffer_info->skb); /* put skb in last TPD */ buffer_info->skb = NULL; @@ -2280,8 +2279,8 @@ static void atl1_tx_map(struct atl1_adapter *adapter, struct sk_buff *skb, ATL1_MAX_TX_BUF_LEN; for (i = 0; i < nseg; i++) { buffer_info = &tpd_ring->buffer_info[next_to_use]; - if (unlikely(buffer_info->skb)) - BUG(); + BUG_ON(buffer_info->skb); + buffer_info->skb = NULL; buffer_info->length = (buf_len > ATL1_MAX_TX_BUF_LEN) ? ATL1_MAX_TX_BUF_LEN : buf_len; @@ -2383,7 +2382,7 @@ static int atl1_xmit_frame(struct sk_buff *skb, struct net_device *netdev) mss = skb_shinfo(skb)->gso_size; if (mss) { - if (skb->protocol == ntohs(ETH_P_IP)) { + if (skb->protocol == htons(ETH_P_IP)) { proto_hdr_len = (skb_transport_offset(skb) + tcp_hdrlen(skb)); if (unlikely(proto_hdr_len > len)) { @@ -2438,7 +2437,6 @@ static int atl1_xmit_frame(struct sk_buff *skb, struct net_device *netdev) atl1_tx_queue(adapter, count, ptpd); atl1_update_mailbox(adapter); mmiowb(); - netdev->trans_start = jiffies; return NETDEV_TX_OK; } diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c index d58c105fc779..d3c734f4d679 100644 --- a/drivers/net/au1000_eth.c +++ b/drivers/net/au1000_eth.c @@ -957,7 +957,7 @@ static int au1000_tx(struct sk_buff *skb, struct net_device *dev) /* We've wrapped around and the transmitter is still busy */ netif_stop_queue(dev); aup->tx_full = 1; - return 1; + return NETDEV_TX_BUSY; } else if (buff_stat & TX_T_DONE) { update_tx_stats(dev, ptxd->status); diff --git a/drivers/net/b44.c b/drivers/net/b44.c index b70b81ec34c3..36d4d377ec2f 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -782,7 +782,7 @@ static int b44_rx(struct b44 *bp, int budget) drop_it: b44_recycle_rx(bp, cons, bp->rx_prod); drop_it_no_recycle: - bp->stats.rx_dropped++; + bp->dev->stats.rx_dropped++; goto next_pkt; } @@ -1647,7 +1647,7 @@ static int b44_close(struct net_device *dev) static struct net_device_stats *b44_get_stats(struct net_device *dev) { struct b44 *bp = netdev_priv(dev); - struct net_device_stats *nstat = &bp->stats; + struct net_device_stats *nstat = &dev->stats; struct b44_hw_stats *hwstat = &bp->hw_stats; /* Convert HW stats into netdevice stats. */ diff --git a/drivers/net/b44.h b/drivers/net/b44.h index e678498de6db..e1905a49279f 100644 --- a/drivers/net/b44.h +++ b/drivers/net/b44.h @@ -97,7 +97,7 @@ #define B44_DMARX_STAT 0x021CUL /* DMA RX Current Active Desc. + Status */ #define DMARX_STAT_CDMASK 0x00000fff /* Current Descriptor Mask */ #define DMARX_STAT_SMASK 0x0000f000 /* State Mask */ -#define DMARX_STAT_SDISABLED 0x00000000 /* State Disbaled */ +#define DMARX_STAT_SDISABLED 0x00000000 /* State Disabled */ #define DMARX_STAT_SACTIVE 0x00001000 /* State Active */ #define DMARX_STAT_SIDLE 0x00002000 /* State Idle Wait */ #define DMARX_STAT_SSTOPPED 0x00003000 /* State Stopped */ @@ -384,7 +384,6 @@ struct b44 { struct timer_list timer; - struct net_device_stats stats; struct b44_hw_stats hw_stats; struct ssb_device *sdev; diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h index b4bb06fdf307..f703758f0a6e 100644 --- a/drivers/net/benet/be.h +++ b/drivers/net/benet/be.h @@ -65,7 +65,7 @@ static inline char *nic_name(struct pci_dev *pdev) #define TX_CQ_LEN 1024 #define RX_Q_LEN 1024 /* Does not support any other value */ #define RX_CQ_LEN 1024 -#define MCC_Q_LEN 64 /* total size not to exceed 8 pages */ +#define MCC_Q_LEN 128 /* total size not to exceed 8 pages */ #define MCC_CQ_LEN 256 #define BE_NAPI_WEIGHT 64 @@ -91,6 +91,61 @@ struct be_queue_info { atomic_t used; /* Number of valid elements in the queue */ }; +static inline u32 MODULO(u16 val, u16 limit) +{ + BUG_ON(limit & (limit - 1)); + return val & (limit - 1); +} + +static inline void index_adv(u16 *index, u16 val, u16 limit) +{ + *index = MODULO((*index + val), limit); +} + +static inline void index_inc(u16 *index, u16 limit) +{ + *index = MODULO((*index + 1), limit); +} + +static inline void *queue_head_node(struct be_queue_info *q) +{ + return q->dma_mem.va + q->head * q->entry_size; +} + +static inline void *queue_tail_node(struct be_queue_info *q) +{ + return q->dma_mem.va + q->tail * q->entry_size; +} + +static inline void queue_head_inc(struct be_queue_info *q) +{ + index_inc(&q->head, q->len); +} + +static inline void queue_tail_inc(struct be_queue_info *q) +{ + index_inc(&q->tail, q->len); +} + + +struct be_eq_obj { + struct be_queue_info q; + char desc[32]; + + /* Adaptive interrupt coalescing (AIC) info */ + bool enable_aic; + u16 min_eqd; /* in usecs */ + u16 max_eqd; /* in usecs */ + u16 cur_eqd; /* in usecs */ + + struct napi_struct napi; +}; + +struct be_mcc_obj { + struct be_queue_info q; + struct be_queue_info cq; +}; + struct be_ctrl_info { u8 __iomem *csr; u8 __iomem *db; /* Door Bell */ @@ -98,11 +153,20 @@ struct be_ctrl_info { int pci_func; /* Mbox used for cmd request/response */ - spinlock_t cmd_lock; /* For serializing cmds to BE card */ + spinlock_t mbox_lock; /* For serializing mbox cmds to BE card */ struct be_dma_mem mbox_mem; /* Mbox mem is adjusted to align to 16 bytes. The allocated addr * is stored for freeing purpose */ struct be_dma_mem mbox_mem_alloced; + + /* MCC Rings */ + struct be_mcc_obj mcc_obj; + spinlock_t mcc_lock; /* For serializing mcc cmds to BE card */ + spinlock_t mcc_cq_lock; + + /* MCC Async callback */ + void (*async_cb)(void *adapter, bool link_up); + void *adapter_ctxt; }; #include "be_cmds.h" @@ -150,19 +214,6 @@ struct be_stats_obj { struct be_dma_mem cmd; }; -struct be_eq_obj { - struct be_queue_info q; - char desc[32]; - - /* Adaptive interrupt coalescing (AIC) info */ - bool enable_aic; - u16 min_eqd; /* in usecs */ - u16 max_eqd; /* in usecs */ - u16 cur_eqd; /* in usecs */ - - struct napi_struct napi; -}; - struct be_tx_obj { struct be_queue_info q; struct be_queue_info cq; @@ -225,8 +276,9 @@ struct be_adapter { u32 if_handle; /* Used to configure filtering */ u32 pmac_id; /* MAC addr handle used by BE card */ - struct be_link_info link; + bool link_up; u32 port_num; + bool promiscuous; }; extern struct ethtool_ops be_ethtool_ops; @@ -235,22 +287,6 @@ extern struct ethtool_ops be_ethtool_ops; #define BE_SET_NETDEV_OPS(netdev, ops) (netdev->netdev_ops = ops) -static inline u32 MODULO(u16 val, u16 limit) -{ - BUG_ON(limit & (limit - 1)); - return val & (limit - 1); -} - -static inline void index_adv(u16 *index, u16 val, u16 limit) -{ - *index = MODULO((*index + val), limit); -} - -static inline void index_inc(u16 *index, u16 limit) -{ - *index = MODULO((*index + 1), limit); -} - #define PAGE_SHIFT_4K 12 #define PAGE_SIZE_4K (1 << PAGE_SHIFT_4K) @@ -339,4 +375,6 @@ static inline u8 is_udp_pkt(struct sk_buff *skb) return val; } +extern void be_cq_notify(struct be_ctrl_info *ctrl, u16 qid, bool arm, + u16 num_popped); #endif /* BE_H */ diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index d444aed962bc..583517ed56f0 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c @@ -17,6 +17,133 @@ #include "be.h" +static void be_mcc_notify(struct be_ctrl_info *ctrl) +{ + struct be_queue_info *mccq = &ctrl->mcc_obj.q; + u32 val = 0; + + val |= mccq->id & DB_MCCQ_RING_ID_MASK; + val |= 1 << DB_MCCQ_NUM_POSTED_SHIFT; + iowrite32(val, ctrl->db + DB_MCCQ_OFFSET); +} + +/* To check if valid bit is set, check the entire word as we don't know + * the endianness of the data (old entry is host endian while a new entry is + * little endian) */ +static inline bool be_mcc_compl_is_new(struct be_mcc_cq_entry *compl) +{ + if (compl->flags != 0) { + compl->flags = le32_to_cpu(compl->flags); + BUG_ON((compl->flags & CQE_FLAGS_VALID_MASK) == 0); + return true; + } else { + return false; + } +} + +/* Need to reset the entire word that houses the valid bit */ +static inline void be_mcc_compl_use(struct be_mcc_cq_entry *compl) +{ + compl->flags = 0; +} + +static int be_mcc_compl_process(struct be_ctrl_info *ctrl, + struct be_mcc_cq_entry *compl) +{ + u16 compl_status, extd_status; + + /* Just swap the status to host endian; mcc tag is opaquely copied + * from mcc_wrb */ + be_dws_le_to_cpu(compl, 4); + + compl_status = (compl->status >> CQE_STATUS_COMPL_SHIFT) & + CQE_STATUS_COMPL_MASK; + if (compl_status != MCC_STATUS_SUCCESS) { + extd_status = (compl->status >> CQE_STATUS_EXTD_SHIFT) & + CQE_STATUS_EXTD_MASK; + printk(KERN_WARNING DRV_NAME + " error in cmd completion: status(compl/extd)=%d/%d\n", + compl_status, extd_status); + return -1; + } + return 0; +} + +/* Link state evt is a string of bytes; no need for endian swapping */ +static void be_async_link_state_process(struct be_ctrl_info *ctrl, + struct be_async_event_link_state *evt) +{ + ctrl->async_cb(ctrl->adapter_ctxt, + evt->port_link_status == ASYNC_EVENT_LINK_UP ? true : false); +} + +static inline bool is_link_state_evt(u32 trailer) +{ + return (((trailer >> ASYNC_TRAILER_EVENT_CODE_SHIFT) & + ASYNC_TRAILER_EVENT_CODE_MASK) == + ASYNC_EVENT_CODE_LINK_STATE); +} + +static struct be_mcc_cq_entry *be_mcc_compl_get(struct be_ctrl_info *ctrl) +{ + struct be_queue_info *mcc_cq = &ctrl->mcc_obj.cq; + struct be_mcc_cq_entry *compl = queue_tail_node(mcc_cq); + + if (be_mcc_compl_is_new(compl)) { + queue_tail_inc(mcc_cq); + return compl; + } + return NULL; +} + +void be_process_mcc(struct be_ctrl_info *ctrl) +{ + struct be_mcc_cq_entry *compl; + int num = 0; + + spin_lock_bh(&ctrl->mcc_cq_lock); + while ((compl = be_mcc_compl_get(ctrl))) { + if (compl->flags & CQE_FLAGS_ASYNC_MASK) { + /* Interpret flags as an async trailer */ + BUG_ON(!is_link_state_evt(compl->flags)); + + /* Interpret compl as a async link evt */ + be_async_link_state_process(ctrl, + (struct be_async_event_link_state *) compl); + } else { + be_mcc_compl_process(ctrl, compl); + atomic_dec(&ctrl->mcc_obj.q.used); + } + be_mcc_compl_use(compl); + num++; + } + if (num) + be_cq_notify(ctrl, ctrl->mcc_obj.cq.id, true, num); + spin_unlock_bh(&ctrl->mcc_cq_lock); +} + +/* Wait till no more pending mcc requests are present */ +static void be_mcc_wait_compl(struct be_ctrl_info *ctrl) +{ +#define mcc_timeout 50000 /* 5s timeout */ + int i; + for (i = 0; i < mcc_timeout; i++) { + be_process_mcc(ctrl); + if (atomic_read(&ctrl->mcc_obj.q.used) == 0) + break; + udelay(100); + } + if (i == mcc_timeout) + printk(KERN_WARNING DRV_NAME "mcc poll timed out\n"); +} + +/* Notify MCC requests and wait for completion */ +static void be_mcc_notify_wait(struct be_ctrl_info *ctrl) +{ + be_mcc_notify(ctrl); + be_mcc_wait_compl(ctrl); +} + static int be_mbox_db_ready_wait(void __iomem *db) { int cnt = 0, wait = 5; @@ -44,11 +171,11 @@ static int be_mbox_db_ready_wait(void __iomem *db) /* * Insert the mailbox address into the doorbell in two steps + * Polls on the mbox doorbell till a command completion (or a timeout) occurs */ static int be_mbox_db_ring(struct be_ctrl_info *ctrl) { int status; - u16 compl_status, extd_status; u32 val = 0; void __iomem *db = ctrl->db + MPU_MAILBOX_DB_OFFSET; struct be_dma_mem *mbox_mem = &ctrl->mbox_mem; @@ -79,24 +206,17 @@ static int be_mbox_db_ring(struct be_ctrl_info *ctrl) if (status != 0) return status; - /* compl entry has been made now */ - be_dws_le_to_cpu(cqe, sizeof(*cqe)); - if (!(cqe->flags & CQE_FLAGS_VALID_MASK)) { - printk(KERN_WARNING DRV_NAME ": ERROR invalid mbox compl\n"); + /* A cq entry has been made now */ + if (be_mcc_compl_is_new(cqe)) { + status = be_mcc_compl_process(ctrl, &mbox->cqe); + be_mcc_compl_use(cqe); + if (status) + return status; + } else { + printk(KERN_WARNING DRV_NAME "invalid mailbox completion\n"); return -1; } - - compl_status = (cqe->status >> CQE_STATUS_COMPL_SHIFT) & - CQE_STATUS_COMPL_MASK; - if (compl_status != MCC_STATUS_SUCCESS) { - extd_status = (cqe->status >> CQE_STATUS_EXTD_SHIFT) & - CQE_STATUS_EXTD_MASK; - printk(KERN_WARNING DRV_NAME - ": ERROR in cmd compl. status(compl/extd)=%d/%d\n", - compl_status, extd_status); - } - - return compl_status; + return 0; } static int be_POST_stage_get(struct be_ctrl_info *ctrl, u16 *stage) @@ -235,6 +355,18 @@ static inline struct be_mcc_wrb *wrb_from_mbox(struct be_dma_mem *mbox_mem) return &((struct be_mcc_mailbox *)(mbox_mem->va))->wrb; } +static inline struct be_mcc_wrb *wrb_from_mcc(struct be_queue_info *mccq) +{ + struct be_mcc_wrb *wrb = NULL; + if (atomic_read(&mccq->used) < mccq->len) { + wrb = queue_head_node(mccq); + queue_head_inc(mccq); + atomic_inc(&mccq->used); + memset(wrb, 0, sizeof(*wrb)); + } + return wrb; +} + int be_cmd_eq_create(struct be_ctrl_info *ctrl, struct be_queue_info *eq, int eq_delay) { @@ -244,7 +376,7 @@ int be_cmd_eq_create(struct be_ctrl_info *ctrl, struct be_dma_mem *q_mem = &eq->dma_mem; int status; - spin_lock(&ctrl->cmd_lock); + spin_lock(&ctrl->mbox_lock); memset(wrb, 0, sizeof(*wrb)); be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); @@ -272,7 +404,7 @@ int be_cmd_eq_create(struct be_ctrl_info *ctrl, eq->id = le16_to_cpu(resp->eq_id); eq->created = true; } - spin_unlock(&ctrl->cmd_lock); + spin_unlock(&ctrl->mbox_lock); return status; } @@ -284,7 +416,7 @@ int be_cmd_mac_addr_query(struct be_ctrl_info *ctrl, u8 *mac_addr, struct be_cmd_resp_mac_query *resp = embedded_payload(wrb); int status; - spin_lock(&ctrl->cmd_lock); + spin_lock(&ctrl->mbox_lock); memset(wrb, 0, sizeof(*wrb)); be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); @@ -304,7 +436,7 @@ int be_cmd_mac_addr_query(struct be_ctrl_info *ctrl, u8 *mac_addr, if (!status) memcpy(mac_addr, resp->mac.addr, ETH_ALEN); - spin_unlock(&ctrl->cmd_lock); + spin_unlock(&ctrl->mbox_lock); return status; } @@ -315,7 +447,7 @@ int be_cmd_pmac_add(struct be_ctrl_info *ctrl, u8 *mac_addr, struct be_cmd_req_pmac_add *req = embedded_payload(wrb); int status; - spin_lock(&ctrl->cmd_lock); + spin_lock(&ctrl->mbox_lock); memset(wrb, 0, sizeof(*wrb)); be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); @@ -332,7 +464,7 @@ int be_cmd_pmac_add(struct be_ctrl_info *ctrl, u8 *mac_addr, *pmac_id = le32_to_cpu(resp->pmac_id); } - spin_unlock(&ctrl->cmd_lock); + spin_unlock(&ctrl->mbox_lock); return status; } @@ -342,7 +474,7 @@ int be_cmd_pmac_del(struct be_ctrl_info *ctrl, u32 if_id, u32 pmac_id) struct be_cmd_req_pmac_del *req = embedded_payload(wrb); int status; - spin_lock(&ctrl->cmd_lock); + spin_lock(&ctrl->mbox_lock); memset(wrb, 0, sizeof(*wrb)); be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); @@ -354,7 +486,7 @@ int be_cmd_pmac_del(struct be_ctrl_info *ctrl, u32 if_id, u32 pmac_id) req->pmac_id = cpu_to_le32(pmac_id); status = be_mbox_db_ring(ctrl); - spin_unlock(&ctrl->cmd_lock); + spin_unlock(&ctrl->mbox_lock); return status; } @@ -370,7 +502,7 @@ int be_cmd_cq_create(struct be_ctrl_info *ctrl, void *ctxt = &req->context; int status; - spin_lock(&ctrl->cmd_lock); + spin_lock(&ctrl->mbox_lock); memset(wrb, 0, sizeof(*wrb)); be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); @@ -388,7 +520,7 @@ int be_cmd_cq_create(struct be_ctrl_info *ctrl, AMAP_SET_BITS(struct amap_cq_context, solevent, ctxt, sol_evts); AMAP_SET_BITS(struct amap_cq_context, eventable, ctxt, 1); AMAP_SET_BITS(struct amap_cq_context, eqid, ctxt, eq->id); - AMAP_SET_BITS(struct amap_cq_context, armed, ctxt, 0); + AMAP_SET_BITS(struct amap_cq_context, armed, ctxt, 1); AMAP_SET_BITS(struct amap_cq_context, func, ctxt, ctrl->pci_func); be_dws_cpu_to_le(ctxt, sizeof(req->context)); @@ -399,7 +531,56 @@ int be_cmd_cq_create(struct be_ctrl_info *ctrl, cq->id = le16_to_cpu(resp->cq_id); cq->created = true; } - spin_unlock(&ctrl->cmd_lock); + spin_unlock(&ctrl->mbox_lock); + + return status; +} + +static u32 be_encoded_q_len(int q_len) +{ + u32 len_encoded = fls(q_len); /* log2(len) + 1 */ + if (len_encoded == 16) + len_encoded = 0; + return len_encoded; +} + +int be_cmd_mccq_create(struct be_ctrl_info *ctrl, + struct be_queue_info *mccq, + struct be_queue_info *cq) +{ + struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); + struct be_cmd_req_mcc_create *req = embedded_payload(wrb); + struct be_dma_mem *q_mem = &mccq->dma_mem; + void *ctxt = &req->context; + int status; + + spin_lock(&ctrl->mbox_lock); + memset(wrb, 0, sizeof(*wrb)); + + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_MCC_CREATE, sizeof(*req)); + + req->num_pages = PAGES_4K_SPANNED(q_mem->va, q_mem->size); + + AMAP_SET_BITS(struct amap_mcc_context, fid, ctxt, ctrl->pci_func); + AMAP_SET_BITS(struct amap_mcc_context, valid, ctxt, 1); + AMAP_SET_BITS(struct amap_mcc_context, ring_size, ctxt, + be_encoded_q_len(mccq->len)); + AMAP_SET_BITS(struct amap_mcc_context, cq_id, ctxt, cq->id); + + be_dws_cpu_to_le(ctxt, sizeof(req->context)); + + be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); + + status = be_mbox_db_ring(ctrl); + if (!status) { + struct be_cmd_resp_mcc_create *resp = embedded_payload(wrb); + mccq->id = le16_to_cpu(resp->id); + mccq->created = true; + } + spin_unlock(&ctrl->mbox_lock); return status; } @@ -415,7 +596,7 @@ int be_cmd_txq_create(struct be_ctrl_info *ctrl, int status; u32 len_encoded; - spin_lock(&ctrl->cmd_lock); + spin_lock(&ctrl->mbox_lock); memset(wrb, 0, sizeof(*wrb)); be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); @@ -446,7 +627,7 @@ int be_cmd_txq_create(struct be_ctrl_info *ctrl, txq->id = le16_to_cpu(resp->cid); txq->created = true; } - spin_unlock(&ctrl->cmd_lock); + spin_unlock(&ctrl->mbox_lock); return status; } @@ -460,7 +641,7 @@ int be_cmd_rxq_create(struct be_ctrl_info *ctrl, struct be_dma_mem *q_mem = &rxq->dma_mem; int status; - spin_lock(&ctrl->cmd_lock); + spin_lock(&ctrl->mbox_lock); memset(wrb, 0, sizeof(*wrb)); be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); @@ -482,7 +663,7 @@ int be_cmd_rxq_create(struct be_ctrl_info *ctrl, rxq->id = le16_to_cpu(resp->id); rxq->created = true; } - spin_unlock(&ctrl->cmd_lock); + spin_unlock(&ctrl->mbox_lock); return status; } @@ -496,7 +677,7 @@ int be_cmd_q_destroy(struct be_ctrl_info *ctrl, struct be_queue_info *q, u8 subsys = 0, opcode = 0; int status; - spin_lock(&ctrl->cmd_lock); + spin_lock(&ctrl->mbox_lock); memset(wrb, 0, sizeof(*wrb)); be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); @@ -518,6 +699,10 @@ int be_cmd_q_destroy(struct be_ctrl_info *ctrl, struct be_queue_info *q, subsys = CMD_SUBSYSTEM_ETH; opcode = OPCODE_ETH_RX_DESTROY; break; + case QTYPE_MCCQ: + subsys = CMD_SUBSYSTEM_COMMON; + opcode = OPCODE_COMMON_MCC_DESTROY; + break; default: printk(KERN_WARNING DRV_NAME ":bad Q type in Q destroy cmd\n"); status = -1; @@ -528,7 +713,7 @@ int be_cmd_q_destroy(struct be_ctrl_info *ctrl, struct be_queue_info *q, status = be_mbox_db_ring(ctrl); err: - spin_unlock(&ctrl->cmd_lock); + spin_unlock(&ctrl->mbox_lock); return status; } @@ -541,7 +726,7 @@ int be_cmd_if_create(struct be_ctrl_info *ctrl, u32 flags, u8 *mac, struct be_cmd_req_if_create *req = embedded_payload(wrb); int status; - spin_lock(&ctrl->cmd_lock); + spin_lock(&ctrl->mbox_lock); memset(wrb, 0, sizeof(*wrb)); be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); @@ -562,7 +747,7 @@ int be_cmd_if_create(struct be_ctrl_info *ctrl, u32 flags, u8 *mac, *pmac_id = le32_to_cpu(resp->pmac_id); } - spin_unlock(&ctrl->cmd_lock); + spin_unlock(&ctrl->mbox_lock); return status; } @@ -572,7 +757,7 @@ int be_cmd_if_destroy(struct be_ctrl_info *ctrl, u32 interface_id) struct be_cmd_req_if_destroy *req = embedded_payload(wrb); int status; - spin_lock(&ctrl->cmd_lock); + spin_lock(&ctrl->mbox_lock); memset(wrb, 0, sizeof(*wrb)); be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); @@ -583,7 +768,7 @@ int be_cmd_if_destroy(struct be_ctrl_info *ctrl, u32 interface_id) req->interface_id = cpu_to_le32(interface_id); status = be_mbox_db_ring(ctrl); - spin_unlock(&ctrl->cmd_lock); + spin_unlock(&ctrl->mbox_lock); return status; } @@ -598,7 +783,7 @@ int be_cmd_get_stats(struct be_ctrl_info *ctrl, struct be_dma_mem *nonemb_cmd) struct be_sge *sge = nonembedded_sgl(wrb); int status; - spin_lock(&ctrl->cmd_lock); + spin_lock(&ctrl->mbox_lock); memset(wrb, 0, sizeof(*wrb)); memset(req, 0, sizeof(*req)); @@ -617,18 +802,20 @@ int be_cmd_get_stats(struct be_ctrl_info *ctrl, struct be_dma_mem *nonemb_cmd) be_dws_le_to_cpu(&resp->hw_stats, sizeof(resp->hw_stats)); } - spin_unlock(&ctrl->cmd_lock); + spin_unlock(&ctrl->mbox_lock); return status; } int be_cmd_link_status_query(struct be_ctrl_info *ctrl, - struct be_link_info *link) + bool *link_up) { struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); struct be_cmd_req_link_status *req = embedded_payload(wrb); int status; - spin_lock(&ctrl->cmd_lock); + spin_lock(&ctrl->mbox_lock); + + *link_up = false; memset(wrb, 0, sizeof(*wrb)); be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); @@ -639,14 +826,11 @@ int be_cmd_link_status_query(struct be_ctrl_info *ctrl, status = be_mbox_db_ring(ctrl); if (!status) { struct be_cmd_resp_link_status *resp = embedded_payload(wrb); - link->speed = resp->mac_speed; - link->duplex = resp->mac_duplex; - link->fault = resp->mac_fault; - } else { - link->speed = PHY_LINK_SPEED_ZERO; + if (resp->mac_speed != PHY_LINK_SPEED_ZERO) + *link_up = true; } - spin_unlock(&ctrl->cmd_lock); + spin_unlock(&ctrl->mbox_lock); return status; } @@ -656,7 +840,7 @@ int be_cmd_get_fw_ver(struct be_ctrl_info *ctrl, char *fw_ver) struct be_cmd_req_get_fw_version *req = embedded_payload(wrb); int status; - spin_lock(&ctrl->cmd_lock); + spin_lock(&ctrl->mbox_lock); memset(wrb, 0, sizeof(*wrb)); be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); @@ -670,7 +854,7 @@ int be_cmd_get_fw_ver(struct be_ctrl_info *ctrl, char *fw_ver) strncpy(fw_ver, resp->firmware_version_string, FW_VER_LEN); } - spin_unlock(&ctrl->cmd_lock); + spin_unlock(&ctrl->mbox_lock); return status; } @@ -681,7 +865,7 @@ int be_cmd_modify_eqd(struct be_ctrl_info *ctrl, u32 eq_id, u32 eqd) struct be_cmd_req_modify_eq_delay *req = embedded_payload(wrb); int status; - spin_lock(&ctrl->cmd_lock); + spin_lock(&ctrl->mbox_lock); memset(wrb, 0, sizeof(*wrb)); be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); @@ -696,7 +880,7 @@ int be_cmd_modify_eqd(struct be_ctrl_info *ctrl, u32 eq_id, u32 eqd) status = be_mbox_db_ring(ctrl); - spin_unlock(&ctrl->cmd_lock); + spin_unlock(&ctrl->mbox_lock); return status; } @@ -707,7 +891,7 @@ int be_cmd_vlan_config(struct be_ctrl_info *ctrl, u32 if_id, u16 *vtag_array, struct be_cmd_req_vlan_config *req = embedded_payload(wrb); int status; - spin_lock(&ctrl->cmd_lock); + spin_lock(&ctrl->mbox_lock); memset(wrb, 0, sizeof(*wrb)); be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); @@ -726,18 +910,22 @@ int be_cmd_vlan_config(struct be_ctrl_info *ctrl, u32 if_id, u16 *vtag_array, status = be_mbox_db_ring(ctrl); - spin_unlock(&ctrl->cmd_lock); + spin_unlock(&ctrl->mbox_lock); return status; } +/* Use MCC for this command as it may be called in BH context */ int be_cmd_promiscuous_config(struct be_ctrl_info *ctrl, u8 port_num, bool en) { - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); - struct be_cmd_req_promiscuous_config *req = embedded_payload(wrb); - int status; + struct be_mcc_wrb *wrb; + struct be_cmd_req_promiscuous_config *req; - spin_lock(&ctrl->cmd_lock); - memset(wrb, 0, sizeof(*wrb)); + spin_lock_bh(&ctrl->mcc_lock); + + wrb = wrb_from_mcc(&ctrl->mcc_obj.q); + BUG_ON(!wrb); + + req = embedded_payload(wrb); be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); @@ -749,21 +937,29 @@ int be_cmd_promiscuous_config(struct be_ctrl_info *ctrl, u8 port_num, bool en) else req->port0_promiscuous = en; - status = be_mbox_db_ring(ctrl); + be_mcc_notify_wait(ctrl); - spin_unlock(&ctrl->cmd_lock); - return status; + spin_unlock_bh(&ctrl->mcc_lock); + return 0; } -int be_cmd_mcast_mac_set(struct be_ctrl_info *ctrl, u32 if_id, u8 *mac_table, - u32 num, bool promiscuous) +/* + * Use MCC for this command as it may be called in BH context + * (mc == NULL) => multicast promiscous + */ +int be_cmd_multicast_set(struct be_ctrl_info *ctrl, u32 if_id, + struct dev_mc_list *mc_list, u32 mc_count) { - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); - struct be_cmd_req_mcast_mac_config *req = embedded_payload(wrb); - int status; +#define BE_MAX_MC 32 /* set mcast promisc if > 32 */ + struct be_mcc_wrb *wrb; + struct be_cmd_req_mcast_mac_config *req; - spin_lock(&ctrl->cmd_lock); - memset(wrb, 0, sizeof(*wrb)); + spin_lock_bh(&ctrl->mcc_lock); + + wrb = wrb_from_mcc(&ctrl->mcc_obj.q); + BUG_ON(!wrb); + + req = embedded_payload(wrb); be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); @@ -771,17 +967,23 @@ int be_cmd_mcast_mac_set(struct be_ctrl_info *ctrl, u32 if_id, u8 *mac_table, OPCODE_COMMON_NTWK_MULTICAST_SET, sizeof(*req)); req->interface_id = if_id; - req->promiscuous = promiscuous; - if (!promiscuous) { - req->num_mac = cpu_to_le16(num); - if (num) - memcpy(req->mac, mac_table, ETH_ALEN * num); + if (mc_list && mc_count <= BE_MAX_MC) { + int i; + struct dev_mc_list *mc; + + req->num_mac = cpu_to_le16(mc_count); + + for (mc = mc_list, i = 0; mc; mc = mc->next, i++) + memcpy(req->mac[i].byte, mc->dmi_addr, ETH_ALEN); + } else { + req->promiscuous = 1; } - status = be_mbox_db_ring(ctrl); + be_mcc_notify_wait(ctrl); - spin_unlock(&ctrl->cmd_lock); - return status; + spin_unlock_bh(&ctrl->mcc_lock); + + return 0; } int be_cmd_set_flow_control(struct be_ctrl_info *ctrl, u32 tx_fc, u32 rx_fc) @@ -790,7 +992,7 @@ int be_cmd_set_flow_control(struct be_ctrl_info *ctrl, u32 tx_fc, u32 rx_fc) struct be_cmd_req_set_flow_control *req = embedded_payload(wrb); int status; - spin_lock(&ctrl->cmd_lock); + spin_lock(&ctrl->mbox_lock); memset(wrb, 0, sizeof(*wrb)); @@ -804,7 +1006,7 @@ int be_cmd_set_flow_control(struct be_ctrl_info *ctrl, u32 tx_fc, u32 rx_fc) status = be_mbox_db_ring(ctrl); - spin_unlock(&ctrl->cmd_lock); + spin_unlock(&ctrl->mbox_lock); return status; } @@ -814,7 +1016,7 @@ int be_cmd_get_flow_control(struct be_ctrl_info *ctrl, u32 *tx_fc, u32 *rx_fc) struct be_cmd_req_get_flow_control *req = embedded_payload(wrb); int status; - spin_lock(&ctrl->cmd_lock); + spin_lock(&ctrl->mbox_lock); memset(wrb, 0, sizeof(*wrb)); @@ -831,7 +1033,7 @@ int be_cmd_get_flow_control(struct be_ctrl_info *ctrl, u32 *tx_fc, u32 *rx_fc) *rx_fc = le16_to_cpu(resp->rx_flow_control); } - spin_unlock(&ctrl->cmd_lock); + spin_unlock(&ctrl->mbox_lock); return status; } @@ -841,7 +1043,7 @@ int be_cmd_query_fw_cfg(struct be_ctrl_info *ctrl, u32 *port_num) struct be_cmd_req_query_fw_cfg *req = embedded_payload(wrb); int status; - spin_lock(&ctrl->cmd_lock); + spin_lock(&ctrl->mbox_lock); memset(wrb, 0, sizeof(*wrb)); @@ -856,6 +1058,6 @@ int be_cmd_query_fw_cfg(struct be_ctrl_info *ctrl, u32 *port_num) *port_num = le32_to_cpu(resp->phys_port); } - spin_unlock(&ctrl->cmd_lock); + spin_unlock(&ctrl->mbox_lock); return status; } diff --git a/drivers/net/benet/be_cmds.h b/drivers/net/benet/be_cmds.h index e499e2d5b8c3..747626da7b4e 100644 --- a/drivers/net/benet/be_cmds.h +++ b/drivers/net/benet/be_cmds.h @@ -76,6 +76,34 @@ struct be_mcc_cq_entry { u32 flags; /* dword 3 */ }; +/* When the async bit of mcc_compl is set, the last 4 bytes of + * mcc_compl is interpreted as follows: + */ +#define ASYNC_TRAILER_EVENT_CODE_SHIFT 8 /* bits 8 - 15 */ +#define ASYNC_TRAILER_EVENT_CODE_MASK 0xFF +#define ASYNC_EVENT_CODE_LINK_STATE 0x1 +struct be_async_event_trailer { + u32 code; +}; + +enum { + ASYNC_EVENT_LINK_DOWN = 0x0, + ASYNC_EVENT_LINK_UP = 0x1 +}; + +/* When the event code of an async trailer is link-state, the mcc_compl + * must be interpreted as follows + */ +struct be_async_event_link_state { + u8 physical_port; + u8 port_link_status; + u8 port_duplex; + u8 port_speed; + u8 port_fault; + u8 rsvd0[7]; + struct be_async_event_trailer trailer; +} __packed; + struct be_mcc_mailbox { struct be_mcc_wrb wrb; struct be_mcc_cq_entry cqe; @@ -101,6 +129,7 @@ struct be_mcc_mailbox { #define OPCODE_COMMON_FIRMWARE_CONFIG 42 #define OPCODE_COMMON_NTWK_INTERFACE_CREATE 50 #define OPCODE_COMMON_NTWK_INTERFACE_DESTROY 51 +#define OPCODE_COMMON_MCC_DESTROY 53 #define OPCODE_COMMON_CQ_DESTROY 54 #define OPCODE_COMMON_EQ_DESTROY 55 #define OPCODE_COMMON_QUERY_FIRMWARE_CONFIG 58 @@ -269,6 +298,38 @@ struct be_cmd_resp_cq_create { u16 rsvd0; } __packed; +/******************** Create MCCQ ***************************/ +/* Pseudo amap definition in which each bit of the actual structure is defined + * as a byte: used to calculate offset/shift/mask of each field */ +struct amap_mcc_context { + u8 con_index[14]; + u8 rsvd0[2]; + u8 ring_size[4]; + u8 fetch_wrb; + u8 fetch_r2t; + u8 cq_id[10]; + u8 prod_index[14]; + u8 fid[8]; + u8 pdid[9]; + u8 valid; + u8 rsvd1[32]; + u8 rsvd2[32]; +} __packed; + +struct be_cmd_req_mcc_create { + struct be_cmd_req_hdr hdr; + u16 num_pages; + u16 rsvd0; + u8 context[sizeof(struct amap_mcc_context) / 8]; + struct phys_addr pages[8]; +} __packed; + +struct be_cmd_resp_mcc_create { + struct be_cmd_resp_hdr hdr; + u16 id; + u16 rsvd0; +} __packed; + /******************** Create TxQ ***************************/ #define BE_ETH_TX_RING_TYPE_STANDARD 2 #define BE_ULP1_NUM 1 @@ -341,7 +402,8 @@ enum { QTYPE_EQ = 1, QTYPE_CQ, QTYPE_TXQ, - QTYPE_RXQ + QTYPE_RXQ, + QTYPE_MCCQ }; struct be_cmd_req_q_destroy { @@ -546,12 +608,6 @@ struct be_cmd_req_link_status { u32 rsvd; }; -struct be_link_info { - u8 duplex; - u8 speed; - u8 fault; -}; - enum { PHY_LINK_DUPLEX_NONE = 0x0, PHY_LINK_DUPLEX_HALF = 0x1, @@ -657,6 +713,9 @@ extern int be_cmd_cq_create(struct be_ctrl_info *ctrl, struct be_queue_info *cq, struct be_queue_info *eq, bool sol_evts, bool no_delay, int num_cqe_dma_coalesce); +extern int be_cmd_mccq_create(struct be_ctrl_info *ctrl, + struct be_queue_info *mccq, + struct be_queue_info *cq); extern int be_cmd_txq_create(struct be_ctrl_info *ctrl, struct be_queue_info *txq, struct be_queue_info *cq); @@ -667,7 +726,7 @@ extern int be_cmd_rxq_create(struct be_ctrl_info *ctrl, extern int be_cmd_q_destroy(struct be_ctrl_info *ctrl, struct be_queue_info *q, int type); extern int be_cmd_link_status_query(struct be_ctrl_info *ctrl, - struct be_link_info *link); + bool *link_up); extern int be_cmd_reset(struct be_ctrl_info *ctrl); extern int be_cmd_get_stats(struct be_ctrl_info *ctrl, struct be_dma_mem *nonemb_cmd); @@ -679,10 +738,11 @@ extern int be_cmd_vlan_config(struct be_ctrl_info *ctrl, u32 if_id, bool promiscuous); extern int be_cmd_promiscuous_config(struct be_ctrl_info *ctrl, u8 port_num, bool en); -extern int be_cmd_mcast_mac_set(struct be_ctrl_info *ctrl, u32 if_id, - u8 *mac_table, u32 num, bool promiscuous); +extern int be_cmd_multicast_set(struct be_ctrl_info *ctrl, u32 if_id, + struct dev_mc_list *mc_list, u32 mc_count); extern int be_cmd_set_flow_control(struct be_ctrl_info *ctrl, u32 tx_fc, u32 rx_fc); extern int be_cmd_get_flow_control(struct be_ctrl_info *ctrl, u32 *tx_fc, u32 *rx_fc); extern int be_cmd_query_fw_cfg(struct be_ctrl_info *ctrl, u32 *port_num); +extern void be_process_mcc(struct be_ctrl_info *ctrl); diff --git a/drivers/net/benet/be_hw.h b/drivers/net/benet/be_hw.h index b132aa4893ca..b02e805c1db3 100644 --- a/drivers/net/benet/be_hw.h +++ b/drivers/net/benet/be_hw.h @@ -61,7 +61,7 @@ /* Clear the interrupt for this eq */ #define DB_EQ_CLR_SHIFT (9) /* bit 9 */ /* Must be 1 */ -#define DB_EQ_EVNT_SHIFT (10) /* bit 10 */ +#define DB_EQ_EVNT_SHIFT (10) /* bit 10 */ /* Number of event entries processed */ #define DB_EQ_NUM_POPPED_SHIFT (16) /* bits 16 - 28 */ /* Rearm bit */ @@ -88,6 +88,12 @@ /* Number of rx frags posted */ #define DB_RQ_NUM_POSTED_SHIFT (24) /* bits 24 - 31 */ +/********** MCC door bell ************/ +#define DB_MCCQ_OFFSET 0x140 +#define DB_MCCQ_RING_ID_MASK 0x7FF /* bits 0 - 10 */ +/* Number of entries posted */ +#define DB_MCCQ_NUM_POSTED_SHIFT (16) /* bits 16 - 29 */ + /* * BE descriptors: host memory data structures whose formats * are hardwired in BE silicon. diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 5c378b5e8e41..66c10c87f517 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -60,26 +60,6 @@ static int be_queue_alloc(struct be_adapter *adapter, struct be_queue_info *q, return 0; } -static inline void *queue_head_node(struct be_queue_info *q) -{ - return q->dma_mem.va + q->head * q->entry_size; -} - -static inline void *queue_tail_node(struct be_queue_info *q) -{ - return q->dma_mem.va + q->tail * q->entry_size; -} - -static inline void queue_head_inc(struct be_queue_info *q) -{ - index_inc(&q->head, q->len); -} - -static inline void queue_tail_inc(struct be_queue_info *q) -{ - index_inc(&q->tail, q->len); -} - static void be_intr_set(struct be_ctrl_info *ctrl, bool enable) { u8 __iomem *addr = ctrl->pcicfg + PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET; @@ -127,7 +107,7 @@ static void be_eq_notify(struct be_ctrl_info *ctrl, u16 qid, iowrite32(val, ctrl->db + DB_EQ_OFFSET); } -static void be_cq_notify(struct be_ctrl_info *ctrl, u16 qid, +void be_cq_notify(struct be_ctrl_info *ctrl, u16 qid, bool arm, u16 num_popped) { u32 val = 0; @@ -168,6 +148,7 @@ static void netdev_stats_update(struct be_adapter *adapter) struct be_port_rxf_stats *port_stats = &rxf_stats->port[adapter->port_num]; struct net_device_stats *dev_stats = &adapter->stats.net_stats; + struct be_erx_stats *erx_stats = &hw_stats->erx; dev_stats->rx_packets = port_stats->rx_total_frames; dev_stats->tx_packets = port_stats->tx_unicastframes + @@ -181,29 +162,33 @@ static void netdev_stats_update(struct be_adapter *adapter) dev_stats->rx_errors = port_stats->rx_crc_errors + port_stats->rx_alignment_symbol_errors + port_stats->rx_in_range_errors + - port_stats->rx_out_range_errors + port_stats->rx_frame_too_long; + port_stats->rx_out_range_errors + + port_stats->rx_frame_too_long + + port_stats->rx_dropped_too_small + + port_stats->rx_dropped_too_short + + port_stats->rx_dropped_header_too_small + + port_stats->rx_dropped_tcp_length + + port_stats->rx_dropped_runt + + port_stats->rx_tcp_checksum_errs + + port_stats->rx_ip_checksum_errs + + port_stats->rx_udp_checksum_errs; - /* packet transmit problems */ - dev_stats->tx_errors = 0; - - /* no space in linux buffers */ - dev_stats->rx_dropped = 0; - - /* no space available in linux */ - dev_stats->tx_dropped = 0; - - dev_stats->multicast = port_stats->tx_multicastframes; - dev_stats->collisions = 0; + /* no space in linux buffers: best possible approximation */ + dev_stats->rx_dropped = erx_stats->rx_drops_no_fragments[0]; /* detailed rx errors */ dev_stats->rx_length_errors = port_stats->rx_in_range_errors + - port_stats->rx_out_range_errors + port_stats->rx_frame_too_long; + port_stats->rx_out_range_errors + + port_stats->rx_frame_too_long; + /* receive ring buffer overflow */ dev_stats->rx_over_errors = 0; + dev_stats->rx_crc_errors = port_stats->rx_crc_errors; /* frame alignment errors */ dev_stats->rx_frame_errors = port_stats->rx_alignment_symbol_errors; + /* receiver fifo overrun */ /* drops_no_pbuf is no per i/f, it's per BE card */ dev_stats->rx_fifo_errors = port_stats->rx_fifo_overflow + @@ -211,6 +196,16 @@ static void netdev_stats_update(struct be_adapter *adapter) rxf_stats->rx_drops_no_pbuf; /* receiver missed packetd */ dev_stats->rx_missed_errors = 0; + + /* packet transmit problems */ + dev_stats->tx_errors = 0; + + /* no space available in linux */ + dev_stats->tx_dropped = 0; + + dev_stats->multicast = port_stats->tx_multicastframes; + dev_stats->collisions = 0; + /* detailed tx_errors */ dev_stats->tx_aborted_errors = 0; dev_stats->tx_carrier_errors = 0; @@ -219,28 +214,24 @@ static void netdev_stats_update(struct be_adapter *adapter) dev_stats->tx_window_errors = 0; } -static void be_link_status_update(struct be_adapter *adapter) +void be_link_status_update(void *ctxt, bool link_up) { - struct be_link_info *prev = &adapter->link; - struct be_link_info now = { 0 }; + struct be_adapter *adapter = ctxt; struct net_device *netdev = adapter->netdev; - be_cmd_link_status_query(&adapter->ctrl, &now); - /* If link came up or went down */ - if (now.speed != prev->speed && (now.speed == PHY_LINK_SPEED_ZERO || - prev->speed == PHY_LINK_SPEED_ZERO)) { - if (now.speed == PHY_LINK_SPEED_ZERO) { - netif_stop_queue(netdev); - netif_carrier_off(netdev); - printk(KERN_INFO "%s: Link down\n", netdev->name); - } else { + if (adapter->link_up != link_up) { + if (link_up) { netif_start_queue(netdev); netif_carrier_on(netdev); printk(KERN_INFO "%s: Link up\n", netdev->name); + } else { + netif_stop_queue(netdev); + netif_carrier_off(netdev); + printk(KERN_INFO "%s: Link down\n", netdev->name); } + adapter->link_up = link_up; } - *prev = now; } /* Update the EQ delay n BE based on the RX frags consumed / sec */ @@ -337,13 +328,10 @@ static void be_tx_stats_update(struct be_adapter *adapter, /* Determine number of WRB entries needed to xmit data in an skb */ static u32 wrb_cnt_for_skb(struct sk_buff *skb, bool *dummy) { - int cnt = 0; - while (skb) { - if (skb->len > skb->data_len) - cnt++; - cnt += skb_shinfo(skb)->nr_frags; - skb = skb_shinfo(skb)->frag_list; - } + int cnt = (skb->len > skb->data_len); + + cnt += skb_shinfo(skb)->nr_frags; + /* to account for hdr wrb */ cnt++; if (cnt & 1) { @@ -409,31 +397,28 @@ static int make_tx_wrbs(struct be_adapter *adapter, hdr = queue_head_node(txq); queue_head_inc(txq); - while (skb) { - if (skb->len > skb->data_len) { - int len = skb->len - skb->data_len; - busaddr = pci_map_single(pdev, skb->data, len, - PCI_DMA_TODEVICE); - wrb = queue_head_node(txq); - wrb_fill(wrb, busaddr, len); - be_dws_cpu_to_le(wrb, sizeof(*wrb)); - queue_head_inc(txq); - copied += len; - } + if (skb->len > skb->data_len) { + int len = skb->len - skb->data_len; + busaddr = pci_map_single(pdev, skb->data, len, + PCI_DMA_TODEVICE); + wrb = queue_head_node(txq); + wrb_fill(wrb, busaddr, len); + be_dws_cpu_to_le(wrb, sizeof(*wrb)); + queue_head_inc(txq); + copied += len; + } - for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { - struct skb_frag_struct *frag = - &skb_shinfo(skb)->frags[i]; - busaddr = pci_map_page(pdev, frag->page, - frag->page_offset, - frag->size, PCI_DMA_TODEVICE); - wrb = queue_head_node(txq); - wrb_fill(wrb, busaddr, frag->size); - be_dws_cpu_to_le(wrb, sizeof(*wrb)); - queue_head_inc(txq); - copied += frag->size; - } - skb = skb_shinfo(skb)->frag_list; + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + struct skb_frag_struct *frag = + &skb_shinfo(skb)->frags[i]; + busaddr = pci_map_page(pdev, frag->page, + frag->page_offset, + frag->size, PCI_DMA_TODEVICE); + wrb = queue_head_node(txq); + wrb_fill(wrb, busaddr, frag->size); + be_dws_cpu_to_le(wrb, sizeof(*wrb)); + queue_head_inc(txq); + copied += frag->size; } if (dummy_wrb) { @@ -478,8 +463,6 @@ static int be_xmit(struct sk_buff *skb, struct net_device *netdev) be_txq_notify(&adapter->ctrl, txq->id, wrb_cnt); - netdev->trans_start = jiffies; - be_tx_stats_update(adapter, wrb_cnt, copied, stopped); return NETDEV_TX_OK; } @@ -562,47 +545,32 @@ static void be_vlan_rem_vid(struct net_device *netdev, u16 vid) be_vid_config(netdev); } -static void be_set_multicast_filter(struct net_device *netdev) -{ - struct be_adapter *adapter = netdev_priv(netdev); - struct dev_mc_list *mc_ptr; - u8 mac_addr[32][ETH_ALEN]; - int i = 0; - - if (netdev->flags & IFF_ALLMULTI) { - /* set BE in Multicast promiscuous */ - be_cmd_mcast_mac_set(&adapter->ctrl, - adapter->if_handle, NULL, 0, true); - return; - } - - for (mc_ptr = netdev->mc_list; mc_ptr; mc_ptr = mc_ptr->next) { - memcpy(&mac_addr[i][0], mc_ptr->dmi_addr, ETH_ALEN); - if (++i >= 32) { - be_cmd_mcast_mac_set(&adapter->ctrl, - adapter->if_handle, &mac_addr[0][0], i, false); - i = 0; - } - - } - - if (i) { - /* reset the promiscuous mode also. */ - be_cmd_mcast_mac_set(&adapter->ctrl, - adapter->if_handle, &mac_addr[0][0], i, false); - } -} - static void be_set_multicast_list(struct net_device *netdev) { struct be_adapter *adapter = netdev_priv(netdev); + struct be_ctrl_info *ctrl = &adapter->ctrl; if (netdev->flags & IFF_PROMISC) { - be_cmd_promiscuous_config(&adapter->ctrl, adapter->port_num, 1); - } else { - be_cmd_promiscuous_config(&adapter->ctrl, adapter->port_num, 0); - be_set_multicast_filter(netdev); + be_cmd_promiscuous_config(ctrl, adapter->port_num, 1); + adapter->promiscuous = true; + goto done; } + + /* BE was previously in promiscous mode; disable it */ + if (adapter->promiscuous) { + adapter->promiscuous = false; + be_cmd_promiscuous_config(ctrl, adapter->port_num, 0); + } + + if (netdev->flags & IFF_ALLMULTI) { + be_cmd_multicast_set(ctrl, adapter->if_handle, NULL, 0); + goto done; + } + + be_cmd_multicast_set(ctrl, adapter->if_handle, netdev->mc_list, + netdev->mc_count); +done: + return; } static void be_rx_rate_update(struct be_adapter *adapter) @@ -637,6 +605,22 @@ static void be_rx_stats_update(struct be_adapter *adapter, stats->be_rx_bytes += pktsize; } +static inline bool do_pkt_csum(struct be_eth_rx_compl *rxcp, bool cso) +{ + u8 l4_cksm, ip_version, ipcksm, tcpf = 0, udpf = 0, ipv6_chk; + + l4_cksm = AMAP_GET_BITS(struct amap_eth_rx_compl, l4_cksm, rxcp); + ipcksm = AMAP_GET_BITS(struct amap_eth_rx_compl, ipcksm, rxcp); + ip_version = AMAP_GET_BITS(struct amap_eth_rx_compl, ip_version, rxcp); + if (ip_version) { + tcpf = AMAP_GET_BITS(struct amap_eth_rx_compl, tcpf, rxcp); + udpf = AMAP_GET_BITS(struct amap_eth_rx_compl, udpf, rxcp); + } + ipv6_chk = (ip_version && (tcpf || udpf)); + + return ((l4_cksm && ipv6_chk && ipcksm) && cso) ? false : true; +} + static struct be_rx_page_info * get_rx_page_info(struct be_adapter *adapter, u16 frag_idx) { @@ -720,7 +704,7 @@ static void skb_fill_rx_data(struct be_adapter *adapter, if (pktsize <= rx_frag_size) { BUG_ON(num_rcvd != 1); - return; + goto done; } /* More frags present for this completion */ @@ -742,6 +726,7 @@ static void skb_fill_rx_data(struct be_adapter *adapter, memset(page_info, 0, sizeof(*page_info)); } +done: be_rx_stats_update(adapter, pktsize, num_rcvd); return; } @@ -752,9 +737,7 @@ static void be_rx_compl_process(struct be_adapter *adapter, { struct sk_buff *skb; u32 vtp, vid; - int l4_cksm; - l4_cksm = AMAP_GET_BITS(struct amap_eth_rx_compl, l4_cksm, rxcp); vtp = AMAP_GET_BITS(struct amap_eth_rx_compl, vtp, rxcp); skb = netdev_alloc_skb(adapter->netdev, BE_HDR_LEN + NET_IP_ALIGN); @@ -769,10 +752,10 @@ static void be_rx_compl_process(struct be_adapter *adapter, skb_fill_rx_data(adapter, skb, rxcp); - if (l4_cksm && adapter->rx_csum) - skb->ip_summed = CHECKSUM_UNNECESSARY; - else + if (do_pkt_csum(rxcp, adapter->rx_csum)) skb->ip_summed = CHECKSUM_NONE; + else + skb->ip_summed = CHECKSUM_UNNECESSARY; skb->truesize = skb->len + sizeof(struct sk_buff); skb->protocol = eth_type_trans(skb, adapter->netdev); @@ -854,12 +837,19 @@ static struct be_eth_rx_compl *be_rx_compl_get(struct be_adapter *adapter) be_dws_le_to_cpu(rxcp, sizeof(*rxcp)); - rxcp->dw[offsetof(struct amap_eth_rx_compl, valid) / 32] = 0; - queue_tail_inc(&adapter->rx_obj.cq); return rxcp; } +/* To reset the valid bit, we need to reset the whole word as + * when walking the queue the valid entries are little-endian + * and invalid entries are host endian + */ +static inline void be_rx_compl_reset(struct be_eth_rx_compl *rxcp) +{ + rxcp->dw[offsetof(struct amap_eth_rx_compl, valid) / 32] = 0; +} + static inline struct page *be_alloc_pages(u32 size) { gfp_t alloc_flags = GFP_ATOMIC; @@ -931,10 +921,8 @@ static void be_post_rx_frags(struct be_adapter *adapter) return; } -static struct be_eth_tx_compl * -be_tx_compl_get(struct be_adapter *adapter) +static struct be_eth_tx_compl *be_tx_compl_get(struct be_queue_info *tx_cq) { - struct be_queue_info *tx_cq = &adapter->tx_obj.cq; struct be_eth_tx_compl *txcp = queue_tail_node(tx_cq); if (txcp->dw[offsetof(struct amap_eth_tx_compl, valid) / 32] == 0) @@ -991,6 +979,7 @@ static void be_rx_q_clean(struct be_adapter *adapter) /* First cleanup pending rx completions */ while ((rxcp = be_rx_compl_get(adapter)) != NULL) { be_rx_compl_discard(adapter, rxcp); + be_rx_compl_reset(rxcp); be_cq_notify(&adapter->ctrl, rx_cq->id, true, 1); } @@ -1021,13 +1010,71 @@ static void be_tx_q_clean(struct be_adapter *adapter) } } +static void be_mcc_queues_destroy(struct be_adapter *adapter) +{ + struct be_queue_info *q; + struct be_ctrl_info *ctrl = &adapter->ctrl; + + q = &ctrl->mcc_obj.q; + if (q->created) + be_cmd_q_destroy(ctrl, q, QTYPE_MCCQ); + be_queue_free(adapter, q); + + q = &ctrl->mcc_obj.cq; + if (q->created) + be_cmd_q_destroy(ctrl, q, QTYPE_CQ); + be_queue_free(adapter, q); +} + +/* Must be called only after TX qs are created as MCC shares TX EQ */ +static int be_mcc_queues_create(struct be_adapter *adapter) +{ + struct be_queue_info *q, *cq; + struct be_ctrl_info *ctrl = &adapter->ctrl; + + /* Alloc MCC compl queue */ + cq = &ctrl->mcc_obj.cq; + if (be_queue_alloc(adapter, cq, MCC_CQ_LEN, + sizeof(struct be_mcc_cq_entry))) + goto err; + + /* Ask BE to create MCC compl queue; share TX's eq */ + if (be_cmd_cq_create(ctrl, cq, &adapter->tx_eq.q, false, true, 0)) + goto mcc_cq_free; + + /* Alloc MCC queue */ + q = &ctrl->mcc_obj.q; + if (be_queue_alloc(adapter, q, MCC_Q_LEN, sizeof(struct be_mcc_wrb))) + goto mcc_cq_destroy; + + /* Ask BE to create MCC queue */ + if (be_cmd_mccq_create(ctrl, q, cq)) + goto mcc_q_free; + + return 0; + +mcc_q_free: + be_queue_free(adapter, q); +mcc_cq_destroy: + be_cmd_q_destroy(ctrl, cq, QTYPE_CQ); +mcc_cq_free: + be_queue_free(adapter, cq); +err: + return -1; +} + static void be_tx_queues_destroy(struct be_adapter *adapter) { struct be_queue_info *q; q = &adapter->tx_obj.q; - if (q->created) + if (q->created) { be_cmd_q_destroy(&adapter->ctrl, q, QTYPE_TXQ); + + /* No more tx completions can be rcvd now; clean up if there + * are any pending completions or pending tx requests */ + be_tx_q_clean(adapter); + } be_queue_free(adapter, q); q = &adapter->tx_obj.cq; @@ -1035,10 +1082,6 @@ static void be_tx_queues_destroy(struct be_adapter *adapter) be_cmd_q_destroy(&adapter->ctrl, q, QTYPE_CQ); be_queue_free(adapter, q); - /* No more tx completions can be rcvd now; clean up if there are - * any pending completions or pending tx requests */ - be_tx_q_clean(adapter); - q = &adapter->tx_eq.q; if (q->created) be_cmd_q_destroy(&adapter->ctrl, q, QTYPE_EQ); @@ -1232,7 +1275,7 @@ static irqreturn_t be_msix_rx(int irq, void *dev) return IRQ_HANDLED; } -static irqreturn_t be_msix_tx(int irq, void *dev) +static irqreturn_t be_msix_tx_mcc(int irq, void *dev) { struct be_adapter *adapter = dev; @@ -1272,6 +1315,8 @@ int be_poll_rx(struct napi_struct *napi, int budget) be_rx_compl_process_lro(adapter, rxcp); else be_rx_compl_process(adapter, rxcp); + + be_rx_compl_reset(rxcp); } lro_flush_all(&adapter->rx_obj.lro_mgr); @@ -1291,40 +1336,51 @@ int be_poll_rx(struct napi_struct *napi, int budget) return work_done; } -/* For TX we don't honour budget; consume everything */ -int be_poll_tx(struct napi_struct *napi, int budget) +void be_process_tx(struct be_adapter *adapter) { - struct be_eq_obj *tx_eq = container_of(napi, struct be_eq_obj, napi); - struct be_adapter *adapter = - container_of(tx_eq, struct be_adapter, tx_eq); - struct be_tx_obj *tx_obj = &adapter->tx_obj; - struct be_queue_info *tx_cq = &tx_obj->cq; - struct be_queue_info *txq = &tx_obj->q; + struct be_queue_info *txq = &adapter->tx_obj.q; + struct be_queue_info *tx_cq = &adapter->tx_obj.cq; struct be_eth_tx_compl *txcp; u32 num_cmpl = 0; u16 end_idx; - while ((txcp = be_tx_compl_get(adapter))) { + while ((txcp = be_tx_compl_get(tx_cq))) { end_idx = AMAP_GET_BITS(struct amap_eth_tx_compl, wrb_index, txcp); be_tx_compl_process(adapter, end_idx); num_cmpl++; } - /* As Tx wrbs have been freed up, wake up netdev queue if - * it was stopped due to lack of tx wrbs. - */ - if (netif_queue_stopped(adapter->netdev) && + if (num_cmpl) { + be_cq_notify(&adapter->ctrl, tx_cq->id, true, num_cmpl); + + /* As Tx wrbs have been freed up, wake up netdev queue if + * it was stopped due to lack of tx wrbs. + */ + if (netif_queue_stopped(adapter->netdev) && atomic_read(&txq->used) < txq->len / 2) { - netif_wake_queue(adapter->netdev); + netif_wake_queue(adapter->netdev); + } + + drvr_stats(adapter)->be_tx_events++; + drvr_stats(adapter)->be_tx_compl += num_cmpl; } +} + +/* As TX and MCC share the same EQ check for both TX and MCC completions. + * For TX/MCC we don't honour budget; consume everything + */ +static int be_poll_tx_mcc(struct napi_struct *napi, int budget) +{ + struct be_eq_obj *tx_eq = container_of(napi, struct be_eq_obj, napi); + struct be_adapter *adapter = + container_of(tx_eq, struct be_adapter, tx_eq); napi_complete(napi); - be_cq_notify(&adapter->ctrl, tx_cq->id, true, num_cmpl); + be_process_tx(adapter); - drvr_stats(adapter)->be_tx_events++; - drvr_stats(adapter)->be_tx_compl += num_cmpl; + be_process_mcc(&adapter->ctrl); return 1; } @@ -1335,9 +1391,6 @@ static void be_worker(struct work_struct *work) container_of(work, struct be_adapter, work.work); int status; - /* Check link */ - be_link_status_update(adapter); - /* Get Stats */ status = be_cmd_get_stats(&adapter->ctrl, &adapter->stats.cmd); if (!status) @@ -1386,7 +1439,7 @@ static int be_msix_register(struct be_adapter *adapter) sprintf(tx_eq->desc, "%s-tx", netdev->name); vec = be_msix_vec_get(adapter, tx_eq->q.id); - status = request_irq(vec, be_msix_tx, 0, tx_eq->desc, adapter); + status = request_irq(vec, be_msix_tx_mcc, 0, tx_eq->desc, adapter); if (status) goto err; @@ -1462,6 +1515,39 @@ static int be_open(struct net_device *netdev) struct be_ctrl_info *ctrl = &adapter->ctrl; struct be_eq_obj *rx_eq = &adapter->rx_eq; struct be_eq_obj *tx_eq = &adapter->tx_eq; + bool link_up; + int status; + + /* First time posting */ + be_post_rx_frags(adapter); + + napi_enable(&rx_eq->napi); + napi_enable(&tx_eq->napi); + + be_irq_register(adapter); + + be_intr_set(ctrl, true); + + /* The evt queues are created in unarmed state; arm them */ + be_eq_notify(ctrl, rx_eq->q.id, true, false, 0); + be_eq_notify(ctrl, tx_eq->q.id, true, false, 0); + + /* Rx compl queue may be in unarmed state; rearm it */ + be_cq_notify(ctrl, adapter->rx_obj.cq.id, true, 0); + + status = be_cmd_link_status_query(ctrl, &link_up); + if (status) + return status; + be_link_status_update(adapter, link_up); + + schedule_delayed_work(&adapter->work, msecs_to_jiffies(100)); + return 0; +} + +static int be_setup(struct be_adapter *adapter) +{ + struct be_ctrl_info *ctrl = &adapter->ctrl; + struct net_device *netdev = adapter->netdev; u32 if_flags; int status; @@ -1488,29 +1574,14 @@ static int be_open(struct net_device *netdev) if (status != 0) goto tx_qs_destroy; - /* First time posting */ - be_post_rx_frags(adapter); + status = be_mcc_queues_create(adapter); + if (status != 0) + goto rx_qs_destroy; - napi_enable(&rx_eq->napi); - napi_enable(&tx_eq->napi); - - be_irq_register(adapter); - - be_intr_set(ctrl, true); - - /* The evt queues are created in the unarmed state; arm them */ - be_eq_notify(ctrl, rx_eq->q.id, true, false, 0); - be_eq_notify(ctrl, tx_eq->q.id, true, false, 0); - - /* The compl queues are created in the unarmed state; arm them */ - be_cq_notify(ctrl, adapter->rx_obj.cq.id, true, 0); - be_cq_notify(ctrl, adapter->tx_obj.cq.id, true, 0); - - be_link_status_update(adapter); - - schedule_delayed_work(&adapter->work, msecs_to_jiffies(100)); return 0; +rx_qs_destroy: + be_rx_queues_destroy(adapter); tx_qs_destroy: be_tx_queues_destroy(adapter); if_destroy: @@ -1519,6 +1590,19 @@ do_none: return status; } +static int be_clear(struct be_adapter *adapter) +{ + struct be_ctrl_info *ctrl = &adapter->ctrl; + + be_rx_queues_destroy(adapter); + be_tx_queues_destroy(adapter); + + be_cmd_if_destroy(ctrl, adapter->if_handle); + + be_mcc_queues_destroy(adapter); + return 0; +} + static int be_close(struct net_device *netdev) { struct be_adapter *adapter = netdev_priv(netdev); @@ -1527,11 +1611,11 @@ static int be_close(struct net_device *netdev) struct be_eq_obj *tx_eq = &adapter->tx_eq; int vec; - cancel_delayed_work(&adapter->work); + cancel_delayed_work_sync(&adapter->work); netif_stop_queue(netdev); netif_carrier_off(netdev); - adapter->link.speed = PHY_LINK_SPEED_ZERO; + adapter->link_up = false; be_intr_set(ctrl, false); @@ -1548,10 +1632,6 @@ static int be_close(struct net_device *netdev) napi_disable(&rx_eq->napi); napi_disable(&tx_eq->napi); - be_rx_queues_destroy(adapter); - be_tx_queues_destroy(adapter); - - be_cmd_if_destroy(ctrl, adapter->if_handle); return 0; } @@ -1626,10 +1706,12 @@ static void be_netdev_init(struct net_device *netdev) netdev->features |= NETIF_F_SG | NETIF_F_HW_VLAN_RX | NETIF_F_TSO | NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER | NETIF_F_IP_CSUM | - NETIF_F_IPV6_CSUM | NETIF_F_TSO6; + NETIF_F_IPV6_CSUM; netdev->flags |= IFF_MULTICAST; + adapter->rx_csum = true; + BE_SET_NETDEV_OPS(netdev, &be_netdev_ops); SET_ETHTOOL_OPS(netdev, &be_ethtool_ops); @@ -1638,7 +1720,7 @@ static void be_netdev_init(struct net_device *netdev) netif_napi_add(netdev, &adapter->rx_eq.napi, be_poll_rx, BE_NAPI_WEIGHT); - netif_napi_add(netdev, &adapter->tx_eq.napi, be_poll_tx, + netif_napi_add(netdev, &adapter->tx_eq.napi, be_poll_tx_mcc, BE_NAPI_WEIGHT); netif_carrier_off(netdev); @@ -1720,7 +1802,12 @@ static int be_ctrl_init(struct be_adapter *adapter) mbox_mem_align->va = PTR_ALIGN(mbox_mem_alloc->va, 16); mbox_mem_align->dma = PTR_ALIGN(mbox_mem_alloc->dma, 16); memset(mbox_mem_align->va, 0, sizeof(struct be_mcc_mailbox)); - spin_lock_init(&ctrl->cmd_lock); + spin_lock_init(&ctrl->mbox_lock); + spin_lock_init(&ctrl->mcc_lock); + spin_lock_init(&ctrl->mcc_cq_lock); + + ctrl->async_cb = be_link_status_update; + ctrl->adapter_ctxt = adapter; val = ioread32(ctrl->pcicfg + PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET); ctrl->pci_func = (val >> MEMBAR_CTRL_INT_CTRL_PFUNC_SHIFT) & @@ -1758,6 +1845,8 @@ static void __devexit be_remove(struct pci_dev *pdev) unregister_netdev(adapter->netdev); + be_clear(adapter); + be_stats_cleanup(adapter); be_ctrl_cleanup(adapter); @@ -1855,13 +1944,18 @@ static int __devinit be_probe(struct pci_dev *pdev, be_netdev_init(netdev); SET_NETDEV_DEV(netdev, &adapter->pdev->dev); + status = be_setup(adapter); + if (status) + goto stats_clean; status = register_netdev(netdev); if (status != 0) - goto stats_clean; + goto unsetup; dev_info(&pdev->dev, "%s port %d\n", nic_name(pdev), adapter->port_num); return 0; +unsetup: + be_clear(adapter); stats_clean: be_stats_cleanup(adapter); ctrl_clean: @@ -1886,6 +1980,7 @@ static int be_suspend(struct pci_dev *pdev, pm_message_t state) if (netif_running(netdev)) { rtnl_lock(); be_close(netdev); + be_clear(adapter); rtnl_unlock(); } @@ -1912,6 +2007,7 @@ static int be_resume(struct pci_dev *pdev) if (netif_running(netdev)) { rtnl_lock(); + be_setup(adapter); be_open(netdev); rtnl_unlock(); } diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c index b4da18213324..c15fc281f79f 100644 --- a/drivers/net/bfin_mac.c +++ b/drivers/net/bfin_mac.c @@ -194,13 +194,13 @@ static int desc_list_init(void) struct dma_descriptor *b = &(r->desc_b); /* allocate a new skb for next time receive */ - new_skb = dev_alloc_skb(PKT_BUF_SZ + 2); + new_skb = dev_alloc_skb(PKT_BUF_SZ + NET_IP_ALIGN); if (!new_skb) { printk(KERN_NOTICE DRV_NAME ": init: low on mem - packet dropped\n"); goto init_error; } - skb_reserve(new_skb, 2); + skb_reserve(new_skb, NET_IP_ALIGN); r->skb = new_skb; /* @@ -566,9 +566,9 @@ static void adjust_tx_list(void) */ if (current_tx_ptr->next->next == tx_list_head) { while (tx_list_head->status.status_word == 0) { - mdelay(1); + udelay(10); if (tx_list_head->status.status_word != 0 - || !(bfin_read_DMA2_IRQ_STATUS() & 0x08)) { + || !(bfin_read_DMA2_IRQ_STATUS() & DMA_RUN)) { goto adjust_head; } if (timeout_cnt-- < 0) { @@ -606,93 +606,41 @@ static int bfin_mac_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { u16 *data; - + u32 data_align = (unsigned long)(skb->data) & 0x3; current_tx_ptr->skb = skb; - if (ANOMALY_05000285) { - /* - * TXDWA feature is not avaible to older revision < 0.3 silicon - * of BF537 - * - * Only if data buffer is ODD WORD alignment, we do not - * need to memcpy - */ - u32 data_align = (u32)(skb->data) & 0x3; - if (data_align == 0x2) { - /* move skb->data to current_tx_ptr payload */ - data = (u16 *)(skb->data) - 1; - *data = (u16)(skb->len); - current_tx_ptr->desc_a.start_addr = (u32)data; - /* this is important! */ - blackfin_dcache_flush_range((u32)data, - (u32)((u8 *)data + skb->len + 4)); - } else { - *((u16 *)(current_tx_ptr->packet)) = (u16)(skb->len); - memcpy((u8 *)(current_tx_ptr->packet + 2), skb->data, - skb->len); - current_tx_ptr->desc_a.start_addr = - (u32)current_tx_ptr->packet; - if (current_tx_ptr->status.status_word != 0) - current_tx_ptr->status.status_word = 0; - blackfin_dcache_flush_range( - (u32)current_tx_ptr->packet, - (u32)(current_tx_ptr->packet + skb->len + 2)); - } + if (data_align == 0x2) { + /* move skb->data to current_tx_ptr payload */ + data = (u16 *)(skb->data) - 1; + *data = (u16)(skb->len); + current_tx_ptr->desc_a.start_addr = (u32)data; + /* this is important! */ + blackfin_dcache_flush_range((u32)data, + (u32)((u8 *)data + skb->len + 4)); } else { - /* - * TXDWA feature is avaible to revision < 0.3 silicon of - * BF537 and always avaible to BF52x - */ - u32 data_align = (u32)(skb->data) & 0x3; - if (data_align == 0x0) { - u16 sysctl = bfin_read_EMAC_SYSCTL(); - sysctl |= TXDWA; - bfin_write_EMAC_SYSCTL(sysctl); - - /* move skb->data to current_tx_ptr payload */ - data = (u16 *)(skb->data) - 2; - *data = (u16)(skb->len); - current_tx_ptr->desc_a.start_addr = (u32)data; - /* this is important! */ - blackfin_dcache_flush_range( - (u32)data, - (u32)((u8 *)data + skb->len + 4)); - } else if (data_align == 0x2) { - u16 sysctl = bfin_read_EMAC_SYSCTL(); - sysctl &= ~TXDWA; - bfin_write_EMAC_SYSCTL(sysctl); - - /* move skb->data to current_tx_ptr payload */ - data = (u16 *)(skb->data) - 1; - *data = (u16)(skb->len); - current_tx_ptr->desc_a.start_addr = (u32)data; - /* this is important! */ - blackfin_dcache_flush_range( - (u32)data, - (u32)((u8 *)data + skb->len + 4)); - } else { - u16 sysctl = bfin_read_EMAC_SYSCTL(); - sysctl &= ~TXDWA; - bfin_write_EMAC_SYSCTL(sysctl); - - *((u16 *)(current_tx_ptr->packet)) = (u16)(skb->len); - memcpy((u8 *)(current_tx_ptr->packet + 2), skb->data, - skb->len); - current_tx_ptr->desc_a.start_addr = - (u32)current_tx_ptr->packet; - if (current_tx_ptr->status.status_word != 0) - current_tx_ptr->status.status_word = 0; - blackfin_dcache_flush_range( - (u32)current_tx_ptr->packet, - (u32)(current_tx_ptr->packet + skb->len + 2)); - } + *((u16 *)(current_tx_ptr->packet)) = (u16)(skb->len); + memcpy((u8 *)(current_tx_ptr->packet + 2), skb->data, + skb->len); + current_tx_ptr->desc_a.start_addr = + (u32)current_tx_ptr->packet; + if (current_tx_ptr->status.status_word != 0) + current_tx_ptr->status.status_word = 0; + blackfin_dcache_flush_range( + (u32)current_tx_ptr->packet, + (u32)(current_tx_ptr->packet + skb->len + 2)); } + /* make sure the internal data buffers in the core are drained + * so that the DMA descriptors are completely written when the + * DMA engine goes to fetch them below + */ + SSYNC(); + /* enable this packet's dma */ current_tx_ptr->desc_a.config |= DMAEN; /* tx dma is running, just return */ - if (bfin_read_DMA2_IRQ_STATUS() & 0x08) + if (bfin_read_DMA2_IRQ_STATUS() & DMA_RUN) goto out; /* tx dma is not running */ @@ -718,7 +666,7 @@ static void bfin_mac_rx(struct net_device *dev) /* allocate a new skb for next time receive */ skb = current_rx_ptr->skb; - new_skb = dev_alloc_skb(PKT_BUF_SZ + 2); + new_skb = dev_alloc_skb(PKT_BUF_SZ + NET_IP_ALIGN); if (!new_skb) { printk(KERN_NOTICE DRV_NAME ": rx: low on mem - packet dropped\n"); @@ -726,7 +674,7 @@ static void bfin_mac_rx(struct net_device *dev) goto out; } /* reserve 2 bytes for RXDWA padding */ - skb_reserve(new_skb, 2); + skb_reserve(new_skb, NET_IP_ALIGN); current_rx_ptr->skb = new_skb; current_rx_ptr->desc_a.start_addr = (unsigned long)new_skb->data - 2; @@ -1022,7 +970,8 @@ static int __devinit bfin_mac_probe(struct platform_device *pdev) { struct net_device *ndev; struct bfin_mac_local *lp; - int rc, i; + struct platform_device *pd; + int rc; ndev = alloc_etherdev(sizeof(struct bfin_mac_local)); if (!ndev) { @@ -1047,13 +996,6 @@ static int __devinit bfin_mac_probe(struct platform_device *pdev) goto out_err_probe_mac; } - /* set the GPIO pins to Ethernet mode */ - rc = peripheral_request_list(pin_req, DRV_NAME); - if (rc) { - dev_err(&pdev->dev, "Requesting peripherals failed!\n"); - rc = -EFAULT; - goto out_err_setup_pin_mux; - } /* * Is it valid? (Did bootloader initialize it?) @@ -1069,26 +1011,14 @@ static int __devinit bfin_mac_probe(struct platform_device *pdev) setup_mac_addr(ndev->dev_addr); - /* MDIO bus initial */ - lp->mii_bus = mdiobus_alloc(); - if (lp->mii_bus == NULL) - goto out_err_mdiobus_alloc; - - lp->mii_bus->priv = ndev; - lp->mii_bus->read = bfin_mdiobus_read; - lp->mii_bus->write = bfin_mdiobus_write; - lp->mii_bus->reset = bfin_mdiobus_reset; - lp->mii_bus->name = "bfin_mac_mdio"; - snprintf(lp->mii_bus->id, MII_BUS_ID_SIZE, "0"); - lp->mii_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL); - for (i = 0; i < PHY_MAX_ADDR; ++i) - lp->mii_bus->irq[i] = PHY_POLL; - - rc = mdiobus_register(lp->mii_bus); - if (rc) { - dev_err(&pdev->dev, "Cannot register MDIO bus!\n"); - goto out_err_mdiobus_register; + if (!pdev->dev.platform_data) { + dev_err(&pdev->dev, "Cannot get platform device bfin_mii_bus!\n"); + rc = -ENODEV; + goto out_err_probe_mac; } + pd = pdev->dev.platform_data; + lp->mii_bus = platform_get_drvdata(pd); + lp->mii_bus->priv = ndev; rc = mii_probe(ndev); if (rc) { @@ -1107,7 +1037,7 @@ static int __devinit bfin_mac_probe(struct platform_device *pdev) /* now, enable interrupts */ /* register irq handler */ rc = request_irq(IRQ_MAC_RX, bfin_mac_interrupt, - IRQF_DISABLED | IRQF_SHARED, "EMAC_RX", ndev); + IRQF_DISABLED, "EMAC_RX", ndev); if (rc) { dev_err(&pdev->dev, "Cannot request Blackfin MAC RX IRQ!\n"); rc = -EBUSY; @@ -1130,11 +1060,8 @@ out_err_reg_ndev: out_err_request_irq: out_err_mii_probe: mdiobus_unregister(lp->mii_bus); -out_err_mdiobus_register: mdiobus_free(lp->mii_bus); -out_err_mdiobus_alloc: peripheral_free_list(pin_req); -out_err_setup_pin_mux: out_err_probe_mac: platform_set_drvdata(pdev, NULL); free_netdev(ndev); @@ -1149,8 +1076,7 @@ static int __devexit bfin_mac_remove(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); - mdiobus_unregister(lp->mii_bus); - mdiobus_free(lp->mii_bus); + lp->mii_bus->priv = NULL; unregister_netdev(ndev); @@ -1188,6 +1114,74 @@ static int bfin_mac_resume(struct platform_device *pdev) #define bfin_mac_resume NULL #endif /* CONFIG_PM */ +static int __devinit bfin_mii_bus_probe(struct platform_device *pdev) +{ + struct mii_bus *miibus; + int rc, i; + + /* + * We are setting up a network card, + * so set the GPIO pins to Ethernet mode + */ + rc = peripheral_request_list(pin_req, DRV_NAME); + if (rc) { + dev_err(&pdev->dev, "Requesting peripherals failed!\n"); + return rc; + } + + rc = -ENOMEM; + miibus = mdiobus_alloc(); + if (miibus == NULL) + goto out_err_alloc; + miibus->read = bfin_mdiobus_read; + miibus->write = bfin_mdiobus_write; + miibus->reset = bfin_mdiobus_reset; + + miibus->parent = &pdev->dev; + miibus->name = "bfin_mii_bus"; + snprintf(miibus->id, MII_BUS_ID_SIZE, "0"); + miibus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL); + if (miibus->irq == NULL) + goto out_err_alloc; + for (i = 0; i < PHY_MAX_ADDR; ++i) + miibus->irq[i] = PHY_POLL; + + rc = mdiobus_register(miibus); + if (rc) { + dev_err(&pdev->dev, "Cannot register MDIO bus!\n"); + goto out_err_mdiobus_register; + } + + platform_set_drvdata(pdev, miibus); + return 0; + +out_err_mdiobus_register: + mdiobus_free(miibus); +out_err_alloc: + peripheral_free_list(pin_req); + + return rc; +} + +static int __devexit bfin_mii_bus_remove(struct platform_device *pdev) +{ + struct mii_bus *miibus = platform_get_drvdata(pdev); + platform_set_drvdata(pdev, NULL); + mdiobus_unregister(miibus); + mdiobus_free(miibus); + peripheral_free_list(pin_req); + return 0; +} + +static struct platform_driver bfin_mii_bus_driver = { + .probe = bfin_mii_bus_probe, + .remove = __devexit_p(bfin_mii_bus_remove), + .driver = { + .name = "bfin_mii_bus", + .owner = THIS_MODULE, + }, +}; + static struct platform_driver bfin_mac_driver = { .probe = bfin_mac_probe, .remove = __devexit_p(bfin_mac_remove), @@ -1201,7 +1195,11 @@ static struct platform_driver bfin_mac_driver = { static int __init bfin_mac_init(void) { - return platform_driver_register(&bfin_mac_driver); + int ret; + ret = platform_driver_register(&bfin_mii_bus_driver); + if (!ret) + return platform_driver_register(&bfin_mac_driver); + return -ENODEV; } module_init(bfin_mac_init); @@ -1209,6 +1207,7 @@ module_init(bfin_mac_init); static void __exit bfin_mac_cleanup(void) { platform_driver_unregister(&bfin_mac_driver); + platform_driver_unregister(&bfin_mii_bus_driver); } module_exit(bfin_mac_cleanup); diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c index 44d015f70d1c..9578a3dfac01 100644 --- a/drivers/net/bmac.c +++ b/drivers/net/bmac.c @@ -1247,6 +1247,16 @@ static const struct ethtool_ops bmac_ethtool_ops = { .get_link = ethtool_op_get_link, }; +static const struct net_device_ops bmac_netdev_ops = { + .ndo_open = bmac_open, + .ndo_stop = bmac_close, + .ndo_start_xmit = bmac_output, + .ndo_set_multicast_list = bmac_set_multicast, + .ndo_set_mac_address = bmac_set_address, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, +}; + static int __devinit bmac_probe(struct macio_dev *mdev, const struct of_device_id *match) { int j, rev, ret; @@ -1308,12 +1318,8 @@ static int __devinit bmac_probe(struct macio_dev *mdev, const struct of_device_i bmac_enable_and_reset_chip(dev); bmwrite(dev, INTDISABLE, DisableAll); - dev->open = bmac_open; - dev->stop = bmac_close; + dev->netdev_ops = &bmac_netdev_ops; dev->ethtool_ops = &bmac_ethtool_ops; - dev->hard_start_xmit = bmac_output; - dev->set_multicast_list = bmac_set_multicast; - dev->set_mac_address = bmac_set_address; bmac_get_station_address(dev, addr); if (bmac_verify_checksum(dev) != 0) diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index b0cb29d4cc01..b70cc99962fc 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -48,7 +48,12 @@ #include #include #include +#include +#if defined(CONFIG_CNIC) || defined(CONFIG_CNIC_MODULE) +#define BCM_CNIC 1 +#include "cnic_if.h" +#endif #include "bnx2.h" #include "bnx2_fw.h" @@ -315,6 +320,158 @@ bnx2_ctx_wr(struct bnx2 *bp, u32 cid_addr, u32 offset, u32 val) spin_unlock_bh(&bp->indirect_lock); } +#ifdef BCM_CNIC +static int +bnx2_drv_ctl(struct net_device *dev, struct drv_ctl_info *info) +{ + struct bnx2 *bp = netdev_priv(dev); + struct drv_ctl_io *io = &info->data.io; + + switch (info->cmd) { + case DRV_CTL_IO_WR_CMD: + bnx2_reg_wr_ind(bp, io->offset, io->data); + break; + case DRV_CTL_IO_RD_CMD: + io->data = bnx2_reg_rd_ind(bp, io->offset); + break; + case DRV_CTL_CTX_WR_CMD: + bnx2_ctx_wr(bp, io->cid_addr, io->offset, io->data); + break; + default: + return -EINVAL; + } + return 0; +} + +static void bnx2_setup_cnic_irq_info(struct bnx2 *bp) +{ + struct cnic_eth_dev *cp = &bp->cnic_eth_dev; + struct bnx2_napi *bnapi = &bp->bnx2_napi[0]; + int sb_id; + + if (bp->flags & BNX2_FLAG_USING_MSIX) { + cp->drv_state |= CNIC_DRV_STATE_USING_MSIX; + bnapi->cnic_present = 0; + sb_id = bp->irq_nvecs; + cp->irq_arr[0].irq_flags |= CNIC_IRQ_FL_MSIX; + } else { + cp->drv_state &= ~CNIC_DRV_STATE_USING_MSIX; + bnapi->cnic_tag = bnapi->last_status_idx; + bnapi->cnic_present = 1; + sb_id = 0; + cp->irq_arr[0].irq_flags &= ~CNIC_IRQ_FL_MSIX; + } + + cp->irq_arr[0].vector = bp->irq_tbl[sb_id].vector; + cp->irq_arr[0].status_blk = (void *) + ((unsigned long) bnapi->status_blk.msi + + (BNX2_SBLK_MSIX_ALIGN_SIZE * sb_id)); + cp->irq_arr[0].status_blk_num = sb_id; + cp->num_irq = 1; +} + +static int bnx2_register_cnic(struct net_device *dev, struct cnic_ops *ops, + void *data) +{ + struct bnx2 *bp = netdev_priv(dev); + struct cnic_eth_dev *cp = &bp->cnic_eth_dev; + + if (ops == NULL) + return -EINVAL; + + if (cp->drv_state & CNIC_DRV_STATE_REGD) + return -EBUSY; + + bp->cnic_data = data; + rcu_assign_pointer(bp->cnic_ops, ops); + + cp->num_irq = 0; + cp->drv_state = CNIC_DRV_STATE_REGD; + + bnx2_setup_cnic_irq_info(bp); + + return 0; +} + +static int bnx2_unregister_cnic(struct net_device *dev) +{ + struct bnx2 *bp = netdev_priv(dev); + struct bnx2_napi *bnapi = &bp->bnx2_napi[0]; + struct cnic_eth_dev *cp = &bp->cnic_eth_dev; + + cp->drv_state = 0; + bnapi->cnic_present = 0; + rcu_assign_pointer(bp->cnic_ops, NULL); + synchronize_rcu(); + return 0; +} + +struct cnic_eth_dev *bnx2_cnic_probe(struct net_device *dev) +{ + struct bnx2 *bp = netdev_priv(dev); + struct cnic_eth_dev *cp = &bp->cnic_eth_dev; + + cp->drv_owner = THIS_MODULE; + cp->chip_id = bp->chip_id; + cp->pdev = bp->pdev; + cp->io_base = bp->regview; + cp->drv_ctl = bnx2_drv_ctl; + cp->drv_register_cnic = bnx2_register_cnic; + cp->drv_unregister_cnic = bnx2_unregister_cnic; + + return cp; +} +EXPORT_SYMBOL(bnx2_cnic_probe); + +static void +bnx2_cnic_stop(struct bnx2 *bp) +{ + struct cnic_ops *c_ops; + struct cnic_ctl_info info; + + rcu_read_lock(); + c_ops = rcu_dereference(bp->cnic_ops); + if (c_ops) { + info.cmd = CNIC_CTL_STOP_CMD; + c_ops->cnic_ctl(bp->cnic_data, &info); + } + rcu_read_unlock(); +} + +static void +bnx2_cnic_start(struct bnx2 *bp) +{ + struct cnic_ops *c_ops; + struct cnic_ctl_info info; + + rcu_read_lock(); + c_ops = rcu_dereference(bp->cnic_ops); + if (c_ops) { + if (!(bp->flags & BNX2_FLAG_USING_MSIX)) { + struct bnx2_napi *bnapi = &bp->bnx2_napi[0]; + + bnapi->cnic_tag = bnapi->last_status_idx; + } + info.cmd = CNIC_CTL_START_CMD; + c_ops->cnic_ctl(bp->cnic_data, &info); + } + rcu_read_unlock(); +} + +#else + +static void +bnx2_cnic_stop(struct bnx2 *bp) +{ +} + +static void +bnx2_cnic_start(struct bnx2 *bp) +{ +} + +#endif + static int bnx2_read_phy(struct bnx2 *bp, u32 reg, u32 *val) { @@ -488,6 +645,7 @@ bnx2_napi_enable(struct bnx2 *bp) static void bnx2_netif_stop(struct bnx2 *bp) { + bnx2_cnic_stop(bp); bnx2_disable_int_sync(bp); if (netif_running(bp->dev)) { bnx2_napi_disable(bp); @@ -504,6 +662,7 @@ bnx2_netif_start(struct bnx2 *bp) netif_tx_wake_all_queues(bp->dev); bnx2_napi_enable(bp); bnx2_enable_int(bp); + bnx2_cnic_start(bp); } } } @@ -545,8 +704,7 @@ bnx2_free_rx_mem(struct bnx2 *bp) rxr->rx_desc_mapping[j]); rxr->rx_desc_ring[j] = NULL; } - if (rxr->rx_buf_ring) - vfree(rxr->rx_buf_ring); + vfree(rxr->rx_buf_ring); rxr->rx_buf_ring = NULL; for (j = 0; j < bp->rx_max_pg_ring; j++) { @@ -556,8 +714,7 @@ bnx2_free_rx_mem(struct bnx2 *bp) rxr->rx_pg_desc_mapping[j]); rxr->rx_pg_desc_ring[j] = NULL; } - if (rxr->rx_pg_ring) - vfree(rxr->rx_pg_ring); + vfree(rxr->rx_pg_ring); rxr->rx_pg_ring = NULL; } } @@ -2630,14 +2787,15 @@ bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget) tx_buf = &txr->tx_buf_ring[sw_ring_cons]; skb = tx_buf->skb; + /* prefetch skb_end_pointer() to speedup skb_shinfo(skb) */ + prefetch(&skb->end); + /* partial BD completions possible with TSO packets */ - if (skb_is_gso(skb)) { + if (tx_buf->is_gso) { u16 last_idx, last_ring_idx; - last_idx = sw_cons + - skb_shinfo(skb)->nr_frags + 1; - last_ring_idx = sw_ring_cons + - skb_shinfo(skb)->nr_frags + 1; + last_idx = sw_cons + tx_buf->nr_frags + 1; + last_ring_idx = sw_ring_cons + tx_buf->nr_frags + 1; if (unlikely(last_ring_idx >= MAX_TX_DESC_CNT)) { last_idx++; } @@ -2649,7 +2807,7 @@ bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget) skb_dma_unmap(&bp->pdev->dev, skb, DMA_TO_DEVICE); tx_buf->skb = NULL; - last = skb_shinfo(skb)->nr_frags; + last = tx_buf->nr_frags; for (i = 0; i < last; i++) { sw_cons = NEXT_TX_BD(sw_cons); @@ -2662,7 +2820,8 @@ bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget) if (tx_pkt == budget) break; - hw_cons = bnx2_get_hw_tx_cons(bnapi); + if (hw_cons == sw_cons) + hw_cons = bnx2_get_hw_tx_cons(bnapi); } txr->hw_tx_cons = hw_cons; @@ -3164,6 +3323,11 @@ bnx2_has_work(struct bnx2_napi *bnapi) if (bnx2_has_fast_work(bnapi)) return 1; +#ifdef BCM_CNIC + if (bnapi->cnic_present && (bnapi->cnic_tag != sblk->status_idx)) + return 1; +#endif + if ((sblk->status_attn_bits & STATUS_ATTN_EVENTS) != (sblk->status_attn_bits_ack & STATUS_ATTN_EVENTS)) return 1; @@ -3193,6 +3357,23 @@ bnx2_chk_missed_msi(struct bnx2 *bp) bp->idle_chk_status_idx = bnapi->last_status_idx; } +#ifdef BCM_CNIC +static void bnx2_poll_cnic(struct bnx2 *bp, struct bnx2_napi *bnapi) +{ + struct cnic_ops *c_ops; + + if (!bnapi->cnic_present) + return; + + rcu_read_lock(); + c_ops = rcu_dereference(bp->cnic_ops); + if (c_ops) + bnapi->cnic_tag = c_ops->cnic_handler(bp->cnic_data, + bnapi->status_blk.msi); + rcu_read_unlock(); +} +#endif + static void bnx2_poll_link(struct bnx2 *bp, struct bnx2_napi *bnapi) { struct status_block *sblk = bnapi->status_blk.msi; @@ -3267,6 +3448,10 @@ static int bnx2_poll(struct napi_struct *napi, int budget) work_done = bnx2_poll_work(bp, bnapi, work_done, budget); +#ifdef BCM_CNIC + bnx2_poll_cnic(bp, bnapi); +#endif + /* bnapi->last_status_idx is used below to tell the hw how * much work has been processed, so we must read it before * checking for more work. @@ -3308,7 +3493,7 @@ bnx2_set_rx_mode(struct net_device *dev) { struct bnx2 *bp = netdev_priv(dev); u32 rx_mode, sort_mode; - struct dev_addr_list *uc_ptr; + struct netdev_hw_addr *ha; int i; if (!netif_running(dev)) @@ -3367,21 +3552,19 @@ bnx2_set_rx_mode(struct net_device *dev) sort_mode |= BNX2_RPM_SORT_USER0_MC_HSH_EN; } - uc_ptr = NULL; - if (dev->uc_count > BNX2_MAX_UNICAST_ADDRESSES) { + if (dev->uc.count > BNX2_MAX_UNICAST_ADDRESSES) { rx_mode |= BNX2_EMAC_RX_MODE_PROMISCUOUS; sort_mode |= BNX2_RPM_SORT_USER0_PROM_EN | BNX2_RPM_SORT_USER0_PROM_VLAN; } else if (!(dev->flags & IFF_PROMISC)) { - uc_ptr = dev->uc_list; - /* Add all entries into to the match filter list */ - for (i = 0; i < dev->uc_count; i++) { - bnx2_set_mac_addr(bp, uc_ptr->da_addr, + i = 0; + list_for_each_entry(ha, &dev->uc.list, list) { + bnx2_set_mac_addr(bp, ha->addr, i + BNX2_START_UNICAST_ADDRESS_INDEX); sort_mode |= (1 << (i + BNX2_START_UNICAST_ADDRESS_INDEX)); - uc_ptr = uc_ptr->next; + i++; } } @@ -4632,8 +4815,11 @@ bnx2_init_chip(struct bnx2 *bp) val = REG_RD(bp, BNX2_MQ_CONFIG); val &= ~BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE; val |= BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE_256; - if (CHIP_ID(bp) == CHIP_ID_5709_A0 || CHIP_ID(bp) == CHIP_ID_5709_A1) - val |= BNX2_MQ_CONFIG_HALT_DIS; + if (CHIP_NUM(bp) == CHIP_NUM_5709) { + val |= BNX2_MQ_CONFIG_BIN_MQ_MODE; + if (CHIP_REV(bp) == CHIP_REV_Ax) + val |= BNX2_MQ_CONFIG_HALT_DIS; + } REG_WR(bp, BNX2_MQ_CONFIG, val); @@ -5486,7 +5672,7 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode) dev_kfree_skb(skb); return -EIO; } - map = skb_shinfo(skb)->dma_maps[0]; + map = skb_shinfo(skb)->dma_head; REG_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT); @@ -6166,7 +6352,7 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev) } sp = skb_shinfo(skb); - mapping = sp->dma_maps[0]; + mapping = sp->dma_head; tx_buf = &txr->tx_buf_ring[ring_prod]; tx_buf->skb = skb; @@ -6179,6 +6365,8 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev) txbd->tx_bd_vlan_tag_flags = vlan_tag_flags | TX_BD_FLAGS_START; last_frag = skb_shinfo(skb)->nr_frags; + tx_buf->nr_frags = last_frag; + tx_buf->is_gso = skb_is_gso(skb); for (i = 0; i < last_frag; i++) { skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; @@ -6188,7 +6376,7 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev) txbd = &txr->tx_desc_ring[ring_prod]; len = frag->size; - mapping = sp->dma_maps[i + 1]; + mapping = sp->dma_maps[i]; txbd->tx_bd_haddr_hi = (u64) mapping >> 32; txbd->tx_bd_haddr_lo = (u64) mapping & 0xffffffff; @@ -6207,7 +6395,6 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev) mmiowb(); txr->tx_prod = prod; - dev->trans_start = jiffies; if (unlikely(bnx2_tx_avail(bp, txr) <= MAX_SKB_FRAGS)) { netif_tx_stop_queue(txq); @@ -6638,6 +6825,14 @@ bnx2_nway_reset(struct net_device *dev) return 0; } +static u32 +bnx2_get_link(struct net_device *dev) +{ + struct bnx2 *bp = netdev_priv(dev); + + return bp->link_up; +} + static int bnx2_get_eeprom_len(struct net_device *dev) { @@ -7205,7 +7400,7 @@ static const struct ethtool_ops bnx2_ethtool_ops = { .get_wol = bnx2_get_wol, .set_wol = bnx2_set_wol, .nway_reset = bnx2_nway_reset, - .get_link = ethtool_op_get_link, + .get_link = bnx2_get_link, .get_eeprom_len = bnx2_get_eeprom_len, .get_eeprom = bnx2_get_eeprom, .set_eeprom = bnx2_set_eeprom, @@ -7471,7 +7666,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 + TX_MAX_TSS_RINGS); + mem_len = MB_GET_CID_ADDR(TX_TSS_CID + TX_MAX_TSS_RINGS + 1); dev->mem_end = dev->mem_start + mem_len; dev->irq = pdev->irq; diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h index 5b570e17c839..f1edfaa9e56a 100644 --- a/drivers/net/bnx2.h +++ b/drivers/net/bnx2.h @@ -361,6 +361,9 @@ struct l2_fhdr { #define BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE_VALUE (1<<28) #define BNX2_L2CTX_HOST_BDIDX 0x00000004 +#define BNX2_L2CTX_STATUSB_NUM_SHIFT 16 +#define BNX2_L2CTX_STATUSB_NUM(sb_id) \ + (((sb_id) > 0) ? (((sb_id) + 7) << BNX2_L2CTX_STATUSB_NUM_SHIFT) : 0) #define BNX2_L2CTX_HOST_BSEQ 0x00000008 #define BNX2_L2CTX_NX_BSEQ 0x0000000c #define BNX2_L2CTX_NX_BDHADDR_HI 0x00000010 @@ -5900,6 +5903,7 @@ struct l2_fhdr { #define BNX2_RXP_FTQ_CTL_CUR_DEPTH (0x3ffL<<22) #define BNX2_RXP_SCRATCH 0x000e0000 +#define BNX2_RXP_SCRATCH_RXP_FLOOD 0x000e0024 #define BNX2_RXP_SCRATCH_RSS_TBL_SZ 0x000e0038 #define BNX2_RXP_SCRATCH_RSS_TBL 0x000e003c #define BNX2_RXP_SCRATCH_RSS_TBL_MAX_ENTRIES 128 @@ -6552,6 +6556,8 @@ struct sw_pg { struct sw_tx_bd { struct sk_buff *skb; + unsigned short is_gso; + unsigned short nr_frags; }; #define SW_RXBD_RING_SIZE (sizeof(struct sw_bd) * RX_DESC_CNT) @@ -6678,6 +6684,11 @@ struct bnx2_napi { u32 last_status_idx; u32 int_num; +#ifdef BCM_CNIC + u32 cnic_tag; + int cnic_present; +#endif + struct bnx2_rx_ring_info rx_ring; struct bnx2_tx_ring_info tx_ring; }; @@ -6727,6 +6738,11 @@ struct bnx2 { int tx_ring_size; u32 tx_wake_thresh; +#ifdef BCM_CNIC + struct cnic_ops *cnic_ops; + void *cnic_data; +#endif + /* End of fields used in the performance code paths. */ unsigned int current_interval; @@ -6885,6 +6901,10 @@ struct bnx2 { u32 idle_chk_status_idx; +#ifdef BCM_CNIC + struct cnic_eth_dev cnic_eth_dev; +#endif + const struct firmware *mips_firmware; const struct firmware *rv2p_firmware; }; diff --git a/drivers/net/bnx2x.h b/drivers/net/bnx2x.h index a329bee25550..8678457849f9 100644 --- a/drivers/net/bnx2x.h +++ b/drivers/net/bnx2x.h @@ -965,6 +965,21 @@ struct bnx2x { int gunzip_outlen; #define FW_BUF_SIZE 0x8000 + struct raw_op *init_ops; + /* Init blocks offsets inside init_ops */ + u16 *init_ops_offsets; + /* Data blob - has 32 bit granularity */ + u32 *init_data; + /* Zipped PRAM blobs - raw data */ + const u8 *tsem_int_table_data; + const u8 *tsem_pram_data; + const u8 *usem_int_table_data; + const u8 *usem_pram_data; + const u8 *xsem_int_table_data; + const u8 *xsem_pram_data; + const u8 *csem_int_table_data; + const u8 *csem_pram_data; + const struct firmware *firmware; }; diff --git a/drivers/net/bnx2x_fw_file_hdr.h b/drivers/net/bnx2x_fw_file_hdr.h new file mode 100644 index 000000000000..3f5ee5d7cc2a --- /dev/null +++ b/drivers/net/bnx2x_fw_file_hdr.h @@ -0,0 +1,37 @@ +/* bnx2x_fw_file_hdr.h: FW binary file header structure. + * + * Copyright (c) 2007-2009 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation. + * + * Maintained by: Eilon Greenstein + * Written by: Vladislav Zolotarov + * Based on the original idea of John Wright . + */ + +#ifndef BNX2X_INIT_FILE_HDR_H +#define BNX2X_INIT_FILE_HDR_H + +struct bnx2x_fw_file_section { + __be32 len; + __be32 offset; +}; + +struct bnx2x_fw_file_hdr { + struct bnx2x_fw_file_section init_ops; + struct bnx2x_fw_file_section init_ops_offsets; + struct bnx2x_fw_file_section init_data; + struct bnx2x_fw_file_section tsem_int_table_data; + struct bnx2x_fw_file_section tsem_pram_data; + struct bnx2x_fw_file_section usem_int_table_data; + struct bnx2x_fw_file_section usem_pram_data; + struct bnx2x_fw_file_section csem_int_table_data; + struct bnx2x_fw_file_section csem_pram_data; + struct bnx2x_fw_file_section xsem_int_table_data; + struct bnx2x_fw_file_section xsem_pram_data; + struct bnx2x_fw_file_section fw_version; +}; + +#endif /* BNX2X_INIT_FILE_HDR_H */ diff --git a/drivers/net/bnx2x_init.h b/drivers/net/bnx2x_init.h index 39ba2936c0c2..3ba4d888068f 100644 --- a/drivers/net/bnx2x_init.h +++ b/drivers/net/bnx2x_init.h @@ -1,4 +1,5 @@ /* bnx2x_init.h: Broadcom Everest network driver. + * Structures and macroes needed during the initialization. * * Copyright (c) 2007-2009 Broadcom Corporation * @@ -8,6 +9,7 @@ * * Maintained by: Eilon Greenstein * Written by: Eliezer Tamir + * Modified by: Vladislav Zolotarov */ #ifndef BNX2X_INIT_H @@ -45,33 +47,71 @@ #define OP_WR_64 0x8 /* write 64 bit pattern */ #define OP_WB 0x9 /* copy a string using DMAE */ -/* Operation specific for E1 */ -#define OP_RD_E1 0xa /* read single register */ -#define OP_WR_E1 0xb /* write single register */ -#define OP_IW_E1 0xc /* write single register using mailbox */ -#define OP_SW_E1 0xd /* copy a string to the device */ -#define OP_SI_E1 0xe /* copy a string using mailbox */ -#define OP_ZR_E1 0xf /* clear memory */ -#define OP_ZP_E1 0x10 /* unzip then copy with DMAE */ -#define OP_WR_64_E1 0x11 /* write 64 bit pattern on E1 */ -#define OP_WB_E1 0x12 /* copy a string using DMAE */ - -/* Operation specific for E1H */ -#define OP_RD_E1H 0x13 /* read single register */ -#define OP_WR_E1H 0x14 /* write single register */ -#define OP_IW_E1H 0x15 /* write single register using mailbox */ -#define OP_SW_E1H 0x16 /* copy a string to the device */ -#define OP_SI_E1H 0x17 /* copy a string using mailbox */ -#define OP_ZR_E1H 0x18 /* clear memory */ -#define OP_ZP_E1H 0x19 /* unzip then copy with DMAE */ -#define OP_WR_64_E1H 0x1a /* write 64 bit pattern on E1H */ -#define OP_WB_E1H 0x1b /* copy a string using DMAE */ - /* FPGA and EMUL specific operations */ -#define OP_WR_EMUL_E1H 0x1c /* write single register on E1H Emul */ -#define OP_WR_EMUL 0x1d /* write single register on Emulation */ -#define OP_WR_FPGA 0x1e /* write single register on FPGA */ -#define OP_WR_ASIC 0x1f /* write single register on ASIC */ +#define OP_WR_EMUL 0xa /* write single register on Emulation */ +#define OP_WR_FPGA 0xb /* write single register on FPGA */ +#define OP_WR_ASIC 0xc /* write single register on ASIC */ + +/* Init stages */ +#define COMMON_STAGE 0 +#define PORT0_STAGE 1 +#define PORT1_STAGE 2 +/* Never reorder FUNCx stages !!! */ +#define FUNC0_STAGE 3 +#define FUNC1_STAGE 4 +#define FUNC2_STAGE 5 +#define FUNC3_STAGE 6 +#define FUNC4_STAGE 7 +#define FUNC5_STAGE 8 +#define FUNC6_STAGE 9 +#define FUNC7_STAGE 10 +#define STAGE_IDX_MAX 11 + +#define STAGE_START 0 +#define STAGE_END 1 + + +/* Indices of blocks */ +#define PRS_BLOCK 0 +#define SRCH_BLOCK 1 +#define TSDM_BLOCK 2 +#define TCM_BLOCK 3 +#define BRB1_BLOCK 4 +#define TSEM_BLOCK 5 +#define PXPCS_BLOCK 6 +#define EMAC0_BLOCK 7 +#define EMAC1_BLOCK 8 +#define DBU_BLOCK 9 +#define MISC_BLOCK 10 +#define DBG_BLOCK 11 +#define NIG_BLOCK 12 +#define MCP_BLOCK 13 +#define UPB_BLOCK 14 +#define CSDM_BLOCK 15 +#define USDM_BLOCK 16 +#define CCM_BLOCK 17 +#define UCM_BLOCK 18 +#define USEM_BLOCK 19 +#define CSEM_BLOCK 20 +#define XPB_BLOCK 21 +#define DQ_BLOCK 22 +#define TIMERS_BLOCK 23 +#define XSDM_BLOCK 24 +#define QM_BLOCK 25 +#define PBF_BLOCK 26 +#define XCM_BLOCK 27 +#define XSEM_BLOCK 28 +#define CDU_BLOCK 29 +#define DMAE_BLOCK 30 +#define PXP_BLOCK 31 +#define CFC_BLOCK 32 +#define HC_BLOCK 33 +#define PXP2_BLOCK 34 +#define MISC_AEU_BLOCK 35 + +/* Returns the index of start or end of a specific block stage in ops array*/ +#define BLOCK_OPS_IDX(block, stage, end) \ + (2*(((block)*STAGE_IDX_MAX) + (stage)) + (end)) struct raw_op { @@ -118,292 +158,6 @@ union init_op { struct raw_op raw; }; -#include "bnx2x_init_values.h" - -static void bnx2x_reg_wr_ind(struct bnx2x *bp, u32 addr, u32 val); -static int bnx2x_gunzip(struct bnx2x *bp, u8 *zbuf, int len); - -static void bnx2x_init_str_wr(struct bnx2x *bp, u32 addr, const u32 *data, - u32 len) -{ - int i; - - for (i = 0; i < len; i++) { - REG_WR(bp, addr + i*4, data[i]); - if (!(i % 10000)) { - touch_softlockup_watchdog(); - cpu_relax(); - } - } -} - -static void bnx2x_init_ind_wr(struct bnx2x *bp, u32 addr, const u32 *data, - u16 len) -{ - int i; - - for (i = 0; i < len; i++) { - REG_WR_IND(bp, addr + i*4, data[i]); - if (!(i % 10000)) { - touch_softlockup_watchdog(); - cpu_relax(); - } - } -} - -static void bnx2x_write_big_buf(struct bnx2x *bp, u32 addr, u32 len) -{ - int offset = 0; - - if (bp->dmae_ready) { - while (len > DMAE_LEN32_WR_MAX) { - bnx2x_write_dmae(bp, bp->gunzip_mapping + offset, - addr + offset, DMAE_LEN32_WR_MAX); - offset += DMAE_LEN32_WR_MAX * 4; - len -= DMAE_LEN32_WR_MAX; - } - bnx2x_write_dmae(bp, bp->gunzip_mapping + offset, - addr + offset, len); - } else - bnx2x_init_str_wr(bp, addr, bp->gunzip_buf, len); -} - -static void bnx2x_init_fill(struct bnx2x *bp, u32 addr, int fill, u32 len) -{ - u32 buf_len = (((len * 4) > FW_BUF_SIZE) ? FW_BUF_SIZE : (len * 4)); - u32 buf_len32 = buf_len / 4; - int i; - - memset(bp->gunzip_buf, fill, buf_len); - - for (i = 0; i < len; i += buf_len32) { - u32 cur_len = min(buf_len32, len - i); - - bnx2x_write_big_buf(bp, addr + i * 4, cur_len); - } -} - -static void bnx2x_init_wr_64(struct bnx2x *bp, u32 addr, const u32 *data, - u32 len64) -{ - u32 buf_len32 = FW_BUF_SIZE / 4; - u32 len = len64 * 2; - u64 data64 = 0; - int i; - - /* 64 bit value is in a blob: first low DWORD, then high DWORD */ - data64 = HILO_U64((*(data + 1)), (*data)); - len64 = min((u32)(FW_BUF_SIZE/8), len64); - for (i = 0; i < len64; i++) { - u64 *pdata = ((u64 *)(bp->gunzip_buf)) + i; - - *pdata = data64; - } - - for (i = 0; i < len; i += buf_len32) { - u32 cur_len = min(buf_len32, len - i); - - bnx2x_write_big_buf(bp, addr + i * 4, cur_len); - } -} - -/********************************************************* - There are different blobs for each PRAM section. - In addition, each blob write operation is divided into a few operations - in order to decrease the amount of phys. contiguous buffer needed. - Thus, when we select a blob the address may be with some offset - from the beginning of PRAM section. - The same holds for the INT_TABLE sections. -**********************************************************/ -#define IF_IS_INT_TABLE_ADDR(base, addr) \ - if (((base) <= (addr)) && ((base) + 0x400 >= (addr))) - -#define IF_IS_PRAM_ADDR(base, addr) \ - if (((base) <= (addr)) && ((base) + 0x40000 >= (addr))) - -static const u32 *bnx2x_sel_blob(u32 addr, const u32 *data, int is_e1) -{ - IF_IS_INT_TABLE_ADDR(TSEM_REG_INT_TABLE, addr) - data = is_e1 ? tsem_int_table_data_e1 : - tsem_int_table_data_e1h; - else - IF_IS_INT_TABLE_ADDR(CSEM_REG_INT_TABLE, addr) - data = is_e1 ? csem_int_table_data_e1 : - csem_int_table_data_e1h; - else - IF_IS_INT_TABLE_ADDR(USEM_REG_INT_TABLE, addr) - data = is_e1 ? usem_int_table_data_e1 : - usem_int_table_data_e1h; - else - IF_IS_INT_TABLE_ADDR(XSEM_REG_INT_TABLE, addr) - data = is_e1 ? xsem_int_table_data_e1 : - xsem_int_table_data_e1h; - else - IF_IS_PRAM_ADDR(TSEM_REG_PRAM, addr) - data = is_e1 ? tsem_pram_data_e1 : tsem_pram_data_e1h; - else - IF_IS_PRAM_ADDR(CSEM_REG_PRAM, addr) - data = is_e1 ? csem_pram_data_e1 : csem_pram_data_e1h; - else - IF_IS_PRAM_ADDR(USEM_REG_PRAM, addr) - data = is_e1 ? usem_pram_data_e1 : usem_pram_data_e1h; - else - IF_IS_PRAM_ADDR(XSEM_REG_PRAM, addr) - data = is_e1 ? xsem_pram_data_e1 : xsem_pram_data_e1h; - - return data; -} - -static void bnx2x_init_wr_wb(struct bnx2x *bp, u32 addr, const u32 *data, - u32 len, int gunzip, int is_e1, u32 blob_off) -{ - int offset = 0; - - data = bnx2x_sel_blob(addr, data, is_e1) + blob_off; - - if (gunzip) { - int rc; -#ifdef __BIG_ENDIAN - int i, size; - u32 *temp; - - temp = kmalloc(len, GFP_KERNEL); - size = (len / 4) + ((len % 4) ? 1 : 0); - for (i = 0; i < size; i++) - temp[i] = swab32(data[i]); - data = temp; -#endif - rc = bnx2x_gunzip(bp, (u8 *)data, len); - if (rc) { - BNX2X_ERR("gunzip failed ! rc %d\n", rc); -#ifdef __BIG_ENDIAN - kfree(temp); -#endif - return; - } - len = bp->gunzip_outlen; -#ifdef __BIG_ENDIAN - kfree(temp); - for (i = 0; i < len; i++) - ((u32 *)bp->gunzip_buf)[i] = - swab32(((u32 *)bp->gunzip_buf)[i]); -#endif - } else { - if ((len * 4) > FW_BUF_SIZE) { - BNX2X_ERR("LARGE DMAE OPERATION ! " - "addr 0x%x len 0x%x\n", addr, len*4); - return; - } - memcpy(bp->gunzip_buf, data, len * 4); - } - - if (bp->dmae_ready) { - while (len > DMAE_LEN32_WR_MAX) { - bnx2x_write_dmae(bp, bp->gunzip_mapping + offset, - addr + offset, DMAE_LEN32_WR_MAX); - offset += DMAE_LEN32_WR_MAX * 4; - len -= DMAE_LEN32_WR_MAX; - } - bnx2x_write_dmae(bp, bp->gunzip_mapping + offset, - addr + offset, len); - } else - bnx2x_init_ind_wr(bp, addr, bp->gunzip_buf, len); -} - -static void bnx2x_init_block(struct bnx2x *bp, u32 op_start, u32 op_end) -{ - int is_e1 = CHIP_IS_E1(bp); - int is_e1h = CHIP_IS_E1H(bp); - int is_emul_e1h = (CHIP_REV_IS_EMUL(bp) && is_e1h); - int hw_wr, i; - union init_op *op; - u32 op_type, addr, len; - const u32 *data, *data_base; - - if (CHIP_REV_IS_FPGA(bp)) - hw_wr = OP_WR_FPGA; - else if (CHIP_REV_IS_EMUL(bp)) - hw_wr = OP_WR_EMUL; - else - hw_wr = OP_WR_ASIC; - - if (is_e1) - data_base = init_data_e1; - else /* CHIP_IS_E1H(bp) */ - data_base = init_data_e1h; - - for (i = op_start; i < op_end; i++) { - - op = (union init_op *)&(init_ops[i]); - - op_type = op->str_wr.op; - addr = op->str_wr.offset; - len = op->str_wr.data_len; - data = data_base + op->str_wr.data_off; - - /* careful! it must be in order */ - if (unlikely(op_type > OP_WB)) { - - /* If E1 only */ - if (op_type <= OP_WB_E1) { - if (is_e1) - op_type -= (OP_RD_E1 - OP_RD); - - /* If E1H only */ - } else if (op_type <= OP_WB_E1H) { - if (is_e1h) - op_type -= (OP_RD_E1H - OP_RD); - } - - /* HW/EMUL specific */ - if (op_type == hw_wr) - op_type = OP_WR; - - /* EMUL on E1H is special */ - if ((op_type == OP_WR_EMUL_E1H) && is_emul_e1h) - op_type = OP_WR; - } - - switch (op_type) { - case OP_RD: - REG_RD(bp, addr); - break; - case OP_WR: - REG_WR(bp, addr, op->write.val); - break; - case OP_SW: - bnx2x_init_str_wr(bp, addr, data, len); - break; - case OP_WB: - bnx2x_init_wr_wb(bp, addr, data, len, 0, is_e1, 0); - break; - case OP_SI: - bnx2x_init_ind_wr(bp, addr, data, len); - break; - case OP_ZR: - bnx2x_init_fill(bp, addr, 0, op->zero.len); - break; - case OP_ZP: - bnx2x_init_wr_wb(bp, addr, data, len, 1, is_e1, - op->str_wr.data_off); - break; - case OP_WR_64: - bnx2x_init_wr_64(bp, addr, data, len); - break; - default: - /* happens whenever an op is of a diff HW */ -#if 0 - DP(NETIF_MSG_HW, "skipping init operation " - "index %d[%d:%d]: type %d addr 0x%x " - "len %d(0x%x)\n", - i, op_start, op_end, op_type, addr, len, len); -#endif - break; - } - } -} - - /**************************************************************************** * PXP ****************************************************************************/ @@ -567,111 +321,6 @@ static const struct arb_line write_arb_addr[NUM_WR_Q-1] = { PXP2_REG_RQ_BW_WR_UBOUND30} }; -static void bnx2x_init_pxp(struct bnx2x *bp) -{ - u16 devctl; - int r_order, w_order; - u32 val, i; - - pci_read_config_word(bp->pdev, - bp->pcie_cap + PCI_EXP_DEVCTL, &devctl); - DP(NETIF_MSG_HW, "read 0x%x from devctl\n", devctl); - w_order = ((devctl & PCI_EXP_DEVCTL_PAYLOAD) >> 5); - if (bp->mrrs == -1) - r_order = ((devctl & PCI_EXP_DEVCTL_READRQ) >> 12); - else { - DP(NETIF_MSG_HW, "force read order to %d\n", bp->mrrs); - r_order = bp->mrrs; - } - - if (r_order > MAX_RD_ORD) { - DP(NETIF_MSG_HW, "read order of %d order adjusted to %d\n", - r_order, MAX_RD_ORD); - r_order = MAX_RD_ORD; - } - if (w_order > MAX_WR_ORD) { - DP(NETIF_MSG_HW, "write order of %d order adjusted to %d\n", - w_order, MAX_WR_ORD); - w_order = MAX_WR_ORD; - } - if (CHIP_REV_IS_FPGA(bp)) { - DP(NETIF_MSG_HW, "write order adjusted to 1 for FPGA\n"); - w_order = 0; - } - DP(NETIF_MSG_HW, "read order %d write order %d\n", r_order, w_order); - - for (i = 0; i < NUM_RD_Q-1; i++) { - REG_WR(bp, read_arb_addr[i].l, read_arb_data[i][r_order].l); - REG_WR(bp, read_arb_addr[i].add, - read_arb_data[i][r_order].add); - REG_WR(bp, read_arb_addr[i].ubound, - read_arb_data[i][r_order].ubound); - } - - for (i = 0; i < NUM_WR_Q-1; i++) { - if ((write_arb_addr[i].l == PXP2_REG_RQ_BW_WR_L29) || - (write_arb_addr[i].l == PXP2_REG_RQ_BW_WR_L30)) { - - REG_WR(bp, write_arb_addr[i].l, - write_arb_data[i][w_order].l); - - REG_WR(bp, write_arb_addr[i].add, - write_arb_data[i][w_order].add); - - REG_WR(bp, write_arb_addr[i].ubound, - write_arb_data[i][w_order].ubound); - } else { - - val = REG_RD(bp, write_arb_addr[i].l); - REG_WR(bp, write_arb_addr[i].l, - val | (write_arb_data[i][w_order].l << 10)); - - val = REG_RD(bp, write_arb_addr[i].add); - REG_WR(bp, write_arb_addr[i].add, - val | (write_arb_data[i][w_order].add << 10)); - - val = REG_RD(bp, write_arb_addr[i].ubound); - REG_WR(bp, write_arb_addr[i].ubound, - val | (write_arb_data[i][w_order].ubound << 7)); - } - } - - val = write_arb_data[NUM_WR_Q-1][w_order].add; - val += write_arb_data[NUM_WR_Q-1][w_order].ubound << 10; - val += write_arb_data[NUM_WR_Q-1][w_order].l << 17; - REG_WR(bp, PXP2_REG_PSWRQ_BW_RD, val); - - val = read_arb_data[NUM_RD_Q-1][r_order].add; - val += read_arb_data[NUM_RD_Q-1][r_order].ubound << 10; - val += read_arb_data[NUM_RD_Q-1][r_order].l << 17; - REG_WR(bp, PXP2_REG_PSWRQ_BW_WR, val); - - REG_WR(bp, PXP2_REG_RQ_WR_MBS0, w_order); - REG_WR(bp, PXP2_REG_RQ_WR_MBS1, w_order); - REG_WR(bp, PXP2_REG_RQ_RD_MBS0, r_order); - REG_WR(bp, PXP2_REG_RQ_RD_MBS1, r_order); - - if (r_order == MAX_RD_ORD) - REG_WR(bp, PXP2_REG_RQ_PDR_LIMIT, 0xe00); - - REG_WR(bp, PXP2_REG_WR_USDMDP_TH, (0x18 << w_order)); - - if (CHIP_IS_E1H(bp)) { - val = ((w_order == 0) ? 2 : 3); - REG_WR(bp, PXP2_REG_WR_HC_MPS, val); - REG_WR(bp, PXP2_REG_WR_USDM_MPS, val); - REG_WR(bp, PXP2_REG_WR_CSDM_MPS, val); - REG_WR(bp, PXP2_REG_WR_TSDM_MPS, val); - REG_WR(bp, PXP2_REG_WR_XSDM_MPS, val); - REG_WR(bp, PXP2_REG_WR_QM_MPS, val); - REG_WR(bp, PXP2_REG_WR_TM_MPS, val); - REG_WR(bp, PXP2_REG_WR_SRC_MPS, val); - REG_WR(bp, PXP2_REG_WR_DBG_MPS, val); - REG_WR(bp, PXP2_REG_WR_DMAE_MPS, 2); /* DMAE is special */ - REG_WR(bp, PXP2_REG_WR_CDU_MPS, val); - } -} - /**************************************************************************** * CDU @@ -695,128 +344,12 @@ static void bnx2x_init_pxp(struct bnx2x *bp) (0x80 | ((_type) & 0xf << 3) | (CDU_CRC8(_cid, _region, _type) & 0x7)) #define CDU_RSRVD_INVALIDATE_CONTEXT_VALUE(_val) ((_val) & ~0x80) -/***************************************************************************** - * Description: - * Calculates crc 8 on a word value: polynomial 0-1-2-8 - * Code was translated from Verilog. - ****************************************************************************/ -static u8 calc_crc8(u32 data, u8 crc) -{ - u8 D[32]; - u8 NewCRC[8]; - u8 C[8]; - u8 crc_res; - u8 i; - - /* split the data into 31 bits */ - for (i = 0; i < 32; i++) { - D[i] = data & 1; - data = data >> 1; - } - - /* split the crc into 8 bits */ - for (i = 0; i < 8; i++) { - C[i] = crc & 1; - crc = crc >> 1; - } - - NewCRC[0] = D[31] ^ D[30] ^ D[28] ^ D[23] ^ D[21] ^ D[19] ^ D[18] ^ - D[16] ^ D[14] ^ D[12] ^ D[8] ^ D[7] ^ D[6] ^ D[0] ^ C[4] ^ - C[6] ^ C[7]; - NewCRC[1] = D[30] ^ D[29] ^ D[28] ^ D[24] ^ D[23] ^ D[22] ^ D[21] ^ - D[20] ^ D[18] ^ D[17] ^ D[16] ^ D[15] ^ D[14] ^ D[13] ^ - D[12] ^ D[9] ^ D[6] ^ D[1] ^ D[0] ^ C[0] ^ C[4] ^ C[5] ^ C[6]; - NewCRC[2] = D[29] ^ D[28] ^ D[25] ^ D[24] ^ D[22] ^ D[17] ^ D[15] ^ - D[13] ^ D[12] ^ D[10] ^ D[8] ^ D[6] ^ D[2] ^ D[1] ^ D[0] ^ - C[0] ^ C[1] ^ C[4] ^ C[5]; - NewCRC[3] = D[30] ^ D[29] ^ D[26] ^ D[25] ^ D[23] ^ D[18] ^ D[16] ^ - D[14] ^ D[13] ^ D[11] ^ D[9] ^ D[7] ^ D[3] ^ D[2] ^ D[1] ^ - C[1] ^ C[2] ^ C[5] ^ C[6]; - NewCRC[4] = D[31] ^ D[30] ^ D[27] ^ D[26] ^ D[24] ^ D[19] ^ D[17] ^ - D[15] ^ D[14] ^ D[12] ^ D[10] ^ D[8] ^ D[4] ^ D[3] ^ D[2] ^ - C[0] ^ C[2] ^ C[3] ^ C[6] ^ C[7]; - NewCRC[5] = D[31] ^ D[28] ^ D[27] ^ D[25] ^ D[20] ^ D[18] ^ D[16] ^ - D[15] ^ D[13] ^ D[11] ^ D[9] ^ D[5] ^ D[4] ^ D[3] ^ C[1] ^ - C[3] ^ C[4] ^ C[7]; - NewCRC[6] = D[29] ^ D[28] ^ D[26] ^ D[21] ^ D[19] ^ D[17] ^ D[16] ^ - D[14] ^ D[12] ^ D[10] ^ D[6] ^ D[5] ^ D[4] ^ C[2] ^ C[4] ^ - C[5]; - NewCRC[7] = D[30] ^ D[29] ^ D[27] ^ D[22] ^ D[20] ^ D[18] ^ D[17] ^ - D[15] ^ D[13] ^ D[11] ^ D[7] ^ D[6] ^ D[5] ^ C[3] ^ C[5] ^ - C[6]; - - crc_res = 0; - for (i = 0; i < 8; i++) - crc_res |= (NewCRC[i] << i); - - return crc_res; -} /* registers addresses are not in order so these arrays help simplify the code */ -static const int cm_start[E1H_FUNC_MAX][9] = { - {MISC_FUNC0_START, TCM_FUNC0_START, UCM_FUNC0_START, CCM_FUNC0_START, - XCM_FUNC0_START, TSEM_FUNC0_START, USEM_FUNC0_START, CSEM_FUNC0_START, - XSEM_FUNC0_START}, - {MISC_FUNC1_START, TCM_FUNC1_START, UCM_FUNC1_START, CCM_FUNC1_START, - XCM_FUNC1_START, TSEM_FUNC1_START, USEM_FUNC1_START, CSEM_FUNC1_START, - XSEM_FUNC1_START}, - {MISC_FUNC2_START, TCM_FUNC2_START, UCM_FUNC2_START, CCM_FUNC2_START, - XCM_FUNC2_START, TSEM_FUNC2_START, USEM_FUNC2_START, CSEM_FUNC2_START, - XSEM_FUNC2_START}, - {MISC_FUNC3_START, TCM_FUNC3_START, UCM_FUNC3_START, CCM_FUNC3_START, - XCM_FUNC3_START, TSEM_FUNC3_START, USEM_FUNC3_START, CSEM_FUNC3_START, - XSEM_FUNC3_START}, - {MISC_FUNC4_START, TCM_FUNC4_START, UCM_FUNC4_START, CCM_FUNC4_START, - XCM_FUNC4_START, TSEM_FUNC4_START, USEM_FUNC4_START, CSEM_FUNC4_START, - XSEM_FUNC4_START}, - {MISC_FUNC5_START, TCM_FUNC5_START, UCM_FUNC5_START, CCM_FUNC5_START, - XCM_FUNC5_START, TSEM_FUNC5_START, USEM_FUNC5_START, CSEM_FUNC5_START, - XSEM_FUNC5_START}, - {MISC_FUNC6_START, TCM_FUNC6_START, UCM_FUNC6_START, CCM_FUNC6_START, - XCM_FUNC6_START, TSEM_FUNC6_START, USEM_FUNC6_START, CSEM_FUNC6_START, - XSEM_FUNC6_START}, - {MISC_FUNC7_START, TCM_FUNC7_START, UCM_FUNC7_START, CCM_FUNC7_START, - XCM_FUNC7_START, TSEM_FUNC7_START, USEM_FUNC7_START, CSEM_FUNC7_START, - XSEM_FUNC7_START} -}; - -static const int cm_end[E1H_FUNC_MAX][9] = { - {MISC_FUNC0_END, TCM_FUNC0_END, UCM_FUNC0_END, CCM_FUNC0_END, - XCM_FUNC0_END, TSEM_FUNC0_END, USEM_FUNC0_END, CSEM_FUNC0_END, - XSEM_FUNC0_END}, - {MISC_FUNC1_END, TCM_FUNC1_END, UCM_FUNC1_END, CCM_FUNC1_END, - XCM_FUNC1_END, TSEM_FUNC1_END, USEM_FUNC1_END, CSEM_FUNC1_END, - XSEM_FUNC1_END}, - {MISC_FUNC2_END, TCM_FUNC2_END, UCM_FUNC2_END, CCM_FUNC2_END, - XCM_FUNC2_END, TSEM_FUNC2_END, USEM_FUNC2_END, CSEM_FUNC2_END, - XSEM_FUNC2_END}, - {MISC_FUNC3_END, TCM_FUNC3_END, UCM_FUNC3_END, CCM_FUNC3_END, - XCM_FUNC3_END, TSEM_FUNC3_END, USEM_FUNC3_END, CSEM_FUNC3_END, - XSEM_FUNC3_END}, - {MISC_FUNC4_END, TCM_FUNC4_END, UCM_FUNC4_END, CCM_FUNC4_END, - XCM_FUNC4_END, TSEM_FUNC4_END, USEM_FUNC4_END, CSEM_FUNC4_END, - XSEM_FUNC4_END}, - {MISC_FUNC5_END, TCM_FUNC5_END, UCM_FUNC5_END, CCM_FUNC5_END, - XCM_FUNC5_END, TSEM_FUNC5_END, USEM_FUNC5_END, CSEM_FUNC5_END, - XSEM_FUNC5_END}, - {MISC_FUNC6_END, TCM_FUNC6_END, UCM_FUNC6_END, CCM_FUNC6_END, - XCM_FUNC6_END, TSEM_FUNC6_END, USEM_FUNC6_END, CSEM_FUNC6_END, - XSEM_FUNC6_END}, - {MISC_FUNC7_END, TCM_FUNC7_END, UCM_FUNC7_END, CCM_FUNC7_END, - XCM_FUNC7_END, TSEM_FUNC7_END, USEM_FUNC7_END, CSEM_FUNC7_END, - XSEM_FUNC7_END}, -}; - -static const int hc_limits[E1H_FUNC_MAX][2] = { - {HC_FUNC0_START, HC_FUNC0_END}, - {HC_FUNC1_START, HC_FUNC1_END}, - {HC_FUNC2_START, HC_FUNC2_END}, - {HC_FUNC3_START, HC_FUNC3_END}, - {HC_FUNC4_START, HC_FUNC4_END}, - {HC_FUNC5_START, HC_FUNC5_END}, - {HC_FUNC6_START, HC_FUNC6_END}, - {HC_FUNC7_START, HC_FUNC7_END} +static const int cm_blocks[9] = { + MISC_BLOCK, TCM_BLOCK, UCM_BLOCK, CCM_BLOCK, XCM_BLOCK, + TSEM_BLOCK, USEM_BLOCK, CSEM_BLOCK, XSEM_BLOCK }; #endif /* BNX2X_INIT_H */ diff --git a/drivers/net/bnx2x_init_ops.h b/drivers/net/bnx2x_init_ops.h new file mode 100644 index 000000000000..32552b9366cb --- /dev/null +++ b/drivers/net/bnx2x_init_ops.h @@ -0,0 +1,442 @@ +/* bnx2x_init_ops.h: Broadcom Everest network driver. + * Static functions needed during the initialization. + * This file is "included" in bnx2x_main.c. + * + * Copyright (c) 2007-2009 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation. + * + * Maintained by: Eilon Greenstein + * Written by: Vladislav Zolotarov + */ +#ifndef BNX2X_INIT_OPS_H +#define BNX2X_INIT_OPS_H + +static void bnx2x_reg_wr_ind(struct bnx2x *bp, u32 addr, u32 val); +static int bnx2x_gunzip(struct bnx2x *bp, const u8 *zbuf, int len); + +static void bnx2x_init_str_wr(struct bnx2x *bp, u32 addr, const u32 *data, + u32 len) +{ + int i; + + for (i = 0; i < len; i++) { + REG_WR(bp, addr + i*4, data[i]); + if (!(i % 10000)) { + touch_softlockup_watchdog(); + cpu_relax(); + } + } +} + +static void bnx2x_init_ind_wr(struct bnx2x *bp, u32 addr, const u32 *data, + u16 len) +{ + int i; + + for (i = 0; i < len; i++) { + REG_WR_IND(bp, addr + i*4, data[i]); + if (!(i % 10000)) { + touch_softlockup_watchdog(); + cpu_relax(); + } + } +} + +static void bnx2x_write_big_buf(struct bnx2x *bp, u32 addr, u32 len) +{ + int offset = 0; + + if (bp->dmae_ready) { + while (len > DMAE_LEN32_WR_MAX) { + bnx2x_write_dmae(bp, bp->gunzip_mapping + offset, + addr + offset, DMAE_LEN32_WR_MAX); + offset += DMAE_LEN32_WR_MAX * 4; + len -= DMAE_LEN32_WR_MAX; + } + bnx2x_write_dmae(bp, bp->gunzip_mapping + offset, + addr + offset, len); + } else + bnx2x_init_str_wr(bp, addr, bp->gunzip_buf, len); +} + +static void bnx2x_init_fill(struct bnx2x *bp, u32 addr, int fill, u32 len) +{ + u32 buf_len = (((len * 4) > FW_BUF_SIZE) ? FW_BUF_SIZE : (len * 4)); + u32 buf_len32 = buf_len / 4; + int i; + + memset(bp->gunzip_buf, fill, buf_len); + + for (i = 0; i < len; i += buf_len32) { + u32 cur_len = min(buf_len32, len - i); + + bnx2x_write_big_buf(bp, addr + i * 4, cur_len); + } +} + +static void bnx2x_init_wr_64(struct bnx2x *bp, u32 addr, const u32 *data, + u32 len64) +{ + u32 buf_len32 = FW_BUF_SIZE / 4; + u32 len = len64 * 2; + u64 data64 = 0; + int i; + + /* 64 bit value is in a blob: first low DWORD, then high DWORD */ + data64 = HILO_U64((*(data + 1)), (*data)); + len64 = min((u32)(FW_BUF_SIZE/8), len64); + for (i = 0; i < len64; i++) { + u64 *pdata = ((u64 *)(bp->gunzip_buf)) + i; + + *pdata = data64; + } + + for (i = 0; i < len; i += buf_len32) { + u32 cur_len = min(buf_len32, len - i); + + bnx2x_write_big_buf(bp, addr + i * 4, cur_len); + } +} + +/********************************************************* + There are different blobs for each PRAM section. + In addition, each blob write operation is divided into a few operations + in order to decrease the amount of phys. contiguous buffer needed. + Thus, when we select a blob the address may be with some offset + from the beginning of PRAM section. + The same holds for the INT_TABLE sections. +**********************************************************/ +#define IF_IS_INT_TABLE_ADDR(base, addr) \ + if (((base) <= (addr)) && ((base) + 0x400 >= (addr))) + +#define IF_IS_PRAM_ADDR(base, addr) \ + if (((base) <= (addr)) && ((base) + 0x40000 >= (addr))) + +static const u8 *bnx2x_sel_blob(struct bnx2x *bp, u32 addr, const u8 *data) +{ + IF_IS_INT_TABLE_ADDR(TSEM_REG_INT_TABLE, addr) + data = bp->tsem_int_table_data; + else IF_IS_INT_TABLE_ADDR(CSEM_REG_INT_TABLE, addr) + data = bp->csem_int_table_data; + else IF_IS_INT_TABLE_ADDR(USEM_REG_INT_TABLE, addr) + data = bp->usem_int_table_data; + else IF_IS_INT_TABLE_ADDR(XSEM_REG_INT_TABLE, addr) + data = bp->xsem_int_table_data; + else IF_IS_PRAM_ADDR(TSEM_REG_PRAM, addr) + data = bp->tsem_pram_data; + else IF_IS_PRAM_ADDR(CSEM_REG_PRAM, addr) + data = bp->csem_pram_data; + else IF_IS_PRAM_ADDR(USEM_REG_PRAM, addr) + data = bp->usem_pram_data; + else IF_IS_PRAM_ADDR(XSEM_REG_PRAM, addr) + data = bp->xsem_pram_data; + + return data; +} + +static void bnx2x_write_big_buf_wb(struct bnx2x *bp, u32 addr, u32 len) +{ + int offset = 0; + + if (bp->dmae_ready) { + while (len > DMAE_LEN32_WR_MAX) { + bnx2x_write_dmae(bp, bp->gunzip_mapping + offset, + addr + offset, DMAE_LEN32_WR_MAX); + offset += DMAE_LEN32_WR_MAX * 4; + len -= DMAE_LEN32_WR_MAX; + } + bnx2x_write_dmae(bp, bp->gunzip_mapping + offset, + addr + offset, len); + } else + bnx2x_init_ind_wr(bp, addr, bp->gunzip_buf, len); +} + +static void bnx2x_init_wr_wb(struct bnx2x *bp, u32 addr, const u32 *data, + u32 len) +{ + /* This is needed for NO_ZIP mode, currently supported + in little endian mode only */ + data = (const u32*)bnx2x_sel_blob(bp, addr, (const u8*)data); + + if ((len * 4) > FW_BUF_SIZE) { + BNX2X_ERR("LARGE DMAE OPERATION ! " + "addr 0x%x len 0x%x\n", addr, len*4); + return; + } + memcpy(bp->gunzip_buf, data, len * 4); + + bnx2x_write_big_buf_wb(bp, addr, len); +} + +static void bnx2x_init_wr_zp(struct bnx2x *bp, u32 addr, + u32 len, u32 blob_off) +{ + int rc, i; + const u8 *data = NULL; + + data = bnx2x_sel_blob(bp, addr, data) + 4*blob_off; + + if (data == NULL) { + panic("Blob not found for addr 0x%x\n", addr); + return; + } + + rc = bnx2x_gunzip(bp, data, len); + if (rc) { + BNX2X_ERR("gunzip failed ! addr 0x%x rc %d\n", addr, rc); + BNX2X_ERR("blob_offset=0x%x\n", blob_off); + return; + } + + /* gunzip_outlen is in dwords */ + len = bp->gunzip_outlen; + for (i = 0; i < len; i++) + ((u32 *)bp->gunzip_buf)[i] = + cpu_to_le32(((u32 *)bp->gunzip_buf)[i]); + + bnx2x_write_big_buf_wb(bp, addr, len); +} + +static void bnx2x_init_block(struct bnx2x *bp, u32 block, u32 stage) +{ + int hw_wr, i; + u16 op_start = + bp->init_ops_offsets[BLOCK_OPS_IDX(block,stage,STAGE_START)]; + u16 op_end = + bp->init_ops_offsets[BLOCK_OPS_IDX(block,stage,STAGE_END)]; + union init_op *op; + u32 op_type, addr, len; + const u32 *data, *data_base; + + /* If empty block */ + if (op_start == op_end) + return; + + if (CHIP_REV_IS_FPGA(bp)) + hw_wr = OP_WR_FPGA; + else if (CHIP_REV_IS_EMUL(bp)) + hw_wr = OP_WR_EMUL; + else + hw_wr = OP_WR_ASIC; + + data_base = bp->init_data; + + for (i = op_start; i < op_end; i++) { + + op = (union init_op *)&(bp->init_ops[i]); + + op_type = op->str_wr.op; + addr = op->str_wr.offset; + len = op->str_wr.data_len; + data = data_base + op->str_wr.data_off; + + /* HW/EMUL specific */ + if (unlikely((op_type > OP_WB) && (op_type == hw_wr))) + op_type = OP_WR; + + switch (op_type) { + case OP_RD: + REG_RD(bp, addr); + break; + case OP_WR: + REG_WR(bp, addr, op->write.val); + break; + case OP_SW: + bnx2x_init_str_wr(bp, addr, data, len); + break; + case OP_WB: + bnx2x_init_wr_wb(bp, addr, data, len); + break; + case OP_SI: + bnx2x_init_ind_wr(bp, addr, data, len); + break; + case OP_ZR: + bnx2x_init_fill(bp, addr, 0, op->zero.len); + break; + case OP_ZP: + bnx2x_init_wr_zp(bp, addr, len, + op->str_wr.data_off); + break; + case OP_WR_64: + bnx2x_init_wr_64(bp, addr, data, len); + break; + default: + /* happens whenever an op is of a diff HW */ +#if 0 + DP(NETIF_MSG_HW, "skipping init operation " + "index %d[%d:%d]: type %d addr 0x%x " + "len %d(0x%x)\n", + i, op_start, op_end, op_type, addr, len, len); +#endif + break; + } + } +} + +/* PXP */ +static void bnx2x_init_pxp(struct bnx2x *bp) +{ + u16 devctl; + int r_order, w_order; + u32 val, i; + + pci_read_config_word(bp->pdev, + bp->pcie_cap + PCI_EXP_DEVCTL, &devctl); + DP(NETIF_MSG_HW, "read 0x%x from devctl\n", devctl); + w_order = ((devctl & PCI_EXP_DEVCTL_PAYLOAD) >> 5); + if (bp->mrrs == -1) + r_order = ((devctl & PCI_EXP_DEVCTL_READRQ) >> 12); + else { + DP(NETIF_MSG_HW, "force read order to %d\n", bp->mrrs); + r_order = bp->mrrs; + } + + if (r_order > MAX_RD_ORD) { + DP(NETIF_MSG_HW, "read order of %d order adjusted to %d\n", + r_order, MAX_RD_ORD); + r_order = MAX_RD_ORD; + } + if (w_order > MAX_WR_ORD) { + DP(NETIF_MSG_HW, "write order of %d order adjusted to %d\n", + w_order, MAX_WR_ORD); + w_order = MAX_WR_ORD; + } + if (CHIP_REV_IS_FPGA(bp)) { + DP(NETIF_MSG_HW, "write order adjusted to 1 for FPGA\n"); + w_order = 0; + } + DP(NETIF_MSG_HW, "read order %d write order %d\n", r_order, w_order); + + for (i = 0; i < NUM_RD_Q-1; i++) { + REG_WR(bp, read_arb_addr[i].l, read_arb_data[i][r_order].l); + REG_WR(bp, read_arb_addr[i].add, + read_arb_data[i][r_order].add); + REG_WR(bp, read_arb_addr[i].ubound, + read_arb_data[i][r_order].ubound); + } + + for (i = 0; i < NUM_WR_Q-1; i++) { + if ((write_arb_addr[i].l == PXP2_REG_RQ_BW_WR_L29) || + (write_arb_addr[i].l == PXP2_REG_RQ_BW_WR_L30)) { + + REG_WR(bp, write_arb_addr[i].l, + write_arb_data[i][w_order].l); + + REG_WR(bp, write_arb_addr[i].add, + write_arb_data[i][w_order].add); + + REG_WR(bp, write_arb_addr[i].ubound, + write_arb_data[i][w_order].ubound); + } else { + + val = REG_RD(bp, write_arb_addr[i].l); + REG_WR(bp, write_arb_addr[i].l, + val | (write_arb_data[i][w_order].l << 10)); + + val = REG_RD(bp, write_arb_addr[i].add); + REG_WR(bp, write_arb_addr[i].add, + val | (write_arb_data[i][w_order].add << 10)); + + val = REG_RD(bp, write_arb_addr[i].ubound); + REG_WR(bp, write_arb_addr[i].ubound, + val | (write_arb_data[i][w_order].ubound << 7)); + } + } + + val = write_arb_data[NUM_WR_Q-1][w_order].add; + val += write_arb_data[NUM_WR_Q-1][w_order].ubound << 10; + val += write_arb_data[NUM_WR_Q-1][w_order].l << 17; + REG_WR(bp, PXP2_REG_PSWRQ_BW_RD, val); + + val = read_arb_data[NUM_RD_Q-1][r_order].add; + val += read_arb_data[NUM_RD_Q-1][r_order].ubound << 10; + val += read_arb_data[NUM_RD_Q-1][r_order].l << 17; + REG_WR(bp, PXP2_REG_PSWRQ_BW_WR, val); + + REG_WR(bp, PXP2_REG_RQ_WR_MBS0, w_order); + REG_WR(bp, PXP2_REG_RQ_WR_MBS1, w_order); + REG_WR(bp, PXP2_REG_RQ_RD_MBS0, r_order); + REG_WR(bp, PXP2_REG_RQ_RD_MBS1, r_order); + + if (r_order == MAX_RD_ORD) + REG_WR(bp, PXP2_REG_RQ_PDR_LIMIT, 0xe00); + + REG_WR(bp, PXP2_REG_WR_USDMDP_TH, (0x18 << w_order)); + + if (CHIP_IS_E1H(bp)) { + val = ((w_order == 0) ? 2 : 3); + REG_WR(bp, PXP2_REG_WR_HC_MPS, val); + REG_WR(bp, PXP2_REG_WR_USDM_MPS, val); + REG_WR(bp, PXP2_REG_WR_CSDM_MPS, val); + REG_WR(bp, PXP2_REG_WR_TSDM_MPS, val); + REG_WR(bp, PXP2_REG_WR_XSDM_MPS, val); + REG_WR(bp, PXP2_REG_WR_QM_MPS, val); + REG_WR(bp, PXP2_REG_WR_TM_MPS, val); + REG_WR(bp, PXP2_REG_WR_SRC_MPS, val); + REG_WR(bp, PXP2_REG_WR_DBG_MPS, val); + REG_WR(bp, PXP2_REG_WR_DMAE_MPS, 2); /* DMAE is special */ + REG_WR(bp, PXP2_REG_WR_CDU_MPS, val); + } +} + +/***************************************************************************** + * Description: + * Calculates crc 8 on a word value: polynomial 0-1-2-8 + * Code was translated from Verilog. + ****************************************************************************/ +static u8 calc_crc8(u32 data, u8 crc) +{ + u8 D[32]; + u8 NewCRC[8]; + u8 C[8]; + u8 crc_res; + u8 i; + + /* split the data into 31 bits */ + for (i = 0; i < 32; i++) { + D[i] = data & 1; + data = data >> 1; + } + + /* split the crc into 8 bits */ + for (i = 0; i < 8; i++) { + C[i] = crc & 1; + crc = crc >> 1; + } + + NewCRC[0] = D[31] ^ D[30] ^ D[28] ^ D[23] ^ D[21] ^ D[19] ^ D[18] ^ + D[16] ^ D[14] ^ D[12] ^ D[8] ^ D[7] ^ D[6] ^ D[0] ^ C[4] ^ + C[6] ^ C[7]; + NewCRC[1] = D[30] ^ D[29] ^ D[28] ^ D[24] ^ D[23] ^ D[22] ^ D[21] ^ + D[20] ^ D[18] ^ D[17] ^ D[16] ^ D[15] ^ D[14] ^ D[13] ^ + D[12] ^ D[9] ^ D[6] ^ D[1] ^ D[0] ^ C[0] ^ C[4] ^ C[5] ^ C[6]; + NewCRC[2] = D[29] ^ D[28] ^ D[25] ^ D[24] ^ D[22] ^ D[17] ^ D[15] ^ + D[13] ^ D[12] ^ D[10] ^ D[8] ^ D[6] ^ D[2] ^ D[1] ^ D[0] ^ + C[0] ^ C[1] ^ C[4] ^ C[5]; + NewCRC[3] = D[30] ^ D[29] ^ D[26] ^ D[25] ^ D[23] ^ D[18] ^ D[16] ^ + D[14] ^ D[13] ^ D[11] ^ D[9] ^ D[7] ^ D[3] ^ D[2] ^ D[1] ^ + C[1] ^ C[2] ^ C[5] ^ C[6]; + NewCRC[4] = D[31] ^ D[30] ^ D[27] ^ D[26] ^ D[24] ^ D[19] ^ D[17] ^ + D[15] ^ D[14] ^ D[12] ^ D[10] ^ D[8] ^ D[4] ^ D[3] ^ D[2] ^ + C[0] ^ C[2] ^ C[3] ^ C[6] ^ C[7]; + NewCRC[5] = D[31] ^ D[28] ^ D[27] ^ D[25] ^ D[20] ^ D[18] ^ D[16] ^ + D[15] ^ D[13] ^ D[11] ^ D[9] ^ D[5] ^ D[4] ^ D[3] ^ C[1] ^ + C[3] ^ C[4] ^ C[7]; + NewCRC[6] = D[29] ^ D[28] ^ D[26] ^ D[21] ^ D[19] ^ D[17] ^ D[16] ^ + D[14] ^ D[12] ^ D[10] ^ D[6] ^ D[5] ^ D[4] ^ C[2] ^ C[4] ^ + C[5]; + NewCRC[7] = D[30] ^ D[29] ^ D[27] ^ D[22] ^ D[20] ^ D[18] ^ D[17] ^ + D[15] ^ D[13] ^ D[11] ^ D[7] ^ D[6] ^ D[5] ^ C[3] ^ C[5] ^ + C[6]; + + crc_res = 0; + for (i = 0; i < 8; i++) + crc_res |= (NewCRC[i] << i); + + return crc_res; +} + +#endif /* BNX2X_INIT_OPS_H */ diff --git a/drivers/net/bnx2x_init_values.h b/drivers/net/bnx2x_init_values.h deleted file mode 100644 index 1f22c9ab66d4..000000000000 --- a/drivers/net/bnx2x_init_values.h +++ /dev/null @@ -1,16322 +0,0 @@ -#ifndef __BNX2X_INIT_VALUES_H__ -#define __BNX2X_INIT_VALUES_H__ - -/* bnx2x_init_values.h: Broadcom NX2 10G network driver. - * - * Copyright (c) 2007-2009 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, except as noted below. - * - * This file contains firmware data derived from proprietary unpublished - * source code, Copyright (c) 2007-2009 Broadcom Corporation. - * - * Permission is hereby granted for the distribution of this firmware data - * in hexadecimal or equivalent format, provided this copyright notice is - * accompanying it. - * - * - * This array contains the list of operations needed to initialize the chip. - * - * For each block in the chip there are three init stages: - * common - HW used by both ports, - * port1 and port2 - initialization for a specific Ethernet port. - * When a port is opened or closed, the management CPU tells the driver - * whether to init/disable common HW in addition to the port HW. - * This way the first port going up will first initializes the common HW, - * and the last port going down also resets the common HW - * - * For each init stage/block there is a list of actions needed in a format: - * {operation, register, data} - * where: - * OP_WR - write a value to the chip. - * OP_RD - read a register (usually a clear on read register). - * OP_SW - string write, write a section of consecutive addresses to the chip. - * OP_SI - copy a string using indirect writes. - * OP_ZR - clear a range of memory. - * OP_ZP - unzip and copy using DMAE. - * OP_WB - string copy using DMAE. - * - * The #defines mark the stages. - * - */ - -static const struct raw_op init_ops[] = { -#define PRS_COMMON_START 0 - {OP_WR, PRS_REG_INC_VALUE, 0xf}, - {OP_WR, PRS_REG_EVENT_ID_1, 0x45}, - {OP_WR, PRS_REG_EVENT_ID_2, 0x84}, - {OP_WR, PRS_REG_EVENT_ID_3, 0x6}, - {OP_WR, PRS_REG_NO_MATCH_EVENT_ID, 0x4}, - {OP_WR, PRS_REG_CM_HDR_TYPE_0, 0x0}, - {OP_WR, PRS_REG_CM_HDR_TYPE_1, 0x12170000}, - {OP_WR, PRS_REG_CM_HDR_TYPE_2, 0x22170000}, - {OP_WR, PRS_REG_CM_HDR_TYPE_3, 0x32170000}, - {OP_ZR, PRS_REG_CM_HDR_TYPE_4, 0x5}, - {OP_WR, PRS_REG_CM_HDR_LOOPBACK_TYPE_1, 0x12150000}, - {OP_WR, PRS_REG_CM_HDR_LOOPBACK_TYPE_2, 0x22150000}, - {OP_WR, PRS_REG_CM_HDR_LOOPBACK_TYPE_3, 0x32150000}, - {OP_ZR, PRS_REG_CM_HDR_LOOPBACK_TYPE_4, 0x4}, - {OP_WR, PRS_REG_CM_NO_MATCH_HDR, 0x2100000}, - {OP_WR, PRS_REG_CM_HDR_FLUSH_NO_LOAD_TYPE_0, 0x100000}, - {OP_WR, PRS_REG_CM_HDR_FLUSH_NO_LOAD_TYPE_1, 0x10100000}, - {OP_WR, PRS_REG_CM_HDR_FLUSH_NO_LOAD_TYPE_2, 0x20100000}, - {OP_WR, PRS_REG_CM_HDR_FLUSH_NO_LOAD_TYPE_3, 0x30100000}, - {OP_ZR_E1, PRS_REG_CM_HDR_FLUSH_NO_LOAD_TYPE_4, 0x4}, - {OP_WR_E1H, PRS_REG_CM_HDR_FLUSH_NO_LOAD_TYPE_4, 0x40100000}, - {OP_ZR_E1H, PRS_REG_CM_HDR_FLUSH_NO_LOAD_TYPE_5, 0x3}, - {OP_WR, PRS_REG_CM_HDR_FLUSH_LOAD_TYPE_0, 0x100000}, - {OP_WR, PRS_REG_CM_HDR_FLUSH_LOAD_TYPE_1, 0x12140000}, - {OP_WR, PRS_REG_CM_HDR_FLUSH_LOAD_TYPE_2, 0x22140000}, - {OP_WR, PRS_REG_CM_HDR_FLUSH_LOAD_TYPE_3, 0x32140000}, - {OP_ZR_E1, PRS_REG_CM_HDR_FLUSH_LOAD_TYPE_4, 0x4}, - {OP_WR_E1H, PRS_REG_CM_HDR_FLUSH_LOAD_TYPE_4, 0x42140000}, - {OP_ZR_E1H, PRS_REG_CM_HDR_FLUSH_LOAD_TYPE_5, 0x3}, - {OP_RD, PRS_REG_NUM_OF_PACKETS, 0x0}, - {OP_RD, PRS_REG_NUM_OF_CFC_FLUSH_MESSAGES, 0x0}, - {OP_RD, PRS_REG_NUM_OF_TRANSPARENT_FLUSH_MESSAGES, 0x0}, - {OP_RD, PRS_REG_NUM_OF_DEAD_CYCLES, 0x0}, - {OP_WR_E1H, PRS_REG_FCOE_TYPE, 0x8906}, - {OP_WR, PRS_REG_FLUSH_REGIONS_TYPE_0, 0xff}, - {OP_WR, PRS_REG_FLUSH_REGIONS_TYPE_1, 0xff}, - {OP_WR, PRS_REG_FLUSH_REGIONS_TYPE_2, 0xff}, - {OP_WR, PRS_REG_FLUSH_REGIONS_TYPE_3, 0xff}, - {OP_WR, PRS_REG_FLUSH_REGIONS_TYPE_4, 0xff}, - {OP_WR, PRS_REG_FLUSH_REGIONS_TYPE_5, 0xff}, - {OP_WR, PRS_REG_FLUSH_REGIONS_TYPE_6, 0xff}, - {OP_WR, PRS_REG_FLUSH_REGIONS_TYPE_7, 0xff}, - {OP_WR, PRS_REG_PURE_REGIONS, 0x3e}, - {OP_WR, PRS_REG_PACKET_REGIONS_TYPE_0, 0x0}, - {OP_WR, PRS_REG_PACKET_REGIONS_TYPE_1, 0x3f}, - {OP_WR, PRS_REG_PACKET_REGIONS_TYPE_2, 0x3f}, - {OP_WR, PRS_REG_PACKET_REGIONS_TYPE_3, 0x3f}, - {OP_WR_E1, PRS_REG_PACKET_REGIONS_TYPE_4, 0x0}, - {OP_WR_E1H, PRS_REG_PACKET_REGIONS_TYPE_4, 0x3f}, - {OP_WR, PRS_REG_PACKET_REGIONS_TYPE_5, 0x3f}, - {OP_WR, PRS_REG_PACKET_REGIONS_TYPE_6, 0x3f}, - {OP_WR, PRS_REG_PACKET_REGIONS_TYPE_7, 0x3f}, -#define PRS_COMMON_END 52 -#define SRCH_COMMON_START 52 - {OP_WR_E1H, SRC_REG_E1HMF_ENABLE, 0x1}, -#define SRCH_COMMON_END 53 -#define TSDM_COMMON_START 53 - {OP_WR_E1, TSDM_REG_CFC_RSP_START_ADDR, 0x411}, - {OP_WR_E1H, TSDM_REG_CFC_RSP_START_ADDR, 0x211}, - {OP_WR_E1, TSDM_REG_CMP_COUNTER_START_ADDR, 0x400}, - {OP_WR_E1H, TSDM_REG_CMP_COUNTER_START_ADDR, 0x200}, - {OP_WR_E1, TSDM_REG_Q_COUNTER_START_ADDR, 0x404}, - {OP_WR_E1H, TSDM_REG_Q_COUNTER_START_ADDR, 0x204}, - {OP_WR_E1, TSDM_REG_PCK_END_MSG_START_ADDR, 0x419}, - {OP_WR_E1H, TSDM_REG_PCK_END_MSG_START_ADDR, 0x219}, - {OP_WR, TSDM_REG_CMP_COUNTER_MAX0, 0xffff}, - {OP_WR, TSDM_REG_CMP_COUNTER_MAX1, 0xffff}, - {OP_WR, TSDM_REG_CMP_COUNTER_MAX2, 0xffff}, - {OP_WR, TSDM_REG_CMP_COUNTER_MAX3, 0xffff}, - {OP_ZR_E1, TSDM_REG_AGG_INT_EVENT_0, 0x2}, - {OP_WR_E1H, TSDM_REG_AGG_INT_EVENT_0, 0x20}, - {OP_WR_E1H, TSDM_REG_AGG_INT_EVENT_1, 0x0}, - {OP_WR, TSDM_REG_AGG_INT_EVENT_2, 0x34}, - {OP_WR, TSDM_REG_AGG_INT_EVENT_3, 0x35}, - {OP_ZR_E1, TSDM_REG_AGG_INT_EVENT_4, 0x7c}, - {OP_ZR_E1H, TSDM_REG_AGG_INT_EVENT_4, 0x1c}, - {OP_WR_E1H, TSDM_REG_AGG_INT_T_0, 0x1}, - {OP_ZR_E1H, TSDM_REG_AGG_INT_T_1, 0x5f}, - {OP_WR, TSDM_REG_ENABLE_IN1, 0x7ffffff}, - {OP_WR, TSDM_REG_ENABLE_IN2, 0x3f}, - {OP_WR, TSDM_REG_ENABLE_OUT1, 0x7ffffff}, - {OP_WR, TSDM_REG_ENABLE_OUT2, 0xf}, - {OP_RD, TSDM_REG_NUM_OF_Q0_CMD, 0x0}, - {OP_RD, TSDM_REG_NUM_OF_Q1_CMD, 0x0}, - {OP_RD, TSDM_REG_NUM_OF_Q3_CMD, 0x0}, - {OP_RD, TSDM_REG_NUM_OF_Q4_CMD, 0x0}, - {OP_RD, TSDM_REG_NUM_OF_Q5_CMD, 0x0}, - {OP_RD, TSDM_REG_NUM_OF_Q6_CMD, 0x0}, - {OP_RD, TSDM_REG_NUM_OF_Q7_CMD, 0x0}, - {OP_RD, TSDM_REG_NUM_OF_Q8_CMD, 0x0}, - {OP_RD, TSDM_REG_NUM_OF_Q9_CMD, 0x0}, - {OP_RD, TSDM_REG_NUM_OF_Q10_CMD, 0x0}, - {OP_RD, TSDM_REG_NUM_OF_Q11_CMD, 0x0}, - {OP_RD, TSDM_REG_NUM_OF_PKT_END_MSG, 0x0}, - {OP_RD, TSDM_REG_NUM_OF_PXP_ASYNC_REQ, 0x0}, - {OP_RD, TSDM_REG_NUM_OF_ACK_AFTER_PLACE, 0x0}, - {OP_WR_E1, TSDM_REG_INIT_CREDIT_PXP_CTRL, 0x1}, - {OP_WR_ASIC, TSDM_REG_TIMER_TICK, 0x3e8}, - {OP_WR_EMUL, TSDM_REG_TIMER_TICK, 0x1}, - {OP_WR_FPGA, TSDM_REG_TIMER_TICK, 0xa}, -#define TSDM_COMMON_END 96 -#define TCM_COMMON_START 96 - {OP_WR, TCM_REG_XX_MAX_LL_SZ, 0x20}, - {OP_WR, TCM_REG_XX_OVFL_EVNT_ID, 0x32}, - {OP_WR, TCM_REG_TQM_TCM_HDR_P, 0x2150020}, - {OP_WR, TCM_REG_TQM_TCM_HDR_S, 0x2150020}, - {OP_WR, TCM_REG_TM_TCM_HDR, 0x30}, - {OP_WR, TCM_REG_ERR_TCM_HDR, 0x8100000}, - {OP_WR, TCM_REG_ERR_EVNT_ID, 0x33}, - {OP_WR, TCM_REG_EXPR_EVNT_ID, 0x30}, - {OP_WR, TCM_REG_STOP_EVNT_ID, 0x31}, - {OP_WR, TCM_REG_STORM_WEIGHT, 0x2}, - {OP_WR, TCM_REG_PRS_WEIGHT, 0x5}, - {OP_WR, TCM_REG_PBF_WEIGHT, 0x6}, - {OP_WR, TCM_REG_USEM_WEIGHT, 0x2}, - {OP_WR, TCM_REG_CSEM_WEIGHT, 0x2}, - {OP_WR, TCM_REG_CP_WEIGHT, 0x0}, - {OP_WR, TCM_REG_TSDM_WEIGHT, 0x5}, - {OP_WR, TCM_REG_TQM_P_WEIGHT, 0x2}, - {OP_WR, TCM_REG_TQM_S_WEIGHT, 0x2}, - {OP_WR, TCM_REG_TM_WEIGHT, 0x2}, - {OP_WR, TCM_REG_TCM_TQM_USE_Q, 0x1}, - {OP_WR, TCM_REG_GR_ARB_TYPE, 0x1}, - {OP_WR, TCM_REG_GR_LD0_PR, 0x1}, - {OP_WR, TCM_REG_GR_LD1_PR, 0x2}, - {OP_WR, TCM_REG_CFC_INIT_CRD, 0x1}, - {OP_WR, TCM_REG_FIC0_INIT_CRD, 0x40}, - {OP_WR, TCM_REG_FIC1_INIT_CRD, 0x40}, - {OP_WR, TCM_REG_TQM_INIT_CRD, 0x20}, - {OP_WR, TCM_REG_XX_INIT_CRD, 0x13}, - {OP_WR, TCM_REG_XX_MSG_NUM, 0x20}, - {OP_ZR, TCM_REG_XX_TABLE, 0xa}, - {OP_SW, TCM_REG_XX_DESCR_TABLE, 0x200000}, - {OP_WR, TCM_REG_N_SM_CTX_LD_0, 0x7}, - {OP_WR, TCM_REG_N_SM_CTX_LD_1, 0x7}, - {OP_WR, TCM_REG_N_SM_CTX_LD_2, 0x8}, - {OP_WR, TCM_REG_N_SM_CTX_LD_3, 0x8}, - {OP_ZR_E1, TCM_REG_N_SM_CTX_LD_4, 0x4}, - {OP_WR_E1H, TCM_REG_N_SM_CTX_LD_4, 0x1}, - {OP_ZR_E1H, TCM_REG_N_SM_CTX_LD_5, 0x3}, - {OP_WR, TCM_REG_TCM_REG0_SZ, 0x6}, - {OP_WR_E1, TCM_REG_PHYS_QNUM0_0, 0xd}, - {OP_WR_E1, TCM_REG_PHYS_QNUM0_1, 0x2d}, - {OP_WR_E1, TCM_REG_PHYS_QNUM1_0, 0x7}, - {OP_WR_E1, TCM_REG_PHYS_QNUM1_1, 0x27}, - {OP_WR_E1, TCM_REG_PHYS_QNUM2_0, 0x7}, - {OP_WR_E1, TCM_REG_PHYS_QNUM2_1, 0x27}, - {OP_WR_E1, TCM_REG_PHYS_QNUM3_0, 0x7}, - {OP_WR_E1, TCM_REG_PHYS_QNUM3_1, 0x27}, - {OP_WR, TCM_REG_TCM_STORM0_IFEN, 0x1}, - {OP_WR, TCM_REG_TCM_STORM1_IFEN, 0x1}, - {OP_WR, TCM_REG_TCM_TQM_IFEN, 0x1}, - {OP_WR, TCM_REG_STORM_TCM_IFEN, 0x1}, - {OP_WR, TCM_REG_TQM_TCM_IFEN, 0x1}, - {OP_WR, TCM_REG_TSDM_IFEN, 0x1}, - {OP_WR, TCM_REG_TM_TCM_IFEN, 0x1}, - {OP_WR, TCM_REG_PRS_IFEN, 0x1}, - {OP_WR, TCM_REG_PBF_IFEN, 0x1}, - {OP_WR, TCM_REG_USEM_IFEN, 0x1}, - {OP_WR, TCM_REG_CSEM_IFEN, 0x1}, - {OP_WR, TCM_REG_CDU_AG_WR_IFEN, 0x1}, - {OP_WR, TCM_REG_CDU_AG_RD_IFEN, 0x1}, - {OP_WR, TCM_REG_CDU_SM_WR_IFEN, 0x1}, - {OP_WR, TCM_REG_CDU_SM_RD_IFEN, 0x1}, - {OP_WR, TCM_REG_TCM_CFC_IFEN, 0x1}, -#define TCM_COMMON_END 159 -#define TCM_FUNC0_START 159 - {OP_WR_E1H, TCM_REG_PHYS_QNUM0_0, 0xd}, - {OP_WR_E1H, TCM_REG_PHYS_QNUM1_0, 0x7}, - {OP_WR_E1H, TCM_REG_PHYS_QNUM2_0, 0x7}, - {OP_WR_E1H, TCM_REG_PHYS_QNUM3_0, 0x7}, -#define TCM_FUNC0_END 163 -#define TCM_FUNC1_START 163 - {OP_WR_E1H, TCM_REG_PHYS_QNUM0_1, 0x2d}, - {OP_WR_E1H, TCM_REG_PHYS_QNUM1_1, 0x27}, - {OP_WR_E1H, TCM_REG_PHYS_QNUM2_1, 0x27}, - {OP_WR_E1H, TCM_REG_PHYS_QNUM3_1, 0x27}, -#define TCM_FUNC1_END 167 -#define TCM_FUNC2_START 167 - {OP_WR_E1H, TCM_REG_PHYS_QNUM0_0, 0x1d}, - {OP_WR_E1H, TCM_REG_PHYS_QNUM1_0, 0x17}, - {OP_WR_E1H, TCM_REG_PHYS_QNUM2_0, 0x17}, - {OP_WR_E1H, TCM_REG_PHYS_QNUM3_0, 0x17}, -#define TCM_FUNC2_END 171 -#define TCM_FUNC3_START 171 - {OP_WR_E1H, TCM_REG_PHYS_QNUM0_1, 0x3d}, - {OP_WR_E1H, TCM_REG_PHYS_QNUM1_1, 0x37}, - {OP_WR_E1H, TCM_REG_PHYS_QNUM2_1, 0x37}, - {OP_WR_E1H, TCM_REG_PHYS_QNUM3_1, 0x37}, -#define TCM_FUNC3_END 175 -#define TCM_FUNC4_START 175 - {OP_WR_E1H, TCM_REG_PHYS_QNUM0_0, 0x4d}, - {OP_WR_E1H, TCM_REG_PHYS_QNUM1_0, 0x47}, - {OP_WR_E1H, TCM_REG_PHYS_QNUM2_0, 0x47}, - {OP_WR_E1H, TCM_REG_PHYS_QNUM3_0, 0x47}, -#define TCM_FUNC4_END 179 -#define TCM_FUNC5_START 179 - {OP_WR_E1H, TCM_REG_PHYS_QNUM0_1, 0x6d}, - {OP_WR_E1H, TCM_REG_PHYS_QNUM1_1, 0x67}, - {OP_WR_E1H, TCM_REG_PHYS_QNUM2_1, 0x67}, - {OP_WR_E1H, TCM_REG_PHYS_QNUM3_1, 0x67}, -#define TCM_FUNC5_END 183 -#define TCM_FUNC6_START 183 - {OP_WR_E1H, TCM_REG_PHYS_QNUM0_0, 0x5d}, - {OP_WR_E1H, TCM_REG_PHYS_QNUM1_0, 0x57}, - {OP_WR_E1H, TCM_REG_PHYS_QNUM2_0, 0x57}, - {OP_WR_E1H, TCM_REG_PHYS_QNUM3_0, 0x57}, -#define TCM_FUNC6_END 187 -#define TCM_FUNC7_START 187 - {OP_WR_E1H, TCM_REG_PHYS_QNUM0_1, 0x7d}, - {OP_WR_E1H, TCM_REG_PHYS_QNUM1_1, 0x77}, - {OP_WR_E1H, TCM_REG_PHYS_QNUM2_1, 0x77}, - {OP_WR_E1H, TCM_REG_PHYS_QNUM3_1, 0x77}, -#define TCM_FUNC7_END 191 -#define BRB1_COMMON_START 191 - {OP_SW, BRB1_REG_LL_RAM, 0x2000020}, - {OP_WR, BRB1_REG_SOFT_RESET, 0x1}, - {OP_RD, BRB1_REG_NUM_OF_FULL_CYCLES_4, 0x0}, - {OP_SW, BRB1_REG_FREE_LIST_PRS_CRDT, 0x30220}, - {OP_WR, BRB1_REG_SOFT_RESET, 0x0}, -#define BRB1_COMMON_END 196 -#define BRB1_PORT0_START 196 - {OP_WR_E1, BRB1_REG_PAUSE_LOW_THRESHOLD_0, 0xb8}, - {OP_WR_E1, BRB1_REG_PAUSE_HIGH_THRESHOLD_0, 0x114}, - {OP_RD, BRB1_REG_NUM_OF_PAUSE_CYCLES_0, 0x0}, - {OP_RD, BRB1_REG_NUM_OF_FULL_CYCLES_0, 0x0}, -#define BRB1_PORT0_END 200 -#define BRB1_PORT1_START 200 - {OP_WR_E1, BRB1_REG_PAUSE_LOW_THRESHOLD_1, 0xb8}, - {OP_WR_E1, BRB1_REG_PAUSE_HIGH_THRESHOLD_1, 0x114}, - {OP_RD, BRB1_REG_NUM_OF_PAUSE_CYCLES_1, 0x0}, - {OP_RD, BRB1_REG_NUM_OF_FULL_CYCLES_1, 0x0}, -#define BRB1_PORT1_END 204 -#define TSEM_COMMON_START 204 - {OP_RD, TSEM_REG_MSG_NUM_FIC0, 0x0}, - {OP_RD, TSEM_REG_MSG_NUM_FIC1, 0x0}, - {OP_RD, TSEM_REG_MSG_NUM_FOC0, 0x0}, - {OP_RD, TSEM_REG_MSG_NUM_FOC1, 0x0}, - {OP_RD, TSEM_REG_MSG_NUM_FOC2, 0x0}, - {OP_RD, TSEM_REG_MSG_NUM_FOC3, 0x0}, - {OP_WR, TSEM_REG_ARB_ELEMENT0, 0x1}, - {OP_WR, TSEM_REG_ARB_ELEMENT1, 0x2}, - {OP_WR, TSEM_REG_ARB_ELEMENT2, 0x3}, - {OP_WR, TSEM_REG_ARB_ELEMENT3, 0x0}, - {OP_WR, TSEM_REG_ARB_ELEMENT4, 0x4}, - {OP_WR, TSEM_REG_ARB_CYCLE_SIZE, 0x1}, - {OP_WR, TSEM_REG_TS_0_AS, 0x0}, - {OP_WR, TSEM_REG_TS_1_AS, 0x1}, - {OP_WR, TSEM_REG_TS_2_AS, 0x4}, - {OP_WR, TSEM_REG_TS_3_AS, 0x0}, - {OP_WR, TSEM_REG_TS_4_AS, 0x1}, - {OP_WR, TSEM_REG_TS_5_AS, 0x3}, - {OP_WR, TSEM_REG_TS_6_AS, 0x0}, - {OP_WR, TSEM_REG_TS_7_AS, 0x1}, - {OP_WR, TSEM_REG_TS_8_AS, 0x4}, - {OP_WR, TSEM_REG_TS_9_AS, 0x0}, - {OP_WR, TSEM_REG_TS_10_AS, 0x1}, - {OP_WR, TSEM_REG_TS_11_AS, 0x3}, - {OP_WR, TSEM_REG_TS_12_AS, 0x0}, - {OP_WR, TSEM_REG_TS_13_AS, 0x1}, - {OP_WR, TSEM_REG_TS_14_AS, 0x4}, - {OP_WR, TSEM_REG_TS_15_AS, 0x0}, - {OP_WR, TSEM_REG_TS_16_AS, 0x4}, - {OP_WR, TSEM_REG_TS_17_AS, 0x3}, - {OP_ZR, TSEM_REG_TS_18_AS, 0x2}, - {OP_WR, TSEM_REG_ENABLE_IN, 0x3fff}, - {OP_WR, TSEM_REG_ENABLE_OUT, 0x3ff}, - {OP_WR, TSEM_REG_FIC0_DISABLE, 0x0}, - {OP_WR, TSEM_REG_FIC1_DISABLE, 0x0}, - {OP_WR, TSEM_REG_PAS_DISABLE, 0x0}, - {OP_WR, TSEM_REG_THREADS_LIST, 0xff}, - {OP_ZR, TSEM_REG_PASSIVE_BUFFER, 0x400}, - {OP_WR, TSEM_REG_FAST_MEMORY + 0x18bc0, 0x1}, - {OP_WR, TSEM_REG_FAST_MEMORY + 0x18000, 0x34}, - {OP_WR, TSEM_REG_FAST_MEMORY + 0x18040, 0x18}, - {OP_WR, TSEM_REG_FAST_MEMORY + 0x18080, 0xc}, - {OP_WR, TSEM_REG_FAST_MEMORY + 0x180c0, 0x20}, - {OP_WR_ASIC, TSEM_REG_FAST_MEMORY + 0x18300, 0x7a120}, - {OP_WR_EMUL, TSEM_REG_FAST_MEMORY + 0x18300, 0x138}, - {OP_WR_FPGA, TSEM_REG_FAST_MEMORY + 0x18300, 0x1388}, - {OP_WR, TSEM_REG_FAST_MEMORY + 0x183c0, 0x1f4}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x2000, 0xb2}, - {OP_WR_E1H, TSEM_REG_FAST_MEMORY + 0x11480, 0x1}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x23c8, 0xc1}, - {OP_WR_EMUL_E1H, TSEM_REG_FAST_MEMORY + 0x11480, 0x0}, - {OP_SW_E1, TSEM_REG_FAST_MEMORY + 0x23c8 + 0x304, 0x10223}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x1000, 0x2b3}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x1020, 0xc8}, - {OP_SW_E1H, TSEM_REG_FAST_MEMORY + 0x1000 + 0xacc, 0x10223}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x1000, 0x2}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0xa020, 0xc8}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x1c18, 0x4}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0xa000, 0x2}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x1c10, 0x2}, - {OP_WR_E1H, TSEM_REG_FAST_MEMORY + 0x1ad0, 0x0}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x800, 0x2}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x1ad8, 0x4}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x808, 0x2}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x3678, 0x6}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x810, 0x4}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x3670, 0x2}, - {OP_SW_E1, TSEM_REG_FAST_MEMORY + 0x1fb0, 0x40224}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x5000, 0x2}, - {OP_SW_E1, TSEM_REG_FAST_MEMORY + 0x4cb0, 0x80228}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x5008, 0x4}, - {OP_ZP_E1, TSEM_REG_INT_TABLE, 0x930000}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x5018, 0x4}, - {OP_WR_64_E1, TSEM_REG_INT_TABLE + 0x360, 0x140230}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x5028, 0x4}, - {OP_ZP_E1, TSEM_REG_PRAM, 0x324f0000}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x5038, 0x4}, - {OP_ZP_E1, TSEM_REG_PRAM + 0x8000, 0x33250c94}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x5048, 0x4}, - {OP_ZP_E1, TSEM_REG_PRAM + 0x10000, 0xe4d195e}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x5058, 0x4}, - {OP_WR_64_E1, TSEM_REG_PRAM + 0x11e00, 0x5c400232}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x5068, 0x4}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x5078, 0x2}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x4000, 0x2}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x4008, 0x2}, - {OP_SW_E1H, TSEM_REG_FAST_MEMORY + 0x62c0, 0x200224}, - {OP_ZP_E1H, TSEM_REG_INT_TABLE, 0x9b0000}, - {OP_WR_64_E1H, TSEM_REG_INT_TABLE + 0x398, 0xd0244}, - {OP_ZP_E1H, TSEM_REG_PRAM, 0x325e0000}, - {OP_ZP_E1H, TSEM_REG_PRAM + 0x8000, 0x35960c98}, - {OP_ZP_E1H, TSEM_REG_PRAM + 0x10000, 0x1aea19fe}, - {OP_WR_64_E1H, TSEM_REG_PRAM + 0x143d0, 0x57860246}, -#define TSEM_COMMON_END 297 -#define TSEM_PORT0_START 297 - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x22c8, 0x20}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x2000, 0x16c}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x4000, 0x16c}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0xb000, 0x28}, - {OP_WR_E1, TSEM_REG_FAST_MEMORY + 0x4b60, 0x0}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0xb140, 0xc}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x1400, 0xa}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x32c0, 0x12}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x1450, 0x6}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x3350, 0x64}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x1500, 0x2}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x8108, 0x2}, - {OP_SW_E1, TSEM_REG_FAST_MEMORY + 0x1500 + 0x8, 0x50234}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x1500 + 0x1c, 0x7}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x1570, 0x12}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x9c0, 0x4c}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x800, 0x2}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x820, 0xe}, - {OP_SW_E1, TSEM_REG_FAST_MEMORY + 0x1fb0, 0x20239}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x2908, 0x2}, -#define TSEM_PORT0_END 317 -#define TSEM_PORT1_START 317 - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x2348, 0x20}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x25b0, 0x16c}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x45b0, 0x16c}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0xb0a0, 0x28}, - {OP_WR_E1, TSEM_REG_FAST_MEMORY + 0x4b64, 0x0}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0xb170, 0xc}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x1428, 0xa}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x3308, 0x12}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x1468, 0x6}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x34e0, 0x64}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x1538, 0x2}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x8110, 0x2}, - {OP_SW_E1, TSEM_REG_FAST_MEMORY + 0x1538 + 0x8, 0x5023b}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x1538 + 0x1c, 0x7}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x15b8, 0x12}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0xaf0, 0x4c}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x808, 0x2}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x858, 0xe}, - {OP_SW_E1, TSEM_REG_FAST_MEMORY + 0x1fb8, 0x20240}, - {OP_ZR_E1, TSEM_REG_FAST_MEMORY + 0x2910, 0x2}, -#define TSEM_PORT1_END 337 -#define TSEM_FUNC0_START 337 - {OP_WR_E1H, TSEM_REG_FAST_MEMORY + 0x2b60, 0x0}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x3000, 0x2}, - {OP_SW_E1H, TSEM_REG_FAST_MEMORY + 0x3000 + 0x8, 0x50248}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x3000 + 0x1c, 0x7}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x31c0, 0x8}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x5000, 0x2}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x5080, 0x12}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x4000, 0x2}, -#define TSEM_FUNC0_END 345 -#define TSEM_FUNC1_START 345 - {OP_WR_E1H, TSEM_REG_FAST_MEMORY + 0x2b64, 0x0}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x3038, 0x2}, - {OP_SW_E1H, TSEM_REG_FAST_MEMORY + 0x3038 + 0x8, 0x5024d}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x3038 + 0x1c, 0x7}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x31e0, 0x8}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x5010, 0x2}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x50c8, 0x12}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x4008, 0x2}, -#define TSEM_FUNC1_END 353 -#define TSEM_FUNC2_START 353 - {OP_WR_E1H, TSEM_REG_FAST_MEMORY + 0x2b68, 0x0}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x3070, 0x2}, - {OP_SW_E1H, TSEM_REG_FAST_MEMORY + 0x3070 + 0x8, 0x50252}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x3070 + 0x1c, 0x7}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x3200, 0x8}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x5020, 0x2}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x5110, 0x12}, - {OP_SW_E1H, TSEM_REG_FAST_MEMORY + 0x4010, 0x20257}, -#define TSEM_FUNC2_END 361 -#define TSEM_FUNC3_START 361 - {OP_WR_E1H, TSEM_REG_FAST_MEMORY + 0x2b6c, 0x0}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x30a8, 0x2}, - {OP_SW_E1H, TSEM_REG_FAST_MEMORY + 0x30a8 + 0x8, 0x50259}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x30a8 + 0x1c, 0x7}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x3220, 0x8}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x5030, 0x2}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x5158, 0x12}, - {OP_SW_E1H, TSEM_REG_FAST_MEMORY + 0x4018, 0x2025e}, -#define TSEM_FUNC3_END 369 -#define TSEM_FUNC4_START 369 - {OP_WR_E1H, TSEM_REG_FAST_MEMORY + 0x2b70, 0x0}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x30e0, 0x2}, - {OP_SW_E1H, TSEM_REG_FAST_MEMORY + 0x30e0 + 0x8, 0x50260}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x30e0 + 0x1c, 0x7}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x3240, 0x8}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x5040, 0x2}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x51a0, 0x12}, - {OP_SW_E1H, TSEM_REG_FAST_MEMORY + 0x4020, 0x20265}, -#define TSEM_FUNC4_END 377 -#define TSEM_FUNC5_START 377 - {OP_WR_E1H, TSEM_REG_FAST_MEMORY + 0x2b74, 0x0}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x3118, 0x2}, - {OP_SW_E1H, TSEM_REG_FAST_MEMORY + 0x3118 + 0x8, 0x50267}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x3118 + 0x1c, 0x7}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x3260, 0x8}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x5050, 0x2}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x51e8, 0x12}, - {OP_SW_E1H, TSEM_REG_FAST_MEMORY + 0x4028, 0x2026c}, -#define TSEM_FUNC5_END 385 -#define TSEM_FUNC6_START 385 - {OP_WR_E1H, TSEM_REG_FAST_MEMORY + 0x2b78, 0x0}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x3150, 0x2}, - {OP_SW_E1H, TSEM_REG_FAST_MEMORY + 0x3150 + 0x8, 0x5026e}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x3150 + 0x1c, 0x7}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x3280, 0x8}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x5060, 0x2}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x5230, 0x12}, - {OP_SW_E1H, TSEM_REG_FAST_MEMORY + 0x4030, 0x20273}, -#define TSEM_FUNC6_END 393 -#define TSEM_FUNC7_START 393 - {OP_WR_E1H, TSEM_REG_FAST_MEMORY + 0x2b7c, 0x0}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x3188, 0x2}, - {OP_SW_E1H, TSEM_REG_FAST_MEMORY + 0x3188 + 0x8, 0x50275}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x3188 + 0x1c, 0x7}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x32a0, 0x8}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x5070, 0x2}, - {OP_ZR_E1H, TSEM_REG_FAST_MEMORY + 0x5278, 0x12}, - {OP_SW_E1H, TSEM_REG_FAST_MEMORY + 0x4038, 0x2027a}, -#define TSEM_FUNC7_END 401 -#define MISC_COMMON_START 401 - {OP_WR_E1, MISC_REG_GRC_TIMEOUT_EN, 0x1}, - {OP_WR, MISC_REG_PLL_STORM_CTRL_1, 0x71d2911}, - {OP_WR, MISC_REG_PLL_STORM_CTRL_2, 0x0}, - {OP_WR, MISC_REG_PLL_STORM_CTRL_3, 0x9c0424}, - {OP_WR, MISC_REG_PLL_STORM_CTRL_4, 0x0}, - {OP_WR, MISC_REG_LCPLL_CTRL_1, 0x209}, - {OP_WR_E1, MISC_REG_SPIO, 0xff000000}, -#define MISC_COMMON_END 408 -#define MISC_FUNC0_START 408 - {OP_WR_E1H, MISC_REG_NIG_WOL_P0, 0x0}, -#define MISC_FUNC0_END 409 -#define MISC_FUNC1_START 409 - {OP_WR_E1H, MISC_REG_NIG_WOL_P1, 0x0}, -#define MISC_FUNC1_END 410 -#define MISC_FUNC2_START 410 - {OP_WR_E1H, MISC_REG_NIG_WOL_P0, 0x0}, -#define MISC_FUNC2_END 411 -#define MISC_FUNC3_START 411 - {OP_WR_E1H, MISC_REG_NIG_WOL_P1, 0x0}, -#define MISC_FUNC3_END 412 -#define MISC_FUNC4_START 412 - {OP_WR_E1H, MISC_REG_NIG_WOL_P0, 0x0}, -#define MISC_FUNC4_END 413 -#define MISC_FUNC5_START 413 - {OP_WR_E1H, MISC_REG_NIG_WOL_P1, 0x0}, -#define MISC_FUNC5_END 414 -#define MISC_FUNC6_START 414 - {OP_WR_E1H, MISC_REG_NIG_WOL_P0, 0x0}, -#define MISC_FUNC6_END 415 -#define MISC_FUNC7_START 415 - {OP_WR_E1H, MISC_REG_NIG_WOL_P1, 0x0}, -#define MISC_FUNC7_END 416 -#define NIG_COMMON_START 416 - {OP_WR, NIG_REG_PBF_LB_IN_EN, 0x1}, - {OP_WR, NIG_REG_PRS_REQ_IN_EN, 0x1}, - {OP_WR, NIG_REG_EGRESS_DEBUG_IN_EN, 0x1}, - {OP_WR, NIG_REG_BRB_LB_OUT_EN, 0x1}, - {OP_WR, NIG_REG_PRS_EOP_OUT_EN, 0x1}, -#define NIG_COMMON_END 421 -#define NIG_PORT0_START 421 - {OP_WR, NIG_REG_LLH0_CM_HEADER, 0x300000}, - {OP_WR, NIG_REG_LLH0_EVENT_ID, 0x28}, - {OP_WR, NIG_REG_LLH0_ERROR_MASK, 0x0}, - {OP_WR, NIG_REG_LLH0_XCM_MASK, 0x4}, - {OP_WR, NIG_REG_LLH0_BRB1_NOT_MCP, 0x1}, - {OP_WR, NIG_REG_STATUS_INTERRUPT_PORT0, 0x0}, - {OP_WR_E1H, NIG_REG_LLH0_CLS_TYPE, 0x1}, - {OP_WR, NIG_REG_LLH0_XCM_INIT_CREDIT, 0x30}, - {OP_WR, NIG_REG_BRB0_PAUSE_IN_EN, 0x1}, - {OP_WR, NIG_REG_EGRESS_PBF0_IN_EN, 0x1}, - {OP_WR, NIG_REG_BRB0_OUT_EN, 0x1}, - {OP_WR, NIG_REG_XCM0_OUT_EN, 0x1}, -#define NIG_PORT0_END 433 -#define NIG_PORT1_START 433 - {OP_WR, NIG_REG_LLH1_CM_HEADER, 0x300000}, - {OP_WR, NIG_REG_LLH1_EVENT_ID, 0x28}, - {OP_WR, NIG_REG_LLH1_ERROR_MASK, 0x0}, - {OP_WR, NIG_REG_LLH1_XCM_MASK, 0x4}, - {OP_WR, NIG_REG_LLH1_BRB1_NOT_MCP, 0x1}, - {OP_WR, NIG_REG_STATUS_INTERRUPT_PORT1, 0x0}, - {OP_WR_E1H, NIG_REG_LLH1_CLS_TYPE, 0x1}, - {OP_WR, NIG_REG_LLH1_XCM_INIT_CREDIT, 0x30}, - {OP_WR, NIG_REG_BRB1_PAUSE_IN_EN, 0x1}, - {OP_WR, NIG_REG_EGRESS_PBF1_IN_EN, 0x1}, - {OP_WR, NIG_REG_BRB1_OUT_EN, 0x1}, - {OP_WR, NIG_REG_XCM1_OUT_EN, 0x1}, -#define NIG_PORT1_END 445 -#define UPB_COMMON_START 445 - {OP_WR, GRCBASE_UPB + PB_REG_CONTROL, 0x20}, -#define UPB_COMMON_END 446 -#define CSDM_COMMON_START 446 - {OP_WR_E1, CSDM_REG_CFC_RSP_START_ADDR, 0xa11}, - {OP_WR_E1H, CSDM_REG_CFC_RSP_START_ADDR, 0x211}, - {OP_WR_E1, CSDM_REG_CMP_COUNTER_START_ADDR, 0xa00}, - {OP_WR_E1H, CSDM_REG_CMP_COUNTER_START_ADDR, 0x200}, - {OP_WR_E1, CSDM_REG_Q_COUNTER_START_ADDR, 0xa04}, - {OP_WR_E1H, CSDM_REG_Q_COUNTER_START_ADDR, 0x204}, - {OP_WR, CSDM_REG_CMP_COUNTER_MAX0, 0xffff}, - {OP_WR, CSDM_REG_CMP_COUNTER_MAX1, 0xffff}, - {OP_WR, CSDM_REG_CMP_COUNTER_MAX2, 0xffff}, - {OP_WR, CSDM_REG_CMP_COUNTER_MAX3, 0xffff}, - {OP_WR, CSDM_REG_AGG_INT_EVENT_0, 0xc6}, - {OP_WR, CSDM_REG_AGG_INT_EVENT_1, 0x0}, - {OP_WR, CSDM_REG_AGG_INT_EVENT_2, 0x34}, - {OP_WR, CSDM_REG_AGG_INT_EVENT_3, 0x35}, - {OP_ZR, CSDM_REG_AGG_INT_EVENT_4, 0x1c}, - {OP_WR, CSDM_REG_AGG_INT_T_0, 0x1}, - {OP_ZR, CSDM_REG_AGG_INT_T_1, 0x5f}, - {OP_WR, CSDM_REG_ENABLE_IN1, 0x7ffffff}, - {OP_WR, CSDM_REG_ENABLE_IN2, 0x3f}, - {OP_WR, CSDM_REG_ENABLE_OUT1, 0x7ffffff}, - {OP_WR, CSDM_REG_ENABLE_OUT2, 0xf}, - {OP_RD, CSDM_REG_NUM_OF_Q0_CMD, 0x0}, - {OP_RD, CSDM_REG_NUM_OF_Q1_CMD, 0x0}, - {OP_RD, CSDM_REG_NUM_OF_Q3_CMD, 0x0}, - {OP_RD, CSDM_REG_NUM_OF_Q4_CMD, 0x0}, - {OP_RD, CSDM_REG_NUM_OF_Q5_CMD, 0x0}, - {OP_RD, CSDM_REG_NUM_OF_Q6_CMD, 0x0}, - {OP_RD, CSDM_REG_NUM_OF_Q7_CMD, 0x0}, - {OP_RD, CSDM_REG_NUM_OF_Q8_CMD, 0x0}, - {OP_RD, CSDM_REG_NUM_OF_Q9_CMD, 0x0}, - {OP_RD, CSDM_REG_NUM_OF_Q10_CMD, 0x0}, - {OP_RD, CSDM_REG_NUM_OF_Q11_CMD, 0x0}, - {OP_RD, CSDM_REG_NUM_OF_PKT_END_MSG, 0x0}, - {OP_RD, CSDM_REG_NUM_OF_PXP_ASYNC_REQ, 0x0}, - {OP_RD, CSDM_REG_NUM_OF_ACK_AFTER_PLACE, 0x0}, - {OP_WR_E1, CSDM_REG_INIT_CREDIT_PXP_CTRL, 0x1}, - {OP_WR_ASIC, CSDM_REG_TIMER_TICK, 0x3e8}, - {OP_WR_EMUL, CSDM_REG_TIMER_TICK, 0x1}, - {OP_WR_FPGA, CSDM_REG_TIMER_TICK, 0xa}, -#define CSDM_COMMON_END 485 -#define USDM_COMMON_START 485 - {OP_WR_E1, USDM_REG_CFC_RSP_START_ADDR, 0xa11}, - {OP_WR_E1H, USDM_REG_CFC_RSP_START_ADDR, 0x411}, - {OP_WR_E1, USDM_REG_CMP_COUNTER_START_ADDR, 0xa00}, - {OP_WR_E1H, USDM_REG_CMP_COUNTER_START_ADDR, 0x400}, - {OP_WR_E1, USDM_REG_Q_COUNTER_START_ADDR, 0xa04}, - {OP_WR_E1H, USDM_REG_Q_COUNTER_START_ADDR, 0x404}, - {OP_WR_E1, USDM_REG_PCK_END_MSG_START_ADDR, 0xa21}, - {OP_WR_E1H, USDM_REG_PCK_END_MSG_START_ADDR, 0x421}, - {OP_WR, USDM_REG_CMP_COUNTER_MAX0, 0xffff}, - {OP_WR, USDM_REG_CMP_COUNTER_MAX1, 0xffff}, - {OP_WR, USDM_REG_CMP_COUNTER_MAX2, 0xffff}, - {OP_WR, USDM_REG_CMP_COUNTER_MAX3, 0xffff}, - {OP_WR, USDM_REG_AGG_INT_EVENT_0, 0x46}, - {OP_WR, USDM_REG_AGG_INT_EVENT_1, 0x5}, - {OP_WR, USDM_REG_AGG_INT_EVENT_2, 0x34}, - {OP_WR, USDM_REG_AGG_INT_EVENT_3, 0x35}, - {OP_ZR_E1, USDM_REG_AGG_INT_EVENT_4, 0x5c}, - {OP_WR_E1H, USDM_REG_AGG_INT_EVENT_4, 0x7}, - {OP_ZR_E1H, USDM_REG_AGG_INT_EVENT_5, 0x5b}, - {OP_WR, USDM_REG_AGG_INT_MODE_0, 0x1}, - {OP_ZR_E1, USDM_REG_AGG_INT_MODE_1, 0x1f}, - {OP_ZR_E1H, USDM_REG_AGG_INT_MODE_1, 0x3}, - {OP_WR_E1H, USDM_REG_AGG_INT_MODE_4, 0x1}, - {OP_ZR_E1H, USDM_REG_AGG_INT_MODE_5, 0x1b}, - {OP_WR, USDM_REG_ENABLE_IN1, 0x7ffffff}, - {OP_WR, USDM_REG_ENABLE_IN2, 0x3f}, - {OP_WR, USDM_REG_ENABLE_OUT1, 0x7ffffff}, - {OP_WR, USDM_REG_ENABLE_OUT2, 0xf}, - {OP_RD, USDM_REG_NUM_OF_Q0_CMD, 0x0}, - {OP_RD, USDM_REG_NUM_OF_Q1_CMD, 0x0}, - {OP_RD, USDM_REG_NUM_OF_Q2_CMD, 0x0}, - {OP_RD, USDM_REG_NUM_OF_Q3_CMD, 0x0}, - {OP_RD, USDM_REG_NUM_OF_Q4_CMD, 0x0}, - {OP_RD, USDM_REG_NUM_OF_Q5_CMD, 0x0}, - {OP_RD, USDM_REG_NUM_OF_Q6_CMD, 0x0}, - {OP_RD, USDM_REG_NUM_OF_Q7_CMD, 0x0}, - {OP_RD, USDM_REG_NUM_OF_Q8_CMD, 0x0}, - {OP_RD, USDM_REG_NUM_OF_Q9_CMD, 0x0}, - {OP_RD, USDM_REG_NUM_OF_Q10_CMD, 0x0}, - {OP_RD, USDM_REG_NUM_OF_Q11_CMD, 0x0}, - {OP_RD, USDM_REG_NUM_OF_PKT_END_MSG, 0x0}, - {OP_RD, USDM_REG_NUM_OF_PXP_ASYNC_REQ, 0x0}, - {OP_RD, USDM_REG_NUM_OF_ACK_AFTER_PLACE, 0x0}, - {OP_WR_E1, USDM_REG_INIT_CREDIT_PXP_CTRL, 0x1}, - {OP_WR_ASIC, USDM_REG_TIMER_TICK, 0x3e8}, - {OP_WR_EMUL, USDM_REG_TIMER_TICK, 0x1}, - {OP_WR_FPGA, USDM_REG_TIMER_TICK, 0xa}, -#define USDM_COMMON_END 532 -#define CCM_COMMON_START 532 - {OP_WR, CCM_REG_XX_OVFL_EVNT_ID, 0x32}, - {OP_WR, CCM_REG_CQM_CCM_HDR_P, 0x2150020}, - {OP_WR, CCM_REG_CQM_CCM_HDR_S, 0x2150020}, - {OP_WR, CCM_REG_ERR_CCM_HDR, 0x8100000}, - {OP_WR, CCM_REG_ERR_EVNT_ID, 0x33}, - {OP_WR, CCM_REG_STORM_WEIGHT, 0x2}, - {OP_WR, CCM_REG_TSEM_WEIGHT, 0x0}, - {OP_WR, CCM_REG_XSEM_WEIGHT, 0x5}, - {OP_WR, CCM_REG_USEM_WEIGHT, 0x5}, - {OP_ZR, CCM_REG_PBF_WEIGHT, 0x2}, - {OP_WR, CCM_REG_CSDM_WEIGHT, 0x2}, - {OP_WR, CCM_REG_CQM_P_WEIGHT, 0x3}, - {OP_WR, CCM_REG_CQM_S_WEIGHT, 0x2}, - {OP_WR, CCM_REG_CCM_CQM_USE_Q, 0x1}, - {OP_WR, CCM_REG_CNT_AUX1_Q, 0x2}, - {OP_WR, CCM_REG_CNT_AUX2_Q, 0x2}, - {OP_WR, CCM_REG_INV_DONE_Q, 0x1}, - {OP_WR, CCM_REG_GR_ARB_TYPE, 0x1}, - {OP_WR, CCM_REG_GR_LD0_PR, 0x1}, - {OP_WR, CCM_REG_GR_LD1_PR, 0x2}, - {OP_WR, CCM_REG_CFC_INIT_CRD, 0x1}, - {OP_WR, CCM_REG_CQM_INIT_CRD, 0x20}, - {OP_WR, CCM_REG_FIC0_INIT_CRD, 0x40}, - {OP_WR, CCM_REG_FIC1_INIT_CRD, 0x40}, - {OP_WR, CCM_REG_XX_INIT_CRD, 0x3}, - {OP_WR, CCM_REG_XX_MSG_NUM, 0x18}, - {OP_ZR, CCM_REG_XX_TABLE, 0x12}, - {OP_SW_E1, CCM_REG_XX_DESCR_TABLE, 0x240242}, - {OP_SW_E1H, CCM_REG_XX_DESCR_TABLE, 0x24027c}, - {OP_WR, CCM_REG_N_SM_CTX_LD_0, 0x1}, - {OP_WR, CCM_REG_N_SM_CTX_LD_1, 0x2}, - {OP_WR, CCM_REG_N_SM_CTX_LD_2, 0x8}, - {OP_WR, CCM_REG_N_SM_CTX_LD_3, 0x8}, - {OP_ZR, CCM_REG_N_SM_CTX_LD_4, 0x4}, - {OP_WR, CCM_REG_CCM_REG0_SZ, 0x4}, - {OP_WR_E1, CCM_REG_QOS_PHYS_QNUM0_0, 0x9}, - {OP_WR_E1, CCM_REG_QOS_PHYS_QNUM0_1, 0x29}, - {OP_WR_E1, CCM_REG_QOS_PHYS_QNUM1_0, 0xa}, - {OP_WR_E1, CCM_REG_QOS_PHYS_QNUM1_1, 0x2a}, - {OP_WR_E1, CCM_REG_QOS_PHYS_QNUM2_0, 0x7}, - {OP_WR_E1, CCM_REG_QOS_PHYS_QNUM2_1, 0x27}, - {OP_WR_E1, CCM_REG_QOS_PHYS_QNUM3_0, 0x7}, - {OP_WR_E1, CCM_REG_QOS_PHYS_QNUM3_1, 0x27}, - {OP_WR_E1, CCM_REG_PHYS_QNUM1_0, 0xc}, - {OP_WR_E1, CCM_REG_PHYS_QNUM1_1, 0x2c}, - {OP_WR_E1, CCM_REG_PHYS_QNUM2_0, 0xc}, - {OP_WR_E1, CCM_REG_PHYS_QNUM2_1, 0x2c}, - {OP_WR_E1, CCM_REG_PHYS_QNUM3_0, 0xc}, - {OP_WR_E1, CCM_REG_PHYS_QNUM3_1, 0x2c}, - {OP_WR, CCM_REG_CCM_STORM0_IFEN, 0x1}, - {OP_WR, CCM_REG_CCM_STORM1_IFEN, 0x1}, - {OP_WR, CCM_REG_CCM_CQM_IFEN, 0x1}, - {OP_WR, CCM_REG_STORM_CCM_IFEN, 0x1}, - {OP_WR, CCM_REG_CQM_CCM_IFEN, 0x1}, - {OP_WR, CCM_REG_CSDM_IFEN, 0x1}, - {OP_WR, CCM_REG_TSEM_IFEN, 0x1}, - {OP_WR, CCM_REG_XSEM_IFEN, 0x1}, - {OP_WR, CCM_REG_USEM_IFEN, 0x1}, - {OP_WR, CCM_REG_PBF_IFEN, 0x1}, - {OP_WR, CCM_REG_CDU_AG_WR_IFEN, 0x1}, - {OP_WR, CCM_REG_CDU_AG_RD_IFEN, 0x1}, - {OP_WR, CCM_REG_CDU_SM_WR_IFEN, 0x1}, - {OP_WR, CCM_REG_CDU_SM_RD_IFEN, 0x1}, - {OP_WR, CCM_REG_CCM_CFC_IFEN, 0x1}, -#define CCM_COMMON_END 596 -#define CCM_FUNC0_START 596 - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM0_0, 0x9}, - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM1_0, 0xa}, - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM2_0, 0x7}, - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM3_0, 0x7}, - {OP_WR_E1H, CCM_REG_PHYS_QNUM1_0, 0xc}, - {OP_WR_E1H, CCM_REG_PHYS_QNUM2_0, 0xb}, - {OP_WR_E1H, CCM_REG_PHYS_QNUM3_0, 0x7}, -#define CCM_FUNC0_END 603 -#define CCM_FUNC1_START 603 - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM0_1, 0x29}, - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM1_1, 0x2a}, - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM2_1, 0x27}, - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM3_1, 0x27}, - {OP_WR_E1H, CCM_REG_PHYS_QNUM1_1, 0x2c}, - {OP_WR_E1H, CCM_REG_PHYS_QNUM2_1, 0x2b}, - {OP_WR_E1H, CCM_REG_PHYS_QNUM3_1, 0x27}, -#define CCM_FUNC1_END 610 -#define CCM_FUNC2_START 610 - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM0_0, 0x19}, - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM1_0, 0x1a}, - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM2_0, 0x17}, - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM3_0, 0x17}, - {OP_WR_E1H, CCM_REG_PHYS_QNUM1_0, 0x1c}, - {OP_WR_E1H, CCM_REG_PHYS_QNUM2_0, 0x1b}, - {OP_WR_E1H, CCM_REG_PHYS_QNUM3_0, 0x17}, -#define CCM_FUNC2_END 617 -#define CCM_FUNC3_START 617 - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM0_1, 0x39}, - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM1_1, 0x3a}, - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM2_1, 0x37}, - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM3_1, 0x37}, - {OP_WR_E1H, CCM_REG_PHYS_QNUM1_1, 0x3c}, - {OP_WR_E1H, CCM_REG_PHYS_QNUM2_1, 0x3b}, - {OP_WR_E1H, CCM_REG_PHYS_QNUM3_1, 0x37}, -#define CCM_FUNC3_END 624 -#define CCM_FUNC4_START 624 - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM0_0, 0x49}, - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM1_0, 0x4a}, - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM2_0, 0x47}, - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM3_0, 0x47}, - {OP_WR_E1H, CCM_REG_PHYS_QNUM1_0, 0x4c}, - {OP_WR_E1H, CCM_REG_PHYS_QNUM2_0, 0x4b}, - {OP_WR_E1H, CCM_REG_PHYS_QNUM3_0, 0x47}, -#define CCM_FUNC4_END 631 -#define CCM_FUNC5_START 631 - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM0_1, 0x69}, - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM1_1, 0x6a}, - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM2_1, 0x67}, - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM3_1, 0x67}, - {OP_WR_E1H, CCM_REG_PHYS_QNUM1_1, 0x6c}, - {OP_WR_E1H, CCM_REG_PHYS_QNUM2_1, 0x6b}, - {OP_WR_E1H, CCM_REG_PHYS_QNUM3_1, 0x67}, -#define CCM_FUNC5_END 638 -#define CCM_FUNC6_START 638 - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM0_0, 0x59}, - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM1_0, 0x5a}, - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM2_0, 0x57}, - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM3_0, 0x57}, - {OP_WR_E1H, CCM_REG_PHYS_QNUM1_0, 0x5c}, - {OP_WR_E1H, CCM_REG_PHYS_QNUM2_0, 0x5b}, - {OP_WR_E1H, CCM_REG_PHYS_QNUM3_0, 0x57}, -#define CCM_FUNC6_END 645 -#define CCM_FUNC7_START 645 - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM0_1, 0x79}, - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM1_1, 0x7a}, - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM2_1, 0x77}, - {OP_WR_E1H, CCM_REG_QOS_PHYS_QNUM3_1, 0x77}, - {OP_WR_E1H, CCM_REG_PHYS_QNUM1_1, 0x7c}, - {OP_WR_E1H, CCM_REG_PHYS_QNUM2_1, 0x7b}, - {OP_WR_E1H, CCM_REG_PHYS_QNUM3_1, 0x77}, -#define CCM_FUNC7_END 652 -#define UCM_COMMON_START 652 - {OP_WR, UCM_REG_XX_OVFL_EVNT_ID, 0x32}, - {OP_WR, UCM_REG_UQM_UCM_HDR_P, 0x2150020}, - {OP_WR, UCM_REG_UQM_UCM_HDR_S, 0x2150020}, - {OP_WR, UCM_REG_TM_UCM_HDR, 0x30}, - {OP_WR, UCM_REG_ERR_UCM_HDR, 0x8100000}, - {OP_WR, UCM_REG_ERR_EVNT_ID, 0x33}, - {OP_WR, UCM_REG_EXPR_EVNT_ID, 0x30}, - {OP_WR, UCM_REG_STOP_EVNT_ID, 0x31}, - {OP_WR, UCM_REG_STORM_WEIGHT, 0x2}, - {OP_WR, UCM_REG_TSEM_WEIGHT, 0x4}, - {OP_WR, UCM_REG_CSEM_WEIGHT, 0x0}, - {OP_WR, UCM_REG_XSEM_WEIGHT, 0x2}, - {OP_WR, UCM_REG_DORQ_WEIGHT, 0x2}, - {OP_WR, UCM_REG_CP_WEIGHT, 0x0}, - {OP_WR, UCM_REG_USDM_WEIGHT, 0x2}, - {OP_WR, UCM_REG_UQM_P_WEIGHT, 0x7}, - {OP_WR, UCM_REG_UQM_S_WEIGHT, 0x2}, - {OP_WR, UCM_REG_TM_WEIGHT, 0x2}, - {OP_WR, UCM_REG_UCM_UQM_USE_Q, 0x1}, - {OP_WR, UCM_REG_INV_CFLG_Q, 0x1}, - {OP_WR, UCM_REG_GR_ARB_TYPE, 0x1}, - {OP_WR, UCM_REG_GR_LD0_PR, 0x1}, - {OP_WR, UCM_REG_GR_LD1_PR, 0x2}, - {OP_WR, UCM_REG_CFC_INIT_CRD, 0x1}, - {OP_WR, UCM_REG_FIC0_INIT_CRD, 0x40}, - {OP_WR, UCM_REG_FIC1_INIT_CRD, 0x40}, - {OP_WR, UCM_REG_TM_INIT_CRD, 0x4}, - {OP_WR, UCM_REG_UQM_INIT_CRD, 0x20}, - {OP_WR, UCM_REG_XX_INIT_CRD, 0xe}, - {OP_WR, UCM_REG_XX_MSG_NUM, 0x1b}, - {OP_ZR, UCM_REG_XX_TABLE, 0x12}, - {OP_SW_E1, UCM_REG_XX_DESCR_TABLE, 0x1b0266}, - {OP_SW_E1H, UCM_REG_XX_DESCR_TABLE, 0x1b02a0}, - {OP_WR, UCM_REG_N_SM_CTX_LD_0, 0x10}, - {OP_WR, UCM_REG_N_SM_CTX_LD_1, 0x7}, - {OP_WR, UCM_REG_N_SM_CTX_LD_2, 0xf}, - {OP_WR, UCM_REG_N_SM_CTX_LD_3, 0x10}, - {OP_ZR_E1, UCM_REG_N_SM_CTX_LD_4, 0x4}, - {OP_WR_E1H, UCM_REG_N_SM_CTX_LD_4, 0xb}, - {OP_ZR_E1H, UCM_REG_N_SM_CTX_LD_5, 0x3}, - {OP_WR, UCM_REG_UCM_REG0_SZ, 0x3}, - {OP_WR_E1, UCM_REG_PHYS_QNUM0_0, 0xf}, - {OP_WR_E1, UCM_REG_PHYS_QNUM0_1, 0x2f}, - {OP_WR_E1, UCM_REG_PHYS_QNUM1_0, 0xe}, - {OP_WR_E1, UCM_REG_PHYS_QNUM1_1, 0x2e}, - {OP_WR, UCM_REG_UCM_STORM0_IFEN, 0x1}, - {OP_WR, UCM_REG_UCM_STORM1_IFEN, 0x1}, - {OP_WR, UCM_REG_UCM_UQM_IFEN, 0x1}, - {OP_WR, UCM_REG_STORM_UCM_IFEN, 0x1}, - {OP_WR, UCM_REG_UQM_UCM_IFEN, 0x1}, - {OP_WR, UCM_REG_USDM_IFEN, 0x1}, - {OP_WR, UCM_REG_TM_UCM_IFEN, 0x1}, - {OP_WR, UCM_REG_UCM_TM_IFEN, 0x1}, - {OP_WR, UCM_REG_TSEM_IFEN, 0x1}, - {OP_WR, UCM_REG_CSEM_IFEN, 0x1}, - {OP_WR, UCM_REG_XSEM_IFEN, 0x1}, - {OP_WR, UCM_REG_DORQ_IFEN, 0x1}, - {OP_WR, UCM_REG_CDU_AG_WR_IFEN, 0x1}, - {OP_WR, UCM_REG_CDU_AG_RD_IFEN, 0x1}, - {OP_WR, UCM_REG_CDU_SM_WR_IFEN, 0x1}, - {OP_WR, UCM_REG_CDU_SM_RD_IFEN, 0x1}, - {OP_WR, UCM_REG_UCM_CFC_IFEN, 0x1}, -#define UCM_COMMON_END 714 -#define UCM_FUNC0_START 714 - {OP_WR_E1H, UCM_REG_PHYS_QNUM0_0, 0xf}, - {OP_WR_E1H, UCM_REG_PHYS_QNUM1_0, 0xe}, - {OP_WR_E1H, UCM_REG_PHYS_QNUM2_0, 0x0}, - {OP_WR_E1H, UCM_REG_PHYS_QNUM3_0, 0x0}, -#define UCM_FUNC0_END 718 -#define UCM_FUNC1_START 718 - {OP_WR_E1H, UCM_REG_PHYS_QNUM0_1, 0x2f}, - {OP_WR_E1H, UCM_REG_PHYS_QNUM1_1, 0x2e}, - {OP_WR_E1H, UCM_REG_PHYS_QNUM2_1, 0x0}, - {OP_WR_E1H, UCM_REG_PHYS_QNUM3_1, 0x0}, -#define UCM_FUNC1_END 722 -#define UCM_FUNC2_START 722 - {OP_WR_E1H, UCM_REG_PHYS_QNUM0_0, 0x1f}, - {OP_WR_E1H, UCM_REG_PHYS_QNUM1_0, 0x1e}, - {OP_WR_E1H, UCM_REG_PHYS_QNUM2_0, 0x0}, - {OP_WR_E1H, UCM_REG_PHYS_QNUM3_0, 0x0}, -#define UCM_FUNC2_END 726 -#define UCM_FUNC3_START 726 - {OP_WR_E1H, UCM_REG_PHYS_QNUM0_1, 0x3f}, - {OP_WR_E1H, UCM_REG_PHYS_QNUM1_1, 0x3e}, - {OP_WR_E1H, UCM_REG_PHYS_QNUM2_1, 0x0}, - {OP_WR_E1H, UCM_REG_PHYS_QNUM3_1, 0x0}, -#define UCM_FUNC3_END 730 -#define UCM_FUNC4_START 730 - {OP_WR_E1H, UCM_REG_PHYS_QNUM0_0, 0x4f}, - {OP_WR_E1H, UCM_REG_PHYS_QNUM1_0, 0x4e}, - {OP_WR_E1H, UCM_REG_PHYS_QNUM2_0, 0x0}, - {OP_WR_E1H, UCM_REG_PHYS_QNUM3_0, 0x0}, -#define UCM_FUNC4_END 734 -#define UCM_FUNC5_START 734 - {OP_WR_E1H, UCM_REG_PHYS_QNUM0_1, 0x6f}, - {OP_WR_E1H, UCM_REG_PHYS_QNUM1_1, 0x6e}, - {OP_WR_E1H, UCM_REG_PHYS_QNUM2_1, 0x0}, - {OP_WR_E1H, UCM_REG_PHYS_QNUM3_1, 0x0}, -#define UCM_FUNC5_END 738 -#define UCM_FUNC6_START 738 - {OP_WR_E1H, UCM_REG_PHYS_QNUM0_0, 0x5f}, - {OP_WR_E1H, UCM_REG_PHYS_QNUM1_0, 0x5e}, - {OP_WR_E1H, UCM_REG_PHYS_QNUM2_0, 0x0}, - {OP_WR_E1H, UCM_REG_PHYS_QNUM3_0, 0x0}, -#define UCM_FUNC6_END 742 -#define UCM_FUNC7_START 742 - {OP_WR_E1H, UCM_REG_PHYS_QNUM0_1, 0x7f}, - {OP_WR_E1H, UCM_REG_PHYS_QNUM1_1, 0x7e}, - {OP_WR_E1H, UCM_REG_PHYS_QNUM2_1, 0x0}, - {OP_WR_E1H, UCM_REG_PHYS_QNUM3_1, 0x0}, -#define UCM_FUNC7_END 746 -#define USEM_COMMON_START 746 - {OP_RD, USEM_REG_MSG_NUM_FIC0, 0x0}, - {OP_RD, USEM_REG_MSG_NUM_FIC1, 0x0}, - {OP_RD, USEM_REG_MSG_NUM_FOC0, 0x0}, - {OP_RD, USEM_REG_MSG_NUM_FOC1, 0x0}, - {OP_RD, USEM_REG_MSG_NUM_FOC2, 0x0}, - {OP_RD, USEM_REG_MSG_NUM_FOC3, 0x0}, - {OP_WR, USEM_REG_ARB_ELEMENT0, 0x1}, - {OP_WR, USEM_REG_ARB_ELEMENT1, 0x2}, - {OP_WR, USEM_REG_ARB_ELEMENT2, 0x3}, - {OP_WR, USEM_REG_ARB_ELEMENT3, 0x0}, - {OP_WR, USEM_REG_ARB_ELEMENT4, 0x4}, - {OP_WR, USEM_REG_ARB_CYCLE_SIZE, 0x1}, - {OP_WR, USEM_REG_TS_0_AS, 0x0}, - {OP_WR, USEM_REG_TS_1_AS, 0x1}, - {OP_WR, USEM_REG_TS_2_AS, 0x4}, - {OP_WR, USEM_REG_TS_3_AS, 0x0}, - {OP_WR, USEM_REG_TS_4_AS, 0x1}, - {OP_WR, USEM_REG_TS_5_AS, 0x3}, - {OP_WR, USEM_REG_TS_6_AS, 0x0}, - {OP_WR, USEM_REG_TS_7_AS, 0x1}, - {OP_WR, USEM_REG_TS_8_AS, 0x4}, - {OP_WR, USEM_REG_TS_9_AS, 0x0}, - {OP_WR, USEM_REG_TS_10_AS, 0x1}, - {OP_WR, USEM_REG_TS_11_AS, 0x3}, - {OP_WR, USEM_REG_TS_12_AS, 0x0}, - {OP_WR, USEM_REG_TS_13_AS, 0x1}, - {OP_WR, USEM_REG_TS_14_AS, 0x4}, - {OP_WR, USEM_REG_TS_15_AS, 0x0}, - {OP_WR, USEM_REG_TS_16_AS, 0x4}, - {OP_WR, USEM_REG_TS_17_AS, 0x3}, - {OP_ZR, USEM_REG_TS_18_AS, 0x2}, - {OP_WR, USEM_REG_ENABLE_IN, 0x3fff}, - {OP_WR, USEM_REG_ENABLE_OUT, 0x3ff}, - {OP_WR, USEM_REG_FIC0_DISABLE, 0x0}, - {OP_WR, USEM_REG_FIC1_DISABLE, 0x0}, - {OP_WR, USEM_REG_PAS_DISABLE, 0x0}, - {OP_WR, USEM_REG_THREADS_LIST, 0xffff}, - {OP_ZR, USEM_REG_PASSIVE_BUFFER, 0x800}, - {OP_WR, USEM_REG_FAST_MEMORY + 0x18bc0, 0x1}, - {OP_WR, USEM_REG_FAST_MEMORY + 0x18000, 0x1a}, - {OP_WR, USEM_REG_FAST_MEMORY + 0x18040, 0x4e}, - {OP_WR, USEM_REG_FAST_MEMORY + 0x18080, 0x10}, - {OP_WR, USEM_REG_FAST_MEMORY + 0x180c0, 0x20}, - {OP_WR_ASIC, USEM_REG_FAST_MEMORY + 0x18300, 0x7a120}, - {OP_WR_EMUL, USEM_REG_FAST_MEMORY + 0x18300, 0x138}, - {OP_WR_FPGA, USEM_REG_FAST_MEMORY + 0x18300, 0x1388}, - {OP_WR, USEM_REG_FAST_MEMORY + 0x183c0, 0x1f4}, - {OP_WR_ASIC, USEM_REG_FAST_MEMORY + 0x18380, 0x1dcd6500}, - {OP_WR_EMUL, USEM_REG_FAST_MEMORY + 0x18380, 0x4c4b4}, - {OP_WR_FPGA, USEM_REG_FAST_MEMORY + 0x18380, 0x4c4b40}, - {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x5000, 0xc2}, - {OP_WR_EMUL_E1H, USEM_REG_FAST_MEMORY + 0x11480, 0x0}, - {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x1020, 0xc8}, - {OP_WR_E1H, USEM_REG_FAST_MEMORY + 0x11480, 0x1}, - {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x1000, 0x2}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x2000, 0x102}, - {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x4640, 0x40}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x8980, 0xc8}, - {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x57f0, 0x4}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x8960, 0x2}, - {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x57d8, 0x5}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x3228, 0x4}, - {OP_SW_E1, USEM_REG_FAST_MEMORY + 0x57d8 + 0x14, 0x10281}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x3200, 0x9}, - {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x1c60, 0x20}, - {OP_SW_E1H, USEM_REG_FAST_MEMORY + 0x3200 + 0x24, 0x102bb}, - {OP_SW_E1, USEM_REG_FAST_MEMORY + 0x2830, 0x20282}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x3180, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5000, 0x400}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x4000, 0x2}, - {OP_SW_E1H, USEM_REG_FAST_MEMORY + 0x4000 + 0x8, 0x102bc}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x4000 + 0xc, 0x3}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x6b68, 0x2}, - {OP_SW_E1H, USEM_REG_FAST_MEMORY + 0x6b68 + 0x8, 0x202bd}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x6b10, 0x2}, - {OP_SW_E1H, USEM_REG_FAST_MEMORY + 0x74c0, 0x202bf}, - {OP_WR, USEM_REG_FAST_MEMORY + 0x10800, 0x1000000}, - {OP_SW_E1, USEM_REG_FAST_MEMORY + 0x10c00, 0x100284}, - {OP_SW_E1H, USEM_REG_FAST_MEMORY + 0x10c00, 0x1002c1}, - {OP_WR, USEM_REG_FAST_MEMORY + 0x10800, 0x0}, - {OP_SW_E1, USEM_REG_FAST_MEMORY + 0x10c40, 0x100294}, - {OP_SW_E1H, USEM_REG_FAST_MEMORY + 0x10c40, 0x1002d1}, - {OP_ZP_E1, USEM_REG_INT_TABLE, 0xc30000}, - {OP_ZP_E1H, USEM_REG_INT_TABLE, 0xd20000}, - {OP_WR_64_E1, USEM_REG_INT_TABLE + 0x368, 0x1302a4}, - {OP_WR_64_E1H, USEM_REG_INT_TABLE + 0x3a8, 0xb02e1}, - {OP_ZP_E1, USEM_REG_PRAM, 0x314c0000}, - {OP_ZP_E1H, USEM_REG_PRAM, 0x31b60000}, - {OP_ZP_E1, USEM_REG_PRAM + 0x8000, 0x35ef0c53}, - {OP_ZP_E1H, USEM_REG_PRAM + 0x8000, 0x36500c6e}, - {OP_ZP_E1, USEM_REG_PRAM + 0x10000, 0x361319cf}, - {OP_ZP_E1H, USEM_REG_PRAM + 0x10000, 0x37591a02}, - {OP_ZP_E1, USEM_REG_PRAM + 0x18000, 0x7112754}, - {OP_ZP_E1H, USEM_REG_PRAM + 0x18000, 0x286127d9}, - {OP_WR_64_E1, USEM_REG_PRAM + 0x18ee0, 0x4e2402a6}, - {OP_WR_64_E1H, USEM_REG_PRAM + 0x1ff40, 0x401802e3}, -#define USEM_COMMON_END 842 -#define USEM_PORT0_START 842 - {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x1400, 0xa0}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x9000, 0xa0}, - {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x1900, 0x10}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x9500, 0x40}, - {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x1980, 0x30}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x9700, 0x3c}, - {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x4740, 0xb4}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x2450, 0xb4}, - {OP_WR_E1, USEM_REG_FAST_MEMORY + 0x1d90, 0x0}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x2ad0, 0x2}, - {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x1b40, 0x4}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x3080, 0x20}, - {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x1b60, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x8000, 0x12c}, - {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x5318, 0x98}, - {OP_WR_E1H, USEM_REG_FAST_MEMORY + 0x3238, 0x0}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5000, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5100, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5200, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5300, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5400, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5500, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5600, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5700, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5800, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5900, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5a00, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5b00, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5c00, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5d00, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5e00, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5f00, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x6b78, 0x52}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x6e08, 0xc}, -#define USEM_PORT0_END 876 -#define USEM_PORT1_START 876 - {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x1680, 0xa0}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x9280, 0xa0}, - {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x1940, 0x10}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x9600, 0x40}, - {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x1a40, 0x30}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x97f0, 0x3c}, - {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x4a10, 0xb4}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x2720, 0xb4}, - {OP_WR_E1, USEM_REG_FAST_MEMORY + 0x1d94, 0x0}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x2ad8, 0x2}, - {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x1b50, 0x4}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x3100, 0x20}, - {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x1be0, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x84b0, 0x12c}, - {OP_ZR_E1, USEM_REG_FAST_MEMORY + 0x5578, 0x98}, - {OP_WR_E1H, USEM_REG_FAST_MEMORY + 0x323c, 0x0}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5080, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5180, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5280, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5380, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5480, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5580, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5680, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5780, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5880, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5980, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5a80, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5b80, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5c80, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5d80, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5e80, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x5f80, 0x20}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x6cc0, 0x52}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x6e38, 0xc}, -#define USEM_PORT1_END 910 -#define USEM_FUNC0_START 910 - {OP_WR_E1H, USEM_REG_FAST_MEMORY + 0x2a30, 0x0}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x3000, 0x4}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x4018, 0x2}, -#define USEM_FUNC0_END 913 -#define USEM_FUNC1_START 913 - {OP_WR_E1H, USEM_REG_FAST_MEMORY + 0x2a34, 0x0}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x3010, 0x4}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x4028, 0x2}, -#define USEM_FUNC1_END 916 -#define USEM_FUNC2_START 916 - {OP_WR_E1H, USEM_REG_FAST_MEMORY + 0x2a38, 0x0}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x3020, 0x4}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x4038, 0x2}, -#define USEM_FUNC2_END 919 -#define USEM_FUNC3_START 919 - {OP_WR_E1H, USEM_REG_FAST_MEMORY + 0x2a3c, 0x0}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x3030, 0x4}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x4048, 0x2}, -#define USEM_FUNC3_END 922 -#define USEM_FUNC4_START 922 - {OP_WR_E1H, USEM_REG_FAST_MEMORY + 0x2a40, 0x0}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x3040, 0x4}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x4058, 0x2}, -#define USEM_FUNC4_END 925 -#define USEM_FUNC5_START 925 - {OP_WR_E1H, USEM_REG_FAST_MEMORY + 0x2a44, 0x0}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x3050, 0x4}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x4068, 0x2}, -#define USEM_FUNC5_END 928 -#define USEM_FUNC6_START 928 - {OP_WR_E1H, USEM_REG_FAST_MEMORY + 0x2a48, 0x0}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x3060, 0x4}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x4078, 0x2}, -#define USEM_FUNC6_END 931 -#define USEM_FUNC7_START 931 - {OP_WR_E1H, USEM_REG_FAST_MEMORY + 0x2a4c, 0x0}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x3070, 0x4}, - {OP_ZR_E1H, USEM_REG_FAST_MEMORY + 0x4088, 0x2}, -#define USEM_FUNC7_END 934 -#define CSEM_COMMON_START 934 - {OP_RD, CSEM_REG_MSG_NUM_FIC0, 0x0}, - {OP_RD, CSEM_REG_MSG_NUM_FIC1, 0x0}, - {OP_RD, CSEM_REG_MSG_NUM_FOC0, 0x0}, - {OP_RD, CSEM_REG_MSG_NUM_FOC1, 0x0}, - {OP_RD, CSEM_REG_MSG_NUM_FOC2, 0x0}, - {OP_RD, CSEM_REG_MSG_NUM_FOC3, 0x0}, - {OP_WR, CSEM_REG_ARB_ELEMENT0, 0x1}, - {OP_WR, CSEM_REG_ARB_ELEMENT1, 0x2}, - {OP_WR, CSEM_REG_ARB_ELEMENT2, 0x3}, - {OP_WR, CSEM_REG_ARB_ELEMENT3, 0x0}, - {OP_WR, CSEM_REG_ARB_ELEMENT4, 0x4}, - {OP_WR, CSEM_REG_ARB_CYCLE_SIZE, 0x1}, - {OP_WR, CSEM_REG_TS_0_AS, 0x0}, - {OP_WR, CSEM_REG_TS_1_AS, 0x1}, - {OP_WR, CSEM_REG_TS_2_AS, 0x4}, - {OP_WR, CSEM_REG_TS_3_AS, 0x0}, - {OP_WR, CSEM_REG_TS_4_AS, 0x1}, - {OP_WR, CSEM_REG_TS_5_AS, 0x3}, - {OP_WR, CSEM_REG_TS_6_AS, 0x0}, - {OP_WR, CSEM_REG_TS_7_AS, 0x1}, - {OP_WR, CSEM_REG_TS_8_AS, 0x4}, - {OP_WR, CSEM_REG_TS_9_AS, 0x0}, - {OP_WR, CSEM_REG_TS_10_AS, 0x1}, - {OP_WR, CSEM_REG_TS_11_AS, 0x3}, - {OP_WR, CSEM_REG_TS_12_AS, 0x0}, - {OP_WR, CSEM_REG_TS_13_AS, 0x1}, - {OP_WR, CSEM_REG_TS_14_AS, 0x4}, - {OP_WR, CSEM_REG_TS_15_AS, 0x0}, - {OP_WR, CSEM_REG_TS_16_AS, 0x4}, - {OP_WR, CSEM_REG_TS_17_AS, 0x3}, - {OP_ZR, CSEM_REG_TS_18_AS, 0x2}, - {OP_WR, CSEM_REG_ENABLE_IN, 0x3fff}, - {OP_WR, CSEM_REG_ENABLE_OUT, 0x3ff}, - {OP_WR, CSEM_REG_FIC0_DISABLE, 0x0}, - {OP_WR, CSEM_REG_FIC1_DISABLE, 0x0}, - {OP_WR, CSEM_REG_PAS_DISABLE, 0x0}, - {OP_WR, CSEM_REG_THREADS_LIST, 0xffff}, - {OP_ZR, CSEM_REG_PASSIVE_BUFFER, 0x800}, - {OP_WR, CSEM_REG_FAST_MEMORY + 0x18bc0, 0x1}, - {OP_WR, CSEM_REG_FAST_MEMORY + 0x18000, 0x10}, - {OP_WR, CSEM_REG_FAST_MEMORY + 0x18040, 0x12}, - {OP_WR, CSEM_REG_FAST_MEMORY + 0x18080, 0x30}, - {OP_WR, CSEM_REG_FAST_MEMORY + 0x180c0, 0xe}, - {OP_WR, CSEM_REG_FAST_MEMORY + 0x183c0, 0x1f4}, - {OP_ZR_E1, CSEM_REG_FAST_MEMORY + 0x5000, 0x42}, - {OP_WR_E1H, CSEM_REG_FAST_MEMORY + 0x11480, 0x1}, - {OP_ZR_E1, CSEM_REG_FAST_MEMORY + 0x1020, 0xc8}, - {OP_WR_EMUL_E1H, CSEM_REG_FAST_MEMORY + 0x11480, 0x0}, - {OP_ZR_E1, CSEM_REG_FAST_MEMORY + 0x1000, 0x2}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x1000, 0x42}, - {OP_ZR_E1, CSEM_REG_FAST_MEMORY + 0x2000, 0xc0}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x7020, 0xc8}, - {OP_ZR_E1, CSEM_REG_FAST_MEMORY + 0x3070, 0x80}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x7000, 0x2}, - {OP_ZR_E1, CSEM_REG_FAST_MEMORY + 0x4280, 0x4}, - {OP_WR_E1H, CSEM_REG_FAST_MEMORY + 0x11e8, 0x0}, - {OP_ZR_E1, CSEM_REG_FAST_MEMORY + 0x25c0, 0x240}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x3000, 0xc0}, - {OP_SW_E1, CSEM_REG_FAST_MEMORY + 0x2ec8, 0x802a8}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x4070, 0x80}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x5280, 0x4}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x6700, 0x100}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x9000, 0x400}, - {OP_SW_E1H, CSEM_REG_FAST_MEMORY + 0x6b08, 0x2002e5}, - {OP_WR, CSEM_REG_FAST_MEMORY + 0x10800, 0x13fffff}, - {OP_SW_E1, CSEM_REG_FAST_MEMORY + 0x10c00, 0x1002b0}, - {OP_SW_E1H, CSEM_REG_FAST_MEMORY + 0x10c00, 0x100305}, - {OP_WR, CSEM_REG_FAST_MEMORY + 0x10800, 0x0}, - {OP_SW_E1, CSEM_REG_FAST_MEMORY + 0x10c40, 0x1002c0}, - {OP_SW_E1H, CSEM_REG_FAST_MEMORY + 0x10c40, 0x100315}, - {OP_ZP_E1, CSEM_REG_INT_TABLE, 0x710000}, - {OP_ZP_E1H, CSEM_REG_INT_TABLE, 0x740000}, - {OP_WR_64_E1, CSEM_REG_INT_TABLE + 0x380, 0x1002d0}, - {OP_WR_64_E1H, CSEM_REG_INT_TABLE + 0x380, 0x100325}, - {OP_ZP_E1, CSEM_REG_PRAM, 0x32290000}, - {OP_ZP_E1H, CSEM_REG_PRAM, 0x32260000}, - {OP_ZP_E1, CSEM_REG_PRAM + 0x8000, 0x23630c8b}, - {OP_ZP_E1H, CSEM_REG_PRAM + 0x8000, 0x246e0c8a}, - {OP_WR_64_E1, CSEM_REG_PRAM + 0xc930, 0x654002d2}, - {OP_WR_64_E1H, CSEM_REG_PRAM + 0xcbb0, 0x64f00327}, -#define CSEM_COMMON_END 1014 -#define CSEM_PORT0_START 1014 - {OP_ZR_E1, CSEM_REG_FAST_MEMORY + 0x1400, 0xa0}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x8000, 0xa0}, - {OP_ZR_E1, CSEM_REG_FAST_MEMORY + 0x1900, 0x10}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x8500, 0x40}, - {OP_ZR_E1, CSEM_REG_FAST_MEMORY + 0x1980, 0x30}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x8700, 0x3c}, - {OP_WR_E1, CSEM_REG_FAST_MEMORY + 0x5118, 0x0}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x4040, 0x6}, - {OP_ZR_E1, CSEM_REG_FAST_MEMORY + 0x2300, 0xe}, - {OP_ZR_E1, CSEM_REG_FAST_MEMORY + 0x3040, 0x6}, - {OP_ZR_E1, CSEM_REG_FAST_MEMORY + 0x2410, 0x30}, -#define CSEM_PORT0_END 1025 -#define CSEM_PORT1_START 1025 - {OP_ZR_E1, CSEM_REG_FAST_MEMORY + 0x1680, 0xa0}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x8280, 0xa0}, - {OP_ZR_E1, CSEM_REG_FAST_MEMORY + 0x1940, 0x10}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x8600, 0x40}, - {OP_ZR_E1, CSEM_REG_FAST_MEMORY + 0x1a40, 0x30}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x87f0, 0x3c}, - {OP_WR_E1, CSEM_REG_FAST_MEMORY + 0x511c, 0x0}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x4058, 0x6}, - {OP_ZR_E1, CSEM_REG_FAST_MEMORY + 0x2338, 0xe}, - {OP_ZR_E1, CSEM_REG_FAST_MEMORY + 0x3058, 0x6}, - {OP_ZR_E1, CSEM_REG_FAST_MEMORY + 0x24d0, 0x30}, -#define CSEM_PORT1_END 1036 -#define CSEM_FUNC0_START 1036 - {OP_WR_E1H, CSEM_REG_FAST_MEMORY + 0x1148, 0x0}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x3300, 0x2}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x6040, 0x30}, -#define CSEM_FUNC0_END 1039 -#define CSEM_FUNC1_START 1039 - {OP_WR_E1H, CSEM_REG_FAST_MEMORY + 0x114c, 0x0}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x3308, 0x2}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x6100, 0x30}, -#define CSEM_FUNC1_END 1042 -#define CSEM_FUNC2_START 1042 - {OP_WR_E1H, CSEM_REG_FAST_MEMORY + 0x1150, 0x0}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x3310, 0x2}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x61c0, 0x30}, -#define CSEM_FUNC2_END 1045 -#define CSEM_FUNC3_START 1045 - {OP_WR_E1H, CSEM_REG_FAST_MEMORY + 0x1154, 0x0}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x3318, 0x2}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x6280, 0x30}, -#define CSEM_FUNC3_END 1048 -#define CSEM_FUNC4_START 1048 - {OP_WR_E1H, CSEM_REG_FAST_MEMORY + 0x1158, 0x0}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x3320, 0x2}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x6340, 0x30}, -#define CSEM_FUNC4_END 1051 -#define CSEM_FUNC5_START 1051 - {OP_WR_E1H, CSEM_REG_FAST_MEMORY + 0x115c, 0x0}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x3328, 0x2}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x6400, 0x30}, -#define CSEM_FUNC5_END 1054 -#define CSEM_FUNC6_START 1054 - {OP_WR_E1H, CSEM_REG_FAST_MEMORY + 0x1160, 0x0}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x3330, 0x2}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x64c0, 0x30}, -#define CSEM_FUNC6_END 1057 -#define CSEM_FUNC7_START 1057 - {OP_WR_E1H, CSEM_REG_FAST_MEMORY + 0x1164, 0x0}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x3338, 0x2}, - {OP_ZR_E1H, CSEM_REG_FAST_MEMORY + 0x6580, 0x30}, -#define CSEM_FUNC7_END 1060 -#define XPB_COMMON_START 1060 - {OP_WR, GRCBASE_XPB + PB_REG_CONTROL, 0x20}, -#define XPB_COMMON_END 1061 -#define DQ_COMMON_START 1061 - {OP_WR, DORQ_REG_MODE_ACT, 0x2}, - {OP_WR, DORQ_REG_NORM_CID_OFST, 0x3}, - {OP_WR, DORQ_REG_OUTST_REQ, 0x4}, - {OP_WR, DORQ_REG_DPM_CID_ADDR, 0x8}, - {OP_WR, DORQ_REG_RSP_INIT_CRD, 0x2}, - {OP_WR, DORQ_REG_NORM_CMHEAD_TX, 0x90}, - {OP_WR, DORQ_REG_CMHEAD_RX, 0x90}, - {OP_WR, DORQ_REG_SHRT_CMHEAD, 0x800090}, - {OP_WR, DORQ_REG_ERR_CMHEAD, 0x8140000}, - {OP_WR, DORQ_REG_AGG_CMD0, 0x8a}, - {OP_WR, DORQ_REG_AGG_CMD1, 0x80}, - {OP_WR, DORQ_REG_AGG_CMD2, 0x90}, - {OP_WR, DORQ_REG_AGG_CMD3, 0x80}, - {OP_WR, DORQ_REG_SHRT_ACT_CNT, 0x6}, - {OP_WR, DORQ_REG_DQ_FIFO_FULL_TH, 0x7d0}, - {OP_WR, DORQ_REG_DQ_FIFO_AFULL_TH, 0x76c}, - {OP_WR, DORQ_REG_REGN, 0x7c1004}, - {OP_WR, DORQ_REG_IF_EN, 0xf}, -#define DQ_COMMON_END 1079 -#define TIMERS_COMMON_START 1079 - {OP_ZR, TM_REG_CLIN_PRIOR0_CLIENT, 0x2}, - {OP_WR, TM_REG_LIN_SETCLR_FIFO_ALFULL_THR, 0x1c}, - {OP_WR, TM_REG_CFC_AC_CRDCNT_VAL, 0x1}, - {OP_WR, TM_REG_CFC_CLD_CRDCNT_VAL, 0x1}, - {OP_WR, TM_REG_CLOUT_CRDCNT0_VAL, 0x1}, - {OP_WR, TM_REG_CLOUT_CRDCNT1_VAL, 0x1}, - {OP_WR, TM_REG_CLOUT_CRDCNT2_VAL, 0x1}, - {OP_WR, TM_REG_EXP_CRDCNT_VAL, 0x1}, - {OP_WR_E1, TM_REG_PCIARB_CRDCNT_VAL, 0x1}, - {OP_WR_E1H, TM_REG_PCIARB_CRDCNT_VAL, 0x2}, - {OP_WR_ASIC, TM_REG_TIMER_TICK_SIZE, 0x3d090}, - {OP_WR_EMUL, TM_REG_TIMER_TICK_SIZE, 0x9c}, - {OP_WR_FPGA, TM_REG_TIMER_TICK_SIZE, 0x9c4}, - {OP_WR, TM_REG_CL0_CONT_REGION, 0x8}, - {OP_WR, TM_REG_CL1_CONT_REGION, 0xc}, - {OP_WR, TM_REG_CL2_CONT_REGION, 0x10}, - {OP_WR, TM_REG_TM_CONTEXT_REGION, 0x20}, - {OP_WR, TM_REG_EN_TIMERS, 0x1}, - {OP_WR, TM_REG_EN_REAL_TIME_CNT, 0x1}, - {OP_WR, TM_REG_EN_CL0_INPUT, 0x1}, - {OP_WR, TM_REG_EN_CL1_INPUT, 0x1}, - {OP_WR, TM_REG_EN_CL2_INPUT, 0x1}, -#define TIMERS_COMMON_END 1101 -#define TIMERS_PORT0_START 1101 - {OP_WR, TM_REG_LIN0_LOGIC_ADDR, 0x0}, - {OP_WR, TM_REG_LIN0_PHY_ADDR_VALID, 0x0}, - {OP_ZR, TM_REG_LIN0_PHY_ADDR, 0x2}, -#define TIMERS_PORT0_END 1104 -#define TIMERS_PORT1_START 1104 - {OP_WR, TM_REG_LIN1_LOGIC_ADDR, 0x0}, - {OP_WR, TM_REG_LIN1_PHY_ADDR_VALID, 0x0}, - {OP_ZR, TM_REG_LIN1_PHY_ADDR, 0x2}, -#define TIMERS_PORT1_END 1107 -#define XSDM_COMMON_START 1107 - {OP_WR_E1, XSDM_REG_CFC_RSP_START_ADDR, 0x614}, - {OP_WR_E1H, XSDM_REG_CFC_RSP_START_ADDR, 0x424}, - {OP_WR_E1, XSDM_REG_CMP_COUNTER_START_ADDR, 0x600}, - {OP_WR_E1H, XSDM_REG_CMP_COUNTER_START_ADDR, 0x410}, - {OP_WR_E1, XSDM_REG_Q_COUNTER_START_ADDR, 0x604}, - {OP_WR_E1H, XSDM_REG_Q_COUNTER_START_ADDR, 0x414}, - {OP_WR, XSDM_REG_CMP_COUNTER_MAX0, 0xffff}, - {OP_WR, XSDM_REG_CMP_COUNTER_MAX1, 0xffff}, - {OP_WR, XSDM_REG_CMP_COUNTER_MAX2, 0xffff}, - {OP_WR, XSDM_REG_CMP_COUNTER_MAX3, 0xffff}, - {OP_WR, XSDM_REG_AGG_INT_EVENT_0, 0x20}, - {OP_WR, XSDM_REG_AGG_INT_EVENT_1, 0x20}, - {OP_WR, XSDM_REG_AGG_INT_EVENT_2, 0x34}, - {OP_WR, XSDM_REG_AGG_INT_EVENT_3, 0x35}, - {OP_WR, XSDM_REG_AGG_INT_EVENT_4, 0x23}, - {OP_WR, XSDM_REG_AGG_INT_EVENT_5, 0x24}, - {OP_WR, XSDM_REG_AGG_INT_EVENT_6, 0x25}, - {OP_WR, XSDM_REG_AGG_INT_EVENT_7, 0x26}, - {OP_WR, XSDM_REG_AGG_INT_EVENT_8, 0x27}, - {OP_WR, XSDM_REG_AGG_INT_EVENT_9, 0x29}, - {OP_WR, XSDM_REG_AGG_INT_EVENT_10, 0x2a}, - {OP_WR, XSDM_REG_AGG_INT_EVENT_11, 0x2b}, - {OP_WR, XSDM_REG_AGG_INT_EVENT_12, 0x2c}, - {OP_WR, XSDM_REG_AGG_INT_EVENT_13, 0x2d}, - {OP_ZR, XSDM_REG_AGG_INT_EVENT_14, 0x52}, - {OP_WR, XSDM_REG_AGG_INT_MODE_0, 0x1}, - {OP_ZR, XSDM_REG_AGG_INT_MODE_1, 0x1f}, - {OP_WR, XSDM_REG_ENABLE_IN1, 0x7ffffff}, - {OP_WR, XSDM_REG_ENABLE_IN2, 0x3f}, - {OP_WR, XSDM_REG_ENABLE_OUT1, 0x7ffffff}, - {OP_WR, XSDM_REG_ENABLE_OUT2, 0xf}, - {OP_RD, XSDM_REG_NUM_OF_Q0_CMD, 0x0}, - {OP_RD, XSDM_REG_NUM_OF_Q1_CMD, 0x0}, - {OP_RD, XSDM_REG_NUM_OF_Q3_CMD, 0x0}, - {OP_RD, XSDM_REG_NUM_OF_Q4_CMD, 0x0}, - {OP_RD, XSDM_REG_NUM_OF_Q5_CMD, 0x0}, - {OP_RD, XSDM_REG_NUM_OF_Q6_CMD, 0x0}, - {OP_RD, XSDM_REG_NUM_OF_Q7_CMD, 0x0}, - {OP_RD, XSDM_REG_NUM_OF_Q8_CMD, 0x0}, - {OP_RD, XSDM_REG_NUM_OF_Q9_CMD, 0x0}, - {OP_RD, XSDM_REG_NUM_OF_Q10_CMD, 0x0}, - {OP_RD, XSDM_REG_NUM_OF_Q11_CMD, 0x0}, - {OP_RD, XSDM_REG_NUM_OF_PKT_END_MSG, 0x0}, - {OP_RD, XSDM_REG_NUM_OF_PXP_ASYNC_REQ, 0x0}, - {OP_RD, XSDM_REG_NUM_OF_ACK_AFTER_PLACE, 0x0}, - {OP_WR_E1, XSDM_REG_INIT_CREDIT_PXP_CTRL, 0x1}, - {OP_WR_ASIC, XSDM_REG_TIMER_TICK, 0x3e8}, - {OP_WR_EMUL, XSDM_REG_TIMER_TICK, 0x1}, - {OP_WR_FPGA, XSDM_REG_TIMER_TICK, 0xa}, -#define XSDM_COMMON_END 1156 -#define QM_COMMON_START 1156 - {OP_WR, QM_REG_ACTCTRINITVAL_0, 0x6}, - {OP_WR, QM_REG_ACTCTRINITVAL_1, 0x5}, - {OP_WR, QM_REG_ACTCTRINITVAL_2, 0xa}, - {OP_WR, QM_REG_ACTCTRINITVAL_3, 0x5}, - {OP_WR, QM_REG_PCIREQAT, 0x2}, - {OP_WR, QM_REG_CMINITCRD_0, 0x4}, - {OP_WR, QM_REG_CMINITCRD_1, 0x4}, - {OP_WR, QM_REG_CMINITCRD_2, 0x4}, - {OP_WR, QM_REG_CMINITCRD_3, 0x4}, - {OP_WR, QM_REG_CMINITCRD_4, 0x4}, - {OP_WR, QM_REG_CMINITCRD_5, 0x4}, - {OP_WR, QM_REG_CMINITCRD_6, 0x4}, - {OP_WR, QM_REG_CMINITCRD_7, 0x4}, - {OP_WR, QM_REG_OUTLDREQ, 0x4}, - {OP_WR, QM_REG_CTXREG_0, 0x7c}, - {OP_WR, QM_REG_CTXREG_1, 0x3d}, - {OP_WR, QM_REG_CTXREG_2, 0x3f}, - {OP_WR, QM_REG_CTXREG_3, 0x9c}, - {OP_WR, QM_REG_ENSEC, 0x7}, - {OP_ZR, QM_REG_QVOQIDX_0, 0x5}, - {OP_WR, QM_REG_WRRWEIGHTS_0, 0x1010101}, - {OP_WR, QM_REG_QVOQIDX_5, 0x0}, - {OP_WR, QM_REG_QVOQIDX_6, 0x4}, - {OP_WR, QM_REG_QVOQIDX_7, 0x4}, - {OP_WR, QM_REG_QVOQIDX_8, 0x2}, - {OP_WR, QM_REG_WRRWEIGHTS_1, 0x8012004}, - {OP_WR, QM_REG_QVOQIDX_9, 0x5}, - {OP_WR, QM_REG_QVOQIDX_10, 0x5}, - {OP_WR, QM_REG_QVOQIDX_11, 0x5}, - {OP_WR, QM_REG_QVOQIDX_12, 0x5}, - {OP_WR, QM_REG_WRRWEIGHTS_2, 0x20081001}, - {OP_WR, QM_REG_QVOQIDX_13, 0x8}, - {OP_WR, QM_REG_QVOQIDX_14, 0x6}, - {OP_WR, QM_REG_QVOQIDX_15, 0x7}, - {OP_WR, QM_REG_QVOQIDX_16, 0x0}, - {OP_WR, QM_REG_WRRWEIGHTS_3, 0x1010120}, - {OP_ZR, QM_REG_QVOQIDX_17, 0x4}, - {OP_WR, QM_REG_WRRWEIGHTS_4, 0x1010101}, - {OP_ZR_E1, QM_REG_QVOQIDX_21, 0x4}, - {OP_WR_E1H, QM_REG_QVOQIDX_21, 0x0}, - {OP_WR_E1, QM_REG_WRRWEIGHTS_5, 0x1010101}, - {OP_WR_E1H, QM_REG_QVOQIDX_22, 0x4}, - {OP_ZR_E1, QM_REG_QVOQIDX_25, 0x4}, - {OP_WR_E1H, QM_REG_QVOQIDX_23, 0x4}, - {OP_WR_E1, QM_REG_WRRWEIGHTS_6, 0x1010101}, - {OP_WR_E1H, QM_REG_QVOQIDX_24, 0x2}, - {OP_ZR_E1, QM_REG_QVOQIDX_29, 0x3}, - {OP_WR_E1H, QM_REG_WRRWEIGHTS_5, 0x8012004}, - {OP_WR_E1H, QM_REG_QVOQIDX_25, 0x5}, - {OP_WR_E1H, QM_REG_QVOQIDX_26, 0x5}, - {OP_WR_E1H, QM_REG_QVOQIDX_27, 0x5}, - {OP_WR_E1H, QM_REG_QVOQIDX_28, 0x5}, - {OP_WR_E1H, QM_REG_WRRWEIGHTS_6, 0x20081001}, - {OP_WR_E1H, QM_REG_QVOQIDX_29, 0x8}, - {OP_WR_E1H, QM_REG_QVOQIDX_30, 0x6}, - {OP_WR_E1H, QM_REG_QVOQIDX_31, 0x7}, - {OP_WR, QM_REG_QVOQIDX_32, 0x1}, - {OP_WR_E1, QM_REG_WRRWEIGHTS_7, 0x1010101}, - {OP_WR_E1H, QM_REG_WRRWEIGHTS_7, 0x1010120}, - {OP_WR, QM_REG_QVOQIDX_33, 0x1}, - {OP_WR, QM_REG_QVOQIDX_34, 0x1}, - {OP_WR, QM_REG_QVOQIDX_35, 0x1}, - {OP_WR, QM_REG_QVOQIDX_36, 0x1}, - {OP_WR, QM_REG_WRRWEIGHTS_8, 0x1010101}, - {OP_WR, QM_REG_QVOQIDX_37, 0x1}, - {OP_WR, QM_REG_QVOQIDX_38, 0x4}, - {OP_WR, QM_REG_QVOQIDX_39, 0x4}, - {OP_WR, QM_REG_QVOQIDX_40, 0x2}, - {OP_WR, QM_REG_WRRWEIGHTS_9, 0x8012004}, - {OP_WR, QM_REG_QVOQIDX_41, 0x5}, - {OP_WR, QM_REG_QVOQIDX_42, 0x5}, - {OP_WR, QM_REG_QVOQIDX_43, 0x5}, - {OP_WR, QM_REG_QVOQIDX_44, 0x5}, - {OP_WR, QM_REG_WRRWEIGHTS_10, 0x20081001}, - {OP_WR, QM_REG_QVOQIDX_45, 0x8}, - {OP_WR, QM_REG_QVOQIDX_46, 0x6}, - {OP_WR, QM_REG_QVOQIDX_47, 0x7}, - {OP_WR, QM_REG_QVOQIDX_48, 0x1}, - {OP_WR, QM_REG_WRRWEIGHTS_11, 0x1010120}, - {OP_WR, QM_REG_QVOQIDX_49, 0x1}, - {OP_WR, QM_REG_QVOQIDX_50, 0x1}, - {OP_WR, QM_REG_QVOQIDX_51, 0x1}, - {OP_WR, QM_REG_QVOQIDX_52, 0x1}, - {OP_WR, QM_REG_WRRWEIGHTS_12, 0x1010101}, - {OP_WR, QM_REG_QVOQIDX_53, 0x1}, - {OP_WR_E1, QM_REG_QVOQIDX_54, 0x1}, - {OP_WR_E1H, QM_REG_QVOQIDX_54, 0x4}, - {OP_WR_E1, QM_REG_QVOQIDX_55, 0x1}, - {OP_WR_E1H, QM_REG_QVOQIDX_55, 0x4}, - {OP_WR_E1, QM_REG_QVOQIDX_56, 0x1}, - {OP_WR_E1H, QM_REG_QVOQIDX_56, 0x2}, - {OP_WR_E1, QM_REG_WRRWEIGHTS_13, 0x1010101}, - {OP_WR_E1H, QM_REG_WRRWEIGHTS_13, 0x8012004}, - {OP_WR_E1, QM_REG_QVOQIDX_57, 0x1}, - {OP_WR_E1H, QM_REG_QVOQIDX_57, 0x5}, - {OP_WR_E1, QM_REG_QVOQIDX_58, 0x1}, - {OP_WR_E1H, QM_REG_QVOQIDX_58, 0x5}, - {OP_WR_E1, QM_REG_QVOQIDX_59, 0x1}, - {OP_WR_E1H, QM_REG_QVOQIDX_59, 0x5}, - {OP_WR_E1, QM_REG_QVOQIDX_60, 0x1}, - {OP_WR_E1H, QM_REG_QVOQIDX_60, 0x5}, - {OP_WR_E1, QM_REG_WRRWEIGHTS_14, 0x1010101}, - {OP_WR_E1H, QM_REG_WRRWEIGHTS_14, 0x20081001}, - {OP_WR_E1, QM_REG_QVOQIDX_61, 0x1}, - {OP_WR_E1H, QM_REG_QVOQIDX_61, 0x8}, - {OP_WR_E1, QM_REG_QVOQIDX_62, 0x1}, - {OP_WR_E1H, QM_REG_QVOQIDX_62, 0x6}, - {OP_WR_E1, QM_REG_QVOQIDX_63, 0x1}, - {OP_WR_E1H, QM_REG_QVOQIDX_63, 0x7}, - {OP_WR_E1, QM_REG_WRRWEIGHTS_15, 0x1010101}, - {OP_WR_E1H, QM_REG_QVOQIDX_64, 0x0}, - {OP_WR_E1, QM_REG_VOQQMASK_0_LSB, 0xffff003f}, - {OP_WR_E1H, QM_REG_WRRWEIGHTS_15, 0x1010120}, - {OP_ZR_E1, QM_REG_VOQQMASK_0_MSB, 0x2}, - {OP_ZR_E1H, QM_REG_QVOQIDX_65, 0x4}, - {OP_WR_E1, QM_REG_VOQQMASK_1_MSB, 0xffff003f}, - {OP_WR_E1H, QM_REG_WRRWEIGHTS_16, 0x1010101}, - {OP_WR_E1, QM_REG_VOQQMASK_2_LSB, 0x100}, - {OP_WR_E1H, QM_REG_QVOQIDX_69, 0x0}, - {OP_WR_E1, QM_REG_VOQQMASK_2_MSB, 0x100}, - {OP_WR_E1H, QM_REG_QVOQIDX_70, 0x4}, - {OP_WR_E1H, QM_REG_QVOQIDX_71, 0x4}, - {OP_WR_E1H, QM_REG_QVOQIDX_72, 0x2}, - {OP_WR_E1H, QM_REG_WRRWEIGHTS_17, 0x8012004}, - {OP_WR_E1H, QM_REG_QVOQIDX_73, 0x5}, - {OP_WR_E1H, QM_REG_QVOQIDX_74, 0x5}, - {OP_WR_E1H, QM_REG_QVOQIDX_75, 0x5}, - {OP_WR_E1H, QM_REG_QVOQIDX_76, 0x5}, - {OP_WR_E1H, QM_REG_WRRWEIGHTS_18, 0x20081001}, - {OP_WR_E1H, QM_REG_QVOQIDX_77, 0x8}, - {OP_WR_E1H, QM_REG_QVOQIDX_78, 0x6}, - {OP_WR_E1H, QM_REG_QVOQIDX_79, 0x7}, - {OP_WR_E1H, QM_REG_QVOQIDX_80, 0x0}, - {OP_WR_E1H, QM_REG_WRRWEIGHTS_19, 0x1010120}, - {OP_ZR_E1H, QM_REG_QVOQIDX_81, 0x4}, - {OP_WR_E1H, QM_REG_WRRWEIGHTS_20, 0x1010101}, - {OP_WR_E1H, QM_REG_QVOQIDX_85, 0x0}, - {OP_WR_E1H, QM_REG_QVOQIDX_86, 0x4}, - {OP_WR_E1H, QM_REG_QVOQIDX_87, 0x4}, - {OP_WR_E1H, QM_REG_QVOQIDX_88, 0x2}, - {OP_WR_E1H, QM_REG_WRRWEIGHTS_21, 0x8012004}, - {OP_WR_E1H, QM_REG_QVOQIDX_89, 0x5}, - {OP_WR_E1H, QM_REG_QVOQIDX_90, 0x5}, - {OP_WR_E1H, QM_REG_QVOQIDX_91, 0x5}, - {OP_WR_E1H, QM_REG_QVOQIDX_92, 0x5}, - {OP_WR_E1H, QM_REG_WRRWEIGHTS_22, 0x20081001}, - {OP_WR_E1H, QM_REG_QVOQIDX_93, 0x8}, - {OP_WR_E1H, QM_REG_QVOQIDX_94, 0x6}, - {OP_WR_E1H, QM_REG_QVOQIDX_95, 0x7}, - {OP_WR_E1H, QM_REG_QVOQIDX_96, 0x1}, - {OP_WR_E1H, QM_REG_WRRWEIGHTS_23, 0x1010120}, - {OP_WR_E1H, QM_REG_QVOQIDX_97, 0x1}, - {OP_WR_E1H, QM_REG_QVOQIDX_98, 0x1}, - {OP_WR_E1H, QM_REG_QVOQIDX_99, 0x1}, - {OP_WR_E1H, QM_REG_QVOQIDX_100, 0x1}, - {OP_WR_E1H, QM_REG_WRRWEIGHTS_24, 0x1010101}, - {OP_WR_E1H, QM_REG_QVOQIDX_101, 0x1}, - {OP_WR_E1H, QM_REG_QVOQIDX_102, 0x4}, - {OP_WR_E1H, QM_REG_QVOQIDX_103, 0x4}, - {OP_WR_E1H, QM_REG_QVOQIDX_104, 0x2}, - {OP_WR_E1H, QM_REG_WRRWEIGHTS_25, 0x8012004}, - {OP_WR_E1H, QM_REG_QVOQIDX_105, 0x5}, - {OP_WR_E1H, QM_REG_QVOQIDX_106, 0x5}, - {OP_WR_E1H, QM_REG_QVOQIDX_107, 0x5}, - {OP_WR_E1H, QM_REG_QVOQIDX_108, 0x5}, - {OP_WR_E1H, QM_REG_WRRWEIGHTS_26, 0x20081001}, - {OP_WR_E1H, QM_REG_QVOQIDX_109, 0x8}, - {OP_WR_E1H, QM_REG_QVOQIDX_110, 0x6}, - {OP_WR_E1H, QM_REG_QVOQIDX_111, 0x7}, - {OP_WR_E1H, QM_REG_QVOQIDX_112, 0x1}, - {OP_WR_E1H, QM_REG_WRRWEIGHTS_27, 0x1010120}, - {OP_WR_E1H, QM_REG_QVOQIDX_113, 0x1}, - {OP_WR_E1H, QM_REG_QVOQIDX_114, 0x1}, - {OP_WR_E1H, QM_REG_QVOQIDX_115, 0x1}, - {OP_WR_E1H, QM_REG_QVOQIDX_116, 0x1}, - {OP_WR_E1H, QM_REG_WRRWEIGHTS_28, 0x1010101}, - {OP_WR_E1H, QM_REG_QVOQIDX_117, 0x1}, - {OP_WR_E1H, QM_REG_QVOQIDX_118, 0x4}, - {OP_WR_E1H, QM_REG_QVOQIDX_119, 0x4}, - {OP_WR_E1H, QM_REG_QVOQIDX_120, 0x2}, - {OP_WR_E1H, QM_REG_WRRWEIGHTS_29, 0x8012004}, - {OP_WR_E1H, QM_REG_QVOQIDX_121, 0x5}, - {OP_WR_E1H, QM_REG_QVOQIDX_122, 0x5}, - {OP_WR_E1H, QM_REG_QVOQIDX_123, 0x5}, - {OP_WR_E1H, QM_REG_QVOQIDX_124, 0x5}, - {OP_WR_E1H, QM_REG_WRRWEIGHTS_30, 0x20081001}, - {OP_WR_E1H, QM_REG_QVOQIDX_125, 0x8}, - {OP_WR_E1H, QM_REG_QVOQIDX_126, 0x6}, - {OP_WR_E1H, QM_REG_QVOQIDX_127, 0x7}, - {OP_WR_E1H, QM_REG_WRRWEIGHTS_31, 0x1010120}, - {OP_WR_E1H, QM_REG_VOQQMASK_0_LSB, 0x3f003f}, - {OP_WR_E1H, QM_REG_VOQQMASK_0_MSB, 0x0}, - {OP_WR_E1H, QM_REG_VOQQMASK_0_LSB_EXT_A, 0x3f003f}, - {OP_WR_E1H, QM_REG_VOQQMASK_0_MSB_EXT_A, 0x0}, - {OP_WR_E1H, QM_REG_VOQQMASK_1_LSB, 0x0}, - {OP_WR_E1H, QM_REG_VOQQMASK_1_MSB, 0x3f003f}, - {OP_WR_E1H, QM_REG_VOQQMASK_1_LSB_EXT_A, 0x0}, - {OP_WR_E1H, QM_REG_VOQQMASK_1_MSB_EXT_A, 0x3f003f}, - {OP_WR_E1H, QM_REG_VOQQMASK_2_LSB, 0x1000100}, - {OP_WR_E1H, QM_REG_VOQQMASK_2_MSB, 0x1000100}, - {OP_WR_E1H, QM_REG_VOQQMASK_2_LSB_EXT_A, 0x1000100}, - {OP_WR_E1H, QM_REG_VOQQMASK_2_MSB_EXT_A, 0x1000100}, - {OP_ZR, QM_REG_VOQQMASK_3_LSB, 0x2}, - {OP_WR_E1, QM_REG_VOQQMASK_4_LSB, 0xc0}, - {OP_WR_E1H, QM_REG_VOQQMASK_3_LSB_EXT_A, 0x0}, - {OP_WR_E1, QM_REG_VOQQMASK_4_MSB, 0xc0}, - {OP_WR_E1H, QM_REG_VOQQMASK_3_MSB_EXT_A, 0x0}, - {OP_WR_E1, QM_REG_VOQQMASK_5_LSB, 0x1e00}, - {OP_WR_E1H, QM_REG_VOQQMASK_4_LSB, 0xc000c0}, - {OP_WR_E1, QM_REG_VOQQMASK_5_MSB, 0x1e00}, - {OP_WR_E1H, QM_REG_VOQQMASK_4_MSB, 0xc000c0}, - {OP_WR_E1, QM_REG_VOQQMASK_6_LSB, 0x4000}, - {OP_WR_E1H, QM_REG_VOQQMASK_4_LSB_EXT_A, 0xc000c0}, - {OP_WR_E1, QM_REG_VOQQMASK_6_MSB, 0x4000}, - {OP_WR_E1H, QM_REG_VOQQMASK_4_MSB_EXT_A, 0xc000c0}, - {OP_WR_E1, QM_REG_VOQQMASK_7_LSB, 0x8000}, - {OP_WR_E1H, QM_REG_VOQQMASK_5_LSB, 0x1e001e00}, - {OP_WR_E1, QM_REG_VOQQMASK_7_MSB, 0x8000}, - {OP_WR_E1H, QM_REG_VOQQMASK_5_MSB, 0x1e001e00}, - {OP_WR_E1, QM_REG_VOQQMASK_8_LSB, 0x2000}, - {OP_WR_E1H, QM_REG_VOQQMASK_5_LSB_EXT_A, 0x1e001e00}, - {OP_WR_E1, QM_REG_VOQQMASK_8_MSB, 0x2000}, - {OP_WR_E1H, QM_REG_VOQQMASK_5_MSB_EXT_A, 0x1e001e00}, - {OP_ZR_E1, QM_REG_VOQQMASK_9_LSB, 0x7}, - {OP_WR_E1H, QM_REG_VOQQMASK_6_LSB, 0x40004000}, - {OP_WR_E1H, QM_REG_VOQQMASK_6_MSB, 0x40004000}, - {OP_WR_E1H, QM_REG_VOQQMASK_6_LSB_EXT_A, 0x40004000}, - {OP_WR_E1H, QM_REG_VOQQMASK_6_MSB_EXT_A, 0x40004000}, - {OP_WR_E1H, QM_REG_VOQQMASK_7_LSB, 0x80008000}, - {OP_WR_E1H, QM_REG_VOQQMASK_7_MSB, 0x80008000}, - {OP_WR_E1H, QM_REG_VOQQMASK_7_LSB_EXT_A, 0x80008000}, - {OP_WR_E1H, QM_REG_VOQQMASK_7_MSB_EXT_A, 0x80008000}, - {OP_WR_E1H, QM_REG_VOQQMASK_8_LSB, 0x20002000}, - {OP_WR_E1H, QM_REG_VOQQMASK_8_MSB, 0x20002000}, - {OP_WR_E1H, QM_REG_VOQQMASK_8_LSB_EXT_A, 0x20002000}, - {OP_WR_E1H, QM_REG_VOQQMASK_8_MSB_EXT_A, 0x20002000}, - {OP_ZR_E1H, QM_REG_VOQQMASK_9_LSB, 0x2}, - {OP_WR_E1H, QM_REG_VOQQMASK_9_LSB_EXT_A, 0x0}, - {OP_WR_E1H, QM_REG_VOQQMASK_9_MSB_EXT_A, 0x0}, - {OP_WR_E1H, QM_REG_VOQQMASK_10_LSB, 0x0}, - {OP_WR_E1H, QM_REG_VOQQMASK_10_MSB, 0x0}, - {OP_WR_E1H, QM_REG_VOQQMASK_10_LSB_EXT_A, 0x0}, - {OP_WR_E1H, QM_REG_VOQQMASK_10_MSB_EXT_A, 0x0}, - {OP_WR_E1H, QM_REG_VOQQMASK_11_LSB, 0x0}, - {OP_WR_E1H, QM_REG_VOQQMASK_11_MSB, 0x0}, - {OP_WR_E1H, QM_REG_VOQQMASK_11_LSB_EXT_A, 0x0}, - {OP_WR_E1H, QM_REG_VOQQMASK_11_MSB_EXT_A, 0x0}, - {OP_WR_E1H, QM_REG_VOQPORT_0, 0x0}, - {OP_WR, QM_REG_VOQPORT_1, 0x1}, - {OP_ZR, QM_REG_VOQPORT_2, 0xa}, - {OP_WR, QM_REG_CMINTVOQMASK_0, 0xc08}, - {OP_WR, QM_REG_CMINTVOQMASK_1, 0x40}, - {OP_WR, QM_REG_CMINTVOQMASK_2, 0x100}, - {OP_WR, QM_REG_CMINTVOQMASK_3, 0x20}, - {OP_WR, QM_REG_CMINTVOQMASK_4, 0x17}, - {OP_WR, QM_REG_CMINTVOQMASK_5, 0x80}, - {OP_WR, QM_REG_CMINTVOQMASK_6, 0x200}, - {OP_WR, QM_REG_CMINTVOQMASK_7, 0x0}, - {OP_WR_E1, QM_REG_HWAEMPTYMASK_LSB, 0xffff01ff}, - {OP_WR_E1H, QM_REG_HWAEMPTYMASK_LSB, 0x1ff01ff}, - {OP_WR_E1, QM_REG_HWAEMPTYMASK_MSB, 0xffff01ff}, - {OP_WR_E1H, QM_REG_HWAEMPTYMASK_MSB, 0x1ff01ff}, - {OP_WR_E1H, QM_REG_HWAEMPTYMASK_LSB_EXT_A, 0x1ff01ff}, - {OP_WR_E1H, QM_REG_HWAEMPTYMASK_MSB_EXT_A, 0x1ff01ff}, - {OP_WR, QM_REG_ENBYPVOQMASK, 0x13}, - {OP_WR, QM_REG_VOQCREDITAFULLTHR, 0x13f}, - {OP_WR, QM_REG_VOQINITCREDIT_0, 0x140}, - {OP_WR, QM_REG_VOQINITCREDIT_1, 0x140}, - {OP_ZR, QM_REG_VOQINITCREDIT_2, 0x2}, - {OP_WR, QM_REG_VOQINITCREDIT_4, 0xc0}, - {OP_ZR, QM_REG_VOQINITCREDIT_5, 0x7}, - {OP_WR, QM_REG_TASKCRDCOST_0, 0x48}, - {OP_WR, QM_REG_TASKCRDCOST_1, 0x48}, - {OP_ZR, QM_REG_TASKCRDCOST_2, 0x2}, - {OP_WR, QM_REG_TASKCRDCOST_4, 0x48}, - {OP_ZR, QM_REG_TASKCRDCOST_5, 0x7}, - {OP_WR, QM_REG_BYTECRDINITVAL, 0x8000}, - {OP_WR, QM_REG_BYTECRDCOST, 0x25e4}, - {OP_WR, QM_REG_BYTECREDITAFULLTHR, 0x7fff}, - {OP_WR_E1, QM_REG_ENBYTECRD_LSB, 0x7}, - {OP_WR_E1H, QM_REG_ENBYTECRD_LSB, 0x70007}, - {OP_WR_E1, QM_REG_ENBYTECRD_MSB, 0x7}, - {OP_WR_E1H, QM_REG_ENBYTECRD_MSB, 0x70007}, - {OP_WR_E1H, QM_REG_ENBYTECRD_LSB_EXT_A, 0x70007}, - {OP_WR_E1H, QM_REG_ENBYTECRD_MSB_EXT_A, 0x70007}, - {OP_WR, QM_REG_BYTECRDPORT_LSB, 0x0}, - {OP_WR, QM_REG_BYTECRDPORT_MSB, 0xffffffff}, - {OP_WR_E1, QM_REG_FUNCNUMSEL_LSB, 0x0}, - {OP_WR_E1H, QM_REG_BYTECRDPORT_LSB_EXT_A, 0x0}, - {OP_WR_E1, QM_REG_FUNCNUMSEL_MSB, 0xffffffff}, - {OP_WR_E1H, QM_REG_BYTECRDPORT_MSB_EXT_A, 0xffffffff}, - {OP_WR_E1H, QM_REG_PQ2PCIFUNC_0, 0x0}, - {OP_WR_E1H, QM_REG_PQ2PCIFUNC_1, 0x2}, - {OP_WR_E1H, QM_REG_PQ2PCIFUNC_2, 0x1}, - {OP_WR_E1H, QM_REG_PQ2PCIFUNC_3, 0x3}, - {OP_WR_E1H, QM_REG_PQ2PCIFUNC_4, 0x4}, - {OP_WR_E1H, QM_REG_PQ2PCIFUNC_5, 0x6}, - {OP_WR_E1H, QM_REG_PQ2PCIFUNC_6, 0x5}, - {OP_WR_E1H, QM_REG_PQ2PCIFUNC_7, 0x7}, - {OP_WR, QM_REG_CMINTEN, 0xff}, -#define QM_COMMON_END 1456 -#define PBF_COMMON_START 1456 - {OP_WR, PBF_REG_INIT, 0x1}, - {OP_WR, PBF_REG_INIT_P4, 0x1}, - {OP_WR, PBF_REG_MAC_LB_ENABLE, 0x1}, - {OP_WR, PBF_REG_IF_ENABLE_REG, 0x7fff}, - {OP_WR, PBF_REG_INIT_P4, 0x0}, - {OP_WR, PBF_REG_INIT, 0x0}, - {OP_WR, PBF_REG_DISABLE_NEW_TASK_PROC_P4, 0x0}, -#define PBF_COMMON_END 1463 -#define PBF_PORT0_START 1463 - {OP_WR, PBF_REG_INIT_P0, 0x1}, - {OP_WR, PBF_REG_MAC_IF0_ENABLE, 0x1}, - {OP_WR, PBF_REG_INIT_P0, 0x0}, - {OP_WR, PBF_REG_DISABLE_NEW_TASK_PROC_P0, 0x0}, -#define PBF_PORT0_END 1467 -#define PBF_PORT1_START 1467 - {OP_WR, PBF_REG_INIT_P1, 0x1}, - {OP_WR, PBF_REG_MAC_IF1_ENABLE, 0x1}, - {OP_WR, PBF_REG_INIT_P1, 0x0}, - {OP_WR, PBF_REG_DISABLE_NEW_TASK_PROC_P1, 0x0}, -#define PBF_PORT1_END 1471 -#define XCM_COMMON_START 1471 - {OP_WR, XCM_REG_XX_OVFL_EVNT_ID, 0x32}, - {OP_WR, XCM_REG_XQM_XCM_HDR_P, 0x3150020}, - {OP_WR, XCM_REG_XQM_XCM_HDR_S, 0x3150020}, - {OP_WR, XCM_REG_TM_XCM_HDR, 0x1000030}, - {OP_WR, XCM_REG_ERR_XCM_HDR, 0x8100000}, - {OP_WR, XCM_REG_ERR_EVNT_ID, 0x33}, - {OP_WR, XCM_REG_EXPR_EVNT_ID, 0x30}, - {OP_WR, XCM_REG_STOP_EVNT_ID, 0x31}, - {OP_WR, XCM_REG_STORM_WEIGHT, 0x3}, - {OP_WR, XCM_REG_TSEM_WEIGHT, 0x6}, - {OP_WR, XCM_REG_CSEM_WEIGHT, 0x3}, - {OP_WR, XCM_REG_USEM_WEIGHT, 0x3}, - {OP_WR, XCM_REG_DORQ_WEIGHT, 0x2}, - {OP_WR, XCM_REG_PBF_WEIGHT, 0x0}, - {OP_WR, XCM_REG_NIG0_WEIGHT, 0x2}, - {OP_WR, XCM_REG_CP_WEIGHT, 0x0}, - {OP_WR, XCM_REG_XSDM_WEIGHT, 0x6}, - {OP_WR, XCM_REG_XQM_P_WEIGHT, 0x4}, - {OP_WR, XCM_REG_XQM_S_WEIGHT, 0x2}, - {OP_WR, XCM_REG_TM_WEIGHT, 0x2}, - {OP_WR, XCM_REG_XCM_XQM_USE_Q, 0x1}, - {OP_WR, XCM_REG_XQM_BYP_ACT_UPD, 0x6}, - {OP_WR, XCM_REG_UNA_GT_NXT_Q, 0x0}, - {OP_WR, XCM_REG_AUX1_Q, 0x2}, - {OP_WR, XCM_REG_AUX_CNT_FLG_Q_19, 0x1}, - {OP_WR, XCM_REG_GR_ARB_TYPE, 0x1}, - {OP_WR, XCM_REG_GR_LD0_PR, 0x1}, - {OP_WR, XCM_REG_GR_LD1_PR, 0x2}, - {OP_WR, XCM_REG_CFC_INIT_CRD, 0x1}, - {OP_WR, XCM_REG_FIC0_INIT_CRD, 0x40}, - {OP_WR, XCM_REG_FIC1_INIT_CRD, 0x40}, - {OP_WR, XCM_REG_TM_INIT_CRD, 0x4}, - {OP_WR, XCM_REG_XQM_INIT_CRD, 0x20}, - {OP_WR, XCM_REG_XX_INIT_CRD, 0x2}, - {OP_WR_E1, XCM_REG_XX_MSG_NUM, 0x1f}, - {OP_WR_E1H, XCM_REG_XX_MSG_NUM, 0x20}, - {OP_ZR, XCM_REG_XX_TABLE, 0x12}, - {OP_SW_E1, XCM_REG_XX_DESCR_TABLE, 0x1f02d4}, - {OP_SW_E1H, XCM_REG_XX_DESCR_TABLE, 0x1f0329}, - {OP_WR, XCM_REG_N_SM_CTX_LD_0, 0xf}, - {OP_WR, XCM_REG_N_SM_CTX_LD_1, 0x7}, - {OP_WR, XCM_REG_N_SM_CTX_LD_2, 0xb}, - {OP_WR, XCM_REG_N_SM_CTX_LD_3, 0xe}, - {OP_ZR_E1, XCM_REG_N_SM_CTX_LD_4, 0x4}, - {OP_WR_E1H, XCM_REG_N_SM_CTX_LD_4, 0xe}, - {OP_ZR_E1H, XCM_REG_N_SM_CTX_LD_5, 0x3}, - {OP_WR, XCM_REG_XCM_REG0_SZ, 0x4}, - {OP_WR, XCM_REG_XCM_STORM0_IFEN, 0x1}, - {OP_WR, XCM_REG_XCM_STORM1_IFEN, 0x1}, - {OP_WR, XCM_REG_XCM_XQM_IFEN, 0x1}, - {OP_WR, XCM_REG_STORM_XCM_IFEN, 0x1}, - {OP_WR, XCM_REG_XQM_XCM_IFEN, 0x1}, - {OP_WR, XCM_REG_XSDM_IFEN, 0x1}, - {OP_WR, XCM_REG_TM_XCM_IFEN, 0x1}, - {OP_WR, XCM_REG_XCM_TM_IFEN, 0x1}, - {OP_WR, XCM_REG_TSEM_IFEN, 0x1}, - {OP_WR, XCM_REG_CSEM_IFEN, 0x1}, - {OP_WR, XCM_REG_USEM_IFEN, 0x1}, - {OP_WR, XCM_REG_DORQ_IFEN, 0x1}, - {OP_WR, XCM_REG_PBF_IFEN, 0x1}, - {OP_WR, XCM_REG_NIG0_IFEN, 0x1}, - {OP_WR, XCM_REG_NIG1_IFEN, 0x1}, - {OP_WR, XCM_REG_CDU_AG_WR_IFEN, 0x1}, - {OP_WR, XCM_REG_CDU_AG_RD_IFEN, 0x1}, - {OP_WR, XCM_REG_CDU_SM_WR_IFEN, 0x1}, - {OP_WR, XCM_REG_CDU_SM_RD_IFEN, 0x1}, - {OP_WR, XCM_REG_XCM_CFC_IFEN, 0x1}, -#define XCM_COMMON_END 1538 -#define XCM_PORT0_START 1538 - {OP_WR_E1, XCM_REG_GLB_DEL_ACK_TMR_VAL_0, 0xc8}, - {OP_WR_E1, XCM_REG_GLB_DEL_ACK_MAX_CNT_0, 0x2}, - {OP_WR_E1, XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD00, 0x0}, - {OP_WR_E1, XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD10, 0x0}, - {OP_WR_E1, XCM_REG_WU_DA_CNT_CMD00, 0x2}, - {OP_WR_E1, XCM_REG_WU_DA_CNT_CMD10, 0x2}, - {OP_WR_E1, XCM_REG_WU_DA_CNT_UPD_VAL00, 0xff}, - {OP_WR_E1, XCM_REG_WU_DA_CNT_UPD_VAL10, 0xff}, -#define XCM_PORT0_END 1546 -#define XCM_PORT1_START 1546 - {OP_WR_E1, XCM_REG_GLB_DEL_ACK_TMR_VAL_1, 0xc8}, - {OP_WR_E1, XCM_REG_GLB_DEL_ACK_MAX_CNT_1, 0x2}, - {OP_WR_E1, XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD01, 0x0}, - {OP_WR_E1, XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD11, 0x0}, - {OP_WR_E1, XCM_REG_WU_DA_CNT_CMD01, 0x2}, - {OP_WR_E1, XCM_REG_WU_DA_CNT_CMD11, 0x2}, - {OP_WR_E1, XCM_REG_WU_DA_CNT_UPD_VAL01, 0xff}, - {OP_WR_E1, XCM_REG_WU_DA_CNT_UPD_VAL11, 0xff}, -#define XCM_PORT1_END 1554 -#define XCM_FUNC0_START 1554 - {OP_WR_E1H, XCM_REG_GLB_DEL_ACK_TMR_VAL_0, 0xc8}, - {OP_WR_E1H, XCM_REG_GLB_DEL_ACK_MAX_CNT_0, 0x2}, - {OP_WR_E1H, XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD00, 0x0}, - {OP_WR_E1H, XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD10, 0x0}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_CMD00, 0x2}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_CMD10, 0x2}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_UPD_VAL00, 0xff}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_UPD_VAL10, 0xff}, - {OP_WR_E1H, XCM_REG_PHYS_QNUM3_0, 0x0}, -#define XCM_FUNC0_END 1563 -#define XCM_FUNC1_START 1563 - {OP_WR_E1H, XCM_REG_GLB_DEL_ACK_TMR_VAL_1, 0xc8}, - {OP_WR_E1H, XCM_REG_GLB_DEL_ACK_MAX_CNT_1, 0x2}, - {OP_WR_E1H, XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD01, 0x0}, - {OP_WR_E1H, XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD11, 0x0}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_CMD01, 0x2}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_CMD11, 0x2}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_UPD_VAL01, 0xff}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_UPD_VAL11, 0xff}, - {OP_WR_E1H, XCM_REG_PHYS_QNUM3_1, 0x0}, -#define XCM_FUNC1_END 1572 -#define XCM_FUNC2_START 1572 - {OP_WR_E1H, XCM_REG_GLB_DEL_ACK_TMR_VAL_0, 0xc8}, - {OP_WR_E1H, XCM_REG_GLB_DEL_ACK_MAX_CNT_0, 0x2}, - {OP_WR_E1H, XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD00, 0x0}, - {OP_WR_E1H, XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD10, 0x0}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_CMD00, 0x2}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_CMD10, 0x2}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_UPD_VAL00, 0xff}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_UPD_VAL10, 0xff}, - {OP_WR_E1H, XCM_REG_PHYS_QNUM3_0, 0x0}, -#define XCM_FUNC2_END 1581 -#define XCM_FUNC3_START 1581 - {OP_WR_E1H, XCM_REG_GLB_DEL_ACK_TMR_VAL_1, 0xc8}, - {OP_WR_E1H, XCM_REG_GLB_DEL_ACK_MAX_CNT_1, 0x2}, - {OP_WR_E1H, XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD01, 0x0}, - {OP_WR_E1H, XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD11, 0x0}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_CMD01, 0x2}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_CMD11, 0x2}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_UPD_VAL01, 0xff}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_UPD_VAL11, 0xff}, - {OP_WR_E1H, XCM_REG_PHYS_QNUM3_1, 0x0}, -#define XCM_FUNC3_END 1590 -#define XCM_FUNC4_START 1590 - {OP_WR_E1H, XCM_REG_GLB_DEL_ACK_TMR_VAL_0, 0xc8}, - {OP_WR_E1H, XCM_REG_GLB_DEL_ACK_MAX_CNT_0, 0x2}, - {OP_WR_E1H, XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD00, 0x0}, - {OP_WR_E1H, XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD10, 0x0}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_CMD00, 0x2}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_CMD10, 0x2}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_UPD_VAL00, 0xff}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_UPD_VAL10, 0xff}, - {OP_WR_E1H, XCM_REG_PHYS_QNUM3_0, 0x0}, -#define XCM_FUNC4_END 1599 -#define XCM_FUNC5_START 1599 - {OP_WR_E1H, XCM_REG_GLB_DEL_ACK_TMR_VAL_1, 0xc8}, - {OP_WR_E1H, XCM_REG_GLB_DEL_ACK_MAX_CNT_1, 0x2}, - {OP_WR_E1H, XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD01, 0x0}, - {OP_WR_E1H, XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD11, 0x0}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_CMD01, 0x2}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_CMD11, 0x2}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_UPD_VAL01, 0xff}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_UPD_VAL11, 0xff}, - {OP_WR_E1H, XCM_REG_PHYS_QNUM3_1, 0x0}, -#define XCM_FUNC5_END 1608 -#define XCM_FUNC6_START 1608 - {OP_WR_E1H, XCM_REG_GLB_DEL_ACK_TMR_VAL_0, 0xc8}, - {OP_WR_E1H, XCM_REG_GLB_DEL_ACK_MAX_CNT_0, 0x2}, - {OP_WR_E1H, XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD00, 0x0}, - {OP_WR_E1H, XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD10, 0x0}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_CMD00, 0x2}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_CMD10, 0x2}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_UPD_VAL00, 0xff}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_UPD_VAL10, 0xff}, - {OP_WR_E1H, XCM_REG_PHYS_QNUM3_0, 0x0}, -#define XCM_FUNC6_END 1617 -#define XCM_FUNC7_START 1617 - {OP_WR_E1H, XCM_REG_GLB_DEL_ACK_TMR_VAL_1, 0xc8}, - {OP_WR_E1H, XCM_REG_GLB_DEL_ACK_MAX_CNT_1, 0x2}, - {OP_WR_E1H, XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD01, 0x0}, - {OP_WR_E1H, XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD11, 0x0}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_CMD01, 0x2}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_CMD11, 0x2}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_UPD_VAL01, 0xff}, - {OP_WR_E1H, XCM_REG_WU_DA_CNT_UPD_VAL11, 0xff}, - {OP_WR_E1H, XCM_REG_PHYS_QNUM3_1, 0x0}, -#define XCM_FUNC7_END 1626 -#define XSEM_COMMON_START 1626 - {OP_RD, XSEM_REG_MSG_NUM_FIC0, 0x0}, - {OP_RD, XSEM_REG_MSG_NUM_FIC1, 0x0}, - {OP_RD, XSEM_REG_MSG_NUM_FOC0, 0x0}, - {OP_RD, XSEM_REG_MSG_NUM_FOC1, 0x0}, - {OP_RD, XSEM_REG_MSG_NUM_FOC2, 0x0}, - {OP_RD, XSEM_REG_MSG_NUM_FOC3, 0x0}, - {OP_WR, XSEM_REG_ARB_ELEMENT0, 0x1}, - {OP_WR, XSEM_REG_ARB_ELEMENT1, 0x2}, - {OP_WR, XSEM_REG_ARB_ELEMENT2, 0x3}, - {OP_WR, XSEM_REG_ARB_ELEMENT3, 0x0}, - {OP_WR, XSEM_REG_ARB_ELEMENT4, 0x4}, - {OP_WR, XSEM_REG_ARB_CYCLE_SIZE, 0x1}, - {OP_WR, XSEM_REG_TS_0_AS, 0x0}, - {OP_WR, XSEM_REG_TS_1_AS, 0x1}, - {OP_WR, XSEM_REG_TS_2_AS, 0x4}, - {OP_WR, XSEM_REG_TS_3_AS, 0x0}, - {OP_WR, XSEM_REG_TS_4_AS, 0x1}, - {OP_WR, XSEM_REG_TS_5_AS, 0x3}, - {OP_WR, XSEM_REG_TS_6_AS, 0x0}, - {OP_WR, XSEM_REG_TS_7_AS, 0x1}, - {OP_WR, XSEM_REG_TS_8_AS, 0x4}, - {OP_WR, XSEM_REG_TS_9_AS, 0x0}, - {OP_WR, XSEM_REG_TS_10_AS, 0x1}, - {OP_WR, XSEM_REG_TS_11_AS, 0x3}, - {OP_WR, XSEM_REG_TS_12_AS, 0x0}, - {OP_WR, XSEM_REG_TS_13_AS, 0x1}, - {OP_WR, XSEM_REG_TS_14_AS, 0x4}, - {OP_WR, XSEM_REG_TS_15_AS, 0x0}, - {OP_WR, XSEM_REG_TS_16_AS, 0x4}, - {OP_WR, XSEM_REG_TS_17_AS, 0x3}, - {OP_ZR, XSEM_REG_TS_18_AS, 0x2}, - {OP_WR, XSEM_REG_ENABLE_IN, 0x3fff}, - {OP_WR, XSEM_REG_ENABLE_OUT, 0x3ff}, - {OP_WR, XSEM_REG_FIC0_DISABLE, 0x0}, - {OP_WR, XSEM_REG_FIC1_DISABLE, 0x0}, - {OP_WR, XSEM_REG_PAS_DISABLE, 0x0}, - {OP_WR, XSEM_REG_THREADS_LIST, 0xffff}, - {OP_ZR, XSEM_REG_PASSIVE_BUFFER, 0x800}, - {OP_WR, XSEM_REG_FAST_MEMORY + 0x18bc0, 0x1}, - {OP_WR, XSEM_REG_FAST_MEMORY + 0x18000, 0x0}, - {OP_WR, XSEM_REG_FAST_MEMORY + 0x18040, 0x18}, - {OP_WR, XSEM_REG_FAST_MEMORY + 0x18080, 0xc}, - {OP_WR, XSEM_REG_FAST_MEMORY + 0x180c0, 0x66}, - {OP_WR_ASIC, XSEM_REG_FAST_MEMORY + 0x18300, 0x7a120}, - {OP_WR_EMUL, XSEM_REG_FAST_MEMORY + 0x18300, 0x138}, - {OP_WR_FPGA, XSEM_REG_FAST_MEMORY + 0x18300, 0x1388}, - {OP_WR, XSEM_REG_FAST_MEMORY + 0x183c0, 0x1f4}, - {OP_WR_ASIC, XSEM_REG_FAST_MEMORY + 0x18340, 0x1f4}, - {OP_WR_EMUL, XSEM_REG_FAST_MEMORY + 0x18340, 0x0}, - {OP_WR_FPGA, XSEM_REG_FAST_MEMORY + 0x18340, 0x5}, - {OP_WR_EMUL, XSEM_REG_FAST_MEMORY + 0x18380, 0x4c4b4}, - {OP_WR_ASIC, XSEM_REG_FAST_MEMORY + 0x18380, 0x1dcd6500}, - {OP_WR_EMUL_E1H, XSEM_REG_FAST_MEMORY + 0x11480, 0x0}, - {OP_WR_FPGA, XSEM_REG_FAST_MEMORY + 0x18380, 0x4c4b40}, - {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x3d60, 0x4}, - {OP_WR_E1H, XSEM_REG_FAST_MEMORY + 0x11480, 0x1}, - {OP_SW_E1, XSEM_REG_FAST_MEMORY + 0x3d60 + 0x10, 0x202f3}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x29c8, 0x4}, - {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x3000, 0x48}, - {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x29c8 + 0x10, 0x20348}, - {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x1020, 0xc8}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x2080, 0x48}, - {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x1000, 0x2}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x9020, 0xc8}, - {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x3128, 0x8e}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x9000, 0x2}, - {OP_WR_E1, XSEM_REG_FAST_MEMORY + 0x3368, 0x0}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x21a8, 0x86}, - {OP_SW_E1, XSEM_REG_FAST_MEMORY + 0x3370, 0x202f5}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x2000, 0x20}, - {OP_SW_E1, XSEM_REG_FAST_MEMORY + 0x3b90, 0x402f7}, - {OP_WR_E1H, XSEM_REG_FAST_MEMORY + 0x23c8, 0x0}, - {OP_SW_E1, XSEM_REG_FAST_MEMORY + 0x3e20, 0x202fb}, - {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x23d0, 0x2034a}, - {OP_WR_E1, XSEM_REG_FAST_MEMORY + 0x1518, 0x1}, - {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x2498, 0x4034c}, - {OP_WR_E1, XSEM_REG_FAST_MEMORY + 0x1830, 0x0}, - {OP_WR_E1H, XSEM_REG_FAST_MEMORY + 0x2c20, 0x0}, - {OP_WR_E1, XSEM_REG_FAST_MEMORY + 0x1838, 0x0}, - {OP_WR_E1H, XSEM_REG_FAST_MEMORY + 0x2c10, 0x0}, - {OP_SW_E1, XSEM_REG_FAST_MEMORY + 0x1820, 0x202fd}, - {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x2c08, 0x20350}, - {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x4ac0, 0x2}, - {OP_WR_E1H, XSEM_REG_FAST_MEMORY + 0x3010, 0x1}, - {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x4b00, 0x4}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x4040, 0x10}, - {OP_SW_E1, XSEM_REG_FAST_MEMORY + 0x1f48, 0x202ff}, - {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x4000, 0x100352}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x6ac0, 0x2}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x6b00, 0x4}, - {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x8408, 0x20362}, - {OP_WR, XSEM_REG_FAST_MEMORY + 0x10800, 0x0}, - {OP_SW_E1, XSEM_REG_FAST_MEMORY + 0x10c00, 0x100301}, - {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x10c00, 0x100364}, - {OP_WR, XSEM_REG_FAST_MEMORY + 0x10800, 0x1000000}, - {OP_SW_E1, XSEM_REG_FAST_MEMORY + 0x10c40, 0x80311}, - {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x10c40, 0x80374}, - {OP_WR, XSEM_REG_FAST_MEMORY + 0x10800, 0x2000000}, - {OP_SW_E1, XSEM_REG_FAST_MEMORY + 0x10c60, 0x80319}, - {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x10c60, 0x8037c}, - {OP_ZP_E1, XSEM_REG_INT_TABLE, 0xb50000}, - {OP_ZP_E1H, XSEM_REG_INT_TABLE, 0xbd0000}, - {OP_WR_64_E1, XSEM_REG_INT_TABLE + 0x368, 0x130321}, - {OP_WR_64_E1H, XSEM_REG_INT_TABLE + 0x3a8, 0xb0384}, - {OP_ZP_E1, XSEM_REG_PRAM, 0x33660000}, - {OP_ZP_E1H, XSEM_REG_PRAM, 0x34060000}, - {OP_ZP_E1, XSEM_REG_PRAM + 0x8000, 0x38b30cda}, - {OP_ZP_E1H, XSEM_REG_PRAM + 0x8000, 0x37960d02}, - {OP_ZP_E1, XSEM_REG_PRAM + 0x10000, 0x3bb11b07}, - {OP_ZP_E1H, XSEM_REG_PRAM + 0x10000, 0x3bc31ae8}, - {OP_ZP_E1, XSEM_REG_PRAM + 0x18000, 0x2a2629f4}, - {OP_ZP_E1H, XSEM_REG_PRAM + 0x18000, 0x382629d9}, - {OP_WR_64_E1, XSEM_REG_PRAM + 0x1d6c0, 0x45280323}, - {OP_ZP_E1H, XSEM_REG_PRAM + 0x20000, 0x124537e3}, - {OP_WR_64_E1H, XSEM_REG_PRAM + 0x22220, 0x3bbc0386}, -#define XSEM_COMMON_END 1741 -#define XSEM_PORT0_START 1741 - {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x3ba0, 0x14}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0xc000, 0xfc}, - {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x3c40, 0x24}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x24a8, 0x14}, - {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x1400, 0xa}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x2548, 0x24}, - {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x1450, 0x6}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x2668, 0x24}, - {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x3378, 0xfc}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x2788, 0x24}, - {OP_WR_E1, XSEM_REG_FAST_MEMORY + 0x3b58, 0x0}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x28a8, 0x24}, - {OP_SW_E1, XSEM_REG_FAST_MEMORY + 0x3d78, 0x20325}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0xa000, 0x28}, - {OP_SW_E1, XSEM_REG_FAST_MEMORY + 0x3d88, 0x100327}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0xa140, 0xc}, - {OP_WR_E1, XSEM_REG_FAST_MEMORY + 0x1500, 0x0}, - {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x29e0, 0x20388}, - {OP_WR_E1, XSEM_REG_FAST_MEMORY + 0x1508, 0x1}, - {OP_WR_E1H, XSEM_REG_FAST_MEMORY + 0x3000, 0x1}, - {OP_ZR, XSEM_REG_FAST_MEMORY + 0x5020, 0x2}, - {OP_ZR, XSEM_REG_FAST_MEMORY + 0x5030, 0x2}, - {OP_ZR, XSEM_REG_FAST_MEMORY + 0x5000, 0x2}, - {OP_ZR, XSEM_REG_FAST_MEMORY + 0x5010, 0x2}, - {OP_WR_E1, XSEM_REG_FAST_MEMORY + 0x5040, 0x0}, - {OP_WR_E1H, XSEM_REG_FAST_MEMORY + 0x5208, 0x1}, - {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x5048, 0xe}, - {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x6ac8, 0x2038a}, - {OP_WR_E1, XSEM_REG_FAST_MEMORY + 0x50b8, 0x1}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x6b10, 0x42}, - {OP_SW_E1, XSEM_REG_FAST_MEMORY + 0x4ac8, 0x20337}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x6d20, 0x4}, - {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x4b10, 0x42}, - {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x4d20, 0x4}, -#define XSEM_PORT0_END 1775 -#define XSEM_PORT1_START 1775 - {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x3bf0, 0x14}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0xc3f0, 0xfc}, - {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x3cd0, 0x24}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x24f8, 0x14}, - {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x1428, 0xa}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x25d8, 0x24}, - {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x1468, 0x6}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x26f8, 0x24}, - {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x3768, 0xfc}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x2818, 0x24}, - {OP_WR_E1, XSEM_REG_FAST_MEMORY + 0x3b5c, 0x0}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x2938, 0x24}, - {OP_SW_E1, XSEM_REG_FAST_MEMORY + 0x3d80, 0x20339}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0xa0a0, 0x28}, - {OP_SW_E1, XSEM_REG_FAST_MEMORY + 0x3dc8, 0x10033b}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0xa170, 0xc}, - {OP_WR_E1, XSEM_REG_FAST_MEMORY + 0x1504, 0x0}, - {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x29e8, 0x2038c}, - {OP_WR_E1, XSEM_REG_FAST_MEMORY + 0x150c, 0x1}, - {OP_WR_E1H, XSEM_REG_FAST_MEMORY + 0x3004, 0x1}, - {OP_ZR, XSEM_REG_FAST_MEMORY + 0x5028, 0x2}, - {OP_ZR, XSEM_REG_FAST_MEMORY + 0x5038, 0x2}, - {OP_ZR, XSEM_REG_FAST_MEMORY + 0x5008, 0x2}, - {OP_ZR, XSEM_REG_FAST_MEMORY + 0x5018, 0x2}, - {OP_WR_E1, XSEM_REG_FAST_MEMORY + 0x5044, 0x0}, - {OP_WR_E1H, XSEM_REG_FAST_MEMORY + 0x520c, 0x1}, - {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x5080, 0xe}, - {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x6ad0, 0x2038e}, - {OP_WR_E1, XSEM_REG_FAST_MEMORY + 0x50bc, 0x1}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x6c18, 0x42}, - {OP_SW_E1, XSEM_REG_FAST_MEMORY + 0x4ad0, 0x2034b}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x6d30, 0x4}, - {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x4c18, 0x42}, - {OP_ZR_E1, XSEM_REG_FAST_MEMORY + 0x4d30, 0x4}, -#define XSEM_PORT1_END 1809 -#define XSEM_FUNC0_START 1809 - {OP_WR_E1H, XSEM_REG_FAST_MEMORY + 0xc7e0, 0x0}, - {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x29f0, 0x100390}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x5048, 0xe}, -#define XSEM_FUNC0_END 1812 -#define XSEM_FUNC1_START 1812 - {OP_WR_E1H, XSEM_REG_FAST_MEMORY + 0xc7e4, 0x0}, - {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x2a30, 0x1003a0}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x5080, 0xe}, -#define XSEM_FUNC1_END 1815 -#define XSEM_FUNC2_START 1815 - {OP_WR_E1H, XSEM_REG_FAST_MEMORY + 0xc7e8, 0x0}, - {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x2a70, 0x1003b0}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x50b8, 0xe}, -#define XSEM_FUNC2_END 1818 -#define XSEM_FUNC3_START 1818 - {OP_WR_E1H, XSEM_REG_FAST_MEMORY + 0xc7ec, 0x0}, - {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x2ab0, 0x1003c0}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x50f0, 0xe}, -#define XSEM_FUNC3_END 1821 -#define XSEM_FUNC4_START 1821 - {OP_WR_E1H, XSEM_REG_FAST_MEMORY + 0xc7f0, 0x0}, - {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x2af0, 0x1003d0}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x5128, 0xe}, -#define XSEM_FUNC4_END 1824 -#define XSEM_FUNC5_START 1824 - {OP_WR_E1H, XSEM_REG_FAST_MEMORY + 0xc7f4, 0x0}, - {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x2b30, 0x1003e0}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x5160, 0xe}, -#define XSEM_FUNC5_END 1827 -#define XSEM_FUNC6_START 1827 - {OP_WR_E1H, XSEM_REG_FAST_MEMORY + 0xc7f8, 0x0}, - {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x2b70, 0x1003f0}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x5198, 0xe}, -#define XSEM_FUNC6_END 1830 -#define XSEM_FUNC7_START 1830 - {OP_WR_E1H, XSEM_REG_FAST_MEMORY + 0xc7fc, 0x0}, - {OP_SW_E1H, XSEM_REG_FAST_MEMORY + 0x2bb0, 0x100400}, - {OP_ZR_E1H, XSEM_REG_FAST_MEMORY + 0x51d0, 0xe}, -#define XSEM_FUNC7_END 1833 -#define CDU_COMMON_START 1833 - {OP_WR, CDU_REG_CDU_CONTROL0, 0x1}, - {OP_WR_E1H, CDU_REG_MF_MODE, 0x1}, - {OP_WR, CDU_REG_CDU_CHK_MASK0, 0x3d000}, - {OP_WR, CDU_REG_CDU_CHK_MASK1, 0x3d}, - {OP_WB_E1, CDU_REG_L1TT, 0x200034d}, - {OP_WB_E1H, CDU_REG_L1TT, 0x2000410}, - {OP_WB_E1, CDU_REG_MATT, 0x20054d}, - {OP_WB_E1H, CDU_REG_MATT, 0x280610}, - {OP_ZR_E1, CDU_REG_MATT + 0x80, 0x2}, - {OP_WB_E1, CDU_REG_MATT + 0x88, 0x6056d}, - {OP_ZR, CDU_REG_MATT + 0xa0, 0x18}, -#define CDU_COMMON_END 1844 -#define DMAE_COMMON_START 1844 - {OP_ZR, DMAE_REG_CMD_MEM, 0xe0}, - {OP_WR, DMAE_REG_CRC16C_INIT, 0x0}, - {OP_WR, DMAE_REG_CRC16T10_INIT, 0x1}, - {OP_WR_E1, DMAE_REG_PXP_REQ_INIT_CRD, 0x1}, - {OP_WR_E1H, DMAE_REG_PXP_REQ_INIT_CRD, 0x2}, - {OP_WR, DMAE_REG_PCI_IFEN, 0x1}, - {OP_WR, DMAE_REG_GRC_IFEN, 0x1}, -#define DMAE_COMMON_END 1851 -#define PXP_COMMON_START 1851 - {OP_WB_E1, PXP_REG_HST_INBOUND_INT + 0x400, 0x50573}, - {OP_WB_E1H, PXP_REG_HST_INBOUND_INT + 0x400, 0x50638}, - {OP_WB_E1, PXP_REG_HST_INBOUND_INT + 0x420, 0x50578}, - {OP_WB_E1H, PXP_REG_HST_INBOUND_INT, 0x5063d}, - {OP_WB_E1, PXP_REG_HST_INBOUND_INT, 0x5057d}, - {OP_WB_E1H, PXP_REG_HST_INBOUND_INT + 0x20, 0x50642}, -#define PXP_COMMON_END 1857 -#define CFC_COMMON_START 1857 - {OP_ZR_E1H, CFC_REG_LINK_LIST, 0x100}, - {OP_WR, CFC_REG_CONTROL0, 0x10}, - {OP_WR, CFC_REG_DISABLE_ON_ERROR, 0x3fff}, - {OP_WR, CFC_REG_INTERFACES, 0x280000}, - {OP_WR, CFC_REG_LCREQ_WEIGHTS, 0x84924a}, - {OP_WR, CFC_REG_INTERFACES, 0x0}, -#define CFC_COMMON_END 1863 -#define HC_COMMON_START 1863 - {OP_ZR_E1, HC_REG_USTORM_ADDR_FOR_COALESCE, 0x4}, -#define HC_COMMON_END 1864 -#define HC_PORT0_START 1864 - {OP_WR_E1, HC_REG_CONFIG_0, 0x1080}, - {OP_ZR_E1, HC_REG_UC_RAM_ADDR_0, 0x2}, - {OP_WR_E1, HC_REG_ATTN_NUM_P0, 0x10}, - {OP_WR_E1, HC_REG_LEADING_EDGE_0, 0xffff}, - {OP_WR_E1, HC_REG_TRAILING_EDGE_0, 0xffff}, - {OP_WR_E1, HC_REG_AGG_INT_0, 0x0}, - {OP_WR_E1, HC_REG_ATTN_IDX, 0x0}, - {OP_ZR_E1, HC_REG_ATTN_BIT, 0x2}, - {OP_WR_E1, HC_REG_VQID_0, 0x2b5}, - {OP_WR_E1, HC_REG_PCI_CONFIG_0, 0x0}, - {OP_ZR_E1, HC_REG_P0_PROD_CONS, 0x4a}, - {OP_WR_E1, HC_REG_INT_MASK, 0x1ffff}, - {OP_ZR_E1, HC_REG_PBA_COMMAND, 0x2}, - {OP_WR_E1, HC_REG_CONFIG_0, 0x1a80}, - {OP_ZR_E1, HC_REG_STATISTIC_COUNTERS, 0x24}, - {OP_ZR_E1, HC_REG_STATISTIC_COUNTERS + 0x120, 0x4a}, - {OP_ZR_E1, HC_REG_STATISTIC_COUNTERS + 0x370, 0x4a}, - {OP_ZR_E1, HC_REG_STATISTIC_COUNTERS + 0x5c0, 0x4a}, -#define HC_PORT0_END 1882 -#define HC_PORT1_START 1882 - {OP_WR_E1, HC_REG_CONFIG_1, 0x1080}, - {OP_ZR_E1, HC_REG_UC_RAM_ADDR_1, 0x2}, - {OP_WR_E1, HC_REG_ATTN_NUM_P1, 0x10}, - {OP_WR_E1, HC_REG_LEADING_EDGE_1, 0xffff}, - {OP_WR_E1, HC_REG_TRAILING_EDGE_1, 0xffff}, - {OP_WR_E1, HC_REG_AGG_INT_1, 0x0}, - {OP_WR_E1, HC_REG_ATTN_IDX + 0x4, 0x0}, - {OP_ZR_E1, HC_REG_ATTN_BIT + 0x8, 0x2}, - {OP_WR_E1, HC_REG_VQID_1, 0x2b5}, - {OP_WR_E1, HC_REG_PCI_CONFIG_1, 0x0}, - {OP_ZR_E1, HC_REG_P1_PROD_CONS, 0x4a}, - {OP_WR_E1, HC_REG_INT_MASK + 0x4, 0x1ffff}, - {OP_ZR_E1, HC_REG_PBA_COMMAND + 0x8, 0x2}, - {OP_WR_E1, HC_REG_CONFIG_1, 0x1a80}, - {OP_ZR_E1, HC_REG_STATISTIC_COUNTERS + 0x90, 0x24}, - {OP_ZR_E1, HC_REG_STATISTIC_COUNTERS + 0x248, 0x4a}, - {OP_ZR_E1, HC_REG_STATISTIC_COUNTERS + 0x498, 0x4a}, - {OP_ZR_E1, HC_REG_STATISTIC_COUNTERS + 0x6e8, 0x4a}, -#define HC_PORT1_END 1900 -#define HC_FUNC0_START 1900 - {OP_WR_E1H, HC_REG_CONFIG_0, 0x1080}, - {OP_WR_E1H, HC_REG_FUNC_NUM_P0, 0x0}, - {OP_WR_E1H, HC_REG_ATTN_NUM_P0, 0x10}, - {OP_WR_E1H, HC_REG_ATTN_IDX, 0x0}, - {OP_ZR_E1H, HC_REG_ATTN_BIT, 0x2}, - {OP_WR_E1H, HC_REG_VQID_0, 0x2b5}, - {OP_WR_E1H, HC_REG_PCI_CONFIG_0, 0x0}, - {OP_ZR_E1H, HC_REG_P0_PROD_CONS, 0x4a}, - {OP_WR_E1H, HC_REG_INT_MASK, 0x1ffff}, - {OP_ZR_E1H, HC_REG_PBA_COMMAND, 0x2}, - {OP_WR_E1H, HC_REG_CONFIG_0, 0x1a80}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS, 0x24}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x120, 0x4a}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x370, 0x4a}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x5c0, 0x4a}, -#define HC_FUNC0_END 1915 -#define HC_FUNC1_START 1915 - {OP_WR_E1H, HC_REG_CONFIG_1, 0x1080}, - {OP_WR_E1H, HC_REG_FUNC_NUM_P1, 0x1}, - {OP_WR_E1H, HC_REG_ATTN_NUM_P1, 0x10}, - {OP_WR_E1H, HC_REG_ATTN_IDX + 0x4, 0x0}, - {OP_ZR_E1H, HC_REG_ATTN_BIT + 0x8, 0x2}, - {OP_WR_E1H, HC_REG_VQID_1, 0x2b5}, - {OP_WR_E1H, HC_REG_PCI_CONFIG_1, 0x0}, - {OP_ZR_E1H, HC_REG_P1_PROD_CONS, 0x4a}, - {OP_WR_E1H, HC_REG_INT_MASK + 0x4, 0x1ffff}, - {OP_ZR_E1H, HC_REG_PBA_COMMAND + 0x8, 0x2}, - {OP_WR_E1H, HC_REG_CONFIG_1, 0x1a80}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x90, 0x24}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x248, 0x4a}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x498, 0x4a}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x6e8, 0x4a}, -#define HC_FUNC1_END 1930 -#define HC_FUNC2_START 1930 - {OP_WR_E1H, HC_REG_CONFIG_0, 0x1080}, - {OP_WR_E1H, HC_REG_FUNC_NUM_P0, 0x2}, - {OP_WR_E1H, HC_REG_ATTN_NUM_P0, 0x10}, - {OP_WR_E1H, HC_REG_ATTN_IDX, 0x0}, - {OP_ZR_E1H, HC_REG_ATTN_BIT, 0x2}, - {OP_WR_E1H, HC_REG_VQID_0, 0x2b5}, - {OP_WR_E1H, HC_REG_PCI_CONFIG_0, 0x0}, - {OP_ZR_E1H, HC_REG_P0_PROD_CONS, 0x4a}, - {OP_WR_E1H, HC_REG_INT_MASK, 0x1ffff}, - {OP_ZR_E1H, HC_REG_PBA_COMMAND, 0x2}, - {OP_WR_E1H, HC_REG_CONFIG_0, 0x1a80}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS, 0x24}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x120, 0x4a}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x370, 0x4a}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x5c0, 0x4a}, -#define HC_FUNC2_END 1945 -#define HC_FUNC3_START 1945 - {OP_WR_E1H, HC_REG_CONFIG_1, 0x1080}, - {OP_WR_E1H, HC_REG_FUNC_NUM_P1, 0x3}, - {OP_WR_E1H, HC_REG_ATTN_NUM_P1, 0x10}, - {OP_WR_E1H, HC_REG_ATTN_IDX + 0x4, 0x0}, - {OP_ZR_E1H, HC_REG_ATTN_BIT + 0x8, 0x2}, - {OP_WR_E1H, HC_REG_VQID_1, 0x2b5}, - {OP_WR_E1H, HC_REG_PCI_CONFIG_1, 0x0}, - {OP_ZR_E1H, HC_REG_P1_PROD_CONS, 0x4a}, - {OP_WR_E1H, HC_REG_INT_MASK + 0x4, 0x1ffff}, - {OP_ZR_E1H, HC_REG_PBA_COMMAND + 0x8, 0x2}, - {OP_WR_E1H, HC_REG_CONFIG_1, 0x1a80}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x90, 0x24}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x248, 0x4a}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x498, 0x4a}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x6e8, 0x4a}, -#define HC_FUNC3_END 1960 -#define HC_FUNC4_START 1960 - {OP_WR_E1H, HC_REG_CONFIG_0, 0x1080}, - {OP_WR_E1H, HC_REG_FUNC_NUM_P0, 0x4}, - {OP_WR_E1H, HC_REG_ATTN_NUM_P0, 0x10}, - {OP_WR_E1H, HC_REG_ATTN_IDX, 0x0}, - {OP_ZR_E1H, HC_REG_ATTN_BIT, 0x2}, - {OP_WR_E1H, HC_REG_VQID_0, 0x2b5}, - {OP_WR_E1H, HC_REG_PCI_CONFIG_0, 0x0}, - {OP_ZR_E1H, HC_REG_P0_PROD_CONS, 0x4a}, - {OP_WR_E1H, HC_REG_INT_MASK, 0x1ffff}, - {OP_ZR_E1H, HC_REG_PBA_COMMAND, 0x2}, - {OP_WR_E1H, HC_REG_CONFIG_0, 0x1a80}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS, 0x24}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x120, 0x4a}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x370, 0x4a}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x5c0, 0x4a}, -#define HC_FUNC4_END 1975 -#define HC_FUNC5_START 1975 - {OP_WR_E1H, HC_REG_CONFIG_1, 0x1080}, - {OP_WR_E1H, HC_REG_FUNC_NUM_P1, 0x5}, - {OP_WR_E1H, HC_REG_ATTN_NUM_P1, 0x10}, - {OP_WR_E1H, HC_REG_ATTN_IDX + 0x4, 0x0}, - {OP_ZR_E1H, HC_REG_ATTN_BIT + 0x8, 0x2}, - {OP_WR_E1H, HC_REG_VQID_1, 0x2b5}, - {OP_WR_E1H, HC_REG_PCI_CONFIG_1, 0x0}, - {OP_ZR_E1H, HC_REG_P1_PROD_CONS, 0x4a}, - {OP_WR_E1H, HC_REG_INT_MASK + 0x4, 0x1ffff}, - {OP_ZR_E1H, HC_REG_PBA_COMMAND + 0x8, 0x2}, - {OP_WR_E1H, HC_REG_CONFIG_1, 0x1a80}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x90, 0x24}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x248, 0x4a}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x498, 0x4a}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x6e8, 0x4a}, -#define HC_FUNC5_END 1990 -#define HC_FUNC6_START 1990 - {OP_WR_E1H, HC_REG_CONFIG_0, 0x1080}, - {OP_WR_E1H, HC_REG_FUNC_NUM_P0, 0x6}, - {OP_WR_E1H, HC_REG_ATTN_NUM_P0, 0x10}, - {OP_WR_E1H, HC_REG_ATTN_IDX, 0x0}, - {OP_ZR_E1H, HC_REG_ATTN_BIT, 0x2}, - {OP_WR_E1H, HC_REG_VQID_0, 0x2b5}, - {OP_WR_E1H, HC_REG_PCI_CONFIG_0, 0x0}, - {OP_ZR_E1H, HC_REG_P0_PROD_CONS, 0x4a}, - {OP_WR_E1H, HC_REG_INT_MASK, 0x1ffff}, - {OP_ZR_E1H, HC_REG_PBA_COMMAND, 0x2}, - {OP_WR_E1H, HC_REG_CONFIG_0, 0x1a80}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS, 0x24}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x120, 0x4a}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x370, 0x4a}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x5c0, 0x4a}, -#define HC_FUNC6_END 2005 -#define HC_FUNC7_START 2005 - {OP_WR_E1H, HC_REG_CONFIG_1, 0x1080}, - {OP_WR_E1H, HC_REG_FUNC_NUM_P1, 0x7}, - {OP_WR_E1H, HC_REG_ATTN_NUM_P1, 0x10}, - {OP_WR_E1H, HC_REG_ATTN_IDX + 0x4, 0x0}, - {OP_ZR_E1H, HC_REG_ATTN_BIT + 0x8, 0x2}, - {OP_WR_E1H, HC_REG_VQID_1, 0x2b5}, - {OP_WR_E1H, HC_REG_PCI_CONFIG_1, 0x0}, - {OP_ZR_E1H, HC_REG_P1_PROD_CONS, 0x4a}, - {OP_WR_E1H, HC_REG_INT_MASK + 0x4, 0x1ffff}, - {OP_ZR_E1H, HC_REG_PBA_COMMAND + 0x8, 0x2}, - {OP_WR_E1H, HC_REG_CONFIG_1, 0x1a80}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x90, 0x24}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x248, 0x4a}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x498, 0x4a}, - {OP_ZR_E1H, HC_REG_STATISTIC_COUNTERS + 0x6e8, 0x4a}, -#define HC_FUNC7_END 2020 -#define PXP2_COMMON_START 2020 - {OP_WR_E1H, PXP2_REG_RQ_DRAM_ALIGN, 0x1}, - {OP_WR, PXP2_REG_PGL_CONTROL0, 0xe38340}, - {OP_WR, PXP2_REG_PGL_CONTROL1, 0x3c10}, - {OP_WR_E1H, PXP2_REG_RQ_ELT_DISABLE, 0x1}, - {OP_WR_E1H, PXP2_REG_WR_REV_MODE, 0x0}, - {OP_WR, PXP2_REG_PGL_INT_TSDM_0, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_TSDM_1, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_TSDM_2, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_TSDM_3, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_TSDM_4, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_TSDM_5, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_TSDM_6, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_TSDM_7, 0xffffffff}, - {OP_WR_E1, PXP2_REG_PGL_INT_USDM_1, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_USDM_2, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_USDM_3, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_USDM_4, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_USDM_5, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_USDM_6, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_USDM_7, 0xffffffff}, - {OP_WR_E1H, PXP2_REG_PGL_INT_XSDM_1, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_XSDM_2, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_XSDM_3, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_XSDM_4, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_XSDM_5, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_XSDM_6, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_XSDM_7, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_CSDM_0, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_CSDM_1, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_CSDM_2, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_CSDM_3, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_CSDM_4, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_CSDM_5, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_CSDM_6, 0xffffffff}, - {OP_WR, PXP2_REG_PGL_INT_CSDM_7, 0xffffffff}, - {OP_WR_E1, PXP2_REG_PGL_INT_XSDM_0, 0xffff3330}, - {OP_WR_E1H, PXP2_REG_PGL_INT_XSDM_0, 0xff802000}, - {OP_WR_E1, PXP2_REG_PGL_INT_XSDM_1, 0xffff3340}, - {OP_WR_E1H, PXP2_REG_PGL_INT_USDM_0, 0xf0005000}, - {OP_WR_E1, PXP2_REG_PGL_INT_USDM_0, 0xf0003000}, - {OP_WR_E1H, PXP2_REG_PGL_INT_USDM_1, 0xf0008000}, - {OP_WR, PXP2_REG_RD_MAX_BLKS_VQ6, 0x8}, - {OP_WR, PXP2_REG_RD_MAX_BLKS_VQ9, 0x8}, - {OP_WR, PXP2_REG_RD_MAX_BLKS_VQ10, 0x8}, - {OP_WR, PXP2_REG_RD_MAX_BLKS_VQ11, 0x2}, - {OP_WR, PXP2_REG_RD_MAX_BLKS_VQ17, 0x4}, - {OP_WR, PXP2_REG_RD_MAX_BLKS_VQ18, 0x5}, - {OP_WR, PXP2_REG_RD_MAX_BLKS_VQ19, 0x4}, - {OP_WR, PXP2_REG_RD_MAX_BLKS_VQ22, 0x0}, - {OP_WR, PXP2_REG_RD_START_INIT, 0x1}, - {OP_WR, PXP2_REG_WR_DMAE_TH, 0x3f}, - {OP_WR, PXP2_REG_RQ_BW_RD_ADD0, 0x40}, - {OP_WR, PXP2_REG_PSWRQ_BW_ADD1, 0x1808}, - {OP_WR, PXP2_REG_PSWRQ_BW_ADD2, 0x803}, - {OP_WR, PXP2_REG_PSWRQ_BW_ADD3, 0x803}, - {OP_WR, PXP2_REG_RQ_BW_RD_ADD4, 0x40}, - {OP_WR, PXP2_REG_RQ_BW_RD_ADD5, 0x3}, - {OP_WR, PXP2_REG_PSWRQ_BW_ADD6, 0x803}, - {OP_WR, PXP2_REG_PSWRQ_BW_ADD7, 0x803}, - {OP_WR, PXP2_REG_PSWRQ_BW_ADD8, 0x803}, - {OP_WR, PXP2_REG_PSWRQ_BW_ADD9, 0x10003}, - {OP_WR, PXP2_REG_PSWRQ_BW_ADD10, 0x803}, - {OP_WR, PXP2_REG_PSWRQ_BW_ADD11, 0x803}, - {OP_WR, PXP2_REG_RQ_BW_RD_ADD12, 0x3}, - {OP_WR, PXP2_REG_RQ_BW_RD_ADD13, 0x3}, - {OP_WR, PXP2_REG_RQ_BW_RD_ADD14, 0x3}, - {OP_WR, PXP2_REG_RQ_BW_RD_ADD15, 0x3}, - {OP_WR, PXP2_REG_RQ_BW_RD_ADD16, 0x3}, - {OP_WR, PXP2_REG_RQ_BW_RD_ADD17, 0x3}, - {OP_WR, PXP2_REG_RQ_BW_RD_ADD18, 0x3}, - {OP_WR, PXP2_REG_RQ_BW_RD_ADD19, 0x3}, - {OP_WR, PXP2_REG_RQ_BW_RD_ADD20, 0x3}, - {OP_WR, PXP2_REG_RQ_BW_RD_ADD22, 0x3}, - {OP_WR, PXP2_REG_RQ_BW_RD_ADD23, 0x3}, - {OP_WR, PXP2_REG_RQ_BW_RD_ADD24, 0x3}, - {OP_WR, PXP2_REG_RQ_BW_RD_ADD25, 0x3}, - {OP_WR, PXP2_REG_RQ_BW_RD_ADD26, 0x3}, - {OP_WR, PXP2_REG_RQ_BW_RD_ADD27, 0x3}, - {OP_WR, PXP2_REG_PSWRQ_BW_ADD28, 0x2403}, - {OP_WR, PXP2_REG_RQ_BW_WR_ADD29, 0x2f}, - {OP_WR, PXP2_REG_RQ_BW_WR_ADD30, 0x9}, - {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND0, 0x19}, - {OP_WR, PXP2_REG_PSWRQ_BW_UB1, 0x184}, - {OP_WR, PXP2_REG_PSWRQ_BW_UB2, 0x183}, - {OP_WR, PXP2_REG_PSWRQ_BW_UB3, 0x306}, - {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND4, 0x19}, - {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND5, 0x6}, - {OP_WR, PXP2_REG_PSWRQ_BW_UB6, 0x306}, - {OP_WR, PXP2_REG_PSWRQ_BW_UB7, 0x306}, - {OP_WR, PXP2_REG_PSWRQ_BW_UB8, 0x306}, - {OP_WR, PXP2_REG_PSWRQ_BW_UB9, 0xc86}, - {OP_WR, PXP2_REG_PSWRQ_BW_UB10, 0x306}, - {OP_WR, PXP2_REG_PSWRQ_BW_UB11, 0x306}, - {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND12, 0x6}, - {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND13, 0x6}, - {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND14, 0x6}, - {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND15, 0x6}, - {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND16, 0x6}, - {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND17, 0x6}, - {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND18, 0x6}, - {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND19, 0x6}, - {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND20, 0x6}, - {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND22, 0x6}, - {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND23, 0x6}, - {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND24, 0x6}, - {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND25, 0x6}, - {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND26, 0x6}, - {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND27, 0x6}, - {OP_WR, PXP2_REG_PSWRQ_BW_UB28, 0x306}, - {OP_WR, PXP2_REG_RQ_BW_WR_UBOUND29, 0x13}, - {OP_WR, PXP2_REG_RQ_BW_WR_UBOUND30, 0x6}, - {OP_WR, PXP2_REG_PSWRQ_BW_L1, 0x1004}, - {OP_WR, PXP2_REG_PSWRQ_BW_L2, 0x1004}, - {OP_WR, PXP2_REG_PSWRQ_BW_RD, 0x106440}, - {OP_WR, PXP2_REG_PSWRQ_BW_WR, 0x106440}, - {OP_WR_E1H, PXP2_REG_RQ_ILT_MODE, 0x1}, - {OP_WR, PXP2_REG_RQ_RBC_DONE, 0x1}, -#define PXP2_COMMON_END 2137 -#define MISC_AEU_COMMON_START 2137 - {OP_ZR, MISC_REG_AEU_GENERAL_ATTN_0, 0x16}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE1_NIG_0, 0x55540000}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE2_NIG_0, 0x55555555}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE3_NIG_0, 0x5555}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE4_NIG_0, 0xf0000000}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE1_PXP_0, 0x55540000}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE2_PXP_0, 0x55555555}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE3_PXP_0, 0x5555}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE4_PXP_0, 0xf0000000}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE1_NIG_1, 0x55540000}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE2_NIG_1, 0x55555555}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE3_NIG_1, 0x5555}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE4_NIG_1, 0xf0000000}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE1_PXP_1, 0x0}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE2_PXP_1, 0x10000}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE3_PXP_1, 0x5014}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE4_PXP_1, 0x0}, - {OP_WR_E1H, MISC_REG_AEU_CLR_LATCH_SIGNAL, 0xc00}, - {OP_WR_E1H, MISC_REG_AEU_GENERAL_MASK, 0x3}, -#define MISC_AEU_COMMON_END 2156 -#define MISC_AEU_PORT0_START 2156 - {OP_WR_E1, MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0, 0xbf5c0000}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0, 0xff5c0000}, - {OP_WR_E1, MISC_REG_AEU_ENABLE2_FUNC_0_OUT_0, 0xfff51fef}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE2_FUNC_0_OUT_0, 0xfff55fff}, - {OP_WR, MISC_REG_AEU_ENABLE3_FUNC_0_OUT_0, 0xffff}, - {OP_WR_E1, MISC_REG_AEU_ENABLE4_FUNC_0_OUT_0, 0x500003e0}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE4_FUNC_0_OUT_0, 0xf00003e0}, - {OP_WR, MISC_REG_AEU_ENABLE1_FUNC_0_OUT_1, 0x0}, - {OP_WR, MISC_REG_AEU_ENABLE2_FUNC_0_OUT_1, 0xa000}, - {OP_ZR, MISC_REG_AEU_ENABLE3_FUNC_0_OUT_1, 0x5}, - {OP_WR, MISC_REG_AEU_ENABLE4_FUNC_0_OUT_2, 0xfe00000}, - {OP_ZR_E1, MISC_REG_AEU_ENABLE1_FUNC_0_OUT_3, 0x14}, - {OP_ZR_E1H, MISC_REG_AEU_ENABLE1_FUNC_0_OUT_3, 0x7}, - {OP_WR_E1, MISC_REG_AEU_ENABLE1_NIG_0, 0x55540000}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE4_FUNC_0_OUT_4, 0x400}, - {OP_WR_E1, MISC_REG_AEU_ENABLE2_NIG_0, 0x55555555}, - {OP_ZR_E1H, MISC_REG_AEU_ENABLE1_FUNC_0_OUT_5, 0x3}, - {OP_WR_E1, MISC_REG_AEU_ENABLE3_NIG_0, 0x5555}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE4_FUNC_0_OUT_5, 0x1000}, - {OP_WR_E1, MISC_REG_AEU_ENABLE4_NIG_0, 0x0}, - {OP_ZR_E1H, MISC_REG_AEU_ENABLE1_FUNC_0_OUT_6, 0x3}, - {OP_WR_E1, MISC_REG_AEU_ENABLE1_PXP_0, 0x55540000}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE4_FUNC_0_OUT_6, 0x4000}, - {OP_WR_E1, MISC_REG_AEU_ENABLE2_PXP_0, 0x55555555}, - {OP_ZR_E1H, MISC_REG_AEU_ENABLE1_FUNC_0_OUT_7, 0x3}, - {OP_WR_E1, MISC_REG_AEU_ENABLE3_PXP_0, 0x5555}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE4_FUNC_0_OUT_7, 0x10000}, - {OP_WR_E1, MISC_REG_AEU_ENABLE4_PXP_0, 0x0}, - {OP_ZR_E1H, MISC_REG_AEU_INVERTER_1_FUNC_0, 0x4}, - {OP_WR_E1, MISC_REG_AEU_INVERTER_1_FUNC_0, 0x0}, - {OP_ZR_E1, MISC_REG_AEU_INVERTER_2_FUNC_0, 0x3}, - {OP_WR_E1, MISC_REG_AEU_MASK_ATTN_FUNC_0, 0x7}, -#define MISC_AEU_PORT0_END 2188 -#define MISC_AEU_PORT1_START 2188 - {OP_WR_E1, MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0, 0xbf5c0000}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0, 0xff5c0000}, - {OP_WR_E1, MISC_REG_AEU_ENABLE2_FUNC_1_OUT_0, 0xfff51fef}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE2_FUNC_1_OUT_0, 0xfff55fff}, - {OP_WR, MISC_REG_AEU_ENABLE3_FUNC_1_OUT_0, 0xffff}, - {OP_WR_E1, MISC_REG_AEU_ENABLE4_FUNC_1_OUT_0, 0x500003e0}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE4_FUNC_1_OUT_0, 0xf00003e0}, - {OP_WR, MISC_REG_AEU_ENABLE1_FUNC_1_OUT_1, 0x0}, - {OP_WR, MISC_REG_AEU_ENABLE2_FUNC_1_OUT_1, 0xa000}, - {OP_ZR, MISC_REG_AEU_ENABLE3_FUNC_1_OUT_1, 0x5}, - {OP_WR, MISC_REG_AEU_ENABLE4_FUNC_1_OUT_2, 0xfe00000}, - {OP_ZR_E1, MISC_REG_AEU_ENABLE1_FUNC_1_OUT_3, 0x14}, - {OP_ZR_E1H, MISC_REG_AEU_ENABLE1_FUNC_1_OUT_3, 0x7}, - {OP_WR_E1, MISC_REG_AEU_ENABLE1_NIG_1, 0x55540000}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE4_FUNC_1_OUT_4, 0x800}, - {OP_WR_E1, MISC_REG_AEU_ENABLE2_NIG_1, 0x55555555}, - {OP_ZR_E1H, MISC_REG_AEU_ENABLE1_FUNC_1_OUT_5, 0x3}, - {OP_WR_E1, MISC_REG_AEU_ENABLE3_NIG_1, 0x5555}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE4_FUNC_1_OUT_5, 0x2000}, - {OP_WR_E1, MISC_REG_AEU_ENABLE4_NIG_1, 0x0}, - {OP_ZR_E1H, MISC_REG_AEU_ENABLE1_FUNC_1_OUT_6, 0x3}, - {OP_WR_E1, MISC_REG_AEU_ENABLE1_PXP_1, 0x55540000}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE4_FUNC_1_OUT_6, 0x8000}, - {OP_WR_E1, MISC_REG_AEU_ENABLE2_PXP_1, 0x55555555}, - {OP_ZR_E1H, MISC_REG_AEU_ENABLE1_FUNC_1_OUT_7, 0x3}, - {OP_WR_E1, MISC_REG_AEU_ENABLE3_PXP_1, 0x5555}, - {OP_WR_E1H, MISC_REG_AEU_ENABLE4_FUNC_1_OUT_7, 0x20000}, - {OP_WR_E1, MISC_REG_AEU_ENABLE4_PXP_1, 0x0}, - {OP_ZR_E1H, MISC_REG_AEU_INVERTER_1_FUNC_1, 0x4}, - {OP_WR_E1, MISC_REG_AEU_INVERTER_1_FUNC_1, 0x0}, - {OP_ZR_E1, MISC_REG_AEU_INVERTER_2_FUNC_1, 0x3}, - {OP_WR_E1, MISC_REG_AEU_MASK_ATTN_FUNC_1, 0x7}, -#define MISC_AEU_PORT1_END 2220 - -}; - -static const u32 init_data_e1[] = { - 0x00010000, 0x000204c0, 0x00030980, 0x00040e40, 0x00051300, 0x000617c0, - 0x00071c80, 0x00082140, 0x00092600, 0x000a2ac0, 0x000b2f80, 0x000c3440, - 0x000d3900, 0x000e3dc0, 0x000f4280, 0x00104740, 0x00114c00, 0x001250c0, - 0x00135580, 0x00145a40, 0x00155f00, 0x001663c0, 0x00176880, 0x00186d40, - 0x00197200, 0x001a76c0, 0x001b7b80, 0x001c8040, 0x001d8500, 0x001e89c0, - 0x001f8e80, 0x00209340, 0x00002000, 0x00004000, 0x00006000, 0x00008000, - 0x0000a000, 0x0000c000, 0x0000e000, 0x00010000, 0x00012000, 0x00014000, - 0x00016000, 0x00018000, 0x0001a000, 0x0001c000, 0x0001e000, 0x00020000, - 0x00022000, 0x00024000, 0x00026000, 0x00028000, 0x0002a000, 0x0002c000, - 0x0002e000, 0x00030000, 0x00032000, 0x00034000, 0x00036000, 0x00038000, - 0x0003a000, 0x0003c000, 0x0003e000, 0x00040000, 0x00042000, 0x00044000, - 0x00046000, 0x00048000, 0x0004a000, 0x0004c000, 0x0004e000, 0x00050000, - 0x00052000, 0x00054000, 0x00056000, 0x00058000, 0x0005a000, 0x0005c000, - 0x0005e000, 0x00060000, 0x00062000, 0x00064000, 0x00066000, 0x00068000, - 0x0006a000, 0x0006c000, 0x0006e000, 0x00070000, 0x00072000, 0x00074000, - 0x00076000, 0x00078000, 0x0007a000, 0x0007c000, 0x0007e000, 0x00080000, - 0x00082000, 0x00084000, 0x00086000, 0x00088000, 0x0008a000, 0x0008c000, - 0x0008e000, 0x00090000, 0x00092000, 0x00094000, 0x00096000, 0x00098000, - 0x0009a000, 0x0009c000, 0x0009e000, 0x000a0000, 0x000a2000, 0x000a4000, - 0x000a6000, 0x000a8000, 0x000aa000, 0x000ac000, 0x000ae000, 0x000b0000, - 0x000b2000, 0x000b4000, 0x000b6000, 0x000b8000, 0x000ba000, 0x000bc000, - 0x000be000, 0x000c0000, 0x000c2000, 0x000c4000, 0x000c6000, 0x000c8000, - 0x000ca000, 0x000cc000, 0x000ce000, 0x000d0000, 0x000d2000, 0x000d4000, - 0x000d6000, 0x000d8000, 0x000da000, 0x000dc000, 0x000de000, 0x000e0000, - 0x000e2000, 0x000e4000, 0x000e6000, 0x000e8000, 0x000ea000, 0x000ec000, - 0x000ee000, 0x000f0000, 0x000f2000, 0x000f4000, 0x000f6000, 0x000f8000, - 0x000fa000, 0x000fc000, 0x000fe000, 0x00100000, 0x00102000, 0x00104000, - 0x00106000, 0x00108000, 0x0010a000, 0x0010c000, 0x0010e000, 0x00110000, - 0x00112000, 0x00114000, 0x00116000, 0x00118000, 0x0011a000, 0x0011c000, - 0x0011e000, 0x00120000, 0x00122000, 0x00124000, 0x00126000, 0x00128000, - 0x0012a000, 0x0012c000, 0x0012e000, 0x00130000, 0x00132000, 0x00134000, - 0x00136000, 0x00138000, 0x0013a000, 0x0013c000, 0x0013e000, 0x00140000, - 0x00142000, 0x00144000, 0x00146000, 0x00148000, 0x0014a000, 0x0014c000, - 0x0014e000, 0x00150000, 0x00152000, 0x00154000, 0x00156000, 0x00158000, - 0x0015a000, 0x0015c000, 0x0015e000, 0x00160000, 0x00162000, 0x00164000, - 0x00166000, 0x00168000, 0x0016a000, 0x0016c000, 0x0016e000, 0x00170000, - 0x00172000, 0x00174000, 0x00176000, 0x00178000, 0x0017a000, 0x0017c000, - 0x0017e000, 0x00180000, 0x00182000, 0x00184000, 0x00186000, 0x00188000, - 0x0018a000, 0x0018c000, 0x0018e000, 0x00190000, 0x00192000, 0x00194000, - 0x00196000, 0x00198000, 0x0019a000, 0x0019c000, 0x0019e000, 0x001a0000, - 0x001a2000, 0x001a4000, 0x001a6000, 0x001a8000, 0x001aa000, 0x001ac000, - 0x001ae000, 0x001b0000, 0x001b2000, 0x001b4000, 0x001b6000, 0x001b8000, - 0x001ba000, 0x001bc000, 0x001be000, 0x001c0000, 0x001c2000, 0x001c4000, - 0x001c6000, 0x001c8000, 0x001ca000, 0x001cc000, 0x001ce000, 0x001d0000, - 0x001d2000, 0x001d4000, 0x001d6000, 0x001d8000, 0x001da000, 0x001dc000, - 0x001de000, 0x001e0000, 0x001e2000, 0x001e4000, 0x001e6000, 0x001e8000, - 0x001ea000, 0x001ec000, 0x001ee000, 0x001f0000, 0x001f2000, 0x001f4000, - 0x001f6000, 0x001f8000, 0x001fa000, 0x001fc000, 0x001fe000, 0x00200000, - 0x00202000, 0x00204000, 0x00206000, 0x00208000, 0x0020a000, 0x0020c000, - 0x0020e000, 0x00210000, 0x00212000, 0x00214000, 0x00216000, 0x00218000, - 0x0021a000, 0x0021c000, 0x0021e000, 0x00220000, 0x00222000, 0x00224000, - 0x00226000, 0x00228000, 0x0022a000, 0x0022c000, 0x0022e000, 0x00230000, - 0x00232000, 0x00234000, 0x00236000, 0x00238000, 0x0023a000, 0x0023c000, - 0x0023e000, 0x00240000, 0x00242000, 0x00244000, 0x00246000, 0x00248000, - 0x0024a000, 0x0024c000, 0x0024e000, 0x00250000, 0x00252000, 0x00254000, - 0x00256000, 0x00258000, 0x0025a000, 0x0025c000, 0x0025e000, 0x00260000, - 0x00262000, 0x00264000, 0x00266000, 0x00268000, 0x0026a000, 0x0026c000, - 0x0026e000, 0x00270000, 0x00272000, 0x00274000, 0x00276000, 0x00278000, - 0x0027a000, 0x0027c000, 0x0027e000, 0x00280000, 0x00282000, 0x00284000, - 0x00286000, 0x00288000, 0x0028a000, 0x0028c000, 0x0028e000, 0x00290000, - 0x00292000, 0x00294000, 0x00296000, 0x00298000, 0x0029a000, 0x0029c000, - 0x0029e000, 0x002a0000, 0x002a2000, 0x002a4000, 0x002a6000, 0x002a8000, - 0x002aa000, 0x002ac000, 0x002ae000, 0x002b0000, 0x002b2000, 0x002b4000, - 0x002b6000, 0x002b8000, 0x002ba000, 0x002bc000, 0x002be000, 0x002c0000, - 0x002c2000, 0x002c4000, 0x002c6000, 0x002c8000, 0x002ca000, 0x002cc000, - 0x002ce000, 0x002d0000, 0x002d2000, 0x002d4000, 0x002d6000, 0x002d8000, - 0x002da000, 0x002dc000, 0x002de000, 0x002e0000, 0x002e2000, 0x002e4000, - 0x002e6000, 0x002e8000, 0x002ea000, 0x002ec000, 0x002ee000, 0x002f0000, - 0x002f2000, 0x002f4000, 0x002f6000, 0x002f8000, 0x002fa000, 0x002fc000, - 0x002fe000, 0x00300000, 0x00302000, 0x00304000, 0x00306000, 0x00308000, - 0x0030a000, 0x0030c000, 0x0030e000, 0x00310000, 0x00312000, 0x00314000, - 0x00316000, 0x00318000, 0x0031a000, 0x0031c000, 0x0031e000, 0x00320000, - 0x00322000, 0x00324000, 0x00326000, 0x00328000, 0x0032a000, 0x0032c000, - 0x0032e000, 0x00330000, 0x00332000, 0x00334000, 0x00336000, 0x00338000, - 0x0033a000, 0x0033c000, 0x0033e000, 0x00340000, 0x00342000, 0x00344000, - 0x00346000, 0x00348000, 0x0034a000, 0x0034c000, 0x0034e000, 0x00350000, - 0x00352000, 0x00354000, 0x00356000, 0x00358000, 0x0035a000, 0x0035c000, - 0x0035e000, 0x00360000, 0x00362000, 0x00364000, 0x00366000, 0x00368000, - 0x0036a000, 0x0036c000, 0x0036e000, 0x00370000, 0x00372000, 0x00374000, - 0x00376000, 0x00378000, 0x0037a000, 0x0037c000, 0x0037e000, 0x00380000, - 0x00382000, 0x00384000, 0x00386000, 0x00388000, 0x0038a000, 0x0038c000, - 0x0038e000, 0x00390000, 0x00392000, 0x00394000, 0x00396000, 0x00398000, - 0x0039a000, 0x0039c000, 0x0039e000, 0x003a0000, 0x003a2000, 0x003a4000, - 0x003a6000, 0x003a8000, 0x003aa000, 0x003ac000, 0x003ae000, 0x003b0000, - 0x003b2000, 0x003b4000, 0x003b6000, 0x003b8000, 0x003ba000, 0x003bc000, - 0x003be000, 0x003c0000, 0x003c2000, 0x003c4000, 0x003c6000, 0x003c8000, - 0x003ca000, 0x003cc000, 0x003ce000, 0x003d0000, 0x003d2000, 0x003d4000, - 0x003d6000, 0x003d8000, 0x003da000, 0x003dc000, 0x003de000, 0x003e0000, - 0x003e2000, 0x003e4000, 0x003e6000, 0x003e8000, 0x003ea000, 0x003ec000, - 0x003ee000, 0x003f0000, 0x003f2000, 0x003f4000, 0x003f6000, 0x003f8000, - 0x003fa000, 0x003fc000, 0x003fe000, 0x003fe001, 0x00000000, 0x000001ff, - 0x00000200, 0x00000001, 0x00000003, 0x00bebc20, 0x00000003, 0x00bebc20, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0x00000000, 0x00007ff8, 0x00000000, 0x00003500, - 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, 0x00000003, - 0x00bebc20, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, - 0x00000003, 0x00bebc20, 0x00002000, 0x000040c0, 0x00006180, 0x00008240, - 0x0000a300, 0x0000c3c0, 0x0000e480, 0x00010540, 0x00012600, 0x000146c0, - 0x00016780, 0x00018840, 0x0001a900, 0x0001c9c0, 0x0001ea80, 0x00020b40, - 0x00022c00, 0x00024cc0, 0x00026d80, 0x00028e40, 0x0002af00, 0x0002cfc0, - 0x0002f080, 0x00031140, 0x00033200, 0x000352c0, 0x00037380, 0x00039440, - 0x0003b500, 0x0003d5c0, 0x0003f680, 0x00041740, 0x00043800, 0x000458c0, - 0x00047980, 0x00049a40, 0x00008000, 0x00010380, 0x00018700, 0x00020a80, - 0x00028e00, 0x00031180, 0x00039500, 0x00041880, 0x00049c00, 0x00051f80, - 0x0005a300, 0x00062680, 0x0006aa00, 0x00072d80, 0x0007b100, 0x00083480, - 0x0008b800, 0x00093b80, 0x0009bf00, 0x000a4280, 0x000ac600, 0x000b4980, - 0x000bcd00, 0x000c5080, 0x000cd400, 0x000d5780, 0x000ddb00, 0x00001900, - 0x00000000, 0xffffffff, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x00000000, 0x00007ff8, - 0x00000000, 0x00001500, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x00000000, 0x00007ff8, 0x00000000, 0x00001500, 0x00001000, 0x00002080, - 0x00003100, 0x00004180, 0x00005200, 0x00006280, 0x00007300, 0x00008380, - 0x00009400, 0x0000a480, 0x0000b500, 0x0000c580, 0x0000d600, 0x0000e680, - 0x0000f700, 0x00010780, 0x00011800, 0x00012880, 0x00013900, 0x00014980, - 0x00015a00, 0x00016a80, 0x00017b00, 0x00018b80, 0x00019c00, 0x0001ac80, - 0x0001bd00, 0x0001cd80, 0x0001de00, 0x0001ee80, 0x0001ff00, 0x10000000, - 0x000028ad, 0x00000000, 0x00010001, 0x00350804, 0xccccccc1, 0xffffffff, - 0xffffffff, 0x7058103c, 0x00000000, 0xcccc0201, 0xcccccccc, 0x00000000, - 0xffffffff, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x00000000, 0x00007ff8, 0x00000000, - 0x00003500, 0x000e01b7, 0x011600d6, 0x0000ffff, 0x00000000, 0x0000ffff, - 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, - 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, - 0x00000000, 0x00100000, 0x00000000, 0x007201bb, 0x012300f3, 0x0000ffff, - 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, - 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, - 0x00000000, 0x0000ffff, 0x00000000, 0x00100000, 0x00000000, 0xfffffff3, - 0x320fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0000cf3c, - 0xcdcdcdcd, 0xfffffff1, 0x30efffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, - 0xf3cf3cf3, 0x0001cf3c, 0xcdcdcdcd, 0xfffffff6, 0x305fffff, 0x0c30c30c, - 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0002cf3c, 0xcdcdcdcd, 0xfffff406, - 0x1cbfffff, 0x0c30c305, 0xc30c30c3, 0xcf300014, 0xf3cf3cf3, 0x0004cf3c, - 0xcdcdcdcd, 0xfffffff2, 0x304fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, - 0xf3cf3cf3, 0x0008cf3c, 0xcdcdcdcd, 0xfffffffa, 0x302fffff, 0x0c30c30c, - 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0010cf3c, 0xcdcdcdcd, 0xfffffff7, - 0x31efffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0020cf3c, - 0xcdcdcdcd, 0xfffffff5, 0x302fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, - 0xf3cf3cf3, 0x0040cf3c, 0xcdcdcdcd, 0xfffffff3, 0x310fffff, 0x0c30c30c, - 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0000cf3c, 0xcdcdcdcd, 0xfffffff1, - 0x310fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0001cf3c, - 0xcdcdcdcd, 0xfffffff6, 0x305fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, - 0xf3cf3cf3, 0x0002cf3c, 0xcdcdcdcd, 0xfffff406, 0x1cbfffff, 0x0c30c305, - 0xc30c30c3, 0xcf300014, 0xf3cf3cf3, 0x0004cf3c, 0xcdcdcdcd, 0xfffffff2, - 0x304fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0008cf3c, - 0xcdcdcdcd, 0xfffffffa, 0x302fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, - 0xf3cf3cf3, 0x0010cf3c, 0xcdcdcdcd, 0xfffffff7, 0x30efffff, 0x0c30c30c, - 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0020cf3c, 0xcdcdcdcd, 0xfffffff5, - 0x304fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0040cf3c, - 0xcdcdcdcd, 0xfffffff3, 0x31efffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, - 0xf3cf3cf3, 0x0000cf3c, 0xcdcdcdcd, 0xfffffff1, 0x310fffff, 0x0c30c30c, - 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0001cf3c, 0xcdcdcdcd, 0xfffffff6, - 0x305fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0002cf3c, - 0xcdcdcdcd, 0xfffff406, 0x1cbfffff, 0x0c30c305, 0xc30c30c3, 0xcf300014, - 0xf3cf3cf3, 0x0004cf3c, 0xcdcdcdcd, 0xfffffff2, 0x304fffff, 0x0c30c30c, - 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0008cf3c, 0xcdcdcdcd, 0xfffffffa, - 0x302fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0010cf3c, - 0xcdcdcdcd, 0xffffff97, 0x056fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cc000, - 0xf3cf3cf3, 0x0020cf3c, 0xcdcdcdcd, 0xfffffff5, 0x310fffff, 0x0c30c30c, - 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0040cf3c, 0xcdcdcdcd, 0xfffffff3, - 0x320fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0000cf3c, - 0xcdcdcdcd, 0xfffffff1, 0x310fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, - 0xf3cf3cf3, 0x0001cf3c, 0xcdcdcdcd, 0xfffffff6, 0x305fffff, 0x0c30c30c, - 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0002cf3c, 0xcdcdcdcd, 0xfffff406, - 0x1cbfffff, 0x0c30c305, 0xc30c30c3, 0xcf300014, 0xf3cf3cf3, 0x0004cf3c, - 0xcdcdcdcd, 0xfffffff2, 0x304fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, - 0xf3cf3cf3, 0x0008cf3c, 0xcdcdcdcd, 0xffffff8a, 0x042fffff, 0x0c30c30c, - 0xc30c30c3, 0xcf3cc000, 0xf3cf3cf3, 0x0010cf3c, 0xcdcdcdcd, 0xffffff97, - 0x05cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cc000, 0xf3cf3cf3, 0x0020cf3c, - 0xcdcdcdcd, 0xfffffff5, 0x310fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, - 0xf3cf3cf3, 0x0040cf3c, 0xcdcdcdcd, 0xfffffff3, 0x300fffff, 0x0c30c30c, - 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0000cf3c, 0xcdcdcdcd, 0xfffffff1, - 0x300fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0001cf3c, - 0xcdcdcdcd, 0xfffffff6, 0x305fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, - 0xf3cf3cf3, 0x0002cf3c, 0xcdcdcdcd, 0xfffff406, 0x1cbfffff, 0x0c30c305, - 0xc30c30c3, 0xcf300014, 0xf3cf3cf3, 0x0004cf3c, 0xcdcdcdcd, 0xfffffff2, - 0x304fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0008cf3c, - 0xcdcdcdcd, 0xfffffffa, 0x302fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, - 0xf3cf3cf3, 0x0010cf3c, 0xcdcdcdcd, 0xffffff97, 0x040fffff, 0x0c30c30c, - 0xc30c30c3, 0xcf3cc000, 0xf3cf3cf3, 0x0020cf3c, 0xcdcdcdcd, 0xfffffff5, - 0x300fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0040cf3c, - 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, - 0xf3cf3cf3, 0x0000cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, - 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0001cf3c, 0xcdcdcdcd, 0xffffffff, - 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0002cf3c, - 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, - 0xf3cf3cf3, 0x0004cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, - 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0008cf3c, 0xcdcdcdcd, 0xffffffff, - 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0010cf3c, - 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, - 0xf3cf3cf3, 0x0020cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, - 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0040cf3c, 0xcdcdcdcd, 0xffffffff, - 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0000cf3c, - 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, - 0xf3cf3cf3, 0x0001cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, - 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0002cf3c, 0xcdcdcdcd, 0xffffffff, - 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0004cf3c, - 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, - 0xf3cf3cf3, 0x0008cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, - 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0010cf3c, 0xcdcdcdcd, 0xffffffff, - 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0020cf3c, - 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, - 0xf3cf3cf3, 0x0040cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, - 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0000cf3c, 0xcdcdcdcd, 0xffffffff, - 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0001cf3c, - 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, - 0xf3cf3cf3, 0x0002cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, - 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0004cf3c, 0xcdcdcdcd, 0xffffffff, - 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0008cf3c, - 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, - 0xf3cf3cf3, 0x0010cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, - 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0020cf3c, 0xcdcdcdcd, 0xffffffff, - 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0040cf3c, - 0xcdcdcdcd, 0x00100000, 0x00070100, 0x00028170, 0x000b8198, 0x00020250, - 0x00010270, 0x000f0280, 0x00010370, 0x00080000, 0x00080080, 0x00028100, - 0x000b8128, 0x000201e0, 0x00010200, 0x00070210, 0x00020280, 0x000f0000, - 0x000800f0, 0x00028170, 0x000b8198, 0x00020250, 0x00010270, 0x000b8280, - 0x00080338, 0x00100000, 0x00080100, 0x00028180, 0x000b81a8, 0x00020260, - 0x00018280, 0x000e8298, 0x00080380, 0x00028000, 0x000b8028, 0x000200e0, - 0x00010100, 0x00008110, 0x00000118, 0xcccccccc, 0xcccccccc, 0xcccccccc, - 0xcccccccc, 0x00002000, 0xcccccccc, 0xcccccccc, 0xcccccccc, 0xcccccccc, - 0x00002000, 0xcccccccc, 0xcccccccc, 0xcccccccc, 0xcccccccc, 0x00002000 -}; - -static const u32 init_data_e1h[] = { - 0x00010000, 0x000204c0, 0x00030980, 0x00040e40, 0x00051300, 0x000617c0, - 0x00071c80, 0x00082140, 0x00092600, 0x000a2ac0, 0x000b2f80, 0x000c3440, - 0x000d3900, 0x000e3dc0, 0x000f4280, 0x00104740, 0x00114c00, 0x001250c0, - 0x00135580, 0x00145a40, 0x00155f00, 0x001663c0, 0x00176880, 0x00186d40, - 0x00197200, 0x001a76c0, 0x001b7b80, 0x001c8040, 0x001d8500, 0x001e89c0, - 0x001f8e80, 0x00209340, 0x00002000, 0x00004000, 0x00006000, 0x00008000, - 0x0000a000, 0x0000c000, 0x0000e000, 0x00010000, 0x00012000, 0x00014000, - 0x00016000, 0x00018000, 0x0001a000, 0x0001c000, 0x0001e000, 0x00020000, - 0x00022000, 0x00024000, 0x00026000, 0x00028000, 0x0002a000, 0x0002c000, - 0x0002e000, 0x00030000, 0x00032000, 0x00034000, 0x00036000, 0x00038000, - 0x0003a000, 0x0003c000, 0x0003e000, 0x00040000, 0x00042000, 0x00044000, - 0x00046000, 0x00048000, 0x0004a000, 0x0004c000, 0x0004e000, 0x00050000, - 0x00052000, 0x00054000, 0x00056000, 0x00058000, 0x0005a000, 0x0005c000, - 0x0005e000, 0x00060000, 0x00062000, 0x00064000, 0x00066000, 0x00068000, - 0x0006a000, 0x0006c000, 0x0006e000, 0x00070000, 0x00072000, 0x00074000, - 0x00076000, 0x00078000, 0x0007a000, 0x0007c000, 0x0007e000, 0x00080000, - 0x00082000, 0x00084000, 0x00086000, 0x00088000, 0x0008a000, 0x0008c000, - 0x0008e000, 0x00090000, 0x00092000, 0x00094000, 0x00096000, 0x00098000, - 0x0009a000, 0x0009c000, 0x0009e000, 0x000a0000, 0x000a2000, 0x000a4000, - 0x000a6000, 0x000a8000, 0x000aa000, 0x000ac000, 0x000ae000, 0x000b0000, - 0x000b2000, 0x000b4000, 0x000b6000, 0x000b8000, 0x000ba000, 0x000bc000, - 0x000be000, 0x000c0000, 0x000c2000, 0x000c4000, 0x000c6000, 0x000c8000, - 0x000ca000, 0x000cc000, 0x000ce000, 0x000d0000, 0x000d2000, 0x000d4000, - 0x000d6000, 0x000d8000, 0x000da000, 0x000dc000, 0x000de000, 0x000e0000, - 0x000e2000, 0x000e4000, 0x000e6000, 0x000e8000, 0x000ea000, 0x000ec000, - 0x000ee000, 0x000f0000, 0x000f2000, 0x000f4000, 0x000f6000, 0x000f8000, - 0x000fa000, 0x000fc000, 0x000fe000, 0x00100000, 0x00102000, 0x00104000, - 0x00106000, 0x00108000, 0x0010a000, 0x0010c000, 0x0010e000, 0x00110000, - 0x00112000, 0x00114000, 0x00116000, 0x00118000, 0x0011a000, 0x0011c000, - 0x0011e000, 0x00120000, 0x00122000, 0x00124000, 0x00126000, 0x00128000, - 0x0012a000, 0x0012c000, 0x0012e000, 0x00130000, 0x00132000, 0x00134000, - 0x00136000, 0x00138000, 0x0013a000, 0x0013c000, 0x0013e000, 0x00140000, - 0x00142000, 0x00144000, 0x00146000, 0x00148000, 0x0014a000, 0x0014c000, - 0x0014e000, 0x00150000, 0x00152000, 0x00154000, 0x00156000, 0x00158000, - 0x0015a000, 0x0015c000, 0x0015e000, 0x00160000, 0x00162000, 0x00164000, - 0x00166000, 0x00168000, 0x0016a000, 0x0016c000, 0x0016e000, 0x00170000, - 0x00172000, 0x00174000, 0x00176000, 0x00178000, 0x0017a000, 0x0017c000, - 0x0017e000, 0x00180000, 0x00182000, 0x00184000, 0x00186000, 0x00188000, - 0x0018a000, 0x0018c000, 0x0018e000, 0x00190000, 0x00192000, 0x00194000, - 0x00196000, 0x00198000, 0x0019a000, 0x0019c000, 0x0019e000, 0x001a0000, - 0x001a2000, 0x001a4000, 0x001a6000, 0x001a8000, 0x001aa000, 0x001ac000, - 0x001ae000, 0x001b0000, 0x001b2000, 0x001b4000, 0x001b6000, 0x001b8000, - 0x001ba000, 0x001bc000, 0x001be000, 0x001c0000, 0x001c2000, 0x001c4000, - 0x001c6000, 0x001c8000, 0x001ca000, 0x001cc000, 0x001ce000, 0x001d0000, - 0x001d2000, 0x001d4000, 0x001d6000, 0x001d8000, 0x001da000, 0x001dc000, - 0x001de000, 0x001e0000, 0x001e2000, 0x001e4000, 0x001e6000, 0x001e8000, - 0x001ea000, 0x001ec000, 0x001ee000, 0x001f0000, 0x001f2000, 0x001f4000, - 0x001f6000, 0x001f8000, 0x001fa000, 0x001fc000, 0x001fe000, 0x00200000, - 0x00202000, 0x00204000, 0x00206000, 0x00208000, 0x0020a000, 0x0020c000, - 0x0020e000, 0x00210000, 0x00212000, 0x00214000, 0x00216000, 0x00218000, - 0x0021a000, 0x0021c000, 0x0021e000, 0x00220000, 0x00222000, 0x00224000, - 0x00226000, 0x00228000, 0x0022a000, 0x0022c000, 0x0022e000, 0x00230000, - 0x00232000, 0x00234000, 0x00236000, 0x00238000, 0x0023a000, 0x0023c000, - 0x0023e000, 0x00240000, 0x00242000, 0x00244000, 0x00246000, 0x00248000, - 0x0024a000, 0x0024c000, 0x0024e000, 0x00250000, 0x00252000, 0x00254000, - 0x00256000, 0x00258000, 0x0025a000, 0x0025c000, 0x0025e000, 0x00260000, - 0x00262000, 0x00264000, 0x00266000, 0x00268000, 0x0026a000, 0x0026c000, - 0x0026e000, 0x00270000, 0x00272000, 0x00274000, 0x00276000, 0x00278000, - 0x0027a000, 0x0027c000, 0x0027e000, 0x00280000, 0x00282000, 0x00284000, - 0x00286000, 0x00288000, 0x0028a000, 0x0028c000, 0x0028e000, 0x00290000, - 0x00292000, 0x00294000, 0x00296000, 0x00298000, 0x0029a000, 0x0029c000, - 0x0029e000, 0x002a0000, 0x002a2000, 0x002a4000, 0x002a6000, 0x002a8000, - 0x002aa000, 0x002ac000, 0x002ae000, 0x002b0000, 0x002b2000, 0x002b4000, - 0x002b6000, 0x002b8000, 0x002ba000, 0x002bc000, 0x002be000, 0x002c0000, - 0x002c2000, 0x002c4000, 0x002c6000, 0x002c8000, 0x002ca000, 0x002cc000, - 0x002ce000, 0x002d0000, 0x002d2000, 0x002d4000, 0x002d6000, 0x002d8000, - 0x002da000, 0x002dc000, 0x002de000, 0x002e0000, 0x002e2000, 0x002e4000, - 0x002e6000, 0x002e8000, 0x002ea000, 0x002ec000, 0x002ee000, 0x002f0000, - 0x002f2000, 0x002f4000, 0x002f6000, 0x002f8000, 0x002fa000, 0x002fc000, - 0x002fe000, 0x00300000, 0x00302000, 0x00304000, 0x00306000, 0x00308000, - 0x0030a000, 0x0030c000, 0x0030e000, 0x00310000, 0x00312000, 0x00314000, - 0x00316000, 0x00318000, 0x0031a000, 0x0031c000, 0x0031e000, 0x00320000, - 0x00322000, 0x00324000, 0x00326000, 0x00328000, 0x0032a000, 0x0032c000, - 0x0032e000, 0x00330000, 0x00332000, 0x00334000, 0x00336000, 0x00338000, - 0x0033a000, 0x0033c000, 0x0033e000, 0x00340000, 0x00342000, 0x00344000, - 0x00346000, 0x00348000, 0x0034a000, 0x0034c000, 0x0034e000, 0x00350000, - 0x00352000, 0x00354000, 0x00356000, 0x00358000, 0x0035a000, 0x0035c000, - 0x0035e000, 0x00360000, 0x00362000, 0x00364000, 0x00366000, 0x00368000, - 0x0036a000, 0x0036c000, 0x0036e000, 0x00370000, 0x00372000, 0x00374000, - 0x00376000, 0x00378000, 0x0037a000, 0x0037c000, 0x0037e000, 0x00380000, - 0x00382000, 0x00384000, 0x00386000, 0x00388000, 0x0038a000, 0x0038c000, - 0x0038e000, 0x00390000, 0x00392000, 0x00394000, 0x00396000, 0x00398000, - 0x0039a000, 0x0039c000, 0x0039e000, 0x003a0000, 0x003a2000, 0x003a4000, - 0x003a6000, 0x003a8000, 0x003aa000, 0x003ac000, 0x003ae000, 0x003b0000, - 0x003b2000, 0x003b4000, 0x003b6000, 0x003b8000, 0x003ba000, 0x003bc000, - 0x003be000, 0x003c0000, 0x003c2000, 0x003c4000, 0x003c6000, 0x003c8000, - 0x003ca000, 0x003cc000, 0x003ce000, 0x003d0000, 0x003d2000, 0x003d4000, - 0x003d6000, 0x003d8000, 0x003da000, 0x003dc000, 0x003de000, 0x003e0000, - 0x003e2000, 0x003e4000, 0x003e6000, 0x003e8000, 0x003ea000, 0x003ec000, - 0x003ee000, 0x003f0000, 0x003f2000, 0x003f4000, 0x003f6000, 0x003f8000, - 0x003fa000, 0x003fc000, 0x003fe000, 0x003fe001, 0x00000000, 0x000001ff, - 0x00000200, 0x00000001, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00007ff8, - 0x00000000, 0x00003500, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, - 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, - 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, 0x00000003, - 0x00bebc20, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, - 0x00000003, 0x00bebc20, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, - 0xffffffff, 0x00000003, 0x00bebc20, 0xffffffff, 0x00000000, 0xffffffff, - 0x00000000, 0xffffffff, 0x00000003, 0x00bebc20, 0xffffffff, 0x00000000, - 0xffffffff, 0x00000000, 0xffffffff, 0x00000003, 0x00bebc20, 0xffffffff, - 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, 0x00000003, 0x00bebc20, - 0x00002000, 0x000040c0, 0x00006180, 0x00008240, 0x0000a300, 0x0000c3c0, - 0x0000e480, 0x00010540, 0x00012600, 0x000146c0, 0x00016780, 0x00018840, - 0x0001a900, 0x0001c9c0, 0x0001ea80, 0x00020b40, 0x00022c00, 0x00024cc0, - 0x00026d80, 0x00028e40, 0x0002af00, 0x0002cfc0, 0x0002f080, 0x00031140, - 0x00033200, 0x000352c0, 0x00037380, 0x00039440, 0x0003b500, 0x0003d5c0, - 0x0003f680, 0x00041740, 0x00043800, 0x000458c0, 0x00047980, 0x00049a40, - 0x00008000, 0x00010380, 0x00018700, 0x00020a80, 0x00028e00, 0x00031180, - 0x00039500, 0x00041880, 0x00049c00, 0x00051f80, 0x0005a300, 0x00062680, - 0x0006aa00, 0x00072d80, 0x0007b100, 0x00083480, 0x0008b800, 0x00093b80, - 0x0009bf00, 0x000a4280, 0x000ac600, 0x000b4980, 0x000bcd00, 0x000c5080, - 0x000cd400, 0x000d5780, 0x000ddb00, 0x00001900, 0x00000028, 0x00100000, - 0x00000000, 0x00000000, 0xffffffff, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x00000000, - 0x00007ff8, 0x00000000, 0x00001500, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x00000000, 0x00007ff8, 0x00000000, 0x00001500, 0x00001000, - 0x00002080, 0x00003100, 0x00004180, 0x00005200, 0x00006280, 0x00007300, - 0x00008380, 0x00009400, 0x0000a480, 0x0000b500, 0x0000c580, 0x0000d600, - 0x0000e680, 0x0000f700, 0x00010780, 0x00011800, 0x00012880, 0x00013900, - 0x00014980, 0x00015a00, 0x00016a80, 0x00017b00, 0x00018b80, 0x00019c00, - 0x0001ac80, 0x0001bd00, 0x0001cd80, 0x0001de00, 0x0001ee80, 0x0001ff00, - 0x10000000, 0x000028ad, 0x00000000, 0x00010001, 0x00350804, 0xccccccc5, - 0xffffffff, 0xffffffff, 0x7058103c, 0x00000000, 0xcccc0201, 0xcccccccc, - 0xcccc0201, 0xcccccccc, 0xcccc0201, 0xcccccccc, 0xcccc0201, 0xcccccccc, - 0xcccc0201, 0xcccccccc, 0xcccc0201, 0xcccccccc, 0xcccc0201, 0xcccccccc, - 0xcccc0201, 0xcccccccc, 0x00000000, 0xffffffff, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, - 0x00000000, 0x00007ff8, 0x00000000, 0x00003500, 0x000e0232, 0x011600d6, - 0x00100000, 0x00000000, 0x00720236, 0x012300f3, 0x00100000, 0x00000000, - 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, - 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, - 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, - 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, - 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, - 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, - 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, - 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, - 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, - 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, - 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, - 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, - 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, - 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, - 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, - 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, - 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, - 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, - 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, - 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, - 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, 0x0000ffff, 0x00000000, - 0x0000ffff, 0x00000000, 0xfffffff3, 0x320fffff, 0x0c30c30c, 0xc30c30c3, - 0xcf3cf300, 0xf3cf3cf3, 0x0000cf3c, 0xcdcdcdcd, 0xfffffff1, 0x30efffff, - 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0001cf3c, 0xcdcdcdcd, - 0xfffffff6, 0x305fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, - 0x0002cf3c, 0xcdcdcdcd, 0xfffff406, 0x1cbfffff, 0x0c30c305, 0xc30c30c3, - 0xcf300014, 0xf3cf3cf3, 0x0004cf3c, 0xcdcdcdcd, 0xfffffff2, 0x304fffff, - 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0008cf3c, 0xcdcdcdcd, - 0xfffffffa, 0x302fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, - 0x0010cf3c, 0xcdcdcdcd, 0xfffffff7, 0x31efffff, 0x0c30c30c, 0xc30c30c3, - 0xcf3cf300, 0xf3cf3cf3, 0x0020cf3c, 0xcdcdcdcd, 0xfffffff5, 0x302fffff, - 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0040cf3c, 0xcdcdcdcd, - 0xfffffff3, 0x310fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, - 0x0000cf3c, 0xcdcdcdcd, 0xfffffff1, 0x310fffff, 0x0c30c30c, 0xc30c30c3, - 0xcf3cf300, 0xf3cf3cf3, 0x0001cf3c, 0xcdcdcdcd, 0xfffffff6, 0x305fffff, - 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0002cf3c, 0xcdcdcdcd, - 0xfffff406, 0x1cbfffff, 0x0c30c305, 0xc30c30c3, 0xcf300014, 0xf3cf3cf3, - 0x0004cf3c, 0xcdcdcdcd, 0xfffffff2, 0x304fffff, 0x0c30c30c, 0xc30c30c3, - 0xcf3cf300, 0xf3cf3cf3, 0x0008cf3c, 0xcdcdcdcd, 0xfffffffa, 0x302fffff, - 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0010cf3c, 0xcdcdcdcd, - 0xfffffff7, 0x30efffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, - 0x0020cf3c, 0xcdcdcdcd, 0xfffffff5, 0x304fffff, 0x0c30c30c, 0xc30c30c3, - 0xcf3cf300, 0xf3cf3cf3, 0x0040cf3c, 0xcdcdcdcd, 0xfffffff3, 0x31efffff, - 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0000cf3c, 0xcdcdcdcd, - 0xfffffff1, 0x310fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, - 0x0001cf3c, 0xcdcdcdcd, 0xfffffff6, 0x305fffff, 0x0c30c30c, 0xc30c30c3, - 0xcf3cf300, 0xf3cf3cf3, 0x0002cf3c, 0xcdcdcdcd, 0xfffff406, 0x1cbfffff, - 0x0c30c305, 0xc30c30c3, 0xcf300014, 0xf3cf3cf3, 0x0004cf3c, 0xcdcdcdcd, - 0xfffffff2, 0x304fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, - 0x0008cf3c, 0xcdcdcdcd, 0xfffffffa, 0x302fffff, 0x0c30c30c, 0xc30c30c3, - 0xcf3cf300, 0xf3cf3cf3, 0x0010cf3c, 0xcdcdcdcd, 0xffffff97, 0x056fffff, - 0x0c30c30c, 0xc30c30c3, 0xcf3cc000, 0xf3cf3cf3, 0x0020cf3c, 0xcdcdcdcd, - 0xfffffff5, 0x310fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, - 0x0040cf3c, 0xcdcdcdcd, 0xfffffff3, 0x320fffff, 0x0c30c30c, 0xc30c30c3, - 0xcf3cf300, 0xf3cf3cf3, 0x0000cf3c, 0xcdcdcdcd, 0xfffffff1, 0x310fffff, - 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0001cf3c, 0xcdcdcdcd, - 0xfffffff6, 0x305fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, - 0x0002cf3c, 0xcdcdcdcd, 0xfffff406, 0x1cbfffff, 0x0c30c305, 0xc30c30c3, - 0xcf300014, 0xf3cf3cf3, 0x0004cf3c, 0xcdcdcdcd, 0xfffffff2, 0x304fffff, - 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0008cf3c, 0xcdcdcdcd, - 0xffffff8a, 0x042fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cc000, 0xf3cf3cf3, - 0x0010cf3c, 0xcdcdcdcd, 0xffffff97, 0x05cfffff, 0x0c30c30c, 0xc30c30c3, - 0xcf3cc000, 0xf3cf3cf3, 0x0020cf3c, 0xcdcdcdcd, 0xfffffff5, 0x310fffff, - 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0040cf3c, 0xcdcdcdcd, - 0xfffffff3, 0x316fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, - 0x0000cf3c, 0xcdcdcdcd, 0xfffffff1, 0x302fffff, 0x0c30c30c, 0xc30c30c3, - 0xcf3cf300, 0xf3cf3cf3, 0x0001cf3c, 0xcdcdcdcd, 0xfffffff6, 0x305fffff, - 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0002cf3c, 0xcdcdcdcd, - 0xfffffff6, 0x30bfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf314, 0xf3cf3cf3, - 0x0004cf3c, 0xcdcdcdcd, 0xfffffff2, 0x304fffff, 0x0c30c30c, 0xc30c30c3, - 0xcf3cf300, 0xf3cf3cf3, 0x0008cf3c, 0xcdcdcdcd, 0xfffffffa, 0x302fffff, - 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0010cf3c, 0xcdcdcdcd, - 0xfffffff7, 0x31cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, - 0x0020cf3c, 0xcdcdcdcd, 0xfffffff0, 0x307fffff, 0x0c30c30c, 0xc30c30c3, - 0xcf3cf300, 0xf3cf3cf3, 0x0040cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, - 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0000cf3c, 0xcdcdcdcd, - 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, - 0x0001cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, - 0xcf3cf3cc, 0xf3cf3cf3, 0x0002cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, - 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0004cf3c, 0xcdcdcdcd, - 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, - 0x0008cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, - 0xcf3cf3cc, 0xf3cf3cf3, 0x0010cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, - 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0020cf3c, 0xcdcdcdcd, - 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, - 0x0040cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, - 0xcf3cf3cc, 0xf3cf3cf3, 0x0000cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, - 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0001cf3c, 0xcdcdcdcd, - 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, - 0x0002cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, - 0xcf3cf3cc, 0xf3cf3cf3, 0x0004cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, - 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0008cf3c, 0xcdcdcdcd, - 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, - 0x0010cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, - 0xcf3cf3cc, 0xf3cf3cf3, 0x0020cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, - 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0040cf3c, 0xcdcdcdcd, - 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, - 0x0000cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, - 0xcf3cf3cc, 0xf3cf3cf3, 0x0001cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, - 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0002cf3c, 0xcdcdcdcd, - 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, - 0x0004cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, - 0xcf3cf3cc, 0xf3cf3cf3, 0x0008cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, - 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0010cf3c, 0xcdcdcdcd, - 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, - 0x0020cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, - 0xcf3cf3cc, 0xf3cf3cf3, 0x0040cf3c, 0xcdcdcdcd, 0x00100000, 0x00070100, - 0x00028170, 0x000b8198, 0x00020250, 0x00010270, 0x000f0280, 0x00010370, - 0x00080000, 0x00080080, 0x00028100, 0x000b8128, 0x000201e0, 0x00010200, - 0x00070210, 0x00020280, 0x000f0000, 0x000800f0, 0x00028170, 0x000b8198, - 0x00020250, 0x00010270, 0x000b8280, 0x00080338, 0x00100000, 0x00080100, - 0x00028180, 0x000b81a8, 0x00020260, 0x00018280, 0x000e8298, 0x00080380, - 0x000b0000, 0x000100b0, 0x000280c0, 0x000580e8, 0x00020140, 0x00010160, - 0x000e0170, 0x00038250, 0xcccccccc, 0xcccccccc, 0xcccccccc, 0xcccccccc, - 0x00002000, 0xcccccccc, 0xcccccccc, 0xcccccccc, 0xcccccccc, 0x00002000, - 0xcccccccc, 0xcccccccc, 0xcccccccc, 0xcccccccc, 0x04002000 -}; - -static const u32 tsem_int_table_data_e1[] = { - 0x00088b1f, 0x00000000, 0x51fbff00, 0x03f0c0cf, 0x19d9458a, 0x1138fc18, - 0x5980a1fc, 0xd8181998, 0x88039880, 0x81b8803d, 0x91a18191, 0xdafd7891, - 0xbf760862, 0x6ec30330, 0x0211e620, 0x1082239a, 0xf354029f, 0x0f5fc806, - 0x6512b315, 0x3a263860, 0x06a77ef0, 0x298d2ade, 0xc1124536, 0x1e4586de, - 0x93476f19, 0xca8922ff, 0xff4041df, 0x65296340, 0x229dbe54, 0x04a65e84, - 0xe4d1a5a1, 0xd7f2a1ed, 0x5192fea1, 0x0dee6ec6, 0xf8003ca8, 0x6065495c, - 0x00606549 -}; - -static const u32 tsem_pram_data_e1[] = { - 0x00088b1f, 0x00000000, 0x7dedff00, 0xd554780b, 0x733ef0b5, 0x49999cce, - 0x424e4cce, 0x4c22f212, 0x21a08812, 0x8a80af0c, 0x2201277f, 0x282039f5, - 0x4201d458, 0xd4837908, 0xcdedaf4b, 0x11102484, 0x0547f435, 0x5088768b, - 0x340da2d1, 0x0ec160d2, 0x6d7b1420, 0xc0faf06f, 0x480bf5ea, 0xb12f3141, - 0xcbc57e20, 0xe7dad6bf, 0x264ce664, 0xafdbd880, 0xb4fdffff, 0xece7d9b8, - 0xebdaf7b3, 0x7b5ad7b5, 0x75923ded, 0xc7bf9302, 0x03fc45d8, 0x8c4d4fe5, - 0xf2c109b1, 0x80f66667, 0xc9b18727, 0x473afebd, 0x6d55633c, 0x9da23b19, - 0x99ec258c, 0x50281421, 0x2c23d5fe, 0xbfdf8250, 0xf097c365, 0x4219b6ff, - 0xd0977c3e, 0xc3e611e9, 0x02d5e4fb, 0x933a876b, 0xea0c319c, 0x4b19b98c, - 0x126b2c64, 0x4b223fa3, 0xe0ff828d, 0x8f392573, 0x27fc34b1, 0x61467574, - 0xc678c0ae, 0x5c531e32, 0x38a9d0d4, 0x843f7815, 0xbcd2c67f, 0x0731b725, - 0xbc03cf63, 0xbcf071c9, 0x61de3a5a, 0xc22eefe5, 0x3af3a1df, 0xae58cd6a, - 0x32773e30, 0x416589a7, 0xf3e33ebf, 0x3d6346ac, 0x4fe3d99b, 0xec3fc346, - 0x8c517ecc, 0xb1138f30, 0xcb3c018c, 0x632f0e54, 0x5467b2bd, 0x6a9b1f10, - 0x2c32a258, 0x852f0f58, 0x56338765, 0xed975e03, 0xf8165c16, 0x2f6c39fe, - 0xbed7e631, 0x15ead66b, 0xa362593e, 0xb50404a1, 0x67eff4e4, 0x11bfcb11, - 0x2b30fef1, 0xea4ab2a0, 0xaf805595, 0xfb765aaa, 0x67edfe95, 0x54e88933, - 0x5bf6b929, 0x5adefc61, 0xf1866ae6, 0x02d59997, 0x91fb2fac, 0x7a83e5d3, - 0x21476366, 0x36d0fa83, 0xc1198981, 0x9e00afef, 0x007f91db, 0xa52b2a1e, - 0x740642de, 0xb02bddec, 0x871c0ce6, 0x776cbbf7, 0x0c65f306, 0x6658e70c, - 0x32e73826, 0x74893a41, 0xd2073071, 0xf324bcc1, 0xcea84289, 0xb0f3dc54, - 0x9de29f7f, 0xe7f4ed87, 0x38e60b49, 0xf25700bd, 0x57a06650, 0x9d3ab5b1, - 0xea563265, 0xbe442969, 0x8decb538, 0x9e025855, 0xf7c02413, 0x08a78b7c, - 0x5798a9fb, 0xa780cd9d, 0x8d1859e6, 0xff2db43f, 0x0cf80933, 0xc4c5f3ba, - 0x76313f21, 0xf04f843c, 0x5a11f1cf, 0xde981c5d, 0xb08b2b97, 0x05f1091f, - 0x1f011772, 0x26a0423f, 0x544d28e0, 0x29fc573a, 0xd0a0d86b, 0xc3595bfa, - 0xe50069c6, 0x3f0cbc11, 0x0843ac61, 0x1cbd4be5, 0xb0ff3bba, 0x3c303b94, - 0x04f3d3ff, 0xab7e1274, 0x1fc8b700, 0xbfd97615, 0xca61f812, 0xf7c0e6ab, - 0x362a3f80, 0xd40b7e0b, 0xe8dbaf4d, 0x5e26f77d, 0x3765d80f, 0x16d74ff2, - 0xbdf00ba8, 0x1bf1fda5, 0x155ebf91, 0x3b763359, 0xfa84ca22, 0x3b06a4e5, - 0xc0750f1b, 0x578db147, 0xbbef362b, 0x692fbf1f, 0xf41b30b3, 0xf17bb157, - 0x7d42371d, 0xc33361f1, 0x6b5b1526, 0x2fa814e5, 0x582d0bf1, 0xf0e029ef, - 0xfe8976f9, 0xc7bed0ad, 0x1b389ed1, 0xc6ba73e8, 0x63329cca, 0xc4f6f675, - 0xa567c059, 0xf8851dfe, 0xc176e95d, 0xf29f6885, 0xc943d6ea, 0xb917af38, - 0x8b6d977c, 0x7f1d4e66, 0xab64f7f0, 0xbc1ef818, 0x64f3065f, 0xd662efd0, - 0xb07a8854, 0xd93aeb62, 0xebe20f69, 0xe34a8d74, 0x8bdfc9f4, 0x577c0e30, - 0xc2e08af9, 0x989a5629, 0x7bb0e517, 0xf3ce6db7, 0x56afce0a, 0xbce3b6ce, - 0x6ed8cb56, 0x2efe7fb1, 0xfea5cd54, 0xbc2172cd, 0x59b4dd2f, 0xdb910e2e, - 0x8c836db2, 0x1ac86d70, 0xd7208dec, 0xd7807841, 0x52f583b2, 0x0fa803d4, - 0x233cbf25, 0x852acf84, 0xb2cbe258, 0x1a73226d, 0xddd388f8, 0x13fc2ef7, - 0x6bdbe5f0, 0x74eabc27, 0x1aa7d3eb, 0x1aa8cedd, 0xbcdea51d, 0xf8f81119, - 0xc003a471, 0x827884d3, 0x9f06ad72, 0x97cb3263, 0x9b877fa0, 0x3cbb02a9, - 0xd999365f, 0xf563067c, 0xd2dd07b0, 0xd99750f5, 0xf582e652, 0x7bb1fa50, - 0x0493d42a, 0x9f3867ef, 0xc25bc17a, 0x2496abd7, 0x9579e00f, 0xfce0e6c0, - 0x30d0218f, 0xc0c955af, 0xa6f7809f, 0x8bcf7969, 0x3c7b0682, 0xb17f8bd6, - 0x39fa8326, 0xa198fd43, 0xf7cbac9f, 0x324e16a3, 0x9616a3f4, 0x8dfcfde8, - 0x595db1fa, 0x37854d3f, 0x2c29e118, 0x0491fbd5, 0xbf6f5768, 0x37a979b2, - 0x73c2364f, 0x13f53973, 0xbcc5d53b, 0x1ae7ae0a, 0xb776b03f, 0xed95ef08, - 0xb0d763b1, 0x5028be50, 0x0edb8005, 0x17ca1252, 0x0ca29331, 0x8eeb187c, - 0x27a1d433, 0x4175e4f5, 0x958813fd, 0x45397c69, 0x9f90bd26, 0x43faa562, - 0x85e90a29, 0x5ef06e87, 0x8e20eb83, 0x2ea192cd, 0x11ab477b, 0x14e01af8, - 0x60961258, 0x7ff52417, 0xf1ccdabf, 0x217a9050, 0x5f7c18fb, 0x8ecdea65, - 0xa635fa85, 0x6f116bfc, 0xe5eb812e, 0x63559128, 0x230b28bb, 0x233ab4fd, - 0x085f79ef, 0x00871a9e, 0xbf6085fd, 0x126f668d, 0xdaf8d7f2, 0xc0127c67, - 0xcc086ab7, 0x12ba0527, 0x60f8099e, 0xa43d5a3d, 0x69f10938, 0x43be4191, - 0xfc6197c7, 0x06ff1a1c, 0xc71ba3c4, 0xbe3fe84f, 0x61927325, 0x897a6b7c, - 0x0cab7c61, 0x4fbf03e3, 0xc6d66dad, 0xc0ddfc07, 0x99a134d8, 0x97a4b7c6, - 0x65abf8d0, 0x3f186256, 0x5bfc6faa, 0x819efe70, 0x83799fe6, 0xa5e9fe71, - 0x7ccbf9c6, 0x5f6ab3fe, 0xa28fc6d2, 0x5e16cff9, 0x2f4ff3e2, 0xf0b7f3e5, - 0x77c6fb7e, 0x5effe1f4, 0x8077bf9c, 0x93592df1, 0x5a1ff38d, 0x85bf9c6e, - 0xbb545f8f, 0xa15f1b53, 0x3b0917f1, 0x9687fcf9, 0xc5b2f8d3, 0x923e42eb, - 0xfdaaa353, 0x81a44f68, 0x1d260c40, 0x0472a6e5, 0x1fa00518, 0x04990a86, - 0x9c5143c7, 0x0145ceef, 0x7d4129bf, 0x5120fcc7, 0x352acfa0, 0x9edb2f9e, - 0xa59ea32f, 0x376889f7, 0x6d453ff1, 0x6c37ad22, 0x1c3fc5bd, 0x136eede0, - 0x5a2f587d, 0xa45f937f, 0xe5db8ef5, 0xf005c660, 0x1c9e5ff9, 0xaf3a1cd5, - 0x935172f0, 0x418764f9, 0xbe3c388e, 0x1aa23602, 0x26476be0, 0x9fac1098, - 0xc60a3d04, 0x7a0e3b2f, 0x6653cb14, 0x009c8f6e, 0x50e4cb3d, 0xf6e5a9b9, - 0x93bd8f88, 0x5bbaf303, 0xc4a4ff83, 0xb9727df1, 0x9ffc47e0, 0x4654b75b, - 0x09a8b4fd, 0x7910e98c, 0xd4e8d2af, 0x6fe2dbbb, 0x4e9f0816, 0x243dcfc4, - 0x97fd8c8a, 0xde2fd766, 0xddf0c830, 0x486fe63c, 0xd70bf682, 0xc2a21fce, - 0xc7307ffc, 0x53ed1632, 0x13548490, 0x354b31c9, 0xa7316f81, 0x15399d75, - 0x31ccf72a, 0xb9faec1b, 0x07fd635e, 0xb77ac625, 0xa1366fd9, 0x6044b1bd, - 0xfbdfa19b, 0xf5ef8daa, 0x71093671, 0x78daae9c, 0x78722777, 0x2c72c3ef, - 0xae89563e, 0x5bfcabf7, 0x87aa9e1d, 0xeb402ccd, 0x43024765, 0xc812fa3a, - 0x7caaf35e, 0xdef0e1de, 0x3dbab66f, 0x3ffdcf00, 0xe19f0912, 0x1ebc77f0, - 0x1d8136ed, 0x4be1b1d7, 0xe1b7da33, 0xff8709f3, 0xf3e11581, 0xf7d46551, - 0xcfe17df3, 0xf3849f39, 0xfe5b5553, 0xed2113a0, 0x3fbe5a2a, 0x7f0844e8, - 0x619b6d95, 0xcff12fa8, 0xbc5fb435, 0xfde1be61, 0x8625a6a2, 0x971b0bf7, - 0x7df3ea1a, 0x7fb4323f, 0xe1ad4560, 0x8fd57dfd, 0xa0ffde18, 0x3ea19d64, - 0xd0d1bbd7, 0x9b399efe, 0xaf4def0d, 0xe513bc8f, 0x915deea8, 0x5671bae1, - 0xda38f939, 0xc9156783, 0xb4f8f485, 0xe0e48926, 0xca938d74, 0x5671b6ee, - 0xc583d72f, 0x5e9c4c0c, 0x71af9ce1, 0x4665ea32, 0xc2aff3fa, 0xea0f9f05, - 0x849c137f, 0xcc83713f, 0x02c2c002, 0xe3e3eb8b, 0x7de4315e, 0x6fde65c7, - 0xd71f4100, 0x11d8bdff, 0xf35579f9, 0x046aa1fc, 0xb72821ff, 0xb9d7152c, - 0x0f7d6d1e, 0x302e5f7f, 0xc673e84f, 0xd79c9256, 0xb94ceb69, 0xf941f5cc, - 0xf402e4ce, 0x40e5cbbf, 0xc6a5f576, 0xa2a4016b, 0x3ceb449e, 0xa401f901, - 0x592fc0c0, 0xdceef906, 0x955c1227, 0xaf4013a8, 0xc19e63ae, 0x8133d426, - 0x8d77e903, 0x49dc3842, 0xa04b6f54, 0x66b3bd75, 0x1213a0fa, 0xe543c7d2, - 0xa87335a7, 0xa5e3593c, 0x094d44f2, 0xaa6bc795, 0x59a8eca9, 0x35c7e541, - 0xaa3f2a3e, 0xcff2a469, 0x1e544d35, 0xe540d9ad, 0x2a7e357b, 0x54dc6bbb, - 0xba2bf9f6, 0xecd78dfe, 0x80afcd55, 0x67ea8795, 0x43d4b9b4, 0x739276db, - 0xf9ca1257, 0x365ce519, 0x8e67e3da, 0x31996382, 0xf9c2be30, 0xba3a606d, - 0xf6295ec9, 0xf5c7fd03, 0xe28b6f7f, 0xd899b274, 0xd9a67074, 0xe17fc323, - 0x7543905a, 0x16065909, 0x7b0cd724, 0xed617e84, 0x8e5d7a43, 0x9bddcc4e, - 0x71e8133b, 0xe5bf99f2, 0xda75bf61, 0x407517fa, 0x059875a4, 0xbd21779e, - 0xeb46f042, 0x9aabef5a, 0xfe0cbfbe, 0xd7f0faba, 0xfbfe8e9e, 0xfea54141, - 0x985ab4cf, 0x13dc7884, 0x67e607ed, 0xef3f0e67, 0x965c7940, 0x444f5264, - 0x565e83c0, 0x4aa864b4, 0x66d3fae8, 0x12699fac, 0x7ad0b7a6, 0x35998cec, - 0x554af90a, 0xfa430c4f, 0xf7a95127, 0x56492cb3, 0x9ebc804f, 0xc31596de, - 0x5f3f6fd7, 0x12c7b707, 0x485f82bf, 0xf0deffed, 0x0e8fd40c, 0xecad630f, - 0x03ea2b13, 0xedf59778, 0xfd2672fd, 0x6c57e295, 0xda1cf98f, 0x7bf8160b, - 0x1207e291, 0xab7ef5d5, 0x659f445a, 0x6edf3e34, 0x73be0f18, 0xc5f73eea, - 0xadf14bcc, 0xc4864ec4, 0xf169d611, 0x366db2c6, 0xc4aeb8d5, 0x6d55ea1a, - 0x9d61aac9, 0xfc807fc1, 0x42416ab3, 0xb8d729be, 0x1a5247a8, 0xdcaf8005, - 0xab7ea4e4, 0xc2aede04, 0xe17b21da, 0xa72b5751, 0x9df040db, 0x94ec39ae, - 0xac4bde40, 0x7c0201e0, 0xa7232d25, 0x6aeb9ea2, 0x7b444bad, 0xf33c4cb0, - 0xf7c22790, 0x8d024d3b, 0xee6fc4b7, 0x1aa3ae35, 0x57e8307f, 0x167e4e7f, - 0xd4864e53, 0xcedc4d3b, 0x80f7ef0e, 0xf0e5efd6, 0x48fdb953, 0xfece8de1, - 0xfb6caa78, 0x1c92f642, 0x82f2ffc1, 0x57f1d278, 0x401cf26e, 0xedba5a7d, - 0x9fa3d918, 0x0fd97d9a, 0xf53f425f, 0x44929f9f, 0x5e7d5271, 0x6129303e, - 0x7c5a059c, 0x9ef7f817, 0xfd3d610f, 0x6ccddfec, 0x2ec7c00d, 0x6f782b40, - 0x13335fd6, 0xa17d4133, 0x5ad05b56, 0xcfdd7146, 0x2a8edc4c, 0xd1071e62, - 0xa1e53581, 0x4cc5d91d, 0x5d4f11d3, 0xb8c76dec, 0x329c3a10, 0x1667a4c9, - 0x18ed1a36, 0xf50d7fb0, 0xf58c1bc5, 0x11333662, 0x7af149f5, 0x340bf333, - 0xf7fbc33f, 0x7fe12a4d, 0x855eab31, 0xf9a4aaeb, 0x26540b23, 0x157c02a5, - 0x6f3679bf, 0x4c5fc63e, 0xe3d10fdc, 0x38e24b23, 0x7ef1a5fc, 0x3fef0dd9, - 0xf7771d69, 0x8b06488d, 0x89c6157f, 0x6d730c58, 0xfbf1fd65, 0x870fe16d, - 0xfbaf5f57, 0x383469c5, 0xdb826dc4, 0x2f7f811f, 0xeba67c68, 0xd5445beb, - 0x8ddc17e0, 0x21bf10f5, 0xb2e2d446, 0xee911322, 0x67d5aa5d, 0x14f7a18a, - 0xb4edf7b7, 0xde80eab8, 0x0679373f, 0x4ec81389, 0xed2165c8, 0xd2f26e7e, - 0xade14ef3, 0x995bb462, 0x3b45c814, 0xe218d614, 0x07e35953, 0x8b91ca31, - 0x833b66f1, 0x6fe81475, 0x9fa0f841, 0xdb92f655, 0xbbc62e58, 0xbfa1de41, - 0x87851cc7, 0x94dba805, 0x59fd8656, 0x7cf18c92, 0xaf58d39b, 0x1d207fc2, - 0x3f8a3046, 0xc2908f45, 0xa86018f0, 0xe32eed0f, 0x84e851f3, 0x201fdd91, - 0x8b10763e, 0x02556943, 0x26cf8c22, 0xfe7d9d49, 0x7bfa2656, 0x2f8a7e1c, - 0x2ae5fb40, 0xc5a95f6f, 0x507f97cf, 0x12ee3830, 0x3ceaa8fa, 0x21419068, - 0x7fbe3d75, 0x71fe625e, 0x3a6f41df, 0xd10d5561, 0xde4d739b, 0xd40f4869, - 0x009f0893, 0x760d78e3, 0x2a1a9a60, 0xf8c20be7, 0x88e1aae3, 0x5dfd0667, - 0x2ddef26e, 0xe387f426, 0xea4ffbaa, 0x4882ffd7, 0xfeeabcf3, 0xbfebf587, - 0x15ff5232, 0x977979bf, 0xf4a9f80f, 0x803a4f57, 0x5267d999, 0xe80ba253, - 0xc1b5be5e, 0xa9f97281, 0x5d2073e4, 0xd38bf33f, 0x16e7c923, 0xb74f9751, - 0xff11e422, 0x7e9d1f10, 0xd03bd1e9, 0xd5b73aae, 0x607c52ac, 0x0160259b, - 0x5d6caca6, 0x9b63e5c2, 0xafaf18e5, 0xb3f902fe, 0x2fa8cdaa, 0x32785f4a, - 0x40cde311, 0x0e7fcd49, 0xb9507f90, 0x68852fe5, 0x5eb15577, 0xdfe17bd2, - 0xe3e7f8e1, 0x2f981ec8, 0xaf7ff4c7, 0x6955f3ef, 0x7d6aa978, 0x84910bf4, - 0xcdfc83a5, 0x9a25f6f0, 0x68a4ffbd, 0xdf38a78f, 0xf9113644, 0xf307c74c, - 0xeebf7b73, 0x8f73a7c5, 0x5b9d3c01, 0xe421ddfe, 0xd727f284, 0x165a677b, - 0xe735fcfe, 0x0dd4f2c0, 0xaed4317a, 0x6767d7d6, 0xeca7e69b, 0x39b965e1, - 0xb03f40e0, 0xe5d9b37c, 0xfcbeba43, 0xc19e2ffc, 0x1607ccb8, 0xbfe870d7, - 0xef83e5ec, 0xb2f500dd, 0xdbf8e61d, 0x211434f8, 0x2a974831, 0x6c62bbf8, - 0xbfa50e90, 0x473b283e, 0x8e3fe7f1, 0x6ca3d20b, 0x8d993ec7, 0x298f8fea, - 0x0ee4fb2d, 0x5a5d0225, 0x3fa2158e, 0x57e2f751, 0xcfafea32, 0xe0d8175e, - 0xdcf8088c, 0x62ec907c, 0x51d113c4, 0xdd1f53a3, 0x0157dac2, 0xeabf505d, - 0xff7f0a74, 0xc7fe9a2f, 0xc4399cfe, 0x86bcafcf, 0xb67f28fb, 0x25fe70b8, - 0xc0e83caf, 0xaa929c79, 0xdb3f5f39, 0x7186e890, 0x44becc4b, 0xbcfe4a95, - 0x121fb9e4, 0xf23e2dbf, 0x7f8a44c3, 0x89b27730, 0x325f056c, 0xa6d16fce, - 0x62bf34d9, 0x2bbe25e6, 0xe0f45679, 0x8959e0fe, 0x4111df4d, 0xae24522e, - 0x5b354f8f, 0xa7654d70, 0x7dc0e170, 0xff45b785, 0x2dff8a56, 0x0fcaf8a5, - 0xb620fdf5, 0xad67ea8c, 0x885f4e9c, 0xac1abefa, 0xbafca13c, 0xd23b7565, - 0xf710f4e7, 0x571b8c60, 0xe1a7c931, 0xfd08b843, 0x0da6478a, 0x4e61f4e6, - 0x0efb4f29, 0x7c14fdf4, 0xcddbed8e, 0xe1ae5b6e, 0x2331763b, 0x6d72fe38, - 0x0a3b807c, 0x8953d5ed, 0x9845ff60, 0xafa4a15f, 0x85576037, 0x7c8857f0, - 0xf2df7973, 0x5d6f9708, 0xa633fdde, 0xbebffbe3, 0xbf07e5c3, 0xe0057b43, - 0xf7a60c0a, 0xa40966fb, 0x102c2c0f, 0x98b7ae49, 0xbe36b935, 0xe004f9d7, - 0xeddd7096, 0x3fec17e3, 0x764ff08e, 0xf87af16c, 0x565f442e, 0xfe8e78e1, - 0xbb72e9fd, 0x04ff9358, 0x6cff28c9, 0x81fb9713, 0x8f1f09fd, 0xbffd984b, - 0x15e50678, 0xaff713e4, 0x7b365fcb, 0x6f9fde70, 0xbddef03f, 0xb79fa720, - 0xd46a72e8, 0x5a72e19f, 0x8b0273b2, 0x639fa724, 0x3924421a, 0xe511e785, - 0x3e20e954, 0x4fe947fe, 0x85377f1d, 0x87d74fe1, 0x5c31e103, 0x7459fe1f, - 0xf087d446, 0xd7961de7, 0xbe74ff9f, 0xf4adf9d3, 0x29431597, 0xa5f3a63e, - 0x7c7d77ce, 0xbf5df3a9, 0x7f01a378, 0x182defe1, 0x3cb80183, 0x4714cdbb, - 0xf7c3df28, 0x43bbe17f, 0x4f09e3a9, 0x58c65a6e, 0xf8d4a1d3, 0xac3fbad0, - 0xded612de, 0x84f7561d, 0xd586f7b5, 0xcbed0dab, 0x3cc80edb, 0x686025af, - 0x8678ae27, 0x1228327d, 0x5fb9fabf, 0xec85fada, 0x7a50be43, 0x4af37be9, - 0x3c63b3e6, 0xf148af7c, 0xf1c01e91, 0x67a7182a, 0xf31f867b, 0x3c6c1a24, - 0xf6a3d4ee, 0x6c5ed03a, 0xdef5e588, 0xea157904, 0xaf79fd3d, 0x7af5c78d, - 0xd88ebd3c, 0xd8edfb10, 0x76f4911e, 0x8f4d9f87, 0x8ac267e4, 0xc1d47242, - 0xe3cf7a06, 0x2544d3fd, 0x5fc6057d, 0x8617449a, 0xef6a8a74, 0x419e6071, - 0x3bac9ecf, 0x45f3c0e7, 0x8db48a6f, 0x7b7683d8, 0x2dc7920c, 0x77f88725, - 0x53df329f, 0xbf7e3193, 0x4579fb87, 0x11ecc36b, 0xa9f896b6, 0xa32e5958, - 0xecbf053e, 0x82ff71b8, 0xd6a945cb, 0xe326c95f, 0xdc7bfd7b, 0xbdfb45c1, - 0xbdf18b74, 0x34078b57, 0x863272eb, 0x71fcd18d, 0xf4d28f1e, 0xe73134f2, - 0x8f4039ce, 0xc322c39e, 0x7b33fbfd, 0x99c7a244, 0x9ebf7ced, 0x23d7f6e2, - 0x3e92f77f, 0x89d4f1d4, 0xac0f24f2, 0xfd5f3aaf, 0x9187bcaf, 0x987d766f, - 0x3b2833fb, 0xfd907d77, 0xe6ffac5b, 0x590ff4fd, 0x5e53f6ff, 0x493ed1b7, - 0xe276ebcf, 0x7fbd9ef7, 0xeb187f4c, 0x9f142dbb, 0xabfd79ee, 0x9e9fe45c, - 0xd4129695, 0x80433d77, 0xec1f68fe, 0x83b72afd, 0xa27ad7d6, 0x99251fdb, - 0xfe7b47db, 0x8f10b1f6, 0xed0acc25, 0x49a3d786, 0xb35eaa9e, 0x67ad3c51, - 0xa17957ef, 0x9d77ff76, 0x7fb6a54f, 0x736763d9, 0xb17c2276, 0xeaa7df7c, - 0x5f3fd7b7, 0xad17f98b, 0xf085e4fb, 0xbeefca7e, 0xda3d45c9, 0x43db93b3, - 0xe78ee6dd, 0x68ee7f70, 0x6695dcfd, 0x0a3773c0, 0x9bac0a55, 0xa014cf0d, - 0xcbc7f4dc, 0xbc271437, 0xfcf47c52, 0xc10f835f, 0xdd9df5cd, 0xde70156f, - 0x21fc7f5f, 0x2dd785ea, 0x7cfa97c4, 0x25a96f3f, 0xf372e57b, 0x9c799876, - 0x799dffe4, 0x992b810b, 0x3ff328f7, 0x2d7fbd37, 0xe12e8939, 0xcf9fd072, - 0xf5443ef7, 0x822eed97, 0xfdf90af7, 0xf9f27ff6, 0xefba6b7f, 0x2e3bba04, - 0x7ff2ef3f, 0x4c0f79f2, 0xd7ef37f7, 0x7e62aee8, 0xbeefd54b, 0xadbef821, - 0x4ffb5b9e, 0xcd03ef2e, 0xd7ebb75f, 0x994d5c98, 0xaf439f18, 0xc569d601, - 0xc311b33e, 0xcc466b85, 0x14ced154, 0xf52bf6c3, 0xfb99af72, 0x5bee224d, - 0x086f9c62, 0xcd31f38f, 0x3d2da28f, 0x8a525a18, 0x94958ec9, 0x96bedc55, - 0xc06eed5c, 0x176b9acb, 0x887728b8, 0xc5ea3d8d, 0x1764da7a, 0xfcc3afc5, - 0xb9817ac9, 0xa56fb005, 0x8c396f6b, 0x84798dfe, 0xa5c96029, 0xab9618f2, - 0x59a4b8b5, 0x8f7e0d95, 0xdbac6392, 0x45bac69c, 0x38cacfeb, 0xe624d6fc, - 0x38b4f8c7, 0x798abf72, 0x8918e26d, 0xb1b75009, 0x17fa1f26, 0xf7e32496, - 0x1ec0311b, 0x5abdcf12, 0xe1f6f63c, 0x1bbb6c71, 0x44d238f1, 0x2e4a6b71, - 0xfcb8bc25, 0x8d9e786b, 0x55d788d5, 0x094f88ed, 0x7f6e5ffd, 0x34ccdf91, - 0xbad2597f, 0xdc984690, 0xcd3b6336, 0x9d2cbe4f, 0xcbd25d38, 0x332d3a35, - 0x43a745d0, 0xe818fa04, 0xdbf9e3a2, 0x2e9c27d2, 0x6fdff8e1, 0x07fe1276, - 0x974e97a2, 0x50cdc534, 0xbf9acd5e, 0x49fd1530, 0x1879a7ac, 0xfe6b33ed, - 0x66ef1482, 0xea93a43e, 0xf42f4862, 0xb7e002db, 0xf3fb7efd, 0x7aea2714, - 0x081dd8e9, 0x456fd94f, 0x75fc0566, 0x00b3b76f, 0x65f92f7e, 0x5b4b43f4, - 0x33fb8a45, 0x57779029, 0x6eafbec8, 0xcafd97f7, 0xdd29f34e, 0x06dff169, - 0xfaee97df, 0xb0ec9724, 0xd7e4bd95, 0x38125ef8, 0xb91d7ddd, 0x2a5bafb8, - 0x9c23ff71, 0x9e65625f, 0x3bb9d027, 0x6dc60e7a, 0xdf3c6d84, 0x1ee5b4b6, - 0x7f90c5b3, 0x91dbd666, 0x28bdf05e, 0xc213be50, 0xa9e79a17, 0x2f9d1dfb, - 0x36be1c0a, 0x76f31fb3, 0xe8edb74b, 0xe953f8c6, 0xc30b8b51, 0xbedb55d2, - 0x298dfda0, 0xd1d97abf, 0x68b6fe41, 0xf3f43f88, 0xc489b7fb, 0x15ad951f, - 0x9d4087e4, 0x25b2a2f8, 0x72ebfc72, 0xafd969fe, 0x01f2eef6, 0xfd7ecb0a, - 0x5be30382, 0x3ab7dba7, 0x76dfffc8, 0x3f5bb8e9, 0x91e5bf3f, 0xa7f9fa4b, - 0xbfe01ff1, 0xc58720dc, 0x220db649, 0xcbe0047f, 0xadef948b, 0xcbd95bf3, - 0x38c39f67, 0xcfcee774, 0xcb78439f, 0xe7cbfbff, 0xaf609fd0, 0x88add4db, - 0xa5de9797, 0xddfe9e38, 0x9dc7992c, 0x817c5fbb, 0x1fdd9fe2, 0x7f01df80, - 0x4a9ef7ba, 0x7bb27f47, 0x1889d7c7, 0x77be592f, 0xef9c60da, 0x0ca757f2, - 0x88f41166, 0xfadf225e, 0x1afe20af, 0xad03af4e, 0xe9efc807, 0xdfa37a02, - 0x69b717d9, 0x3071e0a9, 0xd9af16a7, 0xddce391e, 0x7ad33e2f, 0x8d379dd7, - 0x72ecd2c7, 0xd3882bb2, 0x1c7403bc, 0xdbf4057d, 0x7fe688fe, 0x175fa646, - 0xb4e803fe, 0x677e8c2c, 0xfcfd175b, 0x3ad77c19, 0x4d38c068, 0xa6f00ae0, - 0x27bfd1c7, 0xa3227fbb, 0x25fced7c, 0x6e90c5c5, 0xbb44c1b7, 0x8e9b3e5f, - 0x9a9f0ffb, 0xe7e7ef7b, 0xc62a2c32, 0xbef74a1b, 0xfdd3f24f, 0x538a11ea, - 0xdd9e2d33, 0xf0fefacd, 0x5396a3f8, 0xcec5b559, 0xfe1a3be3, 0x74e3fe31, - 0xce2d73d0, 0x8f58f9c3, 0xf7140cff, 0xde799569, 0xafdf1e88, 0x16a1f2d8, - 0x4bd2094f, 0x3a748498, 0x08fdc976, 0xe22a0f1d, 0x1c686261, 0xad7c7233, - 0xd1adde2f, 0xf187e90b, 0x2538becb, 0x6e30d3d4, 0x67de17e5, 0xf741f411, - 0xecff1e66, 0xa3ce4736, 0xbf9ae3d2, 0xff53970a, 0x2f33c595, 0xc5b7ff07, - 0x52765f8f, 0xea78e1bf, 0x8f5910bc, 0x75f32dbf, 0xc5f7aaff, 0xbe4305ca, - 0x7bc9b941, 0xa2b1f904, 0xcfcc98f5, 0x52f3f0a5, 0xb53b7cfa, 0x97ced1bc, - 0xad778a44, 0x7a40396a, 0xe85f5c3c, 0xf0e1a6fb, 0xade0d09e, 0x44ebe36c, - 0x5fbb4ee7, 0xf73a7e81, 0xae7e26ef, 0xe28c7edc, 0xfdb6876d, 0x5908ee5a, - 0xf09d7157, 0xf9dfc087, 0x1e5cbeca, 0xec79e5b7, 0xd19ce3e1, 0x9ed561f4, - 0x6d54e3c8, 0x4e30c2ff, 0xe645af99, 0xc7a5fdeb, 0xefb92d3b, 0xb74efec1, - 0x79e6199b, 0xa7116e9e, 0xf5173a47, 0xea6eb6ae, 0xbd707ee7, 0x23fd7ca4, - 0xf8cc5cfc, 0x1f28a3b7, 0xe991f97e, 0x63c4c61f, 0xfe878409, 0x9f396b5a, - 0x9dc4feb6, 0x3d6ef48a, 0xeb88af72, 0x6fc42ed4, 0xf79f9d88, 0x3b14f54e, - 0x8fbc85e8, 0x5d91e33c, 0xc4cdf5c3, 0xfc0326a3, 0x5c60ce30, 0x1fa1ea07, - 0xf982a73c, 0xe88f086e, 0xf08e9c28, 0xb549aa88, 0x61e7fd09, 0x5e743c56, - 0xacd7ef40, 0xb003cf1a, 0xd89ce30b, 0x1e4cd24f, 0x8bbe4c47, 0x3cfd3e97, - 0xbf94714e, 0xa059e60e, 0xf02cd378, 0x7d7d927d, 0xe78641c6, 0xde5126bf, - 0x78c59676, 0x554bac6e, 0xdfd0267c, 0x596ce4cf, 0xf949d937, 0x4258d707, - 0x20580ff3, 0x6f51f917, 0x587defd7, 0x7e1a427e, 0x1a88fd02, 0x7e5a597c, - 0x21d610c2, 0xc9bd7da0, 0x0e27cfce, 0xf84de255, 0xbd9af3fd, 0xec3f9fa9, - 0xec315e77, 0xcee5e29c, 0xc94fc627, 0x05d43a5f, 0xcf7ab4fc, 0x8f5fcc14, - 0x477f27bf, 0x12798aaa, 0xe7829e7f, 0xc85fe257, 0xf50c931f, 0x9c1fab13, - 0xc8fff54a, 0xf50e931f, 0x8dff1a6f, 0xca04cbd7, 0x3d582d57, 0xebf22a7a, - 0x2cf9cb55, 0xce5188c0, 0x75bc40ef, 0x7bba3e79, 0x1ff31391, 0x5f8e657a, - 0x4376c1e6, 0xa5bc7126, 0x40ed1f29, 0x75350d3c, 0xfe7f22d4, 0xb157ef7c, - 0x4c9c17a8, 0xaca8fc25, 0xc1fa455e, 0x2f1749a3, 0x9e174791, 0x93eba64f, - 0x01f78acd, 0xf991e384, 0xe05ce823, 0xad332533, 0x98cf5f3c, 0x78d4c0c7, - 0x469167a2, 0x1ad3844f, 0x58bf8f92, 0x5cfcc9f4, 0xafa6934c, 0x9e38aaa6, - 0x2f172be0, 0xe1edf75e, 0x4be7507a, 0xc8695ced, 0x1087c679, 0x7de29f5e, - 0xffd092c8, 0x161de33c, 0x9f7c0acf, 0x1d3e7c5c, 0x9f3f5bf9, 0x91ce7e18, - 0x48a6bd49, 0x76b35ff6, 0x782071ce, 0x2aef563d, 0x77f3371c, 0x41879dce, - 0xc91746be, 0x1ccd4c2e, 0x827c62bd, 0x5215cfc4, 0x4695439e, 0x971324bf, - 0xa310f643, 0x8b1ed67d, 0xb9bf46e0, 0xf49541e7, 0x6dd15a77, 0x44f557e4, - 0x3e60b467, 0xfcc3cf50, 0x4c66295c, 0xd90d1ca3, 0xbf401313, 0x5ce0e40f, - 0x339c1c98, 0x71c673ae, 0xdb3a2e7b, 0x553fa83a, 0xb00c0feb, 0xe0b9e0c4, - 0xe5eb911e, 0xc1271a9e, 0xf6f98431, 0xa57efae1, 0x18b56de3, 0xde02fdcf, - 0xe8bc405f, 0xc0e5ff78, 0xa3457bf4, 0xe8912bdf, 0x74fe7e17, 0x6bfbc5be, - 0xf8aa7f6c, 0x15742ad0, 0x869dcfc3, 0x6a4ab5d3, 0x78ae88da, 0x682f9ee2, - 0x36e9d19d, 0x412b857a, 0xe3a0641a, 0xe8efd8eb, 0x10985f3d, 0x4f7e9d5e, - 0xfdef900f, 0xcf5f0b07, 0x9c4bc7c2, 0x8de291d3, 0x1060feb4, 0xcf58212e, - 0xf8d1e6b5, 0xde3c4d83, 0x10bdbfd3, 0x7fd03e71, 0x30f2a5e6, 0x2fde5573, - 0x50fdffe0, 0xf110ffbe, 0xfe22223f, 0x03bc463f, 0xf6c63ffe, 0x4fff8057, - 0xdd7f852e, 0xf4d32fae, 0x2bee1942, 0xc5fcff01, 0x13313339, 0x15142dc6, - 0x5b25ffe2, 0xd21f6d45, 0x62725b7d, 0xb92c8f50, 0x199f7abe, 0xb3c970f8, - 0x9169f102, 0x73fd5e76, 0x784b5ced, 0x1cf15f5e, 0xcbc9e91f, 0x49f9f7e7, - 0x336d950f, 0xe410bf3e, 0xc7ca74db, 0x93f3f1f5, 0xe11726a2, 0x68a33ff8, - 0xd628a2fa, 0x0e9c2ed0, 0x864daa43, 0x29e4f03c, 0x9f90fd7d, 0xbe726497, - 0x3fb5f14f, 0x07c61998, 0xf8fc52dc, 0xbc63e200, 0xcdfb1530, 0xef56e4d7, - 0xe30ae86f, 0x33e19f3a, 0x6acbfb9e, 0x1bfb9e34, 0x686294de, 0x4c86cd7f, - 0xfe91fbc3, 0xafef0d6b, 0x50d636db, 0x8372d51f, 0xb6e8fda1, 0x4c7d4302, - 0xfb4316e0, 0x1a678771, 0xefda13ea, 0x789fb435, 0xfde18174, 0x86a51df5, - 0xba7e37f7, 0xa9bf50cc, 0xed0d5ff7, 0x5eb88b03, 0x94935fdc, 0x740ae786, - 0x2a5fecbc, 0xbe7c549b, 0xe6a4db34, 0x744f3e86, 0xccb1733b, 0x357fa373, - 0xb14cbc90, 0xae85a726, 0x6cccf9cf, 0xac536bd0, 0x55817ac6, 0xe07497e3, - 0xcdfe2017, 0xa55ca356, 0x026bcf56, 0x2ca59bb3, 0xd2f94619, 0x58b75f20, - 0xc5bb7eb9, 0xedfa657a, 0xaa7f6c4e, 0xece74032, 0x444be5c3, 0xd2a2caf9, - 0xcca9fb47, 0x1b96f945, 0x4d3e466d, 0xccaf401a, 0xc3cf1ab3, 0x9b61ea8b, - 0xfd139064, 0xd0a8f9f9, 0xdbe2c2e7, 0xa0676f28, 0x05a4e57e, 0x7d016eb7, - 0xa97b2729, 0x9aaf9fd4, 0x97988a63, 0x3bf590f7, 0xfa1b49fa, 0x210f4fd9, - 0xde92bb7e, 0xccf30a7e, 0x92f5e72a, 0x316c94bf, 0x775825e2, 0x5479e60d, - 0x508e7e4e, 0x54dcffe5, 0xae2b78d3, 0x173cfaf7, 0x1133307d, 0x06d203f3, - 0xd55e9ff0, 0x4d5cf1e6, 0xc345adc9, 0x14d53fb0, 0x7a45bf7a, 0xfd10aaa0, - 0x1e5aa198, 0xc8a653f4, 0xd53f4af9, 0x0a8c19fa, 0x5503ed14, 0xaba0fb21, - 0x048723f8, 0x9377f8f3, 0x17c8a7f7, 0xe7b7460b, 0x6ecb73f1, 0xabb24cd7, - 0xd75f8254, 0xe78ae943, 0xe92bd429, 0x66731249, 0xf06787f4, 0x06636f3c, - 0x338fafbc, 0xf7aa14b9, 0xe59e380a, 0x820d8cc7, 0x5bffeaf1, 0xf7eaf824, - 0x3cf94f5f, 0xe29aa516, 0x993cfaa7, 0xc7afdfb6, 0xcd26cf8b, 0xd63c418a, - 0x6e77db5f, 0xacfd6187, 0x7ec76de2, 0xd337aecf, 0x8205f5b8, 0x6f3ebde1, - 0x741dc369, 0xe15d2b1e, 0x79862ef3, 0x3496dc23, 0x73fd570e, 0xb8234b02, - 0x43d2f7fe, 0x8aecbfe8, 0x0dbc6176, 0xe889b1f0, 0x6738ceed, 0xf30f27d2, - 0x34a418aa, 0x25fb21af, 0x96fa1fb2, 0x4cdbaf95, 0xf688959d, 0x4635f254, - 0x66f5c5b8, 0xc51707f2, 0xe0af942a, 0xd1a159af, 0x55ef38d5, 0x9cef3349, - 0xbdd4f00b, 0xfd4c3223, 0x2d347671, 0x15df043d, 0xfcbb46b7, 0xef78fece, - 0x01387272, 0x6e10b7ee, 0xcd214371, 0xdc21da9b, 0x33d8173f, 0xde77c819, - 0x14ff44e9, 0x977dc313, 0xd3fff870, 0xefc4e3ca, 0x879a5558, 0xeb7c549c, - 0x16584196, 0xb51ddc91, 0x7fceb80e, 0xfcebe568, 0xeb08d687, 0xfdeee5fc, - 0x7ed39f28, 0x6dd14b08, 0xeadaecd2, 0x197b50ec, 0xec49d6f4, 0x318baf57, - 0x7ec5ce3f, 0x3ccbb607, 0x9719d94d, 0x1ed0cbb7, 0xedd3fe43, 0x8d5abfb1, - 0x9e886476, 0xb3d34afd, 0x9ea15d5f, 0x4eed80bd, 0x68881bdd, 0x91c824c7, - 0x1b38dcf5, 0x2a957fc7, 0x1be3ca33, 0x6d9f9e20, 0x0e1f6c8b, 0xce5d0eb4, - 0xd68cc8cf, 0xefd754f9, 0xc560dfdc, 0x9c2fed32, 0x247fe0d9, 0xe329f71b, - 0xedde5187, 0xaea4fd40, 0xf10d83f8, 0x886de3ab, 0xc04f88cd, 0xf9c6d3a3, - 0x648b69c4, 0x1e03960f, 0x0e3c064d, 0xd903f6c7, 0xdfad5783, 0x6ee78c4b, - 0x837c35ba, 0xbc71979e, 0xce3ebbae, 0xe545b8c3, 0xe7a473ec, 0x399c7aaf, - 0xf74475c6, 0x011c61bf, 0xd77ddfe7, 0xb7716b7f, 0xd5178a0e, 0x0c4d7abd, - 0x0a2aa7c6, 0x9586f4fa, 0xa49985db, 0x5976bb07, 0x576708dc, 0xece7cf1c, - 0x10f135da, 0xaf3e39c6, 0x85299c39, 0xaf5d2dd8, 0x4333c91c, 0x8f3b5d7f, - 0x209449e4, 0xd17e27e7, 0xfc5c57df, 0x128f3ccf, 0xc7d0273c, 0x0ebe566f, - 0xf8f1b7ad, 0xc798d3c9, 0xf7b19a36, 0xfaf963a3, 0x1c7a6891, 0xe3bf479f, - 0x7f7ea1f3, 0xc7e57054, 0xdd262b00, 0xab664c55, 0x00a68de5, 0x6e0a8f96, - 0xbe55e311, 0x4d3cfc91, 0x911b1652, 0x4728fd01, 0x8e0803db, 0x8dd7a3a3, - 0xa7ea29db, 0x0b2c3eea, 0xc402ef14, 0x2baf5c7b, 0x37fc7d09, 0xa1b38d87, - 0xe14d215f, 0x7e77b77a, 0x29ef1f94, 0x8fb9344a, 0x6767aa80, 0xc58c2f0e, - 0xe68b7ff7, 0xd258f2f2, 0x8e5c2689, 0x38a03970, 0x5a669bd4, 0x710d96df, - 0xef822f27, 0xe7884d97, 0x9805e97e, 0x9639c87d, 0x0967e3c7, 0x00b90714, - 0x14e78178, 0xb53e02fa, 0x3317cc4b, 0x89b0f416, 0x0bf055b9, 0xee4293ec, - 0x68ffc1d9, 0x4d60fc76, 0x4d38f6ff, 0x45e0333e, 0xd5db1976, 0x5c0cee09, - 0xfc81774f, 0xb4fa030d, 0x7ca958d5, 0x184d46ad, 0xa7b8f206, 0xafea8926, - 0x0ca938d7, 0xe7a08cd4, 0x545c6bfb, 0xa7b5368f, 0x552c7ad3, 0xfe879baf, - 0x0b12fdf5, 0xbc23b7bd, 0x8e567bc4, 0x97f9c887, 0x0093e62e, 0x3d352fae, - 0x38d6fb52, 0xc6a7afe2, 0xfd31d400, 0x8ad9ffbf, 0x054d643f, 0xa3fa983d, - 0x415359c3, 0x78129f8e, 0x181e02fe, 0x552e748e, 0xb7329f2f, 0xf0a9a2c4, - 0x4df31b6b, 0xc8bcc24d, 0x8e153fde, 0xe8f6cc61, 0x1d4ea69f, 0xfdc7f309, - 0xf6c614fe, 0xc7abdeda, 0xfba9d873, 0x818bab3f, 0xfc6dc8f9, 0x82899f3e, - 0x7d4056a7, 0x0bf39b33, 0x98b53c93, 0x3773d9cf, 0xbefee273, 0x1b5ece3e, - 0xdb7613b7, 0x51399db8, 0xe6c1fce0, 0x411e5aca, 0xbae86e6f, 0xef3ede11, - 0x8f74d7c0, 0x2fb78c0f, 0x2f5e30d5, 0xfa0711c5, 0xd7ff752e, 0xe95c8eb4, - 0x491f3d77, 0xc4847cfc, 0xe6ba2bf3, 0xfda66e26, 0xba1f6878, 0x4723da8f, - 0xd2ded7b6, 0xed0681d6, 0x659fb7be, 0xa68372f0, 0xf5c62457, 0x05d16bff, - 0x61b947bf, 0x5fda38de, 0x09e2d3aa, 0xe57a3a93, 0x2f7e76f9, 0x13d43e5c, - 0x3c04784e, 0xd1a5d70f, 0x1e605533, 0x6048ffcc, 0x28028433, 0xdbcf36dd, - 0xc2d24fd8, 0xd197be4d, 0x7165d85e, 0xe3a3d9a2, 0xd903eeab, 0x6121fa8a, - 0x8fda31cf, 0x643a13aa, 0x8f97f7a4, 0xcb714d7c, 0x3275733a, 0x1b176dd5, - 0xbdb4feb0, 0x99d6237a, 0x6fa9ebef, 0xd60c3f00, 0x13e3e1ce, 0x90bb63d4, - 0x3b5829e8, 0x7e06ef57, 0xf5e665d8, 0x4b391f2f, 0x5ccbb1fc, 0xe18d9f3d, - 0xef987af5, 0xaa6f58ae, 0x52905409, 0xe1fd65fb, 0xb7aeb09b, 0x77da92ff, - 0x3f6e54db, 0xa40cde2a, 0x855d5f7f, 0x2ea43dba, 0xf2b33af1, 0xc55f9f52, - 0x7f29af81, 0xe70f72b8, 0xce1bc447, 0xc3cdef13, 0x7a8ce975, 0xa4eb51d4, - 0xd73673b8, 0x9f0301d7, 0xb753e7e9, 0x2a2cbc98, 0x085ecf44, 0xce42ff5b, - 0x84a8b1d9, 0x38b4fe90, 0xbb033a76, 0x6f182b34, 0x2a2e64cd, 0x950f3187, - 0xee96dbd9, 0xbb2db447, 0x7a89d5af, 0xfad73e2b, 0x68e89780, 0xd09e1ff4, - 0xe8fae2f4, 0x01a31bfc, 0x7782f59e, 0xf17a888d, 0xe74ab365, 0xb2243a2f, - 0x35b53b37, 0x5330ad8c, 0xf73b5cbd, 0x5de95e6d, 0xeef51233, 0x19ab9322, - 0x4f0cb3d7, 0x2fbe19be, 0xaae19ddb, 0xe7bcc165, 0xc496d8b2, 0xef304ab1, - 0xaa3faf59, 0xb546d9f1, 0xd2f786c9, 0x9543fbe8, 0x71d2eb6d, 0x7db3fb7f, - 0xbd3c901f, 0x7c41951f, 0x447ad15c, 0xbf69daf6, 0x29f3c64c, 0xd6fad99f, - 0xbef75a3f, 0x0b74196c, 0xeb2ff5ea, 0x79b8744d, 0x06f43d20, 0x38373fe8, - 0xac6a87c8, 0x5dc2fe54, 0xde9a2d7d, 0xd3295105, 0xbfb4606c, 0x9156e990, - 0xb9ade68f, 0x7c0ac1a6, 0x8eac82f4, 0x179b3e44, 0x5b7c4b95, 0xbe722b16, - 0xdd07b964, 0x0dcfb692, 0x6535d4f5, 0x3c53bed3, 0x6f68c8be, 0x88526d54, - 0xc80ec00f, 0xdca83e47, 0x7ee1f260, 0x4edac9a2, 0x45e77de7, 0x368fcd31, - 0xaf5c4f9e, 0x6cdf3be9, 0xdcbddf1e, 0xf392c539, 0x511e7451, 0xe51fbfaf, - 0x9128be24, 0x55ffb47c, 0xe741de72, 0x38fbbf18, 0xc879c356, 0x0428e3fe, - 0x794e3e87, 0x57d21c70, 0x27ec1fe5, 0x6b8df83f, 0x4dd67b75, 0x3be5ac71, - 0x9b05fcb4, 0xf3f6307b, 0x1827a6b4, 0x7780b1fa, 0xeeafa329, 0x1ccf4093, - 0xf933d3ec, 0x90d3530d, 0x6cf7c1be, 0xb90f4192, 0xc1d3a025, 0xfbeead28, - 0x51f6e47e, 0xf533ed61, 0xa986ccfa, 0xf3c3fb93, 0xb7582db4, 0x1be97b42, - 0xe11d5f4b, 0xa1f573a3, 0xe3e9c5fd, 0xe9fd4bdf, 0xb51a97fc, 0xf80fa0f0, - 0x27ac60ef, 0x7a7cf31f, 0xca273367, 0x8d4966e1, 0x21d08572, 0x37af8a35, - 0x35afe725, 0xf7883fe0, 0x4ffd035c, 0xfb0d38d5, 0x968b8b8a, 0x549879d1, - 0xc7cc5e9d, 0xca6d77cf, 0xfe27ec32, 0x16ae387f, 0x7000f70e, 0xc307fd4c, - 0x5e30c231, 0x031c8e10, 0x870b577c, 0x7a6b3b18, 0x8f6bda06, 0x280f2898, - 0x66b3e4d1, 0x6ff65da2, 0x0ca78a26, 0x880f3c67, 0xfb0de329, 0x2c7b99b4, - 0x9efe31f3, 0xd2c3b129, 0xb7279458, 0xa9d716b3, 0x5f64489f, 0x39ab73c1, - 0x726e870e, 0x204ffde3, 0x665fd495, 0x1f82b7b9, 0x82fbe6f2, 0x70d33efa, - 0xbde3e595, 0xe7a39ba0, 0xfb8d18df, 0xaa1e7366, 0xe7983cc2, 0x352ff195, - 0x92bc8330, 0x2c20d21d, 0xabe33b25, 0x701b87a8, 0x147076bf, 0xf6045bb7, - 0xe4e1c370, 0xbcb9ef48, 0xf0f35b9e, 0x341b8c34, 0x8b5e74af, 0xcdb353fe, - 0xf31fb2df, 0xe8531e76, 0x47acd6de, 0x50998dfd, 0x6899d717, 0xfd6314bd, - 0xdf719adb, 0x176cc9fd, 0x68cd11da, 0x47fb60bf, 0x566bf214, 0xf0d338d5, - 0x6d3a927e, 0x76b2d81d, 0xc1798ab2, 0x87148af5, 0x732addeb, 0x773c5cf5, - 0x8dd1ee31, 0x51ebd60d, 0x071ab98f, 0x949ebca9, 0x339aeb8c, 0x7b463ad3, - 0xae68c80f, 0xb1a8a675, 0x6ff0fac1, 0x3d20fac0, 0x9dc1b1b3, 0x2b2efd86, - 0x883bfad5, 0xe2178a71, 0xef68bc34, 0xd2f4fb33, 0xcbcc06c6, 0xf5836b12, - 0xaddf30a9, 0x353d72cf, 0xfb47fa18, 0xc3e3e60b, 0x877b057b, 0xca4e744b, - 0x603b6306, 0x9991b67e, 0x0cd7dfb4, 0x2bef117a, 0xdfc91dee, 0xf234fbeb, - 0xd3ed1370, 0x6f5c7b60, 0xbdbcc96c, 0x57df833c, 0x8a15db20, 0x307ac037, - 0x149ef315, 0xf371ffa6, 0x8fb6a4b8, 0x01f78511, 0x75a3f084, 0xf73a32ed, - 0xdc661d69, 0x8cd3979f, 0x16798975, 0xaa27bfa0, 0x4637e7c6, 0x8341f96b, - 0x6dda0a58, 0x133e4dc3, 0xfcc91bb6, 0x02c75e54, 0x628d8f64, 0x8d1f541d, - 0x1e16635e, 0x41d2725b, 0x2dcc71ab, 0x47aa38f2, 0x71313b44, 0xf2471eae, - 0x74be414e, 0x61766b47, 0x7e3fef0a, 0xf7ca2cc6, 0xcdef69f5, 0x313d8633, - 0x7eb5e60d, 0x50ceddc6, 0x2f5f4efb, 0x48adfb75, 0x68cbf983, 0xa0bda221, - 0x364575db, 0xe5984f5e, 0xc6147a7e, 0x26cddb11, 0x58ad9fbc, 0x6f16638b, - 0xbb444fc8, 0x5cdf68ac, 0x44d787b2, 0xd16cbb73, 0x77b219fa, 0x9af79e14, - 0xfe7f764f, 0x183109ba, 0xb9b06fa7, 0xfe47ae62, 0xdfbf23fd, 0xb1ed4af5, - 0x0a6bc4e6, 0xc19b1e50, 0x8ffbc6af, 0xcadd9a0e, 0x758be418, 0x6ccec8c3, - 0xc7d6f28e, 0xffcdbf42, 0x41d574ea, 0xf73667fd, 0x4e3823f8, 0x8f7f1443, - 0x6f2126f7, 0x3ff7edf6, 0x1e8c5c2f, 0xfdf0fc78, 0x91b183fe, 0x43bdf1ef, - 0xfed05fc3, 0xd9dd90f0, 0xdcc4f660, 0xcbbdf087, 0xead679e7, 0x112f5189, - 0x86b4fb67, 0xd67603e7, 0xe64058b8, 0xbd62d1f7, 0xdd3f68a4, 0x22d25caf, - 0x097cdc50, 0x3a3d226b, 0xeed5894c, 0xc5e631a7, 0x4dbd1696, 0x795b4bed, - 0x42d632fb, 0xe17a75ed, 0x8301b5bd, 0xf0ce3a1d, 0xdcd11dfd, 0x78acdd6f, - 0xfffb431f, 0xc4d91991, 0x1167c04f, 0x07e22df3, 0x31b977d8, 0x371faf9a, - 0xf6c8db62, 0xb863f128, 0xe05cb87d, 0xc207b3e7, 0x9379d553, 0xde0a3d61, - 0x7ad3219f, 0x49f9add4, 0xeb7c9387, 0x7ff9846f, 0x244af59f, 0x23bddaa7, - 0x425f8275, 0x33befaf9, 0x2d1bdeec, 0xa6ba680f, 0xcb43fe25, 0x6b3ef9ef, - 0xfd0dc379, 0xf402cedc, 0x9eed61dd, 0x48a41412, 0xafd01979, 0x3adc1f41, - 0xddbf58c2, 0x39dfac65, 0x7d3df229, 0xb4d46b6b, 0xd6aa7bd0, 0xf38e700e, - 0x575e8d2d, 0x0b12df7f, 0x0b7bebcf, 0xf9815ee9, 0xc17fb494, 0x1b14faf3, - 0xd91ea0f3, 0xfb46cfbf, 0xbc8a5521, 0x55164319, 0xbde2efe0, 0x9f9d8af0, - 0x17ff4037, 0x998a05e3, 0x97de0fb7, 0x1251f7c4, 0x3c5a493c, 0x633495c3, - 0x1b87b7d4, 0x0bca2afd, 0xdc46d896, 0x27e60d77, 0xe8edef1a, 0x0f38fe8a, - 0xcf9863fd, 0xe84f8c6c, 0x3e7d5a71, 0x2c7f28ff, 0x39cfbb5a, 0x346b6e9c, - 0xa30ba8f9, 0x39d23d73, 0xb973df07, 0x87bb52f9, 0x43c129ff, 0x26896879, - 0xb3ac171e, 0x9c528eb9, 0xea0ff344, 0xf306b8b4, 0x56ef5d7d, 0x1095ecc2, - 0xed7d22ff, 0x39f5f5d7, 0x38f377e4, 0x156a2d88, 0x360dc3ae, 0xfaa66ebd, - 0x00a6e6d3, 0x5aaffdf9, 0x831f189c, 0x6718ddef, 0x411dcdf3, 0x065d5d7e, - 0x0e7bc14b, 0xb4cbb0de, 0x6abdd6fe, 0xd8f5c669, 0xdb76f36d, 0xba49f242, - 0xf9d1efec, 0xf9fd08a6, 0xf90dfd0c, 0xf8c1fd76, 0xfd7788ad, 0xa7f61bfd, - 0xceff2202, 0x691bf949, 0xa17b1fed, 0x42cbb89e, 0xf7fd4f71, 0xe7cfca0f, - 0x7a8cfdd1, 0x4e14137f, 0xd51ace87, 0x8e5d8f90, 0xe507377a, 0x67f49da0, - 0x8320cb45, 0x69f5d4de, 0x681bf9c5, 0x57482cbf, 0xb5212e2d, 0x38aa5e93, - 0xbc68bfff, 0x349e903b, 0xf7e9124e, 0x3549c781, 0x38e0e3e8, 0xf7700c93, - 0xc132671f, 0xdac38fa1, 0x9fe70ca2, 0xae3ccceb, 0x33986672, 0x1e823626, - 0x83714bd1, 0x60ff70c9, 0x62b2e49d, 0x4eca75ff, 0x287f3435, 0xef005f7c, - 0xf02164c5, 0x867ac1d5, 0xf30b72c1, 0x3d405e52, 0x072213f6, 0x62a5d9a2, - 0xf8c262bf, 0xc62ef9e9, 0xbdb945fe, 0x33727d10, 0x8bd82df2, 0x7e3b583f, - 0x49ec0f95, 0x4769ecc9, 0x93764aba, 0x6b68f313, 0x45c51315, 0x64ac92eb, - 0xca12adff, 0xbd739455, 0x2243a95f, 0x8f7df438, 0x9f29e681, 0xc33cd077, - 0x9ffb3bef, 0x76a14f1b, 0x3b57eefd, 0x0f93d730, 0x93545bfd, 0x4e5d450b, - 0x2127d853, 0x47ef0ff4, 0xec4520da, 0x8e9dbc27, 0x6ce901ff, 0x3d2070ee, - 0x88a5e3ba, 0x951b1079, 0x310798ef, 0x271f4c2f, 0xe00ecd1c, 0x238742f7, - 0xe5f48323, 0xa5f50546, 0xdc9fccfd, 0xb4cbd24e, 0x7fafadef, 0x56a984e6, - 0xbc6c4f9e, 0xfe206f57, 0x7d62f1d3, 0xf3c641f3, 0x7f94bd53, 0x483c3972, - 0xfb43cb82, 0xe2297600, 0x425836be, 0x4938fc86, 0x354fe631, 0x63e21e48, - 0x56d54df3, 0x5b4927da, 0x927dc569, 0x063392d5, 0x37ded8fd, 0xf983fec1, - 0xbe793a35, 0x6bff786a, 0xb4661ef0, 0xc4531573, 0x06a379fb, 0x34baafb0, - 0x77d9acfa, 0xf501fe69, 0x3775c1e1, 0x71524e2a, 0x399b35dd, 0x4bad03bc, - 0xe103bf7a, 0xfc7dd1eb, 0x392c1bf7, 0xffae3f56, 0x4a35e3e1, 0xbc3e4f1e, - 0x7078046f, 0xcd31acdf, 0x546df84d, 0xd5fd1525, 0xcc5111e8, 0x656fea1a, - 0x67f7a2cc, 0xccf1e3e2, 0x8f8c6b22, 0xe3a3979c, 0x1df2b769, 0x186f1ded, - 0x8f7f0e5f, 0x7c21e8e2, 0xe84ca9d9, 0x91bb97cf, 0xfc381317, 0x5aa6f7a1, - 0xbc458633, 0x7f1fb27f, 0xde4df186, 0xf7e74664, 0x19b94306, 0xeed56efa, - 0xb5c0aa43, 0xf2f4fc0b, 0xc2a6147b, 0xe477e6fa, 0xc939405f, 0xcfcfdf6b, - 0xf026b4d1, 0xefb51e7b, 0x625dc7c3, 0x12c8fee7, 0xcc654abb, 0xf12ff751, - 0xdb5a37f7, 0x5e789ca3, 0xb22e35b1, 0xd763931f, 0xb49a68f3, 0xb41d0873, - 0xcfb7a14f, 0xcddcc79b, 0x1b3dc50a, 0x257fe0ad, 0xa9ffb5f4, 0x82023fb6, - 0xf9dce30b, 0xf99aebdb, 0x7f3e51f9, 0xfb62ab8c, 0x5c8ec4c4, 0x740efc41, - 0xf70cc6db, 0x3b5855db, 0xe7ce51b2, 0x7699bc9a, 0x68eaa718, 0x5bd62247, - 0x4e9d3edf, 0xb71d6f7e, 0x47777b37, 0x3fa0dc53, 0x79f96a7d, 0xcc29f3f2, - 0xdd3fa837, 0xad00a5ca, 0xd3e7e5ab, 0xcd1c6f99, 0x0b8d67db, 0xc2d3bfbe, - 0xc8b1a4d8, 0x884f1c00, 0x30f4489f, 0x7a064ddb, 0x675e3c80, 0x7881e8d7, - 0x76b7a3ea, 0x76a74bef, 0xcd71e0bf, 0xf72a615f, 0xa5fbf5d7, 0xe5f7678e, - 0x5b7dd05b, 0x13f736e5, 0x3b0b4f78, 0xe6be5222, 0xfefc29c2, 0x771685c4, - 0x0b57da0c, 0x6a1453ff, 0xf3937f69, 0x7f0d22fd, 0xf745cc9d, 0xdad6f80e, - 0x984ebef8, 0x54f1967f, 0xc23fb8fe, 0x44da8bf7, 0x305f1bca, 0xbf61f145, - 0xbf05ed79, 0xe2f9fdc4, 0x773a68c6, 0xae7bf0be, 0x2dd76893, 0xc4e6c27c, - 0xfe597bdf, 0x327e6641, 0xc9fcbbf4, 0xdf07d50c, 0x24f0af45, 0x27a05d59, - 0x8853db1f, 0x3083457e, 0x0630be7f, 0x0ec7cafc, 0x98b8c2ac, 0xcf94cdf4, - 0xf47f506d, 0x615677b1, 0x18b7e9bc, 0xf63b26e7, 0x63b442dd, 0xf4d0425f, - 0xc1c03ffd, 0x5a4d874b, 0xa9aac4fd, 0x4daff2a0, 0x2a293568, 0x562765fa, - 0xc4d939e1, 0x1318f738, 0xfd8ef78c, 0x6fec42b3, 0xcea313c1, 0xe7f7806d, - 0xbec817ed, 0xdf693a00, 0x014f370b, 0xb278bbbb, 0x582d975e, 0x86668f8f, - 0x3339be38, 0xd9da3e38, 0x8b7c7aad, 0x718cdd45, 0xd505e3f7, 0x3fe82453, - 0xceaea1c3, 0xc4d8c919, 0x1baaf9f5, 0xc476cfc6, 0x98f18cdd, 0x837dbed6, - 0x1f18d5f8, 0x03de656b, 0xd37f7866, 0xb66e43e3, 0x07e36202, 0x30a8c679, - 0x29d641ff, 0xf4dfa7ab, 0x4463e41d, 0x0d59f3bf, 0x939204f6, 0xf4d28843, - 0xc2defc15, 0xe34ef93e, 0x1f57db7c, 0xc3cfc1d1, 0x5e24f5e8, 0x59195d6f, - 0xc312dc5f, 0x2a35baf9, 0x4d66fbf2, 0x03be003f, 0x8b6d7f14, 0x08cf0ff6, - 0x1f900fea, 0xa79224eb, 0x807f5c75, 0x93b4cd1c, 0xefec46dc, 0xab6bcadb, - 0xab79af76, 0xf8c68ee4, 0x30c7ae82, 0xcce38682, 0xfa0d3bb5, 0x017daf39, - 0x3151d7e9, 0xc9c7872a, 0xc53093f1, 0xb59847a8, 0xdf743b3d, 0x3cda77fe, - 0xe3d3ae33, 0x7439013f, 0x8ef969df, 0x9f9e4bfc, 0x7f38c72d, 0x9c1dbd88, - 0x678a54c7, 0xfa17ebf4, 0xbbfd6a73, 0x5f04ae72, 0x15f065ea, 0xdcbaf84f, - 0x19fd833c, 0xfbfd2fe3, 0xc17db593, 0x223ae326, 0xa4f38647, 0x7f8027ce, - 0x2cfe8853, 0x9ea9f4d6, 0x6bbdd107, 0x064fe524, 0x31e7e5c7, 0xc4bfbe81, - 0x81f25ddf, 0x963d453e, 0xc56fb927, 0x71ed79f6, 0xc0efda2a, 0xbf1af56f, - 0x3a6fc849, 0xaae35b9d, 0xebbe69f3, 0xfa4bb204, 0x3ada41d9, 0xd024d79a, - 0x9e0d99ef, 0x87e715e7, 0x7beba7c0, 0xeb55bfe8, 0xe7e73c7f, 0xf9f8fb67, - 0xcd1f943e, 0x0eae679f, 0x1c3d5fba, 0x732885fe, 0xd5eb2109, 0xeb8a36ab, - 0x5abb78eb, 0x85edd7fe, 0x25d701f2, 0xf8377d07, 0x84e1c068, 0x1e518b76, - 0x7cb55f50, 0xb664f742, 0x7f0c89b6, 0x8de700b2, 0xd74f237a, 0x8795be93, - 0x5bb2240a, 0x49d97a82, 0x37ae8bf6, 0xb06b5603, 0x2bb5b9fd, 0xaf51eb0b, - 0xc7ecf76a, 0xc7c5a08b, 0x7348e106, 0x9277bb70, 0xddfc4597, 0x5dbb1cb8, - 0x8f3423d7, 0xe80a2b8d, 0x6d2a855e, 0xe1d49d3d, 0x345378a3, 0x104271e2, - 0x7d7afa1f, 0x15e3a5a7, 0x8197bced, 0xd83af51f, 0xaca69525, 0x7ef8ff60, - 0xe7df0866, 0x841f3839, 0xeabbe7d3, 0x0f83c027, 0x0d43f0f1, 0xc75009ef, - 0x04982d7b, 0xfde617eb, 0x6b5c50cc, 0x56e04232, 0x104e3eb8, 0x5d8f5c4d, - 0x07e22e46, 0x58f7ed31, 0x41cf24ec, 0xe5bb707c, 0xe7168701, 0x3f29eed5, - 0xa1390268, 0xcf3e367d, 0xd4c95dee, 0xddad6cef, 0x6f2f4bdf, 0x7496f2d6, - 0xb5e2b17b, 0xf846cdd4, 0x1cbb7f79, 0x47792f1c, 0x8ed063dd, 0x5c51ee19, - 0xb5e41fe8, 0xf98fdccf, 0xf07bd924, 0x7c820407, 0xe5c2dd9e, 0xc34bb814, - 0x43db9bcb, 0xd874adfb, 0xbbfb3975, 0x28fb23cc, 0xcba457e7, 0x5a72217d, - 0xbe3850e3, 0xc4167e60, 0xa3d464a7, 0x83f7f97a, 0xcf1fb3c3, 0x3e039525, - 0x78eb6d50, 0xbf996d6b, 0x7c7286d2, 0x8e50b994, 0x9be65bbb, 0x315d2146, - 0xa219cc11, 0x79f3d61f, 0xf02876e8, 0xe5f20b65, 0x1a10c73a, 0x7751f86f, - 0x1fbc0e74, 0xc613768e, 0x7eec5b7d, 0x0efc23f4, 0xe2072eef, 0x14ef5673, - 0x8cad4fdc, 0x85b5aeae, 0xdf6bef3c, 0x8f89ed06, 0x1fee22bd, 0xf8c03f95, - 0x7cdaf1bd, 0x02cfa9a0, 0x20c855e3, 0x0f5459a7, 0x655ade20, 0x3ef7bede, - 0x5611a5fa, 0xf97bf229, 0x95befd60, 0x536df3f8, 0xfd17d21c, 0xcb93b424, - 0xee1a4f45, 0x16c1b27b, 0xe003ae17, 0x1fbf1077, 0x06c931b4, 0x4a1efffd, - 0xc4d3d3d4, 0x6b8e74a5, 0xfb40965a, 0x8f7fba44, 0xa4fd0b7a, 0x4d17bf3b, - 0x3c2ec8fc, 0xd3e30c38, 0x4e9cd109, 0xeb558fd0, 0x1b1d6ac7, 0x48ffbf94, - 0x8efe491f, 0x141dbebe, 0xe0e7ea04, 0xd735d74d, 0xd841f885, 0x83ffea1f, - 0xa5b48cc2, 0x1f9affc8, 0x7c61f647, 0x7b45dd70, 0xce21ac65, 0xebe0d3e6, - 0x0a3e4748, 0x3ed147b5, 0x7d67b3ed, 0x0cdf57f3, 0xf4e2767a, 0x715e0096, - 0x6e8acb5f, 0x6fe817fe, 0x36b3d81a, 0x8d3ec3c0, 0xf8660e2f, 0x3d4fdc44, - 0xfba05c38, 0x79450fdc, 0xe095aa73, 0x5c5a8938, 0x33cb5120, 0xe5e28c4f, - 0x1eb8620f, 0xaf863cfc, 0xbca837d7, 0x1c88e89e, 0xbdad9847, 0xeb89a9ff, - 0x91f935f7, 0x684fd1f3, 0xedaaf5fa, 0xfc211cde, 0x8e13eebe, 0xdd7dda09, - 0xe3c76f94, 0xfe340bfd, 0xe8873b06, 0xf8abb414, 0x876e9d7e, 0x4d9f6d9e, - 0xf78213f5, 0x2c047bbd, 0x9f904f3d, 0xf148aef4, 0x6f58e2a1, 0x55a5e622, - 0xcb8e4544, 0xf4f0d20c, 0x38a30d59, 0xcfdc29ef, 0xb7bfe6cb, 0x1b25f585, - 0x1d7ba49e, 0xe29f994a, 0x1a1b45bd, 0xc8aebf68, 0x80a7302f, 0xc78799fe, - 0x943a3581, 0x710d116e, 0xb552c5e7, 0xe4139b1c, 0xae1dfc5b, 0x9b25f7d0, - 0x57ea19c6, 0x1816976f, 0x7a823bf2, 0xbfec90a7, 0x3e757ef0, 0x8f4fb70f, - 0xf10d38d7, 0x861b05ee, 0x78cdf217, 0x73217ede, 0x36177cd1, 0x11ef1966, - 0xb2b84c6e, 0x1ec1827b, 0x538445f5, 0x3fa8fd26, 0xf7f80e3f, 0x17f7c485, - 0xe08c3a7c, 0x7bc38bf8, 0x8e018c5d, 0xc433e668, 0xdff326cf, 0xf8f1b429, - 0xef8ff023, 0x7e407652, 0x07f577cc, 0x1fc01dae, 0xfa87fdc8, 0xb9937903, - 0x024d65fe, 0x9c4ce0e5, 0x66cfb46a, 0x6e75f0c7, 0xc1b44c76, 0x679a2b3e, - 0x6b57376c, 0x776b5737, 0xa84a38b9, 0xa164265d, 0xe9fde33e, 0x71951fbf, - 0xffca6dfa, 0xedc310dc, 0x6eaa9fd7, 0xbbf40c6f, 0xd0773b56, 0xefdade6f, - 0xf735ad4a, 0x5e5285e5, 0x1e6fe6e0, 0x09dfc3ac, 0xf601dde9, 0xfcc1e83f, - 0x7ba0df67, 0x6eeff4ba, 0xb432d15f, 0xa954f008, 0x8bb973c9, 0x15dcafcf, - 0x3f418790, 0xae1ce529, 0x827d96b4, 0x5a5df214, 0x22b76f09, 0x2ff06cc6, - 0xffd5a27f, 0x6549c635, 0x1840495a, 0x3652ed06, 0xec24116d, 0x0b577f0f, - 0x66a949e0, 0x93dfd0fe, 0xedcf194a, 0x6fc7db9a, 0x04e61616, 0x9a68d0f1, - 0x5c62a391, 0x85da3135, 0xaa47cceb, 0x50f10eb7, 0xce8051fe, 0xa8fc4c49, - 0xbdbb425d, 0x23d7755b, 0x7078eb7f, 0xae0a6a8a, 0x711fd1a3, 0xfcfa9b38, - 0x30bebe62, 0x4766a8f6, 0xe976eb37, 0x42edc661, 0x5712a75a, 0x3efc308e, - 0xb69c6261, 0xef32244e, 0x37da854e, 0xa327a232, 0xccae24f9, 0x2c76e66e, - 0x2cb4f7a7, 0x3e7c16cf, 0xb1c8f06d, 0xd647df78, 0xbf8480da, 0x26dafe3b, - 0x51fbc453, 0xc3fc359a, 0xf9c59e3c, 0x9cb8f3e9, 0x99dbd05e, 0xe84f8807, - 0x3d3d10f2, 0xd8c1dfb2, 0xff3ef4e3, 0xe97bf8d9, 0x997acafe, 0xc74e4f7e, - 0x69eab77f, 0xb4a6bc41, 0x3708166c, 0xdc7a78da, 0x5ca39f0e, 0xe78d971e, - 0xfb94073a, 0x16873b15, 0xbd7dca85, 0x1cd9f44c, 0xdbafe796, 0xe1887ff7, - 0x5890eaeb, 0x4bc43ecf, 0x8a3adb65, 0xc2d92cef, 0x4067f77f, 0xfe215cfc, - 0x07ee1284, 0xfbe1cf94, 0x4acff95e, 0x7ab2ff44, 0xe5acfbfe, 0xb8f077db, - 0x0b998fce, 0xcb7943f5, 0x0728a10e, 0x8773077f, 0x9f0428b0, 0xca7ee5a9, - 0xaec6bf83, 0x5bd71fcb, 0x718efce1, 0x0e53b462, 0xe87eb8d9, 0xb87c57cc, - 0xf669dc1f, 0xcebb6396, 0xe61768e4, 0xfff8e977, 0xe99b8efd, 0xa77db5dc, - 0xa3658025, 0x8ac939a9, 0xcad70efb, 0x6eabe42e, 0xe9127bd5, 0x5a792713, - 0x78d8fbf1, 0xbe16abbb, 0x58d85a75, 0x3c72b955, 0x8fe30c4c, 0x72e63f89, - 0xf43aa493, 0x24b186bc, 0xeb9daa37, 0x67d7132d, 0x1e7ccc87, 0xf787193b, - 0xb3ee3107, 0xe3878724, 0xf294dc68, 0xca1f9d00, 0x70d3bd38, 0x5fc830ce, - 0x1b7dbfee, 0x2c3fff7e, 0x00284ba1, 0x0000284b, 0x00088b1f, 0x00000000, - 0x7dd5ff00, 0xc5547c7b, 0xbddcf8f5, 0x0dd90afb, 0xdc3bf79b, 0x24280c10, - 0x01049e6c, 0x878424d9, 0x28026e20, 0x47796bc8, 0xd2026c92, 0x6dfad0fe, - 0xe5318316, 0x16d46b6b, 0x882ea945, 0x835ab696, 0xb80d06a2, 0x47d62228, - 0x2d8aa523, 0x2220a5da, 0xfb1b6484, 0x6fcb56c0, 0xec9999ce, 0x0f0d9bde, - 0x7cf9fb6b, 0xdcc98fe1, 0xe6739f79, 0x9ce7339c, 0xb5331d99, 0x228ca8cd, - 0x389aa6a4, 0xfd2d34bc, 0x84e90ee9, 0xf00b9085, 0x8321226f, 0xf121326c, - 0xbd3ca484, 0x582c524d, 0x1c5a7fbe, 0x052627d6, 0xaed84bbe, 0xa0af9686, - 0x84225ba9, 0xa0e4258c, 0x31cc7881, 0x2ae8b484, 0xfd68d947, 0x7b488496, - 0x663b2d13, 0x68db4573, 0x9d63967f, 0xeab4ac07, 0xa33e6398, 0xda4bf68b, - 0x4264c7e9, 0x121230de, 0x8c1ddb41, 0x6dd3ed60, 0x42229074, 0x07891b26, - 0x233d1bbf, 0xc1dfda14, 0xbfb083a1, 0xa6eab797, 0xc37b697a, 0x19d8b220, - 0x9b74ef32, 0x6ca5db0e, 0xe8e921dd, 0x5a48b8f7, 0x513f321e, 0x595b01ef, - 0xcc67cc26, 0x43844ed4, 0xae3d56dd, 0x1ce8c2a7, 0xb05466b6, 0x8fe868de, - 0xe6ed7bd6, 0xfa7e8c4f, 0xbd2fc7fd, 0xbf50246f, 0xc1b47255, 0x37df5bfc, - 0xa9a1c9ce, 0x4932e7e7, 0x613a6420, 0xf0bf36ff, 0xdfa151be, 0x70a6efa7, - 0x76eaf5a2, 0xa32fd2ef, 0xc5a95769, 0x24268d23, 0x8b6bccf3, 0xdefd2148, - 0x74112266, 0x5736dd6e, 0xfbce8d91, 0x0e535dcd, 0x58845149, 0x20f9339f, - 0xc421f015, 0x06b4e19f, 0x3a5225e7, 0x722fce30, 0x10b3fd2a, 0x55ef46b2, - 0x95ddf099, 0xb7eb4559, 0xccf830c6, 0x42e0cc1f, 0x157bec2c, 0x0b80975f, - 0x8c0a7f1d, 0xdce5915f, 0x2454fd01, 0x329bd846, 0xaff99e61, 0xebdc2999, - 0x823d92ec, 0x672b8d56, 0x579d0cf0, 0x79b84e65, 0xe2f1c06d, 0x44f8d963, - 0x7180cfef, 0xefb2f109, 0xf9216932, 0x3873f6c1, 0x1f77e9be, 0x3a864efb, - 0xd7f38273, 0x4d836fe2, 0xe861fac2, 0xa3ac116c, 0xc7cf98f6, 0x0f53ace8, - 0xe6799674, 0xd043e230, 0xeab6cfcd, 0xd5fd1531, 0x5fd88cd9, 0x708f4d9d, - 0x1a780cd9, 0x2c03534c, 0xcc1ba69a, 0xc7850f5e, 0x1f26f39b, 0x7e297292, - 0x20fa316e, 0xb4b7437d, 0x48dfca16, 0xe8b7e361, 0xdf216b74, 0x34859772, - 0x6e1d5e21, 0x376bcf98, 0x6a7e2147, 0x26bd1ae7, 0x9f8fcfda, 0x63de5897, - 0x67fa12f1, 0x72f66bad, 0x22e24768, 0xfe024fec, 0x738c075c, 0x4ae9fdac, - 0x51bf6e79, 0xb7a7dfa1, 0xf027fdb1, 0xe8c6db50, 0x0107ec4b, 0xbd3c20d7, - 0xf024fdaa, 0x8db07f31, 0x17a505d1, 0xcecd7780, 0x3349db08, 0x0102eb1b, - 0xe5568cfa, 0x6d93dbeb, 0xf3044727, 0xd007f035, 0x81620ec1, 0x79f2d679, - 0xeeb9d3ce, 0x6755fd83, 0x50341ff6, 0x0d1f16d4, 0x881f7ee0, 0xffd66b7e, - 0x0164fb3a, 0x0e93ab21, 0xadf62a61, 0x7f7aa861, 0x6f78e56f, 0x7bb69482, - 0x4d4dd382, 0xcbee1b61, 0xb80d939a, 0x19532d9f, 0x231cb35f, 0x133c508e, - 0xdebe43f2, 0x457db17b, 0x9964db64, 0x71e2bdc2, 0xfa44d6c9, 0xaba44fcf, - 0xa36ce224, 0xf5b67dfd, 0x0025a8f5, 0xc82eafdf, 0x37ae98a4, 0x3777ad82, - 0x3b5d3be7, 0xde91c029, 0xcc248c1b, 0x3fb72f7a, 0x01223be2, 0xec386b3c, - 0x1f2e9ebb, 0x17a529fb, 0xf6c1cecf, 0xcf92e8ab, 0xf6eb3d3e, 0xbbbce94f, - 0xcbb44c76, 0x4e4d3640, 0x7c409fa4, 0xa53b7d84, 0x4c99389f, 0x37de2895, - 0x351ebdb4, 0xfcfbb68e, 0x81f3a397, 0xf7cdbf6f, 0xe5e799fd, 0xbb9700f5, - 0x75ecf67e, 0x95e35e50, 0xce304d62, 0x95ffc7ce, 0xdea9fb42, 0x26100f51, - 0xd57cbf4d, 0x74f5a7e8, 0xfbec6dde, 0xa836c1ce, 0xf713f9f7, 0x6ef0075f, - 0xf2c26b6a, 0xc36c4f33, 0x7b3f6bfc, 0x683fdf76, 0x94675abd, 0x799dea1d, - 0xa5e23f7e, 0xc077a5d6, 0xeba2077a, 0x33f6bbcd, 0xe126d97e, 0x1973237e, - 0x2d74131f, 0x9ff3f7e8, 0x2a1b1e2d, 0x16f7c437, 0x833b9723, 0xcb391c98, - 0x994d6ff7, 0xb3d205a5, 0x85cc44cf, 0xfe8dbaf5, 0xcf9868ec, 0x1f174628, - 0xb6d47871, 0x2db831ad, 0xf9fb1ed8, 0x487bee80, 0x9e7d2873, 0x6b4ef4a2, - 0x0050b8ed, 0xeb0afde3, 0x11257ad3, 0x2f37be14, 0x7cc12e38, 0x18354722, - 0xbf9e706a, 0xd574e564, 0xebc5e5a1, 0xe96a3d18, 0x059b0be0, 0x907d8beb, - 0x4d32bbb2, 0xb2603e41, 0xd6ce3e33, 0x6aed5297, 0xd7efd2b2, 0x65d973af, - 0x4f97c78a, 0x4a9c9e1f, 0x211b3ff3, 0x65fe2015, 0x8f39c989, 0x5ba9c705, - 0xd04e465f, 0xd9a2eaf9, 0x11b0497e, 0x07c8b5fd, 0xd7ba31b6, 0xf205bd13, - 0x89f200fa, 0x072e16ba, 0x1279b077, 0x96632073, 0xae59db15, 0x83ce098d, - 0x3058b3b6, 0x29b8c81f, 0x678ee407, 0xc51dca2e, 0x233df388, 0xe4f101f8, - 0xee09cc2e, 0x711d04b7, 0x8c13fe01, 0x7e30b534, 0x4ffb4953, 0x8a4d2e8f, - 0x09a60a2e, 0x16b95883, 0xf2f0b74e, 0x923b451f, 0x3b5e01a2, 0x60f25563, - 0xdaf2be20, 0x6e4cddcd, 0xe91c72bf, 0x08740dd0, 0xaa4ebbe3, 0x6472f6e4, - 0xf70e94ae, 0x5c3a471c, 0xabf8cede, 0xb8d4bdbb, 0x259ba68c, 0xefe61732, - 0x7404f4e6, 0x9bf9a764, 0x7d71a3a2, 0xd9fcebee, 0x39baa7c0, 0x61ef75dd, - 0x4e86f6f4, 0xbcf801e7, 0x36e47db1, 0xf95a0790, 0x113b5528, 0x6f8a6edf, - 0xd67a0493, 0x67a0c3ba, 0x3b1355d5, 0x6ef757ec, 0x081a1fbe, 0x7b7707ee, - 0x2fe872e5, 0x5d9a6e35, 0x992f5096, 0xeef34a9c, 0xfb04525a, 0xd96b652d, - 0xd20ba01e, 0x20ab912e, 0x0ddced5f, 0xab8fafed, 0x2099cbb3, 0x9927b6f7, - 0x47ebfd69, 0xcdfb6314, 0xf4294ae9, 0xb620a9e7, 0x706f2127, 0x9cdb3ca1, - 0xf20ed23c, 0x88daedce, 0x0651177a, 0xb89ca1d9, 0xbea16bf4, 0x6c80b3db, - 0xe3ecc292, 0xcb03923d, 0x08de91bd, 0x3b7a7eda, 0xeddc7fd3, 0x139f1f6c, - 0xa1a911f0, 0xd78c1173, 0x788982fd, 0xbd9d20a4, 0x930a67b9, 0x509a2fb3, - 0x746d9ece, 0x34541390, 0x10568c8f, 0x358e02af, 0xa03a99ad, 0x9966425b, - 0xf8cb1e60, 0x4c0d5a3c, 0x3973446e, 0x9b2f7590, 0x1fbe72c7, 0x78eb4796, - 0xaffbe46a, 0x9b05c995, 0xe0e41727, 0x921e3e39, 0x73970245, 0xe5bae874, - 0xb527dc3e, 0xe2feb34f, 0xdbbc8e4c, 0xe855e842, 0x6c7a5a47, 0x6ca6e3e2, - 0x3301203d, 0xa55ad949, 0x57d7e7da, 0x5d3d5f13, 0x755bf5e7, 0xa8b989be, - 0xfc82dd37, 0x6c91837c, 0x77f7fa97, 0x5be3344f, 0x3cceb115, 0xcdd7e409, - 0xfa3fd416, 0x8720e9f6, 0xb8f4022e, 0x84dec97c, 0xea1670ab, 0x09d3bd68, - 0xede03b56, 0x5a8e1c47, 0xbdafab7d, 0xd19c0f46, 0x4325c9ea, 0x4186e969, - 0x549e0173, 0xa198b75f, 0xa7b68d9d, 0x8fb612f5, 0xf213627b, 0xf7ec26ab, - 0xeb1b68f6, 0xd859d627, 0xcb2e2c00, 0x27c98eb9, 0x7adc3dab, 0x9e85a3d2, - 0x074f28bd, 0x82db33f4, 0xafc7e1fb, 0xbd194b48, 0x01284151, 0x41fdb23d, - 0x5278fee8, 0x3d447a41, 0xf4e0ddca, 0xb647a786, 0xaf54dc5f, 0xd29b3d02, - 0x27a65ae3, 0x4fdb085b, 0xa7232e8c, 0x7c007932, 0x159f542b, 0xefbb54fb, - 0xedf6fd05, 0xefdccbfb, 0x1fb606dd, 0x801c29bb, 0xfce8fbde, 0x9be74665, - 0x48fdd036, 0xfdd137cb, 0xffc214d8, 0x981fe7b5, 0x04079c27, 0x73663dbf, - 0x745f0076, 0x19ab7f6f, 0x47f396c9, 0xc83fcbf7, 0x65de98be, 0x5fb4ca86, - 0xa1afdd33, 0xe0a663f4, 0xea63e6b6, 0xb9113901, 0x8947ad5e, 0x266883f4, - 0xdeb1bebf, 0xa3d24238, 0x55f1c3de, 0x007d73ab, 0x46f41e7c, 0x6324114a, - 0x131bd33d, 0xde00e640, 0x417a47b6, 0x20484e3f, 0xccc2e7ae, 0x67df3f67, - 0xfce29f02, 0xeac51090, 0xff7df2f7, 0x4ff7af29, 0x4b9c869e, 0x3a283f70, - 0x0f2271d7, 0x3b448f2c, 0x172c2f3a, 0xd73be9f3, 0x137cd998, 0xbedecaee, - 0xc18f0429, 0x3e75757d, 0x5eeb37e0, 0x25a97e9f, 0x8b908e38, 0xf981ba5a, - 0xf581fc83, 0xb81a8e54, 0x7e7eeb5e, 0x71d0d33e, 0x7b5fdf04, 0xb482b8a8, - 0x2bfbe0d5, 0x5635c7ee, 0x2522fa02, 0x9d2c4707, 0xe1befd57, 0x088d1f6c, - 0xeafb4364, 0x314dd758, 0x9331dfb4, 0xdfa0fef8, 0xa09ce0ab, 0x0c531e27, - 0xf5e0dde0, 0xd3f9e087, 0x8f7fd618, 0xe991ecd5, 0xd623b8fe, 0x3ded0d15, - 0x03eec465, 0xe5077339, 0x896fb027, 0x4df808af, 0x0147f13d, 0x5d58c79c, - 0xbf4031f1, 0xc9366772, 0xf257fca2, 0x63f7c2e7, 0x84b95111, 0xfb71f3f6, - 0x85799f6f, 0xcaf85ab6, 0x03df85b9, 0x22317afa, 0x18e2e803, 0x513b97d5, - 0x830656df, 0x944bddbe, 0xfc30b6c1, 0xcc0ba457, 0x20beb33a, 0x55663f98, - 0x7a442f9f, 0x6fc30c4d, 0xe214f9fd, 0x09fe8589, 0x627bbf9e, 0x1f5df614, - 0x56ea8230, 0x78833e7f, 0xeb1f7f68, 0x985b7548, 0x30c53771, 0xc84ddb7a, - 0xf7e570d4, 0x0f7671f1, 0xb030fb65, 0x7f02f24d, 0xe1bf5eac, 0x07e532cf, - 0x3eacebd5, 0xe831694c, 0x8f36d56f, 0xc7f3474f, 0xd11f8c0c, 0xc5cdb37f, - 0xeb47b941, 0x0e03c7e9, 0x4b20f43c, 0x2e52e0f9, 0xbc3596b7, 0x13d825f9, - 0x3cc4f5aa, 0xdcb3f69e, 0x4a983cec, 0x2cb33e8b, 0xbfb6028f, 0x25b73bf2, - 0x5c4a5c80, 0x32eccad0, 0xf40d9264, 0x4331c95e, 0x317910be, 0xfa8f4b3d, - 0xe29fe231, 0xe7188beb, 0x82f7c04c, 0x80f504c1, 0x7a45b705, 0xd07c213d, - 0xa5a1e1cc, 0x7eb84f9b, 0x767feda5, 0xfe81196c, 0x739ca23a, 0xdc163e81, - 0xcfc54e76, 0x53ff25ba, 0xad5d028f, 0x649fdab1, 0x433865dd, 0x623bfee8, - 0xc43af3bc, 0x675e4f53, 0xa04cfaf6, 0x87c640df, 0x30eacf60, 0x940a3cd9, - 0xa2cf111b, 0x291a9fdd, 0xe60ecbe3, 0x361e9e97, 0x196be819, 0xde0337b1, - 0x1244b597, 0x033f084f, 0xc3e81805, 0x3f609e7d, 0x3cde3b4b, 0xaddcfc0a, - 0x2c9d23f7, 0x8f105b35, 0x9c7af3ee, 0x74316907, 0x8a7b45f9, 0x8e5123fb, - 0x9e7d60db, 0x9f47c67b, 0x263f491a, 0x7eb8efd2, 0xfdf0edd7, 0xe228c8a1, - 0x4b78fa00, 0xf3a70ef6, 0x832b35ef, 0xeabc2863, 0x460e948d, 0x734e3763, - 0xd243fe88, 0x77fc6aac, 0xcc25f5bc, 0x65d9b967, 0xc2be3904, 0x32a7cf41, - 0x6457c9e0, 0xef8a151b, 0x9185f2f1, 0x45ef8f97, 0x6c7fbf7c, 0x661ff4a4, - 0xe1c7dd1f, 0xa5ea23df, 0x71f27db0, 0x0e7ea906, 0x4a686bd2, 0x943c7ddb, - 0x3e79f3e7, 0x604bd79b, 0x9f7c1df9, 0xeacb9c7c, 0xc5f1c769, 0x3b36fe30, - 0xe015b1d6, 0x8cf9db45, 0x22fb1740, 0x16b7a8bc, 0xfc077e52, 0xea3a6d6d, - 0xedaf94ad, 0xc4d97ac0, 0x4cf58d17, 0x03485728, 0xcfb07be5, 0xcf84148b, - 0x274a52a6, 0xd7b03cb4, 0x04aedb64, 0xa9f02af1, 0x8c7b63c5, 0xc3c9eff4, - 0xd43e9251, 0x61e5428e, 0xa3b30c7b, 0xd27f6118, 0x9e991899, 0x85f10c36, - 0x3e5f2274, 0x608c6ebe, 0xf4fba078, 0x7bd418b5, 0xfba1397d, 0x97c704e5, - 0x0f1f67e0, 0x8ab5e352, 0x5e6de1e3, 0x8d8c516f, 0x007b4fc9, 0x31c7ddf7, - 0x165c7eac, 0x0f424393, 0xcb8703ff, 0xc8549a4d, 0xd5533195, 0x1c4dc5fa, - 0x44c5379f, 0x087ebc09, 0x88f215f3, 0x345f17f2, 0x5e0b0fdd, 0x217f2135, - 0xb0d9031b, 0x63bd68ff, 0x2c0a6e58, 0xe472a58a, 0x18dfaa26, 0x22ddb1f3, - 0x3cefdf68, 0x85d04a3f, 0x3e9c8095, 0x1853d625, 0xe54f7e40, 0x296bae1d, - 0xba437ca1, 0xd037fe34, 0xd694c93a, 0xd8560c87, 0x03a64ef9, 0x208fed02, - 0xe147f40a, 0xb850e7fe, 0xc63bc76b, 0x319fe0e9, 0x96f11e92, 0x9f70f247, - 0x7585ffbd, 0x9cf2ed21, 0x51d1eccd, 0xceb8ffbe, 0xe9fa0175, 0xd42dfdba, - 0x7d198fcb, 0x3096add9, 0x63df46e5, 0xf2c1490f, 0x3d973fc5, 0x762fca46, - 0xe4fd7677, 0xa5eeba66, 0x861db29d, 0x5fe77a5c, 0x7a031ddf, 0x0ec1a775, - 0xdf2a46e7, 0xbcc3d5ef, 0x791e981b, 0x83a6a74c, 0x9f55dfb3, 0x1962d273, - 0x83dea8be, 0x3be09cfa, 0x4adf7e42, 0x5c81577c, 0x461c465f, 0x66b4ff48, - 0xe1420cd5, 0x0eb2c2b7, 0x6be7d1f9, 0xbc1ea1a7, 0x7cb07892, 0x4fe18b59, - 0x4561f2a1, 0xeabf3aab, 0x56fe7561, 0x67df3aaf, 0x2f0f2e7f, 0x32c7a7df, - 0xd94b3e3a, 0xb03fe03e, 0x3d05e4c1, 0x98af5b48, 0x3ca4cbd7, 0x24f813b1, - 0x4760fb95, 0x48e11758, 0x6ebebe04, 0xc5e2696f, 0xe7f57cec, 0x10de21af, - 0x37a8237d, 0x6c6f12e4, 0x63cb7eff, 0xf4238415, 0xe071f0ab, 0x2cb671bc, - 0xc6263afc, 0x10653d0a, 0x8bbe27f6, 0x45e3827e, 0xcfea3ce1, 0x8f98079b, - 0x5d9fdb05, 0x1b9c7e19, 0xa9b1c6fa, 0x7db064e4, 0xfc6b931c, 0xa3e82d1c, - 0x7e127cfe, 0x07a17917, 0x31a5db07, 0xd9a48afd, 0xf906454e, 0x8b63b094, - 0x224270fd, 0x3bb464e6, 0xebcfcfdd, 0x5fb05cf6, 0x083d009f, 0x6514e3f6, - 0x714e9f9f, 0x66c6f7d9, 0xf70687eb, 0x941d768b, 0x43f8ceae, 0x58b2eef8, - 0x6b8e1c6b, 0x57187627, 0xdba2fbd0, 0xe8bb062b, 0x6778ff7c, 0x546ba279, - 0x30f53f28, 0xe85189bf, 0x9c95165f, 0xbc391a25, 0xd42dfdac, 0x95bea8bb, - 0xd3e74c0d, 0xbd23b7bd, 0x04ce24af, 0xbd9ef3a0, 0xff5c33c3, 0xf315fc86, - 0x6259e599, 0x9ba79820, 0x2abfee98, 0x1d599f3e, 0x99d3ef4c, 0xc71c061d, - 0x025b1441, 0x7cd9a51e, 0xd3d4f329, 0xf9be84fc, 0x908e9183, 0x12fe7cf1, - 0x9df0a7b4, 0xd4b253c0, 0x36f30495, 0xbc74b8c1, 0x824de208, 0x5dac69b4, - 0xe4a27481, 0x3079b3d4, 0x0d264f3c, 0x675f5069, 0x9d6ccbf6, 0xd0090674, - 0x985e0fbe, 0xc6fcf2b7, 0x568bbdd9, 0x158b77c0, 0xcf9188f9, 0xe52c4763, - 0x2fe46687, 0xc9b75866, 0xfd1cfbe2, 0x94f53c64, 0x3d8fb829, 0x3bda0943, - 0x02369106, 0xe72c5ae3, 0x1b58b03c, 0x8f9049b1, 0xe0faf5b0, 0x66ce70fc, - 0x2346e8f1, 0x0b19dc9f, 0x677a527c, 0xf285e025, 0x19ff6665, 0xc3ef5ca8, - 0x73e0b773, 0x4d7e7c31, 0x1325cf9c, 0xe2588706, 0xb01ef1c0, 0x40419cae, - 0x49d65984, 0xd44b7ed0, 0x25eff454, 0x7969e000, 0x8abd54ec, 0xd53bc56f, - 0xeab9c4f9, 0x9d4bb27c, 0x3f93d337, 0xcf928be8, 0x16217499, 0xc02359cf, - 0xfce062de, 0xebcf99a2, 0x3d74a408, 0xfd3e71ef, 0xbb13f58d, 0x8eeebcfa, - 0xe3b41231, 0xd0cd9825, 0xde57d53f, 0xcafa658b, 0x97281e27, 0xf3cfc803, - 0xc0f9b626, 0x837cd3ae, 0x7e8bbf64, 0x1b2ab66f, 0x3d5494f4, 0xc76624d3, - 0xf54adbd1, 0x865b7cb4, 0xe689becd, 0x1d7ec1eb, 0xd5b7f30b, 0x49f68d3c, - 0x0247ab13, 0xdc8fe0cd, 0x8366c9b6, 0x81e5717a, 0x8bd046c9, 0x76db1057, - 0xbfbe8612, 0xce86fba2, 0x53c809f7, 0x5e9c48bc, 0xf3290f22, 0x7cbc0d71, - 0xc59dfc07, 0xe18b13f2, 0x65feca5c, 0x3a75e475, 0x90e0eec0, 0x77d62e51, - 0xa16ebde4, 0xcecd65e3, 0xb3bc3b43, 0x0973f99c, 0x3463f7df, 0x905c6afb, - 0x8f3cb1ce, 0x707587e7, 0x899c6ebb, 0x746d6bf9, 0x36666288, 0x8c71fac0, - 0xfc44edfe, 0x5af2fb63, 0xfd07fc12, 0x47fb0795, 0x5829343e, 0x7467dc1c, - 0xbdb37ca8, 0x1bd696a9, 0x87edf7a3, 0xa78e3c7d, 0xa37d3c79, 0xbf9406f4, - 0x628b3a9d, 0x6d7db1d4, 0x861302ce, 0x14b80653, 0x04d07edb, 0x7c904cfd, - 0xbd4c6698, 0x5fa609bf, 0xd147edc5, 0x06ef4649, 0x12a68eba, 0x77b4678a, - 0xd820f9fc, 0x4907e5a5, 0x88e9e001, 0x0739c841, 0x7a15d39e, 0x3a1afb1c, - 0xfd406c98, 0x2a932ffc, 0xd5013bf0, 0xd2bbce8c, 0xbe2116c6, 0x755f2c0f, - 0xe36a3f28, 0xb337e464, 0x6abf32a6, 0x57b35cfd, 0x10ce4092, 0xbbd277e6, - 0xb10a6f32, 0xc43f0897, 0x773206fb, 0x44f39857, 0x4fd31c6d, 0x3b3066ab, - 0xa346fd6f, 0x1d537fca, 0x335eecc7, 0x8c8f26e3, 0xfcc47943, 0x5c7179a7, - 0x46411b6f, 0xe10a9f00, 0xaf504523, 0x81edf4ab, 0x9cba8cf8, 0x8e3999f3, - 0xfdea0302, 0xbe08df9c, 0xf6c41cee, 0xd2423cf3, 0x9367ae81, 0x87ffe406, - 0x7e456f4b, 0x18f11373, 0x951f6f00, 0x310278b1, 0xd55359ef, 0xa71cd27a, - 0x5cf37f3a, 0xf0c51ead, 0xe79dc621, 0x09579752, 0x5aaa783d, 0xfff05e0f, - 0xb9468abe, 0xdd54f89a, 0xe7e02185, 0xc000f660, 0xe873f30b, 0x1bdc6e91, - 0xbebc3f99, 0x388def3d, 0x127767d8, 0x4976cfbe, 0xb2ffd1cb, 0x82115a4b, - 0xaf5ad4ff, 0xb8647204, 0x987dd855, 0x7934e4de, 0xc3df83f7, 0x91128359, - 0x49e3cebc, 0x493c400e, 0xadbe907e, 0x57165665, 0x30b51c41, 0xa45b349f, - 0x16fef41d, 0x65da3e5d, 0x2aaca25b, 0x0da6fa3b, 0x13d4054a, 0x44c558f6, - 0x6e9c6df2, 0xd7779dc2, 0xbafe31c5, 0x71766259, 0x9e333ccf, 0x9cb3e32b, - 0xbc413f2a, 0x9d828e4c, 0x229c6470, 0x63fda3ea, 0x5c95c1b3, 0x44af5340, - 0xd2171197, 0xd11b265e, 0x4fe1a8ae, 0xb476b1f1, 0xce0fc7eb, 0x9cfd3b41, - 0x2fb43c8e, 0xfd844b12, 0xffd8292a, 0xf4dbd99c, 0xdf53a710, 0xdcbf4db1, - 0x7bbba412, 0x8d5cb8e2, 0xaf409124, 0xe7ba767d, 0x7ba7684c, 0x5ffce75c, - 0xa35acba0, 0x2171ed0f, 0x07df8af4, 0x38ab8b92, 0x9cca18bd, 0xf9d056f3, - 0xb46bbcf5, 0x1d19f9c3, 0xe7ffb46d, 0x9da344f7, 0x50455f51, 0x652c6d3e, - 0xec07a47c, 0x9f1d745f, 0xf9e35745, 0x8ad4a360, 0x663ba3f2, 0x6af1d232, - 0x073c01cb, 0x74a56f57, 0x569f2218, 0x6be750ef, 0xdf9e2748, 0x47ee9f6b, - 0x0517c8cf, 0x56ef761f, 0xd4c323b7, 0xcb8f377c, 0x7da77c8b, 0x7d4c0556, - 0x9d8b3dae, 0x8641e9c3, 0x1de8a3ae, 0x2eefb723, 0x008a9db0, 0x7494fb56, - 0xc7adfd31, 0xfb665a7a, 0x2283c99f, 0x6e568e3e, 0xedbd7115, 0xe0bfca3a, - 0xb0f42afc, 0x07f2c222, 0x92721d74, 0x42df382e, 0x7fe84ede, 0x7c084e42, - 0x52109695, 0xa743f742, 0xc9434fe0, 0xed37c050, 0x0489f71f, 0xd8314391, - 0x7dce07bf, 0x9478f8e3, 0xb7203c1e, 0x17b33a3d, 0x6a59abe8, 0x06693940, - 0x9ba69f3d, 0x83ca1724, 0x323daa97, 0x692c7bc0, 0xd6833598, 0x8cee6f1b, - 0x3a513804, 0x3f4a1239, 0xb197c44d, 0x11d1524b, 0xbf457796, 0x848e961d, - 0xc47df33c, 0x74e998f4, 0x054fd0c5, 0x7a687e38, 0xc8e76240, 0xeb1f9629, - 0xbadbfda1, 0x53274869, 0xf30f5789, 0xf1a9b0ab, 0x9d49253f, 0xa3f4a69f, - 0x70c38c0f, 0x1f4e7870, 0x08772ea1, 0xfcd4477e, 0x857c932e, 0xc1f9187a, - 0x5d80efc1, 0x193d7221, 0xd50dfa01, 0x6a1f7144, 0xb8ebe0e9, 0xf26fdd6f, - 0xbf185c75, 0x13b70f49, 0x2bfc4b5f, 0xd3fa969f, 0xeb1bf759, 0x7a10a4e5, - 0x65e2fb14, 0x907f8b03, 0xa9fe655e, 0xe5193312, 0x642afa03, 0x3fb14576, - 0x8cfa05ae, 0x315dd209, 0xcf119eff, 0x19086ce9, 0xa1367402, 0x5327c23d, - 0xfef1e4bc, 0xcbba05ae, 0xe223ea0f, 0xd254d15c, 0xa532be8f, 0x705fd42c, - 0xa47d09df, 0xd26b6a40, 0xb91f0267, 0x1be609a7, 0xe3434f42, 0x512f808b, - 0xda7dc27a, 0xcbaace4f, 0xf026f435, 0x52e5f42e, 0x367480d2, 0xea60a75b, - 0xf2855cab, 0x5b32dcb5, 0xacdfed0f, 0x0936f462, 0xea0b31e8, 0xdca5e9ab, - 0xe96bceac, 0x0ba88e91, 0x9f4b571d, 0x10dbd103, 0x5f2137a0, 0x6f4d2f63, - 0x75bfe3d3, 0x7f1e9b7a, 0xd2d37a11, 0xbb5fe099, 0xa0e56c22, 0x4b57d73f, - 0xde0a0f28, 0xf904d61d, 0xa89975e1, 0xb68aef4f, 0xdf5d7ea3, 0x3b0bcac0, - 0xbdc4321d, 0xe5e3ad64, 0xc872ce99, 0xe5a7afd7, 0x23a2ebb4, 0xd8662e2c, - 0xef3cac9d, 0xadd786ae, 0x587867a0, 0x6f3f97fb, 0xb968a396, 0x2fb799b7, - 0x7c872d6d, 0xff6b0b7d, 0x46a9f819, 0xb79a7c43, 0x7d5fbe09, 0x1d9da66f, - 0x3efe99ab, 0x9777af91, 0xd8ebdcf4, 0x5bb595ae, 0x883cd075, 0xe99ff9e0, - 0x75f1d7e5, 0xd6cadc4e, 0xfae27719, 0x8ba50aa9, 0xea0f0115, 0xb574a76f, - 0x06dfc8c5, 0x4a973f38, 0x4e9069ad, 0x5217eca1, 0x22ded987, 0xcc7e650f, - 0x7b8874ed, 0x45fd99e2, 0xce20fff8, 0x9f4432a0, 0xd99e27b8, 0x84bd4563, - 0xa0018a18, 0xa8ac4787, 0xa4ff0b5f, 0x812221ef, 0x723587bc, 0xbfac243d, - 0x03564a72, 0x865311ea, 0x5fa53f08, 0x9b8e94bf, 0xc98be177, 0x3f43ece1, - 0xe69ee3e2, 0x7a7d1371, 0x075337b2, 0x880bb174, 0xf4800524, 0x7f41afde, - 0x487e05db, 0xa43ca426, 0xf2caf004, 0xbd7fe35b, 0x853c65a9, 0xef41aeaf, - 0x2196a101, 0xccc9dc61, 0x1c1be24e, 0x53fe7fd5, 0xc467c4f4, 0xff362638, - 0x1e544d95, 0x7e31d123, 0x8fe38736, 0xe90abf8c, 0xd3c73677, 0x2a7f05cf, - 0x9fc00520, 0xddbc70e6, 0x347aa664, 0x8356c3f2, 0x133c6f86, 0xcb6a720f, - 0xbabbfa80, 0xaa57c35c, 0xb92bb8f9, 0x092b7ede, 0x4a727ea0, 0x7a7a62f2, - 0x6bdbd30b, 0xbf50472c, 0xe98479e9, 0x8fc4b5ed, 0xbed68ffa, 0x9d53b359, - 0xe7536baf, 0xf9d5dbeb, 0x8e0f1c9e, 0xaea5b3d3, 0xd58aec18, 0x768bbf0f, - 0x5fc16aec, 0x42fe6abc, 0x5fc67115, 0xed06ba1e, 0x6f98df51, 0x6f4f4d3c, - 0xd0b8aac5, 0xfa9c02df, 0xb22f35ec, 0x613714f8, 0xeb1e8276, 0x4e70f988, - 0xa4791a25, 0x9c7927e5, 0x86fb089f, 0x84792fe0, 0x8e7a23c9, 0x8241d77d, - 0xd7ab5c7c, 0xbd73c4f5, 0x84d39f97, 0xfa0793fe, 0x35d3d00f, 0x4164480d, - 0xdb7f6439, 0x9fc88724, 0xc0668579, 0xee99be73, 0x6c978067, 0x545971c9, - 0xca05f0f4, 0x7bcf8199, 0xbd0d72ea, 0x2dd6f388, 0x81665e9c, 0xff8e8527, - 0xe781c97b, 0x32b7c3ba, 0x5963997a, 0xd1faf487, 0xe22f466a, 0xe7e577dc, - 0x4dfc873c, 0x747d79ce, 0x5ef54112, 0x17491e9a, 0x8fe67ce7, 0x1d1897af, - 0xf87d55d4, 0x82cfe818, 0x246e1c2f, 0x3e10faf1, 0x64cd34d1, 0x934a3b06, - 0xaa839d81, 0xbc5c7fa6, 0x38cf8434, 0x13134a22, 0x88ee5940, 0x5d6cfb47, - 0x669c7aa4, 0x7fbbf3a9, 0x4fd2f380, 0xd44ed123, 0x954130fb, 0x70eb77a4, - 0x6b3edb8c, 0x31527e60, 0x7707559f, 0x7ec3f3ee, 0x08ebff5c, 0x359f953d, - 0x5ac5f792, 0xe4c4b65a, 0x6a7186ca, 0xb3233e74, 0x5fa27663, 0xb03b8c57, - 0xf283d65d, 0x931af8d5, 0x106901c3, 0xefd2e1c6, 0xb5fea1d9, 0x4f8c89d1, - 0x2aeb11df, 0xca0f8848, 0xa43f614b, 0xc6a49652, 0xc126fd04, 0x376606f8, - 0x5c710bf9, 0x6361be32, 0xb69e7d88, 0x568f1b0f, 0xf5f8c096, 0x61ce29f7, - 0x1da307de, 0xd39f30e5, 0x9a7b8fdc, 0x474efdfb, 0xcce03f31, 0x752cfabe, - 0xf734f4f1, 0x518e9e13, 0xbd4487fb, 0x8ecc09a5, 0x6cd1b272, 0xbf07a8de, - 0x1c6f313a, 0x21ec4946, 0x93c60353, 0xea78602c, 0x6dbd13d9, 0xa5ff8853, - 0xfbf4a12e, 0xd87f9f30, 0xba43379c, 0x31b8f5bc, 0x23df0ed4, 0x0f77f3b1, - 0x089e97a7, 0xeb718a96, 0x0fbf2a12, 0xe799ec78, 0xe5f63c47, 0x13bc8ac7, - 0xc099effb, 0xfe5f6bf8, 0xb84f2c3b, 0xf5d843dd, 0x69f7f207, 0xd0547bfd, - 0x044073b0, 0xfd6bcfb3, 0x3f050bf3, 0x05f9fee3, 0xec2d1f9c, 0x45827e60, - 0x4a9cd266, 0x247717cb, 0x946e73b2, 0x9fe55b27, 0x515e44f7, 0xcba0863c, - 0x3ecef49e, 0x2123f67f, 0xee3aecfe, 0xeb13accf, 0xdf5eaddb, 0xbadf0903, - 0x8481fb3f, 0x6d6cfe30, 0xa08bc3dc, 0xe20b0c47, 0xc18dad61, 0x2dae42ad, - 0xef6f7b07, 0xe8718272, 0xd65adf6b, 0xb5e0f604, 0x2a0b003f, 0xa7d431f2, - 0x079c38eb, 0x53bc575a, 0x9d951447, 0x4251107d, 0x8aec9fe6, 0x4351e551, - 0x4d03890f, 0xb5514ead, 0xaa186f4f, 0xfd643faa, 0x4cf2aa35, 0x9f2abe4f, - 0xaaad72d5, 0x65ad55fe, 0x87f0fcaa, 0xcfd557af, 0xa3074323, 0x0c90ecfd, - 0xb57221b6, 0x3e554ab7, 0xaa2de772, 0x86919ff6, 0xbd69e3cd, 0x79fe42dd, - 0x8aa39d1c, 0x39ce7183, 0xed554b6d, 0x62b6a49b, 0x9f46f01f, 0xbd6893e4, - 0xcb5f1c15, 0x62ff993b, 0x556afb74, 0xd8a367ff, 0x5fad183d, 0xa32e7696, - 0x912ed61e, 0x7efea447, 0xfb8eeada, 0xa8ee219b, 0xf296bfbf, 0x356eda4d, - 0xfe80bf3d, 0x8e6fd5a6, 0x5d3f7026, 0x7461490a, 0x0b0ba5ad, 0x5bbd7fea, - 0xe627b465, 0xc687ec91, 0xc40cbc23, 0x5fc7f4ab, 0xae76612f, 0x76ada7de, - 0xf559ff88, 0x47a432d6, 0x2e9a9253, 0x5d351422, 0xd3508e44, 0xa6aed585, - 0x6a25c183, 0x3dc2d03a, 0x0ba6a1da, 0x43ffa7e2, 0x2ae02de0, 0x553b1ee0, - 0x785a374d, 0xda0093e7, 0xc95eddd9, 0xfc6123ee, 0x70dbede2, 0x1fd2975d, - 0xf86a89f5, 0x34701c16, 0x2c6e1059, 0x61e84cbe, 0x68ffae26, 0xaf4213fd, - 0x7ae44b89, 0xf847ef15, 0x0f259a17, 0xfe7d51ea, 0x865f12c2, 0xa7f4132f, - 0x44ecc206, 0xf0c4a4ce, 0x3efc4676, 0xc0519d90, 0x2620f675, 0x03886b2f, - 0x882be1ed, 0xc9ddf90b, 0x3ed15bca, 0x63f2cab4, 0xad9ebbf4, 0x35527a62, - 0xbf9f22f1, 0xaa02b8e2, 0xfb109287, 0x528e16ab, 0x02b3e487, 0x20f2e1bf, - 0x79087485, 0x1378c2e0, 0x62e6864a, 0xad471f95, 0x30df82e7, 0xbd097f84, - 0xe0278c57, 0x189af829, 0xe41a44cf, 0x1a17d824, 0x6846473e, 0x3b6a48fd, - 0xe0f3b08d, 0x22fe2160, 0x44265dad, 0xe9916e0f, 0xcc90f238, 0x57f14226, - 0xdda07360, 0xce7488af, 0xe625ef87, 0xc2bd26b6, 0x935713ed, 0x80c4fb3e, - 0xfe12eaf2, 0xc91e59e8, 0x7f6668ff, 0x6bf0b43f, 0xf89fe5d3, 0x5e3c6d03, - 0x55ef1052, 0x078f0f2f, 0xa76fea7a, 0x857d1fb4, 0x02eb23f6, 0xc3f6a1b1, - 0x9206fbbe, 0x1373d71f, 0x424ddc71, 0x693710f4, 0x133f3c9b, 0x4e54c4ec, - 0xecca4146, 0xab5da458, 0x8ed1eb07, 0x012ba3ac, 0x2121afba, 0x60ccda7e, - 0xfee5e639, 0x74371179, 0x42e27d29, 0x3fc78da2, 0xc22778b0, 0x5f38a0f9, - 0x139e740e, 0xcf701471, 0x2221fc16, 0x9139a84e, 0x4973839f, 0xf74ff42e, - 0xb444a6db, 0x29fdd01f, 0xbec7ee85, 0xef2c22b8, 0xeb351fb7, 0xb2147117, - 0x42ed10b5, 0x7bd742cb, 0x7a10f019, 0x3ea86fcb, 0x1234f780, 0x0dd7a615, - 0x0381f63a, 0x553b0b8a, 0x46f59e71, 0x7b01807a, 0x8e3c8bc1, 0xafad4daf, - 0xe3c89b3f, 0xe739f893, 0x181af052, 0x4eee3c1f, 0xf532e3e0, 0x27771130, - 0x7f42f8e0, 0xc151efb8, 0xd8bcefb5, 0xe13df707, 0x72e02ee0, 0x29f3a8ae, - 0x3d6c97c0, 0xeef00092, 0x83ee7288, 0xfd47e9fa, 0x705d24a7, 0x1772155e, - 0xb6f6cbc6, 0xcf3f78cb, 0x5bc5813d, 0xc8c8f7b9, 0x4c3bba1a, 0x6ead37e8, - 0xc2f51d7f, 0x68ca46ae, 0xa6761ea9, 0xbfa90e91, 0x0340bd88, 0x47ce81ef, - 0x681f3d62, 0x75e22fd6, 0x7f7f3ae8, 0x3efc3809, 0xe42a1c1c, 0x9ee18351, - 0x919c5f57, 0x1551903e, 0x75da1f42, 0xb0f4e66c, 0x013cef56, 0x4cef1dfd, - 0x55fd0cdb, 0x53071dc8, 0x24eb3e00, 0xd1357fbc, 0x26cbeec4, 0x2574fbf3, - 0xdc3b06fe, 0xb34a4e37, 0xe1a9fde0, 0xe09d91df, 0xdd78fe17, 0x4f70316d, - 0x5c3ff44c, 0x4efde1d2, 0xe4fb9e42, 0x57f0428e, 0xa26fb02e, 0x162685b9, - 0xddf99197, 0xe5165f48, 0x891aaf23, 0x61a3f619, 0x6bde0368, 0x68cb4409, - 0xc9938cb7, 0x313ba024, 0x561f716f, 0xfafb877c, 0x7c52ef70, 0x2814d89f, - 0x0ed34b58, 0xdd620f4e, 0x0503cb13, 0xfc20960d, 0x16a65c45, 0x3c385b3e, - 0x66c6f1dc, 0xcdbb17d0, 0x52c9fce2, 0x9f23d362, 0xfb666759, 0xe255d8e6, - 0xc2b3edfc, 0xe11dd4b9, 0xf6063c18, 0x7932fbdf, 0xb17f2692, 0xe3470639, - 0xc7d415fa, 0xbb58d9d7, 0xbf071e6e, 0x44b2a3ee, 0x6f8e5f88, 0xa66f1f0a, - 0x5c73b124, 0x8beff72d, 0x1f7ab5ef, 0x42d58dc6, 0xf04176bc, 0x6bc695fb, - 0x01fc788b, 0x27ad10e1, 0xef78d1fa, 0x7ab179dc, 0x0e4bfcaf, 0x3ebebe7b, - 0x0fe22749, 0xcf4defd1, 0x0be3615b, 0xf9d8934b, 0xe807182a, 0x7dc37bc7, - 0x4a7b85f1, 0xce45c913, 0x0ef3eefb, 0x889fdc55, 0x9f9f7737, 0xfd7e7184, - 0x29fda5fa, 0xe15c6096, 0x92dff040, 0x86e5e6c8, 0xd082bf78, 0xdefb0aef, - 0x8f1c4e37, 0xc147f3df, 0xbb45fd3e, 0x7feaf78c, 0x75374871, 0xd779987b, - 0x5db83127, 0x7dc7af13, 0x1c47d233, 0x2f8cc2db, 0x35fb89ea, 0x76aa9ee2, - 0xfccbbb7e, 0x10fe608b, 0xbc6e1c47, 0xc48e9ca5, 0x30c777bc, 0x99f7b87c, - 0xed059ef0, 0x77bde317, 0xe257f8c7, 0xf1a9b0be, 0xd7b73b7c, 0x9fdebeec, - 0xa6bcf781, 0x40c33b31, 0x728de0f4, 0xd8f504fd, 0x4a65699b, 0x06fac53f, - 0xffb216c9, 0x410f452e, 0x7854ebb8, 0x23770fed, 0xfbf457e2, 0x4fbe61f9, - 0xe702c389, 0xbe5c25b7, 0x8351d92d, 0x1f38affa, 0x8cb0fe7d, 0x139f17f1, - 0xbcf927e6, 0xcff3c255, 0xeb211752, 0xf95a1f29, 0x88334164, 0x844925b9, - 0xbec3175c, 0x46e909df, 0xf97c9fb5, 0x87ecfdbd, 0xaeae5424, 0x57280d20, - 0xdd58fe56, 0xfbdc9aae, 0xb49fd067, 0xdce1fbfe, 0xb1d6272e, 0x479e8939, - 0x2629ef40, 0xd61f20c5, 0x3185f93e, 0x1f78194a, 0x777ca69c, 0xaff81e98, - 0x46aed319, 0x48bfa61b, 0x44963c72, 0xc927b7f1, 0x9ed20db5, 0xbdff59f7, - 0x7e4cbdb5, 0xb9438d6c, 0x2efd64d5, 0x087975f2, 0xc0f7ebe3, 0x1e14093b, - 0x97d31326, 0x720d7412, 0x5e2dea14, 0xf1e387a4, 0x6266aa6b, 0x74049ede, - 0x29cbf71f, 0xefce3153, 0x800e9197, 0x4752a6f7, 0x3625d81e, 0x997bb255, - 0xb3f31366, 0xf6317f7b, 0x0c837035, 0x0cbfbb6b, 0x8eb6c1ce, 0xf7b03efd, - 0x7cfee8b4, 0x5a57e210, 0x8bf163ae, 0xfeff3a09, 0xe2f190d4, 0xe049bd23, - 0x691f8f87, 0x388f38c4, 0x21af34b9, 0xcdca5e24, 0x9edbd171, 0x1ec27685, - 0xb61bb083, 0xa8bde045, 0x8183a1da, 0x18435c8f, 0x1bdc459e, 0xdf5421cc, - 0x8470a2ed, 0xbf914ba0, 0x19f24da6, 0x12fdf0a2, 0xded4e3f4, 0x0f984be5, - 0x7ae7ea72, 0xf98983f4, 0x5c9abdc5, 0x212efe06, 0x364be69f, 0xfae34766, - 0xfe223cfc, 0x5cd97f31, 0xb8f3274e, 0x923f3f1e, 0xb1297bc1, 0x5bbb4067, - 0x474a24cc, 0xf2fcd4b7, 0x675c22b6, 0xf41a218d, 0x19f7e105, 0x6f08cf58, - 0x653f72ff, 0xa58df765, 0x72743640, 0x62e7c286, 0xf9c030fb, 0xdd9b3bb2, - 0x88c323bb, 0xee8cfc03, 0x81b7c37d, 0x8834c27d, 0x7f29aff9, 0xa3e49732, - 0x73866d5e, 0x44afadd4, 0x2f22f8f0, 0xc8ec4fbf, 0xfa9cf883, 0x8c7cb4aa, - 0xc01a3913, 0x0dba3777, 0xc7dc0cfe, 0x5448ef94, 0xf2da0e36, 0xb87a19fd, - 0xf54299af, 0xd92f9a35, 0x0fcb2f72, 0xd1d4aff5, 0x4f2d92fc, 0xfdd3d0cd, - 0x7fc6bee1, 0x5b35f20a, 0xbe7cb176, 0xf34ca57f, 0x655e5bcd, 0x4960e1f5, - 0x2dc1ec09, 0x68786707, 0xb9a267ff, 0xf1fbb7bc, 0xe5fbb59e, 0x3b50bae1, - 0xe332636b, 0x9db8675b, 0x59264cf8, 0x1ef0055c, 0xb2febe11, 0x5a0f1d64, - 0xac54c569, 0x4927b457, 0xf325dbe1, 0xf7e56e71, 0x924627a3, 0xb7e60896, - 0x3c5144f3, 0x8e18e81c, 0x93afc77e, 0x6e9e9862, 0x38fbe3f3, 0x4f011fa2, - 0x77189fd1, 0xe067c835, 0xac789acb, 0x3f8664ec, 0x1c46ce3a, 0xdd839867, - 0xcb4aae2b, 0xbc51fc03, 0xf4de39e9, 0x8dbbfcec, 0x1bf68fcd, 0xa0728b9d, - 0x07f8ec00, 0x33f5a2be, 0xd2d6f383, 0x93324149, 0x3136b72f, 0x3a206b7f, - 0x6269e90b, 0xa5677f24, 0x668ebd50, 0xe4c6870e, 0x466f7e68, 0xc2512bc0, - 0x1c389a71, 0xcf78fcd3, 0x5dd74af2, 0x775a1ff1, 0xf01cbe08, 0xf681ca5e, - 0xf5b3b7ab, 0xcd7bf0c4, 0xd4188cfe, 0xf557eef7, 0xa6836677, 0xb8c1097d, - 0x164c7736, 0x8227bfb6, 0xd93bf198, 0x332ed7de, 0xa0ade997, 0x2c778acf, - 0x123ae788, 0x7bec47ea, 0xc58da2af, 0x39d70667, 0xd3af90a3, 0x6369d7c6, - 0xe8aaf4eb, 0x64091c95, 0xa7f6b6cc, 0xf7f83ee3, 0x9f2a37f5, 0xe7daa7f7, - 0x7d83fae1, 0xd65e103d, 0xd6f93a73, 0xa9e622f0, 0x9c1f6781, 0xf013f335, - 0xed8dfd84, 0x52e9a946, 0x5926b3cc, 0xfb35939c, 0x8e1bf33b, 0xd5daca57, - 0xb9e2cedd, 0xeba6a289, 0x3a99ddba, 0xed102b88, 0x1027c16a, 0x3dffb41f, - 0x89edcc9a, 0x806d2469, 0x93c7c4f8, 0x0ddac28b, 0x9cf6bbf1, 0xe2cd13d8, - 0x8af6b5d5, 0x277b789e, 0x9cf4afdc, 0x8c0aef63, 0xc06fd8d3, 0x259cf4cf, - 0x5f282ed8, 0x9c73f9d4, 0x3fb7f63f, 0x7e603205, 0xe7b2a685, 0x47d53b15, - 0x7e431cb6, 0xecb8385d, 0x7f9a4cb6, 0xc88ff935, 0xcb530bcf, 0xfca4c8be, - 0x9fb27f7c, 0x7d9647e5, 0x5bf21431, 0x44feacfc, 0xefc0f3c7, 0x633fc789, - 0xaf507252, 0x41592d78, 0x3ae5c9b8, 0x02647402, 0xc7ae8625, 0xe309aaf4, - 0x075c04f6, 0xba4d0b4a, 0x6ff77086, 0x07a3eedf, 0x812957e6, 0xf3b0153f, - 0x5f803b71, 0xf403b2af, 0xdf7bb144, 0x8eff7b3d, 0x483e5df7, 0x1e027576, - 0x16bb23ea, 0x5dfcd265, 0x1fa09f91, 0x3dd0724f, 0xc515f601, 0xf9d01646, - 0x9c9b5d4a, 0xd5913fa0, 0xe11eb376, 0x745eedca, 0xfc28178d, 0xf3f7d95e, - 0x61b2a5ef, 0xb18f309c, 0xefd40f9c, 0xe06ff2fb, 0x633fadf7, 0x7af983b1, - 0xdb96c76c, 0xdb1aff40, 0x4c97f6f1, 0x39fbb30e, 0xc163de62, 0x97bf49ae, - 0xfe709bb4, 0x5eae3b63, 0xfdc7f501, 0xe80b23b6, 0x5f31c264, 0x9e85b013, - 0xaaa52fbd, 0xcf90e5ee, 0x39d71a2e, 0xc04ddfa0, 0x54aa53e3, 0xf478460d, - 0x857c7832, 0xf1dd67f1, 0x68fd9b87, 0x7fdf54fc, 0xfa3afaa2, 0x20c97b91, - 0xc433f83b, 0xbdad7a7d, 0x5d2568f4, 0x213efd1f, 0xa2106740, 0x6f3c4f4f, - 0x98248ca6, 0xaad1252f, 0x5939b97c, 0x96c2bf55, 0x929f2aa9, 0x7caab574, - 0xcaa7929a, 0x56311f4f, 0x7b06ff55, 0x637f2aa9, 0xfd5534c9, 0x2aa5474a, - 0x536be79f, 0xd4382fd5, 0x423f2eae, 0xfe43c064, 0x90ebfb51, 0xa0749d16, - 0x74f8b5d9, 0x8e90ebc3, 0x87030bfd, 0xed7c5ed6, 0xe1d7b6f9, 0x6b17b0bb, - 0xfb0933ef, 0xc5b2cdf1, 0x276f0c6b, 0x0567d24e, 0x75901fdf, 0x18d33eec, - 0x94eaebab, 0xa67de0a2, 0xa62f6089, 0x7c58a848, 0x00e347ee, 0x3d980b4f, - 0x062028ed, 0x68adbee3, 0x686a3c87, 0x2c0fe678, 0xf81d200e, 0x5cc084de, - 0x9e27bad5, 0x5dd6a977, 0xe0d56e4a, 0x5f2a8d69, 0x555dbb61, 0x06d24a7f, - 0xe534f955, 0xdd3c1a07, 0x60dfcaaf, 0xd3c1a2df, 0x7e9e0d36, 0xf4172aae, - 0x5aedc1dd, 0x451ec0fb, 0xcefef1d3, 0x75c3c072, 0x8f8803a7, 0x72d6ce92, - 0x47b5d3c0, 0x855f10db, 0xb039673e, 0x0d43e2cb, 0xa3ea43af, 0xf76831e7, - 0xa612635a, 0xb4151a07, 0x1c6c1d6b, 0x46a1e981, 0x75ff7e3b, 0xefa60963, - 0x7d303a34, 0xa62a71af, 0x4c4e8d9d, 0xb0db1adb, 0xed8d73fe, 0xdb162ecc, - 0x3a45def7, 0x75ba07d8, 0x8278377e, 0x77923f17, 0xeecbf003, 0xc86efe41, - 0x37ec45df, 0x25f9a24c, 0xbee844c0, 0x374f29fc, 0x80023aa4, 0xca1c3757, - 0x18f1828a, 0x1e473a6d, 0xa477e1e8, 0x3ea1f84c, 0x37bb909d, 0xd16c9338, - 0x79a66f2c, 0xb3c63644, 0x83a1f84d, 0x2033d712, 0x33a9d04a, 0xf7c806e1, - 0x7772b044, 0x401b84ca, 0xfec6ff0f, 0xff3f4773, 0x61291df9, 0x9ccfe7fc, - 0xd760ac56, 0x70d5fc39, 0x30e3c02b, 0x48396fb7, 0x4d09619e, 0x0679f54b, - 0x0747b390, 0x80f0b7b8, 0xe009b4ae, 0xcfb3a6d0, 0xebef78c1, 0xb7e8040d, - 0x5fe7624a, 0xca95cf51, 0x0dcf41e4, 0x1d4f3c26, 0x605639d1, 0x7814995c, - 0x3dbce00c, 0xdee112a5, 0x00640d63, 0x4e29bcfc, 0x3c0f8f96, 0xf243d926, - 0x079f0606, 0xb6fc6e52, 0x3858f3e1, 0x62913cf8, 0xcfb6fa63, 0x807a0e91, - 0x74a91fc8, 0x3e7ec1d4, 0x0ab8ea52, 0x4d38cfef, 0xad3aff6c, 0x3ed0abde, - 0x139a28e4, 0x9219e762, 0xd1f7606a, 0xd82262e1, 0x71916f3b, 0x39e16b9f, - 0x7be99521, 0xce702748, 0xe789179c, 0xf63a2382, 0xfeb6819e, 0xb3d70e02, - 0xe3dbc283, 0xbd32a616, 0xdd566ca2, 0xfed02f33, 0x6045d67a, 0xe1ce3dd7, - 0x34f58fa8, 0x342ae850, 0x8e70dd3d, 0x1cec9b95, 0x9dbfe824, 0xf2d17f0f, - 0xfb6e3a67, 0xfd68efeb, 0xda45d64f, 0xaed88651, 0xc2ddf841, 0x358c2f2b, - 0xb0b4fea3, 0xe40cbd2a, 0x07ee7ce2, 0x27d5645c, 0x1f503ba0, 0x1727846d, - 0x9af25b97, 0xcac90429, 0x3c234ab8, 0xb69d5525, 0xd5d219a6, 0xc237eec3, - 0xa3b52913, 0x1a833576, 0x70b7475b, 0xff3ff211, 0x5e748dbb, 0x0acbd78b, - 0xfb89cf3b, 0x145735ae, 0xf7e822cf, 0xa23b8f08, 0xeaf3c040, 0xd16f0e22, - 0xd787116e, 0x3fae1489, 0x0b9c90e6, 0x67d63f6a, 0x0b5def40, 0xc01ecddf, - 0xe72ea0cf, 0x4607e3fa, 0xfdf6ae36, 0xe2ee3112, 0x3afe7654, 0x0994a462, - 0x4c2de4fa, 0xfdcee40e, 0xba22aee2, 0x9b0edcfe, 0x1615e30e, 0x7800bdd7, - 0x78e76de8, 0xd8769034, 0x4b3cb34f, 0x221df93e, 0x8f754e26, 0xd2f252f7, - 0x0f2b69de, 0x7e859795, 0xbca87967, 0x96b4092c, 0xf2145c83, 0x7d4ff851, - 0x2f9cd58d, 0x3d3f2037, 0xf31eb8d0, 0x983d1b07, 0xe16c6a1e, 0xcb15b97c, - 0x987c69df, 0xe72f65f3, 0x7bf13bcb, 0x4c5ce347, 0x58ba35f7, 0x9519ca3e, - 0xecc4fb0a, 0x37c4f8c2, 0xf80898b6, 0x4c3b7ae7, 0x77419f18, 0xc68f63c4, - 0x0991fc41, 0xe36a71ef, 0xbe7cb490, 0xf7761e8f, 0x0525377b, 0x1f8be9c6, - 0xc8717d02, 0x9874f4c0, 0x4be05628, 0xe4fe8ff9, 0x0fafd006, 0xf4158a2b, - 0xcdd482e9, 0xac50ef2c, 0x7c2f9a06, 0x8a5de794, 0x22ac04d5, 0x5be421f5, - 0x358a3d87, 0x1f8be682, 0x7b95887d, 0xc7f33a09, 0x06f5ba3d, 0x2259f00f, - 0x51fd801d, 0x449cce6e, 0xd79505c5, 0x5f6007a5, 0x325a494c, 0xcec5f609, - 0x63e90514, 0x00e1b29a, 0xd88fa7e4, 0xfaab87a6, 0x46de4b0e, 0x57165768, - 0x937687a9, 0x846cd6d2, 0xdd879376, 0x376d0faf, 0x8daed475, 0xdf619f90, - 0x74fd07a6, 0xf8b1f027, 0x2f223f60, 0x169f05ca, 0x3ba37271, 0x720f289c, - 0x0f289ddb, 0x66ca5c04, 0xf60dde57, 0xc976facf, 0x663cc126, 0x0a417d4b, - 0x86e89310, 0xbf2949f7, 0x97f53ebe, 0x5db40dd6, 0xc5afe43d, 0x7c370ffc, - 0xa6fbfcbb, 0xfbfc30d4, 0x41dfbe43, 0xfbdc43de, 0x0ef64687, 0x2e1c33cc, - 0xac4b1df5, 0x712a8ef8, 0x7acf4159, 0x97f3cb9e, 0x9fe5a520, 0x7f8bb4f1, - 0x70e7407f, 0x52ab38c1, 0x3fb21fb9, 0x6549a87f, 0x8f735ffb, 0xce728064, - 0x6d52ea1f, 0xea3cf7aa, 0x76bfbb08, 0x6d3b38a9, 0xee36b89c, 0x3b693564, - 0x1fecc8e8, 0xf70b526f, 0xc7fab2dc, 0x6a788b7f, 0xdf781c6d, 0xe3106ab9, - 0xd78173a7, 0x496eba50, 0xde4f901d, 0xdc38097b, 0xfd0e0e1b, 0x9c5843d6, - 0x2438bf7b, 0x5daeef1e, 0xb3c57117, 0xfc798d77, 0x827d76bb, 0xafaffa2e, - 0xcf5fc195, 0xbbf54fe0, 0x157e60c7, 0xec04ad8b, 0xe7fca156, 0x3fe11777, - 0x6df67e5a, 0x179bc9f1, 0x65bbe1d7, 0xf3d8f861, 0xb898f8e1, 0x854dafcf, - 0xf3f70a9e, 0xde121e20, 0x7e738239, 0x1f6ba265, 0x1653d3f4, 0xce0e9bf8, - 0xddec71a1, 0xaed183f0, 0x325df0fd, 0x1106b8b2, 0xe75a7c97, 0x6de815f9, - 0x19fa3def, 0x106eb3f2, 0xbc8f7416, 0x97a0f341, 0x7ce6c3fd, 0x4647e013, - 0xefa18df8, 0x7f140f8f, 0xff2e1bfb, 0xdf6ca7fa, 0x9ed43889, 0xa0665f6d, - 0xfb12eefd, 0x54782062, 0x70fde3c8, 0x24b7a43f, 0x9767e512, 0xdef07c44, - 0x02695771, 0xe95d2dea, 0xdfa43d46, 0x2bb8b9f6, 0xd7fb1b3d, 0x92bb8f9e, - 0xdc6ccc4b, 0x7d2153c9, 0x2154f92f, 0xf0dfbdc8, 0xa376cbf8, 0xb03de0a7, - 0x408d8f0f, 0x928dfeff, 0xa0e010bf, 0xbd77573d, 0xc94ca0b5, 0xa6be7fed, - 0xeb049beb, 0xbbae3dab, 0xe95dbe1b, 0xfd76bb79, 0xb9c408df, 0x15ff5b8f, - 0xaeeff781, 0x19ddfcfc, 0x5e80ab93, 0x12026ae1, 0xf545d319, 0x54bf9a09, - 0x8939d6fc, 0x4333d39e, 0x6f25e5ce, 0x9e2e38b3, 0xfde7cf6a, 0xed5c09de, - 0x960dc751, 0x5e308afa, 0xe147f645, 0x7b1d60bd, 0x73c4436f, 0xf3cfc9bd, - 0x243ebcf4, 0x9d70ed0d, 0xfaf3aa19, 0xfa2d1f1d, 0x0881f21e, 0xa678ef8c, - 0xcc3c44fd, 0xf19d8ff5, 0x0945793f, 0xedbd77d2, 0x9df4246f, 0xbdf5dac0, - 0x86d77caa, 0x7056fbe0, 0x5ff6ab1f, 0x2a25ca32, 0x4f105ac7, 0xdae335e4, - 0xda4af910, 0xef07dcfe, 0x55df94d1, 0xbe50c002, 0xd074cf36, 0x3cfc9576, - 0x8de44844, 0x92aeda0e, 0x67891f9f, 0xe78f2b25, 0xb09f3df5, 0xff28ba7c, - 0x7fac4ce3, 0x1c6fe895, 0x79164f2b, 0x22d5dfde, 0x9623789f, 0x25f68a67, - 0xc6239f2c, 0xaded64af, 0xade4feac, 0x7a099cff, 0x33f7e08d, 0xe09cb8d2, - 0xfe5152ef, 0xba2b4cef, 0xba8ebc68, 0xf107cb9c, 0x1dc5550e, 0x85df22d3, - 0x6126dc7d, 0x9ded61ec, 0x9fe7b406, 0x0dcb698d, 0xe22f2fbd, 0x56e59c7a, - 0x7baaf38c, 0x9976f871, 0x1e813bc7, 0xe9fb9cb3, 0xfa0b642b, 0x65ef7a61, - 0x3d207e7c, 0x97fae570, 0x57ecf855, 0x46d3dfce, 0xef1d2547, 0xf1130fdc, - 0xd619027e, 0xee02f189, 0x27c44934, 0x116abde0, 0x45971757, 0x8e7e701c, - 0xbd82297b, 0x13b27aa7, 0x97caeff9, 0x6ebb7d98, 0xef28ebcb, 0xda0aca96, - 0xea1ebe97, 0xe9f0075a, 0x2f77b2b6, 0x87dfae57, 0xc531f4fb, 0x8160fdc6, - 0xbcf0a151, 0x3dfc3fb3, 0x8517f169, 0x3ffcbabf, 0x5dad7f0c, 0x5fd7dc5d, - 0x7ff1857d, 0x07e656dd, 0xfd3c73b6, 0x7314a749, 0xf0023d78, 0x33a2b73a, - 0x20865a3b, 0x778c4eee, 0x29df90ab, 0x6f56f382, 0xde009583, 0xdccea5bb, - 0x5fe0c30f, 0x9f38ae7b, 0x69715441, 0xf7c3fb3b, 0xf7d04be9, 0xfa4dffd3, - 0x8dfbd44e, 0x1f1bf076, 0x15e5ef65, 0x18c9fe77, 0x4ef41f1a, 0x0f073b1a, - 0x317e676e, 0x2c171711, 0x713c32b7, 0xd55d53ff, 0xffc1e33b, 0xc4c3f624, - 0xfe06d248, 0x76d74a04, 0xa076d74e, 0x41bf416b, 0x176d143f, 0xfa41be06, - 0x912e2c25, 0xfdb7e9c3, 0x25e1fae1, 0x7fe1fae0, 0xa9bbae13, 0xdbfe8c3e, - 0x4ed02217, 0x3ff385a3, 0xbc055c38, 0x0e2fd323, 0xfff4c8e7, 0xd3239c0c, - 0x439d9515, 0xf9207bc0, 0x988fc5a4, 0x5a7d9877, 0xe9f64df4, 0x4f9c1923, - 0x8f18fde9, 0x4c7bc5ab, 0x27bc3f7a, 0xef1c5fa4, 0x30fff2ea, 0xd370b5de, - 0x9fdcb5a6, 0x985efdab, 0xfbbf203e, 0x7ff8e056, 0xb0b04fcd, 0x7caabf61, - 0x54b7faf1, 0xef3c4be5, 0x415f965f, 0x5bfffbd8, 0x57e105fe, 0x2afcf998, - 0xb51ff81d, 0xc43741f2, 0xc7a023f9, 0x7afe5f1b, 0xf93087d4, 0xb78c6cea, - 0xe5af8dba, 0xff7ff18b, 0xbe947be4, 0xf66068be, 0x3ffb63d6, 0xfd392837, - 0x79e165e9, 0xd084711d, 0xeff5c2d9, 0x5acf401b, 0x54fbd848, 0xa60ffada, - 0xc6307b33, 0x30be5149, 0x710c4cd7, 0x9dcc1f94, 0xcf4beecb, 0x0c630705, - 0x2d173ea6, 0x3e27a99f, 0xd2bb8f78, 0xd099f7a2, 0xffbea9ef, 0x75efe26e, - 0xd558b893, 0x21d9783d, 0x9cdf9c63, 0xbd2fe612, 0xf786d2c5, 0xba1de787, - 0x60f7dceb, 0x14f46f2f, 0x7177b8b1, 0xbaf7f0ff, 0x3e83f12b, 0x9c2a7a08, - 0x5fee24fb, 0xff40635f, 0x2addb6ba, 0xca669fbe, 0xd9a38b12, 0xc533e2c3, - 0x3beba4fe, 0xf767ca64, 0x48f7e060, 0xbe0c1b2a, 0x67a0b9e1, 0xbb3d47ef, - 0x2e4364be, 0x927eafe0, 0x1b94dc74, 0xafd4ef3c, 0xd7b60bff, 0x7a6d67f2, - 0x4fd5f6b9, 0xbd210f1a, 0xb1d17388, 0xb5e61f46, 0x1305d6f6, 0x93fd17ff, - 0x6de2ff63, 0x57dc7482, 0xd0c70f8e, 0x3b1bfb75, 0x827b2dff, 0xbb0823b0, - 0x214ed682, 0xbf7888f8, 0xe36e97d2, 0xa296b2ef, 0x59e883df, 0xc1edf82a, - 0xd7f9fcfe, 0x27d717e9, 0x61ffe5d5, 0xf4b97cfe, 0xe4c49b5f, 0x8fee96aa, - 0xed0cfd56, 0xb5be82cf, 0x6200bff4, 0x0bf8e852, 0x27bc25ea, 0xab55773e, - 0xcdf49c61, 0xe5b57de9, 0x9b830664, 0xb15c2e46, 0x3c78503c, 0x0be78c87, - 0x0ec6bc93, 0x87810f76, 0xefd5d3af, 0x48bc5303, 0xab971719, 0xfafff2ea, - 0xa2e4e039, 0x8917266f, 0xcb489f4a, 0xe56eb7e8, 0xfe56eb12, 0xb90eeb9b, - 0xd648b4a7, 0x40e3ef05, 0x81c435fc, 0xfdd978f6, 0x56ccead4, 0x5203ddfc, - 0x7e028812, 0x995eeb77, 0xde8e9efd, 0x790e4fa1, 0xf88bad3f, 0x5c7a003e, - 0x3bbd9e35, 0x769b8da4, 0xd5ea78f3, 0xbf78dd96, 0x9a0efb51, 0xf376cb88, - 0xa1efb4fe, 0x9de2f689, 0x687bed03, 0x1c783253, 0x67c93e76, 0xe7172971, - 0xcf20dda3, 0xdd35fc43, 0x5da2355f, 0x4ac7c6e1, 0x05a4f3ee, 0xa32732f1, - 0x9799df1f, 0xa3be7171, 0xd32fff2e, 0x81dd6caf, 0x94aed8f7, 0x3a64477e, - 0x827f40dc, 0x9bf1f72f, 0x6fc84c57, 0x3df33bc4, 0xf7c19e6b, 0x24be7a87, - 0xd4bd97e8, 0xbb13e33b, 0x09c435d8, 0x564dbd27, 0xc771d78a, 0x1baf683c, - 0xf785c47b, 0xe3bcc776, 0x927f8880, 0xc329c077, 0x233e85bc, 0xff209bf4, - 0x78d9f7e2, 0xf2e5d59c, 0x37f52bb9, 0x8cfca7fe, 0xb75d5ee2, 0xbf0457c1, - 0x13d9e0e7, 0xa103bf81, 0x1993ff9d, 0x93be8bba, 0x7ae511dc, 0x8b34f012, - 0x5ef109cb, 0xdecc8572, 0x94edef49, 0xeeb85ed1, 0xabfb7e7f, 0xdb4b9547, - 0xbd6dea15, 0x2265cf61, 0x7bb1d7ad, 0x0ae5f92d, 0x79c249c6, 0xc287ec0d, - 0x7fada89e, 0x297b294a, 0xe35bed03, 0xdeda3df1, 0x067cd987, 0xfafd57c2, - 0x603f8e00, 0x7ebf1f39, 0xf42d916f, 0x19f3959d, 0xdb43e77d, 0xdf107329, - 0xff174b97, 0x332dced7, 0xa891e265, 0xbc91cd7c, 0x4c25ef4c, 0x3a405dff, - 0x02445d31, 0xbb08ba98, 0xd894b0cf, 0x9c4e5d31, 0x5c55ae98, 0x3718195d, - 0xf8c04814, 0x39ff17d3, 0xdce6e80a, 0x215ae375, 0xf2dbf146, 0xbef56923, - 0xbd853c9e, 0x3fc2f497, 0xd9f4077f, 0xcb863ff3, 0xa2471be2, 0x1848641c, - 0xa57bd33f, 0x54d7bb32, 0x17dc5df2, 0x325dfde2, 0x96e1f989, 0xfee26627, - 0xc4cdf209, 0x826f826d, 0xb8e7393f, 0xdcc3c58e, 0xc67be12a, 0x6e1d7eed, - 0x99159cb1, 0xb9ddf85e, 0x3cacddf6, 0x2bda2ea7, 0xd8ce7cd1, 0x26be5608, - 0x4ff70bda, 0xee3f1216, 0xfb70c5cb, 0x4bfb8644, 0xdf8a2f8c, 0x8227a00b, - 0xbf6d12a1, 0xeeccc3a2, 0x30ff1051, 0x70b9ffe0, 0x4f170a7e, 0xf1f18433, - 0xbf1943d1, 0xb6a65d1f, 0xe5e50c87, 0xdf6529f7, 0x0cb47807, 0x810d6471, - 0x9b9d31fa, 0x3b042c1e, 0x9f808e90, 0xb7b1b3e6, 0xb4535fa3, 0x1b29517b, - 0x959ff501, 0x67bfbc58, 0x4c6fbf2f, 0xfea10902, 0x794ab5b1, 0x1a2bd42e, - 0x40d3f8c2, 0x51df8570, 0x2f398674, 0xd1d1f88a, 0xbb436670, 0xd277c13c, - 0x7e58959e, 0x6f5be3f2, 0x5f4168dc, 0xe3f40782, 0x44d71517, 0x91b46f18, - 0xffcc0b10, 0x1b7efca7, 0xbb00c869, 0x4cc7aae8, 0x3e2fd03a, 0xee18e2a2, - 0x9e81fcf7, 0x98fd21b7, 0xfd219b9e, 0x43373d23, 0x9b9e9c7a, 0xcf413d21, - 0x38ae90cd, 0xccc7876f, 0x8e2189c9, 0xf0bfd0b9, 0x5be769f7, 0xd7f18439, - 0x1af7f1be, 0x14fbfc71, 0x0fb7c217, 0xfe087bdf, 0xd1b3edde, 0x8b989481, - 0xdecf5bd0, 0x749fa3bf, 0xff08b820, 0x0a7cb6a3, 0x6eee6bc7, 0xdcffca3d, - 0xcad47f76, 0x872b7a90, 0xce7db118, 0xa0a3270b, 0x1f5b6eff, 0x5d121d7c, - 0xcb1d4cf2, 0xb9fc7caf, 0x828e371b, 0x0fbe3bf9, 0xf9f74174, 0xdb73486a, - 0xfc00fb7f, 0x1fed2a5e, 0xa47a24e3, 0x2f3c66c0, 0x85a1d668, 0xb3d75883, - 0xa09b9dd1, 0x0c2fb3fd, 0xbe509585, 0x01bed843, 0xadc2923a, 0xe7ae0377, - 0x10a05346, 0x78dd0bee, 0xa71b0e41, 0x8a529f7d, 0x7a064e70, 0xcaddfe43, - 0x025f4653, 0x7f74df6f, 0xe223fb6b, 0xa5e015fd, 0xafa5c80a, 0xac2f40a2, - 0xed04f1e4, 0x06fd87bb, 0x2439e9d6, 0xdabdf813, 0xfdea31d1, 0x49e38bb7, - 0x8d7b39a4, 0xb3d7c04e, 0x830d4f7b, 0x7e2989f7, 0xc57bc186, 0x455c86db, - 0x31ef7f42, 0x8f97ec67, 0xf587183c, 0xe769f7f1, 0x10156d91, 0xbcdf3337, - 0xd2580dff, 0x0af1db42, 0x9c599b88, 0x74841d24, 0x19399289, 0x7dc465e2, - 0x4a236583, 0x9a96c20f, 0x7d44af61, 0x4c9814ae, 0x37287c88, 0xd847f247, - 0x558a3c85, 0xa524a7e5, 0x534feaaa, 0xd3e554b2, 0x95548c47, 0xd867718b, - 0x46f5540b, 0xc28604c7, 0x83ae8e79, 0xa4ff03bd, 0x3986f18c, 0x7eb91c2f, - 0x7ccfcd24, 0x43be0e6a, 0x9f2f2cf9, 0x17b95cf9, 0xe143d1f0, 0xd50aa469, - 0x6c1f92e9, 0xd33a107e, 0xf76a179c, 0xa1d0713e, 0xe179c65c, 0x8184e712, - 0xed164fde, 0xca04e7b5, 0xbe001f37, 0xd9c5fa39, 0x3edbf036, 0x14cbf63b, - 0xcdfd4788, 0x0caefe10, 0x440c3f3f, 0x43fb7d37, 0xbcdd1852, 0xc3279325, - 0xf2440dd0, 0xe9643a32, 0x7eecc3cc, 0xb5f295de, 0xa1af814f, 0x4243c0bd, - 0x6b577f7f, 0xb46d1bdf, 0xb036e6ff, 0xc32bbd47, 0x7bbea50d, 0x6fe12b93, - 0x64ef4839, 0x93bbb6f9, 0x07bbf0e3, 0xb73761f4, 0xb8520df7, 0xffbb553e, - 0x60c2e4ee, 0x5c775939, 0x29dc9f55, 0x1bf2ab35, 0x7bf9d533, 0xdb439b4b, - 0xad8fa40f, 0xd189787c, 0x6ef70395, 0x37bfb0a5, 0xfff3e62c, 0xd5800901, - 0x00800020, 0x00000000, 0x00088b1f, 0x00000000, 0x19b5ff00, 0x6554540b, - 0xcef7bbfa, 0x7860190b, 0x77421028, 0x840a4498, 0xb0285789, 0xd71ea08d, - 0x8f4c1ada, 0xe5935654, 0xe04d7903, 0xe3d8f4b6, 0xb68fad18, 0x695b6d07, - 0x9656356b, 0xb139e4e7, 0x36254644, 0xeb495bae, 0x66a254d6, 0x42d899e4, - 0x7a26704c, 0xf75a9d6d, 0x5efffefb, 0x5b602e67, 0xe74ed69d, 0xffffef9f, - 0x27ef7ffb, 0x70ca1490, 0xf60800ce, 0x9970ccac, 0xd6f70601, 0x8018e41a, - 0xe2eff4d3, 0xf9b8daf0, 0xcf03837a, 0x3a380057, 0x01cfe3cc, 0x031401d6, - 0x7b81295c, 0x5914f3a2, 0xff60e760, 0x2fbdf165, 0x00490801, 0xde8d179e, - 0xe38456ed, 0x6e67065c, 0xf08d9ef8, 0xd918064e, 0xbfefff72, 0x25f5c22a, - 0x8c0ee3b0, 0xbd0d43c4, 0x5c75d79b, 0x9fcd7114, 0x77d1d704, 0x98809679, - 0x55706b80, 0x00e207b4, 0x3c636a9a, 0x679e3e62, 0x2e990e86, 0xa6f1c804, - 0x01529bb5, 0xc0228a8e, 0x78074439, 0xe3ef14a0, 0x245f041b, 0xa4ef39a7, - 0x67c8b9df, 0xe7c72fcc, 0x35b03245, 0xe99432bf, 0x7ed77bc6, 0xbf1ce787, - 0xce91a203, 0x8f4a803f, 0x2e5c4c03, 0x19bdbb04, 0x3f233ffe, 0x1812bd4d, - 0xf0619f90, 0x605aba1d, 0x25a9ccd7, 0xa7e92b00, 0x061dfb4c, 0x196fd890, - 0xb2957f70, 0xe57cb2bf, 0xf08b10a5, 0x2040fd56, 0xa70fbd9b, 0x7fd5fff1, - 0xf198376f, 0xda53f57c, 0x530f427d, 0xfbe52f90, 0x77b3f03a, 0x3de277eb, - 0x235ef853, 0x8499fddc, 0x697636ef, 0xc7245fbf, 0xe0e60d24, 0x3828028f, - 0x916db12d, 0xf1366bde, 0xdf4ae6f7, 0xea097bbd, 0xc925e9b1, 0xd1adc46e, - 0x00e2d3dd, 0xa83983f9, 0xf2f1d4e4, 0x7a8cda6b, 0xa7c30c2a, 0xbdf34b76, - 0xca175f74, 0x5e319ea8, 0xe2c960ce, 0x5f1c2cf8, 0x0bd7c573, 0xf735f101, - 0x7ed0d0e8, 0x1146cf00, 0xcf3c08e4, 0xf2ae31ed, 0x07f4c39a, 0xfcc79c2d, - 0x66132f9e, 0x1d75f2e7, 0x1ced01d1, 0x98bf702f, 0x093e8021, 0x60b541f1, - 0x5f4b8edf, 0xc925724f, 0x9f004fbf, 0x589ec05c, 0x5cfd4264, 0x7da39fc1, - 0x8fe02433, 0xe11d6c94, 0xfdc8a859, 0x7c7fd28a, 0x8b77e023, 0x434f167b, - 0xd750e00a, 0x0cd43eb2, 0x0c6d906c, 0xe8f012df, 0xf17d2f49, 0xa416f4ce, - 0x604932f3, 0x1f17dff6, 0x7f10161a, 0xd0b4455f, 0xeff7b026, 0xbe55f7a4, - 0x74cef4fa, 0x8e6be337, 0x26f51065, 0x4e902e38, 0x47978f47, 0x183aae58, - 0x712bf554, 0x9c7f2177, 0xfb3edd2b, 0xd1dbf412, 0x223160a5, 0x684b97bd, - 0xabc30838, 0x49ab8fdc, 0xae5133d6, 0xe8813f82, 0x6e17966c, 0xe4bbf191, - 0x97417bd6, 0x1d372118, 0x2f5533f7, 0xd3c71caa, 0xf72de2a1, 0xd1bf903b, - 0x9fb3021d, 0xecccbb46, 0xe4fcb1b3, 0x7f104b83, 0x0bb25fa3, 0xeeb2cf48, - 0x7e4847bd, 0x403b6b1d, 0xe7401e77, 0x2eb66eda, 0x527d9933, 0xd98be31e, - 0x414688ad, 0x6056ad7c, 0x7c35a7c6, 0x0c7be61e, 0x7c3f51bc, 0x3804ce06, - 0x9e7ceb18, 0xfbf35bf8, 0x1096fbcf, 0xe3ca1bb5, 0xad901f99, 0x3fa61b9d, - 0x466000df, 0xa3db43fa, 0x3c304fbd, 0x6125af68, 0x27b13d7b, 0x9e0b70eb, - 0xcf53789f, 0xc55f75cc, 0x416ea7c3, 0x68f6cd78, 0x0913e726, 0xf3a549e0, - 0x3d7ba627, 0x18a56178, 0xb9216fea, 0xb7d8c677, 0x47f1f9e3, 0x13bb3fa7, - 0xa767dae1, 0xf24c89d9, 0x7de5191f, 0xda011d3c, 0x7d953e7f, 0xef1c2907, - 0xa52fc50a, 0x57dc6667, 0x24cfe74e, 0xaa8f09da, 0xa347a1bf, 0xfaf2801c, - 0x16797c12, 0x8293bd34, 0x87c45067, 0xc79dc4eb, 0xdbcbb404, 0xc483ae0c, - 0xfe47eaf7, 0xf90ca87a, 0x37e67aa9, 0xfa44cf0f, 0x0c9bdf6a, 0xaf584ef4, - 0x6c40e2e3, 0xdffc9720, 0x915ffdc6, 0x288edd4f, 0x7111c7cb, 0x5e23a1a6, - 0xa7753703, 0x888e3e5a, 0x65c07537, 0x8e82f50c, 0xfc57a9f8, 0x1d745eaa, - 0x201aba25, 0x8422e3c0, 0x0557640c, 0x78a0e092, 0xc8c7ba10, 0xced63fe4, - 0xd1916546, 0x8b822f51, 0x224179e2, 0x6fc85298, 0xc17e5c5d, 0x713fa67b, - 0x9266ca17, 0xfbf54135, 0x223385ac, 0xf1bfb3ed, 0xcdcfb215, 0xc39f6646, - 0x8d2f3c51, 0x391ff3c5, 0xc2bf7d9e, 0x87f305f4, 0xf5a4f933, 0x17385adf, - 0x0aef141c, 0x9bc2e4da, 0xf4516d70, 0x29c52c72, 0x1dee4958, 0xc03aeff7, - 0xe6f5b9e4, 0xbf7784a3, 0x0e0fe999, 0x0507b970, 0xf7d5279e, 0xa0429856, - 0xb77a242b, 0xfdd57a31, 0xf3872dc1, 0xe0fef85c, 0x8079390b, 0xf24cbcf6, - 0xe505fe0f, 0x7fc62a73, 0x3b5c36ec, 0x853bbff7, 0x7a58e0f2, 0xd9475beb, - 0x2c3c2a7b, 0x4f5438f0, 0xf7fee07c, 0xa264ce99, 0x8b08c313, 0xcd77030f, - 0x2b9bf260, 0xfe91c6e5, 0xf4b42783, 0x7d53a58d, 0x7d4fa55f, 0xcd37bd5f, - 0x8e39322a, 0x9479fc18, 0x90cc5ff7, 0xc48d7c35, 0xcde2f3fa, 0x75e16fb4, - 0x11c20244, 0x3f4356f6, 0x2635bf51, 0x5f48db8c, 0x6f608d4d, 0xa1efb603, - 0xcfab89b8, 0x29f5e785, 0x03722b2f, 0x78ed09a7, 0x906762b1, 0x6eecc894, - 0x5ebb7011, 0xabedc4ac, 0xe80f43a0, 0x75c4472f, 0xfda035bf, 0xa03c770d, - 0x5dc64577, 0x74f151cf, 0xbb8f4fce, 0xa6c84a9e, 0x31623df8, 0x9e66bab3, - 0x7bb1d055, 0xf74e90e9, 0x43eedcf0, 0x1a74f03b, 0xcf486ded, 0x8173a2e3, - 0x6f53e515, 0x1f91e5f0, 0x2e3ddfa8, 0xb0fed8ba, 0xe9056070, 0x3cbe741b, - 0x1bc4ef56, 0x233ac040, 0x77eed938, 0x25f65d50, 0xd412b8b0, 0xe2274d43, - 0xdd12aa2d, 0x3c70e69d, 0x5167e354, 0x5ca3ee0e, 0xf55f682b, 0xa29bb457, - 0x30fded7c, 0xb8f85a3f, 0x515dfb95, 0x98eee8a2, 0x576e5fc0, 0x1d06dcf4, - 0x9e67f712, 0xb914cb47, 0x4522dd63, 0x4a8d2dd6, 0x9ac60f9c, 0x53f2123c, - 0x82f51bb6, 0xb7ce9970, 0x028c5697, 0x9dfa8ad0, 0x5efe3e05, 0x539e36b7, - 0xf2ca590e, 0xcbcb0e72, 0xaf7514b3, 0x7a40dc17, 0xc2fe5135, 0x2fc12ef5, - 0x082bfad1, 0x1601d5b1, 0x06a8ad1d, 0x2701ceb6, 0x9b81e75b, 0x9da1f3ad, - 0x83a00bad, 0x9f8297ad, 0xaf8170ad, 0xb83e580d, 0xf98832dd, 0x52bd7e18, - 0xb45cbca4, 0xfc7ae264, 0x675e4571, 0xf9460797, 0x8f2f9f92, 0x614ae079, - 0x2e4d9d74, 0xdd99b353, 0x923172ab, 0x5177e27d, 0xb5a14de0, 0x9dec0202, - 0xf190c98b, 0xeb20d99d, 0x0702ae08, 0x48fee783, 0x5c069479, 0x04ee573a, - 0xd89aa972, 0x7628764e, 0x5d364c52, 0x87d7d61c, 0x54171e56, 0x49d201bd, - 0x3ebc60f9, 0x2ce88321, 0x5cfcae8a, 0xdaf190c6, 0x3a9df7b6, 0x8545a38c, - 0x84362d95, 0xe53f590f, 0xf3e55970, 0xd91f0899, 0x9ba9d276, 0x595e7649, - 0x1563b7a8, 0x39d86eba, 0x184dcf07, 0x4e50a3fc, 0x52824d92, 0xb1515d5c, - 0x677e8079, 0x74ebac94, 0xdbc657e8, 0x5719c580, 0xd59f8014, 0xe46568b3, - 0x7ebc3527, 0x7ae1635d, 0xbd706bdb, 0x60da7e4a, 0xc8cac5f2, 0x73759ad3, - 0x6e5f2993, 0x3ff7f030, 0xbce72c9a, 0x22327282, 0x9841533e, 0x44f73c4f, - 0xe4101c21, 0x186b5696, 0xf7c08fff, 0x77c21fcf, 0x5deb8a6b, 0x594dcf16, - 0x534ffa40, 0x676779f2, 0x245d8a59, 0x3f8616fc, 0xd2d59310, 0x5207478a, - 0x7bd21f9c, 0x776e18c1, 0x5eb95a1f, 0x329ab6ce, 0x27581f1d, 0xfbae0fd8, - 0xe28f977a, 0x084827d0, 0xd599f3be, 0x34744035, 0x428c8189, 0xd11dd7d4, - 0x27640cc7, 0xa80b1daa, 0x7fc8a5bc, 0x06bc039b, 0x96e51fe6, 0x2d98f533, - 0xe5c107ec, 0xa5ca1ef8, 0xd2ace9c8, 0x8d4971e3, 0xa5ad1f7b, 0x3c2af6ae, - 0xa2413c21, 0xad0a49a7, 0x1538bb20, 0x13e19eff, 0xb953a7e6, 0xabf12a3d, - 0x6def4f67, 0x42741c69, 0xed361f84, 0x0fabe6f9, 0xa34ddf50, 0x0f5d3b66, - 0x1696dffb, 0x1ab00bea, 0xd517c4d4, 0x1b75672f, 0x955fd47d, 0x397f3eed, - 0xaf78abdd, 0xfa7146df, 0x1b40fee2, 0x9ec1cb95, 0x2fdc69c3, 0x6bfe3ad4, - 0x93e4e7e1, 0x750512b9, 0x905ecbac, 0xabe446bc, 0x050bea99, 0xdc7c20f6, - 0x47137684, 0xa9bf79f7, 0xbd0d95f6, 0x2fa819af, 0xc43c67c1, 0xff42ad6f, - 0x5c37adaa, 0xad62f54a, 0xd62fdb57, 0x13d77bf5, 0xb43b75dd, 0xd9bf6afb, - 0x4f5f7ca4, 0xea8d9af5, 0x26bded3e, 0xa8f337ea, 0x67eed3fe, 0xa6fd2a66, - 0xa940ff92, 0x772a5733, 0xeb333f88, 0x235e0cff, 0x68fcd6f2, 0x7042dd8b, - 0xe2ced9ba, 0x6606fd6d, 0xd87deac7, 0x446cc89a, 0x8ddadbf5, 0x5567eac0, - 0x1b4ff98e, 0xfc8fa41d, 0x5d5993a7, 0xab3cf58c, 0xf09e3047, 0x22651efe, - 0x173ddda0, 0x1114ca1f, 0xd93d73cf, 0x5fb7aa76, 0x7f80eb5e, 0x4fa6179d, - 0x4ae7f7ad, 0xd40cab3b, 0x7d88dd47, 0xf7356e14, 0x4266d93e, 0xd01379b8, - 0x3b2d240d, 0xe2a6ea8e, 0xe97812fd, 0x503ef01d, 0x1a976b8e, 0xbeb0524f, - 0x9447908f, 0x09e4093c, 0xa2a379fa, 0x04ece8b7, 0xfd8c79cd, 0x71f7cd1c, - 0xefda99a5, 0x6e7f0e3d, 0xfe73c509, 0x02e3bc7d, 0xc136fdcd, 0xcd91f76d, - 0xbc3ff004, 0xb188ae57, 0xcd82bfc2, 0x17e7121d, 0x886fee68, 0xec9fb79d, - 0xdd0bfcbb, 0x4b703b18, 0x01657764, 0x2f504780, 0xe7b586b3, 0x21db07c5, - 0x1d47f116, 0x57998dd4, 0x16ea8078, 0x5fddaca3, 0x54c5daae, 0x4399aa98, - 0xb73b919c, 0x9121d1fb, 0x9c0945d9, 0x117970f7, 0x5e0f59c9, 0x46dcbc79, - 0x66fba569, 0x598bf303, 0x8a762dbd, 0x5a9d9347, 0x68d727f9, 0xd2ea9fe5, - 0x956d3bca, 0x6ee9de56, 0x6dcfbcad, 0xead7cad5, 0xb6cfcad1, 0xfee69671, - 0x0d4af6b4, 0x02f37d3c, 0xbdf3fdcd, 0xce70350b, 0xf734ab8e, 0xd32c7467, - 0xaf77e79c, 0x76ab9cd6, 0x2e0ed636, 0xb18f35f4, 0x08c41133, 0x567aabfd, - 0xff70a0ed, 0xff3c1aad, 0x1f6ffd6f, 0xc8a7ffa3, 0xbdde31d7, 0x37743b15, - 0xd165ebb9, 0x999dae3c, 0x59eb9427, 0x9cb6f6bf, 0x77431558, 0x54e6fc95, - 0xff941bf2, 0x0e16c391, 0x7df6fddb, 0x8e0acf14, 0xae88ab38, 0x1f7b80a2, - 0xa192f385, 0xba38aaf6, 0x32d900ef, 0xe89c8f85, 0x02a5e5fe, 0x857e34e8, - 0x3cb094f0, 0x93acf0af, 0xd972f0e2, 0x1636de77, 0x4be9c96e, 0xa120f3c2, - 0x6a85e794, 0x22e81447, 0xeca152e4, 0x29e92503, 0xf3abf961, 0xc007ec23, - 0x6880fd40, 0x2759b6f2, 0x9bec77aa, 0xb98f5625, 0x86f67d58, 0xa57362e0, - 0x067f2645, 0x25dff7c5, 0xc4cedebb, 0xb44a76b8, 0x139eaccb, 0x54c46d02, - 0xa4a31890, 0x76afa9e5, 0xed871f50, 0xff2bcd2c, 0xb56d4774, 0x6f919727, - 0xb6f09409, 0x67f5fe99, 0xa2648eba, 0xcb0407fc, 0xf6fc42fa, 0x332759ad, - 0x25197f28, 0xcd014494, 0xe9471c4f, 0x24dcccfc, 0x78c3f919, 0x0f65101b, - 0xab73c289, 0x9390fac0, 0x08ccd8f4, 0x67a8ddff, 0xbe940b79, 0x5e451aec, - 0x54b65f6a, 0x4f803fc1, 0x7e78c2ac, 0x4c1bf74d, 0xc329752e, 0x6dca1cca, - 0x37fbe0b7, 0x5017354c, 0x428e0a5f, 0xd5e7ef3b, 0xfa4d2d3e, 0xed557929, - 0xbf76cf6b, 0xd348652e, 0xc4cec32f, 0x6391e709, 0xbe615ee7, 0x9b03fbf9, - 0x1a1e59a2, 0xe6ce94d8, 0x4ff7e18b, 0x71aff7b1, 0x93b1a3bf, 0xd7df5aeb, - 0x9ef5dfd8, 0x81e7348f, 0x0d3e90a4, 0x4aec0ff9, 0xca35779d, 0x6305e46f, - 0xa8abf509, 0x715b38b7, 0x3dc0fdf8, 0xbe10e7d3, 0xa7e7cdff, 0x6bfdbe4c, - 0xa6ee6cfd, 0xed6c79f2, 0xd6070611, 0x963ad806, 0x55bfb54f, 0x20dfc357, - 0x90e5ea9b, 0xd13ec930, 0x1b31e6bc, 0x67fa83ef, 0x7ca4a94f, 0xd06e9fdc, - 0xc38b35f1, 0x0e26a5a9, 0x6b4f9bcf, 0x48de6f50, 0x00bf6dfd, 0x61ed010e, - 0xec7ce0a9, 0x3abbe47a, 0xa36b95d9, 0x2875727a, 0xd0fe874f, 0x56b81f94, - 0x1ebe7d40, 0xfe27caef, 0x53062c05, 0x599d1813, 0x890c37d4, 0x63013c9e, - 0x764f4dc1, 0x3ffd5357, 0x8a73c934, 0xadad7632, 0x83fa9aab, 0x8ff70321, - 0x847c9e5b, 0x16b7c3f9, 0xe77a4cd7, 0x31f24113, 0xf0497e7b, 0x16f6676e, - 0xf88c2c30, 0xaf3a82bb, 0xfa9b7ea1, 0x5f14609b, 0xdff8db67, 0xacc72a5f, - 0xae3c6d4b, 0x316b42dd, 0x2ceee5e9, 0xe8ca7bfa, 0x5f902366, 0x48873e20, - 0x5cf87af8, 0x40f20a76, 0x6f560d75, 0x78285fac, 0xf8a3e8d5, 0x1675cea1, - 0xbdecacdb, 0xd79f1b24, 0xf467dd24, 0xeefcb1b6, 0x3a46a8cf, 0xef58f5db, - 0x1070df50, 0x846d1cd8, 0x7a1161e6, 0xfde36c59, 0xc008dc17, 0xd1b793cf, - 0xc0ef4379, 0xdf278a31, 0x24aeba67, 0x72880c39, 0x8693c509, 0xdeacbdd8, - 0xecc9b66b, 0xf197a43b, 0x4ee1718f, 0x382fcfd2, 0xfa455c0f, 0x7805306d, - 0x03ccaadd, 0x91b726cf, 0x7287fee5, 0x9ecbfcd9, 0xf4a9f441, 0xb6cdfd22, - 0x4a9db988, 0x1f9df87f, 0xae750bf6, 0x5b83c2a5, 0x9f916436, 0xbcf85ea1, - 0x5bae1251, 0x0ff7c138, 0x963efa2a, 0xfe10f4e2, 0xf73e6ed5, 0xfb4ddb0b, - 0xcf4947cd, 0x271666bd, 0x58fdf6cf, 0xf4f61b3e, 0x9f207932, 0x117f12d7, - 0xc91bde7c, 0xe1cf48e7, 0x9fe57287, 0x9d305fcf, 0xb8291dff, 0x190c9bed, - 0xfdd86fbf, 0xbbb211c6, 0xdf1e7506, 0x18339da5, 0x9aff6127, 0x1d1cd130, - 0x5d444fb3, 0x9fbf5466, 0x8f7ed3aa, 0xa9cd3905, 0xa9dfc9bb, 0xbff0717e, - 0xb8f9a98b, 0x846be94b, 0x1f2cebc0, 0x87f23e10, 0xe58782f5, 0xd18e7545, - 0x23de6026, 0x585abadd, 0x35ce909e, 0xbb9ec9db, 0xe4fd06d0, 0x34473a07, - 0xe98f5f9b, 0xb835bfa3, 0xd6fc9176, 0x4c9953bc, 0x9be7767d, 0x8d7e940b, - 0xc562a9e7, 0x3f098b2e, 0xc71b9fd1, 0xa148b5ec, 0xf584c4af, 0x7c852650, - 0x15e7c48f, 0xd363fcca, 0xef3e9aeb, 0x685932bf, 0x001e0053, 0x00000000 -}; - -static const u32 usem_int_table_data_e1[] = { - 0x00088b1f, 0x00000000, 0x51fbff00, 0x03f0c0cf, 0x1915c58a, 0x19d44418, - 0x18344c18, 0x20685618, 0xb58969c4, 0x9fd329b8, 0x90c0c2c9, 0x40b9c40d, - 0x7cc40f9c, 0xfc0c0c4c, 0x17ebc44c, 0xf5b04514, 0x84181904, 0x026ffc80, - 0x85d70c0c, 0x8bbe1818, 0x03083030, 0xf1402ef9, 0x01ce2004, 0x58a06f62, - 0x045e900b, 0x2c40ddc4, 0x7cdf8a22, 0x6bf20251, 0x37f95185, 0x847bf8d1, - 0x1057ebf0, 0x47af2fc1, 0x161b1e40, 0x3e3f22d1, 0x3bd02922, 0x015f5810, - 0xc7265f95, 0x0f27d0c0, 0xb8a87f8c, 0x4bfc9201, 0x0e5cbb20, 0x6096f6c2, - 0xf2062860, 0x9bb0150d, 0x2f9403eb, 0x857dca01, 0xcc0003ca, 0x688cbacc, - 0x00688cba -}; - -static const u32 usem_pram_data_e1[] = { - 0x00088b1f, 0x00000000, 0x7de5ff00, 0x4514780b, 0x74f570b6, 0x9924ccf7, - 0xf2124c99, 0x00493de0, 0x210e0311, 0x9970c044, 0x46a2c024, 0x141a020d, - 0x84920275, 0x7e889790, 0x33feaeec, 0xa8a08901, 0x17acb9f1, 0x376141dd, - 0x0c06e8b2, 0x60e03518, 0xba2eb300, 0xe7c045c1, 0x36bc8026, 0xb9f04324, - 0x9d6f5ecb, 0xdd33d553, 0xc7c4099d, 0xffef7fde, 0xa55f9f8f, 0x71ebaaba, - 0xe9d4e7de, 0x278f3242, 0xdf210a64, 0x9f968fc1, 0xf890848b, 0x206f5950, - 0x8841922e, 0x6df466d7, 0x88cfa64c, 0x68e67a23, 0xd11d985a, 0xef435837, - 0x9ed5cbe9, 0x186934a4, 0x1c790f21, 0x23e21258, 0x5ab54e84, 0x16f50520, - 0xe0933ba8, 0x213e3a7d, 0x0ff8e8fd, 0x30f8e246, 0x1a18992d, 0xe0311067, - 0xf9ad537b, 0x421eb089, 0xc3e6476a, 0x213b16fc, 0x9f9f7bfd, 0xa7eb888e, - 0xf7c10def, 0xb59efa24, 0x6529efef, 0x13fd0e57, 0xf66ddff6, 0xf108146d, - 0x71c7fcef, 0x8699ef58, 0x5d130e39, 0xd9b7766f, 0xbeea053f, 0xb6899f6c, - 0xc0fb6ee7, 0xe5fed126, 0xda0944db, 0xf0233b0d, 0x8275cefd, 0xa695ea0f, - 0xa4ae47d6, 0x9136c0f5, 0xf8d30f3c, 0x4092062d, 0x613371c8, 0xeb15873f, - 0x5aac1145, 0x6dd77ebe, 0xa3495f30, 0xf7d04489, 0x2e88378f, 0x28d92fa8, - 0xaf9d08f8, 0x8c07b5fc, 0xc578e803, 0xc23ea13e, 0x1f1beb41, 0x3ee83a33, - 0xd8fcef97, 0x7ce146d6, 0x0e2663da, 0xa4a3ee23, 0x52908d3e, 0x03e996df, - 0x9ba5fbe8, 0xbe802705, 0x4ed9dd74, 0x83695f58, 0xe3a45c3c, 0x228bae2d, - 0xee6c918e, 0xd7cc08ef, 0xdbe7147c, 0xf9830f26, 0x65dfce4a, 0x6ee52404, - 0xca2e9193, 0xdf603ae9, 0x3da7bcca, 0x053e716b, 0xd22fe59e, 0x8abf68f9, - 0x6c270597, 0xdc40c2b1, 0xd7ce8eb0, 0xb05e0a22, 0x8daafec0, 0x7deaac23, - 0x7d876e14, 0x1bd6fa94, 0x7d605ba7, 0x69458deb, 0xd716f1a1, 0x7d76a7fd, - 0xdd13536b, 0xf3e3bd69, 0x748287b4, 0x4a5ea844, 0x4fe90b88, 0x8e8119f2, - 0x85e7e795, 0xe2f7c418, 0xcc38913a, 0x3a15f1a1, 0xe9c07ef0, 0xf1958774, - 0x12dbc701, 0x842ce03b, 0xc73b6eb7, 0x54c814a3, 0x8f94af8f, 0x7ae83e00, - 0x2c763d6a, 0x6124f71f, 0x81c7a4f9, 0x33da7b70, 0x1eb5cb12, 0xc67f3e27, - 0x75cb0133, 0xcf96171e, 0xe9606679, 0xbf63e4f3, 0x58053de7, 0xf1b8f06e, - 0x253d6ff9, 0xaa79d658, 0xcf26f9f0, 0x7b372c32, 0x65fcf8bc, 0xeb2c2acf, - 0x6e58b53d, 0xb2d17c05, 0x7ec3e3c1, 0x58753ddb, 0xf1ea7a36, 0x469eebf9, - 0x3870d72c, 0xb648b2da, 0x7360e144, 0x3b453b11, 0x6573cd89, 0x9b1eb4cb, - 0xf309eacf, 0x5a46d9bc, 0x3ad3704f, 0x3280cb85, 0xd689b67f, 0xf6b15407, - 0x1c92f721, 0xf10fad33, 0x3594f6b2, 0x5a089cae, 0xed65a94f, 0x7379d623, - 0x847d6922, 0xda8fb58f, 0xa289cfec, 0xacf551f5, 0xc9134c7d, 0x18fad0b5, - 0xefa7ab3f, 0x695ae573, 0xd595bd3d, 0xe6f13f33, 0xb33d68da, 0xa93fbd8d, - 0x2c3a27c3, 0x55b0f13d, 0x14202c76, 0xb9de4d57, 0x9bca892e, 0x5dc746ad, - 0x7bc849c4, 0x892ef9de, 0xd90687ca, 0xde6ded85, 0x746eacc5, 0x77b77b61, - 0x2edff629, 0xaa5db1bb, 0xb7db0fbe, 0x9ed8dd1b, 0xed835d50, 0xdb17b28d, - 0x8a3f5647, 0x2f468ded, 0x5eaa4fb6, 0x65d7f58b, 0x55e7b61f, 0xaffec7af, - 0xfed87d1b, 0x5c9bfdf8, 0x05fd6953, 0xe41dbdc1, 0x5dc10ade, 0x9e815242, - 0xee4093ea, 0xf9f970d5, 0x6d1d101c, 0x446fe9af, 0x6efadc3e, 0xbfc00be6, - 0xf507ebf8, 0x983edfa2, 0x89bce38c, 0x1c74c8e3, 0xa4e3e2f1, 0x334137bf, - 0x257bfa4e, 0x382d38ca, 0xc6df444e, 0x24defad9, 0x2bde7aed, 0x0fd9c655, - 0xdac2b4fc, 0xffa57db7, 0x9ebb4b39, 0xe329973f, 0x89eb847c, 0x1a7adbe9, - 0xa7c2d03e, 0x7c2083e1, 0xf138e28e, 0xc64f5b7d, 0x327c2d41, 0xd3e1060e, - 0xeff4e381, 0x070d38db, 0x3869f0b5, 0x97cf8418, 0x7dc19f08, 0x21c657db, - 0x0e327c2d, 0x5ff3e105, 0xbee49eb8, 0x53fdb38d, 0x7fb67c2d, 0x498f841a, - 0xef0cf580, 0x3f32bedb, 0xf327c2d3, 0xec7c20b3, 0x7da5ce38, 0x67fb671b, - 0xff6cf85a, 0xfe9f082c, 0xbee8ce38, 0xaff32bed, 0xfe64f85a, 0x149f0835, - 0xb633e001, 0xfc69eb6f, 0xc69f0b5c, 0xb9f083cf, 0xdf19c70c, 0x384cf5b7, - 0x84cf85ae, 0x64f841e3, 0xf626bee0, 0xe3c69c6d, 0x1e34f85a, 0x3267c20f, - 0x6fb9338e, 0x42709afb, 0x27099f0b, 0x8e99f082, 0xebbb64e3, 0xc7465198, - 0xce3ef6b1, 0xf0b467eb, 0x104cfd79, 0x38e3d73e, 0xa938e8d3, 0x52671f17, - 0x933e16a7, 0x29f0833a, 0xeaae71c0, 0x77af38db, 0x7af3e16a, 0x853e1067, - 0x7db5ce38, 0x2ea4d7db, 0x75267c2d, 0x3b8cf831, 0xa36b9550, 0x3a1754ed, - 0x95cafa45, 0x40972e1d, 0xd59da2eb, 0x8093bb45, 0xf62a225d, 0x89756906, - 0xe6cb7df4, 0x8907f498, 0xb9c8eeda, 0x4ac7e813, 0xddb531ad, 0x52213d11, - 0xb8c4e763, 0xb8f53562, 0xfd340319, 0x3453f3e3, 0xa30589ed, 0xddfded34, - 0xc0fa9ae9, 0xfe9a4992, 0x3472ab83, 0xaecba1f5, 0xf64ff4d6, 0xa7a9a0de, - 0xd359baae, 0x7ced787f, 0x6b25fb4d, 0x97ed354b, 0xea6896fa, 0x42fdd597, - 0xfd747fd3, 0xe5fb4d72, 0xda6a0f8d, 0xd71ffac7, 0x3cb5c7d4, 0xbe3fe9a3, - 0xfb4d79f5, 0x69378715, 0x6db627da, 0x3cafd4d5, 0xcecebaf9, 0x5f8fd8b3, - 0xd022ebc6, 0x7f76613d, 0xf8f7e67f, 0x1bac46ad, 0x8ed05807, 0x722d65df, - 0x35f8a31c, 0xd1c0b5be, 0x7017e28f, 0xf6457e0a, 0xda4b9280, 0x267bf3e8, - 0xd3b12fb9, 0xdd18f7e7, 0xd8c3db97, 0x041e94a7, 0xc3a50492, 0xfdbea500, - 0x63d19901, 0x23f3c0ce, 0x95fbe9da, 0x1888c086, 0xb312cf5a, 0x777e811b, - 0x8a2fcc0a, 0xf4154914, 0xf411348b, 0xce481e0b, 0xa2abc17c, 0x298355d7, - 0x71a10a1f, 0x24eec957, 0xaade33b0, 0x1d82f76e, 0xee983352, 0xcd21006b, - 0x4bdfbb42, 0x0607b4fd, 0xe9b92517, 0xb5232678, 0x1bf3d5d3, 0x3869fce9, - 0xebd00b7f, 0x7c7f307b, 0x294df9cf, 0x9bf33413, 0xe6689487, 0xfce91b37, - 0xafde4276, 0xa7e7c53e, 0xc8449848, 0x3853845f, 0x094869bf, 0x9180ffce, - 0xf9ea2bfa, 0x1ff38323, 0xd67ffd86, 0x2653fedb, 0xa43ff769, 0x237fbb54, - 0xea91ffdb, 0x48fe7cb3, 0xe151ffdc, 0x90ffdb2c, 0x137fb652, 0xbf38371b, - 0x93ff082d, 0x2f677f30, 0xb3529bf3, 0x5a1ffbb4, 0x89bfdda6, 0xfd5ddfcd, - 0x82df9f2d, 0xbe139ff3, 0x5a1ffb65, 0x4d1bf386, 0x8fd0276e, 0x95646071, - 0x1d4fce8f, 0x04490761, 0x40f3a172, 0xfd163239, 0x148497e4, 0x913dc75c, - 0x8abede8c, 0xf286f4a4, 0x58fccbc6, 0x996c951f, 0xb4e2efd4, 0xb67378be, - 0xb612e411, 0x21657f53, 0x8d1dea5f, 0x7937d222, 0x4e1be4d2, 0x28d9dbd7, - 0xc77ea17a, 0x207d9393, 0xe44d2aff, 0x4f787cf6, 0xfe787e22, 0x9fa353f9, - 0x5f4bef57, 0x8f95ac2e, 0x2df8a9b7, 0x90e547e8, 0x98165591, 0x1fa9aed7, - 0xa1107ea1, 0xd427c5fe, 0x249420cf, 0xbe6cca8f, 0x04bfa8cf, 0x2fea36f5, - 0xd5213b41, 0x75e25fb8, 0xae8c307d, 0x3f289f3f, 0x26f3ee17, 0x9e3a2964, - 0xc8f7f8c4, 0xf807c11a, 0x14597db8, 0x3d687e05, 0x4d38de85, 0xfb0fee9d, - 0x7c12ae07, 0x86380bcf, 0x9333e01b, 0xbd60478f, 0x67605eb4, 0xe8a21cef, - 0xb0514fef, 0x8a40d560, 0xb338d08b, 0xa44e4b88, 0x5a59cfef, 0xa2e84328, - 0x2f061055, 0x2059fa01, 0xe0119753, 0x69278de7, 0x7ae8389c, 0xf1b3b66f, - 0x63e4ba67, 0x14f5aa6d, 0x3e5766c8, 0xa1414f5d, 0x359feb88, 0xd1fedb43, - 0x619728ce, 0x3d572d0c, 0xc9ccf381, 0x54dfb6d7, 0x75cfada0, 0xef54eb6b, - 0x6ef7a0c9, 0xa73fd129, 0x9cfba160, 0x5d2b8417, 0xade75d28, 0x56b70e1c, - 0x5e0d5ec9, 0xda556dc1, 0x26e0a021, 0x5f7c2fb8, 0xf6ffd9ec, 0xa17ada65, - 0xb05f5b57, 0xa73e374a, 0xff1ce39b, 0x683e8047, 0x83e80279, 0xa718f3c2, - 0xd55c908f, 0xc18dc7d2, 0x50fa306d, 0x625c71f6, 0x8ebe3828, 0xdac2c7d1, - 0x50f4f0a8, 0x9707a418, 0x7a14be9a, 0xc3d38db8, 0x8a1e9ca7, 0x6ae96ad7, - 0x4cadf12e, 0xb2dfefa2, 0xe9e21766, 0xe8c850a0, 0x3d0a97e1, 0xc1e869b4, - 0x8f41e9cd, 0x3d38dbbf, 0x4673f6dc, 0xb67c7a0f, 0x5b687a71, 0x29264e7b, - 0xf14af13d, 0x3c53a9a0, 0x376ef0e8, 0x7c503d02, 0xf987a584, 0x8dd37dc1, - 0xde02fad3, 0x9c5f03d6, 0x053db01e, 0x4e104ec0, 0xcf6a7ef8, 0x684e54fe, - 0xc36bc5ea, 0x31b2bfe3, 0x6a98ee3b, 0x57f5e55d, 0xf5531dc5, 0x53375c5b, - 0x9be45f53, 0xbc5fe9ab, 0xbed350b6, 0xa69176b0, 0x3baac17d, 0xef42f535, - 0x6ffd35cf, 0x69ad565f, 0xb56ab5bf, 0x9296fda6, 0xb9f534c7, 0xfa6b5fee, - 0x5eb054df, 0xff273ed3, 0xacfb4d45, 0xf5345b19, 0x34d7ae99, 0x2f3b0dfd, - 0x31e81ebd, 0xc048a0eb, 0x71e638fe, 0xf71fdd20, 0xa4f2c48c, 0x717c89c7, - 0xcb0133da, 0x4fcd8d7d, 0x7cbb495c, 0x26882819, 0x91167f4c, 0x2cf64218, - 0xcaaf5777, 0x504e7d02, 0x7971feef, 0x1077b551, 0x07065395, 0xad6f39c2, - 0x11c7f891, 0xe2528022, 0x50c407f3, 0x6d1b567b, 0x3dbdeb8f, 0xb614ad6f, - 0x0a4dab3d, 0xe3e56e3b, 0x61ed4385, 0x7e2133e2, 0x3ec10326, 0xb9f6e2ea, - 0x204cbdbe, 0x84e7eaf9, 0x8ffe472c, 0x5cfd3031, 0xa2726466, 0x1cff6b6c, - 0x7fba8362, 0xe685d544, 0x95cca7ab, 0xaa91f408, 0xb5e2e3e1, 0x3ce46997, - 0x3c6de881, 0xcd38d9d0, 0x5775c5f3, 0xd8ebde6a, 0x2bbae225, 0x7d508640, - 0x07e48c3d, 0xfd97a00c, 0x8d6643cd, 0xceba7586, 0x355e401a, 0xd8fda3c6, - 0x771199e1, 0xe63c024c, 0x53d27963, 0x8f71e580, 0x9e63cb1b, 0x788f2c12, - 0xf36cb0aa, 0x33f2c32c, 0x4fcb178f, 0xfcb0ab3c, 0xe58b53c8, 0x2c5acf61, - 0x587c7a0f, 0x61d4f01e, 0x1ea7bef9, 0x234f56cb, 0x171e9d96, 0x29bf0a96, - 0xddd3d0f0, 0x4fa7ae49, 0x805dfd03, 0x07c4e2ce, 0x0a0d57aa, 0x8ae259d1, - 0x59bdab87, 0xd6f371a1, 0x249d389a, 0x0861e868, 0x81e364f8, 0x5e9c4c5e, - 0xade7b7c2, 0x9ed82f95, 0x1d8726d5, 0x7ff9f2bf, 0xf9cdbd0d, 0xa216f491, - 0x7a3a81a7, 0x3d18bd4a, 0x87c7124d, 0xc18e69e8, 0xa71ff4ce, 0x1f6087a7, - 0x628ffc61, 0xabc6ea30, 0x14573aec, 0x73f3678b, 0xb2d16a07, 0x7b9f3678, - 0x15ae1d05, 0x48df3fed, 0xc8f773c0, 0x78808fbf, 0xaa61f77d, 0xdf7b9328, - 0x7a5e9e9f, 0xfd0bbb87, 0x551f22a0, 0xb67ae3a2, 0xb8324447, 0x0cc81846, - 0xeac84e92, 0xce75bfe1, 0x44bac34f, 0x9f7de162, 0xf3986673, 0x4f670228, - 0xeb871789, 0x6357eb0a, 0xcfe3bc60, 0xca1323fc, 0xe6148639, 0x688b34df, - 0x0bff13df, 0x506f804e, 0x499c991f, 0x0c0f0710, 0x3ed1da37, 0xf0b459f0, - 0x667ad2f3, 0x29ab7e08, 0xdf515a8c, 0xfc2126d7, 0xa2357d86, 0x77e01f7f, - 0x317f3931, 0x0df7ce78, 0xf3c097f8, 0x62f1f262, 0x1cb89172, 0xfdd2372f, - 0x9d1ced77, 0xe403a0fe, 0xade185e0, 0xd7e95f9c, 0x7d28bcf3, 0x4aee3a2f, - 0x75b8e850, 0x88f3a108, 0xefc71da2, 0xc984b86e, 0xdbeec52f, 0x05f5f266, - 0xb59267af, 0xf9c53de3, 0xbbaf194f, 0xf81b05e5, 0x0c924b5b, 0xf06163f6, - 0xf5e594a0, 0xda8b76c9, 0xd6d46cfe, 0x19856bbb, 0x3a2768f5, 0x068f67a2, - 0x1fb7613d, 0x3b72061b, 0x9c654b09, 0xfb464925, 0x4ef72a31, 0x3346a5d7, - 0xe4c7cf3f, 0x9418e6c1, 0x663da717, 0xaf53ffec, 0x9471b7a7, 0x40d210f5, - 0x1e419a8e, 0xded4b6d3, 0xcf4af7fb, 0x3c4617d2, 0xbf926df7, 0x4cd0fb02, - 0xfc0effff, 0x5d61220d, 0x5eb2b719, 0x872e9af4, 0xf3359be7, 0xca1cf7d1, - 0x2977eb19, 0x891be217, 0x96e8571c, 0x5c638bea, 0x8bae2c9f, 0xcfed6bb0, - 0xb2bd4d18, 0x635dbfb1, 0x541fc28f, 0x412a92fe, 0xe329fa02, 0x5925d3e4, - 0x7d740956, 0x1090426f, 0xfd6056e8, 0x466dcdca, 0x95ce03b7, 0x5b7ade19, - 0x4cdfc51f, 0x897c9289, 0x61cf16b9, 0x9d2fea4b, 0x4ce67a0a, 0x88048ac3, - 0xbb162c1b, 0xf30fc9ef, 0x79312cbe, 0x0727c8bf, 0xa73df6b4, 0x55c7420f, - 0x945c639e, 0xeaab8e58, 0x8f16061d, 0x009b8fd1, 0x1c5fc6e3, 0xf79b153e, - 0x413b074f, 0xc68aa70f, 0xca3746b3, 0x665ffa45, 0xfc0a4e08, 0x13f314de, - 0x697e3a24, 0x2dc63b5d, 0x11deca4e, 0xbc80bcbf, 0x4b3fb9ec, 0xd528f1d2, - 0x15a4bcbe, 0x813f99e6, 0x371c444f, 0xf8e54c7d, 0x04c93fa9, 0x4f3910e4, - 0x4862657b, 0x063bfb86, 0xf90cc862, 0x161bf33b, 0x4fbc01e7, 0xe547bf81, - 0xdf241de6, 0xb5207886, 0x9cdfe099, 0x00198621, 0x7de433a7, 0x1e1538db, - 0x87232572, 0x94829533, 0xf1c14c1e, 0xefc1fddd, 0xb4d41532, 0xb9e0638a, - 0xc23ff8a4, 0x72471877, 0x50b7980b, 0x897b9ec0, 0x97e81ab9, 0x3f1a51fa, - 0x9a51fa8d, 0x34a3f53a, 0x437222f5, 0x1425e402, 0x9f13293d, 0xb4d27080, - 0x88ec928f, 0x555262c7, 0xafd1f603, 0xbe6dfc79, 0xe903489d, 0x7d5fcb3e, - 0xee90b336, 0xc5896ae7, 0xf57394fd, 0x0e0cb145, 0xa33e25a5, 0x7f73d2cb, - 0xddc61b47, 0x8c3f2548, 0x6fcfcec7, 0x051e6236, 0xdc994ab4, 0x7de949f4, - 0xa20d89ff, 0xfd06c22b, 0xbd6573e8, 0xff7fdfc9, 0xf212fdfa, 0xb4a3ee38, - 0xfa01266e, 0xc02791eb, 0x09d723f7, 0x7e185f2e, 0xaf74e42a, 0x013ba7e8, - 0xf143e37e, 0xf574fbac, 0x4abe1cd5, 0xfb5d29fd, 0xfd2f960f, 0xbcbe4688, - 0x93efba29, 0x027933c6, 0x00a417f0, 0x1e0fd7f2, 0xf8c7a93f, 0x7f1f81ab, - 0x6907f1b2, 0xff8e9ef9, 0xfeba4fd4, 0xbfd63d61, 0xcbfadc3e, 0xbb697d5f, - 0xd297ea97, 0x23653c3f, 0x494edf94, 0x8a4e09b5, 0x2b8db2f7, 0x3b902e6d, - 0x7c06d792, 0xce27ca71, 0x870f4708, 0x06a57cb8, 0x78804588, 0xc749fc2b, - 0xa1e9bd3f, 0xf89ec0eb, 0xc76ca36a, 0xc99d6a38, 0x5cf4a26f, 0x8f28b0d1, - 0x3b7ac18c, 0x16703fab, 0x51b2bfe8, 0xd3a6a23e, 0x953ddfd2, 0x94357900, - 0x921a0652, 0x7fa3f4a0, 0xf3e1b152, 0x546f60e9, 0xabf20092, 0xff983dfe, - 0x87d4589b, 0x9ee8c685, 0x499818ed, 0xafd9f780, 0xb3a1e1b2, 0x6afe0da2, - 0xbe9038c3, 0x37f7097f, 0x3f6b245a, 0x82b9273c, 0x54f2015c, 0x31f10781, - 0x8bc5637f, 0x4ed31abf, 0xe1b1d3d7, 0x0541364f, 0xea4fc527, 0x9bf05fae, - 0xcbbd1dd7, 0x87ca4eef, 0xd156bb6a, 0xee468e4f, 0xb2b13527, 0xaedbf64c, - 0x6ca4f2a4, 0xd2f4ecbd, 0xbd2f65c7, 0x2067dbf0, 0xc9a1fd7e, 0xbf8e9c39, - 0x073da5f8, 0xe2fad127, 0x3cbf722d, 0x908b0db6, 0x254bc210, 0x7a597ffd, - 0xafa50f08, 0x463a31ec, 0xc6f7e7b3, 0x78b1f086, 0x19232ecb, 0xb91e13dd, - 0x6d8cbbf5, 0xa9783096, 0x760e9f6f, 0xbf178adf, 0x3bbc8236, 0x892053b5, - 0xb9e061c9, 0x85da0f7e, 0x23c42700, 0x6f1053c7, 0x1495feba, 0x145fa02f, - 0x37dbe93c, 0xe3027971, 0x9e90d239, 0xce9d7e5f, 0xc991f25f, 0x792ffb09, - 0xec1b2ef9, 0xc55484e3, 0x95d9fae8, 0x4adf2009, 0x1d826f64, 0xe4bcf64b, - 0xde91bbb9, 0x9ddff78a, 0xae92e2c0, 0x95d406fe, 0xbfb0fede, 0xe0e6eb85, - 0x1b888afe, 0x59e4aee9, 0xcb47df31, 0x6332252f, 0xb8be184b, 0xf2726656, - 0x2354f3c4, 0x509dfdd0, 0x22fbc0f4, 0x627703d7, 0xbe6ef3dc, 0x62316a17, - 0xc3334bfd, 0xc0d930d3, 0x2bd32ce5, 0xf0dd7a41, 0xd38bea00, 0x70895d83, - 0xd21956be, 0xc437a80f, 0x1912d3fd, 0xc19e987e, 0xc99ea8f7, 0xbfd0e785, - 0x8c457655, 0x7a87bcd1, 0x297f9945, 0x3bae9f9f, 0x13b5ec12, 0x8ffde109, - 0xdf0acb9f, 0x4542bb53, 0x66fe2a5f, 0x3561befc, 0xdf856fe3, 0x4067337d, - 0x180717fb, 0xa07bc0ff, 0xfcbae967, 0x6bbed889, 0xc0f280b6, 0xf8e1fc44, - 0xf9cc837a, 0xd0aedb5a, 0x24b75d09, 0x05e8ab44, 0xf8458fc6, 0x7a2f5ea3, - 0x92a7be92, 0x9f309597, 0x0a78e7ad, 0xfe7316df, 0xf96b219f, 0xef8bac9f, - 0x99653e53, 0x33edfbec, 0x3f94afc0, 0x57e00ebd, 0xfdf61f39, 0x07cdcdb7, - 0xfa7ca66f, 0x4f857ab7, 0xcf53f2b5, 0xef5b25a7, 0x7a9f4026, 0xa0dbfd3e, - 0x4f96122a, 0x7cb0f3e9, 0x7feda83a, 0xf02a7e54, 0x45f802ab, 0xc8a7e085, - 0xa8e0dec3, 0xd9568797, 0xd21e5611, 0xd99201df, 0xba14fe93, 0xf4ade853, - 0x4143e5f7, 0x52e904ee, 0x5d20bba1, 0xdfa7742a, 0xfa7e16af, 0xc13249f6, - 0x26bfe575, 0xd65cffa3, 0xe942f2c4, 0x66077b7b, 0xa85c9c20, 0xdeed48c6, - 0x75d4fd81, 0xaf5eae9f, 0xd5d2efeb, 0xddfd75f3, 0xa6957aba, 0xb363597f, - 0xfdfe2091, 0xb2e27e9a, 0xb8d1c867, 0x63eaf470, 0x59c3597e, 0xc2e817a3, - 0xe5f7c012, 0x790bc4e5, 0x221d8186, 0x28ba05c6, 0x7e206b8c, 0xe7d939b1, - 0x656372a5, 0x743f8b04, 0x58b603d9, 0x618cae5a, 0xb1bc40f5, 0xf29ee406, - 0xe2c1103c, 0x01f95d8a, 0x9fca8c5b, 0x51126f6a, 0xc8f9b76e, 0x167e708c, - 0x47c828d5, 0x76b7a46d, 0x4d35ee76, 0x06590cb4, 0xd15aa571, 0x1df83609, - 0xe0d937d5, 0x29aba9dc, 0xfa02faf5, 0x451fe17c, 0x8ae97b4c, 0x75818db4, - 0xea4baf11, 0x4e6ff2af, 0x59d3ef12, 0x9a0b7f74, 0xc7739f98, 0x423d9d1a, - 0x153d20d6, 0x411a9659, 0xe27f529e, 0x86bcf688, 0x1f2945f1, 0xb69d64af, - 0xd29f795d, 0xa5f3fa01, 0x6eedb41b, 0xa07f0fee, 0x3258c9f0, 0x2ca3fb96, - 0xf2e5c30e, 0xfaed3134, 0xae8f8a02, 0x68989116, 0x4449bbbd, 0x166f747c, - 0x234f107c, 0xb7e478de, 0x7940120a, 0x03a9c0a8, 0xbbd8c9f8, 0xf6d8eabc, - 0x812fe669, 0x3c7fb66e, 0xd9693fe6, 0x11c3fdb1, 0xd5fd406f, 0x263e4343, - 0xeee7fb3d, 0xff73c08c, 0xa4569dae, 0xef1daef7, 0xd425f90e, 0x6139335f, - 0xbf3b5d9d, 0xd3f4031e, 0x0254dcb5, 0x306baef2, 0xd8aec78b, 0x3698f5f1, - 0x33f7afd4, 0xfe6461fd, 0x3fd37761, 0x41fa133e, 0x76057749, 0xe428cec3, - 0x23d7caa7, 0x6bbbdf30, 0x6e99d7c7, 0x9fb74fcb, 0xd1e79e0a, 0x5b052565, - 0x2c317d61, 0x8df2a18f, 0xd3542f89, 0x761bcbf9, 0xf6d01719, 0x39ff37dc, - 0xd768e406, 0x750f6656, 0x41cf6dca, 0xf194431e, 0xe29972dc, 0x8a9813ab, - 0x33bfcd3a, 0xdf02e466, 0x3fcb84f4, 0x57d63e31, 0xaffca478, 0x62e08781, - 0x33eacef2, 0x6fefb00b, 0xe318fb3f, 0x4ba4269a, 0xab7fbf65, 0xe57b46af, - 0xfecefb62, 0x82df6e7f, 0x76fb2fbf, 0xfbef9bff, 0x7abbd738, 0xe749e83e, - 0xfac1ee3b, 0xae27564b, 0xeef48fb7, 0xffc7fd85, 0x7bffeefb, 0xc52b7de3, - 0xfbe2edbb, 0x5affcdfe, 0x36f1ffbc, 0x7e3b778e, 0x3fe6f3d7, 0x57df7d71, - 0x6ff9bdce, 0xf6def78e, 0xadf5d8af, 0x067b2a86, 0xa9015f5d, 0x316182b5, - 0x92dbbe37, 0xd76c80e1, 0x8f30fd73, 0xc34bce0e, 0x23014df8, 0x904d0bf3, - 0xfb7e0747, 0x0b89411c, 0x1d751fa2, 0x1bae1fb7, 0xc8768254, 0x9987ae75, - 0xb55520dd, 0xadfed366, 0x989c0b39, 0x0fd24973, 0x7b3ea1bb, 0xfd6baf32, - 0xe204f7c9, 0x7f1da812, 0x2d35ce5d, 0xef5ed760, 0xa5eed112, 0x1fbbda25, - 0x9ece990c, 0x3dfad04f, 0xfadadd73, 0xfada054d, 0x8dde3e1c, 0xc6ffad84, - 0x7107c17c, 0x13f65355, 0x356710f1, 0x9089942d, 0x5542f90c, 0x98bfc12b, - 0x7f7daf93, 0xe3c1f81f, 0x531c3c7f, 0x971c0a4d, 0xb6485c20, 0xfa48dce8, - 0xeebe4700, 0x7d63d9d6, 0x244ccf90, 0x8de38327, 0x838c4ee5, 0xe65b7f73, - 0x5596cbef, 0xb2cfc0ad, 0xfc56cfce, 0x4de0dee5, 0xe38dffb8, 0x2fe084a4, - 0xbff444bb, 0xadff9d65, 0xe2fbe5e0, 0x8fe3c143, 0x3a97cbc5, 0xb8b20cbc, - 0xccabf008, 0x16a985fd, 0xca0fab27, 0xc8de7827, 0x9fa905fd, 0x42d3788b, - 0xcc8bdf79, 0x5f386ce6, 0x30148f33, 0x1afd71de, 0x3983f511, 0xe575c04d, - 0x8f31904f, 0x7e4373f8, 0x6f3be026, 0xbf1515dc, 0x0270cb60, 0xb871173c, - 0xb42a9117, 0xeff9c95f, 0x84cacbbe, 0xf6820673, 0x211722ef, 0xadbf52d7, - 0x47f04b28, 0x4b157852, 0x0e9d1bc4, 0x1c816f71, 0xb5bdc4d1, 0x47fdf875, - 0x8b9c6842, 0xbe4deff5, 0x5fe5d4fc, 0x323b3ca9, 0x1e41fa8c, 0x5849bb9e, - 0xaff156dc, 0x70626f6f, 0x7c132cac, 0x7e774829, 0xee755f39, 0x83e71cf8, - 0x0e3bdebf, 0xa3f664e5, 0xefd1a3a3, 0x6fd03977, 0x437ee4a8, 0x0d11d7b7, - 0xa6eeae71, 0x9b3e7e54, 0x55cb536b, 0xfdcfdca5, 0x7e40bfee, 0xa6bb2d21, - 0xf822b50a, 0xf1802471, 0x08d4ef5c, 0xfe4c31b2, 0x1931ffeb, 0x6154fd38, - 0x627e001c, 0xfd91e026, 0xd1abe98a, 0xadbc2ab1, 0x3494f6b9, 0xe01e27a6, - 0x0e754477, 0x0be163f9, 0x75c03e7e, 0xf4db447f, 0xadfb30fc, 0x5638b135, - 0xe2df5bde, 0x34379c77, 0x9700cb25, 0x9a8aa61b, 0x2655fb73, 0x238d97ee, - 0x795d60e3, 0x9b655d6f, 0x11697808, 0x66ddf09d, 0xa359d365, 0xb079cc3b, - 0x3e309e1e, 0xca8fd5c4, 0xe78022ce, 0x082387d1, 0xf2efd1f8, 0xf834c673, - 0x430d226e, 0x2b882e3a, 0xb5c39afe, 0x72c764d3, 0x1cb65e56, 0x6b4de74f, - 0xa3858fb0, 0x7fbc01d4, 0xe3211827, 0xbd878921, 0x501bf4a7, 0x1bb5fac6, - 0xf6e115ed, 0xed823c3f, 0xef3898bf, 0xfbfc2099, 0x51fb2de1, 0xec073fab, - 0xae3ca983, 0x09ae83d2, 0x0cf747f2, 0x1bfa07c1, 0xe7ac61fc, 0xdf84efb1, - 0xbeb3be55, 0x8559e981, 0xde70f5ee, 0xccace1cb, 0xe2c4dc7f, 0xfce27faf, - 0x8159c0a5, 0x4abd7eaf, 0xa6af2a7f, 0xd751e3a8, 0x197d8e37, 0x268a9bec, - 0x43a06ec1, 0x466d4855, 0xc6cac3e0, 0x6f3864c7, 0xe360eb99, 0x8c7f2912, - 0xd3a09f3a, 0x9a3bf2c4, 0x0dbcafd3, 0x1adce4e8, 0xe242e813, 0x0dace3ba, - 0x06bbf0e4, 0x7be19fe7, 0x227bef6a, 0x790178d9, 0xcea7b1f5, 0x8f525535, - 0x9ceb8c9b, 0x432d9655, 0xb296ecf8, 0x8aa2725d, 0xb14d3a9e, 0x1f3caed8, - 0x8748e650, 0x5c3e74e7, 0x1311f787, 0xd242ef81, 0xfbf15bea, 0x62aa5bd4, - 0xd4961d18, 0x3d6232ef, 0xf32bfb19, 0xf9e8f329, 0x369e7669, 0x6e4178ef, - 0x4b8020db, 0xd4bfc99e, 0x1f4e8619, 0x8ee72b33, 0xb84f53df, 0xf98edd28, - 0x2c4f48ff, 0x1b44f455, 0xef2bb9e6, 0x3e3335cf, 0xc489e957, 0x49627a70, - 0xf01123b5, 0x6a4764b0, 0x92c93022, 0x084b4e3f, 0xf03e27a7, 0x43e373b0, - 0xaeeebbfc, 0x5c4f54d9, 0xb313d2ae, 0xf44e9023, 0x959ae5ef, 0xe88b8d73, - 0xff6f0509, 0x03e6f2c3, 0xf86113d0, 0x56b346fb, 0x54d8dc4f, 0xc6e27a88, - 0xfbe6a2d9, 0x17cd6baa, 0x09d913d3, 0x3b2eb173, 0xcfd0c2a3, 0x39bfdc07, - 0x61fbf3c4, 0x6b17d01e, 0x9b8476cc, 0x26f46f5e, 0x55f6c7d7, 0x825fffae, - 0x97d722b3, 0x43f761cc, 0x8243a4f4, 0x2e64bcf4, 0xd002eb95, 0x4beb9323, - 0x4e71e56e, 0x07cd9c9d, 0x96a19b39, 0x0afdecb3, 0x950bd337, 0x9abfc98d, - 0xae6fdb47, 0xda669d95, 0xdc90e6ff, 0xddcb54cd, 0xe1096635, 0x96ee43dc, - 0xae7bb930, 0x4fda1c69, 0x53efedbd, 0x3ca96f2e, 0x430ce61b, 0xa2f3051f, - 0x1ddfdf34, 0xda76fb1d, 0xef2fc02b, 0xfb7e788a, 0xf603b739, 0x033b7d8d, - 0x7c53e9ec, 0xfcb8db3d, 0x5cf8f4eb, 0xc81ca953, 0xd3d983bd, 0x84459be5, - 0xe303455f, 0x91618aff, 0x4fad073e, 0xcf16ff4f, 0x60ef1761, 0x0774b0e7, - 0xfc2ad979, 0xadb77e2f, 0x1605ce06, 0x1cf017af, 0x005fbe19, 0x78731678, - 0xe3173916, 0xdaf14a39, 0xe53fe7f0, 0xa6a2dfbc, 0x5f0f18f5, 0x2bf6d3e4, - 0x29f5761f, 0x4cf247f0, 0xaf790f0c, 0xc9f5be08, 0xeba0cf90, 0xe78d5ce7, - 0xdaf5e547, 0x7ef907e7, 0xb4fe8a17, 0xe4fbe857, 0xd3bfcccf, 0x1ea0fbc3, - 0x123f252e, 0x5c29fb2e, 0x70f5fe32, 0xd40e0de9, 0x01f3c7be, 0x2b0e3c3d, - 0x649d2572, 0x6e7e1f00, 0xf15ca170, 0x42e143be, 0xb1e3bbe7, 0x40fb9ae1, - 0xbcb8738e, 0xf4d7706b, 0x02157e87, 0xb75e2bf6, 0xad024f65, 0x6327abcf, - 0x78a178e1, 0x070f56ad, 0x03837ef5, 0xaabcfaf5, 0xc7e4022d, 0xfbdfe42e, - 0xc31ef895, 0x5d6e547b, 0xed3cf546, 0xe4dd20bf, 0xfdf07386, 0x9b940111, - 0x47c6dd0a, 0x8e25fb30, 0x03a3a1cb, 0x3f515302, 0xe4760a35, 0xd3047f47, - 0x704f1457, 0xc4f34bbf, 0xbc73a7af, 0x2352b8b0, 0xc52563c3, 0xf4f3f01b, - 0x63af5e26, 0x4a2de076, 0x39f05ebd, 0xbbab9004, 0x8c5f7664, 0x8e04e240, - 0x847e9504, 0x04ecd5f3, 0xb4779e15, 0x28dffa33, 0x8f81f138, 0xf043f7fe, - 0x33dd2bdc, 0xf4afa63b, 0x3e29c0ae, 0xfde78b42, 0xe379ad11, 0x9bf9c1fa, - 0x737bc4e0, 0x9cf0629a, 0xbb2d58e8, 0xbf9525ff, 0xf00be7a7, 0xd1f7d43b, - 0x438584cc, 0x088cf37e, 0x79c50fcc, 0xa65d9853, 0x7bfa4f96, 0xfe6fbe80, - 0x45692551, 0xc7942c7b, 0x04de7ee8, 0x3410cde3, 0x09104ef9, 0x09ff3a03, - 0x7cd5bfc6, 0x9249f181, 0xef96f31d, 0xedcf2bb2, 0x5e2cbbec, 0x799c1e6f, - 0xef851e68, 0x13a255b9, 0x0c9ba85c, 0x2059838e, 0x09941e6f, 0x7db9cbf0, - 0x81e98bb2, 0x853bd428, 0xefc51eef, 0x0e590ad9, 0x8fbc291a, 0x7ca397e9, - 0xbd511f3d, 0x0a5882ed, 0xf70f1fa9, 0xee76cce0, 0x7880e69a, 0x95fec64b, - 0x2b39ce70, 0x20f07ed7, 0xbb3573e0, 0xaac8e907, 0xeed3f45c, 0x7e4053ba, - 0x06f14c3b, 0x9d99cfef, 0x9d20f07c, 0xf155d6f7, 0xcf396e78, 0x9c237f15, - 0x27dbce63, 0xdfb41d3a, 0x16adeb82, 0x66bcc738, 0x2adc48a4, 0x5a4adcf8, - 0xaf33be31, 0xb039ceea, 0x0faa12ee, 0xf72864c5, 0xfa844b4f, 0xafdf013a, - 0xf08dbaf4, 0xdaeb66bd, 0x3a0cc6b3, 0x07ed117f, 0xc75caf60, 0x106e55fa, - 0x5dfa909c, 0xca18f4d4, 0x020da2cb, 0x4ad3345e, 0x1b335fed, 0xe3a667d7, - 0xefa3aeb6, 0xbc317ad3, 0x886ee30f, 0x27ce11b9, 0xf13ae92b, 0x78d509fd, - 0xdf445d2e, 0x75a4cda3, 0xde389dc3, 0x810275a2, 0x264b03ef, 0x01323f24, - 0x3b27dbc6, 0xaed0fda1, 0xdd611b5f, 0xfaf9d1b7, 0x8817f1d3, 0x3fa0d36d, - 0xc760a5f9, 0x46ea87fb, 0x0baddc60, 0x542f0c36, 0xe63ac70d, 0x0c103b13, - 0x651f3a92, 0x4efb0447, 0x755968b8, 0xcdabec0d, 0x406c9f1b, 0x046b3aba, - 0xc28c7e3d, 0x3c874ddb, 0x2e79646a, 0xc6a3decd, 0xfd1c9536, 0xdf152228, - 0x1b31a3bf, 0x921626f3, 0x709bcc7c, 0xa47b3357, 0x0f84657d, 0xb2ed6ae2, - 0x6f3c087d, 0xe7c2695e, 0xfd312f9d, 0x0db839d3, 0xd627dbe3, 0x5fbe04c9, - 0xf52eb15c, 0x89e3c069, 0x9bd232cd, 0x1bcb2cf8, 0xc5897e28, 0xb1d79ac9, - 0x352c4f71, 0xa0b57bb2, 0x5f8bd69d, 0xb40af254, 0x51c8ac72, 0x2f4a728a, - 0x6b72f497, 0x46d593d1, 0xf21ed920, 0x9474e96a, 0xef54a557, 0x90f5a100, - 0x306a8357, 0x5797aa6e, 0xc8a2c495, 0x5f8874a9, 0xbe0f9616, 0xf1d02d6d, - 0x8183ecad, 0x5f6bff56, 0xb77a053e, 0x49e04acc, 0x5a7f6485, 0x80417460, - 0x6d35e65f, 0xa0f812f9, 0xde045e64, 0xf01c75c7, 0x26b37c00, 0x8bafcf0e, - 0x6f08857c, 0x78b72f25, 0x95ce96ad, 0xb75ce3f8, 0xfd6a5c48, 0x5c451255, - 0xee877eaa, 0xe74af4a3, 0xf051bdb9, 0x743ca881, 0xbbdefb5f, 0xc76eb033, - 0xf6e32d75, 0xd22b1ac1, 0x9f9fa1f3, 0x7af4095d, 0x0102bddb, 0xdd789d7b, - 0x2b0fa035, 0x880e0ad6, 0xcbdf170f, 0xefa62fde, 0xfd0fbac3, 0xa515d19a, - 0x7fd0076f, 0xf6c7bac5, 0x820dff62, 0xb43fc603, 0x89ed10be, 0xb048af12, - 0xfa3b437d, 0x614f540f, 0x57b3599e, 0xaffa004c, 0x0764dfb8, 0x23a14953, - 0xf9db2e85, 0xecc4087d, 0xbe8b331c, 0x15160ab7, 0xc51e93df, 0x4fa82102, - 0xbd2a4e81, 0x5fdace8c, 0x36409d92, 0xf64ba717, 0xae09fc1d, 0xe767c55f, - 0x74ef874c, 0x047ea98a, 0x975e6d3a, 0xe23b046b, 0xfcc04f84, 0x49749e8a, - 0x4a3b6a2c, 0x0567cba1, 0xd07baf26, 0x7b0e8ea3, 0x4ba71dd0, 0x5128fe85, - 0xb6595fa3, 0xfdf0264f, 0xdd1e9ebd, 0x908dfd72, 0x32f851ff, 0x6f5d0fdd, - 0xd1cfcd6e, 0x48e0575e, 0x2f5009eb, 0x8fde5892, 0x12e50fc2, 0xdefb0fcb, - 0xbfcdd3eb, 0x87e78229, 0x2c883f01, 0xe74fc97f, 0x0bf37b7d, 0x66792f98, - 0x6875fb53, 0xe941bcdf, 0xd9bfe000, 0x7fe8fc4a, 0x950e50f8, 0x6f988836, - 0xe67f244d, 0xaedf952c, 0xfe2cbfe4, 0x5de11583, 0xcbe4d5ba, 0x6e97efa3, - 0xf3063a3f, 0x30079611, 0x49bbc7bf, 0xde1fe760, 0xfdf031b6, 0xf2c4a950, - 0xc176f470, 0xe71648f0, 0xaa2d78ea, 0xa136ec00, 0x57b3dd8e, 0x6c937f5a, - 0x0775c552, 0x2f38ca45, 0x63e787ed, 0xb8678a5e, 0xa7d6011f, 0xc94ddfbe, - 0x9178e9bf, 0xa3695fd1, 0x695cf68c, 0xc84e96dd, 0x6c3d2cc3, 0xb2b73f42, - 0xfc11acee, 0xbc3fdcd8, 0x55f3f784, 0x3c9a8a36, 0x6ff91ebc, 0x04dfa275, - 0xe50d5bf9, 0xeb437e78, 0x0faf58ed, 0xb17a079f, 0x7fc5ad3c, 0x4bddb1d8, - 0x95f8b841, 0xbef0d9df, 0x368dd6be, 0xeea9eefc, 0x3da7f9c2, 0x57eaddf2, - 0xeddf305f, 0x0941fc34, 0x5d48baeb, 0x931d60be, 0x997d746b, 0xc4e261f9, - 0xa5eb7b41, 0x7c839f2f, 0x7fad8eec, 0x5bd60e7b, 0x9ee75ff6, 0xb21abc83, - 0xf60ec233, 0x0fa6e548, 0x79559f30, 0xd99224af, 0xfe2f9d7f, 0x3b80f30e, - 0x6139343f, 0x271dceb4, 0xd1bd8086, 0x04dbe5b9, 0xba5defc8, 0x73c61a63, - 0x4dcb6e96, 0x05e26124, 0xeb74094a, 0xb21e43eb, 0x0dcd5f1e, 0x73ff98cd, - 0xe41be286, 0xb17f3043, 0x83e59cbe, 0xe2de783a, 0xdef9f0e6, 0x1b14f23d, - 0x193f5d66, 0xb30362e4, 0xaf9a2e0b, 0xf1e28078, 0x6fe03ef2, 0x4f2e6af3, - 0x0cefe3c2, 0x54f141fc, 0x57cda913, 0xe161b2fc, 0xb6819e6f, 0xf35eb886, - 0x807dfd15, 0x3e4f929b, 0x58f5d22b, 0xd6cdf024, 0x287e63df, 0x01cf2de0, - 0x21cbf9f2, 0x293e1710, 0x10fe3007, 0xefc261d8, 0x1c774b2c, 0xdce9fe42, - 0xb5f31fb6, 0xeeebcf09, 0xcb1fc124, 0x9eb1e5c3, 0x96560dca, 0x0fe1c8e7, - 0x1b0e9079, 0x8ef9e73e, 0x3c958e8c, 0x1ff2dec8, 0xf853225b, 0x4f2c2a7d, - 0xc7c37cb3, 0x8430af3c, 0xe002612f, 0x7982fda9, 0xec1c0aa5, 0xd42b8700, - 0xf3e1bcf9, 0xdf79834c, 0x3f805f1c, 0x7cc1d390, 0x041f5a5d, 0xe13e9bf9, - 0x0f230910, 0x3cb3d73a, 0xfc394ee0, 0x7e4accf7, 0x4f9eb36f, 0xebcb7d7d, - 0xbffad8bd, 0x221a7c2f, 0x1eae381d, 0xc3e71d4e, 0x9ce3f1cb, 0xf7f07fef, - 0xfe826521, 0x81cf93fb, 0xda1bcb1e, 0x899f788d, 0xfdf13fe2, 0x5a78f076, - 0xf31126c7, 0x9bea6b3e, 0xe5eb8e51, 0x273f0545, 0x1bf7afd1, 0x468adebe, - 0xb63a27a6, 0x3a167d5a, 0xaf5bc74e, 0x6c573d21, 0xd3bcc76e, 0x18af75bd, - 0xcbe754db, 0xaa7c27a0, 0xbcbc77f5, 0x6dca0c6b, 0x7e98bf7e, 0x9b14631e, - 0xfc29b2a7, 0xcf9b953c, 0xec59e66a, 0x2dda37ad, 0xb4ef9f17, 0xc609bae4, - 0xeccadd3b, 0xe2f5d3a5, 0xf9985f0c, 0x49bd714f, 0x0f3b2d48, 0xef12faa5, - 0x7bb2b359, 0x245b44d5, 0xad4b5fda, 0xf7470e13, 0x7988d283, 0x79aa2b2f, - 0xce7dcc9e, 0x0af7c024, 0xd604d5eb, 0xabe012bb, 0xbb65e3f2, 0x26dd809b, - 0xa867e527, 0xf59459cf, 0x8819fb1b, 0xa5ff854f, 0xe08919d6, 0x3bc9127f, - 0x5d71d608, 0xe812d7ca, 0x8b0f56bf, 0x47f393df, 0x56f3c187, 0x8e27bec9, - 0x553adb8e, 0xb5e84270, 0x34fbdd27, 0x2e998671, 0xf8b17ded, 0x5fdd1c0d, - 0xf680d3b7, 0xb7e0d5a0, 0x1ac42ed3, 0x0e849ad1, 0xa43883ac, 0x0214fc04, - 0xf41e21f3, 0xfdc16798, 0xcd4236c8, 0x94e7e853, 0x449ff734, 0xf774904f, - 0xc30390a1, 0x385abd28, 0x39712abd, 0x8e9bfb2b, 0xacf786db, 0x6a91a4c4, - 0x5635df20, 0x4f0dda37, 0xe869fbf0, 0x41e4246f, 0xa74892c4, 0x3a26fefa, - 0x38fbe6af, 0x1ea6af3a, 0xe3d6d2e3, 0xc2c74866, 0xbe3897e9, 0x05a2e98e, - 0xcd3310e1, 0x796bf8a0, 0xeb4213c3, 0x4e27898e, 0x6b5fb43f, 0x2801efc1, - 0xfbd5797b, 0xebb458b0, 0xc8d3eba6, 0x36b4e889, 0x53ad81af, 0x1c4edcf3, - 0xa5dfee02, 0xabd74e7d, 0x714617a9, 0x09112779, 0xdcc59de4, 0xbbfc384a, - 0x5fbef035, 0x013837da, 0x5fb843f0, 0xcf9025ed, 0x41f7cd12, 0xb7f4d7e7, - 0xcd807443, 0x0c871daf, 0x43bfabb2, 0xbfeb9cbd, 0x25fc9651, 0x329e9451, - 0x62615687, 0x49125676, 0x9ba5efc3, 0x4a7ca1fa, 0x79839659, 0xa32d4227, - 0x086b61ab, 0x00b0cdf2, 0x3fba9bcf, 0x9351ed12, 0xd2237899, 0xe2367be1, - 0x1661d395, 0x7043cf1f, 0xa1d0372c, 0xd69455a4, 0x814d7be8, 0x8a42c31c, - 0xa2687a84, 0xb94657e3, 0x9f28a3aa, 0x2774ccd6, 0xf6c2c619, 0x3bb95ede, - 0x52f6b90b, 0xaa1a0888, 0x1969eef7, 0xef04228c, 0xbdde20f1, 0x6bc6807b, - 0xec153a95, 0x6d7f9df0, 0x32eeb064, 0x9b5f7953, 0x3e8feac2, 0xdc2577b4, - 0xcf6e9337, 0x49f6147f, 0x7851f6cc, 0xd58fe5de, 0x9bddf3dc, 0x39d6517e, - 0x173f8372, 0x3abe05ee, 0x1df5eec0, 0x777e0d6e, 0xa3787a8f, 0xd1fba945, - 0xd86fc88f, 0xbcad728f, 0x1bb63f7e, 0xa1cb4ea0, 0x81dcfe71, 0x472f9f74, - 0x74969a1d, 0xa1af1d29, 0xd93e0930, 0xd0ea357f, 0x30eef81e, 0x578f8704, - 0x82141eee, 0xc3fcb483, 0xd5932d3d, 0x0f70f870, 0x857d21d8, 0x7d0fabc3, - 0xebe87088, 0x6c5d29be, 0x935cbc07, 0xd6fbc06d, 0xc16c38ae, 0x45fd0af8, - 0xe3e23ea0, 0xbbe5efac, 0xa11fc56c, 0xd354ece3, 0x429ef297, 0x4dd1bd57, - 0x628fb12a, 0xe96a6cf7, 0xf5ca2ba7, 0x25abac36, 0x358f75ca, 0xf78ff71e, - 0x76e35c00, 0x0b8ea73b, 0xb8b135d1, 0xeefdc1c7, 0x5bf32ca3, 0xf2f254a3, - 0x6225ec9a, 0x81c9c40a, 0xfb43e217, 0x8de65f89, 0x19f74118, 0xde6032ef, - 0xfb8b28fc, 0x2b63cc20, 0x7721f808, 0x1ee20aec, 0xbe218827, 0xd9abe650, - 0x9af5fcc1, 0x396f8342, 0x6015ef3b, 0xb47d10bc, 0xc023e8e9, 0x1db1a3e8, - 0xa9a2a3e9, 0x6347d19d, 0x06644e75, 0x3f03373b, 0xc60496bf, 0xa23bde02, - 0x51269abe, 0x151a1ffa, 0x91ba01a8, 0xe5a6e7bd, 0x3d708a5d, 0x7c3f161d, - 0x7abeca7d, 0x4b6d6fc3, 0xe06943ca, 0xe033ee4f, 0x37029779, 0x858c5fa5, - 0x58b6c5e5, 0xfc035fdd, 0xedb4272a, 0x6d6fed85, 0x36f31f79, 0xd86efb6c, - 0x66dbef05, 0x42390c53, 0x5beed6f3, 0xd767f78e, 0xd87dd806, 0x05e024d1, - 0x3c3bdebd, 0xe104ff18, 0x1a4f7601, 0xf91da3c0, 0x5eff1365, 0x7051ab2c, - 0x1a1f9e81, 0x890deec5, 0xebf3b0b4, 0xd7111621, 0xcec2c439, 0xbdf7e259, - 0x95bf8225, 0xfb01bf75, 0xa69943c7, 0xbcfdffde, 0xaf89a4bf, 0xe854f82b, - 0x28d24a89, 0x4ce47fb8, 0xa2d13b8c, 0xa8d89fa1, 0xca78d514, 0x88788f7b, - 0x47aa0ef3, 0xff3dd8af, 0x94abd02e, 0xfc00be7e, 0x968dfb04, 0x4a6e0023, - 0x70cfa07f, 0x0defa1f8, 0x1e60f987, 0xecb617b0, 0x3de2225e, 0x6bc47d1a, - 0x491bdc26, 0x914667fb, 0xfdf4adaa, 0x425a68cc, 0x13d78e3d, 0x2b207d79, - 0x1a713f53, 0x3d7cfa04, 0xb64ebb8f, 0xc931fcf0, 0xd186ea3e, 0x5c766750, - 0xea245256, 0xe16f8505, 0xb738080e, 0x75f9f896, 0x00c5204a, 0x58f85378, - 0x56fc180a, 0x2452b4aa, 0x18f20187, 0x7dd0f1de, 0x9dcbbd4b, 0xdf652fab, - 0xcf9fea71, 0xc1f9ebe4, 0x3d17f5f6, 0x099eefbe, 0xb7372df0, 0xad03723d, - 0x0e7a5c57, 0x479707cf, 0xa1795c55, 0xebf42f7b, 0xdbfce77f, 0x4d874051, - 0x7ec298df, 0xe1c3550f, 0xc029e2d6, 0xbdf932f7, 0xc951242e, 0xb1e55633, - 0xcbb71b42, 0xf8299510, 0xffaced1c, 0xf8081140, 0xf0b14af4, 0x9e32547e, - 0xe5d14e1f, 0x9f87fead, 0xc132f9c5, 0x71250030, 0xcf3628c9, 0x324ecc37, - 0x9ce0ffd3, 0x173f1a69, 0xaf72477b, 0xdef1d2b0, 0x357cec21, 0x19aaae33, - 0xc6c4c4ea, 0xfbda26cf, 0x6b13320a, 0xb8c2c6a7, 0xdf18c9d1, 0xdaeb35ca, - 0xc812bd53, 0x8c9a9269, 0x88d38979, 0x7a633eca, 0x08eeed03, 0xe3902eba, - 0x742c8cd7, 0xe7ede54e, 0x4d43ffe8, 0x2a99f6e4, 0xc72ae37f, 0x8d54e75c, - 0xf78b52fd, 0x9fe9fd01, 0xf2e1ede2, 0xfce33e2c, 0x77c9e2df, 0x1eb3f9c2, - 0xe10e399e, 0x27a3ab7e, 0xd470f5dc, 0xab815dc3, 0x9fd98e1e, 0x86c6a738, - 0x2e1e9381, 0x48ed48d3, 0xdc0a63d0, 0xc77970f5, 0x9de2e8cc, 0xabde1334, - 0xe0c48ef8, 0x23350ef8, 0x9ba41ea1, 0x01ef1168, 0xf5e28cce, 0xbab04737, - 0x64a8ef82, 0xae1eb7c4, 0xc666387a, 0x58e3f7f1, 0x2f00bdff, 0xe202e509, - 0xcc9ba147, 0x31ddaad4, 0xec507a2a, 0x2e1c69eb, 0xfb46bed4, 0x8ade3739, - 0xafb02671, 0xe08425a7, 0xd6ce5b96, 0xf2dc3b95, 0xf4a9f83c, 0x72bfbc75, - 0xff3fe10a, 0xca2f3c14, 0xce0555e4, 0xdad1be53, 0xa69ad3c9, 0xc338829f, - 0x7efb9350, 0x1080cfa0, 0x1475e783, 0x707447ee, 0xd767bed7, 0xf870f5d6, - 0xb131fc03, 0x3a14bc27, 0xe3c2c0fb, 0x20c8034e, 0xbcc797b0, 0xf20d1196, - 0x86c5349b, 0x715c4b8d, 0x0e383f38, 0x63a457a7, 0xcf83b881, 0x423fa9ed, - 0x5aa3ed8e, 0x36c72552, 0x96d3ee8b, 0x4c729ef8, 0x8e64d3c1, 0xbbc4c987, - 0x934be20b, 0xd045f489, 0xed0e481f, 0xe7d95bbf, 0xf6103240, 0xc1c58379, - 0x67df3fe4, 0xbcd4df70, 0xf8b3f984, 0x0b6659fc, 0x02435f7e, 0xce104752, - 0x91df7829, 0x5a1b18d7, 0x4fbf9287, 0x66115486, 0x7bc3cdcf, 0xc85c29ae, - 0x75a15177, 0x8482ac98, 0x75f0fdf7, 0x7b33a99c, 0x5bad8f21, 0x9d814774, - 0x1bec21d7, 0xfc93fb83, 0xe9ff4023, 0xee35cfdb, 0xda7680ae, 0xf1fb08af, - 0x59162ff5, 0xc3b021fc, 0xb93e7be4, 0xb2953b77, 0x8509ea35, 0xfbe0b37e, - 0xde81cbd4, 0xdd6103fd, 0xd1d54053, 0xf659e772, 0x6376431d, 0xecf304ba, - 0xff7966e9, 0x8125c439, 0xdfa7ab7d, 0xa1a74bef, 0x08604578, 0x5d8a29f8, - 0x1eead536, 0x57cfa569, 0x9b66eff3, 0x05188ece, 0xf4c1f978, 0x4f4b4074, - 0xba511d0a, 0xecf00f1a, 0x69fcf8ca, 0xcddfc730, 0x7a009738, 0x43dfb151, - 0x026b8a76, 0x3b37a7ac, 0x3dd5897e, 0x3b017ac5, 0x2e67b15e, 0xdd9087e6, - 0x74a641d4, 0xcbc71b74, 0xccab733c, 0x600fcdee, 0x48eafdfe, 0x473b5ee5, - 0xb791d824, 0x54d94ead, 0xd586e707, 0x6b7efe2c, 0x83f1ac95, 0x86dd90dd, - 0x66fbb3ef, 0x6da65f6f, 0xfe604cff, 0xfb57a17e, 0x3412589c, 0x9cf6edf7, - 0xc035e0d7, 0x3123c3bc, 0xaf3f413f, 0x79fa7f7e, 0xe6adf3f5, 0x636ad57e, - 0xcaa748ed, 0x6560592e, 0xaaf750f6, 0xcae0ebc7, 0xe7e0deba, 0x93480f36, - 0xb5abf754, 0x082c8ead, 0x328c6f77, 0x79ef029e, 0x00e2cfc4, 0xc3dff255, - 0xe59b83dd, 0xde81f166, 0x98161de6, 0xe1a0768a, 0xf608bf49, 0x4100b0fc, - 0xe02b3bfb, 0xf8d02c32, 0xee4fcc01, 0xbdc007e1, 0xd65eb426, 0x01f98bb0, - 0x4fe8d5f5, 0x027f5194, 0x387accf4, 0x17c01e9b, 0x41fe8694, 0xfc85dfd0, - 0xcfb82ca9, 0x12c3fb92, 0x5ad497a5, 0xf5a37fd6, 0x096ae35d, 0x927755fc, - 0xe363294c, 0x98d7efc3, 0x93555fa9, 0xf508224c, 0xf8785eab, 0xc06be9fd, - 0x09758e5f, 0xad287f70, 0xf7fa58d7, 0xf8debfdd, 0xb81afef0, 0x65fa946f, - 0x7f2aaceb, 0x78fe37b7, 0x0b918c04, 0x3dba47f0, 0xa1f0237f, 0x8a68af12, - 0x111f7ce0, 0x8068bba4, 0x57274297, 0x7e8f9b2f, 0xe725c445, 0x589e4087, - 0x16ffc716, 0x46c38f2b, 0x129ff7b1, 0xbf905bdd, 0x023f3adf, 0x8cefcbe2, - 0x5cfe8a3c, 0xe7c59593, 0xd04a79f7, 0xb9f0527e, 0x3f702acb, 0xf8103fc9, - 0xcdf1daed, 0x6497e071, 0x43de02c9, 0x9efb24da, 0x7900cf4c, 0x82bedb34, - 0xa26b296e, 0x6b13bf11, 0xbc0ff08a, 0x35a7655b, 0x9b4cfbf1, 0xa81deece, - 0x661e63ce, 0x4565ddcd, 0x308bf3fa, 0xeec6567e, 0x7befa0c3, 0xfd212fd3, - 0x7f4012e1, 0x13fbf390, 0x61a8fcf0, 0x42e20d8f, 0x827efc1d, 0x09cd0d33, - 0xbe5969f3, 0xf0362fe5, 0x70e7ded7, 0xe2b52338, 0xdb654a3d, 0x83ffbc44, - 0x0b709bce, 0x161ba7c4, 0xf7efb264, 0x8a6777d8, 0x67ff4cfe, 0x167cc0f3, - 0xc8efc434, 0xb2727b14, 0xf583ebd9, 0x188b5535, 0xbbac9e2f, 0xbf0a6c37, - 0x5f6f4c37, 0x712ab49e, 0x87cc04e9, 0xf3676a5a, 0x594fc6f4, 0x9f12c4df, - 0x24b2df8a, 0xcfeb08bf, 0xc08126fa, 0x5a679715, 0x03c89e52, 0xcec89e3f, - 0x44ac30e1, 0xcafda376, 0x6fe89fcf, 0xbe43dc37, 0x6cde5793, 0x4aeb3738, - 0xfdfb6624, 0x77600997, 0xe0b1fbb9, 0x8a07d322, 0x1be5377d, 0x6f557c6d, - 0x8d34e6e7, 0x41207fbd, 0xa77fb378, 0x55eec022, 0x06ff61eb, 0x7bb587a6, - 0xe10c7909, 0xf52dbe90, 0x2947b81a, 0x3b068ffd, 0x7c02dbcc, 0x3cf80f11, - 0x54fcf787, 0xd08dff10, 0xda20d15e, 0x927eb0fd, 0x95f01971, 0x70283762, - 0x6cdf3c69, 0x91d7431e, 0x5f60d675, 0x3378874e, 0xcffa05f0, 0x2fbcfee3, - 0x5357f40e, 0x8273c240, 0xa3bbb3ac, 0x60e4a816, 0x3e0379d3, 0x5bfcf37f, - 0xd881e7da, 0x2dbde0cb, 0xef17e606, 0x28f7fbde, 0x9e6f4b90, 0x82f1c6ef, - 0xbb4f4376, 0x6b91e118, 0x67718315, 0xc44c5db5, 0xb79003ac, 0xaa9a2d35, - 0xbb77a131, 0x7213fb37, 0xb4f495bf, 0x1ec0721f, 0x11d8c311, 0x3e74ce1c, - 0x6f48f809, 0xe36e5c57, 0x24c1e6f1, 0x6ca3ee1d, 0x18b71f3c, 0x8a6e1fbf, - 0x7d472fb2, 0xaea5eccc, 0xbf1fa7dd, 0x13ef9e06, 0xe711fdd9, 0xb7a7e445, - 0xda1e2e76, 0x2a5be2a6, 0x5f4f1139, 0xf9db3ff5, 0xd5ffed06, 0x4716489e, - 0xa9979c97, 0xf50877bf, 0xf97871f7, 0x38f3b007, 0xd7b800ef, 0x2fdb07e9, - 0xfafc3d1d, 0xc3da1b3c, 0x1ea0e981, 0x376bac46, 0xac5bfe02, 0x90d9d7f9, - 0x00a3eadf, 0x33925e2e, 0xf3804c90, 0x7403927a, 0x7626a815, 0xb5b627f0, - 0x97800c18, 0x98c98d8c, 0x9f89b3a7, 0xafaa2e57, 0xe8ab2635, 0xef3f1162, - 0x877b293a, 0x1f9eaac4, 0x72f931b0, 0x6fe94f72, 0x43e34f30, 0xc61e1913, - 0x31b06cde, 0xd18afb7d, 0xe866cd7b, 0xdf80c477, 0xfbdeed0d, 0xcfb85efa, - 0xc761d178, 0x3dff8858, 0xbf607362, 0x6a9b7dc6, 0xf1b7cf20, 0x5452d013, - 0x14286caf, 0x37de740d, 0xefc58388, 0x1fd0180e, 0x893dc60f, 0xf9f60e2b, - 0x1bcf5f10, 0xf9cd062d, 0xdefc1bd8, 0x326d7bdd, 0x89b12fb6, 0x2dadc788, - 0x37a07139, 0xbbeeac5a, 0x8e2fa06d, 0x12c0d5b5, 0x629f7894, 0xb03c4daf, - 0xf4d19af5, 0x061d89cf, 0x71dba03b, 0xf61179e0, 0x484938eb, 0xd87a408c, - 0x8f3c746f, 0x3a37bc7a, 0x1d7478d8, 0x2abf016f, 0xff9aa7f0, 0x7f5a34a1, - 0x858a55a3, 0xfe052efc, 0xf9943eca, 0xb5c4f51d, 0xe4ac82de, 0xb8817ada, - 0x3a5f92b3, 0x7f944ece, 0xd2e9012f, 0x6a3d7368, 0xda0ef663, 0x30f727d7, - 0xae15e8bb, 0xe1524947, 0x829f8050, 0x8b1b7aa7, 0xe9eb2a33, 0xdbdffe6d, - 0xca549e98, 0x9bd74bef, 0xe9178764, 0x0fcb1b66, 0xe6fd7877, 0x6b23c854, - 0xcf7fc54c, 0xfb679549, 0x93e7a47b, 0x1b057bda, 0xf8060cdb, 0x8762ac0e, - 0x6de68310, 0x20ebed1f, 0x48f5499d, 0x09878d7f, 0xdd6971f2, 0x48ee2c9d, - 0x7fbf0de5, 0x81d1cf0d, 0x7a79f87f, 0x1396817f, 0x18afd69b, 0xdbf5f088, - 0x7042af80, 0x65037ca2, 0xe811ad55, 0x5652d175, 0xe973f316, 0xc8dd6b45, - 0x58eb459f, 0x5b1ee17e, 0x0ce7ae32, 0x886257a7, 0x27f9001c, 0x657f0e2e, - 0x6e9c79dd, 0xd13c354f, 0xfa52f30c, 0x73e013fa, 0x4f63e352, 0x7a1572c3, - 0xc641b53d, 0xb5224a71, 0x7cadf6e7, 0x18076dbc, 0x20dc4fbd, 0x5ffdc0e7, - 0x0ec4bd13, 0x3637ec71, 0x7e41146c, 0x9cf401bf, 0xf41cf8cc, 0x0f3dc9ed, - 0xf402fd46, 0x4081bb5c, 0x2315fcbc, 0xe2a2d929, 0x5febdd8b, 0x696ff0d5, - 0x1835f55d, 0x158b6f97, 0x7c2bce40, 0x15fdc0ab, 0xe42af3a3, 0xfc74ebff, - 0x2fbd953f, 0xdfb03b47, 0x9fff9c13, 0x9ff94198, 0x10d98a3e, 0xaf38c023, - 0x07dfc318, 0xa40ff5f7, 0x6d5ca0bf, 0xbf5721eb, 0xcdb57266, 0xafe74a96, - 0xe31bb6b8, 0x71f5c10c, 0xaa6279ba, 0x02c93742, 0x6296bfc0, 0x8bc01870, - 0x99e815c2, 0xdfb7cdda, 0xd95c8690, 0x0f39e122, 0xf9e2473f, 0x0277ca1f, - 0xe486bf0a, 0x6eb7c299, 0xd5d83473, 0x8056ab53, 0xe7971f5d, 0x253cfa45, - 0x52c687b8, 0xf80a767d, 0x383c8c38, 0x57c7e5c1, 0xf762fbb2, 0x7a000fee, - 0x221ea12e, 0x13ac87ec, 0xa51780ec, 0xdd8eb1dd, 0x5a3c3ac3, 0x2bbf9cd0, - 0xef0c1ff5, 0x41fb8f40, 0x7c634787, 0x3c84603a, 0xa63e11d5, 0x839088c7, - 0x570c40fc, 0x5b3e000f, 0xcdd7f544, 0x4a75fd2a, 0x553a45ae, 0x347970e0, - 0xc55f5f93, 0x95ff7db0, 0xe21585d3, 0x2f73aa85, 0x024890ea, 0x605167e3, - 0xf8c22e7c, 0xba4cf6a7, 0xdafde90a, 0x076ef4f0, 0xfe162aff, 0x48f5a73d, - 0xec33319f, 0x13cb1df8, 0x46223392, 0xb0f91f63, 0x57f1bddc, 0xfd01d7e8, - 0x46f7bf02, 0xff4025ff, 0xfbdd0c24, 0xf0abdd28, 0xa501d0a7, 0x55a26b8b, - 0x174f41f2, 0x02a379ca, 0xe7745797, 0x33474f95, 0x9780b079, 0x66f25e8e, - 0x60fcfd94, 0x81ec9f3c, 0xcf0cf9e7, 0x7c02be21, 0x67e1f22b, 0x3dafe117, - 0xaf6c76d1, 0xe60174f9, 0x73f2d4a9, 0x9f3e7aab, 0xd1a5eeb2, 0x4b7ce682, - 0xca34ee7f, 0x5a2bbee2, 0x48ea3e77, 0x34c7d10b, 0xd92ecf6e, 0xff73c268, - 0x7802d02d, 0xbdfecddb, 0xbb3de56c, 0x0a4f0d44, 0x4cd115ea, 0xe1f42b8e, - 0xc3246658, 0x55f2ffa8, 0xc86ee172, 0xab59f9ff, 0xdd346f37, 0x77a316c7, - 0x07e8b5f6, 0xf182af38, 0xd833caaf, 0xc6241f21, 0xde201765, 0x7c0a2481, - 0x33cd8fb8, 0x1979d52e, 0xe70ec9fa, 0x0f079038, 0xf8297c73, 0x9bd0e055, - 0xaf0deb9e, 0xe27c387b, 0x8e5ebb79, 0x9efe7314, 0x5c5dfbc2, 0xe045788e, - 0x2f711b27, 0x59fd6117, 0xe505fe4c, 0x73c11648, 0x727597c9, 0x5e9fe5e4, - 0x91acbc8e, 0xc2da1323, 0x0bfa11ca, 0x1bf1ffcb, 0x4b1da216, 0x63b7870e, - 0x3d334677, 0x93fa0f1c, 0xb2f78bf6, 0x3987def3, 0xc48a52dd, 0x0ddac9bc, - 0x5713cc26, 0x366d90e4, 0xaf7f81c9, 0x16fa06d9, 0x1f76cd7a, 0xc5e70c9e, - 0x9c074649, 0x03929f5f, 0xd453f788, 0xfa45af01, 0xc7fbc7c8, 0x0223c8c3, - 0x47ef12f1, 0x9cefd083, 0x9f213626, 0x5046992c, 0x78deee7f, 0x4955d205, - 0x74008a5e, 0x23175a5b, 0x54ec7b40, 0x94e401bb, 0x962b8fb2, 0x71b0c819, - 0xd40707c8, 0x6f0ae472, 0xcdbbfe15, 0x49dce343, 0x47210c72, 0x33fb3d1f, - 0x8da8bc75, 0x22f1d5d6, 0xfbe07f5a, 0x468e8bc4, 0x78801e07, 0xae6c3fd1, - 0x94779876, 0xea28ff25, 0x912ac4b7, 0xc5d6e4a8, 0x4a1fb7ec, 0x2e3c952f, - 0x34a95a45, 0x81c4d04e, 0x6073ab6f, 0x582bf81c, 0xe380c54f, 0x7870c34f, - 0x7b5846af, 0x1fa3ad9b, 0x13e40b97, 0x97e8f882, 0xfc42255f, 0x063b9145, - 0x2fe2ac7b, 0xa197900b, 0x037fdbf0, 0xd7b57d1c, 0x00008000, 0x00088b1f, - 0x00000000, 0x7dcdff00, 0xd5947809, 0xe77df0d5, 0x24cb2d9d, 0x7642c993, - 0x03bbec26, 0x4eb1ab09, 0x04906008, 0x8d441007, 0xb0900938, 0xd2910364, - 0x208196d6, 0x2b188a06, 0x0eb154b5, 0x4551fa14, 0xdb1ab61b, 0x1a4013a0, - 0xad563414, 0x61a5afd8, 0x80891d91, 0xe58ad3fd, 0x7bdce73b, 0x264ef333, - 0xe79f6a02, 0xcdcf0f0f, 0xcf7bde5d, 0x773dfb3d, 0x79632d49, 0x9b19223b, - 0xed50b390, 0xccc9a906, 0x831b163c, 0x43632f1f, 0x087a3e79, 0x6b9859e6, - 0xf26b6320, 0x01de7975, 0x9fc75d8c, 0xa269fd3b, 0x678e3e15, 0x30d6fe6c, - 0xb53349eb, 0x7fe1d767, 0x268c5d79, 0x649f595f, 0x9fc7d93d, 0x24bf8f9f, - 0x4c33ffc1, 0x2b1812cf, 0xe1a7e263, 0x70ffdfcb, 0xdfc7b418, 0x54dec655, - 0x805689dd, 0x12dcdca7, 0xd8ceddd5, 0x13c7f933, 0x52d491dc, 0x223ddf87, - 0xb97178c6, 0x71debde3, 0x55de798c, 0x0fc816d9, 0x4a3d1936, 0x64e2fc34, - 0xe8826b76, 0x06947e0f, 0x041967c5, 0x55437ff9, 0xfe97632c, 0xc5f4a3ad, - 0x32f2b89f, 0x7a8afbe0, 0xb439639d, 0x185068ab, 0xd1cc62cb, 0x19cd7995, - 0x4785d58c, 0x5fd0620d, 0xa748bece, 0x292fca01, 0x8329af66, 0x870800d1, - 0xa23fc241, 0xd41b7d35, 0xd8983757, 0xca5ec86a, 0xe119ac61, 0xd9a23bd5, - 0x077e3f00, 0x0fa67e1d, 0x6bca00cc, 0x630b2e1d, 0xff78c29b, 0x7b64c29b, - 0xb483347b, 0xecd192db, 0xd7a7c004, 0xf40d1633, 0x6983c481, 0x036e92f6, - 0x1f3099f4, 0x8018f33d, 0x3eadd94e, 0xadd2f115, 0x9163aed5, 0xadf471fe, - 0x4ddbe68c, 0x6039d76f, 0xf7813afc, 0x543b4d9d, 0xd873e03d, 0x156ada98, - 0xf728d2d2, 0xa8f3c458, 0x2c6aaaec, 0xa8f7cd8f, 0xa59f686e, 0x00b3ed54, - 0xe678d85e, 0xcce502d8, 0x848f8307, 0x18d616fa, 0x2398d905, 0x2828ce2d, - 0xd9c6751f, 0x1de60038, 0xf60a62ed, 0x1a32d8c7, 0xcba45fbf, 0x38b2fd85, - 0xfd0052a7, 0x2307fb0c, 0x767ec8bc, 0xec568d36, 0xf35c6f00, 0xc01ec518, - 0xe24d305f, 0xfeccf5ab, 0x73d7ec53, 0xba40e748, 0x7398ebda, 0xfaefb423, - 0x2c31bf72, 0xd2bedfca, 0xb778d0aa, 0x46b9ddbb, 0xd879f346, 0x9c8fdf0a, - 0x0067ddee, 0xf1cf8678, 0x03da33ec, 0x519733e6, 0x1e2d297f, 0x11d2479a, - 0x8ba60e77, 0xcfd4312d, 0xc6be33a8, 0x4baed001, 0xca07cc15, 0x543f9ad3, - 0x5569af10, 0x71d20acd, 0x825ed367, 0x3f79b537, 0xea11814f, 0x7201dd20, - 0x8f301755, 0xcd1d16c5, 0xa145b163, 0x99c5e574, 0x7fa82e89, 0x6c5eeac4, - 0xc79fea19, 0x62771cca, 0xbebff415, 0x7cfb5ba9, 0xb7bc027b, 0x278867c1, - 0xab72dfd9, 0xb269fa91, 0xf3847fb8, 0x72de9cab, 0x476f7900, 0x48a39fd3, - 0x88e21a2e, 0x8e8709be, 0x96123d13, 0x78a0ce00, 0x0a85a1fd, 0x85f5aa83, - 0x23a53340, 0xddb8279e, 0x8899318e, 0xf89f806f, 0x09311ac7, 0x8c62f2f8, - 0x91c706bb, 0xd91427ed, 0xb45f5022, 0xcf77c5e7, 0x598e652e, 0xfbcf003d, - 0x6eb2778b, 0x12f77748, 0xbb7b7ba4, 0x21878f81, 0xb38b313f, 0xa4bbfb16, - 0xce38e9b0, 0xf942984b, 0x979e064b, 0x95abfaf8, 0xeb11ebe3, 0x7896c5a4, - 0xf02b278e, 0xbc614bf1, 0x7a1eb05d, 0xb3bfcad7, 0xcd617e0b, 0x1e705f9c, - 0xbb64bfa8, 0xdbdfa2dd, 0x3d5cee9d, 0x08cd93e7, 0xde11c8e7, 0xc3b7c87d, - 0x90fb3cf3, 0xe098d3ff, 0x27ce3c93, 0xcfbefcc1, 0x467ea36a, 0x8865699d, - 0xb9852cf7, 0xd32ee902, 0xa1ae10d7, 0x89a3dfc8, 0xb61e407f, 0x52c378e3, - 0x800354aa, 0x13acc712, 0xdec67758, 0x5da9dab6, 0x3ee708e6, 0xd3ab37e4, - 0x207cf245, 0x2be54ac2, 0xc07f3833, 0xfc407ff7, 0x2ed3cb05, 0x7e01a394, - 0x7e438a39, 0x8fc8ec8c, 0xbcf013bf, 0x63a5e42d, 0x613feeff, 0x3acd71ff, - 0x0c9d02a7, 0x65e9123f, 0xa2f874d0, 0x8fe1152a, 0x00ffc063, 0x358e6da0, - 0xa52ce507, 0x5d20a1cc, 0x875c229b, 0x230fd4ad, 0x4732b9bd, 0xef86ade7, - 0x893b46e6, 0x3ed8df7e, 0x366667ec, 0xc01f6fcc, 0xe115fc1e, 0xb6b07b03, - 0x6ff4f508, 0x3d4469ff, 0xd7f2976a, 0x38a22434, 0x48ae3f80, 0xf7a7e0bd, - 0x410bd271, 0x73d60ef4, 0xebf6f4c1, 0x039ead05, 0xf4e05d7c, 0x9f226770, - 0x522f35c5, 0xead07eb9, 0xd1e8ceb5, 0x3a083f41, 0x7e708a5c, 0x0c5cf881, - 0x7ae38832, 0x583eb346, 0x0e1d99de, 0x76a4898b, 0x1c3b45ff, 0xd1df1316, - 0xadcceb0e, 0x47c01507, 0x576a8379, 0x8fd50a61, 0xff489cd9, 0x8714eb17, - 0x41a4e509, 0x71787e25, 0x4bd93865, 0xbb67ef09, 0xdbb107a3, 0xcff21520, - 0x8ec9dddc, 0xf188c656, 0xf18790ed, 0xd679592f, 0xc5277568, 0x1793e804, - 0x4308be1b, 0x644ff73c, 0x62c64e03, 0x0ed6a70b, 0xf0290883, 0x537f09bd, - 0x6b83af10, 0x69ac1454, 0x95269dee, 0xfb1dd6e8, 0xfe5ace1b, 0xbd700d9c, - 0xceb46dbc, 0xf537c81d, 0x05ec6757, 0xb8232bf8, 0xf7b4be5d, 0x33e42f5a, - 0x92f77f59, 0x3f7bd262, 0x13192b07, 0xeedf1fa0, 0x61eb8273, 0xd53d6856, - 0x2a76871f, 0x850023d7, 0x7a3ee651, 0x70d427f4, 0x27f5aa87, 0x7baa3988, - 0x7f107e02, 0xbf84e18d, 0x77209eea, 0x48e70419, 0xc5bf7fec, 0xfca092c8, - 0xb623c80a, 0x037f7093, 0xe2074778, 0xaa6f0fd1, 0xe08454f5, 0x5f0fd50b, - 0x0e905d3b, 0xd16abfd0, 0xb12e3cd3, 0xb3d20770, 0x4864e8ce, 0xe151cf7f, - 0x55ba081f, 0xd4bb9e08, 0x1b88f430, 0x91e2f7e6, 0x7f7e0754, 0x984afea9, - 0x46fd122e, 0x979c14f7, 0x851ad69a, 0xc35f70f6, 0x032dbe95, 0xc54dbf48, - 0x4e872bf2, 0xbe03dcd8, 0x8466fcd1, 0x7e7687a6, 0x9ac8fa95, 0x6150ff40, - 0x7cc17e7c, 0xfe3434a4, 0xf244194b, 0x7a1f50c7, 0x1ab799d2, 0xa072bde6, - 0x997ba7e0, 0x983ee51d, 0xabab46de, 0x6e402622, 0xaaed15ff, 0x9c70b842, - 0xcf342194, 0x741f9885, 0x41a66678, 0xc31bf387, 0x7f4a6ed0, 0xb0effd0f, - 0x4eff7e21, 0xfe7dafce, 0x3a0daf3d, 0x3fbe68c4, 0xf80071c6, 0xaf803ae5, - 0xeac18c12, 0xfb79c08c, 0x62e51e88, 0x48e6e57e, 0x61f30a9f, 0x5a170cbb, - 0xd6e81ea4, 0x4fa07e11, 0x19e7c20d, 0x46e238ed, 0xd235fefa, 0xd1f88d51, - 0x5fd15b37, 0xc6acf985, 0x28a2367a, 0x2fdfe711, 0xf505b9d2, 0x18cb4bfc, - 0x57a5f3f1, 0x4c137798, 0x1d7efb76, 0xd646cbf1, 0x9fbef88f, 0x570cf2ee, - 0x3af3c924, 0xb9ab3b84, 0xb77a8756, 0x43aed7a7, 0xb9b7da7d, 0x3e23a74e, - 0x8622ff70, 0x5799e4fc, 0xff5f00f4, 0x37ea556d, 0x686f07e4, 0xaf40ef7e, - 0x92f481cd, 0x7c16cb78, 0x43788d90, 0xbfaad083, 0xe3f662d0, 0x52c3e80d, - 0x63fb1d6c, 0xf11d25ac, 0xe9faf8d4, 0x5fd02d5e, 0x67a71bc5, 0xfe2a5e20, - 0x18262260, 0xd1be87f3, 0xe59fefc8, 0x2e67f684, 0xe872ad2c, 0x257a9fc1, - 0x85d91ba6, 0x446cd632, 0x6ebca13f, 0xa01f4381, 0x76ffa5cf, 0x8f9cd0c8, - 0xaa1a1ffd, 0xe78065b2, 0x5de18e2b, 0xd13b0858, 0xbfa12fee, 0x472fb006, - 0xafcf11d8, 0xff734567, 0x20f646d1, 0xa5a1fdb8, 0x7a631c73, 0xa1dfde74, - 0xbdd361c1, 0x907e7df0, 0x8634741f, 0x18b6b5db, 0x2141876e, 0x8bce113b, - 0x3d78b7bf, 0xc8717450, 0xfd0c5147, 0x641f5dcc, 0x2e8f807a, 0xfe47e6b2, - 0x35767288, 0xf971d692, 0x5cca3f83, 0xe5cbf166, 0xdcf8231d, 0x70ed78ef, - 0xe7da1d94, 0xe717df6f, 0x1ddfc009, 0x9db57f4c, 0x5c7033af, 0x7d33e346, - 0x07a42f4b, 0x04d9e3fb, 0xaff9a43b, 0xf9c715bf, 0x74874120, 0xdbf4245e, - 0xc028b0ef, 0x525fcedf, 0xf3247c41, 0xe6666de5, 0xebc80d8d, 0x04b88d9b, - 0x648b6f2e, 0x37b7685e, 0x7a4712c6, 0xa3259926, 0x5f14e99e, 0xe0cf8937, - 0x43cf8972, 0xa3a6cf83, 0x2759f15f, 0x1b6f70fe, 0xf7ced76f, 0xd74fc14b, - 0x7ceff3fb, 0x0aec3ea5, 0x8d845df1, 0x638ae9d3, 0xf7f41764, 0x1ebe8df2, - 0xe4ed10d6, 0x4f1832fa, 0x8d2b5f6f, 0xdf7f7ec0, 0x050bca66, 0xfba6de97, - 0x21ca7e76, 0x1fc02a80, 0x53baa6dc, 0x9c1fc26d, 0xbe8af90c, 0xbad1c657, - 0xd08bf25a, 0x4f30777b, 0x306fca23, 0xf77a487f, 0xfadd01b0, 0x296672a3, - 0x318bb748, 0x4237ce76, 0x047ca41e, 0x9d3831e3, 0x50ee6460, 0x62af80eb, - 0x98c35e24, 0x23e1f407, 0xdf640d1b, 0xf8fb5f0f, 0xf7e04cde, 0xd60c1bd3, - 0x9ce430e5, 0x3ea5f617, 0x0673f503, 0xe40aac9b, 0x3d7ddb4f, 0x5f4bee50, - 0x0fc85d50, 0x923c37a7, 0xf3d21330, 0x0065bf20, 0x0346e947, 0xf8d9cf95, - 0x159f9528, 0x42fa5d72, 0x97d47f7c, 0x4eaff787, 0xf9ce3a40, 0x486989ea, - 0x6b46ed97, 0x9690c1ff, 0x631c536d, 0x6f3df002, 0xbf269873, 0xe0e6c75d, - 0x995d243c, 0x47af6ee2, 0xa6d53f13, 0x1f7176fb, 0x04dfd69f, 0xa0aa72ff, - 0x3029c4e3, 0x57a18aef, 0x77dfafc8, 0xc9ec9c20, 0xf92a919b, 0xffc1be8f, - 0x20db9def, 0xde95fb9f, 0xa09dbe41, 0x674158f3, 0xb7a45cb0, 0x9f3ccc4b, - 0xfc9ebafb, 0x4a8b5ccf, 0x91f686f8, 0x7bfea163, 0xf40fbda2, 0x5321ca2c, - 0x848dd7b3, 0x0da36376, 0xf7d0ed0c, 0x19f2f37c, 0xdb3bc9d8, 0x025bc7f4, - 0xd59a33e6, 0x387f41f6, 0xca821987, 0xcf2c7a9d, 0xc7cb6b35, 0x2cfbb8f6, - 0xad630ffa, 0x77c972da, 0xfab4d88f, 0x7381df62, 0xf3009b3f, 0x92a4392b, - 0x7d237cff, 0xafc22efc, 0x5dbf3a47, 0x3bbe0db8, 0xf872b02c, 0x4915e9da, - 0x142357c8, 0xd3acf186, 0xe3cb42d7, 0x665ea41f, 0x7e3edf40, 0xe63816fa, - 0xdc51e7b6, 0xa0b119ef, 0xdff08f3d, 0x7afb1ebc, 0x8d9b753d, 0xed8233c7, - 0xfcdcb046, 0xfe46ecb7, 0x3dd2b7e0, 0x837f4a16, 0x5ced85e9, 0x89eb06ef, - 0xe1213b60, 0xbcb7860a, 0x0fb1a74d, 0x191ea15f, 0x8c27681a, 0xc3be2764, - 0x6d8370f5, 0x30f5c768, 0x2f8431f8, 0xad3d30cf, 0x6adfc1c3, 0x220376c4, - 0x0039b1ed, 0xb76b0ad2, 0x167fb208, 0x405b7ef7, 0xb6ffaa1c, 0x8dea1d5a, - 0x418cf8f6, 0xeb91a71b, 0x9d8477d5, 0x1cfa13a8, 0xceb4abd6, 0x4eee18df, - 0xc9b8e3d4, 0x8c96c746, 0x48f9f88e, 0xcfccefb4, 0xbeac7e95, 0x8fb1fb86, - 0x389a5d58, 0xa893eb19, 0x5fa2fb89, 0xd9edf28e, 0xfcf34e1b, 0x420d7154, - 0xe733d439, 0xf4016ddf, 0xf87036a9, 0x8f89e183, 0x319276e5, 0xb207f917, - 0xd0e8f67c, 0xd5895c7a, 0x679cfb53, 0xff474fef, 0x07c6d3ed, 0x7ebf51d2, - 0xede7141a, 0x169e1e4c, 0xb0a4faf2, 0x2e223123, 0x11ca14f0, 0x9dda41e4, - 0x55fbe1db, 0x57245d4b, 0x9d3a5d3f, 0x2e9667d2, 0xb613faa1, 0x9adf1a0c, - 0x775767f3, 0x35c9d3c0, 0xd989d92a, 0x18af5746, 0x59a4eef8, 0x1385f147, - 0xbb799155, 0xd19cb122, 0xb3f6727a, 0x0278b613, 0x6c277ee2, 0x6743a27a, - 0xfd8f8cf3, 0x9cbdfa66, 0xbda144b5, 0x23d7e76a, 0x2db5ec1d, 0xac7fe316, - 0x55db0125, 0xb6bdcd2a, 0xb7c71d29, 0x2c7c6732, 0xf59197f2, 0x0ba9b947, - 0xb828f6e7, 0xe72c4a5d, 0x1fa1bfc3, 0x8a7efd0b, 0x9e842b76, 0x2f3a0bb1, - 0xb1ed38b4, 0xc922efa4, 0x81b8275f, 0x728cbe5f, 0x60b84776, 0xd313d65d, - 0x7c785d61, 0x2ac5b16e, 0xf0a9c3f8, 0x5fab8e75, 0x5bf8886c, 0x609ef167, - 0x7811de38, 0xc9038e0d, 0x8681c654, 0xbcf9f2c6, 0xe26ab36d, 0x0eff1842, - 0x79f9ff15, 0x1ba3d72c, 0x2a3c5bc3, 0x7c03c3ca, 0xdb25de3d, 0x2b7c60a3, - 0x0736bf25, 0xc5775fe3, 0x2da5b8f2, 0xeb889dcf, 0xa344e4f6, 0x3736e303, - 0xea038f2b, 0xc05f7c9c, 0xd63823ad, 0x7ac27b37, 0xcd095c01, 0xa4231cee, - 0x0d317153, 0xaac2edf8, 0xa0dd2196, 0x6b23211d, 0x9157b87f, 0x92686c8b, - 0x4028f429, 0x6772861a, 0x454f728c, 0x559b0cba, 0xfa718d55, 0xffbe3294, - 0x77715670, 0x9c9f01b5, 0xa43c2b7d, 0xe8225c3f, 0xc9d194cf, 0x36b3fa68, - 0xacae081b, 0x819f3fcd, 0xf9b59f7c, 0xa012bd2e, 0x1ac79687, 0xdf67fe68, - 0xe295d79a, 0x58989f16, 0xea7a10cf, 0x1e5f8287, 0x69d87410, 0x8b7fcd0c, - 0xac6fbb45, 0x55405bcf, 0xe2f9f569, 0x5b3880d8, 0xd265f945, 0xed6393e7, - 0xfaf3ce34, 0x80c903ba, 0x3167e7cf, 0xe68a0787, 0xf148dd6d, 0xbac69dd7, - 0xe4efb8f1, 0xa431d0a9, 0x7f03fefb, 0x7e8c9038, 0x60fb2ce4, 0xbfda23f4, - 0x4ad2f43f, 0x0e7e7f2c, 0x4ff88c1b, 0x60ad3ef2, 0x619fe63c, 0x7faf84b5, - 0x65b1316e, 0xbf7db718, 0x210ffc6e, 0xc74cbebf, 0xcf04bf50, 0xe832461b, - 0x19f53112, 0xfd382374, 0xba4a0f51, 0x91190303, 0x886e921e, 0xee90edbf, - 0xc11af2df, 0x2a9ae12f, 0xb6f3dee2, 0x7c8f1f6e, 0x53665c92, 0xe1204e30, - 0x793d91ba, 0xd9dbf631, 0x0ed0ef93, 0x221b12bf, 0x0ec21d2e, 0x610d88ef, - 0x2fed8387, 0x637738b3, 0xe1d91bbb, 0x36ff82e1, 0x7fed06c6, 0x08597ee0, - 0xed8d0dba, 0x1fdf0f10, 0xe3ff621b, 0xdef0f146, 0x43ff72b1, 0xc97f0f1b, - 0xad6ff5c8, 0x293c3d8d, 0x1374bc84, 0xb5d6ebe3, 0xc67ed11a, 0xf5212835, - 0x518b62d9, 0x1c7e1fee, 0x125fb01b, 0xe0438fac, 0xefb628f7, 0x17b7cdbb, - 0xe9890d5b, 0x5bee8111, 0xdeb0ebbf, 0x29ce310d, 0x22fb3f81, 0xf6a6fb46, - 0x0afa462a, 0x141e5ef2, 0x371429f4, 0x934f38b0, 0xbec1badd, 0x1cd69dd5, - 0x3ee483f2, 0xd6ab54d5, 0x938b8c4f, 0x239f9ced, 0xd89d699c, 0x3c097f89, - 0x70dbfcc1, 0x4c45b8dc, 0xf7231fb3, 0x3caae261, 0xcd0b318a, 0x6af8a311, - 0x32f758d7, 0x1d6bb403, 0x209b1cc9, 0xcd685d1f, 0x9b6a7d41, 0xfdc468e3, - 0x7917959a, 0x02e57e3c, 0xfd4e5de6, 0x7732f9f0, 0x17ca2f37, 0x2e302dd2, - 0xe1c71110, 0x72e38888, 0x1cd27606, 0x8f0ae1c7, 0x9293b00b, 0x3e75ba1e, - 0x1adae895, 0xd0054eda, 0x77df46d5, 0x50efd742, 0x3771ed2e, 0x8cf71fe7, - 0x19be05bb, 0x7c737718, 0x4b4c14f3, 0x8f04dfec, 0x0ff38997, 0x2cf80f1e, - 0xf826ee2b, 0xee2deaec, 0x50881e8f, 0xa5dc5dbe, 0xc4275e23, 0x6b77d085, - 0x487d75f2, 0x4770b35f, 0x233abb28, 0x7dbff22e, 0xa086645e, 0x179d2df7, - 0x2d27f179, 0xdcb3a446, 0x06f090f7, 0xe591139f, 0x264a0d15, 0xf6733fae, - 0xc075a35d, 0xd37fc6a5, 0x79e3a03a, 0x42ee3e0f, 0x678003e4, 0xcea03aac, - 0x7977f207, 0xea56919b, 0x22ffb32a, 0x4df6e31b, 0x53b5e606, 0xefb6337b, - 0x7efb78c7, 0x633656db, 0xd31faadc, 0x547ac47b, 0xa8fdceb9, 0x7ee39468, - 0x8d5b2a4d, 0xbebcadf9, 0x6197998a, 0x847a3a5c, 0xf003d98e, 0x670ce319, - 0xc67c00f6, 0x7934d9e6, 0x2f9e4eb9, 0x25778dc6, 0x32efbe6b, 0x7da69bbd, - 0xa69fbb92, 0x10ce653e, 0x6aad3e4d, 0x577da694, 0xf981cfb0, 0x9addcf0c, - 0x266bddf6, 0x6b3df26b, 0x3fb4d01f, 0xcd9eaacd, 0x9c7a79c6, 0xce003dcd, - 0xdece0259, 0xdf358beb, 0x0dd5d7f5, 0xf920a1f3, 0xffee1f14, 0x326c16cd, - 0xfa73c44b, 0xfa69e77a, 0x5e6aff3d, 0x9df80293, 0x19386b5d, 0x7c219f18, - 0xea4b7e00, 0x8c1cf615, 0x5b5eba5b, 0xe9e1a73f, 0xce902995, 0xe7cb6af5, - 0x829cbee1, 0xdf2dadfc, 0x823d73ad, 0x71ed9deb, 0xe228ce22, 0x7f03ac3d, - 0x97b8d244, 0x9778f037, 0xc41de9ea, 0xb13a5a1f, 0x762fc96f, 0x44a62fc1, - 0xd984bf2d, 0x7a52fcb5, 0x1f30e770, 0x88ff88eb, 0xe47c413e, 0x78017f81, - 0xf895f897, 0x7cb438b7, 0x9de15df5, 0xdb91af31, 0x3ff96d0d, 0xb5f1b4e2, - 0xe3ee917e, 0xd4aeb7a8, 0xbf71522f, 0x7df1e58d, 0x57f52bfb, 0x6bb21d07, - 0xdb3ad7f6, 0x17173a4f, 0xfb175718, 0x3f709749, 0x137636f1, 0xfefb89fb, - 0xd900f885, 0x1f801b77, 0xb98708d8, 0xcc30ff7d, 0xac147fbf, 0x760a6537, - 0xb238cbe3, 0xd77dfe27, 0x587af86a, 0x085c5ff4, 0x9387dcaf, 0xf9e472e7, - 0xe7c91621, 0x3c01fb29, 0xf143f1a8, 0x022d9ffc, 0xf7dbadd7, 0x96f5a42f, - 0xc4c43f3c, 0x7e10bfb9, 0x3aefe93f, 0xfc8935fc, 0x6e78f081, 0x6d3123cf, - 0xf9c407f7, 0x3bcf692e, 0xb7ee47eb, 0x7b2a9675, 0x6c3fda55, 0x9b1dc255, - 0x5e93d842, 0xfd72dff1, 0x1c43a675, 0xe07c57ba, 0x2bd1ebfa, 0x00aed007, - 0xb962fbde, 0x5af602c5, 0x5febdbf1, 0xbf114444, 0xbd541eb6, 0xb2e0a1bd, - 0x036d1ed9, 0x6984363c, 0xab4c88ed, 0xf403c9cc, 0x3daf58b1, 0x11f727e7, - 0x6367db83, 0x27fd80fb, 0x8fe34ef8, 0xfdc21cac, 0x6e78ecb5, 0xe488bfdf, - 0x9114c1fe, 0x175a0caf, 0xbf70d655, 0xe9f8236c, 0x4cfd010d, 0xfb50b789, - 0x533911a5, 0xc08e29e2, 0x332bbbd7, 0x5627f214, 0x21f90a2a, 0x5347a267, - 0x9cb8b5fd, 0x623fc4c9, 0xbbe8299c, 0x6edaffc1, 0x38bb1e1c, 0x37fb238f, - 0xe6f6f3c7, 0x4e94d1f8, 0xb88ab789, 0xf21fb5b3, 0x93846547, 0xa1aa35fa, - 0xc7a6a5f7, 0xb5ad79f3, 0x6a27e930, 0x84e3fee2, 0xbf38c4de, 0xf9a3fb89, - 0x71fc1363, 0x7f66a67e, 0xf1138c68, 0x773e857d, 0x53ba9ea2, 0x78b3bdd0, - 0x758fb3bf, 0x75276e3f, 0x12fbf78c, 0x1dfbc643, 0x0fde28e3, 0x5e71ea5f, - 0xa47f71c1, 0x2fcd8443, 0xb7c48f3f, 0xd45483db, 0x7746f54f, 0x5abbae35, - 0x0eff8377, 0x2dbc7dc5, 0xf0301fb4, 0xae077750, 0xb06656af, 0xb7e416bd, - 0x7fa18c65, 0x5ba2df5f, 0x6bf5061e, 0xf58acc3c, 0x75f03723, 0xbb7ae95b, - 0x8069a703, 0x8865b075, 0x8bac1f5f, 0xd7bc218f, 0xc46e4cb7, 0xf73581fd, - 0xa19a1b32, 0x1b9b565a, 0x06d0fe85, 0xf8dd7216, 0x09b39094, 0xd4557b39, - 0xdfe8f117, 0x53d3a087, 0x0fa04e82, 0x879d22d6, 0xf0afbab7, 0x4fae38fd, - 0xfae22548, 0x1bcebf74, 0x373f3d6a, 0xf21d773a, 0xe86f40c1, 0x0b5ac3f5, - 0x1175b7e7, 0xdda8e7ae, 0xb5ee7e2e, 0x59dfea54, 0xba07a63a, 0x9d74114f, - 0xdf9f81b2, 0x5faed760, 0xc89fa557, 0x7a867fa8, 0x8b5ef4a5, 0xa543e317, - 0x821e190d, 0x7a38a5cb, 0x7868bea2, 0xd2f985df, 0xc62b2cac, 0x657f9c23, - 0xe43ea9ca, 0xbfae3262, 0xd494ecf4, 0xe3c76427, 0xb269df68, 0x16b5b7e0, - 0x0d473f3b, 0xfc008e28, 0xb6586e97, 0x7cefcf17, 0xfb466bf4, 0xd6d4474b, - 0x54d9d861, 0x2192ce40, 0x2159ea98, 0xfef82bc5, 0x1fa2bdd5, 0x5c61bfcf, - 0xa9dc7fb3, 0x3e69070d, 0x63cc0c47, 0xb4ba3e06, 0xfa3b3ee7, 0xcde32bdb, - 0xfb93c714, 0xf75547b2, 0xf48464e3, 0xda0815ad, 0x56110dfd, 0x43fc7f8c, - 0x82465df0, 0xc7d21f7b, 0x057c7cbd, 0x6596c1da, 0xa3c474a6, 0x1a92797b, - 0xd7ba7007, 0xd1ef342a, 0x788c93cb, 0x8ae6617e, 0x4f50e3c1, 0x95ce610d, - 0x2879df18, 0xd3948596, 0x9d7cf1f3, 0x60655c58, 0x849a68c6, 0x172fe311, - 0xbf8a146b, 0x015bfee0, 0x988e67d0, 0xf7aaf95f, 0xec3f88a3, 0x1e186ff0, - 0x733fe5cb, 0x1e494aaa, 0xe46bcec1, 0x19d58ca7, 0x799fa093, 0xdb39606b, - 0xf1fdec8d, 0xc043fe0e, 0x3af2ef79, 0x5b257d6d, 0x7f9d39f3, 0x5befe061, - 0xeb682ed0, 0xe8f2953f, 0xaba40e60, 0x8cc5b17b, 0x0b4684e7, 0x51ad14bc, - 0x665fa8ac, 0xbf8c68ae, 0x9b33f20f, 0xb4f20754, 0xe8eb0bc4, 0x8f39d3ef, - 0x693d4dcb, 0x6ed9703d, 0xdced82ef, 0x2bff5c51, 0x2c70f77a, 0x3dd6287f, - 0xadf1d71c, 0x9e18589f, 0x06d6399b, 0x1ec618fe, 0xc5106ccd, 0xd06cac1f, - 0x5a3b00a4, 0x6026b064, 0x16c3dfbc, 0xb7be3226, 0x779c0e65, 0xf90d79a5, - 0x07e89581, 0x1f91f9f2, 0x672c50f8, 0x15d7d6d5, 0xeac39f3a, 0x9a07e40d, - 0xd6781f85, 0xae009b5e, 0x6e3d7317, 0xde2d3920, 0x687e4316, 0x235c8af1, - 0xaef16ff2, 0xe043d218, 0x63d87e07, 0xc78e9f98, 0x481e6456, 0xeb8b7e84, - 0x96aa1c32, 0xb8ff5a7e, 0x5ba498e6, 0x4b4fbf47, 0xe8a193b7, 0x94d2f406, - 0xff0824a7, 0x3d8bd04e, 0x477e4b16, 0x7ab782e1, 0xcb9e019a, 0xee746155, - 0x83ff33a8, 0xbed1c6a5, 0xe6175c9e, 0xdfafb725, 0xcafcdf68, 0xb744a19a, - 0xfde57a60, 0xb470e667, 0x16afec27, 0xa1ec7a86, 0xc9e1ecee, 0xc2b0fe50, - 0xeaa1ebe5, 0xa72879f1, 0x6f5c0959, 0x6614b7be, 0xfdec6468, 0xece666a5, - 0x4b07d8c5, 0x68ff94ad, 0x3fe52269, 0xf4a76a5e, 0x287da593, 0x68e2293d, - 0x0180ce52, 0x25475f88, 0x951af970, 0x6cdee220, 0x8caa2251, 0x307cffbc, - 0xa1c56754, 0x4d8c27d2, 0x271eec63, 0xdfc02320, 0x046f7e99, 0xdf3db912, - 0x4b8eb062, 0x9571ff44, 0xd8befa42, 0x3da6bb75, 0x3c4625f8, 0x64facdff, - 0x9ce9cbfa, 0x1938dd98, 0xfcfef0f8, 0x69fb4d58, 0xfc9a2935, 0xcd3b04e4, - 0x775e527b, 0x8503f94d, 0xa2f935fd, 0x9e024036, 0xf8db302f, 0xb7d8aafe, - 0xd7c6cc67, 0xf6de56eb, 0x2ef0d56a, 0xaf7807df, 0x7d50321e, 0x5d243d30, - 0x31d7ad67, 0x73368037, 0xfa0dcc3d, 0x933b593d, 0x11fceae4, 0x95fdd90b, - 0x1ddf32db, 0xdb63f901, 0x7ebfb40c, 0x5aec456c, 0xb63e3fdc, 0x418a3e2d, - 0x32a95eea, 0x7ac1fa1f, 0xe80591ab, 0xcb15dcb7, 0x9156fce8, 0xf940e4d7, - 0xf9efda2f, 0xd1dbcc95, 0x5120441f, 0xbd543e3e, 0xe7e8853e, 0x14befc24, - 0xf902dde6, 0xf1afa033, 0x16ccf8c8, 0x8519d70e, 0xd9fcc0ad, 0xfaf5bfb0, - 0xb171c03e, 0x8744b6a0, 0x50f501eb, 0x1dcbe93c, 0x2dbe432a, 0xfda0605c, - 0xa91fb9bb, 0x94cf311b, 0xde9c2921, 0x64479d2a, 0x7fa8992f, 0x021c0ad6, - 0xd6fd16ed, 0x77d689b4, 0x0f77e44c, 0xfc16aef4, 0x26747c89, 0x08633986, - 0x3de08558, 0x46fc7ef7, 0xd3e3f7ac, 0xfde7083b, 0x32b5dea5, 0x5cebf801, - 0xe9107789, 0x49e2c7b5, 0x7ef182ae, 0x96f5c8d2, 0xf140e507, 0x9cbf4beb, - 0x9d3e272d, 0x38247069, 0x25655f48, 0xb93abea1, 0x98e740c6, 0x3519de99, - 0x3b3fd689, 0x38e58f88, 0x71f6f527, 0x9ac9df08, 0x96fb860c, 0xf2546bc5, - 0x78ff9007, 0xffe72f7b, 0x1b3755a7, 0x28d6fd0e, 0x23a5d66e, 0x60b23cdf, - 0x9a639d38, 0xc141d621, 0x9033e07a, 0x7f2f7755, 0x7e1ede7e, 0xb56586ce, - 0x181defe8, 0x7c158f38, 0xbfde44bc, 0xd650073c, 0xd1474fed, 0xd4dcbee5, - 0xf0ed1a3d, 0xe2550fd9, 0x6addb3b3, 0x3d022587, 0x0ef6e82f, 0xcfe43efb, - 0xe94e7817, 0xb854ff21, 0xae02677b, 0xd26b7457, 0x3e786e95, 0xdbdac4f6, - 0xaf73bbe1, 0xe6241c18, 0x7f49e24b, 0x6e697bcc, 0x8ef3c0d7, 0x2f97f51d, - 0x38bfef99, 0xe7c01493, 0x38dd7b7c, 0x775c00eb, 0xe21d84bb, 0xe6e3b1f8, - 0xbac5e02a, 0xc343c14e, 0xcb50c4ec, 0x3d773c6a, 0x3024c413, 0xec42784e, - 0x7a101f8f, 0x1109fa45, 0xa67e785d, 0x7b37f38e, 0x0dbf2155, 0xbffa347e, - 0x944f9c52, 0xebea5f7a, 0xfb4b5632, 0xf81247c1, 0x8ab9c639, 0xe055da97, - 0xa8a82ece, 0x420f2b12, 0x79356d97, 0x97d419bd, 0x480fd035, 0xfbe762ee, - 0x9e57c643, 0x652db645, 0x417e7ccd, 0xbc19ceed, 0x1d19cd25, 0x75894ded, - 0xf51b0ae3, 0xfc60706f, 0x69c854a4, 0xf5e2ad79, 0xdd9079f1, 0xd98af194, - 0xdb066ec2, 0x28f60ea7, 0x0ecd0ec8, 0x56acb3b2, 0xde01576b, 0xc2471c48, - 0x2ba70c1b, 0x987842c2, 0xbda17007, 0x0f7b712d, 0x15b8244c, 0x03b25007, - 0x35cca53c, 0x01e70626, 0x477b3ef5, 0xd5e782f8, 0xcf315e01, 0x1c4bb860, - 0xff70fb9f, 0x5187cf18, 0x1e6829bc, 0xfec11e92, 0x894ba49a, 0xa4b7e387, - 0x7e7a2141, 0x3207eeda, 0x7e491b8a, 0x9d500581, 0x44d77bf6, 0xeba567d4, - 0xf866ff40, 0xd3f247f9, 0x8517563c, 0x7cc152fc, 0xbe50932b, 0x46d3757c, - 0xe1bedfa2, 0x49ca237d, 0x53d7cda1, 0x5c288317, 0xb4bcd3fb, 0x1044f580, - 0xd7446f9e, 0x9c378a6f, 0xbdc65e95, 0x37b34f00, 0x41b0ceab, 0x1ce2769a, - 0x60e48791, 0xc463c78e, 0xb11cc6f8, 0x9c11bfee, 0x6e7e7a95, 0x76f086fc, - 0x5b7d27e2, 0x68baf3b8, 0x9fbf62fd, 0x943a33d5, 0xaff76a9e, 0xdffaec82, - 0x217e3c0c, 0xbd55f1f5, 0x5025e293, 0x2aaefc2e, 0x079b8f2b, 0x2cb4f1e9, - 0xc225e3d2, 0x4e71cbae, 0xf149dfad, 0xf768d9b7, 0x5d3fca03, 0xfee293b7, - 0x476657c6, 0x6a7dffa1, 0x78b5ccfd, 0xb6d4ebbe, 0x4be76499, 0xde76939f, - 0x1ff40c6d, 0xbd17d772, 0xdfe463f8, 0x9f1461ad, 0x16efd92f, 0xabd01eeb, - 0x9ebeced0, 0x8eb651eb, 0xb452d5eb, 0x1ec80387, 0x8b76c6f6, 0x51bddc4b, - 0xc9ca020e, 0xe99e2e4e, 0xe81eddfe, 0x11cbf177, 0xc2a10f0e, 0xdf91d3ea, - 0x3da1f56e, 0xf1f85f2c, 0x0ee73c51, 0x1fa3fff6, 0xd90ffb48, 0x92f77a8d, - 0xc26f282e, 0x1bab97ee, 0x27e8add3, 0x5ff13b08, 0x3439bfc0, 0xfe1087fe, - 0x01ff118b, 0x6bc720fb, 0x06679e38, 0x1ac4ffe1, 0xdb95974e, 0xfae147ba, - 0x774d78f1, 0x6f8eb3f2, 0x9ff849eb, 0xcff01ab5, 0x3f5a5fe3, 0x8ff006ab, - 0x3fc408eb, 0xdfbc5bc0, 0xe0eff02e, 0x78e1aff8, 0x3a786b67, 0x3d9e03ab, - 0xf1618e74, 0xf40e4daf, 0xf984ce1b, 0xb33a9fc8, 0x01d5655d, 0x83f4987e, - 0xbfb560be, 0xe24d7f42, 0xe6af6e7f, 0x0a7fa841, 0x1453fe9f, 0x76ee61d2, - 0x80efa41e, 0x82ece67f, 0xfc7fb8fe, 0x95e9bf76, 0x7e01f12e, 0xa9d24dd3, - 0xd918b982, 0x1d3f86c5, 0xe28375c1, 0x786d4f84, 0xd7dc468f, 0xd7ded7a8, - 0x851933c0, 0x382f8c36, 0x278466cc, 0x8a1ef835, 0xf91c619b, 0x9f3f3d9f, - 0xbce490b1, 0x6dbe7355, 0xba19f322, 0xa758ffa0, 0xf2c6fdd0, 0x39513945, - 0x55d4e30c, 0x2ee9c704, 0x78fce68a, 0xff23aab9, 0xfdc8ccb1, 0xf93fb948, - 0xde0ff0ae, 0x25d7c2ed, 0xd2b175ef, 0x18c29777, 0x164b81d9, 0x23ef17a3, - 0x112a7ac0, 0x31ecf7c7, 0x228edd11, 0xd57f804c, 0x6036e228, 0x1f4f9102, - 0x1f4f9c64, 0x38a26c8c, 0x5e54ac39, 0xd0f8bb40, 0xfc839312, 0x8a68b8da, - 0xf4203ed7, 0x2b9183dd, 0x1e1f685d, 0x313a348a, 0x783d7e85, 0x1a30ce88, - 0x0df18786, 0xafba46c9, 0x796e6853, 0x0fbe9705, 0xd4789e27, 0x06dea00c, - 0x55c637ee, 0xd75dd7e0, 0xc5d23b63, 0x9c6d1f4f, 0x743c32a7, 0xe055a3dc, - 0x293a714b, 0xbe82639e, 0x2b8e01c3, 0xdcb12f68, 0x9df1e56e, 0x8b27400d, - 0xe5c1be9f, 0x03f7c3cc, 0xe35cf0ca, 0x6419c628, 0x935fe104, 0xfaf2332f, - 0x26afc4f0, 0xec66cbac, 0x103ecccf, 0x3a8656e9, 0x45f7d704, 0x978c5ed1, - 0x25f183df, 0xe27aa61b, 0xe67ac997, 0x26b4f1d1, 0x89cccf12, 0x8144d378, - 0x9823a9cf, 0xeef01a2f, 0x778da83b, 0xf9d3e7dd, 0xef7e037a, 0x911afbd1, - 0xbb66753f, 0xb8e30ac1, 0xb82194f2, 0x7e5b292e, 0x25a6f073, 0xa5d7f39a, - 0xcfc75e42, 0x80feb585, 0x041e21c7, 0xcdbc4561, 0xeafdb3d0, 0x8807ce10, - 0xdd9b4a97, 0x2816ed43, 0x71950f14, 0xc1ff4936, 0x1d207dd0, 0x41f0141f, - 0xf851353f, 0xbd3431bd, 0xf5ca26fa, 0xabad1d73, 0x9bb90be7, 0x9b6de52f, - 0x27c6de56, 0x82bda9da, 0xede0307e, 0x26769141, 0xff44e317, 0x5cb912e3, - 0x78e2dd64, 0x9d35b22c, 0x7908b7ce, 0xfef13729, 0x88f7f8e5, 0x8da24c74, - 0x00f095fa, 0x7ec71ebf, 0x9001a074, 0x56d64f5f, 0x87347f93, 0x33b5c405, - 0x5f24edfc, 0xebb7cc77, 0x4c75dd11, 0x10b3ad8d, 0xc2f7caf5, 0x1f47a81c, - 0xacf5d634, 0x4ed8ec8a, 0xb214dbee, 0x3d230366, 0xc261e229, 0x23558cfe, - 0xa1407ce9, 0x5e0fefc2, 0x7478b1ca, 0x31a718d1, 0x630b6910, 0xf13f3a14, - 0xf27fb137, 0x89e2f450, 0x5185d728, 0x33a63d46, 0xfbf52b58, 0xe8b76b77, - 0x33de18fb, 0x0e763156, 0x77c88f03, 0xa8d5b8c2, 0x8d7e7877, 0x4aa29b33, - 0x21c77f22, 0xdee1e027, 0xca7f406b, 0x09df2f7f, 0x4b7a5ffd, 0xe93bb3d4, - 0x0b8f4bfb, 0xf2e4f63e, 0x7d65cffc, 0x92afcf1e, 0xff3cf9f5, 0xe45feca4, - 0x5faa0e9f, 0x4bff5416, 0x3ebc5f9e, 0x7e83df3f, 0xd2ce68eb, 0xd214a385, - 0xbe847b53, 0x23ee5c28, 0xf6ea16fc, 0xf33474f2, 0xdc6eb2e9, 0x6ba2536e, - 0xd51fda0f, 0xf682d272, 0x2764d5f7, 0x704f9fe5, 0x75c44b2f, 0x63c524d4, - 0xa1fb7d44, 0xc4c1ec97, 0xed1fce4e, 0xf8e3c2e9, 0xbfa0929b, 0x05fb7ea1, - 0x8c4eacfd, 0x1c7ef5bf, 0x80ae1c49, 0x26f99e7e, 0x23a7fcf0, 0x49be1b3c, - 0xb592b33f, 0x487f48fd, 0x86be7549, 0xe32763f3, 0xe645e734, 0x8d11c4ff, - 0xe78627f1, 0xf3f50045, 0x67a5d797, 0x5ff3ff42, 0x04bd3d7d, 0xe76125fd, - 0xcc74da2b, 0xdb34f789, 0x1be7a518, 0x7de2313f, 0x8d5d8ab3, 0xaed071c6, - 0x00dcd212, 0x9c04cab8, 0x93f4e760, 0x8373ec03, 0x3d8c1bd0, 0x5f37f7cd, - 0x7a47ab3d, 0x9dd5d7ce, 0xf6ed0e7a, 0x3ee42528, 0xddf166cd, 0x17ce4ed1, - 0xe87a15ef, 0x11b39a6a, 0x8c6bf9e7, 0xb73e4021, 0x60fb93ba, 0x855f1c49, - 0x1ccdeec2, 0x01db3166, 0xe43f43cf, 0x1b2554fb, 0x3c608632, 0xd184cdf8, - 0x6d7e24ef, 0xc795b53c, 0x3c781b53, 0xbcd6d0b5, 0x33379408, 0x31ad9526, - 0x84d8c1df, 0x0339485f, 0xf36f8591, 0x9d5f324c, 0xc79b263f, 0x767f30bb, - 0x506b63fd, 0xb9c29a6e, 0xf0d0fb1f, 0x17a8e181, 0x7422325a, 0x37e79056, - 0x498c8be3, 0x8efcb143, 0x639e5871, 0x222af4b2, 0x8be232fc, 0xc75de337, - 0x3db05f90, 0x46dc41c6, 0x307dfc5f, 0x2adbf70f, 0x0f75a79d, 0xda87708a, - 0xc087fa77, 0x4ac931ab, 0x19901369, 0x870917fd, 0xf9fc1f1c, 0xdfd0cd45, - 0x8349e5c9, 0x9f71db57, 0x3490c725, 0x467e3fd4, 0xe072fb82, 0xac7527f8, - 0x6e292e17, 0x024b8e16, 0x5dee030e, 0xd95dbe03, 0xac06732a, 0x898f26f3, - 0xcdefe4d0, 0xc0ce658f, 0x29bded38, 0xc2f4fc9a, 0x0ff69aee, 0xa9afeacc, - 0x6735302f, 0xb1f80555, 0x1e49fb9d, 0x62d2a782, 0xee7f4709, 0xfc5f0def, - 0xfff441e5, 0xf40eab36, 0xd9eee755, 0xa1db97f2, 0x4e3c65d5, 0x3b47f145, - 0xc9cecbc5, 0xa77a28f3, 0xe85f703e, 0xf3a66b22, 0x03ed9d3e, 0x7cee75c9, - 0x773a7eeb, 0x03ef5df6, 0xeb124af5, 0x086c21dd, 0x55cbc3da, 0xaebc511f, - 0xefcf9222, 0x8cc7ebe2, 0xfb8a0fb8, 0xdf81d78a, 0xd10fc2ef, 0x50f36c3f, - 0xfeb73b3c, 0x1d9bed18, 0xba7ae448, 0x1e817522, 0x42551def, 0x1c68768a, - 0xe068abe8, 0x3646e697, 0xbbee1770, 0x1fb85866, 0xb19936de, 0x1e2be458, - 0x884a69df, 0xf3d77ba1, 0xbca8f26b, 0xfa9c2da2, 0x1e6d4f7f, 0x5f09e747, - 0xa1ff6853, 0xe5a1e520, 0x29b87e78, 0x11e033dc, 0x77e0b718, 0xde21e577, - 0xf3f1762a, 0x9fea05b5, 0x5a4016b3, 0xdf479b56, 0x49aca817, 0x42617f01, - 0x05bfb72e, 0xaf21f368, 0x46acb30e, 0x7d1aabbb, 0x3d479ebd, 0x9e90b463, - 0x807b6e89, 0x336cafc6, 0x24f7f7d3, 0xd0d77f71, 0xdb1ae1c2, 0xc972a2e6, - 0xba93530f, 0x860fd669, 0x7c7acdf8, 0xc2d0c397, 0x6dddfda8, 0xf39528fd, - 0xafcfbb7d, 0x21ae3ee9, 0x14b8eafe, 0x71dbf798, 0x90dc958a, 0xa57c3d20, - 0x0b34786a, 0xc7daa7a1, 0xf4e7e369, 0xdcfc6d4c, 0x738a615e, 0x31c0127e, - 0x3d16b1f1, 0x48b107ee, 0x35f115b3, 0x7b60c471, 0xa97c8049, 0x2237ef7b, - 0xdeeb0c7d, 0x369da237, 0x501b9a41, 0x33ce2e5f, 0x05e9eb04, 0x2f4f5249, - 0x1dda54a3, 0xf9067576, 0x82ac33a9, 0xccfc8501, 0x7e54fa10, 0x1a6b4cdf, - 0x1e6ee3a0, 0xc5347fc7, 0x45f502bd, 0xbe9b0e73, 0x7366f483, 0x7cc3ee3a, - 0x9d03f057, 0x89f90acd, 0x751e742d, 0x0ebb08e2, 0x04abffe3, 0x6f8e525c, - 0xa2c58f34, 0x5b2a7bfd, 0x77befd82, 0x4ecd9de7, 0x47f1afe8, 0x0f689999, - 0x25cfb8e4, 0xcc297bf1, 0xd70d7ada, 0x446f9583, 0x0bde51d8, 0xfb863170, - 0xb44c7b9d, 0xda72814e, 0xc37ca8cf, 0x89ef09b4, 0x7ac14654, 0x7dcfc615, - 0x7c87cc33, 0x9866f8dc, 0xef46ed1e, 0x4873f774, 0x7b37dccf, 0xa1f5c18f, - 0x67a4c1b3, 0x9f38f7e4, 0x09db3d27, 0x5bd237bc, 0xe5267cc1, 0xe5c35dd3, - 0x69f048a5, 0xb73f90b1, 0x552ba390, 0xaf0e485d, 0xe340063c, 0xca63e93e, - 0x27e85dc0, 0x7ef42dd8, 0x02cb9493, 0x79410f5c, 0x3a18ff41, 0x8dfd2bff, - 0x6b2c3960, 0xe5bf52b3, 0xef21766d, 0xb94bca36, 0x6372162b, 0x2cc67e12, - 0x53bbe7c1, 0x5e20efdc, 0xee41aa0a, 0x3f1f68a3, 0xcfc9e50b, 0xf22b4637, - 0x624df017, 0x54fc8049, 0xd0cfde37, 0xb9c5313f, 0x41666f88, 0xcc9fe81a, - 0xac4ff76e, 0xfe0012e3, 0x74322b89, 0x9da9df78, 0xe6f9db7f, 0x8f7ff8e6, - 0x48e29790, 0x67f44f5f, 0x0e61550d, 0x397e873c, 0x2cf7ef8e, 0xb8f1c55c, - 0x45cae0d0, 0x2fe162ff, 0xa1978a15, 0x697a81df, 0x632a91d8, 0xfee51c60, - 0x0ecc41b6, 0xd6d29878, 0x1337d283, 0x0f1147dc, 0x04d36d45, 0xa37d06be, - 0x4ea1c5fd, 0x7832471e, 0x198d8e4d, 0xab724718, 0x6933e748, 0xe04cfacc, - 0x1d7ade7e, 0xbee4c3c5, 0x992b8ca3, 0x807cbcf0, 0x5f42fd1d, 0x37ef4e9b, - 0x7299c704, 0xb0bfddb8, 0xbf7640d9, 0xc3cff1ac, 0x2e7f5074, 0xed05d9c3, - 0x777a97c9, 0xbcf5f21b, 0x0d57dec9, 0xe4ff9f90, 0x7691a8ce, 0xf4eb3e3f, - 0x47689ebe, 0x188f00eb, 0xa35baaef, 0xbfb979e6, 0xc9f7c113, 0x7e4b7f38, - 0x79f3e60e, 0x9f88dd6d, 0xc89954ae, 0xbe015d0e, 0x48760165, 0xe7a91dda, - 0x7c91fda5, 0xfae7ae5d, 0xda323cab, 0xb408c9eb, 0x395c933b, 0xf87d77c8, - 0xddbf1a79, 0x1476b4d9, 0x38a5c1ca, 0xed28b73a, 0xbc1cb046, 0xd31c14b6, - 0x8eed1d5e, 0xcf52ebd4, 0xfa35bb4b, 0xfe772fe5, 0x8a55cd15, 0xe032407b, - 0xb73d6eeb, 0x2deb775f, 0xe3633fc4, 0x6f91e926, 0x1e8f5e6e, 0x98f47a13, - 0x74568f46, 0x27060762, 0x741c9adf, 0x4cf3ed15, 0x3d447fdc, 0xa3dfd81f, - 0xe0c7a329, 0x7327c63c, 0xc15dfb3b, 0x1ffe99dd, 0xfa6b7c9f, 0x88b2587f, - 0xff40ddf7, 0xfd732617, 0x99efac1f, 0x73a7bf95, 0x2f5f4f69, 0x0ca383da, - 0xc1da03ec, 0x16fb0886, 0x5ec80f61, 0xbf7b4784, 0x4d5c1ece, 0x7888599b, - 0x1e0f610a, 0xf616fe4a, 0x94a1f240, 0x5227291b, 0x48e5822e, 0x9f84c5ca, - 0xe9113ac2, 0x57bf1ef4, 0x6cf7ae50, 0x7b46fda3, 0xcf9460c4, 0x976e3f76, - 0xc1d6f242, 0xf1f9084e, 0x6ed68bcb, 0xf290b948, 0x5ca7e522, 0x20ecc5c8, - 0xd6a7d8b9, 0xf70a333d, 0x6bdd92cb, 0x72fde393, 0xd823b652, 0x57ca743e, - 0xb3645918, 0xf218aae3, 0x81a43955, 0x44ea657c, 0xbe499e1e, 0xd968bf35, - 0x6fd3f24d, 0xf4fcfbfe, 0xe9f84e9b, 0x3f0dbe7f, 0x3f63f475, 0x3c03b2ce, - 0xdf40b257, 0x6df9f866, 0xfb8c3bc2, 0x7af9dd0f, 0x0497d600, 0x8d319377, - 0xae133ee2, 0x2f8a2ab3, 0x7494be0a, 0x6cc0fe96, 0x93387711, 0xe1077ae2, - 0x82c0f5c5, 0x447bd39b, 0xb35c5367, 0xb327d711, 0x03f40d21, 0x9b7ff33a, - 0xbdef516f, 0x3e749371, 0xfb9dfc96, 0x4392c78d, 0xb1c78dfb, 0xb5d29bfc, - 0xf8899720, 0x300b8fde, 0x29e138de, 0x0acb6791, 0x46d38f10, 0x3c9ffac8, - 0xfa81ece9, 0x38b8c981, 0x53de39c5, 0xf4b3de45, 0x3f6818f0, 0x8fe619e1, - 0xd8fd439b, 0xb8f6e8ec, 0xedfcc288, 0x3b1fe795, 0x51e886bc, 0xddcce5cb, - 0x3ffbe7a2, 0x79059f22, 0x447e404b, 0x6f037e50, 0x616fa51f, 0x9045e781, - 0x9c21949f, 0xff00aece, 0x7fdf8601, 0x5585ed05, 0xa8d71861, 0xd6f8db8c, - 0xf56bd415, 0xb545ed0a, 0x14d581e3, 0xfbc55338, 0x735f94b9, 0xc23e09d8, - 0xbe78bb03, 0x93ed4a4f, 0x37e8bd1e, 0xa1bddce0, 0xb9d2714e, 0xb78a1183, - 0x7c47465b, 0xdad149f7, 0x6bd1fc27, 0x1e7867bf, 0x6fbe56ef, 0x8dd6cfbf, - 0x6e99f7be, 0xb2fbfc61, 0xfe7f9f43, 0xefe70a5e, 0x21d15931, 0xa8a5c7eb, - 0x37111fbc, 0x68a1f1a0, 0x7be85d4a, 0xb8c513b0, 0x425fb8cd, 0x24f6dcf8, - 0x28d9b7e2, 0x93f2fdf1, 0x196377c8, 0x60cfc4d3, 0x9fdfca7c, 0x8d4172f2, - 0x19d74f9e, 0x9bafaf84, 0xa91480ef, 0xf2f8fdbf, 0xf4cbd104, 0x8476f835, - 0xfb5db7c0, 0xe8ebefbd, 0xf7c3ac35, 0x48e76f82, 0xf86a763e, 0x22ef5a3d, - 0x538e8cfe, 0x5747e8ac, 0xe0d6c2b8, 0x9f2fc17a, 0x6cbe27bf, 0x1d03fb96, - 0x02b5efe4, 0x890abf94, 0x4febcf47, 0x74bafca2, 0x3cb9eded, 0x7335f3b6, - 0x52bc01f6, 0x7fbe0fc8, 0x27faf9e4, 0x7c092e31, 0xd794f541, 0x2c1dc007, - 0xf941758f, 0x15f920ec, 0x03fa47f2, 0xa9e001ed, 0xb8b7ea27, 0x007b4663, - 0xd04cfc9f, 0x27b8a2e9, 0xfb9a3cda, 0x78ddcd93, 0xfb8523ba, 0x7c09cf8f, - 0x9bed126e, 0x90f003c3, 0x1f1fe1aa, 0xe6025bae, 0x3fba784d, 0x93fbce4e, - 0x63d07c82, 0xbf5e36cd, 0x27a3e52d, 0x7cfed93d, 0xa6af7f70, 0x7880527c, - 0xf1fff7f1, 0xee23f461, 0x91db7817, 0x27b0e472, 0xc139d052, 0xf0214eff, - 0x5163bd07, 0x74a1fc8e, 0x761f8fe4, 0xd04f4fe4, 0x774ef4f7, 0x3a7bdf67, - 0xfa0cef7e, 0xea3de19e, 0xd05eff9b, 0xae883f2d, 0x1d744179, 0x942f9413, - 0xff46af79, 0x5c5cbd4a, 0x09e3f4ff, 0x54df1871, 0x9fbf38e8, 0xbd934f9f, - 0xfc956f99, 0xf230e67b, 0xcf9f9fab, 0xd7279e12, 0xce79ba09, 0x787a893d, - 0x51e1ea12, 0xd414fcfe, 0x5f3f9443, 0x7e61fb80, 0xea81757b, 0xed91abef, - 0x7afd922f, 0xefec8560, 0x3a4bca33, 0xb225cf32, 0xbd0bf777, 0xa4ad3cc3, - 0xf035e7f7, 0xfe7d3fef, 0x2b5fc3f3, 0x7841b50f, 0xf79410d9, 0x775fb504, - 0x22b6fb03, 0x82c7fbe8, 0xe504d7ea, 0x6be507d7, 0xcd17dfb4, 0x8b0e4852, - 0xc9fdf046, 0xe60cb960, 0xda522f8f, 0xf6ed63e3, 0xff24895c, 0x1357234e, - 0xfafe79aa, 0xa829fff3, 0xa7c80c89, 0xb21e89b0, 0xc05a30ef, 0xb9d041fd, - 0xc1f8151e, 0xbcde89d0, 0xecde99d8, 0x79ef6c13, 0xd7f03ffd, 0xd22fda24, - 0x54fb25f8, 0x9551be6d, 0xbbbd4770, 0x5f603228, 0xe2265995, 0xfdf3baba, - 0x6389889b, 0x22fc0352, 0x6744f84f, 0xfb653cc0, 0x575d5f71, 0xd4f8bc71, - 0x719b89f0, 0xd8b4687f, 0x14f1b4d7, 0xf68aa5ec, 0x6fc452ba, 0x5d39e1c6, - 0xebee176c, 0x0fd030b9, 0x70bd7562, 0x523f8d9e, 0xd550bbf9, 0x53c01f40, - 0x79d3b311, 0xea7899d3, 0x47d43bbe, 0x0df92f47, 0x47efb77c, 0xd3b412ea, - 0xd2c49747, 0xa945a639, 0x17dcefdc, 0x366135dd, 0x1e231be4, 0xf8db7d26, - 0xf74a58c4, 0xad95ceaa, 0x353ae856, 0x5f646279, 0x3c268fac, 0x4fc43639, - 0x9dfc065c, 0x38276a99, 0x426b36dc, 0xabdbfa3d, 0x085fb40d, 0xfc457e2d, - 0x3069a4f3, 0x968bb7ae, 0xb0fda7f5, 0x1a4f9fe2, 0x8ab0f787, 0x3ed0371f, - 0x4ace8b49, 0xeaf72271, 0x6a2e74b1, 0x7a910ad6, 0xcdf4a2ee, 0x1abafcff, - 0xbeb569ef, 0x0efbd0a0, 0x7bad5c77, 0x9b9e1067, 0xf74ee9ac, 0x7580de2e, - 0x3efb9e00, 0x17b7bebe, 0x089f21cf, 0xa473a2ab, 0x8bee9ed0, 0xbfb35e95, - 0xdb0b313b, 0xd0e5d6ab, 0xa39414fe, 0x956a7cff, 0x41ef09ba, 0xc2594515, - 0xa9f6fcf1, 0x75c518af, 0xa26e3d4e, 0x478e2277, 0x8fac67ba, 0xe8b8fba3, - 0x8a53b3e9, 0x3c014a3d, 0x67d0da4c, 0x96126262, 0xfb7d049b, 0x1e011544, - 0xfced748a, 0x24a4f643, 0xa527e786, 0x05b899f6, 0x97ea71e6, 0xd87ce9bd, - 0xe4e754c1, 0x2fd7c054, 0x52539cd2, 0x6e5e11e3, 0x0ffcdeb7, 0xe3fc8fdf, - 0xe404e285, 0x395287af, 0x56d1bf5f, 0xbef8109c, 0x3d45c977, 0x469bc1f1, - 0x277a22fb, 0xc14d3c30, 0x41f03675, 0x67cdc62c, 0xf00b7589, 0x219d92f3, - 0xa9e1abfc, 0xf1abd12a, 0x48d9f1a7, 0x0f5f3f5f, 0x19f5177f, 0x5f2037ad, - 0x2d7321b1, 0xa693b9da, 0x0f44ec25, 0x91fe7ed6, 0x3c230bed, 0x7985b619, - 0x7e3032c3, 0xfc871cea, 0x7aeb12cd, 0xc804b64d, 0x77ff68a1, 0xfbe73f0f, - 0xeb8f6877, 0xfe7bbfbe, 0x9fb812d7, 0x4697db21, 0x5ce83c59, 0xf458b69c, - 0xfaa38f48, 0x3cf0a7a5, 0x060bc95a, 0x2f2503b2, 0x8ad63fc4, 0x06f807fa, - 0xf3c16be3, 0x81aa63fa, 0x933a31c7, 0xad18cf4b, 0x1331b25c, 0xc99dbe71, - 0xdc86cd65, 0x3b239b89, 0x2b52cb97, 0x5ee34fd7, 0x9651efe0, 0x71e8b50e, - 0x0bf4737f, 0x7ba16d6f, 0x86c20b74, 0xd289bde0, 0xaf444c17, 0x63c58b16, - 0x13ef0dbd, 0x9031f458, 0xedca9b3e, 0x9f90bd69, 0xcde9955c, 0x7ba52843, - 0xf0df7212, 0x9e6792ec, 0xe797e3c5, 0x70da7798, 0x2765dfc0, 0xbbcbd3e7, - 0x063f8a54, 0x1f9623ef, 0x61cc69dc, 0x788fb137, 0x32c3fd83, 0xdfde22d6, - 0xf07dfd0d, 0xa9abe1fe, 0x0687fbc1, 0x2a5e4fba, 0x37730ff6, 0xe9770428, - 0x3fcf7e12, 0x8dc79637, 0xfa052e4f, 0x1ede691b, 0x0f3c10eb, 0x294eedcd, - 0xf866bc53, 0x0b0daef5, 0x13d98e28, 0x6e7184f1, 0x89e26ef1, 0xae3a4730, - 0x085e4bf3, 0xfe96fc23, 0x7e5fee6a, 0xfaf78599, 0xd702e20a, 0x2f91fbd5, - 0xde197e38, 0x9cfd941f, 0x7a63f65e, 0x45f731a7, 0x7cc31f58, 0xabd8634a, - 0xbd2067f7, 0x9f71d292, 0x5d2bb653, 0xbc5ea3fe, 0x61afac1d, 0x4ab45d1d, - 0xecc7efe5, 0x041d9136, 0x01644f59, 0xad672cf7, 0x72346838, 0x8712c63b, - 0xeedaff09, 0x1c769fbf, 0x6eeaf1ea, 0x2687b8a5, 0x51ef27f1, 0xfbf8e915, - 0x853a8574, 0x268157ee, 0x97497ba3, 0x7b5fb953, 0x679f953a, 0xd0774a28, - 0xb5f29cfd, 0x0cf2c726, 0x7dfb4fde, 0x95df584f, 0x684b9aeb, 0x26f7f33f, - 0xae54ab8a, 0x45867308, 0x3b17f3f1, 0x6af9d006, 0x51f011bd, 0xe2fae766, - 0xa56f98b2, 0x745dd27d, 0x8ecf419f, 0xdcbea1e8, 0x7963f5c2, 0x923de00c, - 0x186e8a33, 0xe8c767be, 0x9bf624dc, 0x7c602834, 0x3f439445, 0xbf7f28f6, - 0x83563a4d, 0xdf6c1b71, 0x31e21077, 0x8474da76, 0xe49515ef, 0x76b49019, - 0xaf7dfa04, 0xdeb899a8, 0x6fb55a2e, 0xf9dfea1c, 0x8de307db, 0xeaf45609, - 0xe63f6407, 0x88b7fa0b, 0x90c56773, 0x22b677c7, 0xb93cb8d2, 0x8a2f1e55, - 0xef345348, 0xf2fac910, 0xbf1e0655, 0x8a8f3d07, 0xc7d97ca5, 0xa5b96fd4, - 0x6ff50139, 0x30c36ef9, 0x6951d3d4, 0x978b2e5c, 0x011f65a5, 0x44362abe, - 0x6583bbd3, 0xe623029e, 0xca156acb, 0x4f8bbffb, 0xbf3d3e47, 0xe428b5e2, - 0xbe61139f, 0x5a97689e, 0xe8398417, 0xc795a1de, 0xe8afceeb, 0x6695f749, - 0xf82d9b59, 0x45acc19e, 0xbfa86ddd, 0x467d5a8f, 0x975a3fac, 0xd3bcc3a1, - 0xbcc6cd6a, 0xe51b7f53, 0x2df38bcf, 0xa57c83f4, 0x6d973a70, 0xbfc467db, - 0xcc44324f, 0x1f2be2f7, 0x4ff8c2f4, 0x2f737a79, 0x07c02bb4, 0xcf1052bd, - 0x9764292f, 0xf3f1b62b, 0x2a0f92ee, 0xee400f90, 0xa83e09e6, 0xf7daf5d8, - 0x902a1e51, 0xf23a43fe, 0x7ef3f011, 0x71b1df2a, 0xefdfe31c, 0x76913e47, - 0x0c2bf20c, 0xf1df8c36, 0xa71a667c, 0xe18f943f, 0xfc019ee5, 0x39fb5d1c, - 0x741c8d04, 0x1a575f46, 0xcbc587b7, 0x5d6fa44c, 0x5a1e5c69, 0x428eed56, - 0x657c5dfa, 0x67dc01df, 0x5601df29, 0x1e421eda, 0x712a3e04, 0x3f0451fe, - 0x389517f9, 0xfcff28df, 0xc85ef9db, 0xf3e32561, 0xd4adf393, 0x7acbf98b, - 0xc124fdf1, 0xe04c652f, 0x2e6f576b, 0x50ce4277, 0x0ebde98e, 0x4db73f31, - 0xf7e50efb, 0x22dcfcc5, 0x28bad665, 0x17d20fc4, 0x103e0ff5, 0x04fa9469, - 0xbedc5c9a, 0x4bf1ce91, 0x57f8497a, 0xdf403809, 0x7e6c6339, 0xf274b63a, - 0xe095644e, 0x778f639b, 0xfc07af49, 0xcf4adf9d, 0xeabf116c, 0x7c93c603, - 0x7dcbc723, 0x38ddd279, 0x87dfe86f, 0x8f71cbfd, 0xd8f4227a, 0xe5c651cf, - 0xe52fc243, 0xa1fab732, 0x614707bb, 0xee968bbb, 0x9cde7003, 0xacd2ab8e, - 0xfd13bdf4, 0x59def805, 0xfadc50af, 0x1fe75898, 0xa8b5fc7b, 0x7e7e01e2, - 0x277c427f, 0x307f0cf9, 0x6de1263e, 0x7038f1b2, 0x0f52dc30, 0x9f73b849, - 0x2c6eefb8, 0xbee3f097, 0x4a9f2051, 0x957e4a3c, 0xf982f5f7, 0xda4e7896, - 0xfe73b54f, 0x463d4cae, 0x943a77e7, 0xfc27f707, 0x5ce213a2, 0xe33c6b79, - 0x8915ff71, 0x8af735fb, 0xb40c8b18, 0xc08ed23f, 0x807d1acf, 0xa7bf69fd, - 0x8b3ce716, 0xd690bb74, 0xc73ffa8d, 0xd0398cea, 0xe699d96f, 0x9dcef871, - 0xb8ef43f4, 0x31a353ea, 0x9f8bb55e, 0x52fc9377, 0xc93f6176, 0xffb8b941, - 0x83eab454, 0xefc8e182, 0xbed035bf, 0x63e3d14e, 0xcfdfe88d, 0x187332dd, - 0x41ef01a2, 0xbb3f5ea0, 0xbf266879, 0x984d6059, 0x3621f786, 0x01ed333f, - 0xaf559f28, 0xd80dbbd2, 0xd16fca0f, 0x5f1499a3, 0x52d6113d, 0xf8fd0a30, - 0xf456a81f, 0x32df6fe3, 0x7f6c31f4, 0x0c6ba5bb, 0x39b1b63d, 0x7d4ef296, - 0xe907d934, 0x8073caf7, 0xc7dee2d5, 0x3fde845f, 0xe22a9edc, 0x2f755ffc, - 0xdd6f8fdc, 0xacef4618, 0x75ed1a14, 0x4f6f1c3e, 0x54675a17, 0x23eaf11a, - 0xbf255bdd, 0x99918e6c, 0xb9508693, 0x0fca0939, 0x451f9a1a, 0x51f0723b, - 0x3f7c60cb, 0x86d7a992, 0x9a7f7315, 0x6ac63bef, 0x70912ddf, 0x0fc6247c, - 0xdf7e4fee, 0x1b08eb84, 0xefa44fdd, 0xedf8aecf, 0x6783b434, 0xe1b4f6b7, - 0x09ef4fbc, 0xa703fba3, 0xcf77da0d, 0x57def56e, 0x79297df0, 0x9a74f56f, - 0xfc938fd6, 0x377bc37e, 0x839ed37f, 0xa5b9d1bc, 0xdd194b0b, 0x8d397efb, - 0x2263f7d1, 0xe789dabe, 0x4d6a4b08, 0x7307bc56, 0xf71ef912, 0xfcab76b3, - 0xcb99a5fe, 0x99ddc9c1, 0xe4b7bf74, 0x525f3c6f, 0x3ef178a7, 0x9fa7fef2, - 0xb30af3a0, 0xabc4cfc1, 0xf3feed09, 0xa1a7a7ba, 0xb8765c38, 0xfe7de257, - 0xf9f95bcb, 0x32ef0e8a, 0x2079dc1c, 0xdfb9dec9, 0xcbfb5dfc, 0x9f110e32, - 0x2fcfbdae, 0x4fd72cf1, 0x8c3f026f, 0xdbc7e218, 0x90e74b67, 0xa9617cbf, - 0xca4bd29b, 0x23b7b5b1, 0xe9a25b1f, 0xeb1fc0be, 0xbdf1519f, 0x835df2a8, - 0x783ae1af, 0xbd346454, 0xd2d9f293, 0x7a8fb425, 0xa5156961, 0x0e32de92, - 0x46aec777, 0xfab3eefa, 0x9fbc06cc, 0xb46446fb, 0x90b603b0, 0xdeeced74, - 0xb9d79cb1, 0x4afa701f, 0x9d6dcfb8, 0x6af38519, 0x61b63e7c, 0x2235d224, - 0x5f7e8ada, 0x724738a9, 0xabf73d6a, 0x7fa398cf, 0x3df40f93, 0x024a61b3, - 0xbb3737be, 0x5869def1, 0xb147b25e, 0xb1c07ae2, 0xae145267, 0xb7d53edb, - 0xa8fde144, 0x7bcbd74f, 0x3bfa5e55, 0xd8f2a354, 0xca3f6c14, 0x0cf667a7, - 0x7c8d75be, 0x9e82f232, 0x879ebfee, 0x5c938a72, 0x0938a70b, 0xb9e2c4fc, - 0xf3afd991, 0x3afb4af8, 0x6ef3ac57, 0x347ef317, 0x31f726dd, 0x04773ca8, - 0x61bd3f2f, 0xefec44e7, 0x158366ec, 0xb36cfee1, 0x079ffa81, 0xc01d33eb, - 0x5f2b667b, 0xd71e60f7, 0xf2b767cb, 0x3abccdf5, 0x5f29bebe, 0xfbf27060, - 0xcc7e5aa2, 0xef47680d, 0x5ef274fb, 0x9f273cc8, 0x97b03cdf, 0xbe60df38, - 0x7475618d, 0x9e9bec8f, 0xdbe60d17, 0x855f92f9, 0xd7e7687e, 0xe044f8ce, - 0xf91de513, 0xbcc3f255, 0xdedf7cf5, 0x07383756, 0x47f24ef9, 0xd5593bf0, - 0x57dfc646, 0x7bd385d4, 0xed2293b8, 0x530fb406, 0x20c65ae2, 0xe74e3e5a, - 0xab9a807e, 0x37bde273, 0xf90a6d56, 0x748acece, 0x744557ee, 0xdeefc465, - 0xcf3f2b74, 0xc97fee29, 0x86922614, 0x84527b76, 0x343b0bed, 0xaefd3a79, - 0xcfc0f47b, 0x3db76e93, 0xd8c1ddda, 0xee0bd32f, 0x267cc3d1, 0x7776da65, - 0xbff3fc83, 0xb7f3c09a, 0x201a86d9, 0x78994cbf, 0xd7c818cf, 0x4a9f3ba7, - 0xece7180f, 0x38692e96, 0x19ff283f, 0xbbc5d796, 0xa5698e7f, 0x49760fb8, - 0x24b41d69, 0xfdfedfc3, 0x7fa3963d, 0x2df3fbb4, 0x18ee9606, 0x7f097980, - 0xdd25b4e8, 0xf8f4abf9, 0x8cc5e58e, 0xf5e74e3d, 0x0e1efc3c, 0x09ccb8fc, - 0xf38a4f78, 0x97bcb15b, 0x2f741353, 0x9fefc1c7, 0xf252fbc9, 0xff5f543e, - 0xb70db27d, 0x92ec9f72, 0x2a1dff81, 0x0fbda9c5, 0x89fc34a6, 0xf6a9f9de, - 0xa23096b0, 0x4d9ef683, 0x7753be39, 0xa20bdd1b, 0x6f4c87fb, 0x57337d27, - 0xac683bfa, 0x29dff987, 0xfcfc8960, 0x1f82a3c1, 0x3d652f4f, 0x9fe8807a, - 0xca39b77f, 0x985c700e, 0xfa85ebe8, 0xfddc3220, 0xe9d7c427, 0x0ba9d50d, - 0xaa1ef0e3, 0xed0f91c9, 0x7df978cf, 0xb7e132ce, 0x42f1cdb2, 0x3bbea82f, - 0x46535da1, 0x87684ddf, 0x757c17de, 0xfe97c321, 0x192bd423, 0xed049d7c, - 0xde5d3ce8, 0xb1e2bbf2, 0x4fed85dd, 0x700d98f4, 0xbc06009b, 0xfa1e35a7, - 0xf7a3611c, 0xfb4a98aa, 0x7efe5ecf, 0xa2799e92, 0xd5eef86c, 0x3ee2e933, - 0x9413dd11, 0xeff89274, 0x1a181740, 0x999d59fd, 0xbeee1019, 0xfdfd036c, - 0xf91f492f, 0xddc2e2ce, 0x7742fe3c, 0xe31e4524, 0xe2cda748, 0xb0759fef, - 0xbf916f8b, 0xd1e9620a, 0x330d9fe8, 0x11c9db43, 0xf5d88d1b, 0xff2f6d77, - 0x92fc2e9d, 0xe0706cc1, 0xa2a5923b, 0xd0b558cd, 0x2d5bef8e, 0x7bd3378c, - 0xe85f0b25, 0x96c1fc4e, 0xb60590fc, 0x89621b63, 0xa866565f, 0xf5b9ff84, - 0x2a1dde8c, 0xf3a64fa8, 0x36f5f994, 0x12daa34a, 0x6fecfca9, 0x7ae2c9de, - 0xe0a7d389, 0xa68cba7f, 0xd3ff4b73, 0xd9d6529b, 0x6691a77b, 0xf0bbcfba, - 0x0b6bb720, 0xc7bfcaa7, 0xbbafefc2, 0xc8ae3804, 0xb90b8a1a, 0xe753dc3a, - 0xf0ba57ef, 0xe77e00be, 0x677d5034, 0xfc4a57ef, 0x82dd049a, 0x7a9cb3df, - 0xde913330, 0x59ef147f, 0x9aed174e, 0xceb3bdc5, 0x4fbcb5de, 0x6a227bb4, - 0xddf2135c, 0xc8696774, 0x9ef52d77, 0xcffa0730, 0x7a48d486, 0x373ee147, - 0xf59a97f8, 0xf11e8b4c, 0xbf9b2d30, 0xba753973, 0xfd90deb6, 0x4373e939, - 0x92778776, 0x4d8fa80c, 0xecfb6d2e, 0xf50ec2ae, 0xf6bf7d65, 0x2354d15d, - 0xbe3d4fd9, 0x69f90b3b, 0xf4515de2, 0xbfffd10f, 0xff10b4ec, 0xb83bc49b, - 0x112b2ccd, 0xbeadc2f5, 0xdbfffb27, 0xefc1b1fb, 0x03bf06c4, 0x42eb7fdb, - 0xdd607e4d, 0x6fed350f, 0xa9ae5fab, 0xad5bec1f, 0xfa6ccfa9, 0xb43f2699, - 0xfb4d39f9, 0x693647e1, 0xbcb647ea, 0xfdbfa9a4, 0xfe4d0ecc, 0x683fd68e, - 0xb6d9dfda, 0x61cf9357, 0xe7da68ef, 0xe4d03f9a, 0x57ff5ac7, 0xc4aefed3, - 0xf1fa9a13, 0xfa9af3f6, 0x68ae7d09, 0x2f8e05f2, 0x373fed35, 0x457757ba, - 0x0cea22bf, 0x433aadf1, 0xf944f861, 0x6629a6e5, 0xba6b07d4, 0xf8247d0a, - 0xd3b0b96f, 0x7ba307ac, 0x6cd563ac, 0x3d5ff11f, 0xc1a0bbff, 0xde7f4f76, - 0x1ff8c4e5, 0x6bdf8d7b, 0x527f068b, 0x8c7e301f, 0xff02ccd3, 0x9e6c5dee, - 0x778f9355, 0x77da6a25, 0xd4d76e99, 0x68fbb927, 0x38e653ea, 0xaab4f934, - 0x5df69a11, 0xf9353897, 0xa69e4f0c, 0x971af77d, 0x76b3df26, 0xef7da6ba, - 0x7d4d6ef5, 0x4d1cef5f, 0x55adff7d, 0xbac0fc9a, 0xb7f69a25, 0xf5347bd5, - 0x9a357d83, 0x5aa6ccfa, 0xf3687e4d, 0xe1fb4d7a, 0xfa9abc47, 0x355b2d91, - 0xa99fb7f5, 0x68efe4d3, 0xbfb4d7ad, 0xc9a7cdb3, 0x9a83b0e7, 0xf7e6b9f6, - 0xd6b1f935, 0xefed344f, 0xa9a63c4a, 0xab3f6f1f, 0xce7e97a9, 0x6b9f3e84, - 0x53df85cb, 0xe697f8e0, 0x6ef7f6fb, 0x1f742877, 0x6ed75cea, 0x96c57df2, - 0x24fd1530, 0x6c99c517, 0xf5111078, 0xb727de15, 0x8539f3f1, 0x238aaf14, - 0x944c887f, 0x810bcf1d, 0xab8510df, 0xf40c8cb6, 0xfefc23ab, 0xccf5ea5b, - 0xdadff79b, 0xd5dcff84, 0xf288beee, 0xfb6eaf31, 0x989f7a38, 0x1c225679, - 0x77bffdf2, 0x956dde83, 0x19f378e9, 0x17f00fa6, 0xa6d5860f, 0x389af90e, - 0x05f378c1, 0xb6c1ef86, 0x22e22bf7, 0x17bdc7f8, 0x16bff406, 0xf7f817d6, - 0x9a976b23, 0xffc76fe9, 0xf295a96c, 0x522696eb, 0x3a00fffe, 0x0047bf29, - 0x000047bf, 0x00088b1f, 0x00000000, 0x7dedff00, 0x4554780b, 0xeedd7096, - 0x9d248fdb, 0x777579d0, 0x493cdc9e, 0xf09d0848, 0x3a3e00d8, 0xc0406021, - 0x490435e6, 0x41a8c1a4, 0xf881ba43, 0xbb75744f, 0xb2021031, 0x10d191b3, - 0x0186c195, 0x099d1964, 0x09d1a32e, 0xe09af09a, 0x1c604c3a, 0x3719d9c5, - 0x8ee2a3a0, 0xcfe31e10, 0x7fc38fee, 0x937ba9ce, 0x380e9dbe, 0xf7ff3afe, - 0xb4fbfa3f, 0xab755538, 0x739d554e, 0x2aaa3cea, 0x89895ead, 0xde6d6322, - 0xf39f4a1c, 0xc99899da, 0x316f36d8, 0x0ebddbc1, 0x72defd82, 0x9d7a774a, - 0x5bcbbf94, 0xaf1ef041, 0xdebdd28b, 0x79f74a1a, 0x92fe543d, 0x9fe081b7, - 0xb6947d7a, 0xff299b7b, 0xc10b6f15, 0x046dbc07, 0x53f5eabf, 0x4bdde1da, - 0x76de1be9, 0x76f4ef2a, 0xb7a6fc10, 0x6f2ee08b, 0xbc87c10f, 0xf11f04bd, - 0x98f8269e, 0x1ed28fb7, 0xbe9467ef, 0xf2a7eded, 0x0957bc77, 0xdbbf8ebe, - 0xcd2afc19, 0x2631e49f, 0x7ae69730, 0xc9ccc21e, 0x00f63226, 0xff824bfe, - 0xcc8846e2, 0x8cfdd8c2, 0xb0d73eff, 0x9413769a, 0x3ff2fe77, 0x74c60285, - 0x1f8d8ca5, 0xf662690f, 0xc634c6ce, 0xe675b026, 0xd318724f, 0x63d75740, - 0x4e09fb07, 0xd6191319, 0x2d75dfc3, 0x58c7dffe, 0x94bffc3c, 0x834c78e5, - 0x14095369, 0x55befb42, 0x1a777f82, 0x3e20d755, 0xbf1c8dab, 0x95135a69, - 0xf82c3e57, 0x5563020d, 0x8be9f322, 0x587dfb18, 0xc11b0154, 0x2e8f25d8, - 0x2172c447, 0x04830edc, 0x443a8ff8, 0x2c5d7e0e, 0x9da5b18e, 0xd29b1d86, - 0x84aaf106, 0xfdf035ef, 0x0c1a562b, 0x3a3d64ab, 0x1df203c4, 0x9ec618da, - 0x4ba6b8b7, 0x8a60ff90, 0xf687a7c6, 0xed9fc999, 0x2dec648c, 0xe6066b8b, - 0x77dcf25f, 0xc07f1b0c, 0x7ec6cf6c, 0xe2ba1b66, 0xfdff4117, 0x9df6b5c7, - 0xe1f3f0d2, 0x6c67296e, 0xdfca0ddc, 0x02ec973c, 0xa2ffca3c, 0x9ffce175, - 0xf85645d0, 0x492f01f3, 0x1a4a78e0, 0xeadb3a55, 0x7cf8825a, 0x47b9e919, - 0xe5f85303, 0xacf6ab6d, 0xae552181, 0x82e11aca, 0x2582eeef, 0xcd8c1963, - 0x418e9265, 0x38e67cf9, 0x2d4d069a, 0x17822e64, 0x6fa51f31, 0xb1aabbc5, - 0x4fccc59d, 0x21b26bb0, 0x82b8d435, 0x78cb72f1, 0x947c65b9, 0xabab71f4, - 0x20e5e38e, 0xba4c4ebc, 0xa5c71b23, 0x5596f5e0, 0x58737aa2, 0xefc476ff, - 0x3f1783cb, 0xd2863211, 0x174077c7, 0xeb1e6826, 0x73ac3d31, 0xf7d18ea3, - 0x7e088f8d, 0x2e856ba4, 0xb791992a, 0x0be418fb, 0xf4027481, 0xd2fc8451, - 0x92373a9f, 0x0949e4e8, 0x92707c1a, 0x0b1fa7d6, 0xb3f8d4e3, 0x87d12d05, - 0x1efc005e, 0x48fa0388, 0xea0e9e1f, 0xe00d219a, 0x67afa01f, 0xaff3bdb0, - 0xce0e5dff, 0x49cdfb97, 0xa357ce12, 0xe801d606, 0xd6b6f7d8, 0x99925bbe, - 0x94ed6014, 0x6ba47e31, 0x73edda26, 0xb17ae0c7, 0xdfa84ea5, 0xfb0d65ad, - 0xfbf687f3, 0xb417ae2a, 0x2ba6c27f, 0x9cbb53f7, 0x9ff295cf, 0x63c5fae2, - 0x5eadebca, 0x16ad69f5, 0xe8713ff0, 0x131a5e9c, 0x6f0d1c62, 0xe00666e7, - 0x3338eeef, 0xe44261dd, 0x45e7f2fa, 0x949fe60e, 0x1fa144e9, 0xb5d23ead, - 0x178814c3, 0xf9e817ef, 0xd13744e7, 0x4419cf40, 0xe0f89fcf, 0x690639d3, - 0xfb4822c4, 0x20ba6a60, 0xd660bd75, 0x672cdd23, 0x99ab4a76, 0x6007d293, - 0x9d7e91f9, 0x38f4a7be, 0x76b20fef, 0xbe2bafca, 0x7cf482d7, 0x8a95c6bf, - 0xa5eb2d70, 0x2feb377c, 0x2dfcc1b3, 0xd47b5e6c, 0x6fcf5806, 0x025a6a79, - 0xff3cefcc, 0xce98a3b2, 0xe27c25dd, 0x7a3f8893, 0xc13eaf10, 0xfa113eb3, - 0x92a5fbbf, 0x3f9049f5, 0x85d7cb47, 0x175f2bfd, 0x8f047e45, 0x97a1f81b, - 0xe341cb8f, 0xab9546d2, 0x09f2a1f8, 0x9da010e6, 0xff0683fe, 0xfe00b4ce, - 0xdfe87e28, 0x898e5093, 0x7ae0f7fd, 0xc434dfbb, 0x083f7ae0, 0x29c71be2, - 0x806b1838, 0x2ad690fe, 0x882a8863, 0xe1621fde, 0xb9f7ac76, 0xa79fdf4c, - 0xcfefa230, 0x4060e605, 0xa67417bf, 0x5ae50166, 0x0456cbaa, 0xbe60acf8, - 0x6ee50626, 0x38054bcd, 0xd725234f, 0x1fd744a7, 0xa61537b5, 0xa7f7fca1, - 0xf7ff280a, 0x698dec19, 0x5d84fdaa, 0xe321408f, 0x3f9f3861, 0x0ec776c0, - 0x3e284bc5, 0x14429ff6, 0xf33d0663, 0xbf888b19, 0xebe444d9, 0x57f13d44, - 0x066d4e23, 0x3c94e3f6, 0x9feda1a6, 0xf9edf190, 0xef744b4a, 0x16ecf183, - 0xf7c3f542, 0x60f8432b, 0x2c3f243f, 0xa7d1fa8c, 0xfa563e71, 0x64bea663, - 0x6a75d027, 0x86974b84, 0xc716c182, 0xcb998be5, 0x4fb49e97, 0xe67d7133, - 0xc8a8de4c, 0xdd8f6a65, 0x09d1e5c6, 0xf843e49d, 0x1d9a4944, 0x9c80d724, - 0x97f8abbd, 0xbb8f11a7, 0x2d2ea68c, 0xdd16eca4, 0x7d94fa9f, 0xff707d30, - 0x7fd94bbd, 0xeffbe16f, 0xefb5991c, 0xf1babb12, 0x3aecc67b, 0xfd972fc4, - 0x6d8f995e, 0xf22adfb8, 0x0b7ec871, 0xf9c5eb03, 0x832b2513, 0xc7c0b574, - 0xdc253abf, 0x36c47c8f, 0xf4f8d2e7, 0xfe0cfcb2, 0x58c15ade, 0x13c651a6, - 0x19704bfe, 0x20ce6659, 0x5663549c, 0x9b1e29c1, 0x06c8feaa, 0xe69e5549, - 0x679551cb, 0x7055db34, 0xaab14b56, 0x8736a8fe, 0x97f5ce0a, 0xede7eaab, - 0x31e0aa75, 0xfaaa15ed, 0xaa5c3b63, 0x1aaec2f2, 0x1eb8f955, 0xd09e0a8f, - 0xffaaa0db, 0xaa7da777, 0xcd7d49f2, 0x9f29f2aa, 0x5be0a8b5, 0xf554dbfb, - 0x57eabf6f, 0x7fb09795, 0x354f9556, 0xd3c157ee, 0xeaabafcc, 0x16fb80bf, - 0xb61dcff0, 0x0cfe556e, 0xbbeab8e9, 0xaa4e733b, 0x75e417e0, 0x270e2df6, - 0xe72d68be, 0xfb6cd1fb, 0x5876aa07, 0xfebe68e7, 0x7b6f3c61, 0x510b1fcf, - 0xf4d76e4e, 0x4add21a7, 0xf222735a, 0xdcf16671, 0x2c664043, 0x14aab1db, - 0xf94e5bc5, 0x1d308753, 0x8a5fdced, 0x715f926c, 0x05a610f2, 0xd0a58bae, - 0x44d7b31c, 0xc8b4c61f, 0x8ad53853, 0x3dcc34a8, 0xdf44e98c, 0x5728a9aa, - 0x3f5c785f, 0x2a28f91a, 0x074fa146, 0x827d67d1, 0x7eb9f886, 0xf28fc9b1, - 0x24c532c7, 0x96139032, 0xb1d65a1f, 0x9a8b4c02, 0x1af66d31, 0xfa0f5f99, - 0xba519780, 0xfe666bc9, 0xaf67206c, 0x93fae08d, 0x43a795f7, 0x44ab233b, - 0xe699aa33, 0x48258f51, 0xe5f5bed0, 0x765d9c96, 0xb0edd6c6, 0x42e5d7cf, - 0xc59e19ff, 0x4e01a23b, 0x30058e63, 0x2398167f, 0x25b19936, 0xfa76df3b, - 0x97c287f2, 0x244d9d33, 0x5cf6c417, 0x7694ffd4, 0x6e7e9637, 0xdf2198d7, - 0x11e74bf7, 0xf1adf798, 0xc21df4e1, 0xa75f9925, 0xb60b475d, 0xf69ef90b, - 0x4cfc7c10, 0x977fdf1a, 0x0a7d73a4, 0x66eb8487, 0xacc6cbe5, 0x808ca7a0, - 0xa93adcb9, 0xf0ea0ce1, 0xa027d9a2, 0xe0d7627c, 0x892b907b, 0xe0832958, - 0x4e01c3db, 0x6c625840, 0xc7eb967f, 0xc5d5afd8, 0xfa00d9d8, 0xc351a849, - 0xcf9e615b, 0xa3e20e66, 0x89f1aa5b, 0x8fdd0630, 0xf43b769d, 0xc60aadb3, - 0x3d56f00b, 0x7a9437d7, 0xf68c34a3, 0xf8d32ff7, 0xcdaece7e, 0xf49ea3b7, - 0xe79e3ca5, 0x3e8bfdbc, 0xeb7b44ce, 0x3589a52a, 0xf205c11e, 0xb4e95acd, - 0xae9ea0fb, 0x8423e611, 0x348bf2de, 0x1dd7be91, 0xa090447e, 0x1269a7de, - 0x7e9589c1, 0x0d52771a, 0xbf801bb4, 0x6609f44d, 0xe63db7c8, 0x9b3f1013, - 0xf06769d9, 0x885a331d, 0x3cc8d7fe, 0xcbf86b61, 0x0f418fa2, 0x769d79d3, - 0x13bba7ac, 0x271f33e8, 0xb86663d4, 0x47e3c94e, 0xa3eb10b0, 0x0d3e86a4, - 0x9f40dc73, 0xd47d4a8f, 0xddc5fb43, 0xe80b2926, 0xa6c585fb, 0xda211d8a, - 0x9f9e54fb, 0xfeea310d, 0x1f3e5a2d, 0x6cbedc8a, 0xf0a8ebe6, 0xa6689af1, - 0x526be392, 0x846f5bc6, 0xc8cdb5af, 0x6ef8015c, 0xd0cc7e85, 0x55abe1be, - 0xe83f1c66, 0x4fea4ed0, 0xc764f2e4, 0x6ec8728f, 0x21c75e0a, 0x3f9408f4, - 0xa3e908a2, 0x7c08dfcf, 0xdbd2a868, 0xfeb26f51, 0x7b809343, 0x116b2273, - 0x5358be50, 0xdc447aca, 0xae5744d7, 0x793e8433, 0xd654ba33, 0x839fd94f, - 0x3d774bd7, 0x9c12fde3, 0x31d57fef, 0x1f56c7d4, 0x05718f8f, 0x3a4c53d0, - 0xd662cba7, 0x98fe45a2, 0xbd29dacc, 0x7a52f585, 0xd4a7eb1b, 0xa622ccc1, - 0x694ecca5, 0x3a527319, 0x2d28799d, 0xce942d67, 0xce94ed64, 0x8294bd62, - 0x93a9433d, 0x9aeec999, 0xa637fb07, 0xd293980b, 0xa50f31ef, 0x7e9ce999, - 0xc10b582b, 0x4a76b377, 0x24ef803b, 0x8c01fa3d, 0x9c827694, 0x904df4c3, - 0x79769873, 0xa3652625, 0xd287201f, 0xa53b5e23, 0x94c5bcc7, 0x541d78f6, - 0x396f6def, 0x9d78efa5, 0x56f09e94, 0x75ebda50, 0xde53bd51, 0xf5df4a1a, - 0xcf7d287a, 0x69e940db, 0xdfd28faf, 0x1d299b79, 0xc67e07a5, 0x2be9cdf9, - 0xf53e7d44, 0x0243bd23, 0xe591ecf9, 0xe68761d2, 0xb8f1dc99, 0x40661a6e, - 0x235b283a, 0x7359fd20, 0xa43f0e34, 0x0b56729b, 0xe1ba42f7, 0x0cdfd704, - 0x0fd248d6, 0x82f56dad, 0x0876ed04, 0x5808da7d, 0xa9e9e9cb, 0x9f208d73, - 0xbad93a4b, 0x19c23b08, 0xee81194f, 0xfd3ce876, 0x64bca03b, 0x08d734a7, - 0xc8e4d67b, 0x8fb1ff53, 0xe93e54c3, 0x03346b08, 0xfb3d2b3c, 0xe38138a9, - 0x7befc281, 0xaee6733b, 0x253c44cd, 0x34c5f3c2, 0xbf512c30, 0xfa44c47e, - 0xd9db6175, 0x93c00d42, 0x68454c1a, 0xebd40617, 0xae1fba42, 0xf2b9705e, - 0x9655b6dd, 0x0d879c46, 0x0e5a809f, 0x7d19a959, 0xd5f3ab85, 0x5ebe6aed, - 0x837b4cff, 0x09eb03fe, 0x7f6f6837, 0x7d32a396, 0x3a7effc2, 0xdd6fa60f, - 0x6bf68ff5, 0x8e640fc8, 0x5774fdc1, 0xfd339734, 0x04ee9fa0, 0xc8c577bc, - 0x1a4cc6f0, 0x5c43ca17, 0xd29b0db7, 0x77803efd, 0x1f573985, 0xd47ff2c7, - 0xd14277d8, 0xa6d770ae, 0xc933825c, 0xc621b13f, 0x8f931393, 0x97df3cfa, - 0x0d1f935a, 0xbff80293, 0xafcb9d39, 0xe95cb7ad, 0x447681dd, 0xc16586b3, - 0x979b3b77, 0x7681cc6f, 0xf419bc7e, 0xdc478007, 0x0b31bd5a, 0x6a37d3ca, - 0x19656a26, 0x78fc7887, 0x4d9ef573, 0x8f255fa8, 0x7686c98e, 0x99796433, - 0xb857db1a, 0x55bce806, 0x95a7b6af, 0x7e649ff4, 0xce6686a9, 0x954d6c82, - 0x3a1df4ed, 0xdfb81156, 0xefc64cfd, 0xd53c5957, 0x57fdcedd, 0xfee19186, - 0x25fc6027, 0xc3bfb923, 0xfe48ceb2, 0x7ff24b0e, 0xca03bc9d, 0x7634db2d, - 0x6b44e954, 0xea1d5aed, 0x3b598bfb, 0x810ee3f2, 0xe14bef7f, 0x0a28217a, - 0xec0373e9, 0xd3deadf2, 0xfc03328b, 0x9f0ab684, 0xc97bf680, 0x0fa15ac8, - 0x07e49ff7, 0x2dfbb405, 0x15c12e15, 0x8781f689, 0xb965cfca, 0xf80e927e, - 0xfbe12ad9, 0xb992fd40, 0xa15d7012, 0xd2768adf, 0x605158f3, 0xf8b3a77f, - 0x3b07ac3c, 0x75d5f499, 0x782bc27a, 0x97654ebe, 0x95f6c01e, 0xff2e0c75, - 0xabb7067e, 0x5d013d77, 0xe24c1f20, 0xdd89f376, 0xce3fa489, 0xa0770d69, - 0xa9e274fd, 0x6f0465d1, 0x3d40ec99, 0xc9eec4f2, 0xb39d31d3, 0x3bd52665, - 0xb41eb021, 0xb96ce787, 0xd4fcc45b, 0xdb0bc00c, 0x7a27a33b, 0x41e5b39c, - 0xcb47fbf9, 0xe358bcb0, 0x91da09fb, 0x22fb8dc5, 0x1c9e4ed0, 0xa6124af9, - 0xf57d3427, 0x5dffd0dd, 0xdc2bf666, 0xe31b9d9e, 0xfe1cb1fe, 0x74a9f731, - 0xbfd7ea1d, 0xf5a74f4b, 0xc41ccf9c, 0xec835007, 0xf6f65bba, 0x8a4d061e, - 0x3fded6dd, 0xe65ccc15, 0xc11f30e8, 0x5ecbb4b4, 0xd657d386, 0xe9823ce3, - 0x194f5ef4, 0xa7e52faa, 0xba608e5b, 0x3bf5d724, 0xff179f9c, 0xbcaf7be1, - 0xc7c8f008, 0x07a8cdeb, 0x37d13e65, 0xebf92763, 0x21f90c74, 0x45a7926b, - 0x746c048b, 0x787ca0c6, 0x835169f6, 0xad21b9fb, 0xc3610c25, 0xb41ae97d, - 0xb745770b, 0xb3b8d0d4, 0xe3ce19c2, 0x210fb0db, 0x3b45645d, 0x809f9063, - 0x3e1d692f, 0x10d3e993, 0x634731ed, 0x1fcf187e, 0xe1ce17a8, 0x5af503f3, - 0x27ea04c2, 0x13fb2046, 0xbfdc06d4, 0xddfef26d, 0x38093cc6, 0xcf48d61f, - 0x64ebf40e, 0x67fe7095, 0xb02e9c91, 0xfa44d37a, 0x96cd9c84, 0xb89dcf16, - 0xe897560e, 0x3ba40beb, 0xf40706d8, 0x19827491, 0x055bd7da, 0x219c830e, - 0x7e87f0bc, 0x42c98b0c, 0xbf828d7a, 0x0bda02b5, 0x1c7033d0, 0xdf834cf3, - 0x9b177429, 0x4235c7c1, 0x65acbfa6, 0xdf053dbc, 0x9f2e0cb8, 0x83496f01, - 0x7c6568f8, 0x009a1c60, 0xd1ea027c, 0x66f006f8, 0x05d21b76, 0xa7817a48, - 0xc703124c, 0x8471ad5f, 0x7a645da1, 0x4fe8fbf5, 0x02394289, 0xf753fe78, - 0x69f22324, 0x327238f0, 0x46df08d2, 0x6f5187d0, 0xfce2e99f, 0x11e958db, - 0x18423ec8, 0x3a2c9fc7, 0x35681fd0, 0x017416ad, 0xf326b5e3, 0xa5667a7d, - 0xcae51ba7, 0x3b08e2cc, 0xac9df7d2, 0xf3999d7d, 0xc04c91f7, 0xf81b146f, - 0x41c4d899, 0x4f47f0bd, 0x97127bbf, 0x97b59934, 0xf9fee2e4, 0x70b3fdf8, - 0x3a3eb6fd, 0x4ff107b3, 0x3baa79cc, 0x5e741a06, 0x197dd794, 0x6ca4ebf7, - 0x1c0e3f13, 0xe0079247, 0x8d44bf40, 0x41e81cba, 0x65742b05, 0x71a21a13, - 0xe444d1bf, 0x7a819ccf, 0xe486944a, 0x6129c83b, 0x33fd4841, 0xf9e4ae88, - 0xaee7d657, 0x375a4c8c, 0x03af89ab, 0x171bb7eb, 0x5583ca46, 0x6dfa09d6, - 0x011f3604, 0xa658df74, 0xd7680bf5, 0xac28fd62, 0x919de2cf, 0x8769d743, - 0x03399a4e, 0x1ac3f4e5, 0x74366ef3, 0x7edc815e, 0xc3ed7a4b, 0xf90e5471, - 0x7dfc91a2, 0x436af801, 0xb8f5eac1, 0xac6dfd59, 0xb48cee6b, 0xc989f9a1, - 0x3ee2660b, 0x68cb589b, 0x47cb83fd, 0x575ea63d, 0xa3c737b2, 0xbbf988ff, - 0xce7ac1be, 0x8655de4c, 0xbaf07cfa, 0x1a97742a, 0x105f7a1b, 0xa65f3933, - 0x954fd846, 0x92215e93, 0x114ce09e, 0xa2ed03e3, 0x1f7c190d, 0x1335fdba, - 0x23ec43ed, 0x5cb71fa3, 0x93ef577b, 0xa50eb0b9, 0xae683457, 0x1cefa3b0, - 0x484ce1fa, 0xddeafda7, 0xf50affd5, 0x1a657da6, 0xb06ff987, 0x10e819be, - 0x9d80f5f1, 0x2fdaf001, 0xa3a0b4f6, 0xd992b1a4, 0xfa55df71, 0xf3f723d9, - 0x49df9d0b, 0x645735f2, 0x820e493b, 0x2f401e65, 0x7e896900, 0x56731978, - 0x68dd90b6, 0x5907cccd, 0xf6bd6e8d, 0xfe5fb425, 0xefd0cf49, 0xd242af38, - 0xe7f8c095, 0x65ba4a55, 0x5917c7e8, 0xf311ea39, 0x3f94ec2b, 0xf3ced2bf, - 0x417f3c8d, 0x17f28385, 0xbe783a54, 0x3e61f209, 0x7bf85616, 0x42eed0bd, - 0x41a48c53, 0x93a5783f, 0x50355f97, 0x0f603bf9, 0x87c90264, 0xde49f987, - 0xe1a67cb7, 0xb84f12f1, 0x0d5c005f, 0x123d4591, 0x1a7ddfce, 0x8624167b, - 0x01999114, 0xe9c2b67e, 0xf3f942d7, 0x13809fcc, 0x6af546f9, 0xbfe43667, - 0x719a2c91, 0xc0386f7c, 0xabf9c66e, 0xe9de6915, 0x351bf007, 0xd8cf14c9, - 0x7dadfb21, 0x67e48c2b, 0xfc875d05, 0xa2456cac, 0xf2f0c7ac, 0x7ecdcb6d, - 0x0e40c7d4, 0xdff63ad2, 0x001e9227, 0x1cedf0f2, 0xca5e8bd4, 0x484987b4, - 0xb37e6ab7, 0xa12f2f54, 0x19992af6, 0x9559f2ed, 0x97c6bdbc, 0xea0d7e34, - 0x3379a655, 0xf71a0e91, 0xafda3b32, 0x2a9f56cf, 0x9b78458b, 0x87e5cedd, - 0x56342e5a, 0xe12e396f, 0x731a3c78, 0x7ee7d516, 0xe94f46ad, 0xc830ad2e, - 0xd2deb4cf, 0x2a18fca0, 0xd83dec6f, 0xa955424e, 0xb3d4137d, 0x8fd138c0, - 0xf3cf4dbd, 0x1488f77d, 0x8b54b067, 0x4182e65d, 0xa7914efe, 0x187c82d0, - 0xc545f245, 0x525fa35f, 0xf9923fc3, 0xc45df814, 0x3176f971, 0x5d95c93b, - 0x27207aea, 0x52af2835, 0x67f9d4da, 0x2fc504b2, 0xe0879aa5, 0xb87ab679, - 0xe71e0bdc, 0xc2bab8e0, 0x34b8d146, 0xd7285c7c, 0x74d73f20, 0x2b73f288, - 0xa124bb45, 0x853f6bbc, 0x92f51fe3, 0x9e00bac8, 0x13345d55, 0x66d669e9, - 0x6643b90d, 0x0b925eb3, 0xe2b71b37, 0x671e08df, 0x6436f8f0, 0x1cdf6968, - 0x1bd707d0, 0x7d6c1f49, 0xb8c1a4c4, 0xe15be822, 0x973857e8, 0x099e1a55, - 0x532230f3, 0x6bafd7d6, 0x34693cb9, 0xacea9d11, 0xfa04e58f, 0xa5d1841f, - 0xeebeb023, 0x72bcec7a, 0x68e91b8a, 0xac72c1dc, 0x93639658, 0x2a7c60fa, - 0x933873ff, 0xd6f7e602, 0x7c1518fe, 0x5544d5fb, 0x2e1012fd, 0x8d53e581, - 0x69f2aa79, 0xf82a71e6, 0x5514db0e, 0x54d219fd, 0xce677c15, 0xb3faaa9d, - 0xf055f3ed, 0x544bc55d, 0xee3ae7f5, 0x2fcf9555, 0xbe55487f, 0x0546b9d0, - 0x7bf8aa2f, 0xaec5fd55, 0x92f95546, 0xe555279a, 0x9293f6c1, 0x3f726696, - 0xe79b56cf, 0x8be483a4, 0x0e46704b, 0x14a967ad, 0x3dd703fb, 0x53eb822a, - 0xe51af5c1, 0xe04178f5, 0x48feb1fd, 0xe29df20d, 0x91ed637f, 0xd75cff2a, - 0x3ec6c9e4, 0xec72fa13, 0xb2dd23ef, 0xc51fdc13, 0xc53bfcfc, 0x04fdd57f, - 0x56f683d4, 0x715ba647, 0xabbf43bf, 0xf9fd0f4b, 0xb7bfe435, 0xb40bd736, - 0xe7ae6e0f, 0x7aab957e, 0xc00d8ae6, 0x7ef38583, 0x828e78e5, 0x70447327, - 0xcf1860ff, 0x95fb26df, 0x52bf439e, 0xb03f6336, 0x17787e28, 0xac509bb5, - 0x467fa1f7, 0x7a08f6a8, 0x662e5b94, 0x07284836, 0x97ff5397, 0x5823ec2b, - 0xd2567988, 0x398daf56, 0xbd5b7da0, 0xc61ead6f, 0x69399756, 0xbcd0b3cb, - 0x1fc8c3cd, 0x94e668f3, 0xe7816b2d, 0xa25321ff, 0xf9104975, 0xf75f3f3c, - 0xd03db9c6, 0xa5956b5f, 0x706ae508, 0xf3bb9279, 0x941bb1e2, 0xd5f2bf3f, - 0xd1bfee0f, 0x671d75f7, 0x87ca029a, 0x24568bf5, 0x1d004732, 0x7ed08648, - 0x74c81ff9, 0x27ac9ee5, 0x5a33d63f, 0xcfc893d7, 0xd7ff2617, 0xddf0bdc4, - 0x3dcae979, 0xfe43a7a8, 0xea1f300f, 0xcf9ebcd1, 0x29e744bc, 0xbf40f352, - 0x2c3bfd47, 0x941edd34, 0x95ad17db, 0x5a07e8fd, 0xd097a91d, 0x7e324fce, - 0x0eea7e46, 0x83abb71d, 0x07e7f7ed, 0xb276edec, 0xedcbf7bf, 0xad5396ec, - 0x8ccf7f99, 0xe45a263e, 0xf98840f8, 0x09b546d0, 0xab12af28, 0xf9024fc5, - 0x4f523ba2, 0x498b047e, 0x6a983bf6, 0xc5017e54, 0x791dd06f, 0x6f7480bf, - 0x7e415ae9, 0x6017f47a, 0x75e5077b, 0x2417f609, 0xe8b4ff19, 0xb51bd8e3, - 0x23f206cf, 0x04fd1084, 0x27f8a1e1, 0xa3f1fb82, 0xccfb813e, 0x27d270ca, - 0x397dc782, 0x6650e4b3, 0xff48f23c, 0x7e503bc9, 0x7ed1d29f, 0x84bd1c38, - 0x1fcce149, 0x266f7ed0, 0x7223efb7, 0x91f95462, 0x0fe644f6, 0x64b35ff4, - 0x321127f3, 0x48cc5b0c, 0x51c6df7d, 0xbcdbdfd8, 0xbb3a13bf, 0xd841f48d, - 0x7bfed0f6, 0xeee7e64f, 0xab69465c, 0x01b7976c, 0x9cfa631f, 0xd9fa4cd7, - 0x843fe036, 0x4a257bb7, 0x4a1cdefd, 0x54ed7a77, 0x4c5bcbbe, 0x83af1ef0, - 0x72debde0, 0x9d79f74a, 0xb792ff94, 0x7a9fe082, 0x7bb6945d, 0x15ff286b, - 0x03e087af, 0x5f8206de, 0x44507d45, 0xa533753f, 0xa85b786f, 0x46dbd3bc, - 0x3f5e9bf0, 0xbdde5da5, 0xdbc87f94, 0x6f11f04e, 0xbcc7c107, 0x78f7045d, - 0xdb7d287b, 0xeff94bdb, 0xdc134f78, 0xb1938f2b, 0xfa2f5ee6, 0x84a25c2b, - 0xaeb3ddfa, 0xd7ea336a, 0x331a65b6, 0x9736f38a, 0x39fa0566, 0x78f255b6, - 0x86956d9f, 0x87a040fc, 0xb39f51fa, 0xf8fa7b2d, 0x405f2a34, 0x49b15be5, - 0xabac4a30, 0x56cafeb8, 0x159ea9ea, 0x77c1020f, 0xfd2b6adb, 0xb25b805a, - 0xbadca9c3, 0xedbb244a, 0x3a278d79, 0x245deb9b, 0xae3aadbf, 0x1074283f, - 0x22e9fb21, 0x974a44b2, 0xa3fc7365, 0x23ef4232, 0xfc4a5919, 0xc707b9a4, - 0xf182ab67, 0xf555be21, 0x5a5f8c46, 0x49f183ef, 0x3aae3fa4, 0xc3247804, - 0xc07f1178, 0x6cc2fc87, 0xad97d719, 0xaf08eb55, 0x94f365e4, 0xda346778, - 0xfa9e6de9, 0xa56f84b9, 0x36cd7e48, 0xfbe8a1d7, 0xe7ca4e50, 0xe1f1ac7c, - 0x50fe7f4e, 0xf082327c, 0xddb8c6df, 0xd2fa0c90, 0x00e310fe, 0xc7a9478b, - 0x198f78fd, 0x26f1fa43, 0xb2627acb, 0x3d8ff9c0, 0x6dff122c, 0xc1f7a067, - 0x7e81cf77, 0x503943e7, 0xfa156fba, 0x72cd1eab, 0x3c02cc4d, 0x3f8d247e, - 0x531c0224, 0xaf4fdbce, 0x1ea0f717, 0xae7deb0d, 0x3e37f209, 0xb689d9b8, - 0x6966ec71, 0xdb5bb22d, 0xd01357b2, 0xa82c95ff, 0xcb4947d7, 0x3bb63c65, - 0xd5cf7b78, 0xb64fe48b, 0x76903aae, 0x865bf784, 0xfa8e26fd, 0x61ba187d, - 0x1a481632, 0x55c91914, 0x2fec45e2, 0xe5cda1ec, 0x66fc5fd8, 0x215fd287, - 0xe775f7f6, 0x65e3e469, 0xbc085756, 0x37279386, 0xb38b2393, 0x8e48e322, - 0x9424b124, 0xb8ebcf23, 0xe49df2dc, 0x861d24fa, 0x1fb43499, 0xc4ae7e25, - 0xe8e383d3, 0x243d3235, 0x61c74219, 0xfde80d57, 0xddb7aa3e, 0xe749c9b1, - 0x0b3e304b, 0x6c75ab45, 0xeaf3ae05, 0xdaf37092, 0xa4a0f410, 0x018e505b, - 0x468bdfdf, 0xb9b3b523, 0xe1a3b79c, 0x56cadced, 0x32625c11, 0x6bc842fb, - 0x6e5a7d25, 0x4e2c81e7, 0xbe0f49b7, 0xae18f1b4, 0x3a3adbef, 0xc69cf413, - 0x04ed11bf, 0xc92d09df, 0xfb6d44d7, 0x78013d8e, 0x79e3cb35, 0xb5cfef4e, - 0x7b40ff23, 0x915728f9, 0x7fc9f25f, 0xcc0566c1, 0x5addf2bb, 0xa3fd8fd9, - 0x29a21b6b, 0x2eb55cbe, 0x36a3f50c, 0xb07a2466, 0x85d13cea, 0x4560f401, - 0x1f410cba, 0x4af4b2fb, 0x3254d53c, 0x7c32e311, 0x728a9e5f, 0x583ef009, - 0xe1fb451d, 0xdeef65d4, 0x5be01639, 0xd47688ae, 0xe5ab9ecb, 0xfd2713e7, - 0x26e74351, 0xdb9c7cde, 0xb7fdb77d, 0x7bf41eb2, 0xb3e9c827, 0x7a41e768, - 0x77b3334b, 0x52dcbac1, 0xcdff226d, 0xb3c557ad, 0xb91a7681, 0x7da3c7a4, - 0x5335fdc1, 0x803ca1fa, 0xa67d26fe, 0xaa330fae, 0xa1233d45, 0xab6f9d4f, - 0x1a66703a, 0xcb56d3f4, 0xf6bb6e3f, 0x7d8471fe, 0x93f21af5, 0xf429f500, - 0x4dfe4093, 0xe78097d1, 0x191a3716, 0x32eb73c9, 0x41e519a3, 0xe49c25b7, - 0x1362db5f, 0x321ba1e9, 0x9ea18757, 0x8faaa86c, 0xdea474c6, 0xa77d03b7, - 0x7dffbbdd, 0xe4812d9e, 0x817f3f2d, 0xfa0c5984, 0xae7abdc0, 0xb6faf8e4, - 0x7944cb4c, 0xc3f2a1a9, 0x8b7dffbb, 0xac077d0f, 0x3490f085, 0x7e0f912c, - 0xe29bbe00, 0x2fdf02d4, 0x444e6740, 0xabae74f8, 0x4243e507, 0x8b1baf9c, - 0x56ce9ab6, 0xcae2f9d2, 0x5d33e238, 0x31e987b5, 0x18c8b2bf, 0x9f0ae7c8, - 0xfffcb5fc, 0xbbe71cb4, 0x59b81c99, 0xf7e337bb, 0xbe73a59f, 0x369ece19, - 0x154f230c, 0x9acf18fb, 0x4b6c8a63, 0x7d59eafb, 0xf6eafd48, 0xc567ce6c, - 0x643e7e7a, 0x72f4c54e, 0xfaf8c38a, 0x96c73c44, 0xa9f9cd93, 0x714912cd, - 0xd674b6e2, 0xdf037185, 0xf7f70d72, 0xdafff1c4, 0x3fc9d32a, 0xa2782ad4, - 0x3e78197d, 0xeb8695c2, 0x147306d7, 0xa6b7fd09, 0xfcceb972, 0xabc6331e, - 0x409a9da1, 0xf3dec1fc, 0x9198e9a9, 0x0bfe4c3e, 0xa49ef12d, 0xa3b7f00f, - 0x17fd1c5f, 0xdadddfc1, 0xbf6f86af, 0x984b86aa, 0x354f054e, 0x6669e1aa, - 0xe6c96c35, 0x361dfa7a, 0x490cfe75, 0x1ca7270d, 0x73f0d309, 0x7f01a6ed, - 0xbbf044b3, 0xa07e0199, 0x01769a0d, 0xafa525e7, 0xadb2fc96, 0x93dfdca9, - 0x73f6af5c, 0xb596b224, 0x6df90231, 0xfcb6f954, 0x73fa0255, 0x7cead56c, - 0x8c150798, 0xbff48acb, 0x9f95d724, 0x02e9718d, 0x4b3aee7e, 0xc5cde9eb, - 0x238b6875, 0xcf934a3e, 0x1fdd0d05, 0x95b8d0b7, 0x7c0f9076, 0xfa45e301, - 0xe62f840f, 0xc76726ba, 0x05f03e73, 0x7df997ee, 0xa503e43a, 0x41f8e1bf, - 0x3962c7e1, 0xab9ca26e, 0xa5b722b9, 0x97a9ab9c, 0x0475c7cf, 0x92b9c79d, - 0x81e7465c, 0x09aef4ae, 0xc877c50f, 0xce6cbe67, 0x946e9877, 0xdf20d7cf, - 0xef9cf4f9, 0xd5f0df30, 0xfd28672a, 0xafbcbcf0, 0xcc37b43c, 0xf8c071fc, - 0xab47b656, 0x82477760, 0xd3bcf039, 0x740ff843, 0x3a3337ba, 0x0f2b5a47, - 0xbf338be7, 0xe908d3db, 0x0b975a5b, 0xd66567d7, 0x338f3d59, 0xfe51ebf5, - 0xdff7979e, 0x38dd820d, 0xdb94c05a, 0xbb668da5, 0xccbdfd11, 0x57f2a19f, - 0xd5877e28, 0x31acd22b, 0x0188ff80, 0x4cd3823f, 0x33e34de7, 0x35118fc9, - 0x2b3771d5, 0xccf73c04, 0xa2046f98, 0x554e85dc, 0x658fc790, 0x97d0fd97, - 0x035e383c, 0xce02abfa, 0x0f441923, 0x3573b923, 0xe7014995, 0xff655bca, - 0x9b1f00c5, 0x7f609796, 0x7896cc3f, 0xd679863c, 0xda9fff72, 0x6ab8665f, - 0xd833b553, 0xdfaab27e, 0x722fd956, 0xfed5f6f3, 0xf4d5c337, 0x0ecfda61, - 0xb21cdf6a, 0xd576c1fd, 0x11afbc7e, 0x3e436f1f, 0xb5ffce18, 0x1ba7965f, - 0xf45e9e6c, 0xd818e97f, 0x06071495, 0x6a8898fa, 0xc369ff23, 0x5d5379f9, - 0xa60fdab2, 0x1f927e63, 0x90d647cf, 0x3e6048fc, 0x9859df8a, 0x47d7f287, - 0xbbf1e74d, 0x1371b960, 0x8798c179, 0xfd00dea1, 0x3f57f2a9, 0x46d3f7c2, - 0x3c42eec1, 0xfff3c783, 0x89abdd8a, 0xfa4bdf1c, 0x64b84a73, 0xdbde81b8, - 0xe32575ea, 0x3dc21bf7, 0xfeeb1835, 0x762ebb3c, 0x1b3de83d, 0x7c08c630, - 0x71bb3576, 0xfb84cfbe, 0xf58fa724, 0x27a21a71, 0x1d96ddcb, 0xb27a00da, - 0xa8695de8, 0xf2345af7, 0xa1fc2f39, 0x65bd6cbf, 0xfd10a6e7, 0x029bfa2b, - 0x8f002b5b, 0x956dba00, 0xfe81e6f5, 0xd0ee2496, 0x3163b406, 0x3fa90ab8, - 0xd2a35ce5, 0xeb37d35f, 0xf7ecab6f, 0xdeb3fa52, 0x559f1ea3, 0x59f1a1ef, - 0xe947fde5, 0x2f8e2b6f, 0xb4dd5f04, 0x1e8ed93f, 0x7aa96fe8, 0x8783567c, - 0x72d567c6, 0x7f40e1ff, 0xbfacdf4d, 0x931ef936, 0xe1d3e64d, 0x0e37fdce, - 0x1a76ab9c, 0x29b4ae51, 0x7f7940fe, 0xbfb414bb, 0x37f796ad, 0x714bfbe5, - 0xbddfe4e9, 0x18df33d4, 0xfdc35f6a, 0x247ac98c, 0x2648f593, 0xcf0891eb, - 0x3ea67a99, 0xf0b0e81e, 0x22f9b6c5, 0x1e73e3ec, 0x153e333a, 0xf62f19e0, - 0x5f6117cf, 0x99e2f39a, 0xc9f04903, 0xccbe2fcb, 0xe6787fcb, 0x9b94324a, - 0x2fcdef7c, 0x962a3803, 0xde0ac7ef, 0x8db7bf4a, 0xbba37ae2, 0xbfee73e1, - 0xfb8af904, 0x87aa6356, 0x42f17fa1, 0x32d47f72, 0xe94eefa8, 0x310f2cb7, - 0x6eea4a2f, 0x467e4f38, 0xff287914, 0x40bfe1e6, 0xee53cfb4, 0xefab9467, - 0x6d454467, 0x8c2ffd22, 0xef28cdf9, 0xba0e8c22, 0x28d6f84f, 0x642c1fbe, - 0x376e0af6, 0x39f25948, 0x31cfba0d, 0xd76e58bf, 0xb1cfcb7c, 0xb1c6a17c, - 0xdfd9ed1e, 0x478aaa4e, 0x173958f5, 0x7f783797, 0x1bf5d772, 0xbe0e1f9c, - 0x23e7393f, 0x23c2eb81, 0x3ba5bfb8, 0xb9f7e257, 0xa886fc02, 0x9f370ef7, - 0x7db8a3b5, 0x0e9f383f, 0x0e319f3e, 0xfee69f3e, 0xfeb0b5a8, 0xcb7ee8ee, - 0x5d9fc413, 0xc86be721, 0x5fcd06bc, 0xd8a628fd, 0xb7a45a79, 0x32b7cd9b, - 0xc1f9caaf, 0xa2ca4146, 0x794feafd, 0x3183fd2a, 0x8e2a14bb, 0xb819f483, - 0x4e6deabf, 0x5d19fe86, 0xcf073d9c, 0x45fe3795, 0xde5cf21b, 0xd63e796e, - 0xb9d38546, 0x3d28c6ce, 0x51dddbd9, 0x97fa1933, 0x9a74d345, 0x72a8b297, - 0x8da96f3a, 0x8f68ed65, 0xd7239f06, 0xce9bb88e, 0x68ad6901, 0x703a4041, - 0xa461d92e, 0xe8b989f8, 0xc5c8e786, 0x8f239d9b, 0x91cfc999, 0x7425e947, - 0xea45b459, 0x7f239e43, 0xf7df146c, 0x713c71bb, 0x278c3f88, 0xa21c706d, - 0x31d1c799, 0xf5f2023f, 0x7f231766, 0xc7de3cba, 0xea5075e4, 0x861ecc1b, - 0xb7ab40f2, 0x68a7a84b, 0x613ef9c3, 0x4e5869b0, 0xf7c8bf08, 0xfbe8e947, - 0x34cd724f, 0xd7231aaf, 0x5afce7cb, 0x7a4fe908, 0x4fe29475, 0xc3674d0a, - 0x0d3cc9d1, 0xf0a7473f, 0x9e9302e1, 0x302df7ce, 0x0fd14ad9, 0xef0800b2, - 0xfa8098b3, 0xf7e22db7, 0x0dbb4581, 0x5337e7e9, 0x6ff9ff6e, 0xb9f9ba18, - 0x43353e7c, 0x4ee3f747, 0x8f61cc09, 0xd57e7a19, 0x869e8ce9, 0x66bb9a6e, - 0xec87599d, 0xeff2e2f7, 0x867b6115, 0x167553e3, 0x779fec89, 0xa85ca146, - 0x0f1f5b4e, 0x42caa2f0, 0x94dfdd1d, 0x08ee44e3, 0xd19fc72e, 0xa28e4eba, - 0x51e7d178, 0x624748a5, 0xa3e22a7f, 0xea0289c4, 0x9e2a37bd, 0xd7e1cdea, - 0x18dea0c5, 0x7f67d394, 0x1eb462ef, 0x127a50b6, 0x302c4fda, 0x07cb236e, - 0xf302a3b4, 0x01627ed1, 0x2f2c27eb, 0x9085f6b6, 0x609a4a17, 0x0d5292db, - 0xd0909e7c, 0xff92a942, 0xee5b43ac, 0x57aeb10f, 0xc6fd75e5, 0x601b4c76, - 0x8ed0713b, 0x2ae5fb01, 0xd517dbce, 0x61e32ca7, 0x17657548, 0xe9b18ec9, - 0x88933e15, 0x1e6106bf, 0x45fb04af, 0xd5b0de75, 0xfba14beb, 0x6d38f2fe, - 0xa346d62b, 0x1c55031d, 0xbcdb9f48, 0x9965296d, 0xcec8e383, 0x8d13e991, - 0x17a889b6, 0x5c725ff3, 0x97f40ccb, 0x74349b24, 0x5326013e, 0x6e612f75, - 0x38b4f459, 0xccdd4534, 0x2ed0926e, 0x3f3d25ef, 0xf896bae1, 0x62f0e120, - 0xa4ab7186, 0xef0176b8, 0x23f40d03, 0x97ae6fdf, 0x5c57b9e3, 0x048e3465, - 0xcefec0eb, 0xf38d0ec8, 0x747945cd, 0x518e69e5, 0xe5d58fc2, 0xdcfc71c9, - 0xe1d5fdc2, 0x3ae8097e, 0x4057b6a9, 0x380c0138, 0x5c27c5f4, 0x426b4c6f, - 0x045af279, 0x6db58bf9, 0xf207cc99, 0x45745527, 0xfb3ce0e5, 0xc9a6ffa5, - 0xdf0b0790, 0x9c207cad, 0xa136b3f4, 0x25d90665, 0x285869f7, 0x1c98cf3f, - 0xc828c7ee, 0x609ffce1, 0x1ea94d6b, 0x44d3e987, 0xcf975f37, 0x1db39067, - 0x9f11d9f4, 0x1c58fa2d, 0x759a7bd4, 0x9b73e9a1, 0x7ec0efdc, 0x185fcf21, - 0x7f911973, 0x3b9382b5, 0xdbeef739, 0xce82cfb7, 0x55e74613, 0x8d7ac936, - 0x4e444ed2, 0xd846153b, 0x45cf0c1d, 0xdf07660a, 0x9b3ecc07, 0xf9abd60f, - 0x7b486d2b, 0x791cc1eb, 0xb26b491f, 0x4cb2fd61, 0x94fd0dbb, 0x1a55f7c1, - 0x70da26d3, 0x0c671a7d, 0x7031a9d0, 0xcb4ee85f, 0x53cf1f7e, 0x2c747a99, - 0x70591cf0, 0x2173c7aa, 0x972837b1, 0x1d3797cf, 0x9b42e7e2, 0x78bd454c, - 0x14c9a10e, 0xfec74457, 0xa99cfc4c, 0x3a64df52, 0x64def246, 0x1356f1e7, - 0xa2020fee, 0x3ba1e7c7, 0x83cd18ed, 0x0e5a6f52, 0x7b26ab97, 0x5bfbc317, - 0xd53f76e1, 0x3e9d130b, 0x161fe00d, 0x4ffee8c7, 0x55f39198, 0x318fac04, - 0x7e95ef80, 0xd1d1cb6f, 0x172535bc, 0x7e1096f5, 0x6704de22, 0x1b22b64d, - 0xdf38dbed, 0xb4636fd0, 0xaf9cdf42, 0x5be7971f, 0x3e51a769, 0x434f7aff, - 0x58b2fcce, 0xd73913f4, 0xa6bb60e4, 0x83b446e5, 0x6fe391b4, 0x6186ded8, - 0x285e6bdb, 0xf238f7b7, 0xc8b23685, 0x50e9ed8c, 0xc3a0845e, 0xfe76e467, - 0x30ede357, 0x97df74b3, 0x9f305a60, 0xa3de942d, 0xa38c46a4, 0xddfa1b8f, - 0xebbf9637, 0x90247ed4, 0xfc717bbf, 0x1ecf932b, 0xee1ca12b, 0xdb2eda3f, - 0x619d8a27, 0x2ededb91, 0x3ee87bf0, 0xef4edc21, 0x8776c836, 0x0f3d4c25, - 0xf941f783, 0xe0ae5c3a, 0xc72ee6e7, 0x046b8a31, 0x77e5f3f3, 0xb40e8a3e, - 0x73ef504f, 0x04bb7364, 0x1c4bb453, 0x610d9fb2, 0x9da01bf4, 0x80fdf0a2, - 0xfa42b75f, 0x3f005ba7, 0x0d6fc803, 0x7b242bb4, 0xc90dbe88, 0xe7c8697d, - 0x053bf2a9, 0x5cd7f643, 0x4785a72e, 0xfe434b3f, 0x4feb8b2e, 0xf982efc0, - 0xae4785fc, 0x5e78e026, 0xce703198, 0xab43e286, 0x7bf3a717, 0x1cffc7d9, - 0xfed10aed, 0x457feecd, 0x86b4dd9d, 0x5ce5c0f4, 0xdf5bfc0f, 0x8cbedb07, - 0x821d9deb, 0xcda4efda, 0x5fe77ae5, 0x7acc7de4, 0x2df7a455, 0x2eb965ce, - 0x0ab61f20, 0x7f28e5e6, 0xe7e11f53, 0x5e3f56e6, 0x2103d9ff, 0xed1841f8, - 0x804e73fa, 0xacdc5c3d, 0xa35a3f27, 0x8dc47d29, 0xafc31ce2, 0x71cb87b3, - 0x1e4b7d79, 0x24f3f235, 0x5b17ae2e, 0x39d3f75c, 0x23f3e095, 0x243bd5c3, - 0xbea53dcb, 0x7947db01, 0xfe479a62, 0x23684b80, 0x964dbfa0, 0x7678c17b, - 0xf3c864e2, 0x12b90463, 0x18456875, 0xed93abb6, 0x3f8aedb1, 0xe8c8a2a3, - 0xb75ef808, 0x1a58c8b8, 0x8c8d2f40, 0x6e0ddf9f, 0x01dcceff, 0xafa55a7d, - 0x459f70e8, 0xf89c50df, 0x433901a7, 0xcab8658a, 0x0ffa518e, 0x70163f3e, - 0xf38c2c5e, 0x5a67b729, 0xe818dcf1, 0x962b6bb7, 0x6df9c48f, 0x582f5d15, - 0x3ffa1e61, 0xe739d030, 0xecbe650f, 0xb872f993, 0x43b1f3f5, 0xf6318ca0, - 0x97823b04, 0xc64e80d6, 0x68fe408f, 0xfb94d4cc, 0x5cb38c43, 0xfd08671e, - 0xafdcd6fa, 0xe6975fa7, 0x51afd086, 0xc504767f, 0xd461021f, 0xf4211d9b, - 0xec8213eb, 0xedcf900f, 0x1d49d09c, 0x270f307d, 0x6f611d6e, 0x919ee894, - 0xf6045ec3, 0x32678bc3, 0x239f6f51, 0x23c7bc0c, 0x608c31db, 0x221623b0, - 0x6799735e, 0xc50203df, 0x48ee5a51, 0x5c04eea3, 0xa7ad9b8f, 0x3711fb24, - 0xdc613ac2, 0xb2daf5a1, 0x0ce2a119, 0x274038ff, 0xef02ba28, 0x042ac007, - 0xc48695c4, 0x63e282cb, 0x38194e18, 0x5a1dabff, 0x7562aeff, 0x35e36afc, - 0xac30bfee, 0x0427fe60, 0x2eaa1f3c, 0x0bae5f9f, 0xe2a9cf8e, 0xba9d0b5a, - 0x887c7c60, 0x6f8cb26f, 0x2907b6ca, 0x452d3e0e, 0x64acfde4, 0xc707cf64, - 0xbd850cbd, 0xc3ea2d0e, 0xf7f48c15, 0x9e363f60, 0x5eff2517, 0x09cf6305, - 0x7d5ade74, 0x59e9e4df, 0x1cfbf8e7, 0x8fd8e52d, 0x50c3532d, 0xafbe0e3f, - 0xf09bc4a0, 0x7de04c98, 0x22dde569, 0xe10d62cb, 0x53b77cc7, 0x8797e2b9, - 0x4b12a6fa, 0x55eeb9c0, 0xdd3ea06c, 0x1e85f2a3, 0x59d6d6f7, 0x1c4fef14, - 0x82ec29ef, 0xa33b24a2, 0x66aa4879, 0x3cc00764, 0x86fae2a8, 0xce345d94, - 0xc58c354b, 0xaaa038f2, 0x7076013c, 0xbf184fa4, 0xe30fce2a, 0x76c1c154, - 0x4deccde7, 0x0de64a43, 0xfccdf9e5, 0x5e39068d, 0x646e46f8, 0x633be91c, - 0x77d418d8, 0xa69f8b2c, 0xeb04b8f5, 0x34597e81, 0x03c54284, 0x68fb4337, - 0x5f90ba07, 0xc4dfd1e2, 0x30caef54, 0xc9f74887, 0xb38e6284, 0xf1e4eb10, - 0xfc467ce1, 0x9507086d, 0x9859f80b, 0xbce0706c, 0xc3000c1b, 0x333d0590, - 0x56be4026, 0x15af37f6, 0x33308898, 0x4fdc8ddb, 0xe36bbca8, 0x866d77a7, - 0xff7407eb, 0xcfec30be, 0xfa53bfc7, 0xdb8ef219, 0xfb27be0d, 0x7dfc1ccd, - 0x951df919, 0xff9b87fe, 0xfb6ddee1, 0x2777d4c3, 0x3267bf70, 0x20e56bd1, - 0x4cbc12bd, 0x1efc47a6, 0x4abdc2e5, 0x0c77adb1, 0xfb3c37de, 0xfd1d8470, - 0xf0e303e0, 0xefe5a9dd, 0xed75fdd1, 0x9361e00d, 0x8c0fbe48, 0xafef6e4b, - 0x02fd171d, 0xbc06dae4, 0x4fe78434, 0x279d192a, 0xcf4ab8b0, 0x000e7489, - 0x1392a0c6, 0x4013ef01, 0xf10e1b7b, 0xf15baf73, 0xb0710b9d, 0xd02bd45f, - 0x4255b06e, 0x483b087e, 0xbf19ab49, 0xd5e0ac1f, 0x1a3d07a8, 0xf5c352e9, - 0x3ea6d9e8, 0xe935cf11, 0xe445fae2, 0x2e68e71f, 0x37e807c7, 0x0bf9d19e, - 0xce7c926d, 0xdfc4a471, 0xfbe4cb4d, 0x84cfd29b, 0xfe591ad1, 0x47fbd2f7, - 0xd54e23b3, 0xf2c6764b, 0x442fc5f6, 0x11ecfcff, 0x00d3eaa7, 0xe167d82e, - 0x2ba9d270, 0xecc66669, 0xd10bacfb, 0xef3b3f9f, 0x807495d4, 0x78d9f68b, - 0x464614f9, 0x097df8ce, 0x319fd10b, 0xd559b461, 0xd7385bfe, 0xd53cdff1, - 0xcf21341a, 0x5a36df63, 0xe8c94f39, 0xf3b3ad3e, 0x2e31a797, 0x47f654e9, - 0xdf482e87, 0xde0b2281, 0x717f9323, 0x9d0f1451, 0x9dd9d329, 0x1452eef8, - 0x68bb2dfa, 0xfa0d477e, 0x6bfe9fe9, 0x4382f4fc, 0xccca9779, 0x1bff812a, - 0x2c2b981b, 0x99ee8023, 0x9f9d7343, 0x81b8a603, 0xffd28f82, 0x6960bc10, - 0xbc4098c5, 0x0a3b51b6, 0x0d0a175e, 0xc70587a4, 0xfd082e87, 0x549cf1db, - 0x2fd6cfc4, 0x10ba75c2, 0x002a9fd9, 0x9eb79e1c, 0x7c42edd6, 0x1ec176ff, - 0x3af8eb00, 0xa22bef56, 0xd6a3fc75, 0x027a3d51, 0xdfc5dbbe, 0xe396686f, - 0xbbc64f50, 0x019f687c, 0x32b9d1dd, 0xfc9e8a5f, 0x05e36548, 0xb03fa047, - 0xcbf7346e, 0x69d3925c, 0x49cf1686, 0x01f74ba0, 0xfa85ad81, 0xf5976bee, - 0xeecc9fa8, 0x3d47a33c, 0x19c0eeba, 0xad4bde3d, 0xa9da1843, 0x8477a6db, - 0x32feffd2, 0x97f2ab5a, 0xd1d77629, 0xe8f5ec94, 0x16abab77, 0xeade1ee8, - 0x6e1fb9d7, 0x251c32f5, 0xb2df7763, 0x55b8fc9f, 0x98f5eece, 0x477d652e, - 0xc588ddf1, 0xdceaad2e, 0x089a92c0, 0xcabe3c55, 0x9782ab13, 0xc0eac0b6, - 0x21b4bb3e, 0xc31df549, 0xef82cf5d, 0xd0fe0e28, 0xd790affe, 0x736db171, - 0x16bbfa2f, 0xcc7ad4bb, 0x62b5ceec, 0x11ede20c, 0xfece1aec, 0x84b77e12, - 0x00d2108f, 0x7de60abd, 0xa3d7075a, 0x648c2aea, 0x0c22549f, 0xab595af3, - 0x7393e3f5, 0x54f45347, 0xa810eeee, 0xbb972ddc, 0x576e046b, 0xa975f2cb, - 0x8392e38c, 0x75d1a727, 0x37a39f52, 0xa5df0033, 0x88e7e515, 0x437d651e, - 0xc4855719, 0x290d8df5, 0xddb0e9ef, 0x5817dfa5, 0x4b8d1a6c, 0xa92d47a5, - 0x1e55c351, 0xd59e905d, 0xbdf943a7, 0xff9d41b4, 0xbef2d1f3, 0x90f2c79e, - 0x2d18de9f, 0x07189f88, 0xbca53fe1, 0x81ef0277, 0x0f3ad25d, 0xead67d22, - 0xdf700abb, 0x1175a4bb, 0x7e4394ac, 0xb8afdf1d, 0xce01a2be, 0x751befc3, - 0xa7de330e, 0x8814adf5, 0x00b0976e, 0xb06d27bd, 0xa1dac13e, 0x7722bf70, - 0xe4f59cc3, 0x98283d0f, 0x13286f51, 0x83de221d, 0x8fc61c6f, 0x83e6517e, - 0x1f2fac13, 0x2246caf1, 0x9eca7585, 0x99f6823f, 0xf996b7ec, 0x3d948e30, - 0xc4bf204e, 0x4371809d, 0xc922a611, 0x37b03991, 0xad9a4184, 0xf920af6d, - 0xe66f563e, 0x58da62ef, 0xfc70bca0, 0xbe701333, 0x0bb27510, 0xfde87b93, - 0x9b6d39bd, 0xcc5ca22f, 0x3d1470cc, 0x193df805, 0xf27ffbc6, 0x16bfc175, - 0x3fcba9da, 0x0ad3f246, 0xd6fd81e4, 0xda3964d9, 0x5acff6a1, 0xc121ae51, - 0x7ea7cacc, 0x32f89413, 0xc3ed15d0, 0x9fa4a55d, 0x9f7ee558, 0xddb8942d, - 0x2e7ca0fc, 0xe2d6f98d, 0xd1befaf9, 0xf495f28c, 0xcaabfb1b, 0x5e283104, - 0xe61a3750, 0x4fada579, 0x5be9de75, 0xe901bf6c, 0x187db82c, 0x395e2abe, - 0x8a2d7b4d, 0xcc1d77ee, 0xfee8deb0, 0x3ea8d694, 0x8733a4b7, 0x53bbdd07, - 0xf6d99fcb, 0x777ba0a4, 0xeef74119, 0xddee82f2, 0x2df9efa9, 0xba094e74, - 0xe7bea777, 0x54cdb067, 0xe6930fd5, 0x9c88e0a9, 0x23f555bb, 0xe7d5cbed, - 0xbcff8eae, 0x77c74842, 0x2e7d7d06, 0xe0668798, 0xc198e28d, 0x0a2f247d, - 0x3e1a432a, 0x6984cc2e, 0x0ba1a173, 0x9139a4e9, 0xe386e7db, 0xa0badb0f, - 0x9788e31d, 0xfc6fe88c, 0x452fe089, 0x9f28c4fb, 0x18fd1953, 0xaf33ed53, - 0x52be7015, 0x5cf2dbd2, 0x7d61f3b3, 0x494af7f2, 0xdee01dfc, 0x463eb8d1, - 0xf9036c7c, 0xaf7e55e6, 0x476cac78, 0x5f3ced28, 0x0f353258, 0xcc7fcfbe, - 0xece28331, 0xf07efc1d, 0xa78f3d4e, 0xe7e55ef8, 0xfa3bf35b, 0xfe008e34, - 0xf5c7993e, 0xa59c6790, 0xeba91f14, 0xf9165d84, 0x1eaceda9, 0x75d465ef, - 0x7ee14776, 0xab3ce056, 0x60c9bf47, 0x89cfbcbe, 0xaf68e1fd, 0x743dacff, - 0x9e6d6d3c, 0x98e3f89e, 0x1eabd72c, 0x91bb72d6, 0xb9e16639, 0x575e4571, - 0xabe3e7ed, 0xe7e7a85a, 0x1d1a3160, 0x9c836e42, 0xc396ab3e, 0x707ef50e, - 0xca3d7f8b, 0xaadf900e, 0x4c174b7a, 0x12b7bb27, 0x31f236e4, 0x797573c8, - 0x17c91372, 0x7caae790, 0x3c80de77, 0xdf0ebfcf, 0x426a769d, 0x8170f38e, - 0xda78f348, 0xffe69535, 0xf4479819, 0x64333da7, 0xde7cf8de, 0xc65ebe6c, - 0xb7580fb5, 0x2ebf7ae0, 0xf2f6ebe0, 0x7dfaf230, 0x0a775d79, 0x4c2845bd, - 0xa270cedd, 0x634625db, 0x387b9e09, 0x1365f296, 0x7eaae1c6, 0xfd3dd02e, - 0x6e3eeb7f, 0xbf5ffd41, 0xfd05a8ff, 0xa3f6ee61, 0x594db016, 0x8b5a4ead, - 0x85d03c7a, 0xba9ef51d, 0x7fc22e8e, 0x6eb8fb65, 0x21d95fcc, 0xee3dfbd0, - 0xd3a71703, 0x135f5938, 0x0e770bc6, 0xf28fd783, 0x37befeb8, 0x307ee24f, - 0xfb89f417, 0xdf8301fd, 0x801d202f, 0x5ebc425c, 0x35e5f017, 0xb1a373b6, - 0xf51e9422, 0x1f7cf26f, 0xe867a8d9, 0xef85afaf, 0x52c71c71, 0x488de98e, - 0xb205fb47, 0x27edddb5, 0xfb604617, 0xfa863af5, 0x17df8285, 0xe21fbd29, - 0xd6a83ff8, 0x3580a7a1, 0xbe696b56, 0x52d7a83f, 0x74fbda3b, 0xc15e2f04, - 0xae1c55cf, 0x0929a8fe, 0x56a0fdda, 0x530c7ba0, 0x31f3fbef, 0xe0af1784, - 0x3d305afa, 0x4c1af42b, 0x3bf4c19f, 0xbe6b4e84, 0xc91e9d19, 0xe4d5ef93, - 0xe7dc02b1, 0x59a7dd61, 0xe11e7e91, 0xae2be3f7, 0x7fa1d61d, 0x6cc9bd33, - 0x31e0027f, 0x0b7aff5a, 0xbcc389ca, 0x8776b0bc, 0x748de5c0, 0x5261f237, - 0xbda19eb3, 0x971e7efb, 0x7ae3ef4b, 0xfad0e3c5, 0x31af8c05, 0xe51d37b1, - 0x4f1c9a52, 0x2ac7457a, 0x905c53f6, 0xaf319bcb, 0x96ef54d9, 0xbd71e537, - 0x40839143, 0xe4fdaee6, 0xc44f6d97, 0xcb2f147b, 0xe55341e7, 0xfa32b2f6, - 0xf485cfa7, 0x672f4caa, 0xf8143c64, 0x6cff4cb2, 0x1f68cfdb, 0x59c72d9f, - 0xd1743666, 0x833ccc79, 0x879453eb, 0xabdf52b3, 0x39ae7dc5, 0x3a7cedfd, - 0x25378d67, 0xc9fbe226, 0xd27877fc, 0x60d6dba7, 0x9c372fdc, 0xe0ec31d6, - 0x381e7453, 0x35bc6b2c, 0x49439c54, 0x7a2557dd, 0x6aeeb08f, 0x3c0aa53a, - 0x7d39d0f7, 0x1701d91f, 0x5c9f13a7, 0x2ddea9b5, 0x7bc654fc, 0x5d3ef28c, - 0x80f3f727, 0x8b8b169c, 0xf329eb06, 0x1c659e80, 0x2ed6586f, 0xab35af5a, - 0x75a92158, 0xcefe29ec, 0x0149ed66, 0xa458bddf, 0x304ce873, 0x608defdf, - 0xfc8b1f25, 0x3657241d, 0x748c4dc6, 0xd784fb2f, 0xd7af704c, 0xaf29f046, - 0x61ade944, 0x687c88ce, 0x4f11e167, 0xe1dbce16, 0xde275694, 0x8ef0bc57, - 0x336ba64e, 0xd32e2fbf, 0x2d4ee5da, 0xeb9c6233, 0xc2e3e800, 0x5cf7fe20, - 0xddfba44d, 0xa0fec3bf, 0xbf0d959f, 0xaf677921, 0xed1d38b9, 0x33dac2a2, - 0x1bbb084d, 0xf51d3cfe, 0xff610f89, 0xf41ebd20, 0x72809b7b, 0xd3bd24e4, - 0x8635795d, 0xd35979da, 0xcbf91d3f, 0xf740a6f7, 0xb8ec3e6f, 0xfdf2b7a8, - 0x7873dc89, 0xf2fd1c2f, 0xb9a3f2b3, 0xd42ce91c, 0x243afad0, 0xddeb3bd5, - 0x0a2bffa3, 0x20d8c3d7, 0x7e0a7afd, 0xc865a3df, 0xfb4a9bbf, 0xe421cca3, - 0xdff469ef, 0xb071f365, 0x15e5a1ec, 0x9e165f7a, 0xe990ac93, 0x3cbcb838, - 0xa13fc07f, 0xebefca73, 0xa1fe0108, 0x3fdfc62a, 0x2ba7bb05, 0xaab8f81c, - 0x67f92a73, 0x0dc23caa, 0xd1c333fd, 0xeb4dd7e1, 0x28cff718, 0x818dda30, - 0x1bb44d7e, 0x1f7faa99, 0x252b077f, 0x74f786f3, 0x14897ddc, 0x666bafcf, - 0x795aef14, 0xe7a53475, 0x2120df5f, 0xfbc318ff, 0x6b7ee95b, 0x8cec86b6, - 0xfeb53e95, 0xcb80a533, 0x7c052985, 0x60f95cde, 0x01b0e52f, 0xa2ec097b, - 0x5db9f37b, 0xa9887514, 0x7ce0a5ec, 0xf28c97b2, 0x13101d3d, 0xe04257ae, - 0x6941477d, 0xca977e0d, 0xd9ce885a, 0x72fefc3b, 0xe4d738f0, 0xf8553e73, - 0x35f2317a, 0xe7076fd2, 0xe776e0eb, 0x41ac9415, 0x4c38da3e, 0xe65cab7c, - 0x8c6d95fb, 0x16ddcbe6, 0x05f4f343, 0x0296736b, 0x78017e5d, 0x0bd23de0, - 0x3444674e, 0xe5c17f7c, 0x3df3c08c, 0x6ba81c8a, 0x36efa70b, 0xc58bce66, - 0x48cda373, 0xf9ded0f7, 0x9c46a98e, 0x38da7be7, 0x7dfd29ff, 0x1638b5d8, - 0xae8269f9, 0xf2876f5f, 0x5133cee4, 0x784df7a8, 0xf22c7e7d, 0xfe7870e1, - 0xcf1918fd, 0x1e12c486, 0x70bd8797, 0x004f6ca2, 0xba27ee7e, 0x87fa9de8, - 0x6fd1181a, 0x56ffabf7, 0xbe7c7c87, 0xfb8cc233, 0x230717e6, 0x0bcabde8, - 0x3de81a6f, 0x7df95a9a, 0x7d742fd5, 0x7cbf4873, 0x22f74b5d, 0x47fe6fdd, - 0xfba3f22b, 0x3b9d0355, 0xc373a87c, 0x6af7dc45, 0xc39c673b, 0x5f6b5677, - 0xc3f2dbfa, 0xd25486ca, 0x3ff8148b, 0xbe2746bc, 0xe45e7bf3, 0x8ea1e272, - 0xf77d217f, 0x0b976ba1, 0x17ca7cf0, 0x44c7ff07, 0xb7ee6b94, 0x79444f2e, - 0xe5c5fee6, 0x7eee5889, 0x4a13c22d, 0xc05eb95f, 0x7eca3efd, 0xa8aef699, - 0x90ad0ff2, 0x5d6d23e9, 0x3d07bd0b, 0x7b02e4e1, 0x130fbbe0, 0xac4e34b2, - 0x65b7e13f, 0x7c05f7b1, 0xa457aeb7, 0x93f8e338, 0x01d51165, 0x814f7974, - 0x7e2ff14e, 0x930ebf23, 0xf019c7df, 0x77f2f4e3, 0x8af6367f, 0x1aa37dfc, - 0x83a1ee81, 0x5ee432fe, 0x8affad1a, 0x88df7a58, 0xc73bce89, 0x8b38478c, - 0x3e6205de, 0x00ccd1e3, 0xaf71693d, 0x7400cba6, 0xe869d154, 0x57befd22, - 0xacb0433c, 0xf173dd3f, 0x2134c8d3, 0xe7267f84, 0xe39434d4, 0xf81a7ec1, - 0x8ade2245, 0x71e955be, 0xc1fe20a5, 0x15a59bfe, 0x287f9077, 0xd6937fd8, - 0x8f666a2b, 0xe9dff7c7, 0xf78c2f3a, 0x8bf22369, 0xfae287a2, 0xffc1081d, - 0x3970c66b, 0xbad5f0a6, 0x5dff1e5e, 0xcc6a5bd7, 0xe656b484, 0x9db003ab, - 0x75fda0fa, 0xa377f39d, 0xb5dd611f, 0x60631145, 0x3bbdd6be, 0xfc813d8f, - 0x66352e6f, 0xeed777e1, 0x1fcc2e30, 0xfee097a4, 0xf2e18ca6, 0x184f4072, - 0x97cbdf66, 0xed5bfaf1, 0xe463397f, 0x87ff6cf3, 0x87607fef, 0xedc31d8f, - 0x4fdc25f0, 0xe0f0edc2, 0xc791437d, 0x792ebb4a, 0x63ca879d, 0xc04877fe, - 0xec79265e, 0xbd51231a, 0xb1b9cee4, 0xbbbf4764, 0x0d325620, 0xb4433f6d, - 0x87f2626b, 0x71e8afb6, 0xa8e39f6e, 0x871ced11, 0x1749fb96, 0x99bef408, - 0x9db9f7a2, 0xeee3e902, 0xeb1f9d4a, 0x2ef57829, 0x85d57ee0, 0x4c3f9d0e, - 0x150fd418, 0xdca071fd, 0xa2b9502e, 0x637a2a4f, 0x71fb93af, 0xe5e78c17, - 0x16b986b7, 0xd87d7ce1, 0x13f94615, 0xc67cf126, 0x0093479c, 0x813df45e, - 0xfacbff11, 0xc1a742a4, 0xcea5e6fa, 0xd7be1b8c, 0x4fa64db3, 0x8352cf85, - 0xbfd943f8, 0xdd39f39a, 0x1dfee1d7, 0x7ff7fb8b, 0xe0f2f4aa, 0x7eff6176, - 0x466ff108, 0x1fbe121d, 0x19d15bff, 0x4aff3eca, 0x5efe0bd6, 0x23debf59, - 0x72af8825, 0x7db8764e, 0x6fd64eb5, 0xce6f2b86, 0xbcfc7aff, 0xdfdf1e47, - 0x8e779f8a, 0x9f43bff9, 0xf50bd01d, 0x4779c7a1, 0xc64fc941, 0x6b86bcc0, - 0x739e743d, 0x1ecdf7b8, 0xb055f595, 0x7c745573, 0x41af4534, 0xc35dc8bb, - 0xd1cd03fd, 0x7ec9afd2, 0xf7a5ae39, 0xef921e57, 0xd5783e73, 0xea2d694c, - 0xd92e90c9, 0xd9de927b, 0xc6a3525d, 0xb77d19bf, 0x34aafdf8, 0xb157eb8a, - 0x552bf232, 0xf19b4675, 0x7c737fbc, 0x2be431fb, 0xb4ad6edf, 0xc6feb03b, - 0x237d72d1, 0x44d5b7f7, 0x618fdfd3, 0x95407a41, 0x57df5827, 0x645305eb, - 0xfa70d13f, 0xc3ba2fc1, 0xd1e95cb8, 0x39d79f12, 0xd055dff9, 0xe0b97277, - 0xbf23086e, 0x886bda09, 0x820d67d7, 0x5f3ddf1f, 0x4cfbd729, 0x13ff25ec, - 0xcaa0d3c5, 0x2ca7ceb9, 0xd4dfb20e, 0xbb95a3f1, 0x33724b7e, 0x73148e38, - 0x0d0b8e40, 0xd2268dc4, 0x60959079, 0xbc9fe24f, 0x5dd24b72, 0x1f80ff38, - 0x71dc93f3, 0x9730fca8, 0xfb223e7a, 0x3cebc973, 0x7e2433fe, 0xc7933cd4, - 0x95ddf08f, 0xa5c87e10, 0xc51d8f23, 0xb374a3bf, 0xc75d51b8, 0x3247ba49, - 0xd208ff44, 0x518dae3b, 0x8a4719fb, 0xb23b8fdc, 0x7fa33053, 0x8f3ca46a, - 0x9c31b77f, 0x7fe9eaf4, 0x79458ea8, 0xf9d3aca0, 0xcf5e7cb9, 0x04a5707f, - 0x07f89bbf, 0xe3061cd1, 0xf507c5fa, 0xb0e249bf, 0xbbf09464, 0x63b408fa, - 0x7561ffce, 0x2febce04, 0x2fbfc520, 0x3169daf1, 0x2bd23fa4, 0x0fd82dcb, - 0xbfc80ba3, 0x45a5fb2c, 0x07230fd8, 0xdfc139fd, 0x6bbf976d, 0xfc853306, - 0xf8f3af98, 0x6b82737e, 0xa6cfc126, 0xa61efe33, 0xffcefc83, 0xfe8d7402, - 0x2c183ca2, 0x1a7f9fc6, 0xbc61d6ce, 0xf5de39a8, 0xb3d1f136, 0x08f9091a, - 0x9338a7be, 0xfb44bf6f, 0xc6194e23, 0xfcf40a73, 0x0cea465d, 0xbcb46bd6, - 0xc760098e, 0xb0093c62, 0xe6f18059, 0x53ae393c, 0x6c44ce10, 0x6b9d49ff, - 0xf997be13, 0x5f68b764, 0x8f604c4b, 0x83bf77c5, 0x83824be3, 0x3895c5c7, - 0x1f1f1293, 0x6024ce2e, 0xee9c053f, 0x8715b9f8, 0x25737180, 0xe7bec49e, - 0x635720a4, 0xf7ce87b1, 0x48c8533f, 0x718b7fae, 0x21f9259e, 0xc83548e2, - 0xd5cf2463, 0x394dc571, 0xfe9d10af, 0x3dc4f1b5, 0x1cb7d863, 0x13f3e2ff, - 0xe8f8f78c, 0xb7b2164b, 0x51effabe, 0x5e76cfb4, 0x42f0fda6, 0x8fbe41bf, - 0xecfdc7d0, 0x2ff23a9d, 0x2dbb005c, 0x3d9f603e, 0x3ddbcf9a, 0xe89539d4, - 0x596f40ff, 0x2f3fd604, 0x777c6fe7, 0x48d9fcc1, 0xbd22bd97, 0xe3e78b07, - 0xd03b0ed0, 0xbd404e2b, 0x975c5be5, 0xb1098fef, 0xd0f0c62e, 0xcbe44cef, - 0xc05f947c, 0x07ea63e9, 0xd772fedc, 0x598a38f3, 0x72ee0b96, 0x63c1c93d, - 0xf1411629, 0xc5435b9f, 0xa7ef5e59, 0x856aa37d, 0xbe1cf740, 0xa3a59c71, - 0x82b7de5b, 0xd3e5d3fc, 0xe70e6e49, 0x9b880eb7, 0x15b7caab, 0x23879c0c, - 0x815475ff, 0xe31dc699, 0xb3c12c29, 0xbff8ca87, 0x73b875c5, 0xfb3a086c, - 0x695fdb16, 0x9fdb6eff, 0xb6ddf792, 0x6e3be6bf, 0x77de6d7f, 0xf1dee71b, - 0xf57fe31d, 0xccff6e3b, 0xaf3f3c77, 0x73ffffe5, 0x70700300, 0x5cf83f9c, - 0xdfbc7040, 0x1f3efc70, 0x36106d96, 0x6a4177f7, 0x42b57a8c, 0x462d5100, - 0x0877a2ef, 0x71e24d66, 0x46658db0, 0xf0610eff, 0x5f32807c, 0x1db90b4b, - 0xe8bfce61, 0x4e79858b, 0xc596f475, 0x126c9fa2, 0x82fd877f, 0x132acefc, - 0x18cef4cd, 0xfbc04cd4, 0xa161cdf1, 0x7261aae3, 0x23edc37b, 0xdc9617cf, - 0xfe9e3631, 0xfbc8436c, 0xfec82f1d, 0x23077347, 0xa51324bf, 0xafd47984, - 0xd0fa8094, 0x3f3c2388, 0x76398baa, 0xda525e10, 0xa507b23c, 0x8b6fc434, - 0x998def1c, 0xfe869d99, 0x0bd018e8, 0x14f81e31, 0x8e2905c6, 0x4a7aa665, - 0xe58c1f7f, 0x31d16dfd, 0xe55bee81, 0xac4cf3f2, 0x9e2aa0f9, 0xebae8ef7, - 0xc50265e3, 0xfe2396f3, 0xe574d2bf, 0x89934cef, 0xff37e618, 0x8ce29980, - 0x48bd2627, 0x8956777f, 0xf331adef, 0x6ed1872a, 0x1cd63c06, 0xbbf4471c, - 0xf7a4d0e4, 0x7733e9f1, 0x750f68a6, 0x17f1514f, 0x1dfd969c, 0x8940bf8a, - 0xf65efd6b, 0xfe887c93, 0x221fba17, 0xab1dea51, 0x27f7b6f9, 0xfc10d8ef, - 0xfee045bf, 0xb8afdf21, 0xde9c687f, 0x6e78119e, 0xaf3cb372, 0xdc78bacb, - 0xecf7f142, 0xee33c793, 0x01976d11, 0x4d71d2f6, 0xcfb8f463, 0x094a6b8f, - 0xe1c0b4c7, 0xf07de0d7, 0x35fbd5c5, 0xa285faca, 0xb2b1d6a3, 0x9fa7a31f, - 0x12ff7ae2, 0x60ffe714, 0x30bf3f2c, 0xf1e390af, 0x0824d801, 0x1b12c9af, - 0x711c7d51, 0x2a1b598b, 0x7605549e, 0xacb9e231, 0xccade399, 0x34975577, - 0x7339fb15, 0xd309bfb4, 0xa9b49aa2, 0xbdaf6fe4, 0x9bfa84d8, 0x63e5dafb, - 0x4cbf93b7, 0x713da12f, 0xefda9f4f, 0xa5a30ab6, 0xfd2784f1, 0x0cdf5a9d, - 0x71e3ec91, 0x9fa24433, 0xb230aa98, 0x4c74635f, 0x2e78426b, 0xca8a8bd7, - 0xcc22a6e3, 0x3e934416, 0x4523d458, 0xe83f97df, 0x51998b07, 0x74f38f1f, - 0xe2aaf8b3, 0xcc35bb4f, 0xe7ae1af1, 0x5d5f1b5f, 0x74bbcef9, 0x971954ae, - 0x9c4a2f32, 0xaaf8b874, 0x5dc1ce72, 0x2e75457e, 0x4ff62dc3, 0xb8e3ff47, - 0xf2f46783, 0xfe334b39, 0xfe25611d, 0x8bf5ee3a, 0xe2557714, 0x45cf6eac, - 0x3be1abd2, 0x0e3f7e3d, 0x06213f96, 0xf1e217df, 0x9ef157d7, 0xffef1e94, - 0xd4bee999, 0xc5fdf21b, 0xe63f184e, 0xa1cde9bf, 0xa76bcbb4, 0x98b790f4, - 0x45e77752, 0x387ed78a, 0x53ef1d56, 0xb49779e2, 0xd56333ce, 0x0e0923e7, - 0xc369f78e, 0xddc6bfb9, 0x97bfa3a3, 0x48c77ee1, 0x73a4bbf2, 0xfaebdd19, - 0x246ba4f2, 0xf1875de2, 0x38ba00b6, 0xe187b0ef, 0x9de7613b, 0xb38c30f6, - 0xa73eeb8d, 0x752ff3c7, 0xfd1eaf62, 0x12718061, 0x1f744d1e, 0xf7cfc8b8, - 0xdfd09676, 0x5c69bae3, 0x136fe3ac, 0xe59ffb17, 0x00210141, 0x00002101, - 0x00088b1f, 0x00000000, 0x17b5ff00, 0x67534c5d, 0xb7b77cf4, 0x0bdf96e5, - 0x72223f2a, 0xa29862c1, 0xa740c2dc, 0xac741631, 0x4a8a5c13, 0x66b50102, - 0x2d09922e, 0xcbc2ccd9, 0x01893ad2, 0xb8b2c3dd, 0x26a9f364, 0x87b6e883, - 0x6ead93fa, 0x840b0b55, 0xc3e22e25, 0x52c9719c, 0xba33330d, 0xd8dc6281, - 0xdf39d85c, 0xd8bdb5bd, 0xa4da2cbd, 0xdf3f3d39, 0xfff9df39, 0x0730000a, - 0xb956e7da, 0xf84ce706, 0xffc6cfa5, 0x4fa43d0f, 0xbddde38c, 0x1726eb4b, - 0x3ebbf1c4, 0x036935c9, 0xce9c5df8, 0xf6002b94, 0x1c5ace87, 0xaccf1f04, - 0xedfc2176, 0x4ab5dfc2, 0xd2f7803a, 0xee202d4c, 0x96a666fd, 0xd2afdef8, - 0x4fe9027a, 0x8ed77bdb, 0x70045e97, 0x106b4196, 0xc12e55f9, 0xb8e08271, - 0x4546fac3, 0x25c06e5c, 0x80fce938, 0xe89b34ad, 0xd9a55cc7, 0xf5f4137b, - 0x00674539, 0xdaaf39e9, 0x09f489ac, 0x06a019bb, 0xc15c0ce9, 0x556bf624, - 0x7fdfdb81, 0x4a4f2ad2, 0xdbf11c7a, 0xe036cc1d, 0x3c8150de, 0xf7c71e59, - 0xfc028fd3, 0xd422666e, 0xb9e97402, 0xd77264b8, 0x3bafa8aa, 0x52816a3f, - 0x5c5b4ca2, 0xdf5e30ab, 0x12acfd4b, 0xbefcf860, 0x170568e2, 0xa0172095, - 0xe0373f4d, 0xb19c5bdc, 0x3d7fc010, 0x4698ca05, 0x4adf9113, 0x2a8e143f, - 0xa769da22, 0xb6e5785f, 0x4c27f7fc, 0xcdba11ab, 0xbdc268fe, 0xc3829dda, - 0x2eedc99a, 0x7920ce6d, 0x212fce31, 0xb74bd3a5, 0x51cc22ad, 0xf413e428, - 0x025ac217, 0x36ada8d2, 0x0406ef6e, 0x7ca1b07e, 0xa488539b, 0x70d69da0, - 0x6f50044a, 0xdf045395, 0xcd7b088b, 0x7c461281, 0x2be726f1, 0xbf11366f, - 0x042aae4f, 0xcbe7e3f4, 0x09417916, 0x3464dfbf, 0xf3aa8e21, 0x3c52fed3, - 0x953176af, 0x34ef6adc, 0x4193f1f2, 0xe3d6ee7e, 0xfc3433b2, 0x5ff72172, - 0xcb9e0136, 0x8e38031d, 0x18f67776, 0x756eedcf, 0x3f7461de, 0x337fa0f8, - 0x904d81ca, 0x6bde8907, 0x3b3aa394, 0x001ff18d, 0x43d62670, 0x0d41d537, - 0xe7e1c641, 0x45d513e8, 0x582a0615, 0xbf373f11, 0xf974467e, 0xf062faf9, - 0x5117f10c, 0xd80d567d, 0x024dbf28, 0xf5e10194, 0x9f412d92, 0x9eb9155f, - 0xfc01650f, 0xde17d728, 0x7e30c83e, 0x915f8f7d, 0x4a6e505a, 0xd2ca97ae, - 0x32f7b8e3, 0x401653d6, 0x036cf0f5, 0x9858fbc5, 0x794d1581, 0x28bef1f3, - 0x6eb17d57, 0xbc4ead9c, 0x31dfe6a7, 0x3a44f9cc, 0x0d9a81d5, 0x61205f9a, - 0x5817fcbc, 0x55ed1060, 0x491c3d35, 0xb2b9f8a3, 0xec8532d5, 0x23a50ed8, - 0x6b126dee, 0x3c2ee118, 0x160ef840, 0xf6e7f090, 0x005b9d2b, 0xd8b754ed, - 0x5bdc52af, 0x15aacc3a, 0x40dade88, 0x50596bf4, 0xff122937, 0xc4a97bc4, - 0x55aa672f, 0x9eb3be21, 0x445f8df8, 0xade7aa44, 0x7865a514, 0x8d28cbb7, - 0xeac1b37d, 0x551f500e, 0xf411a337, 0x3587476f, 0x84b5fe40, 0xce90cd9b, - 0xbea041eb, 0xedcf5b7b, 0x328f45b7, 0x099f48a3, 0x5f916757, 0x16d3cc0b, - 0xea356115, 0x7841c82e, 0xb005bee1, 0xb4e2bc1f, 0x73b94645, 0x05ac4c3e, - 0xc49f4be0, 0x8327c861, 0xd7c03963, 0xc30e7cbe, 0x2fd3853e, 0x8c39cafa, - 0x470e54f8, 0xa8356b7c, 0x959e3cca, 0xdd02fbe1, 0x7059a727, 0x7e6f9b25, - 0xf9623ebd, 0x29ef0baa, 0xba3e7ba6, 0x93962eea, 0x5a20c7c8, 0x6ad6142c, - 0x6730c9fd, 0x06c3e75e, 0xe881e3b2, 0x60a73a61, 0x460d61be, 0xef308421, - 0xaa6febbf, 0xd96f9b52, 0xf193b802, 0x04faf467, 0x3cd02287, 0xfad24b7a, - 0x5fc5787f, 0x48529e3c, 0xf31eb2b9, 0x413719e6, 0xd48fd20a, 0xbe7f736b, - 0x4f18eb9e, 0xc0ddb8c0, 0xcf9c1278, 0xcbf8b56f, 0x74ad1f28, 0xa7e7248f, - 0x0ac4faf4, 0xb432bb30, 0x4fbc329c, 0x600e6c47, 0x8f30b220, 0x4916211d, - 0x19df3ec5, 0x244774de, 0x96e0c3d8, 0xd73c7e71, 0x46e6d87d, 0xb6f389a5, - 0xf9268d33, 0xd54a5c13, 0x34592ce2, 0xf6d56fd8, 0x8b5d935a, 0xb56e0c73, - 0x9471756b, 0xfbeb059a, 0x381679e8, 0xa9e7fd88, 0x734ebb18, 0xd001cf2c, - 0x93c7c38b, 0xd1311e9f, 0xef990f3c, 0xd8e3993d, 0x0c8a791f, 0x3794391d, - 0x41f6260c, 0x24077e81, 0x63946dc0, 0x6e611c91, 0x192dca25, 0x9f7d259f, - 0x2f6e15d8, 0x01905777, 0xfe0450ba, 0x465f3483, 0x1a77502d, 0x639d77ed, - 0x3bfa9070, 0xf70502e0, 0x1bf1e8fd, 0xdd214f87, 0xb4c98e73, 0x5783ba8e, - 0x16ef9ef9, 0x78ff7827, 0xbc2d77c2, 0x3537831e, 0x0239887a, 0x403af249, - 0x6eed1dfb, 0x6e687f46, 0x05301f74, 0xc36ed052, 0xbdafad39, 0x41404b0e, - 0x1de8ac7c, 0xe79df091, 0x1cd1e419, 0xa5162653, 0x1980ff11, 0xafdc2502, - 0xfd84baa6, 0xfc855f84, 0xd8cfed8e, 0xf4c0f1fe, 0x6bd52158, 0x0a235327, - 0x8cb73fdf, 0x922f05fb, 0xed2fdf1b, 0xcd3361a1, 0x0643dc1b, 0x868eddb9, - 0x713f343b, 0x4be918cf, 0xf9e7df0e, 0x53af2880, 0x7e062fdc, 0xe1633d8d, - 0x58092c6d, 0x38731509, 0xca5536cf, 0x6eaddf3c, 0x1f18dcc6, 0x91757049, - 0xc991709f, 0xc7e76f34, 0xf5aed1ab, 0x419fa341, 0xc877e62f, 0xd0c7d5a2, - 0xa3f0163a, 0x94a2237c, 0x7b8ba1f7, 0x1cfd0cfc, 0x40aa62aa, 0x8c2120f1, - 0x3e3d16c7, 0x6e1f802f, 0x70a9fc4b, 0xe01aae6c, 0x2b61ac35, 0x5ea353d6, - 0x6e01000f, 0xd4e3f9a7, 0x8e23bd08, 0x2af9839a, 0xf9f8977f, 0xe055677d, - 0xe814d4fc, 0x6bafd649, 0x6ab375ec, 0xf33dc90d, 0x7b2ed3f7, 0x47d3f792, - 0x3b2276f8, 0x244ced7b, 0x2bbe30bf, 0x15efbfa9, 0x411ccb5d, 0xb5c981f4, - 0x5975ce8f, 0xbea9ab22, 0x1cdc981f, 0xee91f18f, 0x8b82fda1, 0x91f516ef, - 0x87cf8c00, 0xcc67e523, 0xa2769794, 0x125beec7, 0xe9b8e397, 0x0aa1fc69, - 0xa1efdacf, 0xfda79aca, 0x17fa867e, 0x7f57cfab, 0x1dbcb26e, 0xa497f9a2, - 0xe7d27e7e, 0x9912c01f, 0x3893cbf7, 0x6487b683, 0xaa3c75e0, 0xa67ef5ef, - 0xc87b48fc, 0x06199dff, 0xed5cf895, 0x7ff4d0cf, 0xc18beba6, 0x9bf61d51, - 0xf6f9b935, 0xfc39f427, 0x8a71c98b, 0xa4f2bdee, 0xdf824a00, 0xa0a982ab, - 0x195df824, 0xf6e031ca, 0x7c8362c8, 0x81a978f5, 0xc2b1335f, 0xbd735fc0, - 0x14bf80ca, 0x5f90675d, 0x01bd6bff, 0xc5bd30df, 0xcff1bf20, 0xd63c066d, - 0xb95875bf, 0x4936e789, 0x0ae41baf, 0x157e8d3b, 0x2afd18f5, 0x15fa35ee, - 0x37e25bd3, 0xdfacb7fa, 0xf64e5fe8, 0xde855c83, 0x91fcffa1, 0x2060fb49, - 0x34f3c33c, 0x13029d35, 0xa8c44734, 0x66c21fb6, 0xf0a617be, 0x84a2e2ff, - 0xd7a72c3c, 0x0919da3f, 0xb9d2b32f, 0x2b369d0f, 0x512edbbd, 0xfe3e600d, - 0x2e76d705, 0x000ee017, 0x00000000 -}; - -static const u32 csem_int_table_data_e1[] = { - 0x00088b1f, 0x00000000, 0xe3e3ff00, 0x51f86066, 0xb8d3c10f, 0x72361818, - 0x0143f821, 0x684333b7, 0x0606163e, 0xc77e2001, 0x9ef0c0c8, 0x38330491, - 0x207eec10, 0x27880abb, 0x7dcf5071, 0xe52f1143, 0x5f5d9fa1, 0x153d76a0, - 0x837f7818, 0x031083b0, 0x03309b83, 0x8408b483, 0x55045fbf, 0xc10851de, - 0x99412e7e, 0xfa819f5d, 0xbbeb8d01, 0x00038031, 0x00000000 -}; - -static const u32 csem_pram_data_e1[] = { - 0x00088b1f, 0x00000000, 0x7de5ff00, 0xd5547c0b, 0x733ef7b5, 0x9993331e, - 0x420f264c, 0x084f0042, 0x21842a20, 0x38880840, 0x8d069009, 0x8808089a, - 0x420100ca, 0xa9113248, 0x676d5e97, 0x6ad11422, 0xa36d2d1b, 0x4101da97, - 0x180d45a3, 0x1d0340e8, 0x5abc414c, 0x5b4a0a8d, 0x3c3141b5, 0xe878490a, - 0xef5bd6c5, 0x33ef6b5e, 0x42667399, 0xfddfb6a2, 0x7f17dfbe, 0xecfb36fe, - 0x7b5ef673, 0x7b5affad, 0x231fb5ed, 0xd313c659, 0x057c8415, 0x7213d77f, - 0xf4842448, 0x0b3b4eeb, 0x108e3a68, 0xb0398e7f, 0xb4242055, 0x24edefef, - 0x4db39085, 0x267355b3, 0x98c7fb21, 0xf2d3d743, 0x80fc81b3, 0xdd4f9699, - 0xd121c479, 0x514ed57c, 0x3ed37282, 0xb1df7e2b, 0xde400851, 0xf1fd6e6b, - 0xb5df34b5, 0x699b2453, 0x376424d5, 0xda425491, 0xa9fd842d, 0x6a5f98f1, - 0x4daad965, 0xf682effb, 0x626683ca, 0x37b7dfa5, 0xafc86e89, 0x08042adc, - 0xf76aaf6d, 0x5a00ca83, 0xd080b2df, 0x7e695568, 0x1a8a63eb, 0xfb03c84f, - 0xb368ecfe, 0x67da7213, 0xfd82aa21, 0x491c6f28, 0x7b604548, 0x7dfa00e1, - 0x65c136c5, 0x6c57f5a2, 0xf401d73c, 0xc3c93455, 0x8adf5a44, 0x47511b06, - 0x22bfb6b0, 0x07cb5ed0, 0x794eded8, 0xfe57b428, 0x110a3de5, 0x1bb29fa1, - 0x74a2abbe, 0x76b5bf40, 0xb1eafb4f, 0x559f8d3d, 0xe8f6d1cf, 0x0a2fd57b, - 0xb562e82e, 0x8e807889, 0xb9d6dd8e, 0x7fa1db4f, 0xf8f0cab5, 0xdc2c7ec8, - 0x08a8fd05, 0xed0a526c, 0x6526df40, 0xfaeec8e9, 0x87fc3456, 0xacfabe9e, - 0x72889efe, 0x47da7a63, 0x3bbc3a59, 0xbb88415f, 0xa44bd691, 0xaa3a5280, - 0x4207f9fb, 0xa1e32122, 0x96a8917e, 0xe4a9faee, 0x23fe0711, 0x0f949ff4, - 0x81f1bdfe, 0x72dd99ad, 0x9904e95b, 0xbcedcb75, 0xea51cb93, 0x5fac8dca, - 0xf20c7f4b, 0xf9d4f4a0, 0xee3e989c, 0x8374c34b, 0xfdbe454f, 0xd30237dc, - 0x9f0b9f7a, 0xc3cbe93f, 0x8dcfa374, 0x22be53e9, 0x12be034c, 0x6fb36f7c, - 0x7c5ba62e, 0x8cfe7c1e, 0x06d31caf, 0x7f3e0d5f, 0xd31ab7de, 0x3e3f3e6d, - 0x1eb7d17f, 0x1d5f46d3, 0x5e403ba6, 0x05f26d34, 0xbe5dbdf0, 0xbe834c06, - 0xc7be7c46, 0x11f4c417, 0x64c747ce, 0x3e512f92, 0x49c4dc38, 0x8a924ec5, - 0xcd32f9dd, 0x7cb09527, 0x7cfe1dea, 0x3d53e685, 0x32f94f34, 0x6f9432a0, - 0x3501f9a6, 0xfdf07cac, 0xf342c0a4, 0x7cacfd83, 0x02ee23c8, 0xa90fcd2b, - 0x37c3e563, 0x68e20bfa, 0x9580787e, 0x542dbd5f, 0xabf9a360, 0x7679591b, - 0xa76a9933, 0xcb10ecf9, 0x9ee1bce7, 0x39f34f1a, 0xfb9f2cad, 0x83aa7f81, - 0xd8db73e6, 0x04ce93f7, 0x2d1ed544, 0xbab21d87, 0x6d595098, 0x4b70cff4, - 0x515e6913, 0xca2e21ef, 0x6eadff1f, 0x43f29d29, 0xc8796376, 0x9bcb1f3f, - 0xbf963714, 0xfcc32fe3, 0xe583d92e, 0x2c55fdc7, 0xfcb078af, 0x98bdff73, - 0x2c7eca0f, 0x58fad4b7, 0xf963f15e, 0x58f5da80, 0x80391eff, 0x1f6b23e5, - 0x4a3df2c3, 0x5f1fcb00, 0x1a7ba4fb, 0x3c11afcd, 0xd23c073f, 0x01649cb4, - 0x4ad31a9e, 0x09d69e28, 0xf7e02e64, 0x8a3a0007, 0x0ae975cb, 0x3f8ee1ea, - 0xfa0d3ee4, 0x90297f8b, 0xc3ccfa5f, 0xaffdf899, 0xd6991eb0, 0x4f5ef623, - 0xba799bce, 0x2cde727a, 0x8069ead7, 0xfb58d6f7, 0x378ecf56, 0x79e9e927, - 0x67ab42b3, 0xdf13d23b, 0xbce57eb7, 0xcf4f5935, 0x3d5a955b, 0xc49e907b, - 0x74d3d1be, 0xa69fcf44, 0xb4fe6123, 0xfafd3d20, 0xf7b8cf46, 0xf719fcf4, - 0x6f3f985e, 0x7de93d60, 0x3de9a7ab, 0xde9a7f3d, 0x08e7f30b, 0xdf506bf6, - 0x7dee35fa, 0xbdc67f3d, 0x47cfe61f, 0xdf664f48, 0xa1f5d9ea, 0x3ebb3f9e, - 0x04e7f30c, 0x6fac33d6, 0x48fdcafd, 0x8fdc9fcf, 0xc2e9fcc2, 0x5beaae7a, - 0xd23ebb3d, 0x47d767f3, 0x817cfe61, 0x5bea8cf5, 0xa2ff72bf, 0x5fee4fe7, - 0x0931fcc2, 0xbe98cf50, 0x54fc13d1, 0xa7e09fcf, 0xb0d8fe61, 0xa37df19e, - 0xcf5daf27, 0x30f6bc9f, 0x9004527f, 0xd5bec4fb, 0xf3d76c13, 0xe61ed827, - 0xe7ac20cf, 0x2bf5beba, 0x3f9e84ef, 0xfcc22779, 0xcafd8e19, 0xf40f7aa7, - 0x7c4f5a10, 0x39ecf5cf, 0x9ecfe7ab, 0x8cfe61b3, 0xd3a67ac6, 0xaf7ab27a, - 0x9e875267, 0xc23a933f, 0x7ac3c9fc, 0x9eadf466, 0xfe7a1d3d, 0xf308e9ec, - 0x73f91f27, 0x35fadf53, 0x9fcf53a9, 0x3f8c9d49, 0x4cd70f63, 0x3a72d075, - 0xfa44ba16, 0xdc67b5c9, 0x45e6816e, 0x4e8bcb27, 0x44bf0117, 0xd20dfcd4, - 0xf7e916ea, 0x39896df6, 0xbf48930f, 0xfa14a0a3, 0xb1bd4f15, 0x2123bf48, - 0xe7e74e2f, 0x7493ba24, 0x01a2e4f9, 0x95fbf7ba, 0xf795d10c, 0xaeb57b9f, - 0xa393dd3c, 0x4f9467cb, 0xa83fbdd2, 0xbf9740a6, 0xba0df562, 0xb7fd33f7, - 0xeb59f2ea, 0x3fbdd76f, 0xae916eac, 0x0afacafc, 0x8155f95d, 0x35fcba95, - 0x7baeff0d, 0x03e3547f, 0xc1d1f2ba, 0x63e57587, 0xf2eb8f42, 0xa93d0f63, - 0xeb7c7f7b, 0x84f95d66, 0xcaebcfa3, 0xd0edb627, 0xb93dafe5, 0xd9e7e0c7, - 0xf0d7ed9d, 0x27b808bc, 0x574fefcc, 0xc50bdfd0, 0x0657982b, 0xdf8fd1d8, - 0x3d54bf1f, 0xbcabe54e, 0xa14d58b2, 0x129905f2, 0x0fe7ae3a, 0x8db2bf28, - 0x9277bf3e, 0x7d274ae7, 0x19e2af7e, 0x9fe18ced, 0x24083c52, 0x04d5520d, - 0x41fcb1a9, 0x20b1e199, 0xc7e1cbe3, 0x535ef7e8, 0x9a44f0d7, 0xd7e62fef, - 0x129e5e03, 0x38d3884c, 0x7bc0d491, 0xf3826671, 0x73330782, 0xe047f69f, - 0xaa20fd75, 0xbd774287, 0x1a4f65eb, 0x6b9b19f8, 0x1f83f6df, 0xed106eb2, - 0x9e4200d7, 0xf90ede16, 0x07efd287, 0xd0f34d2d, 0xf50accfa, 0x57db23d3, - 0xb123fb68, 0xff6806fd, 0x37da1ec5, 0xb5d3c90f, 0xae5c196f, 0xd0a2df6b, - 0x1fd49df6, 0x6f23fda8, 0x12610a9f, 0x7f0b2f21, 0x83cdf6c4, 0x07fdb1cb, - 0x895f3a15, 0xdc2e3f6c, 0x77f4107e, 0x3e3fb41f, 0x4c87ff46, 0x707ff7d2, - 0x0affbe85, 0xb52bffeb, 0x71fb78c7, 0xe116ffd8, 0xe0ffeb18, 0x337fd60a, - 0xbedc37ab, 0x43ffcc23, 0x7b37ffd0, 0x64d67fea, 0xa8afff7d, 0xccdff7d4, - 0xf6a77fda, 0x8edf6f14, 0x9c2bbfed, 0xa2bffd62, 0xcc57db12, 0x47e0171e, - 0x09ab88c9, 0x40c9f6d0, 0x03fa986a, 0x903b685c, 0xa0a2488e, 0x6151e426, - 0x6f71d208, 0xe7dbc31c, 0x686f1471, 0x9cf8fc6f, 0xcb65a804, 0x8e2ef3a5, - 0xf2db15f5, 0x584bb015, 0x4b2be74e, 0x4165a938, 0x364df111, 0x28c30398, - 0xd1411dbd, 0x0db2f90f, 0xfec005d7, 0x4164cd79, 0x91277c09, 0xf4ff3c10, - 0x4736a367, 0x2e98cbf6, 0xdbdb93a9, 0x3c2df422, 0x23202a8f, 0xd37d286a, - 0xbbe30401, 0x79d31ff3, 0x8bf3a110, 0x833ce80f, 0x227e4850, 0xa23ef6b3, - 0xb7c825f3, 0x9412f9d1, 0xdf8b5213, 0xa70eead1, 0x384bfa51, 0x4c4b1ffd, - 0x43be3f5f, 0x7ea9f808, 0x31bdfe7e, 0xb05d4f38, 0xde9946da, 0x7f42c74d, - 0xfb4f2eb2, 0x753907e5, 0x360736ed, 0x155fc80b, 0xaa8a55f8, 0xf5e2c849, - 0xddd79419, 0xc54fbfef, 0x7f594e9e, 0xfdcb711b, 0xae77fbe9, 0x69390612, - 0xe6ddb3bb, 0xb84e361c, 0xd7a84c33, 0x4794c324, 0x634dadc8, 0x29035a64, - 0xb71fcb75, 0xb33bb445, 0x5d9f9f48, 0xc877cfa2, 0xe944d96e, 0xc81528ea, - 0x9cef5a26, 0xad72fab9, 0x8929bb1d, 0x57b799c9, 0x9be8ca92, 0x3c0e6903, - 0xe79ca276, 0x1ab7d93a, 0x32c5de3d, 0x3c82c29d, 0xc808fdfd, 0xef829fd5, - 0xfd64eedd, 0x573bd236, 0x684bb8b6, 0x142ee73f, 0x236f8003, 0x67da7ffd, - 0x69b29b73, 0x32a7feba, 0xc7f74531, 0x8f3cff48, 0x328d3fb1, 0xcbf3c38c, - 0x6e19cf8d, 0x3ffcb9da, 0xf4d07c06, 0xd283e004, 0xa3e39c7f, 0x7c32aedb, - 0x9b9ecd78, 0x4f5d0f01, 0xcae50488, 0xc71b72f1, 0x3d3a92cb, 0xc8f1082e, - 0x7365c720, 0x23879c85, 0xe3873070, 0x1ebd5960, 0xbf127737, 0x2e431e9c, - 0xfa6c36f3, 0xdd1a9a61, 0x6e390fbf, 0x1fb23fe6, 0x4fdd13f9, 0xb8bba726, - 0xd1acee9c, 0xe5c6df97, 0xeb97277a, 0x0ec7fadc, 0x6e41f350, 0xe8320357, - 0x4d3ef7bb, 0x793a6d9e, 0x8d3cb87a, 0xe5c5de74, 0x98f7d779, 0xb6f48d3c, - 0xd5b67971, 0x90c9905f, 0xf48d7a68, 0xd51d582d, 0xb9e4051f, 0x9e5b1fd0, - 0xf27e60de, 0x55e788f1, 0x8f92338d, 0x8ad9e847, 0x7e5d5286, 0xee9e6079, - 0x0bf565fd, 0xea4be575, 0x17caeb96, 0x975bbfaf, 0x9effe85f, 0xab05fdee, - 0x77e5756b, 0x2ba43cd6, 0x98fe5f9f, 0xf3cf3f2e, 0x39fdee84, 0xcae93773, - 0xa73c9767, 0xb4599f2b, 0x752f975d, 0x6fbdd6ef, 0x2dd577da, 0x8e37cf80, - 0x89fc0488, 0x30275ccf, 0x4b99f82e, 0xc73bc176, 0xbae22a7d, 0xd30237dd, - 0xe2173e93, 0x0f2fb4fe, 0x8b608ed3, 0x3a09c61d, 0x89252e2e, 0x6e9bccd4, - 0x103f5dae, 0xe38269c6, 0xacd316e9, 0x4264ff5a, 0x91526d7e, 0x0af5c5df, - 0x44258d09, 0xd386c180, 0x944625d1, 0x5e52f5b7, 0x727f0d4f, 0x5b717974, - 0xc7dee7ec, 0x8ce15e17, 0xd6e97711, 0x7e019253, 0xbbf7274f, 0x0295e58d, - 0x4e7c8929, 0xd7a803c8, 0x5bb8f8e7, 0xaffd30a9, 0x405e91dc, 0x0d0f901c, - 0x7b5cb9af, 0xfde4148d, 0x3a592701, 0x7f565e3d, 0x13bece8d, 0x03f6ca88, - 0x3dd58dbc, 0xad70d15f, 0xfb33bbee, 0x1abba445, 0x1844c56c, 0x375e4b16, - 0xb50e1d81, 0x0a399e0c, 0x61bf74e8, 0xd82a7182, 0x33c2fd0f, 0xe3e4a2be, - 0x04afc812, 0xb9be93d3, 0x3cfbb698, 0x95f71e98, 0xafb1fa63, 0xdf36d306, - 0xf23f4c6a, 0xc0fd31f9, 0x3fd31eb7, 0x3d30eaf9, 0xf4c7abea, 0xd3005f3d, - 0x4c06bec3, 0x6235f1df, 0x620beada, 0x6373e1da, 0x6f5de9aa, 0xc7c93bb8, - 0xbf80d3e1, 0x78eb3818, 0xfaed5560, 0x3b38ddc9, 0xd6afba6f, 0xcf9bb03f, - 0x8e66f5c5, 0x1e1d5487, 0x336080be, 0xf297ace2, 0xb0e3997a, 0x9763efa7, - 0x6bff377b, 0xc4de36f0, 0x8a6fccfc, 0x653c6eb7, 0xd594f018, 0x89fa9e1b, - 0x34f1bbe3, 0x7e64e4de, 0x8fd3c70f, 0xe6311fa0, 0x84e00515, 0xd7f08bf4, - 0xa71636dc, 0xd409ebe6, 0x6a716553, 0xfa1af6de, 0x75fa2b6e, 0x6e301181, - 0xb7f11f9c, 0x3f8710e1, 0x274cd47f, 0xcff73d7d, 0xf99e9388, 0xcdf9c6ee, - 0xbc1d00d2, 0x5b9746c6, 0xad5f18e3, 0xe8445226, 0xb0d0f6b8, 0x468b5c67, - 0x49225e62, 0x55c07df0, 0x5ea31f1a, 0x7f032bea, 0x9aebe37b, 0xa1b3cff8, - 0xff27f6be, 0x78e90b9e, 0xe397f313, 0xdbf4445a, 0x1769e849, 0x2e3c37f0, - 0x10695d99, 0xa61aeedf, 0x086fd138, 0xf3fcf5d8, 0x376e7cd3, 0x3ca21eff, - 0xb771c56a, 0x37f90d2e, 0xe9e1f3f4, 0x6f5fe07d, 0x7e37bdf6, 0xf80c0a2e, - 0x37b3f097, 0x5d9bd8fb, 0xc5f56e24, 0xe77fed20, 0x0f3951be, 0x870760ab, - 0x0f5a79b0, 0xa5d6d6fc, 0xff7cf48c, 0x33b8e26b, 0xeb71c355, 0xf9db4260, - 0xf9cbeb88, 0x40132ba6, 0x9c1eb42e, 0xe4ed741f, 0x722f7e7e, 0xafa99b3d, - 0x2fac6bcf, 0x68c22141, 0xa2bc6eda, 0x6a420490, 0x22a3cf44, 0x6d5c6fce, - 0xec1b887e, 0xa8d6b9b3, 0xfd3c6f30, 0x1a854866, 0xf385f1f5, 0xc0769e87, - 0x9a656c3c, 0x863c79c9, 0xaab4b51c, 0x8f69d331, 0xf504af9c, 0x4275f3f9, - 0xe7ce2351, 0xa35984d4, 0x3a719c60, 0xbb050f8f, 0x56a9869f, 0xc534cacf, - 0xddda9c79, 0x09590dd3, 0x6017fe6c, 0x225b64f6, 0x3ed39bda, 0xcfffbe0b, - 0x7aa7a7a6, 0x69087a34, 0xc0589f22, 0xacb2d39e, 0x51efdf9e, 0x0a8ba41f, - 0xb34937c4, 0x37cc39fc, 0xaffff4ad, 0x12bd4086, 0xbd7ab5e6, 0x3cdfa28d, - 0xd36f9e1a, 0x53bf47b5, 0xf857b5b5, 0x93bd67ae, 0x7b86bb48, 0xf957bf2a, - 0x068af0fa, 0xc7ef53ab, 0xdef2ea26, 0xe753ba60, 0xc03fc2d7, 0x2411af71, - 0x87255fc0, 0x5f64a75f, 0x0cda780f, 0xbf9843c1, 0x2abdec08, 0x51e29b4b, - 0x015a5d51, 0x34f28b9f, 0xfe73abfc, 0xa9d4ed4c, 0x7a0265d7, 0x54a4be46, - 0x20a9f2e5, 0x4c44cde2, 0xbf98bf34, 0x4569a8bd, 0xa75b8c31, 0x50fe6c4c, - 0x301c4a46, 0x75272e3f, 0x3d4f10b9, 0xa0454c4b, 0x3bc9679f, 0xfa11b18e, - 0xb0544e78, 0xf5ebc5d2, 0xdf9d3c7e, 0xeacbf2eb, 0xe4a5f9f5, 0x075854d6, - 0x2641ba5f, 0x86ec0101, 0xe898fcbe, 0x91977ac4, 0x6e30759a, 0xbbc79cff, - 0x94893916, 0xfaabe941, 0x17732fcd, 0x892e3a52, 0xd6d5fc6c, 0x31279771, - 0x05662bfa, 0xff7d3714, 0xb7b1a693, 0xbf440b51, 0x7583ac0f, 0x71297f6d, - 0xf2d1256d, 0x1bf4bafb, 0x81fcd5e9, 0x4e64f5a8, 0xe0834a47, 0x63b0c40e, - 0x3d30248a, 0x6aeef6e3, 0x838ba9c9, 0x223e42e4, 0xf18df20e, 0x78744294, - 0x067a2cda, 0x7e19e34b, 0xd4820f00, 0x4dbe78a5, 0xf55169fd, 0xfbf52d5f, - 0x903fd627, 0xabab9fd6, 0x4a9ff73f, 0xfa28d0ff, 0x5fd5620b, 0x76179bf5, - 0xa93da9f9, 0x0e67e978, 0x53c9c742, 0x8baa5d52, 0xeb72b5ca, 0x9a6e1d0f, - 0x0efc949e, 0x80a9ebc0, 0xde4b1458, 0x76f2c3ab, 0xbb8805db, 0xfd693fc1, - 0x11ff9fa7, 0xdf3e23c6, 0x9e313b2a, 0x990e60d6, 0x37563ea9, 0xd9262f2d, - 0xf2c63f98, 0x21139e0f, 0xafe3d41f, 0xa59fd9e2, 0x8a0afec2, 0x0a5f1e14, - 0xbd5b3fa1, 0x1c42d3e5, 0xea17489f, 0x683bf191, 0xda1252ff, 0x424a85bf, - 0x13a53974, 0xce5e04e3, 0x8fd36f17, 0xf80e89ce, 0xdfce1b57, 0x7397ef8d, - 0x14b974ff, 0xa36ed29f, 0x26409eff, 0xf8d43d80, 0x3fcc0241, 0x2fdcf35d, - 0x7a518fb2, 0xdd796cce, 0x49f04421, 0x8df3a3d3, 0x47b57f8b, 0x76ded9ed, - 0xf48b3d50, 0x4af1b483, 0xbabf720d, 0x7295a599, 0xd52d71c8, 0xb24dcafb, - 0x571f4fcb, 0x33f4f0be, 0xf31c424f, 0x30d7668f, 0x178aff5a, 0x8937bc0e, - 0x976c57e6, 0x37598a53, 0xb76a42ec, 0xfff4bc5c, 0x72dd39d5, 0x80f978a8, - 0xcf628ea2, 0x96ea4fef, 0xfbed8ac7, 0x9a2a3215, 0xf71b531f, 0x18f66d2b, - 0x563c6972, 0x9ac27e08, 0x814bfee7, 0x7da9e2f8, 0x199fe902, 0x0e9b9f83, - 0x7c001fa0, 0x39723942, 0x7866e585, 0x02e54bdf, 0x93935af6, 0x6e46fcb1, - 0x753ea04f, 0xc5f9e224, 0xf2fdb43d, 0xd05d993f, 0xef17f2ff, 0x4e3f4071, - 0xd70c3548, 0x2a61fcbf, 0xd972afd8, 0x94c4ea9f, 0xea7f2f3d, 0x65b788bb, - 0x15377f6f, 0x9dc449e3, 0xc7b1c26e, 0x5bfd0e9f, 0xf63671b2, 0x20f1296f, - 0x297fcaee, 0xfa680496, 0xb68a4499, 0x0e8bd0c7, 0x362717ae, 0xf68c4753, - 0x1fcc04ef, 0x23bf5ec1, 0x422abee2, 0xffa026ee, 0xa17de5df, 0x3fe6021e, - 0x1d3930b3, 0xaf5c4c90, 0x8919b7a8, 0xb60f2dd7, 0x0f4e7c82, 0x7587f772, - 0xfc912f16, 0x57c21f9c, 0xedf15eb4, 0x7c99fde9, 0xf2e52a88, 0x3f38e8ef, - 0xfbc39e15, 0x9adbb2ad, 0x7c8efbad, 0xfeddd995, 0xa53ede2a, 0xe7c60e3b, - 0xfdb1a913, 0xa6b201d5, 0x8e9c74f7, 0x7e8457c0, 0xf2df7d33, 0x4d6fd310, - 0x45a503df, 0x30f17e50, 0x0ef81fd3, 0x574a3fc6, 0xef963fa8, 0x3da0259f, - 0x58e6f3a0, 0xe645bd7a, 0xd72fad7a, 0x96e94270, 0xbc088484, 0xc849fd40, - 0x595f5c7f, 0x177e81ba, 0xd0bd2f61, 0x3eba239e, 0x71976f4d, 0xfa053ffd, - 0xfeb74d7f, 0xef4c8d93, 0xfc9ff67b, 0x07236e2c, 0xf412799e, 0x5fa7ea95, - 0x4b957d05, 0xdd7fdfa0, 0xeddef2d6, 0xdaff4f54, 0xdea9e9a8, 0xb4f51a7e, - 0x1278c77c, 0x6aff4f4b, 0x7a989177, 0xd4c79f4a, 0xe21b7b53, 0xfd94fff8, - 0x2897f8d4, 0xd9a7f9eb, 0x68f89ec3, 0x4a2f87b4, 0x68d3f22a, 0x61dfe90f, - 0x3f8d1b92, 0xde1a770d, 0x755d7e2a, 0x309dd805, 0x85dc352e, 0x2ee1a971, - 0xe3ab7e2a, 0xcffcb19f, 0x74a26b10, 0x4fd4b7cd, 0xa5847981, 0x2bbce08b, - 0xeb88967f, 0x048b96a6, 0xc880bef5, 0x7df06fb8, 0xf078cd53, 0xfdfca743, - 0x52f7b3b6, 0xbf13e77a, 0xebe5d6cc, 0xbfebf464, 0xc9abeafc, 0x73b73fb4, - 0xeca7cefe, 0x63ca89be, 0xe28424ae, 0x24f39d28, 0x82484fe2, 0x3e40acf8, - 0x7e63a08e, 0x7f0f3eb9, 0xebbb5253, 0xaffdede9, 0xa6f90f3b, 0xb63edbe9, - 0xa42ef576, 0x2979b143, 0x20a54f12, 0xef3fca57, 0x04302138, 0x549b52ed, - 0x7aaf3112, 0xb79ddb9c, 0x0f1ccda7, 0x9cfe4bfe, 0xe70c0951, 0xeb7e7183, - 0xbcebf6e5, 0xbb004d5f, 0x0b39be7e, 0x0fe7afe7, 0xb58f8e2d, 0xe385b26f, - 0x575f00ec, 0x750bb4e9, 0x277dc522, 0xc5ff42e9, 0xad92b76f, 0xbefdd631, - 0xe4f89b2f, 0xfe8dcb83, 0x736e5489, 0xd1e70e39, 0x2272134f, 0xa6eb36e4, - 0x5a239253, 0x71f7f00e, 0xdbeb3cc4, 0x0d7017f2, 0xb6b16dfc, 0x88c49615, - 0xf384fdd7, 0x5f2bca6f, 0x69d5fee0, 0xf012f9cd, 0xd45d9a71, 0xd41e39c5, - 0x192475f4, 0x794d7409, 0xe3a3f965, 0x87bd8e29, 0x57ec1744, 0x539f36f5, - 0xbbe6313c, 0xfd427e46, 0x901e47e0, 0x23afc89d, 0xe012c972, 0x56d991eb, - 0xef96eb02, 0x58aaae2a, 0xb3374e74, 0x523cc878, 0xe138d9f2, 0xe6fe3eff, - 0x150f89cf, 0xb79c7e50, 0xd1c0fdb3, 0x7f7a63f8, 0x6a0429de, 0xc8a1c005, - 0x004229f2, 0xc48564e2, 0x0164e8f3, 0x48fafdf5, 0x2c1f95fb, 0xd5f6017d, - 0x4e0b3754, 0x96af2d13, 0xb1c014da, 0x025db837, 0x9546fcff, 0x20de31b8, - 0x159a8cd5, 0x203ad711, 0x96afc84b, 0x277eddbf, 0x2cc2f7f0, 0xdcba0133, - 0x6039cf23, 0x3cd0bfdc, 0xa7a0f516, 0x47c1fd7e, 0xa0934ca6, 0x30f8821e, - 0xc530a1e2, 0x9ecfcba6, 0xa8ba064a, 0xdb98a6dc, 0x90c571ee, 0xe18532df, - 0xcdf6cfac, 0x7d99fff2, 0x1bed4c9b, 0x691cb5c3, 0x512b46df, 0x2c7fadf6, - 0x56b2b6fb, 0x58b80fed, 0x3fab37b9, 0x6be575c8, 0xb2c5fa4b, 0xd8faaf6f, - 0xbe35fdfc, 0x2073bb0f, 0x23a36fb5, 0x6a40dbec, 0x6dc462df, 0xffcd15d3, - 0x59bec5ec, 0xeff477fe, 0x316fb055, 0xd1523bfa, 0xe6a2b7db, 0x456fb45a, - 0x7edd4503, 0xcf852ca8, 0x6fb47ae7, 0x1b367f0b, 0x16cbb2f3, 0x57c03f03, - 0x71af6fb0, 0x80ed073b, 0x38a45b9d, 0xdabefdb1, 0xdabed2b9, 0x3e25ffb9, - 0xe56e766b, 0x239e7620, 0xcecc871a, 0x7664ccad, 0x665ee56e, 0x630e56e7, - 0xdf68ce76, 0x1beca20a, 0x047abefb, 0x8be71efd, 0x83b8bf99, 0x95cf1796, - 0x7efa165d, 0x5f9daab1, 0x691f19a8, 0x122916ef, 0xdeca39f2, 0x39e1ceb9, - 0xddecde90, 0x86ef605b, 0x0a1b1da2, 0xc7c4647a, 0xba6d430d, 0xbe4772fd, - 0x4bf5ff68, 0x107f2fa0, 0xbefd9e71, 0xf68bcd89, 0x163ed17d, 0xa7376ef4, - 0xc98551e7, 0x47e7c3b3, 0x24753a7b, 0x43aaf7d3, 0x544e3871, 0xbfac0937, - 0x15010bf7, 0x5dbf81c6, 0x9df2f9c2, 0x797cd97b, 0x83f1998e, 0xcec89bfc, - 0x2c16505d, 0xdcc3c08c, 0xd718154b, 0x0b112b9c, 0x0e0baff8, 0xfc0a70dd, - 0xd69705d6, 0x00bbbfa3, 0x89bec39e, 0x32eb6ded, 0x2e77bb68, 0xa1de7017, - 0x1798efed, 0x3f7a97b6, 0xec737e76, 0x38531a7d, 0x13ee533d, 0xa72fb002, - 0x2f107db7, 0x239bfd72, 0xc8bf21b6, 0xf8cc625b, 0x985ef6a4, 0x97c62e4f, - 0x6fcc55aa, 0xf289f30e, 0xf9a2154d, 0xbc5d2544, 0x2f9bb530, 0xfda4ee77, - 0xbfb9e94d, 0xf7a2df1a, 0x3e71b8e1, 0xd7bf80b3, 0x3e341f13, 0xf39ff547, - 0xb8a9fa9d, 0x8fc8c79f, 0x5ccecd46, 0x5e814643, 0x3cf26fbe, 0xf4701e3a, - 0x942f949f, 0x0de6dbce, 0xd9e79dd3, 0x9372f9c5, 0x54b4d8e7, 0x6a48f815, - 0x97b76700, 0x4a903f6f, 0x3b8b77fb, 0xe6420733, 0x78a6ffb3, 0x62d0fe20, - 0xa83b42ed, 0xcccd30e1, 0x8e57f870, 0x9c0323c3, 0x09bc70d3, 0xafd44e0a, - 0xf1cec190, 0xca5e647d, 0x6f5fd067, 0x144f8f90, 0x859fa09f, 0x720578da, - 0xa9bcffa1, 0x5bc5c999, 0x6e5ca023, 0x81075d26, 0x8229d5ef, 0x2aab442b, - 0x21ff6e0c, 0xd57ab7ec, 0x9e839f4a, 0xcdae0b97, 0xf4f61d8c, 0x963898d4, - 0x3718e162, 0x9b8c4609, 0x24bde00b, 0xc668b7d8, 0x1efceff6, 0x3f4647b3, - 0xf5b98a65, 0xe533d008, 0x09b264df, 0x7fe8061e, 0xfa303811, 0xf07a5131, - 0xa4fdf735, 0x2afdfb72, 0xfc0ec1c8, 0x1fc052ee, 0xf8d886f2, 0x257b95a3, - 0x4df21a75, 0x8e904393, 0x1c98e32f, 0xc8dfa960, 0x3cb45be7, 0x6fde1fe0, - 0x7ef86416, 0x324f9506, 0xfa6a9a2d, 0x7786a0e2, 0x2fcd1ab3, 0x47a42788, - 0x6fb00dd8, 0xd596eb91, 0x4f91b7c1, 0xeea2ac37, 0x27cd1a99, 0x07603e4d, - 0x28afc72f, 0x8fee09fd, 0x9bea7fb9, 0x599a4fea, 0xacfb3faf, 0x868faf5d, - 0x015eda38, 0x4e690aed, 0xf20fc5d4, 0xd65e6ccc, 0xce20f562, 0x5d935ebb, - 0xfb68d59b, 0x0b971573, 0xcf2257cc, 0x0e854def, 0xd3b1bac1, 0xfad13e4a, - 0x2ce1843d, 0xd5783c72, 0xf5f941ea, 0x5e04ff54, 0x98fe4f7f, 0xb40eff96, - 0x5516fb07, 0xf1c67b7d, 0xf5278b48, 0x6669afd6, 0x69be3f66, 0xbe76b4bf, - 0x9783baee, 0x4dfc62b4, 0x2cd87f5b, 0xc32e7e7a, 0xd048b8fc, 0xca5073ad, - 0x9ff2fd71, 0xe558ff50, 0xfc43f532, 0xfcf94428, 0x31a7b6ea, 0xf9f67d5e, - 0xfe833763, 0x48adf8ac, 0x3a9f542c, 0x1093c5b6, 0x80a207db, 0x24d1509f, - 0x91167ae2, 0x2333b942, 0xd6420cfc, 0x14bc7e30, 0x62a7768f, 0x4c503987, - 0xf5d8afbf, 0xddc43649, 0xf6601e3a, 0xc73cffcf, 0x1b2dbfa3, 0x242bfbd6, - 0x946f8eb6, 0x9f1cbdcf, 0xe6db7667, 0x1a16fd82, 0x8ad779d8, 0x39b239c6, - 0x6550ce22, 0x7b5c5996, 0x59f70db7, 0x70139ffb, 0x17d0329f, 0xdb52ce79, - 0x39e679ff, 0x822b9766, 0xcdce0072, 0xef6c3456, 0xc5783880, 0xaffa3351, - 0x0a7386de, 0x5f53a7f8, 0x23fd017a, 0xc5d4506f, 0x8fe2a341, 0x0cc8620d, - 0x2aa6b3f1, 0x7f3403b4, 0xb18df30c, 0xc5bdf0e3, 0xb4bc56c9, 0xb29f9777, - 0xcfcbc570, 0x6cdcf03a, 0xc60756eb, 0x1f2e1b21, 0x378a8fff, 0xd9743e36, - 0x8e69e378, 0xf5995f8f, 0x21a435eb, 0x9490e319, 0x1892dcbe, 0xee308b71, - 0x29ecf85f, 0xb33b0f58, 0x014fafe3, 0xb8ff95bd, 0xe07dd4f0, 0x3ab3ed8f, - 0x3ef6bc61, 0x13d7047f, 0x7376efb4, 0xee78ef3d, 0xe9875c59, 0x05d9a3f8, - 0x3dec75b5, 0x23d61831, 0x917fb63a, 0x55db710a, 0x3ce3a77b, 0xa9ced56d, - 0x798c49fd, 0x6e029680, 0x07587d03, 0xa5abca32, 0xd03065a9, 0x1bca9679, - 0xfc70b65c, 0xc58ab1b8, 0x371e55e3, 0xbd7b16de, 0xdc4e2a2d, 0xeb96f334, - 0x926efc60, 0x43e92a5d, 0x9530f8bc, 0xc83ee8e3, 0x9a43db6f, 0xbf298fbd, - 0x2a0ff0b3, 0xf20df7a7, 0xc969acfb, 0xb2849eaf, 0xe31ee4a6, 0xf03ea1c5, - 0xdbcf5b4d, 0x6c7f7662, 0xf1d9bd06, 0x83cf8c6b, 0x835ce8dc, 0xd9f0bc74, - 0x9cb38860, 0xc2eebb94, 0xcd7b33fd, 0x62aa2fb8, 0x3fa8fbef, 0xc6df3b1d, - 0xd7c232f5, 0xf8483ad5, 0xf083ad8f, 0x4b779c39, 0x73338b3c, 0x5a1c43fe, - 0x1e73e075, 0xd638666f, 0xc53dd0e2, 0x6c2dd39f, 0xceb6913f, 0xcfe5b558, - 0xf5c4310a, 0xd3903c85, 0x8baecbb1, 0x02707c6a, 0xae44261f, 0xf38ec4a7, - 0xb8ddd787, 0xe07e40bc, 0x4bd7857f, 0xc4207e68, 0xfbc203cf, 0xe83d8624, - 0x61d6c4d8, 0xfbd8e43a, 0x95f5b50f, 0x4f418b14, 0x575b7d03, 0xaffe8de9, - 0x26191fcb, 0xf9a3e39b, 0xd8cbe674, 0x45827c76, 0x61fb76f8, 0xf5a8852a, - 0xcfac0b7f, 0x60531d37, 0x638da1fe, 0xf0cf7f5a, 0xe799f279, 0xb1ef3c45, - 0xed05b1ae, 0x545ed1b8, 0x341f1613, 0xd3833bd2, 0xe3641d5b, 0xf11d99c4, - 0xe7ad3b01, 0x11bb2bcc, 0x8edbd5cf, 0xdf5a7e29, 0x959786c1, 0x52fd88b6, - 0x22044e30, 0xe2f33fe8, 0x7eb66cfe, 0xc6e5e6c4, 0x76f0e676, 0xdbb1cdbc, - 0xa73b6ef1, 0xbf85676b, 0x77e76151, 0x69dedf2e, 0xea073dc9, 0x132add3b, - 0xba7fbfd8, 0xc40a2c51, 0x45927f68, 0x4cf2e2d6, 0x8978e86f, 0xd9e31de7, - 0x493146f9, 0x557aff41, 0x84d1de7c, 0x15154814, 0x6a6b14e2, 0x35d2fed9, - 0x81a577df, 0xde24d7bc, 0x756deb86, 0x533afe06, 0xbf10f99c, 0x192b4e70, - 0xda357007, 0x49b7449b, 0xf8aaff47, 0x1e70fea2, 0xc7f72d7f, 0xf3c2e488, - 0xb0a3a297, 0x3a23fa08, 0x8c6b4e4d, 0x5ed905f5, 0x7c113c42, 0xf3fa9d91, - 0xb1cbe492, 0xeda3d42a, 0xb4b4a9a3, 0xa742c41e, 0x4b0ab71b, 0xfcddec79, - 0x77ec4e59, 0x4f3e36e7, 0x99d51370, 0xc183f6ca, 0x23b9d1b8, 0xc68c9b21, - 0xe29b890f, 0x0b9fc6d1, 0x07eff6db, 0x41d6b47b, 0xcf5489dc, 0x31555728, - 0x8e8dce0b, 0x805908b1, 0xfe6f73d3, 0x6d6bd696, 0xd0fe7116, 0x85f6d769, - 0xcf4113ba, 0xdc11e46c, 0xfe5007ff, 0x4e9bb92a, 0x0240bee3, 0xdf76a4af, - 0xb45d312b, 0xfce7bce3, 0x10071646, 0x98bfd5c9, 0x2470e2cc, 0xf1f3f400, - 0xf3a70564, 0x7ef0a43c, 0x3ae78299, 0x72f6bd96, 0x3930886e, 0xb92bf244, - 0xb4be7f48, 0x86c8eade, 0x77e27975, 0x9939c2b7, 0xbf5f5e32, 0x53b9fd12, - 0xd07e7eaa, 0x4f5c25d3, 0xf0b4baff, 0x32bfd810, 0xebb452cf, 0xcfeae7fd, - 0x59f71aa5, 0x2fb0bd21, 0x93ddea8c, 0xabbef442, 0xd6c7e6f2, 0x7a397cc1, - 0x011915ff, 0x482ac9fb, 0xe7ce0b9c, 0x97d068ac, 0x79bb03ef, 0xd893b015, - 0xebef172f, 0xc36dbf95, 0xdc79317f, 0x0aebf965, 0xe2dbfbc1, 0xecb2ae31, - 0x9f68c5b5, 0xfe7a69cc, 0x7f3d555a, 0x7c8c236d, 0xde39f3d4, 0x369be7a5, - 0xcf89ecff, 0xf3fa7909, 0x4b3e46be, 0x021bc784, 0xb5110e2c, 0x09b82dbf, - 0xd9f236e9, 0x0b76d7c8, 0x7ce2f75f, 0x96257fa5, 0x81b26654, 0x842974ee, - 0xa3d4617a, 0x80487b0c, 0x094a0f7f, 0xae57e2d4, 0x69efb478, 0x19423fbc, - 0x7a06cefb, 0x2ebd0224, 0xd13823d4, 0x46de7607, 0x5bb6703e, 0x909f5841, - 0x59e9aeaf, 0xfe94f79e, 0xfa22d8fe, 0xefc046d5, 0x762bd468, 0x0489376e, - 0x9e8264d6, 0x6e309cba, 0x6a2cfa37, 0x9ff70499, 0x286cb510, 0xc4e27bdc, - 0x1f7cc7f4, 0x8248e74a, 0x431b82fb, 0x3ec15317, 0xeba738fd, 0xde7bb066, - 0xec04a425, 0x6c71cde0, 0xa798b29e, 0xdc2ab77f, 0xed7b4eae, 0x59bef87a, - 0x785ce156, 0xcb56f367, 0x4507c830, 0x9bc47fbc, 0xb4157758, 0x332cd1df, - 0x812ccaba, 0xd8bf1061, 0x1dbb632b, 0x7cf19365, 0x6b6fd865, 0x3a40fb66, - 0x2c713f9b, 0x1de7b08e, 0x055e9fc1, 0x4c27acf1, 0x0c9ff7b1, 0xfdf89ab7, - 0xfc70df35, 0x7fda8c6d, 0xf6cadc37, 0x0878fdc7, 0xe97547ed, 0x330e3e79, - 0xcb96b87d, 0x6f4bf7f9, 0x6ceffec0, 0x47185416, 0x6e3bc50a, 0x39fb451c, - 0xe3c488f1, 0x392e2c30, 0x9bbfbf8e, 0x1f80d2b8, 0x0223af13, 0x3fc4f3e8, - 0x35b7dc12, 0xce2966ae, 0xa0eb7eab, 0x7586cf38, 0xb05b8a52, 0xe8ec6773, - 0x956f8fbf, 0x9c4cb874, 0x798169e6, 0x04a384e6, 0xa384eded, 0x123cf2fa, - 0x369db110, 0x4f6bf3fd, 0x5605f3ea, 0x49076f8e, 0xf86f7c05, 0x3aba4452, - 0x01eb88bb, 0xd9676f5a, 0xa6efbc00, 0xda9c22f3, 0x6297e9a5, 0x7e71ac51, - 0xf281e026, 0xe08509eb, 0x52c4f2f8, 0x5fefc63b, 0x05715a59, 0x7f9feb8c, - 0xac4573cf, 0x7611e073, 0xafed8129, 0xe2502772, 0x0ad7ae29, 0xe975df8c, - 0xebf63125, 0x70d6386b, 0x7d39e1ad, 0xd6279c69, 0xad0fc4be, 0x58290fcc, - 0x6050423a, 0x204fb65e, 0x078ed7c0, 0x373d973c, 0x640f27e3, 0xe0de3d00, - 0x2db3f405, 0x963b82cd, 0xeacab19f, 0x07bef360, 0x1fb0b5fc, 0x94aa5eef, - 0xae7b1f60, 0xabce0377, 0x2ba0876e, 0x5ba9677c, 0x9770e788, 0x8866c858, - 0xe9754b67, 0xee03c6b7, 0x4758cea7, 0xc4b27de9, 0x427e7284, 0xfefd2176, - 0xbe30422a, 0x03b5e3c0, 0x229b266f, 0xc0ff23cf, 0x95b0ff9a, 0xd5b0fbd6, - 0xf6497289, 0xdfa004b8, 0xe5ffdff5, 0xbceebd00, 0x0e394664, 0xed1ff3e0, - 0x4f9cadbb, 0x6bdce3a3, 0x3ca4ff01, 0xe5c3f505, 0xc965a871, 0xe5012f70, - 0x54758c7b, 0xf24d2fcd, 0xe946db50, 0xf09bb249, 0x76e22e7e, 0xdf6d4eab, - 0x45efe119, 0x090903e8, 0x69a5f604, 0x166854f6, 0xff14f142, 0x10f62ce3, - 0xca9233cc, 0x0929bf69, 0xf5616256, 0xc2674ab5, 0x9f71aae7, 0x2e65c53b, - 0xb8226e1c, 0xd2360daf, 0x9d9afd42, 0xdaf3ecd5, 0x66f68244, 0x605263ed, - 0xa367ad0d, 0xf88566d4, 0x2d5ba649, 0x4944ad80, 0xbde78a92, 0x7d339507, - 0x32fd65b4, 0x50afec31, 0x0ff31f65, 0xf5ac4171, 0xfcc38fba, 0xfc00bcf2, - 0xf5d43eca, 0x2e35b80a, 0x75cf6b2b, 0x79fe82c0, 0x3f706ed8, 0xbb8f90ac, - 0xb1353f13, 0xeba102fd, 0xb69dbf71, 0x1bb4668e, 0x15de0f54, 0x953eaf41, - 0x75cf9e08, 0xb572ffd3, 0xf611772d, 0xb9938f83, 0xf4169ac1, 0x2d91c4dd, - 0x5f6bc780, 0xa238bbc7, 0x3784c8ec, 0xde806b3c, 0x8c3f6a6f, 0xa2131878, - 0x33e5c8fa, 0x2a7b8552, 0x943ce19c, 0xfcf95ab7, 0x949bdb8e, 0xd1fd71d2, - 0x3338e5af, 0x6bd357f2, 0xace7bea3, 0xb198b576, 0xc13200d6, 0xba110ed8, - 0xc0b350e9, 0x8221bd1e, 0x4f99df7f, 0xbae942f1, 0xfc0ef417, 0x19818bf3, - 0xcd0d9b80, 0x7e82b1df, 0xa3f1e37c, 0xb11d7e99, 0xa227fabf, 0xf6cac3a7, - 0x0f803b87, 0xf22ffbd5, 0x728423f1, 0xea95cb0e, 0x443c6447, 0xe711bdc3, - 0x81ac5e9a, 0xf0b2330b, 0xf9011c7c, 0x0a234288, 0x3a364cd6, 0x7f9aaf81, - 0xcfec26bd, 0x9eb9e226, 0xded64e55, 0xcbf3591a, 0xefe8165d, 0xfe82f8aa, - 0xf5175b97, 0x97f3a25e, 0x5e30f388, 0x67e70ba9, 0x090a4bde, 0x7e0b7f24, - 0xb9eb6905, 0xc4a57e3a, 0x0757e0c5, 0xfff8d1e8, 0x6d93fb27, 0x6a83cfec, - 0x25ae7f77, 0x51b6df9e, 0x4f7b90bb, 0x05c33a7d, 0x89169c39, 0xd95ebe0b, - 0x51e77e93, 0x2dd706fd, 0x7a0d9f4a, 0xea99b13c, 0x8f5a29b1, 0xde09725d, - 0x6bdae75b, 0xd4677b43, 0x5fbc8beb, 0x7be31b5e, 0x1199e88d, 0x5371f307, - 0x5dc060d7, 0x8b924ab6, 0x41d9b129, 0xb6afad91, 0x91c6eb26, 0x8fddf1e8, - 0x2ff35276, 0xf8d2bf35, 0xe4afd85e, 0xcf1686e3, 0xff148214, 0xc7f7dfb4, - 0x5f01e679, 0xfcd938d7, 0x829a0e13, 0xab03fcbf, 0xcfa00ee7, 0x0710fb46, - 0x42231aeb, 0x125e2c99, 0x4f5be9d2, 0xe83365fa, 0xc248634f, 0xc74fcc71, - 0xcf4261b1, 0x4b8bf4f4, 0xab52f464, 0xc0ca7e02, 0xab1ac25c, 0x7bafb826, - 0x47bb3660, 0xbb0e6066, 0xe3dff1f7, 0x7dcc7ad8, 0xd0dc6c71, 0x4b581fd2, - 0xc97e81ee, 0x739bf112, 0x40dd39be, 0xef0fc42a, 0x0ddf738f, 0xb914b0fc, - 0x4e191fb1, 0xde2812e2, 0x0146a432, 0x552437f6, 0x1b8b02aa, 0x40ee3612, - 0x28cbeb4a, 0xdc61f356, 0x16b6a0ca, 0xcd1920e2, 0x6cf5cfb1, 0x5dbf9388, - 0xea29abbc, 0x3886ca3c, 0x541f6fe6, 0x8b937f68, 0x709479d9, 0x0f9286dc, - 0xbf88edfc, 0xf1db3b0d, 0xf50f5b19, 0x1b3e3227, 0x30205fe7, 0xf3c497e8, - 0x6488543f, 0x91f9c24d, 0x99df04df, 0xb23f382c, 0xd8235711, 0x58e297cf, - 0xe09d755c, 0x9ff90f5a, 0xb8165d48, 0xffc3476f, 0xeadf278f, 0x8e2be892, - 0xc367ceeb, 0xc3ea959c, 0x8eaf20f3, 0xaf87e7c9, 0x0d741ec5, 0x8b737866, - 0x9aeffdba, 0x4eb282dc, 0x8788566e, 0x78ebda44, 0x1df7e705, 0xe60b9c42, - 0x05cb1d43, 0xe160a746, 0x7d2403e7, 0x43db869c, 0x27781c6d, 0xb7e9132e, - 0xbc18ff11, 0xb2e2cc1f, 0xfd1a3d00, 0x86a473e1, 0x73c69e73, 0xe15969a0, - 0xee3a4db8, 0xe0512d93, 0xbe722f8e, 0x97fe86d9, 0xdff4c1d7, 0x60fe8788, - 0x6e732e3c, 0x15abf292, 0xae5fdbe4, 0xdb7b0449, 0x0ee3ceff, 0x0f91af90, - 0xcc7f829d, 0xfadf5841, 0x9f731c83, 0xa5a69688, 0x7f05280d, 0x0d3d2d34, - 0xbd79ed53, 0x07198a5d, 0xeef5cd3c, 0x9eb5e31b, 0xc3f30c58, 0xb39fd0d3, - 0x73de779e, 0x6177baa3, 0x8e3ebc7c, 0xd15ebbf1, 0x8026a8f8, 0x5de7759e, - 0x927eec09, 0x90ff7644, 0x8373c993, 0x492a52cf, 0xd1b9ef91, 0xdc47e91f, - 0x1181e633, 0xad9320d8, 0xbf166b88, 0x5065ced1, 0x97e4c743, 0xb9fae8c8, - 0xec294c6f, 0xcc6d919f, 0x30dc5d2e, 0x254bdb1d, 0x5387580f, 0x312d2ebe, - 0x73ae20b9, 0x1c9fd176, 0x517c1470, 0xe02e6b46, 0x91e888fd, 0xd431e36d, - 0x65b7f38d, 0x88409573, 0x9ea52a42, 0x9726241a, 0xb8eeb819, 0xff7314d0, - 0xe6c6ddb3, 0x4e71cddf, 0x06d2d34c, 0x8d8d9697, 0x39440fcc, 0x7aa47869, - 0xae365e98, 0xc5309cfb, 0x6fb40a47, 0x994ea7d4, 0x40dd6104, 0x9c2987b3, - 0xd63d9aff, 0xf40521f4, 0x4b01d60c, 0xe4d47da8, 0x9abf8439, 0xfc4af18a, - 0xfd5f9a13, 0x8e03e602, 0xded00aeb, 0x8f5ffd51, 0xd98232fa, 0xd3d82b6f, - 0xe7653888, 0xc107f7de, 0xdf87dffa, 0xeb0f10bf, 0xba917f40, 0x9e7ec1e2, - 0x78ddffbc, 0xe1f43738, 0x715e2cfd, 0x351e6197, 0xfaecc6c1, 0x6c92b6a3, - 0xdf02d7e8, 0x227ae77f, 0xb3564970, 0x01e58d75, 0x5c9e70d1, 0x554f2f7f, - 0x9ee1b263, 0x5bd63f1e, 0x32e7efc5, 0xcb92a1ca, 0x4db6f961, 0xed0a864a, - 0x7eb6dc7b, 0xa08f6e70, 0x14d93cbd, 0x8d11f38f, 0xc6db459e, 0xfa773028, - 0xaf99b34b, 0x6ccab77f, 0xc317705c, 0xf387967a, 0xc1e748cd, 0x6fac367d, - 0xfed8cfc9, 0xadb48594, 0x7abed4d5, 0x0b79d99a, 0x7c963f63, 0xa7f616a8, - 0x90f25bc2, 0x7862f380, 0x4e3a7eff, 0x883f5679, 0x7ec65eeb, 0x31cdef1a, - 0xe6d55f9e, 0xfcb8cb53, 0xf50788cb, 0x6b5cea2f, 0x369f5b33, 0x1fceffc6, - 0xff61b2ca, 0x91fe3c6d, 0x79c0264b, 0x86871de8, 0x3eee5c24, 0x1efc33e5, - 0x1a57b826, 0x823e93d2, 0x654db669, 0xbf3464f7, 0xaae02f7d, 0xef1db83a, - 0xf6bafb19, 0x94f9aaa6, 0x6b30f603, 0x91fa8776, 0xa43f01ab, 0x97f9d04c, - 0x282e9bd5, 0xf8cbbe6c, 0x7e7f0770, 0x1b37f407, 0x3fab59f6, 0x7ce54c9a, - 0x317ca547, 0xbf321ef2, 0xa6ee7f4d, 0xfad5fdaf, 0x2b5bf5a9, 0xd1fbe2af, - 0xf869df8c, 0x2c78e6cf, 0x6eba52db, 0x9ad16500, 0xf30627bd, 0x4e7868f3, - 0x1197c347, 0x4948cb3f, 0x8110ba61, 0xb147e693, 0xcb3c9a5f, 0xfef216ea, - 0xbaf8d3fb, 0x8fc41a5e, 0x118dc37a, 0xdb721d1f, 0x2367d060, 0xb87a3a3e, - 0x3627e45f, 0xa99427e6, 0x678842ee, 0x9d763751, 0x394fc233, 0xbc1dd529, - 0x0b6cf40f, 0xf8c479c3, 0xd7b99ccb, 0x57cf1c65, 0xe1fdabc6, 0xdb943d3e, - 0x6017d844, 0x5a7bc3f6, 0xb73eed3b, 0x7c04a86b, 0xb4f4c22f, 0x7435c4af, - 0xd2f97768, 0xc0382e27, 0x411cee8f, 0x11d38e30, 0x77f7a7af, 0xf9e91136, - 0xa543971d, 0x3f8ffad4, 0xd2da8d83, 0xda1dfb8a, 0xa071e4bf, 0xb145cd2f, - 0xfe27f9fa, 0x86f7e11d, 0x4cf5c5dd, 0xe02c979b, 0x99abbb72, 0xda2f67ad, - 0x30f28a58, 0x437ad7ee, 0xd0661670, 0x638d3caa, 0x51bf9014, 0xdf5c4b3e, - 0x51607dc1, 0xf08f2272, 0xdc1e017d, 0x2f5653a7, 0x28c3dc62, 0x93bb7cbf, - 0x6b57a39d, 0x42b71e70, 0x790ebd8a, 0xb5f4dda5, 0xc7ec63fa, 0xed0126c2, - 0x65fe91a4, 0x0dd76a5b, 0xd67fd020, 0x847ee8bf, 0xe25da206, 0x55fad4fd, - 0xff785c46, 0x50fad440, 0x7224f5db, 0xe6f2f53f, 0xbf2fb8c5, 0xb09ff69a, - 0x85c61238, 0x7a35fa34, 0x1428fd8d, 0x8816c8cf, 0x5c16aee3, 0xefa39f60, - 0xeeeb7327, 0xb0d85c3f, 0xafc8207f, 0x66fb625d, 0xce02fddb, 0x203f3b0b, - 0xbd607d6c, 0x3d69eb80, 0xed99afca, 0x8e59ea07, 0xe7dc0a35, 0x8851b657, - 0xf565c729, 0x11a1aef9, 0x60796a76, 0x8ea86b86, 0x1fdc46de, 0x54a1a2b2, - 0x9d807cf7, 0xfdb893c7, 0x48df4dee, 0x38cc624d, 0x9a5fa693, 0x97fa69be, - 0x3cd9576f, 0xcc1c0a47, 0xfebb04c8, 0xa84bce18, 0xcedabe5d, 0xd1e607d7, - 0xb89faa57, 0x581f5ba0, 0xb3e4c792, 0xe7c62c44, 0xca57d93d, 0x1e7d9d07, - 0x7fefd767, 0xd1fdb6f8, 0x85e9a1fa, 0x5ea33fd6, 0xc5aff918, 0x30728cd5, - 0x82e81ff2, 0x7b1bc1f9, 0x0407816d, 0xa74677d0, 0xe915af7f, 0x702b48ec, - 0x3fc839c1, 0xce9407c0, 0x31dbf4ea, 0x9496235f, 0xc75e71da, 0xfae34de7, - 0xe1c83f16, 0xab4ed67e, 0x473b2c7b, 0xb80c9254, 0x36db5298, 0xf8a4e2d3, - 0x2174647c, 0xe53a2bdc, 0x1099b6b1, 0xc8f25efa, 0x5fb84298, 0xb6d6ca7e, - 0xea2e2d77, 0x2d8ed5d7, 0x57e5fb84, 0xf680dd80, 0x10db9607, 0x89e53d57, - 0x9579f2e7, 0x5cce3fbd, 0xcbdd9f32, 0x292bcacc, 0x3c742d8f, 0xfc3c3cab, - 0x959fa0f7, 0x1045c5ad, 0x8884a9b7, 0xaacf1d37, 0x2d908edc, 0x93e78d9b, - 0x6cdb7be8, 0xf076559e, 0xc5ad2eeb, 0xb0f2adf1, 0x0e44fa84, 0x44a8b8b1, - 0xdfa56afb, 0x7ea38dad, 0xdaefe52f, 0xe60b8b24, 0x1fb9f4af, 0x936bb5e6, - 0xf11aaadc, 0x7c1f935c, 0x35ac7407, 0xfdfb75b1, 0x684f0daf, 0xbf78ccbb, - 0xc32647df, 0x67c5a43c, 0x9e58d4c1, 0x7cf138af, 0xc589be44, 0xbfe58c35, - 0x512cecd2, 0xd5170033, 0xaf161487, 0x4fe07fa6, 0x17a61156, 0xeb9d84d5, - 0xf04c3aaa, 0xa1f54b1c, 0x02c73c42, 0xd63ffcfb, 0x735ff0e1, 0x571ba58e, - 0x92054f8c, 0xc08a5930, 0x55bb34f5, 0x9bfb1797, 0x887f4046, 0x7382e718, - 0xa9866218, 0xbfed0766, 0x294d0578, 0x4ba7243f, 0xea5afb84, 0xe1114ea6, - 0x3235a9be, 0x62623fdf, 0xf6b5cce7, 0xb47f389a, 0x64bdb4f4, 0xecfdc807, - 0x36b9ad5b, 0xf3817eb6, 0x6bbfad61, 0x60113704, 0xe08075de, 0x149c80f9, - 0xb3fc02d2, 0xe01e7711, 0x127b3ded, 0x375b37e7, 0x90197fa6, 0x97a6ccba, - 0x57f78a55, 0xfa84591f, 0xdd304ae0, 0x6ff34993, 0x7cb197d9, 0x2642e986, - 0xf6dbf085, 0xc6bf9672, 0xcd086174, 0xce5f6bbf, 0x49c0b0f2, 0xf623b607, - 0x48ff428a, 0x7de38768, 0xc01afb9b, 0xf16264b7, 0x0515e917, 0x7db453d7, - 0x44e96b21, 0x1ef8f00b, 0xa7884dd8, 0xdafc16d4, 0x02eaf106, 0x3dfb0ab7, - 0x837bf336, 0xf1aa69be, 0x7099b455, 0xf02903fe, 0x4fce43ff, 0xc9a42e4d, - 0x8bec0d7d, 0x6bee8d25, 0xb4ed1d60, 0xf606d3dd, 0xad1bec66, 0x377ec053, - 0x5ca7f3bd, 0x0afc9fbc, 0x37d8cf56, 0xf6909ce8, 0x066fece7, 0x8f5c8a6d, - 0xffcf6d3e, 0x62a3be14, 0x5054ff40, 0xaa0ee49d, 0x44dc6b87, 0xbe60b255, - 0x362f9fac, 0xb69f6611, 0x82ce4ad9, 0x10c0c95c, 0xf6455b8e, 0x6bc84e92, - 0x26b49cf6, 0x9b5f69f5, 0x845abd92, 0x23293971, 0xd8117478, 0x7bb1dfff, - 0x1bb7043d, 0x14be73f7, 0xed8cd7be, 0xfec1b10f, 0x177fd010, 0xf2a7f349, - 0x2f8b17f8, 0x88dc9493, 0x07ef3079, 0xec1a7efd, 0x63609f37, 0xbf6807fb, - 0x63abb044, 0x58e98a88, 0x81656788, 0xdf983d28, 0xde8f1a43, 0xdc7feb47, - 0x9649e2ca, 0x0f8ba206, 0x38b3c766, 0x8b074ccb, 0x8dc9c60f, 0x10ff82b7, - 0xc1388e77, 0xa5fce87f, 0x22fee122, 0xae2379c9, 0x11341d8f, 0x3959f7a0, - 0x99f584e0, 0x7524abae, 0xafaee933, 0xab5bcb93, 0xbd4571f7, 0x7372e20a, - 0x7d3fcc1d, 0x7ee09f36, 0x4a53aee8, 0x934dd600, 0x91352c32, 0xf92b9ff1, - 0x0b390f77, 0xfe21e332, 0x408e37bc, 0xc5f613fb, 0xbf0e4099, 0x056396de, - 0x3c04bc3c, 0x32487ca2, 0xfa86ef3b, 0x7a502e92, 0xdb39f133, 0x63a92f27, - 0x277f2812, 0xe15760dd, 0xad67a9be, 0x7ee0378d, 0x784c17d0, 0x8a4beebf, - 0x2ff214ab, 0x609d579d, 0x6ccd9f7f, 0xbcfec38c, 0xbcfec260, 0xf575d714, - 0xc3f74a4a, 0x4a7c5823, 0xec0911b2, 0x502a64b2, 0x73cfa6ef, 0x493cd9e3, - 0xe3cbd3b3, 0x2e3cfe99, 0x200f3c10, 0x7f51f299, 0x9d3afdb4, 0xebf7045d, - 0x2ad59bf4, 0x4ae38e02, 0x4851b8b5, 0xe4cf7884, 0xdb7e8212, 0xe78cbb64, - 0x307f6072, 0xc29b1b9c, 0x0f94efed, 0x813d712a, 0xdc30e04a, 0xe762d97f, - 0x75f168f7, 0x4e39ebc5, 0x226d23ae, 0x5dd791f8, 0x07882e22, 0x8a497f5d, - 0xe74e47e9, 0x10233ef5, 0x97be8129, 0x0095517f, 0xef44f977, 0x2faf4de7, - 0xe0e3053c, 0x39e18b54, 0x8f4889f8, 0x4ff7cf1b, 0x4fee1a77, 0xd6f3e78e, - 0xe47064c1, 0x1d6d313e, 0xf238ba68, 0x8b53f409, 0x65f01714, 0x3efdddbb, - 0x5bfa7bac, 0x38b97265, 0xb63e33e2, 0xa5c46f9f, 0xa1ff5c38, 0x2e03b4f8, - 0xf3afaeae, 0xafbf695b, 0x07eaca1e, 0xb95d821c, 0xc92997f2, 0xf1cde760, - 0xa968decc, 0x97c03b86, 0xcbe18133, 0x3f5bba39, 0xe267c557, 0x01be9a7b, - 0x3d9ea0ee, 0xac7e6072, 0xd78a6575, 0xedd78055, 0xb3f38276, 0xe65ba51f, - 0xed699e82, 0xf86789ec, 0x6aeba637, 0x7587ee57, 0x6c67ff1d, 0xe03698bc, - 0xde391292, 0x3864e87f, 0x3375aaf3, 0xf3fda66f, 0xbf5c65da, 0x8be7e549, - 0x1e92f122, 0x770d1781, 0xef16761d, 0x7533f0d1, 0x3c22bbf7, 0x2119fa9f, - 0x9e124cce, 0x99f86887, 0x9c3867e2, 0x138d8872, 0xddc7e1bd, 0xe6069ce5, - 0x87370a31, 0x280a6e18, 0xb7f7f03e, 0x118fc07a, 0x8af54f37, 0x3cf12f9b, - 0x53bdaafc, 0x186ebb2f, 0x7df7e9f4, 0xb689d31a, 0x8f82fbd8, 0x56ef7e72, - 0x06cc6eea, 0x8993717b, 0x48937f9d, 0xe714adc6, 0x7bb4e3bb, 0x20b26be5, - 0xf6625dbf, 0x19b37b67, 0xbb76cfed, 0xd77183c7, 0xcb9e0b34, 0x0da79226, - 0x06bbf5f6, 0xdfc8d458, 0xc72ef8d1, 0x9a1ca361, 0xeffc0278, 0xf3fc98d7, - 0x1b81ca6e, 0x197a48ec, 0x93b8c393, 0xe21126ca, 0xfdfc8e42, 0xe04faf80, - 0xc3c02d4e, 0x25ef0571, 0xa0ae3eaa, 0xbecdfc5d, 0xbe210bb7, 0x9e1feda9, - 0xc2ede7b0, 0x3ef09182, 0xdc6bd9c3, 0x3c796aae, 0xd276014a, 0xc4fd2f70, - 0xfd2679f0, 0x8025f2bd, 0x72eeec9f, 0x73eb7de3, 0x1d1784e0, 0x736d6e77, - 0x60b3074d, 0x4e7d6fbc, 0x9b1f9d88, 0x1d3dd47d, 0x7dd4654c, 0xb70f1ceb, - 0x715dd691, 0xdffdf462, 0x163e7c74, 0xd7fbf10f, 0xc1c40a43, 0x6b9a951b, - 0x26a27cd8, 0xa68fec0b, 0xf947f877, 0x08e1f8d6, 0xc3ff7ddd, 0x88f3f8f8, - 0x38f7624b, 0x4eb829b5, 0xdf6128f8, 0xeb71f235, 0x39f7ae2b, 0x0f9c5eab, - 0xb96c70f6, 0x576dd71b, 0xfe7c4539, 0x64b21213, 0x125cbc81, 0xca3477ae, - 0x4213d4ea, 0x2a447bf7, 0xe5a76119, 0x8dc5fa7b, 0x70eff685, 0xf00e4c78, - 0x43aea42b, 0x4984ddf0, 0x6ec16339, 0x4dacc7db, 0xa34c7186, 0xb455d29b, - 0x874dded5, 0xc7275746, 0x858e1dc9, 0xf678c726, 0xe0a1d81d, 0x7c0b76b1, - 0x71a0e1af, 0xff2639ef, 0xfc803c08, 0x2c20f1bb, 0x07c6bc80, 0xfcb54f1b, - 0xa10f1f3f, 0x1e9f2081, 0x087100f1, 0x43c2b7c7, 0xc355f016, 0xaed7f503, - 0xfe68fe02, 0xf6c2a35a, 0x0d796a1d, 0x7cf64507, 0x10a5cf7c, 0xf6443fdc, - 0x6d39d959, 0x57ae224f, 0x6d64ecbc, 0x3ed87e74, 0x6498ba98, 0xebf983b2, - 0x8c89efda, 0x57e80909, 0xe106a18e, 0x06e3f40e, 0x71743da2, 0x4176917e, - 0x71377b80, 0xf806796f, 0xd064a197, 0xe2e6318b, 0x877fe010, 0xf8064a6d, - 0xc9b63987, 0x5daf8059, 0x0ebd5623, 0x01aed643, 0x516f2fe5, 0xcd27fdbb, - 0x6af0b5ee, 0x746ff6b5, 0xbd74fb30, 0x020f9d9b, 0x87491dbb, 0x2c41ff66, - 0x9a108740, 0x86cafa63, 0x0db9baf6, 0x41d039ec, 0x205fbaf9, 0xe41fe04d, - 0x5329dc9b, 0x17ebcfc1, 0xcece8092, 0x860c5fbd, 0xf3716538, 0xde8147ab, - 0xd43d6d62, 0x350f5fa5, 0xbf9ad1fa, 0x342bcda3, 0xcf9b487f, 0xe504df82, - 0xd3b9fcd9, 0x26add6cc, 0x6e782c87, 0xeaf3f1f9, 0xbfae6e55, 0x3147ed12, - 0xa42dc7ef, 0xeed2e915, 0xf399b91d, 0x9d10f8a3, 0x39436687, 0x3e513721, - 0x1defc4dc, 0xbfa5c9b9, 0xbc96e157, 0x688ef7d8, 0xbef6f4f5, 0xd6b87c71, - 0x6df46eb0, 0x763e43d3, 0xfa7fc8cf, 0xd2773cd8, 0xc12fd110, 0xce979a80, - 0x327069ee, 0x62521c3e, 0xb9fb578f, 0xb5324efe, 0xe5b9c365, 0x8efe7bfd, - 0x7b2be3e3, 0xf81efefe, 0x494f1389, 0x4eb5f604, 0x012e353a, 0xd2f3e7d7, - 0xab593d70, 0x9369fbd7, 0x88e7b08d, 0x5777ed1f, 0xdc7a520e, 0xc167d00a, - 0x1e67b7f4, 0x77d429ff, 0x2244b8f1, 0x2a144dcf, 0xc710a19e, 0xbfbfe42d, - 0xfe605073, 0x907e5692, 0xf3c5eeff, 0x21b0b71c, 0xc48fbb42, 0x9be7211c, - 0x9a193df8, 0x593a6f5c, 0x8eca4a74, 0xfdfc0f96, 0x5a0be233, 0xf399a15c, - 0x11fcb48f, 0xa77cb7cf, 0xfc096ee9, 0x89a4eff3, 0xeed11dc4, 0xe0ce950c, - 0x2f1ce223, 0x4a7e0c3b, 0xbd3f73cb, 0xde2b8e99, 0x4adc4437, 0xfede6de8, - 0x5be4367a, 0x8ff798c5, 0x9dfbf918, 0xfef1bbe6, 0x2a092191, 0xfb5bd3d2, - 0x38a6ae93, 0x27720d19, 0x65cbcfcc, 0xe51877f7, 0xff9ecafb, 0xd91b6e48, - 0x927bbf33, 0xbf0e51bf, 0xeb80533d, 0xc3c9bd4e, 0xb47ddb88, 0xbfda7e9f, - 0x9fa7ed10, 0xf8af63fa, 0xbdff989c, 0x1af30d2f, 0x9f7bbd5e, 0x4e7f064e, - 0x64f4e9c3, 0xbb899b86, 0xec4c9a7f, 0xf232f2dd, 0xf30773ed, 0xd710e66b, - 0x3fe99bec, 0x78ae0a77, 0xd27e17b4, 0x4ab3fb0a, 0x0e738d38, 0x41ffa217, - 0xe31079f8, 0x1c473638, 0x7bdee789, 0xa19bddfd, 0x5b9832f9, 0xbf0578e3, - 0x36b802c7, 0x6f45538e, 0xb2e049d4, 0x98ab4a15, 0xba7ee31d, 0xce519746, - 0xf6094847, 0x8d3a27a3, 0xabd23038, 0xefdae7f9, 0x4c7e50c0, 0xddf5a24f, - 0xff63e6aa, 0xce61c6a2, 0xdfc69e97, 0x9c95fa9e, 0x1cdee3c0, 0x4e4e17ff, - 0xdbd80b7b, 0xe519be93, 0xecd72c66, 0x90342147, 0xfc1fa983, 0xa9092191, - 0x97850fa8, 0xe3a6e214, 0x3fa8190c, 0xaf8a4eff, 0xe3ddbc40, 0xc27acf64, - 0x1325f55b, 0xe37724f1, 0x663e0e4e, 0x96eddc03, 0x1f106cea, 0xba5ecebd, - 0xda6f5406, 0xf0b305a7, 0x1336879e, 0xf4d99081, 0x102d73e6, 0x251ef047, - 0xa0a03e78, 0xc054ff79, 0x56a5efe9, 0x5e75479c, 0x08b1e424, 0xbcd8333f, - 0x587e06c6, 0x6f9d8530, 0x7448983b, 0x27f790fb, 0x8f06bc30, 0x1dd9bf9f, - 0x2f12fca3, 0x29dc499f, 0xc72e38d9, 0x70a3fc63, 0x3ffb09bd, 0x481d704d, - 0x9e65bf01, 0xce85f380, 0xa40e13bd, 0xee3b7a50, 0x333b444c, 0xdde0f83d, - 0xc6882a4e, 0xcf8b1eff, 0x780a16bb, 0xeaa140cf, 0x59617cc2, 0x98dfee26, - 0x99e48ff0, 0x433e50c5, 0x74cdf9c6, 0x788252b1, 0x2134d9d4, 0x7b8be607, - 0xf85ab684, 0x297f5c1d, 0xfd38876b, 0x7cff30c9, 0x0c7938a7, 0xaa9c76fe, - 0xefe187e5, 0x3cc31203, 0x0bced56d, 0x7cb4cdfb, 0xf7016cd5, 0x66774eef, - 0x7e047f10, 0x7953d70a, 0x6cb8a58e, 0xb8005fee, 0x3fa4599e, 0xc4bb3837, - 0xeb910246, 0xef138216, 0xf7c83b21, 0xfc097769, 0xe7ae7c5e, 0xcfbc7037, - 0xfbac9b99, 0x3f3094ae, 0x6453bbd3, 0xb3e471f7, 0xf4d6a1df, 0x87ae46eb, - 0xf1f9f037, 0x8e864f3c, 0xd288628e, 0x5b3f4088, 0x62e5be47, 0xa5cf0e1b, - 0xe78707e2, 0x1c6ef6d3, 0x8ad79861, 0x17116b95, 0x6f1d6c69, 0x1382ec36, - 0xdfea6ec1, 0x9f4f25bb, 0x97c7a18f, 0x3d9a13b5, 0xc457bd98, 0xf9d9c375, - 0x8902cf94, 0xaebfd3f2, 0x726098bd, 0xd078801d, 0x78dc97ad, 0xbd944e8f, - 0x1be8a0f8, 0x50df8bd9, 0x7aa3cc1d, 0x1f0264fd, 0x41910737, 0x8ba63760, - 0x380a7edb, 0xa6e3a4ea, 0xb48e0639, 0xef9b4771, 0x063d5217, 0x6c3390dc, - 0xa5fa659d, 0xa4efdc34, 0x76c3f7cd, 0xae25fa84, 0x6fd2fe18, 0xf774b212, - 0x4aed847a, 0xe7225f84, 0x64bf7b7e, 0x9547f53a, 0x206fa01c, 0x7b458ff1, - 0x42c97186, 0xf10518d8, 0x1873b4c1, 0x744af1e7, 0xf3e38afe, 0xb02f88d3, - 0xb752427f, 0x15fd187e, 0xd63cce2d, 0x7a53f9a9, 0x8de3849c, 0xa57dd8b3, - 0x810a4e1a, 0xb3ffa09f, 0xf4eb8c44, 0xfdad1b86, 0xa212f0de, 0x564c08f6, - 0xfae1788f, 0xf2f175f7, 0x197c6d17, 0x05f6864a, 0x343e1a27, 0x9bc718bc, - 0x83c434ff, 0xba6f1a7a, 0x0e6f197a, 0xaed1908c, 0x7cd7e6f7, 0xeaf3e4ea, - 0x37a62704, 0x7f1b355c, 0xd82c6897, 0xf937f011, 0x6b8e15b8, 0x1c9c33d5, - 0xc1245b68, 0xec1791fa, 0x1cb76647, 0xfff078b4, 0x81c4c600, 0x008000d5, - 0x00000000, 0x00088b1f, 0x00000000, 0x7cbdff00, 0xd5547c0b, 0x67b7efb9, - 0x332479ef, 0x49926649, 0x1d843c32, 0x09212108, 0x11bc210e, 0x11084937, - 0x88a80ca2, 0x1f01d68f, 0x4d092060, 0x6f53d5ad, 0x52812133, 0xbd583d6c, - 0xf4f47bd6, 0x41ed5837, 0x0108750d, 0x26702783, 0xd0f098a0, 0x7ac0f820, - 0x452968da, 0x5a18921b, 0xf5cf6a0f, 0xf6b7df7c, 0x8326664e, 0x73def7a5, - 0xd62e9f87, 0xf5af6b5e, 0x5ff9efad, 0x4a9b5adf, 0x500a9fc0, 0x982015b3, - 0xe1f95006, 0x06484a86, 0x01203be8, 0x96d40314, 0xfe1b41c9, 0xb1fdb4b5, - 0x0cdd45c7, 0x51df8956, 0xf5c02661, 0x950b7e20, 0x06e6c50e, 0xbc95e658, - 0xd6801672, 0xe1bfde2e, 0x62a82592, 0xf9af7afd, 0xe89b1ee3, 0x5fff35fb, - 0xb800c803, 0x197f7f51, 0x2ffb0ffd, 0x1860a4d3, 0x3b365d5f, 0x978dffba, - 0xa6913fca, 0x62d72c02, 0x3e4fc39e, 0x22f2a793, 0xac24becc, 0x8fb74457, - 0xcfb92673, 0xe32ff1d9, 0x32d7fc61, 0x65f3c5c0, 0xaff7516f, 0xc8ed77e9, - 0x523d48f2, 0xace80166, 0xdb1971b7, 0x7f016e5e, 0x4d2581c8, 0x0065c450, - 0x9d0a0152, 0x581998b8, 0x0d0164bf, 0x136308f9, 0x3ab9f7e0, 0xdf86131d, - 0x07e3883f, 0x8e30dc70, 0x3801c81f, 0xfae4ef54, 0xae1ef56b, 0x2f82935f, - 0x877fe3a4, 0xb8a8b0bf, 0xdfedc59e, 0xdf38fc51, 0x8f0a4be2, 0x93d69b3b, - 0x71830b4f, 0xf73f9eb4, 0x0de3fd16, 0xb6bfdc30, 0xbf8b33fd, 0xf9ebf2f0, - 0xa7e7f35b, 0xcd3f3ca8, 0xcf0c15ab, 0x180144bb, 0x9a5ceb83, 0x635fcd1b, - 0xc6f9589e, 0xfeb96fca, 0x56fcac7e, 0x90c7acc4, 0x32a2f40f, 0xffc38a8d, - 0xa6d0264b, 0x437e5e5f, 0xb3f8b1f2, 0xdb2305bd, 0x72c97e01, 0x974f1e1a, - 0xbe2b7417, 0x19974142, 0xb752baf5, 0x40efd40b, 0xb2b9ca0a, 0x4889c213, - 0x2be7f5d8, 0xf4a8513e, 0x9471f04a, 0x6c7c033e, 0x1e1e5bc8, 0xe425d17f, - 0xbcf0da6b, 0x7764148b, 0x0b1f3d11, 0xa8eb3881, 0xea1471a1, 0x6c39601f, - 0x155a61d9, 0x635c75c2, 0x547d3b81, 0xe0328a26, 0x937db894, 0xf6e3c4d3, - 0x8266c5ff, 0x3e5e01ab, 0x48025998, 0x3cead79f, 0x42011306, 0xbff7e066, - 0xdfb9524e, 0x240824e6, 0x74a0fce0, 0x945ec8db, 0xb45c8012, 0x25b4653b, - 0x364388d8, 0xd91f612b, 0x8157bf61, 0x2fdbb406, 0x050ef78d, 0xc914076e, - 0x4c738fe6, 0x7ef4598d, 0xf61e7bb8, 0xa8a4559b, 0xcb8bb0db, 0xda877eaa, - 0x9d580efb, 0xfeff5ef4, 0x699877ef, 0x1780bf9c, 0x0ed78429, 0xe7da8158, - 0xf241cc3b, 0xe3e48b1f, 0xfdeb09b2, 0xec560003, 0xb8557f3f, 0xd76e5014, - 0x13a37740, 0xc724b9cb, 0x8d7bf238, 0xfece9bd6, 0xe50a31c3, 0xd39740b4, - 0x956fdd02, 0x8fd9901e, 0x41c92694, 0x53f61ac8, 0x5a32ead7, 0x3a256c80, - 0x7ae1b416, 0x4bdafdb1, 0xb4bf5c4a, 0xe1771f48, 0x9321419f, 0x7ad1085c, - 0xf84da8bb, 0x14d012a3, 0x6d4b29c0, 0x97e4ed31, 0xce459e90, 0xc973e7e8, - 0xef5ea277, 0xf84bf18e, 0xf7bcd133, 0x8bbcc53b, 0xf726bfe4, 0xb65ffae0, - 0x43cdef68, 0x9a4e077a, 0x0e7c59e1, 0x6732b1e7, 0xd0da5f24, 0x973983ae, - 0x07fd8bb7, 0xe9153513, 0xc7f49979, 0x9ad1f541, 0xfdf2f53a, 0x940cf6a7, - 0xb9787760, 0x13028579, 0x7b4f1d58, 0x3df98632, 0xff3aaf82, 0x22d9f963, - 0xf91d9341, 0x5bddb0bc, 0x0465ae46, 0x8f913b1f, 0x80c95ef8, 0x295cf3c6, - 0x78fb0d1f, 0x46a25cf9, 0xb9f2fefa, 0xffcd1ad1, 0xfa6be92a, 0x3feffeb0, - 0xfe48983b, 0x2aa8f913, 0x2e0317a8, 0xd659f79b, 0xa1f7a15f, 0x6dc13951, - 0xf5d16f58, 0x81c4e5fc, 0xefc4f9a3, 0x67de4deb, 0xe3651a69, 0xe48515c4, - 0x9c96b737, 0x0d2477c5, 0x7ed107a4, 0x7709d524, 0xfb401960, 0xa40b7d21, - 0x1993eb02, 0x36f34042, 0x9534f06a, 0x29abe60b, 0x1c41efc4, 0xe341dbb3, - 0xe7a429a9, 0x338bd7f0, 0xf923857d, 0x0a8f52de, 0xd6b4f385, 0x1b2534db, - 0x93bd5f60, 0x1ef56deb, 0x57ad5f2e, 0x2c74dcb9, 0x8e20c1f9, 0x3459ab53, - 0x7df86d25, 0x8fb0aa57, 0x8867e805, 0x052005ae, 0x0b73a803, 0x5ef5d61e, - 0x249b8291, 0x27ae1392, 0x97289f82, 0x08dc9ec1, 0x4d2936fe, 0x35b26693, - 0xf28bbcb0, 0x063efc4d, 0x59f3e0ff, 0xdca3fb23, 0x4baaeaa3, 0xbae67e62, - 0x961724b4, 0x52f8743f, 0x6e916ca8, 0xb8017c39, 0x5bf512ee, 0xfe380be5, - 0x7842f0f4, 0x74c3e310, 0x15f10c14, 0xfd13b77f, 0x402c3a33, 0xca80c1f2, - 0xd3a45976, 0x492e7da3, 0x323e70e7, 0xe0c7af9d, 0x30cad67b, 0xe83ed1e9, - 0x17be2349, 0xb4767cdb, 0xc843a428, 0xf66e9355, 0x9cde3848, 0x26578b74, - 0xa6fa26d2, 0x75fe446f, 0xd884e3a4, 0x6323a3bf, 0xa6f68aac, 0x4fbc6f29, - 0x1cd9ad76, 0xcc2b8161, 0x71113dbd, 0x719e133c, 0x9f22bc52, 0xbdf235f6, - 0x01c977f3, 0x73886bf6, 0x9e758fc8, 0x7186f64a, 0xd92e6b9e, 0x7fd256bc, - 0xf5ed117a, 0x54f26260, 0x5dd0cff2, 0xd6b8ebc6, 0x6f91d626, 0xd8bb17f6, - 0x9f0f859f, 0x6dfef7c0, 0xe9fc8010, 0xca1fdd35, 0x9a94f480, 0x907b32f2, - 0xe4d2c3ce, 0xfc9f2a14, 0x9701725d, 0x897b92a7, 0x764d073f, 0xa77de695, - 0x46ce2d5e, 0x72ded17d, 0xd61d0098, 0x0a1cb782, 0xa1ea2795, 0xe5f51b38, - 0x971b7aad, 0x5c9deb27, 0x70f7aa9e, 0x49db1879, 0x76c75e9f, 0xb037b7d2, - 0xd85dea9d, 0x1c31e54e, 0xdba2ca97, 0x96bc7893, 0xb42c92db, 0xd0c9838e, - 0xfa4fcc6c, 0xb70c4e14, 0x3fe01782, 0xab6afb1e, 0x978c2aed, 0x34a17f56, - 0xb3f4f90d, 0xac142aaf, 0xee3c5b1f, 0xbb60bfa1, 0x1fa667f9, 0x9bde90db, - 0x8f5a394e, 0xaa9edd63, 0xfa41d8fc, 0x9d112c79, 0xb9b59923, 0xa63a434b, - 0xcd1c6f93, 0x3660d76c, 0x7af4d3d6, 0xd95d7cc0, 0xa595807c, 0x42e0f93d, - 0xaf597125, 0x577f21b3, 0xa3dffdda, 0xabb025ba, 0xaa2aeca2, 0x7b248863, - 0xb641cc97, 0x7b92b1f7, 0x95bbc605, 0x127fff0e, 0xd17b0dbf, 0x91a43fa4, - 0x49a9987f, 0xbcb372e0, 0xe1a49383, 0x95bf46e7, 0x49ff458e, 0x25debafa, - 0x98cd7db3, 0xc741692f, 0xfa35fb48, 0x96ab38cd, 0x9e66fc91, 0x72a26f2f, - 0xeb8b8559, 0x9ab355be, 0x1ccbfec8, 0x94bf7b97, 0x65d07fdf, 0x512dbd66, - 0x389c5fb0, 0x8e9bf468, 0x7bb8464a, 0xf8312ba0, 0x69f5e92c, 0xd612637f, - 0x8ab27917, 0x0337dd64, 0xb63b5dd7, 0xebe57b51, 0xde576cad, 0xf2e12f24, - 0x6990a899, 0x21d0bed8, 0x2a64c379, 0x4a6a3ff3, 0xe4a776a3, 0xd42db625, - 0xa6289da6, 0xbbd96cf6, 0xd5a7ea90, 0xa7510a32, 0x2ef38594, 0xb9c5bf60, - 0xbe1b5e29, 0xd0fc2a77, 0x85dfd245, 0x04de49b9, 0xf04af3f2, 0x7baa1ae9, - 0x9506dead, 0x6958f1d6, 0x4aa38d32, 0x5bd6135e, 0x1ffd286e, 0x2f894744, - 0xda892405, 0xd7e10a5d, 0xc3f77f27, 0x6bf62732, 0xd9012719, 0xde70a9cf, - 0x85fe889f, 0x026a899d, 0xb38b69f9, 0xb16bde8c, 0x5c4dce48, 0xff5295f7, - 0x7d598e40, 0x7e3dc71e, 0x41e39d9b, 0x8c055be5, 0x36df8e83, 0xe542e386, - 0xa84bf35b, 0x78126e3c, 0xcaadf2bd, 0x41376e0a, 0xe54a9c98, 0xf7e2dfed, - 0xb0fe97b6, 0x1fe38dcc, 0xdf62ef1b, 0x562a7282, 0xf624fc22, 0xbfde8907, - 0x77fb9abd, 0x9d0f9948, 0x0b17fec5, 0x38ac8a52, 0x213bb97f, 0x58c57faa, - 0x497d5457, 0x2562a8f6, 0x16564fc2, 0x6fd54564, 0xb38a9628, 0xe6fbfa23, - 0x57d54427, 0xb38ab994, 0x54dffa23, 0xbeaa2a39, 0xa8aca6f2, 0x1cd342fa, - 0x61ea3fe1, 0xf3b0997e, 0x20d965f9, 0xa9fc898c, 0x037df453, 0x3b26efdb, - 0xa9f812ef, 0x09f885c8, 0x55d652e5, 0xd8b971cc, 0x00affbae, 0x92667b74, - 0x2ebf17ff, 0x83de8f1c, 0x4999fe20, 0x16fc4878, 0x201e2376, 0xdc60a47c, - 0xcca7a08e, 0x2bc71d11, 0xff27cd40, 0x84b9d15b, 0x67b954f1, 0x319a1979, - 0xbdfa31f2, 0x8161f90a, 0x2ee86243, 0xa5c732ea, 0xf46c62b7, 0xabae06fb, - 0x316be9d0, 0x09529bf9, 0x6eb4058b, 0x7ac635c2, 0xb72e3a0c, 0x8ef90a9e, - 0xdfff1432, 0xfd2c575c, 0x7f791b00, 0xa0d74b11, 0x8881c74b, 0x760718a7, - 0xc43e32a6, 0x3e1e3b9f, 0x254f7030, 0xa45737fa, 0xee48737f, 0xf79785e5, - 0x97b8c66f, 0xb8c67bc3, 0x2cd0fbc6, 0xfbc6fcf3, 0x2955cf43, 0xd89df3fe, - 0x73ce293f, 0xf9ff14b7, 0x17fdd173, 0x03a36a28, 0x4828f8ed, 0xfbf100de, - 0x2410aab8, 0x35ad3d2b, 0x43e8b951, 0x747842bf, 0x1340d9f1, 0x837af395, - 0xfeb8adc7, 0x956572eb, 0x1e060df2, 0x8cd75d8a, 0x3a4fb154, 0xabb5497a, - 0x5012ded8, 0x68bfb4ed, 0xd3b55879, 0x8345aa3e, 0x6a2fda0a, 0x691b4d13, - 0x63e5a1bf, 0x549cf589, 0x52f3e7e1, 0xca318e05, 0x5e7f6567, 0xb6d5962a, - 0x8b09479e, 0x60317cd4, 0x94703021, 0x48c15e70, 0x0954779c, 0xa3be683a, - 0xbe1d070f, 0xa57e3f08, 0x29146f38, 0xa7e93a5b, 0x91fa45a4, 0x16825b52, - 0x391637e9, 0xaff5515d, 0xc7d8aa9c, 0xbd45467b, 0x159a9d77, 0x6bf10fd5, - 0x46a0e12e, 0xe42ae40b, 0x5e894d47, 0x7cb177c2, 0xfd7d17fc, 0xe093875e, - 0xaadd9813, 0x97138fec, 0x7f82a5bc, 0xa457cfb1, 0x6fea7d8a, 0x6e583d68, - 0x35f4154f, 0xe2013ec9, 0x3e933710, 0x4f71d6c4, 0xc3c68aba, 0x77a43d91, - 0x22e9bb5e, 0x4ef86f42, 0x29d7d5ea, 0xe9decfa8, 0xc44eefa6, 0x8ba923fa, - 0x699e7d44, 0xffac04cf, 0xd45cb534, 0x374d36af, 0x057e017b, 0xc32baf8b, - 0xe7dbba7a, 0xfb79c54f, 0x12ad8ecd, 0x24c519e2, 0x787b9141, 0x0588fbff, - 0x160a29e3, 0x21734c95, 0xd8ab76ad, 0xa024d72f, 0x25fea3ff, 0xaafc4a9a, - 0xdce43049, 0x1d714193, 0x9134ceee, 0x6ff630bf, 0x87be0b76, 0xfcd8e7ef, - 0xc25f42b5, 0xa5fa2ac9, 0xca2ff7fb, 0x9ed8bd24, 0xe7f5e4ea, 0x21e799ef, - 0x7d74857f, 0x7ffdfa97, 0x3c536ba4, 0x62cc9aba, 0xfc96de9e, 0xf9bb8a52, - 0xd21c51e3, 0xbb70bcb0, 0x4213cfcf, 0xcb8c2ba8, 0xf5848f35, 0x4bc59746, - 0x90fb7d38, 0x6cacaf7c, 0xb213f3d4, 0x9c8de85d, 0x1bb8da62, 0xfaeb9fcb, - 0x3bcd14f2, 0x1819e683, 0x01f51cb7, 0x56e3039c, 0xe93a8a14, 0x0d172c83, - 0xf81ede10, 0xf7979256, 0x7e0763c7, 0xbfac03fb, 0x97be4777, 0x8907f470, - 0x82ab3f82, 0xb07b1a13, 0xbc1acd3e, 0x3e748c2a, 0x967fe694, 0x6b36e0f4, - 0x9beb1270, 0x8d126363, 0xfbc0692f, 0x877f6310, 0x32d538fb, 0x1fee2471, - 0x88d82f39, 0x11ccb7cf, 0x45e6367c, 0xee28da9e, 0x3c5b37bc, 0xf9c0e837, - 0x06ff885b, 0xc074433d, 0x03c72758, 0x45a47910, 0x61e443b2, 0xbce260ff, - 0x1f192d49, 0x359cf7d6, 0xcfaebef1, 0xe68057d8, 0x9b933d58, 0x27399e78, - 0x6c4cc936, 0xd4ccff00, 0xb6af4859, 0xfa7de7ad, 0x7de8ee8c, 0x7f4eacfa, - 0x9bdf03a9, 0x7cfc7ef5, 0xdc7d3cc8, 0x299410d9, 0x89e9cf5e, 0xdf4f37ee, - 0x1f3bcfa7, 0x54cdfcfd, 0x868dbe3d, 0x8e7991d1, 0x33ff7d3a, 0x0a427c78, - 0x3af929e9, 0x516ef919, 0x3a9d9865, 0xeb5a37ec, 0xf90e5fb1, 0x85971b47, - 0x11779da7, 0xa8f56dfd, 0x93f216d0, 0x7b0d2e1e, 0x770d3c2a, 0x7988d4c2, - 0xf837bd74, 0xe0bef838, 0xdc9eb4e3, 0xbac7cf9f, 0x410cd3b9, 0x739d7875, - 0x820d3e75, 0xd3a0f3e0, 0xd99e7cc2, 0x61e9cbf5, 0x98f5647c, 0x5f588d40, - 0x6a089a82, 0xe7b53f84, 0x65d546a6, 0xce3a3e43, 0x9f8fae98, 0x351d1de4, - 0x0c37818e, 0x5a9abdf9, 0x643849de, 0xe31d63ba, 0x13d9948e, 0x3e2dc6a2, - 0x64272b1e, 0x2476e11c, 0xd7089ff2, 0x70a2569f, 0x80772cc6, 0x3fb30038, - 0xc9706254, 0x68ec9976, 0xe7e8d9ee, 0xc8cbb4e6, 0x84fc72ed, 0xef9f3fa9, - 0xe9f9fbfe, 0x99f9a2d2, 0xcfcd1156, 0x3f345f74, 0xf3455733, 0x9a3f946d, - 0x4dd6632f, 0x6abf6a89, 0x7d545163, 0xa37383fc, 0x006167fa, 0xdc4fac8c, - 0xffaa24ba, 0xa22beda4, 0xba9f93ea, 0x5e7faa2d, 0x7b544d70, 0x2baacefe, - 0xa8617f92, 0xb11faa2e, 0xf20df4d7, 0x1fedbabf, 0xeff9e6a2, 0x34a2ff96, - 0xcbaf2f3d, 0x438e997f, 0xc7fa1a5c, 0x4538e1a2, 0x93f215e9, 0xbe37f6ae, - 0xa04bfca0, 0x53bce544, 0x1b780960, 0xd909edb1, 0x1b5f9127, 0xa136ac83, - 0xc13268df, 0x8ff7f23a, 0x879c4c9a, 0x2abcec34, 0xaa8be04d, 0x9ff7e134, - 0xf8a69b46, 0xeccff066, 0x78449ede, 0xa0993643, 0xe29ae29b, 0xc671bf65, - 0x716be101, 0x7034793e, 0x7934ab5e, 0xa899b2f6, 0x329bf287, 0xd1e51fef, - 0x7d71507e, 0x3f1fc78d, 0x8b9ff941, 0xfa4a9b0e, 0x03faa72a, 0x7d70b714, - 0x2461e7a1, 0x3eaf795e, 0x49f6893c, 0x67957d46, 0xbfea66e3, 0x93858eea, - 0xf43aff68, 0x498e8efc, 0x88721165, 0x388adf5c, 0x697be8f8, 0xc4673f22, - 0x6aacdb87, 0x6bca0f63, 0x3ffc2c9a, 0xa5ef85c6, 0x903ffae1, 0x9c0b361e, - 0xbad33015, 0xde724e31, 0xba8085df, 0xe194cb0e, 0x8d7ea478, 0x84c1f54a, - 0x26f9dc68, 0x08fb4411, 0xffc72a5b, 0xbb7f0d5b, 0x36f98f2e, 0x3fee88e8, - 0xc144f778, 0xd7236fcf, 0x2c67df90, 0xdd061d62, 0xfc3f75e7, 0x7b87eea9, - 0xe446ffc9, 0x78edd79b, 0xf5f0893c, 0xa7815c99, 0xe8cfe78d, 0x4d267d72, - 0x3bf5e9e0, 0x79919c13, 0x2b90eac7, 0x36db5eaa, 0x423679ca, 0xeb1bd70f, - 0xad0a4bf0, 0x3f6e8363, 0xc93d9dd5, 0xf1e301b7, 0xdc70d3a7, 0xbf171d9a, - 0x37de8fbd, 0x3888640d, 0x6ef9e01a, 0xd7180f79, 0x4415f2df, 0xd297d2e1, - 0x25e57e44, 0x95cb0ba2, 0xdf513858, 0x776c6256, 0xfcc6f951, 0x7c3bb272, - 0xbeb0961e, 0x84cc13ac, 0xb3fb96d3, 0x53f4c4cc, 0x2f677de0, 0x9a5f6d2e, - 0x04dcf3ca, 0xc5c5333e, 0x9d5dbf77, 0xc686fd44, 0x4319c633, 0x2bd459b9, - 0x419cc057, 0x246b9af9, 0x9f380dc6, 0xeefb9e8d, 0xe299b318, 0xbbdf31af, - 0x0ef0bfe0, 0xf00ac5ea, 0xf8c6b8f2, 0x7e51a900, 0x90cb03f8, 0xbf24ed1c, - 0x98532eba, 0x677539f2, 0xd1fe7cac, 0xebf030df, 0xdfce9007, 0x57b17d55, - 0xbb7fba42, 0xfb57e07a, 0x4fadf9f0, 0xb5c5dfa1, 0x87fddb66, 0xc3ce22d3, - 0x917ddcce, 0xc8f10ced, 0x33924ff3, 0x25eac97a, 0xeaa0f8fb, 0xbc489ca5, - 0x616d227f, 0xb307bd27, 0x479ee2d3, 0xab2beec4, 0x6ed93f48, 0x8699c655, - 0xeba7de5e, 0x930bdd65, 0xd25d79f9, 0xfd447ad0, 0x57f39979, 0xbcac0775, - 0xd7477fbf, 0xbf17aa87, 0x9f991998, 0x54bd416b, 0x7274a873, 0x2a9ce749, - 0xf1cf66f2, 0x6fd4a9c1, 0x21efeca3, 0xe978393d, 0xefaa64e3, 0x5e4bf379, - 0x6574dc0f, 0xf323f7f4, 0x9b5cf922, 0xf92ef034, 0x567dea93, 0xa550f295, - 0xdd8ef2fb, 0x4e9af58e, 0x9eb83bf4, 0x239eae0b, 0x6a7ed34f, 0x979404bf, - 0xb02709aa, 0x9569af73, 0xaac79482, 0x65bddb6a, 0x9aabd60c, 0xba931797, - 0x3f0b26d6, 0x0522d356, 0xa7f03c69, 0x748a7f31, 0x357d28db, 0xb00b1fef, - 0x18a8efbd, 0x787d5cff, 0x4ff459ea, 0x9d9f2d7d, 0xb4363a23, 0x763f3959, - 0x196c292e, 0xd85ef383, 0xea02852d, 0xb9f6ddb0, 0x5d6a3ec4, 0xcd0b31e8, - 0xe5b9eebb, 0xfb0f04d9, 0x90b49df6, 0xfad75c7f, 0xbcfeb958, 0x20fb8458, - 0x9dfac5db, 0xf322931d, 0xfc21f749, 0x81f8c883, 0xf70805f4, 0x09e39082, - 0xdaab3e5d, 0xbb123627, 0x7dedafd0, 0xe6bf625a, 0x3bdf9374, 0xffdfebb8, - 0xffdde695, 0xff98932f, 0x7fc657c5, 0x4f1805f0, 0xc0f3e8d4, 0xda1653f9, - 0x9ab4d61f, 0x173bc5cf, 0x77dbbefa, 0xf0c67b95, 0x571636fe, 0x3880b16f, - 0xc10099b7, 0x381e29e7, 0x91ab2c06, 0x07511f9e, 0x0e7147a4, 0xdd60d658, - 0x71467646, 0xc608e3c2, 0xb9d717db, 0xf70f9e15, 0x9de31b08, 0xedead657, - 0x858f6aa5, 0x9e3570f2, 0x75e90b5e, 0x7113f84d, 0x51f6df5e, 0xbf6716b9, - 0x7e16ed5c, 0xc303d0d3, 0xa7d2ebde, 0x87985db0, 0xc6c860e2, 0x66b85f76, - 0xdd53e280, 0xda0ed47e, 0x03fcb817, 0x6f607744, 0x2beb4a82, 0xccc9f7dd, - 0xfe79889e, 0x5187dba4, 0xa3f979af, 0xe7e266a9, 0x2aa68f9e, 0xfbcfc349, - 0xe2eb1c32, 0xddaa55e5, 0x4e6f4e22, 0xb68f9df6, 0x186f0483, 0xb769ade7, - 0xda07f9f3, 0xe28e96c1, 0x75b83b48, 0xf3d20edd, 0x168bd976, 0xcb6d3501, - 0x3fdc0dfd, 0x91e24bc9, 0x480616db, 0x8fa7650f, 0x8afe13f5, 0xcfd4cdf3, - 0xae52267d, 0xe91b7fdb, 0x4f08e291, 0xd46bcc8a, 0xd17e7a98, 0xb75c9121, - 0xaf9a266b, 0xc96fd808, 0xef0f5f0e, 0x54338a9f, 0x9e1ec7da, 0xa7c40e51, - 0x38901e9f, 0xf54e6b5f, 0xf922cd6f, 0xbfb9951e, 0x010bf0e5, 0x9bee973a, - 0x9f44c506, 0x4e9fdeb1, 0xe38c830b, 0x2f042e6c, 0xff79bb4d, 0xdfd21e2d, - 0x611fa69f, 0x86f7617c, 0x234afc80, 0xe7ca06e2, 0x61420bd8, 0xd721271a, - 0x3ce32c57, 0xf3276e79, 0x7bf562cb, 0x4d941f29, 0x4d875c75, 0xfa23adf1, - 0xb144ee6c, 0x657b1e9f, 0xb23eba79, 0x1bce857f, 0xe92f9cfd, 0xed3d0b33, - 0x5f180abb, 0x399d1df3, 0xbe09a4d4, 0x6b2e76c1, 0x46a63adb, 0xf044dbc6, - 0xdf79e8db, 0x44bc5bfe, 0xd75139bf, 0xb6448cf7, 0xfff9d88b, 0xe499f499, - 0x35b35a6e, 0x7c4cf88b, 0x7bf64753, 0xf067ef5a, 0x2e7f1403, 0xaa922bd9, - 0x8d0fcbc5, 0x4e3c9777, 0xea9cdd72, 0xf01575cb, 0xc300acf1, 0x76b8c49e, - 0x57fffd87, 0xe91fff64, 0xf8a2dcfc, 0x4ddfc46d, 0xf16cdd7a, 0x7fb64ea9, - 0x0ff34a9f, 0xfc746fad, 0xf6e9b5f5, 0xff8265ba, 0x4fb7d71b, 0x15399f5f, - 0x4bc68df5, 0x4e67ee06, 0xff48060e, 0x78a0929a, 0xec3e3e13, 0xdd90f72a, - 0xc5f4396d, 0xa6f7b238, 0x2807af24, 0xd66075af, 0x2dfbb22a, 0xfd636fa3, - 0xbc85f4ff, 0x9e623922, 0xad256913, 0x697ebfe4, 0xcfe2cbac, 0x42fc75a5, - 0x5d6323d7, 0xabdf6ee9, 0x11bc88ee, 0x915f758c, 0x9fbe80fe, 0x17f1eaf3, - 0xff9c73f7, 0x2f4487eb, 0xd6ee279d, 0x3e02b771, 0x783b1bd6, 0x1a55c655, - 0x1f7ba31c, 0xd8261d8d, 0xe4a6cb46, 0x5d39c454, 0x36326cb2, 0xb70d9a7d, - 0x4c6c74e6, 0xebba6fed, 0xbd213496, 0x0b2021fb, 0xaf9d167c, 0xa4d24d00, - 0x6bc53cc8, 0x14f3f155, 0xc91bf8cf, 0x9e56ff2e, 0xb4d84e62, 0xf7f292da, - 0xbace2be7, 0x9f3df7a3, 0x2a2655ba, 0x31f42b94, 0x8a0c4e14, 0xa74c17bc, - 0xf133537d, 0x067bff12, 0x2df6cad7, 0x5cdae5f5, 0xfbee4f68, 0x8b1d6db7, - 0xd62d9776, 0xfa46f54f, 0x3dc0a77b, 0xd78ff943, 0x46ee30a6, 0xfef3273f, - 0x12d3a9df, 0xc462b723, 0x88f7c06b, 0x27f2a352, 0x265f23e1, 0x4aed7e93, - 0xb922df55, 0x7cc9740c, 0xe941244f, 0xd8e2b8b1, 0x03c23ed9, 0xd38bf7e8, - 0xd6c43ec5, 0x6d17ce26, 0x317ec6aa, 0x269ce9c1, 0x79c5d847, 0x579fc8b7, - 0x9c60f91f, 0x05dc3105, 0x02e4f1d3, 0xdec37f1c, 0xc34a6496, 0xf6f33fad, - 0x5392ba4c, 0xe91df8a2, 0xa54ffeb8, 0xc236391d, 0x53835ba9, 0xf0a13f89, - 0x93f21484, 0x94040a85, 0xf1f138a2, 0x14de22a9, 0x87c53cd7, 0x3ed850ff, - 0xe5e12d7d, 0x2f58b0da, 0xa6c661cd, 0x7ae036bc, 0x2a635b5f, 0x6ffb578d, - 0xbf934607, 0xe05d297a, 0x4d2f179a, 0xa02bef11, 0x74acff50, 0x41e7ae97, - 0x5f0be513, 0x7d8cf3d2, 0xcfdc4c97, 0x6db0bf98, 0x3d44eca1, 0x3f6f0828, - 0x76cd79c4, 0x4df24aab, 0x3f040e78, 0x771813da, 0x0c5c1ed6, 0x5dfae714, - 0x7db095e0, 0x6fc0e257, 0x0e061f49, 0x773a5558, 0x876e704d, 0x977f1c54, - 0x0f2b4f7e, 0x31c5b215, 0x2f98dcfc, 0x94e7fda1, 0xe0bd2413, 0x6504dff3, - 0x88e35c3b, 0xd31277e4, 0xd5eba25d, 0x89b0c4ae, 0x260645ce, 0xe9875ee1, - 0x7813a61a, 0x3cce835e, 0x2cbbfbf6, 0xe07ee703, 0xa49cba66, 0xe8207907, - 0x2ac9f684, 0xa704d1f9, 0x7048ebc6, 0x3480deaa, 0xa9daae92, 0x6ed0fc08, - 0x35e7251e, 0x6baed877, 0x36eb8713, 0x135d85b4, 0xff8f3f40, 0x8f3a36d5, - 0x8393aa1f, 0xfefc3d99, 0x6c2fe92d, 0xf9cb1a6b, 0xa28c80bd, 0x949963b6, - 0x7954eb4a, 0xb545e87d, 0x07c122f4, 0xb767afba, 0xfea1f689, 0xaa0ee7a8, - 0xaf3f443b, 0x925f69d5, 0x8742f6c5, 0xf07843d7, 0xee7c297e, 0xded7b45a, - 0x05297cc7, 0xd35eaeb8, 0xb19a07a1, 0x87569fdf, 0xe93ee872, 0x1aff5673, - 0x3e57cfd2, 0x2148f35c, 0x665ddbf9, 0x9df9256f, 0x18cfc09e, 0x5668bf87, - 0x1dd845b7, 0xe0c81d8c, 0xf33180fb, 0xf4d99ed4, 0xfdd7c233, 0xce9525fb, - 0x03cdfbbd, 0x9aee88e3, 0xe85a3ff6, 0xfeed64be, 0x4b4f188f, 0x9a1afe19, - 0x035b766f, 0x039b6bdf, 0x1b5ef9db, 0x9fbe43fa, 0x7f08f218, 0xe73a7832, - 0x390886d9, 0xec2e913c, 0xe3fc060d, 0xebb55e29, 0xf6907af6, 0xedee58dd, - 0x8d2275b8, 0x07cf57bf, 0xc035ef18, 0xf7c431a1, 0x971af04d, 0xa0fef3c6, - 0x967a4152, 0x4eedaeff, 0xa3ffa22d, 0x3dbf02e9, 0x66702e9a, 0x89bf8676, - 0xf1df5de8, 0xd69925b1, 0x8e343679, 0x4521b9f6, 0xf1c6714d, 0x1bf64323, - 0xcab54f63, 0xd7fa8580, 0x2bf6079e, 0x14a6ef28, 0xef4bdf94, 0x8d594db6, - 0x4ca2f7cf, 0xe2ae2852, 0xefe294fe, 0x0c6fb35e, 0xe7786ff5, 0xc7e4a9f3, - 0xe74f481e, 0x607e7ff5, 0x1be278fd, 0x22497fea, 0x606ed9d9, 0x69d866bf, - 0xbe29d901, 0x5ffa405f, 0xf63cf54c, 0xdd2cbbcb, 0xf72ed84b, 0x12ec809a, - 0x01ed9ff5, 0xf849dff5, 0xf689c0ae, 0x664fefc0, 0x6dd5df3b, 0xa32718d2, - 0xf5c49f5f, 0xbea91b92, 0xc9ccbbab, 0x05f74e76, 0xc35ec88a, 0x109c7887, - 0x9d1224c0, 0xfca8be04, 0xe9993b88, 0xe7e5fc36, 0x86e3d06e, 0x75c5e29a, - 0xca3965d8, 0xa4e2223e, 0xf4711ba8, 0x9edb33c9, 0xee817b40, 0x0fdc28d4, - 0xffbf0bef, 0xd5563d5d, 0x59773ebd, 0xeeb3ae33, 0x07edcc84, 0x585e7df5, - 0x7a4393d7, 0x86e2867e, 0xefdc5d3a, 0xb033e7a5, 0x675df74e, 0x094b1b6a, - 0xd8aecd63, 0xb9ca987e, 0x412950be, 0xbaabf9c8, 0x99859b0f, 0xb5fe93e7, - 0x9f2eba1e, 0x9ff5cdee, 0x920242b1, 0xc0e5fad8, 0xb5c45f6f, 0xf910703d, - 0xe14e271f, 0x10ff5872, 0xcf018d6f, 0xc97ef6c8, 0x4bbd23f0, 0x5afb1f48, - 0x123ae1e5, 0x4d8a8352, 0x3fd277f5, 0xbac016dd, 0x9f7b433f, 0x99c7e254, - 0x3f49f7fe, 0x997e4ffb, 0xf7b96641, 0xb7c7d8b4, 0xd27cb45a, 0xb809d69f, - 0xa7a38db5, 0x3c8ba5af, 0xe215b14f, 0xa57e4b9e, 0x009cc1c7, 0xfef1223c, - 0x5106765c, 0x655a17ee, 0xe7f882cd, 0xce56043c, 0xe7a37f23, 0xfd01ef6f, - 0x941fe1a7, 0xf57abdcf, 0x182bc21e, 0x627deeb7, 0x89bfb9c4, 0xbb6d69f4, - 0x6b84ff04, 0xfc4cf75f, 0x5e46097b, 0x1db6beeb, 0x3ca0c647, 0xee8b9eab, - 0x9ee861b7, 0xbdf7887b, 0xefa39a1b, 0xae957c1b, 0x308996e3, 0xea0b7091, - 0xb307fb13, 0xd4569d02, 0xfd3257df, 0x7e5e109f, 0x84f824c9, 0xf2ed957e, - 0x671eb713, 0x1a3f844a, 0x8f7c00b8, 0xe8676f28, 0x99d7dd30, 0xa5e59cdb, - 0xa22ae639, 0x165b6e7d, 0x825019c7, 0x9837dd32, 0x19cbf9ad, 0xd3b4075f, - 0x9d642f74, 0x89c127ee, 0xa3bf287f, 0x8e9d6baf, 0x460beee7, 0x82073dd3, - 0xdacf348d, 0xd1fee29d, 0xbff19dfa, 0xc7d5a813, 0xc9d4f0d9, 0xac0e9423, - 0xabf7450e, 0xdb53f9d5, 0x05bcfd16, 0x9f181278, 0xfccf7d11, 0xfc43ef4a, - 0xc5f02cc9, 0x4638fadb, 0xc219b5fb, 0x7920d67f, 0x410ddf24, 0xb37a4839, - 0x0b240a4e, 0xd58e0b7c, 0x865df748, 0x65f7e8be, 0x73f9d6ef, 0xbc2fae97, - 0xfabf7c2e, 0xe7482919, 0x24ff7780, 0x427bfe9a, 0x1f49cbab, 0x5d6af562, - 0x6df199b3, 0x10b46c15, 0xabd58dbe, 0xd97d21aa, 0x1638a16e, 0x7e354fab, - 0x0b7432e9, 0x4b7ffe5c, 0x98737af7, 0xffeb4cf3, 0x3ca5e4a7, 0xdfadbdd4, - 0x745e50b1, 0xf9087da4, 0xa27a1956, 0x5defebaf, 0x7c86edcf, 0x9614c0a7, - 0x15da456f, 0xf1a283ee, 0x50cb6ef4, 0x7cf3929e, 0x38139d83, 0x51e86e3f, - 0x3ae538ec, 0x14fc5f2e, 0xada17970, 0xa2f84ed4, 0x2bc9b8ff, 0x4c7f9ca9, - 0x4c3e442e, 0xe103203f, 0x89f6fe8d, 0xfe90078f, 0x37c513a2, 0xfa7cbe52, - 0xd83f8c09, 0xf8b3a7be, 0x115fe457, 0x7d91a4e1, 0x4ecaec2f, 0xc783bdfb, - 0x7fddf8e1, 0x4af1e8bc, 0xcbc7c3f2, 0x095c698a, 0x787ee9db, 0x1a871e91, - 0x7bd9178e, 0xfdd1e222, 0xbedf2219, 0x47fbf3c5, 0x78b05f69, 0xf94bd9b7, - 0xff66c58e, 0xafa404a6, 0xdbc905e8, 0xe91db380, 0x8d24f43e, 0x52a4f68b, - 0xeef166be, 0xf6a21def, 0xd3125dda, 0x28bedfdf, 0xc7c5177f, 0xb8a5eca0, - 0x577edfd7, 0x7384bdc1, 0x7053dc0e, 0x477cc457, 0x595f8552, 0xe399957c, - 0xfb68ef71, 0xcf292b2f, 0xff60eda9, 0x1eeafbd0, 0xb0577f0b, 0xae0f024b, - 0xf0e788f3, 0xbd0f89af, 0x085a4efb, 0x9eb697e4, 0xf1c4f4b4, 0x017946cf, - 0xce6171b7, 0xf0b76ebf, 0x7fbdca3d, 0x6b7ad0b0, 0xf388fb9e, 0x126d5569, - 0x67aaa7fb, 0x794aa0e4, 0x58af039e, 0x9a6b3f48, 0x8accc825, 0x3b73376c, - 0xffaa51f9, 0x65f859b1, 0xe8d7ef43, 0xbde86e7a, 0x746b0761, 0xd6d775ff, - 0x17bf3d68, 0xf1a32db4, 0x579a7bfd, 0x7ba03df3, 0x5ff7c7b6, 0x4b5c1f86, - 0x2b8c52fb, 0xee8a9f6b, 0x7e90df77, 0xc7bfd807, 0x3257c9fa, 0x3cd8f3f4, - 0x1efd23c8, 0xaf19af0c, 0x7e7d3da0, 0xc43c6ab2, 0xd71e3bc9, 0x8f1180f1, - 0x8e26c307, 0xfafdb167, 0x285a2eda, 0xfe76d68e, 0x796bf199, 0x872c67fb, - 0xbe0ef6ca, 0xf83d7aaf, 0xaf1f1037, 0x093bb76f, 0x08f65747, 0x6ed25fbb, - 0x6a25060d, 0x7c91350f, 0xef8a0ffb, 0x4aaf023b, 0xf740a38c, 0x7e756b7f, - 0xb7f9d5ae, 0x6367f716, 0xbe8adee8, 0x772fbeff, 0xe2ba11c7, 0xdf3fa351, - 0x993875d0, 0x8404b8f8, 0x12125a7f, 0x8790c9fe, 0xc6465f11, 0x936f81d1, - 0x5bb7d73c, 0x52f8bef9, 0x6d2d3fdd, 0xc593df16, 0x51fe8bfa, 0xddff9176, - 0x8d8de82b, 0xd1ad35a7, 0xd232bbfd, 0xea0fdfd9, 0xc313f878, 0xa8f2e8df, - 0xe53b001c, 0xb2a897e7, 0x756fc837, 0xe77f342b, 0x63cf8954, 0x2989d53b, - 0x194beef1, 0xce3a9be5, 0x28cbea37, 0x43fd864f, 0xc88eedce, 0x998dfc7d, - 0xcd54af02, 0xcf240391, 0xb2cf7d88, 0xfbb8aca2, 0xba44c81e, 0xd77b18df, - 0xee45a64f, 0x391db47b, 0xf23f67a4, 0xf7495e3c, 0x859b6a8c, 0x8d9be87f, - 0x8e10a6e3, 0xb5c5c607, 0xed20d6cd, 0x4f516a4f, 0xd2307bf8, 0x76bfb20f, - 0x07e91169, 0x991c1bee, 0x3a72cf48, 0x2ff5c4aa, 0x8e38c36f, 0xfb2f2fc3, - 0x2baaf58c, 0xf91bac5b, 0x1f6f1996, 0x6a1fec61, 0x6a9c092e, 0x7a51af3c, - 0xd3511f78, 0xb749ee2e, 0x5c62fa1e, 0x7fdbd216, 0xadc63fe0, 0xa64172c6, - 0x25adbf88, 0xbee98fa1, 0x6cbbe7cf, 0x90e8f171, 0xd89a97bf, 0x3dcc6a0e, - 0xf6578c19, 0x859c2e23, 0x4fedf37e, 0x7ad1df79, 0xca4ee128, 0xf1adf5c7, - 0x837e778f, 0x13601a9c, 0xd04ddae3, 0x9ee125c4, 0xd6b81c48, 0xdd0fee29, - 0xaa49c7ab, 0x7d7a8c3f, 0x505df62f, 0x03eecf14, 0x2349e65b, 0x1bf0dded, - 0xafbebad5, 0x85b1d82f, 0xf163e08e, 0x476eb551, 0x2e39fc88, 0x1ba2e2c6, - 0xb4f5a333, 0xc644ede1, 0xb25dfdb9, 0xc8c47293, 0x268c5fd7, 0x7ef887dc, - 0xeb3c9c42, 0xf65ebaa7, 0x0dbee7ea, 0x9be665b3, 0x0d288e69, 0x63fc851c, - 0xe93fe97d, 0xcb1c5208, 0x04caf83f, 0x9dfaff92, 0x2445e7d1, 0xdfdf3f3f, - 0xaafcb20a, 0x433e7643, 0x3a5fda32, 0xd214caf8, 0xbfb786b3, 0xf97211cc, - 0xbee2c722, 0x29467d3c, 0x6bff6249, 0x77fec492, 0x4c93d2af, 0xfddaaefb, - 0xfef22fb2, 0xbbe721bc, 0x4501fd75, 0x65d7f3ec, 0x686f5caa, 0x3a617a17, - 0x7f9c4a20, 0x98f3c8a5, 0xed11fe79, 0xdf2fa825, 0xe880b710, 0x9ad7d942, - 0x6aef5807, 0x9e989a4f, 0x198393da, 0x05ef11d9, 0xf24cdc68, 0x801b0d7b, - 0xc81d88fd, 0xefa52ebf, 0xf4beb10f, 0x59c604fd, 0x523c2647, 0x64adce29, - 0xc0f5bf20, 0x239355db, 0x3d05fffd, 0xc1f103ee, 0x09e72843, 0x87cebf31, - 0xcf42b04d, 0xae3d0813, 0xee2c71d2, 0x8ec89aaf, 0x5757f763, 0x0e1b938a, - 0xc7f28158, 0xf9581fb5, 0x07e7d03e, 0x1dfef2d6, 0x9327f92e, 0xffbf019f, - 0x381f2a6a, 0x3d3276b8, 0x7de0fcff, 0x53de7357, 0xaf9514da, 0x1e7d1008, - 0x797f51c2, 0x97c276f7, 0x90e30a5d, 0xefd3aea2, 0x9eeaf9d2, 0x9b7f3356, - 0xc677bd59, 0xc22481e3, 0xe94b454f, 0x9d3d9dbb, 0xe21feb0a, 0xd947032a, - 0x289d4719, 0xe3851c66, 0x165c82f8, 0x71a4ab1f, 0x5314944f, 0xc9db0937, - 0x1c274d9f, 0x55c618e5, 0x9cff3d06, 0xdfd9f829, 0x13f9c091, 0x3d082609, - 0xba28ec83, 0xcebeb437, 0x9b436438, 0x86bdf51c, 0x4ceedef1, 0xd7b0ae71, - 0xa490b3d0, 0x16ed1eb1, 0x3db686e5, 0xf58eb419, 0x49eb10e6, 0xb459b343, - 0xd02512ef, 0xfe0ccdf9, 0xfc4038d8, 0x508f4639, 0xc12c4b2e, 0x77db84b1, - 0xea079d0f, 0xe28239f7, 0xe7635d5e, 0x686efe44, 0x3b8f73b0, 0x4e39fc5e, - 0xda4833e7, 0xcfb12cd1, 0xf3af6d89, 0xd1c67c88, 0x1e2fc233, 0x1c9fe85d, - 0xa0063fcf, 0x25fbec44, 0xe6ad7e5d, 0x86e7788a, 0xdf223d1b, 0xe06c73b4, - 0xef71e928, 0x373e04ee, 0xfc8975ec, 0x974b696c, 0xac9fdf42, 0x5066956f, - 0xfb9f5a3c, 0x829f7f1e, 0x83f662f5, 0x6e7cfde1, 0xbbbcdd5a, 0xc7438b5c, - 0x1f111eb5, 0x01dfe897, 0xbd57d08f, 0xd37814fd, 0x23da7df5, 0xaa735e74, - 0xdf14ecd2, 0x4aef8999, 0xf9fdd06f, 0x199bd78d, 0xd5029d37, 0xc43fce2c, - 0xdd32c539, 0xfba0df2f, 0x3bdf11f9, 0xe99b033f, 0x7bf6229c, 0xdfafc367, - 0x02bf8fac, 0xf6371e34, 0x759bf5bb, 0x2fb3783c, 0x4ca5f9fa, 0x40e6071d, - 0x10f3f90e, 0x1fbe17c6, 0x71c09791, 0xa4e1697a, 0xbe8338b8, 0xeff55703, - 0xe434a9c0, 0x1ef790de, 0x1da3bfc7, 0xdfcd7e67, 0x80499c13, 0xc5ce7109, - 0xe19fe386, 0xf2126e3f, 0xaa2dcfd6, 0x4346829d, 0x077017ee, 0x331f9916, - 0xe7463ee4, 0x3df1ffff, 0x22505ca0, 0xcacf25f3, 0x3a1e31fe, 0x32f5b09f, - 0x7015c6fe, 0x8d75c41c, 0xce35d7d3, 0x2edf111a, 0x571d5a8c, 0x97d7877f, - 0xc471101a, 0x9e4765cd, 0x75627195, 0xfbefe248, 0x5f62c3aa, 0xf6265d5b, - 0x02ad39b5, 0x49bcaea7, 0xbb126a0a, 0x9f44d3c3, 0x6ccb3fa1, 0x7a180f02, - 0x5d2fc432, 0xf09da87f, 0x3e3a0dc1, 0xc9a3d588, 0xf94e5dd0, 0xc9345be6, - 0x472af74b, 0x6abf3f7c, 0xeee4ebda, 0xa83fa72f, 0x22effc6f, 0xf7d1eac4, - 0x0f12fe3d, 0x07bad3e5, 0xb8e21657, 0x38fef347, 0xe6a6f48e, 0x2df37632, - 0x3b13888f, 0x7ca3811d, 0x3f45a4df, 0x6bc96fef, 0x747e21eb, 0x5ec7e302, - 0x3a96f757, 0xbcf9ab81, 0xc09c3abf, 0xb75643df, 0xb0bbf9db, 0xc486d6ea, - 0xdb7fe429, 0xeb1daf65, 0xcb27ad95, 0xc5959f88, 0xad4a3ee2, 0xb38bdc5d, - 0x10b7fdb9, 0x3b7bd77d, 0x2df9cfa2, 0xfba8bf3d, 0xf58f3d06, 0xa3091b6b, - 0xf9f7ffa5, 0x5f3a8d9b, 0x662ebaea, 0xfea9c14c, 0x26afe690, 0xfd7fec7d, - 0xd71d0b45, 0xa5794ed5, 0x6d88ae9c, 0xefdca8f4, 0x268ee6fa, 0xf41af34a, - 0xf93a6477, 0x707351f9, 0x82d2e32c, 0xd30fbb2b, 0xa98dffb0, 0x3afaa714, - 0x225aa6ba, 0x0eb7bbf4, 0xf91c73fd, 0xb7498035, 0x494b855b, 0x25e3a15a, - 0x07b5c761, 0x3e50670e, 0xb7ec97a2, 0x9277ca80, 0xdeacb1b3, 0x12792a7d, - 0xa2bd96e1, 0xed19c21c, 0xa503f732, 0xa4e6e727, 0x3336fa48, 0x6242177d, - 0x9c9e801c, 0xdb230b1b, 0xdb5fff1b, 0x27a4d3ff, 0x289eb6d5, 0x84f837fb, - 0x3efe7cbb, 0xcad07037, 0xbce808f7, 0xc72115c6, 0x347f7457, 0x644b370b, - 0x7ce873a7, 0x3b41227a, 0xbaa0ee05, 0x95256102, 0xb2c38bce, 0x96377fb8, - 0x7d4cf7fd, 0xb84a59fe, 0xcee9ee83, 0xe737cfd1, 0x5bf73742, 0x6a5c0300, - 0x8befe4e0, 0xe5cbc04b, 0x29785b6c, 0x5082f1c1, 0x099fbf88, 0x73ae2867, - 0xe63bfd36, 0xe61ef238, 0x0ce7029b, 0x0e74c87e, 0xc51bee26, 0xd75ba7ae, - 0xf09a59c7, 0xe81d043b, 0x086cee7e, 0x35fbb9f1, 0xbf9fa3d0, 0x3cc75fc7, - 0xb9d1f7dc, 0x3b6835db, 0x208fcc89, 0xeb4f9ff7, 0xa7ade391, 0x198b2967, - 0x9f449cca, 0x7d30ce14, 0x75f2bf6d, 0x4d6dd3f4, 0x35df57ca, 0xe283f7d0, - 0x6f4b73e1, 0xd3ef1bfb, 0xd349627d, 0x97b1bef8, 0x7da6c7be, 0x1de9584e, - 0x001363f2, 0xe6b3ddfe, 0xc66f6437, 0x07e01af7, 0xfb11e7be, 0xf72d06bd, - 0x3df0c67c, 0xedfee335, 0x950ae0ce, 0x72ac6fee, 0xaddff8db, 0x9b8db229, - 0x87ca794e, 0x21bffcd2, 0x6a40fabd, 0x2883c49e, 0x638c19c1, 0x83b2bd75, - 0x2fd69b36, 0x22f7c669, 0xf432fac0, 0x006401ef, 0xb763b77f, 0x1e69ef8a, - 0xa5b43d41, 0x74abf6b2, 0x2e1e1a0f, 0x6f2f0955, 0xf4bcd971, 0xe895ae5d, - 0xdbd30fb5, 0x2ff71368, 0xb16bfb8c, 0x19b46c7c, 0x8daf4a79, 0x77cc7671, - 0xfcda773e, 0xbfe89bff, 0x9324a93f, 0xcbfe6070, 0x3f7c3df3, 0x7758c129, - 0xc3eb8d89, 0x37191af7, 0x6a7dd136, 0x1d31aba4, 0xe1e21ef8, 0xba149ca4, - 0x25d8d51f, 0xa63753ee, 0x9b7fd807, 0xf3fb12fd, 0x4ed2cec6, 0x0e83078a, - 0x6eabdf0b, 0xaa34f974, 0x4421d207, 0x3ef89ffe, 0x69bbe0df, 0xfd21ef98, - 0xed91505e, 0xde5157d7, 0x4a1b9a7f, 0x6169bde9, 0xc0f1126d, 0xe5061ef8, - 0x4e9519e0, 0x7befa3cf, 0xfbe4e281, 0x501c8617, 0x9d995831, 0xb90d7cba, - 0xf8ef8d38, 0x3bea2535, 0x8f5e437e, 0x98b90a24, 0x44cc26e9, 0x71a5577e, - 0xf061e563, 0x8f00bffd, 0x30b1ae40, 0x0030b1ae -}; - -static const u32 xsem_int_table_data_e1[] = { - 0x00088b1f, 0x00000000, 0x243bff00, 0xa3f0c0c3, 0x4aef811e, 0xf1303031, - 0x12d18aa2, 0x6064e3ef, 0x6062e010, 0xfbe20530, 0x330c0c3c, 0x204cf480, - 0x6066e516, 0x1ae20310, 0xc40dde20, 0x19f8807b, 0x1039fc50, 0x1be200ef, - 0xbefd103c, 0xfe0c0c4c, 0xc4081c40, 0x95fc40c1, 0x1be18181, 0x73f6f103, - 0x4c30330a, 0x2ff04715, 0x249fd903, 0xc1ffe7e9, 0xe90c4386, 0xa071df6b, - 0x10acf37d, 0x7b20467c, 0x9aaa15be, 0xcdf85605, 0xbf268858, 0x18bf8d08, - 0x0372fe8f, 0x4d5afe54, 0x81b5b334, 0xcd4909e9, 0x6efc4d3a, 0x40aac741, - 0x3101a9ff, 0x5ff1ad00, 0x000368ca, 0x00000000 -}; - -static const u32 xsem_pram_data_e1[] = { - 0x00088b1f, 0x00000000, 0x7de5ff00, 0xd5947809, 0xe77df0d5, 0x9926665d, - 0x6c81bc99, 0x44d84eac, 0x4242740b, 0x61db101a, 0x8311688b, 0x9817054b, - 0x264f6408, 0xdac7f520, 0x0040cfef, 0x8b435151, 0x03b45a35, 0x341b0504, - 0x024180d8, 0x2d82e00e, 0x5d6ad8d5, 0xc8a0d2da, 0x1b80931a, 0xcefc5dfe, - 0xc9bef739, 0x82264efb, 0xf5ffffb5, 0xf8f8fefb, 0xf77bee5c, 0xce73ddb3, - 0xe28ef73d, 0x8b94c718, 0xff12fb18, 0xdd98c7be, 0xd71b18c6, 0x2356329d, - 0xcf2d4ad2, 0x03d058cd, 0xac62ccff, 0x9785addc, 0x653633a7, 0x5ef91a87, - 0x4837e412, 0x6de43b61, 0xde549d7b, 0x23e79ebe, 0xa0cfcd6e, 0xc83aa3fc, - 0xdeded04b, 0x5065c0f2, 0x6643b9de, 0x91dbb11b, 0xc2963671, 0xe30731d8, - 0xcf90597f, 0xc9c0ac66, 0xf61be5b3, 0x45f6c5cd, 0x84e6764d, 0x1577cafe, - 0xf20cbcce, 0x86550785, 0x2f37ca55, 0xbe43fad3, 0x60352c38, 0x9f3263be, - 0x1ca7685f, 0x3bf50cde, 0x37292d3c, 0x553b18b8, 0x8d5e60e5, 0x4b776ab1, - 0x18a3f5ca, 0xcf6f092b, 0xf52576c5, 0x3a970f92, 0x97e6c765, 0xb6bae1fb, - 0x97bb3e4a, 0xf12dd2b1, 0xcf923bcc, 0xfff84be1, 0xf91ca358, 0x862f941e, - 0xb7e83275, 0x32e4d590, 0xab5fc719, 0xf0dddd79, 0xd3a5553b, 0x7cbe4638, - 0xed038c2b, 0x7c969e2a, 0x1b0ac4b8, 0xf8c0340b, 0xb39cbbed, 0x7d70b937, - 0x6e11b4cb, 0x1addd75c, 0xe70c2bd6, 0x717a74ef, 0x5cb41b7e, 0xbf592f28, - 0xd5182b41, 0x96e95fdd, 0xd579d6be, 0x980d4d0e, 0x53d3a3ca, 0x47798c55, - 0x184be774, 0xbf4037f3, 0xb36b094c, 0xff7f7746, 0x96322580, 0xcccbfd8c, - 0x1feee8eb, 0x43df4920, 0x013fc16f, 0x6e3da15e, 0xb781ab82, 0xdbfc3ac5, - 0xb3b78ddb, 0xd2a3c0ba, 0xdfee6d99, 0x3c401f48, 0x106a7cc0, 0x11ae904e, - 0x644cf3f3, 0xdfe81493, 0xc4ba67e3, 0x918f5f7a, 0x9f2ca8d6, 0x420b58c1, - 0x78cafda3, 0x116c6bc8, 0x93f631f3, 0xa9fed915, 0x059fbf90, 0x57bce2e6, - 0xc4228148, 0x690d6313, 0x24abbf48, 0xffd71b36, 0x94349c03, 0xf407eaaf, - 0x99af7009, 0x9649bd96, 0x3093dcc4, 0xbdc4f05f, 0x214fd4e9, 0x3f42a3f5, - 0x8fdfcf43, 0xe9639b9e, 0x322dcf47, 0x7ea4a9fa, 0x4fd6179c, 0xeb04ee4d, - 0x8c4b727c, 0x7ea4ee7e, 0x2eb617dc, 0xd6898afd, 0x46515cf9, 0xf54e24fd, - 0x97d400b1, 0x2d607a0d, 0x5dca197e, 0xef6389f5, 0x98ba6665, 0xdff912bc, - 0xa6625c0d, 0x389c848b, 0xfa261d0b, 0xd0f258fb, 0x5bec7e93, 0x44830f22, - 0x5f1a3512, 0x5c91afeb, 0x41dfd498, 0xbbfa3bf9, 0x31dc2e48, 0x0eb17021, - 0x59b1c0f3, 0x816bc83f, 0xe831eb6f, 0xb129e61a, 0x36bd4c34, 0xefcba34c, - 0x261c3956, 0x88dbf80f, 0x683ed023, 0x08911ceb, 0xa4d2f5f9, 0x365c205f, - 0x27c11b33, 0x5895664e, 0x48cece2f, 0x9e9ddd3e, 0x826429bd, 0x8041ead3, - 0xdfbba97f, 0x0d206ad5, 0xbb2b6be9, 0xb6f48421, 0xa7ac106a, 0x854f633f, - 0x14848fae, 0x20a83f68, 0xd769e10d, 0xe3cdbf80, 0x28fe306b, 0x1c19ff1a, - 0x3f8e0777, 0xf6f8e7ae, 0xf1963921, 0x2c8b831d, 0x18343be3, 0x177de81f, - 0x0f8c55bb, 0xd8c09bf0, 0x685ba1f3, 0x22e0fb7c, 0x8d6eff1a, 0x8fc65915, - 0x05ff1aeb, 0xdea5f71c, 0x82643fd6, 0x4b83fd75, 0xf8d7ebac, 0x0b655ffa, - 0xb471f8c5, 0x16875ffe, 0x2e0ff5f0, 0xf3b7ebe1, 0xf7c6bb7e, 0x75ffc174, - 0xdeadf71c, 0xa2743fd6, 0x9517fd75, 0xe76fd759, 0xcacbbfe3, 0x1a2ef8c5, - 0x1950bdff, 0x6545ff5f, 0x0f66be34, 0xb48e90f8, 0x61957101, 0x040d9f18, - 0x19254886, 0x6474a7e5, 0xfda0c61f, 0xe084363a, 0xa71c4770, 0x80e2cfbb, - 0xf2dd5cde, 0xa381858e, 0x08559e40, 0x9fad2f9a, 0xa59ca1a4, 0x0b7b9072, - 0x341754c5, 0xb0dfb4c9, 0x70f0f675, 0x937b6f98, 0x82fcc21c, 0x65879775, - 0xbcd8efda, 0xb0a76c3c, 0xf0ff7e08, 0xcd1bd1a1, 0x174e8aeb, 0x5ac7a8d6, - 0xe7c47c2d, 0x46cc9a13, 0xa6fcc256, 0xeb8c1121, 0x39031fce, 0xbe7e40ca, - 0xd314720f, 0x078c2ae3, 0x9c828fdf, 0x6f999a65, 0x3c7df196, 0x991cdec4, - 0xff827282, 0xbc38531d, 0xc2912d8f, 0xd6cfff08, 0x3e50d22e, 0x0789ac2d, - 0x23cf77a0, 0xb9d4f028, 0x28de1ecb, 0x08bd3c11, 0x15891b9f, 0xa033fb19, - 0xb6801fb5, 0xa5afb6b0, 0xbc2c2ddd, 0xcfea0d32, 0x483f935f, 0x3cdff587, - 0xc6563edb, 0x07f983fd, 0xd98f88d8, 0x630e5b00, 0xaad71bb3, 0xe3732003, - 0x56fdf56c, 0x0139fb53, 0x22e6fe6b, 0x0d5dbe6b, 0x37d436ab, 0x01b6258a, - 0xd2b5bdfa, 0x938c6e5a, 0x78e1f528, 0x20fde315, 0x56f7cf85, 0x67e2c74c, - 0x573af09d, 0xf98d6de7, 0x5952ef04, 0xd6cbf684, 0x4ff84664, 0x9d017aa6, - 0xbe7a3baf, 0x3f875573, 0xf733e60f, 0x19e0994e, 0xbdd6ff3d, 0x18db7ef1, - 0x563f6b48, 0xd7a30491, 0x79ff3d13, 0xa3d7a34b, 0x1f961e93, 0xe9cefe8a, - 0x829e9a24, 0x1efa934d, 0x6f2bd535, 0x51efb2b8, 0x6e957d13, 0x17c96599, - 0xea58e787, 0x5be6d617, 0x14d617ca, 0xafe7ca5b, 0xe7c9645e, 0xd4b4ee87, - 0x9974b79f, 0xcad6fca5, 0x37e52c7b, 0xe4b5ad17, 0xb11e04e7, 0xf671bfd4, - 0x6db94b06, 0x20d725ef, 0x25bf551f, 0x3e37dc33, 0x007b1d75, 0x5d4fc1f5, - 0x71f10f8a, 0xf88d2aa2, 0x979554e0, 0x4ca6f6d2, 0xc1cb8047, 0x16715402, - 0xad086b2e, 0x9972889e, 0x5e2cfc91, 0x1a1433b6, 0xe4adda08, 0xb5c9f825, - 0x09008b1a, 0x174fac4b, 0xa6ca771d, 0x94f3d6f2, 0x67a302d7, 0x5b972cf6, - 0x6e0f7f63, 0xe508bfcc, 0x00f26f4e, 0x3ee006fe, 0xf7f621d7, 0x8932f2e8, - 0x33bf99e5, 0xfcf89cb6, 0x65b3909c, 0x6507971a, 0xcc9bf6cf, 0x8c8f983c, - 0xf1aafca8, 0x28a8001a, 0x4f3b5127, 0x2e007a46, 0x50cbd0b0, 0xedb77f0b, - 0x155e6993, 0xa3c61328, 0x235bc9c8, 0x1c899ca1, 0x68dd7c18, 0x7eff879c, - 0x29aef909, 0xb6f5f699, 0x8f7de9aa, 0x3c9f882a, 0xcd544f4a, 0x5558f4a6, - 0x55a3d280, 0x5fbe9445, 0x6b694955, 0x0f4a52d5, 0xfd288557, 0x4a6ad553, - 0xa1aaabdf, 0x5aaa9df4, 0x1550ff4a, 0xcabdb4a6, 0x0fc1a94f, 0x4937f25d, - 0xaec2abe8, 0xf2879d80, 0x565ac567, 0xe216dd40, 0xf21a5f73, 0x67d759f9, - 0x3f1f5023, 0xa19d8efb, 0xbc1bdfbe, 0x77ade9a2, 0x5f49fa3c, 0xfe030829, - 0x3b967b33, 0x9c9e38e3, 0x819d3636, 0xf867ba3c, 0x46dbbe13, 0x92415e51, - 0x37c90d81, 0xdfa31dcb, 0x75f08c61, 0x7f313c3e, 0x016b98e7, 0xfd1ec71f, - 0x7bf6366b, 0x717fec4e, 0x87da6407, 0x0f936459, 0x1b8265f1, 0x3b9d6bed, - 0x0f3fbc84, 0x82ea3efc, 0x0660cb5f, 0x274904e9, 0x68db3bfa, 0xb1c20a67, - 0xc40c3e39, 0xdc1ececf, 0x5c7e41e4, 0x8fd3669c, 0x918380c6, 0xeba43796, - 0xd3fef32e, 0xad9fcd64, 0x9037a691, 0x5c26f63c, 0x4ae91a3f, 0x430e8fd7, - 0x6a51a7fc, 0x4d38b3f4, 0xbf028fd3, 0x3432da9e, 0x61dfef81, 0x27d60fbe, - 0x5d82bd12, 0xd5fff548, 0x1fade9f3, 0x358c3e63, 0x281c0fb2, 0xe86ca00f, - 0x1e9dedf9, 0xd13e5778, 0xcd5f10f2, 0x2fa867ea, 0x5fffc1c4, 0x157ec10e, - 0x06fd1bca, 0xfd90e41b, 0xdebdf8db, 0xf3b41e32, 0xb637361a, 0x156e9deb, - 0x2ba0cc76, 0x1a1a5790, 0x3a2764cb, 0x92beeb75, 0x9b07c968, 0x7d96e9fa, - 0xfc01ff06, 0x4152820f, 0x541329ba, 0x56b8a1d4, 0x23bf304b, 0x2f013f28, - 0x2bd78941, 0x016ab477, 0x0b63912f, 0xe5b719ea, 0xbde77418, 0xef208ff1, - 0x6546fe4f, 0xdff962f7, 0xae505660, 0xf720c51a, 0x2f9f906c, 0x9635b772, - 0x77b940ce, 0xf9f7c6d2, 0x83cf2c05, 0xab114f46, 0xe73d46c9, 0x8e9b6623, - 0xfb11fff4, 0x64d3279d, 0x1a6cf86f, 0x6afe73ad, 0xfa0b3eeb, 0x585f2599, - 0xb017cd6b, 0xde90536b, 0x2ca9d60b, 0x5a5f212c, 0x9d36bdcb, 0x95642dfa, - 0x41dec8ab, 0xbdc6057b, 0x00ca674d, 0x73f95f98, 0x43e7658f, 0xae363bfe, - 0x7bf61ba7, 0xff3e1f71, 0xe6b0a492, 0x1a0ff287, 0x19707f33, 0x55e1f6c3, - 0x6e42a728, 0x7accdbe6, 0xceebefe2, 0xc6be7a3f, 0x8fc3d27e, 0x6f21e620, - 0x18e1fc91, 0x9b34da76, 0x10adf424, 0xbae037a5, 0xbe6b7a4d, 0x2f918380, - 0x19dfca8f, 0xe9a7ff95, 0xe859892d, 0xc81488ed, 0xfa7325b7, 0x52417d42, - 0x37c0b53a, 0x47ad3fe9, 0xd2ffe5ff, 0xff4207fe, 0xeffe96d9, 0x3ff697fc, - 0x57fcc7ac, 0xfcbfeac6, 0x433b6db9, 0x9e4a6f20, 0x60c3c879, 0xd4a93a1f, - 0xef00f8a4, 0x7a579b65, 0x284e0e90, 0xf3d20f21, 0x3d3cb0c9, 0x46ec3d16, - 0xa23f207a, 0x5da125df, 0xfe84ff85, 0xdf753d4f, 0x3e67dc4c, 0x64eaacdb, - 0x47b16d2f, 0x15afc0ec, 0xd833c58d, 0xe11fca18, 0xc8cfbbf9, 0xd2b26f98, - 0x0f93c967, 0x0dffa0a5, 0x13d84528, 0x2a97d211, 0xc5cc3eea, 0x3ac8287d, - 0xdba2cf89, 0xfae7f8e1, 0xd7cc7c90, 0xc3967a12, 0x0fcf493c, 0x1b04b80a, - 0xa3233bef, 0x72b593ef, 0xfd54683f, 0xd4ffa122, 0xc749dcdb, 0xdf6274c0, - 0x7941df61, 0x8583c069, 0xbd53feb9, 0x4731e1f5, 0x756d3e60, 0x2648f1bf, - 0x767c1938, 0x2ffe61b6, 0x2ef6f79e, 0x9d85db8f, 0x4c2eddd7, 0x424dbced, - 0x69e66b6f, 0xa0f11a99, 0x41b65c5e, 0x73e085f5, 0x4f4db6d9, 0xea768a3c, - 0x70df76bb, 0xdb74bfe8, 0x00987f4b, 0x6aedd2f9, 0x0cbe0cd2, 0x8dd29497, - 0xbffc2097, 0x1e376c74, 0x92f57e4a, 0xbfcd1de6, 0x374fb8ff, 0xefb74a3e, - 0x9ee8d8d3, 0xb0d298f0, 0xc5756b4f, 0x91c34bc0, 0xaaafd45c, 0xa1ae7eb7, - 0xaf72793d, 0x63d352c4, 0x4bc373c0, 0x9c2027a4, 0x4f028f08, 0xaa8b785d, - 0xa0bc041f, 0x14f0373c, 0x9080fe5d, 0x779fd83f, 0xd3f3d114, 0xf95fa3cf, - 0xd70fbb3d, 0xedf4f45f, 0x71c75c1e, 0xf5d392a5, 0xfc532b63, 0x1a916e30, - 0xe529d14a, 0xff1e8bdf, 0xe15bd121, 0xe14c3f1b, 0x9fbfa0f6, 0x50a6f68d, - 0xc2df5c3f, 0xfad037f5, 0xe880580a, 0x3931e8ae, 0xa7e90c2f, 0x3dbe9b0a, - 0xc8645f06, 0x6f8e2f9c, 0xd60b8504, 0x12ed1c77, 0x4efeb3f4, 0x7f266f0e, - 0xfc8622c8, 0x3fc343ff, 0xfe5316ce, 0x93c70753, 0xbe09b643, 0x4ccf6d02, - 0xb77775af, 0x0d4e7e20, 0x1fa2a7f2, 0x9094c82d, 0x25f48780, 0x31bf2bf4, - 0x87e3952d, 0xd16c9579, 0x2980f40e, 0xb7eb1df8, 0x18e77ea8, 0x65f63b4b, - 0x4bf8f77a, 0xef30f8c4, 0x8fbfdc38, 0x86a2b0a7, 0x55bbeb18, 0xf61ef836, - 0x997d1371, 0x7bf39bf8, 0xbf9c3ddd, 0xcf0f7e0d, 0x9fe58e9a, 0x07f9c9bc, - 0x08fee1db, 0x52a48af3, 0x25ebbef9, 0x16760792, 0x75d7c589, 0x6b6be0aa, - 0x302741b9, 0x304a456f, 0xdff60bd1, 0xfe4fe087, 0xd07582b3, 0x832f24ce, - 0x67a79e38, 0x16df067f, 0x251ffe0a, 0xad9ff95b, 0xbbdf7ce7, 0x7da2157e, - 0x3f0d4cae, 0x2bf228f1, 0x8bc867f0, 0xe1e6aafc, 0x1fd74fba, 0xc04dc3f8, - 0x0c1ba7a7, 0xcfcab53e, 0x7a2d3e68, 0xf484b376, 0xa7a7cd19, 0x891b408b, - 0x3df0a7c5, 0xb5169f26, 0x9f953ffe, 0x8faefc06, 0x0f219f82, 0xb463837b, - 0xf3633c3c, 0xe5a33c12, 0xc9bdfc21, 0x9fd27bb2, 0xbd067741, 0xfcb2fc95, - 0x1817f222, 0x5dd06974, 0x741a5d17, 0x62ffc3d7, 0xf9745f81, 0xa005a460, - 0x2a5dbc93, 0xcd6555d9, 0xda0c3cfc, 0x8b203cbd, 0x6da7e4e0, 0x3cbcd58c, - 0x0f9cc920, 0xa21be547, 0xf2a3fbea, 0x03f55179, 0x4b4af951, 0x03a6b2fd, - 0x47fc231a, 0x4becf52c, 0xc41f651f, 0xfd8c87b0, 0x4678d826, 0x0c5d210b, - 0xde50d4ec, 0x0541cba9, 0x1ee0ff45, 0x0ec5ec99, 0x182af180, 0x3d3ea3a7, - 0xb1b9021c, 0xf0edc9d2, 0xd3d3bd0e, 0x8995d207, 0xac99df3c, 0x67b942ad, - 0x7274ef7c, 0x5e47473f, 0xe4d127a7, 0x2cd238a7, 0x0d6edc93, 0xfcb1e9b3, - 0x10a3b020, 0x6f595bde, 0x39ffdce5, 0x5e0d764d, 0x8d68f68a, 0x771343ec, - 0x3d1bb2c1, 0x68e92ae8, 0x6ccd7a1e, 0x55f0bef8, 0x3a558e99, 0x70633ce2, - 0x57e42c5e, 0x89ec99fa, 0xb3f42c13, 0x6ccfe889, 0x82c576e6, 0x08fa5135, - 0x54f4435b, 0xa1a25ae0, 0xe03b053c, 0x973fab7d, 0xe88945f3, 0xb5bd68af, - 0x278f68dc, 0x95df685a, 0x03cb59d4, 0x65da3ec2, 0xcb0649f0, 0x86833920, - 0x42e7da0f, 0x47934f2e, 0xf01b335d, 0x665071d1, 0xb6799e78, 0x9c7c2659, - 0x97e7e7ad, 0xfc4c942c, 0x493ac156, 0x6a701a1e, 0x7ad27e43, 0x3b6d5797, - 0x177d9cfe, 0x3fcecdd2, 0xa439f98e, 0x1ddf3b6d, 0xcff31bb1, 0x8ff83dbd, - 0x29fd67ac, 0x37e49d7b, 0x26ebd8ee, 0xf3d8ef7a, 0x6177c1db, 0xfc9d977e, - 0x3f7b1d75, 0xd7f4831f, 0x845edcb1, 0x1063aef2, 0xf7aa87b7, 0x95a63e7c, - 0x8415d7f6, 0xc6b2a3b7, 0xbfe6a3f5, 0x3092961e, 0xdea15585, 0xf89e37b0, - 0x93bcf829, 0x7b1d0bfc, 0xb80ecf3e, 0xa9eb75fe, 0x1d39e710, 0x59fb366e, - 0xf7225f9c, 0x8f770783, 0xcf0cb4df, 0x69f71ba3, 0xca7ca1f3, 0x831f7f0b, - 0x59e3b472, 0xabb50fae, 0x79e38fad, 0xe1fc8745, 0xdce01532, 0x9fd54c8e, - 0x1194fbb1, 0x62a34393, 0xe4efe5c1, 0x7850b937, 0x4fb70a68, 0x21e1fdff, - 0x73bcb9f9, 0xae121d87, 0x7fc38bfb, 0xd7b0b944, 0xac69744e, 0x32c374f7, - 0xb7ce57d2, 0x7fcae1ee, 0xd0b83a17, 0x0b914b75, 0x7fd4f759, 0x5aff7c73, - 0xa2fcd2f6, 0x9d27a0f9, 0xf283b9ef, 0x9a3edcdb, 0xfbd205ef, 0x7869ff82, - 0xeef0167f, 0xabbaff39, 0xddd7cdff, 0x9d5fde3b, 0xe3aef02b, 0x85f07f79, - 0xbefcd3bf, 0xf4db9cae, 0x0dee94df, 0x9b15febd, 0xa80ccdf7, 0xb8d59d3f, - 0xb2b8b150, 0x19abff7c, 0xc0cafa50, 0xdf388903, 0x37e751c9, 0xc2a6fa46, - 0x92c9a6ed, 0x9641ec8d, 0x907b0928, 0x840351db, 0x496030fe, 0x0321e901, - 0xf5cfde06, 0x0ebbc506, 0x195f1fcf, 0xb147df3c, 0x3bec6c14, 0x97ebcc01, - 0x9ed5bc8b, 0xfcc4b9fc, 0x603a3478, 0xa20ff7f0, 0xa0703b5e, 0xa42f7a4c, - 0xe8beefa4, 0x97bfce99, 0xe7bb1669, 0x0ed5af4a, 0xdab24dca, 0x7f45534b, - 0xff9f18d3, 0x0e149734, 0x0f261c03, 0xfa1269fa, 0x570f2747, 0x5cf90499, - 0xf6815816, 0xb59754c5, 0xc33c06bf, 0xe1cdf719, 0x380d5768, 0x8797590e, - 0x93241c70, 0x70bcf49f, 0xdc1379c4, 0x2f18c232, 0x871f14c3, 0x1f729f63, - 0xbd859df9, 0x904d474d, 0x5aab5c57, 0xb4159f90, 0xc81c3997, 0xe5ec36ce, - 0x84cde0de, 0x2188adfd, 0x032bf80d, 0xdad3bf65, 0x06dfd91f, 0x3e2ebe5e, - 0x537e3c0c, 0x851bbcbc, 0x45ae8197, 0x74ebf20a, 0x62fa17b4, 0x1f9e0cfd, - 0xdce85218, 0x570bd84d, 0xa4291778, 0x50cc0cf7, 0x8e855f10, 0x1cf0aba6, - 0x6893e1c4, 0xd9b7171e, 0x64707f68, 0x91f70449, 0xdfe50ab5, 0x10e3e9b0, - 0x7b2f33df, 0x0c9df4ee, 0x8d7ee6fd, 0xf1e53dc7, 0x7dbf8ff3, 0x8c44e5f9, - 0x2c781417, 0x46afff84, 0x167aff3f, 0x2d380389, 0xa1285854, 0x25bdfa0f, - 0xefc5bef6, 0xdfe3cd6d, 0xfbba5377, 0xdefd5f39, 0x3abfcae4, 0xd8e40e7d, - 0x5df300fb, 0xe1a30e98, 0xfd5db315, 0xaf0e669d, 0x1e1621e0, 0xe42ae3c2, - 0xe139d33c, 0x9ffe821d, 0x99b3d3fb, 0xea4ed768, 0xe5c09518, 0x17b230eb, - 0x385ec282, 0x3e09bccb, 0xa1d7ca17, 0x79fe7409, 0x8ac77650, 0xec2adc2b, - 0x7c625fed, 0x751da409, 0xfb4646ac, 0x1f92758d, 0x60e75437, 0xb7c4639b, - 0x9f86abe4, 0xfe0de04a, 0x8f3c6ce4, 0x842fe3e1, 0xbc6609a6, 0xa938cdb5, - 0x0789e98c, 0x74df7bfc, 0xe14df51e, 0xc23df68b, 0x35b3ab77, 0xfc862f37, - 0x6fc05db8, 0xc82ffee6, 0xf36979ff, 0xefd21b06, 0xcb3675a5, 0x2aa96af9, - 0x6cb1b1ec, 0xe66bce2c, 0x0b3ba77e, 0xf65072f1, 0xb0673c61, 0x88168cf9, - 0x0d182e71, 0xfd1fec4f, 0x9d555be9, 0xdab76bf8, 0xbae11f30, 0x430723fb, - 0x56977a3b, 0x9e6b1a53, 0x9e7cec03, 0xedc3590b, 0xfdffd263, 0xc3a93be0, - 0xf68c9915, 0x7e131d67, 0x63fa688f, 0xb767c744, 0xafee30b0, 0x5ca2af68, - 0x68cf5b38, 0xdc90077f, 0xf037768f, 0x7eccf7fb, 0xb69b8b9c, 0x82f512ff, - 0xc749668a, 0xa50a8623, 0x6d3f4355, 0xc65129b0, 0x6bc3387d, 0xa3eabbc4, - 0xc5f137af, 0xf8215556, 0xfbb0981e, 0xe3f71c66, 0x9ea18d36, 0xd3b17fe2, - 0xc7f8fb83, 0x07c499cd, 0x57ebadbd, 0xa9aaec55, 0x972a3748, 0x30f4d187, - 0x92ce3eaa, 0xf40e4cbf, 0x699afe47, 0x8be25d6f, 0x6befbf81, 0xbc173892, - 0xfe16f940, 0xbdbe4cff, 0x80b7c869, 0xa3e2679c, 0xf90f5abe, 0xbe4b1a96, - 0xa9bc962d, 0x7bc5f708, 0x5e22a686, 0x26aabf17, 0xdb6f92c7, 0xe739f8aa, - 0xb94e2233, 0xdbe411a3, 0xadf24db7, 0x8c5be411, 0x5fbf9078, 0xff0b7ca8, - 0x36dff0d7, 0xd6316f94, 0xf9566bab, 0x08f9a636, 0x8d31b7c9, 0xaf3c4b36, - 0x7c9f3b5d, 0x47af9293, 0xeaa0f8fd, 0x3f418f8b, 0xfe3e84db, 0xc44b888c, - 0xe5ce5071, 0x7f8d3a6a, 0xe2ee72a1, 0xff73950b, 0xe4367045, 0x8c1de2dc, - 0xd27b9ce2, 0x8b739721, 0x939c8177, 0x9cb91e90, 0x7187bc5b, 0x7c945cbf, - 0xbe43d91b, 0x115faa31, 0x4d83ede1, 0x02df0fe9, 0xabf58dfd, 0x1fd4073e, - 0xc6ef2ddb, 0xae5de599, 0x7adc10a6, 0x1783bbc8, 0x0876ef26, 0x6c720779, - 0x68d7ca08, 0x5b35f0fa, 0x8f77c1e3, 0x2bff5e3f, 0xcadf97e4, 0x86f8de74, - 0xbd0f9f8d, 0x1678fe36, 0x6263d7d2, 0xdc848b3e, 0x510aaf6b, 0xe45e53ff, - 0xf1772beb, 0x468af138, 0xd4561fae, 0xfc2f614b, 0x17c27733, 0x78bfce1a, - 0x2152c48f, 0xebcecb3f, 0xf38d27b3, 0xc3233632, 0x720b0f44, 0xbfcfc94a, - 0xf40e6140, 0x72ba97e3, 0x5bfea24f, 0xfefdc39a, 0xf17be2a5, 0xd0abadab, - 0x88fc5dff, 0x46a5e744, 0xe711ab7c, 0xa26e23db, 0x77f91979, 0x6627e3a3, - 0x99a9b88a, 0x1bc294bf, 0x947fc462, 0x7fe6b16e, 0x966ff822, 0x62f04adc, - 0xe331cbaf, 0x5d7a8c38, 0xe0283a70, 0x7ed32754, 0x802705da, 0x27bd379b, - 0x33d3009c, 0xe1ba5232, 0x585bfc52, 0xebef566f, 0xbd16e035, 0x5d7fc36e, - 0x0de9fa2a, 0x7b9c060e, 0x1dc05fac, 0x939202ec, 0xa758f0d1, 0x33b5f975, - 0xe8094e31, 0xe84ce486, 0x181700d7, 0x70d26f2f, 0x47977dcb, 0xd664fd05, - 0xe1829a4c, 0xae30b30c, 0x6a0bca1c, 0x0fdcbd17, 0x1dee31e0, 0x4edc58ef, - 0x0f609b2f, 0x56ec39e0, 0x41c92767, 0x35db0e83, 0x141c07ae, 0xbfddddf0, - 0xf9d93272, 0x7a8e924d, 0x24e23048, 0xae0106b8, 0xa828ff78, 0x8106fc70, - 0x0eff911e, 0x8719f23c, 0x8bc91ee3, 0x635c9dfe, 0x40bc42bf, 0x8e66ccfd, - 0x22586097, 0x4eb164bc, 0xa8a97f3a, 0x84117c95, 0x8206d35f, 0xe19f219f, - 0x93c665cf, 0x58957e89, 0x4c954bf4, 0xa8a965fb, 0xf35ed337, 0x99e7a407, - 0x036caa4f, 0xfbfe1b81, 0x4f3e7a2a, 0x9e34501c, 0xb6bc04da, 0x085d3c21, - 0x77ae4eb7, 0xfba0be45, 0x50794650, 0x39e05909, 0x5f73d1e5, 0x0671af09, - 0x518e90bc, 0xcbe735be, 0x92682f98, 0x9ef4df58, 0x50f3c5eb, 0xef17bf33, - 0x7ffbc239, 0x18b1f24c, 0xba60beeb, 0x8b9e85ee, 0xbcf16e80, 0x8eba37a4, - 0xd23b5386, 0xe9bab7f3, 0xe76735f9, 0xe7a44ca1, 0x43f7123d, 0xce5a2734, - 0x1e763d35, 0x09d5b5f7, 0xeeeb0f74, 0x6df5557c, 0xcb90c6f4, 0x7ed1ee82, - 0xbb37df30, 0xf1821704, 0x141c5ba2, 0x18f347ef, 0xb353f5c2, 0x64e6de7c, - 0xf567d7c9, 0x2edbbfde, 0x37278cc5, 0x3f2323f4, 0xf8c3c71a, 0x6f1826f9, - 0xd178f764, 0x2fe183fb, 0xfabadf38, 0xbad9bfdb, 0x6ebe718c, 0xb590543c, - 0xb88d5e10, 0xe05223a8, 0x73ea2a47, 0xfc4b25d3, 0xc85ccc15, 0x7fdc6fad, - 0x7bdc96aa, 0xa74d2cff, 0xebb774fb, 0xe89d77c6, 0xe2674f33, 0xdbe26f7c, - 0xec7fefb8, 0x5998e7e7, 0x44d6f636, 0xab263fdc, 0xe3eae90c, 0xa1f92a43, - 0xe3ca9e3f, 0xedf9af6e, 0x3e5d0501, 0x3898f0d7, 0x8938cd76, 0xb037acec, - 0x87a8f1eb, 0x047f983b, 0xef132fc1, 0xd5d465ed, 0x5f02f14c, 0xae12dd8f, - 0xa537d4c6, 0xc435e933, 0x219924db, 0x7dfc5ade, 0x7f20b8a7, 0x032c87fb, - 0x1fa0a05d, 0x07b1fb50, 0x9bd63259, 0x33264fe0, 0x27e37c66, 0xf3075e6f, - 0xf6487f18, 0xacdea179, 0x03172e03, 0x7ae47a7d, 0xe0980b1b, 0xab858135, - 0xfe34dfd1, 0x9c3affa8, 0x3be81177, 0xa8a44f78, 0x07b54379, 0x6a25ebf3, - 0x72050c1f, 0x6d9eb03d, 0xbf7267b5, 0xea017285, 0xf5c13761, 0x4eb05ebc, - 0x728861f2, 0x8a5af341, 0x93a82a2f, 0xb6e142e8, 0xbc1cc4b0, 0xfa03b0df, - 0xda1eb6dd, 0x05fee167, 0xbadfb1ed, 0x875e6f33, 0x49e60772, 0xb9f9ebed, - 0xf3b4017c, 0x2dd4bf22, 0xd78afea2, 0xb3ef0c4b, 0x7df3d514, 0xea90e8a9, - 0x7dc6f2c3, 0x3b7ed08f, 0x97ebc603, 0x6450fb8e, 0xca0bdd2a, 0x2fba7494, - 0xf84c1a19, 0x7f1c60eb, 0xf220fa6c, 0xabbc520b, 0x98a0c097, 0x64fe63e3, - 0xb3f2421f, 0xeb4cb7c0, 0x96bcfd0b, 0x236e9c93, 0xe7433aba, 0xde0147ed, - 0x1bf78001, 0x40e55e22, 0xab5a07ce, 0xc2fc5f69, 0x9b9f943e, 0x38a24d34, - 0x8f2c858e, 0x8e6638e2, 0xebe6fae7, 0xe8c33b97, 0xed5d7be7, 0x0fdf881c, - 0xefa76e5c, 0x1cb8dbed, 0x4ad41f6e, 0xebe3f6fe, 0x58f78655, 0x24cbd7aa, - 0xabd78e2f, 0x7e563f74, 0x1431c78c, 0xc7fae36e, 0xdfbcf581, 0xe1b7a8e3, - 0x439607b9, 0x11ab70be, 0xb4e5c0e7, 0xe8167f61, 0x90c2fe3c, 0xdd62e5bb, - 0x75a1f63d, 0xd92434cb, 0x2e5b7968, 0x8b0971e4, 0x2d1cbd90, 0x1cf1cb77, - 0x197c83dd, 0xeae6271d, 0x0e9063b6, 0x5d105f22, 0x19521c57, 0x07d231da, - 0x9714b96d, 0x73a247b6, 0x92cdf18b, 0x8a1ae31f, 0x4987b1de, 0xcfe70eff, - 0x2fee11fb, 0x8619daef, 0x3c431f2c, 0xb1ca9c80, 0xa7e9fe77, 0x1be4fdf0, - 0x02088c0e, 0xb827c9ba, 0x59be711b, 0x4f3c799b, 0x52eb1bd6, 0x9b2f3ef0, - 0x40e497da, 0x02ccad61, 0x52713926, 0x13775ff2, 0xd4741fdf, 0x667c0c77, - 0xb8053569, 0xc1cb7ebf, 0x66ef55f7, 0xd8646315, 0x043d84ef, 0xf51f81f6, - 0x6b5de29b, 0x1d133453, 0x9b59ef14, 0x55f7c322, 0x1aa61e22, 0x576857f7, - 0x8a71f1ac, 0x06fa4af7, 0x3f4638d3, 0x2edabf46, 0x1ee86ede, 0x7fd6f69e, - 0xd68fce31, 0xf286a9f9, 0x1e9fba22, 0x4fd2f7e3, 0xadcfefce, 0x395e6093, - 0xac14cbaf, 0x8cc1f39e, 0x1d73e6a1, 0xcafc3523, 0x98da6fd9, 0x9cbf04df, - 0xbf31c53f, 0xe38ddf09, 0x7f01ef80, 0x61493757, 0x23f984a7, 0xe516795a, - 0x0af3e475, 0x98ae7fe1, 0x1aebcfca, 0x8158de33, 0x4b233f7c, 0xa1607a22, - 0x8937d680, 0xfa2f35f4, 0x78b30bfd, 0x8f6842fb, 0x08f8d8fc, 0x13904fe7, - 0x1523945e, 0x52e6d7eb, 0x8bc93afd, 0xc86e37fd, 0x28a47d27, 0x5e546647, - 0xa3f48477, 0x4923a6a2, 0xb7c0c7c8, 0xa81f50eb, 0x51d76898, 0x68fc1b8e, - 0xe2ebf7f0, 0xe8732b3e, 0xc67ef1a3, 0x8be646ff, 0x21f2d7c1, 0xf583d72e, - 0x39831f9c, 0xdf5f5f9c, 0x2f0ae2a6, 0x9f89bf84, 0xfce16f8f, 0x43763f2a, - 0x2f87de2e, 0xc3efccdc, 0x453f581f, 0x78fa7d43, 0xa6fda258, 0xbd737f27, - 0xabbf9a35, 0x7defbe25, 0xe0d2fd5d, 0xe18f836f, 0xaf1c6aef, 0xef14f80c, - 0xf5f3464f, 0x0fe1b54c, 0xaf7cc3b7, 0x03d61a79, 0xddf29df3, 0x26ad3d3b, - 0x14f90939, 0x3c2817cc, 0x2b90cb9e, 0xfb8f0ae5, 0x8bf3dafb, 0xb76c3f1a, - 0x677e47fa, 0xebf1e44f, 0xfdd12a75, 0x07b3f8f9, 0x7f205d9f, 0x9d5f285e, - 0xf18d3f8f, 0x7ed63de5, 0x2de8277e, 0x8076bfba, 0xfae0046b, 0x8a26fd4a, - 0xa9e8fdf3, 0x3f113323, 0xce81bba5, 0xddeabe91, 0x4e72822c, 0x557ed309, - 0x3dd328d2, 0xb244a601, 0xf99b73af, 0x956dc798, 0x7a26e33e, 0x1ed6792a, - 0x4bed019e, 0x86307e76, 0x779668e2, 0xe85a5c52, 0x872fa129, 0x1f20c75a, - 0x7e3c2894, 0x042e5a2c, 0xd70fdc1c, 0x367e2bb6, 0xc2da4fae, 0x69288fdf, - 0x9bb551b8, 0x746e25ce, 0x3a3d46a8, 0x1d010dd7, 0x9c5dfde3, 0x02ddf99f, - 0x6dac6e23, 0x2513972b, 0x81d92a4d, 0xb7b65b25, 0xc970fc63, 0x77f2763b, - 0xa19cb705, 0x9e5310fb, 0x94fe46d9, 0x396c9360, 0xb711eb7f, 0xd88e45b9, - 0xb1b0ee31, 0x211dce9c, 0x0df2847f, 0xcf97e3b1, 0xfa585f17, 0x219d9ecc, - 0xafe96100, 0x7ca0f49e, 0xd9b2d539, 0x7e877083, 0xba6e32bf, 0xc3669c47, - 0xa7195f3d, 0x01ff0a79, 0x438f738c, 0x9c4635d8, 0xa4be96eb, 0xb2fcc247, - 0x739c62f3, 0xdbe5e974, 0xef1c7d3e, 0x7b3db411, 0x6f9c71fa, 0x7e3e3fd9, - 0xd8c1e31c, 0x77ed275e, 0xa2dea7c1, 0xdda36c38, 0xb5dfb126, 0xe2927d6f, - 0xb5dfdbd7, 0xf6b7b0fb, 0x6307c73d, 0xf6fb603c, 0x6fd0522f, 0x34cf64b9, - 0xd92eebf2, 0xc5952531, 0x148c2fd8, 0x017c36e9, 0xf8d1f3f1, 0x8078d03a, - 0x023ed6e2, 0xebfca37c, 0x286dbb8a, 0x5ecc71e7, 0x1f5b6f11, 0x8f429efb, - 0xebc6daf8, 0xe51cb9ae, 0x1fd7237e, 0xfb671bcf, 0xdbf1e026, 0x7abf8017, - 0x1b102fc3, 0x3fe11f7f, 0xa2fb4f00, 0xe369f7f0, 0x8a3c5fc2, 0x7b7d8d65, - 0x5c8db38d, 0x7b8cdc00, 0xfc380f10, 0x88c91c87, 0x5c525fe7, 0x866de233, - 0x4f9ff717, 0x91fde307, 0x5ce76a13, 0xc7b85fba, 0x68bc63ae, 0x89b79ec9, - 0xbc77da7f, 0x26687e41, 0xb3b423ee, 0x3f1e3fae, 0xd675892e, 0xae7c79b9, - 0xefc63f80, 0x5df43d7a, 0x3a72e9c4, 0x7b77e236, 0x9d95db8b, 0xee36cf5c, - 0xfdd79467, 0x76c3c451, 0x41ca4be3, 0xcaf91d3c, 0x0e036878, 0xddc390ba, - 0xe3b1e871, 0x2beebba3, 0xfe217c08, 0x8aea1f70, 0xc0fc8733, 0x7a37e4b1, - 0x0790c59b, 0xfc781bed, 0xfb1abb7a, 0x9711b05e, 0x3e688ffe, 0x3c585f0d, - 0xffe6f9fa, 0x81d3e175, 0x4f724fca, 0x2dfdb538, 0x774f1cb6, 0x9eecdf4a, - 0x7d149961, 0x1cebca6f, 0x473b7187, 0xbb83b434, 0xdeb16cec, 0x6f57e136, - 0x78a64a7b, 0x070d55e5, 0xcb478e48, 0x2f7c0a8b, 0x337cc625, 0x9a2b7cc5, - 0xf6d13ef8, 0x82ec3bac, 0xeff6da7e, 0xa8ae7a22, 0xd2f1423f, 0x95f96f2f, - 0x8b8a6ad6, 0x6c227dc0, 0xd3db7f9a, 0xdc90c6fb, 0x44b2ef16, 0x8c49338f, - 0x3d8e6c13, 0x8cfeb04e, 0x50d29c65, 0xcebba683, 0xc529de3f, 0x77f6237f, - 0x83eb85aa, 0xe9e41aa7, 0x0fe318e1, 0x77d6aa73, 0xa4bf60a1, 0xfcdc67f7, - 0x13d919bd, 0x12e5fa47, 0x093bce77, 0x146a9849, 0x4cbd55af, 0x87fd77c4, - 0x5df10d2f, 0xe18abeed, 0x7c22577c, 0x551e7e4d, 0x4bd4300f, 0x2cbcb4d5, - 0xcb442bf4, 0xc6c92d1b, 0x2ffc26c2, 0xf54f4f71, 0x644779d2, 0x70f3e220, - 0xfb1571c6, 0x9f944bfd, 0x5b0a2fea, 0xfbf30a95, 0x2df2484b, 0xdfd97e83, - 0xe794183e, 0x977fd9ee, 0xd963f11e, 0xb0aa57e2, 0xbb461e77, 0xa4e0bd84, - 0xaf7906f8, 0x08f9de93, 0xf5a4ee3e, 0xf9f1d81e, 0xff5fa413, 0xb9f8cec2, - 0x202f580f, 0xde750aaf, 0x9f1df1c7, 0xd457fe3f, 0x8c31b19f, 0xd438f85f, - 0x3ea1bb47, 0x8e9cec9e, 0xa0c61367, 0x85f0a45f, 0x3ca266bb, 0xf4e78c2b, - 0x6a4cf858, 0x3bfa1ab8, 0xc7f3cc96, 0x77a20db6, 0x759f4a25, 0x81e8dc53, - 0xe055cf1d, 0x4cfed4be, 0xa97dc33c, 0xe7a105fd, 0x53bc52ff, 0xcd7aab55, - 0x4cc5e3f1, 0xf3ef9af1, 0x12de6294, 0x2fc8c4af, 0xfe847c41, 0xba04a6aa, - 0xaffa0407, 0xd48f9fa5, 0x447c3bce, 0xfcfea1c7, 0x3fa453fe, 0x7ae883ca, - 0xcebdf946, 0x395ee221, 0xd77573b4, 0x059d6a0f, 0x9fd35f3c, 0xaa1693cb, - 0xf853b0ff, 0xcf79458f, 0x87fd797e, 0xeeeefc84, 0x10afb787, 0xd344d0ef, - 0x6fd146ef, 0x5fbf96e9, 0x959deb1c, 0xefa7f318, 0xc858943f, 0x76ca7a86, - 0x857fbd27, 0x7de028ef, 0x3f1a9d85, 0x44f32ad7, 0xdd9b9de8, 0xc5971e42, - 0x9ddde845, 0x581e62fe, 0xd1ccf31f, 0x9fbd34fa, 0x61939cf6, 0x0bf9595c, - 0xbbe23f6e, 0xc7e7e77c, 0x71859e7e, 0x1714f189, 0xffc2fe5f, 0xb7283a22, - 0x3f22e647, 0xb3b76e74, 0xdbe7c88d, 0xfc8c1d5f, 0x0646a6da, 0xf38af9f7, - 0xbb06f2ba, 0x58bffef5, 0xdaaaa9c7, 0xbbbef0cb, 0xa4b6af71, 0x57f33917, - 0x5fa3d727, 0x725ffa71, 0xdf5bbf12, 0x35553a73, 0x59df133b, 0x3897ea30, - 0x77c5cb62, 0x137c5e51, 0x71eaee39, 0x9c5df53f, 0x25ac47cf, 0x153efd05, - 0x3ca377a0, 0x3e92d92f, 0xfb04fd10, 0x043bc69d, 0x8fdc04de, 0xb25eabf6, - 0xef3531a7, 0x7caa2733, 0xf430ca99, 0x54cc8cdf, 0x1b1d1d60, 0x67f414ce, - 0x9cea4718, 0x9dee4b1d, 0x3ad3c676, 0x98f61c4a, 0x09cf9df7, 0x8d0f7aba, - 0x1e3e64fe, 0xee3187f2, 0x724c357e, 0x2f388ef8, 0xbb012bd5, 0x6e97bf08, - 0x79699399, 0xa1a9457f, 0x04a7c07a, 0x4eb662cf, 0x6fc932cb, 0xa5e2bc63, - 0x264a9959, 0x4ffe577e, 0xddcabd17, 0x24a16678, 0x01150bd2, 0x9faeb663, - 0xa2887ee5, 0x7e1039e6, 0x15d3cb1a, 0x86a54919, 0x358e3df8, 0x7502ea50, - 0x5653bf8b, 0x9e4e50c9, 0xe8f6e710, 0x1bb4c2ef, 0xdc92775e, 0x6c620d0f, - 0x07be3a78, 0x4dd04de1, 0x10f153f0, 0x5763e61e, 0x1797192a, 0x93b47433, - 0x7d8050a5, 0x5d54f409, 0xe9133d35, 0x18fcfe11, 0x07a64907, 0xbfa3cfcc, - 0x41ea05fc, 0x3dfca740, 0x70b2efbf, 0xc3188035, 0x3aafc981, 0xe877f199, - 0xccc3bf56, 0x71a5c6f6, 0x68e77892, 0x1731c91f, 0x84ebfeeb, 0x94558a3c, - 0xff09d5b7, 0x4473c1c8, 0xa822ce97, 0x58bbc617, 0xd7521e24, 0x9994e528, - 0x90593dff, 0x3ea9d137, 0xcd1e5ad1, 0xa2d72017, 0xf8206dc6, 0x449fbf41, - 0x5449fbf5, 0x557c9fbf, 0x829c06bf, 0x7c3e8d8e, 0x556562a7, 0x1f1b809e, - 0x06e021cf, 0xef8919f0, 0x9c5b31e8, 0x13879c4f, 0x6cc4e35c, 0xf01f58ec, - 0x4e971e5a, 0x612fb978, 0x41c6276f, 0x865aa4b3, 0x890aef76, 0x97f0d3ef, - 0x63b532e7, 0xf0f883ba, 0xb94e311e, 0xc30af380, 0xbea3d53f, 0x1eaff493, - 0xd5bd9df5, 0xdf5d8b8f, 0xe27cdbdd, 0xb127cf63, 0xe26bfe97, 0x75fff663, - 0x0bc552e5, 0xe786bf6f, 0x49f25db6, 0xf55bd007, 0xd438f2cc, 0xfd8f1333, - 0x70be95a3, 0xd031d33d, 0xa438ef8a, 0xb8b7a06f, 0xd1efd661, 0x7d1bd274, - 0x40758be5, 0xe00fd5de, 0x7f189370, 0xf73f1d6a, 0xf70965be, 0xe87981d3, - 0x8b37fac7, 0x0a3937fa, 0xc470dfc9, 0xbabfdfc6, 0x91eb96a5, 0xa658fcb7, - 0xef1ee9f3, 0x803fe151, 0x2a5d6edf, 0xb1e92385, 0x7562d7de, 0x9e6e3f78, - 0xbdfa3f18, 0xe6f300aa, 0xbd6396ae, 0xd2e9c557, 0xfd1757b8, 0x9602c54e, - 0xb321de27, 0xd4eb3f7e, 0xcd67e4bb, 0x2c7deea8, 0x1ee816b4, 0x7ba04ff5, - 0xebc7973c, 0xe2171462, 0x485c78d1, 0x4f3a20cb, 0xd9dfe433, 0xdc04de91, - 0x307f99af, 0xeff3aeff, 0xa6f4af8b, 0x2a1def9a, 0xef2ce2e7, 0xbeab54f5, - 0xea6f9434, 0xc15fd039, 0x0dced654, 0x39535e61, 0xfcc4ade8, 0x7249be18, - 0xa3094d2a, 0x3cf4545c, 0xaf7a8856, 0xa8c3ef78, 0xd55d25af, 0x0ebe67a5, - 0x4b8e6fff, 0xbc5cbe26, 0xb6f74bd6, 0xdbcf8b3f, 0x7b24f489, 0x57017c72, - 0xed087a4f, 0xc6aeebe0, 0x5cf7a775, 0xf3e6b54f, 0x157dbe91, 0x6ffc8080, - 0x4fce073e, 0xf6df7bb6, 0xa37efce2, 0xf4bbf432, 0x44ef8f84, 0x86cfca18, - 0x887c5007, 0x0463309c, 0xbc46bf8e, 0x6ababa6f, 0xaa2ba524, 0xbc794898, - 0xaf2a8adc, 0xea447348, 0xaa74e917, 0x1a556f77, 0xf95557e5, 0xebe03528, - 0xfbd0d5f0, 0x7c618e93, 0xf02e877c, 0xf0136497, 0xe5fe900b, 0x73a4ab48, - 0x195ea745, 0xd8df77c1, 0x7077d840, 0xc10d7a59, 0xf919d357, 0xe53ea135, - 0x548798ed, 0xf8419dad, 0x564af452, 0xc56fe508, 0x5c228e07, 0x2d4bde9d, - 0xd3da5aef, 0x7fbd46c6, 0x836f051a, 0xb871b6de, 0x7a712fdf, 0xfdfb868b, - 0xe3178b6a, 0xb2bfee22, 0x82295deb, 0x1c43983b, 0xe7e6bfee, 0xdee13db4, - 0x09be7b32, 0xe9eceeee, 0x04fbf704, 0x7016ef9c, 0xa87816ad, 0x46acf016, - 0xa47e53b8, 0x3a44fbc8, 0xc47bd29d, 0x112bb7fb, 0x08ca901f, 0x7d878077, - 0x30c98854, 0xf179ba1e, 0x7412eecf, 0x1fc8dbab, 0xfcf2bb2a, 0x127b7708, - 0x05c3bb87, 0x06ba2078, 0x3cb17bb8, 0x5d54f044, 0x9f50ce1c, 0x15e441e3, - 0x7e267b84, 0xb800f8e7, 0x871f8df7, 0x058270f2, 0xe4d25ace, 0x23fb830b, - 0x124b7f7c, 0xbf0d1e7c, 0xafbf8d24, 0x6f77f06b, 0x88b571fa, 0xef16aeb7, - 0x511c2227, 0xe00879af, 0x4f0e34c3, 0xc8a47dfe, 0x164d28fb, 0xe0357ff6, - 0x161fcb01, 0x19c210fa, 0x73c51fd3, 0x56c93cfb, 0x38454fb9, 0xf2efe1f5, - 0x1b10a4b0, 0x6878cd98, 0x85a5fe2f, 0xc6f31798, 0x4ad7aff9, 0x44aeb23f, - 0x7de903bd, 0xdd6de918, 0xcf0daaab, 0x57a5e43f, 0xcb67ee59, 0x5e89fdb3, - 0x42407f82, 0xc13ee6bd, 0x5e916b87, 0x1edc7e68, 0xe0e8295e, 0xeefef16e, - 0xee7e823d, 0xa0fcfc17, 0x7e3e3741, 0x74cd643f, 0x9498c71e, 0x20ef1361, - 0x4e399846, 0xc0d7d130, 0xd9179834, 0xe94a5e36, 0x8ef64b9d, 0x7e36f89d, - 0x7d23f314, 0x6773be25, 0x9b43bf98, 0xa1f50fd7, 0xd9dde344, 0x39c4de89, - 0xa23d3174, 0x6520f788, 0xc4b64f6e, 0xdab5df7c, 0x7e81dfb7, 0x13e6de99, - 0xafa7f3ef, 0x6be2f184, 0xf54764dd, 0x59cde40d, 0x2d577908, 0xcb0c55d8, - 0xc1707cb9, 0xf44d0bbc, 0x5f8bdf11, 0x595d7547, 0xf64af480, 0xa93fa438, - 0xf844ea1d, 0xe8bdac02, 0xcd487abf, 0xc1fb87eb, 0xfdb18943, 0xb9e2b370, - 0x7593c4bf, 0xb09fc5a9, 0x3b53f54e, 0xde55a27d, 0x43fb13ac, 0xfe56a99f, - 0xcb83f630, 0xc59f7f44, 0x0f147e07, 0x6e729674, 0xa4cfc92a, 0x0fef636b, - 0xc216aad5, 0x47aa39f7, 0xe50ebe73, 0xee6f5c6b, 0x9d187721, 0x8c0d9c83, - 0x2ffe88d8, 0x3396be83, 0x8c42e72e, 0xbac693eb, 0x3ef4867e, 0x9d01f702, - 0x01f71ee8, 0x34c3cbcc, 0x5b949ba2, 0x587fe46c, 0x5eecf825, 0x046b5fc1, - 0x7c803d5f, 0x81df0235, 0x13fa51f6, 0x90eb4fc1, 0x12dd20ff, 0x78f5ce9f, - 0x6197bef1, 0x8c772cc7, 0xab1cf7a5, 0x0fda365d, 0x61ed7794, 0xfb05da17, - 0xf7e8ebc6, 0x7a59dd91, 0x59e58dc0, 0x43c03f0e, 0x91d2cc4a, 0x2f733e5e, - 0xe2abe8b8, 0xf4fd015b, 0x72a2b0ae, 0x949ea47f, 0x451fdec7, 0x9ef453a7, - 0xcb5faa80, 0x70fd3fd0, 0xe113a552, 0x8f3c70fc, 0xcfcdaad3, 0x3e03b826, - 0xe29bc5b6, 0x5f6752a5, 0x1f1ef5d5, 0x2f70ff76, 0x12ec12ef, 0x0c0d82f2, - 0xf92661b1, 0x7bde2b50, 0x1b10de64, 0xcb139269, 0xf432e787, 0x0f94f5eb, - 0xcdcbc8bd, 0x90ae5e5c, 0x434bcb62, 0x65e4377f, 0xd2315cb4, 0xb74d1795, - 0x5d54a7dc, 0x66f2463e, 0xc1ff6c64, 0xfcede3ef, 0xf3e66a1d, 0x2cf7a7e5, - 0xdefd7807, 0x83d42f0c, 0xf7c57f0c, 0x5a27ac62, 0xcab89e3e, 0xf40357d8, - 0xcd02d03e, 0xaff8f0fb, 0xfbad57dc, 0xd5b9e141, 0x9c140fa4, 0xa8b4a1cb, - 0x11f13a76, 0x9318d3c3, 0xfd7c7c9d, 0xdf883d0f, 0x7ce2b5e3, 0xc61abd7c, - 0x1b7da4b8, 0x0e607aef, 0xe3c175c0, 0xe38f9d32, 0x14d90d3d, 0xbcb2c2df, - 0xef1ba7a4, 0xdf0f1e23, 0x31c731ee, 0xe9d4fc14, 0x37bffd47, 0x1f582c7a, - 0x8d537fdb, 0x83bb44ff, 0x5da246f9, 0x675dfa01, 0x9fbff504, 0x18dde938, - 0x18da1f23, 0x8fc733ef, 0xf15be918, 0xdc21ced3, 0x33f78adf, 0xab9dd217, - 0xf4d79d0f, 0xdc7c17ce, 0xc733e863, 0x4547d273, 0x7dc0359c, 0xca7fc596, - 0x098f49cf, 0xf473187f, 0xca271e52, 0x7b94bdbd, 0xd3133c78, 0xd3ff9763, - 0x3d51a47e, 0xb821b4ec, 0xd3daf2fe, 0x2fa5deab, 0x6280f3d6, 0x60bdc711, - 0x79787c63, 0x2059be0c, 0x102f07ee, 0x7d065de7, 0xd0df7f15, 0x465d39b3, - 0xd4f4add3, 0x1fa74425, 0x5fc9541f, 0x87f4015b, 0xd4f4987a, 0x698f7a78, - 0x3d9713d9, 0xf9c00b78, 0x95324393, 0x10739d97, 0x87ffb65d, 0x3bfce28f, - 0xefd2ab7f, 0x70727c26, 0xb7ebc51a, 0xbb9ef78b, 0xedc5cef8, 0x5c5c1bda, - 0xbb9c14ae, 0x8bbbe897, 0x35f3c2ae, 0x7382dbe4, 0x565e900f, 0x4ebdef80, - 0x788f75c0, 0xe8229279, 0x1fb60277, 0xea1cbb92, 0x3e72b615, 0x15431361, - 0x10de8fe4, 0x0637bbef, 0xf2e0df3f, 0x0b45e25a, 0xff50d75b, 0x24c3f40c, - 0x02c85c53, 0x8507fbf1, 0xe584b878, 0x21a5887a, 0xd6f908df, 0x77d6ff4d, - 0xd69ddbb0, 0xc2e91a75, 0xb04e75ae, 0xebdd61d8, 0x73e72efc, 0xb6146fa1, - 0x7579f0e6, 0xe3e7e7ad, 0x7ba7ad63, 0x7da9131d, 0xf1ec627b, 0x1fe317ef, - 0x9bc22aab, 0xbc44ac5b, 0xbe105bb7, 0xd5f7c35d, 0xf627d60a, 0x2aeb4c91, - 0xc4b52dac, 0xe6d4152b, 0x857afbd3, 0xdbb5f3eb, 0x1753fb4c, 0x97fe425e, - 0xc6eb0d27, 0x2e6bfdcb, 0xaea8bc23, 0x7e913bbc, 0x7c553d8f, 0xec5e7bc7, - 0x84e9e397, 0x49531a16, 0x4f76eaf2, 0xf74dfbac, 0x56a9e347, 0x80ec09e0, - 0x0c9e132c, 0x3fb744fc, 0x8efcb9b6, 0xe21cf0f7, 0x509afe11, 0x0a2bf2ef, - 0xe1b1e97f, 0xd7a0a4f7, 0x040fa063, 0xdf7e082e, 0xf5cbc4b2, 0x6f813f0a, - 0x77c63e03, 0x08c2e7d0, 0x379127b7, 0x4e3fb193, 0x5b83e70f, 0x1e82f8f7, - 0xcf5ec526, 0x59eb5d6b, 0xc7a042ca, 0x3eb8d49c, 0xee7afbd1, 0x05c72162, - 0x4f8ba7ac, 0xfa7c2df3, 0x385b9ada, 0x9ffc0a9f, 0xd10f7fdc, 0xbc70b1f5, - 0x7a54e30f, 0x486bcf5b, 0xd062e307, 0x1b10b0c1, 0x8f7ffd95, 0xfe684e0e, - 0x3ee08f11, 0xee15fb02, 0xde4fc5d3, 0xbf3cc63f, 0xfd27e2b7, 0x9aa5f69e, - 0x0ea73b0b, 0xf41df64d, 0xfb277ed2, 0x434961aa, 0x633f815d, 0xa3cf12fb, - 0x6e9fa19f, 0xc6cfe245, 0x578bd2c4, 0xc72e0556, 0xaaea8bf3, 0x8fd1cba2, - 0x973d0aaa, 0xce9b9ea1, 0xd623177f, 0xcdcc7d7b, 0xaab2bbf1, 0x983fce92, - 0x94f4c423, 0xd80077ee, 0x47f24c89, 0x7eab2e2b, 0x1d01a9a6, 0x789adffd, - 0x025540a7, 0xd0b3d3ab, 0x1194945f, 0x1fefc132, 0xb2ee7e2e, 0x8ebf6d26, - 0xe8761ae7, 0x8e60fd1f, 0x8b59ca81, 0x6545ecff, 0x93c05f41, 0x1c731cf1, - 0x124bf06b, 0x46cf13f9, 0x5acf13f9, 0xf30491e6, 0x5b3b0afe, 0x1ce87871, - 0x8fc26152, 0x5f01e02c, 0x5bbb1f68, 0x1e5cebe7, 0x607d21ef, 0xb23645d5, - 0xff09d6eb, 0x2fd0cff4, 0xe851704d, 0xe0c301bc, 0xc096beb0, 0x73c4e1d7, - 0xaded190c, 0xf8dde508, 0x4f4c9762, 0x4f984a1f, 0xf3095e64, 0x1564597d, - 0x931d0fda, 0x3f20ef5a, 0xe69033a0, 0xd67ebc06, 0x84b0e5af, 0x817912e7, - 0xb5ce118b, 0x0bc32872, 0x77217ff5, 0xc1bd6066, 0x1f4ef450, 0xf7845e9e, - 0xf3a60212, 0x8eb421ce, 0x33dcbcee, 0x2552d17f, 0x6feffcea, 0x5fcb9b17, - 0xc62ffa71, 0xf93b5479, 0x1f4960fb, 0x57be7448, 0x94ee75dd, 0x64f2fb47, - 0xd123c737, 0x41d5d205, 0x559d37ae, 0xc87d09bc, 0xf3323d9f, 0x7c3ccb45, - 0xec22bc96, 0x53a03ad1, 0xe832a73c, 0xb7e29863, 0xaf0d1d21, 0x3c66ef81, - 0xfb77d0c6, 0xf079e8b8, 0x31b9fa98, 0xe897183f, 0xcb973e55, 0x7a28e3f7, - 0xf9f12dd8, 0xdced8a87, 0x1921646e, 0x20c73af1, 0xcf05653c, 0x8fe33227, - 0x8d77b5ec, 0x82b62773, 0x0b9e75e7, 0xb9cfc6de, 0xa733e7a3, 0x3c16eef9, - 0xdcd399ef, 0x7b9e3e6f, 0xf8ba29ce, 0xab774c43, 0x51e3fb9d, 0x2250fc5e, - 0xb7a6f67d, 0x21e3545e, 0x46e6f1dd, 0xae609f7a, 0x73bfef9b, 0xf88aa759, - 0xe35d300f, 0x5a6156e7, 0x27cc6ddf, 0xfa2a0df2, 0x84896e1d, 0x721ab86f, - 0xbe18beb7, 0xb9bdd51a, 0x425f3b07, 0xf41a05b4, 0x321b3a5c, 0x5ef935da, - 0xaede79e6, 0xf14e0e0b, 0x838a47fb, 0x6ebdd5d6, 0x58c1c107, 0x7c24d427, - 0xbc49c174, 0xa5c066cf, 0x37f1dd6b, 0xf8fe855f, 0x1cdce4de, 0x790fe8c7, - 0x579f3c9c, 0xc13e9c34, 0x0b939022, 0xb91ffedd, 0xb77afca1, 0xcb4c2eff, - 0x95839d1c, 0x5537c421, 0x0390af98, 0x1c00a517, 0xb8141a3e, 0xd1e11938, - 0xf482f7d2, 0x2e4ec3fe, 0x1ba70e0f, 0x1bab6d7a, 0xc8bd9be9, 0xf7e35af5, - 0x38ed5632, 0x008dff7e, 0xe55e8f9f, 0xcb95cdef, 0x22ee6bde, 0x62ccb2ff, - 0x7a4621d9, 0x1e0df858, 0x7bc4db76, 0xf39d7cd1, 0x79ef0e14, 0xcf74f18d, - 0xd952de6e, 0xbcfdbef2, 0x957e3ca5, 0xae632d29, 0x2b09d8b7, 0xecf75d04, - 0xd11afd07, 0x3a5fccfd, 0xd92dde99, 0xc893e9a9, 0xa738f1cf, 0xfd53f9b3, - 0x4ffdc632, 0x1f912d58, 0x6f51fc69, 0xe7e42b53, 0xc87d1387, 0x5ceff3ae, - 0x97ef899c, 0x3f70b454, 0x28bcaa67, 0x7d203fe3, 0xefdf3f68, 0xe108bf31, - 0x5d7bf2e4, 0x369af3a6, 0x474332b5, 0xe5d5be7a, 0x7f907947, 0xc45dffbd, - 0x30e7e1a7, 0x40e7ddf6, 0xce38c00f, 0x39bc5bfc, 0x0df91f48, 0x0ea53f4e, - 0x5c81c4a6, 0x039857cb, 0x298d54d3, 0x98e34c4e, 0xe5ecd303, 0x9daa7f42, - 0x2783fa45, 0xf7c34f27, 0x9f9bf3c4, 0x17db14fc, 0x927d912a, 0x9bf29e89, - 0xee82fd5f, 0x28f3f9c3, 0x5b5bf74e, 0x39dd8b34, 0xff9ac1ba, 0x9f359376, - 0x33e6b111, 0x03f35a0f, 0x7d266d70, 0x1e1eff73, 0x9a7a529f, 0x1e7defdf, - 0x3c22a060, 0x3e49d9b6, 0xce6d294e, 0xd38778c6, 0x586dbb4f, 0xdceffbbe, - 0xeadceeee, 0xf72577a4, 0xe2c717bd, 0x6a1df092, 0x3f2c46e7, 0x8d90d71d, - 0x4fa845fe, 0xbbb04b71, 0x71bb408e, 0xbd06a5e7, 0x69be2986, 0xfdf83fe7, - 0xf6adce94, 0x9c51c630, 0xd3e4f5de, 0xb7a79f48, 0xec7d200e, 0xc3642979, - 0x70f7437e, 0xf3884ffc, 0xe954e458, 0x7e3dab16, 0x1d01e842, 0xe879b527, - 0xd6b8ba17, 0xc24beeba, 0xa8a77cd6, 0x7d331b7f, 0x10f8c74f, 0xdc34aaef, - 0x7ec53767, 0xc173fdbf, 0xa53d4f17, 0x8b2b7419, 0x37991ef7, 0xe2befba5, - 0xdb73eeee, 0x8e800325, 0x4316114a, 0x4697bfba, 0x0f85db8d, 0x38927fd1, - 0xadfceb2f, 0x5539f04c, 0xef896455, 0xaafbd2e8, 0x4d53697c, 0xed4151fb, - 0xd27c94be, 0xdca5f757, 0xca67da66, 0xb9481eb6, 0xdb6bfa19, 0xebefd0a2, - 0xe279cd95, 0xf8490981, 0xf9c06e5d, 0xe7fa3962, 0xf25e1ada, 0x8bd03d60, - 0xbde39ac7, 0xa5c76b0a, 0xe9f1354d, 0x834ba5d7, 0x0e74ca9f, 0x5a72e79f, - 0x461ef172, 0x1dff2d69, 0x1b86d2be, 0xe11abbae, 0x4fdf9ebe, 0x9e5856cf, - 0xb653fc0c, 0x8fef86fd, 0xc7c1ef86, 0x3e70f9c6, 0x2d24f8d9, 0x3fadbbde, - 0xee76f743, 0x44ff71b5, 0x7b465c34, 0xfdef7e38, 0xe508ab81, 0xa2f7f412, - 0x3fb52c6d, 0xe47d0368, 0x6bd0e4c4, 0xd3954337, 0x570fe1ac, 0x95965c53, - 0x253e809e, 0x373ab7d4, 0xf48dbe4b, 0xb5f67975, 0x97fb5aa8, 0x943a3c51, - 0x8a37b4c7, 0xa27ed6c3, 0x47a57cf1, 0x68f77e32, 0xa25e99a4, 0x119df5eb, - 0x2ab7dfa2, 0xcd720a5b, 0x1d97efa4, 0xd878a1ad, 0x19c871e8, 0xc13b8a68, - 0x7c4bd1fd, 0x027a14ec, 0x22d91c93, 0xcf287c5e, 0x48a7bbd3, 0xa5104097, - 0x5ea9b297, 0x6cb5eb84, 0x4bcfa63a, 0x99640791, 0x33f203cb, 0x79278b6d, - 0x3eb7a6d0, 0xa3a473f1, 0x1e74d1fa, 0xefdc5fd6, 0xe846f36e, 0x77e358bd, - 0x9e74da71, 0x5276692f, 0x8fe9d53c, 0xcb979234, 0xeb138e30, 0xd9b4ed3f, - 0xbd3b5f40, 0x8c64efbd, 0xe06b6e0b, 0x6a9f8aef, 0xfb593be8, 0x9a37fd8a, - 0xf17d8def, 0xdf13fe08, 0x8bf8f54f, 0xacdfb83d, 0xa9d371e0, 0x2a332b7d, - 0x68c9e063, 0x6655a497, 0x79d2bda0, 0x91b7cbab, 0x0ae953eb, 0xc8d3ddf9, - 0xfc2f92af, 0x79e9f749, 0xbea07877, 0xe1faea1b, 0xe5073eff, 0xfc77e88d, - 0xa1ddf640, 0x1f3eed0f, 0xa015905f, 0x03f4e3fb, 0x7cfe3036, 0xa0144585, - 0xafb8f9b7, 0xc93ca18c, 0x25ebf9cf, 0xb05c238a, 0x7c1ebac6, 0x1fbcdae7, - 0x292fe116, 0xb0b8c50e, 0xd68b4a06, 0x718bcb5b, 0xbc50f0ff, 0x94cbc517, - 0x19cb59d4, 0xad1f908b, 0x7b4bfeac, 0xca7db82c, 0x6bf9f58c, 0xa3b9163c, - 0x50f9dc92, 0x95f5a3ce, 0xd20037a2, 0x1cfec49b, 0x6d2733bc, 0x4b1da401, - 0xc82da427, 0x7cee7bc4, 0x8ed3231f, 0x8fbf98f8, 0x45953a57, 0x7177f106, - 0xa58fee18, 0x346452cd, 0xe42c1de6, 0xe3bfcb19, 0x6eb820fb, 0x63313df3, - 0xf35eb8dd, 0xc726f677, 0x10cf71ab, 0x2f2e6bd7, 0xab287013, 0x3afc5bb7, - 0x90a5ea13, 0x7f78dbfb, 0x55da95a9, 0xb7697e34, 0x5ff62bf4, 0x1399b7d8, - 0x68a135f0, 0x798b8c83, 0x878e4ba8, 0x0f75892f, 0xdf80b0e5, 0xf4143743, - 0x107d7e43, 0x02fecff5, 0x9f2439c0, 0x45809f84, 0x5c5e301c, 0xca9e5766, - 0xfcf397b3, 0x8ae04f3e, 0xaf6081da, 0x873a01a9, 0xbde72f9a, 0x471bf78c, - 0x425e0626, 0xf9b7ccbc, 0xb7c42b07, 0x17e411fe, 0xf0e1ca5d, 0x4bcad8f0, - 0xc5d9632a, 0x933fbf02, 0x3e5ce81a, 0xa3ef8bb4, 0xd54eacee, 0x8bfef7ec, - 0xfb094790, 0x4f5ee95b, 0xee890ee7, 0x1d223f13, 0x8fb6fba1, 0x6865e95c, - 0x9e01a7c7, 0x223eee50, 0x5ef815b1, 0xace3565e, 0x9e212f45, 0x787ce2b3, - 0x38de5fde, 0xd1772e49, 0x15beb9fa, 0xcf01b95f, 0x8de75283, 0x0e748b1c, - 0x2d779eeb, 0xe3d0ff7c, 0xb9faf1a5, 0x96d3de38, 0x8f17d287, 0x16f3f1c2, - 0x387c84bd, 0xa1ee8e3a, 0xdcac02a7, 0x8d5d287d, 0xcb1a547a, 0x60fa87d8, - 0x58ef0cda, 0xe43fb9f4, 0xdb24e3e1, 0x50b379e4, 0xf3cb1bcf, 0xf92c7e7d, - 0xae111237, 0xed5271a5, 0x17ce3a6c, 0xe85ea3bf, 0xcb823f40, 0x9529ef84, - 0xea7e3819, 0x69269e50, 0x3c0f8a11, 0x99bde064, 0xd12de9c7, 0x25e9c919, - 0x454a4c5f, 0x1b50ee3b, 0xbf20d418, 0xec340d0e, 0xf48b88cc, 0x792361f0, - 0x2df7617d, 0x5ff7e0c9, 0xfa1b0692, 0xa1d7af0f, 0x513213fa, 0xf5c1beae, - 0x7e5c4ff1, 0xa65f57f2, 0x4fbf8ec5, 0x0a78e048, 0x61638b9e, 0x3838ff93, - 0x13d233fb, 0x2c3ce783, 0xf027da6c, 0x1c734dbd, 0x7ed15977, 0x72841dfa, - 0x01f742d6, 0x71ac1bca, 0xc5c597e7, 0xf3a0d71e, 0x0b1b39e0, 0x1e3225f5, - 0x21d7f688, 0xc2d573a9, 0x4b17ba24, 0x73c13be7, 0xc6990b1a, 0x63eb9e0f, - 0x33cd77cd, 0xaee9fa85, 0x9af5acc7, 0x2c7aa73e, 0xe383d5a7, 0xb4adebb4, - 0x29cf048f, 0x6fd8ced4, 0x90b6c23a, 0xeedcfc0a, 0xe21de5e5, 0x6fa8cf3c, - 0x5b3ed7f4, 0xf8def713, 0x556de8bb, 0x2e007820, 0x219f368f, 0xf359747f, - 0x418b823e, 0x89f0dd0f, 0x7c132167, 0x225baa52, 0x69ede036, 0x7bb86e0f, - 0xc990d814, 0x871f05fb, 0x9feddd36, 0xbbf8e508, 0x8ebe260f, 0x73e2eacf, - 0xd90f3312, 0x42172e64, 0x9d4f7775, 0xfa8bca68, 0x9b43ed5d, 0x340a98af, - 0xb78a3595, 0x27c1e6bf, 0x4e4e595e, 0xdf111a8b, 0xcf3839df, 0xa23bca6d, - 0x8fc82ef2, 0xa8f5e536, 0xf2a8a4f2, 0x40fca8b4, 0x1dcdbf5e, 0x40fb2c19, - 0xd4f83fde, 0x9efbf815, 0x7322fd6d, 0x358f05f1, 0xf02bb6f2, 0xb3cb7cf7, - 0x56d3eff8, 0xc93e4b34, 0xba2b3f24, 0xb55bf3ce, 0x0e10a3f9, 0x1ca32f2d, - 0x74926b28, 0x0d5debd4, 0xc79423db, 0xbb535e76, 0x963f6e06, 0x76a11c35, - 0xd23ff6bd, 0xef7c7c46, 0xdea9f7c8, 0xd89fcef9, 0x5befeb0c, 0x751e76f5, - 0x4e2c0a44, 0x7f7eee48, 0xdbfb6dbd, 0x0a2fbfdd, 0xf9fbdbdf, 0x8d1c900f, - 0xc41e07ba, 0xf9bab8f9, 0xbde380c4, 0x7bd2cf23, 0xdd1c7fb4, 0x03aa16fc, - 0x2cce4bf1, 0x9fdda053, 0x438f8fcb, 0xb4df0b7d, 0x67e37dc5, 0xdc12f852, - 0x81651e8f, 0x5bdc704b, 0xc3ef87cb, 0xac384c9f, 0xef863eb6, 0xf0786f95, - 0x98142be5, 0xeb7761df, 0xb709fc20, 0xf06f094d, 0x7f2b727c, 0x1dff4551, - 0xa0f0e7e1, 0xc83641d6, 0xa6c0993f, 0xeb787e53, 0x3d7f9863, 0x3faf04e1, - 0xac9075ba, 0xf27209a3, 0xdf90a98a, 0xf7e6c7ac, 0x37ae04da, 0x369bf31b, - 0x8453ffdc, 0xfbe32b0b, 0x76335e0d, 0x5b9d3c80, 0x66db6a72, 0x1fdcc780, - 0xdb9c93c5, 0x55dd76dc, 0x50870479, 0xa611c61e, 0x7ed3780a, 0x215d7248, - 0xee1fa27d, 0xf1ba7d81, 0xe2dc1ee9, 0xd2e2fda5, 0x37a8edca, 0x451dcea4, - 0xc7a145fb, 0xddc9e92f, 0x52193869, 0x3ae92fa8, 0x8db2eb97, 0xef5223e2, - 0xf51e9372, 0x033df8a0, 0x0fa23be0, 0x36cbc097, 0x096d9eb1, 0x80f6bfdc, - 0xf3f51a67, 0xc47fe49e, 0x42ca6321, 0xc5a7f24e, 0xf372be91, 0x202b9006, - 0x7989d7d7, 0x097b5baf, 0x466e29f9, 0xfc28f13f, 0x67d7efee, 0xbffeb754, - 0xaef2032e, 0xdd6ebb6e, 0xf33f7f2c, 0x0dbaf6b9, 0x5b90dcbc, 0x7b79d2eb, - 0xad4abf63, 0x3ea4e3e6, 0x5c46c978, 0x28c2bc47, 0xece17b7e, 0xd1971b11, - 0xad2d7ffe, 0xfdfdf99f, 0x5a3f0ed0, 0x7a86c43c, 0xc29f81a9, 0x1257fee1, - 0x89373d60, 0xf035efdf, 0xb74f8c64, 0x907f51e2, 0x3b407f41, 0xeb403135, - 0x0c627d07, 0xfae06e0f, 0x3316d204, 0xad2997c1, 0xfffbf0e3, 0xfdb53820, - 0x4ff4e02b, 0xc947779f, 0x0c379021, 0x7a5f2ffb, 0xedff72dc, 0x23d1013f, - 0x8000702a, 0x00008000, 0x00088b1f, 0x00000000, 0x7dc5ff00, 0xd554780b, - 0x733ef0b5, 0x9992bcce, 0x924c2664, 0x84e3c849, 0x71100840, 0xf0444312, - 0x51888431, 0xd4503b69, 0x20717ad8, 0x9926023c, 0x4b62d5a8, 0x79120cff, - 0x22341809, 0x0281c150, 0x06f55bc5, 0x701a8c45, 0xaf7a8a44, 0xb7ad8ef6, - 0xff7f6c57, 0x4a8f8808, 0xd2f5a232, 0x5ad7fd97, 0xce64ef7b, 0xb6b4a924, - 0xdc3ef9bd, 0xd9cfb3ee, 0xd7b5ed7b, 0xf6b5af6b, 0x4cf5a61e, 0xd8c05c0a, - 0xce6a2566, 0x7c2c64ae, 0x61edf148, 0x67cf07f0, 0xf7fb193b, 0x95d5a0b4, - 0xf19fd8c9, 0xe6c60aef, 0x2729bf7e, 0x8ded0658, 0x61cb1823, 0xcfbbf52c, - 0xd500ded4, 0x7a3f4bb9, 0x3f7c0f7c, 0x8ca97bf7, 0x43ef03e9, 0xf7c18c8f, - 0x5b6dbcef, 0xd2842ecf, 0x793519d2, 0xf986bca0, 0xef7bc056, 0x27435898, - 0xbe0ef7f4, 0x5563097a, 0x35e5bbdf, 0xdbb19136, 0x93632a5d, 0xf8ab5b18, - 0x258a9873, 0xbbe0db0b, 0x644b2cf0, 0x7d63114f, 0x0cd85311, 0x23b875fd, - 0xb8c1175b, 0xf995d71d, 0x1f5fd0c2, 0xef867e63, 0xf7a54b2d, 0x4c3ddc3a, - 0x744bf6c3, 0x0ec24017, 0x19faa17e, 0x5a37e3d4, 0x7814bb22, 0x76c2ce5e, - 0x3e325f6c, 0xf3fa8612, 0x7f7d0e30, 0x0f644a63, 0x8f82cfb6, 0xa371dea0, - 0xfe861237, 0x47622cec, 0xfa763a78, 0x8c1c3273, 0x05acaae5, 0x8228efe1, - 0x2b59943a, 0x0701cdd9, 0x713fcfe2, 0x0f007396, 0x6899775f, 0x3d95a93e, - 0xf437ff4f, 0x7ddbd6c7, 0xe1b0a063, 0xcf6f58ab, 0x3b997826, 0x66f88558, - 0xb803fc1a, 0x89c81fea, 0xcce7c3ac, 0xb1eb8557, 0x479fe9da, 0x5520fff0, - 0xb61ff847, 0x0ab635b3, 0x66d61528, 0x0bfc00cb, 0x43fb5878, 0x37630c00, - 0x978000e3, 0xd670d7ff, 0x2bf3c3a9, 0x07ad0a5d, 0x556df9fc, 0xbc67cd8c, - 0xd4f2fe7d, 0x58899577, 0x1a6b51aa, 0xa5735b3c, 0xef46c7bf, 0xe28f3fb1, - 0x0bfa0da5, 0x25b7f132, 0x09ba44ee, 0xd86977e2, 0xba9defff, 0xfdf0eb03, - 0xf8765c44, 0xfbe074be, 0xf9a3173a, 0xfc3955cf, 0x475535ac, 0xc8fc4afc, - 0xd7c24eb2, 0x713f90fe, 0x724e393c, 0xfcbaf7bf, 0x00be2237, 0x0f74d1ef, - 0x75a545e2, 0x63d7864d, 0x43b06f89, 0xd556dcfb, 0x33e0377d, 0xf349ccb8, - 0x9cdef095, 0x158cbf1d, 0x74ffee0f, 0x8695736a, 0xe9c65ff3, 0x02b72d9d, - 0x62f112e2, 0x5d03a819, 0x63f1642c, 0xe7886526, 0x8445f45a, 0xc247517f, - 0x2fdff4f7, 0x49ef89ac, 0x92ba617e, 0x2ba0bf04, 0xdd70d15d, 0x375f0a82, - 0x373e258b, 0x6e183650, 0x82d5cf89, 0x245d24ee, 0xe2357be3, 0x7c60d27b, - 0xf93d2c7b, 0x99706fd8, 0xdc94f095, 0xfa11633f, 0xf03b21ee, 0x16ddd00f, - 0xdd7a2145, 0x646a5772, 0x3da7f225, 0x19f117be, 0xad157c3a, 0x1492ef77, - 0xdb2bc19d, 0x9441302c, 0x9c9d8733, 0x4a7a4b8f, 0x617a9f90, 0x9f587ece, - 0x9dd5d7de, 0xc1024561, 0xeaebf358, 0xdeffa42e, 0xfde6af67, 0x19d548ac, - 0x618843d4, 0xfe143718, 0xbc032b43, 0x2cc5349e, 0xe0175e34, 0xff09c257, - 0x435fe17a, 0xe8bc80c5, 0xbf1c06c3, 0x9807cb8b, 0xe71a12e1, 0x1d6c29db, - 0x526cdb8c, 0x6f6826fc, 0xb23e3a5e, 0x4361c392, 0x20146a3e, 0x9b589b35, - 0xf7c03152, 0x2513a6cd, 0x36f195b7, 0x85bbde0d, 0xf78175f1, 0x5f002a8e, - 0x4c7d6da3, 0xfa45ba45, 0xd8a5f687, 0xff80345e, 0xf9bff5e6, 0x7cdfc213, - 0x8d1748c0, 0xb1e7198f, 0x8a9e9134, 0xb524e806, 0xd589e392, 0x8018c8b0, - 0xa9ea29d7, 0x8a88b1b5, 0xcd565a78, 0x66e9024e, 0x8199e91e, 0xecace3f4, - 0x0ca1f364, 0x11fcc07d, 0xf74a7b80, 0xc24697ce, 0x58daeefb, 0xb4374e3e, - 0x4e8bb6ec, 0xbeb0345d, 0xba4bce12, 0x41cca937, 0x0077d1e3, 0x83bf7f8a, - 0xfb371bde, 0x6ef2c482, 0xa4d32efa, 0xe0f6bd12, 0xcd1be423, 0x38c0a39f, - 0x328c979b, 0x82a67ae1, 0xbcb9437c, 0xaeec7db0, 0x7f678415, 0x07b7ca09, - 0x09ce80d3, 0x942abe9f, 0xeaeea52f, 0xbfa0bb5f, 0xffd5dca7, 0x138e258d, - 0x47f4e270, 0xa648be90, 0x23bd64e7, 0x6e2ecbdf, 0x0c716f29, 0x17f01eff, - 0x35be2de1, 0x4d0fcb9d, 0xffa2faa1, 0x475cef30, 0x374469f0, 0x222f6db7, - 0xdac0dc79, 0x591ade89, 0xbbf482c4, 0x69c2c6c8, 0xe08b1740, 0x172874b5, - 0x3d32b16f, 0x4496fd61, 0x2146f58c, 0x31616e0f, 0x7d96fefa, 0x2c35ed49, - 0x26f684ea, 0x62a68b1b, 0x6f6c69d9, 0xef417166, 0x3e26b67f, 0xbe7c1d67, - 0x77758b37, 0x20d444d7, 0x1dab7bcc, 0xbe065774, 0x33eb4ed0, 0x5a4ef965, - 0x7f0af4cf, 0x4fa83dd1, 0x76fb355e, 0x27bedd01, 0xe7e24bd6, 0xbbf5575e, - 0xd514f788, 0xdf8ff344, 0x9cfc2563, 0xeb8dbd02, 0xdd9b9f7f, 0xdeca1b3c, - 0x7a3bdd56, 0x55c9a234, 0x1839db30, 0xb39eebcf, 0xb8dd2037, 0xb7c226dd, - 0x65cc7e7c, 0xddd57aa6, 0x522bff02, 0x088abb23, 0x9e9113dd, 0x7d4946aa, - 0x82ce26ca, 0x5666bbfa, 0xe6f509d7, 0xec411deb, 0x07ed07af, 0xb9b817a8, - 0x5b7028de, 0x2eb27e68, 0x06e92be7, 0x52fea1c6, 0x84a5e22e, 0xc85b8c63, - 0x7f89b641, 0xe6eff427, 0x493b2925, 0xafd3f6ff, 0x96fd1189, 0xd7882c05, - 0x795c84e7, 0x3695ca4e, 0x9a2b972b, 0xa832ee6b, 0x9941f73f, 0x95e01d6f, - 0x83de8295, 0x4a3f1bef, 0x5e9e91d1, 0xef5fe8f9, 0x9fb419fd, 0x5ba2c0fd, - 0xd2017da1, 0x73dbac18, 0x6047970a, 0x8fd4307f, 0x38f6c08d, 0xb1c1e36e, - 0xb41c7f64, 0xc846fb08, 0xe0b4c6cf, 0x4fd085d6, 0x3e9993e3, 0xbcf664a0, - 0x5ee8f239, 0xf7643f6c, 0x1b7e81ed, 0x1b5e3853, 0xdf491b9f, 0x4e0f613f, - 0x733cc377, 0x3c9f91ad, 0x05e37281, 0x677bd92b, 0xc2117459, 0xaed3b67f, - 0x70277be0, 0x4250e95e, 0xeaf3829b, 0x043d9276, 0x10b39a7c, 0x36b93bbe, - 0xe04bcf9b, 0x0986e4e9, 0xcd9b17c4, 0xb3f0bc7c, 0xc27fbd0a, 0x0391981c, - 0x974f13f5, 0x534056fb, 0xb512c05f, 0xee873d00, 0xbd5e76e3, 0x7881df49, - 0x09538762, 0xa11eb95e, 0x62678b8d, 0xf2e9687b, 0x1c7ca3af, 0xde51cf8e, - 0xd9b904b3, 0xc805e2cb, 0x461adb4f, 0x9f514675, 0x91f38f74, 0x585e655a, - 0x171ba07c, 0x9994f77f, 0xc87e35e3, 0xbe7cf44c, 0xb57ce3fd, 0x707fae2a, - 0x65c8109c, 0xe48ff926, 0x1d5d4272, 0xfec8ceaa, 0x2d973d0c, 0xfb633aec, - 0x1de0ceeb, 0xe6bfa06e, 0x9de7fffb, 0x38df8465, 0x9ed645c9, 0xca797c49, - 0x748b9fec, 0x5a89aeeb, 0xf3e827e6, 0xeaaf820d, 0x63fec2ad, 0x1f224b51, - 0x6aaaf6ca, 0x72cbdd23, 0x677fa0bd, 0xc1f7cb8c, 0x1fc126ed, 0x1ea2b4df, - 0x6641c29b, 0x1c47a885, 0xfd4ebfd8, 0x6a20f94f, 0xe17a87a9, 0x9165a8f2, - 0x004f9128, 0xcc1b51df, 0x2756d4fb, 0x03406fe7, 0x3268b3f6, 0x48b97d23, - 0x02b5fb05, 0x3d5deb9f, 0x9fa72eb0, 0xfafa7376, 0xf0056023, 0xf7898f3d, - 0x82ef60ac, 0x4da67b1c, 0x607ee289, 0x2eeb16de, 0xb5f2117b, 0x7ae2755f, - 0x8e48576e, 0x569b6bcd, 0x4bea15b2, 0xeb405c0f, 0xd399369f, 0x9b88d2e5, - 0x2114e2f4, 0x11adeb1f, 0x3fdfd90b, 0x01f21851, 0x74764ff4, 0x53947c23, - 0x280f1831, 0x10f40dd7, 0x5d83a849, 0xcb93a534, 0x9cf20655, 0x524bd825, - 0x671ca3de, 0x919ff649, 0x1f52c23e, 0xf4c7b971, 0x527b946c, 0x0aebdf2e, - 0xae49b974, 0xf5c6ce8d, 0x72e4f585, 0x7842bf73, 0xa42d626d, 0xe81ea44f, - 0x91e8571f, 0xeb986ad3, 0x2a26eb2b, 0xd117775f, 0x27594b78, 0x57a913e9, - 0xd783a386, 0x7e0e84bf, 0xed007486, 0xe8b01f8d, 0xe35e3065, 0x9a6d1672, - 0x44e74bc8, 0x4f5c8fd2, 0xc49eb8da, 0xf43ce532, 0x4c7eb265, 0x7ac987d6, - 0xf5c2db30, 0x69675c9d, 0xe74f64cf, 0xe594c076, 0xfcc19511, 0x3ff9a636, - 0x60349cce, 0xb2de84d7, 0xb10bf4d9, 0xe0a3601e, 0xd369c5bd, 0xf686ca6e, - 0xc8fcc690, 0x9780a957, 0xbb7cf09d, 0xb36b7bb0, 0x2d7bdd39, 0x5acd7e9c, - 0x703b9580, 0xcfb4625d, 0x1732678d, 0xe7c4a3d2, 0x577c2776, 0xfd71df81, - 0x8dbdffd4, 0x7c24a5b5, 0x9d9cfd5f, 0xcfe7eae4, 0xb256233a, 0x6e858247, - 0x57eb2fe8, 0x7b53b256, 0x3e92739f, 0xd0fa15ed, 0xd128f683, 0x5fae2acb, - 0x21275d71, 0x648f5535, 0x35cafb48, 0x4a045123, 0xcdc9acfb, 0xf6c1aced, - 0x8a2f6890, 0xcae9cf5d, 0xcfccfb4a, 0x62773ddd, 0x6861e01d, 0x588fff9f, - 0xe981d0e7, 0xe787dfe5, 0xc7c380a1, 0x472c1fb1, 0xdfaab57a, 0xf406deb9, - 0x1e5d4335, 0xd1e60bbf, 0xa170ef94, 0xfc29ab9e, 0x846f2ff5, 0xcc0787fa, - 0xbceb8acc, 0x1b1d7a67, 0x5dfcbc35, 0xe89f3112, 0x5b97e049, 0x4deb19f6, - 0xa87ac69d, 0xc82f58cb, 0x4f4e7a70, 0xfbe1d920, 0xd5b5d033, 0x4ec1f2da, - 0xbcfad780, 0xa7d1f495, 0x067160ee, 0xfc535bca, 0x5ad9e218, 0xf444f1f8, - 0x3fba846f, 0x02b4b051, 0x38cac4ed, 0x3faf91fe, 0x742bcfb7, 0x01b7810d, - 0x899b31fc, 0x3ad60cf0, 0x85ce492f, 0x2c789f04, 0x845f0ffe, 0x9d9a2ff9, - 0x9e9bbae2, 0xaa4e67f8, 0x60927b42, 0x572da164, 0x2dfb887f, 0xae096f78, - 0xf059e9ff, 0xb0d5c01e, 0x46c3eb85, 0xbe434b16, 0xd3bb066d, 0x477c4b06, - 0x5b875f06, 0x5155e2da, 0x8c8edff8, 0xa70871da, 0x802d27f6, 0xfb1ab1f4, - 0xaf93b04d, 0xe07ae0cd, 0xd7767d96, 0xdd1e0329, 0x2ba87a86, 0x912a75c7, - 0x61fc84ff, 0xb8968a79, 0x09577a1f, 0x6bf88b5e, 0xa658f5b2, 0xfc57f8c1, - 0xf79233e9, 0xa7cd978b, 0x5d80c47d, 0xb4f9256d, 0x3d20aef8, 0xdf2b697f, - 0x6ade9e17, 0xa7ef11d7, 0xe3fdf3b7, 0xc4473ce2, 0x857bff06, 0x8bdbdb9b, - 0x19453be1, 0xbc64c78c, 0x55f0ffbd, 0xf7a3a45e, 0xdc2f1f19, 0xf78fedc9, - 0x62af805d, 0xf7f60efe, 0xefd8177e, 0xaaf9e20a, 0x2e2e510f, 0xd0faaede, - 0x9c87604e, 0xbc598fe4, 0x0b71cafd, 0xa7dfd81d, 0x5fa1a623, 0xe895c768, - 0x02f7c289, 0x89d7ee11, 0xb5cf015d, 0x1d93171d, 0x95bb7477, 0xedb6e9c3, - 0xf15c79c5, 0x4af89527, 0xda20b133, 0xff161dc7, 0xfd67e438, 0x70333de1, - 0x959fde5d, 0x1ff7a26b, 0xf10b9857, 0x85965ee1, 0x5a2b17cf, 0x61b7f900, - 0x899992cb, 0x866a4ef6, 0xad35eb4a, 0x8f567970, 0x7ae9f883, 0xdb4da3d4, - 0xfc707f81, 0xf2ff6fd9, 0x3f224f46, 0x4cc55edd, 0xc3cbf609, 0xc27a235f, - 0x6be028bf, 0x57d7c0b1, 0xaa6b2be5, 0x12968be4, 0xef8ba394, 0x0d71296e, - 0xf3f45761, 0x0f9cc3c5, 0xb850cbef, 0xc32f20ff, 0x6e18cfb0, 0x3528e65f, - 0xf9b15e91, 0x940f7f98, 0xc62db0d9, 0x0c81f7fd, 0x640fda8d, 0xfb5f7b70, - 0x5efb6ddd, 0xcd4d7987, 0x80cf6e08, 0x97f3217a, 0x71ebbae3, 0xb1983557, - 0xbbb26288, 0x6e56c3d8, 0x8edc6ac7, 0xf6c99cde, 0x8fd84bae, 0x997f6277, - 0x62f61724, 0xffc7bd3f, 0xdaf10c78, 0x44f1f05c, 0xe7420fb4, 0x1fa0b33e, - 0x90add1cd, 0x02f8773c, 0xd425e90c, 0x282d8b3d, 0x21c3901b, 0xc913d71f, - 0x0653faf3, 0x3c84efdf, 0xfde7ea71, 0x3b7f9c11, 0xb73e9cdc, 0x3f214b2d, - 0xc44f36e4, 0xb5ff408e, 0xa5ed2a7c, 0x67efc225, 0x5f94fddb, 0x288efa45, - 0xd75831ae, 0x35f47f39, 0x30a88dcc, 0x8bbb87ce, 0x77d9dfc9, 0x854f9a60, - 0x1feec736, 0x788519ad, 0xf0fb32ea, 0x27af877d, 0xe1f7e70d, 0x386993ee, - 0x2add86bf, 0xf221bbcd, 0xb2c2d649, 0x33f0b901, 0xca3af825, 0x1c52e601, - 0x0f94be38, 0x34feee1f, 0xfb83816b, 0x567f480b, 0xa7978d0e, 0x8e7ed3dc, - 0x39715fdf, 0x1e8f975f, 0xee5046b7, 0xfd07647d, 0x3f6f2096, 0x777d7272, - 0xefee432a, 0xdf500b3a, 0x2a6fd7f4, 0xf89ca135, 0xdfcf8b8e, 0x402ce963, - 0x628dfc7e, 0x1ae967ec, 0x6c808b13, 0x5006b25f, 0xa3e8f203, 0x40299f47, - 0x9ee1ff79, 0x27e60a67, 0x9dfc97c0, 0x78e57b2c, 0xfd266fc2, 0x344b1ea8, - 0xef9bc70f, 0xe57f72b3, 0xf9547e30, 0xfdc2db3e, 0xab3e7da1, 0xbf28748e, - 0xf1486beb, 0xc7db7da3, 0xe6ff246c, 0xacbf0b77, 0x83da3fdf, 0x7df918fb, - 0x1e15ff52, 0x974a4f4e, 0xd483fe42, 0xe3c938b2, 0x7bde59bf, 0xe4133d60, - 0xbff3ac3d, 0xd9345f21, 0x3246c7e2, 0xe20b0fa2, 0xd0ecd2cd, 0xad653f50, - 0xbf15f4e4, 0x2afb44c3, 0x81d7ae4b, 0x928aecf2, 0x30133694, 0x6d2527a2, - 0xf201c622, 0xfde94b73, 0xfba73570, 0x7f231670, 0x516b0e5b, 0xb8bb5e48, - 0x326f3edf, 0xea83ad73, 0x9edc11ac, 0x16df32f1, 0x5dd698b5, 0xc490ff41, - 0x480bd487, 0x3f1f283f, 0x3f446c52, 0x7642b74a, 0x9cea6aa7, 0x470efd8b, - 0xc847134f, 0xa7a73ffd, 0x893ffafe, 0x188f269e, 0x3a829e8e, 0x36d793d1, - 0x3f093d34, 0xcfbf79f1, 0xbfdc01c2, 0xdd7c0b66, 0xfc4ee427, 0x9bf49b0e, - 0x99df382b, 0x3699bfa2, 0xfd455447, 0x9c7f33e1, 0x187dffe8, 0x27dc5fec, - 0x0efda0e5, 0xf395c8e5, 0x16375a74, 0x417f41eb, 0xd236c5ea, 0x629af78f, - 0x64af6845, 0x8fd96f8f, 0xb73d9174, 0xed2562ac, 0xa8dcf2ff, 0x92b7500f, - 0x7559741f, 0x0488d4e0, 0xdf10e17b, 0xe5df34cf, 0xbbd3e7a7, 0x1a107db9, - 0x387b216d, 0x7184a5d4, 0x96039b9d, 0x6b41da08, 0x095fee15, 0x3cebb06f, - 0xa0afa3ee, 0x740fcfb8, 0x488a171e, 0x8ecf6fff, 0x35bd23ef, 0x91efc838, - 0xf83a3f1c, 0x1fc7ca85, 0x8efc68c3, 0xeaaf1e72, 0xfee75ab8, 0x1d7eb115, - 0x6e39fcb3, 0x18d607b4, 0x85c659f9, 0x18809cfa, 0x7afe6f18, 0xae43ad3b, - 0xd2ccf1ca, 0x0cff5c6d, 0x67e40b96, 0x162c9ace, 0xfa6fc446, 0x05241cf9, - 0xbb4573d6, 0xcb39378c, 0x79684502, 0xb7e9bbbf, 0xbd00a4af, 0x8e9fa166, - 0x68c2ca6f, 0x987f93f7, 0xfc7dc9d7, 0xc90009a0, 0x5cffd6c5, 0x42697357, - 0xf03fbc5d, 0x6b6bdcfd, 0xf6ef48f2, 0xa0d823b7, 0x6fdd658f, 0x351e31d7, - 0xbd81aed0, 0xf852eb6b, 0xb5c761f7, 0x3c068e57, 0xfffc7228, 0x7f47eb5c, - 0xc6199da1, 0x4b4f844b, 0xfd0cdfea, 0x7ef9743b, 0x784af6bc, 0x590ac1e1, - 0x1fad66bf, 0x6ccfbbe0, 0x2a508fec, 0x1c8ac7be, 0x6dacd6ef, 0x0de7d6eb, - 0x276005d8, 0x39911aec, 0x7eac1f60, 0x85fb667b, 0xebaa5630, 0x5dea0b53, - 0x1e43e7a9, 0x648fec85, 0xe4203d7e, 0x572cdfc3, 0xf47641f5, 0x57241181, - 0x4b20667b, 0xe483fec2, 0x80796876, 0xf6073da1, 0xdbc21748, 0xd3e3fc7b, - 0xef7b422f, 0x1b1fdfec, 0xb77be3a9, 0x37bb45ce, 0xba234e74, 0x2353ed0d, - 0x4dadd00a, 0x71e80bf0, 0x7a480b8a, 0x7412ea5a, 0x8c330eea, 0x521c7473, - 0xbe898526, 0x83ae0a5a, 0xf8f7ccb5, 0xe438425f, 0xde7932be, 0xf7c11ebf, - 0xead2a10f, 0xffd825ad, 0x9da1856e, 0x44f4aeb0, 0x37da02d6, 0x30b59bbd, - 0x5d25bbe1, 0x973e120f, 0x890f33ec, 0xe08f5fc7, 0x67e6de71, 0xdca3f69f, - 0x90a228f8, 0x22d0684c, 0xbd40a76b, 0x9684c1a1, 0xcc8cab20, 0x1ce291bb, - 0x06361675, 0xed0477e6, 0xdf638426, 0x7053c337, 0x814ff0de, 0x8b02db47, - 0xab6e9f48, 0x4e2839b3, 0x56ff3a54, 0xc52b83c2, 0x5758788f, 0xe3839d5a, - 0xe19acf34, 0xd808f8a2, 0x7cded871, 0x2fc8b7d7, 0xd75ae124, 0x3b45ae65, - 0xb9ec0aa7, 0xfcee00a7, 0x7d6a6b8c, 0xd523c7c0, 0x3bb7e5fd, 0xb43e5e30, - 0x266eff1c, 0x25368ba7, 0x2546fe10, 0xa25941f9, 0x8bb0b35f, 0x8d9f8ddb, - 0x2be218b0, 0xf6e08d9f, 0xd8e1a5ec, 0xc39f2474, 0xda2a4f5a, 0xffe621d3, - 0x2ccff704, 0xd0f7d0e0, 0xe479713a, 0x3fc9d569, 0xdcf4f366, 0x5fb6217b, - 0x85fed1aa, 0xe00f3d69, 0x3d6bbdb8, 0xf04c75be, 0x2aefd601, 0xbd4f7da3, - 0x3278a827, 0x7d70bcf9, 0xaabd9f7b, 0xd288fd1c, 0xa8fb5aee, 0x5ae6f49d, - 0x2d7f7ea7, 0x69dfd3ca, 0x16c01f3c, 0x7e874d8f, 0x833efe96, 0x8f6b5dc6, - 0x0ff5c5ac, 0xbda954ef, 0x607411d8, 0xb9be4bbf, 0x2bd22265, 0x504a4473, - 0xed3d9a8f, 0xb618e90c, 0xb12fe42b, 0xe30c0279, 0xf3c3d3c4, 0x45f50534, - 0x1d333d92, 0x5fb455fd, 0xb6bf90f1, 0x18c7f05a, 0x36d382a0, 0x3fb68562, - 0x6fb0188f, 0x1ce3f95e, 0xbb4a1f0d, 0xfee364c7, 0x14ba9af3, 0x5b2df686, - 0x42663f15, 0xc627bd7f, 0xea6e0ed0, 0xa69c6854, 0xb82d27d2, 0x93a5b96f, - 0xec4877f3, 0x057f0033, 0xf18c5768, 0xa07b0aa4, 0x5839fb8d, 0xc448d8ec, - 0x3d7c63f3, 0x12f78319, 0xad8cabfc, 0xf440f2e0, 0x86711167, 0x0257e126, - 0x3eed484d, 0xef5bb48f, 0xf3b7fd16, 0x59bb8c52, 0xc455f989, 0xf062b96b, - 0x2af2cb87, 0x91fa7df1, 0xdfe40cf8, 0xfa17d038, 0xb32ab697, 0xcc29fd6e, - 0xf1a4eb6f, 0xbcc1343e, 0x056a4e40, 0x0452073e, 0x7d7657bc, 0x86e90332, - 0xd7e232d5, 0x6a69aee6, 0x6fc78393, 0x4ec85ed0, 0xed89d96d, 0x929737d9, - 0xc8f8c67e, 0x35fe786c, 0x1cb3e70f, 0x79d7f707, 0x61170eef, 0x48fd33bc, - 0xe29fd6e0, 0x90a417f8, 0xd61b35bf, 0xe54199c6, 0x796ff41a, 0xa88bf959, - 0xf533bd7f, 0xc647840a, 0x382e30f5, 0x38e48cab, 0x8a7c33d5, 0x3794177f, - 0x0e34dc78, 0x116aefec, 0x711e7c5e, 0xd119c40c, 0x62e3876f, 0xdecb0f1c, - 0x7e46a89c, 0x7be7d07e, 0xacbb4e90, 0xccd7c42e, 0x42df97ae, 0xc6d33b7d, - 0x9aee293a, 0xd3c4b764, 0x3a4419be, 0x7a733bed, 0xd7083dc7, 0x947d0775, - 0x8f6492cf, 0xb739715c, 0x93da3fcb, 0xec3f23aa, 0xec1b7212, 0x797f1e47, - 0x9323ef9c, 0xf6efc8ed, 0x23b72faf, 0x777febfb, 0x17c3923b, 0x28f3c3de, - 0x890f7ca4, 0xc35f5f7d, 0x5fd434d9, 0xaed23d2b, 0xd8f7ca4d, 0xba3df22d, - 0xd0f7ce87, 0x0ff8f276, 0xee494186, 0xae222dba, 0x43cef7e5, 0x84bb87ff, - 0x7b2bc0e4, 0x3748c353, 0x64ed3b67, 0x4b6e6997, 0x7b6ae114, 0x3cc11ada, - 0xe0453688, 0x578890eb, 0x2c1c4459, 0x834744a3, 0x4025a0e2, 0xa4fc3f72, - 0xd2abc799, 0x85ee8f22, 0x1ce1e37a, 0xd462cf11, 0x54d9f87f, 0x8a6377c2, - 0x37fd8e9e, 0x8608fbfe, 0x183eaa71, 0x09f9d70f, 0x87bb707b, 0x7fbc5ae2, - 0xe75582f6, 0x8968b3f1, 0x33b0f01b, 0x93bfedc2, 0x05a8a6a5, 0x8993bde6, - 0x32f59f3c, 0xd9e7c5ae, 0x8f2461b7, 0x8231a0cb, 0xdcb5b2fb, 0xe32f545f, - 0x1fb98755, 0xa5c45eae, 0xf45ece4e, 0xb458a608, 0xb8b52d29, 0xdd7cfb4f, - 0xdf9ff234, 0x2a2cff79, 0xfd18d7eb, 0x3fd08bfd, 0x3f103c5f, 0xf9f77e96, - 0xf6e167cc, 0xd0ff80f3, 0xbe8cf604, 0xfd46ab46, 0x775cc459, 0xc3d03ea3, - 0x43177ab0, 0x1a2506d9, 0x19600af1, 0x7ad6d3de, 0x57bd7052, 0x6f4899b7, - 0x7e4cdb85, 0xcbd24f7c, 0x67ae1eab, 0xbd70f5df, 0xe08ea803, 0x336cb238, - 0xe883788b, 0x4533056f, 0xbc2934b1, 0x6ad2ed5c, 0xb2dfd287, 0x8b7336bf, - 0xcdda1a6d, 0x77f226f9, 0xd7f16e7f, 0xa338bf91, 0xcda9d684, 0x96a6b2d9, - 0x7d2f13b7, 0xa8078f6e, 0x1b8d32fd, 0x40cf4c96, 0x8782fa79, 0xf19217c7, - 0x58ddb0b6, 0x2cc38e4f, 0xf5eb1889, 0xa736382c, 0x120dc798, 0xf420bf9f, - 0x8aebe7c4, 0x167dbe04, 0xfe72bb94, 0xde38f22b, 0x1cbcf94c, 0x875d5f95, - 0xe30a3074, 0x725845ca, 0x84cc2abf, 0x99751fe0, 0x48fa2147, 0xcdcdb782, - 0x96bc29e9, 0x5aff21fb, 0xfee193f8, 0xf82593d0, 0xb8c5efd8, 0x42cbbd65, - 0xf5f3e871, 0x1a64a497, 0xf5fdb7f7, 0x96feffbf, 0xaad7e7ef, 0x45c6bf22, - 0x8bbe6972, 0xe2a4e5cf, 0xe7c51bdb, 0x701fb00e, 0x0ad56b1e, 0xbfd32394, - 0x3479a0e9, 0x8239061f, 0x3de5ac71, 0x9bd7a805, 0x304a7bab, 0x5f8c935e, - 0xf2935684, 0xef9bde0c, 0xda08fd81, 0xf18c6b0d, 0x55f1c1b8, 0x2666617f, - 0xee4e7bee, 0xd7f5197f, 0x2fe93b7e, 0xad17bff8, 0x16cfffc8, 0x388b5c91, - 0x2e316383, 0xee894a14, 0xda1171f8, 0x6a8edc31, 0x44eeb6ea, 0x5b7e713b, - 0xff0f7c42, 0xef18deb3, 0xc8326b63, 0x8c3aceef, 0x4e1e1bcf, 0xfc506efa, - 0x65d69daf, 0x0e3825b3, 0x10f41df9, 0x599c1de5, 0xbeb86262, 0x116faaf5, - 0x7633a92a, 0xc67e7da3, 0x466bd7c9, 0x3e3fd4a6, 0xebfabfb2, 0x57d9d683, - 0x6f5ceb82, 0x7ec4c162, 0x619d709a, 0x3ac51b7d, 0xe2fa799f, 0x8fe75c12, - 0x825c5ff7, 0xdcd9bceb, 0x29be47ee, 0x41af0775, 0x32ba9cfc, 0xe615f640, - 0x9d1f20ef, 0x94de3d2f, 0xfd378f44, 0x2eb1e8e3, 0x59321f31, 0xe3f4363f, - 0x3d1fa8cb, 0xe50f3d16, 0xf59b7cc1, 0xfc49ea2f, 0x679fd21b, 0xe3ff92b3, - 0xdd3f1ff0, 0xdd18f948, 0xb227d92a, 0xb05ac3bf, 0xc3a3ed18, 0x617d796f, - 0xd3fef865, 0xb5e5fd85, 0x59fa30b1, 0xda40bee4, 0x78f2c997, 0x03cf98b9, - 0x8cdffe99, 0x3ce21bf8, 0x20dc7fd2, 0x3e45b1de, 0x6eef76e5, 0xc7fdc7c5, - 0x6e4fe49d, 0x85cf343e, 0x220fe2fe, 0xfcdc7fdc, 0x8ff93974, 0x8a5e4497, - 0xeb193e62, 0x1fb85c56, 0xddfbb259, 0x9003cc34, 0xe7d85efb, 0xf9499fde, - 0xeffdc635, 0x69939107, 0x70003798, 0xa7708fbf, 0xa416e27a, 0xffd866fb, - 0xb360de61, 0xfd863f16, 0xd9187b36, 0xc65d9505, 0xef8ca0fd, 0x48580b6e, - 0x56eb6eee, 0xb3af2822, 0x3ca2c12c, 0xcf2c6bd4, 0x80753a75, 0xfe9922cf, - 0x077e9017, 0x5dfeeae2, 0xa7fe9758, 0x44e9ad9e, 0xe6663dbf, 0xdb3ca177, - 0x4cf214ea, 0xdbf6f923, 0x7591dd87, 0x6fc37609, 0x584edc23, 0x34c1f322, - 0xbd60d516, 0x1ff1cd16, 0x7946f5c7, 0xf7924d1f, 0xaf197589, 0x494585bf, - 0x9eb1352f, 0xc4b0bcfe, 0xf9e392f7, 0xf4370718, 0x75ca5ac3, 0xe4dd93f4, - 0xab9c51f0, 0x6356cfeb, 0x9bef987b, 0x55961f81, 0x5cafd00c, 0xcdbf4907, - 0x6a1d1fc2, 0xe90ab138, 0xb8a5d437, 0xe8dd7f70, 0x08dbf4e3, 0x9bcc2ffb, - 0xd677e64d, 0x1d13cc69, 0xdd7fff8e, 0xff9c77cf, 0x9cac3d7f, 0x5bf8c7fa, - 0x3f97efdf, 0xfce5ef9c, 0x7fbeffa5, 0xe70add9e, 0x2579a4cb, 0xfd935bef, - 0x79df72ee, 0x8bf0f2be, 0xf17c7c24, 0x70c7c60f, 0x6b2530f2, 0x7242fde8, - 0x96afe35c, 0xf8e0ff87, 0x1e8723c6, 0xa881334a, 0xf6145258, 0x6fcebb72, - 0x50cf1788, 0x371e7e1d, 0x453e7955, 0x9f5ddc72, 0x9ceee221, 0x5a7a5f9f, - 0x126af5a5, 0x43a6e1f1, 0xdabe1f4e, 0xf14c58e0, 0xe9f8e4d9, 0x067fb652, - 0x1c72512e, 0xb8f911b5, 0xa9e3cbf8, 0x3d396517, 0x56749f24, 0xc90a7984, - 0x392f5a79, 0x4c111d3e, 0x32eaef58, 0x410c08d8, 0xcc2d36d7, 0x4f9e1232, - 0xf4f6e2cb, 0xc89f224b, 0x05e7e16b, 0xfaa673ee, 0x35e31f71, 0x7ca77cf1, - 0xd67a604f, 0x02ef9424, 0xc0decf9f, 0x4797804c, 0x4f249dcc, 0x1f0e4dc2, - 0xc7e93fca, 0x10effd91, 0xa5f38b71, 0x19676ff3, 0xfebfbce9, 0x85fbe24f, - 0xdaffbe92, 0xc016ddb8, 0x181f818d, 0x186befd1, 0x4c1a2a67, 0x33f5c3b7, - 0xcb2efd1c, 0x459edc0a, 0xa44ff178, 0x94f3e6fc, 0xf195a92f, 0x622fe893, - 0xfa3aac07, 0xfce26d37, 0x239f5b0b, 0xaabeebf6, 0xcd979459, 0x73c88fcf, - 0x8fd9c336, 0x9ff9fb1b, 0xf5fd8fdb, 0xc8fd93bf, 0x9c7681dc, 0x7e69a9e7, - 0xed5ffbca, 0x5f71f804, 0xc875a8f8, 0xdcf22cf3, 0x5df997c5, 0xcdc3f6f6, - 0xb0ef6ae9, 0xe563ff70, 0x34ff93e7, 0x34fbf9f9, 0xdf0ea3f4, 0x7be4584f, - 0x9e22fcc6, 0xf82576c6, 0x9e3143b7, 0x8092f7af, 0x447f3e57, 0x6cf4c5e8, - 0xa75c51ff, 0x6cdb8f8f, 0x9e4c1d2c, 0x9b172e4a, 0x2f8a0e03, 0xbcf27734, - 0x8ce5e697, 0xfa3377e4, 0xafd0cb4f, 0xbda18b38, 0xf8233537, 0xf57efc33, - 0x9ab08edb, 0xd9f77e8e, 0xdebbed0c, 0xa9febce3, 0x6c73f83b, 0xa1ef2d0f, - 0xecc74678, 0xaaef288f, 0xae9fcfea, 0x7824adaa, 0xb1e08fc9, 0x7cadcf1a, - 0x0fe3c591, 0xbf43fcb2, 0x5f93f13c, 0x9e06e3ff, 0xf8f21d9f, 0x908fe85d, - 0x3d54f17e, 0xe6a67e46, 0xab68dc03, 0xd87cf952, 0x9e88f3f7, 0x2b4c0f9a, - 0xeb29ff47, 0x9da397b4, 0x072bf55b, 0xbe3ef7ed, 0x24f2972b, 0x0fc13dea, - 0x2b3a3e51, 0x5da35723, 0xa0e3085a, 0xfef1fbbd, 0x6e11cbab, 0xa336ff29, - 0xdfc61cff, 0xc7fa34ec, 0xd9e78d99, 0x4f9bdd2f, 0x4762cbfb, 0x6fec53f0, - 0x11c39db3, 0xa3ce23de, 0x3279bf08, 0xcfbe4bff, 0x4e344d56, 0x146db7f6, - 0x6172972f, 0x6d0599b3, 0xe4f203c5, 0xf22e9678, 0x635e444c, 0xa79e2cf7, - 0x8f0eea22, 0x81f3bf31, 0x238f2bcc, 0xb4b3c73c, 0xe61f96af, 0x402f9418, - 0x187e62fd, 0x9c5805c5, 0xe7a92dfc, 0xca3d1db8, 0x727a2165, 0x9c51df02, - 0xed09e806, 0xb1e34bf9, 0x6b9e78e9, 0x52f44774, 0x73e1f3c4, 0x3693c226, - 0xd38a35eb, 0xbc7c2ba4, 0x6b3df5e2, 0xc61fa2c7, 0xb865e6f5, 0xabbb7aa4, - 0x353a511a, 0x4d9f9023, 0x52968cfb, 0xbffaaf1c, 0xf29f3ccc, 0x17f92a50, - 0x291a0a3a, 0x6df7b29f, 0x4e3ce1ab, 0x77661972, 0xa8e4fe53, 0xbc505fae, - 0x194079c0, 0x72762f32, 0xd6f083b6, 0xa0cd8e1c, 0x3d4b9b1c, 0x43b56724, - 0xb538a2bf, 0x094356b6, 0x7eccdac4, 0x0b439e13, 0xefe460af, 0x32e1d31c, - 0x8a157ae1, 0xc3be98fc, 0xa418987f, 0x0f8c8afd, 0x937e7844, 0xee1567b9, - 0x3d15b4c3, 0x3d718797, 0xcd4db80e, 0xbc5fd865, 0x872dfc99, 0x4fd21952, - 0xddf15761, 0xb85ea153, 0xb0f145c6, 0x296ee7be, 0xcc2aff24, 0xf310cc73, - 0xf336ca2c, 0x9aa50ffe, 0x9b699f50, 0xd5470f98, 0x04d559dc, 0x875083f7, - 0x3c8a467e, 0x453f1955, 0xa9ea143f, 0xd7e0ecf4, 0xffb63f30, 0x14b2d21c, - 0xe3490e7e, 0xb2e712fe, 0xf3c71fb7, 0xfc2c3b3d, 0xc391e79c, 0xdf936613, - 0xe0a6ad6f, 0xe6ee7c3a, 0x663794f9, 0x42e70c9b, 0x847ff006, 0x1d4756f2, - 0x6bd705fa, 0xaff61630, 0x68bd3999, 0xd13b3d6b, 0x2d38b8bf, 0x97ba7948, - 0x8a5545b5, 0x3d4eb99f, 0xec27ab50, 0x3d70b673, 0xef8fbcd3, 0x35f793cb, - 0x6e5fa65f, 0x2dda36cb, 0x927ff5fd, 0xfe83f2dd, 0xfdc6fff1, 0xf3ee330a, - 0xe497ed92, 0x3b20dd7d, 0xe1bfa93c, 0x8f9918ec, 0x0e303d52, 0xd29da7b7, - 0xf21b0a4e, 0xe21daa75, 0xd8cda17c, 0x5c23e5ff, 0xbf995f34, 0x5f52b593, - 0xf1fa7981, 0xd7f2301f, 0x70a23cc9, 0x09f7cf35, 0xee746c9b, 0x29dacbd0, - 0x8b24687f, 0xd3f90a2a, 0x6d7ce87a, 0xc111e636, 0x47b2eb77, 0x99dbbf51, - 0xf24a8d6f, 0x6e105752, 0x509fe63b, 0xeb646abe, 0x3ae71c22, 0xc7638d07, - 0x308b93fc, 0x15bfc085, 0x06f4ebe5, 0x05c85f1e, 0x9bf48c7d, 0xa1d39a3b, - 0xa1e78ebd, 0x99133cc8, 0x50f12217, 0x3b9bf02d, 0xca115176, 0xf04ab5c1, - 0x99ae7151, 0x4e0dffcb, 0xec195e71, 0x79c0cf6b, 0xfbc63ee4, 0xf898370f, - 0xaf376479, 0xf9d18c77, 0xf82fa079, 0x728ebb39, 0x2832779e, 0xaf09253f, - 0xc9e53f32, 0xe411e0b4, 0xcbf3e497, 0xd6124e92, 0x6f47ce8f, 0xfaedc43b, - 0xcd0b06ea, 0x35c96fa3, 0x5bec97e4, 0xffa86262, 0x9cadbbab, 0xdbc692ee, - 0x51616756, 0xd88b57ec, 0xf5ca7e51, 0x16bb32ff, 0xfd14b5d6, 0x6b5a47be, - 0x38053a2f, 0xa01ada3e, 0x74aecfb2, 0xf9d217aa, 0xa928b9d2, 0xf9f2d89e, - 0xe60e5ab5, 0x140bc4db, 0xb7e79920, 0xea93347e, 0xb077f199, 0xcf16eafe, - 0xc39034d7, 0x3be2637d, 0xffff7814, 0xdbc47f79, 0x19731691, 0x87a1f77b, - 0x5f1d8666, 0x91fddf41, 0x9c71e725, 0xc4d3bd41, 0xc8c5567a, 0x5df4245f, - 0x5e879725, 0x25ec8587, 0x653fc8af, 0x151f2235, 0x5f503b23, 0x714e5399, - 0x0fd3077b, 0x8f3db0c4, 0x7682cf9f, 0x6395ffa2, 0x26da7fb8, 0x49e582e8, - 0x184f54bf, 0x22cadbe5, 0x2fdf7d37, 0x23580f8f, 0xc7c63fdc, 0x0be9e37f, - 0xf325be28, 0xe573196a, 0xf280b9cf, 0xfbf50c6c, 0xa61ce2ec, 0x73c7cae6, - 0xc2cd2bec, 0x36f515ee, 0x8bc53067, 0x043e44f3, 0x2b8dee7b, 0x7c865bbf, - 0xf7e0e674, 0xbb5ca347, 0x82fb02ca, 0xeed8e421, 0xfac72e1c, 0x0a358ecc, - 0x0ce3577c, 0xfac2f08e, 0x773a95bf, 0xa8291e06, 0x82cd311b, 0xf8581747, - 0x9af11551, 0x3dc4e829, 0xaee7c387, 0x77982809, 0xc7ced2ba, 0x7e6a0ccd, - 0x9c10f73a, 0x70075ca3, 0xbcb854af, 0xc9d28f86, 0xd3d52a8e, 0xa3611cf1, - 0x0aaad738, 0xe74971b9, 0xf5ed1526, 0x35beb79f, 0xe006d355, 0x878885fb, - 0x78c8a2ff, 0xcbdca23e, 0xce5962ed, 0x900bf556, 0xf0ad56fe, 0x12f336bc, - 0xf8e9ce7c, 0x9565b4ca, 0x557da798, 0xfa254b6a, 0x4f3d0769, 0x0965e787, - 0xaf7f2b75, 0xc02f16d1, 0xed0be673, 0x8f8849c1, 0x7bbde7cf, 0x3b87ca27, - 0x0778df73, 0x30de24f3, 0xaf91390b, 0x98eef588, 0x79eb069e, 0xf22dd8ac, - 0x0f446c3c, 0x3f72c6c7, 0xdb1e7f64, 0xfaf28538, 0xe7e1ce66, 0xb165af49, - 0x9ef81eb6, 0x3ed0159c, 0xd9117263, 0xde453391, 0x02b78cc5, 0x9817e869, - 0x435c4371, 0x5d9c3a39, 0xacd79574, 0xc3f024f7, 0x7eb1bad5, 0xfeb1a96d, - 0xfeb19f35, 0x1a7fc98d, 0xd97f589b, 0xf48d9fee, 0xf3c2bcf4, 0x3097c33e, - 0x47bdd117, 0x32fda309, 0x715c99e1, 0x27e7970e, 0x77d8abfe, 0x5199333d, - 0xdb3ed67b, 0x20373c2e, 0x68aad7fd, 0xb665e09f, 0xef7e0cc2, 0xb8bbea03, - 0x3d1cf222, 0x0761d314, 0x3f71756f, 0x816bbc2e, 0xd3ce0e7e, 0x46aa3f89, - 0x4e9052da, 0x76261cb2, 0xa552f239, 0x239aec8d, 0xb9e4ee82, 0x058d2aea, - 0x8602cf30, 0x1be5839c, 0xe88bd766, 0xc87f0ea7, 0x69dbe718, 0x8a5be51a, - 0x415b1831, 0x5d0487f5, 0xfff2911f, 0x57589a07, 0xef1840e0, 0x1e5cfaec, - 0x74652e87, 0x656cfe5e, 0xdd25d509, 0xae01fe4b, 0x41a18d1e, 0xe927f445, - 0x0b4ea7f9, 0xbf7a83d1, 0x34bbf849, 0xea590213, 0xb8807092, 0xc93d42c9, - 0x7195fec8, 0x6c9b7cba, 0x7ef8fcd7, 0x7e75930e, 0xd44b2bde, 0xaa6a29a1, - 0xf2fcfd40, 0x3b7f48ef, 0x879c417c, 0xe746cd25, 0xa3e38693, 0x767f825d, - 0x4b91f125, 0xe8f89abb, 0x3b92cea7, 0x9c6bee08, 0xa5afd42e, 0x0cba9730, - 0x2a23fd2a, 0x4fce3bf0, 0x474f8a6a, 0xed66f9be, 0x825aa9f1, 0x9bef869c, - 0xc6a9f7f8, 0x7df0bdef, 0x69f7c246, 0xe0d97df0, 0x6d3b77ef, 0xec44d351, - 0x21ef4aa7, 0xc9a5187d, 0xade6235e, 0xaeeff166, 0xa3b17911, 0xd47de0d3, - 0x3cc6a55b, 0x67d93613, 0xa4e4fca3, 0x94ab92bc, 0x57c839e5, 0xba9adb57, - 0x97bfa07b, 0x655e3ac5, 0x82e67e0a, 0x2dcf2fe7, 0x57fc8a39, 0x98688b6b, - 0x8b2d77d7, 0xedc5c2ae, 0xc47c169b, 0xe1f24c5d, 0x6693e459, 0x03363835, - 0xedcc67ea, 0x222d6fa3, 0x9bce79fe, 0x495e1839, 0xa45e1227, 0x493fa417, - 0xf770c92f, 0x3bd7e7af, 0x3b6f1129, 0x4a5851d8, 0x16b18abb, 0xe7ad779e, - 0x880bcc0f, 0x65ad8668, 0x2f35da34, 0xdc93092f, 0x00fdcab8, 0x9cbd65e5, - 0x944ffc1b, 0x7e177567, 0xcbe1a052, 0x716379de, 0xc6f000df, 0x95e137fe, - 0xbca0e3f6, 0x862d0fe3, 0xf8e1e3bc, 0x421b8e4c, 0xfcc550bb, 0x47949de4, - 0xf0e39a1c, 0x109179e1, 0x5256c1e6, 0xc2ec8afc, 0x6f6e14e7, 0xb09b1587, - 0x3f37cee3, 0xaf7b7199, 0x33dedfa9, 0x9477d7e4, 0x6e3bb873, 0x35fde5d5, - 0xc79c5edc, 0x4b393db8, 0x51742fb4, 0xefc3ccbb, 0x86fdc9d8, 0xd58f4f1d, - 0x03b05fb1, 0xe9607ec9, 0x322ccec2, 0x7f839bde, 0xde40d64a, 0xb73366f8, - 0x7c99b75f, 0x62e79455, 0x9ce2f7e1, 0x318cfe91, 0xff64fc7c, 0x628e6e62, - 0xd7f74f88, 0xc5fe4eff, 0x3f307752, 0x585bfa07, 0x4c502fe6, 0x33f71708, - 0x1c3e7d02, 0xd6fe9863, 0xfeed1a32, 0x9bcb59ab, 0xcfa262a6, 0xcfa41ce2, - 0xc59f4009, 0x9d1cfa06, 0x24e5c993, 0xb3e925c2, 0x934b2e9f, 0x1782caf3, - 0xee1d3f60, 0xa3355fce, 0xf56ddcbd, 0x9e5abcf1, 0x072c9827, 0xa059e012, - 0xaa3c7871, 0xc24cf04a, 0x39e19371, 0xa4493e1f, 0xf9c66ccf, 0xc97e3861, - 0x59d858d6, 0x2f2fc031, 0x083583db, 0xacdf3f7f, 0x41a3fbe2, 0xa20eab70, - 0xe46febaf, 0x2a509471, 0x4f1847d7, 0x67f181c9, 0x5faff189, 0xfaf0e9cb, - 0xdd10b17f, 0x8451f802, 0x9f68b67f, 0x7944ddd5, 0xcc6bb354, 0x00ed1227, - 0x13a9b719, 0x94f1cdef, 0xe605919b, 0x4bc634cc, 0xf1e26eea, 0x8b58eb9a, - 0x7ebde119, 0x3a9fb18e, 0xcc13feb6, 0xc9bbab0b, 0xd3983cf8, 0x8b19671f, - 0xc2a39671, 0xfc07d08f, 0xd3f4fc82, 0xdf0fc5cc, 0xf63bf40a, 0xe8156587, - 0x6b32ba77, 0x504deec9, 0xf1b6f1ff, 0xd669ff54, 0x06f3bfb7, 0xa128efb6, - 0xb9260d7a, 0xf9083ee1, 0xd54df511, 0xc114d78d, 0xa2ed47b8, 0x39f95bdf, - 0xb04a6f02, 0xe7bc1663, 0xf28a389d, 0xbc846b21, 0xdbc85be9, 0xc9d0bdaf, - 0xd66f5e53, 0x9358dfc9, 0x79f5efc2, 0x2bbffcad, 0x66b73f30, 0x3c57a894, - 0x47eb1e3f, 0x1ee84f95, 0x8726de80, 0xce6ff886, 0x09da7ee5, 0x1c744aa5, - 0x4326a5e0, 0xe7c4dff4, 0xd1e2b335, 0x9a8fe45c, 0x04cfde6a, 0xc5b5b4df, - 0x2ce99ef8, 0x6d737bd5, 0x250f2869, 0x70e7b59f, 0xa9ed2cfd, 0x67fbe080, - 0x8db6effc, 0x36037e80, 0x0c5387c5, 0xdf977e4c, 0xe7e0e55f, 0x22fe02cb, - 0xd3bcfd0d, 0xb37f3cfd, 0x0722b6da, 0x0f5fe7f7, 0x5e712a5a, 0x51f95b2e, - 0x27d26fb4, 0xf9449b4f, 0x466636be, 0xdf74073d, 0xf1787c41, 0x48690527, - 0xdd230e6c, 0x259aba4b, 0x48c6bde9, 0xdbafc0d7, 0x5cbf3272, 0xdae81b5e, - 0xc3d7403e, 0xd700b9d9, 0xa9ae098f, 0x3fd5fd46, 0x265f124e, 0xbc9c3b8f, - 0x7944bfc0, 0x275f003a, 0x661e5ff1, 0x7f2315c5, 0xecfe4bb6, 0xa62c3842, - 0x29b39d18, 0xe9e37c54, 0x7630ea60, 0x1f2f8486, 0x8315ae7d, 0x4d3fc2e1, - 0xcffc7fda, 0x3cf2fb83, 0xf9df0ed1, 0x5c00c659, 0x242bfe30, 0x7871570f, - 0x5c2d2bb6, 0x5c7b08be, 0xe59be7ee, 0xf38cbb7c, 0xe7e14aad, 0x77e8bdde, - 0xf97bdf21, 0xcfb87ef8, 0x7ce41d63, 0xcf6f4242, 0x169c05b1, 0xee75db98, - 0x1b9fa27a, 0xb469f858, 0x8339968f, 0x74f117ff, 0x843e14c4, 0xcc859cfb, - 0xa057f14f, 0x1272778f, 0x6f090dec, 0x879a9e32, 0xf3c9a791, 0xc0cfc649, - 0xbec8c5ba, 0xfad8e793, 0xf39e7be7, 0xc7897694, 0x6577f462, 0x8654ff08, - 0x452147f0, 0xc99e7ea1, 0x2fb87c52, 0xc853ee98, 0x6cc998be, 0xd6679724, - 0xe19e7d72, 0xd487f6e0, 0xc7f1c3fb, 0x92339715, 0x991b3357, 0xe7c73738, - 0xd9874c95, 0x2c0ee7ac, 0xadf4da67, 0xd1ef900b, 0xe007d14e, 0x7ee0e99f, - 0x215cecec, 0x24cf583f, 0xf5fdf3d4, 0x67be7a41, 0xe49fca12, 0x9e66c9fb, - 0x8cd2fee3, 0x99ca8c73, 0xa12777be, 0xeda8cf9e, 0xcc728499, 0x737bf2e9, - 0x1fdc0d27, 0xd1c78c98, 0x871926b9, 0x4cfa2f3b, 0x3f191fe6, 0xc706736b, - 0xcfd238e2, 0x55894671, 0x1e154be1, 0x583fe897, 0x76ec7484, 0xff434d15, - 0xe81b1cc5, 0xcbba1823, 0x1730bc15, 0x008fede9, 0xf10e6e0f, 0x75e3c055, - 0x347bc135, 0xe1e12c3e, 0x2b878136, 0xfb3d5e85, 0x89f14ab0, 0x43e97f1a, - 0xbd084218, 0xe2116662, 0x45e93f57, 0x59d8bf79, 0xf8a2a030, 0xb24e63fe, - 0x5abf1633, 0xb195f14f, 0x4f4c4c5b, 0x22e393d0, 0x327b8629, 0x30cbec26, - 0xcce82fd4, 0x617fbc35, 0x7b4328d7, 0xa1bc7479, 0x2a57a2fd, 0xb149f50c, - 0x2ff78629, 0x50daab7e, 0x1ae7a4bf, 0x3f53fbc3, 0x83a86d98, 0xde70d0c6, - 0xd8559f7b, 0x65f79836, 0xbe196ff1, 0x19b6cdff, 0xf3bc60af, 0xb2f7d8a4, - 0x0a563fb0, 0xe9205878, 0x637cdcf6, 0xaa25517f, 0xf3df2154, 0x79eb05bf, - 0xc034f6be, 0x0bbf625c, 0xc4f68ddb, 0x7ac62de2, 0x55a6f743, 0xe7071b28, - 0xe354b479, 0x79c93955, 0x79ae351e, 0x50cfa426, 0xe317d82e, 0x62ec1110, - 0x8e1b33cc, 0xfd6cbfcf, 0x2fe8d84b, 0xfefe7f5b, 0xf5d90b16, 0xaa7d5f8b, - 0xac8f0a2a, 0xdbfae35e, 0xa7fae375, 0xdfd71a96, 0x7fae33e9, 0xfae364fa, - 0xf5c6fdbb, 0x5c6b511f, 0x7180ccff, 0x8cebb3fd, 0x34139feb, 0x06c8ffae, - 0xb7e7fae3, 0x70bbd718, 0x8b3d7199, 0xed0d4bc2, 0xe52febc9, 0xdb9af165, - 0x7a01ef8c, 0x2074094d, 0xa04168e9, 0xc677f281, 0x30cf7fb4, 0xc03d324e, - 0xf744d1be, 0x6e3ec1bf, 0xf4fe729b, 0xfc8ad201, 0xf1f4c9bd, 0xeec2b96f, - 0xfa017414, 0x0ae513a8, 0x614f17d8, 0xd8563759, 0xeda181fb, 0x12bf290b, - 0xbee279f5, 0x36b93878, 0x7d894f48, 0x0a7ab0f2, 0x81f6c9f7, 0xf470f27d, - 0x8fb31c7b, 0x4f5a8ec8, 0x5d1ba57e, 0xf14f8e1c, 0xcfe825d1, 0xf2f4827d, - 0x32700071, 0xe71c7bc0, 0x4f1fe303, 0x8dfe4099, 0xd928b36f, 0x1982ffed, - 0xcdd83096, 0xe2ada898, 0x953a4f3d, 0x2f6f42f5, 0x858ffe14, 0xb95be0f6, - 0x9851efdc, 0xc5e6e385, 0x7b14bce8, 0xdd79c46d, 0xe3027123, 0x4f782008, - 0xca011c61, 0x9ba73b5e, 0xf8ae52d3, 0xc049ee99, 0x4ae9fce7, 0x6ab5d929, - 0xcd3de50a, 0xfd2141bf, 0x787fff34, 0x2cfa1719, 0x4cb95cb9, 0xd85db3e2, - 0x482edc03, 0x149ac3c7, 0x07416277, 0xc2e7cde1, 0xb8fe8675, 0xfc47ff1f, - 0x0ae3cd7c, 0xd06726d3, 0x675a3331, 0x0f3c6f5c, 0x9c38daa5, 0x0d999b8f, - 0x058139f1, 0x57bc0ec9, 0xfbc6d103, 0x7bfbcf1b, 0xd3fa1463, 0x7cfff554, - 0xcfe306ad, 0x9ffa2e38, 0xfe863e1d, 0x63ebd566, 0xf41abfe8, 0xba14c0fc, - 0xcebfa324, 0x87f87bf8, 0xc27e9178, 0xbb2f413c, 0xbdfb8c9d, 0x2386fc92, - 0x98c09055, 0xe7e663bf, 0x16dabdc3, 0xe63c9fbe, 0x984d635b, 0x37666337, - 0x32fbe79e, 0x6df3087b, 0xc7e4274f, 0x790cbac3, 0x3cb4e98f, 0xb657efae, - 0x71865c36, 0x07115ea2, 0x7835a7bb, 0xaab7ae19, 0x0e2f28f9, 0x277257ef, - 0x40f16f7c, 0x6a9f027b, 0xdd43068e, 0x5e1008ec, 0x10b6b556, 0x3dc598dd, - 0x6ef3ab50, 0xfc130573, 0x148e1712, 0xcc2d86f6, 0x984c595c, 0xc1f7f0c6, - 0x55f38674, 0xc4e9da5d, 0x0bd5a87d, 0x2bca25fd, 0xfa2590ad, 0xb6b4d7ad, - 0x94abdc10, 0xb33b1060, 0x3b51668e, 0xe1aadbe0, 0xbe785459, 0x67922af5, - 0x3e6de716, 0x3867f7bc, 0xdabd59fc, 0xc87289e7, 0x8728d23f, 0x5db56fee, - 0xd95af88e, 0x93c68cba, 0x756f6b78, 0x8df58e5d, 0xbed15ead, 0xb54dda82, - 0x71f482ba, 0x8621681a, 0xc7ad1671, 0xb03d7189, 0x03c61933, 0x045b5ecd, - 0xe1eac899, 0x05a3b2f0, 0x5d731f44, 0x8df4061c, 0xbc7d03e5, 0xfb4cccb3, - 0x1df3dbd3, 0xafedfef4, 0x0fd1798f, 0x1e01607c, 0xf98aff51, 0xf0238ff4, - 0x88721167, 0xf200c169, 0x23572595, 0x6b86747f, 0xdfe3ad36, 0xbbc49fda, - 0x1f28cec5, 0x20ef92d4, 0xe17cebbb, 0xf7148d0c, 0x27bc0950, 0x44f00fe3, - 0x8176f472, 0xe2efdba7, 0xefdbbe7e, 0xcec79460, 0xd55fc196, 0x148d5d00, - 0x059b25f2, 0x056f6ca8, 0xeb8252c1, 0x0b416365, 0x49d675e8, 0xbfd1db2f, - 0xcd7eed83, 0x4deaa18d, 0x58599e35, 0xaa7c9c6e, 0xbef1d91d, 0x618b3f4b, - 0xc474be89, 0x4581ab97, 0xc51fccf0, 0x1d783d8e, 0x89a7af35, 0x5e3ab4f6, - 0xe9ed174f, 0xf7cf5e01, 0x20d4a93f, 0x97f14960, 0xd5c6477c, 0x2dbe51a3, - 0xb27cfc60, 0x3b60e7b8, 0x91c2f213, 0xdb06ab31, 0xbe74626f, 0x50ffb640, - 0x4e38e7b4, 0x394629ac, 0xfdf8c73c, 0x6c878156, 0xe9f689c7, 0xb6319f14, - 0xa64af8cb, 0xf42bece3, 0xfdb1997d, 0xd3bdf141, 0x1d363671, 0xc71b47db, - 0x53da20df, 0x08ef3c1d, 0x473f21c4, 0x15efda2f, 0xc76c76ed, 0xed8d4bf1, - 0x2bf8c56b, 0x43ad0095, 0xf8899f3f, 0x9d568ee4, 0xf67cc9ea, 0x7e0cc8ea, - 0x99f0598e, 0xf21b196b, 0x23abfcdc, 0x9a4cbe79, 0x0ff7e3de, 0x7b650f21, - 0xb8a34b86, 0x10b5eaaf, 0x421d591d, 0xec3e088e, 0x8b4a2397, 0xf717138f, - 0x3d197f97, 0x8e7ee103, 0xfe00acf2, 0xbef39e90, 0x04c16263, 0x98db9679, - 0xef0982c2, 0x1864177b, 0xe53759ea, 0xccf7de1a, 0x77686519, 0xb4378e54, - 0xf13e58b3, 0xae826dc7, 0x0c2aca52, 0x02bef2ed, 0x923e73a6, 0xf479b576, - 0x677bc314, 0xa474f54b, 0xcb57d3ed, 0x367cabfb, 0x39b70b94, 0x1f236547, - 0x3275a4fe, 0xef20df1a, 0x8974a26c, 0xc9474bd2, 0xa2eab656, 0xc7f54a5e, - 0x7aaf3cdc, 0xd78fab65, 0x6f9d188b, 0x4b5ad95e, 0x2f81c7f5, 0x56d7fcb1, - 0xa07b953f, 0xfb0e160e, 0x43aff411, 0x7fa13b3f, 0xfd023fac, 0xfa1db963, - 0xd087f2c7, 0x856fb63f, 0x10feb17e, 0x83e585c0, 0x7f3e0fd0, 0xfac7fa00, - 0xd500d6a6, 0xa3ad6bef, 0x20d686fa, 0x36b6f795, 0xadb5f3d0, 0xdd5f542d, - 0x7bca8cba, 0xae54c35a, 0xed435d6c, 0x1f37a116, 0x1f1fe713, 0x7dcfc69b, - 0x467faf27, 0xeed5f29e, 0x4504a8bb, 0x93c8655e, 0x7dc3c8c8, 0x2f31a775, - 0x7047f110, 0x931e39d8, 0xe02b18e1, 0x2b62cf18, 0xa0dcb952, 0x2e98eb38, - 0xc0a9dddf, 0xf85b23a7, 0xc57517ba, 0x81a73da9, 0xcc56378f, 0x2cc27993, - 0xef1f8aaf, 0x957af7c5, 0x8f2a7558, 0x831f9337, 0x553f0179, 0x9133dce2, - 0x7084c479, 0x7f419369, 0x1fb3cc27, 0x270e6e5f, 0x78286de2, 0x7c78f22b, - 0xe4ecad43, 0xb6d49bf7, 0x52cd9147, 0xbf742dfc, 0x102ead89, 0x04f4a0d5, - 0xc24f7482, 0x603373f8, 0xed720593, 0x874ce5dc, 0xb8d1af32, 0x505dcaff, - 0xa8e7d861, 0xfd3236e7, 0xccb7e822, 0x194a4fb8, 0x3be19b7d, 0x0cf7de5b, - 0xddcf16ed, 0xb7f9f686, 0x22f2ad14, 0x8a32473e, 0xafd7593b, 0xd7003960, - 0x044d8ec2, 0xbde05057, 0xfdf9d157, 0xefc5fbed, 0xfffb0844, 0x2f812ec7, - 0xd7da7adb, 0x6af3758e, 0x84d87a49, 0xa7e3e7fa, 0xee8e49d2, 0xfe44c47d, - 0x622c71ed, 0x01337942, 0xbf6c48cc, 0x56726f00, 0x151ccae9, 0x574ce5eb, - 0x8b117eb1, 0xec08bed3, 0x17a43aff, 0xb11fffb0, 0x7e4cfd43, 0xbf3cc7f0, - 0xba7a4a2b, 0x8967ac44, 0xd16d07dc, 0x73c3fd92, 0x635fc8f3, 0x26d6073c, - 0xdc2b01f6, 0xef18d955, 0xff261ded, 0xd6fde9ce, 0x1eb005d4, 0x2a3a9cce, - 0xba0df3e5, 0xd173c869, 0xbf2abecb, 0x623d016c, 0x086597e4, 0x9fca99ff, - 0xaabba167, 0xf89c7479, 0xe52ccda6, 0x728e9e98, 0x4beea06c, 0x3ba2bb27, - 0x89a3f087, 0x1adbd9f5, 0x3900fca4, 0xd377ed4f, 0x560f985c, 0xf74ff222, - 0xb53adeb5, 0x661f2126, 0x52dfa0b7, 0x3d45ab16, 0xf2665a5a, 0xaf27a845, - 0x1f617fc1, 0x73c7eedd, 0xf3055afa, 0xc71e18a1, 0xbabce9da, 0x794a85f6, - 0x4b91da40, 0xb0760e98, 0xe16511c3, 0x997e81b2, 0x477c83f0, 0x5ccff5c8, - 0xad0f3435, 0x3e47da40, 0x33ecddd4, 0x74863f87, 0x998759f7, 0x6309e5b3, - 0x9183a97b, 0x6a545b9e, 0xa60ae889, 0x3dd3b423, 0x850eda8b, 0x1c2115e5, - 0x50f3bdd3, 0x254c1f8f, 0x52dd4dba, 0x7bc35745, 0x79f5c14c, 0x1e99c700, - 0x1a49a0fd, 0xd35ef057, 0xb42ecb04, 0x5e22c71b, 0xa5d19c70, 0x6285c784, - 0x575afbbe, 0x159e9e10, 0xefcb68f3, 0x87873bc7, 0xcf78fcf9, 0xe90ea2e9, - 0x73ce31bf, 0x37f56543, 0x95c6def0, 0x74d85531, 0x33ae7c46, 0x53ce26c7, - 0x3802e006, 0x5538459f, 0xbffc9b84, 0x8f4d7e7c, 0xc819bf70, 0xbb8a5ab1, - 0xc4b1324e, 0xa32cabb8, 0xc8cdfe42, 0x4ebc1173, 0x0ba9dcef, 0xdfac4a2e, - 0xb8fd7444, 0x761fe7c2, 0xcd2f3c6a, 0xfd13d7ef, 0x7ee4ebc4, 0x487f9c59, - 0xdff6f011, 0xe79e36e3, 0x6c583a61, 0x0d2de60b, 0x25fe1fb7, 0xc4a4ca2e, - 0x18e830fd, 0x649d5718, 0x759f3ca3, 0x7f4b8f32, 0x337cc743, 0x8afcf12c, - 0x6ae9d04d, 0xe4af31a7, 0x77b71e5c, 0xe8f589ce, 0xc6be71b3, 0x567964b8, - 0xdd17bdc2, 0x91ffe4f5, 0x6ebecc71, 0xfd2e0f9e, 0x09044b6b, 0x78e51df4, - 0xa5587be8, 0xee92e5f8, 0xa17df96b, 0x7ba01e87, 0x1d2fa156, 0xbc5ea1e9, - 0xe8c6bf5f, 0x3bb059ef, 0x1f452ab0, 0xc45a57ec, 0x48d7e4c2, 0xfb2527f6, - 0x279b7e91, 0x563e69f6, 0x93ca718e, 0xa58f8beb, 0x88a67ee0, 0x91dbb9d1, - 0x8f7493ea, 0xedfb5831, 0x2b294f78, 0x24f4f7e3, 0x0525fbaf, 0x3ef3c216, - 0x1c63aeb9, 0x37d867e4, 0xbefff389, 0x7d7ecf17, 0x96f3f40c, 0x81ce18ae, - 0x099ba5bc, 0xae81e38f, 0xac64ecb1, 0xa0fba876, 0x5f4df3b2, 0xa5c0bced, - 0x68d7dfc6, 0x9639eaea, 0xcbbc93aa, 0xfa7807ca, 0xad3efd8e, 0x4e27f88c, - 0x575107bf, 0xb841e1c4, 0x7ecbfcf1, 0x137327d3, 0xbe7c60e9, 0x7c83edc6, - 0xbf9357d3, 0xceb84635, 0x7599bd94, 0x1c6b870d, 0x3d1bd5c2, 0xb7689591, - 0x0ff6b848, 0xa5fabf73, 0x934f155f, 0x0120fa8d, 0x12ff534f, 0x865bf69e, - 0xc0966786, 0xf28e4fcf, 0xb70642fb, 0xd5fd457f, 0xccf78461, 0x51ebb163, - 0xb3bc023c, 0x53de7f08, 0x15331459, 0x14acebf8, 0xe42959f4, 0xa8ce8f8e, - 0x17dbd0b0, 0xa75e7e53, 0x7743dbc6, 0x79e08a2e, 0x0b8bdf02, 0xe0dfd10a, - 0x7ba56e3c, 0x7949429e, 0x2f5cb222, 0x573fb1e6, 0xab0f1219, 0x78bcb9f3, - 0xd4f9b5f1, 0x596fbddf, 0xed83ca19, 0x5ef5df22, 0xef0da757, 0xc47895ef, - 0x2194057a, 0x2a117c4b, 0x3f2b7bba, 0x218ee9b3, 0xf1f133c6, 0x1be24bee, - 0x572c9e39, 0xbb7297e4, 0xe2aa3954, 0x2efb8739, 0xd9ee937d, 0x2352afba, - 0xe337fb99, 0xfe127d7f, 0x7d666fa3, 0x8acbd39d, 0x2aa3f47c, 0x037da5ef, - 0xfe2521ea, 0x9fc432b3, 0x0ff34825, 0x3b656dbd, 0x6a78c195, 0xe72bf414, - 0xe12fe727, 0x80b65e76, 0x7ae099ce, 0xc5abe020, 0xa44f52fb, 0xf387bd0b, - 0xa9713d22, 0x4c89cfc6, 0xef5d68d2, 0xce853c9b, 0xf917ecf5, 0x2c4bf114, - 0xc32efe43, 0xf76f0233, 0x0c45fb9e, 0x770da9ef, 0x055ee99b, 0xbf78f5a6, - 0x7a147409, 0x9a7ba35d, 0xf16a9e81, 0x5f17a8de, 0xfb869b3b, 0x66f903e8, - 0x3e40fb82, 0xe77d8797, 0x6f3a5ad4, 0x2e67daf3, 0x9ffe8135, 0x5d8557ce, - 0x39e18b12, 0xfc158d9a, 0xd84380dc, 0x4ed78e01, 0x8efc2035, 0x2ab3dfc9, - 0x4f767a09, 0xdbbe95be, 0xf9678968, 0x48740e30, 0xdfee5165, 0xfaeffba1, - 0x38ba0bcf, 0x8f2b9a1e, 0xe8e09d92, 0x3de2f7e6, 0x5c13af9d, 0x7841f708, - 0x33ee329e, 0x57b63d57, 0x06a378c2, 0xf8ba77be, 0xe24ca67a, 0x77dcd0f7, - 0x785dcfe9, 0xc2ba5eef, 0x4be8fee8, 0x3906cc0a, 0xd7c45f5e, 0x1632b3a1, - 0xe5fc851b, 0xb6af28d2, 0x0d9b7a33, 0x17c97aed, 0xf4a947a3, 0x97916add, - 0x29727abe, 0xe3a499f1, 0x57c105b9, 0x02366e91, 0x76493c5f, 0x9d302c4e, - 0xc72ae3f0, 0x95c7e3fc, 0x3fb71d58, 0x2fd42e2c, 0x819326a5, 0x380b8adf, - 0xec12c8dd, 0xee77b252, 0xf52cb410, 0xc6c45b7d, 0xb7ffbf30, 0xa3a566e7, - 0x2796da5d, 0x0dbf3ced, 0x095db5f1, 0x38e117a4, 0xbed2a5ff, 0x4ed7c5ef, - 0x6db8e034, 0xdbe42f30, 0x58ea7e7b, 0x9b49f68f, 0x2a7c4fcb, 0x26dcd7c7, - 0x9fbc1eb1, 0x2bff16fd, 0xbb8c6fe8, 0x47447df9, 0x43635ca6, 0x4cf787fa, - 0xad7bcfd8, 0xd81a0bf8, 0x07f90d4f, 0xcf66ba16, 0xb116efc0, 0x6bb42ae0, - 0x86a87517, 0x11ee177b, 0xb9e162f2, 0xd84d1614, 0xfc9c2c1f, 0xb6373a2d, - 0x8b1a5cf0, 0x8f75bd82, 0x8f7d1738, 0x0ac45738, 0x443b3d38, 0xdfe515e9, - 0x24bef7cc, 0xcbf995bd, 0xdf39f3bd, 0xb7e802b3, 0x14b1e949, 0xa71b10c1, - 0xebce9efc, 0x62ead7bc, 0x780492d1, 0x0473cd07, 0xd38c268b, 0x1b39deff, - 0x7d6067cd, 0xcc0efd39, 0x787841d7, 0x784bd5af, 0x91ffbe1c, 0xf40e3c06, - 0xc780ca3f, 0xd097fdc1, 0x96b5eff8, 0x13ff497e, 0x375fe986, 0xefd03fc0, - 0xf7b71a68, 0xa71ffcc8, 0x891ddf02, 0xf9edbdde, 0x331dfc4a, 0x017efd2b, - 0xa6aceaeb, 0x338f8473, 0xe77a673a, 0x83bddfe1, 0xee779af9, 0x8c70f8b2, - 0xae7c733e, 0x333d086f, 0x78c2b99a, 0xc72c979f, 0x7cd31417, 0xb4db9f92, - 0x32f30b88, 0x0b9aa56d, 0xc6d11f7f, 0x71bb9162, 0x236952df, 0x42e32739, - 0xe53fdfb2, 0x3b3cf2a9, 0x6f7907c9, 0x979112cb, 0x5e08ec57, 0xd4beeb81, - 0x13fcded4, 0xd283f6f8, 0xcc373a36, 0x33f69b98, 0xe1a36e32, 0xa315bf2f, - 0xf0c0305f, 0x7a13cdfc, 0xf77e0670, 0x18271043, 0xd82f51c7, 0xb5bcc41d, - 0xb8df620d, 0xfaf31ec1, 0x0de6e412, 0xb357da05, 0xe893da17, 0xf72fd276, - 0xdedd3946, 0x227e8050, 0xfcc4f635, 0xedb7cc22, 0xe976f711, 0x55778a16, - 0xfefba31e, 0xff7dcbe6, 0x8ebce49a, 0xd1da377c, 0x8694ce32, 0x6b687779, - 0xbef7e46c, 0x7af2a7d5, 0xa08c7ffd, 0xffb01073, 0xf9432d49, 0xfee55fb2, - 0x3adf1120, 0x67d0e62b, 0xf94058db, 0xe41f22f7, 0x744bf76c, 0x35d9e4af, - 0xebfd6863, 0xdd3ef85f, 0x973fb70b, 0x43beb1eb, 0xf563d24e, 0xde155f56, - 0x973fb85b, 0x5a9dabdb, 0xc122ad34, 0x579d5d7e, 0xe3f9f24d, 0x894c6335, - 0x0aef8ff1, 0xfa51b079, 0x1578b537, 0xb8f9679e, 0xd233fa32, 0xf4ec07a3, - 0x83a6513b, 0xfba2abbf, 0xe95a372d, 0x0faa0177, 0x875cdb8e, 0x8d34c3fb, - 0x074d91f2, 0x99cf04ed, 0x2d7efc75, 0x5de516fc, 0xf491c1d3, 0xa9f556fb, - 0x6c27ca71, 0x6095f14a, 0xe0feafdc, 0xffd7ba54, 0x057186e4, 0x644eff28, - 0xaf7405ea, 0xf43c06f1, 0x6343f509, 0x17b5f3f9, 0xe75579d3, 0x50e0d4c6, - 0x8fa9107e, 0xdaefef92, 0xdbde5b9f, 0x6719f885, 0x7dfca1f3, 0xb8f1f14f, - 0xd9f12bef, 0xf915c53a, 0xd77ad2f9, 0xbc7dfa69, 0x6f778efa, 0x43dcf462, - 0x73f72b74, 0x0bd5e3c9, 0x12dfb57d, 0x4bbf8b9f, 0xe052bf56, 0x624efc5d, - 0x7e9ca9bd, 0x7de24faf, 0xb73dd263, 0x24fd084f, 0x69af93cb, 0xd8205f74, - 0x1fe80511, 0x4ad8793a, 0xe3727674, 0x2eaf3a04, 0x9c07abc7, 0x4f2f80b8, - 0x7113e864, 0xf2169f5d, 0xdf257eaa, 0x30e7caa7, 0xe77f0c7e, 0xa5487e30, - 0x573eaebc, 0x92e30d3c, 0xef593df2, 0x4ab74f9f, 0x3fb597bf, 0x6f5a45f7, - 0xf48627a0, 0x49c17a64, 0x82f43a7a, 0xe7ae1775, 0x8c2c95c7, 0x5bf0cffe, - 0x8ec7f7fc, 0xfd92b21c, 0xef9c77dc, 0x9fdd076f, 0xe01788e6, 0x17a1a1fd, - 0xeb1c9246, 0xe0ef8fcb, 0xdf9db6f6, 0xf046f8ab, 0xcdff1162, 0xe611f711, - 0xf9f79da0, 0xed147b21, 0x9e29283c, 0xbdbb6610, 0x2a70fcf4, 0x940fff43, - 0xca63cf14, 0xeefd2f01, 0xdf176b0c, 0x3bfbe8c7, 0x5163820b, 0x0c59df2e, - 0xfbf03bfd, 0xe7def453, 0x521782a3, 0x5cb18a0c, 0xf52e5e31, 0xa42c1f9b, - 0x5e67cae7, 0xed2a7bfe, 0xed463da2, 0x62f06b21, 0x9cafc79a, 0xf310e76c, - 0xeef7aafc, 0x41182d1d, 0x06e128eb, 0x98dd933c, 0x05b3978c, 0x3b7bf126, - 0x74c91f1c, 0x5f9ebfd9, 0x5ffa1f02, 0x21f6bce8, 0xc6eb8ebe, 0x591cb859, - 0x63ec813b, 0xc86296d6, 0x88715b9f, 0xbbd0c3df, 0xdceb49c1, 0x843ff667, - 0x86fe28fa, 0xed7bf199, 0x3f4022c0, 0xf9a1e4c5, 0x4f9123e5, 0xcf2d64bf, - 0xd1e8fbb3, 0x39e60bf7, 0xfbf25cf0, 0xd2c97386, 0xa49d085f, 0xe1c63fa1, - 0x97e6d3d3, 0x255d7b71, 0x7aeff8f8, 0xf4eb346d, 0x0de16bbb, 0x711fc8e3, - 0xa41fa2d2, 0x775b87df, 0x4ae90981, 0x77f2172d, 0xbc9f9f13, 0x7bde4b2f, - 0x8a9f8c95, 0x7f9262c2, 0x33782c4d, 0x827ea1de, 0x61c259e9, 0x91fff746, - 0x6984df7b, 0xe29f9a88, 0xf485acb6, 0xf67be0c2, 0xbbf25f2c, 0xf5bbff6c, - 0xf42b5c2a, 0xd38795ef, 0xe07eaf50, 0x3a46fbe2, 0x5d7a8f7d, 0xc36cf3e5, - 0x83af300f, 0x4e14a605, 0x879276a2, 0x5dbc281f, 0xf341b9ca, 0x7ec17a47, - 0xebe83df0, 0x7fee429a, 0x710cae63, 0xc16c2bc8, 0x9fa94d3c, 0xc2668a42, - 0xdca7f373, 0xe3d21a7a, 0x19c5b5a9, 0xc60f302b, 0xda2567ad, 0x8ca3a1d5, - 0x78eb8bce, 0xf8c5f8df, 0x89fe32fb, 0x9fdbf7e8, 0x243bf461, 0xb4e4f3c3, - 0xed89b99e, 0x9eb90a73, 0xf6285f9b, 0xe44c8599, 0x8de32657, 0xb162fbaf, - 0xf0796aee, 0x2687da72, 0x4b78b7bd, 0xa487a0ba, 0x7fcfede7, 0x1ea0f297, - 0x4913de36, 0xef185fb1, 0x612c5783, 0x532c42e5, 0x61bdaf28, 0x0d739713, - 0xb92cceaf, 0x5ee9d78b, 0xef3b6985, 0x59e3dfa1, 0x12caebb0, 0xad16e5c6, - 0x05c7a483, 0xb412fe05, 0x555be2e3, 0xc345f217, 0x51e09516, 0x56d73ecd, - 0x8b7a7e78, 0x06bbec99, 0xbce9cf01, 0x9bad1a60, 0xe00b34c6, 0x4c16b4fd, - 0xab75fb23, 0xa4a1ddf8, 0x6f7bc079, 0xe043156a, 0x99d7c6c7, 0x043c53f0, - 0xa261bc1d, 0xbf805a75, 0xec70890b, 0x79bfc854, 0x33783f3a, 0xfec14fd6, - 0xabe9cf1f, 0x7dd0969b, 0x3ef8c936, 0x7d120b6d, 0x91f3162e, 0x471e4cf8, - 0xf10fb3e2, 0x2bd2f689, 0x85ef4853, 0x6291541e, 0x9fdd8bd9, 0xda7cbed2, - 0x99df2ba1, 0x8137cf8a, 0x9ea3a2dd, 0x6fb3f51d, 0xa35b9ea3, 0xfe7a8c52, - 0x962ce2a1, 0xff71afa4, 0x39f5ff39, 0x3d04a669, 0xf1c83ea9, 0xa4e73aa4, - 0xcff7a42d, 0xebe91d7e, 0xaacbee84, 0xf1ef7848, 0x83b8fec2, 0x37eabd61, - 0xc70d21fd, 0xa66f5869, 0xe975c979, 0x7ca079c3, 0x208d4f6b, 0xc5e5f7fd, - 0x4eb95fa9, 0xeb8df4fd, 0xde09e920, 0x9742affb, 0xf24c2718, 0xb05154e8, - 0x9d0437ca, 0xc6007a2c, 0x38b6fec5, 0xf3d2fee9, 0xa3e2571d, 0x5f05bd7f, - 0x71d71d53, 0xd1f91147, 0x74686f4d, 0xfb44e0c8, 0xc7c80555, 0xd02fa0f5, - 0xc4af516f, 0x647ba1df, 0x1ee9590f, 0xb74dfae6, 0xd5e38cdc, 0xb09ab71f, - 0xabe1d4fd, 0x495c1226, 0x2a780aeb, 0xfbde8a18, 0xbe05e28a, 0x3d81fc04, - 0xe72dfc41, 0xc1370093, 0xba29fb01, 0x08afa88f, 0x0e4133d6, 0xedc859bc, - 0x65df782e, 0xf7e6fa21, 0xd7cff561, 0x575f3495, 0x64df7cd2, 0x17ccdf44, - 0x782cf9a4, 0xe7c26adb, 0xb6bfee0b, 0xa73df704, 0x79a74dd6, 0x4ff0ca9d, - 0x553afe44, 0x210ffd00, 0x0fdc172f, 0x0bfb2cf3, 0xd3b76cf3, 0xcf3b0d7a, - 0xf60ef88c, 0x89f9e617, 0xcf3943a0, 0x0d3d34f7, 0xcf43f9f3, 0x2efd0caa, - 0xc6c0fca1, 0xbf4ebca9, 0x73321713, 0x4a6d087a, 0xdedf7ca5, 0x04fbfe6e, - 0x78c00e52, 0x260f49e7, 0xd55387a2, 0xd0c9e6fa, 0x3f07ffdf, 0x00b71737, - 0x0000b717, 0x00088b1f, 0x00000000, 0x7dcdff00, 0xd554780b, 0x733effb5, - 0x64932666, 0x08124c92, 0x3c984081, 0x49849009, 0x768a8802, 0x02d10478, - 0x89794f0d, 0x42100793, 0x69b5a05e, 0x0240cd6b, 0x350d45a2, 0x01d45a2a, - 0x0da2a281, 0xbc150a0a, 0x45622a03, 0xb68b57c5, 0x514026e5, 0x5ea0c679, - 0xffd7b5ae, 0x4e7dadfa, 0x5490ce72, 0x7dfbdedb, 0xdf1f7cff, 0x5afd9f66, - 0xd7b5ed7b, 0xe7bdaf5e, 0xcbaa3dc2, 0xe4e216ef, 0xff6f05dd, 0xf7a517bc, - 0xfc812eaa, 0x02cddf58, 0x2cc38ff9, 0x934a14fe, 0xfe70a68b, 0xa56b9b65, - 0xa689c422, 0xa141fdbf, 0x367d85fc, 0x0bf2a0b7, 0xcef74529, 0xea8f7e46, - 0x2fed415a, 0x259f680c, 0xd8b97386, 0x5deae544, 0x2e509a23, 0xcae61e1e, - 0x0df2f2a0, 0x09644261, 0x6856fbfe, 0x3be9237f, 0x6ba50b52, 0x34786f55, - 0xfd2f4da5, 0x6fa5c944, 0x578f3756, 0xf724abf3, 0xb97e34dd, 0xf9ed5855, - 0x399edca8, 0xf388472d, 0x03136d7b, 0x233f32d9, 0xb03fcb87, 0x5d8d7952, - 0x7bf85af8, 0x0e6a7dad, 0xd2b6e28f, 0x0fa98b38, 0xfae94a91, 0xea60ef18, - 0x938d317f, 0x8b7de342, 0x0e5c1fbf, 0xe7cb0edf, 0x9fa88a0b, 0xf6626d7b, - 0xf55dd973, 0x4ddb34f4, 0x6d46f61d, 0x553b577b, 0x3cc62588, 0x2422a1e1, - 0x477914bf, 0xa432be57, 0x7ca42abc, 0xa7cfbf47, 0x1f2f3914, 0x1fc6037f, - 0x12c785d1, 0x2c3b8f0d, 0x72eb1df4, 0x44d8128f, 0xbab12dff, 0xfe09cbed, - 0x9b88c6e7, 0x55a94fd1, 0x47cdae38, 0x5f9e0ebd, 0x86345589, 0x87bbe3e5, - 0xa6f3e9eb, 0xe2c31afe, 0xced11f28, 0x89bd53e3, 0xda9e4376, 0xab9ae09b, - 0x4ba7a3c1, 0x4ebb85b7, 0x7fa0f3ea, 0xa6b12d55, 0xbeeecd7c, 0x7c0693ae, - 0xfa7fc52f, 0x3449bfd2, 0x8bc091fb, 0xdddaabfc, 0xe892307a, 0xcdf14da7, - 0x17bf5375, 0x9d1d7e0e, 0x1f75e6ed, 0x9beb4459, 0x7f3ea6af, 0xbedbe698, - 0x426cf547, 0xfdd86fbf, 0xe7fd0c4a, 0x6e0f8b9b, 0x2fd5efa7, 0xddbb89a7, - 0xc50ff35d, 0x17dd85e3, 0xfbe953a3, 0x08f643f9, 0xb9e68c31, 0x9dac7e37, - 0x5c4762e8, 0xaf78b77b, 0xef5dd6d5, 0x35b5bcef, 0xdea1aa7a, 0x3d1ad179, - 0x252f40cd, 0x8bd62fbb, 0x5f9fc65c, 0xefc2efcd, 0xc7bd7d89, 0xf4bdf4aa, - 0x5ac6fdf7, 0xc35fbd28, 0xf736bddb, 0x6e096b13, 0xcf309eff, 0xfcfb8216, - 0x682db31b, 0x728dfe7f, 0xcbcdbd2d, 0x244f5fe9, 0x8b68fc63, 0xbc7d77a4, - 0xf70b6e35, 0x7b696a53, 0x8fda1aec, 0x93ebbfa5, 0x55d290d2, 0xcfc96a5e, - 0xb76f3ac4, 0xdc002fb5, 0x46b115e7, 0xe7eaeb89, 0xdb9bb77e, 0xc9f3df9f, - 0x270fe063, 0x4f901dee, 0x41f94d64, 0x3f2a3eb9, 0xa64151ff, 0x7f3dfa8b, - 0xf80f5f4f, 0xfb9b76c2, 0xbbb7a636, 0xf7d83ca2, 0xa7187f7a, 0xb9effd16, - 0xe90fa462, 0xca5e1247, 0xb8e4fae7, 0xabbf257e, 0xfb8b68df, 0x17e0d1be, - 0xb679b7bf, 0xeffcb250, 0x31627d69, 0x6ee7ec3f, 0x4d74a1d6, 0xf89b7098, - 0xbb864ac9, 0x22ec7844, 0x030b964d, 0x228995bd, 0xc9b0befe, 0xf1117dfc, - 0xbc5f7c09, 0x5cbdfcde, 0xa56ead34, 0x98092df9, 0x3fda0bbf, 0x6bec04fe, - 0x5ec5affd, 0xff7a0514, 0x4f54cc36, 0x40fe35f8, 0x255f091f, 0xc7c11fb4, - 0x8102519e, 0xbbdf5895, 0xe8679e54, 0xa775debc, 0x2287bb70, 0xab4167ff, - 0x5b8f5d61, 0xf0913584, 0x1c2edc7a, 0x47e8f989, 0xf5fa8508, 0x6c0b0bef, - 0x0f7726a1, 0x04b92afe, 0xc231af7c, 0x5bbe0822, 0x427ce05d, 0x49f7d8ac, - 0x5d29fa32, 0x356de853, 0xe6c177c0, 0xd4e7e87d, 0xe25dfdbe, 0xf8ef54d7, - 0x58d340d8, 0xddf8eb82, 0x1ba1a7aa, 0xb1af4eb8, 0xe1014088, 0x02212ee3, - 0xf27f94f1, 0x5a62e493, 0x7cb6cf97, 0xa4625c92, 0x36cc457f, 0x129ea3d2, - 0xef3ebc24, 0xfcd2ef61, 0x305cd38e, 0x5d7ad09f, 0x57866beb, 0x2ab867c7, - 0x87a3bb6a, 0x54f740cf, 0x5577f59e, 0xf7efb178, 0xcfa002d9, 0x3c5f8dc8, - 0xb9f40f38, 0xa14ae6d7, 0xa9f66bb1, 0x2de6955e, 0x0c81a8f6, 0x4f7b639c, - 0x9ce05744, 0x52e053d9, 0xd9aef30d, 0x7ce116a3, 0x62fbbf39, 0xf7366942, - 0x44edc533, 0xa03c07fb, 0xf8e09edf, 0xf7fd5b9b, 0xccd79ff8, 0x7f65ceff, - 0xf8037090, 0x9953c6c0, 0x07c4efe0, 0x79a6e6ff, 0xc6fccf9e, 0xad10bc8e, - 0x047f4123, 0xe09bb45f, 0x2af810bc, 0x8e5c105a, 0xd037aabd, 0xa5443acd, - 0xff4f19d8, 0x09137c32, 0xf82e84be, 0x94a89e08, 0x56705d11, 0x38eddbbb, - 0xa2382f67, 0x694fc173, 0x12f29342, 0x0dc9f3b4, 0x493a5afe, 0xbf1d7f10, - 0x70cae167, 0x8a4d0bc8, 0x97be8c27, 0xdcf955ed, 0x191bdb2a, 0x3f1816c0, - 0xd2f9c9c8, 0x1840d547, 0xa3a827e5, 0xea9b30ff, 0xf547be2f, 0xfb148ed0, - 0x07f6de37, 0x8375d61b, 0x881ca04d, 0x344b5c03, 0xfdec96b8, 0x8d0a67e1, - 0x2ddf78b3, 0xe2ce3007, 0x170f1407, 0xe8edf3a8, 0x8a43c977, 0x67405788, - 0x3a46e3b6, 0xce64d85b, 0x0bad122f, 0xc1fc1554, 0x9ef09dfc, 0x96fd415c, - 0xdd730eef, 0xa102f18d, 0x4abc42e5, 0xff68d4f0, 0x3b58cacf, 0xcfd500f7, - 0x3c6768da, 0xe2170f9c, 0xb5abf608, 0x0d204135, 0x1d6326b6, 0x6bf9efcf, - 0xe6b1d632, 0x2995ff77, 0xcebf59ba, 0xaa37b4fd, 0x2148a9d7, 0xc4514eae, - 0xfba0a9b7, 0xba8a538b, 0x201b6fa9, 0x9b36c5f7, 0xca879fbf, 0x8afc6c0f, - 0x3d85c1f9, 0x6eae81be, 0xbf6bb7e8, 0x892dc3fa, 0x02e18348, 0xd716f0e9, - 0x2427d80d, 0x35be620f, 0xdb4f569b, 0x97f0f944, 0x44b9386c, 0xf793864d, - 0x42c7f60b, 0x3efabf43, 0x80be06d9, 0x0fe48474, 0x1cf201b6, 0x7b9daa3d, - 0x4c77f6db, 0x9e06e8c9, 0xd71b6ea3, 0x5c100db3, 0xd17759ef, 0x845bd05c, - 0xbe0d1fc5, 0x775ebc2d, 0xa2b3c22f, 0x5d4357d1, 0x89ef82ad, 0xfed389a2, - 0x47d385a2, 0x5139f085, 0xc05c785f, 0x620310b3, 0xf3de3f81, 0xccbecf8c, - 0xadac7f37, 0xe8357821, 0x022b1fc4, 0xeaffe85b, 0x63508746, 0x46b5ed20, - 0xce5451a3, 0x5206fbb4, 0xd503edb9, 0x1dde40a2, 0xc7a7afa0, 0xa5f7fd85, - 0x718c4673, 0x2e1ff6fd, 0xaafe8899, 0x8c22a976, 0xd3b73bfa, 0xd44e8226, - 0x7c02fda7, 0x9ec2fe1c, 0x57b4be02, 0x6b979011, 0x35ef8f28, 0x80deada3, - 0xa4772f01, 0xd50f18d8, 0x9cf29929, 0x4d0f7ab6, 0xbbcf7ea2, 0xeb90ec4a, - 0x26cb876d, 0x25b1bce2, 0xd701d896, 0x1d63c3fe, 0x58b75829, 0xd59bef2b, - 0x8f71f57b, 0x547fd0b8, 0x6f0c07ec, 0x4445b663, 0xa3c6bb53, 0xa6460161, - 0x30a1f243, 0xc18daf0d, 0x37770ef1, 0xe317e3eb, 0x2a28c493, 0x044ea9df, - 0x255ce79c, 0x2da3ac2e, 0x0aeee896, 0x4ef36f6a, 0x0dfa9abc, 0x078b8d8b, - 0xd2526b7c, 0x8abf3d78, 0xbf3865ad, 0xcfc2f122, 0x08b6b7fb, 0x65fec6f9, - 0xe9bee32a, 0x35cfde21, 0xd47e390e, 0x51cf953e, 0xe343a571, 0x4abbefdb, - 0xc9059c69, 0x0f4147be, 0xc46dfc9d, 0x39fc02ab, 0xf96162cb, 0xe735f1ac, - 0xbd21f05a, 0xa48a6cfc, 0x563d7d37, 0xc0bab2f5, 0xe8d51e3f, 0xc8ab9573, - 0xa7986f91, 0xc345b7ad, 0x78039157, 0x3a2f61da, 0x9da5f384, 0x3cdce3be, - 0x01cd3890, 0x59ea853d, 0x7aa9cfd0, 0xf47631da, 0xfc01c33b, 0x3255ea2e, - 0x8b16ed01, 0x6fd8d5da, 0x22abd78b, 0x8dabe068, 0xa2ee3936, 0x1822114b, - 0x22ee35df, 0x7f6e3f5a, 0xe9045a29, 0x970c6ddc, 0xe4a31af5, 0x452379fe, - 0xb50f9fee, 0xf969b4f9, 0x7baf997f, 0x5cfd7ccc, 0x96b61fec, 0x46fefe48, - 0xa55bf50a, 0xa1484eb4, 0xec4eadf9, 0xa7bf03b0, 0x98225dea, 0xb2f78069, - 0xa08bc679, 0x7acedc61, 0x9f3c1c97, 0x3370f5ae, 0x75f35dfc, 0xd54e1e32, - 0x7b1e3227, 0x84c93fee, 0x53feaec7, 0xbcbc784d, 0xff1e4cff, 0x77d67d54, - 0x87b43ff4, 0xf826ddfe, 0xe74dfabb, 0xdf6ec571, 0x3b97f040, 0x980fc45d, - 0x505f886e, 0x3df15db9, 0xdbe4357e, 0xe404c28f, 0x7dc2afbe, 0xfe065c83, - 0x65ce0df0, 0x4982e7d6, 0xd17eb7e0, 0xeecd69cc, 0xded0138b, 0xfb017c4d, - 0x11af2f49, 0xf8270ced, 0x3583e885, 0x7cb9bab4, 0xf4106fb7, 0x4e8e1d22, - 0xa775e679, 0x20fb42df, 0xa3dfdf6c, 0x582f8fb1, 0x2878a7db, 0x46abd96d, - 0x7c75f71a, 0xb1a7a4aa, 0x6dc8be03, 0x68d5efa5, 0xb6ef7c47, 0x020e9797, - 0xdac3aa7e, 0x81f70173, 0x8b96ff97, 0x7dabe473, 0xfbe2074b, 0xf2cfaa36, - 0xdabdbd87, 0x5d2fe863, 0x5196fcb8, 0x5533a95d, 0xefd0ffee, 0xf435f6db, - 0x89db1c03, 0x0b9209bd, 0x0a2aebab, 0x0d83c64e, 0xff07ef79, 0x58b7c412, - 0x5d3dda1f, 0xeef9031d, 0x28799243, 0x948f7c3f, 0x100f861b, 0xe40a4b01, - 0x83670fbe, 0xb08f544f, 0x470aa0bb, 0x79611de4, 0xc384623b, 0xbffd50a5, - 0xdbe397f7, 0xa1a42f21, 0xe83c617d, 0xf164caf9, 0x1b6dc9ef, 0xf04ff642, - 0x34edeabd, 0x3ada955e, 0xfbc29c65, 0x7c153f28, 0xde2fadfb, 0x04d7f4d6, - 0x9c01cfac, 0xfbcf046b, 0xa9653f5a, 0xcf502bbe, 0xe7bd68e7, 0x7337aa0a, - 0xe864df56, 0x7e9ac547, 0x52112626, 0x947e64ae, 0xe5c83b03, 0x83d4b6e7, - 0x3e7c525e, 0xd7dfc1e0, 0x35f9c1e1, 0xfa384934, 0x62455e12, 0x8d1a7520, - 0xa2d5213b, 0xc0140fdb, 0xe39b443d, 0x965afd33, 0x1939f2c7, 0xfd1d0388, - 0x4b4ee3b3, 0xfc064ef5, 0x670ffd7a, 0x75f1cbcd, 0xf2e86e73, 0xb2deddbc, - 0x57b6700c, 0xfc7f5939, 0xeed44500, 0x41615989, 0x8a7a1a35, 0xf9f40d73, - 0x0e0b91a3, 0x8c7c26f6, 0x43cdf28f, 0xbc6fb3ff, 0xcaf2357e, 0x72f77881, - 0xeb7173d0, 0xc2efd648, 0xbca3377d, 0x981be1d2, 0x373c5340, 0x062837c0, - 0xbc517c87, 0x9451275c, 0xfc2dd453, 0x45629e12, 0xe518df8e, 0xc53f472b, - 0x5d8f2396, 0x23d66f81, 0x8d106f6c, 0x739fb9bd, 0x9dde5176, 0xe1e3affc, - 0xfd8f3698, 0x25ed7136, 0x75fedf9a, 0x82069e31, 0x1bceecb7, 0xba50d417, - 0x109452d0, 0xdf704d54, 0x575d4a96, 0xf6078bfa, 0x9cee7925, 0x4ebb834d, - 0xcaeadb83, 0x50e7ee34, 0x79741bb8, 0xeb0a17e5, 0xf947fc83, 0x81b1fd17, - 0x661f29bb, 0x74c1f8b9, 0x16395b9c, 0x886c93b6, 0x7a45bda0, 0x9c1a3be4, - 0x73bed28f, 0x35f7f1c4, 0x21189ef8, 0x683e27db, 0x507ec009, 0xaf0f7634, - 0x4ed513d3, 0x15634a8f, 0x721db70b, 0xb2f0a950, 0x31d7fcfe, 0x4ad7db7f, - 0xf54e6af3, 0xddbc07dd, 0xfe496f1c, 0x0df0e180, 0x6b790a9d, 0x3fc79cb4, - 0x1e793790, 0xc6cb84d3, 0x6b589942, 0xcd31fc81, 0x50b2a725, 0xba63fb91, - 0xde30daf0, 0x7ae3e14c, 0x7bb79def, 0x07bc4fa1, 0xbee0885d, 0xfbf9f851, - 0x74e0111c, 0xfd72089e, 0xe72b449b, 0x7d137c75, 0xd24bdcdc, 0x547d27c7, - 0xc056ffc6, 0xee646efd, 0xc79a3a80, 0x650687d4, 0xdcd57eb0, 0x5df3f19b, - 0xe8d54f70, 0x6feff686, 0xbfd88eb1, 0x699fa833, 0xdfec8437, 0xf5f5bdf1, - 0xfb47f8cc, 0xa74748e8, 0x4bece4fe, 0x5b4eb878, 0x4bbcebd2, 0xc2127f59, - 0x8fd1f2c5, 0xa85b7db4, 0x5a2f453a, 0xd26e239f, 0x89960897, 0x62259663, - 0x10afafbe, 0x3ad0156f, 0x15463ebe, 0xcbd35c0d, 0xfd68a6ed, 0xe13fe94d, - 0x0f5bd833, 0xe1af608b, 0x92f0aed4, 0x8218d5ef, 0xbdba8a7b, 0x27ca9631, - 0xc6bd27f6, 0xefaeefc0, 0xfd0ac3b5, 0xf37486ee, 0x66d949f7, 0x68b267fd, - 0x94fe3152, 0xfb7ae6e1, 0xb3a22781, 0xfea553f7, 0x21888622, 0x0b7af2df, - 0x1d3e718b, 0x2fda2e93, 0x69111c10, 0x2eb18fbe, 0x75ff27cb, 0x5615c601, - 0xb7ea9f39, 0x1debb655, 0x288b7927, 0xa7ac9c50, 0xca532293, 0x4a7fc825, - 0xd3d203f2, 0xcf4e6ef5, 0xf28f79d2, 0xce1ef5f3, 0x9d15a417, 0x6b25bf40, - 0x7d62b73e, 0xf8970cee, 0x9a696f2e, 0x762ab000, 0x5a441cb7, 0x809a2c16, - 0xa1d17663, 0xef4883da, 0x6adbd4ec, 0xe1d3be59, 0xd3a345be, 0xfda6a25b, - 0xe1d68730, 0x87aa3d96, 0x4da603f3, 0x790bdc9f, 0xa27be71b, 0x444baaa3, - 0x54572433, 0x012fdeab, 0xdb6f7797, 0xdf9a78c1, 0x18a3f527, 0xbdeacfee, - 0xfa99f70c, 0x4a4e9c89, 0xe81bfa2b, 0x673e2bcc, 0xf6f26c79, 0xd5126b36, - 0x5e2af42f, 0xbd6bdbec, 0xfda01022, 0xcf26deb7, 0x0e74f581, 0xc98f1f60, - 0xade8f699, 0x67da7c02, 0x6671a34b, 0x10a4b0de, 0x55194ce3, 0x1bbd456c, - 0x201921bf, 0xbf4e8ba5, 0xf9f5ee8b, 0x76eb6957, 0xf18565ee, 0x2d33b1d8, - 0xf2c17206, 0x907d695d, 0xf5d4bf12, 0xade048dd, 0xe18592e3, 0xc11a38ec, - 0x6ede86fa, 0xe648aef9, 0xd807cb3b, 0xb760c203, 0x2ceb433c, 0x99e6f20c, - 0x36e27e67, 0xe2672b9e, 0x18fabe5a, 0x922fedfc, 0x736491bf, 0xbff011ea, - 0xa03cfdfe, 0x9c9af393, 0x24467a4d, 0xcd6abfce, 0x84fe08ae, 0x690899fc, - 0x6cf91dcf, 0x2fec58d2, 0x4e1c478c, 0xf32bfce8, 0x7f5287d9, 0x6f1aeeee, - 0x8fc2cb5b, 0xb9fca11f, 0xa36fc580, 0x689ce9f3, 0xf03bff39, 0xb64ecddf, - 0x10a9ddeb, 0xb77f383c, 0x967ce3f4, 0xc3a88d62, 0xbc022bf9, 0xb714b3bf, - 0x55f88eb5, 0xf70f73e5, 0x44bdfd03, 0xe5451838, 0x648bad2f, 0xcd92f67e, - 0xfd0eac73, 0xfbfb2a3d, 0x3d3fbdcd, 0x3de91bbe, 0xc53ff955, 0x31c5a4f2, - 0xb57ecbfe, 0xd3da0864, 0x52fa2ef9, 0xa8bf4f7f, 0x3f69c304, 0x5fef34e7, - 0x1be097d9, 0xd2cda1b6, 0xcdbcd28f, 0xa1d2034a, 0x04386e03, 0x690df3bb, - 0xb05f6e6e, 0xc24d453d, 0xf817ec36, 0xee7c07f8, 0xec81e59b, 0xf6c7cfe6, - 0xc1725d13, 0xf4e5a510, 0x2c358246, 0x8fbe68f9, 0xf3c4d7f1, 0xfa77b5d9, - 0xe604f3fb, 0xe0071241, 0xf87bb62e, 0x37f80a1c, 0xf9cf3d62, 0xd7ac3cb2, - 0x061ff915, 0x25f39d9d, 0xbd2e7078, 0x55fc7a40, 0xcacc7fa8, 0xf3717cf3, - 0xebb0d1bb, 0x1c7e90c4, 0x5e487f0e, 0xafd404fb, 0x7e16e01a, 0xb1e03f6a, - 0x3f0226eb, 0x6d773bd5, 0x1d2a7ee4, 0xe5b9e81e, 0x4c1e2ebb, 0xbd789c82, - 0x0e8064f0, 0x2ffcca77, 0x2a3d7bc7, 0xe37cb54d, 0xa47f3297, 0xa445f388, - 0xbf515a75, 0x0f47ca54, 0x689fe769, 0xc8fe65cd, 0x5aeeeda4, 0x31525faf, - 0xf8a7d7ca, 0xadaec2fb, 0xde749b9f, 0xab61a555, 0x23fb65d8, 0x3325e763, - 0x79e7be5e, 0x2dced767, 0xec87bfbd, 0xfd4e1fc2, 0x3b036cc0, 0x3cbb06fa, - 0x7f10b7a7, 0xe7e8bd01, 0x0bfb8d34, 0xef6a5fec, 0x524d3f05, 0x849d9c95, - 0xc287a48f, 0xbef8ce58, 0x598ecfe3, 0x2eb6e7cd, 0x4844d567, 0x0567c83e, - 0xe5185fb5, 0x5bf30bbb, 0xc2f39da8, 0x1c86ceea, 0x7bca2332, 0x3a57be37, - 0x073193da, 0x45ef3f3a, 0xb9255abe, 0x7720cd2b, 0xd7bee339, 0xe51759f9, - 0xbe7cc66d, 0x91b1fd6f, 0x520c6704, 0xad22cf5d, 0x9c7e5ba3, 0xfc05bdba, - 0xc93081f8, 0x980aa38f, 0x0bf3e91f, 0xda15ffed, 0x33e23ef7, 0xe279d1af, - 0x738fdc23, 0x7af2b18e, 0x3ca96abe, 0xa170e748, 0x6c84011c, 0x79ce1d8d, - 0x6fe1146f, 0xbe1553bc, 0x3d45f46e, 0x1e7af5a5, 0x2bd099f8, 0xb0af54d2, - 0xfb1dac57, 0x5bcefbf7, 0x8d47d6d5, 0xbba9f9d0, 0x37767097, 0x5bcf396f, - 0x01f447c2, 0xdf2ac65e, 0x5b0ebe6f, 0xc3ac41d1, 0x9f1e6738, 0x539ce38b, - 0xc304f98f, 0x43df187f, 0x1f3a19e7, 0xf27ef8e1, 0xe1158fd2, 0x7dff60b7, - 0xdafb676e, 0xd3eb5b5e, 0xee7c25bf, 0x81ed925d, 0xf005e89d, 0x68cff05e, - 0x7bb3cb3b, 0x7c1f84a3, 0x84d4ef65, 0x2f45ec00, 0xdf044f41, 0x79642de8, - 0x77bfacb8, 0x7f53950e, 0x5f68c2fd, 0x2f345ec0, 0x069feb42, 0x7d15fb46, - 0x52837db8, 0xda0e66fb, 0xbe6488af, 0xf9203473, 0x706c7378, 0x9bdf4a9e, - 0xa814cf3f, 0xd6045477, 0xeddea2a4, 0xe5435fd2, 0x6fd43549, 0x122192f3, - 0xf951ffce, 0xf3ce68dc, 0x32738df6, 0x4cfb671f, 0x5f6f54f3, 0x697aaff8, - 0x51bcd5eb, 0x3d83f796, 0x9429e514, 0x9b63f4a7, 0xab573fac, 0x974691f7, - 0x0f99cfb4, 0x5a44a6f8, 0xd2fde741, 0x99d2c24b, 0xc2fb7929, 0x5948f3ef, - 0xe728db06, 0xc29f5c56, 0xcbd9a3f4, 0x5b7c6b66, 0x1c0d0fef, 0xcb2f2123, - 0xb70b39bf, 0x679e8384, 0x41b78796, 0xbe5a3bee, 0xfb7a0a32, 0x0c1a9f4c, - 0xa3395c83, 0xaf29dbd0, 0xaf5c62a5, 0xd74cb71c, 0xc0a582ff, 0x0eedcbeb, - 0xf7cb3771, 0x3ea302c1, 0x556fafa5, 0xa37898cb, 0x27615cde, 0x2cf042fe, - 0x9a6df6d1, 0x7d3bd7d3, 0xebe9f404, 0xf4fa8de3, 0xe40f65a7, 0xc6d2fef2, - 0x8def5b3b, 0xb90e993f, 0xfaa7226d, 0x0f7a9d78, 0x57e74dd6, 0x25db97a0, - 0xfb6b08bd, 0xdf298b47, 0x07887b30, 0xd389eaf6, 0x1d6f4c1c, 0x1f2ce12d, - 0xf08ecc37, 0xb0d76ec2, 0x06ed8c2b, 0x83fb6b37, 0x1ba628f4, 0xee28beff, - 0xf32ed2a7, 0x3065cf95, 0x0f60bcdd, 0xe515b93c, 0x7fb3872f, 0x8e5a32b6, - 0x24bbf95b, 0x29bd2e8d, 0x5fb17aab, 0x32a5e98e, 0xe5c31dc2, 0x7a678fbf, - 0x57dc367a, 0x7d127c00, 0xd2bc5db2, 0x258ccc1e, 0xe8d31ffc, 0xfb237a0f, - 0x98a36af5, 0xf796856e, 0xf59e3cfd, 0x797f9238, 0x437ddf3c, 0x7bb3ef39, - 0x3ec42efb, 0xf0c91e5a, 0xf2c9731c, 0xbcb19563, 0xb7dfe60f, 0xc5fc30f4, - 0xbcec8ac7, 0x55ed8e5f, 0x73fade59, 0x9f841a9d, 0x9acfa75b, 0x86dfc725, - 0xe1baa8f9, 0xd4dde4a3, 0x5595fccf, 0x7e6ed093, 0x7053edc5, 0xf69af6de, - 0x4369fb29, 0x4afcf3f7, 0x97d47fb3, 0xf98c9dee, 0x760764d5, 0x1e7ea41c, - 0x116a739c, 0xee9fd3d6, 0x3ef5869b, 0xe17d6f6f, 0xeb77044f, 0x5eb23f8a, - 0x6fb47d74, 0xd85fbe26, 0x5fae1bf3, 0x16bff2bd, 0xb6afce41, 0xcfd17a4a, - 0x7e8d1ae3, 0x1e6f8645, 0x7cae57ea, 0xc881f59d, 0x7f9223ec, 0xf8fdfede, - 0x5bbde9ce, 0xdda8505e, 0xd5bd88d2, 0x5c81aa9c, 0x94676b9c, 0x0692b460, - 0xed3d4a7c, 0x8d182bac, 0xa459f175, 0x5b74b89c, 0x4b181f88, 0x7fd9a091, - 0x16d2dda8, 0xf242bf19, 0x19f41d82, 0x7d297f5a, 0xf3df7ae7, 0x9168857b, - 0xdf7763df, 0xf75cb57b, 0xfc387060, 0xb09b19ae, 0xfd76e7ee, 0x77e8d326, - 0x872f4d0d, 0xacffce57, 0xeace5fb6, 0xbdb665fb, 0xb9005ed3, 0x7d33fceb, - 0xfe76744c, 0x3f9cc1c9, 0x112bb4ad, 0x577f974a, 0x72465a78, 0x65b78d7c, - 0x07e7e424, 0xe34befb5, 0xaf82465b, 0x384e7ce9, 0xff59725a, 0x85c96acf, - 0x47f3abbe, 0xc992d451, 0x992d03df, 0x4582ff68, 0x8ff853da, 0x3a78a8e0, - 0xd2dde369, 0x0cb7e10f, 0x26e87e47, 0x1a71f5e4, 0xe91f25c2, 0xa58fbe69, - 0xf9e63b4b, 0xbd9bf639, 0x7ad07f54, 0x707ca9bb, 0x9adf9cc0, 0x03e7ed2e, - 0xfa6fe243, 0xc3fbeda9, 0x213c8e70, 0x3fd7f5ba, 0xd4f38da3, 0x3c719d53, - 0x0acfa6aa, 0x6e1f4eb7, 0x80dbdf29, 0xf13a8fef, 0xf1126b7d, 0x6398a5e5, - 0x9e5fcf2a, 0xfb494f67, 0xbe790bcd, 0xe7179c24, 0xff821781, 0x67ca5885, - 0x7892be43, 0x3e3af3d5, 0xf2bfe743, 0xb04945a3, 0xae947edf, 0x7d3cf9db, - 0xde3a9740, 0xefa46c1a, 0x2e3f4364, 0x8569382f, 0x2c49ecde, 0xdaec1ab3, - 0xd81cf3eb, 0xe4378b57, 0xd6748c39, 0x10e0adb0, 0xece21c49, 0x2007ab36, - 0xf7035837, 0xd86f7e42, 0x05f8b6a6, 0x54bc3b97, 0xc0f3acff, 0x68b7a8db, - 0xe43e6c43, 0xe2fdbd6d, 0xcb1223f5, 0xdd0e700c, 0x9c875e66, 0xd87e7316, - 0x04fe736e, 0xffde80ce, 0xa0bcbb7c, 0xc8705f39, 0x83e4ff9c, 0x9c81675b, - 0xbdff55cb, 0x3f89f42a, 0xf384384d, 0x5e17d3f1, 0x2cfac68c, 0x41d94bfd, - 0x71a149e8, 0x0a6eb422, 0x56ff08f4, 0xb2e3e985, 0xf81e9178, 0x810f1e81, - 0x93a4619d, 0x683fe10a, 0xfebcb94d, 0xcb32d119, 0x5955744b, 0x64e0bcb7, - 0x57bf5741, 0x43b3acb6, 0xb71d0bce, 0x9c2ffda7, 0x6aec375e, 0xd964a3c5, - 0xc5637555, 0xd62df809, 0xf4013bbe, 0x854bfc57, 0xe7e28ae5, 0xbe0abd07, - 0xce63b6df, 0x9ace9c0d, 0xedd0f8c8, 0x2af78b7d, 0xbbca28c1, 0x5dba4946, - 0x7d615eb8, 0x1cd1a4bd, 0x36b65747, 0xd9a6de24, 0xf778be5c, 0x9f86fffe, - 0x18f1dcbe, 0x1e5c33c7, 0x05781827, 0xa7c55b7a, 0x153ded82, 0x330dbf9b, - 0x2d79cb97, 0xbfe1e7d4, 0xaee1e396, 0xcf3a5592, 0xd0c893b7, 0x574bf0f9, - 0xe1066a51, 0x8de6aafd, 0xbd9b94aa, 0x7597ecc5, 0xb0ce39da, 0x918221ca, - 0x28a1cf04, 0xdf45d7bb, 0x628fae2f, 0x18516179, 0x9cf99fc9, 0x438e708a, - 0xdda0c4f4, 0x965477a9, 0x25e2aa83, 0x571eaa1e, 0x56c5b002, 0xfc8a48c1, - 0x04bf3213, 0xd25526de, 0x3f00d78f, 0x1798cdd6, 0xab6f524d, 0x03f706b4, - 0xc0e79d2f, 0x4abd7336, 0x38d1e79a, 0xefe659c8, 0xeb9da2d5, 0x36feecd7, - 0x60ddf8cc, 0x527d65df, 0xc8556bd7, 0x7aa70433, 0xb3cb0447, 0x402398c4, - 0xef14ab57, 0x29150ec3, 0xefa0e39d, 0x2f964e25, 0xe7946ee6, 0x838c3347, - 0x0dd78390, 0xae67b966, 0xbe04cde2, 0xd670bac4, 0x1fdca9a7, 0x64e58bde, - 0x4e484396, 0x7daa3966, 0x12e39d8e, 0x825af39b, 0x1f9ac790, 0x0ad0f148, - 0xf3e47f32, 0x96709ee8, 0x4aa79a7b, 0x5d79a7b9, 0x31ff6e1f, 0x390beb40, - 0xf9b9e25a, 0xb71e1c9e, 0x89db2a9f, 0x200f523e, 0x7a133ab9, 0x41e5c102, - 0x67472eb9, 0xb04afac5, 0x9bfcfaee, 0xe0a3db63, 0xf1e512c7, 0xd86e4bdf, - 0xed879da2, 0xf003c2eb, 0x8a549c53, 0xf60c5a0e, 0xe4325ba9, 0xac7231f9, - 0x8f56ab77, 0x966519fd, 0x80ff77a9, 0xd07b29e0, 0xe9486ee2, 0xf5e1075a, - 0x27fe6266, 0x83e785d7, 0x958e46ee, 0x7963a7f6, 0x0e479f92, 0x73bf1c17, - 0xedefd6bb, 0x9a531619, 0x48f44118, 0x942c9cfd, 0xe1a8edf6, 0xa4076c45, - 0xbbb9ba35, 0x19359038, 0xb32a9cf2, 0x9afefd17, 0xa4e9e06e, 0xde52f18b, - 0xd94cb93d, 0x72f2e124, 0x5fc8dfbc, 0xf0fdb385, 0xe8de76a4, 0x347441eb, - 0x8d71cf82, 0xe8d3ad9f, 0x74cf5d66, 0xb98ba263, 0x3741b790, 0xd8b9e473, - 0xfada5749, 0x7af0dd12, 0x485d13b7, 0x6be211ba, 0x4b742fb4, 0xdf443b79, - 0x7bb7d4ea, 0x0e88b7d0, 0x6de8c89e, 0x074217a8, 0xf1181ac2, 0x252cfc8f, - 0x2a4762a3, 0x564904b4, 0x2cdc47e1, 0xd7c646ce, 0x4ac0d65d, 0x55bfa782, - 0xab00cbae, 0x653a3ba4, 0x5cf911fc, 0xd9f88bdf, 0x0b17fbe2, 0x4e2fd52f, - 0x4ab76c12, 0x2626f927, 0xa409db8e, 0xb0aa0770, 0xf68a50e7, 0xffb231c5, - 0xc46fa262, 0x5e7f51b3, 0xdcc69c4b, 0x2a7fc246, 0xfb407e58, 0xef6e7ce8, - 0x5ef6c8b7, 0xd303a52b, 0x5f6a3ee4, 0x2bf8c615, 0x264073be, 0x58d264e8, - 0x66249d33, 0x4f41394a, 0xbadd331b, 0x7e0890dc, 0x9838d250, 0xf08699cf, - 0xd85daaa2, 0x7d48cfa7, 0x4df578a3, 0xbe004793, 0xd83de367, 0xeca7a7c2, - 0x494aff60, 0x7f1f9ce3, 0x5b653d08, 0x98df7f38, 0x780f7be9, 0x17b8ad3f, - 0x250fa2ec, 0x27b15f33, 0xcb5f7b52, 0xa3bf73d4, 0xc77f8a74, 0xa62390db, - 0xfeb950cc, 0xb9ed2114, 0x338e51a2, 0x35b9ffd9, 0x3c9bfa91, 0x94f0e15a, - 0xf25770b6, 0xb455f832, 0xd1a63df5, 0x98b84377, 0x70139cfd, 0xcd4cc80d, - 0x24821f86, 0xe4e46ed4, 0xfd5a9901, 0xc806ca31, 0xc9c70343, 0x47d7a7fd, - 0x2d37e83f, 0xcfb7ee53, 0xe7a77db4, 0xbf5caf09, 0x5b584d6c, 0x5b52345a, - 0xf3a51070, 0x039ec6b2, 0x2a94999f, 0xde07ac26, 0x4d8aaa7f, 0x317b6f0c, - 0x4ca885f3, 0x8f82f837, 0xfba65914, 0xee99836d, 0xb7b4c6db, 0xb6f949dd, - 0x7ed2392d, 0x0bf3e9a7, 0x82e5825d, 0xef9231b6, 0x64896fb5, 0xd5cc73fe, - 0xed27151a, 0x97dfac5d, 0xd7f1246a, 0xe17b86ba, 0xda752e37, 0x2c7e70db, - 0xfb3a607c, 0x499b4bfb, 0xfd5c47bf, 0x4f7eb35a, 0x6658787a, 0xa87afa37, - 0x019a0e5e, 0x55ad951d, 0x36070e98, 0x997dec78, 0xcc2e29cf, 0x4c19ccaf, - 0xf32fff07, 0xf05c7384, 0x37fb7a65, 0xb091f784, 0xba0e0b1f, 0xd7c83a1a, - 0x3716e30b, 0x1a7eb315, 0xfe63ed99, 0xbc255035, 0xd4cf1d10, 0xec126fe8, - 0xd64be0a0, 0x97d8bed6, 0xdf6865af, 0x4e995ce3, 0xbe70eba6, 0x7366d06f, - 0xb6be0265, 0x9c16e155, 0x4a5693b7, 0xe77da6fa, 0xbb80bdc0, 0xfc0222ac, - 0x7ed6b8e0, 0xd16b0afe, 0x77f7ca46, 0x1c546b08, 0xe98f2be8, 0xfbe5903b, - 0xe9f7eb0c, 0xc828c42f, 0xd76ba50d, 0xfa34b849, 0xe323d610, 0x4f9c69e3, - 0xc3e4a4b7, 0x53d3a0ae, 0x766c6b20, 0x5d0308e6, 0x1e9850cc, 0x60873e68, - 0x55979d9f, 0xfa728f92, 0x32f41fbe, 0x1d306c69, 0x6a85d871, 0x76abc725, - 0xe20f0a24, 0x3b443a87, 0x241d23cb, 0xea3f808f, 0x27e7467c, 0x475e1744, - 0xeb7ad742, 0x3d6b657c, 0xde784681, 0xf4e0ef56, 0xb0977aa9, 0x5ed84f12, - 0x67f9c89f, 0xb69cddeb, 0xf7f167d4, 0x9c3deae7, 0x8a3f59df, 0x7bd42ff3, - 0x7ebbbf39, 0xabbfa722, 0x84efe22f, 0x3a4be61f, 0x93f9d1df, 0x9f3a5f4e, - 0x05aba50a, 0x33dc6684, 0x0fccf6a0, 0x79883e75, 0xf8bbf258, 0xa9cebe93, - 0x113f914a, 0xceb450fc, 0x5428ff01, 0x22f33ecf, 0xdca3b9e1, 0x1da1f1c9, - 0x0ec1f242, 0x8dcf83a7, 0x0dd8bb64, 0x32c340fb, 0x869ddb6f, 0xb95e7873, - 0xba06ac22, 0x5c36a9bd, 0x7d740d58, 0x29ac5d73, 0xfdeebf3f, 0xff50fad7, - 0x2df18b3f, 0xbb1cfac2, 0x7fa3d4e3, 0xdf8fefa4, 0xeb033a71, 0x796c704e, - 0x1edee308, 0x2ad1c1a1, 0xceddbae1, 0x08c0d2f2, 0xcfe14fa9, 0x2d738861, - 0xfb7d894e, 0x31e70437, 0xda061d6d, 0xc146b35d, 0x754ab32e, 0x1f2aa4ad, - 0xfbe8bd63, 0x2af5b59f, 0x7c630ba9, 0xfb6a3496, 0x4cff18d4, 0x57de3cf8, - 0x78a75cb0, 0xe91f8085, 0x41ec2ff8, 0x71c41192, 0x685011c5, 0xad94851c, - 0xae17b0f9, 0xe428fd79, 0x10eea574, 0x873ed5cb, 0x8428e393, 0xd8d676df, - 0x9077529f, 0xfed689eb, 0xc8c838a6, 0xf83b5ee1, 0xeb1b6805, 0x40759256, - 0x268b9f60, 0x94f1ef85, 0xd6cbdf69, 0xe2f8a628, 0xe655337b, 0xac32878b, - 0x14ca0e9c, 0x89a5139a, 0x5e9d29cf, 0x3c707f89, 0x9e535963, 0x2f81917d, - 0x4bdf6897, 0x78a62cb3, 0x321943c7, 0x98106a2e, 0x6777a505, 0x3217daa5, - 0xdc7373df, 0x24bf5ebd, 0xea757f2b, 0xe883f470, 0x8ff6aea0, 0xddb95a64, - 0x84970ca1, 0x59e741c7, 0x74e9c714, 0x72e82e7b, 0xeff8a7cc, 0xeb3f0c95, - 0x3ecf1559, 0x7bfc2cfd, 0xe30a7f15, 0x9862a9f3, 0x0ec8df66, 0xf2ce9c8c, - 0x8ca9d78f, 0xd72dfc84, 0x7fd3fc7f, 0x547c4689, 0x57694ecd, 0x690db4a5, - 0x6ce5edf5, 0xd0f6ab57, 0x9f0388fe, 0x5fcdfb35, 0xd14ff67d, 0xf897acad, - 0x5bf8b493, 0xdeaaf78e, 0xc0e38279, 0xd0afb8f4, 0x37ca3576, 0x71eaa7ac, - 0xb63fba01, 0xf78d9f70, 0x851ecd4d, 0x5d9a98f5, 0xe7c01317, 0x4aadf66a, - 0x272e2ee8, 0x5e3d5fb4, 0xd5bfb740, 0xc39fb588, 0xc384487f, 0xffad0ff8, - 0xaf546676, 0x62054353, 0x3b60aed5, 0x1c705588, 0x8e2d72c7, 0xc19023b3, - 0xe49ee17e, 0xc4f59aed, 0xedbf49f0, 0x1063bab0, 0x88417caf, 0x53addd89, - 0x7e7920fc, 0x047da39f, 0xed85f0bf, 0x1791cb2a, 0x7ef147b6, 0xff7edea8, - 0x55dbc441, 0x8dd8566f, 0x308e2557, 0xaa77aade, 0x0fe061c2, 0xc50bb035, - 0xd2e70cf7, 0x416aa3a7, 0x145a4b5f, 0xadf816ef, 0xde98ee1d, 0x35da7806, - 0xd61a5afa, 0x45d79232, 0xf814ff83, 0x5cce419a, 0x8e7ef7b2, 0xe77aa413, - 0x6df9ae59, 0x51b3c724, 0xce036f0f, 0xd80a1b33, 0x65a4bd4f, 0x05cb3547, - 0x105d23db, 0xccdb4e69, 0xd1be29f7, 0x9346fbc6, 0x4fc0ced3, 0xaacff682, - 0x4e030f2c, 0x5ad3cbec, 0xcedeab3c, 0xb3b64832, 0x0dfb7868, 0xae88e7f6, - 0xda5a4bfa, 0xfea9d3a2, 0xe7dfbb27, 0xee4839d4, 0x23ce25e3, 0x3f4738b9, - 0xf7c919d9, 0xf9d93eed, 0xd12f09eb, 0xc65ae778, 0xfb0c52f4, 0x1b20e06c, - 0x41b73fd7, 0x25f301c6, 0x5a0fd611, 0xb6673e78, 0x27ac2927, 0x9f84df03, - 0x8f9f3b33, 0xf63ef0b6, 0xab717bff, 0xc86b15b3, 0xb2eb847d, 0x5bfe8047, - 0xed11fbb5, 0x7fe5fd9a, 0xed6affa7, 0xa4529b7b, 0x3bef238d, 0xc20e3d08, - 0xd53beda5, 0x796efbc9, 0x2fef9d94, 0xbee6182c, 0xe8f81e71, 0x518e329b, - 0x043f77f4, 0x3bc16ffd, 0x596f6cf1, 0x41f7736e, 0x36c38bfe, 0x282c13f6, - 0xa1f51cf0, 0xed9d8c7e, 0x75b1224a, 0x6dadec04, 0xa8be5229, 0x933b435c, - 0xe88fdc50, 0xacf84fcd, 0x8f84580c, 0xa50793f2, 0x523ebaf2, 0xd9daf16e, - 0xfbe413ff, 0xc2ecc792, 0xfe2f7b8f, 0x5d7ea4e7, 0x0efd2a99, 0x517f608f, - 0xcc17195a, 0x4edd878c, 0x69ca9ba3, 0x9fa06e54, 0x4cc14dca, 0xed674fc8, - 0x72891ed2, 0xf9954de8, 0x46835eb2, 0xfd07e8a7, 0xceb8a5b6, 0x2bbbbcb3, - 0xb0ef404a, 0xed2518bc, 0xdf09bf21, 0xaf386614, 0xe9241a6f, 0x07f341b8, - 0xf848b7fa, 0xf8e41700, 0x4ca6f625, 0xb8fab9c8, 0x789ba24b, 0x78dab3bc, - 0xa49a224b, 0xc78b44ff, 0xdf1e7d43, 0xd3bfd826, 0xcb1864fe, 0x1efba7cb, - 0x9fe30179, 0xc730727e, 0x04a5b411, 0xf2e6ed16, 0xaee38e70, 0x082c2a78, - 0x327b3f78, 0x9f58ed8a, 0xf61ca4d9, 0xcb025459, 0x1ea28761, 0x3afe805c, - 0xe0298736, 0xc2299fa3, 0x2df2889e, 0xa80e59bd, 0x3f63afa8, 0x17b10549, - 0x4e94afc8, 0xd9f7dc84, 0x276cc196, 0x950decfa, 0xf7d0292f, 0x13eef835, - 0xc67e0b4d, 0x3ff4bff2, 0x6fea7e9e, 0xaff3bb83, 0xdb366c54, 0xd7f5f4c3, - 0x2418efcb, 0x0c7703ed, 0xcac97a92, 0x7fe92e41, 0x30796c8b, 0xf929e795, - 0xeb03ad03, 0x131fb47f, 0xd63f6f60, 0x714127b2, 0xccc1cf02, 0xdbef035f, - 0x7a759ea4, 0x42fd8dbb, 0x79462f15, 0xe774fed9, 0xb0ef7c15, 0x78729542, - 0xdbde4585, 0x99eed0ab, 0xb2674456, 0xcdf08b7d, 0x16fb6d7a, 0x8e471b55, - 0x01d6d9fb, 0xd4109fd2, 0xf0e42ff2, 0x7149b83d, 0x2c69e6e2, 0x05c86d5f, - 0x8e6e2f5e, 0x1a79f8e4, 0x87b88bc7, 0x5cfd9f8a, 0x116633e2, 0xae7407eb, - 0xd4ae7f31, 0x9dd573f8, 0x5ee0c757, 0xe5477881, 0xad1712fb, 0xbfe03e9e, - 0x4f7af8a1, 0x5f4b63e3, 0x41f99478, 0xc417ed25, 0xfcd52d59, 0x529f4bcb, - 0xba5c9e58, 0x9887eafa, 0x136dbeef, 0xb6705fb8, 0xe368fee5, 0xf8d5ec7a, - 0x0f7b5767, 0xf54a5fd7, 0xa337fb65, 0x36ad9e19, 0x5d09e00f, 0xfeddefc7, - 0x6a5ff529, 0xf242d15f, 0xf3e5ee45, 0xdc8e28bf, 0x95f027f6, 0x676ce1ed, - 0x7be7f5a3, 0x2d6c6746, 0x33ff308b, 0xbf3384cf, 0xf72b1339, 0x9e7427fd, - 0xe780edfa, 0x5db1f787, 0x02e9bded, 0x80e2d0e7, 0xae1d5fb9, 0xafdf1afd, - 0xc0c4f78a, 0xeb45534f, 0x7d68fe81, 0xdfedc47e, 0xd0fb71b1, 0x768e3cf9, - 0xf4fb0c23, 0x9ba64899, 0xbae4fd33, 0x1076799c, 0xb16d679f, 0xde09de92, - 0x674be864, 0x1b8a6562, 0x0a87a03e, 0x3387a497, 0x1ed85a63, 0xc1d94670, - 0xb64d9b69, 0xfcd3a8ab, 0x897f44da, 0x26d01fa0, 0xb58ea9ec, 0x80c72047, - 0xe7cc8fcf, 0xcefb8834, 0xd07376a1, 0xbebfce29, 0x84dcf259, 0xcf3e0578, - 0xe3f61b7e, 0x733df0b4, 0x564f269f, 0x4fdcbf6e, 0xdcaa7588, 0xeb3fb0ae, - 0x02fe7692, 0xddba5eea, 0xa972e89f, 0x6e22f15f, 0xb2e3696b, 0xa5fba025, - 0x81e6ebb5, 0x2c79f5ee, 0xb75feed5, 0xd3c32a29, 0x27fb4e16, 0x74f1f2fb, - 0x8a59aafc, 0x5c279f1e, 0x7b45f9fa, 0x2dcb2c38, 0x4db288e9, 0xa3655fd4, - 0x49c796b2, 0x395bf5d1, 0xb84f1d3f, 0x5efb02cd, 0xb9df769b, 0x70ebf9a7, - 0x524f04f6, 0x6d4fe496, 0x6f9ef229, 0xbef25bfb, 0x0a6fc5f6, 0x81fee262, - 0xfa91c83c, 0x7f047f7a, 0x72106816, 0x96e7c68f, 0x704eaec2, 0xfb306e66, - 0x9b36b273, 0x9bb643f3, 0xcd3bd9f3, 0xe6bddcf9, 0x7355e7bc, 0x7b7185de, - 0xfa09e177, 0xa103e236, 0xbe85236f, 0xfa94ceed, 0xb7d0f236, 0xc6df4291, - 0xc8dbe877, 0x1e46df43, 0xd0f236fa, 0xdf4291b7, 0x1a39f7c6, 0x7b352a9e, - 0xe381d629, 0xeb84f6d4, 0x5fbc00f1, 0x6049cc2e, 0x52ac2a3e, 0x24b0bd1f, - 0x4ec7e59b, 0x0754d33b, 0x38f499db, 0x7ca2b7a7, 0xc37ab2e3, 0x75647b7f, - 0xc76e14df, 0xdf9ae7f6, 0x6573fb49, 0xf613b87e, 0x9f55d68e, 0x13d886ac, - 0x444df288, 0xf6b60bfd, 0x556fc0ad, 0x6fec2bdd, 0x7ee15d6f, 0xfd7207e7, - 0xc7a2eed8, 0xdce3152d, 0x7d26df03, 0x7b6fc649, 0x6a3b461c, 0xac485fa8, - 0x3f21e435, 0xa1f39b35, 0x35f0207e, 0x355f69af, 0x6e3c1d31, 0xbe0bef6b, - 0x0749e27f, 0xa13af3df, 0x6cc4edd9, 0xba63cb17, 0x8f29df3c, 0xc26ca3dd, - 0x2b24bdf9, 0x1c77db8e, 0xd3dd30ca, 0x2f4b4d0b, 0xdabcb3e5, 0x58ab5f99, - 0x8cd94e30, 0xaf59fb15, 0x73e68c4e, 0xb60d16e9, 0x0dff9041, 0x440e0f70, - 0xe868e898, 0xbf10b8b6, 0xfd533f65, 0x4353bb61, 0x4c4396fc, 0x16d7d3e5, - 0x17b5ef98, 0x1f2a6d5d, 0x878cef68, 0x96ff4873, 0xd64b9f06, 0xe7cce8b9, - 0x4bd686f9, 0x847f3c56, 0x25bc56bf, 0x9a32d3e5, 0x7b40b787, 0xfe1f239f, - 0xe014ef39, 0x16c5bcaf, 0x54bef38b, 0x9d44873b, 0xb72e5cf9, 0xae2bbf0a, - 0x5dcaee8b, 0xed4b1bc2, 0x2536b4bf, 0x71dd1d33, 0x14255934, 0x2472192d, - 0xe57d0837, 0x8246278d, 0x8dd4aaae, 0xbf2a2ec9, 0xc56c0955, 0x71d3ec45, - 0xa4ae123b, 0xf8b4fff2, 0x75a2c91e, 0xef05b64a, 0xba3e0f9d, 0xbde04d23, - 0x9f6b1391, 0x3cb8e68f, 0x6d92fe8d, 0xc1d008ae, 0xf59526c6, 0xd4cdd814, - 0xd93a2eb8, 0x011f14d8, 0x8c7ca6bd, 0x717297e2, 0x0bdf49b4, 0x9aa147c5, - 0xe69b8efd, 0x2a90f17b, 0xf36a40ef, 0xf592ee5c, 0xaf6cba45, 0xe7d7b3df, - 0x47d3527b, 0x96be362b, 0x3f7d0b79, 0x2e7f783b, 0xd65784ae, 0x2f79e6ef, - 0xdadf6cb5, 0x1d7bd297, 0xd7985dbe, 0x45c6b7f2, 0x7ce3495f, 0x87c65db9, - 0x89f9b5ff, 0x4fc4fcc7, 0xc27a6cef, 0x8541fb0e, 0x1e876035, 0x46e4fe5c, - 0xae18e23b, 0xbf91b6db, 0xcc56da2f, 0xbefd00f6, 0x7c7aa7da, 0xf28f86b3, - 0x1706cab1, 0x60ffb3cd, 0x23ca4fc9, 0xa14b1c64, 0xdc35fa3a, 0x4db8b813, - 0x66bcc3c9, 0xe3b0ed14, 0x1a3bff1e, 0x37dd09df, 0x17a7871d, 0xabbd86f6, - 0xdf20f145, 0x89993ed3, 0x0f4472cb, 0x39b92fd3, 0x0869719d, 0x0a1fd5eb, - 0x8e70bed2, 0xd7e88764, 0xcf695587, 0xad123c43, 0xd83db973, 0x85e43a6b, - 0x0ffbe597, 0x8d0e7455, 0x2ede87ca, 0x169455c4, 0x744d568d, 0xd23e335e, - 0x0b660fb4, 0xfea2bec3, 0xa67e8966, 0x69498cfc, 0xce37faa6, 0x67e21a18, - 0x672aefce, 0xe99575fe, 0xdbaa975d, 0xe3856efd, 0xbf9ac67b, 0xd33b7a53, - 0xf6a60dd9, 0xe99a6255, 0x9b25975d, 0x133c65df, 0x8fa1d995, 0x41f76b95, - 0xb4dafb66, 0x9dfcadef, 0xafda6226, 0x7f3cd303, 0x8da5e794, 0x1dba08fd, - 0x9ffe367d, 0x1979ddd6, 0x898f19d1, 0x3bd85bf8, 0xe479667c, 0x42a9eb08, - 0x669543ae, 0x92caaa8f, 0xff2aa8f6, 0x9be23b11, 0x24d6ff09, 0x93754942, - 0xaa46f6c2, 0x938a48ef, 0x7df1dbf9, 0x075ef9a7, 0xf284bbfa, 0xf6316a43, - 0x35796857, 0x42e71bcd, 0xb047ec35, 0x6bfde983, 0x19f4eafd, 0xb43ecf7a, - 0x3760df1f, 0x6d8ae7ef, 0x23f60e3b, 0x8a2f4cbc, 0x497c43cd, 0x5b54cb65, - 0x74e5f671, 0x8bfdf3a6, 0x7fb616e5, 0x857e1c75, 0xdca3ace9, 0xddf191ea, - 0xd51f18ff, 0x0d6f695e, 0x3445bfa5, 0x1799f81f, 0x013c54ed, 0x5e03d645, - 0x432e81fa, 0x0dd492f0, 0x753c74be, 0x7ca42de2, 0x1c33fe31, 0x004a11f1, - 0xbc32f27c, 0xfad478e8, 0x2c13e45f, 0x013c1267, 0x3fa42786, 0xff742a31, - 0x20efc2dd, 0x84506c74, 0x3c6ef94b, 0xed24bb4c, 0xe4d30336, 0x2977dbbc, - 0xb3ebc81e, 0x7bf9592e, 0xc914bd27, 0x9319f538, 0x93b3fbcc, 0x7ee48a7e, - 0x81297999, 0xd36ffddb, 0x8fd177d1, 0x8d099fee, 0x5defd6ff, 0xddac1a2d, - 0x46211a4b, 0xc44ffb7c, 0x4072ebaf, 0xe749e74f, 0xf0d2e379, 0xf6ed4cef, - 0x951e5e1c, 0x3edaf1ca, 0xf3a88ecd, 0x4ed69f63, 0xca98b71f, 0xefa005dd, - 0x17b009fe, 0x4b4c6eaf, 0xe317be36, 0x3b63655b, 0x788af26f, 0x5dc38b4e, - 0x8a473809, 0x4d77c857, 0x27d5df8e, 0xe388fe01, 0x26bd6cab, 0x7fc7d751, - 0xe4593c3a, 0xe9c85f20, 0xb3617589, 0x3d78768d, 0xed2c1a6d, 0x7e39fa35, - 0x7a3872ce, 0xaadff636, 0x0508d15d, 0xfdeaba5a, 0xcf3a2e91, 0x8f7c5957, - 0xef7f660f, 0x85cf3e46, 0xec2e636b, 0x513cba70, 0x0fb0aab1, 0xffcafdce, - 0x9c31e579, 0xb615befb, 0x9fa3c804, 0x840aa07d, 0xc679d0ce, 0xe1a7c472, - 0xdd3fae92, 0x10f7c912, 0x1784553f, 0xea25a6fe, 0xe9975cfe, 0x0b3bdd5c, - 0x41deffe3, 0xb8c08ee3, 0x1889ad81, 0xc4cfe3d7, 0x1915beb8, 0x57d9dd31, - 0xbd66b4f4, 0xeab6f394, 0xeecd64f6, 0x791ef90c, 0x6270f7c8, 0x1e47be41, - 0xc8523df2, 0x4dbef8f7, 0x6c0c2ff3, 0x7e83cf68, 0xb22b1fea, 0x75bcf96a, - 0xbf7e4166, 0x80f08945, 0x78a2dcff, 0xc1bc70fa, 0xc4def966, 0xd57590f2, - 0x49da6bd3, 0xedd03306, 0x84392e0f, 0x8c6e6e31, 0xc7e53588, 0xea9afa39, - 0x4c52ba17, 0x0e25d7e5, 0xef5f9536, 0x7fe533ce, 0xa9a57598, 0x18cf64fe, - 0xa347fe53, 0x9fd537ae, 0xca6a9dea, 0xc7389f4f, 0x51667f54, 0xc6fca9b1, - 0xe54c4bd9, 0x4ccb7c73, 0x3fe579f9, 0xa9bfd535, 0xdca98576, 0x9c565c2b, - 0x77a17b77, 0x865fde11, 0x2de945de, 0x8d38656f, 0x9c7a3aeb, 0x7977dba5, - 0x5072694e, 0x36dea1bf, 0xd7ee25d0, 0x68070e80, 0xc0be67f7, 0x7e1bd2b9, - 0xf522a0c9, 0x417d23de, 0x42f5a137, 0x1e4747cb, 0x35a6e8b8, 0x7a2a7a2c, - 0xc4f895a6, 0x140e2be8, 0xf57e51a4, 0xad338553, 0x5f465fc4, 0x54f9e07d, - 0xb53d37ca, 0x3b0f964a, 0x51e51170, 0xf320df4f, 0x1a8b05d3, 0x7af90c8f, - 0x31e69f86, 0x6ba907fa, 0xd26ed23d, 0xa769bc6d, 0x80f0883d, 0x01e04d78, - 0x13e89069, 0x4fa201e9, 0x7d12afa4, 0x710ba596, 0xe913e890, 0xf13fd221, - 0x7fa4f7fd, 0xfa4c3d22, 0x49b7d227, 0x847a44ff, 0xefa44ff4, 0xf4e6cfd5, - 0xb71f7a83, 0x397d43fb, 0x6beb47a7, 0xf5c7fbf9, 0xb9fe9c75, 0x5ddfcfde, - 0x433b7443, 0xba31ed90, 0x7e1aabff, 0x76edd847, 0xfd1acedb, 0x9e578ac2, - 0xb2bfbaa7, 0x46b456a1, 0x5ab69f62, 0xba394f63, 0xf33d90fc, 0x6538ab5b, - 0x0f5ebf90, 0xe10d26f7, 0x98bbfbf1, 0x8fdf6b6f, 0xf203e989, 0x520a9d69, - 0x9f28297d, 0x2aba5f99, 0x0fc7f886, 0x81b5a9be, 0x74b43e5e, 0x0bfb7f7f, - 0x87da4e8d, 0x8c873378, 0xebbbf2e8, 0xf8ceef7e, 0x1e5f831a, 0x8e3d6cfe, - 0xf3c7f747, 0x473e219f, 0xf1eb93f7, 0xef6ad741, 0x707ee923, 0xef47fe3d, - 0x6092f0b7, 0x1acd77be, 0x512dcb2b, 0x38c41156, 0x35cf9c7a, 0xc43c968e, - 0xe9535c3b, 0x3eb738e4, 0x23ef1df4, 0xde2f3d52, 0x25fcdb99, 0xf2edcfd5, - 0xe6d1f7bb, 0x8f3ce541, 0xb63e4bc2, 0xc5a35ed7, 0x43bda01d, 0x753bf396, - 0xfc831188, 0xe1db2941, 0x7da8551e, 0x001c577e, 0xfaca47ea, 0xfe97f441, - 0xdd178d15, 0xc4068fb5, 0x6e21e4b5, 0x93b5406c, 0x8c36c6e3, 0xb9bdf209, - 0xded7b1e9, 0x4e22aad3, 0xd8c7e638, 0xfaa74f47, 0xefcf0266, 0xf00f73ee, - 0x5c5a7e50, 0x53a46f5a, 0xebb5de43, 0x62e67d66, 0xe97c755d, 0x4bd7d778, - 0x9e21b7c7, 0x5dfcf18a, 0x6eba17eb, 0xafa5eba1, 0x2ea5e153, 0x977f03fc, - 0xfad74faf, 0xfffb3ec1, 0xb70cfacb, 0xcc7df0b6, 0x07874ab0, 0x7ad77d70, - 0x262edcdd, 0xf1783ee0, 0xa441f725, 0x5f7cd24b, 0x8a967f80, 0xc05c1331, - 0x81cd4b91, 0xdeb4279d, 0xef59eff2, 0x077a90e1, 0x7cd60ae2, 0xbd79769d, - 0x1af521dd, 0x7ed60b62, 0x374ced2d, 0xe43d7ce2, 0xed1fb1b6, 0x1e3d70cd, - 0xa3ccebc3, 0xf1a71c75, 0x96a243a3, 0xd7120fcf, 0xf1df58fc, 0xcb8f52da, - 0xee72cc5e, 0x6e59a778, 0x514df09c, 0xd09dc623, 0xd68e442b, 0x6837e1fc, - 0x9a275efd, 0x7bd0dfb8, 0xf26837f2, 0xf93de869, 0xf26886e7, 0x01488a65, - 0x3c2f1a9f, 0xbded2e12, 0xd92ef183, 0x2f46926f, 0x8c556e69, 0x9f083d06, - 0x55f1cc15, 0x8b9077bc, 0xbf9cfd71, 0xfd38045e, 0x3f7208a1, 0x22918993, - 0x6c2123ff, 0x79039df2, 0xf55ab33f, 0x2ce427fd, 0xc2e65efd, 0xd8abdf70, - 0x4e44af77, 0x28f78f99, 0x4b8c15c6, 0xe303bb47, 0x1c9f2cdd, 0xbcb1a470, - 0x8b657d84, 0x6f7fdaeb, 0x6e92f9d0, 0x9106f795, 0x3a60dee2, 0xe9d7966d, - 0x86fe41fc, 0xed0215ac, 0x71cdb826, 0x1ffb7a38, 0x6b0ac6ba, 0xfdfccf41, - 0xfa7bb987, 0x66f3aec3, 0xb0f1a0ec, 0x7b19bf83, 0xf7cc78c5, 0x163ed8cd, - 0x39d98699, 0xbd3179cd, 0xa74e793b, 0x26f1aee7, 0xcf7c6b08, 0x1af1d678, - 0xcf1d4f8a, 0x2f5e02ff, 0x2fd78774, 0x37290b06, 0xa23e4a47, 0xac2ab7e3, - 0x1f671ef3, 0xa5445c63, 0x33e9e243, 0xb87b8c80, 0x3cf15775, 0xfd17a93e, - 0x7545ef81, 0xd43cb8a3, 0xc736250e, 0xc77f5e70, 0xef83ccec, 0x7c122746, - 0xea7c39d7, 0xd9cbc250, 0x492660fc, 0x0d93e230, 0xfaef7c0d, 0x07aab3dc, - 0xeaa57ff2, 0x4f01eb5e, 0x3f655379, 0x95e6f8a0, 0xc509f864, 0xa3e3eee6, - 0xaf121d2b, 0x32b3feba, 0xa7f788ad, 0xca241570, 0x3de4d5f7, 0xe81e5d72, - 0x8be3261f, 0x3dccfbf5, 0x232307c9, 0x1feb1f24, 0xbeaef926, 0xf38ed49e, - 0x48cfd449, 0xf74953e2, 0xb03eb045, 0x1a4de5db, 0x78ca7f0a, 0x75a79261, - 0x97a3bfbd, 0x5af03f7c, 0x68d0f991, 0x643f8fca, 0xef2a0113, 0xf14c2f18, - 0x946f8564, 0xfa16bbf2, 0x44b098fd, 0xfc0cafd2, 0x611ddc20, 0x32346f7a, - 0x8f94ce2b, 0xd533f4f2, 0x6a95198f, 0x0ef58f2a, 0x4fc79531, 0x7be537cc, - 0xaa655d17, 0x58f667df, 0xefafbe53, 0xa4fd5306, 0xbca669f2, 0xe49297ce, - 0x76a03127, 0xc0fda9ae, 0xfd5312ba, 0xf9857f14, 0xf7bf54fd, 0x9e025648, - 0x697f9477, 0xbc87966b, 0x96116aaf, 0x90ef5d91, 0xde5a3afc, 0x5ce89907, - 0x6491efc4, 0x0cccfd34, 0x8a8dfa8f, 0x46292673, 0xae24f7e1, 0x60f99b73, - 0x3f39a261, 0x2af795de, 0x2b9c6e96, 0xa828fe34, 0x6a929e80, 0xf3efa6ad, - 0x347c6a86, 0x9eb2e457, 0xefeb5dfe, 0xff5a621b, 0x4e5d7c50, 0x05e7cf0f, - 0x6f9ed2dd, 0xf9ec179c, 0x9ec0bc46, 0x9ec3cc6f, 0x7b0fac6f, 0xf61cb1be, - 0xc179637c, 0x8c1d3321, 0x83a66238, 0xe99a8e2b, 0xd0cfa740, 0xd5b2baf5, - 0xa7c21f4c, 0xb07f94f8, 0x6a7f575e, 0xf5d09fa6, 0xd78b0921, 0x1153826f, - 0xfbfca48f, 0x642eb5eb, 0x87d73abd, 0xf6f90df0, 0xbe50e0da, 0x48785b27, - 0xe4b77815, 0xd79e6d51, 0x27e5ad0d, 0x7d5bb6c3, 0xae7de6bf, 0x5f4355d1, - 0x871d5749, 0x1f070f9e, 0xffa4347d, 0x02f9fbd7, 0xfe3b3fa8, 0xf41db262, - 0x45df2ed1, 0xee1f036b, 0x49b715dd, 0x77bcba7a, 0xe39533f2, 0x9a598e18, - 0x82ebf014, 0xf036df18, 0x6bb39bcb, 0x1367f815, 0x458ed145, 0x8ff9cb88, - 0x17e464b0, 0x77f7940c, 0xdf2b7645, 0xe2f9d07f, 0x17192482, 0xf35432d8, - 0xdc647af3, 0xa543f3ce, 0xe3ca24dd, 0xe2e338e2, 0x83bf796c, 0x05e499d4, - 0xe1c7c039, 0x47c041f0, 0x69df85b3, 0x39b9b56c, 0x86ffc46e, 0x83f7e02a, - 0x72f90b1c, 0x35df2680, 0x0070e47c, 0x85eb41fe, 0x1c1d9ce9, 0x5be29870, - 0x99736e87, 0x892d39f2, 0x76c3faa6, 0x79e54dbb, 0x79532cc1, 0x298f21c1, - 0x28c8e23f, 0x8e2bfd53, 0x2bf94d7a, 0xea9a275b, 0x9169fd5f, 0xda249f29, - 0x077e061f, 0x3e8f522a, 0xe2553433, 0x7e382dc9, 0xb19dc16f, 0xa6a7def2, - 0xba72eb5f, 0xd3ecf71e, 0xde5439e8, 0x71f7681f, 0x5f43751c, 0x187be1e1, - 0x129f4d0e, 0xa7c03d66, 0xde772dc5, 0xe39bf0a3, 0xe578f596, 0xd3417d4e, - 0xdd39740f, 0x35ecaf10, 0x082f2bc6, 0xe03dfeeb, 0x3dd6d2ff, 0x7681fe14, - 0x9f86df39, 0x88def9da, 0x3c28570e, 0xda38b533, 0xefee8e2d, 0x25b2d8f5, - 0x1465259d, 0xfef41dfd, 0xcad3cd98, 0x365fdd6f, 0x4fd5a79e, 0x0bf0d5f4, - 0xfba567bb, 0x305bc7bb, 0xbe67ce4c, 0xd4f372c5, 0x32cf8e6c, 0x3bdf83bd, - 0x51fdea5b, 0xf3b74ab9, 0xe323105b, 0xdd8c44a7, 0x79edfa0d, 0x44cf893c, - 0xfbe468bb, 0xff9c5a47, 0xee5b6b4d, 0xf3454419, 0x7bda4ded, 0xe81b0160, - 0x9258d261, 0xd884f2c3, 0xb35765b6, 0xc7a2e493, 0x3f6cacea, 0x35ddbfe9, - 0xceb8248b, 0x49031bfb, 0x407d01ef, 0xb4be81b6, 0x71e54721, 0x1b9ec1ae, - 0x4df6fd81, 0xfb3d9c67, 0xced08405, 0x754fa90b, 0x874c6f43, 0xaffe3cfa, - 0xf143ede3, 0x42adeba4, 0xd74c338b, 0xd7f1d2e0, 0xf0d07769, 0x707fdfa7, - 0x6d15b32f, 0x8a3df272, 0xd2db8889, 0x4725afd7, 0x86ad65d2, 0x3f03d40f, - 0xa15ea9ea, 0xfb031d9a, 0xc7708772, 0x43a1bab8, 0xc2bffd3d, 0x9eff8e8b, - 0xc4f557ee, 0xc2f9421f, 0xeab7dd77, 0xd9ff4e89, 0x3e06577b, 0xb468e321, - 0x5ba40975, 0x677d3fd8, 0x6f3f7994, 0x8d7696cc, 0xa2beda71, 0x6799ddf3, - 0xf60217e6, 0xaa5586f1, 0x39e42fc6, 0xc4529c5e, 0x3a8b11ef, 0xe533cb17, - 0xcfd62f1a, 0xc80f85d7, 0xf5aee0f7, 0x455c2516, 0x9b6692f9, 0x15a048d8, - 0xf38fbbfb, 0x1b93bf66, 0x449efe71, 0x3726cdc0, 0x49b4b71a, 0xb94fec09, - 0xc5ecbdfc, 0x5c7ef94e, 0x8bd9bbe8, 0x2f17fd35, 0x86df602a, 0xcfee65fa, - 0x8f6bced6, 0xe12b7cf0, 0x0ba5bd67, 0x02de8d7e, 0xe8311df2, 0xf3b4aac3, - 0x8e969c70, 0x24fc3737, 0xc2795df1, 0xce16446f, 0xb76b46f3, 0xf89d7471, - 0x9d2afdd5, 0x1cc3c27e, 0x171a1faf, 0x4affd670, 0x1a7e7774, 0xd3d37fdd, - 0xdff4e83e, 0xa85f877c, 0x1e8969c3, 0xff043e05, 0x57e8dbbf, 0x8248f3f9, - 0x3127fd90, 0x6ab48ff0, 0xb98d89fd, 0xf44fdddd, 0xf1c5d8ad, 0xbe2cab10, - 0xf25c40ff, 0xef1fea19, 0x3ce5deb0, 0xf8fb8090, 0xd3bb3493, 0xe4d6f3e5, - 0x7ef2d1b0, 0xe55f8740, 0x2898eef5, 0x1f1373ef, 0xba77d815, 0x08aa7f1f, - 0xfbaa42f6, 0x466b7c49, 0x3f75fe31, 0x14707149, 0x61b339c3, 0x484f0db1, - 0x7b7c3eb6, 0xcbbb8461, 0x403ad27f, 0xe4f4e7c6, 0xc97e9947, 0xb8cdfdc3, - 0x73f71574, 0xca453b2c, 0x2cf78d6b, 0xd90d9d03, 0x67986c26, 0xdffbadab, - 0x23929819, 0xf852d1f7, 0xe21b7bd2, 0xac28567e, 0x84572c07, 0x7cc4071e, - 0x6c5fcf5e, 0x3285f2d2, 0x992acb7f, 0xc5ded56f, 0x3bd9aada, 0x98a44f30, - 0xedf0f40f, 0xf3043d9a, 0xe0798a40, 0xf21af83b, 0x83c86be0, 0xbe0f21af, - 0x0d7c1486, 0x51444bdf, 0xfd2a9e72, 0xfb0de33d, 0xf19efe03, 0xfe09b906, - 0xfe1e631e, 0xf87d631e, 0xf0e58c7b, 0xe1cb18f7, 0xe1e631ef, 0x87d631ef, - 0x8798c7bf, 0x1f58c7bf, 0x1e631efe, 0x7d631efe, 0xe58c7bf8, 0xcb18f7f0, - 0xe631efe1, 0xd631efe1, 0x58c7bf87, 0x629d737e, 0xacdd07f2, 0xba503bbd, - 0xa3e98e3e, 0x2928b539, 0x3ff7d687, 0xc7e7ff23, 0xf3ac54b6, 0x6efc25de, - 0x47845560, 0x44d373ae, 0x2116eeb9, 0x0e7db9d7, 0x76edf3af, 0xf1942f99, - 0x03f4a1c2, 0x74f8cabf, 0x0a4157e9, 0xf8520abf, 0xafc29055, 0xfd2ade32, - 0x57e1482a, 0x55f877c1, 0x82afc290, 0xa4157e14, 0x8520abf0, 0xfc29055f, - 0xbf07682a, 0x55f8520a, 0x157e1df0, 0xe0abf0a4, 0x038231fb, 0x2e1d15fe, - 0x26e9f9c8, 0xd0e8943d, 0x4cba87a4, 0xc6f9c879, 0x8df390fa, 0x8df390e5, - 0x8df390e5, 0xc6f9c879, 0x8df390fa, 0x88f11bf9, 0xef296f71, 0xde41db1b, - 0x9a73e637, 0x86c1affc, 0xf9c37935, 0x46b69157, 0x2e298f29, 0x9e72eb92, - 0x58ff059a, 0x1c92b86b, 0x763921eb, 0x8d676fc5, 0x89f892bf, 0x2b976f16, - 0x6f582dda, 0xbad37bf6, 0xe38282f9, 0x3bfe7383, 0x7f75cb91, 0xbad1ff2b, - 0xac14ede7, 0x90cb6c37, 0x3dede970, 0xd522a5c2, 0xbbe577eb, 0xbe3a17af, - 0xa5f98f5e, 0x28520e01, 0x910710f3, 0x1f33bb77, 0x2d5bedf1, 0x5d0b8c8a, - 0x4372e329, 0xe349aae9, 0x3b2d5b4b, 0xbb50440e, 0x83c562f6, 0x5699077b, - 0x0f96c871, 0x43e6d53c, 0x89cba89e, 0x6b83e2d5, 0x903c42af, 0x7f6eb70e, - 0xf7c13e24, 0x0bb746dd, 0x738d197b, 0x8ec217cd, 0x64985bdf, 0xda04f297, - 0xea1cdf41, 0x0c9bbc57, 0x4732bdf4, 0xff3e7b9e, 0xe8caabb2, 0xb5edd0fb, - 0xdd1ee157, 0xeed908a4, 0x33478f37, 0x2a34a71e, 0xc9fef09b, 0x8bc2ede8, - 0xd4bfb1fb, 0xddba1ee0, 0x71e32f65, 0x4eff7c5d, 0x4378b7ef, 0x2c17df32, - 0x13e3ad16, 0xf0a127d9, 0xde3ae6fb, 0x62af7e68, 0x0fe2c47e, 0x2ffc8ec1, - 0x7121c3df, 0xc3dcfbf1, 0x6c7866b9, 0xc4dbe221, 0xe40ef95e, 0xabc5e1e4, - 0xbe5c137a, 0xf2077c80, 0x5f6a2f9a, 0xf966fce3, 0xcf93240e, 0xcf8f8648, - 0x857e41c3, 0xe298ffdf, 0xe5e968df, 0x15e0bdc6, 0xdfd404b6, 0x0b503c2e, - 0xaf790906, 0xb6579f55, 0x57096238, 0x95e22f40, 0x11fd0378, 0x7a0198e7, - 0xf8d8f3c9, 0x56a9907d, 0x46fc0d97, 0x5d8a7397, 0x7542ec72, 0xf7df0c74, - 0x2e13910b, 0xb8e6f636, 0x8e3d7f8d, 0x93ef83a4, 0xce15df2f, 0xf88f8572, - 0xb9e6f807, 0x5977193c, 0x91c3ecb9, 0x38aed496, 0x8129d392, 0xf3df78ad, - 0xe88eea74, 0x11cb0a51, 0xdb5fc087, 0x7be79f1a, 0x5eabc582, 0x1710fbe3, - 0x96881f1b, 0x7fa4aaf7, 0x9bc34ca5, 0xa85a6f6e, 0x16994fad, 0x5ebc743f, - 0xe74bcfbe, 0x71f7bf30, 0x72c6d1b1, 0x28bca846, 0x880feb84, 0xb46f2b73, - 0xc5d3ddf1, 0x27578b6b, 0x777eee8a, 0xcfe32bc5, 0x349771b5, 0xa84e38da, - 0x2b477b5c, 0x965877f4, 0xd2e8726a, 0x27efe66d, 0x4fe44272, 0xad44fdfd, - 0xaf5bf14e, 0xa83964cc, 0xee71c6d6, 0xb94857f3, 0x0110ec48, 0xbf9867dc, - 0xef059c62, 0xe5dfcc58, 0xd0dd28f5, 0x7c9a3bd1, 0x12830934, 0x8a5ea7de, - 0xed32be60, 0xcfce3f52, 0xe9c894ba, 0xe4b2978d, 0xd11dac77, 0xbca16b4b, - 0x26beff5f, 0x1c44cd17, 0xb2e40165, 0x1dd74c3e, 0x2218d744, 0x4357e357, - 0x302bcabc, 0xf9b24fc3, 0x734e2156, 0xf7c146d2, 0x7e432691, 0x90d982a2, - 0x2fb00aa7, 0x3ef90a52, 0xef8544c6, 0xbe1e4cb7, 0xb407db4c, 0x11f3042f, - 0x37c3f77e, 0xf1006a7e, 0x3b7db337, 0x7d77582c, 0x6dfcf83f, 0x64e60efc, - 0x7bc762bf, 0xcf4d3e81, 0x743de9d6, 0xd4882c5f, 0x694e63ec, 0x8fb4eaff, - 0x9c7e5801, 0xc446f227, 0x2d802eb3, 0xb0b69fb3, 0x6ca8aa84, 0x1b9c9e59, - 0x94236379, 0x6ed37fac, 0x9162df32, 0xfe489ff7, 0x717578e3, 0xe50fb0a4, - 0xf92ad78b, 0xe1d79788, 0xd8d87afa, 0x777ac349, 0xe74941d1, 0x03eeccfe, - 0x5df960bd, 0x4cff2619, 0xf84a5a68, 0x105a3ec6, 0xfc63fad3, 0x5c84d0d2, - 0x889f1de1, 0xf9f5c877, 0x02e2208a, 0xdbf96ae7, 0x8ff2bd9e, 0x278c9c6b, - 0xedcd8fce, 0x3fe22377, 0x38fe65fe, 0x7f1ab15f, 0xf14daa37, 0x3de57379, - 0xdf5809c8, 0x7e76ecc8, 0xa66660c7, 0x212f9e4b, 0x72db9676, 0x845df2dd, - 0x694b7b10, 0x846f3cb6, 0x8f3c9dd5, 0xb66e3afd, 0x3ef3ea57, 0x33df336e, - 0x5cead3d5, 0xbff83769, 0xa0f127ba, 0x7ffbde45, 0xf1d812c4, 0xa06bd122, - 0xe6016fb7, 0xbde208fb, 0xcf1f7e19, 0xa3477f4f, 0xef694f93, 0x74f4e865, - 0xdf22eeac, 0xda712897, 0x9e81aadd, 0x7c28d6ca, 0x4ea4b11f, 0xadf627de, - 0xfcbde451, 0x8f57ec1e, 0xdf9af9cf, 0x17fc7a51, 0xc350b211, 0x91fb7cef, - 0x5d291cd7, 0xdd53fdf8, 0x7f926caf, 0x6f103306, 0x9c36b73f, 0x7afe41df, - 0x018fd158, 0x87b6647f, 0xf11269d7, 0x1a9fd434, 0xbe29fbe3, 0x07238897, - 0xf05c6f61, 0x7df8b7f3, 0x29bd9ae1, 0xf161eefc, 0x78d5bcee, 0x61ebe547, - 0x89723bbe, 0x2e9d8b7e, 0xea90e43b, 0x973e58c6, 0xeed1f417, 0xf6768ba9, - 0xf3ebe9e7, 0x0794ae60, 0x9c723c8a, 0x453e9a0b, 0x354db308, 0x7fe793d5, - 0xedd43ee8, 0x95f6a1a2, 0xbe2af7d0, 0x7b029ecb, 0x5760dd89, 0xb631edd5, - 0x7073e3ac, 0x77b7cf9e, 0xaf8dbbff, 0x4d4776eb, 0xa9d85d9f, 0xe84f66cf, - 0x9d7fb903, 0xbd1d82e2, 0x11bee9cc, 0x8765f5f1, 0x14f0886c, 0xf2dce293, - 0xe4bb92dd, 0xb72525bb, 0x9b3f31e6, 0xc7c9358f, 0xbc5187bd, 0x9402cb8f, - 0xdfbcf7c6, 0x657bade7, 0x53d01ec0, 0xe0f7cbd0, 0x7b5e5ccb, 0x2a2e419c, - 0xef4c526d, 0x17f9e818, 0x721da573, 0xc019a93e, 0xa6b74ddf, 0xd086f1d8, - 0x108f127c, 0x46baf837, 0xaa3b7a27, 0x932571c7, 0xf941c552, 0x9dc114ae, - 0xfe33c722, 0x9349514e, 0xaa063df9, 0xfedd72cf, 0xafee28dc, 0x4ef345d8, - 0x3862ea41, 0xa78c0f09, 0x3fa87bf6, 0xebc38f37, 0xd80c1a51, 0x8f983760, - 0xcfca1678, 0x186c0575, 0xbe51a4a7, 0x2b5be28f, 0x89adf1c7, 0x2e40e7b5, - 0x03ecbab0, 0xa360f28c, 0xbe78cf7c, 0x0411fbf6, 0x65cbcb2f, 0xf3dc2784, - 0x867defd2, 0x8358abe2, 0xd629acbf, 0xad365f2c, 0xe67d61b3, 0xc35ef0f4, - 0x971d1a97, 0xfbe18e34, 0x2f5665f5, 0x69f097df, 0xb2ebfef8, 0x27e1bbf0, - 0x90fcd399, 0x8d79052d, 0x3c097d2f, 0x829e06f7, 0xd23efc19, 0x678e70b2, - 0xe26ae39e, 0xfbe276f9, 0xe40fc201, 0xe3115715, 0x8fc4e89b, 0x66b2c038, - 0xc176faf3, 0x65df2513, 0xfde62e6f, 0xb3eac8b7, 0xac708cbb, 0xfb819fdf, - 0xdf68735b, 0xe127fde3, 0xcc7df1f2, 0xc8dc0f53, 0x3806fbbf, 0x8f28e781, - 0x3bde027b, 0xba61ba22, 0x4167e9d6, 0xfacfdc81, 0xacc35178, 0xec3f0ed2, - 0xf7a9f6bb, 0x06f3e420, 0xffd86f5a, 0x76a7da7b, 0x71a4005c, 0xddf265ed, - 0xab7dd0ba, 0x9f7d57ef, 0xdf56fbea, 0x8ad98fcf, 0x174a8982, 0xbdf3a1df, - 0xf06eb9f6, 0x77834934, 0x84aeb6ae, 0xc18557d7, 0x986237ae, 0x53f3dfdc, - 0xfd1ffbcd, 0xbd54dfa1, 0x03306c7c, 0xfaf53df7, 0xe3f3b8fa, 0x03ec3b64, - 0x30ea5bd0, 0xe5fd674b, 0xe262df5c, 0xfc9da51f, 0x04aafb63, 0x0a1d8ff0, - 0xdf96e1fb, 0xe5bee523, 0xe17bc8cf, 0xf8bf9667, 0x77aa2cf6, 0x0b8dc1fa, - 0xca2ff78c, 0x2c5f9282, 0xfc0b7924, 0x0f269163, 0xe5f4cc6c, 0xe7ec330d, - 0xc99ffbb2, 0xdb98fec4, 0x6f0a7792, 0xf9bcd1a8, 0x3f3fa3bd, 0x5787d2f3, - 0x5dcebbb9, 0x6b251e7d, 0x3b15b5de, 0xf493788d, 0x0756777e, 0x38a55b9f, - 0x6953e8b7, 0x61f33163, 0x8f7a4891, 0xa1eeb5d2, 0xa8dc50f4, 0x5a579cb0, - 0xfea03237, 0xd2ebf22f, 0x8df953b5, 0xf4bd7d28, 0x73f45f77, 0xa67f8757, - 0x35734eb6, 0x4c3d9e7a, 0xe5b9c3ee, 0xbc45f629, 0xf8ec53ff, 0x5a39cdbd, - 0xf3329cf9, 0x72f5cef7, 0xd5fbf275, 0x9fb827d8, 0x58eaf584, 0xcbf6936b, - 0x57ad97ed, 0x1d02e432, 0x9d9ac58e, 0x6f66a172, 0xcbc9a45c, 0x8d8b5eb4, - 0x71f8b5eb, 0xcfa55eb9, 0xbc17f5be, 0xd3f34653, 0xef93a3de, 0xecb4940a, - 0xb39b75e0, 0x852d9d66, 0x5864fdea, 0xa8fe298a, 0x05cf36b4, 0x35dcfd3b, - 0x07e06d1b, 0xf126193f, 0xf3f74a16, 0x1d62f8b5, 0x148f38af, 0xaf473f83, - 0x83b83e0f, 0x5975b9c6, 0x77f1b478, 0x3d1a02ed, 0xc6c6d697, 0xdad2bc61, - 0x7fa17be2, 0xe840e7e9, 0x2e113bfe, 0xf50945f7, 0x6279fd87, 0x55ef878c, - 0x377ed7cf, 0x43feb42f, 0xdafddd1a, 0x4cbfdf26, 0x92796c8a, 0x226a3be3, - 0xe913e03c, 0x8c01ade9, 0xdc067a0b, 0x2f7c8b76, 0xf5b2bd33, 0xa241c073, - 0x20f5c73c, 0x105b7bc5, 0xbf2813ed, 0x79ef22c9, 0xdd32aaa5, 0xa607e1a7, - 0x5e8b9437, 0x5f1efcad, 0x2151bbe7, 0x9b176af4, 0x1fdde0d7, 0xefc12f7b, - 0xa9f4e9a6, 0xa7d3a3f7, 0xcd3dbf4e, 0x9cf7d76f, 0xcd1489df, 0x49e592ce, - 0x0bb8d076, 0xbfc41bee, 0xf35df16b, 0x35ef6bb4, 0x4c37ce76, 0x65c7defe, - 0xfa974df3, 0x6df3cf52, 0x66e84c2e, 0xd4f3a1be, 0x431e89f7, 0x694fe9df, - 0x1394fe92, 0xd4639d0a, 0x70b2c4ee, 0xe7d3ab8e, 0xbff5dba5, 0x8f87bdef, - 0xf669c586, 0xc828d6aa, 0xdfb5f397, 0x99411151, 0x86a9f7c7, 0xaff9faef, - 0xf3a75fbf, 0xdab593e9, 0xef5a28f9, 0x75167ec1, 0xf50f7c69, 0x2889d358, - 0x627313bc, 0x6f4f848c, 0xde4dab77, 0x76511673, 0xbbcfde37, 0xfe3cd6e9, - 0x8d8594bd, 0xbd9f587d, 0xf98d2ea9, 0x587e4dc2, 0x1ea74517, 0x83e348b0, - 0xaf16b791, 0xd7f502be, 0xc2eff0a7, 0x4e7a742d, 0x43f6e7ad, 0x2313903d, - 0x53daa79b, 0xfa961e59, 0xbb17ee82, 0x7c451155, 0x127c0d4f, 0x3fb2cbfb, - 0xe2cfe71d, 0x983f52f5, 0xe06b1164, 0x50d81d3f, 0xf82fa134, 0xfc8ac3c4, - 0xe60d9a3d, 0x0e86bcf7, 0x7c02fa2a, 0xbc5df426, 0x5e2d6d5b, 0xe482a7e8, - 0x16d1d80e, 0x9e588b3a, 0x93e345bf, 0xf8db9ac7, 0xaf1d7ebd, 0x78bfe08f, - 0x7ec42aa7, 0x1a276a14, 0xff07d9a8, 0x7b8faf1f, 0x0080003d, 0x00000000, - 0x00088b1f, 0x00000000, 0x7cb5ff00, 0x65545c0b, 0xce7bf8da, 0xc0cc2b99, - 0x1245c880, 0x85848b87, 0xd780c034, 0x508151da, 0xb9bba0bb, 0x658e21ba, - 0x500665ca, 0xd7775ddb, 0xa6a18cfe, 0x45fa7d66, 0x80ed65a6, 0x76c36a97, - 0xa8283448, 0x59990bc9, 0x6a37627f, 0x5b63b92f, 0xba402de6, 0x6dbfedfc, - 0xbcf3cf7d, 0x511730e7, 0x6fbefddb, 0x797bf9fc, 0x9f5ef3df, 0xcfbcf3fb, - 0x8c346339, 0x63181b75, 0x418e8b2a, 0x89486839, 0x8d8c9964, 0x615f6909, - 0xf6c3894c, 0xc645db25, 0x7cfb4046, 0x1962c893, 0xfa31d72b, 0x1fbf8f7d, - 0x3c1f7631, 0x42f3c337, 0x07d634a9, 0xcc37d7fd, 0xd6c972a0, 0xf1ae6dc2, - 0x2509258c, 0x606393b1, 0xb66ae3c0, 0xce258a07, 0x2b307719, 0x8da4d3cc, - 0x73c325d2, 0xc7292bb5, 0x496f9fe0, 0x0c4943e3, 0xd4699dc6, 0x7b4377cf, - 0x414e6981, 0xba5f8c14, 0x325b2a33, 0x6f5dfbfb, 0xc91b1811, 0x4673a558, - 0xcc614b1c, 0x67e1ddf1, 0x1fb0a94c, 0xf304d398, 0x7709e57f, 0xa38ba0bb, - 0x82492dae, 0xb3aa3c23, 0x7fa058a7, 0x6f31d895, 0x4e73cc12, 0xa04def70, - 0x5338e6fe, 0xe5a1fac0, 0xccc63ae9, 0xff398ce9, 0xcf3487cf, 0x3b89e2e7, - 0x8778c016, 0xce047f73, 0x1ff8f553, 0x6c3201f2, 0xb2cf689d, 0x8dbce1e4, - 0x1c124d7b, 0x56637b74, 0xbee39c09, 0xda46c7c7, 0xf79f2f33, 0xa8b668b6, - 0xdbcbda04, 0x6957c118, 0xd48ee85f, 0x5eeddc20, 0x696131a6, 0x28689a62, - 0x956c48cf, 0x52dbca07, 0x06b9a2d8, 0xe10dbb7f, 0x899eeb00, 0x025492dc, - 0x9f7b15ed, 0x79433248, 0xa5ebc8d6, 0x9c7a7f7b, 0xddff4045, 0xd5e20d5a, - 0x0b1a62ae, 0x25d7bb8c, 0xb250dcd8, 0x12c668f2, 0x7d6ea310, 0x59b19199, - 0xaf9a7096, 0x630e7b62, 0xc17dfeb9, 0xab3f6a73, 0x8fb8c562, 0xd903f531, - 0x8bfca1cb, 0xe21f7bca, 0x7ab52ff3, 0xf1192b8b, 0xfcbc2662, 0x84548b65, - 0x05fbaeed, 0xfac05636, 0xac1a637e, 0x6ac9165f, 0xf4a17c71, 0xcf049b57, - 0xb2101c57, 0x787b30b5, 0x1ee6b766, 0xd1169103, 0xd389b559, 0x75768ad9, - 0x7fe02251, 0x2d408b45, 0x3357950e, 0x2f2abe1c, 0x80e6664d, 0xb6b656fd, - 0x8eb0cc68, 0x09ce19a3, 0x539e1dfd, 0x5e78a59a, 0x7cb185b6, 0x89fe27c0, - 0xa53e6bf8, 0x3f0037b9, 0x2e1cadd5, 0xbede56ce, 0x3b900338, 0x1362b699, - 0x26dea0d2, 0x6b3ebd50, 0xaa35fcc2, 0xfcfe7ac0, 0x9a586935, 0x354c4e08, - 0xf0025490, 0xa3d194dc, 0xd73bfc41, 0x5d42f3ca, 0x0d5eb01d, 0xde48e512, - 0xf1c06a9e, 0x3caf1a66, 0xd146b677, 0x6c33af78, 0x3609bb03, 0x61506d51, - 0x4434ef59, 0x56b3b960, 0x715950cc, 0x09166173, 0x1611dfe0, 0x6122c591, - 0x3d5eaaca, 0x3b501240, 0xf6845870, 0x83fb48dc, 0x0c719f48, 0x33e802b8, - 0x06057991, 0xf9dfdff4, 0x7fce2e59, 0x17df18cb, 0x5eaeb60c, 0x017e7d33, - 0x8b26c3d0, 0x5f4c8e7c, 0xc8f1d22e, 0xb0af4043, 0x6cd5a7bf, 0xcf073e83, - 0x42e6c257, 0x08c2cc3b, 0xb984dfcf, 0xafdfc0f7, 0xce226f31, 0x54de74cf, - 0xcc9af71c, 0xc35a25a7, 0xf5f60106, 0x63fb149b, 0x053b8fb8, 0x116cf8f5, - 0xc58d2071, 0xfe6afd7e, 0xc2796d9c, 0x4ffc03a6, 0xa367e8e7, 0x4062e645, - 0xf1519aa2, 0xc163a406, 0x60ab6366, 0x0f3307fd, 0x2e80cbdd, 0x31d01e1e, - 0x5eaf9c2d, 0x7d3dcfcf, 0x0094ec20, 0x2a8f46fd, 0xf4165916, 0x2958ab37, - 0x29943ff4, 0x9fd8557a, 0x9fd8dce9, 0xbe6d0ae9, 0x8196590c, 0x7a88d0fc, - 0x78eff51b, 0xca011bf3, 0xe1e2e944, 0xe2573848, 0x3d4b052f, 0x3c1b29f4, - 0x85fff4fd, 0x5352f4b2, 0xfca1efcb, 0x19bda475, 0xb0727751, 0x501d94f8, - 0xa3c9b0f6, 0xf9f264b3, 0xf1dff702, 0xa2226fab, 0xfabeff45, 0x7bef4e07, - 0xcea58ad9, 0xe9b8c022, 0x9b57921d, 0xfa7ef975, 0xa9e361e3, 0x39e18fd4, - 0x5ba20dfb, 0xe1ffb010, 0xd37f710f, 0x14af0675, 0x17d4e381, 0x38ff3a7c, - 0x751d1e66, 0x284646fa, 0xb1913ef8, 0x8c3cdc58, 0x7068b81f, 0x6fb9c137, - 0xa14ff991, 0x488b1eaf, 0xf191e9f8, 0xe991c0a4, 0x7e9122b2, 0x5e8ad5eb, - 0x4cb385f0, 0xe8d67f3f, 0x5e0cff38, 0xff386d12, 0xcdd6b960, 0x8ec18a60, - 0x5727d254, 0x007fa792, 0xd740ca79, 0xfb6a97bc, 0xf90fc233, 0x78fc074a, - 0xc02f0c97, 0x25f9c33f, 0x64bbfe79, 0x1065ddb8, 0x127e9c39, 0x6e992702, - 0xf650ba14, 0x5863982f, 0x9f1fb469, 0x47ddd7ec, 0x8f099323, 0xe383ffe3, - 0xdfc213ef, 0x01d62737, 0xff51b11b, 0xfc784598, 0x579fc05f, 0xf80bfeb4, - 0x9fc50eeb, 0xe23d7f57, 0xd2d171ef, 0x0880fc84, 0x26d2a1c8, 0x0658f9c2, - 0x932ffe23, 0xe09b2cc2, 0xffe4767c, 0x8fef889b, 0xfc2bdf22, 0x37d8a63e, - 0x49e4f51e, 0x7dc19ec6, 0xb50f44f9, 0x10a766a7, 0xbac75f9f, 0xf01db013, - 0xf117379c, 0xe876d82e, 0xfb7d2c24, 0x5df5865e, 0x1ecb0615, 0x5bbf6f38, - 0xfe61a974, 0x8ef72886, 0xc36eb0a5, 0x1716995d, 0xd59633b6, 0x3ca07286, - 0xbe7a82cc, 0x85cb8a21, 0xa4e90586, 0x277e0f87, 0x73c2ad25, 0x34b3082c, - 0x6c86ff41, 0xa01323df, 0x6cd630de, 0x57d74171, 0x1dbe9605, 0xd1d1cfc7, - 0x38730d3a, 0x323c36dd, 0x057a8dda, 0x7af3cff4, 0x1e593fa8, 0x0d9cf0c6, - 0x6884b68d, 0x2297cba0, 0x61b3a3ec, 0x4e24a3ff, 0xd0c90dd7, 0xa136e50e, - 0x387dc164, 0x6fbe78df, 0x17b082df, 0xfa2cc2f7, 0xd0591034, 0xb195727e, - 0x42a5e509, 0x73a57797, 0x75c63779, 0xc9c2076a, 0xd4659d35, 0x937ffcc2, - 0xbb814be9, 0x556c6360, 0x0afe1fb4, 0x70c8c59d, 0x7a735617, 0xe5974d73, - 0xd7733562, 0xe65f080b, 0x96f8070b, 0x42414169, 0xadd93469, 0xe5faefb8, - 0xf7091780, 0x527fe1cf, 0x619ee564, 0x2847e7f8, 0x4c88f32c, 0x328fe404, - 0x0ca3f9c6, 0x6fe908e9, 0x0051d015, 0x75df31fd, 0x65c3a751, 0x6bf1823a, - 0x70d3258d, 0x3f85cfbd, 0x89e363e4, 0x87f34a7f, 0x3656675b, 0xf40b0397, - 0x9fd899f6, 0x51148eed, 0xf130ae5f, 0x7f644ef5, 0xc5f51a36, 0x79bd5fc9, - 0x23c7961d, 0x86cb6e4a, 0x7c16dbfe, 0xfce2845d, 0x353e096f, 0x0b6fe39e, - 0xb468fffe, 0xbf56ca43, 0x43fef449, 0x192859f7, 0xaf4e5032, 0x15a67d04, - 0xb074e4b0, 0x74463ef2, 0x896ac890, 0xfd65e36e, 0x47a30c05, 0x00f37539, - 0xbcca8ed8, 0x9747fff0, 0xce896c74, 0xa2c69f5f, 0x7433ea82, 0x0bfd4109, - 0xcf41c94d, 0x171f8d6f, 0x39a67cf4, 0x3b3ea83b, 0xff505263, 0x82d32ddb, - 0x9c4e77ea, 0x8e7fd419, 0xdd504e6d, 0x1f244cc6, 0x738aea3a, 0xe1bb013f, - 0xdc92bab5, 0xe397544f, 0xd0f6aa63, 0xe805b37e, 0x5f3bdb24, 0x91ea0935, - 0x43265687, 0x11cb537d, 0xf43c4f5e, 0x66e03245, 0xf9d1cb73, 0x53dbd02a, - 0x45f43c6f, 0x6d1fd40a, 0xa7cfe2e9, 0x40a362c0, 0x39bcb6ac, 0x9af805df, - 0x8adf629b, 0xa9779af8, 0xf98a28f6, 0xbdccd7f7, 0xb942592f, 0x06746730, - 0xc53727ec, 0xbf3e10fe, 0x759ef62b, 0x1ffb0091, 0x46ab5b7d, 0x5d98bf3c, - 0xa1e915b2, 0xf3a722ff, 0x91978853, 0x96097eff, 0x8a61d903, 0x3c92bd9c, - 0x03adf854, 0x1512c6f4, 0xa54749c2, 0xe544ceb7, 0x2a78baa1, 0xd999d48f, - 0x57638012, 0xc795065d, 0x7ed42cea, 0x95226ebc, 0x546cea27, 0x4c575bbe, - 0x095d7765, 0xb2ff0a95, 0x6a0d96bd, 0x2a974224, 0x4fceb4ea, 0x63d2578f, - 0x69d92820, 0xf9d09f05, 0x39adbd4d, 0x9d75ce9b, 0x6959e909, 0x81f9da3f, - 0x9dfa0459, 0x3d11d56a, 0x9b74354f, 0x475e5675, 0x22fbb8b9, 0xbc118af3, - 0x5fb02a9f, 0xfd1b278c, 0x030ea998, 0x841b4bf5, 0xefd8597e, 0xf79404cd, - 0x16356b53, 0x509e63b4, 0xf61e9733, 0x90df146f, 0x20e31d70, 0x05d86cca, - 0x903ad518, 0x6ba07157, 0x63f439f1, 0x0f77283a, 0x4746f5f2, 0xf9472ed7, - 0x60ccba34, 0x95f2e7a9, 0x08e24be4, 0x2fee026f, 0xda86a571, 0x198f628d, - 0x9d5f60e5, 0x69d21677, 0x0ae72c81, 0x30ef5c34, 0x80bde411, 0x576dfb7c, - 0xedf3da22, 0xd02f9edc, 0xfa44ec96, 0xfe7156ae, 0xf77a3165, 0xd5475c1e, - 0xf42cf15d, 0xb44d89eb, 0xc568426c, 0x6069641f, 0x14d617b7, 0xeddca267, - 0xaf885b61, 0x13fd5ec1, 0x338fdbd2, 0x9945df81, 0xf89e6048, 0x4da6f0e2, - 0xd7adda02, 0xce5d21e7, 0x300f9ad5, 0xf65f07e0, 0xdcfbd100, 0x7a1e7348, - 0xafecbe0a, 0x7cce3d79, 0x26e78040, 0x00bf3036, 0xe9cf55ea, 0xf0049f4d, - 0x1513d3a9, 0x4b69af54, 0xc0127d30, 0x07f855a7, 0x09b747fa, 0x0ebb942a, - 0x04a72b79, 0xb7c405fb, 0x0d73f8b3, 0x0680dfdf, 0xd98bd8ed, 0xb06fa266, - 0x0fef4997, 0x9bba34cc, 0x2371bf60, 0xa057b36a, 0xce6994fd, 0xea497ec3, - 0x63f40881, 0x1555bffa, 0x19efc9bb, 0x78c9f888, 0xd33d7d3f, 0x287b5121, - 0x70e6b5dd, 0xcd26af7f, 0x50f119b0, 0x51d3af1d, 0x88b171d9, 0x92569d91, - 0x4db97686, 0xd0cbfdc3, 0xb8737bf1, 0xaf5e491e, 0xa240b921, 0x0b6cb608, - 0xc5dd4a63, 0xf8d63226, 0xbf21b08b, 0x34c9c007, 0xc83f6563, 0x41476235, - 0x1b7f505a, 0x8e7a1ff6, 0x8ff31cf6, 0xbb49794f, 0x5e4aad63, 0x2965e90f, - 0x183fa373, 0x72abc72a, 0xc0b965a3, 0x8c74fcf1, 0x9cf111be, 0xe77d0126, - 0x504cc950, 0xb2338626, 0xd75f1337, 0x773e91bb, 0xa7fd39eb, 0x2ddcbc89, - 0x309afef2, 0x577a42e6, 0xb94d87fc, 0x79b929f6, 0xe6978f34, 0x91b25a91, - 0x879813ae, 0x24ec57d6, 0x43d81fa5, 0xaa02127a, 0xd7c47481, 0x161c4954, - 0xa672279e, 0x448ce515, 0x4fb1b0fe, 0x5f77e403, 0x40aac478, 0x78e355fc, - 0xe9b8e043, 0xef194e34, 0x4fb2255c, 0x245c9047, 0x89a6723a, 0x4b562fe4, - 0xfe8088ec, 0xa0d6eb16, 0xf5c6539e, 0x14fc1c82, 0x9047f0f0, 0x087e588b, - 0xffd710f2, 0x2c43c833, 0x10f20aff, 0x3c824fdb, 0xf207d2c4, 0x063fdb10, - 0xbce58879, 0xe4568dbb, 0x69b69a9f, 0x7e20d3ec, 0x017ddb50, 0xc369def5, - 0xa64391d3, 0xe1e4dea3, 0xe1cbaf9f, 0x2def457e, 0xa0fd9f1c, 0x00ffd1bf, - 0x8a6b5cba, 0xef1eb2be, 0x1ef9b237, 0x7cb6d380, 0x27f4876e, 0x1cd2faf0, - 0x226dd535, 0xb7e38edb, 0xfaf86be5, 0x3e396229, 0x79f345b7, 0xb245d37b, - 0x9e4ea69f, 0x9e0724b6, 0x3da162db, 0xbdef5fc7, 0x8db73f81, 0x7a43ede2, - 0x253e7e56, 0xeff8a4d7, 0x652fdce9, 0xbd012764, 0xff4afcd3, 0x3e7226f7, - 0x4eefed0c, 0xc3dd8b13, 0x992de3c0, 0xd02f896f, 0x483e469e, 0x6a8be00e, - 0x4285f133, 0x55fd0a87, 0xa73872e5, 0x073a6569, 0x43f042dd, 0x3a72831d, - 0x25f64f4e, 0xe0c6c5c0, 0x9905bb3c, 0x01f9425f, 0x0a07d44a, 0xa07c283f, - 0xf0227bd0, 0x3fed1099, 0xf421cdc7, 0xca8f94aa, 0x358ee8e7, 0xdaf09cfe, - 0xdfa136a1, 0x87cc3377, 0xc1c513e3, 0xfe46ef77, 0xd19a358c, 0xc87c2cf5, - 0x1c9c3b50, 0xc2effaeb, 0x570b9143, 0x7065c780, 0x5ff2f0d0, 0x39c90385, - 0xbf48e394, 0xfdadc8c3, 0x5db2d139, 0x44f7e9ce, 0xd21f6d8e, 0x57a0bf51, - 0xafd0dfa1, 0xd9dac367, 0x7f39f2db, 0x05547428, 0x89eb103a, 0xcbd4ce78, - 0x9e729ee5, 0x632e73a1, 0xc2d2ff24, 0x9e287b78, 0xc8057395, 0x0139c3bf, - 0xb8c61ff1, 0xd81d717d, 0x4d4fe817, 0x3ed335c9, 0x567e47fa, 0xcff995b6, - 0x6f0e477f, 0x88944a7f, 0x32fd141e, 0x8b482ed4, 0xe90664e6, 0x3f42661d, - 0xfc4b53af, 0xe67f05ee, 0x3e871825, 0x3fe49b21, 0x71e320bf, 0x1158fe70, - 0xafbebbed, 0x63d42e0d, 0x4e06a37d, 0x6fbe300a, 0x6436183b, 0x136ed897, - 0x07deef40, 0xd4f5063a, 0x2c7b9005, 0x7273b19d, 0x73cfa11c, 0x73fa24f1, - 0xa6243b35, 0x3b4a5003, 0xf4879abe, 0x6d53b4b4, 0xf6d0b8a2, 0x3d218ec7, - 0xcc156e9e, 0xb5f49768, 0xbfa1f1c2, 0xd6e8c1b3, 0xa822ff43, 0x0665ff63, - 0xd7ccdb8d, 0x4383f8a3, 0x7d53ef5e, 0x85c60a75, 0x1350ec66, 0x2f3e97dc, - 0x3b3ed1b9, 0x0aa57dbc, 0x02dda7eb, 0x4571838b, 0x04aeead2, 0x2d3e57a8, - 0xce30b458, 0x8b3a2861, 0xe7ca82f1, 0xf30bc599, 0xc918b657, 0xa0da5dcf, - 0x6017d8fe, 0xb7bb945f, 0x29eed06a, 0x5edc19df, 0x0eb83bb9, 0xeff922f8, - 0x00f68668, 0x8e6dfcf9, 0xcdec8631, 0xed1b2c71, 0xe3c0d64d, 0xbf7c8ab9, - 0x71756edc, 0xcb82ba39, 0x8cbec66d, 0xea5f7f45, 0x63e92afc, 0x91cfaf03, - 0xfea0a7eb, 0x2f1c57f9, 0xe5aa5c0a, 0x604f3fb5, 0xb79c0f56, 0x426f53ba, - 0xfdbabfff, 0xb71811ef, 0x51f309af, 0x22bd9f7c, 0xdbded099, 0x10b926d8, - 0xfd0ecebe, 0x56e0112e, 0x8d3de07d, 0x5f7088d9, 0xadcaf64e, 0xe31eb5cc, - 0x64515edc, 0xdd4744dd, 0xb666a714, 0x4f38a581, 0x84debb5f, 0x2bf54076, - 0x8ddd741f, 0xd30203f5, 0xfb471e23, 0xee964e88, 0x2da58640, 0xfbe426dd, - 0xbc4244e9, 0x913d9e22, 0x8865af84, 0xe033c477, 0x212cf11d, 0x51bc713e, - 0x2274e6e3, 0x73f4fd51, 0xde0abf1c, 0x1acda48b, 0xe46caf6c, 0x63b19e78, - 0xa230b6cf, 0xe9933503, 0x7a7ef080, 0xa6bbc727, 0x14669d73, 0x08636fd2, - 0x876bb41d, 0x77f700e8, 0xe0841d19, 0x8df002bf, 0x0e942072, 0x93dff142, - 0xd806e5c3, 0x429fa7df, 0x7e08dbfb, 0x23c7f301, 0x1ef55646, 0xcaf5818d, - 0x973bcfa2, 0xf8d8fb43, 0x08da5897, 0xe4157f8a, 0xe66bfc62, 0x5d10eb3b, - 0xc85eb33d, 0x57a97a46, 0x813cf6fb, 0x70a88b71, 0x27f4e38a, 0x32f9d9cf, - 0xfa20bb9c, 0xd816a49b, 0x5a6bcd7f, 0xc928deba, 0x35ec8715, 0xf129978c, - 0xc533c074, 0x5a1d9cc9, 0x2d6b171e, 0x73fa05b4, 0x5cfc09fd, 0xb2819a85, - 0xc017e8e5, 0x608eb87c, 0x555e7ee3, 0x28178f07, 0x1295597e, 0x8e0e6837, - 0x77a6081b, 0x2e455fa8, 0xc6a55f8f, 0x3b466cdd, 0xb3017ebc, 0x4d5ea587, - 0xcc78f03f, 0x74dfb2d3, 0x0af1fb45, 0x1bb1427a, 0x6e382b99, 0x65a9c8a1, - 0x8f1ef913, 0x6ab8e2fe, 0x76fdc604, 0x8a8f840b, 0x704f900e, 0xdab70ade, - 0xf802166d, 0x19ffee49, 0xedc01bd2, 0xa0f6ab8c, 0x19dd2128, 0x990ebf68, - 0x8e91ab3e, 0xd695bce0, 0x9cf02237, 0x38ae590e, 0x7f148dda, 0x8a5b64ab, - 0x612aee90, 0xf430ef3d, 0x0b5cf954, 0xa2d729f9, 0xaccec527, 0xb7ee0d6e, - 0xce487731, 0xe01eff8c, 0x396401bb, 0x992e7bd7, 0xf12332fe, 0x99906fde, - 0x879f9123, 0xedc09ff4, 0x5cfe4537, 0x3c581dbf, 0x6e71de60, 0xac05531d, - 0xa673e37f, 0x4f78faa0, 0x9bff507c, 0xcf41ccda, 0x4119bdb3, 0x598f73cf, - 0xdd79ea82, 0x4ffa8313, 0x5416d0f8, 0x0e2be49f, 0x4ce53fea, 0x307d5049, - 0x9573ce13, 0xe35bc1fb, 0x33fea085, 0xf9a0facd, 0x05446767, 0x320d07d5, - 0x52bb647c, 0xce5f77b1, 0x686ef6e5, 0x76f7c0a9, 0x8a3af04b, 0xc4e77ebf, - 0xd8e6f5e0, 0xa1fbd782, 0xfa0bd978, 0xc27e0554, 0xb15fa073, 0x13f81dfc, - 0x9a13f02a, 0xfac09fc1, 0x604fe08b, 0x027f01e9, 0x7f025fdb, 0xe0adeb02, - 0x20fd604f, 0x6f583ff8, 0xf2a62bab, 0x6a12ba95, 0xbafc16bf, 0xc98f75e4, - 0xd7971eeb, 0x74e177fd, 0x5def9e42, 0x9c6ebe79, 0xdcffcd2f, 0xbc563c59, - 0x2d3cfc04, 0x87c6acfa, 0x5f0ac37e, 0x062dc611, 0xc61892de, 0x7ddd99a5, - 0xf5062eac, 0x338a08d9, 0xb78192b3, 0x7d52ae31, 0xc9b4d520, 0x0fecfa8c, - 0xbef3e2ef, 0x7c8cc956, 0xefeda879, 0x85cf3811, 0x5f74614b, 0xef107a4a, - 0x5461bf1b, 0x31cf04df, 0x05b33a0e, 0x37e90804, 0x0bb7e90f, 0x4ddd4a69, - 0xcd25bdf7, 0x53c41a2d, 0x3c29f215, 0x0ea3cb7f, 0x635cfe7e, 0xf61373d0, - 0xe54ab287, 0xb9c238a6, 0x2f3e6536, 0xf1a477f5, 0xcf73cf7b, 0x053f5e1d, - 0xe2cb6ff5, 0x5e7f7811, 0xec5efcd5, 0xc7c157bd, 0xc85f07e7, 0x76cafba4, - 0x9fe0cf98, 0x96aed9cf, 0x8eff7ceb, 0x68a296b4, 0x02cd1c54, 0x05c50b1b, - 0x5fee85b6, 0x38f6daaa, 0x65556e50, 0x0066addc, 0x248f7e9f, 0xbdf837c7, - 0xb8c4c391, 0x22f9e71d, 0x5f57ef02, 0xc3bd1cf7, 0x38edf886, 0xf6eb811c, - 0xfe414ab7, 0xb72b68d3, 0x355b478f, 0xad0bbf84, 0x5ef02387, 0x30e7a377, - 0x4bcabb87, 0xd7243fe7, 0x7824a1fb, 0xfe7449b7, 0xd0624b8a, 0x5586763d, - 0xb66679a2, 0xb9e2358d, 0xbd7c3c7a, 0xb799ab1c, 0x825e2da7, 0xbf1e3ffb, - 0x7b224f20, 0xca350410, 0xef661bf1, 0xcaa43b41, 0xf386d923, 0x79e40aef, - 0x4e9cd4bb, 0xdfdb4adf, 0x78f8f285, 0xd26c88f1, 0x699f8a11, 0x916f76e5, - 0x7a869ec6, 0x3660c7a4, 0x583f9d22, 0xfc446a9c, 0xdb12c21e, 0xec69778b, - 0xe6c7bc06, 0xba98f5eb, 0x7aee9023, 0xb425735a, 0xf2f99477, 0xe88775e5, - 0x2e6f087b, 0xbbb953c2, 0xf8f380d1, 0x73dbc7f1, 0x7fea26ac, 0x3cdefddc, - 0x327aabb4, 0xe92ec9c2, 0xa7f230d2, 0x5db99aab, 0xd891d3dc, 0x924f7818, - 0xf2fd9563, 0xdaf0910c, 0xfb96a6d7, 0x0587bddd, 0x39d353f5, 0xde0eec2f, - 0xea7dc98f, 0x1dc7b451, 0xf50c4b4f, 0x1b5d43a2, 0x6cffe78b, 0xcafef067, - 0xd43b3865, 0x00d8d8de, 0x0fb4757a, 0xe8818df1, 0x13e15dbc, 0xc153e133, - 0xb7064f63, 0xf9e27ae7, 0x65a3a4bd, 0xe5f5d10f, 0x64eea4f1, 0x7f121ff4, - 0xe778a3a9, 0xc567fcb5, 0xaff0086e, 0xea8bfa18, 0x313cd4e2, 0xbc1f6fc5, - 0xb6ab6b96, 0xabbf448e, 0x1ecafc84, 0xac2cf606, 0x3a7b44e9, 0xb61ff292, - 0xad83bae1, 0x76bfba6a, 0x7d66daea, 0xa0d97602, 0xf6051805, 0x2d53b83d, - 0x0cd97bdf, 0x952ed768, 0xcccfdaed, 0xf4097cf6, 0x488d73af, 0x866473e7, - 0x27d31f91, 0x5bcfbdcb, 0xbb24ef92, 0x426498e1, 0x8786687f, 0x668ec1db, - 0x7b56d76e, 0x2a63ff92, 0x6acdedda, 0x8a60d4cc, 0xed94e21d, 0xddb2d390, - 0x80cd7a7b, 0x4e9bfc86, 0x8c963d81, 0xbb5b2a79, 0x33b9e112, 0xb3d91673, - 0xec99a94e, 0x83db6589, 0x6fb007ed, 0xcf55ea82, 0x7217da85, 0xdc13cb7c, - 0xdb87f8ae, 0xc67643ac, 0x0a67f438, 0xc871a9a5, 0x78c82f0f, 0x959bfc55, - 0xb7942de3, 0x9e6551b3, 0x1021c4a5, 0xfb9d355e, 0x6edf702b, 0xfc859847, - 0x10af558d, 0xe4bffb5c, 0x3c7f4c7e, 0x33f47823, 0x36fedf0e, 0x6a35e74e, - 0x48f98dc1, 0x34b64035, 0xaf704e9f, 0x6bb338c1, 0x13e48230, 0x17c8c563, - 0x7f70162b, 0x5f3186d5, 0x7e156b28, 0xb7abd108, 0x54527ca8, 0xb3689c80, - 0x02bf50a6, 0x3ea3b30d, 0x90b4695b, 0xe3a31b7e, 0x6ae17a76, 0xc3d2364f, - 0xb5c7f018, 0x31f8f101, 0xfb010186, 0xc7807eed, 0xc27895ff, 0x1d49951c, - 0x191fa015, 0x95fd435b, 0xf0a241f9, 0xdf9ad7f1, 0xfc1bf304, 0x23bc03f3, - 0x585fde11, 0x93b7a42d, 0xfff728e6, 0xca97c4b5, 0xbd002e79, 0x63181c61, - 0xc7378834, 0x9fc837ce, 0xf5eeb273, 0x8228ae38, 0xf708a3ef, 0x5e30f583, - 0xe79651fe, 0xbcbc79b1, 0xf9152e4d, 0x7b6790d5, 0x95f50adf, 0x593ff679, - 0x8899ae49, 0xb4ca573e, 0x9c4cf602, 0xbbf9186f, 0xf0891de2, 0x03f005fa, - 0x5ac2fbf2, 0x64169cc1, 0xaf3a712f, 0x3cec4de1, 0x454ef4f3, 0xdd6cb838, - 0xc6d79819, 0x5a2d7f38, 0x05a737a5, 0xbd2007de, 0x0251ffa3, 0x2fd1f2ff, - 0x5372bfe3, 0x57946dc5, 0x8cd62ab5, 0xc83517f7, 0xa6d7290f, 0x87ba50ff, - 0xb7a44edf, 0xa0b5a66a, 0x0b69a97e, 0xa1516e7d, 0x084dfe3d, 0x74c9245f, - 0xe81768da, 0x5bf1bd7e, 0x95a38f15, 0xbb37140a, 0x4e911a0b, 0xcafd87e9, - 0x7e71b9a7, 0xfba0b3cc, 0x391886ae, 0xee862bef, 0x9f227ee1, 0xf7952eff, - 0xa3efe40d, 0xc6324f6a, 0xf93a8e71, 0xe602d53d, 0x52dd7ba1, 0x6f654dd6, - 0x2f01f578, 0x8d1aee4d, 0x7607f87e, 0x1a91c52d, 0x511936d7, 0xb5b166ce, - 0x031fbc26, 0xfbee7936, 0x1bdb2bdc, 0x9468f7a1, 0xc7e7959f, 0x92bccaf3, - 0x83a03cf8, 0xf8a38033, 0x57c7cb9c, 0x02207fbd, 0xfefe7ee1, 0xca7ef3fd, - 0xb9020fd0, 0xd654f305, 0xbdd064b6, 0x67758b8c, 0xabf1fbe4, 0x1fc153e0, - 0xf08399b4, 0x0eb9670a, 0x0d9f33e0, 0xd36e63e4, 0xc0a9f0b5, 0xf03d4939, - 0xe8250463, 0xa1439231, 0x5ee05678, 0x3cd56acd, 0xeefb56fe, 0xb3ffe802, - 0xed19a2b5, 0x7ef0cbca, 0xf578fc0d, 0x28d791fc, 0x257b3f90, 0x5a78297c, - 0xff54bcc8, 0xfb8f8a30, 0xf144a170, 0x7c69ffc3, 0x4bd9e435, 0xb7c2aef2, - 0x257a7ca1, 0x2ab45cbe, 0xf8437f84, 0x2d2f8874, 0x7f002ff0, 0xc41155f6, - 0x1d7e0a8f, 0x5193f066, 0x2d1875ff, 0x3e39766e, 0xfdc5dfd1, 0xec0ab654, - 0xf087e149, 0xe3fc8fab, 0xad017c50, 0x541f50d8, 0xa9f305e7, 0xc92bc782, - 0x7dee452d, 0x4d47bcc4, 0x7067dd02, 0x9685fe3e, 0xfb94e9f2, 0xe2dee50c, - 0x6fae3cd1, 0xc08fcb42, 0xa27bc16e, 0x233d194d, 0xd5ebded1, 0x7bf0f328, - 0x74d68fd7, 0xcd7cc68f, 0xb2f1a68f, 0x4cf3c357, 0x8c2dba94, 0x4a3f03c7, - 0x6e10bad0, 0xa6e3091f, 0x91f01da3, 0x783bcbf0, 0xc6634e3d, 0xe9b882fa, - 0xaaf7a826, 0x83e1f895, 0x5376fcb2, 0x0982d1f9, 0x604fd405, 0x661e1047, - 0x3ad09581, 0x0c5d1082, 0xe7e8f9fb, 0x5ef07363, 0x03ff3940, 0xf48e3c79, - 0x431cf91b, 0x095ff6f1, 0x045f6f14, 0xf784c3aa, 0x289fd302, 0x93f6814e, - 0xa6cd4ebf, 0xc115cafb, 0x4dfea3eb, 0x56e538a6, 0x4b96e79a, 0x99c5ea03, - 0xe90d7dfe, 0xbc8b82cd, 0xa0d8c97d, 0xf45b667c, 0xbb27ee38, 0x8f512353, - 0xf06d7a29, 0x60437ed8, 0x1cacf51c, 0x8faa1e77, 0x5029247b, 0xf7b1be2f, - 0xa79c74e1, 0xb2cae35c, 0xf98f3018, 0x1fb424a9, 0x943ef7ca, 0xdeed764e, - 0x9fe8e98d, 0x9c3d3794, 0xb87aa36e, 0x1523fc9d, 0x7df9f73f, 0x0a6d7693, - 0x9d6fa3b0, 0x52fbedc0, 0x68851bdd, 0xf1bacedf, 0xb71875f3, 0x816bfb1f, - 0x590b70e2, 0xb7d43af7, 0xaf9c1965, 0xe48e8358, 0xf747cc3f, 0xddc67ba4, - 0xfee51bbe, 0xabbf8cf1, 0xcdfea097, 0x657cd153, 0x0e39bdcc, 0x041b6fe3, - 0xfbf9bf8a, 0xd77ba68f, 0x4d056bc5, 0x51ea0c7c, 0xc7fd779e, 0xe38228bc, - 0xbbb21b3d, 0x356cbdb0, 0x75a59f6f, 0x3ce0f6b7, 0xcf28684f, 0x4a65140a, - 0xf63dc049, 0x3df8f31f, 0x72cda2dd, 0xcebcb1be, 0x8db16dd8, 0xa3fce781, - 0xfe567f8c, 0x3b83c901, 0xb6dcbc65, 0xf123bdfa, 0xdaa46f30, 0x2b9467fe, - 0x3a7e3eef, 0x4159e50d, 0xa44cd9f4, 0xfb1ab1f3, 0xee781593, 0x2bc52d26, - 0x528959ad, 0xb9cff41c, 0x5863da7f, 0xf8bd5a2e, 0xfb8c0ac9, 0x1f91d76e, - 0x856feca6, 0x5fd11660, 0xd3f8dc3d, 0x676e107b, 0xa479e71e, 0x8faf1a2b, - 0xe2fe5abb, 0x1f3c75b3, 0x1d3af9fc, 0x99d42f95, 0xb88e1998, 0xea9e2eaf, - 0x5333afbf, 0xfa73e6c9, 0xaea6f252, 0xa5ee5f34, 0xb65bca30, 0x1e51d06e, - 0xf6d6ae7d, 0x6bc01e55, 0xa6ce0dec, 0xc6b9f28d, 0x576cf8c2, 0x83840cf2, - 0x2ef2e375, 0xe54f6134, 0xedeaff71, 0x64490d9e, 0xf53eaf87, 0xcf3c054c, - 0x0ef92fcc, 0x5e76ebc7, 0xe1c178a4, 0x10ca87f6, 0x5a4de5de, 0xdcf93e7e, - 0x8f4f1e67, 0xbce3127b, 0x7fc9a96f, 0xea79d9af, 0xde508d99, 0x26b979bb, - 0xe87fde90, 0xf795bf79, 0xbabe2d73, 0x75fe1c12, 0x89387abe, 0xf809a7f8, - 0xe7dff32a, 0x6bd59aab, 0xf3737e08, 0xc3e6c64b, 0x5da8cffe, 0x674fc849, - 0x744cddc6, 0x0814eaee, 0x571c8afe, 0xf3e6a7c6, 0xd12ae8fb, 0x48ec99b3, - 0x057f8e59, 0xf7c2239e, 0xd2cff68d, 0xaafe8ed1, 0xcf55c16d, 0x3d0eb07d, - 0xe99b8c22, 0x9e7d0ca8, 0x62a7b1af, 0xc8be715e, 0xe7d0e7ed, 0x712be7b7, - 0xc5b71e78, 0xa790109f, 0x458d84e2, 0x13fea346, 0x972061bc, 0x9eb76d9d, - 0x06ffa155, 0xc1c7e17e, 0x38fb2876, 0x695faf40, 0xab2ad7bf, 0x5f951e71, - 0x50f84eee, 0x3d00de64, 0xc617c93e, 0x0eeb01bc, 0xa6d02bf9, 0x049efba1, - 0x37880b92, 0x6bea87cc, 0xf584d71f, 0xc78e1ab3, 0x97e083be, 0x930cb8f1, - 0x3ce7fdf2, 0x0b3e7edb, 0x79e86ce5, 0x4f395fab, 0x7b68e1f4, 0xe740a2e8, - 0x9556799f, 0xbff3ed75, 0x167cf7b1, 0xdaacefe2, 0x57fe8f97, 0x8597c69f, - 0x957ea878, 0x157ff3cb, 0xc57b4a0e, 0x138f0d06, 0x23f2260a, 0x140ba50b, - 0xc63be807, 0xedd500e3, 0x0e9e48bb, 0x4c78f076, 0x145dd88d, 0xda8bf187, - 0xcf285d53, 0x5fb9e306, 0x28dbf306, 0xd65521cf, 0xa481aa83, 0x1ed72039, - 0xee07a219, 0xfe419e0f, 0x1e3ce0d5, 0x6561e507, 0x2bb43385, 0x433f21ce, - 0xe4aad97b, 0x67e748f5, 0x507323dc, 0xf59dbe3e, 0xdf8a6a8f, 0x926e1ebd, - 0x30958ec8, 0x4e0878c7, 0x4b70e743, 0x2987d13c, 0xb3387176, 0xd1abf405, - 0xbf24ef98, 0x9fbf38fa, 0xf381b9ab, 0xf3857b13, 0x1bed7393, 0xf980f89a, - 0x93f3257e, 0x7ace4f62, 0x97c41ffd, 0x9edae70f, 0x470cbe40, 0xc5f38859, - 0xb51e5247, 0x72871ef2, 0x90e8691f, 0x8962f8fd, 0x49b4d79e, 0x58e5ef0c, - 0x0af291bc, 0xca16d98a, 0x3cc59cb7, 0x8f5e7953, 0xf029d1ef, 0x52ebf67c, - 0x81a1e62e, 0xdbf74d3d, 0x34f66145, 0x15ead3cc, 0x1eae1905, 0x7d009ceb, - 0xf73e7ef6, 0x024aa757, 0x8481b1e9, 0x6653b270, 0xe29677ce, 0x5a7e957e, - 0x9833eb91, 0xe62cec87, 0x7bc2c81e, 0xc81de655, 0xa556fbc2, 0xc3d7bcdf, - 0x322f496b, 0xc05e758f, 0x79f3a73a, 0xbc0bf3bc, 0x5279071f, 0x16c3df23, - 0x436edf4a, 0x27456b7f, 0x15ec7fbf, 0x3cc03f93, 0x19c01733, 0xf01e7af1, - 0x63fd436a, 0xf21b3667, 0x6e91f8cf, 0x7d9a9fe4, 0xbd7cc302, 0x136d76ea, - 0xd5aa85c6, 0xe7a458be, 0x6bef6d8d, 0xf06b9e90, 0x8e3c765e, 0xdcbc7267, - 0x35bf7944, 0xf5efc626, 0x00ffaeda, 0x63ce76e3, 0x553a8b5c, 0x003c51ef, - 0x57ae36e5, 0xfe42dad5, 0xc97983bf, 0x073477ff, 0x3c60cdd3, 0xf287e78f, - 0x737ce9c9, 0xdccc7f10, 0x1e63f9ce, 0x681b73e6, 0x675fc538, 0x5d91c7c6, - 0xf1c71fe2, 0xafce9360, 0x3fa63b43, 0xfc7ca045, 0x5ad730fe, 0xe95c8fb4, - 0x7fe9aedc, 0xbd2b05ed, 0x5b73a3f7, 0x3cf98c7f, 0x733bddb2, 0x149556c3, - 0x1d999fb0, 0x1fd8de3c, 0x120fcac6, 0x21d7edde, 0x25b97c3e, 0xbe31f267, - 0x777819a3, 0x4483c60a, 0x3d0d1f1e, 0x6b8e5d87, 0xfdfc671c, 0xb3df6528, - 0x3cb91313, 0xa3a26e63, 0x5bbf392e, 0xc651d7c9, 0x504132df, 0x9fb8d1ee, - 0xfaae5824, 0xd7de1a5e, 0xde2b9e60, 0x3bf960d7, 0xef161f39, 0xa2feb06b, - 0xf78b0f9c, 0xf78ed835, 0x956f5835, 0xbef161f3, 0x5f78eb06, 0x722be583, - 0xdc71ec3e, 0x6df1e52a, 0xa2e90a7c, 0x946d790b, 0x1d1bdebf, 0xdc151f52, - 0x085a37bf, 0xa8128fae, 0xc6c269bf, 0x78ff30a7, 0xc52f9293, 0xc3b446cc, - 0xfbf9c22a, 0x7b06a91a, 0xf3f404ec, 0x45ed778b, 0x9bf81e7f, 0x882b9fde, - 0xef4a505e, 0x1968c497, 0x27dba3ca, 0x804f47d8, 0xcd8ec7f1, 0x724adb48, - 0xecf74f52, 0x31bb3fbd, 0x6f7ae292, 0x25824c49, 0xaee465a7, 0x9a7d42b5, - 0x85fa2041, 0x512a6ef9, 0x67984cfc, 0xab62c746, 0x1307cb8a, 0x9285cbda, - 0xb3ae0963, 0x8b9f4122, 0xd588f872, 0x51fb819e, 0x6a345de0, 0x45da1a59, - 0x07f36a5d, 0xbd759f18, 0x57e866a3, 0xa53c7129, 0x69d693df, 0x99bfb8f9, - 0x736ba919, 0x36607e70, 0x0d367794, 0xd9fdc66b, 0x9ea170c4, 0x855997e4, - 0x027f20f2, 0x66e99ba7, 0x357b1f6e, 0xfa345566, 0x62d361f5, 0x4bb75ef0, - 0x1931f3c6, 0x3c65c7cf, 0x81573de3, 0x6173df8a, 0x585cf789, 0x2da3e686, - 0x4db12fcf, 0x240f7820, 0xcdb3e605, 0x0097df92, 0xd4f7a10a, 0xf31c729c, - 0x34ee594b, 0xcadc95e6, 0x9e6879c7, 0x778e392a, 0x6f7c1d5e, 0x8ff38ca8, - 0xbdce5467, 0x166bcb89, 0xbf79e1a9, 0xe61731d7, 0x397dcf15, 0x7d50e281, - 0x06a5d16e, 0x5e05cfbc, 0x5ec67947, 0x8b2efee6, 0x77337ce7, 0xabf51c7f, - 0xcea9e397, 0x7c74eee8, 0xe64fa3af, 0xf07ea52f, 0xe4979e3b, 0x81ba81cc, - 0xf3a123de, 0xa776e739, 0x4fbd4147, 0x5f488bd0, 0xbcfe26ce, 0x673fe647, - 0x7c9f3c8a, 0x24f3a61e, 0x3bfa3e21, 0xf7c24e5f, 0xbc193710, 0xf7fcb94b, - 0x66dc93a6, 0x6fcc74de, 0x4e782f3a, 0xadf1be62, 0x98a5296d, 0xed5e7f6f, - 0xb3eb0679, 0x5d78d2db, 0x0a693968, 0x93d23e7c, 0xb7c8f984, 0x6296a5b6, - 0x91f9f23e, 0x5944cf2d, 0x97eaea02, 0xcd73e24e, 0x98a56983, 0xeb5b3c9f, - 0x7487563e, 0x5f4e7bf3, 0x4e077dfa, 0xdaaa7c23, 0x7d3efdb9, 0x2f0b81df, - 0x603e7ea1, 0x7582bca4, 0xdf099213, 0x6ecfedf5, 0x6beb7a46, 0x6c3f1351, - 0x99ff7e6a, 0x2d3f50df, 0x6b665985, 0xc90c563d, 0xba1db494, 0x3b35f71b, - 0xd625f3dc, 0x89bc4f17, 0x047b31f6, 0x13a5ebe7, 0x4f914a73, 0xfbec0efb, - 0xd9b3ea05, 0xe2d86091, 0x13d05e7e, 0x8ff72a7e, 0x40b8c02b, 0x0cbbb19f, - 0x9dfeafe7, 0xec1fe796, 0x718e9b8f, 0xc09cff82, 0x6e2a31f3, 0xfa8492d8, - 0xf9e57c56, 0xf8c1bfbd, 0x74f4efe6, 0xcd1353df, 0xa94abded, 0xe1397f31, - 0xcc5ed76f, 0x5e7be95b, 0x15aff74f, 0xe2b39318, 0x2963ac7b, 0x3feaff3e, - 0x78865eff, 0xee769428, 0x772ff6c5, 0x438445eb, 0x7916c68f, 0x8f61f233, - 0x0acefc9a, 0x3bd15eb9, 0xdc27ef82, 0x8bf84457, 0xfa8492d9, 0xafc472b6, - 0xcf7dc0ee, 0x833cb696, 0x567b0f7e, 0x670e774b, 0xc1b8079f, 0xd47bb3b8, - 0xfb034998, 0x5e90aa30, 0xca5b0bce, 0xf7f9c49e, 0xf5e77ef0, 0xae9e085b, - 0x5c33d73d, 0xd431fa0f, 0xad85e7c7, 0xf767ed41, 0x7e859b3c, 0xcddfb9e9, - 0xa154ff26, 0x2a5f8573, 0xf4836b77, 0x58824922, 0x3fca5b8c, 0x02198b93, - 0x0ee759e2, 0x927be8ee, 0x6b9fc7f9, 0x00357b56, 0x5b2d0aa3, 0x0acdf98b, - 0xde26543f, 0xabe78c5a, 0xd1d31b14, 0xf5c8a97e, 0x9c5f2195, 0x3c5d33d5, - 0xd65b7bf4, 0x6bad955b, 0x7c1da0e6, 0x45fcfda5, 0xc95f4796, 0x9b55f87c, - 0xdf781dde, 0xb5fe5a18, 0xa84f998e, 0xb585f5fc, 0x95e5b25a, 0x78d6def9, - 0x55afe81c, 0x71f97347, 0x8337fa12, 0xac93fb1c, 0x0aad16ef, 0x04eeffee, - 0xad594f9e, 0xfea3a5f1, 0x7b7fe653, 0x87db8982, 0xca3a5f2a, 0xb371d0ab, - 0xbcde5925, 0xa9bc9020, 0xd14e156c, 0xd20824fb, 0x2b3c3f58, 0xe6372e75, - 0x87870d13, 0x0f197cf8, 0x70f1e612, 0xd66caabe, 0x4f30f4db, 0x022f9855, - 0xd18725ed, 0x50768117, 0x6b122bdf, 0xa317d192, 0x5fe29fcc, 0x5653894f, - 0xfd36d478, 0x71c1eb70, 0x865e4fd0, 0x5628037f, 0x537ce44f, 0xeb4e16de, - 0x1f2f9331, 0x677cb6e9, 0xa73c38f0, 0xfb1f8029, 0x06c576da, 0xf70cebfa, - 0xa751f74d, 0xfffa6f88, 0x07bd31f9, 0xb5b2295e, 0x4e794f78, 0x4083efe0, - 0x3907de9d, 0x5677df27, 0x43086d7e, 0x95f739fa, 0x4fb8f883, 0x7b9c91f0, - 0x7246cdb1, 0x23ed4fac, 0x626bb739, 0xf947af11, 0xbd6e50ca, 0x24a7f138, - 0x7c12fa3f, 0xd29ef865, 0x2f8ea566, 0xd01d81cc, 0xe490b6d1, 0xe7896cc9, - 0x6a5db051, 0x71138f13, 0xe1932f78, 0xde86d8c4, 0xd443f23a, 0x3a97b466, - 0x42f72a27, 0x25f9ff1a, 0x31f53f3f, 0xe456bef3, 0xc50372cf, 0x6abec07d, - 0xc0ed097e, 0x8c16b105, 0x4dc287a7, 0x898c5fb9, 0xe22966fe, 0x7da31de9, - 0xbc3cc4ec, 0x9f91f4cf, 0xf64ed401, 0x5a6bf57c, 0xd5fb37f2, 0x7e517b03, - 0x71f68db9, 0x0e9e0113, 0x547af74d, 0xbed41771, 0x67ed342e, 0x1c91bd21, - 0x97d6f4e1, 0x07bf8bb9, 0x4e4fdf22, 0xfa00f192, 0x7d22358c, 0x87cf1c08, - 0x409ff6db, 0x9dd7d379, 0x943a724a, 0x3db6ce9f, 0xe3728116, 0xaeefd043, - 0x87c07880, 0x7ca59f8b, 0x0798f980, 0x6b3de502, 0xf837cf83, 0x2fc98fed, - 0xda039b64, 0x821b1e91, 0x4170a1eb, 0xf106f4ba, 0x7df68b81, 0xc01bf23f, - 0x777a6aa7, 0xa861c235, 0x52ea173e, 0x4850fd40, 0x2b3fa43d, 0xfdc3f6e1, - 0xebcd1813, 0x25eded18, 0xcf1f7e3f, 0xbd07adef, 0xe103f546, 0xee2d3f74, - 0xc315bd03, 0x8bea16f5, 0x8a6e88aa, 0xd01df55f, 0x83cabdd2, 0xe1259fed, - 0x291e81f9, 0xfed5534e, 0xf7fa2c72, 0x699826eb, 0xb18fd07e, 0xa0731794, - 0x11fd163d, 0x7a21dda5, 0x0cf7e5d2, 0x287e50b2, 0x9bc94eed, 0x42e5794e, - 0x5f3e1677, 0x8719cb27, 0xeb097508, 0x10e1ce8c, 0x76b3df38, 0x287ce489, - 0xf4c956de, 0x8b21f20a, 0xe15e39f2, 0x1e4503f1, 0xe572c854, 0x7267b610, - 0xf72937fe, 0x84cf7852, 0x9c8c3f7c, 0x23815af8, 0xcef8a5ab, 0xbccd13fd, - 0x79a78f2e, 0xe789fc79, 0x3e7abded, 0xc713252b, 0x45f79599, 0xd528f2fd, - 0x0e505f2f, 0x781c93c4, 0xe70b1d50, 0xb0467caa, 0x8a90c3d4, 0xd04535d2, - 0x2d532d9d, 0x1ab8a22f, 0x2e1ae7e6, 0x1d2857df, 0xf8e44e45, 0x1fb914ad, - 0xa057b95e, 0x6a73a5fb, 0xf2076f7e, 0x580fde86, 0x08a6b056, 0x18beeff9, - 0x5fd026a7, 0x4bfcd6be, 0xcbeb821b, 0xc514d76a, 0x95e7c30d, 0x8d76b6ab, - 0x57cf9764, 0x8a2c6f61, 0xaede5f35, 0x5e9cfbec, 0xf574e7d9, 0xcc7840c8, - 0x1234535f, 0x7fba65ca, 0xdcfc1e17, 0x5eb5dae7, 0x5d2d57ca, 0xb7c4f743, - 0x8a0daa5c, 0xbe6b5eb3, 0x7ba6e60a, 0x3fed2b90, 0xde0874b4, 0x312b8c5e, - 0xc43dafe0, 0x0137c067, 0xf4cbc5eb, 0x289f143a, 0xfd063c5f, 0x3c5f6653, - 0x113e3026, 0x339be25a, 0xb88ae522, 0x2c3e04a8, 0x0f030cb3, 0x89d1ffa5, - 0x3f1ace3c, 0xa8f1d391, 0x5e3b55d9, 0xe9d71462, 0xa57bf941, 0x22fe4cf7, - 0xbf07efef, 0x9c233267, 0x9bd4ebf7, 0xdfd3fe30, 0x87c50df9, 0xe619d7fb, - 0x03077bf3, 0x5de7804b, 0x029be3f1, 0x26abc0e3, 0xdc243b71, 0x9a9dedca, - 0xe3d5f50c, 0xa1c6994b, 0x1bd912f8, 0xdf74e199, 0x05f6d7d2, 0x8efeb7e9, - 0x8bde133c, 0x0dbb75f4, 0xff356fc8, 0xa8b17ffc, 0x3e3afb87, 0xbeb4bca5, - 0x7ca33f6f, 0xde728db5, 0x3936a1e0, 0x6cdbabdf, 0xe2fef6c4, 0xbf6117bf, - 0x8fe9724d, 0x98f8f02f, 0x83f12a52, 0x3bf9ff00, 0x4c7b53d4, 0x54c51f1b, - 0x2db0ca99, 0x7fc0bf24, 0xe1bd468e, 0xe3982b8f, 0x04c38b86, 0x54d215c6, - 0x2580ae3c, 0xd2d215c6, 0xeb015c78, 0x12c05718, 0x8ed80ae3, 0x63ac0571, - 0x18eb015c, 0xc63ac057, 0xb8c4b015, 0x297fb602, 0x0fd1e7bf, 0x3dc78b82, - 0x57f7240d, 0xc0337e62, 0xbf27656f, 0x47b95abf, 0x7c617ba2, 0xdff503cf, - 0xad3b7965, 0x678ede72, 0xd607dd2b, 0x882c901c, 0xc41f7c22, 0x3bf98e95, - 0x1e314703, 0x5822d354, 0x7db198d6, 0x6363ed3e, 0xa507de47, 0x6d47bed8, - 0x4f44cd11, 0x828d9f1c, 0xd57c8f5b, 0x57e287b1, 0x949d7105, 0x2cd35fef, - 0xcebb8c30, 0xd93f72d3, 0x0e6b4129, 0x1d92abdd, 0x9376d4ed, 0x9cf552ff, - 0xef7c0e60, 0x45e266bb, 0x7dca1392, 0x88fe52f5, 0xf37a3d39, 0x6b3d2092, - 0xf85779e3, 0x29c7ec27, 0x1d9377e7, 0x2d176012, 0x6c6c7bc5, 0xf7a5be97, - 0xe0e09c4d, 0x9dae108e, 0xd1d95577, 0xb5f31eb2, 0x55fe687e, 0xdef924e1, - 0x47bf9b3a, 0x92f8fc52, 0xbd60077d, 0xb25a2dc1, 0x609f6e53, 0x1e526dbf, - 0x28d819e6, 0x53b472ee, 0x27d67e4f, 0x8a0faf5b, 0xd74a14bb, 0x8563dc51, - 0x7dfd205a, 0x3b9f6ac4, 0x4672e809, 0x6f14bdf1, 0x246f1199, 0xf0e8563e, - 0x4fc96b49, 0xe315de70, 0x0a9877f9, 0x34e7ecb5, 0xa5cf9c9f, 0x5eb0a9e0, - 0x2cf7e370, 0xbd0b3316, 0xc008b03f, 0xe5517187, 0x188b1ffb, 0xe850afcf, - 0x8156c56a, 0xbcbe8ae8, 0x84bdf010, 0x103df845, 0x6af77fd0, 0x289bfdb9, - 0xc4f27bf2, 0xe28f3c4d, 0xfca7663e, 0x7d486591, 0xd7d7e912, 0x0f6ed07c, - 0xdb892ebf, 0x9c38e6f7, 0x3571f17f, 0xc61707e5, 0x276e9edd, 0xf9405f3d, - 0x6ef78213, 0xaf1bfbe9, 0xf3833f26, 0xb9aa8e27, 0x927801dc, 0xf485d59f, - 0x3b1ef14a, 0xcaebc795, 0xbf229ca9, 0x5efa161f, 0xcbe77f43, 0xb0be382d, - 0xf84160c6, 0xc03df15f, 0xffbfabb0, 0xebf394e6, 0x5c9ec512, 0x6be3c233, - 0x51e10583, 0xef49d718, 0xf3caa589, 0xb25b9c3f, 0x8b69f109, 0x1f5c2e60, - 0x00b669ef, 0x40f08b7c, 0x3dd1c602, 0x66cf7c36, 0x513053a0, 0x7265f53e, - 0xcc3aeb74, 0x1349a953, 0x2daf184c, 0x1852db0a, 0xa517f30b, 0x7677d324, - 0x1c78da6a, 0x4e4a0fb6, 0x92dc5307, 0x62aac7c0, 0xf1cf7e31, 0x3fb5cbe8, - 0xdfcf293d, 0xb3e65b3e, 0x782f8efe, 0xe3b5f11e, 0xfbe9bbb4, 0xef4f4c1c, - 0xf60fd3af, 0xd1c6fb35, 0xe855af14, 0xae39b068, 0x45a8e909, 0xa5a513d6, - 0x8ed1a9ef, 0x37b3cc68, 0x96ca1c23, 0x4b175c5c, 0x4e3e1ce7, 0x87dfe4a6, - 0xe502c9c6, 0xde46ffed, 0x5aba89fd, 0x5baddf2a, 0x9d776545, 0xe8079e8b, - 0xbf08238b, 0x7d6f101f, 0xf130d27b, 0x4733a656, 0xbe05be92, 0x90edf1e7, - 0xbbf02af8, 0x33efc018, 0xd9eea23a, 0x8348f680, 0xcdf782c6, 0xd2bcff98, - 0xfde1f240, 0x59c6c349, 0x2819f815, 0xf4c83b2e, 0xe9878839, 0x112aa919, - 0x926dff9e, 0x44e71410, 0x2273c1be, 0x7c8960df, 0xf9f952a3, 0xa30d69e6, - 0x7da194ef, 0x40fb22e0, 0xbf5df84f, 0xd40ae406, 0x20a665ef, 0x442172b9, - 0xf32380ae, 0xac5f7a33, 0x0936cb43, 0xe9cffcfe, 0x19ca5c50, 0xb878ce46, - 0xe61d199c, 0xb3be9e79, 0xf9461d50, 0x44efc0c5, 0xf2374767, 0xac25bdbc, - 0x461dd684, 0x3e7bd0de, 0x38188ef7, 0xbff414f9, 0xd90361f7, 0x9613eb39, - 0xe477ffe6, 0x71279fcd, 0xdf813c78, 0xed5d5073, 0x059b0e7b, 0xb15d8fbc, - 0xbe236590, 0xc439ef95, 0x7bf218c1, 0x39eff5ff, 0x123c988c, 0x0ae0e7bf, - 0xdc439efa, 0x30e7be15, 0x6171b26a, 0x461cf7e0, 0x30b11e4d, 0xc60e7bf8, - 0xb29df885, 0x39efc1ff, 0xbbce4fa4, 0x370e7bfc, 0xa0ff364e, 0x3d8039ef, - 0x4fe3899b, 0x63c6d8e4, 0x3b9f2899, 0xe3e5fdf4, 0x97643df2, 0xb2c52f68, - 0xa2a5c228, 0xc56dd176, 0x73d16df2, 0x5f03b63f, 0x1578444c, 0x037d963d, - 0x5125977e, 0xf2bca1eb, 0x49b6ad27, 0xb96bff38, 0x3cf8c9b6, 0x2f5fde34, - 0x73f60f9f, 0xcd0bf60b, 0xe2e8531f, 0x0e5cc9ae, 0xa9cb93cd, 0xc7bfc3f5, - 0xbf326f3f, 0xbed6be4f, 0xe077bf61, 0xd9feca7a, 0xdc56c596, 0x4ef7ec0f, - 0xb7ec27dc, 0x88664b04, 0xf80f7a0e, 0xc9757a72, 0x2e7462fb, 0x3fb38f90, - 0x9528f6e1, 0x14772ae9, 0x1ea30dda, 0x7ee14770, 0xe80e3547, 0xdf907df1, - 0x68f406ba, 0xf576fc3f, 0x7fdb1e80, 0xdaf9e36b, 0x9f6ff3a1, 0xf491fdcc, - 0x7e3403a9, 0x4dddfc0c, 0x1440c1fe, 0xe5e96dda, 0x14ae3447, 0xf66d4f7a, - 0x93764127, 0x8c7bf899, 0x01e636dc, 0x8c3d2191, 0x1e78c1d9, 0xe90c4163, - 0xef1d4ab9, 0xfdc0f95a, 0x38d1d222, 0x803bec37, 0xaedfaefe, 0xaf7e0c1a, - 0xaae34bd7, 0x5ec025e4, 0x64ee7a0b, 0x9474bf3c, 0x5ed08f2c, 0x39d9efc4, - 0x77d08fcb, 0x0b8ec0a6, 0x79be8f99, 0x594f9430, 0xe6bfb3ad, 0x62be5333, - 0x77a5bf50, 0xfa3d66ff, 0x5ba5e5b5, 0x2f17e435, 0xa58f5969, 0x269ef1c3, - 0x197d918e, 0xcbec1fd4, 0xfb65faa0, 0xf547d90c, 0xc7d717fd, 0xd02eb30d, - 0x13a456c1, 0xaa8e0e85, 0x4fd0e33d, 0xb30cea3d, 0x3c1df7f0, 0x269a5df4, - 0x5df4bdf9, 0xcadd39ff, 0x5d3965f3, 0x3f1df8c0, 0xa9ea8e8c, 0xaf1df2bf, - 0x1c8a956b, 0x8dcefa1c, 0x5e28b986, 0x7248cb39, 0xfff646ae, 0xc89897aa, - 0xbaf8511e, 0xb539e55a, 0x18c5fb1e, 0x8a9bfe79, 0x7aabf7d1, 0xcf9451c4, - 0xcfac3f4d, 0xacfba54a, 0x178f7ad8, 0x5db81de7, 0x15b9efa0, 0x5ab97384, - 0x9e389628, 0x4447e785, 0xa7815dfe, 0x98487e51, 0x37bfc147, 0xbf972530, - 0xf8cf103f, 0xca98db77, 0x369df21c, 0xed7a1e39, 0xeff1b4ef, 0xf7e7cd92, - 0x25510d72, 0xf9f1cba5, 0xf9e81b82, 0x1f52efc1, 0x2afee2b1, 0x71b4ef94, - 0x4e61bf7b, 0x557f3d06, 0x3d41af30, 0x5d807ae1, 0x7a6d3be9, 0xef80fbe4, - 0xf887bdb3, 0xd9f7d6ba, 0x1c0fef94, 0x23c3705d, 0xbd1c397b, 0x3355ef78, - 0xafe418cb, 0x3c3117ff, 0x56c0d29e, 0x000056c0 -}; - -static const u32 tsem_int_table_data_e1h[] = { - 0x00088b1f, 0x00000000, 0x51fbff00, 0x03f0c0cf, 0x3370278a, 0x45e39c30, - 0x8381e9f0, 0x5fd32918, 0x50c0cec6, 0x4055c401, 0x3f880bbc, 0x7c3032b1, - 0xff5e2566, 0xdb042935, 0x21818248, 0x88d7881e, 0x49a83031, 0xa41dc422, - 0x03261819, 0xb150a1f9, 0x5f3a4047, 0x0f77328a, 0x80a69c16, 0x872ae629, - 0x9163a760, 0x6819c647, 0x50e54bf2, 0xf40499f9, 0xa2be340f, 0xa2ffca8e, - 0xa013a10a, 0xe4d157e2, 0x3be542bf, 0xa6bafea0, 0x4edcdd8e, 0xc35dfd32, - 0xfc01a102, 0x9847b099, 0x009847b0 -}; - -static const u32 tsem_pram_data_e1h[] = { - 0x00088b1f, 0x00000000, 0x7dedff00, 0xd554780b, 0x733ef0b5, 0x7993331e, - 0x31e424e4, 0x1e4e1081, 0x03086820, 0xb78a8884, 0xf6301027, 0xd57876d2, - 0xaf0e2d58, 0x6b86f210, 0x7fb6bd2d, 0x78490806, 0x111fc1a8, 0x29e1d5ad, - 0x311d82f6, 0x0388b622, 0xbdabd228, 0x557c5837, 0x0bd11feb, 0x2a44908a, - 0xe5b5ef6a, 0x3ef6b5ee, 0x09939cc9, 0xafdb7b04, 0x7cfdffff, 0xc7ecee9f, - 0xf5ed7bd9, 0xfdad6bda, 0x8131c918, 0xe4230da4, 0x06fbfc22, 0x109d9221, - 0x9d37a132, 0xd72120e3, 0x66924218, 0x92ddfd2f, 0xbadc4214, 0xa349bfe2, - 0xe4febba9, 0x5f5f9a1a, 0xa4aff0ec, 0x4d1f5b4d, 0x2d096a78, 0x2fa1efbf, - 0x7cd04fc3, 0xad79ecfa, 0xce7eb4c5, 0x5d0fc924, 0x10ab1a1d, 0xd8e7ed02, - 0x520176c2, 0x9097e581, 0x927fa130, 0x45f8e8af, 0x9fe8b884, 0x37fe9724, - 0xa5b21c89, 0xd1e43e60, 0x99029ea0, 0x31364846, 0x7e6055fe, 0xf509fc36, - 0xd0677744, 0x779e75ef, 0x7fec13e5, 0xdb0a5f8e, 0xf27347e9, 0x4dc87203, - 0x6d08c6d3, 0xfb1dc749, 0xf908395d, 0xe4990cc0, 0xd8b68763, 0x0fca6ffe, - 0xd214754c, 0x080b67fe, 0x49d9f9ff, 0xcc82da36, 0x3be1eda6, 0x1a1f4e22, - 0xd99f67cc, 0xe0dfb8e8, 0x40dfdddf, 0x5fc0a7ff, 0xe5a1094b, 0x9e0c1ccb, - 0xc5d9d9e4, 0x1989ce30, 0xbf4316d7, 0x3213a673, 0x9d4d5688, 0x4490f63d, - 0x891aebf3, 0xcddb4edf, 0xcf1c0d29, 0xcbf8d981, 0xe80293a7, 0x60ee8e97, - 0xffc45f7d, 0x64ef38eb, 0xcc3fde3e, 0xfa102b1e, 0x8a97f641, 0xa0725da9, - 0x4bd153f9, 0x2d056a48, 0xee53191f, 0xd09a769f, 0xe6e9e4f2, 0x721340f6, - 0xc425211d, 0x1aea7293, 0xc91677fa, 0xad4228ba, 0xee8c0b6a, 0x4a6b0fe5, - 0x22f9fdff, 0x12fa01d0, 0x6a1fd6fb, 0xa0e9e99c, 0x7b375af8, 0xf4d08796, - 0x0f2cc0f5, 0xd9f5efe0, 0xd68f10b3, 0x676673f6, 0xfb5e0227, 0x06feef1b, - 0xfa08d03a, 0xb5b3c73d, 0xea48907e, 0x39fbf423, 0x31c3d13a, 0x9301dffd, - 0x0964254d, 0xb34d1b30, 0xd2a6d525, 0xe88d6cfa, 0x95e33891, 0x3b69b102, - 0x28994992, 0x0ff352e3, 0x2637bb61, 0x71c34ad9, 0xef0773e6, 0xb81a55c7, - 0x6fa50e67, 0x751274d6, 0x2912ba51, 0x75e2c6aa, 0x1a548a5d, 0xddc7038e, - 0x68425e1c, 0xe1c0cf7b, 0x02d86571, 0x47329fd0, 0xf5c2c40c, 0x42678003, - 0x4ca24a6f, 0x18f8e6ee, 0xfbbf72fd, 0x338f506c, 0x8e00bb8f, 0xecaa9009, - 0x0c8f0e3b, 0xb201937c, 0x43fc8296, 0xe02463c2, 0xb91eccfb, 0xe5070124, - 0x17f0a18f, 0xa42dae15, 0x1412d47b, 0x47ec56b2, 0x0324a4f4, 0xde1157bd, - 0x4f51290f, 0x42157e51, 0xd78b84ab, 0x129e6a5c, 0x35f06539, 0x193ba9f0, - 0x5e1cbfc7, 0xe518a048, 0x88d43152, 0xe307c078, 0xed4df92b, 0xbacba502, - 0x947ee5d1, 0x90218a6f, 0xe17e4333, 0x3bf457df, 0xbdccff37, 0xca91d29c, - 0xd3396b91, 0x2cdf8a8f, 0x8e92eb67, 0xc82008b5, 0x0f49b964, 0x40241210, - 0xeb6f0377, 0xbc78a2be, 0xfb5bbf04, 0xe7c86fdd, 0xc9983260, 0x053f9327, - 0x79bd07fa, 0xf0077ed3, 0x5edf3af5, 0x5d6bcc07, 0x7a825efe, 0xe8c7d38a, - 0x5daf95d7, 0x81d6ce52, 0xee808d7c, 0x9ea748c3, 0xc6a7d1f2, 0xa6767e02, - 0x748bf72a, 0x08933b7e, 0x6b75d9ea, 0xd02b7848, 0xb5e594b5, 0xb5e1696f, - 0x9d3b8e74, 0xd698bebc, 0xed06bcd3, 0x3adbbea9, 0x68870b49, 0x8d8b6b7e, - 0x85ab1fb5, 0x311f9a45, 0x8a148491, 0xc2c56d4f, 0xbe5a4e95, 0x17eaa375, - 0x34fd5eb5, 0x2d6725a2, 0xdeb2dfb4, 0xbdf00aa6, 0x3b23ad8f, 0x443849f3, - 0x39b1dfc7, 0x69239bf9, 0xf9b2143e, 0xf24fd387, 0xd945faf8, 0x022844a5, - 0x9c3a31b4, 0xae5c7921, 0xa9e50204, 0x7ecb7cbc, 0xa48ebfff, 0x5d363df0, - 0x45a0aff2, 0x4ccfd63b, 0x769e28d0, 0x3f048168, 0xc0f07f4d, 0xccefcc7c, - 0xdd00260c, 0x9f9c6e76, 0xc0f14c00, 0x461b99e6, 0xd2617b41, 0x6ce91d61, - 0x1f47ffd6, 0x00ec3a28, 0x9e994b38, 0x7e0d6a4f, 0xbcf9a253, 0x89b91249, - 0xadcf214e, 0x1fdbdc21, 0x4f5811b2, 0x8b6de8fb, 0xcdd44ebe, 0xb4eb5779, - 0x5d7f818f, 0x2009160f, 0x86353bda, 0x923741e7, 0xbeec8af0, 0xc85cefe3, - 0x5d2913ea, 0xbf2e0e80, 0x96675962, 0x4756f85a, 0x3c717079, 0x1c755ab9, - 0x897a488f, 0x578bd690, 0x62469ffa, 0xf07ae9f0, 0xe9f58128, 0x8163e78a, - 0x7ca05d27, 0x9cab830f, 0x1c1eb9ef, 0x6357caf7, 0x21b1f1e3, 0x7fa01eef, - 0x6177c522, 0x50eb0424, 0x0a24617a, 0x57c9e2fc, 0x9a0bb034, 0xc5c93109, - 0x7cfbd1a1, 0x1337201d, 0xaf583e22, 0x837e8dd7, 0x81568fc9, 0x6fe630f8, - 0xb7e4f7b4, 0xc1fb5893, 0xf87287a8, 0x697853ce, 0xcb87bb39, 0x847f4f59, - 0x732447ad, 0x4f75c21c, 0x5e7561e1, 0xc84c7d1c, 0x97cb940a, 0x817ae049, - 0xedcddea6, 0x6c06a751, 0x7900dfae, 0x910240b7, 0x134ddf38, 0x42d27ad8, - 0xe9a05d74, 0x162f44a3, 0x664b9d70, 0x2eb2d7fa, 0xbc9fd1f5, 0x16e9165d, - 0xd468df40, 0x8734803e, 0x23cd31f8, 0x92474c01, 0x26af4c56, 0x49f34c11, - 0xa405a63b, 0xaf43531b, 0x422a89f8, 0xfac4c47e, 0xa4e720c9, 0xe58b63da, - 0x3264d0bb, 0x3cce3eb2, 0x73782d9a, 0xf8ebf890, 0xe75f021d, 0xfc8aa648, - 0xf17af843, 0xe818b06e, 0xfc2854c5, 0xefccdbbb, 0x0ebe24e2, 0x693dea38, - 0xdd335780, 0xcd54548d, 0xf06d5a7c, 0x1c2444a9, 0xc41f32c7, 0xd6b8cc63, - 0xfb7356fe, 0x9c9f98c6, 0x491f23a2, 0x50cf666e, 0x71bdf438, 0x0828d1f0, - 0xab419e7c, 0x29b23adc, 0xb6494bbf, 0x6b9a5ac8, 0xe8764f74, 0x893f2f38, - 0x7ceb6747, 0xbe2af0ac, 0xa9b3c181, 0xcb0a9e07, 0xc297fa3a, 0xfea64ff3, - 0x1db24ca4, 0x86a20bd6, 0xbc56de70, 0x42def9f6, 0xd2e4fe8f, 0x57d66991, - 0x02d78a4a, 0x069f8587, 0xe37c7f68, 0xe47fea4b, 0x211bfac3, 0xa9ec2a41, - 0xe60101f9, 0x1a40ad7f, 0xc85e2913, 0xa0eda268, 0x6af5cd70, 0x698b8ecc, - 0x91f41937, 0x74c90b66, 0xee92cfbe, 0xe43ed023, 0xf41d9127, 0x6df367b3, - 0x7d695ba5, 0x63b69faa, 0x1e4005fd, 0x0b6d1dae, 0x9fd1b940, 0xf5329e4e, - 0x112efd47, 0xe836e1f0, 0xe4c3f163, 0x1fb436b1, 0x6fa27c95, 0xc75f2389, - 0x1d157cb9, 0x9eb0ea71, 0xb094cab8, 0x8ffa1b33, 0xb53e4314, 0x5d61f89a, - 0xe6cdd49f, 0x30e1c651, 0x59fa9de6, 0x6a7e0040, 0xc03b31f7, 0x3fd04855, - 0x74da3254, 0xb4dd1ff0, 0x7e42f50e, 0x50531754, 0xd83fa23f, 0x5f3d9e1f, - 0xd00bed3d, 0xb9d47d7e, 0x92be076a, 0x9fa0e9fc, 0xc8568f57, 0xf8bdfa60, - 0xfff63b3b, 0x1862a7b9, 0x47cf9989, 0x0bb1d10d, 0xa670c1a9, 0x67a618e1, - 0xed31da1b, 0xd30b786c, 0x594ae9fe, 0xebceda8e, 0xc0d7e27e, 0x3f0f101e, - 0xc00f3447, 0x5c75d51d, 0x12a21c17, 0x82802eb3, 0xd36fff06, 0xdaf0bcd8, - 0x086bc46c, 0x67d54de6, 0xe0367878, 0x9e000a5b, 0xc2223887, 0x77867cd2, - 0x01d03fc0, 0x3c8e8bca, 0x5cf102b7, 0x9e02c64d, 0x0ca4c937, 0x13e03cf4, - 0x827d89d6, 0x03800eed, 0xfe69f3f2, 0xc1fa8ffa, 0xf78659fb, 0x9e29978c, - 0x4b494e00, 0x8eadc664, 0x913b95f2, 0x27d7120b, 0xf9927abd, 0xbdf6bdd9, - 0xcf00eff6, 0xac894696, 0x68a6bc85, 0xf7b7114a, 0x15824a41, 0xdcdfc1d3, - 0x28fd3e56, 0xe2b90bd8, 0x5a648757, 0x3a5eb43e, 0x4f2311d9, 0xfd746559, - 0xb0c276a4, 0xecf2e6e5, 0x074f3990, 0xb7347f40, 0xc43e5cc5, 0x87aef5c6, - 0xad1e4078, 0xe8b65af3, 0xd3fd7157, 0xea240d55, 0x02f26396, 0x1791a7c3, - 0x423b13bc, 0x46cb7e74, 0x4c038c11, 0xb3f5b1b7, 0x7ca3be15, 0xd74f2f71, - 0x5231fa5b, 0x46dba269, 0x193d30c6, 0xddba7d6f, 0x46ce3c56, 0x4db06bfb, - 0x72a3671e, 0x042292e4, 0x5b9777ec, 0x93f9e3d1, 0x8e126dd3, 0xebb5209f, - 0xfbab8522, 0x4adfe23a, 0xee4cbef1, 0x2c7c828e, 0x21fcd62b, 0x30fe4750, - 0xd51263ca, 0x15f66261, 0x700253c1, 0x6c4a7850, 0xfb044e38, 0x0738a6e9, - 0xcc997dfb, 0x4a365dfa, 0xf6376823, 0x3655e703, 0xd80ce119, 0x34fd0904, - 0x1555974e, 0xa34df739, 0x9f554ed9, 0x2667fd05, 0x78c16705, 0x7e6fb946, - 0x1963fa29, 0x2bf4ccc3, 0x0167d477, 0x2206547f, 0x4e7f80d3, 0x926c5f7b, - 0x36b7bce9, 0xf144bf10, 0x702b9eff, 0x7357f41b, 0xb008fd7b, 0x5e06df7f, - 0x3b2a0098, 0xa5ac7a80, 0xa25fa564, 0x148972e5, 0xca3f2995, 0x25bf0f13, - 0x2a1a4017, 0x938b3886, 0x477d33d4, 0x35224bf5, 0xf5231cbd, 0xa27e218f, - 0x72d03c80, 0x60256f55, 0xdba8380f, 0xef863270, 0x1e734c94, 0x7cd8fa6c, - 0x72e37a7f, 0x27e79829, 0x09fe0387, 0x49dde9da, 0x26927fcc, 0xde000bfa, - 0xa6ffaf7b, 0xc4fcf006, 0x67f93366, 0x5a4d7f56, 0x79696ffe, 0xfee26810, - 0xd5fcb4b6, 0x80f1bcb4, 0x979c5697, 0x9432ca63, 0x24f0050b, 0xbf07f932, - 0xe41d67be, 0xcf5bf878, 0x572f58db, 0xf835bc37, 0xa720e1c3, 0xa43f831d, - 0x052d59c4, 0x3e42ff91, 0x1c28b5f0, 0x098f9992, 0x62134f78, 0x18176e52, - 0x5a9c9bf6, 0xdc947488, 0x988ea9d2, 0x8fc0ddf5, 0xc1ddfcb2, 0xf4878e1f, - 0x78ad4c6d, 0x0120a455, 0xd768d03f, 0xe018b713, 0xe234effa, 0x1fc479a9, - 0xa47338a5, 0x7a6a78b0, 0xf30a285e, 0x09fd5272, 0x233dd3eb, 0xf0c56b5f, - 0x3b0fc581, 0x3f20ad94, 0x61b68cb4, 0x7865b35c, 0xf90290e4, 0xd1406a0c, - 0x5dca677a, 0x4c6d8821, 0xe37c63cd, 0xd4f5b3f4, 0x7e8c3c35, 0xbdbfa198, - 0xad5e1f1c, 0x67b3f51c, 0x31ded9a2, 0x2b2701d6, 0xdb36f4a2, 0xa694ce51, - 0xbe82c54f, 0x9b539a7e, 0x69e51a76, 0x233fb9a4, 0xe36ed1de, 0xc96b8bf1, - 0x593768b5, 0xe1fd12e2, 0x71f86bcd, 0xdcbcd913, 0xfc1849d3, 0x5189f4e6, - 0xcfd79bc4, 0x9bd866f0, 0x9bbf3e1e, 0xfc04234a, 0xf3f89ebe, 0xeb6f0ccd, - 0x7fa28baf, 0x29ec7eb7, 0x85bd67b4, 0xce3f261d, 0xa1ca1ef8, 0x76c4fcfe, - 0x18f6a1a8, 0x23711bcb, 0x19e9a78a, 0x61ebbd69, 0xaddbb72b, 0x92275374, - 0x4763d062, 0x8315a747, 0x84b7bede, 0x3cab4ec2, 0x6297587a, 0x7ef2adf0, - 0xdf867cd4, 0x7cd8cb7b, 0xd3f47b69, 0x93989def, 0xf266e304, 0x7f11b0f8, - 0xebcbf1ee, 0x284f78cd, 0x2d85c4b4, 0x67eab77e, 0xcc4b52f4, 0x5f39abe5, - 0x57a7222b, 0xe8ce192a, 0x4f3e3035, 0x84bcf832, 0xdf3279f1, 0xd12f4837, - 0x921d010e, 0x4dff994a, 0x4df37e2c, 0x5e8c1d29, 0x00c88f37, 0xa9fefc3f, - 0x97663edd, 0x7126ba30, 0xc6efbc7e, 0x71c80211, 0x40268972, 0xc33e727d, - 0x13c53253, 0xa5c977ac, 0x4ef6efcc, 0x525db0d4, 0x0b5ba309, 0x5fe14c7c, - 0x898a7403, 0x5b4b3b1f, 0x6b7fa075, 0x741d4ef1, 0xe1c53259, 0xd4cf0a20, - 0xd81b0a52, 0x805fb49d, 0xc51853d7, 0x49525ab8, 0xfca5d870, 0x82a2427a, - 0x10f887cd, 0xe94b686c, 0x7e58253c, 0x20b26268, 0xa7ef7ed0, 0x80f1c07c, - 0x8f173c71, 0x785fdfa3, 0xfddcf512, 0xc8364df0, 0x1cebf6a9, 0x36a5279a, - 0xf707f83f, 0xf108e697, 0xbcc6e7e2, 0x2acb83fb, 0x35f812c7, 0x9572fc31, - 0x16dee3c8, 0x22475dfe, 0x57c82e6a, 0xa5f76f48, 0x830feaf5, 0x65e47aff, - 0xfecbe312, 0x87a189f4, 0xb21824dd, 0x1fd5f765, 0xdef8ce92, 0x7940179e, - 0x24ef03eb, 0x8a52afc6, 0x9136fcb9, 0x5e867fdb, 0x140792d1, 0x00a12727, - 0xd72277ae, 0x02da4f4f, 0xf054c50b, 0x4eb8c3bb, 0xae74c8b8, 0xca9f1937, - 0xe6a6ff9c, 0x4ae2bd33, 0x9776b089, 0x903aa78d, 0xa834d6df, 0xc65a1fa8, - 0x439ed5de, 0x7866b0f1, 0x73be1f93, 0xb9196b8c, 0x3cdbf68d, 0x2b70797c, - 0x30fdc00c, 0xac22bfd4, 0x8d5f8c83, 0x0e03307d, 0x61d21992, 0x7e09cc9f, - 0x2467e011, 0x24905fdb, 0xeb8fb512, 0x4795df1d, 0x6967cde1, 0x0dc19f28, - 0xb6ebc9fe, 0x6f9c2ae0, 0xa2946b7e, 0xc99bce9b, 0x42216acb, 0xebcc225c, - 0xb21e7c72, 0x9f8ebe31, 0x025df7f6, 0xe1c4d3ec, 0xdb22dddf, 0x472d59a7, - 0x7e085088, 0xf289ed1b, 0x6a6ceac9, 0xa381c797, 0xd56bf391, 0xc3f8672e, - 0x89ab7e18, 0x75f29924, 0x1fc233fb, 0x7711fac6, 0x514fb80a, 0x4358d1cd, - 0xcf00b23a, 0xf61a29ef, 0x48eb6b57, 0xe9177c83, 0x78025b4e, 0x8b8f0310, - 0x5277fd74, 0x90b8c4be, 0xd6eb607b, 0x81a7f0e5, 0x4085d10c, 0x0fa9e4cb, - 0x178e9879, 0x69e307dc, 0xd2bf2b2a, 0xf5f0e371, 0x4d7cb10b, 0x6a5957c4, - 0x147f6be5, 0x129ddaf9, 0x9fb77ac5, 0x8fc1b5f1, 0xad1f9c89, 0xbf8c687c, - 0xd6afc79e, 0x335f3e72, 0x708549a1, 0x9b51dadf, 0x2ce69e30, 0x7c015cda, - 0x25aa32de, 0x64de7c0c, 0x17df35f0, 0xdb2efea1, 0xa35ad31f, 0x72264eb0, - 0xeed456be, 0xeb7b9006, 0x38935d7c, 0xbe0534bc, 0x5f39b806, 0x93f807bf, - 0xae08ddfd, 0x076bd7c1, 0x45bad7cc, 0xfed39b6f, 0xc2d927fc, 0xf1891ed7, - 0xd7c067e7, 0xb30a4f00, 0x963edc63, 0xdfea7eca, 0x06e7e9c7, 0x6b99f989, - 0xe5ac1cb9, 0x1fb6b072, 0x223ff839, 0x9afe03f3, 0xc98b3072, 0xe5a24381, - 0x8cae9389, 0xd3b0251f, 0x9e7bc8e3, 0xe1b5fc24, 0xbc4334de, 0x27fe3c72, - 0xbe84cd30, 0xcfd234f4, 0xe4c0e744, 0x73c98f3b, 0x76be727f, 0xfe387c68, - 0xa7f46453, 0x26922ef8, 0xffbe395c, 0x7215705a, 0x43f0367e, 0xb728c582, - 0x3a667a31, 0x86a92bc0, 0xd304799e, 0x28ad79a9, 0x81be86a7, 0x2bfa0a58, - 0x3bc62b6a, 0x68ad999c, 0x98f3399f, 0x24fc31be, 0xb88d7ceb, 0x33d71378, - 0x02217949, 0x853d9feb, 0x9eaa3f70, 0xcc9951f9, 0xd5e2301f, 0x18a8fd86, - 0xbbd0d47e, 0x79a79f70, 0x97da3d78, 0x3bd637cd, 0x36c3ede2, 0xf077eefb, - 0x3ed35f4d, 0x0e5a1aeb, 0xbbc9aefd, 0xc3b3c49f, 0xfb18798c, 0x6e3e4e46, - 0xa8b51e73, 0x32df5c60, 0xc76adefc, 0xfeb26734, 0x7ae7be7a, 0xbbd1ee57, - 0x54768f2c, 0x6f9f8c6e, 0x03e0c7e9, 0xa343e885, 0xe4183710, 0x4ce7091e, - 0x3f04849a, 0x924dc7d8, 0x90729d20, 0x5aa97b1e, 0xff401689, 0x9cbc6627, - 0x3db2f685, 0xbce406b8, 0x0380abe9, 0x53aba9e2, 0x96c6f35e, 0xe6f19d9f, - 0xa56cc1b7, 0x7ee2d5df, 0xb148838e, 0xdc2763fb, 0x4b7ed1db, 0xe9c737c8, - 0x09ae149c, 0xcc13c402, 0xbf8f0ae5, 0x72e69928, 0xa45fc799, 0xe7394b14, - 0xbe34b90f, 0xeb93795e, 0x7602df15, 0x1cc4e74e, 0x713bd716, 0x30674f2b, - 0xdbc73efe, 0xc234f375, 0x535feef5, 0xf6e5251f, 0xe29befc2, 0x9922f8c7, - 0x3ebb4765, 0x2b9d852b, 0x26e7b120, 0xa26b5fe0, 0xccfc6244, 0xff9781a1, - 0x61d4f108, 0x06cabe0b, 0xea156b3c, 0xdb465861, 0xc79c6ca5, 0x28f74263, - 0x3ae6cf18, 0x02f5fb8b, 0x6a72e345, 0xdbf40b12, 0xef8521db, 0x3a52c0bd, - 0x91057b8f, 0x37c0ecbf, 0x8c29d022, 0xb1448ba9, 0x303a43de, 0xe61b089f, - 0x5187e0b9, 0x33c44bbf, 0xc61b614c, 0xf6cc7e8d, 0x7888d643, 0x03a8836e, - 0xedc9bfb4, 0x4297f82a, 0x1ae77e88, 0x40be77f8, 0xc4c8316b, 0xc608b2e0, - 0x7cedad93, 0xa039d853, 0xaffb7a3e, 0x5237df4f, 0x548f8173, 0x1ce8372c, - 0x694ef514, 0x5ff2df42, 0x12f38189, 0xdc58abc6, 0x2a5f5acd, 0xde4017e9, - 0x0bc2e5ac, 0x7e053a7f, 0x6467aaf4, 0x3ca7a3f4, 0x41bf4723, 0x045b35f3, - 0x076d53f4, 0x770fe89d, 0x51f2c23e, 0xfb43a28f, 0x8c05db73, 0xdbd9d507, - 0xe201bdef, 0x0488cf8a, 0x19708dfd, 0xe29d8bee, 0x59fb2673, 0x80079cbe, - 0x9a1cb66a, 0xec57df0b, 0x77d813b7, 0xf16e79a8, 0xf9a06fb7, 0xf464c7c5, - 0xac766a51, 0x657f6050, 0x40885849, 0xc1326bbe, 0xc4fb43f1, 0xbeda0ef0, - 0x369edbcb, 0x2bfb0dc7, 0x455da20e, 0xa7b4f6e1, 0xa9f4a6cd, 0x0d353f0c, - 0x2ddcabbe, 0x98ffc1f8, 0xa38eccf2, 0x9abbf419, 0xa73c0427, 0x45cbb550, - 0x9cba18b4, 0xdfa3136a, 0x9d33f880, 0x8bc5f827, 0xc034eb49, 0x0d8ecd7b, - 0xb713168a, 0x9230d33c, 0x7cdef668, 0x1c7413cd, 0x93ed5dfa, 0x58a61f82, - 0xe041236b, 0x9ce7ce8f, 0x30dcdb65, 0x08ca15bf, 0x59abcc0f, 0xc38b7681, - 0x7ec1f6f3, 0x8b78657a, 0x57d68d32, 0x2945b23e, 0xaaa7e18f, 0x2d10d75d, - 0x6d4e3f86, 0xd4bf4dce, 0xae867b7a, 0x54f0b15b, 0x88b7a612, 0xc4665614, - 0xc8767bec, 0x453f9c49, 0xdf06ff53, 0x18275e87, 0xef3d0ac7, 0x741abc41, - 0xbd32a65b, 0xbcedd060, 0x7528e9ca, 0xb388cd17, 0xd02f7aaf, 0x2af10ec1, - 0x1bfbd315, 0x6c6e987c, 0x9b3e90d0, 0xe1577f00, 0x7b9606be, 0x88629127, - 0xa275788b, 0x3c9f52c2, 0x21962f5d, 0xf960124e, 0x8283dbb4, 0x1bf98976, - 0x383926e9, 0xb75c820f, 0x964c4fc9, 0x49bebae8, 0x7e252e09, 0x77b4be3a, - 0x6075c972, 0xc8e705a7, 0x1d9fb0a9, 0xe8f160ac, 0xa2e40f88, 0x7ccbef89, - 0xd6f2664b, 0x7c60a194, 0x8bf7d364, 0x41eda1b6, 0x7d365e18, 0xec277cbf, - 0xe67ed1ab, 0x1aae54ca, 0xee4fda65, 0x9b49fbe5, 0x4fd4d13b, 0xa30adcda, - 0x8fd8c59f, 0x6cfd6073, 0x19bd7b9a, 0x4695b99e, 0x8fd8f53f, 0x4af36067, - 0x199263bb, 0xb1aa3b9e, 0xfddbf49f, 0x06881f68, 0xdc7690ff, 0x4eef7517, - 0xc496b71a, 0x1fe4d1f2, 0x2a1e78c3, 0x947cb155, 0x24c13138, 0xb27a494f, - 0x74a83f29, 0x6a7da9b0, 0x9f54c720, 0x85b5765e, 0xbfa8dd2f, 0x8a814f31, - 0xab38b126, 0xbd415832, 0x81d83c53, 0xbb06bbf9, 0x75dcef51, 0xb02af07d, - 0xd05600f7, 0xc12977f3, 0xbe1c6a31, 0x0812f3a1, 0x1b34cfc6, 0x32ec7da4, - 0x7939efbe, 0xde2357c8, 0xd9d7dfa7, 0xd12447ba, 0xf14a43fc, 0xadef3023, - 0x8de3b332, 0x9d824338, 0xce6bfea0, 0x8a16da2e, 0x50cb6bc1, 0x6f422fca, - 0xd0722dbf, 0x73b8fc07, 0x4a576ff5, 0xa1a6be14, 0x7a6e1e0a, 0xe1edfe5c, - 0x9b99b510, 0x00fb9687, 0xea8576ff, 0x15f1d88f, 0x8e3e7e3a, 0xdfc61bbf, - 0xd93b332b, 0x673dbe3a, 0x477c69a2, 0x7c698556, 0xa7c74287, 0xf56fb1f2, - 0x8a7c7c3b, 0x7909ebbf, 0xc7077e56, 0xe05567b7, 0xa90acdf8, 0xd09f8d30, - 0x9001fe33, 0xcdfdc39f, 0xf37ae73f, 0xcd2ab3fc, 0xfcd857f3, 0x80feae8f, - 0xf3809f8f, 0x80fe597f, 0x92ab3fcd, 0xfacedfcd, 0xdbdf19ed, 0x6157ff83, - 0x37f5affe, 0xe649dcff, 0x36ab0ff9, 0xc6cedfcf, 0x27f5637f, 0x8e377c7c, - 0x09fca6ff, 0x6ab0ff9b, 0x07b15f1c, 0xca47c0fd, 0xf07a8490, 0xa461a99f, - 0xa35d4061, 0x923a40e3, 0xc837a9c5, 0x5dc70839, 0x3eef8c09, 0xe6fca04f, - 0x24a7d5ee, 0xea90254c, 0xd3ce5acb, 0x158bbb55, 0xd0842fe6, 0x41c4585f, - 0xc45fb85d, 0xb46c8cf5, 0x78538787, 0x218bf73b, 0x78dc2fc8, 0xac5b9e23, - 0x77dc13b3, 0xfa3056a7, 0xc0f1ff1f, 0xf3b1ade8, 0x5a8ba6b2, 0x13fecb65, - 0xef38c783, 0xa6ab2454, 0xa78829fc, 0x127c3d50, 0x9e9a1ffc, 0xb478e996, - 0x83f043fc, 0x1b958aae, 0x768c2e76, 0xce9f2277, 0xfe1cbbeb, 0xf7c31253, - 0xdc053ba9, 0xc37cf847, 0xd9f40552, 0xc99756a2, 0x74e3a86f, 0x8ece7eea, - 0x79c68dfb, 0x14505bbe, 0xc1fdf909, 0xbb051d6f, 0x41e6f171, 0x276eefa6, - 0x1470d5e1, 0x79fac173, 0xff3a5543, 0xe3eccadb, 0xeb6b8c44, 0x9c1c5843, - 0x49b8810c, 0x7906db59, 0x52dccd08, 0xf9ec9b26, 0xfce6835b, 0x7ce6156d, - 0x6d961ca7, 0x112ccf60, 0xefda16c8, 0xcb65ebf7, 0x8e3600b9, 0x76e64957, - 0xbbef1b25, 0xb4198694, 0x8e90fbe8, 0xe9156283, 0xdf65573a, 0xddd4f01a, - 0xae28932d, 0xb8a91dc7, 0x454a140f, 0xb2a82dbf, 0x9de15b79, 0x00f43b2b, - 0x8fee6785, 0x15a7c444, 0x2e838efe, 0xf3ed46dd, 0x907fcd8e, 0x9d6c7e21, - 0x3bfe158f, 0xa3e75b96, 0xcc3eb02a, 0x19cb590b, 0xa9f9589f, 0x36f17f6e, - 0xf37b3db3, 0xb5fb58b6, 0x530cd76a, 0x56f8497e, 0x9bc5fb53, 0x17ea99e7, - 0xd5312eb5, 0x6a59682f, 0xfd0bcfca, 0x8efed4c8, 0xf54c2be5, 0x635fafdf, - 0x62adbfaa, 0x6b7f2983, 0xfb5321f0, 0x98b6ca5b, 0x47076dea, 0x68e4077d, - 0x9e22ebd5, 0x3ee0bdfd, 0x9bd82f75, 0xee12dc17, 0xed447e73, 0x33839015, - 0xb4815ed4, 0xf478ff73, 0x2c1ea9a7, 0xf9a24d87, 0x2d5598ca, 0x0997a099, - 0x6572cfea, 0x24d0aac2, 0xd7b0178a, 0x9b887ca9, 0x041d1215, 0x0f724cce, - 0x318b771f, 0xa9971df5, 0x7d054cdf, 0xb17adf7c, 0xdd797e23, 0xd4c379d6, - 0xaf6a7e38, 0xb02192dc, 0xce5975ce, 0xb569189f, 0xb1a73ce5, 0xeb817dbf, - 0xe9856ad9, 0x19bdea83, 0x86736193, 0xe223e5fa, 0xf9ec9b9d, 0x0db0223e, - 0x53feb048, 0x98861f81, 0x76aa6bf6, 0xfbe49ae5, 0xe11121ec, 0x409d05aa, - 0x5217eaf5, 0x72028d60, 0x35923d16, 0xa1c0346b, 0xef4055af, 0x75c54fec, - 0xe9436cfd, 0x3fafd836, 0xf4c010d3, 0x4c3286a3, 0x3104354f, 0x02a1b0fd, - 0xf50d93d3, 0x2c347698, 0x86bdf4c7, 0x36efa610, 0xbbfa60b4, 0xdf4c5686, - 0xe98cd86a, 0x4c610d1b, 0x4c741b3b, 0xd1e8790d, 0x0f6e01bf, 0x84d71b1b, - 0x2e7cc3db, 0xe73da98d, 0xf7ff70c2, 0x11f3fbbc, 0x7f9fef60, 0x6cfb8ecb, - 0xcacbe1fd, 0x51d3fd6f, 0x3ca57b47, 0x639d083c, 0x8133bd6b, 0x2369c9d1, - 0xec1c64a5, 0xcff4ecff, 0xc4bcc7cf, 0xfd84f52e, 0xfa713c33, 0xfa5d7885, - 0xf444e9e5, 0x949982ee, 0xfe1ea71e, 0xf7e822af, 0x607fac02, 0x71111c07, - 0x6dd1261d, 0x95d7a07e, 0xe1784de2, 0x2f1059f7, 0xbf83d73b, 0x8b882cf6, - 0xd8a8ab5d, 0x3b36f9ff, 0xf9d2f881, 0xcfbc2e03, 0x36d8fe75, 0x32e3c82f, - 0x3d8e189f, 0x6b4d6147, 0xb761d922, 0xe736efc9, 0xa50ab7cf, 0x689a1e78, - 0x0347b389, 0x3861a95f, 0xe0d9d20f, 0x67e8d4c3, 0x71c14f99, 0x65caecce, - 0x5e7e3371, 0x424eec83, 0x277ea57e, 0x869fffb6, 0x0c7ebfa7, 0x23690878, - 0x5e08381f, 0xdb98bb71, 0xf97efb7f, 0x814cfa49, 0x20392af8, 0x82f60e7f, - 0x1177fe9d, 0x6122651c, 0x2eb7e8de, 0x63ec8622, 0x69b77ca0, 0x669dfa3c, - 0x7317f4f8, 0xe6b7c52e, 0x042234fb, 0x9c46bf68, 0x80fe0aa4, 0x02f530f3, - 0x788cabc6, 0x6ee49749, 0xc6f4c611, 0xbc78ea4b, 0xa1d1c6b8, 0xb9d16904, - 0xee4bdcb6, 0x38699e9f, 0xaf39c2a6, 0x02ab470a, 0x64454fce, 0xb9e80954, - 0xd2ab6d73, 0x12ac1ec0, 0x2f15dfcf, 0x67679b7e, 0x6125bd71, 0x8ebcdbb9, - 0xb420fe72, 0x1d9ca35f, 0x8a9f7472, 0x31b59fc9, 0xefdadb3b, 0xf6c0fb04, - 0x1f776a2d, 0xd683769f, 0xfbb54f17, 0x3e30553f, 0x5c53112e, 0x7bdfc0c9, - 0x9d82604a, 0xd772a9e2, 0x7e8f68fb, 0xdc468724, 0xd4fd097d, 0x9f6e7e77, - 0x88727ce9, 0xf338c3b4, 0x8881f227, 0x743bcb76, 0x15f8fd3d, 0xe4db9d99, - 0xf67b80e7, 0xfebef995, 0xdf9b9e02, 0x84e78556, 0x8ff7de3e, 0x242dff68, - 0x81d22f01, 0x1d8116b4, 0x4ad88e79, 0xc8e74f01, 0x31f1de6b, 0x3a95b874, - 0x05ef404a, 0x863b662d, 0xfca6bfda, 0x7ce6cde2, 0x06999939, 0xa37ca4fa, - 0xce02c24c, 0xb37f54cf, 0x177ec55d, 0x5826fa93, 0x8fee2557, 0x348957cc, - 0x9ad5ea84, 0x34567f67, 0xb411c28f, 0x88c83f33, 0x66492cbf, 0x4a656076, - 0xc27d8158, 0x7fc6da0f, 0x832006f7, 0x7104dc3d, 0xfc489228, 0xfc5f483b, - 0x56fc295e, 0xbaf58d78, 0xc3881c4f, 0xe212ee21, 0xdad603ee, 0x86cf6e05, - 0xe7c03d30, 0xc705f86d, 0x7615f92c, 0x2452de7e, 0x9cfdd022, 0x12d908ea, - 0x851fdeb1, 0xbb5edc78, 0x7106957f, 0x7b6ac0fc, 0xdfdc6f6a, 0x0f649768, - 0xe159f962, 0xf73c72d5, 0xf00b4520, 0xef8f21de, 0xc41f9c2b, 0x9c016f04, - 0xdc40f523, 0x3a75ce1e, 0xdf215bbd, 0xf3c0a9e4, 0xef20751f, 0xbc7bbfb4, - 0x9c418ed3, 0xa35a41da, 0xbb5fe53a, 0xa01fb2cf, 0x902ef399, 0x5067d04b, - 0x09a2e780, 0x235cb9c6, 0x7e3cedcd, 0x2e31fe73, 0x4381748f, 0xdf39ee3e, - 0xe14770e6, 0x2899093c, 0xb7f1ed9d, 0x63dfc072, 0x56fdc3f0, 0xcaa77f68, - 0x7df2d7da, 0x9edf3bdd, 0x097c9e9c, 0xa5f7547d, 0xeb31c240, 0xadd49d48, - 0x7dd61f00, 0xd7f96129, 0x5d1a9bd6, 0xe6f46355, 0x59f04a2b, 0x27a604fb, - 0x8e813e01, 0x64dfbb13, 0x027087bd, 0x2f4261f8, 0x386d7c3f, 0x7f498852, - 0x8f04a7bf, 0x6be383c5, 0xd3ebeff7, 0xbbe009ff, 0xf3feb1ff, 0x11dff4fa, - 0x679afe0f, 0xd10becf7, 0x17f2b5f5, 0x10e1780f, 0x6b52c7d3, 0xacef9c1a, - 0x0bdab1de, 0x1491f972, 0x3f5d02f2, 0xef718b0e, 0x0c3ba6e7, 0x70ddd3be, - 0xf396b08f, 0xaf9f99dd, 0x2ff836fb, 0x5590ef9f, 0xb2ec0f8c, 0x2994ed47, - 0x3096db6b, 0x7f65d8f9, 0xf19be59f, 0x7edd53bc, 0x7ca8beb3, 0x0d3481fc, - 0xb885550f, 0xff451cff, 0x7ffb76a0, 0xabbb034c, 0xdea3748e, 0xe3077eb3, - 0xf68c997f, 0xb1253cc0, 0x0e71bd6f, 0xa5e38eab, 0xde1d6dae, 0xbb6baf13, - 0x9a1334f9, 0xad3bf40e, 0xbb7055df, 0x9f30e1df, 0x42f034df, 0x5feeccc2, - 0x0583c4f5, 0xceb853ef, 0x2bc57f6e, 0x29f2c7e4, 0x23e77fd3, 0xa5fb1e0b, - 0x755cbfd6, 0x6b18fd52, 0xb4eb1b5f, 0x2bfb9fb6, 0x2d5a5807, 0x0fe0bd47, - 0xf1916f56, 0x9ef57bbc, 0x861f3b6d, 0x76dbccf8, 0x7fda70ff, 0xde979ed5, - 0xabe69eb8, 0xa653929e, 0xe1b869b3, 0x9f41a29e, 0xf2dffa3a, 0xa8f4bd71, - 0x4525fa7c, 0x7fcacd1b, 0x974bdc9c, 0x290ea7aa, 0x7c5f7464, 0x521c894c, - 0x85b67ed8, 0xa7f7913e, 0xeab15f81, 0xd0142f89, 0x141f1f5f, 0x1c767a48, - 0x09796e7c, 0x13c063ed, 0xabd393d2, 0xf6967e87, 0xa82e9475, 0xb2f42d17, - 0xaf98fbb6, 0xc42fd007, 0x3f7f29e3, 0xb7d84bf9, 0x0fdd9df9, 0xf278a878, - 0x9f30bc9f, 0xe33d52d3, 0x4ead9ff3, 0x1520fb83, 0xc54d2872, 0x3c579594, - 0xbfe403fa, 0x907fc7c5, 0xeac5cec6, 0x575cfc19, 0xd173cc06, 0x9e707323, - 0x7c8824e5, 0x7633f158, 0x4482fccf, 0x238a9f4a, 0xd839f727, 0xab7a763a, - 0x4f11371d, 0xfb0242c3, 0xe189af18, 0x640f181d, 0x607f0de7, 0x65913fec, - 0x60e0bf98, 0x30e45af4, 0xa5d1f1ee, 0xb77f9624, 0x9d03b737, 0xd3d50cce, - 0x475c8e21, 0x87c710a4, 0x2bf69170, 0xce9a9f1e, 0x52681dcf, 0xea8eff11, - 0x0e5029ff, 0xdd65dbed, 0x8efa6059, 0x1deecc5c, 0x3e3e4eff, 0xec013b85, - 0xd469d3d7, 0xbf338c1e, 0x9d630e03, 0x0c5676a6, 0x3bc8c59f, 0x6bedff93, - 0xf21bbc98, 0x0a519e1f, 0x609d9ff5, 0x81df0472, 0x8ae142fd, 0xa1fd63a6, - 0x07ea02d9, 0x93c6893b, 0x9732edf3, 0x95bd7373, 0x12fc285f, 0x7c3dc7ac, - 0x2324e303, 0x2dbed01d, 0x8fbf48df, 0xae30abd5, 0x86bf6fb7, 0xfae62f1c, - 0x1f45ad60, 0x07524790, 0x2d5b7fb4, 0x0c3e7787, 0x35e54bf2, 0xcafc81a4, - 0x27c15ef8, 0xf1bc8fbb, 0x9fb72a3d, 0x35b90c44, 0xdcab55eb, 0x409dec56, - 0x27edc9e2, 0x2b893f6e, 0xae3cb4b7, 0x903bbadc, 0x7ad6ff9f, 0xd3e3c0d5, - 0x7a1a3c16, 0x5a7c3fb2, 0x1db7e4f5, 0x493d5c5a, 0x45209dff, 0xe0d1f97d, - 0x2aff8343, 0xcf06a5ff, 0xa9f0f50b, 0x7c3d87c1, 0x9f61f06a, 0x8f09a478, - 0xe1bbfad6, 0xc0853a6f, 0xcfc63273, 0xfdb00fab, 0xd1ddfa67, 0x2f888521, - 0xd239971d, 0x4a48747a, 0xc96c3e6c, 0x75ed2c47, 0x69603e4b, 0xebe4b41f, - 0xf7abed4d, 0xb9d8511f, 0x9da9a89e, 0xe4a7fcb8, 0x01f13883, 0x6baa1d63, - 0x010954fb, 0xf1bbb87f, 0x0925797b, 0xfe5e2079, 0xf2f188bc, 0x26e38a2e, - 0xeed74e3a, 0x608f7c6c, 0x57c593b5, 0x2f6ed4ba, 0x93ab93d8, 0x553bbe58, - 0x683d0269, 0x593b7794, 0xd02bafdc, 0xb18a4ded, 0x203fdeef, 0x08ef1ea2, - 0x7e78d293, 0xa140de28, 0xfd20edf8, 0x80fdb3d5, 0x61d7b02e, 0x30ac84bc, - 0xd154e3f0, 0xe21cb59d, 0xde22ad35, 0xe2b85b6b, 0x239c2f16, 0xfb903ae9, - 0xbe5a329d, 0xdb22d7e8, 0x52e90ca6, 0xf81f8c46, 0x9a6d0911, 0xf5fec024, - 0x059fe47a, 0xb85f9807, 0x797c7d70, 0x95dfe4a8, 0x4054efbb, 0xee7f52ef, - 0x87beec64, 0x23c54fd1, 0xff03f296, 0x15a6e5c8, 0xdb951fe3, 0x1e41f5cd, - 0xe4ec183f, 0x92c7bee7, 0xb77fdcb1, 0x9e0fdec5, 0xa77fe62a, 0xeba7d28c, - 0x3ce04898, 0x2203f9c1, 0x6efce7d2, 0xe3007e76, 0xbf01d7fc, 0xe7b12b77, - 0x7c82cea9, 0x1ebfd55d, 0xefccfb3b, 0x3e06ee8b, 0xc14ef7da, 0x767a694f, - 0x7e23dbdf, 0xdf67f905, 0xf4877acc, 0xa0e53f6d, 0xba55f713, 0xff907a0e, - 0x4dff9ebb, 0x7f90ddd6, 0xecf18ece, 0x145f83ae, 0xad753f00, 0x1e8057b4, - 0xefe7e2ec, 0x45ff3d56, 0xbfae0741, 0xa9c7488d, 0x9f4fe64e, 0xef5ff03f, - 0xf381fdc1, 0xc0ace807, 0x42e838be, 0xa5fbaaf9, 0x5d6fe313, 0x14517fcf, - 0xa5fc27eb, 0xfbe5a9f3, 0x521e5d9d, 0x4be017b6, 0x7544fb62, 0x1b6ebabf, - 0xd3512fbc, 0x40594876, 0xf0bca7eb, 0xafd002a7, 0xdd997b5d, 0x3c7729d4, - 0x8179fb0a, 0xca340f35, 0x209d5e94, 0xff698364, 0x0128de6b, 0x978bea39, - 0x715c613f, 0xfc58f8a0, 0x043e0d7f, 0x4f3fe99d, 0x29854c18, 0xdef8ff07, - 0x0e27a03b, 0x8d2f91da, 0x59127ef9, 0xe5ccf681, 0xfff4dde6, 0xe885bcdc, - 0x03bde640, 0xefe13de6, 0xc0d7de77, 0xbed4a1a1, 0xcf97d072, 0xf30bbf9f, - 0x847e3c7b, 0xfefc8077, 0xfcf9dfd2, 0x7bee98af, 0x97bddd29, 0x7f87f79f, - 0x9feef3e7, 0xcb9ebfee, 0x79c2aee9, 0xfe17ba98, 0xa95df084, 0xfe12939e, - 0xbfbde5be, 0xfef61bf9, 0x35bf9b5a, 0x93cf1b27, 0x70b0c03a, 0x40b6667b, - 0xc8ed7178, 0x9dd82a99, 0xd5ef3f62, 0x7e60484c, 0xf7b02895, 0x1650c821, - 0xcfdc240f, 0xf80d6382, 0xdd9b880e, 0x4ddc933b, 0xc9137768, 0xbc53aedf, - 0xbe7abdac, 0x911acf1f, 0x21056f71, 0x8fc9399f, 0xbf8b6ef1, 0x5d1028d9, - 0x74aef6a0, 0x818f37f5, 0xb48f23df, 0x9805ed45, 0x33690fbe, 0xaaca638f, - 0xdc87f262, 0x53bce6f9, 0xbcede733, 0xf061073f, 0x0c247c3b, 0xd4716cf1, - 0xd3ce1561, 0x02256389, 0x4938a54f, 0x0efc086b, 0x7dfccfbb, 0x7ee10252, - 0xc7865fef, 0xa716048a, 0xed718512, 0x9471e03a, 0x78dce30d, 0xe2f11b48, - 0x08baf7c7, 0xf17baff7, 0xf80ed4da, 0x663fc094, 0xd5fa17f6, 0x12d3fb84, - 0x691a42ef, 0x76e69dd3, 0x2cbe8fdc, 0xb25d189d, 0x969d39aa, 0xd062e899, - 0x4c7d0e21, 0x7cf03174, 0xd2b1f4a5, 0xebff8ac5, 0xf75f1813, 0x2e832f47, - 0xef1d6e99, 0x7fdcc9d7, 0x133f0128, 0x820199f2, 0x7fdcabfb, 0xbc745290, - 0x7eaa24a7, 0x7e0097bc, 0xe01a945c, 0x86deef2f, 0x3f73a4f1, 0x00dbff7f, - 0x44afd54f, 0xebf8a0e2, 0x5121eddc, 0x2b0a5ef8, 0xb6569fe0, 0x404fb889, - 0xacd168a4, 0xc3627d98, 0x85faa80f, 0xb953e707, 0x4e9e1ed7, 0xf7dcafbf, - 0x61da0141, 0xcfd1bb2b, 0x605cfd09, 0x14750f74, 0xa5703ec0, 0x2b11fcc4, - 0x6049acbf, 0xcfb396f1, 0xae20cab9, 0xe762ec23, 0xb7232b7f, 0x7398f6c8, - 0x9904a14d, 0x739e9bc5, 0x3d085ea1, 0x28f9e021, 0xdcf62f80, 0x9c87e1a9, - 0xf060427d, 0x9df197ed, 0x4f5dca98, 0xaa7c4275, 0x1fbb2df2, 0x5dbaf8cc, - 0xc87ee29f, 0xf1ec5f94, 0x2e1fa076, 0x7d12e29a, 0x44bb01e2, 0xb6da8fe4, - 0x6843f41a, 0x36a2f91e, 0x2beffdc2, 0x7eab57f4, 0xb83efcf1, 0xf4f55670, - 0x7f885ee3, 0xe1df699d, 0xaec0b8c5, 0xfae7c74b, 0x3591fff8, 0xd6ffffdc, - 0x3b4f7669, 0x067fffbe, 0xf176a0fe, 0xfb9609d3, 0xb106bbab, 0xb44914f7, - 0x71ef52e8, 0xf0b9ed55, 0xcfafc428, 0x51e4fdee, 0xcffabb80, 0xfc14787f, - 0xa9d0720a, 0xba827dc2, 0xf18ebf9f, 0xdfbbe33e, 0xf9d03d70, 0x2f18e3c4, - 0xfa9b7ced, 0xe75ff41f, 0xc0b3a7f3, 0xea7ceccf, 0x4f10698f, 0xa9f9f3b9, - 0x9dce6ef8, 0x27494ccf, 0x9189f471, 0x0786ff02, 0xd2b5af10, 0x11db48ed, - 0x51ce7ff4, 0xd9ff83ba, 0xd489d713, 0xc69978b0, 0xe3bb39e3, 0xc4fbc7c7, - 0x7d66da6f, 0x4842c6e7, 0x0646bf65, 0x4139c710, 0x006639e9, 0xe3cddc74, - 0x5d6f9175, 0x0e738e32, 0x3af4a0fe, 0x85e3a16b, 0x3d8f45b6, 0x836d750c, - 0x44e38dfa, 0x233f8007, 0x413fbefe, 0xe40122ff, 0x60bfef68, 0x37e80cfc, - 0x73b84e9d, 0xd82c85cf, 0xee48f8bf, 0x85ef8b9e, 0x21576f3c, 0xfcf9511e, - 0x9d4f289b, 0xf8c71ccf, 0xf071e136, 0x8ff3d24e, 0x99f92bc5, 0x1eedbacc, - 0x74e1ff16, 0xe690f880, 0x071e72c5, 0xc46d7c62, 0x0b8bfa87, 0x73b1718d, - 0x40bec627, 0x7877f6cd, 0x6e97a5bc, 0xd7a044c2, 0xcfdc97fb, 0x02a0f030, - 0x8d8dae1e, 0xc38fc67b, 0x2d3dc4f5, 0x427a0374, 0xae27b3bc, 0x7b13d849, - 0xcde16175, 0xcef47178, 0xda5e2c2d, 0x8f3fc729, 0xaf41c465, 0x9fe25976, - 0x3fc581e1, 0x2b8f372f, 0x9760d3c5, 0xf15afd86, 0xf8abf675, 0xae5bfdfa, - 0xe85f9d81, 0xdaad7f77, 0x3de61f7c, 0x05dd3825, 0xef6d6bfb, 0xa7cf042b, - 0x2b73b374, 0xf967be7c, 0x3fb3d3f9, 0xd62e3117, 0xfa823914, 0x8c3faadd, - 0xbc2b57fd, 0x6b787077, 0xe3f5b3f7, 0xd84f5eec, 0x7b39fb4d, 0xebe439f8, - 0x63efddda, 0xaee8ee5c, 0x988e95a7, 0x8fd616f5, 0xce7ccc70, 0x80a8793e, - 0xdfe379c5, 0x3171ab1b, 0x40eeb37b, 0x76ea71fc, 0xa71a6a7f, 0x9851142a, - 0xf1e9701d, 0x2dfa48ce, 0x7699dfd0, 0x3a4ddf19, 0xbee31113, 0xc9701c17, - 0x95a11f7c, 0x475d0fc9, 0x71c09ef1, 0xf0a77f76, 0x573c04b5, 0xd2f1e77f, - 0xb7fde077, 0x8358a93b, 0x82b6dfdd, 0x4fdb69f1, 0xef4021f4, 0x13dfe3b6, - 0x07dafd61, 0xffb18df8, 0x4fd44e8b, 0x50fd50f1, 0x10a06ef4, 0x77aad5d8, - 0x66cb7dae, 0x938e9f82, 0x2342eb0e, 0x83ee07ed, 0xbc39b9c0, 0x569dee57, - 0xaa88f00a, 0x7d0a754d, 0xf9bb21e7, 0xafde557d, 0x21ef9aac, 0x6bc6af90, - 0x266f8fd0, 0xcc664b8b, 0x9f165232, 0x87f7190c, 0xabc213ca, 0xaf7f7ce8, - 0x28bb3706, 0x8d9e7c5e, 0x78112fd9, 0x06a26a27, 0x2e63d3f6, 0x4bc1de7e, - 0x83bcecbc, 0x7aa3643b, 0xf6ff61fd, 0x9e08930d, 0x7c06d867, 0x819e73d9, - 0x2f800b44, 0xea7d768d, 0x321de72d, 0x5a2a13e1, 0x17338722, 0xfd5025ee, - 0x77866ab2, 0xf11fe42b, 0xb2cdf7b0, 0x3821f748, 0xdb8db0df, 0x1560d9a3, - 0xe77df6e7, 0x6fbeebec, 0x78a53296, 0x853f30e9, 0x535ff5d3, 0xca7c5ce1, - 0x0d4fc52d, 0x2d856951, 0xa3dc1a63, 0x78bc7949, 0xcfcd066c, 0x34f4ff5f, - 0xe2f7ffac, 0xff3459b1, 0xb20e7b93, 0xcf012afa, 0xaeb0bec1, 0xeff01a76, - 0xd9fb96d7, 0xb9663314, 0x77f0057f, 0x77eef02e, 0xae706917, 0xefe15ba2, - 0xdda00465, 0x7f0c89d0, 0x9f77ee99, 0x98657f02, 0xf00563ad, 0x7fcf63eb, - 0x16f78491, 0x2aa1fbf9, 0xdce15469, 0x789a2d15, 0xf3e712f1, 0xccfbbcfa, - 0x498dcbf5, 0x3f8177c1, 0xbc8de79a, 0xef1d1a6f, 0x0e718ae1, 0xf2d00e76, - 0x829aa34e, 0xe9c85d74, 0xcb3df84a, 0x8b3e7c45, 0x02c290c5, 0x7f5caddf, - 0x5751ef19, 0x1ef4578b, 0xdbab8735, 0x67fbefd5, 0x3378007f, 0x007f8293, - 0x3fdf59fc, 0xb815c57b, 0xe519f500, 0x5c7de25f, 0xeb333de3, 0xea4468bb, - 0xfb3efb8e, 0x5a2efe56, 0x9bfef07f, 0x69ba283b, 0x682f39ff, 0x39518f7b, - 0xf150b31b, 0x31cfd1c3, 0xd2fd0bcb, 0x0426c220, 0x1fa71076, 0xf788cf3c, - 0xb822ee1f, 0x1765db5f, 0xbbaff074, 0x7d4549fe, 0x3a70b99e, 0xae5d5ffa, - 0x339c08ec, 0xc35bbaea, 0x018a3d7d, 0xe869e401, 0xf828c481, 0x3e1e5487, - 0xe7c3c8b7, 0x8f37fe66, 0xdb5175db, 0xa9fd81df, 0xa06a3fbc, 0xed8bdcc5, - 0xee9e9912, 0x8e10d06a, 0x087424a1, 0x8e81fdd6, 0xebe6e397, 0x46cfa737, - 0x9eeb9e9b, 0xee1ff880, 0x28ffc18e, 0xcc74bf77, 0xe63a3377, 0xd1d0e3bb, - 0x7bdd6efa, 0x6858e0ae, 0x28fcba77, 0x7d675fbe, 0xdf4aceaf, 0x21f5a93a, - 0xed2b3b78, 0xfeb8a7c0, 0xb31bf418, 0x29d22c7c, 0x00939e86, 0x3e07318e, - 0x06bc01b5, 0xe7ec1f1d, 0x9ba9793c, 0xf1d673ad, 0x063acad2, 0x9fb4e307, - 0xf74cd6e5, 0x451c0a0e, 0x69ca897e, 0x87c58dba, 0xb7efb6fa, 0x9d4b9cff, - 0x59502cf3, 0x73ff14bf, 0xfe064f00, 0xfbf3756f, 0x7ff17dea, 0xf8a3b43b, - 0x3fe61dbf, 0xbbcffc00, 0xfb0dfe14, 0x87eb8abf, 0xa29fd82a, 0xda1ff47c, - 0x3a1cb4cc, 0x8dd134ee, 0x8764b072, 0xd931f7c8, 0x3e865ffb, 0xfd5d7259, - 0xb917b821, 0xf20267e4, 0xfefe42eb, 0xfdfc27e5, 0xc1b9eb4b, 0xea10b2f2, - 0x1f9fcbcb, 0xaa3ea30c, 0xff2e65da, 0xbbcf7767, 0xde785997, 0xad352417, - 0x2b4ebdf7, 0xb9bbcffe, 0xb4e858de, 0xd72f7bc5, 0xdbd68748, 0x33cce74c, - 0x83f4f4a6, 0xa6cfa0fe, 0xb8f189bd, 0xc409957f, 0xa5297413, 0x2019de10, - 0xf4094285, 0xd7e5cc5b, 0x72d86fe8, 0x1d9ffaf3, 0xcc43df32, 0x43df316d, - 0xbe6ade1c, 0x66d57887, 0x51c43df3, 0xc43df361, 0x338d766b, 0xae4747e5, - 0xb31fb537, 0x3f29b27f, 0x534dfa36, 0x66c7f1fb, 0xda13f29a, 0x7f6a67bf, - 0x4df35bed, 0x5475d7f5, 0xf86fea9a, 0x7f299968, 0x9b3ff763, 0x311747da, - 0x61b878fd, 0x5bdc1179, 0x7872f030, 0xa15362a9, 0x9b08e97c, 0x9e5b105a, - 0x90056ba6, 0x7fe0e916, 0x532f27f5, 0x8a2a3f1c, 0x898ba75d, 0x536fd26c, - 0xd47ce61c, 0x8f7dfe6d, 0x35722c97, 0xcb527ea4, 0xbc1d9a08, 0x63cf0f24, - 0xc63af953, 0x01b1dbf5, 0xa0dfb7ea, 0x9b46d57c, 0x2f956f20, 0x9a01bde3, - 0xad8fd886, 0x1f9f77b0, 0xd4f99a72, 0xf95e8fd7, 0x0738db9d, 0x53facad4, - 0x264bc6cb, 0x3fca3139, 0x172d8c2a, 0x73c74f16, 0xabf5fd40, 0xb35c16f8, - 0x3bbc107d, 0xa3530f3c, 0x16cca9bc, 0x67dfdcf7, 0x7fd0bfee, 0x8ec7dcda, - 0x7cf00cfa, 0x26daf7ce, 0x7b56bf38, 0x51fa377b, 0x5e337619, 0x5decf37a, - 0x479e0363, 0xac3e481a, 0xb6fdc6f7, 0xebe13445, 0xd177ce36, 0xe0d333db, - 0x3f66419c, 0x87a155fe, 0x1b47ebe9, 0x042cd742, 0xe98711c2, 0xb456795e, - 0x39f81a6e, 0xeb79f8c3, 0xe7f8b64d, 0x0c3c92a0, 0x48a0e92f, 0xdd505ec1, - 0x2b9c2f68, 0x4f0bd77f, 0x0f68dcc7, 0x38e87926, 0x17b4c7f3, 0xbad4fbb1, - 0x5ee8e67f, 0x947d0db8, 0x026c0ee5, 0x93e592fd, 0x17dd9688, 0x83dbf49e, - 0x788ef02d, 0xefcdb263, 0x00b77cc6, 0x4c7fd9e3, 0x5e3a20c8, 0x84459fe3, - 0x75f0f1af, 0xeec83e78, 0xabb8c7ae, 0xcfc24f31, 0xe6711809, 0x89d9be0b, - 0xabc6cf80, 0xe107ee7b, 0xdc17907b, 0xf7e876c1, 0xc71946c2, 0x982c9c6d, - 0x4b798dea, 0xf78dbf9b, 0x6cdcb2be, 0xde74e5de, 0x933db700, 0xa8f8d5c1, - 0xae113240, 0x28f4bdff, 0x5cfb35f8, 0xc507def8, 0xc7c010c7, 0x73fb3d39, - 0x3a79319b, 0xee419aaf, 0x9ed16bad, 0x4ea7ef89, 0x8fa1e637, 0xe33bd134, - 0xe2fc332a, 0xc6fd1946, 0x3c6e4945, 0x886e10ef, 0xe79afa72, 0xf99be4df, - 0x5c295b9d, 0xf8884eab, 0xd1d6b6de, 0xfd28f4ba, 0xe5cdbcae, 0xf17d6b0f, - 0xf0634e7f, 0x7ba7f852, 0x4f36de40, 0x79e3f9c3, 0x31ff806a, 0x0d9c3c81, - 0x452c17fc, 0x236c183e, 0xc7d36fb0, 0x7930f04e, 0xd951ed9e, 0x72be357b, - 0x85be8726, 0xfda76cd7, 0x5dfa7995, 0xb0f36ff7, 0x4f36ff75, 0x72ff759c, - 0x975707ef, 0x54851fb5, 0x37b445d4, 0x111fa908, 0x3d53476b, 0x1bfd0e56, - 0xc7f13179, 0xff6fd005, 0x65bf9a76, 0xede5f644, 0x80cfb034, 0xecfb0d0f, - 0xaed98f4e, 0x3fbbd18c, 0xfbbd30f4, 0xf4c0cf43, 0xfda18fee, 0xe345efe9, - 0x4aa935da, 0xb4f7bd7c, 0xac1fdd87, 0xe7821553, 0x0fd9fb03, 0xdae5c9d8, - 0xd6feef3a, 0x1ff9cba5, 0x4f832e39, 0xfcfefacd, 0xf4112d31, 0x4207ca54, - 0x86b777dc, 0x3c6dbf2c, 0xad9b6bd0, 0xf7cc3378, 0x78fe1667, 0xf59f4d68, - 0x18f1cc2b, 0x6ac78b8e, 0x099b478a, 0x973c3b8f, 0xb6bf0fb0, 0xdf30afbe, - 0xf8e4e9f3, 0x09bf7aa6, 0xeb373bc6, 0x6b8822bd, 0x1cf9ced4, 0x1ed7fef5, - 0xaebccca7, 0x1d397e18, 0xa1e00567, 0x799fd673, 0xe303ae7c, 0xb99eab4a, - 0x58e2112a, 0x7a0d9335, 0xaa7df044, 0x4839f9f3, 0xecfb7397, 0x2e79c03a, - 0x3d139d99, 0xa3daefb7, 0xa4f8f710, 0x2c7258e1, 0x793dcf7d, 0xfda648bc, - 0xbc7bdb9d, 0x7703c248, 0xd43bd361, 0x5b7f1735, 0xdef77014, 0x37e1e84b, - 0x368f5b07, 0xe57c593a, 0x37173841, 0x6abfda86, 0x7a65f212, 0x285eed9a, - 0x1dbf1d17, 0x395c21fc, 0xa62fe63f, 0xd04ab259, 0x7ec11633, 0xee373cd3, - 0xc972f967, 0x9dfa6cc8, 0xe387ad12, 0x6af9c4cc, 0x04efc098, 0xf1444eb8, - 0xef3c02f7, 0x3ef86076, 0x02b243f1, 0xbdffc29e, 0x78093c1a, 0x09ab3a4f, - 0x77c41a89, 0x471e6e8a, 0xd30a6953, 0x3ab7ddbf, 0x848cf7f0, 0x53aaaf05, - 0x3cdafea8, 0xdd8efd93, 0x920b63f9, 0x55691fc0, 0x0df2de99, 0xb463e1eb, - 0x6be7078b, 0xe6231737, 0x40577c75, 0x921d1955, 0x8a6b6c33, 0xf9c78c35, - 0x25fe98f3, 0x3dff1a52, 0x1eb7ca29, 0x1c43a6cd, 0xc5cef8d8, 0xfc522bbf, - 0x7803cebf, 0xf0fcdb46, 0xabfb8f4e, 0x92ca386f, 0x28ccfb69, 0x945e5fbe, - 0xc39de1c0, 0xfbef07de, 0xd345e34e, 0xd4b5187d, 0x27b74efc, 0xe214b4d0, - 0x6defd0fc, 0x8bcef8c9, 0x38a29eb9, 0x0bbb9691, 0x0aaee5cd, 0x47e18f9a, - 0xf6d677eb, 0xae925f86, 0x37f63832, 0xbf0f1038, 0x79fd506c, 0x340e8f94, - 0xb07f30f8, 0xda34c341, 0x0fcb1230, 0x2f31f837, 0x986cf4da, 0x7faffa4f, - 0xeebb1490, 0x9d54efc2, 0x75c3e18c, 0xf9ade472, 0x88df8f80, 0xaf15af88, - 0xdefe478e, 0x3a8e9a34, 0x7367bd86, 0xfefec632, 0xd257f2e9, 0x0d5f284a, - 0xd3afd1f9, 0xefc3c64a, 0x17f3b096, 0xf63a4170, 0x257aee1e, 0xe093f9a0, - 0x34c63477, 0xfbc2863b, 0xc95bc1a4, 0xfd239458, 0xbbf089c5, 0x6c337b0b, - 0x949a7eb4, 0x07f8ecd7, 0x64deab80, 0xe7e7afe7, 0x6c9f1f33, 0xbce3afd6, - 0x0a66ff4c, 0x71bce3c5, 0x537e09f8, 0x39acfd00, 0x3307b9c6, 0xbf54891e, - 0xeb8a76e1, 0xdfb3efe6, 0xc754485f, 0xf7bde1fb, 0xcec35ecd, 0xbec5f7a9, - 0xff99bee7, 0xe1e2440e, 0x29176825, 0x103bf63e, 0x0f7b0a29, 0x4d930489, - 0xe5cdedef, 0x0606ccfd, 0x1f57d09a, 0x15fde6cf, 0xfb0e791d, 0x8897df83, - 0xf087eff5, 0xccd8c3df, 0x3574d3f5, 0xed4dec50, 0x5bd4676d, 0x7759ebbf, - 0x0bd1216d, 0x890143f6, 0xed04bd80, 0xd4bb698a, 0xdc02030f, 0xd7ce33ef, - 0xcdf80b3e, 0x93ddfdef, 0xebc3027d, 0x8a7d3c93, 0xd4494eff, 0xe3079813, - 0x123c16fb, 0xca7603da, 0x6206bb3e, 0x8fe47452, 0xf8947ef8, 0xe701c53b, - 0xbc0f53fc, 0xd9e5eecf, 0xbf38143a, 0x7c5bd2b8, 0x4551c413, 0xf3033ea5, - 0x816f4ef7, 0xfa9e83fc, 0xdda3d887, 0x1f0137c5, 0x06f7f3a4, 0x01000408, - 0xe1aa080e, 0x43fd638f, 0x64654eb3, 0x2bf2cc9f, 0x873637bd, 0x3f5f2132, - 0xf208f80f, 0x7dbfb48d, 0xc021c149, 0x86e16e47, 0x423763e6, 0x037f68de, - 0x5789ffb6, 0x3b8ffe65, 0x4af60d98, 0x79a55e4f, 0x625e4c4f, 0xa960e279, - 0x239abf31, 0xd073c47f, 0x3bd807b5, 0x6607a95d, 0xd4cf3008, 0xff1033fd, - 0xbcb7d5e7, 0x878c342b, 0x04eb608f, 0xf41b978b, 0xa6e1ee30, 0x79f783d9, - 0x9d61f863, 0xc4c76cd7, 0x0fbc27dc, 0x1fd3ddf0, 0x36cbaf8f, 0xf74a9ef6, - 0xc6efd88f, 0x547b030d, 0x86b9b884, 0xa3dc2e69, 0x70c1fea7, 0x98395c12, - 0xcde35fd6, 0xb55e3a41, 0xa9cdfb3b, 0xa75f2f5a, 0x80772964, 0xf8b54e3e, - 0x3f5cd935, 0x7f8b508f, 0x372b4893, 0xf0b5c10a, 0x8f686c9e, 0x937de2ac, - 0x4728195d, 0x228eb967, 0x5f3183f5, 0xcbbfefcd, 0x476b832b, 0xc4591e81, - 0x76556ef4, 0xdfa658a0, 0x8d973d57, 0xf0670bbf, 0x2452555d, 0xf7bb9c6d, - 0x3791b75c, 0x21e4477e, 0xef09d5b5, 0x5afb18f2, 0x6437fbb5, 0xc7fd3ec1, - 0x3b46de87, 0x36624971, 0x76d359c2, 0x69df815c, 0x7ca36da9, 0xd8fbbf47, - 0xa3c763d9, 0xc887f25f, 0xbe026fa0, 0xc368d0fe, 0xd9fdddcb, 0xfd522f55, - 0xea85d3a6, 0xd3038368, 0xd5fd7a9d, 0xf09c0ae0, 0x49c9b82e, 0x1cf1e9f9, - 0xeafe055d, 0xf51eb7bc, 0x3a8ae3d8, 0xd3aff80a, 0xe066c3fb, 0x9124aae7, - 0x5f0febf3, 0x7ef8f3d6, 0xb9efcd3d, 0xbfa6edb7, 0xa160df68, 0x7ba9fed9, - 0x41fc8dc4, 0x02df92ed, 0xb66ed51f, 0xb3fd6085, 0xbef1da39, 0x1be82773, - 0xfbe65fd4, 0xa6051b99, 0x5873430f, 0xf772fa1c, 0x74be2b34, 0xfd8c7091, - 0xe99124bd, 0x84290aab, 0x5f1576fb, 0x2ffeb17a, 0xba69c71f, 0x1c77da0f, - 0xe31bd637, 0x838ef754, 0xf6fd527c, 0x5fcff461, 0xafb0dabc, 0x77ffd475, - 0x61cfc53e, 0xe874f538, 0xd0d941e7, 0xa4cfd427, 0x1ee78678, 0xf9243e79, - 0x47a97908, 0x2e6dacff, 0xf6fa04c9, 0x7eb313d6, 0xb74a25d2, 0x3e781297, - 0xc9737f74, 0x13ed38a4, 0x8c73ed2c, 0x7fb14ffc, 0x3a0f3c2b, 0xda0ef37b, - 0xbd93fa5e, 0x6df00f27, 0x4bfa59b0, 0x86dfc636, 0xb7fc19fd, 0x65fbbbc7, - 0xa5e9ef78, 0x10f140a4, 0x2068df66, 0x15245b87, 0xc0d1877f, 0x3ebe1ef3, - 0x8d797c55, 0x78bdff09, 0x9f95302f, 0xfb4cd06e, 0x2e178ba1, 0x7b3f7bc3, - 0x41563af8, 0xdb3eec42, 0x7da6b923, 0xc70fffd0, 0xb8a385d7, 0xfe4a381f, - 0x328c70c6, 0x385e81e9, 0x5fe54df2, 0x69310e17, 0xec366976, 0xa1b1ad53, - 0x0b66909f, 0x6ec07239, 0xf7ec5ffb, 0x0734201a, 0x61a899e7, 0xce57da6c, - 0x079f6039, 0x448e79c6, 0x40e3498e, 0x056d749e, 0x913f53ac, 0xe5a1afd0, - 0x8619390e, 0xfde1d56e, 0xd8952a2b, 0xb0754e5f, 0xe6f51986, 0xab876277, - 0xe5a258a4, 0xb879d5e3, 0xdd94e5ee, 0xfdf60755, 0xcfe17736, 0xbc931357, - 0x5ab27da2, 0xc7f68a58, 0x9b17c49a, 0x3d38df61, 0x0233d981, 0x58f9b179, - 0x267abc46, 0xbdf72daf, 0x31c41378, 0xaed4aeb6, 0xab6e7f06, 0x0c391c33, - 0x6e3df9eb, 0xdcaa3dfc, 0xf816e175, 0x83710abd, 0x314bd70d, 0x2b6bbc29, - 0x6078179c, 0x8bec1f84, 0x40d760ad, 0x5c6e35fb, 0x421a5bff, 0xe2af2f68, - 0xf5f6c0eb, 0xe7385493, 0x9296e8dc, 0x916bbd61, 0xb8056feb, 0x64efba5e, - 0xd03ae3b3, 0x4196fe63, 0x80cbef3c, 0x71cb4d75, 0x14f5e58c, 0x68575b19, - 0x3485c183, 0x44ffc3f2, 0x33d412ad, 0x6b0ed127, 0x04ab2f74, 0xbfd68e3b, - 0x7a78a0ec, 0x85e3993c, 0xe8f4e7d7, 0xa0cd93a5, 0xbd15c507, 0xef3a12f9, - 0x7a633f1d, 0x3fda09ea, 0xe7452bbc, 0x18778213, 0xe84947bb, 0xc1242587, - 0x74d0c76f, 0x9dfb0e74, 0xbd17aa5b, 0x3849c7e8, 0x491f635f, 0x0f7ec519, - 0x7ac3da1d, 0x83919093, 0x0cca98fb, 0xe2835ef6, 0x66fde371, 0xdd5677e3, - 0xb3a7f8c4, 0x67df2978, 0x43de5971, 0x895fae70, 0x784ee99b, 0x4f862137, - 0x0b7bcb15, 0x07cc0912, 0xcd544b7b, 0xe449bfe5, 0xd8834afb, 0xb70eadef, - 0xa32ed085, 0x35e98452, 0xd9f68a24, 0xf981d268, 0xe66de031, 0x0d2c35c2, - 0x278d8e2f, 0xbbe2c8ba, 0xc7ec1101, 0x788d5bb4, 0x44f5f04c, 0x96bfdeba, - 0xfc36e3c8, 0x66538c77, 0x7d7ee214, 0x5fab1266, 0x0fbbc815, 0x338dbcec, - 0xc69c61a6, 0xf58cefb0, 0x16dfb0d2, 0xab579872, 0xc17b5c42, 0x3a16ebb0, - 0xb6753e59, 0x8868e0fe, 0x0b53b66b, 0x2fee1b34, 0xf96af8b3, 0xb034e2e6, - 0xba1e16cb, 0x4ce4ed15, 0x8b65d995, 0x8250ce36, 0xdadee1a3, 0x8a07f43c, - 0x84484c37, 0x4ed5847d, 0x8575e27f, 0xfbe267e8, 0xc7b503b9, 0x355da6b6, - 0xab71e419, 0xca90128d, 0xeeb24bfb, 0xb17c0b1e, 0xcced0f21, 0xc6c109ad, - 0xd6efda24, 0xabfcd67f, 0x4ea7fe68, 0x8c38f0bd, 0xd5813ab3, 0xc051bbc3, - 0x12e73d9b, 0xc9bbe1b6, 0x3d6f8dfd, 0x1252f097, 0xa8ca7f7b, 0x7e536fff, - 0x80007d7c, 0x00008000, 0x00088b1f, 0x00000000, 0x7dbdff00, 0xd5947c0b, - 0x66fdf895, 0x666579be, 0xf263c992, 0xc2130922, 0x9e4e5e4b, 0x124c2280, - 0x4cb443c2, 0xe8202a10, 0xa79034f0, 0xbadc5d48, 0x30040cff, 0x5706b650, - 0x84ea2b11, 0xbbaac562, 0x351ba341, 0xb88080ea, 0xda446dd6, 0x8ffd16d2, - 0x4810154a, 0xfed2b58a, 0x39cf65dd, 0x7cccdef7, 0xb5f01993, 0x3efeb4ff, - 0xe7ddf7ee, 0xce73df79, 0x12e973bd, 0x2c614dfc, 0x5630a494, 0x51c1d8ca, - 0x618cf58c, 0x24dea98c, 0x064dcf06, 0x34e2d26f, 0xa37efac6, 0xf5e1bb67, - 0x926f6617, 0x25d8c6c3, 0x79fa2ed1, 0xa0b199aa, 0xcdb3b189, 0xc11c166e, - 0x336699d8, 0x1f966b95, 0x9fa0c698, 0xb9850e9a, 0xc55b19f2, 0x3f6336da, - 0x69923baf, 0x3d0155dc, 0xf4648e0b, 0x5bfe0977, 0xd528fcbd, 0xebc9dd5f, - 0xaa0eb2d7, 0x4f3192bf, 0xf76b3c07, 0x1cd0595a, 0x51df5fae, 0x4a1f69ac, - 0xd7bf51d2, 0x3b06fb25, 0x5bdd8c9c, 0x2abefc3d, 0x5d569f78, 0xfae1f662, - 0x13e38e58, 0x87afa8ab, 0xebe63af7, 0x77aeb188, 0x49de5c04, 0xac4e8a82, - 0x32b1d0ed, 0xe03ad6c6, 0x1ec62e9f, 0x6c7cd850, 0x15f7f6b7, 0xc2632919, - 0x9e2ad6ed, 0xf898c70c, 0xa8bc6a70, 0x88d48167, 0xc467dab2, 0x345e35f5, - 0x0ef3fbd2, 0x63075fb3, 0x3ff4c91e, 0x7fac2d70, 0x1953eb26, 0x909f53cc, - 0xcd5d8e38, 0x71258b58, 0xba673e37, 0x08a17d0c, 0x53333038, 0xf8337e71, - 0xc4ebf62b, 0x71944769, 0xed403ed8, 0xa98ed967, 0xc473400c, 0x8303735e, - 0x90b037f7, 0xce060aca, 0x28fdfa0f, 0x2359dfb2, 0xdd1be5b5, 0x09ecf2da, - 0x7e6332da, 0x9a4fd782, 0x1a4eca9b, 0x04fefdc2, 0x0311d6a6, 0x5802b72e, - 0x5eed7eb1, 0x0464e04b, 0x923beb1e, 0xaec6e535, 0x88c9c0ac, 0x1ff16a71, - 0x135ff059, 0x589d775f, 0xdf4607f7, 0x5bc00ead, 0x71190b3d, 0x46c140dd, - 0xacc658ef, 0x7c45e616, 0xf16fd81d, 0xcfe812b0, 0x00b76e66, 0xabbb1b7c, - 0xdef02595, 0x30ef876a, 0xe196273f, 0xfaf03569, 0x0e88058c, 0x39da8fe0, - 0x5bed99bd, 0xb713e415, 0xcdfedaab, 0xff00dde7, 0x4f0293dd, 0x24ac3d95, - 0x0ea3ac46, 0x5e1e91d6, 0x07eb39c7, 0x582f8865, 0xa5ec6fcf, 0xa6461748, - 0xf3d78524, 0x5cb5e1ad, 0x5dc6af0b, 0x1837a236, 0x1844bde7, 0xcea761a7, - 0xceb2846f, 0x7e4463dc, 0x3ce917b9, 0x1c72de06, 0x6f3c4c4a, 0xe0c73c43, - 0xfcaceda7, 0x1cc7e43e, 0xc7181fe4, 0x6527eeb6, 0x8f818b27, 0xfa1737aa, - 0x054dbea0, 0x547186fe, 0x08a9bff8, 0x6d3bd9c8, 0xe9d03255, 0xc3e73b29, - 0x7a2e890d, 0x0abc50ee, 0xe75d35e2, 0xd5fa47c9, 0xcc43b827, 0x66a3f1c1, - 0xcb601942, 0xf962c1ae, 0xefe81ebd, 0xcb1b9821, 0xf0098416, 0xcbc2c878, - 0xefca392f, 0x6ee308dd, 0x0de5e64a, 0xd5b9bd3f, 0x16ca093f, 0xe5439e59, - 0x416d0c87, 0xffdde03d, 0x44f5c982, 0x28f7b53e, 0x32305e58, 0x4d4c04f0, - 0x2365843f, 0x4226a65e, 0xf4b720e7, 0x9b769a2f, 0xeed05ea0, 0xa78427fb, - 0xfb39ff5c, 0x26363cf1, 0x4d7e7f66, 0xacdf797f, 0x53bf183f, 0xfbf87577, - 0x419dc4d4, 0xc2e76f3d, 0xe7a72c76, 0x9ff43f03, 0x6d89a2fe, 0x0623e285, - 0xda179b76, 0x632c5dd5, 0xd43908c1, 0xb679f023, 0x5b7241d9, 0xf943afbe, - 0xa9f9063d, 0x7d70e487, 0xfe46aa47, 0x7f5cb94a, 0x7f4d5af1, 0xc27c8e39, - 0x43dabd57, 0xe2feadf2, 0x121efa64, 0x736cf4f2, 0xf889e926, 0xc8d20ce3, - 0x1338f0f5, 0x72f8b059, 0xefa24ce3, 0xcbe61c72, 0x06bdb922, 0xa4240ce7, - 0x87bc8237, 0x750c2e71, 0x465f2525, 0x0276d99f, 0x67ac4591, 0x63341a9b, - 0x07dcdbff, 0xfc18be1c, 0xb844e520, 0x1edb51bd, 0x811b23f4, 0x4863edf4, - 0x7aacffb7, 0xd4fa91cc, 0x5038f066, 0x8af6a86f, 0x34372e23, 0x86647e4d, - 0x5169280a, 0xd97f3d39, 0xd1e881b6, 0x411f706e, 0x3aeddafc, 0xafbe1f97, - 0x483ce9b7, 0x730e2d27, 0x51bdf100, 0x7281c1b9, 0x076bf643, 0xb8f38f31, - 0x7a421b60, 0xd57ade3d, 0x0f54898b, 0xa9199266, 0xc6f7ff1f, 0x0f17c583, - 0x31bd8f1c, 0xfa0b88f1, 0x6e744b57, 0x910be00b, 0x1d0471fa, 0xdf63f744, - 0x779cc6a9, 0xff093d74, 0x8436f8b8, 0xe7fe1112, 0x8119ba6d, 0x4d2ef318, - 0x9e9bbe56, 0xdf25145a, 0x3c3b7f93, 0xd095ed88, 0x49f20a0f, 0xa32696fe, - 0x90bc2dfc, 0x3922e958, 0x73b5ee9f, 0xb6e385b1, 0x7d9a8ed8, 0xed988fa4, - 0x3ebfd913, 0xb849fd3e, 0x64aade18, 0x04601f88, 0x4ae37a86, 0x412bb070, - 0x1597e22f, 0xd3e50caa, 0xa76f3a40, 0x77d7f4f9, 0xeb11e743, 0x0edd516f, - 0x75fd6ba4, 0x99ca331e, 0xe6398ef5, 0xaa379410, 0x20f9d9ae, 0x02defa87, - 0xb7d6127b, 0x1cc8ad29, 0xc15a8f8b, 0x2df9c46e, 0xd669d64d, 0x1d669f23, - 0xf7e8dfe7, 0x9eb9925b, 0xb13fdd68, 0x9f1253c7, 0x79d2407e, 0xcb9b8f51, - 0x5856c754, 0xe7c0de9f, 0x0763896b, 0xc1e37eca, 0x0b7ecb6b, 0xa87569c9, - 0x44f68039, 0x549b78f4, 0xbe078f77, 0xf8f9826f, 0xc7c39cb1, 0x3aa254df, - 0x16d74376, 0x47330257, 0x4b3837d4, 0x6c17fe08, 0xdf0f4c69, 0xc63d2137, - 0xd3849798, 0x68efe4bc, 0xe8a2f93f, 0xc3b7f732, 0x5d0d10d9, 0xcba2c6b6, - 0x4b37a879, 0x3999fcf9, 0x9343fe72, 0x8c7c8ebe, 0x49b29ba6, 0x977c83cc, - 0x5876cf01, 0x66caa76f, 0x807d43ec, 0x9844d6b6, 0xe636cddf, 0x393e9900, - 0x32677cb5, 0xe7acb7ac, 0x3f219180, 0x1d693a74, 0xf47da275, 0x8e14a6b8, - 0x838a533f, 0x3dc7499e, 0xf8014f4f, 0xb824f676, 0x99d4f814, 0x0630fa02, - 0xbc088f7c, 0x9fc6d633, 0xf21c686a, 0xb65fac8f, 0xc3767988, 0x6b0250f3, - 0xb2bd8335, 0xc607c84f, 0x154fe7ee, 0x99c61718, 0xdde8cafd, 0xf58a2f64, - 0x80b5021f, 0x43d3d3f5, 0x77fd14e3, 0x585edbc0, 0xeade047d, 0xdbc221cd, - 0x6bdf46db, 0xe3c69f08, 0x772c74a1, 0x87933d1e, 0x70b670f8, 0x25efb5fb, - 0x6ee9006b, 0xd3d67e20, 0x0e2eeafc, 0x81e2fe62, 0x8353ab78, 0x2eeb5fa4, - 0x5877d1e6, 0x129cdfb7, 0x6c1b3efe, 0x2eb00986, 0x4270e666, 0x47c2c4f8, - 0x896be0bb, 0xa3eb500f, 0x081f02ed, 0x3ec48fa7, 0x4eef1fa7, 0x780666e3, - 0xefe66b3f, 0xdf246799, 0xfe7d0987, 0x005e4251, 0x0d1f33f7, 0x7a46ce07, - 0x91e95d50, 0xe2cea77a, 0xac3e6fb9, 0x67abbd9b, 0x5963c04f, 0xed15ada5, - 0x4f2665ab, 0xcb5dda12, 0xeb2bd3de, 0xc48409f3, 0x3c042b07, 0x5df732cf, - 0x36ff3f88, 0xc209e38b, 0x97ff769f, 0xf8bca3bf, 0xa2bf681d, 0x9346ef4b, - 0xcda56971, 0xf596fd8f, 0x876d3c54, 0xad5b2bf7, 0x2efd062e, 0x04fee29b, - 0xf765bded, 0xf21b5c59, 0xa438bf71, 0x5dfa0b3c, 0x03be60fb, 0x9d7581e5, - 0x06ecd337, 0xeb7ee093, 0x6de02b4c, 0x8964b293, 0x7dac0852, 0x1516ca7f, - 0x57feacf0, 0x281667e5, 0xc17f755f, 0x8c75f316, 0x1cb282bd, 0xd0ff59ed, - 0xfedf6899, 0xf646a712, 0x7f6fb72e, 0xca274479, 0x82a65bc5, 0xece5180a, - 0xce60d9d4, 0xb78a532b, 0xf4fc6198, 0x0ea14f14, 0x32935bc6, 0xb7f62661, - 0x7fb1bef4, 0x77df09dd, 0xa99acca4, 0x44de13e6, 0xcaccef7b, 0x926ed0a1, - 0x54b3cf2c, 0x56697f42, 0x27a7b616, 0x090fbf00, 0x77f68f8f, 0xbdfdbf67, - 0x1cd4e660, 0x53454bc0, 0xbffd0aa5, 0x96db729e, 0x36315731, 0x877281fe, - 0x983fc607, 0x15a664b2, 0x9469dff0, 0xf16d97f5, 0xcc9d58c0, 0xbe0186f7, - 0xbafef1ff, 0x9fa86699, 0x742dea96, 0xcd53fac0, 0x91996ff7, 0x65f81dfb, - 0x4fbd12a4, 0x1271482c, 0x90461cdf, 0x33ebade6, 0xf82afd72, 0x71d3873d, - 0x9424797f, 0x4ce511ed, 0x10dcee5e, 0x4e9c7e5b, 0x33b972e5, 0x8f77f621, - 0xef004b90, 0xb3e90ea0, 0x96181acb, 0xc027961f, 0xc409e64f, 0x3cb9db5f, - 0x639abe01, 0xd98e3e27, 0x5fe537df, 0xd3f53b80, 0xe8ac7aa9, 0x0d7290bf, - 0x71c56666, 0x69764cbe, 0xcf5975e4, 0xbfb79252, 0xeb7c154a, 0x5671f0e2, - 0x330ae56a, 0xb8470cf7, 0xc58b76c8, 0x4b47f33a, 0x88d052ff, 0xe2d6b9fc, - 0xacf9c0c9, 0xc19e57dd, 0xd787632e, 0xf8d72c5d, 0x98ebc24b, 0xf407ef4a, - 0x44b9fd0b, 0x5f31eeff, 0x57c95e07, 0x7d1a5780, 0xc33ad2bf, 0x3bfd69fd, - 0x7ee3fb03, 0xc57a019e, 0x1b9e7b18, 0x415eb853, 0xe422ebf8, 0x5f214ada, - 0x3d916a41, 0xabc5fe7e, 0x8fcd6f76, 0xf503771c, 0x7a7df80f, 0x412fee0a, - 0x2b1ca2be, 0xb0b33d53, 0x8a4f597e, 0xa079ed03, 0xde828db7, 0x8937a454, - 0xa694cee7, 0x76ef5a72, 0x863bb1c5, 0x3913f81d, 0x83c536af, 0x22c649f6, - 0xc4497e9f, 0x87fca4fc, 0xff453bfe, 0x1f9e9c25, 0xc5e7a7ed, 0x2fc23fc8, - 0xdf40dcc4, 0x5fce0763, 0x08ce36c1, 0x2582f5fd, 0x7091f380, 0x2ff4b6fb, - 0xb8ba87ed, 0xda912a7a, 0x260f1c65, 0x219ea0ba, 0xb9f9c5c5, 0x6bc4e3e3, - 0xe9755f51, 0xebe2e299, 0x2651b946, 0xe7bfa4e5, 0x764a8548, 0xbb2e584c, - 0x72919ec8, 0x87366833, 0xbdbfdfeb, 0x9446c667, 0x2fbe26ab, 0x1483d34f, - 0xe3cf0a2f, 0x2fae14e5, 0x2798f827, 0x24781d96, 0x08e52ed9, 0x75e1e3ad, - 0x5863ec95, 0xd7e85d9f, 0xf93f2109, 0x664c9eb3, 0xf0e13ec2, 0xb67bfa90, - 0xdcaff429, 0x47a5a64f, 0xa53b0659, 0xee105741, 0x89cfbf1f, 0x8263fba0, - 0xf3f1a20e, 0xc013e55d, 0x48708fc1, 0xc872e14d, 0xed056509, 0x17f4150b, - 0xb55cffc0, 0x3f35bdcd, 0x2e36de62, 0x1d7a9d8f, 0xe0576397, 0xfe54b48b, - 0x3b25efbd, 0x1e1873f1, 0x2ff98edc, 0x1d76f701, 0xc17dc1ab, 0x09f01d21, - 0xaf8da2d2, 0x598bfcf3, 0x29e7efd4, 0xeffeb93a, 0x1bb72e45, 0xd7ce3c61, - 0xbfd63f64, 0x3b5da83c, 0xdcdfde7f, 0x658f4e54, 0x68853dc7, 0xdaf30cc7, - 0x285fb8dc, 0xc07399eb, 0xdde1e500, 0x4b6b038a, 0xc1de1f3a, 0x4ba814f9, - 0x67ade5c0, 0xa5b5fb22, 0xbefa3a72, 0x38fc31d6, 0xcbc457a7, 0xcd3e08e2, - 0x7871b54d, 0x084cfac1, 0x472b554f, 0x9bfbf3e5, 0x0180f787, 0xf0075bd6, - 0xe12db140, 0x64b1d9d6, 0xf8f90583, 0x1f237338, 0xa258ef9f, 0xdd788b1b, - 0xebbec8c9, 0xf00f0f97, 0x147b4875, 0xe903b2e8, 0x5cd4eaf2, 0x71d86f1a, - 0x7c0c758f, 0x1376861f, 0xec3b95fa, 0x4c57dc01, 0x4dcdf54e, 0xedce7845, - 0x4a2064ab, 0xeb4dac1a, 0xfbef112d, 0x7d4177eb, 0x7e9f63a2, 0x36f3ce2c, - 0xc2bab6c6, 0xfaa981eb, 0x6f5a1fd1, 0xa02d3e04, 0xd6e11072, 0xfbf5e469, - 0xcf8a3316, 0x8cfbe834, 0xf7f41df8, 0xa3cfa22c, 0x2fc414ba, 0x6ed09bee, - 0x737bd3ae, 0x67d7dc14, 0x07a8dc98, 0xf4421f60, 0x54c2c87e, 0x26fff40b, - 0x574e513c, 0x8fd8efe9, 0x502aaaf0, 0xae242ddc, 0x60dc85da, 0xcd37dc41, - 0x7a25629e, 0x39dd5f64, 0xbff51ab4, 0xfa09e395, 0xcc7e8b31, 0xff30a2e6, - 0x2aef3afd, 0xfd48ffda, 0xa8514876, 0x8dd7439f, 0xb112ddde, 0x50fec22f, - 0xaa521ffe, 0xfa40ee73, 0xb23afb17, 0x7ac2d30f, 0x2295ed17, 0xfdde245b, - 0x3ca17e62, 0x7b48a3a4, 0x7ed3ed14, 0xb1dfd67b, 0xd9c83a65, 0x823a33f1, - 0xd152073a, 0x01ff33f3, 0xf60551d6, 0x70e005ac, 0x33972a5b, 0xfafdf287, - 0x30df9c44, 0x3abc3f58, 0xd31be09c, 0x938f0b64, 0xe90ffc2e, 0x482fee46, - 0xbfcfe04f, 0xe73b72a7, 0x1e5c6927, 0x978d21fe, 0xfb6313d3, 0xf510be2b, - 0x1f971354, 0xfcb9cb5b, 0x41b7ae8f, 0xedadfbf4, 0x668a31de, 0xef760f7f, - 0xf76e5486, 0x885fb91a, 0x0a9613c7, 0x873b06fa, 0xabb614f0, 0xda503c78, - 0xccf45fa1, 0xf372f2a3, 0xbfe8d97b, 0xe69fedbf, 0xb6f487dd, 0xf27a37f2, - 0xf1149c57, 0xbec99582, 0xbfdc64f4, 0xabf6c427, 0x75d6273c, 0x1f9199ba, - 0x1b8c53f8, 0x893dec82, 0xaf284371, 0x34e0f9da, 0x2cd5bfe4, 0xe5e0fe40, - 0x5c51373b, 0x61407970, 0x69f7052e, 0x1627ee5e, 0x47bd58f8, 0xdf4bf1af, - 0x931936ae, 0x77e984c7, 0x6e369b45, 0x58abb358, 0xf6f6fe53, 0x440b2569, - 0xfcb0a1c8, 0xa3ef4699, 0x1ef495fb, 0xd47ea76d, 0xc3f8d2ec, 0x461cee97, - 0x97f597eb, 0x77ad3731, 0x66816b59, 0xf395acde, 0x49f9bc49, 0xd4bb45ba, - 0x469e731f, 0x008ffbcd, 0xff08fefe, 0x4353d2ff, 0xa92d1e69, 0xba40ffbe, - 0xcac3cf09, 0xdabf1afc, 0xb027c724, 0x7ee16656, 0xff23a049, 0x5081ece5, - 0x6fffa72a, 0x71d1f70f, 0xfee305f6, 0xca0beebf, 0xcc397126, 0x0c3614da, - 0x6aa7e31e, 0xa0bfb4ed, 0xa7c52bbe, 0x616beb95, 0xa45f2d47, 0xd45177ad, - 0x5dea28bb, 0x6912bfc9, 0x2805299f, 0x0d7f78d7, 0xcff38f82, 0xa0ba351c, - 0x6e34f8de, 0x3d3916c7, 0x6cef5097, 0x438e24b3, 0x4b36ca7f, 0x52f5005e, - 0x38bafaff, 0x48336d1d, 0x033b8a3f, 0x5ffed6e1, 0x88a8b677, 0x0fb07dc7, - 0xfe587900, 0x8a1641e8, 0xae375390, 0x01cb3c53, 0xef2176de, 0x7d7cdcea, - 0x71a0ee75, 0x5d93f428, 0xd395e7c7, 0x23515fb1, 0x08d4e5da, 0x419a5f7f, - 0xc1cccfb3, 0x8d254e32, 0x9a9ce3cb, 0xea1432a0, 0xa3daef65, 0x875fd8a8, - 0xbb337a42, 0x41130009, 0xdc25d957, 0xa4b1b9be, 0x2636595d, 0x5d56870c, - 0xe00718f5, 0xeadd35a7, 0x8f737d46, 0x0d2437d3, 0x182279e7, 0xf8fcedc4, - 0xda2a3d13, 0x7a753fef, 0x619cd20a, 0x8ef4b838, 0xd6a7d46c, 0x6d9e7c13, - 0xae63fbfd, 0x4da22867, 0xdcddabfe, 0x23b3d19e, 0xa487db8c, 0x8c37d2af, - 0xe727bd24, 0xf4229e97, 0x3df33a45, 0xadfaa367, 0x68c9f08c, 0x861be93d, - 0x2cf6e6ef, 0x815577c7, 0xafbe0f77, 0xa8aab8ca, 0x6c17de05, 0xa14baa0b, - 0x62bbcbdd, 0x85cb83fb, 0x4c75813e, 0x75c9f5c2, 0xc82e495c, 0x7e38867a, - 0xd60fc90a, 0x1ff7b119, 0x2f7d2230, 0x216d347f, 0xa36eb7ce, 0x30949991, - 0xf4ea7ffc, 0x64f9c6ce, 0x082bb477, 0x93dfe91b, 0x1dff4ae3, 0xfcfe477e, - 0x96f928c8, 0xfe5c5fd3, 0x2cf7a75f, 0x1b67948f, 0x6927848d, 0xc7e7873f, - 0x69d5fded, 0xeabecf5c, 0xf9c12ef4, 0x276d7434, 0x3daacf7f, 0xf9631a1f, - 0xe2f9a3ab, 0x6a54704a, 0x6ea0bef8, 0xeb8039be, 0x25547f2f, 0x68dda83a, - 0xdd5938a4, 0x9fb8fb33, 0x46e61ee7, 0xb1d75139, 0xe30e594f, 0x4fb33ed6, - 0xd7011159, 0x05017541, 0x2ec233e7, 0xafcb90f9, 0x3f47ba68, 0x872dda32, - 0x9c4e5c2d, 0x15f9b72d, 0x8359eb80, 0x9deb0eaf, 0xfdbab2cd, 0xbc3c61f9, - 0x11fa6fb9, 0x3fb037cc, 0xb3e20a67, 0xd33bb755, 0x475af50c, 0x5f48dd19, - 0x36fa753f, 0x54525c23, 0x4fb6276f, 0xd7bbb34e, 0x89975b43, 0xfbbca115, - 0x1f1870ba, 0xefe32745, 0x85d3fce1, 0x91db8872, 0x813fc845, 0xa7b4bb34, - 0x361dae48, 0xc73c75f0, 0x9eff7cf8, 0xe89079ea, 0x8d0a48f8, 0x54175d9b, - 0x7f9d9fd0, 0x6b9239e6, 0x9d30ffb2, 0xe4891e79, 0xb3cf2bdf, 0x56f488c3, - 0xf950e42b, 0x8f947ba3, 0x4bfde623, 0x6e91f430, 0xba019fb2, 0xfdf7d1b4, - 0x3ea8d333, 0xbdf0b933, 0xe16aed42, 0x79088afb, 0x4311d723, 0xf5c3ecee, - 0x1cf44ed8, 0xc82772e4, 0xbe628dfd, 0x157cf8d1, 0x9a7c1fe5, 0xde99ea06, - 0x3123fd1b, 0x48787a2e, 0xe527f502, 0xbedf3440, 0xe51ce82a, 0xfe46cea5, - 0xe52bb25a, 0x22bd64fc, 0x34fec567, 0xc10f4382, 0x4a977ea1, 0x7a32a9eb, - 0xc111de87, 0xfd16bf0f, 0x03f9b81d, 0x07fdca23, 0xa25dfdfe, 0x8536fac7, - 0xedacf1e2, 0xd43ce35d, 0xf4a7fe47, 0xe2ce6768, 0xf1db0126, 0xa784bbc2, - 0x2e5c9d59, 0x53ee77d7, 0x74c2d997, 0xc0e67f9a, 0xf56748ad, 0xfb86261d, - 0xdfbfa022, 0xe9a27c20, 0xca47c254, 0xb4f878dd, 0x9472e0ce, 0x47e48df9, - 0x3e54fd85, 0xdca429fa, 0x4eaa7bfe, 0xfbf809f8, 0x1cbc690b, 0xa7df1fa6, - 0xdcb08f08, 0xe45f10b5, 0x603a299f, 0x5bb87dc6, 0x5a7f3f21, 0xe4678725, - 0xc6c7aabc, 0x54ce9b97, 0x50d437a1, 0x587b1cde, 0x7fcbf7be, 0x810bfed1, - 0xe41f786f, 0xd410d9ef, 0xd1fe72f3, 0x7277cbf8, 0xce831b7d, 0x11d71bfe, - 0x3da4dfad, 0xc9e6e920, 0x8f46aa5d, 0xea469dd8, 0x731b0ecf, 0x728ec79c, - 0x61d8cf1e, 0xc76cfae0, 0xe500737a, 0x780b9bc9, 0xa17d995e, 0x43cf8831, - 0xf875a5ba, 0x1f3650fd, 0x5ba755bf, 0x0dd6e583, 0x7842d636, 0x4b3a24f5, - 0x19127e91, 0x1e5c8f97, 0x973cf03e, 0x5b7e7567, 0xeb3fc180, 0x5397737c, - 0xe2cd39dc, 0xf333b8c6, 0xb3ce341d, 0xd72ba40f, 0x2e8dfb73, 0x83ab3f78, - 0x03c49ff3, 0x2fa253c8, 0xae120fc9, 0xb8727861, 0xf8927e4b, 0x67f4bbf8, - 0xa77cbd03, 0xda3daabc, 0x46dbdc78, 0xbe4ed5df, 0x706c3acf, 0xc7869fa1, - 0x6fd1e217, 0xb3b7baed, 0xb51d824f, 0x7a2df33a, 0xfd85be4a, 0x27bf86ac, - 0x3817bc09, 0x74afbeb9, 0x2da9ba72, 0xacbe20e9, 0xfc44d93d, 0xe5c19b6c, - 0x5684ed9a, 0xcff6331e, 0xa8dbbd62, 0x63b5955d, 0x5477e61a, 0x7038ae3d, - 0x6e4f1fbf, 0xfcf0aede, 0xbd774fb8, 0x72f98891, 0xf2b02bec, 0xe1629e31, - 0xe4eb9deb, 0x5eece272, 0x7bd13800, 0xf672f193, 0x63fa95fb, 0xc20a63c1, - 0xfac056b3, 0x139533ec, 0xec7e84ff, 0x61ee49bd, 0x9ecfe4b0, 0x3feee9b9, - 0xeecfbcc1, 0xf746e299, 0x978b5a65, 0x69cfa7e8, 0x037ee371, 0xf40cf7c4, - 0x78efae17, 0x685af123, 0xabe9fa77, 0xd76e508b, 0x799e798a, 0xe10ebf5e, - 0x7fc9e1b2, 0x6bdf8c9b, 0x09aa4a03, 0xf8fbd9c7, 0xbe63677f, 0xf2469eea, - 0xfd3cb517, 0x17f311ba, 0xfe768174, 0x03926f7e, 0xf9fe9deb, 0xef08c9f6, - 0xfa168e96, 0xede7e67e, 0xe4f03e54, 0x77f6bdbf, 0x1378e3f4, 0xccef58dd, - 0x2f09fbf3, 0xf2953e75, 0xf5d1e2db, 0xb9fb7d8e, 0x8f3d44bc, 0xcb9f307c, - 0x92d74931, 0x793f4f7e, 0xbd48c4db, 0x0ab7df21, 0x026b4e7f, 0x099f23d7, - 0xe0adadfe, 0x9ecfcef1, 0xfda7ccb5, 0x1c343181, 0x6375c5f7, 0x2ddc5d38, - 0x71d751e0, 0x46c1a187, 0xdf9fa9ed, 0x73e3df02, 0x27e7d02c, 0x64852923, - 0xd7ca25cf, 0x0faa57f9, 0xbfa026f5, 0x1f45e6e7, 0xeb1f382a, 0x2d432698, - 0xfe69f3cd, 0xf91d561d, 0x6c6d6cbd, 0x38bffb3f, 0xe02ec26d, 0x59dd907c, - 0x3922e39d, 0x8b0f7260, 0x6bb387b0, 0x27182d7c, 0xcfad7ebe, 0xbe3c07ad, - 0xb4e8ea7c, 0x727e5041, 0xf84c52a4, 0xcf5c2bd7, 0x4e346df9, 0x81c1fa3d, - 0x3e0b768f, 0xf5307749, 0xdc03921a, 0x32a5501f, 0xaa7e46d5, 0xf513923e, - 0xee0f42ad, 0x736e7e11, 0x764dde5f, 0x26bb676a, 0xed061f62, 0xf72a366c, - 0xf310fde5, 0xe7f8674a, 0x1971de93, 0xa467be69, 0xf27e603c, 0x8b7e4a7b, - 0xbca11bf6, 0x57d1fcc1, 0x285de59d, 0x3d33e51f, 0xefe4bf8e, 0x74b8fbe2, - 0x15ca174f, 0xa35537b6, 0x95c9e20f, 0xe79f3703, 0x0f95fb7a, 0x901b0e89, - 0xdf7c710e, 0x5ede8d49, 0xe815c24e, 0x890fa5f0, 0x7177970e, 0x55d0daf9, - 0xd4fdc46e, 0x69d7e10e, 0x7484f410, 0xbfe8fb84, 0x9c69933a, 0xe1a1c986, - 0x0bcea728, 0x12ff3bba, 0x3a43b7a7, 0x0e01f91d, 0xdedd1eed, 0x8fd40ca2, - 0xf0978d4a, 0xe6f800dd, 0xa3daf376, 0xd7d56768, 0x6bf23730, 0x07e0a743, - 0xbe117bb0, 0xcbd55d0d, 0x6941bfb1, 0x0ddfc933, 0x41b4c976, 0x63a86e50, - 0xd96fc8a5, 0x425e2abb, 0x7c5d60ba, 0x035d9e3f, 0x4dd22cf6, 0x9f5bbd5a, - 0xdb8f7a8f, 0x2c8fd7bd, 0x723bf6a3, 0xf2e7145d, 0xf38a3157, 0x19fb40ef, - 0x68d65df5, 0x36fb3f6e, 0x5cc5dd92, 0x6537e409, 0xd60d753e, 0x622ff06f, - 0xcd11d794, 0xb4292fc7, 0x5808680f, 0x56681f29, 0x1a7fb717, 0x9f1f38ba, - 0x4f91f093, 0xe4adcf43, 0xc4c17f8f, 0xd0fe11fc, 0xce9a5f37, 0x268becf5, - 0x359fb3d2, 0xb0c7d87b, 0xbc85b7a0, 0x6dac7097, 0xdd21d7cb, 0x09937632, - 0xcc4cb1e7, 0xf5c0cda3, 0x03d0b246, 0x3cf8db05, 0x77e174d4, 0xa789d74c, - 0xe2e79b51, 0xe17f93f0, 0xc88f189c, 0x39e85d22, 0x797eba18, 0xeea4f890, - 0x9a5fde19, 0x677853c9, 0xfb4abd04, 0x0b1e9a28, 0xbbd9b8c4, 0x4c282a0e, - 0xd1cd77b2, 0x35f5f9f0, 0xeb08d82c, 0x2e977ebc, 0xd91c6538, 0x9e490b4d, - 0x58b237af, 0xd2232af9, 0x9556fdb9, 0xbf442dea, 0x36cdd576, 0xb93fa477, - 0xb3a3c12a, 0x24571da0, 0x12ded8fd, 0x4a9d1b8c, 0x6f11bbb7, 0xd25dd2e3, - 0x5bd8d30e, 0xdcdff703, 0xcda1bc0e, 0x1ff70e3f, 0xf309f581, 0xda09ae29, - 0x0edcfc8d, 0xf7fb8f68, 0x9cfed7dd, 0xb85bdfef, 0x070402ff, 0x6f5499c9, - 0x9d8ffa09, 0x5cb5de05, 0xb1ddd93f, 0x93aaf3d6, 0xcdc0e7af, 0x3ee216b7, - 0x8dae61b1, 0x5781e1f8, 0xde9ca594, 0xbee21140, 0x83f9c7da, 0xe13c7f01, - 0x3b247a22, 0x1bc9a1aa, 0x9c8f4d88, 0xaec01a5f, 0xe81b3b42, 0x93b70d71, - 0x13f38c6d, 0xbfb94ba7, 0x6915b947, 0x8d3e4acf, 0xbf497be6, 0x35ff7cfd, - 0x81bcfdf9, 0x8079e3f3, 0x3f7bd203, 0xe9ccbf9d, 0xe07aeb7c, 0x15bef847, - 0x4225b1f8, 0x7fef47fe, 0x1fb89e70, 0x1ef6f290, 0x3a5177a7, 0x6fdda1ca, - 0xab50c66d, 0x2f0d8f94, 0x397e196f, 0x958ccbbb, 0xf0335fa1, 0x60fd246b, - 0x445ed68c, 0x09ea3f4f, 0xfed8baeb, 0x6dd2bb8f, 0x3f3fcddf, 0xaee52f30, - 0x7981d2f4, 0x73a8e929, 0xadbb6f10, 0xa58fb401, 0x3e7a291f, 0x499f044b, - 0x03fdca7c, 0xfeb021c6, 0x37ef82fd, 0x888f7a89, 0x84bec467, 0xf3a5c1f8, - 0xf679487d, 0x6c91f471, 0xb5f97df7, 0x2f5238e4, 0x8c8dd346, 0xaa7ae0a3, - 0xd7afc4c7, 0xcfec5fb6, 0x29f8e8a2, 0x800b5fc1, 0x6dde7037, 0xc417e086, - 0x19d8778f, 0x99f813e5, 0x71e31527, 0x7ce08daf, 0x386fb234, 0xfa66b7b6, - 0x92ba44be, 0x8f7c5d7e, 0x115aaa71, 0x6bddacbf, 0x7f9e4408, 0xd18337b9, - 0xb376bd38, 0x91fc0f5f, 0x87dbe99b, 0xcc15fded, 0xf33d441d, 0x2b8a168f, - 0x8a5b8181, 0x8591a6f2, 0xefce1112, 0x205efb25, 0x0cf7d5fa, 0x39e3bf47, - 0xdf0e3425, 0xdafe109f, 0xfb5fc213, 0xcf7bd77e, 0x17ad02be, 0xf16e72bf, - 0x5ece918f, 0x7d21e4b4, 0xe7f4b09c, 0xdda125bf, 0x92b9817d, 0x690e772e, - 0x55ef5991, 0x2767fc23, 0x7ffdb1ec, 0x373c0b6f, 0x532b788a, 0xb7c3ed19, - 0x19f97067, 0xe3c4bf3e, 0xb4ebefad, 0x1cf937fe, 0xdfe1c193, 0x501ce719, - 0xd7df0661, 0xfce10e74, 0x50aed7d8, 0xdd66afbc, 0x41eb3ffa, 0xb5acd42e, - 0x9f09e907, 0x71ab8ed1, 0x283a83f8, 0xb970309f, 0xcd737f04, 0x07fd6165, - 0xc849d4f5, 0xc5077e33, 0xfd0a96bf, 0xcde9acb5, 0xa15fa1bf, 0x49e66546, - 0xf2c71845, 0x9f041e1e, 0x4f2db53e, 0xf2bff144, 0xa3a67747, 0xd458ca7e, - 0xa6c1f226, 0x55fed03a, 0x2fe8373c, 0x6f672f59, 0x132764a9, 0x1ede001d, - 0x22f6f0cc, 0xe24a2f1f, 0x7745c17e, 0x08fe035a, 0xf057b879, 0x7cfd3461, - 0xcdbce710, 0x01151997, 0xaa616fec, 0xefd46ff7, 0x7234e79d, 0xfa12bced, - 0x5f4823c5, 0x4fddd877, 0x22f2eef0, 0x05d263f3, 0x0e316bfc, 0xb7b1a204, - 0xbaf867b0, 0xbee3a47c, 0x5fa1dfbc, 0xf0e4dbab, 0x91bbf0bb, 0xf176cbbe, - 0xe3f141e2, 0xd2232e40, 0x8545c347, 0xf76961e8, 0xae51c79b, 0xa221a837, - 0x1b66a593, 0xa2e1b1e1, 0xd5a9e9ca, 0xdb243670, 0xa4d7ee03, 0x6032d27a, - 0x277bfe9e, 0x093c5325, 0x17c389f8, 0xe39c452a, 0x37c332f8, 0xf7e00328, - 0x36f13590, 0x305d7fdc, 0x8f3092bb, 0xf408d1ad, 0xe7753570, 0x43d84735, - 0xa5aec72c, 0xfeb7ee83, 0x6e5af386, 0xaf5119f6, 0xd134f0af, 0x4945b179, - 0x98c752c1, 0xd24fbc48, 0xf5fd1a5f, 0xc8497ef1, 0x3c8df797, 0x9d20646f, - 0xcf6c3c73, 0x39b2f510, 0xc79fbcbf, 0xe7c39e6a, 0xbb427828, 0x728887f7, - 0x170f2891, 0x7979d2f5, 0xf797e09a, 0xd17af1c7, 0xe3152ce3, 0x99e1997c, - 0x7682708c, 0xc7d22341, 0x673a166b, 0xfe404ac4, 0x935bbca1, 0xc82c764b, - 0x770869b9, 0x4c982718, 0x67a44cf5, 0x41c81358, 0xa96f67c0, 0xb5b3e08b, - 0xe305e81c, 0x289aaf41, 0x2bf1241e, 0xcf8d1af1, 0x77ca1985, 0x181f4fcb, - 0x51985ebf, 0xcd7e303a, 0x17c250d8, 0xf38c4bd1, 0xf5f0f11f, 0x03c73b6b, - 0x0cf2ebf0, 0xb1c183d2, 0x49b37c91, 0xb5ca51c0, 0x78b413f7, 0xe39d3cfd, - 0xbbd45ea1, 0xda1f7684, 0xe23eeed1, 0x7853f7bf, 0xae02b4fd, 0xfe5da497, - 0x5f2e024f, 0x529f6ba6, 0xd1fb44cf, 0xe2f214bf, 0x47ee74cb, 0x8ddebc07, - 0x09fa95f3, 0x19304ce4, 0xebd178f8, 0x6c339226, 0xd5e51f63, 0x83ffbd40, - 0xea645af0, 0xf41535bb, 0xdec10fca, 0xbb511631, 0x0647284b, 0x48c7efec, - 0xd433b0ba, 0x0e19addb, 0xf4941f6e, 0x48d7b8f1, 0x0ca5aebe, 0x657287e4, - 0x210c63fc, 0x6bf0e40b, 0xc142bf22, 0x6214aebc, 0x07f61767, 0x8c97ff70, - 0xa3dc30d2, 0xe8213bc7, 0x450cd1e0, 0xb215bc25, 0xaddbc442, 0x5f6e7eef, - 0x139e5d0c, 0x4d9365e7, 0xe7ec76be, 0x916fddec, 0x18c27e9d, 0x8b66de1c, - 0x7c18ddf1, 0xfc2521ec, 0xf4a7b6fd, 0x98d5e37e, 0xc1f67e7f, 0x4bdd619b, - 0x1c6ef47b, 0x5f3de972, 0xed1e33bc, 0xc5031eec, 0x6fdf406b, 0x4dde7153, - 0xa13caedc, 0x67c1d2d3, 0x3df76977, 0x907a0baf, 0xdca572e7, 0x157cfa91, - 0x93797373, 0xcb1bb890, 0x3b71dd1f, 0xce5dcb9d, 0x003d87bc, 0x666bd3f7, - 0x3b7c5d92, 0xcf5e51f3, 0x39ed56b2, 0xda6d15db, 0x073bedf2, 0x3925c39c, - 0xfd102abc, 0x2ba5f85e, 0xf3fbeb63, 0x333f2e82, 0x7afdf88a, 0xfdf8cc53, - 0x09fc85ef, 0xb4fbd9c7, 0x2f57fbf1, 0x8c6fbf1f, 0xed87df8a, 0x3df8e888, - 0x6113f7ef, 0x91bf606f, 0x2acffc71, 0xa3e3af62, 0x58b7690c, 0x9f19f935, - 0x125bb00c, 0x45e37be9, 0xd8f99c4b, 0x2b67fde8, 0xd7d38f63, 0x5f368e3f, - 0xe79edc20, 0xb5fdc809, 0x8bc693a4, 0x6567a459, 0xe1c7da59, 0x3df43976, - 0xf4babcfa, 0xf8be4b6f, 0x2ce66158, 0x176d47f2, 0xf29bbc76, 0xbb463f33, - 0xba72f908, 0x4c10b5eb, 0x278fd971, 0x8487570e, 0x1d7a26f9, 0x42675f40, - 0x98d8f211, 0xfd234f69, 0x3a6e66eb, 0xfee82797, 0xe8abbbd6, 0xbdffcf7c, - 0x322332a7, 0x53f72a6e, 0x8f69460d, 0x96fa34d9, 0x65e3e945, 0x1d916f5d, - 0x70d7f606, 0x7a7f3e14, 0xc3d26ef5, 0x1d37992b, 0xd5f7bde9, 0xe56e7411, - 0x3961eadb, 0x4bfc9b9f, 0x35bf3c0c, 0x3987ec8d, 0x75373e62, 0x67503b73, - 0x1c6818f6, 0xd239730f, 0xe7cd8b69, 0x8554420b, 0xf3fd75f2, 0x631de747, - 0x15fcc493, 0xbdf00f6c, 0x52d93c4e, 0xdbce265f, 0x31eae384, 0x8990260d, - 0x6e8996cf, 0x28a73e17, 0x83cf955e, 0x6b1a79e3, 0x3afac1ca, 0xd7cf4873, - 0xc7483309, 0xa2f0fdf6, 0x37945db2, 0xeb70bdce, 0xb36f7c0a, 0x8a313c93, - 0x04cf4c79, 0x6dfc88b9, 0xb75c6666, 0x4d3c16c9, 0xf4f133f1, 0x8f88b857, - 0xf91843fd, 0x07581241, 0xd9b53f9d, 0xb171f9ce, 0xb050e60e, 0x085c716c, - 0x9ce27ee2, 0xf3c7e6c3, 0x672f20c4, 0x5f3fa265, 0xc44ad5f9, 0xee67c80b, - 0x5df78a17, 0x11f3f20d, 0x88a5de42, 0x7908b5f9, 0x8adcc597, 0xe480c7b8, - 0x95f6fddd, 0x267ee037, 0xa3f7798d, 0x71387bbc, 0x32fdc506, 0x93e68f98, - 0xc8d5433a, 0x5b57a72d, 0x46af98ce, 0xe7053bcb, 0xbed3e597, 0x9413b337, - 0xbd04a497, 0x69529799, 0xfd12361f, 0x37210631, 0x3e78598e, 0xcf3166c2, - 0x8853333b, 0x78598e6e, 0xb6b7c25e, 0x7ddadc5b, 0x3f0a437d, 0xdd3e7fbf, - 0xc0f1c66c, 0xe113b98e, 0x07cc7607, 0xdfce167e, 0x41d29c2c, 0x6f9b0279, - 0xe01bdc54, 0x6bbb66fd, 0xeba40abd, 0x7f70a99f, 0xc728ea8f, 0x3cf69c7c, - 0x44f31b87, 0xf7be451b, 0xf6a38b66, 0x9a63f219, 0xb7d63d78, 0xed96e319, - 0xac0e1d5b, 0x37d95697, 0xaafb88cd, 0x9bb1cc15, 0xaff7a0c5, 0xbe608f80, - 0xe032c73f, 0x63f41149, 0x85bae23d, 0xefbe20d6, 0xf0177fc1, 0xdc3294f2, - 0x82bff2bf, 0x773a42ee, 0xd27a3cc9, 0x85dd8d97, 0xbc60d86f, 0xe485b982, - 0xf256f7af, 0x72132fb8, 0x571cbc60, 0x61b5d9f0, 0x85efa7ba, 0x5bb43ca2, - 0x4cd37ff8, 0x80ebae3c, 0x91c4ca21, 0xc69fac43, 0xe4cdc1f9, 0x6bd3e71f, - 0xfb0ff858, 0x4ff70cab, 0xf86a6972, 0x60ef9873, 0xbbb322a8, 0x8dea0ea5, - 0x91fb8357, 0xcf15afaf, 0x543cf142, 0xe5e9237e, 0x65cd9d1e, 0x373e71d4, - 0xc3aba017, 0x94b847ab, 0x60b4b639, 0x4129d73f, 0xd8cde67a, 0x9fd382de, - 0xc94cfc23, 0x9e00c699, 0x00996b37, 0xc8bf2678, 0xffa30f9f, 0xac2fff5a, - 0xcc74f118, 0x279ef520, 0xb9ffe789, 0x0ed53d68, 0xce97593e, 0xc22e7b33, - 0xcf3f28f9, 0x8b74d0c6, 0xa997fef8, 0xd7974955, 0x300f3cbb, 0xe5cf4b25, - 0x871e0ce3, 0xa66f9c6d, 0x7146e5bc, 0x7d53030f, 0xf08c3ff9, 0xc5b8c8af, - 0x7f3606bb, 0x46fd8c5f, 0x07b7164a, 0xfdc0dce6, 0x1f228dc2, 0xcc4f7e47, - 0xbfb27ee2, 0x377b4e64, 0x1e3dec93, 0x949dfd6f, 0x48d9235f, 0xf2115f94, - 0x5f248fe5, 0x278edfca, 0x85dfb47f, 0x29e799fc, 0x40bed036, 0xef2921c8, - 0x68ef22bd, 0x1018f301, 0x1ee23d4f, 0xabe5a395, 0xccdd0e48, 0xf7fef47c, - 0x00ff3c15, 0xfd80d308, 0x6b4334dd, 0x6af3cd3f, 0x8fcf37cb, 0x3e38afb6, - 0x7c0bb8e4, 0xa473efda, 0x6b433c9d, 0x87fa2f27, 0xcf4992af, 0xfea2fc67, - 0x3e70e0d2, 0x3e546351, 0x27c88351, 0x3c2aec6a, 0x4f911694, 0xf3cdd8d4, - 0xaeba1a89, 0xedc44f94, 0xb029af29, 0xde24e31f, 0xec94d25a, 0x727f910d, - 0x8a4ff310, 0xaf6e74c2, 0x0c3cf3b0, 0xa2bca1e6, 0xce95871c, 0x8aeab45d, - 0x9adb8fc8, 0xddf8d768, 0x5577aeb7, 0xbfe93d61, 0x4843f995, 0xc3f6b137, - 0x5f7c59d9, 0x7ee143b3, 0x3302ff74, 0x059d3bed, 0xc15c4d5e, 0xd1c767a9, - 0xa66ef8af, 0x3f27d64b, 0x2f830ec9, 0x019e18ab, 0x8979d185, 0xb67af6fe, - 0x5190fc91, 0xea99ca72, 0x338038a6, 0xf5f92c69, 0x921775e7, 0x2cd9923f, - 0xb84a61ee, 0xdb7379ff, 0x69ebcc55, 0x97576eec, 0x3774c2db, 0x43ec4b36, - 0xf48accac, 0x7bd7efda, 0xbd7e44ce, 0x30b79364, 0x19d7da0b, 0x8bbfe483, - 0x1f7a57a0, 0x2ede5f4f, 0xe150c5e8, 0xe602b05d, 0xd18efbd7, 0x0a6bfb8d, - 0xcfff41cc, 0x7e4c94bf, 0x230e7549, 0x9cb1b53d, 0xf45e93cb, 0x3e3ac193, - 0xfaf7e64d, 0xa466ac6c, 0x4ca7cf5f, 0xc55e3a23, 0xe83d8702, 0x7405db47, - 0xd2cf7918, 0x8eb96d1e, 0xa9fe9075, 0x3d00667b, 0xf2947c93, 0xf4b99eb8, - 0x741b8c06, 0xa1b3db6a, 0x285c395a, 0xbcf147f4, 0xff982da9, 0xf2e3ac50, - 0x0f772d91, 0xf5fb439a, 0x2c4f8e45, 0xa17f7228, 0xebaece5c, 0x73d29fb5, - 0xa17ae7fe, 0xad1ff454, 0x3d854abf, 0x17e41937, 0x7da56fee, 0x7ca9f506, - 0xcfadd750, 0x59e785d4, 0xbb49da22, 0x890bea50, 0x8c09f2af, 0xbbb579e1, - 0x1a7c84b2, 0xbe2086c2, 0x13e27fa1, 0x29583705, 0xf71fbfd4, 0xf18ad785, - 0xa8fc1e80, 0x733afdbf, 0xb36be900, 0xd2fa44d2, 0x3c3ff68c, 0xd23e2ab7, - 0xe35eff0b, 0x4c7d23d7, 0xdd374d64, 0x9926f500, 0xb728ac7b, 0x31fe4e80, - 0x585a7e92, 0xa29f6f30, 0x7efa23a1, 0x98edf936, 0x5af52474, 0x9edcf7f0, - 0x74bcc599, 0x0fe793cf, 0xa83aeedc, 0xd8267df0, 0xeed1079f, 0x93375b7a, - 0x2c2664e8, 0x3955eb03, 0x9e9ff8b4, 0xdf472da9, 0x5ad0c50f, 0x48744328, - 0x9c540678, 0x51bdf44f, 0x98f7291e, 0xb3e5ee56, 0xf8de78af, 0x423fc396, - 0x1d7583ff, 0x0ef6891b, 0x8fc4aa58, 0x27b0f4d1, 0xb78f7beb, 0x118ac9ec, - 0x7e15e96f, 0x68586be5, 0x40ca33e5, 0x687f3b7a, 0x82333e9d, 0xbc7f252e, - 0x1379e06c, 0xae3cebca, 0xc6ccc135, 0x252e1104, 0xf928ffdc, 0xd3a41ae3, - 0x95fd3094, 0xa487f789, 0x06cc197c, 0xd75dbd23, 0x01ea0965, 0xbfa2853f, - 0x8afe906b, 0xdc89f6c2, 0x184cb477, 0x98f96740, 0x4cf60e17, 0xb495d201, - 0x8e958a4f, 0xfde73c16, 0xb6f74bfc, 0xe8237ce0, 0xc3842dea, 0x8ae80559, - 0xf4036afc, 0x147bf6ad, 0x4bfc49dd, 0x359cba7b, 0x6e677ed1, 0xc1b3d702, - 0xcf49dbea, 0xba24b882, 0xa70e737b, 0x21e62abb, 0x5a672bba, 0x6b34a97a, - 0x0974d1cb, 0x74b4ea23, 0x8bba23e7, 0x7478d7a6, 0x4ee91837, 0x2bd4dbea, - 0x48e7ddd3, 0x8fc5df77, 0x3eee9039, 0xa7c672cf, 0x937a68bb, 0xc59f6cf2, - 0x75768951, 0xfa428d63, 0xa19df8a1, 0x511e582d, 0xf6764f9f, 0xd93764be, - 0xfc4d8ddd, 0x478f497b, 0x0533798f, 0x7cf7c56b, 0x1b96256f, 0xe877c1d7, - 0xcf18f4ba, 0x0f7a19ab, 0xa1b85eff, 0xbfbc0de9, 0xdbcfd1a0, 0x337a7cbf, - 0x6c0a879d, 0xdbcbed16, 0xd8dcb12a, 0x8a7fdbca, 0x31abae71, 0x82d02dbf, - 0x96daafef, 0x6fdbe6ef, 0x114fd76e, 0x3ca7ddeb, 0x6bb506f7, 0x3f6eede3, - 0xe4604e6c, 0xfaf6e027, 0x29ceb164, 0xd33af8bb, 0x867ebe3e, 0x4563e80b, - 0xb9ec9f9f, 0x6575744f, 0xece2ef24, 0xb695cbb3, 0x474e7c1c, 0xbc47a639, - 0x43f55bbb, 0x37741c78, 0x3675710c, 0xf8c8d3f7, 0x5429e621, 0x5717d847, - 0x443b7367, 0x614f4bd6, 0xfd8d7e74, 0x72fe4ecc, 0x3e0cdf19, 0x07d414c4, - 0x976146b8, 0x4e778cc4, 0xbb22682f, 0x1960fa62, 0x4ba90ce7, 0x4bc2dc61, - 0xe58b4f9f, 0xe6cb2a47, 0x9129f3f6, 0xd7df2177, 0x4875f204, 0x4890fb17, - 0x90f0fce8, 0xdb9ed077, 0xe734cc97, 0xf3e5f6dc, 0xbcecd4f2, 0x01cd6e7f, - 0x549aeaf8, 0xe58bf7bc, 0xf2b79429, 0x4c161e83, 0xff381c4a, 0x1a0b2ae9, - 0xcf8a0f29, 0x518b657f, 0xe5c257dc, 0x3f813cda, 0xd1186936, 0xa7815cef, - 0x17a16cea, 0xca31598b, 0x6f0279a9, 0x1937343f, 0x336ebeb8, 0x798fc944, - 0x1e3f28d9, 0x6bcf6b8e, 0x97c947bf, 0x4aee311a, 0x62afc761, 0xfd3fe47d, - 0xa7f1d844, 0xfc76e61e, 0xfe41d66a, 0x719fded3, 0x961ebe3b, 0xed12f487, - 0xabddad07, 0x6877d72d, 0xdea00dcb, 0xaec6ffb1, 0x8633b928, 0x1f7ba5fb, - 0x3f432fae, 0x77cecd64, 0x235dffc8, 0x2b404ce5, 0xe740c067, 0x51a1e672, - 0xd6fabfe4, 0xd819e3f2, 0xf26995d5, 0x76c9ef4b, 0x5e77f846, 0x0d2e79e4, - 0x7a11fb8c, 0xc16f23ed, 0xd28b2c7d, 0xa572d14f, 0xe915c850, 0x5bf290ff, - 0xc6429bca, 0x77ec14f5, 0x9b60f1df, 0xe1ef3b28, 0xc4afa16c, 0x4dfa4dfe, - 0x88547da4, 0xd7d211f6, 0xba2226a8, 0xbf727eb0, 0xe847d26d, 0x662505a5, - 0x19917bc4, 0xa6e11bf8, 0xd9f58db7, 0x68f1f434, 0x83f7e5f6, 0xf451efda, - 0x0b63f723, 0x84dcfd05, 0xff181891, 0xb81f720f, 0x5ccfd38a, 0xf4843de6, - 0x9cd5fbf3, 0xf0bee47e, 0x3d03ef9b, 0xa07dc8fa, 0xdd7e4fdc, 0xdd3f60fd, - 0x863ec058, 0xe95cb1e7, 0xfdf1e017, 0x45d38546, 0x3ddf9cfd, 0xf2c2c556, - 0x733368e2, 0xb97086ab, 0x8cc9a665, 0x0316977e, 0x99cd2fdf, 0xd2d97ef5, - 0xb413f908, 0xb8401f97, 0xf9276eb1, 0xdaadeb77, 0x3d2b3671, 0xf711fd77, - 0xc95a8f55, 0x08e174af, 0xc2e59323, 0x0f9411ae, 0xc78199fe, 0x6e7ce55b, - 0xb5f7bc3f, 0xb95bd410, 0xcc6296ee, 0x0255a82f, 0xb7c1d62f, 0x77beac0f, - 0x756bbf91, 0x672f7141, 0xe427c50f, 0xbafdf1b8, 0xc6c7927e, 0xf73f5c03, - 0xdf940929, 0x4787ef0b, 0x38fee9c6, 0xdcefcb88, 0xb807df4c, 0x5b47a91e, - 0xf827f3fa, 0x1b30b413, 0xa7ce1294, 0x704de708, 0x985fcb7f, 0x13798ae7, - 0x04e2231b, 0xbe663ed0, 0xcf2179db, 0x01726147, 0xba6567cc, 0x7fd717a7, - 0x4f85c44a, 0xa9e23889, 0xfc571e44, 0xfe7d7f7b, 0x7ae20db4, 0x3b8894e8, - 0xc6d14a9e, 0x44bd649b, 0x6cd93cf1, 0x60346ef6, 0x37799ebc, 0x3d70fe82, - 0x7ca26a64, 0x5f1c4595, 0x6b252fbd, 0x1ac811ee, 0x106a3e54, 0xd399fbb4, - 0xe3041fab, 0x9ed36f2c, 0xf715ea83, 0xba0af6db, 0xa7f0b5e9, 0x506b371c, - 0xd76c28f5, 0xb3df80bb, 0x289e5fda, 0xbfea5ecb, 0xc910baf7, 0x8ff2fea3, - 0x3a9ce242, 0xf8c893f7, 0x61f8bc40, 0xfa30bc74, 0xbc74699c, 0x37e4b17f, - 0x245fef11, 0x6ee2d4e4, 0xd5b86f1e, 0x820f36cc, 0x6775b7ef, 0x26b8fc50, - 0x135c3fd1, 0xbf5bf7ef, 0xa4879e51, 0x9edcdecf, 0xcff8f8fe, 0xf5e3e222, - 0x2f5a3e22, 0x5da9d7d7, 0xcf0164df, 0x3e3e31ef, 0x60739079, 0x9f3a3c7c, - 0x33b445e2, 0xac3c610c, 0x55b87071, 0xd12aebe9, 0x39617c4f, 0x35f73ca3, - 0x416b2d6f, 0x2d9af23f, 0x615596e2, 0x380bd777, 0xd3975bc7, 0x8d2e63ab, - 0xb9813ebf, 0xe593d622, 0xc994d14b, 0x33c88f92, 0xad93541d, 0x34db9f69, - 0xf07f5344, 0xef9a51ba, 0x4d22fef9, 0x1af5a0b9, 0x6d61fd4d, 0x88f29a15, - 0xea6bd79d, 0x4921b217, 0xa23b6fe4, 0xbb125f47, 0xf347302a, 0x85def47d, - 0xb29ff69a, 0xa0931da6, 0x7b45a75e, 0x7bf3332f, 0x8594c67a, 0x76c7a9f3, - 0xc3f4d52c, 0x29504a82, 0xf633df0b, 0x79a7b899, 0x878f0f79, 0x5ab5dd5c, - 0xbead4e33, 0x1d18f08e, 0x7d622def, 0x086e37e4, 0x1b20ee28, 0xd55dff18, - 0xaeed4ed5, 0x78c8f764, 0x2241c6c8, 0xb2cd97de, 0xd3475d39, 0xc3ec8d85, - 0xe4f4bb0b, 0xc3642c7f, 0xf0449a1f, 0x6b80b032, 0x302efe20, 0xf0bb17ee, - 0x798ddd8c, 0xb5bfb745, 0xca63e68c, 0xde05d2d4, 0x5eb9181f, 0x5d2d48eb, - 0x3a5addd8, 0xa5a09a48, 0x27786883, 0xc174b47b, 0xcbbff042, 0x86753bc0, - 0xb7fe6e96, 0xf081dce0, 0x5be186b5, 0x62d3d07c, 0xbcf1b823, 0x999f6935, - 0x1d143d84, 0x4e7690d7, 0xbbb09070, 0x2e323f45, 0x93f159b1, 0x771fd55d, - 0x0bcc109c, 0xd53da3e6, 0xc95fb8c4, 0x6fe5107b, 0xbd24bf0c, 0x9497e78f, - 0xc09b9d70, 0xf32d67f5, 0x663efc92, 0x93a4fee1, 0x9fc8abd5, 0x913592b4, - 0x9cd9fddd, 0xe8efc2e9, 0xca577aa7, 0x9f901853, 0x8b29f600, 0x06aed7f0, - 0x1fef1a8b, 0xd2a7868a, 0x78ed04ad, 0x4b75986e, 0xfca3e07d, 0xedde0f15, - 0x68ff89a9, 0x51e65fed, 0xb497e522, 0x1278e587, 0xc9ae529e, 0x49ac4c71, - 0x117c899f, 0xc8d8e725, 0xd693f8e8, 0x41fd239f, 0xe3238e32, 0x9bfed14c, - 0x55b8bb08, 0xc1d2718f, 0xce782df9, 0x21e1d8b7, 0xeb29613f, 0x4fdf05b9, - 0xa8b47730, 0xb8bfe12e, 0x2ffbf58a, 0x2babeae2, 0xf26fb5c4, 0xf247a12b, - 0x65b3c607, 0xff961c7c, 0xf1a11ff1, 0x8b95c524, 0xf2f398f3, 0xd3d22708, - 0xfba6bf40, 0x8fd02bf8, 0x8a97d75e, 0x3130aaf5, 0xfdde223d, 0xf5a212a6, - 0x367990fc, 0x6fdb9e45, 0x6ed31d60, 0xe8327f21, 0xa727bc49, 0x58bbfb93, - 0xac3db457, 0x0759bf92, 0xafba412b, 0xde711165, 0x2a77f0fc, 0x659607eb, - 0xec95d21e, 0x82f1a789, 0xe0a3ca72, 0xc84c53f9, 0x8cffb941, 0xf993cfb7, - 0x4f7ef218, 0x94547799, 0x1c75f823, 0x03fd871b, 0x94e595bf, 0xf8017fa2, - 0xc7e48953, 0xfa253cfe, 0xa31f803e, 0x31f32fd6, 0xf212f6f4, 0x5c8b2d1b, - 0x8780d7ef, 0x9c7e5bb4, 0xc8e9e8c3, 0x3eb3d171, 0x3d6fc4e1, 0x47a4b9f8, - 0x68da3f93, 0xfa0d0d84, 0x79145e13, 0xbb5a1d81, 0x9d1c96fd, 0xf7df1b80, - 0xf15e095c, 0xf8f221f1, 0xaebe3e04, 0xf8f3261d, 0x0c971c24, 0x0d0afb84, - 0x8ff7fb5c, 0x115f70fd, 0x2e12ee0b, 0x7e7b4ae7, 0xdbd2f881, 0xbc23a58f, - 0x577aa617, 0xe3dcfd63, 0x5d144fa1, 0xfa555e78, 0x7b8794b3, 0xe74f4ba1, - 0xe3ae1aff, 0x25e1b072, 0xf386893d, 0xb38a26dd, 0x41bd74d6, 0x66d9e176, - 0xfc06b410, 0x72180cbd, 0x08fc65d8, 0xb78ef051, 0xd9eb924f, 0xe5f62390, - 0xef32fd62, 0x39b9d607, 0x475e6627, 0xdfb41c3f, 0xf4aa1c05, 0x1cf09263, - 0x92be7f59, 0x791797da, 0x3af45f5f, 0xfe78722a, 0xf7b329db, 0xc3efec3e, - 0xd81d9c9e, 0xfbbe955f, 0x67c23670, 0xbbe742ad, 0x79f898a6, 0x5e712cdc, - 0xc9a8426f, 0x3399e78d, 0x667df873, 0xf7a47e23, 0xfdf91c62, 0xe0a677b5, - 0xffd93439, 0xe7474508, 0xee7b1947, 0xc12c7f83, 0x3722e6f8, 0xd8bf6fde, - 0xba2fee24, 0x002c1acb, 0x91baf239, 0x186547df, 0x66e744d2, 0xe4f592fa, - 0xb3d34cd7, 0x727748a9, 0xadbcf2de, 0x01f78f7c, 0x7cb15e60, 0xafa5a53f, - 0x7bfa0d78, 0x75c83d04, 0x2beca94f, 0xe185b26e, 0xa33cf32f, 0xf82553e1, - 0x1b43ee43, 0xd05b5ef0, 0xbccde7bf, 0x6daf7d1c, 0x5874feff, 0xf6363dff, - 0x837eb8c8, 0x1e3493c5, 0x6bdc51f9, 0x278717fb, 0xa477df89, 0xbcf6a7bd, - 0xbf97b7c8, 0xdeef1253, 0x51ccff9b, 0x827b97be, 0xcb85e5e2, 0x7078ffbc, - 0x99564869, 0x739d357a, 0xdeae5ef7, 0x8fadff2b, 0x28bedfb9, 0xd3dff7be, - 0xbcec6af9, 0xceb15ec5, 0x88617e70, 0xe7f729ce, 0x7e54be2d, 0x1a477bd9, - 0x08d23ef0, 0xf6bcc838, 0xb48fbc06, 0xd0bf4638, 0xe576cb9f, 0xc4aa877b, - 0x8f301abc, 0x3df23530, 0x38f0b7a7, 0x302f2269, 0xfb7c8894, 0x9d3d2ecb, - 0x11e5ffe3, 0x31dd8cdd, 0xcb9b9de6, 0xa9ca32e1, 0x0e8d1f12, 0xe3b5fbf2, - 0x79e793d5, 0xe8d8b9e4, 0x845675f9, 0x63f9c56e, 0xf1ac729e, 0x3f7cb91c, - 0x99dde72b, 0xf0d1f1c2, 0x9bdf899a, 0xf27cf2aa, 0x4ad094ce, 0x168713e2, - 0x1e04c3cf, 0xe50faf3b, 0x99b2b9d1, 0x8f10efdc, 0xfaa7261e, 0xc8be51ca, - 0xd4caee7b, 0xc111c526, 0x87a2578f, 0x1af5dc30, 0xbb840ebc, 0x7ecbbe91, - 0x7c151f4f, 0xdc363ccb, 0xfa112dcf, 0x5a9ec96e, 0x7ee587b2, 0x3d4ef4e9, - 0x669c6fe5, 0xba72ae3c, 0xd0fda14d, 0xeb631f52, 0x7cad2e40, 0xaa3378a2, - 0xb09925ae, 0x1efe1496, 0xe9661f7f, 0xbaf8a8c6, 0xbd495fd8, 0xbe5fc72a, - 0xd7176b4d, 0x467f6db0, 0x51f4e9fb, 0xb0563f2e, 0x2b3fd226, 0x57f6d01f, - 0xa7d667b3, 0xbce8cf38, 0x8fc21180, 0xec572d37, 0x1958ca57, 0x4f358fea, - 0x9fc46e7c, 0x17c78960, 0x434ffbf8, 0x7ddff187, 0x8efe27c2, 0xc96f3e08, - 0x1720fcf5, 0xf2ef3efd, 0xf5ceaef9, 0x7f45c9cd, 0x7e7cbbc9, 0x702eea17, - 0x8d2bb33d, 0xfd8b5bf4, 0xfaff922e, 0xdffe5cc1, 0x0035f78b, 0x71264c9c, - 0x49aeba6f, 0x4df6489f, 0x43ece880, 0x7e731de7, 0x26776540, 0xd3da43f2, - 0xbf6067d3, 0x1eada7ce, 0x72d6df5c, 0x2ffa214f, 0xf3f356b6, 0x8f1366a1, - 0x397e07df, 0x538600f1, 0xaf6c7686, 0xa39d1740, 0xfd107f7b, 0x3fbaad42, - 0x98bcc61f, 0x5f3cc9d6, 0xda175d32, 0x3c62283f, 0x899035a7, 0x68e77df1, - 0x9a4e6f7e, 0xcb90bcbe, 0x36276e7f, 0xe85c5c08, 0x627f202a, 0x17fa41af, - 0x2e742c3b, 0x2eff8eab, 0xf1c628c6, 0x70eaf32f, 0xf176910e, 0xf9a666d9, - 0x1d51869d, 0x4890d04a, 0x3c50a8f7, 0x30436ea8, 0x67d416fd, 0x4f14a94f, - 0x7b4bf393, 0xe302ab3d, 0xdd8f5266, 0xbfb838a2, 0x0bfdd84d, 0x71e3fc98, - 0x9e82f9b7, 0xff7b0816, 0xf7872b16, 0xc3cee652, 0x2ccd0b76, 0x76ac0751, - 0x2947654b, 0x90d6b3ad, 0x8c85768c, 0x47b7c51f, 0x1ac9fb62, 0xe7e7617e, - 0xe1be959e, 0xf419c9d8, 0x3f865d41, 0x693c85db, 0xffcfce18, 0x83cca1b1, - 0xd786caf1, 0x30efd046, 0x3c781299, 0x1996e41c, 0x843a11ef, 0xbdd61efa, - 0xc88b15ea, 0x73880a5b, 0xd8defccd, 0x453939c6, 0x78f11e74, 0x71ffdd1f, - 0x23ca10de, 0x847906fe, 0x92bea637, 0xe01fbbfb, 0xd90debbd, 0xf941d760, - 0x789fee74, 0x25684879, 0x92991bde, 0x47978977, 0x72c13e85, 0x6cc25e4e, - 0x5685172a, 0x3e3ca1ea, 0x7197932f, 0x36040a03, 0x6cf06f35, 0xc92dda3f, - 0x87702ec2, 0xc377bce8, 0x917423cb, 0x1e7758fe, 0x84676797, 0x3e4cf93f, - 0xc20e6dbb, 0xfaec647b, 0xded27969, 0xc9f5a36e, 0x2cf6caf5, 0xffbb7633, - 0x957e7210, 0xc53da738, 0x3c2d5aca, 0x044fe7fe, 0x1eec1c3c, 0x7fcbf141, - 0xfde14dcd, 0x4f74423b, 0xfa27ec8f, 0xb8e41c77, 0x7bfe15ab, 0xf2a3e759, - 0xcb977ebc, 0xb38c2be5, 0xea19c691, 0xe79be7e1, 0xfe2214e4, 0xc0aa6f00, - 0xc9f7ca9b, 0xd07e7ced, 0x13fefe2f, 0xf46287e8, 0x0afc1ffb, 0xe787e7ea, - 0x27274d1d, 0x5aab38c5, 0x2fb6dc78, 0x69e880b9, 0xf7dc558a, 0xc75da252, - 0x9f6e3cf8, 0xc592f3ba, 0xaf091d79, 0x69c6850c, 0x09cc7011, 0xf6339f0d, - 0xaffbaf9b, 0x8eeb4bff, 0xef0797c0, 0xc5d8396d, 0x9f1e37ef, 0xf485f1c7, - 0xe076429c, 0x677f4d76, 0x9fb547d6, 0xae5f28c0, 0xda80a521, 0x6fee2bdf, - 0x61d9f795, 0xdc71fcbb, 0x57bb45be, 0xfcc1a7de, 0x1c645993, 0x8cdeffb2, - 0x70bf710e, 0x286f3aff, 0x8874eb11, 0xef223a75, 0xcfe7ec33, 0x73797d63, - 0xb8e903ed, 0xfdfdfe1f, 0xfd12298d, 0x563cf869, 0xf1d7c87f, 0x1e5572f0, - 0x1bdf2797, 0xa33ce45e, 0xe70fd9e0, 0x7849f9a8, 0xbb537f22, 0x94ba5a31, - 0xf411ccf3, 0xf3bf8039, 0xe278e5bf, 0xbbfad97e, 0x7338be79, 0xbebae969, - 0xf9875f33, 0x07ddb209, 0x34a0c078, 0x21bc27ec, 0x7327ec4f, 0xbc9c4e58, - 0x339e6f47, 0xde917fa6, 0x7b27ef47, 0xd9efe593, 0xbd1afd69, 0x397bfe4e, - 0x7efc73fe, 0xfca36b83, 0x7a8f183c, 0x176e16ce, 0xf2da2fd6, 0x037e0263, - 0x797d54fd, 0x5312bf38, 0x3bf8f3c5, 0x4af3ab5b, 0x7760ab67, 0xdc552494, - 0xa6e50f99, 0xfc93c6c7, 0xf154192e, 0xf3c83e79, 0xe04d8f35, 0x7c5747df, - 0x79cb043e, 0x8a797913, 0xf79479e7, 0x9eccb460, 0x2bb6159a, 0xd173ccee, - 0x1d4afab8, 0x42676bdd, 0x63d60623, 0xf944dd7a, 0xf1ae1280, 0x5d26259e, - 0xbff3ac53, 0x03d3f4f7, 0xc04cbf8f, 0x1fd0ba7f, 0x2105fc28, 0xe82fe355, - 0xcfe7e44d, 0x92fd5f7b, 0x9bdcd7ce, 0x079f5be7, 0x67ad1bed, 0xf287cd6f, - 0x1407eb06, 0x603c53ef, 0xc61fa087, 0x608b60e5, 0xadd9cabe, 0xd89fb45e, - 0x2559b76a, 0x18ff0ab8, 0xf007a9de, 0xa7b5e57b, 0x0f883c7e, 0x4c79c5e3, - 0xf1a07214, 0x15fdbfb5, 0x678dc4e3, 0x1b346e6c, 0x7c3f7627, 0x135fda27, - 0x1bfedfbb, 0x3cfcc3d7, 0x44f79c90, 0xfbc27ff4, 0x9a265d09, 0xabeec4ff, - 0x6bfd6056, 0x402eebdf, 0x44eeb93a, 0x42c505b0, 0x3effabef, 0x880e7348, - 0x7cd97a7d, 0x39f1b8d1, 0x013f8f09, 0x1e0893a0, 0xf8f0e73f, 0xced9f28a, - 0x0e6e8f3b, 0x7b549391, 0x78ec0ade, 0x605f3b8a, 0x7b8c6e09, 0xd1fd73c8, - 0xd5e3d57e, 0x7f783eb0, 0x20cc1f5d, 0x729e9ec2, 0x24820cd1, 0xc9672e5c, - 0x39a5729a, 0xcabf534b, 0x3ef9af91, 0xcd2af33d, 0x42ae99f7, 0xc8d6794d, - 0x37fa9a89, 0xe535cbba, 0x6a6613d9, 0xaa7b57ea, 0x60c2e535, 0xf17ea687, - 0xf7ed2e91, 0x788f4c63, 0x7eee3a28, 0x27a59f03, 0x2d9ee43d, 0x06f4d53b, - 0x85fe273e, 0xafda2383, 0x8ec5cd7c, 0xf4bdf037, 0x9f9f472b, 0x9be67e92, - 0x3180b6f5, 0x53393fb6, 0x83df082d, 0xf3f1d7a0, 0xfb25ef53, 0x937880fe, - 0xa0a6a7e7, 0x5090195f, 0x9fb9db75, 0x5c32efe2, 0x6efdc458, 0x943111c7, - 0x7f276e4f, 0xd34371e5, 0x79e47fb3, 0xf728b903, 0xaf9bebae, 0x8b94f759, - 0xcbbacd3e, 0x3c28aad9, 0x5729a1dd, 0xd4d6ee39, 0x5eb99e9f, 0x6ba67df3, - 0xb69e144b, 0xba37ca6b, 0x53c28e1f, 0x9e9e147b, 0xf4977cd2, 0x5ffc2ddd, - 0x0adfa1af, 0x3d42939e, 0xc9878895, 0x1f08faa7, 0x2ada7a13, 0x1cd74f11, - 0x957c20ef, 0x2895bd04, 0x348ecb2e, 0x20cf81bd, 0xddb0cbec, 0x7a4ce681, - 0x91766c1e, 0xf370ebff, 0x691e7a48, 0xfffbd376, 0xcf409e68, 0xe87b355f, - 0x33cd9ff9, 0xecd3d9e8, 0x734767a5, 0xae7fd507, 0xcffb8bb9, 0xddeffb52, - 0xc1bf45c8, 0x01a85d79, 0xc18ec623, 0x9e9e495b, 0xc79d084f, 0xeb7f06f2, - 0x3420a9ec, 0x901d67f0, 0x9e207f2f, 0xfb4f2e45, 0x1e0e7860, 0x19fdf8cc, - 0x43a37f22, 0x3b4429e7, 0x0fe3f47c, 0x32e6a7de, 0x37bd69b6, 0x183a7f13, - 0x132866cb, 0x90f7e9b2, 0x93cfbc1e, 0xa8b3d8c3, 0xf7bee84a, 0xb9636707, - 0xe79efc57, 0x241fc7e0, 0xc75bfc3b, 0xe2033dd9, 0xc707a3ec, 0x7b3fb388, - 0x7f4765ca, 0x46afd1cf, 0x471e11d8, 0xc3cbdf85, 0x3bf80d0a, 0xa16ae51c, - 0xf1ecf501, 0x5421e738, 0xe0c97953, 0x7bb75c52, 0x5f91e51e, 0xe1dfa06f, - 0xfdf0a39b, 0xec97acaf, 0xf7a0fae2, 0xa7ed1346, 0x2b3ce98e, 0x957a3f90, - 0xce10c7be, 0x14fe3d37, 0x7b5ea9e9, 0xafc21e5f, 0xbcbdf1fa, 0x4c7becec, - 0x0d944771, 0x8f953e1c, 0x6fdb393f, 0x33e15efb, 0x0d11d71b, 0x1d83b99f, - 0xf4115f7c, 0x201da2e4, 0x3daac7cb, 0x2c5714f5, 0x75c30cf7, 0x389af51c, - 0x81ed7aff, 0xf237e461, 0xf08bce94, 0x360cf4ff, 0xa2e7fad0, 0xe83f44de, - 0xd6207d42, 0x1f9e15ef, 0xa23dedcc, 0x2e67dc13, 0xe0bed2b0, 0xa3df8e98, - 0xeedf5d10, 0xcfa3fbe2, 0x9c87dce2, 0xdc57be28, 0x0becff54, 0x5aef5fd0, - 0xebdd750b, 0x58f6411d, 0x1740136f, 0x54f7ba68, 0xddfe39d3, 0xa12016e4, - 0xf82def38, 0x6cfef82f, 0xfc5f9df7, 0xb07fea06, 0x1d26ead6, 0xf04518e2, - 0x2f2a285b, 0xfd93354e, 0x6e4e78b4, 0x5bc5ea05, 0x56f0bc44, 0x614e9abb, - 0xe8d93543, 0xdb967e80, 0x0403370a, 0x6ab4cad9, 0x5364fe23, 0x9b1dce4d, - 0xe87ab9f1, 0x58f22376, 0x9b7d98dd, 0x07ad8cd1, 0xf9252e16, 0x19a77a17, - 0x3adb75e6, 0xe7ef8bbd, 0xdadaf9e4, 0x22f7946f, 0xc898f7e9, 0xd020024f, - 0xa5c9357e, 0x4949f668, 0x181f4e82, 0x6331e22c, 0xda4bd8d9, 0xe44ed778, - 0xdf8bb3a3, 0x1e271e19, 0xec2efda1, 0x7b8adfc7, 0x4fefa39e, 0x5c3ae391, - 0xcc75ff7c, 0xf6899408, 0x07ae42e4, 0x7cffcdc6, 0x7fac2943, 0x4743b75c, - 0xd5b70d79, 0xb87880bf, 0x68f025d0, 0x4fc85d60, 0x7c97f937, 0x4c421bf0, - 0xf0dce69a, 0xbba5f495, 0xa91951c7, 0xde424b2f, 0x397d48ca, 0x12adafa1, - 0x8fd4a2f5, 0x211ae6c1, 0x8e489b8f, 0x475e6c1e, 0x7ecdc3e5, 0x6e691e7a, - 0x8db8f215, 0x79aaffbe, 0x01c790a7, 0xd2f78f21, 0xf9e6eefb, 0xd9ad7cf4, - 0xa985cf47, 0x6e11d7be, 0xd73b8e32, 0xdcbca3ec, 0x189b0f43, 0x742ef1c6, - 0x038f289b, 0x47b1e238, 0xc94f30d2, 0xa344e744, 0xe5a295f3, 0x743d3f7c, - 0xe5b7b80e, 0xfef7e46d, 0x17b4233c, 0xa7a7c707, 0x4765cca3, 0xe0f1f4b9, - 0x8e8724f3, 0xb4765cba, 0x2e3e4fa7, 0xdd971eca, 0x0d3fe500, 0x71fd25ee, - 0x9bb2e7d4, 0xe3c9fca0, 0xdfbbfcbd, 0xf940b765, 0xfc7dc1d3, 0xd051807b, - 0x2fe0ecff, 0x33958e48, 0x47f220e5, 0x2a7f39a5, 0xd7d00ba8, 0x2f9107e5, - 0x992e67a6, 0x60b17c8a, 0x72e88bb0, 0x41fd6ba6, 0xd91acf2c, 0x1515e2ae, - 0x46e15b1e, 0x5691576c, 0xa9bb62ad, 0xc46c7739, 0x6e86d376, 0xcddb2357, - 0x236fb318, 0xb7706f96, 0x2e9f68ab, 0x1a563940, 0xe59647ee, 0x65a72977, - 0xddd5dd3e, 0xe307d25e, 0x0fa4bcba, 0xe62a5c24, 0xff426f56, 0xe2976367, - 0xa9a5dfc0, 0x27f4ab98, 0x62ee6033, 0x0a93de03, 0x3dfffaf2, 0x87ac77ae, - 0xf9623675, 0xadb72a1a, 0xedfa06ff, 0xe2f6007f, 0x8000e831, 0x00008000, - 0x00088b1f, 0x00000000, 0x3cd5ff00, 0xe5547809, 0x9dcee7b5, 0x4c92642d, - 0xe2420836, 0x96249964, 0x26b6432c, 0x0c486410, 0xf90130ee, 0x10196544, - 0x044816c2, 0x7eab17eb, 0xe0171a19, 0xd16b8d69, 0xb5c46faa, 0x61e4b6af, - 0x1d0958d4, 0x87d252aa, 0xb410553a, 0x88a47479, 0x119099f0, 0xc7d278dc, - 0xf7fce73b, 0x24cee666, 0xbefd1480, 0xff938607, 0xcfd9fbfe, 0x005ffff9, - 0xb3f85380, 0x34607f02, 0x3d2538fe, 0x0468048c, 0xd1bf67f1, 0x0395b26d, - 0x8c0734ac, 0x412fa3a0, 0x6010aba3, 0x76960eaf, 0x24a40014, 0x0b7afcc3, - 0x74b08d96, 0x5de7960b, 0x05480368, 0x20bada68, 0xda85816e, 0x6066e3bb, - 0xe21745fb, 0x52ce38af, 0xe0546e05, 0x9bd40a93, 0x4f34899c, 0x1fd24d9a, - 0x856fc7ca, 0x064a7850, 0x3d9ab7e8, 0x448004ba, 0x0dac7b93, 0xfb9bedc7, - 0x8758834e, 0x31d688af, 0xeb1ebd6c, 0x6c3200e3, 0xca1f1e56, 0x5e541982, - 0xc846ed09, 0xcff5b846, 0xda22a4fb, 0x2327c597, 0x5f434e84, 0xf9ec5f20, - 0x63fe1654, 0xe0543d06, 0x6e03e97a, 0x70d79969, 0xea566020, 0x743967f1, - 0x226670ec, 0x7ed45ede, 0x18bf046f, 0x7dfb43bf, 0xbe8de215, 0xbf697537, - 0x0f5b5403, 0x0230438d, 0xd9dfb8cb, 0x855efe12, 0x878f0dff, 0xc3c06749, - 0x10f0a1a4, 0x1af01fb5, 0xd7de8e41, 0xa66ecb0a, 0xc0bee473, 0xd1fcca9d, - 0xf7218108, 0xf445f2a7, 0xfe05dafe, 0x25ff02f5, 0x5a74e736, 0x38fcdd5f, - 0x8e005390, 0x4d79356d, 0xa9ffdc99, 0x1744293d, 0x2d837593, 0x5b5b3e9a, - 0x00de8367, 0xcdd5adb0, 0x14bad7d0, 0x3f8076f4, 0xf97336b5, 0x2e16d6ad, - 0x30f568ef, 0x8ebad9dc, 0xdb5a5fe1, 0xeb577eb9, 0xdbbf2e46, 0x6fe865ea, - 0x5fbf917d, 0x86657f3b, 0xff4d12db, 0x45cec9d5, 0x7b9e8fc4, 0x3e9913aa, - 0xc853f7b8, 0xc81a9eab, 0xc344b66f, 0x9d658301, 0x8f65c094, 0xd9e1f711, - 0xc36de316, 0x8c73fd7d, 0x19c689bb, 0xad7e09a8, 0x4a437c43, 0x30d0f180, - 0xbe9abdd2, 0x3a1c464b, 0xe4f56689, 0xeb0efe12, 0x6407bf3c, 0xd39b56d9, - 0x383e47a5, 0x17558f1a, 0x6582dc00, 0x78f3ce0f, 0xfa85abaa, 0x48c07e41, - 0x3fa29ce3, 0x097c7193, 0x3af07766, 0x0e1ca210, 0xb1e808c4, 0xd18f2c49, - 0x40ddc850, 0x60f99fba, 0x1913e9e0, 0xcb3382b6, 0xa8f870c5, 0x9e03ab93, - 0x6567a432, 0xd584c3ac, 0xa4f8127d, 0x46538412, 0xd38e00d6, 0x13d46e97, - 0x5644149c, 0x9fc3c750, 0x6322dfc9, 0x14cbf186, 0x6b94d448, 0xed35a3cd, - 0x9a99aceb, 0x5cf4befa, 0xb4d2ff1e, 0xfaed348b, 0xc59a5746, 0x232f53bc, - 0x6f7465d8, 0x0974805c, 0x9b1c9956, 0x98bdfeb0, 0x062822f8, 0xbf1b1698, - 0x317be089, 0x376a5e19, 0x14c9c0ed, 0x934e7dc0, 0x108b237d, 0xc6db9755, - 0x99edc76b, 0x76c36353, 0x6957e657, 0x25c121d7, 0x1dabdfb4, 0xa7df3453, - 0xe9ae5e57, 0x93fb32ef, 0xcef5ad08, 0xc6f7cd7a, 0x9f41af96, 0xe5b1300c, - 0x014be824, 0x343afbc6, 0xecee94e3, 0xbf1fb4d2, 0xeb12641b, 0x378e7d92, - 0x741f9609, 0x152ac4ca, 0x24df9b87, 0x3fa5f558, 0x4e01f683, 0x9f5159b0, - 0x83dc8a4b, 0x963d0247, 0xcae52927, 0x812db7a0, 0xf21270e8, 0x89bf48f5, - 0x6321c230, 0xbff2a963, 0x4c1f104e, 0x32002052, 0x16abf607, 0x3a79804b, - 0x4598d78b, 0x1be5056a, 0xc906c1f5, 0x3847a691, 0x50540e47, 0x8a0428f9, - 0x973aca08, 0x2a6bf89e, 0xb2a58f34, 0x0469dc09, 0xbf74483f, 0x2fdc7c4f, - 0xe2c4da05, 0xcfc4c982, 0x68ff3f75, 0x17ac6dde, 0x5c261c62, 0xfebaefdf, - 0xfd6b4a91, 0x91f53fbb, 0x7e216c37, 0xcd7eb26f, 0x8dcb5278, 0x7f19c72d, - 0x2d6fb96a, 0x92e177cc, 0x9f680ddb, 0xaffe3610, 0xed0a76cc, 0x53a23ada, - 0xb8c9fc23, 0x1ed420ba, 0xc418be3a, 0xbfea3177, 0x04d35a7a, 0x5ddfd7c2, - 0x6f576c4e, 0x9e087210, 0x1c4ef545, 0x29463ea7, 0xa7d44f83, 0xb2a1ed2a, - 0x6ae9cb9e, 0x6f68957d, 0x587bc757, 0x96ad1fb4, 0x522ef195, 0x9ca2cdcb, - 0xa0f7cea9, 0xe5aa1728, 0x397170ff, 0x613fb44e, 0x29ef559b, 0x53ffe908, - 0x0f18ddaa, 0xa06ec9e3, 0xc933903d, 0x1abb481e, 0xeda21f98, 0xb15eb685, - 0x237ff317, 0x44c58c7b, 0xdf63cb8f, 0x90eeb921, 0xf1bae480, 0x8bd38376, - 0xd49e7ff3, 0x12c6b451, 0xb7e7dfc2, 0x6abb7c08, 0xb6329ce3, 0xde6af95f, - 0x3923e226, 0x85c8f76e, 0x563addf8, 0x4ea77ac7, 0xe88138b6, 0xfbd0af7b, - 0xd848ff6a, 0x8686f2d0, 0xb2f5519e, 0x6cc1f3c4, 0xfaf9c1fc, 0xf4f51bef, - 0x8e59c206, 0x9370973f, 0xdcf42999, 0x95add448, 0xea36f3f8, 0x3dd23359, - 0x3a9c1b25, 0x1af29f6c, 0xf1a267ea, 0xc7d0bf41, 0x24f8c5af, 0x8f959c14, - 0x6ff6c9bd, 0x8e528ca1, 0xcf2d7bf8, 0x7c89979d, 0x9fce347a, 0xd0db7c4b, - 0x75d78db2, 0xe3cadd8d, 0x10583583, 0xcce2cf8e, 0x9e97fc28, 0x3fa5ff01, - 0x8271fe26, 0x75cfa403, 0xbeb47428, 0x78b796e5, 0xef95cbbf, 0x43325fac, - 0x472cb8ed, 0x39c68f97, 0x0e1f0832, 0x74074e85, 0x5f050ab6, 0xfabe1357, - 0x1373fb17, 0xf9f0ecb1, 0x3ed9ba47, 0x88972aec, 0x4071cdee, 0xf92a3f74, - 0x410ef68b, 0x0ed68eff, 0x5a5bcbb6, 0x84be18bb, 0x55bad073, 0x8d10dd7c, - 0xc067f9df, 0x131ffcef, 0x01f4a3bf, 0xadfb03a3, 0x4e3c07da, 0x1180ff85, - 0x2b4cf4c2, 0x27e225f1, 0xfae24ba1, 0x2120b93a, 0x138fa9a0, 0x738e52fe, - 0xcae9f13c, 0x37aabb19, 0x98792148, 0x311d0b1c, 0x0ed7cc49, 0xc41daf85, - 0x22ff2ad7, 0x11ea963f, 0xc49d6fcf, 0x37e0437e, 0xf3c0bfc4, 0x3bba78a8, - 0x881baf1a, 0xabc1a78e, 0xc607feb6, 0xc7fa276b, 0xaf8237a4, 0x653778c4, - 0x77f9e346, 0x7c555e0a, 0x7fe4536f, 0x236f3c38, 0x7f9ea73c, 0xb4cb6f3c, - 0xf891b8f1, 0x453ece1e, 0xf75d47d2, 0x7e5a7210, 0x2d3a722e, 0xdff8aadb, - 0x461677e8, 0xa26dfdd3, 0xf74359bb, 0x53c8339e, 0x4f298fcf, 0x848b7891, - 0x3ab8128d, 0x3fdfd12c, 0xdf561ccb, 0x4e3c179d, 0xf8d6ce0a, 0x75bf9367, - 0x29b3fc6b, 0xfd696118, 0xe5349bd8, 0x9aadeb3a, 0xada697f6, 0x6e5fd4d5, - 0xbfa9af5b, 0x4d01ff32, 0x63c76af9, 0xd3e67e11, 0xe77afa9a, 0x73f5346f, - 0xea6bb79b, 0x68f4b7e7, 0xfe7817ea, 0x78ab29aa, 0x1c0adadc, 0x356b6d2f, - 0x65d3f12b, 0xfe03ab0c, 0x8b83125a, 0xdfd9070f, 0xd7b7f4ac, 0xafb24bb2, - 0x32d1fd83, 0xc296ab9f, 0xcd9d8aaa, 0xb5f4126f, 0x2d78955a, 0xad5be18d, - 0x3befd636, 0xee19f35a, 0xf128756c, 0x5dc3255a, 0x4e254ead, 0xb48c3173, - 0xbb66af0b, 0x3d2164a7, 0x44bcbda6, 0xe980b807, 0xc167f87f, 0x77bc5a5e, - 0xdce28ebc, 0x8e5eca35, 0xffb37f57, 0xe3afe436, 0x950726cd, 0x311fb77b, - 0xf9a30ad8, 0x32b7ee65, 0x6cf8c338, 0x0d5fcb6e, 0x45cd67e4, 0x0863ba0f, - 0xa59a9d39, 0xf7207e63, 0xcc2f5003, 0x05218336, 0xd9ecc1f5, 0xf80da392, - 0x189207bb, 0x3f58dcfa, 0x133e0f4d, 0x7a2deb96, 0x979e299f, 0x3fa332e6, - 0x132c4b3d, 0x50f07a4c, 0x7324a43d, 0x7d0d7e9c, 0x383ca1b4, 0xbf18b865, - 0x1c3f22cf, 0xe96f5dfb, 0xbddd9030, 0xfa2fe76e, 0xb87ac36f, 0xf1ce53d3, - 0x25625c3d, 0x3e792dfd, 0x371a9dd6, 0x3520bcbc, 0x5f1850e1, 0x4e19254f, - 0xe1d1f8a5, 0x7adc5277, 0x9cf1c193, 0x05dfba2d, 0xc9a77eca, 0xc16ffb12, - 0x4dde4dd7, 0x713e4852, 0xb84d3b7f, 0x01e226cf, 0xc1b367da, 0x7e445797, - 0xb3f676f6, 0x16d72a9b, 0x2e9a9d11, 0x15313e91, 0xa69de285, 0x8fd92f96, - 0x91cfd48f, 0x90f14cf0, 0xfe656fc3, 0x93badfdb, 0x8b8d45f9, 0x5c7d5b7a, - 0x6ab80b2e, 0x39a3e3c3, 0xa64dff93, 0x4beaa7b8, 0x3c4cff11, 0x53fbdce9, - 0xd5a077dc, 0x17e52fff, 0x9a82bcd4, 0x5bcc8867, 0xde647aa8, 0x6e0975ad, - 0x2c9aefdc, 0x94f30651, 0x5ea3a674, 0xdedf5540, 0x9765159a, 0xbd3ac8ef, - 0xffd6d67e, 0x6cf9fac0, 0x4d31bff9, 0xbe48d5d8, 0x05e337df, 0xe553ad03, - 0x9ffe48ef, 0xfe707d43, 0xd7924d39, 0xf67a7a83, 0x44c37692, 0x7df9dce9, - 0x88a0e5b9, 0xc2ed238b, 0x3607b6f7, 0x2b5c9ba6, 0x92617c73, 0x1e50726f, - 0x4743a544, 0xcf3add34, 0x1fceb740, 0x76d16e93, 0x73bce0f1, 0xf1a08bb3, - 0x8acbdfcf, 0xc83e27f2, 0xa91fbd3a, 0xf781ffad, 0x636b1d6d, 0xef4472b8, - 0xea27593c, 0x01627c45, 0x80eff21d, 0x74b8e657, 0x3c7b6669, 0x195033c5, - 0xb77d278c, 0xf2065bac, 0xd4ef410f, 0x5cfe468f, 0x1f67f0a2, 0x7e243ef8, - 0x7ef7055c, 0x25980941, 0x22ae4bd5, 0x09f4b73d, 0xfc4f0843, 0x27f393af, - 0xcb7e94ab, 0xda469d2d, 0xb567f2ef, 0x1a71d4ed, 0x1fc88a5f, 0x19fa5f57, - 0x73f0ddb0, 0xa7556fde, 0x5977dfb6, 0x62872971, 0x084b1659, 0xa7d267ef, - 0x1baec947, 0x5b27cac2, 0x3f20bf39, 0x9e03e0f3, 0xc4fa21b1, 0x71f14764, - 0xf9e9f65c, 0x23ff5b58, 0xf71cb1f3, 0xf9e891ac, 0xbf78f97d, 0xeb4599dd, - 0xa0f3f556, 0xc4c379de, 0xdca0677a, 0x37a4f226, 0x9e2daefd, 0x3804e4f8, - 0x2a161d88, 0x6a85d2f9, 0x369d74be, 0xcfb93a5f, 0x49b979c7, 0x716dbd07, - 0xbd89f748, 0x55dbce1e, 0x59b776ed, 0x5dd3fcb0, 0xa3fc994e, 0x64b96ff1, - 0xdfeab75a, 0x484efea8, 0xbeb0e58f, 0xf66bbce3, 0xd53bebd9, 0x30f6aa2e, - 0x06560ed2, 0xfec96bdb, 0xe3b6f84d, 0x2be7824d, 0xf7691eaf, 0x7a138bde, - 0x57c1a8e2, 0x8cfc97be, 0xcf1c63d7, 0xaffaf441, 0xc67e16cb, 0x0302cf4c, - 0x1f091fcb, 0x450cdbca, 0x764fae6e, 0xf54d975f, 0x99d0bd8a, 0xa3b2069d, - 0x23df7275, 0xf95f12d7, 0xde1bce65, 0xbf07c77c, 0xccedb5ff, 0xeb2685f9, - 0x863ff671, 0x749a338b, 0xa2f8a6e0, 0x4a56d6a4, 0x6dc50c7e, 0xf3544794, - 0x9fed918a, 0xc8acd7b0, 0xb5573ce6, 0xd9eb49df, 0x1c33d628, 0xbe5a9abd, - 0x8731e4d0, 0xbba9bf9b, 0x4c30badc, 0x16ca5e3e, 0xdbd22ef1, 0xa21cc87a, - 0xc5f2d9f7, 0x65f8b7ff, 0x091e0c9a, 0xe4a16ced, 0x082ffe15, 0xf80e783f, - 0x2083ce19, 0xf9583743, 0x38216a7c, 0x17022e18, 0xdbbb7cc3, 0x60337c4b, - 0xbe248e08, 0xbbf57fea, 0xfe9be202, 0x57b6278b, 0x5f3bf9c1, 0x06fff48a, - 0xfe78dbc6, 0xdbbe5781, 0x7039fc43, 0xf4ace187, 0x6764eac6, 0xe451f127, - 0x53bbcb79, 0x01d73e64, 0x8b967afd, 0x03e8ab7a, 0x1b72a497, 0xe64cd8eb, - 0x1cde908b, 0x37aab4f5, 0xc2bf6017, 0xd7ac744f, 0xb5e49960, 0x80aed363, - 0x70ac458e, 0xa657a671, 0x2fa8a772, 0x95e8995c, 0x15585cb0, 0x4a6fea23, - 0xc52642f4, 0xcb960143, 0x0fac00f9, 0x8bd08017, 0xf7938237, 0x96419189, - 0x6f17fd84, 0x3e709735, 0xa4390216, 0x8e288bff, 0xb74e221a, 0x2f7908e6, - 0xbefa12ce, 0x179b46b8, 0xc95b30f9, 0x4a6bdb1b, 0xe7561072, 0x1d12f738, - 0x1bfc938b, 0x7ca32a1e, 0xa1360e90, 0x75567d7c, 0xaa779f2b, 0x35ed1afd, - 0xcdbf84bd, 0xe2bc7012, 0x9f7936e9, 0x238ce713, 0xf2cdcfc3, 0xa807b5ed, - 0x7b5a11dd, 0xc578f0f9, 0x47f71c7e, 0xd78795cb, 0x1bb14c57, 0x43f1fbe7, - 0xe5cbcf25, 0xebe679ff, 0xf80b3bfa, 0x7e43c14c, 0x7ddda372, 0x046fd79c, - 0x9ffad0b0, 0x40147114, 0x47e50673, 0xd2653c97, 0x11f19f91, 0x03c8639a, - 0xddc61bf8, 0xe31bff04, 0xc77f8267, 0x27e099f8, 0xfc133f18, 0x04cfc607, - 0x1e3b7f17, 0x8d802283, 0x4e4b4e39, 0x301ce879, 0x1c86bd72, 0xf9c1cf81, - 0x7f3c8dbb, 0xf8cddd9d, 0xebf7a41d, 0x9973a5e0, 0x0bc189cd, 0x6fc34e92, - 0xf0dfdd03, 0x7870e9f9, 0x2325cf51, 0xe853bfeb, 0x67a9d45a, 0x15d45ffb, - 0x6b086f88, 0x918e4177, 0x395f0beb, 0x1fe34f18, 0xd7e20eb5, 0xa796e129, - 0x82f944e9, 0x08332d67, 0x677675bf, 0xe51bed09, 0x51f6833c, 0x83c1f5d4, - 0x7c78cb13, 0x75a364ab, 0xb8e51f04, 0x911f6221, 0xb5f75078, 0x81bfd139, - 0x257e6ffa, 0x7a82768b, 0x10dc8407, 0xed43491f, 0xcff32d77, 0xccb05374, - 0x7e9deb8a, 0x0a1e6e4a, 0x29f675ff, 0x5477e78c, 0xc7cf537e, 0xe952fe15, - 0x1df2ae76, 0x6b901e39, 0x6ae77e84, 0xb236a5d2, 0xc9e3274b, 0xee57ac2f, - 0xe6757419, 0xf4fb47bc, 0x6ec194ec, 0xc8d63e63, 0x5f8562df, 0x6dd85854, - 0x36bd1174, 0x59ca1f77, 0xe4fa6164, 0xb3f6c62c, 0xbc9aec72, 0x89d56167, - 0xe14a1fc7, 0xea9a56f6, 0xceba783a, 0x60dfe38a, 0x6d36fede, 0x93f5ae69, - 0xcf2c44ba, 0x1076934f, 0x9ccb605c, 0xe5a3649a, 0x37fd797a, 0x41d94fe6, - 0xa3957522, 0x29b9fd9e, 0xecc264a4, 0x9639ad43, 0xcb071f0e, 0x4d64d675, - 0x31b4d2f9, 0xdb97f69a, 0x57f535b2, 0xd4d38fe6, 0xe55ef3ab, 0x2bb4d528, - 0x51660a4e, 0x60fb875c, 0x64e780b9, 0x7da25daf, 0x1c62beef, 0x3f3da796, - 0xca6e41cb, 0xda7ea566, 0xd12f5a96, 0x69f10063, 0x70ea8744, 0x1f47fae5, - 0xe222c1a2, 0x67eec686, 0xe76d3876, 0x130c3710, 0x7100ac2f, 0xdc5c3f8e, - 0xa02f1910, 0xf4907cfe, 0xd7abf167, 0xdc70db58, 0x2e2755cd, 0xef3ee1b0, - 0x8238c1cc, 0x47128dec, 0x833fc70c, 0x04d92272, 0xf0c8f4ff, 0x03fc10dc, - 0x1f850bf0, 0x3ef69c05, 0xdf0533fa, 0x4a7dbf5f, 0x07f38dfa, 0x57efc51e, - 0xafbe4460, 0x6f78e8d8, 0xdea7e50d, 0xf9ce8191, 0x03ae24e1, 0x77e81beb, - 0xb0f7c439, 0x46bbe9e8, 0x0f77f0a7, 0x94aba6b9, 0x731fdffc, 0x71aabf14, - 0xcba35dfb, 0xf370f542, 0x70f69a27, 0xa6b774bb, 0xb6a6677c, 0xbb94ef7c, - 0xe70ffbc3, 0x5c6c3597, 0x9ca37460, 0x392c3c36, 0x8be843bd, 0x28a4f5c1, - 0x097ba1fa, 0xdb43dbeb, 0x716d1997, 0xe157edd1, 0x6cb79478, 0xaadec618, - 0x193aea7a, 0x7faa879a, 0x71cf9d47, 0x08fbe77e, 0xcdf64f71, 0xc3b09af3, - 0x8db8251f, 0x2fb27ce1, 0xf47b9c47, 0x1dc0f63f, 0xee79d35f, 0xeabe22eb, - 0xa3f6144f, 0x9d33f3a8, 0x08f1610e, 0xd6455fc1, 0xd2ec8e80, 0x0f58d2c0, - 0x2d359ca0, 0x8ae8f38b, 0x7e088fc9, 0x5e4f1e68, 0x9a0f2dc7, 0xeb1fce91, - 0x3cbb1a74, 0x9616c140, 0xd9fd9efb, 0xf7e93b8c, 0xe92f7102, 0x2fb3ed7c, - 0xad7d8407, 0x1e637a11, 0xb7629ff1, 0xd3565500, 0xc768305d, 0x5e10cf48, - 0xbf6b9ca8, 0xc987fdf5, 0x7a11efcf, 0x370af283, 0xb4e05fb0, 0x1d0df368, - 0xbbf8e72c, 0xd73efc2d, 0xb78feb59, 0xf3968dda, 0xd84647a8, 0x218779b5, - 0x57fbc5f4, 0x5e9b3d22, 0xd05ef997, 0x04f6adb1, 0x911fd308, 0x28da6c78, - 0xe5ab9cb3, 0xcbe55ba3, 0x830f6cbc, 0xd185f519, 0x83a706f8, 0x55b57fe5, - 0xd27ab7cc, 0x4ec83337, 0x8bd6eeaf, 0xcdc32f4b, 0x5b064eb3, 0xb79b3cd8, - 0x5d929699, 0x603fd753, 0xf749f455, 0x0a534957, 0x843b5c04, 0xc0bf457d, - 0x417e4290, 0xecf1c4bd, 0x3551ee9e, 0x123da784, 0x3c256cf8, 0x5c6635c4, - 0x1c314cdf, 0x5e50b77d, 0xf9f2d214, 0xd71aa59e, 0xacecf1aa, 0xf27659ee, - 0x5cec3f63, 0x072907b8, 0xccd9ec93, 0x8782d74f, 0x893deefd, 0x93ca74ae, - 0x3fee534c, 0xf60c49ec, 0x67bdbf91, 0xf744ac52, 0x3bfc7019, 0x5f757c69, - 0xf4ae0c7b, 0x9297de66, 0x44fe752f, 0xf67b153e, 0x67aaa271, 0xa7dbe4eb, - 0xf7e7495c, 0xf14ac073, 0xf85974ec, 0x2147f0d5, 0x6d5eaacf, 0x6c49fc92, - 0xa633edaa, 0xa34f11db, 0xe4a97e5a, 0xf735db7d, 0xafd6cf00, 0x5fa38c1e, - 0x567f9894, 0xb1bc4439, 0x47f3faaa, 0x57f9c5ae, 0xfe4fbc61, 0xedaec2dd, - 0x917f08fb, 0x7c60fdf1, 0x7be62ff5, 0xd733e3a3, 0xcddfda32, 0x73df1c77, - 0x69c7442d, 0xea817183, 0xcb173e5f, 0x58a8d6e7, 0xfc287c85, 0xee5b647a, - 0x7f5835de, 0x66062fe4, 0xfd2737d7, 0x58ade8ea, 0x58b9f9be, 0x2491f3c6, - 0x391d90f0, 0xebcf29b2, 0x744b06c1, 0x6fb25ec1, 0xcf8e25b0, 0x327b3e69, - 0x512fb7ef, 0x76b7f27e, 0x7e4843f6, 0x7cc2e86c, 0xe88ff746, 0xb9a3cbfb, - 0xbcc5b81f, 0xca5c8a0d, 0x5fde142f, 0x242ff54d, 0xa5427e73, 0x6327e1df, - 0x7dac149c, 0x2b22be05, 0x92e7deb2, 0x5bdd10e7, 0x697ba15c, 0xf97c84bf, - 0x06f708d5, 0xc7f2f7da, 0x89c3f3ff, 0x17da9fb8, 0x1555feae, 0x07d96fae, - 0x84e340a9, 0xdfb43ae8, 0xb66b6c70, 0x3f057f90, 0xf18c5e2b, 0x27d30c1e, - 0x35123b2b, 0xd1aea6e5, 0x7a6183de, 0x729ef068, 0x04e7c4a3, 0xed5c8a8d, - 0xeddbba37, 0xfba5d794, 0x713f4ca9, 0xce84b51f, 0xf7ff08ab, 0x91ff1899, - 0x5da2f67c, 0xf3566739, 0x4e60c93c, 0x0b75b923, 0x97dc0dfc, 0x31e289b7, - 0xf1493d9f, 0x33b9823b, 0xb3f9c30a, 0x9c1bd577, 0x7b8931e7, 0x9f43318f, - 0x13da77eb, 0xf9837db9, 0x699e4d4b, 0x4d09cb55, 0x015567fe, 0xd2501fb0, - 0x89bd2b66, 0xba1487ce, 0x7aee9fdc, 0xf1def18d, 0x18bbabc0, 0xf2dc4f9f, - 0xd3bbcd31, 0x5d83f4c2, 0x11163c4a, 0xbf98356f, 0x69efe450, 0xe87e7f8d, - 0x9445bdb1, 0xcaf438ff, 0xd3ca22b8, 0x87fd942e, 0xf7c99d7e, 0x86dff69c, - 0xf7cecb70, 0xb91e2f39, 0x0c7ba8de, 0x8d43d092, 0xba648fb4, 0xc77ae3ff, - 0xf42e72ce, 0x850d81c3, 0x1f353f8c, 0xe864703d, 0xa75d5078, 0x3ebabe3a, - 0xddb57c75, 0x5f22ecdf, 0x17f46fd0, 0x415ffd91, 0xfb6130e7, 0x17f78fea, - 0xbbe85a25, 0x4913f855, 0xb7e30e58, 0x2abcf57f, 0xf06a7cf2, 0x47c9565c, - 0xfdadd3ed, 0xaff91199, 0x8321e3af, 0x7eef5c3b, 0x752a73cf, 0xdafdeabd, - 0xfd85ab7e, 0x2576939b, 0xe90e9f1f, 0x1deb0ed4, 0xb7bff23e, 0xc7e41c98, - 0x905c9a27, 0x3469f88b, 0x9afef8fa, 0xe4d12fda, 0x7991efe6, 0x234481f9, - 0x81e5bdd0, 0xf7fce554, 0x42bd602b, 0x9c16e871, 0xd756acb7, 0xd212c5bc, - 0x2cfeaa87, 0x0bdf871b, 0x3ea91ee8, 0xdf2027e4, 0xdb6b1594, 0x2da3f687, - 0xa0ae7bff, 0x6eb25963, 0x24b938c8, 0x1b65c857, 0x9e42c874, 0xa89d1d85, - 0xbf0d1de0, 0xacd7ee1c, 0x40fcf452, 0x0743d9bc, 0x8ab713bb, 0xf513ab7b, - 0x5104edbe, 0x124b400b, 0x89f4995d, 0xfab4baf1, 0x1cc86c9c, 0xd8e3cbb6, - 0xc8504f2e, 0xccd4b77d, 0xf7435bf7, 0xc132fd5c, 0xd0c8218b, 0x413d5609, - 0x4bc30324, 0x2a70c5c0, 0x0cbc3334, 0x015e19da, 0x02af0c1d, 0x89f8433f, - 0x1ed80daf, 0xff656edc, 0x3a25f2e9, 0xd765cbb2, 0xcf97ed0e, 0x3c35f052, - 0x57cb503e, 0xa63e3b9c, 0x8772f72a, 0x7cd8cbc5, 0x2f157be6, 0xec4fe226, - 0x34de0317, 0xc0209382, 0x46264ce3, 0xdd78a6ce, 0x6b7ef7c6, 0xbae5c9c1, - 0x6547c4b3, 0x1777adc0, 0xda97810c, 0x9e64f9a1, 0xb90327c2, 0xe951f8c0, - 0x8dae48f5, 0x30dd2acb, 0x7b234c50, 0xc84f4d10, 0xc59675a0, 0xa7a71cd6, - 0x5f3fb722, 0x7a8f5336, 0x66b4acb4, 0x5f90a90d, 0xe5154ee6, 0xd32f3589, - 0xf3fb7d51, 0x71728a97, 0x81c1a94d, 0xcbdae85e, 0xfa825e66, 0x27dcadd9, - 0xa011a337, 0xb672637b, 0x2b761738, 0x724dcaf7, 0x2fba5ae6, 0x580dba66, - 0x0063b8df, 0x22d7ecfc, 0xb8bc91b7, 0xb37b1c45, 0x3aafd055, 0x2e4b7dd6, - 0x2fb333d9, 0xb87486de, 0x28dd6d79, 0x18f79bb2, 0xa49ff8c5, 0x81bdc6da, - 0xc49932f8, 0xbf7556bd, 0xc189ef58, 0xadb24072, 0xad0cc969, 0x59c75d4b, - 0xe9d77bcc, 0x774fcde6, 0x023d206f, 0x15c70736, 0xbefb1463, 0x34c4cb65, - 0x1d7030f4, 0x20475e56, 0x0b4d772e, 0xee91dd56, 0x1bc6847a, 0xf87c1388, - 0x7529d108, 0x75cbe878, 0xc43b943e, 0xdfb581f7, 0xbd23eabc, 0x042e29f4, - 0xae4df9c7, 0x475a71fb, 0x51902e93, 0x45fbf48a, 0x05007a2c, 0x9096be21, - 0x0f107398, 0x1af04e6d, 0x77945e59, 0x99f9ca36, 0x8b03172a, 0x4fc43c71, - 0x8b55cb99, 0xcc5422ee, 0x60937e6e, 0x16bdbba5, 0x179e686b, 0x724d3d68, - 0xe4f881b0, 0xc607e268, 0xc76e594f, 0xf454fe0a, 0x9eb6f759, 0xa288c6db, - 0xb2e4c20b, 0xaf89db69, 0x6f7486ff, 0x5071663a, 0x3e3c90f3, 0xe79c46b6, - 0x46fa345a, 0x5d09d395, 0x9c383e26, 0xc5a2f5b8, 0x07d26ed4, 0xb7a4d9bd, - 0xda06f727, 0xe81e7dc8, 0xc8463bde, 0x7fd7ea89, 0x7d8b9d23, 0xfc8cccf9, - 0xf9104091, 0x839c5e23, 0x8af4fc73, 0xad5f0738, 0xeca93de4, 0x788b7de1, - 0x573b8d54, 0xde2dbcf6, 0x6ff07985, 0x122bbd05, 0x713e967f, 0x6fc455e3, - 0xd48bef91, 0x6949b478, 0x7bd7a2b7, 0xf227ed37, 0xc51351bd, 0xbfc345a3, - 0xa27a6a37, 0xc8d1e396, 0xb9bd46f7, 0xb14afe4a, 0xa1f8a08f, 0xb436944b, - 0x87c70b3f, 0xf709af46, 0x35c9fab6, 0xd3952b0e, 0xc7d60e2d, 0xe10e3d57, - 0x6489e1ed, 0x9e5519e6, 0xd893ad97, 0x5af156bf, 0x49c9bcfc, 0x7e7e28eb, - 0xe8cdfb14, 0xe97b8bef, 0xde913e4a, 0x837bd012, 0x2cc189cd, 0xb9ba67ba, - 0xfe41df3b, 0x9d5a1ff8, 0x68430ff0, 0x503c6a7d, 0x4b54bf27, 0x2d8e87ef, - 0x3f0b38c2, 0xa679eead, 0xd5e58ccd, 0x1055e9eb, 0x13f384a5, 0xdf2aafc8, - 0xc6978329, 0xd543ef01, 0x39153b08, 0xc0e9a537, 0x188f8616, 0x0db008db, - 0x29300f91, 0x4fcd8bf4, 0x39c7d4d2, 0x4ff4d02e, 0xd4d2cca8, 0xf788c5b7, - 0xfa71e032, 0xef422a0b, 0x3f9d1248, 0x0083f4d1, 0xbd08adfe, 0x7e27b917, - 0x4f7e4eea, 0x3ce06fe2, 0x2565f245, 0x7926f69a, 0x5dfc4cab, 0x435ea5fd, - 0xa6529fcf, 0xb956f11b, 0x9c1cfd1b, 0xb69f4267, 0x01e0263e, 0x5bb317ea, - 0x984bc9af, 0x85f2da6c, 0x629e4a79, 0xe4d58c2c, 0x2ef10629, 0x61d8fef8, - 0x0545f31d, 0xbaaafce4, 0x006cf08c, 0x6f1a2daf, 0x5df840c7, 0x1c5ac6c7, - 0x426a96f4, 0xc932cbcf, 0x8b4baa41, 0xb5b351ff, 0xd6ed1ff8, 0x52cc7be2, - 0x9bd3be2d, 0xb0bef8b5, 0x4cd78b45, 0xd96f168f, 0xda6826eb, 0x346bdbdb, - 0x578dbce5, 0xe45fda68, 0x8f29a19d, 0x4d7af17b, 0x858ec2fb, 0xaee2fa9a, - 0x957a9ae5, 0x83e386cf, 0x11d5bef1, 0xdd03a6fc, 0x74a0f869, 0xf335cfe7, - 0x9ff450fd, 0x05e8a79f, 0x2bd7fe85, 0xf8dde576, 0xb892f7c3, 0x7a158b4e, - 0x50df3070, 0xee78e06d, 0x6d725b3d, 0xc505e91c, 0x7b14b9de, 0x894f3907, - 0x1d9455b2, 0xa2bf717e, 0x36ab9f64, 0x2cf746de, 0x8a8afdc4, 0x09b5edc3, - 0x1de23ed4, 0x494af4d6, 0xf91dde73, 0x67a66b2e, 0xd1209cad, 0x3f7144bd, - 0x841ef231, 0xdeab3efa, 0x2739a319, 0x96bdee1f, 0x78c25f9a, 0x2f148c01, - 0x3efccce8, 0x721fda31, 0x5fd9946c, 0xf6ffb373, 0x79cdc967, 0xfecc6ba7, - 0xecefe20c, 0x79f5eeb1, 0x3aa3b788, 0x3dfd8d87, 0x00d6fde5, 0x2fdf8c6d, - 0x3ca4ccf5, 0xbb8600e9, 0xdfd4d794, 0xbd2663b3, 0x5be5c45b, 0xac221503, - 0xe68f3fa6, 0x71a41fb9, 0xbbd6480e, 0xbbefb14b, 0x20cf3e13, 0x73a2667b, - 0xff3e12fe, 0xfc2f387e, 0xee147bfc, 0x406df50f, 0x79f0f367, 0x8e25cfee, - 0xc1a73e53, 0x77e4c2aa, 0x4f79419d, 0xb9b6e22a, 0xb8d4be0a, 0xff328e6d, - 0x29621c01, 0x5db9f3ea, 0xacbc667f, 0xe253eb48, 0x158766bd, 0xac71bfc7, - 0x7bef84a5, 0x221d4b39, 0xb8e357de, 0xb1f7f231, 0x87ba67b3, 0x88ed22b5, - 0x97869e26, 0x57cc8792, 0x42c5e646, 0x1fe316fb, 0x76cb1f58, 0x74fac0e8, - 0xc6863fce, 0x85f9ca3f, 0xfbdacdb9, 0x3e5bf3dd, 0x02dff0d2, 0xfa9a27cf, - 0x30d04a40, 0x781ff706, 0x1bd4f475, 0xaffd7f10, 0x9e282a98, 0xe4f5ba45, - 0x0fc68795, 0x897797dc, 0xb4ce1bf0, 0x1d79cfcf, 0x5afdcabd, 0x5bfb9f75, - 0xd03971f7, 0xefb8881a, 0xbfc4d1e4, 0x09fe342a, 0x0e8fc9f2, 0x431c234a, - 0xe76673e5, 0x57a9388b, 0xabda7779, 0x55ed3bbc, 0x2af689de, 0x957b42ef, - 0xbbeaa177, 0x9c095edd, 0x8e64bf74, 0x816a7ae4, 0x0f76efc4, 0x969b3ed1, - 0x5de88b07, 0x60715363, 0xbbf3249e, 0x7df423dd, 0x45bb7788, 0x69f49592, - 0x6ef435ea, 0xcf08f0f7, 0xd9d8b251, 0x50d789f9, 0x28d870bc, 0xc5f4a3e4, - 0x7bd2666f, 0xdd53c7bd, 0x3fbf89c7, 0xf31f6495, 0x9f12ebf3, 0x6033832b, - 0xef16719c, 0x13cbbf7a, 0xf32734e7, 0x0a89b9c4, 0xbd0be647, 0x9cb04a56, - 0x2e6f72e8, 0x68dabbbf, 0x385777e2, 0x7617539f, 0x7df2221f, 0x4d1fc95c, - 0x6a1fd23e, 0x5f2127de, 0xbbd3379c, 0xca675a39, 0x6ef126fd, 0xa0cfe02e, - 0x0f747677, 0xbdf245ca, 0x1de29c1b, 0xf0a6de5e, 0xf90930f7, 0x45bd3dca, - 0xb7a779a0, 0x7ec0e7b2, 0xe5af27d2, 0x53f393b9, 0x56c7ef43, 0x7f676fc6, - 0xc6df20af, 0x797ae2f3, 0xee17a8ff, 0xc79cfa24, 0x7e56617c, 0xd7fff479, - 0xf5bc3860, 0x5a3ff62f, 0xf77a1990, 0xaddef616, 0xaf2c3f20, 0x343faea7, - 0x42e5e9ce, 0xe5a97bcd, 0x93dd8f43, 0x7486724b, 0x5948f911, 0x88633f9a, - 0x05f3d3fe, 0x774feffd, 0x97f9a04d, 0x60bc8b37, 0x6fda6f88, 0xdce898f9, - 0x3ef21963, 0x723fdabf, 0xf5b72b9f, 0x9f703e30, 0x617f68f3, 0xf08cbcfb, - 0xbfb3eea5, 0x05a3ef7b, 0xdfdf73b6, 0x6e777df7, 0x6d71811a, 0x767950d2, - 0x7e613eb4, 0x3fed4999, 0x8fedaf56, 0xb1e5390e, 0xd1de48bb, 0xe254e96f, - 0xc4cbb21e, 0xee5daa17, 0x2920e254, 0x02ed83b0, 0x71724bcd, 0xfb61e4b7, - 0xda3be6a8, 0x947fb424, 0x61af7057, 0x685f217b, 0x775f1071, 0x49f9ef22, - 0x58cef41e, 0xc44773ce, 0x758b3fd7, 0xbc7844df, 0xa335aff9, 0xf2defe28, - 0x38942b97, 0x72abd84e, 0x69cb3f85, 0x4147da7e, 0x996df302, 0x730abeb2, - 0x55c9fb33, 0x5e4591e0, 0xac93c943, 0xdff1c1df, 0x141a01ff, 0x43d0aaaf, - 0x000043d0 -}; - -static const u32 usem_int_table_data_e1h[] = { - 0x00088b1f, 0x00000000, 0x51fbff00, 0x03f0c0cf, 0x1894738a, 0x18357a18, - 0x326b3618, 0x31686830, 0x20318830, 0xaf8568e4, 0x9fa65371, 0x8181959b, - 0x81f98817, 0xd7881058, 0x6c303133, 0xff5e2260, 0xfb045111, 0xc303209e, - 0x197f2051, 0x6614ee90, 0x64055860, 0x2fe2031f, 0x1080be40, 0x100c8303, - 0x606115ff, 0xc1d20530, 0xc4036c40, 0x9bf145c7, 0x7c80827f, 0xbf2a08bc, - 0x279f8d1b, 0x25ff5f8c, 0x0ff2fc11, 0xc363c808, 0xc7e41632, 0x7a052247, - 0x29370207, 0xca8ff2a2, 0x543c3033, 0x51d06060, 0x919bf082, 0x6280ede4, - 0xec21e4c7, 0xb8c09229, 0x28b5ca07, 0x2a773762, 0x5004fe50, 0x34894bce, - 0x41d3dcf7, 0x8434afe5, 0x3ebc00d0, 0x03a8e414, 0x000003a8 -}; - -static const u32 usem_pram_data_e1h[] = { - 0x00088b1f, 0x00000000, 0x7de5ff00, 0xc5547c0b, 0x3d9cf8b9, 0x926eece7, - 0x2126cddd, 0x26c2bc21, 0xb80d4401, 0x41a00c40, 0x94520f37, 0xa2a1e1a8, - 0x24786c22, 0xf622ef21, 0xddbf1f62, 0x52c488f0, 0xd4c51f1b, 0xb051768b, - 0x40368bd1, 0x5c1758d0, 0x6d8b459e, 0xd5a045e8, 0x5e40137a, 0xa540b206, - 0xcffd45b6, 0xdd9ccdf7, 0x26364e73, 0xf6ffef6a, 0x9fdbfffe, 0xcccce61d, - 0x7cdf3337, 0x9be6bdf3, 0x91be6489, 0xf21387d8, 0x256efc25, 0x108951e4, - 0x9b4e1892, 0x9fc6933c, 0xedb10994, 0x3bea247e, 0x9e0c8499, 0xd146706b, - 0x64085fa2, 0x21064b4e, 0x758d65c9, 0x793dfa46, 0xe8bc7d91, 0x9819c308, - 0xbdbae47c, 0x720c8409, 0x8266f6d3, 0x7fe92fbf, 0xc637b73f, 0x79c87491, - 0xe131a285, 0xbc9a4afa, 0x877bfa48, 0x149bbeaa, 0x48dda675, 0xfd51fbfb, - 0x9085b720, 0x4678c31f, 0x40cba942, 0x78b8e8b2, 0xfd2e6f5d, 0xaf0e3a3f, - 0x295be8cd, 0x1c1a2210, 0x242444b1, 0xa0482326, 0x679fbe9d, 0x49d7ed3c, - 0xaa36a708, 0x49e74ac8, 0x0896b4c8, 0x808972f5, 0x76cd8878, 0x78e97b25, - 0xe22e7d57, 0x220d57bc, 0x27d69da4, 0x684ed392, 0x61c4953a, 0x232dc7bd, - 0xd57e4206, 0x07123fae, 0x199b1b85, 0xdc155e24, 0x0e210f06, 0xc7afc513, - 0x8f2ae98c, 0xc4c9a79d, 0xab210d71, 0x574c0e3d, 0xfa634679, 0xdb27d0d8, - 0xf9d00673, 0xe9d8320c, 0x63834848, 0x1191dda6, 0x2dc72786, 0x0938e730, - 0xae2926c9, 0x2f5a54c4, 0x4dc840d1, 0xf342dc84, 0x19082375, 0x5084ec49, - 0xbc933dfc, 0x019dca2c, 0x45e60779, 0x7cc37103, 0x2e033263, 0xc62de291, - 0x1c95cf69, 0x1bf8efe1, 0x785fdf80, 0xc1d6152c, 0xefcc1b7d, 0xf0ece219, - 0x46dd9e02, 0x7f5a26e7, 0x5e4ceca5, 0x468ae14a, 0xad832eda, 0x1e1094bb, - 0x1fc04cdf, 0xc9cc8fed, 0x30d7acd5, 0xb4224718, 0xeb05dc73, 0x75b27164, - 0x1574095a, 0xf2e61d61, 0x77655875, 0x38fd19d9, 0x11fa2449, 0xb1fa5aed, - 0x8fe96864, 0xba9fb17e, 0xbf69e79e, 0x3bed424d, 0xbd3ce953, 0x4dce0c4b, - 0xa160dbf4, 0x0af80051, 0x80c425bc, 0x41f92afd, 0x63a05265, 0x179e1ab4, - 0xf6f7e9cb, 0xefcf730e, 0x52e2062d, 0x2a5372e8, 0xcec4777c, 0x6626e3a0, - 0x6b4cec47, 0xe987f1cf, 0xc925d924, 0x4c0eef40, 0xac47041b, 0x477ce300, - 0x9c049b24, 0xf6a4727f, 0x08edd3ff, 0x377ae1f1, 0xda5475f0, 0x3d203c51, - 0x468b1f79, 0x3450883c, 0x17e70c39, 0xad17cf1c, 0x4a434f45, 0x5868e348, - 0x875f9a5f, 0x79a663f4, 0xb09be62b, 0x3fca1edc, 0xacc9e58b, 0xba5e5d3e, - 0x55e3bd18, 0x6eda1759, 0x4291c203, 0x38445e70, 0x9bbf5096, 0x94203f30, - 0x1fd625ff, 0xb7f7eaca, 0xceed251f, 0xf9c29e0d, 0x003b2ebf, 0xd6dbc29f, - 0x2e94adc0, 0x7c106e0e, 0xec0f9a26, 0x75fe418c, 0x9f0cfd7e, 0xd767e289, - 0xea0b9338, 0x8398df9f, 0xefedbcf9, 0x5e5a24db, 0x20945db5, 0xd679d86f, - 0x5bf141d6, 0xfc7f6a63, 0xb83dfa66, 0x602f245d, 0x9f71d377, 0x48b4e29d, - 0x92f9633e, 0xdaad9628, 0xc01e6bb0, 0x91336b2d, 0xeaa70a28, 0x6f3bd2cd, - 0x03d2f9a6, 0x552a8132, 0x838cea9b, 0x4f897e69, 0x8afc8168, 0x3f601f9d, - 0x0ca4b9dd, 0xe039f7f6, 0x752f945b, 0xee93dadb, 0x7dcbdfa6, 0x7ea00a5b, - 0x09c166f9, 0x7ebe5c4b, 0xbf0087d7, 0x211e55bc, 0xcd15f852, 0xdaa1c431, - 0x17db792f, 0xade309df, 0x9426477a, 0xabb291ed, 0x1891190f, 0xe02346a4, - 0x13d36ab5, 0xe79be046, 0x1fb0073c, 0x2f559f05, 0xbb687ed3, 0x2704d7ea, - 0xc0daad4c, 0x3785cdf8, 0x68bce6a3, 0x19d57981, 0x37fb4147, 0xbd42351f, - 0xebf15f52, 0xdf180e51, 0x8c016306, 0x6306fd73, 0x566f8a89, 0x3356ff34, - 0xe94d53ae, 0xbd19dd03, 0xce39e7af, 0x397c95b7, 0xdf484015, 0x4338cf92, - 0x339e87c5, 0x57fd21c4, 0x11c48b34, 0xdf781f81, 0x8760fbe7, 0xbe03f195, - 0xc0ed4b5e, 0x75ebc21a, 0x4fd7cec9, 0x88cd660a, 0xe71ee7c0, 0xcb91a3f2, - 0x7e41278f, 0x2e69f4d0, 0xf971d63f, 0xe271e4d1, 0x933d67f7, 0x71ef5d30, - 0x67bcfa61, 0x4f3ea61a, 0xc17bd611, 0x8dd30733, 0x7f7e371e, 0x698653c9, - 0xbf16a7b3, 0x8e59e2bf, 0x178f66e9, 0x59e6bfbf, 0xa78b6983, 0x9eadd311, - 0x3d5b4c26, 0xbaf7ac3e, 0x36d319a7, 0xff7e0b4f, 0x530da7b5, 0xe98027bf, - 0x9a5f584e, 0x98ed3c06, 0xc31cf6ee, 0x03a7af74, 0x9cf7eddb, 0xc72d74c1, - 0xe49b2dbb, 0x366f1448, 0x18394117, 0x91cae85f, 0x88be3e69, 0x7ae693e5, - 0x9f348c73, 0x8a79a6e4, 0x8195c1c7, 0x0fcd131c, 0x29e565ae, 0x66b9243f, - 0xb2f14f9a, 0xaeb5b4f2, 0x4f9a28dc, 0xa3e5646b, 0xa3737bd6, 0x8f947e69, - 0x39b75f95, 0xf3431b90, 0xf2b0b5d7, 0x67927eb1, 0x01b1f9a1, 0xd07f1f96, - 0xf9a56795, 0x9f2cedf1, 0xcf37a1f5, 0x1d59f346, 0x5d4dfdac, 0x9a58bc81, - 0xcac829bf, 0xf24ab96f, 0x2e4003ed, 0xb5cf980b, 0xd1c7e4e4, 0xe59dae7c, - 0x4b16860b, 0xb7f4088e, 0x0858ee53, 0xb0867c22, 0x7e5125d1, 0xf1d8d3b3, - 0x647d1510, 0x4baaf0a1, 0x2033fca2, 0xfe504593, 0x963af0b0, 0x19648c07, - 0xbc2a3f94, 0x65bbe58d, 0x5cff9607, 0x46f2c038, 0x87ff9607, 0x7bf30870, - 0xef961765, 0xf2c4fe10, 0xff961746, 0xf981385e, 0xcb1bb2fd, 0x962e853b, - 0xfcb1ba37, 0x5753e949, 0xdf2fed3e, 0xdc2e9ee0, 0x5ddb7208, 0x6a597286, - 0x597e0649, 0x04fff9cf, 0xaf2d0640, 0x3944641f, 0xacf3f3b8, 0xd3814517, - 0x97c800f6, 0x05fa04bc, 0x485b3385, 0xc2827d04, 0x7386fb11, 0x349317cb, - 0xa2f96e70, 0x20f3814c, 0x1fea89c2, 0xdc5f9d9c, 0x17cf1da4, 0x129c0ae5, - 0x7fb5979c, 0xcbe5baf3, 0xbe78ed6c, 0xd4e054ac, 0xfeb89c20, 0x4f20278d, - 0xc809c0d4, 0xe59c0aa5, 0x7fb12708, 0x271971e3, 0x8cb8e06b, 0x7538144b, - 0xff506708, 0x378c04e0, 0xac63c76b, 0x863ce050, 0xbfd61e78, 0x534cb979, - 0x5531e3b4, 0xc29e7029, 0x0ff6a4f1, 0x16ab6ece, 0x21adbb3f, 0x3847acfc, - 0xaf37fb23, 0x3f169b5c, 0x7e10b6b9, 0x6b9c2136, 0xb76707fb, 0xdd9f8b4d, - 0x5e7e10b6, 0xe98cfc43, 0x6372bcdf, 0x8dc9f8b5, 0x0de7e10d, 0xfeb8cf1c, - 0xa26f678d, 0x137b3f16, 0x2009f843, 0x37fb1b9c, 0x2d24fc9e, 0x4293f27e, - 0xe10779f8, 0x9c1fee4c, 0xfc5a49bd, 0xe10a4dec, 0x67080fe7, 0x95e6ff4a, - 0x9f8b503f, 0xfc2181fc, 0x7270807c, 0xa94ccddc, 0xbdac70a4, 0x4c3fd9c3, - 0xc3fd9f8b, 0x8939f842, 0x3852a670, 0x29c37de9, 0xa7e2d148, 0x9f842520, - 0xb6e708f3, 0x9fd9c1fe, 0xfecfc5a2, 0xae7e1094, 0xfa3b9c20, 0xe182af37, - 0x0c14fc5a, 0x55b9f867, 0x8672871a, 0xd8274eca, 0x9a19dfe7, 0xc13212e3, - 0xd179624e, 0xf7a024ee, 0x433e8a88, 0xad225dda, 0x371cd96f, 0xd6a231fe, - 0x068d726b, 0xaa56cf4a, 0x9af5a9e5, 0x1ad149d8, 0x15ce2a3d, 0x4c27c9af, - 0x9fa9ac1b, 0x29a69458, 0x3ae7381f, 0xf720f94d, 0x487e4d78, 0xfa9a4dd9, - 0x35736ac3, 0x6fcbe1f9, 0xf54fd4d7, 0xd3e4d4ce, 0xa9afdcd7, 0x8171b23f, - 0xa69afca6, 0xb5f94d72, 0xfc9aa5be, 0xd7dfcdf5, 0xb2d31fd4, 0x437e5342, - 0xf29a63db, 0x35278171, 0x9e0709f9, 0xb1bfd4d5, 0xf94d05fd, 0x68af63c4, - 0x6c7727ca, 0x3e6fe4d5, 0xfd4d6bf3, 0x9addc129, 0xbd9fadfc, 0x439fa9ab, - 0x6fab53fe, 0xd4d03f9b, 0xa13f6a9f, 0xf24eff29, 0x553d3a27, 0xccaf1f6b, - 0x32afcc21, 0x01afd988, 0xc6f311ab, 0xa76616c1, 0x271c4b58, 0x7718fd29, - 0xa00c742f, 0x033403f4, 0xe0ce5176, 0xe83a6bb2, 0xe4ddeff7, 0xbf4ec6be, - 0xbee8cf7f, 0xbf411ec1, 0x9026f4a1, 0x061d4864, 0x8fe5f548, 0x73de8cca, - 0xd51d5c87, 0x18d7db49, 0x68e2a382, 0xe73123fe, 0xf9c7a03e, 0x83ee0306, - 0x42d49168, 0x411368bd, 0xd4d1e9bb, 0xaabd17ac, 0x1866b0fd, 0x308433d5, - 0x3bb235dc, 0xc328f519, 0x9bd03af8, 0x79d187ea, 0xd164260d, 0xbcbb718a, - 0x61fb6823, 0x8fe0c925, 0x3f991930, 0x91bfd424, 0xfd819ff6, 0x6bfe812f, - 0x94dfe97a, 0xbfd34936, 0xd34ca539, 0xfb48d9bf, 0x90f213b7, 0xbfde26e1, - 0xcb36fd19, 0xfec64c56, 0xd865294d, 0x6a46a3ff, 0x8ffba977, 0x88fff50e, - 0x31ebf681, 0xc7b9bb30, 0xd26ed3fc, 0x5ca53fce, 0x9b237f3b, 0x2e434aff, - 0xe71a3fef, 0x0e456abf, 0x394a7f9b, 0xc189bf9b, 0x0b6ff50d, 0xfa01bfe1, - 0xfd2f69ff, 0xb5b3d29b, 0xa95e1ff3, 0xf589bf9d, 0x76e194ff, 0xfb05bfde, - 0x6dc57a7f, 0x2bc3fe6c, 0xc9a37fb1, 0x31fa04ed, 0xf5ae890e, 0x50c9fed1, - 0x040d256a, 0x40fda172, 0xfd1e3a3a, 0xd21a7708, 0x8bdf1c70, 0x2576f466, - 0xf21bd29a, 0xc3b32f33, 0x5273947d, 0xd39aaabb, 0x1ce6c57a, 0x2c3df023, - 0x3164224f, 0x36a2ea1f, 0x3c9be911, 0xa48df26d, 0x26d0bde3, 0xe8bf217a, - 0xe03e29e9, 0x322635af, 0x49da08bf, 0x3fdf0024, 0x1798d9fe, 0xa7d2f3d4, - 0x53e51b8b, 0xde45fc91, 0x96ba325c, 0x1002ef8e, 0x9c7f2a81, 0x186071da, - 0x1eed487f, 0x139fed42, 0x23efeb32, 0xbe41ef6a, 0x687bda83, 0xe63a9338, - 0xdebaf357, 0x5fc7411f, 0x0b9f9444, 0x6e2f79e7, 0x624f0a29, 0x5af8f7fb, - 0x31eb07c1, 0x450c797f, 0xc53c787e, 0xbe4d04de, 0x07eac4c6, 0x2f7c136f, - 0x0dc30808, 0xe1c199f8, 0xcd2f1811, 0x36b3b1cf, 0xb1de7747, 0x7dd1b05f, - 0x5d0866b4, 0x599c308b, 0xa40f25c4, 0x565eefed, 0xa76b832c, 0x8186105d, - 0xa166b09f, 0x3768024c, 0x0649137b, 0xde3a0e27, 0xfe0cedfb, 0x527c970c, - 0x239b47ed, 0x74455d9b, 0x458a733c, 0x69acff1c, 0xed3ff2da, 0xc619718c, - 0x53cd74d2, 0x45ddcfd8, 0xe77bf2da, 0xb9f7f368, 0x572a79b5, 0x0fab9065, - 0x53bfe994, 0xdf8124b4, 0x001bf431, 0xe3907ce3, 0xd95ac1e1, 0x6a5759ab, - 0x72951b76, 0x09b88470, 0x8bdb0bce, 0x5fcfeb3d, 0x7b17cdae, 0x6b85f9b5, - 0xdd39f074, 0x7febe29c, 0xa683e81c, 0x283e81a7, 0xfa724f3e, 0x2d55f308, - 0x9a13dc7d, 0x650fa306, 0xb624a71e, 0x33d6a704, 0x18dc58fa, 0x8a1e9913, - 0x52e0f443, 0x0f4297d3, 0xfc3d38f3, 0x6943d399, 0xeeae9693, 0xc9d5be23, - 0x6b03fdb4, 0x1d3ae177, 0x3d198a11, 0x87a140fc, 0xb83d0d0e, 0xd7e83d39, - 0x87a71e6f, 0x7a308f79, 0x0767afd0, 0xa68e87a7, 0xeb4932cb, 0x1d74aeb9, - 0x0eba7934, 0xa3b775ba, 0x47ae8a1f, 0x10587a44, 0x389d379a, 0x65e42fcd, - 0xd38bd63d, 0x01a79603, 0x09e209da, 0xacf7a7db, 0x2684f94f, 0x7914da5f, - 0x36da6bfd, 0xfaa93dac, 0xf2f2d55e, 0xbb7fb55a, 0x268b79a2, 0xa6f7c4bf, - 0xd3697ea6, 0x717e4d2e, 0xfa9a3be3, 0xd21cd70b, 0x7fbd8be4, 0xbf9fd4d4, - 0xfe5353bc, 0x4d59ed60, 0x176503f9, 0xdcfbf935, 0xbfd4d37f, 0x13f08e77, - 0xa2eefe75, 0xeba89fa8, 0xa7169acf, 0x0d70cfc9, 0xec37d4d2, 0xa02ef6bc, - 0x8bef83c7, 0x4f8ff404, 0xffd1a79d, 0x7653a9f9, 0x1e939d42, 0x5383ee07, - 0x9e98d19e, 0x9f7138f1, 0xc24cf39c, 0x1edb42f4, 0x2a15c80b, 0xc8e04b47, - 0x96e574a6, 0x20d935ba, 0xdfca09d7, 0xd46f958a, 0xb2128779, 0x8a639414, - 0x2326c2ef, 0x44204c09, 0xc7c4e100, 0xe5551415, 0x37947d1d, 0xd0914151, - 0x23b0bcb3, 0x279af7f2, 0x23db878b, 0xf7847f9c, 0x7a021935, 0xe72f7752, - 0x29029524, 0x64277f52, 0xad81f205, 0x34a94f5c, 0xb9517e32, 0xb12e5075, - 0xaa303e41, 0x6bfaabf6, 0x206c9ba1, 0x66ba49d0, 0x5d36973f, 0x04f7e1af, - 0x4089cfbc, 0xdf34136f, 0xd66f9a2b, 0x25daebb4, 0x81abb8e2, 0xfdb95097, - 0x527a292a, 0xd8153e04, 0x0c6b3293, 0x14f5d38c, 0x5112dbe6, 0x34f2ec8f, - 0xc7f385af, 0x4c169e73, 0x30da78cf, 0xac09e53d, 0x93c07385, 0x1e98039e, - 0xda63b4f7, 0xe98639e1, 0x4c0e9e47, 0xc19cf43f, 0x209e4ff4, 0x9f3cc7a6, - 0x43c47a61, 0x0e70027e, 0xfe98cc7b, 0xb4c763c1, 0xe98c93dd, 0xfb0f8f05, - 0x5f5df651, 0xcb867774, 0x7f4073ed, 0xbb6ce811, 0xcd6eac78, 0xbd9d30d0, - 0xa423f2b9, 0x85cf0533, 0x0f4e264d, 0x087a1a49, 0x2377ed80, 0xe51f4bd0, - 0xc3a7324d, 0x2e47dade, 0xbfe179af, 0x7caede87, 0xd30b7a4b, 0x3d1d10d3, - 0x4f45f7a5, 0xe9e9aa1f, 0xe4cec18a, 0x1fa7a720, 0x7d6b73f3, 0x3b1251bf, - 0x77e90ca7, 0x800cdbae, 0xdcfca5aa, 0x98699084, 0x5efbc4bf, 0xa3b5c149, - 0x0d1be81e, 0xe8d2eb72, 0x73828fbf, 0xe8c74b87, 0x3ef6a7e2, 0xf49d3d3f, - 0xda17778e, 0xba3e2543, 0xc61109e8, 0x1af0cd1b, 0xc8d32065, 0x461a4278, - 0x905ce4be, 0xc4897981, 0x739f7b43, 0x3af38446, 0xc06b7542, 0x5d785f6f, - 0x1632bd69, 0xf67a9de0, 0x5e90591f, 0xf475fae1, 0x7cf5111e, 0x09d17812, - 0x25c90df8, 0xfc193393, 0x4691c1f3, 0x6409ea3b, 0xde7f16ba, 0x6bf835db, - 0xcfce5548, 0x7f11931b, 0x1a8cae23, 0xf5fc0fd4, 0xc2fbdfc5, 0xf79802e7, - 0xfb3e037f, 0xf17d8fe2, 0xbc72e245, 0xdfe746d6, 0xf8cc73bd, 0x07c01cc7, - 0xcadf1abf, 0x3c7e9c79, 0xb5f492f9, 0x493bb8e8, 0x14f6e3a1, 0x24d85b88, - 0xa5fe11da, 0x61626bd6, 0xfa70425d, 0xede14f58, 0xbd80a73f, 0x0b553e7f, - 0xef074b2f, 0x6d1781d2, 0x4d2d7760, 0x3270d85e, 0x69283ac2, 0x835d4b55, - 0xb687ad45, 0x1a97f369, 0x382d6985, 0xecec472e, 0x6a272031, 0x5edf181b, - 0x6702a98e, 0xf6097269, 0x3d39ae73, 0x3e7bd996, 0xc7360fc6, 0xe738bf21, - 0xfffac329, 0x06f4f1ec, 0x210f1947, 0x1984e4ad, 0x4b2d31f8, 0xaf7ebdef, - 0xc5fd2cf4, 0x7edde788, 0x89e80af9, 0x97dffa66, 0x09107760, 0x9adc0af3, - 0xba6bd116, 0xd66fbe01, 0x39db47f4, 0x2fe23394, 0xdf6abed3, 0x4294e448, - 0xd45e54b7, 0xe780bd83, 0xd41a4b9b, 0xcb55597a, 0x9af93577, 0xd41a47b6, - 0xfc055c7a, 0x525ff283, 0x3740482b, 0xba8c9c95, 0x811acb25, 0x8218af8e, - 0x088f804f, 0xb9955eac, 0x9fa6e8c3, 0x75b2b7ce, 0xe77c6deb, 0x8854e63c, - 0x3733283b, 0x597239e2, 0x20f9b5cb, 0xaeb7ce67, 0x5bf9024c, 0x5efa5e21, - 0xbff68451, 0x5f2e0494, 0xcf56a0e4, 0x2841f4e7, 0xe9bcd55c, 0x17c212cf, - 0x981977cd, 0xb70f465f, 0xbe91cb8d, 0xf9bd53f0, 0x8ecdc150, 0x6eaa789e, - 0x237468bb, 0xcbffa45f, 0xc149e30a, 0xd454b15f, 0x9771d126, 0xffa27737, - 0x1dec8ce2, 0xe0af83f5, 0x67e73d97, 0xa3153e49, 0xb497979a, 0x260b3f43, - 0xe3888ef1, 0x1f280fde, 0x995bfb3f, 0x57221f00, 0x742cad69, 0xc7bb70cd, - 0x61590c40, 0x6b4167bb, 0xfbe02145, 0xd1d3ebec, 0x8a445bee, 0xa40eb86c, - 0x9cec0b31, 0x7180c4f3, 0x1fc9e755, 0xeb54136c, 0xe464b1f0, 0x305ca678, - 0x1034bb89, 0xd8107bbe, 0xf539a65f, 0xf858e2ed, 0x9076292e, 0x15ca25f0, - 0x17f180b7, 0x2f77d873, 0xfd01d731, 0x634a7b52, 0x4a7b51af, 0x94f6a793, - 0x66425f26, 0x453c4126, 0xf132d3c9, 0x4d278809, 0x8ec941f9, 0xb5252be3, - 0xfd1fa0f5, 0x16e1fb9c, 0x843489d8, 0x37aa87ca, 0xa62acb9e, 0x9892e9f3, - 0x0f894bff, 0xc5654258, 0x5e5e5a20, 0x2cba33e6, 0xa277e73d, 0x943dc275, - 0x163c03f3, 0xd1bf7007, 0x886be2c7, 0xaae2ca43, 0xf3ef5a4f, 0xba2ad81f, - 0x8f506ca2, 0x9bc6577e, 0xafe7f5fa, 0x4f212f9f, 0x9bca3ce2, 0x561c6067, - 0x3e07788f, 0x7059b91f, 0x27ec22f9, 0xf1341651, 0xc332092e, 0x1ad7e29f, - 0x0f5fcbae, 0x6bdf9579, 0x1bfcaea2, 0x440197f3, 0x258a5fc3, 0x913970f7, - 0xbfc013f1, 0x7f710520, 0xc9f8637d, 0x2f5fe03d, 0x844ff8df, 0xefbb543f, - 0xff89fc29, 0xe88ff1d4, 0x48bcfe31, 0x78deabf0, 0x778875f5, 0xcfd5ff2c, - 0xb7ee846c, 0x926352b3, 0xe57bae93, 0x1736d5a6, 0x6bc91df0, 0xd6717d83, - 0x448b4e27, 0x7997df0f, 0x59711fdc, 0xc2bbf004, 0x73fc293f, 0x4ef8fcaf, - 0x6caea3b0, 0x4fe8ed92, 0x4c05366d, 0x5bab9e94, 0xb1921497, 0xf964ef98, - 0xfd022f47, 0xc7c9b4d7, 0xfe5a74d5, 0x41259fcb, 0x94a5107c, 0x48648621, - 0x549f6803, 0x00b8fc6f, 0x121a8df4, 0x6faafdc4, 0x167ffd07, 0xd8b0f28f, - 0x1cb3db18, 0xd049341d, 0x5a6afd9e, 0xb4517c7f, 0x69db7a41, 0xb2d46fe0, - 0xbe90bf44, 0x3bb7195d, 0x00eb642a, 0xc913abe4, 0x0aabe044, 0xd98f885e, - 0x7e5f2b1d, 0x1d276c66, 0xdfc6d757, 0xbe1504da, 0x52e97b14, 0xfc5fc2cb, - 0x1f3bd1da, 0xa3f740bf, 0xe455bf5a, 0xdb8da394, 0x56967e4b, 0xc41b01ca, - 0x906e5573, 0xb9fa5e9d, 0x5f17d5f2, 0xd9fc167a, 0x4739347f, 0xaf15f852, - 0x13723bee, 0x916c57cd, 0x69b21407, 0xf0a48458, 0xffd0d4fa, 0xaf0f8f96, - 0x7db6f947, 0xf618c746, 0xe1f187fd, 0xb2d8a975, 0xf4c648cb, 0xcb5e47c4, - 0x2587632e, 0x74b4fac2, 0xb7fe8016, 0x1abfe5f2, 0xdd9def81, 0xa9819029, - 0x61b9f011, 0x8087ea1f, 0xbe4f5c27, 0xd3f5a15e, 0xeba1afd5, 0xbf467202, - 0x857afa5e, 0x5c00bf9c, 0xf4a1b388, 0x21afdafd, 0x264fee0e, 0xeca1e027, - 0x306c87b5, 0x2d52d39f, 0x56e7f3a3, 0x2bbf0127, 0x7649bd93, 0xb2f7d94c, - 0xfa461fe7, 0x70f43d2b, 0xba57f312, 0x76501906, 0x3cc1077a, 0x1bbfaf17, - 0xdc4259e7, 0xcf658748, 0x9a3e4589, 0x69912a7e, 0x93ec225b, 0x9c9f7c4b, - 0x2e2e817e, 0x4569e79d, 0xe441fc2e, 0xe8bbe172, 0xcf987d0f, 0x98906a85, - 0xd6ccd4ff, 0xd06c80eb, 0xfd10d1c8, 0xe5147c6e, 0xae61b9c7, 0x56ee7081, - 0x28179613, 0x5343c447, 0x6275b207, 0x51db0772, 0xdf0793b9, 0xecbb7ea1, - 0x69ab1a8a, 0xe9467287, 0x9fef197f, 0xf41a3b8e, 0x9149d3b7, 0x46e191ed, - 0x3d500f85, 0xaa674543, 0xfff6cefd, 0xdfb606c6, 0x9beffd95, 0xffca0d31, - 0x23ed9872, 0x97720768, 0x10302b8e, 0x16cd77cb, 0x48983f90, 0xdf3ed220, - 0xae7df328, 0x0bd3d72d, 0xc424bf1d, 0xfa06e8aa, 0x4075c789, 0x34f25f79, - 0xa3e2af6d, 0xadafd035, 0x1f655c27, 0x707e7297, 0xf5c1f81e, 0xd6407e61, - 0x5e2bf627, 0xbdf652b4, 0x5fec2cf4, 0x0ebd5fba, 0x1172bfd8, 0xcd93ffcc, - 0x4fdc8e7b, 0x2d27edf7, 0xf2d5beca, 0x2dbefd55, 0xc630fadb, 0xedf7eb9f, - 0x496b4327, 0xbf4b7dc4, 0x43b7dc47, 0xf847fe3b, 0x24c782aa, 0x2aaf96a3, - 0x7c37b27c, 0x16e4f9ea, 0xd57881d9, 0x3bfa49f3, 0xd27ab24c, 0x0a8742a3, - 0x47ff95fd, 0x47e070d5, 0xe8553a21, 0x0aa74430, 0xade7ea1d, 0xfcbea3c5, - 0x522df023, 0x537a297a, 0x4a95f3c6, 0xa6038b3f, 0xc90ff6ed, 0x50b97c44, - 0xfdc691cc, 0xf3a80643, 0x45be5d3e, 0xcba5df57, 0xbbeae917, 0x4d5af975, - 0x3db6cafd, 0x10748246, 0x9713d4d0, 0x31393bff, 0xfadd1221, 0xf5a1bf98, - 0x39ee11a2, 0xd88258d4, 0xbc415e5e, 0xdc191f10, 0x51b9e221, 0x3d71c537, - 0xa73637f8, 0x8f94bcfa, 0x7e628eac, 0xd07b6e85, 0xd5d34f16, 0x4c1f2c71, - 0x1f03d634, 0xa307be54, 0xbbb1df98, 0x538b6828, 0x7e9d5bd9, 0x8778f911, - 0x0dbdf22f, 0xdd70692a, 0xd7b97a3b, 0x758f9ca1, 0x62c6db47, 0x3e29d17f, - 0xa2a9c7a0, 0xf8396525, 0x27451aa1, 0xea8bece8, 0x79c1b5ee, 0xfd3fb755, - 0xfbf439ae, 0x164477e2, 0x4975e38e, 0xd0765483, 0x975de219, 0xf05c402d, - 0x859fa45a, 0x2d17667e, 0x3f791b5a, 0x2576f394, 0xe0466596, 0x390ed4bb, - 0x51ef3eae, 0xd7ad94e0, 0xe74ff77d, 0xed11a6fb, 0xda8df2ff, 0x9fb73772, - 0xfce4647f, 0xc7191c67, 0xbfe657ed, 0xaa7b7ce1, 0x1cd77198, 0x07dd3eba, - 0xf9a26244, 0xd7117e4b, 0xc166d2e7, 0xe237fe07, 0x57fdc44d, 0xf546824d, - 0xd82e887d, 0xcef4d75f, 0xffb6bac7, 0x4007eb39, 0x307faf47, 0xda69dff6, - 0x471ffaf5, 0x37f905bd, 0x407ca68e, 0xdbcfd67a, 0x02f18519, 0x48ad3bdd, - 0xde3bddff, 0xe401f94b, 0x613934df, 0xff3bdd9c, 0xa9e8163a, 0x0ca9857b, - 0x30f760f8, 0xb95dbfe6, 0x3b63afe3, 0xc2aefe50, 0x1a366c75, 0xffc99f99, - 0xdee08f8f, 0x9d3f25c2, 0x3c17e815, 0xd7e6beae, 0xf0823e51, 0xbea59aff, - 0xe76df40f, 0x43e3cd53, 0xce64adba, 0x1c5f1856, 0x79a87f8b, 0x758bf26b, - 0xd6aaffb4, 0xb485c65d, 0xcfedef3c, 0xfd1c62c7, 0x5d37a656, 0x879e3b90, - 0xc66d87f8, 0x2994acef, 0x26c02f9e, 0x5df646a3, 0xb07935a6, 0xe5e27a8f, - 0xf5a7f473, 0x1aef1f17, 0xaffd7d99, 0xc5c10f8f, 0x67d59ff8, 0x7fde6016, - 0xf403e8fb, 0x2e909a83, 0xd27ef995, 0x4cfa8752, 0xfb3ef35f, 0xfa0e86bf, - 0xd0216f3b, 0x4d9b799f, 0xfdebdaff, 0xeb81d1b8, 0x3d07dfa2, 0xf7c77ce9, - 0xd5aaff30, 0x27ede389, 0xfd368fbd, 0x5beeb63f, 0xfadbbae9, 0xfe77f79e, - 0xfbdde7c5, 0x8f33bfba, 0xce1dbbaf, 0xfede6b53, 0x75f7c71c, 0xffe95cf9, - 0xf457ba52, 0xad4376fd, 0x6f8e933d, 0x82b4690e, 0xe25f7162, 0x03a64b25, - 0x0f2f70a2, 0x383bf8c0, 0x57608d5f, 0xbf989935, 0x581824cd, 0x82dddabc, - 0x3b4447e2, 0x5fae4eeb, 0x0cb439dc, 0x5d3b90f5, 0x827d413f, 0x39edb548, - 0xee7b7eb4, 0x6ac62742, 0xdcc7f192, 0x853d9f90, 0xe6f6b5e7, 0x12e204ef, - 0x677f7ea8, 0xa003f4ee, 0x12e5dee7, 0x29a60f51, 0xa7efbfea, 0x93efb014, - 0x7dd0f6b4, 0xdefe6d6e, 0xddfcda39, 0x843dde1c, 0x229eff8d, 0x587e07c1, - 0x8953ce53, 0x2d3597e0, 0x0a908996, 0xabb54671, 0xbbb8eec1, 0x197edb48, - 0x7f2a6728, 0xe3c537e3, 0x5c78436f, 0x3921788a, 0xed03de22, 0xdc7c8f13, - 0xf9c7b3ed, 0x489ace20, 0x7bc7864e, 0x37e89caa, 0xccb8f6e7, 0x3596cbdb, - 0x659fb0ed, 0xd8ae1d9d, 0x9be1bdd3, 0xe11cfb70, 0x2ff185a4, 0xcfb444bb, - 0xae7d9d65, 0x5dd7cbac, 0xbf1d650f, 0x073cbaed, 0x786372eb, 0x5c5a865d, - 0xccabf604, 0x8b7c87ed, 0x1687e593, 0xe8ae7611, 0x00d2fac3, 0x8466f117, - 0x9897d1e3, 0x9ce02b8b, 0x405a3ccc, 0x6b5dc87f, 0xe60f9445, 0x55c7010c, - 0xf8c64934, 0x450d8fe3, 0x85deb059, 0x7f562613, 0x09c30d9f, 0xf1c25cf8, - 0x516a425e, 0xbf57257f, 0x0b3b32fc, 0xea0825ce, 0x845c4bbf, 0xb8ed41dc, - 0x10216c92, 0x126af10d, 0x078ec6f1, 0x8e40b93f, 0xdae4fc6b, 0x496efc3c, - 0xabe9c30a, 0xe5fc6f7e, 0x17fe9d9f, 0x29c767e5, 0x3a427491, 0xd497bb12, - 0x3f7cf776, 0xa54d63c3, 0xba434be0, 0xfbeac80b, 0xb66605d3, 0x87ebfe0f, - 0xe64f9013, 0x2c4c74fc, 0xe26407f3, 0x6e1ac47d, 0x3af25c37, 0x760fc162, - 0xcfce9fc9, 0x6a6cf373, 0x87a4aabe, 0x9ffe1db8, 0xd3489710, 0x51a17cee, - 0x048b3b04, 0xcdebffd1, 0xc57bc28f, 0xcca376fa, 0x6bafbe06, 0x3f002fd1, - 0xf2afee11, 0xa6d29479, 0x75aaf1b1, 0x59c77b5b, 0x75cf6c69, 0xd571df80, - 0xc5b7ddf9, 0x80fdd82f, 0x1d5143d7, 0xe6114505, 0xafe3893b, 0xf0dff770, - 0x7f4ceafe, 0x99780caa, 0xce6a2f99, 0xee669df9, 0x264098cf, 0x770ab8c0, - 0x0c9b66df, 0x744072eb, 0x1ad57dc2, 0x3ba345ff, 0x1eb1f9c2, 0xfc1f009f, - 0x676427f0, 0xc4f3e009, 0xd808a24f, 0x73f1efd5, 0xcfb80cc9, 0x1eae8191, - 0x731df817, 0xb84fcccc, 0x74c76cce, 0x9c8e6156, 0x68cdfb48, 0x50838fb5, - 0xfebcc1b5, 0xcb03b33a, 0x4a76f087, 0xac95c1bd, 0x5ed1a75e, 0xbffe691d, - 0x79f8128b, 0x937bf399, 0x75bd7f84, 0x35a9f9cb, 0x41fa0b90, 0xd167e2be, - 0xfdc135d3, 0xe09a6971, 0xf60df903, 0x050be630, 0x53de1fd4, 0x64cfafee, - 0x7ba15672, 0xcdab9e3d, 0x1e02f7da, 0x887f78e7, 0x678287d3, 0xf1fabf05, - 0xbf29f52a, 0x9fed55ba, 0xdc6dabba, 0x54dfa06b, 0x81bb05fb, 0x3a96aa82, - 0x6b0fb08c, 0xe1909eda, 0x073ee67c, 0xa2a44b83, 0x83f8eab1, 0x0f166675, - 0xcdfc67b2, 0x2e4e80f3, 0x2c8135af, 0x1745ae24, 0xdf87c06d, 0x0f7f3833, - 0xdfde6c71, 0x57d36489, 0x3c0fabf0, 0x597cf2f6, 0xe715370d, 0x4732ab33, - 0x03da7706, 0x81e4bb95, 0x675a7a2a, 0xe572c78e, 0x074ae0fb, 0xfb420fbe, - 0x1f7871c3, 0x4fb81137, 0x8ed2d192, 0xa81f6cf7, 0x5874638d, 0x88cbb2d6, - 0x7bcd54f9, 0xfa3f4a22, 0x50bb34fd, 0x30bcaf1b, 0xe02863af, 0x5814d0a5, - 0xa7408ce6, 0x7394a393, 0x2729afca, 0xc76e945c, 0x27247ffe, 0xa2722996, - 0x95e3e303, 0xe7df02f6, 0x3031392a, 0x5a589c92, 0xeb0818e7, 0xfa4774b0, - 0x4b24d840, 0x149a99df, 0xefbc4e49, 0x47cce761, 0xeef67df9, 0xdc4e54d9, - 0xb31392a0, 0xf44e90a3, 0xf6513eed, 0x42725f49, 0xcbffb759, 0x907de6fc, - 0xf7f61113, 0x71393a17, 0xe518bf8f, 0x45b33dc4, 0x4facbdcd, 0x391394fb, - 0x5e61f749, 0xa044c676, 0x7db9f79f, 0x0bdf9473, 0x5e407e80, 0x11d94664, - 0xd1b97a6f, 0x53ff5f1b, 0xfffaf97f, 0xbe159e10, 0x3fda94be, 0x7448d4a6, - 0x979e9048, 0xbaf947de, 0xf8c8f400, 0xb907d2fa, 0x67c7539f, 0x66cf808b, - 0x6b2cf9aa, 0x7266ed5f, 0xf52da6a1, 0xfcb4b999, 0x09d946fe, 0x30fef2a2, - 0xf352cddf, 0x5ea8ccdd, 0xe3196ef8, 0x13fd97bb, 0x6dea7f50, 0xfce67f7e, - 0x11b3f296, 0x31f408ce, 0xe68c6e67, 0x7189dede, 0x06d8c9bf, 0x113de5fb, - 0xe63f79cf, 0x71c1c07a, 0x7d04c9bf, 0x9e3e49fa, 0x2f3d7c79, 0x3e794878, - 0x22de5fc5, 0x6d574fa6, 0xd57f1116, 0x57ff6cad, 0x073e0b37, 0xff8c17cd, - 0x56d79e1b, 0xb5e760ec, 0x39850674, 0x78aff5aa, 0xce1ea3af, 0x08362a09, - 0xf70cde78, 0xa59f001e, 0xce259f1c, 0x29573c0a, 0xc1fad26d, 0x2f6da21b, - 0x1e101b90, 0x78abc3fa, 0x105342fd, 0x7f0a1dcf, 0x20373829, 0xabb6d49f, - 0x59fb711a, 0x9a2a4fb0, 0x0d9ddf75, 0x3704ae78, 0xadaf41d4, 0x7b96d16a, - 0x8b17bcf8, 0x146d8c81, 0xb33df93e, 0xf778f4f3, 0xf653f1e8, 0x8873f12d, - 0x9ff327e2, 0xfe259f87, 0xf05e785d, 0xc7a2f175, 0x3f145d47, 0x324f181f, - 0x6c7e3f61, 0xf17f2170, 0xbbe22bbe, 0x189e8b4e, 0xe50f79a9, 0xef2f1ca7, - 0x83f5dc19, 0x80b55ea0, 0x6fd74af5, 0xf34497d9, 0x38c85b73, 0x6d286638, - 0x90e3cad2, 0xa0756ffc, 0xbb5b9f7c, 0xdab88045, 0x60befcc5, 0x7c09ef99, - 0xe5c1e63f, 0xfad3de54, 0xdc9bc70b, 0x287e5e70, 0x53fc882a, 0x409ddfa1, - 0xfa6f94bf, 0x0c4e38f9, 0x9ca3e60e, 0xb8ec136a, 0x4c51032f, 0x8275d16e, - 0x4cf66d77, 0x5f016bfe, 0x6a5fe617, 0x4358eb63, 0x75f60dd7, 0x5be79f81, - 0x80f83e98, 0xe73b22ff, 0xd992eff4, 0x490238fb, 0x44e77e40, 0x8f915cfb, - 0x939aee70, 0x1ddf5aa4, 0x37fe8c9d, 0xe0fc4e09, 0x36fbffa3, 0xbacbdbeb, - 0x7f4cfa2a, 0xd3c157d7, 0x1f3add4e, 0x9c2f6a8a, 0x8272e780, 0xf20bdf13, - 0xd179e1c7, 0xfef646c9, 0x1fae41cd, 0xd805f7e9, 0x78f7ea1f, 0x21c0c066, - 0x145a7a2e, 0xbf6295c6, 0x533f4c69, 0x3bfd29f3, 0x6e375f48, 0xa3b486a9, - 0x7f8e165e, 0x066edf74, 0xd04d3fb9, 0x19d149c4, 0x27ffbee1, 0xbea397c0, - 0x36493e02, 0xc8797ca3, 0x19eebece, 0x1ef02466, 0x3235e5da, 0x06bdd1d2, - 0xe06c91c7, 0x04c98f2f, 0x83e5c7f6, 0x3b9d1e37, 0xa445ca00, 0x26f7e28f, - 0xa56b8354, 0x91aac598, 0x5c9847e2, 0xfffbc13a, 0xaed79513, 0xa097786b, - 0x7ce27b07, 0xb674bf70, 0x0754d773, 0x0f325bf8, 0xcf7386ad, 0x23f67959, - 0x1b1d6047, 0xc74fbbd8, 0x9da1e4d7, 0x0577d0f6, 0xe8c767dc, 0xbb9c017a, - 0x391ea767, 0xe0f7c742, 0xb73c449a, 0xbc4aeb9c, 0xe731ce07, 0x0e9d141e, - 0x5de16f5a, 0x7f9c0b56, 0x122d1f4e, 0x0f2f0ab7, 0xeff47692, 0xeefdadcc, - 0xca4fb0dd, 0xf7843ca8, 0x87fcca9c, 0xfc840ea6, 0xd7db017a, 0xb846dd78, - 0x74ded9e7, 0xfb4998d1, 0x00f5a12f, 0x59eb35dd, 0x028d9abd, 0xe25817be, - 0x64f9027f, 0x1f0146c9, 0xfaa769c4, 0xf5c199af, 0xbed12981, 0xf9a7b69e, - 0x700f6852, 0x03ddc637, 0x743593e7, 0x527ed89c, 0x97539e1d, 0x98b476d0, - 0x2efc6fb4, 0x5eb25bc2, 0xb0af7020, 0xe3ea526c, 0x41de0093, 0x47e509d9, - 0x08dcfd77, 0xfb479ee3, 0x2fe1441b, 0x42a63b14, 0xc103f27d, 0x152eef8e, - 0xbafb8b5e, 0x623bef9b, 0x14e2cd1f, 0xefdca204, 0x2af1d493, 0xb869d125, - 0xd7964a9f, 0x3abcc3d5, 0x06a989bc, 0x468ba7a4, 0x2927e390, 0x7f54ddbe, - 0x7164613d, 0x27bc7b30, 0xfe2a1d8c, 0x1d3a32b9, 0xcb6a2fdb, 0x98b33e41, - 0x853c6114, 0x23e98ebb, 0x7ca3ab9d, 0x94eb57e0, 0x7df029ed, 0x7e136acf, - 0x932af0bf, 0x7586173b, 0xf4fb7fa0, 0xbdc0997a, 0xd3eb95c7, 0x9e3ac1d7, - 0xe13b2cde, 0x8e7c40dc, 0xbe9411c5, 0x7b64fcca, 0xa7b833d6, 0xcb7f199b, - 0x02eeee7b, 0x94a5dbe0, 0x7e70994f, 0xe2563e5a, 0xf53e4728, 0x4be3145c, - 0xe7a57e7a, 0x1b8d6553, 0x65a1cb22, 0xd0e59105, 0x37ee7ad0, 0x6b9f2c8d, - 0xbbe98588, 0xf078c9e3, 0x0d571663, 0xf404d79b, 0x70bb20fc, 0xf3781ed0, - 0xdc819fd3, 0x3be2b4ad, 0x7d92d565, 0x83e8c09d, 0xeb9fff00, 0xec29f2df, - 0x51b9b287, 0x29d90ef8, 0x47d80f58, 0x1cf0136b, 0x8c57c4bb, 0x79e25778, - 0xf4b49b4b, 0xef21f8ae, 0xa5c48b73, 0x31655f96, 0x77aaa5c4, 0x6e9447f4, - 0xdbf33f69, 0xcab01f04, 0xdcea3fa3, 0xe62670ff, 0xe5ae38ed, 0x6b583f5c, - 0xfa3eba45, 0x40d5c5c8, 0x287ef3b7, 0x89dbd010, 0xf20f5dd7, 0x7049bab0, - 0xf4b89f80, 0x297dac87, 0x3ee30f6d, 0x5f4673fa, 0xb01dce94, 0x3fd7aa0f, - 0x6feb1fb1, 0xff001c14, 0xd46286e8, 0x22bcca27, 0x9d8df2c1, 0x79504768, - 0x7b68f185, 0xec1262bc, 0x2655ea83, 0x1562b83b, 0xb3e8527a, 0x40a7bf93, - 0xb3b1cecc, 0xb4673b68, 0x9eb2f903, 0x4239c52e, 0xfd029e48, 0xbd1978d4, - 0x3b2abe75, 0x4df48b61, 0xbd1eec9f, 0xd0227f42, 0xfe98665f, 0x33cfacf6, - 0xf69e3d02, 0x91671809, 0xf40bf407, 0x9fe2b2f9, 0x1eb51621, 0xea7d17d5, - 0xfd07b0e9, 0xe958cbc1, 0xe854fa61, 0xc7874f51, 0x8c0f7225, 0x51d5a1fb, - 0xfabc8f38, 0xce59ef37, 0xcf9e19f6, 0x923fd5e5, 0x44bafb04, 0x0a407162, - 0x1624ab5e, 0x5c63d637, 0x0719d74f, 0xba7c67f5, 0x0e8acc71, 0x20f1edc9, - 0x4a3ea9b7, 0xdf9fb402, 0xe3117e6c, 0xd2bfcf2b, 0x37ea2779, 0x003a516f, - 0x92b66ffc, 0x3e21da00, 0xade547e4, 0x1369c622, 0x4b359029, 0x712bbf65, - 0xb2bf1531, 0xb7cbbe22, 0xb4857c9a, 0x27ebf97d, 0xc25c62c6, 0x7b7fa60a, - 0x39d8115f, 0x2c63b788, 0x972a3bdc, 0x5e8e7c58, 0x345df82f, 0xdebbc3b3, - 0x7a03998c, 0xdeccd09b, 0xb96f2c17, 0xfca93657, 0x65a2fbbb, 0x939e1ea5, - 0xc33ae979, 0x3e300afb, 0x4a76fbf5, 0xcbd74e5c, 0xdbcafe8c, 0xcae7d464, - 0x805cb79b, 0x63f2cd78, 0x6b77b426, 0xc11a2f9a, 0xd5fbcd9e, 0xc41decab, - 0xa7135136, 0xae3e23d7, 0x20980c59, 0x0ab5abae, 0xbe6871cf, 0x3c2df313, - 0xc66bed1e, 0x6afc556f, 0x8a5eebc7, 0xbf6d8ac2, 0x857be1b4, 0x786c9bed, - 0xabf9aa5f, 0xc47b55e3, 0xf034b5c3, 0x4e3bb878, 0x918fe413, 0xc1cee1e3, - 0x7d21283f, 0x878dad16, 0xbf8ccd23, 0x456671d1, 0xa4350f7a, 0xe9fabd77, - 0xddcf10f3, 0xe793f5b5, 0x5f95dc61, 0xe21e7e5c, 0x6882a86c, 0xe6a53d07, - 0xfe31f795, 0x1f176955, 0x97a0edc3, 0xc3f1897f, 0x7268fe17, 0x3b0bb402, - 0xfe80a74e, 0xdfcb6171, 0x782e2092, 0xe8a98ed9, 0x3db659df, 0xedbddf0f, - 0xfa059ecd, 0x7e23f5f5, 0x7b6ebf59, 0x3c60f75a, 0xeeba79d0, 0x714227c0, - 0x2c552d8e, 0xe3c1d47e, 0x8e47371b, 0xcf11ef17, 0xaeeb3ad8, 0x5b1fc029, - 0x67d09e99, 0xba61e35c, 0x63f4379e, 0xf8f3371d, 0xbe3b96d5, 0x3cf1ae32, - 0xd7ae83fc, 0x7c6d18b8, 0x8bada7e8, 0x942cf17f, 0x1af426b5, 0x07e818d7, - 0xf47894fe, 0xd95da3cf, 0xdeb08931, 0xa4f181ff, 0x0e857eb0, 0xa69fd7e0, - 0x8cf8bf80, 0x44bf441c, 0xef098770, 0x38ef966b, 0xc2e9fb8a, 0xef1843f6, - 0xf85c784d, 0xb1fa1205, 0x03ee5df8, 0x6568d9aa, 0x1d7c90f1, 0x61d25e20, - 0x2e3cefc3, 0x12b5d192, 0x9c5bd92f, 0x3498b2e4, 0x8b0b3efe, 0xf8daace7, - 0x0c3f8f01, 0x09309baf, 0x2bf3abd6, 0x3c1550e3, 0x130f01d8, 0x91c071d5, - 0x714352e3, 0x8375bac0, 0x1e3e04f5, 0xf9a5f38a, 0xe9ef10a1, 0x8a468e13, - 0x81b0bf2b, 0x905f0fc5, 0x568fdf23, 0x626b82e2, 0xd7d6fb74, 0xbee078bf, - 0xf175f1e6, 0xa1c63f34, 0x5f051ba1, 0xf323575d, 0x846327f7, 0x85b7646f, - 0x0a549bee, 0x4f2cfbfa, 0x997dc0c4, 0xbe234ed6, 0x55d8a293, 0xdc5dbe7c, - 0x8af5d6df, 0xf5a27188, 0xbf907b2d, 0x3547f9eb, 0x8fd1473f, 0x6f1f2377, - 0x1f931b75, 0x3ead5b5d, 0xb5d3850b, 0xeba44dfb, 0x189dcdea, 0x79bfbaa7, - 0x7543b19b, 0xc3f20cfe, 0xd77f1aa7, 0x22c6bb6b, 0xa2efe73f, 0xcad9fbe9, - 0x3f8d63f9, 0x9b353f72, 0xa9fa6a2f, 0xed18b6f0, 0x3bfbbe96, 0x05eeb927, - 0x99dae778, 0x45ae751e, 0xd08be69c, 0x6462cfff, 0x3237576e, 0xa395383f, - 0x959c3ef8, 0xda2707bd, 0x5b2f51a2, 0x0c749d66, 0x665d21de, 0xcc5c6235, - 0x471e3aca, 0x326723f3, 0xeb4af7ac, 0xbbc604ed, 0xb2abf01a, 0x9bbb65ef, - 0x27273e80, 0xcfaa6517, 0x1bf19461, 0x4f881807, 0xd3ad8fbd, 0x4a7d8206, - 0x1850ef24, 0x7f699dc7, 0xb62e4095, 0x9f7f987b, 0x02313d5c, 0xf64bb7be, - 0x6e14097d, 0x04e0be7b, 0xba4f6cd7, 0x7e43f067, 0x1df69706, 0x4753bc5d, - 0x69c977e7, 0x6ad13d40, 0x1569d808, 0x4f6a8d62, 0x41d70346, 0x5e12521c, - 0x8978c0a5, 0x11e63cc7, 0x46d43f70, 0xf50adaa8, 0x5de6929c, 0x9249d895, - 0x72159dee, 0x57a50478, 0xc557a70b, 0xff65675f, 0xf03b70a6, 0x0cb896fd, - 0xbbe40752, 0x7d46ead6, 0x0b9b29e2, 0xdfd23fef, 0x88938868, 0xf54ed127, - 0x5fb450bb, 0xda3b7dcd, 0xe71f26af, 0xa613e6d2, 0xc9232749, 0x8e3e049b, - 0x7882d102, 0xe06a9b88, 0x70abb2fa, 0xdc785264, 0x19c48971, 0x2c3bf280, - 0x6e808f78, 0x1e7aaf2f, 0xdc768b16, 0x3e1a7c74, 0xe1d19b11, 0x6a71b035, - 0x0389dbbe, 0xe3a747df, 0xaf1bae3d, 0x70b56f26, 0x0911277e, 0xdcc59df8, - 0x2ffe384e, 0x4abdf069, 0x224f8a2a, 0x38c2644c, 0xde2130e9, 0x83cf9625, - 0x6fa9aff6, 0xeb01ef07, 0x0c870b5f, 0xb5efabb5, 0xe0e5c0de, 0x8a514b11, - 0xac93ee85, 0xb818b5e1, 0xb82c9d9d, 0x65a04e4e, 0x9fc801fe, 0x61e796d2, - 0xc8d08a5c, 0x5ac46ae8, 0x4466fb82, 0xad55c790, 0xd53d468a, 0xa8de2664, - 0x8e3f70f1, 0xd0f1e578, 0x3f9f8f8b, 0x28185639, 0xa50d6928, 0x1fceda35, - 0xa62c35cc, 0x4502d08b, 0x8b10fe14, 0x5ff40c6b, 0x6c9dc33f, 0x1bd30718, - 0x2877bf56, 0xc16bdaee, 0x1ba86863, 0x14c0ffba, 0x2ef82164, 0xdd0ef108, - 0x51b8720f, 0x0ec653c9, 0x463406ef, 0x332ef287, 0x698df7e5, 0xdaf37f2c, - 0x7ef0f5a1, 0xe8bda74d, 0xc78c0b66, 0xcf0ebf6c, 0x9af102c3, 0x937bd5f7, - 0x4738ca2f, 0xc1e40c6f, 0x07b7c7fb, 0x23c5fbd9, 0xfc7ba1ad, 0x59378f28, - 0xed007c94, 0x43d6a28b, 0x5aaad7c8, 0x01b9610e, 0x9e1d34f2, 0x421bc810, - 0x65bf79e7, 0xb5f2414c, 0x716b5e14, 0xb1c13c32, 0xbf6632d0, 0xb8c3c1a4, - 0x61d9bdfa, 0x6e2b483c, 0x86e1e1d0, 0x858785af, 0x87a86f6b, 0x3bfa55f7, - 0x0b174a6f, 0x73d35f00, 0xdb8ef80c, 0xf41663c4, 0x145fd0bf, 0x670e23ca, - 0xbcf72f43, 0xc2853b15, 0x97d35729, 0xaba14ed2, 0x9d26e8de, 0xef63afd8, - 0xe7e96a83, 0x87ae2ddf, 0x8b32de00, 0x8896dd2b, 0x0577c7f3, 0x8b8bbba6, - 0x74c213f2, 0x09ee2c4d, 0x11feaef0, 0x5a1f82cb, 0xe9dafe54, 0x34c54b39, - 0x011fde3a, 0x3c31b823, 0xdee5c49f, 0x9e7451a8, 0xc6032e89, 0xb8b11fd5, - 0xdb3b4057, 0x6200609c, 0xf71226cb, 0xf70c4104, 0xfa8feca3, 0xaf8ecc1d, - 0x56f8362f, 0xfc60f3b0, 0xfa611dbb, 0x47d1d0e8, 0x5b47d190, 0xb547d227, - 0x47d193bf, 0x346e5d5b, 0x3b03573f, 0xc70491ba, 0x5937bac1, 0x61a40b0a, - 0x82626e94, 0xb23740f5, 0xc282b6f7, 0x3aebc428, 0xf58f5f18, 0xe652e3e1, - 0x36fadbd5, 0x71fb481e, 0x0799d806, 0xa61e780d, 0xb7a94de0, 0x46e2c2c3, - 0x7ee6cdff, 0x99a9fa11, 0x961fb1d4, 0x3f81eb6f, 0xed875c60, 0xd05dcce0, - 0xae9b36de, 0x6fdc2390, 0xf815c1e3, 0x7f23784e, 0x04963bd7, 0x7bd720bd, - 0x3fdb07c7, 0xde807c21, 0xe8f80193, 0x0af2fdc4, 0xdd9667bf, 0xce40b826, - 0xef618f0f, 0x616ebc90, 0x16bbf576, 0xaf4ca791, 0x5bb83c49, 0x7b2bfb04, - 0x27eb0195, 0x9ea19a42, 0x5f5e2aff, 0x95ddf8d2, 0x89e85575, 0x7818d272, - 0x78f9e4cf, 0xfd2d1ef7, 0xa9a4c7c4, 0x1eed29e0, 0x45a290f7, 0xee265094, - 0xc810f05d, 0x3e3f4a55, 0x7231bb4d, 0x442de014, 0x233e943f, 0x776d0fad, - 0x7c6bad88, 0x5b0be80c, 0xf1152ef6, 0xae7e8e5d, 0x47bc166b, 0xc567eb49, - 0xb4adda90, 0x4d2c567d, 0xf3c09f21, 0x087e7903, 0x743fd34b, 0x7dfa041a, - 0x9ecbf703, 0x922578e5, 0x6399bafd, 0xb8f4cf20, 0x9418e4ec, 0x85beca0b, - 0x5ce05467, 0xdbe7e25b, 0x0334c169, 0x8fb29bac, 0x6021a0a5, 0x4d2b42a5, - 0xce201872, 0xbb8f5de1, 0x7b0bce08, 0x5fb73be3, 0xea81eecb, 0xc7ce7fbf, - 0xebf58df3, 0x2fb8f4bf, 0xb7e039fe, 0xf8f1dcca, 0xbeaf9a4c, 0x69fa32f6, - 0xdf54c457, 0x68ef55fc, 0xeeffc7e8, 0x00c4dfd5, 0x333ffa1d, 0x353fbc45, - 0xf1e8cace, 0xb60e6780, 0x04efe2cb, 0x1c4a8192, 0x15ce2ab2, 0x865eb8ca, - 0xdf86994b, 0x05bacf51, 0xa7ac2059, 0xf6878a57, 0xae78a931, 0xae2eab78, - 0xbb2f3955, 0x80fcc025, 0x42beb159, 0x74faefec, 0x3e49f7f6, 0x9992fa63, - 0xa1ce0ffe, 0x3373f2a6, 0x5efb31d7, 0x09598710, 0x3f08f98d, 0x5afd1536, - 0xfefb4439, 0xaf40d641, 0xf4f28064, 0x67978454, 0x13a795d6, 0x6b915bf4, - 0x4df9c3ae, 0x0cfd2a25, 0x13a346e5, 0xd1f4f1f8, 0xf7f9fe94, 0xe1bff4cb, - 0x867f3226, 0xcdb8ceca, 0xbe515f71, 0xc4696f46, 0xfb7e8577, 0x523f38b9, - 0x2163c5fc, 0x4115173c, 0x8f1e803c, 0x95610eb9, 0xdf13d1d5, 0xf1e9fc7a, - 0x8f51e0ad, 0x9d0f9cb7, 0x9e8ef1f9, 0x23e3d1f8, 0x5be97e7c, 0x7530eb0b, - 0x4bf288b4, 0xfc4f7bc1, 0xedfaf5b0, 0x009eb4b5, 0x0df142f4, 0x30174cf8, - 0x862b27be, 0x3a6c4fd3, 0x140b37e2, 0x0f4801c0, 0x55e3d798, 0x04acc78f, - 0xd5813ede, 0x1af80fdf, 0xed00fc89, 0xb2dd6521, 0xc6f76bd2, 0xe8c4de41, - 0xa7abd14c, 0xbd50bc72, 0xbce6f51a, 0x9bfa2b44, 0x9a9eaf40, 0x5e5bc614, - 0xde571b15, 0x600bcb48, 0xfc0afe9f, 0x0608b1d1, 0x95bcc5df, 0x56e05ff0, - 0xe2ca5f3c, 0xb7df0559, 0x93d5a67e, 0xce0bfaa7, 0xdc3dfe82, 0x05655ee4, - 0x87108c7f, 0xff1479e7, 0xd7f875c7, 0xf36bb3b6, 0x0afc7c7a, 0x27b931fe, - 0xab7a14de, 0x7cfd72b3, 0xfa0a1930, 0x3337d8f2, 0x137f8163, 0xbf447c7f, - 0x4563c4c4, 0x6e9c3821, 0xe2059e91, 0xa7b77d0e, 0x763e0b7f, 0x15494a90, - 0x7253bb1f, 0xd8deb3af, 0xeb298f93, 0xc7af8535, 0x05dde214, 0x4429a67e, - 0x1ec84bfa, 0xffcf0d48, 0xb3f72b79, 0x6043210d, 0x1c585f9e, 0x79f3ff8c, - 0xd54de686, 0x9b3fe84b, 0xb66d9ff7, 0x121bfde0, 0x7842ba94, 0x93f7c34e, - 0xf0f8c6bc, 0xbd656438, 0xd3096a53, 0xfbe2e6e7, 0xe42f14d9, 0x38f098cb, - 0x090559b6, 0xe3e20fdf, 0xf66cdf38, 0xd3db9c42, 0x2b0dfb92, 0x83843df8, - 0x527e7163, 0x3fc81460, 0xb6e5f97d, 0x4e50d5bd, 0x3d6095eb, 0x910afe3e, - 0x3b821ff9, 0x5217be4c, 0xe953d77b, 0xa13946f6, 0xdc3671d0, 0xe801bd7b, - 0xb8c2283e, 0x655cfcfd, 0xcf7645e7, 0xabec45c1, 0xf6f0a7ae, 0x02f7625d, - 0x81db28f2, 0xedfa7a7a, 0x49f34e8b, 0xd3b41e70, 0xcf22abd3, 0x5bfdf81b, - 0x68bb3f45, 0xeb0fbf75, 0xe3efc0de, 0xba8e2ffa, 0x1be7d60e, 0x2d61d5d3, - 0x44f4295d, 0xf438ebe9, 0xf1f99dd3, 0xdfcb503a, 0x049cbccb, 0xe3d151f2, - 0xeb8afac3, 0x9bd7a863, 0xe6dc3f3e, 0x857eb2ee, 0x35e8af3e, 0x6423d97d, - 0xd34644af, 0xebe3ce71, 0x2edcd733, 0x41c68bb3, 0x886fd38c, 0x73cbde56, - 0x393e8344, 0x95ed21af, 0xac573866, 0x07f97e63, 0x3d8d656b, 0xbedb86ec, - 0x67bd9ed8, 0xb6b97f3b, 0xef8a23fc, 0xcef8f141, 0x868ed6ad, 0x7e1491fd, - 0xbf67b7cf, 0xc9c82f06, 0x31a32379, 0xafdf4e7e, 0x7efa7e7e, 0x7035fdf5, - 0xd8c1aafb, 0xd2a9da38, 0x1636ec4f, 0xcd697d47, 0x14f0cd93, 0x73f86f5e, - 0xd4b8879b, 0xa3ae6f7f, 0xa44e7a21, 0x781468f7, 0xc2e7be0a, 0x0fe098cb, - 0x1eff95a8, 0x6cdd9de9, 0xf413f337, 0x6088efd6, 0x8683ea3e, 0xe82203a7, - 0x048223f5, 0xa0ecf0f5, 0x6350b0cb, 0xb97b300f, 0xef003d87, 0x657cd0a4, - 0x0f662eeb, 0x5da1d4b4, 0x0aed4951, 0xe01b3b90, 0x7cc1901d, 0x27681940, - 0x885eec84, 0x7786caaf, 0x0c5db932, 0x37a5a74f, 0x1f33fab2, 0x8c35374f, - 0x9dd5bb00, 0xce932f0c, 0xa8fb5db4, 0xf557da99, 0x508a24a9, 0x76c8aafb, - 0x4ed677ed, 0xde3bdca2, 0xa4bbc025, 0x65a8ff34, 0xecedff72, 0x8fd1b699, - 0xda81bf82, 0x54d9b767, 0xfb6f6f76, 0x039b66e3, 0xfedbd9f1, 0xcd17b4e8, - 0xdf8a3804, 0xe421f282, 0xbe28fe07, 0xf442a3ff, 0x53780b17, 0xe5f6e5e8, - 0x88ced10b, 0x0a6ae6ba, 0x736593c4, 0xb8db703a, 0xc186365f, 0x706189a9, - 0x376e4a26, 0xfbbdd3f4, 0x3bf028ea, 0x04fa3bbf, 0x2b7e79da, 0xf41fdbf3, - 0xe3a91594, 0x026d6bdb, 0x10c097a7, 0xdc777fd8, 0xec0127b8, 0xc0596c95, - 0xb2fd4ef7, 0x99f1e9ef, 0xdb669fc0, 0x6629d257, 0xfde2364f, 0x60547f32, - 0x3d2ac3c8, 0x4ddfcfce, 0x3fdc5ff5, 0xdcff1d44, 0xb5abcd6e, 0xc022f831, - 0x7bdccecf, 0xde80f40c, 0xae584ee4, 0x2b9004b8, 0x24a1eae4, 0xdd6a5f3c, - 0x689f0367, 0xe0e77f17, 0xa49eeb7c, 0xdaad3405, 0xb0369ff2, 0x3e38eae3, - 0xf8ed4bce, 0x76e5535e, 0xa113df11, 0x003d26fd, 0x85d6eb7e, 0x1fdeec59, - 0xc8a6afbb, 0xef9ff1d5, 0x9cc45219, 0x4cff7889, 0x98a737d1, 0x9f183ebd, - 0x1dfd8ebf, 0xf7ba29cc, 0xefe56ec9, 0xcff5e993, 0xe2b26c67, 0xa9f8c32f, - 0x4fd67665, 0xfb2bfb6f, 0x53e204b3, 0x296cbfed, 0xb3f8c220, 0xefc24b3f, - 0x3da40fe7, 0x3df60855, 0x01239d91, 0xa2f644ac, 0xa7cfcb7e, 0xbc2f6fe8, - 0x6793be7b, 0x3cbd6ede, 0x6e2466eb, 0xd004d72a, 0x9803dcc7, 0x07c991d3, - 0xf5bbff45, 0x55dfad33, 0x722b07af, 0x6e3fd732, 0x780210d5, 0xfbc2cc77, - 0x8c240713, 0xc9ebd2f7, 0xbd058353, 0x204fc3e8, 0x4d6d6d7d, 0xfe7b018f, - 0x009f60df, 0xc65eb6dd, 0x49aa83f7, 0xc7781ee0, 0xb455baa9, 0x24fc6007, - 0x67d87af3, 0xe0a13e8a, 0x1eeaeda5, 0x7fda58f3, 0x7d8345f6, 0x76f10505, - 0x57682ff0, 0xc1fdf84f, 0xfe679004, 0x07e784a0, 0xc6f717d9, 0x45f1542c, - 0x7e0355ff, 0x6eeafb7f, 0xfc60f7ed, 0x8b6ed0f5, 0x7bcbd981, 0x063dfff7, - 0x57dbd4f8, 0x90bc212f, 0x6f53d13e, 0xcf3bfd46, 0xd1fc862a, 0x8899bd6a, - 0xde2187d9, 0x152c6a6b, 0xfaef426b, 0x6487ce70, 0xd4f49595, 0x2778422b, - 0xd0f0092e, 0xf0561f43, 0x3e33d3ac, 0x773d71b2, 0xef0f1918, 0x4d5db65e, - 0xc77bc0a8, 0x0afb18fe, 0x8f4ccf94, 0xee7bdeea, 0xfdf0e9c9, 0x9ddec8a0, - 0x7ee22ab8, 0x62b3bdda, 0xdf6a8778, 0xeb8a4e52, 0xc5d06576, 0xfad16f0b, - 0x3345f657, 0xbce4baff, 0x224f7d5e, 0xf1c7df5c, 0xcecc1815, 0xe183bce9, - 0xac6fa8bd, 0xb0f574cf, 0x4361fff7, 0x0058393d, 0xfad462e2, 0xffac234e, - 0x3e8ad9bf, 0x25a5fc67, 0x978bf806, 0xb4210ee4, 0x9268b2df, 0xac15740b, - 0x33b07623, 0x18301fb6, 0x37325d60, 0xcf5c62a5, 0x731cfc2b, 0x31a34b49, - 0x4b174555, 0x19d839f8, 0xaf129bd9, 0x9632befa, 0xfb3397f1, 0x71817fca, - 0x91347f1d, 0xd0f41191, 0xfe4cb185, 0xa77a336e, 0xc77a866f, 0x68df780d, - 0xef5ffeef, 0x97937787, 0x038c731c, 0x5894e0bf, 0x0eda0fb6, 0x710f52be, - 0x821f6dc1, 0x6672a2d4, 0xa068b163, 0x1c45befd, 0x9877afcc, 0x90d6bdfd, - 0x12b8943f, 0xc5379e60, 0xd6fdbe32, 0xdce68301, 0xbefe2dec, 0x8cb1f5ef, - 0x32c6a50f, 0x03d6dabf, 0x700b09b9, 0xc447b9ff, 0x64f01f82, 0x456c3d47, - 0xe8a80fc5, 0x6f0f936f, 0xfe863e9d, 0xc1977273, 0x38edcb0e, 0xf30882fc, - 0x24219c75, 0xf43d204e, 0xac6f0a39, 0x5d5bde1a, 0xc71d1e0c, 0x0aafd86e, - 0xfe04a9fe, 0xbfcd0671, 0x43c52ed5, 0x7f82983c, 0xff4a1e65, 0xdae2168e, - 0xe4adc160, 0xfe15fada, 0x31efe568, 0xe513b04c, 0x5d2033ef, 0x6eb9b76e, - 0x6f72c589, 0xeccfe40a, 0x36d27a63, 0x72494f2e, 0x9fc070f1, 0x79f34eb2, - 0xb7a78caa, 0xe3e7effe, 0x4bafd254, 0x0ec8afd7, 0x76cdd22f, 0xf0ee4f16, - 0x10e9cc06, 0x8e96d677, 0x154a9f7f, 0x8e3f7b97, 0xfdf68cff, 0x830eb6c2, - 0x558fee01, 0x50e210ef, 0xbea7eddd, 0xa933a21d, 0xedafe905, 0x5c7dc118, - 0xe65dfcde, 0x9f72a48f, 0xe786ebbf, 0xf87fb0eb, 0x8120fb39, 0x1bfd93a6, - 0xfc410e56, 0xafb06c06, 0xfba278c2, 0x46dad206, 0x92ebd023, 0xe52d2c65, - 0x9a4bd5e7, 0x4b3fb8dc, 0xc478b3d6, 0x4ca9b165, 0x257a733e, 0xf8c1e886, - 0x7b4dbade, 0x5c1ff08f, 0x7d6d9e7e, 0x4bf40f6a, 0x80fbebe9, 0x9eda9b8f, - 0x55c30758, 0x46ecf5e8, 0x4594e119, 0x3df3cf6b, 0xb8cfccb1, 0xf7a330fd, - 0x5ce51bc9, 0xb26c4f78, 0xbfc1d897, 0x4dc6d6fd, 0xb7eff022, 0xd9539e80, - 0x7b79073e, 0x3163df66, 0xd6f907df, 0x47e02069, 0x652466df, 0x62fb545b, - 0x343786ef, 0xb9bcb7fb, 0xebfa3a6e, 0xe005e23b, 0x55becaf3, 0xe8cdbef0, - 0xfff70dbc, 0x9ffdba9d, 0xc2b7dacf, 0x4f7ad0ba, 0xd4fffdf1, 0xe9ffba34, - 0x718db8a7, 0x66d9c002, 0xdccefc8c, 0xfe90df4b, 0xa3b57c42, 0x297d5f07, - 0x6c1ff996, 0xeaffb4e9, 0xffa12e3b, 0x4e3e3421, 0x2be54f37, 0x002a9374, - 0x0ae91bfe, 0x517c008e, 0x533d02bc, 0xccfe7a3d, 0x0795dc0c, 0xe1ff3c24, - 0x2e3c4be7, 0x6a947704, 0x99f986bf, 0x6fdd6fb2, 0xf2b238c0, 0x9e82576b, - 0x45e8509f, 0xb82b3cfa, 0x7953c787, 0x71f61676, 0x8eb07e04, 0xec8ae3e3, - 0xff7debee, 0x65cf40c1, 0xf98462d4, 0x1d82f590, 0x772945d6, 0xbdef67ac, - 0x94f0e61e, 0x2dbf87ef, 0xde3d83be, 0xf0cc3d21, 0x5c42341d, 0x931f28eb, - 0xc5c84463, 0xb70c40fd, 0xb67d860f, 0xfbafca84, 0xacebf255, 0xaa7488dc, - 0xce23e1e0, 0xb1c4aeb7, 0xc7ce3f79, 0x5d1f07e9, 0x82ff0aa2, 0x3f6c0924, - 0xe7db028b, 0xbb3fc022, 0x90dba6ef, 0x4c88efde, 0xb7b076ef, 0x47efe1e2, - 0x8cfa406d, 0x7bc7669b, 0xce494f2f, 0x7e8d38a8, 0xef74c3e4, 0xced067a6, - 0xfd85fa03, 0x97fd1bde, 0x0893fd01, 0x74a3ef74, 0x853f5aaf, 0xfc5d280e, - 0x7ca5f01d, 0x7285d3d7, 0x65e0a90e, 0x731cee9b, 0xe9e19daa, 0x8d5200ff, - 0x8000b56e, 0x00008000, 0x00088b1f, 0x00000000, 0x7dbdff00, 0xd5547c09, - 0xf37df8d5, 0x3332c966, 0xb2764c99, 0xa00c4930, 0x80490e2c, 0x084ed8b0, - 0xc3884a20, 0x93a0d752, 0x364b0900, 0x94569510, 0x8b062081, 0xb62d1518, - 0xef858320, 0x106d1b43, 0x268358a8, 0x622d1110, 0xa57fb1dc, 0x41459041, - 0xed1fa822, 0xe73bf587, 0x33337bdc, 0x6a02266f, 0xefc7e1ff, 0xdf77dee6, - 0xcf7ece5d, 0x6ec5f739, 0x843631d3, 0xae630731, 0x7d8c01e6, 0xf4bf3f8f, - 0xa12d8c97, 0xcf3773e7, 0x8224715e, 0xf0f7cfd1, 0x5e79babf, 0xc776bd50, - 0xe91c57af, 0xc5cfafe7, 0xffe0525f, 0x8967a671, 0x47f1558c, 0x89ef4cac, - 0xfbc025b5, 0x6cd69d11, 0xe266b498, 0x03846319, 0x8319789f, 0x1c636ff6, - 0x6faa3e54, 0x1f2bd3de, 0xe9cc31ca, 0x9b39a685, 0x998f1533, 0x1b3605b1, - 0x27f967ad, 0xb0dd93d3, 0xc6c646de, 0xc59bbae3, 0xd9dd727c, 0x99c68536, - 0x8f7329e0, 0x66678389, 0xa07b9e4f, 0x6607f9ff, 0x886d964f, 0x70a13ebf, - 0x4018eabe, 0x7ec48c4b, 0x0c985563, 0xc9bf9fe6, 0x326533e4, 0xc49f05b6, - 0xa3db2ac3, 0xfd329b7c, 0xccf4d9ef, 0x9633b7a5, 0x75a4cb6b, 0xb15aeac1, - 0x646858ee, 0xdfbcc197, 0x9bb59666, 0x1dd5d1e1, 0xb081e2de, 0xef462d8f, - 0x389989d4, 0x1c1af398, 0x9d629aff, 0x6a5801ed, 0x38a6cbac, 0x6992d007, - 0xcf8fb65e, 0xeced9793, 0xeea1b2cf, 0x2db9e670, 0xf8128d8c, 0xc930ad62, - 0x421c3f70, 0xd9e1c6f1, 0x20175e13, 0x1750867c, 0xd5e27e7a, 0x667d1ba8, - 0x0144f3ff, 0x78632fbf, 0xd3c1adf9, 0x1d0e66db, 0x553e6027, 0xcacc6649, - 0x5c554b3c, 0xdb6628ff, 0x773ff0e4, 0x1c2e628c, 0x57189a7f, 0x8ffacbb6, - 0x10aeafa6, 0x78869afa, 0x22e88ead, 0xd053eaba, 0xbcc07469, 0x8bdd194c, - 0xee98fac1, 0x80ac5eda, 0xbd71eaba, 0x29554800, 0xf6c7ebe0, 0xd7338d84, - 0x01d99e23, 0x0cc9cb13, 0xcdb567dd, 0xd1b6e1c0, 0xe866fa30, 0xb865e097, - 0x838bc003, 0xde3585e3, 0xdc6bf88a, 0xd7886268, 0xdc39636f, 0x68d953ac, - 0x42b7f403, 0xc6f7247f, 0x57039ea9, 0xd931bd41, 0x9e6050e8, 0xc22e8613, - 0xa0ab89fb, 0xadc3e88d, 0xbc4fbe20, 0xdf9ae23a, 0xa277bb40, 0x8bc0e58e, - 0x05b08d5b, 0xa7bfc3a4, 0x482936f9, 0x27c42da7, 0xc1b2c7f3, 0xbede7826, - 0xd5d11869, 0x052ce2ac, 0xe6ce76e9, 0xdb9f0558, 0x2a74d8c7, 0xd863eff3, - 0x13e89542, 0x16dea0f8, 0xde618f80, 0xd5e1153a, 0x6c93ce3b, 0x11ec6588, - 0x23e335db, 0x32ce81d2, 0xcc1b2459, 0x5f5043d8, 0xb46b7009, 0x4b1614bb, - 0x0a7306f5, 0x236321f1, 0x0cadae08, 0xd518d4f0, 0x6045775d, 0x7f5e2cff, - 0x86eaf1a4, 0x9ec63486, 0x22357189, 0xbb303e9e, 0x87f9c11f, 0x44a9d526, - 0x7fae82e7, 0x127ece80, 0x2c2ed4bd, 0xe0f38762, 0x0e660ef7, 0x47901ba4, - 0xf8066eb7, 0x9b3de895, 0xbd355d70, 0xc38e3e8e, 0x657cb6d5, 0x7ba184f4, - 0x21788eb9, 0x8cc7d817, 0xaeef11f0, 0x7ecdcb53, 0x66c5b3b9, 0x52ed4c17, - 0xfcfc5b26, 0x79eb7286, 0x593b9733, 0x98229a50, 0x7ec762d7, 0xac23a23e, - 0xe5fae4c7, 0xdd62cad1, 0x3e185f78, 0xeb890d7e, 0xaccf9467, 0xf2ff7fe5, - 0x1fd0a19b, 0x9f89577f, 0xc4fce35e, 0xc5a3f5e5, 0x3c22269f, 0xbdf09390, - 0xeb1cc5db, 0xeadf3a97, 0x5fb9748b, 0x3ea09b65, 0x2af464d8, 0xe66db831, - 0xf18a25b0, 0x945b0d90, 0xa820cb56, 0x2e614bff, 0x7fe9c3c0, 0xbfae54a9, - 0x133e3dd7, 0xa1d9afde, 0x7e852e73, 0xf10a2d35, 0xf337b383, 0x371d0045, - 0x31075947, 0xb770af18, 0xf68065d9, 0xc9044ad3, 0xd7009c65, 0x2feb9061, - 0x8268cae8, 0xc02df5e7, 0x5d3d507f, 0xf5c6a808, 0x6c319dea, 0x83be1f80, - 0x1fb47cde, 0x1bda00ec, 0x4f67c89d, 0x9ff1f245, 0x81f0cc8a, 0xbe528310, - 0x4a0188e7, 0x6e825961, 0x62c67af4, 0x78504f00, 0x30b51cb1, 0x3c07a5db, - 0x35e67a2b, 0x7546be00, 0x9f08aab5, 0x8e872eac, 0xe9f3fd99, 0x3bed18bb, - 0x39d0ef4b, 0xd6d5f403, 0x7aabcfbd, 0x31d0eb80, 0x942af58d, 0x6f9e3189, - 0x4623de10, 0x7b63d5d5, 0xf557b15c, 0xa57cff40, 0xe905b76e, 0x44e61aec, - 0x24f92ab9, 0xc1b593ae, 0x81ec5972, 0xda15974e, 0xb5771c47, 0xc7fd800d, - 0xe38299b8, 0x7c0dfd49, 0x0e9162c6, 0x44ca5de3, 0x3fe86718, 0x8e47c118, - 0x68ef75b3, 0xbe3ef905, 0x18e28c63, 0x6be74a10, 0x38b7e398, 0xce9f77ae, - 0x3475f889, 0x9406d733, 0x62ba7f13, 0xf64bc20c, 0xf5cb1def, 0xa78f48ca, - 0xee154408, 0x1de70627, 0xb76fa37e, 0x6c33d601, 0xd1b77796, 0xd99fb011, - 0xed4bc68c, 0x523ed2f4, 0xb10a780e, 0xd2c6b6cc, 0xb78e2338, 0x7e800db6, - 0x1fb07549, 0x78ef4f68, 0xa6b8414f, 0x882875d7, 0x777badcf, 0x3ad37ad1, - 0xf82979da, 0x176179eb, 0x5603db74, 0xdb23ed1d, 0xf2cdf5ca, 0x666f5c53, - 0xadb27ac7, 0x2c7dfe09, 0xd724f42f, 0xf66bf8c1, 0x17ef7566, 0x2895eee5, - 0x52e403e4, 0xc691ac6e, 0xe9eacbb9, 0xbdabfb8f, 0xd20f73b1, 0xdf7bf3e0, - 0xb47f12b1, 0x137e13c4, 0xf84a7df7, 0xba485c48, 0x37d9ad98, 0xb179415f, - 0xa67014a6, 0xca59c284, 0x7eb8358d, 0xf45b1fa2, 0x27cfa024, 0xd8829eed, - 0xcca57b40, 0x20159d1e, 0x8f7be497, 0x19ee662f, 0xed6190b0, 0x16595be5, - 0xb17ef7c9, 0xc27df201, 0x9122fbc0, 0x2e2c9a9e, 0x569fb617, 0xcf388dd8, - 0xfb425833, 0x975e0633, 0xe0407af0, 0x52763b33, 0x870875b6, 0xf8e80d93, - 0x4fde4899, 0x8dee8f2b, 0x83bb09d5, 0xe0eb0bd3, 0x08fb82f4, 0xc666bfb4, - 0x748c3c72, 0x9cf48a79, 0xfee2a64e, 0x76f81786, 0x1b0edd23, 0xf48dddef, - 0x9d04ce9f, 0xa274e78c, 0x63dbf7a5, 0x711d7cb9, 0xdc218bbc, 0x0ee615f3, - 0xc654ef67, 0xbe29bb72, 0x0fd13463, 0xce1943f0, 0x4eb53437, 0x66dca035, - 0x7fa809b6, 0xa0eb137e, 0xae05797e, 0x366f48dd, 0x79f89b97, 0xe9c6d9be, - 0x07d39326, 0x1c273fbc, 0x3e436d3f, 0xa3e7e01a, 0x7347a478, 0x26de3d28, - 0x011bf4e0, 0x3df1d0df, 0xf1f8e177, 0x02973a1d, 0x603b0c83, 0x3ae831f6, - 0x49e8016c, 0xf40653e4, 0xcfb40b0f, 0x9f2215b2, 0x153956a5, 0xb302ebc4, - 0xd7dc1efb, 0xf98d9472, 0x5f3acf48, 0x6c97bc3d, 0x7efe1173, 0x67689eb4, - 0x90686c11, 0x2c40f59d, 0x9557e3b7, 0xfa7ebca1, 0x53ca235b, 0xbdbfe487, - 0x01e5d1b9, 0x50c7f1f4, 0x0e123f7c, 0xa7395adf, 0x2e5fb7c5, 0x8039cb04, - 0x0f8e5ad7, 0x77c7e76e, 0x7cb9502c, 0x3d6b9608, 0x3e4423e1, 0xc1fc3c08, - 0xeb84daec, 0x4045c6cc, 0xfacd1de9, 0xfa4f7b61, 0xf358c5f8, 0x2f67b34f, - 0x8c5f8fac, 0xc7d5084d, 0xd7ae88ba, 0x75478015, 0x6150ea8b, 0xec8bf50b, - 0xfaffc42e, 0x7689c566, 0x9516eee1, 0xf2fd61e8, 0x729bd228, 0x8f6e5fbd, - 0x84aec419, 0x6b3ff052, 0x5a7d258f, 0x5fe62b1b, 0xfcc0bf06, 0xbabc6da7, - 0x3d79e6dd, 0x6fad0e50, 0xe11226f9, 0x71593fdc, 0x4abb411d, 0x85818fab, - 0x84df7814, 0xd70829bf, 0x322a0dc1, 0xad9ef5d6, 0xf6f09526, 0x8c378e2e, - 0x0a33be75, 0xa6a7f5d6, 0x7b40bad1, 0xaf8eeceb, 0xeb05dd6f, 0xfae68daf, - 0xeb9a36b9, 0xcebbd3e7, 0xbb7a41f7, 0x9274e176, 0x9ef4c37b, 0xdce5038f, - 0x730efd1b, 0x6d4acc39, 0xd4e3fb47, 0x68fbe52e, 0xa235a100, 0x0aed1e9f, - 0x06a9ca35, 0x1c4415db, 0x1f0039f5, 0x145b5f84, 0x073eafc1, 0xd6932ef8, - 0xd9d70279, 0x14b2316e, 0xfc0b3f68, 0xbae4fd88, 0xcf7ac47f, 0x9a6f5f84, - 0xa0b468ed, 0xbebfd50b, 0x1e20bc6e, 0xa2d57c60, 0x669c7da7, 0x67c44e51, - 0x10c5d1b3, 0xc283deff, 0xab78103e, 0xba773411, 0x0f01c865, 0x81fd6fec, - 0x7fbe2734, 0x48d9c77a, 0x47ed199d, 0x7d876a8f, 0x565de9a9, 0x5bbb87d4, - 0x39de5ece, 0xc19be480, 0xbb3beb0e, 0x33ddb0ef, 0xcfed47e0, 0xfd88bf6a, - 0x0dcdead5, 0xaa227681, 0x1a945259, 0xda5a523a, 0x220ca9fe, 0x0f2863fe, - 0x57cc19bd, 0x3e5efb0f, 0x54d3d050, 0xd7be40e6, 0xcdbb7be2, 0xe00f619d, - 0xb736cddb, 0xf385d703, 0x3ed2e6a4, 0xe83eb0b3, 0x0679e9cd, 0x0c6fee1d, - 0xed29bd43, 0xb44fb93d, 0xfd7323c7, 0x5ef693fb, 0xce73fef7, 0x68c7da0f, - 0x74ec83df, 0xc52c740e, 0x282d5a73, 0x03320785, 0x784adff7, 0xacfb16a9, - 0xaab7308e, 0xcdb62fb0, 0xca53b270, 0x7dd0ac83, 0xf3869e00, 0x780f387d, - 0x377fcf10, 0x4e11eb3b, 0xda1b0efa, 0x91afb0af, 0x50560fb8, 0xf8708c96, - 0x8c9aecc0, 0x2599fef2, 0xf4fae88c, 0x14f7ccb3, 0xbb4b7a6c, 0x0366e88e, - 0xffe882bb, 0x5b99dd0a, 0xebe266dd, 0x7e7ef8b1, 0xe50ea347, 0xa1cf8e6f, - 0x797ab943, 0x474eb347, 0x2f19e0f4, 0x0f5674e0, 0x54dfebeb, 0xba48fea7, - 0x2e9e1498, 0xabf6f042, 0xb849bc40, 0x30f4128d, 0x3286e10a, 0xb27f4bb9, - 0x370fc233, 0xb54b0bc0, 0x58c78e87, 0xa9c20667, 0x7d63c5ed, 0x9abc613a, - 0x8add8f97, 0xabf9a970, 0xcc618889, 0x418f2f5f, 0x30b2ffba, 0x72735dbc, - 0x0f5b9d71, 0x3dab78c4, 0x157be48b, 0xbda230eb, 0xaddd7200, 0xd2eb900f, - 0xe867db8e, 0xf7f1c628, 0x12d9510d, 0xe759f380, 0x461624b0, 0x3f72c85f, - 0x00396dda, 0xe155f47f, 0xfcc5e4f9, 0xda476e18, 0xb25afc83, 0x9678b7dc, - 0xe7a18c7b, 0x8e0df6f1, 0xb14e7f24, 0xc87a1ec6, 0xa78dedce, 0x81cf5ced, - 0x3ae17660, 0xe2c5fd4f, 0xa9d342f3, 0x0cadf7dc, 0xdb6a74e0, 0xa05e79bb, - 0xe3ac53a3, 0xdf9097f6, 0xb9d336be, 0xfbf078ae, 0x7e2c4b79, 0xfb8abcfe, - 0x2f55d852, 0x407569bc, 0xbb2de2ff, 0xf001bde3, 0xbfe98abb, 0x4ceba6ee, - 0x8fef979c, 0x20fb3be9, 0x274bd83e, 0x16501d12, 0x3c6af8bf, 0x373803a7, - 0x14ff450d, 0x633f8fe7, 0x5ddd8053, 0x3dc6b0bc, 0x1fc02f26, 0xf9922e73, - 0x0efaeb02, 0xab891e23, 0xfda999cf, 0x9e25bb76, 0xd62f4de4, 0x8f4de50b, - 0x7848baf0, 0x3c25db6a, 0x913e0df7, 0x97c5f681, 0x07c5d83d, 0xaf7ec1ec, - 0xdc7b1637, 0xf5fc7263, 0xdea77dbf, 0x5ef30ee6, 0xacff188b, 0xda127873, - 0xd6c6c57d, 0xe1f9c2cb, 0x0b5339e4, 0x57ce37a7, 0x7fb8e346, 0x1f1a6739, - 0xeddb5d6e, 0x3fe69fba, 0x0aab07d8, 0xf44b0bb0, 0xdced379e, 0x326ab05f, - 0x3f2e6bd4, 0xd9ce8e3b, 0xdc845e92, 0xdb798abb, 0xf4b57f90, 0xbefdf121, - 0x4b2a5bc4, 0x693dbc45, 0x11ba7077, 0x43f920fc, 0x396d470b, 0xe13cc8c1, - 0x75cf03ce, 0x799235c3, 0xbede1e41, 0xfe7a40c1, 0x4e1ff3cd, 0x3f7a03cd, - 0x5b60d6b6, 0x5ace530a, 0x51ed3bb7, 0x360da7f4, 0x1fa814d9, 0x865eb473, - 0x4eb95f7c, 0x1c3d2375, 0xe27b7b5b, 0x00bf2874, 0x7582adfe, 0x50306e54, - 0x770dacfb, 0xc109fb50, 0x12eb95d7, 0x7cbca3fa, 0x4481fdb3, 0xeface3c4, - 0xf11ebfee, 0xeb68c5b2, 0xaaca183f, 0x263dc526, 0x3673de00, 0xb7d50646, - 0xdc2cd8e8, 0x532bc487, 0x1dcfdd3c, 0xdc631eb0, 0x6b63c44f, 0x18d51f88, - 0x92ccedc7, 0x9aefb029, 0xbec96721, 0x8a27bddf, 0x662bc9f4, 0xd6c8ec95, - 0xb7f3ffc1, 0xf45ea12b, 0x3649de9d, 0x58f3c09e, 0xce866781, 0x8a8fa040, - 0x7a2f5e08, 0x68764f51, 0x78254591, 0x1d5c82b7, 0x65de4a43, 0x7efd0b1e, - 0x4753df21, 0xfd0e1ead, 0x1818c6c6, 0xb45fa1ea, 0xa06629ce, 0x4e797f27, - 0xc06769ff, 0x9733467e, 0x42e2ed1e, 0x5f6a0866, 0x0a7d6511, 0x4c185aed, - 0x28b0fa8f, 0xd8f9f822, 0x813daecb, 0x5b58c4f6, 0xbfa4bb70, 0xbfa0389c, - 0xb1b97efe, 0x8fe7cf7b, 0x567d804c, 0x9ec953ec, 0xde5c90be, 0x41cafb8f, - 0xda51bf7c, 0x29bdef04, 0xf9e6f3a0, 0x9052cb63, 0x86140abe, 0xe763ae7e, - 0x5ce5f3c3, 0x018c9f41, 0xf1f9fb9e, 0xbb39d13c, 0x7f6c8ebb, 0xeebcc15d, - 0xe2ffae3a, 0xcb0fd9e5, 0xf73b4eab, 0x87f5686f, 0x53fe7f96, 0xf078a3fa, - 0x0b5e19ab, 0xe585ff95, 0xfe5c2dc9, 0x5685e56a, 0x6975c85f, 0x4e7d5bd7, - 0xcf13d20d, 0xd7e27909, 0xfe7a4617, 0x6b8f9e33, 0x9e8486e2, 0x219ec18f, - 0xea877978, 0x760e5ce9, 0x6fd8edd7, 0x5711d980, 0x665a4b08, 0xb9468acb, - 0xdcf164d6, 0x97e01719, 0xa8d4dfea, 0xedd1f943, 0xfb0431af, 0xf5f9e46d, - 0xffbe389e, 0x875e38f2, 0xfb9d2bf3, 0x92794437, 0x2f6f38f5, 0x7e3033a3, - 0x85fbcb25, 0xaf7690fc, 0x9da577b4, 0x7d59ed2b, 0xb367b703, 0x7e41dd63, - 0x5fafd633, 0xed183f90, 0xef73e474, 0xe7da28ae, 0x107b8a67, 0x731569f2, - 0xa017143d, 0x7c0deb07, 0xbcf5dafd, 0x13ec2716, 0x413b26e6, 0x1d1ccfb6, - 0x8d6f9e5e, 0xc2ff53d3, 0x40ca6fc7, 0xb6b3ee3b, 0xce50339b, 0xfff1a67e, - 0x0f0fc4f6, 0x507d7e0b, 0xe15893e8, 0xf9087827, 0xedc0ea08, 0xfef02dae, - 0xe26ec58a, 0xbe2edfab, 0x1747ca91, 0x8fe7a42f, 0xfcd265c5, 0xdc77c2b6, - 0x23a700d9, 0x17d2552b, 0x3eee8d33, 0x91def0b1, 0x1bf91d08, 0xc799d70e, - 0x3b63336f, 0xcce5f3a3, 0xf26c27c7, 0x1f01f806, 0xe90c7dc3, 0x09af9f79, - 0x9d2a5ebc, 0x2b4eb356, 0x7a6eadea, 0xb7a2103d, 0xa72f11db, 0xf6226759, - 0xfa3a55ab, 0xf3a12934, 0xaf5cc83f, 0x2366bf61, 0xd37c8feb, 0x92f5c51c, - 0x029bdfb6, 0x9ed0ab7f, 0xd433f285, 0xcce4615f, 0x7b5e823b, 0xc4ef5d5b, - 0x9333bc91, 0x56eb4edd, 0x3ef44e29, 0xb4e707ce, 0xc639f10f, 0x975fd089, - 0xc775b56d, 0xc779f855, 0x185c71fd, 0xfe4f5c7f, 0xee3aed1f, 0xd570e789, - 0x296485fa, 0xc4c742fd, 0xd9c5167e, 0xe844fc82, 0x0fe70f0f, 0x48de3aba, - 0xd510dbfb, 0xa8b8c5e9, 0x3e7e66f7, 0x55e51a4f, 0x5a95dfd0, 0xfe8858dc, - 0x71c67fb0, 0xbc7da63f, 0xf1cf1927, 0x4e8d92bd, 0x2c5ce3f4, 0x76680e3f, - 0x478138f1, 0xd358eb47, 0x03ec8de1, 0xf0ec4aeb, 0x34a11a14, 0xf8d226c4, - 0x096eac49, 0x11fa0de2, 0xa3dbf230, 0x743c8a7c, 0x213c9743, 0x91a56147, - 0xaddb77c8, 0xbc3c531e, 0x5d467437, 0x53edfa3d, 0xe23c78ab, 0x6de9e284, - 0x1b8d0ecf, 0x5e3932cb, 0xbb88aff0, 0xd0346fe6, 0x3e37f2ba, 0xfcd1f146, - 0x95eb578d, 0x1f943900, 0x27fea06f, 0x9bd39d5e, 0x851f18fc, 0x880ebf8f, - 0x4662f4e7, 0x8a10e11f, 0xbfa58687, 0x313ff17e, 0xf609dcae, 0xef3cb050, - 0x20243f17, 0x0cfaa16f, 0x3c7d73c9, 0xc07f23d7, 0xd358057c, 0x7cc8661f, - 0x8fe40d85, 0xbe6c6add, 0xde51e306, 0xbc431d1a, 0x2bf9efb7, 0xcd676bc5, - 0xb6bc5070, 0xcf7dfdfb, 0x3ff6c72c, 0x118362cc, 0x87be29fe, 0x7ccff415, - 0xc9e3c91b, 0xb1326edf, 0xd9a5b025, 0x3c53376f, 0x8e954d78, 0xeed17ca1, - 0xe832661b, 0xa0db5c78, 0x47f8e02b, 0x0ef12839, 0x7c446404, 0xfc21bc48, - 0x6e3198b6, 0x5fad02fc, 0x7e80cbae, 0xc7dc04f0, 0x4e906b96, 0x15d9557a, - 0x75c817f4, 0x4c9f485d, 0xfa69ff8a, 0xc3d467e4, 0x9c5fc5b7, 0x74819e1e, - 0x5ac3d5ae, 0x7164dbfd, 0x0bbf6255, 0x4213e1e9, 0xd7894dfe, 0x7e3043c4, - 0xc76f0616, 0xf00c1c84, 0xff19df8f, 0x1fe3fc23, 0xe3091ca1, 0xc8c67f1f, - 0x9da36fe5, 0x0c2936dd, 0xe627bcbf, 0x32eeadd7, 0x6f8cfea2, 0xb3cac251, - 0xc651ab6c, 0xfae05713, 0x2b44fc64, 0xb7c0c38f, 0xde5ffb11, 0x7b0bbad4, - 0x165ec6e5, 0x15dbe68d, 0x37b9c3df, 0x046b3ccc, 0x30163b9f, 0xea3aa38a, - 0xa82bc918, 0xb093b8fb, 0x0023f295, 0xb8e04f1f, 0x9d638a17, 0x1d9215b6, - 0x8656e324, 0xf8f3e0d8, 0xcfd9789e, 0x6fc447f5, 0xe27a0f7a, 0xb05d624f, - 0x5fb067ff, 0x141602fc, 0x9971919f, 0x62af3af8, 0xc47547cc, 0x3bdadfc8, - 0xf304b3ce, 0x3386ba3f, 0x8f5053e7, 0xa215b529, 0x72cfb53c, 0x66fc61b6, - 0x9fee29f9, 0xf98f3e5f, 0x79012a96, 0xca2c9e05, 0x05bc4203, 0x0a7607fa, - 0xac53b6f9, 0x5fe4f41b, 0x5abaf9e3, 0xa4f403e2, 0x756e87c4, 0xed784aab, - 0x02a7af0a, 0x43fedaf0, 0xf919fd78, 0xe48b9df2, 0x852f0fcb, 0x9171fe6e, - 0x8c4bf374, 0x3b090c6f, 0x578867df, 0x67407ced, 0xbef88347, 0x78db3a07, - 0xf9d2f189, 0xa7a89fe6, 0x5dfae142, 0x5c28427c, 0xfaeb1657, 0x5166bc91, - 0xd57a70ce, 0x4ffe6096, 0x12d891e7, 0x1e7a5c86, 0x3b7bfac9, 0x1967888d, - 0xd5eb9107, 0xf6c88fe6, 0x0f25169a, 0xbb859fcf, 0xe039d3cf, 0xe8bfdb74, - 0x079a101c, 0x0f9de7c2, 0x39fc8de4, 0xdcd01d56, 0xa677fc0a, 0x752748c9, - 0x377e3995, 0x7bf7fd0a, 0xa0e7cc0d, 0xffd811fe, 0x5ffbc60a, 0x03bcb4d1, - 0x305757fd, 0x479c57bd, 0x1db9ef95, 0x7c7c8315, 0xf2955ec5, 0xfe66d8bf, - 0x2c458ebc, 0x4c74ff41, 0x02398e81, 0x8aeb19e0, 0x78008e62, 0x07b78dc6, - 0x7939e5d5, 0xc13798ae, 0xfde82bdd, 0x82b31ba4, 0xae78a7fa, 0x3a9e7a08, - 0x9ea8372b, 0xa822375e, 0xa385ef7f, 0xde99ea83, 0x67fa836b, 0xaa0e4c37, - 0x1cde34e7, 0xab18ffd4, 0xec147c7b, 0x5bfa3fb3, 0xebcc3f00, 0xd60cb8ea, - 0xb7ac433b, 0xa0f29aef, 0x5afd81f7, 0x53381e31, 0xcf17c990, 0x00abdf8d, - 0xff08671c, 0x39bee5ce, 0x55cfe341, 0x677e88ab, 0x048e1a36, 0xacf469fa, - 0xc02a4f6b, 0x38a7c6b9, 0xb95ea15b, 0xecf9f826, 0xbde81b1d, 0xf6e0bed9, - 0xeb839bb9, 0xd29cde83, 0xb901e79f, 0x4672bf29, 0x87dfb042, 0x9989d085, - 0xb599f4e4, 0x7aa5ffdc, 0x24e86afb, 0x27ec5f18, 0xd0438dd2, 0x9839298d, - 0xc11d226e, 0xfaf95374, 0x0708a1d6, 0xfba3fc2d, 0x0bc9e869, 0xfe007eff, - 0x7d306716, 0xfb4ee169, 0xec567583, 0x95efd850, 0x6acfb850, 0x2a797879, - 0x633b850b, 0x1fd7233e, 0x688fedc1, 0xd981fde0, 0x89ca18f3, 0xa8163bb3, - 0xe3638718, 0xecff3c79, 0xed07af8e, 0x2f898473, 0x97c484e5, 0xf80425d6, - 0xe97c647f, 0xaf19c634, 0x67111764, 0x844ffddc, 0x8f00c807, 0x0b11f301, - 0x71dd119c, 0x3c7f48c5, 0x653f2b49, 0xb9e3fa09, 0xfe2bd204, 0xbc3d6c78, - 0x03e6343d, 0xc653ae37, 0x8ebe64e5, 0x930a2bcc, 0x8497fc9f, 0xb40fcc04, - 0x75f9e347, 0x3a7cfb4b, 0x22bcc977, 0xc302f226, 0x4fa4ffd8, 0x14d7f19a, - 0x26760bb2, 0x0afebd70, 0x176dd78e, 0xa92fbc88, 0x471a7bd7, 0x2a7adfc6, - 0xc52a5d95, 0x2894bb13, 0xf46153e7, 0x3f0947ca, 0xe685bf51, 0xa8147f8f, - 0x38ee6a47, 0x0bf507bb, 0x6c63fdc0, 0x6f4058b7, 0xfdbd7e2b, 0xd12b68bb, - 0xaaebd76b, 0x9c342faf, 0xd8c47089, 0x222d8e01, 0xe445afdf, 0xd6f5c9fb, - 0xf4baa445, 0x9c1ed879, 0x8ae327ff, 0xc28dfdda, 0x3afe71fe, 0x976417bc, - 0x76e5cf2c, 0x870169db, 0x276e160d, 0x9db91318, 0x1f39ab50, 0xfb7036d5, - 0xacd7a40c, 0x8c718096, 0xdfea1689, 0x4c685cdf, 0xdf8471c4, 0x42a67965, - 0x4572c576, 0x77e47b21, 0xfcf4d1b6, 0x868509cf, 0x6fffe844, 0x6011af31, - 0x16636588, 0x93438f5f, 0xe892fe17, 0x68c252ff, 0x36898d2a, 0x5db67fe1, - 0x6a91f481, 0x5da91976, 0x8aa71f0d, 0x1afbe44e, 0xb464f229, 0x42718071, - 0xdfdfa26e, 0xe2d2edc4, 0xfe4189b1, 0xf18cf7fe, 0xd0afdfc2, 0x53942eeb, - 0xef7814bf, 0xeaefffc9, 0xf1476b67, 0xaffff5ad, 0x7ffee48c, 0xf1081f19, - 0x85c73bff, 0x1e23fff5, 0xfe7eeda2, 0x2dd893e9, 0x3e50d29f, 0xea7a30ed, - 0xb5d5fcf1, 0x6878ec1d, 0xa4ebe7ee, 0x7dc0c0b8, 0x673c4ed9, 0xbb64cf2d, - 0x4b6f482c, 0x7f3b4318, 0x696ea747, 0xe95f3c24, 0x3e7c3665, 0xbf3f2d7c, - 0x3871ae55, 0x0e529b71, 0xfdc89d5c, 0x1f380687, 0xbdf1725b, 0x27186dc9, - 0xd9953958, 0xb2350d51, 0xda2b22c6, 0xd8596b45, 0x4168e3f3, 0x770a134f, - 0x4276fe51, 0x0fb7cf17, 0x7693a7ed, 0x73e2217e, 0x2ce79758, 0x7971cf8f, - 0xcf112242, 0x5f3aeda9, 0xb27d73b8, 0xa46ae8ad, 0xf0be81af, 0xc29188e7, - 0xbb32e64f, 0x03f8e227, 0xd87cf1b7, 0x677f294a, 0xf01e98e8, 0x75e0453e, - 0xd79e5aca, 0xff7fcec1, 0x45ed2abd, 0x9433e346, 0x2d53952b, 0x5513f43e, - 0x697a64b6, 0x99c56e5d, 0xe5a2f283, 0x2bd6376d, 0xe86df3f3, 0x9dfd7097, - 0x91fb4729, 0xfcb8c9a9, 0x52a3b3d2, 0x8f1e909e, 0x64d438a7, 0xf1236f41, - 0x72409cb0, 0xc034657e, 0x92ed72bb, 0xf3d7985d, 0xc5191ffe, 0x5da80e9b, - 0x5fb07143, 0xe6167001, 0xa567a962, 0xa648b7e4, 0x718aa671, 0x7982ffbc, - 0xfef3fc23, 0xda75e5aa, 0xf30301cf, 0x9d1d0046, 0x038379de, 0x09e5eeed, - 0x93cfe411, 0xaa83da71, 0x42523ee7, 0x5c1aaefa, 0xd12d4dda, 0x9c83f436, - 0x3a61f9de, 0xb93e4dc6, 0xed05ace7, 0xbbe87fd8, 0x7c2f982c, 0x16bbd17c, - 0x93f1c017, 0x9de52a45, 0x86f42add, 0x897dfb84, 0x271fee1c, 0xdc2117ba, - 0xddfc5b6f, 0x2a3cc0d0, 0xe88130b6, 0xa54fb679, 0x9cb75c90, 0x168d1cdd, - 0xbabd774a, 0x2ea82e39, 0x89b540f5, 0xbf3b85d5, 0x69e824bc, 0x6306d376, - 0xf7e703aa, 0x38fa42ac, 0x7474e7ae, 0xe7c59b7c, 0xa7aff4cd, 0x11b069bc, - 0xb47f83ed, 0xea2b5898, 0x81877d33, 0x8abb49e7, 0x8f0ba015, 0x9d76bfc0, - 0xa68e5e7b, 0xc63e66f1, 0xcc1947e5, 0xebe010b5, 0x724d9969, 0x998fbb41, - 0x25c6389f, 0xae675c01, 0xe3fa1850, 0xc022ffb0, 0xfde1679f, 0xa5fda15f, - 0x379967dd, 0xf9480e58, 0x3cf02955, 0x79f821bd, 0x696fcb65, 0x43cc199c, - 0x27602079, 0x735f9e69, 0xd80af50c, 0x67ed4147, 0x519b66f6, 0x14496f8f, - 0x6ca1edf1, 0xfef0f7d8, 0x18ec88ae, 0x927e184f, 0x36c5c9e5, 0x17cfd622, - 0x7c795047, 0x5172a331, 0xaae3a722, 0x44efb796, 0xc766a97b, 0x738e2316, - 0x9681f1c9, 0x999bd613, 0xe896ef5f, 0x1e21af3d, 0x28252cd9, 0xe1b3504e, - 0x32ec91ac, 0xd1529f01, 0x00f08a5e, 0x1cc2dc3c, 0x503cf1ab, 0xc7f0655a, - 0x5bffe0e9, 0x60c3bf72, 0xd1da80bf, 0xb5173991, 0xb94fb95f, 0x5abcf96f, - 0xf30c7a05, 0x4583e4be, 0xd8cd1f42, 0x2f796938, 0xcefd5100, 0xfc9d1963, - 0x78f649bc, 0x516bc091, 0x8f64fdc4, 0xe3d88517, 0xb7dc3dec, 0xe64ac7a4, - 0xa5a23d24, 0xcc07493b, 0x23f7a06c, 0x4ddebd84, 0x120f2d6f, 0xcc3d245c, - 0xe4685d5c, 0xc8c79be6, 0xb26f4aed, 0xa326d7f0, 0x30e816bf, 0xba063ec8, - 0xed6baa0b, 0x9d0d2ff1, 0xb41f2819, 0xe7ccb876, 0x60e7c2d4, 0x9a5fcf22, - 0xb38d70e1, 0x8073c00d, 0x85f9397b, 0x10ca46f1, 0x3dc6dbe4, 0x6edf2377, - 0x0ff37ce4, 0x92b30f41, 0xf049113c, 0x9af4b3dc, 0xe77fc41a, 0xf2065312, - 0x8a6967b3, 0x3dfd0f1a, 0xc39214ab, 0x18a697a3, 0x97d3ce11, 0x7c871e0d, - 0x345ccb9d, 0x1638b4fe, 0x9c186ed6, 0x7947e5c4, 0x6319819d, 0xf4462908, - 0x506a9f0b, 0x9a8c2fc8, 0x6be02264, 0xf557c096, 0xa4adb78a, 0x6ff01caf, - 0xe01f5e28, 0x2aeab33f, 0xee701f09, 0x52c7cb08, 0x66b154af, 0x3b8c0a63, - 0xd11b6567, 0x82479c31, 0x95b2d7fa, 0x66eaaf84, 0xd5dd7b4d, 0xb9d83f84, - 0xb589cf11, 0xf79f823b, 0x8276124f, 0xbe913993, 0x225a773d, 0xb471af30, - 0x4ad94f80, 0x6b7286c5, 0x84b6b2fa, 0x7d3ea01b, 0xed84eaaf, 0x8587c374, - 0x1f2823fa, 0x1cdecced, 0x719c57f2, 0x9fb09238, 0x52edcac7, 0x8619ef45, - 0x3ce2d3ed, 0xd8cfd0c3, 0x618591f5, 0x73a1df7e, 0x11e4732a, 0xfca20f95, - 0x341b1b2a, 0x2fbec029, 0x3112d833, 0xf365e91e, 0xb83dc593, 0xd4f84088, - 0x7e24ac46, 0x887e45a8, 0x34c3f3f0, 0xdda17b8c, 0x7942a2f3, 0x30476c84, - 0x34709fbd, 0x9091c226, 0x9033efb9, 0x8a6f2e9c, 0xf971f3a5, 0xea2322b2, - 0xb16df2d5, 0xf9c11f64, 0x86cbbdf4, 0x6879f1fa, 0x649ede59, 0x39bcb718, - 0xe306a9d3, 0x19dcf431, 0x0d39ceb0, 0x8efe2487, 0x23bf80f4, 0x7807f0e1, - 0x4f2f6a0b, 0xe0497212, 0x238a2d8d, 0xef3a5abd, 0x58089cd5, 0x48ba99d7, - 0xe9ec93ca, 0x8c66c47c, 0xe903fca0, 0xabdf1abf, 0x7944cfdb, 0x0e57673e, - 0xf169fc21, 0xd3dffe36, 0xcbbda187, 0x68616efe, 0x66cb4d67, 0xf6864db7, - 0x6fce14db, 0x19afead3, 0xddc4768f, 0xbd9e5c49, 0xd5d07205, 0x41b7b197, - 0x0e40ba0e, 0x11f20bbe, 0x4e2fefeb, 0x8b87faa6, 0xb47e541d, 0x47951fb8, - 0xf25fbf84, 0xd102101d, 0x2e2492ed, 0xc9249717, 0x6482faf8, 0xffc66934, - 0x3a21ddfb, 0x6c67de1b, 0x9d36309b, 0xc15cebb1, 0xa9c6f7fa, 0xd3b5fac1, - 0x8c971b60, 0x0a15dbe7, 0xeee5a3d9, 0xe1fd4191, 0x7bc464dc, 0x9e5fac2b, - 0x86f49dbf, 0xe81938c3, 0xb8e2a6f1, 0x37d7fea0, 0x9fd506a4, 0xfad07248, - 0x0ecf8d26, 0xb4b9bf6a, 0xecbd507f, 0xa431919c, 0xf1014777, 0x679102cf, - 0x8e770704, 0xfbef1b17, 0xa4b0dd75, 0x5fbd60bb, 0x73d033ef, 0x5e243e2d, - 0x9951ac67, 0xbe9bc607, 0x2c1fe406, 0x74e348f1, 0x0e2fafe2, 0xb25ce858, - 0x7f6f29bc, 0x350fd401, 0xe80f2819, 0x55b8b2d0, 0x6a1daf68, 0x2832b04a, - 0x6155cb3d, 0x2c8cd8d7, 0x2d15de40, 0xa6f9425b, 0x93933e65, 0xef7697ec, - 0xc0eeb293, 0x122e2af3, 0xd53de4f9, 0xfe10aad7, 0x67df045c, 0xe15ee922, - 0xf127b071, 0x4ef4e12a, 0x0ae3aebe, 0x13f5865b, 0xb9f71f91, 0x6a71d60b, - 0x0e856362, 0xbeea15fd, 0xcf9f9204, 0xb6e90cab, 0xf2819e74, 0xafbf660c, - 0x533ac06e, 0xbe395372, 0x66a3ca55, 0x7c6898cf, 0x021405d6, 0x6d3c16fd, - 0xae01ea7a, 0xfb7d78ff, 0x8203df40, 0x8e8e913e, 0x2c5732c7, 0xf5a1562d, - 0xc276fe7e, 0x87ee7c06, 0xee106fa7, 0xfdc1bd7b, 0xefe01266, 0x20df0af3, - 0x128b6f92, 0x70b4af88, 0xf2e4623f, 0xa07c8bcb, 0x9fa6e5f8, 0x7e9296cf, - 0x26706e98, 0xe56e493a, 0x3adca0a7, 0x7640d2b2, 0xacbbd330, 0x3e8f4893, - 0xe72c744f, 0x8c77a239, 0x691df5c3, 0x5f9864c8, 0xa552be51, 0x1fd20af3, - 0xe7e3efef, 0x0f5587d4, 0xdbcc24d8, 0x525878a0, 0x3edcdd28, 0x5de5186f, - 0x596ded6a, 0xeabc097e, 0xe64bb009, 0x8179e4ec, 0x3f53bf2c, 0x3ee06075, - 0x3cf9f196, 0x4af94105, 0x1daf5955, 0x2ec8eb34, 0xc273c18c, 0xa254f789, - 0x8d5913b3, 0x9f019343, 0x86bb7527, 0x2ff505de, 0xea8f7a26, 0xda223ea1, - 0xeb842ff3, 0x0ccadd5c, 0xfaf30b25, 0x091aaf0f, 0xacfe7def, 0x2e6c49c1, - 0xcf39fcec, 0x43fdeecc, 0x1bd815f6, 0xe1ddb8bd, 0xcffbc14a, 0x1acd1d73, - 0xc7c3807b, 0x00204981, 0x056adb17, 0x7876376d, 0x3c01e588, 0x31d74f57, - 0xe079e04f, 0xb1e3c8b0, 0xa873f324, 0x24a61bb4, 0x5d333973, 0xbd9be9c7, - 0x037a70ac, 0x0f502afb, 0x173db948, 0xbf55aaf3, 0xbb72901e, 0xfe52358a, - 0xdb99238a, 0x1f15b32f, 0x9835ddd9, 0x2bfd0289, 0x56683c6c, 0xf3e4d9b5, - 0xb698d265, 0x7a60fb40, 0x73279732, 0x8e3ecf8c, 0x3ac95be4, 0xfd353ef8, - 0x2af8373e, 0xf543323a, 0xc36d854f, 0x6f8d3b32, 0xb79fa270, 0x756bf052, - 0x256be2a3, 0x51eb853b, 0x299d57e9, 0x3f56a8f4, 0x8d25e885, 0xd1a99a3e, - 0x5831acbb, 0xe97ac2cf, 0xaf5cb2de, 0x68ee9d76, 0x0e61c10b, 0x6ff50bac, - 0xa7b7c785, 0x38add684, 0xeb21a301, 0x31ee64a9, 0x780fb8b1, 0x5d08eade, - 0x215f769f, 0xd4fb15eb, 0xf9c2bbae, 0xbbe62b55, 0x04293554, 0x243eed2f, - 0x9c76b43e, 0x97854bc4, 0x45a2b7c3, 0xd67e7c21, 0xf2321f6d, 0x61ba4b6f, - 0xe02ff0cd, 0xb047497d, 0x6f9412af, 0x1e41ab95, 0xd3d28667, 0x456cd61c, - 0xad61a9ba, 0xdf9053cb, 0x1faf9b5a, 0xb5867e8e, 0xa9f9d36f, 0xa39aded4, - 0x7a50058b, 0xbf8e5773, 0x17e74fca, 0x5cfc278a, 0xe9ddc3f0, 0xe01e9fa5, - 0xeaa37335, 0xd4141c8a, 0x7a3fe44f, 0xbcb38e09, 0x63fa235e, 0xe53f0967, - 0xab59d685, 0x2e5ff7e7, 0xcf015eb8, 0x0fdd7b9f, 0x7764f727, 0x76173f85, - 0x3d1a5bdb, 0xfb81b1ff, 0xfe7ca55b, 0xff22ef5a, 0x3b0bb42e, 0xe3c6ceac, - 0x9eb91a7d, 0xbd724f9e, 0x3979e842, 0x5b35d1cf, 0x13305e29, 0xf68080ed, - 0xa56f56cf, 0xd9f1a578, 0xcbb45699, 0xbe99ae8f, 0x8f52f30a, 0xbd274d36, - 0xa97bf95f, 0x40c63df7, 0x4d68a27b, 0x907bfad9, 0x5247378e, 0xdda2b15c, - 0x2045ce23, 0x639fa167, 0x6cab970d, 0x95b39735, 0x90071fa8, 0xfd8bec7e, - 0xf4f0acee, 0x68087e45, 0xe779bd27, 0x779fcf74, 0xfe77b8c2, 0x25e9da29, - 0x755ad850, 0x5adbcf64, 0xcf563f51, 0xde20f0ff, 0xe07b01d3, 0x7b4b5ffd, - 0x0645aa00, 0xea325b4f, 0x54076121, 0x6c321bab, 0xbd083768, 0x7f801ff1, - 0xe7f87844, 0x11cbfc12, 0xdbf101fe, 0x9c381b4f, 0x7fe06ba7, 0xcbc72578, - 0x2b6ca6f2, 0x6d3f2f9e, 0xebbb26c8, 0x821ca6d3, 0x00078cff, 0x1f5fdcfe, - 0x0035776c, 0x817cf1fc, 0x96f587f0, 0xfc043bb7, 0x0dfe1c9d, 0x256cee1c, - 0xc084672f, 0x57f94bd9, 0xe4d1fe77, 0x78e23b44, 0x57d92b64, 0xaca8b7c7, - 0x932ec03e, 0xac37d176, 0xdfb449f1, 0xf767fc24, 0xf28418e9, 0xd7e1f4a7, - 0xd98788ac, 0x3150785b, 0x95ccfe04, 0xeec7f144, 0xa8edbbf9, 0xdd5f116f, - 0xe245d476, 0x19b986a9, 0xd796c7e9, 0x4239e00e, 0x45bf7171, 0xb66fbc8d, - 0x19bef823, 0xda9592e6, 0x8ce2c5d1, 0xa4f5c088, 0x79d3ef69, 0xbebdc618, - 0xd6eaf9cd, 0x5de7c4f9, 0x25b97941, 0xfe80d5ac, 0xd0acd636, 0x05eaed3d, - 0x8642d685, 0x5a3ab571, 0x09453387, 0x56aecbca, 0x564f6475, 0x447c4519, - 0x892455e4, 0xdc29497e, 0x629c902f, 0x2474f2a3, 0xda707d23, 0x7de1f462, - 0x255f382a, 0x9ddefce3, 0x41dbc226, 0x5fc0135c, 0x333f0a35, 0xb7a442a8, - 0xd3a7185b, 0x297bcc5b, 0x972707ae, 0xa71fa875, 0xc939342d, 0xa18f8dce, - 0x42cdd2f8, 0x5e62ddde, 0x313d46ee, 0x61746ccd, 0x317ae309, 0x1a30d7f9, - 0x0df987a6, 0xef748cbd, 0xf3a234b0, 0xdf123c59, 0x8ef87c96, 0x95ea5808, - 0x1fa38e60, 0xf6dd7e18, 0x5e285c7d, 0xf609f8fc, 0x8546d74b, 0x170c8bf7, - 0x2e5c5070, 0x609b3ff2, 0xc75828ec, 0x6f0714a8, 0x3fb8d877, 0xc9e02d7a, - 0xb6afc7e2, 0xfc79799d, 0xb1f30ab2, 0xbc58f7f9, 0x5d541f24, 0xc8cabd50, - 0x62794f9f, 0x34eaf143, 0x8e61dec6, 0x2ab78881, 0xee782194, 0x61f18b2f, - 0xf43aef7c, 0xd4b1db87, 0xd64cbd13, 0x978eaf33, 0x0e3b660d, 0x25e3fdc7, - 0x2abf9e02, 0x0031ad60, 0x83d7d6f7, 0xb437f3fd, 0x02fb5aea, 0xb7d3af7c, - 0xea7d21b6, 0x1b061c22, 0xaf1ee3cc, 0xa539e2e4, 0xadc5e96a, 0xa689e2b7, - 0xa0a3d5e2, 0xacf9e3ae, 0xfee6bf5d, 0x59805b89, 0xeab76e11, 0xcb9abb59, - 0x52e100e9, 0xa978776b, 0xe2853cdf, 0x202e3237, 0x86183ff1, 0x2de3c40f, - 0x4e307d62, 0x37df1583, 0x7cd7c786, 0x8ccc2f81, 0x15cfb846, 0xf257377c, - 0xbf30535b, 0x0478823d, 0x2ed0553e, 0x22ddb806, 0xe2f89eca, 0x476e14a1, - 0xcfc2943f, 0xe25cf7ef, 0x95dccc7c, 0x82797941, 0x7c4daa5f, 0x75ff397c, - 0xc5307ca2, 0xf5cbe34e, 0x8a7ebd00, 0x0240e8e3, 0x691ebd20, 0x68fb27ac, - 0xc3880b16, 0x49fbfa65, 0x77ad0eba, 0xf7dd11cb, 0x66bb1a58, 0x5f95e820, - 0x8e513a44, 0xce6c62de, 0xf68733a9, 0x52e67193, 0xefa061d6, 0x993f4903, - 0x55633fd0, 0x9535e533, 0xf41efc2a, 0x578b42e9, 0xc7e27607, 0x067bbe22, - 0xa79c46ec, 0xfca15634, 0x773169af, 0x975f2096, 0x2c7a8d5a, 0xdff1163f, - 0x8d17595b, 0x2b2d89ff, 0xdf8606e6, 0xe631504d, 0xa4f80b07, 0xadfb05d8, - 0xebc3f947, 0xe4695d2b, 0x4ff5128d, 0x665c61f7, 0x03a079ea, 0x762e1faa, - 0x5fa7bcc1, 0x91d9cf15, 0xfa7e7c62, 0xdecf413e, 0xe9de34e3, 0x53f3e4c7, - 0xf90af9fc, 0x7f5e2bfc, 0xea2f8e50, 0x2f9e6b0f, 0x827f3cd1, 0xf89f5bd7, - 0xf68bd8aa, 0xda4e68eb, 0x921423a5, 0x37214657, 0x12b6974a, 0xbb754b9c, - 0xb59a3978, 0xdc2ff2ea, 0xdb8a64ef, 0xf7809298, 0x50588fce, 0xd533ff0f, - 0x7e814c65, 0xfe79269f, 0x499ce586, 0x7288d78a, 0xe91f3df7, 0xf21e9285, - 0xae428d27, 0xa6e5ea9f, 0x831ea5f7, 0xf1c3de71, 0xbb9c752f, 0xe4f9c743, - 0x4d738cc7, 0x4738c86a, 0xfebecc7f, 0x24e1ca9c, 0x517691c7, 0xe94bba71, - 0x663afc85, 0x70bf9064, 0x18cebdee, 0xcc314bf4, 0xcfd00377, 0x919cda5d, - 0x7dcfe307, 0x0a8cc5ee, 0xbe849bb4, 0x32a739af, 0xdaa3c817, 0x5f950a73, - 0xc4647db4, 0xdb35b37b, 0xa0e38cda, 0x45942d5f, 0x12aaeb01, 0xa77d04eb, - 0xa7a01c9f, 0x4274bd8d, 0xf3cc3c6e, 0xa13b9e32, 0xd5ce7c47, 0x3dfd1f35, - 0x4a11efea, 0x97f2f8d8, 0x7b077f62, 0xee611fb8, 0x6151e5c5, 0xee34576f, - 0x390614f3, 0xfaa2fc60, 0xbf02f9f0, 0x1528eb12, 0x50fa6ffa, 0xe003844b, - 0x1e3de43c, 0x9b58af5f, 0x62fe8b99, 0x04e8f263, 0x7e8f5b82, 0x67ee2ed6, - 0xd67ee16d, 0x02c77b52, 0xbb994efc, 0xf883ec57, 0xbf09b2dd, 0x2c067c93, - 0x378eef0b, 0x89bf7ac9, 0x3f714663, 0x7ef3d618, 0xf220f99f, 0x6e28decd, - 0x361b4ecf, 0x43e50a30, 0xceb46667, 0x4facfc06, 0x4af7732a, 0xc6abf6c0, - 0xc9a17b61, 0xe08ca7d2, 0xf42e88cb, 0xb8feee49, 0xfe8fec4e, 0x35b18f11, - 0x87d806e1, 0xee950de7, 0x45067803, 0xcbc5c27b, 0xe5c5ef2f, 0x8d97bbb9, - 0x0757b1e0, 0xaff5cceb, 0x760fce43, 0x180e82fd, 0x94d2c8ef, 0x30380fc1, - 0x5d78531e, 0xfcff04af, 0xa33c92b3, 0xa23fe702, 0x68f07d63, 0x18ebb171, - 0x1d71f02e, 0xf74a06c2, 0x80b7a028, 0x31e4def3, 0xa9f541d1, 0x15cc71c5, - 0x9a9dbfe8, 0xb1bf541a, 0xffa83b34, 0x07fa33cd, 0xea689f3d, 0xb00bafc8, - 0x97b67b67, 0x5a9f04bc, 0xed0a258b, 0xbe5a4fba, 0xb416e0f9, 0x4eaa3703, - 0xef6759b4, 0x48c1f4dc, 0xf00675e8, 0x497e471b, 0x3ed1f907, 0x7a747997, - 0x7e303e97, 0x50758a74, 0xd73ca2be, 0x68dc6c5e, 0xf29dadae, 0x78ae7f09, - 0xe25ebcd1, 0x72cb9bfc, 0xa99e3f51, 0x79fc9f7b, 0xcfbe6635, 0xe21e2f53, - 0xbd442ddf, 0x357f7402, 0xe2f688be, 0xc0fc1039, 0x0e3b45ff, 0x86cd9c51, - 0xf7b44dc1, 0xf1e9e6d3, 0x942d64fe, 0x81c65fa8, 0xba018adc, 0x036368e9, - 0x48de61b7, 0xe5db85a6, 0xbf90a6e7, 0xf7146f7c, 0x8c4decfb, 0xcc48efa5, - 0xda86b86d, 0xd345ce6b, 0x1da96ff8, 0xfa2f28e3, 0x13e28505, 0x2da75313, - 0x8decfdc5, 0x1db80ef2, 0xe7f89de6, 0xdc23c7ab, 0x7bf1b66a, 0x77d51302, - 0x5941e7f2, 0xbd0d78d5, 0x7b65513f, 0x621fb015, 0xe342ddce, 0x001b444e, - 0xcb50eaea, 0x5597a803, 0x3f9f6b63, 0x5a31bca0, 0x9ed4de48, 0x26f7a48b, - 0xfdfd7114, 0x0c4f217b, 0x635d7c9d, 0xe7a24dcf, 0xbd7c2e92, 0xf7f282b2, - 0xf51b090d, 0x4321bdf8, 0xaffd42a7, 0x4a9fd73d, 0xfa37dfb9, 0x2fbe91fd, - 0x7af84860, 0xbe8de61c, 0xc8d8af11, 0xe3c8d12c, 0x62c375b3, 0xd5791858, - 0x9e39cf3d, 0xc73a6c6f, 0x3bff8ff3, 0xe417f5cd, 0x9d4592c3, 0x31178c7a, - 0xe10d8473, 0xd8305255, 0x67c01151, 0x8c9baeea, 0xeac31f88, 0xafa88db7, - 0x0516504d, 0xf916af3c, 0xdd795a58, 0xfc83e422, 0x3fd49b8e, 0xd106792c, - 0x4136ade7, 0x9e8f82a0, 0xdf2c7c16, 0x0e33a0ef, 0xf73b71e0, 0x79a6b7f3, - 0xd13942de, 0x7c6ec851, 0x4767e49e, 0x7e69c606, 0x9e03f5ae, 0x1bb21423, - 0xbeaf293b, 0xc3a1c0a4, 0xdd7bc0f8, 0xf3f3877a, 0x26d1f685, 0xca96fdf6, - 0x6fb8e216, 0x1d97f2fd, 0xedaf182e, 0xd43cbcee, 0xcfde720b, 0x0b7bf17a, - 0x1e75d6cc, 0x2fb587cf, 0xef903b47, 0x0ce1e227, 0x4d3ba2e3, 0x76816e74, - 0xbed4778a, 0xef0a7a6c, 0xe15ad5bb, 0x17f30afc, 0x8ad912bd, 0x4af6dc74, - 0xc7f51ea4, 0x9f3dbd1d, 0x5e8a7c21, 0xcf063be9, 0x9316ae8b, 0xe3fd919e, - 0xb6f24a3a, 0x485ef587, 0x4ce9697e, 0x81a7a7f2, 0xa0994bf3, 0x7fc172d3, - 0x6747c11e, 0x0f8892eb, 0x45822ecf, 0x91753c63, 0xda1b7032, 0x7d0b0e0b, - 0xe5f24e97, 0x411f3c44, 0xb1fec4fb, 0xeaa18f74, 0x1f106c5c, 0x14cb9f56, - 0xed471dfc, 0x05cadf92, 0x7d84989f, 0xb5d04331, 0x3f245bb4, 0x624f74b2, - 0x6263ec2a, 0x95bdf03d, 0xc8f9fee2, 0x31ba7e4f, 0x80be90da, 0x022b926e, - 0xedbea7f8, 0x8a768626, 0x744dde29, 0x40ca0333, 0xb766653b, 0x971b629d, - 0x592feb08, 0x7bc3a996, 0x6a79f29b, 0x7fd1a5ea, 0x27c8aa44, 0xa0e6b730, - 0x8ba86b5d, 0x9a7de274, 0x1e3cf133, 0x87057f34, 0xbb837ce3, 0xf98ced08, - 0x3fe4284f, 0xe503fb43, 0x7503d0d2, 0xcabf40c6, 0x5106e74d, 0xb9ca7d3c, - 0x2634a8cb, 0x38472e7b, 0x5ebb9d94, 0x8fd06be0, 0x710e3f8a, 0xc192bf71, - 0xc86e7267, 0x4792bf44, 0x4f1f3c45, 0x0347b667, 0x546b7de3, 0xb8c98ff2, - 0x9933f4a4, 0x804fdef0, 0xdf46fd3e, 0xa3df4198, 0x0a9dfad1, 0xb93ffeb9, - 0xbffa40d1, 0xa19dedaa, 0x79fe783a, 0xf5092ba6, 0xa7837ac9, 0x6733f708, - 0x0339efb2, 0xb83ee7d4, 0xe1dc3ad5, 0xbeb36787, 0x69f50735, 0xfd11c033, - 0xd52bcd5f, 0xf76e3ef1, 0x1a38f344, 0xcf496fa7, 0x739f3a5a, 0x73e09b2e, - 0x7a44ceb6, 0x2dd02ce8, 0x5243d00b, 0x2f3948ef, 0xeba48ff5, 0x5f973d6a, - 0xca18e6d5, 0x9debf323, 0xa442ee49, 0x1f3c7ebb, 0x9e77afd0, 0xf902355a, - 0xe53c74e0, 0x21bd4b5d, 0xc585e0f9, 0x244794c9, 0x03e492f5, 0x7ca5cf29, - 0xf52f7497, 0xfd3fe8d6, 0xc3bfd6ef, 0x3cd293af, 0x7d02a577, 0xfae7ab5d, - 0x85bd5aeb, 0xfc6c67e8, 0xcdd23d24, 0x43d1cbc5, 0x0a1e8e42, 0x3d35a392, - 0xa94581e8, 0x1c5e7e52, 0x7c11cc1f, 0xedc4de33, 0x81f39448, 0x8da6b5e3, - 0xb1f7087e, 0xd9eb953a, 0x3ddd6b9f, 0xa9d5ffc9, 0x97ff2697, 0xfc9c5ea4, - 0xfe54efff, 0xbcad0a9d, 0xa3710fc7, 0xf3bd3fbc, 0x83ea1f72, 0x03f40c83, - 0x6896c1ea, 0x0fa126c7, 0xc5445f48, 0x1f487ef8, 0xfe9ef614, 0xf5e1a9df, - 0xff6c66c1, 0xd240fab1, 0xc91be497, 0xb42f9227, 0x62f9247c, 0xbce16fc2, - 0x8b7a7888, 0xd6aa8fdf, 0x0e289b7b, 0x8c1e88e9, 0xc76dd9fc, 0xdf88536d, - 0xe084f442, 0x04bf3f1f, 0x1fc90deb, 0xff245f92, 0x98fe0b54, 0xf243f829, - 0xf9b56ec5, 0x0a9811d1, 0x08f9e690, 0x93e488e5, 0xfab5e7aa, 0x42ba47a1, - 0x199b234f, 0xae90c75f, 0xa40ca1aa, 0xfc0f532b, 0xf512f070, 0xa48bbec2, - 0xf3feafa7, 0x0f55f4f4, 0xa7e674f4, 0x1da853d0, 0x03be61fb, 0x1f3673d6, - 0x9fa66de4, 0x8dfc26de, 0x9b21fb71, 0x46f6079f, 0x35ee7df1, 0x67ff93a6, - 0xcf3cf7c2, 0x3303da57, 0xd241bf85, 0x01d81e69, 0xf8fc4369, 0xbcc0f3c7, - 0x847b938b, 0x877c5367, 0x3327cf11, 0x03b40ca1, 0x537fb27a, 0xee4d2ed3, - 0x17fe8a45, 0xb480f3c2, 0x1c6edd9f, 0xaf1e1690, 0x027ed303, 0xa262275e, - 0xb22bf92a, 0x00a35c4b, 0xba890f3f, 0xc2094fb7, 0xf902faf1, 0x2e55b2fc, - 0xd607ca3d, 0xf475ddfd, 0xcaa5bc77, 0x31fece7a, 0x8f099eb0, 0x1d1fbf32, - 0x151d8f9e, 0x511fedd3, 0x717fbf98, 0x95fed65a, 0x451be7a4, 0x9ea74ade, - 0x3d4483c7, 0x8096ea1f, 0xbea6817a, 0xeab7f796, 0x3e60593b, 0x928dd209, - 0x0eecf1cb, 0xfa601fb0, 0x2fa8b3f6, 0xff430a6c, 0x86fc6d46, 0x5ca2cf57, - 0x6c50a1db, 0xde0e1baa, 0xfa070481, 0x07d5383e, 0xc65d77ef, 0x78dbcdd8, - 0x43b5f6fd, 0x132f7956, 0x1bdc06e3, 0x2e2b3432, 0x502847ca, 0xa199597c, - 0x4d3dbef0, 0x1eb913ca, 0x0214f746, 0xaf9867de, 0x77ef2977, 0xd1674de7, - 0x4ba6adfb, 0x5186ff98, 0xac6fefe1, 0xe4c6fd10, 0xfe7d84c7, 0xe1ca9a70, - 0x3406fc2f, 0x694d343f, 0xff9f7f0e, 0x1d2fc109, 0x78213f18, 0xfe855a4e, - 0x84a30eed, 0xc2157bb7, 0x41632c7b, 0x9f98347e, 0xbad71bea, 0x7cf41a4b, - 0xbc0d2ebb, 0x77bf687e, 0x03db05a5, 0x5f069bf4, 0xf7801fa6, 0x77de61dd, - 0xfadfbf04, 0x125af843, 0xdba0bef2, 0x5d8e9259, 0xa31ef441, 0xc67d1377, - 0xb4362bc4, 0x91dc6ba3, 0xe0bcf12b, 0x12d2cfe7, 0x138c9b82, 0xb4dff084, - 0xc8033192, 0x6fcf124e, 0xebfc855b, 0xe7f775d6, 0x1ae928fc, 0x5c0136af, - 0xef07f5c9, 0xeb769cbf, 0x024ff42a, 0xaa73d05d, 0xadd603eb, 0x4d66c7e5, - 0x7f86947d, 0xfc91ff05, 0x70007d40, 0x16f941ca, 0x08e8c87f, 0x044f93a0, - 0x7c894e9c, 0xdcd18ef2, 0xe2c8ec9e, 0x3c6977e5, 0xa099f52e, 0x9e9253cb, - 0x90e002a2, 0xf43f4416, 0xf60221f7, 0x29ba704d, 0xbdf3f25e, 0xbfc0c525, - 0xfcfe761d, 0x66fed67f, 0x5fcd3795, 0xcff78ed7, 0x2096f7b5, 0xf7c7ba5c, - 0x768fda2e, 0x6e024dc4, 0x67bdaddf, 0xc08077bf, 0xbbffa273, 0xf41f40ab, - 0xa46a9e3d, 0x3e94250f, 0x2fa50d5e, 0xfa7de6af, 0xbd3d043b, 0x7950b7ff, - 0xcfbcd2e0, 0x17107bf0, 0x5bc0beff, 0xe3af06b1, 0xa31d7835, 0xbaca97a9, - 0x4afe482f, 0xe3be5cb9, 0xe312fbe1, 0xd0a9afd1, 0x3d3f2475, 0x3cf4483f, - 0x77e926d7, 0x4fd5c115, 0x47ed0fcf, 0x2cdc9dfa, 0xf491b5e9, 0xc39424cf, - 0x29f5fc23, 0xfea88728, 0xc5c60970, 0x91eafafc, 0x6fb72855, 0x1ffd9068, - 0x2f37fea5, 0xa6ade393, 0x8c8f12e7, 0xeefa463d, 0xafa97ca6, 0x3fb9271e, - 0xefbf85a7, 0xfeddff4c, 0x4687e41f, 0x6ad65c0d, 0xff4d5eea, 0x6fd017d5, - 0x2fef34cb, 0xa95f3cd2, 0xd4d1afa9, 0x2fdf821b, 0x1f10a19b, 0x38f01596, - 0xb52f96a5, 0xef4ae1f4, 0xf5ba73b6, 0xfb2662b9, 0x26af882e, 0xb5faf3d4, - 0x1a4b1be9, 0x75f501cc, 0x5f384a9b, 0xf7016cc0, 0x7ae6419f, 0x4307a055, - 0x20b3720f, 0xd9b907bd, 0xf9efab4f, 0xafe07ff3, 0x0a371429, 0xab764bb2, - 0x5536f5c1, 0x75bbdbac, 0x810182ff, 0x4be7d5f1, 0x63dd5cf0, 0x5cdbc71c, - 0x2ed02632, 0xae25cd62, 0xfeca7d80, 0x5efbbee3, 0xeb3cf9c5, 0xd1b25cfe, - 0x114f718c, 0x12f3b4df, 0xfa8aa5f4, 0x6ff856ba, 0x2f1e61c6, 0x5aa293c6, - 0x080fe673, 0xee6b27d8, 0xbb6cfb83, 0xb7dfe55b, 0x00fc07ab, 0x8398ca9c, - 0x33a750f2, 0xb6a5e517, 0xfc2cc4c5, 0xf76f782f, 0xd442eadd, 0xc61707d3, - 0x2bd35e51, 0xb17cfce9, 0xe277a63b, 0x45b7a84c, 0xb6f246df, 0x54b1feed, - 0xcb5d52ee, 0x2d8c6cbb, 0x894af75e, 0x1e7c72f9, 0x3bba7043, 0x2592a5fd, - 0xa6f7ef40, 0x8f7de83b, 0x03b896dd, 0x0c07eded, 0x0e043714, 0xe7e89278, - 0x3c60d341, 0xe92d976f, 0xf2b1714f, 0xc38d26c7, 0xf7e5a47b, 0xd25e2819, - 0x9f91b3a9, 0x58c0f3c8, 0xb19a93ca, 0xabde944c, 0xdfe57ca9, 0x7bc7ac7f, - 0x14eb5da6, 0x55cd4efa, 0x6dff375f, 0x1b2bd410, 0xc67ee9b2, 0x9474e7cb, - 0x9ae9fe17, 0x53cc3ebe, 0x47591c3e, 0x9fd0a5f9, 0x9e56bbee, 0xc92fec77, - 0x0daafec7, 0x428e3853, 0x47cfda3b, 0xe14fa857, 0xab32ce3d, 0xbbf30a25, - 0xc8c77e8f, 0x3ef473af, 0xe6ef7d13, 0xd6e7b353, 0x8f74f135, 0x767d2d09, - 0x15587154, 0xf4dac380, 0x29c925fd, 0xf8126ed8, 0x032d6fdc, 0x75d32f3e, - 0x93e90fd3, 0x5f5e588a, 0x92cdeebb, 0xa38fb04d, 0x7ca5f44f, 0xd70c84b1, - 0xd78074ba, 0x93d70ce1, 0xd9fb8a54, 0xc79bfcaf, 0x593a5f25, 0xb5f4889e, - 0xcbf5d059, 0x0313cae7, 0xc5416eff, 0xc1d13d29, 0x02c7462b, 0x5469eefa, - 0x6ce782ba, 0xf43883a0, 0xe710cf9b, 0x85e7a016, 0x57d8c35b, 0x3db9d34b, - 0x84dbf6d6, 0xba208e51, 0x29e498fe, 0xfea0379d, 0xa447fa62, 0x16988ee7, - 0x77752e62, 0x1ddb243e, 0x34327049, 0x3322fa45, 0x1aea7fd1, 0x4ff3a2e7, - 0x96c99f73, 0xfd143e00, 0xfcf2f13f, 0x3fa04fdf, 0xf13efb9e, 0x604b3ffe, - 0xaff6433c, 0x68bc5ab4, 0x58b31c5c, 0x838f88f4, 0x3147c5fa, 0x9d62ad3f, - 0xc540f481, 0x5d4584ba, 0x6e807f28, 0xdda6bfd0, 0xc0c32997, 0xc63d18fd, - 0x192f3f57, 0x5e781693, 0xbbf24139, 0x377cbe27, 0xc6c944fd, 0x65f33d01, - 0xa7cb8da5, 0xf7f8eb71, 0x58872b75, 0x7bbf74f4, 0xe89babdd, 0xc8bcf01e, - 0x5157bc5c, 0xf844ceb9, 0xbc58b4ea, 0xbef12bb6, 0x0b1f4581, 0xae74a1e5, - 0x0e19f54f, 0xca9147c2, 0x54b911f4, 0x190a3dd2, 0xf0b13c3f, 0x1d31c7d1, - 0xbbe673f3, 0xefc0187e, 0xe9d38b8c, 0xf92a6d99, 0xc4f1b51f, 0x1ab7d7ea, - 0x888fd90b, 0x4710f627, 0xe29d62ac, 0xe3e1e2bb, 0xe238da89, 0xbdc5d2bf, - 0xa238eeb3, 0x5187be81, 0x4588e229, 0x7f5a156b, 0xbdfe42e5, 0xee38a292, - 0x18b23e3f, 0xed2fa0e8, 0xc5cb6bdf, 0x7fae693c, 0x8be2992a, 0x5eaf5f80, - 0x99fc8f3b, 0x5e1ce975, 0xb03be265, 0x199d2387, 0x58afde78, 0xae704917, - 0x07f6727c, 0x7de3e44f, 0x81f189c0, 0xa09b6be7, 0xe19f180f, 0xce39683d, - 0xd0f725b1, 0xd68b6777, 0xf31939c3, 0x73d963b4, 0xde226537, 0xde303252, - 0x2e55fb29, 0xef0fbbbd, 0xd86ce707, 0x950ad977, 0xbb6b0f7f, 0xf021f489, - 0xb80b327c, 0xd9633e2f, 0xd72346eb, 0xa8792c67, 0xfe1db3b0, 0xc29f6cfb, - 0x4104fc73, 0x26b7b8ad, 0x5bef27e1, 0xf7f8e995, 0x0a754b36, 0x8902c3dd, - 0x7e97f746, 0xa3fdc191, 0xcedc1979, 0xd270cb2d, 0x55ea9e3d, 0x4cd2e726, - 0xbdf74e3e, 0x55e73875, 0x282a3aeb, 0x1317f9ae, 0x976a57f9, 0xad22ba45, - 0xf9e31f3c, 0xad779401, 0xaa3c0237, 0xfc6e5c1c, 0xad63d042, 0x94d5d263, - 0x0767ae9f, 0x5607eff0, 0xac9cb85b, 0x9bb8058e, 0x86e90139, 0x1939f7e2, - 0xb8e253e5, 0xe6028329, 0x8c3b4457, 0xc7fab0e3, 0x0d63abdd, 0xfec1a7e8, - 0x38420f97, 0x237f5dc6, 0x9559efae, 0xb4801af8, 0xbfed00aa, 0x3c3cd567, - 0xd8ad9777, 0xf0e50e3d, 0xf1832ddc, 0x7b2b0546, 0x23d25dee, 0x3bfe0573, - 0x395a3e45, 0x81bbf1d4, 0xb9706437, 0xdfb951e9, 0x2f0106e8, 0x79f20749, - 0xf7030af5, 0x47bc83e3, 0xe4bd5301, 0xdab71a43, 0x728891d2, 0x81bb7ab8, - 0x8cdf87ee, 0x973806eb, 0x751f492f, 0xdcaae800, 0x51df4310, 0x344ef2ad, - 0x51aabd62, 0xbdffbaa1, 0xd3a40c84, 0x60bd962f, 0x1c39fa45, 0xfa839ad9, - 0xa45e6ba9, 0xda29ee93, 0x8beedfb8, 0xaf743965, 0xc3ad8669, 0x9965df82, - 0x8edb20b1, 0xada0fc72, 0x0fcf88d5, 0xb0ea6736, 0x46d9b2ee, 0xbfa5dd61, - 0x885fea92, 0x41fa177c, 0x9e3852ba, 0x1b769aab, 0xdd2feff1, 0xd4e2e82b, - 0x41f6efb3, 0x4675503f, 0x2fd41f47, 0x527d0740, 0x28cfce11, 0x9a6b9fa4, - 0xa4bc1e78, 0x03a41a83, 0x8239bbe0, 0xbdb66a0e, 0x43f21770, 0x373fe20d, - 0x9e808e94, 0xf9fda9db, 0x7f18e30d, 0x44e91dbf, 0x2fa833ea, 0xce3fa033, - 0x058bebc8, 0x0c7da1fe, 0xe00ef76f, 0xf9dd75f9, 0xd07c4108, 0x66d77e13, - 0x4c3e04e8, 0x8ad77724, 0xd8ae76fd, 0x9dfc456e, 0x1ef7767a, 0x3f54b78c, - 0x11dada0f, 0x3c041f86, 0x56ff716a, 0x19d93f5a, 0xab5fb8b5, 0x74ddff7f, - 0x96b0f82f, 0xfdc9fdf1, 0xfec5ead6, 0xfef173e5, 0x2acfb13a, 0xadb5e026, - 0xc13be72f, 0xf4c7c867, 0x3fb121dd, 0xbbf83d8f, 0xfec5bbba, 0x6cc9449a, - 0x0f8456cd, 0x0fe517e2, 0x28cb8fd0, 0x397409e5, 0xe50365b5, 0xc97c4bf7, - 0xd7efbff5, 0x93fc2e2b, 0x9d8f1254, 0xb6f77c3d, 0xa1c9f045, 0x763292fb, - 0xd8befc00, 0x240d9f4c, 0xcc07d57a, 0xce46e927, 0x49a7f457, 0x61bee2d7, - 0x5f1c56fc, 0x1bd07bce, 0x0e71c7ad, 0x721fce32, 0x8b2f92fd, 0x3b5da7ea, - 0x4efd8ad8, 0x5ed1b259, 0x3f7c7811, 0xbbef46c3, 0xf7806ed0, 0xf2143b5d, - 0xe7121f5f, 0xbdf743fd, 0xe01f2d60, 0xc577f7a7, 0xe19d25ba, 0xe4c9fa0f, - 0xb9daf77a, 0x6ebb583f, 0xbae48729, 0xe1bfee8b, 0xeb976c5a, 0x2051f8c7, - 0x4a384a9d, 0xfaf7957a, 0x344b74b4, 0xdaaaf527, 0xa6d77d33, 0x9dfca21d, - 0x78ed7690, 0x2c3a3ec2, 0x9ebbcdf2, 0xe77df956, 0x41edc965, 0x33188ef7, - 0x259fea07, 0x15b6aef3, 0x49b73c62, 0x521e7ba1, 0x4acfc0af, 0x923e807d, - 0xdef0c1f6, 0x36a57f3c, 0xf10275de, 0x63bc7559, 0x44927e1c, 0x7d57a5da, - 0xa0c6aadd, 0xcf1b6aff, 0x53749383, 0xf89db275, 0x93dc5aa1, 0xeef15b2a, - 0xf74861c4, 0xce281b4f, 0x58df7653, 0xb3fbda23, 0x8a1f4d37, 0x127bc0e0, - 0x6c4fdf28, 0xe047921c, 0xebc4b661, 0xc6c4bef1, 0xbfc7af47, 0x87633a5f, - 0xc1a1df4a, 0xcb8f9071, 0x7f23c8ee, 0xcec8e1eb, 0xaed02389, 0x436ab5ff, - 0xa6e47ebb, 0xffb08b21, 0x58ef4b48, 0xc6d078fa, 0xf4bbaa38, 0xa427a431, - 0x03f32c1d, 0x90bdc5eb, 0xaf9cdeec, 0x8a97757a, 0xefac0bc8, 0xaef9f183, - 0xddf4910d, 0xa3a352a8, 0xdbe715b9, 0x8ee74499, 0x2526385a, 0x2b9ee9db, - 0x8cb369d9, 0x9725222c, 0x453023da, 0xc74375f9, 0x5e4fa81d, 0x1832c3bf, - 0xd4cb8bbf, 0xb9cb43f3, 0x90e3cd7d, 0x61dfc171, 0xeac8eb92, 0x3b57e9cd, - 0x2f7f7c9e, 0x74ec2b9e, 0x3fde919f, 0xebe9ecb1, 0xd89e1f51, 0x7dc7639c, - 0x4919db1f, 0x198e0bf7, 0x78e7bf82, 0xb4c2f7a9, 0x3de4a9f7, 0xc1defcd7, - 0xfba49cf6, 0xb9cbde0b, 0x98f2d2ec, 0x74662e4e, 0x065cfc4f, 0xe8e4fee3, - 0x7e62b6ef, 0xc9a34561, 0x8e64f786, 0x7c63fd20, 0xdf4abb6b, 0xdfbba201, - 0xdb23af80, 0x703ee8f3, 0x5ebcc7c5, 0xf0f8acd1, 0xc3fb72fe, 0xc2fe53f7, - 0xf137b04c, 0x3db7796a, 0xebe1fabd, 0x38ce0d91, 0x3bf1cb3d, 0xf3366700, - 0xef908b7c, 0x75bebc3a, 0xffe38a4f, 0xfd2cfdbf, 0x077bd313, 0xf09347df, - 0x57aae796, 0x720a2e80, 0x72fbf0fd, 0x9fb22cf1, 0x50f62e4f, 0xb4395a79, - 0xb3d2246a, 0x15ee8625, 0x51e3b4bc, 0x5373bf15, 0x79f06dbd, 0x308f1f3c, - 0x9ff7d0c7, 0x90bc5cbe, 0x17279a82, 0x8a3f89d7, 0x15f854b6, 0xb55e547c, - 0xfbde8dad, 0x0b5e4772, 0xd97debde, 0x9ac5c31c, 0x3be820ab, 0x3dbf1299, - 0xfb9657dd, 0x1cd7fcfa, 0x9fdd72cf, 0xc56e9e6f, 0x21fdb57d, 0xe23865ae, - 0x86c63a37, 0xc8a56076, 0x86ba392f, 0x23c7d9db, 0x18abfe62, 0xed7c7cf0, - 0x0efc4494, 0xa9b6ccd1, 0xc57b63d7, 0xe786c54e, 0x49cee703, 0x7dcf3c56, - 0xe2b4efa6, 0xd6cfaa3d, 0x3e57fbc8, 0x237bbbfa, 0xd829b3c6, 0x9eab447f, - 0x84293239, 0xfc32f44c, 0xcbee9ea4, 0xe4ed017e, 0x451f393f, 0x89f813fe, - 0x99927cc3, 0x4bbf722f, 0x9c57f9f7, 0x7d8a46ff, 0xcbb6f7b7, 0x17b506f8, - 0x63f6f015, 0xd096b76b, 0x68de4fdf, 0xbfbae1b0, 0xf1a068dc, 0x4db9c0e7, - 0xbe3deb07, 0xb0839f99, 0x13e8e78e, 0x6779f99b, 0xef3f334e, 0xb833cf54, - 0x60d2fdf8, 0xe80a2cba, 0xeb2ddf47, 0x7323bbe1, 0x737f7c5c, 0x7ee27f40, - 0xb1bf442f, 0x9fee99ac, 0xa93e6a5d, 0xaaff7e96, 0x74dd1791, 0x08bd13db, - 0x23ff22b8, 0x98ba4add, 0xf5c786b3, 0x0b83cded, 0x9d24fe91, 0x5803bf68, - 0x3bfc646f, 0xfa28bab2, 0xb324f7ee, 0x62fa80c3, 0x18e77c4a, 0x075f4f04, - 0x916aaf97, 0xe4f785ce, 0xec29bd58, 0x15dec477, 0xbc1a78f2, 0x7abbf74b, - 0xcff7f8db, 0x59317dc4, 0x474abe82, 0xda293e7d, 0xba038dfe, 0xf2ffae74, - 0xf5d03d3a, 0x3bf691a4, 0xd7809db2, 0x7af35ff5, 0x167b7d9e, 0x7def3fd4, - 0xec3d3af6, 0xf695d26f, 0x2fa80621, 0x75cdf259, 0xc9b9e063, 0x3bd83ae1, - 0x9b139e60, 0x7f71d292, 0xdb087ed0, 0x8e7a27a7, 0xee2b5960, 0xba569d8f, - 0xf4cc2d06, 0xa77b7ff7, 0x0e4be0e5, 0xc0d3bd7f, 0xa73bbbe8, 0x87f5cb7b, - 0xd70e9d2f, 0xa109dea9, 0xdd8ce5ed, 0x5e7cf947, 0x7e076f7e, 0x788911dc, - 0x5dd38aaf, 0xd3c7bcb9, 0xe3c7b9a0, 0xe4d5f7e4, 0x7f792afd, 0xfdff72ea, - 0x7297b5b3, 0x00ffecff, 0x4fb2f369, 0x00008000, 0x00088b1f, 0x00000000, - 0x7de5ff00, 0x5554740b, 0x55b9e896, 0x2a493eb7, 0x54842549, 0xaa84a925, - 0xc0902b7c, 0x310c7c25, 0x0403e548, 0x6a285888, 0xa205a0d4, 0x01148280, - 0x55f4741d, 0x9a7c3061, 0x179f8ee9, 0x102d4622, 0xdd787195, 0x866db1d1, - 0x3220538f, 0xb40e9afc, 0xd38ceb63, 0x68d1d01d, 0x38311b63, 0x6f360cf4, - 0x4dce7def, 0x802a56ea, 0x6f7be7be, 0xf65e97ad, 0xee739f61, 0xffb3ecf9, - 0x5f5bdf67, 0xa5eb2c19, 0x0f24c664, 0xa153ab63, 0x63595a74, 0xff7b9419, - 0x68d2cfe9, 0xac839ac6, 0xc18f2e3b, 0xd3f5a35f, 0x7ccf5051, 0x2e504bba, - 0xcd1a484b, 0x139960c6, 0x996fd062, 0x12aeb189, 0x6d3b26e8, 0x12d8c2cc, - 0x019dfe09, 0x19caf9ff, 0x956c674b, 0x44edfe15, 0xf08742b8, 0x7f466683, - 0x3f98059f, 0x1fd8c0df, 0x3925744f, 0x9d9d8cf5, 0xbb0c2e1d, 0xbc65fb18, - 0x009ce6cf, 0x8ecd1ded, 0xbec634a6, 0xd4a4c37c, 0xd09eff43, 0x60f927df, - 0xe67aa5fc, 0x6d9284ef, 0x24d8ce1f, 0xc3ea2f28, 0x61dfa053, 0x8db6f157, - 0xa9cbbcf0, 0x3f9e0c63, 0xfce70aeb, 0x82c678f5, 0x32f2932e, 0x32777ea3, - 0x9f1eeb80, 0x9dfb1c3e, 0xfe5d7d7d, 0x936eb03d, 0xec1258cc, 0x598c067b, - 0x0030780e, 0x07c32fac, 0xb40e3442, 0xbea09307, 0x0e74f5c5, 0x2f307c23, - 0x0dd8c89b, 0x06ebef8c, 0xf11fbc39, 0x196494c5, 0x6f9b37f7, 0x3283db0f, - 0x3333a38c, 0x98bbae03, 0x4d3f5875, 0x8eb19800, 0x7f60c34b, 0x3263c066, - 0x24c78096, 0xa1eaa6c6, 0xe9afac13, 0x0990fa97, 0x7884d7d6, 0x85d07014, - 0xd72c7a23, 0xc58bf8c3, 0xbc8ecbbc, 0x58c1c46b, 0xeb07fe10, 0x5de62259, - 0x3d7771dc, 0x9092cb9e, 0xc0b74ce1, 0x7ffa25f5, 0x72c79d0f, 0xf2feefd1, - 0xe29c46ad, 0x7eda1dfe, 0xafa6d9cb, 0x52fcf0f5, 0xfdc46dd6, 0x6a8ceb2e, - 0x0cf9a8ef, 0x977cbbd7, 0x99debeb6, 0xc2748698, 0x97b1b2c6, 0xe74d54f4, - 0x99f448bd, 0xca746faa, 0x66e19fb8, 0x371304c5, 0xf4479f3d, 0xb00cdec2, - 0x63ac7ec8, 0x8b4fd118, 0xb1e74f4b, 0x9cc49764, 0x7ebb18e3, 0x42731657, - 0x61aefd53, 0xc85d2654, 0x5fcffaa0, 0x57de3639, 0xd75e7032, 0xc6ab6abf, - 0x6aff5df5, 0x3aea9511, 0x4e1d049a, 0x867497d5, 0x2ce71d61, 0x9b800eb0, - 0x8162c08e, 0xd66e9a7e, 0x99e11887, 0x57bfb199, 0x596bc72c, 0x424fa5df, - 0xfd8a0e58, 0x3a24974a, 0x1f3c6484, 0x433d61ef, 0x031e627a, 0x79993bb5, - 0xa05ca5cd, 0x398ebb1b, 0x24dfe063, 0x19ce2fce, 0x81ee9ccf, 0xfc583976, - 0x87584ab3, 0x0941ae61, 0x5c737b41, 0x33e436d2, 0xe574f416, 0xe20d73c3, - 0x4e38aeb9, 0x54ee0937, 0x1d2af3cd, 0xadfa2adc, 0x18769a4b, 0xb3c1b2e9, - 0x5121e888, 0xc7acd4c9, 0x406a5fa4, 0x67d5b9fa, 0x623ba4f8, 0x585fa21c, - 0x295e0dc7, 0x7378fc84, 0x50ddb683, 0x44ad75f9, 0x8e47d425, 0xfbf6d5e7, - 0xd003d229, 0x717e103b, 0x9c0c3d24, 0xc3a3c583, 0x1224f073, 0xb9cccbbd, - 0x5be012b9, 0xee181b0e, 0xf7cf14df, 0x97310e79, 0x0f80fd86, 0x8875e260, - 0x2e4fa817, 0xc537e2d7, 0xb0e7c5a3, 0x867e2d3a, 0xb7fbb57b, 0xda6ae435, - 0x35237c33, 0xcb8b59ed, 0xbfb67034, 0xc47fd342, 0xec0d6aea, 0xf4d4ce0a, - 0xa37f5bcf, 0xbd682e06, 0xa8bfd35d, 0xbda6817d, 0xa69f7438, 0x268ed47d, - 0xf9da5c0d, 0x98ffa688, 0xda6b8f5d, 0x6a3786c7, 0x7e1dc7da, 0xe84f034a, - 0x7fe9a2da, 0x34db07cd, 0x5fba93ed, 0xdb5fb4d3, 0x9e0686f3, 0xd35bbbdc, - 0x0385ca7f, 0x1d8ab81a, 0x31aff4d3, 0x4f0356ff, 0xa6abfeb5, 0xc7fb74ff, - 0xce19f69a, 0x67da6a3f, 0xd2d1bfb9, 0x93973c6b, 0xa5ff2bd7, 0x9359ee79, - 0x5f50dfef, 0xdd954b34, 0xebf48641, 0x35ba3e24, 0x0184a74d, 0x972a83fe, - 0x1c9e1d04, 0xc1392561, 0xb78e59f2, 0x32b0e914, 0x6e7c7c8c, 0xe0f24497, - 0x28bd28ab, 0x91ebd1ff, 0x4afd9da0, 0x22765e52, 0xc45d41dd, 0x331e29fc, - 0x39d62393, 0x81aaceac, 0x9aed7b87, 0xa706b6fe, 0xe7c33da6, 0x2d67b4d6, - 0xb6703456, 0x7fd35cbf, 0x068f6ac4, 0x34eb0576, 0x7bd6f3fd, 0x6b417035, - 0x517fa683, 0x5ed34fbb, 0x69ac5a1c, 0xafc3b51f, 0x573b4b81, 0xd98ffa6b, - 0x8fb4d415, 0xb4d7af0d, 0xaadc3b8f, 0xb5742781, 0xf35ffa6b, 0x3ed34841, - 0xa6877ba9, 0x4e9edafd, 0x77b93c0d, 0x94ffa697, 0x5c0d610b, 0xfa688ec5, - 0x6a4f98d7, 0x0fd6a9e0, 0xdba7fd35, 0x67da6b4f, 0xb4d73f38, 0x2cd076ab, - 0x7adad7f7, 0xaf5d1761, 0x7cf359fc, 0x90c3dab0, 0x486f823e, 0xd613b34a, - 0x3fe102eb, 0x777ce49c, 0x28ed1e9c, 0x8c14182f, 0x41ad2901, 0x420c92fd, - 0x480ae90c, 0xe2a6358c, 0x20ac4028, 0xc15549b7, 0x4f68c9f3, 0x73aa9000, - 0x1fa0fcb9, 0xeb5ad813, 0x1bb266a7, 0xdf40971c, 0x29bfc25d, 0xa0944b83, - 0x85ebaa9f, 0x4ea166f9, 0x726f3a02, 0x582e3cf9, 0xaf9d7dcf, 0x6862cb4f, - 0x705b0427, 0x9307a01d, 0x9e6f41bb, 0x79776388, 0x378f064b, 0x89780cc3, - 0x5c48ef98, 0x32cca3ab, 0xcc33fcf4, 0xff7fa967, 0xae3e06b8, 0x8a6bfb04, - 0xa0a7ff18, 0xfbb065ee, 0x37c0035a, 0x153d8c05, 0x4cfc12b0, 0x5b704ec0, - 0x7b6549c0, 0x96e54dc0, 0x1ded4280, 0x5f827281, 0x0e087808, 0xdca8ea05, - 0xfd52f016, 0xc10340f6, 0x547c04af, 0xa62c08ee, 0x9f80b5f2, 0x560677da, - 0x40f3fc13, 0xc0ceca90, 0x237faa7a, 0x9bf04ad0, 0xdf827681, 0xdca8840a, - 0xe541d815, 0xb52740ee, 0x22ec0def, 0x9840edf8, 0x30e070e0, 0x5d0207c1, - 0x7c0c1f04, 0x40a1f040, 0x03879537, 0x0d1e543d, 0xf1fb52f4, 0x078205c0, - 0x576b4bce, 0x2e576133, 0xd2c07412, 0x2f793db8, 0x85f6523f, 0xbb462d8e, - 0x43a09177, 0x87983543, 0xcc867740, 0x2ecd6dc2, 0x13a06a3c, 0x71c9d137, - 0x96af2fb4, 0x4070d04e, 0x33560d7a, 0x5a9bd237, 0xc9e954b6, 0x90ae0cfe, - 0xbb732f42, 0x336feb88, 0xb537f553, 0x85283e37, 0x079b9ed0, 0xf811b276, - 0x9f6123e6, 0xe5c7147c, 0xc1bf39f5, 0xa35f768d, 0x66c0af14, 0xb277fe01, - 0x8c2fe03b, 0x5ed77fa4, 0x9fb456d3, 0xc235f5d4, 0xe7183a38, 0x5a2eecbf, - 0x6c3b2357, 0xbd40f5c0, 0x72fc0f47, 0xe2dbe6c6, 0x2fbeba02, 0x2234175b, - 0x85425913, 0x8cc644de, 0x48f3df76, 0xf7fce7e7, 0x17c1c21c, 0x9c429559, - 0x78537ae7, 0x7f30adf8, 0xb2bd11ef, 0x5e3439cd, 0x00ceb796, 0xf6997de1, - 0xa0773fb7, 0x17f75f1d, 0xe1cf0fbd, 0x21b12184, 0xe9dd7404, 0x3acf8892, - 0xd94d3a5d, 0x02fdf766, 0xa26df9d7, 0xa01d4eff, 0x56ebdbf2, 0xb612b2bc, - 0x20a2b8d4, 0xf055ed19, 0x5f680c0f, 0x034e61cf, 0x989b87ca, 0xea1c5de7, - 0xf823e666, 0x52a41656, 0xe176f9b6, 0x21636ebe, 0xa6157d82, 0x8afb589c, - 0x383bd75e, 0x752c70d8, 0xdd90f29a, 0xfbc70077, 0xeb43d136, 0x7a69313a, - 0x5d4bee21, 0x49c33997, 0xdeb366fd, 0xdf7d7017, 0x53fafbee, 0x9d306f29, - 0x61f488fc, 0x3fb06981, 0x3779c233, 0x38e0ef03, 0x214b0fcd, 0x3e9573a4, - 0xa74cc11a, 0x7a851ff1, 0x805e9229, 0x4b7fd04e, 0x9399cdeb, 0x4dd2f448, - 0x3e926ff2, 0xfa7b0468, 0x28542e84, 0x8c4e89e9, 0x5173ac12, 0xee49d01a, - 0xc0f0f4d0, 0xe423287a, 0x17d9d020, 0xfe9fde38, 0xe2371ae1, 0x93dbf96d, - 0x66b7889c, 0xd0079c1d, 0x9ea8f073, 0x442604ec, 0xd2dafebb, 0xb207f910, - 0xc529cca2, 0x7172e373, 0x7ead9ebf, 0x4ddc863d, 0x74f4e5c8, 0x0ba86ec2, - 0xef9cb8d1, 0x2e7d76d5, 0x2e7d473f, 0x15a6df3f, 0xc3d52d9f, 0xf81c4ffa, - 0x8d2ce8dc, 0x3fd58fb1, 0x823f2879, 0x3aef97ae, 0x7e83cd3d, 0xb92eeb17, - 0xbea07131, 0xd2abcc50, 0xe898de91, 0x5c896adb, 0xc75d3f57, 0xa75d22e7, - 0x11e75d00, 0x768a7f5d, 0x33936cf9, 0xbb2856f9, 0x28613501, 0xc95a2f7d, - 0x14c05c7f, 0x2f32172a, 0x0c808b95, 0xc1bd8e90, 0xf7888d27, 0xd52758fb, - 0x777e503f, 0xbdf5d23a, 0xd9f91f3a, 0xd517594b, 0xb5bd672f, 0xaf37b478, - 0x1daef35f, 0xeb537d56, 0x44915393, 0x7fcd0c6f, 0xdb39cb17, 0x4e834fa5, - 0x5cec93e2, 0xe4b747c0, 0xe613227f, 0xd5677dbf, 0x3f505913, 0x85cfcf5b, - 0xa2e7e31d, 0x7de891ca, 0xe0145f03, 0x78a6dff3, 0xa4fa5f68, 0x345f0d3a, - 0x123cce3e, 0xcfbbd38c, 0x8ae6da14, 0xfbf293e0, 0xf28590ff, 0x13bdee4c, - 0xdbf97bcf, 0xef3c54a6, 0xfbd718fb, 0xaf8d4792, 0x119efaa8, 0xe2cfdfbd, - 0x85f7ec15, 0xb22fefa0, 0x17f7d119, 0x658a3812, 0xcb287603, 0xf2cbd9f1, - 0x72f6f406, 0x88d1cedd, 0x95ebd027, 0x7df70e78, 0xd632d9dc, 0x9420fa85, - 0xe1887683, 0xecd29335, 0x7617e8d2, 0x8d850129, 0x7f3e219f, 0x198ee38a, - 0xfca92ebc, 0xeed19fd0, 0xd0591930, 0xce7c465c, 0x677f2226, 0x9abf891a, - 0x3879b511, 0xb7e9d78f, 0x84ff1e0c, 0xefe1ef58, 0x841d3fb8, 0xc52cbcfd, - 0x2feb879a, 0x3cc0fc53, 0x19d24724, 0x2e4773cd, 0x3e7563e7, 0xa076e966, - 0xc1347e9d, 0x8f9e3b77, 0xfd52471a, 0xcfaec3c8, 0x667cf1f2, 0xe5506c57, - 0xaec78d33, 0x84e972e3, 0xf84419c1, 0x014b9544, 0x6f2fd609, 0xa7ff286f, - 0x371d700f, 0x8c612d98, 0xc34ab077, 0x35ff7ed9, 0xdf1f4077, 0xcae3eaa0, - 0x1a8ef8a8, 0x018a61f7, 0x3ecc57d7, 0xf141f152, 0x0e4e551d, 0xb1b0bfd2, - 0x889fc42e, 0x79c7f597, 0xce3fb9fe, 0x8d79c3a3, 0xe6328e42, 0xf8237b77, - 0xae00d6d4, 0x307fc68b, 0xff8d7cb3, 0xd9c0d560, 0xffa6bb7e, 0x4d4ed588, - 0xd6e82bbb, 0x57ade7b4, 0x6b417034, 0x517fa6b9, 0x170347bb, 0xfd34ea87, - 0x6af0ed47, 0x06ced2e0, 0xbb31ff4d, 0xb1f69a7c, 0xf69ac5e1, 0x1afd8771, - 0x6ad74278, 0x3e6bff4d, 0x27da6a08, 0xb4d7af75, 0xaad3db5f, 0xb6f72781, - 0xb94ffa6b, 0x57b4d210, 0xb4d5bfb1, 0xd75f98d7, 0xf1c62fc0, 0xeb54e778, - 0x9b9e683f, 0x81afdf6e, 0xf1e7885f, 0x23ce199a, 0xf9c5e7da, 0x278b6f06, - 0x3ee5987e, 0xffdf69a9, 0x8dcdc8c8, 0x47a12fc0, 0xb67fe474, 0xc53d71d5, - 0x1d39aa1a, 0xd7bef1c4, 0xe66a1f2b, 0xbaf7d1cb, 0x7a9d8e90, 0x75f2266b, - 0x039cf97e, 0xd0ac7640, 0xc51aa2b3, 0xc9eebb9d, 0xf48e5803, 0x6c8d5ebe, - 0xf270d253, 0x7da39600, 0x1903575f, 0xca716533, 0xf996583b, 0x70d8d6c7, - 0xbce7ab89, 0xe0c4e583, 0xb3941a8a, 0xb17e2660, 0x3e7dd608, 0x846d9238, - 0xaa652575, 0xd10f5e71, 0x1d0caaed, 0xdbaaf9f1, 0x4b37142c, 0xa322d6bf, - 0xe81cdf3e, 0xec10791a, 0xd3a7f4dc, 0x69dc62d7, 0xa1f9d83d, 0xc017b022, - 0x59f2c7ee, 0xe043ebb0, 0xbb046d1c, 0x604dcb1f, 0x73fd63f7, 0x9c23f760, - 0x7ad974fe, 0xc9d56e7c, 0x6172ea7b, 0xca0f11fc, 0xd7533456, 0x0e2b7539, - 0x0fec7ac0, 0x4b28ad1a, 0xe267ae8c, 0xec8eb09c, 0x0a8eb065, 0x51078b42, - 0x3052ecfd, 0x1c39321c, 0x2becfd07, 0x1db81a74, 0x2eb045ff, 0x97cf8b58, - 0xaedee93e, 0xb6f9f630, 0x8a1937b3, 0x5d799f61, 0x014d6db7, 0xe6799738, - 0xf1d3be02, 0x93fc602c, 0x09cd8f79, 0x97860c96, 0x48ff7a14, 0x2cee4972, - 0x16b53e46, 0xeb81947d, 0x85fd50da, 0x3ce2b3a2, 0x0839cc8f, 0x787e7eeb, - 0x23e758bc, 0xaff2aa73, 0x79cf5c66, 0xef50ef94, 0x47218cef, 0xffe853fe, - 0x2f5c7993, 0xe5159fc3, 0x08938d93, 0x949d81b3, 0xf376f20c, 0xd1a7d5a4, - 0x41ad90a7, 0xbb23e509, 0x144fcf08, 0x7823c828, 0x1e44fc4a, 0x537947b2, - 0xe733e454, 0x1f3678c1, 0xf1914ed8, 0x785ac5b1, 0x19e79c33, 0x0c7ac0c3, - 0x3282e977, 0x92f0c1ec, 0x9e605157, 0x5fb0798e, 0xb51b3780, 0x8e9165fe, - 0x9f717d91, 0x378beeba, 0xdda76829, 0xf0f5c797, 0xecbb8096, 0x7ffa0313, - 0x4027d94a, 0xfd8b9947, 0xabe40f92, 0x04abd1ad, 0xd2e19fa1, 0x2237efdf, - 0x3ac5df61, 0xfd639f51, 0x27bb089a, 0xb86b8c47, 0x19bc27a4, 0x6a4abd9a, - 0xbd06fcc4, 0x618cefe4, 0xc9e69577, 0x4666b9fc, 0x1e7786ed, 0x5f309c96, - 0xba486366, 0x4bf1c687, 0xc2dbd40a, 0xb1ab3ebc, 0xf0085a53, 0x3a4e791d, - 0xac9c7507, 0x08feb0c5, 0xa0e5d93c, 0xede78564, 0xc425068f, 0x55eadd83, - 0xdae22258, 0x52bdfc4b, 0xf57db4f0, 0x864fb2c4, 0x8abdbae1, 0xa59be717, - 0xcadf9bf2, 0x2b1f3d70, 0xbd42a9bf, 0xc33d1bf6, 0x9c6f8cfb, 0x8c5a724a, - 0xa9a5a87d, 0x973ccf5b, 0x729267f1, 0x9e93f11e, 0x2ce2ddbc, 0xf17dfe00, - 0xd6c34b36, 0x47767418, 0x75b3a71e, 0xe2deaa99, 0x73d749eb, 0xeafaa93c, - 0x1fa72b1b, 0x4cad6e55, 0xce3ab0e1, 0x24f1ecca, 0x8f5a8637, 0xf98e3dad, - 0x19bbd622, 0xfde2b1e6, 0xac2b77cc, 0x21f03788, 0xcc9f34bc, 0xe7d6e9e5, - 0x4637e4dd, 0x3e20cfd3, 0x5c9bd100, 0x1dd97486, 0x31ba066a, 0x682a33cd, - 0x5bfeda2f, 0x2472848b, 0x284ab593, 0xb5d96d47, 0xe7d46587, 0x1bd8afb2, - 0x12be8ec3, 0xa9e7a83f, 0xcf8325da, 0x2abbf9cf, 0x0c0d43b2, 0xe5c9b6e9, - 0xa9f9e1b4, 0x6474da74, 0xe22faa78, 0x3a0bd73c, 0x7aad672e, 0xd60ad3e4, - 0xeb256549, 0xd63af2a2, 0x5987a54b, 0x99ab2c65, 0xf32d6542, 0xf98d3952, - 0xad63aca9, 0x9d64ce54, 0x2eb3d654, 0xa3bfc12a, 0xe4accbd2, 0x7608de87, - 0x9973960c, 0x985bca97, 0x482dca9f, 0xfef013df, 0xdbe095a1, 0xbb952759, - 0x459dff80, 0x53311f18, 0x39e417b9, 0x3c836f96, 0xf20c32c7, 0xf8c269dc, - 0x83ca9b88, 0x43ca8501, 0x0f2a7281, 0xefd43c07, 0xca8ea068, 0x952f01e3, - 0x540d0227, 0xd47c0576, 0x316054ef, 0xfc05ef95, 0x581fbe54, 0x8107e54d, - 0x12ff9520, 0x91654f58, 0xe20ae411, 0x163ddddb, 0x8f9c9afd, 0xe8271e8d, - 0x84f34fa3, 0xfdd1ebff, 0x78f1e2f7, 0x83ba3a8e, 0x94aed5b1, 0x6e6d1e90, - 0xe504279d, 0x74937746, 0x4eeb9437, 0x64d63b70, 0xd93b244b, 0x724abed6, - 0xa4bbb8c2, 0x9c027d6e, 0x0fbcdeed, 0x4f4198e7, 0x6b65ed54, 0x7f841413, - 0xe819a4ff, 0xdfc1ab70, 0x7fda15bb, 0xcebfd2f5, 0xaece8331, 0xc7f53c48, - 0xed4c38d7, 0x66b20e93, 0xf207c02b, 0x26993f4e, 0x10a075f1, 0xc7d2fe3e, - 0xe3e4d673, 0x791cb93a, 0x368e05d5, 0x5b0f19fa, 0xdb18cfc8, 0x0eac667e, - 0x2dab49e0, 0x471fe865, 0xf5b8a3f4, 0xdba2fd50, 0x563ae7d5, 0x1e2337a4, - 0xee0a7dd6, 0x65e51389, 0xcf8c58f7, 0xbbab8e45, 0xfe99f9ba, 0xf647f332, - 0x5e332e93, 0x54e79151, 0x7403ffde, 0x86df4d1e, 0xaebf1f4b, 0x3598f8a3, - 0xf6faf515, 0x7a772e14, 0xdb43e3b3, 0x53dbdd60, 0x9f21bc05, 0x610eb5f6, - 0x8dbad7d8, 0x6fc764b9, 0x1d36f38f, 0xd1bff6c1, 0x69a0db29, 0x636fbc7b, - 0x14f9c131, 0xea9759af, 0xca5ea377, 0xb1fae049, 0x9c48f1cd, 0xffff8233, - 0xe6eee422, 0xadaebeca, 0xd7ad4fe8, 0x6e7802b1, 0x1b05fadb, 0x4bce30dc, - 0x022ec09b, 0xc2f27938, 0x9ed0050d, 0x513741bb, 0xae1e642f, 0x0b4da5e3, - 0xe128d95f, 0x0b5323b8, 0x213cdc61, 0x7586733f, 0x74095d8f, 0xc6d466de, - 0x63f5fa15, 0x8597e73e, 0xd019cc30, 0x5e2239bf, 0x1ac0d5b1, 0x4166f522, - 0x35b7973e, 0x4c34bc45, 0xd33cf1e1, 0xe3d0f888, 0x11aaffb0, 0xbe93fe3c, - 0x9ff14cd6, 0x9e7fc774, 0xe9ed0e9c, 0x4d053a1d, 0x74b6d95a, 0x9efd018d, - 0xf22758db, 0x3f8956e3, 0x76e6cc1f, 0xb92c1832, 0x1efc2273, 0xf2ca37b0, - 0xf6a7e223, 0x7184a086, 0x4b11aa8c, 0xa7378c25, 0x3093ee3b, 0xe0de91fe, - 0xe8897c93, 0xfda9f927, 0x2b9f22ae, 0x6f67d61f, 0xf735e784, 0x3c0cbeb1, - 0x81b79857, 0x566409f2, 0xecdf3916, 0x27878e22, 0xb43d2064, 0x691ad7df, - 0x9af8d15d, 0x991eaee5, 0x1ce07c3f, 0xccbfdba3, 0xfdb8e7e7, 0xf9029871, - 0x1f8f1260, 0x9339789c, 0x6dd9e5ec, 0x23f41ef1, 0xb2393c4f, 0x2aa7e096, - 0x9eff683c, 0x1a62b978, 0x9a9fb396, 0x484efd49, 0x05c630ec, 0xbb753f66, - 0x7939f58c, 0xef1c2eb0, 0x71e891b4, 0x89f753f6, 0xc5a91fe7, 0xf05d72f6, - 0x2e9fd0ef, 0x012d7e6f, 0x891505e3, 0x7961646f, 0x6abdd742, 0x837fcc3f, - 0xd51afd95, 0xda4377b5, 0x3fc1d4df, 0x6b993ce6, 0x378c78c0, 0xf3ce973f, - 0xf031e626, 0xf92f077c, 0xba3b95b7, 0x8e8b01de, 0x5bd9d75d, 0x9ebad783, - 0x5883d65d, 0x34158756, 0x61ed59a3, 0xa72c41ef, 0xd16bf975, 0xa0fba9bc, - 0xdd9620f5, 0xc45e7d23, 0xedffabff, 0x055e3796, 0xab63c478, 0xe68768ac, - 0x633dde3f, 0x0d2fc51b, 0x60a1f90c, 0x8f55bf92, 0xa6f66c04, 0xf6787ca2, - 0xfa875919, 0x8d6ae4dd, 0x4f74d843, 0x4ce30eae, 0x175a53db, 0xe20bbed3, - 0x28f1e219, 0x8ba421e8, 0x2a6f1482, 0x25f013f2, 0x829dc39d, 0x7e294d3e, - 0x8bd60a6b, 0x7efe8e7b, 0xd85e1cf1, 0x4e35afdf, 0xa55279a2, 0x08cdc4a0, - 0x42ec23b4, 0x7f33b79f, 0x96c3e206, 0xf18adfe8, 0xce2a82ad, 0xd3912cff, - 0x996f7605, 0x10508f48, 0x3fd5bd3e, 0xe6c1cf0b, 0xe01bcfeb, 0xb06a0774, - 0x25c93edf, 0x367fee98, 0x39061c4b, 0x3fc2eb43, 0x5ba4e78c, 0x51cec9d2, - 0x806b6fd7, 0x0eec22f1, 0x968dc7dc, 0xba54e781, 0xf5f620db, 0xe60b2884, - 0xf5d4f1f3, 0x7ae7cc6e, 0xd4edd61d, 0x62f47ae1, 0x5d0fb03d, 0xfa227ac4, - 0xd7fafed1, 0xd23b14cd, 0x897e6305, 0x4729cc97, 0xcea17fee, 0xd71a3713, - 0x615fd6ff, 0xe509295c, 0x67f3ac08, 0x919927fb, 0xf1f7a34f, 0xfb88be42, - 0xfe8cbd80, 0xe71f4cc3, 0xbf46e6df, 0x0d94fe84, 0x43bfdc61, 0xd45c60f6, - 0x0c926966, 0x39b5fb11, 0xd99e9eb8, 0x728fdfe8, 0x82796665, 0x8b3df482, - 0x72b5ae75, 0x0f983efe, 0xfd622beb, 0x7136167f, 0xfe7c4ec0, 0xe24ef799, - 0x67583a91, 0xcfea3155, 0xbca5eec7, 0xcc8fcd89, 0xcfeb8c3c, 0x3fb93f74, - 0x7ef40615, 0x3e7dce2d, 0x77656f8f, 0x87bc9ac8, 0xc9acbf2c, 0xac58c88b, - 0xd07a076d, 0xd95d2ac0, 0xa829d5a5, 0x2509746f, 0x9da06733, 0xf923a492, - 0x9a4a720e, 0x8d1ed31b, 0x7f812ba2, 0xcdde7cf5, 0xb373a7cf, 0xb039f859, - 0x737cc55e, 0x7aacd8a2, 0x336f304e, 0xd03279b0, 0x3ead737d, 0x8f1fa124, - 0xb232f1fd, 0x26f70d97, 0xada73e0e, 0x19cce706, 0xd41fa728, 0x2aaf2959, - 0x67a0af0a, 0x94fc99fe, 0x1da8d307, 0xc53365ea, 0xabd6233d, 0xcf6b058f, - 0x3bfd4ae3, 0x0cce7858, 0x4cfae0d7, 0xa899dcc7, 0x32973367, 0xf6e8ff3a, - 0xe7b547a2, 0x78ef7e4a, 0x50b1a38c, 0xe79c07f8, 0x5af6c74c, 0xcfa3efb4, - 0x9cbba555, 0xc2f5b161, 0x2f5c0523, 0xa72824e4, 0x90aec8ea, 0x66f04ec9, - 0xfd23c3cb, 0xb9f2efa4, 0x57e5301f, 0xec43d216, 0x1f087363, 0x3f5dc255, - 0xa8738629, 0xfba1d3ee, 0x7e3ddec2, 0x5099e9e0, 0x7bf5fd4e, 0xdfa0c74d, - 0xe32cefd4, 0xeb377eb0, 0xa081819e, 0xf90361e0, 0x7cbe6b8d, 0x440315a5, - 0x414c8dcd, 0xe3ceabbd, 0x6efae028, 0x25e4218f, 0xb32c5af9, 0xd907246d, - 0xf4114bc5, 0xe89e9002, 0x6f31b787, 0x91f92b63, 0x8612fcb6, 0xaccd3c79, - 0x97d20ef3, 0xe30c8d67, 0x383637af, 0xffb0550d, 0x869d1b1b, 0x219f78f9, - 0x23b43ab3, 0xa8506a6e, 0x8546a6fe, 0xfd799bd7, 0xd50f06dc, 0xf0f46dcf, - 0x5bd40b7a, 0xd4290f30, 0x6f718015, 0x753aa4b6, 0xe8d01f78, 0x4c17ede5, - 0xfc1c7ed4, 0x8c27cc01, 0xbc910b8f, 0xf1d1ed6f, 0x7c7f237b, 0x9ab58248, - 0x3b0ecb12, 0xe8f77f11, 0xcc175014, 0x2b332d94, 0x7836cfc0, 0x7f687a43, - 0x1032858e, 0x3617bb91, 0x7ea10b79, 0xe2b643b7, 0x7b8376fe, 0xc147f98b, - 0x9de132a5, 0xbdde00fe, 0x3af741d8, 0x3efc455b, 0xf14cc4b8, 0x2875b066, - 0x6496ccde, 0xb7863b0a, 0x86b02c77, 0x39031ed0, 0x7bd8e748, 0x00764c8f, - 0x6ea3c3c8, 0xe6768bb4, 0xca9f182b, 0xb7e5aa5c, 0xaa0b85f4, 0x6646bc68, - 0xbebd3f45, 0xbcd78f91, 0xa1d21753, 0x71b9655d, 0xf341d226, 0x3fa0a60e, - 0x53c2ecfb, 0xee10c3b5, 0x3f2e1450, 0x79a172b4, 0x9c4753e1, 0xcebf1fb8, - 0x79fd405a, 0x5fd9af1c, 0x0d2f5dbd, 0xb79d33f0, 0x0c7e4073, 0x61ca3796, - 0x5e63271c, 0xc1f182b5, 0xc627d874, 0xbc8c3bf3, 0x4ca7783e, 0x0be92df7, - 0xf475b0e5, 0x0b677f00, 0x1f23a614, 0xd17c9126, 0x9dc8d7f0, 0xc179f85a, - 0x32efc0a7, 0x9db82bee, 0xd1673e51, 0x903f6d76, 0x57943a93, 0xfadaedd9, - 0xe3fa8b5b, 0x443c1a02, 0xe7e6d9e3, 0x9f7a2f72, 0xc70afb03, 0x74bed115, - 0xd7285f7c, 0x72d8bea0, 0x1b8bea80, 0x44e9c565, 0x0a79d779, 0x53b45ff7, - 0xeb806166, 0x44cd9617, 0xa4dfaa7a, 0xf5c8f0a3, 0xc2e48bac, 0xc6adf695, - 0x19f7a23b, 0xf2efbfbd, 0xa88e5cf5, 0x6613e0f6, 0x1edb07b2, 0x9ef0e8b6, - 0x78adec15, 0x55dc2b8c, 0x402c1d54, 0x1dc8407b, 0x973d25c3, 0xa216cd27, - 0x51ed8353, 0xa1fc6477, 0x13f55465, 0xd86fd405, 0x6e3c758d, 0x968efb41, - 0xe3173f63, 0xe6d6ea4d, 0x13db5de3, 0xa63f951f, 0x729bc7cd, 0x7f2a3321, - 0x7f2a2f2c, 0x7da6946c, 0x545c75aa, 0x51b5d8fe, 0x1a3563f9, 0x967b9678, - 0xcaf5ffa6, 0x86f81a4d, 0xfd343bf2, 0xd6ee78e7, 0x7754dfb4, 0x66fda6bf, - 0x7c0d4aef, 0x6b5fc36b, 0x6be6dffa, 0xb1dfb4d6, 0xf69a27f8, 0x2d49ff68, - 0xf9701577, 0x3feed9be, 0xd06c0149, 0x3df791f7, 0x28de996a, 0x7b9e46f7, - 0xa7b70252, 0xb9fdfba2, 0x8bfbd380, 0x058f9f12, 0x1c789aed, 0xf135d8f3, - 0x854570ba, 0x71c61bb9, 0x21df951a, 0x0ee262dd, 0x6bb6bfbf, 0x3ff6d9ee, - 0xbc60fd0e, 0x1b5cc4a6, 0xff8c3bea, 0x37b940fa, 0x5f747487, 0x4abf5b61, - 0x69b83d22, 0x5cab8f15, 0xaf3c5230, 0x8eac1d7f, 0xdc46fbc6, 0xeceba96b, - 0x2da47110, 0x85424718, 0xfd4199e4, 0x7ef1c656, 0xe3574d3f, 0x371a3e8e, - 0xa418dca3, 0x7e85bcfc, 0xcdc0e309, 0x7bc5663e, 0x02cb7493, 0x069bff9a, - 0x265d9925, 0xb016da2e, 0x67cc0f33, 0x635c155f, 0x527dbd84, 0xb3d4f7d0, - 0xcfddbcf0, 0x5bd31e28, 0x1853edf0, 0xe143e98f, 0x219d7408, 0xf73f3c73, - 0x5fcfeec0, 0xe6daf981, 0x5ca197a5, 0x5acf6e8d, 0x43ebf7be, 0x6e7f6997, - 0xde1f5bd9, 0x1fe7b97b, 0x25ba75d8, 0x38c87da2, 0xf3264369, 0xe001d044, - 0x80fde62c, 0xf9f5c85c, 0xc5230af2, 0xfc01aeb1, 0xbfbe0215, 0x89cff8aa, - 0x3fb9e03b, 0x44eefb39, 0x65ea1d3b, 0x847e87ac, 0x9fe53fd7, 0x9c92fca3, - 0xa3df6051, 0x9b171dfd, 0x7215c76e, 0x8d6d95ba, 0x6a0718bd, 0xd13a344a, - 0xbb32cfcf, 0x07193eca, 0x7ee06d74, 0xfeffb475, 0xddbfbf5c, 0x9177fe49, - 0x944b2718, 0x9e7f2b7a, 0x4e4c8399, 0x3114f717, 0x6a4fa1f0, 0x655e5097, - 0x8d3f942e, 0x89fd8be4, 0xa4238a46, 0xc1dc445b, 0x171358b2, 0xfb06e350, - 0x9095ef13, 0x4bc3d3ee, 0xf18f9e28, 0x5c6f1c02, 0x11d693a1, 0x32c82f1d, - 0x86bad3e7, 0xd7f59f1e, 0xe6314827, 0x1a875a89, 0x279e889f, 0xea04f684, - 0x64f16599, 0x7bef444f, 0x79556149, 0xd7e470e1, 0x51d393de, 0x90329f7e, - 0x5e8a1c3e, 0x143ccf30, 0x42b4fe31, 0xfe63dfee, 0xe63d6478, 0xe3228787, - 0xef41ccd9, 0x2a0c102b, 0x7bb18466, 0x77ce1143, 0xc277cf94, 0x1ec9d8a0, - 0xfe87b504, 0xd7217d5f, 0x9730d303, 0x19f2386d, 0x81dbcbf7, 0x12dcb1af, - 0xd67d92b0, 0xf087fc01, 0x9527010b, 0xca9b80a1, 0xda85016d, 0x09ca07b7, - 0x21e0257e, 0x8ea04778, 0x5e02d7ca, 0x6819dfaa, 0x01e7f820, 0x819d951f, - 0x46ff54c5, 0x9bf04fc0, 0xbf04d581, 0x0160f685, 0x53d7a9c6, 0x4ad03bb9, - 0xed037bed, 0x081dbf04, 0xec0e1951, 0x8103faa0, 0x060f824e, 0x287c1176, - 0x70f82610, 0x479530e0, 0x7f545d03, 0xc101f03c, 0xc93ee337, 0x15df58ae, - 0x4f8578c0, 0xf77da276, 0x15a16fac, 0x7cfb6bed, 0x79c5159d, 0x04b74fbb, - 0x8d1d1ce3, 0xef131efc, 0x040e3123, 0xed086876, 0x67fcfb39, 0xf6a54c8e, - 0x19bed4b9, 0xc4a70487, 0xafdb82b6, 0xfa91996c, 0x0a2130d9, 0xda58eb9e, - 0xdc03d218, 0xed4f185a, 0xf93215b6, 0xfce9cf6d, 0xeedc8529, 0x336df922, - 0xa541fb70, 0x5c853583, 0xe429aede, 0x161f5cf7, 0xca4a73f1, 0x9e47ad8b, - 0xa6ed542d, 0x7f7187f5, 0x3fb079f6, 0x55bcef5c, 0xb597bc66, 0x72b3a3dd, - 0xcbdf937b, 0xb8bf603a, 0xc50f587e, 0x6e7cd985, 0xade6db2f, 0xe63975a5, - 0xd6ed48df, 0xd05347a2, 0xaff76f4f, 0x6deb439a, 0xd9ae2994, 0x82903bee, - 0x89cf6cf7, 0xf0db277c, 0x64a86f78, 0x8d9e7af0, 0xe3077f5a, 0xec03837e, - 0xec63d7a5, 0x496ed303, 0xc71130cf, 0x331cd47b, 0xe829d78e, 0xfe7121d7, - 0xc4ca0f63, 0xb0302f7f, 0x2db9e0fb, 0x5105df60, 0xb6bf540e, 0xbd55e302, - 0x289dbe85, 0x8e779f37, 0x9c03203f, 0xcfc7c75a, 0x82bf255d, 0xf79c3476, - 0xbf502de7, 0x5e4dbee1, 0x4db0ea5c, 0x6ec835ce, 0xcadff3ed, 0x4397f8c0, - 0x5a8f9ed2, 0xf9f62dbe, 0xb78f8782, 0xf14c9565, 0x378adb64, 0xbcf9075d, - 0x33ff91bb, 0xc38a3e8b, 0x5cde4c30, 0x86450ea7, 0x35fc9e63, 0xff7717ce, - 0xcd423aa6, 0xdf3a8f26, 0x6aef9c58, 0xb1e234f1, 0xc62f9b5a, 0x279286ba, - 0xbf239257, 0x81ef1429, 0x942cb164, 0xb819cf23, 0xe49e0adc, 0x052524f6, - 0x8f3c1a4d, 0xe6a02f9a, 0x0be7440f, 0x29e05efc, 0xde62c4cb, 0x4fd67ee7, - 0xd73a41bf, 0xbd1b3c17, 0x92e36794, 0x35874931, 0x7a12d819, 0xde2aa7ef, - 0x3d0626ba, 0x2853e5a8, 0x1fc100c7, 0x2e713216, 0x38f8ea9b, 0x64ce3e3a, - 0x2ae082b6, 0x4318358b, 0x33e5ab5e, 0x2b7f9c62, 0x759b74e4, 0x870dcedf, - 0x1a8f7cf0, 0x8b6a3728, 0xfd01b42e, 0x3d09e084, 0x7d4cd7c9, 0x2257d6e7, - 0x4117f5d6, 0xa18c5b9f, 0x6e87bc62, 0x504af187, 0x94bf22ae, 0xd582fc50, - 0x7d5de047, 0x1d843fee, 0x75c5fcf0, 0x3cff7429, 0xda1c6d6f, 0x4ccced47, - 0xf83360f4, 0xd046c653, 0x32e90d83, 0x8b387d06, 0xfc0e348c, 0xe226aa59, - 0xcbd70cbd, 0x60972835, 0x2616fbdd, 0x99ac3e91, 0x31acdeff, 0xc9f65700, - 0x65b2cf94, 0x9cd3cf29, 0xca3aeff4, 0x31fb7913, 0xf75df7ee, 0x9fbd2d50, - 0x67ca2194, 0xb283cfd1, 0xc2533d72, 0x0b952e70, 0x99bf142d, 0x133e417c, - 0x4851a7e9, 0x17fa3c7a, 0x6d735e3c, 0x0f79acaf, 0xb68f526d, 0x8f54603f, - 0xb7464676, 0xef3edeb6, 0x6153d3cd, 0xfca5f69e, 0xbf8bf6e1, 0x7070823b, - 0x24e28e95, 0x5064fbea, 0x4df14193, 0xf9819839, 0x8ccc1b9b, 0xbe6db9e4, - 0x60f28ad9, 0xc93c7a7f, 0x2cdbf6bf, 0xcbae8764, 0x3b438a6f, 0x556f34d9, - 0x8c23960a, 0x3b18adc1, 0x2dd5e6bd, 0x9127d937, 0x55f355bc, 0xec1cac82, - 0xdc8dbb81, 0xf73e09c8, 0xe51954f4, 0x9967cf25, 0xa796eaf4, 0xadd8f983, - 0xd4e1d695, 0xf9be4cb1, 0xba76f87e, 0xbeb896b7, 0x1da11a70, 0x7ca379e0, - 0x7b4115d7, 0x3f705a46, 0x9cb66d36, 0x6b7ca469, 0xf982324c, 0xccfd0b0d, - 0x658df588, 0x573e48e6, 0xf2fbe4f9, 0x87c63c7f, 0x0e595f87, 0x2bdc695c, - 0x3e417bf1, 0xfca19be7, 0xf210d369, 0x1f8ff554, 0x8bfce029, 0xf57a4b6c, - 0x7da6318c, 0xce22abf5, 0x9e46e567, 0x61bb32a7, 0xc3dd1d5a, 0xcc65bb04, - 0xdc517be7, 0x27a7b50b, 0x7b713dd2, 0xbde30b2e, 0x8e817041, 0xf8d27bc7, - 0xb98ded7f, 0x936a1f14, 0x3cc129fc, 0xb9f097cc, 0x01dafcf0, 0x7f308947, - 0xeb970e5b, 0xe2b7e42c, 0xb38c357d, 0xe0fd7238, 0x74b505ef, 0xa61ec8cc, - 0x789e85f8, 0x888c69cf, 0x1c5c63b7, 0xcfd117e3, 0xc2d5ee4d, 0xe1682e53, - 0xc0d0662a, 0x3c2d6635, 0x3785aad5, 0x7d3b7115, 0x3f5b5dba, 0x1d85a9c3, - 0x74e307d9, 0xc2dfcf3c, 0xf049e222, 0x447e5ef7, 0x68dd681c, 0x765f3efe, - 0xcb8a52f7, 0x78f0e5b6, 0x3695638f, 0x42c591ce, 0x732fe212, 0xd63c5469, - 0x863f66bd, 0xa30bed97, 0x5efc41e3, 0xa9a1f002, 0x7c8a3147, 0x9e68eaf0, - 0xd23dde87, 0xce08bdb7, 0x5f0c60b3, 0x4d1dabc7, 0xdac53f74, 0x5caf88d3, - 0xb0695f22, 0xe88a7cbe, 0xf90f1d40, 0x7fb11822, 0xf84887e4, 0x37be51a1, - 0x8be41e70, 0x2cfea460, 0xfbd036e9, 0xa1be62ab, 0xcfe543f8, 0xa28f7172, - 0x89f4dde6, 0x9bbcd4b1, 0x705f2255, 0x4ebe5457, 0x1936a39f, 0xaebee7fd, - 0xf8b1f195, 0x682ef910, 0xe5887ce2, 0x837f9106, 0xe22c187c, 0xa6f5887c, - 0x637856ef, 0x050b8bd9, 0x63bfdc5d, 0x224f86c9, 0x73acb7f6, 0xbe5e0685, - 0x910de1eb, 0xe3f751f9, 0xbf08303f, 0xed7e519e, 0x2f9db152, 0x2bcbff4f, - 0x48cd0ccd, 0xcf2807df, 0x319c1596, 0x5ea77bf2, 0x42eb9e23, 0xcc99ff61, - 0x2fd1f2b3, 0xf2e211db, 0x37889d6c, 0x33155b34, 0x3b9981c6, 0x50c71355, - 0x4b4d11e3, 0xd854b65c, 0x7c7f7247, 0x7ca56bc1, 0x14f9e1dc, 0xf1aa48df, - 0x32c6cedc, 0x9c6453d6, 0xdd62066b, 0xc056c18e, 0xd957f9e9, 0xc0c74133, - 0xf8174dbe, 0xb0fdc97b, 0x8f2467ec, 0xea68e42e, 0xa39c44db, 0x0b2dbf9f, - 0x8b3e70aa, 0xb0fb49db, 0x1e1aff31, 0xd1c6d417, 0xe73de24c, 0x343be3c1, - 0x7e226df5, 0xb5f1e572, 0x85d33971, 0x2fc621bc, 0x1adf1a8c, 0x7181fc73, - 0xabbdf1b5, 0x714f37b8, 0x2e3a184f, 0xe9cdd236, 0xdfdd9d69, 0x83317185, - 0x06667fe0, 0xf288993a, 0xe3e9ff80, 0xc1ae7e79, 0x198f8da1, 0xfa0baf30, - 0x98b8973f, 0x3efa8ae4, 0x0599fdb5, 0x27cbca12, 0xa4e8fdf0, 0x5a24f2c1, - 0xde44d88e, 0x811cb47c, 0xd37034f9, 0x36cf5cc3, 0xe50f8a4b, 0xfe7ef473, - 0x7587f17f, 0xc8bbe389, 0x778eceae, 0x0f632e9a, 0x638205b7, 0xf175b9f1, - 0x0778c5fe, 0x918ef77e, 0xe3944f69, 0xf88ceb7b, 0x298ec56c, 0xb60f3173, - 0x13ebf04d, 0xa7a23a69, 0xb7d3dbf4, 0x29e823ea, 0xa173e8dd, 0x13ae9c3d, - 0x87f85ff9, 0xd227b471, 0x318c6db7, 0xa9d76abf, 0xd601adb0, 0x6d8e7111, - 0x9fee9ec2, 0xadcc8eef, 0xd27188fa, 0x34b1be4d, 0xa3fe7f5f, 0x87e5af98, - 0xc459b7cd, 0x6cf9d4c3, 0x67f76a77, 0x7f69fa33, 0xd487a136, 0xfee336f9, - 0x15d5f062, 0x75fe13e7, 0x69777cff, 0xf93367f7, 0xf5367f69, 0x7cea1b3b, - 0x3e6c3f2d, 0x76cfe0bb, 0x3d97def1, 0x64377f9e, 0x9a23f7a8, 0xbdccf3fb, - 0xed2f9466, 0xe850bc6a, 0xfa5173bb, 0x3be849ae, 0x6973f9f5, 0x3dff14b9, - 0x7326f877, 0xfa873d2c, 0x933b098d, 0x09933b09, 0xd9e1133b, 0x0d57a735, - 0xbbfc7a07, 0x95cf371d, 0xbecfaf41, 0x1cf8f4ff, 0xf1d9df80, 0xe832b98b, - 0x9eafd9a9, 0x1e0b337e, 0xfbdbfe29, 0xe9f4fc38, 0x5bb4073e, 0xadcccf82, - 0x18693805, 0xbaeacfd7, 0xb97779d5, 0x7cb95db9, 0x6f8f1e75, 0x3d459c82, - 0x67e39cd6, 0xcafc7f18, 0x1f349bd1, 0xeecf2ffa, 0x03105f4d, 0x7cb96a2f, - 0x1e7f2175, 0x9889c0ad, 0xaf48c6cf, 0xc7bea8dd, 0x8f7da752, 0x23692925, - 0x2c7187d9, 0x96394564, 0xfbd0f660, 0x7316d797, 0x533370bd, 0xe15fb81a, - 0x1c79102c, 0x4dcbdef4, 0x6b5c62e5, 0xfdb12fe5, 0x09e79d66, 0x79ff77f4, - 0x68e1bcd2, 0x7379ab3e, 0x3bde06a3, 0xde7dfedd, 0xb1fd9e4f, 0x64e56dc4, - 0x36998f1e, 0x7bdfc9ca, 0xa22b888b, 0x3e143c5d, 0xff73753f, 0x1e9f007e, - 0x0f54cf8e, 0x37b5a7c7, 0xff9c0d69, 0xf4de94f2, 0xc34f89c7, 0x0835f131, - 0xfbf851af, 0x7ea99b93, 0x88ed1ea0, 0xc55be12b, 0xd85f9aab, 0xc80b392c, - 0x9a19675e, 0x14c660fc, 0x1e7bac67, 0x3d48cfa4, 0x197bb46b, 0x3486a3da, - 0xeff98dc5, 0xc7d17fcd, 0x1573dbcc, 0x525ef88b, 0x367de53c, 0x1fc91927, - 0x93349fdf, 0xb659fc61, 0xd4bc234c, 0x3e51d526, 0xeb187ea6, 0x3a357f44, - 0x7c9f5d0f, 0xe909e53b, 0x4061e86d, 0xecc79fd9, 0xe95f2331, 0x5d92563f, - 0x99570048, 0x295f2e87, 0x26753d0f, 0x324f43cf, 0xd85e313a, 0x998c689e, - 0x9badfe87, 0x71fb5dfb, 0x1fb8697f, 0x886eff23, 0xe56c97d8, 0x9f58eef7, - 0xab46f500, 0x5dfc518f, 0x615bffec, 0x4dfda907, 0xf9433f56, 0x4e2a37a0, - 0xa9f45fb4, 0x77e07f5c, 0xe231dc5b, 0x0dbb5f28, 0xa3fdfcf4, 0x99cf5cac, - 0xfb3eddb9, 0x27dfb137, 0x44962b28, 0xdd3624bc, 0x3737450d, 0x9dde78ea, - 0x2d7397ca, 0x9c07ca46, 0xf7d3b16b, 0x2102e66c, 0xf446a4f6, 0xfe56eebf, - 0xd8acb53e, 0x7b7e9e91, 0xfe5f94ed, 0x00b5e196, 0x66a7db97, 0xc2bde818, - 0x28f31253, 0x5df383a9, 0xa994debd, 0xea1bccb8, 0x7645af4f, 0xc8c3182c, - 0xc1757a4e, 0x4e95ad43, 0x8aea8ff2, 0x737d9e91, 0x770fa2a6, 0x77d8c363, - 0x04f2ffb1, 0xfbd5cf2e, 0xfc09e5a5, 0x646bde7d, 0xffec6cdf, 0x4917c555, - 0x725f48d5, 0x2bae0e6f, 0x33dd3fa2, 0x5b9ff445, 0xcffa813c, 0xf5ddafe6, - 0xce3977d2, 0xc8f99da5, 0xec7ce8c7, 0xf429ecb1, 0xbde458b7, 0xe81f9086, - 0xa3d64577, 0xce22c5bf, 0x6e505a53, 0x4f218eeb, 0x3ec332d4, 0xa042e46e, - 0xb18c8cd7, 0xcff5aa54, 0xa175f47a, 0x90fce718, 0xec1fe738, 0x6ac3b4f7, - 0x3df80e27, 0x843cefe0, 0xe172f8f8, 0xb0f1f4a9, 0xbf6a07a5, 0x6ec7bf26, - 0x16ceffec, 0xb00371f9, 0x2db3bef6, 0xdf8c5bd0, 0x87886019, 0x8bf91189, - 0x25f6bf62, 0xefd0526b, 0x20f4b381, 0xbc0476dd, 0x030d6b23, 0xe42cbfcf, - 0xd2160b08, 0x2eb106f3, 0x0ceb5a47, 0x2c38bb8c, 0x6073ca3a, 0x6791aacc, - 0xa6536a73, 0xbb0ba1a6, 0x2716299c, 0xe45df7fa, 0xfbe06417, 0x7c9f180d, - 0xf78636e7, 0x9d69595f, 0xfd75da12, 0xc6f788f3, 0xe17b8957, 0xed2d5f3e, - 0xefd6c327, 0x5ff23197, 0x507382d3, 0xc33df56e, 0x92f19457, 0xc691ddb6, - 0x5dee1ff3, 0x02721f18, 0xed2d67bd, 0xb04f4fc2, 0x30f8700c, 0xa9719fa6, - 0x7282d5d9, 0x140957e6, 0xe7b7d677, 0xfbc820b3, 0x1bfbecb0, 0xf9c877c2, - 0x6c4f2e90, 0xb65b9e16, 0xb9ec9e28, 0x0675a976, 0xe8f731f9, 0xd178ac58, - 0xa7ee62ce, 0x2b628ffc, 0x4fb5cfbf, 0x1f63f4e4, 0xb8e1723f, 0x77ffe7ab, - 0x49f99e84, 0x7fde93b2, 0x4da3ed52, 0x8e47f843, 0x5f213a91, 0xf8115e84, - 0x199f3333, 0x792f45f9, 0xc774b079, 0x96bdaf6b, 0x5b53e8ce, 0x841b4748, - 0x138ea3fd, 0xc6a21f9f, 0xf243c578, 0xb87ab252, 0xedfab0be, 0x75af3841, - 0xce63e9df, 0xfba085ff, 0xd90fd935, 0xd3ad7fb1, 0xfa32c6e7, 0x9c96983d, - 0x3e78dd7b, 0xe9fb332d, 0x96baec95, 0x61dfce33, 0x28f0563e, 0x9fd837cf, - 0xefc3685d, 0x1b0e5941, 0xe265d364, 0x27d046f1, 0x19d8cbce, 0xdeaf9146, - 0x99e78072, 0xbaca58b6, 0xc5a1af30, 0x6a465692, 0x56f3c2d8, 0xcb16fed5, - 0x1607d221, 0x5adfdf85, 0xb8487f50, 0x0947c04c, 0xe110ebae, 0x5077ed43, - 0x128b5dc8, 0x5a5ef866, 0xfd4ad29c, 0x83d7b2cc, 0x34e6ca79, 0x6644f746, - 0xe217f02b, 0xccc75f35, 0xbec9f431, 0x5a4fae62, 0xaabaca4a, 0x7e327d69, - 0xd8b58eb9, 0xe7a4eccb, 0x7cf0ef11, 0xcf968673, 0x577813bf, 0xf91669c7, - 0x4eae77b4, 0xc38ed609, 0x1bf79338, 0xcb16e7a4, 0xf5107302, 0xcbf8e25a, - 0x391a678e, 0xd7fb78d4, 0x43bef18a, 0x2c4fae79, 0x0678e2b3, 0x8d15f7c6, - 0x9c62e1f7, 0x7bfbd5ff, 0x47bd2cc0, 0x581d304d, 0x7deb1ed8, 0x13f3feac, - 0xcfd1f2f7, 0xbc7960fd, 0x02871b56, 0x091eec79, 0x72565afb, 0xd53550e6, - 0x0bd3f8f0, 0xfd519fc2, 0xf6317492, 0xbf7f120b, 0x2bc5283f, 0xe10c5df4, - 0x69c7a4a7, 0x3ef030f1, 0x6f873f2d, 0xde1e781a, 0x7c4c6937, 0xd7cb4e87, - 0x38ff1cdf, 0x059f9345, 0x7131ec7c, 0xde23c63f, 0x3888f5a7, 0x6f18c21d, - 0x049d17a0, 0x89c7f7ff, 0xc33f9c1b, 0x4099acef, 0x5c60eb8e, 0xfa27e1c9, - 0x5dba3936, 0xe239efc8, 0x78d10ffb, 0x2e48c9fe, 0x7a47a5af, 0x51af785c, - 0x119bd69b, 0x7c5fdf8b, 0xee0642f8, 0xfd19c5e7, 0xdf743b79, 0xe769e2f4, - 0xcbc402e6, 0x6ffbed11, 0x474df8ea, 0x22f8a7ce, 0xe5c0a5fd, 0x3a4b2fdf, - 0xd92571b3, 0xddb80b8d, 0x7dfa7ff8, 0x73e617b3, 0xa497753b, 0x084fcf95, - 0xfc141cb9, 0xd320bb60, 0x2aee43f7, 0x3a40adf2, 0x0bac936a, 0x3ce72e50, - 0x9af2f3cc, 0xb3d55b1e, 0xb47f0628, 0xd5fdf28c, 0xbabf08c8, 0xe491bd7c, - 0x3725b35e, 0x28f772f9, 0x9fbb9f43, 0xde7a94e4, 0x79988f55, 0xdb8f8abe, - 0x7bbee9d1, 0x3a260f29, 0x7ea8653f, 0x449d23d5, 0x137f6a0f, 0xc5f28f8e, - 0x15c52372, 0x818fa1ce, 0xb72b3b71, 0x59d7a233, 0xc098c889, 0x7d0663f1, - 0x49607499, 0x106b8e1c, 0x6a0bdcfe, 0xcca1a45c, 0xde7889ec, 0xb9995b70, - 0x9a4e823a, 0x8e0fcf19, 0x2337ff1e, 0xac22fb55, 0xa80c63b1, 0x94c6317f, - 0x97ed9f26, 0xf278643b, 0x0395b4fc, 0x0ee3cc7c, 0xc5a3e743, 0x232dbe71, - 0xf30dac7b, 0x5e0ec0d2, 0x0460b0d3, 0xf64db7e2, 0x3c0368bd, 0xa2687ef4, - 0x0bdfea3c, 0x7c16ed3e, 0x05f9d43a, 0xd23001d9, 0x1d9c7b18, 0x80e297c4, - 0x2327c64e, 0xebe7345f, 0xf63142ea, 0xf3ec5c79, 0x7878f632, 0xc7b3f7e4, - 0x1afe890f, 0x6ded1c7b, 0x46fdd44f, 0xb6768c24, 0x7e3d8627, 0x05f11242, - 0xc2742791, 0x0dd5dce0, 0x39313978, 0x5697be99, 0x5defc090, 0x527fa04e, - 0xabc87e06, 0x7ed1f3a7, 0x7ff52d99, 0x43f84917, 0x47f0608c, 0x62f905fe, - 0xb6bff30e, 0xe23e2248, 0x1b7835f7, 0x73e57e9f, 0xd19236de, 0xf9c036ba, - 0xdb46fde1, 0x6233f9c5, 0x8ea467dd, 0x5037fd52, 0x13ef1165, 0x889d3c33, - 0xf741acfb, 0x72f75174, 0x9fd36d78, 0xdc1fac77, 0xed7286ff, 0x8b86d9bd, - 0x5a622e3c, 0x4b8f42c2, 0x6daa9798, 0x10cea9bf, 0xb9a82f7d, 0x6bd9bb4f, - 0x7d0f5e88, 0xd621d417, 0x1f71dd9b, 0xcd4fbfdd, 0xa644f9e6, 0x04e28c65, - 0xa66df7d1, 0x3d1e5db1, 0x8c0dcfda, 0x38e8fdec, 0x52a9e639, 0xb181b0fc, - 0x79e5122d, 0x7973df6b, 0xfe73fea6, 0x3ad6947d, 0x760ec79c, 0xd1d3da10, - 0xf7a849ef, 0x51f7ea5a, 0xdfab3c55, 0x4dbf4a8f, 0xc163eb47, 0xc6aed429, - 0xb87bf1fd, 0xf911e955, 0x7f582be4, 0x2b7f7a7f, 0x9bdf7b18, 0xcf29eadb, - 0x7fbc7320, 0xb29a186c, 0xc8784614, 0x6fc8c85a, 0xf2683c00, 0xdbd94c09, - 0x16e79f69, 0x224c3633, 0x33da683c, 0xfdd3d340, 0x7e6d42c0, 0x0353ec01, - 0x57abfb47, 0xd94d53f2, 0xf39597f9, 0x9a638a57, 0x94e4bdc4, 0x97fbe251, - 0xed14aca5, 0x9edbf4a2, 0x0738f3a1, 0x5f7181e7, 0xdd629c74, 0xf1826e3b, - 0x77fc8fd1, 0xe2cd2fc1, 0xaefd5b6e, 0xf4c8f30f, 0xce549b1e, 0xf30d2cd7, - 0x12e97bf2, 0x8a6e7c46, 0x8fcc6667, 0x1e4c2a97, 0x04c9bbc4, 0x32596c30, - 0xd4067332, 0x7b3c45eb, 0x8464c48d, 0xf3315599, 0x5dfaa3f8, 0x577d10a1, - 0xd479a868, 0x20b22bef, 0x679d4e7f, 0x2ef577d0, 0x7bf93cf3, 0x6be7e8d6, - 0xcea99e29, 0x87fe143f, 0xbfde8efa, 0x8137bcd5, 0x441d53c7, 0xf4038daf, - 0x417cf04a, 0xca3cf88f, 0x66d5bb85, 0xfa29577b, 0x4c1e670f, 0x114a3650, - 0xd2ce08fb, 0x7e03eff3, 0xd7faf1bf, 0xbc927761, 0x1897dfef, 0x8beefbef, - 0xdae422fe, 0x09597c3a, 0x191a5ef3, 0xfba431e5, 0x29973faa, 0xa0f600ff, - 0xdf111391, 0xd6f18049, 0x1fefce3d, 0x3e77e336, 0xc0e7fef0, 0x13edfe40, - 0xd1f76c16, 0xbcd43677, 0x5da3cc5c, 0x3ef0325b, 0x837df472, 0x89c611bd, - 0x99b26f98, 0x9f401305, 0x0531f4a4, 0xb9ecf3bf, 0x03a65468, 0xa07d6c7e, - 0x93bf0150, 0xa5ee8999, 0x337ead2a, 0x0ae10eff, 0xef676916, 0xefa56e97, - 0x64bf86bd, 0x3e14bf94, 0xc3ee88cf, 0x70c4c39f, 0xddf8ff2e, 0xcbe47afb, - 0x7a5d7da9, 0xfb93f3d4, 0xf67fa4fc, 0xed3d4fd9, 0x9962e7e2, 0x751f9111, - 0xcf545b1d, 0x979f8ae9, 0x5f27ea2c, 0xfdf86a30, 0x46a35eda, 0x5b17c81e, - 0x65fd46be, 0x67aa89ea, 0xe3e33fd3, 0x2dde28f9, 0x53edb5db, 0xdbd03e44, - 0xc35fdf2a, 0xbc73a1ae, 0xcf331698, 0xd5dce06e, 0x71e26e73, 0x79c7c674, - 0x9ff7946e, 0xff404d46, 0xe87147c0, 0xd82fc464, 0xdd952917, 0x58798ecc, - 0x8e994ce5, 0xf3b2bd72, 0xe487a41d, 0x3c0f3cb3, 0x5ffdfc7a, 0x7e8595be, - 0x9dc99ec3, 0xed2f6859, 0x3d15f2f9, 0xd3d5578e, 0x193eb0cb, 0x58a41e4a, - 0x10aa784c, 0xcf5033b4, 0xf59144e3, 0xe74a9eb4, 0xcfe4e565, 0x871a4e50, - 0xd933df6e, 0x87e4c2c2, 0x3da02675, 0xfe7c7cc7, 0x57cab364, 0x70972fec, - 0x9f81845e, 0x52ea54f6, 0x7b9f616a, 0x6c15919e, 0x46f3d3dc, 0xe7bfce02, - 0x7acd39ec, 0xf322fe98, 0x5afbac45, 0x2b53ee71, 0x7efec97b, 0xf92bac4a, - 0xa1c52f6c, 0x30de9553, 0xc3d4dbea, 0x37fefa7a, 0xc8bcf0b3, 0x38a14c61, - 0xfc5eba9a, 0xd73e2a6e, 0x88de7282, 0x5632b3fb, 0x287eec28, 0x55832a33, - 0xcc9a8f98, 0x6b484a76, 0x417d2b53, 0xa5e4e7a4, 0xad939e9c, 0xbf18c3fe, - 0xa3af5e4f, 0x59f24538, 0xcbf406df, 0x0565cb92, 0xf84ae4c9, 0xb7f310ec, - 0xf9d4f98a, 0xa88cf5d5, 0x7ee84bf4, 0x62e3b324, 0x132aaefe, 0xcc5abf8e, - 0x59eb14ef, 0x2c3be8c5, 0x55ad67c9, 0x83272fe8, 0x33df419d, 0x9a79e2b8, - 0xb745f335, 0x99d94f27, 0xb1e0e745, 0xe30ad91e, 0x365b64a5, 0xceb94154, - 0x32ff23a1, 0x3c5187a9, 0x9d27a93d, 0x4f527de4, 0x8a2728a1, 0x0f4269fa, - 0xd4933970, 0xaf2d50f3, 0xa4d2a16f, 0x3f8717ca, 0xda98fb8c, 0x717cb8cb, - 0x98be4978, 0x517cb8d2, 0x9556b8e9, 0x325acc2b, 0x0ff7ea1f, 0x06b5acff, - 0x73f77b9e, 0xbbe5fefe, 0xbcbe5cd9, 0xfbf725fb, 0xd3bf694d, 0x42aa5ca3, - 0x4dfa05c3, 0x33edc0bb, 0xbaab1f95, 0x48113625, 0xe7839a63, 0xc8ba1f87, - 0xd9843b9f, 0x63af00d5, 0x9529c912, 0xdd056b6e, 0x83eab3ae, 0x81fed849, - 0x3477de89, 0x98e5ce39, 0x83fe1ec1, 0x7c41f7ae, 0x33f7f8ef, 0x415def7a, - 0x437e82f5, 0x9a2e494b, 0xe4396c84, 0x3e416058, 0xae487984, 0xe918721e, - 0x3a080ebc, 0xe9af673e, 0x5b3fc308, 0x69fcdfcc, 0xc1ffd43e, 0x9340eb9e, - 0x1e973d4c, 0x885f2f41, 0xe82b3bf3, 0x7bdd29a6, 0xfc04c953, 0xcd1e62fe, - 0x0dfece7b, 0xdcb27fbd, 0xc69f1ff6, 0x3aa72efa, 0x4f7cfa8e, 0xcf19a568, - 0x1f9bd0f5, 0xabb4409f, 0x7b235fe3, 0x7ee3e4ef, 0xd0f89a33, 0x78cf3b12, - 0xadf3fc90, 0x8b7f9688, 0xc80f864a, 0x91667abf, 0xe7121e79, 0x1e4259eb, - 0xddb8554d, 0xe7e56f5e, 0x5fb25f55, 0x8b8afea6, 0xd2af55f6, 0x5ae4f28d, - 0xf29b7fe4, 0x7d4bd124, 0xbd97a73e, 0x0a0f9e82, 0x63ecce7c, 0xed97e89d, - 0x196e982f, 0xe23ef80b, 0x1cff13d2, 0x52c6bb19, 0x291dcf06, 0x024bf095, - 0xd6c97a6c, 0xcf00a9b5, 0xa7a22452, 0x1dad92fa, 0x967fd04d, 0x03a94135, - 0xb3f9e8f8, 0x0eaf3416, 0x9784bc05, 0xe3f872e9, 0x1b9e1754, 0xcaccd3c7, - 0x4ffe8cb0, 0x8cbf63bd, 0xc46df6fa, 0x2ee311ab, 0x7567c11e, 0x6a571f04, - 0x238fb82c, 0x2f2126a5, 0x5e51e33d, 0xd537cace, 0x7c75a18f, 0x1a4c6c7d, - 0x506f77be, 0xa73c95f8, 0x7e82c9ff, 0x6b27ccea, 0xccdfa053, 0xd7196692, - 0x912cd47b, 0xd7da3cfc, 0xc793f944, 0xd2ac393b, 0x74073d2d, 0x5b6fbc79, - 0x6fb61273, 0xd53e4897, 0xe21d2f2b, 0xa7d38fea, 0x0b0f7e3a, 0x3077e1b6, - 0xb7af29cf, 0xb1f53e60, 0xcccf05be, 0x7f1c3c01, 0xb8c43f53, 0xc0ad1f4d, - 0x244cdf71, 0x356d9e3a, 0x8cb1f469, 0x5e84694e, 0xd36f1ead, 0x0d4af5c0, - 0x29cfd3c5, 0x7806e592, 0xad5df3de, 0xd191397b, 0xbd77da52, 0xe14c7be8, - 0xa1cc797c, 0xd63cbe23, 0x8a9cb8f7, 0xfb4659f0, 0xde769991, 0xb21a92fa, - 0x5b29ceaf, 0x826744f5, 0x54f1d50f, 0x4f8a3e3a, 0x9ced1e23, 0x6df68fff, - 0x1dbd20b3, 0xe323bf75, 0x89675d39, 0xa1d0571a, 0x5df0dfaa, 0xda9fa471, - 0x7ef3fb51, 0x3851eb86, 0xd7946bfe, 0xd57d238f, 0xa7a2643b, 0x9afecaa3, - 0x27bf8614, 0xffecd262, 0x9ac91dfe, 0xda7597f1, 0x5db47034, 0xdbfdcfb5, - 0x0ec4cba7, 0xd847a466, 0x3ec2f947, 0xe0771fd2, 0x1768aefa, 0xf7e8eb29, - 0x45d90649, 0x8a2edcf9, 0xbe5487b6, 0xb889d66e, 0x65c78eac, 0x58dff9a3, - 0xf1eec3fa, 0x8e492ad8, 0xc65bbfbc, 0xbe9073ba, 0x8612a3e6, 0x75d01ef1, - 0x15fc23a7, 0x078b6deb, 0xccad7c39, 0xbfbf6976, 0x3f37bfca, 0x1e77d4be, - 0x367495e5, 0x6561df4c, 0x07e518ab, 0x9e786be8, 0xad665e11, 0x258bd488, - 0x8d2df1fd, 0xd84ba45d, 0xac78859b, 0xf1e46b38, 0x38e89e8f, 0x851fea97, - 0xae2bf225, 0x93ea2e52, 0xe67bb8f9, 0x7f6778f0, 0x938f3379, 0xe5fc0915, - 0x5d691a94, 0xdcf7808a, 0xb59efb16, 0x41fa54a4, 0x07dfa2f9, 0xef8029df, - 0x61e690af, 0xb1553d9e, 0xca5291d7, 0x9777b5e3, 0xa14af278, 0x15f12a2c, - 0x3d5e2296, 0x77d35f60, 0x9f643dc5, 0x33bce3a9, 0xfd16e3ca, 0xbcc96146, - 0xee8f0edc, 0x6863ed07, 0xe3d8869c, 0x7a38fb40, 0xf6ec6e7e, 0xfc39b843, - 0x30fb237d, 0x0c0643d2, 0x52f2a664, 0x16e5e32a, 0x8846aefa, 0x1e0de7fb, - 0x9146f3d2, 0x103788af, 0xf4c7fc91, 0x1cbe34f5, 0x58f7419e, 0x8325d82d, - 0x7691f9fb, 0x6a84ac94, 0x6aade322, 0xdf94a8b9, 0x1528ce73, 0x604cf3ef, - 0xa8afc813, 0xea3cfcbc, 0xc3cd43f3, 0xc85765ec, 0x63f35e7b, 0xc3fa49d3, - 0xa55f27e4, 0x4a0e607d, 0x1f39df91, 0x4a89bf6a, 0xc28a1c94, 0x5cf350d3, - 0x22dc79ed, 0xd76af6e8, 0xcc7a655d, 0x2ed1f94e, 0x056b07ce, 0xd5dbf57d, - 0xbe3f1e3f, 0xfe861f3f, 0xfefbd9ca, 0x4a7ef893, 0x37a56842, 0x145e7ec6, - 0xe531f9fb, 0xce70d3c1, 0xfba18c1b, 0x0799ded1, 0xd20263a7, 0xf1f2c77b, - 0x9eb005f0, 0x2dfcc537, 0x6feb9596, 0x1c5b4785, 0x1ef998ba, 0x7a78fe6f, - 0xd93f0da2, 0xdce395ff, 0xa7206dfb, 0xd07d1e5b, 0x7581b0ac, 0x15d96b30, - 0xe347f9ce, 0x6d5d7513, 0x625e305b, 0xf7aabd4d, 0xaf5c5a14, 0x697de024, - 0x764de7ed, 0xb4460efc, 0x43c6a03d, 0xc6a5bd54, 0xa4bb544d, 0x1fe3c1c2, - 0x7bfced33, 0x69f6153d, 0xb20fdfa4, 0xaff21aae, 0x226d3b30, 0x19fd0ab1, - 0xe4fb5add, 0x4657bf3a, 0x9eda2a3b, 0x45334da8, 0x7abd07d9, 0x1715df94, - 0xfe54fdb5, 0xc454acf8, 0x17795451, 0xcf9a4765, 0xbb40499f, 0x670bedeb, - 0x8d142e28, 0x5c2eeb9f, 0xaebd9fde, 0x83f74f5d, 0xb7ad71d1, 0xfdd2e42f, - 0x1baf11a0, 0xcccad4c1, 0x808cc43f, 0x6b7b4c97, 0x18ec1195, 0xf82983a3, - 0x58fc36dd, 0x8d0dc633, 0x7c9c7817, 0xd7fb9d84, 0x2fc18b89, 0x95335185, - 0x78c17da0, 0xef48ce7c, 0xef5d99d3, 0x09bdbd91, 0x9e2186ea, 0xa6199ec7, - 0x5307118b, 0xc08a63cf, 0xb7e66eef, 0x4d81efe3, 0xf7f78bb1, 0x59db462e, - 0xa22d3cfc, 0x2d62e27f, 0x3ce22d3e, 0x435b8327, 0xd3ec79df, 0xe7116f3e, - 0xfb1a596b, 0x63a3ec1c, 0x7aa2439f, 0xc5b6130e, 0x596c39e1, 0x758a4dbc, - 0x2f8b990e, 0x845b0e7f, 0xefd2a95f, 0xb204acb4, 0xe8a6f7af, 0x7b41fbe8, - 0xcb59c313, 0xb2fdfe31, 0xaccfde99, 0xb4367110, 0x6b9f10a4, 0x84bf97b7, - 0xa371db71, 0x7b8e74f5, 0xbcffd125, 0x60feff8e, 0x1fea78cf, 0xf883b327, - 0xfb0780bb, 0x1bbbe9aa, 0xd3bbfcd1, 0x33dd007a, 0x3db9ceb6, 0x839c016b, - 0x9980fb25, 0xcf839bfb, 0x4a3fef07, 0x7b4bbe05, 0xa654b9f8, 0xbda3d49d, - 0xec66f25e, 0x8fe351f3, 0x3a9da47b, 0xaa362b20, 0x98fc8baf, 0xeca33b91, - 0x642db3e9, 0x47c65b67, 0x39c0f7d5, 0x9f8ebdd1, 0xa1d916ec, 0x87ebaf3d, - 0x114aa738, 0x7d7f3087, 0xfb65e28a, 0x7e714efa, 0x25c6d1e9, 0xfe5df727, - 0xe7135e9c, 0xa1c453b4, 0x00e22e7e, 0x7e7fc29d, 0xf2a4e023, 0xea9b80cd, - 0x04280adf, 0x0b940aef, 0x77cfc161, 0x47cb3e56, 0x84aaaf17, 0xcf47edfb, - 0x7f7dbf73, 0xbe83a862, 0x42de74ef, 0xbda417df, 0xdbbf144d, 0x2c727c07, - 0x1fbf49ce, 0x4cdb3478, 0xa5a3b3f1, 0x8a7bfbbf, 0xd16b7cbb, 0xc70bb8f1, - 0xeb4e7ab3, 0x6f184e70, 0xee8b855d, 0x47e036a5, 0xeeffa114, 0xffbe8932, - 0x040e1b34, 0x3a5445ef, 0xf169f537, 0x65ff0f59, 0x1ddff195, 0x617f42c8, - 0xa4e88b8c, 0x2273ef42, 0x4fba373e, 0x571e5f91, 0x871beed8, 0x7af18071, - 0x14fbbe26, 0x3bac4534, 0xe0426f0e, 0x44895379, 0x0a1a73df, 0x86e5d1bf, - 0xa32fae54, 0x3475ffeb, 0xdd1b83d7, 0x773ce8db, 0x50b2ba3b, 0xf913efaf, - 0x2964b310, 0x285fbf48, 0x1cb1dd77, 0x65915bf6, 0xc011bb1f, 0x6853a32d, - 0x4f4afbfd, 0xd8f81c53, 0x21c65785, 0x76b31dfd, 0x79ce305a, 0x53dfc9cc, - 0xf9951387, 0xf29db77b, 0xa4f2312d, 0xe958f2d5, 0x95fdfa22, 0xef7cfc7f, - 0xdf7cd1da, 0x0af5524c, 0xfb815b8c, 0xdef9424d, 0xc3f902b2, 0xfc83b998, - 0xaa73e8cc, 0x88b35f70, 0xfc64f3de, 0xb6bf4f7b, 0x3f782c86, 0x0267ed1c, - 0xff426c7d, 0x3d04f778, 0x5eadaf7d, 0xe782e7e6, 0x1fa4e788, 0x997e13a3, - 0x65667c76, 0xc0fa633e, 0xde1d6079, 0xf13ad0d7, 0xadefaa3e, 0xf86292bf, - 0xc9d683b5, 0xf9589efc, 0xcdcfd1b0, 0x9a20b276, 0x1615b386, 0x709fa176, - 0x99c69f30, 0xcce3e56d, 0x9b7c7112, 0x1759ffa0, 0x81df9475, 0xcf80d6f4, - 0x7927cc95, 0x50f5cc72, 0xb7ac1d57, 0x41c6ce1e, 0x569346fe, 0x5b39090e, - 0xf745525f, 0x07dcc7bd, 0xbfbea3c6, 0xe1e574be, 0x9fc22732, 0xb74154d4, - 0xd52fa529, 0x945a5d20, 0x4c2f8a2e, 0x5d74cb76, 0x36b97d78, 0x17afd14e, - 0xb44bf4a3, 0x928fa8be, 0x54f7113b, 0xf9c4434e, 0x4b9f72cf, 0xab83a488, - 0x2f1ccbc7, 0xd67baf7e, 0x1da71e05, 0xe9f7978c, 0x7803a573, 0xd8ef3e89, - 0xa73e8978, 0xeaad3c01, 0x8c1dcbaa, 0xbf6f155f, 0x1ac9792e, 0x8d1be799, - 0xaf8a1fb7, 0x4156d1e6, 0x579e5caf, 0x3b7dbe08, 0xb771443b, 0xeff94bb7, - 0xff731d4b, 0xb3bfe296, 0x0d63a858, 0xcbe045ca, 0xe8f94239, 0x344ce423, - 0xf4f8061e, 0xbf2e283f, 0x28b7f3fb, 0x21caaa2e, 0xea25f213, 0xea1fc113, - 0x1f9099b9, 0xf02f6f91, 0x2d5e87ef, 0x457ca87f, 0x383f21eb, 0x1fcc8fa4, - 0x5fc5dffc, 0x18cd717b, 0x52167617, 0xd1cab83c, 0xac7bc7a5, 0x3dd250c9, - 0xd27f8892, 0xf5919c3a, 0x591c6e3c, 0xa12f714f, 0xa6b8d4f7, 0xbb3ebeda, - 0x5518412b, 0xc24d47a4, 0xc4fd51de, 0x64538e7d, 0x54faaa7f, 0x57fef716, - 0x08f74fab, 0xfb543a7d, 0x79bb73de, 0x43cbe7dc, 0x1c800f3d, 0xa46f9c9f, - 0x0e4cb8ef, 0xa3dfcc3f, 0xfe498470, 0x9137746f, 0x69fb0c1f, 0xe604a346, - 0xf3e64475, 0xf3bee5a9, 0xefd60a6d, 0x0af4bb95, 0x16ff07f5, 0x568603e0, - 0x0d869dfa, 0x137d738f, 0xd651f457, 0xba83dee5, 0xe6994fb3, 0x61efc24a, - 0xdf835f6f, 0x8c2a0b01, 0xb598ebbe, 0xee458bb4, 0xdc31a5f7, 0xff9c9daf, - 0x68071dd6, 0x69ea1fdd, 0x035768dd, 0x9d964f9d, 0xcfe7050e, 0xfd23dbf6, - 0xf7d97dec, 0xb7009dda, 0x086c697c, 0xa3c37ad1, 0xecf3017e, 0x078d5733, - 0x73ed8d4b, 0x0bf5181f, 0x7346c7c0, 0xa3cc04d5, 0xdbdfb6ac, 0xdae51f3e, - 0x60265bd9, 0xbcec1bfc, 0x83b7d456, 0xcdb7dff6, 0x5d3bbf8c, 0xd69f78ed, - 0xabafa231, 0x5abfbf06, 0x48f7e0ed, 0x87bed1be, 0x7b404cc6, 0x73c1ec39, - 0x0c9f344f, 0x164cdd22, 0x2f1765eb, 0xbd41fc51, 0x9e73d997, 0xf8ff47d3, - 0x8fb80f40, 0x455cbf6b, 0x7db922f7, 0xa026f9ba, 0x3c7d75d5, 0xf1db0c7f, - 0xbf58e07b, 0x001d8628, 0x4be75cf3, 0xcaebf3c6, 0xde8637ba, 0x36fbedcd, - 0xf6e783e0, 0x44bc7064, 0xc31e6fb7, 0xafb882ed, 0x9272cfde, 0x7ff5c03d, - 0xf312c0b0, 0xa9b7553b, 0x3b1ad2fa, 0x552d450f, 0x23daa579, 0x21b35f80, - 0xc69bbf02, 0x7cfdff70, 0xf103a7a9, 0x7fe77df7, 0xe50b710a, 0xf6cf52f1, - 0xae91c331, 0x97ad5f04, 0xee01c663, 0xc5a3f31c, 0x13416e2b, 0x73beabef, - 0x86e96fe9, 0x7441dba6, 0xf8e95065, 0xffe3a221, 0xe27bf48b, 0x20efd0fb, - 0x14fe7479, 0xd347c3dd, 0x03bf4ab1, 0x9be6c874, 0x79e80692, 0x7ec1ba28, - 0xe806928b, 0xfb7ea87a, 0x931fbfce, 0xe9c607de, 0xabdd2cbd, 0xd059b7f4, - 0x540f7a91, 0xfd79ce29, 0xfeec8cd7, 0xf5463da3, 0x7e35c677, 0xca3fe811, - 0x72b0aea3, 0x37b47fb9, 0x3d19fb97, 0x9a9fba66, 0xbe295ee9, 0x235d0dbb, - 0xf211adc6, 0x75dba67e, 0xeaaf3959, 0xfddf550b, 0x43777c4f, 0x00800098, - 0x00000000, 0x00088b1f, 0x00000000, 0x7dedff00, 0xc754740b, 0xeebd6095, - 0x91a93fd7, 0x16883e9e, 0xc085a092, 0xeb404616, 0x7d3d05ff, 0xa71f3210, - 0x900b18c1, 0x04e08b4c, 0x60dd491b, 0x9e3d90e2, 0x123231a1, 0x1f62cd9f, - 0xbd6678cc, 0x8c030d39, 0xc077b19d, 0x0b611c56, 0x3837e2dc, 0x71c6ec4b, - 0x3c4c9c18, 0x6c0843c2, 0xc718d36c, 0xbc4ab243, 0x0f7adef7, 0x0b756bf5, - 0xcceb43db, 0x40e75764, 0xaabd5ea9, 0xfeeb75ba, 0x7ad3d56f, 0xcecc6333, - 0x53f817d8, 0x08acbc3d, 0x65cb191a, 0xfc05f3f4, 0xebf2e2db, 0xdf632b25, - 0xb4cbeeb9, 0x2c93f943, 0x1e670adf, 0x355faf63, 0xb188acca, 0xf6e3a9ae, - 0xfa87b3ea, 0x8c08758f, 0x127b4315, 0xef768674, 0x0077c154, 0x27d1311e, - 0x7d1e9d2e, 0xfd4c9fde, 0x8795cdae, 0x9d32fab3, 0xaf7a6863, 0x59b18d3e, - 0xca0e9bf8, 0x332d9320, 0x5aedcca0, 0xcca012c7, 0x9636f92c, 0xb12e624c, - 0xf2933184, 0x6bcae99e, 0x39f015df, 0xfe831993, 0x56f595eb, 0x0d5d7f30, - 0xcccf31c0, 0x3889f1bc, 0xc9c9d37a, 0x97cd5ed0, 0xd769e30a, 0xfe9fde1d, - 0xe4f329a5, 0x572e3630, 0xfbcdf5a0, 0xf04cf98c, 0xeb6e756b, 0xe7033602, - 0xd1cc7187, 0x1e60a9c7, 0x1d01e999, 0x2adb5ee5, 0xaa6b3fe8, 0xafe5e1c9, - 0x6cdef84b, 0x3e1bdfc6, 0x4ac67ace, 0xe2d9c686, 0x54fac809, 0x4c498ec6, - 0x6f5b2fe9, 0xf8e767c1, 0xb2857ac3, 0xcd6e533e, 0xebcbc455, 0x07e1c792, - 0x860f6778, 0xcb1d6f8d, 0x55633a58, 0x8b9f699f, 0x387d6d0e, 0x58fb305c, - 0x5f4fe5fa, 0x33467cc0, 0x5d398fc7, 0x5d79f847, 0x3e90fa32, 0xeed4ae2a, - 0x4b189362, 0xfc87ec96, 0x992adcf0, 0x36053e1d, 0x7e53f633, 0x0402b8af, - 0xc29fed04, 0x738014bf, 0x5aef6e9b, 0x16ddd027, 0xa21f4c6c, 0x4c0b2597, - 0x2e96381a, 0x9bd4d449, 0xea69c79a, 0xd44f57cb, 0xdb736fec, 0x43fa9add, - 0xea6a661b, 0x354a27ae, 0xd59d55f5, 0xef56f19a, 0xff69ab9c, 0x686feed6, - 0x7f9e6bea, 0x747f5350, 0xe911caff, 0x885f1a22, 0x89e991b6, 0xd23b0579, - 0x3a4d88bf, 0x9cc5cffc, 0xf7f7a3d3, 0x7ec27f21, 0xb7af6ebd, 0xd5fe82ad, - 0xe78d3f57, 0xc5f4b4fd, 0xf90072bc, 0x17d956a3, 0x402bc798, 0xad528d7b, - 0xf445be95, 0x4536635e, 0xee951be4, 0x11560ab6, 0xda66afc7, 0x6db0aafd, - 0x7e47aebd, 0xebd01a2e, 0x3759be61, 0x2157fcb5, 0xc706fc35, 0xc7afcc67, - 0xa5cb84f5, 0x9318eeff, 0x609e397a, 0xfc017fb5, 0x8cc9acc4, 0xa3c74795, - 0x5db7a74a, 0x6f5f6337, 0xeafccadd, 0xa0582b7a, 0xda3ee90e, 0xfc3b67ba, - 0x516b927a, 0x5ebe1dd6, 0x6feffe15, 0xef815f86, 0xf323ff5f, 0xdb1013ed, - 0xe6fc88b2, 0xcfeb5ddf, 0x02402bb5, 0x7a1527bc, 0x278291a8, 0x0e908b12, - 0x83650398, 0x51f99071, 0xc133d40e, 0x9652846f, 0x38af041c, 0x3034ef68, - 0x7e71eb2a, 0xa6861071, 0x35eb45d2, 0x288dca0e, 0xa92c456f, 0xebc79cee, - 0x875e068e, 0xd52ea8f7, 0x3ee7baf2, 0xea92875e, 0x43af275e, 0x5aefaa3f, - 0xb8cef58c, 0x014489c0, 0x5825beeb, 0x5a1e0e37, 0x05ff4bca, 0xe4994a81, - 0x5de83896, 0xec7ea7a7, 0x3707af22, 0xf2d0fa71, 0xf65e3183, 0x5f19b3f9, - 0x813f3c3d, 0xfdc24dbf, 0x006fd75c, 0x828ad43c, 0xd5ef0ec3, 0x3f87320c, - 0xe4d5f715, 0xe097d990, 0x3133a033, 0x8ccf886d, 0x4ab1982c, 0x0f793e20, - 0xedcaadf1, 0xe968e3e1, 0x5af51eab, 0xfc3bec01, 0xe51931be, 0xfaa7a730, - 0x2c12e0b2, 0xd013f9f1, 0xfc327b3e, 0x1f4e1e4b, 0x32a25c2a, 0x5fb5a55f, - 0x32b6aa8f, 0x59b72618, 0x8559d117, 0xd92c9d79, 0x716dcb87, 0x2e2fe550, - 0x56e1c22f, 0x1f39ade5, 0xfb1a6cf8, 0xb9967c3a, 0xaeb36a0a, 0xd9f0abbe, - 0x933e30ba, 0x8496f7ad, 0x321019f0, 0xb7d9f0d3, 0x276e9e89, 0x83094e5f, - 0x4f182675, 0x23e80cf6, 0xc05499ca, 0x3e244243, 0xb21bfb9b, 0x97c8a21f, - 0x5817f037, 0x987e6e67, 0x5cf4519c, 0xfee7aab5, 0xdda2b3a8, 0x117a67e2, - 0xc87c70cb, 0xd2313b2c, 0xbe3cb573, 0x6bba0609, 0x90f80ea8, 0x63be810f, - 0x06dc151f, 0xcec99bcf, 0x805ab862, 0x31e2aac7, 0x71ad6e8c, 0xec909d2f, - 0xecf505bc, 0x4e6e8518, 0xdf11a766, 0xc7bd76c3, 0xb59de442, 0x01f1cbe8, - 0xc70937cd, 0xbf226673, 0xc6db40d5, 0x33fde182, 0x99f00fb1, 0x3e7cc835, - 0x08eacf78, 0x46af5808, 0xf48d9efd, 0xfe51eacf, 0xe8095f57, 0xe5a5ea25, - 0x00745b97, 0xa4013fbf, 0x517c8b57, 0x642e9c30, 0x7ee3d3e6, 0xaffdd57c, - 0x90341fb6, 0xffdb0ebc, 0xcfb0419a, 0xd5394e00, 0x1afa20e4, 0xc8cf6464, - 0x48c7c14e, 0xbc21acbe, 0xade3f6a8, 0x176826f6, 0x622e91e8, 0xf640b37b, - 0xb36ca7d0, 0xf305f381, 0x867a55fa, 0x30afcbe7, 0x34ed1139, 0x7ed4f3cb, - 0xfa23136c, 0x3c97b6a8, 0xb8476755, 0x44cc7606, 0x0abd24b8, 0xc7153f97, - 0x70e260bd, 0x7f08daf9, 0xe4fe0ad5, 0x43331d41, 0x694fbfbb, 0xff5fa30f, - 0xfcd3b720, 0x702bc44f, 0x43f0c8dd, 0x4ed007bf, 0xe5689306, 0x43ff03dd, - 0x69dcf784, 0x01df3f77, 0xf028ae5d, 0x6e856ffc, 0x5124da3f, 0xf5cd3eb9, - 0xc7a07cfd, 0x7c6e917f, 0x0fc866e2, 0xd5f74439, 0x9027cff6, 0xd9f1521e, - 0x10f48637, 0xe8f84dc2, 0xdb8344b3, 0x387510aa, 0xe5bf0abc, 0x2a57c88c, - 0x577c2a9c, 0x0bab7a7c, 0xe7b37bc6, 0xf61c135f, 0x454bf821, 0xfb847ee7, - 0x674fc1cd, 0x92ef88b8, 0x34667635, 0xfc5266f9, 0x964ca488, 0x3ea2a62b, - 0x85cc7388, 0x74cb8c75, 0x364cbad1, 0x02fd1da3, 0xf393274b, 0x82734860, - 0xf7f08ccf, 0xd2ec37a7, 0xa9d6fb43, 0xfbc13322, 0x36bcb35b, 0x09fea75a, - 0x9399eb86, 0xd60361e9, 0x6577f3e8, 0x9c11293e, 0xbf475083, 0xa2f1c6c7, - 0xf8f4689f, 0xc75fb9e0, 0xc10a1cd6, 0xee02c1cb, 0xe7cd9d8f, 0x1e17dae5, - 0x842976d9, 0xad0fda3f, 0xbdddd4d3, 0x2976dbdf, 0x106ede54, 0x3697dc44, - 0xd9db8e85, 0x5ff404c0, 0xe13b455a, 0x903743a1, 0x2c6bf586, 0xae0a7e78, - 0x008fe70f, 0x5be73fff, 0xd2ff3d62, 0x8ff650a9, 0xff69fee1, 0x0df91f24, - 0x2b1ffcea, 0x5f38ffeb, 0xa6387317, 0xb3ba1e01, 0x9f70c5bf, 0x3f7c6c6a, - 0x7a72504d, 0xf54372e6, 0x739e8677, 0x3ea55179, 0x73de3a0f, 0x1ce91d12, - 0x994c76a8, 0x7de911f6, 0x71bbd227, 0x48b5bea8, 0xf08be8d7, 0x220573fe, - 0x16c07bc1, 0xa15b3db9, 0x5c139d97, 0xdfe8d9dd, 0x6c73ab3f, 0xcbce2586, - 0xe51e3adc, 0x7adb56fd, 0xe2e653a2, 0x38c058eb, 0xf4cbcebf, 0xd1e81978, - 0x82b7fe79, 0x8dd62a42, 0xf886c2cc, 0xe70bf557, 0x01d13e89, 0xd7f2bbfd, - 0x5ddd7199, 0x1c66f5b6, 0x82d684cf, 0xea3c386e, 0xe6ec0fba, 0xf4cbcef3, - 0xb2e9e089, 0xc57bb9b9, 0xa33fa801, 0xee5e7bac, 0x6aaf6a3a, 0x09149ff4, - 0x4367e07f, 0xf568e8dd, 0x87263ce2, 0x3ac246bd, 0xb2c66c73, 0xec89784f, - 0x0dbf5513, 0x9dad4fe9, 0x91bafa72, 0x15d763e4, 0xf244cf9d, 0x07305e53, - 0xbcaf9fde, 0x7b720d6d, 0xa3bf6bbe, 0x1cf7c45f, 0xf3e3f902, 0x764dbf73, - 0x2e77359d, 0x56b3e7b7, 0x98549179, 0x3fa1f04f, 0x5bc54f31, 0x195f569e, - 0xa0b7171d, 0xd4de30fa, 0x2c59d1ea, 0x2abe90c0, 0x70f3fcc2, 0x40bb3b7d, - 0x5972d7b1, 0x2d2bda31, 0xc863df26, 0x420d960f, 0xe2a1c23a, 0x8e814575, - 0x7c8620e8, 0x942667b0, 0xb465d95d, 0xd3ccfaaf, 0x5f980417, 0x4366df17, - 0x8cdbd0be, 0xb31bc47e, 0xa80d1f8a, 0xffc24df3, 0xb7b22533, 0x2f848eb0, - 0xfc79397d, 0x86c7966e, 0xb032eceb, 0xa7f248a6, 0xfdf380b6, 0x927e5907, - 0x8ddad10f, 0x7bd2041b, 0x66377caa, 0xc237d932, 0x5c8cdb78, 0xd25f80ce, - 0x3ebf402b, 0xffa017a4, 0xf7b35a17, 0x7ba205e9, 0xadf1e519, 0x12efb152, - 0xfe1fb90b, 0xca898166, 0x547eca93, 0xc336717f, 0xaffc8235, 0x8430f2aa, - 0xc7ca94df, 0xf1f26533, 0x732f224c, 0x2e3f7195, 0x5cdc7ce2, 0x5fb97b14, - 0xfb7a339a, 0x8d7a4b1c, 0x90285287, 0x98dd79e8, 0xc52e4987, 0xa3396f12, - 0x5da33788, 0xa7073fa1, 0x73fdb513, 0xaaffde45, 0xb274e620, 0xe51472b4, - 0xa4e92c41, 0xde83cfe2, 0x79ff97cf, 0x68da47ec, 0x99a3e3ae, 0xe042d4f2, - 0x2e9cbf93, 0x96e583df, 0xbbdb23d7, 0x772f63f3, 0x72801ed3, 0x37df04f1, - 0x79b3e923, 0xfb97b185, 0x48bed14b, 0xf845f6e1, 0x3d15cbfc, 0xd2794b14, - 0x11b36504, 0xff011fd6, 0xfcc28e8f, 0xef5073cb, 0xe5817b72, 0x0fa4b99e, - 0x67e1dfb1, 0x3ec42eb2, 0x1c147b06, 0x0543b441, 0xeddd9239, 0x2d7efd8d, - 0x643f487d, 0x5c61ccaf, 0x2ff3a81f, 0x7af8e12c, 0xb0e0147a, 0x25eade00, - 0xc29baf6e, 0xbfcb50e0, 0x7dbd8c2d, 0xe043e92a, 0x1fbb0548, 0x444205cb, - 0xd0a7af7b, 0x1a7e7318, 0xe2d9780b, 0xe4918d60, 0xefd8c9c9, 0xca0d9a4b, - 0xd3cee9aa, 0x4b96d728, 0x5c60e787, 0x1ff8fbf9, 0x79d21be6, 0xc1a561be, - 0xaeff45e5, 0xbc3bb24b, 0xac478c76, 0x7ccafaa2, 0x52af43bb, 0x94dfb63e, - 0x6c05db7c, 0xe57d51d7, 0xda1f24ef, 0xd617dfc3, 0xf1c6c99d, 0xfb1deb36, - 0x959dc618, 0xe78d837c, 0x9e36ac1b, 0x3c6d109f, 0x29b560ef, 0xcf1b0779, - 0x4a6d583b, 0xf3c6c1de, 0x929b560e, 0xbcf1b077, 0xe4a6d583, 0xef3c6c1d, - 0x7929b560, 0x3bcf1b07, 0xde6a6d58, 0x1538d3c1, 0x9e3691e3, 0x78dab077, - 0xe36ac1de, 0x97980779, 0x3c6c1de7, 0xf17000ef, 0x722d83bc, 0x943ac1de, - 0xf1ff2077, 0x67a49618, 0x547f5fb8, 0x7b06cfa9, 0x786334dd, 0xe76ab55e, - 0x17182dfe, 0xfc7209ab, 0x5e783955, 0x77b414d9, 0x457e300a, 0x04dfb066, - 0x114565fe, 0xb0d5f0c3, 0x13f3c3f9, 0xbde7d9dd, 0xb0a3fa02, 0x03bc2997, - 0x18ea29e5, 0xfe7c3f7f, 0x3b577161, 0x65d6e78f, 0x3bf08b7e, 0x78482cbb, - 0x8718e7c3, 0x13f253ad, 0xffad56b5, 0xb2e67f2a, 0x995f71f9, 0xf80899d4, - 0xbb6d4590, 0x8c2ff988, 0xd7f15ebb, 0x6ab7dc61, 0x15771b50, 0xb8d41b33, - 0x844bcf3c, 0xe1df39c1, 0x6b045f1c, 0x2a7f016a, 0xc1cfe601, 0x53ae15a4, - 0xa45e7c12, 0x881bddb7, 0x453bbcbe, 0xaa6814c7, 0x9e606404, 0x6a2012a5, - 0xc654d286, 0xf24cd2ac, 0xfe9d389b, 0xf1bdd4d7, 0x030f28d9, 0x6c04467a, - 0xf9a83c23, 0xbf580485, 0x2bfc8334, 0x332aeff2, 0x3a47bffd, 0xcc82eb50, - 0x5d8238f3, 0x2f80cd62, 0x5c266ef9, 0xceab9336, 0x45eb6f90, 0x73c335e6, - 0x9b37e941, 0x2d4e2905, 0x76f28933, 0x6541ccb5, 0x695774d1, 0xcea3f011, - 0x7ae175ec, 0x0966ecaa, 0xee3d85f9, 0xf148db3c, 0x32e97ae4, 0xf60049e0, - 0x48da62f8, 0x2ec88a76, 0x451cf8ab, 0x2f1f48bb, 0xadc92278, 0x61ebd88a, - 0x0a2a83b2, 0x2dc7c919, 0x7cfcb22c, 0xcfcb84ac, 0xdf5d4b37, 0xfbd73c44, - 0x878fd516, 0xd0be8f2e, 0x6d9b794a, 0x5bc2f161, 0x6f628afd, 0x90e72447, - 0xe901b93d, 0x8f04f17a, 0x1688e10d, 0xf62a78c7, 0x1b49ecf0, 0x767baec1, - 0xd45aec14, 0x2aecb743, 0xfa9399fb, 0xb1ca3b50, 0xd0ba4f0e, 0x9092baef, - 0xc3ddaa38, 0x8d67143c, 0x6979af1c, 0x9920e214, 0xfe13bfa8, 0xea639d0b, - 0x87fb023a, 0x54bcfbe5, 0x428ef8e1, 0x634be387, 0xa0d317cf, 0x613e27d4, - 0x771b8d0b, 0x970e0459, 0xf5c0d041, 0xfdff62b9, 0x78f624a0, 0x7d72812a, - 0xf22efca9, 0xf974d561, 0x7caa5867, 0xbae1df3b, 0x2d29fc40, 0xf9024faa, - 0x767f66bc, 0x0689ea01, 0x2ae35edb, 0x52d5f780, 0x3a22fdf9, 0x5b1ff46f, - 0x1eb16e1e, 0xf7bc478f, 0xa3cb22b9, 0xc50911bb, 0x28de4fe4, 0x67e4fee2, - 0xfe288784, 0x638bafe4, 0xea7b2fbe, 0xc9fc8673, 0x5b1ffe70, 0x639de3cc, - 0x068e0147, 0xf1465728, 0xc28ca6eb, 0xbf5a8dfc, 0x443ebf6e, 0x854110ce, - 0xdc6c69e6, 0xfc1163af, 0xba35973d, 0x147b37bf, 0xf310b1d6, 0xf591b571, - 0x31c57dda, 0x7e96aff7, 0x3307ca03, 0xd0a9fd5b, 0x6f30bcc4, 0xb2be50da, - 0x0fafd5c9, 0x383f738d, 0xe537e0e1, 0xb37e7008, 0xf272e638, 0xf91e9c7c, - 0xe119bd75, 0x7e066ae9, 0x255fb08d, 0x9bffdc25, 0x9611e13b, 0x3a637688, - 0xe411f743, 0x3637cf09, 0x83637e29, 0x2a767fa2, 0x2c53d472, 0xe52ce952, - 0xe851b9f5, 0xfbcad7fa, 0xb69c4a8d, 0x2bf26251, 0xec7ff491, 0x38fce6e9, - 0x71c6e728, 0xf30def38, 0xf453dfcf, 0xd3d89ec4, 0xa00c9ecf, 0x91b5b993, - 0xf63075f1, 0x0274b174, 0xf6d4bfcc, 0xf8901cf4, 0x0d9b2fb0, 0x2e9c5f94, - 0xef0c58bf, 0x57c28b6d, 0x69782b9f, 0xb03a3e86, 0x34a05bfb, 0x9010f942, - 0xfa405481, 0x6fec55ed, 0x14308e01, 0xf1de0420, 0x3af4e7e8, 0xce7c1ee4, - 0x7fe46d5c, 0xca1bc884, 0x3999569f, 0x83a774df, 0x0efe88ff, 0x9339d333, - 0x9fcf20ae, 0xfcf26576, 0x6a3c3868, 0x456ff4fe, 0x71cf198f, 0xc4166577, - 0xebddf285, 0x6f26989b, 0xe78575dc, 0x8a4fc185, 0xc949fad3, 0x8f8527e4, - 0x74b9909f, 0x247fa85e, 0x021fdcc8, 0x5c50267f, 0xa917e43c, 0x7c98cffe, - 0x7ff15cf9, 0xcd1dfd02, 0x4947119f, 0x07308b0f, 0x74ddff3e, 0x8f10dff9, - 0x1fd3d023, 0x9fd3d0a3, 0x347fdfb0, 0x11cc627a, 0xf0cc68b7, 0x1eb2bb71, - 0x708eb5b7, 0xd321203f, 0x54ce9119, 0x9b7a02fa, 0xe8763250, 0xb4f3217d, - 0x4b136f4a, 0xbd3ebf8a, 0xf0bec05d, 0xafe1acef, 0xd149d6ec, 0x7ab59dfb, - 0xfa0f28cc, 0xf19bd732, 0x99d4c49e, 0x6bce072e, 0x006c9911, 0x3e5cbb38, - 0x007b9e33, 0x64bf2f3b, 0xcdc1bc84, 0x7e3f2e22, 0xdcffecad, 0x2aff9c09, - 0x7dbe0b96, 0x6c4d7fc0, 0x4df70197, 0x4958ff7d, 0x7b88fdec, 0x35ee4872, - 0xf7208c96, 0xe2f8565e, 0x2b5f0573, 0xe729d6da, 0xfb445899, 0xfdec5567, - 0x942b348c, 0x45d75273, 0x745be3a4, 0x2285e787, 0xe21467ac, 0xe4c7e7e0, - 0xcd4c3ce0, 0xfc406d2b, 0xf1c4563e, 0x7dfecd17, 0xb3fc146a, 0x4ad70089, - 0xfd0199f6, 0xc7ff5969, 0x11e748ac, 0x39d9158e, 0x0390069c, 0x5995df80, - 0xfc31b7ba, 0xb5a495d9, 0x67f7d487, 0x67aefe2b, 0x5267e414, 0xf1c3ce0e, - 0x4c0e7e1a, 0x3ec5cf2d, 0x88b4b01e, 0x80ffb9fb, 0x73fc0efc, 0xe358a4a8, - 0x64a8fee7, 0xb5f73f64, 0x1adc8f7f, 0xcba8e850, 0x7d9ed911, 0x40fbf621, - 0xdd60e0e7, 0xb9157cef, 0xaa6f6e11, 0xdbd89ee5, 0x7a59697b, 0xd1c3879c, - 0x24e7b4c8, 0x28dff16e, 0x8f5d2de0, 0x77e968f3, 0x5ffae325, 0x1a58c385, - 0xe78c73f3, 0xff31e867, 0x7d79f9c3, 0x94be2ba9, 0x198f36ec, 0x07d837f5, - 0xb95f6714, 0xcd1f2539, 0x6b67d82a, 0x93be96a9, 0xefa6474a, 0x403bd2e4, - 0xfc9caadf, 0x534c6117, 0xa899bca8, 0xa5699bc8, 0x29afdfb1, 0x8e48af18, - 0x632baf2c, 0x73dbe71f, 0x79744e77, 0xfb379eac, 0x4f1b4147, 0x8f25bd6e, - 0x69474e63, 0x7921faa9, 0x7087eaac, 0x5e868d3c, 0x0bd10c48, 0xcce4510d, - 0x3631c068, 0x9db51f04, 0x98afe502, 0xc0a6f98d, 0x39d89daf, 0x96c7dee4, - 0x4f138851, 0xc87f8d0f, 0xa047af60, 0xb1a5dde3, 0xbca37fcf, 0xdb7c37e9, - 0x47f9d236, 0x28c5d5a3, 0x3173623f, 0xb19fec3b, 0xf6f295b3, 0x94ad05c6, - 0x029d6687, 0xf498fde5, 0xab79f92e, 0x30a7de6c, 0x9e5c367d, 0x5e398d6c, - 0x97d8728b, 0x28c537f6, 0xf8ebcd7e, 0x37f93a4a, 0x153ca3af, 0xb347ee24, - 0xf74ecc0d, 0xb97cafa4, 0x202f58fb, 0x9a2f3012, 0x763ee8c4, 0x7ac7e1a7, - 0x051b47cc, 0xe65cfe3e, 0x974ff9e7, 0xf0a3fc77, 0x31a0e59e, 0x7f543b7f, - 0xfb4d9a51, 0xcfe569de, 0xf39bf6bb, 0x9ea5849f, 0xc19e15b6, 0xa753e1f3, - 0xec1c5327, 0x6b8f03c5, 0xbc5aecec, 0xdf7e80c7, 0x7e861e0b, 0x35d329a2, - 0x9c3b2471, 0xae927f31, 0xa89a508c, 0xfa5e7a94, 0xf86d9d05, 0xf7f73bfb, - 0xbd67e848, 0x724cc078, 0x9e81ea7f, 0xe32155f8, 0x3e719627, 0xfe3d06b6, - 0x35af0019, 0x093273d3, 0xf92b1def, 0xce799173, 0x632bc2d4, 0x0f9d00a4, - 0x6b5791df, 0x2ebba50e, 0x794cd6a9, 0x639d5ce4, 0xfceb1d8a, 0xf4fc431c, - 0x4082fdda, 0x112edd7e, 0xe19aef50, 0xec7a86ba, 0xc3eb890d, 0x496b53a9, - 0xe72a75ab, 0x2de4761e, 0xc7ef8039, 0xf1a7af4f, 0x7b64593b, 0xe5c658cc, - 0x99068bf0, 0x80f17de6, 0x55c8e748, 0x7c69debc, 0x0f30cbd6, 0xa6dea3e0, - 0xa7d87ba7, 0xe5114e8d, 0x8134e9d0, 0xdf2d82ed, 0xee8578e9, 0x0288ec99, - 0xb94a2fef, 0xa96cca9f, 0xf7a77f44, 0x748f2e77, 0xbfa55f7e, 0xa96433c9, - 0x49c0ed0c, 0xff94269e, 0x36e4b6cc, 0xdf24f17c, 0xe68743bf, 0xcffc03cf, - 0x227fc17d, 0x6b21f70e, 0xf75c78cf, 0x6a76a507, 0x1f0f45bf, 0xb0f442bd, - 0xe3efc8c5, 0x8e717578, 0x858eb003, 0xcf1101d6, 0x8352184f, 0x2a6de794, - 0x8b74f2e3, 0x81630fca, 0x7d3de01f, 0xc507bf06, 0xcea9da26, 0x84270726, - 0x559ea3de, 0x0597aca6, 0xc2f9f132, 0xd83777f8, 0xf6158c1d, 0xb08b37a6, - 0xef8985fe, 0x7a86c86e, 0x5e78ef49, 0xb3f778cf, 0xb2b1896c, 0x9f5e0cde, - 0x9367eef6, 0x9bd15ea0, 0x3095ebc9, 0x9bb078d4, 0xbd9ab37a, 0xa4be3879, - 0x0f15bf19, 0xfd7f1472, 0x45d26f52, 0x28355f8c, 0x031f87eb, 0xfbece3ce, - 0xe2ef3a47, 0x78fd5b34, 0x86c9832e, 0x3419f8b0, 0x6077dc85, 0xff2409a9, - 0xf30bfbd4, 0xf63f7f45, 0x84fd99d7, 0x2759bbdf, 0xad8073d9, 0x7e145fdd, - 0x5c2e7b79, 0xc8d96dee, 0x8c4e785c, 0xef0966b1, 0xd64c0833, 0x78e3c17d, - 0x855f9c4e, 0x187f9d47, 0xc8b5b05c, 0x3d70439f, 0x70a8e34f, 0x7937cb5d, - 0x6b7ade51, 0x0427ae59, 0xe084d74f, 0x456c180f, 0x0f1dacda, 0x1b5d3ee1, - 0x40209c13, 0x1b7cb93d, 0xb1b5dbed, 0x8e081fc1, 0xef81ba90, 0x096f5b63, - 0x289763ed, 0x9b9d21b7, 0x216ed68c, 0xb8eeb191, 0xe60c1984, 0xe5d631d9, - 0x406e7bc5, 0xd8ef7477, 0x1c74659b, 0x8beb3800, 0xc7a1f9b4, 0x83fb3a15, - 0x98e60f22, 0x01ce7976, 0x047bba5d, 0xdc70f786, 0xa88c3783, 0x5df616ff, - 0xa4be6234, 0x11a2e7a3, 0xeb03bee9, 0xf3c74e30, 0x6ff988c6, 0xbd5eb963, - 0x91e74a2f, 0x4f1c4bd6, 0x7aeeb2a7, 0xe9e0152a, 0xbdd02d58, 0x9247f5bc, - 0x7d7d60e6, 0xb192ae2b, 0xe78755e5, 0x38b4b920, 0x72c29ffb, 0x95381b25, - 0xccb4240a, 0x10f667a5, 0x4d62b93d, 0xe887b33c, 0x8a4f16c9, 0x1772bea6, - 0x280cceec, 0xfa686637, 0xeafee531, 0x83f43632, 0x949a98e7, 0xdb665c7d, - 0xeeb8c019, 0x3bc19732, 0xc2de3210, 0x3262cdbe, 0x1c11edc2, 0xcbd28d74, - 0xe0ad3fcf, 0x1c52842b, 0xf7cf1f7a, 0xefc40af4, 0xba7a6d1d, 0xcbdcd3c7, - 0x35e6aeed, 0x202ecf82, 0x0dbdf81e, 0xed40af77, 0xeba7deee, 0x1bef1193, - 0x47000f00, 0x7d84f8da, 0x9347112c, 0x4ad5dce9, 0xdf775605, 0xb38e0339, - 0xdd023be2, 0x9bbf5567, 0xb2bfc2a0, 0x91ce91a9, 0xa45e7c01, 0x4d9d754f, - 0x5ce947f6, 0x9789cad5, 0x6187a80d, 0x3406977d, 0x5bd6d4f8, 0xcafada3c, - 0xd1fada8d, 0xf29ee532, 0xf90d3634, 0x209978e9, 0xb52439e2, 0xf9d651fe, - 0xe75ef1b7, 0x0a79d16e, 0xe8cdb3e9, 0x7efa819f, 0xbaa2e8b7, 0x3bcf0eda, - 0xf89df118, 0xb1f100e1, 0xc5b9fc40, 0xf8354b20, 0x8176973d, 0xb60576e8, - 0x0f67f3ab, 0xfd754fbd, 0x554dfaf0, 0x1b9c5aee, 0x4730bbe8, 0x90ed0905, - 0x9316517a, 0x222f88f3, 0xbdf9779e, 0xa36f07c2, 0xeeb803f6, 0x7d852242, - 0x44feebba, 0xbde6179f, 0x3a56cdeb, 0x215776e7, 0xf91d81d0, 0xd6e7475e, - 0x2f79e3e6, 0x7903ef28, 0x2ef28168, 0x9226a1fd, 0x128d33ef, 0x9ce577c9, - 0xe42f2a97, 0xb6e7b517, 0x219e67e6, 0xe7beeb3b, 0xb579d276, 0xc17239c9, - 0x2d0fa8d3, 0x471dfe7c, 0x1866df04, 0x34ef23a7, 0x3271cfc9, 0x61d72f3f, - 0x2f68e453, 0xfd7551c8, 0x50e3bfb0, 0x692261ae, 0x9bcd1e41, 0x5da9566e, - 0xf8283926, 0xffe8756b, 0xdde6538e, 0x75a76d5f, 0x487a3da7, 0x316775c0, - 0xe60166ef, 0x7c3a82bb, 0x55f950ec, 0xf8b5d7ed, 0x565de80b, 0x5b63b5af, - 0x65e3d745, 0x6dbb5f30, 0x2dcfc8c0, 0x1fa88d06, 0xdef8e0ee, 0xf2c3e348, - 0x50ee7475, 0x4730fbe2, 0x7680983f, 0x39a3face, 0xf608d8e3, 0xd3acde8d, - 0x148311c8, 0xf33791a7, 0x67f2b573, 0x772b43a1, 0xa39651be, 0x4f245f69, - 0xdfdfb4d3, 0x3fa9a858, 0xbcd4ace0, 0x9d5360ff, 0xcdb26ea6, 0xb16fbcd3, - 0xe3d4d62f, 0xde6b9773, 0xa558e31f, 0xf5bd3769, 0xed0126a3, 0xc077b371, - 0x06e87805, 0x1e4b28de, 0x12d323d2, 0xe32865e0, 0x2c562d0a, 0x744df3bb, - 0x3c7bb64e, 0xec4497e8, 0x773a1dff, 0xc97c4e69, 0xdfe5035c, 0xfc5abe0b, - 0xc9a00e7e, 0x3ddbf685, 0xf0e3684f, 0x5f38abc7, 0xb94365a9, 0x280ac1eb, - 0x67b05ef3, 0x81e97bf0, 0xcc7f707b, 0x45db8c71, 0x2ec999af, 0x5376899a, - 0xb071bf88, 0x397e66ba, 0xbe427bf6, 0xf582f917, 0xbc0a6932, 0x3b08cfb7, - 0x35ee7a8b, 0xebcbf523, 0xe685d01d, 0xce597ff7, 0xceb3c1e5, 0xfc717bda, - 0xb2d03e8e, 0x7dcf4fc8, 0xaebf4468, 0x013fafa3, 0xe70cd9f5, 0xcfb44687, - 0x7a2b9e87, 0x61c60c4e, 0x0e1fe39c, 0x63de23e9, 0xa46e5edd, 0x722b4ff1, - 0x7a3be5bd, 0xf78b4f3a, 0x864a6b37, 0xe1cb73e4, 0x63ef1fa0, 0x7bf3b4b7, - 0x368e789b, 0xf9069c92, 0xbca861fc, 0xf41d367d, 0x4f1a4cc1, 0x97960fa3, - 0x3edee9f9, 0xfbcd6fc8, 0x5c34972b, 0xc8257cc5, 0x4cf3ed71, 0xb1961e7e, - 0x73fa0301, 0xed35d720, 0xfb95cb1b, 0xde58d39c, 0x2e072017, 0xdbdf2338, - 0x9f8abb7d, 0xaae0b833, 0x16787da3, 0x47e789f0, 0x3f861d9f, 0xe1dbd78e, - 0x81a465ed, 0x661bfd90, 0xff7157ff, 0x7228e5ea, 0xbfb2a2fb, 0x014084fb, - 0x33b7550a, 0x8577e88e, 0xa5ed75b9, 0xcf97dc42, 0xdebfa2b7, 0xee8123f2, - 0xffb2ffc1, 0xac3b34ad, 0x54f878df, 0x7697de1a, 0x86953a1f, 0x0cdb89f7, - 0xcf68cdf6, 0x3dd07d03, 0x3f5e8ee4, 0xa87edfc1, 0xb79f1fb0, 0x140e0af7, - 0xeb9eeec9, 0x364eb40d, 0xa3fd15b0, 0x3ae0517d, 0xabedce58, 0x2a76e5c3, - 0x13982edd, 0xc98f7ef5, 0x1e9013e7, 0x5c213e40, 0x820fc047, 0xe66dbefa, - 0xd4f648a6, 0x27df0565, 0xde1919b7, 0xfe836dfb, 0x59d38eb8, 0xbdf88da7, - 0xb0c39685, 0x71d7012e, 0x1c7881ee, 0xa181837f, 0xf7c2a19d, 0x03e05671, - 0xabfbff5c, 0x2dcf0c0d, 0x27ad596f, 0x81bfbf7c, 0x87fa27db, 0x0335bd7f, - 0x2e80cbea, 0x270f3bf1, 0x9d38df56, 0xbfbee301, 0x7569db86, 0x2f881b0f, - 0x6e13ad97, 0xa50e4bdd, 0xff6e956b, 0x70d3a146, 0xdba70dfa, 0xe6baf461, - 0xdbebd1eb, 0x90ecb7e5, 0x61f7a819, 0x438ce7ff, 0x731efa3a, 0x1a7e401c, - 0x0718613c, 0x2ada4f70, 0x63c3c039, 0xa7bef5d3, 0x9c6e50d2, 0x6df9ede0, - 0x7f2e057b, 0x7d71cbec, 0x8646dd19, 0x2a2e08f7, 0xd95176fb, 0x0a0b3b37, - 0x62cfc8f1, 0xa9ca1260, 0xf9ce256c, 0x1d35818a, 0xe452ff46, 0x8ffa67f2, - 0x87b77b6d, 0x2b7fefd0, 0xcaab74e7, 0xe64669c5, 0xf7c56c3a, 0x045f8d0f, - 0xe06cbce3, 0x282735e7, 0x09c94de3, 0x52822c36, 0xe4e5c157, 0xd438156f, - 0x3e149ffa, 0x437f2760, 0xe6685cf8, 0xd1b79ff8, 0xf8eb8cdf, 0xbd75c999, - 0x305fde1c, 0xea1b7ce1, 0x3f49eebd, 0xb9dfe3c9, 0xee1d9073, 0xa27ff056, - 0x63cf37fc, 0x3532cfee, 0x72d7f68e, 0xe90969f4, 0x68a532d9, 0x30f148dc, - 0xe66ccdf7, 0xbaba014a, 0x5aa54399, 0xaafc745f, 0x82fc8071, 0x2fc40deb, - 0xb9e9d337, 0x0553efda, 0x8e46e9ee, 0x4a97d607, 0xb6e41b7a, 0x67921658, - 0xfaa0f150, 0xfb2996e3, 0x5b1ebf69, 0xcfee28c7, 0x8f84d3d8, 0x84e76d15, - 0x41e71856, 0x02b06c83, 0x3627cfbe, 0x8534bdad, 0x626c9fb1, 0x3a0b05cc, - 0x5cccc9bb, 0x6c7d0377, 0xd81ea892, 0xbbfaa364, 0x5e54ec9b, 0xa2c738b6, - 0xa4e079fe, 0xede20a67, 0x671ed644, 0xed73cc2d, 0x41f081ac, 0xfdf4063b, - 0x376b4298, 0x0cccf4fa, 0x947a37ed, 0xf028adef, 0x8333743f, 0xfcbe40b9, - 0x8e83e702, 0x467f1bed, 0xe6b1cf72, 0x49fa037a, 0xb7176df9, 0xf1bddd62, - 0x5f680d77, 0x04fa007c, 0x7eec0ce9, 0x9e501366, 0x81da339c, 0xa66f9a0e, - 0xeb2f38d0, 0x77c80d82, 0x430263de, 0xf7a0fcfa, 0xd71c71ba, 0xe12d7457, - 0xe6744df9, 0x48ad2d9f, 0xfbb8fc22, 0x7f7c75f2, 0xf7a1748b, 0xf9effa29, - 0x87ee0243, 0x9dfda379, 0x467fec4a, 0xb7af90cf, 0xa41306d7, 0x02f87208, - 0xa3978b8c, 0x86581d70, 0xbd1937b7, 0x413cf053, 0xe1c74293, 0xfa158bed, - 0x941b4c04, 0x213229ef, 0xc1239f8d, 0x5258169f, 0x41f93262, 0xe7e038fe, - 0xabbabe96, 0x811e9622, 0xcff5a87d, 0x762187d8, 0xfc3a347c, 0x437e25b2, - 0x4329c3e6, 0x4323f475, 0x1fa07fef, 0x82fbe919, 0xe3c9aca6, 0xb9778a46, - 0x83bec007, 0xc300eafd, 0xf4829ec9, 0x4fca8d3e, 0x91d9748e, 0xc171cc7f, - 0xd82fa83d, 0x3bf23a5d, 0x7b5abdda, 0x87e141a8, 0x7a1ec506, 0x3feb42b4, - 0x5ed49f81, 0x84a4fdc1, 0x3fe34ce3, 0xff273f85, 0x057c8cc9, 0xfd834ef3, - 0xfed22579, 0xc7aed554, 0x2ed8137e, 0x740673a2, 0xbe15f48e, 0xe0a8bfce, - 0xebe5547a, 0x48d7c865, 0xaf9cbdbf, 0xa96dc7c3, 0x1c0bf9aa, 0x7b945b77, - 0xf157f710, 0x139fdaf1, 0xe7ee5f08, 0x1f4f0852, 0xb59ce7b3, 0x031f9740, - 0x2e80fb1c, 0xf19d39af, 0x9affd049, 0x6c9f19cb, 0x1d03921d, 0xbf53c5cf, - 0xa717936d, 0x19fd42b4, 0xef187ba4, 0x8a3ade93, 0x1cf43e6f, 0xbe753fe7, - 0x52cbfc0f, 0x0d8a9f90, 0xda03a341, 0x262efb33, 0x7c581da0, 0xe414fee4, - 0x6e7068c3, 0xdce054ad, 0x4bdad8f8, 0xf01e9c29, 0x455aee1c, 0xf49fb9bf, - 0x6bff111b, 0xdfa23237, 0xd97ed7fe, 0x49fc7c81, 0xfa84bc5f, 0xf1a3e3f0, - 0xd7ff945e, 0x3a7c998e, 0x6f10fc81, 0x8fb5c822, 0x91f7030d, 0x2f4479bd, - 0x3ee8ffa1, 0xc83ddbf6, 0x4cd7ee8f, 0xb5b1f968, 0x51d75d7d, 0xddf5b5ef, - 0xf2c4557b, 0x87e5d1a5, 0xd38f8df6, 0x6ffad57a, 0x28ed9937, 0xb9113f47, - 0xfbdb589c, 0x6bbfd92a, 0xc0cc6f07, 0x47c7ea38, 0xca094fff, 0x379bf735, - 0xb99e504a, 0x8251b8df, 0xc71feeed, 0x2dd9227b, 0x84f4b371, 0x665f5557, - 0xe26a27bf, 0xfa141b45, 0xd5dceec8, 0x57f00938, 0x03896e7c, 0x7b6ab6f3, - 0x139d14f1, 0x79fe2fdf, 0x21c3ca7d, 0x22033afd, 0xce8a8de5, 0x0eafc7d5, - 0xaa47cba1, 0x94ef9a0c, 0x0f38d57d, 0x2df7e2b6, 0x0275c56f, 0xec0efa3a, - 0xbfc880b6, 0xf046bb2f, 0xf601bfa1, 0xb23f784b, 0x923daea7, 0x9910f742, - 0xbd3f9ce8, 0x1c53eb08, 0x5628eddb, 0x8726a7cc, 0x02cb4bd8, 0xe809bf3a, - 0xe4cfa9a8, 0x203f7b27, 0x62baa45e, 0xfd743d47, 0x85b26337, 0xdc9a7108, - 0x1ca0e777, 0xc0d78f0f, 0x5b8418cf, 0xa7ceafb5, 0xa651f8f3, 0x042dd247, - 0x993b9ab8, 0x161d7884, 0x4b9a69d7, 0xf8f0a2f1, 0xdbb03d8e, 0x93ecfd8c, - 0xabc21275, 0x8fb8a5da, 0xc0e4113d, 0x7972565f, 0x6757f2a6, 0x3af5e780, - 0xc9e6b503, 0x69577e50, 0xcc7491ef, 0xece9780b, 0xc600ffbb, 0x1f073a17, - 0xf30e9f8c, 0x98b7be74, 0x9ae79e61, 0x829e6b54, 0x9ae706fd, 0xa21bc81f, - 0x1af9f09b, 0x345db92a, 0xd6442f64, 0x5f0aa57f, 0x2c1e968f, 0xd0f3fcac, - 0x579fe083, 0x7cff7254, 0x709f8f05, 0x7f5c3cff, 0x1d5972a8, 0xef82ad77, - 0x2af972e1, 0x47e039d9, 0x5b5e5c93, 0x32f7a769, 0x90a516fb, 0x92defd7f, - 0xf875bb14, 0x43a239f8, 0x7c379c97, 0x739ed57c, 0x6653e57b, 0x3d647bf4, - 0x897ba7f1, 0x97fcc3e0, 0x9db9ff6a, 0xeee5d902, 0xdf0f8366, 0x2c0ae153, - 0x07d8f1e1, 0x22cf8364, 0xaa89d90c, 0xddab791d, 0x6abb5021, 0x63f6aa57, - 0xbbe3c9c0, 0xfb788a4b, 0x556b8b65, 0xa75c58e5, 0x97179e85, 0x398ce7f3, - 0xf55fa14f, 0x918152e0, 0x4aec501c, 0xedc34e95, 0x72fb4fce, 0x438a4712, - 0xa7d0af3d, 0xc21367ca, 0x63d543f8, 0x7e7054cf, 0x5e3d40eb, 0xf7fc7a88, - 0x7c3cfb1a, 0x8fe3d05c, 0x463f5257, 0x2e7e8bfd, 0xebf9233a, 0xadfc6566, - 0x4e05feea, 0x59bc20d6, 0xfd19b02c, 0xf5fa68cc, 0x139d8a7b, 0xc519fdad, - 0x3f1dbc7e, 0xc8e4561f, 0xcbf3f168, 0x70f2b795, 0xf9f9a9ff, 0x8c687d96, - 0xd557bf62, 0x1ffb86bc, 0x6a04f7a7, 0x97feff90, 0xe1eee281, 0xfaa53def, - 0xecd3229f, 0xa32ca9cf, 0xf723fd0e, 0xe83f1e1a, 0x43bfb24e, 0x7a5bcc7e, - 0x05ace386, 0xb8ed107f, 0x51266f47, 0x32f686d9, 0x385e2b94, 0x1588f947, - 0x77f0b46b, 0xfb174c63, 0xf3a6cbaf, 0x9eac2d03, 0x7d2d4ce2, 0x5016d249, - 0x0f63dd0a, 0xf2be469d, 0x0fdbd01e, 0x88ffbe84, 0xc799befa, 0xfba636e1, - 0x661af728, 0xc278b40f, 0x7dad7eed, 0x8dc4a950, 0x6f09d9a2, 0x5cb85bf4, - 0x3e27a339, 0xd378c0ef, 0x7d8cc64c, 0x37b82e5c, 0x474938f2, 0xfc04e6df, - 0xd2bb6a08, 0x500c457e, 0x6bf28a1c, 0xbed5eaf0, 0x3ee8d3a7, 0x27cdac97, - 0x39ffefb5, 0xbcf0cbc9, 0x970f7252, 0xbd36ee4b, 0xa12a4792, 0x83b797ef, - 0xed0e393f, 0x1bfdbb4b, 0x8b807788, 0xc8de48f9, 0x3ecbb89a, 0xe9f4af25, - 0x3f257f99, 0x2891c574, 0x79eea479, 0x7ca48f3c, 0x1e787727, 0x0ca9f4e9, - 0x48f3edfb, 0xe8e7bd1d, 0xf2edcb1e, 0x5baaa649, 0x3b8a1c71, 0x7c79144e, - 0x209f6277, 0x626abc61, 0xe9775f1f, 0xafb238b6, 0x3ab57e1b, 0xba81e505, - 0xe22c9f4f, 0xfde4fdf8, 0x5fb06acf, 0xc944afc9, 0xe37aeb02, 0xcb3f0dfd, - 0xd9bb75e0, 0xc436fd8e, 0xc9f33fa3, 0x23c7d6af, 0x1280df7e, 0x17c7e7f7, - 0xc9f1c8c4, 0x667578a1, 0x959dc515, 0xfa08b578, 0x5c50cc70, 0x8bdfbc27, - 0x746e5c55, 0x7142bb83, 0xef3c23cd, 0x9aee9ddf, 0x9ebff547, 0x29dff8c4, - 0xfd1e2990, 0xc635d02a, 0x62c1a68d, 0x3ffd2f31, 0xe62758e3, 0xbac7ba91, - 0xf47c427e, 0xf23b3ad7, 0xfca7f411, 0x9db0f793, 0x6a8623f4, 0x0333cf31, - 0xf7405b3f, 0xdf295231, 0x8fb28f73, 0xa2cfe0e9, 0x2cd0095f, 0x34f43cc1, - 0x2333df25, 0xfe38898e, 0xfb6b830e, 0xf52fcc54, 0xc4cd8e8b, 0x3c148e04, - 0x779e196f, 0x2f9e6412, 0x6a4ff357, 0xfe5a3cde, 0x9479c049, 0xf3f056ef, - 0xf980b296, 0xc4cf3574, 0xf9293a96, 0x43cca5b5, 0x807c42f7, 0xde73afb3, - 0xcffc846b, 0xf21115c3, 0x982beb3f, 0xf3699f62, 0x5f73db8d, 0xaafd3a21, - 0x78c3c679, 0xe68ee2ae, 0x0fdcecc5, 0x28bb830d, 0xf234d3e9, 0x6ff8febb, - 0xfb67a409, 0xbc3e906e, 0x00b13416, 0x78071fc5, 0x40cfbddc, 0xe06b8671, - 0xd10d8dbf, 0xf054efb3, 0xd5f78f71, 0x04f7fd11, 0xfdf1e3ea, 0xb7cf2bdf, - 0x7ee4b7bd, 0x01bdf7b4, 0xc60b1dfe, 0x13d63fb8, 0x6ed18b10, 0xf2fb83b9, - 0xf5846564, 0x7eb8e399, 0x52a3e70a, 0xab4aff85, 0xdeeb9e38, 0x7b987ee7, - 0x48afcf03, 0x7b705c8a, 0x74fd5e78, 0xc6a09a56, 0xca45c7d3, 0x92091cbf, - 0x447968de, 0x7cc9efa0, 0x33cbfcd9, 0xf1f391e9, 0x462f7a2b, 0x3634bfce, - 0x168cfc90, 0x638f0ecf, 0xff2a9dff, 0x7638f3a6, 0xeb44957a, 0xd7e4f64e, - 0xeb43638c, 0xb0fb83bf, 0x7d845674, 0x6fe383b8, 0xf1db1d9c, 0x3b63caeb, - 0x1e3113fe, 0xc78c7b7f, 0x6c7961ff, 0x8abaebf3, 0xdbffc2d8, 0x1fdfc318, - 0x57fffe09, 0xe78407cf, 0x0bcfc3ff, 0x30039f84, 0x17b0f5bd, 0x9d84badb, - 0xefc33f41, 0x24d6bf8d, 0x93141c80, 0xce7dd3f6, 0x1f3ce505, 0xecdeadb6, - 0x9d0c2bdb, 0xf5f1501b, 0x23f73568, 0x5eebbca5, 0x04d45efc, 0x829f5039, - 0xfe72b2f1, 0x59ae4377, 0x898c5e78, 0xc9e63a52, 0xc5f4cde0, 0x5b749760, - 0x5359e722, 0xe9a2f195, 0x35d58391, 0xe315678b, 0x7c8a3d1f, 0x4a87ff0e, - 0xe5ea521c, 0x6899e9f7, 0xf34c5f4f, 0x1ed1d3da, 0x9fc93c4a, 0xbc99f827, - 0x67b2e097, 0xdc7fe62f, 0x7be11b20, 0x26ffc946, 0x1b2bbbcf, 0x60c9d2e3, - 0xf05e6217, 0x920fcc69, 0x7bd12b3f, 0x66977cea, 0x19ea3f71, 0x9f301303, - 0xcfca9deb, 0xdf9eb139, 0xe6a6fd91, 0xfc1acef5, 0xca055a97, 0xfc23b5eb, - 0xf3f9d53f, 0x442b65f6, 0xebcdf80c, 0xf8df2891, 0xe5dff976, 0x9e1e68ba, - 0xe24c7be7, 0xbf409caf, 0xec78e019, 0xefd12168, 0xffe5e38a, 0xc7fe8cd4, - 0x3cf09164, 0xe254afcc, 0x78941705, 0x502f1a87, 0xacff5bf3, 0xc03e49c4, - 0x03940bf8, 0x72810f18, 0x9ddd2cfb, 0x67db4fd6, 0x67ffe045, 0xf21f1e04, - 0x87c794fe, 0x9c8e8d0a, 0x7f94f3d0, 0x63ef8b35, 0x2fe79fab, 0x0fcf78d4, - 0x7e14f595, 0xefc7ef4f, 0x9d6e15a1, 0x5f3d446e, 0x0e2b35b8, 0x4fb219cb, - 0x5ef80697, 0x4eb0fab6, 0x7448bfdd, 0xe75957b4, 0xca4133b6, 0x961abdef, - 0x8b34bff7, 0xa968679f, 0x097bfbe6, 0xd418a0ff, 0x6e229b1f, 0xb131f341, - 0xca47d24a, 0x5f80b52b, 0x76b6708c, 0x7c55b873, 0x75edf8b7, 0x53c5cf38, - 0x1658adc1, 0xa3aec9ac, 0xf5db7bb8, 0xb9bf68ad, 0xae9c6f07, 0xd19978a6, - 0x43c4fe8e, 0xdbb8da03, 0xfe3cd513, 0xe01a2afe, 0x457bb788, 0xef0b8ff2, - 0x927e8915, 0xbfe42c5b, 0xde981b26, 0xdc45f58a, 0x4c682a2e, 0x5b3ac3ad, - 0x60f64492, 0xd27b19c1, 0x714379c3, 0x377be4b0, 0xdd3c458c, 0xc6aacf2e, - 0xe45b2ed3, 0x5f9fb8e3, 0x7edacf35, 0x6f3a3df6, 0xc54baeaa, 0x8d2f9a8b, - 0xcf556796, 0x3f1bb83d, 0x70d39cd3, 0x8c06c18b, 0xbd1e163f, 0x5fce5468, - 0xa1ecb64a, 0x91e16c3c, 0x557f94eb, 0xcf6eadf3, 0xa1abb275, 0xf7fb119f, - 0xd7f9e26c, 0x2c0e00d7, 0xb2dd617b, 0xdba1ef09, 0x7583eca8, 0x9b63f3e3, - 0x6ff4a972, 0x7c795072, 0xf8951953, 0x64f4c999, 0xa75edbcc, 0x59d5edbc, - 0x524dcec3, 0xe8b76f5e, 0x15f108fc, 0x7aa3f792, 0x1f4fde78, 0xee35e3c7, - 0xbefa0633, 0x99acfba1, 0x5f4d77e4, 0x0ff444eb, 0x9ae73f3e, 0x60777088, - 0x2e842dde, 0x961d913e, 0x9d83f424, 0xdbe60b0e, 0x1aaffb0a, 0x874c3cf1, - 0x3c623018, 0xc0cf200c, 0x9eee8b23, 0x6fdcfceb, 0xf1058d5f, 0x58fcdb7b, - 0x8fcfffef, 0x58fc957d, 0x273f3577, 0x0291caad, 0x8bde4ea7, 0xf2d919e5, - 0xd89c8870, 0x94f9e4e6, 0x1127936d, 0x4e76ee1f, 0x321d5a4a, 0x8f23675e, - 0x3bdf245f, 0xfcfa12d9, 0x1f3cd597, 0x67302c96, 0x33567924, 0xc7ddebfb, - 0xd76e411b, 0x3ffbb244, 0xe5d029f9, 0x238ba04c, 0x90389edf, 0x343f19c7, - 0x71adb71e, 0x2831c4f5, 0xd8982e9f, 0xd3af1e14, 0x5858e3c4, 0x5c5a2e5e, - 0x4ea3456e, 0xa179d0b6, 0xdbd404e0, 0x2633f1e1, 0xbd702706, 0xbde0672e, - 0x83319814, 0xf961b195, 0xdf305fb9, 0xfbc327cf, 0xa4751acb, 0x5d3cd42f, - 0x36c8a341, 0x6c167d01, 0x3f28f834, 0xa45e28d7, 0xec6fc576, 0x90320a94, - 0x6b383fce, 0x16ae3094, 0x34731f1e, 0x049eefee, 0x026d1dfd, 0x5dba0bdd, - 0x073d4f1e, 0x3fdbd2de, 0xf96de307, 0x3d77576c, 0xac9fcff4, 0xf4fcf093, - 0x3f1e7cf0, 0xd8a05dff, 0x3671e139, 0x4bb433a4, 0x1bf0e3c2, 0x38d83a15, - 0xd7adeb9b, 0x1d537f14, 0x4e17ed47, 0xcd9d3f3f, 0xb8b46df5, 0xbc6551fe, - 0x6d82c6ce, 0x177f7193, 0x93ea18e8, 0xf35ac6ce, 0x76f190e4, 0xdbe7e6cc, - 0x60fcc19e, 0x907e686a, 0xf3c301e7, 0x2b9caa82, 0x037dffec, 0xc8377be2, - 0x6e63d46b, 0x141fcf1b, 0x8339ab1e, 0x4e086372, 0xc377b7ae, 0xbec8079e, - 0xbe312473, 0x457bfa2e, 0xc502a3de, 0x7c160ae7, 0xea1e3c76, 0xf74499cc, - 0x2767dcb0, 0x3ca2b16f, 0xe316205a, 0x53b71ebd, 0xc26795b8, 0xeffdd27c, - 0xbcefa1ac, 0x7f903e16, 0x81e5f70e, 0x0f9d0366, 0xfddef554, 0xf03534ef, - 0xc64fbdf6, 0xe0ae7b61, 0x79f1d8b0, 0x763f7d23, 0xfa7e4bfe, 0x110b58bb, - 0x81e7903a, 0xe44497b3, 0xd716cb9b, 0x151f23df, 0x4cf2522e, 0x3f4f5ccd, - 0xc0c8b7d0, 0xead3cec8, 0x9f5913cd, 0x46e83c53, 0x8fe5215f, 0x43fcf052, - 0x29be90de, 0x6c7a0a3c, 0x63d39dcc, 0x112d9d3f, 0x1e82673e, 0x17927843, - 0xf87d3cf1, 0xf650effe, 0x8a5e9a3f, 0xff518726, 0xde63fbf0, 0x5c36c10c, - 0xee31db8f, 0x3af68a53, 0xd3a2e394, 0x71661fdf, 0x628a4eba, 0xa149fdcf, - 0xa7e7a8df, 0xcf27477a, 0x7fd987f4, 0xd563791e, 0x4df352ff, 0xa0f6bfaa, - 0x65ab0f62, 0xbbfe5293, 0x72a037ef, 0x21bf788d, 0x86fdf239, 0x68090e87, - 0x1bf7a8a7, 0xcd59194e, 0x4f3c54e1, 0xf277dcab, 0xe93b222d, 0x62fcdfd4, - 0x78a98beb, 0x509049df, 0x3a1fb51d, 0x1dbe7a47, 0xa7b223ec, 0xe3cb7efa, - 0xf9f887ad, 0xc8def6f0, 0xaddbdddf, 0x32f5dfd8, 0xaed1b923, 0xe86db79c, - 0xb744f251, 0x8b8f96e2, 0xb74b71a1, 0x3d56303d, 0x7f23ebc7, 0x8cc71b4f, - 0x60ecb716, 0xdbb73a41, 0xa07046b1, 0x39ddb87e, 0x79ca5ddc, 0x4c71a8dd, - 0xb973e479, 0xb94c71e1, 0xb9c79b5a, 0xf7c4966f, 0x680825db, 0xce759aef, - 0x7fb73a36, 0x9d22904c, 0xcd5a5ef3, 0x257cf4e5, 0xc8d0720f, 0x8560e3e9, - 0xf06ff740, 0xfbee1e1e, 0x1efc63c1, 0x7e02c1ce, 0x7bcd470f, 0xa66bf7a8, - 0xe83de50e, 0x2f7a9dfe, 0xc367bd47, 0x5ae08f98, 0x7d1c5cf4, 0xe1876bc7, - 0xbddb8d90, 0x1a3f7e5e, 0x43e61065, 0x8913cc4d, 0x6bab6b5f, 0xef7a6ac4, - 0x8f4fdb8e, 0x7bf04754, 0xe91f8a7d, 0x2fea8eae, 0xfad6afac, 0xf70f540b, - 0xde54ee17, 0xecd98be3, 0x87fbfb4e, 0x9e8f1c63, 0xf1b63b32, 0xfb48ecc4, - 0xfda2c5b6, 0x5e5aaf1e, 0xb0dfe456, 0xbb0dc5ef, 0x7af5c92f, 0xa7ff60b7, - 0x1ba7ca4a, 0xcaae9f28, 0x7c31eed5, 0xe3291ffc, 0x294065a9, 0xd77ca3bb, - 0xbc4a97f9, 0x7b944bac, 0x2f69ee10, 0xd397e368, 0x97e3690f, 0x35937b33, - 0x78ff7cf5, 0x6785fbcd, 0x8bda6926, 0xda68f703, 0x68142f4b, 0x1503e5ea, - 0xaf2bf79a, 0xb3ea6ad4, 0x65f8da82, 0x61c5cdf5, 0xb47d38f7, 0xdca01abe, - 0xe6757ed0, 0xcbde6a6f, 0x575da358, 0xaebb4796, 0xebb51b89, 0xf6cdc752, - 0xd397d76a, 0x325f5dad, 0xbef2e3e6, 0x7f2e3e7e, 0xc7c95db6, 0xdfb058e5, - 0x2d938d33, 0xf7a9b768, 0xfef7d5a9, 0x5866372f, 0x007f40df, 0x00000000 -}; - -static const u32 csem_int_table_data_e1h[] = { - 0x00088b1f, 0x00000000, 0xe4b3ff00, 0x51f86066, 0xb97bc10f, 0x726e1818, - 0x0143f821, 0xd08667cf, 0x0c0c2c6a, 0xc6cc401a, 0xcec0c0c4, 0x717ebc44, - 0x1d7b044e, 0x4cc30307, 0x31c8de20, 0x481afef0, 0x7e879d7c, 0x42f3a976, - 0x81c15968, 0x570837f7, 0xb430310a, 0xc430330a, 0x0cf84088, 0x55f2a8a2, - 0xa9b60842, 0x39766524, 0x0003f502, 0x3471cc24, 0x00000380 -}; - -static const u32 csem_pram_data_e1h[] = { - 0x00088b1f, 0x00000000, 0x7de5ff00, 0xd554780b, 0x733ef0b5, 0x7993331e, - 0x0f20f264, 0x0084f102, 0x021842a2, 0x27088784, 0x01a8c421, 0x54bc8083, - 0x48433c26, 0xbfa81132, 0x2677bd6d, 0xb5ad1104, 0xbc1b6951, 0x14101de8, - 0xd1a07515, 0x40e81c06, 0xdbdab114, 0xd5a8f8a8, 0x40445076, 0x8bcbc248, - 0xaf7fd52d, 0xe649cfb5, 0xd4484c9c, 0xffffbff6, 0xdbf3f1fd, 0xd9cfb3ec, - 0xdaf5ed7b, 0xf6bdad6b, 0x9a32c11e, 0xe4224e24, 0x65a3f85b, 0xf4842784, - 0x0adb2ce9, 0x64918fda, 0x8b2ffc42, 0x108e36f2, 0xf08e77ee, 0xbc8451a4, - 0x980b99b5, 0xcfbc3d69, 0x9fad0846, 0x603d34de, 0xff6422ce, 0xef02b308, - 0x8f9ade9f, 0xbd2fc9f5, 0x7b6814e7, 0x00bc4bd5, 0x13bed375, 0x109d88ce, - 0xa1e5b9af, 0xf6f3e96b, 0x85b27897, 0x93fc450e, 0x9085244d, 0xfec21663, - 0x52fab22e, 0x6d56ab2b, 0xf4077fde, 0x2664de5b, 0xd54fda56, 0xaed365ee, - 0x8765f5a5, 0x54af0244, 0xfa95ab6d, 0x00f2fad2, 0x9afa8417, 0x71c67f7d, - 0x79480ada, 0x27212870, 0x5f22167d, 0x96ceeb49, 0x79f45994, 0x11676045, - 0x83b15fbc, 0xfbe89b73, 0x7ff69b15, 0x3457fd0c, 0xda79038a, 0x36ed8aff, - 0x63610f22, 0x1e604b7f, 0xbc01a64b, 0xc4886f55, 0x97e5eb4c, 0x70044956, - 0xa54bd424, 0x61ff180e, 0x38c07649, 0x0d1c7087, 0xd0cf559f, 0xd577e871, - 0x986e702f, 0x7889b55a, 0xddd69e00, 0xda4f39d6, 0xd2b55e61, 0xf77ef860, - 0xb7bc127d, 0xb2f6502c, 0x36f80655, 0xe700454b, 0xd2d2cda6, 0xadfd9da1, - 0x0ea6fed8, 0xd90d63ae, 0x76a89ea9, 0x47d27963, 0xacee6c88, 0x04a21057, - 0x407700ed, 0xf3ac3e9a, 0x812e79f9, 0x3fd0d190, 0x674b644f, 0xc83094ff, - 0xe8f7fe07, 0xf60f813f, 0xb2db023a, 0xd2b5e93a, 0x772dff45, 0x4bacebd2, - 0x9ed09fa5, 0x56bfdd17, 0xa074043e, 0x5cfbd4f0, 0x4be23e58, 0x4f8372c3, - 0xcafdbc46, 0x06cb0437, 0x3f9f1b9f, 0xe58b1be6, 0xe5829f26, 0x2c62be13, - 0x7c52be03, 0x0e6f8b6f, 0x1e7d5b96, 0xaf94fe7c, 0xbeedcb1c, 0xacfe7c1a, - 0x772c6eef, 0xfcf8fcf8, 0x2c7adf05, 0x2c7abe83, 0xb01af977, 0xf005f46c, - 0xdb7d97bd, 0x05f26cb1, 0x5f1ef9f1, 0x5f219613, 0x407dcb18, 0x7d865a5f, - 0xf01e582d, 0xabe5887d, 0x777e08be, 0xcb1c77d0, 0x3bbc5507, 0x817c9027, - 0x10a9cde2, 0x92171517, 0x8be4a258, 0xca589eb4, 0xf9b729ea, 0x4f5a25f3, - 0xc53ad0f1, 0x70cadf63, 0xfbd699be, 0xccf6b0d6, 0x8581487b, 0xacfd33d6, - 0x4a83c07d, 0x07d69581, 0xc1f6b3d4, 0x7105fc9b, 0xc0383eb4, 0x11deafda, - 0xfad1b02e, 0x9ed641d5, 0xed932213, 0x66139eb4, 0x94b7dcf5, 0xcf5a0ec9, - 0xbcf5616d, 0x9d93fd8f, 0x61179eb4, 0x153f8fdf, 0xeb4f1c9e, 0xfb59dbe3, - 0xd0a44bc4, 0x0913eb45, 0x7b02f587, 0xad02617e, 0xbd58b817, 0x20995fa8, - 0x7dbfe0c7, 0xa1116462, 0x7fddb0bc, 0xd3a422b3, 0x455914ba, 0xfe9f14dc, - 0x8b0f5839, 0xbfb43164, 0x84532fe5, 0x912eb471, 0x17fed0d5, 0x1fb6057f, - 0x6f6c6510, 0xf6c2aff7, 0xed8c9203, 0xb07bdaa6, 0x60a8aafe, 0xbded727b, - 0x92abfef8, 0x6b83ed82, 0x41fac21f, 0x63ed83d1, 0xef8d7f6b, 0xd83c941f, - 0x80dac8fe, 0xffeb4852, 0x00b679c1, 0x9e71d75f, 0xfc0d9272, 0xa52b4c1a, - 0x238ebafc, 0x1e3e4073, 0xf2a6a600, 0x525d2eb0, 0xfbedbf40, 0x3c93de47, - 0x3276f2a7, 0xf53e97d4, 0xf3f61640, 0xd223f61c, 0xfb9ef87e, 0x58cdf899, - 0xbf133f5d, 0x69fad729, 0xaceaf784, 0xdf67ebbd, 0xf0f5e337, 0xf5a1537c, - 0x71fb17b3, 0x135e6ef4, 0x87a09dbf, 0xad4adbe7, 0x4fd8839f, 0x09e0ef42, - 0xfd74638b, 0x5a65c584, 0x7ec47f3f, 0x1e0ef4fa, 0xeba71a45, 0x6b969147, - 0xfd887cfd, 0x9faef7a4, 0x1ead74b0, 0xd685691e, 0xa7ec11cf, 0xa5e6ef7f, - 0xc3d3af98, 0xfad2ae63, 0xcf748939, 0x073f5dea, 0x1cfc7a1c, 0xe7e07470, - 0xa833c21c, 0x702af377, 0xe053f1ea, 0x25cfc0ec, 0xdeaae7ec, 0xa9c073f5, - 0x6701cfc7, 0x0e447e07, 0x77ac35e6, 0xd7882af3, 0xbe20a7e3, 0x0e4e3f03, - 0x3bd119e0, 0xa3ed5e78, 0x7dabcfc7, 0x8a93f03a, 0x1dee8cf0, 0x7a29853c, - 0x74a614fc, 0x784647e0, 0x9faef5c6, 0xf8f45357, 0x03a53579, 0x3f61573f, - 0x5e6ef5d7, 0xfc7aa985, 0xe076a614, 0xc9fb1727, 0x78476cf7, 0xd1c7ed08, - 0xfb073f7d, 0xb073f1eb, 0xae7e077f, 0xd0a67ec5, 0xee7bb27e, 0x8f5328a7, - 0x0ecca29f, 0x9e2214fc, 0x3f5de86f, 0xf8f53307, 0x81d99839, 0xcfd8a99f, - 0xabcdded4, 0x7e3d0ae8, 0xf860ae8a, 0xc08c2499, 0x9dae8675, 0x727e9e6e, - 0x857cbf7d, 0x2ef3efa3, 0x6e5de756, 0xaf0f7602, 0x45a433d9, 0xf6fbe9e1, - 0x0fb9091d, 0xa6bb6890, 0x8fc076e0, 0xd1795a83, 0xd8fc4d76, 0x951d9d38, - 0xeaea24a0, 0x757dc549, 0x1d29f7ef, 0x9d4f6ba0, 0x3daeb573, 0xabab93dd, - 0xd78f9467, 0xa6bfdfbd, 0xe2bf5740, 0xef751bee, 0xd16ff967, 0xcfd7b3d5, - 0xa83fbdd3, 0xfdaea17e, 0x5d0a86ca, 0x958155fb, 0xdb35faba, 0x7f7ba27f, - 0xae8d7058, 0x03d3787d, 0xe111f6ba, 0x91f57447, 0xbdd31e87, 0x8b65ba3f, - 0x87cc7dae, 0xc7daeacf, 0xeae97645, 0xa3df1ed7, 0xf6baff7b, 0xa4faba03, - 0xbdd7bf8b, 0xd5de4f9f, 0x3f96dbdb, 0xe29fdeeb, 0x7ed74cfa, 0x0697da7d, - 0x3aeed53b, 0xe75a8d76, 0xfa08ae41, 0x0974fe25, 0x43b0d5ed, 0xd7d4bac2, - 0xc714fcce, 0xe528f952, 0x22c0e91f, 0x92f91939, 0x21bb51fe, 0x95f96fbf, - 0xaefcfa11, 0x5d2b9ef1, 0x925df9f4, 0x862bb867, 0x8df9437d, 0xca506923, - 0xed8d2826, 0xdf8c89f7, 0x0d2e320b, 0xf7bf423e, 0x2707da9a, 0x3e70fad0, - 0xf1f2083f, 0xbb426732, 0x35278e3a, 0x999c5ef0, 0x5f74dfa0, 0xfe93de56, - 0xdf587928, 0x5c19da9f, 0x45ebbf67, 0x51da1a4f, 0xc1f89fb5, 0x9fd759ce, - 0x212fabce, 0x849f70af, 0xf7e903fd, 0x79a697fd, 0x89667f68, 0xe3d119fa, - 0xa1fc744b, 0xe4187e38, 0x3f8c20e1, 0xe6f8ebba, 0xe3756301, 0x75cb325b, - 0x3a245be3, 0xdf908bbe, 0x8eae7ed7, 0x9e30894f, 0xcfb93790, 0x66737c71, - 0x9f7f8e39, 0xe8aefd44, 0xc63ae3f1, 0xbff9816f, 0x07fcdddf, 0x3fcfd78c, - 0x7f3f42b3, 0xa3ffcd89, 0xf8ead3da, 0x3fff3871, 0xfcd9a773, 0xfcd82b33, - 0x8edfaccd, 0xf81d9df1, 0xc7f8c08f, 0x9cdf19ba, 0xff3f413d, 0xf3f52a2b, - 0x4ff1b337, 0xc7505ed6, 0x5ff8e3b7, 0xfcd81772, 0xf1c4a8af, 0x0dc7b325, - 0xc46523fc, 0xf8e804d5, 0x7c551fa4, 0x742ec0a9, 0x2487281c, 0x6421a152, - 0xe100371b, 0xf18e2bb8, 0x947157db, 0xf99f50df, 0x500939f1, 0xfd4799cd, - 0x57d79546, 0x4097c8ec, 0xf53b61ef, 0xa0a896b7, 0x91e26e2e, 0x7306c9bf, - 0xb7851060, 0x43f789b5, 0xeb86f17d, 0xbd5fa002, 0x14a0b266, 0x184813be, - 0xcbfe7f9e, 0xe7a25b61, 0xd4972c65, 0x5122c78b, 0x07e1d6f2, 0x35219016, - 0xc029be14, 0xeb3ba304, 0x0e3f529f, 0xa98fe31c, 0xffa843df, 0xc6c899f3, - 0xf7f50bfb, 0xfea11ea0, 0xa4ce3a1e, 0xdda3bf16, 0xf0a34e1d, 0x7ff0aa97, - 0xfd79302a, 0xe02e36f4, 0xd5f9f2a7, 0x7fa0478f, 0x1b6ee0bd, 0x1c277a45, - 0x5d24fe65, 0x0fcbce9d, 0x6ddf6a74, 0x10e16c0e, 0x6be032bf, 0x21268a3a, - 0x5067d68b, 0xffbe775c, 0x07a9bec1, 0xb7212739, 0xa54c4512, 0x9abedfef, - 0xe3a2efeb, 0xb9cc52ce, 0x32521d6c, 0x24d7284c, 0x909634c3, 0x88471a5b, - 0x5d3207b4, 0x448d3f11, 0x58a33b8d, 0xaa559f5f, 0x8a8ab7af, 0xb570a268, - 0x66c8e74e, 0x39ecefda, 0x9c6d76fa, 0x4644a681, 0x52bc7567, 0xfa74938a, - 0xb9943668, 0x7485d8f0, 0xdf62e39e, 0x1778f06a, 0x7e8c2489, 0x010fbfbc, - 0xf193faba, 0x362e79bd, 0x73bc236f, 0x4a528b44, 0x8ca739e7, 0x1b7f000f, - 0x9f68ffe1, 0xd0e5314d, 0x22a3fd72, 0x8f9d7531, 0x1eb9fe11, 0x22827ce3, - 0xcbf3f3ac, 0xdf19cf8d, 0xffe9531c, 0x2d07f029, 0xa0fe00bf, 0xf9551ff0, - 0x32af53a3, 0x3d9af0fe, 0xda1f80d3, 0xe904f237, 0xadcbf2aa, 0xa92cbf2a, - 0x2105f3d7, 0xb8e8111e, 0xfb970e6c, 0xcc1f1440, 0x5960f956, 0x6e6f9e83, - 0x3d317e27, 0x6ee65d06, 0x9a6f7cd8, 0x9f7e75dc, 0xff337ca8, 0x9f88fdc1, - 0x7464f3ae, 0xd3a543ba, 0xf6fa35ed, 0xdeba555b, 0x4e75d2ae, 0x51afc3c3, - 0xc9e641f5, 0xdde41101, 0x9e8d53fb, 0x3d3d1d11, 0x708d3d2a, 0xf3d2a1de, - 0x7a331f8e, 0xa88de11a, 0x9c348cf4, 0xae80c913, 0x5be11af0, 0xf9977770, - 0xccab5c60, 0xde9e9b1f, 0x4755fca6, 0x05579ea3, 0x3475586f, 0x6c56ce4a, - 0x2fabae9f, 0xbdd5cc0f, 0x4ca1acbf, 0x7ea4bed7, 0xd17daeb9, 0xf5753bfa, - 0x758fff32, 0xbbb82fef, 0x7b7ed756, 0xf6bafdcd, 0xeb0fe5f9, 0x1b3d73ea, - 0x9ecfef75, 0x3ed759b3, 0x5d19f4ab, 0x9de28cfb, 0x6574faba, 0xd37deeb7, - 0x066eabbe, 0x3deb7cfe, 0x713d809e, 0xc605fdc1, 0x45b82f33, 0xd473bc37, - 0x1f5f2327, 0xf2c10df3, 0x7c8dcfb8, 0x1637d27f, 0x66a6d6cb, 0x7413ac3b, - 0x124a5c5d, 0xcd326908, 0x0fdf5dab, 0xeb8269d6, 0xa9e4c869, 0xb37ad3f5, - 0x28794649, 0x78489069, 0x2c1c2124, 0xed1c2a36, 0xa47b547c, 0xaa06f687, - 0xb6ba93f8, 0x3f624497, 0x76523ef7, 0x7765f005, 0xcbfd03eb, 0x4da7bb00, - 0xed8debb5, 0x8d291c95, 0x1ac84e7e, 0x626ac384, 0xc4a54776, 0x5772bfe4, - 0x4271017a, 0xe6b83c3d, 0x2905e372, 0x9f02a793, 0x78e4eb64, 0x3a35c359, - 0x9a204efd, 0x6df807dc, 0x8af9eea4, 0xbeead7ed, 0x479fb53b, 0x5741abb8, - 0xb165838c, 0xe81333f4, 0xe67370e1, 0xa700618c, 0x4deb1472, 0x3c2ed07d, - 0x755e2be5, 0xafd01074, 0xbee3cb14, 0xf31e5839, 0xea3cb079, 0x53f2c72b, - 0x11960d5f, 0xfe58dddf, 0xf2c7e7c5, 0x2c7adf63, 0x63d5f23f, 0x01afa1f9, - 0x017df7cb, 0xb6fb0f2c, 0x2f8ef963, 0xaf8b6588, 0x9f56cb09, 0x7726a582, - 0x71ddf13d, 0x093e1d75, 0xcf8317fc, 0xed7f3aa4, 0x7c9d09fa, 0x87dfc716, - 0xb9e1a67c, 0xf2acc1a4, 0x1f8e8a43, 0x4397c012, 0xbda1eb3e, 0xb0f95441, - 0xb763efbb, 0x6bfcb77b, 0x0fea6df8, 0x7e4eb7e4, 0x53f030ca, 0x34fc4f76, - 0xa7e28f8c, 0xb31726a9, 0xfa7e547b, 0x8623cc19, 0x8c0f315f, 0xf6513e90, - 0x826f929a, 0xbaa56c75, 0x601f420f, 0x763aacfd, 0x05b77d1d, 0x10c0baed, - 0x0ece3758, 0xd860dbf9, 0x21fb3847, 0xf7567e25, 0x49f233f3, 0xd05778f7, - 0xa01a59bf, 0xdaea4f44, 0x78638d6e, 0x31489ab5, 0xfddaeba1, 0x2f729e83, - 0x81758a1c, 0x01f7c224, 0x8c4774f7, 0x0cada97e, 0xaf09edf8, 0x72af8e75, - 0x8f63bfa0, 0xca0f3dfd, 0x2f6626a9, 0x68f335c7, 0x93f093b7, 0xc76fc06e, - 0xa77664ba, 0x7dbdbc41, 0xbb42e490, 0xe3d64c81, 0xc3a05fcf, 0x4714fddf, - 0xd6eeb82d, 0x06fe21a7, 0xbd38357e, 0x49ebf817, 0xcf84f7bf, 0x7fef3085, - 0xd27b3e01, 0x45e93d8f, 0x342fc8a2, 0xedb7f9d1, 0x80fb961b, 0x1e5ee30c, - 0x9afedadf, 0x7e5f9e11, 0x4b6e3e47, 0x25b8f8d1, 0xa41f8093, 0xc6d9cbca, - 0x2e81e32b, 0x40f4fd1d, 0x9f77ee4f, 0x7eff8264, 0xdfdf4b3a, 0xe2fec67d, - 0xa70dc225, 0x89243ae3, 0x92bf53c4, 0xd1e36cf7, 0xfc47719f, 0x67d83710, - 0xe0c9d773, 0xaffc9e37, 0xeb3d0cb0, 0x0f670be3, 0x3f04e93d, 0x5f1a656c, - 0x1d063473, 0x982ab2b5, 0xf68f6355, 0xf5f49a57, 0x715cf5b3, 0xc725e710, - 0xeb061ccf, 0xa8e6ab8c, 0x0d3f7a08, 0x959fad4b, 0x738e1269, 0x3c767b72, - 0x4c02fff3, 0x4048ec9f, 0x67d2737d, 0xd9fff7c1, 0x8fd774f0, 0x8d210f06, - 0xe80b33e4, 0xdd96da73, 0xcaddfbfd, 0x825e7083, 0x890929f8, 0x69bf815f, - 0x3b7fffa5, 0xb015fa00, 0x0debf5ae, 0x70f37ef2, 0x3743be78, 0xd64efd1e, - 0xbbe18cf6, 0x204ee5ee, 0xa7be34c7, 0xbaabfbf4, 0xbb62bdbf, 0xc76f46b5, - 0xdeeae826, 0x9d1af4a6, 0x00ff0b5d, 0x1386bdc3, 0x54ab0960, 0xb04db0d9, - 0xda7e07af, 0xf049c103, 0x5ef6385f, 0x79222595, 0x16971464, 0x6385d3e0, - 0x6797fe35, 0xa9ea99ff, 0x048a6f13, 0xa25c8ce4, 0xaea9e550, 0x899bf220, - 0x917d6898, 0xc6c2f6fa, 0x6eb02515, 0x26f9789d, 0x931643f4, 0xc7f82752, - 0x0f3ea4e5, 0x89a7b5e2, 0xf3e418a9, 0x39c77934, 0xad1e4a32, 0x2e9d8482, - 0xe3b7af5a, 0xabaf7fa9, 0xd7d06b2f, 0x525b9297, 0xe97edf60, 0x38049106, - 0xf6fa1bd0, 0xf61779af, 0xacd48cbb, 0x57fb7583, 0xa16bbc6a, 0x5419088b, - 0xf6fd556f, 0x0a32bcf1, 0x71604b87, 0x7a1f6d16, 0x7ff32279, 0x2406662a, - 0x59ffbe85, 0xa95bc8e3, 0x07dfa206, 0xbc7ec1d6, 0x6f713a7f, 0xf7e95d23, - 0xc237e15d, 0x5d03d9ab, 0x3855c3f6, 0x4a73b792, 0xcb1e8620, 0x67263814, - 0x102bbeaa, 0xc7b8ba5c, 0x7bfd4334, 0xd13253f3, 0xde1ed3f1, 0x668c2793, - 0xc0fc03fc, 0xe792ed09, 0xd69ff487, 0x7f82ffa5, 0x68fdff6a, 0xfeba79ff, - 0xfb53fda7, 0xfe05d81f, 0xaffab179, 0x2ff3edfa, 0xa93ea9fb, 0x4e97f178, - 0x13c9d742, 0x9b8a7d42, 0xdb72b5d2, 0x96854ebd, 0x13bf05c7, 0x8044f5f8, - 0xef458e2f, 0x154e0587, 0x41cec542, 0x49fe0ddc, 0xecf93ffb, 0xf11e30cf, - 0x85d136d5, 0xe6edb4f1, 0x61ca99b0, 0x12f2e375, 0x23f58392, 0x19df7eac, - 0x7a4dea1e, 0xfa78abfe, 0x1f902997, 0x8d453942, 0x9ed1852f, 0x79fadead, - 0x5e4fac11, 0x64728ed2, 0xbfc60efc, 0xaffa8898, 0xdaef8a4c, 0x38c4e14e, - 0x8bc55781, 0x6767f1b7, 0x37942778, 0x82fa017c, 0xc7e8227a, 0x572bbf1b, - 0x8235d4ed, 0x8d98f923, 0x190c7bfe, 0xc3517a03, 0x3b30090b, 0x5f99eeb5, - 0x70a11ce7, 0xa6fada9d, 0x97c28b93, 0x83674f26, 0x8f73fe8b, 0x6ddebddc, - 0x6d16f2a5, 0x96eb690f, 0xd7daa4dc, 0x8a565621, 0xf3e42761, 0xdd166e54, - 0xf2b8fa7e, 0x7a9f27f9, 0x7f99e20c, 0xd107bb32, 0xff3c57fe, 0x69e3fbda, - 0x314ec57d, 0xc34d84b9, 0xd274a5ce, 0xbfff4bc7, 0x1e93b73b, 0x4d79bf15, - 0xe7b18792, 0xd27624f7, 0xfdcec565, 0x15d61912, 0xfb83931f, 0x063d88a5, - 0x8a47827d, 0x7ba85ec0, 0x8825bfe6, 0xc7d89e33, 0x18acd491, 0x1afcdcf8, - 0x278003da, 0xaf4aa7a4, 0xde19fa0e, 0x80ba52f7, 0xcbd236de, 0x5522def8, - 0x90bf40bf, 0xfbf94167, 0x07903d85, 0x0dd991f5, 0x617f2878, 0xf3e61395, - 0xf8c35085, 0x537bf1fc, 0x8b959f40, 0x961714fe, 0x13f979ec, 0x5bfe423f, - 0x528ff6f6, 0x9444be30, 0x45ae1374, 0xe79874fe, 0x70b34d92, 0x07894b9e, - 0x71fcb0f9, 0xcb4034be, 0xde29020b, 0xac4e4319, 0x2f939322, 0xd2e250b6, - 0xfe017e79, 0x77efe824, 0xb436c0f8, 0xa024efbb, 0xcea47e0f, 0x580c5a85, - 0xf46160bf, 0x2ebaabfa, 0xa33eb010, 0x7deb77f9, 0x93a7402d, 0xd85495fd, - 0xc112f177, 0xfb83e2af, 0xbfcbf696, 0xd195253d, 0x9e42c889, 0xf75d1dfa, - 0x7873c327, 0xac5445bf, 0xc8efba39, 0xe39d59b7, 0xa7c756af, 0x7ac1c770, - 0x6c4a45fd, 0xd44f35fb, 0xb75d00f4, 0x4a2cf8a3, 0x6ffc99de, 0xbbc99fbd, - 0xe981ff26, 0xfe7ed0c5, 0xf8239330, 0x0a43d60e, 0xdb153857, 0x50e4cff7, - 0x3a3f503f, 0x156f9c96, 0xb7d73955, 0xc285f91b, 0x51f1702f, 0x24e3037c, - 0xdf701d22, 0xfa06e965, 0xf51e947d, 0xaeceb8c2, 0xbc726afd, 0x455bf34c, - 0x9b203ebd, 0xdee81e98, 0x9e23f2ae, 0x53c0c52a, 0x52fc818f, 0x20cbf579, - 0xcc2962bf, 0xcd1dcbff, 0x72a3cfef, 0x935065fb, 0x355ebd5b, 0xaef96dca, - 0xdc9624d1, 0x9377697e, 0x9f4b7298, 0x7b5b94c7, 0xfff9f904, 0xf0d55eb4, - 0x78f00c38, 0x351e274d, 0x3e1dd93d, 0x90f27a8d, 0x8d5e2320, 0x1dfe927a, - 0xf95d7926, 0x8d43e351, 0xab9e2aff, 0x51f402ba, 0x7c6a9f07, 0x1aa7c1d8, - 0xef89761f, 0x6c68f0ea, 0x34fb00bf, 0x96f9ae14, 0x528ed38d, 0x4ed2d257, - 0x7f26df70, 0xaafb8f26, 0xe584f396, 0xf3111081, 0xd5303f43, 0x753b068c, - 0x3d6fdfe2, 0x7785177d, 0x2c8bf13e, 0x445ea02f, 0xb7d2ffbb, 0xf3a04edf, - 0x79e2a799, 0x54fb453e, 0x0239974a, 0x70a38e17, 0x3f8815ce, 0xb7e2113e, - 0x0a34f91c, 0xfae5f98e, 0x4c4dfc3a, 0xa7a7ece9, 0x9fabbff7, 0xb7cb7df2, - 0x1d3f5d29, 0x50bbc844, 0x10bc388a, 0x81d357cd, 0xde7f14ae, 0x00605c51, - 0x5088a9ea, 0xbd77e51a, 0xf3fb3220, 0xa319c2ed, 0x9fc9bec1, 0xf19e2c3d, - 0x7bf460fb, 0x3b3eaabd, 0x41e397eb, 0x650d9fcf, 0xf67b7fa3, 0xac4722d0, - 0x9566d0bc, 0xf7535ecf, 0x5cecda5d, 0xbff94f3d, 0x7da3b48d, 0xc95bb7e3, - 0x82fb18b6, 0x5f4d451b, 0x7fa374ab, 0x8e7f1d3c, 0xe97387ca, 0x51b9f1a7, - 0xf5399b74, 0x4aece084, 0x34fbf807, 0xa1fb0fca, 0x06be05f8, 0x235b36fc, - 0xe231a545, 0xf8a9cf79, 0x6be0789b, 0x0c2dcfcc, 0xc7800be5, 0x8baf3b42, - 0xc9a93c83, 0x143250eb, 0x60789ae0, 0x5347cff9, 0xe21ef63e, 0xeb8f90dd, - 0x3c919d0d, 0x2361fc31, 0xb07fa13e, 0x2e888f33, 0x627bd7c4, 0xebc012e9, - 0x04acb37b, 0x95df35f6, 0xe0b155dc, 0xf5b3332c, 0xbd292e66, 0xbffb8a30, - 0xb3f9bf0f, 0x8a02e11d, 0x9676b38f, 0xff95ddf7, 0x759fdc98, 0x0e5a8171, - 0xf56790f8, 0x71002e64, 0xf9e222b4, 0xe50e04f9, 0xfeb4527d, 0xfe9a6fca, - 0x54f5e43c, 0x89973887, 0x110b57b6, 0xdbd8f809, 0xfb0053b4, 0x289926fd, - 0x6a108f18, 0x8a8ccd86, 0x05111d7b, 0xdff357c4, 0xf80edde6, 0x4cd3373d, - 0xe8652e00, 0x01d82719, 0x512342e7, 0xd79bba0e, 0x5a647c1f, 0x10fd08a1, - 0x3f230fe4, 0x74db2514, 0x499359f5, 0xdba5373f, 0x95647344, 0xeafd063b, - 0xbd67c624, 0xff966fd6, 0x04dbf4cf, 0x5f18dfaa, 0xedfad18b, 0x7df18926, - 0x8d4b7e94, 0xd656dfa5, 0x17c0a9ca, 0xa766f72b, 0xbe575d02, 0x2c4fa4b1, - 0x8fbaf6fd, 0xa86ff7f9, 0xfd6de679, 0x1e1b7ea8, 0x51fadfa5, 0xae2316fd, - 0xa5ea5a3b, 0xcffcb37e, 0xa0ebdfc8, 0xb7cc62df, 0xa69fc558, 0xb5438adf, - 0xfb8adfa8, 0xa97cbaf1, 0xfa4f5249, 0xb397ecad, 0x6dba2eb0, 0xf007f831, - 0x0dedfa0a, 0x38c1cf55, 0x5dfee7a0, 0x3d277d72, 0x3d5bd557, 0x67843ff7, - 0xecadcf4d, 0xd33da1cf, 0x9e990f95, 0xf4c5995b, 0x4cbdcadc, 0xc41cadcf, - 0xbf519cf4, 0x6fd17415, 0x21eafbec, 0x23f47bf4, 0x1b7d7eb3, 0x23992f6d, - 0xfdf42dba, 0x9f3b5912, 0x5a3a3351, 0xd4bbfddf, 0x9f73be8d, 0x3d2e73c1, - 0x823fbbe9, 0x7a841bbe, 0x91c8206c, 0x1c6e3f91, 0xd3e5d368, 0xb1f5f7bd, - 0x79045ee7, 0xfe8f03f9, 0xe62607f7, 0xfafbed27, 0xbb9048d8, 0xaa1e00f7, - 0xf9519eef, 0x47e7d5af, 0x28793a7d, 0x7baaf793, 0x1baafe18, 0xd5df3639, - 0x7586407c, 0xd1176fe0, 0x2f7dbe8f, 0x9b67a3f3, 0xc0d8fa5b, 0x225fffcf, - 0x2bfd25ca, 0x87e28b29, 0x302b1739, 0xce2bb9ee, 0xccfc05b9, 0x80b10239, - 0xd0e0bb1d, 0x7ec0278d, 0x3d71705d, 0xe00bbdda, 0xc8e92279, 0xa1db98fb, - 0xebf6f527, 0xaf9da6bc, 0xf9ae9065, 0x8ccd1310, 0x7157132e, 0x5d59cd81, - 0x5da823f3, 0xc62df986, 0xabdf893c, 0x47cd9ff3, 0x8fe45f10, 0xe5f8cc7c, - 0x72788def, 0xad54bc33, 0xaa78f5e6, 0x89e262e1, 0x2ca4ba52, 0xb72f13a5, - 0x975914bf, 0x39cbed01, 0xf38cb7f4, 0x9c66f0d6, 0xcd4786bf, 0xbea059bf, - 0x24743f3f, 0x86889e66, 0x22f92ee7, 0xf80dde1a, 0x33d34b78, 0x206190d7, - 0x3c981f97, 0x7c0d1f3f, 0x178a7bf4, 0x73ade70a, 0x2bcee907, 0x65e2a3bd, - 0x6148e7aa, 0x24780c8a, 0xf367c035, 0x96be77ca, 0xb377e742, 0x210b9592, - 0x937f59f5, 0x688f103c, 0x1ea3b6b6, 0x9470f8d4, 0x5985c999, 0xf5ef2bd5, - 0x7ae21575, 0x50b9c4d3, 0x3d06c2be, 0x7999e6a7, 0xd7f261ef, 0xbaf7fdcc, - 0x6788518c, 0x91482e58, 0x5d015eb6, 0x86a73fe8, 0x40bc5d18, 0x69cffa17, - 0xe020fda4, 0x73993abd, 0xa6fde187, 0x3f02f79d, 0xcfa56ebd, 0x39cbce41, - 0x0e8616f7, 0x65ca7a7b, 0xc58858f9, 0xc8cc18c7, 0x173f5ceb, 0x5d897bc0, - 0xe68993ed, 0x8e00f796, 0x366e5489, 0xfd00c3c3, 0x46fe8a2f, 0x07c8c5fb, - 0x7503e53d, 0x2ab9efc7, 0x3a075f9e, 0xeddf01d8, 0xde43d812, 0xb47f5b30, - 0x1720af76, 0x3a34de22, 0x65f5d134, 0x2983a314, 0xd66f9e06, 0xbd9e2aea, - 0xef844e21, 0x6ffea06f, 0x7ebb0712, 0xf8d41f5f, 0xc5772cdd, 0xd215c413, - 0xe806f4a3, 0xcd7de8b7, 0x11b7a6ea, 0xa6ae375f, 0x15dc99e6, 0x407d1a5f, - 0x6f0e5e0f, 0xd34fcadd, 0x61799891, 0x467e55df, 0xb3f2f599, 0xe6fedacf, - 0xedab8870, 0x90af50e5, 0x7e2e8250, 0xecccd330, 0x07ab6696, 0x0dfdbcf9, - 0xee45bdd1, 0xa8a67faa, 0x257f0174, 0x64e27cfa, 0x4de80898, 0xa67c9597, - 0xe3007bcd, 0xe0f5e8b7, 0xe907ab75, 0x33ff5dd7, 0xedfecccc, 0xead31ece, - 0x9078c3d7, 0xc7eb28d7, 0x5a47ae33, 0x79a7a95c, 0xbf71d479, 0x71b4bcef, - 0x84beebbe, 0x3c60b497, 0xd89fdb4e, 0x89767bc3, 0x73163f60, 0x0a107dba, - 0xfe6fee39, 0x59bffa13, 0xff7ddd1a, 0x530a3f10, 0xe3bebf3c, 0x9f638c49, - 0x34c8f67e, 0xaf159f90, 0xe542c4f0, 0x838775af, 0x889e5984, 0x45427604, - 0x5dfb8f23, 0xcde70844, 0xa833b288, 0xf1f0c327, 0x5ef503a2, 0xa0732ec5, - 0xf15f7e84, 0x103967f2, 0xc35d6b7f, 0x59ff9ff4, 0x91fd1f95, 0xa807c81c, - 0xbcfed810, 0xa88f3e91, 0xb76a79fc, 0x6fe80e6d, 0xc73b3b6e, 0x2d9c115b, - 0x0ce2a39a, 0x16459bf7, 0xc36ddee7, 0x33ff6c3c, 0x0331e61c, 0x48e7d17c, - 0x53d0fcb5, 0x5cbd30cf, 0xe00624d1, 0xf6c5703c, 0x1710ad9d, 0x8cd0f8af, - 0xfb77abf6, 0xd3ec0919, 0xcf3e2fc9, 0xf1371bce, 0x976878ba, 0x3e76e438, - 0x59f8866c, 0x01ea1563, 0xf5823f5a, 0xfbf71aa0, 0x15b2718e, 0xd97dee2f, - 0xe2b8514f, 0xf13b4f37, 0x36cb705c, 0xb723c627, 0xa05f7e5f, 0x7831dc4b, - 0x9c771abf, 0xf5c105fa, 0xf1dc7621, 0x2127caa4, 0x48ee3eb3, 0x3c6127b6, - 0x5799c292, 0xd17e231a, 0x5fcfffc1, 0xcdf60278, 0xf2faed4e, 0xf2bb8009, - 0xfc4f739b, 0x2a93e294, 0xdbac1720, 0xc3df67de, 0xbbed067d, 0xd27d55f7, - 0xb8d3ccfa, 0x27fad34f, 0x6b7a1bb3, 0x2645fbdd, 0xeeb453ec, 0xe2053afc, - 0x4ef7abb8, 0xf56d7f41, 0x4953934b, 0x2b407f0c, 0xbd037f81, 0xd23227d8, - 0x39b1b9ad, 0x4d3ce013, 0x77eb0ee9, 0x58393c47, 0xb2f4e2c5, 0x11de471a, - 0x4bae5f7b, 0xc671b8dc, 0x3ac1d7cd, 0x65ba28de, 0xf1f88bd2, 0xe1cf4a61, - 0x0ee3a0bd, 0x38209f75, 0xe3f1b2f5, 0x4a0ff0d3, 0x7d660baf, 0xe342fe1c, - 0x0c7cff92, 0xba931ada, 0x7b871f8d, 0xdf6d3f81, 0x2159bf6f, 0x5da39016, - 0x1edc61cf, 0x0f7d47e8, 0x85fcfad2, 0x1cbb884c, 0xc0efdb17, 0x66bdebfc, - 0xd8aaa3cc, 0x53ca01fb, 0xe36f4beb, 0xf7511abe, 0xc7495adf, 0x5127db1f, - 0x56ef3a7d, 0xab3b8b07, 0xb4b88074, 0x6ae7c4ec, 0xb5f199fc, 0x2eee9716, - 0x32d63d1e, 0xabbfed80, 0x5b5591fb, 0x43112cff, 0x0b1b9fbc, 0xd9723af4, - 0x0f0d547d, 0x98c3c02e, 0xd896fde8, 0xfd8efff1, 0x80dd0316, 0x758f609e, - 0x7ad0a7ec, 0x07ab883f, 0xed620fb8, 0x666eb5df, 0x62ad34fb, 0x6d45bcec, - 0xc5a465ff, 0xe812efb0, 0x4f4bbedd, 0x78aef8f3, 0xb42706ca, 0x9d7c574f, - 0xbf5b14ba, 0xd4e16adf, 0xe7be037b, 0x67257ebe, 0x05981bcc, 0x78d5597c, - 0x4a7b0244, 0xf9b4df5b, 0xe7fd529e, 0x78f2cf53, 0xb05d644e, 0x51bbf519, - 0x1613547f, 0x5bc23437, 0xab7a616e, 0x1fad89ba, 0x023976a7, 0xa9cfda76, - 0xaf91bb03, 0x911c77ab, 0x83bfb4fc, 0x45237fdb, 0x60acf2a2, 0xc14408fd, - 0xfd85ea7f, 0x897f6c39, 0x71c6ebf9, 0xf1c752ee, 0xe38f6286, 0x374671dd, - 0x507f0ace, 0x2e7ee762, 0x4149de3f, 0x9dfd0d99, 0xe409116c, 0xf20c9ffd, - 0xe31881c5, 0x5a88b5cf, 0x0fc98b3c, 0x1cf1475d, 0xbb9d83a6, 0xb42513e4, - 0xc63b57bb, 0xfde7087e, 0x19243b57, 0xb57517e2, 0xeeb52f2c, 0x4069dcdf, - 0x5b84baef, 0xdeae3f71, 0xb2575f80, 0x1ae21f2b, 0x51d2c2ae, 0xbd46aec0, - 0x7498a093, 0x1476aff0, 0xce14caa7, 0x469daab5, 0x0b9e3704, 0xc5459de5, - 0x65de1f30, 0xec635972, 0x52f6883b, 0x8bc289e2, 0xe39fd2e8, 0xca469724, - 0x7f968fd0, 0x39696953, 0x052e8d88, 0xb1858c53, 0x99fcddec, 0xdb779c2e, - 0x507fd50e, 0x614aec88, 0x8eb06479, 0xcf8aedb4, 0x43f1c321, 0xb47e50a2, - 0x1db9cfa9, 0x5e83f7fb, 0x4a24eb5a, 0x8a339502, 0x86cf9955, 0x2c23acf3, - 0xe9f0365c, 0x857aff99, 0xf10d6bf6, 0xd9b457e8, 0x25527cb5, 0x46cce401, - 0x41bcc41e, 0x936fe560, 0xe634e13a, 0x25781213, 0x298d3eea, 0xa1fd1dbc, - 0x7c589bb3, 0xff572780, 0xcf8b027a, 0xafc00091, 0x542b2fae, 0xe212cf38, - 0x3bfbc30e, 0x580f181c, 0x9422c6f6, 0x3443a01f, 0xf58a92be, 0xac1b5ee7, - 0x67f01cce, 0xbf555a36, 0xc0b4afc6, 0x6ac59b39, 0xf54a7dbf, 0x18a962e7, - 0x975e41fa, 0xe5faf2a8, 0x9843a2d2, 0x8a59e68f, 0x8e753e7a, 0x31acdcfe, - 0xaa204b4f, 0xfe601c9f, 0xadbc9773, 0xb708cda6, 0xc56b7f31, 0xc35d7d76, - 0x37a027e3, 0x127402af, 0x80e2e5fb, 0x3237e23d, 0x4613d7f8, 0x9afc777d, - 0xb5f8f4d3, 0xdafc7aca, 0xa7f11886, 0xadc3afc7, 0x97e697c7, 0xf8df8776, - 0xc873fab1, 0x8afc2aff, 0x548ed556, 0x4aff4af1, 0x654c292d, 0x42e9dc03, - 0x28c2e518, 0x30f61947, 0x9feeff07, 0xafc5a81c, 0xefd40edc, 0xb87cea69, - 0x1b3becc5, 0xf00f11c8, 0xe08e51ba, 0x79e82024, 0x75d8f91b, 0xfac40acc, - 0x4d7b7c8c, 0x355cf4f7, 0x0b23d5fd, 0x809b57e9, 0x3f23877f, 0x89bef3b0, - 0x05975024, 0xc176ea72, 0x59f41dfa, 0xb8458bdc, 0x17b885f7, 0x5efb820f, - 0xa43e585c, 0x0db4abe6, 0x306e7825, 0x029f3e18, 0xdca1e9fa, 0xf7a069f6, - 0x29484bbc, 0xc51fc1e8, 0x0f03f3b1, 0x38bf65a8, 0x85abd549, 0xef824c6f, - 0xe70ca243, 0xdb42dbd5, 0xdea0832c, 0x2a3de3c4, 0xabfa84de, 0x90d6fc60, - 0x6c5ae0c8, 0x38820c09, 0xc7115ec8, 0x013c5d6d, 0xd87665cf, 0x2f96216f, - 0xccfa16d2, 0x9f4a28b9, 0x7a3d36b7, 0x36b9c415, 0xa9e7629a, 0x7e9ab14c, - 0xec1bfad8, 0xc537b792, 0x1eeaf2ca, 0x51e7401a, 0xbaacfd3d, 0xb879330e, - 0xabf3a556, 0xf9c46f4b, 0x64e214bf, 0xf88a4758, 0x461a6edb, 0x3dee39e7, - 0xb0cf8d41, 0xf528e578, 0x2fd03afd, 0xdfeb5fa8, 0xddc3e9e5, 0xe7020547, - 0x2cd546f4, 0x15eb7f45, 0xca73e527, 0x704a7917, 0x616df024, 0xcdef0128, - 0xd04c7ef1, 0x22dd1fae, 0x4f33f8e8, 0x22f3575d, 0x44c05e54, 0x3edf50f9, - 0xec18222e, 0xfc0f00a0, 0xfd71ed75, 0xd55685f3, 0x149272ee, 0x970df3e0, - 0x5ef20e78, 0x7b89dadb, 0x6dbb850d, 0xa3845f71, 0xfa9c3ced, 0xbe25e5a5, - 0xbf7ad638, 0x62f8caca, 0x9d7044a3, 0x8ed4b8d9, 0x4b03c5f1, 0xf580ae2b, - 0x7b1fabfd, 0x8e7588ae, 0xc53f4a3c, 0x252c7cb3, 0xfe058c9e, 0xbc31cb5e, - 0xc697a7d7, 0xf8d7f7c8, 0x8d6fe359, 0xc697d3af, 0x35e56279, 0x7665637e, - 0x21d2c15a, 0xdafe049c, 0xe38f0e3e, 0x5cf1aeb6, 0x9f8ddcf6, 0x7800c9ac, - 0xd0e74dbc, 0x3884b6ee, 0xb1bd9625, 0xfec4eac1, 0x6bf8d75b, 0x2eef8f21, - 0x27a09c2a, 0x0377efbb, 0x813f5bfa, 0x677c2ca0, 0x73c32fa9, 0x642c4bbc, - 0x85bbc40b, 0x1c5bf4fa, 0x6f93ffc0, 0x7de14758, 0xeb84d4ac, 0x8dd146eb, - 0x08abfbf0, 0x1a83f8c1, 0x8d37edcf, 0xcf3e8e6c, 0xff3584fc, 0xc7a52b59, - 0xd21756b3, 0xe6e3c925, 0x3ff77e00, 0xf209dbfe, 0x8cd176dd, 0xfaabec74, - 0xaf77da43, 0x36dd9959, 0x0ad94e33, 0x64f293df, 0xc7b71394, 0x123c5ee9, - 0x78a04dee, 0x4ea3928f, 0xbbf1f9fa, 0x71d50f44, 0xbb449e14, 0x2892f909, - 0xc5d2ec8a, 0x4728fd29, 0x30905c9a, 0x4d8f2047, 0x885cabd3, 0x1ca83b0b, - 0xc3d8b28c, 0x962477e0, 0x105379d3, 0xfac2c4ac, 0x754e116b, 0x3cc6cb9c, - 0x7997ca79, 0x608a3870, 0x71121448, 0xdf4d7fa1, 0x6d7a7a6a, 0x59794102, - 0xa810b0fb, 0x126cfda3, 0xaf885622, 0x01722964, 0x0a251aa4, 0xef179e32, - 0xff304e5f, 0x78fd96d2, 0x42dd8742, 0x37c47e85, 0xfb5882fc, 0x869c7c79, - 0x401fcf2f, 0x6a1ce46f, 0x8de6003f, 0x73c6cadb, 0x3b4166bf, 0xa87f43bd, - 0xba9158f6, 0xdcfb8efe, 0xc209f2c4, 0x3ef44893, 0x687f519b, 0xebb8c9f6, - 0xbf606b22, 0x189fdc68, 0x055bb49c, 0xcead1bbe, 0xa89f43b7, 0x1098e6eb, - 0xfbf427d5, 0x66c8d0dc, 0xf72b07b8, 0x5dc72663, 0x3f21c9f4, 0xbefbf80f, - 0x17c8c47a, 0x2e54c223, 0x32a1f6d5, 0xeae1a7dc, 0x19fb43a8, 0x9e49de83, - 0xed152a3e, 0x8cdf955c, 0xdbe4d678, 0x77b9f728, 0x0ccd9bbb, 0x1a47e62e, - 0x275c21c6, 0xe836721c, 0xb078b7a5, 0x29f2dbf7, 0xbf5c281e, 0xf4a3f902, - 0xb81f384b, 0x21bfe601, 0xe415bd74, 0x27af7be4, 0x5475fa21, 0xbcd3f69e, - 0x0fae3e27, 0xc04e27ae, 0xf3fef543, 0x46127aea, 0x01c8777a, 0x78e89395, - 0x46ffc689, 0xa3e4d77e, 0xc8de2e0e, 0x047673c6, 0x0b9e59d6, 0x663065e2, - 0x7805c9b2, 0x3aedecd5, 0xfe25bed5, 0x56ffb474, 0x1eba88bb, 0x4f800665, - 0x5ecd44ea, 0xe3a25b77, 0x051dab53, 0x4fdb97a9, 0xfea45ef5, 0x1b39d459, - 0xfe8ed0af, 0x84a2f79b, 0xfe37bfcf, 0x7914289a, 0x898dfc3a, 0x7f15dd1b, - 0xb08471f1, 0x9ffec2fb, 0x230cdf9f, 0x7727dc7f, 0xe25aefce, 0xf5422579, - 0xf5aade47, 0x3f193675, 0xd7969c39, 0xfb682f55, 0x01e9dd9f, 0xa98fbca3, - 0x70c66fac, 0xeef20f4b, 0x25f8a9b5, 0xb3e80664, 0xb76a61f1, 0xff957564, - 0xbcfceaf3, 0xb6f78636, 0x8307db5b, 0x3de7ad3c, 0x2f687135, 0xb0264c46, - 0xb413762b, 0x8ffbdc7b, 0x5bde513a, 0x4feb7492, 0x8fc0bb57, 0xa7d9a9f2, - 0x7c6a5d9a, 0x552ec3af, 0x3e2d1bd7, 0x795135ca, 0x193cf0a1, 0x1c03f1e7, - 0xbfe62e75, 0xd05701c2, 0x3d584f63, 0x365fc075, 0xd838973a, 0xce12192f, - 0xb096f162, 0x93bb3e4e, 0xde419b47, 0xb03f1482, 0xfae9f9fe, 0x1eeb8837, - 0x0971b19e, 0x85aa5e0c, 0x97e9bec0, 0xd560d847, 0xfbc7f304, 0x6bfbb0e5, - 0xfbb2e5fa, 0x31c73732, 0xa18b65fb, 0xfa5ac27c, 0x144bcc18, 0xfb9cdf88, - 0x5006e1fd, 0x64f90e21, 0xf800d29c, 0x382b14b0, 0x71170c8f, 0x19de9473, - 0xbc839042, 0x994ac489, 0xd247f163, 0xfb48ffb9, 0xf39128cb, 0x06323f81, - 0x9a373c12, 0x9e7d8a11, 0xf13895e8, 0x8debd987, 0xbcc1ce5d, 0x41cfcaa2, - 0xa937ce89, 0xe9839d84, 0xf050fb88, 0x8eadbf01, 0xadb2715b, 0xab3ed817, - 0xd9e1813f, 0xc101bfe8, 0x5a825e60, 0x822257bf, 0x2bfd1135, 0xdfaff03f, - 0xcaff4164, 0xd041dc46, 0xb1c41fb7, 0xce3aecf8, 0xbfea1ebd, 0x702dda10, - 0x37268fcf, 0x343c3c9a, 0x40b716e1, 0x775e755f, 0x5f7c0736, 0x00ef172a, - 0x9c275b9e, 0x6716bc1d, 0xf8c99ed2, 0xf975e14e, 0x9afd1af6, 0xacfd1d44, - 0xd6895710, 0x08690ef3, 0x5cadedd8, 0xaafc1b9c, 0x831ce5d6, 0xe7a8b397, - 0x3cdd0411, 0x1fcc6cd3, 0xe7f55369, 0x90b2e3df, 0x84f5b51f, 0xc63d6fce, - 0xe8f30d7f, 0x386a8738, 0x973c6a77, 0x11dd969a, 0x7cc74a07, 0xee0952dc, - 0x43672332, 0xbce3b436, 0x124cf6ce, 0x6a64bce3, 0x5cf31ac4, 0xbc5256b0, - 0x4b780d7d, 0x40126b15, 0xcedea71f, 0x1f1188f4, 0xc47f9c6d, 0xfb47d841, - 0x1f331883, 0xd2d32b45, 0x4c584a6e, 0xbf4b4fdf, 0x79ed4b01, 0x19885d83, - 0x71b24c57, 0x64dcec3f, 0xfc18b103, 0xed1b24cd, 0x9de7b4ef, 0xff1415f7, - 0x37bb8c76, 0x37bc31c4, 0x37bc31c4, 0xe53e1a48, 0xcebf9078, 0xf7975bba, - 0x4967c1b4, 0xd10f2010, 0xb9f28e9f, 0xdde8c5c4, 0xf682bef9, 0xdca21f4d, - 0xc4941730, 0x436c9106, 0x21f167be, 0xafc87ced, 0x4024cf7c, 0x96db94be, - 0x16fbfaa5, 0x0604df46, 0x530df9f7, 0xb214dc70, 0xe2983ac6, 0xc9a96979, - 0xd3a3710d, 0xc2723f0b, 0x1985e991, 0x0f20792d, 0x1b8f79a7, 0x984a97e6, - 0x8e6cb85f, 0x2ed30814, 0xc2a81b93, 0x01ba7462, 0x4ccb3bf7, 0xc7aef331, - 0xe9fed8d8, 0x961738d1, 0x90d36969, 0x92f59d4e, 0x8c4bf004, 0x35e54a7c, - 0xcea8f17d, 0x6f94cc73, 0x790c5b14, 0x1349136b, 0x185beb87, 0xb1ac95f1, - 0x35b7aab3, 0x39064979, 0x52ab7d84, 0x3a3547aa, 0x4d5f500f, 0xfe28b8c1, - 0xbfd7a171, 0x79c37f06, 0x45ea015d, 0x10c88e4d, 0xa0ade7a6, 0xa1e2a377, - 0xe83f7b6d, 0x9f8efb0f, 0x0739dbfc, 0x55fd3bec, 0x9e807768, 0xbbcf7e3d, - 0xf4c7380e, 0x2e2c3dc9, 0x4fc18772, 0xfa63645b, 0x74ad8f7f, 0x8177e01e, - 0x9e791fef, 0x77257e28, 0xe593fdb3, 0xde70de01, 0x506f7f5d, 0x70c93055, - 0xf11f908f, 0x1fdea55a, 0x46c7a466, 0x2cb78b1b, 0xca59b1df, 0x4f7c6190, - 0x5c7f8c25, 0x378f43f5, 0xd1dfd03a, 0x63b859e0, 0xd9be0484, 0x7566435f, - 0x6445bdff, 0x025287eb, 0x151e67fb, 0x0f38466f, 0x2f6af7aa, 0x8fcb25f9, - 0xdd63a329, 0x27b0f54d, 0x187bcec4, 0x13e4b1e7, 0x129528b9, 0x1cfdc96f, - 0xfef0ddfa, 0xf33d743d, 0xee1f7ddc, 0xd9e719b3, 0x051f5ef5, 0x2a65b3fd, - 0x6de78dbd, 0x3ed88597, 0x41e262f8, 0xfe72ecf9, 0xc5cec436, 0x678de318, - 0x00db650f, 0xa9b0bf0f, 0x323cc4f1, 0xef6dce06, 0xfe20343a, 0x9f56f772, - 0x828bef52, 0x3ca1bb7b, 0xce5823ee, 0xe2902303, 0xf6f432bf, 0xd55fc05d, - 0x3ef13b4d, 0x8faaefb4, 0x9c2742aa, 0xe9ad4b90, 0x6e876a25, 0x8b20f903, - 0x5a7d9d39, 0xc49cf9bd, 0x9f866afc, 0xb7e7d4db, 0x20723e01, 0xd9fe5bdf, - 0xdbef4a04, 0xd1f3c52a, 0x6f3da5f7, 0xf7c3efd3, 0x3cdabe76, 0xed6b79b5, - 0x9c5e6a55, 0x0e4d3bf1, 0xb97ca9e6, 0x75f4eb78, 0xea8a297d, 0xa9917ef6, - 0xf3c3939e, 0x2d9f1a42, 0xe945a523, 0xa349f831, 0x84df076f, 0xd3f38e7e, - 0xbeb8bae8, 0x3f83c54c, 0x4c4fdd4d, 0x91957883, 0xa73a7a8f, 0x32462add, - 0x7c8dbe41, 0x7dcddad2, 0xb31b2128, 0x4acb162f, 0xa8cfc411, 0x15cebbf9, - 0x171cdf65, 0x14fe0fea, 0xe32b6ee4, 0x083d0efb, 0xf7e8314e, 0xff5c4537, - 0x54e43a57, 0xe90fffb8, 0x13f20e37, 0x4f787ecc, 0x4f98e71b, 0x808a0651, - 0x4f2c62ff, 0x81954afa, 0x97db3a83, 0x04e73c6e, 0x086dbbfb, 0xab51b8c1, - 0x69ef0f43, 0xe37a8f1b, 0x4a8f4ab4, 0x3f9be5a1, 0xdadace83, 0xc7177982, - 0xa771a92e, 0x58e2e64b, 0x39d8b4f3, 0x7778bddd, 0xf9a872a8, 0xfa540b35, - 0xfb6211dd, 0x4d370be9, 0xc9747a47, 0xa1fd54bf, 0xf50e46b2, 0x4b3e918e, - 0x3e63d7dc, 0x3e40a2da, 0x5e85df7e, 0xbba441e4, 0xda776e91, 0x371eec5d, - 0x7b8246a1, 0xe26d8eed, 0x8571ff70, 0x73ff7b10, 0x9df4ddb6, 0x479c63e6, - 0xdb2ff077, 0x2faebb5a, 0x908ff981, 0xf08dcf80, 0x425ff36b, 0xd4a7a614, - 0x2f3776f9, 0xf2c49912, 0x7f75d434, 0x815b9c39, 0x790793fd, 0xc6adcf96, - 0x35f834a1, 0x28f38d78, 0x7cf12be2, 0x8f035b41, 0xf877d979, 0x77067dd9, - 0xfd70e5ac, 0x9a4e8eed, 0x7bf6d15e, 0x30ca9baa, 0xfb43cb6f, 0xedb63b01, - 0x29f6c263, 0xcf7873d6, 0x0cf4b75b, 0xeea57cb1, 0xa30849e8, 0x374a62db, - 0xdebb3ff0, 0x0caf909f, 0x0a27de8c, 0x8c0ca0dc, 0x4122b7de, 0xb15957cc, - 0xf9eeba7d, 0x8e35768d, 0x9ef5eaa5, 0x24d48fe4, 0x696f8cc4, 0x9fc9a6f2, - 0xda778f26, 0x0a6f6665, 0x59198381, 0xd1879f80, 0x7afaa1bf, 0x3df99d9e, - 0xafa5cd0f, 0xa73c6f54, 0x3258a7db, 0x096bd196, 0xbbcf825f, 0x0f14bbd3, - 0xd8bdbd3a, 0xf8c3cfae, 0xe6d1f3a1, 0x3689c9a1, 0x189ca33f, 0x43d237bf, - 0xe919ef8b, 0xc007a462, 0x5bc67e09, 0x35816d7b, 0x38b7ce14, 0xaf7fb706, - 0x4d6ee115, 0xb9c0ac9b, 0xf9f4eacd, 0x3e01fe58, 0xb0fb074c, 0x768eceb4, - 0x8d87eaae, 0x225c5dea, 0x5ecbb557, 0xd9232ab2, 0x24d2a7b9, 0xb58993e0, - 0x17161991, 0x583e8f21, 0xa4f7045c, 0x32387c4e, 0xbff14203, 0x5646f07e, - 0xd77916df, 0xfcfb86e2, 0x690a8a4b, 0x2fd071fd, 0x95fa2fa0, 0x6efbe0db, - 0xf973c4eb, 0x1fdeccba, 0xcf9d2e65, 0xed66b1ee, 0xb33ed495, 0xf2aef5d0, - 0x4157e0f0, 0x4a5b2b7e, 0x542e218a, 0xba781109, 0xce2955de, 0xad872db0, - 0x7be9e3fb, 0x4f3cd91f, 0x76ee21d9, 0x8bae2d71, 0x94058795, 0xc588722f, - 0x573a0567, 0x6d6efd2b, 0x2993b51c, 0x5a26d77e, 0xd317e0dc, 0x97f07ee7, - 0xb22a26d7, 0xa35cf51c, 0x70077c1f, 0x7cb135ac, 0x0c6ffd82, 0xc65c8f8e, - 0x23efd82e, 0x34cfe025, 0x1a582cfb, 0x1725f3db, 0x37c8e79e, 0xb18978b1, - 0x76bb6dfd, 0x00ce49ae, 0x243ea8be, 0x1fc3fca1, 0x84559fd8, 0x613549c9, - 0x0eaad0e7, 0x53773c13, 0xcf08a87d, 0x84b9c0dd, 0xe07a754f, 0xa6ee735f, - 0x9e18af93, 0x44ae040a, 0xd0b71a88, 0xf9d5d56e, 0x9810d354, 0xdce3e10f, - 0xcf846e70, 0xa2ecd530, 0xa0afe7f3, 0xe087c525, 0xff70f372, 0x89e4fd4c, - 0x559fdc3c, 0x2d79aa27, 0xbe3e7626, 0xe557dd63, 0x39fb2b4f, 0xdd028f4a, - 0x25b1ff4f, 0x53f6c6cf, 0xe6d6afd0, 0x8429c75b, 0x35ed7f03, 0x7219e782, - 0xe0334993, 0xb19446cf, 0x47166fc0, 0x6c97caa2, 0x65fe9b3f, 0x9b36e940, - 0x7e53237e, 0x9fc1faff, 0xe3bbff22, 0x68b2ab4d, 0x59f8739d, 0x2e74c33d, - 0xef30b28b, 0x6bf565a8, 0xd006e74c, 0xc358e8ba, 0x4af1b0ea, 0xa3b33e17, - 0x143fc8ae, 0xba3171c6, 0x01ae50ee, 0x2c4c16fe, 0x901c23ae, 0xcb477f70, - 0x794b5957, 0xe2d1f806, 0x5d747a60, 0x3673c16d, 0x28179b88, 0xec4fe432, - 0xfa41ef51, 0x5786a5be, 0x7f4266de, 0x7fc04a09, 0x53e183bc, 0x54690ba3, - 0x5e3c81ae, 0x81ae5412, 0x0e7ebd7d, 0x7e83a24f, 0x96adf23f, 0x1bcfa089, - 0x0f28f9df, 0x82bf73ef, 0x2df233f5, 0xf9d243ea, 0xff6dfe9c, 0xe4fbd1cd, - 0xa9f91cfd, 0x03251df0, 0xec9cafda, 0x3951b722, 0x2c8853ac, 0xad9f8365, - 0x091b2ff7, 0xd91f4fd3, 0xa070af4a, 0x3ae3093e, 0x67bb13f6, 0x7e8dd400, - 0xec496933, 0x949dde55, 0x17ee3773, 0x7d346625, 0x85d610b8, 0x4a7bb1df, - 0xfcc14538, 0xee3b17d3, 0x9718236b, 0x373891b2, 0x9b898dc4, 0xd453f9a4, - 0xf1899af8, 0x945e7255, 0x87ceacff, 0x79085f7e, 0x2c6c63f2, 0x8fce81bf, - 0x823afd07, 0x848e58c8, 0xa0365938, 0x3df583d8, 0x4fe1f824, 0x588fff69, - 0xb2ca7c59, 0x8fe2e89d, 0xb7160e65, 0xe2c9c079, 0xf062718f, 0xe22bb016, - 0xd81710ce, 0x4b8f6d15, 0x0bcfee02, 0xdf709bae, 0xe309a0ee, 0x018b4fdc, - 0xb517ec17, 0x5bc8255f, 0x6d7f6748, 0x7eb5dd2a, 0xabe4911f, 0x0bf7ee20, - 0x9d3fab27, 0xbb8f304f, 0x801484fd, 0x0cc4dcfd, 0x3c744d4b, 0xd9839e69, - 0x1573bfbb, 0x043a04cc, 0x1811c6f7, 0x38becc7f, 0xb9e3d013, 0xe056b91d, - 0x4701178b, 0x66890f14, 0x5fd09dd7, 0x6f0a39e2, 0xf9673e16, 0x223c82fd, - 0xfc77e29e, 0xee19768d, 0x1ada7ad1, 0x56f311bc, 0xbde1379f, 0xee4a2fc1, - 0xf17f50e9, 0x3d02ecac, 0x305674fc, 0xbcf3e70e, 0x62f3e709, 0x2bd5fb5c, - 0x0c0fdc29, 0xc12ef161, 0xcfd00446, 0xbe40a982, 0xae5f3e93, 0xafa6b1f2, - 0xd11c8137, 0xc11c23fa, 0x29820c73, 0xcb48e51f, 0x276b6a27, 0x67d44f98, - 0xfc0f0b66, 0x8b5d371c, 0x8879853b, 0x25284d17, 0xb04dcf68, 0x05ce788b, - 0xbce199f2, 0x0f5544db, 0xb2b8fc4f, 0xbb07e584, 0x9ebdc30f, 0x7ef576cd, - 0x739f7530, 0xd727ca92, 0xa16f0891, 0x245dd7ed, 0x4d27886e, 0x8fdfa8ba, - 0x5f60ca78, 0x57fb514e, 0xf0855dda, 0xede89f38, 0x450d29bf, 0x2c3d6027, - 0xfc008a20, 0x6862d934, 0x09d23b07, 0x9febf0f7, 0xfd50e03f, 0x19924cdc, - 0xeda6c79d, 0x87e14d43, 0xb5fb446e, 0x5e037258, 0x0f95da76, 0xdfc03f20, - 0xc5cb9222, 0xb1f29f25, 0x1721c37c, 0x2cae046d, 0x8769fca4, 0x50dd5cf9, - 0x79d2b7ef, 0xf5903d5f, 0xfa087c0f, 0x93c7cae5, 0x8fdf4093, 0x95a5e957, - 0x7f01df1a, 0x7f19e2b9, 0xca7786b9, 0x2c8ed3e7, 0x37934f7c, 0x67e83be0, - 0x1f98188f, 0xf29bbf6b, 0xafc0d3eb, 0xfd04ed3b, 0x5ba59fb8, 0x699c80e6, - 0x7caab4e3, 0xd5d72c6d, 0xbf0fdcae, 0xc0bfe4fb, 0xbec28dd6, 0x75e8a517, - 0x83024fbf, 0xcfd72bd7, 0x68790698, 0xccf31176, 0x5173d452, 0x1e92fcd1, - 0xdf1a2fc5, 0x9c59dab5, 0xc99fe348, 0xe1e5dfbb, 0x840be4f9, 0x8748b2b8, - 0xcff1a2bf, 0xf7187f44, 0xe6122781, 0x67f9189f, 0x93fc3757, 0x40165e7f, - 0x9fe1756f, 0xba7f8c43, 0x0fda1be3, 0xe4616bde, 0xaa1c779f, 0xff2dddbd, - 0xfcf3c25c, 0xbe4ef7ab, 0x93657eec, 0x6a9f9f4f, 0x62d9c72c, 0x54bb2fe7, - 0xea96efbc, 0xbd01ca6f, 0xcec4d531, 0xe32409ef, 0xeeef0a16, 0xfcdeed38, - 0xefa86c9a, 0xda1e9814, 0x1ea33219, 0x78f769da, 0x669b7e30, 0x0557e761, - 0x23ce044f, 0xe45afbb8, 0xd921dfe8, 0x587660ee, 0xfb8f0c50, 0x37f1ec02, - 0x9d8c1f18, 0x2a43cb9a, 0xa662fa5a, 0x971d4617, 0xcfefc336, 0xbfccea3d, - 0x06967c00, 0x79dfa3b8, 0xcf784a8f, 0x0951f552, 0xf76fe3f5, 0xf1045dbd, - 0x79cf2d51, 0x8bb79ecc, 0xfbc2860a, 0xa1fedf8c, 0x8ead65ea, 0x5f404047, - 0x1fddee1a, 0x4b1e71d7, 0x297e6f7f, 0x674e51f0, 0xf93ef1bb, 0x3fdb1c60, - 0x11644d99, 0xb4719886, 0xdeb85ef4, 0xfcaf78cc, 0xff3b30ec, 0x27b0f336, - 0x2af2bdf6, 0x37ef187f, 0x8a77f6a7, 0xe7efec13, 0x6841f65a, 0xdd6cc884, - 0xd7354a0e, 0x26a33f30, 0x9349f81b, 0xf8a3fc43, 0x44327e0b, 0xb706bbf7, - 0xd07ff3a9, 0xa9fbb02d, 0x4bee1222, 0xefb09cfe, 0x363aea82, 0x40f4c9ca, - 0xe617eaee, 0xcb239c03, 0xcba06695, 0xd7162eb3, 0x5b0905f9, 0x6e6e81b2, - 0x8253f701, 0x0bf93ca2, 0x223df3ae, 0xd3b10e94, 0xe27d3df6, 0x8ff8c246, - 0x9c633d3a, 0xed099f60, 0x31bbe087, 0x824773e3, 0x588fb71e, 0x9aeb049b, - 0xab853706, 0x13bd9b78, 0x81ae0d0e, 0x8f97c64e, 0x00c6cb3a, 0xd03be01e, - 0x8e474d4b, 0x8d7be059, 0xcf7b821f, 0xe2883e30, 0x4e83e00b, 0x4016e0be, - 0xa283c35d, 0xfdb7cfae, 0x8b42f88b, 0x17c8f46b, 0x7e70b710, 0x0b98be2f, - 0x05f23578, 0xce3ce7b5, 0x505cf618, 0xc6937962, 0xe7b13fe7, 0x896efbe3, - 0xd913de60, 0x6bbf6567, 0x7dc049e8, 0xd8b8df90, 0x1c9f6d98, 0x28a6a4cb, - 0x7664e559, 0x2a3bf6bd, 0xda1cc223, 0xa2a8239f, 0xbced0db8, 0xdd27a87e, - 0x31c8fe2a, 0x46fb838e, 0x033e3731, 0x1270d0ec, 0xcc236bd8, 0x87906125, - 0x1989b65d, 0xdae63f60, 0xfcc36426, 0xfab21e5f, 0x5ed2584d, 0x9bfe5bee, - 0x7da772ad, 0x66c3e9a5, 0xfc6d5bb5, 0x4c7f2a35, 0x2779d852, 0x70d1ebd0, - 0x9003eb68, 0xc2e0e009, 0xdadf4db3, 0x22878f50, 0x00936f14, 0xfd878a0e, - 0xfb04691c, 0x24a4df21, 0xb03b064f, 0x3800584f, 0x9d7ef6db, 0x92cef109, - 0x021febd0, 0x3eda25bc, 0x0fbf5bac, 0x35b7b46b, 0x3ff3487b, 0xf3497b34, - 0x82aec17b, 0x1fd532f6, 0xbed99971, 0x05b084d8, 0xe47853ef, 0xa2957cac, - 0xe740b3ca, 0xe3cea251, 0x7082d266, 0x4ca9f769, 0x7251f153, 0x39abfa88, - 0x54c84ed0, 0xeaa9878a, 0xdd532a7d, 0x6e22fbfa, 0x3efb1b1e, 0x9e9fad15, - 0x1bae37de, 0xa3f61ad7, 0xc879687e, 0xf94feec7, 0xc3f98fbd, 0x7ef007e3, - 0xb1dfd601, 0x09feec59, 0x21c3c317, 0x763af629, 0xf1eb9551, 0x9c0e48a6, - 0xe7bfdec7, 0x1e6eb8ef, 0xf7f7f3d8, 0x771c8ec1, 0x97902042, 0xa8c4fe3b, - 0x180fcc78, 0x695f232b, 0x6f3f7afd, 0x9cf611b4, 0xccdeff44, 0x728f0a41, - 0xc167c025, 0x8f5395f2, 0x9dfd0a3c, 0xe8902a3f, 0x92451f73, 0xe5c42067, - 0x1ddfd48b, 0x7b31c83a, 0xa83f6b4a, 0x11c7defe, 0x21216f95, 0xc567bb43, - 0xa9e7451c, 0x1a1ffdea, 0x2f1ea75d, 0x74e4213e, 0xfdfc0fa5, 0x5a10e233, - 0xaa9ce1fc, 0x9ff3490f, 0xf5ce7cf0, 0x600a778d, 0xc69f5fbf, 0xdc6a2513, - 0xe9ea641b, 0x4e21c547, 0x6ff60d3a, 0x4e8f33f3, 0xb7e5bc83, 0xf4814c78, - 0x99be7686, 0x3e16f503, 0x462abde6, 0xba1f5efc, 0x9955ef13, 0xa3e4cf1b, - 0x5fc7f1a7, 0x3864f94d, 0x3b309dd0, 0x4bdd8f30, 0x81efa462, 0x1491ff3d, - 0xbe3dda19, 0x91bfa3bb, 0x2a9caf0e, 0x9eac7dc0, 0xdbe461e8, 0xfe9e747d, - 0x5377e12b, 0xbf8fc42d, 0xfac2ea9b, 0xac34beab, 0xddeafc6b, 0xd81264fb, - 0x4e9f1a79, 0x337c6249, 0x49a3f76e, 0x2f49dec4, 0xc586de23, 0xc97ffe33, - 0xee25d9aa, 0xa3e8d359, 0x843ae977, 0x2d27ea8c, 0xaa563790, 0x70fb3ac2, - 0x4425da11, 0x5c62cf3d, 0xb7f366df, 0xda75014d, 0xccfeefd3, 0xf57acb94, - 0x6fc5397b, 0x0eb00bd5, 0x99ab0916, 0x78ed531e, 0x9d231e0d, 0x08a523df, - 0x19f0777f, 0xe708c0f9, 0xf6f91d4b, 0xda07ae0a, 0x18cce0ef, 0xc6262598, - 0x8f868798, 0xc7ae8499, 0x8f5fbdd9, 0xdbd78c6f, 0x178ee7ef, 0xdad011fe, - 0xe919bc9d, 0xf4d76c66, 0x900c1147, 0xec1fa58b, 0x29f1b993, 0x8ba2df48, - 0x3ae85112, 0xcfe9fa43, 0x2b9293f5, 0xb956df91, 0xf8eeb3d8, 0x4f22faad, - 0xf93b233c, 0xd87a6c4e, 0x5bb77c06, 0x1c41b7a8, 0xf4fb3af5, 0xc2bd103a, - 0xe2660bcf, 0x131115fd, 0x94dad081, 0x886699d0, 0x243f7833, 0x20a1be78, - 0xf0327fb4, 0x0b42abe9, 0xe76d59fa, 0xca387909, 0xd50a6cee, 0x6b2ec0d9, - 0xf3e7664a, 0x5d10260e, 0x78c5f4fe, 0x8e9a6fa6, 0xc4a69d9e, 0x62ee1f68, - 0x28833cfc, 0x9ff439c9, 0x7f29eb45, 0xc7dc1f80, 0x42927181, 0x325afdce, - 0x39732dd8, 0xf6da23f4, 0x992d798e, 0x7b7adbc2, 0x2999ea02, 0xe9ddf74d, - 0xfe0884a2, 0x6f3e2463, 0xfef0e32f, 0x8dd92284, 0x59c5a2f5, 0xf98df7e8, - 0x09466926, 0xa220dfb4, 0xaf8533df, 0x755e2014, 0xabc38d3a, 0x9170f63c, - 0x623df85a, 0x0e3674ff, 0xc093f971, 0x24a77d3f, 0x66fe0469, 0x07d5ac9e, - 0x122eefe1, 0xfab6ff83, 0xcdfb73a5, 0x2cf57db4, 0xa78df30e, 0x3f8832b8, - 0xd68a7f8a, 0x5baf384b, 0xc005a942, 0xf58a33d7, 0xaac31ee7, 0xd4ab393d, - 0xfbd10246, 0xe50b9cf9, 0xfdb5a0fa, 0xf11dfc56, 0xf98122bd, 0xa37e7269, - 0xe7b3efca, 0x9bbee924, 0xa9dd984e, 0xaa4dd5c9, 0xfaa8ddfc, 0x193d73cd, - 0x094bf1ba, 0x40fe87b3, 0x64810bda, 0x7ed8b8f7, 0x96f6b4f4, 0x25e1f3c3, - 0xd068dfbe, 0x310d3787, 0xe57cbdf8, 0x348be45a, 0xc8f78dce, 0x37edf5b8, - 0x8dd7d58f, 0x0fd46bf2, 0x8f8b20b3, 0x3427aaef, 0x2f6b307d, 0x683c422f, - 0x33c53e56, 0xbb7ac5da, 0x317d27bd, 0x7d1bae26, 0x17be4971, 0xfa2e90cc, - 0xefe2e3e2, 0x4b7e2fa5, 0x54b196dd, 0x578edfae, 0xa4fecdd7, 0x298de83f, - 0x81478efc, 0xbae8da8f, 0x47c18e69, 0xc5a3bada, 0x1ca88a01, 0xc5381ea3, - 0x5ca663f6, 0x91fe274c, 0x0e80719d, 0x12ed423d, 0xa97b0c77, 0xe51b3e35, - 0x68ef43ab, 0x2eca257a, 0xb87ef311, 0xda85325d, 0xc02e52a3, 0x2be10fd7, - 0x2925ef52, 0x882b8482, 0xc19da61f, 0xa0579038, 0xcfae2cfe, 0x817f224f, - 0x3b12e3fe, 0xaf68c3e5, 0x0ae87168, 0xe94f6697, 0x1e23a5f9, 0xc3dd9339, - 0x1149f1aa, 0x7fe413e0, 0x04fb8f26, 0x7fd41bff, 0x8000b303, 0x00008000, - 0x00088b1f, 0x00000000, 0x7cc5ff00, 0x55547809, 0xf579f096, 0x55492d5e, - 0x146caa92, 0xb612f08b, 0x84582484, 0x5916ec80, 0xa014a358, 0x8168cb80, - 0x9a126b0b, 0x69ee9c71, 0x0242a6ff, 0x83b74343, 0xe8cedad2, 0x3ad857f4, - 0x08b41a83, 0xd09d0301, 0x584c5015, 0xf82e0834, 0x1a6d1ad9, 0x84490ed1, - 0xbfbb46d6, 0x739cffcf, 0x2aaa4bef, 0xffff4d85, 0xb49fdf3f, 0xdeefb97d, - 0x67b9ef77, 0x979ee73f, 0xb3559bdb, 0xf6e008ad, 0x14078a99, 0x77f1d000, - 0xe042c022, 0xadacc37f, 0xc78ef016, 0x69fcd7be, 0xe7f80d87, 0x9c2ffc3b, - 0xa42cfc90, 0x900bcf50, 0xce54b009, 0x7d57fc5f, 0x3c5e3d33, 0x52fe7a27, - 0x92b9fd98, 0xf81b700c, 0xf71c30cd, 0xff8ec5f3, 0xc7154bec, 0x7e8b2e97, - 0x4a4ce99e, 0xff8790bf, 0xbe230118, 0xd4ca0153, 0x22b79dba, 0x5527ddbc, - 0x334c558f, 0x390ffed1, 0x350ffec5, 0x7c800c97, 0x1674df80, 0x3db1f8a7, - 0x1c2111b6, 0xd1bad00d, 0xec71edc6, 0xefc5f107, 0x3c66e7e8, 0x21fc059f, - 0x52b4b607, 0x4801b721, 0xc4ed1805, 0xff602745, 0x0d3f9e2a, 0xc02486c7, - 0x5c2473ef, 0xe7af00d9, 0xf104e798, 0x5eb8c3bd, 0xe30dd700, 0xf75c01fa, - 0xf72746c8, 0xe6e8db5f, 0x442e0dfe, 0xfac0066a, 0x37af2714, 0x8776f72f, - 0xe35bdf1f, 0x50e7e6cc, 0xf844da3e, 0x7b2fe036, 0x1004086a, 0xac77afdf, - 0x807494d0, 0xb1e2b72a, 0x01d1f566, 0x8e58e34f, 0xbe25cbf3, 0x102ab72b, - 0x1fe5e7c4, 0xc4072bae, 0xee33575f, 0x2aa9f887, 0xfc368355, 0x63d34967, - 0x0cdf453b, 0xdefa08d6, 0x33028e22, 0x86cd16b5, 0x28f02cfb, 0xf1f7151e, - 0x6ff78936, 0x1d412af5, 0x278b79ff, 0x63871e9a, 0xae58bee8, 0x0ffe80b3, - 0x47305bdf, 0x9d718609, 0xdfa29305, 0xd6757c5b, 0xfed8cae7, 0xe898b47c, - 0xbf3fb63e, 0xb7744edc, 0xc1863fe3, 0x95fba230, 0x8d6fa58b, 0xc5ba3e85, - 0x8e74b1b6, 0x9d16bf1d, 0x673a27ef, 0xc6ce9b5c, 0xce8b7ffb, 0x904e110f, - 0x1bf470be, 0x30049e8b, 0x1a07e9bb, 0x55f679d1, 0x32add78d, 0x861433ce, - 0xd4fe79d2, 0xb76ff859, 0xaafcdf42, 0xfe2d2fa6, 0xe79f6b82, 0x22bfed6f, - 0x69fde745, 0xdf7e6f5f, 0x8034f3be, 0xf9ce78c1, 0x8df8d139, 0xbd2c6ba5, - 0x62f7ca16, 0xe635b5e9, 0xa05d061c, 0x60689913, 0x555fbc1c, 0xd16b8e19, - 0x162e97ad, 0x7e4f08ff, 0x5f8071ff, 0xd6fab9f3, 0x76827493, 0xe02057cd, - 0x03c84732, 0x052075f2, 0x0ade5be9, 0xec0444e1, 0x3e738b96, 0x28f5a8d7, - 0x39c469f0, 0x8353e7e8, 0xfadf6ace, 0xb2075765, 0x96fb19fc, 0x14b01069, - 0x972173d2, 0xd255f0b1, 0x7e69233a, 0xcb68f980, 0x10b2d32e, 0x05ba639e, - 0x9b51f5ee, 0x4e03da28, 0x9d1a07a1, 0xfbb75e26, 0x6e099b2b, 0xf0e57804, - 0xf8406280, 0x09e7563c, 0x33218bd2, 0xc945fbf0, 0x9cdfcf3a, 0xdc048104, - 0x9b76b41f, 0x2b44f90f, 0x3941c806, 0x825906d3, 0x9d64b835, 0xdc91f616, - 0xa8347b75, 0xd1bbb946, 0xe048ef78, 0x6c92402e, 0xa99474fe, 0x0fde8b26, - 0x79c54fb7, 0xfa6a1537, 0xb2e29c36, 0xf1a03fea, 0x93ab66ae, 0xf83eebde, - 0x5a662dcf, 0x20f02be7, 0x335af084, 0x4f8e1532, 0xa4839873, 0x93d4ca37, - 0xddfb09aa, 0x8fa4003d, 0x970b2da6, 0x3a6dd200, 0xb138d7b4, 0x8c74429d, - 0xd0bfbf43, 0xde843379, 0x9a74881a, 0x4334e921, 0x6692abea, 0x4946f595, - 0xac841a92, 0xb374fd3e, 0x408cd1a4, 0xee0a497b, 0x3c53433b, 0xf9bfd835, - 0x8fc516aa, 0xba3e932f, 0x951f4fb1, 0x3dbdf5c9, 0x019686ba, 0xff344266, - 0x3d0a3596, 0x798b6254, 0xbe0fed2e, 0xe6557cc9, 0x429f1e8c, 0xfbf913ba, - 0x825e8c62, 0xa653fb18, 0x03b935fe, 0xc58af0f1, 0x8454defb, 0x19b4e7bb, - 0x70e7c59e, 0xfb933b11, 0xc631a7e3, 0x07b6c51e, 0x757a270f, 0xe215eb84, - 0x07f50723, 0xd7b1f579, 0xa3b63f9e, 0xf18e98a7, 0x0d22dd4a, 0xcf2d99b2, - 0xf0fb33ba, 0x92bf0fde, 0xad78b10e, 0xdbde7a97, 0x8e8d7ce8, 0xad8f0fdb, - 0x979ed8b3, 0x48d749fc, 0xf8bdfdf5, 0x95e5e434, 0xe25e890b, 0x0c2e57ff, - 0x4afdb2f2, 0x0c3e59d2, 0xfe783879, 0x51e92272, 0x21aea7c4, 0x6cb8f49f, - 0x9f99679e, 0x06841c85, 0xc36e0a8e, 0xc12485fe, 0xf624aff7, 0xbc23cf1c, - 0x3cf262df, 0xeb68db4b, 0x202a2f87, 0xd175b9fd, 0xe2803379, 0x2887e505, - 0x84ee8a4f, 0xa00db1bb, 0x05ff113c, 0x72482152, 0xd0108662, 0x785e35be, - 0xd319da9a, 0xfbc214f4, 0xddb35c65, 0x29e9eb41, 0xd7f0f7c4, 0x057d132b, - 0xbf5ff1fd, 0xee1a7c11, 0xe6d1b0d3, 0x1c2f50d3, 0x7ee4e8d8, 0xb73746e3, - 0xdcea3687, 0xfc913a6e, 0xaa1ff243, 0x169f16bc, 0xa5e657a1, 0x0330fd0a, - 0x35c10ef5, 0x00609403, 0x23c66f79, 0x7288f2c0, 0x10a4dc10, 0x393cf0bd, - 0xfa44f87d, 0xe888ee5c, 0x3b56ad43, 0x82a59321, 0x67985ee9, 0x09d1f7e2, - 0xd59f3e08, 0x3fd23e7f, 0xfc8cbfaa, 0xefc38416, 0xb0b996f2, 0xb37c390d, - 0x7adf885d, 0x4bd1e965, 0xf4b9fdc0, 0x43b95ebc, 0x8feb84bd, 0x1f84cf0f, - 0x8f18bda2, 0xe2bc2184, 0xff045dcf, 0x100b1684, 0xb2b0d07d, 0xf21a167c, - 0x5ca2b5f9, 0x8448fdc0, 0xef8c1bbe, 0xc4c3cb59, 0x23a0074f, 0x645ef08d, - 0x7e49d9f3, 0x3f04b997, 0xdddb9578, 0x3937ae0a, 0x0951e2c3, 0xf1bee1b4, - 0x2d7f11eb, 0xce21b819, 0x1cc9696f, 0xb713e7a2, 0xc93ef1bd, 0x08e6d7b7, - 0xcc986cab, 0xf6111d9d, 0xe33c007c, 0x74927f24, 0x476877dc, 0x0e4e3f5a, - 0x6abb9eb0, 0x6b5e9209, 0x09ec933d, 0xafd33ee3, 0xacbfd8da, 0x6e5117a7, - 0x8f26270f, 0x42133d65, 0x63f2430d, 0x6d98e713, 0x3c23aff6, 0x7a3e65a0, - 0xedfbdf0a, 0xafd20065, 0x543fdbd3, 0x312d0fc9, 0x40e80ee5, 0xa32a8f38, - 0xf27da853, 0x6e7ce4e3, 0x127724cf, 0xec9b0e7e, 0xcefbed3a, 0x0474bd46, - 0x8da9cbf2, 0xf9023a50, 0x368dade3, 0x746f4f6e, 0xa3667b72, 0x38a3db9b, - 0x3af3fc4e, 0xbd7f138e, 0x6fd4e381, 0x4f6a71c3, 0x7ad43ae0, 0x489872df, - 0xe5bc677e, 0xbc2da8d0, 0xfadb892b, 0x742c933b, 0x50c9c38e, 0xfc4fec67, - 0x370c4e14, 0x2ee50780, 0xdb53fdd5, 0xad3f680d, 0x1c6502fe, 0xf754d4c0, - 0xae3a6d5c, 0x8fe87b3b, 0x19f1c2be, 0x6a7ec3a9, 0x3b6f7843, 0x893868e3, - 0xf5c7d2fd, 0x3f883a9f, 0x92a2244f, 0xb7643c24, 0xc7365179, 0xc418d293, - 0x24c2f768, 0xfd19a7ec, 0xc8a5b9ec, 0x3a4a4b0a, 0xb005c0f2, 0x73e1b1f3, - 0x25df886d, 0x513fff76, 0x9b6812df, 0xfa9d3a53, 0xbc927010, 0xcb20e62b, - 0x7d2510fb, 0xadbfda11, 0xd4c4ff0e, 0xabc07f08, 0xf48d21fc, 0x02af44c3, - 0x77a674ae, 0xf7d2a470, 0xd5b798dc, 0x15313651, 0x2ed7f7f9, 0xc269f995, - 0x741bc534, 0x635f97f4, 0x7af384de, 0xe26fd129, 0xd4b559c5, 0xe2e3982e, - 0x4dd96fbe, 0xa5ff24b5, 0x5fbd6b8e, 0x5c87efc2, 0xc547d666, 0x638bce1a, - 0xe3798d17, 0xffc8c991, 0x0c4b69ee, 0x7d7c4b3e, 0x84935fd6, 0x567732fd, - 0x34752aa1, 0x6bb5df70, 0xbf978d1b, 0xe572c0de, 0x59e8f249, 0xa5ed8ac4, - 0xd33e3869, 0x24c278a1, 0xa93ed32a, 0xa771a34d, 0xcdb421e2, 0x553b8ef4, - 0x5423e344, 0x9fea4ccf, 0xd89d4bd5, 0x4e66d19e, 0x66f384bd, 0x6c78a4e7, - 0xf099def8, 0xff10ae8f, 0xf249ccce, 0x1714e824, 0xa4ae9f04, 0xa9eac7be, - 0x8f1ce9d6, 0x3ad32495, 0x6131e2ba, 0x92d6febf, 0x147045ff, 0x514052fb, - 0x91a5dc68, 0xc7e4fb1f, 0xe275293f, 0x0aa1fabc, 0x099cfc90, 0xe091fee7, - 0xa89ad99f, 0xf5402027, 0xbd296716, 0x9c516f57, 0x2befb89b, 0x5181f9a1, - 0x5c79fd66, 0x769de4f7, 0x6fe507b6, 0x745fb3e5, 0x6cc1cef2, 0x9adfca17, - 0x49ed4c56, 0xcbdbf093, 0xc39f2adf, 0x930826e3, 0xebbf2952, 0x1dbdf81f, - 0x4d293f25, 0x0c4ff5c7, 0x416eb173, 0x116a953a, 0x83e70d7a, 0x55dfef42, - 0x945bf3c1, 0x8f3a3f01, 0xa7e4aff3, 0xff715a14, 0x5109e959, 0x710ce7f3, - 0x8de7f545, 0x45aa5818, 0xfcf2b1d8, 0xadfea8ac, 0x88e94a45, 0x69bef988, - 0x45fd5109, 0x11d2aea5, 0x2b6ff311, 0x5fd5181f, 0x54565b72, 0xb269a67f, - 0xa11b1fd0, 0x7dc854bc, 0x9bfb2979, 0x0a87acd9, 0x1bee629d, 0x8e3f7e38, - 0x7f09b617, 0xfe85d0aa, 0xb4a5d214, 0x80fd88ad, 0xc68f7c36, 0x8f52ec8b, - 0x3ddda005, 0xfc80ec91, 0xf62fe209, 0x6677658b, 0x6305fa3b, 0xb768ae89, - 0x752fe023, 0xfaf1db44, 0xcc27e144, 0x0bad7f01, 0x75a739e9, 0x6557fb1e, - 0x6145d5e9, 0xbf467c20, 0x2a370b1f, 0x13779dd1, 0xac6ab61f, 0x890ce737, - 0xd4adafd9, 0xf48c7ec1, 0xb7c8e6ef, 0xe0217d8c, 0xc6ff276d, 0xffb18738, - 0x4733ceb5, 0xe17ec69d, 0xacd73adf, 0xa9a5859c, 0xcf5fe171, 0x9c2c4cfe, - 0x4f32a979, 0xfb15fe81, 0xeca9ad85, 0x7a4fe22f, 0xf0c13f3c, 0xcf51ca7f, - 0x9cf522b9, 0x585f4943, 0x673d6d70, 0xff2d7bac, 0x78d758cf, 0xde54ea1f, - 0xf7bf78df, 0x7fc4aeb9, 0x27e71bbe, 0xae9e79c5, 0x5cfe7fc4, 0x9a19fcf4, - 0x7940e35e, 0x278a0e3e, 0xa93f7840, 0x959ae46b, 0x52d6f59c, 0x5fa1f65b, - 0xf670b723, 0xb52d40f9, 0x27833b53, 0xb9fe78ad, 0xf94eaa39, 0xea2fc307, - 0x0aa56717, 0x55f8e47f, 0x78e3aedd, 0x53b7407d, 0x88ff51dc, 0xaaf8a76e, - 0x28730bde, 0x370ef48e, 0xc438a7ad, 0xf62d879b, 0xfa154def, 0xdf7c857e, - 0xfea90f68, 0x857f0415, 0xf251e3ad, 0xe9bf2a49, 0x1c5f10b1, 0xbf2f7f27, - 0x5c77bfbf, 0xbf683a0b, 0x1d048fe3, 0x7e7d08be, 0x22defebd, 0xe20ca662, - 0xa917c553, 0x096c4a4f, 0x51fd48be, 0xf54574e6, 0x83ff93c7, 0x0f76cdef, - 0xae6f7a8c, 0x0f35159e, 0xf21cd8fd, 0x902c6a87, 0x353e91a3, 0xcfc87a25, - 0xefe3c58b, 0x0e3df9e5, 0x6051b927, 0x7f55d74e, 0x29e4fb1c, 0x7d8bf811, - 0xc4553dbe, 0x9ec88373, 0x52273ae3, 0x556b6e75, 0xd0e6709f, 0x887e267f, - 0xbaac63ed, 0x95c3d68c, 0x1e77c4dd, 0xba0ae9bb, 0xe3d2f0e0, 0x686ae7f3, - 0x4de33dff, 0xfb1c38ff, 0x215f1ec7, 0xfb4d53fa, 0xfadfb1b2, 0x7fa27df8, - 0xd9bc69a3, 0xb819ec83, 0xf9296e7f, 0x7fbee90b, 0x9b75fa27, 0xd4155b1d, - 0xa8099503, 0x4cd5b0d7, 0xf7a6140a, 0x2ddbc7c5, 0xc0915f68, 0x175e6cc8, - 0x156ec0d2, 0xc26574f1, 0x13d920d0, 0x13abd8ad, 0x0c132ade, 0x9264777a, - 0x09da879d, 0xdd9d7151, 0xfbe1ef82, 0x0bff3665, 0xc9c26f82, 0x87a5ea3a, - 0x200d960e, 0xea9138fe, 0xede43c64, 0x7d26ea9b, 0x21edf085, 0x01fffefb, - 0xf078e6be, 0x3ec59ad5, 0x2579f59d, 0x86f38f64, 0x3e947921, 0x3a6a15fa, - 0x21084f3f, 0xeebfb0ef, 0xb1fe5375, 0x90f165c6, 0xf2427eff, 0x35b6f5ef, - 0xdaa18f32, 0x29a91f05, 0xb17bf5a6, 0xcff25b7d, 0x6a2fb919, 0x910ba1be, - 0x33d9c03f, 0xe8815174, 0x6aa87f13, 0xe1f90f61, 0xe490ff3d, 0x83f9f8a1, - 0x183f8144, 0x8fd1f3d2, 0x777bf9f1, 0xf1b679e7, 0x65a78173, 0x0e9aecc1, - 0x06b38fec, 0xe3fca06f, 0x47ff34a1, 0xad3b8784, 0x87cc91c1, 0xb449f58e, - 0x8e05e28f, 0x0ff88c53, 0x32dd3ce3, 0x705c7fbc, 0x46c1fded, 0x64e96576, - 0x7f637781, 0xe88db1c4, 0xf124def1, 0xe10780dc, 0x303e26e8, 0x0785eae0, - 0x8f393886, 0xd4ff2200, 0x2e8be325, 0xa7ec8f5a, 0xdc7910ea, 0xff38983f, - 0x8ac24552, 0x4de77dfd, 0x791a0f1c, 0xfb1022e0, 0x49b53e4d, 0xf803e065, - 0x96a2513b, 0xcb5c695e, 0x7684fdf1, 0xf6fe262d, 0x2a9d3db2, 0xd5a9bfdf, - 0xf6a0e25f, 0x5379e8fd, 0x093f1c65, 0x59c52a82, 0xc6623b93, 0x467fe71b, - 0x18bd4feb, 0x4d293cfd, 0x3041c3da, 0xb24f3228, 0x974dc641, 0x10a7664f, - 0x2b186b1f, 0x8b0f48a8, 0xd4a4c2ae, 0xb0d33d3e, 0x4959e711, 0x2db8da9f, - 0x8fbceb38, 0x88dc69f6, 0xf49a3f0c, 0x435b9baa, 0xc2ce0aee, 0x623630bd, - 0x0617291f, 0x2fbf2f1e, 0x23ae38f0, 0xb0d397e7, 0x43356e6f, 0xc3c3ef50, - 0x0c2f8914, 0xbbfe38df, 0xf6c1d17c, 0x62db626b, 0xead9e495, 0x711e8136, - 0x113d04be, 0x6c7d08f4, 0xea8d49cf, 0xb59e92ab, 0xca7ed109, 0x924fb978, - 0x7ad45067, 0xd062bf86, 0xacea50f3, 0xc663f256, 0xdfb1563b, 0x3b293292, - 0x93a2fd6a, 0x042ef8d1, 0x63e2979f, 0x71c087cf, 0x5ab3c4c0, 0x29327f94, - 0x63f983bc, 0xcfd187d2, 0xee8f9ca7, 0xfcc9a697, 0xaedd2c56, 0xfb184f85, - 0x7fe969cb, 0xde5d3e3f, 0xcda67c68, 0x8667c689, 0x039f1a2f, 0x6be34596, - 0x1f1a3fa0, 0x898d5783, 0x7d61bf1a, 0xd87f5461, 0xcd44a70f, 0x198342cf, - 0x75be1fd9, 0x91fcd45e, 0xf545163b, 0x67753f47, 0xe0dcfcd4, 0xbcf1a88a, - 0x2efe6bdd, 0x368417fa, 0x3427cd44, 0xfe87be9b, 0x4bfe3637, 0x53ff7ed4, - 0xa18daff4, 0xe7d256ff, 0xa85e8813, 0xecfb0b37, 0xa425b919, 0x6f4d5d3f, - 0x9b79437c, 0xf9ceb140, 0xf03cc0aa, 0x2fd8e0d4, 0x7a429f54, 0xdaa2306e, - 0xd6a37a84, 0x1ec8ab04, 0x71326a3c, 0xf390d31e, 0x3f84d317, 0xc89a62f2, - 0x7b78197b, 0xd922ed1a, 0x43ea5541, 0x248efa73, 0x935453f2, 0xfec9da09, - 0x1fd61e69, 0xbe101ce7, 0x0755f719, 0x4ac5e701, 0x982d2792, 0xbea8fc88, - 0xa9fc72a9, 0x8e83f20e, 0xe4e6a4f6, 0x9f8453ce, 0x4e9b0e2b, 0xfaa6ab7c, - 0xf0df6403, 0xa1e7a19c, 0xdef39fbf, 0xf1495846, 0xe65fd196, 0xe699bf5e, - 0xe67bbb2f, 0x7b7f8a48, 0xacaddf9f, 0x43a08d2c, 0xc51739e4, 0xa40eabf1, - 0xd867fb09, 0xdc7ec313, 0x3a6bd569, 0x538c3ed0, 0xbb407d85, 0xf10d2071, - 0x88f281f1, 0x0169f859, 0xed1f9d33, 0xb827df2a, 0x80df21d0, 0xdd9f4a6d, - 0xe643bfd2, 0xda3b20fa, 0x00937d6f, 0xf74438a3, 0x1de33df0, 0x955dfe86, - 0xecbbf8cb, 0xf97f9e88, 0xaf02e1fe, 0x90f620f7, 0xe22ce70e, 0x17fc063c, - 0x42fe5ea5, 0xd24ee5ea, 0xebf911c7, 0x2676bb55, 0x2e7e7f91, 0xc6e3f847, - 0x3a49dff3, 0xe54d2eff, 0x9dddaff3, 0x047cfeb0, 0xae422ade, 0xe3557ea8, - 0xf991f5c0, 0x39c6b5cd, 0xe7468afc, 0xa8e52758, 0xf923b5a2, 0xfe7f604e, - 0xb75c34c3, 0x7b95d772, 0xa6fbd00e, 0x67614c9e, 0xd2dfbc03, 0x82e380f7, - 0x28817fa5, 0xcd33b6bf, 0xa67570cc, 0x09613889, 0xbbe44e36, 0xb803e825, - 0xda637da8, 0x7c3fe22c, 0xbfb0561e, 0xa4cc15a0, 0xb3fa16bf, 0x33f484cc, - 0x3f6779e0, 0x69cfed1e, 0x1b73ef3a, 0xfb7ef8f8, 0x922a7bdd, 0xd6340fd8, - 0x8141d633, 0x3def3f20, 0x499cc057, 0x0ae99f79, 0x9fb817fb, 0xeefb9e8d, - 0xec99bc1e, 0xbbdfb1b0, 0x0ef4bfe0, 0xf022c5f2, 0xfac6baf0, 0x1134d740, - 0x4b03f97a, 0x44ed1d2f, 0xa66d0dbf, 0x3685e530, 0xbdf2b39c, 0xcf75774a, - 0x9c230fcb, 0x66f9af1f, 0x7f7082bf, 0xbfe7bcb4, 0x3bf3e00e, 0x4741529e, - 0xfdd9f1be, 0xbc447a5a, 0x2bfeee79, 0xafe86f2c, 0x2924ff3c, 0x1eac97a5, - 0xd60f9392, 0x322a34bc, 0x9f4e485e, 0xf74e9099, 0xe2d2933b, 0xc6c46fde, - 0x3f886ba5, 0xf6757e59, 0x5cbe0d4b, 0xc372f92d, 0xf9f9a30b, 0xf3dea486, - 0x2af3fe88, 0x3436c1e7, 0xf1af395b, 0x3587e48e, 0x31337e2f, 0x8f57cf32, - 0xa95ba97c, 0xf74b7275, 0x09fa3aa6, 0x1e5e4efb, 0xeaab71cb, 0x1e73a2cf, - 0x3269fabe, 0xf9bdf7f5, 0x6e079f2d, 0xbbf83ebb, 0x78917911, 0x79ea4aae, - 0xc54af497, 0xf94eab01, 0xb90392ac, 0x7ec2ee27, 0x1fea2b65, 0x5725cf3c, - 0x29a7b1c7, 0x00a83b1e, 0xc32ab7e5, 0x2be4ac09, 0xe520941b, 0xee34d6c3, - 0xfb1832dd, 0x1616ea6b, 0x2556bb11, 0x59567d0b, 0xb13704af, 0xe9873e1f, - 0xa365285c, 0xbfee50e4, 0xd778e3e5, 0x85feb171, 0x3cf6b08d, 0xf55d9dc6, - 0x38205e5f, 0x395a35d6, 0x292176cf, 0xfb8c196c, 0x84abda5e, 0xdc9f7a02, - 0x1c44b976, 0x98f42ab6, 0xf55df685, 0xe411c2dc, 0x381d7636, 0xb93d216d, - 0x59b1e1aa, 0x309179f2, 0x8b9641ff, 0x9595bbb5, 0xd5ac7991, 0xa4420ee8, - 0x02f842fd, 0x40eafb13, 0x2cfa494e, 0x435e1a6b, 0xb6bd42e8, 0xf58569ff, - 0x97e242da, 0xf9ef0e0f, 0xdf686fdd, 0x923dff83, 0x7d745ff1, 0x805f07f8, - 0xb94a8bfd, 0x633c5c0f, 0xb2b2f8a1, 0xde217cc1, 0xba6352fd, 0xcfda1eef, - 0xfd638f88, 0x10162dee, 0x10d93ff7, 0x82ec9e7c, 0x1cb2c7a3, 0x9a57f9e1, - 0xce68f080, 0xec0acb1e, 0xc8ce48db, 0xc11db85e, 0xbef57178, 0x84f18d74, - 0x78fac4b1, 0x3921a0f7, 0x5877a25e, 0xe9579f28, 0x5f10b4ee, 0x173f8657, - 0x9f8dfff7, 0x89c6f2cc, 0x574e5fb7, 0x273f33a4, 0x6437de4a, 0x30b9618c, - 0x90c3daf7, 0x60bee58d, 0xa9d90f45, 0x3b91070d, 0xbfb7a214, 0xec0ee087, - 0x7ce9d04f, 0x9f3e0725, 0xcfb111d8, 0xf47ca51f, 0xf95e59e6, 0xf099ac64, - 0xb193efb9, 0xf3df525a, 0xaac74cae, 0x97997978, 0xdedd85d3, 0x18bbec9c, - 0x9e09072d, 0xd95bee30, 0x147be764, 0x2d2d8394, 0x70729145, 0xc45daac7, - 0x07aa4de7, 0x1b2a0225, 0x79abfa17, 0xc887927e, 0x0cce36a3, 0x4eaa1f10, - 0xfc27f31f, 0x289bf715, 0xff508fef, 0x3ff74dcd, 0x39ac724d, 0x1e646560, - 0xf1d4d2a4, 0xe88516ab, 0xa26bc3ba, 0xf5810afd, 0x75f0ea96, 0x94553c70, - 0x7bdc53a9, 0x202cc274, 0x59bcfd3c, 0x39afbce1, 0x8b35bfd5, 0xe55c7be8, - 0x2fa396f9, 0xbbbee804, 0x11141c6b, 0x7f79c67c, 0x2a0c2e3e, 0x00b9b3ae, - 0xe6edb43c, 0xc4dd4b83, 0x38cf3fbf, 0xdd867ec6, 0x2bd20213, 0x503fe835, - 0x1f9ec7de, 0x093ad30a, 0x1522be39, 0xee9359f7, 0x58b4be64, 0x27ca1efd, - 0x36fb203d, 0xe08ab7cd, 0x8a27a5b3, 0xf5c87bf8, 0x48baf9e5, 0x6f74cdfe, - 0x4b7ce7e9, 0x69f05997, 0x71c00dd7, 0x4cfcd722, 0xe32f21a6, 0xb83b06cd, - 0xd6546aad, 0x44d7da46, 0x79e8dbf0, 0x1ea5c1d7, 0x2d9cdf82, 0x91333df9, - 0xff7622e5, 0xa99f888f, 0x62b4c0ce, 0x99e1166b, 0x9ff7a6f0, 0x7be4a1f7, - 0xf9a01f03, 0x115e4873, 0xfcbc6f54, 0xf8bd3f92, 0x7375d12c, 0x95c72faa, - 0xc2bcd7cf, 0xc6277629, 0xff9c3b95, 0x31b7c901, 0x89f095bf, 0xfcd16fef, - 0x51efc236, 0xc5b35f89, 0xfe593ba7, 0xdfed3a7d, 0xf141be7b, 0x3c8df7cf, - 0xff6c96df, 0xcfef9ef7, 0x54e67cf2, 0x2f5a37e4, 0x399e7819, 0xfe201839, - 0xa2824dab, 0xa8f8f84d, 0xe49b966b, 0x6f91cb6e, 0xd7bc9286, 0x40dc7926, - 0x9be6b179, 0x6fdc9196, 0xf3277419, 0xe42f17ff, 0xfb11aa16, 0x7f17a724, - 0x2f3be745, 0xe2c5b1cf, 0x7c73a1cf, 0x9c69cf2c, 0xefba496b, 0xf911e92f, - 0x7e921826, 0xd7b3fc5d, 0x7194d7b8, 0x61da479e, 0x8f38f38c, 0x5c890dd8, - 0xfa57b67f, 0x98f81ae1, 0xd1e0ec7f, 0xc2f2bfd9, 0xa92baa09, 0x36c13169, - 0xb5253e3a, 0x92fdee22, 0x0c119355, 0xb2186d7a, 0x8d3435d3, 0x39d89f3b, - 0x3ee116af, 0xf8550108, 0x0cf9d169, 0x255e2af0, 0xdaf18f32, 0x63cbeb9a, - 0x21afe33c, 0x63cd8d79, 0x969b0e4c, 0x23ae525b, 0xbcdaf19f, 0xd18cf9b8, - 0x5171d119, 0xc0ce8641, 0x7f047285, 0x4189c286, 0xf1833791, 0x26eabf94, - 0x9fe3855b, 0xde5999e3, 0x9b1cae95, 0x13e0ed0b, 0x3adb6c4f, 0x8470e50d, - 0x6bf503c0, 0xf1f5c988, 0xe6f507ec, 0xc31b5e47, 0x3dea387e, 0x4e02f395, - 0x1d0c4b09, 0x137fd08b, 0x2a27a541, 0xf63e12bf, 0xdbf1326d, 0x2dfd549e, - 0x9b4f4fa2, 0x092875ca, 0x15c5875a, 0x900eee47, 0xe076807f, 0x3e84339f, - 0x7b8a35b7, 0x65ee9b4b, 0x74e0993d, 0xe423538e, 0xd8432f24, 0x1f638aa5, - 0x2ca0b50c, 0x4c9d325d, 0xd7f5c7ce, 0xa64fafed, 0x73dade34, 0xd2a44f6f, - 0xff353b9f, 0xff3c0c82, 0x51aeca17, 0xb75bf236, 0x7e12c706, 0xae6ce142, - 0x20d02ccf, 0x87f615a0, 0x3c29eaa7, 0x9504ba14, 0x5b71a54f, 0x257e34d0, - 0x58555ff1, 0x30f6979c, 0x6dcc8aa3, 0xd5dfb854, 0xeb4a9358, 0x79b6fd55, - 0x97afe910, 0xf39f8432, 0xf13cd5e2, 0xcd1a06be, 0x25c33fbf, 0xa2682a99, - 0x324be37c, 0x5575d94f, 0xfec679e5, 0x55338d05, 0x7e41f227, 0xce11c778, - 0x7559368b, 0x73c26fa2, 0x94d1f020, 0xd5687ec0, 0x7640d9e1, 0x1e05dbaf, - 0x24f7c705, 0xfc447cf6, 0xd56cd3d0, 0xc1373ee9, 0x715203b9, 0x1eb23dfd, - 0xb619172c, 0xdcf7d1de, 0xe9a12fd8, 0x24439497, 0xe57be0be, 0x4c076d04, - 0x3be24477, 0xc959d849, 0xc3127b57, 0xe967ba26, 0x59efdf41, 0x4e0fab86, - 0x380d7de0, 0xec0ed973, 0xf85cf4b1, 0xe5c33a71, 0x05c83e24, 0x8d342701, - 0x26af49d6, 0x8e7cbd38, 0x09eea704, 0xaae1fd28, 0x208e8b1a, 0xa4a3cfca, - 0xc9f4a6cc, 0x5f625577, 0xb0b286df, 0xfca41b27, 0x9d2b6eb7, 0x8547d916, - 0xfdefa933, 0xf8e278ff, 0x9c21dab6, 0x48a80bff, 0x49b63b7f, 0x214e74a9, - 0xde122857, 0x0781428c, 0xdbb40baa, 0x7cef78c4, 0x2a4773e4, 0xe79e7fdb, - 0xf3ed3ab1, 0xf85e58b2, 0x0ff0d17e, 0x17c2521f, 0x76d2466e, 0xc94be63e, - 0x9a7573c7, 0x875c3c8e, 0x3cb8fef3, 0xfd8c2a34, 0x79ffab16, 0x3f57cfe2, - 0x80bdb15c, 0xb31eeff4, 0x4ff49ca7, 0xf671e047, 0xeb345fcb, 0x0ee422db, - 0x7264f486, 0x3ecc61dd, 0x3d36e755, 0xf776fe4e, 0xfba74541, 0xcf736ef4, - 0xb2bb8250, 0xd50b33e9, 0xfc1d5663, 0xb2ebfd84, 0xda5eff4c, 0x3563526f, - 0x864dcfd7, 0x873f5c1d, 0x20eb917a, 0x4fa16e43, 0xf51d9f2e, 0x1d04756c, - 0x06f293de, 0x6461fe3d, 0xbca49abf, 0x1c38a61e, 0x772dfddb, 0xf7f5a70c, - 0xf180fccb, 0x191c355e, 0x04df784c, 0x3c6b71af, 0x5c6a0eef, 0xaef79cbf, - 0xc46f5eed, 0xfe52d3fc, 0x56fdcb4f, 0x20dffa67, 0x7cb6d778, 0xc2d2a16a, - 0xa1a1f3aa, 0x3486f714, 0x4719c53d, 0x6fcaf48f, 0x69553c8c, 0x5f9a163d, - 0xaf581175, 0x536bbd20, 0xbd2f7e90, 0x396638db, 0x348fdf3e, 0x8b3b2149, - 0xe3d92af1, 0x60df66fd, 0xcefd5f9a, 0x8f4963d7, 0xf020241d, 0xaf375f7f, - 0x4378461d, 0x244e2ffe, 0xac0bdb39, 0xcd390cd7, 0xf7c53927, 0x8bff89f3, - 0x7acb9fa8, 0x7da58f79, 0x7ee5cb1e, 0x225c9013, 0x203cb3ff, 0xdfc93bff, - 0x3ca277cb, 0x59a3fbf0, 0x9bb4f7ce, 0xa337ecbc, 0xfdc91f5e, 0xdfd4c5e2, - 0x64ea5ed3, 0x843aa739, 0xf0d79242, 0x04275e11, 0x45f2d740, 0xfd22f80a, - 0x648cbcff, 0xf1242f71, 0xd8433939, 0x9e8e5083, 0xd873c1e2, 0x3e4a3555, - 0xe8a5ec22, 0x9a5a7b4b, 0xbf6d97f9, 0x26524698, 0xda5384ed, 0xd678ff49, - 0x6d28fffb, 0xa7d786d5, 0x73c3a82c, 0xf2a5386e, 0xf71961f8, 0x1c9f2585, - 0xb21af991, 0xa89a7a1b, 0x13e7a61f, 0xe5f54fb0, 0x4bebbd13, 0x9a4d1cc8, - 0xb528e3b3, 0x12a17c53, 0x2da6db72, 0x166a3f6b, 0xfc479e62, 0x6e6470d7, - 0x75e3d51e, 0x0242b39f, 0x6df0d882, 0x222f47cf, 0x8c3e1e1e, 0xa7638ff8, - 0x7fcc38f0, 0x060d7fe8, 0x6ef1ff77, 0x4091ea45, 0xc7e27cd2, 0xafb506ae, - 0x2254808f, 0xfddf5363, 0x007b7da4, 0x677fe76d, 0x2267077a, 0xf00ccf3e, - 0xfa7ddb73, 0xcb124cdb, 0x5c4567fd, 0xe6f160df, 0x6434ff11, 0x871ba863, - 0x2299ad4f, 0x856453ef, 0x379cf7b8, 0x18390a67, 0x0aed8015, 0x33aaebc7, - 0xd4bf7488, 0xe82d7aa0, 0xc0845d2f, 0x6fa4a992, 0x01f75e64, 0xfc5e3f90, - 0x283cfa45, 0xdf900fbb, 0xc1eb7682, 0x11d6c45f, 0x316fd978, 0xeb0058f2, - 0x2b5fc44d, 0x0ff8149b, 0x67aac5c4, 0x93afe7a2, 0x1babf275, 0x8c1b1d77, - 0x5cf35d74, 0x2df938cc, 0xe211ff7c, 0x5d5d7878, 0xcdc33d74, 0x197fd299, - 0x7fc9c30e, 0x3d62be41, 0xd5a0d661, 0x60ac7c8a, 0xf6224314, 0x0be04992, - 0x67cb2bf5, 0x8a6f61be, 0xb9ea5e85, 0x94a75c04, 0x94743bbb, 0xd4a681ea, - 0x8f687965, 0x9f189a29, 0xee2598d2, 0x4aa0b4a7, 0xbc930c75, 0x77ec59fe, - 0xa967bc07, 0xd49564de, 0x5fc4e097, 0xd3c8fbca, 0xddfe92af, 0x9d6c60ea, - 0x9553c0a8, 0x8219379c, 0xcaefb435, 0x69dea2dd, 0xf9e8eeed, 0xeb4f1255, - 0x8c7d3a9e, 0xa11585d2, 0xa7897198, 0x3a98c6aa, 0xdc38b116, 0xadef299f, - 0xf5fb7d64, 0xd1fc5bd6, 0xb78dfc2c, 0xf8c63ae5, 0xef914ce6, 0x1063c4ad, - 0xd505d77d, 0x2ad1f120, 0xfc2c9025, 0xc72c705e, 0xb067ddf3, 0xbdcfac81, - 0x3ee9e25f, 0x7e7c3fc9, 0x19e2bf7c, 0xfdc57df1, 0x7f868b3f, 0x832cf80d, - 0x0d83f9f1, 0xde50b03f, 0x56df9631, 0xffd999d5, 0x13f1235d, 0x7a6b5fcb, - 0x858767f9, 0x7f2c5bec, 0x6b95fa55, 0xf6fc2fc0, 0x0df85bff, 0xcb91af3a, - 0x398735ac, 0x09f6b53f, 0xabf943c5, 0xf7ab9d6b, 0x7f7cf23c, 0x359eb9ef, - 0xc6063de8, 0xa4e7bd30, 0x63bd175d, 0x96bdedfd, 0xe726bcde, 0x66b72f05, - 0xe0dd3e73, 0x6675d8ab, 0xf67dbf49, 0xbd7fc253, 0x276258d4, 0xa4fba3ff, - 0x9ce8a3c9, 0xc02e4caf, 0x566f8ff3, 0xee91fc81, 0x033be1a6, 0xa9e17f08, - 0x5f94c5a2, 0xed0a7f1f, 0xb707dd13, 0x0257fd16, 0xd27b07df, 0xb667ee48, - 0xbdfb488d, 0xfb61d783, 0x70b27dde, 0xe9e93967, 0xb445a593, 0x54e382ae, - 0xed285e9f, 0x42c9f554, 0xbd84477b, 0xc8a64dfa, 0xff716fcf, 0x1b8a51fe, - 0x7b35ef66, 0xdb323f28, 0x8094dfec, 0xa0be15f0, 0xb771aa78, 0x9e47ed63, - 0xbe5175a4, 0xf38acd28, 0x8d08e9fe, 0x1851ed57, 0xb2a6eefe, 0x3f643dbc, - 0xec87aa83, 0x7dd37762, 0x1f920ff9, 0xfe40fcd4, 0x1dfb117d, 0x66fa154b, - 0xb6660df6, 0xec839dd7, 0xbca72ebf, 0xeb1777a8, 0xfb43ce8d, 0xc37dfc2c, - 0x78dc051e, 0xa3ee63ce, 0x3a1e132f, 0x50b69c0f, 0x70d25010, 0x4711d2da, - 0x25ed1b7f, 0x9cc2f30c, 0xe161ddaf, 0x7ffdcdfa, 0x2b79d0b0, 0xf384fb9f, - 0x7e286b6f, 0x19ef3f20, 0x3a77bf95, 0x85aafcda, 0x4eb2b4f8, 0x91590181, - 0x271e66e3, 0xcffd4afd, 0x369e84ea, 0xe4857ff8, 0x0dff8377, 0xf5215879, - 0xe35b7dda, 0xffa1bbf3, 0x96ef041e, 0x03deb841, 0x0eb9cb75, 0xd11d81e9, - 0xfc5257f3, 0x17cd237a, 0xa9f2befc, 0xbdd5f1e8, 0xfd601e7c, 0xbf47ab1f, - 0x2e7ff433, 0x5f9f12e4, 0xa618af0e, 0x7d7d3ca1, 0x8830cd7a, 0x293caf93, - 0x6ec306fd, 0xd89b0e5f, 0xebcec5ee, 0x2162bc6a, 0xfad55b7b, 0x6773f627, - 0xf4c97d35, 0xe16a6f28, 0xc05bd97a, 0x79f08ebf, 0x49dd934b, 0x877976fe, - 0x9af303d0, 0x42a0c1ac, 0xa25aa1e3, 0xf161f773, 0x90e049bd, 0x4816fec2, - 0xe252b8bd, 0xe3c4a575, 0x06e38c4a, 0x8c8c7d53, 0xbc652be3, 0xd7673abe, - 0xa9292a31, 0xdaebe394, 0x1e13268e, 0x5bd081e7, 0x6f4242f3, 0xec31f419, - 0x40beac50, 0xd10f770b, 0x95936d77, 0x4be7d6eb, 0x0ebf35bd, 0x5fd296f5, - 0xb40f747f, 0x7ef1fc8b, 0xddac7701, 0x9e886cad, 0xfc201aef, 0x7fd2cbd8, - 0x4d101c2e, 0xb01ef297, 0x9e7f7e53, 0xfc827aae, 0xfb46bb56, 0x7e458eb7, - 0xf55bf5c3, 0xeaf129e1, 0x4df68cb5, 0xfd181719, 0xc3679405, 0x0ee721f9, - 0xffdc6447, 0x7f84039f, 0x1ab266b3, 0xc446ba20, 0xb30a0b49, 0x7349c6e2, - 0x8637f409, 0x71b3f7dc, 0x77927191, 0xb7e228d7, 0x2cef757f, 0xaaa6baa7, - 0xba2fa13a, 0x29bae126, 0xfb03f7e4, 0xd67555d1, 0x5533c520, 0x7dfc2fc8, - 0xc909f11a, 0x46529363, 0xc671827c, 0x42feb4ed, 0xf3c4eaba, 0xfb446c2f, - 0x2c2fcb8e, 0xabf992fd, 0x3738846d, 0xbc406de2, 0x3788c3b8, 0xbf0aaf2a, - 0xa95e78d6, 0x51dc7075, 0xb5ea24d9, 0x337c8e1b, 0xede10b34, 0xd0f3fe6e, - 0x3e4f54e5, 0x86e7d840, 0x54a7d0e2, 0x1ef5f457, 0xb5ff5c5b, 0xb52bff57, - 0xe6950f2c, 0x6bf64c8e, 0x791fa20e, 0xb7d1ea13, 0xa538e0bf, 0xbdc248e1, - 0x5aebcf94, 0xfce61fe1, 0xc3553a1e, 0x3783f626, 0xe4b72d41, 0x8dfa451f, - 0x4ea29d2b, 0x3f6941e9, 0xf208ffa9, 0x773883f5, 0xf97f6146, 0x8549f437, - 0x10d5ebe4, 0xe95532d8, 0xa42a07af, 0xdfcdacdc, 0xf6ae85b5, 0x0aa7fd63, - 0x31184f29, 0xf58cbdb0, 0x8633fe9f, 0x4edfab5f, 0xbbb8ff64, 0xae52754d, - 0xabfbf119, 0x6227e441, 0x271d905c, 0xe485fb5f, 0x7f794ecf, 0x65493d5c, - 0x8b2699fc, 0x10b7f0d6, 0xdd37cc8f, 0xb2411da7, 0x5f87796f, 0x583e26cd, - 0xdefa3bbb, 0xe7e8e889, 0xc8a0b1ba, 0x7cec8547, 0xbf8c6517, 0x31d5f874, - 0x6fd56fc4, 0xd04a3b7f, 0x96519be7, 0x67c36bf4, 0xe2228ab4, 0xe2229366, - 0x475afde6, 0x556bc532, 0x645f5507, 0xef41bf3d, 0x813ca597, 0xf503f226, - 0xabe67403, 0x1fc126ea, 0xe2d166a6, 0x7e444bfe, 0xf7fbccc8, 0xbe462f1b, - 0x067b1ef9, 0x40f21704, 0xf987b995, 0x89b4eaaf, 0x7d3aa9e1, 0xc4447339, - 0x775a017b, 0xeabfe900, 0xc4fac075, 0xe76fa40e, 0xd891f7d3, 0x027eff9f, - 0xb2c761fb, 0xfb8b97b7, 0x7f48152f, 0x9af6fc3d, 0x60f691d1, 0x2f7100e2, - 0x3707840e, 0x10bf3f79, 0x6c3c4bfb, 0xbf324582, 0xaf79f820, 0x2e309b8c, - 0x9c40737b, 0xfd7aecb8, 0x2b66eae9, 0xeab9fe50, 0x19d72b03, 0x92bcdd7d, - 0xeab87ee3, 0x06fa4d1f, 0xa91bfefc, 0xcaf0f87d, 0xebfcf4d1, 0xe46fabc3, - 0x29b2a97c, 0x2011cf2a, 0x5fe4dcf8, 0x5deef57d, 0x69b67fe4, 0xb6149fec, - 0xee977d9d, 0x9835f769, 0x8ad1dbf9, 0x067613fd, 0x2aafc892, 0x11df4f9c, - 0x98d56bed, 0x32dfd0ff, 0xfb3b2bfc, 0xd88aa757, 0x7c75c2bf, 0x4e8b6e41, - 0xa7bad394, 0x9a688b8a, 0xd7a4e382, 0xe57f93c6, 0x0cb7f3e8, 0xf8933e78, - 0xe0496eec, 0xd9028bbc, 0x4460cf82, 0x1aebdc14, 0x64ff675e, 0xf51aa35d, - 0xdef188fd, 0x7b88065f, 0x3e0cef87, 0xe65e290b, 0x5da2bda3, 0x932fb8d7, - 0x1cd6b1ce, 0xaea93e62, 0x3df18b33, 0x07ba05a2, 0x411fc09a, 0x273f0807, - 0x65d211e8, 0x8438259e, 0xbdbdfafc, 0x2eb28af7, 0xf5ea2824, 0xf3875a6a, - 0x5b974c77, 0xb3c7a5f7, 0x9ee92743, 0xe3be1d07, 0x8a1e2259, 0x5badff1d, - 0x9f8e41e4, 0xf8f1fa13, 0x78e8ff4c, 0xc500327a, 0x48a05f22, 0xef8835fa, - 0x35e763ed, 0xfe787ad3, 0xc70243dd, 0xf73b8f89, 0x63fdf026, 0x75e44ba7, - 0x34dbea4b, 0x6d661efa, 0xec813283, 0xf79cdad2, 0xec197bf8, 0x5c9e9117, - 0xf7c83e1b, 0x7b7515af, 0xc0e37967, 0xec2dddb1, 0x9df93cc3, 0x7cf8ec72, - 0x3c067e39, 0xdb9e3219, 0x673ef74e, 0xf14ecdca, 0xeef89bdd, 0xd7a956f5, - 0x6662df17, 0xe80cea3f, 0x227f7166, 0x481639ee, 0xd4ab7dbd, 0x63dfb1f7, - 0x76fdfa1b, 0x67c2ceb9, 0x73dd3360, 0x7d9f7ec4, 0x170ff4bb, 0xefd79781, - 0xf4bd5df7, 0xfeff6313, 0xea5b8942, 0x8a3051f5, 0xed087af4, 0xe45bd70d, - 0x9eddb026, 0xae32305f, 0xa9df41df, 0x753bf2eb, 0x57fa0d6a, 0xf6c7bee7, - 0xb9cb78f0, 0x86fbf997, 0x1d900973, 0xcfad9ee7, 0xe47a1a1e, 0x79774136, - 0x14e151ef, 0xbff41a30, 0x645a1184, 0xffa0cd7e, 0xff0e9283, 0x394575c7, - 0x63e645a0, 0x07fea90e, 0x475419dd, 0x38fec9dd, 0x21ed809e, 0x3ca86b9e, - 0x846b50d7, 0x7034bb9d, 0xee3e5c79, 0x406a5f3b, 0x6e7493d8, 0xecad725b, - 0x14845637, 0x22b0eefe, 0x9b7fa20c, 0x51caf9c2, 0xbf5c2d0d, 0xf154a4b1, - 0x3c5a8578, 0x7c19f04b, 0xfc26c0b4, 0x7a5f8303, 0x88f925f1, 0xb85fc9c6, - 0xb10bfa55, 0xda1a34fc, 0x4bfad167, 0xea878abd, 0x47c9af36, 0x4ebdc6cb, - 0xf8b5eee1, 0x4cd2f908, 0x9f96317a, 0x1ffb735e, 0xb775fc25, 0x80525e5f, - 0xfdcf1feb, 0x4ff1286c, 0xe8e435e5, 0xddbf4945, 0xae71c08e, 0x7597a963, - 0x8db9f504, 0x5697841d, 0xd3b2bf60, 0x8365bed5, 0x8eb9b7f0, 0xc09c22a0, - 0x4d15a5f5, 0xad6efe76, 0x713aa1a2, 0x26e3e90c, 0x7ec763d5, 0x52e9c379, - 0x179423ca, 0x2a973a89, 0xabbba8bb, 0xbbba8bb2, 0xe7fee9b9, 0xeff813dc, - 0x11d74403, 0xb57e3a58, 0x3ef87be1, 0x9335df56, 0x7fe1370f, 0x4b350f4e, - 0xbb686cfc, 0xc4863992, 0x887fdd34, 0xfd7eeee0, 0x8a7d0b45, 0xd5e63551, - 0xd6825459, 0xde79d6ec, 0xb52d752d, 0xe0365694, 0x429dbbb7, 0x43839aef, - 0xbfcd6fd8, 0xea9b7abe, 0x258c6f83, 0xd2d5d5fb, 0xc112d636, 0x501b9def, - 0x63a1c76f, 0x1ca49835, 0xca2adc6b, 0x0947e922, 0x3e6aaeb9, 0x8bf9499a, - 0x7ce7924e, 0x1e49df6a, 0xdec56d81, 0xc923c933, 0x5a2fd99f, 0x4d4bbd63, - 0xad03cf2a, 0x49edd463, 0x666df091, 0xc4852ef8, 0xa31d003a, 0x8e441716, - 0xd6bffcd7, 0x3e851707, 0x07d288e8, 0x16429e06, 0x0388efe0, 0xa75cad87, - 0xae3ff740, 0x036a3a08, 0xc26efd05, 0x76e48a60, 0x0f7bdd32, 0x834f9727, - 0x41afa9bb, 0xfba54b58, 0xea2ab0e9, 0xbeb086fb, 0xbff7289f, 0x50b70b49, - 0x7964f03d, 0xda053a5f, 0xe80cde79, 0x4e0bd6e1, 0x18ba0efe, 0xb24edc3c, - 0x5a53e785, 0xe2143f2b, 0x99c27bef, 0x4d82eb9a, 0x871d6f7e, 0xd3787dde, - 0x0f8182e0, 0x44d5ee95, 0x79ec533d, 0xfc28186e, 0x42bc9bbc, 0x414b910f, - 0x2093c0f5, 0xd3f9f7c4, 0xebde43a1, 0x54c73fc7, 0x1ee90b8c, 0x31ba3a6f, - 0x208f8c89, 0xe7469fcf, 0xa79de351, 0x19933e63, 0x9f049d4a, 0x7d34ce12, - 0x73febf67, 0x28355374, 0xebefbde5, 0x5171fae9, 0xa7a83ddf, 0xa9f78de9, - 0x7af1597e, 0x43d9beb9, 0xfc538ddf, 0x7b3ad613, 0xc03659f5, 0x722b8198, - 0xfbe84e06, 0xc0fc046e, 0xdfb12475, 0x277c448d, 0xfe231702, 0xe751922e, - 0x48b83bbb, 0x65913aa7, 0x7bfe36e9, 0xa1b6853b, 0x79af29e3, 0x339fcd28, - 0x7dea8330, 0x62f246eb, 0xfb02705a, 0xecbf92b9, 0x78449de0, 0xf7c6bc50, - 0xd37cc02b, 0x320bf7fb, 0xb227bf81, 0x3e77c55b, 0x6d1f91db, 0x3a052ca9, - 0x23c35fd5, 0xd3f93a25, 0x0f365c5b, 0x256c477d, 0x707dedb8, 0x1d44d8d7, - 0xd44d8d48, 0x72f51879, 0xb1ad78b1, 0x8f4e7919, 0x98f1fd8d, 0x627e90ef, - 0x7842dff3, 0x98a9287a, 0xde530eff, 0x5cdcd32b, 0x7fbf250f, 0xf03049aa, - 0xe7e36c50, 0xec94f57d, 0x3d52d667, 0x9359c237, 0x78ff5c01, 0x0a546934, - 0xb4d565d5, 0x9aee7a89, 0x77eb008c, 0x7d615fb3, 0xd25ad35f, 0xb2e2f64a, - 0xdd75c2c3, 0x07512e35, 0xd080c81f, 0x3d347af3, 0xa0f419a6, 0x8f594bfb, - 0x5c65d064, 0x7bd0943a, 0x91dec2e3, 0xdb429384, 0xfdd037cb, 0x7470b8c2, - 0x69d2197d, 0xf7a9d135, 0xc9cd1e3b, 0x7d061ef5, 0xd9987190, 0x06ee929d, - 0xdfc69cbd, 0x516af023, 0xa0c08f7f, 0x4144f6e3, 0xe055332f, 0x7577e70c, - 0x4e96375a, 0x14e11bff, 0x4bb0bac1, 0x00004bb0 -}; - -static const u32 xsem_int_table_data_e1h[] = { - 0x00088b1f, 0x00000000, 0x93cbff00, 0x51f86065, 0xd2f9c08f, 0xbcde0c0c, - 0xc4b462a8, 0x0c0c5c0c, 0x0e5c4041, 0x7b401ac4, 0xdbe9016f, 0xcdce1c40, - 0xc40110c0, 0x1ff881fb, 0x6207ff10, 0x04d6200d, 0x79405fe2, 0x5b1ba845, - 0xda181898, 0x8803b880, 0x875880bb, 0x97418191, 0x93fb7891, 0xde181984, - 0x7af82389, 0xcd0c0c12, 0xfff3f452, 0x5631c360, 0x29efb5f4, 0x174e3ed0, - 0x19c73f04, 0x505c2498, 0xe0bb70d5, 0x4d078337, 0xcf8d179e, 0x9e7f4787, - 0x5cbf2a21, 0x4d3f950b, 0x23e18187, 0x2d0a9a92, 0xc7416efc, 0x0c0c468a, - 0xabc4464a, 0xca8c60df, 0xd081300f, 0xb1adf900, 0x0003a809, 0x00000000 -}; - -static const u32 xsem_pram_data_e1h[] = { - 0x00088b1f, 0x00000000, 0x7de5ff00, 0xd5547c09, 0xf37df0f5, 0x66499996, - 0x0d909326, 0x8a027108, 0x081380a8, 0xc3b44069, 0x8e22a222, 0x260dc55b, - 0x1037d902, 0xfdaff0fd, 0x2d361032, 0x4682d0d6, 0xa0c0748b, 0x0d0482c1, - 0x00e02418, 0xd52ff82e, 0x5b7bbfd8, 0x16c34a0c, 0x7e1b8092, 0xce7fe5b5, - 0xef25f7b9, 0x6d80264d, 0xfdfb5fbf, 0xe6f169bf, 0x5ddf7bbc, 0x3dcf76ce, - 0x14fbdcf7, 0xf89628db, 0xe0cec663, 0x2cabd20f, 0xdd51b18c, 0xa0db6ce9, - 0x74fa87a1, 0x6559ffe7, 0x4287ead3, 0x6ed0ab1e, 0x9cfdd61e, 0x7e5485b1, - 0x386b8c40, 0xf4d31cbb, 0x8f0e1b10, 0x9616c96d, 0x6e7dd8cc, 0x0901bf46, - 0x912974be, 0x5615ceb1, 0x780cbaf7, 0x085c7aae, 0x20c8f7df, 0xf7c25077, - 0x1652c93c, 0xbaa23fe4, 0xbecc01d7, 0x6cb3233f, 0xe0da66c6, 0xc3fc0f6f, - 0x7cbea07a, 0x63106cac, 0x059969ea, 0x77ea7fa0, 0x3403a512, 0x00efc336, - 0x6c2df978, 0xfeeed0dc, 0xecfd13b9, 0xe8b78073, 0x5b7e89f9, 0x097f90c0, - 0xecffa893, 0x5faa4afb, 0xf2f16f6f, 0x073e6c5b, 0x8d941636, 0x7f963bcf, - 0x8be7c2e9, 0x7aa16e9b, 0xd82c5318, 0xc8b772cf, 0x635cfc4f, 0xbbfaee96, - 0x76a214f1, 0x04d3d874, 0x3188feed, 0xb6bfb5e9, 0xd543c032, 0x0563d556, - 0xaad84cbc, 0x700c7f86, 0x84295ae9, 0x9d9765b0, 0xfb4bc031, 0x9d870e6a, - 0x9fcb0f9a, 0xaa1805a8, 0xff36b728, 0xdbc40afc, 0xa3ad9956, 0xf784fc66, - 0x3bc71b56, 0x9e70e46b, 0x6ba5839d, 0xf7c74f77, 0xccad1a0b, 0x6e95f50e, - 0x057a9fcf, 0x54fbf9c0, 0xd74a4586, 0x01fad02f, 0xea92185c, 0xcf18ee11, - 0x36e0fda8, 0xca1eb439, 0x939ab877, 0x1ff1836f, 0xcf31b4ab, 0x676fd0c5, - 0x80adf273, 0x96d0a287, 0xd15ef849, 0x2c8bc946, 0xfaeb6134, 0x7bc2fb37, - 0xaf241ba5, 0x5c52f015, 0x433ccb17, 0xc0ce1f78, 0x3906d6bf, 0x9fc863fc, - 0x1964e30b, 0x49ead748, 0x57f6c64c, 0x37671e68, 0x0e558e9e, 0x376b1e61, - 0xda01ba5c, 0x5ecaf781, 0xc438bc94, 0x200b0b32, 0xb76fb65f, 0x81d67b4f, - 0x0da05be3, 0x96b8e276, 0x3f2e586a, 0xeecdbb94, 0xd5adfec1, 0xd17e4126, - 0x9e5ab5ea, 0x75c5fe81, 0xcd8f3197, 0x419aafd0, 0x88fe4629, 0x9b018f4c, - 0xc453fb18, 0xf91eaf98, 0x37690944, 0x9fa2e419, 0x2ef44f14, 0xf54d93ae, - 0x4b192603, 0x007eff82, 0x82be027f, 0x57849d3b, 0x05736e9d, 0x3b74e91f, - 0x2987e425, 0xfac6d99d, 0x48e7f4f5, 0x754fe807, 0x5fd29ba5, 0xba52a654, - 0xf443d2b2, 0x07f10279, 0x6fd172e9, 0x4e3658d7, 0x3e5d7681, 0x4b3146e6, - 0xa71be298, 0xe7e09c02, 0x01ddf270, 0xf19673c9, 0x6a13e9eb, 0x72651720, - 0x53e49b15, 0x05ac02fa, 0xb42f30e6, 0x9be8dcaf, 0xd7b19a38, 0x1c71e059, - 0x502922ff, 0xac657480, 0x740fd53e, 0x1e812259, 0xc52d7c01, 0x961e0241, - 0x067e05f4, 0x4f713d3a, 0x24b2b3f6, 0x70889ac6, 0x668f73de, 0x54353d50, - 0x0cf50a8f, 0xc93d773a, 0xf54c73d3, 0xd02f4f24, 0xf54b59eb, 0x9eafcfd8, - 0x318fa627, 0x917a67f7, 0x580bcf5e, 0xfcf3916e, 0x633c95c6, 0x333fb9ac, - 0x949ea84a, 0x002cbdbb, 0x7f9d65e5, 0x864fb358, 0xf8c6c77c, 0x23328f11, - 0x86df8d1f, 0xaa4139f5, 0x97147c8c, 0xa7926313, 0x09825f78, 0x9fb933ee, - 0x7f927ca9, 0x653f29a0, 0x7c11a5da, 0x5eb770e9, 0x54e86026, 0xfea35e38, - 0xd234fd6a, 0xd9fae33b, 0x9fa07e08, 0x03cef483, 0xbb170263, 0x57d8dfa1, - 0x407ff406, 0x8eee5c0b, 0x2e3037c2, 0xea62a589, 0x991a60b1, 0x78e554bf, - 0xfbffdf1b, 0xfde107c1, 0xe0e74b72, 0x4bff8078, 0x8e21f71a, 0x4ca88ffb, - 0x32316e81, 0x3172c0ab, 0x6ffa4656, 0xb3f64669, 0x975e0341, 0x917e000d, - 0xa65debba, 0x1f915206, 0x4115825b, 0x3025cfe4, 0x8c7eb041, 0xe115641d, - 0xfef085e0, 0xc454bc80, 0xfd0355bf, 0x835f6c61, 0xfb5287f6, 0x5b7ed8ad, - 0x075bed2f, 0xb7da98e6, 0xda9817a5, 0x3ed069b7, 0x706747c8, 0xf01f68be, - 0x93b18637, 0x6fb53e6c, 0xf6a02f4d, 0xc0ac6a97, 0x574c7ed4, 0xbb60dffb, - 0x49fb63df, 0x703fc651, 0xe9fc798c, 0x6bf1e645, 0x416cfc7c, 0x431fb450, - 0x20a497e3, 0x117a7f1f, 0xd795bf1f, 0xabbed5db, 0x049aff0b, 0x5ea43aed, - 0xac683fc6, 0x9417fc79, 0xe56fc798, 0x2c17bbed, 0xa83bed13, 0x196978fd, - 0x2505ff1f, 0x0d66bed4, 0xb48f9178, 0x211531fe, 0x40d34f9c, 0x07485280, - 0x921d28fa, 0x93e818c0, 0x8481b2df, 0x38620787, 0x03137ddf, 0xd6e8e6fc, - 0x12042ca7, 0x9970f308, 0x8de2e9e0, 0x3f3e34e3, 0x9f5e6907, 0xab3aba2d, - 0x8cf9a651, 0x2e86b4ad, 0x37b6fe82, 0x678441ca, 0x2432bcad, 0x760a7cd3, - 0xb0a7be02, 0xf3ff3e30, 0x8ceb61aa, 0x674c8ae3, 0x2dadab57, 0xd2eab906, - 0x90d9e3ef, 0x055fe80a, 0x6ea8c132, 0x34f415b8, 0x39fc3d03, 0x0f4c63e8, - 0x392edcab, 0x5d9c7a04, 0x059b946c, 0xb2092edc, 0xff4087f7, 0xdffa227f, - 0xb77c70aa, 0x884293ce, 0xcc566fff, 0xcd9f50d1, 0xa4058eae, 0x5ca3f777, - 0xbb73a9d0, 0x14f64435, 0x9f88074c, 0x191449db, 0x1baed3fb, 0x305c94de, - 0x31f4d63f, 0x0b3777bd, 0xf2854e2d, 0x0ee79733, 0xeff8c370, 0x211d669a, - 0x7cc4fce3, 0xc7242dfd, 0x8725bfac, 0x2b0d69b1, 0xdc00fed4, 0xbcfd4d3e, - 0x1dfef0c5, 0x577c3301, 0x576e1981, 0xed05aa43, 0xad894299, 0xa9ef7a85, - 0xedebe730, 0x3812964c, 0x3f7b455d, 0x85f41c01, 0x3a60f747, 0x89bb1f02, - 0xfcddd3ae, 0xe53fbd5d, 0x4c2ca90f, 0x124b71f3, 0x5127fa23, 0x8f9b80b9, - 0xd3bfb23b, 0x0fcf9b55, 0xa0fe99fd, 0xec8cf84c, 0x58aecb7f, 0xd9ec059f, - 0x552f9a96, 0xf1c8c164, 0xc67ff644, 0xb8f1c8fc, 0x721f9c35, 0x39cf9183, - 0x53f2449f, 0x5fb8e379, 0x53f0321e, 0xbfb5fd69, 0xaf78643c, 0x1326eeb8, - 0xc3ba185c, 0x26bf3e54, 0xbb3f94d7, 0x3f94d0ba, 0x131cd973, 0xd07c1b9c, - 0xfcc67e54, 0x7bfca605, 0xe5311e2a, 0xc2b055df, 0x7811df04, 0xf6fe54ca, - 0xf94d6b69, 0xdc975d96, 0xf5547288, 0xde70cc81, 0xfad1daf8, 0xbf37b473, - 0xa45e2876, 0x57b011c7, 0x818e0e50, 0x7b6982bd, 0xabb248e3, 0x31e60f41, - 0x4b56a130, 0xc6cb83fb, 0xa4665ea2, 0xefd2433f, 0xc634c183, 0x843c979e, - 0x6346b93f, 0x89616061, 0x71f17425, 0x6fc86ca7, 0x0d7e4739, 0x9ec8fa08, - 0xf44b72f9, 0x72ebe5e7, 0xd3bd402f, 0x5f803e9b, 0x3ae79c7f, 0x99103d84, - 0xbf31225f, 0x7ebeb9f1, 0x7ae25cba, 0x53ac44be, 0x3bea5e4a, 0x0e10b99e, - 0x5b38ae0f, 0x5480f57b, 0xfd6893d4, 0x803f2127, 0x51e81814, 0x24c8375c, - 0x65bb6ddf, 0xea1957ea, 0x99abd004, 0x4257bfcc, 0x9bde133d, 0xec30cb7e, - 0xd475ef87, 0x8931acfb, 0xcab6f5e6, 0xa43cbfc9, 0x94fc7d22, 0x469ca91e, - 0x80656b69, 0x059543d2, 0x595e7e94, 0xe54b6941, 0x540f4a7c, 0x63fd2906, - 0x3f4a32e5, 0xf4a6acad, 0x4a1acae3, 0x510cac3f, 0xa3e95eda, 0x2e879754, - 0xf617ebfd, 0xc0b758b0, 0x8b0f6e03, 0xb2822cb1, 0xdee724cd, 0x53f39454, - 0xa3066f8e, 0x63ea7fbd, 0xde8ca260, 0x6fc915f1, 0x47d1d3bd, 0x085e4af6, - 0xcf4fa798, 0xa70c7b7c, 0x26c2dd93, 0x8f47d033, 0xf79cf45c, 0x2b04a1de, - 0xa9c032c8, 0x519c9bde, 0x0fb985ea, 0x3a2e75e9, 0x70e75f31, 0x3eb7675c, - 0xac6c97fd, 0x206972f7, 0xcaf7879f, 0xf0b30f34, 0xd7a45eb3, 0xf49bc50f, - 0x5bd29fda, 0x2e89dca0, 0x33a735fc, 0x6e48e748, 0x8354ffaa, 0xc7882995, - 0x2e10d8a6, 0x7bed4f8d, 0x38f285d6, 0x3eae5537, 0x7c77b234, 0x5467d695, - 0x29e30c3b, 0xa7c3346f, 0xdcc9a5aa, 0xbb89e07f, 0x95f21875, 0x45d0fabb, - 0x4a54ff48, 0xa6e67af5, 0xb1ced46a, 0x7c7141ba, 0x79f10efe, 0xf13c6370, - 0xa93bac2b, 0x3fbb3ffc, 0xf7a3d5bd, 0xf606b187, 0x01f50d85, 0xf73a0de4, - 0xdd07a8fa, 0x3f34af95, 0xfd49abd2, 0x1885ed06, 0x206677f8, 0xac10abd6, - 0x2f5e5bd7, 0xe397ad07, 0xf6a68df3, 0xbe8f3de0, 0x7af7c7a6, 0xb5855be7, - 0x7d04e3ea, 0xe7f0a575, 0xabd9d714, 0xbc4af3cd, 0xec6f2e09, 0x679a6d5b, - 0x7f900ff0, 0xc8292156, 0x9b82253f, 0x32c7143a, 0x6a97fa09, 0xe5bd50f1, - 0x6a572f12, 0x1e02d16b, 0xb466c762, 0xd1cdee33, 0xfb73cff9, 0x1fdf401f, - 0x1ecaadfd, 0xd7e17cc5, 0xb06cf551, 0xe7e82d6f, 0x0dbdd011, 0xef5053c5, - 0x3d76dd1d, 0x98b327d9, 0xa48b85df, 0x8d9d5602, 0x6609ce76, 0x7ffc8c99, - 0x35defd82, 0xc8deb0d2, 0x9fd468b7, 0xf3cccb99, 0x2667d82c, 0x0cc6bf38, - 0x939bb1e7, 0x56f3df91, 0xa0b730aa, 0x6ff39a5c, 0xbe49b8b7, 0x12c559f2, - 0x3f08ef5a, 0xa66ebdd8, 0x2fb907f4, 0xec99e57d, 0x87e8a1dc, 0xf75bfae0, - 0x7026140f, 0x3128a53b, 0xff20f9a4, 0x3f91868b, 0xfbe182b9, 0xa7a825a1, - 0x5de64e82, 0xefd27acf, 0xb23ff687, 0xd27cfabf, 0xfa214fc3, 0xbe49d721, - 0xda759450, 0xd84916c3, 0x974a415b, 0x76eb718b, 0x5c044d6b, 0x47d7011b, - 0xbf377fc0, 0xbf133225, 0x35025aa5, 0x5fce2496, 0x4a482f68, 0x47f816a7, - 0x51ed4fea, 0xb53fed7f, 0x3fa834fe, 0xfd7f54db, 0x0bfeb53f, 0x29bff47b, - 0xafa5fd5a, 0x0416da6c, 0x79b4537d, 0x3cc18b95, 0x4ea95474, 0x4bdd02f6, - 0x21762fd6, 0x82511c1f, 0xa3e7e42e, 0x34727921, 0x22d2f87e, 0xe7cca2fc, - 0x855d7090, 0xc7fd427f, 0x54d9f85e, 0x59bee7b4, 0xbd69baaf, 0x5b0d6754, - 0x1acb4e41, 0xdfa0a70a, 0x1c83e017, 0x46527a5e, 0x9fccd1b8, 0x4aafcf45, - 0x701eff46, 0x844f588a, 0xab2a5ec9, 0x9c24f3fd, 0x2759ca87, 0x7be459c9, - 0x04e9fed8, 0x5ab98fd2, 0xe87ccf5c, 0xe5f9d927, 0x0de52f02, 0xbb293b3f, - 0x30f6bd30, 0x4cb013ea, 0x7c8f0ec8, 0x41d840af, 0xc4ce2c87, 0xb1425856, - 0xa11fb11f, 0xc2f1d4de, 0xaa0edc42, 0xf0e4f0da, 0xb6afd083, 0x24badfda, - 0x7974be03, 0xf33f553b, 0x7a7aafd7, 0x62edcbd7, 0x5efdd7bd, 0x34f3de88, - 0x89adfb0a, 0xd86a25a7, 0xc971f685, 0x841bd55a, 0x9e9b25c7, 0x5c69ee7d, - 0xf5627eaf, 0x17f5045e, 0xc3e37a6f, 0x6f170031, 0xf0a71351, 0xe4a43861, - 0xc394fa6e, 0xba23f9bf, 0xf2f451e9, 0x18679a1b, 0x4270fe7f, 0xb78a5d37, - 0xb0d8d6ec, 0x5098f89e, 0x716b5bbf, 0xfd4fa144, 0x676849c1, 0x56f86d55, - 0xd1e575c3, 0xc94b125d, 0xb5cf8288, 0x80bd906f, 0x0a7a2278, 0x2fd1757a, - 0xd0397ca2, 0x247af505, 0xbdcb22bd, 0x1465fa81, 0x93fd17af, 0xbe2fdfc0, - 0x4fec7e8a, 0x43c45ead, 0xb9f78bc1, 0x95873c70, 0xcfe7ce0a, 0x3f464e2c, - 0x4c1a817d, 0x9fca5376, 0x9fb9ac17, 0xbdff2ff8, 0xfaf993fb, 0x42d7d7d0, - 0x2fb05573, 0xeaf6738e, 0x799c68db, 0x587c402c, 0x0fec8cf0, 0xc2b5fa41, - 0x22896f26, 0x9732c527, 0x80ebc393, 0xc3ce30b8, 0xbf414eb8, 0xd0e5efee, - 0xcc8ff27a, 0xee0fa861, 0x6cf1fdd7, 0x8b5fc12e, 0xb27184fd, 0xdae75f45, - 0xbb5bfc4c, 0x74e919b4, 0x052f806c, 0x4ce56afd, 0x487c0a09, 0xf95ea067, - 0x3853abbd, 0xc947989d, 0x5d81ef16, 0x639f0130, 0x67d566f9, 0x8f7a6e1f, - 0x6ee8c99d, 0x1f689e7f, 0xf3831dfa, 0x5664e1f9, 0x7c651f50, 0x07aeb235, - 0xf0375e60, 0xb9de4199, 0xc23ed7fc, 0xff975de5, 0x31934dd0, 0xb9f7abff, - 0x387be11c, 0xc2bf425f, 0xfbbf9429, 0x83f48956, 0xc9a38595, 0xe42aad79, - 0xc91f9cdc, 0x457fd02f, 0x0df0338a, 0x744093b6, 0xde5abf20, 0xa8df784a, - 0x575db157, 0x39757acf, 0x20fa17ce, 0x707d064f, 0x603eb759, 0xe81eb9ab, - 0xf20aeedd, 0x7a1a9bf5, 0x5f9469ee, 0x07a0d790, 0xe3f557e5, 0xdc6f8ff8, - 0x209de1fb, 0x75ebc7b7, 0xd5eb35b9, 0x782db948, 0x7c84bd69, 0xc7b7291a, - 0x894ac00b, 0x3cf0b726, 0xb416dcaa, 0xaaf44bfc, 0x65c7c78e, 0xf5d55eb3, - 0x8cf86f64, 0xca9793d4, 0x127aa89e, 0xecb3ef7e, 0xf3a8fc9e, 0x457fcea1, - 0x80bd29bf, 0x9f3a09fc, 0xc5d87cea, 0xf61f3aa7, 0xf098cff0, 0x3b7f9918, - 0xc10c04f2, 0x7f255dbf, 0xdf134962, 0xdef7838f, 0xf8459fec, 0xc734d1f2, - 0x9fecdfaa, 0x11438468, 0x79447d70, 0x8fec045f, 0x80881f28, 0x4be54c2b, - 0x8c6af71a, 0x2a6c20f8, 0x2bff9d67, 0x759445f6, 0x950f3eac, 0x82d49c37, - 0x9d691fc8, 0x753fea1a, 0xe8a89821, 0x9329dc3f, 0x7003b0ff, 0xe9da04bc, - 0x0a1198d8, 0x6c591e82, 0x0ecdebe7, 0x012ba777, 0x1cf1c5d2, 0x96d24cee, - 0x9fd41ea0, 0x1fb9da77, 0xe9dfc3a4, 0x31f8378a, 0xa4c9360e, 0x6c425bc7, - 0x093f3472, 0xdf8434cc, 0x3e5bd616, 0xe0768ff7, 0x87b633be, 0xcf40cefb, - 0xfa4765ab, 0x56bf5c7c, 0x23605ecb, 0xedc16b36, 0x77a1742e, 0x71ba0d34, - 0xfd9f3c1a, 0x6db7ccb6, 0xafa53e82, 0x8471dd61, 0x2b189f05, 0x72de7ee1, - 0x4d999fe2, 0x6b321d7c, 0x28797479, 0x39e5ef12, 0x77a869e6, 0xb9f0fd61, - 0xd7ac0fd1, 0xe23ab053, 0x42f5d379, 0x3d69aa6e, 0xce6b5458, 0xd4f5880f, - 0xc9feba37, 0x7fa49964, 0xeb84a170, 0xafb7a17a, 0x38de8796, 0xb1d3e80d, - 0xbfb8664f, 0x2649aa7a, 0xc8da9cfa, 0x305953f7, 0x8cafe489, 0xd4be9275, - 0xf286d6f1, 0x7aef7175, 0x9feb6dac, 0x3e421fb2, 0xe187f6da, 0x6db482bf, - 0x778327db, 0x47cafc20, 0x3d607fe9, 0x65d84fcb, 0xc7733f27, 0x7ff1272e, - 0xa5dfcec7, 0x76f0843f, 0x3af7f92b, 0x1c3b7d76, 0xa163b1f9, 0x60f500b5, - 0x7ebe00c7, 0xedf9daaa, 0x7f9a16f0, 0x331d1117, 0x7de88d14, 0x072fe9aa, - 0x54e02e30, 0xed0a8c13, 0x24b15d8b, 0xdaafe55f, 0xb1d11fc9, 0x80ecdbf3, - 0x9e379fe3, 0xd3ffb132, 0x5ed364e1, 0x73c5fec2, 0x8ef979bf, 0xc02ecfd1, - 0xdd86f1fd, 0x9fc84cda, 0x875fdaf0, 0x78ed7ea3, 0xed4ddb89, 0xdc1acb6a, - 0x48ba18df, 0xbd02a85e, 0xfac851da, 0xd16fb631, 0x4728f1c4, 0x57f2f13d, - 0x2f9cb3f2, 0x7c28263e, 0x8feffb3d, 0xf5c7c90f, 0x9364339f, 0x1ddfdc70, - 0x89ea03f8, 0x4be2565d, 0xebc7bc7d, 0x733d9017, 0xfbdf71ae, 0x52dc6e3f, - 0xbdc67cf8, 0xff9cdfe0, 0xfa878aad, 0x3d072917, 0x03e77cf9, 0x7a726f04, - 0xc9e7bfa9, 0xa7ff6bef, 0xa025fdd1, 0xe3dcebbb, 0x4b3fff0e, 0x0ba7b7f7, - 0x3e31bbba, 0xbfb5fca0, 0xa87eff52, 0x37f96b9e, 0xe36f7ba7, 0xb7fdedd7, - 0x33f79e2c, 0x5664fca1, 0xe2c340ed, 0x6f3dd2da, 0x5bee4267, 0xb1e37b69, - 0xf623e3bf, 0x5e34f47b, 0xf1b6fee5, 0xed03efb8, 0xac4978b2, 0xab3af917, - 0xfa2fb0bf, 0x3b23cbcf, 0x63da7fa4, 0xc5304f64, 0x2bf712b3, 0xe99f4adf, - 0x360bd8a5, 0xc200e3e2, 0x6c052bee, 0x4afe6f5e, 0x4adc3e62, 0xfd7e9fed, - 0xd373b43e, 0x83b264d2, 0xf7fb2521, 0xfe64d775, 0xad3344bc, 0x98f5ae87, - 0x129347d7, 0x89a8ebcd, 0x19abbea2, 0x0ed5ffef, 0x3c021429, 0xcbf01f8c, - 0x8ea7f444, 0x126548bf, 0x605893c0, 0x263bae11, 0x9df5cc3a, 0x836c7dc0, - 0xc5eff1bf, 0x3c2ec4e3, 0x47e95c0e, 0xc9900e3c, 0x3c4e7aaf, 0x6f09bf62, - 0xc78c2199, 0xe3978a61, 0x4bd4a131, 0x1eb16a7e, 0x1da26ec7, 0x349638a3, - 0xb82b3ca3, 0xa078e69e, 0x9ebeb875, 0x4cdf0dee, 0xd115cfac, 0x257f8ea4, - 0xcdd9f64d, 0x5cfad1f5, 0xa50fcba7, 0x7fc74e87, 0xaac92e94, 0x8e692e99, - 0xebca0a39, 0x8c3f5c64, 0x1c99f2c4, 0xb42a0b4e, 0x0fd624df, 0x28e678d7, - 0xa4278041, 0xaf482a65, 0x22f6db7c, 0x79b51f8c, 0xc5c7ea25, 0x1f9a166d, - 0xe112596c, 0x428d487d, 0xf7167bf0, 0xd4f7a428, 0xfe395e2b, 0xbb3f4320, - 0xba06e34f, 0x7c97ef9f, 0xd8cce67f, 0xf0c7f46c, 0xde7fc61f, 0x59b7eb00, - 0x063859ab, 0x615b34f0, 0xf404b8c1, 0x73ec4b93, 0x0cdc9f93, 0xe4aaefe3, - 0x55ce7aee, 0xf2bd37be, 0x015f4ecf, 0x45f9f63d, 0x94c76d8c, 0xc6288a6f, - 0x9a8ff6f5, 0xf7cabe38, 0x1e40d0b3, 0x0dfb2187, 0xab2f8afb, 0xcaf33fdc, - 0x891a5f1f, 0x1d71dceb, 0x7eb8e343, 0xa971e2cd, 0x8a70bd62, 0x0ebce279, - 0xe283afd4, 0x9f74bf68, 0xe7168cec, 0xbfac41b8, 0x28f1837f, 0xb2d47690, - 0x57d7196a, 0xbefc93ac, 0x5b1b5ac1, 0x661e251f, 0x7e116a8d, 0xf8374122, - 0x7fb8d9c9, 0x0d9fdbc3, 0xe919c6af, 0xa8e536d6, 0x1d27bc32, 0x61b9f7f0, - 0xc51feaff, 0x11f7ae2f, 0x2dec1bbf, 0xf451fc93, 0xdfc0bd47, 0x91df3dd4, - 0xa6d2f49f, 0xdfe416b5, 0xa62d6b4b, 0x553ad8fd, 0xb04631f8, 0xa9afd811, - 0x2cceec7b, 0xd93ecba4, 0xe5a5f18b, 0x40b5274d, 0x48c47d94, 0xe8fd627c, - 0xdd556f7f, 0xb50eeed4, 0x75e2267e, 0xc31b09c7, 0xad76f575, 0x3f5a38ba, - 0x7ef2b4ef, 0xf7f566ce, 0xf7f8cf0d, 0x0eb8efc3, 0xae3c7847, 0xf0996b3f, - 0x1ff24483, 0x553e3e23, 0xbf3842c7, 0xf5157ae2, 0x8c8da9c2, 0xc94077e6, - 0x06feb863, 0xd1b1ff79, 0xe37173af, 0x5da0df96, 0xb924d650, 0x4ca24b71, - 0x8fd0d169, 0x2f18de5b, 0xe99c3ce3, 0xdd6fe3d1, 0xc8356ec3, 0x10aaab45, - 0xd98ef6be, 0xfbb61771, 0xd0c69b65, 0xdebdf14e, 0xfc79c2e9, 0x2491a6cb, - 0xeb8dbd07, 0x34564ae5, 0x841ce311, 0x87e48c3e, 0x4c631ba1, 0xa07215f0, - 0x54d7ca1f, 0x6f3ccb6b, 0xd32dfa14, 0x788fb124, 0xf42dfa9e, 0x7b7e99ff, - 0x016fd75f, 0x23906fd9, 0x419bc0bf, 0xd344a5bf, 0x4f25736f, 0xee7de20a, - 0x482941ce, 0xab6fb9d7, 0xdbf4d149, 0x2fbe4aa6, 0x4dc459ba, 0x7e803477, - 0xdfa0dcbb, 0x45bf401a, 0xa3191f89, 0x73fa7ee9, 0xbfd0b7e8, 0xa136fe46, - 0xde328b7e, 0x74fe041b, 0xe9bc36fd, 0xe1b7e920, 0x3c53160d, 0xf84d44f0, - 0x6fd57a9b, 0x68add252, 0xbd53ef1f, 0x67f851b1, 0x37c7b093, 0x6c46388b, - 0x955cf507, 0x5cf4c3f6, 0xb9eaf9de, 0x759e117f, 0x2b77373d, 0x9ee8b8a3, - 0xdcf5c87c, 0xe7a0eddc, 0xae47e424, 0x64eee6e7, 0xa1172fdc, 0xd0f486df, - 0x97ca8c6f, 0xe5fbf985, 0xde4f198d, 0xf08df50d, 0x941b5ea9, 0xefadd11f, - 0x5df51946, 0xbe8bd695, 0xfa7e77db, 0x77d0ab6e, 0xa206c7a0, 0x0fe48d7e, - 0xde39936f, 0xc3e8c77c, 0x79465f1b, 0xfb4c9df9, 0xf859ef92, 0xa33bd1fe, - 0x7f21670f, 0xf3fa2a7d, 0xd9e9c6a2, 0xfaa4195e, 0xc7cebc27, 0xfb91ba57, - 0xb81acbcb, 0x2b56587d, 0xe7f03c87, 0x69df31a4, 0x9dc2ffd8, 0xf8014b12, - 0x13f56b26, 0x9febb40e, 0x1f589957, 0xf034c94d, 0x629cacc3, 0xd957fbf2, - 0xfcf0eb5d, 0xd9852cd1, 0xec5fbfd0, 0xed147498, 0xbe1ce2e0, 0x9e2c501f, - 0xb3b071eb, 0x4464f4bb, 0x9ce3483c, 0x9eb3fb37, 0xad531671, 0x9f53ae9c, - 0xb7184295, 0x22ee33da, 0xb8a17a44, 0x5dfcfcce, 0xc9377f21, 0xf62f842d, - 0xee351cae, 0x85d72f43, 0x4f027da7, 0x9e131780, 0x3c545242, 0x64a7a501, - 0xa5e37726, 0x4b2d77f0, 0xf0a05f70, 0x91f68929, 0xe3adc723, 0x3afc722d, - 0x773f751e, 0xbf2fa8b1, 0x6b9d2d69, 0x8e8bc48a, 0x747c48e7, 0x1f023de1, - 0x7e5d69ef, 0xd71891ed, 0x7a437c04, 0x809ff826, 0x3fc76817, 0xf9d322ee, - 0x5e048f9b, 0x9b8f5646, 0x370fe180, 0xe43a1c61, 0x79ccd5e7, 0x63e02fb3, - 0x119ec7d4, 0x315e9d38, 0x7dc01ac6, 0x4ef60dda, 0x1f3a83d2, 0x3e72b30e, - 0xd95e84d4, 0x3c62afd1, 0x251bf3ad, 0xe521da37, 0xb5e13b61, 0x0ed1f81c, - 0xf53ef645, 0x578124cd, 0x6aaf9d37, 0xd013f314, 0x26eb82c1, 0xf10abe7d, - 0x9b2358f3, 0xebca5d38, 0x58b25d38, 0x94c7ed27, 0x30de48d5, 0x71aca78c, - 0xeba1c50e, 0x0e7e19fa, 0xf0a29d23, 0x7f8d12af, 0xb39b3a19, 0x62cde7bb, - 0xb5aa6e51, 0xe7dc43fa, 0xb1f20a99, 0xfe10d896, 0x3efe1677, 0x2450fc57, - 0x78132ebd, 0x757884db, 0xb93afe20, 0x8efe15fd, 0xf9e969ce, 0x84d04ae5, - 0x9f4f09d7, 0x53b7fce6, 0xac5fa0f2, 0xcfc86f0b, 0xc74a3f90, 0xd233f21b, - 0x465729a1, 0xddf00f38, 0x78e7a327, 0x28d4bf71, 0x0f3b85f7, 0x919ffaf2, - 0xb8ca2cbc, 0xff7f307f, 0x4deebe40, 0xc55987de, 0xf7f0413a, 0xfdcef63b, - 0x77bf9123, 0xd12fdc4a, 0xf7da6f14, 0xd7cac1bc, 0x20ec1b4d, 0xf6dfb807, - 0xe75deab6, 0xae1fa9e9, 0xc03972b2, 0xe0c784f5, 0x0704baf7, 0x75a6f182, - 0xa4178a36, 0xf6e40c7e, 0x6f5f51aa, 0x5ba4b3b2, 0x7faf7ab3, 0x37bfa88a, - 0x8787497b, 0x47a87b61, 0x21bda11b, 0xce45eddd, 0xe0ffba17, 0x43bae35c, - 0x3bdfcff0, 0x1f9dbd2e, 0xce554f1a, 0x4c5f699a, 0xb54aab8f, 0xd1515e04, - 0x992c9bbe, 0xe7a0b7e2, 0x70ffce82, 0xa36ab7fd, 0xa59faf7a, 0xd08ec8da, - 0x2d5ecbcf, 0xf010583b, 0x254fa5f6, 0xe32b0179, 0x7f38b183, 0x1079878c, - 0x8ff72f92, 0xca6ee8fa, 0xed9f6997, 0x29f5dfc6, 0x1bc87dc5, 0xbb1d0c79, - 0xfb225331, 0x6cac3de1, 0x36e1da34, 0x268ab3e6, 0x47e73f21, 0xd73c21f1, - 0x3d5b5992, 0x3d7203c1, 0x85542ea2, 0x674277a9, 0xaf483be2, 0x7a433271, - 0x4cfafb35, 0xbef7f9c0, 0xdc4cb33f, 0x813b078a, 0x8fb119ea, 0x31b96125, - 0xce5a24be, 0xeaf86e8c, 0x7fa05bfd, 0x5ecbf7a3, 0x69bb940f, 0x7281c3af, - 0x85b56436, 0x19780c05, 0xe85542c3, 0xc87d1a77, 0x83ea0b77, 0xf07bb002, - 0xd341497c, 0xc2172ada, 0xbf7a25ab, 0xe498183c, 0xaa6dfe82, 0x32e93939, - 0x0e500bd4, 0xcd5f29ab, 0x4ad795cb, 0xce710c5e, 0xf1415a6b, 0x12b57948, - 0x14dc601d, 0xd78d9892, 0xbd41b21b, 0xfbc3569b, 0xc17f3859, 0xed6f58fb, - 0x416ff7c9, 0xa4fd03bd, 0xfdf237f7, 0xcf783cfa, 0x3b527283, 0x5c2bea87, - 0x073c312d, 0xcf91b053, 0x55fb054f, 0xec37e62f, 0xdde68a7e, 0xdf5ed029, - 0xc28f9c0c, 0xd13ce913, 0xe74dc948, 0x80be1f38, 0x0e0756f4, 0xa5f05f18, - 0x4909f8f3, 0xa3fd62c0, 0x6dfd7fdb, 0x9e535cfc, 0x07d68177, 0x272779ea, - 0xfc42c329, 0xe1f69274, 0x03be010f, 0x79379c56, 0x9cdecb3c, 0xc316b42f, - 0x1b6398fc, 0x6acfef44, 0x1e71471c, 0xe29f99b3, 0xe68ea63c, 0x57bbe776, - 0xefe843da, 0x4ced577b, 0xaf7be7c3, 0xf6f3d2b4, 0xb70f5c4d, 0xbf21680f, - 0x2ad5e1fb, 0x552ff3c3, 0x13d265ab, 0x74aa3787, 0x867e576e, 0x6fe437c7, - 0xdec876e2, 0xc3debcd5, 0x9b7edc75, 0x936dccf0, 0x5fce1e70, 0xeaf9cfcf, - 0x875f5a7a, 0x4d0bb9e6, 0x9ea45bf3, 0xa970f5d5, 0xf54147c0, 0x8f4fda5a, - 0xfaa5bbd4, 0x6fa1187c, 0x9d9f714b, 0x24c3d3f6, 0x91f5a547, 0x6e8e65f1, - 0x43f20dbf, 0xefe23bf8, 0xc32afdb2, 0x45f48d75, 0x678a24db, 0xf21ef9c3, - 0x3e493747, 0xf8287b8c, 0x7b221ad8, 0xe33b943c, 0xf99e703f, 0xc8f0cac4, - 0x03d22b48, 0xb58e54f4, 0x84bf8ff3, 0xb3df47e7, 0xf010e461, 0x5fe12e4f, - 0x5ace138f, 0xb27ee3cf, 0x8c995bde, 0xc4d98de7, 0xf207a43e, 0x3016646b, - 0x92a38de8, 0xf93b96ef, 0xfb46e0fc, 0x966ba747, 0xf3879d56, 0xeb8d916c, - 0x957acf47, 0x0bc78bce, 0x3e0bd618, 0xb70a77b4, 0x0cd648af, 0x73b850fc, - 0x0ea83245, 0xcbc444b6, 0xe6738954, 0xa76f1a85, 0x5ee49770, 0xaf47686b, - 0xdb57af47, 0xb41bdfce, 0xd5bda793, 0xa3fd885f, 0xa1ad7e71, 0xa7ac88de, - 0xd4bdfb47, 0xa75ff393, 0xffb9e257, 0x0a65779c, 0x62f9cf76, 0x3ee320ca, - 0x7eea9e8f, 0x2df7ece6, 0x5fc067cc, 0x98631fce, 0x86ef40cf, 0x40ff2051, - 0xb91a1bbf, 0xea30d73d, 0x459a56a0, 0xbde51bb0, 0xcba3f84c, 0xbbfdf226, - 0x16f7cc86, 0xc94ffca1, 0x581f8892, 0x49f5a030, 0x83cdfb24, 0x59f900fb, - 0x787cfdfc, 0xe1b2e51f, 0xa0a72e29, 0x4fa83c2f, 0x98af56ca, 0x256be544, - 0xb0dfd60f, 0x92ec9736, 0x51991c82, 0xb241ed7e, 0x0f1a0a93, 0x833ca226, - 0x7b44aefc, 0xd5ac6ca0, 0x9758ea8d, 0xdfce5d4b, 0x9961e715, 0xcf0c3dcd, - 0x5876e077, 0xf796f934, 0x72b76133, 0xe1cf2cb9, 0x26eefb72, 0x3e784715, - 0xad724e72, 0x728cb1cb, 0xc72dd59c, 0xd04f577b, 0x870fae50, 0x99a38a24, - 0xe5007a80, 0xe71e837c, 0xf3d8edc4, 0xd973f395, 0xbf20a599, 0x72ea5f38, - 0xa475cbae, 0x2d2b373c, 0xee3f62b7, 0xe34ed2bb, 0xf6d57098, 0xfae3ef0f, - 0x275ff68a, 0x3260f55c, 0x853cc7ea, 0x78e979c7, 0x5c78552d, 0xad7e8f60, - 0x3df5a05c, 0xf445fe9f, 0xd9ab33e3, 0x8b6f125f, 0xb5eff1e7, 0xb9fdf12a, - 0x9c87b3e4, 0x9e7ca79d, 0x4b9d5caf, 0xe5f6f53e, 0xe27ae69d, 0xf5476991, - 0xf01dafac, 0xbe3c0618, 0x8a59f1b5, 0xc2f13e0f, 0x8748a9c1, 0xe7c01de2, - 0x9d1b5fc8, 0x4e7a8c2c, 0x55bcd109, 0x39d320d4, 0xb384a603, 0xe51a716f, - 0x1575c798, 0x3f12766f, 0x0d64bd15, 0x8bf7814d, 0x9c317db6, 0x76166ae2, - 0xf05adc52, 0x072f6105, 0x1ca3865b, 0xbe3c2914, 0xfc2f522c, 0xe7edc6da, - 0xd3b1edb6, 0x1d527c70, 0xa8a2dfbf, 0x6ad576fe, 0xc278a7d8, 0x50bb52a6, - 0x8379f68e, 0xfe78c7c0, 0xbc67fb17, 0x2b8f4157, 0xf5c0db6b, 0x1aa35144, - 0x8a327bc2, 0x63b4b6ea, 0xc7d171bc, 0x957ff256, 0xf3a49dd7, 0x6f361314, - 0x794aff22, 0x8fda6ca3, 0x59df11eb, 0x18ad8727, 0x4a50d897, 0x1f0090fb, - 0xc45eb824, 0xf8c0fe53, 0x3bcde2c3, 0x850105b7, 0xef3f2fc5, 0xac72fd42, - 0xf10bbd79, 0x359ef50e, 0x3c47bade, 0x2223fd67, 0xc386f39e, 0x2f4b6f74, - 0xf0c79cf1, 0xb794100f, 0x4e78e66d, 0xec87d756, 0xb667e84b, 0x47feca3f, - 0xe9be7d97, 0x1e7835eb, 0xe3a5eda1, 0x25dfb06b, 0x0d72fb7f, 0x5db189c6, - 0xcaf79a76, 0xe280f85f, 0xbef7f5b7, 0xc87f09b0, 0xfe29e786, 0xab13fdbd, - 0xdf6b6b17, 0xe31d3879, 0x7cb7db06, 0xccfe8c97, 0x26af3b79, 0xadbcef7f, - 0x94585213, 0x914f4379, 0x11e7437f, 0xb7491f7f, 0x297b0dbd, 0xd004ed9e, - 0x5760f51d, 0x297d6e9c, 0x88f67f8f, 0xd18ddcf8, 0x88f43bcf, 0xe5b86dc7, - 0xff512bc6, 0xf27b7037, 0xefb9719c, 0x3f2f3d03, 0x146e3a0f, 0x37f5d7f1, - 0xf72e359c, 0xf401fe04, 0x74cdd8b2, 0xf661bafc, 0xbcc69faf, 0xc6bd3e86, - 0x03cf86e5, 0x8a79fa7f, 0xa73e6c77, 0xa5e8e51d, 0x343c50df, 0x078a6fd2, - 0xd3afa3e7, 0x11ca3cf1, 0xce3a73b5, 0xad3b9d3f, 0xd14fdf74, 0x9e488fce, - 0x47beb7da, 0xce266a7e, 0xaeb3b435, 0x973f8f1f, 0x9d6b78c4, 0xd0579e3c, - 0x3d7de301, 0xe22e7a2e, 0xeb5f397a, 0xc5bdbef1, 0x1f6d5ef9, 0xe00fee28, - 0xb5a5c8f1, 0xb3f1107f, 0x729374dd, 0xcf075e90, 0xe3ad471a, 0x72f42dc1, - 0xf47b1c77, 0x38aeeab8, 0x21ba08f6, 0xea9e713d, 0x3807538a, 0x49f9046d, - 0x2e768a3e, 0x8f2d7da2, 0xa3576f7f, 0xe3d6379f, 0xf4117dda, 0x9bdbc7d6, - 0x7b72e8bc, 0x50fc71ae, 0x4266d13c, 0xb57c4f52, 0xbf5d1f7d, 0x7f4bb4cf, - 0xebbefad7, 0x148954bc, 0x5eeb1e79, 0x86d2cbe4, 0xeccfe483, 0xf18b7f5a, - 0x7bff09b6, 0xc5320bdb, 0xdfa92f39, 0x523dfa4b, 0xbde1947f, 0x7bfa512d, - 0xe7d85dbf, 0x68fe7c8d, 0x7219c97b, 0x7b6d3d40, 0x975f13b6, 0x71483c6d, - 0xbdd66fd6, 0xe218b5ac, 0x08fe7027, 0xf6d3c619, 0xa4e1eee2, 0x30fdc5cf, - 0x8954ed91, 0xa29bca76, 0xf1be53b7, 0xe29da9a4, 0x76e6bd60, 0x63bdbb9c, - 0xac76ef8a, 0xb73358ef, 0xcbd58f13, 0xf6d14393, 0xd8aaec69, 0x29e6afef, - 0x0f74a3cc, 0x7bdf938e, 0xc862bb23, 0xcce79cee, 0x112e38f9, 0xbae28d53, - 0x388816aa, 0x537a9fb0, 0xce55de91, 0x77f618eb, 0xe0d7e231, 0x01dd51ff, - 0x9aaaf686, 0xbf42cfea, 0xd1dea443, 0x642c2d12, 0xe73cf7a0, 0xed0f14e4, - 0x90d3848b, 0x0f32079e, 0x67ef58ab, 0xcfabfe11, 0x0524b614, 0x5059f7fa, - 0x7a802ef2, 0x0c5ff7d9, 0xd67b3bf0, 0x8781c3af, 0xa9bf9365, 0x0079dacc, - 0x35ec2bd7, 0xc847ed3b, 0x7f74ecbb, 0x3b1af948, 0xd6ef778d, 0xbb239f6f, - 0xc656d7fb, 0x556087f7, 0xb996f783, 0xb7871d79, 0x2fe6bb7e, 0xcbe35768, - 0x1afe7ed0, 0x89eb8f28, 0xfeb4b18d, 0x8e2978e9, 0x7fcb51ee, 0xa8a9a1ed, - 0x3963f2d7, 0x4e6fe63f, 0x7d415509, 0x6e1c49ad, 0xee8034dd, 0xc97e28ab, - 0x7ba5f149, 0x8652beb7, 0xe6fb54f3, 0x60330c58, 0xfb09afed, 0x7ee237ff, - 0x63d51aad, 0x642f338c, 0x2e78c78a, 0x536118a8, 0x3f23135c, 0xfa11c906, - 0xe8e31ab1, 0xc5d8113c, 0xa84e7aa6, 0x89780f9d, 0xf8fd838f, 0x3f70aa39, - 0xe59107d4, 0x76fdfcf4, 0xdcbd8e7e, 0xba39ef0a, 0x9d6b97cb, 0xeeae1c79, - 0x3349f5c7, 0xe744ff95, 0xb3df9173, 0x23fe5e5e, 0x7aaedebd, 0xe265fbf8, - 0xfe489b7e, 0x57a5d43d, 0xb4717afe, 0xf4a25bfb, 0x2fdf9e9f, 0xed05a0b1, - 0xba762d96, 0x67ef0bb7, 0xdb0e73c0, 0x55ffbe34, 0xfdd30ae2, 0x3e843b39, - 0xd309892e, 0x44fd3e7d, 0xc23cb03f, 0x22f2d6cc, 0x15f4bdd2, 0xb3f8c33b, - 0x3e9cd7d2, 0xb6e977a4, 0x957f5b6f, 0xb18bf185, 0x7d2bd7e4, 0x1f117fed, - 0xd3c35a94, 0x2dbcfee9, 0xe7f78656, 0x3b796db5, 0x4db5e51d, 0x9c27a70d, - 0xb4af5f65, 0x57be6ade, 0x58e38c40, 0xbc42e865, 0xaf3f4177, 0x9e8bd45b, - 0xdb8632b9, 0x9f18f6d7, 0xdde48635, 0xb1d44f7c, 0xc641c6ca, 0x9e45fbf3, - 0x7fb17ae8, 0x9d8ffa8c, 0x38f47743, 0x263fdaf7, 0xe699ed09, 0x96407464, - 0xfa8e3d81, 0xe4eea8bc, 0x7c1ff430, 0x6fdfa316, 0xf9c389e0, 0x73ad33e8, - 0xcfbfea18, 0x19873bd2, 0x952399e7, 0x92a28f36, 0x8ed2875f, 0xfaf327b5, - 0xb5378c31, 0xf7a68b4f, 0x12c4c586, 0x8e1e8afe, 0x7a8e7a8d, 0xabe70c4c, - 0x531f6834, 0x43e5176c, 0x2d33f76f, 0x31b87a44, 0x49ebc3c6, 0xbcf8690b, - 0x20fb6eb8, 0x950a1e23, 0x72072a6a, 0x642cf84a, 0x832cb52b, 0x2bdbd6fe, - 0x28f0ef9c, 0xf2813f74, 0x55f8ba7f, 0x3933a6ee, 0x518e3191, 0x5c6614e0, - 0xe7eb33f2, 0x6fd51448, 0xcc69fc43, 0x646456ef, 0xf7926a95, 0xa94f5618, - 0x7e2ecc03, 0x43055a5f, 0xec44793d, 0x0c1fa3ef, 0x3d7c6ed3, 0x383f7a48, - 0x328bb180, 0x4f09bef0, 0xbf80db9c, 0x3eb3706b, 0x2b69e309, 0x5317d718, - 0x488f68dc, 0x033b00c1, 0x595554fc, 0x03df8837, 0x2f187cc2, 0xf42c2649, - 0xf37ee5cf, 0x8083b43b, 0x843df94f, 0x1550b157, 0x86c318a0, 0x9e3aefc9, - 0x96f3fbf1, 0xeb8ccc7d, 0x0741128f, 0x7a4ddc16, 0x7fbac1cc, 0x5aa3009d, - 0x155b7d45, 0xdc1cb7f7, 0x59b8739f, 0x58c3ed18, 0x42c70b07, 0x1caa18ea, - 0x2bbfca33, 0x5f03600b, 0xf39ac7ba, 0xf402e523, 0xf5bb445a, 0xf7a83f84, - 0xbf7a88ab, 0xabf7a88a, 0xe3abd5b3, 0x2836dca9, 0x58a5ef03, 0xf02f595c, - 0x09b3dbc6, 0x867e01bc, 0xcc7f3de0, 0xfb15e312, 0x18d784e6, 0x962b1bd1, - 0x8e6eba07, 0xfa7e20c9, 0x4eaedc59, 0x8966978c, 0xc3d70c35, 0xbefd248b, - 0x1877e64f, 0x1b6e63de, 0xa223e1c9, 0xcf02cd9d, 0x55bf748b, 0xb276f28f, - 0xb7947abf, 0x263e56f7, 0x6f67797a, 0xde8d89fd, 0xea5ef89f, 0x5a8d8eaf, - 0x4bd50fff, 0xf47daf65, 0x76efee0e, 0xa03727e9, 0x6e676cde, 0x1a54fd46, - 0x16b7fadf, 0x4cedc27a, 0xde999a5b, 0xc0dfc831, 0x9a17316f, 0x49f2479f, - 0xf472fe14, 0x29df7185, 0x61f3bbda, 0xe74d5e7e, 0xbe315c83, 0x9f7cb589, - 0xdc79eefc, 0x46cb078f, 0x25dfe61f, 0xe1aeeff2, 0x0fdde3f6, 0x1b0fb4cb, - 0xc1d5bf79, 0xe1efcdff, 0x801f07b8, 0x5f33ddbc, 0xa233850a, 0xdec5dbdd, - 0x677a878f, 0xde44fe88, 0x9e601583, 0x68e4cb49, 0xbe7160f7, 0x45e1cfd4, - 0x8b317fde, 0x66fdc5f9, 0x3159e7e6, 0x22dbe26e, 0x0f55a425, 0x82c79eed, - 0xd1ef802b, 0xc7be04fe, 0x9c592ffd, 0x8d2e66c7, 0x9adfd7c7, 0xa77fd260, - 0x70e27886, 0x8baf66be, 0x7cfe6ee7, 0x149eb5ee, 0xe54579e3, 0x1ee9ac74, - 0x9bd52aa0, 0x3d4dfa8a, 0x80f33d7d, 0x07a76a1c, 0x1f218f31, 0x7e1256ec, - 0x3d24f30c, 0x5084aa95, 0x3f6e2a2f, 0x37bb47cb, 0x5eb3f39e, 0xaebc4b5e, - 0x177ccecb, 0xe6461dfe, 0x5dcfff81, 0xdff3a1e1, 0xa7fc3957, 0x5d95fe71, - 0xa380de39, 0xb7043f27, 0xe15771f2, 0x8e7a33b8, 0x7af34aa7, 0x0ebedec9, - 0xcbf245e6, 0x3fd86d79, 0xc8f9ead9, 0xadfbfd83, 0xd30fd0ca, 0x23de3f13, - 0x153fc821, 0x24714fea, 0xc194dc72, 0xbc72fed8, 0xfff4146f, 0xe8bf7132, - 0x52264aa2, 0x08b7571e, 0x34a51fef, 0x913ea447, 0x8f72a64e, 0x974a7b8a, - 0xd5297a54, 0x56f36bf1, 0xb6983dd3, 0x36fb790b, 0xa25fa0b7, 0x402fe045, - 0xb52d97f6, 0xed1df682, 0xde308aee, 0x60d2c727, 0xb961c1de, 0x9abf09ab, - 0x13bf919b, 0x456c13ca, 0x66b55218, 0x7149d10a, 0xc87cb057, 0x0604754f, - 0xe37da2c7, 0x6987df31, 0xd6711d4d, 0xf8bb31fb, 0xfbc7136d, 0xb7e71263, - 0xa63fbc48, 0x6e307b36, 0xbb6bb1e2, 0xbc22abee, 0xe38872c3, 0x7ef93ffd, - 0x37bc4f6e, 0xc0699b4f, 0x327b33bb, 0x0267fde1, 0x5e054bcf, 0xaa1d04ab, - 0xc4ab3e04, 0xe255afbd, 0x812adcde, 0x3bc42adf, 0x7b888fa4, 0x3d23177b, - 0xef119520, 0xa1d6bfc0, 0x7b432641, 0x520f0f7c, 0xb75be087, 0xb2a4fc85, - 0xbc43efc3, 0xde39135b, 0x03a00e6d, 0xdde035f1, 0xc241f983, 0x78e0eaa7, - 0x0e9cf286, 0xef105602, 0xa739f123, 0xb6fde007, 0x87d424d8, 0xd6784c63, - 0x1f9fc712, 0xf3e29fde, 0xf390a25b, 0x6a25fc48, 0x5d605efc, 0x8fb37bbe, - 0x765c44ab, 0x1197b895, 0xcd7688f1, 0xbb0fc02a, 0x3f93e398, 0x2f60221f, - 0xfd6249a5, 0xc074055f, 0x3d8527fc, 0x74c67884, 0xb75f2c67, 0x762a5a24, - 0x04a788ab, 0x4b0fdf7e, 0x6cb4b20c, 0xf18043c6, 0x1e641a97, 0xe1fdf584, - 0xc8ff335a, 0x7ee2256e, 0xc893cf49, 0x56df2b6f, 0x2f7fb82d, 0x74debfcf, - 0xe69e5bae, 0xfe10f78b, 0x35da1203, 0xb872133f, 0xfa85f902, 0x8bc3d7c7, - 0x152c1f05, 0x223f06f7, 0x2131e7f8, 0x7ceb8fcf, 0x48e7e5e3, 0xf1e64f96, - 0x1699898e, 0x9862bf71, 0xe309e319, 0x834cf5bd, 0xc6dad17e, 0x9fdd2943, - 0x92b63ec9, 0x650ec6dc, 0xf8afe43e, 0xf10c1f8f, 0x7dfd70fb, 0xd78a1ed1, - 0xeb1dbfef, 0x0e83bf89, 0x711587b4, 0xd7cca4cf, 0xef51cd93, 0xeef2ad8d, - 0xa65fa1b1, 0xbeecfeb7, 0x73f11b69, 0x1e44e5de, 0xbfe027d6, 0x8ec03663, - 0xc157581a, 0xc81bd62f, 0xa57a8c5e, 0xebfc49c6, 0x1be7fe80, 0x17b624f8, - 0xc754ceff, 0x5f501bb5, 0x240680bc, 0x6a2fc130, 0xcf11d906, 0xfa0f7380, - 0xfea956b1, 0xac2f38be, 0x8fee8f8a, 0xdf2c65fb, 0x5d657087, 0xac2bf26a, - 0x9ef47d54, 0xef59ac7b, 0x44f314ac, 0x9cb344c2, 0x4fc2f3e8, 0x39577d45, - 0x5fb13b02, 0x9227a7c9, 0x1cde273c, 0x52a89e7d, 0xf7de20b5, 0xcb8c3551, - 0xe3573077, 0xfd0f73f6, 0xe49f68c3, 0x3af06054, 0x7ce983f4, 0x7d7190b6, - 0xaedc6417, 0x04f5c7d4, 0xe715bdf2, 0x3ff13703, 0xcb0807ce, 0xdefc6a17, - 0xe42dbbe3, 0xe4225887, 0x672151ed, 0xfd7c85cb, 0x8acbe51c, 0x297b58f7, - 0xab9085fd, 0x90872895, 0xe0cd8f1e, 0x3fb8bcf6, 0x2ccf5f4c, 0xfba08db4, - 0x161cab22, 0x4f94179a, 0xae0721ac, 0x768f760f, 0x7647ffa3, 0x4e03b966, - 0xfba2cfcc, 0x2cf8a5dc, 0x37cdf237, 0x9c1759ce, 0xc8161e2d, 0x2b16f74f, - 0xea4bf72a, 0x8957c8f7, 0xf75408fb, 0xd5fd0ccd, 0xd856264f, 0x9635de29, - 0xe4d787c7, 0x81de1366, 0x86b19d1e, 0xb4ca5a75, 0xfbeebaeb, 0xec9feac3, - 0xef835ee5, 0x6960de85, 0x41a17641, 0xfb88d44f, 0xc8279924, 0xc5f41886, - 0x31268bc2, 0xd4f5eff4, 0xcde8bd13, 0x2e6f5cf5, 0x4deba292, 0xf5d78edd, - 0xd17ea466, 0x4c17c5d3, 0x54bf9d36, 0x7a465e1d, 0x3f744867, 0xcac3b242, - 0xd7992ff7, 0x33d19b9b, 0xec95f01f, 0xed0be030, 0xf16fdd21, 0x89e328e3, - 0xae4793d4, 0x00d7e7d3, 0x4b343bdd, 0xfa393cf3, 0x79abf3ac, 0xfd3fc85e, - 0x794fcd08, 0x5a5347a7, 0xd92d7350, 0x69770c23, 0x1c2ef70c, 0x0bbf7d5e, - 0x46b87be9, 0x56af9fec, 0x74bf1843, 0x197166b8, 0x0f76d5c1, 0x2fdc66d2, - 0x3de1741e, 0xc8d6b34d, 0x247e9fb4, 0xf14e9826, 0x399fdf9f, 0x63e21b23, - 0x9a5dac16, 0x6b38fc8e, 0x373a52dd, 0x37c1247b, 0x59806fd8, 0x79ec8796, - 0xbcc6fefd, 0xb43ead67, 0xdbe37bc7, 0xfdd1d5bc, 0x27f8553d, 0x779853ae, - 0x7643ae08, 0x8674c6bb, 0xfc8e0f81, 0x82eb4ec2, 0x8ed82d2a, 0x58bad570, - 0x2555837c, 0x280fbf44, 0x0fb571d5, 0xf0ea94e9, 0x73298b5d, 0x4f7ed024, - 0xdbc472ef, 0x3b5f456f, 0x2d3ebbee, 0x3a0245ee, 0xbbf264dd, 0x56d77df2, - 0xb66347e1, 0x4463f25e, 0x7c97a7be, 0x62938f17, 0x7ff9e8ee, 0x6869ffb7, - 0x315df58f, 0xe6b4bf8e, 0xe84f92f8, 0xa11f7989, 0xcf8bc450, 0x5a1b175a, - 0x66ce4518, 0xb3c7f389, 0xce997ec4, 0xebd7858f, 0xe3e739f6, 0x5e973e48, - 0xfaf884b8, 0xcd2a7dcb, 0xafc0656b, 0x17a5efa8, 0x507dd346, 0xe2bb9e0b, - 0xfc0b8c71, 0xf94cbf6a, 0xc4eda725, 0xf53fedc7, 0xce8239d2, 0x9df4a9df, - 0x5df6af88, 0xda01e74d, 0x3ad3fdc5, 0x7c9cd29e, 0xc1c6bc3d, 0xe9de50f5, - 0x743c919f, 0xa66857f1, 0x779e7286, 0x5e5ce7fa, 0x31d9fef0, 0xdeebec38, - 0xe0a1771c, 0x2cd7806b, 0x2169349f, 0xc2df9bd4, 0x0d8d8ae5, 0x7b1f9196, - 0xd1f7ac6d, 0xc6bff228, 0xb5f931e1, 0xf3965bf2, 0x4caec0f7, 0xcc99c434, - 0xc87bdf12, 0x65efcd3f, 0x4b20ee65, 0xfa127945, 0xcc0e5bb0, 0xdbb772f7, - 0xd3d4e3cd, 0x79c6bb17, 0xd6fd6985, 0xe8abce3d, 0x53b09e79, 0x13465bf2, - 0x5f9e3ddc, 0x9e368e8d, 0xa58c71ee, 0xd1f1edf2, 0xb450ffdb, 0xc0595adf, - 0x8b4fa07c, 0x79bffdc4, 0xd434fba1, 0xe3ab791f, 0xb8c32413, 0x4d8a6bf2, - 0x35794ff1, 0x5fdf74b9, 0xed5ceafe, 0x76bc835e, 0x36cd85d1, 0x4743e5d1, - 0xd532e880, 0x40e3dfe1, 0xf0a17cb9, 0x583d4f81, 0x11d3a72f, 0x82bc382d, - 0xae7ddbf4, 0x3ea7e768, 0x8d53a48c, 0x1fac13a0, 0xd2740cb2, 0x7ef913e9, - 0x07d2faeb, 0x8bfdc53e, 0x45edf8a7, 0x08b1ebbd, 0xc74465fa, 0xf383a75f, - 0x0fd82b6b, 0xdfc2f381, 0xbbf8a665, 0xe827f15e, 0x7f47e3ad, 0x51dff60e, - 0x944efb94, 0x1f5851cd, 0xe17387e7, 0xc17dbbad, 0x8fa2e30f, 0xf3a9c527, - 0x04167cc3, 0x71aa3e01, 0xf1f7a3fb, 0xb682c43c, 0x974f18f3, 0xf1362e9c, - 0x01738a43, 0xff415397, 0x211e7ba3, 0xc50d6ebe, 0xbd19ed7a, 0xd9c5278f, - 0x185c1f0b, 0xffb34364, 0x11c1f1ef, 0x29f837cd, 0xde60479c, 0xf0bd79c2, - 0x1b86c7f9, 0x18ea97fb, 0x79c4e697, 0xf6fcfaa9, 0xbde383b7, 0x1e1d70fb, - 0xab7b275c, 0x8e254860, 0xbf7c60c0, 0x37f4f5c8, 0x145bdfe8, 0x68f0c4ff, - 0xcae2f476, 0xdfa0977d, 0x99b2aab5, 0xc5d85552, 0x0ce2ed0c, 0x688f5dfe, - 0x2b5e05f7, 0xcae2ebf4, 0xb5b7ee66, 0x70db9905, 0x323b00cf, 0x8ad8fc92, - 0x69cf6cc3, 0x7e8dc06a, 0x83dc4d73, 0x65812aa0, 0x67e85919, 0x1a0ccc4a, - 0x938d77f0, 0x4f2cd7ef, 0xfdc6e3dd, 0x8fd42b10, 0x9a5b33fe, 0x77e4ca72, - 0xe5995d7b, 0xd7e93a04, 0x7ab0c744, 0x1f91249f, 0x1f8454f2, 0x1fa994f2, - 0x7da6cd89, 0x28bc488a, 0x281dfe36, 0xb3ff0985, 0x9dfe87c0, 0x3e6ea5a4, - 0x8fc295ce, 0xaffa04fd, 0x363b022f, 0xc1f645d6, 0x7c2c0b92, 0xe853687d, - 0x3c6b2bbe, 0xf1c5af2f, 0xff71d871, 0x59f5c643, 0xde276098, 0xd5d32610, - 0xf1c2128b, 0xdc2123cc, 0xe0978587, 0x5c63a37a, 0xfcf803cb, 0xd7207b79, - 0xa6ff7809, 0x0901f36f, 0x81fc33f7, 0x35cf118b, 0x03d33072, 0x772d7fe5, - 0x74b96266, 0x8138fac8, 0x39e017a7, 0x9f618087, 0xdcd7df94, 0xe13dcb0d, - 0x112be60b, 0x5fdf86fb, 0xc7b7cc6c, 0x1fb02af8, 0x4acbdf91, 0xfda242fc, - 0x074cfc41, 0x34fdff9f, 0xf2772f3f, 0x07f10575, 0x6e3ed7f2, 0x3c529d3f, - 0x87efb871, 0xb4dd79d8, 0xbcf363ef, 0x114f686e, 0xe05ad8eb, 0x4fb0c557, - 0xb3e2a177, 0x545d3f20, 0xfd8dcf0d, 0x2727628d, 0xf2dae838, 0xdebd76a8, - 0x83af3c3f, 0x4f4f94f8, 0x92247b22, 0xed74762f, 0x69eff027, 0x9e33a1dd, - 0xf1c388b2, 0xfad1ff4c, 0xfdae93ee, 0x761c45aa, 0x5efca873, 0x69fe3fbe, - 0x99c51c6e, 0xa3b8fdea, 0xda336969, 0xf53477c5, 0xbcf8899d, 0x3fe2e0a3, - 0xed43ba63, 0xfa8b13dc, 0xce897ee2, 0xc1f9dd97, 0xa42c6aeb, 0x475fdf5b, - 0x2f3c1ff7, 0xeb3a71e4, 0x01fe9154, 0x7ef8d6e6, 0x47df8857, 0xae02bcc5, - 0x715fd157, 0xdb743877, 0xf3dd000d, 0x3406e87a, 0xebefa6f7, 0x43d5037c, - 0x893ddea0, 0xf7f494f6, 0x726fbd1a, 0x35d7bf98, 0xe346c57e, 0x8daf1ee9, - 0x0f8fafc6, 0xeff84a7a, 0xf7b88fc2, 0xf8c7c74d, 0x77dc7c99, 0x1d75dec4, - 0xe03acb3b, 0x3fb0db0e, 0xde3e78f3, 0x7cfc489f, 0x1fa05985, 0xf6fa745f, - 0xe33e3f20, 0xbd45edf4, 0x4ceb6257, 0xbc920657, 0xcbcf85bc, 0xc905c0e4, - 0x0313fe30, 0x21271702, 0x9cfb9a1e, 0xc07fbd97, 0x80fbf9ce, 0x81f7f39d, - 0x5baf9d0c, 0xecd7c89c, 0x538d2274, 0x92c77eff, 0xbb1f87ad, 0xc4fbf81d, - 0xbb3efcdb, 0xe373d952, 0x9697e443, 0x3e2e3199, 0xfc203d32, 0x7c5d2d0c, - 0x433bc7c8, 0xa332f2e1, 0xc1ce9621, 0x9b2f98cc, 0x319fdbee, 0x32c3c79f, - 0xadf879a5, 0x22c275a6, 0xb3d2d711, 0x4483f41e, 0xfe7333d6, 0x6517ba04, - 0x471ee69b, 0x9c35917e, 0xf44e66cf, 0x608e78c9, 0xf68932cc, 0xf21f47f1, - 0x3c00b634, 0x45ef1433, 0xe0f99d31, 0xfbc20d7f, 0xb99aca51, 0x9e45347f, - 0x4853f993, 0xf3e1ed57, 0x1073c23d, 0xc79f0e4f, 0x69cfd861, 0xdd322b53, - 0x38f7cfc8, 0x7207a87c, 0x827df56f, 0x22fdd574, 0x0afbbcfa, 0x171801d8, - 0x27b77b9a, 0xb724f907, 0xd4a3eede, 0xd01894c6, 0xb30ab96b, 0x31a29a61, - 0x0c698ec5, 0xbd9a61b3, 0x354fd850, 0xe0fd9137, 0x786bf1ca, 0xd36e79bf, - 0xfbe35ff3, 0xb7784af9, 0xdcabe064, 0xa3bfb7a6, 0x3f3e7673, 0x565efdc5, - 0x9fd699a7, 0xf0cdeac3, 0x38668de5, 0x47866c33, 0x65c333ee, 0x67683638, - 0xe11ef88c, 0x86569d9e, 0xde2b2bdf, 0xf438a56c, 0xa0ae7157, 0xe93b5e78, - 0x4dc509c5, 0x712718d9, 0x05a745fc, 0xfe3b95fd, 0x59c532fa, 0x658a6e74, - 0xfbb86718, 0x831618d3, 0xed9bbc71, 0x18bf30eb, 0xd9fe8768, 0xb5f6cde2, - 0xedb34f18, 0x434f9d52, 0xedb50f14, 0x4bbcfc6f, 0x086b06e7, 0x6f8e2ee3, - 0xe445fe7f, 0xfa1be3cb, 0xaaf61d93, 0x7d60b414, 0xdd3847c1, 0x3ebd08c7, - 0xe2f5e846, 0xfc7af33a, 0xaf6e970a, 0xfce287ba, 0xe3812637, 0x2fb2b5bb, - 0x2577c587, 0x8c6dfb74, 0x40dd67b0, 0x7687cfcf, 0xd08879d3, 0x7ba179cf, - 0x6bd11f35, 0xb3ea0c41, 0x0cdaa38e, 0x5c5d4bf4, 0xcea3c663, 0xcc8497df, - 0x24ba27cf, 0xcf0ce7a1, 0xc55e3033, 0xe71524b3, 0xdfa367ef, 0x8bbd7f53, - 0xbc2f19db, 0x20f2e9a0, 0x992a7b8b, 0xb2ae70c7, 0x79b3ef5b, 0x089e31fd, - 0xfbb035e9, 0xbb447179, 0x2eb1fd7a, 0xda5fcf2e, 0x448279f8, 0x95638781, - 0xe86ec8fb, 0x7d2b23b2, 0x380689be, 0x727766af, 0x776fe12e, 0xf986bdf2, - 0xdec364aa, 0x4e30bbe4, 0x8f414eae, 0xe3b92b36, 0x498f9fb9, 0x3d72e7c4, - 0x11f313f6, 0x6ff56d8f, 0xd81cb0b8, 0x718c23d9, 0x5735f967, 0xe41a26fb, - 0xb9f287fe, 0x3712b74e, 0x392bcbc7, 0x9cf093cd, 0xff0d7148, 0xfd71618e, - 0x80dcb76d, 0xcfcd5ef8, 0xcc2b67d3, 0x963c832f, 0xfaedb96c, 0xfcbcf061, - 0xec5e5199, 0x2b71540f, 0x78de2f3e, 0x3d15ce92, 0x8efee16a, 0x0504fa48, - 0x13fa3d9f, 0x39ea0147, 0xcb75efa8, 0x9f7f7a08, 0x239bec05, 0xdcef83e3, - 0xb38e4505, 0xa06f0ffa, 0x9f3330f8, 0x684bdf02, 0x97ae75bf, 0xe9e8ebbc, - 0xd19becc2, 0xa02df754, 0x8fc87978, 0x0c297eba, 0xa489eb99, 0x6fc16aef, - 0xe4621bf0, 0x7d72c893, 0xdce904a6, 0xd07cc974, 0x43ff0693, 0x8a6aa1c9, - 0x076c8dcf, 0xc1985823, 0xe181da0e, 0x9b972875, 0xfc169c78, 0x88b65b24, - 0x61c41f63, 0xf915c7ba, 0xf8a21811, 0x83d13652, 0x4d99bd78, 0x37d754c6, - 0xc3f5396d, 0x52abfcb1, 0xa2bf73cb, 0xe7249cfa, 0xdd30ee6d, 0x9c4fdb6f, - 0x70f36f47, 0x8feeff58, 0x64d45f9e, 0xe3aeb8a7, 0xbfd23427, 0x149e300b, - 0xb768bfcb, 0x3d68c058, 0x78cfa5be, 0xab6e538c, 0x1fa5f7e7, 0x5e33efab, - 0x1ebccb3b, 0xf9f44fa9, 0x39fe20f6, 0xbe7afd1a, 0x83ce1726, 0x771c788b, - 0xcc8a9f4a, 0xd274288a, 0x2ad44bdf, 0xd3fd7132, 0xbbc38f79, 0xcc14f08e, - 0x9fefc850, 0x5c9a7e4a, 0xe83a9fe1, 0x02edbff6, 0xaca139ba, 0xec25fe0f, - 0xdfa1d793, 0xfbd90bf3, 0xf7507b80, 0xacacfd3e, 0xa3df9d00, 0xfb40f40f, - 0x56161533, 0xe266df80, 0x609c353c, 0xae674f9a, 0x719e2896, 0x78f372d6, - 0xe36ebef0, 0xaac05afc, 0x5622dea9, 0x6ac1694f, 0xce217e73, 0x273c2e47, - 0x8a76e3c7, 0xfaf9cd6a, 0x8d92c0b9, 0xf0d1ac67, 0xc7d335f6, 0xc702fbe7, - 0xa36cdd27, 0x2ab7ddfe, 0x6977ef8e, 0x6df387cc, 0xe9272ae7, 0xa01662ff, - 0xe629dc7e, 0x7307f2fd, 0xed20b37d, 0x37d33f98, 0xcb9e0fab, 0x2d23f3e7, - 0xf99e4919, 0x13c57ebd, 0xbf007859, 0xbce187cf, 0x8524dc5b, 0x036c2187, - 0x9fc11d51, 0x3826bde3, 0x3679e37e, 0x6e38fc7d, 0x3ef673e3, 0x9e116fa7, - 0xb8f9929b, 0x0225f98d, 0xad1b251f, 0x98d17f26, 0x79d0528d, 0x6aaf9e39, - 0x1acaf7a1, 0xf54d58ce, 0xec1d798a, 0xba076601, 0x2b58298d, 0x755660e3, - 0x25d0f1e9, 0x1ccbced1, 0x755c7810, 0x945f5e5b, 0xbed1c7db, 0x9d1027ed, - 0xf84a7a43, 0x06d858a3, 0xec8cc5ed, 0x7b3f2982, 0xe2938721, 0x26a6bd1e, - 0x4a2fbe8d, 0x653361fb, 0x0e789bff, 0xd03e32b3, 0x99da0e37, 0x2ba5f169, - 0xc1bebf24, 0xcf9d6fe4, 0x88e4f0f1, 0xa22a4b8a, 0x3a75b7ac, 0x53d5213f, - 0x3b70409c, 0x599da79f, 0x20c06a9d, 0xb8e32317, 0xd3db8cbe, 0x3a8fe742, - 0xfe744ab7, 0x20e929f9, 0xea7e0f9d, 0xff430f5a, 0x09d02a40, 0x1253eff5, - 0xfcf7845b, 0x34dc3565, 0x73a40de7, 0xe3178c56, 0xc61b4a0f, 0x1a0ea5c9, - 0x62e3b73f, 0xbee2d62b, 0x218cca54, 0x61df9023, 0x866e33dc, 0x3ce3a3e7, - 0x075f5ed4, 0xc2ea7ba7, 0xa1dcc660, 0xce7fbed8, 0xc38f281b, 0x7cbce862, - 0x99cae00a, 0xb432e940, 0xe65952cf, 0x5333b46e, 0xa04678a7, 0x8b957f4f, - 0x916493b7, 0xf684dc67, 0x270e08e3, 0xd6f92c3c, 0xa0ae1311, 0xfcac5276, - 0x1cf87a93, 0xfa1b4ded, 0x7a061c27, 0xc4c8a84f, 0xf10653f6, 0xa70b5134, - 0xbbfb3d61, 0x75a01ee8, 0x23373cc8, 0xbbef3d7d, 0x2eb82971, 0x0b06dfdc, - 0xfb63d075, 0x97fdf4d3, 0xfbec83b0, 0xf2f0870b, 0x97994ec2, 0x24e7cfc9, - 0x15f6eba6, 0xfaa1d72f, 0x5ea246e2, 0xf9db8f7d, 0xe47c395f, 0xeb42bf07, - 0xa0803ce5, 0x58e9f953, 0x0bcc3216, 0x21bed3e5, 0xb4fcb3fb, 0xef1cf4cb, - 0x95c63509, 0xa1ec1497, 0xb2943bef, 0x509f3a66, 0x838e6f5a, 0x7a2622bf, - 0x979f3abb, 0x3059969f, 0xf99abb6a, 0x2c3ee9f9, 0xb95a27d8, 0xd3f3f364, - 0xfc6e1992, 0xe8539456, 0x7169cb39, 0x0a71fae1, 0x67a847ce, 0x7aa09642, - 0xda5d3779, 0x79a62ddd, 0xe1c3dda8, 0xa8bfb10e, 0xb7f5ebe7, 0x39c4d34f, - 0x7bcf7e3d, 0x2028255b, 0x4dd3cfc0, 0x5ddfc927, 0xf09bb4d2, 0x3745f3a3, - 0xd059629e, 0xaae4a780, 0x6405b0e6, 0xfdb8e9fc, 0x025e874b, 0xcba3d924, - 0x7d4b3bf3, 0xbf1f2163, 0xef90616b, 0x792eacd8, 0xcab37527, 0xf0fd0b22, - 0x6389d2ee, 0xdf2f308d, 0x35f37efd, 0xb2b78113, 0x6bf7f286, 0x6b7bdee3, - 0x7506c621, 0x4ce83b9d, 0xb00d3bf7, 0x0076022d, 0xbb00cc3c, 0x2313f223, - 0xe02353f2, 0xcdbe5e34, 0xbd974e19, 0xfb8e6d8c, 0xf4051ae0, 0xf0df5b5c, - 0x6479bc74, 0xd747d579, 0x4b8ef7e0, 0x7bf7f8b3, 0xaf249acb, 0x65a3d064, - 0xe4871e5e, 0x3368b6f0, 0x9a1e2287, 0x507d44df, 0x71b928d2, 0xdfa8e0fd, - 0xdf182612, 0xabde18f3, 0x92d3ebe7, 0x5ef483fa, 0xb10ff5af, 0x3a3f3c90, - 0x772a73e4, 0x362dfdae, 0xaf3dfcc5, 0x52bbf6de, 0x50b7812d, 0xc7f7eadf, - 0xa8f96db7, 0x20aa7bfb, 0x7d7ded7f, 0x469f497b, 0xc72f5b9c, 0xe5ba38fe, - 0xa3e3c745, 0x7dd14e43, 0xd6187fba, 0x079a01f4, 0x2e4ef3b1, 0xff75abc0, - 0x14787a54, 0x27785fda, 0x4f1fce2f, 0x704ba148, 0x059a7a5e, 0xef76c12e, - 0x3768bd29, 0x80ec6a7e, 0x5e0cf2da, 0xdc4df309, 0x01ffc249, 0xfc00cb67, - 0xc7e9dd64, 0xa4e1c2ff, 0xe609ba16, 0xafefeab6, 0x1ecdefc1, 0xc032d018, - 0x8ff7f002, 0xe0993a5f, 0x419e5a8b, 0x04eac2f8, 0x196b0f0e, 0x03fbc320, - 0x23267d83, 0xa3bbd6fd, 0xa109fdcb, 0xc5fef46f, 0x891df60e, 0x84aafb43, - 0x2c783bcf, 0x757a06da, 0x4db1d17a, 0xd31f01eb, 0xf49623ff, 0x5bb6fadd, - 0x1e13f3ae, 0x6f8c7e82, 0xa6f8114c, 0xbbf49179, 0x5f44f642, 0xba130b9c, - 0x6f4ce9e9, 0x71bcd0f6, 0xb416c569, 0x0fa6521f, 0x55e379a5, 0xee27ef97, - 0xe9e9dd51, 0xc4fe9e24, 0x5bfae6ed, 0x46bc50b6, 0xb24e43ca, 0xdf171eab, - 0x23b90067, 0xba0870fe, 0x3c7cdc58, 0x73190dff, 0x80001bd1, 0x00008000, - 0x00088b1f, 0x00000000, 0x7dddff00, 0xc594780d, 0xbbbcf0b5, 0x26effeef, - 0xb24d9bbb, 0xf379f909, 0x71100843, 0xa9189313, 0x18884dd6, 0x220bb531, - 0x49716b62, 0xc93049f8, 0x2d16ad46, 0x544859bd, 0x46d10882, 0xe1b80a04, - 0xfd2b6202, 0x1a8c4582, 0xf68882e8, 0x72dfbd2b, 0xbd3fadeb, 0x8a7e1bd7, - 0xb4564288, 0xeb6dea5c, 0x2666739d, 0x5c9377d9, 0x9f7b7aa8, 0xbe8f8be7, - 0xcef33bce, 0xfe73399c, 0xb3339ce6, 0x9086bb1a, 0x258e4264, 0x4ec730dc, - 0xe631df9f, 0x224c9d15, 0xf433bba4, 0xc84b499c, 0xc421127b, 0x09f04845, - 0x0e7b6853, 0xd1eddf21, 0xb4897504, 0x734de1de, 0x44b2d116, 0xc345bd7c, - 0xd57fbde5, 0xd2b3e5de, 0xd32d3172, 0x9912abe7, 0xbd33f58b, 0xfe5a0e69, - 0xa7aefe02, 0x9f561ee5, 0x58ad25ae, 0x7fbec39f, 0xe5dc84aa, 0x76d4cfa3, - 0x7d296e3a, 0xb5b89dae, 0x916b8e9d, 0x0bca1789, 0x5d6c16e7, 0x736a614e, - 0x897842cc, 0x51269bd7, 0xe6364ef8, 0x76d1566a, 0xc8afa7bf, 0x515c8435, - 0x97b0cde0, 0xff40f9d1, 0x44d21c74, 0x3c369527, 0x37981cfe, 0x7ad7afad, - 0xcf3a64b3, 0x39fe1ddb, 0xe35ebed0, 0xd0b4429d, 0x77c0b789, 0x8823b405, - 0x3b76399f, 0x40f227b6, 0xffffbc19, 0xb8954f08, 0x4f115fee, 0x7534ef77, - 0xf8242c9d, 0xb7fd05f7, 0x2aa1d7b9, 0xbad2fa07, 0xcb871a4e, 0xd0ffc377, - 0x24ad4871, 0x2c3a1493, 0x8d6e22ab, 0xbfe836ff, 0x7a07e979, 0x513781a2, - 0xf02ff43d, 0xeb0a4ebe, 0x82fce952, 0x76cf24fb, 0xb2cfdec2, 0xe8959211, - 0x21e613bf, 0xc3f79ee0, 0xd17f34e6, 0x3f2c7cf0, 0x76e6a978, 0xe4b79c5a, - 0xf4edaecc, 0x590f79fb, 0xdb865108, 0x9d711ed3, 0xb8cf7fdf, 0x9f495c9a, - 0x86b0defa, 0x19fdebe2, 0xb69cb3c4, 0x1a435f7b, 0x73efff00, 0x743f95bc, - 0x853211f7, 0xb5d95f90, 0xd0499df8, 0xbddbe483, 0x53b7e288, 0xd0234122, - 0xd23d4cc3, 0xd28860c3, 0xfeb095c3, 0xfbe87d74, 0x872707ee, 0x067d7482, - 0x619100c9, 0xbec4153e, 0xbfa9895d, 0x29eb00a3, 0xb44d049d, 0x0e68da3e, - 0x5e80956d, 0x50a5a028, 0x5feb093f, 0x07fad895, 0x38e230ef, 0x1d1933dd, - 0x433a3776, 0xb6001cc1, 0xc6de008b, 0x7694a3a2, 0x64487482, 0xb69994ef, - 0xe36c7c61, 0x3a52c172, 0xb4dbe2f0, 0xe4dab23f, 0xb01f4f19, 0xbb943284, - 0x4a3c7152, 0xbe91ab0f, 0xfd470664, 0xab42d38f, 0x394f5c70, 0x36a3cbac, - 0x1f787cef, 0x014591fd, 0xc89937f8, 0x7d09634a, 0xe8c3a44a, 0xe1c0eba4, - 0x134f5d21, 0x60bb83a0, 0x7f878a00, 0x536f386f, 0xd89ffbe8, 0x08038425, - 0x484e58cd, 0x75f5611d, 0xa4c72ccb, 0x86d4f029, 0xddf4090d, 0x03bc1bca, - 0xd972be82, 0xf3fb48d3, 0xeb22ba73, 0x83c036a3, 0x804bbe1f, 0x29b73ffe, - 0xefd32856, 0xd3f2c0a7, 0xbf870bef, 0x7df039ff, 0xe0c7c019, 0x65166d27, - 0x1f8c34bb, 0x80b9fcf1, 0x6f69ebaf, 0x9c6278ec, 0xd98f7ef8, 0xf007ffbd, - 0x4e1ef145, 0xb45e0174, 0xf0f1aeb8, 0xc7d1f4ba, 0x5e7eb44d, 0x82b1d69b, - 0xd4bfd3e2, 0xf015f386, 0xbd1a95de, 0xec8de48e, 0xa5a594ff, 0x2ff9865c, - 0x964f7465, 0x62e22819, 0x2e1fa2f1, 0x485dd253, 0xd23587a2, 0xf0e5ef28, - 0x517f8001, 0xf8f7cc77, 0x621abfdf, 0x21be09db, 0x3f07148a, 0x92452ba7, - 0x12fcdd61, 0x3ebd375b, 0x56e40f3a, 0x9f02dc3c, 0x8de5c6ff, 0x7c788ba0, - 0xbbe01bff, 0x5dbe246c, 0xe84c81fa, 0x80d4bfd7, 0x9fef8a78, 0xf77e1090, - 0x4d0489b4, 0x4bd6ee94, 0xfaebd212, 0x90212d07, 0xe8a6839b, 0x6067c00e, - 0xdeb88dff, 0x0acd1ae7, 0xea364da1, 0xf705bf19, 0x171f18db, 0xdc80140c, - 0xece7473b, 0xee73eba5, 0xa09eda37, 0xa4208024, 0xadda37e5, 0x5ee7ff40, - 0xb3f589be, 0x5a10a2dc, 0xe986000e, 0x7fe081b8, 0x578a11b6, 0xc7119669, - 0x0a57b13f, 0x8fbea019, 0x5e4639e2, 0x36ffa39e, 0x8dcb0c94, 0x3800a841, - 0x07082cfa, 0x8e23699d, 0x59335df7, 0xd16fc745, 0xad0d5e48, 0x2932596f, - 0x31e0ced4, 0x16d5cac6, 0x4a90e90d, 0x45bff986, 0xdee0bc73, 0xa7275622, - 0x60ac7970, 0x851243bb, 0x3ab8c9b3, 0x05fa05a2, 0x4bf5a03e, 0x78673ea0, - 0x7f565a1d, 0x479817f4, 0x7d351ecb, 0x9eaf3d34, 0xba5892c7, 0x17a619ca, - 0x17c3294b, 0xf1a126a9, 0x2f1b5e14, 0x21226a5b, 0xe963e02d, 0x2ae27234, - 0xc0e0f4da, 0x5b23a074, 0xa3a92f69, 0xe269c0cf, 0xa7b8510d, 0x36bcf7f6, - 0xd477b68e, 0xba613244, 0xcdbfa581, 0xf0d5793b, 0xaf380b3a, 0x4b427fe9, - 0x7e1e38ac, 0xeef14147, 0x89bb62b6, 0x7d88aeb3, 0x92efc0ae, 0x0f2f4c35, - 0x1fe02bc0, 0x75cde999, 0xfd526f5c, 0x617af28a, 0xafd404d7, 0xce40ffa0, - 0xf4c0953d, 0x903dc831, 0xaa8e6d33, 0x9e741cab, 0x14d56766, 0xc71b1947, - 0x27e98367, 0xa788fea1, 0x243d78eb, 0xb5e6a5da, 0xc75ab716, 0x0cf9476e, - 0x90dd16f1, 0x2c88e4c8, 0xafd17961, 0x10ab3d75, 0xe6e9193e, 0x2839cdde, - 0x97481b97, 0x89bce81e, 0xc740f484, 0x98248c8b, 0x1162e940, 0x9f48966d, - 0x881bd78b, 0x8d7eb312, 0x89b97521, 0x49bb85cb, 0x7bbfbf04, 0x357d5c67, - 0x7d68db09, 0x2d8491b3, 0xd755ecf0, 0x8e7d50b7, 0x85f7d67c, 0xe93df621, - 0x8bbdf366, 0x3aa3bbaf, 0x79d3f5a4, 0xdd51306f, 0x5d0684ea, 0x97533eb8, - 0x267ae0f5, 0x1e737896, 0x2bf2bd06, 0xa52b679d, 0xf5f03fdb, 0x6639f812, - 0xbc00aaaf, 0x9c1ab59b, 0x0361f47f, 0xd524e7e2, 0x6bfeb0e3, 0x59aee41d, - 0x8dae79f4, 0x8075f378, 0x2cd67b26, 0xaf3c48db, 0x00d4c57a, 0xd0e0d374, - 0xd32ae8a8, 0xf972c3a1, 0xe5ff8e0a, 0x1cd6d096, 0xa014f744, 0xa15cf2a7, - 0x9994c957, 0x474c7cb4, 0x6e5a3bed, 0x43f56399, 0x4f60037f, 0x0efdf2d0, - 0x77eecf26, 0x453d71e8, 0xd057cc59, 0xfb071d0d, 0x9ec55f33, 0x43658e02, - 0x74609fed, 0xbaf0f5c3, 0xea0f7346, 0xd5fa21e1, 0x22dfa410, 0xfaf01e9f, - 0xf32b970a, 0xf8a16ec1, 0x1412857e, 0x2f608fc8, 0x3e295fb3, 0xe5a52de6, - 0x79174e57, 0x67402956, 0xf2bcde4c, 0x4159331d, 0xccf37c87, 0x27fb1f4f, - 0xb4fe7f5a, 0xfad0315e, 0x746b4005, 0x88915efd, 0xbe0bc617, 0xbe810868, - 0x7b33d26c, 0x15ff69b4, 0xfbd19ecc, 0x71842c37, 0xc079d05e, 0x084a69de, - 0xeb03b73d, 0xa2943cd3, 0x863aabc9, 0x16cbe0cf, 0xf439bdf6, 0xa0bb9fb3, - 0xa413d53e, 0xff26a3ed, 0x74d75846, 0x7a889283, 0xc25ad7f9, 0x381709c6, - 0x878f5e28, 0x9c7ddd98, 0x4e304956, 0xa1fb0dbf, 0x90b69a7c, 0x33a273f6, - 0xe543e715, 0x2759da2f, 0x82b618d6, 0x34375dfc, 0x8fed84ae, 0xd3d37ceb, - 0x8bf8f968, 0xb4e59ec5, 0x0fa7d06a, 0x073d29eb, 0xafbb32d6, 0x016ca35e, - 0x16fd90fc, 0x8f58879c, 0xb5c59ac0, 0xb2581f50, 0x8f9016ec, 0xc839f163, - 0x3723127b, 0x166891cf, 0x86c6d3f0, 0xe830dedc, 0x1e89fe95, 0x4dc4af54, - 0x8dd29f17, 0xa93db59d, 0xee8df863, 0x5f3d21d3, 0x1740ff6e, 0x43d33972, - 0xca804e30, 0x0ff82265, 0x594c72e5, 0xad995a3b, 0x5495e063, 0xeba9df6e, - 0x47fc1253, 0x9e5a5d60, 0x97f78ffc, 0x145e302a, 0x4ae922e5, 0xa93cbe46, - 0xba03cef3, 0xf5875475, 0xfd7a3175, 0x99d983a4, 0x076e06f5, 0x963eb092, - 0x797d450f, 0xc5ee9a95, 0x7fa704f3, 0xf7c9845b, 0xce1af591, 0x401ab71f, - 0x20654d8f, 0x23d06c93, 0xc15fe856, 0x0e9ea7fe, 0x3969ebeb, 0xbf58597b, - 0x4f813f88, 0x46c3be28, 0x1b93ef3a, 0x29bf8c6c, 0x459fa01a, 0xe5f50415, - 0x63b52d22, 0xd2bde04b, 0xe5d74037, 0xa40e8bd4, 0x8a67f22f, 0xf9ef8a15, - 0x5033b784, 0xb1ca97bb, 0x30a43a97, 0xafe60bec, 0xe5356c37, 0xb57b5f00, - 0xcdcf5836, 0xf9b1ca12, 0x1b05951d, 0x9ec97968, 0x13fd702b, 0x2e5d182a, - 0x2f503909, 0xb1f2e54e, 0xa3d210de, 0x8933fe1d, 0xf6883ec0, 0x1374f68f, - 0x64ad28fd, 0xae401e24, 0x1421e8ab, 0xd1f6a653, 0x57265ed4, 0x24e79509, - 0xf2126ec6, 0x8938e41e, 0xf4d503b3, 0x88fa1411, 0xa4a23dc9, 0x7213dc82, - 0x97dd98f9, 0x3e3b44e8, 0x97d6153f, 0x9b9327ae, 0x6bc425bb, 0x7d456933, - 0xd0c0f422, 0x9c8f5cb8, 0xbe9906d2, 0xcf813c32, 0xae0e677c, 0x8bd212eb, - 0x95e844fa, 0xdf20e8b1, 0x88fbe1a9, 0xbc60e9d1, 0x9afec153, 0x75f0934e, - 0x65a6bc74, 0x853cdc24, 0x50536d3d, 0x693d323f, 0x9e127a64, 0x97d0cbe6, - 0x5e31faf1, 0xc1ebc61f, 0x77d33d54, 0x3d859d62, 0xd98d3a93, 0x85975301, - 0xfc08a4b4, 0x94eade35, 0x26bb61e4, 0xa8d18ef0, 0x1f65095c, 0x9ef905c9, - 0x2a62f950, 0xc4c80fad, 0xa1657c0b, 0xefa1e978, 0xb7fb7337, 0xd7cd9527, - 0xabf467ad, 0xd8a47d93, 0xc112eb0a, 0x99346f7d, 0x051e81d8, 0xe8db373e, - 0x1df02577, 0xefa1b7e3, 0x1cc3a48d, 0x2bd57df3, 0x173fd426, 0x0c85b65e, - 0xb3f88f68, 0x94bfb41d, 0x4ed01bdf, 0x0d8af73d, 0xae39e9f5, 0xefc25d0f, - 0x7e611e40, 0x41aebe16, 0x008e3552, 0xc6334bed, 0xf6140881, 0xd983b359, - 0x21ed2359, 0x99139f5e, 0x80cae8c3, 0x8e0bcdfb, 0x4ca00781, 0x7fa021e1, - 0x7e32716e, 0x5699ec0f, 0x3efa43fc, 0x187ab3e0, 0x40c5fdf6, 0xf7ed06af, - 0x7d2918e7, 0x8b2ed74d, 0xd1e7483e, 0x83b5699c, 0xfeceab7e, 0x41dddfd7, - 0xd1ee1fcb, 0xf3ac0311, 0x497369f6, 0xb7f2d8ee, 0x3e3ba431, 0x772fc310, - 0x9b9754ef, 0x40e5d57b, 0xbf7cba9f, 0x653ae6d3, 0xf9e1d941, 0xc1b5d282, - 0x87ba7ad0, 0xd5786bc2, 0x8668fa80, 0x1390ffd3, 0x7a26ade4, 0xc86cf018, - 0xf80a78fe, 0x9ffd023b, 0x5034f048, 0x31148a36, 0x5f5f03fc, 0xb6cfcd30, - 0x61b7828f, 0x06a311fc, 0x75ad4cf1, 0x173944f6, 0xd2e27ce0, 0x403c3f7b, - 0x9668bfe7, 0xdf02bed9, 0xcacb6b78, 0x18449ec1, 0x4dfd6049, 0x8bbec21f, - 0xf5846bb6, 0xb693353f, 0xac3570a3, 0x89b0fa67, 0x6f801244, 0x69dda85b, - 0x1bfc4ba4, 0x77776fce, 0xf4c3cb44, 0x359dbb7f, 0xf94e0113, 0xe80fb22f, - 0x37e851e3, 0xeade4ec6, 0x4bfc7264, 0x463299fb, 0x02b699f8, 0x038d9afe, - 0xfe3a4afa, 0x0cf97ff5, 0xa5e2fde5, 0x823ee1af, 0xb33e63ce, 0xc80a4dab, - 0x1e0fc5a7, 0xdf62f7c0, 0x8ad32a76, 0x36d7b6fb, 0xa1d95818, 0xcda9f2c7, - 0xb8b95f6c, 0x3cc10a57, 0x931759a5, 0x6c2f412a, 0x640dd9d6, 0xf1e35e24, - 0xb7a6c1f8, 0xf5efc013, 0xf61d2201, 0xc7b3127b, 0xb809adec, 0x135a507f, - 0xac0cbec0, 0x9043f1bf, 0x6b378b8f, 0x902f603d, 0xcff4367d, 0xc37cde2c, - 0xe85685c4, 0x4aa4d3e7, 0xb96d13f0, 0xd0543c01, 0x7e6217ce, 0xf4f5c89e, - 0x6ae5bcbd, 0xd0f1f805, 0x62ff0666, 0xd0077187, 0xd17ff5d1, 0x1ac97f22, - 0xb93b07e2, 0x089def5b, 0xda6cad7c, 0xe7d61d3e, 0x1ae99983, 0x224bbf6c, - 0x638bc076, 0x5fbc0a69, 0xe03ec92c, 0x8df586e3, 0x4f76b1b5, 0xc7f9939d, - 0xa597b32a, 0xaf91580c, 0x6d3e80e6, 0x08f94cde, 0xdef59fc6, 0x0d70eeef, - 0x6b3495f3, 0xa1532dfd, 0x1e7567ff, 0x7b21bbe0, 0x90b7d366, 0x4c2fe0be, - 0xe398b5f1, 0x99f2abeb, 0xa4f822c1, 0xeae400b5, 0x05ad15e2, 0x8cec51f6, - 0x44d93e21, 0x213272f9, 0xf9129da7, 0x1993fc02, 0x63bed54e, 0xb59a7dac, - 0xc67a8350, 0xedde21e8, 0xb74a99f4, 0xb71fb0c9, 0x6f58c925, 0x7d23d24b, - 0x77ba7fcb, 0xbce86fe7, 0x2ffa749e, 0x26ccbe80, 0x6bd062de, 0x455ed44a, - 0x35405acd, 0x136461da, 0xcc89afb3, 0x92eb85fc, 0x31558ec9, 0x125373fb, - 0x39504fdb, 0x73f405f1, 0x1f3fddee, 0x64b6fc06, 0xec053c7d, 0xcfc5c085, - 0xb35fe0f4, 0xdf284bf6, 0x011f1ead, 0xcff409ba, 0x868a0b24, 0xc3c072e5, - 0xbcfc46f4, 0x98e924e6, 0xb145751c, 0x82974a9f, 0x41076ee5, 0xd4b8da7a, - 0x46fef68c, 0x4004c857, 0x2b7cadff, 0xee46a7ec, 0xfb6e340f, 0x740b5785, - 0xe3ec921e, 0xfe30aca1, 0x17986c18, 0x3e71d2d2, 0xc41796dc, 0x8f4a9ef2, - 0xb759d696, 0x5ccae3fd, 0xce9f53c0, 0x9eaded03, 0xdf980481, 0x244edb87, - 0xb61afcc0, 0x0dde7169, 0x16524fa1, 0x09cb0d16, 0x905fc69d, 0x5d827604, - 0x42f8c2b2, 0xedb87c5e, 0x560594d3, 0x7d403fe6, 0x5e3a3a5a, 0xc9cacecc, - 0xdff5fdf0, 0x6672eb64, 0x72042197, 0xf9898cf0, 0x33bb45f7, 0xaeffa636, - 0xcdfe124b, 0x3fd02cde, 0xa2796543, 0xf7c4e406, 0x2efe6ced, 0xf0166f7d, - 0xba9247e5, 0xb52b259f, 0x52e54424, 0x84894ae3, 0xf33fcca8, 0x20594bdc, - 0xfedc3fff, 0x0c5d5652, 0x89dff17c, 0x6a498de7, 0xaff09a7f, 0x0ce1f4ba, - 0x63ceaf18, 0x31cc7e60, 0x3da2abfc, 0xa4fccf59, 0x816b9483, 0x8377c50e, - 0xd82f660d, 0x18c483bb, 0x5d5b9702, 0x7ad7f73f, 0xd82ef9bd, 0xe3ef88d7, - 0xf40d5ffa, 0xfa92e144, 0x5827f424, 0x9f28a28a, 0x77fcb4bf, 0x918cf5d1, - 0x8d9d74ff, 0xc6cd4eb0, 0x0471e1e8, 0x780f43e9, 0x6558b7d3, 0xed2957d0, - 0xf7a2be8c, 0xe59f706b, 0x814c2732, 0xdd3e80b8, 0x76f9056d, 0x43b9817d, - 0xb3ef0893, 0x333ed042, 0x0bbf10bd, 0x0ffa3156, 0xc3f410a6, 0x095691a5, - 0xe676b4fd, 0x20a8cfe7, 0xf8b455f6, 0xe76624b3, 0xbd6789b8, 0x5fd70f36, - 0xc70738c2, 0x400fd08b, 0xcf2f2047, 0x23a44648, 0x7b425fa9, 0x9de9ab54, - 0x458efd07, 0xbac52b57, 0x2a1aba72, 0xeae89dff, 0x23c74149, 0x20afcae8, - 0xa38db95d, 0x23f715d3, 0x127b765f, 0x36bec1f4, 0x2d6be395, 0xfbd13f97, - 0x2eafc28d, 0x796b7cc1, 0x6b46b57f, 0xc47a0b58, 0xd638fba3, 0xda89bc3f, - 0x4a7fb0c5, 0x3e9ebb03, 0x57cfb5c7, 0x6448dd70, 0x9608fc00, 0x2fa88dab, - 0x7244d31f, 0x9d498ec0, 0xe81bbad4, 0x515e7523, 0x0bee3b49, 0x17a01c33, - 0x7fa2d740, 0x1f34e974, 0x1c5823b3, 0x8f533a28, 0x07969cfb, 0x8ecc7d2b, - 0x097e41a8, 0xa02936ac, 0xe7f5a707, 0x08fa072c, 0x031e232c, 0x86cf71d2, - 0x9dcfe045, 0xac80f56d, 0xb225f113, 0x9d77cd52, 0x05538b12, 0x0f18226f, - 0x0d338e1b, 0xe821f96c, 0xf422c6ff, 0x8ff90c9b, 0x8dea09f3, 0xd6438dcb, - 0xde2136ad, 0xd068fc45, 0x25741146, 0x3fb191fa, 0x7a646892, 0x407ca468, - 0x054a73ff, 0xa1eb7f11, 0x3cca2e9c, 0x5ff823de, 0x456ca3c4, 0xc8b01cbe, - 0xbf399c2b, 0x049c4332, 0xb36c77fc, 0x00fd8416, 0x19598dfa, 0x694fcadd, - 0x50e92028, 0xaaab9ffb, 0xbcca6233, 0xc1f7d0fd, 0x5f573755, 0xa877fa8b, - 0x7aa6c01e, 0x26bd9459, 0xc355e205, 0x83b532f5, 0xff127d8d, 0x1be6e2be, - 0x941eaaa8, 0xee7ff8c4, 0xd11f82f4, 0xc5e35444, 0xf5c727c2, 0x5bfda3af, - 0x383ede15, 0xefe826ee, 0x7e5112a9, 0xe14bd3a0, 0xf753ab5b, 0xdfe52887, - 0xf78c4143, 0xaf0e537f, 0x6c319d5a, 0xe17b501f, 0xc36549cf, 0xefa3c276, - 0x495d76d5, 0x3fd8b2c7, 0x15fe83d5, 0x92e03efa, 0xe7890ed0, 0xf49704d7, - 0x656becd5, 0xe09d7d84, 0x74f5f662, 0x2fba4960, 0x581df941, 0xdf6023e6, - 0xe9c4bb52, 0xe3e4bb42, 0xfd680753, 0x1f9f59b9, 0xbb40a71e, 0xbec1e67b, - 0x4651702a, 0xa9d81bf9, 0x6f94490d, 0xaeccfd8c, 0xe31cfaa6, 0x967e8205, - 0x38fd39d8, 0x97fc0482, 0x32a4fbdd, 0x5a4277a0, 0x6ba36eb3, 0x379703f9, - 0xfbe1c713, 0x9779f8cd, 0x205f98bb, 0xa1b55850, 0x26dffa00, 0x5617b011, - 0x594f1e15, 0x63a9fb80, 0xbe630b29, 0x0a7bec6b, 0x53b8d9f1, 0xcb1e2a37, - 0x7804e1a9, 0x45f9796c, 0x338dc82f, 0x42650921, 0x04ea1c83, 0x41a1b6bb, - 0x29211603, 0x03bfcd0d, 0xf5731fe3, 0x5f9d3c64, 0x8177d706, 0xa706b79d, - 0xbfe9bcc2, 0xd1b57d12, 0xc4e508b7, 0x2b46b9c6, 0xeb0a91c6, 0xd83c41ee, - 0xc3c05ecd, 0x34aac2aa, 0xe665a718, 0x4dc63b74, 0xf5073da8, 0x077e0f2d, - 0xae0245fd, 0x1aba7d55, 0xa9ca77b0, 0x0a0bf75d, 0x4673a677, 0xf5f2878d, - 0xe2eeed38, 0x5710acfb, 0xff8e5d1f, 0x174664bf, 0xf82f921d, 0x8ff452ed, - 0x677f5892, 0x1fb31f76, 0x55e9716f, 0x5c5bf1fe, 0x36bdaecc, 0xe4069918, - 0xb01e5fb2, 0x201d5d80, 0x5f604fde, 0x65567c4d, 0x9313ae3b, 0x0536ae5f, - 0xd74666fd, 0x425763c0, 0xee32b5fd, 0xf03c8867, 0x5cf71863, 0x8ab3cba7, - 0xf2803e70, 0x90214583, 0xfe5cfbc7, 0x96fac2ef, 0xdcf57b73, 0x831637cb, - 0x5fd8517f, 0x5099cf9d, 0x94da766f, 0x4e406b27, 0x796649fe, 0x6468c603, - 0xc967ed1a, 0xb71c4ee7, 0x84ea14d3, 0x68f60ff5, 0xeac9beb1, 0xdbf4045f, - 0x29faeb78, 0x0d608798, 0xd51e8015, 0xd008bab9, 0xa0bedd31, 0xf2e8c51f, - 0x4f238811, 0x2597ce0b, 0x767117d0, 0x63f034cd, 0x85c5bee1, 0xce2adc7e, - 0x1529e31f, 0x2b22329c, 0x34917c74, 0xf9bce76c, 0xbc32d9e7, 0xc68ff614, - 0xd5eefcc8, 0xec04cd73, 0xf448f25c, 0xf8fc06b0, 0x7b0108ae, 0xc257b9b8, - 0x5f0b9a71, 0xe5fec3d0, 0xdfc65eee, 0xa0dfbe01, 0x78c2cbf8, 0xedc2cb94, - 0x67460e81, 0x1c787224, 0xb679f9e0, 0x76d0849e, 0x42577e31, 0xc0793396, - 0xf8f3d3fb, 0x37f73343, 0xf5884d51, 0xcec25cab, 0x5b8ea158, 0x49d771f0, - 0xf016af11, 0xfca92c5a, 0xc3d9e2e4, 0x183c4fbf, 0x1bfc0e9d, 0x7e05f4a5, - 0xccd20da7, 0xf3a75e7b, 0xc93650db, 0x9b98a603, 0x04b69392, 0xa45253de, - 0xfbed2f78, 0x0dd03a64, 0xafc821a9, 0xda957d2d, 0xeb8b2b66, 0xa58c5e60, - 0x53ea07b5, 0xfd442aef, 0x5993710c, 0x1cb3fdf4, 0xe65669af, 0x08af73c7, - 0x341c40e6, 0x9eefa0f1, 0x2bfc61d7, 0x4d87e8cc, 0x73636ba5, 0xf82573e2, - 0xf8a4dcbd, 0x7767e800, 0xf00252ad, 0xc41f7888, 0x0d16670b, 0x3d38e3e7, - 0x7d2b7792, 0x983976ee, 0x6a40cedf, 0x1f785e00, 0x1fc70eb2, 0xe3079fc1, - 0x9e0f7c42, 0x32c2d2e7, 0xc0c9fffa, 0xefb8ed96, 0x483e6037, 0xef1bdf6d, - 0x35adfe80, 0xc78c5e92, 0xd52dd9c6, 0x02beb789, 0xf6783ff4, 0x018796d4, - 0x7af6dbae, 0xce25ef30, 0x9bfeb91e, 0xb33f3ecc, 0x3f00a2dd, 0x9b72e56c, - 0x27c88fda, 0x3f6c5dc1, 0x1e476f19, 0x27f7a975, 0xddafe543, 0x05f0648e, - 0x0b3cb3b7, 0x7c03df21, 0x70d837ff, 0xd7f4013e, 0x13c10dbf, 0x8db20f97, - 0x8ff483e7, 0xe6f20f9e, 0xe8104b0e, 0x09af7ce1, 0x8f3292fd, 0x45b59d7b, - 0x7524001f, 0x01cf0e38, 0x72581b79, 0xca1ae7e6, 0x8b0f727f, 0x8f12c923, - 0x4b4afd33, 0x6bcc5c58, 0x808bff07, 0x774c765b, 0x3e408b7b, 0x713779b2, - 0xb39351bf, 0x2ef16140, 0x94d43796, 0x7b002e10, 0x87ae55ea, 0x5e2ccc9a, - 0x87d0e835, 0x26a35d61, 0x185d1fff, 0x93df62d7, 0xd8941a5f, 0x884f56b8, - 0x0a2775d9, 0x9d3d6135, 0x07d80f67, 0x59ab6eb0, 0x9f286b7c, 0xc7a1bf60, - 0x5890e2c0, 0x41ccec1e, 0xe22f5939, 0x3f99fb56, 0xa7c79eae, 0xf45acc4e, - 0x745ca40c, 0xb035ad48, 0xaab0bb3f, 0x0fe8fd12, 0x9f13393c, 0x7ed52bf5, - 0xa7e045ff, 0x238e1bcf, 0x1d7bff0b, 0xbd99e8f1, 0xd447ec3c, 0x5945fb50, - 0xbe815729, 0x15f621cc, 0x2095ff20, 0xe9abad5d, 0xc13e83b3, 0x12349768, - 0xa77239d8, 0xfbeb0ccb, 0xf5068768, 0xe343b054, 0xcf027685, 0x8fccc939, - 0xf3324d74, 0x0aa5d06b, 0xd9e238c1, 0x0771e3a1, 0xa272dfde, 0x2353c309, - 0x76a3e7b1, 0x7d3466b9, 0xd0ebfa2d, 0x4fc11ab5, 0xa0d4cd17, 0xde82fbdf, - 0xc6fd173b, 0x790202ce, 0xd6b61d54, 0x1eac3595, 0x2982e779, 0xebfac3ea, - 0x12486664, 0x33f209c5, 0xcbe79935, 0x616de1c5, 0x1f1cba97, 0xa90c698f, - 0x3fc4f5cb, 0xc58f2d21, 0xa7df620f, 0x75f93326, 0xc70e5561, 0xe3f307b7, - 0x6797fcc4, 0x3269bc30, 0xb33733d9, 0x41d02e6a, 0x7397c42e, 0xabfcc9e0, - 0x7f082674, 0x092e75ee, 0xde0e23e9, 0x80da300e, 0x3c593abe, 0x3f856ff4, - 0xe4caee1e, 0xbc1fae14, 0xd65f886e, 0x8f18f5db, 0x493f5cbe, 0x0e5ab25d, - 0xfebf950d, 0x27db2cfd, 0x9e796a75, 0x50e51d8d, 0xe5cd9d9d, 0x11d9e484, - 0x6a56f786, 0x3a3cc02f, 0x3f6025b5, 0x8ad5bb4c, 0x6fd968f3, 0xf3703f42, - 0xd02c81b2, 0x03552de3, 0x89b71005, 0x2b402fc7, 0xdb45f90b, 0xfee8b9d5, - 0xd884ec03, 0x4b5f3c76, 0xfef5671d, 0xf60cb920, 0xbf762739, 0xb76afa01, - 0xfd15f509, 0xf00603bf, 0x839cbcb3, 0x3687ccf6, 0x0bb41b7f, 0x9e5bc398, - 0x85bb01cd, 0xfdcd4dd9, 0x0bb01e86, 0xe2623aeb, 0xd59ff07c, 0x591fb8ea, - 0x3bff44e9, 0x6fbf56e9, 0xddf714d8, 0x17603888, 0xbd3af3ae, 0x3bf0227f, - 0x7f983bd5, 0x8351b670, 0x5af50379, 0xb79022cf, 0x7b6a4d67, 0xad8dacfc, - 0x75a196d7, 0xb5bda0f6, 0xf675cc65, 0xd73ac014, 0xb63f886b, 0x6758669f, - 0x7c4dbeba, 0x78becf9d, 0xf3ac0175, 0x2eafbbc7, 0xa75e7580, 0xdf02f2eb, - 0x5bfc39b4, 0x27bf6993, 0x3da1f06f, 0x2f58f225, 0x24f71e97, 0x432bfdab, - 0xff21ffe5, 0x30fa58ca, 0x5a87043c, 0x4af4ba1f, 0x3a83c806, 0xd5bfe1a3, - 0xaa37f08b, 0x4068cf1f, 0x3ffec77f, 0x0766ba7f, 0x2d7e81c8, 0xbfa223da, - 0x0f3fb2fd, 0xeffda1ec, 0x69413db8, 0xb91bfeec, 0x246dd85f, 0x88abf041, - 0x27b0807d, 0x5bf1e5e3, 0x251f3e7c, 0xbb006f7b, 0x8dfacbe6, 0x633bf81b, - 0xe76653e8, 0xcc3c936e, 0x7e8bdc6f, 0xf37d96e4, 0x3e27e0ed, 0xe37e621d, - 0xd18b1796, 0x7a18dc6f, 0x65790c2d, 0xc3b25fa4, 0xdb71a3fe, 0x07c804b1, - 0xba5cfb10, 0x8c933daf, 0xefdea8f4, 0x489d0e9e, 0x0a01fc80, 0x71e82577, - 0x07aa2b8b, 0xfba16fba, 0x6c23c83d, 0xa187a391, 0xc11716df, 0x3ed2973c, - 0xc44ffef5, 0xf4fa3779, 0xf6377728, 0xd790214b, 0x4e7f7a29, 0x9235e806, - 0x2078c761, 0xc98bb3e7, 0xb294d4de, 0xf7baf8d8, 0xe1e4e4f3, 0x0d81b07c, - 0x03bf4889, 0x83b5e23a, 0xe360db3c, 0xf9464cf2, 0x8e4dc7f6, 0x630fcb10, - 0x6218ffed, 0xc8a34276, 0x5849930b, 0x68b5eba6, 0x585df7b6, 0xe1f7906f, - 0x5b1f7938, 0xbbfb7116, 0x52f51849, 0xca181933, 0x176d8b0f, 0x7887d71f, - 0xd21faab8, 0x1f80ac5a, 0x07ab4eec, 0xb8f881e0, 0xf6c83eba, 0x961f94eb, - 0xafd30c96, 0xbf410758, 0x1d0fdc2d, 0x08fe3868, 0x4fa06fd0, 0xd77d83b2, - 0xdbf461e4, 0x905bf744, 0xefcf1b47, 0x379d57a4, 0x97ff163a, 0xd1f5a8a6, - 0xe4eff950, 0x453ebd5f, 0xfe62f7cd, 0x343f6fc2, 0xf1897ecf, 0xe2bcdc65, - 0xfef1a9f7, 0xbccfb176, 0x2738795c, 0x870f2d45, 0x79677fca, 0x2eb43758, - 0x1d50f2f1, 0xe59bf8cf, 0x5c70ffe1, 0x4f7d99e3, 0x03bec027, 0xa7d878ec, - 0x63aedcac, 0xfd1413f9, 0xe9e2f1b1, 0xc597ab5a, 0x5ea2b54f, 0xa657871d, - 0xe33c38f3, 0xd45ed7eb, 0xf335bae2, 0x3ef37138, 0x369a079b, 0x9c631758, - 0xba7e3e36, 0x0e9eec84, 0x471f154b, 0xce7e026d, 0x753c74bb, 0x8f8b0a75, - 0x20725852, 0x6f3e216f, 0xa7eb35eb, 0x7598fe49, 0x1ba22aaf, 0xdbe85182, - 0x33890728, 0x14c6fde6, 0xc6bf5766, 0x7adc8bf3, 0xad608e76, 0xfd85e2cd, - 0xf2c35b8c, 0xf2e07e9f, 0x18bc826d, 0xfaf1c2a3, 0x4344edf2, 0xae8cf2f1, - 0xb04ae517, 0x3901ead9, 0xa237fc28, 0x5e3c8bff, 0x3ffad971, 0xfcf7de8e, - 0x3c7bd30f, 0xf18bf67e, 0xddb8d6fe, 0x151b8a7a, 0xe3a4105f, 0xca5f1023, - 0x63bf4919, 0x1d1633f5, 0x1df14d1f, 0xfe766149, 0xb857cc14, 0x2963394c, - 0x3f009e8d, 0x5063d911, 0x7e09afc0, 0xab8fd412, 0xaa3e78d3, 0xe6267ca7, - 0x2573b369, 0x58ce1ce2, 0x4307e476, 0xc8ecc3eb, 0x9f5cc60f, 0xde47672f, - 0x087df0ee, 0xd2b27674, 0x1e01e78b, 0x61f851b5, 0x619cf87f, 0xe22e73d4, - 0xfca5c63c, 0xd1c45f2d, 0x4bff17d5, 0x3a92d472, 0x75f95d96, 0x13cfd1cb, - 0x763a7fc0, 0xff9e413f, 0x45bc4119, 0x6b6449f7, 0x103b5f8c, 0x197bf961, - 0xfef15e1c, 0xa1bef83f, 0x999bd521, 0xfc7fdf4a, 0x1248d1ae, 0x652e9ea9, - 0x67c5b172, 0x4b42b8c5, 0x697fcb2f, 0x8e504659, 0xb4df80b7, 0x3389fc08, - 0x4f7dd809, 0x2013fd3a, 0xf7d1ee8f, 0x226d41ac, 0x1167dbf8, 0xbdcef3b0, - 0x9c33cacb, 0x6798c9fe, 0xe3006cb7, 0xceb3dd18, 0xf9561e60, 0x523e9f17, - 0xa2f08a53, 0x5065c13f, 0x3db9679f, 0xf133c995, 0x6f843d9c, 0x3ff3fa2f, - 0xdaf9606e, 0x0ed79701, 0x0fe1097e, 0x8c1128b7, 0x61ecb42b, 0x96b95bc6, - 0x30fc87cd, 0x65a9e903, 0xf831654f, 0xa9af494d, 0xf2ddec18, 0xdf715bdf, - 0xe983f1f7, 0xcfb12798, 0x7c02afe5, 0x37434ad8, 0x4d9a7d81, 0xf7bb01c7, - 0x1537dde3, 0xfe42dc03, 0x39bf03ad, 0x4d9d7f1d, 0x462717ed, 0x64bf7796, - 0x33ee2647, 0x5afeac9b, 0x133aff98, 0x9db82383, 0xfee14f9f, 0x17fe78f2, - 0xd5aa9f7c, 0xdfa938e0, 0x5c9c6235, 0x3a7585c8, 0x0de637e2, 0x9e1293cb, - 0xf1701867, 0x99fec73c, 0x97854f2c, 0xbe752ead, 0x37c947e7, 0x253c0094, - 0x8b57f2a9, 0xe4475967, 0xb2a4940b, 0x5cea9678, 0xb322e5a2, 0x7aed73a7, - 0x4adb27a4, 0x9454e2c2, 0xbfaec09e, 0x06991a36, 0xbbf2bce7, 0x9e02d7c3, - 0x20d45ff7, 0x4799e49e, 0x28933e30, 0x56f2f1b1, 0x004e740f, 0xadfd8c7f, - 0x954960eb, 0xa0157b2e, 0xefa749f4, 0xffe45481, 0xaf1842d6, 0x2c745fea, - 0x059f72bf, 0x59dd0cfd, 0x795f984d, 0xea833dee, 0x33fc4e7c, 0x3e605648, - 0x6fdf6e65, 0xdb604e31, 0x279a8d23, 0x15aa44fb, 0x1825a6f9, 0x36398e99, - 0xce50bad7, 0x1f7efbca, 0xee43bb04, 0x91024194, 0x03579d0e, 0xcb82d3e7, - 0xc7f5fa09, 0xb035db77, 0x3f3cd95e, 0x7fff7066, 0xbee3f14e, 0x4205c445, - 0x3749bf2c, 0xc7ec08f0, 0xdf03e5e4, 0xec7ac20c, 0xc05a6871, 0xb68baa7f, - 0x9f65dfa0, 0xd9acfd05, 0xbe2b797d, 0x2bd9cb41, 0x1b0718ed, 0x6ceee57c, - 0xf3a7e7cc, 0x3cca3f1c, 0xf9654a1f, 0x8b3ef248, 0xfc99f406, 0xa8c0f104, - 0x0aa523b2, 0x968a7ee1, 0x07df3f69, 0x8e1e4a7a, 0x0a3f829b, 0xaa4354f4, - 0xcdd0077f, 0xa5a4b9d0, 0x892e7666, 0x2db5a79f, 0x9c176f7d, 0xfdc2d9f7, - 0x4ff707b9, 0xbffe859e, 0x7582594e, 0xf960e0b8, 0xb2a42f95, 0xfc48e278, - 0xd63cc41f, 0x65bf7ddc, 0x02e28d7a, 0x8c7597fa, 0x574ee45e, 0x5f19f80f, - 0xde63f049, 0x611d75ee, 0xeccdc62d, 0xa35c7f27, 0xd677ecc4, 0xb2d33d33, - 0xe3cfed93, 0xd29737f7, 0x921ebf2f, 0x0cbf4c33, 0x764eff95, 0xf4e2efcb, - 0x6fbcdfca, 0x5efdea21, 0xbf12fdbc, 0x8f611bbf, 0x9637f5c7, 0x50f2231d, - 0x61c786aa, 0xd84db4f6, 0x9e554149, 0x9f95954e, 0xfbaa343b, 0x47649f5f, - 0x3b79107a, 0x72caed29, 0xfe8fdbc8, 0x4edfa088, 0x3c8915e4, 0xcb1560a2, - 0x8c6a09f7, 0x4dd12e78, 0x687f30ba, 0x124b091c, 0xf006d7fa, 0xe42a6dfc, - 0x4fefd111, 0xff62e6a4, 0xa567899b, 0x22a6e516, 0xc826fc01, 0xb802493f, - 0xc1161b43, 0x7159b778, 0x9fe4133c, 0x033ee124, 0xc7dd39f9, 0x35a756f2, - 0x3a43b8b0, 0x4e50cfd5, 0x697467cf, 0x3cc7ab9a, 0x22579156, 0x5e044ff2, - 0xd3be38aa, 0x01ca2c27, 0x54f228b9, 0xe53d99d6, 0x39c11760, 0x1cbf3868, - 0xbcf3346c, 0x776fd613, 0x4f9e2e63, 0x2979b2fe, 0xf91678f1, 0x7f44fa29, - 0xe46cbba6, 0x37416739, 0x7089eb31, 0xecc7dc6d, 0x3d06aafc, 0x71b063ce, - 0x072bfa06, 0xec04351b, 0x037eaa81, 0xf1b8c3a3, 0x93d5ce36, 0x872bf430, - 0x054f204c, 0xceca5c3d, 0x085beba5, 0x6d83e0fe, 0x524ef33b, 0xd6d43fde, - 0x9341cf8b, 0x12bdabd4, 0x03cea1cf, 0xb48df5c9, 0x1af95afc, 0x6689b7c8, - 0x6a849449, 0x96faafd3, 0x60c4f54c, 0x287df472, 0x7be1bedf, 0xba3e3cac, - 0x9beda245, 0xed623ed3, 0xa9d33681, 0xefff5ed8, 0x57eb41b5, 0x267f7fd0, - 0x351cf9f1, 0xebf464ee, 0x3f41123c, 0xa57fd712, 0xadba3e4c, 0xdc9fb47a, - 0x54951f3c, 0x8854fcf3, 0x7b72d0f8, 0xefc6315a, 0x13d944ad, 0x030cfa81, - 0xe30827b3, 0xccf1f687, 0xf4e46d6f, 0xbf843240, 0xf208206a, 0x81c73dae, - 0xe7c90fdf, 0xf310863d, 0x8ff1b19b, 0x9e0578be, 0xb679124b, 0x6733d884, - 0x36f9815f, 0x135af2aa, 0xdb29a73f, 0x7bbce133, 0xc1db8ebb, 0xe6c47cbc, - 0x04f3885f, 0xddf6a4be, 0x507e1bd1, 0x7674fc04, 0x41f30fef, 0xa7a8ddce, - 0xe45184fb, 0x933a595a, 0xeb3a836b, 0xb77e894a, 0x016fe6c6, 0x32c77c3a, - 0x311c3a6f, 0xa9549b9a, 0xc1bc0077, 0xd780b4e7, 0x8e274e64, 0x473e0cd9, - 0x3c824fb5, 0x1b1376d4, 0x7b2fd937, 0x7f845cf1, 0x851b74b6, 0xf2625dbb, - 0x88947e9b, 0x92a15576, 0x26c87108, 0xcb55ee7e, 0xcb9688e5, 0x1b6e7f91, - 0xc1a997c8, 0x13ef4d78, 0x7fe7b05a, 0xbfe2e3cb, 0x9f9f51cd, 0xb83371e8, - 0x569673c5, 0xcfe802b9, 0x523aaba5, 0xab40e94b, 0xfd7084f7, 0x37186d32, - 0x772b603e, 0xa5efd00f, 0x42951fec, 0xe67b773e, 0xbe214a8f, 0xdc7a75a7, - 0x8f7298be, 0x357fd19b, 0x59bc03b4, 0xefc14b5a, 0x97f5b5fb, 0xfa2bfb48, - 0xf50dfdf2, 0x35706063, 0x7059a319, 0x9359fe6e, 0xffac3b7f, 0x30c7f985, - 0xfa40fc2e, 0xaf21f7d1, 0xd18ea8e3, 0xe793305d, 0x69ee93e3, 0x0eee9409, - 0x5e7839e7, 0x1ebf8b0a, 0xa8fcc09e, 0xfcb17e54, 0xe61289d1, 0x66ced621, - 0x266f62e7, 0xfa018e91, 0x68593a3d, 0x1c8af4fd, 0x796b7fb4, 0x77f4c89e, - 0x7eb0097c, 0xca8f6fd3, 0xb2c7f720, 0xeb746ee7, 0x3e188194, 0x975149be, - 0x97542e6f, 0x9751e5bf, 0x97f15dbf, 0x9365b109, 0xe8107bd9, 0xdf8955f5, - 0xb10d7147, 0xa4ba7f23, 0x935dd820, 0xe7e74a5f, 0xe53e5989, 0xf17ef94f, - 0xf5820aa5, 0x5b8d3b29, 0xfdcf508d, 0x3f5e5aef, 0xd98c4dd9, 0xea07c44e, - 0xf3c4a8e9, 0x93185d32, 0xb1ef7b22, 0x6d343f33, 0xecfda7ab, 0x1f20af9d, - 0xe43558a7, 0xa5ebc09b, 0x04c3b446, 0x289bb45f, 0x963c537d, 0x819a338f, - 0x9e75dbde, 0xd697d0f5, 0x2f40506c, 0xb1182657, 0xc83fed6f, 0x9b96d7a8, - 0xcb4ec40c, 0x63371f07, 0x3e265cb9, 0x20a123c8, 0x51e786ce, 0x0ad4279d, - 0x60eda5f3, 0x160eedbe, 0xeb96d757, 0x7ed3cf51, 0x3e0f5d71, 0x9c1109a1, - 0xf98ca57f, 0xc1661ca6, 0x7c247477, 0x6be734ff, 0x518486ad, 0x7bb3a58e, - 0xfed10e39, 0xbf83dfa1, 0xdfa0f6d2, 0x13b950ae, 0x271bcfea, 0xc0a8b9e0, - 0x592f79d0, 0xda15c003, 0x67e87cb9, 0x3f04f2e7, 0xa542f90b, 0x852bbe5e, - 0xf8149030, 0x053b050f, 0xfb8204ec, 0xccb71100, 0xd97a8a34, 0x0da6fd0b, - 0xe0e767b5, 0x56997852, 0x60253585, 0x27f1bca7, 0xe4b1c3a0, 0x931a6145, - 0xe429e213, 0xc3c316c5, 0x19af6a47, 0xef0a3d6d, 0x9b0cf2c7, 0x84c7ad9d, - 0xad4be00c, 0xe8064279, 0x478776cd, 0x0b94c5f1, 0xae6a76e9, 0xdb45f013, - 0x35adf2d1, 0x18e5f2c7, 0xc69854fd, 0xe76d00e4, 0x1ef0a24d, 0xc0192934, - 0xdb8ca3bf, 0x7cb5c6cc, 0xe9bae3bd, 0x41ddb4b8, 0xb6971d1b, 0x843266db, - 0x8da30935, 0x78c0a15f, 0xa2971a97, 0x833f911d, 0x93a503af, 0x0ec1f820, - 0xaf4834da, 0xf2be7833, 0x1e3664c1, 0xffe75429, 0xf8e99be4, 0xcea65f98, - 0xda51b9f7, 0xfa7a01d4, 0x56c25369, 0x3837cfa0, 0xfcb61cdd, 0x69d83e43, - 0x382bcc6f, 0x71267284, 0xd1100779, 0xf28bd20c, 0x0bc1c846, 0xa1cac769, - 0x8de1e54c, 0x0fde7469, 0x079d1ee4, 0x3c721f9d, 0xa5f68f9d, 0x56935bd9, - 0x417e1236, 0xa06e029f, 0x218be053, 0x5f838d3a, 0xa5b91bd0, 0x37251317, - 0x9e173b53, 0xa425eec2, 0x2bc5e595, 0xa3f3c399, 0xd8dd3e44, 0x18d1e6ca, - 0x746fb844, 0xe6f318fc, 0xffe718ee, 0xf735c01e, 0xbef04fca, 0x3f9ee222, - 0x1477f601, 0xc96979de, 0xc6f07bff, 0xca97f9db, 0xcf8b1f0f, 0xacd2f8c5, - 0x1e1f989d, 0x7cc56d98, 0x3f3c69f1, 0xc1a0d036, 0x0fdd00b8, 0x85a23ee2, - 0x97204318, 0x5cbb72a7, 0x45785b9c, 0xe0d6fe62, 0x7d45068b, 0xde7c513f, - 0xe97982b8, 0xbf2c65c1, 0x6f7ec87c, 0x1f7ed056, 0x9cfc73d2, 0x93317744, - 0x28f7dded, 0xe689fbea, 0x44fdf513, 0x7121ed0b, 0x32948a6f, 0xdddfbf9c, - 0xbbfe9043, 0x9f58b96d, 0x88fa65ae, 0xa3e9837c, 0xbaa21cee, 0x399d691f, - 0x94f31134, 0x46c15e78, 0x6ff83fc8, 0x9a7e0bf2, 0xc2fca926, 0xc9afe543, - 0xf0e6dc2f, 0x5b3a02ef, 0x92cde458, 0xebd63d28, 0xd2987f99, 0x8108a6eb, - 0x7cd6c574, 0x44dda7d8, 0xe4d2df5a, 0x02febd21, 0xa53275e9, 0xbd153cd7, - 0x15fc61ee, 0xe82d2144, 0x0b4e8875, 0xfd00f3e3, 0x6edc60fb, 0x5befef47, - 0x6fd35f60, 0x683cb0f0, 0x2f19d796, 0x59e0621f, 0x5c783320, 0xf3c22d5a, - 0x0f13f43a, 0x4df0e5cf, 0x12a69d2c, 0xf1631fc6, 0x824caa4f, 0xfe6192b6, - 0x6ffd9931, 0x7c43b8c1, 0xcfdb08f4, 0x6b5b808e, 0x739a7a45, 0x057f8b07, - 0x802ecc2c, 0x1d1a5838, 0x7f1f267f, 0xdaafa74e, 0x4a66ed01, 0xfa610f0c, - 0x167f850f, 0xdfd99faf, 0xb370798c, 0x63c775aa, 0x2f2120ed, 0x2e6ddc45, - 0x7dab7f6f, 0xd2f20ea6, 0xe3aad767, 0x64ef735d, 0xb339b6f1, 0x25ccfdd5, - 0x7cc13fab, 0x03aad24d, 0x53bdcdfc, 0xda49ff5d, 0x026c9c50, 0x710ec9c4, - 0xe520d03f, 0xd7a3e013, 0xba6f1793, 0x84f9d287, 0x8095149f, 0x9486f0df, - 0xd04f6dc6, 0x271bb3f2, 0x94f5f961, 0x28ff7eef, 0xc0296fd4, 0xe25c3572, - 0xe056fb04, 0x8567ca43, 0xc8cc77e5, 0xc27d0049, 0xe087bdfb, 0xdfd9b77b, - 0x73b6933d, 0x3cc5c94f, 0xd7ee6ad6, 0xeac85c18, 0xc6d2be6f, 0x52ef9552, - 0x6d5c5fd0, 0x1d35f766, 0x04bb7e29, 0x73abaaf2, 0xd5e4b979, 0x243e5049, - 0x3af7827d, 0xcab66b9c, 0xe92d0eb0, 0xb93ecfcc, 0xa44f0a50, 0xf276a978, - 0xbcd99bfe, 0x4b9e4b6a, 0xaea93e07, 0xf64cfd62, 0x41e67654, 0x2c79cd3b, - 0x26374b9f, 0xbf05fe00, 0x957df0e5, 0x5c7d2bb0, 0x3de4bc4e, 0xfb4491d6, - 0x0f2519f5, 0x7157d14c, 0x664bdd8c, 0x7d03e765, 0xfc191cde, 0x2cbcd3f4, - 0xb8cab6ef, 0xe1e40d3c, 0x297d7e2d, 0x2c6ecbcc, 0x1179043e, 0x65951589, - 0x246da798, 0xfe94beb8, 0x3f03a7c7, 0x5649fd5e, 0x559d1002, 0xbe82ff4d, - 0xafba0a66, 0xe537d356, 0x65e9c9db, 0x2adf9697, 0xd30d36fa, 0x3ef658f7, - 0xe102ab85, 0xaf5a86fa, 0xc7138d0d, 0x8ee3f19f, 0x2fe03725, 0xc30efe56, - 0x987c8bd7, 0x798dd901, 0x825da7c0, 0x38026f4f, 0x9e089af4, 0x3c96ca8f, - 0x7180f093, 0x7a88c785, 0x055f8e2f, 0x33e0997c, 0x1709192f, 0x6ec2c9fc, - 0xf02e7f65, 0x7af064a3, 0x38979dfa, 0xe3a2e187, 0x7a0e91df, 0xcf0611fc, - 0xc995a966, 0x112fbe19, 0x311697fe, 0x7cf53edf, 0x1eeccdcb, 0xcbf83703, - 0x3c527630, 0xcbee0869, 0x9f310758, 0xb3e7d700, 0x9e9b3e8d, 0x4736edce, - 0xedcfd23d, 0x283aa354, 0xff74c25e, 0xd41e700f, 0x7ec1f704, 0x62f1216f, - 0x47d29cfc, 0x6ec63d20, 0xe3c6f012, 0xb90c65a9, 0x789f3f1a, 0x5baf0cfc, - 0xe29e0d24, 0x7cd0e1fc, 0xf19e732f, 0xaf4b8af6, 0xb93a5bf6, 0xec39d17f, - 0xfa842c4f, 0xa0f6625a, 0xe123d13f, 0xda96af7e, 0x6ba7201f, 0x71fa086b, - 0xfa0d569c, 0x321d8513, 0xff5c9f16, 0x6ab7264d, 0xf73f089b, 0x4f17e6c8, - 0xe064a98f, 0x1ad6787e, 0x800b0d95, 0xaaac1bff, 0x56b50673, 0x4e788f16, - 0x503211c8, 0xa87f7a06, 0x0fef423c, 0x8a1c8194, 0xf6ae7fbf, 0x3b7bf322, - 0xacf84a2f, 0x032b1cf5, 0x19acefbd, 0x56790328, 0x14fef767, 0x13dc55d6, - 0xbdcf8f19, 0x97911ae9, 0x1a745972, 0x0e2247cf, 0x7fe6c47a, 0x3fc63d39, - 0xa08a5675, 0xcbb5759f, 0xcfe7e7ce, 0xd8767a01, 0xefc12a73, 0xaad8db34, - 0xd138bb03, 0xce903fe1, 0x5f17e8e4, 0x9a17e6c0, 0x56de3c52, 0x66587fed, - 0xee1e22c3, 0x81b878e5, 0x9bf3d9eb, 0xa90fb8b4, 0x0d3e16f6, 0x9bc0a0a1, - 0xbe42123a, 0x147ea2f5, 0xa79dc6f7, 0xda185506, 0x7d436f3f, 0xf557f8bb, - 0xb09b2718, 0x1894435e, 0x6431397d, 0x327fdd56, 0x5553a779, 0x5d37a2be, - 0xbecafed5, 0x717d555c, 0xfeaa9278, 0x544b37aa, 0x54c8b2e5, 0xdfabfb55, - 0xaf9552a9, 0x6aa19819, 0x3df403bf, 0x4e37e3c5, 0xffbd52cf, 0x37f4e368, - 0x5d7d3e21, 0xefaa3bf4, 0x043f704f, 0x85237a09, 0x040bfe74, 0x53ac5ebd, - 0x9acd4f7d, 0x7c0e54b0, 0xac16fecf, 0x95f77966, 0xfdb16314, 0xdb52ec2d, - 0x28903713, 0x84b62be6, 0x40984f24, 0xbeba9dde, 0xf107afb1, 0x0f7ba97a, - 0x6be6b826, 0xc69754c0, 0x22633b51, 0x0d5c8220, 0xf1638379, 0xbfd6a5fb, - 0xa97fe480, 0xd5b837f5, 0xd4526feb, 0x54296feb, 0xa3cdbfaf, 0x0ac4ff5e, - 0xbc3bfaf5, 0xaa4ff5ea, 0xb27faf51, 0xa9febd4f, 0x9febd573, 0xffaf57e6, - 0xbaf506b8, 0xd7aab667, 0x7aa97b3b, 0x4b82735d, 0x74f1f554, 0xc849e820, - 0xf795bccf, 0xa453dbaa, 0x42e86268, 0x5f02d9d0, 0x8d63e603, 0x35487aef, - 0x4c7d3c5e, 0xf48f3c20, 0xe547d22b, 0x727f6e38, 0xa97aa0ba, 0xda325c6a, - 0x73c03719, 0xff6e04ee, 0x33b746fb, 0xd58afc84, 0xe6fbb1eb, 0x08dae4b1, - 0xd1f7c57d, 0xd82bea63, 0xf7869b47, 0xefd163d1, 0x59ea84bb, 0xfa357c1c, - 0x33b0eecf, 0x999a0e38, 0x5429ff3d, 0xd1db435d, 0xde141536, 0x743e6177, - 0x93cd77fc, 0x1df20fd1, 0x7183abd2, 0x7c1124ef, 0x7c5123ce, 0x755d89fa, - 0xf10165be, 0x645fb9e9, 0xc9a9e009, 0x7a0e5038, 0xa3fcc2ff, 0xee7c63ef, - 0xdd65d248, 0xe21c7207, 0x3909e33f, 0x49c9e5c5, 0xf2d10388, 0x27f71339, - 0x8ae2897a, 0xee29e7c1, 0x269bacf7, 0x5a259ea1, 0xd5b1e633, 0x9ea12edd, - 0xf60ffbaa, 0xf4c71f6c, 0x52e788da, 0x6e2ed781, 0xa13b301f, 0x62dd0e0f, - 0xadf890fc, 0xec7a8f68, 0x3fb4deb0, 0x47f98716, 0xdbb17f76, 0x25dce0c8, - 0x89c2b911, 0xdd7106c7, 0x7ce1fd61, 0xe0c8db9b, 0x4623a5db, 0xe264efc0, - 0x31f0fb47, 0xd63c8a99, 0xefd624ef, 0x17f05cd1, 0x7e6fcd9a, 0xa9f21aab, - 0xf472e0e5, 0xa88f7fdf, 0xb677f7fd, 0xffbfe84a, 0x3e9b851e, 0x1b8f76dd, - 0xef28b2f4, 0x1e21b802, 0xfbe8ed00, 0x04ab7754, 0xadafb1fe, 0xb10f3dbf, - 0xbfb25f76, 0x83087ea1, 0x3d60fe0b, 0x83367f85, 0xd281b7d2, 0x11efb6cb, - 0xfbc61ff4, 0xa969c76b, 0x31fc8106, 0xc097bb1d, 0xfb67af2d, 0xbb1ec3e2, - 0x7444cfca, 0x7a47380e, 0xf20e7b29, 0x9cc54fbe, 0x3474a0d3, 0x1fbafdea, - 0xa47cb065, 0x44c8b6f6, 0xe39e4b88, 0xdb87d771, 0x56b2c4de, 0x265e60f6, - 0x88e5f7dc, 0xa2ef5ef9, 0x4e7231f5, 0x63efd2b6, 0xeace8de4, 0x1e6bcbc3, - 0xbc608b69, 0x25efc753, 0x5ee3347b, 0xbfc63fbb, 0x6e38cef2, 0xc4831927, - 0x69b8429e, 0x4f4eff4f, 0x5a3f4023, 0x762a7cbb, 0xd3706d1f, 0xeef562fe, - 0x1b1264c5, 0xf6d9587f, 0x88fdc20e, 0x6743f7e4, 0x36127c86, 0x641b7c51, - 0xdf4d0338, 0xe511b86f, 0xaf76deaf, 0x1aa1ee07, 0xb7067f0b, 0x7e56217c, - 0xdf8e387e, 0xe7e5c5cf, 0xc9d16d93, 0xdb7b4e30, 0x5d6f0a80, 0xfdf1176d, - 0xc452369a, 0x7ac43fea, 0xf4828d4d, 0x42d28a73, 0xf27ae204, 0xc1fc0d80, - 0x10263ed4, 0x8db9d67f, 0xb8306f18, 0xa2e4bc18, 0x9e63e90b, 0x3e00c19d, - 0x1f4a4cbf, 0xe1d52fef, 0x4cbefafe, 0xefbfb62b, 0x780fe337, 0x29eadf29, - 0xc37fb41a, 0x61c7867c, 0xf973d3f8, 0x0fbf6449, 0x5d3e80e4, 0xd38538c6, - 0xf1d70b3e, 0xf027f6cb, 0xcc1137ae, 0x5a67d647, 0x5cb85ed1, 0x6a19dd38, - 0x8fe3c7bc, 0xffe509e2, 0xf74f1c7d, 0x93fcc83d, 0xf04fddf7, 0x4a59053c, - 0xe987caff, 0x87971c6a, 0xcf87c4a9, 0x082a36ae, 0x465eb00d, 0xed409fe2, - 0x8d8bd211, 0x82a7e04d, 0x80ecaf7a, 0xaa2788d4, 0xb9e1335d, 0x1764e2a6, - 0x6bdae3b0, 0x13c08b3f, 0x2f801162, 0xc109037b, 0xab98bc55, 0xf877c740, - 0xd7813959, 0xe565cc27, 0xe89f5e44, 0xef4ce563, 0x0035520b, 0xcb471716, - 0xca6f3ab4, 0x80bc7907, 0xfcf173b0, 0x84cd8d7e, 0x73ab0bcb, 0xdfd43566, - 0x8b9cf049, 0xaf09ffa8, 0x5f1eb34f, 0x637a0799, 0x0dfbfab6, 0xd6a90f1c, - 0x30d35de3, 0x17aea6de, 0xeb64acf1, 0xfbf137f9, 0x53fd7522, 0xf59b7bfc, - 0xd41a647c, 0x7fc7abe7, 0xac5bd79c, 0xca8def2c, 0x037f767e, 0xd78c7faf, - 0xc61ea09b, 0x5af5642f, 0x6f09df71, 0x18e1c9d7, 0x431e33e2, 0xbf33260c, - 0x233696f2, 0xbf3c57f2, 0x73f707dd, 0x9bf30d95, 0xf519297d, 0x32fb86de, - 0x5049dc98, 0x51debc06, 0x77a8a2e4, 0x37cc65da, 0x48f5bad0, 0x972b064f, - 0x871f9c27, 0xead489e4, 0xe4c64461, 0x9ae8a5f4, 0x9005f012, 0x0ff4596b, - 0xfbe33ae8, 0x918fe21a, 0x664de973, 0x83e58fe2, 0x39554e05, 0x5574cee5, - 0x5cecd77b, 0x74b5bd55, 0xcc9eaa92, 0xdc9f2276, 0x5ccbe9cb, 0x17aaa254, - 0x6d9065f7, 0xb59d9dbc, 0x554fe5d3, 0xa85f3bb5, 0x9f8d0224, 0xa3dc49ba, - 0x7c8231e6, 0x9b96d7b8, 0xb3f8fc0a, 0x4e440ab6, 0xf627e53b, 0x1ba7f3b4, - 0x54fa598c, 0xcb10b978, 0x7e583bcf, 0x879b7b7f, 0x9e087395, 0xab6f6faf, - 0xca2ef2c1, 0x69fcf09f, 0xdb9f179b, 0xcfa15969, 0x2bfda47f, 0xda1e9fb4, - 0xa19f943f, 0x3373c3fd, 0x3f9e1fed, 0xfd43fda1, 0x942fda06, 0xc170a69f, - 0x0fda29f3, 0xed31ffbc, 0xb44fca1f, 0xb6bcb0f9, 0x1f962e6d, 0xf3e3f36f, - 0x7c06b6b1, 0x8ad6d9df, 0x96db47e5, 0xb6e1f3e2, 0xdbdb3e20, 0x2f7d6256, - 0xf9e793a7, 0x2be7dc79, 0xf103bdd9, 0x219fdfeb, 0x9d2fbb61, 0x154a539f, - 0x3f2ab97a, 0xfc033fa7, 0xfceabd02, 0xc21fc054, 0x8c786261, 0x0668e387, - 0x91270fb3, 0x930b72c8, 0x1f07181f, 0x6159e7df, 0xae35fca1, 0x4e7bad95, - 0xd3eb145f, 0x4778d81a, 0x5c409db9, 0xce519241, 0xbb439b8e, 0xcaa45273, - 0xd007f2c2, 0x14dc430f, 0x5aece53f, 0x21e64672, 0x5725c00d, 0x331e3d50, - 0x397c21af, 0xb7809c18, 0x57fde0d1, 0x696d378e, 0xa75fbb2f, 0x6c0c2ba6, - 0xe2b6f666, 0xb9c63afd, 0x9f4cb0be, 0xef1f9f2e, 0x717498e9, 0x5224dd3a, - 0x9bf176f9, 0x8ccfa144, 0x31fef526, 0x6a89417d, 0xb8bda67f, 0xd1572886, - 0xfbd48b7e, 0xbdfe733c, 0x198cefaa, 0xf5eaa90f, 0xfaaa15ae, 0x1e73bbba, - 0xc73e0371, 0x6199b8b1, 0x210272f5, 0x4fdd85e4, 0x4ce65c20, 0x92738f36, - 0x605f7ec2, 0x133dff37, 0xd6797fbe, 0x5c65f1ce, 0x09f2fb8d, 0x482c560e, - 0x0f406a0c, 0x448bfc7d, 0x9e3b7f94, 0x7e9fa0d1, 0x40690922, 0xe6a64cde, - 0x015fd424, 0xf16b8c37, 0x942d26aa, 0x85a2898b, 0x8a2455f2, 0x7fba3afb, - 0xf5d264d1, 0x9ffad16b, 0xd9f2d131, 0x2cb3ff4c, 0xfa8c30bf, 0x67af80ba, - 0xadc7d881, 0xdcfde397, 0x37f44cc6, 0x7625cfa9, 0x874bfdf0, 0x970df989, - 0xc153ca3b, 0x46373e0e, 0x7dcda83e, 0x14058de2, 0x63b4b6df, 0x1fef14f8, - 0x9ea33457, 0x94cbcfd7, 0xf75e5abe, 0xd44faa7a, 0xf307937c, 0xcffa5b38, - 0x6b76e029, 0xff228fc9, 0x3c84e874, 0x9e411253, 0x893d970d, 0x3b1e6624, - 0x93c9deda, 0x11fa2151, 0x375f326f, 0x4ff95f31, 0x4bc87695, 0xd179e02c, - 0xf2d2db3b, 0x7f0fc7ab, 0x5074e3ef, 0xa0352248, 0x348b0b5f, 0xe074109e, - 0x31fcabb5, 0x2f2efca6, 0x4b930b9c, 0xf2c40788, 0xf785d244, 0xd57fc829, - 0x7c9a3e62, 0x50a21af0, 0x0d6ad8fb, 0x70d16093, 0x75fb84bf, 0xfce5cfbe, - 0x9c6af667, 0xec259c8f, 0x74e80f26, 0x1bd599f2, 0xacfc3a01, 0xf4d8c75b, - 0xd0bebab8, 0x2def504a, 0x1487d42a, 0xebcbee09, 0xe5407bc2, 0xc8c9122d, - 0xb9a63801, 0xdf7e83e7, 0xb63a416b, 0x9fc72fac, 0xe359b830, 0x0efc40af, - 0xc2357b28, 0x9aeda2e8, 0x82b7eb27, 0xf001393d, 0xdcbc0562, 0x430d5f91, - 0x1e2217e7, 0x2f79f217, 0xc8e8f3e4, 0x833fc21c, 0x70bc7887, 0x6ea2ef1f, - 0xcf528fe1, 0xaad2f1f3, 0xa2bdc36f, 0xff2d11ed, 0x3e352299, 0x5322e957, - 0x70c34be6, 0x66173851, 0xb8015c82, 0xd80f82af, 0x919f9afc, 0x941cc6c8, - 0x6f68356b, 0x3f306994, 0x9b2e9e3d, 0x8fdc9932, 0x7dd9d866, 0x4853eee4, - 0x93e5c3cf, 0xc2482c6f, 0x5bb333fd, 0x8fcb326c, 0x58957af4, 0xe12af7bf, - 0x72e7e45f, 0xa1de1ccc, 0xb127057b, 0x892b60bc, 0xb4bc87ac, 0x2bf5f6b1, - 0xdc707332, 0xb53d7de1, 0xa53f205d, 0x5c7988cc, 0xa13e44ab, 0x69995472, - 0x57384f63, 0xfa74e465, 0xf79d4da8, 0x6fcf9db3, 0x418f5f3b, 0xf27bc8a3, - 0x9cc716d6, 0xafeba9f3, 0x88963f47, 0xff720ed3, 0x1d59a0e1, 0xa4e46d57, - 0xaba87830, 0xc1f10cca, 0x6da7162e, 0xdd99bfec, 0xc7efbb6b, 0xed302f78, - 0xa87a0153, 0x57ebede7, 0x0b58fdaa, 0x5f91fa77, 0xf164fde3, 0x398a317e, - 0xe31fec3d, 0x335b62fd, 0x43c27ef9, 0x7b0e218a, 0x61de7562, 0x7277ec33, - 0x1f0f9e08, 0xef017da7, 0x81bba6dd, 0x974fb82e, 0xa3fbb114, 0x54ffd7e2, - 0xb2f11e96, 0x78efac53, 0x3ba5da2b, 0xd81c98cb, 0x2dfce079, 0x2b3f69e3, - 0xf9d52473, 0x3a399580, 0x29b7a75c, 0x97b3c37d, 0xeed19a90, 0xa9943b29, - 0xef726af9, 0xc1eff55a, 0x1c0df734, 0xff2828b6, 0x1fba035e, 0x4279fc3c, - 0x1451f211, 0x08c4bf7f, 0xc19930c2, 0x76b3e70d, 0x17993e6b, 0x676f0f4b, - 0x36ff58ca, 0x0d2f8ba7, 0xae1ab557, 0xa56f45b3, 0xfd7060cc, 0xb9c6e40e, - 0x5894f1f0, 0xb5c0467b, 0x03df8c7b, 0xe2abf0f8, 0x1fad42a9, 0xfa74f062, - 0x6ed3c3bf, 0xfcf0e8fd, 0xb3f3c395, 0x9b5eec43, 0x515ff591, 0xe1ab759f, - 0x647cfb3d, 0x0a49880e, 0x7f115fef, 0x182993ee, 0xebf8e613, 0x59f4e52d, - 0x078fe5ca, 0xc09150cf, 0x1e63577b, 0x924caf66, 0xbe5ca16a, 0x2cf77f00, - 0x02c3ef93, 0xbf9e3f1a, 0x4619ef21, 0x64d77f95, 0x9ddeba31, 0x878a8d2e, - 0xcf362cd2, 0xb2ea4703, 0xd8f1bfc1, 0x7202063b, 0xbfcf3361, 0x6bdecc7e, - 0x05a67b84, 0x425ca11e, 0x747d019f, 0xc7bc2811, 0x2a333f4a, 0xd3c651d6, - 0xc6d6f1b0, 0x4f188df1, 0x1564a73c, 0x3a557b32, 0x387385a4, 0x0b7daf6b, - 0x5b5b7fef, 0xfdeca32a, 0x1d5ff8d2, 0x5bf0ff87, 0x7a30b729, 0xe1459299, - 0x90fe916b, 0x0e5a6df0, 0x2a7fd148, 0xbd157c82, 0xa01fe71f, 0x4691ec78, - 0x8b2d29e2, 0x9f988bd1, 0xdb80bf98, 0x5c02dd76, 0x06bbdb07, 0xbca51a54, - 0x8917d0bd, 0xbcc1ff5c, 0x2b5c5f50, 0x654c73b3, 0xdafbae32, 0xee78a98a, - 0x17cf376c, 0x1fa35e89, 0x164477f5, 0x763dbc70, 0xb811b7f1, 0xafd83947, - 0x883ffbc3, 0x15bee03c, 0x8dff1fee, 0x5389f78c, 0xfb81aa7a, 0x391c0ecc, - 0xebfb009f, 0x843a59f9, 0x87973e7b, 0x35b51783, 0xc8ec1e78, 0x0c6d7667, - 0x6965d7fd, 0x89127db9, 0x35af39c0, 0x8b3cec25, 0xd603db95, 0x001b2723, - 0x43c56b7e, 0xde862906, 0x10196566, 0x68fa35ae, 0x17f6878a, 0x6125a7d8, - 0x7bc1ffe6, 0xb3ce8719, 0x5a1e19da, 0xbda10f4a, 0xf767ed60, 0x2965d635, - 0xb852ce4c, 0xe6f7d2f7, 0xebd99f89, 0x8e94bea1, 0xbdfc3b97, 0xd3d6cecd, - 0x4beec65c, 0x3fed7b5a, 0xc83ee1db, 0x471df844, 0x79f2efd8, 0x7292b80a, - 0x48dfbc35, 0xcbf81724, 0x5abe632e, 0x235ef86f, 0x2f82fbd8, 0x62d5cade, - 0x39f947bb, 0x0a2b4789, 0x4cae7043, 0xdb35b1d0, 0xcc1640ff, 0x0bc5f28f, - 0x7c44ef68, 0xf63f10d3, 0xdf33c862, 0x32e64525, 0x076f443b, 0x68d42c3e, - 0xe116fc54, 0x549e26eb, 0x73dda3fd, 0xa15da73f, 0x46423bf7, 0xfe4de702, - 0x22667178, 0x191da7d8, 0x1af3dec2, 0x259b5f01, 0x8c0e625f, 0xdc5a2ff3, - 0x72381e0f, 0xedc601bc, 0xbe02f3a0, 0xeb75f87d, 0x3a53b06a, 0x53e45eec, - 0xd0ecbe31, 0xfd60f5f0, 0xdf7bd6ec, 0xd4647f04, 0x3acdeec1, 0x11867538, - 0xd3b69fe8, 0xa07f3f40, 0x04f0f7fb, 0xfd1aa7e8, 0xb3ed0b06, 0x8b77c3a6, - 0xb011ff88, 0x6b75176f, 0x3c83f755, 0xc2c5e5cc, 0x8e12168b, 0xac2c2fd9, - 0x6b9e0ef8, 0x0131785c, 0xcfcc3fdf, 0xcfcc3fed, 0xf8e2edbd, 0x5f3f9978, - 0xfb8afacf, 0xde9c4f6f, 0x8eddfe4a, 0xbbf7c63a, 0xa59afd60, 0xfaa83d01, - 0xc73f5335, 0x687f64f3, 0x21b093b3, 0xf311de06, 0x98e1224c, 0x5dda8771, - 0x52709134, 0xfa32faec, 0x15af9e1d, 0xe6d0ffeb, 0xdd8e3c46, 0x1e1538ff, - 0x53cffb87, 0xff6471e1, 0x87ff5805, 0xf44bc2b6, 0xfe8c793f, 0x0ff05473, - 0xef8f9bf7, 0x7bac1dcf, 0xeef942d6, 0xc6c57860, 0xf7e14b57, 0x7bf80cf7, - 0xb7afa41b, 0xeeb9cf0a, 0xfa0e7822, 0x7a7ffd81, 0x1f52f21f, 0xc0f7aad8, - 0xe8ba8318, 0x7a28cf3c, 0x83d89f26, 0x789cef70, 0x87959dbe, 0xdeff1ceb, - 0x90ec8728, 0x942c6a67, 0x8ce7a0ed, 0x015a1224, 0x235297fb, 0xdf1139ca, - 0x34fefd12, 0xb392ab53, 0x46a17ee2, 0x68d87f9e, 0x26aff161, 0xac2cffab, - 0x574d12ff, 0x1f68cfcb, 0xf03b0ba7, 0x0e213b7c, 0xf888d7dc, 0xc5fb0c8e, - 0xf97d703c, 0x9b0b9c08, 0x0cffe397, 0x1509fbbe, 0xd1ef102b, 0x0fcdb15e, - 0xf38f79f9, 0xa6e3e47d, 0x2313db88, 0xf2d9753f, 0xba1bb357, 0xecb7e8e2, - 0x8cc23b77, 0x40d9757e, 0xcfc8dabf, 0x7ce072eb, 0x67bf00e3, 0xb9fb414e, - 0xde30f4ae, 0xfc275947, 0xf3e32b02, 0x601d3256, 0x54788b4f, 0x8217e402, - 0xdd86b0dd, 0x616f5853, 0x275ffae5, 0xba17b9e1, 0x8114b21f, 0x65add99c, - 0x071e22fe, 0x1e61cf3b, 0x02c9ae34, 0x7cf20efc, 0xaffdf397, 0xe7a7bde1, - 0x3a478e57, 0x0fe5ffa8, 0xddc31ef1, 0x0d9f4ce9, 0x3ea1b3ee, 0xca7837ab, - 0xddcd5ee1, 0xed6ecce9, 0x2509c395, 0xa3ec7631, 0xa7285519, 0x5e395e3f, - 0x19271b13, 0xc2e4cd9f, 0x94ffe11a, 0xce70e5a3, 0xf0d2e3ea, 0xdd3ea13f, - 0x1bdfc263, 0x53fdecd3, 0xbabfde39, 0x63bf80c6, 0xe277b551, 0x5fb0b9ba, - 0x1f31904c, 0x84d7b35b, 0xc55d9cf0, 0x6f8383ee, 0xef35ee41, 0xcbbf871d, - 0x62896f56, 0xd9b364de, 0xc1f10053, 0xc0dfbdfa, 0xf1389fdf, 0x902cc4f8, - 0x9593c783, 0xfb6fbc2c, 0x3a748a71, 0x26fbe3ef, 0x579df7b0, 0xdb6ab9e3, - 0x347f8b1a, 0x4bd088ff, 0xedcdf7f1, 0xd73e2f4e, 0x6899f807, 0x5e1c80f4, - 0x675fe438, 0xbfd607f7, 0x24a59d19, 0xf306ffa0, 0xa7edea17, 0xeb1df7f0, - 0x49dd8fbb, 0x42e93e30, 0xbcfb15fa, 0xb9eb71f8, 0x8faddafe, 0xd5df83ce, - 0xf8e76fab, 0x59f7bfe7, 0xdfc629af, 0x5ff8149b, 0xf31f7713, 0xc5de38f7, - 0x1911c4f3, 0x76a4b9ef, 0x8ff81645, 0x2037ec4e, 0x33589dbd, 0x1057ef19, - 0x5853d5e3, 0x8f4f94ed, 0xb029953b, 0x15b20bbe, 0xb676ff36, 0xe9ef157f, - 0xbdf811f8, 0x2d3ee8ce, 0xda0dafe6, 0xc71009a3, 0x7944ed14, 0x5afd3e68, - 0xddb7bdfc, 0xdd7007e9, 0xa0115d29, 0x6d2fcd2b, 0xbf03b7a8, 0xf71bbf64, - 0x82092971, 0x8ef8349f, 0x077bf701, 0x9ed019f7, 0x9d977c1e, 0xef711fcf, - 0x059a359f, 0x7e06dcf7, 0xdae50e39, 0x0b746660, 0x784dbfb3, 0x51e0e4cf, - 0x5e3cd5ff, 0xd1efc69c, 0xefbb034c, 0x18533ec2, 0xc4fa3eec, 0x6c9043b8, - 0xfdfbe373, 0x882fbc16, 0x24f9d93e, 0x7f1b8f69, 0xf1748937, 0xfdf823ef, - 0x09fe5903, 0xc81fa720, 0xe15bfda3, 0xeed893fb, 0x4affae42, 0x9211598c, - 0xc74bc7ce, 0xd9fd337e, 0xccfa5ef8, 0xa80f7ecd, 0xb047d78b, 0x5ff0603e, - 0xbdf8f38d, 0x328cf48d, 0x5f7aafcf, 0x49d97de4, 0x6e028eb8, 0x23b4678a, - 0x93d2f1e3, 0x029ff6cd, 0x3974f11f, 0x80979eb4, 0x7832fc0f, 0xb63ec0bf, - 0xea26ab8e, 0x9ce93c99, 0xde32f68c, 0x27931430, 0x07df7cb8, 0x3a839748, - 0x97a0d3ef, 0x847547a2, 0x2d48c3dd, 0x5457f003, 0x16f576b0, 0x7010f7e6, - 0x07e7e19c, 0x1e593b1a, 0x3ee799e1, 0x856f9ac8, 0xa81ff3f3, 0xff0bcfce, - 0x0124ed21, 0x8f5633fc, 0xc4575092, 0xc22d76ec, 0x6e8f7ec5, 0xdfc14e8d, - 0x3e3e0c0b, 0x2712fd11, 0xbc5ecaf4, 0x15d57607, 0x6d27a01a, 0x4fbf9731, - 0xfb8979b0, 0x6d3dc4dd, 0xc81978f1, 0x99b2fa66, 0x3b82eff8, 0x25138ffe, - 0xf14b0785, 0xff744abe, 0x52cd206b, 0x7e589af6, 0x9185ea3b, 0x2fea42f7, - 0xff827bf1, 0xb053e5bb, 0x9f806556, 0xd5e80260, 0x7fb676d3, 0x40225bc4, - 0x3cd96bbf, 0xb803e03b, 0x4ef882ff, 0x5bc45e83, 0x4e1e2825, 0x9e3eac4b, - 0x1bbc84ce, 0x1ba00f81, 0xa3be17e8, 0x9d9e7f7d, 0x763ff6c3, 0x17943f27, - 0xaa5e43d4, 0x490157d0, 0x0f7dc0d6, 0x024a1d27, 0xcec9e5d0, 0xc872e73c, - 0x292871f7, 0xe076f6b1, 0x0e7bc110, 0x73ff3814, 0x922efc35, 0x05f80a77, - 0xfed53b77, 0x5e787888, 0xfd401ca8, 0xc6985ff3, 0x800053c5, 0x00008000, - 0x00088b1f, 0x00000000, 0x7db5ff00, 0xd554780b, 0x733effb5, 0x79332666, - 0x84841e4e, 0xe4249840, 0x09308401, 0x0741410f, 0x68151048, 0x85280978, - 0x42100793, 0x17b6881e, 0x240cdb5b, 0x41b45a20, 0x768bd151, 0xb4544140, - 0x03414141, 0x58a50077, 0x56d56351, 0x880dcb6d, 0xa8311fbc, 0xadadff97, - 0xfb5bf5ff, 0x90ce649c, 0xf9b7b5a8, 0x67d9d83e, 0x7b5ad7bf, 0x3bdaf5ed, - 0x3f437cdf, 0x756109d7, 0x10f4422b, 0x116dce22, 0xa3109862, 0x42f382dc, - 0x11c885d8, 0xca8df3fc, 0x5c3adb89, 0x8df88588, 0xdaf9aaaa, 0x2bc89eb5, - 0x1f5c2deb, 0x774675e3, 0xb5f1bdf1, 0x28f250ff, 0x084c21b3, 0x5d3dfe87, - 0x1e310f88, 0x90ea7b8d, 0x460ca7dd, 0x09ac2e1a, 0x75ac5442, 0xa51a45fa, - 0xbacc4e6f, 0x4285e653, 0x5c6cc775, 0xe34ad899, 0xca2a6f96, 0x1fb29112, - 0xd0aaf341, 0xea9e55e7, 0x0a8752cd, 0xeaa8f6d1, 0xebf684da, 0x6a8f9e55, - 0xa51eb8f3, 0xdbd627ef, 0x9fa9cb5c, 0x273e7d0a, 0xc5d16b7a, 0x0ab794b9, - 0xf280bdab, 0x45da2d56, 0x54782efd, 0xb177f62d, 0x81f7aa3e, 0xf80ba0b5, - 0x3a894d60, 0x1ea8327c, 0xe39469d6, 0x7268f7bf, 0xc2fcd157, 0x63cc77e9, - 0xd1f7e2a3, 0xd1f44efc, 0xfc7f21e6, 0x82b13093, 0x45daeaf2, 0x2bdceed1, - 0xa1c27de1, 0x01727b45, 0x031eb95f, 0x18e3a19e, 0x7808bcf0, 0xbabd20c6, - 0xabf04bc5, 0xa0f5487d, 0x4be6bece, 0x98df80d1, 0xae47453d, 0x61b5f7c1, - 0xecda8c22, 0xcefe9c3b, 0x8b8f34ad, 0x3d4155ab, 0x193dd28a, 0xdbc68289, - 0x2e7cf96e, 0x4dbf73e0, 0xd2917acc, 0x47a7b7d2, 0x46fd285b, 0x21f51fa7, - 0x6a352709, 0xae7cf47a, 0x98b93edf, 0x9edcc7f2, 0x7aa082c4, 0x2ce9d63f, - 0x6b655f14, 0x718d16ff, 0x78d8d62a, 0x2e5e065d, 0xbf341d62, 0xfe118d8b, - 0x8b9704e5, 0x5fb8dbbd, 0xbf464f03, 0x4183c015, 0xa56f544f, 0xe38fa5db, - 0x114717b3, 0xe1b4d35c, 0x64e82e9e, 0x2e3483c1, 0xe51f5bfa, 0xff7de675, - 0x74780d71, 0x25969be0, 0x8f03fc0c, 0xbc6da44f, 0xde59be97, 0x93d10ab3, - 0x7d78d0e0, 0xcbdf42aa, 0x850984f6, 0xda532bfa, 0x9c09288e, 0xac14fb77, - 0x8c3cf17f, 0x9871f657, 0xf7c7e505, 0xf3c79f5e, 0xc12bc10a, 0x7a2bb529, - 0x96d698bf, 0xdf8209ea, 0x736d3ec5, 0x7d06be79, 0xe79bce74, 0x4c37bb51, - 0x4c5c5f60, 0x76467c23, 0xf801b1c2, 0x5df5c619, 0x6f6fa676, 0xb1d7e01e, - 0x7ac8575e, 0xfdeb215d, 0x0b7d3040, 0x29ebc68f, 0x82cc24ff, 0xdc0fe5ef, - 0x71a6e594, 0x8e3bdf8e, 0xce3c75d7, 0x75fd879b, 0xcffa953c, 0xe59d72bd, - 0x733ad00f, 0x8d9d65bf, 0xb757c64e, 0x7b6b8ceb, 0x3acb7c42, 0x6874ea37, - 0xab33f3ac, 0xfa8ada3b, 0x9cb155bb, 0x14fb6a8a, 0xcc8d7fdf, 0xd0d056bb, - 0x0f4936b5, 0xfc236bb5, 0x6685d7c0, 0x6e7f04db, 0xf1a01f27, 0x583d27be, - 0x8f8e1e98, 0x023c3f75, 0xea9f75f4, 0x9701b9f2, 0x9cfcef21, 0x57efc7f2, - 0xb1f9025d, 0x0fc47e12, 0xc70fe02c, 0x73278b53, 0xb5cdaf7e, 0xb4f9fa82, - 0x047f6ff1, 0x63dc5cfd, 0x5f5e0b73, 0x90b3fdf1, 0xaf82f9a7, 0xc66e5c11, - 0xebce54b8, 0xd619ef57, 0xe8f17288, 0xbba65760, 0x0214be0b, 0xaa358ae7, - 0x01d21f69, 0x3ed5e3c1, 0x3ac6e290, 0x8713380c, 0xa83a9acd, 0x4fc81e13, - 0x9709d41f, 0x9ad0bb5a, 0xfb12fbf8, 0xfc414194, 0x9749f00c, 0x3cff44e7, - 0xa2d2c7c9, 0xc873f683, 0x8ff942fc, 0xff48cf51, 0xcc57c1d2, 0x705178fc, - 0x1950e09e, 0xc21c5f92, 0xca42aa37, 0xb7ca43ab, 0xf99cfaf7, 0x13f8e840, - 0x31bee4d3, 0xc3aa58e0, 0x9145bb71, 0xc53ee47c, 0x2d7e89bf, 0x4bedbab5, - 0x8e2ffe69, 0x4fd0f311, 0xae385599, 0xced97de5, 0x8ab52beb, 0x7c02b086, - 0x633d70f7, 0x435fd4dd, 0xc3e51c58, 0x7aa21f25, 0x7941ec13, 0xf31adf83, - 0xf0934f09, 0x5bc5d230, 0x83c78d9d, 0x14dd59e0, 0xeed7ca6b, 0xee3c6e4a, - 0xc62fcce8, 0x6ff4c92f, 0x387ead22, 0xaa7f22e0, 0x8c1eb577, 0xb249fa20, - 0xd469e168, 0xff83c5ef, 0x66eb9d1b, 0x262f0fbc, 0xe9a816fc, 0xf5a61d2f, - 0x3d56edb6, 0x9befd09b, 0x5f11fcf2, 0x1b787a5f, 0x9bd9af7d, 0x7775ee21, - 0x8e143fae, 0x8a5d7717, 0x17efa74e, 0x05c3d90e, 0xcda501c9, 0xd1ed63f1, - 0x84babfbc, 0xbb875bbb, 0x6b05dfd1, 0xa094f46b, 0x6b44177a, 0x7a20d4f4, - 0xa975dd29, 0xfc31e44e, 0x1f106a7c, 0x8f4f74ff, 0x2f7d2ab1, 0xb1af7dfb, - 0xe9c74a16, 0x736fdefd, 0xe686b93f, 0xe61ddbed, 0xbef34cd9, 0x0b2ce6f0, - 0xb3785fda, 0xea7f4f42, 0x4fb3f4e5, 0xb47e3153, 0x31bbd245, 0x293488de, - 0x8e59954f, 0xfc1a313e, 0x699ed5ff, 0xe59d69f5, 0x2c829665, 0xad9b79e0, - 0x7de62e6d, 0x95ab1141, 0xc67eceb8, 0xfdb9b9a5, 0x9f27dd85, 0xf4f87f00, - 0x60053efe, 0x6776172b, 0x7e5469e7, 0x5921e3e1, 0xc2f7ea2e, 0xf01ec97d, - 0xf7366d85, 0xeede994f, 0xdf60f289, 0x9c61fd1b, 0xf77fe825, 0xa435c355, - 0x52f9cb1f, 0xe3934f3e, 0xce8294fa, 0xee2da37e, 0xbf028f5f, 0xb3cdbdf8, - 0x7fa59299, 0x8b19e8cf, 0x773f61f5, 0xd5b28781, 0xe26dc261, 0xde782b27, - 0x8763c2a5, 0x1172841c, 0xa2e55f44, 0x6fcfbf98, 0x405f7f34, 0x17df027c, - 0xaf7f37ae, 0x5aab8d10, 0xfc8b7d69, 0xf682efe6, 0xfb112f8f, 0xe269f8da, - 0xd6f17ef3, 0xf54cc26f, 0x0fe74f84, 0xa5c7e60e, 0xc7c11fb4, 0xfefc579e, - 0x3defc015, 0x7433af2a, 0xd2d3cb5d, 0x448f1d78, 0x6b6e63fc, 0x598f5e10, - 0xe0893584, 0x1c2ecc7a, 0x47e80549, 0xbeab9c08, 0xcdfe613d, 0xfedee4d4, - 0x3296a55f, 0xe0b24bdf, 0x05c3b83c, 0xedfd47ce, 0x7e8a9939, 0x791756ca, - 0x77e6835b, 0xe47de6d1, 0xdf5790e7, 0xf54d7e23, 0x37f58d8e, 0x1d79a58e, - 0xd4f557bb, 0x33af3177, 0xe3f99f24, 0x28f71e09, 0xf2843fc2, 0x2d4c9ccf, - 0xde9cbc21, 0x34b5327c, 0x3115fe98, 0x8d1e982b, 0xebc26694, 0xf489ac82, - 0xeb05ad18, 0x89d7ad09, 0x0d7cf35f, 0xb1553a78, 0x787a2ba4, 0xe54f7414, - 0x05577f39, 0x3d9acee4, 0x33e83f36, 0x0f17e362, 0x6cfa0adf, 0xda40b9b6, - 0x2f547bb5, 0x5bb174e4, 0x1ce267f5, 0xba34fe6b, 0xeecce712, 0x68352e21, - 0x170e74dd, 0xb0b97ce3, 0x596252eb, 0x1933f72e, 0x9eed44f2, 0xdfa03c87, - 0x5cf1e6ee, 0xf1affa9a, 0xff99af3f, 0x20fdcf9d, 0x81f046f1, 0xc0b2278d, - 0x3e0f89df, 0x99fd8697, 0x791db5f5, 0x83875a21, 0x2c7e68fe, 0x7ff45fbf, - 0xa3a5f2c5, 0xbbfaf559, 0x349ec3c0, 0x07ffc33b, 0xcd026fcf, 0x7e73b12f, - 0xe03d9f34, 0x6b3cc6cb, 0x9c766ddc, 0xd11d17b3, 0xb4a7e079, 0x89f989a0, - 0x06e4f9fa, 0x289b2d7f, 0xee16bf88, 0x09c2bf9e, 0xf151a179, 0x6f280f40, - 0x2adcf956, 0xddfaa0df, 0xecc29784, 0x213bf6bb, 0xe5443e9f, 0x3abc74d4, - 0xa8b38fea, 0x54fbc2fe, 0xf8dbefce, 0x80da3fd3, 0x11360dd7, 0x47863c06, - 0x63c7d26f, 0x3e916879, 0x37cd45bf, 0xb7a0569d, 0x013d51ec, 0xe51cdfb4, - 0xd5b2f7c1, 0xf4c163b6, 0x50bf1f35, 0x2bd7f37f, 0xf81a40fe, 0xc2fcb984, - 0x27ce9f30, 0x5c6fbe42, 0x027f7535, 0x89eb2b52, 0x72e6fc8b, 0xf34ebcfc, - 0xdf7fd5a9, 0x17a6b99a, 0x29c173f0, 0xabf60b44, 0x1df595b5, 0x054d6811, - 0xfeec2f1e, 0xac78152c, 0xb27ff57d, 0xebf81744, 0x51cd4fd8, 0x84222709, - 0xc6e74b38, 0xfdd01637, 0x5dc5c9a5, 0x8fb17fd4, 0x6d5b17dc, 0x63905ebe, - 0x8afc6ff7, 0xddc5c1f9, 0x17575f5a, 0x5fb9dbf4, 0x124b4e7d, 0x205380d2, - 0xbae4da1d, 0xe484fb11, 0x1f417bc1, 0xdd4d569b, 0x6be77944, 0xa2424836, - 0xf7923336, 0xfcc7f60b, 0x7d8d7ea0, 0x017c15b2, 0x1fc930e9, 0xe523ec5e, - 0xbcbad584, 0xfb5f75b0, 0xe62ecce4, 0x26cd3ab3, 0x923edbcf, 0x2b4dcc6f, - 0x9c874f0e, 0x0345f161, 0x75ebc21f, 0x157c1027, 0x97eabe9d, 0x3df0512d, - 0xda723449, 0xfa71345b, 0x245a10b8, 0x0b8f0bea, 0x4fa21670, 0x7bc7e02c, - 0x31abd79e, 0x8e89fcdf, 0xd06af03b, 0xf8562f83, 0xeaefd337, 0x63508746, - 0x46b5ed20, 0xa0d451a3, 0x4beebfa9, 0x540fb6e5, 0x3ed49fd6, 0x2e3d3e06, - 0xc8cbf7e0, 0xf8c131e9, 0x74b877db, 0xdeabfa02, 0xf52e7a49, 0x4d877e77, - 0x5957a004, 0x3d50bf69, 0xec2fe1db, 0xcd4be069, 0x5cbc808a, 0xaf7c794b, - 0xfaf5651d, 0x9792e083, 0x9a91e12e, 0xbb70c59e, 0x9a1ef560, 0x9573fa08, - 0xdbd721da, 0xc04f970e, 0x2a4b6379, 0xfb5e63b5, 0xa4758f0e, 0x56b16f01, - 0x9aab37de, 0x5c5b718d, 0xf62a3fe8, 0x436f9e03, 0x534445ae, 0xc28f86bb, - 0x874c0cfc, 0x3a6143e4, 0x85021b5c, 0xf817770e, 0x14c289f1, 0x77ca8231, - 0xcf3013a8, 0x1752aef3, 0x958b68f0, 0x9b308776, 0x9af40277, 0x78b8d8b0, - 0x7a446fcc, 0xabffcf06, 0xcf3c25d8, 0x80bc48af, 0x7af241be, 0xbd0df231, - 0x7d8655cb, 0x8fbc23e3, 0xfc721d6b, 0x9f2a3da8, 0x43a462a3, 0xbbefdbe7, - 0xc89c68ca, 0xd024dabe, 0xa89f3183, 0xf00baf61, 0x858b1ce7, 0x3786b3e5, - 0x2f80d722, 0xd21be518, 0xf819bd25, 0x75609958, 0xae3c7f81, 0x574ae7d3, - 0x6820a3b1, 0x161eb69d, 0x0ec55e1d, 0xbdbb69c0, 0x97ce10f8, 0x738efa36, - 0x54d27f73, 0xaa14f407, 0x273f4167, 0x64c768ea, 0x0ee9dfa3, 0x424177c0, - 0x5bb478e9, 0xc2ac9628, 0x5eb85b7e, 0x3e208115, 0xe39360db, 0x211cb82e, - 0xc73a4302, 0xe3f8405d, 0xf9a397f6, 0xd653837b, 0xfb92886b, 0x2974cee7, - 0xd3d4ae2f, 0x83fa7ab5, 0xccc7baf9, 0xfec7cfd7, 0xe4a94b71, 0x53a677ef, - 0xeb4ad5bf, 0xab268878, 0x80edda92, 0x973a89ef, 0xcd058408, 0xc6758af7, - 0x38d0408b, 0x3b2ef51d, 0x183e2045, 0x47c66e1f, 0xb9237ae7, 0x125d44fc, - 0xfefbb1c3, 0xec704c53, 0x04c33fec, 0xcffb2bc7, 0x7513f2e2, 0xffd1df39, - 0x4ffa6ec0, 0xb3bfcd33, 0x5dfc7edf, 0x82fad2ec, 0x22eddcbf, 0xd374c07e, - 0xbb2676ca, 0x7606fda2, 0x9871f12f, 0x95f7dc80, 0x0576cb53, 0xe96d87f1, - 0x0b9f5d76, 0xfadf80a4, 0x6b4e3ac4, 0x8f1a5d77, 0x0be26ef6, 0xcbd0e76c, - 0xcf1b456b, 0xfa02fc13, 0xbab648bd, 0x96977cb9, 0x98c8bd0d, 0xf33c8747, - 0x859f48bb, 0x9ed841f6, 0x1f6347bf, 0x4db6b45f, 0xa9aa7d86, 0xde088d59, - 0xfdf407d7, 0x17cfb631, 0xd5d7b079, 0xbdf11da0, 0x9c5dee9f, 0x84d4f80d, - 0xde61e5b5, 0x2dfef7fb, 0x57c8e70f, 0xc5f7167b, 0x9f54adf7, 0x5b7b0fe5, - 0xbfa8278d, 0xb3e5c27e, 0x9b4ce88c, 0xfa1ffdf5, 0xfa9eeb7d, 0x36c7985e, - 0x2e483dd8, 0x56f659ac, 0xb078f1c6, 0xe083ef21, 0x16f8825f, 0xa6bb43eb, - 0xdf2063a9, 0x0f32487d, 0x96ee87e5, 0x3ed0c372, 0x83496fc2, 0x2ce1f7dc, - 0x619a89f0, 0xe1541776, 0x9616fcf0, 0x3987c3b7, 0x9f9f385c, 0xebc193ed, - 0xc84e43b3, 0x78a2fb40, 0xf154e7a6, 0x1b6dc9af, 0xe04ff642, 0x68db350f, - 0x75b56abc, 0xf78538f2, 0xa9f031d1, 0x78bfb79a, 0x135fd747, 0x8c5a9f81, - 0x5f78f04b, 0x432127ef, 0x9a7a893b, 0xabbef5a3, 0x9b8cdea8, 0x1fa15393, - 0x99fae895, 0x19404898, 0x1068fcc9, 0x9e5720ec, 0x7a0f52db, 0xc034d14d, - 0xf0ec97c1, 0x981afce0, 0x71c91c22, 0xf4fed0d8, 0x57ee34a9, 0x2ec316e9, - 0x03de60aa, 0xdf3d35f4, 0x2c6969ab, 0x38fe939f, 0x3b3fd1d0, 0xfbc325ae, - 0xa30bf077, 0xdf3787fe, 0xe2eb483a, 0x79e430dc, 0x36e9bdbb, 0x3aadb3cc, - 0x9847f592, 0xc9eed0f3, 0x2a02c39b, 0xc8b68aec, 0x3fe7d0d5, 0xb07b988a, - 0xfee3c107, 0x83222d28, 0x799acdda, 0x95e42ac3, 0xa5eef1fd, 0xd692e7a0, - 0xd3e7c0e1, 0x83262d4e, 0x6872afc6, 0x8969137d, 0xd968fbe7, 0x8be43831, - 0x449e25e3, 0x2ee2a0f1, 0x53e72fe7, 0x0ff1c8a2, 0xe8496947, 0xf2d2c4a7, - 0x66f855c4, 0x837b616d, 0xfdc1e868, 0x8a8bb79c, 0x037fe4ae, 0x75f4470e, - 0x6b89b3ec, 0xf6fad32f, 0xd4f18dad, 0xefcb7cd3, 0x96b7399e, 0xe296f9d2, - 0x9a6a80c4, 0x55d61677, 0x9be92be5, 0x79f3f24c, 0x65ef3e9b, 0xaeadbcfa, - 0x1cfde0ac, 0x437aef3a, 0xc285f95e, 0x50ff20fa, 0xac5f15fe, 0x87ca5eff, - 0x307d2e59, 0x20d6e70d, 0x3649db0b, 0x22ded384, 0x7d5df23d, 0xbed38f9e, - 0xf7f1c473, 0x149ef8d5, 0x3d27db2e, 0x7ec3f16c, 0x37763c50, 0x9ac9e9e3, - 0x634a8f48, 0x1db70895, 0xf0995072, 0xd9fc5cb2, 0x69edbf98, 0x661575a5, - 0x6e01d768, 0xa92de2f3, 0xb43cf01f, 0x6f205381, 0xf8eb928d, 0xd7937916, - 0x6cb85531, 0x3589942c, 0x531fc816, 0xf329725d, 0xa63fb915, 0xe30daf09, - 0xd71a10cd, 0xbb05c3fb, 0x1fc4fa17, 0xbcd10ba0, 0x7f1f0a67, 0x9cfc2d9f, - 0x5c022ade, 0x95a2c7ff, 0x89bc06f3, 0x4825e63e, 0x53d938fa, 0x8cdff865, - 0x9117bf79, 0xad1967d7, 0xd923ca63, 0xad5fac99, 0xf9f0c1eb, 0xd14f79ae, - 0xeff686e9, 0xfd83f43c, 0x99fa9d3b, 0xfec8637a, 0xe061ec2d, 0xf6dbf333, - 0x877b4b51, 0x4c9914fe, 0x475eb870, 0xc5def5e9, 0xa9153fac, 0xf847c291, - 0xfaa51969, 0xf21c7721, 0xa0484f2e, 0xb9fddc75, 0xb77e83d4, 0x843dbc5c, - 0x46377fca, 0xd2dcf515, 0x64d4f2cb, 0xbdc99fbd, 0x9d869fc7, 0x2408b0f5, - 0x17b9a50c, 0x8f5ed65d, 0x564ef9a1, 0x52c435b7, 0xa4de84f9, 0xbdf104c7, - 0x5bb6121b, 0xd8ddd7a1, 0x627dfccf, 0x99df59ae, 0xc0551a24, 0x7350f279, - 0x0f807dbd, 0x0c8ad7d1, 0x0188b7a9, 0xdfee8062, 0x47fbb963, 0x13ed1f7a, - 0x0be1d92f, 0xbb433579, 0x3a5c7007, 0x18b9b3e9, 0x7ae55857, 0xd951de6a, - 0xe48c779e, 0xdf9d2f2c, 0x84e8ebc7, 0x08f29308, 0x6e48a7f2, 0xcea67a40, - 0x3a39e9cd, 0xa17e51e7, 0x67eb23ce, 0x7d803f14, 0x73faba56, 0xb772f02b, - 0x6ef9c253, 0x761faa67, 0xc6a68ab5, 0xe55e98f1, 0x4883a6ae, 0xe3c503cb, - 0x382ecc71, 0xd220e4b4, 0xb6f43bbb, 0x5fdd0e25, 0x5dbff3c0, 0xa3dbd3a7, - 0x8834dea6, 0xbbedc9f6, 0xf6ebdfa5, 0x4da7533e, 0xc6de404a, 0xa8e8eef9, - 0x3422b2fa, 0xa8cf22da, 0xb758cdde, 0xc1e8f9b7, 0xc9e75a78, 0xff3c11ba, - 0x9e5e75d3, 0x09bad9ff, 0xa33dfe9c, 0x27ae39f8, 0x6c79673e, 0xd6a3b6d2, - 0xe45faa14, 0xb7d8bc55, 0xdf857ad7, 0xdeb1744f, 0xf581cf26, 0x1f600e74, - 0xf534198f, 0xe9303bf1, 0xda276d0c, 0x5171b8cf, 0x3c99c611, 0x7a8ac4a2, - 0x2216bf33, 0x4e93ad3e, 0x8dee8bbf, 0xf8eb57f5, 0x6157bf3b, 0x1bdf9e78, - 0xdf6cf0cb, 0xf9031191, 0x8ccee960, 0x6f89489e, 0x046f7a1a, 0xd97ed7e0, - 0xff6df3c2, 0x8ef59c28, 0x774bf6d0, 0x7a89ec0e, 0x22df0967, 0xfb3cde48, - 0x83b87ffc, 0x71b395cf, 0x027d5f4d, 0xc957f6fe, 0x39b248df, 0x5ff818f1, - 0xd01e5eef, 0xce5d05cb, 0x02233d26, 0x6e8d5fe7, 0x427f0457, 0xb4b86cfe, - 0x217f0ee7, 0x17f62c65, 0x9c1373c6, 0xb9191cc3, 0x7f7087c7, 0xfd467e47, - 0x9258fcbd, 0xb9effa07, 0x63a48fed, 0xf34dadfc, 0xfa8c793f, 0xf8b7ef3f, - 0x9d4e746c, 0x5e174d17, 0x2a7e1f05, 0x777bed92, 0x9c2f342b, 0x717b9bc3, - 0x86b1473e, 0x2c39c32f, 0x73cfbcfc, 0x1975b714, 0x17aaadf1, 0x7a05ed1f, - 0x30608d7c, 0x5b5fca82, 0xed7cc11b, 0xc8e79b35, 0xb8f7f432, 0xfbe9efec, - 0x0bb63cef, 0x05d57de9, 0x65fa5277, 0xa1e31c46, 0x034581fc, 0x79ce9ed0, - 0x3dfd4c91, 0x80128af7, 0xbad06abf, 0x69922b7d, 0x1c37837e, 0x34a2f4b5, - 0x1ea529ff, 0x373ec0e9, 0xf9fd821e, 0x6e6e196f, 0x9a5b643f, 0xd96d829a, - 0x75c9ffcb, 0xe59bfe7c, 0x9f75dc82, 0x3a25ed8f, 0x4a0183e5, 0x348d99d3, - 0x8fd4b0d7, 0x6386340a, 0x6767af23, 0x6ff7b4f3, 0x49075815, 0x8977981e, - 0x91e7c3dd, 0x7811b7df, 0x78e5af3e, 0xf62bbf58, 0x3b7a0a3d, 0x707a25af, - 0xfa4cbd3e, 0x7fa8d5fc, 0x7cebcac4, 0xa2f7a9e5, 0x2189df61, 0xbf09d93d, - 0x78db7e48, 0xe3eeafd4, 0xf587f016, 0x09fae279, 0x8ecd4f80, 0x9fb91b9d, - 0xfa07872a, 0x4bcec56e, 0x2f205307, 0x993c20de, 0x321dc7a0, 0xaf42abff, - 0x56a5a547, 0xe652fc6c, 0x5f398a5b, 0xfc27da4c, 0xca4ca2fe, 0xe7e88f49, - 0x63cd68a0, 0xee24c97e, 0xafd7c4ee, 0xebe518a8, 0xb0c97cd3, 0x27e71b6f, - 0xfda97b9d, 0xb2ec65b0, 0x5bd8cb7d, 0xdf2e1953, 0xebb3dcf3, 0xdfd197e7, - 0x73e17623, 0xdf303f52, 0xc1be9ec0, 0xcdebcf2e, 0x2f4067c4, 0xe34d79c6, - 0xed93f5e6, 0x29afe0bd, 0x076832aa, 0x91e523c1, 0xbe379630, 0x62b3f8ef, - 0x6df9f156, 0xe1b55bc8, 0xd9f22f92, 0x885fed41, 0x37eeaed2, 0x7932760c, - 0x3bab0bde, 0xe3c8f217, 0xfa6bde51, 0x96d5bcb1, 0x39d0358a, 0x53e61d7a, - 0x95fc92a3, 0x457f2411, 0x73af7dc6, 0x2de51034, 0x5beffb42, 0xcd046c7f, - 0xf1290633, 0x86a468ef, 0x485a45de, 0x7d39fc97, 0xf3f8135b, 0x3f926143, - 0xbe610d47, 0x7433ac64, 0x07c4039c, 0x6f3be234, 0x11a339d0, 0x3917183f, - 0x7d78cac6, 0x907552dd, 0x3922e5ce, 0x1ada0802, 0xdef3943b, 0x61638228, - 0x2eb42aa4, 0x252347f4, 0x3ac7cdbc, 0x984427c7, 0xc42515ea, 0xbf8fb1da, - 0x1d55faef, 0x3cb86a4f, 0x8370d4bf, 0x7413babf, 0xfac87dbf, 0x776f7ae5, - 0x3abe630e, 0xeb7ef956, 0xdf15b22e, 0x8b8f3c09, 0x7373e7cc, 0x2394e45c, - 0xd475e09a, 0x7ae87be1, 0x1c25d743, 0xfa8e4fdf, 0x167c2289, 0xedcfc7ec, - 0xb66b776c, 0x5bf73eb5, 0xa2f36b82, 0x47ec0f5c, 0x70bed32f, 0xb54e9f80, - 0x0cdb9cb3, 0x37ea92d9, 0x5c7170f7, 0xdfba6bcb, 0x6f5b37dc, 0xbe7c14ef, - 0xc5eecf34, 0x615ef47e, 0x48ec1034, 0xd26fd2f5, 0x16f25b6c, 0xe5e6ebce, - 0x819a1e29, 0x69efc150, 0x97e47ccb, 0x095ebcfc, 0x817f0adc, 0x40bb73ef, - 0xfeb175fd, 0x5f94e9d5, 0x9e0c8bf7, 0x8fa447cf, 0x8abc62d7, 0xeb5be670, - 0x71c9bd62, 0xff979f04, 0xb279f2a1, 0x91f29f2e, 0x6ed9d7cc, 0x378a6eb3, - 0x04ad7e19, 0x36eb6f1d, 0xb05ef2ca, 0x4d3ca293, 0x26c4ffb6, 0xd7a2dfeb, - 0xfbf1d04b, 0xb4a74eb1, 0x683f99ff, 0xa0ac2393, 0x95fb77ff, 0x46fbc6be, - 0x17e19378, 0x933cac7a, 0x54b7986d, 0xf4c690de, 0x66d3dba4, 0xe8dcfce9, - 0xc31c0d17, 0x9fcb4f21, 0x3b37f3d9, 0x2a33df41, 0x1f21479c, 0x22b1547e, - 0x0cfd7a0a, 0x21840d4d, 0x917a6abe, 0x4bae43b7, 0x395eb8c7, 0x1fa1b96e, - 0xdf00ca06, 0x710e6dbd, 0x81ffcb2f, 0x96fac121, 0xfa45e781, 0x1a6eadbe, - 0x7eb060f3, 0xfe27695d, 0x72e51833, 0x6a45573f, 0xd57d07bf, 0xc1e1baee, - 0x54fbbd60, 0xbc7943f9, 0xcf71f4ef, 0x3c1f79d5, 0x6f39099e, 0xb8c6a702, - 0xf011fa1d, 0xd5f6fd49, 0xefda73cf, 0xdaf00b3e, 0x92fa94e4, 0x85e3edb5, - 0x359faf94, 0x09f7cf80, 0xd85e1d53, 0x8477daf5, 0xadaf61f9, 0xc5ee159f, - 0x44f7eaba, 0x985761f9, 0xd21befa7, 0x6fbbf8bb, 0xade98dbb, 0x667feeca, - 0xdaabb50b, 0x89e99fdb, 0x96ed95e8, 0x642357be, 0x6d37b479, 0xf79450e5, - 0xcd79fa64, 0xf2e18ee6, 0xe5c15537, 0x58ac81e1, 0x539b7782, 0x1375853b, - 0xbcfdb2bd, 0x1fbf2eca, 0xfa12e9d1, 0x96fffb25, 0x42bf7144, 0x8f3f6bcf, - 0x584f7d67, 0x91f3c9bd, 0xaf207dbf, 0x7dcbb347, 0x7ea46a21, 0xe725c478, - 0x9e39a475, 0x8f4185f7, 0xdcb78a47, 0xef809593, 0xfcd2af24, 0x0d4cb2fe, - 0xd06e1fc0, 0xf2f5329f, 0xbb5157db, 0xd9555f4f, 0xd7e7336f, 0xfbe30f8b, - 0x13d5159c, 0x6bbcad39, 0xf5cb9f32, 0xa2eea71f, 0xa7a984f2, 0xe06bbfd8, - 0xd9954e7f, 0xe9989a9f, 0xdf813355, 0x83f6ff5c, 0xd9e1ff54, 0xaf001627, - 0x473533c3, 0xf6dbec26, 0x4cff97d6, 0xfe5d6df3, 0x36a3d627, 0xf8116b44, - 0xd3f7717e, 0xc566bf5c, 0x7e802cff, 0x74956350, 0xb5db9c63, 0x91bf3d3a, - 0xffa2c5a9, 0x63bf15aa, 0xb722223d, 0xbbd7f245, 0x3a3f1fbe, 0x65f9bcd3, - 0x0e2dda85, 0x54e1ae6f, 0xfce1e7f5, 0xa204ab3b, 0x2b860c95, 0x5ce775eb, - 0x47e06881, 0x72b948b3, 0xbf10d6f1, 0xa8925031, 0xdda88bdb, 0x8f5526e2, - 0x41dbf457, 0x17f5a1a7, 0xf7ae77d3, 0x8a57bf3d, 0x763df926, 0x30d7fdd7, - 0xfe0045fe, 0x64cf33ae, 0x9c3d026e, 0x5674f9df, 0x34369fb0, 0x72be72bd, - 0x7df4e7fd, 0xd8be8e73, 0xc2db6f40, 0x0b85f64c, 0xf4eb24cf, 0xc2e9e926, - 0xe7ecd933, 0xd9f7d44e, 0x0967c505, 0x085fbb47, 0x9e10678e, 0x971ce1a6, - 0x0e1a6de3, 0x9d61fbb9, 0x6f8e2e2f, 0x67be0e1a, 0x68e141f0, 0x41bb63ca, - 0xf41e534e, 0x8a7f8364, 0xfe2ca6e2, 0x42ca6fee, 0xd22d97fb, 0xa7cc630e, - 0x8e14b9f2, 0xf0b5a27b, 0x6e7caefe, 0x8de426e0, 0x929dea71, 0x253bd4ef, - 0xb75d097f, 0xe8ed2996, 0x1ee64fa4, 0x3ea4b3a7, 0x5c82f496, 0xde6593e4, - 0x370bf329, 0x6fe1d894, 0xbcc9b7af, 0xfd897d6b, 0x35f7e618, 0x4fc4b569, - 0xc5bf7473, 0xdda97f02, 0xfafefb0b, 0x3f1ce1e5, 0xcf3edb31, 0x7af6694b, - 0x035c69bb, 0xe6fdfd0f, 0xf9f48bef, 0x0b890df4, 0xedb6a5ea, 0xf639c30b, - 0x8e32e8a4, 0xb4a64960, 0x6cfb3ee3, 0xaa917c47, 0x6dc2dbeb, 0xea5ba1d0, - 0x8fd78c1b, 0xef5e06ed, 0x2ff9a148, 0x5ea5e3d6, 0xfab848b6, 0xe37c959e, - 0x052d7ce5, 0xc005d5e7, 0x2c5ce71d, 0xef2173e5, 0x7919bc49, 0xf0a15f03, - 0x82f1f15d, 0x9f95d814, 0xc7f694c8, 0x8f2c7c50, 0xe513de1a, 0xd4cf5c06, - 0xdc00ca1d, 0xa89d758d, 0x68e97af3, 0xafbfb4eb, 0x8c6877cf, 0x30477c8f, - 0x1d6fd77d, 0x20248872, 0xd5ab6e71, 0x5bd42583, 0xbf43f7fd, 0x36aadfa8, - 0x3b9704f9, 0x91739780, 0xbd41dffb, 0x0b621b05, 0xed180fa0, 0xf22fae17, - 0x7bcd0796, 0x5e3356e0, 0xf3993506, 0xf3997783, 0x0d06715b, 0xe5dbe7fb, - 0x21f9cc07, 0x93f9cc87, 0x3371dc1f, 0xea854fb6, 0xbe855fbb, 0x87f1e7f3, - 0x7a9f4e70, 0xe06895f9, 0xcb5ff16b, 0x0b8f420f, 0x3c21678d, 0x7c73d02a, - 0x97a6145b, 0xba5ae22b, 0xdc4643e1, 0x30627606, 0xdf0a54dd, 0x95da6b41, - 0xa68acff5, 0x6744bd9b, 0xcfdecb55, 0xecb37a90, 0x5ad36477, 0xd0cee43b, - 0x3be3bb71, 0xc6ebd222, 0x21192a3e, 0x365eaecb, 0xfe8a7c4e, 0x1e37bcd6, - 0x2bf258f4, 0x929be585, 0x075fb297, 0x3edd1cdd, 0x6f4e46fb, 0x30f0c09e, - 0x9b0b92ec, 0xe5144095, 0x8744235d, 0x8bf11f7f, 0xf1210da5, 0xe2426b9f, - 0xcb99d682, 0xf7daee17, 0x504710ff, 0xe38278e1, 0x678cae2e, 0x5e801ff4, - 0xb04a7959, 0xa9f2aa7d, 0xe5ccc26f, 0xf5f35d72, 0xade71875, 0xf1cb5df0, - 0xaacb577b, 0xa3fe38e2, 0x4ba8e973, 0xcb73853b, 0x5eaf7738, 0xf29551b7, - 0xfd84b7bc, 0x8e7691c8, 0x8876ac8b, 0xebcd0440, 0xebdd9450, 0xd697efa2, - 0xb2bcb147, 0xe85ce480, 0x270a948b, 0x627a4dc7, 0xbbc4eed0, 0xd565cb2a, - 0xd51e12f1, 0xb0fc51bf, 0xa8c3571d, 0x3293fc8b, 0xd80448bf, 0xf23a0bbe, - 0xf803ad06, 0x468bce0b, 0x59565fa9, 0x9f00fb03, 0xab68738e, 0xad155eb9, - 0xc838a3f3, 0x35efe67b, 0xd7eb8da2, 0x2c26faee, 0x3d907bf8, 0x435ef59a, - 0xf97556ff, 0x3865fd4a, 0x20744fcb, 0x6cbe8384, 0xeebedcba, 0x6823921e, - 0x7b0d2b7d, 0xdf295af8, 0x9e51b2dd, 0x679f2463, 0xd6eb4e01, 0xef867c92, - 0xce206fa4, 0xf70a2c44, 0xea5ef94b, 0x6766eb0b, 0xf2f45cb1, 0x400a5e3f, - 0x487b691f, 0xbad2bb61, 0xbaefd97c, 0x3973fafb, 0xe3c2a7f8, 0xb61cb184, - 0xde518a6e, 0x4f91f587, 0xc864c530, 0x1ef7faf9, 0x4bdefe6e, 0x3ec166f5, - 0xb2741e22, 0xfb90c47d, 0x2ebeb90d, 0x1ac9cb56, 0x75feb9d6, 0xf0516db1, - 0xf88a89bb, 0x6cb725ef, 0x36e3cfd6, 0x2afc3f5a, 0x83e295c7, 0xf5198ff0, - 0x73c96646, 0xef58f865, 0xfb1ebd16, 0x532dca5f, 0xe68ebdee, 0xc5b0fe55, - 0x81a17b0d, 0x66f5e107, 0xd7c70e01, 0x77400b3a, 0x7b4ac7c3, 0xc97c91d9, - 0x0a8623e7, 0xab1a378e, 0xcb363bf7, 0xc2934a62, 0x9fa91e89, 0x1ed245e3, - 0x98b4351f, 0x132496ed, 0x6e2aebcc, 0x4fdeb265, 0xf7f8bdb9, 0x4f98bba3, - 0x4a145d07, 0x6df8fbf9, 0x2f3926ca, 0x0e27c72f, 0xf6c9c07f, 0x39fae3ce, - 0xe881e064, 0x0fcb1868, 0x0d8b5f3a, 0xa0b59ba1, 0xa0879c07, 0x6e982507, - 0x8b7174cc, 0xee2be122, 0xbaf7f293, 0xe8379958, 0xf13ff482, 0x229ba0bf, - 0x4eeff0c1, 0xdbd6340f, 0x74481e9d, 0xd07408b0, 0x0e842f51, 0xec3fd584, - 0xa542fcdb, 0x2b876223, 0xab148284, 0x17ce21f0, 0xebc32467, 0xb11fab1e, - 0x12adbd78, 0x92ac7d2f, 0xf1b4e8ee, 0x7d701785, 0x4b7de22f, 0xbc285c1e, - 0x4524bf54, 0x1fad7db0, 0x713155c9, 0x45204edc, 0xbb0a8e58, 0x5f68a513, - 0x2ffb2312, 0xfe3829e9, 0x5af3fa8e, 0x36e674e2, 0xc15efe1c, 0x47da0572, - 0x9f7b7017, 0x5af7b645, 0x219bed29, 0x95b698f5, 0x5cbf1c61, 0x2c9f7772, - 0xb1c4c9d0, 0xa2393a66, 0xde9195d3, 0x8dd6ed94, 0xf0249e75, 0xfe86d283, - 0x3bd4de7c, 0x0277ab8b, 0xb047cf9f, 0xeab259fc, 0x618693c7, 0x7bc42f7e, - 0x9333c280, 0xa83fb3b7, 0x4ff661b4, 0xb4be843e, 0x2bdfc9d5, 0x59f5b5b2, - 0xf715ff90, 0xa1f49ddc, 0x7b01c674, 0x9ad7b512, 0x957f9ca6, 0xedbec9d2, - 0x989e40ef, 0xfae55d3c, 0x3fb48593, 0xce39068b, 0xd6e7df24, 0xd26fea24, - 0x69c38528, 0xa95d3a8e, 0xa40fc1b7, 0x2ca9f7e3, 0xe47f9745, 0x5592813d, - 0x73d2b27d, 0xc9213fe1, 0xfd390bb8, 0x18fea353, 0xa5e40365, 0xfee4e3be, - 0x1fa3ea33, 0x4b3a7bf4, 0xd5bf55ca, 0x09e462e1, 0x7cbf5cae, 0x8cd1d875, - 0x40b6a468, 0xfde9a536, 0x7584bec7, 0xe3174c4e, 0x77ee03d7, 0xcf1362aa, - 0xf984adb7, 0x1b965442, 0x4291abf4, 0xd6e3facd, 0x8f27ccfe, 0x7a3b698e, - 0x6e8fe537, 0x8ced241e, 0xbe617dba, 0x707cb04b, 0x77e48c74, 0x98239b6d, - 0x5ab88ffe, 0x3da4e2a3, 0x650ded8e, 0xb67c493a, 0xf87efeac, 0xed22cbb9, - 0xcc7e7147, 0xc71a687f, 0x53ad9427, 0x07b86103, 0x6f6cc6b0, 0xded48aa8, - 0xb5087ec6, 0x07da841b, 0xa3a03340, 0xd30a35f2, 0x8f7adf61, 0x9cf9993d, - 0xcafac2e2, 0x70fd0323, 0x9c7b940e, 0x857cc71c, 0x826be0fd, 0xb9d870fb, - 0xb5890705, 0x009f6b67, 0x258d254e, 0xe446efac, 0xfabfcc6a, 0xec1704aa, - 0x26fe9d17, 0xbe0b5ec2, 0xc64d6d64, 0x9655fcbe, 0x3130f19b, 0xc91595ce, - 0xfbe4ed74, 0xae6d4711, 0xe8efcc2c, 0xe705a74a, 0x9215c4ed, 0x39df69be, - 0x1ee18f70, 0x3f0708ab, 0xfb259ad8, 0x5adcb39d, 0xbdf291bc, 0x151ac21d, - 0x67cafa07, 0x5fd85efa, 0x75e62dfb, 0x046217ea, 0x35b289e4, 0x74bce56b, - 0x96d610fa, 0xe71a78c2, 0x02b4e6d4, 0xe43a01d8, 0xdb63fedb, 0xba0ec701, - 0x3d30ae98, 0xc10e7ad0, 0xbfde9c8e, 0xe9ca32f4, 0xcbd03efb, 0x7e81b1c4, - 0x522f1b88, 0xb6be38ab, 0xe078493d, 0x6d176c77, 0x93b48f2c, 0x67be023c, - 0x9f8319f0, 0x1d785d10, 0xdef89d89, 0x22534752, 0xceb5be1e, 0x75b3e9c1, - 0x7825612e, 0xe24bab6f, 0x6e750bfc, 0x72ea9b4e, 0x758bfbf8, 0xa8efce1e, - 0x97f9c11b, 0xdf9cbceb, 0xd3813755, 0xf98aeb57, 0x08afc1bb, 0x0c97cc3e, - 0x27f063be, 0x3e0cbe83, 0x73574a15, 0x17b8cc09, 0x1f99ed41, 0xeb107c1a, - 0xf27414b0, 0xe9cf0327, 0x092fb14a, 0xceb450fc, 0x5228ff06, 0x0aff3dcf, - 0x22bdb9c1, 0xed22ed92, 0xf6c1f242, 0x079f0748, 0x0bb176a9, 0xdbfa89f6, - 0x0eef47bc, 0xad6f873a, 0x88358450, 0xc4bc7f8e, 0x7441ac29, 0xac596f3c, - 0xd9673f29, 0xa4f46ffb, 0xd18ddffe, 0x1e69b372, 0xe2797e47, 0xf7d13ff1, - 0x4cf2fcdf, 0xf34ef026, 0xc608fcd8, 0x9f5c2bbd, 0xd79cab47, 0x9796765d, - 0x7d4b86fa, 0xd4b86fab, 0x08e3f0b7, 0xa23dcf8a, 0x2d24a3e3, 0xb1a79df6, - 0x9baeec6f, 0xb44ec047, 0xfa4bde52, 0xf2a3f804, 0x2bf8e8bf, 0x70c6165d, - 0xf7d06d2d, 0x36dc706b, 0xb258f5c1, 0xf14ef960, 0xd7bf010a, 0x03d85fb1, - 0x63882b24, 0x40afc38a, 0x6be52276, 0xab98ec0e, 0xe411f77f, 0x21d96576, - 0x4735b396, 0x087fc724, 0x705ced9f, 0x83b2ca7f, 0xf6b44f5c, 0x466fc536, - 0xc1daf50c, 0xc0e34037, 0x7ece695f, 0x1a2efd81, 0x547fbe15, 0x5f2f7fae, - 0xa2e298ad, 0xf2ab6467, 0x959645de, 0x4259f3d3, 0xf91a473f, 0x96e832bc, - 0x61c708f8, 0xdbe63796, 0xe7f10417, 0x597bfd52, 0xa714c58e, 0x9d967f79, - 0xcd8f39fb, 0x9bdefd49, 0xcf9f6e93, 0xf7cdcffc, 0xa5fa8c05, 0x60ab0539, - 0x835d2e4f, 0xf6cea6a8, 0x7d56d925, 0x7fa92e5e, 0x8b5ce839, 0x2ea2f8e2, - 0x9e4307cf, 0x475f8539, 0xef59fcf2, 0xb9e17caa, 0xac8fe017, 0x9f1873fc, - 0x75839553, 0x7fae4afb, 0x839634f8, 0x70ca91bc, 0xff12e1c8, 0x35fdcf85, - 0xb55d711a, 0x97bda43b, 0x6b48a3d2, 0xfb60aaee, 0xf6878d5e, 0xadf81c49, - 0xfaffefd9, 0xfbe67f0b, 0x14b0849d, 0xe3986e3d, 0x7c766ad4, 0xb06bf1ca, - 0x7286f9c7, 0x1d5f1c7f, 0xf956beda, 0x4257f59a, 0x68a7c32c, 0x3c8997cf, - 0x12979d8f, 0xf76ae7c1, 0x2aec4cac, 0x1fb4288e, 0xb0c1ce23, 0x358ad5ff, - 0x59cfc39f, 0x9384d77b, 0xff65de92, 0xca1eeda1, 0x31384a8e, 0xeec62050, - 0x5893b62a, 0x2c9fc705, 0xed38edd5, 0x63f64cfe, 0xd7772777, 0x2446a7ae, - 0xdd5bb592, 0xbeb38831, 0xae84c428, 0xb649f4f0, 0xd3cf6b94, 0xfb3f823e, - 0xe59536e2, 0xa2db8bca, 0x6cd43f78, 0xe220f07b, 0x529e6b04, 0x2d58edd8, - 0xafce385a, 0x1c2a8766, 0xec1de7c1, 0xcfddf147, 0x5173f173, 0x8b5f404b, - 0x66ef149a, 0xc3bb4f9a, 0x6823d31d, 0xbe80af3e, 0x87173488, 0xff470d35, - 0x079ffcc6, 0x37920b7f, 0xc83f3517, 0xef548df1, 0xbf37cb02, 0x3c38e08d, - 0xc1dec93a, 0x186ecf3c, 0x45f5fec2, 0x586bdb4d, 0xe116d83e, 0x8ce9e982, - 0xe40f7ccd, 0x81de3e80, 0x9c8f296c, 0x67d1edd5, 0x1f59505f, 0x2fb13cc2, - 0xb871e8cf, 0xf537bb46, 0x4b666f76, 0x5b26a7f9, 0xfea34fee, 0xd1a3a6a2, - 0xc9fea8fd, 0xfa73ef5d, 0x166fbebe, 0x3df0b645, 0x223b93cf, 0xc9e09ef8, - 0xfe39ff1d, 0x7cef1a35, 0x250498d3, 0xc89d9f68, 0xba7dc9b6, 0xf32fc641, - 0x13d61725, 0x673d789a, 0xac28a5b7, 0xa4de032f, 0xf1dd9fb7, 0x3643df12, - 0x1c1febe4, 0xb14b382f, 0x18a3dc86, 0x8d72083d, 0xd7bf55a3, 0x63dba6d1, - 0xaffa6ffe, 0x5927bfd1, 0xe471f58a, 0xc4610d3d, 0xbd64b86f, 0x27b73522, - 0xc1dcddf6, 0x97b899ee, 0x7192de2d, 0xfbb7a297, 0x737fe811, 0xbb678ddf, - 0xbb9b52cb, 0x1c5ff227, 0xe0958526, 0xce887733, 0x875a9257, 0x347bbec1, - 0x8615ca4d, 0xb56aad3f, 0xbf04bc22, 0x3e67445e, 0xd0aafde4, 0x49c90760, - 0x563d7c67, 0x71daf161, 0x99d9463e, 0x3bb7ea2e, 0x75bec137, 0xec7c2ec4, - 0x29d17b7f, 0xd2e927fd, 0xf618f20f, 0x7155a517, 0xd878ac81, 0xa9ba74f1, - 0x41e54a9a, 0x29b553f4, 0xea390590, 0x2bda5d9c, 0xa9fd0e51, 0xabd640aa, - 0xfd14e9d7, 0x69a3dfa0, 0xf72c0bae, 0xd0128cee, 0x44af2c3f, 0xd3c8bb49, - 0x41614dce, 0x1cbf76e7, 0xc777118b, 0x66df4afe, 0x0bcc3f39, 0x7b22fcf2, - 0x5de41663, 0xd145dc63, 0x39de3c8d, 0xe145bc7d, 0xa39fd28d, 0x3ea211c7, - 0xec136f8f, 0x267b6a77, 0x33e6e58c, 0x632f2dc9, 0xf4cf33fc, 0xa387b8e7, - 0xbb05fe69, 0xf1c9dcb8, 0x86cf95e7, 0xd3df3005, 0x5db144cf, 0xca4db4eb, - 0x12a3a763, 0x143b1e59, 0xf65cf0f5, 0xa6153d63, 0x5a742ec0, 0x9424f611, - 0xf2c1ee6f, 0x32dd6540, 0x1254d7f6, 0x4b1c817b, 0x7fc804e9, 0x67f737a7, - 0x37e9d17b, 0x415cbe55, 0xbbe357df, 0xfee71a26, 0x0880f58c, 0x799e23b6, - 0x83fd6ff6, 0x5a463bfd, 0x3ed994f9, 0x5183d066, 0xf923945e, 0xd48e5160, - 0x71c86e53, 0xd11d5a71, 0xaf3a70f4, 0xc207f253, 0xb481eb03, 0xef61131f, - 0x3bb4d23f, 0x9c048951, 0x09ff5903, 0xfa956fb8, 0x366d99d6, 0xbe5553f6, - 0x3b65e512, 0xf157ddd4, 0x554ac97d, 0x1695e3ca, 0xf950df79, 0xffb656e5, - 0x2ce33fd4, 0xde083c00, 0x6db6dfac, 0xe471f556, 0xf4b7a7b8, 0x808d7e91, - 0x10797f9e, 0xc62635fb, 0x59537989, 0x0790dace, 0x2a7a5eb8, 0x69fee382, - 0x34e22f1c, 0x73f67f2a, 0x0598cf09, 0xc1d027ac, 0x4ab9fccd, 0x77d5cfe7, - 0xfb83135f, 0x955de210, 0xb25c79ef, 0xff827a7a, 0xd1ebc286, 0xbf3f9d1c, - 0x83f338fc, 0x8837da2a, 0xfbac5b0f, 0xab3f1713, 0x78b95cb0, 0x308f35d5, - 0x26c77ddf, 0x5ce22f70, 0xc1d183d3, 0x91cfa8f8, 0xbdb3b0fc, 0xa62feb87, - 0x5bfdb2fa, 0x2d9f3cd1, 0x13e60f36, 0xddefc78a, 0x07f559fe, 0x226cafb5, - 0xcaef22f9, 0x2d125ff5, 0xf833fd3f, 0xfb2736cb, 0x7cff0951, 0xadacea3f, - 0x7fd60169, 0xf32779f6, 0x72b1b39d, 0xf3a49fdf, 0xf98d97d4, 0xb66bf4dc, - 0x9a61fccb, 0xd0b439c0, 0x98d7ee6f, 0x9b1cead7, 0x4f78b7a4, 0xd544fc0c, - 0x47f40f84, 0xb711f9f8, 0xedc6d77f, 0x40b3d743, 0x4fb1d76f, 0xba608f9f, - 0xe24bdb39, 0xd90bece5, 0x8d1d9e7c, 0xf34ef495, 0x74de854d, 0xb8a65636, - 0xa87a0499, 0x387a4974, 0xed89a63b, 0xed956702, 0xc9b51e9c, 0x74cb9576, - 0x5fd13b7f, 0xb407e812, 0x63aabb09, 0x19e40b4d, 0x05e1f9f0, 0x4f70069c, - 0x0e8ed43b, 0xd7f9c53a, 0xe333efaa, 0xebf6051d, 0x89a79fb0, 0xba6bc7ef, - 0xedb5593c, 0xf0257f4a, 0x614db554, 0x197fda7f, 0x13acd0fd, 0xd1003f0c, - 0xc29f62e5, 0x6e2c22ef, 0xfb116db8, 0xbdac96d3, 0xac6f7415, 0x6f7eb163, - 0xf2a2a8fc, 0x693a8e7c, 0x395ee4ff, 0xdfdf019e, 0xef1d28e7, 0xf38cb875, - 0x3bf0f68b, 0x47496e39, 0xfea46d94, 0x35941aaa, 0xa19a4e3c, 0x19f5cae7, - 0xd8b02270, 0xaa3be761, 0x6eeed3df, 0xbb3cc6fd, 0x9d31cf9b, 0x934d1fcf, - 0xdedb93f7, 0x2fccf796, 0x26243d7d, 0x41e45bee, 0xf46061be, 0xd063b887, - 0x22f3f520, 0x35f61cf8, 0xcf34ebec, 0xff660dac, 0xe653ce4e, 0xe66d80fc, - 0x730eee7c, 0x9cd9af3e, 0xce6ebcf7, 0x0ee309ff, 0xf41384eb, 0x4235c46f, - 0xfd0a46ff, 0xf5261ddb, 0x7fa1e46f, 0x8dfe8523, 0x91bfd0ef, 0x3c8dfe87, - 0xa1e46ff4, 0xfe85237f, 0xfeeeef8d, 0xba554e12, 0xe07814bd, 0x4eddbab8, - 0xf7813e23, 0x89d9c5cb, 0x558547cc, 0x1717a5ea, 0xd8fcb2e5, 0xe29a6f61, - 0x11937b60, 0xad18958f, 0x1c47f785, 0x2ab2d280, 0xb1db8d39, 0x55f6ba1d, - 0x2aae8769, 0xeec24670, 0xe4f2bad1, 0xa73d882a, 0xd418b4a3, 0xdb6b68bf, - 0x2f56f802, 0xff7ec03b, 0x77eee5d6, 0x63f893af, 0x5f118bfb, 0x0f738255, - 0x25f49b7c, 0x71ee7719, 0x4353db04, 0x4d6244fd, 0xd3f21e50, 0xd43e733a, - 0xe6be042f, 0x46abed35, 0x6c6fc7c6, 0xfbe0c96d, 0xe0e33e9f, 0xea9f69fb, - 0xcb313bf6, 0x2198f2c1, 0x1bce23cf, 0x9f7a5970, 0x95e709b2, 0xc31c7fa7, - 0xa650fdb9, 0x68617ee9, 0x0879765a, 0xf91df3cb, 0xe3058a35, 0xbe5f4f94, - 0xcd6af58f, 0xedd2e7cb, 0xd7b2dcfa, 0xeef34c5b, 0xd1370fef, 0x71adc0d1, - 0x5ecc7e21, 0x7783faa6, 0x31f887a5, 0xa7ca9807, 0xbe6219ad, 0x8d7c5f8f, - 0xbdafbca9, 0xa1cf6e23, 0xfce4b9fb, 0xa5ceb25c, 0x6f5e02c8, 0xc554bd68, - 0x6ff827f3, 0x4e52dbc5, 0xc673a72d, 0x2bbfaf1b, 0x9d7f0052, 0x57e03277, - 0x858b64d1, 0x3f4cad9d, 0xf332c487, 0x15615cb9, 0x275c573e, 0x84b855dd, - 0x7fda9637, 0x654c6d69, 0x47e5fa3a, 0x68812aa9, 0x3c9680d1, 0xde8bafe8, - 0xe838727c, 0x98dd5aaa, 0x3bf2a2ea, 0x5c16ff14, 0xb7133f20, 0x9524713d, - 0x495aa927, 0xaa73c27f, 0x1cff702d, 0x19edd1f0, 0x7ca4ef02, 0x68a5e6ba, - 0xe9d41f8e, 0x0ae6d52f, 0x6c6c1d07, 0x814f5954, 0xeb8d4cfd, 0x8d8d93a4, - 0x6bd0e1f1, 0x3e28c62a, 0x5c06c7c8, 0x8508fa0c, 0xefefc907, 0x97bd69ba, - 0x94f7c90e, 0x752e758c, 0x41a2fac9, 0x07de37b6, 0x5c7bd630, 0x372b47d7, - 0x3b7591be, 0x7fd73f7d, 0x7e1b9e5f, 0xbc5dbadc, 0x6d96c5ee, 0x7d29925b, - 0x85dda1c7, 0x7b7d2d75, 0x1a48f45c, 0x326dcbe7, 0x75b3fdae, 0x23e13e4f, - 0xe3777a7e, 0x0fe87693, 0x9dbf5695, 0x6679cddf, 0x0ef11da3, 0xc8dd6fd7, - 0x2d6c17df, 0x71807b61, 0x1194eecf, 0xa3c3ad97, 0xc1b2ac62, 0xde3ceb45, - 0x1585ca5f, 0xa69e32e1, 0x46f51d48, 0x55b5d602, 0xa6bac7c9, 0xe3b76f17, - 0xf58781fd, 0xa6fba17a, 0xa2b4f0fd, 0x357bb01e, 0xd4c71c29, 0x11993edd, - 0x64fbcfe8, 0x4e34e5da, 0xc81e5fa7, 0x8287de7a, 0x239c2fb4, 0xf5fa21b9, - 0xf5da5561, 0x4ef9559a, 0x30903d98, 0x5ec2f20d, 0x35456ef9, 0x0a23439d, - 0x710bb7a0, 0xa3c5a535, 0xd79d1354, 0xf6984616, 0xb4112cc1, 0x9bbfa8af, - 0x7e532f45, 0x530cc4fa, 0x07d399fd, 0x0b9df886, 0x7f99cb3a, 0x8f7a6d5d, - 0x9f2efaa6, 0xc7bb615b, 0x4a77f358, 0xbb3a62ef, 0x5abed4d1, 0x47bd354c, - 0xf7a9e8b3, 0x6544ce18, 0x54e1c476, 0x6658f7e8, 0xeff54769, 0x169dfcad, - 0x7dafda62, 0x927f3c33, 0xfd8da5e7, 0x7d3d8609, 0xe8cf7e16, 0xef0cbcea, - 0xbc451788, 0x9a1dec30, 0x61691e59, 0x3c48553d, 0xa8f6eb54, 0x8f691cea, - 0xd8b5f6aa, 0xf04d8f11, 0x4810a6b7, 0xb6151a6a, 0x477d5237, 0xdfcc9c4a, - 0xcc3bef85, 0xdfd052f7, 0x521f9465, 0x42bfb04b, 0xdd686bcb, 0x606a1738, - 0xd83b6247, 0x076c9384, 0xfbd1c633, 0xf434e837, 0xfed0807d, 0x33700c06, - 0xbadcaeff, 0x822f60fd, 0xd8e2b4cf, 0x549dc47c, 0x95b14d35, 0x6f495ee4, - 0x54bfff06, 0x7ebf6161, 0x4c03e1fb, 0x5615ed6f, 0xff4b8c8f, 0x78d4b876, - 0x9435dda5, 0xbad0170e, 0xb05e7fe0, 0x15f8f143, 0xe9f00f59, 0x810cfa05, - 0x70174a4f, 0x01d5e033, 0x7e7290bf, 0xe2286e3f, 0x0a7be426, 0x1425c057, - 0x0b38fa9e, 0x2772c134, 0xf3cfcbcd, 0x8c57e90a, 0xb78fdd08, 0xb0ffd9db, - 0xe52e1141, 0xf531e1bb, 0xf4e3b4b2, 0x6feb90cd, 0x2078a9db, 0xd97cdfbf, - 0xe83bdfca, 0xd9c658a7, 0xde689f4f, 0x54f41daf, 0x8ccff72c, 0xeedc89cb, - 0xdf5745df, 0xff864f45, 0xdd7e3426, 0x19e647b8, 0x1ab7dfa0, 0xf37d8626, - 0x1be1c44f, 0xe77741f2, 0xe439c74c, 0x9910f1d2, 0xbcf9e5de, 0xe39d2a34, - 0xbedd35cc, 0x4d69f068, 0x5b8c676f, 0x78eee542, 0x7e6f7bd0, 0x43557167, - 0xfbf06a46, 0x1b4ada37, 0x975381db, 0xe25a73c7, 0x7ce22574, 0xdf2e5929, - 0x4f763969, 0x29f844cf, 0x25b4ad8e, 0x8faea44c, 0x553439dd, 0x88be420c, - 0x86d74fd3, 0xcfb60acd, 0x032de91b, 0x9c61f9e4, 0x872de7ef, 0x3f6167a3, - 0x8d19dcae, 0x2bc5a190, 0xa2ee1fdf, 0xa2d9be73, 0xfec01a2d, 0xce7c8de0, - 0x3cc6d70b, 0x390ce7d8, 0x516572a3, 0x5503c84f, 0x04f038ff, 0xb96d01e4, - 0xea72112d, 0x81540fe9, 0xe73a1ad0, 0xe538be58, 0x6a7df494, 0xabdf0473, - 0x2f08a53c, 0xd48b51fc, 0xd32e797d, 0x337cdb79, 0xd2708fc6, 0xae30c3b8, - 0xc6124b7f, 0x30b2f8f5, 0x333cb6ae, 0x8bbb2ba6, 0x97aed691, 0xc316dff2, - 0xa3dbacce, 0x0f23f721, 0x4b645fb9, 0xc8791fb9, 0xf72148fd, 0xfc0d7be3, - 0xd71bf00e, 0x6f43e5b7, 0x39158df5, 0x8e1cf84b, 0x7f5c81cc, 0x01ee12bb, - 0xf15dba3f, 0x8478e4f4, 0xf9e5620f, 0x2357821b, 0xb246dd1d, 0x5edd1059, - 0x8221d977, 0x88c6ebe3, 0x9c7e5358, 0xbf54d923, 0x2a6695c8, 0xbfa93ebf, - 0x7706fca9, 0x537f29be, 0xfd5348ce, 0xa6319e49, 0xdc468ffc, 0xc53faa60, - 0x9f94c53b, 0xa9b66136, 0x12e28cfe, 0x59ccf953, 0xb3e54c8b, 0xf94cdbb5, - 0x34ee2b5b, 0x92f1ffd5, 0xaf72a6e5, 0x0e715970, 0x231f4336, 0x3e85efb8, - 0x6fede946, 0xe3064667, 0x4b38d475, 0x350cef97, 0x56fa900d, 0x39f7ae74, - 0x09ee25d0, 0xe8fb0e81, 0xe2f680f7, 0xbf06199c, 0xfa914065, 0xe8324b70, - 0x685eb426, 0xfd88a8f9, 0x6594f097, 0x9f6ee7ff, 0x313e2561, 0x43fdaaea, - 0xfb7f2832, 0x5619e6c0, 0xaea32fe2, 0x3a52ffd9, 0xdcf17fe5, 0xf07cb237, - 0x57284bfe, 0xfccbf772, 0xc822c134, 0x9bce06af, 0x8c75a3e1, 0x8d7d2eba, - 0xba53da47, 0x5235538c, 0x9d7101c0, 0x00d20380, 0xfdd227d1, 0x5f489f44, - 0xb72cfa27, 0xe8907109, 0xd221e913, 0xf7fdf14b, 0x3d2297a4, 0xd2297a4c, - 0x452f4877, 0x297a42da, 0xcdd43fd2, 0x3a83f4e2, 0xb1fddb8d, 0x8fd382ae, - 0xf7f096ea, 0x7196ea4f, 0x1f3a97fa, 0x8064ff7f, 0xb0087f61, 0x8bf0c69d, - 0x091fc0d5, 0xdb2ede7b, 0xb1bf60b9, 0xabe795e2, 0x5facc7e1, 0xb0235a22, - 0xb1ad5b4f, 0xfe9d1c27, 0xadf9eec9, 0x92089c55, 0xdee19ccb, 0xf8f006cf, - 0xb7cc5dbd, 0xc447eff5, 0x84053eb4, 0xb5d34fa7, 0x3307e0b3, 0xc656ca0a, - 0xeeb8ff10, 0xd03625eb, 0xae9687cb, 0xd5efa3ef, 0x03a7dbf9, 0xf7e86dbd, - 0xa65dfd5a, 0xae321d6b, 0x6b6b5af0, 0xbfdbdb3d, 0x03c46e14, 0xefec33ed, - 0x5ef958f7, 0xe085f2b1, 0xc104e8fc, 0x5b2ffaf9, 0x5af10e38, 0xcf892797, - 0xc46f3d1d, 0xfdf87505, 0xef1413f1, 0x8de1f863, 0x2fc29f78, 0x3e41c75a, - 0x77691d18, 0x0dc48587, 0x2fbedfc0, 0xbcc68fea, 0xc3277df8, 0x97d4ffbf, - 0xf2f78022, 0xb5fe3f0c, 0xd834968e, 0xe1df4615, 0x33c704f0, 0xe57afe19, - 0xe715168b, 0x64af1189, 0x3bcc638c, 0x15fd4aca, 0x5d23c674, 0x47ca6aeb, - 0x757d465c, 0x93d7f724, 0x49dde3be, 0xb955e7aa, 0xec3e535d, 0x22aba3c7, - 0x8ce9423d, 0xafa9e813, 0x3af1ea9b, 0x38d0bf0b, 0x1eb4624e, 0x1c7e8127, - 0x01df9cb2, 0x48109d1c, 0xa39ffbc6, 0xb03dd897, 0xb88e3e83, 0xb8ce82b3, - 0x088fd405, 0x2798c7da, 0x15f7edfa, 0xbcf217cd, 0x9df0cbd7, 0x29f492e6, - 0x3f5e7adc, 0x2c6385af, 0x3d54bbdb, 0xfae61c5f, 0xcfd1046b, 0x90da19ad, - 0x1fdfd481, 0x7ccc8c94, 0x7a3217d6, 0x094fdf60, 0x0bb04779, 0xf03119fa, - 0xbc7e84ff, 0x05bdef12, 0xe942e1db, 0x418fc0c8, 0xbbde064f, 0x0e832ba3, - 0x18d0e282, 0x65711def, 0xf4a17f7a, 0x199d1dd6, 0x43ad75f4, 0x8cf001d2, - 0xae8320f8, 0xf89a2f94, 0x2ae8eb1e, 0x067f9f07, 0xc5d2855d, 0xe9257495, - 0x0e27feb4, 0xba4aefee, 0xc007a4ea, 0x55d387e5, 0xf8f38a8b, 0x79a7a59f, - 0xee3c626d, 0x765c97ff, 0xabda441f, 0x7c17b69f, 0x198c4ca6, 0x2e13120f, - 0x62ec1075, 0xba32f5a1, 0x7f4a17a9, 0xbc6eeda1, 0x6e465da2, 0xfa71bb70, - 0xaeda1959, 0x047aed12, 0x71c21bb7, 0xf7e96f11, 0x1a72de08, 0x999e2d71, - 0xb90e5390, 0x2f2df26d, 0x27cc8de1, 0xf3a719ba, 0x096243f3, 0xee24bf9f, - 0x854f40fa, 0xcb8d693a, 0x42fac85d, 0x71d76461, 0xedea3705, 0xdc5d7fc7, - 0x4f8cf980, 0x37e3cb30, 0xf5fcf2ea, 0x0ffb91a2, 0xc6e1477d, 0xce59ebdc, - 0x61477d0f, 0xfe3d40f3, 0x81a44d20, 0x8f0a17df, 0x0efe9f9c, 0xcfbea146, - 0xc9ba7453, 0x5462ab70, 0x6a9bee1c, 0xaf321c56, 0x3c8c1de3, 0xfce3eb8c, - 0xe9cfc20d, 0xfdc0224d, 0x0903a24c, 0x61091ff9, 0xc85fef93, 0xaa35bafb, - 0x5790dff6, 0x4fba7b8d, 0xb057b53b, 0x4c440fcf, 0x4a77839e, 0xd7190dc6, - 0x17f6ed0f, 0xdbce59ba, 0xb960c8ef, 0x16d2fb13, 0xde27c9d7, 0x5fba73a4, - 0x8a37bca6, 0xfb46f714, 0x3bfa79d1, 0xbf91c73a, 0x40b96731, 0x736ef1bb, - 0xfed193bc, 0x6138d726, 0x9cfeef8d, 0x776f29bc, 0xdecdd86f, 0x042ecd8a, - 0xbd8adf7e, 0x7deb10aa, 0x45a7b62b, 0x4e7661a6, 0xafd2bd07, 0xa0d8b92b, - 0xc6f1cefb, 0xc1dd78f3, 0x286b80d9, 0xff380d3c, 0xeb1eb800, 0x077bae0a, - 0xaa379608, 0xad5f2423, 0xd57c908e, 0x58757380, 0x9ede7dc7, 0x5527f1c1, - 0xf9af090e, 0x5611aecb, 0x2c17f512, 0x93f9c91b, 0xb807c275, 0x6092c69f, - 0xf7b10f10, 0xce58eb09, 0x9ddcef1b, 0xe8bdf87d, 0x2ae79a24, 0x983ff687, - 0x4082b9df, 0xe2844916, 0xbe7a86e4, 0x05fe7f8f, 0xaa7d03d5, 0xf1af754a, - 0x96facec0, 0x7d71ef2a, 0xfe15207d, 0xd754f158, 0x0e55e8f1, 0x9f435f09, - 0x98afd21c, 0x5fb1adf7, 0x80befe85, 0x0ef55f21, 0xc6dcf193, 0xe4eef73d, - 0x92e1e1ad, 0x930ef5af, 0xebc0d8fc, 0xee7ebb06, 0x89c33f53, 0x3afca68f, - 0x98abf59c, 0x2e4c6f58, 0xc28583ec, 0x76189fa4, 0xf904f695, 0x22b5ca7e, - 0x945191eb, 0x13643c2f, 0x076f2a7e, 0x92794043, 0x1fb6b3f4, 0xef82a4ba, - 0xfc294517, 0x6f71863e, 0x22c92c29, 0xc27c41dc, 0xbd370ee9, 0x13911b4b, - 0x7947ca67, 0xc7ea997a, 0x9537488c, 0x98077ac7, 0x1427e3ca, 0x8a3df298, - 0xefd536af, 0x29ac6b39, 0x68ddac9f, 0x31529faa, 0xf83794d5, 0x24fc8a58, - 0xc5b92cfa, 0xb2efbed4, 0x34fd5352, 0x5ca9a55f, 0x319b3bc5, 0x25b7ab40, - 0x81cf1127, 0xd58c9fca, 0xe3de434b, 0xf0cb08b5, 0xfe6b77ce, 0xcbde5a33, - 0x80b91099, 0x6cc9afdf, 0x9e7999fc, 0x2c6b44ea, 0xcdbbd7a5, 0xc928b17c, - 0xb9171f9c, 0x71df814f, 0x9fcccb9c, 0x4d589653, 0xeae51ff9, 0xe44f34fc, - 0xbbe3ddb1, 0x300daff0, 0x4e143fe1, 0x7efc0f44, 0xef9d3b68, 0xcdebcc3e, - 0x070f7e32, 0x75e0937e, 0x0c126fc0, 0x824df807, 0x049bf0f3, 0x24df87d7, - 0x937e1cb8, 0x8721f2e0, 0xd61ff8cc, 0x55ffc662, 0x6ff1991f, 0x787765d0, - 0xa66ad91a, 0x9a29a10f, 0xba782df2, 0x7e9994e6, 0x1d73f142, 0x09b15b89, - 0x09e287c0, 0xbe387fb8, 0x8be08656, 0x37f7c3f0, 0x31477bdb, 0xd7d71e7e, - 0x20606d75, 0x3a2e97df, 0x6fbc0aa4, 0x71f3ac63, 0x6d3fdcfd, 0x89731ad5, - 0x5dcefccf, 0x763e0490, 0xdb7e909d, 0x4f1655f1, 0x207fba80, 0x29d99c64, - 0x3fa843da, 0xaa52fe2b, 0x26d2741d, 0x0e7bcfdf, 0x95d8797c, 0x123eb2f1, - 0xf6bef84f, 0x27be54cf, 0xa8d2c475, 0x8eaf8f80, 0x9f009ed1, 0x84bb9799, - 0x8a249bd7, 0x5c402fb7, 0xa5857fd4, 0xafb73f22, 0x722dc7bc, 0x89fef95b, - 0xa6e727c1, 0x2da9b8c8, 0xdd7fbab9, 0x9ea7e323, 0x777295c9, 0x71c5c794, - 0xf2b925de, 0x8ba90d7e, 0x010773a9, 0xd99d873e, 0x0b3acf80, 0x8ad9ebbf, - 0x9d09e47b, 0x0f21c8f7, 0xa3ecfe43, 0x1ff57fcb, 0x47581c3b, 0x3a617af6, - 0x1dfbfb7f, 0x81e2f8a6, 0xfca65d5b, 0x5324a6a0, 0xdcbbc1fd, 0x40fcf2a6, - 0xc87ca98e, 0x3f298f21, 0xa98465ac, 0x791f55fe, 0xad91f94d, 0xaff54c13, - 0xca6c5539, 0x47b688a7, 0x8abedf01, 0xcd1c53b4, 0xb9fa974d, 0xe4dc705b, - 0xe563bbdc, 0x7edd5f7d, 0x46fbc861, 0xd3a6b9dc, 0xd11ea875, 0xe8e52ed7, - 0xf52164fa, 0x1fae8746, 0xa13eb30a, 0x1de371e9, 0xe67c58f7, 0x5e2371b8, - 0xd0ef43bc, 0x7b8e8af5, 0xe2f19d34, 0xf178e0de, 0xbf5d61b9, 0xc75e7d1f, - 0xfbfce87b, 0xeb7ae5da, 0xbdf3b4ef, 0xa15e631d, 0x96c949f3, 0xd1d9bb74, - 0xbfaabdf5, 0x46fb4ae5, 0x25f1666b, 0x3613fdd0, 0x6dff2b4f, 0xf3c62b84, - 0xb75e22b4, 0xcf7617fe, 0x8f77f70a, 0x5cb07737, 0x658b1ccf, 0x8e5c94de, - 0xddfd338b, 0x92418884, 0x7583adbe, 0x78c84afb, 0xdc646373, 0xbbb1889a, - 0x8fddbf41, 0x6499e127, 0xff7c0d17, 0xf167bf4b, 0xf74d35e3, 0xbd8e68a1, - 0xce3f7f51, 0x4c3d036f, 0x59f24b1c, 0x5b13c93e, 0x49143d7a, 0xcb13ca72, - 0x8a9f6cac, 0x3757fe7b, 0xde75fafb, 0xfa4be99f, 0xb203e810, 0x07a8f40e, - 0xb72954f2, 0x2beb920c, 0xb8eebf52, 0x187ec0e7, 0x43f3f421, 0x174fbc70, - 0x6874c6f4, 0x75dfe3ac, 0xdba0c1ef, 0xfa193850, 0x3be3d0af, 0xd2f319fb, - 0x07ec67e1, 0xfdc67e03, 0xb66df713, 0x7c914de2, 0xe202658f, 0x6dfc0ce5, - 0xc6f693c9, 0x503c3a05, 0xbba8fc0f, 0x6e6a457a, 0xedf7ec0c, 0xeae31dc2, - 0xea3b0e82, 0x62e09bff, 0xfbbbbfc0, 0x87f1dd6d, 0x5df0be50, 0xa3baddf7, - 0xdef67fd3, 0x909f105b, 0x5e3a4bf1, 0x1c2cfdfc, 0x94777017, 0x323f3f79, - 0x9189f248, 0xe4fdf483, 0xccd6fd23, 0x0ffc042f, 0x9d552bf5, 0xbcf3c85f, - 0xdf98ad24, 0x8af9c6af, 0x37f35bfb, 0x8847f94a, 0x87abc4e2, 0xe36f8fc2, - 0x7ad7cbfb, 0x4a6ddb05, 0xde3f151b, 0x75f12af9, 0x9fb30fad, 0x0772cdcf, - 0x26c83bbf, 0x46576a4d, 0x5da5f6ed, 0xc2facef9, 0x60eef948, 0x0beafbe8, - 0x2f19bd75, 0x86df606a, 0x19eebdfa, 0x3cb1fba4, 0x9cf2c3c2, 0xa150d71e, - 0x37a0e9d7, 0x0e6f7cbf, 0x31f6327a, 0x671f1ca5, 0x3f0dcdc0, 0x3cce90d4, - 0x073c37c1, 0xb58379e7, 0x0ec5f8cb, 0xab7e1af8, 0x61ecbf0e, 0x1a1127be, - 0x77ce718f, 0x3f2bba20, 0xeb1fe198, 0xf8741f6e, 0xefc3bec7, 0x89691ed6, - 0x69f1dfc6, 0x67df26df, 0xfd5bf4e9, 0x22cbb865, 0xf03153fd, 0xfdeab53f, - 0x5d798d89, 0x96d50fdd, 0x9438e4ef, 0x73b68b66, 0x2cefad10, 0x7b778ff5, - 0x9fdc89ef, 0x26117788, 0x2ba976ea, 0xcdcbadd7, 0x8fe914a3, 0xef8ca9f6, - 0x5ef209f6, 0x8151f13d, 0x4fc4677d, 0x0481114c, 0x4a1f86a4, 0xe1923d5b, - 0x4aa1f86f, 0x9e792302, 0xda17ea33, 0xeb68e4f0, 0x851577a3, 0x53fd3bbb, - 0x5c647dad, 0xaa7e7754, 0xb9f39769, 0xaf97e9bf, 0x183e7ee1, 0xb6e52694, - 0x036efb86, 0x2ad80d9d, 0xab67586c, 0x4bbfebad, 0xabf3a851, 0x3d9ae812, - 0x96ade282, 0x962fbc2b, 0xbf88c22a, 0xe46f3e62, 0xf9ea352f, 0x7dbf9922, - 0xeab7cca5, 0xd16da7ef, 0x275820ed, 0x7a07ac52, 0x4edd36f9, 0xc5207582, - 0x7c1df03a, 0x35f0790d, 0x90d7c1e4, 0x0a435f07, 0xa5ef86be, 0x761538a2, - 0x0ad3f85b, 0xfc07f683, 0x72418569, 0xc169fc13, 0x82d3f879, 0x169fc3eb, - 0x5a7f0e5c, 0x69fc3970, 0xd3f879c1, 0x9fc3eb82, 0x3f879c16, 0xfc3eb82d, - 0xf879c169, 0xc3eb82d3, 0x0e5c169f, 0x39705a7f, 0x79c169fc, 0xeb82d3f8, - 0x5c169fc3, 0x62996f3e, 0xd3cdb7f2, 0x5b287fdf, 0x51f4cf1f, 0x9b1c5198, - 0xeffdf847, 0xc4fc7f88, 0x373c0e96, 0x2edd022f, 0x48f70ead, 0x904e373c, - 0x8908b778, 0x8cd9b6e7, 0x32ecbbe7, 0xb4e3245f, 0x7e07e943, 0xf49b42ab, - 0xdf85215b, 0x56fc290a, 0x2ab7e148, 0x2b7e94cc, 0xe15bf0a4, 0x4856fc3b, - 0x0a42b7e1, 0xf85215bf, 0x6fc290ad, 0x2b7e1485, 0x0adf83b4, 0xf856fc29, - 0x5215bf0e, 0xfdf0adf8, 0xfe03cd08, 0x905e632b, 0xf499fbf3, 0x9343a252, - 0xe532ea5e, 0xd707e721, 0x5c1f9c87, 0xb83f390e, 0x707e721c, 0x707e721e, - 0xc1f9c87d, 0xdc8349f9, 0xef20bfbc, 0xbc83b707, 0xd41f9c1f, 0xb6037be8, - 0x2e1b49ab, 0x35b48ebc, 0x7142794a, 0x2f353109, 0x8bfc2673, 0x35254ead, - 0x6d8423d6, 0x859980f9, 0x38f4d794, 0x66d13cc7, 0xae39be01, 0x05a6f080, - 0x0f65c704, 0x5cc97ffa, 0xf9b3f86e, 0xbf9ef087, 0x50deb043, 0x35afdfa3, - 0x4b847bda, 0xefd46a45, 0x2f5d77cc, 0x1ea37c74, 0x79a0cbf3, 0x8f996290, - 0xbbfc9378, 0xaf700b22, 0x91458b60, 0x642bb8f1, 0x5d28743c, 0xe793caad, - 0xf6cb16fb, 0x5388e1fd, 0xb83c5129, 0x156591ef, 0x80056c87, 0x7e0292d3, - 0x562f2af7, 0xab92d75f, 0xcc658711, 0x124bb0db, 0x867be09f, 0xbd84daa3, - 0xfd19c69c, 0xefe3b085, 0x4bb44c73, 0xa0ed0279, 0x29f40e6f, 0xf4414dde, - 0x9e4f2cbd, 0xb6ef9a7b, 0xfbe9cbab, 0xae4b6dc0, 0x89c5fdc6, 0xd3ddb2e1, - 0x386689bf, 0xf8506e4e, 0x6da8ce9e, 0xc9fb8bc2, 0x3a7e75cb, 0x5ecb9b70, - 0xf8bae3ce, 0x6fd1a3de, 0xbe5486c9, 0x5a2259a7, 0x450f710b, 0x3df8550c, - 0xb46e037c, 0xbeb1d7be, 0xb02ada2c, 0xfbe0ff2f, 0x7e2e244f, 0xa34ffb9f, - 0x2116c687, 0xcb3450ae, 0x0d2742f7, 0x83d9592d, 0xe5f9a5e6, 0xbfa3a17b, - 0xe706f258, 0x85ef929f, 0xe70cf932, 0x9879f1f9, 0xfdf853ed, 0x8dbec995, - 0xee370496, 0x25b72f65, 0xe136fea2, 0xf5055881, 0x8d8af708, 0x168ae575, - 0xbd01538b, 0x41f10388, 0x639c47f4, 0xdf25e83a, 0x59f7e363, 0x365d58a6, - 0xce431bf0, 0xb1c97129, 0x3151d48b, 0x4432cf7c, 0xd0d4b84e, 0x7e62e383, - 0x3b4e9c78, 0xba5fe7df, 0x8572c9d3, 0xbe615eb6, 0xc65f3e79, 0xf6dd56bb, - 0x7a4b70e1, 0x99ce9c67, 0xbc16ff34, 0x7d267b03, 0x8508f47b, 0x79bd88e5, - 0x0da3d704, 0xcd3df12f, 0xf06f9592, 0x0d4b943d, 0xfbcb450f, 0x52ffd26c, - 0xb0cdc3ae, 0xf1d7cd3b, 0x69c7ae53, 0xef93ab1d, 0xcc39d33a, 0x6a5caeef, - 0x119cb1b0, 0xf21a2f2a, 0x911ef1a7, 0xc23fae10, 0x60d153ce, 0x0bc03be3, - 0x4aac94d7, 0x91ca5712, 0x7339758b, 0xe38d8351, 0xf7f42ab2, 0x6eff42d4, - 0x1e3d62cf, 0xf356f16b, 0x42f24ff7, 0x7de350e4, 0xc94ebd4d, 0xb06607db, - 0xc6c4b43c, 0xcb39cdfe, 0xb6247ca5, 0x93ee3f0b, 0xce3e59cc, 0xe666f782, - 0x947af4ec, 0x5de9e82e, 0xd89a4e5d, 0x4ff864ea, 0xfcc11cb9, 0x14e5ea65, - 0x397cdfce, 0x9799d399, 0xee2adc65, 0x5a6e8122, 0x073be48b, 0xd1f2ebef, - 0xc6b1c40c, 0xc9eb3e43, 0xf44eddf4, 0x74f2218d, 0xabc035be, 0x3878801c, - 0x44ada6d1, 0x8dc4ec9c, 0x4d83ef82, 0xfd451c82, 0x155c82cf, 0x5691fd8f, - 0x2661f7c4, 0x68bf7c28, 0xf4dbd0d2, 0x43fb40fd, 0xf7e13f30, 0x29c2b457, - 0xcd39c47e, 0x805bb6d2, 0x685f637f, 0x5efca3be, 0x629f24ea, 0x9a923bc7, - 0x741b6fae, 0xe63fba1f, 0xb276e846, 0xeb076948, 0xb26193b0, 0xb7c92478, - 0xd3e4266a, 0xf66db0b9, 0x608109d2, 0xcb2b951f, 0xd576fc7b, 0x419206cc, - 0xc9fb55ff, 0xde458b1c, 0x9039233f, 0x96880bef, 0x2f949ea2, 0x4014a359, - 0xf5e6323f, 0x38ec67b9, 0x3a4eb0cf, 0xa7d8ed28, 0xd2e51ef2, 0x7e4d327b, - 0x8cb4d09b, 0x34fd8de0, 0x27f5a637, 0xf468610a, 0x1c2de160, 0x85ebf781, - 0x005428f1, 0xe8b798f1, 0x3bc1eaf9, 0x973ab4ff, 0x91f9c4e1, 0xa6687dbf, - 0xe05ff22f, 0x6b147393, 0x4b1bdff0, 0x0d5768b2, 0x50f7c1ee, 0x11bf03c7, - 0x9efc6db9, 0x4bb64a44, 0x7b10a9f2, 0x8960f54b, 0x4bbb50c7, 0x773cae59, - 0x7a9dd584, 0xdc7bfb2b, 0xd634b76c, 0xbe66cc7d, 0xf3a46be7, 0x5ee7eb07, - 0x9ee7bfdd, 0xf916c3ca, 0x1663c2fe, 0x8857f6ff, 0xd0f72f5e, 0x8fbd6066, - 0xe79ede21, 0x8cfaf1af, 0xf83a4cf7, 0x896efe95, 0x96474f41, 0x2afbe25d, - 0xb77691a5, 0xe54f441a, 0x0fbe15ab, 0xde4cba5a, 0x2b56d6e7, 0x6e845df2, - 0x99bf58ec, 0x9efcbffd, 0x117e6fd5, 0xf8750b2e, 0xbcb7b1ce, 0x84eb48e1, - 0x3d979fef, 0x347c9360, 0x0efb8990, 0xf2712cb7, 0x7b9fd9bb, 0x0f06ab8a, - 0x8c3c9e03, 0xe5d871a7, 0x8c4b7f54, 0x4bdf04b6, 0xd841cb45, 0xfcfee71d, - 0xba8f7e6d, 0xdf8d39b6, 0x95d92cbf, 0xd9ef0abf, 0x7ed1ee7c, 0x4497f582, - 0x4790ecba, 0xf9621a6a, 0x53db9e7c, 0xda2bcfbf, 0xe067cfd8, 0xd2c1bee7, - 0xbe7d778e, 0xaea2e71c, 0x6cc01157, 0xbaf54c53, 0xf61a63b6, 0x4b3b50d1, - 0xdf21bbe8, 0xdd815765, 0x5f641ec4, 0xb632ec35, 0x71b3639c, 0x77b1cfae, - 0xf73ef7fd, 0xf437f3ea, 0x7a1df9da, 0x9ef8ee6d, 0x2ad7ff90, 0xcbd3d82e, - 0x7133dd23, 0x90fca1bf, 0x62b4910d, 0xbe5b9c62, 0x7c8f731f, 0x8ef4a63f, - 0x7367e67c, 0xdc029380, 0xfbc9193b, 0xe94fdcb8, 0xfbf7ee90, 0xf40f6bad, - 0x0a7a0dd9, 0x821df978, 0x1ed79772, 0x951f2417, 0x77a62a35, 0x0bfc8c24, - 0x97c95583, 0xfc00dd48, 0x9a477c7e, 0xcd396f1d, 0xf1093121, 0x27417b99, - 0x51db3ac3, 0x993f8e3d, 0xca0e2e98, 0xfe14bdf7, 0x2f18e4bb, 0x955beff8, - 0xc3df9a36, 0xdf2cfaa0, 0xc51c1aed, 0x68b895fd, 0x5d4869dd, 0x03824f3c, - 0x3eeda9c3, 0xe3cdcfea, 0x02ca3e30, 0x07ec1b7e, 0x42f71073, 0x7e5c5bf9, - 0x6d29c61b, 0x68d4ef90, 0xda38e46b, 0x20fb58ea, 0x975607c8, 0x5cb04fbd, - 0xbddf20d8, 0xddffa39e, 0xcb2f9a11, 0x2704e5cd, 0xee33b3dc, 0xabc286dd, - 0x797f9f44, 0xce59ac63, 0x036b5c6c, 0xf377667e, 0xdd39c65e, 0x30da5d0e, - 0x2837df86, 0xbef97ab7, 0xfbc3a68a, 0xf79cdbb3, 0x7b325fc2, 0x34b623dd, - 0xb065ffca, 0xe9cf6b94, 0x7a6271fb, 0xa9df9320, 0xf1c9cdba, 0x8d5db3e3, - 0x780edebc, 0x81f0443f, 0x662ae2dc, 0xf89d1378, 0xbe596f10, 0xcedf8cce, - 0x77c944f9, 0xf095d7fc, 0xd5605bfe, 0x79e0aeec, 0x8997dfac, 0xb4d9a1f8, - 0x970ef1ef, 0x1f7c6970, 0x3343c4f6, 0x6205eff9, 0xe6cf1c9e, 0xbbc78f71, - 0x4c374453, 0x18fd06d7, 0xf18df3f7, 0xb4ab1eac, 0x6bbe7bc7, 0x420f7a9f, - 0x7c27af4e, 0xddd00fc3, 0x02e3b53e, 0x2f6b8d26, 0x5e07ef97, 0xfdf4efc1, - 0x6a01fffa, 0x00d36c91, 0x0000d36c, 0x00088b1f, 0x00000000, 0x7dedff00, - 0x65555c7b, 0xd6bbf0ba, 0xc0d857da, 0x51b08b66, 0x62020dc0, 0x10106d11, - 0x80a17515, 0x636a735b, 0x8dc42937, 0x910150b7, 0xf39fa8ac, 0xa96f0db1, - 0x962a2695, 0x8da6b675, 0xb2707595, 0xd99b1b46, 0x0f5d9a6a, 0x39d38d3a, - 0x32cdb653, 0x34d209bb, 0x99d37d9f, 0xde79e7be, 0x0daf60b5, 0xf9a675a4, - 0x3efcefce, 0x7df5e3fc, 0xee7d7bd7, 0x765ef3cf, 0xb24c6322, 0x98783631, - 0x8c81b183, 0x45931819, 0x77a13fc8, 0x6302edfb, 0xbeac7195, 0x28d2132d, - 0x0b6bff56, 0xdfe3df63, 0xa2749ef8, 0x8f2c6453, 0x5da0dbb1, 0x10af7c1b, - 0xd6ccabd9, 0x29d33df3, 0x148af7d0, 0xd41dd336, 0x7ec3fb1e, 0x13efd5e3, - 0x338b69fc, 0xe3abea7b, 0xbb78d856, 0x9a7ed0a9, 0xdd8beb05, 0x3ea81bf5, - 0x26e9b3cf, 0x3632c591, 0x87ff04db, 0x7b4894a5, 0x32e6c456, 0x7057b0d6, - 0xe1a8a11a, 0x18b18941, 0xf08b9f48, 0xbec664b1, 0x3bcdf868, 0xcfbd40b7, - 0x64af6f37, 0x35e67b43, 0x398a3fc7, 0xf7363046, 0x0c733652, 0xa5de6c60, - 0x0f569431, 0x073864f3, 0xf8dbd506, 0xc607ba5c, 0xfb2dadbf, 0x5a307fdc, - 0x30e59fb7, 0xbf73fef6, 0xe868e3fd, 0xde9f3197, 0x3acf4d7d, 0xa13ead66, - 0xc304b2af, 0x4d73af8d, 0x83155746, 0x18b6ce79, 0xcd14121c, 0x64c55e5e, - 0x33b32798, 0x13e41a67, 0x422bcc75, 0x16fd6cbf, 0xf3eb04d9, 0xb557fe30, - 0x5da9905c, 0x824fbe63, 0x7a860cf5, 0xdf5e1cc6, 0x58f7f00c, 0x4884670c, - 0x912de8a8, 0xcdbc1903, 0xf83d29f7, 0x21a90c1d, 0x89ef07a7, 0x5ecc1d0a, - 0x7b6d0657, 0x330305f0, 0x65eb0f96, 0xfceaae1c, 0xbff32aa7, 0xfb20bd6d, - 0x4e0ddea0, 0x2757cf07, 0x7ac1e61b, 0x364face7, 0x5cb486cc, 0x473e5ef9, - 0x2f8dde5b, 0xccaf8aab, 0x4f587695, 0x57c71b57, 0xe13d3ad7, 0x2f4f6bab, - 0xa931257c, 0x00771e67, 0x8e00d8be, 0xe382362f, 0x57c0530b, 0xa82f33a5, - 0x7c70bfde, 0xedfe7ecd, 0xd0765e0f, 0xceffa8fa, 0x1dbe8d07, 0xb6acffd0, - 0xf2b784bd, 0xc9f41bd5, 0x99ceaf50, 0xdb51704c, 0xb6cfaecf, 0x6de78032, - 0x1debb7ab, 0xe8eefc16, 0x9521ee93, 0x413f1059, 0x6790099e, 0x3bbc40ba, - 0x397ea7a2, 0x9c617ba4, 0x91cd8b25, 0x719edaec, 0x3cf428b6, 0x86da3ebb, - 0xafaecde3, 0x7165887a, 0xf66777fa, 0x66b3bfe6, 0xa0b317ce, 0xb3cfe43f, - 0xe424ce45, 0xd4510a8b, 0x3e9a9bf0, 0x79837884, 0x35e0063d, 0xdbc3fe23, - 0x0c38469e, 0x6ce6145e, 0xa9a94f86, 0x8b8e1f01, 0x36f38cf4, 0x826bcc88, - 0x8135a97a, 0x548f388b, 0x876c28a0, 0x528d8469, 0x1df90b16, 0x4802ed30, - 0xee9e2453, 0xc3f5f273, 0x677e3f77, 0x5c3c8131, 0xa1cf4abf, 0x3b606af4, - 0xfe00a757, 0xd9cc310d, 0x4fa1e8ec, 0x3e951fb5, 0x6fedfa55, 0x70ae7b7d, - 0x3993677d, 0x3386593c, 0x56e304c9, 0xb9cc3c3e, 0x3afcb846, 0x0f00610d, - 0x817ad05b, 0x7d6c0b58, 0x903537ac, 0x0fcd7657, 0x24a5b7ad, 0x86f58fb6, - 0x93e553ae, 0xc3ce2639, 0x015127c0, 0xfad77798, 0xf10c51a1, 0xca2f302d, - 0xcd8bb39d, 0x5d5bce22, 0x504d53d7, 0xbbb6e619, 0x33e944c9, 0xc368c04d, - 0x764d3e00, 0xe4df3fca, 0x29adb4a0, 0x9ddbca83, 0x633f9a36, 0x80698881, - 0x85308aa7, 0x8f3cfdff, 0xe54165e5, 0xee9c6d53, 0x11035b4e, 0xfd3920b6, - 0x0d79bd71, 0x0efa428b, 0xccfc883c, 0x5db2871a, 0xf5e9d430, 0x4cc42367, - 0x3f3e4fa4, 0x7d12ddb5, 0x163fc927, 0x02ec7061, 0x24b19b96, 0xe02374fb, - 0x38f2ee6b, 0x9b129027, 0xe49438d1, 0xb46f0cc2, 0x7eb00093, 0xcc78430b, - 0xf860e453, 0x2395aa92, 0xb26b7eb1, 0xe6718055, 0x5ae79c5a, 0xced5fda9, - 0x4b7bf1fb, 0x93252199, 0x9026caaa, 0x72287763, 0xdcc0896c, 0xa07787c8, - 0x12fe449c, 0xfea2a50f, 0xf055a3b9, 0x56cf291b, 0x21d7000b, 0x78d2eecd, - 0x055b1394, 0xbb6c0ee7, 0xa9a9e40d, 0x0d769e47, 0x7a817f73, 0xf4077d81, - 0x255ffd07, 0x5d710220, 0xca1c726d, 0x75824df1, 0xb979c317, 0x059f080d, - 0x6e9c9d0a, 0xc8e11339, 0xa3eb81ec, 0x65105ff8, 0x288b23cc, 0x3d141b6f, - 0x79406486, 0x310e4e45, 0xca41f870, 0x3a3f11da, 0xa0e909a7, 0xc51292cb, - 0x886f28fa, 0xf2c38948, 0xc912ad39, 0xaa9e9545, 0x7c2835d5, 0xa3be1733, - 0x2a912bde, 0x56be9162, 0x74a44cb6, 0xcd9286ce, 0x24e3a05e, 0x9a3b1dc1, - 0xb867a3d6, 0x13b5399e, 0x55bc47af, 0x9b4630ef, 0x7a496f00, 0x104e526f, - 0xbed9ce3f, 0xbb41892a, 0xd3cddbf3, 0x5b17fe51, 0xa1a38acb, 0xd16dbcfd, - 0x1e9052d9, 0x7ae6ca49, 0xc4ed4164, 0xacf00638, 0x2791fbf9, 0xe78fa0ac, - 0xe8569f42, 0x70b69bff, 0xd4aa179f, 0x924fed34, 0x31dee780, 0xa1b3e279, - 0xe0f142fe, 0x1f50a32d, 0xe2a7be08, 0xce23bea9, 0x503c87da, 0x0fc073d3, - 0xdaf7a00e, 0xf51ef5ff, 0xd6f895f3, 0xbed0e5f5, 0x4885f6a6, 0xa6e167ec, - 0xa15be43f, 0x49e8a0fc, 0x173ffec3, 0x45653fb6, 0x9edd6c02, 0xee7c7a85, - 0x4f28b4a6, 0xf917f21f, 0xbd51f100, 0xaaf8205f, 0x517c33e5, 0xc7bb8406, - 0x4c560ccf, 0xf480ccad, 0x8d625e7e, 0xf6a80f68, 0x323e5a8c, 0xf3adcb9b, - 0x9093eb51, 0xb53fe64e, 0xccf50925, 0x5f3c1167, 0x6fadd4f1, 0xecf2dca0, - 0xaf101a34, 0x38331d1e, 0x41799f51, 0x551d22bf, 0x93c6ff03, 0x04ae61dd, - 0x0eca2a7a, 0x6fceb827, 0x51fa411d, 0xa77c179d, 0xcc74cff2, 0xd218f385, - 0x748d99dc, 0x7f9d67ff, 0xcff3e22e, 0x17a766f5, 0xf5cd99f1, 0x4bd79fdb, - 0x05ee58a5, 0xe47b4186, 0x885febcf, 0xd8f4b548, 0xfbd2256f, 0xd67684b2, - 0xea36428b, 0x76ccf0ed, 0x1bb22cc3, 0x9d59d118, 0xc359d395, 0xe0e97d01, - 0xa8c7b218, 0x37e746a4, 0x05af85f4, 0x9dd5bd8a, 0x80d7b7df, 0x87b3527c, - 0x6d3511db, 0x508ec867, 0x855a92ed, 0x39ee179f, 0xda857643, 0x871f6eae, - 0x5e3eed4b, 0xc801955e, 0x80e5cd1d, 0x0aba4200, 0xfbf905f1, 0xd3d7f5fe, - 0x7bf26997, 0xb5df7f29, 0x750f2e56, 0xb7a8499d, 0x349c64d6, 0x976bfe20, - 0x5e42fd2b, 0xbcde341f, 0x2f0481ec, 0xc16a1f2c, 0xfd8d0ef6, 0x9a2fbb50, - 0xc36bfbda, 0x97bea356, 0x4c3a2ceb, 0xa42d6b9b, 0x8bd5b7ff, 0x9c5cba19, - 0xed13985c, 0x916183b9, 0x07472859, 0x06653c2e, 0x3b6a0248, 0xbe50888f, - 0x2f73ca3a, 0x031c67d2, 0x6f5090ae, 0x5fb405f8, 0x74f95e3b, 0x6e3ff604, - 0x066be048, 0xbf0bd753, 0xf20c5e9b, 0x2d981964, 0x06671f64, 0x0f1d2046, - 0xf4e5cc3c, 0x1ab67ae3, 0xb9d31bf5, 0xf72834d9, 0x3c42dca3, 0xdbe61b7f, - 0x1dffff05, 0xfec60ff3, 0x143fc999, 0xd0a4bddb, 0x5968dba7, 0xaebcc02d, - 0x8359ea1e, 0xd041be4b, 0x222d935f, 0xac34a40e, 0xdfe7a1d7, 0x82757b55, - 0xc113a722, 0xc8bb408e, 0x416ec830, 0xf3366e3a, 0xccb209f5, 0xf71e611a, - 0x8d9e1e67, 0xa76d7a7a, 0x9d611989, 0xc8c33a13, 0xe41c4d7e, 0x6cd6bd22, - 0x2dbd224e, 0x02ac7438, 0x14ce1fea, 0xcfac3afd, 0xcfac3e4c, 0xae76214c, - 0x9db19668, 0x6fb5f070, 0x960fbe51, 0x82891e2e, 0x47be0df5, 0x9d433670, - 0x8f73aeca, 0x15a41bff, 0xfdec7697, 0x2dff4857, 0xe113b3ca, 0x75cbba7a, - 0x5ba803c6, 0x39336d6b, 0xc160deb9, 0xef7838eb, 0xb13691b7, 0x9d1d7e67, - 0x4dfb9ee7, 0x2726a62e, 0x07099fea, 0xa11fd225, 0xc3b0e9f3, 0x3d5287c4, - 0x2c3b3bb2, 0xb0104fa2, 0x70f791fe, 0x164c137e, 0xbaf684bf, 0xb065ff49, - 0xc48e617e, 0x935773e8, 0x83df614a, 0x938b1091, 0xd1747d47, 0x38eb7642, - 0x3a550f85, 0xdb9b2b7b, 0x72296f8f, 0x73338555, 0xaf582cc8, 0xd66cf0a8, - 0x1022faab, 0xf87b32ce, 0xaf529176, 0x932892eb, 0xf46d5e1d, 0xebb2e831, - 0x33d250e0, 0x3fd9c9fd, 0xf601dda0, 0xf954f2c4, 0x5327845d, 0x0acdeef4, - 0x2dfd54fc, 0xacdffd29, 0x8b66f1c0, 0x5376e1c8, 0x7a14dc08, 0x1e97a50a, - 0xdb41887a, 0xeccf1ba3, 0x51a3f6be, 0x6bdf84c9, 0xfd78e61e, 0xedfaf090, - 0xcd802b5b, 0x4dbfa0d8, 0x0cfefc21, 0xb98bf578, 0xedaf023f, 0x9bf578a1, - 0x375e2187, 0xa0676489, 0xa376881d, 0xb5c0e507, 0x60f6e794, 0x51392306, - 0xd7398529, 0x8077e324, 0x87c91643, 0x541f28a3, 0x15c430b9, 0xe9f506b8, - 0x71e57069, 0x8db1017e, 0x10a4e797, 0xf6b0245d, 0xbc072c78, 0x277da1e7, - 0x7e668699, 0xe5b7720c, 0xdfdedf01, 0x82cd3f40, 0x983ceb6f, 0x8b66f78f, - 0x0eb7ed13, 0xc3d5e89f, 0x59a25a3c, 0xbf187ed6, 0x4e55fe65, 0x4533962f, - 0xf8374c6e, 0xef837ed0, 0xbdf88d49, 0xe97f7f9c, 0x441f67ef, 0x8d33acfb, - 0xb25abad1, 0x67da3a59, 0xf419652d, 0xdcaab7fd, 0xb7823079, 0xddf4e32f, - 0x43e6df32, 0xa3e8f43d, 0x27a8e1be, 0xf1cbb65a, 0x510d4836, 0x981cf89e, - 0xd38920ff, 0x94324b7d, 0x7059ba43, 0x7ec5cf97, 0x0df3e1ae, 0xff3d8794, - 0x4e657414, 0xe506d105, 0x76231ba7, 0xe9555ca0, 0x2e30f074, 0xcf7887df, - 0x7938456c, 0x7a8cb027, 0x8543ffe8, 0x0bf854de, 0x008d36c0, 0x3c1098f7, - 0xa31774a8, 0xca585fc0, 0x413bcfe9, 0xf31d4f59, 0x0091bfa1, 0x38070953, - 0xf0c11a57, 0xd5967483, 0x6ff38d93, 0x91f80c5e, 0x0f1c1d70, 0xdd5645a7, - 0x155f07d6, 0x0df128e6, 0xa6f90218, 0xa9be7192, 0x7a42ba44, 0x0aba046c, - 0x481647a2, 0xae173e88, 0x83ca15d0, 0x1cb8f708, 0xc257e758, 0xf0b1f21f, - 0xa694ffad, 0xa4ce35f7, 0x1e2f2e1c, 0x734a7b33, 0xd04def48, 0x656f9dd8, - 0xfa889a7f, 0xafbdf4e5, 0x149a6025, 0xeb8c9ee5, 0xd7fe5cd8, 0x1fff1452, - 0xb8f407c6, 0xffcb0f8e, 0x2dda224f, 0x235f4b95, 0x79d2bffa, 0x37989996, - 0x5d1ee01c, 0x00fd382c, 0x462d79bf, 0x16f824e7, 0x0c755c57, 0x6ad659e1, - 0x56911874, 0x1c8d62d8, 0x408f2b3b, 0xda1d8a37, 0x39ba246a, 0xf4894bf7, - 0x8b92b9c1, 0x0f800eaf, 0x4e0856e7, 0x32d657ac, 0x3790256c, 0xa816292b, - 0xa057995e, 0x1ca9657a, 0x051a275f, 0xaf4037a2, 0xde283b25, 0x8ef5a731, - 0x13df88a9, 0xa40f5fc5, 0x187ac1f8, 0x2e63e547, 0x959e48de, 0x56abf529, - 0xbb47911b, 0xacb597bf, 0x3ffc88ba, 0xde521bd3, 0xec53e93a, 0x5b51acb7, - 0x8235c6ee, 0x4e57771d, 0x07ca0c44, 0xefce64e6, 0x40f24811, 0x93fa0ff2, - 0x447140bb, 0xc20f30cf, 0x61bc89c3, 0x99eba47a, 0xdba05708, 0xdd7ca5e8, - 0xbe0aa733, 0x99ceb049, 0x1f67ce16, 0xfbbe0996, 0x09ff3e05, 0x5065ef40, - 0x5d740b1e, 0x38e4c316, 0xe626dd48, 0x2e79c70f, 0xca09f61d, 0xd438d3db, - 0x8fefaa28, 0xf75ca1b4, 0xb78911e8, 0xe5a52f32, 0xede947cc, 0x98f34fcc, - 0x74933ac1, 0xfc93af90, 0xf38e312b, 0x0367b32b, 0x8b5fd7d2, 0xe0169c4e, - 0x4239ddfb, 0x439428de, 0xdd68038d, 0x701f5b97, 0x067680a5, 0x5fac41aa, - 0x147ee396, 0x4ccab3fb, 0x74ab718f, 0x995a8e95, 0x17d61537, 0x9be2debb, - 0x6b8beb04, 0xf5c21cf5, 0x38374fa6, 0x1383ef10, 0x74133af8, 0x543f9fdc, - 0x81a3606e, 0x183f360e, 0xdb3a43e6, 0xda2035bc, 0x03e6fea1, 0x97cc0180, - 0xf0bc14af, 0x4e61eadd, 0x7559d38c, 0xfeed111e, 0x188f56a2, 0xe1a7e208, - 0x394441b2, 0x23d3be91, 0x5ab49ea2, 0x353d53d7, 0x4fd4ac5f, 0x59067937, - 0x4e9e4ec9, 0xa15c33f4, 0xd49fb51f, 0x045f8356, 0x4ac917b8, 0x57b7997d, - 0x9e8a61fb, 0x3961db56, 0xab7a67d2, 0x453f4fa3, 0x3f505b4d, 0x08f88f83, - 0x7bd205c6, 0xfd711fca, 0x1bf084da, 0x36abf378, 0x2103374c, 0x9d1c71f8, - 0x79e34cc7, 0x15d33cf8, 0xbfbf87da, 0x63e38f7f, 0xb9bbf01e, 0xe422fef5, - 0x1f00cda3, 0x9de6f3c4, 0xcfd4ccb3, 0x799a59f4, 0xf286a931, 0x4b070825, - 0xa23c75ef, 0xd53d2fcc, 0xbd695a23, 0xe76843ce, 0xe28ccba5, 0x763f6a01, - 0xf405741d, 0x857a776a, 0x90cbcc7a, 0x47b8945a, 0x4eb38e3a, 0x5d31ff40, - 0x6b4957c1, 0xf63361fd, 0x5f1466e3, 0xfe85cf4c, 0x8426fea1, 0xfc37a183, - 0x5e99e742, 0x4273e7cc, 0xf18edfa9, 0xe76c7494, 0x74431158, 0xd5d7e7c5, - 0x1c6214ea, 0xa08fb197, 0x7e90c9fd, 0x0cb8c29e, 0x7e4ecfa4, 0xb42e4a6d, - 0x97d1fe7f, 0x52d0b476, 0x0fb33e0e, 0xf5ab56e5, 0x9c709be6, 0xff9f2283, - 0x5de2724d, 0x206ddf98, 0x53be9a3d, 0x7944db4e, 0xebfd1393, 0x55df56ae, - 0x2cbd422f, 0xeb64c618, 0x0a138f3d, 0x3a15da9c, 0xcb793938, 0x53ef5c20, - 0x582c7745, 0x5f87ed02, 0x3b8d38f7, 0x94fcca7c, 0x9b0fc816, 0x30abcbf8, - 0xc78e5f7f, 0xfee4023c, 0xde5fd2b0, 0x6ae50fb6, 0x821cfce9, 0x4576c597, - 0xda39a9f2, 0xbf02f5e3, 0x52dc4737, 0xd2b8fc8e, 0x24487066, 0xfa19eb77, - 0x7711cd59, 0xe5bfb1db, 0x4c26f9d1, 0x36bfd60d, 0x6e3c9ca1, 0x1e2131c9, - 0x18132d9a, 0x0aaceb96, 0x4f1bbe9e, 0x885240fa, 0x73847772, 0xe5744cba, - 0x0c272864, 0xbcad0609, 0x2f7971d6, 0xb43e1dd9, 0xf5acba9f, 0x60cc8148, - 0x7ca05409, 0x69795493, 0x3c717a71, 0xa3b4e2c9, 0x9142b4bf, 0xaf862c37, - 0xf73960d3, 0x5eaf389f, 0x962e63fd, 0x867f4b50, 0x4128ccb0, 0x9bda3ff9, - 0x573e10c6, 0xbbc58353, 0x6844f518, 0x70205d7f, 0x4fa38e50, 0x7e337647, - 0x5eddee48, 0x7a341bb2, 0x7a5e5ba4, 0xf221f5a2, 0x7a811e52, 0x792058a2, - 0x0ceb61e9, 0x0c12feb8, 0x3c5c00b2, 0x545eb8db, 0xce267bf9, 0x49e5f005, - 0x5e5c9165, 0x2673e4e9, 0xd1efc60e, 0x452a5cae, 0x5e021e22, 0xc3e9e0c9, - 0x9378f79f, 0x9d1e507f, 0xa987fa41, 0x21fe9007, 0x0fe144fd, 0x6f078a8f, - 0x50a3f5d9, 0xd912cb5f, 0x85cb9503, 0xe2cfb436, 0x6947d1bc, 0x2edcc5be, - 0xa6bf9768, 0x892a1cf5, 0x7979444b, 0xc799d962, 0xbebd41ef, 0xfff49c29, - 0x5667a5a4, 0xa66e3c60, 0x211a7057, 0x7d1a59ef, 0x6f987bf7, 0x905d3a34, - 0x81f0ab3f, 0x914597fb, 0xb8084f68, 0x759e8cce, 0x83321656, 0xf139e29b, - 0x3b409633, 0x34e0a34f, 0xa1e07a3b, 0xef527ac7, 0x37bc05f5, 0xfad0fe46, - 0xa8d7bc3f, 0x3e7759c8, 0xc6a2d9ca, 0x700a87e4, 0x7cf5eb5d, 0xd7d18d9e, - 0x3927de53, 0x1cb97639, 0x3fd8a99e, 0x57b3a59e, 0xc0f7c3c6, 0xcef9416a, - 0xc8a956f1, 0x88e340e5, 0x0d3f1863, 0x3e48172c, 0xa252bc79, 0x5ccdda1f, - 0xef784d9e, 0x5d900a28, 0xb43de5d8, 0x722b5a92, 0x3674a3de, 0x94588c17, - 0xe3dfa76f, 0xfe479ffe, 0x9bb62563, 0x83b5a2d3, 0x0cfd0226, 0x67bcb840, - 0xf1e9fd26, 0xefbad196, 0xea6945f0, 0xd38ead55, 0x8bab3de4, 0xe7b0c7ae, - 0x52277bac, 0x3992af3c, 0x2ade9122, 0xc1376e65, 0xe61b259f, 0x4f9d5733, - 0x2ac7b731, 0xa27ec18b, 0xb07b5aef, 0x3389fec7, 0x78a8df20, 0x3a13f154, - 0x19765eef, 0xacd076e3, 0xdd7ada75, 0x16301076, 0xe5caba8a, 0x32bf76da, - 0xb9459fbb, 0xe038dee8, 0xaeabf21b, 0x80821e50, 0x266e7f21, 0xa61f71e3, - 0xced543e8, 0x517a592f, 0x6668728f, 0xc23d45e3, 0x1fd2e673, 0x385fa7e6, - 0xa1bef3b5, 0x3ebb4a20, 0xbf934e39, 0x534435d1, 0x30f766ff, 0xa75bf7cd, - 0x5ef9ab5f, 0xc9a919ee, 0x5e3d5edf, 0xfd467f53, 0x7a1cad24, 0xa3d69a37, - 0x79bfa7e2, 0xa3e8a5bf, 0x12ec4277, 0xe23a9d35, 0xbf91133f, 0xe4672c3f, - 0x33787cbf, 0x1d31f8d3, 0xe7822423, 0xf93d5c80, 0xc8e5f731, 0xbf208fef, - 0xa1f44fc9, 0x7343f3c2, 0xa228c9a1, 0x7ee4627f, 0x725fa879, 0x5e503990, - 0xfdb1d4ce, 0xff8f5442, 0x9cf30e67, 0xe3bafec7, 0xf10f4b0d, 0x1f884378, - 0xff78a573, 0xbfcc0670, 0x4d79790f, 0x16c3f72e, 0xffaf36ee, 0xb58e0838, - 0xfc9ad16d, 0xebf1fda2, 0x3bd60e3f, 0xae1d044b, 0x93e146b3, 0x7da0165a, - 0xa0e8bb52, 0x40c4eafe, 0x583be62c, 0xf4b46c67, 0x0a8b838f, 0x258f800f, - 0xa9de2837, 0x193fc3fa, 0x9e0a453e, 0x1a70b4cb, 0x90e3cb93, 0x29108f5f, - 0xc7239cdd, 0xf103fee7, 0xf49eb41c, 0xdc7fbcdc, 0xc847227a, 0x9f9f0859, - 0xe3dfaf1b, 0x17940f1e, 0x7f0b908e, 0xfe4cb826, 0x47a5c247, 0xd82f47cf, - 0x72a3fa0d, 0xfdfb819d, 0xbf5c33de, 0xfefd7237, 0xf68fb47c, 0x44f39b87, - 0xed070ee7, 0xe93ed297, 0x618d7ba1, 0x59df1819, 0x797d23a1, 0x8190997a, - 0x2126c2fe, 0x0f36fc8c, 0xc81648ab, 0xc878b9be, 0xaa31fd48, 0x3afded07, - 0x0551f390, 0xe4096b3e, 0x71e5ccdf, 0x716e35b1, 0xf5038a4a, 0x1eac1ff6, - 0xe27a8b8a, 0xfd9e1e11, 0x696be130, 0x2bee45df, 0x6bd0127e, 0x8512d1e5, - 0xd5cc5f8f, 0x2e1f3ad1, 0x949db914, 0x1f70ba2a, 0xa9d81563, 0x96065768, - 0x915f28eb, 0x6d59e9c7, 0x9d0a1ff7, 0x14dd94c7, 0xda88f386, 0x7d7dba24, - 0x2e51fb8c, 0x793d0f8f, 0xb3ed1857, 0x68742a01, 0xd6bddbef, 0xaf582e69, - 0x8d96d0bd, 0xdcdadfb6, 0x4d6fea68, 0xcf159746, 0x748cfca1, 0xfe8eca78, - 0x8cfac0a0, 0xe655cd33, 0x580feeab, 0xe936fe94, 0x9da2bf41, 0x1e289822, - 0xf91af161, 0xb16715f9, 0x1ccade26, 0xa76e0b02, 0xf428f3d6, 0x1b42c76a, - 0xeff697e1, 0x5db178d5, 0x1ba417a1, 0xcf4abbc4, 0x8983fda1, 0xe9cc8dec, - 0x15d9f389, 0xe51a8e52, 0x8f748dd9, 0x1f90eafd, 0x07fe5cbc, 0xe3c4be6e, - 0xded7de2c, 0xe18879c3, 0x0c9c525f, 0x5fce4aec, 0xbee2434b, 0x024f913f, - 0x40cf0e66, 0xde1e5684, 0xdac9d0ab, 0x48de827f, 0x3ebc02ba, 0x8fe5cb9c, - 0x36fdc0ab, 0xb2c73bca, 0xfba230d4, 0x96270b1f, 0x51384560, 0x3872ba5e, - 0x1f3df379, 0xcc749e10, 0x7f71b46f, 0x72e1f90b, 0x31c2a47c, 0xbe9e6449, - 0x3c88f2f4, 0xca1bfbe5, 0x6ab7ae7e, 0x61d90fc8, 0x02c57728, 0xcc2cd2c6, - 0xffb6bc61, 0x8f9c0e7a, 0x396ae885, 0x96aee5d2, 0xcfe43094, 0xcabc6564, - 0x0ca7d29b, 0x205fa077, 0x040ed018, 0xe3c0c3bf, 0x574edc3f, 0xb94f7ae5, - 0x72c47ed6, 0x1f8f664f, 0xeaf7daa6, 0x82973c77, 0x59f3aae3, 0xfd61d8a5, - 0x125577cd, 0xdca2724b, 0x808f765a, 0x5ab1dcf0, 0x717df8d4, 0x0325615e, - 0x7fce3e3f, 0x8efd13af, 0xcdafb038, 0xf575cf28, 0x5e083382, 0x0a817b81, - 0xf8871338, 0xe24fe02b, 0x8967bd3a, 0x57c7425e, 0x85abb1d7, 0x5de71b8f, - 0x9f90c82c, 0xa02f5154, 0x9956b7df, 0xa3055c7f, 0x3e9969ef, 0x9e21e301, - 0xe38a5616, 0x03335655, 0x332af5c6, 0xf2865399, 0x7443c6ca, 0x02b9edde, - 0x206f2539, 0x4f3a4fc9, 0xa4f02ae3, 0x4d1d01e7, 0x7643284d, 0x864bb867, - 0x167f89f1, 0x4cb5a71d, 0x59efa2f0, 0x843ce2d4, 0x11d001fe, 0x2d3c7dc5, - 0xe75f1a01, 0x5d7271e5, 0x80e9c18b, 0x658d4875, 0x5521ffb4, 0xd4329c1b, - 0xdf29b63b, 0x2d95f18f, 0x0ddfdc8d, 0xd67493f5, 0xd1c3d7fa, 0x9910ab5f, - 0x790a0144, 0x5659fa2a, 0x30562e85, 0xf7ee3b77, 0x41fe1933, 0xdca548bb, - 0x2a6f3d5a, 0xd0e52266, 0x13dc8378, 0x6b9e409f, 0xd3b240dc, 0x678daa94, - 0xc92b2d48, 0x7d6233af, 0x890faca8, 0xa5d54877, 0xac971714, 0xf35bf2da, - 0x8e086222, 0x9e1e3c59, 0x8d88ef73, 0x727cc2b7, 0x1fe3797f, 0x41873d30, - 0xfe5b8033, 0x4c073bb2, 0xac16ff87, 0xa62378d8, 0xe8cebc4f, 0xe08fc19c, - 0xfa8c6657, 0xe8fafcf1, 0xb2abf295, 0xb9d00f26, 0xd27dafc2, 0x094f1abf, - 0xfe954fe5, 0x4d4ef943, 0x7f865ed7, 0x120526d7, 0xdf4f0f91, 0xdb03323b, - 0x73de3657, 0x5f88c7c8, 0x77d00705, 0x117177a5, 0x5660ba23, 0x5e5bd097, - 0x490b3784, 0x1f37bfec, 0x3b7c863f, 0x13e7effe, 0x95df087f, 0x63ce8c09, - 0xf649fd81, 0xdfaa9a9c, 0x3eb9f223, 0x246790bd, 0xc1464ebc, 0x053bac0a, - 0xc7bee0da, 0x2b4e6078, 0xf02e7fa4, 0x4de38b3c, 0xef9e3c81, 0x6b40fd7b, - 0x4b37ae0c, 0xa78ef5c7, 0x76e68edb, 0xa8ffb748, 0x06590fd8, 0xdced0536, - 0x771126c0, 0xc0e0596e, 0xe2d63be7, 0xc9b96bbe, 0xcaeb0699, 0xf448dfba, - 0xf68a0484, 0xa7689651, 0xb6aee5b8, 0x9f69cb8f, 0xd2c0d1b1, 0x0ee06e28, - 0x006473c3, 0x4caab0cf, 0xacc357b2, 0x857aaf68, 0x1e88aaa4, 0x22f5087b, - 0xef2cb40a, 0x30ac53ad, 0xb042aefe, 0xec7b3347, 0x59fed51c, 0xeb4c9f9c, - 0x6820ed57, 0x8fddb0c7, 0x0b4aa7e5, 0x19bb224b, 0xf7fb83e6, 0x90264cb6, - 0xff5213ed, 0xd92332f4, 0x7baf76af, 0x5bb470ca, 0xa0e6a797, 0x9ae30add, - 0xfd7f6e24, 0xbb67ca3b, 0x285ef94e, 0x49b9e0e6, 0x05801f75, 0x8718d174, - 0xfeaaed53, 0xe763a5e7, 0x9505b954, 0x9f2f9b7f, 0x59ff7ec1, 0x5563dd72, - 0x634d4de8, 0xe9e079f8, 0xcf8dbd0a, 0x9e9a5337, 0x73dbb3ff, 0xfe93aea7, - 0x39feeb79, 0x9ffae1d7, 0xffd88eb1, 0x3cd8f821, 0x3ac67ff9, 0x4ff2996e, - 0x5f37875c, 0x43cfc86e, 0xe746d679, 0x7e2eec88, 0xdee41c2e, 0xcb9cbc3d, - 0x09938b39, 0x74ffc764, 0xfd84d779, 0x1c1f419d, 0x7778a1cf, 0x67183a08, - 0x88a1a588, 0x8ca5cdec, 0x2c8681f6, 0x4340fbe5, 0x224d3a96, 0x6e1603da, - 0xec520e27, 0xb94b41ce, 0x9ca719dd, 0x118b882b, 0x3fd4327d, 0xca5bcbf6, - 0xbee0c6e7, 0xd5ec9190, 0xf5dd36e6, 0x5e53d416, 0x868fce89, 0xd2d289da, - 0x5f9c4a95, 0xf6aa9f6b, 0x79e31a68, 0xb4b3b2fd, 0xa3daa74f, 0xb4f29443, - 0x603f7ca5, 0x1ed68b48, 0xdad6ab8d, 0x1082fa8f, 0xbaa9733b, 0xeb49d07f, - 0xe9d72dd3, 0xa87ffcf1, 0xb07b89dd, 0xab0714a8, 0xfeb4067a, 0xf630d74d, - 0xf9f77e74, 0x1fdc1c8c, 0xd05ab99a, 0xcf5539e8, 0x7e282402, 0x43e3e2a4, - 0x3f8873d4, 0x5fb534f7, 0xaf3e6fd2, 0x2e4c7048, 0x539cd74f, 0x1e7eec62, - 0x3a73712f, 0x11eaf5fa, 0xddaed16b, 0x37c6eeb7, 0xfd697d31, 0x04e5e19d, - 0x6f54f5af, 0xebc6cb7f, 0x7650ff30, 0xe6123dbb, 0x53a8d0f5, 0xefd009ef, - 0x85e33c6a, 0x2978b3eb, 0x9e14b68f, 0x7ab3d08b, 0xa4dbdfda, 0x0d9f4c0f, - 0x45122be5, 0x23be911c, 0x1832981d, 0x59309f9d, 0x35f57e78, 0x30e3ee8c, - 0x1a9f5ce5, 0xd73d0987, 0xc7c3cab7, 0xc4f00559, 0x18963573, 0x39a91f7e, - 0x08e9fee1, 0x818766ef, 0x8b3939e1, 0x624fee72, 0xa82aaed5, 0xbf7edc77, - 0x0bee167d, 0x7e881867, 0x26ce98a4, 0x9ed993c4, 0x71c2af63, 0xcd35e242, - 0x2037e929, 0xfbb5bc59, 0x20679ef0, 0xc9cf7b7d, 0x2a9d312f, 0xf3c3efb5, - 0x88465225, 0xbf6bd29f, 0x9bdc1198, 0x4a5f3387, 0x6e3b9632, 0x754e9110, - 0x869a6feb, 0x50c154fe, 0x4f581ae7, 0x1bf30258, 0xbd611e60, 0x7b7989f6, - 0xce9c20a9, 0xf59648d5, 0xdfd80d15, 0x7fba08a8, 0xae03bec0, 0x4df3a7cb, - 0x80f657f4, 0x0e3a47a8, 0xc38ff653, 0x1fed7b32, 0x30c2fcd3, 0x3b59e14d, - 0x7a15c3e4, 0xca7b635f, 0x6b77fb87, 0x106e5213, 0x69f53d1d, 0xbbd6195f, - 0xab1bbbf2, 0x26fd5f68, 0x9fcf1593, 0xcafb2985, 0xa574e3a1, 0x43675b3a, - 0x6418b46a, 0x55f11673, 0xe0725f0f, 0xe68353d8, 0x9cfaf501, 0x736e3aa7, - 0xda83c71e, 0x64c2d19f, 0xf74323b4, 0x81fb43ad, 0x56be7079, 0x31fda9ea, - 0x01e746d6, 0x518b8874, 0xa7abb57d, 0xe9df0db9, 0xff1fbb24, 0xcc82e382, - 0x35fc431a, 0xcedb55ac, 0x0dcfca9c, 0x2a18f4a8, 0xfdd0a52f, 0x6f7ad4f7, - 0x9f81e138, 0x1fad0827, 0xf6d0d70a, 0x5833b7f0, 0xe160ddde, 0xa95d88fb, - 0xac22b99d, 0x473da57b, 0xbf5a7f33, 0xef7fd3d0, 0xbe6d3cfd, 0xb9f6364c, - 0x7d07943e, 0x4e8277cd, 0x6c596fbb, 0x8d2fb6d1, 0x25777ed1, 0x4592f368, - 0x6d91dfe9, 0x8e1af3a2, 0xf79e137c, 0x18d8f953, 0x8af7efe2, 0x2efa2adf, - 0x1e74c991, 0x79de9375, 0xe3c4e50e, 0x01d24033, 0xf82c3c7d, 0x552e58cc, - 0x0f515bb4, 0x93d3adc6, 0xaefc7a9c, 0xbde0ce5b, 0x6ba016a0, 0xf771e584, - 0xc56e9b47, 0xf148b17c, 0x70fb9b0d, 0xcb51d239, 0x37bf5f77, 0x3a9fcf1b, - 0x5bce740d, 0x75b1b73d, 0x1e2b61ac, 0x94cb8a0b, 0xfdf069cd, 0x84e62aa1, - 0x6323b099, 0xfc712363, 0x15a2d12d, 0xd1f3ddf5, 0x718efff5, 0x8c19e694, - 0xe14219f6, 0x46d23757, 0x756e3672, 0x5bf780b6, 0x5f9b1e1e, 0x06317289, - 0xaf9465fc, 0xc57dca90, 0xf015c717, 0xc5b6c0f8, 0xbe23c52f, 0xdb0f5837, - 0xa2159e69, 0x52d8a713, 0x8b7fe5c1, 0x7b3ed185, 0x3752a8f3, 0x72ec4d1e, - 0x8b3c0ec9, 0x41dee2d8, 0x2d595ef3, 0x9cacd972, 0xc8580197, 0xbe9c3951, - 0xfd4a360c, 0xb3346e98, 0x972839f8, 0x7ce8c292, 0x81f67f50, 0x57cb84b4, - 0xe9cc6f6c, 0x1143debf, 0x5cc8f18d, 0x9fe467cb, 0x6dfd0b9f, 0xf299b19d, - 0x538d3caa, 0xdfbbbbe8, 0x1bba3d10, 0x36724bf0, 0x9e2ce41a, 0x878e63c7, - 0xf575b789, 0x3a20b4c2, 0x7c8055d5, 0x2ee7e2cd, 0xbebb7e30, 0x87e334a8, - 0x9b9d4cfc, 0x5518e5cb, 0x97ebbb1e, 0xda05dc61, 0x635f51fb, 0x0fce783f, - 0xb7d71952, 0x443fa851, 0x830cf37e, 0xe839ef03, 0x430e402a, 0x56825d7b, - 0xc9181c4f, 0xc1fb35f1, 0xa09eccbb, 0x728c4d38, 0xbea3661e, 0xeb069cde, - 0x744338d9, 0x6c78076e, 0xfa1068a9, 0x55c4c78a, 0x0d997e70, 0xde6fd1f5, - 0x1b139152, 0x8c669ebc, 0x36d0c073, 0xdb9f0fd7, 0xbfc885d3, 0xbc79235d, - 0x1cdd67bd, 0x3f4071be, 0x479a87a8, 0x6ae6ae97, 0x557241da, 0x6d6de567, - 0x073a7aae, 0xcfc155d9, 0xf813ad5d, 0xc4a4827e, 0xf28b9bcb, 0x4bf4bf49, - 0x492b152f, 0x57e2849f, 0xe5fd3f9d, 0x9911e907, 0x8719f1f1, 0x4cceb49b, - 0xda07e1fa, 0x4af9743b, 0x1e0bd47d, 0x62ba7f6d, 0xf8e33651, 0xaf105fa8, - 0x7bc5e63a, 0x95fda193, 0x3a16fc2a, 0xe069c91f, 0x8d9db1ed, 0xdbf48bf8, - 0xc8e00169, 0xa1ce82e9, 0x3c38f7b3, 0x7c3a24b7, 0x2e01f86b, 0xae7487d2, - 0x78f7a52b, 0x658e098f, 0x7de8efb8, 0xe7f3a25d, 0xcd4f7aa1, 0xb13070ab, - 0x3e9ce736, 0x0f9c4dec, 0xa76935ea, 0x01fa89d7, 0xed8a97d0, 0x094b2a36, - 0x5cd4b3bb, 0xd7ade8e0, 0xab6d5cba, 0x937282af, 0x03f69983, 0x99534c3c, - 0x79c0307f, 0x1ccf33ed, 0x3df58abf, 0xf803ae0e, 0xe6bce099, 0xe63347f9, - 0xedf37b40, 0xb9b426ad, 0xf5a1cf43, 0x76a4ef6e, 0x4cab4b71, 0x23c519d3, - 0x86b95465, 0xafd90b08, 0xe48674cc, 0xc6c934b3, 0x3d10a7ed, 0x50f80eb9, - 0x644af08f, 0x38d0af04, 0x49f8e871, 0xdefcc905, 0x1a52e2e4, 0xa7454377, - 0x5d90e31e, 0x4ec57aae, 0xefa9f4f2, 0x7bb1fb42, 0xff23a73a, 0xc81a1577, - 0xc1f87e1e, 0xcf119349, 0xc51265de, 0x7bd17ad1, 0x233dbac8, 0x1cae9cf5, - 0x7f28cd8b, 0xdbb9ccb7, 0xfec3e8ec, 0x8b3152d8, 0x965a2fce, 0xa5633b70, - 0x88e481bd, 0xe7b942a5, 0x71cbd8a2, 0xa213bfaa, 0x3754b727, 0x9bdef198, - 0x8590de7a, 0xed97dbd8, 0xbbbd1fbf, 0xf18bf961, 0x2aee4fa8, 0x79c78869, - 0x4ff0896f, 0xd5df1377, 0xf2029f93, 0xf1e51e38, 0x920e91a2, 0x7ff2dd2f, - 0x0e3b39c6, 0x5569181e, 0x43db8af8, 0x417fe25f, 0x928d66bf, 0x1c6014a7, - 0x8e44b52d, 0x74bc6076, 0x00d3bbdf, 0x7abd93ae, 0xfb8d63f2, 0x2fc1f481, - 0x49382632, 0x681e9e5f, 0xac9d22b0, 0x8f46fc6a, 0xe2ce6bf7, 0x7fe855e9, - 0x87b70255, 0x9818c556, 0xa1f342df, 0x2e754f45, 0xf5a7a866, 0x0137dc09, - 0x798fc5bf, 0xfd102316, 0xbaf18e4c, 0x298700ad, 0x30bbbe31, 0xd7ac4aad, - 0x129c60d9, 0xf080b447, 0xc563a29d, 0x9daf1e06, 0x115cf385, 0x59c511f3, - 0xd1c5a727, 0xc5a3547d, 0xc9fbc3ad, 0xf6d5677a, 0x8bce8cb5, 0xb015bc51, - 0x8ce1f74a, 0xb6bdc718, 0xeeab8e27, 0xdcf1a913, 0x04290575, 0xffc1212f, - 0xcb23e22d, 0x1ef1101a, 0x403e987e, 0x46aaf8f6, 0xcd41f913, 0x91da3b09, - 0xf823323d, 0x3e7aa43e, 0xb163e017, 0x0c567c02, 0x95d69bbc, 0x17bb1494, - 0x91faa5e7, 0x50af20f1, 0xcc2565de, 0x4beb8a9b, 0x4aedc37a, 0x0cc67a86, - 0x1660365d, 0xa2b9eae0, 0xc61eac78, 0xd8583c21, 0xabfb4c38, 0x40d122bf, - 0xf2d0d8f1, 0x5c780b27, 0x21050b32, 0x135eebae, 0x755dcfdd, 0xaaf7bee0, - 0x301e7e50, 0x6767c939, 0xffbc1481, 0x66771dde, 0xaeddff7c, 0xdbb5bf9c, - 0xa63f740d, 0xf8ccbe3b, 0xe71abcbe, 0xd9e51a88, 0x31f2788c, 0xc7f421c7, - 0x8f71abfe, 0x4fca461b, 0x6dac7f60, 0x63c515c0, 0x68eac6c2, 0x8529279f, - 0x05f78279, 0x5feb2956, 0x7a870dd5, 0x75f5ea3b, 0xf6079428, 0x378d870f, - 0x2226bbe7, 0x88ec46dd, 0x47dafd47, 0x171343bc, 0x79287bc1, 0xfa6204b1, - 0x9c79aa93, 0x3cea6624, 0x5348778a, 0x0ad93ef9, 0xdcfc6016, 0x7c84c0a0, - 0xfd4beaba, 0xe887700d, 0x927accd7, 0x90ae9193, 0x7f2f48b8, 0x6576e645, - 0xa2dbdc88, 0x02f1f9f0, 0xcf91ee25, 0x93e7bff2, 0x5228bb25, 0x1889f7d9, - 0xe8724295, 0xd90a5711, 0x411cc443, 0x9d9cbef0, 0x87b15073, 0x8f9ca77e, - 0x83e72bf7, 0x83e72b0f, 0x0b77c55f, 0x863f90c0, 0x7a4016ef, 0xe549c9bc, - 0x2815346f, 0x6fe399ca, 0x4892ee45, 0xf9941fb2, 0xadf994e9, 0x25734eb0, - 0x6d567e03, 0x5879d3d3, 0xe984c263, 0xaf32cf68, 0xdb119edc, 0x7587ef73, - 0x9efcbfc2, 0x095da773, 0x3a4f3a1e, 0x3ff7cac7, 0x542d7c55, 0xb612afea, - 0xc75f9019, 0x36e16a76, 0xc6a452fe, 0xda622cae, 0x4d1397f3, 0x4bf53443, - 0x97f3daac, 0x6ad7ec93, 0x68764fbe, 0x975e5fcf, 0x1f643e31, 0x0b574b56, - 0x806e8013, 0x7d33aa4e, 0xd685ff34, 0xcd7b8a52, 0x74c7b90d, 0x3f36ab47, - 0x2fcda7df, 0xabcdaddc, 0x46c3c9e7, 0x9230f429, 0xf131fc8d, 0x0cf7e44e, - 0x0107ef85, 0x3ab36fbf, 0xcfda1199, 0xf8bf7816, 0x1b00c61e, 0x76c94bed, - 0xe3ac238c, 0x5cb09ff7, 0xc3bdcbc7, 0xbe7af695, 0xdb8ec56f, 0x4b1dbee8, - 0x06ede1cc, 0xfc7eeff0, 0x72f1a48e, 0xfe87af0e, 0xa21bd612, 0xe5c353f4, - 0xfe459c93, 0x33ec9b82, 0x62b36b23, 0xc2fe016a, 0xe9399a34, 0xab0c759e, - 0x9075bf27, 0x51327f72, 0x43bca4e8, 0x3e6186b0, 0xf0a67045, 0xe48f85f8, - 0xfe4950c3, 0x89f12a75, 0xf447745b, 0xb90d97e6, 0xaaf007ba, 0x910286f8, - 0x5623e2e4, 0xd8f9ef46, 0xbf13f75c, 0xb016c36e, 0x8f6b336e, 0xf87a1549, - 0x61bcede7, 0x5c135fc4, 0xb52fda0e, 0x780b2415, 0x8588a52e, 0x4536cb9c, - 0xc4a3e869, 0x5f42171a, 0x4be84243, 0x9d7f7f4b, 0x3945d5ec, 0xe842ce90, - 0xe5be2ff0, 0xaf182c51, 0x05fa8f4c, 0x7689d58f, 0xca9e054a, 0x754f9602, - 0xee319b46, 0x73d18b67, 0x3fd8a579, 0xab9f4aa5, 0xb2eb59e4, 0x566bfbe1, - 0xf6e649d1, 0xf13d2dba, 0x96df1825, 0xea35f600, 0x5c919963, 0x1fd3b07d, - 0x7fd43576, 0x65fffc04, 0xeb1bfd0c, 0x65efbc64, 0x5f10e4b5, 0x7949623f, - 0xd05ef300, 0x437f58e8, 0xe5aff731, 0xef826ce8, 0x05bea151, 0xc23da5ef, - 0xc1a94cf2, 0xfebc2df5, 0x5164597a, 0x31189f90, 0x9dbfea82, 0xcef86667, - 0xd9a07781, 0x63ec7187, 0xdd77acf2, 0x7b7feb41, 0xaf07d714, 0xa8f11c19, - 0x7c991e0f, 0xd287a677, 0x685f8d74, 0xbee4104b, 0x8f8517ce, 0x92bd7236, - 0x78c7e25b, 0x34c2747c, 0xfd039957, 0xe90bb71d, 0xf112e742, 0xfd375be8, - 0xa87e2b44, 0x0fc106e4, 0x5d749b4b, 0xe3ff430e, 0x35770b11, 0xd59e291e, - 0x02f98652, 0xd903ee91, 0xd9ebe25c, 0x7e02aeb8, 0xe54af0fe, 0x181ea871, - 0xbfdb9a32, 0x3c448693, 0xdffa1430, 0xb15a2450, 0x2b7a0dff, 0x4ef1e7dd, - 0x1757e466, 0xe097eabb, 0x11096dbc, 0xda6fcf0c, 0xbe781a0a, 0x00ccc0d8, - 0xbd6b934f, 0x4a69f117, 0xf6c08cf5, 0x7a7e0747, 0x5b19ed1c, 0x703a4882, - 0xaef9cba2, 0x2817eb1b, 0x79e29df1, 0x9b3c70eb, 0x599ab445, 0xb9541c0f, - 0xcbc99ebe, 0x0ab2ffc9, 0x0accdef4, 0xce0d436b, 0x708491e7, 0xae6df3b2, - 0x79e20b06, 0xd13d40c3, 0x7f224941, 0xc2556a57, 0xffcc0ab4, 0x7191a062, - 0x1f2ff3be, 0x5381fe8a, 0x5b3575a0, 0xc75e681a, 0xc139892e, 0xa9a896ef, - 0xcf85a1d9, 0xf8f146ef, 0xf1e30990, 0xf5b79f80, 0x8b9a9ccc, 0x78a7a3f4, - 0x6b7c7f53, 0x7ece5d73, 0x2afe61fb, 0x110b0394, 0xc29785be, 0xfa404f98, - 0xfe61293d, 0x5b017f77, 0x60d9d680, 0x6e41fec1, 0xbfa2fabb, 0x7e9cd188, - 0x4b0e0b9b, 0xd7824ef8, 0x341f1021, 0x444e4e5b, 0xb528783e, 0xa1e8e88c, - 0x899a8f82, 0xfcf3862f, 0xeef779db, 0x137a3c41, 0xe77f69c3, 0x315982a1, - 0x60bef4c1, 0x32f44894, 0x4e616fee, 0x9463e23f, 0x91fbf881, 0x8c56c708, - 0xccf3794f, 0x824bbf64, 0x986cd975, 0x2862c4e7, 0x5da2fe87, 0x7ef13e62, - 0x0b8f0575, 0xd57e302b, 0xf8843b65, 0x31664a90, 0x3949ae7e, 0xef9114f7, - 0xb435435c, 0x25956ffa, 0xd8cfde97, 0x4270d092, 0xbb20b6d9, 0x5722906a, - 0x45889406, 0x5906df28, 0xeb655db8, 0xbb940594, 0xaa47fba1, 0xed29d7be, - 0xa65b328c, 0x371b54a3, 0x7d7015d2, 0xe97f6a1b, 0xc35edc2c, 0xae8fbc3f, - 0x893f35cf, 0x317438e7, 0x197f7ada, 0x0a739ca5, 0x3a54afb1, 0x7ae560df, - 0xd1ae4362, 0xa1bd7487, 0x2a59db98, 0x47f2ab1f, 0x872abf85, 0xef7e7bd4, - 0x5195f628, 0x87365e4e, 0xe599eae4, 0xd4076f78, 0xc317739e, 0xfa56897b, - 0x1f72aefe, 0x6f6294f1, 0x5bd8a7bd, 0x5bd8a1ff, 0x05bda3ef, 0x835186f9, - 0x1437bf08, 0x08dd762e, 0x20901af3, 0x3a14df11, 0xedc44c4e, 0x271971af, - 0x61d97d2c, 0x0ea2d111, 0x348f05e3, 0x36497bf2, 0x1598ed97, 0x95cf59f1, - 0x766b2cf9, 0xbcbb3469, 0x7ae3f27c, 0xe43ed1d2, 0xb9557beb, 0x994c794f, - 0xfe6571ff, 0x57f3286f, 0x43498fed, 0xbca132be, 0xefaf10df, 0xfc297e47, - 0xb9d0a729, 0xb57950a8, 0xe908c401, 0xfc9122eb, 0xe778209f, 0x25bde46a, - 0x4ef5f720, 0x1e68c959, 0x7660dbbf, 0x7c462c57, 0xa714664e, 0x27aae89d, - 0xb90365b9, 0xf8b37245, 0xca6ceb5c, 0xe5833847, 0x6381519e, 0x8e5acbb1, - 0x4638be72, 0x24571f4f, 0x5bbdd0a4, 0x1d0efed5, 0x0cf072f7, 0x82a66795, - 0xf3e25ef5, 0x6c7247ff, 0x8ee3e32c, 0xfd3a24bd, 0x4f1cde5c, 0x91237926, - 0x5fed0a7c, 0x636f3795, 0xbe2064cc, 0xfba1644f, 0x610a7700, 0x9de7844e, - 0x3f307c28, 0xff7dd197, 0x673d8ac1, 0x01d1de57, 0xceb8a14e, 0xf5b04ed8, - 0xfc7af883, 0x1bf75325, 0x8f8edc6c, 0x9a27e4d6, 0x4bf535e2, 0xef9ac9ac, - 0x35c3ec93, 0xb23b27df, 0x32ebf935, 0xffea6946, 0xc9a459c2, 0x593050df, - 0x2e4cbf53, 0x6665e4d3, 0x0e4877a5, 0xfa1eed36, 0xa7fd1eb1, 0xa71fa1b6, - 0xa14f86f5, 0x0e0bf0f1, 0xa3b5e160, 0x00e8678b, 0x87518546, 0xfc864cef, - 0x6793d1c6, 0x0aef80e8, 0x3afe1f07, 0xd3685819, 0x7f3c29e8, 0x53afe1f5, - 0xf465bf20, 0x863f3c75, 0x3adcf091, 0x2f0cea7a, 0xea1c59e0, 0xd0347479, - 0xea972df1, 0xf83da28f, 0xe6d365c7, 0x4ef84b26, 0x06625940, 0x8a6ce7cc, - 0x7efc61e7, 0x15acec73, 0xfc761178, 0x8f74f577, 0x79a337ed, 0xfc8b8ebb, - 0x8b8e8d5d, 0xbb0d1dfc, 0x53f6f1c8, 0xcbbef553, 0x7e9a0e04, 0x64115fdf, - 0xfd05af7e, 0xdc6939cd, 0xfd14c4df, 0xdfd14c4d, 0xcdfd14c4, 0x6fee7a39, - 0x26fe8a62, 0x89bfa396, 0x324d5be9, 0xb934efa5, 0x726f6d28, 0xbf7dda53, - 0x6ae729e0, 0xef380a3d, 0x985b8b4f, 0x1117e4c3, 0x4ae7a14e, 0x4f9df43a, - 0x45ca7ed0, 0x12fbc0e6, 0x394e2287, 0x39acbf70, 0x2e7444cf, 0x4c3bb674, - 0x9730bdf0, 0xb62f9be7, 0x617e503b, 0x8e9eed1e, 0x946cb6e8, 0x16b5cdbf, - 0x35bbee27, 0x23c7f45f, 0x1bd6149f, 0x714cdee8, 0xe9c52767, 0xbdfc2d0a, - 0xc7114384, 0x91e3288e, 0x9179da5c, 0x277c45f9, 0xb0eedcc7, 0x3f60e32a, - 0xea326e30, 0x3025c2b7, 0xbf5bf52e, 0xb0a9fa98, 0x842b8f74, 0xe1fa6b8c, - 0x410a2771, 0x3176a6e3, 0xc701177a, 0xf5c66875, 0xfc3f744b, 0x78c25fa2, - 0xd3b44761, 0x354d718e, 0x21df8c5f, 0xdfcf45bf, 0xf8742c5f, 0xb893d425, - 0x5bef89bd, 0x33d881c6, 0x1f0d79d3, 0x47a865c9, 0x5d9db971, 0x9a179d7c, - 0x9f900bfc, 0x6077958a, 0x7ba58cc0, 0x730c4c9b, 0x9128bea2, 0x38363bbe, - 0xe339df17, 0x1b15a0ef, 0x1f90dbdd, 0xde5c74eb, 0xdf3318b0, 0xcfb5d057, - 0x3bd415ff, 0xec983b19, 0x4bfb0495, 0xb404752c, 0x44cae45f, 0x5b24e3bb, - 0x7568724f, 0x8f7fe794, 0x31be7a06, 0xf4505eb3, 0x7763f527, 0xfdc0ef85, - 0x86578e88, 0x4d1f21e5, 0x645e3a33, 0x1f7fbfc0, 0x3cfc44dd, 0x8791ca2d, - 0x7dfdac2f, 0x8f9e0af4, 0x3788bc73, 0x69acad83, 0x8ffc7146, 0xf1452f3f, - 0xa79a740d, 0x7fb43a0a, 0x765373d4, 0x063613d1, 0xfaeb54e0, 0xd7e7c0ca, - 0x7078c069, 0xc10718d4, 0x4661e06f, 0x273a98e7, 0xe076f847, 0xfa80df7e, - 0xb2878c6c, 0xd61e474c, 0xd277d24b, 0xef8ef27d, 0xa827fdf8, 0x50537919, - 0x8389fefc, 0xf8afab92, 0xdc31c9e3, 0x6a945d4e, 0xa8788759, 0x944c9bb3, - 0xe748bc1e, 0x9dce9982, 0xd96bf18a, 0xa97bf7d0, 0xfae18eaf, 0x41a57921, - 0x74410231, 0x30e594c2, 0x0cbde6a6, 0xbbf6d0f4, 0x8bdfbac3, 0x43327003, - 0xdef3c89a, 0xeb178f1d, 0xac65f534, 0xe31dfddf, 0xbda7acf4, 0x8fcddbfc, - 0xc6554f2f, 0xc7997a43, 0xd50c7fc8, 0x6d0b6b3b, 0x843f3bea, 0xcc63c7e7, - 0x523de9db, 0x14877949, 0x4e315aea, 0x3de8ce11, 0x37bfc1ae, 0x9e819afb, - 0x3d399a76, 0xdd3c8aa7, 0xeafaf229, 0xbbeaa53b, 0x7a14cf6b, 0xa3cc2b6e, - 0x8fd4fc7e, 0xdf1b37b4, 0x6d6788cb, 0x6efabe34, 0x012f5a94, 0x2b0920f4, - 0xe23a675d, 0xfb1250ab, 0x63e7e784, 0x1d20e68a, 0xb2f2685c, 0xcdf4824f, - 0xc6c8f085, 0x49d5fc60, 0x3f5af7da, 0xda81331f, 0x1b6beda9, 0x284fb227, - 0x3a27e978, 0x69154daa, 0x624ebd1f, 0x9c3be2af, 0xa80d5920, 0xa776d597, - 0x78e2de40, 0xc5fc82ef, 0xbb903df4, 0x3ed1e89f, 0xfbe94e9d, 0x3f2a1e4d, - 0x694d54dd, 0xca9ea9a0, 0xa46a6a3f, 0x23db96f4, 0x167f9172, 0x3ec65fed, - 0xdaf7a209, 0x1027bd36, 0xd4553f94, 0x51ad1d37, 0x7254e8e8, 0x1c9fdfdf, - 0x53bbedc3, 0x3b3e38e3, 0xf7c0dec0, 0x972e80da, 0xdbfd6d5b, 0xfdca1d1d, - 0xf9e3a3ae, 0x3c4765fe, 0xc31f2fcf, 0x64596efd, 0xe8fed8ad, 0x3fef0378, - 0xefc6ac45, 0x7bf78db2, 0x77a45d2a, 0xb1357ea4, 0x5831fee8, 0x73ca163f, - 0xaea7f27a, 0x41e5dfe2, 0xaf9d5cbc, 0x42b6fdfa, 0x61eefaab, 0x8fcf7f3a, - 0x7a02f7df, 0xfad5fea7, 0x3e702663, 0x4befad0c, 0x43c9e7e5, 0xc2a9f1e1, - 0x6817c4b7, 0x241f2367, 0x9d45f107, 0xa542f883, 0xd6fe9543, 0xa7387216, - 0x0f3a151a, 0x07eee7e7, 0x76842ea3, 0xb4cce383, 0xbbe3208f, 0x9d9eb0cb, - 0xa12fc282, 0x63bca0fc, 0xca83f2ac, 0x0fbd2a07, 0xefe33e06, 0x8c75f334, - 0x5f79fa95, 0x7b475958, 0x845dc46c, 0x2b7a83d7, 0x12b1adea, 0xb0792f7f, - 0xedcef5d8, 0x11b19fc8, 0x96918c0e, 0xf7d4b2ac, 0xfe3ec725, 0x9543c2af, - 0xa3c0fd0b, 0xca0c1c17, 0x123fc3bb, 0x50e7240e, 0xf6fd238e, 0x8c4eb721, - 0x177629b1, 0xc7cfdfa7, 0x1d226fc8, 0x1d660875, 0x30e87bde, 0xf05f7df7, - 0x0ebe78e8, 0x16d68e95, 0xe3074a32, 0x96f6873a, 0xba7aea7b, 0x230779d7, - 0xc61a97f9, 0xacf143cb, 0xfe482bae, 0xa979c19d, 0xec0c64f0, 0xa127e81f, - 0xe8ef42c6, 0xe0e856dd, 0xd3f036fc, 0x67ac0dca, 0x3e8a35fd, 0xf8944c7b, - 0x7e8ac87b, 0xa4172ee9, 0x1a996599, 0xcf4743bd, 0xefe15f3a, 0x5645fb8a, - 0xa372ef8d, 0x171c1d6f, 0xe5c8521f, 0x3cf4d743, 0x2f13f711, 0xf742d5fc, - 0xea0c2f8b, 0xcef68d3c, 0x533d5685, 0x2a9b23de, 0x8b9dde80, 0xf90c133e, - 0xf39ef2a5, 0x0ef7e8e7, 0x176d7a83, 0xb5bda34f, 0x4cc4ab68, 0xeb609e78, - 0x3d20b737, 0x4f457bcd, 0x5b9a99e7, 0x7a471e37, 0xc04fb73c, 0x85d96fe7, - 0x31c5027d, 0x7c225b6b, 0x0a5fa866, 0xc77fac79, 0xe3c7c96e, 0x39c5328b, - 0x3ef1946a, 0xa0a5d731, 0xeb713e5d, 0xfb843a5d, 0x8b02edbc, 0xb48f7e83, - 0xdf0c79de, 0x8db7391d, 0x366b2fdf, 0xf9c0ee47, 0x0ceb4a97, 0xc17ca083, - 0x635e5e76, 0xf70cfd29, 0xcd3c1743, 0x60b3fe28, 0x8ff9046f, 0x1ff45af3, - 0x8eec8205, 0xfcda6dea, 0x4066d67c, 0x53b0583a, 0x07b35e5b, 0x79f241f2, - 0x2f12a150, 0x29b2ce19, 0xe3c2d25e, 0xef7caa07, 0xb97b5f6d, 0xde506d1c, - 0x897f66ff, 0x5f0ff7a5, 0x23e926f9, 0x2997cf0b, 0xff9033f9, 0x178e1bea, - 0xca752e15, 0xb3c55fd8, 0x675836dc, 0x2b662bdd, 0x0775edfa, 0x79e246ce, - 0x016145b0, 0xbd99177a, 0xded1592c, 0xe4bf607b, 0x1ed6f845, 0xfb893f34, - 0x9e2f7598, 0xa13c6030, 0xb262df74, 0xef312657, 0xfd9bf44a, 0x89dac8a2, - 0x7de9da8e, 0xce77265f, 0x1c2e7ec3, 0x0ed15b30, 0x4ff97ba8, 0xfcc76ec7, - 0xa7dd028b, 0x201890bc, 0x55b7993a, 0x0c437ba2, 0x1efcb42d, 0xaf10913a, - 0x28b6e788, 0x0ee58f7a, 0x19e23bc4, 0x4648eef0, 0xd071e13a, 0xf44b4f79, - 0xd9b5b9bd, 0xf9cff580, 0xbc557e38, 0x094b4a97, 0xe71e0bcf, 0x75b89cf8, - 0xa430e6d7, 0x64f5a783, 0x76811f8f, 0x0d3b7883, 0xe15e181d, 0xc5d85ffd, - 0xd37791cf, 0x376301c1, 0x2f3ce01d, 0xa7c00747, 0x472ff7a4, 0x97e89d07, - 0xddffbf92, 0x0ed0c7b9, 0x87e7e08f, 0xd51b77d5, 0x2e071a77, 0xdf14753c, - 0xbfb34ae7, 0xa5777640, 0xc5da8bed, 0x9d09de8c, 0x4be78853, 0x02bdbf26, - 0xca7277d1, 0x2f14d9b3, 0x6d7607d5, 0x744378c1, 0x3ac7c538, 0xe1b6cb92, - 0xb6c598fb, 0xc2f6936f, 0xcefd163a, 0xeb11e748, 0x3fc67e15, 0xbea2073c, - 0xa7780c4b, 0x07b519f3, 0xc65cfc8d, 0xe1fbed3e, 0xce9cf11d, 0x959d0c4b, - 0x804fd18b, 0x411c70fe, 0xc2e9fee6, 0x451dfc83, 0xa85c9fd5, 0x47b8a7be, - 0x60836efb, 0x3dea9b7d, 0x70429850, 0xd6371a18, 0x73797681, 0x0d84f339, - 0xc17d21fd, 0x5c7ca9df, 0xb5fa8bf1, 0x1bd1fb27, 0xbcc91daa, 0x15daf721, - 0x014775b9, 0xbbd1e39f, 0x7be1d0df, 0xf93b1d8c, 0x3fcc3bef, 0x062af208, - 0x1af519f7, 0xd4a753b9, 0x0fe914ff, 0x5bde76e0, 0x052892ff, 0x8bf797cb, - 0xa79a9fb1, 0x48753f79, 0xf5571457, 0xfe830e6f, 0x33d36cbe, 0x4c0597e4, - 0x23fb3791, 0x4bd46e28, 0xbedcecbe, 0x50f7cd12, 0x76085aba, 0x94222e26, - 0x69f6eabe, 0xa85d3deb, 0x670e7bec, 0xfff9e0d7, 0x90e031af, 0xba5f23d7, - 0x8e67e9df, 0x6eefe428, 0xef68287d, 0x056b0fef, 0x77ea0f96, 0x63c4cfb8, - 0xeafe4aa4, 0xfe4d56dd, 0xa6bb369a, 0x1dfbb5fe, 0xfed9ef9a, 0x11f7cd0c, - 0x7c9a9dc7, 0xa6817b5e, 0x64f7c8fe, 0xc0547e4d, 0xe63fa9a5, 0xef935bbc, - 0xf4f584ca, 0xe9a8cf61, 0xa9a0bb24, 0xd661d93f, 0x465d7ff4, 0x65df26b4, - 0xd8a3e051, 0xfbfdaa99, 0xff6e42a7, 0x7c2aa686, 0x8ed4e17f, 0x37edfaa3, - 0x2bc76814, 0x5de3b593, 0x1df05e29, 0xff9e9d41, 0xf8a6027e, 0x34ba09fb, - 0x9809fbfe, 0xc04fdfc7, 0x013f7f14, 0xe4dd7fcb, 0xa6befca4, 0x04bfca02, - 0xf7e6097e, 0xe9829f83, 0x609fe0cb, 0x77e0e5f9, 0xb8f7194c, 0xca1bee32, - 0x4e153fb8, 0xbdfd296f, 0xef87f4a3, 0x3df4ea0d, 0x795d6bdf, 0xe3e025e2, - 0x7467db22, 0x086e595f, 0xa31c6294, 0xe18975f3, 0xf1e667f9, 0x418a6f1d, - 0xa18036fd, 0x9ddcc49d, 0x6e3ee26f, 0xad438bdd, 0x81efae78, 0x07787ffd, - 0x27d85fbf, 0xf0e6bc51, 0xd891b3fe, 0xc29797cf, 0xe90a30e9, 0x7cd7c845, - 0x0d7e502b, 0x6773c77c, 0xca4af793, 0xa46d67bb, 0x554cbeef, 0x2fba3ef3, - 0xd7b3deed, 0xb85a7880, 0x7f7d2f7b, 0xf35af81d, 0xcd76f77d, 0x87d62b77, - 0x47cea174, 0xf7cf8571, 0xa9f9fdab, 0x7f2a4d7e, 0xddf3fe3f, 0x418e5647, - 0x6ab7bc7d, 0x17b5c600, 0x3b1139ee, 0xf1f007fb, 0x66cf4bd5, 0x3da81ea2, - 0xd1e72920, 0x07b57f78, 0xcf9e4af4, 0x6f7526bf, 0x63379e29, 0xb3ba047b, - 0x4f5b25f4, 0xee16c4e7, 0x728355df, 0xedc66176, 0xb57f8a7a, 0x83bc4a49, - 0x6350d3bf, 0x6baedc65, 0xdf123afb, 0xdb7dffa9, 0x1ef1ebd1, 0x23c1c774, - 0xc74c5ef4, 0x4fe3493e, 0xf1cb1d8d, 0xf72c763b, 0x77dcbeff, 0x09cf1224, - 0x8476d03e, 0xa7e75dc3, 0xf2561ff5, 0xbc12901d, 0xfeb44bf7, 0xcd2497f9, - 0xc0b801ef, 0xcdfba171, 0x7022d3fb, 0xf8db275d, 0x7d40d378, 0xd56a7950, - 0x1bff9c1c, 0xe53cf2f6, 0xddfa327d, 0xaeab8ea1, 0x767285db, 0xe7d49b61, - 0xd839f779, 0x98efcc2f, 0xebe9d39e, 0x1b1c2fa9, 0xc37f7004, 0x749b2035, - 0x62af5284, 0xa59bd72c, 0xea2a4f06, 0x47169391, 0xfdf9d204, 0x8811a1ae, - 0x6298c3df, 0xba49ebb9, 0x1f60be07, 0xb5a4ef1f, 0xeee9123d, 0x5211bee4, - 0x2dcbfef0, 0xe9ba7aca, 0x5e6f1bbb, 0x6fb553c2, 0xe9fb05bb, 0x9f2f1fc1, - 0xf54ad636, 0xb89df0df, 0x93aced05, 0xc0ddfc19, 0xfe460663, 0xdc3dc2f5, - 0x70793e4e, 0xfbe0f6f0, 0x7c14d359, 0x7df06474, 0xf5fb0bf5, 0x77dbbd4a, - 0x3d3d4d31, 0xed4ed7c7, 0x33beac7c, 0x5e7da10f, 0x6744b8f3, 0xf5f46a1d, - 0x4ffeb8b1, 0x57e769b7, 0x46b9c0ad, 0x0d8d8fef, 0x039ad7a2, 0x21637cdd, - 0xf2a03f3a, 0xa9f08389, 0x8664f1e2, 0xe765e7c4, 0xecd5f8ef, 0xdd7445dd, - 0xe3c4be3b, 0x31ef83b7, 0x74be2939, 0xb55a7f19, 0x2dfc821b, 0xbd23bdfa, - 0x989e686b, 0x9c1f63d2, 0x1a1f942e, 0x987e879b, 0x93ccfc9b, 0x185bec0c, - 0xebed16b3, 0x891dfa28, 0xd76e38cd, 0xffbd3d3e, 0xb03a6b5f, 0xef23df00, - 0xc0a30272, 0xe9b6bbbc, 0x4667dfbb, 0x629e773b, 0xf0ea7ee7, 0x7fa04be4, - 0xb489976b, 0x923d9abe, 0x5c17cf0f, 0x57dee450, 0x406f937b, 0x2e39ad7a, - 0x9a3fd159, 0x70fc96d8, 0x77e92e61, 0xdaeb57b2, 0xb75c9db8, 0x58bb205b, - 0x156a43b5, 0x629ce43b, 0xd65b9f07, 0x57e3edc9, 0xea11b604, 0x7b030dad, - 0x9b5de604, 0xdaec8539, 0xcadd695a, 0x473c0ec1, 0xe61bb5a5, 0xe7443c1f, - 0xd1cec0ae, 0xaddc2f94, 0x69b6d7cd, 0xf8bfaaf3, 0x3b6ed8d2, 0x37fa3863, - 0x1c615225, 0x0a9bc3f2, 0xe77f555e, 0xf49c6bce, 0xe80f27fb, 0xb8d4531c, - 0xd16bc204, 0xc7cc2f2b, 0xc26afb79, 0x347fe49c, 0xdae096fe, 0xd7ee17f1, - 0x1bdee074, 0xf0e333f2, 0xe9cfd8ed, 0xf05e917c, 0x2cbaefe1, 0xfd815d42, - 0x32df0499, 0xbb7b3b8c, 0x293e4922, 0xca1a08e7, 0x632affb9, 0xb2a6180c, - 0xe7f72c7e, 0x38eaf543, 0x0e8a405d, 0xb1811392, 0xd8af5429, 0xde57cfc0, - 0xfd24e119, 0xedc4c436, 0x6e2621f5, 0x75d10faf, 0x85dfa32e, 0x7df02418, - 0x6997ac8e, 0x9d6d60ff, 0x0417f685, 0xe10e957b, 0x955076b1, 0x887de90e, - 0xfd032db5, 0x8c5f353a, 0xec7b33df, 0x478b5283, 0x8cece387, 0x047d9417, - 0x74cb4fae, 0x90747d56, 0x996c657e, 0x3dea7e66, 0x7e7d9fcc, 0xa59f9856, - 0xef807e67, 0x75ff6c28, 0x86ec93ae, 0xf7f532a4, 0x2e49ea1a, 0x12fcf0a8, - 0x7018bde8, 0x816c7745, 0x1db66a6e, 0x96b2ff22, 0x76c4afb5, 0x1d7c91a5, - 0xbefe06a5, 0x4f186951, 0xfcb8e375, 0xa5d2512a, 0xc3f6b4e3, 0x7eb27191, - 0xc63ba41c, 0xf2e34db9, 0x79953f68, 0x6f0d7d61, 0x43d677f3, 0x13943ee5, - 0x7c0d7d3d, 0x466ff288, 0xd54d60bd, 0xbf9c69d8, 0x6ea2f116, 0xf6f85a3e, - 0xea27c493, 0xc66acc39, 0xa3667bf9, 0xc41a9ad9, 0xdf908b17, 0xc377ded0, - 0x138c7cbf, 0xeb6abff0, 0xe9973a7c, 0xa2b58c69, 0xfa48b75f, 0x7e25f692, - 0xda2ddf2c, 0xcdfbcdaf, 0x11fdfe9c, 0x1949f902, 0x0de3bae3, 0x0a498fc4, - 0x08f76c7f, 0xfb600e74, 0xcf1e3a77, 0x7e2810ab, 0x36143377, 0x624994da, - 0xba22eabd, 0xe333724f, 0x4b596347, 0x3dbbf28c, 0x796fb431, 0x9beeb293, - 0x2843fe75, 0xdbea8e57, 0x749e3192, 0xc4e4d6b4, 0x1b59cbfe, 0xc15a6fbd, - 0x153d29da, 0x9fa2f75e, 0x2226f73a, 0x63c9fddd, 0xf6d678a4, 0x50223be5, - 0xe5b167be, 0x044fdc56, 0xb7c6ec50, 0x73b3fb01, 0xd51df742, 0x2f60c4fb, - 0x027d21c7, 0x1d2127fe, 0xd8dc079c, 0x5fb77a73, 0x2317c7f8, 0x2c5f7f11, - 0x5b96e179, 0x9d5ffa19, 0xa82d47e4, 0x5df7465f, 0x33da9c81, 0xaaf07bf2, - 0x5bc55de2, 0xf01d5e37, 0xb0af182f, 0x938404a6, 0xc91965f4, 0xe8917fa5, - 0xf0e5d69c, 0xbc7dc2aa, 0x0e3b9f82, 0x8a15f970, 0xb70f156f, 0x43f5bbe2, - 0x236eef49, 0xc923313c, 0xb87a50cb, 0x3080be1c, 0xc4d93ce9, 0xa1f92318, - 0x4f2e4583, 0x2813cf07, 0xf33b795e, 0xf48012bc, 0xf5f7f096, 0xc70adefc, - 0xb782855b, 0x2fdf313f, 0x71ff9232, 0xce323b78, 0x606e34dd, 0xe50dbe6f, - 0xb2f8fed3, 0x37fce1c6, 0x18fa5f55, 0x3f0863f2, 0x376bf087, 0x2ff09d1e, - 0xc69e8f08, 0x6ecbe248, 0xae7b4b7c, 0x7fe22f4c, 0x5fb58e30, 0xaf93f9f0, - 0x46055f80, 0xf8f8bfbf, 0x54dead38, 0xa5c2a6f1, 0x07e0b8bf, 0x2ad47fcc, - 0xe70abed0, 0x748dbbe3, 0x57dd43ff, 0x5e4ff751, 0x5cf5c719, 0xd801fa68, - 0xb55fb84b, 0x40e4e326, 0x194f33b4, 0xfef87ed4, 0xdacb07ef, 0xb6f7f113, - 0xe9e2283e, 0xddff0329, 0x872f350f, 0x07e4b8f1, 0xc22f46f1, 0xf86103e9, - 0x1f33d404, 0xcf5cf708, 0x070671f3, 0x26e3cbe6, 0x53903de0, 0x798e357a, - 0xf07f12bf, 0x8f9479f1, 0x027aa62c, 0x074a5dff, 0xf61ddefe, 0x1736082b, - 0xbb83e7cc, 0x9d7de8d2, 0x718d7dee, 0x467f0edc, 0xdc774759, 0xe2815eff, - 0x355133fe, 0x84c4fee1, 0x877c2e2d, 0x437df4f3, 0xb4df69b3, 0xea3e3b41, - 0x978a64fd, 0xfee7e06e, 0xabea752e, 0xb75bf482, 0xc8be2dbe, 0xd1e4e7cb, - 0xbfa88cef, 0x86db2747, 0xc7dcff73, 0xd550df7f, 0x5fc75d67, 0x73c704b0, - 0xdfe2533f, 0x0fe1f9dd, 0xc3eb0526, 0x4dad4f43, 0x0daa7ec7, 0x05a72cde, - 0xb1ee877f, 0xaa5bb424, 0x4e955a9f, 0x0f53f4f6, 0x545fa3a4, 0xba6d63bd, - 0x0f70f94c, 0xbe3a65f9, 0x1b9e2fee, 0xd4f3e745, 0xdccaf6fe, 0x1d30a8af, - 0x3dbd412a, 0x56afeae5, 0xda41fee0, 0xffc5027d, 0x15f6b066, 0x332b67a8, - 0x16b15f38, 0xe87fc913, 0x776bf68f, 0x4ec5ff0d, 0x646f0794, 0x81cfd59c, - 0x203e127a, 0xd5df1035, 0xdfa3adf2, 0x7fcd5c09, 0x7ea7b027, 0x56ffed22, - 0x9de8172d, 0xfcf519ab, 0xf1a4f377, 0x59c704d1, 0xd18fb3ab, 0x794b57fb, - 0x6fa314f9, 0x67ec49df, 0x3fdf818b, 0xe094ee64, 0xb29270fb, 0x9d73385f, - 0xca717bf2, 0x639b6938, 0x53af07b7, 0x591df652, 0xdf2477ea, 0x32f0506e, - 0x5789e975, 0x54efd0ed, 0x1e3cc7bd, 0xe9b3bfbe, 0x619faa5c, 0x3a33f41c, - 0xf066985f, 0xd71f3a3c, 0x7148c3bd, 0xc1acdcd2, 0xcfd41c52, 0x11b45259, - 0xab4b99d3, 0x728f9d1e, 0xcd94d5b8, 0xf9f2358f, 0x114e0835, 0xed91f4e5, - 0xb842ceb7, 0x7fc4df9d, 0xfb61abff, 0xc2ddfa30, 0xafdee4fe, 0xf9eff89a, - 0xa264dd3d, 0x2b26d9f4, 0xcfeba3c3, 0xff29d935, 0x4a0e4daf, 0xcd3cf4d9, - 0xd7f4d8ef, 0xe14b88df, 0xb973bbf4, 0x3bf4cdab, 0x39460d88, 0x2bc03c75, - 0x1ddaaaed, 0xc2eb280f, 0xbdb2b8f7, 0x0e1113c9, 0x3e2c0fb9, 0x75b3a686, - 0x7d97df3c, 0x24eae4f3, 0x2c77d614, 0x7cc4f33d, 0x78fb7ef8, 0x270835f7, - 0x148bb6d3, 0x607238a7, 0xbbc22555, 0xaf91877a, 0xf9f7594f, 0x8f71e94d, - 0x75f97c62, 0x160dc53d, 0xc4f33b6d, 0x877f0c03, 0x9821b177, 0xbd74afde, - 0x7ee78f57, 0xaaf8e5e6, 0x78fc383f, 0x449b5abe, 0xf803b3fc, 0xf3a7f32a, - 0xcba5a2d5, 0xc6cb7e08, 0xb8426fbb, 0x937bd79d, 0x0fce9f90, 0xee744b1f, - 0xf820457d, 0xdbbc72ab, 0xbfe056af, 0x575b6c50, 0xc723dc98, 0x04b961bf, - 0x3e0743df, 0xf9fb474d, 0x3fe5fd9b, 0x6097eeb8, 0x1861fedd, 0x1a5133af, - 0xe0df3dfa, 0xf584ea19, 0x3ef3f7e5, 0x6af1d2e8, 0x539f9ffc, 0x36213fc0, - 0xe6219df8, 0xd4f9828d, 0x61fc141c, 0x26cfa859, 0xbf43a67d, 0x8fcffc11, - 0x198ce734, 0x9f4828fb, 0xcbdf37f7, 0x4fd875a5, 0x1ddc8f5a, 0xfcc89ef9, - 0x547b7a41, 0x83f98c20, 0x73f6edc6, 0xfb40cca0, 0x1724f14e, 0x2e786f10, - 0xe181c2ec, 0x99ff303b, 0xc2f1e381, 0xf14f604b, 0xf2931078, 0xd9f9d67b, - 0x50b22f81, 0xb7ae86ce, 0x882fe5ee, 0xaff66a3e, 0xfad028ba, 0xcba67f27, - 0x0ffafcba, 0x1645f53d, 0x7d33efe2, 0xb6fd1f20, 0x1640860b, 0xb7eea1e2, - 0x58ff9e5c, 0xf3e5a838, 0xf7e81b57, 0x1304eb3a, 0xf48949d1, 0x2e1fc525, - 0x87f1e71c, 0x924f03ba, 0xc83aed3c, 0xc48b40e3, 0x8c38d2f6, 0x399fd49b, - 0xcbacf286, 0xe831fdce, 0x2b71de9f, 0x41e8aa1c, 0xde12675d, 0x4dd83bf7, - 0x3c8fdc0f, 0x0c3bfc8f, 0xf3a369fb, 0x9c2b2cbd, 0x39f15da1, 0x7c30f3f2, - 0x257930bf, 0xdf79f9d2, 0x8f941cc0, 0xadfd666f, 0xbf86e28e, 0xb27ba70f, - 0xe6926db5, 0x3af7799c, 0x703f127c, 0x29fb54c4, 0xe7c1c99c, 0x1b8e0cb9, - 0x837e6ec8, 0xba2e13ef, 0x7b13f38a, 0xed53f399, 0x7b0643f2, 0x15bb7f50, - 0xc8ed527e, 0x1bffbf29, 0x85b3e5f1, 0xd504fd32, 0xffc7a54f, 0x4cf7fe9f, - 0x33412fff, 0x800063ec, 0x00008000, 0x00088b1f, 0x00000000, 0x5aa5ff00, - 0x5554700d, 0xbdef3e96, 0xdd2749fe, 0x12421349, 0x42068408, 0x03621a88, - 0xc4d67281, 0x206efce9, 0x6b01bb33, 0x8d08c42d, 0x749d2422, 0x6aece882, - 0x021a6eb9, 0x367564ac, 0x1d47598c, 0x809f9b47, 0x9476ec28, 0x0da0c040, - 0x6ba2cb0a, 0x3a26aa45, 0xab545b55, 0xa6e00eac, 0xd63b8223, 0x3be7b8e2, - 0x1dddb5ef, 0xa6ed4fe2, 0xee7dba8a, 0x9ee7b9cf, 0xce77ce7b, 0x52b48f3d, - 0x6a22ca22, 0x2a08cdcf, 0x6ea6ff0a, 0x6d4445a2, 0xf67f2429, 0xaf1f4541, - 0x7dbc64d3, 0x58c9a340, 0xce08eb93, 0x4754419e, 0x459a26dd, 0x654284b4, - 0x29bf71a4, 0x795bcbf2, 0x6d0dfebc, 0x61931741, 0xb06aad1b, 0x7aa6d513, - 0x1314360b, 0xaacaab0d, 0x0bcc6286, 0x4b9d2e95, 0x7efe0df4, 0x879b744a, - 0x2a224f99, 0xf60f14d3, 0x169c9d1b, 0x8b5dc9dc, 0x491bfb97, 0xeaa7984d, - 0x534f98f3, 0xa3827c08, 0xd81d4b25, 0x9964b468, 0x8eef3e23, 0x07d6d237, - 0xd2a14e31, 0xf9f6123b, 0x68858f4b, 0xcb17d121, 0x650faa17, 0xdaae79f2, - 0x51337403, 0x29ed768d, 0x70ddf785, 0x05564ccc, 0xafbc67fc, 0x670239f2, - 0xfa65ea34, 0x790a4752, 0x4bceccac, 0x1bcf0f1e, 0xd8293b99, 0x3f6fe7c5, - 0xe78990a0, 0xeeb11db5, 0x6d79e14c, 0x9bb648e6, 0xf036ddf7, 0xdb878b3b, - 0x2cf7fef6, 0xcf58b9ae, 0x9e433647, 0x6dfa1514, 0x174ff277, 0xce607f91, - 0x3f3177fb, 0xf44d69ff, 0x67bd37ed, 0x05d7d621, 0x5afd8f9e, 0x82d5f60e, - 0x56f0a56e, 0x3cfdda27, 0x9bbf48af, 0xe5dff86f, 0xb386575c, 0xf8be7e38, - 0xa7a25d39, 0x69f8bd18, 0xd602f73e, 0x43eb468b, 0x21ee5976, 0x6e717b96, - 0x252e8ece, 0x5fae9d71, 0x4b69768f, 0x9d15cb0e, 0x6615b8a9, 0x6c0d4d15, - 0x851f4276, 0x1797b38a, 0xb97f5f47, 0x9bf42d74, 0x9dbd2c12, 0x90b517cf, - 0xc7e2c7dc, 0x04b49bb6, 0x6a0f1679, 0x3443dc1e, 0xc90e9a95, 0xe2a77bbd, - 0x61bca83e, 0xd61267a9, 0x2b7bbe8d, 0x7955196f, 0x73fafdbd, 0x7975ca04, - 0xc9a9b0ce, 0xd7721b7d, 0x80ede5e7, 0xc400d9fe, 0xfaa94e8e, 0xc7951efe, - 0xbfd7c7e7, 0x46a79c68, 0xf089ce2b, 0x9dc506f8, 0x9f671ce3, 0xf587bb58, - 0xe9ef86be, 0xb46fbe45, 0x6938752f, 0xfda26ccd, 0xff42b91d, 0xda4b8773, - 0xf4914750, 0x16e1d2bf, 0x2dc760fa, 0xf0ea1f42, 0x51d03d08, 0x8ed1ed27, - 0x033fe906, 0x708cff51, 0xe2ec20a0, 0x4a6d7c14, 0x1cce1e9c, 0x9e494f43, - 0x24a99c3f, 0x991453d3, 0x3cb870ff, 0xa5fa6018, 0x939ca732, 0xc0d1ca8d, - 0x4b4e68fa, 0xb40ca12f, 0x674a41f9, 0x037bb1bb, 0x3ffbb61e, 0x43daedd4, - 0x4bcfc533, 0xf33aaf30, 0xdbf846ce, 0x692b2ce5, 0x1ec3cfac, 0xde63dfef, - 0x0555d3e9, 0x683fd1db, 0xfef95b73, 0x94dc5787, 0xff47bd01, 0xb78d234d, - 0xb05a28ae, 0x0ae994b9, 0xcc7622bb, 0xc86e6efc, 0x4fc6bb66, 0xb83553e6, - 0xe3a4d4ba, 0x02b67384, 0xc1aeb7fd, 0xdb261b3e, 0xfc795816, 0x57f7b94a, - 0xf7a627d8, 0x0aeb29da, 0xd98bd0bc, 0xf3cabef5, 0xa66eff02, 0x80f79e5e, - 0xdf649dc3, 0x822bcb47, 0x45c59bb0, 0x07cf36b3, 0xd9ba767f, 0xf5bb3fbc, - 0x51e7c87e, 0xc14e94d3, 0xb8099731, 0xf3fdc410, 0x452e953e, 0x716c30ec, - 0x7f993299, 0x2b22b538, 0x194eebc0, 0xb8da7df7, 0x7dc633ef, 0xd5fdc3bf, - 0xfdcbbedc, 0x1fb88768, 0x9e988aed, 0xd085a34d, 0x0da7f05f, 0xef44792f, - 0xa3a0f9a3, 0x3b0e5a66, 0xd33f025c, 0x81bf27f1, 0x5ca278e5, 0x036ee397, - 0x6b6e867f, 0x85d7d3e8, 0x858b4f84, 0x4bffb0bc, 0x9f609f58, 0xf5f175b1, - 0x9bb2ed24, 0xe7c29029, 0x20b6c3a0, 0x895344f4, 0x0ecb5f80, 0x692e08e7, - 0xcf8ab329, 0x017a644f, 0xabd29e09, 0xae5e7d56, 0x85fc216b, 0x8cfb2475, - 0x9980d504, 0x399fc4ed, 0xf2c99854, 0x167e188e, 0x49fd0fa3, 0xcff6fc13, - 0xd7db9a67, 0xfe7cfd14, 0x13854365, 0xa9b15eb0, 0x4eff33b0, 0xe1acfc7d, - 0x0699fe87, 0x943ce33f, 0x7dc7ca12, 0xce1d8f44, 0x2ee987bf, 0x1ead787b, - 0x8285c207, 0x5c2e14df, 0x42549c06, 0xd44dc8e7, 0xaf7dfc77, 0x47d027e9, - 0xfdd079e8, 0xd3af7fc7, 0x6739df4a, 0x50a4f8e2, 0xfd04e2be, 0x3df74181, - 0x409dc13f, 0x87395f9b, 0xdfa6cb71, 0x3327ab7b, 0xa783586e, 0xff37603b, - 0xed97dba2, 0xd027ff40, 0x2b11cb5b, 0x0f2b2ec1, 0x0af67ff4, 0x3bf4b78f, - 0xa8fb80dc, 0xbbe88667, 0xc7dec8f3, 0x7d236f61, 0xae87f166, 0xfe7bbffd, - 0x25679911, 0x35bd5b98, 0xcfbc4a54, 0xe37fe3d1, 0xb49f6135, 0x6fd015d0, - 0x39179c57, 0xfeea27ea, 0xa9f1543d, 0xf5bd0037, 0xc46bf81f, 0x0a0cfab5, - 0x65e96ec0, 0xe46647be, 0x6a86f57b, 0xc771e12a, 0x6ff04ad0, 0x86eac97b, - 0xcd5efa9d, 0x5f1f84a9, 0xfb14ccf3, 0x3bb1be6b, 0x3d57711f, 0x23cf6fba, - 0x23679859, 0xc99edbc8, 0xf57ac476, 0xdd163b69, 0x6bb7f72f, 0xf7206fcf, - 0x64ed1b3e, 0x03cccd3e, 0x99ef35fb, 0xd1f00c1d, 0xe3fafb5e, 0x1a87b895, - 0xe83db9ed, 0xa6dbb2bf, 0x2d670f42, 0xf8728c9e, 0xbbb359e1, 0xba0ceb17, - 0x2ea27879, 0x56a45a4f, 0x3bab2fee, 0x37d7711f, 0x80bfe1f1, 0xf75af5dc, - 0x3ce2cff3, 0x3884ad7b, 0xeb1f6171, 0xe85dd78d, 0x2dc7cf35, 0x9873ec8f, - 0x94972f60, 0x82cf95ee, 0xef3eaf7f, 0xf45bad92, 0x439de819, 0x11e78fd8, - 0x6525f2e2, 0x85ff527b, 0x5e25bdde, 0x97c5dfd6, 0x09bd8bea, 0x17f31bf6, - 0x526b6edf, 0x6024147c, 0xbf19f25c, 0x3b2019c9, 0x8366dfc7, 0x99e878bc, - 0xbe296791, 0x737ee2fe, 0x6a3ac2d8, 0x94e6d2b6, 0xf83fb8cc, 0x0ebcfef2, - 0x3ba9f3e7, 0x34c7910a, 0x84ac882f, 0x51b05c5f, 0x7bcf2e4a, 0xbe5f88db, - 0x2a971b83, 0x4f2ddf25, 0xc7ee854d, 0x38f57357, 0x16c07576, 0x1ddf280c, - 0x83a3fe8f, 0x8eccef9c, 0x67af77d3, 0x7e71297e, 0xad425b6f, 0x2db7de6e, - 0x738fc753, 0xe33f7f3c, 0xcfb19558, 0xe79287aa, 0x299152df, 0x8966d3f6, - 0xc60e2214, 0x88ac2ff8, 0x10a45ae1, 0x5d763578, 0xe013d23d, 0xe08acbc8, - 0xf2a0ef88, 0xa86e96a1, 0x4fae3b34, 0xa8204a5f, 0x0f7f8c95, 0x7b8c8bb9, - 0x55ef5e60, 0xdbe57ee8, 0x98d8f36f, 0x246a4b4f, 0xab53791d, 0x7c8e9223, - 0x46a8e468, 0xcbeb8d3b, 0x199ff18a, 0x4649afdf, 0xf6643fb8, 0x8fdbc6d8, - 0x6f3c438f, 0x2ab37e1d, 0xfdd0a93e, 0x4d2069a6, 0x646723f6, 0xe9b6ec11, - 0x3875e4b9, 0x1fc133a7, 0x65760647, 0x8fe2137b, 0xaa3b90cf, 0x137e287c, - 0x7ca3fafd, 0xa54f81d8, 0xf6ab0acd, 0x65b1af22, 0x3a294d0a, 0xe5b1b01d, - 0xa7b4befb, 0x5e2e7ec2, 0x1e3f156d, 0x73822251, 0x0aae27b9, 0x23988c3e, - 0xca8e7382, 0x18fc11ff, 0x09591099, 0xb4adcadc, 0xc9f196af, 0x1e2e9591, - 0xa0c2b2ff, 0x03e491a7, 0x57322785, 0xb5ea4f03, 0x3711b7d1, 0x09d99769, - 0x7be9893f, 0xa227a19d, 0x783b86c7, 0xb3410ffc, 0x4e61f10b, 0x0be462a5, - 0xb5f9f896, 0x908d3fb8, 0xf841c0eb, 0xdddd9367, 0xfdc1a32b, 0xbc1f20af, - 0xe5dddb33, 0x326f5eba, 0xcacae587, 0xee2d6afc, 0xfbdd3b29, 0xdfcc158f, - 0x07c91c5f, 0x4bb5b1ce, 0xdd7b6a1c, 0x47fb13ba, 0x807ba3cd, 0xde1c175f, - 0x9f582b27, 0xada196ad, 0x67d22ca5, 0xa429c8e6, 0x6f604bf8, 0xbdba2382, - 0xb2ef148d, 0x561e9f08, 0x9767eb2a, 0x4b940f71, 0xa1f603b4, 0xe6fcf7e8, - 0x00efabc0, 0x6686466f, 0xf58f4e09, 0x4f030ba7, 0x3e3703a6, 0x981ef8e0, - 0x60ffef13, 0xfa0b5ef5, 0xc3b8bf97, 0x9ef6e112, 0xbbe7c9cd, 0x0cf6ed7c, - 0x9e3d0bf8, 0xec7b0fd0, 0xeac7a649, 0x4e197605, 0xe88083f2, 0x29c79cfd, - 0x0e54b7f2, 0xdf0f41b5, 0xd698cbd2, 0x6313e812, 0xa9f331e8, 0xce1fcf41, - 0xb6f84879, 0x430f0b4e, 0xcc07236f, 0xe4ef7c04, 0x7f7426b8, 0x1aef105a, - 0xadc700f5, 0x216e3d2c, 0x0fa4b45e, 0x8cbdc4ad, 0x989d5bf4, 0xa7c8e9bf, - 0xdb3f38f9, 0xdbce3e63, 0x3670e472, 0xf78dcec1, 0x6cc7c704, 0x1ff4b78c, - 0x24bbc6c9, 0x86aadfd6, 0x4717210a, 0x47e012b8, 0x85afdfac, 0x8b7f210b, - 0xf1825432, 0xf996e428, 0x49a06b4c, 0xe8aad1ce, 0x34474f7e, 0xf7b1f9c1, - 0x6e8551f6, 0x250f8caf, 0x1d3707c8, 0xb11254bd, 0xd9a0f1c7, 0xe81395c0, - 0xdffdd62f, 0x09c0c8b9, 0xbf0cda5e, 0xbc27071f, 0xf5a3dc31, 0xae7dc816, - 0xb63b9742, 0x3bcaf85e, 0x6de32023, 0x992a5daf, 0xc6758c59, 0xa3c04a3c, - 0x017c7159, 0x0e0ae40e, 0xf367326c, 0x2bcf7cb9, 0xd25e4eee, 0x96b1b8dc, - 0xd33ad3a7, 0x6bd0b5fd, 0x5de40513, 0xb1ae5637, 0x8570f476, 0x553ebf7e, - 0xf6fb8f7f, 0x964ec128, 0x7d6322eb, 0x9bc17cee, 0x5d67f030, 0xf85ac6f5, - 0x7e597ddf, 0xf9bbe24b, 0xedaff887, 0xadd7a649, 0x339b58df, 0x1efb9f8e, - 0x126a7eda, 0xd9afcf5d, 0xdb36a3bb, 0x4c7f7d75, 0x98b68bee, 0x49e6959c, - 0xbe58fa89, 0xb71276b1, 0xaffe52eb, 0x7dcfd0fa, 0x8c3588f1, 0xb5facbb8, - 0xfdb7fce0, 0x0925bd71, 0x5f807fb7, 0x9d6b0533, 0xfe5bbe33, 0x12ab6db1, - 0x4f80561e, 0xe2bd5fec, 0x0937ec67, 0x18aa6dfb, 0x5a68a753, 0x37791d3d, - 0x4f4f5779, 0x6d8c53ac, 0xa8a72819, 0x49bd88b7, 0xd2b87ecb, 0x623e8e3d, - 0xd4ae6ff3, 0x864d9f64, 0x6fa94f1d, 0x1e15e679, 0x53ccb97f, 0x557ec956, - 0xbf92a9ae, 0xa6a7dd8f, 0x860fcf52, 0x80bf1db2, 0xcd07453d, 0xb949f84e, - 0x4f33eba6, 0xfc2efcbd, 0xe1db2f31, 0x357e64ea, 0xbcfa6955, 0xea273663, - 0x5f63d140, 0xffe07be5, 0xa5cbec5b, 0xd3b262ce, 0x953f1e64, 0x3df0573b, - 0xc6c7cfb6, 0x7aa5693e, 0x645ed3be, 0x533afefe, 0x3adbe3b1, 0xc51be493, - 0x12d9c169, 0xf890bf87, 0xe85c1d16, 0xf7c05cd4, 0xd6fe1da0, 0x677ff5fe, - 0x0c8f0e23, 0x0bba67fe, 0xd3ed75b8, 0xb6cfd874, 0x81d38f81, 0x6606270f, - 0x1d9ed039, 0x1fd03972, 0x16b8fbad, 0x368cbaf3, 0x8b30675e, 0xf636b19c, - 0x13d58e7e, 0xcdd1de12, 0x73af6bd0, 0x614b2fdb, 0x82dda9ef, 0xce8efc63, - 0xd788fc44, 0xe3395c19, 0xeb1265d5, 0xf5b3050c, 0xd45a033a, 0x7acc0a19, - 0xea34019d, 0x6751680c, 0x0cea3f40, 0x006751a0, 0x68033a8d, 0xa2d019d4, - 0x2bfe80ce, 0xbcb16ba8, 0x50de4e51, 0xecd1aadf, 0xf40fff82, 0xf5e4416a, - 0x74d31c0f, 0xc412877a, 0xfbc67f7d, 0xaf460e23, 0x28b075e8, 0xe77953c7, - 0xfbcb341f, 0x5eda1a20, 0xd6f71337, 0x5571b9af, 0xd9371117, 0xa3cddb14, - 0x6a1f5127, 0x1bdc53ef, 0x2e5fe85d, 0x5c1b6c72, 0xfa237ef8, 0xd56ecd7b, - 0x9abafb85, 0x6f97fa8d, 0x58ea57b0, 0x2cc739d5, 0x15fbcf72, 0xeffde1ca, - 0x64efeab0, 0x2cbdc6bf, 0x9545b0f7, 0x1d6fda3c, 0xcb4bf792, 0x4d738a8b, - 0x7eda1e42, 0x1382e7cb, 0x9df4b69d, 0xb21fd790, 0xc524d739, 0x7de48f57, - 0xc174fc7e, 0x45433c8d, 0xa7d5af4c, 0x7b5edf90, 0xf9213801, 0xb47e4248, - 0x33fcd9d6, 0x5da467e4, 0x7efce133, 0x644ee87e, 0x6d3dd6f9, 0xb09228fe, - 0x9930737f, 0x6df60df6, 0x99c823cd, 0x034a8fdc, 0x943fb2e2, 0x74aa1fdc, - 0xc6927d64, 0x3cd1e63f, 0xff755be4, 0x3f40e6b4, 0xdbb977ef, 0x61caf92a, - 0x2570f78f, 0xb349f1fb, 0x272fea47, 0xbde4d98f, 0x9cfb7e75, 0x8d4bfaa4, - 0x1fea5536, 0xc48acc1b, 0xdee52bf1, 0xaacbb063, 0xeea57bba, 0x10eb9552, - 0xe1d98e7f, 0x3786f2d1, 0x5cc377c0, 0x6abfd497, 0xe10bf4ac, 0xf72f7ec7, - 0x7f16683c, 0x8254e9ab, 0xc9abd32a, 0xad7f816d, 0x3d8a7562, 0x298fed99, - 0x78ab0fec, 0xbb04c6af, 0x915db0da, 0x100a42bc, 0x8695e7ac, 0xfe0d573e, - 0xfb0a57eb, 0x3d56bdcb, 0x5553ce0f, 0xc5d79fe1, 0xdfe78b71, 0xfc0b5e47, - 0x55c71d66, 0x5f671cb4, 0x37bf708f, 0x9ebe6a6d, 0xc072bbe7, 0x3319f57f, - 0x726a4f01, 0x95e85e7e, 0xfced5f78, 0x095bef84, 0x737da5df, 0xa8e1f7d3, - 0xc8493e89, 0x759a4f6b, 0xca7d61fc, 0xec14eb7b, 0x5e3eea55, 0x3474cf69, - 0x8ca2bb49, 0x340bffc4, 0xe02f6f3d, 0x4a6672bb, 0xeb0fa2dd, 0x6eedda6b, - 0x0b863fe8, 0xbefc8dbb, 0xe796e540, 0x5bd54eed, 0xdc29d30b, 0xca5b8d3f, - 0xe7617e14, 0x5c71d47c, 0x3d4f3fc2, 0x7d05c0bb, 0x4377697c, 0xc739351f, - 0x31dde1e6, 0x72ffe0cb, 0xdc55c359, 0x029d2797, 0x438f9fd8, 0x5adfacdd, - 0x5d41481c, 0x50d1e43d, 0x38a63f27, 0x1ebfaef1, 0x716fb74f, 0x140acfc2, - 0xb5b7ea27, 0xd935dda9, 0xe676bfcc, 0x9cf0370c, 0x61ea55f1, 0x76eadc23, - 0x53506b70, 0x6ca6b5f4, 0xff0df3d4, 0x54a6f729, 0xd7f78a4d, 0x1d147e1b, - 0xf11d22fc, 0x6dd447f5, 0x807f8377, 0x835eee6c, 0xfea0ec3f, 0xbf5269a6, - 0xe5d1d98d, 0x613b39fd, 0xf4ab5347, 0xef8d8d75, 0x0c4f9199, 0xc1cde6dd, - 0x7cd72bfe, 0xce5b25be, 0x8cbd7e39, 0xb8033771, 0x165eb63b, 0x463df1c3, - 0x6b781dfd, 0x26baea32, 0x326baea3, 0xa326baea, 0xea326bae, 0xaea326ba, - 0xbaea326b, 0x6baea326, 0x26baea32, 0x97ae13a9, 0x878eddf6, 0x08ea1da4, - 0xbc4278c8, 0xc7eab9b8, 0x55175dd5, 0xa577538d, 0xc4865714, 0xbd7bf65d, - 0xcea63dde, 0x26aefeca, 0xe0d57bf8, 0x431e7b84, 0x7163d25e, 0x6b5438b3, - 0x603c16f1, 0x54f07c17, 0x8d6f5b8d, 0xf52ecfe9, 0x9b64cbd9, 0x2ca87b8f, - 0x5152659a, 0x23ee34c7, 0xdf84ef56, 0x1bf09ce0, 0xd31bf0b4, 0xfcdfb8ec, - 0x5daec2d6, 0x0109e7aa, 0x726c13c9, 0x32375bbf, 0x2f7d30ae, 0xe5709339, - 0xc2b831b3, 0x90159a0f, 0x95a0ed63, 0x233f74ba, 0x37254ff8, 0x0e3f9c7f, - 0x9c7484ce, 0xda1a9699, 0xb5a67d87, 0x1791baa5, 0x9d8bbfb3, 0x88a6dc9d, - 0x06a1afbf, 0xbc1c77d9, 0x7c9e4749, 0x73d1c4ef, 0xf7f9e1bf, 0xf25d83fe, - 0xd793ad9d, 0xe0fffa2e, 0xae954d4d, 0x84775f8f, 0x9659e77d, 0x43b654ea, - 0x16d5578e, 0xb8ba922a, 0x50fe2a9a, 0x58ae3da3, 0xd377a380, 0xb577dc3c, - 0xc839e1b5, 0x2efec399, 0xa32cdfef, 0x6a1a6bbe, 0xd9f4cbde, 0xbe373cec, - 0x3dcd4dab, 0x800b0544, 0xb0c57547, 0xadd4b3ab, 0x1963dd60, 0xbf83bfde, - 0xa7cc5edc, 0x96fee356, 0xb3b69753, 0xce63ee4b, 0x32fbdc42, 0xf51fabab, - 0x9e6f2d86, 0xb2c27a90, 0xd442d70c, 0x79bcb61b, 0x5c73a75a, 0xe51b8afd, - 0xabab13b2, 0x66f8827f, 0x109f3eeb, 0x09a1fd67, 0xc0fb7449, 0x09f3eee4, - 0x3f05ae71, 0x3f4e9df8, 0xafb84c53, 0x5c944356, 0xf21dbbd5, 0x4bfeebf9, - 0xa8d3cf7f, 0xaaa7c9c4, 0x749c5c74, 0xe7b0c282, 0xf90ec5d1, 0x713397fe, - 0xdbd43cfd, 0x10b5d8a8, 0xfdaf38f3, 0xe2f8ec35, 0xc1a79ead, 0x7738cf27, - 0x3579f10e, 0x0d90c758, 0xbbe319ed, 0xdbd529e4, 0x3d36b688, 0x357e9260, - 0x6df68a58, 0xfa20f435, 0x81762fd9, 0xf393ed4f, 0x3a622c6e, 0xb79a1acf, - 0xe9788ede, 0x73fe8dd9, 0xec5e9e65, 0xdfeeb637, 0xe58f9c69, 0xc37987d9, - 0xf9e4aa85, 0x6dea37c3, 0x55c22ecc, 0x371d0e3a, 0x93aca8fc, 0x58e7fbe4, - 0xa55e39fb, 0xfdf9781a, 0x47bcb372, 0x7e4c4f20, 0x0a5d5eea, 0xa3de5879, - 0x61afbc86, 0x5299ec9c, 0x7b6ef98f, 0xc77ec80d, 0x7c653b0d, 0xe3af396c, - 0xa685b4a3, 0x0de404e0, 0x4e0d1e53, 0x7653bc80, 0xdc5cda8c, 0xb51810be, - 0xe1787f21, 0xe86d476f, 0x7543c17f, 0x56bfe1e3, 0xc2df09ad, 0x3f5951b2, - 0x921af79d, 0x04e8c277, 0x4d856fe4, 0x6c02596f, 0xe69e73b7, 0xb7f2937d, - 0xd3638922, 0xfe9a5b0d, 0x87b04aa8, 0xe490cfe9, 0x259d54ab, 0xdd14bee3, - 0x3e8f7dff, 0x6e8ec2a8, 0x09dcb208, 0x69e737f6, 0x1248e5d3, 0x6bacb0df, - 0xf3837031, 0x3f71a4b5, 0x3cbe4733, 0xe423c0c5, 0x378c8d8f, 0xbeb7a6fe, - 0x79c8be42, 0x8c7e18dc, 0x261c314d, 0xebef5dc4, 0x20fc1711, 0xbbdade79, - 0xf78ad91e, 0x76e3536d, 0xd78fbc8b, 0xdb456df4, 0x259efada, 0x4cbf2487, - 0x65f9cf9a, 0x9c9d7d12, 0x7b68e463, 0x39adf3f0, 0x76cbece3, 0x0ed12d70, - 0x37439a4e, 0xd27abde0, 0x480eea9f, 0x0fdd091c, 0x6ad9d97c, 0xecae2377, - 0xd8a555fa, 0xa9f5b7d7, 0xfaa98f32, 0xa751d947, 0x52540fcc, 0x87e6fc11, - 0xe1e011da, 0x0c3c24ec, 0x8972dd48, 0xddae7043, 0xadb60778, 0x123e4a71, - 0x5336ebf3, 0x98adc3e8, 0xef90e597, 0x45b70c11, 0x6f7c2ca6, 0x4aeee29a, - 0x2ece2bc8, 0x9d041599, 0x830a19dd, 0x15cfe8ef, 0xd5c8ea37, 0xd6ae3a69, - 0x7bad0da8, 0x352dfc79, 0x5bf1b82c, 0x6ff307e0, 0x7697acb7, 0xb14cd945, - 0x290a5cdb, 0x7067fffa, 0x3d7bc42d, 0x67ad3df6, 0x20efb05b, 0xf04afbde, - 0x8fa8b599, 0xe45d95fe, 0x80d50689, 0x33d3cf99, 0x7bb70481, 0xb8942cee, - 0xc686a513, 0x2cff91fb, 0x6a3a954f, 0x13d704cf, 0xd3da6ef8, 0xf5e4a37c, - 0xc7a4fe87, 0x29a5d1fb, 0x3d71e46e, 0x711b5cf3, 0x5d479eae, 0xa29afe32, - 0xa13c0bf3, 0xa967a7eb, 0xe69ece7e, 0xc59f794c, 0x8767a1ee, 0xbfbe3267, - 0xe5bc3259, 0x1803a8d5, 0x667b1fdf, 0x4fb73f70, 0xde770d29, 0x75733e07, - 0xb9945779, 0xde4edee4, 0x7b13e379, 0xf1867d74, 0x897dac1d, 0xfefde923, - 0xcb80febf, 0x002220b3, 0x00000000 -}; - -#endif /*__BNX2X_INIT_VALUES_H__*/ diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index ad5ef25add3e..fbf1352e9c1c 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -53,12 +53,19 @@ #include "bnx2x.h" #include "bnx2x_init.h" +#include "bnx2x_init_ops.h" #include "bnx2x_dump.h" -#define DRV_MODULE_VERSION "1.48.105" -#define DRV_MODULE_RELDATE "2009/03/02" +#define DRV_MODULE_VERSION "1.48.105-1" +#define DRV_MODULE_RELDATE "2009/04/22" #define BNX2X_BC_VER 0x040200 +#include +#include "bnx2x_fw_file_hdr.h" +/* FW files */ +#define FW_FILE_PREFIX_E1 "bnx2x-e1-" +#define FW_FILE_PREFIX_E1H "bnx2x-e1h-" + /* Time in jiffies before concluding the transmitter is hung */ #define TX_TIMEOUT (5*HZ) @@ -1539,7 +1546,7 @@ static int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget) len, cqe, comp_ring_cons); #ifdef BNX2X_STOP_ON_ERROR if (bp->panic) - return -EINVAL; + return 0; #endif bnx2x_update_sge_prod(fp, @@ -5232,13 +5239,15 @@ static void bnx2x_gunzip_end(struct bnx2x *bp) } } -static int bnx2x_gunzip(struct bnx2x *bp, u8 *zbuf, int len) +static int bnx2x_gunzip(struct bnx2x *bp, const u8 *zbuf, int len) { int n, rc; /* check gzip header */ - if ((zbuf[0] != 0x1f) || (zbuf[1] != 0x8b) || (zbuf[2] != Z_DEFLATED)) + if ((zbuf[0] != 0x1f) || (zbuf[1] != 0x8b) || (zbuf[2] != Z_DEFLATED)) { + BNX2X_ERR("Bad gzip header\n"); return -EINVAL; + } n = 10; @@ -5247,7 +5256,7 @@ static int bnx2x_gunzip(struct bnx2x *bp, u8 *zbuf, int len) if (zbuf[3] & FNAME) while ((zbuf[n++] != 0) && (n < len)); - bp->strm->next_in = zbuf + n; + bp->strm->next_in = (typeof(bp->strm->next_in))zbuf + n; bp->strm->avail_in = len - n; bp->strm->next_out = bp->gunzip_buf; bp->strm->avail_out = FW_BUF_SIZE; @@ -5369,8 +5378,8 @@ static int bnx2x_int_mem_test(struct bnx2x *bp) msleep(50); REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET, 0x03); msleep(50); - bnx2x_init_block(bp, BRB1_COMMON_START, BRB1_COMMON_END); - bnx2x_init_block(bp, PRS_COMMON_START, PRS_COMMON_END); + bnx2x_init_block(bp, BRB1_BLOCK, COMMON_STAGE); + bnx2x_init_block(bp, PRS_BLOCK, COMMON_STAGE); DP(NETIF_MSG_HW, "part2\n"); @@ -5434,8 +5443,8 @@ static int bnx2x_int_mem_test(struct bnx2x *bp) msleep(50); REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET, 0x03); msleep(50); - bnx2x_init_block(bp, BRB1_COMMON_START, BRB1_COMMON_END); - bnx2x_init_block(bp, PRS_COMMON_START, PRS_COMMON_END); + bnx2x_init_block(bp, BRB1_BLOCK, COMMON_STAGE); + bnx2x_init_block(bp, PRS_BLOCK, COMMON_STAGE); #ifndef BCM_ISCSI /* set NIC mode */ REG_WR(bp, PRS_REG_NIC_MODE, 1); @@ -5510,7 +5519,7 @@ static int bnx2x_init_common(struct bnx2x *bp) REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET, 0xffffffff); REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET, 0xfffc); - bnx2x_init_block(bp, MISC_COMMON_START, MISC_COMMON_END); + bnx2x_init_block(bp, MISC_BLOCK, COMMON_STAGE); if (CHIP_IS_E1H(bp)) REG_WR(bp, MISC_REG_E1HMF_MODE, IS_E1HMF(bp)); @@ -5518,14 +5527,14 @@ static int bnx2x_init_common(struct bnx2x *bp) msleep(30); REG_WR(bp, MISC_REG_LCPLL_CTRL_REG_2, 0x0); - bnx2x_init_block(bp, PXP_COMMON_START, PXP_COMMON_END); + bnx2x_init_block(bp, PXP_BLOCK, COMMON_STAGE); if (CHIP_IS_E1(bp)) { /* enable HW interrupt from PXP on USDM overflow bit 16 on INT_MASK_0 */ REG_WR(bp, PXP_REG_PXP_INT_MASK_0, 0); } - bnx2x_init_block(bp, PXP2_COMMON_START, PXP2_COMMON_END); + bnx2x_init_block(bp, PXP2_BLOCK, COMMON_STAGE); bnx2x_init_pxp(bp); #ifdef __BIG_ENDIAN @@ -5571,60 +5580,60 @@ static int bnx2x_init_common(struct bnx2x *bp) REG_WR(bp, PXP2_REG_RQ_DISABLE_INPUTS, 0); REG_WR(bp, PXP2_REG_RD_DISABLE_INPUTS, 0); - bnx2x_init_block(bp, DMAE_COMMON_START, DMAE_COMMON_END); + bnx2x_init_block(bp, DMAE_BLOCK, COMMON_STAGE); /* clean the DMAE memory */ bp->dmae_ready = 1; bnx2x_init_fill(bp, TSEM_REG_PRAM, 0, 8); - bnx2x_init_block(bp, TCM_COMMON_START, TCM_COMMON_END); - bnx2x_init_block(bp, UCM_COMMON_START, UCM_COMMON_END); - bnx2x_init_block(bp, CCM_COMMON_START, CCM_COMMON_END); - bnx2x_init_block(bp, XCM_COMMON_START, XCM_COMMON_END); + bnx2x_init_block(bp, TCM_BLOCK, COMMON_STAGE); + bnx2x_init_block(bp, UCM_BLOCK, COMMON_STAGE); + bnx2x_init_block(bp, CCM_BLOCK, COMMON_STAGE); + bnx2x_init_block(bp, XCM_BLOCK, COMMON_STAGE); bnx2x_read_dmae(bp, XSEM_REG_PASSIVE_BUFFER, 3); bnx2x_read_dmae(bp, CSEM_REG_PASSIVE_BUFFER, 3); bnx2x_read_dmae(bp, TSEM_REG_PASSIVE_BUFFER, 3); bnx2x_read_dmae(bp, USEM_REG_PASSIVE_BUFFER, 3); - bnx2x_init_block(bp, QM_COMMON_START, QM_COMMON_END); + bnx2x_init_block(bp, QM_BLOCK, COMMON_STAGE); /* soft reset pulse */ REG_WR(bp, QM_REG_SOFT_RESET, 1); REG_WR(bp, QM_REG_SOFT_RESET, 0); #ifdef BCM_ISCSI - bnx2x_init_block(bp, TIMERS_COMMON_START, TIMERS_COMMON_END); + bnx2x_init_block(bp, TIMERS_BLOCK, COMMON_STAGE); #endif - bnx2x_init_block(bp, DQ_COMMON_START, DQ_COMMON_END); + bnx2x_init_block(bp, DQ_BLOCK, COMMON_STAGE); REG_WR(bp, DORQ_REG_DPM_CID_OFST, BCM_PAGE_SHIFT); if (!CHIP_REV_IS_SLOW(bp)) { /* enable hw interrupt from doorbell Q */ REG_WR(bp, DORQ_REG_DORQ_INT_MASK, 0); } - bnx2x_init_block(bp, BRB1_COMMON_START, BRB1_COMMON_END); - bnx2x_init_block(bp, PRS_COMMON_START, PRS_COMMON_END); + bnx2x_init_block(bp, BRB1_BLOCK, COMMON_STAGE); + bnx2x_init_block(bp, PRS_BLOCK, COMMON_STAGE); REG_WR(bp, PRS_REG_A_PRSU_20, 0xf); /* set NIC mode */ REG_WR(bp, PRS_REG_NIC_MODE, 1); if (CHIP_IS_E1H(bp)) REG_WR(bp, PRS_REG_E1HOV_MODE, IS_E1HMF(bp)); - bnx2x_init_block(bp, TSDM_COMMON_START, TSDM_COMMON_END); - bnx2x_init_block(bp, CSDM_COMMON_START, CSDM_COMMON_END); - bnx2x_init_block(bp, USDM_COMMON_START, USDM_COMMON_END); - bnx2x_init_block(bp, XSDM_COMMON_START, XSDM_COMMON_END); + bnx2x_init_block(bp, TSDM_BLOCK, COMMON_STAGE); + bnx2x_init_block(bp, CSDM_BLOCK, COMMON_STAGE); + bnx2x_init_block(bp, USDM_BLOCK, COMMON_STAGE); + bnx2x_init_block(bp, XSDM_BLOCK, COMMON_STAGE); bnx2x_init_fill(bp, TSTORM_INTMEM_ADDR, 0, STORM_INTMEM_SIZE(bp)); bnx2x_init_fill(bp, USTORM_INTMEM_ADDR, 0, STORM_INTMEM_SIZE(bp)); bnx2x_init_fill(bp, CSTORM_INTMEM_ADDR, 0, STORM_INTMEM_SIZE(bp)); bnx2x_init_fill(bp, XSTORM_INTMEM_ADDR, 0, STORM_INTMEM_SIZE(bp)); - bnx2x_init_block(bp, TSEM_COMMON_START, TSEM_COMMON_END); - bnx2x_init_block(bp, USEM_COMMON_START, USEM_COMMON_END); - bnx2x_init_block(bp, CSEM_COMMON_START, CSEM_COMMON_END); - bnx2x_init_block(bp, XSEM_COMMON_START, XSEM_COMMON_END); + bnx2x_init_block(bp, TSEM_BLOCK, COMMON_STAGE); + bnx2x_init_block(bp, USEM_BLOCK, COMMON_STAGE); + bnx2x_init_block(bp, CSEM_BLOCK, COMMON_STAGE); + bnx2x_init_block(bp, XSEM_BLOCK, COMMON_STAGE); /* sync semi rtc */ REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR, @@ -5632,16 +5641,16 @@ static int bnx2x_init_common(struct bnx2x *bp) REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET, 0x80000000); - bnx2x_init_block(bp, UPB_COMMON_START, UPB_COMMON_END); - bnx2x_init_block(bp, XPB_COMMON_START, XPB_COMMON_END); - bnx2x_init_block(bp, PBF_COMMON_START, PBF_COMMON_END); + bnx2x_init_block(bp, UPB_BLOCK, COMMON_STAGE); + bnx2x_init_block(bp, XPB_BLOCK, COMMON_STAGE); + bnx2x_init_block(bp, PBF_BLOCK, COMMON_STAGE); REG_WR(bp, SRC_REG_SOFT_RST, 1); for (i = SRC_REG_KEYRSS0_0; i <= SRC_REG_KEYRSS1_9; i += 4) { REG_WR(bp, i, 0xc0cac01a); /* TODO: replace with something meaningful */ } - bnx2x_init_block(bp, SRCH_COMMON_START, SRCH_COMMON_END); + bnx2x_init_block(bp, SRCH_BLOCK, COMMON_STAGE); REG_WR(bp, SRC_REG_SOFT_RST, 0); if (sizeof(union cdu_context) != 1024) @@ -5649,7 +5658,7 @@ static int bnx2x_init_common(struct bnx2x *bp) printk(KERN_ALERT PFX "please adjust the size of" " cdu_context(%ld)\n", (long)sizeof(union cdu_context)); - bnx2x_init_block(bp, CDU_COMMON_START, CDU_COMMON_END); + bnx2x_init_block(bp, CDU_BLOCK, COMMON_STAGE); val = (4 << 24) + (0 << 12) + 1024; REG_WR(bp, CDU_REG_CDU_GLOBAL_PARAMS, val); if (CHIP_IS_E1(bp)) { @@ -5658,7 +5667,7 @@ static int bnx2x_init_common(struct bnx2x *bp) REG_WR(bp, CDU_REG_CDU_DEBUG, 0); } - bnx2x_init_block(bp, CFC_COMMON_START, CFC_COMMON_END); + bnx2x_init_block(bp, CFC_BLOCK, COMMON_STAGE); REG_WR(bp, CFC_REG_INIT_REG, 0x7FF); /* enable context validation interrupt from CFC */ REG_WR(bp, CFC_REG_CFC_INT_MASK, 0); @@ -5666,20 +5675,25 @@ static int bnx2x_init_common(struct bnx2x *bp) /* set the thresholds to prevent CFC/CDU race */ REG_WR(bp, CFC_REG_DEBUG0, 0x20020000); - bnx2x_init_block(bp, HC_COMMON_START, HC_COMMON_END); - bnx2x_init_block(bp, MISC_AEU_COMMON_START, MISC_AEU_COMMON_END); + bnx2x_init_block(bp, HC_BLOCK, COMMON_STAGE); + bnx2x_init_block(bp, MISC_AEU_BLOCK, COMMON_STAGE); /* PXPCS COMMON comes here */ + bnx2x_init_block(bp, PXPCS_BLOCK, COMMON_STAGE); /* Reset PCIE errors for debug */ REG_WR(bp, 0x2814, 0xffffffff); REG_WR(bp, 0x3820, 0xffffffff); /* EMAC0 COMMON comes here */ + bnx2x_init_block(bp, EMAC0_BLOCK, COMMON_STAGE); /* EMAC1 COMMON comes here */ + bnx2x_init_block(bp, EMAC1_BLOCK, COMMON_STAGE); /* DBU COMMON comes here */ + bnx2x_init_block(bp, DBU_BLOCK, COMMON_STAGE); /* DBG COMMON comes here */ + bnx2x_init_block(bp, DBG_BLOCK, COMMON_STAGE); - bnx2x_init_block(bp, NIG_COMMON_START, NIG_COMMON_END); + bnx2x_init_block(bp, NIG_BLOCK, COMMON_STAGE); if (CHIP_IS_E1H(bp)) { REG_WR(bp, NIG_REG_LLH_MF_MODE, IS_E1HMF(bp)); REG_WR(bp, NIG_REG_LLH_E1HOV_MODE, IS_E1HMF(bp)); @@ -5763,6 +5777,7 @@ static int bnx2x_init_common(struct bnx2x *bp) static int bnx2x_init_port(struct bnx2x *bp) { int port = BP_PORT(bp); + int init_stage = port ? PORT1_STAGE : PORT0_STAGE; u32 low, high; u32 val; @@ -5771,7 +5786,9 @@ static int bnx2x_init_port(struct bnx2x *bp) REG_WR(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4, 0); /* Port PXP comes here */ + bnx2x_init_block(bp, PXP_BLOCK, init_stage); /* Port PXP2 comes here */ + bnx2x_init_block(bp, PXP2_BLOCK, init_stage); #ifdef BCM_ISCSI /* Port0 1 * Port1 385 */ @@ -5798,21 +5815,19 @@ static int bnx2x_init_port(struct bnx2x *bp) REG_WR(bp, PXP2_REG_PSWRQ_SRC0_L2P + func*4, PXP_ONE_ILT(i)); #endif /* Port CMs come here */ - bnx2x_init_block(bp, (port ? XCM_PORT1_START : XCM_PORT0_START), - (port ? XCM_PORT1_END : XCM_PORT0_END)); + bnx2x_init_block(bp, XCM_BLOCK, init_stage); /* Port QM comes here */ #ifdef BCM_ISCSI REG_WR(bp, TM_REG_LIN0_SCAN_TIME + func*4, 1024/64*20); REG_WR(bp, TM_REG_LIN0_MAX_ACTIVE_CID + func*4, 31); - bnx2x_init_block(bp, func ? TIMERS_PORT1_START : TIMERS_PORT0_START, - func ? TIMERS_PORT1_END : TIMERS_PORT0_END); + bnx2x_init_block(bp, TIMERS_BLOCK, init_stage); #endif /* Port DQ comes here */ + bnx2x_init_block(bp, DQ_BLOCK, init_stage); - bnx2x_init_block(bp, (port ? BRB1_PORT1_START : BRB1_PORT0_START), - (port ? BRB1_PORT1_END : BRB1_PORT0_END)); + bnx2x_init_block(bp, BRB1_BLOCK, init_stage); if (CHIP_REV_IS_SLOW(bp) && !CHIP_IS_E1H(bp)) { /* no pause for emulation and FPGA */ low = 0; @@ -5837,25 +5852,27 @@ static int bnx2x_init_port(struct bnx2x *bp) /* Port PRS comes here */ + bnx2x_init_block(bp, PRS_BLOCK, init_stage); /* Port TSDM comes here */ + bnx2x_init_block(bp, TSDM_BLOCK, init_stage); /* Port CSDM comes here */ + bnx2x_init_block(bp, CSDM_BLOCK, init_stage); /* Port USDM comes here */ + bnx2x_init_block(bp, USDM_BLOCK, init_stage); /* Port XSDM comes here */ + bnx2x_init_block(bp, XSDM_BLOCK, init_stage); - bnx2x_init_block(bp, port ? TSEM_PORT1_START : TSEM_PORT0_START, - port ? TSEM_PORT1_END : TSEM_PORT0_END); - bnx2x_init_block(bp, port ? USEM_PORT1_START : USEM_PORT0_START, - port ? USEM_PORT1_END : USEM_PORT0_END); - bnx2x_init_block(bp, port ? CSEM_PORT1_START : CSEM_PORT0_START, - port ? CSEM_PORT1_END : CSEM_PORT0_END); - bnx2x_init_block(bp, port ? XSEM_PORT1_START : XSEM_PORT0_START, - port ? XSEM_PORT1_END : XSEM_PORT0_END); + bnx2x_init_block(bp, TSEM_BLOCK, init_stage); + bnx2x_init_block(bp, USEM_BLOCK, init_stage); + bnx2x_init_block(bp, CSEM_BLOCK, init_stage); + bnx2x_init_block(bp, XSEM_BLOCK, init_stage); /* Port UPB comes here */ + bnx2x_init_block(bp, UPB_BLOCK, init_stage); /* Port XPB comes here */ + bnx2x_init_block(bp, XPB_BLOCK, init_stage); - bnx2x_init_block(bp, port ? PBF_PORT1_START : PBF_PORT0_START, - port ? PBF_PORT1_END : PBF_PORT0_END); + bnx2x_init_block(bp, PBF_BLOCK, init_stage); /* configure PBF to work without PAUSE mtu 9000 */ REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 0); @@ -5885,18 +5902,17 @@ static int bnx2x_init_port(struct bnx2x *bp) /* Port SRCH comes here */ #endif /* Port CDU comes here */ + bnx2x_init_block(bp, CDU_BLOCK, init_stage); /* Port CFC comes here */ + bnx2x_init_block(bp, CFC_BLOCK, init_stage); if (CHIP_IS_E1(bp)) { REG_WR(bp, HC_REG_LEADING_EDGE_0 + port*8, 0); REG_WR(bp, HC_REG_TRAILING_EDGE_0 + port*8, 0); } - bnx2x_init_block(bp, port ? HC_PORT1_START : HC_PORT0_START, - port ? HC_PORT1_END : HC_PORT0_END); + bnx2x_init_block(bp, HC_BLOCK, init_stage); - bnx2x_init_block(bp, port ? MISC_AEU_PORT1_START : - MISC_AEU_PORT0_START, - port ? MISC_AEU_PORT1_END : MISC_AEU_PORT0_END); + bnx2x_init_block(bp, MISC_AEU_BLOCK, init_stage); /* init aeu_mask_attn_func_0/1: * - SF mode: bits 3-7 are masked. only bits 0-2 are in use * - MF mode: bit 3 is masked. bits 0-2 are in use as in SF @@ -5905,13 +5921,17 @@ static int bnx2x_init_port(struct bnx2x *bp) (IS_E1HMF(bp) ? 0xF7 : 0x7)); /* Port PXPCS comes here */ + bnx2x_init_block(bp, PXPCS_BLOCK, init_stage); /* Port EMAC0 comes here */ + bnx2x_init_block(bp, EMAC0_BLOCK, init_stage); /* Port EMAC1 comes here */ + bnx2x_init_block(bp, EMAC1_BLOCK, init_stage); /* Port DBU comes here */ + bnx2x_init_block(bp, DBU_BLOCK, init_stage); /* Port DBG comes here */ + bnx2x_init_block(bp, DBG_BLOCK, init_stage); - bnx2x_init_block(bp, port ? NIG_PORT1_START : NIG_PORT0_START, - port ? NIG_PORT1_END : NIG_PORT0_END); + bnx2x_init_block(bp, NIG_BLOCK, init_stage); REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 1); @@ -5931,7 +5951,9 @@ static int bnx2x_init_port(struct bnx2x *bp) } /* Port MCP comes here */ + bnx2x_init_block(bp, MCP_BLOCK, init_stage); /* Port DMAE comes here */ + bnx2x_init_block(bp, DMAE_BLOCK, init_stage); switch (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config)) { case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726: @@ -6036,7 +6058,7 @@ static int bnx2x_init_func(struct bnx2x *bp) if (CHIP_IS_E1H(bp)) { for (i = 0; i < 9; i++) bnx2x_init_block(bp, - cm_start[func][i], cm_end[func][i]); + cm_blocks[i], FUNC0_STAGE + func); REG_WR(bp, NIG_REG_LLH0_FUNC_EN + port*8, 1); REG_WR(bp, NIG_REG_LLH0_FUNC_VLAN_ID + port*8, bp->e1hov); @@ -6049,7 +6071,7 @@ static int bnx2x_init_func(struct bnx2x *bp) REG_WR(bp, HC_REG_LEADING_EDGE_0 + port*8, 0); REG_WR(bp, HC_REG_TRAILING_EDGE_0 + port*8, 0); } - bnx2x_init_block(bp, hc_limits[func][0], hc_limits[func][1]); + bnx2x_init_block(bp, HC_BLOCK, FUNC0_STAGE + func); /* Reset PCIE errors for debug */ REG_WR(bp, 0x2114, 0xffffffff); @@ -10595,7 +10617,6 @@ static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) mmiowb(); fp->tx_bd_prod += nbd; - dev->trans_start = jiffies; if (unlikely(bnx2x_tx_avail(fp) < MAX_SKB_FRAGS + 3)) { /* We want bnx2x_tx_int to "see" the updated tx_bd_prod @@ -11082,6 +11103,190 @@ static int __devinit bnx2x_get_pcie_speed(struct bnx2x *bp) val = (val & PCICFG_LINK_SPEED) >> PCICFG_LINK_SPEED_SHIFT; return val; } +static int __devinit bnx2x_check_firmware(struct bnx2x *bp) +{ + struct bnx2x_fw_file_hdr *fw_hdr; + struct bnx2x_fw_file_section *sections; + u16 *ops_offsets; + u32 offset, len, num_ops; + int i; + const struct firmware *firmware = bp->firmware; + const u8 * fw_ver; + + if (firmware->size < sizeof(struct bnx2x_fw_file_hdr)) + return -EINVAL; + + fw_hdr = (struct bnx2x_fw_file_hdr *)firmware->data; + sections = (struct bnx2x_fw_file_section *)fw_hdr; + + /* Make sure none of the offsets and sizes make us read beyond + * the end of the firmware data */ + for (i = 0; i < sizeof(*fw_hdr) / sizeof(*sections); i++) { + offset = be32_to_cpu(sections[i].offset); + len = be32_to_cpu(sections[i].len); + if (offset + len > firmware->size) { + printk(KERN_ERR PFX "Section %d length is out of bounds\n", i); + return -EINVAL; + } + } + + /* Likewise for the init_ops offsets */ + offset = be32_to_cpu(fw_hdr->init_ops_offsets.offset); + ops_offsets = (u16 *)(firmware->data + offset); + num_ops = be32_to_cpu(fw_hdr->init_ops.len) / sizeof(struct raw_op); + + for (i = 0; i < be32_to_cpu(fw_hdr->init_ops_offsets.len) / 2; i++) { + if (be16_to_cpu(ops_offsets[i]) > num_ops) { + printk(KERN_ERR PFX "Section offset %d is out of bounds\n", i); + return -EINVAL; + } + } + + /* Check FW version */ + offset = be32_to_cpu(fw_hdr->fw_version.offset); + fw_ver = firmware->data + offset; + if ((fw_ver[0] != BCM_5710_FW_MAJOR_VERSION) || + (fw_ver[1] != BCM_5710_FW_MINOR_VERSION) || + (fw_ver[2] != BCM_5710_FW_REVISION_VERSION) || + (fw_ver[3] != BCM_5710_FW_ENGINEERING_VERSION)) { + printk(KERN_ERR PFX "Bad FW version:%d.%d.%d.%d." + " Should be %d.%d.%d.%d\n", + fw_ver[0], fw_ver[1], fw_ver[2], + fw_ver[3], BCM_5710_FW_MAJOR_VERSION, + BCM_5710_FW_MINOR_VERSION, + BCM_5710_FW_REVISION_VERSION, + BCM_5710_FW_ENGINEERING_VERSION); + return -EINVAL; + } + + return 0; +} + +static void inline be32_to_cpu_n(const u8 *_source, u8 *_target, u32 n) +{ + u32 i; + const __be32 *source = (const __be32*)_source; + u32 *target = (u32*)_target; + + for (i = 0; i < n/4; i++) + target[i] = be32_to_cpu(source[i]); +} + +/* + Ops array is stored in the following format: + {op(8bit), offset(24bit, big endian), data(32bit, big endian)} + */ +static void inline bnx2x_prep_ops(const u8 *_source, u8 *_target, u32 n) +{ + u32 i, j, tmp; + const __be32 *source = (const __be32*)_source; + struct raw_op *target = (struct raw_op*)_target; + + for (i = 0, j = 0; i < n/8; i++, j+=2) { + tmp = be32_to_cpu(source[j]); + target[i].op = (tmp >> 24) & 0xff; + target[i].offset = tmp & 0xffffff; + target[i].raw_data = be32_to_cpu(source[j+1]); + } +} +static void inline be16_to_cpu_n(const u8 *_source, u8 *_target, u32 n) +{ + u32 i; + u16 *target = (u16*)_target; + const __be16 *source = (const __be16*)_source; + + for (i = 0; i < n/2; i++) + target[i] = be16_to_cpu(source[i]); +} + +#define BNX2X_ALLOC_AND_SET(arr, lbl, func) \ + do { \ + u32 len = be32_to_cpu(fw_hdr->arr.len); \ + bp->arr = kmalloc(len, GFP_KERNEL); \ + if (!bp->arr) { \ + printk(KERN_ERR PFX "Failed to allocate %d bytes for "#arr"\n", len); \ + goto lbl; \ + } \ + func(bp->firmware->data + \ + be32_to_cpu(fw_hdr->arr.offset), \ + (u8*)bp->arr, len); \ + } while (0) + + +static int __devinit bnx2x_init_firmware(struct bnx2x *bp, struct device *dev) +{ + char fw_file_name[40] = {0}; + int rc, offset; + struct bnx2x_fw_file_hdr *fw_hdr; + + /* Create a FW file name */ + if (CHIP_IS_E1(bp)) + offset = sprintf(fw_file_name, FW_FILE_PREFIX_E1); + else + offset = sprintf(fw_file_name, FW_FILE_PREFIX_E1H); + + sprintf(fw_file_name + offset, "%d.%d.%d.%d.fw", + BCM_5710_FW_MAJOR_VERSION, + BCM_5710_FW_MINOR_VERSION, + BCM_5710_FW_REVISION_VERSION, + BCM_5710_FW_ENGINEERING_VERSION); + + printk(KERN_INFO PFX "Loading %s\n", fw_file_name); + + rc = request_firmware(&bp->firmware, fw_file_name, dev); + if (rc) { + printk(KERN_ERR PFX "Can't load firmware file %s\n", fw_file_name); + goto request_firmware_exit; + } + + rc = bnx2x_check_firmware(bp); + if (rc) { + printk(KERN_ERR PFX "Corrupt firmware file %s\n", fw_file_name); + goto request_firmware_exit; + } + + fw_hdr = (struct bnx2x_fw_file_hdr *)bp->firmware->data; + + /* Initialize the pointers to the init arrays */ + /* Blob */ + BNX2X_ALLOC_AND_SET(init_data, request_firmware_exit, be32_to_cpu_n); + + /* Opcodes */ + BNX2X_ALLOC_AND_SET(init_ops, init_ops_alloc_err, bnx2x_prep_ops); + + /* Offsets */ + BNX2X_ALLOC_AND_SET(init_ops_offsets, init_offsets_alloc_err, be16_to_cpu_n); + + /* STORMs firmware */ + bp->tsem_int_table_data = bp->firmware->data + + be32_to_cpu(fw_hdr->tsem_int_table_data.offset); + bp->tsem_pram_data = bp->firmware->data + + be32_to_cpu(fw_hdr->tsem_pram_data.offset); + bp->usem_int_table_data = bp->firmware->data + + be32_to_cpu(fw_hdr->usem_int_table_data.offset); + bp->usem_pram_data = bp->firmware->data + + be32_to_cpu(fw_hdr->usem_pram_data.offset); + bp->xsem_int_table_data = bp->firmware->data + + be32_to_cpu(fw_hdr->xsem_int_table_data.offset); + bp->xsem_pram_data = bp->firmware->data + + be32_to_cpu(fw_hdr->xsem_pram_data.offset); + bp->csem_int_table_data = bp->firmware->data + + be32_to_cpu(fw_hdr->csem_int_table_data.offset); + bp->csem_pram_data = bp->firmware->data + + be32_to_cpu(fw_hdr->csem_pram_data.offset); + + return 0; +init_offsets_alloc_err: + kfree(bp->init_ops); +init_ops_alloc_err: + kfree(bp->init_data); +request_firmware_exit: + release_firmware(bp->firmware); + + return rc; +} + + static int __devinit bnx2x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) @@ -11116,6 +11321,13 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev, if (rc) goto init_one_exit; + /* Set init arrays */ + rc = bnx2x_init_firmware(bp, &pdev->dev); + if (rc) { + printk(KERN_ERR PFX "Error loading firmware\n"); + goto init_one_exit; + } + rc = register_netdev(dev); if (rc) { dev_err(&pdev->dev, "Cannot register net device\n"); @@ -11163,6 +11375,11 @@ static void __devexit bnx2x_remove_one(struct pci_dev *pdev) unregister_netdev(dev); + kfree(bp->init_ops_offsets); + kfree(bp->init_ops); + kfree(bp->init_data); + release_firmware(bp->firmware); + if (bp->regview) iounmap(bp->regview); @@ -11412,13 +11629,20 @@ static struct pci_driver bnx2x_pci_driver = { static int __init bnx2x_init(void) { + int ret; + bnx2x_wq = create_singlethread_workqueue("bnx2x"); if (bnx2x_wq == NULL) { printk(KERN_ERR PFX "Cannot create workqueue\n"); return -ENOMEM; } - return pci_register_driver(&bnx2x_pci_driver); + ret = pci_register_driver(&bnx2x_pci_driver); + if (ret) { + printk(KERN_ERR PFX "Cannot register driver\n"); + destroy_workqueue(bnx2x_wq); + } + return ret; } static void __exit bnx2x_cleanup(void) @@ -11431,3 +11655,4 @@ static void __exit bnx2x_cleanup(void) module_init(bnx2x_init); module_exit(bnx2x_cleanup); + diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index faf094abef7f..d4b570886c6e 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -1850,9 +1850,10 @@ static u16 aggregator_identifier; * Can be called only after the mac address of the bond is set. */ void bond_3ad_initialize(struct bonding *bond, u16 tick_resolution, int lacp_fast) -{ +{ // check that the bond is not initialized yet - if (MAC_ADDRESS_COMPARE(&(BOND_AD_INFO(bond).system.sys_mac_addr), &(bond->dev->dev_addr))) { + if (MAC_ADDRESS_COMPARE(&(BOND_AD_INFO(bond).system.sys_mac_addr), + bond->dev->dev_addr)) { aggregator_identifier = 0; diff --git a/drivers/net/bonding/bond_3ad.h b/drivers/net/bonding/bond_3ad.h index a306230381c8..2c46a154f2c6 100644 --- a/drivers/net/bonding/bond_3ad.h +++ b/drivers/net/bonding/bond_3ad.h @@ -26,10 +26,10 @@ #include #include #include +#include // General definitions -#define BOND_ETH_P_LACPDU 0x8809 -#define PKT_TYPE_LACPDU cpu_to_be16(BOND_ETH_P_LACPDU) +#define PKT_TYPE_LACPDU cpu_to_be16(ETH_P_SLOW) #define AD_TIMER_INTERVAL 100 /*msec*/ #define MULTICAST_LACPDU_ADDR {0x01, 0x80, 0xC2, 0x00, 0x00, 0x02} diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 74824028f85c..d927f71af8a3 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -51,10 +51,10 @@ #include #include #include +#include #include -#include #include -#include +#include #include #include #include @@ -89,19 +89,19 @@ static int max_bonds = BOND_DEFAULT_MAX_BONDS; static int num_grat_arp = 1; static int num_unsol_na = 1; static int miimon = BOND_LINK_MON_INTERV; -static int updelay = 0; -static int downdelay = 0; +static int updelay; +static int downdelay; static int use_carrier = 1; -static char *mode = NULL; -static char *primary = NULL; -static char *lacp_rate = NULL; -static char *ad_select = NULL; -static char *xmit_hash_policy = NULL; +static char *mode; +static char *primary; +static char *lacp_rate; +static char *ad_select; +static char *xmit_hash_policy; static int arp_interval = BOND_LINK_ARP_INTERV; -static char *arp_ip_target[BOND_MAX_ARP_TARGETS] = { NULL, }; -static char *arp_validate = NULL; -static char *fail_over_mac = NULL; -struct bond_params bonding_defaults; +static char *arp_ip_target[BOND_MAX_ARP_TARGETS]; +static char *arp_validate; +static char *fail_over_mac; +static struct bond_params bonding_defaults; module_param(max_bonds, int, 0); MODULE_PARM_DESC(max_bonds, "Max number of bonded devices"); @@ -151,14 +151,14 @@ static const char * const version = LIST_HEAD(bond_dev_list); #ifdef CONFIG_PROC_FS -static struct proc_dir_entry *bond_proc_dir = NULL; +static struct proc_dir_entry *bond_proc_dir; #endif -static __be32 arp_target[BOND_MAX_ARP_TARGETS] = { 0, } ; -static int arp_ip_count = 0; +static __be32 arp_target[BOND_MAX_ARP_TARGETS]; +static int arp_ip_count; static int bond_mode = BOND_MODE_ROUNDROBIN; -static int xmit_hashtype= BOND_XMIT_POLICY_LAYER2; -static int lacp_fast = 0; +static int xmit_hashtype = BOND_XMIT_POLICY_LAYER2; +static int lacp_fast; const struct bond_parm_tbl bond_lacp_tbl[] = { @@ -210,6 +210,7 @@ struct bond_parm_tbl ad_select_tbl[] = { /*-------------------------- Forward declarations ---------------------------*/ static void bond_send_gratuitous_arp(struct bonding *bond); +static int bond_init(struct net_device *bond_dev); static void bond_deinit(struct net_device *bond_dev); /*---------------------------- General routines -----------------------------*/ @@ -221,7 +222,7 @@ static const char *bond_mode_name(int mode) [BOND_MODE_ACTIVEBACKUP] = "fault-tolerance (active-backup)", [BOND_MODE_XOR] = "load balancing (xor)", [BOND_MODE_BROADCAST] = "fault-tolerance (broadcast)", - [BOND_MODE_8023AD]= "IEEE 802.3ad Dynamic link aggregation", + [BOND_MODE_8023AD] = "IEEE 802.3ad Dynamic link aggregation", [BOND_MODE_TLB] = "transmit load balancing", [BOND_MODE_ALB] = "adaptive load balancing", }; @@ -246,12 +247,11 @@ static int bond_add_vlan(struct bonding *bond, unsigned short vlan_id) struct vlan_entry *vlan; pr_debug("bond: %s, vlan id %d\n", - (bond ? bond->dev->name: "None"), vlan_id); + (bond ? bond->dev->name : "None"), vlan_id); vlan = kzalloc(sizeof(struct vlan_entry), GFP_KERNEL); - if (!vlan) { + if (!vlan) return -ENOMEM; - } INIT_LIST_HEAD(&vlan->vlan_list); vlan->vlan_id = vlan_id; @@ -351,16 +351,15 @@ static int bond_has_challenged_slaves(struct bonding *bond) * * Returns %NULL if list is empty, bond->next_vlan if @curr is %NULL, * or @curr->next otherwise (even if it is @curr itself again). - * + * * Caller must hold bond->lock */ struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr) { struct vlan_entry *next, *last; - if (list_empty(&bond->vlan_list)) { + if (list_empty(&bond->vlan_list)) return NULL; - } if (!curr) { next = list_entry(bond->vlan_list.next, @@ -382,11 +381,11 @@ struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr) /** * bond_dev_queue_xmit - Prepare skb for xmit. - * + * * @bond: bond device that got this skb for tx. * @skb: hw accel VLAN tagged skb to transmit * @slave_dev: slave that is supposed to xmit this skbuff - * + * * When the bond gets an skb to transmit that is * already hardware accelerated VLAN tagged, and it * needs to relay this skb to a slave that is not @@ -394,7 +393,8 @@ struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr) * i.e. strip the hwaccel tag and re-insert it as part * of the payload. */ -int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_device *slave_dev) +int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, + struct net_device *slave_dev) { unsigned short uninitialized_var(vlan_id); @@ -428,7 +428,7 @@ int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_de * b. The operation is protected by the RTNL semaphore in the 8021q code, * c. Holding a lock with BH disabled while directly calling a base driver * entry point is generally a BAD idea. - * + * * The design of synchronization/protection for this operation in the 8021q * module is good for one or more VLAN devices over a single physical device * and cannot be extended for a teaming solution like bonding, so there is a @@ -443,7 +443,8 @@ int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_de * @bond_dev: bonding net device that got called * @grp: vlan group being registered */ -static void bond_vlan_rx_register(struct net_device *bond_dev, struct vlan_group *grp) +static void bond_vlan_rx_register(struct net_device *bond_dev, + struct vlan_group *grp) { struct bonding *bond = netdev_priv(bond_dev); struct slave *slave; @@ -485,7 +486,7 @@ static void bond_vlan_rx_add_vid(struct net_device *bond_dev, uint16_t vid) res = bond_add_vlan(bond, vid); if (res) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Error: Failed to add vlan id %d\n", bond_dev->name, vid); } @@ -520,7 +521,7 @@ static void bond_vlan_rx_kill_vid(struct net_device *bond_dev, uint16_t vid) res = bond_del_vlan(bond, vid); if (res) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Error: Failed to remove vlan id %d\n", bond_dev->name, vid); } @@ -551,7 +552,8 @@ out: write_unlock_bh(&bond->lock); } -static void bond_del_vlans_from_slave(struct bonding *bond, struct net_device *slave_dev) +static void bond_del_vlans_from_slave(struct bonding *bond, + struct net_device *slave_dev) { const struct net_device_ops *slave_ops = slave_dev->netdev_ops; struct vlan_entry *vlan; @@ -673,7 +675,7 @@ static int bond_update_speed_duplex(struct slave *slave) * if supports MII link status reporting, check its link status. * * We either do MII/ETHTOOL ioctls, or check netif_carrier_ok(), - * depening upon the setting of the use_carrier parameter. + * depending upon the setting of the use_carrier parameter. * * Return either BMSR_LSTATUS, meaning that the link is up (or we * can't tell and just pretend it is), or 0, meaning that the link is @@ -685,16 +687,29 @@ static int bond_update_speed_duplex(struct slave *slave) * It'd be nice if there was a good way to tell if a driver supports * netif_carrier, but there really isn't. */ -static int bond_check_dev_link(struct bonding *bond, struct net_device *slave_dev, int reporting) +static int bond_check_dev_link(struct bonding *bond, + struct net_device *slave_dev, int reporting) { const struct net_device_ops *slave_ops = slave_dev->netdev_ops; - static int (* ioctl)(struct net_device *, struct ifreq *, int); + static int (*ioctl)(struct net_device *, struct ifreq *, int); struct ifreq ifr; struct mii_ioctl_data *mii; if (bond->params.use_carrier) return netif_carrier_ok(slave_dev) ? BMSR_LSTATUS : 0; + /* Try to get link status using Ethtool first. */ + if (slave_dev->ethtool_ops) { + if (slave_dev->ethtool_ops->get_link) { + u32 link; + + link = slave_dev->ethtool_ops->get_link(slave_dev); + + return link ? BMSR_LSTATUS : 0; + } + } + + /* Ethtool can't be used, fallback to MII ioctls. */ ioctl = slave_ops->ndo_do_ioctl; if (ioctl) { /* TODO: set pointer to correct ioctl on a per team member */ @@ -714,23 +729,8 @@ static int bond_check_dev_link(struct bonding *bond, struct net_device *slave_de mii = if_mii(&ifr); if (IOCTL(slave_dev, &ifr, SIOCGMIIPHY) == 0) { mii->reg_num = MII_BMSR; - if (IOCTL(slave_dev, &ifr, SIOCGMIIREG) == 0) { - return (mii->val_out & BMSR_LSTATUS); - } - } - } - - /* - * Some drivers cache ETHTOOL_GLINK for a period of time so we only - * attempt to get link status from it if the above MII ioctls fail. - */ - if (slave_dev->ethtool_ops) { - if (slave_dev->ethtool_ops->get_link) { - u32 link; - - link = slave_dev->ethtool_ops->get_link(slave_dev); - - return link ? BMSR_LSTATUS : 0; + if (IOCTL(slave_dev, &ifr, SIOCGMIIREG) == 0) + return mii->val_out & BMSR_LSTATUS; } } @@ -740,7 +740,7 @@ static int bond_check_dev_link(struct bonding *bond, struct net_device *slave_de * cannot report link status). If not reporting, pretend * we're ok. */ - return (reporting ? -1 : BMSR_LSTATUS); + return reporting ? -1 : BMSR_LSTATUS; } /*----------------------------- Multicast list ------------------------------*/ @@ -748,7 +748,8 @@ static int bond_check_dev_link(struct bonding *bond, struct net_device *slave_de /* * Returns 0 if dmi1 and dmi2 are the same, non-0 otherwise */ -static inline int bond_is_dmi_same(struct dev_mc_list *dmi1, struct dev_mc_list *dmi2) +static inline int bond_is_dmi_same(const struct dev_mc_list *dmi1, + const struct dev_mc_list *dmi2) { return memcmp(dmi1->dmi_addr, dmi2->dmi_addr, dmi1->dmi_addrlen) == 0 && dmi1->dmi_addrlen == dmi2->dmi_addrlen; @@ -757,14 +758,14 @@ static inline int bond_is_dmi_same(struct dev_mc_list *dmi1, struct dev_mc_list /* * returns dmi entry if found, NULL otherwise */ -static struct dev_mc_list *bond_mc_list_find_dmi(struct dev_mc_list *dmi, struct dev_mc_list *mc_list) +static struct dev_mc_list *bond_mc_list_find_dmi(struct dev_mc_list *dmi, + struct dev_mc_list *mc_list) { struct dev_mc_list *idmi; for (idmi = mc_list; idmi; idmi = idmi->next) { - if (bond_is_dmi_same(dmi, idmi)) { + if (bond_is_dmi_same(dmi, idmi)) return idmi; - } } return NULL; @@ -826,15 +827,14 @@ static void bond_mc_add(struct bonding *bond, void *addr, int alen) { if (USES_PRIMARY(bond->params.mode)) { /* write lock already acquired */ - if (bond->curr_active_slave) { + if (bond->curr_active_slave) dev_mc_add(bond->curr_active_slave->dev, addr, alen, 0); - } } else { struct slave *slave; int i; - bond_for_each_slave(bond, slave, i) { + + bond_for_each_slave(bond, slave, i) dev_mc_add(slave->dev, addr, alen, 0); - } } } @@ -846,9 +846,9 @@ static void bond_mc_delete(struct bonding *bond, void *addr, int alen) { if (USES_PRIMARY(bond->params.mode)) { /* write lock already acquired */ - if (bond->curr_active_slave) { - dev_mc_delete(bond->curr_active_slave->dev, addr, alen, 0); - } + if (bond->curr_active_slave) + dev_mc_delete(bond->curr_active_slave->dev, addr, + alen, 0); } else { struct slave *slave; int i; @@ -872,9 +872,8 @@ static void bond_resend_igmp_join_requests(struct bonding *bond) rcu_read_lock(); in_dev = __in_dev_get_rcu(bond->dev); if (in_dev) { - for (im = in_dev->mc_list; im; im = im->next) { + for (im = in_dev->mc_list; im; im = im->next) ip_mc_rejoin_group(im); - } } rcu_read_unlock(); @@ -893,7 +892,8 @@ static void bond_mc_list_destroy(struct bonding *bond) kfree(dmi); dmi = bond->mc_list; } - bond->mc_list = NULL; + + bond->mc_list = NULL; } /* @@ -926,14 +926,14 @@ static int bond_mc_list_copy(struct dev_mc_list *mc_list, struct bonding *bond, /* * flush all members of flush->mc_list from device dev->mc_list */ -static void bond_mc_list_flush(struct net_device *bond_dev, struct net_device *slave_dev) +static void bond_mc_list_flush(struct net_device *bond_dev, + struct net_device *slave_dev) { struct bonding *bond = netdev_priv(bond_dev); struct dev_mc_list *dmi; - for (dmi = bond_dev->mc_list; dmi; dmi = dmi->next) { + for (dmi = bond_dev->mc_list; dmi; dmi = dmi->next) dev_mc_delete(slave_dev, dmi->dmi_addr, dmi->dmi_addrlen, 0); - } if (bond->params.mode == BOND_MODE_8023AD) { /* del lacpdu mc addr from mc list */ @@ -950,44 +950,40 @@ static void bond_mc_list_flush(struct net_device *bond_dev, struct net_device *s * old active slaves (if any) according to the multicast mode, and * promiscuous flags unconditionally. */ -static void bond_mc_swap(struct bonding *bond, struct slave *new_active, struct slave *old_active) +static void bond_mc_swap(struct bonding *bond, struct slave *new_active, + struct slave *old_active) { struct dev_mc_list *dmi; - if (!USES_PRIMARY(bond->params.mode)) { + if (!USES_PRIMARY(bond->params.mode)) /* nothing to do - mc list is already up-to-date on * all slaves */ return; - } if (old_active) { - if (bond->dev->flags & IFF_PROMISC) { + if (bond->dev->flags & IFF_PROMISC) dev_set_promiscuity(old_active->dev, -1); - } - if (bond->dev->flags & IFF_ALLMULTI) { + if (bond->dev->flags & IFF_ALLMULTI) dev_set_allmulti(old_active->dev, -1); - } - for (dmi = bond->dev->mc_list; dmi; dmi = dmi->next) { - dev_mc_delete(old_active->dev, dmi->dmi_addr, dmi->dmi_addrlen, 0); - } + for (dmi = bond->dev->mc_list; dmi; dmi = dmi->next) + dev_mc_delete(old_active->dev, dmi->dmi_addr, + dmi->dmi_addrlen, 0); } if (new_active) { /* FIXME: Signal errors upstream. */ - if (bond->dev->flags & IFF_PROMISC) { + if (bond->dev->flags & IFF_PROMISC) dev_set_promiscuity(new_active->dev, 1); - } - if (bond->dev->flags & IFF_ALLMULTI) { + if (bond->dev->flags & IFF_ALLMULTI) dev_set_allmulti(new_active->dev, 1); - } - for (dmi = bond->dev->mc_list; dmi; dmi = dmi->next) { - dev_mc_add(new_active->dev, dmi->dmi_addr, dmi->dmi_addrlen, 0); - } + for (dmi = bond->dev->mc_list; dmi; dmi = dmi->next) + dev_mc_add(new_active->dev, dmi->dmi_addr, + dmi->dmi_addrlen, 0); bond_resend_igmp_join_requests(bond); } } @@ -1041,7 +1037,7 @@ static void bond_do_fail_over_mac(struct bonding *bond, rv = dev_set_mac_address(new_active->dev, &saddr); if (rv) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Error %d setting MAC of slave %s\n", bond->dev->name, -rv, new_active->dev->name); goto out; @@ -1055,7 +1051,7 @@ static void bond_do_fail_over_mac(struct bonding *bond, rv = dev_set_mac_address(old_active->dev, &saddr); if (rv) - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Error %d setting MAC of slave %s\n", bond->dev->name, -rv, new_active->dev->name); out: @@ -1063,7 +1059,7 @@ out: write_lock_bh(&bond->curr_slave_lock); break; default: - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: bond_do_fail_over_mac impossible: bad policy %d\n", bond->dev->name, bond->params.fail_over_mac); break; @@ -1088,17 +1084,17 @@ static struct slave *bond_find_best_slave(struct bonding *bond) new_active = old_active = bond->curr_active_slave; if (!new_active) { /* there were no active slaves left */ - if (bond->slave_cnt > 0) { /* found one slave */ + if (bond->slave_cnt > 0) /* found one slave */ new_active = bond->first_slave; - } else { + else return NULL; /* still no slave, return NULL */ - } } - /* first try the primary link; if arping, a link must tx/rx traffic - * before it can be considered the curr_active_slave - also, we would skip - * slaves between the curr_active_slave and primary_slave that may be up - * and able to arp + /* + * first try the primary link; if arping, a link must tx/rx + * traffic before it can be considered the curr_active_slave. + * also, we would skip slaves between the curr_active_slave + * and primary_slave that may be up and able to arp */ if ((bond->primary_slave) && (!bond->params.arp_interval) && @@ -1146,16 +1142,15 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) { struct slave *old_active = bond->curr_active_slave; - if (old_active == new_active) { + if (old_active == new_active) return; - } if (new_active) { new_active->jiffies = jiffies; if (new_active->link == BOND_LINK_BACK) { if (USES_PRIMARY(bond->params.mode)) { - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: making interface %s the new " "active one %d ms earlier.\n", bond->dev->name, new_active->dev->name, @@ -1165,15 +1160,14 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) new_active->delay = 0; new_active->link = BOND_LINK_UP; - if (bond->params.mode == BOND_MODE_8023AD) { + if (bond->params.mode == BOND_MODE_8023AD) bond_3ad_handle_link_change(new_active, BOND_LINK_UP); - } if (bond_is_lb(bond)) bond_alb_handle_link_change(bond, new_active, BOND_LINK_UP); } else { if (USES_PRIMARY(bond->params.mode)) { - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: making interface %s the new " "active one.\n", bond->dev->name, new_active->dev->name); @@ -1181,9 +1175,8 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) } } - if (USES_PRIMARY(bond->params.mode)) { + if (USES_PRIMARY(bond->params.mode)) bond_mc_swap(bond, new_active, old_active); - } if (bond_is_lb(bond)) { bond_alb_handle_active_change(bond, new_active); @@ -1196,9 +1189,8 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) } if (bond->params.mode == BOND_MODE_ACTIVEBACKUP) { - if (old_active) { + if (old_active) bond_set_slave_inactive_flags(old_active); - } if (new_active) { bond_set_slave_active_flags(new_active); @@ -1228,7 +1220,7 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) * bond_select_active_slave - select a new active slave, if needed * @bond: our bonding struct * - * This functions shoud be called when one of the following occurs: + * This functions should be called when one of the following occurs: * - The old curr_active_slave has been released or lost its link. * - The primary_slave has got its link back. * - A slave has got its link back and there's no old curr_active_slave. @@ -1248,11 +1240,11 @@ void bond_select_active_slave(struct bonding *bond) return; if (netif_carrier_ok(bond->dev)) { - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: first active interface up!\n", bond->dev->name); } else { - printk(KERN_INFO DRV_NAME ": %s: " + pr_info(DRV_NAME ": %s: " "now running without any active interface !\n", bond->dev->name); } @@ -1294,13 +1286,11 @@ static void bond_attach_slave(struct bonding *bond, struct slave *new_slave) */ static void bond_detach_slave(struct bonding *bond, struct slave *slave) { - if (slave->next) { + if (slave->next) slave->next->prev = slave->prev; - } - if (slave->prev) { + if (slave->prev) slave->prev->next = slave->next; - } if (bond->first_slave == slave) { /* slave is the first slave */ if (bond->slave_cnt > 1) { /* there are more slave */ @@ -1331,7 +1321,7 @@ static int bond_sethwaddr(struct net_device *bond_dev, (NETIF_F_VLAN_CHALLENGED | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_TX | \ NETIF_F_HW_VLAN_FILTER) -/* +/* * Compute the common dev->feature set available to all slaves. Some * feature bits are managed elsewhere, so preserve those feature bits * on the master device. @@ -1399,14 +1389,14 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) if (!bond->params.use_carrier && slave_dev->ethtool_ops == NULL && slave_ops->ndo_do_ioctl == NULL) { - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": %s: Warning: no link monitoring support for %s\n", bond_dev->name, slave_dev->name); } /* bond must be initialized by bond_open() before enslaving */ if (!(bond_dev->flags & IFF_UP)) { - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME " %s: master_dev is not up in bond_enslave\n", bond_dev->name); } @@ -1422,14 +1412,14 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) if (slave_dev->features & NETIF_F_VLAN_CHALLENGED) { pr_debug("%s: NETIF_F_VLAN_CHALLENGED\n", slave_dev->name); if (!list_empty(&bond->vlan_list)) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Error: cannot enslave VLAN " "challenged slave %s on VLAN enabled " "bond %s\n", bond_dev->name, slave_dev->name, bond_dev->name); return -EPERM; } else { - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": %s: Warning: enslaved VLAN challenged " "slave %s. Adding VLANs will be blocked as " "long as %s is part of bond %s\n", @@ -1449,12 +1439,12 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) /* * Old ifenslave binaries are no longer supported. These can - * be identified with moderate accurary by the state of the slave: + * be identified with moderate accuracy by the state of the slave: * the current ifenslave will set the interface down prior to * enslaving it; the old ifenslave will not. */ if ((slave_dev->flags & IFF_UP)) { - printk(KERN_ERR DRV_NAME ": %s is up. " + pr_err(DRV_NAME ": %s is up. " "This may be due to an out of date ifenslave.\n", slave_dev->name); res = -EPERM; @@ -1472,7 +1462,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) if (slave_dev->type != ARPHRD_ETHER) bond_setup_by_slave(bond_dev, slave_dev); } else if (bond_dev->type != slave_dev->type) { - printk(KERN_ERR DRV_NAME ": %s ether type (%d) is different " + pr_err(DRV_NAME ": %s ether type (%d) is different " "from other slaves (%d), can not enslave it.\n", slave_dev->name, slave_dev->type, bond_dev->type); @@ -1482,14 +1472,14 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) if (slave_ops->ndo_set_mac_address == NULL) { if (bond->slave_cnt == 0) { - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": %s: Warning: The first slave device " "specified does not support setting the MAC " "address. Setting fail_over_mac to active.", bond_dev->name); bond->params.fail_over_mac = BOND_FOM_ACTIVE; } else if (bond->params.fail_over_mac != BOND_FOM_ACTIVE) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Error: The slave device specified " "does not support setting the MAC address, " "but fail_over_mac is not set to active.\n" @@ -1539,7 +1529,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) /* open the slave since the application closed it */ res = dev_open(slave_dev); if (res) { - pr_debug("Openning slave %s failed\n", slave_dev->name); + pr_debug("Opening slave %s failed\n", slave_dev->name); goto err_unset_master; } @@ -1551,9 +1541,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) * it might fail and we do not want to have to undo everything */ res = bond_alb_init_slave(bond, new_slave); - if (res) { + if (res) goto err_close; - } } /* If the mode USES_PRIMARY, then the new slave gets the @@ -1578,9 +1567,9 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) netif_addr_lock_bh(bond_dev); /* upload master's mc_list to new slave */ - for (dmi = bond_dev->mc_list; dmi; dmi = dmi->next) { - dev_mc_add (slave_dev, dmi->dmi_addr, dmi->dmi_addrlen, 0); - } + for (dmi = bond_dev->mc_list; dmi; dmi = dmi->next) + dev_mc_add(slave_dev, dmi->dmi_addr, + dmi->dmi_addrlen, 0); netif_addr_unlock_bh(bond_dev); } @@ -1621,7 +1610,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) * supported); thus, we don't need to change * the messages for netif_carrier. */ - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": %s: Warning: MII and ETHTOOL support not " "available for interface %s, and " "arp_interval/arp_ip_target module parameters " @@ -1630,7 +1619,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) bond_dev->name, slave_dev->name); } else if (link_reporting == -1) { /* unable get link status using mii/ethtool */ - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": %s: Warning: can't get link status from " "interface %s; the network driver associated " "with this interface does not support MII or " @@ -1662,13 +1651,13 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) if (bond_update_speed_duplex(new_slave) && (new_slave->link != BOND_LINK_DOWN)) { - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": %s: Warning: failed to get speed and duplex from %s, " "assumed to be 100Mb/sec and Full.\n", bond_dev->name, new_slave->dev->name); if (bond->params.mode == BOND_MODE_8023AD) { - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": %s: Warning: Operation of 802.3ad mode requires ETHTOOL " "support in base driver for proper aggregator " "selection.\n", bond_dev->name); @@ -1677,9 +1666,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) if (USES_PRIMARY(bond->params.mode) && bond->params.primary[0]) { /* if there is a primary slave, remember it */ - if (strcmp(bond->params.primary, new_slave->dev->name) == 0) { + if (strcmp(bond->params.primary, new_slave->dev->name) == 0) bond->primary_slave = new_slave; - } } write_lock_bh(&bond->curr_slave_lock); @@ -1726,9 +1714,9 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) * anyway (it holds no special properties of the bond device), * so we can change it without calling change_active_interface() */ - if (!bond->curr_active_slave) { + if (!bond->curr_active_slave) bond->curr_active_slave = new_slave; - } + break; } /* switch(bond_mode) */ @@ -1742,7 +1730,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) if (res) goto err_close; - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: enslaving %s as a%s interface with a%s link.\n", bond_dev->name, slave_dev->name, new_slave->state == BOND_STATE_ACTIVE ? "n active" : " backup", @@ -1774,7 +1762,7 @@ err_free: err_undo_flags: bond_dev->features = old_features; - + return res; } @@ -1799,7 +1787,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) /* slave is not a slave or master is not master of this slave */ if (!(slave_dev->flags & IFF_SLAVE) || (slave_dev->master != bond_dev)) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Error: cannot release %s.\n", bond_dev->name, slave_dev->name); return -EINVAL; @@ -1810,7 +1798,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) slave = bond_get_slave_by_dev(bond, slave_dev); if (!slave) { /* not a slave of this bond */ - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: %s not enslaved\n", bond_dev->name, slave_dev->name); write_unlock_bh(&bond->lock); @@ -1821,7 +1809,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) mac_addr_differ = memcmp(bond_dev->dev_addr, slave->perm_hwaddr, ETH_ALEN); if (!mac_addr_differ && (bond->slave_cnt > 1)) - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": %s: Warning: the permanent HWaddr of %s - " "%pM - is still in use by %s. " "Set the HWaddr of %s to a different address " @@ -1839,7 +1827,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) bond_3ad_unbind_slave(slave); } - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: releasing %s interface %s\n", bond_dev->name, (slave->state == BOND_STATE_ACTIVE) @@ -1855,13 +1843,11 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) bond_compute_features(bond); - if (bond->primary_slave == slave) { + if (bond->primary_slave == slave) bond->primary_slave = NULL; - } - if (oldcurrent == slave) { + if (oldcurrent == slave) bond_change_active_slave(bond, NULL); - } if (bond_is_lb(bond)) { /* Must be called only after the slave has been @@ -1903,18 +1889,18 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) if (list_empty(&bond->vlan_list)) { bond_dev->features |= NETIF_F_VLAN_CHALLENGED; } else { - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": %s: Warning: clearing HW address of %s while it " "still has VLANs.\n", bond_dev->name, bond_dev->name); - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": %s: When re-adding slaves, make sure the bond's " "HW address matches its VLANs'.\n", bond_dev->name); } } else if ((bond_dev->features & NETIF_F_VLAN_CHALLENGED) && !bond_has_challenged_slaves(bond)) { - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: last VLAN challenged slave %s " "left bond %s. VLAN blocking is removed\n", bond_dev->name, slave_dev->name, bond_dev->name); @@ -1934,14 +1920,12 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) */ if (!USES_PRIMARY(bond->params.mode)) { /* unset promiscuity level from slave */ - if (bond_dev->flags & IFF_PROMISC) { + if (bond_dev->flags & IFF_PROMISC) dev_set_promiscuity(slave_dev, -1); - } /* unset allmulti level from slave */ - if (bond_dev->flags & IFF_ALLMULTI) { + if (bond_dev->flags & IFF_ALLMULTI) dev_set_allmulti(slave_dev, -1); - } /* flush master's mc_list from slave */ netif_addr_lock_bh(bond_dev); @@ -1974,41 +1958,36 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) * Destroy a bonding device. * Must be under rtnl_lock when this function is called. */ -void bond_destroy(struct bonding *bond) -{ - bond_deinit(bond->dev); - bond_destroy_sysfs_entry(bond); - unregister_netdevice(bond->dev); -} - -static void bond_destructor(struct net_device *bond_dev) +static void bond_uninit(struct net_device *bond_dev) { struct bonding *bond = netdev_priv(bond_dev); + bond_deinit(bond_dev); + bond_destroy_sysfs_entry(bond); + if (bond->wq) destroy_workqueue(bond->wq); netif_addr_lock_bh(bond_dev); bond_mc_list_destroy(bond); netif_addr_unlock_bh(bond_dev); - - free_netdev(bond_dev); } /* -* First release a slave and than destroy the bond if no more slaves iare left. +* First release a slave and than destroy the bond if no more slaves are left. * Must be under rtnl_lock when this function is called. */ -int bond_release_and_destroy(struct net_device *bond_dev, struct net_device *slave_dev) +int bond_release_and_destroy(struct net_device *bond_dev, + struct net_device *slave_dev) { struct bonding *bond = netdev_priv(bond_dev); int ret; ret = bond_release(bond_dev, slave_dev); if ((ret == 0) && (bond->slave_cnt == 0)) { - printk(KERN_INFO DRV_NAME ": %s: destroying bond %s.\n", + pr_info(DRV_NAME ": %s: destroying bond %s.\n", bond_dev->name, bond_dev->name); - bond_destroy(bond); + unregister_netdevice(bond_dev); } return ret; } @@ -2027,9 +2006,8 @@ static int bond_release_all(struct net_device *bond_dev) netif_carrier_off(bond_dev); - if (bond->slave_cnt == 0) { + if (bond->slave_cnt == 0) goto out; - } bond->current_arp_slave = NULL; bond->primary_slave = NULL; @@ -2039,9 +2017,8 @@ static int bond_release_all(struct net_device *bond_dev) /* Inform AD package of unbinding of slave * before slave is detached from the list. */ - if (bond->params.mode == BOND_MODE_8023AD) { + if (bond->params.mode == BOND_MODE_8023AD) bond_3ad_unbind_slave(slave); - } slave_dev = slave->dev; bond_detach_slave(bond, slave); @@ -2070,14 +2047,12 @@ static int bond_release_all(struct net_device *bond_dev) */ if (!USES_PRIMARY(bond->params.mode)) { /* unset promiscuity level from slave */ - if (bond_dev->flags & IFF_PROMISC) { + if (bond_dev->flags & IFF_PROMISC) dev_set_promiscuity(slave_dev, -1); - } /* unset allmulti level from slave */ - if (bond_dev->flags & IFF_ALLMULTI) { + if (bond_dev->flags & IFF_ALLMULTI) dev_set_allmulti(slave_dev, -1); - } /* flush master's mc_list from slave */ netif_addr_lock_bh(bond_dev); @@ -2112,20 +2087,20 @@ static int bond_release_all(struct net_device *bond_dev) */ memset(bond_dev->dev_addr, 0, bond_dev->addr_len); - if (list_empty(&bond->vlan_list)) { + if (list_empty(&bond->vlan_list)) bond_dev->features |= NETIF_F_VLAN_CHALLENGED; - } else { - printk(KERN_WARNING DRV_NAME + else { + pr_warning(DRV_NAME ": %s: Warning: clearing HW address of %s while it " "still has VLANs.\n", bond_dev->name, bond_dev->name); - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": %s: When re-adding slaves, make sure the bond's " "HW address matches its VLANs'.\n", bond_dev->name); } - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: released all slaves\n", bond_dev->name); @@ -2143,8 +2118,8 @@ out: * - is already active. * - The link state of is not BOND_LINK_UP. * - is not running. - * In these cases, this fuction does nothing. - * In the other cases, currnt_slave pointer is changed and 0 is returned. + * In these cases, this function does nothing. + * In the other cases, current_slave pointer is changed and 0 is returned. */ static int bond_ioctl_change_active(struct net_device *bond_dev, struct net_device *slave_dev) { @@ -2153,15 +2128,12 @@ static int bond_ioctl_change_active(struct net_device *bond_dev, struct net_devi struct slave *new_active = NULL; int res = 0; - if (!USES_PRIMARY(bond->params.mode)) { + if (!USES_PRIMARY(bond->params.mode)) return -EINVAL; - } /* Verify that master_dev is indeed the master of slave_dev */ - if (!(slave_dev->flags & IFF_SLAVE) || - (slave_dev->master != bond_dev)) { + if (!(slave_dev->flags & IFF_SLAVE) || (slave_dev->master != bond_dev)) return -EINVAL; - } read_lock(&bond->lock); @@ -2186,9 +2158,8 @@ static int bond_ioctl_change_active(struct net_device *bond_dev, struct net_devi write_lock_bh(&bond->curr_slave_lock); bond_change_active_slave(bond, new_active); write_unlock_bh(&bond->curr_slave_lock); - } else { + } else res = -EINVAL; - } read_unlock(&bond->lock); @@ -2240,6 +2211,9 @@ static int bond_miimon_inspect(struct bonding *bond) { struct slave *slave; int i, link_state, commit = 0; + bool ignore_updelay; + + ignore_updelay = !bond->curr_active_slave ? true : false; bond_for_each_slave(bond, slave, i) { slave->new_link = BOND_LINK_NOCHANGE; @@ -2254,7 +2228,7 @@ static int bond_miimon_inspect(struct bonding *bond) slave->link = BOND_LINK_FAIL; slave->delay = bond->params.downdelay; if (slave->delay) { - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: link status down for %s" "interface %s, disabling it in %d ms.\n", bond->dev->name, @@ -2273,7 +2247,7 @@ static int bond_miimon_inspect(struct bonding *bond) */ slave->link = BOND_LINK_UP; slave->jiffies = jiffies; - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: link status up again after %d " "ms for interface %s.\n", bond->dev->name, @@ -2300,10 +2274,11 @@ static int bond_miimon_inspect(struct bonding *bond) slave->delay = bond->params.updelay; if (slave->delay) { - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: link status up for " "interface %s, enabling it in %d ms.\n", bond->dev->name, slave->dev->name, + ignore_updelay ? 0 : bond->params.updelay * bond->params.miimon); } @@ -2311,7 +2286,7 @@ static int bond_miimon_inspect(struct bonding *bond) case BOND_LINK_BACK: if (!link_state) { slave->link = BOND_LINK_DOWN; - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: link status down again after %d " "ms for interface %s.\n", bond->dev->name, @@ -2322,9 +2297,13 @@ static int bond_miimon_inspect(struct bonding *bond) continue; } + if (ignore_updelay) + slave->delay = 0; + if (slave->delay <= 0) { slave->new_link = BOND_LINK_UP; commit++; + ignore_updelay = false; continue; } @@ -2361,7 +2340,7 @@ static void bond_miimon_commit(struct bonding *bond) slave->state = BOND_STATE_BACKUP; } - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: link status definitely " "up for interface %s.\n", bond->dev->name, slave->dev->name); @@ -2390,7 +2369,7 @@ static void bond_miimon_commit(struct bonding *bond) bond->params.mode == BOND_MODE_8023AD) bond_set_slave_inactive_flags(slave); - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: link status definitely down for " "interface %s, disabling it\n", bond->dev->name, slave->dev->name); @@ -2399,8 +2378,7 @@ static void bond_miimon_commit(struct bonding *bond) bond_3ad_handle_link_change(slave, BOND_LINK_DOWN); - if (bond->params.mode == BOND_MODE_TLB || - bond->params.mode == BOND_MODE_ALB) + if (bond_is_lb(bond)) bond_alb_handle_link_change(bond, slave, BOND_LINK_DOWN); @@ -2410,7 +2388,7 @@ static void bond_miimon_commit(struct bonding *bond) continue; default: - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: invalid new link %d on slave %s\n", bond->dev->name, slave->new_link, slave->dev->name); @@ -2531,18 +2509,18 @@ static void bond_arp_send(struct net_device *slave_dev, int arp_op, __be32 dest_ pr_debug("arp %d on slave %s: dst %x src %x vid %d\n", arp_op, slave_dev->name, dest_ip, src_ip, vlan_id); - + skb = arp_create(arp_op, ETH_P_ARP, dest_ip, slave_dev, src_ip, NULL, slave_dev->dev_addr, NULL); if (!skb) { - printk(KERN_ERR DRV_NAME ": ARP packet allocation failed\n"); + pr_err(DRV_NAME ": ARP packet allocation failed\n"); return; } if (vlan_id) { skb = vlan_put_tag(skb, vlan_id); if (!skb) { - printk(KERN_ERR DRV_NAME ": failed to insert VLAN tag\n"); + pr_err(DRV_NAME ": failed to insert VLAN tag\n"); return; } } @@ -2582,7 +2560,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) rv = ip_route_output_key(&init_net, &rt, &fl); if (rv) { if (net_ratelimit()) { - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": %s: no route to arp_ip_target %pI4\n", bond->dev->name, &fl.fl4_dst); } @@ -2619,7 +2597,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) } if (net_ratelimit()) { - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": %s: no path to arp_ip_target %pI4 via rt.dev %s\n", bond->dev->name, &fl.fl4_dst, rt->u.dst.dev ? rt->u.dst.dev->name : "NULL"); @@ -2767,13 +2745,11 @@ void bond_loadbalance_arp_mon(struct work_struct *work) delta_in_ticks = msecs_to_jiffies(bond->params.arp_interval); - if (bond->kill_timers) { + if (bond->kill_timers) goto out; - } - if (bond->slave_cnt == 0) { + if (bond->slave_cnt == 0) goto re_arm; - } read_lock(&bond->curr_slave_lock); oldcurrent = bond->curr_active_slave; @@ -2789,7 +2765,7 @@ void bond_loadbalance_arp_mon(struct work_struct *work) */ bond_for_each_slave(bond, slave, i) { if (slave->link != BOND_LINK_UP) { - if (time_before_eq(jiffies, slave->dev->trans_start + delta_in_ticks) && + if (time_before_eq(jiffies, dev_trans_start(slave->dev) + delta_in_ticks) && time_before_eq(jiffies, slave->dev->last_rx + delta_in_ticks)) { slave->link = BOND_LINK_UP; @@ -2801,14 +2777,14 @@ void bond_loadbalance_arp_mon(struct work_struct *work) * is closed. */ if (!oldcurrent) { - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: link status definitely " "up for interface %s, ", bond->dev->name, slave->dev->name); do_failover = 1; } else { - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: interface %s is now up\n", bond->dev->name, slave->dev->name); @@ -2821,24 +2797,22 @@ void bond_loadbalance_arp_mon(struct work_struct *work) * when the source ip is 0, so don't take the link down * if we don't know our ip yet */ - if (time_after_eq(jiffies, slave->dev->trans_start + 2*delta_in_ticks) || + if (time_after_eq(jiffies, dev_trans_start(slave->dev) + 2*delta_in_ticks) || (time_after_eq(jiffies, slave->dev->last_rx + 2*delta_in_ticks))) { slave->link = BOND_LINK_DOWN; slave->state = BOND_STATE_BACKUP; - if (slave->link_failure_count < UINT_MAX) { + if (slave->link_failure_count < UINT_MAX) slave->link_failure_count++; - } - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: interface %s is now down.\n", bond->dev->name, slave->dev->name); - if (slave == oldcurrent) { + if (slave == oldcurrent) do_failover = 1; - } } } @@ -2849,9 +2823,8 @@ void bond_loadbalance_arp_mon(struct work_struct *work) * do - all replies will be rx'ed on same link causing slaves * to be unstable during low/no traffic periods */ - if (IS_UP(slave->dev)) { + if (IS_UP(slave->dev)) bond_arp_send_all(bond, slave); - } } if (do_failover) { @@ -2932,7 +2905,7 @@ static int bond_ab_arp_inspect(struct bonding *bond, int delta_in_ticks) * the bond has an IP address) */ if ((slave->state == BOND_STATE_ACTIVE) && - (time_after_eq(jiffies, slave->dev->trans_start + + (time_after_eq(jiffies, dev_trans_start(slave->dev) + 2 * delta_in_ticks) || (time_after_eq(jiffies, slave_last_rx(bond, slave) + 2 * delta_in_ticks)))) { @@ -2976,13 +2949,13 @@ static void bond_ab_arp_commit(struct bonding *bond, int delta_in_ticks) write_lock_bh(&bond->curr_slave_lock); if (!bond->curr_active_slave && - time_before_eq(jiffies, slave->dev->trans_start + + time_before_eq(jiffies, dev_trans_start(slave->dev) + delta_in_ticks)) { slave->link = BOND_LINK_UP; bond_change_active_slave(bond, slave); bond->current_arp_slave = NULL; - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: %s is up and now the " "active interface\n", bond->dev->name, slave->dev->name); @@ -2998,7 +2971,7 @@ static void bond_ab_arp_commit(struct bonding *bond, int delta_in_ticks) bond_set_slave_inactive_flags(slave); bond->current_arp_slave = NULL; - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: backup interface %s is now up\n", bond->dev->name, slave->dev->name); } @@ -3014,7 +2987,7 @@ static void bond_ab_arp_commit(struct bonding *bond, int delta_in_ticks) slave->link = BOND_LINK_DOWN; if (slave == bond->curr_active_slave) { - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: link status down for active " "interface %s, disabling it\n", bond->dev->name, slave->dev->name); @@ -3033,7 +3006,7 @@ static void bond_ab_arp_commit(struct bonding *bond, int delta_in_ticks) bond->current_arp_slave = NULL; } else if (slave->state == BOND_STATE_BACKUP) { - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: backup interface %s is now down\n", bond->dev->name, slave->dev->name); @@ -3042,7 +3015,7 @@ static void bond_ab_arp_commit(struct bonding *bond, int delta_in_ticks) break; default: - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: impossible: new_link %d on slave %s\n", bond->dev->name, slave->new_link, slave->dev->name); @@ -3076,7 +3049,7 @@ static void bond_ab_arp_probe(struct bonding *bond) read_lock(&bond->curr_slave_lock); if (bond->current_arp_slave && bond->curr_active_slave) - printk("PROBE: c_arp %s && cas %s BAD\n", + pr_info(DRV_NAME "PROBE: c_arp %s && cas %s BAD\n", bond->current_arp_slave->dev->name, bond->curr_active_slave->dev->name); @@ -3126,7 +3099,7 @@ static void bond_ab_arp_probe(struct bonding *bond) bond_set_slave_inactive_flags(slave); - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: backup interface %s is now down.\n", bond->dev->name, slave->dev->name); } @@ -3176,9 +3149,8 @@ void bond_activebackup_arp_mon(struct work_struct *work) bond_ab_arp_probe(bond); re_arm: - if (bond->params.arp_interval) { + if (bond->params.arp_interval) queue_delayed_work(bond->wq, &bond->arp_work, delta_in_ticks); - } out: read_unlock(&bond->lock); } @@ -3200,14 +3172,12 @@ static void *bond_info_seq_start(struct seq_file *seq, loff_t *pos) read_lock(&dev_base_lock); read_lock(&bond->lock); - if (*pos == 0) { + if (*pos == 0) return SEQ_START_TOKEN; - } bond_for_each_slave(bond, slave, i) { - if (++off == *pos) { + if (++off == *pos) return slave; - } } return NULL; @@ -3219,9 +3189,8 @@ static void *bond_info_seq_next(struct seq_file *seq, void *v, loff_t *pos) struct slave *slave = v; ++*pos; - if (v == SEQ_START_TOKEN) { + if (v == SEQ_START_TOKEN) return bond->first_slave; - } slave = slave->next; @@ -3284,14 +3253,14 @@ static void bond_info_show_master(struct seq_file *seq) /* ARP information */ - if(bond->params.arp_interval > 0) { - int printed=0; + if (bond->params.arp_interval > 0) { + int printed = 0; seq_printf(seq, "ARP Polling Interval (ms): %d\n", bond->params.arp_interval); seq_printf(seq, "ARP IP target/s (n.n.n.n form):"); - for(i = 0; (i < BOND_MAX_ARP_TARGETS) ;i++) { + for (i = 0; (i < BOND_MAX_ARP_TARGETS); i++) { if (!bond->params.arp_targets[i]) break; if (printed) @@ -3331,7 +3300,8 @@ static void bond_info_show_master(struct seq_file *seq) } } -static void bond_info_show_slave(struct seq_file *seq, const struct slave *slave) +static void bond_info_show_slave(struct seq_file *seq, + const struct slave *slave) { struct bonding *bond = seq->private; @@ -3347,12 +3317,11 @@ static void bond_info_show_slave(struct seq_file *seq, const struct slave *slave const struct aggregator *agg = SLAVE_AD_INFO(slave).port.aggregator; - if (agg) { + if (agg) seq_printf(seq, "Aggregator ID: %d\n", agg->aggregator_identifier); - } else { + else seq_puts(seq, "Aggregator ID: N/A\n"); - } } } @@ -3361,9 +3330,8 @@ static int bond_info_seq_show(struct seq_file *seq, void *v) if (v == SEQ_START_TOKEN) { seq_printf(seq, "%s\n", version); bond_info_show_master(seq); - } else { + } else bond_info_show_slave(seq, v); - } return 0; } @@ -3408,13 +3376,12 @@ static int bond_create_proc_entry(struct bonding *bond) bond->proc_entry = proc_create_data(bond_dev->name, S_IRUGO, bond_proc_dir, &bond_info_fops, bond); - if (bond->proc_entry == NULL) { - printk(KERN_WARNING DRV_NAME + if (bond->proc_entry == NULL) + pr_warning(DRV_NAME ": Warning: Cannot create /proc/net/%s/%s\n", DRV_NAME, bond_dev->name); - } else { + else memcpy(bond->proc_file_name, bond_dev->name, IFNAMSIZ); - } } return 0; @@ -3437,7 +3404,7 @@ static void bond_create_proc_dir(void) if (!bond_proc_dir) { bond_proc_dir = proc_mkdir(DRV_NAME, init_net.proc_net); if (!bond_proc_dir) - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": Warning: cannot create /proc/net/%s\n", DRV_NAME); } @@ -3453,8 +3420,28 @@ static void bond_destroy_proc_dir(void) bond_proc_dir = NULL; } } + +#else /* !CONFIG_PROC_FS */ + +static int bond_create_proc_entry(struct bonding *bond) +{ +} + +static void bond_remove_proc_entry(struct bonding *bond) +{ +} + +static void bond_create_proc_dir(void) +{ +} + +static void bond_destroy_proc_dir(void) +{ +} + #endif /* CONFIG_PROC_FS */ + /*-------------------------- netdev event handling --------------------------*/ /* @@ -3462,18 +3449,17 @@ static void bond_destroy_proc_dir(void) */ static int bond_event_changename(struct bonding *bond) { -#ifdef CONFIG_PROC_FS bond_remove_proc_entry(bond); bond_create_proc_entry(bond); -#endif - down_write(&(bonding_rwsem)); - bond_destroy_sysfs_entry(bond); - bond_create_sysfs_entry(bond); - up_write(&(bonding_rwsem)); + + bond_destroy_sysfs_entry(bond); + bond_create_sysfs_entry(bond); + return NOTIFY_DONE; } -static int bond_master_netdev_event(unsigned long event, struct net_device *bond_dev) +static int bond_master_netdev_event(unsigned long event, + struct net_device *bond_dev) { struct bonding *event_bond = netdev_priv(bond_dev); @@ -3490,7 +3476,8 @@ static int bond_master_netdev_event(unsigned long event, struct net_device *bond return NOTIFY_DONE; } -static int bond_slave_netdev_event(unsigned long event, struct net_device *slave_dev) +static int bond_slave_netdev_event(unsigned long event, + struct net_device *slave_dev) { struct net_device *bond_dev = slave_dev->master; struct bonding *bond = netdev_priv(bond_dev); @@ -3568,7 +3555,8 @@ static int bond_slave_netdev_event(unsigned long event, struct net_device *slave * locks for us to safely manipulate the slave devices (RTNL lock, * dev_probe_lock). */ -static int bond_netdev_event(struct notifier_block *this, unsigned long event, void *ptr) +static int bond_netdev_event(struct notifier_block *this, + unsigned long event, void *ptr) { struct net_device *event_dev = (struct net_device *)ptr; @@ -3923,9 +3911,9 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd switch (cmd) { case SIOCGMIIPHY: mii = if_mii(ifr); - if (!mii) { + if (!mii) return -EINVAL; - } + mii->phy_id = 0; /* Fall Through */ case SIOCGMIIREG: @@ -3934,18 +3922,18 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd * instead of SIOCGMIIPHY. */ mii = if_mii(ifr); - if (!mii) { + if (!mii) return -EINVAL; - } + if (mii->reg_num == 1) { struct bonding *bond = netdev_priv(bond_dev); mii->val_out = 0; read_lock(&bond->lock); read_lock(&bond->curr_slave_lock); - if (netif_carrier_ok(bond->dev)) { + if (netif_carrier_ok(bond->dev)) mii->val_out = BMSR_LSTATUS; - } + read_unlock(&bond->curr_slave_lock); read_unlock(&bond->lock); } @@ -3955,32 +3943,26 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd case SIOCBONDINFOQUERY: u_binfo = (struct ifbond __user *)ifr->ifr_data; - if (copy_from_user(&k_binfo, u_binfo, sizeof(ifbond))) { + if (copy_from_user(&k_binfo, u_binfo, sizeof(ifbond))) return -EFAULT; - } res = bond_info_query(bond_dev, &k_binfo); - if (res == 0) { - if (copy_to_user(u_binfo, &k_binfo, sizeof(ifbond))) { - return -EFAULT; - } - } + if (res == 0 && + copy_to_user(u_binfo, &k_binfo, sizeof(ifbond))) + return -EFAULT; return res; case BOND_SLAVE_INFO_QUERY_OLD: case SIOCBONDSLAVEINFOQUERY: u_sinfo = (struct ifslave __user *)ifr->ifr_data; - if (copy_from_user(&k_sinfo, u_sinfo, sizeof(ifslave))) { + if (copy_from_user(&k_sinfo, u_sinfo, sizeof(ifslave))) return -EFAULT; - } res = bond_slave_info_query(bond_dev, &k_sinfo); - if (res == 0) { - if (copy_to_user(u_sinfo, &k_sinfo, sizeof(ifslave))) { - return -EFAULT; - } - } + if (res == 0 && + copy_to_user(u_sinfo, &k_sinfo, sizeof(ifslave))) + return -EFAULT; return res; default: @@ -3988,18 +3970,16 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd break; } - if (!capable(CAP_NET_ADMIN)) { + if (!capable(CAP_NET_ADMIN)) return -EPERM; - } - down_write(&(bonding_rwsem)); slave_dev = dev_get_by_name(&init_net, ifr->ifr_slave); pr_debug("slave_dev=%p: \n", slave_dev); - if (!slave_dev) { + if (!slave_dev) res = -ENODEV; - } else { + else { pr_debug("slave_dev->name=%s: \n", slave_dev->name); switch (cmd) { case BOND_ENSLAVE_OLD: @@ -4025,7 +4005,6 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd dev_put(slave_dev); } - up_write(&(bonding_rwsem)); return res; } @@ -4037,30 +4016,30 @@ static void bond_set_multicast_list(struct net_device *bond_dev) /* * Do promisc before checking multicast_mode */ - if ((bond_dev->flags & IFF_PROMISC) && !(bond->flags & IFF_PROMISC)) { + if ((bond_dev->flags & IFF_PROMISC) && !(bond->flags & IFF_PROMISC)) /* * FIXME: Need to handle the error when one of the multi-slaves * encounters error. */ bond_set_promiscuity(bond, 1); - } - if (!(bond_dev->flags & IFF_PROMISC) && (bond->flags & IFF_PROMISC)) { + + if (!(bond_dev->flags & IFF_PROMISC) && (bond->flags & IFF_PROMISC)) bond_set_promiscuity(bond, -1); - } + /* set allmulti flag to slaves */ - if ((bond_dev->flags & IFF_ALLMULTI) && !(bond->flags & IFF_ALLMULTI)) { + if ((bond_dev->flags & IFF_ALLMULTI) && !(bond->flags & IFF_ALLMULTI)) /* * FIXME: Need to handle the error when one of the multi-slaves * encounters error. */ bond_set_allmulti(bond, 1); - } - if (!(bond_dev->flags & IFF_ALLMULTI) && (bond->flags & IFF_ALLMULTI)) { + + if (!(bond_dev->flags & IFF_ALLMULTI) && (bond->flags & IFF_ALLMULTI)) bond_set_allmulti(bond, -1); - } + read_lock(&bond->lock); @@ -4068,16 +4047,14 @@ static void bond_set_multicast_list(struct net_device *bond_dev) /* looking for addresses to add to slaves' mc list */ for (dmi = bond_dev->mc_list; dmi; dmi = dmi->next) { - if (!bond_mc_list_find_dmi(dmi, bond->mc_list)) { + if (!bond_mc_list_find_dmi(dmi, bond->mc_list)) bond_mc_add(bond, dmi->dmi_addr, dmi->dmi_addrlen); - } } /* looking for addresses to delete from slaves' list */ for (dmi = bond->mc_list; dmi; dmi = dmi->next) { - if (!bond_mc_list_find_dmi(dmi, bond_dev->mc_list)) { + if (!bond_mc_list_find_dmi(dmi, bond_dev->mc_list)) bond_mc_delete(bond, dmi->dmi_addr, dmi->dmi_addrlen); - } } /* save master's multicast list */ @@ -4197,9 +4174,8 @@ static int bond_set_mac_address(struct net_device *bond_dev, void *addr) if (bond->params.fail_over_mac == BOND_FOM_ACTIVE) return 0; - if (!is_valid_ether_addr(sa->sa_data)) { + if (!is_valid_ether_addr(sa->sa_data)) return -EADDRNOTAVAIL; - } /* Can't hold bond->lock with bh disabled here since * some base drivers panic. On the other hand we can't @@ -4270,9 +4246,8 @@ static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *bond_dev read_lock(&bond->lock); - if (!BOND_IS_OK(bond)) { + if (!BOND_IS_OK(bond)) goto out; - } /* * Concurrent TX may collide on rr_tx_counter; we accept that @@ -4282,9 +4257,8 @@ static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *bond_dev bond_for_each_slave(bond, slave, i) { slave_no--; - if (slave_no < 0) { + if (slave_no < 0) break; - } } start_at = slave; @@ -4319,9 +4293,8 @@ static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *bond_d read_lock(&bond->lock); read_lock(&bond->curr_slave_lock); - if (!BOND_IS_OK(bond)) { + if (!BOND_IS_OK(bond)) goto out; - } if (!bond->curr_active_slave) goto out; @@ -4329,10 +4302,10 @@ static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *bond_d res = bond_dev_queue_xmit(bond, skb, bond->curr_active_slave->dev); out: - if (res) { + if (res) /* no suitable interface, frame not sent */ dev_kfree_skb(skb); - } + read_unlock(&bond->curr_slave_lock); read_unlock(&bond->lock); return 0; @@ -4353,17 +4326,15 @@ static int bond_xmit_xor(struct sk_buff *skb, struct net_device *bond_dev) read_lock(&bond->lock); - if (!BOND_IS_OK(bond)) { + if (!BOND_IS_OK(bond)) goto out; - } slave_no = bond->xmit_hash_policy(skb, bond_dev, bond->slave_cnt); bond_for_each_slave(bond, slave, i) { slave_no--; - if (slave_no < 0) { + if (slave_no < 0) break; - } } start_at = slave; @@ -4399,17 +4370,15 @@ static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *bond_dev) read_lock(&bond->lock); - if (!BOND_IS_OK(bond)) { + if (!BOND_IS_OK(bond)) goto out; - } read_lock(&bond->curr_slave_lock); start_at = bond->curr_active_slave; read_unlock(&bond->curr_slave_lock); - if (!start_at) { + if (!start_at) goto out; - } bond_for_each_slave_from(bond, slave, i, start_at) { if (IS_UP(slave->dev) && @@ -4418,7 +4387,7 @@ static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *bond_dev) if (tx_dev) { struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); if (!skb2) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Error: bond_xmit_broadcast(): " "skb_clone() failed\n", bond_dev->name); @@ -4435,15 +4404,14 @@ static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *bond_dev) } } - if (tx_dev) { + if (tx_dev) res = bond_dev_queue_xmit(bond, skb, tx_dev); - } out: - if (res) { + if (res) /* no suitable interface, frame not sent */ dev_kfree_skb(skb); - } + /* frame sent to all suitable interfaces */ read_unlock(&bond->lock); return 0; @@ -4487,7 +4455,7 @@ static int bond_start_xmit(struct sk_buff *skb, struct net_device *dev) return bond_alb_xmit(skb, dev); default: /* Should never happen, mode already checked */ - printk(KERN_ERR DRV_NAME ": %s: Error: Unknown bonding mode %d\n", + pr_err(DRV_NAME ": %s: Error: Unknown bonding mode %d\n", dev->name, bond->params.mode); WARN_ON_ONCE(1); dev_kfree_skb(skb); @@ -4524,7 +4492,7 @@ void bond_set_mode_ops(struct bonding *bond, int mode) break; default: /* Should never happen, mode already checked */ - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Error: Unknown bonding mode %d\n", bond_dev->name, mode); @@ -4551,6 +4519,8 @@ static const struct ethtool_ops bond_ethtool_ops = { }; static const struct net_device_ops bond_netdev_ops = { + .ndo_init = bond_init, + .ndo_uninit = bond_uninit, .ndo_open = bond_open, .ndo_stop = bond_close, .ndo_start_xmit = bond_start_xmit, @@ -4565,48 +4535,34 @@ static const struct net_device_ops bond_netdev_ops = { .ndo_vlan_rx_kill_vid = bond_vlan_rx_kill_vid, }; -/* - * Does not allocate but creates a /proc entry. - * Allowed to fail. - */ -static int bond_init(struct net_device *bond_dev, struct bond_params *params) +static void bond_setup(struct net_device *bond_dev) { struct bonding *bond = netdev_priv(bond_dev); - pr_debug("Begin bond_init for %s\n", bond_dev->name); - /* initialize rwlocks */ rwlock_init(&bond->lock); rwlock_init(&bond->curr_slave_lock); - bond->params = *params; /* copy params struct */ - - bond->wq = create_singlethread_workqueue(bond_dev->name); - if (!bond->wq) - return -ENOMEM; + bond->params = bonding_defaults; /* Initialize pointers */ - bond->first_slave = NULL; - bond->curr_active_slave = NULL; - bond->current_arp_slave = NULL; - bond->primary_slave = NULL; bond->dev = bond_dev; - bond->send_grat_arp = 0; - bond->send_unsol_na = 0; - bond->setup_by_slave = 0; INIT_LIST_HEAD(&bond->vlan_list); /* Initialize the device entry points */ + ether_setup(bond_dev); bond_dev->netdev_ops = &bond_netdev_ops; bond_dev->ethtool_ops = &bond_ethtool_ops; bond_set_mode_ops(bond, bond->params.mode); - bond_dev->destructor = bond_destructor; + bond_dev->destructor = free_netdev; /* Initialize the device options */ bond_dev->tx_queue_len = 0; bond_dev->flags |= IFF_MASTER|IFF_MULTICAST; bond_dev->priv_flags |= IFF_BONDING; + bond_dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; + if (bond->params.arp_interval) bond_dev->priv_flags |= IFF_MASTER_ARPMON; @@ -4631,12 +4587,6 @@ static int bond_init(struct net_device *bond_dev, struct bond_params *params) NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER); -#ifdef CONFIG_PROC_FS - bond_create_proc_entry(bond); -#endif - list_add_tail(&bond->bond_list, &bond_dev_list); - - return 0; } static void bond_work_cancel_all(struct bonding *bond) @@ -4671,9 +4621,7 @@ static void bond_deinit(struct net_device *bond_dev) bond_work_cancel_all(bond); -#ifdef CONFIG_PROC_FS bond_remove_proc_entry(bond); -#endif } /* Unregister and free all bond devices. @@ -4689,12 +4637,10 @@ static void bond_free_all(void) bond_work_cancel_all(bond); /* Release the bonded slaves */ bond_release_all(bond_dev); - bond_destroy(bond); + unregister_netdevice(bond_dev); } -#ifdef CONFIG_PROC_FS bond_destroy_proc_dir(); -#endif } /*------------------------- Module initialization ---------------------------*/ @@ -4742,7 +4688,7 @@ static int bond_check_params(struct bond_params *params) if (mode) { bond_mode = bond_parse_parm(mode, bond_mode_tbl); if (bond_mode == -1) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": Error: Invalid bonding mode \"%s\"\n", mode == NULL ? "NULL" : mode); return -EINVAL; @@ -4752,16 +4698,16 @@ static int bond_check_params(struct bond_params *params) if (xmit_hash_policy) { if ((bond_mode != BOND_MODE_XOR) && (bond_mode != BOND_MODE_8023AD)) { - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": xor_mode param is irrelevant in mode %s\n", bond_mode_name(bond_mode)); } else { xmit_hashtype = bond_parse_parm(xmit_hash_policy, xmit_hashtype_tbl); if (xmit_hashtype == -1) { - printk(KERN_ERR DRV_NAME - ": Error: Invalid xmit_hash_policy \"%s\"\n", - xmit_hash_policy == NULL ? "NULL" : + pr_err(DRV_NAME + ": Error: Invalid xmit_hash_policy \"%s\"\n", + xmit_hash_policy == NULL ? "NULL" : xmit_hash_policy); return -EINVAL; } @@ -4770,13 +4716,13 @@ static int bond_check_params(struct bond_params *params) if (lacp_rate) { if (bond_mode != BOND_MODE_8023AD) { - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": lacp_rate param is irrelevant in mode %s\n", bond_mode_name(bond_mode)); } else { lacp_fast = bond_parse_parm(lacp_rate, bond_lacp_tbl); if (lacp_fast == -1) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": Error: Invalid lacp rate \"%s\"\n", lacp_rate == NULL ? "NULL" : lacp_rate); return -EINVAL; @@ -4787,14 +4733,14 @@ static int bond_check_params(struct bond_params *params) if (ad_select) { params->ad_select = bond_parse_parm(ad_select, ad_select_tbl); if (params->ad_select == -1) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": Error: Invalid ad_select \"%s\"\n", ad_select == NULL ? "NULL" : ad_select); return -EINVAL; } if (bond_mode != BOND_MODE_8023AD) { - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": ad_select param only affects 802.3ad mode\n"); } } else { @@ -4802,7 +4748,7 @@ static int bond_check_params(struct bond_params *params) } if (max_bonds < 0 || max_bonds > INT_MAX) { - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": Warning: max_bonds (%d) not in range %d-%d, so it " "was reset to BOND_DEFAULT_MAX_BONDS (%d)\n", max_bonds, 0, INT_MAX, BOND_DEFAULT_MAX_BONDS); @@ -4810,7 +4756,7 @@ static int bond_check_params(struct bond_params *params) } if (miimon < 0) { - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": Warning: miimon module parameter (%d), " "not in range 0-%d, so it was reset to %d\n", miimon, INT_MAX, BOND_LINK_MON_INTERV); @@ -4818,7 +4764,7 @@ static int bond_check_params(struct bond_params *params) } if (updelay < 0) { - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": Warning: updelay module parameter (%d), " "not in range 0-%d, so it was reset to 0\n", updelay, INT_MAX); @@ -4826,7 +4772,7 @@ static int bond_check_params(struct bond_params *params) } if (downdelay < 0) { - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": Warning: downdelay module parameter (%d), " "not in range 0-%d, so it was reset to 0\n", downdelay, INT_MAX); @@ -4834,7 +4780,7 @@ static int bond_check_params(struct bond_params *params) } if ((use_carrier != 0) && (use_carrier != 1)) { - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": Warning: use_carrier module parameter (%d), " "not of valid value (0/1), so it was set to 1\n", use_carrier); @@ -4842,14 +4788,14 @@ static int bond_check_params(struct bond_params *params) } if (num_grat_arp < 0 || num_grat_arp > 255) { - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": Warning: num_grat_arp (%d) not in range 0-255 so it " "was reset to 1 \n", num_grat_arp); num_grat_arp = 1; } if (num_unsol_na < 0 || num_unsol_na > 255) { - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": Warning: num_unsol_na (%d) not in range 0-255 so it " "was reset to 1 \n", num_unsol_na); num_unsol_na = 1; @@ -4858,12 +4804,12 @@ static int bond_check_params(struct bond_params *params) /* reset values for 802.3ad */ if (bond_mode == BOND_MODE_8023AD) { if (!miimon) { - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": Warning: miimon must be specified, " "otherwise bonding will not detect link " "failure, speed and duplex which are " "essential for 802.3ad operation\n"); - printk(KERN_WARNING "Forcing miimon to 100msec\n"); + pr_warning("Forcing miimon to 100msec\n"); miimon = 100; } } @@ -4872,12 +4818,12 @@ static int bond_check_params(struct bond_params *params) if ((bond_mode == BOND_MODE_TLB) || (bond_mode == BOND_MODE_ALB)) { if (!miimon) { - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": Warning: miimon must be specified, " "otherwise bonding will not detect link " "failure and link speed which are essential " "for TLB/ALB load balancing\n"); - printk(KERN_WARNING "Forcing miimon to 100msec\n"); + pr_warning("Forcing miimon to 100msec\n"); miimon = 100; } } @@ -4897,7 +4843,7 @@ static int bond_check_params(struct bond_params *params) /* just warn the user the up/down delay will have * no effect since miimon is zero... */ - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": Warning: miimon module parameter not set " "and updelay (%d) or downdelay (%d) module " "parameter is set; updelay and downdelay have " @@ -4907,7 +4853,7 @@ static int bond_check_params(struct bond_params *params) } else { /* don't allow arp monitoring */ if (arp_interval) { - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": Warning: miimon (%d) and arp_interval (%d) " "can't be used simultaneously, disabling ARP " "monitoring\n", @@ -4916,7 +4862,7 @@ static int bond_check_params(struct bond_params *params) } if ((updelay % miimon) != 0) { - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": Warning: updelay (%d) is not a multiple " "of miimon (%d), updelay rounded to %d ms\n", updelay, miimon, (updelay / miimon) * miimon); @@ -4925,7 +4871,7 @@ static int bond_check_params(struct bond_params *params) updelay /= miimon; if ((downdelay % miimon) != 0) { - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": Warning: downdelay (%d) is not a multiple " "of miimon (%d), downdelay rounded to %d ms\n", downdelay, miimon, @@ -4936,7 +4882,7 @@ static int bond_check_params(struct bond_params *params) } if (arp_interval < 0) { - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": Warning: arp_interval module parameter (%d) " ", not in range 0-%d, so it was reset to %d\n", arp_interval, INT_MAX, BOND_LINK_ARP_INTERV); @@ -4949,7 +4895,7 @@ static int bond_check_params(struct bond_params *params) /* not complete check, but should be good enough to catch mistakes */ if (!isdigit(arp_ip_target[arp_ip_count][0])) { - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": Warning: bad arp_ip_target module parameter " "(%s), ARP monitoring will not be performed\n", arp_ip_target[arp_ip_count]); @@ -4962,7 +4908,7 @@ static int bond_check_params(struct bond_params *params) if (arp_interval && !arp_ip_count) { /* don't allow arping if no arp_ip_target given... */ - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": Warning: arp_interval module parameter (%d) " "specified without providing an arp_ip_target " "parameter, arp_interval was reset to 0\n", @@ -4972,12 +4918,12 @@ static int bond_check_params(struct bond_params *params) if (arp_validate) { if (bond_mode != BOND_MODE_ACTIVEBACKUP) { - printk(KERN_ERR DRV_NAME - ": arp_validate only supported in active-backup mode\n"); + pr_err(DRV_NAME + ": arp_validate only supported in active-backup mode\n"); return -EINVAL; } if (!arp_interval) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": arp_validate requires arp_interval\n"); return -EINVAL; } @@ -4985,7 +4931,7 @@ static int bond_check_params(struct bond_params *params) arp_validate_value = bond_parse_parm(arp_validate, arp_validate_tbl); if (arp_validate_value == -1) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": Error: invalid arp_validate \"%s\"\n", arp_validate == NULL ? "NULL" : arp_validate); return -EINVAL; @@ -4994,20 +4940,20 @@ static int bond_check_params(struct bond_params *params) arp_validate_value = 0; if (miimon) { - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": MII link monitoring set to %d ms\n", miimon); } else if (arp_interval) { int i; - printk(KERN_INFO DRV_NAME - ": ARP monitoring set to %d ms, validate %s, with %d target(s):", + pr_info(DRV_NAME ": ARP monitoring set to %d ms," + " validate %s, with %d target(s):", arp_interval, arp_validate_tbl[arp_validate_value].modename, arp_ip_count); for (i = 0; i < arp_ip_count; i++) - printk (" %s", arp_ip_target[i]); + printk(" %s", arp_ip_target[i]); printk("\n"); @@ -5015,7 +4961,7 @@ static int bond_check_params(struct bond_params *params) /* miimon and arp_interval not set, we need one so things * work as expected, see bonding.txt for details */ - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": Warning: either miimon or arp_interval and " "arp_ip_target module parameters must be specified, " "otherwise bonding will not detect link failures! see " @@ -5026,7 +4972,7 @@ static int bond_check_params(struct bond_params *params) /* currently, using a primary only makes sense * in active backup, TLB or ALB modes */ - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": Warning: %s primary device specified but has no " "effect in %s mode\n", primary, bond_mode_name(bond_mode)); @@ -5037,14 +4983,14 @@ static int bond_check_params(struct bond_params *params) fail_over_mac_value = bond_parse_parm(fail_over_mac, fail_over_mac_tbl); if (fail_over_mac_value == -1) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": Error: invalid fail_over_mac \"%s\"\n", arp_validate == NULL ? "NULL" : arp_validate); return -EINVAL; } if (bond_mode != BOND_MODE_ACTIVEBACKUP) - printk(KERN_WARNING DRV_NAME + pr_warning(DRV_NAME ": Warning: fail_over_mac only affects " "active-backup mode.\n"); } else { @@ -5094,37 +5040,53 @@ static void bond_set_lockdep_class(struct net_device *dev) netdev_for_each_tx_queue(dev, bond_set_lockdep_class_one, NULL); } +/* + * Called from registration process + */ +static int bond_init(struct net_device *bond_dev) +{ + struct bonding *bond = netdev_priv(bond_dev); + + pr_debug("Begin bond_init for %s\n", bond_dev->name); + + bond->wq = create_singlethread_workqueue(bond_dev->name); + if (!bond->wq) + return -ENOMEM; + + bond_set_lockdep_class(bond_dev); + + netif_carrier_off(bond_dev); + + bond_create_proc_entry(bond); + list_add_tail(&bond->bond_list, &bond_dev_list); + + return 0; +} + /* Create a new bond based on the specified name and bonding parameters. * If name is NULL, obtain a suitable "bond%d" name for us. * Caller must NOT hold rtnl_lock; we need to release it here before we * set up our sysfs entries. */ -int bond_create(char *name, struct bond_params *params) +int bond_create(const char *name) { struct net_device *bond_dev; - struct bonding *bond; int res; rtnl_lock(); - down_write(&bonding_rwsem); - /* Check to see if the bond already exists. */ - if (name) { - list_for_each_entry(bond, &bond_dev_list, bond_list) - if (strnicmp(bond->dev->name, name, IFNAMSIZ) == 0) { - printk(KERN_ERR DRV_NAME - ": cannot add bond %s; it already exists\n", - name); - res = -EPERM; - goto out_rtnl; - } + /* FIXME: pass netns from caller */ + if (name && __dev_get_by_name(&init_net, name)) { + pr_err(DRV_NAME ": cannot add bond %s; already exists\n", + name); + res = -EEXIST; + goto out_rtnl; } bond_dev = alloc_netdev(sizeof(struct bonding), name ? name : "", - ether_setup); + bond_setup); if (!bond_dev) { - printk(KERN_ERR DRV_NAME - ": %s: eek! can't alloc netdev!\n", + pr_err(DRV_NAME ": %s: eek! can't alloc netdev!\n", name); res = -ENOMEM; goto out_rtnl; @@ -5136,43 +5098,24 @@ int bond_create(char *name, struct bond_params *params) goto out_netdev; } - /* bond_init() must be called after dev_alloc_name() (for the - * /proc files), but before register_netdevice(), because we - * need to set function pointers. - */ - - res = bond_init(bond_dev, params); - if (res < 0) { - goto out_netdev; - } - res = register_netdevice(bond_dev); - if (res < 0) { + if (res < 0) goto out_bond; - } - bond_set_lockdep_class(bond_dev); - - netif_carrier_off(bond_dev); - - up_write(&bonding_rwsem); - rtnl_unlock(); /* allows sysfs registration of net device */ res = bond_create_sysfs_entry(netdev_priv(bond_dev)); if (res < 0) goto out_unreg; + rtnl_unlock(); return 0; out_unreg: - rtnl_lock(); - down_write(&bonding_rwsem); unregister_netdevice(bond_dev); out_bond: bond_deinit(bond_dev); out_netdev: free_netdev(bond_dev); out_rtnl: - up_write(&bonding_rwsem); rtnl_unlock(); return res; } @@ -5182,21 +5125,16 @@ static int __init bonding_init(void) int i; int res; - printk(KERN_INFO "%s", version); + pr_info("%s", version); res = bond_check_params(&bonding_defaults); - if (res) { + if (res) goto out; - } -#ifdef CONFIG_PROC_FS bond_create_proc_dir(); -#endif - - init_rwsem(&bonding_rwsem); for (i = 0; i < max_bonds; i++) { - res = bond_create(NULL, &bonding_defaults); + res = bond_create(NULL); if (res) goto err; } @@ -5238,13 +5176,3 @@ MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_VERSION); MODULE_DESCRIPTION(DRV_DESCRIPTION ", v" DRV_VERSION); MODULE_AUTHOR("Thomas Davis, tadavis@lbl.gov and many others"); -MODULE_SUPPORTED_DEVICE("most ethernet devices"); - -/* - * Local variables: - * c-indent-level: 8 - * c-basic-offset: 8 - * tab-width: 8 - * End: - */ - diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index d28731535226..55bf34f59bbf 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -1,4 +1,3 @@ - /* * Copyright(c) 2004-2005 Intel Corporation. All rights reserved. * @@ -34,33 +33,14 @@ #include #include #include +#include #include #include "bonding.h" -#define to_dev(obj) container_of(obj,struct device,kobj) +#define to_dev(obj) container_of(obj, struct device, kobj) #define to_bond(cd) ((struct bonding *)(netdev_priv(to_net_dev(cd)))) -/*---------------------------- Declarations -------------------------------*/ - -static int expected_refcount = -1; -/*--------------------------- Data Structures -----------------------------*/ - -/* Bonding sysfs lock. Why can't we just use the subsystem lock? - * Because kobject_register tries to acquire the subsystem lock. If - * we already hold the lock (which we would if the user was creating - * a new bond through the sysfs interface), we deadlock. - * This lock is only needed when deleting a bond - we need to make sure - * that we don't collide with an ongoing ioctl. - */ - -struct rw_semaphore bonding_rwsem; - - - - -/*------------------------------ Functions --------------------------------*/ - /* * "show" function for the bond_masters attribute. * The class parameter is ignored. @@ -70,7 +50,7 @@ static ssize_t bonding_show_bonds(struct class *cls, char *buf) int res = 0; struct bonding *bond; - down_read(&(bonding_rwsem)); + rtnl_lock(); list_for_each_entry(bond, &bond_dev_list, bond_list) { if (res > (PAGE_SIZE - IFNAMSIZ)) { @@ -84,10 +64,22 @@ static ssize_t bonding_show_bonds(struct class *cls, char *buf) } if (res) buf[res-1] = '\n'; /* eat the leftover space */ - up_read(&(bonding_rwsem)); + + rtnl_unlock(); return res; } +static struct net_device *bond_get_by_name(const char *ifname) +{ + struct bonding *bond; + + list_for_each_entry(bond, &bond_dev_list, bond_list) { + if (strncmp(bond->dev->name, ifname, IFNAMSIZ) == 0) + return bond->dev; + } + return NULL; +} + /* * "store" function for the bond_masters attribute. This is what * creates and deletes entire bonds. @@ -96,12 +88,12 @@ static ssize_t bonding_show_bonds(struct class *cls, char *buf) * */ -static ssize_t bonding_store_bonds(struct class *cls, const char *buffer, size_t count) +static ssize_t bonding_store_bonds(struct class *cls, + const char *buffer, size_t count) { char command[IFNAMSIZ + 1] = {0, }; char *ifname; int rv, res = count; - struct bonding *bond; sscanf(buffer, "%16s", command); /* IFNAMSIZ*/ ifname = command + 1; @@ -110,67 +102,48 @@ static ssize_t bonding_store_bonds(struct class *cls, const char *buffer, size_t goto err_no_cmd; if (command[0] == '+') { - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s is being created...\n", ifname); - rv = bond_create(ifname, &bonding_defaults); + rv = bond_create(ifname); if (rv) { - printk(KERN_INFO DRV_NAME ": Bond creation failed.\n"); + pr_info(DRV_NAME ": Bond creation failed.\n"); res = rv; } - goto out; - } + } else if (command[0] == '-') { + struct net_device *bond_dev; - if (command[0] == '-') { rtnl_lock(); - down_write(&bonding_rwsem); - - list_for_each_entry(bond, &bond_dev_list, bond_list) - if (strnicmp(bond->dev->name, ifname, IFNAMSIZ) == 0) { - /* check the ref count on the bond's kobject. - * If it's > expected, then there's a file open, - * and we have to fail. - */ - if (atomic_read(&bond->dev->dev.kobj.kref.refcount) - > expected_refcount){ - printk(KERN_INFO DRV_NAME - ": Unable remove bond %s due to open references.\n", - ifname); - res = -EPERM; - goto out_unlock; - } - printk(KERN_INFO DRV_NAME - ": %s is being deleted...\n", - bond->dev->name); - bond_destroy(bond); - goto out_unlock; - } - - printk(KERN_ERR DRV_NAME - ": unable to delete non-existent bond %s\n", ifname); - res = -ENODEV; - goto out_unlock; - } - -err_no_cmd: - printk(KERN_ERR DRV_NAME - ": no command found in bonding_masters. Use +ifname or -ifname.\n"); - return -EPERM; - -out_unlock: - up_write(&bonding_rwsem); - rtnl_unlock(); + bond_dev = bond_get_by_name(ifname); + if (bond_dev) { + pr_info(DRV_NAME ": %s is being deleted...\n", + ifname); + unregister_netdevice(bond_dev); + } else { + pr_err(DRV_NAME ": unable to delete non-existent %s\n", + ifname); + res = -ENODEV; + } + rtnl_unlock(); + } else + goto err_no_cmd; /* Always return either count or an error. If you return 0, you'll * get called forever, which is bad. */ -out: return res; + +err_no_cmd: + pr_err(DRV_NAME ": no command found in bonding_masters." + " Use +ifname or -ifname.\n"); + return -EPERM; } + /* class attribute for bond_masters file. This ends up in /sys/class/net */ static CLASS_ATTR(bonding_masters, S_IWUSR | S_IRUGO, bonding_show_bonds, bonding_store_bonds); -int bond_create_slave_symlinks(struct net_device *master, struct net_device *slave) +int bond_create_slave_symlinks(struct net_device *master, + struct net_device *slave) { char linkname[IFNAMSIZ+7]; int ret = 0; @@ -181,19 +154,20 @@ int bond_create_slave_symlinks(struct net_device *master, struct net_device *sla if (ret) return ret; /* next, create a link from the master to the slave */ - sprintf(linkname,"slave_%s",slave->name); + sprintf(linkname, "slave_%s", slave->name); ret = sysfs_create_link(&(master->dev.kobj), &(slave->dev.kobj), linkname); return ret; } -void bond_destroy_slave_symlinks(struct net_device *master, struct net_device *slave) +void bond_destroy_slave_symlinks(struct net_device *master, + struct net_device *slave) { char linkname[IFNAMSIZ+7]; sysfs_remove_link(&(slave->dev.kobj), "master"); - sprintf(linkname,"slave_%s",slave->name); + sprintf(linkname, "slave_%s", slave->name); sysfs_remove_link(&(master->dev.kobj), linkname); } @@ -251,8 +225,8 @@ static ssize_t bonding_store_slaves(struct device *d, /* Note: We can't hold bond->lock here, as bond_create grabs it. */ - rtnl_lock(); - down_write(&(bonding_rwsem)); + if (!rtnl_trylock()) + return restart_syscall(); sscanf(buffer, "%16s", command); /* IFNAMSIZ*/ ifname = command + 1; @@ -264,46 +238,47 @@ static ssize_t bonding_store_slaves(struct device *d, /* Got a slave name in ifname. Is it already in the list? */ found = 0; - read_lock(&bond->lock); - bond_for_each_slave(bond, slave, i) - if (strnicmp(slave->dev->name, ifname, IFNAMSIZ) == 0) { - printk(KERN_ERR DRV_NAME - ": %s: Interface %s is already enslaved!\n", - bond->dev->name, ifname); - ret = -EPERM; - read_unlock(&bond->lock); - goto out; - } - read_unlock(&bond->lock); - printk(KERN_INFO DRV_NAME ": %s: Adding slave %s.\n", - bond->dev->name, ifname); - dev = dev_get_by_name(&init_net, ifname); + /* FIXME: get netns from sysfs object */ + dev = __dev_get_by_name(&init_net, ifname); if (!dev) { - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: Interface %s does not exist!\n", bond->dev->name, ifname); - ret = -EPERM; + ret = -ENODEV; goto out; } - else - dev_put(dev); if (dev->flags & IFF_UP) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Error: Unable to enslave %s " "because it is already up.\n", bond->dev->name, dev->name); ret = -EPERM; goto out; } + + read_lock(&bond->lock); + bond_for_each_slave(bond, slave, i) + if (slave->dev == dev) { + pr_err(DRV_NAME + ": %s: Interface %s is already enslaved!\n", + bond->dev->name, ifname); + ret = -EPERM; + read_unlock(&bond->lock); + goto out; + } + read_unlock(&bond->lock); + + pr_info(DRV_NAME ": %s: Adding slave %s.\n", + bond->dev->name, ifname); + /* If this is the first slave, then we need to set the master's hardware address to be the same as the slave's. */ - if (!(*((u32 *) & (bond->dev->dev_addr[0])))) { + if (is_zero_ether_addr(bond->dev->dev_addr)) memcpy(bond->dev->dev_addr, dev->dev_addr, dev->addr_len); - } /* Set the slave's MTU to match the bond */ original_mtu = dev->mtu; @@ -317,9 +292,9 @@ static ssize_t bonding_store_slaves(struct device *d, bond_for_each_slave(bond, slave, i) if (strnicmp(slave->dev->name, ifname, IFNAMSIZ) == 0) slave->original_mtu = original_mtu; - if (res) { + if (res) ret = res; - } + goto out; } @@ -333,7 +308,7 @@ static ssize_t bonding_store_slaves(struct device *d, break; } if (dev) { - printk(KERN_INFO DRV_NAME ": %s: Removing slave %s\n", + pr_info(DRV_NAME ": %s: Removing slave %s\n", bond->dev->name, dev->name); res = bond_release(bond->dev, dev); if (res) { @@ -342,9 +317,9 @@ static ssize_t bonding_store_slaves(struct device *d, } /* set the slave MTU to the default */ dev_set_mtu(dev, original_mtu); - } - else { - printk(KERN_ERR DRV_NAME ": unable to remove non-existent slave %s for bond %s.\n", + } else { + pr_err(DRV_NAME ": unable to remove non-existent" + " slave %s for bond %s.\n", ifname, bond->dev->name); ret = -ENODEV; } @@ -352,16 +327,16 @@ static ssize_t bonding_store_slaves(struct device *d, } err_no_cmd: - printk(KERN_ERR DRV_NAME ": no command found in slaves file for bond %s. Use +ifname or -ifname.\n", bond->dev->name); + pr_err(DRV_NAME ": no command found in slaves file for bond %s. Use +ifname or -ifname.\n", bond->dev->name); ret = -EPERM; out: - up_write(&(bonding_rwsem)); rtnl_unlock(); return ret; } -static DEVICE_ATTR(slaves, S_IRUGO | S_IWUSR, bonding_show_slaves, bonding_store_slaves); +static DEVICE_ATTR(slaves, S_IRUGO | S_IWUSR, bonding_show_slaves, + bonding_store_slaves); /* * Show and set the bonding mode. The bond interface must be down to @@ -385,16 +360,15 @@ static ssize_t bonding_store_mode(struct device *d, struct bonding *bond = to_bond(d); if (bond->dev->flags & IFF_UP) { - printk(KERN_ERR DRV_NAME - ": unable to update mode of %s because interface is up.\n", - bond->dev->name); + pr_err(DRV_NAME ": unable to update mode of %s" + " because interface is up.\n", bond->dev->name); ret = -EPERM; goto out; } new_value = bond_parse_parm(buf, bond_mode_tbl); if (new_value < 0) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Ignoring invalid mode value %.*s.\n", bond->dev->name, (int)strlen(buf) - 1, buf); @@ -409,17 +383,19 @@ static ssize_t bonding_store_mode(struct device *d, bond->params.mode = new_value; bond_set_mode_ops(bond, bond->params.mode); - printk(KERN_INFO DRV_NAME ": %s: setting mode to %s (%d).\n", - bond->dev->name, bond_mode_tbl[new_value].modename, new_value); + pr_info(DRV_NAME ": %s: setting mode to %s (%d).\n", + bond->dev->name, bond_mode_tbl[new_value].modename, + new_value); } out: return ret; } -static DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, bonding_show_mode, bonding_store_mode); +static DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, + bonding_show_mode, bonding_store_mode); /* - * Show and set the bonding transmit hash method. The bond interface must be down to - * change the xmit hash policy. + * Show and set the bonding transmit hash method. + * The bond interface must be down to change the xmit hash policy. */ static ssize_t bonding_show_xmit_hash(struct device *d, struct device_attribute *attr, @@ -440,7 +416,7 @@ static ssize_t bonding_store_xmit_hash(struct device *d, struct bonding *bond = to_bond(d); if (bond->dev->flags & IFF_UP) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME "%s: Interface is up. Unable to update xmit policy.\n", bond->dev->name); ret = -EPERM; @@ -449,7 +425,7 @@ static ssize_t bonding_store_xmit_hash(struct device *d, new_value = bond_parse_parm(buf, xmit_hashtype_tbl); if (new_value < 0) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Ignoring invalid xmit hash policy value %.*s.\n", bond->dev->name, (int)strlen(buf) - 1, buf); @@ -458,13 +434,15 @@ static ssize_t bonding_store_xmit_hash(struct device *d, } else { bond->params.xmit_policy = new_value; bond_set_mode_ops(bond, bond->params.mode); - printk(KERN_INFO DRV_NAME ": %s: setting xmit hash policy to %s (%d).\n", - bond->dev->name, xmit_hashtype_tbl[new_value].modename, new_value); + pr_info(DRV_NAME ": %s: setting xmit hash policy to %s (%d).\n", + bond->dev->name, + xmit_hashtype_tbl[new_value].modename, new_value); } out: return ret; } -static DEVICE_ATTR(xmit_hash_policy, S_IRUGO | S_IWUSR, bonding_show_xmit_hash, bonding_store_xmit_hash); +static DEVICE_ATTR(xmit_hash_policy, S_IRUGO | S_IWUSR, + bonding_show_xmit_hash, bonding_store_xmit_hash); /* * Show and set arp_validate. @@ -489,39 +467,41 @@ static ssize_t bonding_store_arp_validate(struct device *d, new_value = bond_parse_parm(buf, arp_validate_tbl); if (new_value < 0) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Ignoring invalid arp_validate value %s\n", bond->dev->name, buf); return -EINVAL; } if (new_value && (bond->params.mode != BOND_MODE_ACTIVEBACKUP)) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: arp_validate only supported in active-backup mode.\n", bond->dev->name); return -EINVAL; } - printk(KERN_INFO DRV_NAME ": %s: setting arp_validate to %s (%d).\n", + pr_info(DRV_NAME ": %s: setting arp_validate to %s (%d).\n", bond->dev->name, arp_validate_tbl[new_value].modename, new_value); - if (!bond->params.arp_validate && new_value) { + if (!bond->params.arp_validate && new_value) bond_register_arp(bond); - } else if (bond->params.arp_validate && !new_value) { + else if (bond->params.arp_validate && !new_value) bond_unregister_arp(bond); - } bond->params.arp_validate = new_value; return count; } -static DEVICE_ATTR(arp_validate, S_IRUGO | S_IWUSR, bonding_show_arp_validate, bonding_store_arp_validate); +static DEVICE_ATTR(arp_validate, S_IRUGO | S_IWUSR, bonding_show_arp_validate, + bonding_store_arp_validate); /* * Show and store fail_over_mac. User only allowed to change the * value when there are no slaves. */ -static ssize_t bonding_show_fail_over_mac(struct device *d, struct device_attribute *attr, char *buf) +static ssize_t bonding_show_fail_over_mac(struct device *d, + struct device_attribute *attr, + char *buf) { struct bonding *bond = to_bond(d); @@ -530,13 +510,15 @@ static ssize_t bonding_show_fail_over_mac(struct device *d, struct device_attrib bond->params.fail_over_mac); } -static ssize_t bonding_store_fail_over_mac(struct device *d, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t bonding_store_fail_over_mac(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) { int new_value; struct bonding *bond = to_bond(d); if (bond->slave_cnt != 0) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Can't alter fail_over_mac with slaves in bond.\n", bond->dev->name); return -EPERM; @@ -544,21 +526,22 @@ static ssize_t bonding_store_fail_over_mac(struct device *d, struct device_attri new_value = bond_parse_parm(buf, fail_over_mac_tbl); if (new_value < 0) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Ignoring invalid fail_over_mac value %s.\n", bond->dev->name, buf); return -EINVAL; } bond->params.fail_over_mac = new_value; - printk(KERN_INFO DRV_NAME ": %s: Setting fail_over_mac to %s (%d).\n", + pr_info(DRV_NAME ": %s: Setting fail_over_mac to %s (%d).\n", bond->dev->name, fail_over_mac_tbl[new_value].modename, new_value); return count; } -static DEVICE_ATTR(fail_over_mac, S_IRUGO | S_IWUSR, bonding_show_fail_over_mac, bonding_store_fail_over_mac); +static DEVICE_ATTR(fail_over_mac, S_IRUGO | S_IWUSR, + bonding_show_fail_over_mac, bonding_store_fail_over_mac); /* * Show and set the arp timer interval. There are two tricky bits @@ -583,28 +566,28 @@ static ssize_t bonding_store_arp_interval(struct device *d, struct bonding *bond = to_bond(d); if (sscanf(buf, "%d", &new_value) != 1) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: no arp_interval value specified.\n", bond->dev->name); ret = -EINVAL; goto out; } if (new_value < 0) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Invalid arp_interval value %d not in range 1-%d; rejected.\n", bond->dev->name, new_value, INT_MAX); ret = -EINVAL; goto out; } - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: Setting ARP monitoring interval to %d.\n", bond->dev->name, new_value); bond->params.arp_interval = new_value; if (bond->params.arp_interval) bond->dev->priv_flags |= IFF_MASTER_ARPMON; if (bond->params.miimon) { - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: ARP monitoring cannot be used with MII monitoring. " "%s Disabling MII monitoring.\n", bond->dev->name, bond->dev->name); @@ -615,7 +598,7 @@ static ssize_t bonding_store_arp_interval(struct device *d, } } if (!bond->params.arp_targets[0]) { - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: ARP monitoring has been set up, " "but no ARP targets have been specified.\n", bond->dev->name); @@ -641,7 +624,8 @@ static ssize_t bonding_store_arp_interval(struct device *d, out: return ret; } -static DEVICE_ATTR(arp_interval, S_IRUGO | S_IWUSR , bonding_show_arp_interval, bonding_store_arp_interval); +static DEVICE_ATTR(arp_interval, S_IRUGO | S_IWUSR, + bonding_show_arp_interval, bonding_store_arp_interval); /* * Show and set the arp targets. @@ -677,7 +661,7 @@ static ssize_t bonding_store_arp_targets(struct device *d, /* look for adds */ if (buf[0] == '+') { if ((newtarget == 0) || (newtarget == htonl(INADDR_BROADCAST))) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: invalid ARP target %pI4 specified for addition\n", bond->dev->name, &newtarget); ret = -EINVAL; @@ -686,14 +670,14 @@ static ssize_t bonding_store_arp_targets(struct device *d, /* look for an empty slot to put the target in, and check for dupes */ for (i = 0; (i < BOND_MAX_ARP_TARGETS) && !done; i++) { if (targets[i] == newtarget) { /* duplicate */ - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: ARP target %pI4 is already present\n", bond->dev->name, &newtarget); ret = -EINVAL; goto out; } if (targets[i] == 0) { - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: adding ARP target %pI4.\n", bond->dev->name, &newtarget); done = 1; @@ -701,17 +685,16 @@ static ssize_t bonding_store_arp_targets(struct device *d, } } if (!done) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: ARP target table is full!\n", bond->dev->name); ret = -EINVAL; goto out; } - } - else if (buf[0] == '-') { + } else if (buf[0] == '-') { if ((newtarget == 0) || (newtarget == htonl(INADDR_BROADCAST))) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: invalid ARP target %pI4 specified for removal\n", bond->dev->name, &newtarget); ret = -EINVAL; @@ -721,7 +704,7 @@ static ssize_t bonding_store_arp_targets(struct device *d, for (i = 0; (i < BOND_MAX_ARP_TARGETS) && !done; i++) { if (targets[i] == newtarget) { int j; - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: removing ARP target %pI4.\n", bond->dev->name, &newtarget); for (j = i; (j < (BOND_MAX_ARP_TARGETS-1)) && targets[j+1]; j++) @@ -732,15 +715,15 @@ static ssize_t bonding_store_arp_targets(struct device *d, } } if (!done) { - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: unable to remove nonexistent ARP target %pI4.\n", bond->dev->name, &newtarget); ret = -EINVAL; goto out; } - } - else { - printk(KERN_ERR DRV_NAME ": no command found in arp_ip_targets file for bond %s. Use + or -.\n", + } else { + pr_err(DRV_NAME ": no command found in arp_ip_targets file" + " for bond %s. Use + or -.\n", bond->dev->name); ret = -EPERM; goto out; @@ -773,7 +756,7 @@ static ssize_t bonding_store_downdelay(struct device *d, struct bonding *bond = to_bond(d); if (!(bond->params.miimon)) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Unable to set down delay as MII monitoring is disabled\n", bond->dev->name); ret = -EPERM; @@ -781,14 +764,14 @@ static ssize_t bonding_store_downdelay(struct device *d, } if (sscanf(buf, "%d", &new_value) != 1) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: no down delay value specified.\n", bond->dev->name); ret = -EINVAL; goto out; } if (new_value < 0) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Invalid down delay value %d not in range %d-%d; rejected.\n", bond->dev->name, new_value, 1, INT_MAX); ret = -EINVAL; @@ -803,15 +786,17 @@ static ssize_t bonding_store_downdelay(struct device *d, bond->params.miimon); } bond->params.downdelay = new_value / bond->params.miimon; - printk(KERN_INFO DRV_NAME ": %s: Setting down delay to %d.\n", - bond->dev->name, bond->params.downdelay * bond->params.miimon); + pr_info(DRV_NAME ": %s: Setting down delay to %d.\n", + bond->dev->name, + bond->params.downdelay * bond->params.miimon); } out: return ret; } -static DEVICE_ATTR(downdelay, S_IRUGO | S_IWUSR , bonding_show_downdelay, bonding_store_downdelay); +static DEVICE_ATTR(downdelay, S_IRUGO | S_IWUSR, + bonding_show_downdelay, bonding_store_downdelay); static ssize_t bonding_show_updelay(struct device *d, struct device_attribute *attr, @@ -831,7 +816,7 @@ static ssize_t bonding_store_updelay(struct device *d, struct bonding *bond = to_bond(d); if (!(bond->params.miimon)) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Unable to set up delay as MII monitoring is disabled\n", bond->dev->name); ret = -EPERM; @@ -839,14 +824,14 @@ static ssize_t bonding_store_updelay(struct device *d, } if (sscanf(buf, "%d", &new_value) != 1) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: no up delay value specified.\n", bond->dev->name); ret = -EINVAL; goto out; } if (new_value < 0) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Invalid down delay value %d not in range %d-%d; rejected.\n", bond->dev->name, new_value, 1, INT_MAX); ret = -EINVAL; @@ -861,7 +846,7 @@ static ssize_t bonding_store_updelay(struct device *d, bond->params.miimon); } bond->params.updelay = new_value / bond->params.miimon; - printk(KERN_INFO DRV_NAME ": %s: Setting up delay to %d.\n", + pr_info(DRV_NAME ": %s: Setting up delay to %d.\n", bond->dev->name, bond->params.updelay * bond->params.miimon); } @@ -869,7 +854,8 @@ static ssize_t bonding_store_updelay(struct device *d, out: return ret; } -static DEVICE_ATTR(updelay, S_IRUGO | S_IWUSR , bonding_show_updelay, bonding_store_updelay); +static DEVICE_ATTR(updelay, S_IRUGO | S_IWUSR, + bonding_show_updelay, bonding_store_updelay); /* * Show and set the LACP interval. Interface must be down, and the mode @@ -894,7 +880,7 @@ static ssize_t bonding_store_lacp(struct device *d, struct bonding *bond = to_bond(d); if (bond->dev->flags & IFF_UP) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Unable to update LACP rate because interface is up.\n", bond->dev->name); ret = -EPERM; @@ -902,7 +888,7 @@ static ssize_t bonding_store_lacp(struct device *d, } if (bond->params.mode != BOND_MODE_8023AD) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Unable to update LACP rate because bond is not in 802.3ad mode.\n", bond->dev->name); ret = -EPERM; @@ -913,19 +899,20 @@ static ssize_t bonding_store_lacp(struct device *d, if ((new_value == 1) || (new_value == 0)) { bond->params.lacp_fast = new_value; - printk(KERN_INFO DRV_NAME - ": %s: Setting LACP rate to %s (%d).\n", - bond->dev->name, bond_lacp_tbl[new_value].modename, new_value); + pr_info(DRV_NAME ": %s: Setting LACP rate to %s (%d).\n", + bond->dev->name, bond_lacp_tbl[new_value].modename, + new_value); } else { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Ignoring invalid LACP rate value %.*s.\n", - bond->dev->name, (int)strlen(buf) - 1, buf); + bond->dev->name, (int)strlen(buf) - 1, buf); ret = -EINVAL; } out: return ret; } -static DEVICE_ATTR(lacp_rate, S_IRUGO | S_IWUSR, bonding_show_lacp, bonding_store_lacp); +static DEVICE_ATTR(lacp_rate, S_IRUGO | S_IWUSR, + bonding_show_lacp, bonding_store_lacp); static ssize_t bonding_show_ad_select(struct device *d, struct device_attribute *attr, @@ -947,7 +934,7 @@ static ssize_t bonding_store_ad_select(struct device *d, struct bonding *bond = to_bond(d); if (bond->dev->flags & IFF_UP) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Unable to update ad_select because interface " "is up.\n", bond->dev->name); ret = -EPERM; @@ -958,12 +945,12 @@ static ssize_t bonding_store_ad_select(struct device *d, if (new_value != -1) { bond->params.ad_select = new_value; - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: Setting ad_select to %s (%d).\n", bond->dev->name, ad_select_tbl[new_value].modename, new_value); } else { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Ignoring invalid ad_select value %.*s.\n", bond->dev->name, (int)strlen(buf) - 1, buf); ret = -EINVAL; @@ -971,8 +958,8 @@ static ssize_t bonding_store_ad_select(struct device *d, out: return ret; } - -static DEVICE_ATTR(ad_select, S_IRUGO | S_IWUSR, bonding_show_ad_select, bonding_store_ad_select); +static DEVICE_ATTR(ad_select, S_IRUGO | S_IWUSR, + bonding_show_ad_select, bonding_store_ad_select); /* * Show and set the number of grat ARP to send after a failover event. @@ -994,14 +981,14 @@ static ssize_t bonding_store_n_grat_arp(struct device *d, struct bonding *bond = to_bond(d); if (sscanf(buf, "%d", &new_value) != 1) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: no num_grat_arp value specified.\n", bond->dev->name); ret = -EINVAL; goto out; } if (new_value < 0 || new_value > 255) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Invalid num_grat_arp value %d not in range 0-255; rejected.\n", bond->dev->name, new_value); ret = -EINVAL; @@ -1012,10 +999,11 @@ static ssize_t bonding_store_n_grat_arp(struct device *d, out: return ret; } -static DEVICE_ATTR(num_grat_arp, S_IRUGO | S_IWUSR, bonding_show_n_grat_arp, bonding_store_n_grat_arp); +static DEVICE_ATTR(num_grat_arp, S_IRUGO | S_IWUSR, + bonding_show_n_grat_arp, bonding_store_n_grat_arp); /* - * Show and set the number of unsolicted NA's to send after a failover event. + * Show and set the number of unsolicited NA's to send after a failover event. */ static ssize_t bonding_show_n_unsol_na(struct device *d, struct device_attribute *attr, @@ -1034,25 +1022,26 @@ static ssize_t bonding_store_n_unsol_na(struct device *d, struct bonding *bond = to_bond(d); if (sscanf(buf, "%d", &new_value) != 1) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: no num_unsol_na value specified.\n", bond->dev->name); ret = -EINVAL; goto out; } + if (new_value < 0 || new_value > 255) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Invalid num_unsol_na value %d not in range 0-255; rejected.\n", bond->dev->name, new_value); ret = -EINVAL; goto out; - } else { + } else bond->params.num_unsol_na = new_value; - } out: return ret; } -static DEVICE_ATTR(num_unsol_na, S_IRUGO | S_IWUSR, bonding_show_n_unsol_na, bonding_store_n_unsol_na); +static DEVICE_ATTR(num_unsol_na, S_IRUGO | S_IWUSR, + bonding_show_n_unsol_na, bonding_store_n_unsol_na); /* * Show and set the MII monitor interval. There are two tricky bits @@ -1077,37 +1066,37 @@ static ssize_t bonding_store_miimon(struct device *d, struct bonding *bond = to_bond(d); if (sscanf(buf, "%d", &new_value) != 1) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: no miimon value specified.\n", bond->dev->name); ret = -EINVAL; goto out; } if (new_value < 0) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: Invalid miimon value %d not in range %d-%d; rejected.\n", bond->dev->name, new_value, 1, INT_MAX); ret = -EINVAL; goto out; } else { - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: Setting MII monitoring interval to %d.\n", bond->dev->name, new_value); bond->params.miimon = new_value; - if(bond->params.updelay) - printk(KERN_INFO DRV_NAME + if (bond->params.updelay) + pr_info(DRV_NAME ": %s: Note: Updating updelay (to %d) " "since it is a multiple of the miimon value.\n", bond->dev->name, bond->params.updelay * bond->params.miimon); - if(bond->params.downdelay) - printk(KERN_INFO DRV_NAME + if (bond->params.downdelay) + pr_info(DRV_NAME ": %s: Note: Updating downdelay (to %d) " "since it is a multiple of the miimon value.\n", bond->dev->name, bond->params.downdelay * bond->params.miimon); if (bond->params.arp_interval) { - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: MII monitoring cannot be used with " "ARP monitoring. Disabling ARP monitoring...\n", bond->dev->name); @@ -1141,7 +1130,8 @@ static ssize_t bonding_store_miimon(struct device *d, out: return ret; } -static DEVICE_ATTR(miimon, S_IRUGO | S_IWUSR, bonding_show_miimon, bonding_store_miimon); +static DEVICE_ATTR(miimon, S_IRUGO | S_IWUSR, + bonding_show_miimon, bonding_store_miimon); /* * Show and set the primary slave. The store function is much @@ -1171,12 +1161,13 @@ static ssize_t bonding_store_primary(struct device *d, struct slave *slave; struct bonding *bond = to_bond(d); - rtnl_lock(); + if (!rtnl_trylock()) + return restart_syscall(); read_lock(&bond->lock); write_lock_bh(&bond->curr_slave_lock); if (!USES_PRIMARY(bond->params.mode)) { - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: Unable to set primary slave; %s is in mode %d\n", bond->dev->name, bond->dev->name, bond->params.mode); } else { @@ -1184,7 +1175,7 @@ static ssize_t bonding_store_primary(struct device *d, if (strnicmp (slave->dev->name, buf, strlen(slave->dev->name)) == 0) { - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: Setting %s as primary slave.\n", bond->dev->name, slave->dev->name); bond->primary_slave = slave; @@ -1196,13 +1187,13 @@ static ssize_t bonding_store_primary(struct device *d, /* if we got here, then we didn't match the name of any slave */ if (strlen(buf) == 0 || buf[0] == '\n') { - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: Setting primary slave to None.\n", bond->dev->name); bond->primary_slave = NULL; bond_select_active_slave(bond); } else { - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: Unable to set %.*s as primary slave as it is not a slave.\n", bond->dev->name, (int)strlen(buf) - 1, buf); } @@ -1214,7 +1205,8 @@ out: return count; } -static DEVICE_ATTR(primary, S_IRUGO | S_IWUSR, bonding_show_primary, bonding_store_primary); +static DEVICE_ATTR(primary, S_IRUGO | S_IWUSR, + bonding_show_primary, bonding_store_primary); /* * Show and set the use_carrier flag. @@ -1237,7 +1229,7 @@ static ssize_t bonding_store_carrier(struct device *d, if (sscanf(buf, "%d", &new_value) != 1) { - printk(KERN_ERR DRV_NAME + pr_err(DRV_NAME ": %s: no use_carrier value specified.\n", bond->dev->name); ret = -EINVAL; @@ -1245,17 +1237,18 @@ static ssize_t bonding_store_carrier(struct device *d, } if ((new_value == 0) || (new_value == 1)) { bond->params.use_carrier = new_value; - printk(KERN_INFO DRV_NAME ": %s: Setting use_carrier to %d.\n", + pr_info(DRV_NAME ": %s: Setting use_carrier to %d.\n", bond->dev->name, new_value); } else { - printk(KERN_INFO DRV_NAME + pr_info(DRV_NAME ": %s: Ignoring invalid use_carrier value %d.\n", bond->dev->name, new_value); } out: return count; } -static DEVICE_ATTR(use_carrier, S_IRUGO | S_IWUSR, bonding_show_carrier, bonding_store_carrier); +static DEVICE_ATTR(use_carrier, S_IRUGO | S_IWUSR, + bonding_show_carrier, bonding_store_carrier); /* @@ -1284,19 +1277,20 @@ static ssize_t bonding_store_active_slave(struct device *d, { int i; struct slave *slave; - struct slave *old_active = NULL; - struct slave *new_active = NULL; + struct slave *old_active = NULL; + struct slave *new_active = NULL; struct bonding *bond = to_bond(d); - rtnl_lock(); + if (!rtnl_trylock()) + return restart_syscall(); read_lock(&bond->lock); write_lock_bh(&bond->curr_slave_lock); - if (!USES_PRIMARY(bond->params.mode)) { - printk(KERN_INFO DRV_NAME - ": %s: Unable to change active slave; %s is in mode %d\n", - bond->dev->name, bond->dev->name, bond->params.mode); - } else { + if (!USES_PRIMARY(bond->params.mode)) + pr_info(DRV_NAME ": %s: Unable to change active slave;" + " %s is in mode %d\n", + bond->dev->name, bond->dev->name, bond->params.mode); + else { bond_for_each_slave(bond, slave, i) { if (strnicmp (slave->dev->name, buf, @@ -1335,18 +1329,18 @@ static ssize_t bonding_store_active_slave(struct device *d, /* if we got here, then we didn't match the name of any slave */ if (strlen(buf) == 0 || buf[0] == '\n') { - printk(KERN_INFO DRV_NAME - ": %s: Setting active slave to None.\n", - bond->dev->name); + pr_info(DRV_NAME + ": %s: Setting active slave to None.\n", + bond->dev->name); bond->primary_slave = NULL; - bond_select_active_slave(bond); + bond_select_active_slave(bond); } else { - printk(KERN_INFO DRV_NAME - ": %s: Unable to set %.*s as active slave as it is not a slave.\n", - bond->dev->name, (int)strlen(buf) - 1, buf); + pr_info(DRV_NAME ": %s: Unable to set %.*s" + " as active slave as it is not a slave.\n", + bond->dev->name, (int)strlen(buf) - 1, buf); } } -out: + out: write_unlock_bh(&bond->curr_slave_lock); read_unlock(&bond->lock); rtnl_unlock(); @@ -1354,7 +1348,8 @@ out: return count; } -static DEVICE_ATTR(active_slave, S_IRUGO | S_IWUSR, bonding_show_active_slave, bonding_store_active_slave); +static DEVICE_ATTR(active_slave, S_IRUGO | S_IWUSR, + bonding_show_active_slave, bonding_store_active_slave); /* @@ -1371,7 +1366,7 @@ static ssize_t bonding_show_mii_status(struct device *d, curr = bond->curr_active_slave; read_unlock(&bond->curr_slave_lock); - return sprintf(buf, "%s\n", (curr) ? "up" : "down"); + return sprintf(buf, "%s\n", curr ? "up" : "down"); } static DEVICE_ATTR(mii_status, S_IRUGO, bonding_show_mii_status, NULL); @@ -1388,7 +1383,9 @@ static ssize_t bonding_show_ad_aggregator(struct device *d, if (bond->params.mode == BOND_MODE_8023AD) { struct ad_info ad_info; - count = sprintf(buf, "%d\n", (bond_3ad_get_active_agg_info(bond, &ad_info)) ? 0 : ad_info.aggregator_id); + count = sprintf(buf, "%d\n", + (bond_3ad_get_active_agg_info(bond, &ad_info)) + ? 0 : ad_info.aggregator_id); } return count; @@ -1408,7 +1405,9 @@ static ssize_t bonding_show_ad_num_ports(struct device *d, if (bond->params.mode == BOND_MODE_8023AD) { struct ad_info ad_info; - count = sprintf(buf, "%d\n", (bond_3ad_get_active_agg_info(bond, &ad_info)) ? 0: ad_info.ports); + count = sprintf(buf, "%d\n", + (bond_3ad_get_active_agg_info(bond, &ad_info)) + ? 0 : ad_info.ports); } return count; @@ -1428,7 +1427,9 @@ static ssize_t bonding_show_ad_actor_key(struct device *d, if (bond->params.mode == BOND_MODE_8023AD) { struct ad_info ad_info; - count = sprintf(buf, "%d\n", (bond_3ad_get_active_agg_info(bond, &ad_info)) ? 0 : ad_info.actor_key); + count = sprintf(buf, "%d\n", + (bond_3ad_get_active_agg_info(bond, &ad_info)) + ? 0 : ad_info.actor_key); } return count; @@ -1448,7 +1449,9 @@ static ssize_t bonding_show_ad_partner_key(struct device *d, if (bond->params.mode == BOND_MODE_8023AD) { struct ad_info ad_info; - count = sprintf(buf, "%d\n", (bond_3ad_get_active_agg_info(bond, &ad_info)) ? 0 : ad_info.partner_key); + count = sprintf(buf, "%d\n", + (bond_3ad_get_active_agg_info(bond, &ad_info)) + ? 0 : ad_info.partner_key); } return count; @@ -1468,9 +1471,8 @@ static ssize_t bonding_show_ad_partner_mac(struct device *d, if (bond->params.mode == BOND_MODE_8023AD) { struct ad_info ad_info; - if (!bond_3ad_get_active_agg_info(bond, &ad_info)) { + if (!bond_3ad_get_active_agg_info(bond, &ad_info)) count = sprintf(buf, "%pM\n", ad_info.partner_system); - } } return count; @@ -1538,6 +1540,7 @@ int bond_create_sysfs(void) printk(KERN_ERR "network device named %s already exists in sysfs", class_attr_bonding_masters.attr.name); + ret = 0; } return ret; @@ -1562,12 +1565,8 @@ int bond_create_sysfs_entry(struct bonding *bond) int err; err = sysfs_create_group(&(dev->dev.kobj), &bonding_group); - if (err) { + if (err) printk(KERN_EMERG "eek! didn't create group!\n"); - } - - if (expected_refcount < 1) - expected_refcount = atomic_read(&bond->dev->dev.kobj.kref.refcount); return err; } diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index ca849d2adf98..6290a502742e 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -286,8 +286,7 @@ static inline unsigned long slave_last_rx(struct bonding *bond, static inline void bond_set_slave_inactive_flags(struct slave *slave) { struct bonding *bond = netdev_priv(slave->dev->master); - if (bond->params.mode != BOND_MODE_TLB && - bond->params.mode != BOND_MODE_ALB) + if (!bond_is_lb(bond)) slave->state = BOND_STATE_BACKUP; slave->dev->priv_flags |= IFF_SLAVE_INACTIVE; if (slave_do_arp_validate(bond, slave)) @@ -322,8 +321,7 @@ static inline void bond_unset_master_alb_flags(struct bonding *bond) struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr); int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_device *slave_dev); -int bond_create(char *name, struct bond_params *params); -void bond_destroy(struct bonding *bond); +int bond_create(const char *name); int bond_release_and_destroy(struct net_device *bond_dev, struct net_device *slave_dev); int bond_create_sysfs(void); void bond_destroy_sysfs(void); @@ -350,12 +348,8 @@ extern const struct bond_parm_tbl bond_mode_tbl[]; extern const struct bond_parm_tbl xmit_hashtype_tbl[]; extern const struct bond_parm_tbl arp_validate_tbl[]; extern const struct bond_parm_tbl fail_over_mac_tbl[]; -extern struct bond_params bonding_defaults; extern struct bond_parm_tbl ad_select_tbl[]; -/* exported from bond_sysfs.c */ -extern struct rw_semaphore bonding_rwsem; - #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) void bond_send_unsolicited_na(struct bonding *bond); void bond_register_ipv6_notifier(void); diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig index 57def0d57371..33821a81cbf8 100644 --- a/drivers/net/can/Kconfig +++ b/drivers/net/can/Kconfig @@ -12,6 +12,68 @@ config CAN_VCAN This driver can also be built as a module. If so, the module will be called vcan. +config CAN_DEV + tristate "Platform CAN drivers with Netlink support" + depends on CAN + default Y + ---help--- + Enables the common framework for platform CAN drivers with Netlink + support. This is the standard library for CAN drivers. + If unsure, say Y. + +config CAN_CALC_BITTIMING + bool "CAN bit-timing calculation" + depends on CAN_DEV + default Y + ---help--- + If enabled, CAN bit-timing parameters will be calculated for the + bit-rate specified via Netlink argument "bitrate" when the device + get started. This works fine for the most common CAN controllers + with standard bit-rates but may fail for exotic bit-rates or CAN + source clock frequencies. Disabling saves some space, but then the + bit-timing parameters must be specified directly using the Netlink + arguments "tq", "prop_seg", "phase_seg1", "phase_seg2" and "sjw". + If unsure, say Y. + +config CAN_SJA1000 + depends on CAN_DEV && HAS_IOMEM + tristate "Philips SJA1000" + ---help--- + Driver for the SJA1000 CAN controllers from Philips or NXP + +config CAN_SJA1000_PLATFORM + depends on CAN_SJA1000 + tristate "Generic Platform Bus based SJA1000 driver" + ---help--- + This driver adds support for the SJA1000 chips connected to + the "platform bus" (Linux abstraction for directly to the + processor attached devices). Which can be found on various + boards from Phytec (http://www.phytec.de) like the PCM027, + PCM038. + +config CAN_SJA1000_OF_PLATFORM + depends on CAN_SJA1000 && PPC_OF + tristate "Generic OF Platform Bus based SJA1000 driver" + ---help--- + This driver adds support for the SJA1000 chips connected to + the OpenFirmware "platform bus" found on embedded systems with + OpenFirmware bindings, e.g. if you have a PowerPC based system + you may want to enable this option. + +config CAN_EMS_PCI + tristate "EMS CPC-PCI and CPC-PCIe Card" + depends on PCI && CAN_SJA1000 + ---help--- + This driver is for the one or two channel CPC-PCI and CPC-PCIe + cards from EMS Dr. Thomas Wuensche (http://www.ems-wuensche.de). + +config CAN_KVASER_PCI + tristate "Kvaser PCIcanx and Kvaser PCIcan PCI Cards" + depends on PCI && CAN_SJA1000 + ---help--- + This driver is for the the PCIcanx and PCIcan cards (1, 2 or + 4 channel) from Kvaser (http://www.kvaser.com). + config CAN_DEBUG_DEVICES bool "CAN devices debugging messages" depends on CAN diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile index c4bead705cd9..523a941b358b 100644 --- a/drivers/net/can/Makefile +++ b/drivers/net/can/Makefile @@ -3,3 +3,10 @@ # obj-$(CONFIG_CAN_VCAN) += vcan.o + +obj-$(CONFIG_CAN_DEV) += can-dev.o +can-dev-y := dev.o + +obj-$(CONFIG_CAN_SJA1000) += sja1000/ + +ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c new file mode 100644 index 000000000000..574daddc21bf --- /dev/null +++ b/drivers/net/can/dev.c @@ -0,0 +1,657 @@ +/* + * Copyright (C) 2005 Marc Kleine-Budde, Pengutronix + * Copyright (C) 2006 Andrey Volkov, Varma Electronics + * Copyright (C) 2008-2009 Wolfgang Grandegger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the version 2 of the GNU General Public License + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define MOD_DESC "CAN device driver interface" + +MODULE_DESCRIPTION(MOD_DESC); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Wolfgang Grandegger "); + +#ifdef CONFIG_CAN_CALC_BITTIMING +#define CAN_CALC_MAX_ERROR 50 /* in one-tenth of a percent */ + +/* + * Bit-timing calculation derived from: + * + * Code based on LinCAN sources and H8S2638 project + * Copyright 2004-2006 Pavel Pisa - DCE FELK CVUT cz + * Copyright 2005 Stanislav Marek + * email: pisa@cmp.felk.cvut.cz + * + * Calculates proper bit-timing parameters for a specified bit-rate + * and sample-point, which can then be used to set the bit-timing + * registers of the CAN controller. You can find more information + * in the header file linux/can/netlink.h. + */ +static int can_update_spt(const struct can_bittiming_const *btc, + int sampl_pt, int tseg, int *tseg1, int *tseg2) +{ + *tseg2 = tseg + 1 - (sampl_pt * (tseg + 1)) / 1000; + if (*tseg2 < btc->tseg2_min) + *tseg2 = btc->tseg2_min; + if (*tseg2 > btc->tseg2_max) + *tseg2 = btc->tseg2_max; + *tseg1 = tseg - *tseg2; + if (*tseg1 > btc->tseg1_max) { + *tseg1 = btc->tseg1_max; + *tseg2 = tseg - *tseg1; + } + return 1000 * (tseg + 1 - *tseg2) / (tseg + 1); +} + +static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt) +{ + struct can_priv *priv = netdev_priv(dev); + const struct can_bittiming_const *btc = priv->bittiming_const; + long rate, best_rate = 0; + long best_error = 1000000000, error = 0; + int best_tseg = 0, best_brp = 0, brp = 0; + int tsegall, tseg = 0, tseg1 = 0, tseg2 = 0; + int spt_error = 1000, spt = 0, sampl_pt; + u64 v64; + + if (!priv->bittiming_const) + return -ENOTSUPP; + + /* Use CIA recommended sample points */ + if (bt->sample_point) { + sampl_pt = bt->sample_point; + } else { + if (bt->bitrate > 800000) + sampl_pt = 750; + else if (bt->bitrate > 500000) + sampl_pt = 800; + else + sampl_pt = 875; + } + + /* tseg even = round down, odd = round up */ + for (tseg = (btc->tseg1_max + btc->tseg2_max) * 2 + 1; + tseg >= (btc->tseg1_min + btc->tseg2_min) * 2; tseg--) { + tsegall = 1 + tseg / 2; + /* Compute all possible tseg choices (tseg=tseg1+tseg2) */ + brp = priv->clock.freq / (tsegall * bt->bitrate) + tseg % 2; + /* chose brp step which is possible in system */ + brp = (brp / btc->brp_inc) * btc->brp_inc; + if ((brp < btc->brp_min) || (brp > btc->brp_max)) + continue; + rate = priv->clock.freq / (brp * tsegall); + error = bt->bitrate - rate; + /* tseg brp biterror */ + if (error < 0) + error = -error; + if (error > best_error) + continue; + best_error = error; + if (error == 0) { + spt = can_update_spt(btc, sampl_pt, tseg / 2, + &tseg1, &tseg2); + error = sampl_pt - spt; + if (error < 0) + error = -error; + if (error > spt_error) + continue; + spt_error = error; + } + best_tseg = tseg / 2; + best_brp = brp; + best_rate = rate; + if (error == 0) + break; + } + + if (best_error) { + /* Error in one-tenth of a percent */ + error = (best_error * 1000) / bt->bitrate; + if (error > CAN_CALC_MAX_ERROR) { + dev_err(dev->dev.parent, + "bitrate error %ld.%ld%% too high\n", + error / 10, error % 10); + return -EDOM; + } else { + dev_warn(dev->dev.parent, "bitrate error %ld.%ld%%\n", + error / 10, error % 10); + } + } + + /* real sample point */ + bt->sample_point = can_update_spt(btc, sampl_pt, best_tseg, + &tseg1, &tseg2); + + v64 = (u64)best_brp * 1000000000UL; + do_div(v64, priv->clock.freq); + bt->tq = (u32)v64; + bt->prop_seg = tseg1 / 2; + bt->phase_seg1 = tseg1 - bt->prop_seg; + bt->phase_seg2 = tseg2; + bt->sjw = 1; + bt->brp = best_brp; + /* real bit-rate */ + bt->bitrate = priv->clock.freq / (bt->brp * (tseg1 + tseg2 + 1)); + + return 0; +} +#else /* !CONFIG_CAN_CALC_BITTIMING */ +static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt) +{ + dev_err(dev->dev.parent, "bit-timing calculation not available\n"); + return -EINVAL; +} +#endif /* CONFIG_CAN_CALC_BITTIMING */ + +/* + * Checks the validity of the specified bit-timing parameters prop_seg, + * phase_seg1, phase_seg2 and sjw and tries to determine the bitrate + * prescaler value brp. You can find more information in the header + * file linux/can/netlink.h. + */ +static int can_fixup_bittiming(struct net_device *dev, struct can_bittiming *bt) +{ + struct can_priv *priv = netdev_priv(dev); + const struct can_bittiming_const *btc = priv->bittiming_const; + int tseg1, alltseg; + u64 brp64; + + if (!priv->bittiming_const) + return -ENOTSUPP; + + tseg1 = bt->prop_seg + bt->phase_seg1; + if (!bt->sjw) + bt->sjw = 1; + if (bt->sjw > btc->sjw_max || + tseg1 < btc->tseg1_min || tseg1 > btc->tseg1_max || + bt->phase_seg2 < btc->tseg2_min || bt->phase_seg2 > btc->tseg2_max) + return -ERANGE; + + brp64 = (u64)priv->clock.freq * (u64)bt->tq; + if (btc->brp_inc > 1) + do_div(brp64, btc->brp_inc); + brp64 += 500000000UL - 1; + do_div(brp64, 1000000000UL); /* the practicable BRP */ + if (btc->brp_inc > 1) + brp64 *= btc->brp_inc; + bt->brp = (u32)brp64; + + if (bt->brp < btc->brp_min || bt->brp > btc->brp_max) + return -EINVAL; + + alltseg = bt->prop_seg + bt->phase_seg1 + bt->phase_seg2 + 1; + bt->bitrate = priv->clock.freq / (bt->brp * alltseg); + bt->sample_point = ((tseg1 + 1) * 1000) / alltseg; + + return 0; +} + +int can_get_bittiming(struct net_device *dev, struct can_bittiming *bt) +{ + struct can_priv *priv = netdev_priv(dev); + int err; + + /* Check if the CAN device has bit-timing parameters */ + if (priv->bittiming_const) { + + /* Non-expert mode? Check if the bitrate has been pre-defined */ + if (!bt->tq) + /* Determine bit-timing parameters */ + err = can_calc_bittiming(dev, bt); + else + /* Check bit-timing params and calculate proper brp */ + err = can_fixup_bittiming(dev, bt); + if (err) + return err; + } + + return 0; +} + +/* + * Local echo of CAN messages + * + * CAN network devices *should* support a local echo functionality + * (see Documentation/networking/can.txt). To test the handling of CAN + * interfaces that do not support the local echo both driver types are + * implemented. In the case that the driver does not support the echo + * the IFF_ECHO remains clear in dev->flags. This causes the PF_CAN core + * to perform the echo as a fallback solution. + */ +static void can_flush_echo_skb(struct net_device *dev) +{ + struct can_priv *priv = netdev_priv(dev); + struct net_device_stats *stats = &dev->stats; + int i; + + for (i = 0; i < CAN_ECHO_SKB_MAX; i++) { + if (priv->echo_skb[i]) { + kfree_skb(priv->echo_skb[i]); + priv->echo_skb[i] = NULL; + stats->tx_dropped++; + stats->tx_aborted_errors++; + } + } +} + +/* + * Put the skb on the stack to be looped backed locally lateron + * + * The function is typically called in the start_xmit function + * of the device driver. The driver must protect access to + * priv->echo_skb, if necessary. + */ +void can_put_echo_skb(struct sk_buff *skb, struct net_device *dev, int idx) +{ + struct can_priv *priv = netdev_priv(dev); + + /* check flag whether this packet has to be looped back */ + if (!(dev->flags & IFF_ECHO) || skb->pkt_type != PACKET_LOOPBACK) { + kfree_skb(skb); + return; + } + + if (!priv->echo_skb[idx]) { + struct sock *srcsk = skb->sk; + + if (atomic_read(&skb->users) != 1) { + struct sk_buff *old_skb = skb; + + skb = skb_clone(old_skb, GFP_ATOMIC); + kfree_skb(old_skb); + if (!skb) + return; + } else + skb_orphan(skb); + + skb->sk = srcsk; + + /* make settings for echo to reduce code in irq context */ + skb->protocol = htons(ETH_P_CAN); + skb->pkt_type = PACKET_BROADCAST; + skb->ip_summed = CHECKSUM_UNNECESSARY; + skb->dev = dev; + + /* save this skb for tx interrupt echo handling */ + priv->echo_skb[idx] = skb; + } else { + /* locking problem with netif_stop_queue() ?? */ + dev_err(dev->dev.parent, "%s: BUG! echo_skb is occupied!\n", + __func__); + kfree_skb(skb); + } +} +EXPORT_SYMBOL_GPL(can_put_echo_skb); + +/* + * Get the skb from the stack and loop it back locally + * + * The function is typically called when the TX done interrupt + * is handled in the device driver. The driver must protect + * access to priv->echo_skb, if necessary. + */ +void can_get_echo_skb(struct net_device *dev, int idx) +{ + struct can_priv *priv = netdev_priv(dev); + + if ((dev->flags & IFF_ECHO) && priv->echo_skb[idx]) { + netif_rx(priv->echo_skb[idx]); + priv->echo_skb[idx] = NULL; + } +} +EXPORT_SYMBOL_GPL(can_get_echo_skb); + +/* + * CAN device restart for bus-off recovery + */ +void can_restart(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct can_priv *priv = netdev_priv(dev); + struct net_device_stats *stats = &dev->stats; + struct sk_buff *skb; + struct can_frame *cf; + int err; + + BUG_ON(netif_carrier_ok(dev)); + + /* + * No synchronization needed because the device is bus-off and + * no messages can come in or go out. + */ + can_flush_echo_skb(dev); + + /* send restart message upstream */ + skb = dev_alloc_skb(sizeof(struct can_frame)); + if (skb == NULL) { + err = -ENOMEM; + goto out; + } + skb->dev = dev; + skb->protocol = htons(ETH_P_CAN); + cf = (struct can_frame *)skb_put(skb, sizeof(struct can_frame)); + memset(cf, 0, sizeof(struct can_frame)); + cf->can_id = CAN_ERR_FLAG | CAN_ERR_RESTARTED; + cf->can_dlc = CAN_ERR_DLC; + + netif_rx(skb); + + dev->last_rx = jiffies; + stats->rx_packets++; + stats->rx_bytes += cf->can_dlc; + + dev_dbg(dev->dev.parent, "restarted\n"); + priv->can_stats.restarts++; + + /* Now restart the device */ + err = priv->do_set_mode(dev, CAN_MODE_START); + +out: + netif_carrier_on(dev); + if (err) + dev_err(dev->dev.parent, "Error %d during restart", err); +} + +int can_restart_now(struct net_device *dev) +{ + struct can_priv *priv = netdev_priv(dev); + + /* + * A manual restart is only permitted if automatic restart is + * disabled and the device is in the bus-off state + */ + if (priv->restart_ms) + return -EINVAL; + if (priv->state != CAN_STATE_BUS_OFF) + return -EBUSY; + + /* Runs as soon as possible in the timer context */ + mod_timer(&priv->restart_timer, jiffies); + + return 0; +} + +/* + * CAN bus-off + * + * This functions should be called when the device goes bus-off to + * tell the netif layer that no more packets can be sent or received. + * If enabled, a timer is started to trigger bus-off recovery. + */ +void can_bus_off(struct net_device *dev) +{ + struct can_priv *priv = netdev_priv(dev); + + dev_dbg(dev->dev.parent, "bus-off\n"); + + netif_carrier_off(dev); + priv->can_stats.bus_off++; + + if (priv->restart_ms) + mod_timer(&priv->restart_timer, + jiffies + (priv->restart_ms * HZ) / 1000); +} +EXPORT_SYMBOL_GPL(can_bus_off); + +static void can_setup(struct net_device *dev) +{ + dev->type = ARPHRD_CAN; + dev->mtu = sizeof(struct can_frame); + dev->hard_header_len = 0; + dev->addr_len = 0; + dev->tx_queue_len = 10; + + /* New-style flags. */ + dev->flags = IFF_NOARP; + dev->features = NETIF_F_NO_CSUM; +} + +/* + * Allocate and setup space for the CAN network device + */ +struct net_device *alloc_candev(int sizeof_priv) +{ + struct net_device *dev; + struct can_priv *priv; + + dev = alloc_netdev(sizeof_priv, "can%d", can_setup); + if (!dev) + return NULL; + + priv = netdev_priv(dev); + + priv->state = CAN_STATE_STOPPED; + + init_timer(&priv->restart_timer); + + return dev; +} +EXPORT_SYMBOL_GPL(alloc_candev); + +/* + * Free space of the CAN network device + */ +void free_candev(struct net_device *dev) +{ + free_netdev(dev); +} +EXPORT_SYMBOL_GPL(free_candev); + +/* + * Common open function when the device gets opened. + * + * This function should be called in the open function of the device + * driver. + */ +int open_candev(struct net_device *dev) +{ + struct can_priv *priv = netdev_priv(dev); + + if (!priv->bittiming.tq && !priv->bittiming.bitrate) { + dev_err(dev->dev.parent, "bit-timing not yet defined\n"); + return -EINVAL; + } + + setup_timer(&priv->restart_timer, can_restart, (unsigned long)dev); + + return 0; +} +EXPORT_SYMBOL_GPL(open_candev); + +/* + * Common close function for cleanup before the device gets closed. + * + * This function should be called in the close function of the device + * driver. + */ +void close_candev(struct net_device *dev) +{ + struct can_priv *priv = netdev_priv(dev); + + if (del_timer_sync(&priv->restart_timer)) + dev_put(dev); + can_flush_echo_skb(dev); +} +EXPORT_SYMBOL_GPL(close_candev); + +/* + * CAN netlink interface + */ +static const struct nla_policy can_policy[IFLA_CAN_MAX + 1] = { + [IFLA_CAN_STATE] = { .type = NLA_U32 }, + [IFLA_CAN_CTRLMODE] = { .len = sizeof(struct can_ctrlmode) }, + [IFLA_CAN_RESTART_MS] = { .type = NLA_U32 }, + [IFLA_CAN_RESTART] = { .type = NLA_U32 }, + [IFLA_CAN_BITTIMING] = { .len = sizeof(struct can_bittiming) }, + [IFLA_CAN_BITTIMING_CONST] + = { .len = sizeof(struct can_bittiming_const) }, + [IFLA_CAN_CLOCK] = { .len = sizeof(struct can_clock) }, +}; + +static int can_changelink(struct net_device *dev, + struct nlattr *tb[], struct nlattr *data[]) +{ + struct can_priv *priv = netdev_priv(dev); + int err; + + /* We need synchronization with dev->stop() */ + ASSERT_RTNL(); + + if (data[IFLA_CAN_CTRLMODE]) { + struct can_ctrlmode *cm; + + /* Do not allow changing controller mode while running */ + if (dev->flags & IFF_UP) + return -EBUSY; + cm = nla_data(data[IFLA_CAN_CTRLMODE]); + priv->ctrlmode &= ~cm->mask; + priv->ctrlmode |= cm->flags; + } + + if (data[IFLA_CAN_BITTIMING]) { + struct can_bittiming bt; + + /* Do not allow changing bittiming while running */ + if (dev->flags & IFF_UP) + return -EBUSY; + memcpy(&bt, nla_data(data[IFLA_CAN_BITTIMING]), sizeof(bt)); + if ((!bt.bitrate && !bt.tq) || (bt.bitrate && bt.tq)) + return -EINVAL; + err = can_get_bittiming(dev, &bt); + if (err) + return err; + memcpy(&priv->bittiming, &bt, sizeof(bt)); + + if (priv->do_set_bittiming) { + /* Finally, set the bit-timing registers */ + err = priv->do_set_bittiming(dev); + if (err) + return err; + } + } + + if (data[IFLA_CAN_RESTART_MS]) { + /* Do not allow changing restart delay while running */ + if (dev->flags & IFF_UP) + return -EBUSY; + priv->restart_ms = nla_get_u32(data[IFLA_CAN_RESTART_MS]); + } + + if (data[IFLA_CAN_RESTART]) { + /* Do not allow a restart while not running */ + if (!(dev->flags & IFF_UP)) + return -EINVAL; + err = can_restart_now(dev); + if (err) + return err; + } + + return 0; +} + +static int can_fill_info(struct sk_buff *skb, const struct net_device *dev) +{ + struct can_priv *priv = netdev_priv(dev); + struct can_ctrlmode cm = {.flags = priv->ctrlmode}; + enum can_state state = priv->state; + + if (priv->do_get_state) + priv->do_get_state(dev, &state); + NLA_PUT_U32(skb, IFLA_CAN_STATE, state); + NLA_PUT(skb, IFLA_CAN_CTRLMODE, sizeof(cm), &cm); + NLA_PUT_U32(skb, IFLA_CAN_RESTART_MS, priv->restart_ms); + NLA_PUT(skb, IFLA_CAN_BITTIMING, + sizeof(priv->bittiming), &priv->bittiming); + NLA_PUT(skb, IFLA_CAN_CLOCK, sizeof(cm), &priv->clock); + if (priv->bittiming_const) + NLA_PUT(skb, IFLA_CAN_BITTIMING_CONST, + sizeof(*priv->bittiming_const), priv->bittiming_const); + + return 0; + +nla_put_failure: + return -EMSGSIZE; +} + +static int can_fill_xstats(struct sk_buff *skb, const struct net_device *dev) +{ + struct can_priv *priv = netdev_priv(dev); + + NLA_PUT(skb, IFLA_INFO_XSTATS, + sizeof(priv->can_stats), &priv->can_stats); + + return 0; + +nla_put_failure: + return -EMSGSIZE; +} + +static struct rtnl_link_ops can_link_ops __read_mostly = { + .kind = "can", + .maxtype = IFLA_CAN_MAX, + .policy = can_policy, + .setup = can_setup, + .changelink = can_changelink, + .fill_info = can_fill_info, + .fill_xstats = can_fill_xstats, +}; + +/* + * Register the CAN network device + */ +int register_candev(struct net_device *dev) +{ + dev->rtnl_link_ops = &can_link_ops; + return register_netdev(dev); +} +EXPORT_SYMBOL_GPL(register_candev); + +/* + * Unregister the CAN network device + */ +void unregister_candev(struct net_device *dev) +{ + unregister_netdev(dev); +} +EXPORT_SYMBOL_GPL(unregister_candev); + +static __init int can_dev_init(void) +{ + int err; + + err = rtnl_link_register(&can_link_ops); + if (!err) + printk(KERN_INFO MOD_DESC "\n"); + + return err; +} +module_init(can_dev_init); + +static __exit void can_dev_exit(void) +{ + rtnl_link_unregister(&can_link_ops); +} +module_exit(can_dev_exit); + +MODULE_ALIAS_RTNL_LINK("can"); diff --git a/drivers/net/can/sja1000/Makefile b/drivers/net/can/sja1000/Makefile new file mode 100644 index 000000000000..9d0c08da273c --- /dev/null +++ b/drivers/net/can/sja1000/Makefile @@ -0,0 +1,11 @@ +# +# Makefile for the SJA1000 CAN controller drivers. +# + +obj-$(CONFIG_CAN_SJA1000) += sja1000.o +obj-$(CONFIG_CAN_SJA1000_PLATFORM) += sja1000_platform.o +obj-$(CONFIG_CAN_SJA1000_OF_PLATFORM) += sja1000_of_platform.o +obj-$(CONFIG_CAN_EMS_PCI) += ems_pci.o +obj-$(CONFIG_CAN_KVASER_PCI) += kvaser_pci.o + +ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG diff --git a/drivers/net/can/sja1000/ems_pci.c b/drivers/net/can/sja1000/ems_pci.c new file mode 100644 index 000000000000..121b64101d72 --- /dev/null +++ b/drivers/net/can/sja1000/ems_pci.c @@ -0,0 +1,320 @@ +/* + * Copyright (C) 2007 Wolfgang Grandegger + * Copyright (C) 2008 Markus Plessing + * Copyright (C) 2008 Sebastian Haas + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the version 2 of the GNU General Public License + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sja1000.h" + +#define DRV_NAME "ems_pci" + +MODULE_AUTHOR("Sebastian Haas "); +MODULE_DESCRIPTION("Socket-CAN driver for EMS CPC-PCI/PCIe CAN cards"); +MODULE_SUPPORTED_DEVICE("EMS CPC-PCI/PCIe CAN card"); +MODULE_LICENSE("GPL v2"); + +#define EMS_PCI_MAX_CHAN 2 + +struct ems_pci_card { + int channels; + + struct pci_dev *pci_dev; + struct net_device *net_dev[EMS_PCI_MAX_CHAN]; + + void __iomem *conf_addr; + void __iomem *base_addr; +}; + +#define EMS_PCI_CAN_CLOCK (16000000 / 2) + +/* + * Register definitions and descriptions are from LinCAN 0.3.3. + * + * PSB4610 PITA-2 bridge control registers + */ +#define PITA2_ICR 0x00 /* Interrupt Control Register */ +#define PITA2_ICR_INT0 0x00000002 /* [RC] INT0 Active/Clear */ +#define PITA2_ICR_INT0_EN 0x00020000 /* [RW] Enable INT0 */ + +#define PITA2_MISC 0x1c /* Miscellaneous Register */ +#define PITA2_MISC_CONFIG 0x04000000 /* Multiplexed parallel interface */ + +/* + * The board configuration is probably following: + * RX1 is connected to ground. + * TX1 is not connected. + * CLKO is not connected. + * Setting the OCR register to 0xDA is a good idea. + * This means normal output mode , push-pull and the correct polarity. + */ +#define EMS_PCI_OCR (OCR_TX0_PUSHPULL | OCR_TX1_PUSHPULL) + +/* + * In the CDR register, you should set CBP to 1. + * You will probably also want to set the clock divider value to 7 + * (meaning direct oscillator output) because the second SJA1000 chip + * is driven by the first one CLKOUT output. + */ +#define EMS_PCI_CDR (CDR_CBP | CDR_CLKOUT_MASK) +#define EMS_PCI_MEM_SIZE 4096 /* Size of the remapped io-memory */ +#define EMS_PCI_CAN_BASE_OFFSET 0x400 /* offset where the controllers starts */ +#define EMS_PCI_CAN_CTRL_SIZE 0x200 /* memory size for each controller */ + +#define EMS_PCI_PORT_BYTES 0x4 /* Each register occupies 4 bytes */ + +#define EMS_PCI_VENDOR_ID 0x110a /* PCI device and vendor ID */ +#define EMS_PCI_DEVICE_ID 0x2104 + +static struct pci_device_id ems_pci_tbl[] = { + {EMS_PCI_VENDOR_ID, EMS_PCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,}, + {0,} +}; +MODULE_DEVICE_TABLE(pci, ems_pci_tbl); + +/* + * Helper to read internal registers from card logic (not CAN) + */ +static u8 ems_pci_readb(struct ems_pci_card *card, unsigned int port) +{ + return readb(card->base_addr + (port * EMS_PCI_PORT_BYTES)); +} + +static u8 ems_pci_read_reg(const struct sja1000_priv *priv, int port) +{ + return readb(priv->reg_base + (port * EMS_PCI_PORT_BYTES)); +} + +static void ems_pci_write_reg(const struct sja1000_priv *priv, int port, u8 val) +{ + writeb(val, priv->reg_base + (port * EMS_PCI_PORT_BYTES)); +} + +static void ems_pci_post_irq(const struct sja1000_priv *priv) +{ + struct ems_pci_card *card = (struct ems_pci_card *)priv->priv; + + /* reset int flag of pita */ + writel(PITA2_ICR_INT0_EN | PITA2_ICR_INT0, card->conf_addr + + PITA2_ICR); +} + +/* + * Check if a CAN controller is present at the specified location + * by trying to set 'em into the PeliCAN mode + */ +static inline int ems_pci_check_chan(const struct sja1000_priv *priv) +{ + unsigned char res; + + /* Make sure SJA1000 is in reset mode */ + ems_pci_write_reg(priv, REG_MOD, 1); + + ems_pci_write_reg(priv, REG_CDR, CDR_PELICAN); + + /* read reset-values */ + res = ems_pci_read_reg(priv, REG_CDR); + + if (res == CDR_PELICAN) + return 1; + + return 0; +} + +static void ems_pci_del_card(struct pci_dev *pdev) +{ + struct ems_pci_card *card = pci_get_drvdata(pdev); + struct net_device *dev; + int i = 0; + + for (i = 0; i < card->channels; i++) { + dev = card->net_dev[i]; + + if (!dev) + continue; + + dev_info(&pdev->dev, "Removing %s.\n", dev->name); + unregister_sja1000dev(dev); + free_sja1000dev(dev); + } + + if (card->base_addr != NULL) + pci_iounmap(card->pci_dev, card->base_addr); + + if (card->conf_addr != NULL) + pci_iounmap(card->pci_dev, card->conf_addr); + + kfree(card); + + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); +} + +static void ems_pci_card_reset(struct ems_pci_card *card) +{ + /* Request board reset */ + writeb(0, card->base_addr); +} + +/* + * Probe PCI device for EMS CAN signature and register each available + * CAN channel to SJA1000 Socket-CAN subsystem. + */ +static int __devinit ems_pci_add_card(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct sja1000_priv *priv; + struct net_device *dev; + struct ems_pci_card *card; + int err, i; + + /* Enabling PCI device */ + if (pci_enable_device(pdev) < 0) { + dev_err(&pdev->dev, "Enabling PCI device failed\n"); + return -ENODEV; + } + + /* Allocating card structures to hold addresses, ... */ + card = kzalloc(sizeof(struct ems_pci_card), GFP_KERNEL); + if (card == NULL) { + dev_err(&pdev->dev, "Unable to allocate memory\n"); + pci_disable_device(pdev); + return -ENOMEM; + } + + pci_set_drvdata(pdev, card); + + card->pci_dev = pdev; + + card->channels = 0; + + /* Remap PITA configuration space, and controller memory area */ + card->conf_addr = pci_iomap(pdev, 0, EMS_PCI_MEM_SIZE); + if (card->conf_addr == NULL) { + err = -ENOMEM; + goto failure_cleanup; + } + + card->base_addr = pci_iomap(pdev, 1, EMS_PCI_MEM_SIZE); + if (card->base_addr == NULL) { + err = -ENOMEM; + goto failure_cleanup; + } + + /* Configure PITA-2 parallel interface (enable MUX) */ + writel(PITA2_MISC_CONFIG, card->conf_addr + PITA2_MISC); + + /* Check for unique EMS CAN signature */ + if (ems_pci_readb(card, 0) != 0x55 || + ems_pci_readb(card, 1) != 0xAA || + ems_pci_readb(card, 2) != 0x01 || + ems_pci_readb(card, 3) != 0xCB || + ems_pci_readb(card, 4) != 0x11) { + dev_err(&pdev->dev, "Not EMS Dr. Thomas Wuensche interface\n"); + err = -ENODEV; + goto failure_cleanup; + } + + ems_pci_card_reset(card); + + /* Detect available channels */ + for (i = 0; i < EMS_PCI_MAX_CHAN; i++) { + dev = alloc_sja1000dev(0); + if (dev == NULL) { + err = -ENOMEM; + goto failure_cleanup; + } + + card->net_dev[i] = dev; + priv = netdev_priv(dev); + priv->priv = card; + priv->irq_flags = IRQF_SHARED; + + dev->irq = pdev->irq; + priv->reg_base = card->base_addr + EMS_PCI_CAN_BASE_OFFSET + + (i * EMS_PCI_CAN_CTRL_SIZE); + + /* Check if channel is present */ + if (ems_pci_check_chan(priv)) { + priv->read_reg = ems_pci_read_reg; + priv->write_reg = ems_pci_write_reg; + priv->post_irq = ems_pci_post_irq; + priv->can.clock.freq = EMS_PCI_CAN_CLOCK; + priv->ocr = EMS_PCI_OCR; + priv->cdr = EMS_PCI_CDR; + + SET_NETDEV_DEV(dev, &pdev->dev); + + /* Enable interrupts from card */ + writel(PITA2_ICR_INT0_EN, card->conf_addr + PITA2_ICR); + + /* Register SJA1000 device */ + err = register_sja1000dev(dev); + if (err) { + dev_err(&pdev->dev, "Registering device failed " + "(err=%d)\n", err); + free_sja1000dev(dev); + goto failure_cleanup; + } + + card->channels++; + + dev_info(&pdev->dev, "Channel #%d at 0x%p, irq %d\n", + i + 1, priv->reg_base, dev->irq); + } else { + free_sja1000dev(dev); + } + } + + return 0; + +failure_cleanup: + dev_err(&pdev->dev, "Error: %d. Cleaning Up.\n", err); + + ems_pci_del_card(pdev); + + return err; +} + +static struct pci_driver ems_pci_driver = { + .name = DRV_NAME, + .id_table = ems_pci_tbl, + .probe = ems_pci_add_card, + .remove = ems_pci_del_card, +}; + +static int __init ems_pci_init(void) +{ + return pci_register_driver(&ems_pci_driver); +} + +static void __exit ems_pci_exit(void) +{ + pci_unregister_driver(&ems_pci_driver); +} + +module_init(ems_pci_init); +module_exit(ems_pci_exit); + diff --git a/drivers/net/can/sja1000/kvaser_pci.c b/drivers/net/can/sja1000/kvaser_pci.c new file mode 100644 index 000000000000..7dd7769b9713 --- /dev/null +++ b/drivers/net/can/sja1000/kvaser_pci.c @@ -0,0 +1,412 @@ +/* + * Copyright (C) 2008 Per Dalen + * + * Parts of this software are based on (derived) the following: + * + * - Kvaser linux driver, version 4.72 BETA + * Copyright (C) 2002-2007 KVASER AB + * + * - Lincan driver, version 0.3.3, OCERA project + * Copyright (C) 2004 Pavel Pisa + * Copyright (C) 2001 Arnaud Westenberg + * + * - Socketcan SJA1000 drivers + * Copyright (C) 2007 Wolfgang Grandegger + * Copyright (c) 2002-2007 Volkswagen Group Electronic Research + * Copyright (c) 2003 Matthias Brukner, Trajet Gmbh, Rebenring 33, + * 38106 Braunschweig, GERMANY + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the version 2 of the GNU General Public License + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sja1000.h" + +#define DRV_NAME "kvaser_pci" + +MODULE_AUTHOR("Per Dalen "); +MODULE_DESCRIPTION("Socket-CAN driver for KVASER PCAN PCI cards"); +MODULE_SUPPORTED_DEVICE("KVASER PCAN PCI CAN card"); +MODULE_LICENSE("GPL v2"); + +#define MAX_NO_OF_CHANNELS 4 /* max no of channels on a single card */ + +struct kvaser_pci { + int channel; + struct pci_dev *pci_dev; + struct net_device *slave_dev[MAX_NO_OF_CHANNELS-1]; + void __iomem *conf_addr; + void __iomem *res_addr; + int no_channels; + u8 xilinx_ver; +}; + +#define KVASER_PCI_CAN_CLOCK (16000000 / 2) + +/* + * The board configuration is probably following: + * RX1 is connected to ground. + * TX1 is not connected. + * CLKO is not connected. + * Setting the OCR register to 0xDA is a good idea. + * This means normal output mode , push-pull and the correct polarity. + */ +#define KVASER_PCI_OCR (OCR_TX0_PUSHPULL | OCR_TX1_PUSHPULL) + +/* + * In the CDR register, you should set CBP to 1. + * You will probably also want to set the clock divider value to 0 + * (meaning divide-by-2), the Pelican bit, and the clock-off bit + * (you will have no need for CLKOUT anyway). + */ +#define KVASER_PCI_CDR (CDR_CBP | CDR_CLKOUT_MASK) + +/* + * These register values are valid for revision 14 of the Xilinx logic. + */ +#define XILINX_VERINT 7 /* Lower nibble simulate interrupts, + high nibble version number. */ + +#define XILINX_PRESUMED_VERSION 14 + +/* + * Important S5920 registers + */ +#define S5920_INTCSR 0x38 +#define S5920_PTCR 0x60 +#define INTCSR_ADDON_INTENABLE_M 0x2000 + + +#define KVASER_PCI_PORT_BYTES 0x20 + +#define PCI_CONFIG_PORT_SIZE 0x80 /* size of the config io-memory */ +#define PCI_PORT_SIZE 0x80 /* size of a channel io-memory */ +#define PCI_PORT_XILINX_SIZE 0x08 /* size of a xilinx io-memory */ + +#define KVASER_PCI_VENDOR_ID1 0x10e8 /* the PCI device and vendor IDs */ +#define KVASER_PCI_DEVICE_ID1 0x8406 + +#define KVASER_PCI_VENDOR_ID2 0x1a07 /* the PCI device and vendor IDs */ +#define KVASER_PCI_DEVICE_ID2 0x0008 + +static struct pci_device_id kvaser_pci_tbl[] = { + {KVASER_PCI_VENDOR_ID1, KVASER_PCI_DEVICE_ID1, PCI_ANY_ID, PCI_ANY_ID,}, + {KVASER_PCI_VENDOR_ID2, KVASER_PCI_DEVICE_ID2, PCI_ANY_ID, PCI_ANY_ID,}, + { 0,} +}; + +MODULE_DEVICE_TABLE(pci, kvaser_pci_tbl); + +static u8 kvaser_pci_read_reg(const struct sja1000_priv *priv, int port) +{ + return ioread8(priv->reg_base + port); +} + +static void kvaser_pci_write_reg(const struct sja1000_priv *priv, + int port, u8 val) +{ + iowrite8(val, priv->reg_base + port); +} + +static void kvaser_pci_disable_irq(struct net_device *dev) +{ + struct sja1000_priv *priv = netdev_priv(dev); + struct kvaser_pci *board = priv->priv; + u32 intcsr; + + /* Disable interrupts from card */ + intcsr = ioread32(board->conf_addr + S5920_INTCSR); + intcsr &= ~INTCSR_ADDON_INTENABLE_M; + iowrite32(intcsr, board->conf_addr + S5920_INTCSR); +} + +static void kvaser_pci_enable_irq(struct net_device *dev) +{ + struct sja1000_priv *priv = netdev_priv(dev); + struct kvaser_pci *board = priv->priv; + u32 tmp_en_io; + + /* Enable interrupts from card */ + tmp_en_io = ioread32(board->conf_addr + S5920_INTCSR); + tmp_en_io |= INTCSR_ADDON_INTENABLE_M; + iowrite32(tmp_en_io, board->conf_addr + S5920_INTCSR); +} + +static int number_of_sja1000_chip(void __iomem *base_addr) +{ + u8 status; + int i; + + for (i = 0; i < MAX_NO_OF_CHANNELS; i++) { + /* reset chip */ + iowrite8(MOD_RM, base_addr + + (i * KVASER_PCI_PORT_BYTES) + REG_MOD); + status = ioread8(base_addr + + (i * KVASER_PCI_PORT_BYTES) + REG_MOD); + /* check reset bit */ + if (!(status & MOD_RM)) + break; + } + + return i; +} + +static void kvaser_pci_del_chan(struct net_device *dev) +{ + struct sja1000_priv *priv; + struct kvaser_pci *board; + int i; + + if (!dev) + return; + priv = netdev_priv(dev); + board = priv->priv; + if (!board) + return; + + dev_info(&board->pci_dev->dev, "Removing device %s\n", + dev->name); + + /* Disable PCI interrupts */ + kvaser_pci_disable_irq(dev); + + for (i = 0; i < board->no_channels - 1; i++) { + if (board->slave_dev[i]) { + dev_info(&board->pci_dev->dev, "Removing device %s\n", + board->slave_dev[i]->name); + unregister_sja1000dev(board->slave_dev[i]); + free_sja1000dev(board->slave_dev[i]); + } + } + unregister_sja1000dev(dev); + + pci_iounmap(board->pci_dev, priv->reg_base); + pci_iounmap(board->pci_dev, board->conf_addr); + pci_iounmap(board->pci_dev, board->res_addr); + + free_sja1000dev(dev); +} + +static int kvaser_pci_add_chan(struct pci_dev *pdev, int channel, + struct net_device **master_dev, + void __iomem *conf_addr, + void __iomem *res_addr, + void __iomem *base_addr) +{ + struct net_device *dev; + struct sja1000_priv *priv; + struct kvaser_pci *board; + int err, init_step; + + dev = alloc_sja1000dev(sizeof(struct kvaser_pci)); + if (dev == NULL) + return -ENOMEM; + + priv = netdev_priv(dev); + board = priv->priv; + + board->pci_dev = pdev; + board->channel = channel; + + /* S5920 */ + board->conf_addr = conf_addr; + + /* XILINX board wide address */ + board->res_addr = res_addr; + + if (channel == 0) { + board->xilinx_ver = + ioread8(board->res_addr + XILINX_VERINT) >> 4; + init_step = 2; + + /* Assert PTADR# - we're in passive mode so the other bits are + not important */ + iowrite32(0x80808080UL, board->conf_addr + S5920_PTCR); + + /* Enable interrupts from card */ + kvaser_pci_enable_irq(dev); + } else { + struct sja1000_priv *master_priv = netdev_priv(*master_dev); + struct kvaser_pci *master_board = master_priv->priv; + master_board->slave_dev[channel - 1] = dev; + master_board->no_channels = channel + 1; + board->xilinx_ver = master_board->xilinx_ver; + } + + priv->reg_base = base_addr + channel * KVASER_PCI_PORT_BYTES; + + priv->read_reg = kvaser_pci_read_reg; + priv->write_reg = kvaser_pci_write_reg; + + priv->can.clock.freq = KVASER_PCI_CAN_CLOCK; + + priv->ocr = KVASER_PCI_OCR; + priv->cdr = KVASER_PCI_CDR; + + priv->irq_flags = IRQF_SHARED; + dev->irq = pdev->irq; + + init_step = 4; + + dev_info(&pdev->dev, "reg_base=%p conf_addr=%p irq=%d\n", + priv->reg_base, board->conf_addr, dev->irq); + + SET_NETDEV_DEV(dev, &pdev->dev); + + /* Register SJA1000 device */ + err = register_sja1000dev(dev); + if (err) { + dev_err(&pdev->dev, "Registering device failed (err=%d)\n", + err); + goto failure; + } + + if (channel == 0) + *master_dev = dev; + + return 0; + +failure: + kvaser_pci_del_chan(dev); + return err; +} + +static int __devinit kvaser_pci_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + int err; + struct net_device *master_dev = NULL; + struct sja1000_priv *priv; + struct kvaser_pci *board; + int no_channels; + void __iomem *base_addr = NULL; + void __iomem *conf_addr = NULL; + void __iomem *res_addr = NULL; + int i; + + dev_info(&pdev->dev, "initializing device %04x:%04x\n", + pdev->vendor, pdev->device); + + err = pci_enable_device(pdev); + if (err) + goto failure; + + err = pci_request_regions(pdev, DRV_NAME); + if (err) + goto failure_release_pci; + + /* S5920 */ + conf_addr = pci_iomap(pdev, 0, PCI_CONFIG_PORT_SIZE); + if (conf_addr == NULL) { + err = -ENODEV; + goto failure_release_regions; + } + + /* XILINX board wide address */ + res_addr = pci_iomap(pdev, 2, PCI_PORT_XILINX_SIZE); + if (res_addr == NULL) { + err = -ENOMEM; + goto failure_iounmap; + } + + base_addr = pci_iomap(pdev, 1, PCI_PORT_SIZE); + if (base_addr == NULL) { + err = -ENOMEM; + goto failure_iounmap; + } + + no_channels = number_of_sja1000_chip(base_addr); + if (no_channels == 0) { + err = -ENOMEM; + goto failure_iounmap; + } + + for (i = 0; i < no_channels; i++) { + err = kvaser_pci_add_chan(pdev, i, &master_dev, + conf_addr, res_addr, + base_addr); + if (err) + goto failure_cleanup; + } + + priv = netdev_priv(master_dev); + board = priv->priv; + + dev_info(&pdev->dev, "xilinx version=%d number of channels=%d\n", + board->xilinx_ver, board->no_channels); + + pci_set_drvdata(pdev, master_dev); + return 0; + +failure_cleanup: + kvaser_pci_del_chan(master_dev); + +failure_iounmap: + if (conf_addr != NULL) + pci_iounmap(pdev, conf_addr); + if (res_addr != NULL) + pci_iounmap(pdev, res_addr); + if (base_addr != NULL) + pci_iounmap(pdev, base_addr); + +failure_release_regions: + pci_release_regions(pdev); + +failure_release_pci: + pci_disable_device(pdev); + +failure: + return err; + +} + +static void __devexit kvaser_pci_remove_one(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + + kvaser_pci_del_chan(dev); + + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); +} + +static struct pci_driver kvaser_pci_driver = { + .name = DRV_NAME, + .id_table = kvaser_pci_tbl, + .probe = kvaser_pci_init_one, + .remove = __devexit_p(kvaser_pci_remove_one), +}; + +static int __init kvaser_pci_init(void) +{ + return pci_register_driver(&kvaser_pci_driver); +} + +static void __exit kvaser_pci_exit(void) +{ + pci_unregister_driver(&kvaser_pci_driver); +} + +module_init(kvaser_pci_init); +module_exit(kvaser_pci_exit); diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c new file mode 100644 index 000000000000..571f133a8fec --- /dev/null +++ b/drivers/net/can/sja1000/sja1000.c @@ -0,0 +1,637 @@ +/* + * sja1000.c - Philips SJA1000 network device driver + * + * Copyright (c) 2003 Matthias Brukner, Trajet Gmbh, Rebenring 33, + * 38106 Braunschweig, GERMANY + * + * Copyright (c) 2002-2007 Volkswagen Group Electronic Research + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Volkswagen nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Alternatively, provided that this notice is retained in full, this + * software may be distributed under the terms of the GNU General + * Public License ("GPL") version 2, in which case the provisions of the + * GPL apply INSTEAD OF those given above. + * + * The provided data structures and external interfaces from this code + * are not restricted to be used by modules with a GPL compatible license. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * Send feedback to + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "sja1000.h" + +#define DRV_NAME "sja1000" + +MODULE_AUTHOR("Oliver Hartkopp "); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_DESCRIPTION(DRV_NAME "CAN netdevice driver"); + +static struct can_bittiming_const sja1000_bittiming_const = { + .name = DRV_NAME, + .tseg1_min = 1, + .tseg1_max = 16, + .tseg2_min = 1, + .tseg2_max = 8, + .sjw_max = 4, + .brp_min = 1, + .brp_max = 64, + .brp_inc = 1, +}; + +static int sja1000_probe_chip(struct net_device *dev) +{ + struct sja1000_priv *priv = netdev_priv(dev); + + if (priv->reg_base && (priv->read_reg(priv, 0) == 0xFF)) { + printk(KERN_INFO "%s: probing @0x%lX failed\n", + DRV_NAME, dev->base_addr); + return 0; + } + return -1; +} + +static void set_reset_mode(struct net_device *dev) +{ + struct sja1000_priv *priv = netdev_priv(dev); + unsigned char status = priv->read_reg(priv, REG_MOD); + int i; + + /* disable interrupts */ + priv->write_reg(priv, REG_IER, IRQ_OFF); + + for (i = 0; i < 100; i++) { + /* check reset bit */ + if (status & MOD_RM) { + priv->can.state = CAN_STATE_STOPPED; + return; + } + + priv->write_reg(priv, REG_MOD, MOD_RM); /* reset chip */ + udelay(10); + status = priv->read_reg(priv, REG_MOD); + } + + dev_err(dev->dev.parent, "setting SJA1000 into reset mode failed!\n"); +} + +static void set_normal_mode(struct net_device *dev) +{ + struct sja1000_priv *priv = netdev_priv(dev); + unsigned char status = priv->read_reg(priv, REG_MOD); + int i; + + for (i = 0; i < 100; i++) { + /* check reset bit */ + if ((status & MOD_RM) == 0) { + priv->can.state = CAN_STATE_ERROR_ACTIVE; + /* enable all interrupts */ + priv->write_reg(priv, REG_IER, IRQ_ALL); + return; + } + + /* set chip to normal mode */ + priv->write_reg(priv, REG_MOD, 0x00); + udelay(10); + status = priv->read_reg(priv, REG_MOD); + } + + dev_err(dev->dev.parent, "setting SJA1000 into normal mode failed!\n"); +} + +static void sja1000_start(struct net_device *dev) +{ + struct sja1000_priv *priv = netdev_priv(dev); + + /* leave reset mode */ + if (priv->can.state != CAN_STATE_STOPPED) + set_reset_mode(dev); + + /* Clear error counters and error code capture */ + priv->write_reg(priv, REG_TXERR, 0x0); + priv->write_reg(priv, REG_RXERR, 0x0); + priv->read_reg(priv, REG_ECC); + + /* leave reset mode */ + set_normal_mode(dev); +} + +static int sja1000_set_mode(struct net_device *dev, enum can_mode mode) +{ + struct sja1000_priv *priv = netdev_priv(dev); + + if (!priv->open_time) + return -EINVAL; + + switch (mode) { + case CAN_MODE_START: + sja1000_start(dev); + if (netif_queue_stopped(dev)) + netif_wake_queue(dev); + break; + + default: + return -EOPNOTSUPP; + } + + return 0; +} + +static int sja1000_set_bittiming(struct net_device *dev) +{ + struct sja1000_priv *priv = netdev_priv(dev); + struct can_bittiming *bt = &priv->can.bittiming; + u8 btr0, btr1; + + btr0 = ((bt->brp - 1) & 0x3f) | (((bt->sjw - 1) & 0x3) << 6); + btr1 = ((bt->prop_seg + bt->phase_seg1 - 1) & 0xf) | + (((bt->phase_seg2 - 1) & 0x7) << 4); + if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) + btr1 |= 0x80; + + dev_info(dev->dev.parent, + "setting BTR0=0x%02x BTR1=0x%02x\n", btr0, btr1); + + priv->write_reg(priv, REG_BTR0, btr0); + priv->write_reg(priv, REG_BTR1, btr1); + + return 0; +} + +/* + * initialize SJA1000 chip: + * - reset chip + * - set output mode + * - set baudrate + * - enable interrupts + * - start operating mode + */ +static void chipset_init(struct net_device *dev) +{ + struct sja1000_priv *priv = netdev_priv(dev); + + /* set clock divider and output control register */ + priv->write_reg(priv, REG_CDR, priv->cdr | CDR_PELICAN); + + /* set acceptance filter (accept all) */ + priv->write_reg(priv, REG_ACCC0, 0x00); + priv->write_reg(priv, REG_ACCC1, 0x00); + priv->write_reg(priv, REG_ACCC2, 0x00); + priv->write_reg(priv, REG_ACCC3, 0x00); + + priv->write_reg(priv, REG_ACCM0, 0xFF); + priv->write_reg(priv, REG_ACCM1, 0xFF); + priv->write_reg(priv, REG_ACCM2, 0xFF); + priv->write_reg(priv, REG_ACCM3, 0xFF); + + priv->write_reg(priv, REG_OCR, priv->ocr | OCR_MODE_NORMAL); +} + +/* + * transmit a CAN message + * message layout in the sk_buff should be like this: + * xx xx xx xx ff ll 00 11 22 33 44 55 66 77 + * [ can-id ] [flags] [len] [can data (up to 8 bytes] + */ +static int sja1000_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct sja1000_priv *priv = netdev_priv(dev); + struct net_device_stats *stats = &dev->stats; + struct can_frame *cf = (struct can_frame *)skb->data; + uint8_t fi; + uint8_t dlc; + canid_t id; + uint8_t dreg; + int i; + + netif_stop_queue(dev); + + fi = dlc = cf->can_dlc; + id = cf->can_id; + + if (id & CAN_RTR_FLAG) + fi |= FI_RTR; + + if (id & CAN_EFF_FLAG) { + fi |= FI_FF; + dreg = EFF_BUF; + priv->write_reg(priv, REG_FI, fi); + priv->write_reg(priv, REG_ID1, (id & 0x1fe00000) >> (5 + 16)); + priv->write_reg(priv, REG_ID2, (id & 0x001fe000) >> (5 + 8)); + priv->write_reg(priv, REG_ID3, (id & 0x00001fe0) >> 5); + priv->write_reg(priv, REG_ID4, (id & 0x0000001f) << 3); + } else { + dreg = SFF_BUF; + priv->write_reg(priv, REG_FI, fi); + priv->write_reg(priv, REG_ID1, (id & 0x000007f8) >> 3); + priv->write_reg(priv, REG_ID2, (id & 0x00000007) << 5); + } + + for (i = 0; i < dlc; i++) + priv->write_reg(priv, dreg++, cf->data[i]); + + stats->tx_bytes += dlc; + dev->trans_start = jiffies; + + can_put_echo_skb(skb, dev, 0); + + priv->write_reg(priv, REG_CMR, CMD_TR); + + return 0; +} + +static void sja1000_rx(struct net_device *dev) +{ + struct sja1000_priv *priv = netdev_priv(dev); + struct net_device_stats *stats = &dev->stats; + struct can_frame *cf; + struct sk_buff *skb; + uint8_t fi; + uint8_t dreg; + canid_t id; + uint8_t dlc; + int i; + + skb = dev_alloc_skb(sizeof(struct can_frame)); + if (skb == NULL) + return; + skb->dev = dev; + skb->protocol = htons(ETH_P_CAN); + + fi = priv->read_reg(priv, REG_FI); + dlc = fi & 0x0F; + + if (fi & FI_FF) { + /* extended frame format (EFF) */ + dreg = EFF_BUF; + id = (priv->read_reg(priv, REG_ID1) << (5 + 16)) + | (priv->read_reg(priv, REG_ID2) << (5 + 8)) + | (priv->read_reg(priv, REG_ID3) << 5) + | (priv->read_reg(priv, REG_ID4) >> 3); + id |= CAN_EFF_FLAG; + } else { + /* standard frame format (SFF) */ + dreg = SFF_BUF; + id = (priv->read_reg(priv, REG_ID1) << 3) + | (priv->read_reg(priv, REG_ID2) >> 5); + } + + if (fi & FI_RTR) + id |= CAN_RTR_FLAG; + + cf = (struct can_frame *)skb_put(skb, sizeof(struct can_frame)); + memset(cf, 0, sizeof(struct can_frame)); + cf->can_id = id; + cf->can_dlc = dlc; + for (i = 0; i < dlc; i++) + cf->data[i] = priv->read_reg(priv, dreg++); + + while (i < 8) + cf->data[i++] = 0; + + /* release receive buffer */ + priv->write_reg(priv, REG_CMR, CMD_RRB); + + netif_rx(skb); + + dev->last_rx = jiffies; + stats->rx_packets++; + stats->rx_bytes += dlc; +} + +static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status) +{ + struct sja1000_priv *priv = netdev_priv(dev); + struct net_device_stats *stats = &dev->stats; + struct can_frame *cf; + struct sk_buff *skb; + enum can_state state = priv->can.state; + uint8_t ecc, alc; + + skb = dev_alloc_skb(sizeof(struct can_frame)); + if (skb == NULL) + return -ENOMEM; + skb->dev = dev; + skb->protocol = htons(ETH_P_CAN); + cf = (struct can_frame *)skb_put(skb, sizeof(struct can_frame)); + memset(cf, 0, sizeof(struct can_frame)); + cf->can_id = CAN_ERR_FLAG; + cf->can_dlc = CAN_ERR_DLC; + + if (isrc & IRQ_DOI) { + /* data overrun interrupt */ + dev_dbg(dev->dev.parent, "data overrun interrupt\n"); + cf->can_id |= CAN_ERR_CRTL; + cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; + stats->rx_over_errors++; + stats->rx_errors++; + priv->write_reg(priv, REG_CMR, CMD_CDO); /* clear bit */ + } + + if (isrc & IRQ_EI) { + /* error warning interrupt */ + dev_dbg(dev->dev.parent, "error warning interrupt\n"); + + if (status & SR_BS) { + state = CAN_STATE_BUS_OFF; + cf->can_id |= CAN_ERR_BUSOFF; + can_bus_off(dev); + } else if (status & SR_ES) { + state = CAN_STATE_ERROR_WARNING; + } else + state = CAN_STATE_ERROR_ACTIVE; + } + if (isrc & IRQ_BEI) { + /* bus error interrupt */ + priv->can.can_stats.bus_error++; + stats->rx_errors++; + + ecc = priv->read_reg(priv, REG_ECC); + + cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; + + switch (ecc & ECC_MASK) { + case ECC_BIT: + cf->data[2] |= CAN_ERR_PROT_BIT; + break; + case ECC_FORM: + cf->data[2] |= CAN_ERR_PROT_FORM; + break; + case ECC_STUFF: + cf->data[2] |= CAN_ERR_PROT_STUFF; + break; + default: + cf->data[2] |= CAN_ERR_PROT_UNSPEC; + cf->data[3] = ecc & ECC_SEG; + break; + } + /* Error occured during transmission? */ + if ((ecc & ECC_DIR) == 0) + cf->data[2] |= CAN_ERR_PROT_TX; + } + if (isrc & IRQ_EPI) { + /* error passive interrupt */ + dev_dbg(dev->dev.parent, "error passive interrupt\n"); + if (status & SR_ES) + state = CAN_STATE_ERROR_PASSIVE; + else + state = CAN_STATE_ERROR_ACTIVE; + } + if (isrc & IRQ_ALI) { + /* arbitration lost interrupt */ + dev_dbg(dev->dev.parent, "arbitration lost interrupt\n"); + alc = priv->read_reg(priv, REG_ALC); + priv->can.can_stats.arbitration_lost++; + stats->rx_errors++; + cf->can_id |= CAN_ERR_LOSTARB; + cf->data[0] = alc & 0x1f; + } + + if (state != priv->can.state && (state == CAN_STATE_ERROR_WARNING || + state == CAN_STATE_ERROR_PASSIVE)) { + uint8_t rxerr = priv->read_reg(priv, REG_RXERR); + uint8_t txerr = priv->read_reg(priv, REG_TXERR); + cf->can_id |= CAN_ERR_CRTL; + if (state == CAN_STATE_ERROR_WARNING) { + priv->can.can_stats.error_warning++; + cf->data[1] = (txerr > rxerr) ? + CAN_ERR_CRTL_TX_WARNING : + CAN_ERR_CRTL_RX_WARNING; + } else { + priv->can.can_stats.error_passive++; + cf->data[1] = (txerr > rxerr) ? + CAN_ERR_CRTL_TX_PASSIVE : + CAN_ERR_CRTL_RX_PASSIVE; + } + } + + priv->can.state = state; + + netif_rx(skb); + + dev->last_rx = jiffies; + stats->rx_packets++; + stats->rx_bytes += cf->can_dlc; + + return 0; +} + +irqreturn_t sja1000_interrupt(int irq, void *dev_id) +{ + struct net_device *dev = (struct net_device *)dev_id; + struct sja1000_priv *priv = netdev_priv(dev); + struct net_device_stats *stats = &dev->stats; + uint8_t isrc, status; + int n = 0; + + /* Shared interrupts and IRQ off? */ + if (priv->read_reg(priv, REG_IER) == IRQ_OFF) + return IRQ_NONE; + + if (priv->pre_irq) + priv->pre_irq(priv); + + while ((isrc = priv->read_reg(priv, REG_IR)) && (n < SJA1000_MAX_IRQ)) { + n++; + status = priv->read_reg(priv, REG_SR); + + if (isrc & IRQ_WUI) + dev_warn(dev->dev.parent, "wakeup interrupt\n"); + + if (isrc & IRQ_TI) { + /* transmission complete interrupt */ + stats->tx_packets++; + can_get_echo_skb(dev, 0); + netif_wake_queue(dev); + } + if (isrc & IRQ_RI) { + /* receive interrupt */ + while (status & SR_RBS) { + sja1000_rx(dev); + status = priv->read_reg(priv, REG_SR); + } + } + if (isrc & (IRQ_DOI | IRQ_EI | IRQ_BEI | IRQ_EPI | IRQ_ALI)) { + /* error interrupt */ + if (sja1000_err(dev, isrc, status)) + break; + } + } + + if (priv->post_irq) + priv->post_irq(priv); + + if (n >= SJA1000_MAX_IRQ) + dev_dbg(dev->dev.parent, "%d messages handled in ISR", n); + + return (n) ? IRQ_HANDLED : IRQ_NONE; +} +EXPORT_SYMBOL_GPL(sja1000_interrupt); + +static int sja1000_open(struct net_device *dev) +{ + struct sja1000_priv *priv = netdev_priv(dev); + int err; + + /* set chip into reset mode */ + set_reset_mode(dev); + + /* common open */ + err = open_candev(dev); + if (err) + return err; + + /* register interrupt handler, if not done by the device driver */ + if (!(priv->flags & SJA1000_CUSTOM_IRQ_HANDLER)) { + err = request_irq(dev->irq, &sja1000_interrupt, priv->irq_flags, + dev->name, (void *)dev); + if (err) { + close_candev(dev); + return -EAGAIN; + } + } + + /* init and start chi */ + sja1000_start(dev); + priv->open_time = jiffies; + + netif_start_queue(dev); + + return 0; +} + +static int sja1000_close(struct net_device *dev) +{ + struct sja1000_priv *priv = netdev_priv(dev); + + netif_stop_queue(dev); + set_reset_mode(dev); + + if (!(priv->flags & SJA1000_CUSTOM_IRQ_HANDLER)) + free_irq(dev->irq, (void *)dev); + + close_candev(dev); + + priv->open_time = 0; + + return 0; +} + +struct net_device *alloc_sja1000dev(int sizeof_priv) +{ + struct net_device *dev; + struct sja1000_priv *priv; + + dev = alloc_candev(sizeof(struct sja1000_priv) + sizeof_priv); + if (!dev) + return NULL; + + priv = netdev_priv(dev); + + priv->dev = dev; + priv->can.bittiming_const = &sja1000_bittiming_const; + priv->can.do_set_bittiming = sja1000_set_bittiming; + priv->can.do_set_mode = sja1000_set_mode; + + if (sizeof_priv) + priv->priv = (void *)priv + sizeof(struct sja1000_priv); + + return dev; +} +EXPORT_SYMBOL_GPL(alloc_sja1000dev); + +void free_sja1000dev(struct net_device *dev) +{ + free_candev(dev); +} +EXPORT_SYMBOL_GPL(free_sja1000dev); + +static const struct net_device_ops sja1000_netdev_ops = { + .ndo_open = sja1000_open, + .ndo_stop = sja1000_close, + .ndo_start_xmit = sja1000_start_xmit, +}; + +int register_sja1000dev(struct net_device *dev) +{ + if (!sja1000_probe_chip(dev)) + return -ENODEV; + + dev->flags |= IFF_ECHO; /* we support local echo */ + dev->netdev_ops = &sja1000_netdev_ops; + + set_reset_mode(dev); + chipset_init(dev); + + return register_candev(dev); +} +EXPORT_SYMBOL_GPL(register_sja1000dev); + +void unregister_sja1000dev(struct net_device *dev) +{ + set_reset_mode(dev); + unregister_candev(dev); +} +EXPORT_SYMBOL_GPL(unregister_sja1000dev); + +static __init int sja1000_init(void) +{ + printk(KERN_INFO "%s CAN netdevice driver\n", DRV_NAME); + + return 0; +} + +module_init(sja1000_init); + +static __exit void sja1000_exit(void) +{ + printk(KERN_INFO "%s: driver removed\n", DRV_NAME); +} + +module_exit(sja1000_exit); diff --git a/drivers/net/can/sja1000/sja1000.h b/drivers/net/can/sja1000/sja1000.h new file mode 100644 index 000000000000..302d2c763ad7 --- /dev/null +++ b/drivers/net/can/sja1000/sja1000.h @@ -0,0 +1,181 @@ +/* + * sja1000.h - Philips SJA1000 network device driver + * + * Copyright (c) 2003 Matthias Brukner, Trajet Gmbh, Rebenring 33, + * 38106 Braunschweig, GERMANY + * + * Copyright (c) 2002-2007 Volkswagen Group Electronic Research + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Volkswagen nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Alternatively, provided that this notice is retained in full, this + * software may be distributed under the terms of the GNU General + * Public License ("GPL") version 2, in which case the provisions of the + * GPL apply INSTEAD OF those given above. + * + * The provided data structures and external interfaces from this code + * are not restricted to be used by modules with a GPL compatible license. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * Send feedback to + * + */ + +#ifndef SJA1000_DEV_H +#define SJA1000_DEV_H + +#include +#include + +#define SJA1000_MAX_IRQ 20 /* max. number of interrupts handled in ISR */ + +/* SJA1000 registers - manual section 6.4 (Pelican Mode) */ +#define REG_MOD 0x00 +#define REG_CMR 0x01 +#define REG_SR 0x02 +#define REG_IR 0x03 +#define REG_IER 0x04 +#define REG_ALC 0x0B +#define REG_ECC 0x0C +#define REG_EWL 0x0D +#define REG_RXERR 0x0E +#define REG_TXERR 0x0F +#define REG_ACCC0 0x10 +#define REG_ACCC1 0x11 +#define REG_ACCC2 0x12 +#define REG_ACCC3 0x13 +#define REG_ACCM0 0x14 +#define REG_ACCM1 0x15 +#define REG_ACCM2 0x16 +#define REG_ACCM3 0x17 +#define REG_RMC 0x1D +#define REG_RBSA 0x1E + +/* Common registers - manual section 6.5 */ +#define REG_BTR0 0x06 +#define REG_BTR1 0x07 +#define REG_OCR 0x08 +#define REG_CDR 0x1F + +#define REG_FI 0x10 +#define SFF_BUF 0x13 +#define EFF_BUF 0x15 + +#define FI_FF 0x80 +#define FI_RTR 0x40 + +#define REG_ID1 0x11 +#define REG_ID2 0x12 +#define REG_ID3 0x13 +#define REG_ID4 0x14 + +#define CAN_RAM 0x20 + +/* mode register */ +#define MOD_RM 0x01 +#define MOD_LOM 0x02 +#define MOD_STM 0x04 +#define MOD_AFM 0x08 +#define MOD_SM 0x10 + +/* commands */ +#define CMD_SRR 0x10 +#define CMD_CDO 0x08 +#define CMD_RRB 0x04 +#define CMD_AT 0x02 +#define CMD_TR 0x01 + +/* interrupt sources */ +#define IRQ_BEI 0x80 +#define IRQ_ALI 0x40 +#define IRQ_EPI 0x20 +#define IRQ_WUI 0x10 +#define IRQ_DOI 0x08 +#define IRQ_EI 0x04 +#define IRQ_TI 0x02 +#define IRQ_RI 0x01 +#define IRQ_ALL 0xFF +#define IRQ_OFF 0x00 + +/* status register content */ +#define SR_BS 0x80 +#define SR_ES 0x40 +#define SR_TS 0x20 +#define SR_RS 0x10 +#define SR_TCS 0x08 +#define SR_TBS 0x04 +#define SR_DOS 0x02 +#define SR_RBS 0x01 + +#define SR_CRIT (SR_BS|SR_ES) + +/* ECC register */ +#define ECC_SEG 0x1F +#define ECC_DIR 0x20 +#define ECC_ERR 6 +#define ECC_BIT 0x00 +#define ECC_FORM 0x40 +#define ECC_STUFF 0x80 +#define ECC_MASK 0xc0 + +/* + * Flags for sja1000priv.flags + */ +#define SJA1000_CUSTOM_IRQ_HANDLER 0x1 + +/* + * SJA1000 private data structure + */ +struct sja1000_priv { + struct can_priv can; /* must be the first member */ + int open_time; + struct sk_buff *echo_skb; + + /* the lower-layer is responsible for appropriate locking */ + u8 (*read_reg) (const struct sja1000_priv *priv, int reg); + void (*write_reg) (const struct sja1000_priv *priv, int reg, u8 val); + void (*pre_irq) (const struct sja1000_priv *priv); + void (*post_irq) (const struct sja1000_priv *priv); + + void *priv; /* for board-specific data */ + struct net_device *dev; + + void __iomem *reg_base; /* ioremap'ed address to registers */ + unsigned long irq_flags; /* for request_irq() */ + + u16 flags; /* custom mode flags */ + u8 ocr; /* output control register */ + u8 cdr; /* clock divider register */ +}; + +struct net_device *alloc_sja1000dev(int sizeof_priv); +void free_sja1000dev(struct net_device *dev); +int register_sja1000dev(struct net_device *dev); +void unregister_sja1000dev(struct net_device *dev); + +irqreturn_t sja1000_interrupt(int irq, void *dev_id); + +#endif /* SJA1000_DEV_H */ diff --git a/drivers/net/can/sja1000/sja1000_of_platform.c b/drivers/net/can/sja1000/sja1000_of_platform.c new file mode 100644 index 000000000000..3373560405ba --- /dev/null +++ b/drivers/net/can/sja1000/sja1000_of_platform.c @@ -0,0 +1,235 @@ +/* + * Driver for SJA1000 CAN controllers on the OpenFirmware platform bus + * + * Copyright (C) 2008-2009 Wolfgang Grandegger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the version 2 of the GNU General Public License + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* This is a generic driver for SJA1000 chips on the OpenFirmware platform + * bus found on embedded PowerPC systems. You need a SJA1000 CAN node + * definition in your flattened device tree source (DTS) file similar to: + * + * can@3,100 { + * compatible = "nxp,sja1000"; + * reg = <3 0x100 0x80>; + * interrupts = <2 0>; + * interrupt-parent = <&mpic>; + * nxp,external-clock-frequency = <16000000>; + * }; + * + * See "Documentation/powerpc/dts-bindings/can/sja1000.txt" for further + * information. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "sja1000.h" + +#define DRV_NAME "sja1000_of_platform" + +MODULE_AUTHOR("Wolfgang Grandegger "); +MODULE_DESCRIPTION("Socket-CAN driver for SJA1000 on the OF platform bus"); +MODULE_LICENSE("GPL v2"); + +#define SJA1000_OFP_CAN_CLOCK (16000000 / 2) + +#define SJA1000_OFP_OCR OCR_TX0_PULLDOWN +#define SJA1000_OFP_CDR (CDR_CBP | CDR_CLK_OFF) + +static u8 sja1000_ofp_read_reg(const struct sja1000_priv *priv, int reg) +{ + return in_8(priv->reg_base + reg); +} + +static void sja1000_ofp_write_reg(const struct sja1000_priv *priv, + int reg, u8 val) +{ + out_8(priv->reg_base + reg, val); +} + +static int __devexit sja1000_ofp_remove(struct of_device *ofdev) +{ + struct net_device *dev = dev_get_drvdata(&ofdev->dev); + struct sja1000_priv *priv = netdev_priv(dev); + struct device_node *np = ofdev->node; + struct resource res; + + dev_set_drvdata(&ofdev->dev, NULL); + + unregister_sja1000dev(dev); + free_sja1000dev(dev); + iounmap(priv->reg_base); + irq_dispose_mapping(dev->irq); + + of_address_to_resource(np, 0, &res); + release_mem_region(res.start, resource_size(&res)); + + return 0; +} + +static int __devinit sja1000_ofp_probe(struct of_device *ofdev, + const struct of_device_id *id) +{ + struct device_node *np = ofdev->node; + struct net_device *dev; + struct sja1000_priv *priv; + struct resource res; + const u32 *prop; + int err, irq, res_size, prop_size; + void __iomem *base; + + err = of_address_to_resource(np, 0, &res); + if (err) { + dev_err(&ofdev->dev, "invalid address\n"); + return err; + } + + res_size = resource_size(&res); + + if (!request_mem_region(res.start, res_size, DRV_NAME)) { + dev_err(&ofdev->dev, "couldn't request %#llx..%#llx\n", + (unsigned long long)res.start, + (unsigned long long)res.end); + return -EBUSY; + } + + base = ioremap_nocache(res.start, res_size); + if (!base) { + dev_err(&ofdev->dev, "couldn't ioremap %#llx..%#llx\n", + (unsigned long long)res.start, + (unsigned long long)res.end); + err = -ENOMEM; + goto exit_release_mem; + } + + irq = irq_of_parse_and_map(np, 0); + if (irq == NO_IRQ) { + dev_err(&ofdev->dev, "no irq found\n"); + err = -ENODEV; + goto exit_unmap_mem; + } + + dev = alloc_sja1000dev(0); + if (!dev) { + err = -ENOMEM; + goto exit_dispose_irq; + } + + priv = netdev_priv(dev); + + priv->read_reg = sja1000_ofp_read_reg; + priv->write_reg = sja1000_ofp_write_reg; + + prop = of_get_property(np, "nxp,external-clock-frequency", &prop_size); + if (prop && (prop_size == sizeof(u32))) + priv->can.clock.freq = *prop / 2; + else + priv->can.clock.freq = SJA1000_OFP_CAN_CLOCK; /* default */ + + prop = of_get_property(np, "nxp,tx-output-mode", &prop_size); + if (prop && (prop_size == sizeof(u32))) + priv->ocr |= *prop & OCR_MODE_MASK; + else + priv->ocr |= OCR_MODE_NORMAL; /* default */ + + prop = of_get_property(np, "nxp,tx-output-config", &prop_size); + if (prop && (prop_size == sizeof(u32))) + priv->ocr |= (*prop << OCR_TX_SHIFT) & OCR_TX_MASK; + else + priv->ocr |= OCR_TX0_PULLDOWN; /* default */ + + prop = of_get_property(np, "nxp,clock-out-frequency", &prop_size); + if (prop && (prop_size == sizeof(u32)) && *prop) { + u32 divider = priv->can.clock.freq * 2 / *prop; + + if (divider > 1) + priv->cdr |= divider / 2 - 1; + else + priv->cdr |= CDR_CLKOUT_MASK; + } else { + priv->cdr |= CDR_CLK_OFF; /* default */ + } + + prop = of_get_property(np, "nxp,no-comparator-bypass", NULL); + if (!prop) + priv->cdr |= CDR_CBP; /* default */ + + priv->irq_flags = IRQF_SHARED; + priv->reg_base = base; + + dev->irq = irq; + + dev_info(&ofdev->dev, + "reg_base=0x%p irq=%d clock=%d ocr=0x%02x cdr=0x%02x\n", + priv->reg_base, dev->irq, priv->can.clock.freq, + priv->ocr, priv->cdr); + + dev_set_drvdata(&ofdev->dev, dev); + SET_NETDEV_DEV(dev, &ofdev->dev); + + err = register_sja1000dev(dev); + if (err) { + dev_err(&ofdev->dev, "registering %s failed (err=%d)\n", + DRV_NAME, err); + goto exit_free_sja1000; + } + + return 0; + +exit_free_sja1000: + free_sja1000dev(dev); +exit_dispose_irq: + irq_dispose_mapping(irq); +exit_unmap_mem: + iounmap(base); +exit_release_mem: + release_mem_region(res.start, res_size); + + return err; +} + +static struct of_device_id __devinitdata sja1000_ofp_table[] = { + {.compatible = "nxp,sja1000"}, + {}, +}; + +static struct of_platform_driver sja1000_ofp_driver = { + .owner = THIS_MODULE, + .name = DRV_NAME, + .probe = sja1000_ofp_probe, + .remove = __devexit_p(sja1000_ofp_remove), + .match_table = sja1000_ofp_table, +}; + +static int __init sja1000_ofp_init(void) +{ + return of_register_platform_driver(&sja1000_ofp_driver); +} +module_init(sja1000_ofp_init); + +static void __exit sja1000_ofp_exit(void) +{ + return of_unregister_platform_driver(&sja1000_ofp_driver); +}; +module_exit(sja1000_ofp_exit); diff --git a/drivers/net/can/sja1000/sja1000_platform.c b/drivers/net/can/sja1000/sja1000_platform.c new file mode 100644 index 000000000000..628374c2a05f --- /dev/null +++ b/drivers/net/can/sja1000/sja1000_platform.c @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2005 Sascha Hauer, Pengutronix + * Copyright (C) 2007 Wolfgang Grandegger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the version 2 of the GNU General Public License + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sja1000.h" + +#define DRV_NAME "sja1000_platform" + +MODULE_AUTHOR("Sascha Hauer "); +MODULE_DESCRIPTION("Socket-CAN driver for SJA1000 on the platform bus"); +MODULE_LICENSE("GPL v2"); + +static u8 sp_read_reg(const struct sja1000_priv *priv, int reg) +{ + return ioread8(priv->reg_base + reg); +} + +static void sp_write_reg(const struct sja1000_priv *priv, int reg, u8 val) +{ + iowrite8(val, priv->reg_base + reg); +} + +static int sp_probe(struct platform_device *pdev) +{ + int err; + void __iomem *addr; + struct net_device *dev; + struct sja1000_priv *priv; + struct resource *res_mem, *res_irq; + struct sja1000_platform_data *pdata; + + pdata = pdev->dev.platform_data; + if (!pdata) { + dev_err(&pdev->dev, "No platform data provided!\n"); + err = -ENODEV; + goto exit; + } + + res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res_mem || !res_irq) { + err = -ENODEV; + goto exit; + } + + if (!request_mem_region(res_mem->start, resource_size(res_mem), + DRV_NAME)) { + err = -EBUSY; + goto exit; + } + + addr = ioremap_nocache(res_mem->start, resource_size(res_mem)); + if (!addr) { + err = -ENOMEM; + goto exit_release; + } + + dev = alloc_sja1000dev(0); + if (!dev) { + err = -ENOMEM; + goto exit_iounmap; + } + priv = netdev_priv(dev); + + dev->irq = res_irq->start; + priv->irq_flags = res_irq->flags & IRQF_TRIGGER_MASK; + priv->reg_base = addr; + priv->read_reg = sp_read_reg; + priv->write_reg = sp_write_reg; + priv->can.clock.freq = pdata->clock; + priv->ocr = pdata->ocr; + priv->cdr = pdata->cdr; + + dev_set_drvdata(&pdev->dev, dev); + SET_NETDEV_DEV(dev, &pdev->dev); + + err = register_sja1000dev(dev); + if (err) { + dev_err(&pdev->dev, "registering %s failed (err=%d)\n", + DRV_NAME, err); + goto exit_free; + } + + dev_info(&pdev->dev, "%s device registered (reg_base=%p, irq=%d)\n", + DRV_NAME, priv->reg_base, dev->irq); + return 0; + + exit_free: + free_sja1000dev(dev); + exit_iounmap: + iounmap(addr); + exit_release: + release_mem_region(res_mem->start, resource_size(res_mem)); + exit: + return err; +} + +static int sp_remove(struct platform_device *pdev) +{ + struct net_device *dev = dev_get_drvdata(&pdev->dev); + struct sja1000_priv *priv = netdev_priv(dev); + struct resource *res; + + unregister_sja1000dev(dev); + dev_set_drvdata(&pdev->dev, NULL); + + if (priv->reg_base) + iounmap(priv->reg_base); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(res->start, resource_size(res)); + + free_sja1000dev(dev); + + return 0; +} + +static struct platform_driver sp_driver = { + .probe = sp_probe, + .remove = sp_remove, + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init sp_init(void) +{ + return platform_driver_register(&sp_driver); +} + +static void __exit sp_exit(void) +{ + platform_driver_unregister(&sp_driver); +} + +module_init(sp_init); +module_exit(sp_exit); diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c index f5222764061c..eb066673c2a0 100644 --- a/drivers/net/cassini.c +++ b/drivers/net/cassini.c @@ -2934,7 +2934,7 @@ static int cas_start_xmit(struct sk_buff *skb, struct net_device *dev) * individual queues. */ if (cas_xmit_tx_ringN(cp, ring++ & N_TX_RINGS_MASK, skb)) - return 1; + return NETDEV_TX_BUSY; dev->trans_start = jiffies; return 0; } diff --git a/drivers/net/chelsio/common.h b/drivers/net/chelsio/common.h index 4bd2455b0fe3..699d22c5fe09 100644 --- a/drivers/net/chelsio/common.h +++ b/drivers/net/chelsio/common.h @@ -46,7 +46,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/net/chelsio/cphy.h b/drivers/net/chelsio/cphy.h index 79d855e267e0..1f095a9fc739 100644 --- a/drivers/net/chelsio/cphy.h +++ b/drivers/net/chelsio/cphy.h @@ -43,10 +43,11 @@ struct mdio_ops { void (*init)(adapter_t *adapter, const struct board_info *bi); - int (*read)(adapter_t *adapter, int phy_addr, int mmd_addr, - int reg_addr, unsigned int *val); - int (*write)(adapter_t *adapter, int phy_addr, int mmd_addr, - int reg_addr, unsigned int val); + int (*read)(struct net_device *dev, int phy_addr, int mmd_addr, + u16 reg_addr); + int (*write)(struct net_device *dev, int phy_addr, int mmd_addr, + u16 reg_addr, u16 val); + unsigned mode_support; }; /* PHY interrupt types */ @@ -83,11 +84,12 @@ struct cphy_ops { int (*set_speed_duplex)(struct cphy *phy, int speed, int duplex); int (*get_link_status)(struct cphy *phy, int *link_ok, int *speed, int *duplex, int *fc); + + u32 mmds; }; /* A PHY instance */ struct cphy { - int addr; /* PHY address */ int state; /* Link status state machine */ adapter_t *adapter; /* associated adapter */ @@ -101,56 +103,61 @@ struct cphy { u32 elmer_gpo; const struct cphy_ops *ops; /* PHY operations */ - int (*mdio_read)(adapter_t *adapter, int phy_addr, int mmd_addr, - int reg_addr, unsigned int *val); - int (*mdio_write)(adapter_t *adapter, int phy_addr, int mmd_addr, - int reg_addr, unsigned int val); + struct mdio_if_info mdio; struct cphy_instance *instance; }; /* Convenience MDIO read/write wrappers */ -static inline int mdio_read(struct cphy *cphy, int mmd, int reg, - unsigned int *valp) +static inline int cphy_mdio_read(struct cphy *cphy, int mmd, int reg, + unsigned int *valp) { - return cphy->mdio_read(cphy->adapter, cphy->addr, mmd, reg, valp); + int rc = cphy->mdio.mdio_read(cphy->mdio.dev, cphy->mdio.prtad, mmd, + reg); + *valp = (rc >= 0) ? rc : -1; + return (rc >= 0) ? 0 : rc; } -static inline int mdio_write(struct cphy *cphy, int mmd, int reg, - unsigned int val) +static inline int cphy_mdio_write(struct cphy *cphy, int mmd, int reg, + unsigned int val) { - return cphy->mdio_write(cphy->adapter, cphy->addr, mmd, reg, val); + return cphy->mdio.mdio_write(cphy->mdio.dev, cphy->mdio.prtad, mmd, + reg, val); } static inline int simple_mdio_read(struct cphy *cphy, int reg, unsigned int *valp) { - return mdio_read(cphy, 0, reg, valp); + return cphy_mdio_read(cphy, MDIO_DEVAD_NONE, reg, valp); } static inline int simple_mdio_write(struct cphy *cphy, int reg, unsigned int val) { - return mdio_write(cphy, 0, reg, val); + return cphy_mdio_write(cphy, MDIO_DEVAD_NONE, reg, val); } /* Convenience initializer */ -static inline void cphy_init(struct cphy *phy, adapter_t *adapter, +static inline void cphy_init(struct cphy *phy, struct net_device *dev, int phy_addr, struct cphy_ops *phy_ops, const struct mdio_ops *mdio_ops) { + struct adapter *adapter = netdev_priv(dev); phy->adapter = adapter; - phy->addr = phy_addr; phy->ops = phy_ops; if (mdio_ops) { - phy->mdio_read = mdio_ops->read; - phy->mdio_write = mdio_ops->write; + phy->mdio.prtad = phy_addr; + phy->mdio.mmds = phy_ops->mmds; + phy->mdio.mode_support = mdio_ops->mode_support; + phy->mdio.mdio_read = mdio_ops->read; + phy->mdio.mdio_write = mdio_ops->write; } + phy->mdio.dev = dev; } /* Operations of the PHY-instance factory */ struct gphy { /* Construct a PHY instance with the given PHY address */ - struct cphy *(*create)(adapter_t *adapter, int phy_addr, + struct cphy *(*create)(struct net_device *dev, int phy_addr, const struct mdio_ops *mdio_ops); /* diff --git a/drivers/net/chelsio/cxgb2.c b/drivers/net/chelsio/cxgb2.c index fa06994f9737..082cdb28b510 100644 --- a/drivers/net/chelsio/cxgb2.c +++ b/drivers/net/chelsio/cxgb2.c @@ -589,7 +589,7 @@ static int get_settings(struct net_device *dev, struct ethtool_cmd *cmd) } cmd->port = (cmd->supported & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE; - cmd->phy_address = p->phy->addr; + cmd->phy_address = p->phy->mdio.prtad; cmd->transceiver = XCVR_EXTERNAL; cmd->autoneg = p->link_config.autoneg; cmd->maxtxpkt = 0; @@ -849,39 +849,9 @@ static const struct ethtool_ops t1_ethtool_ops = { static int t1_ioctl(struct net_device *dev, struct ifreq *req, int cmd) { struct adapter *adapter = dev->ml_priv; - struct mii_ioctl_data *data = if_mii(req); + struct mdio_if_info *mdio = &adapter->port[dev->if_port].phy->mdio; - switch (cmd) { - case SIOCGMIIPHY: - data->phy_id = adapter->port[dev->if_port].phy->addr; - /* FALLTHRU */ - case SIOCGMIIREG: { - struct cphy *phy = adapter->port[dev->if_port].phy; - u32 val; - - if (!phy->mdio_read) - return -EOPNOTSUPP; - phy->mdio_read(adapter, data->phy_id, 0, data->reg_num & 0x1f, - &val); - data->val_out = val; - break; - } - case SIOCSMIIREG: { - struct cphy *phy = adapter->port[dev->if_port].phy; - - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - if (!phy->mdio_write) - return -EOPNOTSUPP; - phy->mdio_write(adapter, data->phy_id, 0, data->reg_num & 0x1f, - data->val_in); - break; - } - - default: - return -EOPNOTSUPP; - } - return 0; + return mdio_mii_ioctl(mdio, if_mii(req), cmd); } static int t1_change_mtu(struct net_device *dev, int new_mtu) diff --git a/drivers/net/chelsio/mv88e1xxx.c b/drivers/net/chelsio/mv88e1xxx.c index 0632be0d6494..809047a99e96 100644 --- a/drivers/net/chelsio/mv88e1xxx.c +++ b/drivers/net/chelsio/mv88e1xxx.c @@ -353,15 +353,16 @@ static struct cphy_ops mv88e1xxx_ops = { .get_link_status = mv88e1xxx_get_link_status, }; -static struct cphy *mv88e1xxx_phy_create(adapter_t *adapter, int phy_addr, +static struct cphy *mv88e1xxx_phy_create(struct net_device *dev, int phy_addr, const struct mdio_ops *mdio_ops) { + struct adapter *adapter = netdev_priv(dev); struct cphy *cphy = kzalloc(sizeof(*cphy), GFP_KERNEL); if (!cphy) return NULL; - cphy_init(cphy, adapter, phy_addr, &mv88e1xxx_ops, mdio_ops); + cphy_init(cphy, dev, phy_addr, &mv88e1xxx_ops, mdio_ops); /* Configure particular PHY's to run in a different mode. */ if ((board_info(adapter)->caps & SUPPORTED_TP) && diff --git a/drivers/net/chelsio/mv88x201x.c b/drivers/net/chelsio/mv88x201x.c index cd856041af34..f7136b2fd1e5 100644 --- a/drivers/net/chelsio/mv88x201x.c +++ b/drivers/net/chelsio/mv88x201x.c @@ -53,7 +53,7 @@ static int led_init(struct cphy *cphy) * Writing these bits maps control to another * register. mmd(0x1) addr(0x7) */ - mdio_write(cphy, 0x3, 0x8304, 0xdddd); + cphy_mdio_write(cphy, MDIO_MMD_PCS, 0x8304, 0xdddd); return 0; } @@ -62,14 +62,14 @@ static int led_link(struct cphy *cphy, u32 do_enable) u32 led = 0; #define LINK_ENABLE_BIT 0x1 - mdio_read(cphy, 0x1, 0x7, &led); + cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_CTRL2, &led); if (do_enable & LINK_ENABLE_BIT) { led |= LINK_ENABLE_BIT; - mdio_write(cphy, 0x1, 0x7, led); + cphy_mdio_write(cphy, MDIO_MMD_PMAPMD, MDIO_CTRL2, led); } else { led &= ~LINK_ENABLE_BIT; - mdio_write(cphy, 0x1, 0x7, led); + cphy_mdio_write(cphy, MDIO_MMD_PMAPMD, MDIO_CTRL2, led); } return 0; } @@ -86,7 +86,8 @@ static int mv88x201x_reset(struct cphy *cphy, int wait) static int mv88x201x_interrupt_enable(struct cphy *cphy) { /* Enable PHY LASI interrupts. */ - mdio_write(cphy, 0x1, 0x9002, 0x1); + cphy_mdio_write(cphy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_CTRL, + MDIO_PMA_LASI_LSALARM); /* Enable Marvell interrupts through Elmer0. */ if (t1_is_asic(cphy->adapter)) { @@ -102,7 +103,7 @@ static int mv88x201x_interrupt_enable(struct cphy *cphy) static int mv88x201x_interrupt_disable(struct cphy *cphy) { /* Disable PHY LASI interrupts. */ - mdio_write(cphy, 0x1, 0x9002, 0x0); + cphy_mdio_write(cphy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_CTRL, 0x0); /* Disable Marvell interrupts through Elmer0. */ if (t1_is_asic(cphy->adapter)) { @@ -122,25 +123,25 @@ static int mv88x201x_interrupt_clear(struct cphy *cphy) #ifdef MV88x2010_LINK_STATUS_BUGS /* Required to read twice before clear takes affect. */ - mdio_read(cphy, 0x1, 0x9003, &val); - mdio_read(cphy, 0x1, 0x9004, &val); - mdio_read(cphy, 0x1, 0x9005, &val); + cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_RXSTAT, &val); + cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_TXSTAT, &val); + cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_STAT, &val); /* Read this register after the others above it else * the register doesn't clear correctly. */ - mdio_read(cphy, 0x1, 0x1, &val); + cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_STAT1, &val); #endif /* Clear link status. */ - mdio_read(cphy, 0x1, 0x1, &val); + cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_STAT1, &val); /* Clear PHY LASI interrupts. */ - mdio_read(cphy, 0x1, 0x9005, &val); + cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_STAT, &val); #ifdef MV88x2010_LINK_STATUS_BUGS /* Do it again. */ - mdio_read(cphy, 0x1, 0x9003, &val); - mdio_read(cphy, 0x1, 0x9004, &val); + cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_RXSTAT, &val); + cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_TXSTAT, &val); #endif /* Clear Marvell interrupts through Elmer0. */ @@ -172,13 +173,12 @@ static int mv88x201x_get_link_status(struct cphy *cphy, int *link_ok, int *speed, int *duplex, int *fc) { u32 val = 0; -#define LINK_STATUS_BIT 0x4 if (link_ok) { /* Read link status. */ - mdio_read(cphy, 0x1, 0x1, &val); - val &= LINK_STATUS_BIT; - *link_ok = (val == LINK_STATUS_BIT); + cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_STAT1, &val); + val &= MDIO_STAT1_LSTATUS; + *link_ok = (val == MDIO_STAT1_LSTATUS); /* Turn on/off Link LED */ led_link(cphy, *link_ok); } @@ -205,9 +205,11 @@ static struct cphy_ops mv88x201x_ops = { .interrupt_handler = mv88x201x_interrupt_handler, .get_link_status = mv88x201x_get_link_status, .set_loopback = mv88x201x_set_loopback, + .mmds = (MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | + MDIO_DEVS_PHYXS | MDIO_DEVS_WIS), }; -static struct cphy *mv88x201x_phy_create(adapter_t *adapter, int phy_addr, +static struct cphy *mv88x201x_phy_create(struct net_device *dev, int phy_addr, const struct mdio_ops *mdio_ops) { u32 val; @@ -216,15 +218,15 @@ static struct cphy *mv88x201x_phy_create(adapter_t *adapter, int phy_addr, if (!cphy) return NULL; - cphy_init(cphy, adapter, phy_addr, &mv88x201x_ops, mdio_ops); + cphy_init(cphy, dev, phy_addr, &mv88x201x_ops, mdio_ops); /* Commands the PHY to enable XFP's clock. */ - mdio_read(cphy, 0x3, 0x8300, &val); - mdio_write(cphy, 0x3, 0x8300, val | 1); + cphy_mdio_read(cphy, MDIO_MMD_PCS, 0x8300, &val); + cphy_mdio_write(cphy, MDIO_MMD_PCS, 0x8300, val | 1); /* Clear link status. Required because of a bug in the PHY. */ - mdio_read(cphy, 0x1, 0x8, &val); - mdio_read(cphy, 0x3, 0x8, &val); + cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_STAT2, &val); + cphy_mdio_read(cphy, MDIO_MMD_PCS, MDIO_STAT2, &val); /* Allows for Link,Ack LED turn on/off */ led_init(cphy); diff --git a/drivers/net/chelsio/my3126.c b/drivers/net/chelsio/my3126.c index 040acd29995a..4c6028512d10 100644 --- a/drivers/net/chelsio/my3126.c +++ b/drivers/net/chelsio/my3126.c @@ -43,11 +43,11 @@ static int my3126_interrupt_handler(struct cphy *cphy) adapter = cphy->adapter; if (cphy->count == 50) { - mdio_read(cphy, 0x1, 0x1, &val); + cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_STAT1, &val); val16 = (u16) val; status = cphy->bmsr ^ val16; - if (status & BMSR_LSTATUS) + if (status & MDIO_STAT1_LSTATUS) t1_link_changed(adapter, 0); cphy->bmsr = val16; @@ -114,14 +114,14 @@ static int my3126_get_link_status(struct cphy *cphy, adapter_t *adapter; adapter = cphy->adapter; - mdio_read(cphy, 0x1, 0x1, &val); + cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_STAT1, &val); val16 = (u16) val; /* Populate elmer_gpo with the register value */ t1_tpi_read(adapter, A_ELMER0_GPO, &val); cphy->elmer_gpo = val; - *link_ok = (val16 & BMSR_LSTATUS); + *link_ok = (val16 & MDIO_STAT1_LSTATUS); if (*link_ok) { /* Turn on the LED. */ @@ -163,9 +163,11 @@ static struct cphy_ops my3126_ops = { .interrupt_handler = my3126_interrupt_handler, .get_link_status = my3126_get_link_status, .set_loopback = my3126_set_loopback, + .mmds = (MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | + MDIO_DEVS_PHYXS), }; -static struct cphy *my3126_phy_create(adapter_t *adapter, +static struct cphy *my3126_phy_create(struct net_device *dev, int phy_addr, const struct mdio_ops *mdio_ops) { struct cphy *cphy = kzalloc(sizeof (*cphy), GFP_KERNEL); @@ -173,7 +175,7 @@ static struct cphy *my3126_phy_create(adapter_t *adapter, if (!cphy) return NULL; - cphy_init(cphy, adapter, phy_addr, &my3126_ops, mdio_ops); + cphy_init(cphy, dev, phy_addr, &my3126_ops, mdio_ops); INIT_DELAYED_WORK(&cphy->phy_update, my3216_poll); cphy->bmsr = 0; diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c index 58f6fc055f6a..3711d64e45ef 100644 --- a/drivers/net/chelsio/sge.c +++ b/drivers/net/chelsio/sge.c @@ -1149,8 +1149,8 @@ static inline void write_tx_desc(struct cmdQ_e *e, dma_addr_t mapping, unsigned int len, unsigned int gen, unsigned int eop) { - if (unlikely(len > SGE_TX_DESC_MAX_PLEN)) - BUG(); + BUG_ON(len > SGE_TX_DESC_MAX_PLEN); + e->addr_lo = (u32)mapping; e->addr_hi = (u64)mapping >> 32; e->len_gen = V_CMD_LEN(len) | V_CMD_GEN1(gen); @@ -1879,7 +1879,6 @@ int t1_start_xmit(struct sk_buff *skb, struct net_device *dev) cpl->vlan_valid = 0; send: - dev->trans_start = jiffies; ret = t1_sge_tx(skb, adapter, 0, dev); /* If transmit busy, and we reallocated skb's due to headroom limit, diff --git a/drivers/net/chelsio/subr.c b/drivers/net/chelsio/subr.c index 7adf30230c4f..17720c6e5bfe 100644 --- a/drivers/net/chelsio/subr.c +++ b/drivers/net/chelsio/subr.c @@ -284,32 +284,29 @@ static void mi1_mdio_init(adapter_t *adapter, const struct board_info *bi) /* * Elmer MI1 MDIO read/write operations. */ -static int mi1_mdio_read(adapter_t *adapter, int phy_addr, int mmd_addr, - int reg_addr, unsigned int *valp) +static int mi1_mdio_read(struct net_device *dev, int phy_addr, int mmd_addr, + u16 reg_addr) { + struct adapter *adapter = dev->ml_priv; u32 addr = V_MI1_REG_ADDR(reg_addr) | V_MI1_PHY_ADDR(phy_addr); - - if (mmd_addr) - return -EINVAL; + unsigned int val; spin_lock(&adapter->tpi_lock); __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_ADDR, addr); __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_OP, MI1_OP_DIRECT_READ); mi1_wait_until_ready(adapter, A_ELMER0_PORT0_MI1_OP); - __t1_tpi_read(adapter, A_ELMER0_PORT0_MI1_DATA, valp); + __t1_tpi_read(adapter, A_ELMER0_PORT0_MI1_DATA, &val); spin_unlock(&adapter->tpi_lock); - return 0; + return val; } -static int mi1_mdio_write(adapter_t *adapter, int phy_addr, int mmd_addr, - int reg_addr, unsigned int val) +static int mi1_mdio_write(struct net_device *dev, int phy_addr, int mmd_addr, + u16 reg_addr, u16 val) { + struct adapter *adapter = dev->ml_priv; u32 addr = V_MI1_REG_ADDR(reg_addr) | V_MI1_PHY_ADDR(phy_addr); - if (mmd_addr) - return -EINVAL; - spin_lock(&adapter->tpi_lock); __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_ADDR, addr); __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_DATA, val); @@ -324,16 +321,19 @@ static int mi1_mdio_write(adapter_t *adapter, int phy_addr, int mmd_addr, static const struct mdio_ops mi1_mdio_ops = { .init = mi1_mdio_init, .read = mi1_mdio_read, - .write = mi1_mdio_write + .write = mi1_mdio_write, + .mode_support = MDIO_SUPPORTS_C22 }; #endif #endif -static int mi1_mdio_ext_read(adapter_t *adapter, int phy_addr, int mmd_addr, - int reg_addr, unsigned int *valp) +static int mi1_mdio_ext_read(struct net_device *dev, int phy_addr, int mmd_addr, + u16 reg_addr) { + struct adapter *adapter = dev->ml_priv; u32 addr = V_MI1_REG_ADDR(mmd_addr) | V_MI1_PHY_ADDR(phy_addr); + unsigned int val; spin_lock(&adapter->tpi_lock); @@ -350,14 +350,15 @@ static int mi1_mdio_ext_read(adapter_t *adapter, int phy_addr, int mmd_addr, mi1_wait_until_ready(adapter, A_ELMER0_PORT0_MI1_OP); /* Read the data. */ - __t1_tpi_read(adapter, A_ELMER0_PORT0_MI1_DATA, valp); + __t1_tpi_read(adapter, A_ELMER0_PORT0_MI1_DATA, &val); spin_unlock(&adapter->tpi_lock); - return 0; + return val; } -static int mi1_mdio_ext_write(adapter_t *adapter, int phy_addr, int mmd_addr, - int reg_addr, unsigned int val) +static int mi1_mdio_ext_write(struct net_device *dev, int phy_addr, + int mmd_addr, u16 reg_addr, u16 val) { + struct adapter *adapter = dev->ml_priv; u32 addr = V_MI1_REG_ADDR(mmd_addr) | V_MI1_PHY_ADDR(phy_addr); spin_lock(&adapter->tpi_lock); @@ -380,7 +381,8 @@ static int mi1_mdio_ext_write(adapter_t *adapter, int phy_addr, int mmd_addr, static const struct mdio_ops mi1_mdio_ext_ops = { .init = mi1_mdio_init, .read = mi1_mdio_ext_read, - .write = mi1_mdio_ext_write + .write = mi1_mdio_ext_write, + .mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22 }; enum { @@ -1133,8 +1135,8 @@ int __devinit t1_init_sw_modules(adapter_t *adapter, struct cmac *mac; int phy_addr = bi->mdio_phybaseaddr + i; - adapter->port[i].phy = bi->gphy->create(adapter, phy_addr, - bi->mdio_ops); + adapter->port[i].phy = bi->gphy->create(adapter->port[i].dev, + phy_addr, bi->mdio_ops); if (!adapter->port[i].phy) { CH_ERR("%s: PHY %d initialization failed\n", adapter->name, i); diff --git a/drivers/net/cnic.c b/drivers/net/cnic.c new file mode 100644 index 000000000000..4d1515f45ba2 --- /dev/null +++ b/drivers/net/cnic.c @@ -0,0 +1,2715 @@ +/* cnic.c: Broadcom CNIC core network driver. + * + * Copyright (c) 2006-2009 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation. + * + * Original skeleton written by: John(Zongxi) Chen (zongxi@broadcom.com) + * Modified and maintained by: Michael Chan + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) +#define BCM_VLAN 1 +#endif +#include +#include +#include +#include +#include +#include + +#include "cnic_if.h" +#include "bnx2.h" +#include "cnic.h" +#include "cnic_defs.h" + +#define DRV_MODULE_NAME "cnic" +#define PFX DRV_MODULE_NAME ": " + +static char version[] __devinitdata = + "Broadcom NetXtreme II CNIC Driver " DRV_MODULE_NAME " v" CNIC_MODULE_VERSION " (" CNIC_MODULE_RELDATE ")\n"; + +MODULE_AUTHOR("Michael Chan and John(Zongxi) " + "Chen (zongxi@broadcom.com"); +MODULE_DESCRIPTION("Broadcom NetXtreme II CNIC Driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(CNIC_MODULE_VERSION); + +static LIST_HEAD(cnic_dev_list); +static DEFINE_RWLOCK(cnic_dev_lock); +static DEFINE_MUTEX(cnic_lock); + +static struct cnic_ulp_ops *cnic_ulp_tbl[MAX_CNIC_ULP_TYPE]; + +static int cnic_service_bnx2(void *, void *); +static int cnic_ctl(void *, struct cnic_ctl_info *); + +static struct cnic_ops cnic_bnx2_ops = { + .cnic_owner = THIS_MODULE, + .cnic_handler = cnic_service_bnx2, + .cnic_ctl = cnic_ctl, +}; + +static void cnic_shutdown_bnx2_rx_ring(struct cnic_dev *); +static void cnic_init_bnx2_tx_ring(struct cnic_dev *); +static void cnic_init_bnx2_rx_ring(struct cnic_dev *); +static int cnic_cm_set_pg(struct cnic_sock *); + +static int cnic_uio_open(struct uio_info *uinfo, struct inode *inode) +{ + struct cnic_dev *dev = uinfo->priv; + struct cnic_local *cp = dev->cnic_priv; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + if (cp->uio_dev != -1) + return -EBUSY; + + cp->uio_dev = iminor(inode); + + cnic_shutdown_bnx2_rx_ring(dev); + + cnic_init_bnx2_tx_ring(dev); + cnic_init_bnx2_rx_ring(dev); + + return 0; +} + +static int cnic_uio_close(struct uio_info *uinfo, struct inode *inode) +{ + struct cnic_dev *dev = uinfo->priv; + struct cnic_local *cp = dev->cnic_priv; + + cp->uio_dev = -1; + return 0; +} + +static inline void cnic_hold(struct cnic_dev *dev) +{ + atomic_inc(&dev->ref_count); +} + +static inline void cnic_put(struct cnic_dev *dev) +{ + atomic_dec(&dev->ref_count); +} + +static inline void csk_hold(struct cnic_sock *csk) +{ + atomic_inc(&csk->ref_count); +} + +static inline void csk_put(struct cnic_sock *csk) +{ + atomic_dec(&csk->ref_count); +} + +static struct cnic_dev *cnic_from_netdev(struct net_device *netdev) +{ + struct cnic_dev *cdev; + + read_lock(&cnic_dev_lock); + list_for_each_entry(cdev, &cnic_dev_list, list) { + if (netdev == cdev->netdev) { + cnic_hold(cdev); + read_unlock(&cnic_dev_lock); + return cdev; + } + } + read_unlock(&cnic_dev_lock); + return NULL; +} + +static void cnic_ctx_wr(struct cnic_dev *dev, u32 cid_addr, u32 off, u32 val) +{ + struct cnic_local *cp = dev->cnic_priv; + struct cnic_eth_dev *ethdev = cp->ethdev; + struct drv_ctl_info info; + struct drv_ctl_io *io = &info.data.io; + + info.cmd = DRV_CTL_CTX_WR_CMD; + io->cid_addr = cid_addr; + io->offset = off; + io->data = val; + ethdev->drv_ctl(dev->netdev, &info); +} + +static void cnic_reg_wr_ind(struct cnic_dev *dev, u32 off, u32 val) +{ + struct cnic_local *cp = dev->cnic_priv; + struct cnic_eth_dev *ethdev = cp->ethdev; + struct drv_ctl_info info; + struct drv_ctl_io *io = &info.data.io; + + info.cmd = DRV_CTL_IO_WR_CMD; + io->offset = off; + io->data = val; + ethdev->drv_ctl(dev->netdev, &info); +} + +static u32 cnic_reg_rd_ind(struct cnic_dev *dev, u32 off) +{ + struct cnic_local *cp = dev->cnic_priv; + struct cnic_eth_dev *ethdev = cp->ethdev; + struct drv_ctl_info info; + struct drv_ctl_io *io = &info.data.io; + + info.cmd = DRV_CTL_IO_RD_CMD; + io->offset = off; + ethdev->drv_ctl(dev->netdev, &info); + return io->data; +} + +static int cnic_in_use(struct cnic_sock *csk) +{ + return test_bit(SK_F_INUSE, &csk->flags); +} + +static void cnic_kwq_completion(struct cnic_dev *dev, u32 count) +{ + struct cnic_local *cp = dev->cnic_priv; + struct cnic_eth_dev *ethdev = cp->ethdev; + struct drv_ctl_info info; + + info.cmd = DRV_CTL_COMPLETION_CMD; + info.data.comp.comp_count = count; + ethdev->drv_ctl(dev->netdev, &info); +} + +static int cnic_send_nlmsg(struct cnic_local *cp, u32 type, + struct cnic_sock *csk) +{ + struct iscsi_path path_req; + char *buf = NULL; + u16 len = 0; + u32 msg_type = ISCSI_KEVENT_IF_DOWN; + struct cnic_ulp_ops *ulp_ops; + + if (cp->uio_dev == -1) + return -ENODEV; + + if (csk) { + len = sizeof(path_req); + buf = (char *) &path_req; + memset(&path_req, 0, len); + + msg_type = ISCSI_KEVENT_PATH_REQ; + path_req.handle = (u64) csk->l5_cid; + if (test_bit(SK_F_IPV6, &csk->flags)) { + memcpy(&path_req.dst.v6_addr, &csk->dst_ip[0], + sizeof(struct in6_addr)); + path_req.ip_addr_len = 16; + } else { + memcpy(&path_req.dst.v4_addr, &csk->dst_ip[0], + sizeof(struct in_addr)); + path_req.ip_addr_len = 4; + } + path_req.vlan_id = csk->vlan_id; + path_req.pmtu = csk->mtu; + } + + rcu_read_lock(); + ulp_ops = rcu_dereference(cp->ulp_ops[CNIC_ULP_ISCSI]); + if (ulp_ops) + ulp_ops->iscsi_nl_send_msg(cp->dev, msg_type, buf, len); + rcu_read_unlock(); + return 0; +} + +static int cnic_iscsi_nl_msg_recv(struct cnic_dev *dev, u32 msg_type, + char *buf, u16 len) +{ + int rc = -EINVAL; + + switch (msg_type) { + case ISCSI_UEVENT_PATH_UPDATE: { + struct cnic_local *cp; + u32 l5_cid; + struct cnic_sock *csk; + struct iscsi_path *path_resp; + + if (len < sizeof(*path_resp)) + break; + + path_resp = (struct iscsi_path *) buf; + cp = dev->cnic_priv; + l5_cid = (u32) path_resp->handle; + if (l5_cid >= MAX_CM_SK_TBL_SZ) + break; + + csk = &cp->csk_tbl[l5_cid]; + csk_hold(csk); + if (cnic_in_use(csk)) { + memcpy(csk->ha, path_resp->mac_addr, 6); + if (test_bit(SK_F_IPV6, &csk->flags)) + memcpy(&csk->src_ip[0], &path_resp->src.v6_addr, + sizeof(struct in6_addr)); + else + memcpy(&csk->src_ip[0], &path_resp->src.v4_addr, + sizeof(struct in_addr)); + if (is_valid_ether_addr(csk->ha)) + cnic_cm_set_pg(csk); + } + csk_put(csk); + rc = 0; + } + } + + return rc; +} + +static int cnic_offld_prep(struct cnic_sock *csk) +{ + if (test_and_set_bit(SK_F_OFFLD_SCHED, &csk->flags)) + return 0; + + if (!test_bit(SK_F_CONNECT_START, &csk->flags)) { + clear_bit(SK_F_OFFLD_SCHED, &csk->flags); + return 0; + } + + return 1; +} + +static int cnic_close_prep(struct cnic_sock *csk) +{ + clear_bit(SK_F_CONNECT_START, &csk->flags); + smp_mb__after_clear_bit(); + + if (test_and_clear_bit(SK_F_OFFLD_COMPLETE, &csk->flags)) { + while (test_and_set_bit(SK_F_OFFLD_SCHED, &csk->flags)) + msleep(1); + + return 1; + } + return 0; +} + +static int cnic_abort_prep(struct cnic_sock *csk) +{ + clear_bit(SK_F_CONNECT_START, &csk->flags); + smp_mb__after_clear_bit(); + + while (test_and_set_bit(SK_F_OFFLD_SCHED, &csk->flags)) + msleep(1); + + if (test_and_clear_bit(SK_F_OFFLD_COMPLETE, &csk->flags)) { + csk->state = L4_KCQE_OPCODE_VALUE_RESET_COMP; + return 1; + } + + return 0; +} + +int cnic_register_driver(int ulp_type, struct cnic_ulp_ops *ulp_ops) +{ + struct cnic_dev *dev; + + if (ulp_type >= MAX_CNIC_ULP_TYPE) { + printk(KERN_ERR PFX "cnic_register_driver: Bad type %d\n", + ulp_type); + return -EINVAL; + } + mutex_lock(&cnic_lock); + if (cnic_ulp_tbl[ulp_type]) { + printk(KERN_ERR PFX "cnic_register_driver: Type %d has already " + "been registered\n", ulp_type); + mutex_unlock(&cnic_lock); + return -EBUSY; + } + + read_lock(&cnic_dev_lock); + list_for_each_entry(dev, &cnic_dev_list, list) { + struct cnic_local *cp = dev->cnic_priv; + + clear_bit(ULP_F_INIT, &cp->ulp_flags[ulp_type]); + } + read_unlock(&cnic_dev_lock); + + rcu_assign_pointer(cnic_ulp_tbl[ulp_type], ulp_ops); + mutex_unlock(&cnic_lock); + + /* Prevent race conditions with netdev_event */ + rtnl_lock(); + read_lock(&cnic_dev_lock); + list_for_each_entry(dev, &cnic_dev_list, list) { + struct cnic_local *cp = dev->cnic_priv; + + if (!test_and_set_bit(ULP_F_INIT, &cp->ulp_flags[ulp_type])) + ulp_ops->cnic_init(dev); + } + read_unlock(&cnic_dev_lock); + rtnl_unlock(); + + return 0; +} + +int cnic_unregister_driver(int ulp_type) +{ + struct cnic_dev *dev; + + if (ulp_type >= MAX_CNIC_ULP_TYPE) { + printk(KERN_ERR PFX "cnic_unregister_driver: Bad type %d\n", + ulp_type); + return -EINVAL; + } + mutex_lock(&cnic_lock); + if (!cnic_ulp_tbl[ulp_type]) { + printk(KERN_ERR PFX "cnic_unregister_driver: Type %d has not " + "been registered\n", ulp_type); + goto out_unlock; + } + read_lock(&cnic_dev_lock); + list_for_each_entry(dev, &cnic_dev_list, list) { + struct cnic_local *cp = dev->cnic_priv; + + if (rcu_dereference(cp->ulp_ops[ulp_type])) { + printk(KERN_ERR PFX "cnic_unregister_driver: Type %d " + "still has devices registered\n", ulp_type); + read_unlock(&cnic_dev_lock); + goto out_unlock; + } + } + read_unlock(&cnic_dev_lock); + + rcu_assign_pointer(cnic_ulp_tbl[ulp_type], NULL); + + mutex_unlock(&cnic_lock); + synchronize_rcu(); + return 0; + +out_unlock: + mutex_unlock(&cnic_lock); + return -EINVAL; +} + +static int cnic_start_hw(struct cnic_dev *); +static void cnic_stop_hw(struct cnic_dev *); + +static int cnic_register_device(struct cnic_dev *dev, int ulp_type, + void *ulp_ctx) +{ + struct cnic_local *cp = dev->cnic_priv; + struct cnic_ulp_ops *ulp_ops; + + if (ulp_type >= MAX_CNIC_ULP_TYPE) { + printk(KERN_ERR PFX "cnic_register_device: Bad type %d\n", + ulp_type); + return -EINVAL; + } + mutex_lock(&cnic_lock); + if (cnic_ulp_tbl[ulp_type] == NULL) { + printk(KERN_ERR PFX "cnic_register_device: Driver with type %d " + "has not been registered\n", ulp_type); + mutex_unlock(&cnic_lock); + return -EAGAIN; + } + if (rcu_dereference(cp->ulp_ops[ulp_type])) { + printk(KERN_ERR PFX "cnic_register_device: Type %d has already " + "been registered to this device\n", ulp_type); + mutex_unlock(&cnic_lock); + return -EBUSY; + } + + clear_bit(ULP_F_START, &cp->ulp_flags[ulp_type]); + cp->ulp_handle[ulp_type] = ulp_ctx; + ulp_ops = cnic_ulp_tbl[ulp_type]; + rcu_assign_pointer(cp->ulp_ops[ulp_type], ulp_ops); + cnic_hold(dev); + + if (test_bit(CNIC_F_CNIC_UP, &dev->flags)) + if (!test_and_set_bit(ULP_F_START, &cp->ulp_flags[ulp_type])) + ulp_ops->cnic_start(cp->ulp_handle[ulp_type]); + + mutex_unlock(&cnic_lock); + + return 0; + +} +EXPORT_SYMBOL(cnic_register_driver); + +static int cnic_unregister_device(struct cnic_dev *dev, int ulp_type) +{ + struct cnic_local *cp = dev->cnic_priv; + + if (ulp_type >= MAX_CNIC_ULP_TYPE) { + printk(KERN_ERR PFX "cnic_unregister_device: Bad type %d\n", + ulp_type); + return -EINVAL; + } + mutex_lock(&cnic_lock); + if (rcu_dereference(cp->ulp_ops[ulp_type])) { + rcu_assign_pointer(cp->ulp_ops[ulp_type], NULL); + cnic_put(dev); + } else { + printk(KERN_ERR PFX "cnic_unregister_device: device not " + "registered to this ulp type %d\n", ulp_type); + mutex_unlock(&cnic_lock); + return -EINVAL; + } + mutex_unlock(&cnic_lock); + + synchronize_rcu(); + + return 0; +} +EXPORT_SYMBOL(cnic_unregister_driver); + +static int cnic_init_id_tbl(struct cnic_id_tbl *id_tbl, u32 size, u32 start_id) +{ + id_tbl->start = start_id; + id_tbl->max = size; + id_tbl->next = 0; + spin_lock_init(&id_tbl->lock); + id_tbl->table = kzalloc(DIV_ROUND_UP(size, 32) * 4, GFP_KERNEL); + if (!id_tbl->table) + return -ENOMEM; + + return 0; +} + +static void cnic_free_id_tbl(struct cnic_id_tbl *id_tbl) +{ + kfree(id_tbl->table); + id_tbl->table = NULL; +} + +static int cnic_alloc_id(struct cnic_id_tbl *id_tbl, u32 id) +{ + int ret = -1; + + id -= id_tbl->start; + if (id >= id_tbl->max) + return ret; + + spin_lock(&id_tbl->lock); + if (!test_bit(id, id_tbl->table)) { + set_bit(id, id_tbl->table); + ret = 0; + } + spin_unlock(&id_tbl->lock); + return ret; +} + +/* Returns -1 if not successful */ +static u32 cnic_alloc_new_id(struct cnic_id_tbl *id_tbl) +{ + u32 id; + + spin_lock(&id_tbl->lock); + id = find_next_zero_bit(id_tbl->table, id_tbl->max, id_tbl->next); + if (id >= id_tbl->max) { + id = -1; + if (id_tbl->next != 0) { + id = find_first_zero_bit(id_tbl->table, id_tbl->next); + if (id >= id_tbl->next) + id = -1; + } + } + + if (id < id_tbl->max) { + set_bit(id, id_tbl->table); + id_tbl->next = (id + 1) & (id_tbl->max - 1); + id += id_tbl->start; + } + + spin_unlock(&id_tbl->lock); + + return id; +} + +static void cnic_free_id(struct cnic_id_tbl *id_tbl, u32 id) +{ + if (id == -1) + return; + + id -= id_tbl->start; + if (id >= id_tbl->max) + return; + + clear_bit(id, id_tbl->table); +} + +static void cnic_free_dma(struct cnic_dev *dev, struct cnic_dma *dma) +{ + int i; + + if (!dma->pg_arr) + return; + + for (i = 0; i < dma->num_pages; i++) { + if (dma->pg_arr[i]) { + pci_free_consistent(dev->pcidev, BCM_PAGE_SIZE, + dma->pg_arr[i], dma->pg_map_arr[i]); + dma->pg_arr[i] = NULL; + } + } + if (dma->pgtbl) { + pci_free_consistent(dev->pcidev, dma->pgtbl_size, + dma->pgtbl, dma->pgtbl_map); + dma->pgtbl = NULL; + } + kfree(dma->pg_arr); + dma->pg_arr = NULL; + dma->num_pages = 0; +} + +static void cnic_setup_page_tbl(struct cnic_dev *dev, struct cnic_dma *dma) +{ + int i; + u32 *page_table = dma->pgtbl; + + for (i = 0; i < dma->num_pages; i++) { + /* Each entry needs to be in big endian format. */ + *page_table = (u32) ((u64) dma->pg_map_arr[i] >> 32); + page_table++; + *page_table = (u32) dma->pg_map_arr[i]; + page_table++; + } +} + +static int cnic_alloc_dma(struct cnic_dev *dev, struct cnic_dma *dma, + int pages, int use_pg_tbl) +{ + int i, size; + struct cnic_local *cp = dev->cnic_priv; + + size = pages * (sizeof(void *) + sizeof(dma_addr_t)); + dma->pg_arr = kzalloc(size, GFP_ATOMIC); + if (dma->pg_arr == NULL) + return -ENOMEM; + + dma->pg_map_arr = (dma_addr_t *) (dma->pg_arr + pages); + dma->num_pages = pages; + + for (i = 0; i < pages; i++) { + dma->pg_arr[i] = pci_alloc_consistent(dev->pcidev, + BCM_PAGE_SIZE, + &dma->pg_map_arr[i]); + if (dma->pg_arr[i] == NULL) + goto error; + } + if (!use_pg_tbl) + return 0; + + dma->pgtbl_size = ((pages * 8) + BCM_PAGE_SIZE - 1) & + ~(BCM_PAGE_SIZE - 1); + dma->pgtbl = pci_alloc_consistent(dev->pcidev, dma->pgtbl_size, + &dma->pgtbl_map); + if (dma->pgtbl == NULL) + goto error; + + cp->setup_pgtbl(dev, dma); + + return 0; + +error: + cnic_free_dma(dev, dma); + return -ENOMEM; +} + +static void cnic_free_resc(struct cnic_dev *dev) +{ + struct cnic_local *cp = dev->cnic_priv; + int i = 0; + + if (cp->cnic_uinfo) { + cnic_send_nlmsg(cp, ISCSI_KEVENT_IF_DOWN, NULL); + while (cp->uio_dev != -1 && i < 15) { + msleep(100); + i++; + } + uio_unregister_device(cp->cnic_uinfo); + kfree(cp->cnic_uinfo); + cp->cnic_uinfo = NULL; + } + + if (cp->l2_buf) { + pci_free_consistent(dev->pcidev, cp->l2_buf_size, + cp->l2_buf, cp->l2_buf_map); + cp->l2_buf = NULL; + } + + if (cp->l2_ring) { + pci_free_consistent(dev->pcidev, cp->l2_ring_size, + cp->l2_ring, cp->l2_ring_map); + cp->l2_ring = NULL; + } + + for (i = 0; i < cp->ctx_blks; i++) { + if (cp->ctx_arr[i].ctx) { + pci_free_consistent(dev->pcidev, cp->ctx_blk_size, + cp->ctx_arr[i].ctx, + cp->ctx_arr[i].mapping); + cp->ctx_arr[i].ctx = NULL; + } + } + kfree(cp->ctx_arr); + cp->ctx_arr = NULL; + cp->ctx_blks = 0; + + cnic_free_dma(dev, &cp->gbl_buf_info); + cnic_free_dma(dev, &cp->conn_buf_info); + cnic_free_dma(dev, &cp->kwq_info); + cnic_free_dma(dev, &cp->kcq_info); + kfree(cp->iscsi_tbl); + cp->iscsi_tbl = NULL; + kfree(cp->ctx_tbl); + cp->ctx_tbl = NULL; + + cnic_free_id_tbl(&cp->cid_tbl); +} + +static int cnic_alloc_context(struct cnic_dev *dev) +{ + struct cnic_local *cp = dev->cnic_priv; + + if (CHIP_NUM(cp) == CHIP_NUM_5709) { + int i, k, arr_size; + + cp->ctx_blk_size = BCM_PAGE_SIZE; + cp->cids_per_blk = BCM_PAGE_SIZE / 128; + arr_size = BNX2_MAX_CID / cp->cids_per_blk * + sizeof(struct cnic_ctx); + cp->ctx_arr = kzalloc(arr_size, GFP_KERNEL); + if (cp->ctx_arr == NULL) + return -ENOMEM; + + k = 0; + for (i = 0; i < 2; i++) { + u32 j, reg, off, lo, hi; + + if (i == 0) + off = BNX2_PG_CTX_MAP; + else + off = BNX2_ISCSI_CTX_MAP; + + reg = cnic_reg_rd_ind(dev, off); + lo = reg >> 16; + hi = reg & 0xffff; + for (j = lo; j < hi; j += cp->cids_per_blk, k++) + cp->ctx_arr[k].cid = j; + } + + cp->ctx_blks = k; + if (cp->ctx_blks >= (BNX2_MAX_CID / cp->cids_per_blk)) { + cp->ctx_blks = 0; + return -ENOMEM; + } + + for (i = 0; i < cp->ctx_blks; i++) { + cp->ctx_arr[i].ctx = + pci_alloc_consistent(dev->pcidev, BCM_PAGE_SIZE, + &cp->ctx_arr[i].mapping); + if (cp->ctx_arr[i].ctx == NULL) + return -ENOMEM; + } + } + return 0; +} + +static int cnic_alloc_bnx2_resc(struct cnic_dev *dev) +{ + struct cnic_local *cp = dev->cnic_priv; + struct uio_info *uinfo; + int ret; + + ret = cnic_alloc_dma(dev, &cp->kwq_info, KWQ_PAGE_CNT, 1); + if (ret) + goto error; + cp->kwq = (struct kwqe **) cp->kwq_info.pg_arr; + + ret = cnic_alloc_dma(dev, &cp->kcq_info, KCQ_PAGE_CNT, 1); + if (ret) + goto error; + cp->kcq = (struct kcqe **) cp->kcq_info.pg_arr; + + ret = cnic_alloc_context(dev); + if (ret) + goto error; + + cp->l2_ring_size = 2 * BCM_PAGE_SIZE; + cp->l2_ring = pci_alloc_consistent(dev->pcidev, cp->l2_ring_size, + &cp->l2_ring_map); + if (!cp->l2_ring) + goto error; + + cp->l2_buf_size = (cp->l2_rx_ring_size + 1) * cp->l2_single_buf_size; + cp->l2_buf_size = PAGE_ALIGN(cp->l2_buf_size); + cp->l2_buf = pci_alloc_consistent(dev->pcidev, cp->l2_buf_size, + &cp->l2_buf_map); + if (!cp->l2_buf) + goto error; + + uinfo = kzalloc(sizeof(*uinfo), GFP_ATOMIC); + if (!uinfo) + goto error; + + uinfo->mem[0].addr = dev->netdev->base_addr; + uinfo->mem[0].internal_addr = dev->regview; + uinfo->mem[0].size = dev->netdev->mem_end - dev->netdev->mem_start; + uinfo->mem[0].memtype = UIO_MEM_PHYS; + + uinfo->mem[1].addr = (unsigned long) cp->status_blk & PAGE_MASK; + if (cp->ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX) + uinfo->mem[1].size = BNX2_SBLK_MSIX_ALIGN_SIZE * 9; + else + uinfo->mem[1].size = BNX2_SBLK_MSIX_ALIGN_SIZE; + uinfo->mem[1].memtype = UIO_MEM_LOGICAL; + + uinfo->mem[2].addr = (unsigned long) cp->l2_ring; + uinfo->mem[2].size = cp->l2_ring_size; + uinfo->mem[2].memtype = UIO_MEM_LOGICAL; + + uinfo->mem[3].addr = (unsigned long) cp->l2_buf; + uinfo->mem[3].size = cp->l2_buf_size; + uinfo->mem[3].memtype = UIO_MEM_LOGICAL; + + uinfo->name = "bnx2_cnic"; + uinfo->version = CNIC_MODULE_VERSION; + uinfo->irq = UIO_IRQ_CUSTOM; + + uinfo->open = cnic_uio_open; + uinfo->release = cnic_uio_close; + + uinfo->priv = dev; + + ret = uio_register_device(&dev->pcidev->dev, uinfo); + if (ret) { + kfree(uinfo); + goto error; + } + + cp->cnic_uinfo = uinfo; + + return 0; + +error: + cnic_free_resc(dev); + return ret; +} + +static inline u32 cnic_kwq_avail(struct cnic_local *cp) +{ + return cp->max_kwq_idx - + ((cp->kwq_prod_idx - cp->kwq_con_idx) & cp->max_kwq_idx); +} + +static int cnic_submit_bnx2_kwqes(struct cnic_dev *dev, struct kwqe *wqes[], + u32 num_wqes) +{ + struct cnic_local *cp = dev->cnic_priv; + struct kwqe *prod_qe; + u16 prod, sw_prod, i; + + if (!test_bit(CNIC_F_CNIC_UP, &dev->flags)) + return -EAGAIN; /* bnx2 is down */ + + spin_lock_bh(&cp->cnic_ulp_lock); + if (num_wqes > cnic_kwq_avail(cp) && + !(cp->cnic_local_flags & CNIC_LCL_FL_KWQ_INIT)) { + spin_unlock_bh(&cp->cnic_ulp_lock); + return -EAGAIN; + } + + cp->cnic_local_flags &= ~CNIC_LCL_FL_KWQ_INIT; + + prod = cp->kwq_prod_idx; + sw_prod = prod & MAX_KWQ_IDX; + for (i = 0; i < num_wqes; i++) { + prod_qe = &cp->kwq[KWQ_PG(sw_prod)][KWQ_IDX(sw_prod)]; + memcpy(prod_qe, wqes[i], sizeof(struct kwqe)); + prod++; + sw_prod = prod & MAX_KWQ_IDX; + } + cp->kwq_prod_idx = prod; + + CNIC_WR16(dev, cp->kwq_io_addr, cp->kwq_prod_idx); + + spin_unlock_bh(&cp->cnic_ulp_lock); + return 0; +} + +static void service_kcqes(struct cnic_dev *dev, int num_cqes) +{ + struct cnic_local *cp = dev->cnic_priv; + int i, j; + + i = 0; + j = 1; + while (num_cqes) { + struct cnic_ulp_ops *ulp_ops; + int ulp_type; + u32 kcqe_op_flag = cp->completed_kcq[i]->kcqe_op_flag; + u32 kcqe_layer = kcqe_op_flag & KCQE_FLAGS_LAYER_MASK; + + if (unlikely(kcqe_op_flag & KCQE_RAMROD_COMPLETION)) + cnic_kwq_completion(dev, 1); + + while (j < num_cqes) { + u32 next_op = cp->completed_kcq[i + j]->kcqe_op_flag; + + if ((next_op & KCQE_FLAGS_LAYER_MASK) != kcqe_layer) + break; + + if (unlikely(next_op & KCQE_RAMROD_COMPLETION)) + cnic_kwq_completion(dev, 1); + j++; + } + + if (kcqe_layer == KCQE_FLAGS_LAYER_MASK_L5_RDMA) + ulp_type = CNIC_ULP_RDMA; + else if (kcqe_layer == KCQE_FLAGS_LAYER_MASK_L5_ISCSI) + ulp_type = CNIC_ULP_ISCSI; + else if (kcqe_layer == KCQE_FLAGS_LAYER_MASK_L4) + ulp_type = CNIC_ULP_L4; + else if (kcqe_layer == KCQE_FLAGS_LAYER_MASK_L2) + goto end; + else { + printk(KERN_ERR PFX "%s: Unknown type of KCQE(0x%x)\n", + dev->netdev->name, kcqe_op_flag); + goto end; + } + + rcu_read_lock(); + ulp_ops = rcu_dereference(cp->ulp_ops[ulp_type]); + if (likely(ulp_ops)) { + ulp_ops->indicate_kcqes(cp->ulp_handle[ulp_type], + cp->completed_kcq + i, j); + } + rcu_read_unlock(); +end: + num_cqes -= j; + i += j; + j = 1; + } + return; +} + +static u16 cnic_bnx2_next_idx(u16 idx) +{ + return idx + 1; +} + +static u16 cnic_bnx2_hw_idx(u16 idx) +{ + return idx; +} + +static int cnic_get_kcqes(struct cnic_dev *dev, u16 hw_prod, u16 *sw_prod) +{ + struct cnic_local *cp = dev->cnic_priv; + u16 i, ri, last; + struct kcqe *kcqe; + int kcqe_cnt = 0, last_cnt = 0; + + i = ri = last = *sw_prod; + ri &= MAX_KCQ_IDX; + + while ((i != hw_prod) && (kcqe_cnt < MAX_COMPLETED_KCQE)) { + kcqe = &cp->kcq[KCQ_PG(ri)][KCQ_IDX(ri)]; + cp->completed_kcq[kcqe_cnt++] = kcqe; + i = cp->next_idx(i); + ri = i & MAX_KCQ_IDX; + if (likely(!(kcqe->kcqe_op_flag & KCQE_FLAGS_NEXT))) { + last_cnt = kcqe_cnt; + last = i; + } + } + + *sw_prod = last; + return last_cnt; +} + +static void cnic_chk_bnx2_pkt_rings(struct cnic_local *cp) +{ + u16 rx_cons = *cp->rx_cons_ptr; + u16 tx_cons = *cp->tx_cons_ptr; + + if (cp->tx_cons != tx_cons || cp->rx_cons != rx_cons) { + cp->tx_cons = tx_cons; + cp->rx_cons = rx_cons; + uio_event_notify(cp->cnic_uinfo); + } +} + +static int cnic_service_bnx2(void *data, void *status_blk) +{ + struct cnic_dev *dev = data; + struct status_block *sblk = status_blk; + struct cnic_local *cp = dev->cnic_priv; + u32 status_idx = sblk->status_idx; + u16 hw_prod, sw_prod; + int kcqe_cnt; + + if (unlikely(!test_bit(CNIC_F_CNIC_UP, &dev->flags))) + return status_idx; + + cp->kwq_con_idx = *cp->kwq_con_idx_ptr; + + hw_prod = sblk->status_completion_producer_index; + sw_prod = cp->kcq_prod_idx; + while (sw_prod != hw_prod) { + kcqe_cnt = cnic_get_kcqes(dev, hw_prod, &sw_prod); + if (kcqe_cnt == 0) + goto done; + + service_kcqes(dev, kcqe_cnt); + + /* Tell compiler that status_blk fields can change. */ + barrier(); + if (status_idx != sblk->status_idx) { + status_idx = sblk->status_idx; + cp->kwq_con_idx = *cp->kwq_con_idx_ptr; + hw_prod = sblk->status_completion_producer_index; + } else + break; + } + +done: + CNIC_WR16(dev, cp->kcq_io_addr, sw_prod); + + cp->kcq_prod_idx = sw_prod; + + cnic_chk_bnx2_pkt_rings(cp); + return status_idx; +} + +static void cnic_service_bnx2_msix(unsigned long data) +{ + struct cnic_dev *dev = (struct cnic_dev *) data; + struct cnic_local *cp = dev->cnic_priv; + struct status_block_msix *status_blk = cp->bnx2_status_blk; + u32 status_idx = status_blk->status_idx; + u16 hw_prod, sw_prod; + int kcqe_cnt; + + cp->kwq_con_idx = status_blk->status_cmd_consumer_index; + + hw_prod = status_blk->status_completion_producer_index; + sw_prod = cp->kcq_prod_idx; + while (sw_prod != hw_prod) { + kcqe_cnt = cnic_get_kcqes(dev, hw_prod, &sw_prod); + if (kcqe_cnt == 0) + goto done; + + service_kcqes(dev, kcqe_cnt); + + /* Tell compiler that status_blk fields can change. */ + barrier(); + if (status_idx != status_blk->status_idx) { + status_idx = status_blk->status_idx; + cp->kwq_con_idx = status_blk->status_cmd_consumer_index; + hw_prod = status_blk->status_completion_producer_index; + } else + break; + } + +done: + CNIC_WR16(dev, cp->kcq_io_addr, sw_prod); + cp->kcq_prod_idx = sw_prod; + + cnic_chk_bnx2_pkt_rings(cp); + + cp->last_status_idx = status_idx; + CNIC_WR(dev, BNX2_PCICFG_INT_ACK_CMD, cp->int_num | + BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | cp->last_status_idx); +} + +static irqreturn_t cnic_irq(int irq, void *dev_instance) +{ + struct cnic_dev *dev = dev_instance; + struct cnic_local *cp = dev->cnic_priv; + u16 prod = cp->kcq_prod_idx & MAX_KCQ_IDX; + + if (cp->ack_int) + cp->ack_int(dev); + + prefetch(cp->status_blk); + prefetch(&cp->kcq[KCQ_PG(prod)][KCQ_IDX(prod)]); + + if (likely(test_bit(CNIC_F_CNIC_UP, &dev->flags))) + tasklet_schedule(&cp->cnic_irq_task); + + return IRQ_HANDLED; +} + +static void cnic_ulp_stop(struct cnic_dev *dev) +{ + struct cnic_local *cp = dev->cnic_priv; + int if_type; + + rcu_read_lock(); + for (if_type = 0; if_type < MAX_CNIC_ULP_TYPE; if_type++) { + struct cnic_ulp_ops *ulp_ops; + + ulp_ops = rcu_dereference(cp->ulp_ops[if_type]); + if (!ulp_ops) + continue; + + if (test_and_clear_bit(ULP_F_START, &cp->ulp_flags[if_type])) + ulp_ops->cnic_stop(cp->ulp_handle[if_type]); + } + rcu_read_unlock(); +} + +static void cnic_ulp_start(struct cnic_dev *dev) +{ + struct cnic_local *cp = dev->cnic_priv; + int if_type; + + rcu_read_lock(); + for (if_type = 0; if_type < MAX_CNIC_ULP_TYPE; if_type++) { + struct cnic_ulp_ops *ulp_ops; + + ulp_ops = rcu_dereference(cp->ulp_ops[if_type]); + if (!ulp_ops || !ulp_ops->cnic_start) + continue; + + if (!test_and_set_bit(ULP_F_START, &cp->ulp_flags[if_type])) + ulp_ops->cnic_start(cp->ulp_handle[if_type]); + } + rcu_read_unlock(); +} + +static int cnic_ctl(void *data, struct cnic_ctl_info *info) +{ + struct cnic_dev *dev = data; + + switch (info->cmd) { + case CNIC_CTL_STOP_CMD: + cnic_hold(dev); + mutex_lock(&cnic_lock); + + cnic_ulp_stop(dev); + cnic_stop_hw(dev); + + mutex_unlock(&cnic_lock); + cnic_put(dev); + break; + case CNIC_CTL_START_CMD: + cnic_hold(dev); + mutex_lock(&cnic_lock); + + if (!cnic_start_hw(dev)) + cnic_ulp_start(dev); + + mutex_unlock(&cnic_lock); + cnic_put(dev); + break; + default: + return -EINVAL; + } + return 0; +} + +static void cnic_ulp_init(struct cnic_dev *dev) +{ + int i; + struct cnic_local *cp = dev->cnic_priv; + + rcu_read_lock(); + for (i = 0; i < MAX_CNIC_ULP_TYPE_EXT; i++) { + struct cnic_ulp_ops *ulp_ops; + + ulp_ops = rcu_dereference(cnic_ulp_tbl[i]); + if (!ulp_ops || !ulp_ops->cnic_init) + continue; + + if (!test_and_set_bit(ULP_F_INIT, &cp->ulp_flags[i])) + ulp_ops->cnic_init(dev); + + } + rcu_read_unlock(); +} + +static void cnic_ulp_exit(struct cnic_dev *dev) +{ + int i; + struct cnic_local *cp = dev->cnic_priv; + + rcu_read_lock(); + for (i = 0; i < MAX_CNIC_ULP_TYPE_EXT; i++) { + struct cnic_ulp_ops *ulp_ops; + + ulp_ops = rcu_dereference(cnic_ulp_tbl[i]); + if (!ulp_ops || !ulp_ops->cnic_exit) + continue; + + if (test_and_clear_bit(ULP_F_INIT, &cp->ulp_flags[i])) + ulp_ops->cnic_exit(dev); + + } + rcu_read_unlock(); +} + +static int cnic_cm_offload_pg(struct cnic_sock *csk) +{ + struct cnic_dev *dev = csk->dev; + struct l4_kwq_offload_pg *l4kwqe; + struct kwqe *wqes[1]; + + l4kwqe = (struct l4_kwq_offload_pg *) &csk->kwqe1; + memset(l4kwqe, 0, sizeof(*l4kwqe)); + wqes[0] = (struct kwqe *) l4kwqe; + + l4kwqe->op_code = L4_KWQE_OPCODE_VALUE_OFFLOAD_PG; + l4kwqe->flags = + L4_LAYER_CODE << L4_KWQ_OFFLOAD_PG_LAYER_CODE_SHIFT; + l4kwqe->l2hdr_nbytes = ETH_HLEN; + + l4kwqe->da0 = csk->ha[0]; + l4kwqe->da1 = csk->ha[1]; + l4kwqe->da2 = csk->ha[2]; + l4kwqe->da3 = csk->ha[3]; + l4kwqe->da4 = csk->ha[4]; + l4kwqe->da5 = csk->ha[5]; + + l4kwqe->sa0 = dev->mac_addr[0]; + l4kwqe->sa1 = dev->mac_addr[1]; + l4kwqe->sa2 = dev->mac_addr[2]; + l4kwqe->sa3 = dev->mac_addr[3]; + l4kwqe->sa4 = dev->mac_addr[4]; + l4kwqe->sa5 = dev->mac_addr[5]; + + l4kwqe->etype = ETH_P_IP; + l4kwqe->ipid_count = DEF_IPID_COUNT; + l4kwqe->host_opaque = csk->l5_cid; + + if (csk->vlan_id) { + l4kwqe->pg_flags |= L4_KWQ_OFFLOAD_PG_VLAN_TAGGING; + l4kwqe->vlan_tag = csk->vlan_id; + l4kwqe->l2hdr_nbytes += 4; + } + + return dev->submit_kwqes(dev, wqes, 1); +} + +static int cnic_cm_update_pg(struct cnic_sock *csk) +{ + struct cnic_dev *dev = csk->dev; + struct l4_kwq_update_pg *l4kwqe; + struct kwqe *wqes[1]; + + l4kwqe = (struct l4_kwq_update_pg *) &csk->kwqe1; + memset(l4kwqe, 0, sizeof(*l4kwqe)); + wqes[0] = (struct kwqe *) l4kwqe; + + l4kwqe->opcode = L4_KWQE_OPCODE_VALUE_UPDATE_PG; + l4kwqe->flags = + L4_LAYER_CODE << L4_KWQ_UPDATE_PG_LAYER_CODE_SHIFT; + l4kwqe->pg_cid = csk->pg_cid; + + l4kwqe->da0 = csk->ha[0]; + l4kwqe->da1 = csk->ha[1]; + l4kwqe->da2 = csk->ha[2]; + l4kwqe->da3 = csk->ha[3]; + l4kwqe->da4 = csk->ha[4]; + l4kwqe->da5 = csk->ha[5]; + + l4kwqe->pg_host_opaque = csk->l5_cid; + l4kwqe->pg_valids = L4_KWQ_UPDATE_PG_VALIDS_DA; + + return dev->submit_kwqes(dev, wqes, 1); +} + +static int cnic_cm_upload_pg(struct cnic_sock *csk) +{ + struct cnic_dev *dev = csk->dev; + struct l4_kwq_upload *l4kwqe; + struct kwqe *wqes[1]; + + l4kwqe = (struct l4_kwq_upload *) &csk->kwqe1; + memset(l4kwqe, 0, sizeof(*l4kwqe)); + wqes[0] = (struct kwqe *) l4kwqe; + + l4kwqe->opcode = L4_KWQE_OPCODE_VALUE_UPLOAD_PG; + l4kwqe->flags = + L4_LAYER_CODE << L4_KWQ_UPLOAD_LAYER_CODE_SHIFT; + l4kwqe->cid = csk->pg_cid; + + return dev->submit_kwqes(dev, wqes, 1); +} + +static int cnic_cm_conn_req(struct cnic_sock *csk) +{ + struct cnic_dev *dev = csk->dev; + struct l4_kwq_connect_req1 *l4kwqe1; + struct l4_kwq_connect_req2 *l4kwqe2; + struct l4_kwq_connect_req3 *l4kwqe3; + struct kwqe *wqes[3]; + u8 tcp_flags = 0; + int num_wqes = 2; + + l4kwqe1 = (struct l4_kwq_connect_req1 *) &csk->kwqe1; + l4kwqe2 = (struct l4_kwq_connect_req2 *) &csk->kwqe2; + l4kwqe3 = (struct l4_kwq_connect_req3 *) &csk->kwqe3; + memset(l4kwqe1, 0, sizeof(*l4kwqe1)); + memset(l4kwqe2, 0, sizeof(*l4kwqe2)); + memset(l4kwqe3, 0, sizeof(*l4kwqe3)); + + l4kwqe3->op_code = L4_KWQE_OPCODE_VALUE_CONNECT3; + l4kwqe3->flags = + L4_LAYER_CODE << L4_KWQ_CONNECT_REQ3_LAYER_CODE_SHIFT; + l4kwqe3->ka_timeout = csk->ka_timeout; + l4kwqe3->ka_interval = csk->ka_interval; + l4kwqe3->ka_max_probe_count = csk->ka_max_probe_count; + l4kwqe3->tos = csk->tos; + l4kwqe3->ttl = csk->ttl; + l4kwqe3->snd_seq_scale = csk->snd_seq_scale; + l4kwqe3->pmtu = csk->mtu; + l4kwqe3->rcv_buf = csk->rcv_buf; + l4kwqe3->snd_buf = csk->snd_buf; + l4kwqe3->seed = csk->seed; + + wqes[0] = (struct kwqe *) l4kwqe1; + if (test_bit(SK_F_IPV6, &csk->flags)) { + wqes[1] = (struct kwqe *) l4kwqe2; + wqes[2] = (struct kwqe *) l4kwqe3; + num_wqes = 3; + + l4kwqe1->conn_flags = L4_KWQ_CONNECT_REQ1_IP_V6; + l4kwqe2->op_code = L4_KWQE_OPCODE_VALUE_CONNECT2; + l4kwqe2->flags = + L4_KWQ_CONNECT_REQ2_LINKED_WITH_NEXT | + L4_LAYER_CODE << L4_KWQ_CONNECT_REQ2_LAYER_CODE_SHIFT; + l4kwqe2->src_ip_v6_2 = be32_to_cpu(csk->src_ip[1]); + l4kwqe2->src_ip_v6_3 = be32_to_cpu(csk->src_ip[2]); + l4kwqe2->src_ip_v6_4 = be32_to_cpu(csk->src_ip[3]); + l4kwqe2->dst_ip_v6_2 = be32_to_cpu(csk->dst_ip[1]); + l4kwqe2->dst_ip_v6_3 = be32_to_cpu(csk->dst_ip[2]); + l4kwqe2->dst_ip_v6_4 = be32_to_cpu(csk->dst_ip[3]); + l4kwqe3->mss = l4kwqe3->pmtu - sizeof(struct ipv6hdr) - + sizeof(struct tcphdr); + } else { + wqes[1] = (struct kwqe *) l4kwqe3; + l4kwqe3->mss = l4kwqe3->pmtu - sizeof(struct iphdr) - + sizeof(struct tcphdr); + } + + l4kwqe1->op_code = L4_KWQE_OPCODE_VALUE_CONNECT1; + l4kwqe1->flags = + (L4_LAYER_CODE << L4_KWQ_CONNECT_REQ1_LAYER_CODE_SHIFT) | + L4_KWQ_CONNECT_REQ3_LINKED_WITH_NEXT; + l4kwqe1->cid = csk->cid; + l4kwqe1->pg_cid = csk->pg_cid; + l4kwqe1->src_ip = be32_to_cpu(csk->src_ip[0]); + l4kwqe1->dst_ip = be32_to_cpu(csk->dst_ip[0]); + l4kwqe1->src_port = be16_to_cpu(csk->src_port); + l4kwqe1->dst_port = be16_to_cpu(csk->dst_port); + if (csk->tcp_flags & SK_TCP_NO_DELAY_ACK) + tcp_flags |= L4_KWQ_CONNECT_REQ1_NO_DELAY_ACK; + if (csk->tcp_flags & SK_TCP_KEEP_ALIVE) + tcp_flags |= L4_KWQ_CONNECT_REQ1_KEEP_ALIVE; + if (csk->tcp_flags & SK_TCP_NAGLE) + tcp_flags |= L4_KWQ_CONNECT_REQ1_NAGLE_ENABLE; + if (csk->tcp_flags & SK_TCP_TIMESTAMP) + tcp_flags |= L4_KWQ_CONNECT_REQ1_TIME_STAMP; + if (csk->tcp_flags & SK_TCP_SACK) + tcp_flags |= L4_KWQ_CONNECT_REQ1_SACK; + if (csk->tcp_flags & SK_TCP_SEG_SCALING) + tcp_flags |= L4_KWQ_CONNECT_REQ1_SEG_SCALING; + + l4kwqe1->tcp_flags = tcp_flags; + + return dev->submit_kwqes(dev, wqes, num_wqes); +} + +static int cnic_cm_close_req(struct cnic_sock *csk) +{ + struct cnic_dev *dev = csk->dev; + struct l4_kwq_close_req *l4kwqe; + struct kwqe *wqes[1]; + + l4kwqe = (struct l4_kwq_close_req *) &csk->kwqe2; + memset(l4kwqe, 0, sizeof(*l4kwqe)); + wqes[0] = (struct kwqe *) l4kwqe; + + l4kwqe->op_code = L4_KWQE_OPCODE_VALUE_CLOSE; + l4kwqe->flags = L4_LAYER_CODE << L4_KWQ_CLOSE_REQ_LAYER_CODE_SHIFT; + l4kwqe->cid = csk->cid; + + return dev->submit_kwqes(dev, wqes, 1); +} + +static int cnic_cm_abort_req(struct cnic_sock *csk) +{ + struct cnic_dev *dev = csk->dev; + struct l4_kwq_reset_req *l4kwqe; + struct kwqe *wqes[1]; + + l4kwqe = (struct l4_kwq_reset_req *) &csk->kwqe2; + memset(l4kwqe, 0, sizeof(*l4kwqe)); + wqes[0] = (struct kwqe *) l4kwqe; + + l4kwqe->op_code = L4_KWQE_OPCODE_VALUE_RESET; + l4kwqe->flags = L4_LAYER_CODE << L4_KWQ_RESET_REQ_LAYER_CODE_SHIFT; + l4kwqe->cid = csk->cid; + + return dev->submit_kwqes(dev, wqes, 1); +} + +static int cnic_cm_create(struct cnic_dev *dev, int ulp_type, u32 cid, + u32 l5_cid, struct cnic_sock **csk, void *context) +{ + struct cnic_local *cp = dev->cnic_priv; + struct cnic_sock *csk1; + + if (l5_cid >= MAX_CM_SK_TBL_SZ) + return -EINVAL; + + csk1 = &cp->csk_tbl[l5_cid]; + if (atomic_read(&csk1->ref_count)) + return -EAGAIN; + + if (test_and_set_bit(SK_F_INUSE, &csk1->flags)) + return -EBUSY; + + csk1->dev = dev; + csk1->cid = cid; + csk1->l5_cid = l5_cid; + csk1->ulp_type = ulp_type; + csk1->context = context; + + csk1->ka_timeout = DEF_KA_TIMEOUT; + csk1->ka_interval = DEF_KA_INTERVAL; + csk1->ka_max_probe_count = DEF_KA_MAX_PROBE_COUNT; + csk1->tos = DEF_TOS; + csk1->ttl = DEF_TTL; + csk1->snd_seq_scale = DEF_SND_SEQ_SCALE; + csk1->rcv_buf = DEF_RCV_BUF; + csk1->snd_buf = DEF_SND_BUF; + csk1->seed = DEF_SEED; + + *csk = csk1; + return 0; +} + +static void cnic_cm_cleanup(struct cnic_sock *csk) +{ + if (csk->src_port) { + struct cnic_dev *dev = csk->dev; + struct cnic_local *cp = dev->cnic_priv; + + cnic_free_id(&cp->csk_port_tbl, csk->src_port); + csk->src_port = 0; + } +} + +static void cnic_close_conn(struct cnic_sock *csk) +{ + if (test_bit(SK_F_PG_OFFLD_COMPLETE, &csk->flags)) { + cnic_cm_upload_pg(csk); + clear_bit(SK_F_PG_OFFLD_COMPLETE, &csk->flags); + } + cnic_cm_cleanup(csk); +} + +static int cnic_cm_destroy(struct cnic_sock *csk) +{ + if (!cnic_in_use(csk)) + return -EINVAL; + + csk_hold(csk); + clear_bit(SK_F_INUSE, &csk->flags); + smp_mb__after_clear_bit(); + while (atomic_read(&csk->ref_count) != 1) + msleep(1); + cnic_cm_cleanup(csk); + + csk->flags = 0; + csk_put(csk); + return 0; +} + +static inline u16 cnic_get_vlan(struct net_device *dev, + struct net_device **vlan_dev) +{ + if (dev->priv_flags & IFF_802_1Q_VLAN) { + *vlan_dev = vlan_dev_real_dev(dev); + return vlan_dev_vlan_id(dev); + } + *vlan_dev = dev; + return 0; +} + +static int cnic_get_v4_route(struct sockaddr_in *dst_addr, + struct dst_entry **dst) +{ +#if defined(CONFIG_INET) + struct flowi fl; + int err; + struct rtable *rt; + + memset(&fl, 0, sizeof(fl)); + fl.nl_u.ip4_u.daddr = dst_addr->sin_addr.s_addr; + + err = ip_route_output_key(&init_net, &rt, &fl); + if (!err) + *dst = &rt->u.dst; + return err; +#else + return -ENETUNREACH; +#endif +} + +static int cnic_get_v6_route(struct sockaddr_in6 *dst_addr, + struct dst_entry **dst) +{ +#if defined(CONFIG_IPV6) || (defined(CONFIG_IPV6_MODULE) && defined(MODULE)) + struct flowi fl; + + memset(&fl, 0, sizeof(fl)); + ipv6_addr_copy(&fl.fl6_dst, &dst_addr->sin6_addr); + if (ipv6_addr_type(&fl.fl6_dst) & IPV6_ADDR_LINKLOCAL) + fl.oif = dst_addr->sin6_scope_id; + + *dst = ip6_route_output(&init_net, NULL, &fl); + if (*dst) + return 0; +#endif + + return -ENETUNREACH; +} + +static struct cnic_dev *cnic_cm_select_dev(struct sockaddr_in *dst_addr, + int ulp_type) +{ + struct cnic_dev *dev = NULL; + struct dst_entry *dst; + struct net_device *netdev = NULL; + int err = -ENETUNREACH; + + if (dst_addr->sin_family == AF_INET) + err = cnic_get_v4_route(dst_addr, &dst); + else if (dst_addr->sin_family == AF_INET6) { + struct sockaddr_in6 *dst_addr6 = + (struct sockaddr_in6 *) dst_addr; + + err = cnic_get_v6_route(dst_addr6, &dst); + } else + return NULL; + + if (err) + return NULL; + + if (!dst->dev) + goto done; + + cnic_get_vlan(dst->dev, &netdev); + + dev = cnic_from_netdev(netdev); + +done: + dst_release(dst); + if (dev) + cnic_put(dev); + return dev; +} + +static int cnic_resolve_addr(struct cnic_sock *csk, struct cnic_sockaddr *saddr) +{ + struct cnic_dev *dev = csk->dev; + struct cnic_local *cp = dev->cnic_priv; + + return cnic_send_nlmsg(cp, ISCSI_KEVENT_PATH_REQ, csk); +} + +static int cnic_get_route(struct cnic_sock *csk, struct cnic_sockaddr *saddr) +{ + struct cnic_dev *dev = csk->dev; + struct cnic_local *cp = dev->cnic_priv; + int is_v6, err, rc = -ENETUNREACH; + struct dst_entry *dst; + struct net_device *realdev; + u32 local_port; + + if (saddr->local.v6.sin6_family == AF_INET6 && + saddr->remote.v6.sin6_family == AF_INET6) + is_v6 = 1; + else if (saddr->local.v4.sin_family == AF_INET && + saddr->remote.v4.sin_family == AF_INET) + is_v6 = 0; + else + return -EINVAL; + + clear_bit(SK_F_IPV6, &csk->flags); + + if (is_v6) { +#if defined(CONFIG_IPV6) || (defined(CONFIG_IPV6_MODULE) && defined(MODULE)) + set_bit(SK_F_IPV6, &csk->flags); + err = cnic_get_v6_route(&saddr->remote.v6, &dst); + if (err) + return err; + + if (!dst || dst->error || !dst->dev) + goto err_out; + + memcpy(&csk->dst_ip[0], &saddr->remote.v6.sin6_addr, + sizeof(struct in6_addr)); + csk->dst_port = saddr->remote.v6.sin6_port; + local_port = saddr->local.v6.sin6_port; +#else + return rc; +#endif + + } else { + err = cnic_get_v4_route(&saddr->remote.v4, &dst); + if (err) + return err; + + if (!dst || dst->error || !dst->dev) + goto err_out; + + csk->dst_ip[0] = saddr->remote.v4.sin_addr.s_addr; + csk->dst_port = saddr->remote.v4.sin_port; + local_port = saddr->local.v4.sin_port; + } + + csk->vlan_id = cnic_get_vlan(dst->dev, &realdev); + if (realdev != dev->netdev) + goto err_out; + + if (local_port >= CNIC_LOCAL_PORT_MIN && + local_port < CNIC_LOCAL_PORT_MAX) { + if (cnic_alloc_id(&cp->csk_port_tbl, local_port)) + local_port = 0; + } else + local_port = 0; + + if (!local_port) { + local_port = cnic_alloc_new_id(&cp->csk_port_tbl); + if (local_port == -1) { + rc = -ENOMEM; + goto err_out; + } + } + csk->src_port = local_port; + + csk->mtu = dst_mtu(dst); + rc = 0; + +err_out: + dst_release(dst); + return rc; +} + +static void cnic_init_csk_state(struct cnic_sock *csk) +{ + csk->state = 0; + clear_bit(SK_F_OFFLD_SCHED, &csk->flags); + clear_bit(SK_F_CLOSING, &csk->flags); +} + +static int cnic_cm_connect(struct cnic_sock *csk, struct cnic_sockaddr *saddr) +{ + int err = 0; + + if (!cnic_in_use(csk)) + return -EINVAL; + + if (test_and_set_bit(SK_F_CONNECT_START, &csk->flags)) + return -EINVAL; + + cnic_init_csk_state(csk); + + err = cnic_get_route(csk, saddr); + if (err) + goto err_out; + + err = cnic_resolve_addr(csk, saddr); + if (!err) + return 0; + +err_out: + clear_bit(SK_F_CONNECT_START, &csk->flags); + return err; +} + +static int cnic_cm_abort(struct cnic_sock *csk) +{ + struct cnic_local *cp = csk->dev->cnic_priv; + u32 opcode; + + if (!cnic_in_use(csk)) + return -EINVAL; + + if (cnic_abort_prep(csk)) + return cnic_cm_abort_req(csk); + + /* Getting here means that we haven't started connect, or + * connect was not successful. + */ + + csk->state = L4_KCQE_OPCODE_VALUE_RESET_COMP; + if (test_bit(SK_F_PG_OFFLD_COMPLETE, &csk->flags)) + opcode = csk->state; + else + opcode = L5CM_RAMROD_CMD_ID_TERMINATE_OFFLOAD; + cp->close_conn(csk, opcode); + + return 0; +} + +static int cnic_cm_close(struct cnic_sock *csk) +{ + if (!cnic_in_use(csk)) + return -EINVAL; + + if (cnic_close_prep(csk)) { + csk->state = L4_KCQE_OPCODE_VALUE_CLOSE_COMP; + return cnic_cm_close_req(csk); + } + return 0; +} + +static void cnic_cm_upcall(struct cnic_local *cp, struct cnic_sock *csk, + u8 opcode) +{ + struct cnic_ulp_ops *ulp_ops; + int ulp_type = csk->ulp_type; + + rcu_read_lock(); + ulp_ops = rcu_dereference(cp->ulp_ops[ulp_type]); + if (ulp_ops) { + if (opcode == L4_KCQE_OPCODE_VALUE_CONNECT_COMPLETE) + ulp_ops->cm_connect_complete(csk); + else if (opcode == L4_KCQE_OPCODE_VALUE_CLOSE_COMP) + ulp_ops->cm_close_complete(csk); + else if (opcode == L4_KCQE_OPCODE_VALUE_RESET_RECEIVED) + ulp_ops->cm_remote_abort(csk); + else if (opcode == L4_KCQE_OPCODE_VALUE_RESET_COMP) + ulp_ops->cm_abort_complete(csk); + else if (opcode == L4_KCQE_OPCODE_VALUE_CLOSE_RECEIVED) + ulp_ops->cm_remote_close(csk); + } + rcu_read_unlock(); +} + +static int cnic_cm_set_pg(struct cnic_sock *csk) +{ + if (cnic_offld_prep(csk)) { + if (test_bit(SK_F_PG_OFFLD_COMPLETE, &csk->flags)) + cnic_cm_update_pg(csk); + else + cnic_cm_offload_pg(csk); + } + return 0; +} + +static void cnic_cm_process_offld_pg(struct cnic_dev *dev, struct l4_kcq *kcqe) +{ + struct cnic_local *cp = dev->cnic_priv; + u32 l5_cid = kcqe->pg_host_opaque; + u8 opcode = kcqe->op_code; + struct cnic_sock *csk = &cp->csk_tbl[l5_cid]; + + csk_hold(csk); + if (!cnic_in_use(csk)) + goto done; + + if (opcode == L4_KCQE_OPCODE_VALUE_UPDATE_PG) { + clear_bit(SK_F_OFFLD_SCHED, &csk->flags); + goto done; + } + csk->pg_cid = kcqe->pg_cid; + set_bit(SK_F_PG_OFFLD_COMPLETE, &csk->flags); + cnic_cm_conn_req(csk); + +done: + csk_put(csk); +} + +static void cnic_cm_process_kcqe(struct cnic_dev *dev, struct kcqe *kcqe) +{ + struct cnic_local *cp = dev->cnic_priv; + struct l4_kcq *l4kcqe = (struct l4_kcq *) kcqe; + u8 opcode = l4kcqe->op_code; + u32 l5_cid; + struct cnic_sock *csk; + + if (opcode == L4_KCQE_OPCODE_VALUE_OFFLOAD_PG || + opcode == L4_KCQE_OPCODE_VALUE_UPDATE_PG) { + cnic_cm_process_offld_pg(dev, l4kcqe); + return; + } + + l5_cid = l4kcqe->conn_id; + if (opcode & 0x80) + l5_cid = l4kcqe->cid; + if (l5_cid >= MAX_CM_SK_TBL_SZ) + return; + + csk = &cp->csk_tbl[l5_cid]; + csk_hold(csk); + + if (!cnic_in_use(csk)) { + csk_put(csk); + return; + } + + switch (opcode) { + case L4_KCQE_OPCODE_VALUE_CONNECT_COMPLETE: + if (l4kcqe->status == 0) + set_bit(SK_F_OFFLD_COMPLETE, &csk->flags); + + smp_mb__before_clear_bit(); + clear_bit(SK_F_OFFLD_SCHED, &csk->flags); + cnic_cm_upcall(cp, csk, opcode); + break; + + case L4_KCQE_OPCODE_VALUE_RESET_RECEIVED: + if (test_and_clear_bit(SK_F_OFFLD_COMPLETE, &csk->flags)) + csk->state = opcode; + /* fall through */ + case L4_KCQE_OPCODE_VALUE_CLOSE_COMP: + case L4_KCQE_OPCODE_VALUE_RESET_COMP: + cp->close_conn(csk, opcode); + break; + + case L4_KCQE_OPCODE_VALUE_CLOSE_RECEIVED: + cnic_cm_upcall(cp, csk, opcode); + break; + } + csk_put(csk); +} + +static void cnic_cm_indicate_kcqe(void *data, struct kcqe *kcqe[], u32 num) +{ + struct cnic_dev *dev = data; + int i; + + for (i = 0; i < num; i++) + cnic_cm_process_kcqe(dev, kcqe[i]); +} + +static struct cnic_ulp_ops cm_ulp_ops = { + .indicate_kcqes = cnic_cm_indicate_kcqe, +}; + +static void cnic_cm_free_mem(struct cnic_dev *dev) +{ + struct cnic_local *cp = dev->cnic_priv; + + kfree(cp->csk_tbl); + cp->csk_tbl = NULL; + cnic_free_id_tbl(&cp->csk_port_tbl); +} + +static int cnic_cm_alloc_mem(struct cnic_dev *dev) +{ + struct cnic_local *cp = dev->cnic_priv; + + cp->csk_tbl = kzalloc(sizeof(struct cnic_sock) * MAX_CM_SK_TBL_SZ, + GFP_KERNEL); + if (!cp->csk_tbl) + return -ENOMEM; + + if (cnic_init_id_tbl(&cp->csk_port_tbl, CNIC_LOCAL_PORT_RANGE, + CNIC_LOCAL_PORT_MIN)) { + cnic_cm_free_mem(dev); + return -ENOMEM; + } + return 0; +} + +static int cnic_ready_to_close(struct cnic_sock *csk, u32 opcode) +{ + if ((opcode == csk->state) || + (opcode == L4_KCQE_OPCODE_VALUE_RESET_RECEIVED && + csk->state == L4_KCQE_OPCODE_VALUE_CLOSE_COMP)) { + if (!test_and_set_bit(SK_F_CLOSING, &csk->flags)) + return 1; + } + return 0; +} + +static void cnic_close_bnx2_conn(struct cnic_sock *csk, u32 opcode) +{ + struct cnic_dev *dev = csk->dev; + struct cnic_local *cp = dev->cnic_priv; + + clear_bit(SK_F_CONNECT_START, &csk->flags); + if (cnic_ready_to_close(csk, opcode)) { + cnic_close_conn(csk); + cnic_cm_upcall(cp, csk, opcode); + } +} + +static void cnic_cm_stop_bnx2_hw(struct cnic_dev *dev) +{ +} + +static int cnic_cm_init_bnx2_hw(struct cnic_dev *dev) +{ + u32 seed; + + get_random_bytes(&seed, 4); + cnic_ctx_wr(dev, 45, 0, seed); + return 0; +} + +static int cnic_cm_open(struct cnic_dev *dev) +{ + struct cnic_local *cp = dev->cnic_priv; + int err; + + err = cnic_cm_alloc_mem(dev); + if (err) + return err; + + err = cp->start_cm(dev); + + if (err) + goto err_out; + + dev->cm_create = cnic_cm_create; + dev->cm_destroy = cnic_cm_destroy; + dev->cm_connect = cnic_cm_connect; + dev->cm_abort = cnic_cm_abort; + dev->cm_close = cnic_cm_close; + dev->cm_select_dev = cnic_cm_select_dev; + + cp->ulp_handle[CNIC_ULP_L4] = dev; + rcu_assign_pointer(cp->ulp_ops[CNIC_ULP_L4], &cm_ulp_ops); + return 0; + +err_out: + cnic_cm_free_mem(dev); + return err; +} + +static int cnic_cm_shutdown(struct cnic_dev *dev) +{ + struct cnic_local *cp = dev->cnic_priv; + int i; + + cp->stop_cm(dev); + + if (!cp->csk_tbl) + return 0; + + for (i = 0; i < MAX_CM_SK_TBL_SZ; i++) { + struct cnic_sock *csk = &cp->csk_tbl[i]; + + clear_bit(SK_F_INUSE, &csk->flags); + cnic_cm_cleanup(csk); + } + cnic_cm_free_mem(dev); + + return 0; +} + +static void cnic_init_context(struct cnic_dev *dev, u32 cid) +{ + struct cnic_local *cp = dev->cnic_priv; + u32 cid_addr; + int i; + + if (CHIP_NUM(cp) == CHIP_NUM_5709) + return; + + cid_addr = GET_CID_ADDR(cid); + + for (i = 0; i < CTX_SIZE; i += 4) + cnic_ctx_wr(dev, cid_addr, i, 0); +} + +static int cnic_setup_5709_context(struct cnic_dev *dev, int valid) +{ + struct cnic_local *cp = dev->cnic_priv; + int ret = 0, i; + u32 valid_bit = valid ? BNX2_CTX_HOST_PAGE_TBL_DATA0_VALID : 0; + + if (CHIP_NUM(cp) != CHIP_NUM_5709) + return 0; + + for (i = 0; i < cp->ctx_blks; i++) { + int j; + u32 idx = cp->ctx_arr[i].cid / cp->cids_per_blk; + u32 val; + + memset(cp->ctx_arr[i].ctx, 0, BCM_PAGE_SIZE); + + CNIC_WR(dev, BNX2_CTX_HOST_PAGE_TBL_DATA0, + (cp->ctx_arr[i].mapping & 0xffffffff) | valid_bit); + CNIC_WR(dev, BNX2_CTX_HOST_PAGE_TBL_DATA1, + (u64) cp->ctx_arr[i].mapping >> 32); + CNIC_WR(dev, BNX2_CTX_HOST_PAGE_TBL_CTRL, idx | + BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ); + for (j = 0; j < 10; j++) { + + val = CNIC_RD(dev, BNX2_CTX_HOST_PAGE_TBL_CTRL); + if (!(val & BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ)) + break; + udelay(5); + } + if (val & BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ) { + ret = -EBUSY; + break; + } + } + return ret; +} + +static void cnic_free_irq(struct cnic_dev *dev) +{ + struct cnic_local *cp = dev->cnic_priv; + struct cnic_eth_dev *ethdev = cp->ethdev; + + if (ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX) { + cp->disable_int_sync(dev); + tasklet_disable(&cp->cnic_irq_task); + free_irq(ethdev->irq_arr[0].vector, dev); + } +} + +static int cnic_init_bnx2_irq(struct cnic_dev *dev) +{ + struct cnic_local *cp = dev->cnic_priv; + struct cnic_eth_dev *ethdev = cp->ethdev; + + if (ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX) { + int err, i = 0; + int sblk_num = cp->status_blk_num; + u32 base = ((sblk_num - 1) * BNX2_HC_SB_CONFIG_SIZE) + + BNX2_HC_SB_CONFIG_1; + + CNIC_WR(dev, base, BNX2_HC_SB_CONFIG_1_ONE_SHOT); + + CNIC_WR(dev, base + BNX2_HC_COMP_PROD_TRIP_OFF, (2 << 16) | 8); + CNIC_WR(dev, base + BNX2_HC_COM_TICKS_OFF, (64 << 16) | 220); + CNIC_WR(dev, base + BNX2_HC_CMD_TICKS_OFF, (64 << 16) | 220); + + cp->bnx2_status_blk = cp->status_blk; + cp->last_status_idx = cp->bnx2_status_blk->status_idx; + tasklet_init(&cp->cnic_irq_task, &cnic_service_bnx2_msix, + (unsigned long) dev); + err = request_irq(ethdev->irq_arr[0].vector, cnic_irq, 0, + "cnic", dev); + if (err) { + tasklet_disable(&cp->cnic_irq_task); + return err; + } + while (cp->bnx2_status_blk->status_completion_producer_index && + i < 10) { + CNIC_WR(dev, BNX2_HC_COALESCE_NOW, + 1 << (11 + sblk_num)); + udelay(10); + i++; + barrier(); + } + if (cp->bnx2_status_blk->status_completion_producer_index) { + cnic_free_irq(dev); + goto failed; + } + + } else { + struct status_block *sblk = cp->status_blk; + u32 hc_cmd = CNIC_RD(dev, BNX2_HC_COMMAND); + int i = 0; + + while (sblk->status_completion_producer_index && i < 10) { + CNIC_WR(dev, BNX2_HC_COMMAND, + hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT); + udelay(10); + i++; + barrier(); + } + if (sblk->status_completion_producer_index) + goto failed; + + } + return 0; + +failed: + printk(KERN_ERR PFX "%s: " "KCQ index not resetting to 0.\n", + dev->netdev->name); + return -EBUSY; +} + +static void cnic_enable_bnx2_int(struct cnic_dev *dev) +{ + struct cnic_local *cp = dev->cnic_priv; + struct cnic_eth_dev *ethdev = cp->ethdev; + + if (!(ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX)) + return; + + CNIC_WR(dev, BNX2_PCICFG_INT_ACK_CMD, cp->int_num | + BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | cp->last_status_idx); +} + +static void cnic_disable_bnx2_int_sync(struct cnic_dev *dev) +{ + struct cnic_local *cp = dev->cnic_priv; + struct cnic_eth_dev *ethdev = cp->ethdev; + + if (!(ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX)) + return; + + CNIC_WR(dev, BNX2_PCICFG_INT_ACK_CMD, cp->int_num | + BNX2_PCICFG_INT_ACK_CMD_MASK_INT); + CNIC_RD(dev, BNX2_PCICFG_INT_ACK_CMD); + synchronize_irq(ethdev->irq_arr[0].vector); +} + +static void cnic_init_bnx2_tx_ring(struct cnic_dev *dev) +{ + struct cnic_local *cp = dev->cnic_priv; + struct cnic_eth_dev *ethdev = cp->ethdev; + u32 cid_addr, tx_cid, sb_id; + u32 val, offset0, offset1, offset2, offset3; + int i; + struct tx_bd *txbd; + dma_addr_t buf_map; + struct status_block *s_blk = cp->status_blk; + + sb_id = cp->status_blk_num; + tx_cid = 20; + cnic_init_context(dev, tx_cid); + cnic_init_context(dev, tx_cid + 1); + cp->tx_cons_ptr = &s_blk->status_tx_quick_consumer_index2; + if (ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX) { + struct status_block_msix *sblk = cp->status_blk; + + tx_cid = TX_TSS_CID + sb_id - 1; + cnic_init_context(dev, tx_cid); + CNIC_WR(dev, BNX2_TSCH_TSS_CFG, (sb_id << 24) | + (TX_TSS_CID << 7)); + cp->tx_cons_ptr = &sblk->status_tx_quick_consumer_index; + } + cp->tx_cons = *cp->tx_cons_ptr; + + cid_addr = GET_CID_ADDR(tx_cid); + if (CHIP_NUM(cp) == CHIP_NUM_5709) { + u32 cid_addr2 = GET_CID_ADDR(tx_cid + 4) + 0x40; + + for (i = 0; i < PHY_CTX_SIZE; i += 4) + cnic_ctx_wr(dev, cid_addr2, i, 0); + + offset0 = BNX2_L2CTX_TYPE_XI; + offset1 = BNX2_L2CTX_CMD_TYPE_XI; + offset2 = BNX2_L2CTX_TBDR_BHADDR_HI_XI; + offset3 = BNX2_L2CTX_TBDR_BHADDR_LO_XI; + } else { + offset0 = BNX2_L2CTX_TYPE; + offset1 = BNX2_L2CTX_CMD_TYPE; + offset2 = BNX2_L2CTX_TBDR_BHADDR_HI; + offset3 = BNX2_L2CTX_TBDR_BHADDR_LO; + } + val = BNX2_L2CTX_TYPE_TYPE_L2 | BNX2_L2CTX_TYPE_SIZE_L2; + cnic_ctx_wr(dev, cid_addr, offset0, val); + + val = BNX2_L2CTX_CMD_TYPE_TYPE_L2 | (8 << 16); + cnic_ctx_wr(dev, cid_addr, offset1, val); + + txbd = (struct tx_bd *) cp->l2_ring; + + buf_map = cp->l2_buf_map; + for (i = 0; i < MAX_TX_DESC_CNT; i++, txbd++) { + txbd->tx_bd_haddr_hi = (u64) buf_map >> 32; + txbd->tx_bd_haddr_lo = (u64) buf_map & 0xffffffff; + } + val = (u64) cp->l2_ring_map >> 32; + cnic_ctx_wr(dev, cid_addr, offset2, val); + txbd->tx_bd_haddr_hi = val; + + val = (u64) cp->l2_ring_map & 0xffffffff; + cnic_ctx_wr(dev, cid_addr, offset3, val); + txbd->tx_bd_haddr_lo = val; +} + +static void cnic_init_bnx2_rx_ring(struct cnic_dev *dev) +{ + struct cnic_local *cp = dev->cnic_priv; + struct cnic_eth_dev *ethdev = cp->ethdev; + u32 cid_addr, sb_id, val, coal_reg, coal_val; + int i; + struct rx_bd *rxbd; + struct status_block *s_blk = cp->status_blk; + + sb_id = cp->status_blk_num; + cnic_init_context(dev, 2); + cp->rx_cons_ptr = &s_blk->status_rx_quick_consumer_index2; + coal_reg = BNX2_HC_COMMAND; + coal_val = CNIC_RD(dev, coal_reg); + if (ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX) { + struct status_block_msix *sblk = cp->status_blk; + + cp->rx_cons_ptr = &sblk->status_rx_quick_consumer_index; + coal_reg = BNX2_HC_COALESCE_NOW; + coal_val = 1 << (11 + sb_id); + } + i = 0; + while (!(*cp->rx_cons_ptr != 0) && i < 10) { + CNIC_WR(dev, coal_reg, coal_val); + udelay(10); + i++; + barrier(); + } + cp->rx_cons = *cp->rx_cons_ptr; + + cid_addr = GET_CID_ADDR(2); + val = BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE_VALUE | + BNX2_L2CTX_CTX_TYPE_SIZE_L2 | (0x02 << 8); + cnic_ctx_wr(dev, cid_addr, BNX2_L2CTX_CTX_TYPE, val); + + if (sb_id == 0) + val = 2 << BNX2_L2CTX_STATUSB_NUM_SHIFT; + else + val = BNX2_L2CTX_STATUSB_NUM(sb_id); + cnic_ctx_wr(dev, cid_addr, BNX2_L2CTX_HOST_BDIDX, val); + + rxbd = (struct rx_bd *) (cp->l2_ring + BCM_PAGE_SIZE); + for (i = 0; i < MAX_RX_DESC_CNT; i++, rxbd++) { + dma_addr_t buf_map; + int n = (i % cp->l2_rx_ring_size) + 1; + + buf_map = cp->l2_buf_map + (n * cp->l2_single_buf_size); + rxbd->rx_bd_len = cp->l2_single_buf_size; + rxbd->rx_bd_flags = RX_BD_FLAGS_START | RX_BD_FLAGS_END; + rxbd->rx_bd_haddr_hi = (u64) buf_map >> 32; + rxbd->rx_bd_haddr_lo = (u64) buf_map & 0xffffffff; + } + val = (u64) (cp->l2_ring_map + BCM_PAGE_SIZE) >> 32; + cnic_ctx_wr(dev, cid_addr, BNX2_L2CTX_NX_BDHADDR_HI, val); + rxbd->rx_bd_haddr_hi = val; + + val = (u64) (cp->l2_ring_map + BCM_PAGE_SIZE) & 0xffffffff; + cnic_ctx_wr(dev, cid_addr, BNX2_L2CTX_NX_BDHADDR_LO, val); + rxbd->rx_bd_haddr_lo = val; + + val = cnic_reg_rd_ind(dev, BNX2_RXP_SCRATCH_RXP_FLOOD); + cnic_reg_wr_ind(dev, BNX2_RXP_SCRATCH_RXP_FLOOD, val | (1 << 2)); +} + +static void cnic_shutdown_bnx2_rx_ring(struct cnic_dev *dev) +{ + struct kwqe *wqes[1], l2kwqe; + + memset(&l2kwqe, 0, sizeof(l2kwqe)); + wqes[0] = &l2kwqe; + l2kwqe.kwqe_op_flag = (L2_LAYER_CODE << KWQE_FLAGS_LAYER_SHIFT) | + (L2_KWQE_OPCODE_VALUE_FLUSH << + KWQE_OPCODE_SHIFT) | 2; + dev->submit_kwqes(dev, wqes, 1); +} + +static void cnic_set_bnx2_mac(struct cnic_dev *dev) +{ + struct cnic_local *cp = dev->cnic_priv; + u32 val; + + val = cp->func << 2; + + cp->shmem_base = cnic_reg_rd_ind(dev, BNX2_SHM_HDR_ADDR_0 + val); + + val = cnic_reg_rd_ind(dev, cp->shmem_base + + BNX2_PORT_HW_CFG_ISCSI_MAC_UPPER); + dev->mac_addr[0] = (u8) (val >> 8); + dev->mac_addr[1] = (u8) val; + + CNIC_WR(dev, BNX2_EMAC_MAC_MATCH4, val); + + val = cnic_reg_rd_ind(dev, cp->shmem_base + + BNX2_PORT_HW_CFG_ISCSI_MAC_LOWER); + dev->mac_addr[2] = (u8) (val >> 24); + dev->mac_addr[3] = (u8) (val >> 16); + dev->mac_addr[4] = (u8) (val >> 8); + dev->mac_addr[5] = (u8) val; + + CNIC_WR(dev, BNX2_EMAC_MAC_MATCH5, val); + + val = 4 | BNX2_RPM_SORT_USER2_BC_EN; + if (CHIP_NUM(cp) != CHIP_NUM_5709) + val |= BNX2_RPM_SORT_USER2_PROM_VLAN; + + CNIC_WR(dev, BNX2_RPM_SORT_USER2, 0x0); + CNIC_WR(dev, BNX2_RPM_SORT_USER2, val); + CNIC_WR(dev, BNX2_RPM_SORT_USER2, val | BNX2_RPM_SORT_USER2_ENA); +} + +static int cnic_start_bnx2_hw(struct cnic_dev *dev) +{ + struct cnic_local *cp = dev->cnic_priv; + struct cnic_eth_dev *ethdev = cp->ethdev; + struct status_block *sblk = cp->status_blk; + u32 val; + int err; + + cnic_set_bnx2_mac(dev); + + val = CNIC_RD(dev, BNX2_MQ_CONFIG); + val &= ~BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE; + if (BCM_PAGE_BITS > 12) + val |= (12 - 8) << 4; + else + val |= (BCM_PAGE_BITS - 8) << 4; + + CNIC_WR(dev, BNX2_MQ_CONFIG, val); + + CNIC_WR(dev, BNX2_HC_COMP_PROD_TRIP, (2 << 16) | 8); + CNIC_WR(dev, BNX2_HC_COM_TICKS, (64 << 16) | 220); + CNIC_WR(dev, BNX2_HC_CMD_TICKS, (64 << 16) | 220); + + err = cnic_setup_5709_context(dev, 1); + if (err) + return err; + + cnic_init_context(dev, KWQ_CID); + cnic_init_context(dev, KCQ_CID); + + cp->kwq_cid_addr = GET_CID_ADDR(KWQ_CID); + cp->kwq_io_addr = MB_GET_CID_ADDR(KWQ_CID) + L5_KRNLQ_HOST_QIDX; + + cp->max_kwq_idx = MAX_KWQ_IDX; + cp->kwq_prod_idx = 0; + cp->kwq_con_idx = 0; + cp->cnic_local_flags |= CNIC_LCL_FL_KWQ_INIT; + + if (CHIP_NUM(cp) == CHIP_NUM_5706 || CHIP_NUM(cp) == CHIP_NUM_5708) + cp->kwq_con_idx_ptr = &sblk->status_rx_quick_consumer_index15; + else + cp->kwq_con_idx_ptr = &sblk->status_cmd_consumer_index; + + /* Initialize the kernel work queue context. */ + val = KRNLQ_TYPE_TYPE_KRNLQ | KRNLQ_SIZE_TYPE_SIZE | + (BCM_PAGE_BITS - 8) | KRNLQ_FLAGS_QE_SELF_SEQ; + cnic_ctx_wr(dev, cp->kwq_cid_addr, L5_KRNLQ_TYPE, val); + + val = (BCM_PAGE_SIZE / sizeof(struct kwqe) - 1) << 16; + cnic_ctx_wr(dev, cp->kwq_cid_addr, L5_KRNLQ_QE_SELF_SEQ_MAX, val); + + val = ((BCM_PAGE_SIZE / sizeof(struct kwqe)) << 16) | KWQ_PAGE_CNT; + cnic_ctx_wr(dev, cp->kwq_cid_addr, L5_KRNLQ_PGTBL_NPAGES, val); + + val = (u32) ((u64) cp->kwq_info.pgtbl_map >> 32); + cnic_ctx_wr(dev, cp->kwq_cid_addr, L5_KRNLQ_PGTBL_HADDR_HI, val); + + val = (u32) cp->kwq_info.pgtbl_map; + cnic_ctx_wr(dev, cp->kwq_cid_addr, L5_KRNLQ_PGTBL_HADDR_LO, val); + + cp->kcq_cid_addr = GET_CID_ADDR(KCQ_CID); + cp->kcq_io_addr = MB_GET_CID_ADDR(KCQ_CID) + L5_KRNLQ_HOST_QIDX; + + cp->kcq_prod_idx = 0; + + /* Initialize the kernel complete queue context. */ + val = KRNLQ_TYPE_TYPE_KRNLQ | KRNLQ_SIZE_TYPE_SIZE | + (BCM_PAGE_BITS - 8) | KRNLQ_FLAGS_QE_SELF_SEQ; + cnic_ctx_wr(dev, cp->kcq_cid_addr, L5_KRNLQ_TYPE, val); + + val = (BCM_PAGE_SIZE / sizeof(struct kcqe) - 1) << 16; + cnic_ctx_wr(dev, cp->kcq_cid_addr, L5_KRNLQ_QE_SELF_SEQ_MAX, val); + + val = ((BCM_PAGE_SIZE / sizeof(struct kcqe)) << 16) | KCQ_PAGE_CNT; + cnic_ctx_wr(dev, cp->kcq_cid_addr, L5_KRNLQ_PGTBL_NPAGES, val); + + val = (u32) ((u64) cp->kcq_info.pgtbl_map >> 32); + cnic_ctx_wr(dev, cp->kcq_cid_addr, L5_KRNLQ_PGTBL_HADDR_HI, val); + + val = (u32) cp->kcq_info.pgtbl_map; + cnic_ctx_wr(dev, cp->kcq_cid_addr, L5_KRNLQ_PGTBL_HADDR_LO, val); + + cp->int_num = 0; + if (ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX) { + u32 sb_id = cp->status_blk_num; + u32 sb = BNX2_L2CTX_STATUSB_NUM(sb_id); + + cp->int_num = sb_id << BNX2_PCICFG_INT_ACK_CMD_INT_NUM_SHIFT; + cnic_ctx_wr(dev, cp->kwq_cid_addr, L5_KRNLQ_HOST_QIDX, sb); + cnic_ctx_wr(dev, cp->kcq_cid_addr, L5_KRNLQ_HOST_QIDX, sb); + } + + /* Enable Commnad Scheduler notification when we write to the + * host producer index of the kernel contexts. */ + CNIC_WR(dev, BNX2_MQ_KNL_CMD_MASK1, 2); + + /* Enable Command Scheduler notification when we write to either + * the Send Queue or Receive Queue producer indexes of the kernel + * bypass contexts. */ + CNIC_WR(dev, BNX2_MQ_KNL_BYP_CMD_MASK1, 7); + CNIC_WR(dev, BNX2_MQ_KNL_BYP_WRITE_MASK1, 7); + + /* Notify COM when the driver post an application buffer. */ + CNIC_WR(dev, BNX2_MQ_KNL_RX_V2P_MASK2, 0x2000); + + /* Set the CP and COM doorbells. These two processors polls the + * doorbell for a non zero value before running. This must be done + * after setting up the kernel queue contexts. */ + cnic_reg_wr_ind(dev, BNX2_CP_SCRATCH + 0x20, 1); + cnic_reg_wr_ind(dev, BNX2_COM_SCRATCH + 0x20, 1); + + cnic_init_bnx2_tx_ring(dev); + cnic_init_bnx2_rx_ring(dev); + + err = cnic_init_bnx2_irq(dev); + if (err) { + printk(KERN_ERR PFX "%s: cnic_init_irq failed\n", + dev->netdev->name); + cnic_reg_wr_ind(dev, BNX2_CP_SCRATCH + 0x20, 0); + cnic_reg_wr_ind(dev, BNX2_COM_SCRATCH + 0x20, 0); + return err; + } + + return 0; +} + +static int cnic_start_hw(struct cnic_dev *dev) +{ + struct cnic_local *cp = dev->cnic_priv; + struct cnic_eth_dev *ethdev = cp->ethdev; + int err; + + if (test_bit(CNIC_F_CNIC_UP, &dev->flags)) + return -EALREADY; + + err = ethdev->drv_register_cnic(dev->netdev, cp->cnic_ops, dev); + if (err) { + printk(KERN_ERR PFX "%s: register_cnic failed\n", + dev->netdev->name); + goto err2; + } + + dev->regview = ethdev->io_base; + cp->chip_id = ethdev->chip_id; + pci_dev_get(dev->pcidev); + cp->func = PCI_FUNC(dev->pcidev->devfn); + cp->status_blk = ethdev->irq_arr[0].status_blk; + cp->status_blk_num = ethdev->irq_arr[0].status_blk_num; + + err = cp->alloc_resc(dev); + if (err) { + printk(KERN_ERR PFX "%s: allocate resource failure\n", + dev->netdev->name); + goto err1; + } + + err = cp->start_hw(dev); + if (err) + goto err1; + + err = cnic_cm_open(dev); + if (err) + goto err1; + + set_bit(CNIC_F_CNIC_UP, &dev->flags); + + cp->enable_int(dev); + + return 0; + +err1: + ethdev->drv_unregister_cnic(dev->netdev); + cp->free_resc(dev); + pci_dev_put(dev->pcidev); +err2: + return err; +} + +static void cnic_stop_bnx2_hw(struct cnic_dev *dev) +{ + struct cnic_local *cp = dev->cnic_priv; + struct cnic_eth_dev *ethdev = cp->ethdev; + + cnic_disable_bnx2_int_sync(dev); + + cnic_reg_wr_ind(dev, BNX2_CP_SCRATCH + 0x20, 0); + cnic_reg_wr_ind(dev, BNX2_COM_SCRATCH + 0x20, 0); + + cnic_init_context(dev, KWQ_CID); + cnic_init_context(dev, KCQ_CID); + + cnic_setup_5709_context(dev, 0); + cnic_free_irq(dev); + + ethdev->drv_unregister_cnic(dev->netdev); + + cnic_free_resc(dev); +} + +static void cnic_stop_hw(struct cnic_dev *dev) +{ + if (test_bit(CNIC_F_CNIC_UP, &dev->flags)) { + struct cnic_local *cp = dev->cnic_priv; + + clear_bit(CNIC_F_CNIC_UP, &dev->flags); + rcu_assign_pointer(cp->ulp_ops[CNIC_ULP_L4], NULL); + synchronize_rcu(); + cnic_cm_shutdown(dev); + cp->stop_hw(dev); + pci_dev_put(dev->pcidev); + } +} + +static void cnic_free_dev(struct cnic_dev *dev) +{ + int i = 0; + + while ((atomic_read(&dev->ref_count) != 0) && i < 10) { + msleep(100); + i++; + } + if (atomic_read(&dev->ref_count) != 0) + printk(KERN_ERR PFX "%s: Failed waiting for ref count to go" + " to zero.\n", dev->netdev->name); + + printk(KERN_INFO PFX "Removed CNIC device: %s\n", dev->netdev->name); + dev_put(dev->netdev); + kfree(dev); +} + +static struct cnic_dev *cnic_alloc_dev(struct net_device *dev, + struct pci_dev *pdev) +{ + struct cnic_dev *cdev; + struct cnic_local *cp; + int alloc_size; + + alloc_size = sizeof(struct cnic_dev) + sizeof(struct cnic_local); + + cdev = kzalloc(alloc_size , GFP_KERNEL); + if (cdev == NULL) { + printk(KERN_ERR PFX "%s: allocate dev struct failure\n", + dev->name); + return NULL; + } + + cdev->netdev = dev; + cdev->cnic_priv = (char *)cdev + sizeof(struct cnic_dev); + cdev->register_device = cnic_register_device; + cdev->unregister_device = cnic_unregister_device; + cdev->iscsi_nl_msg_recv = cnic_iscsi_nl_msg_recv; + + cp = cdev->cnic_priv; + cp->dev = cdev; + cp->uio_dev = -1; + cp->l2_single_buf_size = 0x400; + cp->l2_rx_ring_size = 3; + + spin_lock_init(&cp->cnic_ulp_lock); + + printk(KERN_INFO PFX "Added CNIC device: %s\n", dev->name); + + return cdev; +} + +static struct cnic_dev *init_bnx2_cnic(struct net_device *dev) +{ + struct pci_dev *pdev; + struct cnic_dev *cdev; + struct cnic_local *cp; + struct cnic_eth_dev *ethdev = NULL; + struct cnic_eth_dev *(*probe)(struct net_device *) = NULL; + + probe = symbol_get(bnx2_cnic_probe); + if (probe) { + ethdev = (*probe)(dev); + symbol_put_addr(probe); + } + if (!ethdev) + return NULL; + + pdev = ethdev->pdev; + if (!pdev) + return NULL; + + dev_hold(dev); + pci_dev_get(pdev); + if (pdev->device == PCI_DEVICE_ID_NX2_5709 || + pdev->device == PCI_DEVICE_ID_NX2_5709S) { + u8 rev; + + pci_read_config_byte(pdev, PCI_REVISION_ID, &rev); + if (rev < 0x10) { + pci_dev_put(pdev); + goto cnic_err; + } + } + pci_dev_put(pdev); + + cdev = cnic_alloc_dev(dev, pdev); + if (cdev == NULL) + goto cnic_err; + + set_bit(CNIC_F_BNX2_CLASS, &cdev->flags); + cdev->submit_kwqes = cnic_submit_bnx2_kwqes; + + cp = cdev->cnic_priv; + cp->ethdev = ethdev; + cdev->pcidev = pdev; + + cp->cnic_ops = &cnic_bnx2_ops; + cp->start_hw = cnic_start_bnx2_hw; + cp->stop_hw = cnic_stop_bnx2_hw; + cp->setup_pgtbl = cnic_setup_page_tbl; + cp->alloc_resc = cnic_alloc_bnx2_resc; + cp->free_resc = cnic_free_resc; + cp->start_cm = cnic_cm_init_bnx2_hw; + cp->stop_cm = cnic_cm_stop_bnx2_hw; + cp->enable_int = cnic_enable_bnx2_int; + cp->disable_int_sync = cnic_disable_bnx2_int_sync; + cp->close_conn = cnic_close_bnx2_conn; + cp->next_idx = cnic_bnx2_next_idx; + cp->hw_idx = cnic_bnx2_hw_idx; + return cdev; + +cnic_err: + dev_put(dev); + return NULL; +} + +static struct cnic_dev *is_cnic_dev(struct net_device *dev) +{ + struct ethtool_drvinfo drvinfo; + struct cnic_dev *cdev = NULL; + + if (dev->ethtool_ops && dev->ethtool_ops->get_drvinfo) { + memset(&drvinfo, 0, sizeof(drvinfo)); + dev->ethtool_ops->get_drvinfo(dev, &drvinfo); + + if (!strcmp(drvinfo.driver, "bnx2")) + cdev = init_bnx2_cnic(dev); + if (cdev) { + write_lock(&cnic_dev_lock); + list_add(&cdev->list, &cnic_dev_list); + write_unlock(&cnic_dev_lock); + } + } + return cdev; +} + +/** + * netdev event handler + */ +static int cnic_netdev_event(struct notifier_block *this, unsigned long event, + void *ptr) +{ + struct net_device *netdev = ptr; + struct cnic_dev *dev; + int if_type; + int new_dev = 0; + + dev = cnic_from_netdev(netdev); + + if (!dev && (event == NETDEV_REGISTER || event == NETDEV_UP)) { + /* Check for the hot-plug device */ + dev = is_cnic_dev(netdev); + if (dev) { + new_dev = 1; + cnic_hold(dev); + } + } + if (dev) { + struct cnic_local *cp = dev->cnic_priv; + + if (new_dev) + cnic_ulp_init(dev); + else if (event == NETDEV_UNREGISTER) + cnic_ulp_exit(dev); + else if (event == NETDEV_UP) { + mutex_lock(&cnic_lock); + if (!cnic_start_hw(dev)) + cnic_ulp_start(dev); + mutex_unlock(&cnic_lock); + } + + rcu_read_lock(); + for (if_type = 0; if_type < MAX_CNIC_ULP_TYPE; if_type++) { + struct cnic_ulp_ops *ulp_ops; + void *ctx; + + ulp_ops = rcu_dereference(cp->ulp_ops[if_type]); + if (!ulp_ops || !ulp_ops->indicate_netevent) + continue; + + ctx = cp->ulp_handle[if_type]; + + ulp_ops->indicate_netevent(ctx, event); + } + rcu_read_unlock(); + + if (event == NETDEV_GOING_DOWN) { + mutex_lock(&cnic_lock); + cnic_ulp_stop(dev); + cnic_stop_hw(dev); + mutex_unlock(&cnic_lock); + } else if (event == NETDEV_UNREGISTER) { + write_lock(&cnic_dev_lock); + list_del_init(&dev->list); + write_unlock(&cnic_dev_lock); + + cnic_put(dev); + cnic_free_dev(dev); + goto done; + } + cnic_put(dev); + } +done: + return NOTIFY_DONE; +} + +static struct notifier_block cnic_netdev_notifier = { + .notifier_call = cnic_netdev_event +}; + +static void cnic_release(void) +{ + struct cnic_dev *dev; + + while (!list_empty(&cnic_dev_list)) { + dev = list_entry(cnic_dev_list.next, struct cnic_dev, list); + if (test_bit(CNIC_F_CNIC_UP, &dev->flags)) { + cnic_ulp_stop(dev); + cnic_stop_hw(dev); + } + + cnic_ulp_exit(dev); + list_del_init(&dev->list); + cnic_free_dev(dev); + } +} + +static int __init cnic_init(void) +{ + int rc = 0; + + printk(KERN_INFO "%s", version); + + rc = register_netdevice_notifier(&cnic_netdev_notifier); + if (rc) { + cnic_release(); + return rc; + } + + return 0; +} + +static void __exit cnic_exit(void) +{ + unregister_netdevice_notifier(&cnic_netdev_notifier); + cnic_release(); + return; +} + +module_init(cnic_init); +module_exit(cnic_exit); diff --git a/drivers/net/cnic.h b/drivers/net/cnic.h new file mode 100644 index 000000000000..5192d4a9df5a --- /dev/null +++ b/drivers/net/cnic.h @@ -0,0 +1,299 @@ +/* cnic.h: Broadcom CNIC core network driver. + * + * Copyright (c) 2006-2009 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation. + * + */ + + +#ifndef CNIC_H +#define CNIC_H + +#define KWQ_PAGE_CNT 4 +#define KCQ_PAGE_CNT 16 + +#define KWQ_CID 24 +#define KCQ_CID 25 + +/* + * krnlq_context definition + */ +#define L5_KRNLQ_FLAGS 0x00000000 +#define L5_KRNLQ_SIZE 0x00000000 +#define L5_KRNLQ_TYPE 0x00000000 +#define KRNLQ_FLAGS_PG_SZ (0xf<<0) +#define KRNLQ_FLAGS_PG_SZ_256 (0<<0) +#define KRNLQ_FLAGS_PG_SZ_512 (1<<0) +#define KRNLQ_FLAGS_PG_SZ_1K (2<<0) +#define KRNLQ_FLAGS_PG_SZ_2K (3<<0) +#define KRNLQ_FLAGS_PG_SZ_4K (4<<0) +#define KRNLQ_FLAGS_PG_SZ_8K (5<<0) +#define KRNLQ_FLAGS_PG_SZ_16K (6<<0) +#define KRNLQ_FLAGS_PG_SZ_32K (7<<0) +#define KRNLQ_FLAGS_PG_SZ_64K (8<<0) +#define KRNLQ_FLAGS_PG_SZ_128K (9<<0) +#define KRNLQ_FLAGS_PG_SZ_256K (10<<0) +#define KRNLQ_FLAGS_PG_SZ_512K (11<<0) +#define KRNLQ_FLAGS_PG_SZ_1M (12<<0) +#define KRNLQ_FLAGS_PG_SZ_2M (13<<0) +#define KRNLQ_FLAGS_QE_SELF_SEQ (1<<15) +#define KRNLQ_SIZE_TYPE_SIZE ((((0x28 + 0x1f) & ~0x1f) / 0x20) << 16) +#define KRNLQ_TYPE_TYPE (0xf<<28) +#define KRNLQ_TYPE_TYPE_EMPTY (0<<28) +#define KRNLQ_TYPE_TYPE_KRNLQ (6<<28) + +#define L5_KRNLQ_HOST_QIDX 0x00000004 +#define L5_KRNLQ_HOST_FW_QIDX 0x00000008 +#define L5_KRNLQ_NX_QE_SELF_SEQ 0x0000000c +#define L5_KRNLQ_QE_SELF_SEQ_MAX 0x0000000c +#define L5_KRNLQ_NX_QE_HADDR_HI 0x00000010 +#define L5_KRNLQ_NX_QE_HADDR_LO 0x00000014 +#define L5_KRNLQ_PGTBL_PGIDX 0x00000018 +#define L5_KRNLQ_NX_PG_QIDX 0x00000018 +#define L5_KRNLQ_PGTBL_NPAGES 0x0000001c +#define L5_KRNLQ_QIDX_INCR 0x0000001c +#define L5_KRNLQ_PGTBL_HADDR_HI 0x00000020 +#define L5_KRNLQ_PGTBL_HADDR_LO 0x00000024 + +#define BNX2_PG_CTX_MAP 0x1a0034 +#define BNX2_ISCSI_CTX_MAP 0x1a0074 + +struct cnic_redirect_entry { + struct dst_entry *old_dst; + struct dst_entry *new_dst; +}; + +#define MAX_COMPLETED_KCQE 64 + +#define MAX_CNIC_L5_CONTEXT 256 + +#define MAX_CM_SK_TBL_SZ MAX_CNIC_L5_CONTEXT + +#define MAX_ISCSI_TBL_SZ 256 + +#define CNIC_LOCAL_PORT_MIN 60000 +#define CNIC_LOCAL_PORT_MAX 61000 +#define CNIC_LOCAL_PORT_RANGE (CNIC_LOCAL_PORT_MAX - CNIC_LOCAL_PORT_MIN) + +#define KWQE_CNT (BCM_PAGE_SIZE / sizeof(struct kwqe)) +#define KCQE_CNT (BCM_PAGE_SIZE / sizeof(struct kcqe)) +#define MAX_KWQE_CNT (KWQE_CNT - 1) +#define MAX_KCQE_CNT (KCQE_CNT - 1) + +#define MAX_KWQ_IDX ((KWQ_PAGE_CNT * KWQE_CNT) - 1) +#define MAX_KCQ_IDX ((KCQ_PAGE_CNT * KCQE_CNT) - 1) + +#define KWQ_PG(x) (((x) & ~MAX_KWQE_CNT) >> (BCM_PAGE_BITS - 5)) +#define KWQ_IDX(x) ((x) & MAX_KWQE_CNT) + +#define KCQ_PG(x) (((x) & ~MAX_KCQE_CNT) >> (BCM_PAGE_BITS - 5)) +#define KCQ_IDX(x) ((x) & MAX_KCQE_CNT) + +#define BNX2X_NEXT_KCQE(x) (((x) & (MAX_KCQE_CNT - 1)) == \ + (MAX_KCQE_CNT - 1)) ? \ + (x) + 2 : (x) + 1 + +#define BNX2X_KWQ_DATA_PG(cp, x) ((x) / (cp)->kwq_16_data_pp) +#define BNX2X_KWQ_DATA_IDX(cp, x) ((x) % (cp)->kwq_16_data_pp) +#define BNX2X_KWQ_DATA(cp, x) \ + &(cp)->kwq_16_data[BNX2X_KWQ_DATA_PG(cp, x)][BNX2X_KWQ_DATA_IDX(cp, x)] + +#define DEF_IPID_COUNT 0xc001 + +#define DEF_KA_TIMEOUT 10000 +#define DEF_KA_INTERVAL 300000 +#define DEF_KA_MAX_PROBE_COUNT 3 +#define DEF_TOS 0 +#define DEF_TTL 0xfe +#define DEF_SND_SEQ_SCALE 0 +#define DEF_RCV_BUF 0xffff +#define DEF_SND_BUF 0xffff +#define DEF_SEED 0 +#define DEF_MAX_RT_TIME 500 +#define DEF_MAX_DA_COUNT 2 +#define DEF_SWS_TIMER 1000 +#define DEF_MAX_CWND 0xffff + +struct cnic_ctx { + u32 cid; + void *ctx; + dma_addr_t mapping; +}; + +#define BNX2_MAX_CID 0x2000 + +struct cnic_dma { + int num_pages; + void **pg_arr; + dma_addr_t *pg_map_arr; + int pgtbl_size; + u32 *pgtbl; + dma_addr_t pgtbl_map; +}; + +struct cnic_id_tbl { + spinlock_t lock; + u32 start; + u32 max; + u32 next; + unsigned long *table; +}; + +#define CNIC_KWQ16_DATA_SIZE 128 + +struct kwqe_16_data { + u8 data[CNIC_KWQ16_DATA_SIZE]; +}; + +struct cnic_iscsi { + struct cnic_dma task_array_info; + struct cnic_dma r2tq_info; + struct cnic_dma hq_info; +}; + +struct cnic_context { + u32 cid; + struct kwqe_16_data *kwqe_data; + dma_addr_t kwqe_data_mapping; + wait_queue_head_t waitq; + int wait_cond; + unsigned long timestamp; + u32 ctx_flags; +#define CTX_FL_OFFLD_START 0x00000001 + u8 ulp_proto_id; + union { + struct cnic_iscsi *iscsi; + } proto; +}; + +struct cnic_local { + + spinlock_t cnic_ulp_lock; + void *ulp_handle[MAX_CNIC_ULP_TYPE]; + unsigned long ulp_flags[MAX_CNIC_ULP_TYPE]; +#define ULP_F_INIT 0 +#define ULP_F_START 1 + struct cnic_ulp_ops *ulp_ops[MAX_CNIC_ULP_TYPE]; + + /* protected by ulp_lock */ + u32 cnic_local_flags; +#define CNIC_LCL_FL_KWQ_INIT 0x00000001 + + struct cnic_dev *dev; + + struct cnic_eth_dev *ethdev; + + void *l2_ring; + dma_addr_t l2_ring_map; + int l2_ring_size; + int l2_rx_ring_size; + + void *l2_buf; + dma_addr_t l2_buf_map; + int l2_buf_size; + int l2_single_buf_size; + + u16 *rx_cons_ptr; + u16 *tx_cons_ptr; + u16 rx_cons; + u16 tx_cons; + + u32 kwq_cid_addr; + u32 kcq_cid_addr; + + struct cnic_dma kwq_info; + struct kwqe **kwq; + + struct cnic_dma kwq_16_data_info; + + u16 max_kwq_idx; + + u16 kwq_prod_idx; + u32 kwq_io_addr; + + u16 *kwq_con_idx_ptr; + u16 kwq_con_idx; + + struct cnic_dma kcq_info; + struct kcqe **kcq; + + u16 kcq_prod_idx; + u32 kcq_io_addr; + + void *status_blk; + struct status_block_msix *bnx2_status_blk; + struct host_status_block *bnx2x_status_blk; + + u32 status_blk_num; + u32 int_num; + u32 last_status_idx; + struct tasklet_struct cnic_irq_task; + + struct kcqe *completed_kcq[MAX_COMPLETED_KCQE]; + + struct cnic_sock *csk_tbl; + struct cnic_id_tbl csk_port_tbl; + + struct cnic_dma conn_buf_info; + struct cnic_dma gbl_buf_info; + + struct cnic_iscsi *iscsi_tbl; + struct cnic_context *ctx_tbl; + struct cnic_id_tbl cid_tbl; + int max_iscsi_conn; + atomic_t iscsi_conn; + + /* per connection parameters */ + int num_iscsi_tasks; + int num_ccells; + int task_array_size; + int r2tq_size; + int hq_size; + int num_cqs; + + struct cnic_ctx *ctx_arr; + int ctx_blks; + int ctx_blk_size; + int cids_per_blk; + + u32 chip_id; + int func; + u32 shmem_base; + + u32 uio_dev; + struct uio_info *cnic_uinfo; + + struct cnic_ops *cnic_ops; + int (*start_hw)(struct cnic_dev *); + void (*stop_hw)(struct cnic_dev *); + void (*setup_pgtbl)(struct cnic_dev *, + struct cnic_dma *); + int (*alloc_resc)(struct cnic_dev *); + void (*free_resc)(struct cnic_dev *); + int (*start_cm)(struct cnic_dev *); + void (*stop_cm)(struct cnic_dev *); + void (*enable_int)(struct cnic_dev *); + void (*disable_int_sync)(struct cnic_dev *); + void (*ack_int)(struct cnic_dev *); + void (*close_conn)(struct cnic_sock *, u32 opcode); + u16 (*next_idx)(u16); + u16 (*hw_idx)(u16); +}; + +struct bnx2x_bd_chain_next { + u32 addr_lo; + u32 addr_hi; + u8 reserved[8]; +}; + +#define ISCSI_RAMROD_CMD_ID_UPDATE_CONN (ISCSI_KCQE_OPCODE_UPDATE_CONN) +#define ISCSI_RAMROD_CMD_ID_INIT (ISCSI_KCQE_OPCODE_INIT) + +#define CDU_REGION_NUMBER_XCM_AG 2 +#define CDU_REGION_NUMBER_UCM_AG 4 + +#endif + diff --git a/drivers/net/cnic_defs.h b/drivers/net/cnic_defs.h new file mode 100644 index 000000000000..cee80f694457 --- /dev/null +++ b/drivers/net/cnic_defs.h @@ -0,0 +1,580 @@ + +/* cnic.c: Broadcom CNIC core network driver. + * + * Copyright (c) 2006-2009 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation. + * + */ + +#ifndef CNIC_DEFS_H +#define CNIC_DEFS_H + +/* KWQ (kernel work queue) request op codes */ +#define L2_KWQE_OPCODE_VALUE_FLUSH (4) + +#define L4_KWQE_OPCODE_VALUE_CONNECT1 (50) +#define L4_KWQE_OPCODE_VALUE_CONNECT2 (51) +#define L4_KWQE_OPCODE_VALUE_CONNECT3 (52) +#define L4_KWQE_OPCODE_VALUE_RESET (53) +#define L4_KWQE_OPCODE_VALUE_CLOSE (54) +#define L4_KWQE_OPCODE_VALUE_UPDATE_SECRET (60) +#define L4_KWQE_OPCODE_VALUE_INIT_ULP (61) + +#define L4_KWQE_OPCODE_VALUE_OFFLOAD_PG (1) +#define L4_KWQE_OPCODE_VALUE_UPDATE_PG (9) +#define L4_KWQE_OPCODE_VALUE_UPLOAD_PG (14) + +#define L5CM_RAMROD_CMD_ID_BASE (0x80) +#define L5CM_RAMROD_CMD_ID_TCP_CONNECT (L5CM_RAMROD_CMD_ID_BASE + 3) +#define L5CM_RAMROD_CMD_ID_CLOSE (L5CM_RAMROD_CMD_ID_BASE + 12) +#define L5CM_RAMROD_CMD_ID_ABORT (L5CM_RAMROD_CMD_ID_BASE + 13) +#define L5CM_RAMROD_CMD_ID_SEARCHER_DELETE (L5CM_RAMROD_CMD_ID_BASE + 14) +#define L5CM_RAMROD_CMD_ID_TERMINATE_OFFLOAD (L5CM_RAMROD_CMD_ID_BASE + 15) + +/* KCQ (kernel completion queue) response op codes */ +#define L4_KCQE_OPCODE_VALUE_CLOSE_COMP (53) +#define L4_KCQE_OPCODE_VALUE_RESET_COMP (54) +#define L4_KCQE_OPCODE_VALUE_FW_TCP_UPDATE (55) +#define L4_KCQE_OPCODE_VALUE_CONNECT_COMPLETE (56) +#define L4_KCQE_OPCODE_VALUE_RESET_RECEIVED (57) +#define L4_KCQE_OPCODE_VALUE_CLOSE_RECEIVED (58) +#define L4_KCQE_OPCODE_VALUE_INIT_ULP (61) + +#define L4_KCQE_OPCODE_VALUE_OFFLOAD_PG (1) +#define L4_KCQE_OPCODE_VALUE_UPDATE_PG (9) +#define L4_KCQE_OPCODE_VALUE_UPLOAD_PG (14) + +/* KCQ (kernel completion queue) completion status */ +#define L4_KCQE_COMPLETION_STATUS_SUCCESS (0) +#define L4_KCQE_COMPLETION_STATUS_TIMEOUT (0x93) + +#define L4_LAYER_CODE (4) +#define L2_LAYER_CODE (2) + +/* + * L4 KCQ CQE + */ +struct l4_kcq { + u32 cid; + u32 pg_cid; + u32 conn_id; + u32 pg_host_opaque; +#if defined(__BIG_ENDIAN) + u16 status; + u16 reserved1; +#elif defined(__LITTLE_ENDIAN) + u16 reserved1; + u16 status; +#endif + u32 reserved2[2]; +#if defined(__BIG_ENDIAN) + u8 flags; +#define L4_KCQ_RESERVED3 (0x7<<0) +#define L4_KCQ_RESERVED3_SHIFT 0 +#define L4_KCQ_RAMROD_COMPLETION (0x1<<3) /* Everest only */ +#define L4_KCQ_RAMROD_COMPLETION_SHIFT 3 +#define L4_KCQ_LAYER_CODE (0x7<<4) +#define L4_KCQ_LAYER_CODE_SHIFT 4 +#define L4_KCQ_RESERVED4 (0x1<<7) +#define L4_KCQ_RESERVED4_SHIFT 7 + u8 op_code; + u16 qe_self_seq; +#elif defined(__LITTLE_ENDIAN) + u16 qe_self_seq; + u8 op_code; + u8 flags; +#define L4_KCQ_RESERVED3 (0xF<<0) +#define L4_KCQ_RESERVED3_SHIFT 0 +#define L4_KCQ_RAMROD_COMPLETION (0x1<<3) /* Everest only */ +#define L4_KCQ_RAMROD_COMPLETION_SHIFT 3 +#define L4_KCQ_LAYER_CODE (0x7<<4) +#define L4_KCQ_LAYER_CODE_SHIFT 4 +#define L4_KCQ_RESERVED4 (0x1<<7) +#define L4_KCQ_RESERVED4_SHIFT 7 +#endif +}; + + +/* + * L4 KCQ CQE PG upload + */ +struct l4_kcq_upload_pg { + u32 pg_cid; +#if defined(__BIG_ENDIAN) + u16 pg_status; + u16 pg_ipid_count; +#elif defined(__LITTLE_ENDIAN) + u16 pg_ipid_count; + u16 pg_status; +#endif + u32 reserved1[5]; +#if defined(__BIG_ENDIAN) + u8 flags; +#define L4_KCQ_UPLOAD_PG_RESERVED3 (0xF<<0) +#define L4_KCQ_UPLOAD_PG_RESERVED3_SHIFT 0 +#define L4_KCQ_UPLOAD_PG_LAYER_CODE (0x7<<4) +#define L4_KCQ_UPLOAD_PG_LAYER_CODE_SHIFT 4 +#define L4_KCQ_UPLOAD_PG_RESERVED4 (0x1<<7) +#define L4_KCQ_UPLOAD_PG_RESERVED4_SHIFT 7 + u8 op_code; + u16 qe_self_seq; +#elif defined(__LITTLE_ENDIAN) + u16 qe_self_seq; + u8 op_code; + u8 flags; +#define L4_KCQ_UPLOAD_PG_RESERVED3 (0xF<<0) +#define L4_KCQ_UPLOAD_PG_RESERVED3_SHIFT 0 +#define L4_KCQ_UPLOAD_PG_LAYER_CODE (0x7<<4) +#define L4_KCQ_UPLOAD_PG_LAYER_CODE_SHIFT 4 +#define L4_KCQ_UPLOAD_PG_RESERVED4 (0x1<<7) +#define L4_KCQ_UPLOAD_PG_RESERVED4_SHIFT 7 +#endif +}; + + +/* + * Gracefully close the connection request + */ +struct l4_kwq_close_req { +#if defined(__BIG_ENDIAN) + u8 flags; +#define L4_KWQ_CLOSE_REQ_RESERVED1 (0xF<<0) +#define L4_KWQ_CLOSE_REQ_RESERVED1_SHIFT 0 +#define L4_KWQ_CLOSE_REQ_LAYER_CODE (0x7<<4) +#define L4_KWQ_CLOSE_REQ_LAYER_CODE_SHIFT 4 +#define L4_KWQ_CLOSE_REQ_LINKED_WITH_NEXT (0x1<<7) +#define L4_KWQ_CLOSE_REQ_LINKED_WITH_NEXT_SHIFT 7 + u8 op_code; + u16 reserved0; +#elif defined(__LITTLE_ENDIAN) + u16 reserved0; + u8 op_code; + u8 flags; +#define L4_KWQ_CLOSE_REQ_RESERVED1 (0xF<<0) +#define L4_KWQ_CLOSE_REQ_RESERVED1_SHIFT 0 +#define L4_KWQ_CLOSE_REQ_LAYER_CODE (0x7<<4) +#define L4_KWQ_CLOSE_REQ_LAYER_CODE_SHIFT 4 +#define L4_KWQ_CLOSE_REQ_LINKED_WITH_NEXT (0x1<<7) +#define L4_KWQ_CLOSE_REQ_LINKED_WITH_NEXT_SHIFT 7 +#endif + u32 cid; + u32 reserved2[6]; +}; + + +/* + * The first request to be passed in order to establish connection in option2 + */ +struct l4_kwq_connect_req1 { +#if defined(__BIG_ENDIAN) + u8 flags; +#define L4_KWQ_CONNECT_REQ1_RESERVED1 (0xF<<0) +#define L4_KWQ_CONNECT_REQ1_RESERVED1_SHIFT 0 +#define L4_KWQ_CONNECT_REQ1_LAYER_CODE (0x7<<4) +#define L4_KWQ_CONNECT_REQ1_LAYER_CODE_SHIFT 4 +#define L4_KWQ_CONNECT_REQ1_LINKED_WITH_NEXT (0x1<<7) +#define L4_KWQ_CONNECT_REQ1_LINKED_WITH_NEXT_SHIFT 7 + u8 op_code; + u8 reserved0; + u8 conn_flags; +#define L4_KWQ_CONNECT_REQ1_IS_PG_HOST_OPAQUE (0x1<<0) +#define L4_KWQ_CONNECT_REQ1_IS_PG_HOST_OPAQUE_SHIFT 0 +#define L4_KWQ_CONNECT_REQ1_IP_V6 (0x1<<1) +#define L4_KWQ_CONNECT_REQ1_IP_V6_SHIFT 1 +#define L4_KWQ_CONNECT_REQ1_PASSIVE_FLAG (0x1<<2) +#define L4_KWQ_CONNECT_REQ1_PASSIVE_FLAG_SHIFT 2 +#define L4_KWQ_CONNECT_REQ1_RSRV (0x1F<<3) +#define L4_KWQ_CONNECT_REQ1_RSRV_SHIFT 3 +#elif defined(__LITTLE_ENDIAN) + u8 conn_flags; +#define L4_KWQ_CONNECT_REQ1_IS_PG_HOST_OPAQUE (0x1<<0) +#define L4_KWQ_CONNECT_REQ1_IS_PG_HOST_OPAQUE_SHIFT 0 +#define L4_KWQ_CONNECT_REQ1_IP_V6 (0x1<<1) +#define L4_KWQ_CONNECT_REQ1_IP_V6_SHIFT 1 +#define L4_KWQ_CONNECT_REQ1_PASSIVE_FLAG (0x1<<2) +#define L4_KWQ_CONNECT_REQ1_PASSIVE_FLAG_SHIFT 2 +#define L4_KWQ_CONNECT_REQ1_RSRV (0x1F<<3) +#define L4_KWQ_CONNECT_REQ1_RSRV_SHIFT 3 + u8 reserved0; + u8 op_code; + u8 flags; +#define L4_KWQ_CONNECT_REQ1_RESERVED1 (0xF<<0) +#define L4_KWQ_CONNECT_REQ1_RESERVED1_SHIFT 0 +#define L4_KWQ_CONNECT_REQ1_LAYER_CODE (0x7<<4) +#define L4_KWQ_CONNECT_REQ1_LAYER_CODE_SHIFT 4 +#define L4_KWQ_CONNECT_REQ1_LINKED_WITH_NEXT (0x1<<7) +#define L4_KWQ_CONNECT_REQ1_LINKED_WITH_NEXT_SHIFT 7 +#endif + u32 cid; + u32 pg_cid; + u32 src_ip; + u32 dst_ip; +#if defined(__BIG_ENDIAN) + u16 dst_port; + u16 src_port; +#elif defined(__LITTLE_ENDIAN) + u16 src_port; + u16 dst_port; +#endif +#if defined(__BIG_ENDIAN) + u8 rsrv1[3]; + u8 tcp_flags; +#define L4_KWQ_CONNECT_REQ1_NO_DELAY_ACK (0x1<<0) +#define L4_KWQ_CONNECT_REQ1_NO_DELAY_ACK_SHIFT 0 +#define L4_KWQ_CONNECT_REQ1_KEEP_ALIVE (0x1<<1) +#define L4_KWQ_CONNECT_REQ1_KEEP_ALIVE_SHIFT 1 +#define L4_KWQ_CONNECT_REQ1_NAGLE_ENABLE (0x1<<2) +#define L4_KWQ_CONNECT_REQ1_NAGLE_ENABLE_SHIFT 2 +#define L4_KWQ_CONNECT_REQ1_TIME_STAMP (0x1<<3) +#define L4_KWQ_CONNECT_REQ1_TIME_STAMP_SHIFT 3 +#define L4_KWQ_CONNECT_REQ1_SACK (0x1<<4) +#define L4_KWQ_CONNECT_REQ1_SACK_SHIFT 4 +#define L4_KWQ_CONNECT_REQ1_SEG_SCALING (0x1<<5) +#define L4_KWQ_CONNECT_REQ1_SEG_SCALING_SHIFT 5 +#define L4_KWQ_CONNECT_REQ1_RESERVED2 (0x3<<6) +#define L4_KWQ_CONNECT_REQ1_RESERVED2_SHIFT 6 +#elif defined(__LITTLE_ENDIAN) + u8 tcp_flags; +#define L4_KWQ_CONNECT_REQ1_NO_DELAY_ACK (0x1<<0) +#define L4_KWQ_CONNECT_REQ1_NO_DELAY_ACK_SHIFT 0 +#define L4_KWQ_CONNECT_REQ1_KEEP_ALIVE (0x1<<1) +#define L4_KWQ_CONNECT_REQ1_KEEP_ALIVE_SHIFT 1 +#define L4_KWQ_CONNECT_REQ1_NAGLE_ENABLE (0x1<<2) +#define L4_KWQ_CONNECT_REQ1_NAGLE_ENABLE_SHIFT 2 +#define L4_KWQ_CONNECT_REQ1_TIME_STAMP (0x1<<3) +#define L4_KWQ_CONNECT_REQ1_TIME_STAMP_SHIFT 3 +#define L4_KWQ_CONNECT_REQ1_SACK (0x1<<4) +#define L4_KWQ_CONNECT_REQ1_SACK_SHIFT 4 +#define L4_KWQ_CONNECT_REQ1_SEG_SCALING (0x1<<5) +#define L4_KWQ_CONNECT_REQ1_SEG_SCALING_SHIFT 5 +#define L4_KWQ_CONNECT_REQ1_RESERVED2 (0x3<<6) +#define L4_KWQ_CONNECT_REQ1_RESERVED2_SHIFT 6 + u8 rsrv1[3]; +#endif + u32 rsrv2; +}; + + +/* + * The second ( optional )request to be passed in order to establish + * connection in option2 - for IPv6 only + */ +struct l4_kwq_connect_req2 { +#if defined(__BIG_ENDIAN) + u8 flags; +#define L4_KWQ_CONNECT_REQ2_RESERVED1 (0xF<<0) +#define L4_KWQ_CONNECT_REQ2_RESERVED1_SHIFT 0 +#define L4_KWQ_CONNECT_REQ2_LAYER_CODE (0x7<<4) +#define L4_KWQ_CONNECT_REQ2_LAYER_CODE_SHIFT 4 +#define L4_KWQ_CONNECT_REQ2_LINKED_WITH_NEXT (0x1<<7) +#define L4_KWQ_CONNECT_REQ2_LINKED_WITH_NEXT_SHIFT 7 + u8 op_code; + u8 reserved0; + u8 rsrv; +#elif defined(__LITTLE_ENDIAN) + u8 rsrv; + u8 reserved0; + u8 op_code; + u8 flags; +#define L4_KWQ_CONNECT_REQ2_RESERVED1 (0xF<<0) +#define L4_KWQ_CONNECT_REQ2_RESERVED1_SHIFT 0 +#define L4_KWQ_CONNECT_REQ2_LAYER_CODE (0x7<<4) +#define L4_KWQ_CONNECT_REQ2_LAYER_CODE_SHIFT 4 +#define L4_KWQ_CONNECT_REQ2_LINKED_WITH_NEXT (0x1<<7) +#define L4_KWQ_CONNECT_REQ2_LINKED_WITH_NEXT_SHIFT 7 +#endif + u32 reserved2; + u32 src_ip_v6_2; + u32 src_ip_v6_3; + u32 src_ip_v6_4; + u32 dst_ip_v6_2; + u32 dst_ip_v6_3; + u32 dst_ip_v6_4; +}; + + +/* + * The third ( and last )request to be passed in order to establish + * connection in option2 + */ +struct l4_kwq_connect_req3 { +#if defined(__BIG_ENDIAN) + u8 flags; +#define L4_KWQ_CONNECT_REQ3_RESERVED1 (0xF<<0) +#define L4_KWQ_CONNECT_REQ3_RESERVED1_SHIFT 0 +#define L4_KWQ_CONNECT_REQ3_LAYER_CODE (0x7<<4) +#define L4_KWQ_CONNECT_REQ3_LAYER_CODE_SHIFT 4 +#define L4_KWQ_CONNECT_REQ3_LINKED_WITH_NEXT (0x1<<7) +#define L4_KWQ_CONNECT_REQ3_LINKED_WITH_NEXT_SHIFT 7 + u8 op_code; + u16 reserved0; +#elif defined(__LITTLE_ENDIAN) + u16 reserved0; + u8 op_code; + u8 flags; +#define L4_KWQ_CONNECT_REQ3_RESERVED1 (0xF<<0) +#define L4_KWQ_CONNECT_REQ3_RESERVED1_SHIFT 0 +#define L4_KWQ_CONNECT_REQ3_LAYER_CODE (0x7<<4) +#define L4_KWQ_CONNECT_REQ3_LAYER_CODE_SHIFT 4 +#define L4_KWQ_CONNECT_REQ3_LINKED_WITH_NEXT (0x1<<7) +#define L4_KWQ_CONNECT_REQ3_LINKED_WITH_NEXT_SHIFT 7 +#endif + u32 ka_timeout; + u32 ka_interval ; +#if defined(__BIG_ENDIAN) + u8 snd_seq_scale; + u8 ttl; + u8 tos; + u8 ka_max_probe_count; +#elif defined(__LITTLE_ENDIAN) + u8 ka_max_probe_count; + u8 tos; + u8 ttl; + u8 snd_seq_scale; +#endif +#if defined(__BIG_ENDIAN) + u16 pmtu; + u16 mss; +#elif defined(__LITTLE_ENDIAN) + u16 mss; + u16 pmtu; +#endif + u32 rcv_buf; + u32 snd_buf; + u32 seed; +}; + + +/* + * a KWQE request to offload a PG connection + */ +struct l4_kwq_offload_pg { +#if defined(__BIG_ENDIAN) + u8 flags; +#define L4_KWQ_OFFLOAD_PG_RESERVED1 (0xF<<0) +#define L4_KWQ_OFFLOAD_PG_RESERVED1_SHIFT 0 +#define L4_KWQ_OFFLOAD_PG_LAYER_CODE (0x7<<4) +#define L4_KWQ_OFFLOAD_PG_LAYER_CODE_SHIFT 4 +#define L4_KWQ_OFFLOAD_PG_LINKED_WITH_NEXT (0x1<<7) +#define L4_KWQ_OFFLOAD_PG_LINKED_WITH_NEXT_SHIFT 7 + u8 op_code; + u16 reserved0; +#elif defined(__LITTLE_ENDIAN) + u16 reserved0; + u8 op_code; + u8 flags; +#define L4_KWQ_OFFLOAD_PG_RESERVED1 (0xF<<0) +#define L4_KWQ_OFFLOAD_PG_RESERVED1_SHIFT 0 +#define L4_KWQ_OFFLOAD_PG_LAYER_CODE (0x7<<4) +#define L4_KWQ_OFFLOAD_PG_LAYER_CODE_SHIFT 4 +#define L4_KWQ_OFFLOAD_PG_LINKED_WITH_NEXT (0x1<<7) +#define L4_KWQ_OFFLOAD_PG_LINKED_WITH_NEXT_SHIFT 7 +#endif +#if defined(__BIG_ENDIAN) + u8 l2hdr_nbytes; + u8 pg_flags; +#define L4_KWQ_OFFLOAD_PG_SNAP_ENCAP (0x1<<0) +#define L4_KWQ_OFFLOAD_PG_SNAP_ENCAP_SHIFT 0 +#define L4_KWQ_OFFLOAD_PG_VLAN_TAGGING (0x1<<1) +#define L4_KWQ_OFFLOAD_PG_VLAN_TAGGING_SHIFT 1 +#define L4_KWQ_OFFLOAD_PG_RESERVED2 (0x3F<<2) +#define L4_KWQ_OFFLOAD_PG_RESERVED2_SHIFT 2 + u8 da0; + u8 da1; +#elif defined(__LITTLE_ENDIAN) + u8 da1; + u8 da0; + u8 pg_flags; +#define L4_KWQ_OFFLOAD_PG_SNAP_ENCAP (0x1<<0) +#define L4_KWQ_OFFLOAD_PG_SNAP_ENCAP_SHIFT 0 +#define L4_KWQ_OFFLOAD_PG_VLAN_TAGGING (0x1<<1) +#define L4_KWQ_OFFLOAD_PG_VLAN_TAGGING_SHIFT 1 +#define L4_KWQ_OFFLOAD_PG_RESERVED2 (0x3F<<2) +#define L4_KWQ_OFFLOAD_PG_RESERVED2_SHIFT 2 + u8 l2hdr_nbytes; +#endif +#if defined(__BIG_ENDIAN) + u8 da2; + u8 da3; + u8 da4; + u8 da5; +#elif defined(__LITTLE_ENDIAN) + u8 da5; + u8 da4; + u8 da3; + u8 da2; +#endif +#if defined(__BIG_ENDIAN) + u8 sa0; + u8 sa1; + u8 sa2; + u8 sa3; +#elif defined(__LITTLE_ENDIAN) + u8 sa3; + u8 sa2; + u8 sa1; + u8 sa0; +#endif +#if defined(__BIG_ENDIAN) + u8 sa4; + u8 sa5; + u16 etype; +#elif defined(__LITTLE_ENDIAN) + u16 etype; + u8 sa5; + u8 sa4; +#endif +#if defined(__BIG_ENDIAN) + u16 vlan_tag; + u16 ipid_start; +#elif defined(__LITTLE_ENDIAN) + u16 ipid_start; + u16 vlan_tag; +#endif +#if defined(__BIG_ENDIAN) + u16 ipid_count; + u16 reserved3; +#elif defined(__LITTLE_ENDIAN) + u16 reserved3; + u16 ipid_count; +#endif + u32 host_opaque; +}; + + +/* + * Abortively close the connection request + */ +struct l4_kwq_reset_req { +#if defined(__BIG_ENDIAN) + u8 flags; +#define L4_KWQ_RESET_REQ_RESERVED1 (0xF<<0) +#define L4_KWQ_RESET_REQ_RESERVED1_SHIFT 0 +#define L4_KWQ_RESET_REQ_LAYER_CODE (0x7<<4) +#define L4_KWQ_RESET_REQ_LAYER_CODE_SHIFT 4 +#define L4_KWQ_RESET_REQ_LINKED_WITH_NEXT (0x1<<7) +#define L4_KWQ_RESET_REQ_LINKED_WITH_NEXT_SHIFT 7 + u8 op_code; + u16 reserved0; +#elif defined(__LITTLE_ENDIAN) + u16 reserved0; + u8 op_code; + u8 flags; +#define L4_KWQ_RESET_REQ_RESERVED1 (0xF<<0) +#define L4_KWQ_RESET_REQ_RESERVED1_SHIFT 0 +#define L4_KWQ_RESET_REQ_LAYER_CODE (0x7<<4) +#define L4_KWQ_RESET_REQ_LAYER_CODE_SHIFT 4 +#define L4_KWQ_RESET_REQ_LINKED_WITH_NEXT (0x1<<7) +#define L4_KWQ_RESET_REQ_LINKED_WITH_NEXT_SHIFT 7 +#endif + u32 cid; + u32 reserved2[6]; +}; + + +/* + * a KWQE request to update a PG connection + */ +struct l4_kwq_update_pg { +#if defined(__BIG_ENDIAN) + u8 flags; +#define L4_KWQ_UPDATE_PG_RESERVED1 (0xF<<0) +#define L4_KWQ_UPDATE_PG_RESERVED1_SHIFT 0 +#define L4_KWQ_UPDATE_PG_LAYER_CODE (0x7<<4) +#define L4_KWQ_UPDATE_PG_LAYER_CODE_SHIFT 4 +#define L4_KWQ_UPDATE_PG_LINKED_WITH_NEXT (0x1<<7) +#define L4_KWQ_UPDATE_PG_LINKED_WITH_NEXT_SHIFT 7 + u8 opcode; + u16 oper16; +#elif defined(__LITTLE_ENDIAN) + u16 oper16; + u8 opcode; + u8 flags; +#define L4_KWQ_UPDATE_PG_RESERVED1 (0xF<<0) +#define L4_KWQ_UPDATE_PG_RESERVED1_SHIFT 0 +#define L4_KWQ_UPDATE_PG_LAYER_CODE (0x7<<4) +#define L4_KWQ_UPDATE_PG_LAYER_CODE_SHIFT 4 +#define L4_KWQ_UPDATE_PG_LINKED_WITH_NEXT (0x1<<7) +#define L4_KWQ_UPDATE_PG_LINKED_WITH_NEXT_SHIFT 7 +#endif + u32 pg_cid; + u32 pg_host_opaque; +#if defined(__BIG_ENDIAN) + u8 pg_valids; +#define L4_KWQ_UPDATE_PG_VALIDS_IPID_COUNT (0x1<<0) +#define L4_KWQ_UPDATE_PG_VALIDS_IPID_COUNT_SHIFT 0 +#define L4_KWQ_UPDATE_PG_VALIDS_DA (0x1<<1) +#define L4_KWQ_UPDATE_PG_VALIDS_DA_SHIFT 1 +#define L4_KWQ_UPDATE_PG_RESERVERD2 (0x3F<<2) +#define L4_KWQ_UPDATE_PG_RESERVERD2_SHIFT 2 + u8 pg_unused_a; + u16 pg_ipid_count; +#elif defined(__LITTLE_ENDIAN) + u16 pg_ipid_count; + u8 pg_unused_a; + u8 pg_valids; +#define L4_KWQ_UPDATE_PG_VALIDS_IPID_COUNT (0x1<<0) +#define L4_KWQ_UPDATE_PG_VALIDS_IPID_COUNT_SHIFT 0 +#define L4_KWQ_UPDATE_PG_VALIDS_DA (0x1<<1) +#define L4_KWQ_UPDATE_PG_VALIDS_DA_SHIFT 1 +#define L4_KWQ_UPDATE_PG_RESERVERD2 (0x3F<<2) +#define L4_KWQ_UPDATE_PG_RESERVERD2_SHIFT 2 +#endif +#if defined(__BIG_ENDIAN) + u16 reserverd3; + u8 da0; + u8 da1; +#elif defined(__LITTLE_ENDIAN) + u8 da1; + u8 da0; + u16 reserverd3; +#endif +#if defined(__BIG_ENDIAN) + u8 da2; + u8 da3; + u8 da4; + u8 da5; +#elif defined(__LITTLE_ENDIAN) + u8 da5; + u8 da4; + u8 da3; + u8 da2; +#endif + u32 reserved4; + u32 reserved5; +}; + + +/* + * a KWQE request to upload a PG or L4 context + */ +struct l4_kwq_upload { +#if defined(__BIG_ENDIAN) + u8 flags; +#define L4_KWQ_UPLOAD_RESERVED1 (0xF<<0) +#define L4_KWQ_UPLOAD_RESERVED1_SHIFT 0 +#define L4_KWQ_UPLOAD_LAYER_CODE (0x7<<4) +#define L4_KWQ_UPLOAD_LAYER_CODE_SHIFT 4 +#define L4_KWQ_UPLOAD_LINKED_WITH_NEXT (0x1<<7) +#define L4_KWQ_UPLOAD_LINKED_WITH_NEXT_SHIFT 7 + u8 opcode; + u16 oper16; +#elif defined(__LITTLE_ENDIAN) + u16 oper16; + u8 opcode; + u8 flags; +#define L4_KWQ_UPLOAD_RESERVED1 (0xF<<0) +#define L4_KWQ_UPLOAD_RESERVED1_SHIFT 0 +#define L4_KWQ_UPLOAD_LAYER_CODE (0x7<<4) +#define L4_KWQ_UPLOAD_LAYER_CODE_SHIFT 4 +#define L4_KWQ_UPLOAD_LINKED_WITH_NEXT (0x1<<7) +#define L4_KWQ_UPLOAD_LINKED_WITH_NEXT_SHIFT 7 +#endif + u32 cid; + u32 reserved2[6]; +}; + +#endif /* CNIC_DEFS_H */ diff --git a/drivers/net/cnic_if.h b/drivers/net/cnic_if.h new file mode 100644 index 000000000000..d1bce27ee99e --- /dev/null +++ b/drivers/net/cnic_if.h @@ -0,0 +1,301 @@ +/* cnic_if.h: Broadcom CNIC core network driver. + * + * Copyright (c) 2006 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. + * + */ + + +#ifndef CNIC_IF_H +#define CNIC_IF_H + +#define CNIC_MODULE_VERSION "2.0.0" +#define CNIC_MODULE_RELDATE "May 21, 2009" + +#define CNIC_ULP_RDMA 0 +#define CNIC_ULP_ISCSI 1 +#define CNIC_ULP_L4 2 +#define MAX_CNIC_ULP_TYPE_EXT 2 +#define MAX_CNIC_ULP_TYPE 3 + +struct kwqe { + u32 kwqe_op_flag; + +#define KWQE_OPCODE_MASK 0x00ff0000 +#define KWQE_OPCODE_SHIFT 16 +#define KWQE_FLAGS_LAYER_SHIFT 28 +#define KWQE_OPCODE(x) ((x & KWQE_OPCODE_MASK) >> KWQE_OPCODE_SHIFT) + + u32 kwqe_info0; + u32 kwqe_info1; + u32 kwqe_info2; + u32 kwqe_info3; + u32 kwqe_info4; + u32 kwqe_info5; + u32 kwqe_info6; +}; + +struct kwqe_16 { + u32 kwqe_info0; + u32 kwqe_info1; + u32 kwqe_info2; + u32 kwqe_info3; +}; + +struct kcqe { + u32 kcqe_info0; + u32 kcqe_info1; + u32 kcqe_info2; + u32 kcqe_info3; + u32 kcqe_info4; + u32 kcqe_info5; + u32 kcqe_info6; + u32 kcqe_op_flag; + #define KCQE_RAMROD_COMPLETION (0x1<<27) /* Everest */ + #define KCQE_FLAGS_LAYER_MASK (0x7<<28) + #define KCQE_FLAGS_LAYER_MASK_MISC (0<<28) + #define KCQE_FLAGS_LAYER_MASK_L2 (2<<28) + #define KCQE_FLAGS_LAYER_MASK_L3 (3<<28) + #define KCQE_FLAGS_LAYER_MASK_L4 (4<<28) + #define KCQE_FLAGS_LAYER_MASK_L5_RDMA (5<<28) + #define KCQE_FLAGS_LAYER_MASK_L5_ISCSI (6<<28) + #define KCQE_FLAGS_NEXT (1<<31) + #define KCQE_FLAGS_OPCODE_MASK (0xff<<16) + #define KCQE_FLAGS_OPCODE_SHIFT (16) + #define KCQE_OPCODE(op) \ + (((op) & KCQE_FLAGS_OPCODE_MASK) >> KCQE_FLAGS_OPCODE_SHIFT) +}; + +#define MAX_CNIC_CTL_DATA 64 +#define MAX_DRV_CTL_DATA 64 + +#define CNIC_CTL_STOP_CMD 1 +#define CNIC_CTL_START_CMD 2 +#define CNIC_CTL_COMPLETION_CMD 3 + +#define DRV_CTL_IO_WR_CMD 0x101 +#define DRV_CTL_IO_RD_CMD 0x102 +#define DRV_CTL_CTX_WR_CMD 0x103 +#define DRV_CTL_CTXTBL_WR_CMD 0x104 +#define DRV_CTL_COMPLETION_CMD 0x105 + +struct cnic_ctl_completion { + u32 cid; +}; + +struct drv_ctl_completion { + u32 comp_count; +}; + +struct cnic_ctl_info { + int cmd; + union { + struct cnic_ctl_completion comp; + char bytes[MAX_CNIC_CTL_DATA]; + } data; +}; + +struct drv_ctl_io { + u32 cid_addr; + u32 offset; + u32 data; + dma_addr_t dma_addr; +}; + +struct drv_ctl_info { + int cmd; + union { + struct drv_ctl_completion comp; + struct drv_ctl_io io; + char bytes[MAX_DRV_CTL_DATA]; + } data; +}; + +struct cnic_ops { + struct module *cnic_owner; + /* Calls to these functions are protected by RCU. When + * unregistering, we wait for any calls to complete before + * continuing. + */ + int (*cnic_handler)(void *, void *); + int (*cnic_ctl)(void *, struct cnic_ctl_info *); +}; + +#define MAX_CNIC_VEC 8 + +struct cnic_irq { + unsigned int vector; + void *status_blk; + u32 status_blk_num; + u32 irq_flags; +#define CNIC_IRQ_FL_MSIX 0x00000001 +}; + +struct cnic_eth_dev { + struct module *drv_owner; + u32 drv_state; +#define CNIC_DRV_STATE_REGD 0x00000001 +#define CNIC_DRV_STATE_USING_MSIX 0x00000002 + u32 chip_id; + u32 max_kwqe_pending; + struct pci_dev *pdev; + void __iomem *io_base; + + u32 ctx_tbl_offset; + u32 ctx_tbl_len; + int ctx_blk_size; + u32 starting_cid; + u32 max_iscsi_conn; + u32 max_fcoe_conn; + u32 max_rdma_conn; + u32 reserved0[2]; + + int num_irq; + struct cnic_irq irq_arr[MAX_CNIC_VEC]; + int (*drv_register_cnic)(struct net_device *, + struct cnic_ops *, void *); + int (*drv_unregister_cnic)(struct net_device *); + int (*drv_submit_kwqes_32)(struct net_device *, + struct kwqe *[], u32); + int (*drv_submit_kwqes_16)(struct net_device *, + struct kwqe_16 *[], u32); + int (*drv_ctl)(struct net_device *, struct drv_ctl_info *); + unsigned long reserved1[2]; +}; + +struct cnic_sockaddr { + union { + struct sockaddr_in v4; + struct sockaddr_in6 v6; + } local; + union { + struct sockaddr_in v4; + struct sockaddr_in6 v6; + } remote; +}; + +struct cnic_sock { + struct cnic_dev *dev; + void *context; + u32 src_ip[4]; + u32 dst_ip[4]; + u16 src_port; + u16 dst_port; + u16 vlan_id; + unsigned char old_ha[6]; + unsigned char ha[6]; + u32 mtu; + u32 cid; + u32 l5_cid; + u32 pg_cid; + int ulp_type; + + u32 ka_timeout; + u32 ka_interval; + u8 ka_max_probe_count; + u8 tos; + u8 ttl; + u8 snd_seq_scale; + u32 rcv_buf; + u32 snd_buf; + u32 seed; + + unsigned long tcp_flags; +#define SK_TCP_NO_DELAY_ACK 0x1 +#define SK_TCP_KEEP_ALIVE 0x2 +#define SK_TCP_NAGLE 0x4 +#define SK_TCP_TIMESTAMP 0x8 +#define SK_TCP_SACK 0x10 +#define SK_TCP_SEG_SCALING 0x20 + unsigned long flags; +#define SK_F_INUSE 0 +#define SK_F_OFFLD_COMPLETE 1 +#define SK_F_OFFLD_SCHED 2 +#define SK_F_PG_OFFLD_COMPLETE 3 +#define SK_F_CONNECT_START 4 +#define SK_F_IPV6 5 +#define SK_F_CLOSING 7 + + atomic_t ref_count; + u32 state; + struct kwqe kwqe1; + struct kwqe kwqe2; + struct kwqe kwqe3; +}; + +struct cnic_dev { + struct net_device *netdev; + struct pci_dev *pcidev; + void __iomem *regview; + struct list_head list; + + int (*register_device)(struct cnic_dev *dev, int ulp_type, + void *ulp_ctx); + int (*unregister_device)(struct cnic_dev *dev, int ulp_type); + int (*submit_kwqes)(struct cnic_dev *dev, struct kwqe *wqes[], + u32 num_wqes); + int (*submit_kwqes_16)(struct cnic_dev *dev, struct kwqe_16 *wqes[], + u32 num_wqes); + + int (*cm_create)(struct cnic_dev *, int, u32, u32, struct cnic_sock **, + void *); + int (*cm_destroy)(struct cnic_sock *); + int (*cm_connect)(struct cnic_sock *, struct cnic_sockaddr *); + int (*cm_abort)(struct cnic_sock *); + int (*cm_close)(struct cnic_sock *); + struct cnic_dev *(*cm_select_dev)(struct sockaddr_in *, int ulp_type); + int (*iscsi_nl_msg_recv)(struct cnic_dev *dev, u32 msg_type, + char *data, u16 data_size); + unsigned long flags; +#define CNIC_F_CNIC_UP 1 +#define CNIC_F_BNX2_CLASS 3 +#define CNIC_F_BNX2X_CLASS 4 + atomic_t ref_count; + u8 mac_addr[6]; + + int max_iscsi_conn; + int max_fcoe_conn; + int max_rdma_conn; + + void *cnic_priv; +}; + +#define CNIC_WR(dev, off, val) writel(val, dev->regview + off) +#define CNIC_WR16(dev, off, val) writew(val, dev->regview + off) +#define CNIC_WR8(dev, off, val) writeb(val, dev->regview + off) +#define CNIC_RD(dev, off) readl(dev->regview + off) +#define CNIC_RD16(dev, off) readw(dev->regview + off) + +struct cnic_ulp_ops { + /* Calls to these functions are protected by RCU. When + * unregistering, we wait for any calls to complete before + * continuing. + */ + + void (*cnic_init)(struct cnic_dev *dev); + void (*cnic_exit)(struct cnic_dev *dev); + void (*cnic_start)(void *ulp_ctx); + void (*cnic_stop)(void *ulp_ctx); + void (*indicate_kcqes)(void *ulp_ctx, struct kcqe *cqes[], + u32 num_cqes); + void (*indicate_netevent)(void *ulp_ctx, unsigned long event); + void (*cm_connect_complete)(struct cnic_sock *); + void (*cm_close_complete)(struct cnic_sock *); + void (*cm_abort_complete)(struct cnic_sock *); + void (*cm_remote_close)(struct cnic_sock *); + void (*cm_remote_abort)(struct cnic_sock *); + void (*iscsi_nl_send_msg)(struct cnic_dev *dev, u32 msg_type, + char *data, u16 data_size); + struct module *owner; +}; + +extern int cnic_register_driver(int ulp_type, struct cnic_ulp_ops *ulp_ops); + +extern int cnic_unregister_driver(int ulp_type); + +extern struct cnic_eth_dev *bnx2_cnic_probe(struct net_device *dev); + +#endif diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c index 3f476c7c0736..58afafbd3b9c 100644 --- a/drivers/net/cpmac.c +++ b/drivers/net/cpmac.c @@ -202,7 +202,7 @@ struct cpmac_priv { void __iomem *regs; struct mii_bus *mii_bus; struct phy_device *phy; - char phy_name[BUS_ID_SIZE]; + char phy_name[MII_BUS_ID_SIZE + 3]; int oldlink, oldspeed, oldduplex; u32 msg_enable; struct net_device *dev; @@ -615,13 +615,13 @@ static void cpmac_end_xmit(struct net_device *dev, int queue) dev_kfree_skb_irq(desc->skb); desc->skb = NULL; - if (netif_subqueue_stopped(dev, queue)) + if (__netif_subqueue_stopped(dev, queue)) netif_wake_subqueue(dev, queue); } else { if (netif_msg_tx_err(priv) && net_ratelimit()) printk(KERN_WARNING "%s: end_xmit: spurious interrupt\n", dev->name); - if (netif_subqueue_stopped(dev, queue)) + if (__netif_subqueue_stopped(dev, queue)) netif_wake_subqueue(dev, queue); } } @@ -731,7 +731,6 @@ static void cpmac_clear_tx(struct net_device *dev) static void cpmac_hw_error(struct work_struct *work) { - int i; struct cpmac_priv *priv = container_of(work, struct cpmac_priv, reset_work); @@ -818,7 +817,6 @@ static irqreturn_t cpmac_irq(int irq, void *dev_id) static void cpmac_tx_timeout(struct net_device *dev) { - int i; struct cpmac_priv *priv = netdev_priv(dev); spin_lock(&priv->lock); @@ -1093,11 +1091,24 @@ static int cpmac_stop(struct net_device *dev) return 0; } +static const struct net_device_ops cpmac_netdev_ops = { + .ndo_open = cpmac_open, + .ndo_stop = cpmac_stop, + .ndo_start_xmit = cpmac_start_xmit, + .ndo_tx_timeout = cpmac_tx_timeout, + .ndo_set_multicast_list = cpmac_set_multicast_list, + .ndo_so_ioctl = cpmac_ioctl, + .ndo_set_config = cpmac_config, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, +}; + static int external_switch; static int __devinit cpmac_probe(struct platform_device *pdev) { - int rc, phy_id, i; + int rc, phy_id; char *mdio_bus_id = "0"; struct resource *mem; struct cpmac_priv *priv; @@ -1143,14 +1154,8 @@ static int __devinit cpmac_probe(struct platform_device *pdev) dev->irq = platform_get_irq_byname(pdev, "irq"); - dev->open = cpmac_open; - dev->stop = cpmac_stop; - dev->set_config = cpmac_config; - dev->hard_start_xmit = cpmac_start_xmit; - dev->do_ioctl = cpmac_ioctl; - dev->set_multicast_list = cpmac_set_multicast_list; - dev->tx_timeout = cpmac_tx_timeout; - dev->ethtool_ops = &cpmac_ethtool_ops; + dev->netdev_ops = &cpmac_netdev_ops; + dev->ethtool_ops = &cpmac_ethtool_ops; netif_napi_add(dev, &priv->napi, cpmac_poll, 64); diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c index 7433b88eed7e..3eee666a9cd2 100644 --- a/drivers/net/cs89x0.c +++ b/drivers/net/cs89x0.c @@ -1551,7 +1551,7 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev) spin_unlock_irq(&lp->lock); if (net_debug) printk("cs89x0: Tx buffer not free!\n"); - return 1; + return NETDEV_TX_BUSY; } /* Write the contents of the packet */ writewords(dev->base_addr, TX_FRAME_PORT,skb->data,(skb->len+1) >>1); diff --git a/drivers/net/cxgb3/Makefile b/drivers/net/cxgb3/Makefile index 343467985321..29aff78c7820 100644 --- a/drivers/net/cxgb3/Makefile +++ b/drivers/net/cxgb3/Makefile @@ -5,4 +5,4 @@ obj-$(CONFIG_CHELSIO_T3) += cxgb3.o cxgb3-objs := cxgb3_main.o ael1002.o vsc8211.o t3_hw.o mc5.o \ - xgmac.o sge.o l2t.o cxgb3_offload.o + xgmac.o sge.o l2t.o cxgb3_offload.o aq100x.o diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h index c888e97c9671..1694fad38720 100644 --- a/drivers/net/cxgb3/adapter.h +++ b/drivers/net/cxgb3/adapter.h @@ -195,7 +195,7 @@ struct sge_qset { /* an SGE queue set */ struct sge_rspq rspq; struct sge_fl fl[SGE_RXQ_PER_SET]; struct sge_txq txq[SGE_TXQ_PER_SET]; - struct napi_gro_fraginfo lro_frag_tbl; + int nomem; int lro_enabled; void *lro_va; struct net_device *netdev; @@ -253,6 +253,8 @@ struct adapter { struct mutex mdio_lock; spinlock_t stats_lock; spinlock_t work_lock; + + struct sk_buff *nofail_skb; }; static inline u32 t3_read_reg(struct adapter *adapter, u32 reg_addr) diff --git a/drivers/net/cxgb3/ael1002.c b/drivers/net/cxgb3/ael1002.c index e1b22490ff59..9fe008ec9ba5 100644 --- a/drivers/net/cxgb3/ael1002.c +++ b/drivers/net/cxgb3/ael1002.c @@ -33,14 +33,6 @@ #include "regs.h" enum { - PMD_RSD = 10, /* PMA/PMD receive signal detect register */ - PCS_STAT1_X = 24, /* 10GBASE-X PCS status 1 register */ - PCS_STAT1_R = 32, /* 10GBASE-R PCS status 1 register */ - XS_LN_STAT = 24 /* XS lane status register */ -}; - -enum { - AEL100X_TX_DISABLE = 9, AEL100X_TX_CONFIG1 = 0xc002, AEL1002_PWR_DOWN_HI = 0xc011, AEL1002_PWR_DOWN_LO = 0xc012, @@ -52,12 +44,33 @@ enum { AEL_I2C_STAT = 0xc30c, AEL2005_GPIO_CTRL = 0xc214, AEL2005_GPIO_STAT = 0xc215, + + AEL2020_GPIO_INTR = 0xc103, /* Latch High (LH) */ + AEL2020_GPIO_CTRL = 0xc108, /* Store Clear (SC) */ + AEL2020_GPIO_STAT = 0xc10c, /* Read Only (RO) */ + AEL2020_GPIO_CFG = 0xc110, /* Read Write (RW) */ + + AEL2020_GPIO_SDA = 0, /* IN: i2c serial data */ + AEL2020_GPIO_MODDET = 1, /* IN: Module Detect */ + AEL2020_GPIO_0 = 3, /* IN: unassigned */ + AEL2020_GPIO_1 = 2, /* OUT: unassigned */ + AEL2020_GPIO_LSTAT = AEL2020_GPIO_1, /* wired to link status LED */ }; enum { edc_none, edc_sr, edc_twinax }; /* PHY module I2C device address */ -#define MODULE_DEV_ADDR 0xa0 +enum { + MODULE_DEV_ADDR = 0xa0, + SFF_DEV_ADDR = 0xa2, +}; + +/* PHY transceiver type */ +enum { + phy_transtype_unknown = 0, + phy_transtype_sfp = 3, + phy_transtype_xfp = 6, +}; #define AEL2005_MODDET_IRQ 4 @@ -74,8 +87,8 @@ static int set_phy_regs(struct cphy *phy, const struct reg_val *rv) for (err = 0; rv->mmd_addr && !err; rv++) { if (rv->clear_bits == 0xffff) - err = mdio_write(phy, rv->mmd_addr, rv->reg_addr, - rv->set_bits); + err = t3_mdio_write(phy, rv->mmd_addr, rv->reg_addr, + rv->set_bits); else err = t3_mdio_change_bits(phy, rv->mmd_addr, rv->reg_addr, rv->clear_bits, @@ -86,21 +99,54 @@ static int set_phy_regs(struct cphy *phy, const struct reg_val *rv) static void ael100x_txon(struct cphy *phy) { - int tx_on_gpio = phy->addr == 0 ? F_GPIO7_OUT_VAL : F_GPIO2_OUT_VAL; + int tx_on_gpio = + phy->mdio.prtad == 0 ? F_GPIO7_OUT_VAL : F_GPIO2_OUT_VAL; msleep(100); t3_set_reg_field(phy->adapter, A_T3DBG_GPIO_EN, 0, tx_on_gpio); msleep(30); } +/* + * Read an 8-bit word from a device attached to the PHY's i2c bus. + */ +static int ael_i2c_rd(struct cphy *phy, int dev_addr, int word_addr) +{ + int i, err; + unsigned int stat, data; + + err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL_I2C_CTRL, + (dev_addr << 8) | (1 << 8) | word_addr); + if (err) + return err; + + for (i = 0; i < 200; i++) { + msleep(1); + err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL_I2C_STAT, &stat); + if (err) + return err; + if ((stat & 3) == 1) { + err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL_I2C_DATA, + &data); + if (err) + return err; + return data >> 8; + } + } + CH_WARN(phy->adapter, "PHY %u i2c read of dev.addr %#x.%#x timed out\n", + phy->mdio.prtad, dev_addr, word_addr); + return -ETIMEDOUT; +} + static int ael1002_power_down(struct cphy *phy, int enable) { int err; - err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL100X_TX_DISABLE, !!enable); + err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, MDIO_PMA_TXDIS, !!enable); if (!err) - err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR, - BMCR_PDOWN, enable ? BMCR_PDOWN : 0); + err = mdio_set_flag(&phy->mdio, phy->mdio.prtad, + MDIO_MMD_PMAPMD, MDIO_CTRL1, + MDIO_CTRL1_LPOWER, enable); return err; } @@ -109,11 +155,11 @@ static int ael1002_reset(struct cphy *phy, int wait) int err; if ((err = ael1002_power_down(phy, 0)) || - (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL100X_TX_CONFIG1, 1)) || - (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_PWR_DOWN_HI, 0)) || - (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_PWR_DOWN_LO, 0)) || - (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_XFI_EQL, 0x18)) || - (err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, AEL1002_LB_EN, + (err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL100X_TX_CONFIG1, 1)) || + (err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL1002_PWR_DOWN_HI, 0)) || + (err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL1002_PWR_DOWN_LO, 0)) || + (err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL1002_XFI_EQL, 0x18)) || + (err = t3_mdio_change_bits(phy, MDIO_MMD_PMAPMD, AEL1002_LB_EN, 0, 1 << 5))) return err; return 0; @@ -132,12 +178,15 @@ static int get_link_status_r(struct cphy *phy, int *link_ok, int *speed, { if (link_ok) { unsigned int stat0, stat1, stat2; - int err = mdio_read(phy, MDIO_DEV_PMA_PMD, PMD_RSD, &stat0); + int err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, + MDIO_PMA_RXDET, &stat0); if (!err) - err = mdio_read(phy, MDIO_DEV_PCS, PCS_STAT1_R, &stat1); + err = t3_mdio_read(phy, MDIO_MMD_PCS, + MDIO_PCS_10GBRT_STAT1, &stat1); if (!err) - err = mdio_read(phy, MDIO_DEV_XGXS, XS_LN_STAT, &stat2); + err = t3_mdio_read(phy, MDIO_MMD_PHYXS, + MDIO_PHYXS_LNSTAT, &stat2); if (err) return err; *link_ok = (stat0 & stat1 & (stat2 >> 12)) & 1; @@ -157,6 +206,7 @@ static struct cphy_ops ael1002_ops = { .intr_handler = ael1002_intr_noop, .get_link_status = get_link_status_r, .power_down = ael1002_power_down, + .mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS, }; int t3_ael1002_phy_prep(struct cphy *phy, struct adapter *adapter, @@ -171,13 +221,13 @@ int t3_ael1002_phy_prep(struct cphy *phy, struct adapter *adapter, static int ael1006_reset(struct cphy *phy, int wait) { - return t3_phy_reset(phy, MDIO_DEV_PMA_PMD, wait); + return t3_phy_reset(phy, MDIO_MMD_PMAPMD, wait); } static int ael1006_power_down(struct cphy *phy, int enable) { - return t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR, - BMCR_PDOWN, enable ? BMCR_PDOWN : 0); + return mdio_set_flag(&phy->mdio, phy->mdio.prtad, MDIO_MMD_PMAPMD, + MDIO_CTRL1, MDIO_CTRL1_LPOWER, enable); } static struct cphy_ops ael1006_ops = { @@ -188,6 +238,7 @@ static struct cphy_ops ael1006_ops = { .intr_handler = t3_phy_lasi_intr_handler, .get_link_status = get_link_status_r, .power_down = ael1006_power_down, + .mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS, }; int t3_ael1006_phy_prep(struct cphy *phy, struct adapter *adapter, @@ -200,12 +251,57 @@ int t3_ael1006_phy_prep(struct cphy *phy, struct adapter *adapter, return 0; } +/* + * Decode our module type. + */ +static int ael2xxx_get_module_type(struct cphy *phy, int delay_ms) +{ + int v; + + if (delay_ms) + msleep(delay_ms); + + /* see SFF-8472 for below */ + v = ael_i2c_rd(phy, MODULE_DEV_ADDR, 3); + if (v < 0) + return v; + + if (v == 0x10) + return phy_modtype_sr; + if (v == 0x20) + return phy_modtype_lr; + if (v == 0x40) + return phy_modtype_lrm; + + v = ael_i2c_rd(phy, MODULE_DEV_ADDR, 6); + if (v < 0) + return v; + if (v != 4) + goto unknown; + + v = ael_i2c_rd(phy, MODULE_DEV_ADDR, 10); + if (v < 0) + return v; + + if (v & 0x80) { + v = ael_i2c_rd(phy, MODULE_DEV_ADDR, 0x12); + if (v < 0) + return v; + return v > 10 ? phy_modtype_twinax_long : phy_modtype_twinax; + } +unknown: + return phy_modtype_unknown; +} + +/* + * Code to support the Aeluros/NetLogic 2005 10Gb PHY. + */ static int ael2005_setup_sr_edc(struct cphy *phy) { static struct reg_val regs[] = { - { MDIO_DEV_PMA_PMD, 0xc003, 0xffff, 0x181 }, - { MDIO_DEV_PMA_PMD, 0xc010, 0xffff, 0x448a }, - { MDIO_DEV_PMA_PMD, 0xc04a, 0xffff, 0x5200 }, + { MDIO_MMD_PMAPMD, 0xc003, 0xffff, 0x181 }, + { MDIO_MMD_PMAPMD, 0xc010, 0xffff, 0x448a }, + { MDIO_MMD_PMAPMD, 0xc04a, 0xffff, 0x5200 }, { 0, 0, 0, 0 } }; static u16 sr_edc[] = { @@ -490,8 +586,8 @@ static int ael2005_setup_sr_edc(struct cphy *phy) msleep(50); for (i = 0; i < ARRAY_SIZE(sr_edc) && !err; i += 2) - err = mdio_write(phy, MDIO_DEV_PMA_PMD, sr_edc[i], - sr_edc[i + 1]); + err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, sr_edc[i], + sr_edc[i + 1]); if (!err) phy->priv = edc_sr; return err; @@ -500,12 +596,12 @@ static int ael2005_setup_sr_edc(struct cphy *phy) static int ael2005_setup_twinax_edc(struct cphy *phy, int modtype) { static struct reg_val regs[] = { - { MDIO_DEV_PMA_PMD, 0xc04a, 0xffff, 0x5a00 }, + { MDIO_MMD_PMAPMD, 0xc04a, 0xffff, 0x5a00 }, { 0, 0, 0, 0 } }; static struct reg_val preemphasis[] = { - { MDIO_DEV_PMA_PMD, 0xc014, 0xffff, 0xfe16 }, - { MDIO_DEV_PMA_PMD, 0xc015, 0xffff, 0xa000 }, + { MDIO_MMD_PMAPMD, 0xc014, 0xffff, 0xfe16 }, + { MDIO_MMD_PMAPMD, 0xc015, 0xffff, 0xa000 }, { 0, 0, 0, 0 } }; static u16 twinax_edc[] = { @@ -887,132 +983,73 @@ static int ael2005_setup_twinax_edc(struct cphy *phy, int modtype) msleep(50); for (i = 0; i < ARRAY_SIZE(twinax_edc) && !err; i += 2) - err = mdio_write(phy, MDIO_DEV_PMA_PMD, twinax_edc[i], - twinax_edc[i + 1]); + err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, twinax_edc[i], + twinax_edc[i + 1]); if (!err) phy->priv = edc_twinax; return err; } -static int ael2005_i2c_rd(struct cphy *phy, int dev_addr, int word_addr) -{ - int i, err; - unsigned int stat, data; - - err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL_I2C_CTRL, - (dev_addr << 8) | (1 << 8) | word_addr); - if (err) - return err; - - for (i = 0; i < 5; i++) { - msleep(1); - err = mdio_read(phy, MDIO_DEV_PMA_PMD, AEL_I2C_STAT, &stat); - if (err) - return err; - if ((stat & 3) == 1) { - err = mdio_read(phy, MDIO_DEV_PMA_PMD, AEL_I2C_DATA, - &data); - if (err) - return err; - return data >> 8; - } - } - CH_WARN(phy->adapter, "PHY %u I2C read of addr %u timed out\n", - phy->addr, word_addr); - return -ETIMEDOUT; -} - -static int get_module_type(struct cphy *phy, int delay_ms) +static int ael2005_get_module_type(struct cphy *phy, int delay_ms) { int v; unsigned int stat; - v = mdio_read(phy, MDIO_DEV_PMA_PMD, AEL2005_GPIO_CTRL, &stat); + v = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL2005_GPIO_CTRL, &stat); if (v) return v; if (stat & (1 << 8)) /* module absent */ return phy_modtype_none; - if (delay_ms) - msleep(delay_ms); - - /* see SFF-8472 for below */ - v = ael2005_i2c_rd(phy, MODULE_DEV_ADDR, 3); - if (v < 0) - return v; - - if (v == 0x10) - return phy_modtype_sr; - if (v == 0x20) - return phy_modtype_lr; - if (v == 0x40) - return phy_modtype_lrm; - - v = ael2005_i2c_rd(phy, MODULE_DEV_ADDR, 6); - if (v < 0) - return v; - if (v != 4) - goto unknown; - - v = ael2005_i2c_rd(phy, MODULE_DEV_ADDR, 10); - if (v < 0) - return v; - - if (v & 0x80) { - v = ael2005_i2c_rd(phy, MODULE_DEV_ADDR, 0x12); - if (v < 0) - return v; - return v > 10 ? phy_modtype_twinax_long : phy_modtype_twinax; - } -unknown: - return phy_modtype_unknown; + return ael2xxx_get_module_type(phy, delay_ms); } static int ael2005_intr_enable(struct cphy *phy) { - int err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL2005_GPIO_CTRL, 0x200); + int err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL2005_GPIO_CTRL, 0x200); return err ? err : t3_phy_lasi_intr_enable(phy); } static int ael2005_intr_disable(struct cphy *phy) { - int err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL2005_GPIO_CTRL, 0x100); + int err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL2005_GPIO_CTRL, 0x100); return err ? err : t3_phy_lasi_intr_disable(phy); } static int ael2005_intr_clear(struct cphy *phy) { - int err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL2005_GPIO_CTRL, 0xd00); + int err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL2005_GPIO_CTRL, 0xd00); return err ? err : t3_phy_lasi_intr_clear(phy); } static int ael2005_reset(struct cphy *phy, int wait) { static struct reg_val regs0[] = { - { MDIO_DEV_PMA_PMD, 0xc001, 0, 1 << 5 }, - { MDIO_DEV_PMA_PMD, 0xc017, 0, 1 << 5 }, - { MDIO_DEV_PMA_PMD, 0xc013, 0xffff, 0xf341 }, - { MDIO_DEV_PMA_PMD, 0xc210, 0xffff, 0x8000 }, - { MDIO_DEV_PMA_PMD, 0xc210, 0xffff, 0x8100 }, - { MDIO_DEV_PMA_PMD, 0xc210, 0xffff, 0x8000 }, - { MDIO_DEV_PMA_PMD, 0xc210, 0xffff, 0 }, + { MDIO_MMD_PMAPMD, 0xc001, 0, 1 << 5 }, + { MDIO_MMD_PMAPMD, 0xc017, 0, 1 << 5 }, + { MDIO_MMD_PMAPMD, 0xc013, 0xffff, 0xf341 }, + { MDIO_MMD_PMAPMD, 0xc210, 0xffff, 0x8000 }, + { MDIO_MMD_PMAPMD, 0xc210, 0xffff, 0x8100 }, + { MDIO_MMD_PMAPMD, 0xc210, 0xffff, 0x8000 }, + { MDIO_MMD_PMAPMD, 0xc210, 0xffff, 0 }, { 0, 0, 0, 0 } }; static struct reg_val regs1[] = { - { MDIO_DEV_PMA_PMD, 0xca00, 0xffff, 0x0080 }, - { MDIO_DEV_PMA_PMD, 0xca12, 0xffff, 0 }, + { MDIO_MMD_PMAPMD, 0xca00, 0xffff, 0x0080 }, + { MDIO_MMD_PMAPMD, 0xca12, 0xffff, 0 }, { 0, 0, 0, 0 } }; int err; unsigned int lasi_ctrl; - err = mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, &lasi_ctrl); + err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_CTRL, + &lasi_ctrl); if (err) return err; - err = t3_phy_reset(phy, MDIO_DEV_PMA_PMD, 0); + err = t3_phy_reset(phy, MDIO_MMD_PMAPMD, 0); if (err) return err; @@ -1024,7 +1061,7 @@ static int ael2005_reset(struct cphy *phy, int wait) msleep(50); - err = get_module_type(phy, 0); + err = ael2005_get_module_type(phy, 0); if (err < 0) return err; phy->modtype = err; @@ -1051,18 +1088,18 @@ static int ael2005_intr_handler(struct cphy *phy) unsigned int stat; int ret, edc_needed, cause = 0; - ret = mdio_read(phy, MDIO_DEV_PMA_PMD, AEL2005_GPIO_STAT, &stat); + ret = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL2005_GPIO_STAT, &stat); if (ret) return ret; if (stat & AEL2005_MODDET_IRQ) { - ret = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL2005_GPIO_CTRL, - 0xd00); + ret = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL2005_GPIO_CTRL, + 0xd00); if (ret) return ret; /* modules have max 300 ms init time after hot plug */ - ret = get_module_type(phy, 300); + ret = ael2005_get_module_type(phy, 300); if (ret < 0) return ret; @@ -1098,6 +1135,7 @@ static struct cphy_ops ael2005_ops = { .intr_handler = ael2005_intr_handler, .get_link_status = get_link_status_r, .power_down = ael1002_power_down, + .mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS, }; int t3_ael2005_phy_prep(struct cphy *phy, struct adapter *adapter, @@ -1107,10 +1145,666 @@ int t3_ael2005_phy_prep(struct cphy *phy, struct adapter *adapter, SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE | SUPPORTED_IRQ, "10GBASE-R"); msleep(125); - return t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, AEL_OPT_SETTINGS, 0, + return t3_mdio_change_bits(phy, MDIO_MMD_PMAPMD, AEL_OPT_SETTINGS, 0, 1 << 5); } +/* + * Setup EDC and other parameters for operation with an optical module. + */ +static int ael2020_setup_sr_edc(struct cphy *phy) +{ + static struct reg_val regs[] = { + /* set CDR offset to 10 */ + { MDIO_MMD_PMAPMD, 0xcc01, 0xffff, 0x488a }, + + /* adjust 10G RX bias current */ + { MDIO_MMD_PMAPMD, 0xcb1b, 0xffff, 0x0200 }, + { MDIO_MMD_PMAPMD, 0xcb1c, 0xffff, 0x00f0 }, + { MDIO_MMD_PMAPMD, 0xcc06, 0xffff, 0x00e0 }, + + /* end */ + { 0, 0, 0, 0 } + }; + int err; + + err = set_phy_regs(phy, regs); + msleep(50); + if (err) + return err; + + phy->priv = edc_sr; + return 0; +} + +/* + * Setup EDC and other parameters for operation with an TWINAX module. + */ +static int ael2020_setup_twinax_edc(struct cphy *phy, int modtype) +{ + /* set uC to 40MHz */ + static struct reg_val uCclock40MHz[] = { + { MDIO_MMD_PMAPMD, 0xff28, 0xffff, 0x4001 }, + { MDIO_MMD_PMAPMD, 0xff2a, 0xffff, 0x0002 }, + { 0, 0, 0, 0 } + }; + + /* activate uC clock */ + static struct reg_val uCclockActivate[] = { + { MDIO_MMD_PMAPMD, 0xd000, 0xffff, 0x5200 }, + { 0, 0, 0, 0 } + }; + + /* set PC to start of SRAM and activate uC */ + static struct reg_val uCactivate[] = { + { MDIO_MMD_PMAPMD, 0xd080, 0xffff, 0x0100 }, + { MDIO_MMD_PMAPMD, 0xd092, 0xffff, 0x0000 }, + { 0, 0, 0, 0 } + }; + + /* TWINAX EDC firmware */ + static u16 twinax_edc[] = { + 0xd800, 0x4009, + 0xd801, 0x2fff, + 0xd802, 0x300f, + 0xd803, 0x40aa, + 0xd804, 0x401c, + 0xd805, 0x401e, + 0xd806, 0x2ff4, + 0xd807, 0x3dc4, + 0xd808, 0x2035, + 0xd809, 0x3035, + 0xd80a, 0x6524, + 0xd80b, 0x2cb2, + 0xd80c, 0x3012, + 0xd80d, 0x1002, + 0xd80e, 0x26e2, + 0xd80f, 0x3022, + 0xd810, 0x1002, + 0xd811, 0x27d2, + 0xd812, 0x3022, + 0xd813, 0x1002, + 0xd814, 0x2822, + 0xd815, 0x3012, + 0xd816, 0x1002, + 0xd817, 0x2492, + 0xd818, 0x3022, + 0xd819, 0x1002, + 0xd81a, 0x2772, + 0xd81b, 0x3012, + 0xd81c, 0x1002, + 0xd81d, 0x23d2, + 0xd81e, 0x3022, + 0xd81f, 0x1002, + 0xd820, 0x22cd, + 0xd821, 0x301d, + 0xd822, 0x27f2, + 0xd823, 0x3022, + 0xd824, 0x1002, + 0xd825, 0x5553, + 0xd826, 0x0307, + 0xd827, 0x2522, + 0xd828, 0x3022, + 0xd829, 0x1002, + 0xd82a, 0x2142, + 0xd82b, 0x3012, + 0xd82c, 0x1002, + 0xd82d, 0x4016, + 0xd82e, 0x5e63, + 0xd82f, 0x0344, + 0xd830, 0x2142, + 0xd831, 0x3012, + 0xd832, 0x1002, + 0xd833, 0x400e, + 0xd834, 0x2522, + 0xd835, 0x3022, + 0xd836, 0x1002, + 0xd837, 0x2b52, + 0xd838, 0x3012, + 0xd839, 0x1002, + 0xd83a, 0x2742, + 0xd83b, 0x3022, + 0xd83c, 0x1002, + 0xd83d, 0x25e2, + 0xd83e, 0x3022, + 0xd83f, 0x1002, + 0xd840, 0x2fa4, + 0xd841, 0x3dc4, + 0xd842, 0x6624, + 0xd843, 0x414b, + 0xd844, 0x56b3, + 0xd845, 0x03c6, + 0xd846, 0x866b, + 0xd847, 0x400c, + 0xd848, 0x2712, + 0xd849, 0x3012, + 0xd84a, 0x1002, + 0xd84b, 0x2c4b, + 0xd84c, 0x309b, + 0xd84d, 0x56b3, + 0xd84e, 0x03c3, + 0xd84f, 0x866b, + 0xd850, 0x400c, + 0xd851, 0x2272, + 0xd852, 0x3022, + 0xd853, 0x1002, + 0xd854, 0x2742, + 0xd855, 0x3022, + 0xd856, 0x1002, + 0xd857, 0x25e2, + 0xd858, 0x3022, + 0xd859, 0x1002, + 0xd85a, 0x2fb4, + 0xd85b, 0x3dc4, + 0xd85c, 0x6624, + 0xd85d, 0x56b3, + 0xd85e, 0x03c3, + 0xd85f, 0x866b, + 0xd860, 0x401c, + 0xd861, 0x2c45, + 0xd862, 0x3095, + 0xd863, 0x5b53, + 0xd864, 0x2372, + 0xd865, 0x3012, + 0xd866, 0x13c2, + 0xd867, 0x5cc3, + 0xd868, 0x2712, + 0xd869, 0x3012, + 0xd86a, 0x1312, + 0xd86b, 0x2b52, + 0xd86c, 0x3012, + 0xd86d, 0x1002, + 0xd86e, 0x2742, + 0xd86f, 0x3022, + 0xd870, 0x1002, + 0xd871, 0x2582, + 0xd872, 0x3022, + 0xd873, 0x1002, + 0xd874, 0x2142, + 0xd875, 0x3012, + 0xd876, 0x1002, + 0xd877, 0x628f, + 0xd878, 0x2985, + 0xd879, 0x33a5, + 0xd87a, 0x25e2, + 0xd87b, 0x3022, + 0xd87c, 0x1002, + 0xd87d, 0x5653, + 0xd87e, 0x03d2, + 0xd87f, 0x401e, + 0xd880, 0x6f72, + 0xd881, 0x1002, + 0xd882, 0x628f, + 0xd883, 0x2304, + 0xd884, 0x3c84, + 0xd885, 0x6436, + 0xd886, 0xdff4, + 0xd887, 0x6436, + 0xd888, 0x2ff5, + 0xd889, 0x3005, + 0xd88a, 0x8656, + 0xd88b, 0xdfba, + 0xd88c, 0x56a3, + 0xd88d, 0xd05a, + 0xd88e, 0x2972, + 0xd88f, 0x3012, + 0xd890, 0x1392, + 0xd891, 0xd05a, + 0xd892, 0x56a3, + 0xd893, 0xdfba, + 0xd894, 0x0383, + 0xd895, 0x6f72, + 0xd896, 0x1002, + 0xd897, 0x2b45, + 0xd898, 0x3005, + 0xd899, 0x4178, + 0xd89a, 0x5653, + 0xd89b, 0x0384, + 0xd89c, 0x2a62, + 0xd89d, 0x3012, + 0xd89e, 0x1002, + 0xd89f, 0x2f05, + 0xd8a0, 0x3005, + 0xd8a1, 0x41c8, + 0xd8a2, 0x5653, + 0xd8a3, 0x0382, + 0xd8a4, 0x0002, + 0xd8a5, 0x4218, + 0xd8a6, 0x2474, + 0xd8a7, 0x3c84, + 0xd8a8, 0x6437, + 0xd8a9, 0xdff4, + 0xd8aa, 0x6437, + 0xd8ab, 0x2ff5, + 0xd8ac, 0x3c05, + 0xd8ad, 0x8757, + 0xd8ae, 0xb888, + 0xd8af, 0x9787, + 0xd8b0, 0xdff4, + 0xd8b1, 0x6724, + 0xd8b2, 0x866a, + 0xd8b3, 0x6f72, + 0xd8b4, 0x1002, + 0xd8b5, 0x2641, + 0xd8b6, 0x3021, + 0xd8b7, 0x1001, + 0xd8b8, 0xc620, + 0xd8b9, 0x0000, + 0xd8ba, 0xc621, + 0xd8bb, 0x0000, + 0xd8bc, 0xc622, + 0xd8bd, 0x00ce, + 0xd8be, 0xc623, + 0xd8bf, 0x007f, + 0xd8c0, 0xc624, + 0xd8c1, 0x0032, + 0xd8c2, 0xc625, + 0xd8c3, 0x0000, + 0xd8c4, 0xc627, + 0xd8c5, 0x0000, + 0xd8c6, 0xc628, + 0xd8c7, 0x0000, + 0xd8c8, 0xc62c, + 0xd8c9, 0x0000, + 0xd8ca, 0x0000, + 0xd8cb, 0x2641, + 0xd8cc, 0x3021, + 0xd8cd, 0x1001, + 0xd8ce, 0xc502, + 0xd8cf, 0x53ac, + 0xd8d0, 0xc503, + 0xd8d1, 0x2cd3, + 0xd8d2, 0xc600, + 0xd8d3, 0x2a6e, + 0xd8d4, 0xc601, + 0xd8d5, 0x2a2c, + 0xd8d6, 0xc605, + 0xd8d7, 0x5557, + 0xd8d8, 0xc60c, + 0xd8d9, 0x5400, + 0xd8da, 0xc710, + 0xd8db, 0x0700, + 0xd8dc, 0xc711, + 0xd8dd, 0x0f06, + 0xd8de, 0xc718, + 0xd8df, 0x0700, + 0xd8e0, 0xc719, + 0xd8e1, 0x0f06, + 0xd8e2, 0xc720, + 0xd8e3, 0x4700, + 0xd8e4, 0xc721, + 0xd8e5, 0x0f06, + 0xd8e6, 0xc728, + 0xd8e7, 0x0700, + 0xd8e8, 0xc729, + 0xd8e9, 0x1207, + 0xd8ea, 0xc801, + 0xd8eb, 0x7f50, + 0xd8ec, 0xc802, + 0xd8ed, 0x7760, + 0xd8ee, 0xc803, + 0xd8ef, 0x7fce, + 0xd8f0, 0xc804, + 0xd8f1, 0x520e, + 0xd8f2, 0xc805, + 0xd8f3, 0x5c11, + 0xd8f4, 0xc806, + 0xd8f5, 0x3c51, + 0xd8f6, 0xc807, + 0xd8f7, 0x4061, + 0xd8f8, 0xc808, + 0xd8f9, 0x49c1, + 0xd8fa, 0xc809, + 0xd8fb, 0x3840, + 0xd8fc, 0xc80a, + 0xd8fd, 0x0000, + 0xd8fe, 0xc821, + 0xd8ff, 0x0002, + 0xd900, 0xc822, + 0xd901, 0x0046, + 0xd902, 0xc844, + 0xd903, 0x182f, + 0xd904, 0xc013, + 0xd905, 0xf341, + 0xd906, 0xc084, + 0xd907, 0x0030, + 0xd908, 0xc904, + 0xd909, 0x1401, + 0xd90a, 0xcb0c, + 0xd90b, 0x0004, + 0xd90c, 0xcb0e, + 0xd90d, 0xa00a, + 0xd90e, 0xcb0f, + 0xd90f, 0xc0c0, + 0xd910, 0xcb10, + 0xd911, 0xc0c0, + 0xd912, 0xcb11, + 0xd913, 0x00a0, + 0xd914, 0xcb12, + 0xd915, 0x0007, + 0xd916, 0xc241, + 0xd917, 0xa000, + 0xd918, 0xc243, + 0xd919, 0x7fe0, + 0xd91a, 0xc604, + 0xd91b, 0x000e, + 0xd91c, 0xc609, + 0xd91d, 0x00f5, + 0xd91e, 0xc611, + 0xd91f, 0x000e, + 0xd920, 0xc660, + 0xd921, 0x9600, + 0xd922, 0xc687, + 0xd923, 0x0004, + 0xd924, 0xc60a, + 0xd925, 0x04f5, + 0xd926, 0x0000, + 0xd927, 0x2641, + 0xd928, 0x3021, + 0xd929, 0x1001, + 0xd92a, 0xc620, + 0xd92b, 0x14e5, + 0xd92c, 0xc621, + 0xd92d, 0xc53d, + 0xd92e, 0xc622, + 0xd92f, 0x3cbe, + 0xd930, 0xc623, + 0xd931, 0x4452, + 0xd932, 0xc624, + 0xd933, 0xc5c5, + 0xd934, 0xc625, + 0xd935, 0xe01e, + 0xd936, 0xc627, + 0xd937, 0x0000, + 0xd938, 0xc628, + 0xd939, 0x0000, + 0xd93a, 0xc62c, + 0xd93b, 0x0000, + 0xd93c, 0x0000, + 0xd93d, 0x2b84, + 0xd93e, 0x3c74, + 0xd93f, 0x6435, + 0xd940, 0xdff4, + 0xd941, 0x6435, + 0xd942, 0x2806, + 0xd943, 0x3006, + 0xd944, 0x8565, + 0xd945, 0x2b24, + 0xd946, 0x3c24, + 0xd947, 0x6436, + 0xd948, 0x1002, + 0xd949, 0x2b24, + 0xd94a, 0x3c24, + 0xd94b, 0x6436, + 0xd94c, 0x4045, + 0xd94d, 0x8656, + 0xd94e, 0x5663, + 0xd94f, 0x0302, + 0xd950, 0x401e, + 0xd951, 0x1002, + 0xd952, 0x2807, + 0xd953, 0x31a7, + 0xd954, 0x20c4, + 0xd955, 0x3c24, + 0xd956, 0x6724, + 0xd957, 0x1002, + 0xd958, 0x2807, + 0xd959, 0x3187, + 0xd95a, 0x20c4, + 0xd95b, 0x3c24, + 0xd95c, 0x6724, + 0xd95d, 0x1002, + 0xd95e, 0x24f4, + 0xd95f, 0x3c64, + 0xd960, 0x6436, + 0xd961, 0xdff4, + 0xd962, 0x6436, + 0xd963, 0x1002, + 0xd964, 0x2006, + 0xd965, 0x3d76, + 0xd966, 0xc161, + 0xd967, 0x6134, + 0xd968, 0x6135, + 0xd969, 0x5443, + 0xd96a, 0x0303, + 0xd96b, 0x6524, + 0xd96c, 0x00fb, + 0xd96d, 0x1002, + 0xd96e, 0x20d4, + 0xd96f, 0x3c24, + 0xd970, 0x2025, + 0xd971, 0x3005, + 0xd972, 0x6524, + 0xd973, 0x1002, + 0xd974, 0xd019, + 0xd975, 0x2104, + 0xd976, 0x3c24, + 0xd977, 0x2105, + 0xd978, 0x3805, + 0xd979, 0x6524, + 0xd97a, 0xdff4, + 0xd97b, 0x4005, + 0xd97c, 0x6524, + 0xd97d, 0x2e8d, + 0xd97e, 0x303d, + 0xd97f, 0x2408, + 0xd980, 0x35d8, + 0xd981, 0x5dd3, + 0xd982, 0x0307, + 0xd983, 0x8887, + 0xd984, 0x63a7, + 0xd985, 0x8887, + 0xd986, 0x63a7, + 0xd987, 0xdffd, + 0xd988, 0x00f9, + 0xd989, 0x1002, + 0xd98a, 0x0000, + }; + int i, err; + + /* set uC clock and activate it */ + err = set_phy_regs(phy, uCclock40MHz); + msleep(500); + if (err) + return err; + err = set_phy_regs(phy, uCclockActivate); + msleep(500); + if (err) + return err; + + /* write TWINAX EDC firmware into PHY */ + for (i = 0; i < ARRAY_SIZE(twinax_edc) && !err; i += 2) + err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, twinax_edc[i], + twinax_edc[i + 1]); + /* activate uC */ + err = set_phy_regs(phy, uCactivate); + if (!err) + phy->priv = edc_twinax; + return err; +} + +/* + * Return Module Type. + */ +static int ael2020_get_module_type(struct cphy *phy, int delay_ms) +{ + int v; + unsigned int stat; + + v = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL2020_GPIO_STAT, &stat); + if (v) + return v; + + if (stat & (0x1 << (AEL2020_GPIO_MODDET*4))) { + /* module absent */ + return phy_modtype_none; + } + + return ael2xxx_get_module_type(phy, delay_ms); +} + +/* + * Enable PHY interrupts. We enable "Module Detection" interrupts (on any + * state transition) and then generic Link Alarm Status Interrupt (LASI). + */ +static int ael2020_intr_enable(struct cphy *phy) +{ + int err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL, + 0x2 << (AEL2020_GPIO_MODDET*4)); + return err ? err : t3_phy_lasi_intr_enable(phy); +} + +/* + * Disable PHY interrupts. The mirror of the above ... + */ +static int ael2020_intr_disable(struct cphy *phy) +{ + int err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL, + 0x1 << (AEL2020_GPIO_MODDET*4)); + return err ? err : t3_phy_lasi_intr_disable(phy); +} + +/* + * Clear PHY interrupt state. + */ +static int ael2020_intr_clear(struct cphy *phy) +{ + /* + * The GPIO Interrupt register on the AEL2020 is a "Latching High" + * (LH) register which is cleared to the current state when it's read. + * Thus, we simply read the register and discard the result. + */ + unsigned int stat; + int err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL2020_GPIO_INTR, &stat); + return err ? err : t3_phy_lasi_intr_clear(phy); +} + +/* + * Reset the PHY and put it into a canonical operating state. + */ +static int ael2020_reset(struct cphy *phy, int wait) +{ + static struct reg_val regs0[] = { + /* Erratum #2: CDRLOL asserted, causing PMA link down status */ + { MDIO_MMD_PMAPMD, 0xc003, 0xffff, 0x3101 }, + + /* force XAUI to send LF when RX_LOS is asserted */ + { MDIO_MMD_PMAPMD, 0xcd40, 0xffff, 0x0001 }, + + /* RX_LOS pin is active high */ + { MDIO_MMD_PMAPMD, AEL_OPT_SETTINGS, + 0x0020, 0x0020 }, + + /* output Module's Loss Of Signal (LOS) to LED */ + { MDIO_MMD_PMAPMD, AEL2020_GPIO_CFG+AEL2020_GPIO_LSTAT, + 0xffff, 0x0004 }, + { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL, + 0xffff, 0x8 << (AEL2020_GPIO_LSTAT*4) }, + + /* end */ + { 0, 0, 0, 0 } + }; + int err; + unsigned int lasi_ctrl; + + /* grab current interrupt state */ + err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_CTRL, + &lasi_ctrl); + if (err) + return err; + + err = t3_phy_reset(phy, MDIO_MMD_PMAPMD, 125); + if (err) + return err; + msleep(100); + + /* basic initialization for all module types */ + phy->priv = edc_none; + err = set_phy_regs(phy, regs0); + if (err) + return err; + + /* determine module type and perform appropriate initialization */ + err = ael2020_get_module_type(phy, 0); + if (err < 0) + return err; + phy->modtype = (u8)err; + if (err == phy_modtype_twinax || err == phy_modtype_twinax_long) + err = ael2020_setup_twinax_edc(phy, err); + else + err = ael2020_setup_sr_edc(phy); + if (err) + return err; + + /* reset wipes out interrupts, reenable them if they were on */ + if (lasi_ctrl & 1) + err = ael2005_intr_enable(phy); + return err; +} + +/* + * Handle a PHY interrupt. + */ +static int ael2020_intr_handler(struct cphy *phy) +{ + unsigned int stat; + int ret, edc_needed, cause = 0; + + ret = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL2020_GPIO_INTR, &stat); + if (ret) + return ret; + + if (stat & (0x1 << AEL2020_GPIO_MODDET)) { + /* modules have max 300 ms init time after hot plug */ + ret = ael2020_get_module_type(phy, 300); + if (ret < 0) + return ret; + + phy->modtype = (u8)ret; + if (ret == phy_modtype_none) + edc_needed = phy->priv; /* on unplug retain EDC */ + else if (ret == phy_modtype_twinax || + ret == phy_modtype_twinax_long) + edc_needed = edc_twinax; + else + edc_needed = edc_sr; + + if (edc_needed != phy->priv) { + ret = ael2020_reset(phy, 0); + return ret ? ret : cphy_cause_module_change; + } + cause = cphy_cause_module_change; + } + + ret = t3_phy_lasi_intr_handler(phy); + if (ret < 0) + return ret; + + ret |= cause; + return ret ? ret : cphy_cause_link_change; +} + +static struct cphy_ops ael2020_ops = { + .reset = ael2020_reset, + .intr_enable = ael2020_intr_enable, + .intr_disable = ael2020_intr_disable, + .intr_clear = ael2020_intr_clear, + .intr_handler = ael2020_intr_handler, + .get_link_status = get_link_status_r, + .power_down = ael1002_power_down, + .mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS, +}; + +int t3_ael2020_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr, + const struct mdio_ops *mdio_ops) +{ + cphy_init(phy, adapter, phy_addr, &ael2020_ops, mdio_ops, + SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE | + SUPPORTED_IRQ, "10GBASE-R"); + msleep(125); + return 0; +} + /* * Get link status for a 10GBASE-X device. */ @@ -1119,12 +1813,15 @@ static int get_link_status_x(struct cphy *phy, int *link_ok, int *speed, { if (link_ok) { unsigned int stat0, stat1, stat2; - int err = mdio_read(phy, MDIO_DEV_PMA_PMD, PMD_RSD, &stat0); + int err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, + MDIO_PMA_RXDET, &stat0); if (!err) - err = mdio_read(phy, MDIO_DEV_PCS, PCS_STAT1_X, &stat1); + err = t3_mdio_read(phy, MDIO_MMD_PCS, + MDIO_PCS_10GBX_STAT1, &stat1); if (!err) - err = mdio_read(phy, MDIO_DEV_XGXS, XS_LN_STAT, &stat2); + err = t3_mdio_read(phy, MDIO_MMD_PHYXS, + MDIO_PHYXS_LNSTAT, &stat2); if (err) return err; *link_ok = (stat0 & (stat1 >> 12) & (stat2 >> 12)) & 1; @@ -1144,6 +1841,7 @@ static struct cphy_ops qt2045_ops = { .intr_handler = t3_phy_lasi_intr_handler, .get_link_status = get_link_status_x, .power_down = ael1006_power_down, + .mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS, }; int t3_qt2045_phy_prep(struct cphy *phy, struct adapter *adapter, @@ -1159,9 +1857,10 @@ int t3_qt2045_phy_prep(struct cphy *phy, struct adapter *adapter, * Some cards where the PHY is supposed to be at address 0 actually * have it at 1. */ - if (!phy_addr && !mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR, &stat) && + if (!phy_addr && + !t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_STAT1, &stat) && stat == 0xffff) - phy->addr = 1; + phy->mdio.prtad = 1; return 0; } @@ -1175,15 +1874,16 @@ static int xaui_direct_get_link_status(struct cphy *phy, int *link_ok, { if (link_ok) { unsigned int status; + int prtad = phy->mdio.prtad; status = t3_read_reg(phy->adapter, - XGM_REG(A_XGM_SERDES_STAT0, phy->addr)) | + XGM_REG(A_XGM_SERDES_STAT0, prtad)) | t3_read_reg(phy->adapter, - XGM_REG(A_XGM_SERDES_STAT1, phy->addr)) | + XGM_REG(A_XGM_SERDES_STAT1, prtad)) | t3_read_reg(phy->adapter, - XGM_REG(A_XGM_SERDES_STAT2, phy->addr)) | + XGM_REG(A_XGM_SERDES_STAT2, prtad)) | t3_read_reg(phy->adapter, - XGM_REG(A_XGM_SERDES_STAT3, phy->addr)); + XGM_REG(A_XGM_SERDES_STAT3, prtad)); *link_ok = !(status & F_LOWSIG0); } if (speed) @@ -1211,7 +1911,7 @@ static struct cphy_ops xaui_direct_ops = { int t3_xaui_direct_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr, const struct mdio_ops *mdio_ops) { - cphy_init(phy, adapter, phy_addr, &xaui_direct_ops, mdio_ops, + cphy_init(phy, adapter, MDIO_PRTAD_NONE, &xaui_direct_ops, mdio_ops, SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_TP, "10GBASE-CX4"); return 0; diff --git a/drivers/net/cxgb3/aq100x.c b/drivers/net/cxgb3/aq100x.c new file mode 100644 index 000000000000..b1fd5bf836e4 --- /dev/null +++ b/drivers/net/cxgb3/aq100x.c @@ -0,0 +1,355 @@ +/* + * Copyright (c) 2005-2008 Chelsio, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "common.h" +#include "regs.h" + +enum { + /* MDIO_DEV_PMA_PMD registers */ + AQ_LINK_STAT = 0xe800, + AQ_IMASK_PMA = 0xf000, + + /* MDIO_DEV_XGXS registers */ + AQ_XAUI_RX_CFG = 0xc400, + AQ_XAUI_TX_CFG = 0xe400, + + /* MDIO_DEV_ANEG registers */ + AQ_1G_CTRL = 0xc400, + AQ_ANEG_STAT = 0xc800, + + /* MDIO_DEV_VEND1 registers */ + AQ_FW_VERSION = 0x0020, + AQ_IFLAG_GLOBAL = 0xfc00, + AQ_IMASK_GLOBAL = 0xff00, +}; + +enum { + IMASK_PMA = 1 << 2, + IMASK_GLOBAL = 1 << 15, + ADV_1G_FULL = 1 << 15, + ADV_1G_HALF = 1 << 14, + ADV_10G_FULL = 1 << 12, + AQ_RESET = (1 << 14) | (1 << 15), + AQ_LOWPOWER = 1 << 12, +}; + +static int aq100x_reset(struct cphy *phy, int wait) +{ + /* + * Ignore the caller specified wait time; always wait for the reset to + * complete. Can take up to 3s. + */ + int err = t3_phy_reset(phy, MDIO_MMD_VEND1, 3000); + + if (err) + CH_WARN(phy->adapter, "PHY%d: reset failed (0x%x).\n", + phy->mdio.prtad, err); + + return err; +} + +static int aq100x_intr_enable(struct cphy *phy) +{ + int err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AQ_IMASK_PMA, IMASK_PMA); + if (err) + return err; + + err = t3_mdio_write(phy, MDIO_MMD_VEND1, AQ_IMASK_GLOBAL, IMASK_GLOBAL); + return err; +} + +static int aq100x_intr_disable(struct cphy *phy) +{ + return t3_mdio_write(phy, MDIO_MMD_VEND1, AQ_IMASK_GLOBAL, 0); +} + +static int aq100x_intr_clear(struct cphy *phy) +{ + unsigned int v; + + t3_mdio_read(phy, MDIO_MMD_VEND1, AQ_IFLAG_GLOBAL, &v); + t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_STAT1, &v); + + return 0; +} + +static int aq100x_intr_handler(struct cphy *phy) +{ + int err; + unsigned int cause, v; + + err = t3_mdio_read(phy, MDIO_MMD_VEND1, AQ_IFLAG_GLOBAL, &cause); + if (err) + return err; + + /* Read (and reset) the latching version of the status */ + t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_STAT1, &v); + + return cphy_cause_link_change; +} + +static int aq100x_power_down(struct cphy *phy, int off) +{ + return mdio_set_flag(&phy->mdio, phy->mdio.prtad, + MDIO_MMD_PMAPMD, MDIO_CTRL1, + MDIO_CTRL1_LPOWER, off); +} + +static int aq100x_autoneg_enable(struct cphy *phy) +{ + int err; + + err = aq100x_power_down(phy, 0); + if (!err) + err = mdio_set_flag(&phy->mdio, phy->mdio.prtad, + MDIO_MMD_AN, MDIO_CTRL1, + BMCR_ANENABLE | BMCR_ANRESTART, 1); + + return err; +} + +static int aq100x_autoneg_restart(struct cphy *phy) +{ + int err; + + err = aq100x_power_down(phy, 0); + if (!err) + err = mdio_set_flag(&phy->mdio, phy->mdio.prtad, + MDIO_MMD_AN, MDIO_CTRL1, + BMCR_ANENABLE | BMCR_ANRESTART, 1); + + return err; +} + +static int aq100x_advertise(struct cphy *phy, unsigned int advertise_map) +{ + unsigned int adv; + int err; + + /* 10G advertisement */ + adv = 0; + if (advertise_map & ADVERTISED_10000baseT_Full) + adv |= ADV_10G_FULL; + err = t3_mdio_change_bits(phy, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL, + ADV_10G_FULL, adv); + if (err) + return err; + + /* 1G advertisement */ + adv = 0; + if (advertise_map & ADVERTISED_1000baseT_Full) + adv |= ADV_1G_FULL; + if (advertise_map & ADVERTISED_1000baseT_Half) + adv |= ADV_1G_HALF; + err = t3_mdio_change_bits(phy, MDIO_MMD_AN, AQ_1G_CTRL, + ADV_1G_FULL | ADV_1G_HALF, adv); + if (err) + return err; + + /* 100M, pause advertisement */ + adv = 0; + if (advertise_map & ADVERTISED_100baseT_Half) + adv |= ADVERTISE_100HALF; + if (advertise_map & ADVERTISED_100baseT_Full) + adv |= ADVERTISE_100FULL; + if (advertise_map & ADVERTISED_Pause) + adv |= ADVERTISE_PAUSE_CAP; + if (advertise_map & ADVERTISED_Asym_Pause) + adv |= ADVERTISE_PAUSE_ASYM; + err = t3_mdio_change_bits(phy, MDIO_MMD_AN, MDIO_AN_ADVERTISE, + 0xfe0, adv); + + return err; +} + +static int aq100x_set_loopback(struct cphy *phy, int mmd, int dir, int enable) +{ + return mdio_set_flag(&phy->mdio, phy->mdio.prtad, + MDIO_MMD_PMAPMD, MDIO_CTRL1, + BMCR_LOOPBACK, enable); +} + +static int aq100x_set_speed_duplex(struct cphy *phy, int speed, int duplex) +{ + /* no can do */ + return -1; +} + +static int aq100x_get_link_status(struct cphy *phy, int *link_ok, + int *speed, int *duplex, int *fc) +{ + int err; + unsigned int v; + + if (link_ok) { + err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AQ_LINK_STAT, &v); + if (err) + return err; + + *link_ok = v & 1; + if (!*link_ok) + return 0; + } + + err = t3_mdio_read(phy, MDIO_MMD_AN, AQ_ANEG_STAT, &v); + if (err) + return err; + + if (speed) { + switch (v & 0x6) { + case 0x6: + *speed = SPEED_10000; + break; + case 0x4: + *speed = SPEED_1000; + break; + case 0x2: + *speed = SPEED_100; + break; + case 0x0: + *speed = SPEED_10; + break; + } + } + + if (duplex) + *duplex = v & 1 ? DUPLEX_FULL : DUPLEX_HALF; + + return 0; +} + +static struct cphy_ops aq100x_ops = { + .reset = aq100x_reset, + .intr_enable = aq100x_intr_enable, + .intr_disable = aq100x_intr_disable, + .intr_clear = aq100x_intr_clear, + .intr_handler = aq100x_intr_handler, + .autoneg_enable = aq100x_autoneg_enable, + .autoneg_restart = aq100x_autoneg_restart, + .advertise = aq100x_advertise, + .set_loopback = aq100x_set_loopback, + .set_speed_duplex = aq100x_set_speed_duplex, + .get_link_status = aq100x_get_link_status, + .power_down = aq100x_power_down, + .mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS, +}; + +int t3_aq100x_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr, + const struct mdio_ops *mdio_ops) +{ + unsigned int v, v2, gpio, wait; + int err; + + cphy_init(phy, adapter, phy_addr, &aq100x_ops, mdio_ops, + SUPPORTED_1000baseT_Full | SUPPORTED_10000baseT_Full | + SUPPORTED_Autoneg | SUPPORTED_AUI, "1000/10GBASE-T"); + + /* + * The PHY has been out of reset ever since the system powered up. So + * we do a hard reset over here. + */ + gpio = phy_addr ? F_GPIO10_OUT_VAL : F_GPIO6_OUT_VAL; + t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, gpio, 0); + msleep(1); + t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, gpio, gpio); + + /* + * Give it enough time to load the firmware and get ready for mdio. + */ + msleep(1000); + wait = 500; /* in 10ms increments */ + do { + err = t3_mdio_read(phy, MDIO_MMD_VEND1, MDIO_CTRL1, &v); + if (err || v == 0xffff) { + + /* Allow prep_adapter to succeed when ffff is read */ + + CH_WARN(adapter, "PHY%d: reset failed (0x%x, 0x%x).\n", + phy_addr, err, v); + goto done; + } + + v &= AQ_RESET; + if (v) + msleep(10); + } while (v && --wait); + if (v) { + CH_WARN(adapter, "PHY%d: reset timed out (0x%x).\n", + phy_addr, v); + + goto done; /* let prep_adapter succeed */ + } + + /* Datasheet says 3s max but this has been observed */ + wait = (500 - wait) * 10 + 1000; + if (wait > 3000) + CH_WARN(adapter, "PHY%d: reset took %ums\n", phy_addr, wait); + + /* Firmware version check. */ + t3_mdio_read(phy, MDIO_MMD_VEND1, AQ_FW_VERSION, &v); + if (v != 30) { + CH_WARN(adapter, "PHY%d: unsupported firmware %d\n", + phy_addr, v); + return 0; /* allow t3_prep_adapter to succeed */ + } + + /* + * The PHY should start in really-low-power mode. Prepare it for normal + * operations. + */ + err = t3_mdio_read(phy, MDIO_MMD_VEND1, MDIO_CTRL1, &v); + if (err) + return err; + if (v & AQ_LOWPOWER) { + err = t3_mdio_change_bits(phy, MDIO_MMD_VEND1, MDIO_CTRL1, + AQ_LOWPOWER, 0); + if (err) + return err; + msleep(10); + } else + CH_WARN(adapter, "PHY%d does not start in low power mode.\n", + phy_addr); + + /* + * Verify XAUI settings, but let prep succeed no matter what. + */ + v = v2 = 0; + t3_mdio_read(phy, MDIO_MMD_PHYXS, AQ_XAUI_RX_CFG, &v); + t3_mdio_read(phy, MDIO_MMD_PHYXS, AQ_XAUI_TX_CFG, &v2); + if (v != 0x1b || v2 != 0x1b) + CH_WARN(adapter, + "PHY%d: incorrect XAUI settings (0x%x, 0x%x).\n", + phy_addr, v, v2); + +done: + return err; +} diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h index e508dc32f3ec..d21b705501a9 100644 --- a/drivers/net/cxgb3/common.h +++ b/drivers/net/cxgb3/common.h @@ -39,7 +39,7 @@ #include #include #include -#include +#include #include "version.h" #define CH_ERR(adap, fmt, ...) dev_err(&adap->pdev->dev, fmt, ## __VA_ARGS__) @@ -184,10 +184,11 @@ struct cphy; struct adapter; struct mdio_ops { - int (*read)(struct adapter *adapter, int phy_addr, int mmd_addr, - int reg_addr, unsigned int *val); - int (*write)(struct adapter *adapter, int phy_addr, int mmd_addr, - int reg_addr, unsigned int val); + int (*read)(struct net_device *dev, int phy_addr, int mmd_addr, + u16 reg_addr); + int (*write)(struct net_device *dev, int phy_addr, int mmd_addr, + u16 reg_addr, u16 val); + unsigned mode_support; }; struct adapter_info { @@ -520,27 +521,6 @@ enum { MAC_RXFIFO_SIZE = 32768 }; -/* IEEE 802.3 specified MDIO devices */ -enum { - MDIO_DEV_PMA_PMD = 1, - MDIO_DEV_WIS = 2, - MDIO_DEV_PCS = 3, - MDIO_DEV_XGXS = 4, - MDIO_DEV_ANEG = 7, - MDIO_DEV_VEND1 = 30, - MDIO_DEV_VEND2 = 31 -}; - -/* LASI control and status registers */ -enum { - RX_ALARM_CTRL = 0x9000, - TX_ALARM_CTRL = 0x9001, - LASI_CTRL = 0x9002, - RX_ALARM_STAT = 0x9003, - TX_ALARM_STAT = 0x9004, - LASI_STAT = 0x9005 -}; - /* PHY loopback direction */ enum { PHY_LOOPBACK_TX = 1, @@ -583,11 +563,12 @@ struct cphy_ops { int (*get_link_status)(struct cphy *phy, int *link_ok, int *speed, int *duplex, int *fc); int (*power_down)(struct cphy *phy, int enable); + + u32 mmds; }; /* A PHY instance */ struct cphy { - u8 addr; /* PHY address */ u8 modtype; /* PHY module type */ short priv; /* scratch pad */ unsigned int caps; /* PHY capabilities */ @@ -595,23 +576,23 @@ struct cphy { const char *desc; /* PHY description */ unsigned long fifo_errors; /* FIFO over/under-flows */ const struct cphy_ops *ops; /* PHY operations */ - int (*mdio_read)(struct adapter *adapter, int phy_addr, int mmd_addr, - int reg_addr, unsigned int *val); - int (*mdio_write)(struct adapter *adapter, int phy_addr, int mmd_addr, - int reg_addr, unsigned int val); + struct mdio_if_info mdio; }; /* Convenience MDIO read/write wrappers */ -static inline int mdio_read(struct cphy *phy, int mmd, int reg, - unsigned int *valp) +static inline int t3_mdio_read(struct cphy *phy, int mmd, int reg, + unsigned int *valp) { - return phy->mdio_read(phy->adapter, phy->addr, mmd, reg, valp); + int rc = phy->mdio.mdio_read(phy->mdio.dev, phy->mdio.prtad, mmd, reg); + *valp = (rc >= 0) ? rc : -1; + return (rc >= 0) ? 0 : rc; } -static inline int mdio_write(struct cphy *phy, int mmd, int reg, - unsigned int val) +static inline int t3_mdio_write(struct cphy *phy, int mmd, int reg, + unsigned int val) { - return phy->mdio_write(phy->adapter, phy->addr, mmd, reg, val); + return phy->mdio.mdio_write(phy->mdio.dev, phy->mdio.prtad, mmd, + reg, val); } /* Convenience initializer */ @@ -620,14 +601,16 @@ static inline void cphy_init(struct cphy *phy, struct adapter *adapter, const struct mdio_ops *mdio_ops, unsigned int caps, const char *desc) { - phy->addr = phy_addr; phy->caps = caps; phy->adapter = adapter; phy->desc = desc; phy->ops = phy_ops; if (mdio_ops) { - phy->mdio_read = mdio_ops->read; - phy->mdio_write = mdio_ops->write; + phy->mdio.prtad = phy_addr; + phy->mdio.mmds = phy_ops->mmds; + phy->mdio.mode_support = mdio_ops->mode_support; + phy->mdio.mdio_read = mdio_ops->read; + phy->mdio.mdio_write = mdio_ops->write; } } @@ -819,8 +802,12 @@ int t3_ael1006_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr, const struct mdio_ops *mdio_ops); int t3_ael2005_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr, const struct mdio_ops *mdio_ops); +int t3_ael2020_phy_prep(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *mdio_ops); int t3_qt2045_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr, const struct mdio_ops *mdio_ops); int t3_xaui_direct_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr, const struct mdio_ops *mdio_ops); +int t3_aq100x_phy_prep(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *mdio_ops); #endif /* __CHELSIO_COMMON_H */ diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index 17858b9a5830..538dda4422dc 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -37,7 +37,7 @@ #include #include #include -#include +#include #include #include #include @@ -91,6 +91,8 @@ static const struct pci_device_id cxgb3_pci_tbl[] = { CH_DEVICE(0x31, 3), /* T3B20 */ CH_DEVICE(0x32, 1), /* T3B02 */ CH_DEVICE(0x35, 6), /* T3C20-derived T3C10 */ + CH_DEVICE(0x36, 3), /* S320E-CR */ + CH_DEVICE(0x37, 7), /* N320E-G2 */ {0,} }; @@ -431,40 +433,78 @@ static int init_tp_parity(struct adapter *adap) for (i = 0; i < 16; i++) { struct cpl_smt_write_req *req; - skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL); + skb = alloc_skb(sizeof(*req), GFP_KERNEL); + if (!skb) + skb = adap->nofail_skb; + if (!skb) + goto alloc_skb_fail; + req = (struct cpl_smt_write_req *)__skb_put(skb, sizeof(*req)); memset(req, 0, sizeof(*req)); req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, i)); req->iff = i; t3_mgmt_tx(adap, skb); + if (skb == adap->nofail_skb) { + await_mgmt_replies(adap, cnt, i + 1); + adap->nofail_skb = alloc_skb(sizeof(*greq), GFP_KERNEL); + if (!adap->nofail_skb) + goto alloc_skb_fail; + } } for (i = 0; i < 2048; i++) { struct cpl_l2t_write_req *req; - skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL); + skb = alloc_skb(sizeof(*req), GFP_KERNEL); + if (!skb) + skb = adap->nofail_skb; + if (!skb) + goto alloc_skb_fail; + req = (struct cpl_l2t_write_req *)__skb_put(skb, sizeof(*req)); memset(req, 0, sizeof(*req)); req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, i)); req->params = htonl(V_L2T_W_IDX(i)); t3_mgmt_tx(adap, skb); + if (skb == adap->nofail_skb) { + await_mgmt_replies(adap, cnt, 16 + i + 1); + adap->nofail_skb = alloc_skb(sizeof(*greq), GFP_KERNEL); + if (!adap->nofail_skb) + goto alloc_skb_fail; + } } for (i = 0; i < 2048; i++) { struct cpl_rte_write_req *req; - skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL); + skb = alloc_skb(sizeof(*req), GFP_KERNEL); + if (!skb) + skb = adap->nofail_skb; + if (!skb) + goto alloc_skb_fail; + req = (struct cpl_rte_write_req *)__skb_put(skb, sizeof(*req)); memset(req, 0, sizeof(*req)); req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_RTE_WRITE_REQ, i)); req->l2t_idx = htonl(V_L2T_W_IDX(i)); t3_mgmt_tx(adap, skb); + if (skb == adap->nofail_skb) { + await_mgmt_replies(adap, cnt, 16 + 2048 + i + 1); + adap->nofail_skb = alloc_skb(sizeof(*greq), GFP_KERNEL); + if (!adap->nofail_skb) + goto alloc_skb_fail; + } } - skb = alloc_skb(sizeof(*greq), GFP_KERNEL | __GFP_NOFAIL); + skb = alloc_skb(sizeof(*greq), GFP_KERNEL); + if (!skb) + skb = adap->nofail_skb; + if (!skb) + goto alloc_skb_fail; + greq = (struct cpl_set_tcb_field *)__skb_put(skb, sizeof(*greq)); memset(greq, 0, sizeof(*greq)); greq->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); @@ -473,8 +513,17 @@ static int init_tp_parity(struct adapter *adap) t3_mgmt_tx(adap, skb); i = await_mgmt_replies(adap, cnt, 16 + 2048 + 2048 + 1); + if (skb == adap->nofail_skb) { + i = await_mgmt_replies(adap, cnt, 16 + 2048 + 2048 + 1); + adap->nofail_skb = alloc_skb(sizeof(*greq), GFP_KERNEL); + } + t3_tp_set_offload_mode(adap, 0); return i; + +alloc_skb_fail: + t3_tp_set_offload_mode(adap, 0); + return -ENOMEM; } /** @@ -869,7 +918,12 @@ static int send_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo, struct mngt_pktsched_wr *req; int ret; - skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL); + skb = alloc_skb(sizeof(*req), GFP_KERNEL); + if (!skb) + skb = adap->nofail_skb; + if (!skb) + return -ENOMEM; + req = (struct mngt_pktsched_wr *)skb_put(skb, sizeof(*req)); req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_MNGT)); req->mngt_opcode = FW_MNGTOPCODE_PKTSCHED_SET; @@ -879,6 +933,12 @@ static int send_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo, req->max = hi; req->binding = port; ret = t3_mgmt_tx(adap, skb); + if (skb == adap->nofail_skb) { + adap->nofail_skb = alloc_skb(sizeof(struct cpl_set_tcb_field), + GFP_KERNEL); + if (!adap->nofail_skb) + ret = -ENOMEM; + } return ret; } @@ -1593,7 +1653,7 @@ static int get_settings(struct net_device *dev, struct ethtool_cmd *cmd) } cmd->port = (cmd->supported & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE; - cmd->phy_address = p->phy.addr; + cmd->phy_address = p->phy.mdio.prtad; cmd->transceiver = XCVR_EXTERNAL; cmd->autoneg = p->link_config.autoneg; cmd->maxtxpkt = 0; @@ -2308,70 +2368,25 @@ static int cxgb_ioctl(struct net_device *dev, struct ifreq *req, int cmd) struct mii_ioctl_data *data = if_mii(req); struct port_info *pi = netdev_priv(dev); struct adapter *adapter = pi->adapter; - int ret, mmd; switch (cmd) { - case SIOCGMIIPHY: - data->phy_id = pi->phy.addr; + case SIOCGMIIREG: + case SIOCSMIIREG: + /* Convert phy_id from older PRTAD/DEVAD format */ + if (is_10G(adapter) && + !mdio_phy_id_is_c45(data->phy_id) && + (data->phy_id & 0x1f00) && + !(data->phy_id & 0xe0e0)) + data->phy_id = mdio_phy_id_c45(data->phy_id >> 8, + data->phy_id & 0x1f); /* FALLTHRU */ - case SIOCGMIIREG:{ - u32 val; - struct cphy *phy = &pi->phy; - - if (!phy->mdio_read) - return -EOPNOTSUPP; - if (is_10G(adapter)) { - mmd = data->phy_id >> 8; - if (!mmd) - mmd = MDIO_DEV_PCS; - else if (mmd > MDIO_DEV_VEND2) - return -EINVAL; - - ret = - phy->mdio_read(adapter, data->phy_id & 0x1f, - mmd, data->reg_num, &val); - } else - ret = - phy->mdio_read(adapter, data->phy_id & 0x1f, - 0, data->reg_num & 0x1f, - &val); - if (!ret) - data->val_out = val; - break; - } - case SIOCSMIIREG:{ - struct cphy *phy = &pi->phy; - - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - if (!phy->mdio_write) - return -EOPNOTSUPP; - if (is_10G(adapter)) { - mmd = data->phy_id >> 8; - if (!mmd) - mmd = MDIO_DEV_PCS; - else if (mmd > MDIO_DEV_VEND2) - return -EINVAL; - - ret = - phy->mdio_write(adapter, - data->phy_id & 0x1f, mmd, - data->reg_num, - data->val_in); - } else - ret = - phy->mdio_write(adapter, - data->phy_id & 0x1f, 0, - data->reg_num & 0x1f, - data->val_in); - break; - } + case SIOCGMIIPHY: + return mdio_mii_ioctl(&pi->phy.mdio, data, cmd); case SIOCCHIOCTL: return cxgb_extension_ioctl(dev, req->ifr_data); default: return -EOPNOTSUPP; } - return ret; } static int cxgb_change_mtu(struct net_device *dev, int new_mtu) @@ -3063,6 +3078,14 @@ static int __devinit init_one(struct pci_dev *pdev, goto out_disable_device; } + adapter->nofail_skb = + alloc_skb(sizeof(struct cpl_set_tcb_field), GFP_KERNEL); + if (!adapter->nofail_skb) { + dev_err(&pdev->dev, "cannot allocate nofail buffer\n"); + err = -ENOMEM; + goto out_free_adapter; + } + adapter->regs = ioremap_nocache(mmio_start, mmio_len); if (!adapter->regs) { dev_err(&pdev->dev, "cannot map device registers\n"); @@ -3106,7 +3129,6 @@ static int __devinit init_one(struct pci_dev *pdev, netdev->mem_start = mmio_start; netdev->mem_end = mmio_start + mmio_len - 1; netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO; - netdev->features |= NETIF_F_LLTX; netdev->features |= NETIF_F_GRO; if (pci_using_dac) netdev->features |= NETIF_F_HIGHDMA; @@ -3220,6 +3242,8 @@ static void __devexit remove_one(struct pci_dev *pdev) free_netdev(adapter->port[i]); iounmap(adapter->regs); + if (adapter->nofail_skb) + kfree_skb(adapter->nofail_skb); kfree(adapter); pci_release_regions(pdev); pci_disable_device(pdev); diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c index 620d80be6aac..f9f54b57b28c 100644 --- a/drivers/net/cxgb3/cxgb3_offload.c +++ b/drivers/net/cxgb3/cxgb3_offload.c @@ -566,13 +566,31 @@ static void t3_process_tid_release_list(struct work_struct *work) spin_unlock_bh(&td->tid_release_lock); skb = alloc_skb(sizeof(struct cpl_tid_release), - GFP_KERNEL | __GFP_NOFAIL); + GFP_KERNEL); + if (!skb) + skb = td->nofail_skb; + if (!skb) { + spin_lock_bh(&td->tid_release_lock); + p->ctx = (void *)td->tid_release_list; + td->tid_release_list = (struct t3c_tid_entry *)p; + break; + } mk_tid_release(skb, p - td->tid_maps.tid_tab); cxgb3_ofld_send(tdev, skb); p->ctx = NULL; + if (skb == td->nofail_skb) + td->nofail_skb = + alloc_skb(sizeof(struct cpl_tid_release), + GFP_KERNEL); spin_lock_bh(&td->tid_release_lock); } + td->release_list_incomplete = (td->tid_release_list == NULL) ? 0 : 1; spin_unlock_bh(&td->tid_release_lock); + + if (!td->nofail_skb) + td->nofail_skb = + alloc_skb(sizeof(struct cpl_tid_release), + GFP_KERNEL); } /* use ctx as a next pointer in the tid release list */ @@ -585,7 +603,7 @@ void cxgb3_queue_tid_release(struct t3cdev *tdev, unsigned int tid) p->ctx = (void *)td->tid_release_list; p->client = NULL; td->tid_release_list = p; - if (!p->ctx) + if (!p->ctx || td->release_list_incomplete) schedule_work(&td->tid_release_task); spin_unlock_bh(&td->tid_release_lock); } @@ -1274,6 +1292,9 @@ int cxgb3_offload_activate(struct adapter *adapter) if (list_empty(&adapter_list)) register_netevent_notifier(&nb); + t->nofail_skb = alloc_skb(sizeof(struct cpl_tid_release), GFP_KERNEL); + t->release_list_incomplete = 0; + add_adapter(adapter); return 0; @@ -1298,6 +1319,8 @@ void cxgb3_offload_deactivate(struct adapter *adapter) T3C_DATA(tdev) = NULL; t3_free_l2t(L2DATA(tdev)); L2DATA(tdev) = NULL; + if (t->nofail_skb) + kfree_skb(t->nofail_skb); kfree(t); } diff --git a/drivers/net/cxgb3/cxgb3_offload.h b/drivers/net/cxgb3/cxgb3_offload.h index a8e8e5fcdf84..55945f422aec 100644 --- a/drivers/net/cxgb3/cxgb3_offload.h +++ b/drivers/net/cxgb3/cxgb3_offload.h @@ -191,6 +191,9 @@ struct t3c_data { struct t3c_tid_entry *tid_release_list; spinlock_t tid_release_lock; struct work_struct tid_release_task; + + struct sk_buff *nofail_skb; + unsigned int release_list_incomplete; }; /* diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c index b3ee2bc1a005..29c79eb43beb 100644 --- a/drivers/net/cxgb3/sge.c +++ b/drivers/net/cxgb3/sge.c @@ -653,7 +653,8 @@ static void t3_reset_qset(struct sge_qset *q) q->txq_stopped = 0; q->tx_reclaim_timer.function = NULL; /* for t3_stop_sge_timers() */ q->rx_reclaim_timer.function = NULL; - q->lro_frag_tbl.nr_frags = q->lro_frag_tbl.len = 0; + q->nomem = 0; + napi_free_frags(&q->napi); } @@ -1239,7 +1240,6 @@ int t3_eth_xmit(struct sk_buff *skb, struct net_device *dev) q = &qs->txq[TXQ_ETH]; txq = netdev_get_tx_queue(dev, qidx); - spin_lock(&q->lock); reclaim_completed_tx(adap, q, TX_RECLAIM_CHUNK); credits = q->size - q->in_use; @@ -1250,7 +1250,6 @@ int t3_eth_xmit(struct sk_buff *skb, struct net_device *dev) dev_err(&adap->pdev->dev, "%s: Tx ring %u full while queue awake!\n", dev->name, q->cntxt_id & 7); - spin_unlock(&q->lock); return NETDEV_TX_BUSY; } @@ -1284,9 +1283,6 @@ int t3_eth_xmit(struct sk_buff *skb, struct net_device *dev) if (vlan_tx_tag_present(skb) && pi->vlan_grp) qs->port_stats[SGE_PSTAT_VLANINS]++; - dev->trans_start = jiffies; - spin_unlock(&q->lock); - /* * We do not use Tx completion interrupts to free DMAd Tx packets. * This is good for performamce but means that we rely on new Tx @@ -2073,20 +2069,19 @@ static void lro_add_page(struct adapter *adap, struct sge_qset *qs, struct sge_fl *fl, int len, int complete) { struct rx_sw_desc *sd = &fl->sdesc[fl->cidx]; + struct sk_buff *skb = NULL; struct cpl_rx_pkt *cpl; - struct skb_frag_struct *rx_frag = qs->lro_frag_tbl.frags; - int nr_frags = qs->lro_frag_tbl.nr_frags; - int frag_len = qs->lro_frag_tbl.len; + struct skb_frag_struct *rx_frag; + int nr_frags; int offset = 0; - if (!nr_frags) { - offset = 2 + sizeof(struct cpl_rx_pkt); - qs->lro_va = cpl = sd->pg_chunk.va + 2; + if (!qs->nomem) { + skb = napi_get_frags(&qs->napi); + qs->nomem = !skb; } fl->credits--; - len -= offset; pci_dma_sync_single_for_cpu(adap->pdev, pci_unmap_addr(sd, dma_addr), fl->buf_size - SGE_PG_RSVD, @@ -2099,21 +2094,38 @@ static void lro_add_page(struct adapter *adap, struct sge_qset *qs, fl->alloc_size, PCI_DMA_FROMDEVICE); + if (!skb) { + put_page(sd->pg_chunk.page); + if (complete) + qs->nomem = 0; + return; + } + + rx_frag = skb_shinfo(skb)->frags; + nr_frags = skb_shinfo(skb)->nr_frags; + + if (!nr_frags) { + offset = 2 + sizeof(struct cpl_rx_pkt); + qs->lro_va = sd->pg_chunk.va + 2; + } + len -= offset; + prefetch(qs->lro_va); rx_frag += nr_frags; rx_frag->page = sd->pg_chunk.page; rx_frag->page_offset = sd->pg_chunk.offset + offset; rx_frag->size = len; - frag_len += len; - qs->lro_frag_tbl.nr_frags++; - qs->lro_frag_tbl.len = frag_len; + skb->len += len; + skb->data_len += len; + skb->truesize += len; + skb_shinfo(skb)->nr_frags++; if (!complete) return; - qs->lro_frag_tbl.ip_summed = CHECKSUM_UNNECESSARY; + skb->ip_summed = CHECKSUM_UNNECESSARY; cpl = qs->lro_va; if (unlikely(cpl->vlan_valid)) { @@ -2122,15 +2134,11 @@ static void lro_add_page(struct adapter *adap, struct sge_qset *qs, struct vlan_group *grp = pi->vlan_grp; if (likely(grp != NULL)) { - vlan_gro_frags(&qs->napi, grp, ntohs(cpl->vlan), - &qs->lro_frag_tbl); - goto out; + vlan_gro_frags(&qs->napi, grp, ntohs(cpl->vlan)); + return; } } - napi_gro_frags(&qs->napi, &qs->lro_frag_tbl); - -out: - qs->lro_frag_tbl.nr_frags = qs->lro_frag_tbl.len = 0; + napi_gro_frags(&qs->napi); } /** @@ -2299,8 +2307,6 @@ no_mem: if (fl->use_pages) { void *addr = fl->sdesc[fl->cidx].pg_chunk.va; - prefetch(&qs->lro_frag_tbl); - prefetch(addr); #if L1_CACHE_BYTES < 128 prefetch(addr + L1_CACHE_BYTES); @@ -2846,11 +2852,12 @@ static void sge_timer_tx(unsigned long data) unsigned int tbd[SGE_TXQ_PER_SET] = {0, 0}; unsigned long next_period; - if (spin_trylock(&qs->txq[TXQ_ETH].lock)) { - tbd[TXQ_ETH] = reclaim_completed_tx(adap, &qs->txq[TXQ_ETH], - TX_RECLAIM_TIMER_CHUNK); - spin_unlock(&qs->txq[TXQ_ETH].lock); + if (__netif_tx_trylock(qs->tx_q)) { + tbd[TXQ_ETH] = reclaim_completed_tx(adap, &qs->txq[TXQ_ETH], + TX_RECLAIM_TIMER_CHUNK); + __netif_tx_unlock(qs->tx_q); } + if (spin_trylock(&qs->txq[TXQ_OFLD].lock)) { tbd[TXQ_OFLD] = reclaim_completed_tx(adap, &qs->txq[TXQ_OFLD], TX_RECLAIM_TIMER_CHUNK); @@ -2858,8 +2865,8 @@ static void sge_timer_tx(unsigned long data) } next_period = TX_RECLAIM_PERIOD >> - (max(tbd[TXQ_ETH], tbd[TXQ_OFLD]) / - TX_RECLAIM_TIMER_CHUNK); + (max(tbd[TXQ_ETH], tbd[TXQ_OFLD]) / + TX_RECLAIM_TIMER_CHUNK); mod_timer(&qs->tx_reclaim_timer, jiffies + next_period); } diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c index 4950d5d789ae..870d44992c70 100644 --- a/drivers/net/cxgb3/t3_hw.c +++ b/drivers/net/cxgb3/t3_hw.c @@ -204,35 +204,33 @@ static void mi1_init(struct adapter *adap, const struct adapter_info *ai) /* * MI1 read/write operations for clause 22 PHYs. */ -static int t3_mi1_read(struct adapter *adapter, int phy_addr, int mmd_addr, - int reg_addr, unsigned int *valp) +static int t3_mi1_read(struct net_device *dev, int phy_addr, int mmd_addr, + u16 reg_addr) { + struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; int ret; u32 addr = V_REGADDR(reg_addr) | V_PHYADDR(phy_addr); - if (mmd_addr) - return -EINVAL; - mutex_lock(&adapter->mdio_lock); t3_set_reg_field(adapter, A_MI1_CFG, V_ST(M_ST), V_ST(1)); t3_write_reg(adapter, A_MI1_ADDR, addr); t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(2)); ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 10); if (!ret) - *valp = t3_read_reg(adapter, A_MI1_DATA); + ret = t3_read_reg(adapter, A_MI1_DATA); mutex_unlock(&adapter->mdio_lock); return ret; } -static int t3_mi1_write(struct adapter *adapter, int phy_addr, int mmd_addr, - int reg_addr, unsigned int val) +static int t3_mi1_write(struct net_device *dev, int phy_addr, int mmd_addr, + u16 reg_addr, u16 val) { + struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; int ret; u32 addr = V_REGADDR(reg_addr) | V_PHYADDR(phy_addr); - if (mmd_addr) - return -EINVAL; - mutex_lock(&adapter->mdio_lock); t3_set_reg_field(adapter, A_MI1_CFG, V_ST(M_ST), V_ST(1)); t3_write_reg(adapter, A_MI1_ADDR, addr); @@ -244,8 +242,9 @@ static int t3_mi1_write(struct adapter *adapter, int phy_addr, int mmd_addr, } static const struct mdio_ops mi1_mdio_ops = { - t3_mi1_read, - t3_mi1_write + .read = t3_mi1_read, + .write = t3_mi1_write, + .mode_support = MDIO_SUPPORTS_C22 }; /* @@ -268,9 +267,11 @@ static int mi1_wr_addr(struct adapter *adapter, int phy_addr, int mmd_addr, /* * MI1 read/write operations for indirect-addressed PHYs. */ -static int mi1_ext_read(struct adapter *adapter, int phy_addr, int mmd_addr, - int reg_addr, unsigned int *valp) +static int mi1_ext_read(struct net_device *dev, int phy_addr, int mmd_addr, + u16 reg_addr) { + struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; int ret; mutex_lock(&adapter->mdio_lock); @@ -280,15 +281,17 @@ static int mi1_ext_read(struct adapter *adapter, int phy_addr, int mmd_addr, ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 10); if (!ret) - *valp = t3_read_reg(adapter, A_MI1_DATA); + ret = t3_read_reg(adapter, A_MI1_DATA); } mutex_unlock(&adapter->mdio_lock); return ret; } -static int mi1_ext_write(struct adapter *adapter, int phy_addr, int mmd_addr, - int reg_addr, unsigned int val) +static int mi1_ext_write(struct net_device *dev, int phy_addr, int mmd_addr, + u16 reg_addr, u16 val) { + struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; int ret; mutex_lock(&adapter->mdio_lock); @@ -304,8 +307,9 @@ static int mi1_ext_write(struct adapter *adapter, int phy_addr, int mmd_addr, } static const struct mdio_ops mi1_mdio_ext_ops = { - mi1_ext_read, - mi1_ext_write + .read = mi1_ext_read, + .write = mi1_ext_write, + .mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22 }; /** @@ -325,10 +329,10 @@ int t3_mdio_change_bits(struct cphy *phy, int mmd, int reg, unsigned int clear, int ret; unsigned int val; - ret = mdio_read(phy, mmd, reg, &val); + ret = t3_mdio_read(phy, mmd, reg, &val); if (!ret) { val &= ~clear; - ret = mdio_write(phy, mmd, reg, val | set); + ret = t3_mdio_write(phy, mmd, reg, val | set); } return ret; } @@ -348,15 +352,16 @@ int t3_phy_reset(struct cphy *phy, int mmd, int wait) int err; unsigned int ctl; - err = t3_mdio_change_bits(phy, mmd, MII_BMCR, BMCR_PDOWN, BMCR_RESET); + err = t3_mdio_change_bits(phy, mmd, MDIO_CTRL1, MDIO_CTRL1_LPOWER, + MDIO_CTRL1_RESET); if (err || !wait) return err; do { - err = mdio_read(phy, mmd, MII_BMCR, &ctl); + err = t3_mdio_read(phy, mmd, MDIO_CTRL1, &ctl); if (err) return err; - ctl &= BMCR_RESET; + ctl &= MDIO_CTRL1_RESET; if (ctl) msleep(1); } while (ctl && --wait); @@ -377,7 +382,7 @@ int t3_phy_advertise(struct cphy *phy, unsigned int advert) int err; unsigned int val = 0; - err = mdio_read(phy, 0, MII_CTRL1000, &val); + err = t3_mdio_read(phy, MDIO_DEVAD_NONE, MII_CTRL1000, &val); if (err) return err; @@ -387,7 +392,7 @@ int t3_phy_advertise(struct cphy *phy, unsigned int advert) if (advert & ADVERTISED_1000baseT_Full) val |= ADVERTISE_1000FULL; - err = mdio_write(phy, 0, MII_CTRL1000, val); + err = t3_mdio_write(phy, MDIO_DEVAD_NONE, MII_CTRL1000, val); if (err) return err; @@ -404,7 +409,7 @@ int t3_phy_advertise(struct cphy *phy, unsigned int advert) val |= ADVERTISE_PAUSE_CAP; if (advert & ADVERTISED_Asym_Pause) val |= ADVERTISE_PAUSE_ASYM; - return mdio_write(phy, 0, MII_ADVERTISE, val); + return t3_mdio_write(phy, MDIO_DEVAD_NONE, MII_ADVERTISE, val); } /** @@ -427,7 +432,7 @@ int t3_phy_advertise_fiber(struct cphy *phy, unsigned int advert) val |= ADVERTISE_1000XPAUSE; if (advert & ADVERTISED_Asym_Pause) val |= ADVERTISE_1000XPSE_ASYM; - return mdio_write(phy, 0, MII_ADVERTISE, val); + return t3_mdio_write(phy, MDIO_DEVAD_NONE, MII_ADVERTISE, val); } /** @@ -444,7 +449,7 @@ int t3_set_phy_speed_duplex(struct cphy *phy, int speed, int duplex) int err; unsigned int ctl; - err = mdio_read(phy, 0, MII_BMCR, &ctl); + err = t3_mdio_read(phy, MDIO_DEVAD_NONE, MII_BMCR, &ctl); if (err) return err; @@ -462,34 +467,36 @@ int t3_set_phy_speed_duplex(struct cphy *phy, int speed, int duplex) } if (ctl & BMCR_SPEED1000) /* auto-negotiation required for GigE */ ctl |= BMCR_ANENABLE; - return mdio_write(phy, 0, MII_BMCR, ctl); + return t3_mdio_write(phy, MDIO_DEVAD_NONE, MII_BMCR, ctl); } int t3_phy_lasi_intr_enable(struct cphy *phy) { - return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 1); + return t3_mdio_write(phy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_CTRL, + MDIO_PMA_LASI_LSALARM); } int t3_phy_lasi_intr_disable(struct cphy *phy) { - return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 0); + return t3_mdio_write(phy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_CTRL, 0); } int t3_phy_lasi_intr_clear(struct cphy *phy) { u32 val; - return mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &val); + return t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_STAT, &val); } int t3_phy_lasi_intr_handler(struct cphy *phy) { unsigned int status; - int err = mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &status); + int err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_STAT, + &status); if (err) return err; - return (status & 1) ? cphy_cause_link_change : 0; + return (status & MDIO_PMA_LASI_LSALARM) ? cphy_cause_link_change : 0; } static const struct adapter_info t3_adap_info[] = { @@ -519,6 +526,11 @@ static const struct adapter_info t3_adap_info[] = { F_GPIO10_OEN | F_GPIO1_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL, { S_GPIO9 }, SUPPORTED_10000baseT_Full | SUPPORTED_AUI, &mi1_mdio_ext_ops, "Chelsio T310" }, + {1, 0, 0, + F_GPIO1_OEN | F_GPIO6_OEN | F_GPIO7_OEN | + F_GPIO1_OUT_VAL | F_GPIO6_OUT_VAL, + { S_GPIO9 }, SUPPORTED_10000baseT_Full | SUPPORTED_AUI, + &mi1_mdio_ext_ops, "Chelsio N320E-G2" }, }; /* @@ -545,6 +557,8 @@ static const struct port_type_info port_types[] = { { t3_qt2045_phy_prep }, { t3_ael1006_phy_prep }, { NULL }, + { t3_aq100x_phy_prep }, + { t3_ael2020_phy_prep }, }; #define VPD_ENTRY(name, len) \ @@ -3864,6 +3878,7 @@ int t3_prep_adapter(struct adapter *adapter, const struct adapter_info *ai, return -EINVAL; } + p->phy.mdio.dev = adapter->port[i]; ret = pti->phy_prep(&p->phy, adapter, ai->phy_base_addr + j, ai->mdio_ops); if (ret) @@ -3923,7 +3938,7 @@ int t3_replay_prep_adapter(struct adapter *adapter) ; pti = &port_types[adapter->params.vpd.port_type[j]]; - ret = pti->phy_prep(&p->phy, adapter, p->phy.addr, NULL); + ret = pti->phy_prep(&p->phy, adapter, p->phy.mdio.prtad, NULL); if (ret) return ret; p->phy.ops->power_down(&p->phy, 1); diff --git a/drivers/net/cxgb3/version.h b/drivers/net/cxgb3/version.h index 7bf963ec5548..9d0bd9dd9ab1 100644 --- a/drivers/net/cxgb3/version.h +++ b/drivers/net/cxgb3/version.h @@ -35,10 +35,10 @@ #define DRV_DESC "Chelsio T3 Network Driver" #define DRV_NAME "cxgb3" /* Driver version */ -#define DRV_VERSION "1.1.2-ko" +#define DRV_VERSION "1.1.3-ko" /* Firmware version */ #define FW_VERSION_MAJOR 7 -#define FW_VERSION_MINOR 1 +#define FW_VERSION_MINOR 4 #define FW_VERSION_MICRO 0 #endif /* __CHELSIO_VERSION_H */ diff --git a/drivers/net/cxgb3/vsc8211.c b/drivers/net/cxgb3/vsc8211.c index d07130971b8f..4f9a1c2724f4 100644 --- a/drivers/net/cxgb3/vsc8211.c +++ b/drivers/net/cxgb3/vsc8211.c @@ -91,17 +91,18 @@ enum { */ static int vsc8211_reset(struct cphy *cphy, int wait) { - return t3_phy_reset(cphy, 0, 0); + return t3_phy_reset(cphy, MDIO_DEVAD_NONE, 0); } static int vsc8211_intr_enable(struct cphy *cphy) { - return mdio_write(cphy, 0, VSC8211_INTR_ENABLE, INTR_MASK); + return t3_mdio_write(cphy, MDIO_DEVAD_NONE, VSC8211_INTR_ENABLE, + INTR_MASK); } static int vsc8211_intr_disable(struct cphy *cphy) { - return mdio_write(cphy, 0, VSC8211_INTR_ENABLE, 0); + return t3_mdio_write(cphy, MDIO_DEVAD_NONE, VSC8211_INTR_ENABLE, 0); } static int vsc8211_intr_clear(struct cphy *cphy) @@ -109,18 +110,20 @@ static int vsc8211_intr_clear(struct cphy *cphy) u32 val; /* Clear PHY interrupts by reading the register. */ - return mdio_read(cphy, 0, VSC8211_INTR_STATUS, &val); + return t3_mdio_read(cphy, MDIO_DEVAD_NONE, VSC8211_INTR_STATUS, &val); } static int vsc8211_autoneg_enable(struct cphy *cphy) { - return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE, + return t3_mdio_change_bits(cphy, MDIO_DEVAD_NONE, MII_BMCR, + BMCR_PDOWN | BMCR_ISOLATE, BMCR_ANENABLE | BMCR_ANRESTART); } static int vsc8211_autoneg_restart(struct cphy *cphy) { - return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE, + return t3_mdio_change_bits(cphy, MDIO_DEVAD_NONE, MII_BMCR, + BMCR_PDOWN | BMCR_ISOLATE, BMCR_ANRESTART); } @@ -130,9 +133,9 @@ static int vsc8211_get_link_status(struct cphy *cphy, int *link_ok, unsigned int bmcr, status, lpa, adv; int err, sp = -1, dplx = -1, pause = 0; - err = mdio_read(cphy, 0, MII_BMCR, &bmcr); + err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_BMCR, &bmcr); if (!err) - err = mdio_read(cphy, 0, MII_BMSR, &status); + err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_BMSR, &status); if (err) return err; @@ -142,7 +145,8 @@ static int vsc8211_get_link_status(struct cphy *cphy, int *link_ok, * once more to get the current link state. */ if (!(status & BMSR_LSTATUS)) - err = mdio_read(cphy, 0, MII_BMSR, &status); + err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_BMSR, + &status); if (err) return err; *link_ok = (status & BMSR_LSTATUS) != 0; @@ -156,7 +160,8 @@ static int vsc8211_get_link_status(struct cphy *cphy, int *link_ok, else sp = SPEED_10; } else if (status & BMSR_ANEGCOMPLETE) { - err = mdio_read(cphy, 0, VSC8211_AUX_CTRL_STAT, &status); + err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, VSC8211_AUX_CTRL_STAT, + &status); if (err) return err; @@ -170,9 +175,11 @@ static int vsc8211_get_link_status(struct cphy *cphy, int *link_ok, sp = SPEED_1000; if (fc && dplx == DUPLEX_FULL) { - err = mdio_read(cphy, 0, MII_LPA, &lpa); + err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_LPA, + &lpa); if (!err) - err = mdio_read(cphy, 0, MII_ADVERTISE, &adv); + err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, + MII_ADVERTISE, &adv); if (err) return err; @@ -202,9 +209,9 @@ static int vsc8211_get_link_status_fiber(struct cphy *cphy, int *link_ok, unsigned int bmcr, status, lpa, adv; int err, sp = -1, dplx = -1, pause = 0; - err = mdio_read(cphy, 0, MII_BMCR, &bmcr); + err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_BMCR, &bmcr); if (!err) - err = mdio_read(cphy, 0, MII_BMSR, &status); + err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_BMSR, &status); if (err) return err; @@ -214,7 +221,8 @@ static int vsc8211_get_link_status_fiber(struct cphy *cphy, int *link_ok, * once more to get the current link state. */ if (!(status & BMSR_LSTATUS)) - err = mdio_read(cphy, 0, MII_BMSR, &status); + err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_BMSR, + &status); if (err) return err; *link_ok = (status & BMSR_LSTATUS) != 0; @@ -228,9 +236,10 @@ static int vsc8211_get_link_status_fiber(struct cphy *cphy, int *link_ok, else sp = SPEED_10; } else if (status & BMSR_ANEGCOMPLETE) { - err = mdio_read(cphy, 0, MII_LPA, &lpa); + err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_LPA, &lpa); if (!err) - err = mdio_read(cphy, 0, MII_ADVERTISE, &adv); + err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_ADVERTISE, + &adv); if (err) return err; @@ -270,23 +279,23 @@ static int vsc8211_set_automdi(struct cphy *phy, int enable) { int err; - err = mdio_write(phy, 0, VSC8211_EXT_PAGE_AXS, 0x52b5); + err = t3_mdio_write(phy, MDIO_DEVAD_NONE, VSC8211_EXT_PAGE_AXS, 0x52b5); if (err) return err; - err = mdio_write(phy, 0, 18, 0x12); + err = t3_mdio_write(phy, MDIO_DEVAD_NONE, 18, 0x12); if (err) return err; - err = mdio_write(phy, 0, 17, enable ? 0x2803 : 0x3003); + err = t3_mdio_write(phy, MDIO_DEVAD_NONE, 17, enable ? 0x2803 : 0x3003); if (err) return err; - err = mdio_write(phy, 0, 16, 0x87fa); + err = t3_mdio_write(phy, MDIO_DEVAD_NONE, 16, 0x87fa); if (err) return err; - err = mdio_write(phy, 0, VSC8211_EXT_PAGE_AXS, 0); + err = t3_mdio_write(phy, MDIO_DEVAD_NONE, VSC8211_EXT_PAGE_AXS, 0); if (err) return err; @@ -315,7 +324,7 @@ static int vsc8211_intr_handler(struct cphy *cphy) unsigned int cause; int err, cphy_cause = 0; - err = mdio_read(cphy, 0, VSC8211_INTR_STATUS, &cause); + err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, VSC8211_INTR_STATUS, &cause); if (err) return err; @@ -367,12 +376,13 @@ int t3_vsc8211_phy_prep(struct cphy *phy, struct adapter *adapter, SUPPORTED_TP | SUPPORTED_IRQ, "10/100/1000BASE-T"); msleep(20); /* PHY needs ~10ms to start responding to MDIO */ - err = mdio_read(phy, 0, VSC8211_EXT_CTRL, &val); + err = t3_mdio_read(phy, MDIO_DEVAD_NONE, VSC8211_EXT_CTRL, &val); if (err) return err; if (val & VSC_CTRL_MEDIA_MODE_HI) { /* copper interface, just need to configure the LEDs */ - return mdio_write(phy, 0, VSC8211_LED_CTRL, 0x100); + return t3_mdio_write(phy, MDIO_DEVAD_NONE, VSC8211_LED_CTRL, + 0x100); } phy->caps = SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | @@ -380,20 +390,20 @@ int t3_vsc8211_phy_prep(struct cphy *phy, struct adapter *adapter, phy->desc = "1000BASE-X"; phy->ops = &vsc8211_fiber_ops; - err = mdio_write(phy, 0, VSC8211_EXT_PAGE_AXS, 1); + err = t3_mdio_write(phy, MDIO_DEVAD_NONE, VSC8211_EXT_PAGE_AXS, 1); if (err) return err; - err = mdio_write(phy, 0, VSC8211_SIGDET_CTRL, 1); + err = t3_mdio_write(phy, MDIO_DEVAD_NONE, VSC8211_SIGDET_CTRL, 1); if (err) return err; - err = mdio_write(phy, 0, VSC8211_EXT_PAGE_AXS, 0); + err = t3_mdio_write(phy, MDIO_DEVAD_NONE, VSC8211_EXT_PAGE_AXS, 0); if (err) return err; - err = mdio_write(phy, 0, VSC8211_EXT_CTRL, - val | VSC_CTRL_CLAUSE37_VIEW); + err = t3_mdio_write(phy, MDIO_DEVAD_NONE, VSC8211_EXT_CTRL, + val | VSC_CTRL_CLAUSE37_VIEW); if (err) return err; diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c new file mode 100644 index 000000000000..2df8fb0af701 --- /dev/null +++ b/drivers/net/davinci_emac.c @@ -0,0 +1,2829 @@ +/* + * DaVinci Ethernet Medium Access Controller + * + * DaVinci EMAC is based upon CPPI 3.0 TI DMA engine + * + * Copyright (C) 2009 Texas Instruments. + * + * --------------------------------------------------------------------------- + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * --------------------------------------------------------------------------- + * History: + * 0-5 A number of folks worked on this driver in bits and pieces but the major + * contribution came from Suraj Iyer and Anant Gole + * 6.0 Anant Gole - rewrote the driver as per Linux conventions + * 6.1 Chaithrika U S - added support for Gigabit and RMII features, + * PHY layer usage + */ + +/** Pending Items in this driver: + * 1. Use Linux cache infrastcture for DMA'ed memory (dma_xxx functions) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +static int debug_level; +module_param(debug_level, int, 0); +MODULE_PARM_DESC(debug_level, "DaVinci EMAC debug level (NETIF_MSG bits)"); + +/* Netif debug messages possible */ +#define DAVINCI_EMAC_DEBUG (NETIF_MSG_DRV | \ + NETIF_MSG_PROBE | \ + NETIF_MSG_LINK | \ + NETIF_MSG_TIMER | \ + NETIF_MSG_IFDOWN | \ + NETIF_MSG_IFUP | \ + NETIF_MSG_RX_ERR | \ + NETIF_MSG_TX_ERR | \ + NETIF_MSG_TX_QUEUED | \ + NETIF_MSG_INTR | \ + NETIF_MSG_TX_DONE | \ + NETIF_MSG_RX_STATUS | \ + NETIF_MSG_PKTDATA | \ + NETIF_MSG_HW | \ + NETIF_MSG_WOL) + +/* version info */ +#define EMAC_MAJOR_VERSION 6 +#define EMAC_MINOR_VERSION 1 +#define EMAC_MODULE_VERSION "6.1" +MODULE_VERSION(EMAC_MODULE_VERSION); +static const char emac_version_string[] = "TI DaVinci EMAC Linux v6.1"; + +/* Configuration items */ +#define EMAC_DEF_PASS_CRC (0) /* Do not pass CRC upto frames */ +#define EMAC_DEF_QOS_EN (0) /* EMAC proprietary QoS disabled */ +#define EMAC_DEF_NO_BUFF_CHAIN (0) /* No buffer chain */ +#define EMAC_DEF_MACCTRL_FRAME_EN (0) /* Discard Maccontrol frames */ +#define EMAC_DEF_SHORT_FRAME_EN (0) /* Discard short frames */ +#define EMAC_DEF_ERROR_FRAME_EN (0) /* Discard error frames */ +#define EMAC_DEF_PROM_EN (0) /* Promiscous disabled */ +#define EMAC_DEF_PROM_CH (0) /* Promiscous channel is 0 */ +#define EMAC_DEF_BCAST_EN (1) /* Broadcast enabled */ +#define EMAC_DEF_BCAST_CH (0) /* Broadcast channel is 0 */ +#define EMAC_DEF_MCAST_EN (1) /* Multicast enabled */ +#define EMAC_DEF_MCAST_CH (0) /* Multicast channel is 0 */ + +#define EMAC_DEF_TXPRIO_FIXED (1) /* TX Priority is fixed */ +#define EMAC_DEF_TXPACING_EN (0) /* TX pacing NOT supported*/ + +#define EMAC_DEF_BUFFER_OFFSET (0) /* Buffer offset to DMA (future) */ +#define EMAC_DEF_MIN_ETHPKTSIZE (60) /* Minimum ethernet pkt size */ +#define EMAC_DEF_MAX_FRAME_SIZE (1500 + 14 + 4 + 4) +#define EMAC_DEF_TX_CH (0) /* Default 0th channel */ +#define EMAC_DEF_RX_CH (0) /* Default 0th channel */ +#define EMAC_DEF_MDIO_TICK_MS (10) /* typically 1 tick=1 ms) */ +#define EMAC_DEF_MAX_TX_CH (1) /* Max TX channels configured */ +#define EMAC_DEF_MAX_RX_CH (1) /* Max RX channels configured */ +#define EMAC_POLL_WEIGHT (64) /* Default NAPI poll weight */ + +/* Buffer descriptor parameters */ +#define EMAC_DEF_TX_MAX_SERVICE (32) /* TX max service BD's */ +#define EMAC_DEF_RX_MAX_SERVICE (64) /* should = netdev->weight */ + +/* EMAC register related defines */ +#define EMAC_ALL_MULTI_REG_VALUE (0xFFFFFFFF) +#define EMAC_NUM_MULTICAST_BITS (64) +#define EMAC_TEARDOWN_VALUE (0xFFFFFFFC) +#define EMAC_TX_CONTROL_TX_ENABLE_VAL (0x1) +#define EMAC_RX_CONTROL_RX_ENABLE_VAL (0x1) +#define EMAC_MAC_HOST_ERR_INTMASK_VAL (0x2) +#define EMAC_RX_UNICAST_CLEAR_ALL (0xFF) +#define EMAC_INT_MASK_CLEAR (0xFF) + +/* RX MBP register bit positions */ +#define EMAC_RXMBP_PASSCRC_MASK BIT(30) +#define EMAC_RXMBP_QOSEN_MASK BIT(29) +#define EMAC_RXMBP_NOCHAIN_MASK BIT(28) +#define EMAC_RXMBP_CMFEN_MASK BIT(24) +#define EMAC_RXMBP_CSFEN_MASK BIT(23) +#define EMAC_RXMBP_CEFEN_MASK BIT(22) +#define EMAC_RXMBP_CAFEN_MASK BIT(21) +#define EMAC_RXMBP_PROMCH_SHIFT (16) +#define EMAC_RXMBP_PROMCH_MASK (0x7 << 16) +#define EMAC_RXMBP_BROADEN_MASK BIT(13) +#define EMAC_RXMBP_BROADCH_SHIFT (8) +#define EMAC_RXMBP_BROADCH_MASK (0x7 << 8) +#define EMAC_RXMBP_MULTIEN_MASK BIT(5) +#define EMAC_RXMBP_MULTICH_SHIFT (0) +#define EMAC_RXMBP_MULTICH_MASK (0x7) +#define EMAC_RXMBP_CHMASK (0x7) + +/* EMAC register definitions/bit maps used */ +# define EMAC_MBP_RXPROMISC (0x00200000) +# define EMAC_MBP_PROMISCCH(ch) (((ch) & 0x7) << 16) +# define EMAC_MBP_RXBCAST (0x00002000) +# define EMAC_MBP_BCASTCHAN(ch) (((ch) & 0x7) << 8) +# define EMAC_MBP_RXMCAST (0x00000020) +# define EMAC_MBP_MCASTCHAN(ch) ((ch) & 0x7) + +/* EMAC mac_control register */ +#define EMAC_MACCONTROL_TXPTYPE (0x200) +#define EMAC_MACCONTROL_TXPACEEN (0x40) +#define EMAC_MACCONTROL_MIIEN (0x20) +#define EMAC_MACCONTROL_GIGABITEN (0x80) +#define EMAC_MACCONTROL_GIGABITEN_SHIFT (7) +#define EMAC_MACCONTROL_FULLDUPLEXEN (0x1) +#define EMAC_MACCONTROL_RMIISPEED_MASK BIT(15) + +/* GIGABIT MODE related bits */ +#define EMAC_DM646X_MACCONTORL_GMIIEN BIT(5) +#define EMAC_DM646X_MACCONTORL_GIG BIT(7) +#define EMAC_DM646X_MACCONTORL_GIGFORCE BIT(17) + +/* EMAC mac_status register */ +#define EMAC_MACSTATUS_TXERRCODE_MASK (0xF00000) +#define EMAC_MACSTATUS_TXERRCODE_SHIFT (20) +#define EMAC_MACSTATUS_TXERRCH_MASK (0x7) +#define EMAC_MACSTATUS_TXERRCH_SHIFT (16) +#define EMAC_MACSTATUS_RXERRCODE_MASK (0xF000) +#define EMAC_MACSTATUS_RXERRCODE_SHIFT (12) +#define EMAC_MACSTATUS_RXERRCH_MASK (0x7) +#define EMAC_MACSTATUS_RXERRCH_SHIFT (8) + +/* EMAC RX register masks */ +#define EMAC_RX_MAX_LEN_MASK (0xFFFF) +#define EMAC_RX_BUFFER_OFFSET_MASK (0xFFFF) + +/* MAC_IN_VECTOR (0x180) register bit fields */ +#define EMAC_DM644X_MAC_IN_VECTOR_HOST_INT (0x20000) +#define EMAC_DM644X_MAC_IN_VECTOR_STATPEND_INT (0x10000) +#define EMAC_DM644X_MAC_IN_VECTOR_RX_INT_VEC (0x0100) +#define EMAC_DM644X_MAC_IN_VECTOR_TX_INT_VEC (0x01) + +/** NOTE:: For DM646x the IN_VECTOR has changed */ +#define EMAC_DM646X_MAC_IN_VECTOR_RX_INT_VEC BIT(EMAC_DEF_RX_CH) +#define EMAC_DM646X_MAC_IN_VECTOR_TX_INT_VEC BIT(16 + EMAC_DEF_TX_CH) + +/* CPPI bit positions */ +#define EMAC_CPPI_SOP_BIT BIT(31) +#define EMAC_CPPI_EOP_BIT BIT(30) +#define EMAC_CPPI_OWNERSHIP_BIT BIT(29) +#define EMAC_CPPI_EOQ_BIT BIT(28) +#define EMAC_CPPI_TEARDOWN_COMPLETE_BIT BIT(27) +#define EMAC_CPPI_PASS_CRC_BIT BIT(26) +#define EMAC_RX_BD_BUF_SIZE (0xFFFF) +#define EMAC_BD_LENGTH_FOR_CACHE (16) /* only CPPI bytes */ +#define EMAC_RX_BD_PKT_LENGTH_MASK (0xFFFF) + +/* Max hardware defines */ +#define EMAC_MAX_TXRX_CHANNELS (8) /* Max hardware channels */ +#define EMAC_DEF_MAX_MULTICAST_ADDRESSES (64) /* Max mcast addr's */ + +/* EMAC Peripheral Device Register Memory Layout structure */ +#define EMAC_TXIDVER 0x0 +#define EMAC_TXCONTROL 0x4 +#define EMAC_TXTEARDOWN 0x8 +#define EMAC_RXIDVER 0x10 +#define EMAC_RXCONTROL 0x14 +#define EMAC_RXTEARDOWN 0x18 +#define EMAC_TXINTSTATRAW 0x80 +#define EMAC_TXINTSTATMASKED 0x84 +#define EMAC_TXINTMASKSET 0x88 +#define EMAC_TXINTMASKCLEAR 0x8C +#define EMAC_MACINVECTOR 0x90 + +#define EMAC_DM646X_MACEOIVECTOR 0x94 + +#define EMAC_RXINTSTATRAW 0xA0 +#define EMAC_RXINTSTATMASKED 0xA4 +#define EMAC_RXINTMASKSET 0xA8 +#define EMAC_RXINTMASKCLEAR 0xAC +#define EMAC_MACINTSTATRAW 0xB0 +#define EMAC_MACINTSTATMASKED 0xB4 +#define EMAC_MACINTMASKSET 0xB8 +#define EMAC_MACINTMASKCLEAR 0xBC + +#define EMAC_RXMBPENABLE 0x100 +#define EMAC_RXUNICASTSET 0x104 +#define EMAC_RXUNICASTCLEAR 0x108 +#define EMAC_RXMAXLEN 0x10C +#define EMAC_RXBUFFEROFFSET 0x110 +#define EMAC_RXFILTERLOWTHRESH 0x114 + +#define EMAC_MACCONTROL 0x160 +#define EMAC_MACSTATUS 0x164 +#define EMAC_EMCONTROL 0x168 +#define EMAC_FIFOCONTROL 0x16C +#define EMAC_MACCONFIG 0x170 +#define EMAC_SOFTRESET 0x174 +#define EMAC_MACSRCADDRLO 0x1D0 +#define EMAC_MACSRCADDRHI 0x1D4 +#define EMAC_MACHASH1 0x1D8 +#define EMAC_MACHASH2 0x1DC +#define EMAC_MACADDRLO 0x500 +#define EMAC_MACADDRHI 0x504 +#define EMAC_MACINDEX 0x508 + +/* EMAC HDP and Completion registors */ +#define EMAC_TXHDP(ch) (0x600 + (ch * 4)) +#define EMAC_RXHDP(ch) (0x620 + (ch * 4)) +#define EMAC_TXCP(ch) (0x640 + (ch * 4)) +#define EMAC_RXCP(ch) (0x660 + (ch * 4)) + +/* EMAC statistics registers */ +#define EMAC_RXGOODFRAMES 0x200 +#define EMAC_RXBCASTFRAMES 0x204 +#define EMAC_RXMCASTFRAMES 0x208 +#define EMAC_RXPAUSEFRAMES 0x20C +#define EMAC_RXCRCERRORS 0x210 +#define EMAC_RXALIGNCODEERRORS 0x214 +#define EMAC_RXOVERSIZED 0x218 +#define EMAC_RXJABBER 0x21C +#define EMAC_RXUNDERSIZED 0x220 +#define EMAC_RXFRAGMENTS 0x224 +#define EMAC_RXFILTERED 0x228 +#define EMAC_RXQOSFILTERED 0x22C +#define EMAC_RXOCTETS 0x230 +#define EMAC_TXGOODFRAMES 0x234 +#define EMAC_TXBCASTFRAMES 0x238 +#define EMAC_TXMCASTFRAMES 0x23C +#define EMAC_TXPAUSEFRAMES 0x240 +#define EMAC_TXDEFERRED 0x244 +#define EMAC_TXCOLLISION 0x248 +#define EMAC_TXSINGLECOLL 0x24C +#define EMAC_TXMULTICOLL 0x250 +#define EMAC_TXEXCESSIVECOLL 0x254 +#define EMAC_TXLATECOLL 0x258 +#define EMAC_TXUNDERRUN 0x25C +#define EMAC_TXCARRIERSENSE 0x260 +#define EMAC_TXOCTETS 0x264 +#define EMAC_NETOCTETS 0x280 +#define EMAC_RXSOFOVERRUNS 0x284 +#define EMAC_RXMOFOVERRUNS 0x288 +#define EMAC_RXDMAOVERRUNS 0x28C + +/* EMAC DM644x control registers */ +#define EMAC_CTRL_EWCTL (0x4) +#define EMAC_CTRL_EWINTTCNT (0x8) + +/* EMAC MDIO related */ +/* Mask & Control defines */ +#define MDIO_CONTROL_CLKDIV (0xFF) +#define MDIO_CONTROL_ENABLE BIT(30) +#define MDIO_USERACCESS_GO BIT(31) +#define MDIO_USERACCESS_WRITE BIT(30) +#define MDIO_USERACCESS_READ (0) +#define MDIO_USERACCESS_REGADR (0x1F << 21) +#define MDIO_USERACCESS_PHYADR (0x1F << 16) +#define MDIO_USERACCESS_DATA (0xFFFF) +#define MDIO_USERPHYSEL_LINKSEL BIT(7) +#define MDIO_VER_MODID (0xFFFF << 16) +#define MDIO_VER_REVMAJ (0xFF << 8) +#define MDIO_VER_REVMIN (0xFF) + +#define MDIO_USERACCESS(inst) (0x80 + (inst * 8)) +#define MDIO_USERPHYSEL(inst) (0x84 + (inst * 8)) +#define MDIO_CONTROL (0x04) + +/* EMAC DM646X control module registers */ +#define EMAC_DM646X_CMRXINTEN (0x14) +#define EMAC_DM646X_CMTXINTEN (0x18) + +/* EMAC EOI codes for C0 */ +#define EMAC_DM646X_MAC_EOI_C0_RXEN (0x01) +#define EMAC_DM646X_MAC_EOI_C0_TXEN (0x02) + +/** net_buf_obj: EMAC network bufferdata structure + * + * EMAC network buffer data structure + */ +struct emac_netbufobj { + void *buf_token; + char *data_ptr; + int length; +}; + +/** net_pkt_obj: EMAC network packet data structure + * + * EMAC network packet data structure - supports buffer list (for future) + */ +struct emac_netpktobj { + void *pkt_token; /* data token may hold tx/rx chan id */ + struct emac_netbufobj *buf_list; /* array of network buffer objects */ + int num_bufs; + int pkt_length; +}; + +/** emac_tx_bd: EMAC TX Buffer descriptor data structure + * + * EMAC TX Buffer descriptor data structure + */ +struct emac_tx_bd { + int h_next; + int buff_ptr; + int off_b_len; + int mode; /* SOP, EOP, ownership, EOQ, teardown,Qstarv, length */ + struct emac_tx_bd __iomem *next; + void *buf_token; +}; + +/** emac_txch: EMAC TX Channel data structure + * + * EMAC TX Channel data structure + */ +struct emac_txch { + /* Config related */ + u32 num_bd; + u32 service_max; + + /* CPPI specific */ + u32 alloc_size; + void __iomem *bd_mem; + struct emac_tx_bd __iomem *bd_pool_head; + struct emac_tx_bd __iomem *active_queue_head; + struct emac_tx_bd __iomem *active_queue_tail; + struct emac_tx_bd __iomem *last_hw_bdprocessed; + u32 queue_active; + u32 teardown_pending; + u32 *tx_complete; + + /** statistics */ + u32 proc_count; /* TX: # of times emac_tx_bdproc is called */ + u32 mis_queued_packets; + u32 queue_reinit; + u32 end_of_queue_add; + u32 out_of_tx_bd; + u32 no_active_pkts; /* IRQ when there were no packets to process */ + u32 active_queue_count; +}; + +/** emac_rx_bd: EMAC RX Buffer descriptor data structure + * + * EMAC RX Buffer descriptor data structure + */ +struct emac_rx_bd { + int h_next; + int buff_ptr; + int off_b_len; + int mode; + struct emac_rx_bd __iomem *next; + void *data_ptr; + void *buf_token; +}; + +/** emac_rxch: EMAC RX Channel data structure + * + * EMAC RX Channel data structure + */ +struct emac_rxch { + /* configuration info */ + u32 num_bd; + u32 service_max; + u32 buf_size; + char mac_addr[6]; + + /** CPPI specific */ + u32 alloc_size; + void __iomem *bd_mem; + struct emac_rx_bd __iomem *bd_pool_head; + struct emac_rx_bd __iomem *active_queue_head; + struct emac_rx_bd __iomem *active_queue_tail; + u32 queue_active; + u32 teardown_pending; + + /* packet and buffer objects */ + struct emac_netpktobj pkt_queue; + struct emac_netbufobj buf_queue; + + /** statistics */ + u32 proc_count; /* number of times emac_rx_bdproc is called */ + u32 processed_bd; + u32 recycled_bd; + u32 out_of_rx_bd; + u32 out_of_rx_buffers; + u32 queue_reinit; + u32 end_of_queue_add; + u32 end_of_queue; + u32 mis_queued_packets; +}; + +/* emac_priv: EMAC private data structure + * + * EMAC adapter private data structure + */ +struct emac_priv { + u32 msg_enable; + struct net_device *ndev; + struct platform_device *pdev; + struct napi_struct napi; + char mac_addr[6]; + spinlock_t tx_lock; + spinlock_t rx_lock; + void __iomem *remap_addr; + u32 emac_base_phys; + void __iomem *emac_base; + void __iomem *ctrl_base; + void __iomem *emac_ctrl_ram; + u32 ctrl_ram_size; + struct emac_txch *txch[EMAC_DEF_MAX_TX_CH]; + struct emac_rxch *rxch[EMAC_DEF_MAX_RX_CH]; + u32 link; /* 1=link on, 0=link off */ + u32 speed; /* 0=Auto Neg, 1=No PHY, 10,100, 1000 - mbps */ + u32 duplex; /* Link duplex: 0=Half, 1=Full */ + u32 rx_buf_size; + u32 isr_count; + u8 rmii_en; + u8 version; + struct net_device_stats net_dev_stats; + u32 mac_hash1; + u32 mac_hash2; + u32 multicast_hash_cnt[EMAC_NUM_MULTICAST_BITS]; + u32 rx_addr_type; + /* periodic timer required for MDIO polling */ + struct timer_list periodic_timer; + u32 periodic_ticks; + u32 timer_active; + u32 phy_mask; + /* mii_bus,phy members */ + struct mii_bus *mii_bus; + struct phy_device *phydev; + spinlock_t lock; +}; + +/* clock frequency for EMAC */ +static struct clk *emac_clk; +static unsigned long emac_bus_frequency; +static unsigned long mdio_max_freq; + +/* EMAC internal utility function */ +static inline u32 emac_virt_to_phys(void __iomem *addr) +{ + return (u32 __force) io_v2p(addr); +} + +/* Cache macros - Packet buffers would be from skb pool which is cached */ +#define EMAC_VIRT_NOCACHE(addr) (addr) +#define EMAC_CACHE_INVALIDATE(addr, size) \ + dma_cache_maint((void *)addr, size, DMA_FROM_DEVICE) +#define EMAC_CACHE_WRITEBACK(addr, size) \ + dma_cache_maint((void *)addr, size, DMA_TO_DEVICE) +#define EMAC_CACHE_WRITEBACK_INVALIDATE(addr, size) \ + dma_cache_maint((void *)addr, size, DMA_BIDIRECTIONAL) + +/* DM644x does not have BD's in cached memory - so no cache functions */ +#define BD_CACHE_INVALIDATE(addr, size) +#define BD_CACHE_WRITEBACK(addr, size) +#define BD_CACHE_WRITEBACK_INVALIDATE(addr, size) + +/* EMAC TX Host Error description strings */ +static char *emac_txhost_errcodes[16] = { + "No error", "SOP error", "Ownership bit not set in SOP buffer", + "Zero Next Buffer Descriptor Pointer Without EOP", + "Zero Buffer Pointer", "Zero Buffer Length", "Packet Length Error", + "Reserved", "Reserved", "Reserved", "Reserved", "Reserved", + "Reserved", "Reserved", "Reserved", "Reserved" +}; + +/* EMAC RX Host Error description strings */ +static char *emac_rxhost_errcodes[16] = { + "No error", "Reserved", "Ownership bit not set in input buffer", + "Reserved", "Zero Buffer Pointer", "Reserved", "Reserved", + "Reserved", "Reserved", "Reserved", "Reserved", "Reserved", + "Reserved", "Reserved", "Reserved", "Reserved" +}; + +/* Helper macros */ +#define emac_read(reg) ioread32(priv->emac_base + (reg)) +#define emac_write(reg, val) iowrite32(val, priv->emac_base + (reg)) + +#define emac_ctrl_read(reg) ioread32((priv->ctrl_base + (reg))) +#define emac_ctrl_write(reg, val) iowrite32(val, (priv->ctrl_base + (reg))) + +#define emac_mdio_read(reg) ioread32(bus->priv + (reg)) +#define emac_mdio_write(reg, val) iowrite32(val, (bus->priv + (reg))) + +/** + * emac_dump_regs: Dump important EMAC registers to debug terminal + * @priv: The DaVinci EMAC private adapter structure + * + * Executes ethtool set cmd & sets phy mode + * + */ +static void emac_dump_regs(struct emac_priv *priv) +{ + struct device *emac_dev = &priv->ndev->dev; + + /* Print important registers in EMAC */ + dev_info(emac_dev, "EMAC Basic registers\n"); + dev_info(emac_dev, "EMAC: EWCTL: %08X, EWINTTCNT: %08X\n", + emac_ctrl_read(EMAC_CTRL_EWCTL), + emac_ctrl_read(EMAC_CTRL_EWINTTCNT)); + dev_info(emac_dev, "EMAC: TXID: %08X %s, RXID: %08X %s\n", + emac_read(EMAC_TXIDVER), + ((emac_read(EMAC_TXCONTROL)) ? "enabled" : "disabled"), + emac_read(EMAC_RXIDVER), + ((emac_read(EMAC_RXCONTROL)) ? "enabled" : "disabled")); + dev_info(emac_dev, "EMAC: TXIntRaw:%08X, TxIntMasked: %08X, "\ + "TxIntMasSet: %08X\n", emac_read(EMAC_TXINTSTATRAW), + emac_read(EMAC_TXINTSTATMASKED), emac_read(EMAC_TXINTMASKSET)); + dev_info(emac_dev, "EMAC: RXIntRaw:%08X, RxIntMasked: %08X, "\ + "RxIntMasSet: %08X\n", emac_read(EMAC_RXINTSTATRAW), + emac_read(EMAC_RXINTSTATMASKED), emac_read(EMAC_RXINTMASKSET)); + dev_info(emac_dev, "EMAC: MacIntRaw:%08X, MacIntMasked: %08X, "\ + "MacInVector=%08X\n", emac_read(EMAC_MACINTSTATRAW), + emac_read(EMAC_MACINTSTATMASKED), emac_read(EMAC_MACINVECTOR)); + dev_info(emac_dev, "EMAC: EmuControl:%08X, FifoControl: %08X\n", + emac_read(EMAC_EMCONTROL), emac_read(EMAC_FIFOCONTROL)); + dev_info(emac_dev, "EMAC: MBPEnable:%08X, RXUnicastSet: %08X, "\ + "RXMaxLen=%08X\n", emac_read(EMAC_RXMBPENABLE), + emac_read(EMAC_RXUNICASTSET), emac_read(EMAC_RXMAXLEN)); + dev_info(emac_dev, "EMAC: MacControl:%08X, MacStatus: %08X, "\ + "MacConfig=%08X\n", emac_read(EMAC_MACCONTROL), + emac_read(EMAC_MACSTATUS), emac_read(EMAC_MACCONFIG)); + dev_info(emac_dev, "EMAC: TXHDP[0]:%08X, RXHDP[0]: %08X\n", + emac_read(EMAC_TXHDP(0)), emac_read(EMAC_RXHDP(0))); + dev_info(emac_dev, "EMAC Statistics\n"); + dev_info(emac_dev, "EMAC: rx_good_frames:%d\n", + emac_read(EMAC_RXGOODFRAMES)); + dev_info(emac_dev, "EMAC: rx_broadcast_frames:%d\n", + emac_read(EMAC_RXBCASTFRAMES)); + dev_info(emac_dev, "EMAC: rx_multicast_frames:%d\n", + emac_read(EMAC_RXMCASTFRAMES)); + dev_info(emac_dev, "EMAC: rx_pause_frames:%d\n", + emac_read(EMAC_RXPAUSEFRAMES)); + dev_info(emac_dev, "EMAC: rx_crcerrors:%d\n", + emac_read(EMAC_RXCRCERRORS)); + dev_info(emac_dev, "EMAC: rx_align_code_errors:%d\n", + emac_read(EMAC_RXALIGNCODEERRORS)); + dev_info(emac_dev, "EMAC: rx_oversized_frames:%d\n", + emac_read(EMAC_RXOVERSIZED)); + dev_info(emac_dev, "EMAC: rx_jabber_frames:%d\n", + emac_read(EMAC_RXJABBER)); + dev_info(emac_dev, "EMAC: rx_undersized_frames:%d\n", + emac_read(EMAC_RXUNDERSIZED)); + dev_info(emac_dev, "EMAC: rx_fragments:%d\n", + emac_read(EMAC_RXFRAGMENTS)); + dev_info(emac_dev, "EMAC: rx_filtered_frames:%d\n", + emac_read(EMAC_RXFILTERED)); + dev_info(emac_dev, "EMAC: rx_qos_filtered_frames:%d\n", + emac_read(EMAC_RXQOSFILTERED)); + dev_info(emac_dev, "EMAC: rx_octets:%d\n", + emac_read(EMAC_RXOCTETS)); + dev_info(emac_dev, "EMAC: tx_goodframes:%d\n", + emac_read(EMAC_TXGOODFRAMES)); + dev_info(emac_dev, "EMAC: tx_bcastframes:%d\n", + emac_read(EMAC_TXBCASTFRAMES)); + dev_info(emac_dev, "EMAC: tx_mcastframes:%d\n", + emac_read(EMAC_TXMCASTFRAMES)); + dev_info(emac_dev, "EMAC: tx_pause_frames:%d\n", + emac_read(EMAC_TXPAUSEFRAMES)); + dev_info(emac_dev, "EMAC: tx_deferred_frames:%d\n", + emac_read(EMAC_TXDEFERRED)); + dev_info(emac_dev, "EMAC: tx_collision_frames:%d\n", + emac_read(EMAC_TXCOLLISION)); + dev_info(emac_dev, "EMAC: tx_single_coll_frames:%d\n", + emac_read(EMAC_TXSINGLECOLL)); + dev_info(emac_dev, "EMAC: tx_mult_coll_frames:%d\n", + emac_read(EMAC_TXMULTICOLL)); + dev_info(emac_dev, "EMAC: tx_excessive_collisions:%d\n", + emac_read(EMAC_TXEXCESSIVECOLL)); + dev_info(emac_dev, "EMAC: tx_late_collisions:%d\n", + emac_read(EMAC_TXLATECOLL)); + dev_info(emac_dev, "EMAC: tx_underrun:%d\n", + emac_read(EMAC_TXUNDERRUN)); + dev_info(emac_dev, "EMAC: tx_carrier_sense_errors:%d\n", + emac_read(EMAC_TXCARRIERSENSE)); + dev_info(emac_dev, "EMAC: tx_octets:%d\n", + emac_read(EMAC_TXOCTETS)); + dev_info(emac_dev, "EMAC: net_octets:%d\n", + emac_read(EMAC_NETOCTETS)); + dev_info(emac_dev, "EMAC: rx_sof_overruns:%d\n", + emac_read(EMAC_RXSOFOVERRUNS)); + dev_info(emac_dev, "EMAC: rx_mof_overruns:%d\n", + emac_read(EMAC_RXMOFOVERRUNS)); + dev_info(emac_dev, "EMAC: rx_dma_overruns:%d\n", + emac_read(EMAC_RXDMAOVERRUNS)); +} + +/************************************************************************* + * EMAC MDIO/Phy Functionality + *************************************************************************/ +/** + * emac_get_drvinfo: Get EMAC driver information + * @ndev: The DaVinci EMAC network adapter + * @info: ethtool info structure containing name and version + * + * Returns EMAC driver information (name and version) + * + */ +static void emac_get_drvinfo(struct net_device *ndev, + struct ethtool_drvinfo *info) +{ + strcpy(info->driver, emac_version_string); + strcpy(info->version, EMAC_MODULE_VERSION); +} + +/** + * emac_get_settings: Get EMAC settings + * @ndev: The DaVinci EMAC network adapter + * @ecmd: ethtool command + * + * Executes ethool get command + * + */ +static int emac_get_settings(struct net_device *ndev, + struct ethtool_cmd *ecmd) +{ + struct emac_priv *priv = netdev_priv(ndev); + if (priv->phy_mask) + return phy_ethtool_gset(priv->phydev, ecmd); + else + return -EOPNOTSUPP; + +} + +/** + * emac_set_settings: Set EMAC settings + * @ndev: The DaVinci EMAC network adapter + * @ecmd: ethtool command + * + * Executes ethool set command + * + */ +static int emac_set_settings(struct net_device *ndev, struct ethtool_cmd *ecmd) +{ + struct emac_priv *priv = netdev_priv(ndev); + if (priv->phy_mask) + return phy_ethtool_sset(priv->phydev, ecmd); + else + return -EOPNOTSUPP; + +} + +/** + * ethtool_ops: DaVinci EMAC Ethtool structure + * + * Ethtool support for EMAC adapter + * + */ +static const struct ethtool_ops ethtool_ops = { + .get_drvinfo = emac_get_drvinfo, + .get_settings = emac_get_settings, + .set_settings = emac_set_settings, + .get_link = ethtool_op_get_link, +}; + +/** + * emac_update_phystatus: Update Phy status + * @priv: The DaVinci EMAC private adapter structure + * + * Updates phy status and takes action for network queue if required + * based upon link status + * + */ +static void emac_update_phystatus(struct emac_priv *priv) +{ + u32 mac_control; + u32 new_duplex; + u32 cur_duplex; + struct net_device *ndev = priv->ndev; + + mac_control = emac_read(EMAC_MACCONTROL); + cur_duplex = (mac_control & EMAC_MACCONTROL_FULLDUPLEXEN) ? + DUPLEX_FULL : DUPLEX_HALF; + if (priv->phy_mask) + new_duplex = priv->phydev->duplex; + else + new_duplex = DUPLEX_FULL; + + /* We get called only if link has changed (speed/duplex/status) */ + if ((priv->link) && (new_duplex != cur_duplex)) { + priv->duplex = new_duplex; + if (DUPLEX_FULL == priv->duplex) + mac_control |= (EMAC_MACCONTROL_FULLDUPLEXEN); + else + mac_control &= ~(EMAC_MACCONTROL_FULLDUPLEXEN); + } + + if (priv->speed == SPEED_1000 && (priv->version == EMAC_VERSION_2)) { + mac_control = emac_read(EMAC_MACCONTROL); + mac_control |= (EMAC_DM646X_MACCONTORL_GMIIEN | + EMAC_DM646X_MACCONTORL_GIG | + EMAC_DM646X_MACCONTORL_GIGFORCE); + } else { + /* Clear the GIG bit and GIGFORCE bit */ + mac_control &= ~(EMAC_DM646X_MACCONTORL_GIGFORCE | + EMAC_DM646X_MACCONTORL_GIG); + + if (priv->rmii_en && (priv->speed == SPEED_100)) + mac_control |= EMAC_MACCONTROL_RMIISPEED_MASK; + else + mac_control &= ~EMAC_MACCONTROL_RMIISPEED_MASK; + } + + /* Update mac_control if changed */ + emac_write(EMAC_MACCONTROL, mac_control); + + if (priv->link) { + /* link ON */ + if (!netif_carrier_ok(ndev)) + netif_carrier_on(ndev); + /* reactivate the transmit queue if it is stopped */ + if (netif_running(ndev) && netif_queue_stopped(ndev)) + netif_wake_queue(ndev); + } else { + /* link OFF */ + if (netif_carrier_ok(ndev)) + netif_carrier_off(ndev); + if (!netif_queue_stopped(ndev)) + netif_stop_queue(ndev); + } +} + +/** + * hash_get: Calculate hash value from mac address + * @addr: mac address to delete from hash table + * + * Calculates hash value from mac address + * + */ +static u32 hash_get(u8 *addr) +{ + u32 hash; + u8 tmpval; + int cnt; + hash = 0; + + for (cnt = 0; cnt < 2; cnt++) { + tmpval = *addr++; + hash ^= (tmpval >> 2) ^ (tmpval << 4); + tmpval = *addr++; + hash ^= (tmpval >> 4) ^ (tmpval << 2); + tmpval = *addr++; + hash ^= (tmpval >> 6) ^ (tmpval); + } + + return hash & 0x3F; +} + +/** + * hash_add: Hash function to add mac addr from hash table + * @priv: The DaVinci EMAC private adapter structure + * mac_addr: mac address to delete from hash table + * + * Adds mac address to the internal hash table + * + */ +static int hash_add(struct emac_priv *priv, u8 *mac_addr) +{ + struct device *emac_dev = &priv->ndev->dev; + u32 rc = 0; + u32 hash_bit; + u32 hash_value = hash_get(mac_addr); + + if (hash_value >= EMAC_NUM_MULTICAST_BITS) { + if (netif_msg_drv(priv)) { + dev_err(emac_dev, "DaVinci EMAC: hash_add(): Invalid "\ + "Hash %08x, should not be greater than %08x", + hash_value, (EMAC_NUM_MULTICAST_BITS - 1)); + } + return -1; + } + + /* set the hash bit only if not previously set */ + if (priv->multicast_hash_cnt[hash_value] == 0) { + rc = 1; /* hash value changed */ + if (hash_value < 32) { + hash_bit = BIT(hash_value); + priv->mac_hash1 |= hash_bit; + } else { + hash_bit = BIT((hash_value - 32)); + priv->mac_hash2 |= hash_bit; + } + } + + /* incr counter for num of mcast addr's mapped to "this" hash bit */ + ++priv->multicast_hash_cnt[hash_value]; + + return rc; +} + +/** + * hash_del: Hash function to delete mac addr from hash table + * @priv: The DaVinci EMAC private adapter structure + * mac_addr: mac address to delete from hash table + * + * Removes mac address from the internal hash table + * + */ +static int hash_del(struct emac_priv *priv, u8 *mac_addr) +{ + u32 hash_value; + u32 hash_bit; + + hash_value = hash_get(mac_addr); + if (priv->multicast_hash_cnt[hash_value] > 0) { + /* dec cntr for num of mcast addr's mapped to this hash bit */ + --priv->multicast_hash_cnt[hash_value]; + } + + /* if counter still > 0, at least one multicast address refers + * to this hash bit. so return 0 */ + if (priv->multicast_hash_cnt[hash_value] > 0) + return 0; + + if (hash_value < 32) { + hash_bit = BIT(hash_value); + priv->mac_hash1 &= ~hash_bit; + } else { + hash_bit = BIT((hash_value - 32)); + priv->mac_hash2 &= ~hash_bit; + } + + /* return 1 to indicate change in mac_hash registers reqd */ + return 1; +} + +/* EMAC multicast operation */ +#define EMAC_MULTICAST_ADD 0 +#define EMAC_MULTICAST_DEL 1 +#define EMAC_ALL_MULTI_SET 2 +#define EMAC_ALL_MULTI_CLR 3 + +/** + * emac_add_mcast: Set multicast address in the EMAC adapter (Internal) + * @priv: The DaVinci EMAC private adapter structure + * @action: multicast operation to perform + * mac_addr: mac address to set + * + * Set multicast addresses in EMAC adapter - internal function + * + */ +static void emac_add_mcast(struct emac_priv *priv, u32 action, u8 *mac_addr) +{ + struct device *emac_dev = &priv->ndev->dev; + int update = -1; + + switch (action) { + case EMAC_MULTICAST_ADD: + update = hash_add(priv, mac_addr); + break; + case EMAC_MULTICAST_DEL: + update = hash_del(priv, mac_addr); + break; + case EMAC_ALL_MULTI_SET: + update = 1; + priv->mac_hash1 = EMAC_ALL_MULTI_REG_VALUE; + priv->mac_hash2 = EMAC_ALL_MULTI_REG_VALUE; + break; + case EMAC_ALL_MULTI_CLR: + update = 1; + priv->mac_hash1 = 0; + priv->mac_hash2 = 0; + memset(&(priv->multicast_hash_cnt[0]), 0, + sizeof(priv->multicast_hash_cnt[0]) * + EMAC_NUM_MULTICAST_BITS); + break; + default: + if (netif_msg_drv(priv)) + dev_err(emac_dev, "DaVinci EMAC: add_mcast"\ + ": bad operation %d", action); + break; + } + + /* write to the hardware only if the register status chances */ + if (update > 0) { + emac_write(EMAC_MACHASH1, priv->mac_hash1); + emac_write(EMAC_MACHASH2, priv->mac_hash2); + } +} + +/** + * emac_dev_mcast_set: Set multicast address in the EMAC adapter + * @ndev: The DaVinci EMAC network adapter + * + * Set multicast addresses in EMAC adapter + * + */ +static void emac_dev_mcast_set(struct net_device *ndev) +{ + u32 mbp_enable; + struct emac_priv *priv = netdev_priv(ndev); + + mbp_enable = emac_read(EMAC_RXMBPENABLE); + if (ndev->flags & IFF_PROMISC) { + mbp_enable &= (~EMAC_MBP_PROMISCCH(EMAC_DEF_PROM_CH)); + mbp_enable |= (EMAC_MBP_RXPROMISC); + } else { + mbp_enable = (mbp_enable & ~EMAC_MBP_RXPROMISC); + if ((ndev->flags & IFF_ALLMULTI) || + (ndev->mc_count > EMAC_DEF_MAX_MULTICAST_ADDRESSES)) { + mbp_enable = (mbp_enable | EMAC_MBP_RXMCAST); + emac_add_mcast(priv, EMAC_ALL_MULTI_SET, NULL); + } + if (ndev->mc_count > 0) { + struct dev_mc_list *mc_ptr; + mbp_enable = (mbp_enable | EMAC_MBP_RXMCAST); + emac_add_mcast(priv, EMAC_ALL_MULTI_CLR, NULL); + /* program multicast address list into EMAC hardware */ + for (mc_ptr = ndev->mc_list; mc_ptr; + mc_ptr = mc_ptr->next) { + emac_add_mcast(priv, EMAC_MULTICAST_ADD, + (u8 *)mc_ptr->dmi_addr); + } + } else { + mbp_enable = (mbp_enable & ~EMAC_MBP_RXMCAST); + emac_add_mcast(priv, EMAC_ALL_MULTI_CLR, NULL); + } + } + /* Set mbp config register */ + emac_write(EMAC_RXMBPENABLE, mbp_enable); +} + +/************************************************************************* + * EMAC Hardware manipulation + *************************************************************************/ + +/** + * emac_int_disable: Disable EMAC module interrupt (from adapter) + * @priv: The DaVinci EMAC private adapter structure + * + * Disable EMAC interrupt on the adapter + * + */ +static void emac_int_disable(struct emac_priv *priv) +{ + if (priv->version == EMAC_VERSION_2) { + unsigned long flags; + + local_irq_save(flags); + + /* Program C0_Int_En to zero to turn off + * interrupts to the CPU */ + emac_ctrl_write(EMAC_DM646X_CMRXINTEN, 0x0); + emac_ctrl_write(EMAC_DM646X_CMTXINTEN, 0x0); + /* NOTE: Rx Threshold and Misc interrupts are not disabled */ + + local_irq_restore(flags); + + } else { + /* Set DM644x control registers for interrupt control */ + emac_ctrl_write(EMAC_CTRL_EWCTL, 0x0); + } +} + +/** + * emac_int_enable: Enable EMAC module interrupt (from adapter) + * @priv: The DaVinci EMAC private adapter structure + * + * Enable EMAC interrupt on the adapter + * + */ +static void emac_int_enable(struct emac_priv *priv) +{ + if (priv->version == EMAC_VERSION_2) { + emac_ctrl_write(EMAC_DM646X_CMRXINTEN, 0xff); + emac_ctrl_write(EMAC_DM646X_CMTXINTEN, 0xff); + + /* In addition to turning on interrupt Enable, we need + * ack by writing appropriate values to the EOI + * register */ + + /* NOTE: Rx Threshold and Misc interrupts are not enabled */ + + /* ack rxen only then a new pulse will be generated */ + emac_write(EMAC_DM646X_MACEOIVECTOR, + EMAC_DM646X_MAC_EOI_C0_RXEN); + + /* ack txen- only then a new pulse will be generated */ + emac_write(EMAC_DM646X_MACEOIVECTOR, + EMAC_DM646X_MAC_EOI_C0_TXEN); + + } else { + /* Set DM644x control registers for interrupt control */ + emac_ctrl_write(EMAC_CTRL_EWCTL, 0x1); + } +} + +/** + * emac_irq: EMAC interrupt handler + * @irq: interrupt number + * @dev_id: EMAC network adapter data structure ptr + * + * EMAC Interrupt handler - we only schedule NAPI and not process any packets + * here. EVen the interrupt status is checked (TX/RX/Err) in NAPI poll function + * + * Returns interrupt handled condition + */ +static irqreturn_t emac_irq(int irq, void *dev_id) +{ + struct net_device *ndev = (struct net_device *)dev_id; + struct emac_priv *priv = netdev_priv(ndev); + + ++priv->isr_count; + if (likely(netif_running(priv->ndev))) { + emac_int_disable(priv); + napi_schedule(&priv->napi); + } else { + /* we are closing down, so dont process anything */ + } + return IRQ_HANDLED; +} + +/** EMAC on-chip buffer descriptor memory + * + * WARNING: Please note that the on chip memory is used for both TX and RX + * buffer descriptor queues and is equally divided between TX and RX desc's + * If the number of TX or RX descriptors change this memory pointers need + * to be adjusted. If external memory is allocated then these pointers can + * pointer to the memory + * + */ +#define EMAC_TX_BD_MEM(priv) ((priv)->emac_ctrl_ram) +#define EMAC_RX_BD_MEM(priv) ((priv)->emac_ctrl_ram + \ + (((priv)->ctrl_ram_size) >> 1)) + +/** + * emac_init_txch: TX channel initialization + * @priv: The DaVinci EMAC private adapter structure + * @ch: RX channel number + * + * Called during device init to setup a TX channel (allocate buffer desc + * create free pool and keep ready for transmission + * + * Returns success(0) or mem alloc failures error code + */ +static int emac_init_txch(struct emac_priv *priv, u32 ch) +{ + struct device *emac_dev = &priv->ndev->dev; + u32 cnt, bd_size; + void __iomem *mem; + struct emac_tx_bd __iomem *curr_bd; + struct emac_txch *txch = NULL; + + txch = kzalloc(sizeof(struct emac_txch), GFP_KERNEL); + if (NULL == txch) { + dev_err(emac_dev, "DaVinci EMAC: TX Ch mem alloc failed"); + return -ENOMEM; + } + priv->txch[ch] = txch; + txch->service_max = EMAC_DEF_TX_MAX_SERVICE; + txch->active_queue_head = NULL; + txch->active_queue_tail = NULL; + txch->queue_active = 0; + txch->teardown_pending = 0; + + /* allocate memory for TX CPPI channel on a 4 byte boundry */ + txch->tx_complete = kzalloc(txch->service_max * sizeof(u32), + GFP_KERNEL); + if (NULL == txch->tx_complete) { + dev_err(emac_dev, "DaVinci EMAC: Tx service mem alloc failed"); + kfree(txch); + return -ENOMEM; + } + + /* allocate buffer descriptor pool align every BD on four word + * boundry for future requirements */ + bd_size = (sizeof(struct emac_tx_bd) + 0xF) & ~0xF; + txch->num_bd = (priv->ctrl_ram_size >> 1) / bd_size; + txch->alloc_size = (((bd_size * txch->num_bd) + 0xF) & ~0xF); + + /* alloc TX BD memory */ + txch->bd_mem = EMAC_TX_BD_MEM(priv); + __memzero((void __force *)txch->bd_mem, txch->alloc_size); + + /* initialize the BD linked list */ + mem = (void __force __iomem *) + (((u32 __force) txch->bd_mem + 0xF) & ~0xF); + txch->bd_pool_head = NULL; + for (cnt = 0; cnt < txch->num_bd; cnt++) { + curr_bd = mem + (cnt * bd_size); + curr_bd->next = txch->bd_pool_head; + txch->bd_pool_head = curr_bd; + } + + /* reset statistics counters */ + txch->out_of_tx_bd = 0; + txch->no_active_pkts = 0; + txch->active_queue_count = 0; + + return 0; +} + +/** + * emac_cleanup_txch: Book-keep function to clean TX channel resources + * @priv: The DaVinci EMAC private adapter structure + * @ch: TX channel number + * + * Called to clean up TX channel resources + * + */ +static void emac_cleanup_txch(struct emac_priv *priv, u32 ch) +{ + struct emac_txch *txch = priv->txch[ch]; + + if (txch) { + if (txch->bd_mem) + txch->bd_mem = NULL; + kfree(txch->tx_complete); + kfree(txch); + priv->txch[ch] = NULL; + } +} + +/** + * emac_net_tx_complete: TX packet completion function + * @priv: The DaVinci EMAC private adapter structure + * @net_data_tokens: packet token - skb pointer + * @num_tokens: number of skb's to free + * @ch: TX channel number + * + * Frees the skb once packet is transmitted + * + */ +static int emac_net_tx_complete(struct emac_priv *priv, + void **net_data_tokens, + int num_tokens, u32 ch) +{ + u32 cnt; + + if (unlikely(num_tokens && netif_queue_stopped(priv->ndev))) + netif_start_queue(priv->ndev); + for (cnt = 0; cnt < num_tokens; cnt++) { + struct sk_buff *skb = (struct sk_buff *)net_data_tokens[cnt]; + if (skb == NULL) + continue; + priv->net_dev_stats.tx_packets++; + priv->net_dev_stats.tx_bytes += skb->len; + dev_kfree_skb_any(skb); + } + return 0; +} + +/** + * emac_txch_teardown: TX channel teardown + * @priv: The DaVinci EMAC private adapter structure + * @ch: TX channel number + * + * Called to teardown TX channel + * + */ +static void emac_txch_teardown(struct emac_priv *priv, u32 ch) +{ + struct device *emac_dev = &priv->ndev->dev; + u32 teardown_cnt = 0xFFFFFFF0; /* Some high value */ + struct emac_txch *txch = priv->txch[ch]; + struct emac_tx_bd __iomem *curr_bd; + + while ((emac_read(EMAC_TXCP(ch)) & EMAC_TEARDOWN_VALUE) != + EMAC_TEARDOWN_VALUE) { + /* wait till tx teardown complete */ + cpu_relax(); /* TODO: check if this helps ... */ + --teardown_cnt; + if (0 == teardown_cnt) { + dev_err(emac_dev, "EMAC: TX teardown aborted\n"); + break; + } + } + emac_write(EMAC_TXCP(ch), EMAC_TEARDOWN_VALUE); + + /* process sent packets and return skb's to upper layer */ + if (1 == txch->queue_active) { + curr_bd = txch->active_queue_head; + while (curr_bd != NULL) { + emac_net_tx_complete(priv, (void __force *) + &curr_bd->buf_token, 1, ch); + if (curr_bd != txch->active_queue_tail) + curr_bd = curr_bd->next; + else + break; + } + txch->bd_pool_head = txch->active_queue_head; + txch->active_queue_head = + txch->active_queue_tail = NULL; + } +} + +/** + * emac_stop_txch: Stop TX channel operation + * @priv: The DaVinci EMAC private adapter structure + * @ch: TX channel number + * + * Called to stop TX channel operation + * + */ +static void emac_stop_txch(struct emac_priv *priv, u32 ch) +{ + struct emac_txch *txch = priv->txch[ch]; + + if (txch) { + txch->teardown_pending = 1; + emac_write(EMAC_TXTEARDOWN, 0); + emac_txch_teardown(priv, ch); + txch->teardown_pending = 0; + emac_write(EMAC_TXINTMASKCLEAR, BIT(ch)); + } +} + +/** + * emac_tx_bdproc: TX buffer descriptor (packet) processing + * @priv: The DaVinci EMAC private adapter structure + * @ch: TX channel number to process buffer descriptors for + * @budget: number of packets allowed to process + * @pending: indication to caller that packets are pending to process + * + * Processes TX buffer descriptors after packets are transmitted - checks + * ownership bit on the TX * descriptor and requeues it to free pool & frees + * the SKB buffer. Only "budget" number of packets are processed and + * indication of pending packets provided to the caller + * + * Returns number of packets processed + */ +static int emac_tx_bdproc(struct emac_priv *priv, u32 ch, u32 budget) +{ + struct device *emac_dev = &priv->ndev->dev; + unsigned long flags; + u32 frame_status; + u32 pkts_processed = 0; + u32 tx_complete_cnt = 0; + struct emac_tx_bd __iomem *curr_bd; + struct emac_txch *txch = priv->txch[ch]; + u32 *tx_complete_ptr = txch->tx_complete; + + if (unlikely(1 == txch->teardown_pending)) { + if (netif_msg_tx_err(priv) && net_ratelimit()) { + dev_err(emac_dev, "DaVinci EMAC:emac_tx_bdproc: "\ + "teardown pending\n"); + } + return 0; /* dont handle any pkt completions */ + } + + ++txch->proc_count; + spin_lock_irqsave(&priv->tx_lock, flags); + curr_bd = txch->active_queue_head; + if (NULL == curr_bd) { + emac_write(EMAC_TXCP(ch), + emac_virt_to_phys(txch->last_hw_bdprocessed)); + txch->no_active_pkts++; + spin_unlock_irqrestore(&priv->tx_lock, flags); + return 0; + } + BD_CACHE_INVALIDATE(curr_bd, EMAC_BD_LENGTH_FOR_CACHE); + frame_status = curr_bd->mode; + while ((curr_bd) && + ((frame_status & EMAC_CPPI_OWNERSHIP_BIT) == 0) && + (pkts_processed < budget)) { + emac_write(EMAC_TXCP(ch), emac_virt_to_phys(curr_bd)); + txch->active_queue_head = curr_bd->next; + if (frame_status & EMAC_CPPI_EOQ_BIT) { + if (curr_bd->next) { /* misqueued packet */ + emac_write(EMAC_TXHDP(ch), curr_bd->h_next); + ++txch->mis_queued_packets; + } else { + txch->queue_active = 0; /* end of queue */ + } + } + *tx_complete_ptr = (u32) curr_bd->buf_token; + ++tx_complete_ptr; + ++tx_complete_cnt; + curr_bd->next = txch->bd_pool_head; + txch->bd_pool_head = curr_bd; + --txch->active_queue_count; + pkts_processed++; + txch->last_hw_bdprocessed = curr_bd; + curr_bd = txch->active_queue_head; + if (curr_bd) { + BD_CACHE_INVALIDATE(curr_bd, EMAC_BD_LENGTH_FOR_CACHE); + frame_status = curr_bd->mode; + } + } /* end of pkt processing loop */ + + emac_net_tx_complete(priv, + (void *)&txch->tx_complete[0], + tx_complete_cnt, ch); + spin_unlock_irqrestore(&priv->tx_lock, flags); + return pkts_processed; +} + +#define EMAC_ERR_TX_OUT_OF_BD -1 + +/** + * emac_send: EMAC Transmit function (internal) + * @priv: The DaVinci EMAC private adapter structure + * @pkt: packet pointer (contains skb ptr) + * @ch: TX channel number + * + * Called by the transmit function to queue the packet in EMAC hardware queue + * + * Returns success(0) or error code (typically out of desc's) + */ +static int emac_send(struct emac_priv *priv, struct emac_netpktobj *pkt, u32 ch) +{ + unsigned long flags; + struct emac_tx_bd __iomem *curr_bd; + struct emac_txch *txch; + struct emac_netbufobj *buf_list; + + txch = priv->txch[ch]; + buf_list = pkt->buf_list; /* get handle to the buffer array */ + + /* check packet size and pad if short */ + if (pkt->pkt_length < EMAC_DEF_MIN_ETHPKTSIZE) { + buf_list->length += (EMAC_DEF_MIN_ETHPKTSIZE - pkt->pkt_length); + pkt->pkt_length = EMAC_DEF_MIN_ETHPKTSIZE; + } + + spin_lock_irqsave(&priv->tx_lock, flags); + curr_bd = txch->bd_pool_head; + if (curr_bd == NULL) { + txch->out_of_tx_bd++; + spin_unlock_irqrestore(&priv->tx_lock, flags); + return EMAC_ERR_TX_OUT_OF_BD; + } + + txch->bd_pool_head = curr_bd->next; + curr_bd->buf_token = buf_list->buf_token; + /* FIXME buff_ptr = dma_map_single(... data_ptr ...) */ + curr_bd->buff_ptr = virt_to_phys(buf_list->data_ptr); + curr_bd->off_b_len = buf_list->length; + curr_bd->h_next = 0; + curr_bd->next = NULL; + curr_bd->mode = (EMAC_CPPI_SOP_BIT | EMAC_CPPI_OWNERSHIP_BIT | + EMAC_CPPI_EOP_BIT | pkt->pkt_length); + + /* flush the packet from cache if write back cache is present */ + BD_CACHE_WRITEBACK_INVALIDATE(curr_bd, EMAC_BD_LENGTH_FOR_CACHE); + + /* send the packet */ + if (txch->active_queue_head == NULL) { + txch->active_queue_head = curr_bd; + txch->active_queue_tail = curr_bd; + if (1 != txch->queue_active) { + emac_write(EMAC_TXHDP(ch), + emac_virt_to_phys(curr_bd)); + txch->queue_active = 1; + } + ++txch->queue_reinit; + } else { + register struct emac_tx_bd __iomem *tail_bd; + register u32 frame_status; + + tail_bd = txch->active_queue_tail; + tail_bd->next = curr_bd; + txch->active_queue_tail = curr_bd; + tail_bd = EMAC_VIRT_NOCACHE(tail_bd); + tail_bd->h_next = (int)emac_virt_to_phys(curr_bd); + frame_status = tail_bd->mode; + if (frame_status & EMAC_CPPI_EOQ_BIT) { + emac_write(EMAC_TXHDP(ch), emac_virt_to_phys(curr_bd)); + frame_status &= ~(EMAC_CPPI_EOQ_BIT); + tail_bd->mode = frame_status; + ++txch->end_of_queue_add; + } + } + txch->active_queue_count++; + spin_unlock_irqrestore(&priv->tx_lock, flags); + return 0; +} + +/** + * emac_dev_xmit: EMAC Transmit function + * @skb: SKB pointer + * @ndev: The DaVinci EMAC network adapter + * + * Called by the system to transmit a packet - we queue the packet in + * EMAC hardware transmit queue + * + * Returns success(NETDEV_TX_OK) or error code (typically out of desc's) + */ +static int emac_dev_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + struct device *emac_dev = &ndev->dev; + int ret_code; + struct emac_netbufobj tx_buf; /* buffer obj-only single frame support */ + struct emac_netpktobj tx_packet; /* packet object */ + struct emac_priv *priv = netdev_priv(ndev); + + /* If no link, return */ + if (unlikely(!priv->link)) { + if (netif_msg_tx_err(priv) && net_ratelimit()) + dev_err(emac_dev, "DaVinci EMAC: No link to transmit"); + return NETDEV_TX_BUSY; + } + + /* Build the buffer and packet objects - Since only single fragment is + * supported, need not set length and token in both packet & object. + * Doing so for completeness sake & to show that this needs to be done + * in multifragment case + */ + tx_packet.buf_list = &tx_buf; + tx_packet.num_bufs = 1; /* only single fragment supported */ + tx_packet.pkt_length = skb->len; + tx_packet.pkt_token = (void *)skb; + tx_buf.length = skb->len; + tx_buf.buf_token = (void *)skb; + tx_buf.data_ptr = skb->data; + EMAC_CACHE_WRITEBACK((unsigned long)skb->data, skb->len); + ndev->trans_start = jiffies; + ret_code = emac_send(priv, &tx_packet, EMAC_DEF_TX_CH); + if (unlikely(ret_code != 0)) { + if (ret_code == EMAC_ERR_TX_OUT_OF_BD) { + if (netif_msg_tx_err(priv) && net_ratelimit()) + dev_err(emac_dev, "DaVinci EMAC: xmit() fatal"\ + " err. Out of TX BD's"); + netif_stop_queue(priv->ndev); + } + priv->net_dev_stats.tx_dropped++; + return NETDEV_TX_BUSY; + } + + return NETDEV_TX_OK; +} + +/** + * emac_dev_tx_timeout: EMAC Transmit timeout function + * @ndev: The DaVinci EMAC network adapter + * + * Called when system detects that a skb timeout period has expired + * potentially due to a fault in the adapter in not being able to send + * it out on the wire. We teardown the TX channel assuming a hardware + * error and re-initialize the TX channel for hardware operation + * + */ +static void emac_dev_tx_timeout(struct net_device *ndev) +{ + struct emac_priv *priv = netdev_priv(ndev); + struct device *emac_dev = &ndev->dev; + + if (netif_msg_tx_err(priv)) + dev_err(emac_dev, "DaVinci EMAC: xmit timeout, restarting TX"); + + priv->net_dev_stats.tx_errors++; + emac_int_disable(priv); + emac_stop_txch(priv, EMAC_DEF_TX_CH); + emac_cleanup_txch(priv, EMAC_DEF_TX_CH); + emac_init_txch(priv, EMAC_DEF_TX_CH); + emac_write(EMAC_TXHDP(0), 0); + emac_write(EMAC_TXINTMASKSET, BIT(EMAC_DEF_TX_CH)); + emac_int_enable(priv); +} + +/** + * emac_net_alloc_rx_buf: Allocate a skb for RX + * @priv: The DaVinci EMAC private adapter structure + * @buf_size: size of SKB data buffer to allocate + * @data_token: data token returned (skb handle for storing in buffer desc) + * @ch: RX channel number + * + * Called during RX channel setup - allocates skb buffer of required size + * and provides the skb handle and allocated buffer data pointer to caller + * + * Returns skb data pointer or 0 on failure to alloc skb + */ +static void *emac_net_alloc_rx_buf(struct emac_priv *priv, int buf_size, + void **data_token, u32 ch) +{ + struct net_device *ndev = priv->ndev; + struct device *emac_dev = &ndev->dev; + struct sk_buff *p_skb; + + p_skb = dev_alloc_skb(buf_size); + if (unlikely(NULL == p_skb)) { + if (netif_msg_rx_err(priv) && net_ratelimit()) + dev_err(emac_dev, "DaVinci EMAC: failed to alloc skb"); + return NULL; + } + + /* set device pointer in skb and reserve space for extra bytes */ + p_skb->dev = ndev; + skb_reserve(p_skb, NET_IP_ALIGN); + *data_token = (void *) p_skb; + EMAC_CACHE_WRITEBACK_INVALIDATE((unsigned long)p_skb->data, buf_size); + return p_skb->data; +} + +/** + * emac_init_rxch: RX channel initialization + * @priv: The DaVinci EMAC private adapter structure + * @ch: RX channel number + * @param: mac address for RX channel + * + * Called during device init to setup a RX channel (allocate buffers and + * buffer descriptors, create queue and keep ready for reception + * + * Returns success(0) or mem alloc failures error code + */ +static int emac_init_rxch(struct emac_priv *priv, u32 ch, char *param) +{ + struct device *emac_dev = &priv->ndev->dev; + u32 cnt, bd_size; + void __iomem *mem; + struct emac_rx_bd __iomem *curr_bd; + struct emac_rxch *rxch = NULL; + + rxch = kzalloc(sizeof(struct emac_rxch), GFP_KERNEL); + if (NULL == rxch) { + dev_err(emac_dev, "DaVinci EMAC: RX Ch mem alloc failed"); + return -ENOMEM; + } + priv->rxch[ch] = rxch; + rxch->buf_size = priv->rx_buf_size; + rxch->service_max = EMAC_DEF_RX_MAX_SERVICE; + rxch->queue_active = 0; + rxch->teardown_pending = 0; + + /* save mac address */ + for (cnt = 0; cnt < 6; cnt++) + rxch->mac_addr[cnt] = param[cnt]; + + /* allocate buffer descriptor pool align every BD on four word + * boundry for future requirements */ + bd_size = (sizeof(struct emac_rx_bd) + 0xF) & ~0xF; + rxch->num_bd = (priv->ctrl_ram_size >> 1) / bd_size; + rxch->alloc_size = (((bd_size * rxch->num_bd) + 0xF) & ~0xF); + rxch->bd_mem = EMAC_RX_BD_MEM(priv); + __memzero((void __force *)rxch->bd_mem, rxch->alloc_size); + rxch->pkt_queue.buf_list = &rxch->buf_queue; + + /* allocate RX buffer and initialize the BD linked list */ + mem = (void __force __iomem *) + (((u32 __force) rxch->bd_mem + 0xF) & ~0xF); + rxch->active_queue_head = NULL; + rxch->active_queue_tail = mem; + for (cnt = 0; cnt < rxch->num_bd; cnt++) { + curr_bd = mem + (cnt * bd_size); + /* for future use the last parameter contains the BD ptr */ + curr_bd->data_ptr = emac_net_alloc_rx_buf(priv, + rxch->buf_size, + (void __force **)&curr_bd->buf_token, + EMAC_DEF_RX_CH); + if (curr_bd->data_ptr == NULL) { + dev_err(emac_dev, "DaVinci EMAC: RX buf mem alloc " \ + "failed for ch %d\n", ch); + kfree(rxch); + return -ENOMEM; + } + + /* populate the hardware descriptor */ + curr_bd->h_next = emac_virt_to_phys(rxch->active_queue_head); + /* FIXME buff_ptr = dma_map_single(... data_ptr ...) */ + curr_bd->buff_ptr = virt_to_phys(curr_bd->data_ptr); + curr_bd->off_b_len = rxch->buf_size; + curr_bd->mode = EMAC_CPPI_OWNERSHIP_BIT; + + /* write back to hardware memory */ + BD_CACHE_WRITEBACK_INVALIDATE((u32) curr_bd, + EMAC_BD_LENGTH_FOR_CACHE); + curr_bd->next = rxch->active_queue_head; + rxch->active_queue_head = curr_bd; + } + + /* At this point rxCppi->activeQueueHead points to the first + RX BD ready to be given to RX HDP and rxch->active_queue_tail + points to the last RX BD + */ + return 0; +} + +/** + * emac_rxch_teardown: RX channel teardown + * @priv: The DaVinci EMAC private adapter structure + * @ch: RX channel number + * + * Called during device stop to teardown RX channel + * + */ +static void emac_rxch_teardown(struct emac_priv *priv, u32 ch) +{ + struct device *emac_dev = &priv->ndev->dev; + u32 teardown_cnt = 0xFFFFFFF0; /* Some high value */ + + while ((emac_read(EMAC_RXCP(ch)) & EMAC_TEARDOWN_VALUE) != + EMAC_TEARDOWN_VALUE) { + /* wait till tx teardown complete */ + cpu_relax(); /* TODO: check if this helps ... */ + --teardown_cnt; + if (0 == teardown_cnt) { + dev_err(emac_dev, "EMAC: RX teardown aborted\n"); + break; + } + } + emac_write(EMAC_RXCP(ch), EMAC_TEARDOWN_VALUE); +} + +/** + * emac_stop_rxch: Stop RX channel operation + * @priv: The DaVinci EMAC private adapter structure + * @ch: RX channel number + * + * Called during device stop to stop RX channel operation + * + */ +static void emac_stop_rxch(struct emac_priv *priv, u32 ch) +{ + struct emac_rxch *rxch = priv->rxch[ch]; + + if (rxch) { + rxch->teardown_pending = 1; + emac_write(EMAC_RXTEARDOWN, ch); + /* wait for teardown complete */ + emac_rxch_teardown(priv, ch); + rxch->teardown_pending = 0; + emac_write(EMAC_RXINTMASKCLEAR, BIT(ch)); + } +} + +/** + * emac_cleanup_rxch: Book-keep function to clean RX channel resources + * @priv: The DaVinci EMAC private adapter structure + * @ch: RX channel number + * + * Called during device stop to clean up RX channel resources + * + */ +static void emac_cleanup_rxch(struct emac_priv *priv, u32 ch) +{ + struct emac_rxch *rxch = priv->rxch[ch]; + struct emac_rx_bd __iomem *curr_bd; + + if (rxch) { + /* free the receive buffers previously allocated */ + curr_bd = rxch->active_queue_head; + while (curr_bd) { + if (curr_bd->buf_token) { + dev_kfree_skb_any((struct sk_buff *)\ + curr_bd->buf_token); + } + curr_bd = curr_bd->next; + } + if (rxch->bd_mem) + rxch->bd_mem = NULL; + kfree(rxch); + priv->rxch[ch] = NULL; + } +} + +/** + * emac_set_type0addr: Set EMAC Type0 mac address + * @priv: The DaVinci EMAC private adapter structure + * @ch: RX channel number + * @mac_addr: MAC address to set in device + * + * Called internally to set Type0 mac address of the adapter (Device) + * + * Returns success (0) or appropriate error code (none as of now) + */ +static void emac_set_type0addr(struct emac_priv *priv, u32 ch, char *mac_addr) +{ + u32 val; + val = ((mac_addr[5] << 8) | (mac_addr[4])); + emac_write(EMAC_MACSRCADDRLO, val); + + val = ((mac_addr[3] << 24) | (mac_addr[2] << 16) | \ + (mac_addr[1] << 8) | (mac_addr[0])); + emac_write(EMAC_MACSRCADDRHI, val); + val = emac_read(EMAC_RXUNICASTSET); + val |= BIT(ch); + emac_write(EMAC_RXUNICASTSET, val); + val = emac_read(EMAC_RXUNICASTCLEAR); + val &= ~BIT(ch); + emac_write(EMAC_RXUNICASTCLEAR, val); +} + +/** + * emac_set_type1addr: Set EMAC Type1 mac address + * @priv: The DaVinci EMAC private adapter structure + * @ch: RX channel number + * @mac_addr: MAC address to set in device + * + * Called internally to set Type1 mac address of the adapter (Device) + * + * Returns success (0) or appropriate error code (none as of now) + */ +static void emac_set_type1addr(struct emac_priv *priv, u32 ch, char *mac_addr) +{ + u32 val; + emac_write(EMAC_MACINDEX, ch); + val = ((mac_addr[5] << 8) | mac_addr[4]); + emac_write(EMAC_MACADDRLO, val); + val = ((mac_addr[3] << 24) | (mac_addr[2] << 16) | \ + (mac_addr[1] << 8) | (mac_addr[0])); + emac_write(EMAC_MACADDRHI, val); + emac_set_type0addr(priv, ch, mac_addr); +} + +/** + * emac_set_type2addr: Set EMAC Type2 mac address + * @priv: The DaVinci EMAC private adapter structure + * @ch: RX channel number + * @mac_addr: MAC address to set in device + * @index: index into RX address entries + * @match: match parameter for RX address matching logic + * + * Called internally to set Type2 mac address of the adapter (Device) + * + * Returns success (0) or appropriate error code (none as of now) + */ +static void emac_set_type2addr(struct emac_priv *priv, u32 ch, + char *mac_addr, int index, int match) +{ + u32 val; + emac_write(EMAC_MACINDEX, index); + val = ((mac_addr[3] << 24) | (mac_addr[2] << 16) | \ + (mac_addr[1] << 8) | (mac_addr[0])); + emac_write(EMAC_MACADDRHI, val); + val = ((mac_addr[5] << 8) | mac_addr[4] | ((ch & 0x7) << 16) | \ + (match << 19) | BIT(20)); + emac_write(EMAC_MACADDRLO, val); + emac_set_type0addr(priv, ch, mac_addr); +} + +/** + * emac_setmac: Set mac address in the adapter (internal function) + * @priv: The DaVinci EMAC private adapter structure + * @ch: RX channel number + * @mac_addr: MAC address to set in device + * + * Called internally to set the mac address of the adapter (Device) + * + * Returns success (0) or appropriate error code (none as of now) + */ +static void emac_setmac(struct emac_priv *priv, u32 ch, char *mac_addr) +{ + struct device *emac_dev = &priv->ndev->dev; + + if (priv->rx_addr_type == 0) { + emac_set_type0addr(priv, ch, mac_addr); + } else if (priv->rx_addr_type == 1) { + u32 cnt; + for (cnt = 0; cnt < EMAC_MAX_TXRX_CHANNELS; cnt++) + emac_set_type1addr(priv, ch, mac_addr); + } else if (priv->rx_addr_type == 2) { + emac_set_type2addr(priv, ch, mac_addr, ch, 1); + emac_set_type0addr(priv, ch, mac_addr); + } else { + if (netif_msg_drv(priv)) + dev_err(emac_dev, "DaVinci EMAC: Wrong addressing\n"); + } +} + +/** + * emac_dev_setmac_addr: Set mac address in the adapter + * @ndev: The DaVinci EMAC network adapter + * @addr: MAC address to set in device + * + * Called by the system to set the mac address of the adapter (Device) + * + * Returns success (0) or appropriate error code (none as of now) + */ +static int emac_dev_setmac_addr(struct net_device *ndev, void *addr) +{ + struct emac_priv *priv = netdev_priv(ndev); + struct emac_rxch *rxch = priv->rxch[EMAC_DEF_RX_CH]; + struct device *emac_dev = &priv->ndev->dev; + struct sockaddr *sa = addr; + + /* Store mac addr in priv and rx channel and set it in EMAC hw */ + memcpy(priv->mac_addr, sa->sa_data, ndev->addr_len); + memcpy(rxch->mac_addr, sa->sa_data, ndev->addr_len); + memcpy(ndev->dev_addr, sa->sa_data, ndev->addr_len); + emac_setmac(priv, EMAC_DEF_RX_CH, rxch->mac_addr); + + if (netif_msg_drv(priv)) + dev_notice(emac_dev, "DaVinci EMAC: emac_dev_setmac_addr %pM\n", + priv->mac_addr); + + return 0; +} + +/** + * emac_addbd_to_rx_queue: Recycle RX buffer descriptor + * @priv: The DaVinci EMAC private adapter structure + * @ch: RX channel number to process buffer descriptors for + * @curr_bd: current buffer descriptor + * @buffer: buffer pointer for descriptor + * @buf_token: buffer token (stores skb information) + * + * Prepares the recycled buffer descriptor and addes it to hardware + * receive queue - if queue empty this descriptor becomes the head + * else addes the descriptor to end of queue + * + */ +static void emac_addbd_to_rx_queue(struct emac_priv *priv, u32 ch, + struct emac_rx_bd __iomem *curr_bd, + char *buffer, void *buf_token) +{ + struct emac_rxch *rxch = priv->rxch[ch]; + + /* populate the hardware descriptor */ + curr_bd->h_next = 0; + /* FIXME buff_ptr = dma_map_single(... buffer ...) */ + curr_bd->buff_ptr = virt_to_phys(buffer); + curr_bd->off_b_len = rxch->buf_size; + curr_bd->mode = EMAC_CPPI_OWNERSHIP_BIT; + curr_bd->next = NULL; + curr_bd->data_ptr = buffer; + curr_bd->buf_token = buf_token; + + /* write back */ + BD_CACHE_WRITEBACK_INVALIDATE(curr_bd, EMAC_BD_LENGTH_FOR_CACHE); + if (rxch->active_queue_head == NULL) { + rxch->active_queue_head = curr_bd; + rxch->active_queue_tail = curr_bd; + if (0 != rxch->queue_active) { + emac_write(EMAC_RXHDP(ch), + emac_virt_to_phys(rxch->active_queue_head)); + rxch->queue_active = 1; + } + } else { + struct emac_rx_bd __iomem *tail_bd; + u32 frame_status; + + tail_bd = rxch->active_queue_tail; + rxch->active_queue_tail = curr_bd; + tail_bd->next = curr_bd; + tail_bd = EMAC_VIRT_NOCACHE(tail_bd); + tail_bd->h_next = emac_virt_to_phys(curr_bd); + frame_status = tail_bd->mode; + if (frame_status & EMAC_CPPI_EOQ_BIT) { + emac_write(EMAC_RXHDP(ch), + emac_virt_to_phys(curr_bd)); + frame_status &= ~(EMAC_CPPI_EOQ_BIT); + tail_bd->mode = frame_status; + ++rxch->end_of_queue_add; + } + } + ++rxch->recycled_bd; +} + +/** + * emac_net_rx_cb: Prepares packet and sends to upper layer + * @priv: The DaVinci EMAC private adapter structure + * @net_pkt_list: Network packet list (received packets) + * + * Invalidates packet buffer memory and sends the received packet to upper + * layer + * + * Returns success or appropriate error code (none as of now) + */ +static int emac_net_rx_cb(struct emac_priv *priv, + struct emac_netpktobj *net_pkt_list) +{ + struct sk_buff *p_skb; + p_skb = (struct sk_buff *)net_pkt_list->pkt_token; + /* set length of packet */ + skb_put(p_skb, net_pkt_list->pkt_length); + EMAC_CACHE_INVALIDATE((unsigned long)p_skb->data, p_skb->len); + p_skb->protocol = eth_type_trans(p_skb, priv->ndev); + p_skb->dev->last_rx = jiffies; + netif_receive_skb(p_skb); + priv->net_dev_stats.rx_bytes += net_pkt_list->pkt_length; + priv->net_dev_stats.rx_packets++; + return 0; +} + +/** + * emac_rx_bdproc: RX buffer descriptor (packet) processing + * @priv: The DaVinci EMAC private adapter structure + * @ch: RX channel number to process buffer descriptors for + * @budget: number of packets allowed to process + * @pending: indication to caller that packets are pending to process + * + * Processes RX buffer descriptors - checks ownership bit on the RX buffer + * descriptor, sends the receive packet to upper layer, allocates a new SKB + * and recycles the buffer descriptor (requeues it in hardware RX queue). + * Only "budget" number of packets are processed and indication of pending + * packets provided to the caller. + * + * Returns number of packets processed (and indication of pending packets) + */ +static int emac_rx_bdproc(struct emac_priv *priv, u32 ch, u32 budget) +{ + unsigned long flags; + u32 frame_status; + u32 pkts_processed = 0; + char *new_buffer; + struct emac_rx_bd __iomem *curr_bd; + struct emac_rx_bd __iomem *last_bd; + struct emac_netpktobj *curr_pkt, pkt_obj; + struct emac_netbufobj buf_obj; + struct emac_netbufobj *rx_buf_obj; + void *new_buf_token; + struct emac_rxch *rxch = priv->rxch[ch]; + + if (unlikely(1 == rxch->teardown_pending)) + return 0; + ++rxch->proc_count; + spin_lock_irqsave(&priv->rx_lock, flags); + pkt_obj.buf_list = &buf_obj; + curr_pkt = &pkt_obj; + curr_bd = rxch->active_queue_head; + BD_CACHE_INVALIDATE(curr_bd, EMAC_BD_LENGTH_FOR_CACHE); + frame_status = curr_bd->mode; + + while ((curr_bd) && + ((frame_status & EMAC_CPPI_OWNERSHIP_BIT) == 0) && + (pkts_processed < budget)) { + + new_buffer = emac_net_alloc_rx_buf(priv, rxch->buf_size, + &new_buf_token, EMAC_DEF_RX_CH); + if (unlikely(NULL == new_buffer)) { + ++rxch->out_of_rx_buffers; + goto end_emac_rx_bdproc; + } + + /* populate received packet data structure */ + rx_buf_obj = &curr_pkt->buf_list[0]; + rx_buf_obj->data_ptr = (char *)curr_bd->data_ptr; + rx_buf_obj->length = curr_bd->off_b_len & EMAC_RX_BD_BUF_SIZE; + rx_buf_obj->buf_token = curr_bd->buf_token; + curr_pkt->pkt_token = curr_pkt->buf_list->buf_token; + curr_pkt->num_bufs = 1; + curr_pkt->pkt_length = + (frame_status & EMAC_RX_BD_PKT_LENGTH_MASK); + emac_write(EMAC_RXCP(ch), emac_virt_to_phys(curr_bd)); + ++rxch->processed_bd; + last_bd = curr_bd; + curr_bd = last_bd->next; + rxch->active_queue_head = curr_bd; + + /* check if end of RX queue ? */ + if (frame_status & EMAC_CPPI_EOQ_BIT) { + if (curr_bd) { + ++rxch->mis_queued_packets; + emac_write(EMAC_RXHDP(ch), + emac_virt_to_phys(curr_bd)); + } else { + ++rxch->end_of_queue; + rxch->queue_active = 0; + } + } + + /* recycle BD */ + emac_addbd_to_rx_queue(priv, ch, last_bd, new_buffer, + new_buf_token); + + /* return the packet to the user - BD ptr passed in + * last parameter for potential *future* use */ + spin_unlock_irqrestore(&priv->rx_lock, flags); + emac_net_rx_cb(priv, curr_pkt); + spin_lock_irqsave(&priv->rx_lock, flags); + curr_bd = rxch->active_queue_head; + if (curr_bd) { + BD_CACHE_INVALIDATE(curr_bd, EMAC_BD_LENGTH_FOR_CACHE); + frame_status = curr_bd->mode; + } + ++pkts_processed; + } + +end_emac_rx_bdproc: + spin_unlock_irqrestore(&priv->rx_lock, flags); + return pkts_processed; +} + +/** + * emac_hw_enable: Enable EMAC hardware for packet transmission/reception + * @priv: The DaVinci EMAC private adapter structure + * + * Enables EMAC hardware for packet processing - enables PHY, enables RX + * for packet reception and enables device interrupts and then NAPI + * + * Returns success (0) or appropriate error code (none right now) + */ +static int emac_hw_enable(struct emac_priv *priv) +{ + u32 ch, val, mbp_enable, mac_control; + + /* Soft reset */ + emac_write(EMAC_SOFTRESET, 1); + while (emac_read(EMAC_SOFTRESET)) + cpu_relax(); + + /* Disable interrupt & Set pacing for more interrupts initially */ + emac_int_disable(priv); + + /* Full duplex enable bit set when auto negotiation happens */ + mac_control = + (((EMAC_DEF_TXPRIO_FIXED) ? (EMAC_MACCONTROL_TXPTYPE) : 0x0) | + ((priv->speed == 1000) ? EMAC_MACCONTROL_GIGABITEN : 0x0) | + ((EMAC_DEF_TXPACING_EN) ? (EMAC_MACCONTROL_TXPACEEN) : 0x0) | + ((priv->duplex == DUPLEX_FULL) ? 0x1 : 0)); + emac_write(EMAC_MACCONTROL, mac_control); + + mbp_enable = + (((EMAC_DEF_PASS_CRC) ? (EMAC_RXMBP_PASSCRC_MASK) : 0x0) | + ((EMAC_DEF_QOS_EN) ? (EMAC_RXMBP_QOSEN_MASK) : 0x0) | + ((EMAC_DEF_NO_BUFF_CHAIN) ? (EMAC_RXMBP_NOCHAIN_MASK) : 0x0) | + ((EMAC_DEF_MACCTRL_FRAME_EN) ? (EMAC_RXMBP_CMFEN_MASK) : 0x0) | + ((EMAC_DEF_SHORT_FRAME_EN) ? (EMAC_RXMBP_CSFEN_MASK) : 0x0) | + ((EMAC_DEF_ERROR_FRAME_EN) ? (EMAC_RXMBP_CEFEN_MASK) : 0x0) | + ((EMAC_DEF_PROM_EN) ? (EMAC_RXMBP_CAFEN_MASK) : 0x0) | + ((EMAC_DEF_PROM_CH & EMAC_RXMBP_CHMASK) << \ + EMAC_RXMBP_PROMCH_SHIFT) | + ((EMAC_DEF_BCAST_EN) ? (EMAC_RXMBP_BROADEN_MASK) : 0x0) | + ((EMAC_DEF_BCAST_CH & EMAC_RXMBP_CHMASK) << \ + EMAC_RXMBP_BROADCH_SHIFT) | + ((EMAC_DEF_MCAST_EN) ? (EMAC_RXMBP_MULTIEN_MASK) : 0x0) | + ((EMAC_DEF_MCAST_CH & EMAC_RXMBP_CHMASK) << \ + EMAC_RXMBP_MULTICH_SHIFT)); + emac_write(EMAC_RXMBPENABLE, mbp_enable); + emac_write(EMAC_RXMAXLEN, (EMAC_DEF_MAX_FRAME_SIZE & + EMAC_RX_MAX_LEN_MASK)); + emac_write(EMAC_RXBUFFEROFFSET, (EMAC_DEF_BUFFER_OFFSET & + EMAC_RX_BUFFER_OFFSET_MASK)); + emac_write(EMAC_RXFILTERLOWTHRESH, 0); + emac_write(EMAC_RXUNICASTCLEAR, EMAC_RX_UNICAST_CLEAR_ALL); + priv->rx_addr_type = (emac_read(EMAC_MACCONFIG) >> 8) & 0xFF; + + val = emac_read(EMAC_TXCONTROL); + val |= EMAC_TX_CONTROL_TX_ENABLE_VAL; + emac_write(EMAC_TXCONTROL, val); + val = emac_read(EMAC_RXCONTROL); + val |= EMAC_RX_CONTROL_RX_ENABLE_VAL; + emac_write(EMAC_RXCONTROL, val); + emac_write(EMAC_MACINTMASKSET, EMAC_MAC_HOST_ERR_INTMASK_VAL); + + for (ch = 0; ch < EMAC_DEF_MAX_TX_CH; ch++) { + emac_write(EMAC_TXHDP(ch), 0); + emac_write(EMAC_TXINTMASKSET, BIT(ch)); + } + for (ch = 0; ch < EMAC_DEF_MAX_RX_CH; ch++) { + struct emac_rxch *rxch = priv->rxch[ch]; + emac_setmac(priv, ch, rxch->mac_addr); + emac_write(EMAC_RXINTMASKSET, BIT(ch)); + rxch->queue_active = 1; + emac_write(EMAC_RXHDP(ch), + emac_virt_to_phys(rxch->active_queue_head)); + } + + /* Enable MII */ + val = emac_read(EMAC_MACCONTROL); + val |= (EMAC_MACCONTROL_MIIEN); + emac_write(EMAC_MACCONTROL, val); + + /* Enable NAPI and interrupts */ + napi_enable(&priv->napi); + emac_int_enable(priv); + return 0; + +} + +/** + * emac_poll: EMAC NAPI Poll function + * @ndev: The DaVinci EMAC network adapter + * @budget: Number of receive packets to process (as told by NAPI layer) + * + * NAPI Poll function implemented to process packets as per budget. We check + * the type of interrupt on the device and accordingly call the TX or RX + * packet processing functions. We follow the budget for RX processing and + * also put a cap on number of TX pkts processed through config param. The + * NAPI schedule function is called if more packets pending. + * + * Returns number of packets received (in most cases; else TX pkts - rarely) + */ +static int emac_poll(struct napi_struct *napi, int budget) +{ + unsigned int mask; + struct emac_priv *priv = container_of(napi, struct emac_priv, napi); + struct net_device *ndev = priv->ndev; + struct device *emac_dev = &ndev->dev; + u32 status = 0; + u32 num_pkts = 0; + + if (!netif_running(ndev)) + return 0; + + /* Check interrupt vectors and call packet processing */ + status = emac_read(EMAC_MACINVECTOR); + + mask = EMAC_DM644X_MAC_IN_VECTOR_TX_INT_VEC; + + if (priv->version == EMAC_VERSION_2) + mask = EMAC_DM646X_MAC_IN_VECTOR_TX_INT_VEC; + + if (status & mask) { + num_pkts = emac_tx_bdproc(priv, EMAC_DEF_TX_CH, + EMAC_DEF_TX_MAX_SERVICE); + } /* TX processing */ + + if (num_pkts) + return budget; + + mask = EMAC_DM644X_MAC_IN_VECTOR_RX_INT_VEC; + + if (priv->version == EMAC_VERSION_2) + mask = EMAC_DM646X_MAC_IN_VECTOR_RX_INT_VEC; + + if (status & mask) { + num_pkts = emac_rx_bdproc(priv, EMAC_DEF_RX_CH, budget); + } /* RX processing */ + + if (num_pkts < budget) { + napi_complete(napi); + emac_int_enable(priv); + } + + if (unlikely(status & EMAC_DM644X_MAC_IN_VECTOR_HOST_INT)) { + u32 ch, cause; + dev_err(emac_dev, "DaVinci EMAC: Fatal Hardware Error\n"); + netif_stop_queue(ndev); + napi_disable(&priv->napi); + + status = emac_read(EMAC_MACSTATUS); + cause = ((status & EMAC_MACSTATUS_TXERRCODE_MASK) >> + EMAC_MACSTATUS_TXERRCODE_SHIFT); + if (cause) { + ch = ((status & EMAC_MACSTATUS_TXERRCH_MASK) >> + EMAC_MACSTATUS_TXERRCH_SHIFT); + if (net_ratelimit()) { + dev_err(emac_dev, "TX Host error %s on ch=%d\n", + &emac_txhost_errcodes[cause][0], ch); + } + } + cause = ((status & EMAC_MACSTATUS_RXERRCODE_MASK) >> + EMAC_MACSTATUS_RXERRCODE_SHIFT); + if (cause) { + ch = ((status & EMAC_MACSTATUS_RXERRCH_MASK) >> + EMAC_MACSTATUS_RXERRCH_SHIFT); + if (netif_msg_hw(priv) && net_ratelimit()) + dev_err(emac_dev, "RX Host error %s on ch=%d\n", + &emac_rxhost_errcodes[cause][0], ch); + } + } /* Host error processing */ + + return num_pkts; +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +/** + * emac_poll_controller: EMAC Poll controller function + * @ndev: The DaVinci EMAC network adapter + * + * Polled functionality used by netconsole and others in non interrupt mode + * + */ +void emac_poll_controller(struct net_device *ndev) +{ + struct emac_priv *priv = netdev_priv(ndev); + + emac_int_disable(priv); + emac_irq(ndev->irq, priv); + emac_int_enable(priv); +} +#endif + +/* PHY/MII bus related */ + +/* Wait until mdio is ready for next command */ +#define MDIO_WAIT_FOR_USER_ACCESS\ + while ((emac_mdio_read((MDIO_USERACCESS(0))) &\ + MDIO_USERACCESS_GO) != 0) + +static int emac_mii_read(struct mii_bus *bus, int phy_id, int phy_reg) +{ + unsigned int phy_data = 0; + unsigned int phy_control; + + /* Wait until mdio is ready for next command */ + MDIO_WAIT_FOR_USER_ACCESS; + + phy_control = (MDIO_USERACCESS_GO | + MDIO_USERACCESS_READ | + ((phy_reg << 21) & MDIO_USERACCESS_REGADR) | + ((phy_id << 16) & MDIO_USERACCESS_PHYADR) | + (phy_data & MDIO_USERACCESS_DATA)); + emac_mdio_write(MDIO_USERACCESS(0), phy_control); + + /* Wait until mdio is ready for next command */ + MDIO_WAIT_FOR_USER_ACCESS; + + return emac_mdio_read(MDIO_USERACCESS(0)) & MDIO_USERACCESS_DATA; + +} + +static int emac_mii_write(struct mii_bus *bus, int phy_id, + int phy_reg, u16 phy_data) +{ + + unsigned int control; + + /* until mdio is ready for next command */ + MDIO_WAIT_FOR_USER_ACCESS; + + control = (MDIO_USERACCESS_GO | + MDIO_USERACCESS_WRITE | + ((phy_reg << 21) & MDIO_USERACCESS_REGADR) | + ((phy_id << 16) & MDIO_USERACCESS_PHYADR) | + (phy_data & MDIO_USERACCESS_DATA)); + emac_mdio_write(MDIO_USERACCESS(0), control); + + return 0; +} + +static int emac_mii_reset(struct mii_bus *bus) +{ + unsigned int clk_div; + int mdio_bus_freq = emac_bus_frequency; + + if (mdio_max_freq & mdio_bus_freq) + clk_div = ((mdio_bus_freq / mdio_max_freq) - 1); + else + clk_div = 0xFF; + + clk_div &= MDIO_CONTROL_CLKDIV; + + /* Set enable and clock divider in MDIOControl */ + emac_mdio_write(MDIO_CONTROL, (clk_div | MDIO_CONTROL_ENABLE)); + + return 0; + +} + +static int mii_irqs[PHY_MAX_ADDR] = { PHY_POLL, PHY_POLL }; + +/* emac_driver: EMAC MII bus structure */ + +static struct mii_bus *emac_mii; + +static void emac_adjust_link(struct net_device *ndev) +{ + struct emac_priv *priv = netdev_priv(ndev); + struct phy_device *phydev = priv->phydev; + unsigned long flags; + int new_state = 0; + + spin_lock_irqsave(&priv->lock, flags); + + if (phydev->link) { + /* check the mode of operation - full/half duplex */ + if (phydev->duplex != priv->duplex) { + new_state = 1; + priv->duplex = phydev->duplex; + } + if (phydev->speed != priv->speed) { + new_state = 1; + priv->speed = phydev->speed; + } + if (!priv->link) { + new_state = 1; + priv->link = 1; + } + + } else if (priv->link) { + new_state = 1; + priv->link = 0; + priv->speed = 0; + priv->duplex = ~0; + } + if (new_state) { + emac_update_phystatus(priv); + phy_print_status(priv->phydev); + } + + spin_unlock_irqrestore(&priv->lock, flags); +} + +/************************************************************************* + * Linux Driver Model + *************************************************************************/ + +/** + * emac_devioctl: EMAC adapter ioctl + * @ndev: The DaVinci EMAC network adapter + * @ifrq: request parameter + * @cmd: command parameter + * + * EMAC driver ioctl function + * + * Returns success(0) or appropriate error code + */ +static int emac_devioctl(struct net_device *ndev, struct ifreq *ifrq, int cmd) +{ + dev_warn(&ndev->dev, "DaVinci EMAC: ioctl not supported\n"); + + if (!(netif_running(ndev))) + return -EINVAL; + + /* TODO: Add phy read and write and private statistics get feature */ + + return -EOPNOTSUPP; +} + +/** + * emac_dev_open: EMAC device open + * @ndev: The DaVinci EMAC network adapter + * + * Called when system wants to start the interface. We init TX/RX channels + * and enable the hardware for packet reception/transmission and start the + * network queue. + * + * Returns 0 for a successful open, or appropriate error code + */ +static int emac_dev_open(struct net_device *ndev) +{ + struct device *emac_dev = &ndev->dev; + u32 rc, cnt, ch; + int phy_addr; + struct resource *res; + int q, m; + int i = 0; + int k = 0; + struct emac_priv *priv = netdev_priv(ndev); + + netif_carrier_off(ndev); + for (cnt = 0; cnt <= ETH_ALEN; cnt++) + ndev->dev_addr[cnt] = priv->mac_addr[cnt]; + + /* Configuration items */ + priv->rx_buf_size = EMAC_DEF_MAX_FRAME_SIZE + NET_IP_ALIGN; + + /* Clear basic hardware */ + for (ch = 0; ch < EMAC_MAX_TXRX_CHANNELS; ch++) { + emac_write(EMAC_TXHDP(ch), 0); + emac_write(EMAC_RXHDP(ch), 0); + emac_write(EMAC_RXHDP(ch), 0); + emac_write(EMAC_RXINTMASKCLEAR, EMAC_INT_MASK_CLEAR); + emac_write(EMAC_TXINTMASKCLEAR, EMAC_INT_MASK_CLEAR); + } + priv->mac_hash1 = 0; + priv->mac_hash2 = 0; + emac_write(EMAC_MACHASH1, 0); + emac_write(EMAC_MACHASH2, 0); + + /* multi ch not supported - open 1 TX, 1RX ch by default */ + rc = emac_init_txch(priv, EMAC_DEF_TX_CH); + if (0 != rc) { + dev_err(emac_dev, "DaVinci EMAC: emac_init_txch() failed"); + return rc; + } + rc = emac_init_rxch(priv, EMAC_DEF_RX_CH, priv->mac_addr); + if (0 != rc) { + dev_err(emac_dev, "DaVinci EMAC: emac_init_rxch() failed"); + return rc; + } + + /* Request IRQ */ + + while ((res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, k))) { + for (i = res->start; i <= res->end; i++) { + if (request_irq(i, emac_irq, IRQF_DISABLED, + ndev->name, ndev)) + goto rollback; + } + k++; + } + + /* Start/Enable EMAC hardware */ + emac_hw_enable(priv); + + /* find the first phy */ + priv->phydev = NULL; + if (priv->phy_mask) { + emac_mii_reset(priv->mii_bus); + for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) { + if (priv->mii_bus->phy_map[phy_addr]) { + priv->phydev = priv->mii_bus->phy_map[phy_addr]; + break; + } + } + + if (!priv->phydev) { + printk(KERN_ERR "%s: no PHY found\n", ndev->name); + return -1; + } + + priv->phydev = phy_connect(ndev, dev_name(&priv->phydev->dev), + &emac_adjust_link, 0, PHY_INTERFACE_MODE_MII); + + if (IS_ERR(priv->phydev)) { + printk(KERN_ERR "%s: Could not attach to PHY\n", + ndev->name); + return PTR_ERR(priv->phydev); + } + + priv->link = 0; + priv->speed = 0; + priv->duplex = ~0; + + printk(KERN_INFO "%s: attached PHY driver [%s] " + "(mii_bus:phy_addr=%s, id=%x)\n", ndev->name, + priv->phydev->drv->name, dev_name(&priv->phydev->dev), + priv->phydev->phy_id); + } else{ + /* No PHY , fix the link, speed and duplex settings */ + priv->link = 1; + priv->speed = SPEED_100; + priv->duplex = DUPLEX_FULL; + emac_update_phystatus(priv); + } + + if (!netif_running(ndev)) /* debug only - to avoid compiler warning */ + emac_dump_regs(priv); + + if (netif_msg_drv(priv)) + dev_notice(emac_dev, "DaVinci EMAC: Opened %s\n", ndev->name); + + if (priv->phy_mask) + phy_start(priv->phydev); + + return 0; + +rollback: + + dev_err(emac_dev, "DaVinci EMAC: request_irq() failed"); + + for (q = k; k >= 0; k--) { + for (m = i; m >= res->start; m--) + free_irq(m, ndev); + res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, k-1); + m = res->end; + } + return -EBUSY; +} + +/** + * emac_dev_stop: EMAC device stop + * @ndev: The DaVinci EMAC network adapter + * + * Called when system wants to stop or down the interface. We stop the network + * queue, disable interrupts and cleanup TX/RX channels. + * + * We return the statistics in net_device_stats structure pulled from emac + */ +static int emac_dev_stop(struct net_device *ndev) +{ + struct resource *res; + int i = 0; + int irq_num; + struct emac_priv *priv = netdev_priv(ndev); + struct device *emac_dev = &ndev->dev; + + /* inform the upper layers. */ + netif_stop_queue(ndev); + napi_disable(&priv->napi); + + netif_carrier_off(ndev); + emac_int_disable(priv); + emac_stop_txch(priv, EMAC_DEF_TX_CH); + emac_stop_rxch(priv, EMAC_DEF_RX_CH); + emac_cleanup_txch(priv, EMAC_DEF_TX_CH); + emac_cleanup_rxch(priv, EMAC_DEF_RX_CH); + emac_write(EMAC_SOFTRESET, 1); + + if (priv->phydev) + phy_disconnect(priv->phydev); + + /* Free IRQ */ + while ((res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, i))) { + for (irq_num = res->start; irq_num <= res->end; irq_num++) + free_irq(irq_num, priv->ndev); + i++; + } + + if (netif_msg_drv(priv)) + dev_notice(emac_dev, "DaVinci EMAC: %s stopped\n", ndev->name); + + return 0; +} + +/** + * emac_dev_getnetstats: EMAC get statistics function + * @ndev: The DaVinci EMAC network adapter + * + * Called when system wants to get statistics from the device. + * + * We return the statistics in net_device_stats structure pulled from emac + */ +static struct net_device_stats *emac_dev_getnetstats(struct net_device *ndev) +{ + struct emac_priv *priv = netdev_priv(ndev); + + /* update emac hardware stats and reset the registers*/ + + priv->net_dev_stats.multicast += emac_read(EMAC_RXMCASTFRAMES); + emac_write(EMAC_RXMCASTFRAMES, EMAC_ALL_MULTI_REG_VALUE); + + priv->net_dev_stats.collisions += (emac_read(EMAC_TXCOLLISION) + + emac_read(EMAC_TXSINGLECOLL) + + emac_read(EMAC_TXMULTICOLL)); + emac_write(EMAC_TXCOLLISION, EMAC_ALL_MULTI_REG_VALUE); + emac_write(EMAC_TXSINGLECOLL, EMAC_ALL_MULTI_REG_VALUE); + emac_write(EMAC_TXMULTICOLL, EMAC_ALL_MULTI_REG_VALUE); + + priv->net_dev_stats.rx_length_errors += (emac_read(EMAC_RXOVERSIZED) + + emac_read(EMAC_RXJABBER) + + emac_read(EMAC_RXUNDERSIZED)); + emac_write(EMAC_RXOVERSIZED, EMAC_ALL_MULTI_REG_VALUE); + emac_write(EMAC_RXJABBER, EMAC_ALL_MULTI_REG_VALUE); + emac_write(EMAC_RXUNDERSIZED, EMAC_ALL_MULTI_REG_VALUE); + + priv->net_dev_stats.rx_over_errors += (emac_read(EMAC_RXSOFOVERRUNS) + + emac_read(EMAC_RXMOFOVERRUNS)); + emac_write(EMAC_RXSOFOVERRUNS, EMAC_ALL_MULTI_REG_VALUE); + emac_write(EMAC_RXMOFOVERRUNS, EMAC_ALL_MULTI_REG_VALUE); + + priv->net_dev_stats.rx_fifo_errors += emac_read(EMAC_RXDMAOVERRUNS); + emac_write(EMAC_RXDMAOVERRUNS, EMAC_ALL_MULTI_REG_VALUE); + + priv->net_dev_stats.tx_carrier_errors += + emac_read(EMAC_TXCARRIERSENSE); + emac_write(EMAC_TXCARRIERSENSE, EMAC_ALL_MULTI_REG_VALUE); + + priv->net_dev_stats.tx_fifo_errors = emac_read(EMAC_TXUNDERRUN); + emac_write(EMAC_TXUNDERRUN, EMAC_ALL_MULTI_REG_VALUE); + + return &priv->net_dev_stats; +} + +static const struct net_device_ops emac_netdev_ops = { + .ndo_open = emac_dev_open, + .ndo_stop = emac_dev_stop, + .ndo_start_xmit = emac_dev_xmit, + .ndo_set_multicast_list = emac_dev_mcast_set, + .ndo_set_mac_address = emac_dev_setmac_addr, + .ndo_do_ioctl = emac_devioctl, + .ndo_tx_timeout = emac_dev_tx_timeout, + .ndo_get_stats = emac_dev_getnetstats, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = emac_poll_controller, +#endif +}; + +/** + * davinci_emac_probe: EMAC device probe + * @pdev: The DaVinci EMAC device that we are removing + * + * Called when probing for emac devicesr. We get details of instances and + * resource information from platform init and register a network device + * and allocate resources necessary for driver to perform + */ +static int __devinit davinci_emac_probe(struct platform_device *pdev) +{ + int rc = 0; + struct resource *res; + struct net_device *ndev; + struct emac_priv *priv; + unsigned long size; + struct emac_platform_data *pdata; + struct device *emac_dev; + + /* obtain emac clock from kernel */ + emac_clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(emac_clk)) { + printk(KERN_ERR "DaVinci EMAC: Failed to get EMAC clock\n"); + return -EBUSY; + } + emac_bus_frequency = clk_get_rate(emac_clk); + /* TODO: Probe PHY here if possible */ + + ndev = alloc_etherdev(sizeof(struct emac_priv)); + if (!ndev) { + printk(KERN_ERR "DaVinci EMAC: Error allocating net_device\n"); + clk_put(emac_clk); + return -ENOMEM; + } + + platform_set_drvdata(pdev, ndev); + priv = netdev_priv(ndev); + priv->pdev = pdev; + priv->ndev = ndev; + priv->msg_enable = netif_msg_init(debug_level, DAVINCI_EMAC_DEBUG); + + spin_lock_init(&priv->tx_lock); + spin_lock_init(&priv->rx_lock); + spin_lock_init(&priv->lock); + + pdata = pdev->dev.platform_data; + if (!pdata) { + printk(KERN_ERR "DaVinci EMAC: No platfrom data\n"); + return -ENODEV; + } + + /* MAC addr and PHY mask , RMII enable info from platform_data */ + memcpy(priv->mac_addr, pdata->mac_addr, 6); + priv->phy_mask = pdata->phy_mask; + priv->rmii_en = pdata->rmii_en; + priv->version = pdata->version; + emac_dev = &ndev->dev; + /* Get EMAC platform data */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(emac_dev, "DaVinci EMAC: Error getting res\n"); + rc = -ENOENT; + goto probe_quit; + } + + priv->emac_base_phys = res->start + pdata->ctrl_reg_offset; + size = res->end - res->start + 1; + if (!request_mem_region(res->start, size, ndev->name)) { + dev_err(emac_dev, "DaVinci EMAC: failed request_mem_region() \ + for regs\n"); + rc = -ENXIO; + goto probe_quit; + } + + priv->remap_addr = ioremap(res->start, size); + if (!priv->remap_addr) { + dev_err(emac_dev, "Unable to map IO\n"); + rc = -ENOMEM; + release_mem_region(res->start, size); + goto probe_quit; + } + priv->emac_base = priv->remap_addr + pdata->ctrl_reg_offset; + ndev->base_addr = (unsigned long)priv->remap_addr; + + priv->ctrl_base = priv->remap_addr + pdata->ctrl_mod_reg_offset; + priv->ctrl_ram_size = pdata->ctrl_ram_size; + priv->emac_ctrl_ram = priv->remap_addr + pdata->ctrl_ram_offset; + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res) { + dev_err(emac_dev, "DaVinci EMAC: Error getting irq res\n"); + rc = -ENOENT; + goto no_irq_res; + } + ndev->irq = res->start; + + if (!is_valid_ether_addr(priv->mac_addr)) { + /* Use random MAC if none passed */ + random_ether_addr(priv->mac_addr); + printk(KERN_WARNING "%s: using random MAC addr: %pM\n", + __func__, priv->mac_addr); + } + + ndev->netdev_ops = &emac_netdev_ops; + SET_ETHTOOL_OPS(ndev, ðtool_ops); + netif_napi_add(ndev, &priv->napi, emac_poll, EMAC_POLL_WEIGHT); + + /* register the network device */ + SET_NETDEV_DEV(ndev, &pdev->dev); + rc = register_netdev(ndev); + if (rc) { + dev_err(emac_dev, "DaVinci EMAC: Error in register_netdev\n"); + rc = -ENODEV; + goto netdev_reg_err; + } + + clk_enable(emac_clk); + + /* MII/Phy intialisation, mdio bus registration */ + emac_mii = mdiobus_alloc(); + if (emac_mii == NULL) { + dev_err(emac_dev, "DaVinci EMAC: Error allocating mii_bus\n"); + rc = -ENOMEM; + goto mdio_alloc_err; + } + + priv->mii_bus = emac_mii; + emac_mii->name = "emac-mii", + emac_mii->read = emac_mii_read, + emac_mii->write = emac_mii_write, + emac_mii->reset = emac_mii_reset, + emac_mii->irq = mii_irqs, + emac_mii->phy_mask = ~(priv->phy_mask); + emac_mii->parent = &pdev->dev; + emac_mii->priv = priv->remap_addr + pdata->mdio_reg_offset; + snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%x", priv->pdev->id); + mdio_max_freq = pdata->mdio_max_freq; + emac_mii->reset(emac_mii); + + /* Register the MII bus */ + rc = mdiobus_register(emac_mii); + if (rc) + goto mdiobus_quit; + + if (netif_msg_probe(priv)) { + dev_notice(emac_dev, "DaVinci EMAC Probe found device "\ + "(regs: %p, irq: %d)\n", + (void *)priv->emac_base_phys, ndev->irq); + } + return 0; + +mdiobus_quit: + mdiobus_free(emac_mii); + +netdev_reg_err: +mdio_alloc_err: +no_irq_res: + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(res->start, res->end - res->start + 1); + iounmap(priv->remap_addr); + +probe_quit: + clk_put(emac_clk); + free_netdev(ndev); + return rc; +} + +/** + * davinci_emac_remove: EMAC device remove + * @pdev: The DaVinci EMAC device that we are removing + * + * Called when removing the device driver. We disable clock usage and release + * the resources taken up by the driver and unregister network device + */ +static int __devexit davinci_emac_remove(struct platform_device *pdev) +{ + struct resource *res; + struct net_device *ndev = platform_get_drvdata(pdev); + struct emac_priv *priv = netdev_priv(ndev); + + dev_notice(&ndev->dev, "DaVinci EMAC: davinci_emac_remove()\n"); + + platform_set_drvdata(pdev, NULL); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + mdiobus_unregister(priv->mii_bus); + mdiobus_free(priv->mii_bus); + + release_mem_region(res->start, res->end - res->start + 1); + + unregister_netdev(ndev); + free_netdev(ndev); + iounmap(priv->remap_addr); + + clk_disable(emac_clk); + clk_put(emac_clk); + + return 0; +} + +/** + * davinci_emac_driver: EMAC platform driver structure + * + * We implement only probe and remove functions - suspend/resume and + * others not supported by this module + */ +static struct platform_driver davinci_emac_driver = { + .driver = { + .name = "davinci_emac", + .owner = THIS_MODULE, + }, + .probe = davinci_emac_probe, + .remove = __devexit_p(davinci_emac_remove), +}; + +/** + * davinci_emac_init: EMAC driver module init + * + * Called when initializing the driver. We register the driver with + * the platform. + */ +static int __init davinci_emac_init(void) +{ + return platform_driver_register(&davinci_emac_driver); +} +module_init(davinci_emac_init); + +/** + * davinci_emac_exit: EMAC driver module exit + * + * Called when exiting the driver completely. We unregister the driver with + * the platform and exit + */ +static void __exit davinci_emac_exit(void) +{ + platform_driver_unregister(&davinci_emac_driver); +} +module_exit(davinci_emac_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("DaVinci EMAC Maintainer: Anant Gole "); +MODULE_AUTHOR("DaVinci EMAC Maintainer: Chaithrika U S "); +MODULE_DESCRIPTION("DaVinci EMAC Ethernet driver"); diff --git a/drivers/net/de600.c b/drivers/net/de600.c index de63f1d41d32..e1af089064bc 100644 --- a/drivers/net/de600.c +++ b/drivers/net/de600.c @@ -38,14 +38,6 @@ static const char version[] = "de600.c: $Revision: 1.41-2.5 $, Bjorn Ekwall (bj /* Add more time here if your adapter won't work OK: */ #define DE600_SLOW_DOWN udelay(delay_time) -/* use 0 for production, 1 for verification, >2 for debug */ -#ifdef DE600_DEBUG -#define PRINTK(x) if (de600_debug >= 2) printk x -#else -#define DE600_DEBUG 0 -#define PRINTK(x) /**/ -#endif - #include #include #include @@ -67,10 +59,6 @@ static const char version[] = "de600.c: $Revision: 1.41-2.5 $, Bjorn Ekwall (bj #include "de600.h" -static unsigned int de600_debug = DE600_DEBUG; -module_param(de600_debug, int, 0); -MODULE_PARM_DESC(de600_debug, "DE-600 debug level (0-2)"); - static unsigned int check_lost = 1; module_param(check_lost, bool, 0); MODULE_PARM_DESC(check_lost, "If set then check for unplugged de600"); @@ -180,20 +168,20 @@ static int de600_start_xmit(struct sk_buff *skb, struct net_device *dev) if (free_tx_pages <= 0) { /* Do timeouts, to avoid hangs. */ tickssofar = jiffies - dev->trans_start; if (tickssofar < 5) - return 1; + return NETDEV_TX_BUSY; /* else */ printk(KERN_WARNING "%s: transmit timed out (%d), %s?\n", dev->name, tickssofar, "network cable problem"); /* Restart the adapter. */ spin_lock_irqsave(&de600_lock, flags); if (adapter_init(dev)) { spin_unlock_irqrestore(&de600_lock, flags); - return 1; + return NETDEV_TX_BUSY; } spin_unlock_irqrestore(&de600_lock, flags); } /* Start real output */ - PRINTK(("de600_start_xmit:len=%d, page %d/%d\n", skb->len, tx_fifo_in, free_tx_pages)); + pr_debug("de600_start_xmit:len=%d, page %d/%d\n", skb->len, tx_fifo_in, free_tx_pages); if ((len = skb->len) < RUNT) len = RUNT; @@ -211,7 +199,7 @@ static int de600_start_xmit(struct sk_buff *skb, struct net_device *dev) if (was_down || (de600_read_byte(READ_DATA, dev) != 0xde)) { if (adapter_init(dev)) { spin_unlock_irqrestore(&de600_lock, flags); - return 1; + return NETDEV_TX_BUSY; } } } @@ -259,7 +247,7 @@ static irqreturn_t de600_interrupt(int irq, void *dev_id) irq_status = de600_read_status(dev); do { - PRINTK(("de600_interrupt (%02X)\n", irq_status)); + pr_debug("de600_interrupt (%02X)\n", irq_status); if (irq_status & RX_GOOD) de600_rx_intr(dev); @@ -407,8 +395,7 @@ static struct net_device * __init de600_probe(void) printk(KERN_INFO "%s: D-Link DE-600 pocket adapter", dev->name); /* Alpha testers must have the version number to report bugs. */ - if (de600_debug > 1) - printk(version); + pr_debug("%s", version); /* probe for adapter */ err = -ENODEV; diff --git a/drivers/net/de620.c b/drivers/net/de620.c index d52f34cc9526..55d2bb67cffa 100644 --- a/drivers/net/de620.c +++ b/drivers/net/de620.c @@ -48,7 +48,6 @@ static const char version[] = * Compile-time options: (see below for descriptions) * -DDE620_IO=0x378 (lpt1) * -DDE620_IRQ=7 (lpt1) - * -DDE602_DEBUG=... * -DSHUTDOWN_WHEN_LOST * -DCOUNT_LOOPS * -DLOWSPEED @@ -98,15 +97,6 @@ static const char version[] = #define SHUTDOWN_WHEN_LOST */ -/* - * Enable debugging by "-DDE620_DEBUG=3" when compiling, - * OR by enabling the following #define - * - * use 0 for production, 1 for verification, >2 for debug - * -#define DE620_DEBUG 3 - */ - #ifdef LOWSPEED /* * Enable this #define if you want to see debugging output that show how long @@ -160,14 +150,6 @@ typedef unsigned char byte; #define RUNT 60 /* Too small Ethernet packet */ #define GIANT 1514 /* largest legal size packet, no fcs */ -#ifdef DE620_DEBUG /* Compile-time configurable */ -#define PRINTK(x) if (de620_debug >= 2) printk x -#else -#define DE620_DEBUG 0 -#define PRINTK(x) /**/ -#endif - - /* * Force media with insmod: * insmod de620.o bnc=1 @@ -186,8 +168,6 @@ static int io = DE620_IO; static int irq = DE620_IRQ; static int clone = DE620_CLONE; -static unsigned int de620_debug = DE620_DEBUG; - static spinlock_t de620_lock; module_param(bnc, int, 0); @@ -195,13 +175,11 @@ module_param(utp, int, 0); module_param(io, int, 0); module_param(irq, int, 0); module_param(clone, int, 0); -module_param(de620_debug, int, 0); MODULE_PARM_DESC(bnc, "DE-620 set BNC medium (0-1)"); MODULE_PARM_DESC(utp, "DE-620 set UTP medium (0-1)"); MODULE_PARM_DESC(io, "DE-620 I/O base address,required"); MODULE_PARM_DESC(irq, "DE-620 IRQ number,required"); MODULE_PARM_DESC(clone, "Check also for non-D-Link DE-620 clones (0-1)"); -MODULE_PARM_DESC(de620_debug, "DE-620 debug level (0-2)"); /*********************************************** * * @@ -533,9 +511,9 @@ static int de620_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Start real output */ - spin_lock_irqsave(&de620_lock, flags) - PRINTK(("de620_start_xmit: len=%d, bufs 0x%02x\n", - (int)skb->len, using_txbuf)); + spin_lock_irqsave(&de620_lock, flags); + pr_debug("de620_start_xmit: len=%d, bufs 0x%02x\n", + (int)skb->len, using_txbuf); /* select a free tx buffer. if there is one... */ switch (using_txbuf) { @@ -553,7 +531,7 @@ static int de620_start_xmit(struct sk_buff *skb, struct net_device *dev) case (TXBF0 | TXBF1): /* NONE!!! */ printk(KERN_WARNING "%s: No tx-buffer available!\n", dev->name); spin_unlock_irqrestore(&de620_lock, flags); - return 1; + return NETDEV_TX_BUSY; } de620_write_block(dev, buffer, skb->len, len-skb->len); @@ -585,12 +563,12 @@ de620_interrupt(int irq_in, void *dev_id) /* Read the status register (_not_ the status port) */ irq_status = de620_get_register(dev, R_STS); - PRINTK(("de620_interrupt (%2.2X)\n", irq_status)); + pr_debug("de620_interrupt (%2.2X)\n", irq_status); if (irq_status & RXGOOD) { do { again = de620_rx_intr(dev); - PRINTK(("again=%d\n", again)); + pr_debug("again=%d\n", again); } while (again && (++bogus_count < 100)); } @@ -622,7 +600,7 @@ static int de620_rx_intr(struct net_device *dev) byte pagelink; byte curr_page; - PRINTK(("de620_rx_intr: next_rx_page = %d\n", next_rx_page)); + pr_debug("de620_rx_intr: next_rx_page = %d\n", next_rx_page); /* Tell the adapter that we are going to read data, and from where */ de620_send_command(dev, W_CR | RRN); @@ -631,8 +609,9 @@ static int de620_rx_intr(struct net_device *dev) /* Deep breath, and away we goooooo */ de620_read_block(dev, (byte *)&header_buf, sizeof(struct header_buf)); - PRINTK(("page status=0x%02x, nextpage=%d, packetsize=%d\n", - header_buf.status, header_buf.Rx_NextPage, header_buf.Rx_ByteCount)); + pr_debug("page status=0x%02x, nextpage=%d, packetsize=%d\n", + header_buf.status, header_buf.Rx_NextPage, + header_buf.Rx_ByteCount); /* Plausible page header? */ pagelink = header_buf.Rx_NextPage; @@ -683,7 +662,7 @@ static int de620_rx_intr(struct net_device *dev) buffer = skb_put(skb,size); /* copy the packet into the buffer */ de620_read_block(dev, buffer, size); - PRINTK(("Read %d bytes\n", size)); + pr_debug("Read %d bytes\n", size); skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); /* deliver it "upstairs" */ /* count all receives */ @@ -696,7 +675,7 @@ static int de620_rx_intr(struct net_device *dev) /* NOTE! We're _not_ checking the 'EMPTY'-flag! This seems better... */ curr_page = de620_get_register(dev, R_CPR); de620_set_register(dev, W_NPRF, next_rx_page); - PRINTK(("next_rx_page=%d CPR=%d\n", next_rx_page, curr_page)); + pr_debug("next_rx_page=%d CPR=%d\n", next_rx_page, curr_page); return (next_rx_page != curr_page); /* That was slightly tricky... */ } @@ -830,8 +809,7 @@ struct net_device * __init de620_probe(int unit) netdev_boot_setup_check(dev); } - if (de620_debug) - printk(version); + pr_debug("%s", version); printk(KERN_INFO "D-Link DE-620 pocket adapter"); @@ -878,14 +856,13 @@ struct net_device * __init de620_probe(int unit) /* base_addr and irq are already set, see above! */ /* dump eeprom */ - if (de620_debug) { - printk("\nEEPROM contents:\n"); - printk("RAM_Size = 0x%02X\n", nic_data.RAM_Size); - printk("NodeID = %pM\n", nic_data.NodeID); - printk("Model = %d\n", nic_data.Model); - printk("Media = %d\n", nic_data.Media); - printk("SCR = 0x%02x\n", nic_data.SCR); - } + pr_debug("\nEEPROM contents:\n" + "RAM_Size = 0x%02X\n" + "NodeID = %pM\n" + "Model = %d\n" + "Media = %d\n" + "SCR = 0x%02x\n", nic_data.RAM_Size, nic_data.NodeID, + nic_data.Model, nic_data.Media, nic_data.SCR); err = register_netdev(dev); if (err) diff --git a/drivers/net/declance.c b/drivers/net/declance.c index b62405a69180..2b22e580c4de 100644 --- a/drivers/net/declance.c +++ b/drivers/net/declance.c @@ -895,6 +895,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev) struct lance_private *lp = netdev_priv(dev); volatile struct lance_regs *ll = lp->ll; volatile u16 *ib = (volatile u16 *)dev->mem_start; + unsigned long flags; int entry, len; len = skb->len; @@ -907,6 +908,8 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_bytes += len; + spin_lock_irqsave(&lp->lock, flags); + entry = lp->tx_new; *lib_ptr(ib, btx_ring[entry].length, lp->type) = (-len); *lib_ptr(ib, btx_ring[entry].misc, lp->type) = 0; @@ -925,6 +928,8 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Kick the lance: transmit now */ writereg(&ll->rdp, LE_C0_INEA | LE_C0_TDMD); + spin_unlock_irqrestore(&lp->lock, flags); + dev->trans_start = jiffies; dev_kfree_skb(skb); diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c index 4ec055dc7174..102b8d439714 100644 --- a/drivers/net/defxx.c +++ b/drivers/net/defxx.c @@ -3318,7 +3318,7 @@ static int dfx_xmt_queue_pkt( { skb_pull(skb,3); spin_unlock_irqrestore(&bp->lock, flags); - return(1); /* requeue packet for later */ + return NETDEV_TX_BUSY; /* requeue packet for later */ } /* diff --git a/drivers/net/depca.c b/drivers/net/depca.c index 357f565851ed..97ea2d6d3fe1 100644 --- a/drivers/net/depca.c +++ b/drivers/net/depca.c @@ -810,7 +810,7 @@ static int __init depca_hw_init (struct net_device *dev, struct device *device) dev->mem_start = 0; - device->driver_data = dev; + dev_set_drvdata(device, dev); SET_NETDEV_DEV (dev, device); status = register_netdev(dev); @@ -957,7 +957,7 @@ static int depca_start_xmit(struct sk_buff *skb, struct net_device *dev) if (TX_BUFFS_AVAIL) netif_start_queue(dev); } else - status = -1; + status = NETDEV_TX_LOCKED; out: return status; @@ -1614,7 +1614,7 @@ static int __devexit depca_device_remove (struct device *device) struct depca_private *lp; int bus; - dev = device->driver_data; + dev = dev_get_drvdata(device); lp = netdev_priv(dev); unregister_netdev (dev); @@ -1839,7 +1839,7 @@ static int load_packet(struct net_device *dev, struct sk_buff *skb) lp->tx_new = (++end) & lp->txRingMask; /* update current pointers */ } else { - status = -1; + status = NETDEV_TX_LOCKED; } return status; diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c index 4a1b554654eb..895d72143ee0 100644 --- a/drivers/net/dl2k.c +++ b/drivers/net/dl2k.c @@ -539,7 +539,7 @@ rio_tx_timeout (struct net_device *dev) dev->name, readl (ioaddr + TxStatus)); rio_free_tx(dev, 0); dev->if_port = 0; - dev->trans_start = jiffies; + dev->trans_start = jiffies; /* prevent tx timeout */ } /* allocate and initialize Tx and Rx descriptors */ @@ -610,7 +610,7 @@ start_xmit (struct sk_buff *skb, struct net_device *dev) if (np->link_status == 0) { /* Link Down */ dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } ioaddr = dev->base_addr; entry = np->cur_tx % TX_RING_SIZE; @@ -665,9 +665,7 @@ start_xmit (struct sk_buff *skb, struct net_device *dev) writel (0, dev->base_addr + TFDListPtr1); } - /* NETDEV WATCHDOG timer */ - dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } static irqreturn_t diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index d8350860c0f8..dd771dea6ae6 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c @@ -756,7 +756,7 @@ dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev) dm9000_dbg(db, 3, "%s:\n", __func__); if (db->tx_pkt_cnt > 1) - return 1; + return NETDEV_TX_BUSY; spin_lock_irqsave(&db->lock, flags); @@ -1170,6 +1170,21 @@ dm9000_stop(struct net_device *ndev) return 0; } +static const struct net_device_ops dm9000_netdev_ops = { + .ndo_open = dm9000_open, + .ndo_stop = dm9000_stop, + .ndo_start_xmit = dm9000_start_xmit, + .ndo_tx_timeout = dm9000_timeout, + .ndo_set_multicast_list = dm9000_hash_table, + .ndo_do_ioctl = dm9000_ioctl, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = dm9000_poll_controller, +#endif +}; + #define res_size(_r) (((_r)->end - (_r)->start) + 1) /* @@ -1339,18 +1354,9 @@ dm9000_probe(struct platform_device *pdev) /* driver system function */ ether_setup(ndev); - ndev->open = &dm9000_open; - ndev->hard_start_xmit = &dm9000_start_xmit; - ndev->tx_timeout = &dm9000_timeout; - ndev->watchdog_timeo = msecs_to_jiffies(watchdog); - ndev->stop = &dm9000_stop; - ndev->set_multicast_list = &dm9000_hash_table; - ndev->ethtool_ops = &dm9000_ethtool_ops; - ndev->do_ioctl = &dm9000_ioctl; - -#ifdef CONFIG_NET_POLL_CONTROLLER - ndev->poll_controller = &dm9000_poll_controller; -#endif + ndev->netdev_ops = &dm9000_netdev_ops; + ndev->watchdog_timeo = msecs_to_jiffies(watchdog); + ndev->ethtool_ops = &dm9000_ethtool_ops; db->msg_enable = NETIF_MSG_LINK; db->mii.phy_id_mask = 0x1f; diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 0f9ee1348552..efa680f4b8dd 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -143,6 +143,8 @@ * FIXES: * 2005/12/02 - Michael O'Donnell * - Stratus87247: protect MDI control register manipulations + * 2009/06/01 - Andreas Mohr + * - add clean lowlevel I/O emulation for cards with MII-lacking PHYs */ #include @@ -372,6 +374,7 @@ enum eeprom_op { enum eeprom_offsets { eeprom_cnfg_mdix = 0x03, + eeprom_phy_iface = 0x06, eeprom_id = 0x0A, eeprom_config_asf = 0x0D, eeprom_smbus_addr = 0x90, @@ -381,6 +384,18 @@ enum eeprom_cnfg_mdix { eeprom_mdix_enabled = 0x0080, }; +enum eeprom_phy_iface { + NoSuchPhy = 0, + I82553AB, + I82553C, + I82503, + DP83840, + S80C240, + S80C24, + I82555, + DP83840A = 10, +}; + enum eeprom_id { eeprom_id_wol = 0x0020, }; @@ -545,6 +560,7 @@ struct nic { u32 msg_enable ____cacheline_aligned; struct net_device *netdev; struct pci_dev *pdev; + u16 (*mdio_ctrl)(struct nic *nic, u32 addr, u32 dir, u32 reg, u16 data); struct rx *rxs ____cacheline_aligned; struct rx *rx_to_use; @@ -899,7 +915,21 @@ err_unlock: return err; } -static u16 mdio_ctrl(struct nic *nic, u32 addr, u32 dir, u32 reg, u16 data) +static int mdio_read(struct net_device *netdev, int addr, int reg) +{ + struct nic *nic = netdev_priv(netdev); + return nic->mdio_ctrl(nic, addr, mdi_read, reg, 0); +} + +static void mdio_write(struct net_device *netdev, int addr, int reg, int data) +{ + struct nic *nic = netdev_priv(netdev); + + nic->mdio_ctrl(nic, addr, mdi_write, reg, data); +} + +/* the standard mdio_ctrl() function for usual MII-compliant hardware */ +static u16 mdio_ctrl_hw(struct nic *nic, u32 addr, u32 dir, u32 reg, u16 data) { u32 data_out = 0; unsigned int i; @@ -938,30 +968,83 @@ static u16 mdio_ctrl(struct nic *nic, u32 addr, u32 dir, u32 reg, u16 data) return (u16)data_out; } -static int mdio_read(struct net_device *netdev, int addr, int reg) +/* slightly tweaked mdio_ctrl() function for phy_82552_v specifics */ +static u16 mdio_ctrl_phy_82552_v(struct nic *nic, + u32 addr, + u32 dir, + u32 reg, + u16 data) { - return mdio_ctrl(netdev_priv(netdev), addr, mdi_read, reg, 0); + if ((reg == MII_BMCR) && (dir == mdi_write)) { + if (data & (BMCR_ANRESTART | BMCR_ANENABLE)) { + u16 advert = mdio_read(nic->netdev, nic->mii.phy_id, + MII_ADVERTISE); + + /* + * Workaround Si issue where sometimes the part will not + * autoneg to 100Mbps even when advertised. + */ + if (advert & ADVERTISE_100FULL) + data |= BMCR_SPEED100 | BMCR_FULLDPLX; + else if (advert & ADVERTISE_100HALF) + data |= BMCR_SPEED100; + } + } + return mdio_ctrl_hw(nic, addr, dir, reg, data); } -static void mdio_write(struct net_device *netdev, int addr, int reg, int data) +/* Fully software-emulated mdio_ctrl() function for cards without + * MII-compliant PHYs. + * For now, this is mainly geared towards 80c24 support; in case of further + * requirements for other types (i82503, ...?) either extend this mechanism + * or split it, whichever is cleaner. + */ +static u16 mdio_ctrl_phy_mii_emulated(struct nic *nic, + u32 addr, + u32 dir, + u32 reg, + u16 data) { - struct nic *nic = netdev_priv(netdev); + /* might need to allocate a netdev_priv'ed register array eventually + * to be able to record state changes, but for now + * some fully hardcoded register handling ought to be ok I guess. */ - if ((nic->phy == phy_82552_v) && (reg == MII_BMCR) && - (data & (BMCR_ANRESTART | BMCR_ANENABLE))) { - u16 advert = mdio_read(netdev, nic->mii.phy_id, MII_ADVERTISE); - - /* - * Workaround Si issue where sometimes the part will not - * autoneg to 100Mbps even when advertised. - */ - if (advert & ADVERTISE_100FULL) - data |= BMCR_SPEED100 | BMCR_FULLDPLX; - else if (advert & ADVERTISE_100HALF) - data |= BMCR_SPEED100; + if (dir == mdi_read) { + switch (reg) { + case MII_BMCR: + /* Auto-negotiation, right? */ + return BMCR_ANENABLE | + BMCR_FULLDPLX; + case MII_BMSR: + return BMSR_LSTATUS /* for mii_link_ok() */ | + BMSR_ANEGCAPABLE | + BMSR_10FULL; + case MII_ADVERTISE: + /* 80c24 is a "combo card" PHY, right? */ + return ADVERTISE_10HALF | + ADVERTISE_10FULL; + default: + DPRINTK(HW, DEBUG, + "%s:addr=%d, reg=%d, data=0x%04X: unimplemented emulation!\n", + dir == mdi_read ? "READ" : "WRITE", addr, reg, data); + return 0xFFFF; + } + } else { + switch (reg) { + default: + DPRINTK(HW, DEBUG, + "%s:addr=%d, reg=%d, data=0x%04X: unimplemented emulation!\n", + dir == mdi_read ? "READ" : "WRITE", addr, reg, data); + return 0xFFFF; + } } - - mdio_ctrl(netdev_priv(netdev), addr, mdi_write, reg, data); +} +static inline int e100_phy_supports_mii(struct nic *nic) +{ + /* for now, just check it by comparing whether we + are using MII software emulation. + */ + return (nic->mdio_ctrl != mdio_ctrl_phy_mii_emulated); } static void e100_get_defaults(struct nic *nic) @@ -1013,7 +1096,8 @@ static void e100_configure(struct nic *nic, struct cb *cb, struct sk_buff *skb) config->standard_stat_counter = 0x1; /* 1=standard, 0=extended */ config->rx_discard_short_frames = 0x1; /* 1=discard, 0=pass */ config->tx_underrun_retry = 0x3; /* # of underrun retries */ - config->mii_mode = 0x1; /* 1=MII mode, 0=503 mode */ + if (e100_phy_supports_mii(nic)) + config->mii_mode = 1; /* 1=MII mode, 0=i82503 mode */ config->pad10 = 0x6; config->no_source_addr_insertion = 0x1; /* 1=no, 0=yes */ config->preamble_length = 0x2; /* 0=1, 1=3, 2=7, 3=15 bytes */ @@ -1270,6 +1354,42 @@ static void e100_dump(struct nic *nic, struct cb *cb, struct sk_buff *skb) offsetof(struct mem, dump_buf)); } +static int e100_phy_check_without_mii(struct nic *nic) +{ + u8 phy_type; + int without_mii; + + phy_type = (nic->eeprom[eeprom_phy_iface] >> 8) & 0x0f; + + switch (phy_type) { + case NoSuchPhy: /* Non-MII PHY; UNTESTED! */ + case I82503: /* Non-MII PHY; UNTESTED! */ + case S80C24: /* Non-MII PHY; tested and working */ + /* paragraph from the FreeBSD driver, "FXP_PHY_80C24": + * The Seeq 80c24 AutoDUPLEX(tm) Ethernet Interface Adapter + * doesn't have a programming interface of any sort. The + * media is sensed automatically based on how the link partner + * is configured. This is, in essence, manual configuration. + */ + DPRINTK(PROBE, INFO, + "found MII-less i82503 or 80c24 or other PHY\n"); + + nic->mdio_ctrl = mdio_ctrl_phy_mii_emulated; + nic->mii.phy_id = 0; /* is this ok for an MII-less PHY? */ + + /* these might be needed for certain MII-less cards... + * nic->flags |= ich; + * nic->flags |= ich_10h_workaround; */ + + without_mii = 1; + break; + default: + without_mii = 0; + break; + } + return without_mii; +} + #define NCONFIG_AUTO_SWITCH 0x0080 #define MII_NSC_CONG MII_RESV1 #define NSC_CONG_ENABLE 0x0100 @@ -1290,9 +1410,21 @@ static int e100_phy_init(struct nic *nic) if (!((bmcr == 0xFFFF) || ((stat == 0) && (bmcr == 0)))) break; } - DPRINTK(HW, DEBUG, "phy_addr = %d\n", nic->mii.phy_id); - if (addr == 32) - return -EAGAIN; + if (addr == 32) { + /* uhoh, no PHY detected: check whether we seem to be some + * weird, rare variant which is *known* to not have any MII. + * But do this AFTER MII checking only, since this does + * lookup of EEPROM values which may easily be unreliable. */ + if (e100_phy_check_without_mii(nic)) + return 0; /* simply return and hope for the best */ + else { + /* for unknown cases log a fatal error */ + DPRINTK(HW, ERR, + "Failed to locate any known PHY, aborting.\n"); + return -EAGAIN; + } + } else + DPRINTK(HW, DEBUG, "phy_addr = %d\n", nic->mii.phy_id); /* Isolate all the PHY ids */ for (addr = 0; addr < 32; addr++) @@ -1320,6 +1452,9 @@ static int e100_phy_init(struct nic *nic) if (nic->phy == phy_82552_v) { u16 advert = mdio_read(netdev, nic->mii.phy_id, MII_ADVERTISE); + /* assign special tweaked mdio_ctrl() function */ + nic->mdio_ctrl = mdio_ctrl_phy_82552_v; + /* Workaround Si not advertising flow-control during autoneg */ advert |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; mdio_write(netdev, nic->mii.phy_id, MII_ADVERTISE, advert); @@ -1581,7 +1716,7 @@ static int e100_xmit_frame(struct sk_buff *skb, struct net_device *netdev) /* This is a hard error - log it. */ DPRINTK(TX_ERR, DEBUG, "Out of Tx resources, returning skb\n"); netif_stop_queue(netdev); - return 1; + return NETDEV_TX_BUSY; } netdev->trans_start = jiffies; @@ -2585,6 +2720,7 @@ static int __devinit e100_probe(struct pci_dev *pdev, nic->netdev = netdev; nic->pdev = pdev; nic->msg_enable = (1 << debug) - 1; + nic->mdio_ctrl = mdio_ctrl_hw; pci_set_drvdata(pdev, netdev); if ((err = pci_enable_device(pdev))) { @@ -2759,12 +2895,13 @@ static void __e100_shutdown(struct pci_dev *pdev, bool *enable_wake) static int __e100_power_off(struct pci_dev *pdev, bool wake) { - if (wake) { + if (wake) return pci_prepare_to_sleep(pdev); - } else { - pci_wake_from_d3(pdev, false); - return pci_set_power_state(pdev, PCI_D3hot); - } + + pci_wake_from_d3(pdev, false); + pci_set_power_state(pdev, PCI_D3hot); + + return 0; } #ifdef CONFIG_PM @@ -2785,7 +2922,7 @@ static int e100_resume(struct pci_dev *pdev) /* ack any pending wake events, disable PME */ pci_enable_wake(pdev, 0, 0); - /* disbale reverse auto-negotiation */ + /* disable reverse auto-negotiation */ if (nic->phy == phy_82552_v) { u16 smartspeed = mdio_read(netdev, nic->mii.phy_id, E100_82552_SMARTSPEED); @@ -2822,12 +2959,13 @@ static pci_ers_result_t e100_io_error_detected(struct pci_dev *pdev, pci_channel struct net_device *netdev = pci_get_drvdata(pdev); struct nic *nic = netdev_priv(netdev); - /* Similar to calling e100_down(), but avoids adapter I/O. */ - e100_close(netdev); - - /* Detach; put netif into a state similar to hotplug unplug. */ - napi_enable(&nic->napi); netif_device_detach(netdev); + + if (state == pci_channel_io_perm_failure) + return PCI_ERS_RESULT_DISCONNECT; + + if (netif_running(netdev)) + e100_down(nic); pci_disable_device(pdev); /* Request a slot reset. */ diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index fffb006b7d95..5e3356f8eb5a 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -498,6 +498,8 @@ int e1000_up(struct e1000_adapter *adapter) e1000_irq_enable(adapter); + netif_wake_queue(adapter->netdev); + /* fire a link change interrupt to start the watchdog */ ew32(ICS, E1000_ICS_LSC); return 0; @@ -1234,15 +1236,14 @@ static int __devinit e1000_probe(struct pci_dev *pdev, !e1000_check_mng_mode(hw)) e1000_get_hw_control(adapter); - /* tell the stack to leave us alone until e1000_open() is called */ - netif_carrier_off(netdev); - netif_stop_queue(netdev); - strcpy(netdev->name, "eth%d"); err = register_netdev(netdev); if (err) goto err_register; + /* carrier off reporting is important to ethtool even BEFORE open */ + netif_carrier_off(netdev); + DPRINTK(PROBE, INFO, "Intel(R) PRO/1000 Network Connection\n"); cards_found++; @@ -1441,6 +1442,8 @@ static int e1000_open(struct net_device *netdev) if (test_bit(__E1000_TESTING, &adapter->flags)) return -EBUSY; + netif_carrier_off(netdev); + /* allocate transmit descriptors */ err = e1000_setup_all_tx_resources(adapter); if (err) @@ -2327,7 +2330,8 @@ static void e1000_set_rx_mode(struct net_device *netdev) { struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; - struct dev_addr_list *uc_ptr; + struct netdev_hw_addr *ha; + bool use_uc = false; struct dev_addr_list *mc_ptr; u32 rctl; u32 hash_value; @@ -2366,12 +2370,11 @@ static void e1000_set_rx_mode(struct net_device *netdev) rctl |= E1000_RCTL_VFE; } - uc_ptr = NULL; - if (netdev->uc_count > rar_entries - 1) { + if (netdev->uc.count > rar_entries - 1) { rctl |= E1000_RCTL_UPE; } else if (!(netdev->flags & IFF_PROMISC)) { rctl &= ~E1000_RCTL_UPE; - uc_ptr = netdev->uc_list; + use_uc = true; } ew32(RCTL, rctl); @@ -2389,13 +2392,20 @@ static void e1000_set_rx_mode(struct net_device *netdev) * if there are not 14 addresses, go ahead and clear the filters * -- with 82571 controllers only 0-13 entries are filled here */ + i = 1; + if (use_uc) + list_for_each_entry(ha, &netdev->uc.list, list) { + if (i == rar_entries) + break; + e1000_rar_set(hw, ha->addr, i++); + } + + WARN_ON(i == rar_entries); + mc_ptr = netdev->mc_list; - for (i = 1; i < rar_entries; i++) { - if (uc_ptr) { - e1000_rar_set(hw, uc_ptr->da_addr, i); - uc_ptr = uc_ptr->next; - } else if (mc_ptr) { + for (; i < rar_entries; i++) { + if (mc_ptr) { e1000_rar_set(hw, mc_ptr->da_addr, i); mc_ptr = mc_ptr->next; } else { @@ -2405,7 +2415,6 @@ static void e1000_set_rx_mode(struct net_device *netdev) E1000_WRITE_FLUSH(); } } - WARN_ON(uc_ptr != NULL); /* load any remaining addresses into the hash table */ @@ -2590,7 +2599,6 @@ static void e1000_watchdog(unsigned long data) ew32(TCTL, tctl); netif_carrier_on(netdev); - netif_wake_queue(netdev); mod_timer(&adapter->phy_info_timer, round_jiffies(jiffies + 2 * HZ)); adapter->smartspeed = 0; } else { @@ -2607,7 +2615,6 @@ static void e1000_watchdog(unsigned long data) printk(KERN_INFO "e1000: %s NIC Link is Down\n", netdev->name); netif_carrier_off(netdev); - netif_stop_queue(netdev); mod_timer(&adapter->phy_info_timer, round_jiffies(jiffies + 2 * HZ)); /* 80003ES2LAN workaround-- @@ -2645,6 +2652,8 @@ static void e1000_watchdog(unsigned long data) * (Do the reset outside of interrupt context). */ adapter->tx_timeout_count++; schedule_work(&adapter->reset_task); + /* return immediately since reset is imminent */ + return; } } @@ -2989,7 +2998,7 @@ static int e1000_tx_map(struct e1000_adapter *adapter, size -= 4; buffer_info->length = size; - buffer_info->dma = map[0] + offset; + buffer_info->dma = skb_shinfo(skb)->dma_head + offset; buffer_info->time_stamp = jiffies; buffer_info->next_to_watch = i; @@ -3030,7 +3039,7 @@ static int e1000_tx_map(struct e1000_adapter *adapter, size -= 4; buffer_info->length = size; - buffer_info->dma = map[f + 1] + offset; + buffer_info->dma = map[f] + offset; buffer_info->time_stamp = jiffies; buffer_info->next_to_watch = i; @@ -3362,7 +3371,6 @@ static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) if (count) { e1000_tx_queue(adapter, tx_ring, tx_flags, count); - netdev->trans_start = jiffies; /* Make sure there is space in the ring for the next send. */ e1000_maybe_stop_tx(netdev, tx_ring, MAX_SKB_FRAGS + 2); diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c index 6c01a2072c87..b53b40ba88a8 100644 --- a/drivers/net/e1000e/82571.c +++ b/drivers/net/e1000e/82571.c @@ -71,6 +71,7 @@ static s32 e1000_setup_link_82571(struct e1000_hw *hw); static void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw); static bool e1000_check_mng_mode_82574(struct e1000_hw *hw); static s32 e1000_led_on_82574(struct e1000_hw *hw); +static void e1000_put_hw_semaphore_82571(struct e1000_hw *hw); /** * e1000_init_phy_params_82571 - Init PHY func ptrs. @@ -212,6 +213,9 @@ static s32 e1000_init_mac_params_82571(struct e1000_adapter *adapter) struct e1000_hw *hw = &adapter->hw; struct e1000_mac_info *mac = &hw->mac; struct e1000_mac_operations *func = &mac->ops; + u32 swsm = 0; + u32 swsm2 = 0; + bool force_clear_smbi = false; /* Set media type */ switch (adapter->pdev->device) { @@ -276,6 +280,50 @@ static s32 e1000_init_mac_params_82571(struct e1000_adapter *adapter) break; } + /* + * Ensure that the inter-port SWSM.SMBI lock bit is clear before + * first NVM or PHY acess. This should be done for single-port + * devices, and for one port only on dual-port devices so that + * for those devices we can still use the SMBI lock to synchronize + * inter-port accesses to the PHY & NVM. + */ + switch (hw->mac.type) { + case e1000_82571: + case e1000_82572: + swsm2 = er32(SWSM2); + + if (!(swsm2 & E1000_SWSM2_LOCK)) { + /* Only do this for the first interface on this card */ + ew32(SWSM2, + swsm2 | E1000_SWSM2_LOCK); + force_clear_smbi = true; + } else + force_clear_smbi = false; + break; + default: + force_clear_smbi = true; + break; + } + + if (force_clear_smbi) { + /* Make sure SWSM.SMBI is clear */ + swsm = er32(SWSM); + if (swsm & E1000_SWSM_SMBI) { + /* This bit should not be set on a first interface, and + * indicates that the bootagent or EFI code has + * improperly left this bit enabled + */ + hw_dbg(hw, "Please update your 82571 Bootagent\n"); + } + ew32(SWSM, swsm & ~E1000_SWSM_SMBI); + } + + /* + * Initialze device specific counter of SMBI acquisition + * timeouts. + */ + hw->dev_spec.e82571.smb_counter = 0; + return 0; } @@ -341,8 +389,10 @@ static s32 e1000_get_variants_82571(struct e1000_adapter *adapter) if (e1000_read_nvm(&adapter->hw, NVM_INIT_3GIO_3, 1, &eeprom_data) < 0) break; - if (eeprom_data & NVM_WORD1A_ASPM_MASK) - adapter->flags &= ~FLAG_HAS_JUMBO_FRAMES; + if (!(eeprom_data & NVM_WORD1A_ASPM_MASK)) { + adapter->flags |= FLAG_HAS_JUMBO_FRAMES; + adapter->max_hw_frame_size = DEFAULT_JUMBO; + } } break; default: @@ -411,11 +461,37 @@ static s32 e1000_get_phy_id_82571(struct e1000_hw *hw) static s32 e1000_get_hw_semaphore_82571(struct e1000_hw *hw) { u32 swsm; - s32 timeout = hw->nvm.word_size + 1; + s32 sw_timeout = hw->nvm.word_size + 1; + s32 fw_timeout = hw->nvm.word_size + 1; s32 i = 0; + /* + * If we have timedout 3 times on trying to acquire + * the inter-port SMBI semaphore, there is old code + * operating on the other port, and it is not + * releasing SMBI. Modify the number of times that + * we try for the semaphore to interwork with this + * older code. + */ + if (hw->dev_spec.e82571.smb_counter > 2) + sw_timeout = 1; + + /* Get the SW semaphore */ + while (i < sw_timeout) { + swsm = er32(SWSM); + if (!(swsm & E1000_SWSM_SMBI)) + break; + + udelay(50); + i++; + } + + if (i == sw_timeout) { + hw_dbg(hw, "Driver can't access device - SMBI bit is set.\n"); + hw->dev_spec.e82571.smb_counter++; + } /* Get the FW semaphore. */ - for (i = 0; i < timeout; i++) { + for (i = 0; i < fw_timeout; i++) { swsm = er32(SWSM); ew32(SWSM, swsm | E1000_SWSM_SWESMBI); @@ -426,9 +502,9 @@ static s32 e1000_get_hw_semaphore_82571(struct e1000_hw *hw) udelay(50); } - if (i == timeout) { + if (i == fw_timeout) { /* Release semaphores */ - e1000e_put_hw_semaphore(hw); + e1000_put_hw_semaphore_82571(hw); hw_dbg(hw, "Driver can't access the NVM\n"); return -E1000_ERR_NVM; } @@ -447,9 +523,7 @@ static void e1000_put_hw_semaphore_82571(struct e1000_hw *hw) u32 swsm; swsm = er32(SWSM); - - swsm &= ~E1000_SWSM_SWESMBI; - + swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI); ew32(SWSM, swsm); } @@ -1585,6 +1659,7 @@ static void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw) static struct e1000_mac_operations e82571_mac_ops = { /* .check_mng_mode: mac type dependent */ /* .check_for_link: media type dependent */ + .id_led_init = e1000e_id_led_init, .cleanup_led = e1000e_cleanup_led_generic, .clear_hw_cntrs = e1000_clear_hw_cntrs_82571, .get_bus_info = e1000e_get_bus_info_pcie, @@ -1596,6 +1671,7 @@ static struct e1000_mac_operations e82571_mac_ops = { .init_hw = e1000_init_hw_82571, .setup_link = e1000_setup_link_82571, /* .setup_physical_interface: media type dependent */ + .setup_led = e1000e_setup_led_generic, }; static struct e1000_phy_operations e82_phy_ops_igp = { @@ -1672,6 +1748,7 @@ struct e1000_info e1000_82571_info = { | FLAG_TARC_SPEED_MODE_BIT /* errata */ | FLAG_APME_CHECK_PORT_B, .pba = 38, + .max_hw_frame_size = DEFAULT_JUMBO, .get_variants = e1000_get_variants_82571, .mac_ops = &e82571_mac_ops, .phy_ops = &e82_phy_ops_igp, @@ -1688,6 +1765,7 @@ struct e1000_info e1000_82572_info = { | FLAG_HAS_CTRLEXT_ON_LOAD | FLAG_TARC_SPEED_MODE_BIT, /* errata */ .pba = 38, + .max_hw_frame_size = DEFAULT_JUMBO, .get_variants = e1000_get_variants_82571, .mac_ops = &e82571_mac_ops, .phy_ops = &e82_phy_ops_igp, @@ -1706,6 +1784,7 @@ struct e1000_info e1000_82573_info = { | FLAG_HAS_ERT | FLAG_HAS_SWSM_ON_LOAD, .pba = 20, + .max_hw_frame_size = ETH_FRAME_LEN + ETH_FCS_LEN, .get_variants = e1000_get_variants_82571, .mac_ops = &e82571_mac_ops, .phy_ops = &e82_phy_ops_m88, @@ -1724,6 +1803,7 @@ struct e1000_info e1000_82574_info = { | FLAG_HAS_AMT | FLAG_HAS_CTRLEXT_ON_LOAD, .pba = 20, + .max_hw_frame_size = ETH_FRAME_LEN + ETH_FCS_LEN, .get_variants = e1000_get_variants_82571, .mac_ops = &e82571_mac_ops, .phy_ops = &e82_phy_ops_bm, @@ -1740,6 +1820,7 @@ struct e1000_info e1000_82583_info = { | FLAG_HAS_AMT | FLAG_HAS_CTRLEXT_ON_LOAD, .pba = 20, + .max_hw_frame_size = DEFAULT_JUMBO, .get_variants = e1000_get_variants_82571, .mac_ops = &e82571_mac_ops, .phy_ops = &e82_phy_ops_bm, diff --git a/drivers/net/e1000e/defines.h b/drivers/net/e1000e/defines.h index 243aa499fe90..8890c97e1120 100644 --- a/drivers/net/e1000e/defines.h +++ b/drivers/net/e1000e/defines.h @@ -56,6 +56,7 @@ /* Wake Up Control */ #define E1000_WUC_APME 0x00000001 /* APM Enable */ #define E1000_WUC_PME_EN 0x00000002 /* PME Enable */ +#define E1000_WUC_PHY_WAKE 0x00000100 /* if PHY supports wakeup */ /* Wake Up Filter Control */ #define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */ @@ -65,6 +66,13 @@ #define E1000_WUFC_BC 0x00000010 /* Broadcast Wakeup Enable */ #define E1000_WUFC_ARP 0x00000020 /* ARP Request Packet Wakeup Enable */ +/* Wake Up Status */ +#define E1000_WUS_LNKC E1000_WUFC_LNKC +#define E1000_WUS_MAG E1000_WUFC_MAG +#define E1000_WUS_EX E1000_WUFC_EX +#define E1000_WUS_MC E1000_WUFC_MC +#define E1000_WUS_BC E1000_WUFC_BC + /* Extended Device Control */ #define E1000_CTRL_EXT_SDP7_DATA 0x00000080 /* Value of SW Definable Pin 7 */ #define E1000_CTRL_EXT_EE_RST 0x00002000 /* Reinitialize from EEPROM */ @@ -77,6 +85,7 @@ #define E1000_CTRL_EXT_IAME 0x08000000 /* Interrupt acknowledge Auto-mask */ #define E1000_CTRL_EXT_INT_TIMER_CLR 0x20000000 /* Clear Interrupt timers after IMS clear */ #define E1000_CTRL_EXT_PBA_CLR 0x80000000 /* PBA Clear */ +#define E1000_CTRL_EXT_PHYPDEN 0x00100000 /* Receive Descriptor bit definitions */ #define E1000_RXD_STAT_DD 0x01 /* Descriptor Done */ @@ -140,6 +149,7 @@ #define E1000_RCTL_DTYP_PS 0x00000400 /* Packet Split descriptor */ #define E1000_RCTL_RDMTS_HALF 0x00000000 /* Rx desc min threshold size */ #define E1000_RCTL_MO_SHIFT 12 /* multicast offset shift */ +#define E1000_RCTL_MO_3 0x00003000 /* multicast offset 15:4 */ #define E1000_RCTL_BAM 0x00008000 /* broadcast enable */ /* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */ #define E1000_RCTL_SZ_2048 0x00000000 /* Rx buffer size 2048 */ @@ -153,6 +163,7 @@ #define E1000_RCTL_VFE 0x00040000 /* vlan filter enable */ #define E1000_RCTL_CFIEN 0x00080000 /* canonical form enable */ #define E1000_RCTL_CFI 0x00100000 /* canonical form indicator */ +#define E1000_RCTL_PMCF 0x00800000 /* pass MAC control frames */ #define E1000_RCTL_BSEX 0x02000000 /* Buffer size extension */ #define E1000_RCTL_SECRC 0x04000000 /* Strip Ethernet CRC */ @@ -255,11 +266,16 @@ #define AUTONEG_ADVERTISE_SPEED_DEFAULT E1000_ALL_SPEED_DUPLEX /* LED Control */ +#define E1000_PHY_LED0_MODE_MASK 0x00000007 +#define E1000_PHY_LED0_IVRT 0x00000008 +#define E1000_PHY_LED0_MASK 0x0000001F + #define E1000_LEDCTL_LED0_MODE_MASK 0x0000000F #define E1000_LEDCTL_LED0_MODE_SHIFT 0 #define E1000_LEDCTL_LED0_IVRT 0x00000040 #define E1000_LEDCTL_LED0_BLINK 0x00000080 +#define E1000_LEDCTL_MODE_LINK_UP 0x2 #define E1000_LEDCTL_MODE_LED_ON 0xE #define E1000_LEDCTL_MODE_LED_OFF 0xF @@ -360,6 +376,8 @@ #define E1000_SWSM_SWESMBI 0x00000002 /* FW Semaphore bit */ #define E1000_SWSM_DRV_LOAD 0x00000008 /* Driver Loaded Bit */ +#define E1000_SWSM2_LOCK 0x00000002 /* Secondary driver semaphore bit */ + /* Interrupt Cause Read */ #define E1000_ICR_TXDW 0x00000001 /* Transmit desc written back */ #define E1000_ICR_LSC 0x00000004 /* Link Status Change */ @@ -469,6 +487,8 @@ #define AUTO_READ_DONE_TIMEOUT 10 /* Flow Control */ +#define E1000_FCRTH_RTH 0x0000FFF8 /* Mask Bits[15:3] for RTH */ +#define E1000_FCRTL_RTL 0x0000FFF8 /* Mask Bits[15:3] for RTL */ #define E1000_FCRTL_XONE 0x80000000 /* Enable XON frame transmission */ /* Transmit Configuration Word */ @@ -674,6 +694,8 @@ #define IFE_C_E_PHY_ID 0x02A80310 #define BME1000_E_PHY_ID 0x01410CB0 #define BME1000_E_PHY_ID_R2 0x01410CB1 +#define I82577_E_PHY_ID 0x01540050 +#define I82578_E_PHY_ID 0x004DD040 /* M88E1000 Specific Registers */ #define M88E1000_PHY_SPEC_CTRL 0x10 /* PHY Specific Control Register */ @@ -727,6 +749,9 @@ #define M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK 0x0E00 #define M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X 0x0800 +#define I82578_EPSCR_DOWNSHIFT_ENABLE 0x0020 +#define I82578_EPSCR_DOWNSHIFT_COUNTER_MASK 0x001C + /* BME1000 PHY Specific Control Register */ #define BME1000_PSCR_ENABLE_DOWNSHIFT 0x0800 /* 1 = enable downshift */ diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h index f37360aa12a8..981936c1fb46 100644 --- a/drivers/net/e1000e/e1000.h +++ b/drivers/net/e1000e/e1000.h @@ -62,7 +62,7 @@ struct e1000_info; e_printk(KERN_NOTICE, adapter, format, ## arg) -/* Interrupt modes, as used by the IntMode paramter */ +/* Interrupt modes, as used by the IntMode parameter */ #define E1000E_INT_MODE_LEGACY 0 #define E1000E_INT_MODE_MSI 1 #define E1000E_INT_MODE_MSIX 2 @@ -96,6 +96,51 @@ struct e1000_info; /* Number of packet split data buffers (not including the header buffer) */ #define PS_PAGE_BUFFERS (MAX_PS_BUFFERS - 1) +#define DEFAULT_JUMBO 9234 + +/* BM/HV Specific Registers */ +#define BM_PORT_CTRL_PAGE 769 + +#define PHY_UPPER_SHIFT 21 +#define BM_PHY_REG(page, reg) \ + (((reg) & MAX_PHY_REG_ADDRESS) |\ + (((page) & 0xFFFF) << PHY_PAGE_SHIFT) |\ + (((reg) & ~MAX_PHY_REG_ADDRESS) << (PHY_UPPER_SHIFT - PHY_PAGE_SHIFT))) + +/* PHY Wakeup Registers and defines */ +#define BM_RCTL PHY_REG(BM_WUC_PAGE, 0) +#define BM_WUC PHY_REG(BM_WUC_PAGE, 1) +#define BM_WUFC PHY_REG(BM_WUC_PAGE, 2) +#define BM_WUS PHY_REG(BM_WUC_PAGE, 3) +#define BM_RAR_L(_i) (BM_PHY_REG(BM_WUC_PAGE, 16 + ((_i) << 2))) +#define BM_RAR_M(_i) (BM_PHY_REG(BM_WUC_PAGE, 17 + ((_i) << 2))) +#define BM_RAR_H(_i) (BM_PHY_REG(BM_WUC_PAGE, 18 + ((_i) << 2))) +#define BM_RAR_CTRL(_i) (BM_PHY_REG(BM_WUC_PAGE, 19 + ((_i) << 2))) +#define BM_MTA(_i) (BM_PHY_REG(BM_WUC_PAGE, 128 + ((_i) << 1))) + +#define BM_RCTL_UPE 0x0001 /* Unicast Promiscuous Mode */ +#define BM_RCTL_MPE 0x0002 /* Multicast Promiscuous Mode */ +#define BM_RCTL_MO_SHIFT 3 /* Multicast Offset Shift */ +#define BM_RCTL_MO_MASK (3 << 3) /* Multicast Offset Mask */ +#define BM_RCTL_BAM 0x0020 /* Broadcast Accept Mode */ +#define BM_RCTL_PMCF 0x0040 /* Pass MAC Control Frames */ +#define BM_RCTL_RFCE 0x0080 /* Rx Flow Control Enable */ + +#define HV_SCC_UPPER PHY_REG(778, 16) /* Single Collision Count */ +#define HV_SCC_LOWER PHY_REG(778, 17) +#define HV_ECOL_UPPER PHY_REG(778, 18) /* Excessive Collision Count */ +#define HV_ECOL_LOWER PHY_REG(778, 19) +#define HV_MCC_UPPER PHY_REG(778, 20) /* Multiple Collision Count */ +#define HV_MCC_LOWER PHY_REG(778, 21) +#define HV_LATECOL_UPPER PHY_REG(778, 23) /* Late Collision Count */ +#define HV_LATECOL_LOWER PHY_REG(778, 24) +#define HV_COLC_UPPER PHY_REG(778, 25) /* Collision Count */ +#define HV_COLC_LOWER PHY_REG(778, 26) +#define HV_DC_UPPER PHY_REG(778, 27) /* Defer Count */ +#define HV_DC_LOWER PHY_REG(778, 28) +#define HV_TNCRS_UPPER PHY_REG(778, 29) /* Transmit with no CRS */ +#define HV_TNCRS_LOWER PHY_REG(778, 30) + enum e1000_boards { board_82571, board_82572, @@ -106,6 +151,7 @@ enum e1000_boards { board_ich8lan, board_ich9lan, board_ich10lan, + board_pchlan, }; struct e1000_queue_stats { @@ -293,6 +339,7 @@ struct e1000_adapter { u32 eeprom_wol; u32 wol; u32 pba; + u32 max_hw_frame_size; bool fc_autoneg; @@ -302,6 +349,7 @@ struct e1000_adapter { unsigned int flags2; struct work_struct downshift_task; struct work_struct update_phy_task; + struct work_struct led_blink_task; }; struct e1000_info { @@ -309,6 +357,7 @@ struct e1000_info { unsigned int flags; unsigned int flags2; u32 pba; + u32 max_hw_frame_size; s32 (*get_variants)(struct e1000_adapter *); struct e1000_mac_operations *mac_ops; struct e1000_phy_operations *phy_ops; @@ -351,6 +400,7 @@ struct e1000_info { /* CRC Stripping defines */ #define FLAG2_CRC_STRIPPING (1 << 0) +#define FLAG2_HAS_PHY_WAKEUP (1 << 1) #define E1000_RX_DESC_PS(R, i) \ (&(((union e1000_rx_desc_packet_split *)((R).desc))[i])) @@ -404,6 +454,7 @@ extern struct e1000_info e1000_82583_info; extern struct e1000_info e1000_ich8_info; extern struct e1000_info e1000_ich9_info; extern struct e1000_info e1000_ich10_info; +extern struct e1000_info e1000_pch_info; extern struct e1000_info e1000_es2_info; extern s32 e1000e_read_pba_num(struct e1000_hw *hw, u32 *pba_num); @@ -425,6 +476,7 @@ extern void e1000e_disable_gig_wol_ich8lan(struct e1000_hw *hw); extern s32 e1000e_check_for_copper_link(struct e1000_hw *hw); extern s32 e1000e_check_for_fiber_link(struct e1000_hw *hw); extern s32 e1000e_check_for_serdes_link(struct e1000_hw *hw); +extern s32 e1000e_setup_led_generic(struct e1000_hw *hw); extern s32 e1000e_cleanup_led_generic(struct e1000_hw *hw); extern s32 e1000e_led_on_generic(struct e1000_hw *hw); extern s32 e1000e_led_off_generic(struct e1000_hw *hw); @@ -493,6 +545,15 @@ extern s32 e1000e_phy_reset_dsp(struct e1000_hw *hw); extern s32 e1000e_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data); extern s32 e1000e_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data); extern s32 e1000e_check_downshift(struct e1000_hw *hw); +extern s32 e1000_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data); +extern s32 e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data); +extern s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw, bool slow); +extern s32 e1000_link_stall_workaround_hv(struct e1000_hw *hw); +extern s32 e1000_copper_link_setup_82577(struct e1000_hw *hw); +extern s32 e1000_check_polarity_82577(struct e1000_hw *hw); +extern s32 e1000_get_phy_info_82577(struct e1000_hw *hw); +extern s32 e1000_phy_force_speed_duplex_82577(struct e1000_hw *hw); +extern s32 e1000_get_cable_length_82577(struct e1000_hw *hw); static inline s32 e1000_phy_hw_reset(struct e1000_hw *hw) { diff --git a/drivers/net/e1000e/es2lan.c b/drivers/net/e1000e/es2lan.c index 8964838c686b..ae5d73689353 100644 --- a/drivers/net/e1000e/es2lan.c +++ b/drivers/net/e1000e/es2lan.c @@ -1366,6 +1366,7 @@ static void e1000_clear_hw_cntrs_80003es2lan(struct e1000_hw *hw) } static struct e1000_mac_operations es2_mac_ops = { + .id_led_init = e1000e_id_led_init, .check_mng_mode = e1000e_check_mng_mode_generic, /* check_for_link dependent on media type */ .cleanup_led = e1000e_cleanup_led_generic, @@ -1379,6 +1380,7 @@ static struct e1000_mac_operations es2_mac_ops = { .init_hw = e1000_init_hw_80003es2lan, .setup_link = e1000e_setup_link, /* setup_physical_interface dependent on media type */ + .setup_led = e1000e_setup_led_generic, }; static struct e1000_phy_operations es2_phy_ops = { @@ -1422,6 +1424,7 @@ struct e1000_info e1000_es2_info = { | FLAG_DISABLE_FC_PAUSE_TIME /* errata */ | FLAG_TIPG_MEDIUM_FOR_80003ESLAN, .pba = 38, + .max_hw_frame_size = DEFAULT_JUMBO, .get_variants = e1000_get_variants_80003es2lan, .mac_ops = &es2_mac_ops, .phy_ops = &es2_phy_ops, diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c index 4d25ede88369..1bf4d2a5d34f 100644 --- a/drivers/net/e1000e/ethtool.c +++ b/drivers/net/e1000e/ethtool.c @@ -167,6 +167,15 @@ static int e1000_get_settings(struct net_device *netdev, ecmd->autoneg = ((hw->phy.media_type == e1000_media_type_fiber) || hw->mac.autoneg) ? AUTONEG_ENABLE : AUTONEG_DISABLE; + + /* MDI-X => 2; MDI =>1; Invalid =>0 */ + if ((hw->phy.media_type == e1000_media_type_copper) && + !hw->mac.get_link_status) + ecmd->eth_tp_mdix = hw->phy.is_mdix ? ETH_TP_MDI_X : + ETH_TP_MDI; + else + ecmd->eth_tp_mdix = ETH_TP_MDI_INVALID; + return 0; } @@ -776,6 +785,7 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data) u32 after; u32 i; u32 toggle; + u32 mask; /* * The status register is Read Only, so a write should fail. @@ -788,17 +798,9 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data) case e1000_80003es2lan: toggle = 0x7FFFF3FF; break; - case e1000_82573: - case e1000_82574: - case e1000_82583: - case e1000_ich8lan: - case e1000_ich9lan: - case e1000_ich10lan: + default: toggle = 0x7FFFF033; break; - default: - toggle = 0xFFFFF833; - break; } before = er32(STATUS); @@ -844,11 +846,18 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data) REG_PATTERN_TEST(E1000_TXCW, 0xC000FFFF, 0x0000FFFF); REG_PATTERN_TEST(E1000_TDBAL, 0xFFFFFFF0, 0xFFFFFFFF); REG_PATTERN_TEST(E1000_TIDV, 0x0000FFFF, 0x0000FFFF); + mask = 0x8003FFFF; + switch (mac->type) { + case e1000_ich10lan: + case e1000_pchlan: + mask |= (1 << 18); + break; + default: + break; + } for (i = 0; i < mac->rar_entry_count; i++) REG_PATTERN_TEST_ARRAY(E1000_RA, ((i << 1) + 1), - ((mac->type == e1000_ich10lan) ? - 0x8007FFFF : 0x8003FFFF), - 0xFFFFFFFF); + mask, 0xFFFFFFFF); for (i = 0; i < mac->mta_reg_count; i++) REG_PATTERN_TEST_ARRAY(E1000_MTA, i, 0xFFFFFFFF, 0xFFFFFFFF); @@ -1786,15 +1795,22 @@ static int e1000_set_wol(struct net_device *netdev, /* bit defines for adapter->led_status */ #define E1000_LED_ON 0 -static void e1000_led_blink_callback(unsigned long data) +static void e1000e_led_blink_task(struct work_struct *work) { - struct e1000_adapter *adapter = (struct e1000_adapter *) data; + struct e1000_adapter *adapter = container_of(work, + struct e1000_adapter, led_blink_task); if (test_and_change_bit(E1000_LED_ON, &adapter->led_status)) adapter->hw.mac.ops.led_off(&adapter->hw); else adapter->hw.mac.ops.led_on(&adapter->hw); +} +static void e1000_led_blink_callback(unsigned long data) +{ + struct e1000_adapter *adapter = (struct e1000_adapter *) data; + + schedule_work(&adapter->led_blink_task); mod_timer(&adapter->blink_timer, jiffies + E1000_ID_INTERVAL); } @@ -1807,7 +1823,9 @@ static int e1000_phys_id(struct net_device *netdev, u32 data) data = INT_MAX; if ((hw->phy.type == e1000_phy_ife) || + (hw->mac.type == e1000_pchlan) || (hw->mac.type == e1000_82574)) { + INIT_WORK(&adapter->led_blink_task, e1000e_led_blink_task); if (!adapter->blink_timer.function) { init_timer(&adapter->blink_timer); adapter->blink_timer.function = diff --git a/drivers/net/e1000e/hw.h b/drivers/net/e1000e/hw.h index d8b82296f41e..163c1c0cfee7 100644 --- a/drivers/net/e1000e/hw.h +++ b/drivers/net/e1000e/hw.h @@ -193,7 +193,11 @@ enum e1e_registers { E1000_RXCSUM = 0x05000, /* Rx Checksum Control - RW */ E1000_RFCTL = 0x05008, /* Receive Filter Control */ E1000_MTA = 0x05200, /* Multicast Table Array - RW Array */ - E1000_RA = 0x05400, /* Receive Address - RW Array */ + E1000_RAL_BASE = 0x05400, /* Receive Address Low - RW */ +#define E1000_RAL(_n) (E1000_RAL_BASE + ((_n) * 8)) +#define E1000_RA (E1000_RAL(0)) + E1000_RAH_BASE = 0x05404, /* Receive Address High - RW */ +#define E1000_RAH(_n) (E1000_RAH_BASE + ((_n) * 8)) E1000_VFTA = 0x05600, /* VLAN Filter Table Array - RW Array */ E1000_WUC = 0x05800, /* Wakeup Control - RW */ E1000_WUFC = 0x05808, /* Wakeup Filter Control - RW */ @@ -210,6 +214,7 @@ enum e1e_registers { E1000_FACTPS = 0x05B30, /* Function Active and Power State to MNG */ E1000_SWSM = 0x05B50, /* SW Semaphore */ E1000_FWSM = 0x05B54, /* FW Semaphore */ + E1000_SWSM2 = 0x05B58, /* Driver-only SW semaphore */ E1000_HICR = 0x08F00, /* Host Interface Control */ }; @@ -253,7 +258,7 @@ enum e1e_registers { #define IGP01E1000_PLHR_SS_DOWNGRADE 0x8000 #define IGP01E1000_PSSR_POLARITY_REVERSED 0x0002 -#define IGP01E1000_PSSR_MDIX 0x0008 +#define IGP01E1000_PSSR_MDIX 0x0800 #define IGP01E1000_PSSR_SPEED_MASK 0xC000 #define IGP01E1000_PSSR_SPEED_1000MBPS 0xC000 @@ -368,6 +373,10 @@ enum e1e_registers { #define E1000_DEV_ID_ICH10_R_BM_V 0x10CE #define E1000_DEV_ID_ICH10_D_BM_LM 0x10DE #define E1000_DEV_ID_ICH10_D_BM_LF 0x10DF +#define E1000_DEV_ID_PCH_M_HV_LM 0x10EA +#define E1000_DEV_ID_PCH_M_HV_LC 0x10EB +#define E1000_DEV_ID_PCH_D_HV_DM 0x10EF +#define E1000_DEV_ID_PCH_D_HV_DC 0x10F0 #define E1000_REVISION_4 4 @@ -383,6 +392,7 @@ enum e1000_mac_type { e1000_ich8lan, e1000_ich9lan, e1000_ich10lan, + e1000_pchlan, }; enum e1000_media_type { @@ -417,6 +427,8 @@ enum e1000_phy_type { e1000_phy_igp_3, e1000_phy_ife, e1000_phy_bm, + e1000_phy_82578, + e1000_phy_82577, }; enum e1000_bus_width { @@ -720,6 +732,7 @@ struct e1000_host_mng_command_info { /* Function pointers and static data for the MAC. */ struct e1000_mac_operations { + s32 (*id_led_init)(struct e1000_hw *); bool (*check_mng_mode)(struct e1000_hw *); s32 (*check_for_link)(struct e1000_hw *); s32 (*cleanup_led)(struct e1000_hw *); @@ -733,11 +746,13 @@ struct e1000_mac_operations { s32 (*init_hw)(struct e1000_hw *); s32 (*setup_link)(struct e1000_hw *); s32 (*setup_physical_interface)(struct e1000_hw *); + s32 (*setup_led)(struct e1000_hw *); }; /* Function pointers for the PHY. */ struct e1000_phy_operations { s32 (*acquire_phy)(struct e1000_hw *); + s32 (*check_polarity)(struct e1000_hw *); s32 (*check_reset_block)(struct e1000_hw *); s32 (*commit_phy)(struct e1000_hw *); s32 (*force_speed_duplex)(struct e1000_hw *); @@ -869,6 +884,7 @@ struct e1000_fc_info { struct e1000_dev_spec_82571 { bool laa_is_present; bool alt_mac_addr_is_present; + u32 smb_counter; }; struct e1000_shadow_ram { diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c index 6d1aab6316ba..9e23f50fb9cd 100644 --- a/drivers/net/e1000e/ich8lan.c +++ b/drivers/net/e1000e/ich8lan.c @@ -48,6 +48,10 @@ * 82567LF-3 Gigabit Network Connection * 82567LM-3 Gigabit Network Connection * 82567LM-4 Gigabit Network Connection + * 82577LM Gigabit Network Connection + * 82577LC Gigabit Network Connection + * 82578DM Gigabit Network Connection + * 82578DC Gigabit Network Connection */ #include @@ -116,6 +120,8 @@ #define IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK 0x0300 #define IGP3_VR_CTRL_MODE_SHUTDOWN 0x0200 +#define HV_LED_CONFIG PHY_REG(768, 30) /* LED Configuration */ + /* ICH GbE Flash Hardware Sequencing Flash Status Register bit breakdown */ /* Offset 04h HSFSTS */ union ich8_hws_flash_status { @@ -186,6 +192,14 @@ static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset, static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw); static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw); static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw); +static s32 e1000_cleanup_led_ich8lan(struct e1000_hw *hw); +static s32 e1000_led_on_ich8lan(struct e1000_hw *hw); +static s32 e1000_led_off_ich8lan(struct e1000_hw *hw); +static s32 e1000_id_led_init_pchlan(struct e1000_hw *hw); +static s32 e1000_setup_led_pchlan(struct e1000_hw *hw); +static s32 e1000_cleanup_led_pchlan(struct e1000_hw *hw); +static s32 e1000_led_on_pchlan(struct e1000_hw *hw); +static s32 e1000_led_off_pchlan(struct e1000_hw *hw); static inline u16 __er16flash(struct e1000_hw *hw, unsigned long reg) { @@ -212,6 +226,41 @@ static inline void __ew32flash(struct e1000_hw *hw, unsigned long reg, u32 val) #define ew16flash(reg,val) __ew16flash(hw, (reg), (val)) #define ew32flash(reg,val) __ew32flash(hw, (reg), (val)) +/** + * e1000_init_phy_params_pchlan - Initialize PHY function pointers + * @hw: pointer to the HW structure + * + * Initialize family-specific PHY parameters and function pointers. + **/ +static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val = 0; + + phy->addr = 1; + phy->reset_delay_us = 100; + + phy->ops.check_polarity = e1000_check_polarity_ife_ich8lan; + phy->ops.read_phy_reg = e1000_read_phy_reg_hv; + phy->ops.write_phy_reg = e1000_write_phy_reg_hv; + phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; + + phy->id = e1000_phy_unknown; + e1000e_get_phy_id(hw); + phy->type = e1000e_get_phy_type_from_id(phy->id); + + if (phy->type == e1000_phy_82577) { + phy->ops.check_polarity = e1000_check_polarity_82577; + phy->ops.force_speed_duplex = + e1000_phy_force_speed_duplex_82577; + phy->ops.get_cable_length = e1000_get_cable_length_82577; + phy->ops.get_phy_info = e1000_get_phy_info_82577; + phy->ops.commit_phy = e1000e_phy_sw_reset; + } + + return ret_val; +} + /** * e1000_init_phy_params_ich8lan - Initialize PHY function pointers * @hw: pointer to the HW structure @@ -273,6 +322,8 @@ static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw) break; } + phy->ops.check_polarity = e1000_check_polarity_ife_ich8lan; + return 0; } @@ -358,6 +409,36 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_adapter *adapter) /* Set if manageability features are enabled. */ mac->arc_subsystem_valid = 1; + /* LED operations */ + switch (mac->type) { + case e1000_ich8lan: + case e1000_ich9lan: + case e1000_ich10lan: + /* ID LED init */ + mac->ops.id_led_init = e1000e_id_led_init; + /* setup LED */ + mac->ops.setup_led = e1000e_setup_led_generic; + /* cleanup LED */ + mac->ops.cleanup_led = e1000_cleanup_led_ich8lan; + /* turn on/off LED */ + mac->ops.led_on = e1000_led_on_ich8lan; + mac->ops.led_off = e1000_led_off_ich8lan; + break; + case e1000_pchlan: + /* ID LED init */ + mac->ops.id_led_init = e1000_id_led_init_pchlan; + /* setup LED */ + mac->ops.setup_led = e1000_setup_led_pchlan; + /* cleanup LED */ + mac->ops.cleanup_led = e1000_cleanup_led_pchlan; + /* turn on/off LED */ + mac->ops.led_on = e1000_led_on_pchlan; + mac->ops.led_off = e1000_led_off_pchlan; + break; + default: + break; + } + /* Enable PCS Lock-loss workaround for ICH8 */ if (mac->type == e1000_ich8lan) e1000e_set_kmrn_lock_loss_workaround_ich8lan(hw, 1); @@ -378,10 +459,18 @@ static s32 e1000_get_variants_ich8lan(struct e1000_adapter *adapter) if (rc) return rc; - rc = e1000_init_phy_params_ich8lan(hw); + if (hw->mac.type == e1000_pchlan) + rc = e1000_init_phy_params_pchlan(hw); + else + rc = e1000_init_phy_params_ich8lan(hw); if (rc) return rc; + if (adapter->hw.phy.type == e1000_phy_ife) { + adapter->flags &= ~FLAG_HAS_JUMBO_FRAMES; + adapter->max_hw_frame_size = ETH_FRAME_LEN + ETH_FCS_LEN; + } + if ((adapter->hw.mac.type == e1000_ich8lan) && (adapter->hw.phy.type == e1000_phy_igp_3)) adapter->flags |= FLAG_LSC_GIG_SPEED_DROP; @@ -410,12 +499,15 @@ static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw) while (timeout) { extcnf_ctrl = er32(EXTCNF_CTRL); - extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG; - ew32(EXTCNF_CTRL, extcnf_ctrl); - extcnf_ctrl = er32(EXTCNF_CTRL); - if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG) - break; + if (!(extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG)) { + extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG; + ew32(EXTCNF_CTRL, extcnf_ctrl); + + extcnf_ctrl = er32(EXTCNF_CTRL); + if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG) + break; + } mdelay(1); timeout--; } @@ -554,6 +646,53 @@ static s32 e1000_phy_force_speed_duplex_ich8lan(struct e1000_hw *hw) return 0; } +/** + * e1000_hv_phy_workarounds_ich8lan - A series of Phy workarounds to be + * done after every PHY reset. + **/ +static s32 e1000_hv_phy_workarounds_ich8lan(struct e1000_hw *hw) +{ + s32 ret_val = 0; + + if (hw->mac.type != e1000_pchlan) + return ret_val; + + if (((hw->phy.type == e1000_phy_82577) && + ((hw->phy.revision == 1) || (hw->phy.revision == 2))) || + ((hw->phy.type == e1000_phy_82578) && (hw->phy.revision == 1))) { + /* Disable generation of early preamble */ + ret_val = e1e_wphy(hw, PHY_REG(769, 25), 0x4431); + if (ret_val) + return ret_val; + + /* Preamble tuning for SSC */ + ret_val = e1e_wphy(hw, PHY_REG(770, 16), 0xA204); + if (ret_val) + return ret_val; + } + + if (hw->phy.type == e1000_phy_82578) { + /* + * Return registers to default by doing a soft reset then + * writing 0x3140 to the control register. + */ + if (hw->phy.revision < 2) { + e1000e_phy_sw_reset(hw); + ret_val = e1e_wphy(hw, PHY_CONTROL, 0x3140); + } + } + + /* Select page 0 */ + ret_val = hw->phy.ops.acquire_phy(hw); + if (ret_val) + return ret_val; + hw->phy.addr = 1; + e1000e_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, 0); + hw->phy.ops.release_phy(hw); + + return ret_val; +} + /** * e1000_phy_hw_reset_ich8lan - Performs a PHY reset * @hw: pointer to the HW structure @@ -575,6 +714,12 @@ static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw) if (ret_val) return ret_val; + if (hw->mac.type == e1000_pchlan) { + ret_val = e1000_hv_phy_workarounds_ich8lan(hw); + if (ret_val) + return ret_val; + } + /* * Initialize the PHY from the NVM on ICH platforms. This * is needed due to an issue where the NVM configuration is @@ -701,7 +846,7 @@ static s32 e1000_get_phy_info_ife_ich8lan(struct e1000_hw *hw) phy->polarity_correction = (!(data & IFE_PSC_AUTO_POLARITY_DISABLE)); if (phy->polarity_correction) { - ret_val = e1000_check_polarity_ife_ich8lan(hw); + ret_val = phy->ops.check_polarity(hw); if (ret_val) return ret_val; } else { @@ -741,6 +886,8 @@ static s32 e1000_get_phy_info_ich8lan(struct e1000_hw *hw) break; case e1000_phy_igp_3: case e1000_phy_bm: + case e1000_phy_82578: + case e1000_phy_82577: return e1000e_get_phy_info_igp(hw); break; default: @@ -1851,6 +1998,79 @@ static s32 e1000_valid_led_default_ich8lan(struct e1000_hw *hw, u16 *data) return 0; } +/** + * e1000_id_led_init_pchlan - store LED configurations + * @hw: pointer to the HW structure + * + * PCH does not control LEDs via the LEDCTL register, rather it uses + * the PHY LED configuration register. + * + * PCH also does not have an "always on" or "always off" mode which + * complicates the ID feature. Instead of using the "on" mode to indicate + * in ledctl_mode2 the LEDs to use for ID (see e1000e_id_led_init()), + * use "link_up" mode. The LEDs will still ID on request if there is no + * link based on logic in e1000_led_[on|off]_pchlan(). + **/ +static s32 e1000_id_led_init_pchlan(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + s32 ret_val; + const u32 ledctl_on = E1000_LEDCTL_MODE_LINK_UP; + const u32 ledctl_off = E1000_LEDCTL_MODE_LINK_UP | E1000_PHY_LED0_IVRT; + u16 data, i, temp, shift; + + /* Get default ID LED modes */ + ret_val = hw->nvm.ops.valid_led_default(hw, &data); + if (ret_val) + goto out; + + mac->ledctl_default = er32(LEDCTL); + mac->ledctl_mode1 = mac->ledctl_default; + mac->ledctl_mode2 = mac->ledctl_default; + + for (i = 0; i < 4; i++) { + temp = (data >> (i << 2)) & E1000_LEDCTL_LED0_MODE_MASK; + shift = (i * 5); + switch (temp) { + case ID_LED_ON1_DEF2: + case ID_LED_ON1_ON2: + case ID_LED_ON1_OFF2: + mac->ledctl_mode1 &= ~(E1000_PHY_LED0_MASK << shift); + mac->ledctl_mode1 |= (ledctl_on << shift); + break; + case ID_LED_OFF1_DEF2: + case ID_LED_OFF1_ON2: + case ID_LED_OFF1_OFF2: + mac->ledctl_mode1 &= ~(E1000_PHY_LED0_MASK << shift); + mac->ledctl_mode1 |= (ledctl_off << shift); + break; + default: + /* Do nothing */ + break; + } + switch (temp) { + case ID_LED_DEF1_ON2: + case ID_LED_ON1_ON2: + case ID_LED_OFF1_ON2: + mac->ledctl_mode2 &= ~(E1000_PHY_LED0_MASK << shift); + mac->ledctl_mode2 |= (ledctl_on << shift); + break; + case ID_LED_DEF1_OFF2: + case ID_LED_ON1_OFF2: + case ID_LED_OFF1_OFF2: + mac->ledctl_mode2 &= ~(E1000_PHY_LED0_MASK << shift); + mac->ledctl_mode2 |= (ledctl_off << shift); + break; + default: + /* Do nothing */ + break; + } + } + +out: + return ret_val; +} + /** * e1000_get_bus_info_ich8lan - Get/Set the bus type and width * @hw: pointer to the HW structure @@ -1960,6 +2180,9 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw) kab |= E1000_KABGTXD_BGSQLBIAS; ew32(KABGTXD, kab); + if (hw->mac.type == e1000_pchlan) + ret_val = e1000_hv_phy_workarounds_ich8lan(hw); + return ret_val; } @@ -1985,7 +2208,7 @@ static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw) e1000_initialize_hw_bits_ich8lan(hw); /* Initialize identification LED */ - ret_val = e1000e_id_led_init(hw); + ret_val = mac->ops.id_led_init(hw); if (ret_val) { hw_dbg(hw, "Error initializing identification LED\n"); return ret_val; @@ -2030,6 +2253,16 @@ static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw) ctrl_ext |= E1000_CTRL_EXT_RO_DIS; ew32(CTRL_EXT, ctrl_ext); + /* + * The 82578 Rx buffer will stall if wakeup is enabled in host and + * the ME. Reading the BM_WUC register will clear the host wakeup bit. + * Reset the phy after disabling host wakeup to reset the Rx buffer. + */ + if (hw->phy.type == e1000_phy_82578) { + e1e_rphy(hw, BM_WUC, &i); + e1000e_phy_hw_reset_generic(hw); + } + /* * Clear all of the statistics registers (clear on read). It is * important that we do this after we have tried to establish link @@ -2054,6 +2287,9 @@ static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw) /* Extended Device Control */ reg = er32(CTRL_EXT); reg |= (1 << 22); + /* Enable PHY low-power state when MAC is at D3 w/o WoL */ + if (hw->mac.type >= e1000_pchlan) + reg |= E1000_CTRL_EXT_PHYPDEN; ew32(CTRL_EXT, reg); /* Transmit Descriptor Control 0 */ @@ -2112,8 +2348,13 @@ static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw) * the default flow control setting, so we explicitly * set it to full. */ - if (hw->fc.requested_mode == e1000_fc_default) - hw->fc.requested_mode = e1000_fc_full; + if (hw->fc.requested_mode == e1000_fc_default) { + /* Workaround h/w hang when Tx flow control enabled */ + if (hw->mac.type == e1000_pchlan) + hw->fc.requested_mode = e1000_fc_rx_pause; + else + hw->fc.requested_mode = e1000_fc_full; + } /* * Save off the requested flow control mode for use later. Depending @@ -2130,6 +2371,14 @@ static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw) return ret_val; ew32(FCTTV, hw->fc.pause_time); + if ((hw->phy.type == e1000_phy_82578) || + (hw->phy.type == e1000_phy_82577)) { + ret_val = hw->phy.ops.write_phy_reg(hw, + PHY_REG(BM_PORT_CTRL_PAGE, 27), + hw->fc.pause_time); + if (ret_val) + return ret_val; + } return e1000e_set_fc_watermarks(hw); } @@ -2169,18 +2418,26 @@ static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw) if (ret_val) return ret_val; - if (hw->phy.type == e1000_phy_igp_3) { + switch (hw->phy.type) { + case e1000_phy_igp_3: ret_val = e1000e_copper_link_setup_igp(hw); if (ret_val) return ret_val; - } else if (hw->phy.type == e1000_phy_bm) { + break; + case e1000_phy_bm: + case e1000_phy_82578: ret_val = e1000e_copper_link_setup_m88(hw); if (ret_val) return ret_val; - } - - if (hw->phy.type == e1000_phy_ife) { - ret_val = e1e_rphy(hw, IFE_PHY_MDIX_CONTROL, ®_data); + break; + case e1000_phy_82577: + ret_val = e1000_copper_link_setup_82577(hw); + if (ret_val) + return ret_val; + break; + case e1000_phy_ife: + ret_val = hw->phy.ops.read_phy_reg(hw, IFE_PHY_MDIX_CONTROL, + ®_data); if (ret_val) return ret_val; @@ -2198,9 +2455,13 @@ static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw) reg_data |= IFE_PMC_AUTO_MDIX; break; } - ret_val = e1e_wphy(hw, IFE_PHY_MDIX_CONTROL, reg_data); + ret_val = hw->phy.ops.write_phy_reg(hw, IFE_PHY_MDIX_CONTROL, + reg_data); if (ret_val) return ret_val; + break; + default: + break; } return e1000e_setup_copper_link(hw); } @@ -2417,18 +2678,26 @@ void e1000e_gig_downshift_workaround_ich8lan(struct e1000_hw *hw) * 'LPLU Enabled' and 'Gig Disable' to force link speed negotiation * to a lower speed. * - * Should only be called for ICH9 and ICH10 devices. + * Should only be called for applicable parts. **/ void e1000e_disable_gig_wol_ich8lan(struct e1000_hw *hw) { u32 phy_ctrl; - if ((hw->mac.type == e1000_ich10lan) || - (hw->mac.type == e1000_ich9lan)) { + switch (hw->mac.type) { + case e1000_ich9lan: + case e1000_ich10lan: + case e1000_pchlan: phy_ctrl = er32(PHY_CTRL); phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU | E1000_PHY_CTRL_GBE_DISABLE; ew32(PHY_CTRL, phy_ctrl); + + /* Workaround SWFLAG unexpectedly set during S0->Sx */ + if (hw->mac.type == e1000_pchlan) + udelay(500); + default: + break; } return; @@ -2481,6 +2750,92 @@ static s32 e1000_led_off_ich8lan(struct e1000_hw *hw) return 0; } +/** + * e1000_setup_led_pchlan - Configures SW controllable LED + * @hw: pointer to the HW structure + * + * This prepares the SW controllable LED for use. + **/ +static s32 e1000_setup_led_pchlan(struct e1000_hw *hw) +{ + return hw->phy.ops.write_phy_reg(hw, HV_LED_CONFIG, + (u16)hw->mac.ledctl_mode1); +} + +/** + * e1000_cleanup_led_pchlan - Restore the default LED operation + * @hw: pointer to the HW structure + * + * Return the LED back to the default configuration. + **/ +static s32 e1000_cleanup_led_pchlan(struct e1000_hw *hw) +{ + return hw->phy.ops.write_phy_reg(hw, HV_LED_CONFIG, + (u16)hw->mac.ledctl_default); +} + +/** + * e1000_led_on_pchlan - Turn LEDs on + * @hw: pointer to the HW structure + * + * Turn on the LEDs. + **/ +static s32 e1000_led_on_pchlan(struct e1000_hw *hw) +{ + u16 data = (u16)hw->mac.ledctl_mode2; + u32 i, led; + + /* + * If no link, then turn LED on by setting the invert bit + * for each LED that's mode is "link_up" in ledctl_mode2. + */ + if (!(er32(STATUS) & E1000_STATUS_LU)) { + for (i = 0; i < 3; i++) { + led = (data >> (i * 5)) & E1000_PHY_LED0_MASK; + if ((led & E1000_PHY_LED0_MODE_MASK) != + E1000_LEDCTL_MODE_LINK_UP) + continue; + if (led & E1000_PHY_LED0_IVRT) + data &= ~(E1000_PHY_LED0_IVRT << (i * 5)); + else + data |= (E1000_PHY_LED0_IVRT << (i * 5)); + } + } + + return hw->phy.ops.write_phy_reg(hw, HV_LED_CONFIG, data); +} + +/** + * e1000_led_off_pchlan - Turn LEDs off + * @hw: pointer to the HW structure + * + * Turn off the LEDs. + **/ +static s32 e1000_led_off_pchlan(struct e1000_hw *hw) +{ + u16 data = (u16)hw->mac.ledctl_mode1; + u32 i, led; + + /* + * If no link, then turn LED off by clearing the invert bit + * for each LED that's mode is "link_up" in ledctl_mode1. + */ + if (!(er32(STATUS) & E1000_STATUS_LU)) { + for (i = 0; i < 3; i++) { + led = (data >> (i * 5)) & E1000_PHY_LED0_MASK; + if ((led & E1000_PHY_LED0_MODE_MASK) != + E1000_LEDCTL_MODE_LINK_UP) + continue; + if (led & E1000_PHY_LED0_IVRT) + data &= ~(E1000_PHY_LED0_IVRT << (i * 5)); + else + data |= (E1000_PHY_LED0_IVRT << (i * 5)); + } + } + + return hw->phy.ops.write_phy_reg(hw, HV_LED_CONFIG, data); +} + /** * e1000_get_cfg_done_ich8lan - Read config done bit * @hw: pointer to the HW structure @@ -2488,7 +2843,7 @@ static s32 e1000_led_off_ich8lan(struct e1000_hw *hw) * Read the management control register for the config done bit for * completion status. NOTE: silicon which is EEPROM-less will fail trying * to read the config done bit, so an error is *ONLY* logged and returns - * E1000_SUCCESS. If we were to return with error, EEPROM-less silicon + * 0. If we were to return with error, EEPROM-less silicon * would not be able to be reset or change link. **/ static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw) @@ -2498,7 +2853,8 @@ static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw) e1000e_get_cfg_done(hw); /* If EEPROM is not marked present, init the IGP 3 PHY manually */ - if (hw->mac.type != e1000_ich10lan) { + if ((hw->mac.type != e1000_ich10lan) && + (hw->mac.type != e1000_pchlan)) { if (((er32(EECD) & E1000_EECD_PRES) == 0) && (hw->phy.type == e1000_phy_igp_3)) { e1000e_phy_init_script_igp3(hw); @@ -2524,6 +2880,7 @@ static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw) static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw) { u32 temp; + u16 phy_data; e1000e_clear_hw_cntrs_base(hw); @@ -2541,22 +2898,42 @@ static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw) temp = er32(IAC); temp = er32(ICRXOC); + /* Clear PHY statistics registers */ + if ((hw->phy.type == e1000_phy_82578) || + (hw->phy.type == e1000_phy_82577)) { + hw->phy.ops.read_phy_reg(hw, HV_SCC_UPPER, &phy_data); + hw->phy.ops.read_phy_reg(hw, HV_SCC_LOWER, &phy_data); + hw->phy.ops.read_phy_reg(hw, HV_ECOL_UPPER, &phy_data); + hw->phy.ops.read_phy_reg(hw, HV_ECOL_LOWER, &phy_data); + hw->phy.ops.read_phy_reg(hw, HV_MCC_UPPER, &phy_data); + hw->phy.ops.read_phy_reg(hw, HV_MCC_LOWER, &phy_data); + hw->phy.ops.read_phy_reg(hw, HV_LATECOL_UPPER, &phy_data); + hw->phy.ops.read_phy_reg(hw, HV_LATECOL_LOWER, &phy_data); + hw->phy.ops.read_phy_reg(hw, HV_COLC_UPPER, &phy_data); + hw->phy.ops.read_phy_reg(hw, HV_COLC_LOWER, &phy_data); + hw->phy.ops.read_phy_reg(hw, HV_DC_UPPER, &phy_data); + hw->phy.ops.read_phy_reg(hw, HV_DC_LOWER, &phy_data); + hw->phy.ops.read_phy_reg(hw, HV_TNCRS_UPPER, &phy_data); + hw->phy.ops.read_phy_reg(hw, HV_TNCRS_LOWER, &phy_data); + } } static struct e1000_mac_operations ich8_mac_ops = { + .id_led_init = e1000e_id_led_init, .check_mng_mode = e1000_check_mng_mode_ich8lan, .check_for_link = e1000e_check_for_copper_link, - .cleanup_led = e1000_cleanup_led_ich8lan, + /* cleanup_led dependent on mac type */ .clear_hw_cntrs = e1000_clear_hw_cntrs_ich8lan, .get_bus_info = e1000_get_bus_info_ich8lan, .get_link_up_info = e1000_get_link_up_info_ich8lan, - .led_on = e1000_led_on_ich8lan, - .led_off = e1000_led_off_ich8lan, + /* led_on dependent on mac type */ + /* led_off dependent on mac type */ .update_mc_addr_list = e1000e_update_mc_addr_list_generic, .reset_hw = e1000_reset_hw_ich8lan, .init_hw = e1000_init_hw_ich8lan, .setup_link = e1000_setup_link_ich8lan, .setup_physical_interface= e1000_setup_copper_link_ich8lan, + /* id_led_init dependent on mac type */ }; static struct e1000_phy_operations ich8_phy_ops = { @@ -2595,6 +2972,7 @@ struct e1000_info e1000_ich8_info = { | FLAG_HAS_FLASH | FLAG_APME_IN_WUC, .pba = 8, + .max_hw_frame_size = ETH_FRAME_LEN + ETH_FCS_LEN, .get_variants = e1000_get_variants_ich8lan, .mac_ops = &ich8_mac_ops, .phy_ops = &ich8_phy_ops, @@ -2613,6 +2991,7 @@ struct e1000_info e1000_ich9_info = { | FLAG_HAS_FLASH | FLAG_APME_IN_WUC, .pba = 10, + .max_hw_frame_size = DEFAULT_JUMBO, .get_variants = e1000_get_variants_ich8lan, .mac_ops = &ich8_mac_ops, .phy_ops = &ich8_phy_ops, @@ -2631,6 +3010,25 @@ struct e1000_info e1000_ich10_info = { | FLAG_HAS_FLASH | FLAG_APME_IN_WUC, .pba = 10, + .max_hw_frame_size = DEFAULT_JUMBO, + .get_variants = e1000_get_variants_ich8lan, + .mac_ops = &ich8_mac_ops, + .phy_ops = &ich8_phy_ops, + .nvm_ops = &ich8_nvm_ops, +}; + +struct e1000_info e1000_pch_info = { + .mac = e1000_pchlan, + .flags = FLAG_IS_ICH + | FLAG_HAS_WOL + | FLAG_RX_CSUM_ENABLED + | FLAG_HAS_CTRLEXT_ON_LOAD + | FLAG_HAS_AMT + | FLAG_HAS_FLASH + | FLAG_HAS_JUMBO_FRAMES + | FLAG_APME_IN_WUC, + .pba = 26, + .max_hw_frame_size = 4096, .get_variants = e1000_get_variants_ich8lan, .mac_ops = &ich8_mac_ops, .phy_ops = &ich8_phy_ops, diff --git a/drivers/net/e1000e/lib.c b/drivers/net/e1000e/lib.c index 18a4f5902f3b..be6d9e990374 100644 --- a/drivers/net/e1000e/lib.c +++ b/drivers/net/e1000e/lib.c @@ -378,6 +378,12 @@ s32 e1000e_check_for_copper_link(struct e1000_hw *hw) mac->get_link_status = 0; + if (hw->phy.type == e1000_phy_82578) { + ret_val = e1000_link_stall_workaround_hv(hw); + if (ret_val) + return ret_val; + } + /* * Check if there was DownShift, must be checked * immediately after link-up @@ -1405,6 +1411,38 @@ s32 e1000e_id_led_init(struct e1000_hw *hw) return 0; } +/** + * e1000e_setup_led_generic - Configures SW controllable LED + * @hw: pointer to the HW structure + * + * This prepares the SW controllable LED for use and saves the current state + * of the LED so it can be later restored. + **/ +s32 e1000e_setup_led_generic(struct e1000_hw *hw) +{ + u32 ledctl; + + if (hw->mac.ops.setup_led != e1000e_setup_led_generic) { + return -E1000_ERR_CONFIG; + } + + if (hw->phy.media_type == e1000_media_type_fiber) { + ledctl = er32(LEDCTL); + hw->mac.ledctl_default = ledctl; + /* Turn off LED0 */ + ledctl &= ~(E1000_LEDCTL_LED0_IVRT | + E1000_LEDCTL_LED0_BLINK | + E1000_LEDCTL_LED0_MODE_MASK); + ledctl |= (E1000_LEDCTL_MODE_LED_OFF << + E1000_LEDCTL_LED0_MODE_SHIFT); + ew32(LEDCTL, ledctl); + } else if (hw->phy.media_type == e1000_media_type_copper) { + ew32(LEDCTL, hw->mac.ledctl_mode1); + } + + return 0; +} + /** * e1000e_cleanup_led_generic - Set LED config to default operation * @hw: pointer to the HW structure diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index ca82f19a7ed1..679885a122b4 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -48,7 +48,7 @@ #include "e1000.h" -#define DRV_VERSION "0.3.3.4-k4" +#define DRV_VERSION "1.0.2-k2" char e1000e_driver_name[] = "e1000e"; const char e1000e_driver_version[] = DRV_VERSION; @@ -62,6 +62,7 @@ static const struct e1000_info *e1000_info_tbl[] = { [board_ich8lan] = &e1000_ich8_info, [board_ich9lan] = &e1000_ich9_info, [board_ich10lan] = &e1000_ich10_info, + [board_pchlan] = &e1000_pch_info, }; #ifdef DEBUG @@ -1996,7 +1997,7 @@ static int e1000_clean(struct napi_struct *napi, int budget) struct e1000_adapter *adapter = container_of(napi, struct e1000_adapter, napi); struct e1000_hw *hw = &adapter->hw; struct net_device *poll_dev = adapter->netdev; - int tx_cleaned = 0, work_done = 0; + int tx_cleaned = 1, work_done = 0; adapter = netdev_priv(poll_dev); @@ -2255,8 +2256,6 @@ static void e1000_configure_tx(struct e1000_adapter *adapter) ew32(TARC(1), tarc); } - e1000e_config_collision_dist(hw); - /* Setup Transmit Descriptor Settings for eop descriptor */ adapter->txd_cmd = E1000_TXD_CMD_EOP | E1000_TXD_CMD_IFCS; @@ -2269,6 +2268,8 @@ static void e1000_configure_tx(struct e1000_adapter *adapter) ew32(TCTL, tctl); + e1000e_config_collision_dist(hw); + adapter->tx_queue_len = adapter->netdev->tx_queue_len; } @@ -2308,6 +2309,23 @@ static void e1000_setup_rctl(struct e1000_adapter *adapter) if (adapter->flags2 & FLAG2_CRC_STRIPPING) rctl |= E1000_RCTL_SECRC; + /* Workaround Si errata on 82577 PHY - configure IPG for jumbos */ + if ((hw->phy.type == e1000_phy_82577) && (rctl & E1000_RCTL_LPE)) { + u16 phy_data; + + e1e_rphy(hw, PHY_REG(770, 26), &phy_data); + phy_data &= 0xfff8; + phy_data |= (1 << 2); + e1e_wphy(hw, PHY_REG(770, 26), phy_data); + + e1e_rphy(hw, 22, &phy_data); + phy_data &= 0x0fff; + phy_data |= (1 << 14); + e1e_wphy(hw, 0x10, 0x2823); + e1e_wphy(hw, 0x11, 0x0003); + e1e_wphy(hw, 22, phy_data); + } + /* Setup buffer sizes */ rctl &= ~E1000_RCTL_SZ_4096; rctl |= E1000_RCTL_BSEX; @@ -2751,23 +2769,25 @@ void e1000e_reset(struct e1000_adapter *adapter) /* * flow control settings * - * The high water mark must be low enough to fit one full frame + * The high water mark must be low enough to fit two full frame * (or the size used for early receive) above it in the Rx FIFO. * Set it to the lower of: * - 90% of the Rx FIFO size, and * - the full Rx FIFO size minus the early receive size (for parts * with ERT support assuming ERT set to E1000_ERT_2048), or - * - the full Rx FIFO size minus one full frame + * - the full Rx FIFO size minus two full frames */ - if (adapter->flags & FLAG_HAS_ERT) + if ((adapter->flags & FLAG_HAS_ERT) && + (adapter->netdev->mtu > ETH_DATA_LEN)) hwm = min(((pba << 10) * 9 / 10), ((pba << 10) - (E1000_ERT_2048 << 3))); else hwm = min(((pba << 10) * 9 / 10), - ((pba << 10) - adapter->max_frame_size)); + ((pba << 10) - (2 * adapter->max_frame_size))); - fc->high_water = hwm & 0xFFF8; /* 8-byte granularity */ - fc->low_water = fc->high_water - 8; + fc->high_water = hwm & E1000_FCRTH_RTH; /* 8-byte granularity */ + fc->low_water = (fc->high_water - (2 * adapter->max_frame_size)); + fc->low_water &= E1000_FCRTL_RTL; /* 8-byte granularity */ if (adapter->flags & FLAG_DISABLE_FC_PAUSE_TIME) fc->pause_time = 0xFFFF; @@ -2787,6 +2807,8 @@ void e1000e_reset(struct e1000_adapter *adapter) e1000_get_hw_control(adapter); ew32(WUC, 0); + if (adapter->flags2 & FLAG2_HAS_PHY_WAKEUP) + e1e_wphy(&adapter->hw, BM_WUC, 0); if (mac->ops.init_hw(hw)) e_err("Hardware Error\n"); @@ -2799,7 +2821,8 @@ void e1000e_reset(struct e1000_adapter *adapter) e1000e_reset_adaptive(hw); e1000_get_phy_info(hw); - if (!(adapter->flags & FLAG_SMART_POWER_DOWN)) { + if ((adapter->flags & FLAG_HAS_SMART_POWER_DOWN) && + !(adapter->flags & FLAG_SMART_POWER_DOWN)) { u16 phy_data = 0; /* * speed up time to link by disabling smart power down, ignore @@ -2826,6 +2849,8 @@ int e1000e_up(struct e1000_adapter *adapter) e1000_configure_msix(adapter); e1000_irq_enable(adapter); + netif_wake_queue(adapter->netdev); + /* fire a link change interrupt to start the watchdog */ ew32(ICS, E1000_ICS_LSC); return 0; @@ -2848,7 +2873,7 @@ void e1000e_down(struct e1000_adapter *adapter) ew32(RCTL, rctl & ~E1000_RCTL_EN); /* flush and sleep below */ - netif_tx_stop_all_queues(netdev); + netif_stop_queue(netdev); /* disable transmits in the hardware */ tctl = er32(TCTL); @@ -3072,6 +3097,8 @@ static int e1000_open(struct net_device *netdev) if (test_bit(__E1000_TESTING, &adapter->state)) return -EBUSY; + netif_carrier_off(netdev); + /* allocate transmit descriptors */ err = e1000e_setup_tx_resources(adapter); if (err) @@ -3128,7 +3155,7 @@ static int e1000_open(struct net_device *netdev) e1000_irq_enable(adapter); - netif_tx_start_all_queues(netdev); + netif_start_queue(netdev); /* fire a link status change interrupt to start the watchdog */ ew32(ICS, E1000_ICS_LSC); @@ -3262,6 +3289,7 @@ void e1000e_update_stats(struct e1000_adapter *adapter) { struct e1000_hw *hw = &adapter->hw; struct pci_dev *pdev = adapter->pdev; + u16 phy_data; /* * Prevent stats update while adapter is being reset, or if the pci @@ -3281,11 +3309,34 @@ void e1000e_update_stats(struct e1000_adapter *adapter) adapter->stats.roc += er32(ROC); adapter->stats.mpc += er32(MPC); - adapter->stats.scc += er32(SCC); - adapter->stats.ecol += er32(ECOL); - adapter->stats.mcc += er32(MCC); - adapter->stats.latecol += er32(LATECOL); - adapter->stats.dc += er32(DC); + if ((hw->phy.type == e1000_phy_82578) || + (hw->phy.type == e1000_phy_82577)) { + e1e_rphy(hw, HV_SCC_UPPER, &phy_data); + e1e_rphy(hw, HV_SCC_LOWER, &phy_data); + adapter->stats.scc += phy_data; + + e1e_rphy(hw, HV_ECOL_UPPER, &phy_data); + e1e_rphy(hw, HV_ECOL_LOWER, &phy_data); + adapter->stats.ecol += phy_data; + + e1e_rphy(hw, HV_MCC_UPPER, &phy_data); + e1e_rphy(hw, HV_MCC_LOWER, &phy_data); + adapter->stats.mcc += phy_data; + + e1e_rphy(hw, HV_LATECOL_UPPER, &phy_data); + e1e_rphy(hw, HV_LATECOL_LOWER, &phy_data); + adapter->stats.latecol += phy_data; + + e1e_rphy(hw, HV_DC_UPPER, &phy_data); + e1e_rphy(hw, HV_DC_LOWER, &phy_data); + adapter->stats.dc += phy_data; + } else { + adapter->stats.scc += er32(SCC); + adapter->stats.ecol += er32(ECOL); + adapter->stats.mcc += er32(MCC); + adapter->stats.latecol += er32(LATECOL); + adapter->stats.dc += er32(DC); + } adapter->stats.xonrxc += er32(XONRXC); adapter->stats.xontxc += er32(XONTXC); adapter->stats.xoffrxc += er32(XOFFRXC); @@ -3303,13 +3354,28 @@ void e1000e_update_stats(struct e1000_adapter *adapter) hw->mac.tx_packet_delta = er32(TPT); adapter->stats.tpt += hw->mac.tx_packet_delta; - hw->mac.collision_delta = er32(COLC); + if ((hw->phy.type == e1000_phy_82578) || + (hw->phy.type == e1000_phy_82577)) { + e1e_rphy(hw, HV_COLC_UPPER, &phy_data); + e1e_rphy(hw, HV_COLC_LOWER, &phy_data); + hw->mac.collision_delta = phy_data; + } else { + hw->mac.collision_delta = er32(COLC); + } adapter->stats.colc += hw->mac.collision_delta; adapter->stats.algnerrc += er32(ALGNERRC); adapter->stats.rxerrc += er32(RXERRC); - if ((hw->mac.type != e1000_82574) && (hw->mac.type != e1000_82583)) - adapter->stats.tncrs += er32(TNCRS); + if ((hw->phy.type == e1000_phy_82578) || + (hw->phy.type == e1000_phy_82577)) { + e1e_rphy(hw, HV_TNCRS_UPPER, &phy_data); + e1e_rphy(hw, HV_TNCRS_LOWER, &phy_data); + adapter->stats.tncrs += phy_data; + } else { + if ((hw->mac.type != e1000_82574) && + (hw->mac.type != e1000_82583)) + adapter->stats.tncrs += er32(TNCRS); + } adapter->stats.cexterr += er32(CEXTERR); adapter->stats.tsctc += er32(TSCTC); adapter->stats.tsctfc += er32(TSCTFC); @@ -3598,7 +3664,6 @@ static void e1000_watchdog_task(struct work_struct *work) phy->ops.cfg_on_link_up(hw); netif_carrier_on(netdev); - netif_tx_wake_all_queues(netdev); if (!test_bit(__E1000_DOWN, &adapter->state)) mod_timer(&adapter->phy_info_timer, @@ -3612,7 +3677,6 @@ static void e1000_watchdog_task(struct work_struct *work) printk(KERN_INFO "e1000e: %s NIC Link is Down\n", adapter->netdev->name); netif_carrier_off(netdev); - netif_tx_stop_all_queues(netdev); if (!test_bit(__E1000_DOWN, &adapter->state)) mod_timer(&adapter->phy_info_timer, round_jiffies(jiffies + 2 * HZ)); @@ -3649,6 +3713,8 @@ link_up: */ adapter->tx_timeout_count++; schedule_work(&adapter->reset_task); + /* return immediately since reset is imminent */ + return; } } @@ -3850,7 +3916,7 @@ static int e1000_tx_map(struct e1000_adapter *adapter, buffer_info->length = size; buffer_info->time_stamp = jiffies; buffer_info->next_to_watch = i; - buffer_info->dma = map[0] + offset; + buffer_info->dma = skb_shinfo(skb)->dma_head + offset; count++; len -= size; @@ -3881,7 +3947,7 @@ static int e1000_tx_map(struct e1000_adapter *adapter, buffer_info->length = size; buffer_info->time_stamp = jiffies; buffer_info->next_to_watch = i; - buffer_info->dma = map[f + 1] + offset; + buffer_info->dma = map[f] + offset; len -= size; offset += size; @@ -4145,7 +4211,6 @@ static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) count = e1000_tx_map(adapter, skb, first, max_per_txd, nr_frags, mss); if (count) { e1000_tx_queue(adapter, tx_flags, count); - netdev->trans_start = jiffies; /* Make sure there is space in the ring for the next send. */ e1000_maybe_stop_tx(netdev, MAX_SKB_FRAGS + 2); @@ -4206,27 +4271,17 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu) struct e1000_adapter *adapter = netdev_priv(netdev); int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN; - if ((new_mtu < ETH_ZLEN + ETH_FCS_LEN + VLAN_HLEN) || - (max_frame > MAX_JUMBO_FRAME_SIZE)) { - e_err("Invalid MTU setting\n"); + /* Jumbo frame support */ + if ((max_frame > ETH_FRAME_LEN + ETH_FCS_LEN) && + !(adapter->flags & FLAG_HAS_JUMBO_FRAMES)) { + e_err("Jumbo Frames not supported.\n"); return -EINVAL; } - /* Jumbo frame size limits */ - if (max_frame > ETH_FRAME_LEN + ETH_FCS_LEN) { - if (!(adapter->flags & FLAG_HAS_JUMBO_FRAMES)) { - e_err("Jumbo Frames not supported.\n"); - return -EINVAL; - } - if (adapter->hw.phy.type == e1000_phy_ife) { - e_err("Jumbo Frames not supported.\n"); - return -EINVAL; - } - } - -#define MAX_STD_JUMBO_FRAME_SIZE 9234 - if (max_frame > MAX_STD_JUMBO_FRAME_SIZE) { - e_err("MTU > 9216 not supported.\n"); + /* Supported frame sizes */ + if ((new_mtu < ETH_ZLEN + ETH_FCS_LEN + VLAN_HLEN) || + (max_frame > adapter->max_hw_frame_size)) { + e_err("Unsupported MTU setting\n"); return -EINVAL; } @@ -4346,6 +4401,81 @@ static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) } } +static int e1000_init_phy_wakeup(struct e1000_adapter *adapter, u32 wufc) +{ + struct e1000_hw *hw = &adapter->hw; + u32 i, mac_reg; + u16 phy_reg; + int retval = 0; + + /* copy MAC RARs to PHY RARs */ + for (i = 0; i < adapter->hw.mac.rar_entry_count; i++) { + mac_reg = er32(RAL(i)); + e1e_wphy(hw, BM_RAR_L(i), (u16)(mac_reg & 0xFFFF)); + e1e_wphy(hw, BM_RAR_M(i), (u16)((mac_reg >> 16) & 0xFFFF)); + mac_reg = er32(RAH(i)); + e1e_wphy(hw, BM_RAR_H(i), (u16)(mac_reg & 0xFFFF)); + e1e_wphy(hw, BM_RAR_CTRL(i), (u16)((mac_reg >> 16) & 0xFFFF)); + } + + /* copy MAC MTA to PHY MTA */ + for (i = 0; i < adapter->hw.mac.mta_reg_count; i++) { + mac_reg = E1000_READ_REG_ARRAY(hw, E1000_MTA, i); + e1e_wphy(hw, BM_MTA(i), (u16)(mac_reg & 0xFFFF)); + e1e_wphy(hw, BM_MTA(i) + 1, (u16)((mac_reg >> 16) & 0xFFFF)); + } + + /* configure PHY Rx Control register */ + e1e_rphy(&adapter->hw, BM_RCTL, &phy_reg); + mac_reg = er32(RCTL); + if (mac_reg & E1000_RCTL_UPE) + phy_reg |= BM_RCTL_UPE; + if (mac_reg & E1000_RCTL_MPE) + phy_reg |= BM_RCTL_MPE; + phy_reg &= ~(BM_RCTL_MO_MASK); + if (mac_reg & E1000_RCTL_MO_3) + phy_reg |= (((mac_reg & E1000_RCTL_MO_3) >> E1000_RCTL_MO_SHIFT) + << BM_RCTL_MO_SHIFT); + if (mac_reg & E1000_RCTL_BAM) + phy_reg |= BM_RCTL_BAM; + if (mac_reg & E1000_RCTL_PMCF) + phy_reg |= BM_RCTL_PMCF; + mac_reg = er32(CTRL); + if (mac_reg & E1000_CTRL_RFCE) + phy_reg |= BM_RCTL_RFCE; + e1e_wphy(&adapter->hw, BM_RCTL, phy_reg); + + /* enable PHY wakeup in MAC register */ + ew32(WUFC, wufc); + ew32(WUC, E1000_WUC_PHY_WAKE | E1000_WUC_PME_EN); + + /* configure and enable PHY wakeup in PHY registers */ + e1e_wphy(&adapter->hw, BM_WUFC, wufc); + e1e_wphy(&adapter->hw, BM_WUC, E1000_WUC_PME_EN); + + /* activate PHY wakeup */ + retval = hw->phy.ops.acquire_phy(hw); + if (retval) { + e_err("Could not acquire PHY\n"); + return retval; + } + e1000e_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, + (BM_WUC_ENABLE_PAGE << IGP_PAGE_SHIFT)); + retval = e1000e_read_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, &phy_reg); + if (retval) { + e_err("Could not read PHY page 769\n"); + goto out; + } + phy_reg |= BM_WUC_ENABLE_BIT | BM_WUC_HOST_WU_BIT; + retval = e1000e_write_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, phy_reg); + if (retval) + e_err("Could not set PHY Host Wakeup bit\n"); +out: + hw->phy.ops.release_phy(hw); + + return retval; +} + static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake) { struct net_device *netdev = pci_get_drvdata(pdev); @@ -4388,8 +4518,9 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake) #define E1000_CTRL_ADVD3WUC 0x00100000 /* phy power management enable */ #define E1000_CTRL_EN_PHY_PWR_MGMT 0x00200000 - ctrl |= E1000_CTRL_ADVD3WUC | - E1000_CTRL_EN_PHY_PWR_MGMT; + ctrl |= E1000_CTRL_ADVD3WUC; + if (!(adapter->flags2 & FLAG2_HAS_PHY_WAKEUP)) + ctrl |= E1000_CTRL_EN_PHY_PWR_MGMT; ew32(CTRL, ctrl); if (adapter->hw.phy.media_type == e1000_media_type_fiber || @@ -4407,8 +4538,17 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake) /* Allow time for pending master requests to run */ e1000e_disable_pcie_master(&adapter->hw); - ew32(WUC, E1000_WUC_PME_EN); - ew32(WUFC, wufc); + if ((adapter->flags2 & FLAG2_HAS_PHY_WAKEUP) && + !(hw->mac.ops.check_mng_mode(hw))) { + /* enable wakeup by the PHY */ + retval = e1000_init_phy_wakeup(adapter, wufc); + if (retval) + return retval; + } else { + /* enable wakeup by the MAC */ + ew32(WUFC, wufc); + ew32(WUC, E1000_WUC_PME_EN); + } } else { ew32(WUC, 0); ew32(WUFC, 0); @@ -4551,8 +4691,37 @@ static int e1000_resume(struct pci_dev *pdev) } e1000e_power_up_phy(adapter); + + /* report the system wakeup cause from S3/S4 */ + if (adapter->flags2 & FLAG2_HAS_PHY_WAKEUP) { + u16 phy_data; + + e1e_rphy(&adapter->hw, BM_WUS, &phy_data); + if (phy_data) { + e_info("PHY Wakeup cause - %s\n", + phy_data & E1000_WUS_EX ? "Unicast Packet" : + phy_data & E1000_WUS_MC ? "Multicast Packet" : + phy_data & E1000_WUS_BC ? "Broadcast Packet" : + phy_data & E1000_WUS_MAG ? "Magic Packet" : + phy_data & E1000_WUS_LNKC ? "Link Status " + " Change" : "other"); + } + e1e_wphy(&adapter->hw, BM_WUS, ~0); + } else { + u32 wus = er32(WUS); + if (wus) { + e_info("MAC Wakeup cause - %s\n", + wus & E1000_WUS_EX ? "Unicast Packet" : + wus & E1000_WUS_MC ? "Multicast Packet" : + wus & E1000_WUS_BC ? "Broadcast Packet" : + wus & E1000_WUS_MAG ? "Magic Packet" : + wus & E1000_WUS_LNKC ? "Link Status Change" : + "other"); + } + ew32(WUS, ~0); + } + e1000e_reset(adapter); - ew32(WUS, ~0); e1000_init_manageability(adapter); @@ -4842,6 +5011,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev, adapter->flags2 = ei->flags2; adapter->hw.adapter = adapter; adapter->hw.mac.type = ei->mac; + adapter->max_hw_frame_size = ei->max_hw_frame_size; adapter->msg_enable = (1 << NETIF_MSG_DRV | NETIF_MSG_PROBE) - 1; mmio_start = pci_resource_start(pdev, 0); @@ -4997,6 +5167,8 @@ static int __devinit e1000_probe(struct pci_dev *pdev, /* APME bit in EEPROM is mapped to WUC.APME */ eeprom_data = er32(WUC); eeprom_apme_mask = E1000_WUC_APME; + if (eeprom_data & E1000_WUC_PHY_WAKE) + adapter->flags2 |= FLAG2_HAS_PHY_WAKEUP; } else if (adapter->flags & FLAG_APME_IN_CTRL3) { if (adapter->flags & FLAG_APME_CHECK_PORT_B && (adapter->hw.bus.func == 1)) @@ -5037,15 +5209,14 @@ static int __devinit e1000_probe(struct pci_dev *pdev, if (!(adapter->flags & FLAG_HAS_AMT)) e1000_get_hw_control(adapter); - /* tell the stack to leave us alone until e1000_open() is called */ - netif_carrier_off(netdev); - netif_tx_stop_all_queues(netdev); - strcpy(netdev->name, "eth%d"); err = register_netdev(netdev); if (err) goto err_register; + /* carrier off reporting is important to ethtool even BEFORE open */ + netif_carrier_off(netdev); + e1000_print_device_info(adapter); return 0; @@ -5199,6 +5370,11 @@ static struct pci_device_id e1000_pci_tbl[] = { { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_D_BM_LM), board_ich10lan }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_D_BM_LF), board_ich10lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_M_HV_LM), board_pchlan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_M_HV_LC), board_pchlan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_D_HV_DM), board_pchlan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_D_HV_DC), board_pchlan }, + { } /* terminate list */ }; MODULE_DEVICE_TABLE(pci, e1000_pci_tbl); diff --git a/drivers/net/e1000e/param.c b/drivers/net/e1000e/param.c index e909f96698e8..1342e0b1815c 100644 --- a/drivers/net/e1000e/param.c +++ b/drivers/net/e1000e/param.c @@ -427,6 +427,8 @@ void __devinit e1000e_check_options(struct e1000_adapter *adapter) e1000_validate_option(&crc_stripping, &opt, adapter); if (crc_stripping == OPTION_ENABLED) adapter->flags2 |= FLAG2_CRC_STRIPPING; + } else { + adapter->flags2 |= FLAG2_CRC_STRIPPING; } } { /* Kumeran Lock Loss Workaround */ diff --git a/drivers/net/e1000e/phy.c b/drivers/net/e1000e/phy.c index dc4a9cba6a73..e23459cf3d0e 100644 --- a/drivers/net/e1000e/phy.c +++ b/drivers/net/e1000e/phy.c @@ -37,6 +37,9 @@ static s32 e1000_wait_autoneg(struct e1000_hw *hw); static u32 e1000_get_phy_addr_for_bm_page(u32 page, u32 reg); static s32 e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data, bool read); +static u32 e1000_get_phy_addr_for_hv_page(u32 page); +static s32 e1000_access_phy_debug_regs_hv(struct e1000_hw *hw, u32 offset, + u16 *data, bool read); /* Cable length tables */ static const u16 e1000_m88_cable_length_table[] = @@ -54,6 +57,55 @@ static const u16 e1000_igp_2_cable_length_table[] = #define IGP02E1000_CABLE_LENGTH_TABLE_SIZE \ ARRAY_SIZE(e1000_igp_2_cable_length_table) +#define BM_PHY_REG_PAGE(offset) \ + ((u16)(((offset) >> PHY_PAGE_SHIFT) & 0xFFFF)) +#define BM_PHY_REG_NUM(offset) \ + ((u16)(((offset) & MAX_PHY_REG_ADDRESS) |\ + (((offset) >> (PHY_UPPER_SHIFT - PHY_PAGE_SHIFT)) &\ + ~MAX_PHY_REG_ADDRESS))) + +#define HV_INTC_FC_PAGE_START 768 +#define I82578_ADDR_REG 29 +#define I82577_ADDR_REG 16 +#define I82577_CFG_REG 22 +#define I82577_CFG_ASSERT_CRS_ON_TX (1 << 15) +#define I82577_CFG_ENABLE_DOWNSHIFT (3 << 10) /* auto downshift 100/10 */ +#define I82577_CTRL_REG 23 +#define I82577_CTRL_DOWNSHIFT_MASK (7 << 10) + +/* 82577 specific PHY registers */ +#define I82577_PHY_CTRL_2 18 +#define I82577_PHY_STATUS_2 26 +#define I82577_PHY_DIAG_STATUS 31 + +/* I82577 PHY Status 2 */ +#define I82577_PHY_STATUS2_REV_POLARITY 0x0400 +#define I82577_PHY_STATUS2_MDIX 0x0800 +#define I82577_PHY_STATUS2_SPEED_MASK 0x0300 +#define I82577_PHY_STATUS2_SPEED_1000MBPS 0x0200 + +/* I82577 PHY Control 2 */ +#define I82577_PHY_CTRL2_AUTO_MDIX 0x0400 +#define I82577_PHY_CTRL2_FORCE_MDI_MDIX 0x0200 + +/* I82577 PHY Diagnostics Status */ +#define I82577_DSTATUS_CABLE_LENGTH 0x03FC +#define I82577_DSTATUS_CABLE_LENGTH_SHIFT 2 + +/* BM PHY Copper Specific Control 1 */ +#define BM_CS_CTRL1 16 + +/* BM PHY Copper Specific Status */ +#define BM_CS_STATUS 17 +#define BM_CS_STATUS_LINK_UP 0x0400 +#define BM_CS_STATUS_RESOLVED 0x0800 +#define BM_CS_STATUS_SPEED_MASK 0xC000 +#define BM_CS_STATUS_SPEED_1000 0x8000 + +#define HV_MUX_DATA_CTRL PHY_REG(776, 16) +#define HV_MUX_DATA_CTRL_GEN_TO_MAC 0x0400 +#define HV_MUX_DATA_CTRL_FORCE_SPEED 0x0004 + /** * e1000e_check_reset_block_generic - Check if PHY reset is blocked * @hw: pointer to the HW structure @@ -82,23 +134,48 @@ s32 e1000e_check_reset_block_generic(struct e1000_hw *hw) s32 e1000e_get_phy_id(struct e1000_hw *hw) { struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; + s32 ret_val = 0; u16 phy_id; + u16 retry_count = 0; - ret_val = e1e_rphy(hw, PHY_ID1, &phy_id); - if (ret_val) - return ret_val; + if (!(phy->ops.read_phy_reg)) + goto out; - phy->id = (u32)(phy_id << 16); - udelay(20); - ret_val = e1e_rphy(hw, PHY_ID2, &phy_id); - if (ret_val) - return ret_val; + while (retry_count < 2) { + ret_val = e1e_rphy(hw, PHY_ID1, &phy_id); + if (ret_val) + goto out; - phy->id |= (u32)(phy_id & PHY_REVISION_MASK); - phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK); + phy->id = (u32)(phy_id << 16); + udelay(20); + ret_val = e1e_rphy(hw, PHY_ID2, &phy_id); + if (ret_val) + goto out; - return 0; + phy->id |= (u32)(phy_id & PHY_REVISION_MASK); + phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK); + + if (phy->id != 0 && phy->id != PHY_REVISION_MASK) + goto out; + + /* + * If the PHY ID is still unknown, we may have an 82577i + * without link. We will try again after setting Slow + * MDIC mode. No harm in trying again in this case since + * the PHY ID is unknown at this point anyway + */ + ret_val = e1000_set_mdio_slow_mode_hv(hw, true); + if (ret_val) + goto out; + + retry_count++; + } +out: + /* Revert to MDIO fast mode, if applicable */ + if (retry_count) + ret_val = e1000_set_mdio_slow_mode_hv(hw, false); + + return ret_val; } /** @@ -409,6 +486,43 @@ s32 e1000e_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data) return ret_val; } +/** + * e1000_copper_link_setup_82577 - Setup 82577 PHY for copper link + * @hw: pointer to the HW structure + * + * Sets up Carrier-sense on Transmit and downshift values. + **/ +s32 e1000_copper_link_setup_82577(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_data; + + /* Enable CRS on TX. This must be set for half-duplex operation. */ + ret_val = phy->ops.read_phy_reg(hw, I82577_CFG_REG, &phy_data); + if (ret_val) + goto out; + + phy_data |= I82577_CFG_ASSERT_CRS_ON_TX; + + /* Enable downshift */ + phy_data |= I82577_CFG_ENABLE_DOWNSHIFT; + + ret_val = phy->ops.write_phy_reg(hw, I82577_CFG_REG, phy_data); + if (ret_val) + goto out; + + /* Set number of link attempts before downshift */ + ret_val = phy->ops.read_phy_reg(hw, I82577_CTRL_REG, &phy_data); + if (ret_val) + goto out; + phy_data &= ~I82577_CTRL_DOWNSHIFT_MASK; + ret_val = phy->ops.write_phy_reg(hw, I82577_CTRL_REG, phy_data); + +out: + return ret_val; +} + /** * e1000e_copper_link_setup_m88 - Setup m88 PHY's for copper link * @hw: pointer to the HW structure @@ -427,8 +541,8 @@ s32 e1000e_copper_link_setup_m88(struct e1000_hw *hw) if (ret_val) return ret_val; - /* For newer PHYs this bit is downshift enable */ - if (phy->type == e1000_phy_m88) + /* For BM PHY this bit is downshift enable */ + if (phy->type != e1000_phy_bm) phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX; /* @@ -520,10 +634,27 @@ s32 e1000e_copper_link_setup_m88(struct e1000_hw *hw) /* Commit the changes. */ ret_val = e1000e_commit_phy(hw); - if (ret_val) + if (ret_val) { hw_dbg(hw, "Error committing the PHY changes\n"); + return ret_val; + } - return ret_val; + if (phy->type == e1000_phy_82578) { + ret_val = phy->ops.read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, + &phy_data); + if (ret_val) + return ret_val; + + /* 82578 PHY - set the downshift count to 1x. */ + phy_data |= I82578_EPSCR_DOWNSHIFT_ENABLE; + phy_data &= ~I82578_EPSCR_DOWNSHIFT_COUNTER_MASK; + ret_val = phy->ops.write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, + phy_data); + if (ret_val) + return ret_val; + } + + return 0; } /** @@ -1251,6 +1382,8 @@ s32 e1000e_check_downshift(struct e1000_hw *hw) switch (phy->type) { case e1000_phy_m88: case e1000_phy_gg82563: + case e1000_phy_82578: + case e1000_phy_82577: offset = M88E1000_PHY_SPEC_STATUS; mask = M88E1000_PSSR_DOWNSHIFT; break; @@ -1886,6 +2019,12 @@ enum e1000_phy_type e1000e_get_phy_type_from_id(u32 phy_id) case BME1000_E_PHY_ID_R2: phy_type = e1000_phy_bm; break; + case I82578_E_PHY_ID: + phy_type = e1000_phy_82578; + break; + case I82577_E_PHY_ID: + phy_type = e1000_phy_82577; + break; default: phy_type = e1000_phy_unknown; break; @@ -2181,11 +2320,16 @@ static s32 e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data, bool read) { s32 ret_val; - u16 reg = ((u16)offset) & PHY_REG_MASK; + u16 reg = BM_PHY_REG_NUM(offset); u16 phy_reg = 0; u8 phy_acquired = 1; + /* Gig must be disabled for MDIO accesses to page 800 */ + if ((hw->mac.type == e1000_pchlan) && + (!(er32(PHY_CTRL) & E1000_PHY_CTRL_GBE_DISABLE))) + hw_dbg(hw, "Attempting to access page 800 while gig enabled\n"); + ret_val = hw->phy.ops.acquire_phy(hw); if (ret_val) { phy_acquired = 0; @@ -2289,3 +2433,524 @@ static s32 e1000_set_d0_lplu_state(struct e1000_hw *hw, bool active) return 0; } + +s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw, bool slow) +{ + s32 ret_val = 0; + u16 data = 0; + + ret_val = hw->phy.ops.acquire_phy(hw); + if (ret_val) + return ret_val; + + /* Set MDIO mode - page 769, register 16: 0x2580==slow, 0x2180==fast */ + hw->phy.addr = 1; + ret_val = e1000e_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, + (BM_PORT_CTRL_PAGE << IGP_PAGE_SHIFT)); + if (ret_val) { + hw->phy.ops.release_phy(hw); + return ret_val; + } + ret_val = e1000e_write_phy_reg_mdic(hw, BM_CS_CTRL1, + (0x2180 | (slow << 10))); + + /* dummy read when reverting to fast mode - throw away result */ + if (!slow) + e1000e_read_phy_reg_mdic(hw, BM_CS_CTRL1, &data); + + hw->phy.ops.release_phy(hw); + + return ret_val; +} + +/** + * e1000_read_phy_reg_hv - Read HV PHY register + * @hw: pointer to the HW structure + * @offset: register offset to be read + * @data: pointer to the read data + * + * Acquires semaphore, if necessary, then reads the PHY register at offset + * and storing the retrieved information in data. Release any acquired + * semaphore before exiting. + **/ +s32 e1000_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data) +{ + s32 ret_val; + u16 page = BM_PHY_REG_PAGE(offset); + u16 reg = BM_PHY_REG_NUM(offset); + bool in_slow_mode = false; + + /* Workaround failure in MDIO access while cable is disconnected */ + if ((hw->phy.type == e1000_phy_82577) && + !(er32(STATUS) & E1000_STATUS_LU)) { + ret_val = e1000_set_mdio_slow_mode_hv(hw, true); + if (ret_val) + goto out; + + in_slow_mode = true; + } + + /* Page 800 works differently than the rest so it has its own func */ + if (page == BM_WUC_PAGE) { + ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, + data, true); + goto out; + } + + if (page > 0 && page < HV_INTC_FC_PAGE_START) { + ret_val = e1000_access_phy_debug_regs_hv(hw, offset, + data, true); + goto out; + } + + ret_val = hw->phy.ops.acquire_phy(hw); + if (ret_val) + goto out; + + hw->phy.addr = e1000_get_phy_addr_for_hv_page(page); + + if (page == HV_INTC_FC_PAGE_START) + page = 0; + + if (reg > MAX_PHY_MULTI_PAGE_REG) { + if ((hw->phy.type != e1000_phy_82578) || + ((reg != I82578_ADDR_REG) && + (reg != I82578_ADDR_REG + 1))) { + u32 phy_addr = hw->phy.addr; + + hw->phy.addr = 1; + + /* Page is shifted left, PHY expects (page x 32) */ + ret_val = e1000e_write_phy_reg_mdic(hw, + IGP01E1000_PHY_PAGE_SELECT, + (page << IGP_PAGE_SHIFT)); + if (ret_val) { + hw->phy.ops.release_phy(hw); + goto out; + } + hw->phy.addr = phy_addr; + } + } + + ret_val = e1000e_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & reg, + data); + hw->phy.ops.release_phy(hw); + +out: + /* Revert to MDIO fast mode, if applicable */ + if ((hw->phy.type == e1000_phy_82577) && in_slow_mode) + ret_val = e1000_set_mdio_slow_mode_hv(hw, false); + + return ret_val; +} + +/** + * e1000_write_phy_reg_hv - Write HV PHY register + * @hw: pointer to the HW structure + * @offset: register offset to write to + * @data: data to write at register offset + * + * Acquires semaphore, if necessary, then writes the data to PHY register + * at the offset. Release any acquired semaphores before exiting. + **/ +s32 e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data) +{ + s32 ret_val; + u16 page = BM_PHY_REG_PAGE(offset); + u16 reg = BM_PHY_REG_NUM(offset); + bool in_slow_mode = false; + + /* Workaround failure in MDIO access while cable is disconnected */ + if ((hw->phy.type == e1000_phy_82577) && + !(er32(STATUS) & E1000_STATUS_LU)) { + ret_val = e1000_set_mdio_slow_mode_hv(hw, true); + if (ret_val) + goto out; + + in_slow_mode = true; + } + + /* Page 800 works differently than the rest so it has its own func */ + if (page == BM_WUC_PAGE) { + ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, + &data, false); + goto out; + } + + if (page > 0 && page < HV_INTC_FC_PAGE_START) { + ret_val = e1000_access_phy_debug_regs_hv(hw, offset, + &data, false); + goto out; + } + + ret_val = hw->phy.ops.acquire_phy(hw); + if (ret_val) + goto out; + + hw->phy.addr = e1000_get_phy_addr_for_hv_page(page); + + if (page == HV_INTC_FC_PAGE_START) + page = 0; + + /* + * Workaround MDIO accesses being disabled after entering IEEE Power + * Down (whenever bit 11 of the PHY Control register is set) + */ + if ((hw->phy.type == e1000_phy_82578) && + (hw->phy.revision >= 1) && + (hw->phy.addr == 2) && + ((MAX_PHY_REG_ADDRESS & reg) == 0) && + (data & (1 << 11))) { + u16 data2 = 0x7EFF; + hw->phy.ops.release_phy(hw); + ret_val = e1000_access_phy_debug_regs_hv(hw, (1 << 6) | 0x3, + &data2, false); + if (ret_val) + goto out; + + ret_val = hw->phy.ops.acquire_phy(hw); + if (ret_val) + goto out; + } + + if (reg > MAX_PHY_MULTI_PAGE_REG) { + if ((hw->phy.type != e1000_phy_82578) || + ((reg != I82578_ADDR_REG) && + (reg != I82578_ADDR_REG + 1))) { + u32 phy_addr = hw->phy.addr; + + hw->phy.addr = 1; + + /* Page is shifted left, PHY expects (page x 32) */ + ret_val = e1000e_write_phy_reg_mdic(hw, + IGP01E1000_PHY_PAGE_SELECT, + (page << IGP_PAGE_SHIFT)); + if (ret_val) { + hw->phy.ops.release_phy(hw); + goto out; + } + hw->phy.addr = phy_addr; + } + } + + ret_val = e1000e_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & reg, + data); + hw->phy.ops.release_phy(hw); + +out: + /* Revert to MDIO fast mode, if applicable */ + if ((hw->phy.type == e1000_phy_82577) && in_slow_mode) + ret_val = e1000_set_mdio_slow_mode_hv(hw, false); + + return ret_val; +} + +/** + * e1000_get_phy_addr_for_hv_page - Get PHY adrress based on page + * @page: page to be accessed + **/ +static u32 e1000_get_phy_addr_for_hv_page(u32 page) +{ + u32 phy_addr = 2; + + if (page >= HV_INTC_FC_PAGE_START) + phy_addr = 1; + + return phy_addr; +} + +/** + * e1000_access_phy_debug_regs_hv - Read HV PHY vendor specific high registers + * @hw: pointer to the HW structure + * @offset: register offset to be read or written + * @data: pointer to the data to be read or written + * @read: determines if operation is read or written + * + * Acquires semaphore, if necessary, then reads the PHY register at offset + * and storing the retreived information in data. Release any acquired + * semaphores before exiting. Note that the procedure to read these regs + * uses the address port and data port to read/write. + **/ +static s32 e1000_access_phy_debug_regs_hv(struct e1000_hw *hw, u32 offset, + u16 *data, bool read) +{ + s32 ret_val; + u32 addr_reg = 0; + u32 data_reg = 0; + u8 phy_acquired = 1; + + /* This takes care of the difference with desktop vs mobile phy */ + addr_reg = (hw->phy.type == e1000_phy_82578) ? + I82578_ADDR_REG : I82577_ADDR_REG; + data_reg = addr_reg + 1; + + ret_val = hw->phy.ops.acquire_phy(hw); + if (ret_val) { + hw_dbg(hw, "Could not acquire PHY\n"); + phy_acquired = 0; + goto out; + } + + /* All operations in this function are phy address 2 */ + hw->phy.addr = 2; + + /* masking with 0x3F to remove the page from offset */ + ret_val = e1000e_write_phy_reg_mdic(hw, addr_reg, (u16)offset & 0x3F); + if (ret_val) { + hw_dbg(hw, "Could not write PHY the HV address register\n"); + goto out; + } + + /* Read or write the data value next */ + if (read) + ret_val = e1000e_read_phy_reg_mdic(hw, data_reg, data); + else + ret_val = e1000e_write_phy_reg_mdic(hw, data_reg, *data); + + if (ret_val) { + hw_dbg(hw, "Could not read data value from HV data register\n"); + goto out; + } + +out: + if (phy_acquired == 1) + hw->phy.ops.release_phy(hw); + return ret_val; +} + +/** + * e1000_link_stall_workaround_hv - Si workaround + * @hw: pointer to the HW structure + * + * This function works around a Si bug where the link partner can get + * a link up indication before the PHY does. If small packets are sent + * by the link partner they can be placed in the packet buffer without + * being properly accounted for by the PHY and will stall preventing + * further packets from being received. The workaround is to clear the + * packet buffer after the PHY detects link up. + **/ +s32 e1000_link_stall_workaround_hv(struct e1000_hw *hw) +{ + s32 ret_val = 0; + u16 data; + + if (hw->phy.type != e1000_phy_82578) + goto out; + + /* check if link is up and at 1Gbps */ + ret_val = hw->phy.ops.read_phy_reg(hw, BM_CS_STATUS, &data); + if (ret_val) + goto out; + + data &= BM_CS_STATUS_LINK_UP | + BM_CS_STATUS_RESOLVED | + BM_CS_STATUS_SPEED_MASK; + + if (data != (BM_CS_STATUS_LINK_UP | + BM_CS_STATUS_RESOLVED | + BM_CS_STATUS_SPEED_1000)) + goto out; + + mdelay(200); + + /* flush the packets in the fifo buffer */ + ret_val = hw->phy.ops.write_phy_reg(hw, HV_MUX_DATA_CTRL, + HV_MUX_DATA_CTRL_GEN_TO_MAC | + HV_MUX_DATA_CTRL_FORCE_SPEED); + if (ret_val) + goto out; + + ret_val = hw->phy.ops.write_phy_reg(hw, HV_MUX_DATA_CTRL, + HV_MUX_DATA_CTRL_GEN_TO_MAC); + +out: + return ret_val; +} + +/** + * e1000_check_polarity_82577 - Checks the polarity. + * @hw: pointer to the HW structure + * + * Success returns 0, Failure returns -E1000_ERR_PHY (-2) + * + * Polarity is determined based on the PHY specific status register. + **/ +s32 e1000_check_polarity_82577(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 data; + + ret_val = phy->ops.read_phy_reg(hw, I82577_PHY_STATUS_2, &data); + + if (!ret_val) + phy->cable_polarity = (data & I82577_PHY_STATUS2_REV_POLARITY) + ? e1000_rev_polarity_reversed + : e1000_rev_polarity_normal; + + return ret_val; +} + +/** + * e1000_phy_force_speed_duplex_82577 - Force speed/duplex for I82577 PHY + * @hw: pointer to the HW structure + * + * Calls the PHY setup function to force speed and duplex. Clears the + * auto-crossover to force MDI manually. Waits for link and returns + * successful if link up is successful, else -E1000_ERR_PHY (-2). + **/ +s32 e1000_phy_force_speed_duplex_82577(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_data; + bool link; + + ret_val = phy->ops.read_phy_reg(hw, PHY_CONTROL, &phy_data); + if (ret_val) + goto out; + + e1000e_phy_force_speed_duplex_setup(hw, &phy_data); + + ret_val = phy->ops.write_phy_reg(hw, PHY_CONTROL, phy_data); + if (ret_val) + goto out; + + /* + * Clear Auto-Crossover to force MDI manually. 82577 requires MDI + * forced whenever speed and duplex are forced. + */ + ret_val = phy->ops.read_phy_reg(hw, I82577_PHY_CTRL_2, &phy_data); + if (ret_val) + goto out; + + phy_data &= ~I82577_PHY_CTRL2_AUTO_MDIX; + phy_data &= ~I82577_PHY_CTRL2_FORCE_MDI_MDIX; + + ret_val = phy->ops.write_phy_reg(hw, I82577_PHY_CTRL_2, phy_data); + if (ret_val) + goto out; + + hw_dbg(hw, "I82577_PHY_CTRL_2: %X\n", phy_data); + + udelay(1); + + if (phy->autoneg_wait_to_complete) { + hw_dbg(hw, "Waiting for forced speed/duplex link on 82577 phy\n"); + + ret_val = e1000e_phy_has_link_generic(hw, + PHY_FORCE_LIMIT, + 100000, + &link); + if (ret_val) + goto out; + + if (!link) + hw_dbg(hw, "Link taking longer than expected.\n"); + + /* Try once more */ + ret_val = e1000e_phy_has_link_generic(hw, + PHY_FORCE_LIMIT, + 100000, + &link); + if (ret_val) + goto out; + } + +out: + return ret_val; +} + +/** + * e1000_get_phy_info_82577 - Retrieve I82577 PHY information + * @hw: pointer to the HW structure + * + * Read PHY status to determine if link is up. If link is up, then + * set/determine 10base-T extended distance and polarity correction. Read + * PHY port status to determine MDI/MDIx and speed. Based on the speed, + * determine on the cable length, local and remote receiver. + **/ +s32 e1000_get_phy_info_82577(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 data; + bool link; + + ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link); + if (ret_val) + goto out; + + if (!link) { + hw_dbg(hw, "Phy info is only valid if link is up\n"); + ret_val = -E1000_ERR_CONFIG; + goto out; + } + + phy->polarity_correction = true; + + ret_val = e1000_check_polarity_82577(hw); + if (ret_val) + goto out; + + ret_val = phy->ops.read_phy_reg(hw, I82577_PHY_STATUS_2, &data); + if (ret_val) + goto out; + + phy->is_mdix = (data & I82577_PHY_STATUS2_MDIX) ? true : false; + + if ((data & I82577_PHY_STATUS2_SPEED_MASK) == + I82577_PHY_STATUS2_SPEED_1000MBPS) { + ret_val = hw->phy.ops.get_cable_length(hw); + if (ret_val) + goto out; + + ret_val = phy->ops.read_phy_reg(hw, PHY_1000T_STATUS, &data); + if (ret_val) + goto out; + + phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS) + ? e1000_1000t_rx_status_ok + : e1000_1000t_rx_status_not_ok; + + phy->remote_rx = (data & SR_1000T_REMOTE_RX_STATUS) + ? e1000_1000t_rx_status_ok + : e1000_1000t_rx_status_not_ok; + } else { + phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED; + phy->local_rx = e1000_1000t_rx_status_undefined; + phy->remote_rx = e1000_1000t_rx_status_undefined; + } + +out: + return ret_val; +} + +/** + * e1000_get_cable_length_82577 - Determine cable length for 82577 PHY + * @hw: pointer to the HW structure + * + * Reads the diagnostic status register and verifies result is valid before + * placing it in the phy_cable_length field. + **/ +s32 e1000_get_cable_length_82577(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_data, length; + + ret_val = phy->ops.read_phy_reg(hw, I82577_PHY_DIAG_STATUS, &phy_data); + if (ret_val) + goto out; + + length = (phy_data & I82577_DSTATUS_CABLE_LENGTH) >> + I82577_DSTATUS_CABLE_LENGTH_SHIFT; + + if (length == E1000_CABLE_LENGTH_UNDEFINED) + ret_val = E1000_ERR_PHY; + + phy->cable_length = length; + +out: + return ret_val; +} diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h index 16a41389575a..78952f8324e2 100644 --- a/drivers/net/ehea/ehea.h +++ b/drivers/net/ehea/ehea.h @@ -268,7 +268,7 @@ struct ehea_qp_init_attr { }; /* - * Event Queue attributes, passed as paramter + * Event Queue attributes, passed as parameter */ struct ehea_eq_attr { u32 type; diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index b22dab9153f6..147c4b088fb3 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -3261,7 +3261,7 @@ static ssize_t ehea_probe_port(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct ehea_adapter *adapter = dev->driver_data; + struct ehea_adapter *adapter = dev_get_drvdata(dev); struct ehea_port *port; struct device_node *eth_dn = NULL; int i; @@ -3316,7 +3316,7 @@ static ssize_t ehea_remove_port(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct ehea_adapter *adapter = dev->driver_data; + struct ehea_adapter *adapter = dev_get_drvdata(dev); struct ehea_port *port; int i; u32 logical_port_id; @@ -3404,7 +3404,7 @@ static int __devinit ehea_probe_adapter(struct of_device *dev, adapter->pd = EHEA_PD_ID; - dev->dev.driver_data = adapter; + dev_set_drvdata(&dev->dev, adapter); /* initialize adapter and ports */ @@ -3468,7 +3468,7 @@ out: static int __devexit ehea_remove(struct of_device *dev) { - struct ehea_adapter *adapter = dev->dev.driver_data; + struct ehea_adapter *adapter = dev_get_drvdata(&dev->dev); int i; for (i = 0; i < EHEA_MAX_PORTS; i++) diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index 9080f07da8fe..8005b602f776 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -661,8 +661,6 @@ static int enic_hard_start_xmit(struct sk_buff *skb, struct net_device *netdev) if (vnic_wq_desc_avail(wq) < MAX_SKB_FRAGS + 1) netif_stop_queue(netdev); - netdev->trans_start = jiffies; - spin_unlock_irqrestore(&enic->wq_lock[0], flags); return NETDEV_TX_OK; diff --git a/drivers/net/eql.c b/drivers/net/eql.c index 5210bb1027cc..19b7dd983944 100644 --- a/drivers/net/eql.c +++ b/drivers/net/eql.c @@ -194,6 +194,7 @@ static void __init eql_setup(struct net_device *dev) dev->type = ARPHRD_SLIP; dev->tx_queue_len = 5; /* Hands them off fast */ + dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; } static int eql_open(struct net_device *dev) diff --git a/drivers/net/ethoc.c b/drivers/net/ethoc.c index 91a9b1a33764..ceb6a9c357ad 100644 --- a/drivers/net/ethoc.c +++ b/drivers/net/ethoc.c @@ -811,7 +811,7 @@ static int ethoc_start_xmit(struct sk_buff *skb, struct net_device *dev) if (unlikely(skb->len > ETHOC_BUFSIZ)) { priv->stats.tx_errors++; - return -EMSGSIZE; + goto out; } entry = priv->cur_tx % priv->num_tx; @@ -840,9 +840,9 @@ static int ethoc_start_xmit(struct sk_buff *skb, struct net_device *dev) } dev->trans_start = jiffies; - dev_kfree_skb(skb); - spin_unlock_irq(&priv->lock); +out: + dev_kfree_skb(skb); return NETDEV_TX_OK; } diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c index 1a685a04d4b2..1e9723281405 100644 --- a/drivers/net/ewrk3.c +++ b/drivers/net/ewrk3.c @@ -873,7 +873,7 @@ static int ewrk3_queue_pkt (struct sk_buff *skb, struct net_device *dev) err_out: ENABLE_IRQs; spin_unlock_irq (&lp->hw_lock); - return 1; + return NETDEV_TX_BUSY; } /* diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 682e7f0b5581..0f19b743749b 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -86,8 +86,7 @@ static unsigned char fec_mac_default[] = { #endif #endif /* CONFIG_M5272 */ -/* Forward declarations of some structures to support different PHYs -*/ +/* Forward declarations of some structures to support different PHYs */ typedef struct { uint mii_data; @@ -123,8 +122,7 @@ typedef struct { #error "FEC: descriptor ring size constants too large" #endif -/* Interrupt events/masks. -*/ +/* Interrupt events/masks. */ #define FEC_ENET_HBERR ((uint)0x80000000) /* Heartbeat error */ #define FEC_ENET_BABR ((uint)0x40000000) /* Babbling receiver */ #define FEC_ENET_BABT ((uint)0x20000000) /* Babbling transmitter */ @@ -165,7 +163,7 @@ typedef struct { */ struct fec_enet_private { /* Hardware registers of the FEC device */ - volatile fec_t *hwp; + void __iomem *hwp; struct net_device *netdev; @@ -174,16 +172,20 @@ struct fec_enet_private { /* The saved address of a sent-in-place packet/buffer, for skfree(). */ unsigned char *tx_bounce[TX_RING_SIZE]; struct sk_buff* tx_skbuff[TX_RING_SIZE]; + struct sk_buff* rx_skbuff[RX_RING_SIZE]; ushort skb_cur; ushort skb_dirty; - /* CPM dual port RAM relative addresses. - */ + /* CPM dual port RAM relative addresses */ dma_addr_t bd_dma; - cbd_t *rx_bd_base; /* Address of Rx and Tx buffers. */ - cbd_t *tx_bd_base; - cbd_t *cur_rx, *cur_tx; /* The next free ring entry */ - cbd_t *dirty_tx; /* The ring entries to be free()ed. */ + /* Address of Rx and Tx buffers */ + struct bufdesc *rx_bd_base; + struct bufdesc *tx_bd_base; + /* The next free ring entry */ + struct bufdesc *cur_rx, *cur_tx; + /* The ring entries to be free()ed */ + struct bufdesc *dirty_tx; + uint tx_full; /* hold while accessing the HW like ringbuffer for tx/rx but not MAC */ spinlock_t hw_lock; @@ -209,17 +211,13 @@ struct fec_enet_private { int full_duplex; }; -static int fec_enet_open(struct net_device *dev); -static int fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev); static void fec_enet_mii(struct net_device *dev); static irqreturn_t fec_enet_interrupt(int irq, void * dev_id); static void fec_enet_tx(struct net_device *dev); static void fec_enet_rx(struct net_device *dev); static int fec_enet_close(struct net_device *dev); -static void set_multicast_list(struct net_device *dev); static void fec_restart(struct net_device *dev, int duplex); static void fec_stop(struct net_device *dev); -static void fec_set_mac_address(struct net_device *dev); /* MII processing. We keep this as simple as possible. Requests are @@ -241,19 +239,16 @@ static mii_list_t *mii_tail; static int mii_queue(struct net_device *dev, int request, void (*func)(uint, struct net_device *)); -/* Make MII read/write commands for the FEC. -*/ +/* Make MII read/write commands for the FEC */ #define mk_mii_read(REG) (0x60020000 | ((REG & 0x1f) << 18)) #define mk_mii_write(REG, VAL) (0x50020000 | ((REG & 0x1f) << 18) | \ (VAL & 0xffff)) #define mk_mii_end 0 -/* Transmitter timeout. -*/ -#define TX_TIMEOUT (2*HZ) +/* Transmitter timeout */ +#define TX_TIMEOUT (2 * HZ) -/* Register definitions for the PHY. -*/ +/* Register definitions for the PHY */ #define MII_REG_CR 0 /* Control Register */ #define MII_REG_SR 1 /* Status Register */ @@ -288,18 +283,14 @@ static int mii_queue(struct net_device *dev, int request, static int fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct fec_enet_private *fep; - volatile fec_t *fecp; - volatile cbd_t *bdp; + struct fec_enet_private *fep = netdev_priv(dev); + struct bufdesc *bdp; unsigned short status; unsigned long flags; - fep = netdev_priv(dev); - fecp = (volatile fec_t*)dev->base_addr; - if (!fep->link) { /* Link is down or autonegotiation is in progress. */ - return 1; + return NETDEV_TX_BUSY; } spin_lock_irqsave(&fep->hw_lock, flags); @@ -307,30 +298,27 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) bdp = fep->cur_tx; status = bdp->cbd_sc; -#ifndef final_version + if (status & BD_ENET_TX_READY) { /* Ooops. All transmit buffers are full. Bail out. * This should not happen, since dev->tbusy should be set. */ printk("%s: tx queue full!.\n", dev->name); spin_unlock_irqrestore(&fep->hw_lock, flags); - return 1; + return NETDEV_TX_BUSY; } -#endif - /* Clear all of the status flags. - */ + /* Clear all of the status flags */ status &= ~BD_ENET_TX_STATS; - /* Set buffer length and buffer pointer. - */ + /* Set buffer length and buffer pointer */ bdp->cbd_bufaddr = __pa(skb->data); bdp->cbd_datlen = skb->len; /* - * On some FEC implementations data must be aligned on - * 4-byte boundaries. Use bounce buffers to copy data - * and get it aligned. Ugh. + * On some FEC implementations data must be aligned on + * 4-byte boundaries. Use bounce buffers to copy data + * and get it aligned. Ugh. */ if (bdp->cbd_bufaddr & FEC_ALIGNMENT) { unsigned int index; @@ -339,8 +327,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) bdp->cbd_bufaddr = __pa(fep->tx_bounce[index]); } - /* Save skb pointer. - */ + /* Save skb pointer */ fep->tx_skbuff[fep->skb_cur] = skb; dev->stats.tx_bytes += skb->len; @@ -349,13 +336,12 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Push the data cache so the CPM does not get stale memory * data. */ - dma_sync_single(NULL, bdp->cbd_bufaddr, - bdp->cbd_datlen, DMA_TO_DEVICE); + bdp->cbd_bufaddr = dma_map_single(&dev->dev, skb->data, + FEC_ENET_TX_FRSIZE, DMA_TO_DEVICE); /* Send it on its way. Tell FEC it's ready, interrupt when done, * it's the last BD of the frame, and to put the CRC on the end. */ - status |= (BD_ENET_TX_READY | BD_ENET_TX_INTR | BD_ENET_TX_LAST | BD_ENET_TX_TC); bdp->cbd_sc = status; @@ -363,22 +349,20 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; /* Trigger transmission start */ - fecp->fec_x_des_active = 0; + writel(0, fep->hwp + FEC_X_DES_ACTIVE); - /* If this was the last BD in the ring, start at the beginning again. - */ - if (status & BD_ENET_TX_WRAP) { + /* If this was the last BD in the ring, start at the beginning again. */ + if (status & BD_ENET_TX_WRAP) bdp = fep->tx_bd_base; - } else { + else bdp++; - } if (bdp == fep->dirty_tx) { fep->tx_full = 1; netif_stop_queue(dev); } - fep->cur_tx = (cbd_t *)bdp; + fep->cur_tx = bdp; spin_unlock_irqrestore(&fep->hw_lock, flags); @@ -390,75 +374,33 @@ fec_timeout(struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); - printk("%s: transmit timed out.\n", dev->name); dev->stats.tx_errors++; -#ifndef final_version - { - int i; - cbd_t *bdp; - printk("Ring data dump: cur_tx %lx%s, dirty_tx %lx cur_rx: %lx\n", - (unsigned long)fep->cur_tx, fep->tx_full ? " (full)" : "", - (unsigned long)fep->dirty_tx, - (unsigned long)fep->cur_rx); - - bdp = fep->tx_bd_base; - printk(" tx: %u buffers\n", TX_RING_SIZE); - for (i = 0 ; i < TX_RING_SIZE; i++) { - printk(" %08x: %04x %04x %08x\n", - (uint) bdp, - bdp->cbd_sc, - bdp->cbd_datlen, - (int) bdp->cbd_bufaddr); - bdp++; - } - - bdp = fep->rx_bd_base; - printk(" rx: %lu buffers\n", (unsigned long) RX_RING_SIZE); - for (i = 0 ; i < RX_RING_SIZE; i++) { - printk(" %08x: %04x %04x %08x\n", - (uint) bdp, - bdp->cbd_sc, - bdp->cbd_datlen, - (int) bdp->cbd_bufaddr); - bdp++; - } - } -#endif fec_restart(dev, fep->full_duplex); netif_wake_queue(dev); } -/* The interrupt handler. - * This is called from the MPC core interrupt. - */ static irqreturn_t fec_enet_interrupt(int irq, void * dev_id) { struct net_device *dev = dev_id; - volatile fec_t *fecp; + struct fec_enet_private *fep = netdev_priv(dev); uint int_events; irqreturn_t ret = IRQ_NONE; - fecp = (volatile fec_t*)dev->base_addr; - - /* Get the interrupt events that caused us to be here. - */ do { - int_events = fecp->fec_ievent; - fecp->fec_ievent = int_events; + int_events = readl(fep->hwp + FEC_IEVENT); + writel(int_events, fep->hwp + FEC_IEVENT); - /* Handle receive event in its own function. - */ if (int_events & FEC_ENET_RXF) { ret = IRQ_HANDLED; fec_enet_rx(dev); } /* Transmit OK, or non-fatal error. Update the buffer - descriptors. FEC handles all errors, we just discover - them as part of the transmit process. - */ + * descriptors. FEC handles all errors, we just discover + * them as part of the transmit process. + */ if (int_events & FEC_ENET_TXF) { ret = IRQ_HANDLED; fec_enet_tx(dev); @@ -479,7 +421,7 @@ static void fec_enet_tx(struct net_device *dev) { struct fec_enet_private *fep; - volatile cbd_t *bdp; + struct bufdesc *bdp; unsigned short status; struct sk_buff *skb; @@ -488,7 +430,11 @@ fec_enet_tx(struct net_device *dev) bdp = fep->dirty_tx; while (((status = bdp->cbd_sc) & BD_ENET_TX_READY) == 0) { - if (bdp == fep->cur_tx && fep->tx_full == 0) break; + if (bdp == fep->cur_tx && fep->tx_full == 0) + break; + + dma_unmap_single(&dev->dev, bdp->cbd_bufaddr, FEC_ENET_TX_FRSIZE, DMA_TO_DEVICE); + bdp->cbd_bufaddr = 0; skb = fep->tx_skbuff[fep->skb_dirty]; /* Check for errors. */ @@ -510,31 +456,27 @@ fec_enet_tx(struct net_device *dev) dev->stats.tx_packets++; } -#ifndef final_version if (status & BD_ENET_TX_READY) printk("HEY! Enet xmit interrupt and TX_READY.\n"); -#endif + /* Deferred means some collisions occurred during transmit, * but we eventually sent the packet OK. */ if (status & BD_ENET_TX_DEF) dev->stats.collisions++; - /* Free the sk buffer associated with this last transmit. - */ + /* Free the sk buffer associated with this last transmit */ dev_kfree_skb_any(skb); fep->tx_skbuff[fep->skb_dirty] = NULL; fep->skb_dirty = (fep->skb_dirty + 1) & TX_RING_MOD_MASK; - /* Update pointer to next buffer descriptor to be transmitted. - */ + /* Update pointer to next buffer descriptor to be transmitted */ if (status & BD_ENET_TX_WRAP) bdp = fep->tx_bd_base; else bdp++; - /* Since we have freed up a buffer, the ring is no longer - * full. + /* Since we have freed up a buffer, the ring is no longer full */ if (fep->tx_full) { fep->tx_full = 0; @@ -542,7 +484,7 @@ fec_enet_tx(struct net_device *dev) netif_wake_queue(dev); } } - fep->dirty_tx = (cbd_t *)bdp; + fep->dirty_tx = bdp; spin_unlock_irq(&fep->hw_lock); } @@ -555,9 +497,8 @@ fec_enet_tx(struct net_device *dev) static void fec_enet_rx(struct net_device *dev) { - struct fec_enet_private *fep; - volatile fec_t *fecp; - volatile cbd_t *bdp; + struct fec_enet_private *fep = netdev_priv(dev); + struct bufdesc *bdp; unsigned short status; struct sk_buff *skb; ushort pkt_len; @@ -567,9 +508,6 @@ fec_enet_rx(struct net_device *dev) flush_cache_all(); #endif - fep = netdev_priv(dev); - fecp = (volatile fec_t*)dev->base_addr; - spin_lock_irq(&fep->hw_lock); /* First, grab all of the stats for the incoming packet. @@ -577,143 +515,121 @@ fec_enet_rx(struct net_device *dev) */ bdp = fep->cur_rx; -while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) { + while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) { -#ifndef final_version - /* Since we have allocated space to hold a complete frame, - * the last indicator should be set. - */ - if ((status & BD_ENET_RX_LAST) == 0) - printk("FEC ENET: rcv is not +last\n"); -#endif + /* Since we have allocated space to hold a complete frame, + * the last indicator should be set. + */ + if ((status & BD_ENET_RX_LAST) == 0) + printk("FEC ENET: rcv is not +last\n"); - if (!fep->opened) - goto rx_processing_done; + if (!fep->opened) + goto rx_processing_done; - /* Check for errors. */ - if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO | + /* Check for errors. */ + if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO | BD_ENET_RX_CR | BD_ENET_RX_OV)) { - dev->stats.rx_errors++; - if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH)) { - /* Frame too long or too short. */ - dev->stats.rx_length_errors++; + dev->stats.rx_errors++; + if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH)) { + /* Frame too long or too short. */ + dev->stats.rx_length_errors++; + } + if (status & BD_ENET_RX_NO) /* Frame alignment */ + dev->stats.rx_frame_errors++; + if (status & BD_ENET_RX_CR) /* CRC Error */ + dev->stats.rx_crc_errors++; + if (status & BD_ENET_RX_OV) /* FIFO overrun */ + dev->stats.rx_fifo_errors++; } - if (status & BD_ENET_RX_NO) /* Frame alignment */ + + /* Report late collisions as a frame error. + * On this error, the BD is closed, but we don't know what we + * have in the buffer. So, just drop this frame on the floor. + */ + if (status & BD_ENET_RX_CL) { + dev->stats.rx_errors++; dev->stats.rx_frame_errors++; - if (status & BD_ENET_RX_CR) /* CRC Error */ - dev->stats.rx_crc_errors++; - if (status & BD_ENET_RX_OV) /* FIFO overrun */ - dev->stats.rx_fifo_errors++; + goto rx_processing_done; + } + + /* Process the incoming frame. */ + dev->stats.rx_packets++; + pkt_len = bdp->cbd_datlen; + dev->stats.rx_bytes += pkt_len; + data = (__u8*)__va(bdp->cbd_bufaddr); + + dma_unmap_single(NULL, bdp->cbd_bufaddr, bdp->cbd_datlen, + DMA_FROM_DEVICE); + + /* This does 16 byte alignment, exactly what we need. + * The packet length includes FCS, but we don't want to + * include that when passing upstream as it messes up + * bridging applications. + */ + skb = dev_alloc_skb(pkt_len - 4 + NET_IP_ALIGN); + + if (unlikely(!skb)) { + printk("%s: Memory squeeze, dropping packet.\n", + dev->name); + dev->stats.rx_dropped++; + } else { + skb_reserve(skb, NET_IP_ALIGN); + skb_put(skb, pkt_len - 4); /* Make room */ + skb_copy_to_linear_data(skb, data, pkt_len - 4); + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); + } + + bdp->cbd_bufaddr = dma_map_single(NULL, data, bdp->cbd_datlen, + DMA_FROM_DEVICE); +rx_processing_done: + /* Clear the status flags for this buffer */ + status &= ~BD_ENET_RX_STATS; + + /* Mark the buffer empty */ + status |= BD_ENET_RX_EMPTY; + bdp->cbd_sc = status; + + /* Update BD pointer to next entry */ + if (status & BD_ENET_RX_WRAP) + bdp = fep->rx_bd_base; + else + bdp++; + /* Doing this here will keep the FEC running while we process + * incoming frames. On a heavily loaded network, we should be + * able to keep up at the expense of system resources. + */ + writel(0, fep->hwp + FEC_R_DES_ACTIVE); } - - /* Report late collisions as a frame error. - * On this error, the BD is closed, but we don't know what we - * have in the buffer. So, just drop this frame on the floor. - */ - if (status & BD_ENET_RX_CL) { - dev->stats.rx_errors++; - dev->stats.rx_frame_errors++; - goto rx_processing_done; - } - - /* Process the incoming frame. - */ - dev->stats.rx_packets++; - pkt_len = bdp->cbd_datlen; - dev->stats.rx_bytes += pkt_len; - data = (__u8*)__va(bdp->cbd_bufaddr); - - dma_sync_single(NULL, (unsigned long)__pa(data), - pkt_len - 4, DMA_FROM_DEVICE); - - /* This does 16 byte alignment, exactly what we need. - * The packet length includes FCS, but we don't want to - * include that when passing upstream as it messes up - * bridging applications. - */ - skb = dev_alloc_skb(pkt_len-4); - - if (skb == NULL) { - printk("%s: Memory squeeze, dropping packet.\n", dev->name); - dev->stats.rx_dropped++; - } else { - skb_put(skb,pkt_len-4); /* Make room */ - skb_copy_to_linear_data(skb, data, pkt_len-4); - skb->protocol=eth_type_trans(skb,dev); - netif_rx(skb); - } - rx_processing_done: - - /* Clear the status flags for this buffer. - */ - status &= ~BD_ENET_RX_STATS; - - /* Mark the buffer empty. - */ - status |= BD_ENET_RX_EMPTY; - bdp->cbd_sc = status; - - /* Update BD pointer to next entry. - */ - if (status & BD_ENET_RX_WRAP) - bdp = fep->rx_bd_base; - else - bdp++; - -#if 1 - /* Doing this here will keep the FEC running while we process - * incoming frames. On a heavily loaded network, we should be - * able to keep up at the expense of system resources. - */ - fecp->fec_r_des_active = 0; -#endif - } /* while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) */ - fep->cur_rx = (cbd_t *)bdp; - -#if 0 - /* Doing this here will allow us to process all frames in the - * ring before the FEC is allowed to put more there. On a heavily - * loaded network, some frames may be lost. Unfortunately, this - * increases the interrupt overhead since we can potentially work - * our way back to the interrupt return only to come right back - * here. - */ - fecp->fec_r_des_active = 0; -#endif + fep->cur_rx = bdp; spin_unlock_irq(&fep->hw_lock); } - /* called from interrupt context */ static void fec_enet_mii(struct net_device *dev) { struct fec_enet_private *fep; - volatile fec_t *ep; mii_list_t *mip; - uint mii_reg; fep = netdev_priv(dev); spin_lock_irq(&fep->mii_lock); - ep = fep->hwp; - mii_reg = ep->fec_mii_data; - if ((mip = mii_head) == NULL) { printk("MII and no head!\n"); goto unlock; } if (mip->mii_func != NULL) - (*(mip->mii_func))(mii_reg, dev); + (*(mip->mii_func))(readl(fep->hwp + FEC_MII_DATA), dev); mii_head = mip->mii_next; mip->mii_next = mii_free; mii_free = mip; if ((mip = mii_head) != NULL) - ep->fec_mii_data = mip->mii_regval; + writel(mip->mii_regval, fep->hwp + FEC_MII_DATA); unlock: spin_unlock_irq(&fep->mii_lock); @@ -727,8 +643,7 @@ mii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_devi mii_list_t *mip; int retval; - /* Add PHY address to register command. - */ + /* Add PHY address to register command */ fep = netdev_priv(dev); spin_lock_irqsave(&fep->mii_lock, flags); @@ -745,7 +660,7 @@ mii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_devi mii_tail = mip; } else { mii_head = mii_tail = mip; - fep->hwp->fec_mii_data = regval; + writel(regval, fep->hwp + FEC_MII_DATA); } } else { retval = 1; @@ -1246,11 +1161,8 @@ static void __inline__ fec_phy_ack_intr(void) static void __inline__ fec_get_mac(struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); - volatile fec_t *fecp; unsigned char *iap, tmpaddr[ETH_ALEN]; - fecp = fep->hwp; - if (FEC_FLASHMAC) { /* * Get MAC address from FLASH. @@ -1264,8 +1176,8 @@ static void __inline__ fec_get_mac(struct net_device *dev) (iap[3] == 0xff) && (iap[4] == 0xff) && (iap[5] == 0xff)) iap = fec_mac_default; } else { - *((unsigned long *) &tmpaddr[0]) = fecp->fec_addr_low; - *((unsigned short *) &tmpaddr[4]) = (fecp->fec_addr_high >> 16); + *((unsigned long *) &tmpaddr[0]) = readl(fep->hwp + FEC_ADDR_LOW); + *((unsigned short *) &tmpaddr[4]) = (readl(fep->hwp + FEC_ADDR_HIGH) >> 16); iap = &tmpaddr[0]; } @@ -1375,11 +1287,6 @@ static void mii_relink(struct work_struct *work) fec_restart(dev, duplex); } else fec_stop(dev); - -#if 0 - enable_irq(fep->mii_irq); -#endif - } /* mii_queue_relink is called in interrupt context from mii_link_interrupt */ @@ -1388,12 +1295,12 @@ static void mii_queue_relink(uint mii_reg, struct net_device *dev) struct fec_enet_private *fep = netdev_priv(dev); /* - ** We cannot queue phy_task twice in the workqueue. It - ** would cause an endless loop in the workqueue. - ** Fortunately, if the last mii_relink entry has not yet been - ** executed now, it will do the job for the current interrupt, - ** which is just what we want. - */ + * We cannot queue phy_task twice in the workqueue. It + * would cause an endless loop in the workqueue. + * Fortunately, if the last mii_relink entry has not yet been + * executed now, it will do the job for the current interrupt, + * which is just what we want. + */ if (fep->mii_phy_task_queued) return; @@ -1424,8 +1331,7 @@ phy_cmd_t const phy_cmd_config[] = { { mk_mii_end, } }; -/* Read remainder of PHY ID. -*/ +/* Read remainder of PHY ID. */ static void mii_discover_phy3(uint mii_reg, struct net_device *dev) { @@ -1457,17 +1363,14 @@ static void mii_discover_phy(uint mii_reg, struct net_device *dev) { struct fec_enet_private *fep; - volatile fec_t *fecp; uint phytype; fep = netdev_priv(dev); - fecp = fep->hwp; if (fep->phy_addr < 32) { if ((phytype = (mii_reg & 0xffff)) != 0xffff && phytype != 0) { - /* Got first part of ID, now get remainder. - */ + /* Got first part of ID, now get remainder */ fep->phy_id = phytype << 16; mii_queue(dev, mk_mii_read(MII_REG_PHYIR2), mii_discover_phy3); @@ -1479,15 +1382,15 @@ mii_discover_phy(uint mii_reg, struct net_device *dev) } else { printk("FEC: No PHY device found.\n"); /* Disable external MII interface */ - fecp->fec_mii_speed = fep->phy_speed = 0; + writel(0, fep->hwp + FEC_MII_SPEED); + fep->phy_speed = 0; #ifdef HAVE_mii_link_interrupt fec_disable_phy_intr(); #endif } } -/* This interrupt occurs when the PHY detects a link change. -*/ +/* This interrupt occurs when the PHY detects a link change */ #ifdef HAVE_mii_link_interrupt static irqreturn_t mii_link_interrupt(int irq, void * dev_id) @@ -1497,10 +1400,6 @@ mii_link_interrupt(int irq, void * dev_id) fec_phy_ack_intr(); -#if 0 - disable_irq(fep->mii_irq); /* disable now, enable later */ -#endif - mii_do_cmd(dev, fep->phy->ack_int); mii_do_cmd(dev, phy_cmd_relink); /* restart and display status */ @@ -1508,19 +1407,91 @@ mii_link_interrupt(int irq, void * dev_id) } #endif +static void fec_enet_free_buffers(struct net_device *dev) +{ + struct fec_enet_private *fep = netdev_priv(dev); + int i; + struct sk_buff *skb; + struct bufdesc *bdp; + + bdp = fep->rx_bd_base; + for (i = 0; i < RX_RING_SIZE; i++) { + skb = fep->rx_skbuff[i]; + + if (bdp->cbd_bufaddr) + dma_unmap_single(&dev->dev, bdp->cbd_bufaddr, + FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE); + if (skb) + dev_kfree_skb(skb); + bdp++; + } + + bdp = fep->tx_bd_base; + for (i = 0; i < TX_RING_SIZE; i++) + kfree(fep->tx_bounce[i]); +} + +static int fec_enet_alloc_buffers(struct net_device *dev) +{ + struct fec_enet_private *fep = netdev_priv(dev); + int i; + struct sk_buff *skb; + struct bufdesc *bdp; + + bdp = fep->rx_bd_base; + for (i = 0; i < RX_RING_SIZE; i++) { + skb = dev_alloc_skb(FEC_ENET_RX_FRSIZE); + if (!skb) { + fec_enet_free_buffers(dev); + return -ENOMEM; + } + fep->rx_skbuff[i] = skb; + + bdp->cbd_bufaddr = dma_map_single(&dev->dev, skb->data, + FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE); + bdp->cbd_sc = BD_ENET_RX_EMPTY; + bdp++; + } + + /* Set the last buffer to wrap. */ + bdp--; + bdp->cbd_sc |= BD_SC_WRAP; + + bdp = fep->tx_bd_base; + for (i = 0; i < TX_RING_SIZE; i++) { + fep->tx_bounce[i] = kmalloc(FEC_ENET_TX_FRSIZE, GFP_KERNEL); + + bdp->cbd_sc = 0; + bdp->cbd_bufaddr = 0; + bdp++; + } + + /* Set the last buffer to wrap. */ + bdp--; + bdp->cbd_sc |= BD_SC_WRAP; + + return 0; +} + static int fec_enet_open(struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); + int ret; /* I should reset the ring buffers here, but I don't yet know * a simple way to do that. */ - fec_set_mac_address(dev); + + ret = fec_enet_alloc_buffers(dev); + if (ret) + return ret; fep->sequence_done = 0; fep->link = 0; + fec_restart(dev, 1); + if (fep->phy) { mii_do_cmd(dev, fep->phy->ack_int); mii_do_cmd(dev, fep->phy->config); @@ -1537,21 +1508,17 @@ fec_enet_open(struct net_device *dev) schedule(); mii_do_cmd(dev, fep->phy->startup); - - /* Set the initial link state to true. A lot of hardware - * based on this device does not implement a PHY interrupt, - * so we are never notified of link change. - */ - fep->link = 1; - } else { - fep->link = 1; /* lets just try it and see */ - /* no phy, go full duplex, it's most likely a hub chip */ - fec_restart(dev, 1); } + /* Set the initial link state to true. A lot of hardware + * based on this device does not implement a PHY interrupt, + * so we are never notified of link change. + */ + fep->link = 1; + netif_start_queue(dev); fep->opened = 1; - return 0; /* Success */ + return 0; } static int @@ -1559,12 +1526,13 @@ fec_enet_close(struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); - /* Don't know what to do yet. - */ + /* Don't know what to do yet. */ fep->opened = 0; netif_stop_queue(dev); fec_stop(dev); + fec_enet_free_buffers(dev); + return 0; } @@ -1583,87 +1551,102 @@ fec_enet_close(struct net_device *dev) static void set_multicast_list(struct net_device *dev) { - struct fec_enet_private *fep; - volatile fec_t *ep; + struct fec_enet_private *fep = netdev_priv(dev); struct dev_mc_list *dmi; - unsigned int i, j, bit, data, crc; + unsigned int i, j, bit, data, crc, tmp; unsigned char hash; - fep = netdev_priv(dev); - ep = fep->hwp; + if (dev->flags & IFF_PROMISC) { + tmp = readl(fep->hwp + FEC_R_CNTRL); + tmp |= 0x8; + writel(tmp, fep->hwp + FEC_R_CNTRL); + return; + } - if (dev->flags&IFF_PROMISC) { - ep->fec_r_cntrl |= 0x0008; - } else { + tmp = readl(fep->hwp + FEC_R_CNTRL); + tmp &= ~0x8; + writel(tmp, fep->hwp + FEC_R_CNTRL); - ep->fec_r_cntrl &= ~0x0008; + if (dev->flags & IFF_ALLMULTI) { + /* Catch all multicast addresses, so set the + * filter to all 1's + */ + writel(0xffffffff, fep->hwp + FEC_GRP_HASH_TABLE_HIGH); + writel(0xffffffff, fep->hwp + FEC_GRP_HASH_TABLE_LOW); - if (dev->flags & IFF_ALLMULTI) { - /* Catch all multicast addresses, so set the - * filter to all 1's. - */ - ep->fec_grp_hash_table_high = 0xffffffff; - ep->fec_grp_hash_table_low = 0xffffffff; - } else { - /* Clear filter and add the addresses in hash register. - */ - ep->fec_grp_hash_table_high = 0; - ep->fec_grp_hash_table_low = 0; + return; + } - dmi = dev->mc_list; + /* Clear filter and add the addresses in hash register + */ + writel(0, fep->hwp + FEC_GRP_HASH_TABLE_HIGH); + writel(0, fep->hwp + FEC_GRP_HASH_TABLE_LOW); - for (j = 0; j < dev->mc_count; j++, dmi = dmi->next) - { - /* Only support group multicast for now. - */ - if (!(dmi->dmi_addr[0] & 1)) - continue; + dmi = dev->mc_list; - /* calculate crc32 value of mac address - */ - crc = 0xffffffff; + for (j = 0; j < dev->mc_count; j++, dmi = dmi->next) { + /* Only support group multicast for now */ + if (!(dmi->dmi_addr[0] & 1)) + continue; - for (i = 0; i < dmi->dmi_addrlen; i++) - { - data = dmi->dmi_addr[i]; - for (bit = 0; bit < 8; bit++, data >>= 1) - { - crc = (crc >> 1) ^ - (((crc ^ data) & 1) ? CRC32_POLY : 0); - } - } + /* calculate crc32 value of mac address */ + crc = 0xffffffff; - /* only upper 6 bits (HASH_BITS) are used - which point to specific bit in he hash registers - */ - hash = (crc >> (32 - HASH_BITS)) & 0x3f; - - if (hash > 31) - ep->fec_grp_hash_table_high |= 1 << (hash - 32); - else - ep->fec_grp_hash_table_low |= 1 << hash; + for (i = 0; i < dmi->dmi_addrlen; i++) { + data = dmi->dmi_addr[i]; + for (bit = 0; bit < 8; bit++, data >>= 1) { + crc = (crc >> 1) ^ + (((crc ^ data) & 1) ? CRC32_POLY : 0); } } + + /* only upper 6 bits (HASH_BITS) are used + * which point to specific bit in he hash registers + */ + hash = (crc >> (32 - HASH_BITS)) & 0x3f; + + if (hash > 31) { + tmp = readl(fep->hwp + FEC_GRP_HASH_TABLE_HIGH); + tmp |= 1 << (hash - 32); + writel(tmp, fep->hwp + FEC_GRP_HASH_TABLE_HIGH); + } else { + tmp = readl(fep->hwp + FEC_GRP_HASH_TABLE_LOW); + tmp |= 1 << hash; + writel(tmp, fep->hwp + FEC_GRP_HASH_TABLE_LOW); + } } } -/* Set a MAC change in hardware. - */ -static void -fec_set_mac_address(struct net_device *dev) +/* Set a MAC change in hardware. */ +static int +fec_set_mac_address(struct net_device *dev, void *p) { - volatile fec_t *fecp; + struct fec_enet_private *fep = netdev_priv(dev); + struct sockaddr *addr = p; - fecp = ((struct fec_enet_private *)netdev_priv(dev))->hwp; + if (!is_valid_ether_addr(addr->sa_data)) + return -EADDRNOTAVAIL; - /* Set station address. */ - fecp->fec_addr_low = dev->dev_addr[3] | (dev->dev_addr[2] << 8) | - (dev->dev_addr[1] << 16) | (dev->dev_addr[0] << 24); - fecp->fec_addr_high = (dev->dev_addr[5] << 16) | - (dev->dev_addr[4] << 24); + memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); + writel(dev->dev_addr[3] | (dev->dev_addr[2] << 8) | + (dev->dev_addr[1] << 16) | (dev->dev_addr[0] << 24), + fep->hwp + FEC_ADDR_LOW); + writel((dev->dev_addr[5] << 16) | (dev->dev_addr[4] << 24), + fep + FEC_ADDR_HIGH); + return 0; } +static const struct net_device_ops fec_netdev_ops = { + .ndo_open = fec_enet_open, + .ndo_stop = fec_enet_close, + .ndo_start_xmit = fec_enet_start_xmit, + .ndo_set_multicast_list = set_multicast_list, + .ndo_validate_addr = eth_validate_addr, + .ndo_tx_timeout = fec_timeout, + .ndo_set_mac_address = fec_set_mac_address, +}; + /* * XXX: We need to clean up on failure exits here. * @@ -1672,17 +1655,13 @@ fec_set_mac_address(struct net_device *dev) int __init fec_enet_init(struct net_device *dev, int index) { struct fec_enet_private *fep = netdev_priv(dev); - unsigned long mem_addr; - volatile cbd_t *bdp; - cbd_t *cbd_base; - volatile fec_t *fecp; - int i, j; + struct bufdesc *cbd_base; + int i; - /* Allocate memory for buffer descriptors. - */ - mem_addr = (unsigned long)dma_alloc_coherent(NULL, PAGE_SIZE, - &fep->bd_dma, GFP_KERNEL); - if (mem_addr == 0) { + /* Allocate memory for buffer descriptors. */ + cbd_base = dma_alloc_coherent(NULL, PAGE_SIZE, &fep->bd_dma, + GFP_KERNEL); + if (!cbd_base) { printk("FEC: allocate descriptor memory failed?\n"); return -ENOMEM; } @@ -1690,146 +1669,47 @@ int __init fec_enet_init(struct net_device *dev, int index) spin_lock_init(&fep->hw_lock); spin_lock_init(&fep->mii_lock); - /* Create an Ethernet device instance. - */ - fecp = (volatile fec_t *)dev->base_addr; - fep->index = index; - fep->hwp = fecp; + fep->hwp = (void __iomem *)dev->base_addr; fep->netdev = dev; - /* Whack a reset. We should wait for this. - */ - fecp->fec_ecntrl = 1; - udelay(10); - /* Set the Ethernet address */ #ifdef CONFIG_M5272 fec_get_mac(dev); #else { unsigned long l; - l = fecp->fec_addr_low; + l = readl(fep->hwp + FEC_ADDR_LOW); dev->dev_addr[0] = (unsigned char)((l & 0xFF000000) >> 24); dev->dev_addr[1] = (unsigned char)((l & 0x00FF0000) >> 16); dev->dev_addr[2] = (unsigned char)((l & 0x0000FF00) >> 8); dev->dev_addr[3] = (unsigned char)((l & 0x000000FF) >> 0); - l = fecp->fec_addr_high; + l = readl(fep->hwp + FEC_ADDR_HIGH); dev->dev_addr[4] = (unsigned char)((l & 0xFF000000) >> 24); dev->dev_addr[5] = (unsigned char)((l & 0x00FF0000) >> 16); } #endif - cbd_base = (cbd_t *)mem_addr; - - /* Set receive and transmit descriptor base. - */ + /* Set receive and transmit descriptor base. */ fep->rx_bd_base = cbd_base; fep->tx_bd_base = cbd_base + RX_RING_SIZE; - fep->dirty_tx = fep->cur_tx = fep->tx_bd_base; - fep->cur_rx = fep->rx_bd_base; - - fep->skb_cur = fep->skb_dirty = 0; - - /* Initialize the receive buffer descriptors. - */ - bdp = fep->rx_bd_base; - for (i=0; icbd_sc = BD_ENET_RX_EMPTY; - bdp->cbd_bufaddr = __pa(mem_addr); - mem_addr += FEC_ENET_RX_FRSIZE; - bdp++; - } - } - - /* Set the last buffer to wrap. - */ - bdp--; - bdp->cbd_sc |= BD_SC_WRAP; - - /* ...and the same for transmmit. - */ - bdp = fep->tx_bd_base; - for (i=0, j=FEC_ENET_TX_FRPPG; i= FEC_ENET_TX_FRPPG) { - mem_addr = __get_free_page(GFP_KERNEL); - j = 1; - } else { - mem_addr += FEC_ENET_TX_FRSIZE; - j++; - } - fep->tx_bounce[i] = (unsigned char *) mem_addr; - - /* Initialize the BD for every fragment in the page. - */ - bdp->cbd_sc = 0; - bdp->cbd_bufaddr = 0; - bdp++; - } - - /* Set the last buffer to wrap. - */ - bdp--; - bdp->cbd_sc |= BD_SC_WRAP; - - /* Set receive and transmit descriptor base. - */ - fecp->fec_r_des_start = fep->bd_dma; - fecp->fec_x_des_start = (unsigned long)fep->bd_dma + sizeof(cbd_t) - * RX_RING_SIZE; - #ifdef HAVE_mii_link_interrupt fec_request_mii_intr(dev); #endif - - fecp->fec_grp_hash_table_high = 0; - fecp->fec_grp_hash_table_low = 0; - fecp->fec_r_buff_size = PKT_MAXBLR_SIZE; - fecp->fec_ecntrl = 2; - fecp->fec_r_des_active = 0; -#ifndef CONFIG_M5272 - fecp->fec_hash_table_high = 0; - fecp->fec_hash_table_low = 0; -#endif - - /* The FEC Ethernet specific entries in the device structure. */ - dev->open = fec_enet_open; - dev->hard_start_xmit = fec_enet_start_xmit; - dev->tx_timeout = fec_timeout; + /* The FEC Ethernet specific entries in the device structure */ dev->watchdog_timeo = TX_TIMEOUT; - dev->stop = fec_enet_close; - dev->set_multicast_list = set_multicast_list; + dev->netdev_ops = &fec_netdev_ops; for (i=0; ifec_r_cntrl = OPT_FRAME_SIZE | 0x04; - fecp->fec_x_cntrl = 0x00; - - /* - * Set MII speed to 2.5 MHz - */ + /* Set MII speed to 2.5 MHz */ fep->phy_speed = ((((clk_get_rate(fep->clk) / 2 + 4999999) / 2500000) / 2) & 0x3F) << 1; - fecp->fec_mii_speed = fep->phy_speed; fec_restart(dev, 0); - /* Clear and enable interrupts */ - fecp->fec_ievent = 0xffc00000; - fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII); - /* Queue up command to detect the PHY and initialize the * remainder of the interface. */ @@ -1847,145 +1727,118 @@ int __init fec_enet_init(struct net_device *dev, int index) static void fec_restart(struct net_device *dev, int duplex) { - struct fec_enet_private *fep; - volatile cbd_t *bdp; - volatile fec_t *fecp; + struct fec_enet_private *fep = netdev_priv(dev); + struct bufdesc *bdp; int i; - fep = netdev_priv(dev); - fecp = fep->hwp; - - /* Whack a reset. We should wait for this. - */ - fecp->fec_ecntrl = 1; + /* Whack a reset. We should wait for this. */ + writel(1, fep->hwp + FEC_ECNTRL); udelay(10); - /* Clear any outstanding interrupt. - */ - fecp->fec_ievent = 0xffc00000; + /* Clear any outstanding interrupt. */ + writel(0xffc00000, fep->hwp + FEC_IEVENT); - /* Set station address. - */ - fec_set_mac_address(dev); + /* Reset all multicast. */ + writel(0, fep->hwp + FEC_GRP_HASH_TABLE_HIGH); + writel(0, fep->hwp + FEC_GRP_HASH_TABLE_LOW); +#ifndef CONFIG_M5272 + writel(0, fep->hwp + FEC_HASH_TABLE_HIGH); + writel(0, fep->hwp + FEC_HASH_TABLE_LOW); +#endif - /* Reset all multicast. - */ - fecp->fec_grp_hash_table_high = 0; - fecp->fec_grp_hash_table_low = 0; + /* Set maximum receive buffer size. */ + writel(PKT_MAXBLR_SIZE, fep->hwp + FEC_R_BUFF_SIZE); - /* Set maximum receive buffer size. - */ - fecp->fec_r_buff_size = PKT_MAXBLR_SIZE; - - /* Set receive and transmit descriptor base. - */ - fecp->fec_r_des_start = fep->bd_dma; - fecp->fec_x_des_start = (unsigned long)fep->bd_dma + sizeof(cbd_t) - * RX_RING_SIZE; + /* Set receive and transmit descriptor base. */ + writel(fep->bd_dma, fep->hwp + FEC_R_DES_START); + writel((unsigned long)fep->bd_dma + sizeof(struct bufdesc) * RX_RING_SIZE, + fep->hwp + FEC_X_DES_START); fep->dirty_tx = fep->cur_tx = fep->tx_bd_base; fep->cur_rx = fep->rx_bd_base; - /* Reset SKB transmit buffers. - */ + /* Reset SKB transmit buffers. */ fep->skb_cur = fep->skb_dirty = 0; - for (i=0; i<=TX_RING_MOD_MASK; i++) { - if (fep->tx_skbuff[i] != NULL) { + for (i = 0; i <= TX_RING_MOD_MASK; i++) { + if (fep->tx_skbuff[i]) { dev_kfree_skb_any(fep->tx_skbuff[i]); fep->tx_skbuff[i] = NULL; } } - /* Initialize the receive buffer descriptors. - */ + /* Initialize the receive buffer descriptors. */ bdp = fep->rx_bd_base; - for (i=0; icbd_sc = BD_ENET_RX_EMPTY; bdp++; } - /* Set the last buffer to wrap. - */ + /* Set the last buffer to wrap */ bdp--; bdp->cbd_sc |= BD_SC_WRAP; - /* ...and the same for transmmit. - */ + /* ...and the same for transmit */ bdp = fep->tx_bd_base; - for (i=0; icbd_sc = 0; bdp->cbd_bufaddr = 0; bdp++; } - /* Set the last buffer to wrap. - */ + /* Set the last buffer to wrap */ bdp--; bdp->cbd_sc |= BD_SC_WRAP; - /* Enable MII mode. - */ + /* Enable MII mode */ if (duplex) { - fecp->fec_r_cntrl = OPT_FRAME_SIZE | 0x04;/* MII enable */ - fecp->fec_x_cntrl = 0x04; /* FD enable */ + /* MII enable / FD enable */ + writel(OPT_FRAME_SIZE | 0x04, fep->hwp + FEC_R_CNTRL); + writel(0x04, fep->hwp + FEC_X_CNTRL); } else { - /* MII enable|No Rcv on Xmit */ - fecp->fec_r_cntrl = OPT_FRAME_SIZE | 0x06; - fecp->fec_x_cntrl = 0x00; + /* MII enable / No Rcv on Xmit */ + writel(OPT_FRAME_SIZE | 0x06, fep->hwp + FEC_R_CNTRL); + writel(0x0, fep->hwp + FEC_X_CNTRL); } fep->full_duplex = duplex; - /* Set MII speed. - */ - fecp->fec_mii_speed = fep->phy_speed; + /* Set MII speed */ + writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); - /* And last, enable the transmit and receive processing. - */ - fecp->fec_ecntrl = 2; - fecp->fec_r_des_active = 0; + /* And last, enable the transmit and receive processing */ + writel(2, fep->hwp + FEC_ECNTRL); + writel(0, fep->hwp + FEC_R_DES_ACTIVE); - /* Enable interrupts we wish to service. - */ - fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII); + /* Enable interrupts we wish to service */ + writel(FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII, + fep->hwp + FEC_IMASK); } static void fec_stop(struct net_device *dev) { - volatile fec_t *fecp; - struct fec_enet_private *fep; + struct fec_enet_private *fep = netdev_priv(dev); - fep = netdev_priv(dev); - fecp = fep->hwp; - - /* - ** We cannot expect a graceful transmit stop without link !!! - */ - if (fep->link) - { - fecp->fec_x_cntrl = 0x01; /* Graceful transmit stop */ + /* We cannot expect a graceful transmit stop without link !!! */ + if (fep->link) { + writel(1, fep->hwp + FEC_X_CNTRL); /* Graceful transmit stop */ udelay(10); - if (!(fecp->fec_ievent & FEC_ENET_GRA)) + if (!(readl(fep->hwp + FEC_IEVENT) & FEC_ENET_GRA)) printk("fec_stop : Graceful transmit stop did not complete !\n"); - } + } - /* Whack a reset. We should wait for this. - */ - fecp->fec_ecntrl = 1; + /* Whack a reset. We should wait for this. */ + writel(1, fep->hwp + FEC_ECNTRL); udelay(10); - /* Clear outstanding MII command interrupts. - */ - fecp->fec_ievent = FEC_ENET_MII; + /* Clear outstanding MII command interrupts. */ + writel(FEC_ENET_MII, fep->hwp + FEC_IEVENT); - fecp->fec_imask = FEC_ENET_MII; - fecp->fec_mii_speed = fep->phy_speed; + writel(FEC_ENET_MII, fep->hwp + FEC_IMASK); + writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); } static int __devinit diff --git a/drivers/net/fec.h b/drivers/net/fec.h index 76c64c92e190..30b7dd671336 100644 --- a/drivers/net/fec.h +++ b/drivers/net/fec.h @@ -20,82 +20,55 @@ * registers in the same peripheral device on different models * of the ColdFire! */ -typedef struct fec { - unsigned long fec_reserved0; - unsigned long fec_ievent; /* Interrupt event reg */ - unsigned long fec_imask; /* Interrupt mask reg */ - unsigned long fec_reserved1; - unsigned long fec_r_des_active; /* Receive descriptor reg */ - unsigned long fec_x_des_active; /* Transmit descriptor reg */ - unsigned long fec_reserved2[3]; - unsigned long fec_ecntrl; /* Ethernet control reg */ - unsigned long fec_reserved3[6]; - unsigned long fec_mii_data; /* MII manage frame reg */ - unsigned long fec_mii_speed; /* MII speed control reg */ - unsigned long fec_reserved4[7]; - unsigned long fec_mib_ctrlstat; /* MIB control/status reg */ - unsigned long fec_reserved5[7]; - unsigned long fec_r_cntrl; /* Receive control reg */ - unsigned long fec_reserved6[15]; - unsigned long fec_x_cntrl; /* Transmit Control reg */ - unsigned long fec_reserved7[7]; - unsigned long fec_addr_low; /* Low 32bits MAC address */ - unsigned long fec_addr_high; /* High 16bits MAC address */ - unsigned long fec_opd; /* Opcode + Pause duration */ - unsigned long fec_reserved8[10]; - unsigned long fec_hash_table_high; /* High 32bits hash table */ - unsigned long fec_hash_table_low; /* Low 32bits hash table */ - unsigned long fec_grp_hash_table_high;/* High 32bits hash table */ - unsigned long fec_grp_hash_table_low; /* Low 32bits hash table */ - unsigned long fec_reserved9[7]; - unsigned long fec_x_wmrk; /* FIFO transmit water mark */ - unsigned long fec_reserved10; - unsigned long fec_r_bound; /* FIFO receive bound reg */ - unsigned long fec_r_fstart; /* FIFO receive start reg */ - unsigned long fec_reserved11[11]; - unsigned long fec_r_des_start; /* Receive descriptor ring */ - unsigned long fec_x_des_start; /* Transmit descriptor ring */ - unsigned long fec_r_buff_size; /* Maximum receive buff size */ -} fec_t; +#define FEC_IEVENT 0x004 /* Interrupt event reg */ +#define FEC_IMASK 0x008 /* Interrupt mask reg */ +#define FEC_R_DES_ACTIVE 0x010 /* Receive descriptor reg */ +#define FEC_X_DES_ACTIVE 0x014 /* Transmit descriptor reg */ +#define FEC_ECNTRL 0x024 /* Ethernet control reg */ +#define FEC_MII_DATA 0x040 /* MII manage frame reg */ +#define FEC_MII_SPEED 0x044 /* MII speed control reg */ +#define FEC_MIB_CTRLSTAT 0x064 /* MIB control/status reg */ +#define FEC_R_CNTRL 0x084 /* Receive control reg */ +#define FEC_X_CNTRL 0x0c4 /* Transmit Control reg */ +#define FEC_ADDR_LOW 0x0e4 /* Low 32bits MAC address */ +#define FEC_ADDR_HIGH 0x0e8 /* High 16bits MAC address */ +#define FEC_OPD 0x0ec /* Opcode + Pause duration */ +#define FEC_HASH_TABLE_HIGH 0x118 /* High 32bits hash table */ +#define FEC_HASH_TABLE_LOW 0x11c /* Low 32bits hash table */ +#define FEC_GRP_HASH_TABLE_HIGH 0x120 /* High 32bits hash table */ +#define FEC_GRP_HASH_TABLE_LOW 0x124 /* Low 32bits hash table */ +#define FEC_X_WMRK 0x144 /* FIFO transmit water mark */ +#define FEC_R_BOUND 0x14c /* FIFO receive bound reg */ +#define FEC_R_FSTART 0x150 /* FIFO receive start reg */ +#define FEC_R_DES_START 0x180 /* Receive descriptor ring */ +#define FEC_X_DES_START 0x184 /* Transmit descriptor ring */ +#define FEC_R_BUFF_SIZE 0x188 /* Maximum receive buff size */ #else -/* - * Define device register set address map. - */ -typedef struct fec { - unsigned long fec_ecntrl; /* Ethernet control reg */ - unsigned long fec_ievent; /* Interrupt even reg */ - unsigned long fec_imask; /* Interrupt mask reg */ - unsigned long fec_ivec; /* Interrupt vec status reg */ - unsigned long fec_r_des_active; /* Receive descriptor reg */ - unsigned long fec_x_des_active; /* Transmit descriptor reg */ - unsigned long fec_reserved1[10]; - unsigned long fec_mii_data; /* MII manage frame reg */ - unsigned long fec_mii_speed; /* MII speed control reg */ - unsigned long fec_reserved2[17]; - unsigned long fec_r_bound; /* FIFO receive bound reg */ - unsigned long fec_r_fstart; /* FIFO receive start reg */ - unsigned long fec_reserved3[4]; - unsigned long fec_x_wmrk; /* FIFO transmit water mark */ - unsigned long fec_reserved4; - unsigned long fec_x_fstart; /* FIFO transmit start reg */ - unsigned long fec_reserved5[21]; - unsigned long fec_r_cntrl; /* Receive control reg */ - unsigned long fec_max_frm_len; /* Maximum frame length reg */ - unsigned long fec_reserved6[14]; - unsigned long fec_x_cntrl; /* Transmit Control reg */ - unsigned long fec_reserved7[158]; - unsigned long fec_addr_low; /* Low 32bits MAC address */ - unsigned long fec_addr_high; /* High 16bits MAC address */ - unsigned long fec_grp_hash_table_high;/* High 32bits hash table */ - unsigned long fec_grp_hash_table_low; /* Low 32bits hash table */ - unsigned long fec_r_des_start; /* Receive descriptor ring */ - unsigned long fec_x_des_start; /* Transmit descriptor ring */ - unsigned long fec_r_buff_size; /* Maximum receive buff size */ - unsigned long reserved8[9]; - unsigned long fec_fifo_ram[112]; /* FIFO RAM buffer */ -} fec_t; +#define FEC_ECNTRL; 0x000 /* Ethernet control reg */ +#define FEC_IEVENT; 0x004 /* Interrupt even reg */ +#define FEC_IMASK; 0x008 /* Interrupt mask reg */ +#define FEC_IVEC; 0x00c /* Interrupt vec status reg */ +#define FEC_R_DES_ACTIVE; 0x010 /* Receive descriptor reg */ +#define FEC_X_DES_ACTIVE; 0x01c /* Transmit descriptor reg */ +#define FEC_MII_DATA 0x040 /* MII manage frame reg */ +#define FEC_MII_SPEED 0x044 /* MII speed control reg */ +#define FEC_R_BOUND 0x08c /* FIFO receive bound reg */ +#define FEC_R_FSTART 0x090 /* FIFO receive start reg */ +#define FEC_X_WMRK 0x0a4 /* FIFO transmit water mark */ +#define FEC_X_FSTART 0x0ac /* FIFO transmit start reg */ +#define FEC_R_CNTRL 0x104 /* Receive control reg */ +#define FEC_MAX_FRM_LEN 0x108 /* Maximum frame length reg */ +#define FEC_X_CNTRL 0x144 /* Transmit Control reg */ +#define FEC_ADDR_LOW 0x3c0 /* Low 32bits MAC address */ +#define FEC_ADDR_HIGH 0x3c4 /* High 16bits MAC address */ +#define FEC_GRP_HASH_TABLE_HIGH 0x3c8 /* High 32bits hash table */ +#define FEC_GRP_HASH_TABLE_LOW 0x3cc /* Low 32bits hash table */ +#define FEC_R_DES_START 0x3d0 /* Receive descriptor ring */ +#define FEC_X_DES_START 0x3d4 /* Transmit descriptor ring */ +#define FEC_R_BUFF_SIZE 0x3d8 /* Maximum receive buff size */ +#define FEC_FIFO_RAM 0x400 /* FIFO RAM buffer */ #endif /* CONFIG_M5272 */ @@ -104,17 +77,17 @@ typedef struct fec { * Define the buffer descriptor structure. */ #ifdef CONFIG_ARCH_MXC -typedef struct bufdesc { +struct bufdesc { unsigned short cbd_datlen; /* Data length */ unsigned short cbd_sc; /* Control and status info */ unsigned long cbd_bufaddr; /* Buffer address */ -} cbd_t; +}; #else -typedef struct bufdesc { +struct bufdesc { unsigned short cbd_sc; /* Control and status info */ unsigned short cbd_datlen; /* Data length */ unsigned long cbd_bufaddr; /* Buffer address */ -} cbd_t; +}; #endif /* diff --git a/drivers/net/fec_mpc52xx.c b/drivers/net/fec_mpc52xx.c index 8bbe7f617994..cc786333d95c 100644 --- a/drivers/net/fec_mpc52xx.c +++ b/drivers/net/fec_mpc52xx.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -43,11 +44,9 @@ #define DRIVER_NAME "mpc52xx-fec" -#define FEC5200_PHYADDR_NONE (-1) -#define FEC5200_PHYADDR_7WIRE (-2) - /* Private driver data structure */ struct mpc52xx_fec_priv { + struct net_device *ndev; int duplex; int speed; int r_irq; @@ -59,10 +58,11 @@ struct mpc52xx_fec_priv { int msg_enable; /* MDIO link details */ - int phy_addr; - unsigned int phy_speed; + unsigned int mdio_speed; + struct device_node *phy_node; struct phy_device *phydev; enum phy_state link; + int seven_wire_mode; }; @@ -211,85 +211,25 @@ static void mpc52xx_fec_adjust_link(struct net_device *dev) phy_print_status(phydev); } -static int mpc52xx_fec_init_phy(struct net_device *dev) -{ - struct mpc52xx_fec_priv *priv = netdev_priv(dev); - struct phy_device *phydev; - char phy_id[BUS_ID_SIZE]; - - snprintf(phy_id, sizeof(phy_id), "%x:%02x", - (unsigned int)dev->base_addr, priv->phy_addr); - - priv->link = PHY_DOWN; - priv->speed = 0; - priv->duplex = -1; - - phydev = phy_connect(dev, phy_id, &mpc52xx_fec_adjust_link, 0, PHY_INTERFACE_MODE_MII); - if (IS_ERR(phydev)) { - dev_err(&dev->dev, "phy_connect failed\n"); - return PTR_ERR(phydev); - } - dev_info(&dev->dev, "attached phy %i to driver %s\n", - phydev->addr, phydev->drv->name); - - priv->phydev = phydev; - - return 0; -} - -static int mpc52xx_fec_phy_start(struct net_device *dev) -{ - struct mpc52xx_fec_priv *priv = netdev_priv(dev); - int err; - - if (priv->phy_addr < 0) - return 0; - - err = mpc52xx_fec_init_phy(dev); - if (err) { - dev_err(&dev->dev, "mpc52xx_fec_init_phy failed\n"); - return err; - } - - /* reset phy - this also wakes it from PDOWN */ - phy_write(priv->phydev, MII_BMCR, BMCR_RESET); - phy_start(priv->phydev); - - return 0; -} - -static void mpc52xx_fec_phy_stop(struct net_device *dev) -{ - struct mpc52xx_fec_priv *priv = netdev_priv(dev); - - if (!priv->phydev) - return; - - phy_disconnect(priv->phydev); - /* power down phy */ - phy_stop(priv->phydev); - phy_write(priv->phydev, MII_BMCR, BMCR_PDOWN); -} - -static void mpc52xx_fec_phy_hw_init(struct mpc52xx_fec_priv *priv) -{ - struct mpc52xx_fec __iomem *fec = priv->fec; - - if (priv->phydev) - return; - - out_be32(&fec->mii_speed, priv->phy_speed); -} - static int mpc52xx_fec_open(struct net_device *dev) { struct mpc52xx_fec_priv *priv = netdev_priv(dev); int err = -EBUSY; + if (priv->phy_node) { + priv->phydev = of_phy_connect(priv->ndev, priv->phy_node, + mpc52xx_fec_adjust_link, 0, 0); + if (!priv->phydev) { + dev_err(&dev->dev, "of_phy_connect failed\n"); + return -ENODEV; + } + phy_start(priv->phydev); + } + if (request_irq(dev->irq, &mpc52xx_fec_interrupt, IRQF_SHARED, DRIVER_NAME "_ctrl", dev)) { dev_err(&dev->dev, "ctrl interrupt request failed\n"); - goto out; + goto free_phy; } if (request_irq(priv->r_irq, &mpc52xx_fec_rx_interrupt, 0, DRIVER_NAME "_rx", dev)) { @@ -311,10 +251,6 @@ static int mpc52xx_fec_open(struct net_device *dev) goto free_irqs; } - err = mpc52xx_fec_phy_start(dev); - if (err) - goto free_skbs; - bcom_enable(priv->rx_dmatsk); bcom_enable(priv->tx_dmatsk); @@ -324,16 +260,18 @@ static int mpc52xx_fec_open(struct net_device *dev) return 0; - free_skbs: - mpc52xx_fec_free_rx_buffers(dev, priv->rx_dmatsk); - free_irqs: free_irq(priv->t_irq, dev); free_2irqs: free_irq(priv->r_irq, dev); free_ctrl_irq: free_irq(dev->irq, dev); - out: + free_phy: + if (priv->phydev) { + phy_stop(priv->phydev); + phy_disconnect(priv->phydev); + priv->phydev = NULL; + } return err; } @@ -352,7 +290,12 @@ static int mpc52xx_fec_close(struct net_device *dev) free_irq(priv->r_irq, dev); free_irq(priv->t_irq, dev); - mpc52xx_fec_phy_stop(dev); + if (priv->phydev) { + /* power down phy */ + phy_stop(priv->phydev); + phy_disconnect(priv->phydev); + priv->phydev = NULL; + } return 0; } @@ -696,7 +639,7 @@ static void mpc52xx_fec_hw_init(struct net_device *dev) /* set phy speed. * this can't be done in phy driver, since it needs to be called * before fec stuff (even on resume) */ - mpc52xx_fec_phy_hw_init(priv); + out_be32(&fec->mii_speed, priv->mdio_speed); } /** @@ -732,7 +675,7 @@ static void mpc52xx_fec_start(struct net_device *dev) rcntrl = FEC_RX_BUFFER_SIZE << 16; /* max frame length */ rcntrl |= FEC_RCNTRL_FCE; - if (priv->phy_addr != FEC5200_PHYADDR_7WIRE) + if (!priv->seven_wire_mode) rcntrl |= FEC_RCNTRL_MII_MODE; if (priv->duplex == DUPLEX_FULL) @@ -798,8 +741,6 @@ static void mpc52xx_fec_stop(struct net_device *dev) /* Stop FEC */ out_be32(&fec->ecntrl, in_be32(&fec->ecntrl) & ~FEC_ECNTRL_ETHER_EN); - - return; } /* reset fec and bestcomm tasks */ @@ -817,9 +758,11 @@ static void mpc52xx_fec_reset(struct net_device *dev) mpc52xx_fec_hw_init(dev); - phy_stop(priv->phydev); - phy_write(priv->phydev, MII_BMCR, BMCR_RESET); - phy_start(priv->phydev); + if (priv->phydev) { + phy_stop(priv->phydev); + phy_write(priv->phydev, MII_BMCR, BMCR_RESET); + phy_start(priv->phydev); + } bcom_fec_rx_reset(priv->rx_dmatsk); bcom_fec_tx_reset(priv->tx_dmatsk); @@ -919,8 +862,6 @@ mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match) struct net_device *ndev; struct mpc52xx_fec_priv *priv = NULL; struct resource mem; - struct device_node *phy_node; - const phandle *phy_handle; const u32 *prop; int prop_size; @@ -933,6 +874,7 @@ mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match) return -ENOMEM; priv = netdev_priv(ndev); + priv->ndev = ndev; /* Reserve FEC control zone */ rv = of_address_to_resource(op->node, 0, &mem); @@ -956,6 +898,7 @@ mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match) ndev->ethtool_ops = &mpc52xx_fec_ethtool_ops; ndev->watchdog_timeo = FEC_WATCHDOG_TIMEOUT; ndev->base_addr = mem.start; + SET_NETDEV_DEV(ndev, &op->dev); spin_lock_init(&priv->lock); @@ -1003,14 +946,9 @@ mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match) */ /* Start with safe defaults for link connection */ - priv->phy_addr = FEC5200_PHYADDR_NONE; priv->speed = 100; priv->duplex = DUPLEX_HALF; - priv->phy_speed = ((mpc52xx_find_ipb_freq(op->node) >> 20) / 5) << 1; - - /* the 7-wire property means don't use MII mode */ - if (of_find_property(op->node, "fsl,7-wire-mode", NULL)) - priv->phy_addr = FEC5200_PHYADDR_7WIRE; + priv->mdio_speed = ((mpc5xxx_get_bus_frequency(op->node) >> 20) / 5) << 1; /* The current speed preconfigures the speed of the MII link */ prop = of_get_property(op->node, "current-speed", &prop_size); @@ -1019,43 +957,23 @@ mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match) priv->duplex = prop[1] ? DUPLEX_FULL : DUPLEX_HALF; } - /* If there is a phy handle, setup link to that phy */ - phy_handle = of_get_property(op->node, "phy-handle", &prop_size); - if (phy_handle && (prop_size >= sizeof(phandle))) { - phy_node = of_find_node_by_phandle(*phy_handle); - prop = of_get_property(phy_node, "reg", &prop_size); - if (prop && (prop_size >= sizeof(u32))) - if ((*prop >= 0) && (*prop < PHY_MAX_ADDR)) - priv->phy_addr = *prop; - of_node_put(phy_node); + /* If there is a phy handle, then get the PHY node */ + priv->phy_node = of_parse_phandle(op->node, "phy-handle", 0); + + /* the 7-wire property means don't use MII mode */ + if (of_find_property(op->node, "fsl,7-wire-mode", NULL)) { + priv->seven_wire_mode = 1; + dev_info(&ndev->dev, "using 7-wire PHY mode\n"); } /* Hardware init */ mpc52xx_fec_hw_init(ndev); - mpc52xx_fec_reset_stats(ndev); - SET_NETDEV_DEV(ndev, &op->dev); - - /* Register the new network device */ rv = register_netdev(ndev); if (rv < 0) goto probe_error; - /* Now report the link setup */ - switch (priv->phy_addr) { - case FEC5200_PHYADDR_NONE: - dev_info(&ndev->dev, "Fixed speed MII link: %i%cD\n", - priv->speed, priv->duplex ? 'F' : 'H'); - break; - case FEC5200_PHYADDR_7WIRE: - dev_info(&ndev->dev, "using 7-wire PHY mode\n"); - break; - default: - dev_info(&ndev->dev, "Using PHY at MDIO address %i\n", - priv->phy_addr); - } - /* We're done ! */ dev_set_drvdata(&op->dev, ndev); @@ -1065,6 +983,10 @@ mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match) /* Error handling - free everything that might be allocated */ probe_error: + if (priv->phy_node) + of_node_put(priv->phy_node); + priv->phy_node = NULL; + irq_dispose_mapping(ndev->irq); if (priv->rx_dmatsk) @@ -1093,6 +1015,10 @@ mpc52xx_fec_remove(struct of_device *op) unregister_netdev(ndev); + if (priv->phy_node) + of_node_put(priv->phy_node); + priv->phy_node = NULL; + irq_dispose_mapping(ndev->irq); bcom_fec_rx_release(priv->rx_dmatsk); diff --git a/drivers/net/fec_mpc52xx_phy.c b/drivers/net/fec_mpc52xx_phy.c index dd9bfa42ac34..31e6d62b785d 100644 --- a/drivers/net/fec_mpc52xx_phy.c +++ b/drivers/net/fec_mpc52xx_phy.c @@ -14,12 +14,14 @@ #include #include #include +#include #include #include #include "fec_mpc52xx.h" struct mpc52xx_fec_mdio_priv { struct mpc52xx_fec __iomem *regs; + int mdio_irqs[PHY_MAX_ADDR]; }; static int mpc52xx_fec_mdio_transfer(struct mii_bus *bus, int phy_id, @@ -27,7 +29,7 @@ static int mpc52xx_fec_mdio_transfer(struct mii_bus *bus, int phy_id, { struct mpc52xx_fec_mdio_priv *priv = bus->priv; struct mpc52xx_fec __iomem *fec; - int tries = 100; + int tries = 3; value |= (phy_id << FEC_MII_DATA_PA_SHIFT) & FEC_MII_DATA_PA_MSK; value |= (reg << FEC_MII_DATA_RA_SHIFT) & FEC_MII_DATA_RA_MSK; @@ -38,7 +40,7 @@ static int mpc52xx_fec_mdio_transfer(struct mii_bus *bus, int phy_id, /* wait for it to finish, this takes about 23 us on lite5200b */ while (!(in_be32(&fec->ievent) & FEC_IEVENT_MII) && --tries) - udelay(5); + msleep(1); if (!tries) return -ETIMEDOUT; @@ -64,7 +66,6 @@ static int mpc52xx_fec_mdio_probe(struct of_device *of, { struct device *dev = &of->dev; struct device_node *np = of->node; - struct device_node *child = NULL; struct mii_bus *bus; struct mpc52xx_fec_mdio_priv *priv; struct resource res = {}; @@ -85,22 +86,7 @@ static int mpc52xx_fec_mdio_probe(struct of_device *of, bus->write = mpc52xx_fec_mdio_write; /* setup irqs */ - bus->irq = kmalloc(sizeof(bus->irq[0]) * PHY_MAX_ADDR, GFP_KERNEL); - if (bus->irq == NULL) { - err = -ENOMEM; - goto out_free; - } - for (i=0; iirq[i] = PHY_POLL; - - while ((child = of_get_next_child(np, child)) != NULL) { - int irq = irq_of_parse_and_map(child, 0); - if (irq != NO_IRQ) { - const u32 *id = of_get_property(child, "reg", NULL); - if (id) - bus->irq[*id] = irq; - } - } + bus->irq = priv->mdio_irqs; /* setup registers */ err = of_address_to_resource(np, 0, &res); @@ -120,9 +106,9 @@ static int mpc52xx_fec_mdio_probe(struct of_device *of, /* set MII speed */ out_be32(&priv->regs->mii_speed, - ((mpc52xx_find_ipb_freq(of->node) >> 20) / 5) << 1); + ((mpc5xxx_get_bus_frequency(of->node) >> 20) / 5) << 1); - err = mdiobus_register(bus); + err = of_mdiobus_register(bus, np); if (err) goto out_unmap; diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 9f6a68fb7b45..1094d292630f 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -77,27 +77,31 @@ * Hardware access: */ -#define DEV_NEED_TIMERIRQ 0x000001 /* set the timer irq flag in the irq mask */ -#define DEV_NEED_LINKTIMER 0x000002 /* poll link settings. Relies on the timer irq */ -#define DEV_HAS_LARGEDESC 0x000004 /* device supports jumbo frames and needs packet format 2 */ -#define DEV_HAS_HIGH_DMA 0x000008 /* device supports 64bit dma */ -#define DEV_HAS_CHECKSUM 0x000010 /* device supports tx and rx checksum offloads */ -#define DEV_HAS_VLAN 0x000020 /* device supports vlan tagging and striping */ -#define DEV_HAS_MSI 0x000040 /* device supports MSI */ -#define DEV_HAS_MSI_X 0x000080 /* device supports MSI-X */ -#define DEV_HAS_POWER_CNTRL 0x000100 /* device supports power savings */ -#define DEV_HAS_STATISTICS_V1 0x000200 /* device supports hw statistics version 1 */ -#define DEV_HAS_STATISTICS_V2 0x000600 /* device supports hw statistics version 2 */ -#define DEV_HAS_STATISTICS_V3 0x000e00 /* device supports hw statistics version 3 */ -#define DEV_HAS_TEST_EXTENDED 0x001000 /* device supports extended diagnostic test */ -#define DEV_HAS_MGMT_UNIT 0x002000 /* device supports management unit */ -#define DEV_HAS_CORRECT_MACADDR 0x004000 /* device supports correct mac address order */ -#define DEV_HAS_COLLISION_FIX 0x008000 /* device supports tx collision fix */ -#define DEV_HAS_PAUSEFRAME_TX_V1 0x010000 /* device supports tx pause frames version 1 */ -#define DEV_HAS_PAUSEFRAME_TX_V2 0x020000 /* device supports tx pause frames version 2 */ -#define DEV_HAS_PAUSEFRAME_TX_V3 0x040000 /* device supports tx pause frames version 3 */ -#define DEV_NEED_TX_LIMIT 0x080000 /* device needs to limit tx */ -#define DEV_HAS_GEAR_MODE 0x100000 /* device supports gear mode */ +#define DEV_NEED_TIMERIRQ 0x0000001 /* set the timer irq flag in the irq mask */ +#define DEV_NEED_LINKTIMER 0x0000002 /* poll link settings. Relies on the timer irq */ +#define DEV_HAS_LARGEDESC 0x0000004 /* device supports jumbo frames and needs packet format 2 */ +#define DEV_HAS_HIGH_DMA 0x0000008 /* device supports 64bit dma */ +#define DEV_HAS_CHECKSUM 0x0000010 /* device supports tx and rx checksum offloads */ +#define DEV_HAS_VLAN 0x0000020 /* device supports vlan tagging and striping */ +#define DEV_HAS_MSI 0x0000040 /* device supports MSI */ +#define DEV_HAS_MSI_X 0x0000080 /* device supports MSI-X */ +#define DEV_HAS_POWER_CNTRL 0x0000100 /* device supports power savings */ +#define DEV_HAS_STATISTICS_V1 0x0000200 /* device supports hw statistics version 1 */ +#define DEV_HAS_STATISTICS_V2 0x0000600 /* device supports hw statistics version 2 */ +#define DEV_HAS_STATISTICS_V3 0x0000e00 /* device supports hw statistics version 3 */ +#define DEV_HAS_TEST_EXTENDED 0x0001000 /* device supports extended diagnostic test */ +#define DEV_HAS_MGMT_UNIT 0x0002000 /* device supports management unit */ +#define DEV_HAS_CORRECT_MACADDR 0x0004000 /* device supports correct mac address order */ +#define DEV_HAS_COLLISION_FIX 0x0008000 /* device supports tx collision fix */ +#define DEV_HAS_PAUSEFRAME_TX_V1 0x0010000 /* device supports tx pause frames version 1 */ +#define DEV_HAS_PAUSEFRAME_TX_V2 0x0020000 /* device supports tx pause frames version 2 */ +#define DEV_HAS_PAUSEFRAME_TX_V3 0x0040000 /* device supports tx pause frames version 3 */ +#define DEV_NEED_TX_LIMIT 0x0080000 /* device needs to limit tx */ +#define DEV_NEED_TX_LIMIT2 0x0180000 /* device needs to limit tx, expect for some revs */ +#define DEV_HAS_GEAR_MODE 0x0200000 /* device supports gear mode */ +#define DEV_NEED_PHY_INIT_FIX 0x0400000 /* device needs specific phy workaround */ +#define DEV_NEED_LOW_POWER_FIX 0x0800000 /* device needs special power up workaround */ +#define DEV_NEED_MSI_FIX 0x1000000 /* device needs msi workaround */ enum { NvRegIrqStatus = 0x000, @@ -343,6 +347,7 @@ enum { #define NVREG_POWERSTATE2_POWERUP_MASK 0x0F15 #define NVREG_POWERSTATE2_POWERUP_REV_A3 0x0001 #define NVREG_POWERSTATE2_PHY_RESET 0x0004 +#define NVREG_POWERSTATE2_GATE_CLOCKS 0x0F00 }; /* Big endian: should work, but is untested */ @@ -714,7 +719,8 @@ static const struct register_test nv_registers_test[] = { struct nv_skb_map { struct sk_buff *skb; dma_addr_t dma; - unsigned int dma_len; + unsigned int dma_len:31; + unsigned int dma_single:1; struct ring_desc_ex *first_tx_desc; struct nv_skb_map *next_tx_ctx; }; @@ -1023,6 +1029,23 @@ static int using_multi_irqs(struct net_device *dev) return 1; } +static void nv_txrx_gate(struct net_device *dev, bool gate) +{ + struct fe_priv *np = get_nvpriv(dev); + u8 __iomem *base = get_hwbase(dev); + u32 powerstate; + + if (!np->mac_in_use && + (np->driver_data & DEV_HAS_POWER_CNTRL)) { + powerstate = readl(base + NvRegPowerState2); + if (gate) + powerstate |= NVREG_POWERSTATE2_GATE_CLOCKS; + else + powerstate &= ~NVREG_POWERSTATE2_GATE_CLOCKS; + writel(powerstate, base + NvRegPowerState2); + } +} + static void nv_enable_irq(struct net_device *dev) { struct fe_priv *np = get_nvpriv(dev); @@ -1253,14 +1276,7 @@ static int phy_init(struct net_device *dev) } } if (np->phy_model == PHY_MODEL_REALTEK_8201) { - if (np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_32 || - np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_33 || - np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_34 || - np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_35 || - np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_36 || - np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_37 || - np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_38 || - np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_39) { + if (np->driver_data & DEV_NEED_PHY_INIT_FIX) { phy_reserved = mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG6, MII_READ); phy_reserved |= PHY_REALTEK_INIT7; if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG6, phy_reserved)) { @@ -1451,14 +1467,7 @@ static int phy_init(struct net_device *dev) } } if (np->phy_model == PHY_MODEL_REALTEK_8201) { - if (np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_32 || - np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_33 || - np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_34 || - np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_35 || - np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_36 || - np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_37 || - np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_38 || - np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_39) { + if (np->driver_data & DEV_NEED_PHY_INIT_FIX) { phy_reserved = mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG6, MII_READ); phy_reserved |= PHY_REALTEK_INIT7; if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG6, phy_reserved)) { @@ -1904,6 +1913,7 @@ static void nv_init_tx(struct net_device *dev) np->tx_skb[i].skb = NULL; np->tx_skb[i].dma = 0; np->tx_skb[i].dma_len = 0; + np->tx_skb[i].dma_single = 0; np->tx_skb[i].first_tx_desc = NULL; np->tx_skb[i].next_tx_ctx = NULL; } @@ -1922,23 +1932,30 @@ static int nv_init_ring(struct net_device *dev) return nv_alloc_rx_optimized(dev); } -static int nv_release_txskb(struct net_device *dev, struct nv_skb_map* tx_skb) +static void nv_unmap_txskb(struct fe_priv *np, struct nv_skb_map *tx_skb) { - struct fe_priv *np = netdev_priv(dev); - if (tx_skb->dma) { - pci_unmap_page(np->pci_dev, tx_skb->dma, - tx_skb->dma_len, - PCI_DMA_TODEVICE); + if (tx_skb->dma_single) + pci_unmap_single(np->pci_dev, tx_skb->dma, + tx_skb->dma_len, + PCI_DMA_TODEVICE); + else + pci_unmap_page(np->pci_dev, tx_skb->dma, + tx_skb->dma_len, + PCI_DMA_TODEVICE); tx_skb->dma = 0; } +} + +static int nv_release_txskb(struct fe_priv *np, struct nv_skb_map *tx_skb) +{ + nv_unmap_txskb(np, tx_skb); if (tx_skb->skb) { dev_kfree_skb_any(tx_skb->skb); tx_skb->skb = NULL; return 1; - } else { - return 0; } + return 0; } static void nv_drain_tx(struct net_device *dev) @@ -1956,10 +1973,11 @@ static void nv_drain_tx(struct net_device *dev) np->tx_ring.ex[i].bufhigh = 0; np->tx_ring.ex[i].buflow = 0; } - if (nv_release_txskb(dev, &np->tx_skb[i])) + if (nv_release_txskb(np, &np->tx_skb[i])) dev->stats.tx_dropped++; np->tx_skb[i].dma = 0; np->tx_skb[i].dma_len = 0; + np->tx_skb[i].dma_single = 0; np->tx_skb[i].first_tx_desc = NULL; np->tx_skb[i].next_tx_ctx = NULL; } @@ -2163,6 +2181,7 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev) np->put_tx_ctx->dma = pci_map_single(np->pci_dev, skb->data + offset, bcnt, PCI_DMA_TODEVICE); np->put_tx_ctx->dma_len = bcnt; + np->put_tx_ctx->dma_single = 1; put_tx->buf = cpu_to_le32(np->put_tx_ctx->dma); put_tx->flaglen = cpu_to_le32((bcnt-1) | tx_flags); @@ -2188,6 +2207,7 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev) np->put_tx_ctx->dma = pci_map_page(np->pci_dev, frag->page, frag->page_offset+offset, bcnt, PCI_DMA_TODEVICE); np->put_tx_ctx->dma_len = bcnt; + np->put_tx_ctx->dma_single = 0; put_tx->buf = cpu_to_le32(np->put_tx_ctx->dma); put_tx->flaglen = cpu_to_le32((bcnt-1) | tx_flags); @@ -2283,6 +2303,7 @@ static int nv_start_xmit_optimized(struct sk_buff *skb, struct net_device *dev) np->put_tx_ctx->dma = pci_map_single(np->pci_dev, skb->data + offset, bcnt, PCI_DMA_TODEVICE); np->put_tx_ctx->dma_len = bcnt; + np->put_tx_ctx->dma_single = 1; put_tx->bufhigh = cpu_to_le32(dma_high(np->put_tx_ctx->dma)); put_tx->buflow = cpu_to_le32(dma_low(np->put_tx_ctx->dma)); put_tx->flaglen = cpu_to_le32((bcnt-1) | tx_flags); @@ -2309,6 +2330,7 @@ static int nv_start_xmit_optimized(struct sk_buff *skb, struct net_device *dev) np->put_tx_ctx->dma = pci_map_page(np->pci_dev, frag->page, frag->page_offset+offset, bcnt, PCI_DMA_TODEVICE); np->put_tx_ctx->dma_len = bcnt; + np->put_tx_ctx->dma_single = 0; put_tx->bufhigh = cpu_to_le32(dma_high(np->put_tx_ctx->dma)); put_tx->buflow = cpu_to_le32(dma_low(np->put_tx_ctx->dma)); put_tx->flaglen = cpu_to_le32((bcnt-1) | tx_flags); @@ -2426,10 +2448,7 @@ static int nv_tx_done(struct net_device *dev, int limit) dprintk(KERN_DEBUG "%s: nv_tx_done: flags 0x%x.\n", dev->name, flags); - pci_unmap_page(np->pci_dev, np->get_tx_ctx->dma, - np->get_tx_ctx->dma_len, - PCI_DMA_TODEVICE); - np->get_tx_ctx->dma = 0; + nv_unmap_txskb(np, np->get_tx_ctx); if (np->desc_ver == DESC_VER_1) { if (flags & NV_TX_LASTPACKET) { @@ -2494,10 +2513,7 @@ static int nv_tx_done_optimized(struct net_device *dev, int limit) dprintk(KERN_DEBUG "%s: nv_tx_done_optimized: flags 0x%x.\n", dev->name, flags); - pci_unmap_page(np->pci_dev, np->get_tx_ctx->dma, - np->get_tx_ctx->dma_len, - PCI_DMA_TODEVICE); - np->get_tx_ctx->dma = 0; + nv_unmap_txskb(np, np->get_tx_ctx); if (flags & NV_TX2_LASTPACKET) { if (!(flags & NV_TX2_ERROR)) @@ -3403,12 +3419,14 @@ static void nv_linkchange(struct net_device *dev) if (!netif_carrier_ok(dev)) { netif_carrier_on(dev); printk(KERN_INFO "%s: link up.\n", dev->name); + nv_txrx_gate(dev, false); nv_start_rx(dev); } } else { if (netif_carrier_ok(dev)) { netif_carrier_off(dev); printk(KERN_INFO "%s: link down.\n", dev->name); + nv_txrx_gate(dev, true); nv_stop_rx(dev); } } @@ -5081,7 +5099,7 @@ static int nv_loopback_test(struct net_device *dev) dprintk(KERN_DEBUG "%s: loopback - did not receive test packet\n", dev->name); } - pci_unmap_page(np->pci_dev, test_dma_addr, + pci_unmap_single(np->pci_dev, test_dma_addr, (skb_end_pointer(tx_skb) - tx_skb->data), PCI_DMA_TODEVICE); dev_kfree_skb_any(tx_skb); @@ -5336,6 +5354,7 @@ static int nv_open(struct net_device *dev) mii_rw(dev, np->phyaddr, MII_BMCR, mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ) & ~BMCR_PDOWN); + nv_txrx_gate(dev, false); /* erase previous misconfiguration */ if (np->driver_data & DEV_HAS_POWER_CNTRL) nv_mac_reset(dev); @@ -5523,12 +5542,14 @@ static int nv_close(struct net_device *dev) nv_drain_rxtx(dev); if (np->wolenabled || !phy_power_down) { + nv_txrx_gate(dev, false); writel(NVREG_PFF_ALWAYS|NVREG_PFF_MYADDR, base + NvRegPacketFilterFlags); nv_start_rx(dev); } else { /* power down phy */ mii_rw(dev, np->phyaddr, MII_BMCR, mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ)|BMCR_PDOWN); + nv_txrx_gate(dev, true); } /* FIXME: power down nic */ @@ -5821,8 +5842,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i /* take phy and nic out of low power mode */ powerstate = readl(base + NvRegPowerState2); powerstate &= ~NVREG_POWERSTATE2_POWERUP_MASK; - if ((id->device == PCI_DEVICE_ID_NVIDIA_NVENET_12 || - id->device == PCI_DEVICE_ID_NVIDIA_NVENET_13) && + if ((id->driver_data & DEV_NEED_LOW_POWER_FIX) && pci_dev->revision >= 0xA3) powerstate |= NVREG_POWERSTATE2_POWERUP_REV_A3; writel(powerstate, base + NvRegPowerState2); @@ -5878,14 +5898,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i /* Limit the number of tx's outstanding for hw bug */ if (id->driver_data & DEV_NEED_TX_LIMIT) { np->tx_limit = 1; - if ((id->device == PCI_DEVICE_ID_NVIDIA_NVENET_32 || - id->device == PCI_DEVICE_ID_NVIDIA_NVENET_33 || - id->device == PCI_DEVICE_ID_NVIDIA_NVENET_34 || - id->device == PCI_DEVICE_ID_NVIDIA_NVENET_35 || - id->device == PCI_DEVICE_ID_NVIDIA_NVENET_36 || - id->device == PCI_DEVICE_ID_NVIDIA_NVENET_37 || - id->device == PCI_DEVICE_ID_NVIDIA_NVENET_38 || - id->device == PCI_DEVICE_ID_NVIDIA_NVENET_39) && + if ((id->driver_data & DEV_NEED_TX_LIMIT2) && pci_dev->revision >= 0xA2) np->tx_limit = 0; } @@ -6135,7 +6148,8 @@ static int nv_resume(struct pci_dev *pdev) for (i = 0;i <= np->register_size/sizeof(u32); i++) writel(np->saved_config_space[i], base+i*sizeof(u32)); - pci_write_config_dword(pdev, NV_MSI_PRIV_OFFSET, NV_MSI_PRIV_VALUE); + if (np->driver_data & DEV_NEED_MSI_FIX) + pci_write_config_dword(pdev, NV_MSI_PRIV_OFFSET, NV_MSI_PRIV_VALUE); /* restore phy state, including autoneg */ phy_init(dev); @@ -6184,160 +6198,164 @@ static void nv_shutdown(struct pci_dev *pdev) static struct pci_device_id pci_tbl[] = { { /* nForce Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_1), + PCI_DEVICE(0x10DE, 0x01C3), .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, }, { /* nForce2 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_2), + PCI_DEVICE(0x10DE, 0x0066), .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, }, { /* nForce3 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_3), + PCI_DEVICE(0x10DE, 0x00D6), .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, }, { /* nForce3 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_4), + PCI_DEVICE(0x10DE, 0x0086), .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM, }, { /* nForce3 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_5), + PCI_DEVICE(0x10DE, 0x008C), .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM, }, { /* nForce3 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_6), + PCI_DEVICE(0x10DE, 0x00E6), .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM, }, { /* nForce3 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_7), + PCI_DEVICE(0x10DE, 0x00DF), .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM, }, { /* CK804 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_8), + PCI_DEVICE(0x10DE, 0x0056), .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1|DEV_NEED_TX_LIMIT, }, { /* CK804 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_9), + PCI_DEVICE(0x10DE, 0x0057), .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1|DEV_NEED_TX_LIMIT, }, { /* MCP04 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_10), + PCI_DEVICE(0x10DE, 0x0037), .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1|DEV_NEED_TX_LIMIT, }, { /* MCP04 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_11), + PCI_DEVICE(0x10DE, 0x0038), .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1|DEV_NEED_TX_LIMIT, }, { /* MCP51 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_12), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS_V1, + PCI_DEVICE(0x10DE, 0x0268), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS_V1|DEV_NEED_LOW_POWER_FIX, }, { /* MCP51 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_13), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS_V1, + PCI_DEVICE(0x10DE, 0x0269), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS_V1|DEV_NEED_LOW_POWER_FIX, }, { /* MCP55 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_14), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_NEED_TX_LIMIT, + PCI_DEVICE(0x10DE, 0x0372), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_NEED_TX_LIMIT|DEV_NEED_MSI_FIX, }, { /* MCP55 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_15), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_NEED_TX_LIMIT, + PCI_DEVICE(0x10DE, 0x0373), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_NEED_TX_LIMIT|DEV_NEED_MSI_FIX, }, { /* MCP61 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_16), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, + PCI_DEVICE(0x10DE, 0x03E5), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_MSI_FIX, }, { /* MCP61 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_17), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, + PCI_DEVICE(0x10DE, 0x03E6), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_MSI_FIX, }, { /* MCP61 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_18), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, + PCI_DEVICE(0x10DE, 0x03EE), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_MSI_FIX, }, { /* MCP61 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_19), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, + PCI_DEVICE(0x10DE, 0x03EF), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_MSI_FIX, }, { /* MCP65 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_20), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x0450), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX, }, { /* MCP65 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_21), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x0451), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX, }, { /* MCP65 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_22), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x0452), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX, }, { /* MCP65 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_23), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x0453), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX, }, { /* MCP67 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_24), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x054C), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX, }, { /* MCP67 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_25), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x054D), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX, }, { /* MCP67 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_26), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x054E), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX, }, { /* MCP67 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_27), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x054F), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX, }, { /* MCP73 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_28), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x07DC), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX, }, { /* MCP73 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_29), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x07DD), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX, }, { /* MCP73 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_30), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x07DE), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX, }, { /* MCP73 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_31), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x07DF), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX, }, { /* MCP77 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_32), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x0760), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX, }, { /* MCP77 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_33), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x0761), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX, }, { /* MCP77 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_34), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x0762), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX, }, { /* MCP77 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_35), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x0763), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX, }, { /* MCP79 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_36), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x0AB0), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX, }, { /* MCP79 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_37), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x0AB1), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX, }, { /* MCP79 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_38), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x0AB2), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX, }, { /* MCP79 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_39), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x0AB3), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX, + }, + { /* MCP89 Ethernet Controller */ + PCI_DEVICE(0x10DE, 0x0D7D), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX, }, {0,}, }; diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c index a9cbc3191a2a..b892c3ad9a74 100644 --- a/drivers/net/fs_enet/fs_enet-main.c +++ b/drivers/net/fs_enet/fs_enet-main.c @@ -36,6 +36,8 @@ #include #include #include +#include +#include #include #include @@ -752,9 +754,10 @@ static int fs_init_phy(struct net_device *dev) fep->oldlink = 0; fep->oldspeed = 0; fep->oldduplex = -1; - if(fep->fpi->bus_id) - phydev = phy_connect(dev, fep->fpi->bus_id, &fs_adjust_link, 0, - PHY_INTERFACE_MODE_MII); + if(fep->fpi->phy_node) + phydev = of_phy_connect(dev, fep->fpi->phy_node, + &fs_adjust_link, 0, + PHY_INTERFACE_MODE_MII); else { printk("No phy bus ID specified in BSP code\n"); return -EINVAL; @@ -938,81 +941,6 @@ extern void fs_mii_disconnect(struct net_device *dev); /**************************************************************************************/ -/* handy pointer to the immap */ -void __iomem *fs_enet_immap = NULL; - -static int setup_immap(void) -{ -#ifdef CONFIG_CPM1 - fs_enet_immap = ioremap(IMAP_ADDR, 0x4000); - WARN_ON(!fs_enet_immap); -#elif defined(CONFIG_CPM2) - fs_enet_immap = cpm2_immr; -#endif - - return 0; -} - -static void cleanup_immap(void) -{ -#if defined(CONFIG_CPM1) - iounmap(fs_enet_immap); -#endif -} - -/**************************************************************************************/ - -static int __devinit find_phy(struct device_node *np, - struct fs_platform_info *fpi) -{ - struct device_node *phynode, *mdionode; - int ret = 0, len, bus_id; - const u32 *data; - - data = of_get_property(np, "fixed-link", NULL); - if (data) { - snprintf(fpi->bus_id, 16, "%x:%02x", 0, *data); - return 0; - } - - data = of_get_property(np, "phy-handle", &len); - if (!data || len != 4) - return -EINVAL; - - phynode = of_find_node_by_phandle(*data); - if (!phynode) - return -EINVAL; - - data = of_get_property(phynode, "reg", &len); - if (!data || len != 4) { - ret = -EINVAL; - goto out_put_phy; - } - - mdionode = of_get_parent(phynode); - if (!mdionode) { - ret = -EINVAL; - goto out_put_phy; - } - - bus_id = of_get_gpio(mdionode, 0); - if (bus_id < 0) { - struct resource res; - ret = of_address_to_resource(mdionode, 0, &res); - if (ret) - goto out_put_mdio; - bus_id = res.start; - } - - snprintf(fpi->bus_id, 16, "%x:%02x", bus_id, *data); - -out_put_mdio: - of_node_put(mdionode); -out_put_phy: - of_node_put(phynode); - return ret; -} - #ifdef CONFIG_FS_ENET_HAS_FEC #define IS_FEC(match) ((match)->data == &fs_fec_ops) #else @@ -1062,9 +990,9 @@ static int __devinit fs_enet_probe(struct of_device *ofdev, fpi->rx_copybreak = 240; fpi->use_napi = 1; fpi->napi_weight = 17; - - ret = find_phy(ofdev->node, fpi); - if (ret) + fpi->phy_node = of_parse_phandle(ofdev->node, "phy-handle", 0); + if ((!fpi->phy_node) && (!of_get_property(ofdev->node, "fixed-link", + NULL))) goto out_free_fpi; privsize = sizeof(*fep) + @@ -1136,6 +1064,7 @@ out_cleanup_data: out_free_dev: free_netdev(ndev); dev_set_drvdata(&ofdev->dev, NULL); + of_node_put(fpi->phy_node); out_free_fpi: kfree(fpi); return ret; @@ -1151,7 +1080,7 @@ static int fs_enet_remove(struct of_device *ofdev) fep->ops->free_bd(ndev); fep->ops->cleanup_data(ndev); dev_set_drvdata(fep->dev, NULL); - + of_node_put(fep->fpi->phy_node); free_netdev(ndev); return 0; } @@ -1191,25 +1120,12 @@ static struct of_platform_driver fs_enet_driver = { static int __init fs_init(void) { - int r = setup_immap(); - if (r != 0) - return r; - - r = of_register_platform_driver(&fs_enet_driver); - if (r != 0) - goto out; - - return 0; - -out: - cleanup_immap(); - return r; + return of_register_platform_driver(&fs_enet_driver); } static void __exit fs_cleanup(void) { of_unregister_platform_driver(&fs_enet_driver); - cleanup_immap(); } #ifdef CONFIG_NET_POLL_CONTROLLER diff --git a/drivers/net/fs_enet/fs_enet.h b/drivers/net/fs_enet/fs_enet.h index 85a4bab7f630..ef01e09781a5 100644 --- a/drivers/net/fs_enet/fs_enet.h +++ b/drivers/net/fs_enet/fs_enet.h @@ -194,9 +194,4 @@ extern const struct fs_ops fs_scc_ops; /*******************************************************************/ -/* handy pointer to the immap */ -extern void __iomem *fs_enet_immap; - -/*******************************************************************/ - #endif diff --git a/drivers/net/fs_enet/mac-fec.c b/drivers/net/fs_enet/mac-fec.c index 14e575313c89..ca7bcb8ab3a1 100644 --- a/drivers/net/fs_enet/mac-fec.c +++ b/drivers/net/fs_enet/mac-fec.c @@ -245,10 +245,6 @@ static void set_multicast_list(struct net_device *dev) static void restart(struct net_device *dev) { -#ifdef CONFIG_DUET - immap_t *immap = fs_enet_immap; - u32 cptr; -#endif struct fs_enet_private *fep = netdev_priv(dev); fec_t __iomem *fecp = fep->fec.fecp; const struct fs_platform_info *fpi = fep->fpi; @@ -315,36 +311,6 @@ static void restart(struct net_device *dev) FW(fecp, ievent, 0xffc0); FW(fecp, ivec, (virq_to_hw(fep->interrupt) / 2) << 29); - /* - * adjust to speed (only for DUET & RMII) - */ -#ifdef CONFIG_DUET - if (fpi->use_rmii) { - cptr = in_be32(&immap->im_cpm.cp_cptr); - switch (fs_get_fec_index(fpi->fs_no)) { - case 0: - cptr |= 0x100; - if (fep->speed == 10) - cptr |= 0x0000010; - else if (fep->speed == 100) - cptr &= ~0x0000010; - break; - case 1: - cptr |= 0x80; - if (fep->speed == 10) - cptr |= 0x0000008; - else if (fep->speed == 100) - cptr &= ~0x0000008; - break; - default: - BUG(); /* should never happen */ - break; - } - out_be32(&immap->im_cpm.cp_cptr, cptr); - } -#endif - - FW(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */ /* * adjust to duplex mode diff --git a/drivers/net/fs_enet/mii-bitbang.c b/drivers/net/fs_enet/mii-bitbang.c index 49b6645d7e0c..93b481b0e3c7 100644 --- a/drivers/net/fs_enet/mii-bitbang.c +++ b/drivers/net/fs_enet/mii-bitbang.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include "fs_enet.h" @@ -149,31 +150,12 @@ static int __devinit fs_mii_bitbang_init(struct mii_bus *bus, return 0; } -static void __devinit add_phy(struct mii_bus *bus, struct device_node *np) -{ - const u32 *data; - int len, id, irq; - - data = of_get_property(np, "reg", &len); - if (!data || len != 4) - return; - - id = *data; - bus->phy_mask &= ~(1 << id); - - irq = of_irq_to_resource(np, 0, NULL); - if (irq != NO_IRQ) - bus->irq[id] = irq; -} - static int __devinit fs_enet_mdio_probe(struct of_device *ofdev, const struct of_device_id *match) { - struct device_node *np = NULL; struct mii_bus *new_bus; struct bb_info *bitbang; int ret = -ENOMEM; - int i; bitbang = kzalloc(sizeof(struct bb_info), GFP_KERNEL); if (!bitbang) @@ -196,17 +178,10 @@ static int __devinit fs_enet_mdio_probe(struct of_device *ofdev, if (!new_bus->irq) goto out_unmap_regs; - for (i = 0; i < PHY_MAX_ADDR; i++) - new_bus->irq[i] = -1; - - while ((np = of_get_next_child(ofdev->node, np))) - if (!strcmp(np->type, "ethernet-phy")) - add_phy(new_bus, np); - new_bus->parent = &ofdev->dev; dev_set_drvdata(&ofdev->dev, new_bus); - ret = mdiobus_register(new_bus); + ret = of_mdiobus_register(new_bus, ofdev->node); if (ret) goto out_free_irqs; diff --git a/drivers/net/fs_enet/mii-fec.c b/drivers/net/fs_enet/mii-fec.c index 28077cc1b949..75a09994d665 100644 --- a/drivers/net/fs_enet/mii-fec.c +++ b/drivers/net/fs_enet/mii-fec.c @@ -54,8 +54,7 @@ static int fs_enet_fec_mii_read(struct mii_bus *bus , int phy_id, int location) fec_t __iomem *fecp = fec->fecp; int i, ret = -1; - if ((in_be32(&fecp->fec_r_cntrl) & FEC_RCNTRL_MII_MODE) == 0) - BUG(); + BUG_ON((in_be32(&fecp->fec_r_cntrl) & FEC_RCNTRL_MII_MODE) == 0); /* Add PHY address to register command. */ out_be32(&fecp->fec_mii_data, (phy_id << 23) | mk_mii_read(location)); @@ -79,8 +78,7 @@ static int fs_enet_fec_mii_write(struct mii_bus *bus, int phy_id, int location, int i; /* this must never happen */ - if ((in_be32(&fecp->fec_r_cntrl) & FEC_RCNTRL_MII_MODE) == 0) - BUG(); + BUG_ON((in_be32(&fecp->fec_r_cntrl) & FEC_RCNTRL_MII_MODE) == 0); /* Add PHY address to register command. */ out_be32(&fecp->fec_mii_data, (phy_id << 23) | mk_mii_write(location, val)); @@ -102,23 +100,6 @@ static int fs_enet_fec_mii_reset(struct mii_bus *bus) return 0; } -static void __devinit add_phy(struct mii_bus *bus, struct device_node *np) -{ - const u32 *data; - int len, id, irq; - - data = of_get_property(np, "reg", &len); - if (!data || len != 4) - return; - - id = *data; - bus->phy_mask &= ~(1 << id); - - irq = of_irq_to_resource(np, 0, NULL); - if (irq != NO_IRQ) - bus->irq[id] = irq; -} - static int __devinit fs_enet_mdio_probe(struct of_device *ofdev, const struct of_device_id *match) { @@ -165,17 +146,10 @@ static int __devinit fs_enet_mdio_probe(struct of_device *ofdev, if (!new_bus->irq) goto out_unmap_regs; - for (i = 0; i < PHY_MAX_ADDR; i++) - new_bus->irq[i] = -1; - - while ((np = of_get_next_child(ofdev->node, np))) - if (!strcmp(np->type, "ethernet-phy")) - add_phy(new_bus, np); - new_bus->parent = &ofdev->dev; dev_set_drvdata(&ofdev->dev, new_bus); - ret = mdiobus_register(new_bus); + ret = of_mdiobus_register(new_bus, ofdev->node); if (ret) goto out_free_irqs; diff --git a/drivers/net/fsl_pq_mdio.c b/drivers/net/fsl_pq_mdio.c index aa1eb88c21fc..3af581303ca2 100644 --- a/drivers/net/fsl_pq_mdio.c +++ b/drivers/net/fsl_pq_mdio.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -154,44 +155,6 @@ static int fsl_pq_mdio_reset(struct mii_bus *bus) return 0; } -/* Allocate an array which provides irq #s for each PHY on the given bus */ -static int *create_irq_map(struct device_node *np) -{ - int *irqs; - int i; - struct device_node *child = NULL; - - irqs = kcalloc(PHY_MAX_ADDR, sizeof(int), GFP_KERNEL); - - if (!irqs) - return NULL; - - for (i = 0; i < PHY_MAX_ADDR; i++) - irqs[i] = PHY_POLL; - - while ((child = of_get_next_child(np, child)) != NULL) { - int irq = irq_of_parse_and_map(child, 0); - const u32 *id; - - if (irq == NO_IRQ) - continue; - - id = of_get_property(child, "reg", NULL); - - if (!id) - continue; - - if (*id < PHY_MAX_ADDR && *id >= 0) - irqs[*id] = irq; - else - printk(KERN_WARNING "%s: " - "%d is not a valid PHY address\n", - np->full_name, *id); - } - - return irqs; -} - void fsl_pq_mdio_bus_name(char *name, struct device_node *np) { const u32 *addr; @@ -315,7 +278,7 @@ static int fsl_pq_mdio_probe(struct of_device *ofdev, new_bus->priv = (void __force *)regs; - new_bus->irq = create_irq_map(np); + new_bus->irq = kcalloc(PHY_MAX_ADDR, sizeof(int), GFP_KERNEL); if (NULL == new_bus->irq) { err = -ENOMEM; @@ -338,13 +301,17 @@ static int fsl_pq_mdio_probe(struct of_device *ofdev, of_device_is_compatible(np, "ucc_geth_phy")) { #ifdef CONFIG_UCC_GETH u32 id; + static u32 mii_mng_master; tbipa = ®s->utbipar; if ((err = get_ucc_id_for_range(addr, addr + size, &id))) goto err_free_irqs; - ucc_set_qe_mux_mii_mng(id - 1); + if (!mii_mng_master) { + mii_mng_master = id; + ucc_set_qe_mux_mii_mng(id - 1); + } #else err = -ENODEV; goto err_free_irqs; @@ -384,15 +351,7 @@ static int fsl_pq_mdio_probe(struct of_device *ofdev, out_be32(tbipa, tbiaddr); - /* - * The TBIPHY-only buses will find PHYs at every address, - * so we mask them all but the TBI - */ - if (of_device_is_compatible(np, "fsl,gianfar-tbi")) - new_bus->phy_mask = ~(1 << tbiaddr); - - err = mdiobus_register(new_bus); - + err = of_mdiobus_register(new_bus, np); if (err) { printk (KERN_ERR "%s: Cannot register as MDIO bus\n", new_bus->name); @@ -460,10 +419,10 @@ int __init fsl_pq_mdio_init(void) { return of_register_platform_driver(&fsl_pq_mdio_driver); } +module_init(fsl_pq_mdio_init); void fsl_pq_mdio_exit(void) { of_unregister_platform_driver(&fsl_pq_mdio_driver); } -subsys_initcall_sync(fsl_pq_mdio_init); module_exit(fsl_pq_mdio_exit); diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index a0519184e54e..4ae1d259fced 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -75,6 +75,7 @@ #include #include #include +#include #include #include #include @@ -168,17 +169,13 @@ static inline int gfar_uses_fcb(struct gfar_private *priv) static int gfar_of_init(struct net_device *dev) { - struct device_node *phy, *mdio; - const unsigned int *id; const char *model; const char *ctype; const void *mac_addr; - const phandle *ph; u64 addr, size; int err = 0; struct gfar_private *priv = netdev_priv(dev); struct device_node *np = priv->node; - char bus_name[MII_BUS_ID_SIZE]; const u32 *stash; const u32 *stash_len; const u32 *stash_idx; @@ -264,8 +261,8 @@ static int gfar_of_init(struct net_device *dev) if (of_get_property(np, "fsl,magic-packet", NULL)) priv->device_flags |= FSL_GIANFAR_DEV_HAS_MAGIC_PACKET; - ph = of_get_property(np, "phy-handle", NULL); - if (ph == NULL) { + priv->phy_node = of_parse_phandle(np, "phy-handle", 0); + if (!priv->phy_node) { u32 *fixed_link; fixed_link = (u32 *)of_get_property(np, "fixed-link", NULL); @@ -273,57 +270,10 @@ static int gfar_of_init(struct net_device *dev) err = -ENODEV; goto err_out; } - - snprintf(priv->phy_bus_id, sizeof(priv->phy_bus_id), - PHY_ID_FMT, "0", fixed_link[0]); - } else { - phy = of_find_node_by_phandle(*ph); - - if (phy == NULL) { - err = -ENODEV; - goto err_out; - } - - mdio = of_get_parent(phy); - - id = of_get_property(phy, "reg", NULL); - - of_node_put(phy); - - fsl_pq_mdio_bus_name(bus_name, mdio); - of_node_put(mdio); - snprintf(priv->phy_bus_id, sizeof(priv->phy_bus_id), "%s:%02x", - bus_name, *id); } /* Find the TBI PHY. If it's not there, we don't support SGMII */ - ph = of_get_property(np, "tbi-handle", NULL); - if (ph) { - struct device_node *tbi = of_find_node_by_phandle(*ph); - struct of_device *ofdev; - struct mii_bus *bus; - - if (!tbi) - return 0; - - mdio = of_get_parent(tbi); - if (!mdio) - return 0; - - ofdev = of_find_device_by_node(mdio); - - of_node_put(mdio); - - id = of_get_property(tbi, "reg", NULL); - if (!id) - return 0; - - of_node_put(tbi); - - bus = dev_get_drvdata(&ofdev->dev); - - priv->tbiphy = bus->phy_map[*id]; - } + priv->tbi_node = of_parse_phandle(np, "tbi-handle", 0); return 0; @@ -529,6 +479,10 @@ static int gfar_probe(struct of_device *ofdev, register_fail: iounmap(priv->regs); regs_fail: + if (priv->phy_node) + of_node_put(priv->phy_node); + if (priv->tbi_node) + of_node_put(priv->tbi_node); free_netdev(dev); return err; } @@ -537,6 +491,11 @@ static int gfar_remove(struct of_device *ofdev) { struct gfar_private *priv = dev_get_drvdata(&ofdev->dev); + if (priv->phy_node) + of_node_put(priv->phy_node); + if (priv->tbi_node) + of_node_put(priv->tbi_node); + dev_set_drvdata(&ofdev->dev, NULL); iounmap(priv->regs); @@ -690,7 +649,6 @@ static int init_phy(struct net_device *dev) uint gigabit_support = priv->device_flags & FSL_GIANFAR_DEV_HAS_GIGABIT ? SUPPORTED_1000baseT_Full : 0; - struct phy_device *phydev; phy_interface_t interface; priv->oldlink = 0; @@ -699,21 +657,21 @@ static int init_phy(struct net_device *dev) interface = gfar_get_interface(dev); - phydev = phy_connect(dev, priv->phy_bus_id, &adjust_link, 0, interface); + if (priv->phy_node) { + priv->phydev = of_phy_connect(dev, priv->phy_node, &adjust_link, + 0, interface); + if (!priv->phydev) { + dev_err(&dev->dev, "error: Could not attach to PHY\n"); + return -ENODEV; + } + } if (interface == PHY_INTERFACE_MODE_SGMII) gfar_configure_serdes(dev); - if (IS_ERR(phydev)) { - printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name); - return PTR_ERR(phydev); - } - /* Remove any features not supported by the controller */ - phydev->supported &= (GFAR_SUPPORTED | gigabit_support); - phydev->advertising = phydev->supported; - - priv->phydev = phydev; + priv->phydev->supported &= (GFAR_SUPPORTED | gigabit_support); + priv->phydev->advertising = priv->phydev->supported; return 0; } @@ -730,10 +688,17 @@ static int init_phy(struct net_device *dev) static void gfar_configure_serdes(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); + struct phy_device *tbiphy; - if (!priv->tbiphy) { - printk(KERN_WARNING "SGMII mode requires that the device " - "tree specify a tbi-handle\n"); + if (!priv->tbi_node) { + dev_warn(&dev->dev, "error: SGMII mode requires that the " + "device tree specify a tbi-handle\n"); + return; + } + + tbiphy = of_phy_find_device(priv->tbi_node); + if (!tbiphy) { + dev_err(&dev->dev, "error: Could not get TBI device\n"); return; } @@ -743,17 +708,17 @@ static void gfar_configure_serdes(struct net_device *dev) * everything for us? Resetting it takes the link down and requires * several seconds for it to come back. */ - if (phy_read(priv->tbiphy, MII_BMSR) & BMSR_LSTATUS) + if (phy_read(tbiphy, MII_BMSR) & BMSR_LSTATUS) return; /* Single clk mode, mii mode off(for serdes communication) */ - phy_write(priv->tbiphy, MII_TBICON, TBICON_CLK_SELECT); + phy_write(tbiphy, MII_TBICON, TBICON_CLK_SELECT); - phy_write(priv->tbiphy, MII_ADVERTISE, + phy_write(tbiphy, MII_ADVERTISE, ADVERTISE_1000XFULL | ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM); - phy_write(priv->tbiphy, MII_BMCR, BMCR_ANENABLE | + phy_write(tbiphy, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART | BMCR_FULLDPLX | BMCR_SPEED1000); } @@ -1242,7 +1207,8 @@ static int gfar_enet_open(struct net_device *dev) static inline struct txfcb *gfar_add_fcb(struct sk_buff *skb) { struct txfcb *fcb = (struct txfcb *)skb_push(skb, GMAC_FCB_LEN); - cacheable_memzero(fcb, GMAC_FCB_LEN); + + memset(fcb, 0, GMAC_FCB_LEN); return fcb; } diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h index cf352961ae9b..2cd94338b5d3 100644 --- a/drivers/net/gianfar.h +++ b/drivers/net/gianfar.h @@ -779,7 +779,8 @@ struct gfar_private { spinlock_t bflock; phy_interface_t interface; - char phy_bus_id[BUS_ID_SIZE]; + struct device_node *phy_node; + struct device_node *tbi_node; u32 device_flags; unsigned char rx_csum_enable:1, extended_hash:1, @@ -793,7 +794,6 @@ struct gfar_private { /* PHY stuff */ struct phy_device *phydev; - struct phy_device *tbiphy; struct mii_bus *mii_bus; int oldspeed; int oldduplex; diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c index 310ee035067c..9d5b62cb30f7 100644 --- a/drivers/net/hamachi.c +++ b/drivers/net/hamachi.c @@ -1163,7 +1163,7 @@ static void hamachi_tx_timeout(struct net_device *dev) hmp->rx_ring[RX_RING_SIZE-1].status_n_length |= cpu_to_le32(DescEndRing); /* Trigger an immediate transmit demand. */ - dev->trans_start = jiffies; + dev->trans_start = jiffies; /* prevent tx timeout */ hmp->stats.tx_errors++; /* Restart the chip's Tx/Rx processes . */ @@ -1280,7 +1280,7 @@ static int hamachi_start_xmit(struct sk_buff *skb, struct net_device *dev) status=readw(hmp->base + TxStatus); if( !(status & 0x0001) || (status & 0x0002)) writew(0x0001, hmp->base + TxCmd); - return 1; + return NETDEV_TX_BUSY; } /* Caution: the write order is important here, set the field @@ -1364,7 +1364,6 @@ static int hamachi_start_xmit(struct sk_buff *skb, struct net_device *dev) hmp->tx_full = 1; netif_stop_queue(dev); } - dev->trans_start = jiffies; if (hamachi_debug > 4) { printk(KERN_DEBUG "%s: Hamachi transmit frame #%d queued in slot %d.\n", diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c index bb78c11559cd..5e4b7afd0683 100644 --- a/drivers/net/hamradio/baycom_epp.c +++ b/drivers/net/hamradio/baycom_epp.c @@ -777,7 +777,7 @@ static int baycom_send_packet(struct sk_buff *skb, struct net_device *dev) return 0; } if (bc->skb) - return -1; + return NETDEV_TX_LOCKED; /* strip KISS byte */ if (skb->len >= HDLCDRV_MAXFLEN+1 || skb->len < 3) { dev_kfree_skb(skb); diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c index d509b371a562..abcd19a8bff9 100644 --- a/drivers/net/hamradio/bpqether.c +++ b/drivers/net/hamradio/bpqether.c @@ -260,7 +260,7 @@ static int bpq_xmit(struct sk_buff *skb, struct net_device *dev) */ if (!netif_running(dev)) { kfree_skb(skb); - return -ENODEV; + return NETDEV_TX_OK; } skb_pull(skb, 1); @@ -274,7 +274,7 @@ static int bpq_xmit(struct sk_buff *skb, struct net_device *dev) if ((newskb = skb_realloc_headroom(skb, AX25_BPQ_HEADER_LEN)) == NULL) { printk(KERN_WARNING "bpqether: out of memory\n"); kfree_skb(skb); - return -ENOMEM; + return NETDEV_TX_OK; } if (skb->sk != NULL) @@ -294,7 +294,7 @@ static int bpq_xmit(struct sk_buff *skb, struct net_device *dev) if ((dev = bpq_get_ether_dev(dev)) == NULL) { dev->stats.tx_dropped++; kfree_skb(skb); - return -ENODEV; + return NETDEV_TX_OK; } skb->protocol = ax25_type_trans(skb, dev); diff --git a/drivers/net/hamradio/hdlcdrv.c b/drivers/net/hamradio/hdlcdrv.c index 61de56e45eed..d034f8ca63cb 100644 --- a/drivers/net/hamradio/hdlcdrv.c +++ b/drivers/net/hamradio/hdlcdrv.c @@ -409,7 +409,7 @@ static int hdlcdrv_send_packet(struct sk_buff *skb, struct net_device *dev) return 0; } if (sm->skb) - return -1; + return NETDEV_TX_LOCKED; netif_stop_queue(dev); sm->skb = skb; return 0; diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index 032c0db4c410..fda2fc83e9a1 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -531,7 +531,7 @@ static int ax_xmit(struct sk_buff *skb, struct net_device *dev) if (!netif_running(dev)) { printk(KERN_ERR "mkiss: %s: xmit call when iface is down\n", dev->name); - return 1; + return NETDEV_TX_BUSY; } if (netif_queue_stopped(dev)) { @@ -541,7 +541,7 @@ static int ax_xmit(struct sk_buff *skb, struct net_device *dev) */ if (time_before(jiffies, dev->trans_start + 20 * HZ)) { /* 20 sec timeout not reached */ - return 1; + return NETDEV_TX_BUSY; } printk(KERN_ERR "mkiss: %s: transmit timed out, %s?\n", dev->name, diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c index de3f49f991a3..1d3429a415e6 100644 --- a/drivers/net/hp100.c +++ b/drivers/net/hp100.c @@ -1495,13 +1495,8 @@ static int hp100_start_xmit_bm(struct sk_buff *skb, struct net_device *dev) hp100_outw(0x4210, TRACE); printk("hp100: %s: start_xmit_bm\n", dev->name); #endif - - if (skb == NULL) { - return 0; - } - if (skb->len <= 0) - return 0; + goto drop; if (lp->chip == HP100_CHIPID_SHASTA && skb_padto(skb, ETH_ZLEN)) return 0; @@ -1514,10 +1509,10 @@ static int hp100_start_xmit_bm(struct sk_buff *skb, struct net_device *dev) #endif /* not waited long enough since last tx? */ if (time_before(jiffies, dev->trans_start + HZ)) - return -EAGAIN; + goto drop; if (hp100_check_lan(dev)) - return -EIO; + goto drop; if (lp->lan_type == HP100_LAN_100 && lp->hub_status < 0) { /* we have a 100Mb/s adapter but it isn't connected to hub */ @@ -1551,7 +1546,7 @@ static int hp100_start_xmit_bm(struct sk_buff *skb, struct net_device *dev) } dev->trans_start = jiffies; - return -EAGAIN; + goto drop; } /* @@ -1591,6 +1586,10 @@ static int hp100_start_xmit_bm(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; return 0; + +drop: + dev_kfree_skb(skb); + return NETDEV_TX_OK; } @@ -1648,16 +1647,11 @@ static int hp100_start_xmit(struct sk_buff *skb, struct net_device *dev) hp100_outw(0x4212, TRACE); printk("hp100: %s: start_xmit\n", dev->name); #endif - - if (skb == NULL) { - return 0; - } - if (skb->len <= 0) - return 0; + goto drop; if (hp100_check_lan(dev)) - return -EIO; + goto drop; /* If there is not enough free memory on the card... */ i = hp100_inl(TX_MEM_FREE) & 0x7fffffff; @@ -1671,7 +1665,7 @@ static int hp100_start_xmit(struct sk_buff *skb, struct net_device *dev) printk("hp100: %s: trans_start timing problem\n", dev->name); #endif - return -EAGAIN; + goto drop; } if (lp->lan_type == HP100_LAN_100 && lp->hub_status < 0) { /* we have a 100Mb/s adapter but it isn't connected to hub */ @@ -1705,7 +1699,7 @@ static int hp100_start_xmit(struct sk_buff *skb, struct net_device *dev) } } dev->trans_start = jiffies; - return -EAGAIN; + goto drop; } for (i = 0; i < 6000 && (hp100_inb(OPTION_MSW) & HP100_TX_CMD); i++) { @@ -1759,6 +1753,11 @@ static int hp100_start_xmit(struct sk_buff *skb, struct net_device *dev) #endif return 0; + +drop: + dev_kfree_skb(skb); + return NETDEV_TX_OK; + } @@ -2864,7 +2863,7 @@ static int __init hp100_eisa_probe (struct device *gendev) printk("hp100: %s: EISA adapter found at 0x%x\n", dev->name, dev->base_addr); #endif - gendev->driver_data = dev; + dev_set_drvdata(gendev, dev); return 0; out1: free_netdev(dev); @@ -2873,7 +2872,7 @@ static int __init hp100_eisa_probe (struct device *gendev) static int __devexit hp100_eisa_remove (struct device *gendev) { - struct net_device *dev = gendev->driver_data; + struct net_device *dev = dev_get_drvdata(gendev); cleanup_dev(dev); return 0; } diff --git a/drivers/net/hplance.c b/drivers/net/hplance.c index 2e802634d366..3e3528ade259 100644 --- a/drivers/net/hplance.c +++ b/drivers/net/hplance.c @@ -71,6 +71,19 @@ static struct dio_driver hplance_driver = { .remove = __devexit_p(hplance_remove_one), }; +static const struct net_device_ops hplance_netdev_ops = { + .ndo_open = hplance_open, + .ndo_stop = hplance_close, + .ndo_start_xmit = lance_start_xmit, + .ndo_set_multicast_list = lance_set_multicast, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = lance_poll, +#endif +}; + /* Find all the HP Lance boards and initialise them... */ static int __devinit hplance_init_one(struct dio_dev *d, const struct dio_device_id *ent) @@ -135,13 +148,7 @@ static void __init hplance_init(struct net_device *dev, struct dio_dev *d) /* Fill the dev fields */ dev->base_addr = va; - dev->open = &hplance_open; - dev->stop = &hplance_close; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = lance_poll; -#endif - dev->hard_start_xmit = &lance_start_xmit; - dev->set_multicast_list = &lance_set_multicast; + dev->netdev_ops = &hplance_netdev_ops; dev->dma = 0; for (i=0; i<6; i++) { diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c index 806533c831c7..beb84213b671 100644 --- a/drivers/net/ibm_newemac/core.c +++ b/drivers/net/ibm_newemac/core.c @@ -1484,7 +1484,7 @@ static int emac_start_xmit_sg(struct sk_buff *skb, struct net_device *ndev) stop_queue: netif_stop_queue(ndev); DBG2(dev, "stopped TX queue" NL); - return 1; + return NETDEV_TX_BUSY; } /* Tx lock BHs */ diff --git a/drivers/net/ibmlana.c b/drivers/net/ibmlana.c index c25bc0bc0b25..448098d3b39b 100644 --- a/drivers/net/ibmlana.c +++ b/drivers/net/ibmlana.c @@ -815,7 +815,7 @@ static int ibmlana_close(struct net_device *dev) static int ibmlana_tx(struct sk_buff *skb, struct net_device *dev) { ibmlana_priv *priv = netdev_priv(dev); - int retval = 0, tmplen, addr; + int tmplen, addr; unsigned long flags; tda_t tda; int baddr; @@ -824,7 +824,6 @@ static int ibmlana_tx(struct sk_buff *skb, struct net_device *dev) the upper layer is in deep desperation and we simply ignore the frame. */ if (priv->txusedcnt >= TXBUFCNT) { - retval = -EIO; dev->stats.tx_dropped++; goto tx_done; } @@ -874,7 +873,7 @@ static int ibmlana_tx(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&priv->lock, flags); tx_done: dev_kfree_skb(skb); - return retval; + return NETDEV_TX_OK; } /* switch receiver mode. */ diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 5c6315df86b9..0995c438f286 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -1203,6 +1203,20 @@ static unsigned long ibmveth_get_desired_dma(struct vio_dev *vdev) return ret; } +static const struct net_device_ops ibmveth_netdev_ops = { + .ndo_open = ibmveth_open, + .ndo_stop = ibmveth_close, + .ndo_start_xmit = ibmveth_start_xmit, + .ndo_set_multicast_list = ibmveth_set_multicast_list, + .ndo_do_ioctl = ibmveth_ioctl, + .ndo_change_mtu = ibmveth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = ibmveth_poll_controller, +#endif +}; + static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id) { int rc, i; @@ -1241,7 +1255,7 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ return -ENOMEM; adapter = netdev_priv(netdev); - dev->dev.driver_data = netdev; + dev_set_drvdata(&dev->dev, netdev); adapter->vdev = dev; adapter->netdev = netdev; @@ -1265,21 +1279,13 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ memcpy(&adapter->mac_addr, mac_addr_p, 6); netdev->irq = dev->irq; - netdev->open = ibmveth_open; - netdev->stop = ibmveth_close; - netdev->hard_start_xmit = ibmveth_start_xmit; - netdev->set_multicast_list = ibmveth_set_multicast_list; - netdev->do_ioctl = ibmveth_ioctl; - netdev->ethtool_ops = &netdev_ethtool_ops; - netdev->change_mtu = ibmveth_change_mtu; + netdev->netdev_ops = &ibmveth_netdev_ops; + netdev->ethtool_ops = &netdev_ethtool_ops; SET_NETDEV_DEV(netdev, &dev->dev); -#ifdef CONFIG_NET_POLL_CONTROLLER - netdev->poll_controller = ibmveth_poll_controller; -#endif netdev->features |= NETIF_F_LLTX; spin_lock_init(&adapter->stats_lock); - memcpy(&netdev->dev_addr, &adapter->mac_addr, netdev->addr_len); + memcpy(netdev->dev_addr, &adapter->mac_addr, netdev->addr_len); for(i = 0; irx_buff_pool[i].kobj; @@ -1335,7 +1341,7 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ static int __devexit ibmveth_remove(struct vio_dev *dev) { - struct net_device *netdev = dev->dev.driver_data; + struct net_device *netdev = dev_get_drvdata(&dev->dev); struct ibmveth_adapter *adapter = netdev_priv(netdev); int i; @@ -1368,8 +1374,8 @@ static void ibmveth_proc_unregister_driver(void) static int ibmveth_show(struct seq_file *seq, void *v) { struct ibmveth_adapter *adapter = seq->private; - char *current_mac = ((char*) &adapter->netdev->dev_addr); - char *firmware_mac = ((char*) &adapter->mac_addr) ; + char *current_mac = (char *) adapter->netdev->dev_addr; + char *firmware_mac = (char *) &adapter->mac_addr; seq_printf(seq, "%s %s\n\n", ibmveth_driver_string, ibmveth_driver_version); @@ -1468,8 +1474,8 @@ const char * buf, size_t count) struct ibmveth_buff_pool *pool = container_of(kobj, struct ibmveth_buff_pool, kobj); - struct net_device *netdev = - container_of(kobj->parent, struct device, kobj)->driver_data; + struct net_device *netdev = dev_get_drvdata( + container_of(kobj->parent, struct device, kobj)); struct ibmveth_adapter *adapter = netdev_priv(netdev); long value = simple_strtol(buf, NULL, 10); long rc; diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c index 60a263001933..96713ef06298 100644 --- a/drivers/net/ifb.c +++ b/drivers/net/ifb.c @@ -156,6 +156,7 @@ static void ifb_setup(struct net_device *dev) dev->flags |= IFF_NOARP; dev->flags &= ~IFF_MULTICAST; + dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; random_ether_addr(dev->dev_addr); } diff --git a/drivers/net/igb/e1000_82575.h b/drivers/net/igb/e1000_82575.h index eaf977050368..0f16abab2565 100644 --- a/drivers/net/igb/e1000_82575.h +++ b/drivers/net/igb/e1000_82575.h @@ -130,6 +130,7 @@ struct e1000_adv_tx_context_desc { #define E1000_ADVTXD_MACLEN_SHIFT 9 /* Adv ctxt desc mac len shift */ #define E1000_ADVTXD_TUCMD_IPV4 0x00000400 /* IP Packet Type: 1=IPv4 */ #define E1000_ADVTXD_TUCMD_L4T_TCP 0x00000800 /* L4 Packet TYPE of TCP */ +#define E1000_ADVTXD_TUCMD_L4T_SCTP 0x00001000 /* L4 packet TYPE of SCTP */ /* IPSec Encrypt Enable for ESP */ #define E1000_ADVTXD_L4LEN_SHIFT 8 /* Adv ctxt L4LEN shift */ #define E1000_ADVTXD_MSS_SHIFT 16 /* Adv ctxt MSS shift */ diff --git a/drivers/net/igb/e1000_defines.h b/drivers/net/igb/e1000_defines.h index ad2d319d0f8b..3bda3db73f1f 100644 --- a/drivers/net/igb/e1000_defines.h +++ b/drivers/net/igb/e1000_defines.h @@ -289,8 +289,9 @@ #define E1000_SCTL_DISABLE_SERDES_LOOPBACK 0x0400 /* Receive Checksum Control */ +#define E1000_RXCSUM_IPOFL 0x00000100 /* IPv4 checksum offload */ #define E1000_RXCSUM_TUOFL 0x00000200 /* TCP / UDP checksum offload */ -#define E1000_RXCSUM_IPPCSE 0x00001000 /* IP payload checksum enable */ +#define E1000_RXCSUM_CRCOFL 0x00000800 /* CRC32 offload enable */ #define E1000_RXCSUM_PCSD 0x00002000 /* packet checksum disabled */ /* Header split receive */ diff --git a/drivers/net/igb/e1000_mbx.c b/drivers/net/igb/e1000_mbx.c index 840782fb5736..ed9058eca45c 100644 --- a/drivers/net/igb/e1000_mbx.c +++ b/drivers/net/igb/e1000_mbx.c @@ -140,13 +140,13 @@ static s32 igb_poll_for_msg(struct e1000_hw *hw, u16 mbx_id) struct e1000_mbx_info *mbx = &hw->mbx; int countdown = mbx->timeout; - if (!mbx->ops.check_for_msg) + if (!countdown || !mbx->ops.check_for_msg) goto out; while (mbx->ops.check_for_msg(hw, mbx_id)) { + countdown--; if (!countdown) break; - countdown--; udelay(mbx->usec_delay); } out: @@ -165,13 +165,13 @@ static s32 igb_poll_for_ack(struct e1000_hw *hw, u16 mbx_id) struct e1000_mbx_info *mbx = &hw->mbx; int countdown = mbx->timeout; - if (!mbx->ops.check_for_ack) + if (!countdown || !mbx->ops.check_for_ack) goto out; while (mbx->ops.check_for_ack(hw, mbx_id)) { + countdown--; if (!countdown) break; - countdown--; udelay(mbx->usec_delay); } out: diff --git a/drivers/net/igb/e1000_phy.h b/drivers/net/igb/e1000_phy.h index 3228a862031f..ebe4b616db8a 100644 --- a/drivers/net/igb/e1000_phy.h +++ b/drivers/net/igb/e1000_phy.h @@ -80,7 +80,7 @@ s32 igb_phy_init_script_igp3(struct e1000_hw *hw); #define IGP02E1000_PM_D3_LPLU 0x0004 /* For all other states */ #define IGP01E1000_PLHR_SS_DOWNGRADE 0x8000 #define IGP01E1000_PSSR_POLARITY_REVERSED 0x0002 -#define IGP01E1000_PSSR_MDIX 0x0008 +#define IGP01E1000_PSSR_MDIX 0x0800 #define IGP01E1000_PSSR_SPEED_MASK 0xC000 #define IGP01E1000_PSSR_SPEED_1000MBPS 0xC000 #define IGP02E1000_PHY_CHANNEL_NUM 4 diff --git a/drivers/net/igb/e1000_regs.h b/drivers/net/igb/e1000_regs.h index 0bd7728fe469..6e5924511e40 100644 --- a/drivers/net/igb/e1000_regs.h +++ b/drivers/net/igb/e1000_regs.h @@ -142,6 +142,7 @@ enum { #define E1000_SYNQF(_n) (0x055FC + (4 * (_n))) /* SYN Packet Queue Fltr */ #define E1000_ETQF(_n) (0x05CB0 + (4 * (_n))) /* EType Queue Fltr */ +#define E1000_RQDPC(_n) (0x0C030 + ((_n) * 0x40)) /* Split and Replication RX Control - RW */ /* * Convenience macros diff --git a/drivers/net/igb/igb.h b/drivers/net/igb/igb.h index 4e8464b9df2e..b2c98dea9eed 100644 --- a/drivers/net/igb/igb.h +++ b/drivers/net/igb/igb.h @@ -137,11 +137,17 @@ struct igb_buffer { }; }; -struct igb_queue_stats { +struct igb_tx_queue_stats { u64 packets; u64 bytes; }; +struct igb_rx_queue_stats { + u64 packets; + u64 bytes; + u64 drops; +}; + struct igb_ring { struct igb_adapter *adapter; /* backlink */ void *desc; /* descriptor ring memory */ @@ -167,12 +173,13 @@ struct igb_ring { union { /* TX */ struct { - struct igb_queue_stats tx_stats; + struct igb_tx_queue_stats tx_stats; bool detect_tx_hung; }; /* RX */ struct { - struct igb_queue_stats rx_stats; + struct igb_rx_queue_stats rx_stats; + u64 rx_queue_drops; struct napi_struct napi; int set_itr; struct igb_ring *buddy; @@ -238,7 +245,6 @@ struct igb_adapter { u64 hw_csum_err; u64 hw_csum_good; u32 alloc_rx_buff_failed; - bool rx_csum; u32 gorc; u64 gorc_old; u16 rx_ps_hdr_size; @@ -286,6 +292,7 @@ struct igb_adapter { #define IGB_FLAG_DCA_ENABLED (1 << 1) #define IGB_FLAG_QUAD_PORT_A (1 << 2) #define IGB_FLAG_NEED_CTX_IDX (1 << 3) +#define IGB_FLAG_RX_CSUM_DISABLED (1 << 4) enum e1000_state_t { __IGB_TESTING, diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c index 27eae49e79c2..9598ac09f4b8 100644 --- a/drivers/net/igb/igb_ethtool.c +++ b/drivers/net/igb/igb_ethtool.c @@ -64,6 +64,7 @@ static const struct igb_stats igb_gstrings_stats[] = { { "rx_crc_errors", IGB_STAT(stats.crcerrs) }, { "rx_frame_errors", IGB_STAT(net_stats.rx_frame_errors) }, { "rx_no_buffer_count", IGB_STAT(stats.rnbc) }, + { "rx_queue_drop_packet_count", IGB_STAT(net_stats.rx_fifo_errors) }, { "rx_missed_errors", IGB_STAT(stats.mpc) }, { "tx_aborted_errors", IGB_STAT(stats.ecol) }, { "tx_carrier_errors", IGB_STAT(stats.tncrs) }, @@ -96,9 +97,10 @@ static const struct igb_stats igb_gstrings_stats[] = { }; #define IGB_QUEUE_STATS_LEN \ - ((((struct igb_adapter *)netdev_priv(netdev))->num_rx_queues + \ - ((struct igb_adapter *)netdev_priv(netdev))->num_tx_queues) * \ - (sizeof(struct igb_queue_stats) / sizeof(u64))) + (((((struct igb_adapter *)netdev_priv(netdev))->num_rx_queues)* \ + (sizeof(struct igb_rx_queue_stats) / sizeof(u64))) + \ + ((((struct igb_adapter *)netdev_priv(netdev))->num_tx_queues) * \ + (sizeof(struct igb_tx_queue_stats) / sizeof(u64)))) #define IGB_GLOBAL_STATS_LEN \ sizeof(igb_gstrings_stats) / sizeof(struct igb_stats) #define IGB_STATS_LEN (IGB_GLOBAL_STATS_LEN + IGB_QUEUE_STATS_LEN) @@ -275,13 +277,17 @@ static int igb_set_pauseparam(struct net_device *netdev, static u32 igb_get_rx_csum(struct net_device *netdev) { struct igb_adapter *adapter = netdev_priv(netdev); - return adapter->rx_csum; + return !(adapter->flags & IGB_FLAG_RX_CSUM_DISABLED); } static int igb_set_rx_csum(struct net_device *netdev, u32 data) { struct igb_adapter *adapter = netdev_priv(netdev); - adapter->rx_csum = data; + + if (data) + adapter->flags &= ~IGB_FLAG_RX_CSUM_DISABLED; + else + adapter->flags |= IGB_FLAG_RX_CSUM_DISABLED; return 0; } @@ -293,10 +299,16 @@ static u32 igb_get_tx_csum(struct net_device *netdev) static int igb_set_tx_csum(struct net_device *netdev, u32 data) { - if (data) + struct igb_adapter *adapter = netdev_priv(netdev); + + if (data) { netdev->features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM); - else - netdev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM); + if (adapter->hw.mac.type == e1000_82576) + netdev->features |= NETIF_F_SCTP_CSUM; + } else { + netdev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_SCTP_CSUM); + } return 0; } @@ -1950,7 +1962,8 @@ static void igb_get_ethtool_stats(struct net_device *netdev, { struct igb_adapter *adapter = netdev_priv(netdev); u64 *queue_stat; - int stat_count = sizeof(struct igb_queue_stats) / sizeof(u64); + int stat_count_tx = sizeof(struct igb_tx_queue_stats) / sizeof(u64); + int stat_count_rx = sizeof(struct igb_rx_queue_stats) / sizeof(u64); int j; int i; @@ -1963,14 +1976,14 @@ static void igb_get_ethtool_stats(struct net_device *netdev, for (j = 0; j < adapter->num_tx_queues; j++) { int k; queue_stat = (u64 *)&adapter->tx_ring[j].tx_stats; - for (k = 0; k < stat_count; k++) + for (k = 0; k < stat_count_tx; k++) data[i + k] = queue_stat[k]; i += k; } for (j = 0; j < adapter->num_rx_queues; j++) { int k; queue_stat = (u64 *)&adapter->rx_ring[j].rx_stats; - for (k = 0; k < stat_count; k++) + for (k = 0; k < stat_count_rx; k++) data[i + k] = queue_stat[k]; i += k; } @@ -2004,6 +2017,8 @@ static void igb_get_strings(struct net_device *netdev, u32 stringset, u8 *data) p += ETH_GSTRING_LEN; sprintf(p, "rx_queue_%u_bytes", i); p += ETH_GSTRING_LEN; + sprintf(p, "rx_queue_%u_drops", i); + p += ETH_GSTRING_LEN; } /* BUG_ON(p - data != IGB_STATS_LEN * ETH_GSTRING_LEN); */ break; diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index e25343588fc7..ea17319624aa 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -942,6 +942,8 @@ int igb_up(struct igb_adapter *adapter) rd32(E1000_ICR); igb_irq_enable(adapter); + netif_tx_start_all_queues(adapter->netdev); + /* Fire a link change interrupt to start the watchdog. */ wr32(E1000_ICS, E1000_ICS_LSC); return 0; @@ -994,6 +996,11 @@ void igb_down(struct igb_adapter *adapter) igb_reset(adapter); igb_clean_all_tx_rings(adapter); igb_clean_all_rx_rings(adapter); +#ifdef CONFIG_IGB_DCA + + /* since we reset the hardware DCA settings were cleared */ + igb_setup_dca(adapter); +#endif } void igb_reinit_locked(struct igb_adapter *adapter) @@ -1343,6 +1350,9 @@ static int __devinit igb_probe(struct pci_dev *pdev, if (pci_using_dac) netdev->features |= NETIF_F_HIGHDMA; + if (adapter->hw.mac.type == e1000_82576) + netdev->features |= NETIF_F_SCTP_CSUM; + adapter->en_mng_pt = igb_enable_mng_pass_thru(&adapter->hw); /* before reading the NVM, reset the controller to put the device in a @@ -1390,8 +1400,6 @@ static int __devinit igb_probe(struct pci_dev *pdev, igb_validate_mdi_setting(hw); - adapter->rx_csum = 1; - /* Initial Wake on LAN setting If APM wake is enabled in the EEPROM, * enable the ACPI Magic Packet filter */ @@ -1442,22 +1450,18 @@ static int __devinit igb_probe(struct pci_dev *pdev, * driver. */ igb_get_hw_control(adapter); - /* tell the stack to leave us alone until igb_open() is called */ - netif_carrier_off(netdev); - netif_tx_stop_all_queues(netdev); - strcpy(netdev->name, "eth%d"); err = register_netdev(netdev); if (err) goto err_register; + /* carrier off reporting is important to ethtool even BEFORE open */ + netif_carrier_off(netdev); + #ifdef CONFIG_IGB_DCA if (dca_add_requester(&pdev->dev) == 0) { adapter->flags |= IGB_FLAG_DCA_ENABLED; dev_info(&pdev->dev, "DCA enabled\n"); - /* Always use CB2 mode, difference is masked - * in the CB driver. */ - wr32(E1000_DCA_CTRL, E1000_DCA_CTRL_DCA_MODE_CB2); igb_setup_dca(adapter); } #endif @@ -1699,6 +1703,8 @@ static int igb_open(struct net_device *netdev) if (test_bit(__IGB_TESTING, &adapter->state)) return -EBUSY; + netif_carrier_off(netdev); + /* allocate transmit descriptors */ err = igb_setup_all_tx_resources(adapter); if (err) @@ -2231,29 +2237,24 @@ static void igb_configure_rx(struct igb_adapter *adapter) mrqc |= (E1000_MRQC_RSS_FIELD_IPV6_UDP_EX | E1000_MRQC_RSS_FIELD_IPV6_TCP_EX); - wr32(E1000_MRQC, mrqc); - - /* Multiqueue and raw packet checksumming are mutually - * exclusive. Note that this not the same as TCP/IP - * checksumming, which works fine. */ - rxcsum = rd32(E1000_RXCSUM); - rxcsum |= E1000_RXCSUM_PCSD; - wr32(E1000_RXCSUM, rxcsum); - } else { + } else if (adapter->vfs_allocated_count) { /* Enable multi-queue for sr-iov */ - if (adapter->vfs_allocated_count) - wr32(E1000_MRQC, E1000_MRQC_ENABLE_VMDQ); - /* Enable Receive Checksum Offload for TCP and UDP */ - rxcsum = rd32(E1000_RXCSUM); - if (adapter->rx_csum) - rxcsum |= E1000_RXCSUM_TUOFL | E1000_RXCSUM_IPPCSE; - else - rxcsum &= ~(E1000_RXCSUM_TUOFL | E1000_RXCSUM_IPPCSE); - - wr32(E1000_RXCSUM, rxcsum); + wr32(E1000_MRQC, E1000_MRQC_ENABLE_VMDQ); } + /* Enable Receive Checksum Offload for TCP and UDP */ + rxcsum = rd32(E1000_RXCSUM); + /* Disable raw packet checksumming */ + rxcsum |= E1000_RXCSUM_PCSD; + + if (adapter->hw.mac.type == e1000_82576) + /* Enable Receive Checksum Offload for SCTP */ + rxcsum |= E1000_RXCSUM_CRCOFL; + + /* Don't need to set TUOFL or IPOFL, they default to 1 */ + wr32(E1000_RXCSUM, rxcsum); + /* Set the default pool for the PF's first queue */ igb_configure_vt_default_pool(adapter); @@ -2661,7 +2662,6 @@ static void igb_watchdog_task(struct work_struct *work) } netif_carrier_on(netdev); - netif_tx_wake_all_queues(netdev); igb_ping_all_vfs(adapter); @@ -2678,7 +2678,6 @@ static void igb_watchdog_task(struct work_struct *work) printk(KERN_INFO "igb: %s NIC Link is Down\n", netdev->name); netif_carrier_off(netdev); - netif_tx_stop_all_queues(netdev); igb_ping_all_vfs(adapter); @@ -2712,6 +2711,8 @@ link_up: * (Do the reset outside of interrupt context). */ adapter->tx_timeout_count++; schedule_work(&adapter->reset_task); + /* return immediately since reset is imminent */ + return; } } @@ -2895,13 +2896,13 @@ static void igb_set_itr(struct igb_adapter *adapter) switch (current_itr) { /* counts and packets in update_itr are dependent on these numbers */ case lowest_latency: - new_itr = 70000; + new_itr = 56; /* aka 70,000 ints/sec */ break; case low_latency: - new_itr = 20000; /* aka hwitr = ~200 */ + new_itr = 196; /* aka 20,000 ints/sec */ break; case bulk_latency: - new_itr = 4000; + new_itr = 980; /* aka 4,000 ints/sec */ break; default: break; @@ -2920,7 +2921,8 @@ set_itr_now: * by adding intermediate steps when interrupt rate is * increasing */ new_itr = new_itr > adapter->itr ? - min(adapter->itr + (new_itr >> 2), new_itr) : + max((new_itr * adapter->itr) / + (new_itr + (adapter->itr >> 2)), new_itr) : new_itr; /* Don't write the value here; it resets the adapter's * internal timer, and causes us to delay far longer than @@ -2929,7 +2931,7 @@ set_itr_now: * ends up being correct. */ adapter->itr = new_itr; - adapter->rx_ring->itr_val = 1000000000 / (new_itr * 256); + adapter->rx_ring->itr_val = new_itr; adapter->rx_ring->set_itr = 1; } @@ -3068,11 +3070,15 @@ static inline bool igb_tx_csum_adv(struct igb_adapter *adapter, tu_cmd |= E1000_ADVTXD_TUCMD_IPV4; if (ip_hdr(skb)->protocol == IPPROTO_TCP) tu_cmd |= E1000_ADVTXD_TUCMD_L4T_TCP; + else if (ip_hdr(skb)->protocol == IPPROTO_SCTP) + tu_cmd |= E1000_ADVTXD_TUCMD_L4T_SCTP; break; case cpu_to_be16(ETH_P_IPV6): /* XXX what about other V6 headers?? */ if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP) tu_cmd |= E1000_ADVTXD_TUCMD_L4T_TCP; + else if (ipv6_hdr(skb)->nexthdr == IPPROTO_SCTP) + tu_cmd |= E1000_ADVTXD_TUCMD_L4T_SCTP; break; default: if (unlikely(net_ratelimit())) @@ -3133,8 +3139,7 @@ static inline int igb_tx_map_adv(struct igb_adapter *adapter, /* set time_stamp *before* dma to help avoid a possible race */ buffer_info->time_stamp = jiffies; buffer_info->next_to_watch = i; - buffer_info->dma = map[count]; - count++; + buffer_info->dma = skb_shinfo(skb)->dma_head; for (f = 0; f < skb_shinfo(skb)->nr_frags; f++) { struct skb_frag_struct *frag; @@ -3158,7 +3163,7 @@ static inline int igb_tx_map_adv(struct igb_adapter *adapter, tx_ring->buffer_info[i].skb = skb; tx_ring->buffer_info[first].next_to_watch = i; - return count; + return count + 1; } static inline void igb_tx_queue_adv(struct igb_adapter *adapter, @@ -3338,7 +3343,6 @@ static int igb_xmit_frame_ring_adv(struct sk_buff *skb, if (count) { igb_tx_queue_adv(adapter, tx_ring, tx_flags, count, skb->len, hdr_len); - netdev->trans_start = jiffies; /* Make sure there is space in the ring for the next send. */ igb_maybe_stop_tx(netdev, tx_ring, MAX_SKB_FRAGS + 4); } else { @@ -3582,8 +3586,35 @@ void igb_update_stats(struct igb_adapter *adapter) /* Rx Errors */ + if (hw->mac.type != e1000_82575) { + u32 rqdpc_tmp; + u64 rqdpc_total = 0; + int i; + /* Read out drops stats per RX queue. Notice RQDPC (Receive + * Queue Drop Packet Count) stats only gets incremented, if + * the DROP_EN but it set (in the SRRCTL register for that + * queue). If DROP_EN bit is NOT set, then the some what + * equivalent count is stored in RNBC (not per queue basis). + * Also note the drop count is due to lack of available + * descriptors. + */ + for (i = 0; i < adapter->num_rx_queues; i++) { + rqdpc_tmp = rd32(E1000_RQDPC(i)) & 0xFFF; + adapter->rx_ring[i].rx_stats.drops += rqdpc_tmp; + rqdpc_total += adapter->rx_ring[i].rx_stats.drops; + } + adapter->net_stats.rx_fifo_errors = rqdpc_total; + } + + /* Note RNBC (Receive No Buffers Count) is an not an exact + * drop count as the hardware FIFO might save the day. Thats + * one of the reason for saving it in rx_fifo_errors, as its + * potentially not a true drop. + */ + adapter->net_stats.rx_fifo_errors += adapter->stats.rnbc; + /* RLEC on some newer hardware can be incorrect so build - * our own version based on RUC and ROC */ + * our own version based on RUC and ROC */ adapter->net_stats.rx_errors = adapter->stats.rxerrc + adapter->stats.crcerrs + adapter->stats.algnerrc + adapter->stats.ruc + adapter->stats.roc + @@ -3767,11 +3798,15 @@ static void igb_update_tx_dca(struct igb_ring *tx_ring) static void igb_setup_dca(struct igb_adapter *adapter) { + struct e1000_hw *hw = &adapter->hw; int i; if (!(adapter->flags & IGB_FLAG_DCA_ENABLED)) return; + /* Always use CB2 mode, difference is masked in the CB driver. */ + wr32(E1000_DCA_CTRL, E1000_DCA_CTRL_DCA_MODE_CB2); + for (i = 0; i < adapter->num_tx_queues; i++) { adapter->tx_ring[i].cpu = -1; igb_update_tx_dca(&adapter->tx_ring[i]); @@ -4434,20 +4469,12 @@ static void igb_receive_skb(struct igb_ring *ring, u8 status, bool vlan_extracted = (adapter->vlgrp && (status & E1000_RXD_STAT_VP)); skb_record_rx_queue(skb, ring->queue_index); - if (skb->ip_summed == CHECKSUM_UNNECESSARY) { - if (vlan_extracted) - vlan_gro_receive(&ring->napi, adapter->vlgrp, - le16_to_cpu(rx_desc->wb.upper.vlan), - skb); - else - napi_gro_receive(&ring->napi, skb); - } else { - if (vlan_extracted) - vlan_hwaccel_receive_skb(skb, adapter->vlgrp, - le16_to_cpu(rx_desc->wb.upper.vlan)); - else - netif_receive_skb(skb); - } + if (vlan_extracted) + vlan_gro_receive(&ring->napi, adapter->vlgrp, + le16_to_cpu(rx_desc->wb.upper.vlan), + skb); + else + napi_gro_receive(&ring->napi, skb); } static inline void igb_rx_checksum_adv(struct igb_adapter *adapter, @@ -4456,19 +4483,28 @@ static inline void igb_rx_checksum_adv(struct igb_adapter *adapter, skb->ip_summed = CHECKSUM_NONE; /* Ignore Checksum bit is set or checksum is disabled through ethtool */ - if ((status_err & E1000_RXD_STAT_IXSM) || !adapter->rx_csum) + if ((status_err & E1000_RXD_STAT_IXSM) || + (adapter->flags & IGB_FLAG_RX_CSUM_DISABLED)) return; /* TCP/UDP checksum error bit is set */ if (status_err & (E1000_RXDEXT_STATERR_TCPE | E1000_RXDEXT_STATERR_IPE)) { + /* + * work around errata with sctp packets where the TCPE aka + * L4E bit is set incorrectly on 64 byte (60 byte w/o crc) + * packets, (aka let the stack check the crc32c) + */ + if (!((adapter->hw.mac.type == e1000_82576) && + (skb->len == 60))) + adapter->hw_csum_err++; /* let the stack verify checksum errors */ - adapter->hw_csum_err++; return; } /* It must be a TCP or UDP packet with a valid checksum */ if (status_err & (E1000_RXD_STAT_TCPCS | E1000_RXD_STAT_UDPCS)) skb->ip_summed = CHECKSUM_UNNECESSARY; + dev_dbg(&adapter->pdev->dev, "cksum success: bits %08X\n", status_err); adapter->hw_csum_good++; } diff --git a/drivers/net/igbvf/ethtool.c b/drivers/net/igbvf/ethtool.c index 1dcaa6905312..ee17a097d1ca 100644 --- a/drivers/net/igbvf/ethtool.c +++ b/drivers/net/igbvf/ethtool.c @@ -133,6 +133,24 @@ static int igbvf_set_pauseparam(struct net_device *netdev, return -EOPNOTSUPP; } +static u32 igbvf_get_rx_csum(struct net_device *netdev) +{ + struct igbvf_adapter *adapter = netdev_priv(netdev); + return !(adapter->flags & IGBVF_FLAG_RX_CSUM_DISABLED); +} + +static int igbvf_set_rx_csum(struct net_device *netdev, u32 data) +{ + struct igbvf_adapter *adapter = netdev_priv(netdev); + + if (data) + adapter->flags &= ~IGBVF_FLAG_RX_CSUM_DISABLED; + else + adapter->flags |= IGBVF_FLAG_RX_CSUM_DISABLED; + + return 0; +} + static u32 igbvf_get_tx_csum(struct net_device *netdev) { return ((netdev->features & NETIF_F_IP_CSUM) != 0); @@ -150,8 +168,6 @@ static int igbvf_set_tx_csum(struct net_device *netdev, u32 data) static int igbvf_set_tso(struct net_device *netdev, u32 data) { struct igbvf_adapter *adapter = netdev_priv(netdev); - int i; - struct net_device *v_netdev; if (data) { netdev->features |= NETIF_F_TSO; @@ -159,24 +175,10 @@ static int igbvf_set_tso(struct net_device *netdev, u32 data) } else { netdev->features &= ~NETIF_F_TSO; netdev->features &= ~NETIF_F_TSO6; - /* disable TSO on all VLANs if they're present */ - if (!adapter->vlgrp) - goto tso_out; - for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { - v_netdev = vlan_group_get_device(adapter->vlgrp, i); - if (!v_netdev) - continue; - - v_netdev->features &= ~NETIF_F_TSO; - v_netdev->features &= ~NETIF_F_TSO6; - vlan_group_set_device(adapter->vlgrp, i, v_netdev); - } } -tso_out: dev_info(&adapter->pdev->dev, "TSO is %s\n", data ? "Enabled" : "Disabled"); - adapter->flags |= FLAG_TSO_FORCE; return 0; } @@ -517,6 +519,8 @@ static const struct ethtool_ops igbvf_ethtool_ops = { .set_ringparam = igbvf_set_ringparam, .get_pauseparam = igbvf_get_pauseparam, .set_pauseparam = igbvf_set_pauseparam, + .get_rx_csum = igbvf_get_rx_csum, + .set_rx_csum = igbvf_set_rx_csum, .get_tx_csum = igbvf_get_tx_csum, .set_tx_csum = igbvf_set_tx_csum, .get_sg = ethtool_op_get_sg, diff --git a/drivers/net/igbvf/igbvf.h b/drivers/net/igbvf/igbvf.h index 4bff35e46871..8e9b67ebbf8b 100644 --- a/drivers/net/igbvf/igbvf.h +++ b/drivers/net/igbvf/igbvf.h @@ -45,7 +45,7 @@ struct igbvf_adapter; /* Interrupt defines */ #define IGBVF_START_ITR 648 /* ~6000 ints/sec */ -/* Interrupt modes, as used by the IntMode paramter */ +/* Interrupt modes, as used by the IntMode parameter */ #define IGBVF_INT_MODE_LEGACY 0 #define IGBVF_INT_MODE_MSI 1 #define IGBVF_INT_MODE_MSIX 2 @@ -286,11 +286,7 @@ struct igbvf_info { }; /* hardware capability, feature, and workaround flags */ -#define FLAG_HAS_HW_VLAN_FILTER (1 << 0) -#define FLAG_HAS_JUMBO_FRAMES (1 << 1) -#define FLAG_MSI_ENABLED (1 << 2) -#define FLAG_RX_CSUM_ENABLED (1 << 3) -#define FLAG_TSO_FORCE (1 << 4) +#define IGBVF_FLAG_RX_CSUM_DISABLED (1 << 0) #define IGBVF_RX_DESC_ADV(R, i) \ (&((((R).desc))[i].rx_desc)) diff --git a/drivers/net/igbvf/netdev.c b/drivers/net/igbvf/netdev.c index b774666ad3cf..2bc9d63027db 100644 --- a/drivers/net/igbvf/netdev.c +++ b/drivers/net/igbvf/netdev.c @@ -58,8 +58,7 @@ static void igbvf_reset_interrupt_capability(struct igbvf_adapter *); static struct igbvf_info igbvf_vf_info = { .mac = e1000_vfadapt, - .flags = FLAG_HAS_JUMBO_FRAMES - | FLAG_RX_CSUM_ENABLED, + .flags = 0, .pba = 10, .init_ops = e1000_init_function_pointers_vf, }; @@ -107,8 +106,10 @@ static inline void igbvf_rx_checksum_adv(struct igbvf_adapter *adapter, skb->ip_summed = CHECKSUM_NONE; /* Ignore Checksum bit is set or checksum is disabled through ethtool */ - if ((status_err & E1000_RXD_STAT_IXSM)) + if ((status_err & E1000_RXD_STAT_IXSM) || + (adapter->flags & IGBVF_FLAG_RX_CSUM_DISABLED)) return; + /* TCP/UDP checksum error bit is set */ if (status_err & (E1000_RXDEXT_STATERR_TCPE | E1000_RXDEXT_STATERR_IPE)) { @@ -116,6 +117,7 @@ static inline void igbvf_rx_checksum_adv(struct igbvf_adapter *adapter, adapter->hw_csum_err++; return; } + /* It must be a TCP or UDP packet with a valid checksum */ if (status_err & (E1000_RXD_STAT_TCPCS | E1000_RXD_STAT_UDPCS)) skb->ip_summed = CHECKSUM_UNNECESSARY; @@ -1279,7 +1281,7 @@ static void igbvf_configure_tx(struct igbvf_adapter *adapter) /* Setup the HW Tx Head and Tail descriptor pointers */ ew32(TDLEN(0), tx_ring->count * sizeof(union e1000_adv_tx_desc)); tdba = tx_ring->dma; - ew32(TDBAL(0), (tdba & DMA_32BIT_MASK)); + ew32(TDBAL(0), (tdba & DMA_BIT_MASK(32))); ew32(TDBAH(0), (tdba >> 32)); ew32(TDH(0), 0); ew32(TDT(0), 0); @@ -1365,7 +1367,7 @@ static void igbvf_configure_rx(struct igbvf_adapter *adapter) * the Base and Length of the Rx Descriptor Ring */ rdba = rx_ring->dma; - ew32(RDBAL(0), (rdba & DMA_32BIT_MASK)); + ew32(RDBAL(0), (rdba & DMA_BIT_MASK(32))); ew32(RDBAH(0), (rdba >> 32)); ew32(RDLEN(0), rx_ring->count * sizeof(union e1000_adv_rx_desc)); rx_ring->head = E1000_RDH(0); @@ -2117,8 +2119,7 @@ static inline int igbvf_tx_map_adv(struct igbvf_adapter *adapter, /* set time_stamp *before* dma to help avoid a possible race */ buffer_info->time_stamp = jiffies; buffer_info->next_to_watch = i; - buffer_info->dma = map[count]; - count++; + buffer_info->dma = skb_shinfo(skb)->dma_head; for (f = 0; f < skb_shinfo(skb)->nr_frags; f++) { struct skb_frag_struct *frag; @@ -2142,7 +2143,7 @@ static inline int igbvf_tx_map_adv(struct igbvf_adapter *adapter, tx_ring->buffer_info[i].skb = skb; tx_ring->buffer_info[first].next_to_watch = i; - return count; + return count + 1; } static inline void igbvf_tx_queue_adv(struct igbvf_adapter *adapter, @@ -2268,7 +2269,6 @@ static int igbvf_xmit_frame_ring_adv(struct sk_buff *skb, if (count) { igbvf_tx_queue_adv(adapter, tx_ring, tx_flags, count, skb->len, hdr_len); - netdev->trans_start = jiffies; /* Make sure there is space in the ring for the next send. */ igbvf_maybe_stop_tx(netdev, MAX_SKB_FRAGS + 4); } else { @@ -2351,15 +2351,6 @@ static int igbvf_change_mtu(struct net_device *netdev, int new_mtu) return -EINVAL; } - /* Jumbo frame size limits */ - if (max_frame > ETH_FRAME_LEN + ETH_FCS_LEN) { - if (!(adapter->flags & FLAG_HAS_JUMBO_FRAMES)) { - dev_err(&adapter->pdev->dev, - "Jumbo Frames not supported.\n"); - return -EINVAL; - } - } - #define MAX_STD_JUMBO_FRAME_SIZE 9234 if (max_frame > MAX_STD_JUMBO_FRAME_SIZE) { dev_err(&adapter->pdev->dev, "MTU > 9216 not supported.\n"); @@ -2637,15 +2628,16 @@ static int __devinit igbvf_probe(struct pci_dev *pdev, return err; pci_using_dac = 0; - err = pci_set_dma_mask(pdev, DMA_64BIT_MASK); + err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); if (!err) { - err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); + err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); if (!err) pci_using_dac = 1; } else { - err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); if (err) { - err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); + err = pci_set_consistent_dma_mask(pdev, + DMA_BIT_MASK(32)); if (err) { dev_err(&pdev->dev, "No usable DMA " "configuration, aborting\n"); diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c index c5593f4665a4..e3cfefab670c 100644 --- a/drivers/net/ioc3-eth.c +++ b/drivers/net/ioc3-eth.c @@ -530,7 +530,7 @@ static void ioc3_tcpudp_checksum(struct sk_buff *skb, uint32_t hwsum, int len) * case where the checksum is right the higher layers will still * drop the packet as appropriate. */ - if (eh->h_proto != ntohs(ETH_P_IP)) + if (eh->h_proto != htons(ETH_P_IP)) return; ih = (struct iphdr *) ((char *)eh + ETH_HLEN); diff --git a/drivers/net/ipg.h b/drivers/net/ipg.h index dd9318f19497..dfc2541bb556 100644 --- a/drivers/net/ipg.h +++ b/drivers/net/ipg.h @@ -514,7 +514,7 @@ enum ipg_regs { #define IPG_DMALIST_ALIGN_PAD 0x07 #define IPG_MULTICAST_HASHTABLE_SIZE 0x40 -/* Number of miliseconds to wait after issuing a software reset. +/* Number of milliseconds to wait after issuing a software reset. * 0x05 <= IPG_AC_RESETWAIT to account for proper 10Mbps operation. */ #define IPG_AC_RESETWAIT 0x05 diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig index e6317557a531..f76384221422 100644 --- a/drivers/net/irda/Kconfig +++ b/drivers/net/irda/Kconfig @@ -17,6 +17,51 @@ config IRTTY_SIR If unsure, say Y. +config BFIN_SIR + tristate "Blackfin SIR on UART" + depends on BLACKFIN && IRDA + default n + help + Say Y here if your want to enable SIR function on Blackfin UART + devices. + + To activate this driver you can start irattach like: + "irattach irda0 -s" + + Saying M, it will be built as a module named bfin_sir. + + Note that you need to turn off one of the serial drivers for SIR + to use that UART. + +config BFIN_SIR0 + bool "Blackfin SIR on UART0" + depends on BFIN_SIR && !SERIAL_BFIN_UART0 + +config BFIN_SIR1 + bool "Blackfin SIR on UART1" + depends on BFIN_SIR && !SERIAL_BFIN_UART1 && (!BF531 && !BF532 && !BF533 && !BF561) + +config BFIN_SIR2 + bool "Blackfin SIR on UART2" + depends on BFIN_SIR && !SERIAL_BFIN_UART2 && (BF54x || BF538 || BF539) + +config BFIN_SIR3 + bool "Blackfin SIR on UART3" + depends on BFIN_SIR && !SERIAL_BFIN_UART3 && (BF54x) + +choice + prompt "SIR Mode" + depends on BFIN_SIR + default SIR_BFIN_DMA + +config SIR_BFIN_DMA + bool "DMA mode" + depends on !DMA_UNCACHED_NONE + +config SIR_BFIN_PIO + bool "PIO mode" +endchoice + comment "Dongle support" config DONGLE diff --git a/drivers/net/irda/Makefile b/drivers/net/irda/Makefile index 5d20fde32a24..d82e1e3bd8c8 100644 --- a/drivers/net/irda/Makefile +++ b/drivers/net/irda/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_MCS_FIR) += mcs7780.o obj-$(CONFIG_AU1000_FIR) += au1k_ir.o # SIR drivers obj-$(CONFIG_IRTTY_SIR) += irtty-sir.o sir-dev.o +obj-$(CONFIG_BFIN_SIR) += bfin_sir.o # dongle drivers for SIR drivers obj-$(CONFIG_ESI_DONGLE) += esi-sir.o obj-$(CONFIG_TEKRAM_DONGLE) += tekram-sir.o diff --git a/drivers/net/irda/au1k_ir.c b/drivers/net/irda/au1k_ir.c index 941164076a2b..c4361d466597 100644 --- a/drivers/net/irda/au1k_ir.c +++ b/drivers/net/irda/au1k_ir.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -198,6 +199,17 @@ static int au1k_irda_init_iobuf(iobuff_t *io, int size) return io->head ? 0 : -ENOMEM; } +static const struct net_device_ops au1k_irda_netdev_ops = { + .ndo_open = au1k_irda_start, + .ndo_stop = au1k_irda_stop, + .ndo_start_xmit = au1k_irda_hard_xmit, + .ndo_tx_timeout = au1k_tx_timeout, + .ndo_do_ioctl = au1k_irda_ioctl, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, +}; + static int au1k_irda_net_init(struct net_device *dev) { struct au1k_private *aup = netdev_priv(dev); @@ -209,11 +221,7 @@ static int au1k_irda_net_init(struct net_device *dev) if (err) goto out1; - dev->open = au1k_irda_start; - dev->hard_start_xmit = au1k_irda_hard_xmit; - dev->stop = au1k_irda_stop; - dev->do_ioctl = au1k_irda_ioctl; - dev->tx_timeout = au1k_tx_timeout; + dev->netdev_ops = &au1k_irda_netdev_ops; irda_init_max_qos_capabilies(&aup->qos); @@ -504,13 +512,13 @@ static int au1k_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) printk(KERN_DEBUG "%s: tx_full\n", dev->name); netif_stop_queue(dev); aup->tx_full = 1; - return 1; + return NETDEV_TX_BUSY; } else if (((aup->tx_head + 1) & (NUM_IR_DESC - 1)) == aup->tx_tail) { printk(KERN_DEBUG "%s: tx_full\n", dev->name); netif_stop_queue(dev); aup->tx_full = 1; - return 1; + return NETDEV_TX_BUSY; } pDB = aup->tx_db_inuse[aup->tx_head]; diff --git a/drivers/net/irda/bfin_sir.c b/drivers/net/irda/bfin_sir.c new file mode 100644 index 000000000000..f3eed6a8fba5 --- /dev/null +++ b/drivers/net/irda/bfin_sir.c @@ -0,0 +1,820 @@ +/* + * Blackfin Infra-red Driver + * + * Copyright 2006-2009 Analog Devices Inc. + * + * Enter bugs at http://blackfin.uclinux.org/ + * + * Licensed under the GPL-2 or later. + * + */ +#include "bfin_sir.h" + +#ifdef CONFIG_SIR_BFIN_DMA +#define DMA_SIR_RX_XCNT 10 +#define DMA_SIR_RX_YCNT (PAGE_SIZE / DMA_SIR_RX_XCNT) +#define DMA_SIR_RX_FLUSH_JIFS (HZ * 4 / 250) +#endif + +#if ANOMALY_05000447 +static int max_rate = 57600; +#else +static int max_rate = 115200; +#endif + +static void turnaround_delay(unsigned long last_jif, int mtt) +{ + long ticks; + + mtt = mtt < 10000 ? 10000 : mtt; + ticks = 1 + mtt / (USEC_PER_SEC / HZ); + schedule_timeout_uninterruptible(ticks); +} + +static void __devinit bfin_sir_init_ports(struct bfin_sir_port *sp, struct platform_device *pdev) +{ + int i; + struct resource *res; + + for (i = 0; i < pdev->num_resources; i++) { + res = &pdev->resource[i]; + switch (res->flags) { + case IORESOURCE_MEM: + sp->membase = (void __iomem *)res->start; + break; + case IORESOURCE_IRQ: + sp->irq = res->start; + break; + case IORESOURCE_DMA: + sp->rx_dma_channel = res->start; + sp->tx_dma_channel = res->end; + break; + default: + break; + } + } + + sp->clk = get_sclk(); +#ifdef CONFIG_SIR_BFIN_DMA + sp->tx_done = 1; + init_timer(&(sp->rx_dma_timer)); +#endif +} + +static void bfin_sir_stop_tx(struct bfin_sir_port *port) +{ +#ifdef CONFIG_SIR_BFIN_DMA + disable_dma(port->tx_dma_channel); +#endif + + while (!(SIR_UART_GET_LSR(port) & THRE)) { + cpu_relax(); + continue; + } + + SIR_UART_STOP_TX(port); +} + +static void bfin_sir_enable_tx(struct bfin_sir_port *port) +{ + SIR_UART_ENABLE_TX(port); +} + +static void bfin_sir_stop_rx(struct bfin_sir_port *port) +{ + SIR_UART_STOP_RX(port); +} + +static void bfin_sir_enable_rx(struct bfin_sir_port *port) +{ + SIR_UART_ENABLE_RX(port); +} + +static int bfin_sir_set_speed(struct bfin_sir_port *port, int speed) +{ + int ret = -EINVAL; + unsigned int quot; + unsigned short val, lsr, lcr; + static int utime; + int count = 10; + + lcr = WLS(8); + + switch (speed) { + case 9600: + case 19200: + case 38400: + case 57600: + case 115200: + + quot = (port->clk + (8 * speed)) / (16 * speed)\ + - ANOMALY_05000230; + + do { + udelay(utime); + lsr = SIR_UART_GET_LSR(port); + } while (!(lsr & TEMT) && count--); + + /* The useconds for 1 bits to transmit */ + utime = 1000000 / speed + 1; + + /* Clear UCEN bit to reset the UART state machine + * and control registers + */ + val = SIR_UART_GET_GCTL(port); + val &= ~UCEN; + SIR_UART_PUT_GCTL(port, val); + + /* Set DLAB in LCR to Access THR RBR IER */ + SIR_UART_SET_DLAB(port); + SSYNC(); + + SIR_UART_PUT_DLL(port, quot & 0xFF); + SIR_UART_PUT_DLH(port, (quot >> 8) & 0xFF); + SSYNC(); + + /* Clear DLAB in LCR */ + SIR_UART_CLEAR_DLAB(port); + SSYNC(); + + SIR_UART_PUT_LCR(port, lcr); + + val = SIR_UART_GET_GCTL(port); + val |= UCEN; + SIR_UART_PUT_GCTL(port, val); + + ret = 0; + break; + default: + printk(KERN_WARNING "bfin_sir: Invalid speed %d\n", speed); + break; + } + + val = SIR_UART_GET_GCTL(port); + /* If not add the 'RPOLC', we can't catch the receive interrupt. + * It's related with the HW layout and the IR transiver. + */ + val |= IREN | RPOLC; + SIR_UART_PUT_GCTL(port, val); + return ret; +} + +static int bfin_sir_is_receiving(struct net_device *dev) +{ + struct bfin_sir_self *self = netdev_priv(dev); + struct bfin_sir_port *port = self->sir_port; + + if (!(SIR_UART_GET_IER(port) & ERBFI)) + return 0; + return self->rx_buff.state != OUTSIDE_FRAME; +} + +#ifdef CONFIG_SIR_BFIN_PIO +static void bfin_sir_tx_chars(struct net_device *dev) +{ + unsigned int chr; + struct bfin_sir_self *self = netdev_priv(dev); + struct bfin_sir_port *port = self->sir_port; + + if (self->tx_buff.len != 0) { + chr = *(self->tx_buff.data); + SIR_UART_PUT_CHAR(port, chr); + self->tx_buff.data++; + self->tx_buff.len--; + } else { + self->stats.tx_packets++; + self->stats.tx_bytes += self->tx_buff.data - self->tx_buff.head; + if (self->newspeed) { + bfin_sir_set_speed(port, self->newspeed); + self->speed = self->newspeed; + self->newspeed = 0; + } + bfin_sir_stop_tx(port); + bfin_sir_enable_rx(port); + /* I'm hungry! */ + netif_wake_queue(dev); + } +} + +static void bfin_sir_rx_chars(struct net_device *dev) +{ + struct bfin_sir_self *self = netdev_priv(dev); + struct bfin_sir_port *port = self->sir_port; + unsigned char ch; + + SIR_UART_CLEAR_LSR(port); + ch = SIR_UART_GET_CHAR(port); + async_unwrap_char(dev, &self->stats, &self->rx_buff, ch); + dev->last_rx = jiffies; +} + +static irqreturn_t bfin_sir_rx_int(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + struct bfin_sir_self *self = netdev_priv(dev); + struct bfin_sir_port *port = self->sir_port; + + spin_lock(&self->lock); + while ((SIR_UART_GET_LSR(port) & DR)) + bfin_sir_rx_chars(dev); + spin_unlock(&self->lock); + + return IRQ_HANDLED; +} + +static irqreturn_t bfin_sir_tx_int(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + struct bfin_sir_self *self = netdev_priv(dev); + struct bfin_sir_port *port = self->sir_port; + + spin_lock(&self->lock); + if (SIR_UART_GET_LSR(port) & THRE) + bfin_sir_tx_chars(dev); + spin_unlock(&self->lock); + + return IRQ_HANDLED; +} +#endif /* CONFIG_SIR_BFIN_PIO */ + +#ifdef CONFIG_SIR_BFIN_DMA +static void bfin_sir_dma_tx_chars(struct net_device *dev) +{ + struct bfin_sir_self *self = netdev_priv(dev); + struct bfin_sir_port *port = self->sir_port; + + if (!port->tx_done) + return; + port->tx_done = 0; + + if (self->tx_buff.len == 0) { + self->stats.tx_packets++; + if (self->newspeed) { + bfin_sir_set_speed(port, self->newspeed); + self->speed = self->newspeed; + self->newspeed = 0; + } + bfin_sir_enable_rx(port); + port->tx_done = 1; + netif_wake_queue(dev); + return; + } + + blackfin_dcache_flush_range((unsigned long)(self->tx_buff.data), + (unsigned long)(self->tx_buff.data+self->tx_buff.len)); + set_dma_config(port->tx_dma_channel, + set_bfin_dma_config(DIR_READ, DMA_FLOW_STOP, + INTR_ON_BUF, DIMENSION_LINEAR, DATA_SIZE_8, + DMA_SYNC_RESTART)); + set_dma_start_addr(port->tx_dma_channel, + (unsigned long)(self->tx_buff.data)); + set_dma_x_count(port->tx_dma_channel, self->tx_buff.len); + set_dma_x_modify(port->tx_dma_channel, 1); + enable_dma(port->tx_dma_channel); +} + +static irqreturn_t bfin_sir_dma_tx_int(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + struct bfin_sir_self *self = netdev_priv(dev); + struct bfin_sir_port *port = self->sir_port; + + spin_lock(&self->lock); + if (!(get_dma_curr_irqstat(port->tx_dma_channel) & DMA_RUN)) { + clear_dma_irqstat(port->tx_dma_channel); + bfin_sir_stop_tx(port); + + self->stats.tx_packets++; + self->stats.tx_bytes += self->tx_buff.len; + self->tx_buff.len = 0; + if (self->newspeed) { + bfin_sir_set_speed(port, self->newspeed); + self->speed = self->newspeed; + self->newspeed = 0; + } + bfin_sir_enable_rx(port); + /* I'm hungry! */ + netif_wake_queue(dev); + port->tx_done = 1; + } + spin_unlock(&self->lock); + + return IRQ_HANDLED; +} + +static void bfin_sir_dma_rx_chars(struct net_device *dev) +{ + struct bfin_sir_self *self = netdev_priv(dev); + struct bfin_sir_port *port = self->sir_port; + int i; + + SIR_UART_CLEAR_LSR(port); + + for (i = port->rx_dma_buf.head; i < port->rx_dma_buf.tail; i++) + async_unwrap_char(dev, &self->stats, &self->rx_buff, port->rx_dma_buf.buf[i]); +} + +void bfin_sir_rx_dma_timeout(struct net_device *dev) +{ + struct bfin_sir_self *self = netdev_priv(dev); + struct bfin_sir_port *port = self->sir_port; + int x_pos, pos; + unsigned long flags; + + spin_lock_irqsave(&self->lock, flags); + x_pos = DMA_SIR_RX_XCNT - get_dma_curr_xcount(port->rx_dma_channel); + if (x_pos == DMA_SIR_RX_XCNT) + x_pos = 0; + + pos = port->rx_dma_nrows * DMA_SIR_RX_XCNT + x_pos; + + if (pos > port->rx_dma_buf.tail) { + port->rx_dma_buf.tail = pos; + bfin_sir_dma_rx_chars(dev); + port->rx_dma_buf.head = port->rx_dma_buf.tail; + } + spin_unlock_irqrestore(&self->lock, flags); +} + +static irqreturn_t bfin_sir_dma_rx_int(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + struct bfin_sir_self *self = netdev_priv(dev); + struct bfin_sir_port *port = self->sir_port; + unsigned short irqstat; + + spin_lock(&self->lock); + + port->rx_dma_nrows++; + port->rx_dma_buf.tail = DMA_SIR_RX_XCNT * port->rx_dma_nrows; + bfin_sir_dma_rx_chars(dev); + if (port->rx_dma_nrows >= DMA_SIR_RX_YCNT) { + port->rx_dma_nrows = 0; + port->rx_dma_buf.tail = 0; + } + port->rx_dma_buf.head = port->rx_dma_buf.tail; + + irqstat = get_dma_curr_irqstat(port->rx_dma_channel); + clear_dma_irqstat(port->rx_dma_channel); + spin_unlock(&self->lock); + + mod_timer(&port->rx_dma_timer, jiffies + DMA_SIR_RX_FLUSH_JIFS); + return IRQ_HANDLED; +} +#endif /* CONFIG_SIR_BFIN_DMA */ + +static int bfin_sir_startup(struct bfin_sir_port *port, struct net_device *dev) +{ +#ifdef CONFIG_SIR_BFIN_DMA + dma_addr_t dma_handle; +#endif /* CONFIG_SIR_BFIN_DMA */ + + if (request_dma(port->rx_dma_channel, "BFIN_UART_RX") < 0) { + dev_warn(&dev->dev, "Unable to attach SIR RX DMA channel\n"); + return -EBUSY; + } + + if (request_dma(port->tx_dma_channel, "BFIN_UART_TX") < 0) { + dev_warn(&dev->dev, "Unable to attach SIR TX DMA channel\n"); + free_dma(port->rx_dma_channel); + return -EBUSY; + } + +#ifdef CONFIG_SIR_BFIN_DMA + + set_dma_callback(port->rx_dma_channel, bfin_sir_dma_rx_int, dev); + set_dma_callback(port->tx_dma_channel, bfin_sir_dma_tx_int, dev); + + port->rx_dma_buf.buf = (unsigned char *)dma_alloc_coherent(NULL, PAGE_SIZE, &dma_handle, GFP_DMA); + port->rx_dma_buf.head = 0; + port->rx_dma_buf.tail = 0; + port->rx_dma_nrows = 0; + + set_dma_config(port->rx_dma_channel, + set_bfin_dma_config(DIR_WRITE, DMA_FLOW_AUTO, + INTR_ON_ROW, DIMENSION_2D, + DATA_SIZE_8, DMA_SYNC_RESTART)); + set_dma_x_count(port->rx_dma_channel, DMA_SIR_RX_XCNT); + set_dma_x_modify(port->rx_dma_channel, 1); + set_dma_y_count(port->rx_dma_channel, DMA_SIR_RX_YCNT); + set_dma_y_modify(port->rx_dma_channel, 1); + set_dma_start_addr(port->rx_dma_channel, (unsigned long)port->rx_dma_buf.buf); + enable_dma(port->rx_dma_channel); + + port->rx_dma_timer.data = (unsigned long)(dev); + port->rx_dma_timer.function = (void *)bfin_sir_rx_dma_timeout; + +#else + + if (request_irq(port->irq, bfin_sir_rx_int, IRQF_DISABLED, "BFIN_SIR_RX", dev)) { + dev_warn(&dev->dev, "Unable to attach SIR RX interrupt\n"); + return -EBUSY; + } + + if (request_irq(port->irq+1, bfin_sir_tx_int, IRQF_DISABLED, "BFIN_SIR_TX", dev)) { + dev_warn(&dev->dev, "Unable to attach SIR TX interrupt\n"); + free_irq(port->irq, dev); + return -EBUSY; + } +#endif + + return 0; +} + +static void bfin_sir_shutdown(struct bfin_sir_port *port, struct net_device *dev) +{ + unsigned short val; + + bfin_sir_stop_rx(port); + SIR_UART_DISABLE_INTS(port); + + val = SIR_UART_GET_GCTL(port); + val &= ~(UCEN | IREN | RPOLC); + SIR_UART_PUT_GCTL(port, val); + +#ifdef CONFIG_SIR_BFIN_DMA + disable_dma(port->tx_dma_channel); + disable_dma(port->rx_dma_channel); + del_timer(&(port->rx_dma_timer)); + dma_free_coherent(NULL, PAGE_SIZE, port->rx_dma_buf.buf, 0); +#else + free_irq(port->irq+1, dev); + free_irq(port->irq, dev); +#endif + free_dma(port->tx_dma_channel); + free_dma(port->rx_dma_channel); +} + +#ifdef CONFIG_PM +static int bfin_sir_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct bfin_sir_port *sir_port; + struct net_device *dev; + struct bfin_sir_self *self; + + sir_port = platform_get_drvdata(pdev); + if (!sir_port) + return 0; + + dev = sir_port->dev; + self = netdev_priv(dev); + if (self->open) { + flush_work(&self->work); + bfin_sir_shutdown(self->sir_port, dev); + netif_device_detach(dev); + } + + return 0; +} +static int bfin_sir_resume(struct platform_device *pdev) +{ + struct bfin_sir_port *sir_port; + struct net_device *dev; + struct bfin_sir_self *self; + struct bfin_sir_port *port; + + sir_port = platform_get_drvdata(pdev); + if (!sir_port) + return 0; + + dev = sir_port->dev; + self = netdev_priv(dev); + port = self->sir_port; + if (self->open) { + if (self->newspeed) { + self->speed = self->newspeed; + self->newspeed = 0; + } + bfin_sir_startup(port, dev); + bfin_sir_set_speed(port, 9600); + bfin_sir_enable_rx(port); + netif_device_attach(dev); + } + return 0; +} +#else +#define bfin_sir_suspend NULL +#define bfin_sir_resume NULL +#endif + +static void bfin_sir_send_work(struct work_struct *work) +{ + struct bfin_sir_self *self = container_of(work, struct bfin_sir_self, work); + struct net_device *dev = self->sir_port->dev; + struct bfin_sir_port *port = self->sir_port; + unsigned short val; + int tx_cnt = 10; + + while (bfin_sir_is_receiving(dev) && --tx_cnt) + turnaround_delay(dev->last_rx, self->mtt); + + bfin_sir_stop_rx(port); + + /* To avoid losting RX interrupt, we reset IR function before + * sending data. We also can set the speed, which will + * reset all the UART. + */ + val = SIR_UART_GET_GCTL(port); + val &= ~(IREN | RPOLC); + SIR_UART_PUT_GCTL(port, val); + SSYNC(); + val |= IREN | RPOLC; + SIR_UART_PUT_GCTL(port, val); + SSYNC(); + /* bfin_sir_set_speed(port, self->speed); */ + +#ifdef CONFIG_SIR_BFIN_DMA + bfin_sir_dma_tx_chars(dev); +#endif + bfin_sir_enable_tx(port); + dev->trans_start = jiffies; +} + +static int bfin_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct bfin_sir_self *self = netdev_priv(dev); + int speed = irda_get_next_speed(skb); + + netif_stop_queue(dev); + + self->mtt = irda_get_mtt(skb); + + if (speed != self->speed && speed != -1) + self->newspeed = speed; + + self->tx_buff.data = self->tx_buff.head; + if (skb->len == 0) + self->tx_buff.len = 0; + else + self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data, self->tx_buff.truesize); + + schedule_work(&self->work); + dev_kfree_skb(skb); + + return 0; +} + +static int bfin_sir_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd) +{ + struct if_irda_req *rq = (struct if_irda_req *)ifreq; + struct bfin_sir_self *self = netdev_priv(dev); + struct bfin_sir_port *port = self->sir_port; + int ret = 0; + + switch (cmd) { + case SIOCSBANDWIDTH: + if (capable(CAP_NET_ADMIN)) { + if (self->open) { + ret = bfin_sir_set_speed(port, rq->ifr_baudrate); + bfin_sir_enable_rx(port); + } else { + dev_warn(&dev->dev, "SIOCSBANDWIDTH: !netif_running\n"); + ret = 0; + } + } + break; + + case SIOCSMEDIABUSY: + ret = -EPERM; + if (capable(CAP_NET_ADMIN)) { + irda_device_set_media_busy(dev, TRUE); + ret = 0; + } + break; + + case SIOCGRECEIVING: + rq->ifr_receiving = bfin_sir_is_receiving(dev); + break; + + default: + ret = -EOPNOTSUPP; + break; + } + + return ret; +} + +static struct net_device_stats *bfin_sir_stats(struct net_device *dev) +{ + struct bfin_sir_self *self = netdev_priv(dev); + + return &self->stats; +} + +static int bfin_sir_open(struct net_device *dev) +{ + struct bfin_sir_self *self = netdev_priv(dev); + struct bfin_sir_port *port = self->sir_port; + int err = -ENOMEM; + + self->newspeed = 0; + self->speed = 9600; + + spin_lock_init(&self->lock); + + err = bfin_sir_startup(port, dev); + if (err) + goto err_startup; + + bfin_sir_set_speed(port, 9600); + + self->irlap = irlap_open(dev, &self->qos, DRIVER_NAME); + if (!self->irlap) + goto err_irlap; + + INIT_WORK(&self->work, bfin_sir_send_work); + + /* + * Now enable the interrupt then start the queue + */ + self->open = 1; + bfin_sir_enable_rx(port); + + netif_start_queue(dev); + + return 0; + +err_irlap: + self->open = 0; + bfin_sir_shutdown(port, dev); +err_startup: + return err; +} + +static int bfin_sir_stop(struct net_device *dev) +{ + struct bfin_sir_self *self = netdev_priv(dev); + + flush_work(&self->work); + bfin_sir_shutdown(self->sir_port, dev); + + if (self->rxskb) { + dev_kfree_skb(self->rxskb); + self->rxskb = NULL; + } + + /* Stop IrLAP */ + if (self->irlap) { + irlap_close(self->irlap); + self->irlap = NULL; + } + + netif_stop_queue(dev); + self->open = 0; + + return 0; +} + +static int bfin_sir_init_iobuf(iobuff_t *io, int size) +{ + io->head = kmalloc(size, GFP_KERNEL); + if (!io->head) + return -ENOMEM; + io->truesize = size; + io->in_frame = FALSE; + io->state = OUTSIDE_FRAME; + io->data = io->head; + return 0; +} + +static int __devinit bfin_sir_probe(struct platform_device *pdev) +{ + struct net_device *dev; + struct bfin_sir_self *self; + unsigned int baudrate_mask; + struct bfin_sir_port *sir_port; + int err; + + if (pdev->id >= 0 && pdev->id < ARRAY_SIZE(per) && \ + per[pdev->id][3] == pdev->id) { + err = peripheral_request_list(per[pdev->id], DRIVER_NAME); + if (err) + return err; + } else { + dev_err(&pdev->dev, "Invalid pdev id, please check board file\n"); + return -ENODEV; + } + + err = -ENOMEM; + sir_port = kmalloc(sizeof(*sir_port), GFP_KERNEL); + if (!sir_port) + goto err_mem_0; + + bfin_sir_init_ports(sir_port, pdev); + + dev = alloc_irdadev(sizeof(*self)); + if (!dev) + goto err_mem_1; + + self = netdev_priv(dev); + self->dev = &pdev->dev; + self->sir_port = sir_port; + sir_port->dev = dev; + + err = bfin_sir_init_iobuf(&self->rx_buff, IRDA_SKB_MAX_MTU); + if (err) + goto err_mem_2; + err = bfin_sir_init_iobuf(&self->tx_buff, IRDA_SIR_MAX_FRAME); + if (err) + goto err_mem_3; + + dev->hard_start_xmit = bfin_sir_hard_xmit; + dev->open = bfin_sir_open; + dev->stop = bfin_sir_stop; + dev->do_ioctl = bfin_sir_ioctl; + dev->get_stats = bfin_sir_stats; + dev->irq = sir_port->irq; + + irda_init_max_qos_capabilies(&self->qos); + + baudrate_mask = IR_9600; + + switch (max_rate) { + case 115200: + baudrate_mask |= IR_115200; + case 57600: + baudrate_mask |= IR_57600; + case 38400: + baudrate_mask |= IR_38400; + case 19200: + baudrate_mask |= IR_19200; + case 9600: + break; + default: + dev_warn(&pdev->dev, "Invalid maximum baud rate, using 9600\n"); + } + + self->qos.baud_rate.bits &= baudrate_mask; + + self->qos.min_turn_time.bits = 1; /* 10 ms or more */ + + irda_qos_bits_to_value(&self->qos); + + err = register_netdev(dev); + + if (err) { + kfree(self->tx_buff.head); +err_mem_3: + kfree(self->rx_buff.head); +err_mem_2: + free_netdev(dev); +err_mem_1: + kfree(sir_port); +err_mem_0: + peripheral_free_list(per[pdev->id]); + } else + platform_set_drvdata(pdev, sir_port); + + return err; +} + +static int __devexit bfin_sir_remove(struct platform_device *pdev) +{ + struct bfin_sir_port *sir_port; + struct net_device *dev = NULL; + struct bfin_sir_self *self; + + sir_port = platform_get_drvdata(pdev); + if (!sir_port) + return 0; + dev = sir_port->dev; + self = netdev_priv(dev); + unregister_netdev(dev); + kfree(self->tx_buff.head); + kfree(self->rx_buff.head); + free_netdev(dev); + kfree(sir_port); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static struct platform_driver bfin_ir_driver = { + .probe = bfin_sir_probe, + .remove = __devexit_p(bfin_sir_remove), + .suspend = bfin_sir_suspend, + .resume = bfin_sir_resume, + .driver = { + .name = DRIVER_NAME, + }, +}; + +static int __init bfin_sir_init(void) +{ + return platform_driver_register(&bfin_ir_driver); +} + +static void __exit bfin_sir_exit(void) +{ + platform_driver_unregister(&bfin_ir_driver); +} + +module_init(bfin_sir_init); +module_exit(bfin_sir_exit); + +module_param(max_rate, int, 0); +MODULE_PARM_DESC(max_rate, "Maximum baud rate (115200, 57600, 38400, 19200, 9600)"); + +MODULE_AUTHOR("Graf Yang "); +MODULE_DESCRIPTION("Blackfin IrDA driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/irda/bfin_sir.h b/drivers/net/irda/bfin_sir.h new file mode 100644 index 000000000000..dac71b1f4f9b --- /dev/null +++ b/drivers/net/irda/bfin_sir.h @@ -0,0 +1,148 @@ +/* + * Blackfin Infra-red Driver + * + * Copyright 2006-2009 Analog Devices Inc. + * + * Enter bugs at http://blackfin.uclinux.org/ + * + * Licensed under the GPL-2 or later. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#ifdef CONFIG_SIR_BFIN_DMA +struct dma_rx_buf { + char *buf; + int head; + int tail; +}; +#endif + +struct bfin_sir_port { + unsigned char __iomem *membase; + unsigned int irq; + unsigned int lsr; + unsigned long clk; + struct net_device *dev; +#ifdef CONFIG_SIR_BFIN_DMA + int tx_done; + struct dma_rx_buf rx_dma_buf; + struct timer_list rx_dma_timer; + int rx_dma_nrows; +#endif + unsigned int tx_dma_channel; + unsigned int rx_dma_channel; +}; + +struct bfin_sir_port_res { + unsigned long base_addr; + int irq; + unsigned int rx_dma_channel; + unsigned int tx_dma_channel; +}; + +struct bfin_sir_self { + struct bfin_sir_port *sir_port; + spinlock_t lock; + unsigned int open; + int speed; + int newspeed; + + struct sk_buff *txskb; + struct sk_buff *rxskb; + struct net_device_stats stats; + struct device *dev; + struct irlap_cb *irlap; + struct qos_info qos; + + iobuff_t tx_buff; + iobuff_t rx_buff; + + struct work_struct work; + int mtt; +}; + +#define DRIVER_NAME "bfin_sir" + +#define SIR_UART_GET_CHAR(port) bfin_read16((port)->membase + OFFSET_RBR) +#define SIR_UART_GET_DLL(port) bfin_read16((port)->membase + OFFSET_DLL) +#define SIR_UART_GET_DLH(port) bfin_read16((port)->membase + OFFSET_DLH) +#define SIR_UART_GET_LCR(port) bfin_read16((port)->membase + OFFSET_LCR) +#define SIR_UART_GET_GCTL(port) bfin_read16((port)->membase + OFFSET_GCTL) + +#define SIR_UART_PUT_CHAR(port, v) bfin_write16(((port)->membase + OFFSET_THR), v) +#define SIR_UART_PUT_DLL(port, v) bfin_write16(((port)->membase + OFFSET_DLL), v) +#define SIR_UART_PUT_DLH(port, v) bfin_write16(((port)->membase + OFFSET_DLH), v) +#define SIR_UART_PUT_LCR(port, v) bfin_write16(((port)->membase + OFFSET_LCR), v) +#define SIR_UART_PUT_GCTL(port, v) bfin_write16(((port)->membase + OFFSET_GCTL), v) + +#ifdef CONFIG_BF54x +#define SIR_UART_GET_LSR(port) bfin_read16((port)->membase + OFFSET_LSR) +#define SIR_UART_GET_IER(port) bfin_read16((port)->membase + OFFSET_IER_SET) +#define SIR_UART_SET_IER(port, v) bfin_write16(((port)->membase + OFFSET_IER_SET), v) +#define SIR_UART_CLEAR_IER(port, v) bfin_write16(((port)->membase + OFFSET_IER_CLEAR), v) +#define SIR_UART_PUT_LSR(port, v) bfin_write16(((port)->membase + OFFSET_LSR), v) +#define SIR_UART_CLEAR_LSR(port) bfin_write16(((port)->membase + OFFSET_LSR), -1) + +#define SIR_UART_SET_DLAB(port) +#define SIR_UART_CLEAR_DLAB(port) + +#define SIR_UART_ENABLE_INTS(port, v) SIR_UART_SET_IER(port, v) +#define SIR_UART_DISABLE_INTS(port) SIR_UART_CLEAR_IER(port, 0xF) +#define SIR_UART_STOP_TX(port) do { SIR_UART_PUT_LSR(port, TFI); SIR_UART_CLEAR_IER(port, ETBEI); } while (0) +#define SIR_UART_ENABLE_TX(port) do { SIR_UART_SET_IER(port, ETBEI); } while (0) +#define SIR_UART_STOP_RX(port) do { SIR_UART_CLEAR_IER(port, ERBFI); } while (0) +#define SIR_UART_ENABLE_RX(port) do { SIR_UART_SET_IER(port, ERBFI); } while (0) +#else + +#define SIR_UART_GET_IIR(port) bfin_read16((port)->membase + OFFSET_IIR) +#define SIR_UART_GET_IER(port) bfin_read16((port)->membase + OFFSET_IER) +#define SIR_UART_PUT_IER(port, v) bfin_write16(((port)->membase + OFFSET_IER), v) + +#define SIR_UART_SET_DLAB(port) do { SIR_UART_PUT_LCR(port, SIR_UART_GET_LCR(port) | DLAB); } while (0) +#define SIR_UART_CLEAR_DLAB(port) do { SIR_UART_PUT_LCR(port, SIR_UART_GET_LCR(port) & ~DLAB); } while (0) + +#define SIR_UART_ENABLE_INTS(port, v) SIR_UART_PUT_IER(port, v) +#define SIR_UART_DISABLE_INTS(port) SIR_UART_PUT_IER(port, 0) +#define SIR_UART_STOP_TX(port) do { SIR_UART_PUT_IER(port, SIR_UART_GET_IER(port) & ~ETBEI); } while (0) +#define SIR_UART_ENABLE_TX(port) do { SIR_UART_PUT_IER(port, SIR_UART_GET_IER(port) | ETBEI); } while (0) +#define SIR_UART_STOP_RX(port) do { SIR_UART_PUT_IER(port, SIR_UART_GET_IER(port) & ~ERBFI); } while (0) +#define SIR_UART_ENABLE_RX(port) do { SIR_UART_PUT_IER(port, SIR_UART_GET_IER(port) | ERBFI); } while (0) + +static inline unsigned int SIR_UART_GET_LSR(struct bfin_sir_port *port) +{ + unsigned int lsr = bfin_read16(port->membase + OFFSET_LSR); + port->lsr |= (lsr & (BI|FE|PE|OE)); + return lsr | port->lsr; +} + +static inline void SIR_UART_CLEAR_LSR(struct bfin_sir_port *port) +{ + port->lsr = 0; + bfin_read16(port->membase + OFFSET_LSR); +} +#endif + +static const unsigned short per[][4] = { + /* rx pin tx pin NULL uart_number */ + {P_UART0_RX, P_UART0_TX, 0, 0}, + {P_UART1_RX, P_UART1_TX, 0, 1}, + {P_UART2_RX, P_UART2_TX, 0, 2}, + {P_UART3_RX, P_UART3_TX, 0, 3}, +}; diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c index 6b6548b9fda0..9a0346e751ac 100644 --- a/drivers/net/irda/donauboe.c +++ b/drivers/net/irda/donauboe.c @@ -994,11 +994,11 @@ toshoboe_hard_xmit (struct sk_buff *skb, struct net_device *dev) /* change speed pending, wait for its execution */ if (self->new_speed) - return -EBUSY; + return NETDEV_TX_BUSY; /* device stopped (apm) wait for restart */ if (self->stopped) - return -EBUSY; + return NETDEV_TX_BUSY; toshoboe_checkstuck (self); @@ -1049,7 +1049,7 @@ toshoboe_hard_xmit (struct sk_buff *skb, struct net_device *dev) if (self->txpending) { spin_unlock_irqrestore(&self->spinlock, flags); - return -EBUSY; + return NETDEV_TX_BUSY; } /* If in SIR mode we need to generate a string of XBOFs */ @@ -1105,7 +1105,7 @@ dumpbufs(skb->data,skb->len,'>'); ,skb->len, self->ring->tx[self->txs].control, self->txpending); toshoboe_start_DMA(self, OBOE_CONFIG0H_ENTX); spin_unlock_irqrestore(&self->spinlock, flags); - return -EBUSY; + return NETDEV_TX_BUSY; } if (INB (OBOE_ENABLEH) & OBOE_ENABLEH_SIRON) diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c index 006ba23110db..0c0831c03f64 100644 --- a/drivers/net/irda/irda-usb.c +++ b/drivers/net/irda/irda-usb.c @@ -389,7 +389,6 @@ static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev) s32 speed; s16 xbofs; int res, mtt; - int err = 1; /* Failed */ IRDA_DEBUG(4, "%s() on %s\n", __func__, netdev->name); @@ -430,7 +429,6 @@ static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev) irda_usb_change_speed_xbofs(self); netdev->trans_start = jiffies; /* Will netif_wake_queue() in callback */ - err = 0; /* No error */ goto drop; } } @@ -542,7 +540,7 @@ drop: /* Drop silently the skb and exit */ dev_kfree_skb(skb); spin_unlock_irqrestore(&self->lock, flags); - return err; /* Usually 1 */ + return NETDEV_TX_OK; } /*------------------------------------------------------------------*/ @@ -1859,6 +1857,42 @@ static void irda_usb_disconnect(struct usb_interface *intf) IRDA_DEBUG(0, "%s(), USB IrDA Disconnected\n", __func__); } +#ifdef CONFIG_PM +/* USB suspend, so power off the transmitter/receiver */ +static int irda_usb_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct irda_usb_cb *self = usb_get_intfdata(intf); + int i; + + netif_device_detach(self->netdev); + + if (self->tx_urb != NULL) + usb_kill_urb(self->tx_urb); + if (self->speed_urb != NULL) + usb_kill_urb(self->speed_urb); + for (i = 0; i < self->max_rx_urb; i++) { + if (self->rx_urb[i] != NULL) + usb_kill_urb(self->rx_urb[i]); + } + return 0; +} + +/* Coming out of suspend, so reset hardware */ +static int irda_usb_resume(struct usb_interface *intf) +{ + struct irda_usb_cb *self = usb_get_intfdata(intf); + int i; + + for (i = 0; i < self->max_rx_urb; i++) { + if (self->rx_urb[i] != NULL) + usb_submit_urb(self->rx_urb[i], GFP_KERNEL); + } + + netif_device_attach(self->netdev); + return 0; +} +#endif + /*------------------------------------------------------------------*/ /* * USB device callbacks @@ -1868,6 +1902,10 @@ static struct usb_driver irda_driver = { .probe = irda_usb_probe, .disconnect = irda_usb_disconnect, .id_table = dongles, +#ifdef CONFIG_PM + .suspend = irda_usb_suspend, + .resume = irda_usb_resume, +#endif }; /************************* MODULE CALLBACKS *************************/ diff --git a/drivers/net/irda/kingsun-sir.c b/drivers/net/irda/kingsun-sir.c index 9d813bc4502e..c3e4e2c435ba 100644 --- a/drivers/net/irda/kingsun-sir.c +++ b/drivers/net/irda/kingsun-sir.c @@ -156,9 +156,6 @@ static int kingsun_hard_xmit(struct sk_buff *skb, struct net_device *netdev) int wraplen; int ret = 0; - if (skb == NULL || netdev == NULL) - return -EINVAL; - netif_stop_queue(netdev); /* the IRDA wrapping routines don't deal with non linear skb */ @@ -197,7 +194,7 @@ static int kingsun_hard_xmit(struct sk_buff *skb, struct net_device *netdev) dev_kfree_skb(skb); spin_unlock(&kingsun->lock); - return ret; + return NETDEV_TX_OK; } /* Receive callback function */ diff --git a/drivers/net/irda/ks959-sir.c b/drivers/net/irda/ks959-sir.c index b6ffe9715b61..d73b8b64fcb9 100644 --- a/drivers/net/irda/ks959-sir.c +++ b/drivers/net/irda/ks959-sir.c @@ -391,9 +391,6 @@ static int ks959_hard_xmit(struct sk_buff *skb, struct net_device *netdev) unsigned int wraplen; int ret = 0; - if (skb == NULL || netdev == NULL) - return -EINVAL; - netif_stop_queue(netdev); /* the IRDA wrapping routines don't deal with non linear skb */ @@ -428,7 +425,7 @@ static int ks959_hard_xmit(struct sk_buff *skb, struct net_device *netdev) dev_kfree_skb(skb); spin_unlock(&kingsun->lock); - return ret; + return NETDEV_TX_OK; } /* Receive callback function */ diff --git a/drivers/net/irda/ksdazzle-sir.c b/drivers/net/irda/ksdazzle-sir.c index 64df27f2bfd4..1ef45ec74422 100644 --- a/drivers/net/irda/ksdazzle-sir.c +++ b/drivers/net/irda/ksdazzle-sir.c @@ -304,9 +304,6 @@ static int ksdazzle_hard_xmit(struct sk_buff *skb, struct net_device *netdev) unsigned int wraplen; int ret = 0; - if (skb == NULL || netdev == NULL) - return -EINVAL; - netif_stop_queue(netdev); /* the IRDA wrapping routines don't deal with non linear skb */ @@ -341,7 +338,7 @@ static int ksdazzle_hard_xmit(struct sk_buff *skb, struct net_device *netdev) dev_kfree_skb(skb); spin_unlock(&kingsun->lock); - return ret; + return NETDEV_TX_OK; } /* Receive callback function */ diff --git a/drivers/net/irda/mcs7780.c b/drivers/net/irda/mcs7780.c index fac504d0cfd8..f4df1001983c 100644 --- a/drivers/net/irda/mcs7780.c +++ b/drivers/net/irda/mcs7780.c @@ -824,10 +824,6 @@ static int mcs_hard_xmit(struct sk_buff *skb, struct net_device *ndev) int wraplen; int ret = 0; - - if (skb == NULL || ndev == NULL) - return -EINVAL; - netif_stop_queue(ndev); mcs = netdev_priv(ndev); @@ -870,7 +866,7 @@ static int mcs_hard_xmit(struct sk_buff *skb, struct net_device *ndev) dev_kfree_skb(skb); spin_unlock_irqrestore(&mcs->lock, flags); - return ret; + return NETDEV_TX_OK; } static const struct net_device_ops mcs_netdev_ops = { diff --git a/drivers/net/irda/pxaficp_ir.c b/drivers/net/irda/pxaficp_ir.c index e775338b525f..3376a4f39e0a 100644 --- a/drivers/net/irda/pxaficp_ir.c +++ b/drivers/net/irda/pxaficp_ir.c @@ -14,6 +14,7 @@ */ #include #include +#include #include #include @@ -797,6 +798,16 @@ static int pxa_irda_init_iobuf(iobuff_t *io, int size) return io->head ? 0 : -ENOMEM; } +static const struct net_device_ops pxa_irda_netdev_ops = { + .ndo_open = pxa_irda_start, + .ndo_stop = pxa_irda_stop, + .ndo_start_xmit = pxa_irda_hard_xmit, + .ndo_do_ioctl = pxa_irda_ioctl, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, +}; + static int pxa_irda_probe(struct platform_device *pdev) { struct net_device *dev; @@ -845,10 +856,7 @@ static int pxa_irda_probe(struct platform_device *pdev) if (err) goto err_startup; - dev->hard_start_xmit = pxa_irda_hard_xmit; - dev->open = pxa_irda_start; - dev->stop = pxa_irda_stop; - dev->do_ioctl = pxa_irda_ioctl; + dev->netdev_ops = &pxa_irda_netdev_ops; irda_init_max_qos_capabilies(&si->qos); diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c index 7a2b003954ca..2aeb2e6aec1b 100644 --- a/drivers/net/irda/sa1100_ir.c +++ b/drivers/net/irda/sa1100_ir.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -875,6 +876,16 @@ static int sa1100_irda_init_iobuf(iobuff_t *io, int size) return io->head ? 0 : -ENOMEM; } +static const struct net_device_ops sa1100_irda_netdev_ops = { + .ndo_open = sa1100_irda_start, + .ndo_stop = sa1100_irda_stop, + .ndo_start_xmit = sa1100_irda_hard_xmit, + .ndo_do_ioctl = sa1100_irda_ioctl, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, +}; + static int sa1100_irda_probe(struct platform_device *pdev) { struct net_device *dev; @@ -913,11 +924,8 @@ static int sa1100_irda_probe(struct platform_device *pdev) if (err) goto err_mem_5; - dev->hard_start_xmit = sa1100_irda_hard_xmit; - dev->open = sa1100_irda_start; - dev->stop = sa1100_irda_stop; - dev->do_ioctl = sa1100_irda_ioctl; - dev->irq = IRQ_Ser2ICP; + dev->netdev_ops = &sa1100_irda_netdev_ops; + dev->irq = IRQ_Ser2ICP; irda_init_max_qos_capabilies(&si->qos); diff --git a/drivers/net/irda/sir_dev.c b/drivers/net/irda/sir_dev.c index d940809762ec..fd0796c3db3c 100644 --- a/drivers/net/irda/sir_dev.c +++ b/drivers/net/irda/sir_dev.c @@ -607,7 +607,7 @@ static int sirdev_hard_xmit(struct sk_buff *skb, struct net_device *ndev) * stopped so the network layer will retry after the * fsm completes and wakes the queue. */ - return 1; + return NETDEV_TX_BUSY; } else if (unlikely(err)) { /* other fatal error - forget the speed change and diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c index 59d79807b4d5..d0797adb5f8e 100644 --- a/drivers/net/irda/smsc-ircc2.c +++ b/drivers/net/irda/smsc-ircc2.c @@ -2124,7 +2124,7 @@ static void smsc_ircc_sir_wait_hw_transmitter_finish(struct smsc_ircc_cb *self) while (count-- > 0 && !(inb(iobase + UART_LSR) & UART_LSR_TEMT)) udelay(1); - if (count == 0) + if (count < 0) IRDA_DEBUG(0, "%s(): stuck transmitter\n", __func__); } diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c index cb793c2bade2..e44215cb1882 100644 --- a/drivers/net/iseries_veth.c +++ b/drivers/net/iseries_veth.c @@ -1021,6 +1021,16 @@ static const struct ethtool_ops ops = { .get_link = veth_get_link, }; +static const struct net_device_ops veth_netdev_ops = { + .ndo_open = veth_open, + .ndo_stop = veth_close, + .ndo_start_xmit = veth_start_xmit, + .ndo_change_mtu = veth_change_mtu, + .ndo_set_multicast_list = veth_set_multicast_list, + .ndo_set_mac_address = NULL, + .ndo_validate_addr = eth_validate_addr, +}; + static struct net_device *veth_probe_one(int vlan, struct vio_dev *vio_dev) { @@ -1067,12 +1077,7 @@ static struct net_device *veth_probe_one(int vlan, memcpy(&port->mac_addr, mac_addr, ETH_ALEN); - dev->open = veth_open; - dev->hard_start_xmit = veth_start_xmit; - dev->stop = veth_close; - dev->change_mtu = veth_change_mtu; - dev->set_mac_address = NULL; - dev->set_multicast_list = veth_set_multicast_list; + dev->netdev_ops = &veth_netdev_ops; SET_ETHTOOL_OPS(dev, &ops); SET_NETDEV_DEV(dev, vdev); diff --git a/drivers/net/ixgb/ixgb_hw.c b/drivers/net/ixgb/ixgb_hw.c index 11dcda0f453e..ff67a84e6802 100644 --- a/drivers/net/ixgb/ixgb_hw.c +++ b/drivers/net/ixgb/ixgb_hw.c @@ -192,7 +192,7 @@ ixgb_identify_xpak_vendor(struct ixgb_hw *hw) vendor_name[i] = ixgb_read_phy_reg(hw, MDIO_PMA_PMD_XPAK_VENDOR_NAME + i, IXGB_PHY_ADDRESS, - MDIO_PMA_PMD_DID); + MDIO_MMD_PMAPMD); } /* Determine the actual vendor */ @@ -1225,15 +1225,15 @@ ixgb_optics_reset(struct ixgb_hw *hw) u16 mdio_reg; ixgb_write_phy_reg(hw, - MDIO_PMA_PMD_CR1, - IXGB_PHY_ADDRESS, - MDIO_PMA_PMD_DID, - MDIO_PMA_PMD_CR1_RESET); + MDIO_CTRL1, + IXGB_PHY_ADDRESS, + MDIO_MMD_PMAPMD, + MDIO_CTRL1_RESET); - mdio_reg = ixgb_read_phy_reg( hw, - MDIO_PMA_PMD_CR1, - IXGB_PHY_ADDRESS, - MDIO_PMA_PMD_DID); + mdio_reg = ixgb_read_phy_reg(hw, + MDIO_CTRL1, + IXGB_PHY_ADDRESS, + MDIO_MMD_PMAPMD); } return; diff --git a/drivers/net/ixgb/ixgb_hw.h b/drivers/net/ixgb/ixgb_hw.h index 831fe0c58b2b..af6ca3aab5ad 100644 --- a/drivers/net/ixgb/ixgb_hw.h +++ b/drivers/net/ixgb/ixgb_hw.h @@ -29,6 +29,8 @@ #ifndef _IXGB_HW_H_ #define _IXGB_HW_H_ +#include + #include "ixgb_osdep.h" /* Enums */ @@ -507,18 +509,6 @@ typedef enum { /* Definitions for the optics devices on the MDIO bus. */ #define IXGB_PHY_ADDRESS 0x0 /* Single PHY, multiple "Devices" */ -/* Standard five-bit Device IDs. See IEEE 802.3ae, clause 45 */ -#define MDIO_PMA_PMD_DID 0x01 -#define MDIO_WIS_DID 0x02 -#define MDIO_PCS_DID 0x03 -#define MDIO_XGXS_DID 0x04 - -/* Standard PMA/PMD registers and bit definitions. */ -/* Note: This is a very limited set of definitions, */ -/* only implemented features are defined. */ -#define MDIO_PMA_PMD_CR1 0x0000 -#define MDIO_PMA_PMD_CR1_RESET 0x8000 - #define MDIO_PMA_PMD_XPAK_VENDOR_NAME 0x803A /* XPAK/XENPAK devices only */ /* Vendor-specific MDIO registers */ diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index 4a0826b8f6f2..9c897cf86b9f 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -266,6 +266,8 @@ ixgb_up(struct ixgb_adapter *adapter) napi_enable(&adapter->napi); ixgb_irq_enable(adapter); + netif_wake_queue(netdev); + mod_timer(&adapter->watchdog_timer, jiffies); return 0; @@ -471,10 +473,8 @@ ixgb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (err) goto err_register; - /* we're going to reset, so assume we have no link for now */ - + /* carrier off reporting is important to ethtool even BEFORE open */ netif_carrier_off(netdev); - netif_stop_queue(netdev); DPRINTK(PROBE, INFO, "Intel(R) PRO/10GbE Network Connection\n"); ixgb_check_options(adapter); @@ -592,6 +592,8 @@ ixgb_open(struct net_device *netdev) if (err) goto err_setup_tx; + netif_carrier_off(netdev); + /* allocate receive descriptors */ err = ixgb_setup_rx_resources(adapter); @@ -602,6 +604,8 @@ ixgb_open(struct net_device *netdev) if (err) goto err_up; + netif_start_queue(netdev); + return 0; err_up: @@ -1116,7 +1120,6 @@ ixgb_watchdog(unsigned long data) adapter->link_speed = 10000; adapter->link_duplex = FULL_DUPLEX; netif_carrier_on(netdev); - netif_wake_queue(netdev); } } else { if (netif_carrier_ok(netdev)) { @@ -1125,8 +1128,6 @@ ixgb_watchdog(unsigned long data) printk(KERN_INFO "ixgb: %s NIC Link is Down\n", netdev->name); netif_carrier_off(netdev); - netif_stop_queue(netdev); - } } @@ -1139,6 +1140,8 @@ ixgb_watchdog(unsigned long data) * to get done, so reset controller to flush Tx. * (Do the reset outside of interrupt context). */ schedule_work(&adapter->tx_timeout_task); + /* return immediately since reset is imminent */ + return; } } @@ -1297,7 +1300,7 @@ ixgb_tx_map(struct ixgb_adapter *adapter, struct sk_buff *skb, buffer_info->length = size; WARN_ON(buffer_info->dma != 0); buffer_info->time_stamp = jiffies; - buffer_info->dma = map[0] + offset; + buffer_info->dma = skb_shinfo(skb)->dma_head + offset; pci_map_single(adapter->pdev, skb->data + offset, size, @@ -1337,7 +1340,7 @@ ixgb_tx_map(struct ixgb_adapter *adapter, struct sk_buff *skb, buffer_info->length = size; buffer_info->time_stamp = jiffies; - buffer_info->dma = map[f + 1] + offset; + buffer_info->dma = map[f] + offset; buffer_info->next_to_watch = 0; len -= size; @@ -1485,7 +1488,6 @@ ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev) if (count) { ixgb_tx_queue(adapter, count, vlan_id, tx_flags); - netdev->trans_start = jiffies; /* Make sure there is space in the ring for the next send. */ ixgb_maybe_stop_tx(netdev, &adapter->tx_ring, DESC_NEEDED); diff --git a/drivers/net/ixgb/ixgb_osdep.h b/drivers/net/ixgb/ixgb_osdep.h index d92e72bd627a..371a6be4d965 100644 --- a/drivers/net/ixgb/ixgb_osdep.h +++ b/drivers/net/ixgb/ixgb_osdep.h @@ -40,7 +40,7 @@ #include #undef ASSERT -#define ASSERT(x) if (!(x)) BUG() +#define ASSERT(x) BUG_ON(!(x)) #define MSGOUT(S, A, B) printk(KERN_DEBUG S "\n", A, B) #ifdef DBG diff --git a/drivers/net/ixgbe/Makefile b/drivers/net/ixgbe/Makefile index b3f8208ec7be..21b41f42b61c 100644 --- a/drivers/net/ixgbe/Makefile +++ b/drivers/net/ixgbe/Makefile @@ -37,3 +37,5 @@ ixgbe-objs := ixgbe_main.o ixgbe_common.o ixgbe_ethtool.o \ ixgbe-$(CONFIG_IXGBE_DCB) += ixgbe_dcb.o ixgbe_dcb_82598.o \ ixgbe_dcb_82599.o ixgbe_dcb_nl.o + +ixgbe-$(CONFIG_FCOE:m=y) += ixgbe_fcoe.o diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index c26433d14605..cd22323cfd22 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -36,6 +36,10 @@ #include "ixgbe_type.h" #include "ixgbe_common.h" #include "ixgbe_dcb.h" +#if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) +#define IXGBE_FCOE +#include "ixgbe_fcoe.h" +#endif /* CONFIG_FCOE or CONFIG_FCOE_MODULE */ #ifdef CONFIG_IXGBE_DCA #include #endif @@ -71,6 +75,8 @@ #define IXGBE_RXBUFFER_128 128 /* Used for packet split */ #define IXGBE_RXBUFFER_256 256 /* Used for packet split */ #define IXGBE_RXBUFFER_2048 2048 +#define IXGBE_RXBUFFER_4096 4096 +#define IXGBE_RXBUFFER_8192 8192 #define IXGBE_MAX_RXBUFFER 16384 /* largest size for a single descriptor */ #define IXGBE_RX_HDR_SIZE IXGBE_RXBUFFER_256 @@ -84,6 +90,8 @@ #define IXGBE_TX_FLAGS_VLAN (u32)(1 << 1) #define IXGBE_TX_FLAGS_TSO (u32)(1 << 2) #define IXGBE_TX_FLAGS_IPV4 (u32)(1 << 3) +#define IXGBE_TX_FLAGS_FCOE (u32)(1 << 4) +#define IXGBE_TX_FLAGS_FSO (u32)(1 << 5) #define IXGBE_TX_FLAGS_VLAN_MASK 0xffff0000 #define IXGBE_TX_FLAGS_VLAN_PRIO_MASK 0x0000e000 #define IXGBE_TX_FLAGS_VLAN_SHIFT 16 @@ -113,17 +121,18 @@ struct ixgbe_queue_stats { struct ixgbe_ring { void *desc; /* descriptor ring memory */ - dma_addr_t dma; /* phys. address of descriptor ring */ - unsigned int size; /* length in bytes */ - unsigned int count; /* amount of descriptors */ - unsigned int next_to_use; - unsigned int next_to_clean; - - int queue_index; /* needed for multiqueue queue management */ union { struct ixgbe_tx_buffer *tx_buffer_info; struct ixgbe_rx_buffer *rx_buffer_info; }; + u8 atr_sample_rate; + u8 atr_count; + u16 count; /* amount of descriptors */ + u16 rx_buf_len; + u16 next_to_use; + u16 next_to_clean; + + u8 queue_index; /* needed for multiqueue queue management */ u16 head; u16 tail; @@ -131,22 +140,24 @@ struct ixgbe_ring { unsigned int total_bytes; unsigned int total_packets; - u16 reg_idx; /* holds the special value that gets the hardware register - * offset associated with this ring, which is different - * for DCB and RSS modes */ - #ifdef CONFIG_IXGBE_DCA /* cpu for tx queue */ int cpu; #endif + + u16 work_limit; /* max work per interrupt */ + u16 reg_idx; /* holds the special value that gets + * the hardware register offset + * associated with this ring, which is + * different for DCB and RSS modes + */ + struct ixgbe_queue_stats stats; - u64 v_idx; /* maps directly to the index for this ring in the hardware - * vector array, can also be used for finding the bit in EICR - * and friends that represents the vector for this ring */ + unsigned long reinit_state; + u64 rsc_count; /* stat for coalesced packets */ - - u16 work_limit; /* max work per interrupt */ - u16 rx_buf_len; + unsigned int size; /* length in bytes */ + dma_addr_t dma; /* phys. address of descriptor ring */ }; enum ixgbe_ring_f_enum { @@ -154,6 +165,10 @@ enum ixgbe_ring_f_enum { RING_F_DCB, RING_F_VMDQ, RING_F_RSS, + RING_F_FDIR, +#ifdef IXGBE_FCOE + RING_F_FCOE, +#endif /* IXGBE_FCOE */ RING_F_ARRAY_SIZE /* must be last in enum set */ }; @@ -161,6 +176,10 @@ enum ixgbe_ring_f_enum { #define IXGBE_MAX_DCB_INDICES 8 #define IXGBE_MAX_RSS_INDICES 16 #define IXGBE_MAX_VMDQ_INDICES 16 +#define IXGBE_MAX_FDIR_INDICES 64 +#ifdef IXGBE_FCOE +#define IXGBE_MAX_FCOE_INDICES 8 +#endif /* IXGBE_FCOE */ struct ixgbe_ring_feature { int indices; int mask; @@ -178,6 +197,9 @@ struct ixgbe_ring_feature { */ struct ixgbe_q_vector { struct ixgbe_adapter *adapter; + unsigned int v_idx; /* index of q_vector within array, also used for + * finding the bit in EICR and friends that + * represents the vector for this ring */ struct napi_struct napi; DECLARE_BITMAP(rxr_idx, MAX_RX_QUEUES); /* Rx ring indices */ DECLARE_BITMAP(txr_idx, MAX_TX_QUEUES); /* Tx ring indices */ @@ -207,7 +229,15 @@ struct ixgbe_q_vector { #define IXGBE_TX_CTXTDESC_ADV(R, i) \ (&(((struct ixgbe_adv_tx_context_desc *)((R).desc))[i])) +#define IXGBE_GET_DESC(R, i, type) (&(((struct type *)((R).desc))[i])) +#define IXGBE_TX_DESC(R, i) IXGBE_GET_DESC(R, i, ixgbe_legacy_tx_desc) +#define IXGBE_RX_DESC(R, i) IXGBE_GET_DESC(R, i, ixgbe_legacy_rx_desc) + #define IXGBE_MAX_JUMBO_FRAME_SIZE 16128 +#ifdef IXGBE_FCOE +/* Use 3K as the baby jumbo frame size for FCoE */ +#define IXGBE_FCOE_JUMBO_FRAME_SIZE 3072 +#endif /* IXGBE_FCOE */ #define OTHER_VECTOR 1 #define NON_Q_VECTORS (OTHER_VECTOR) @@ -229,11 +259,12 @@ struct ixgbe_adapter { struct vlan_group *vlgrp; u16 bd_number; struct work_struct reset_task; - struct ixgbe_q_vector q_vector[MAX_MSIX_Q_VECTORS]; + struct ixgbe_q_vector *q_vector[MAX_MSIX_Q_VECTORS]; char name[MAX_MSIX_COUNT][IFNAMSIZ + 9]; struct ixgbe_dcb_config dcb_cfg; struct ixgbe_dcb_config temp_dcb_cfg; u8 dcb_set_bitmap; + enum ixgbe_fc_mode last_lfc_mode; /* Interrupt Throttle Rate */ u32 itr_setting; @@ -294,7 +325,13 @@ struct ixgbe_adapter { #define IXGBE_FLAG_IN_WATCHDOG_TASK (u32)(1 << 23) #define IXGBE_FLAG_IN_SFP_LINK_TASK (u32)(1 << 24) #define IXGBE_FLAG_IN_SFP_MOD_TASK (u32)(1 << 25) +#define IXGBE_FLAG_FDIR_HASH_CAPABLE (u32)(1 << 26) +#define IXGBE_FLAG_FDIR_PERFECT_CAPABLE (u32)(1 << 27) +#define IXGBE_FLAG_FCOE_ENABLED (u32)(1 << 29) + u32 flags2; +#define IXGBE_FLAG2_RSC_CAPABLE (u32)(1) +#define IXGBE_FLAG2_RSC_ENABLED (u32)(1 << 1) /* default to trying for four seconds */ #define IXGBE_TRY_LINK_TIMEOUT (4 * HZ) @@ -303,6 +340,10 @@ struct ixgbe_adapter { struct pci_dev *pdev; struct net_device_stats net_stats; + u32 test_icr; + struct ixgbe_ring test_tx_ring; + struct ixgbe_ring test_rx_ring; + /* structs defined in ixgbe_hw.h */ struct ixgbe_hw hw; u16 msg_enable; @@ -325,6 +366,14 @@ struct ixgbe_adapter { struct timer_list sfp_timer; struct work_struct multispeed_fiber_task; struct work_struct sfp_config_module_task; + u32 fdir_pballoc; + u32 atr_sample_rate; + spinlock_t fdir_perfect_lock; + struct work_struct fdir_reinit_task; +#ifdef IXGBE_FCOE + struct ixgbe_fcoe fcoe; +#endif /* IXGBE_FCOE */ + u64 rsc_count; u32 wol; u16 eeprom_version; }; @@ -333,6 +382,7 @@ enum ixbge_state_t { __IXGBE_TESTING, __IXGBE_RESETTING, __IXGBE_DOWN, + __IXGBE_FDIR_INIT_DONE, __IXGBE_SFP_MODULE_NOT_FOUND }; @@ -363,10 +413,77 @@ extern int ixgbe_setup_tx_resources(struct ixgbe_adapter *, struct ixgbe_ring *) extern void ixgbe_free_rx_resources(struct ixgbe_adapter *, struct ixgbe_ring *); extern void ixgbe_free_tx_resources(struct ixgbe_adapter *, struct ixgbe_ring *); extern void ixgbe_update_stats(struct ixgbe_adapter *adapter); -extern void ixgbe_reset_interrupt_capability(struct ixgbe_adapter *adapter); extern int ixgbe_init_interrupt_scheme(struct ixgbe_adapter *adapter); -void ixgbe_napi_add_all(struct ixgbe_adapter *adapter); -void ixgbe_napi_del_all(struct ixgbe_adapter *adapter); -extern void ixgbe_write_eitr(struct ixgbe_adapter *, int, u32); +extern void ixgbe_clear_interrupt_scheme(struct ixgbe_adapter *adapter); +extern void ixgbe_write_eitr(struct ixgbe_q_vector *); +extern int ethtool_ioctl(struct ifreq *ifr); +extern s32 ixgbe_reinit_fdir_tables_82599(struct ixgbe_hw *hw); +extern s32 ixgbe_init_fdir_signature_82599(struct ixgbe_hw *hw, u32 pballoc); +extern s32 ixgbe_init_fdir_perfect_82599(struct ixgbe_hw *hw, u32 pballoc); +extern s32 ixgbe_fdir_add_signature_filter_82599(struct ixgbe_hw *hw, + struct ixgbe_atr_input *input, + u8 queue); +extern s32 ixgbe_fdir_add_perfect_filter_82599(struct ixgbe_hw *hw, + struct ixgbe_atr_input *input, + u16 soft_id, + u8 queue); +extern u16 ixgbe_atr_compute_hash_82599(struct ixgbe_atr_input *input, u32 key); +extern s32 ixgbe_atr_set_vlan_id_82599(struct ixgbe_atr_input *input, + u16 vlan_id); +extern s32 ixgbe_atr_set_src_ipv4_82599(struct ixgbe_atr_input *input, + u32 src_addr); +extern s32 ixgbe_atr_set_dst_ipv4_82599(struct ixgbe_atr_input *input, + u32 dst_addr); +extern s32 ixgbe_atr_set_src_ipv6_82599(struct ixgbe_atr_input *input, + u32 src_addr_1, u32 src_addr_2, + u32 src_addr_3, u32 src_addr_4); +extern s32 ixgbe_atr_set_dst_ipv6_82599(struct ixgbe_atr_input *input, + u32 dst_addr_1, u32 dst_addr_2, + u32 dst_addr_3, u32 dst_addr_4); +extern s32 ixgbe_atr_set_src_port_82599(struct ixgbe_atr_input *input, + u16 src_port); +extern s32 ixgbe_atr_set_dst_port_82599(struct ixgbe_atr_input *input, + u16 dst_port); +extern s32 ixgbe_atr_set_flex_byte_82599(struct ixgbe_atr_input *input, + u16 flex_byte); +extern s32 ixgbe_atr_set_vm_pool_82599(struct ixgbe_atr_input *input, + u8 vm_pool); +extern s32 ixgbe_atr_set_l4type_82599(struct ixgbe_atr_input *input, + u8 l4type); +extern s32 ixgbe_atr_get_vlan_id_82599(struct ixgbe_atr_input *input, + u16 *vlan_id); +extern s32 ixgbe_atr_get_src_ipv4_82599(struct ixgbe_atr_input *input, + u32 *src_addr); +extern s32 ixgbe_atr_get_dst_ipv4_82599(struct ixgbe_atr_input *input, + u32 *dst_addr); +extern s32 ixgbe_atr_get_src_ipv6_82599(struct ixgbe_atr_input *input, + u32 *src_addr_1, u32 *src_addr_2, + u32 *src_addr_3, u32 *src_addr_4); +extern s32 ixgbe_atr_get_dst_ipv6_82599(struct ixgbe_atr_input *input, + u32 *dst_addr_1, u32 *dst_addr_2, + u32 *dst_addr_3, u32 *dst_addr_4); +extern s32 ixgbe_atr_get_src_port_82599(struct ixgbe_atr_input *input, + u16 *src_port); +extern s32 ixgbe_atr_get_dst_port_82599(struct ixgbe_atr_input *input, + u16 *dst_port); +extern s32 ixgbe_atr_get_flex_byte_82599(struct ixgbe_atr_input *input, + u16 *flex_byte); +extern s32 ixgbe_atr_get_vm_pool_82599(struct ixgbe_atr_input *input, + u8 *vm_pool); +extern s32 ixgbe_atr_get_l4type_82599(struct ixgbe_atr_input *input, + u8 *l4type); +#ifdef IXGBE_FCOE +extern void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter); +extern int ixgbe_fso(struct ixgbe_adapter *adapter, + struct ixgbe_ring *tx_ring, struct sk_buff *skb, + u32 tx_flags, u8 *hdr_len); +extern void ixgbe_cleanup_fcoe(struct ixgbe_adapter *adapter); +extern int ixgbe_fcoe_ddp(struct ixgbe_adapter *adapter, + union ixgbe_adv_rx_desc *rx_desc, + struct sk_buff *skb); +extern int ixgbe_fcoe_ddp_get(struct net_device *netdev, u16 xid, + struct scatterlist *sgl, unsigned int sgc); +extern int ixgbe_fcoe_ddp_put(struct net_device *netdev, u16 xid); +#endif /* IXGBE_FCOE */ #endif /* _IXGBE_H_ */ diff --git a/drivers/net/ixgbe/ixgbe_82598.c b/drivers/net/ixgbe/ixgbe_82598.c index 4791238c3f6e..b9923047ce11 100644 --- a/drivers/net/ixgbe/ixgbe_82598.c +++ b/drivers/net/ixgbe/ixgbe_82598.c @@ -75,18 +75,49 @@ static u16 ixgbe_get_pcie_msix_count_82598(struct ixgbe_hw *hw) static s32 ixgbe_get_invariants_82598(struct ixgbe_hw *hw) { struct ixgbe_mac_info *mac = &hw->mac; - struct ixgbe_phy_info *phy = &hw->phy; - s32 ret_val = 0; - u16 list_offset, data_offset; - - /* Set the bus information prior to PHY identification */ - mac->ops.get_bus_info(hw); /* Call PHY identify routine to get the phy type */ ixgbe_identify_phy_generic(hw); - /* PHY Init */ - switch (phy->type) { + mac->mcft_size = IXGBE_82598_MC_TBL_SIZE; + mac->vft_size = IXGBE_82598_VFT_TBL_SIZE; + mac->num_rar_entries = IXGBE_82598_RAR_ENTRIES; + mac->max_rx_queues = IXGBE_82598_MAX_RX_QUEUES; + mac->max_tx_queues = IXGBE_82598_MAX_TX_QUEUES; + mac->max_msix_vectors = ixgbe_get_pcie_msix_count_82598(hw); + + return 0; +} + +/** + * ixgbe_init_phy_ops_82598 - PHY/SFP specific init + * @hw: pointer to hardware structure + * + * Initialize any function pointers that were not able to be + * set during get_invariants because the PHY/SFP type was + * not known. Perform the SFP init if necessary. + * + **/ +s32 ixgbe_init_phy_ops_82598(struct ixgbe_hw *hw) +{ + struct ixgbe_mac_info *mac = &hw->mac; + struct ixgbe_phy_info *phy = &hw->phy; + s32 ret_val = 0; + u16 list_offset, data_offset; + + /* Identify the PHY */ + phy->ops.identify(hw); + + /* Overwrite the link function pointers if copper PHY */ + if (mac->ops.get_media_type(hw) == ixgbe_media_type_copper) { + mac->ops.setup_link = &ixgbe_setup_copper_link_82598; + mac->ops.setup_link_speed = + &ixgbe_setup_copper_link_speed_82598; + mac->ops.get_link_capabilities = + &ixgbe_get_copper_link_capabilities_82598; + } + + switch (hw->phy.type) { case ixgbe_phy_tn: phy->ops.check_link = &ixgbe_check_phy_link_tnx; phy->ops.get_firmware_version = @@ -106,8 +137,8 @@ static s32 ixgbe_get_invariants_82598(struct ixgbe_hw *hw) /* Check to see if SFP+ module is supported */ ret_val = ixgbe_get_sfp_init_sequence_offsets(hw, - &list_offset, - &data_offset); + &list_offset, + &data_offset); if (ret_val != 0) { ret_val = IXGBE_ERR_SFP_NOT_SUPPORTED; goto out; @@ -117,21 +148,6 @@ static s32 ixgbe_get_invariants_82598(struct ixgbe_hw *hw) break; } - if (mac->ops.get_media_type(hw) == ixgbe_media_type_copper) { - mac->ops.setup_link = &ixgbe_setup_copper_link_82598; - mac->ops.setup_link_speed = - &ixgbe_setup_copper_link_speed_82598; - mac->ops.get_link_capabilities = - &ixgbe_get_copper_link_capabilities_82598; - } - - mac->mcft_size = IXGBE_82598_MC_TBL_SIZE; - mac->vft_size = IXGBE_82598_VFT_TBL_SIZE; - mac->num_rar_entries = IXGBE_82598_RAR_ENTRIES; - mac->max_rx_queues = IXGBE_82598_MAX_RX_QUEUES; - mac->max_tx_queues = IXGBE_82598_MAX_TX_QUEUES; - mac->max_msix_vectors = ixgbe_get_pcie_msix_count_82598(hw); - out: return ret_val; } @@ -149,12 +165,19 @@ static s32 ixgbe_get_link_capabilities_82598(struct ixgbe_hw *hw, bool *autoneg) { s32 status = 0; + u32 autoc = 0; /* * Determine link capabilities based on the stored value of AUTOC, - * which represents EEPROM defaults. + * which represents EEPROM defaults. If AUTOC value has not been + * stored, use the current register value. */ - switch (hw->mac.orig_autoc & IXGBE_AUTOC_LMS_MASK) { + if (hw->mac.orig_link_settings_stored) + autoc = hw->mac.orig_autoc; + else + autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC); + + switch (autoc & IXGBE_AUTOC_LMS_MASK) { case IXGBE_AUTOC_LMS_1G_LINK_NO_AN: *speed = IXGBE_LINK_SPEED_1GB_FULL; *autoneg = false; @@ -173,9 +196,9 @@ static s32 ixgbe_get_link_capabilities_82598(struct ixgbe_hw *hw, case IXGBE_AUTOC_LMS_KX4_AN: case IXGBE_AUTOC_LMS_KX4_AN_1G_AN: *speed = IXGBE_LINK_SPEED_UNKNOWN; - if (hw->mac.orig_autoc & IXGBE_AUTOC_KX4_SUPP) + if (autoc & IXGBE_AUTOC_KX4_SUPP) *speed |= IXGBE_LINK_SPEED_10GB_FULL; - if (hw->mac.orig_autoc & IXGBE_AUTOC_KX_SUPP) + if (autoc & IXGBE_AUTOC_KX_SUPP) *speed |= IXGBE_LINK_SPEED_1GB_FULL; *autoneg = true; break; @@ -206,14 +229,13 @@ static s32 ixgbe_get_copper_link_capabilities_82598(struct ixgbe_hw *hw, *speed = 0; *autoneg = true; - status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_SPEED_ABILITY, - IXGBE_MDIO_PMA_PMD_DEV_TYPE, + status = hw->phy.ops.read_reg(hw, MDIO_SPEED, MDIO_MMD_PMAPMD, &speed_ability); if (status == 0) { - if (speed_ability & IXGBE_MDIO_PHY_SPEED_10G) + if (speed_ability & MDIO_SPEED_10G) *speed |= IXGBE_LINK_SPEED_10GB_FULL; - if (speed_ability & IXGBE_MDIO_PHY_SPEED_1G) + if (speed_ability & MDIO_PMA_SPEED_1000) *speed |= IXGBE_LINK_SPEED_1GB_FULL; } @@ -271,6 +293,17 @@ static s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw, s32 packetbuf_num) u32 rmcs_reg; u32 reg; +#ifdef CONFIG_DCB + if (hw->fc.requested_mode == ixgbe_fc_pfc) + goto out; + +#endif /* CONFIG_DCB */ + /* Negotiate the fc mode to use */ + ret_val = ixgbe_fc_autoneg(hw); + if (ret_val) + goto out; + + /* Disable any previous flow control settings */ fctrl_reg = IXGBE_READ_REG(hw, IXGBE_FCTRL); fctrl_reg &= ~(IXGBE_FCTRL_RFCE | IXGBE_FCTRL_RPFCE); @@ -282,14 +315,20 @@ static s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw, s32 packetbuf_num) * 0: Flow control is completely disabled * 1: Rx flow control is enabled (we can receive pause frames, * but not send pause frames). - * 2: Tx flow control is enabled (we can send pause frames but + * 2: Tx flow control is enabled (we can send pause frames but * we do not support receiving pause frames). * 3: Both Rx and Tx flow control (symmetric) are enabled. * other: Invalid. +#ifdef CONFIG_DCB + * 4: Priority Flow Control is enabled. +#endif */ switch (hw->fc.current_mode) { case ixgbe_fc_none: - /* Flow control completely disabled by software override. */ + /* + * Flow control is disabled by software override or autoneg. + * The code below will actually disable it in the HW. + */ break; case ixgbe_fc_rx_pause: /* @@ -314,6 +353,11 @@ static s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw, s32 packetbuf_num) fctrl_reg |= IXGBE_FCTRL_RFCE; rmcs_reg |= IXGBE_RMCS_TFCE_802_3X; break; +#ifdef CONFIG_DCB + case ixgbe_fc_pfc: + goto out; + break; +#endif /* CONFIG_DCB */ default: hw_dbg(hw, "Flow control param set incorrectly\n"); ret_val = -IXGBE_ERR_CONFIG; @@ -321,7 +365,8 @@ static s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw, s32 packetbuf_num) break; } - /* Enable 802.3x based flow control settings. */ + /* Set 802.3x based flow control settings. */ + fctrl_reg |= IXGBE_FCTRL_DPF; IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl_reg); IXGBE_WRITE_REG(hw, IXGBE_RMCS, rmcs_reg); @@ -340,7 +385,7 @@ static s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw, s32 packetbuf_num) } /* Configure pause time (2 TCs per register) */ - reg = IXGBE_READ_REG(hw, IXGBE_FCTTV(packetbuf_num)); + reg = IXGBE_READ_REG(hw, IXGBE_FCTTV(packetbuf_num / 2)); if ((packetbuf_num & 1) == 0) reg = (reg & 0xFFFF0000) | hw->fc.pause_time; else @@ -353,77 +398,6 @@ out: return ret_val; } -/** - * ixgbe_setup_fc_82598 - Configure flow control settings - * @hw: pointer to hardware structure - * @packetbuf_num: packet buffer number (0-7) - * - * Configures the flow control settings based on SW configuration. This - * function is used for 802.3x flow control configuration only. - **/ -static s32 ixgbe_setup_fc_82598(struct ixgbe_hw *hw, s32 packetbuf_num) -{ - s32 ret_val = 0; - ixgbe_link_speed speed; - bool link_up; - - /* Validate the packetbuf configuration */ - if (packetbuf_num < 0 || packetbuf_num > 7) { - hw_dbg(hw, "Invalid packet buffer number [%d], expected range is" - " 0-7\n", packetbuf_num); - ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS; - goto out; - } - - /* - * Validate the water mark configuration. Zero water marks are invalid - * because it causes the controller to just blast out fc packets. - */ - if (!hw->fc.low_water || !hw->fc.high_water || !hw->fc.pause_time) { - hw_dbg(hw, "Invalid water mark configuration\n"); - ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS; - goto out; - } - - /* - * Validate the requested mode. Strict IEEE mode does not allow - * ixgbe_fc_rx_pause because it will cause testing anomalies. - */ - if (hw->fc.strict_ieee && hw->fc.requested_mode == ixgbe_fc_rx_pause) { - hw_dbg(hw, "ixgbe_fc_rx_pause not valid in strict IEEE mode\n"); - ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS; - goto out; - } - - /* - * 10gig parts do not have a word in the EEPROM to determine the - * default flow control setting, so we explicitly set it to full. - */ - if (hw->fc.requested_mode == ixgbe_fc_default) - hw->fc.requested_mode = ixgbe_fc_full; - - /* - * Save off the requested flow control mode for use later. Depending - * on the link partner's capabilities, we may or may not use this mode. - */ - - hw->fc.current_mode = hw->fc.requested_mode; - - /* Decide whether to use autoneg or not. */ - hw->mac.ops.check_link(hw, &speed, &link_up, false); - if (!hw->fc.disable_fc_autoneg && hw->phy.multispeed_fiber && - (speed == IXGBE_LINK_SPEED_1GB_FULL)) - ret_val = ixgbe_fc_autoneg(hw); - - if (ret_val) - goto out; - - ret_val = ixgbe_fc_enable_82598(hw, packetbuf_num); - -out: - return ret_val; -} - /** * ixgbe_setup_mac_link_82598 - Configures MAC link settings * @hw: pointer to hardware structure @@ -463,13 +437,6 @@ static s32 ixgbe_setup_mac_link_82598(struct ixgbe_hw *hw) } } - /* - * We want to save off the original Flow Control configuration just in - * case we get disconnected and then reconnected into a different hub - * or switch with different Flow Control capabilities. - */ - ixgbe_setup_fc_82598(hw, 0); - /* Add delay to filter out noises during initial link setup */ msleep(50); @@ -500,9 +467,9 @@ static s32 ixgbe_check_mac_link_82598(struct ixgbe_hw *hw, * clear indicates active; set indicates inactive. */ if (hw->phy.type == ixgbe_phy_nl) { - hw->phy.ops.read_reg(hw, 0xC79F, IXGBE_TWINAX_DEV, &link_reg); - hw->phy.ops.read_reg(hw, 0xC79F, IXGBE_TWINAX_DEV, &link_reg); - hw->phy.ops.read_reg(hw, 0xC00C, IXGBE_TWINAX_DEV, + hw->phy.ops.read_reg(hw, 0xC79F, MDIO_MMD_PMAPMD, &link_reg); + hw->phy.ops.read_reg(hw, 0xC79F, MDIO_MMD_PMAPMD, &link_reg); + hw->phy.ops.read_reg(hw, 0xC00C, MDIO_MMD_PMAPMD, &adapt_comp_reg); if (link_up_wait_to_complete) { for (i = 0; i < IXGBE_LINK_UP_TIME; i++) { @@ -515,10 +482,10 @@ static s32 ixgbe_check_mac_link_82598(struct ixgbe_hw *hw, } msleep(100); hw->phy.ops.read_reg(hw, 0xC79F, - IXGBE_TWINAX_DEV, + MDIO_MMD_PMAPMD, &link_reg); hw->phy.ops.read_reg(hw, 0xC00C, - IXGBE_TWINAX_DEV, + MDIO_MMD_PMAPMD, &adapt_comp_reg); } } else { @@ -556,6 +523,11 @@ static s32 ixgbe_check_mac_link_82598(struct ixgbe_hw *hw, else *speed = IXGBE_LINK_SPEED_1GB_FULL; + /* if link is down, zero out the current_mode */ + if (*link_up == false) { + hw->fc.current_mode = ixgbe_fc_none; + hw->fc.fc_was_autonegged = false; + } out: return 0; } @@ -673,6 +645,7 @@ static s32 ixgbe_setup_copper_link_speed_82598(struct ixgbe_hw *hw, static s32 ixgbe_reset_hw_82598(struct ixgbe_hw *hw) { s32 status = 0; + s32 phy_status = 0; u32 ctrl; u32 gheccr; u32 i; @@ -716,14 +689,27 @@ static s32 ixgbe_reset_hw_82598(struct ixgbe_hw *hw) } /* Reset PHY */ - if (hw->phy.reset_disable == false) - hw->phy.ops.reset(hw); + if (hw->phy.reset_disable == false) { + /* PHY ops must be identified and initialized prior to reset */ + /* Init PHY and function pointers, perform SFP setup */ + phy_status = hw->phy.ops.init(hw); + if (phy_status == IXGBE_ERR_SFP_NOT_SUPPORTED) + goto reset_hw_out; + else if (phy_status == IXGBE_ERR_SFP_NOT_PRESENT) + goto no_phy_reset; + + + hw->phy.ops.reset(hw); + } + +no_phy_reset: /* * Prevent the PCI-E bus from from hanging by disabling PCI-E master * access and verify no pending requests before reset */ - if (ixgbe_disable_pcie_master(hw) != 0) { + status = ixgbe_disable_pcie_master(hw); + if (status != 0) { status = IXGBE_ERR_MASTER_REQUESTS_PENDING; hw_dbg(hw, "PCI-E Master disable polling has failed.\n"); } @@ -767,9 +753,19 @@ static s32 ixgbe_reset_hw_82598(struct ixgbe_hw *hw) IXGBE_WRITE_REG(hw, IXGBE_AUTOC, hw->mac.orig_autoc); } + /* + * Store MAC address from RAR0, clear receive address registers, and + * clear the multicast table + */ + hw->mac.ops.init_rx_addrs(hw); + /* Store the permanent mac address */ hw->mac.ops.get_mac_addr(hw, hw->mac.perm_addr); +reset_hw_out: + if (phy_status) + status = phy_status; + return status; } @@ -954,14 +950,14 @@ static s32 ixgbe_read_i2c_eeprom_82598(struct ixgbe_hw *hw, u8 byte_offset, sfp_addr = (sfp_addr | IXGBE_I2C_EEPROM_READ_MASK); hw->phy.ops.write_reg(hw, IXGBE_MDIO_PMA_PMD_SDA_SCL_ADDR, - IXGBE_MDIO_PMA_PMD_DEV_TYPE, + MDIO_MMD_PMAPMD, sfp_addr); /* Poll status */ for (i = 0; i < 100; i++) { hw->phy.ops.read_reg(hw, IXGBE_MDIO_PMA_PMD_SDA_SCL_STAT, - IXGBE_MDIO_PMA_PMD_DEV_TYPE, + MDIO_MMD_PMAPMD, &sfp_stat); sfp_stat = sfp_stat & IXGBE_I2C_EEPROM_STATUS_MASK; if (sfp_stat != IXGBE_I2C_EEPROM_STATUS_IN_PROGRESS) @@ -977,7 +973,7 @@ static s32 ixgbe_read_i2c_eeprom_82598(struct ixgbe_hw *hw, u8 byte_offset, /* Read data */ hw->phy.ops.read_reg(hw, IXGBE_MDIO_PMA_PMD_SDA_SCL_DATA, - IXGBE_MDIO_PMA_PMD_DEV_TYPE, &sfp_data); + MDIO_MMD_PMAPMD, &sfp_data); *eeprom_data = (u8)(sfp_data >> 8); } else { @@ -998,35 +994,56 @@ out: static u32 ixgbe_get_supported_physical_layer_82598(struct ixgbe_hw *hw) { u32 physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN; + u32 autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC); + u32 pma_pmd_10g = autoc & IXGBE_AUTOC_10G_PMA_PMD_MASK; + u32 pma_pmd_1g = autoc & IXGBE_AUTOC_1G_PMA_PMD_MASK; + u16 ext_ability = 0; - switch (hw->device_id) { - case IXGBE_DEV_ID_82598: - /* Default device ID is mezzanine card KX/KX4 */ - physical_layer = (IXGBE_PHYSICAL_LAYER_10GBASE_KX4 | - IXGBE_PHYSICAL_LAYER_1000BASE_KX); + hw->phy.ops.identify(hw); + + /* Copper PHY must be checked before AUTOC LMS to determine correct + * physical layer because 10GBase-T PHYs use LMS = KX4/KX */ + if (hw->phy.type == ixgbe_phy_tn || + hw->phy.type == ixgbe_phy_cu_unknown) { + hw->phy.ops.read_reg(hw, MDIO_PMA_EXTABLE, MDIO_MMD_PMAPMD, + &ext_ability); + if (ext_ability & MDIO_PMA_EXTABLE_10GBT) + physical_layer |= IXGBE_PHYSICAL_LAYER_10GBASE_T; + if (ext_ability & MDIO_PMA_EXTABLE_1000BT) + physical_layer |= IXGBE_PHYSICAL_LAYER_1000BASE_T; + if (ext_ability & MDIO_PMA_EXTABLE_100BTX) + physical_layer |= IXGBE_PHYSICAL_LAYER_100BASE_TX; + goto out; + } + + switch (autoc & IXGBE_AUTOC_LMS_MASK) { + case IXGBE_AUTOC_LMS_1G_AN: + case IXGBE_AUTOC_LMS_1G_LINK_NO_AN: + if (pma_pmd_1g == IXGBE_AUTOC_1G_KX) + physical_layer = IXGBE_PHYSICAL_LAYER_1000BASE_KX; + else + physical_layer = IXGBE_PHYSICAL_LAYER_1000BASE_BX; break; - case IXGBE_DEV_ID_82598_BX: - physical_layer = IXGBE_PHYSICAL_LAYER_1000BASE_BX; - case IXGBE_DEV_ID_82598EB_CX4: - case IXGBE_DEV_ID_82598_CX4_DUAL_PORT: - physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_CX4; + case IXGBE_AUTOC_LMS_10G_LINK_NO_AN: + if (pma_pmd_10g == IXGBE_AUTOC_10G_CX4) + physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_CX4; + else if (pma_pmd_10g == IXGBE_AUTOC_10G_KX4) + physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_KX4; + else /* XAUI */ + physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN; break; - case IXGBE_DEV_ID_82598_DA_DUAL_PORT: - physical_layer = IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU; + case IXGBE_AUTOC_LMS_KX4_AN: + case IXGBE_AUTOC_LMS_KX4_AN_1G_AN: + if (autoc & IXGBE_AUTOC_KX_SUPP) + physical_layer |= IXGBE_PHYSICAL_LAYER_1000BASE_KX; + if (autoc & IXGBE_AUTOC_KX4_SUPP) + physical_layer |= IXGBE_PHYSICAL_LAYER_10GBASE_KX4; break; - case IXGBE_DEV_ID_82598AF_DUAL_PORT: - case IXGBE_DEV_ID_82598AF_SINGLE_PORT: - case IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM: - physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_SR; + default: break; - case IXGBE_DEV_ID_82598EB_XF_LR: - physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_LR; - break; - case IXGBE_DEV_ID_82598AT: - physical_layer = (IXGBE_PHYSICAL_LAYER_10GBASE_T | - IXGBE_PHYSICAL_LAYER_1000BASE_T); - break; - case IXGBE_DEV_ID_82598EB_SFP_LOM: + } + + if (hw->phy.type == ixgbe_phy_nl) { hw->phy.ops.identify_sfp(hw); switch (hw->phy.sfp_type) { @@ -1043,13 +1060,25 @@ static u32 ixgbe_get_supported_physical_layer_82598(struct ixgbe_hw *hw) physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN; break; } - break; + } + switch (hw->device_id) { + case IXGBE_DEV_ID_82598_DA_DUAL_PORT: + physical_layer = IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU; + break; + case IXGBE_DEV_ID_82598AF_DUAL_PORT: + case IXGBE_DEV_ID_82598AF_SINGLE_PORT: + case IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM: + physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_SR; + break; + case IXGBE_DEV_ID_82598EB_XF_LR: + physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_LR; + break; default: - physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN; break; } +out: return physical_layer; } @@ -1086,7 +1115,7 @@ static struct ixgbe_mac_operations mac_ops_82598 = { .disable_mc = &ixgbe_disable_mc_generic, .clear_vfta = &ixgbe_clear_vfta_82598, .set_vfta = &ixgbe_set_vfta_82598, - .setup_fc = &ixgbe_setup_fc_82598, + .fc_enable = &ixgbe_fc_enable_82598, }; static struct ixgbe_eeprom_operations eeprom_ops_82598 = { @@ -1099,6 +1128,7 @@ static struct ixgbe_eeprom_operations eeprom_ops_82598 = { static struct ixgbe_phy_operations phy_ops_82598 = { .identify = &ixgbe_identify_phy_generic, .identify_sfp = &ixgbe_identify_sfp_module_generic, + .init = &ixgbe_init_phy_ops_82598, .reset = &ixgbe_reset_phy_generic, .read_reg = &ixgbe_read_phy_reg_generic, .write_reg = &ixgbe_write_phy_reg_generic, diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c index 29771fbaa42d..1984cab7d48b 100644 --- a/drivers/net/ixgbe/ixgbe_82599.c +++ b/drivers/net/ixgbe/ixgbe_82599.c @@ -71,10 +71,10 @@ s32 ixgbe_clear_vfta_82599(struct ixgbe_hw *hw); s32 ixgbe_init_uta_tables_82599(struct ixgbe_hw *hw); s32 ixgbe_read_analog_reg8_82599(struct ixgbe_hw *hw, u32 reg, u8 *val); s32 ixgbe_write_analog_reg8_82599(struct ixgbe_hw *hw, u32 reg, u8 val); -s32 ixgbe_start_hw_rev_0_82599(struct ixgbe_hw *hw); s32 ixgbe_identify_phy_82599(struct ixgbe_hw *hw); s32 ixgbe_start_hw_82599(struct ixgbe_hw *hw); u32 ixgbe_get_supported_physical_layer_82599(struct ixgbe_hw *hw); +static s32 ixgbe_verify_fw_version_82599(struct ixgbe_hw *hw); void ixgbe_init_mac_link_ops_82599(struct ixgbe_hw *hw) { @@ -100,22 +100,36 @@ s32 ixgbe_setup_sfp_modules_82599(struct ixgbe_hw *hw) if (hw->phy.sfp_type != ixgbe_sfp_type_unknown) { ixgbe_init_mac_link_ops_82599(hw); + + hw->phy.ops.reset = NULL; + ret_val = ixgbe_get_sfp_init_sequence_offsets(hw, &list_offset, &data_offset); if (ret_val != 0) goto setup_sfp_out; + /* PHY config will finish before releasing the semaphore */ + ret_val = ixgbe_acquire_swfw_sync(hw, IXGBE_GSSR_MAC_CSR_SM); + if (ret_val != 0) { + ret_val = IXGBE_ERR_SWFW_SYNC; + goto setup_sfp_out; + } + hw->eeprom.ops.read(hw, ++data_offset, &data_value); while (data_value != 0xffff) { IXGBE_WRITE_REG(hw, IXGBE_CORECTL, data_value); IXGBE_WRITE_FLUSH(hw); hw->eeprom.ops.read(hw, ++data_offset, &data_value); } - /* Now restart DSP */ - IXGBE_WRITE_REG(hw, IXGBE_CORECTL, 0x00000102); - IXGBE_WRITE_REG(hw, IXGBE_CORECTL, 0x00000b1d); - IXGBE_WRITE_FLUSH(hw); + /* Now restart DSP by setting Restart_AN */ + IXGBE_WRITE_REG(hw, IXGBE_AUTOC, + (IXGBE_READ_REG(hw, IXGBE_AUTOC) | IXGBE_AUTOC_AN_RESTART)); + + /* Release the semaphore */ + ixgbe_release_swfw_sync(hw, IXGBE_GSSR_MAC_CSR_SM); + /* Delay obtaining semaphore again to allow FW access */ + msleep(hw->eeprom.semaphore_delay); } setup_sfp_out: @@ -146,43 +160,9 @@ u32 ixgbe_get_pcie_msix_count_82599(struct ixgbe_hw *hw) static s32 ixgbe_get_invariants_82599(struct ixgbe_hw *hw) { struct ixgbe_mac_info *mac = &hw->mac; - struct ixgbe_phy_info *phy = &hw->phy; - s32 ret_val; - - /* Set the bus information prior to PHY identification */ - mac->ops.get_bus_info(hw); - - /* Call PHY identify routine to get the Cu or SFI phy type */ - ret_val = phy->ops.identify(hw); - - if (ret_val == IXGBE_ERR_SFP_NOT_SUPPORTED) - goto get_invariants_out; ixgbe_init_mac_link_ops_82599(hw); - /* Setup SFP module if there is one present. */ - ret_val = mac->ops.setup_sfp(hw); - - /* If copper media, overwrite with copper function pointers */ - if (mac->ops.get_media_type(hw) == ixgbe_media_type_copper) { - mac->ops.setup_link = &ixgbe_setup_copper_link_82599; - mac->ops.setup_link_speed = - &ixgbe_setup_copper_link_speed_82599; - mac->ops.get_link_capabilities = - &ixgbe_get_copper_link_capabilities_82599; - } - - /* PHY Init */ - switch (hw->phy.type) { - case ixgbe_phy_tn: - phy->ops.check_link = &ixgbe_check_phy_link_tnx; - phy->ops.get_firmware_version = - &ixgbe_get_phy_firmware_version_tnx; - break; - default: - break; - } - mac->mcft_size = IXGBE_82599_MC_TBL_SIZE; mac->vft_size = IXGBE_82599_VFT_TBL_SIZE; mac->num_rar_entries = IXGBE_82599_RAR_ENTRIES; @@ -190,7 +170,50 @@ static s32 ixgbe_get_invariants_82599(struct ixgbe_hw *hw) mac->max_tx_queues = IXGBE_82599_MAX_TX_QUEUES; mac->max_msix_vectors = ixgbe_get_pcie_msix_count_82599(hw); -get_invariants_out: + return 0; +} + +/** + * ixgbe_init_phy_ops_82599 - PHY/SFP specific init + * @hw: pointer to hardware structure + * + * Initialize any function pointers that were not able to be + * set during get_invariants because the PHY/SFP type was + * not known. Perform the SFP init if necessary. + * + **/ +s32 ixgbe_init_phy_ops_82599(struct ixgbe_hw *hw) +{ + struct ixgbe_mac_info *mac = &hw->mac; + struct ixgbe_phy_info *phy = &hw->phy; + s32 ret_val = 0; + + /* Identify the PHY or SFP module */ + ret_val = phy->ops.identify(hw); + + /* Setup function pointers based on detected SFP module and speeds */ + ixgbe_init_mac_link_ops_82599(hw); + + /* If copper media, overwrite with copper function pointers */ + if (mac->ops.get_media_type(hw) == ixgbe_media_type_copper) { + mac->ops.setup_link = &ixgbe_setup_copper_link_82599; + mac->ops.setup_link_speed = + &ixgbe_setup_copper_link_speed_82599; + mac->ops.get_link_capabilities = + &ixgbe_get_copper_link_capabilities_82599; + } + + /* Set necessary function pointers based on phy type */ + switch (hw->phy.type) { + case ixgbe_phy_tn: + phy->ops.check_link = &ixgbe_check_phy_link_tnx; + phy->ops.get_firmware_version = + &ixgbe_get_phy_firmware_version_tnx; + break; + default: + break; + } + return ret_val; } @@ -207,8 +230,19 @@ s32 ixgbe_get_link_capabilities_82599(struct ixgbe_hw *hw, bool *negotiation) { s32 status = 0; + u32 autoc = 0; - switch (hw->mac.orig_autoc & IXGBE_AUTOC_LMS_MASK) { + /* + * Determine link capabilities based on the stored value of AUTOC, + * which represents EEPROM defaults. If AUTOC value has not been + * stored, use the current register value. + */ + if (hw->mac.orig_link_settings_stored) + autoc = hw->mac.orig_autoc; + else + autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC); + + switch (autoc & IXGBE_AUTOC_LMS_MASK) { case IXGBE_AUTOC_LMS_1G_LINK_NO_AN: *speed = IXGBE_LINK_SPEED_1GB_FULL; *negotiation = false; @@ -232,22 +266,22 @@ s32 ixgbe_get_link_capabilities_82599(struct ixgbe_hw *hw, case IXGBE_AUTOC_LMS_KX4_KX_KR: case IXGBE_AUTOC_LMS_KX4_KX_KR_1G_AN: *speed = IXGBE_LINK_SPEED_UNKNOWN; - if (hw->mac.orig_autoc & IXGBE_AUTOC_KR_SUPP) + if (autoc & IXGBE_AUTOC_KR_SUPP) *speed |= IXGBE_LINK_SPEED_10GB_FULL; - if (hw->mac.orig_autoc & IXGBE_AUTOC_KX4_SUPP) + if (autoc & IXGBE_AUTOC_KX4_SUPP) *speed |= IXGBE_LINK_SPEED_10GB_FULL; - if (hw->mac.orig_autoc & IXGBE_AUTOC_KX_SUPP) + if (autoc & IXGBE_AUTOC_KX_SUPP) *speed |= IXGBE_LINK_SPEED_1GB_FULL; *negotiation = true; break; case IXGBE_AUTOC_LMS_KX4_KX_KR_SGMII: *speed = IXGBE_LINK_SPEED_100_FULL; - if (hw->mac.orig_autoc & IXGBE_AUTOC_KR_SUPP) + if (autoc & IXGBE_AUTOC_KR_SUPP) *speed |= IXGBE_LINK_SPEED_10GB_FULL; - if (hw->mac.orig_autoc & IXGBE_AUTOC_KX4_SUPP) + if (autoc & IXGBE_AUTOC_KX4_SUPP) *speed |= IXGBE_LINK_SPEED_10GB_FULL; - if (hw->mac.orig_autoc & IXGBE_AUTOC_KX_SUPP) + if (autoc & IXGBE_AUTOC_KX_SUPP) *speed |= IXGBE_LINK_SPEED_1GB_FULL; *negotiation = true; break; @@ -291,14 +325,13 @@ static s32 ixgbe_get_copper_link_capabilities_82599(struct ixgbe_hw *hw, *speed = 0; *autoneg = true; - status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_SPEED_ABILITY, - IXGBE_MDIO_PMA_PMD_DEV_TYPE, + status = hw->phy.ops.read_reg(hw, MDIO_SPEED, MDIO_MMD_PMAPMD, &speed_ability); if (status == 0) { - if (speed_ability & IXGBE_MDIO_PHY_SPEED_10G) + if (speed_ability & MDIO_SPEED_10G) *speed |= IXGBE_LINK_SPEED_10GB_FULL; - if (speed_ability & IXGBE_MDIO_PHY_SPEED_1G) + if (speed_ability & MDIO_PMA_SPEED_1000) *speed |= IXGBE_LINK_SPEED_1GB_FULL; } @@ -323,8 +356,8 @@ enum ixgbe_media_type ixgbe_get_media_type_82599(struct ixgbe_hw *hw) } switch (hw->device_id) { - case IXGBE_DEV_ID_82599: case IXGBE_DEV_ID_82599_KX4: + case IXGBE_DEV_ID_82599_XAUI_LOM: /* Default device ID is mezzanine card KX/KX4 */ media_type = ixgbe_media_type_backplane; break; @@ -380,9 +413,6 @@ s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw) } } - /* Set up flow control */ - status = ixgbe_setup_fc_generic(hw, 0); - /* Add delay to filter out noises during initial link setup */ msleep(50); @@ -428,11 +458,31 @@ s32 ixgbe_setup_mac_link_speed_multispeed_fiber(struct ixgbe_hw *hw, u32 esdp_reg = IXGBE_READ_REG(hw, IXGBE_ESDP); bool link_up = false; bool negotiation; + int i; /* Mask off requested but non-supported speeds */ hw->mac.ops.get_link_capabilities(hw, &phy_link_speed, &negotiation); speed &= phy_link_speed; + /* Set autoneg_advertised value based on input link speed */ + hw->phy.autoneg_advertised = 0; + + if (speed & IXGBE_LINK_SPEED_10GB_FULL) + hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_10GB_FULL; + + if (speed & IXGBE_LINK_SPEED_1GB_FULL) + hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_1GB_FULL; + + /* + * When the driver changes the link speeds that it can support, + * it sets autotry_restart to true to indicate that we need to + * initiate a new autotry session with the link partner. To do + * so, we set the speed then disable and re-enable the tx laser, to + * alert the link partner that it also needs to restart autotry on its + * end. This is consistent with true clause 37 autoneg, which also + * involves a loss of signal. + */ + /* * Try each speed one by one, highest priority first. We do this in * software because 10gb fiber doesn't support speed autonegotiation. @@ -441,21 +491,52 @@ s32 ixgbe_setup_mac_link_speed_multispeed_fiber(struct ixgbe_hw *hw, speedcnt++; highest_link_speed = IXGBE_LINK_SPEED_10GB_FULL; - /* Set hardware SDP's */ + /* If we already have link at this speed, just jump out */ + hw->mac.ops.check_link(hw, &phy_link_speed, &link_up, false); + + if ((phy_link_speed == IXGBE_LINK_SPEED_10GB_FULL) && link_up) + goto out; + + /* Set the module link speed */ esdp_reg |= (IXGBE_ESDP_SDP5_DIR | IXGBE_ESDP_SDP5); IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg); - ixgbe_setup_mac_link_speed_82599(hw, - IXGBE_LINK_SPEED_10GB_FULL, - autoneg, - autoneg_wait_to_complete); + /* Allow module to change analog characteristics (1G->10G) */ + msleep(40); - msleep(50); - - /* If we have link, just jump out */ - hw->mac.ops.check_link(hw, &phy_link_speed, &link_up, false); - if (link_up) + status = ixgbe_setup_mac_link_speed_82599(hw, + IXGBE_LINK_SPEED_10GB_FULL, + autoneg, + autoneg_wait_to_complete); + if (status != 0) goto out; + + /* Flap the tx laser if it has not already been done */ + if (hw->mac.autotry_restart) { + /* Disable tx laser; allow 100us to go dark per spec */ + esdp_reg |= IXGBE_ESDP_SDP3; + IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg); + udelay(100); + + /* Enable tx laser; allow 2ms to light up per spec */ + esdp_reg &= ~IXGBE_ESDP_SDP3; + IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg); + msleep(2); + + hw->mac.autotry_restart = false; + } + + /* The controller may take up to 500ms at 10g to acquire link */ + for (i = 0; i < 5; i++) { + /* Wait for the link partner to also set speed */ + msleep(100); + + /* If we have link, just jump out */ + hw->mac.ops.check_link(hw, &phy_link_speed, + &link_up, false); + if (link_up) + goto out; + } } if (speed & IXGBE_LINK_SPEED_1GB_FULL) { @@ -463,16 +544,44 @@ s32 ixgbe_setup_mac_link_speed_multispeed_fiber(struct ixgbe_hw *hw, if (highest_link_speed == IXGBE_LINK_SPEED_UNKNOWN) highest_link_speed = IXGBE_LINK_SPEED_1GB_FULL; - /* Set hardware SDP's */ + /* If we already have link at this speed, just jump out */ + hw->mac.ops.check_link(hw, &phy_link_speed, &link_up, false); + + if ((phy_link_speed == IXGBE_LINK_SPEED_1GB_FULL) && link_up) + goto out; + + /* Set the module link speed */ esdp_reg &= ~IXGBE_ESDP_SDP5; esdp_reg |= IXGBE_ESDP_SDP5_DIR; IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg); - ixgbe_setup_mac_link_speed_82599( - hw, IXGBE_LINK_SPEED_1GB_FULL, autoneg, - autoneg_wait_to_complete); + /* Allow module to change analog characteristics (10G->1G) */ + msleep(40); - msleep(50); + status = ixgbe_setup_mac_link_speed_82599(hw, + IXGBE_LINK_SPEED_1GB_FULL, + autoneg, + autoneg_wait_to_complete); + if (status != 0) + goto out; + + /* Flap the tx laser if it has not already been done */ + if (hw->mac.autotry_restart) { + /* Disable tx laser; allow 100us to go dark per spec */ + esdp_reg |= IXGBE_ESDP_SDP3; + IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg); + udelay(100); + + /* Enable tx laser; allow 2ms to light up per spec */ + esdp_reg &= ~IXGBE_ESDP_SDP3; + IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg); + msleep(2); + + hw->mac.autotry_restart = false; + } + + /* Wait for the link partner to also set speed */ + msleep(100); /* If we have link, just jump out */ hw->mac.ops.check_link(hw, &phy_link_speed, &link_up, false); @@ -538,6 +647,11 @@ s32 ixgbe_check_mac_link_82599(struct ixgbe_hw *hw, ixgbe_link_speed *speed, else *speed = IXGBE_LINK_SPEED_100_FULL; + /* if link is down, zero out the current_mode */ + if (*link_up == false) { + hw->fc.current_mode = ixgbe_fc_none; + hw->fc.fc_was_autonegged = false; + } return 0; } @@ -558,6 +672,8 @@ s32 ixgbe_setup_mac_link_speed_82599(struct ixgbe_hw *hw, s32 status = 0; u32 autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC); u32 autoc2 = IXGBE_READ_REG(hw, IXGBE_AUTOC2); + u32 start_autoc = autoc; + u32 orig_autoc = 0; u32 link_mode = autoc & IXGBE_AUTOC_LMS_MASK; u32 pma_pmd_1g = autoc & IXGBE_AUTOC_1G_PMA_PMD_MASK; u32 pma_pmd_10g_serial = autoc2 & IXGBE_AUTOC2_10G_SERIAL_PMA_PMD_MASK; @@ -571,15 +687,25 @@ s32 ixgbe_setup_mac_link_speed_82599(struct ixgbe_hw *hw, if (speed == IXGBE_LINK_SPEED_UNKNOWN) { status = IXGBE_ERR_LINK_SETUP; - } else if (link_mode == IXGBE_AUTOC_LMS_KX4_KX_KR || - link_mode == IXGBE_AUTOC_LMS_KX4_KX_KR_1G_AN || - link_mode == IXGBE_AUTOC_LMS_KX4_KX_KR_SGMII) { + goto out; + } + + /* Use stored value (EEPROM defaults) of AUTOC to find KR/KX4 support*/ + if (hw->mac.orig_link_settings_stored) + orig_autoc = hw->mac.orig_autoc; + else + orig_autoc = autoc; + + + if (link_mode == IXGBE_AUTOC_LMS_KX4_KX_KR || + link_mode == IXGBE_AUTOC_LMS_KX4_KX_KR_1G_AN || + link_mode == IXGBE_AUTOC_LMS_KX4_KX_KR_SGMII) { /* Set KX4/KX/KR support according to speed requested */ autoc &= ~(IXGBE_AUTOC_KX4_KX_SUPP_MASK | IXGBE_AUTOC_KR_SUPP); if (speed & IXGBE_LINK_SPEED_10GB_FULL) - if (hw->mac.orig_autoc & IXGBE_AUTOC_KX4_SUPP) + if (orig_autoc & IXGBE_AUTOC_KX4_SUPP) autoc |= IXGBE_AUTOC_KX4_SUPP; - if (hw->mac.orig_autoc & IXGBE_AUTOC_KR_SUPP) + if (orig_autoc & IXGBE_AUTOC_KR_SUPP) autoc |= IXGBE_AUTOC_KR_SUPP; if (speed & IXGBE_LINK_SPEED_1GB_FULL) autoc |= IXGBE_AUTOC_KX_SUPP; @@ -605,7 +731,7 @@ s32 ixgbe_setup_mac_link_speed_82599(struct ixgbe_hw *hw, } } - if (status == 0) { + if (autoc != start_autoc) { /* Restart link */ autoc |= IXGBE_AUTOC_AN_RESTART; IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc); @@ -632,13 +758,11 @@ s32 ixgbe_setup_mac_link_speed_82599(struct ixgbe_hw *hw, } } - /* Set up flow control */ - status = ixgbe_setup_fc_generic(hw, 0); - /* Add delay to filter out noises during initial link setup */ msleep(50); } +out: return status; } @@ -705,14 +829,30 @@ s32 ixgbe_reset_hw_82599(struct ixgbe_hw *hw) /* Call adapter stop to disable tx/rx and clear interrupts */ hw->mac.ops.stop_adapter(hw); + /* PHY ops must be identified and initialized prior to reset */ + + /* Init PHY and function pointers, perform SFP setup */ + status = hw->phy.ops.init(hw); + + if (status == IXGBE_ERR_SFP_NOT_SUPPORTED) + goto reset_hw_out; + + /* Setup SFP module if there is one present. */ + if (hw->phy.sfp_setup_needed) { + status = hw->mac.ops.setup_sfp(hw); + hw->phy.sfp_setup_needed = false; + } + /* Reset PHY */ - hw->phy.ops.reset(hw); + if (hw->phy.reset_disable == false && hw->phy.ops.reset != NULL) + hw->phy.ops.reset(hw); /* * Prevent the PCI-E bus from from hanging by disabling PCI-E master * access and verify no pending requests before reset */ - if (ixgbe_disable_pcie_master(hw) != 0) { + status = ixgbe_disable_pcie_master(hw); + if (status != 0) { status = IXGBE_ERR_MASTER_REQUESTS_PENDING; hw_dbg(hw, "PCI-E Master disable polling has failed.\n"); } @@ -770,9 +910,30 @@ s32 ixgbe_reset_hw_82599(struct ixgbe_hw *hw) } } + /* + * Store MAC address from RAR0, clear receive address registers, and + * clear the multicast table. Also reset num_rar_entries to 128, + * since we modify this value when programming the SAN MAC address. + */ + hw->mac.num_rar_entries = 128; + hw->mac.ops.init_rx_addrs(hw); + /* Store the permanent mac address */ hw->mac.ops.get_mac_addr(hw, hw->mac.perm_addr); + /* Store the permanent SAN mac address */ + hw->mac.ops.get_san_mac_addr(hw, hw->mac.san_addr); + + /* Add the SAN MAC address to the RAR only if it's a valid address */ + if (ixgbe_validate_mac_addr(hw->mac.san_addr) == 0) { + hw->mac.ops.set_rar(hw, hw->mac.num_rar_entries - 1, + hw->mac.san_addr, 0, IXGBE_RAH_AV); + + /* Reserve the last RAR for the SAN MAC address */ + hw->mac.num_rar_entries--; + } + +reset_hw_out: return status; } @@ -1003,6 +1164,931 @@ s32 ixgbe_init_uta_tables_82599(struct ixgbe_hw *hw) return 0; } +/** + * ixgbe_reinit_fdir_tables_82599 - Reinitialize Flow Director tables. + * @hw: pointer to hardware structure + **/ +s32 ixgbe_reinit_fdir_tables_82599(struct ixgbe_hw *hw) +{ + int i; + u32 fdirctrl = IXGBE_READ_REG(hw, IXGBE_FDIRCTRL); + fdirctrl &= ~IXGBE_FDIRCTRL_INIT_DONE; + + /* + * Before starting reinitialization process, + * FDIRCMD.CMD must be zero. + */ + for (i = 0; i < IXGBE_FDIRCMD_CMD_POLL; i++) { + if (!(IXGBE_READ_REG(hw, IXGBE_FDIRCMD) & + IXGBE_FDIRCMD_CMD_MASK)) + break; + udelay(10); + } + if (i >= IXGBE_FDIRCMD_CMD_POLL) { + hw_dbg(hw ,"Flow Director previous command isn't complete, " + "aborting table re-initialization. \n"); + return IXGBE_ERR_FDIR_REINIT_FAILED; + } + + IXGBE_WRITE_REG(hw, IXGBE_FDIRFREE, 0); + IXGBE_WRITE_FLUSH(hw); + /* + * 82599 adapters flow director init flow cannot be restarted, + * Workaround 82599 silicon errata by performing the following steps + * before re-writing the FDIRCTRL control register with the same value. + * - write 1 to bit 8 of FDIRCMD register & + * - write 0 to bit 8 of FDIRCMD register + */ + IXGBE_WRITE_REG(hw, IXGBE_FDIRCMD, + (IXGBE_READ_REG(hw, IXGBE_FDIRCMD) | + IXGBE_FDIRCMD_CLEARHT)); + IXGBE_WRITE_FLUSH(hw); + IXGBE_WRITE_REG(hw, IXGBE_FDIRCMD, + (IXGBE_READ_REG(hw, IXGBE_FDIRCMD) & + ~IXGBE_FDIRCMD_CLEARHT)); + IXGBE_WRITE_FLUSH(hw); + /* + * Clear FDIR Hash register to clear any leftover hashes + * waiting to be programmed. + */ + IXGBE_WRITE_REG(hw, IXGBE_FDIRHASH, 0x00); + IXGBE_WRITE_FLUSH(hw); + + IXGBE_WRITE_REG(hw, IXGBE_FDIRCTRL, fdirctrl); + IXGBE_WRITE_FLUSH(hw); + + /* Poll init-done after we write FDIRCTRL register */ + for (i = 0; i < IXGBE_FDIR_INIT_DONE_POLL; i++) { + if (IXGBE_READ_REG(hw, IXGBE_FDIRCTRL) & + IXGBE_FDIRCTRL_INIT_DONE) + break; + udelay(10); + } + if (i >= IXGBE_FDIR_INIT_DONE_POLL) { + hw_dbg(hw, "Flow Director Signature poll time exceeded!\n"); + return IXGBE_ERR_FDIR_REINIT_FAILED; + } + + /* Clear FDIR statistics registers (read to clear) */ + IXGBE_READ_REG(hw, IXGBE_FDIRUSTAT); + IXGBE_READ_REG(hw, IXGBE_FDIRFSTAT); + IXGBE_READ_REG(hw, IXGBE_FDIRMATCH); + IXGBE_READ_REG(hw, IXGBE_FDIRMISS); + IXGBE_READ_REG(hw, IXGBE_FDIRLEN); + + return 0; +} + +/** + * ixgbe_init_fdir_signature_82599 - Initialize Flow Director signature filters + * @hw: pointer to hardware structure + * @pballoc: which mode to allocate filters with + **/ +s32 ixgbe_init_fdir_signature_82599(struct ixgbe_hw *hw, u32 pballoc) +{ + u32 fdirctrl = 0; + u32 pbsize; + int i; + + /* + * Before enabling Flow Director, the Rx Packet Buffer size + * must be reduced. The new value is the current size minus + * flow director memory usage size. + */ + pbsize = (1 << (IXGBE_FDIR_PBALLOC_SIZE_SHIFT + pballoc)); + IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(0), + (IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(0)) - pbsize)); + + /* + * The defaults in the HW for RX PB 1-7 are not zero and so should be + * intialized to zero for non DCB mode otherwise actual total RX PB + * would be bigger than programmed and filter space would run into + * the PB 0 region. + */ + for (i = 1; i < 8; i++) + IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(i), 0); + + /* Send interrupt when 64 filters are left */ + fdirctrl |= 4 << IXGBE_FDIRCTRL_FULL_THRESH_SHIFT; + + /* Set the maximum length per hash bucket to 0xA filters */ + fdirctrl |= 0xA << IXGBE_FDIRCTRL_MAX_LENGTH_SHIFT; + + switch (pballoc) { + case IXGBE_FDIR_PBALLOC_64K: + /* 8k - 1 signature filters */ + fdirctrl |= IXGBE_FDIRCTRL_PBALLOC_64K; + break; + case IXGBE_FDIR_PBALLOC_128K: + /* 16k - 1 signature filters */ + fdirctrl |= IXGBE_FDIRCTRL_PBALLOC_128K; + break; + case IXGBE_FDIR_PBALLOC_256K: + /* 32k - 1 signature filters */ + fdirctrl |= IXGBE_FDIRCTRL_PBALLOC_256K; + break; + default: + /* bad value */ + return IXGBE_ERR_CONFIG; + }; + + /* Move the flexible bytes to use the ethertype - shift 6 words */ + fdirctrl |= (0x6 << IXGBE_FDIRCTRL_FLEX_SHIFT); + + fdirctrl |= IXGBE_FDIRCTRL_REPORT_STATUS; + + /* Prime the keys for hashing */ + IXGBE_WRITE_REG(hw, IXGBE_FDIRHKEY, + htonl(IXGBE_ATR_BUCKET_HASH_KEY)); + IXGBE_WRITE_REG(hw, IXGBE_FDIRSKEY, + htonl(IXGBE_ATR_SIGNATURE_HASH_KEY)); + + /* + * Poll init-done after we write the register. Estimated times: + * 10G: PBALLOC = 11b, timing is 60us + * 1G: PBALLOC = 11b, timing is 600us + * 100M: PBALLOC = 11b, timing is 6ms + * + * Multiple these timings by 4 if under full Rx load + * + * So we'll poll for IXGBE_FDIR_INIT_DONE_POLL times, sleeping for + * 1 msec per poll time. If we're at line rate and drop to 100M, then + * this might not finish in our poll time, but we can live with that + * for now. + */ + IXGBE_WRITE_REG(hw, IXGBE_FDIRCTRL, fdirctrl); + IXGBE_WRITE_FLUSH(hw); + for (i = 0; i < IXGBE_FDIR_INIT_DONE_POLL; i++) { + if (IXGBE_READ_REG(hw, IXGBE_FDIRCTRL) & + IXGBE_FDIRCTRL_INIT_DONE) + break; + msleep(1); + } + if (i >= IXGBE_FDIR_INIT_DONE_POLL) + hw_dbg(hw, "Flow Director Signature poll time exceeded!\n"); + + return 0; +} + +/** + * ixgbe_init_fdir_perfect_82599 - Initialize Flow Director perfect filters + * @hw: pointer to hardware structure + * @pballoc: which mode to allocate filters with + **/ +s32 ixgbe_init_fdir_perfect_82599(struct ixgbe_hw *hw, u32 pballoc) +{ + u32 fdirctrl = 0; + u32 pbsize; + int i; + + /* + * Before enabling Flow Director, the Rx Packet Buffer size + * must be reduced. The new value is the current size minus + * flow director memory usage size. + */ + pbsize = (1 << (IXGBE_FDIR_PBALLOC_SIZE_SHIFT + pballoc)); + IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(0), + (IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(0)) - pbsize)); + + /* + * The defaults in the HW for RX PB 1-7 are not zero and so should be + * intialized to zero for non DCB mode otherwise actual total RX PB + * would be bigger than programmed and filter space would run into + * the PB 0 region. + */ + for (i = 1; i < 8; i++) + IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(i), 0); + + /* Send interrupt when 64 filters are left */ + fdirctrl |= 4 << IXGBE_FDIRCTRL_FULL_THRESH_SHIFT; + + switch (pballoc) { + case IXGBE_FDIR_PBALLOC_64K: + /* 2k - 1 perfect filters */ + fdirctrl |= IXGBE_FDIRCTRL_PBALLOC_64K; + break; + case IXGBE_FDIR_PBALLOC_128K: + /* 4k - 1 perfect filters */ + fdirctrl |= IXGBE_FDIRCTRL_PBALLOC_128K; + break; + case IXGBE_FDIR_PBALLOC_256K: + /* 8k - 1 perfect filters */ + fdirctrl |= IXGBE_FDIRCTRL_PBALLOC_256K; + break; + default: + /* bad value */ + return IXGBE_ERR_CONFIG; + }; + + /* Turn perfect match filtering on */ + fdirctrl |= IXGBE_FDIRCTRL_PERFECT_MATCH; + fdirctrl |= IXGBE_FDIRCTRL_REPORT_STATUS; + + /* Move the flexible bytes to use the ethertype - shift 6 words */ + fdirctrl |= (0x6 << IXGBE_FDIRCTRL_FLEX_SHIFT); + + /* Prime the keys for hashing */ + IXGBE_WRITE_REG(hw, IXGBE_FDIRHKEY, + htonl(IXGBE_ATR_BUCKET_HASH_KEY)); + IXGBE_WRITE_REG(hw, IXGBE_FDIRSKEY, + htonl(IXGBE_ATR_SIGNATURE_HASH_KEY)); + + /* + * Poll init-done after we write the register. Estimated times: + * 10G: PBALLOC = 11b, timing is 60us + * 1G: PBALLOC = 11b, timing is 600us + * 100M: PBALLOC = 11b, timing is 6ms + * + * Multiple these timings by 4 if under full Rx load + * + * So we'll poll for IXGBE_FDIR_INIT_DONE_POLL times, sleeping for + * 1 msec per poll time. If we're at line rate and drop to 100M, then + * this might not finish in our poll time, but we can live with that + * for now. + */ + + /* Set the maximum length per hash bucket to 0xA filters */ + fdirctrl |= (0xA << IXGBE_FDIRCTRL_MAX_LENGTH_SHIFT); + + IXGBE_WRITE_REG(hw, IXGBE_FDIRCTRL, fdirctrl); + IXGBE_WRITE_FLUSH(hw); + for (i = 0; i < IXGBE_FDIR_INIT_DONE_POLL; i++) { + if (IXGBE_READ_REG(hw, IXGBE_FDIRCTRL) & + IXGBE_FDIRCTRL_INIT_DONE) + break; + msleep(1); + } + if (i >= IXGBE_FDIR_INIT_DONE_POLL) + hw_dbg(hw, "Flow Director Perfect poll time exceeded!\n"); + + return 0; +} + + +/** + * ixgbe_atr_compute_hash_82599 - Compute the hashes for SW ATR + * @stream: input bitstream to compute the hash on + * @key: 32-bit hash key + **/ +u16 ixgbe_atr_compute_hash_82599(struct ixgbe_atr_input *atr_input, u32 key) +{ + /* + * The algorithm is as follows: + * Hash[15:0] = Sum { S[n] x K[n+16] }, n = 0...350 + * where Sum {A[n]}, n = 0...n is bitwise XOR of A[0], A[1]...A[n] + * and A[n] x B[n] is bitwise AND between same length strings + * + * K[n] is 16 bits, defined as: + * for n modulo 32 >= 15, K[n] = K[n % 32 : (n % 32) - 15] + * for n modulo 32 < 15, K[n] = + * K[(n % 32:0) | (31:31 - (14 - (n % 32)))] + * + * S[n] is 16 bits, defined as: + * for n >= 15, S[n] = S[n:n - 15] + * for n < 15, S[n] = S[(n:0) | (350:350 - (14 - n))] + * + * To simplify for programming, the algorithm is implemented + * in software this way: + * + * Key[31:0], Stream[335:0] + * + * tmp_key[11 * 32 - 1:0] = 11{Key[31:0] = key concatenated 11 times + * int_key[350:0] = tmp_key[351:1] + * int_stream[365:0] = Stream[14:0] | Stream[335:0] | Stream[335:321] + * + * hash[15:0] = 0; + * for (i = 0; i < 351; i++) { + * if (int_key[i]) + * hash ^= int_stream[(i + 15):i]; + * } + */ + + union { + u64 fill[6]; + u32 key[11]; + u8 key_stream[44]; + } tmp_key; + + u8 *stream = (u8 *)atr_input; + u8 int_key[44]; /* upper-most bit unused */ + u8 hash_str[46]; /* upper-most 2 bits unused */ + u16 hash_result = 0; + int i, j, k, h; + + /* + * Initialize the fill member to prevent warnings + * on some compilers + */ + tmp_key.fill[0] = 0; + + /* First load the temporary key stream */ + for (i = 0; i < 6; i++) { + u64 fillkey = ((u64)key << 32) | key; + tmp_key.fill[i] = fillkey; + } + + /* + * Set the interim key for the hashing. Bit 352 is unused, so we must + * shift and compensate when building the key. + */ + + int_key[0] = tmp_key.key_stream[0] >> 1; + for (i = 1, j = 0; i < 44; i++) { + unsigned int this_key = tmp_key.key_stream[j] << 7; + j++; + int_key[i] = (u8)(this_key | (tmp_key.key_stream[j] >> 1)); + } + + /* + * Set the interim bit string for the hashing. Bits 368 and 367 are + * unused, so shift and compensate when building the string. + */ + hash_str[0] = (stream[40] & 0x7f) >> 1; + for (i = 1, j = 40; i < 46; i++) { + unsigned int this_str = stream[j] << 7; + j++; + if (j > 41) + j = 0; + hash_str[i] = (u8)(this_str | (stream[j] >> 1)); + } + + /* + * Now compute the hash. i is the index into hash_str, j is into our + * key stream, k is counting the number of bits, and h interates within + * each byte. + */ + for (i = 45, j = 43, k = 0; k < 351 && i >= 2 && j >= 0; i--, j--) { + for (h = 0; h < 8 && k < 351; h++, k++) { + if (int_key[j] & (1 << h)) { + /* + * Key bit is set, XOR in the current 16-bit + * string. Example of processing: + * h = 0, + * tmp = (hash_str[i - 2] & 0 << 16) | + * (hash_str[i - 1] & 0xff << 8) | + * (hash_str[i] & 0xff >> 0) + * So tmp = hash_str[15 + k:k], since the + * i + 2 clause rolls off the 16-bit value + * h = 7, + * tmp = (hash_str[i - 2] & 0x7f << 9) | + * (hash_str[i - 1] & 0xff << 1) | + * (hash_str[i] & 0x80 >> 7) + */ + int tmp = (hash_str[i] >> h); + tmp |= (hash_str[i - 1] << (8 - h)); + tmp |= (int)(hash_str[i - 2] & ((1 << h) - 1)) + << (16 - h); + hash_result ^= (u16)tmp; + } + } + } + + return hash_result; +} + +/** + * ixgbe_atr_set_vlan_id_82599 - Sets the VLAN id in the ATR input stream + * @input: input stream to modify + * @vlan: the VLAN id to load + **/ +s32 ixgbe_atr_set_vlan_id_82599(struct ixgbe_atr_input *input, u16 vlan) +{ + input->byte_stream[IXGBE_ATR_VLAN_OFFSET + 1] = vlan >> 8; + input->byte_stream[IXGBE_ATR_VLAN_OFFSET] = vlan & 0xff; + + return 0; +} + +/** + * ixgbe_atr_set_src_ipv4_82599 - Sets the source IPv4 address + * @input: input stream to modify + * @src_addr: the IP address to load + **/ +s32 ixgbe_atr_set_src_ipv4_82599(struct ixgbe_atr_input *input, u32 src_addr) +{ + input->byte_stream[IXGBE_ATR_SRC_IPV4_OFFSET + 3] = src_addr >> 24; + input->byte_stream[IXGBE_ATR_SRC_IPV4_OFFSET + 2] = + (src_addr >> 16) & 0xff; + input->byte_stream[IXGBE_ATR_SRC_IPV4_OFFSET + 1] = + (src_addr >> 8) & 0xff; + input->byte_stream[IXGBE_ATR_SRC_IPV4_OFFSET] = src_addr & 0xff; + + return 0; +} + +/** + * ixgbe_atr_set_dst_ipv4_82599 - Sets the destination IPv4 address + * @input: input stream to modify + * @dst_addr: the IP address to load + **/ +s32 ixgbe_atr_set_dst_ipv4_82599(struct ixgbe_atr_input *input, u32 dst_addr) +{ + input->byte_stream[IXGBE_ATR_DST_IPV4_OFFSET + 3] = dst_addr >> 24; + input->byte_stream[IXGBE_ATR_DST_IPV4_OFFSET + 2] = + (dst_addr >> 16) & 0xff; + input->byte_stream[IXGBE_ATR_DST_IPV4_OFFSET + 1] = + (dst_addr >> 8) & 0xff; + input->byte_stream[IXGBE_ATR_DST_IPV4_OFFSET] = dst_addr & 0xff; + + return 0; +} + +/** + * ixgbe_atr_set_src_ipv6_82599 - Sets the source IPv6 address + * @input: input stream to modify + * @src_addr_1: the first 4 bytes of the IP address to load + * @src_addr_2: the second 4 bytes of the IP address to load + * @src_addr_3: the third 4 bytes of the IP address to load + * @src_addr_4: the fourth 4 bytes of the IP address to load + **/ +s32 ixgbe_atr_set_src_ipv6_82599(struct ixgbe_atr_input *input, + u32 src_addr_1, u32 src_addr_2, + u32 src_addr_3, u32 src_addr_4) +{ + input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET] = src_addr_4 & 0xff; + input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 1] = + (src_addr_4 >> 8) & 0xff; + input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 2] = + (src_addr_4 >> 16) & 0xff; + input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 3] = src_addr_4 >> 24; + + input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 4] = src_addr_3 & 0xff; + input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 5] = + (src_addr_3 >> 8) & 0xff; + input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 6] = + (src_addr_3 >> 16) & 0xff; + input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 7] = src_addr_3 >> 24; + + input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 8] = src_addr_2 & 0xff; + input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 9] = + (src_addr_2 >> 8) & 0xff; + input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 10] = + (src_addr_2 >> 16) & 0xff; + input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 11] = src_addr_2 >> 24; + + input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 12] = src_addr_1 & 0xff; + input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 13] = + (src_addr_1 >> 8) & 0xff; + input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 14] = + (src_addr_1 >> 16) & 0xff; + input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 15] = src_addr_1 >> 24; + + return 0; +} + +/** + * ixgbe_atr_set_dst_ipv6_82599 - Sets the destination IPv6 address + * @input: input stream to modify + * @dst_addr_1: the first 4 bytes of the IP address to load + * @dst_addr_2: the second 4 bytes of the IP address to load + * @dst_addr_3: the third 4 bytes of the IP address to load + * @dst_addr_4: the fourth 4 bytes of the IP address to load + **/ +s32 ixgbe_atr_set_dst_ipv6_82599(struct ixgbe_atr_input *input, + u32 dst_addr_1, u32 dst_addr_2, + u32 dst_addr_3, u32 dst_addr_4) +{ + input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET] = dst_addr_4 & 0xff; + input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 1] = + (dst_addr_4 >> 8) & 0xff; + input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 2] = + (dst_addr_4 >> 16) & 0xff; + input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 3] = dst_addr_4 >> 24; + + input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 4] = dst_addr_3 & 0xff; + input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 5] = + (dst_addr_3 >> 8) & 0xff; + input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 6] = + (dst_addr_3 >> 16) & 0xff; + input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 7] = dst_addr_3 >> 24; + + input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 8] = dst_addr_2 & 0xff; + input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 9] = + (dst_addr_2 >> 8) & 0xff; + input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 10] = + (dst_addr_2 >> 16) & 0xff; + input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 11] = dst_addr_2 >> 24; + + input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 12] = dst_addr_1 & 0xff; + input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 13] = + (dst_addr_1 >> 8) & 0xff; + input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 14] = + (dst_addr_1 >> 16) & 0xff; + input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 15] = dst_addr_1 >> 24; + + return 0; +} + +/** + * ixgbe_atr_set_src_port_82599 - Sets the source port + * @input: input stream to modify + * @src_port: the source port to load + **/ +s32 ixgbe_atr_set_src_port_82599(struct ixgbe_atr_input *input, u16 src_port) +{ + input->byte_stream[IXGBE_ATR_SRC_PORT_OFFSET + 1] = src_port >> 8; + input->byte_stream[IXGBE_ATR_SRC_PORT_OFFSET] = src_port & 0xff; + + return 0; +} + +/** + * ixgbe_atr_set_dst_port_82599 - Sets the destination port + * @input: input stream to modify + * @dst_port: the destination port to load + **/ +s32 ixgbe_atr_set_dst_port_82599(struct ixgbe_atr_input *input, u16 dst_port) +{ + input->byte_stream[IXGBE_ATR_DST_PORT_OFFSET + 1] = dst_port >> 8; + input->byte_stream[IXGBE_ATR_DST_PORT_OFFSET] = dst_port & 0xff; + + return 0; +} + +/** + * ixgbe_atr_set_flex_byte_82599 - Sets the flexible bytes + * @input: input stream to modify + * @flex_bytes: the flexible bytes to load + **/ +s32 ixgbe_atr_set_flex_byte_82599(struct ixgbe_atr_input *input, u16 flex_byte) +{ + input->byte_stream[IXGBE_ATR_FLEX_BYTE_OFFSET + 1] = flex_byte >> 8; + input->byte_stream[IXGBE_ATR_FLEX_BYTE_OFFSET] = flex_byte & 0xff; + + return 0; +} + +/** + * ixgbe_atr_set_vm_pool_82599 - Sets the Virtual Machine pool + * @input: input stream to modify + * @vm_pool: the Virtual Machine pool to load + **/ +s32 ixgbe_atr_set_vm_pool_82599(struct ixgbe_atr_input *input, u8 vm_pool) +{ + input->byte_stream[IXGBE_ATR_VM_POOL_OFFSET] = vm_pool; + + return 0; +} + +/** + * ixgbe_atr_set_l4type_82599 - Sets the layer 4 packet type + * @input: input stream to modify + * @l4type: the layer 4 type value to load + **/ +s32 ixgbe_atr_set_l4type_82599(struct ixgbe_atr_input *input, u8 l4type) +{ + input->byte_stream[IXGBE_ATR_L4TYPE_OFFSET] = l4type; + + return 0; +} + +/** + * ixgbe_atr_get_vlan_id_82599 - Gets the VLAN id from the ATR input stream + * @input: input stream to search + * @vlan: the VLAN id to load + **/ +s32 ixgbe_atr_get_vlan_id_82599(struct ixgbe_atr_input *input, u16 *vlan) +{ + *vlan = input->byte_stream[IXGBE_ATR_VLAN_OFFSET]; + *vlan |= input->byte_stream[IXGBE_ATR_VLAN_OFFSET + 1] << 8; + + return 0; +} + +/** + * ixgbe_atr_get_src_ipv4_82599 - Gets the source IPv4 address + * @input: input stream to search + * @src_addr: the IP address to load + **/ +s32 ixgbe_atr_get_src_ipv4_82599(struct ixgbe_atr_input *input, u32 *src_addr) +{ + *src_addr = input->byte_stream[IXGBE_ATR_SRC_IPV4_OFFSET]; + *src_addr |= input->byte_stream[IXGBE_ATR_SRC_IPV4_OFFSET + 1] << 8; + *src_addr |= input->byte_stream[IXGBE_ATR_SRC_IPV4_OFFSET + 2] << 16; + *src_addr |= input->byte_stream[IXGBE_ATR_SRC_IPV4_OFFSET + 3] << 24; + + return 0; +} + +/** + * ixgbe_atr_get_dst_ipv4_82599 - Gets the destination IPv4 address + * @input: input stream to search + * @dst_addr: the IP address to load + **/ +s32 ixgbe_atr_get_dst_ipv4_82599(struct ixgbe_atr_input *input, u32 *dst_addr) +{ + *dst_addr = input->byte_stream[IXGBE_ATR_DST_IPV4_OFFSET]; + *dst_addr |= input->byte_stream[IXGBE_ATR_DST_IPV4_OFFSET + 1] << 8; + *dst_addr |= input->byte_stream[IXGBE_ATR_DST_IPV4_OFFSET + 2] << 16; + *dst_addr |= input->byte_stream[IXGBE_ATR_DST_IPV4_OFFSET + 3] << 24; + + return 0; +} + +/** + * ixgbe_atr_get_src_ipv6_82599 - Gets the source IPv6 address + * @input: input stream to search + * @src_addr_1: the first 4 bytes of the IP address to load + * @src_addr_2: the second 4 bytes of the IP address to load + * @src_addr_3: the third 4 bytes of the IP address to load + * @src_addr_4: the fourth 4 bytes of the IP address to load + **/ +s32 ixgbe_atr_get_src_ipv6_82599(struct ixgbe_atr_input *input, + u32 *src_addr_1, u32 *src_addr_2, + u32 *src_addr_3, u32 *src_addr_4) +{ + *src_addr_1 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 12]; + *src_addr_1 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 13] << 8; + *src_addr_1 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 14] << 16; + *src_addr_1 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 15] << 24; + + *src_addr_2 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 8]; + *src_addr_2 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 9] << 8; + *src_addr_2 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 10] << 16; + *src_addr_2 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 11] << 24; + + *src_addr_3 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 4]; + *src_addr_3 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 5] << 8; + *src_addr_3 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 6] << 16; + *src_addr_3 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 7] << 24; + + *src_addr_4 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET]; + *src_addr_4 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 1] << 8; + *src_addr_4 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 2] << 16; + *src_addr_4 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 3] << 24; + + return 0; +} + +/** + * ixgbe_atr_get_dst_ipv6_82599 - Gets the destination IPv6 address + * @input: input stream to search + * @dst_addr_1: the first 4 bytes of the IP address to load + * @dst_addr_2: the second 4 bytes of the IP address to load + * @dst_addr_3: the third 4 bytes of the IP address to load + * @dst_addr_4: the fourth 4 bytes of the IP address to load + **/ +s32 ixgbe_atr_get_dst_ipv6_82599(struct ixgbe_atr_input *input, + u32 *dst_addr_1, u32 *dst_addr_2, + u32 *dst_addr_3, u32 *dst_addr_4) +{ + *dst_addr_1 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 12]; + *dst_addr_1 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 13] << 8; + *dst_addr_1 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 14] << 16; + *dst_addr_1 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 15] << 24; + + *dst_addr_2 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 8]; + *dst_addr_2 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 9] << 8; + *dst_addr_2 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 10] << 16; + *dst_addr_2 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 11] << 24; + + *dst_addr_3 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 4]; + *dst_addr_3 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 5] << 8; + *dst_addr_3 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 6] << 16; + *dst_addr_3 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 7] << 24; + + *dst_addr_4 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET]; + *dst_addr_4 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 1] << 8; + *dst_addr_4 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 2] << 16; + *dst_addr_4 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 3] << 24; + + return 0; +} + +/** + * ixgbe_atr_get_src_port_82599 - Gets the source port + * @input: input stream to modify + * @src_port: the source port to load + * + * Even though the input is given in big-endian, the FDIRPORT registers + * expect the ports to be programmed in little-endian. Hence the need to swap + * endianness when retrieving the data. This can be confusing since the + * internal hash engine expects it to be big-endian. + **/ +s32 ixgbe_atr_get_src_port_82599(struct ixgbe_atr_input *input, u16 *src_port) +{ + *src_port = input->byte_stream[IXGBE_ATR_SRC_PORT_OFFSET] << 8; + *src_port |= input->byte_stream[IXGBE_ATR_SRC_PORT_OFFSET + 1]; + + return 0; +} + +/** + * ixgbe_atr_get_dst_port_82599 - Gets the destination port + * @input: input stream to modify + * @dst_port: the destination port to load + * + * Even though the input is given in big-endian, the FDIRPORT registers + * expect the ports to be programmed in little-endian. Hence the need to swap + * endianness when retrieving the data. This can be confusing since the + * internal hash engine expects it to be big-endian. + **/ +s32 ixgbe_atr_get_dst_port_82599(struct ixgbe_atr_input *input, u16 *dst_port) +{ + *dst_port = input->byte_stream[IXGBE_ATR_DST_PORT_OFFSET] << 8; + *dst_port |= input->byte_stream[IXGBE_ATR_DST_PORT_OFFSET + 1]; + + return 0; +} + +/** + * ixgbe_atr_get_flex_byte_82599 - Gets the flexible bytes + * @input: input stream to modify + * @flex_bytes: the flexible bytes to load + **/ +s32 ixgbe_atr_get_flex_byte_82599(struct ixgbe_atr_input *input, u16 *flex_byte) +{ + *flex_byte = input->byte_stream[IXGBE_ATR_FLEX_BYTE_OFFSET]; + *flex_byte |= input->byte_stream[IXGBE_ATR_FLEX_BYTE_OFFSET + 1] << 8; + + return 0; +} + +/** + * ixgbe_atr_get_vm_pool_82599 - Gets the Virtual Machine pool + * @input: input stream to modify + * @vm_pool: the Virtual Machine pool to load + **/ +s32 ixgbe_atr_get_vm_pool_82599(struct ixgbe_atr_input *input, u8 *vm_pool) +{ + *vm_pool = input->byte_stream[IXGBE_ATR_VM_POOL_OFFSET]; + + return 0; +} + +/** + * ixgbe_atr_get_l4type_82599 - Gets the layer 4 packet type + * @input: input stream to modify + * @l4type: the layer 4 type value to load + **/ +s32 ixgbe_atr_get_l4type_82599(struct ixgbe_atr_input *input, u8 *l4type) +{ + *l4type = input->byte_stream[IXGBE_ATR_L4TYPE_OFFSET]; + + return 0; +} + +/** + * ixgbe_atr_add_signature_filter_82599 - Adds a signature hash filter + * @hw: pointer to hardware structure + * @stream: input bitstream + * @queue: queue index to direct traffic to + **/ +s32 ixgbe_fdir_add_signature_filter_82599(struct ixgbe_hw *hw, + struct ixgbe_atr_input *input, + u8 queue) +{ + u64 fdirhashcmd; + u64 fdircmd; + u32 fdirhash; + u16 bucket_hash, sig_hash; + u8 l4type; + + bucket_hash = ixgbe_atr_compute_hash_82599(input, + IXGBE_ATR_BUCKET_HASH_KEY); + + /* bucket_hash is only 15 bits */ + bucket_hash &= IXGBE_ATR_HASH_MASK; + + sig_hash = ixgbe_atr_compute_hash_82599(input, + IXGBE_ATR_SIGNATURE_HASH_KEY); + + /* Get the l4type in order to program FDIRCMD properly */ + /* lowest 2 bits are FDIRCMD.L4TYPE, third lowest bit is FDIRCMD.IPV6 */ + ixgbe_atr_get_l4type_82599(input, &l4type); + + /* + * The lower 32-bits of fdirhashcmd is for FDIRHASH, the upper 32-bits + * is for FDIRCMD. Then do a 64-bit register write from FDIRHASH. + */ + fdirhash = sig_hash << IXGBE_FDIRHASH_SIG_SW_INDEX_SHIFT | bucket_hash; + + fdircmd = (IXGBE_FDIRCMD_CMD_ADD_FLOW | IXGBE_FDIRCMD_FILTER_UPDATE | + IXGBE_FDIRCMD_LAST | IXGBE_FDIRCMD_QUEUE_EN); + + switch (l4type & IXGBE_ATR_L4TYPE_MASK) { + case IXGBE_ATR_L4TYPE_TCP: + fdircmd |= IXGBE_FDIRCMD_L4TYPE_TCP; + break; + case IXGBE_ATR_L4TYPE_UDP: + fdircmd |= IXGBE_FDIRCMD_L4TYPE_UDP; + break; + case IXGBE_ATR_L4TYPE_SCTP: + fdircmd |= IXGBE_FDIRCMD_L4TYPE_SCTP; + break; + default: + hw_dbg(hw, "Error on l4type input\n"); + return IXGBE_ERR_CONFIG; + } + + if (l4type & IXGBE_ATR_L4TYPE_IPV6_MASK) + fdircmd |= IXGBE_FDIRCMD_IPV6; + + fdircmd |= ((u64)queue << IXGBE_FDIRCMD_RX_QUEUE_SHIFT); + fdirhashcmd = ((fdircmd << 32) | fdirhash); + + IXGBE_WRITE_REG64(hw, IXGBE_FDIRHASH, fdirhashcmd); + + return 0; +} + +/** + * ixgbe_fdir_add_perfect_filter_82599 - Adds a perfect filter + * @hw: pointer to hardware structure + * @input: input bitstream + * @queue: queue index to direct traffic to + * + * Note that the caller to this function must lock before calling, since the + * hardware writes must be protected from one another. + **/ +s32 ixgbe_fdir_add_perfect_filter_82599(struct ixgbe_hw *hw, + struct ixgbe_atr_input *input, + u16 soft_id, + u8 queue) +{ + u32 fdircmd = 0; + u32 fdirhash; + u32 src_ipv4, dst_ipv4; + u32 src_ipv6_1, src_ipv6_2, src_ipv6_3, src_ipv6_4; + u16 src_port, dst_port, vlan_id, flex_bytes; + u16 bucket_hash; + u8 l4type; + + /* Get our input values */ + ixgbe_atr_get_l4type_82599(input, &l4type); + + /* + * Check l4type formatting, and bail out before we touch the hardware + * if there's a configuration issue + */ + switch (l4type & IXGBE_ATR_L4TYPE_MASK) { + case IXGBE_ATR_L4TYPE_TCP: + fdircmd |= IXGBE_FDIRCMD_L4TYPE_TCP; + break; + case IXGBE_ATR_L4TYPE_UDP: + fdircmd |= IXGBE_FDIRCMD_L4TYPE_UDP; + break; + case IXGBE_ATR_L4TYPE_SCTP: + fdircmd |= IXGBE_FDIRCMD_L4TYPE_SCTP; + break; + default: + hw_dbg(hw, "Error on l4type input\n"); + return IXGBE_ERR_CONFIG; + } + + bucket_hash = ixgbe_atr_compute_hash_82599(input, + IXGBE_ATR_BUCKET_HASH_KEY); + + /* bucket_hash is only 15 bits */ + bucket_hash &= IXGBE_ATR_HASH_MASK; + + ixgbe_atr_get_vlan_id_82599(input, &vlan_id); + ixgbe_atr_get_src_port_82599(input, &src_port); + ixgbe_atr_get_dst_port_82599(input, &dst_port); + ixgbe_atr_get_flex_byte_82599(input, &flex_bytes); + + fdirhash = soft_id << IXGBE_FDIRHASH_SIG_SW_INDEX_SHIFT | bucket_hash; + + /* Now figure out if we're IPv4 or IPv6 */ + if (l4type & IXGBE_ATR_L4TYPE_IPV6_MASK) { + /* IPv6 */ + ixgbe_atr_get_src_ipv6_82599(input, &src_ipv6_1, &src_ipv6_2, + &src_ipv6_3, &src_ipv6_4); + + IXGBE_WRITE_REG(hw, IXGBE_FDIRSIPv6(0), src_ipv6_1); + IXGBE_WRITE_REG(hw, IXGBE_FDIRSIPv6(1), src_ipv6_2); + IXGBE_WRITE_REG(hw, IXGBE_FDIRSIPv6(2), src_ipv6_3); + /* The last 4 bytes is the same register as IPv4 */ + IXGBE_WRITE_REG(hw, IXGBE_FDIRIPSA, src_ipv6_4); + + fdircmd |= IXGBE_FDIRCMD_IPV6; + fdircmd |= IXGBE_FDIRCMD_IPv6DMATCH; + } else { + /* IPv4 */ + ixgbe_atr_get_src_ipv4_82599(input, &src_ipv4); + IXGBE_WRITE_REG(hw, IXGBE_FDIRIPSA, src_ipv4); + + } + + ixgbe_atr_get_dst_ipv4_82599(input, &dst_ipv4); + IXGBE_WRITE_REG(hw, IXGBE_FDIRIPDA, dst_ipv4); + + IXGBE_WRITE_REG(hw, IXGBE_FDIRVLAN, (vlan_id | + (flex_bytes << IXGBE_FDIRVLAN_FLEX_SHIFT))); + IXGBE_WRITE_REG(hw, IXGBE_FDIRPORT, (src_port | + (dst_port << IXGBE_FDIRPORT_DESTINATION_SHIFT))); + + fdircmd |= IXGBE_FDIRCMD_CMD_ADD_FLOW; + fdircmd |= IXGBE_FDIRCMD_FILTER_UPDATE; + fdircmd |= IXGBE_FDIRCMD_LAST; + fdircmd |= IXGBE_FDIRCMD_QUEUE_EN; + fdircmd |= queue << IXGBE_FDIRCMD_RX_QUEUE_SHIFT; + + IXGBE_WRITE_REG(hw, IXGBE_FDIRHASH, fdirhash); + IXGBE_WRITE_REG(hw, IXGBE_FDIRCMD, fdircmd); + + return 0; +} /** * ixgbe_read_analog_reg8_82599 - Reads 8 bit Omer analog register * @hw: pointer to hardware structure @@ -1056,8 +2142,9 @@ s32 ixgbe_write_analog_reg8_82599(struct ixgbe_hw *hw, u32 reg, u8 val) s32 ixgbe_start_hw_82599(struct ixgbe_hw *hw) { u32 q_num; + s32 ret_val; - ixgbe_start_hw_generic(hw); + ret_val = ixgbe_start_hw_generic(hw); /* Clear the rate limiters */ for (q_num = 0; q_num < hw->mac.max_tx_queues; q_num++) { @@ -1066,7 +2153,13 @@ s32 ixgbe_start_hw_82599(struct ixgbe_hw *hw) } IXGBE_WRITE_FLUSH(hw); - return 0; + /* We need to run link autotry after the driver loads */ + hw->mac.autotry_restart = true; + + if (ret_val == 0) + ret_val = ixgbe_verify_fw_version_82599(hw); + + return ret_val; } /** @@ -1093,53 +2186,100 @@ s32 ixgbe_identify_phy_82599(struct ixgbe_hw *hw) u32 ixgbe_get_supported_physical_layer_82599(struct ixgbe_hw *hw) { u32 physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN; + u32 autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC); + u32 autoc2 = IXGBE_READ_REG(hw, IXGBE_AUTOC2); + u32 pma_pmd_10g_serial = autoc2 & IXGBE_AUTOC2_10G_SERIAL_PMA_PMD_MASK; + u32 pma_pmd_10g_parallel = autoc & IXGBE_AUTOC_10G_PMA_PMD_MASK; + u32 pma_pmd_1g = autoc & IXGBE_AUTOC_1G_PMA_PMD_MASK; + u16 ext_ability = 0; u8 comp_codes_10g = 0; - switch (hw->device_id) { - case IXGBE_DEV_ID_82599: - case IXGBE_DEV_ID_82599_KX4: - /* Default device ID is mezzanine card KX/KX4 */ - physical_layer = (IXGBE_PHYSICAL_LAYER_10GBASE_KX4 | - IXGBE_PHYSICAL_LAYER_1000BASE_KX); - break; - case IXGBE_DEV_ID_82599_SFP: - hw->phy.ops.identify_sfp(hw); + hw->phy.ops.identify(hw); - switch (hw->phy.sfp_type) { - case ixgbe_sfp_type_da_cu: - case ixgbe_sfp_type_da_cu_core0: - case ixgbe_sfp_type_da_cu_core1: - physical_layer = IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU; - break; - case ixgbe_sfp_type_sr: - physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_SR; - break; - case ixgbe_sfp_type_lr: - physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_LR; - break; - case ixgbe_sfp_type_srlr_core0: - case ixgbe_sfp_type_srlr_core1: - hw->phy.ops.read_i2c_eeprom(hw, - IXGBE_SFF_10GBE_COMP_CODES, - &comp_codes_10g); - if (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE) - physical_layer = - IXGBE_PHYSICAL_LAYER_10GBASE_SR; - else if (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE) - physical_layer = - IXGBE_PHYSICAL_LAYER_10GBASE_LR; - else - physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN; - default: - physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN; - break; - } + if (hw->phy.type == ixgbe_phy_tn || + hw->phy.type == ixgbe_phy_cu_unknown) { + hw->phy.ops.read_reg(hw, MDIO_PMA_EXTABLE, MDIO_MMD_PMAPMD, + &ext_ability); + if (ext_ability & MDIO_PMA_EXTABLE_10GBT) + physical_layer |= IXGBE_PHYSICAL_LAYER_10GBASE_T; + if (ext_ability & MDIO_PMA_EXTABLE_1000BT) + physical_layer |= IXGBE_PHYSICAL_LAYER_1000BASE_T; + if (ext_ability & MDIO_PMA_EXTABLE_100BTX) + physical_layer |= IXGBE_PHYSICAL_LAYER_100BASE_TX; + goto out; + } + + switch (autoc & IXGBE_AUTOC_LMS_MASK) { + case IXGBE_AUTOC_LMS_1G_AN: + case IXGBE_AUTOC_LMS_1G_LINK_NO_AN: + if (pma_pmd_1g == IXGBE_AUTOC_1G_KX_BX) { + physical_layer = IXGBE_PHYSICAL_LAYER_1000BASE_KX | + IXGBE_PHYSICAL_LAYER_1000BASE_BX; + goto out; + } else + /* SFI mode so read SFP module */ + goto sfp_check; + break; + case IXGBE_AUTOC_LMS_10G_LINK_NO_AN: + if (pma_pmd_10g_parallel == IXGBE_AUTOC_10G_CX4) + physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_CX4; + else if (pma_pmd_10g_parallel == IXGBE_AUTOC_10G_KX4) + physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_KX4; + else if (pma_pmd_10g_parallel == IXGBE_AUTOC_10G_XAUI) + physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_XAUI; + goto out; + break; + case IXGBE_AUTOC_LMS_10G_SERIAL: + if (pma_pmd_10g_serial == IXGBE_AUTOC2_10G_KR) { + physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_KR; + goto out; + } else if (pma_pmd_10g_serial == IXGBE_AUTOC2_10G_SFI) + goto sfp_check; + break; + case IXGBE_AUTOC_LMS_KX4_KX_KR: + case IXGBE_AUTOC_LMS_KX4_KX_KR_1G_AN: + if (autoc & IXGBE_AUTOC_KX_SUPP) + physical_layer |= IXGBE_PHYSICAL_LAYER_1000BASE_KX; + if (autoc & IXGBE_AUTOC_KX4_SUPP) + physical_layer |= IXGBE_PHYSICAL_LAYER_10GBASE_KX4; + if (autoc & IXGBE_AUTOC_KR_SUPP) + physical_layer |= IXGBE_PHYSICAL_LAYER_10GBASE_KR; + goto out; break; default: - physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN; + goto out; break; } +sfp_check: + /* SFP check must be done last since DA modules are sometimes used to + * test KR mode - we need to id KR mode correctly before SFP module. + * Call identify_sfp because the pluggable module may have changed */ + hw->phy.ops.identify_sfp(hw); + if (hw->phy.sfp_type == ixgbe_sfp_type_not_present) + goto out; + + switch (hw->phy.type) { + case ixgbe_phy_tw_tyco: + case ixgbe_phy_tw_unknown: + physical_layer = IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU; + break; + case ixgbe_phy_sfp_avago: + case ixgbe_phy_sfp_ftl: + case ixgbe_phy_sfp_intel: + case ixgbe_phy_sfp_unknown: + hw->phy.ops.read_i2c_eeprom(hw, + IXGBE_SFF_10GBE_COMP_CODES, &comp_codes_10g); + if (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE) + physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_SR; + else if (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE) + physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_LR; + break; + default: + break; + } + +out: return physical_layer; } @@ -1187,6 +2327,138 @@ s32 ixgbe_enable_rx_dma_82599(struct ixgbe_hw *hw, u32 regval) return 0; } +/** + * ixgbe_get_device_caps_82599 - Get additional device capabilities + * @hw: pointer to hardware structure + * @device_caps: the EEPROM word with the extra device capabilities + * + * This function will read the EEPROM location for the device capabilities, + * and return the word through device_caps. + **/ +s32 ixgbe_get_device_caps_82599(struct ixgbe_hw *hw, u16 *device_caps) +{ + hw->eeprom.ops.read(hw, IXGBE_DEVICE_CAPS, device_caps); + + return 0; +} + +/** + * ixgbe_get_san_mac_addr_offset_82599 - SAN MAC address offset for 82599 + * @hw: pointer to hardware structure + * @san_mac_offset: SAN MAC address offset + * + * This function will read the EEPROM location for the SAN MAC address + * pointer, and returns the value at that location. This is used in both + * get and set mac_addr routines. + **/ +s32 ixgbe_get_san_mac_addr_offset_82599(struct ixgbe_hw *hw, + u16 *san_mac_offset) +{ + /* + * First read the EEPROM pointer to see if the MAC addresses are + * available. + */ + hw->eeprom.ops.read(hw, IXGBE_SAN_MAC_ADDR_PTR, san_mac_offset); + + return 0; +} + +/** + * ixgbe_get_san_mac_addr_82599 - SAN MAC address retrieval for 82599 + * @hw: pointer to hardware structure + * @san_mac_addr: SAN MAC address + * + * Reads the SAN MAC address from the EEPROM, if it's available. This is + * per-port, so set_lan_id() must be called before reading the addresses. + * set_lan_id() is called by identify_sfp(), but this cannot be relied + * upon for non-SFP connections, so we must call it here. + **/ +s32 ixgbe_get_san_mac_addr_82599(struct ixgbe_hw *hw, u8 *san_mac_addr) +{ + u16 san_mac_data, san_mac_offset; + u8 i; + + /* + * First read the EEPROM pointer to see if the MAC addresses are + * available. If they're not, no point in calling set_lan_id() here. + */ + ixgbe_get_san_mac_addr_offset_82599(hw, &san_mac_offset); + + if ((san_mac_offset == 0) || (san_mac_offset == 0xFFFF)) { + /* + * No addresses available in this EEPROM. It's not an + * error though, so just wipe the local address and return. + */ + for (i = 0; i < 6; i++) + san_mac_addr[i] = 0xFF; + + goto san_mac_addr_out; + } + + /* make sure we know which port we need to program */ + hw->mac.ops.set_lan_id(hw); + /* apply the port offset to the address offset */ + (hw->bus.func) ? (san_mac_offset += IXGBE_SAN_MAC_ADDR_PORT1_OFFSET) : + (san_mac_offset += IXGBE_SAN_MAC_ADDR_PORT0_OFFSET); + for (i = 0; i < 3; i++) { + hw->eeprom.ops.read(hw, san_mac_offset, &san_mac_data); + san_mac_addr[i * 2] = (u8)(san_mac_data); + san_mac_addr[i * 2 + 1] = (u8)(san_mac_data >> 8); + san_mac_offset++; + } + +san_mac_addr_out: + return 0; +} + +/** + * ixgbe_verify_fw_version_82599 - verify fw version for 82599 + * @hw: pointer to hardware structure + * + * Verifies that installed the firmware version is 0.6 or higher + * for SFI devices. All 82599 SFI devices should have version 0.6 or higher. + * + * Returns IXGBE_ERR_EEPROM_VERSION if the FW is not present or + * if the FW version is not supported. + **/ +static s32 ixgbe_verify_fw_version_82599(struct ixgbe_hw *hw) +{ + s32 status = IXGBE_ERR_EEPROM_VERSION; + u16 fw_offset, fw_ptp_cfg_offset; + u16 fw_version = 0; + + /* firmware check is only necessary for SFI devices */ + if (hw->phy.media_type != ixgbe_media_type_fiber) { + status = 0; + goto fw_version_out; + } + + /* get the offset to the Firmware Module block */ + hw->eeprom.ops.read(hw, IXGBE_FW_PTR, &fw_offset); + + if ((fw_offset == 0) || (fw_offset == 0xFFFF)) + goto fw_version_out; + + /* get the offset to the Pass Through Patch Configuration block */ + hw->eeprom.ops.read(hw, (fw_offset + + IXGBE_FW_PASSTHROUGH_PATCH_CONFIG_PTR), + &fw_ptp_cfg_offset); + + if ((fw_ptp_cfg_offset == 0) || (fw_ptp_cfg_offset == 0xFFFF)) + goto fw_version_out; + + /* get the firmware version */ + hw->eeprom.ops.read(hw, (fw_ptp_cfg_offset + + IXGBE_FW_PATCH_VERSION_4), + &fw_version); + + if (fw_version > 0x5) + status = 0; + +fw_version_out: + return status; +} + static struct ixgbe_mac_operations mac_ops_82599 = { .init_hw = &ixgbe_init_hw_generic, .reset_hw = &ixgbe_reset_hw_82599, @@ -1196,6 +2468,8 @@ static struct ixgbe_mac_operations mac_ops_82599 = { .get_supported_physical_layer = &ixgbe_get_supported_physical_layer_82599, .enable_rx_dma = &ixgbe_enable_rx_dma_82599, .get_mac_addr = &ixgbe_get_mac_addr_generic, + .get_san_mac_addr = &ixgbe_get_san_mac_addr_82599, + .get_device_caps = &ixgbe_get_device_caps_82599, .stop_adapter = &ixgbe_stop_adapter_generic, .get_bus_info = &ixgbe_get_bus_info_generic, .set_lan_id = &ixgbe_set_lan_id_multi_port_pcie, @@ -1220,7 +2494,7 @@ static struct ixgbe_mac_operations mac_ops_82599 = { .disable_mc = &ixgbe_disable_mc_generic, .clear_vfta = &ixgbe_clear_vfta_82599, .set_vfta = &ixgbe_set_vfta_82599, - .setup_fc = &ixgbe_setup_fc_generic, + .fc_enable = &ixgbe_fc_enable_generic, .init_uta_tables = &ixgbe_init_uta_tables_82599, .setup_sfp = &ixgbe_setup_sfp_modules_82599, }; @@ -1236,6 +2510,7 @@ static struct ixgbe_eeprom_operations eeprom_ops_82599 = { static struct ixgbe_phy_operations phy_ops_82599 = { .identify = &ixgbe_identify_phy_82599, .identify_sfp = &ixgbe_identify_sfp_module_generic, + .init = &ixgbe_init_phy_ops_82599, .reset = &ixgbe_reset_phy_generic, .read_reg = &ixgbe_read_phy_reg_generic, .write_reg = &ixgbe_write_phy_reg_generic, diff --git a/drivers/net/ixgbe/ixgbe_common.c b/drivers/net/ixgbe/ixgbe_common.c index 186a65069b33..96a185953777 100644 --- a/drivers/net/ixgbe/ixgbe_common.c +++ b/drivers/net/ixgbe/ixgbe_common.c @@ -28,6 +28,8 @@ #include #include #include +#include +#include #include "ixgbe.h" #include "ixgbe_common.h" @@ -71,12 +73,6 @@ s32 ixgbe_start_hw_generic(struct ixgbe_hw *hw) /* Identify the PHY */ hw->phy.ops.identify(hw); - /* - * Store MAC address from RAR0, clear receive address registers, and - * clear the multicast table - */ - hw->mac.ops.init_rx_addrs(hw); - /* Clear the VLAN filter table */ hw->mac.ops.clear_vfta(hw); @@ -89,6 +85,9 @@ s32 ixgbe_start_hw_generic(struct ixgbe_hw *hw) IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext); IXGBE_WRITE_FLUSH(hw); + /* Setup flow control */ + ixgbe_setup_fc(hw, 0); + /* Clear adapter stopped flag */ hw->adapter_stopped = false; @@ -107,13 +106,17 @@ s32 ixgbe_start_hw_generic(struct ixgbe_hw *hw) **/ s32 ixgbe_init_hw_generic(struct ixgbe_hw *hw) { + s32 status; + /* Reset the hardware */ - hw->mac.ops.reset_hw(hw); + status = hw->mac.ops.reset_hw(hw); - /* Start the HW */ - hw->mac.ops.start_hw(hw); + if (status == 0) { + /* Start the HW */ + status = hw->mac.ops.start_hw(hw); + } - return 0; + return status; } /** @@ -1362,15 +1365,14 @@ static void ixgbe_add_uc_addr(struct ixgbe_hw *hw, u8 *addr, u32 vmdq) * Drivers using secondary unicast addresses must set user_set_promisc when * manually putting the device into promiscuous mode. **/ -s32 ixgbe_update_uc_addr_list_generic(struct ixgbe_hw *hw, u8 *addr_list, - u32 addr_count, ixgbe_mc_addr_itr next) +s32 ixgbe_update_uc_addr_list_generic(struct ixgbe_hw *hw, + struct list_head *uc_list) { - u8 *addr; u32 i; u32 old_promisc_setting = hw->addr_ctrl.overflow_promisc; u32 uc_addr_in_use; u32 fctrl; - u32 vmdq; + struct netdev_hw_addr *ha; /* * Clear accounting of old secondary address list, @@ -1388,10 +1390,9 @@ s32 ixgbe_update_uc_addr_list_generic(struct ixgbe_hw *hw, u8 *addr_list, } /* Add the new addresses */ - for (i = 0; i < addr_count; i++) { + list_for_each_entry(ha, uc_list, list) { hw_dbg(hw, " Adding the secondary addresses:\n"); - addr = next(hw, &addr_list, &vmdq); - ixgbe_add_uc_addr(hw, addr, vmdq); + ixgbe_add_uc_addr(hw, ha->addr, 0); } if (hw->addr_ctrl.overflow_promisc) { @@ -1583,19 +1584,30 @@ s32 ixgbe_disable_mc_generic(struct ixgbe_hw *hw) } /** - * ixgbe_fc_enable - Enable flow control + * ixgbe_fc_enable_generic - Enable flow control * @hw: pointer to hardware structure * @packetbuf_num: packet buffer number (0-7) * * Enable flow control according to the current settings. **/ -s32 ixgbe_fc_enable(struct ixgbe_hw *hw, s32 packetbuf_num) +s32 ixgbe_fc_enable_generic(struct ixgbe_hw *hw, s32 packetbuf_num) { s32 ret_val = 0; - u32 mflcn_reg; - u32 fccfg_reg; + u32 mflcn_reg, fccfg_reg; u32 reg; + u32 rx_pba_size; +#ifdef CONFIG_DCB + if (hw->fc.requested_mode == ixgbe_fc_pfc) + goto out; + +#endif /* CONFIG_DCB */ + /* Negotiate the fc mode to use */ + ret_val = ixgbe_fc_autoneg(hw); + if (ret_val) + goto out; + + /* Disable any previous flow control settings */ mflcn_reg = IXGBE_READ_REG(hw, IXGBE_MFLCN); mflcn_reg &= ~(IXGBE_MFLCN_RFCE | IXGBE_MFLCN_RPFCE); @@ -1615,7 +1627,10 @@ s32 ixgbe_fc_enable(struct ixgbe_hw *hw, s32 packetbuf_num) */ switch (hw->fc.current_mode) { case ixgbe_fc_none: - /* Flow control completely disabled by software override. */ + /* + * Flow control is disabled by software override or autoneg. + * The code below will actually disable it in the HW. + */ break; case ixgbe_fc_rx_pause: /* @@ -1644,7 +1659,7 @@ s32 ixgbe_fc_enable(struct ixgbe_hw *hw, s32 packetbuf_num) case ixgbe_fc_pfc: goto out; break; -#endif +#endif /* CONFIG_DCB */ default: hw_dbg(hw, "Flow control param set incorrectly\n"); ret_val = -IXGBE_ERR_CONFIG; @@ -1652,25 +1667,48 @@ s32 ixgbe_fc_enable(struct ixgbe_hw *hw, s32 packetbuf_num) break; } - /* Enable 802.3x based flow control settings. */ + /* Set 802.3x based flow control settings. */ + mflcn_reg |= IXGBE_MFLCN_DPF; IXGBE_WRITE_REG(hw, IXGBE_MFLCN, mflcn_reg); IXGBE_WRITE_REG(hw, IXGBE_FCCFG, fccfg_reg); - /* Set up and enable Rx high/low water mark thresholds, enable XON. */ - if (hw->fc.current_mode & ixgbe_fc_tx_pause) { - if (hw->fc.send_xon) - IXGBE_WRITE_REG(hw, IXGBE_FCRTL_82599(packetbuf_num), - (hw->fc.low_water | IXGBE_FCRTL_XONE)); - else - IXGBE_WRITE_REG(hw, IXGBE_FCRTL_82599(packetbuf_num), - hw->fc.low_water); + reg = IXGBE_READ_REG(hw, IXGBE_MTQC); + /* Thresholds are different for link flow control when in DCB mode */ + if (reg & IXGBE_MTQC_RT_ENA) { + rx_pba_size = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(packetbuf_num)); - IXGBE_WRITE_REG(hw, IXGBE_FCRTH_82599(packetbuf_num), - (hw->fc.high_water | IXGBE_FCRTH_FCEN)); + /* Always disable XON for LFC when in DCB mode */ + reg = (rx_pba_size >> 5) & 0xFFE0; + IXGBE_WRITE_REG(hw, IXGBE_FCRTL_82599(packetbuf_num), reg); + + reg = (rx_pba_size >> 2) & 0xFFE0; + if (hw->fc.current_mode & ixgbe_fc_tx_pause) + reg |= IXGBE_FCRTH_FCEN; + IXGBE_WRITE_REG(hw, IXGBE_FCRTH_82599(packetbuf_num), reg); + } else { + /* + * Set up and enable Rx high/low water mark thresholds, + * enable XON. + */ + if (hw->fc.current_mode & ixgbe_fc_tx_pause) { + if (hw->fc.send_xon) { + IXGBE_WRITE_REG(hw, + IXGBE_FCRTL_82599(packetbuf_num), + (hw->fc.low_water | + IXGBE_FCRTL_XONE)); + } else { + IXGBE_WRITE_REG(hw, + IXGBE_FCRTL_82599(packetbuf_num), + hw->fc.low_water); + } + + IXGBE_WRITE_REG(hw, IXGBE_FCRTH_82599(packetbuf_num), + (hw->fc.high_water | IXGBE_FCRTH_FCEN)); + } } /* Configure pause time (2 TCs per register) */ - reg = IXGBE_READ_REG(hw, IXGBE_FCTTV(packetbuf_num)); + reg = IXGBE_READ_REG(hw, IXGBE_FCTTV(packetbuf_num / 2)); if ((packetbuf_num & 1) == 0) reg = (reg & 0xFFFF0000) | hw->fc.pause_time; else @@ -1687,100 +1725,41 @@ out: * ixgbe_fc_autoneg - Configure flow control * @hw: pointer to hardware structure * - * Negotiates flow control capabilities with link partner using autoneg and - * applies the results. + * Compares our advertised flow control capabilities to those advertised by + * our link partner, and determines the proper flow control mode to use. **/ s32 ixgbe_fc_autoneg(struct ixgbe_hw *hw) { s32 ret_val = 0; - u32 i, reg, pcs_anadv_reg, pcs_lpab_reg; - - reg = IXGBE_READ_REG(hw, IXGBE_PCS1GANA); + ixgbe_link_speed speed; + u32 pcs_anadv_reg, pcs_lpab_reg, linkstat; + bool link_up; /* - * The possible values of fc.current_mode are: - * 0: Flow control is completely disabled - * 1: Rx flow control is enabled (we can receive pause frames, - * but not send pause frames). - * 2: Tx flow control is enabled (we can send pause frames but - * we do not support receiving pause frames). - * 3: Both Rx and Tx flow control (symmetric) are enabled. - * 4: Priority Flow Control is enabled. - * other: Invalid. + * AN should have completed when the cable was plugged in. + * Look for reasons to bail out. Bail out if: + * - FC autoneg is disabled, or if + * - we don't have multispeed fiber, or if + * - we're not running at 1G, or if + * - link is not up, or if + * - link is up but AN did not complete, or if + * - link is up and AN completed but timed out + * + * Since we're being called from an LSC, link is already know to be up. + * So use link_up_wait_to_complete=false. */ - switch (hw->fc.current_mode) { - case ixgbe_fc_none: - /* Flow control completely disabled by software override. */ - reg &= ~(IXGBE_PCS1GANA_SYM_PAUSE | IXGBE_PCS1GANA_ASM_PAUSE); - break; - case ixgbe_fc_rx_pause: - /* - * Rx Flow control is enabled and Tx Flow control is - * disabled by software override. Since there really - * isn't a way to advertise that we are capable of RX - * Pause ONLY, we will advertise that we support both - * symmetric and asymmetric Rx PAUSE. Later, we will - * disable the adapter's ability to send PAUSE frames. - */ - reg |= (IXGBE_PCS1GANA_SYM_PAUSE | IXGBE_PCS1GANA_ASM_PAUSE); - break; - case ixgbe_fc_tx_pause: - /* - * Tx Flow control is enabled, and Rx Flow control is - * disabled by software override. - */ - reg |= (IXGBE_PCS1GANA_ASM_PAUSE); - reg &= ~(IXGBE_PCS1GANA_SYM_PAUSE); - break; - case ixgbe_fc_full: - /* Flow control (both Rx and Tx) is enabled by SW override. */ - reg |= (IXGBE_PCS1GANA_SYM_PAUSE | IXGBE_PCS1GANA_ASM_PAUSE); - break; -#ifdef CONFIG_DCB - case ixgbe_fc_pfc: - goto out; - break; -#endif - default: - hw_dbg(hw, "Flow control param set incorrectly\n"); - ret_val = -IXGBE_ERR_CONFIG; - goto out; - break; - } + hw->mac.ops.check_link(hw, &speed, &link_up, false); + linkstat = IXGBE_READ_REG(hw, IXGBE_PCS1GLSTA); - IXGBE_WRITE_REG(hw, IXGBE_PCS1GANA, reg); - reg = IXGBE_READ_REG(hw, IXGBE_PCS1GLCTL); - - /* Set PCS register for autoneg */ - /* Enable and restart autoneg */ - reg |= IXGBE_PCS1GLCTL_AN_ENABLE | IXGBE_PCS1GLCTL_AN_RESTART; - - /* Disable AN timeout */ - if (hw->fc.strict_ieee) - reg &= ~IXGBE_PCS1GLCTL_AN_1G_TIMEOUT_EN; - - hw_dbg(hw, "Configuring Autoneg; PCS_LCTL = 0x%08X\n", reg); - IXGBE_WRITE_REG(hw, IXGBE_PCS1GLCTL, reg); - - /* See if autonegotiation has succeeded */ - hw->mac.autoneg_succeeded = 0; - for (i = 0; i < FIBER_LINK_UP_LIMIT; i++) { - msleep(10); - reg = IXGBE_READ_REG(hw, IXGBE_PCS1GLSTA); - if ((reg & (IXGBE_PCS1GLSTA_LINK_OK | - IXGBE_PCS1GLSTA_AN_COMPLETE)) == - (IXGBE_PCS1GLSTA_LINK_OK | - IXGBE_PCS1GLSTA_AN_COMPLETE)) { - if (!(reg & IXGBE_PCS1GLSTA_AN_TIMED_OUT)) - hw->mac.autoneg_succeeded = 1; - break; - } - } - - if (!hw->mac.autoneg_succeeded) { - /* Autoneg failed to achieve a link, so we turn fc off */ - hw->fc.current_mode = ixgbe_fc_none; - hw_dbg(hw, "Flow Control = NONE.\n"); + if (hw->fc.disable_fc_autoneg || + !hw->phy.multispeed_fiber || + (speed != IXGBE_LINK_SPEED_1GB_FULL) || + !link_up || + ((linkstat & IXGBE_PCS1GLSTA_AN_COMPLETE) == 0) || + ((linkstat & IXGBE_PCS1GLSTA_AN_TIMED_OUT) == 1)) { + hw->fc.fc_was_autonegged = false; + hw->fc.current_mode = hw->fc.requested_mode; + hw_dbg(hw, "Autoneg FC was skipped.\n"); goto out; } @@ -1823,21 +1802,23 @@ s32 ixgbe_fc_autoneg(struct ixgbe_hw *hw) hw_dbg(hw, "Flow Control = NONE.\n"); } + /* Record that current_mode is the result of a successful autoneg */ + hw->fc.fc_was_autonegged = true; + out: return ret_val; } /** - * ixgbe_setup_fc_generic - Set up flow control + * ixgbe_setup_fc - Set up flow control * @hw: pointer to hardware structure * - * Sets up flow control. + * Called at init time to set up flow control. **/ -s32 ixgbe_setup_fc_generic(struct ixgbe_hw *hw, s32 packetbuf_num) +s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packetbuf_num) { s32 ret_val = 0; - ixgbe_link_speed speed; - bool link_up; + u32 reg; #ifdef CONFIG_DCB if (hw->fc.requested_mode == ixgbe_fc_pfc) { @@ -1866,7 +1847,7 @@ s32 ixgbe_setup_fc_generic(struct ixgbe_hw *hw, s32 packetbuf_num) /* * Validate the requested mode. Strict IEEE mode does not allow - * ixgbe_fc_rx_pause because it will cause testing anomalies. + * ixgbe_fc_rx_pause because it will cause us to fail at UNH. */ if (hw->fc.strict_ieee && hw->fc.requested_mode == ixgbe_fc_rx_pause) { hw_dbg(hw, "ixgbe_fc_rx_pause not valid in strict " @@ -1883,21 +1864,77 @@ s32 ixgbe_setup_fc_generic(struct ixgbe_hw *hw, s32 packetbuf_num) hw->fc.requested_mode = ixgbe_fc_full; /* - * Save off the requested flow control mode for use later. Depending - * on the link partner's capabilities, we may or may not use this mode. + * Set up the 1G flow control advertisement registers so the HW will be + * able to do fc autoneg once the cable is plugged in. If we end up + * using 10g instead, this is harmless. */ - hw->fc.current_mode = hw->fc.requested_mode; + reg = IXGBE_READ_REG(hw, IXGBE_PCS1GANA); - /* Decide whether to use autoneg or not. */ - hw->mac.ops.check_link(hw, &speed, &link_up, false); - if (!hw->fc.disable_fc_autoneg && hw->phy.multispeed_fiber && - (speed == IXGBE_LINK_SPEED_1GB_FULL)) - ret_val = ixgbe_fc_autoneg(hw); - - if (ret_val) + /* + * The possible values of fc.requested_mode are: + * 0: Flow control is completely disabled + * 1: Rx flow control is enabled (we can receive pause frames, + * but not send pause frames). + * 2: Tx flow control is enabled (we can send pause frames but + * we do not support receiving pause frames). + * 3: Both Rx and Tx flow control (symmetric) are enabled. +#ifdef CONFIG_DCB + * 4: Priority Flow Control is enabled. +#endif + * other: Invalid. + */ + switch (hw->fc.requested_mode) { + case ixgbe_fc_none: + /* Flow control completely disabled by software override. */ + reg &= ~(IXGBE_PCS1GANA_SYM_PAUSE | IXGBE_PCS1GANA_ASM_PAUSE); + break; + case ixgbe_fc_rx_pause: + /* + * Rx Flow control is enabled and Tx Flow control is + * disabled by software override. Since there really + * isn't a way to advertise that we are capable of RX + * Pause ONLY, we will advertise that we support both + * symmetric and asymmetric Rx PAUSE. Later, we will + * disable the adapter's ability to send PAUSE frames. + */ + reg |= (IXGBE_PCS1GANA_SYM_PAUSE | IXGBE_PCS1GANA_ASM_PAUSE); + break; + case ixgbe_fc_tx_pause: + /* + * Tx Flow control is enabled, and Rx Flow control is + * disabled by software override. + */ + reg |= (IXGBE_PCS1GANA_ASM_PAUSE); + reg &= ~(IXGBE_PCS1GANA_SYM_PAUSE); + break; + case ixgbe_fc_full: + /* Flow control (both Rx and Tx) is enabled by SW override. */ + reg |= (IXGBE_PCS1GANA_SYM_PAUSE | IXGBE_PCS1GANA_ASM_PAUSE); + break; +#ifdef CONFIG_DCB + case ixgbe_fc_pfc: goto out; + break; +#endif /* CONFIG_DCB */ + default: + hw_dbg(hw, "Flow control param set incorrectly\n"); + ret_val = -IXGBE_ERR_CONFIG; + goto out; + break; + } - ret_val = ixgbe_fc_enable(hw, packetbuf_num); + IXGBE_WRITE_REG(hw, IXGBE_PCS1GANA, reg); + reg = IXGBE_READ_REG(hw, IXGBE_PCS1GLCTL); + + /* Enable and restart autoneg to inform the link partner */ + reg |= IXGBE_PCS1GLCTL_AN_ENABLE | IXGBE_PCS1GLCTL_AN_RESTART; + + /* Disable AN timeout */ + if (hw->fc.strict_ieee) + reg &= ~IXGBE_PCS1GLCTL_AN_1G_TIMEOUT_EN; + + IXGBE_WRITE_REG(hw, IXGBE_PCS1GLCTL, reg); + hw_dbg(hw, "Set up FC; PCS1GLCTL = 0x%08X\n", reg); out: return ret_val; @@ -2044,6 +2081,7 @@ s32 ixgbe_blink_led_start_generic(struct ixgbe_hw *hw, u32 index) hw->mac.ops.check_link(hw, &speed, &link_up, false); if (!link_up) { + autoc_reg |= IXGBE_AUTOC_AN_RESTART; autoc_reg |= IXGBE_AUTOC_FLU; IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg); msleep(10); diff --git a/drivers/net/ixgbe/ixgbe_common.h b/drivers/net/ixgbe/ixgbe_common.h index dd260890ad0a..0d34d4d8244c 100644 --- a/drivers/net/ixgbe/ixgbe_common.h +++ b/drivers/net/ixgbe/ixgbe_common.h @@ -59,13 +59,13 @@ s32 ixgbe_init_rx_addrs_generic(struct ixgbe_hw *hw); s32 ixgbe_update_mc_addr_list_generic(struct ixgbe_hw *hw, u8 *mc_addr_list, u32 mc_addr_count, ixgbe_mc_addr_itr func); -s32 ixgbe_update_uc_addr_list_generic(struct ixgbe_hw *hw, u8 *addr_list, - u32 addr_count, ixgbe_mc_addr_itr func); +s32 ixgbe_update_uc_addr_list_generic(struct ixgbe_hw *hw, + struct list_head *uc_list); s32 ixgbe_enable_mc_generic(struct ixgbe_hw *hw); s32 ixgbe_disable_mc_generic(struct ixgbe_hw *hw); s32 ixgbe_enable_rx_dma_generic(struct ixgbe_hw *hw, u32 regval); -s32 ixgbe_setup_fc_generic(struct ixgbe_hw *hw, s32 packetbuf_num); -s32 ixgbe_fc_enable(struct ixgbe_hw *hw, s32 packtetbuf_num); +s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packetbuf_num); +s32 ixgbe_fc_enable_generic(struct ixgbe_hw *hw, s32 packtetbuf_num); s32 ixgbe_fc_autoneg(struct ixgbe_hw *hw); s32 ixgbe_validate_mac_addr(u8 *mac_addr); diff --git a/drivers/net/ixgbe/ixgbe_dcb_82598.c b/drivers/net/ixgbe/ixgbe_dcb_82598.c index 62206273d888..f30263898ebc 100644 --- a/drivers/net/ixgbe/ixgbe_dcb_82598.c +++ b/drivers/net/ixgbe/ixgbe_dcb_82598.c @@ -294,6 +294,9 @@ s32 ixgbe_dcb_config_pfc_82598(struct ixgbe_hw *hw, u32 reg, rx_pba_size; u8 i; + if (!dcb_config->pfc_mode_enable) + goto out; + /* Enable Transmit Priority Flow Control */ reg = IXGBE_READ_REG(hw, IXGBE_RMCS); reg &= ~IXGBE_RMCS_TFCE_802_3X; @@ -341,6 +344,7 @@ s32 ixgbe_dcb_config_pfc_82598(struct ixgbe_hw *hw, /* Configure flow control refresh threshold value */ IXGBE_WRITE_REG(hw, IXGBE_FCRTV, 0x3400); +out: return 0; } diff --git a/drivers/net/ixgbe/ixgbe_dcb_82599.c b/drivers/net/ixgbe/ixgbe_dcb_82599.c index f4417fc3b0fd..589f62c7062a 100644 --- a/drivers/net/ixgbe/ixgbe_dcb_82599.c +++ b/drivers/net/ixgbe/ixgbe_dcb_82599.c @@ -295,7 +295,7 @@ s32 ixgbe_dcb_config_pfc_82599(struct ixgbe_hw *hw, /* If PFC is disabled globally then fall back to LFC. */ if (!dcb_config->pfc_mode_enable) { for (i = 0; i < MAX_TRAFFIC_CLASS; i++) - hw->mac.ops.setup_fc(hw, i); + hw->mac.ops.fc_enable(hw, i); goto out; } diff --git a/drivers/net/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ixgbe/ixgbe_dcb_nl.c index bd0a0c276952..d56890f5c9d5 100644 --- a/drivers/net/ixgbe/ixgbe_dcb_nl.c +++ b/drivers/net/ixgbe/ixgbe_dcb_nl.c @@ -28,15 +28,22 @@ #include "ixgbe.h" #include +#include "ixgbe_dcb_82598.h" +#include "ixgbe_dcb_82599.h" /* Callbacks for DCB netlink in the kernel */ #define BIT_DCB_MODE 0x01 #define BIT_PFC 0x02 #define BIT_PG_RX 0x04 #define BIT_PG_TX 0x08 -#define BIT_BCN 0x10 +#define BIT_RESETLINK 0x40 #define BIT_LINKSPEED 0x80 +/* Responses for the DCB_C_SET_ALL command */ +#define DCB_HW_CHG_RST 0 /* DCB configuration changed with reset */ +#define DCB_NO_HW_CHG 1 /* DCB configuration did not change */ +#define DCB_HW_CHG 2 /* DCB configuration changed, no reset */ + int ixgbe_copy_dcb_cfg(struct ixgbe_dcb_config *src_dcb_cfg, struct ixgbe_dcb_config *dst_dcb_cfg, int tc_max) { @@ -124,15 +131,12 @@ static u8 ixgbe_dcbnl_set_state(struct net_device *netdev, u8 state) if (netif_running(netdev)) netdev->netdev_ops->ndo_stop(netdev); - ixgbe_reset_interrupt_capability(adapter); - ixgbe_napi_del_all(adapter); - INIT_LIST_HEAD(&netdev->napi_list); - kfree(adapter->tx_ring); - kfree(adapter->rx_ring); - adapter->tx_ring = NULL; - adapter->rx_ring = NULL; + ixgbe_clear_interrupt_scheme(adapter); - adapter->hw.fc.requested_mode = ixgbe_fc_pfc; + if (adapter->hw.mac.type == ixgbe_mac_82598EB) { + adapter->last_lfc_mode = adapter->hw.fc.current_mode; + adapter->hw.fc.requested_mode = ixgbe_fc_none; + } adapter->flags &= ~IXGBE_FLAG_RSS_ENABLED; adapter->flags |= IXGBE_FLAG_DCB_ENABLED; ixgbe_init_interrupt_scheme(adapter); @@ -141,17 +145,13 @@ static u8 ixgbe_dcbnl_set_state(struct net_device *netdev, u8 state) } else { /* Turn off DCB */ if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { - adapter->hw.fc.requested_mode = ixgbe_fc_default; if (netif_running(netdev)) netdev->netdev_ops->ndo_stop(netdev); - ixgbe_reset_interrupt_capability(adapter); - ixgbe_napi_del_all(adapter); - INIT_LIST_HEAD(&netdev->napi_list); - kfree(adapter->tx_ring); - kfree(adapter->rx_ring); - adapter->tx_ring = NULL; - adapter->rx_ring = NULL; + ixgbe_clear_interrupt_scheme(adapter); + adapter->hw.fc.requested_mode = adapter->last_lfc_mode; + adapter->temp_dcb_cfg.pfc_mode_enable = false; + adapter->dcb_cfg.pfc_mode_enable = false; adapter->flags &= ~IXGBE_FLAG_DCB_ENABLED; adapter->flags |= IXGBE_FLAG_RSS_ENABLED; ixgbe_init_interrupt_scheme(adapter); @@ -167,10 +167,15 @@ static void ixgbe_dcbnl_get_perm_hw_addr(struct net_device *netdev, u8 *perm_addr) { struct ixgbe_adapter *adapter = netdev_priv(netdev); - int i; + int i, j; for (i = 0; i < netdev->addr_len; i++) perm_addr[i] = adapter->hw.mac.perm_addr[i]; + + if (adapter->hw.mac.type == ixgbe_mac_82599EB) { + for (j = 0; j < netdev->addr_len; j++, i++) + perm_addr[i] = adapter->hw.mac.san_addr[j]; + } } static void ixgbe_dcbnl_set_pg_tc_cfg_tx(struct net_device *netdev, int tc, @@ -197,8 +202,10 @@ static void ixgbe_dcbnl_set_pg_tc_cfg_tx(struct net_device *netdev, int tc, (adapter->temp_dcb_cfg.tc_config[tc].path[0].bwg_percent != adapter->dcb_cfg.tc_config[tc].path[0].bwg_percent) || (adapter->temp_dcb_cfg.tc_config[tc].path[0].up_to_tc_bitmap != - adapter->dcb_cfg.tc_config[tc].path[0].up_to_tc_bitmap)) + adapter->dcb_cfg.tc_config[tc].path[0].up_to_tc_bitmap)) { adapter->dcb_set_bitmap |= BIT_PG_TX; + adapter->dcb_set_bitmap |= BIT_RESETLINK; + } } static void ixgbe_dcbnl_set_pg_bwg_cfg_tx(struct net_device *netdev, int bwg_id, @@ -209,8 +216,10 @@ static void ixgbe_dcbnl_set_pg_bwg_cfg_tx(struct net_device *netdev, int bwg_id, adapter->temp_dcb_cfg.bw_percentage[0][bwg_id] = bw_pct; if (adapter->temp_dcb_cfg.bw_percentage[0][bwg_id] != - adapter->dcb_cfg.bw_percentage[0][bwg_id]) + adapter->dcb_cfg.bw_percentage[0][bwg_id]) { adapter->dcb_set_bitmap |= BIT_PG_RX; + adapter->dcb_set_bitmap |= BIT_RESETLINK; + } } static void ixgbe_dcbnl_set_pg_tc_cfg_rx(struct net_device *netdev, int tc, @@ -237,8 +246,10 @@ static void ixgbe_dcbnl_set_pg_tc_cfg_rx(struct net_device *netdev, int tc, (adapter->temp_dcb_cfg.tc_config[tc].path[1].bwg_percent != adapter->dcb_cfg.tc_config[tc].path[1].bwg_percent) || (adapter->temp_dcb_cfg.tc_config[tc].path[1].up_to_tc_bitmap != - adapter->dcb_cfg.tc_config[tc].path[1].up_to_tc_bitmap)) + adapter->dcb_cfg.tc_config[tc].path[1].up_to_tc_bitmap)) { adapter->dcb_set_bitmap |= BIT_PG_RX; + adapter->dcb_set_bitmap |= BIT_RESETLINK; + } } static void ixgbe_dcbnl_set_pg_bwg_cfg_rx(struct net_device *netdev, int bwg_id, @@ -249,8 +260,10 @@ static void ixgbe_dcbnl_set_pg_bwg_cfg_rx(struct net_device *netdev, int bwg_id, adapter->temp_dcb_cfg.bw_percentage[1][bwg_id] = bw_pct; if (adapter->temp_dcb_cfg.bw_percentage[1][bwg_id] != - adapter->dcb_cfg.bw_percentage[1][bwg_id]) + adapter->dcb_cfg.bw_percentage[1][bwg_id]) { adapter->dcb_set_bitmap |= BIT_PG_RX; + adapter->dcb_set_bitmap |= BIT_RESETLINK; + } } static void ixgbe_dcbnl_get_pg_tc_cfg_tx(struct net_device *netdev, int tc, @@ -319,28 +332,60 @@ static u8 ixgbe_dcbnl_set_all(struct net_device *netdev) struct ixgbe_adapter *adapter = netdev_priv(netdev); int ret; - adapter->dcb_set_bitmap &= ~BIT_BCN; /* no set for BCN */ if (!adapter->dcb_set_bitmap) - return 1; + return DCB_NO_HW_CHG; - while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state)) - msleep(1); + /* + * Only take down the adapter if the configuration change + * requires a reset. + */ + if (adapter->dcb_set_bitmap & BIT_RESETLINK) { + while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state)) + msleep(1); - if (netif_running(netdev)) - ixgbe_down(adapter); + if (netif_running(netdev)) + ixgbe_down(adapter); + } ret = ixgbe_copy_dcb_cfg(&adapter->temp_dcb_cfg, &adapter->dcb_cfg, adapter->ring_feature[RING_F_DCB].indices); if (ret) { - clear_bit(__IXGBE_RESETTING, &adapter->state); - return ret; + if (adapter->dcb_set_bitmap & BIT_RESETLINK) + clear_bit(__IXGBE_RESETTING, &adapter->state); + return DCB_NO_HW_CHG; } - if (netif_running(netdev)) - ixgbe_up(adapter); + if (adapter->dcb_cfg.pfc_mode_enable) { + if ((adapter->hw.mac.type != ixgbe_mac_82598EB) && + (adapter->hw.fc.current_mode != ixgbe_fc_pfc)) + adapter->last_lfc_mode = adapter->hw.fc.current_mode; + adapter->hw.fc.requested_mode = ixgbe_fc_pfc; + } else { + if (adapter->hw.mac.type != ixgbe_mac_82598EB) + adapter->hw.fc.requested_mode = adapter->last_lfc_mode; + else + adapter->hw.fc.requested_mode = ixgbe_fc_none; + } + if (adapter->dcb_set_bitmap & BIT_RESETLINK) { + if (netif_running(netdev)) + ixgbe_up(adapter); + ret = DCB_HW_CHG_RST; + } else if (adapter->dcb_set_bitmap & BIT_PFC) { + if (adapter->hw.mac.type == ixgbe_mac_82598EB) + ixgbe_dcb_config_pfc_82598(&adapter->hw, + &adapter->dcb_cfg); + else if (adapter->hw.mac.type == ixgbe_mac_82599EB) + ixgbe_dcb_config_pfc_82599(&adapter->hw, + &adapter->dcb_cfg); + ret = DCB_HW_CHG; + } + if (adapter->dcb_cfg.pfc_mode_enable) + adapter->hw.fc.current_mode = ixgbe_fc_pfc; + + if (adapter->dcb_set_bitmap & BIT_RESETLINK) + clear_bit(__IXGBE_RESETTING, &adapter->state); adapter->dcb_set_bitmap = 0x00; - clear_bit(__IXGBE_RESETTING, &adapter->state); return ret; } @@ -416,11 +461,17 @@ static u8 ixgbe_dcbnl_getpfcstate(struct net_device *netdev) { struct ixgbe_adapter *adapter = netdev_priv(netdev); - return !!(adapter->flags & IXGBE_FLAG_DCB_ENABLED); + return adapter->dcb_cfg.pfc_mode_enable; } static void ixgbe_dcbnl_setpfcstate(struct net_device *netdev, u8 state) { + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + adapter->temp_dcb_cfg.pfc_mode_enable = state; + if (adapter->temp_dcb_cfg.pfc_mode_enable != + adapter->dcb_cfg.pfc_mode_enable) + adapter->dcb_set_bitmap |= BIT_PFC; return; } diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index f0a20facc650..86f4f3e36f27 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -67,6 +67,9 @@ static struct ixgbe_stats ixgbe_gstrings_stats[] = { {"rx_over_errors", IXGBE_STAT(net_stats.rx_over_errors)}, {"rx_crc_errors", IXGBE_STAT(net_stats.rx_crc_errors)}, {"rx_frame_errors", IXGBE_STAT(net_stats.rx_frame_errors)}, + {"hw_rsc_count", IXGBE_STAT(rsc_count)}, + {"fdir_match", IXGBE_STAT(stats.fdirmatch)}, + {"fdir_miss", IXGBE_STAT(stats.fdirmiss)}, {"rx_fifo_errors", IXGBE_STAT(net_stats.rx_fifo_errors)}, {"rx_missed_errors", IXGBE_STAT(net_stats.rx_missed_errors)}, {"tx_aborted_errors", IXGBE_STAT(net_stats.tx_aborted_errors)}, @@ -90,6 +93,14 @@ static struct ixgbe_stats ixgbe_gstrings_stats[] = { {"alloc_rx_page_failed", IXGBE_STAT(alloc_rx_page_failed)}, {"alloc_rx_buff_failed", IXGBE_STAT(alloc_rx_buff_failed)}, {"rx_no_dma_resources", IXGBE_STAT(hw_rx_no_dma_resources)}, +#ifdef IXGBE_FCOE + {"fcoe_bad_fccrc", IXGBE_STAT(stats.fccrc)}, + {"rx_fcoe_dropped", IXGBE_STAT(stats.fcoerpdc)}, + {"rx_fcoe_packets", IXGBE_STAT(stats.fcoeprc)}, + {"rx_fcoe_dwords", IXGBE_STAT(stats.fcoedwrc)}, + {"tx_fcoe_packets", IXGBE_STAT(stats.fcoeptc)}, + {"tx_fcoe_dwords", IXGBE_STAT(stats.fcoedwtc)}, +#endif /* IXGBE_FCOE */ }; #define IXGBE_QUEUE_STATS_LEN \ @@ -109,6 +120,13 @@ static struct ixgbe_stats ixgbe_gstrings_stats[] = { IXGBE_PB_STATS_LEN + \ IXGBE_QUEUE_STATS_LEN) +static const char ixgbe_gstrings_test[][ETH_GSTRING_LEN] = { + "Register test (offline)", "Eeprom test (offline)", + "Interrupt test (offline)", "Loopback test (offline)", + "Link test (on/offline)" +}; +#define IXGBE_TEST_LEN sizeof(ixgbe_gstrings_test) / ETH_GSTRING_LEN + static int ixgbe_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) { @@ -120,11 +138,12 @@ static int ixgbe_get_settings(struct net_device *netdev, ecmd->supported = SUPPORTED_10000baseT_Full; ecmd->autoneg = AUTONEG_ENABLE; ecmd->transceiver = XCVR_EXTERNAL; - if (hw->phy.media_type == ixgbe_media_type_copper) { + if ((hw->phy.media_type == ixgbe_media_type_copper) || + (hw->mac.type == ixgbe_mac_82599EB)) { ecmd->supported |= (SUPPORTED_1000baseT_Full | - SUPPORTED_TP | SUPPORTED_Autoneg); + SUPPORTED_Autoneg); - ecmd->advertising = (ADVERTISED_TP | ADVERTISED_Autoneg); + ecmd->advertising = ADVERTISED_Autoneg; if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10GB_FULL) ecmd->advertising |= ADVERTISED_10000baseT_Full; if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_1GB_FULL) @@ -139,7 +158,15 @@ static int ixgbe_get_settings(struct net_device *netdev, ecmd->advertising |= (ADVERTISED_10000baseT_Full | ADVERTISED_1000baseT_Full); - ecmd->port = PORT_TP; + if (hw->phy.media_type == ixgbe_media_type_copper) { + ecmd->supported |= SUPPORTED_TP; + ecmd->advertising |= ADVERTISED_TP; + ecmd->port = PORT_TP; + } else { + ecmd->supported |= SUPPORTED_FIBRE; + ecmd->advertising |= ADVERTISED_FIBRE; + ecmd->port = PORT_FIBRE; + } } else if (hw->phy.media_type == ixgbe_media_type_backplane) { /* Set as FIBRE until SERDES defined in kernel */ switch (hw->device_id) { @@ -187,16 +214,10 @@ static int ixgbe_set_settings(struct net_device *netdev, struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_hw *hw = &adapter->hw; u32 advertised, old; - s32 err; + s32 err = 0; - switch (hw->phy.media_type) { - case ixgbe_media_type_fiber: - if ((ecmd->autoneg == AUTONEG_ENABLE) || - (ecmd->speed + ecmd->duplex != SPEED_10000 + DUPLEX_FULL)) - return -EINVAL; - /* in this case we currently only support 10Gb/FULL */ - break; - case ixgbe_media_type_copper: + if ((hw->phy.media_type == ixgbe_media_type_copper) || + (hw->mac.type == ixgbe_mac_82599EB)) { /* 10000/copper and 1000/copper must autoneg * this function does not support any duplex forcing, but can * limit the advertising of the adapter to only 10000 or 1000 */ @@ -212,20 +233,23 @@ static int ixgbe_set_settings(struct net_device *netdev, advertised |= IXGBE_LINK_SPEED_1GB_FULL; if (old == advertised) - break; + return err; /* this sets the link speed and restarts auto-neg */ + hw->mac.autotry_restart = true; err = hw->mac.ops.setup_link_speed(hw, advertised, true, true); if (err) { DPRINTK(PROBE, INFO, "setup link failed with code %d\n", err); hw->mac.ops.setup_link_speed(hw, old, true, true); } - break; - default: - break; + } else { + /* in this case we currently only support 10Gb/FULL */ + if ((ecmd->autoneg == AUTONEG_ENABLE) || + (ecmd->speed + ecmd->duplex != SPEED_10000 + DUPLEX_FULL)) + return -EINVAL; } - return 0; + return err; } static void ixgbe_get_pauseparam(struct net_device *netdev, @@ -245,6 +269,13 @@ static void ixgbe_get_pauseparam(struct net_device *netdev, else pause->autoneg = 1; +#ifdef CONFIG_DCB + if (hw->fc.current_mode == ixgbe_fc_pfc) { + pause->rx_pause = 0; + pause->tx_pause = 0; + } + +#endif if (hw->fc.current_mode == ixgbe_fc_rx_pause) { pause->rx_pause = 1; } else if (hw->fc.current_mode == ixgbe_fc_tx_pause) { @@ -260,24 +291,46 @@ static int ixgbe_set_pauseparam(struct net_device *netdev, { struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_hw *hw = &adapter->hw; + struct ixgbe_fc_info fc; + +#ifdef CONFIG_DCB + if (adapter->dcb_cfg.pfc_mode_enable || + ((hw->mac.type == ixgbe_mac_82598EB) && + (adapter->flags & IXGBE_FLAG_DCB_ENABLED))) + return -EINVAL; + +#endif + + fc = hw->fc; if (pause->autoneg != AUTONEG_ENABLE) - hw->fc.disable_fc_autoneg = true; + fc.disable_fc_autoneg = true; else - hw->fc.disable_fc_autoneg = false; + fc.disable_fc_autoneg = false; if (pause->rx_pause && pause->tx_pause) - hw->fc.requested_mode = ixgbe_fc_full; + fc.requested_mode = ixgbe_fc_full; else if (pause->rx_pause && !pause->tx_pause) - hw->fc.requested_mode = ixgbe_fc_rx_pause; + fc.requested_mode = ixgbe_fc_rx_pause; else if (!pause->rx_pause && pause->tx_pause) - hw->fc.requested_mode = ixgbe_fc_tx_pause; + fc.requested_mode = ixgbe_fc_tx_pause; else if (!pause->rx_pause && !pause->tx_pause) - hw->fc.requested_mode = ixgbe_fc_none; + fc.requested_mode = ixgbe_fc_none; else return -EINVAL; - hw->mac.ops.setup_fc(hw, 0); +#ifdef CONFIG_DCB + adapter->last_lfc_mode = fc.requested_mode; +#endif + + /* if the thing changed then we'll update and use new autoneg */ + if (memcmp(&fc, &hw->fc, sizeof(struct ixgbe_fc_info))) { + hw->fc = fc; + if (netif_running(netdev)) + ixgbe_reinit_locked(adapter); + else + ixgbe_reset(adapter); + } return 0; } @@ -311,10 +364,17 @@ static u32 ixgbe_get_tx_csum(struct net_device *netdev) static int ixgbe_set_tx_csum(struct net_device *netdev, u32 data) { - if (data) + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + if (data) { netdev->features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM); - else + if (adapter->hw.mac.type == ixgbe_mac_82599EB) + netdev->features |= NETIF_F_SCTP_CSUM; + } else { netdev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM); + if (adapter->hw.mac.type == ixgbe_mac_82599EB) + netdev->features &= ~NETIF_F_SCTP_CSUM; + } return 0; } @@ -710,6 +770,7 @@ static void ixgbe_get_drvinfo(struct net_device *netdev, strncpy(drvinfo->fw_version, firmware_version, 32); strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32); drvinfo->n_stats = IXGBE_STATS_LEN; + drvinfo->testinfo_len = IXGBE_TEST_LEN; drvinfo->regdump_len = ixgbe_get_regs_len(netdev); } @@ -781,7 +842,6 @@ static int ixgbe_set_ringparam(struct net_device *netdev, } goto err_setup; } - temp_tx_ring[i].v_idx = adapter->tx_ring[i].v_idx; } need_update = true; } @@ -811,7 +871,6 @@ static int ixgbe_set_ringparam(struct net_device *netdev, } goto err_setup; } - temp_rx_ring[i].v_idx = adapter->rx_ring[i].v_idx; } need_update = true; } @@ -851,6 +910,8 @@ err_setup: static int ixgbe_get_sset_count(struct net_device *netdev, int sset) { switch (sset) { + case ETH_SS_TEST: + return IXGBE_TEST_LEN; case ETH_SS_STATS: return IXGBE_STATS_LEN; default: @@ -905,6 +966,10 @@ static void ixgbe_get_strings(struct net_device *netdev, u32 stringset, int i; switch (stringset) { + case ETH_SS_TEST: + memcpy(data, *ixgbe_gstrings_test, + IXGBE_TEST_LEN * ETH_GSTRING_LEN); + break; case ETH_SS_STATS: for (i = 0; i < IXGBE_GLOBAL_STATS_LEN; i++) { memcpy(p, ixgbe_gstrings_stats[i].stat_string, @@ -942,6 +1007,815 @@ static void ixgbe_get_strings(struct net_device *netdev, u32 stringset, } } +static int ixgbe_link_test(struct ixgbe_adapter *adapter, u64 *data) +{ + struct ixgbe_hw *hw = &adapter->hw; + bool link_up; + u32 link_speed = 0; + *data = 0; + + hw->mac.ops.check_link(hw, &link_speed, &link_up, true); + if (link_up) + return *data; + else + *data = 1; + return *data; +} + +/* ethtool register test data */ +struct ixgbe_reg_test { + u16 reg; + u8 array_len; + u8 test_type; + u32 mask; + u32 write; +}; + +/* In the hardware, registers are laid out either singly, in arrays + * spaced 0x40 bytes apart, or in contiguous tables. We assume + * most tests take place on arrays or single registers (handled + * as a single-element array) and special-case the tables. + * Table tests are always pattern tests. + * + * We also make provision for some required setup steps by specifying + * registers to be written without any read-back testing. + */ + +#define PATTERN_TEST 1 +#define SET_READ_TEST 2 +#define WRITE_NO_TEST 3 +#define TABLE32_TEST 4 +#define TABLE64_TEST_LO 5 +#define TABLE64_TEST_HI 6 + +/* default 82599 register test */ +static struct ixgbe_reg_test reg_test_82599[] = { + { IXGBE_FCRTL_82599(0), 1, PATTERN_TEST, 0x8007FFF0, 0x8007FFF0 }, + { IXGBE_FCRTH_82599(0), 1, PATTERN_TEST, 0x8007FFF0, 0x8007FFF0 }, + { IXGBE_PFCTOP, 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { IXGBE_VLNCTRL, 1, PATTERN_TEST, 0x00000000, 0x00000000 }, + { IXGBE_RDBAL(0), 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFF80 }, + { IXGBE_RDBAH(0), 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { IXGBE_RDLEN(0), 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF }, + { IXGBE_RXDCTL(0), 4, WRITE_NO_TEST, 0, IXGBE_RXDCTL_ENABLE }, + { IXGBE_RDT(0), 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, + { IXGBE_RXDCTL(0), 4, WRITE_NO_TEST, 0, 0 }, + { IXGBE_FCRTH(0), 1, PATTERN_TEST, 0x8007FFF0, 0x8007FFF0 }, + { IXGBE_FCTTV(0), 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { IXGBE_TDBAL(0), 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF }, + { IXGBE_TDBAH(0), 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { IXGBE_TDLEN(0), 4, PATTERN_TEST, 0x000FFF80, 0x000FFF80 }, + { IXGBE_RXCTRL, 1, SET_READ_TEST, 0x00000001, 0x00000001 }, + { IXGBE_RAL(0), 16, TABLE64_TEST_LO, 0xFFFFFFFF, 0xFFFFFFFF }, + { IXGBE_RAL(0), 16, TABLE64_TEST_HI, 0x8001FFFF, 0x800CFFFF }, + { IXGBE_MTA(0), 128, TABLE32_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { 0, 0, 0, 0 } +}; + +/* default 82598 register test */ +static struct ixgbe_reg_test reg_test_82598[] = { + { IXGBE_FCRTL(0), 1, PATTERN_TEST, 0x8007FFF0, 0x8007FFF0 }, + { IXGBE_FCRTH(0), 1, PATTERN_TEST, 0x8007FFF0, 0x8007FFF0 }, + { IXGBE_PFCTOP, 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { IXGBE_VLNCTRL, 1, PATTERN_TEST, 0x00000000, 0x00000000 }, + { IXGBE_RDBAL(0), 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF }, + { IXGBE_RDBAH(0), 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { IXGBE_RDLEN(0), 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF }, + /* Enable all four RX queues before testing. */ + { IXGBE_RXDCTL(0), 4, WRITE_NO_TEST, 0, IXGBE_RXDCTL_ENABLE }, + /* RDH is read-only for 82598, only test RDT. */ + { IXGBE_RDT(0), 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, + { IXGBE_RXDCTL(0), 4, WRITE_NO_TEST, 0, 0 }, + { IXGBE_FCRTH(0), 1, PATTERN_TEST, 0x8007FFF0, 0x8007FFF0 }, + { IXGBE_FCTTV(0), 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { IXGBE_TIPG, 1, PATTERN_TEST, 0x000000FF, 0x000000FF }, + { IXGBE_TDBAL(0), 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF }, + { IXGBE_TDBAH(0), 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { IXGBE_TDLEN(0), 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF }, + { IXGBE_RXCTRL, 1, SET_READ_TEST, 0x00000003, 0x00000003 }, + { IXGBE_DTXCTL, 1, SET_READ_TEST, 0x00000005, 0x00000005 }, + { IXGBE_RAL(0), 16, TABLE64_TEST_LO, 0xFFFFFFFF, 0xFFFFFFFF }, + { IXGBE_RAL(0), 16, TABLE64_TEST_HI, 0x800CFFFF, 0x800CFFFF }, + { IXGBE_MTA(0), 128, TABLE32_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { 0, 0, 0, 0 } +}; + +#define REG_PATTERN_TEST(R, M, W) \ +{ \ + u32 pat, val, before; \ + const u32 _test[] = {0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF}; \ + for (pat = 0; pat < ARRAY_SIZE(_test); pat++) { \ + before = readl(adapter->hw.hw_addr + R); \ + writel((_test[pat] & W), (adapter->hw.hw_addr + R)); \ + val = readl(adapter->hw.hw_addr + R); \ + if (val != (_test[pat] & W & M)) { \ + DPRINTK(DRV, ERR, "pattern test reg %04X failed: got "\ + "0x%08X expected 0x%08X\n", \ + R, val, (_test[pat] & W & M)); \ + *data = R; \ + writel(before, adapter->hw.hw_addr + R); \ + return 1; \ + } \ + writel(before, adapter->hw.hw_addr + R); \ + } \ +} + +#define REG_SET_AND_CHECK(R, M, W) \ +{ \ + u32 val, before; \ + before = readl(adapter->hw.hw_addr + R); \ + writel((W & M), (adapter->hw.hw_addr + R)); \ + val = readl(adapter->hw.hw_addr + R); \ + if ((W & M) != (val & M)) { \ + DPRINTK(DRV, ERR, "set/check reg %04X test failed: got 0x%08X "\ + "expected 0x%08X\n", R, (val & M), (W & M)); \ + *data = R; \ + writel(before, (adapter->hw.hw_addr + R)); \ + return 1; \ + } \ + writel(before, (adapter->hw.hw_addr + R)); \ +} + +static int ixgbe_reg_test(struct ixgbe_adapter *adapter, u64 *data) +{ + struct ixgbe_reg_test *test; + u32 value, before, after; + u32 i, toggle; + + if (adapter->hw.mac.type == ixgbe_mac_82599EB) { + toggle = 0x7FFFF30F; + test = reg_test_82599; + } else { + toggle = 0x7FFFF3FF; + test = reg_test_82598; + } + + /* + * Because the status register is such a special case, + * we handle it separately from the rest of the register + * tests. Some bits are read-only, some toggle, and some + * are writeable on newer MACs. + */ + before = IXGBE_READ_REG(&adapter->hw, IXGBE_STATUS); + value = (IXGBE_READ_REG(&adapter->hw, IXGBE_STATUS) & toggle); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_STATUS, toggle); + after = IXGBE_READ_REG(&adapter->hw, IXGBE_STATUS) & toggle; + if (value != after) { + DPRINTK(DRV, ERR, "failed STATUS register test got: " + "0x%08X expected: 0x%08X\n", after, value); + *data = 1; + return 1; + } + /* restore previous status */ + IXGBE_WRITE_REG(&adapter->hw, IXGBE_STATUS, before); + + /* + * Perform the remainder of the register test, looping through + * the test table until we either fail or reach the null entry. + */ + while (test->reg) { + for (i = 0; i < test->array_len; i++) { + switch (test->test_type) { + case PATTERN_TEST: + REG_PATTERN_TEST(test->reg + (i * 0x40), + test->mask, + test->write); + break; + case SET_READ_TEST: + REG_SET_AND_CHECK(test->reg + (i * 0x40), + test->mask, + test->write); + break; + case WRITE_NO_TEST: + writel(test->write, + (adapter->hw.hw_addr + test->reg) + + (i * 0x40)); + break; + case TABLE32_TEST: + REG_PATTERN_TEST(test->reg + (i * 4), + test->mask, + test->write); + break; + case TABLE64_TEST_LO: + REG_PATTERN_TEST(test->reg + (i * 8), + test->mask, + test->write); + break; + case TABLE64_TEST_HI: + REG_PATTERN_TEST((test->reg + 4) + (i * 8), + test->mask, + test->write); + break; + } + } + test++; + } + + *data = 0; + return 0; +} + +static int ixgbe_eeprom_test(struct ixgbe_adapter *adapter, u64 *data) +{ + struct ixgbe_hw *hw = &adapter->hw; + if (hw->eeprom.ops.validate_checksum(hw, NULL)) + *data = 1; + else + *data = 0; + return *data; +} + +static irqreturn_t ixgbe_test_intr(int irq, void *data) +{ + struct net_device *netdev = (struct net_device *) data; + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + adapter->test_icr |= IXGBE_READ_REG(&adapter->hw, IXGBE_EICR); + + return IRQ_HANDLED; +} + +static int ixgbe_intr_test(struct ixgbe_adapter *adapter, u64 *data) +{ + struct net_device *netdev = adapter->netdev; + u32 mask, i = 0, shared_int = true; + u32 irq = adapter->pdev->irq; + + *data = 0; + + /* Hook up test interrupt handler just for this test */ + if (adapter->msix_entries) { + /* NOTE: we don't test MSI-X interrupts here, yet */ + return 0; + } else if (adapter->flags & IXGBE_FLAG_MSI_ENABLED) { + shared_int = false; + if (request_irq(irq, &ixgbe_test_intr, 0, netdev->name, + netdev)) { + *data = 1; + return -1; + } + } else if (!request_irq(irq, &ixgbe_test_intr, IRQF_PROBE_SHARED, + netdev->name, netdev)) { + shared_int = false; + } else if (request_irq(irq, &ixgbe_test_intr, IRQF_SHARED, + netdev->name, netdev)) { + *data = 1; + return -1; + } + DPRINTK(HW, INFO, "testing %s interrupt\n", + (shared_int ? "shared" : "unshared")); + + /* Disable all the interrupts */ + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, 0xFFFFFFFF); + msleep(10); + + /* Test each interrupt */ + for (; i < 10; i++) { + /* Interrupt to test */ + mask = 1 << i; + + if (!shared_int) { + /* + * Disable the interrupts to be reported in + * the cause register and then force the same + * interrupt and see if one gets posted. If + * an interrupt was posted to the bus, the + * test failed. + */ + adapter->test_icr = 0; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, + ~mask & 0x00007FFF); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, + ~mask & 0x00007FFF); + msleep(10); + + if (adapter->test_icr & mask) { + *data = 3; + break; + } + } + + /* + * Enable the interrupt to be reported in the cause + * register and then force the same interrupt and see + * if one gets posted. If an interrupt was not posted + * to the bus, the test failed. + */ + adapter->test_icr = 0; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, mask); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, mask); + msleep(10); + + if (!(adapter->test_icr &mask)) { + *data = 4; + break; + } + + if (!shared_int) { + /* + * Disable the other interrupts to be reported in + * the cause register and then force the other + * interrupts and see if any get posted. If + * an interrupt was posted to the bus, the + * test failed. + */ + adapter->test_icr = 0; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, + ~mask & 0x00007FFF); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, + ~mask & 0x00007FFF); + msleep(10); + + if (adapter->test_icr) { + *data = 5; + break; + } + } + } + + /* Disable all the interrupts */ + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, 0xFFFFFFFF); + msleep(10); + + /* Unhook test interrupt handler */ + free_irq(irq, netdev); + + return *data; +} + +static void ixgbe_free_desc_rings(struct ixgbe_adapter *adapter) +{ + struct ixgbe_ring *tx_ring = &adapter->test_tx_ring; + struct ixgbe_ring *rx_ring = &adapter->test_rx_ring; + struct ixgbe_hw *hw = &adapter->hw; + struct pci_dev *pdev = adapter->pdev; + u32 reg_ctl; + int i; + + /* shut down the DMA engines now so they can be reinitialized later */ + + /* first Rx */ + reg_ctl = IXGBE_READ_REG(hw, IXGBE_RXCTRL); + reg_ctl &= ~IXGBE_RXCTRL_RXEN; + IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, reg_ctl); + reg_ctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(0)); + reg_ctl &= ~IXGBE_RXDCTL_ENABLE; + IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(0), reg_ctl); + + /* now Tx */ + reg_ctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(0)); + reg_ctl &= ~IXGBE_TXDCTL_ENABLE; + IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(0), reg_ctl); + if (hw->mac.type == ixgbe_mac_82599EB) { + reg_ctl = IXGBE_READ_REG(hw, IXGBE_DMATXCTL); + reg_ctl &= ~IXGBE_DMATXCTL_TE; + IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, reg_ctl); + } + + ixgbe_reset(adapter); + + if (tx_ring->desc && tx_ring->tx_buffer_info) { + for (i = 0; i < tx_ring->count; i++) { + struct ixgbe_tx_buffer *buf = + &(tx_ring->tx_buffer_info[i]); + if (buf->dma) + pci_unmap_single(pdev, buf->dma, buf->length, + PCI_DMA_TODEVICE); + if (buf->skb) + dev_kfree_skb(buf->skb); + } + } + + if (rx_ring->desc && rx_ring->rx_buffer_info) { + for (i = 0; i < rx_ring->count; i++) { + struct ixgbe_rx_buffer *buf = + &(rx_ring->rx_buffer_info[i]); + if (buf->dma) + pci_unmap_single(pdev, buf->dma, + IXGBE_RXBUFFER_2048, + PCI_DMA_FROMDEVICE); + if (buf->skb) + dev_kfree_skb(buf->skb); + } + } + + if (tx_ring->desc) { + pci_free_consistent(pdev, tx_ring->size, tx_ring->desc, + tx_ring->dma); + tx_ring->desc = NULL; + } + if (rx_ring->desc) { + pci_free_consistent(pdev, rx_ring->size, rx_ring->desc, + rx_ring->dma); + rx_ring->desc = NULL; + } + + kfree(tx_ring->tx_buffer_info); + tx_ring->tx_buffer_info = NULL; + kfree(rx_ring->rx_buffer_info); + rx_ring->rx_buffer_info = NULL; + + return; +} + +static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter) +{ + struct ixgbe_ring *tx_ring = &adapter->test_tx_ring; + struct ixgbe_ring *rx_ring = &adapter->test_rx_ring; + struct pci_dev *pdev = adapter->pdev; + u32 rctl, reg_data; + int i, ret_val; + + /* Setup Tx descriptor ring and Tx buffers */ + + if (!tx_ring->count) + tx_ring->count = IXGBE_DEFAULT_TXD; + + tx_ring->tx_buffer_info = kcalloc(tx_ring->count, + sizeof(struct ixgbe_tx_buffer), + GFP_KERNEL); + if (!(tx_ring->tx_buffer_info)) { + ret_val = 1; + goto err_nomem; + } + + tx_ring->size = tx_ring->count * sizeof(struct ixgbe_legacy_tx_desc); + tx_ring->size = ALIGN(tx_ring->size, 4096); + if (!(tx_ring->desc = pci_alloc_consistent(pdev, tx_ring->size, + &tx_ring->dma))) { + ret_val = 2; + goto err_nomem; + } + tx_ring->next_to_use = tx_ring->next_to_clean = 0; + + IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDBAL(0), + ((u64) tx_ring->dma & 0x00000000FFFFFFFF)); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDBAH(0), + ((u64) tx_ring->dma >> 32)); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDLEN(0), + tx_ring->count * sizeof(struct ixgbe_legacy_tx_desc)); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDH(0), 0); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDT(0), 0); + + reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_HLREG0); + reg_data |= IXGBE_HLREG0_TXPADEN; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_HLREG0, reg_data); + + if (adapter->hw.mac.type == ixgbe_mac_82599EB) { + reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_DMATXCTL); + reg_data |= IXGBE_DMATXCTL_TE; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_DMATXCTL, reg_data); + } + reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_TXDCTL(0)); + reg_data |= IXGBE_TXDCTL_ENABLE; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_TXDCTL(0), reg_data); + + for (i = 0; i < tx_ring->count; i++) { + struct ixgbe_legacy_tx_desc *desc = IXGBE_TX_DESC(*tx_ring, i); + struct sk_buff *skb; + unsigned int size = 1024; + + skb = alloc_skb(size, GFP_KERNEL); + if (!skb) { + ret_val = 3; + goto err_nomem; + } + skb_put(skb, size); + tx_ring->tx_buffer_info[i].skb = skb; + tx_ring->tx_buffer_info[i].length = skb->len; + tx_ring->tx_buffer_info[i].dma = + pci_map_single(pdev, skb->data, skb->len, + PCI_DMA_TODEVICE); + desc->buffer_addr = cpu_to_le64(tx_ring->tx_buffer_info[i].dma); + desc->lower.data = cpu_to_le32(skb->len); + desc->lower.data |= cpu_to_le32(IXGBE_TXD_CMD_EOP | + IXGBE_TXD_CMD_IFCS | + IXGBE_TXD_CMD_RS); + desc->upper.data = 0; + } + + /* Setup Rx Descriptor ring and Rx buffers */ + + if (!rx_ring->count) + rx_ring->count = IXGBE_DEFAULT_RXD; + + rx_ring->rx_buffer_info = kcalloc(rx_ring->count, + sizeof(struct ixgbe_rx_buffer), + GFP_KERNEL); + if (!(rx_ring->rx_buffer_info)) { + ret_val = 4; + goto err_nomem; + } + + rx_ring->size = rx_ring->count * sizeof(struct ixgbe_legacy_rx_desc); + rx_ring->size = ALIGN(rx_ring->size, 4096); + if (!(rx_ring->desc = pci_alloc_consistent(pdev, rx_ring->size, + &rx_ring->dma))) { + ret_val = 5; + goto err_nomem; + } + rx_ring->next_to_use = rx_ring->next_to_clean = 0; + + rctl = IXGBE_READ_REG(&adapter->hw, IXGBE_RXCTRL); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_RXCTRL, rctl & ~IXGBE_RXCTRL_RXEN); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_RDBAL(0), + ((u64)rx_ring->dma & 0xFFFFFFFF)); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_RDBAH(0), + ((u64) rx_ring->dma >> 32)); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_RDLEN(0), rx_ring->size); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_RDH(0), 0); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_RDT(0), 0); + + reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL); + reg_data |= IXGBE_FCTRL_BAM | IXGBE_FCTRL_SBP | IXGBE_FCTRL_MPE; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, reg_data); + + reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_HLREG0); + reg_data &= ~IXGBE_HLREG0_LPBK; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_HLREG0, reg_data); + + reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_RDRXCTL); +#define IXGBE_RDRXCTL_RDMTS_MASK 0x00000003 /* Receive Descriptor Minimum + Threshold Size mask */ + reg_data &= ~IXGBE_RDRXCTL_RDMTS_MASK; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_RDRXCTL, reg_data); + + reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_MCSTCTRL); +#define IXGBE_MCSTCTRL_MO_MASK 0x00000003 /* Multicast Offset mask */ + reg_data &= ~IXGBE_MCSTCTRL_MO_MASK; + reg_data |= adapter->hw.mac.mc_filter_type; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_MCSTCTRL, reg_data); + + reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_RXDCTL(0)); + reg_data |= IXGBE_RXDCTL_ENABLE; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_RXDCTL(0), reg_data); + if (adapter->hw.mac.type == ixgbe_mac_82599EB) { + int j = adapter->rx_ring[0].reg_idx; + u32 k; + for (k = 0; k < 10; k++) { + if (IXGBE_READ_REG(&adapter->hw, + IXGBE_RXDCTL(j)) & IXGBE_RXDCTL_ENABLE) + break; + else + msleep(1); + } + } + + rctl |= IXGBE_RXCTRL_RXEN | IXGBE_RXCTRL_DMBYPS; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_RXCTRL, rctl); + + for (i = 0; i < rx_ring->count; i++) { + struct ixgbe_legacy_rx_desc *rx_desc = + IXGBE_RX_DESC(*rx_ring, i); + struct sk_buff *skb; + + skb = alloc_skb(IXGBE_RXBUFFER_2048 + NET_IP_ALIGN, GFP_KERNEL); + if (!skb) { + ret_val = 6; + goto err_nomem; + } + skb_reserve(skb, NET_IP_ALIGN); + rx_ring->rx_buffer_info[i].skb = skb; + rx_ring->rx_buffer_info[i].dma = + pci_map_single(pdev, skb->data, IXGBE_RXBUFFER_2048, + PCI_DMA_FROMDEVICE); + rx_desc->buffer_addr = + cpu_to_le64(rx_ring->rx_buffer_info[i].dma); + memset(skb->data, 0x00, skb->len); + } + + return 0; + +err_nomem: + ixgbe_free_desc_rings(adapter); + return ret_val; +} + +static int ixgbe_setup_loopback_test(struct ixgbe_adapter *adapter) +{ + struct ixgbe_hw *hw = &adapter->hw; + u32 reg_data; + + /* right now we only support MAC loopback in the driver */ + + /* Setup MAC loopback */ + reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_HLREG0); + reg_data |= IXGBE_HLREG0_LPBK; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_HLREG0, reg_data); + + reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_AUTOC); + reg_data &= ~IXGBE_AUTOC_LMS_MASK; + reg_data |= IXGBE_AUTOC_LMS_10G_LINK_NO_AN | IXGBE_AUTOC_FLU; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_AUTOC, reg_data); + + /* Disable Atlas Tx lanes; re-enabled in reset path */ + if (hw->mac.type == ixgbe_mac_82598EB) { + u8 atlas; + + hw->mac.ops.read_analog_reg8(hw, IXGBE_ATLAS_PDN_LPBK, &atlas); + atlas |= IXGBE_ATLAS_PDN_TX_REG_EN; + hw->mac.ops.write_analog_reg8(hw, IXGBE_ATLAS_PDN_LPBK, atlas); + + hw->mac.ops.read_analog_reg8(hw, IXGBE_ATLAS_PDN_10G, &atlas); + atlas |= IXGBE_ATLAS_PDN_TX_10G_QL_ALL; + hw->mac.ops.write_analog_reg8(hw, IXGBE_ATLAS_PDN_10G, atlas); + + hw->mac.ops.read_analog_reg8(hw, IXGBE_ATLAS_PDN_1G, &atlas); + atlas |= IXGBE_ATLAS_PDN_TX_1G_QL_ALL; + hw->mac.ops.write_analog_reg8(hw, IXGBE_ATLAS_PDN_1G, atlas); + + hw->mac.ops.read_analog_reg8(hw, IXGBE_ATLAS_PDN_AN, &atlas); + atlas |= IXGBE_ATLAS_PDN_TX_AN_QL_ALL; + hw->mac.ops.write_analog_reg8(hw, IXGBE_ATLAS_PDN_AN, atlas); + } + + return 0; +} + +static void ixgbe_loopback_cleanup(struct ixgbe_adapter *adapter) +{ + u32 reg_data; + + reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_HLREG0); + reg_data &= ~IXGBE_HLREG0_LPBK; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_HLREG0, reg_data); +} + +static void ixgbe_create_lbtest_frame(struct sk_buff *skb, + unsigned int frame_size) +{ + memset(skb->data, 0xFF, frame_size); + frame_size &= ~1; + memset(&skb->data[frame_size / 2], 0xAA, frame_size / 2 - 1); + memset(&skb->data[frame_size / 2 + 10], 0xBE, 1); + memset(&skb->data[frame_size / 2 + 12], 0xAF, 1); +} + +static int ixgbe_check_lbtest_frame(struct sk_buff *skb, + unsigned int frame_size) +{ + frame_size &= ~1; + if (*(skb->data + 3) == 0xFF) { + if ((*(skb->data + frame_size / 2 + 10) == 0xBE) && + (*(skb->data + frame_size / 2 + 12) == 0xAF)) { + return 0; + } + } + return 13; +} + +static int ixgbe_run_loopback_test(struct ixgbe_adapter *adapter) +{ + struct ixgbe_ring *tx_ring = &adapter->test_tx_ring; + struct ixgbe_ring *rx_ring = &adapter->test_rx_ring; + struct pci_dev *pdev = adapter->pdev; + int i, j, k, l, lc, good_cnt, ret_val = 0; + unsigned long time; + + IXGBE_WRITE_REG(&adapter->hw, IXGBE_RDT(0), rx_ring->count - 1); + + /* + * Calculate the loop count based on the largest descriptor ring + * The idea is to wrap the largest ring a number of times using 64 + * send/receive pairs during each loop + */ + + if (rx_ring->count <= tx_ring->count) + lc = ((tx_ring->count / 64) * 2) + 1; + else + lc = ((rx_ring->count / 64) * 2) + 1; + + k = l = 0; + for (j = 0; j <= lc; j++) { + for (i = 0; i < 64; i++) { + ixgbe_create_lbtest_frame( + tx_ring->tx_buffer_info[k].skb, + 1024); + pci_dma_sync_single_for_device(pdev, + tx_ring->tx_buffer_info[k].dma, + tx_ring->tx_buffer_info[k].length, + PCI_DMA_TODEVICE); + if (unlikely(++k == tx_ring->count)) + k = 0; + } + IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDT(0), k); + msleep(200); + /* set the start time for the receive */ + time = jiffies; + good_cnt = 0; + do { + /* receive the sent packets */ + pci_dma_sync_single_for_cpu(pdev, + rx_ring->rx_buffer_info[l].dma, + IXGBE_RXBUFFER_2048, + PCI_DMA_FROMDEVICE); + ret_val = ixgbe_check_lbtest_frame( + rx_ring->rx_buffer_info[l].skb, 1024); + if (!ret_val) + good_cnt++; + if (++l == rx_ring->count) + l = 0; + /* + * time + 20 msecs (200 msecs on 2.4) is more than + * enough time to complete the receives, if it's + * exceeded, break and error off + */ + } while (good_cnt < 64 && jiffies < (time + 20)); + if (good_cnt != 64) { + /* ret_val is the same as mis-compare */ + ret_val = 13; + break; + } + if (jiffies >= (time + 20)) { + /* Error code for time out error */ + ret_val = 14; + break; + } + } + + return ret_val; +} + +static int ixgbe_loopback_test(struct ixgbe_adapter *adapter, u64 *data) +{ + *data = ixgbe_setup_desc_rings(adapter); + if (*data) + goto out; + *data = ixgbe_setup_loopback_test(adapter); + if (*data) + goto err_loopback; + *data = ixgbe_run_loopback_test(adapter); + ixgbe_loopback_cleanup(adapter); + +err_loopback: + ixgbe_free_desc_rings(adapter); +out: + return *data; +} + +static void ixgbe_diag_test(struct net_device *netdev, + struct ethtool_test *eth_test, u64 *data) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + bool if_running = netif_running(netdev); + + set_bit(__IXGBE_TESTING, &adapter->state); + if (eth_test->flags == ETH_TEST_FL_OFFLINE) { + /* Offline tests */ + + DPRINTK(HW, INFO, "offline testing starting\n"); + + /* Link test performed before hardware reset so autoneg doesn't + * interfere with test result */ + if (ixgbe_link_test(adapter, &data[4])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + if (if_running) + /* indicate we're in test mode */ + dev_close(netdev); + else + ixgbe_reset(adapter); + + DPRINTK(HW, INFO, "register testing starting\n"); + if (ixgbe_reg_test(adapter, &data[0])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + ixgbe_reset(adapter); + DPRINTK(HW, INFO, "eeprom testing starting\n"); + if (ixgbe_eeprom_test(adapter, &data[1])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + ixgbe_reset(adapter); + DPRINTK(HW, INFO, "interrupt testing starting\n"); + if (ixgbe_intr_test(adapter, &data[2])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + ixgbe_reset(adapter); + DPRINTK(HW, INFO, "loopback testing starting\n"); + if (ixgbe_loopback_test(adapter, &data[3])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + ixgbe_reset(adapter); + + clear_bit(__IXGBE_TESTING, &adapter->state); + if (if_running) + dev_open(netdev); + } else { + DPRINTK(HW, INFO, "online testing starting\n"); + /* Online tests */ + if (ixgbe_link_test(adapter, &data[4])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + /* Online tests aren't run; pass by default */ + data[0] = 0; + data[1] = 0; + data[2] = 0; + data[3] = 0; + + clear_bit(__IXGBE_TESTING, &adapter->state); + } + msleep_interruptible(4 * 1000); +} static int ixgbe_wol_exclusion(struct ixgbe_adapter *adapter, struct ethtool_wolinfo *wol) @@ -1106,20 +1980,40 @@ static int ixgbe_set_coalesce(struct net_device *netdev, } for (i = 0; i < adapter->num_msix_vectors - NON_Q_VECTORS; i++) { - struct ixgbe_q_vector *q_vector = &adapter->q_vector[i]; + struct ixgbe_q_vector *q_vector = adapter->q_vector[i]; if (q_vector->txr_count && !q_vector->rxr_count) /* tx vector gets half the rate */ q_vector->eitr = (adapter->eitr_param >> 1); else /* rx only or mixed */ q_vector->eitr = adapter->eitr_param; - ixgbe_write_eitr(adapter, i, - EITR_INTS_PER_SEC_TO_REG(q_vector->eitr)); + ixgbe_write_eitr(q_vector); } return 0; } +static int ixgbe_set_flags(struct net_device *netdev, u32 data) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + ethtool_op_set_flags(netdev, data); + + if (!(adapter->flags & IXGBE_FLAG2_RSC_CAPABLE)) + return 0; + + /* if state changes we need to update adapter->flags and reset */ + if ((!!(data & ETH_FLAG_LRO)) != + (!!(adapter->flags & IXGBE_FLAG2_RSC_ENABLED))) { + adapter->flags ^= IXGBE_FLAG2_RSC_ENABLED; + if (netif_running(netdev)) + ixgbe_reinit_locked(adapter); + else + ixgbe_reset(adapter); + } + return 0; + +} static const struct ethtool_ops ixgbe_ethtool_ops = { .get_settings = ixgbe_get_settings, @@ -1147,6 +2041,7 @@ static const struct ethtool_ops ixgbe_ethtool_ops = { .set_msglevel = ixgbe_set_msglevel, .get_tso = ethtool_op_get_tso, .set_tso = ixgbe_set_tso, + .self_test = ixgbe_diag_test, .get_strings = ixgbe_get_strings, .phys_id = ixgbe_phys_id, .get_sset_count = ixgbe_get_sset_count, @@ -1154,7 +2049,7 @@ static const struct ethtool_ops ixgbe_ethtool_ops = { .get_coalesce = ixgbe_get_coalesce, .set_coalesce = ixgbe_set_coalesce, .get_flags = ethtool_op_get_flags, - .set_flags = ethtool_op_set_flags, + .set_flags = ixgbe_set_flags, }; void ixgbe_set_ethtool_ops(struct net_device *netdev) diff --git a/drivers/net/ixgbe/ixgbe_fcoe.c b/drivers/net/ixgbe/ixgbe_fcoe.c new file mode 100644 index 000000000000..fa9f24e23683 --- /dev/null +++ b/drivers/net/ixgbe/ixgbe_fcoe.c @@ -0,0 +1,556 @@ +/******************************************************************************* + + Intel 10 Gigabit PCI Express Linux driver + Copyright(c) 1999 - 2009 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + + +#include "ixgbe.h" +#include +#include +#include +#include +#include +#include +#include + +/** + * ixgbe_rx_is_fcoe - check the rx desc for incoming pkt type + * @rx_desc: advanced rx descriptor + * + * Returns : true if it is FCoE pkt + */ +static inline bool ixgbe_rx_is_fcoe(union ixgbe_adv_rx_desc *rx_desc) +{ + u16 p; + + p = le16_to_cpu(rx_desc->wb.lower.lo_dword.hs_rss.pkt_info); + if (p & IXGBE_RXDADV_PKTTYPE_ETQF) { + p &= IXGBE_RXDADV_PKTTYPE_ETQF_MASK; + p >>= IXGBE_RXDADV_PKTTYPE_ETQF_SHIFT; + return p == IXGBE_ETQF_FILTER_FCOE; + } + return false; +} + +/** + * ixgbe_fcoe_clear_ddp - clear the given ddp context + * @ddp - ptr to the ixgbe_fcoe_ddp + * + * Returns : none + * + */ +static inline void ixgbe_fcoe_clear_ddp(struct ixgbe_fcoe_ddp *ddp) +{ + ddp->len = 0; + ddp->err = 0; + ddp->udl = NULL; + ddp->udp = 0UL; + ddp->sgl = NULL; + ddp->sgc = 0; +} + +/** + * ixgbe_fcoe_ddp_put - free the ddp context for a given xid + * @netdev: the corresponding net_device + * @xid: the xid that corresponding ddp will be freed + * + * This is the implementation of net_device_ops.ndo_fcoe_ddp_done + * and it is expected to be called by ULD, i.e., FCP layer of libfc + * to release the corresponding ddp context when the I/O is done. + * + * Returns : data length already ddp-ed in bytes + */ +int ixgbe_fcoe_ddp_put(struct net_device *netdev, u16 xid) +{ + int len = 0; + struct ixgbe_fcoe *fcoe; + struct ixgbe_adapter *adapter; + struct ixgbe_fcoe_ddp *ddp; + + if (!netdev) + goto out_ddp_put; + + if (xid >= IXGBE_FCOE_DDP_MAX) + goto out_ddp_put; + + adapter = netdev_priv(netdev); + fcoe = &adapter->fcoe; + ddp = &fcoe->ddp[xid]; + if (!ddp->udl) + goto out_ddp_put; + + len = ddp->len; + /* if there an error, force to invalidate ddp context */ + if (ddp->err) { + spin_lock_bh(&fcoe->lock); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCFLT, 0); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCFLTRW, + (xid | IXGBE_FCFLTRW_WE)); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCBUFF, 0); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCDMARW, + (xid | IXGBE_FCDMARW_WE)); + spin_unlock_bh(&fcoe->lock); + } + if (ddp->sgl) + pci_unmap_sg(adapter->pdev, ddp->sgl, ddp->sgc, + DMA_FROM_DEVICE); + pci_pool_free(fcoe->pool, ddp->udl, ddp->udp); + ixgbe_fcoe_clear_ddp(ddp); + +out_ddp_put: + return len; +} + +/** + * ixgbe_fcoe_ddp_get - called to set up ddp context + * @netdev: the corresponding net_device + * @xid: the exchange id requesting ddp + * @sgl: the scatter-gather list for this request + * @sgc: the number of scatter-gather items + * + * This is the implementation of net_device_ops.ndo_fcoe_ddp_setup + * and is expected to be called from ULD, e.g., FCP layer of libfc + * to set up ddp for the corresponding xid of the given sglist for + * the corresponding I/O. + * + * Returns : 1 for success and 0 for no ddp + */ +int ixgbe_fcoe_ddp_get(struct net_device *netdev, u16 xid, + struct scatterlist *sgl, unsigned int sgc) +{ + struct ixgbe_adapter *adapter; + struct ixgbe_hw *hw; + struct ixgbe_fcoe *fcoe; + struct ixgbe_fcoe_ddp *ddp; + struct scatterlist *sg; + unsigned int i, j, dmacount; + unsigned int len; + static const unsigned int bufflen = 4096; + unsigned int firstoff = 0; + unsigned int lastsize; + unsigned int thisoff = 0; + unsigned int thislen = 0; + u32 fcbuff, fcdmarw, fcfltrw; + dma_addr_t addr; + + if (!netdev || !sgl) + return 0; + + adapter = netdev_priv(netdev); + if (xid >= IXGBE_FCOE_DDP_MAX) { + DPRINTK(DRV, WARNING, "xid=0x%x out-of-range\n", xid); + return 0; + } + + fcoe = &adapter->fcoe; + if (!fcoe->pool) { + DPRINTK(DRV, WARNING, "xid=0x%x no ddp pool for fcoe\n", xid); + return 0; + } + + ddp = &fcoe->ddp[xid]; + if (ddp->sgl) { + DPRINTK(DRV, ERR, "xid 0x%x w/ non-null sgl=%p nents=%d\n", + xid, ddp->sgl, ddp->sgc); + return 0; + } + ixgbe_fcoe_clear_ddp(ddp); + + /* setup dma from scsi command sgl */ + dmacount = pci_map_sg(adapter->pdev, sgl, sgc, DMA_FROM_DEVICE); + if (dmacount == 0) { + DPRINTK(DRV, ERR, "xid 0x%x DMA map error\n", xid); + return 0; + } + + /* alloc the udl from our ddp pool */ + ddp->udl = pci_pool_alloc(fcoe->pool, GFP_KERNEL, &ddp->udp); + if (!ddp->udl) { + DPRINTK(DRV, ERR, "failed allocated ddp context\n"); + goto out_noddp_unmap; + } + ddp->sgl = sgl; + ddp->sgc = sgc; + + j = 0; + for_each_sg(sgl, sg, dmacount, i) { + addr = sg_dma_address(sg); + len = sg_dma_len(sg); + while (len) { + /* get the offset of length of current buffer */ + thisoff = addr & ((dma_addr_t)bufflen - 1); + thislen = min((bufflen - thisoff), len); + /* + * all but the 1st buffer (j == 0) + * must be aligned on bufflen + */ + if ((j != 0) && (thisoff)) + goto out_noddp_free; + /* + * all but the last buffer + * ((i == (dmacount - 1)) && (thislen == len)) + * must end at bufflen + */ + if (((i != (dmacount - 1)) || (thislen != len)) + && ((thislen + thisoff) != bufflen)) + goto out_noddp_free; + + ddp->udl[j] = (u64)(addr - thisoff); + /* only the first buffer may have none-zero offset */ + if (j == 0) + firstoff = thisoff; + len -= thislen; + addr += thislen; + j++; + /* max number of buffers allowed in one DDP context */ + if (j > IXGBE_BUFFCNT_MAX) { + DPRINTK(DRV, ERR, "xid=%x:%d,%d,%d:addr=%llx " + "not enough descriptors\n", + xid, i, j, dmacount, (u64)addr); + goto out_noddp_free; + } + } + } + /* only the last buffer may have non-full bufflen */ + lastsize = thisoff + thislen; + + fcbuff = (IXGBE_FCBUFF_4KB << IXGBE_FCBUFF_BUFFSIZE_SHIFT); + fcbuff |= (j << IXGBE_FCBUFF_BUFFCNT_SHIFT); + fcbuff |= (firstoff << IXGBE_FCBUFF_OFFSET_SHIFT); + fcbuff |= (IXGBE_FCBUFF_VALID); + + fcdmarw = xid; + fcdmarw |= IXGBE_FCDMARW_WE; + fcdmarw |= (lastsize << IXGBE_FCDMARW_LASTSIZE_SHIFT); + + fcfltrw = xid; + fcfltrw |= IXGBE_FCFLTRW_WE; + + /* program DMA context */ + hw = &adapter->hw; + spin_lock_bh(&fcoe->lock); + IXGBE_WRITE_REG(hw, IXGBE_FCPTRL, ddp->udp & DMA_BIT_MASK(32)); + IXGBE_WRITE_REG(hw, IXGBE_FCPTRH, (u64)ddp->udp >> 32); + IXGBE_WRITE_REG(hw, IXGBE_FCBUFF, fcbuff); + IXGBE_WRITE_REG(hw, IXGBE_FCDMARW, fcdmarw); + /* program filter context */ + IXGBE_WRITE_REG(hw, IXGBE_FCPARAM, 0); + IXGBE_WRITE_REG(hw, IXGBE_FCFLT, IXGBE_FCFLT_VALID); + IXGBE_WRITE_REG(hw, IXGBE_FCFLTRW, fcfltrw); + spin_unlock_bh(&fcoe->lock); + + return 1; + +out_noddp_free: + pci_pool_free(fcoe->pool, ddp->udl, ddp->udp); + ixgbe_fcoe_clear_ddp(ddp); + +out_noddp_unmap: + pci_unmap_sg(adapter->pdev, sgl, sgc, DMA_FROM_DEVICE); + return 0; +} + +/** + * ixgbe_fcoe_ddp - check ddp status and mark it done + * @adapter: ixgbe adapter + * @rx_desc: advanced rx descriptor + * @skb: the skb holding the received data + * + * This checks ddp status. + * + * Returns : < 0 indicates an error or not a FCiE ddp, 0 indicates + * not passing the skb to ULD, > 0 indicates is the length of data + * being ddped. + */ +int ixgbe_fcoe_ddp(struct ixgbe_adapter *adapter, + union ixgbe_adv_rx_desc *rx_desc, + struct sk_buff *skb) +{ + u16 xid; + u32 sterr, fceofe, fcerr, fcstat; + int rc = -EINVAL; + struct ixgbe_fcoe *fcoe; + struct ixgbe_fcoe_ddp *ddp; + struct fc_frame_header *fh; + + if (!ixgbe_rx_is_fcoe(rx_desc)) + goto ddp_out; + + skb->ip_summed = CHECKSUM_UNNECESSARY; + sterr = le32_to_cpu(rx_desc->wb.upper.status_error); + fcerr = (sterr & IXGBE_RXDADV_ERR_FCERR); + fceofe = (sterr & IXGBE_RXDADV_ERR_FCEOFE); + if (fcerr == IXGBE_FCERR_BADCRC) + skb->ip_summed = CHECKSUM_NONE; + + skb_reset_network_header(skb); + skb_set_transport_header(skb, skb_network_offset(skb) + + sizeof(struct fcoe_hdr)); + fh = (struct fc_frame_header *)skb_transport_header(skb); + xid = be16_to_cpu(fh->fh_ox_id); + if (xid >= IXGBE_FCOE_DDP_MAX) + goto ddp_out; + + fcoe = &adapter->fcoe; + ddp = &fcoe->ddp[xid]; + if (!ddp->udl) + goto ddp_out; + + ddp->err = (fcerr | fceofe); + if (ddp->err) + goto ddp_out; + + fcstat = (sterr & IXGBE_RXDADV_STAT_FCSTAT); + if (fcstat) { + /* update length of DDPed data */ + ddp->len = le32_to_cpu(rx_desc->wb.lower.hi_dword.rss); + /* unmap the sg list when FCP_RSP is received */ + if (fcstat == IXGBE_RXDADV_STAT_FCSTAT_FCPRSP) { + pci_unmap_sg(adapter->pdev, ddp->sgl, + ddp->sgc, DMA_FROM_DEVICE); + ddp->sgl = NULL; + ddp->sgc = 0; + } + /* return 0 to bypass going to ULD for DDPed data */ + if (fcstat == IXGBE_RXDADV_STAT_FCSTAT_DDP) + rc = 0; + else + rc = ddp->len; + } + +ddp_out: + return rc; +} + +/** + * ixgbe_fso - ixgbe FCoE Sequence Offload (FSO) + * @adapter: ixgbe adapter + * @tx_ring: tx desc ring + * @skb: associated skb + * @tx_flags: tx flags + * @hdr_len: hdr_len to be returned + * + * This sets up large send offload for FCoE + * + * Returns : 0 indicates no FSO, > 0 for FSO, < 0 for error + */ +int ixgbe_fso(struct ixgbe_adapter *adapter, + struct ixgbe_ring *tx_ring, struct sk_buff *skb, + u32 tx_flags, u8 *hdr_len) +{ + u8 sof, eof; + u32 vlan_macip_lens; + u32 fcoe_sof_eof; + u32 type_tucmd; + u32 mss_l4len_idx; + int mss = 0; + unsigned int i; + struct ixgbe_tx_buffer *tx_buffer_info; + struct ixgbe_adv_tx_context_desc *context_desc; + struct fc_frame_header *fh; + + if (skb_is_gso(skb) && (skb_shinfo(skb)->gso_type != SKB_GSO_FCOE)) { + DPRINTK(DRV, ERR, "Wrong gso type %d:expecting SKB_GSO_FCOE\n", + skb_shinfo(skb)->gso_type); + return -EINVAL; + } + + /* resets the header to point fcoe/fc */ + skb_set_network_header(skb, skb->mac_len); + skb_set_transport_header(skb, skb->mac_len + + sizeof(struct fcoe_hdr)); + + /* sets up SOF and ORIS */ + fcoe_sof_eof = 0; + sof = ((struct fcoe_hdr *)skb_network_header(skb))->fcoe_sof; + switch (sof) { + case FC_SOF_I2: + fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_ORIS; + break; + case FC_SOF_I3: + fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_SOF; + fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_ORIS; + break; + case FC_SOF_N2: + break; + case FC_SOF_N3: + fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_SOF; + break; + default: + DPRINTK(DRV, WARNING, "unknown sof = 0x%x\n", sof); + return -EINVAL; + } + + /* the first byte of the last dword is EOF */ + skb_copy_bits(skb, skb->len - 4, &eof, 1); + /* sets up EOF and ORIE */ + switch (eof) { + case FC_EOF_N: + fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_EOF_N; + break; + case FC_EOF_T: + /* lso needs ORIE */ + if (skb_is_gso(skb)) { + fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_EOF_N; + fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_ORIE; + } else { + fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_EOF_T; + } + break; + case FC_EOF_NI: + fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_EOF_NI; + break; + case FC_EOF_A: + fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_EOF_A; + break; + default: + DPRINTK(DRV, WARNING, "unknown eof = 0x%x\n", eof); + return -EINVAL; + } + + /* sets up PARINC indicating data offset */ + fh = (struct fc_frame_header *)skb_transport_header(skb); + if (fh->fh_f_ctl[2] & FC_FC_REL_OFF) + fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_PARINC; + + /* hdr_len includes fc_hdr if FCoE lso is enabled */ + *hdr_len = sizeof(struct fcoe_crc_eof); + if (skb_is_gso(skb)) + *hdr_len += (skb_transport_offset(skb) + + sizeof(struct fc_frame_header)); + /* vlan_macip_lens: HEADLEN, MACLEN, VLAN tag */ + vlan_macip_lens = (skb_transport_offset(skb) + + sizeof(struct fc_frame_header)); + vlan_macip_lens |= ((skb_transport_offset(skb) - 4) + << IXGBE_ADVTXD_MACLEN_SHIFT); + vlan_macip_lens |= (tx_flags & IXGBE_TX_FLAGS_VLAN_MASK); + + /* type_tycmd and mss: set TUCMD.FCoE to enable offload */ + type_tucmd = IXGBE_TXD_CMD_DEXT | IXGBE_ADVTXD_DTYP_CTXT | + IXGBE_ADVTXT_TUCMD_FCOE; + if (skb_is_gso(skb)) + mss = skb_shinfo(skb)->gso_size; + /* mss_l4len_id: use 1 for FSO as TSO, no need for L4LEN */ + mss_l4len_idx = (mss << IXGBE_ADVTXD_MSS_SHIFT) | + (1 << IXGBE_ADVTXD_IDX_SHIFT); + + /* write context desc */ + i = tx_ring->next_to_use; + context_desc = IXGBE_TX_CTXTDESC_ADV(*tx_ring, i); + context_desc->vlan_macip_lens = cpu_to_le32(vlan_macip_lens); + context_desc->seqnum_seed = cpu_to_le32(fcoe_sof_eof); + context_desc->type_tucmd_mlhl = cpu_to_le32(type_tucmd); + context_desc->mss_l4len_idx = cpu_to_le32(mss_l4len_idx); + + tx_buffer_info = &tx_ring->tx_buffer_info[i]; + tx_buffer_info->time_stamp = jiffies; + tx_buffer_info->next_to_watch = i; + + i++; + if (i == tx_ring->count) + i = 0; + tx_ring->next_to_use = i; + + return skb_is_gso(skb); +} + +/** + * ixgbe_configure_fcoe - configures registers for fcoe at start + * @adapter: ptr to ixgbe adapter + * + * This sets up FCoE related registers + * + * Returns : none + */ +void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter) +{ + int i, fcoe_q, fcoe_i; + struct ixgbe_hw *hw = &adapter->hw; + struct ixgbe_fcoe *fcoe = &adapter->fcoe; + struct ixgbe_ring_feature *f = &adapter->ring_feature[RING_F_FCOE]; + + /* create the pool for ddp if not created yet */ + if (!fcoe->pool) { + /* allocate ddp pool */ + fcoe->pool = pci_pool_create("ixgbe_fcoe_ddp", + adapter->pdev, IXGBE_FCPTR_MAX, + IXGBE_FCPTR_ALIGN, PAGE_SIZE); + if (!fcoe->pool) + DPRINTK(DRV, ERR, + "failed to allocated FCoE DDP pool\n"); + + spin_lock_init(&fcoe->lock); + } + + /* Enable L2 eth type filter for FCoE */ + IXGBE_WRITE_REG(hw, IXGBE_ETQF(IXGBE_ETQF_FILTER_FCOE), + (ETH_P_FCOE | IXGBE_ETQF_FCOE | IXGBE_ETQF_FILTER_EN)); + if (adapter->ring_feature[RING_F_FCOE].indices) { + /* Use multiple rx queues for FCoE by redirection table */ + for (i = 0; i < IXGBE_FCRETA_SIZE; i++) { + fcoe_i = f->mask + i % f->indices; + fcoe_i &= IXGBE_FCRETA_ENTRY_MASK; + fcoe_q = adapter->rx_ring[fcoe_i].reg_idx; + IXGBE_WRITE_REG(hw, IXGBE_FCRETA(i), fcoe_q); + } + IXGBE_WRITE_REG(hw, IXGBE_FCRECTL, IXGBE_FCRECTL_ENA); + IXGBE_WRITE_REG(hw, IXGBE_ETQS(IXGBE_ETQF_FILTER_FCOE), 0); + } else { + /* Use single rx queue for FCoE */ + fcoe_i = f->mask; + fcoe_q = adapter->rx_ring[fcoe_i].reg_idx; + IXGBE_WRITE_REG(hw, IXGBE_FCRECTL, 0); + IXGBE_WRITE_REG(hw, IXGBE_ETQS(IXGBE_ETQF_FILTER_FCOE), + IXGBE_ETQS_QUEUE_EN | + (fcoe_q << IXGBE_ETQS_RX_QUEUE_SHIFT)); + } + + IXGBE_WRITE_REG(hw, IXGBE_FCRXCTRL, + IXGBE_FCRXCTRL_FCOELLI | + IXGBE_FCRXCTRL_FCCRCBO | + (FC_FCOE_VER << IXGBE_FCRXCTRL_FCOEVER_SHIFT)); +} + +/** + * ixgbe_cleanup_fcoe - release all fcoe ddp context resources + * @adapter : ixgbe adapter + * + * Cleans up outstanding ddp context resources + * + * Returns : none + */ +void ixgbe_cleanup_fcoe(struct ixgbe_adapter *adapter) +{ + int i; + struct ixgbe_fcoe *fcoe = &adapter->fcoe; + + /* release ddp resource */ + if (fcoe->pool) { + for (i = 0; i < IXGBE_FCOE_DDP_MAX; i++) + ixgbe_fcoe_ddp_put(adapter->netdev, i); + pci_pool_destroy(fcoe->pool); + fcoe->pool = NULL; + } +} diff --git a/drivers/net/ixgbe/ixgbe_fcoe.h b/drivers/net/ixgbe/ixgbe_fcoe.h new file mode 100644 index 000000000000..c5b50026a897 --- /dev/null +++ b/drivers/net/ixgbe/ixgbe_fcoe.h @@ -0,0 +1,67 @@ +/******************************************************************************* + + Intel 10 Gigabit PCI Express Linux driver + Copyright(c) 1999 - 2009 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#ifndef _IXGBE_FCOE_H +#define _IXGBE_FCOE_H + +#include +#include + +/* shift bits within STAT fo FCSTAT */ +#define IXGBE_RXDADV_FCSTAT_SHIFT 4 + +/* ddp user buffer */ +#define IXGBE_BUFFCNT_MAX 256 /* 8 bits bufcnt */ +#define IXGBE_FCPTR_ALIGN 16 +#define IXGBE_FCPTR_MAX (IXGBE_BUFFCNT_MAX * sizeof(dma_addr_t)) +#define IXGBE_FCBUFF_4KB 0x0 +#define IXGBE_FCBUFF_8KB 0x1 +#define IXGBE_FCBUFF_16KB 0x2 +#define IXGBE_FCBUFF_64KB 0x3 +#define IXGBE_FCBUFF_MAX 65536 /* 64KB max */ +#define IXGBE_FCBUFF_MIN 4096 /* 4KB min */ +#define IXGBE_FCOE_DDP_MAX 512 /* 9 bits xid */ + +/* fcerr */ +#define IXGBE_FCERR_BADCRC 0x00100000 + +struct ixgbe_fcoe_ddp { + int len; + u32 err; + unsigned int sgc; + struct scatterlist *sgl; + dma_addr_t udp; + u64 *udl; +}; + +struct ixgbe_fcoe { + spinlock_t lock; + struct pci_pool *pool; + struct ixgbe_fcoe_ddp ddp[IXGBE_FCOE_DDP_MAX]; +}; + +#endif /* _IXGBE_FCOE_H */ diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 07e778d3e5d2..e756e220db32 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -39,6 +39,7 @@ #include #include #include +#include #include "ixgbe.h" #include "ixgbe_common.h" @@ -47,7 +48,7 @@ char ixgbe_driver_name[] = "ixgbe"; static const char ixgbe_driver_string[] = "Intel(R) 10 Gigabit PCI Express Network Driver"; -#define DRV_VERSION "2.0.8-k2" +#define DRV_VERSION "2.0.34-k2" const char ixgbe_driver_version[] = DRV_VERSION; static char ixgbe_copyright[] = "Copyright (c) 1999-2009 Intel Corporation."; @@ -89,6 +90,8 @@ static struct pci_device_id ixgbe_pci_tbl[] = { board_82598 }, {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_KX4), board_82599 }, + {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_XAUI_LOM), + board_82599 }, {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_SFP), board_82599 }, @@ -183,6 +186,22 @@ static void ixgbe_set_ivar(struct ixgbe_adapter *adapter, s8 direction, } } +static inline void ixgbe_irq_rearm_queues(struct ixgbe_adapter *adapter, + u64 qmask) +{ + u32 mask; + + if (adapter->hw.mac.type == ixgbe_mac_82598EB) { + mask = (IXGBE_EIMS_RTX_QUEUE & qmask); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, mask); + } else { + mask = (qmask & 0xFFFFFFFF); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS_EX(0), mask); + mask = (qmask >> 32); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS_EX(1), mask); + } +} + static void ixgbe_unmap_and_free_tx_resource(struct ixgbe_adapter *adapter, struct ixgbe_tx_buffer *tx_buffer_info) @@ -245,14 +264,13 @@ static void ixgbe_tx_timeout(struct net_device *netdev); /** * ixgbe_clean_tx_irq - Reclaim resources after transmit completes - * @adapter: board private structure + * @q_vector: structure containing interrupt and ring information * @tx_ring: tx ring to clean - * - * returns true if transmit work is done **/ -static bool ixgbe_clean_tx_irq(struct ixgbe_adapter *adapter, +static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector, struct ixgbe_ring *tx_ring) { + struct ixgbe_adapter *adapter = q_vector->adapter; struct net_device *netdev = adapter->netdev; union ixgbe_adv_tx_desc *tx_desc, *eop_desc; struct ixgbe_tx_buffer *tx_buffer_info; @@ -275,12 +293,24 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_adapter *adapter, if (cleaned && skb) { unsigned int segs, bytecount; + unsigned int hlen = skb_headlen(skb); /* gso_segs is currently only valid for tcp */ segs = skb_shinfo(skb)->gso_segs ?: 1; +#ifdef IXGBE_FCOE + /* adjust for FCoE Sequence Offload */ + if ((adapter->flags & IXGBE_FLAG_FCOE_ENABLED) + && (skb->protocol == htons(ETH_P_FCOE)) && + skb_is_gso(skb)) { + hlen = skb_transport_offset(skb) + + sizeof(struct fc_frame_header) + + sizeof(struct fcoe_crc_eof); + segs = DIV_ROUND_UP(skb->len - hlen, + skb_shinfo(skb)->gso_size); + } +#endif /* IXGBE_FCOE */ /* multiply data chunks by size of headers */ - bytecount = ((segs - 1) * skb_headlen(skb)) + - skb->len; + bytecount = ((segs - 1) * hlen) + skb->len; total_packets += segs; total_bytes += bytecount; } @@ -327,7 +357,7 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_adapter *adapter, /* re-arm the interrupt */ if (count >= tx_ring->work_limit) - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, tx_ring->v_idx); + ixgbe_irq_rearm_queues(adapter, ((u64)1 << q_vector->v_idx)); tx_ring->total_bytes += total_bytes; tx_ring->total_packets += total_packets; @@ -398,6 +428,9 @@ static void ixgbe_setup_dca(struct ixgbe_adapter *adapter) if (!(adapter->flags & IXGBE_FLAG_DCA_ENABLED)) return; + /* always use CB2 mode, difference is masked in the CB driver */ + IXGBE_WRITE_REG(&adapter->hw, IXGBE_DCA_CTRL, 2); + for (i = 0; i < adapter->num_tx_queues; i++) { adapter->tx_ring[i].cpu = -1; ixgbe_update_tx_dca(adapter, &adapter->tx_ring[i]); @@ -419,9 +452,6 @@ static int __ixgbe_notify_dca(struct device *dev, void *data) /* if we're already enabled, don't do it again */ if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) break; - /* Always use CB2 mode, difference is masked - * in the CB driver. */ - IXGBE_WRITE_REG(&adapter->hw, IXGBE_DCA_CTRL, 2); if (dca_add_requester(dev) == 0) { adapter->flags |= IXGBE_FLAG_DCA_ENABLED; ixgbe_setup_dca(adapter); @@ -451,6 +481,7 @@ static int __ixgbe_notify_dca(struct device *dev, void *data) **/ static void ixgbe_receive_skb(struct ixgbe_q_vector *q_vector, struct sk_buff *skb, u8 status, + struct ixgbe_ring *ring, union ixgbe_adv_rx_desc *rx_desc) { struct ixgbe_adapter *adapter = q_vector->adapter; @@ -458,24 +489,17 @@ static void ixgbe_receive_skb(struct ixgbe_q_vector *q_vector, bool is_vlan = (status & IXGBE_RXD_STAT_VP); u16 tag = le16_to_cpu(rx_desc->wb.upper.vlan); - skb_record_rx_queue(skb, q_vector - &adapter->q_vector[0]); - if (skb->ip_summed == CHECKSUM_UNNECESSARY) { + skb_record_rx_queue(skb, ring->queue_index); + if (!(adapter->flags & IXGBE_FLAG_IN_NETPOLL)) { if (adapter->vlgrp && is_vlan && (tag != 0)) vlan_gro_receive(napi, adapter->vlgrp, tag, skb); else napi_gro_receive(napi, skb); } else { - if (!(adapter->flags & IXGBE_FLAG_IN_NETPOLL)) { - if (adapter->vlgrp && is_vlan && (tag != 0)) - vlan_hwaccel_receive_skb(skb, adapter->vlgrp, tag); - else - netif_receive_skb(skb); - } else { - if (adapter->vlgrp && is_vlan && (tag != 0)) - vlan_hwaccel_rx(skb, adapter->vlgrp, tag); - else - netif_rx(skb); - } + if (adapter->vlgrp && is_vlan && (tag != 0)) + vlan_hwaccel_rx(skb, adapter->vlgrp, tag); + else + netif_rx(skb); } } @@ -622,6 +646,40 @@ static inline u16 ixgbe_get_pkt_info(union ixgbe_adv_rx_desc *rx_desc) return rx_desc->wb.lower.lo_dword.hs_rss.pkt_info; } +static inline u32 ixgbe_get_rsc_count(union ixgbe_adv_rx_desc *rx_desc) +{ + return (le32_to_cpu(rx_desc->wb.lower.lo_dword.data) & + IXGBE_RXDADV_RSCCNT_MASK) >> + IXGBE_RXDADV_RSCCNT_SHIFT; +} + +/** + * ixgbe_transform_rsc_queue - change rsc queue into a full packet + * @skb: pointer to the last skb in the rsc queue + * + * This function changes a queue full of hw rsc buffers into a completed + * packet. It uses the ->prev pointers to find the first packet and then + * turns it into the frag list owner. + **/ +static inline struct sk_buff *ixgbe_transform_rsc_queue(struct sk_buff *skb) +{ + unsigned int frag_list_size = 0; + + while (skb->prev) { + struct sk_buff *prev = skb->prev; + frag_list_size += skb->len; + skb->prev = NULL; + skb = prev; + } + + skb_shinfo(skb)->frag_list = skb->next; + skb->next = NULL; + skb->len += frag_list_size; + skb->data_len += frag_list_size; + skb->truesize += frag_list_size; + return skb; +} + static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector, struct ixgbe_ring *rx_ring, int *work_done, int work_to_do) @@ -631,12 +689,15 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector, union ixgbe_adv_rx_desc *rx_desc, *next_rxd; struct ixgbe_rx_buffer *rx_buffer_info, *next_buffer; struct sk_buff *skb; - unsigned int i; + unsigned int i, rsc_count = 0; u32 len, staterr; u16 hdr_info; bool cleaned = false; int cleaned_count = 0; unsigned int total_rx_bytes = 0, total_rx_packets = 0; +#ifdef IXGBE_FCOE + int ddp_bytes = 0; +#endif /* IXGBE_FCOE */ i = rx_ring->next_to_clean; rx_desc = IXGBE_RX_DESC_ADV(*rx_ring, i); @@ -667,7 +728,7 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector, prefetch(skb->data - NET_IP_ALIGN); rx_buffer_info->skb = NULL; - if (len && !skb_shinfo(skb)->nr_frags) { + if (rx_buffer_info->dma) { pci_unmap_single(pdev, rx_buffer_info->dma, rx_ring->rx_buf_len, PCI_DMA_FROMDEVICE); @@ -697,20 +758,38 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector, i++; if (i == rx_ring->count) i = 0; - next_buffer = &rx_ring->rx_buffer_info[i]; next_rxd = IXGBE_RX_DESC_ADV(*rx_ring, i); prefetch(next_rxd); - cleaned_count++; + + if (adapter->flags & IXGBE_FLAG2_RSC_CAPABLE) + rsc_count = ixgbe_get_rsc_count(rx_desc); + + if (rsc_count) { + u32 nextp = (staterr & IXGBE_RXDADV_NEXTP_MASK) >> + IXGBE_RXDADV_NEXTP_SHIFT; + next_buffer = &rx_ring->rx_buffer_info[nextp]; + rx_ring->rsc_count += (rsc_count - 1); + } else { + next_buffer = &rx_ring->rx_buffer_info[i]; + } + if (staterr & IXGBE_RXD_STAT_EOP) { + if (skb->prev) + skb = ixgbe_transform_rsc_queue(skb); rx_ring->stats.packets++; rx_ring->stats.bytes += skb->len; } else { - rx_buffer_info->skb = next_buffer->skb; - rx_buffer_info->dma = next_buffer->dma; - next_buffer->skb = skb; - next_buffer->dma = 0; + if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) { + rx_buffer_info->skb = next_buffer->skb; + rx_buffer_info->dma = next_buffer->dma; + next_buffer->skb = skb; + next_buffer->dma = 0; + } else { + skb->next = next_buffer->skb; + skb->next->prev = skb; + } adapter->non_eop_descs++; goto next_desc; } @@ -727,7 +806,15 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector, total_rx_packets++; skb->protocol = eth_type_trans(skb, adapter->netdev); - ixgbe_receive_skb(q_vector, skb, staterr, rx_desc); +#ifdef IXGBE_FCOE + /* if ddp, not passing to ULD unless for FCP_RSP or error */ + if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) { + ddp_bytes = ixgbe_fcoe_ddp(adapter, rx_desc, skb); + if (!ddp_bytes) + goto next_desc; + } +#endif /* IXGBE_FCOE */ + ixgbe_receive_skb(q_vector, skb, staterr, rx_ring, rx_desc); next_desc: rx_desc->wb.upper.status_error = 0; @@ -740,7 +827,7 @@ next_desc: /* use prefetched values */ rx_desc = next_rxd; - rx_buffer_info = next_buffer; + rx_buffer_info = &rx_ring->rx_buffer_info[i]; staterr = le32_to_cpu(rx_desc->wb.upper.status_error); } @@ -751,6 +838,21 @@ next_desc: if (cleaned_count) ixgbe_alloc_rx_buffers(adapter, rx_ring, cleaned_count); +#ifdef IXGBE_FCOE + /* include DDPed FCoE data */ + if (ddp_bytes > 0) { + unsigned int mss; + + mss = adapter->netdev->mtu - sizeof(struct fcoe_hdr) - + sizeof(struct fc_frame_header) - + sizeof(struct fcoe_crc_eof); + if (mss > 512) + mss &= ~511; + total_rx_bytes += ddp_bytes; + total_rx_packets += DIV_ROUND_UP(ddp_bytes, mss); + } +#endif /* IXGBE_FCOE */ + rx_ring->total_packets += total_rx_packets; rx_ring->total_bytes += total_rx_bytes; adapter->net_stats.rx_bytes += total_rx_bytes; @@ -780,7 +882,7 @@ static void ixgbe_configure_msix(struct ixgbe_adapter *adapter) * corresponding register. */ for (v_idx = 0; v_idx < q_vectors; v_idx++) { - q_vector = &adapter->q_vector[v_idx]; + q_vector = adapter->q_vector[v_idx]; /* XXX for_each_bit(...) */ r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues); @@ -810,12 +912,7 @@ static void ixgbe_configure_msix(struct ixgbe_adapter *adapter) /* rx only */ q_vector->eitr = adapter->eitr_param; - /* - * since this is initial set up don't need to call - * ixgbe_write_eitr helper - */ - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EITR(v_idx), - EITR_INTS_PER_SEC_TO_REG(q_vector->eitr)); + ixgbe_write_eitr(q_vector); } if (adapter->hw.mac.type == ixgbe_mac_82598EB) @@ -900,17 +997,19 @@ update_itr_done: /** * ixgbe_write_eitr - write EITR register in hardware specific way - * @adapter: pointer to adapter struct - * @v_idx: vector index into q_vector array - * @itr_reg: new value to be written in *register* format, not ints/s + * @q_vector: structure containing interrupt and ring information * * This function is made to be called by ethtool and by the driver * when it needs to update EITR registers at runtime. Hardware * specific quirks/differences are taken care of here. */ -void ixgbe_write_eitr(struct ixgbe_adapter *adapter, int v_idx, u32 itr_reg) +void ixgbe_write_eitr(struct ixgbe_q_vector *q_vector) { + struct ixgbe_adapter *adapter = q_vector->adapter; struct ixgbe_hw *hw = &adapter->hw; + int v_idx = q_vector->v_idx; + u32 itr_reg = EITR_INTS_PER_SEC_TO_REG(q_vector->eitr); + if (adapter->hw.mac.type == ixgbe_mac_82598EB) { /* must write high and low 16 bits to reset counter */ itr_reg |= (itr_reg << 16); @@ -929,8 +1028,7 @@ static void ixgbe_set_itr_msix(struct ixgbe_q_vector *q_vector) struct ixgbe_adapter *adapter = q_vector->adapter; u32 new_itr; u8 current_itr, ret_itr; - int i, r_idx, v_idx = ((void *)q_vector - (void *)(adapter->q_vector)) / - sizeof(struct ixgbe_q_vector); + int i, r_idx; struct ixgbe_ring *rx_ring, *tx_ring; r_idx = find_first_bit(q_vector->txr_idx, adapter->num_tx_queues); @@ -980,14 +1078,13 @@ static void ixgbe_set_itr_msix(struct ixgbe_q_vector *q_vector) } if (new_itr != q_vector->eitr) { - u32 itr_reg; + /* do an exponential smoothing */ + new_itr = ((q_vector->eitr * 90)/100) + ((new_itr * 10)/100); /* save the algorithm value here, not the smoothed one */ q_vector->eitr = new_itr; - /* do an exponential smoothing */ - new_itr = ((q_vector->eitr * 90)/100) + ((new_itr * 10)/100); - itr_reg = EITR_INTS_PER_SEC_TO_REG(new_itr); - ixgbe_write_eitr(adapter, v_idx, itr_reg); + + ixgbe_write_eitr(q_vector); } return; @@ -1058,14 +1155,64 @@ static irqreturn_t ixgbe_msix_lsc(int irq, void *data) if (hw->mac.type == ixgbe_mac_82598EB) ixgbe_check_fan_failure(adapter, eicr); - if (hw->mac.type == ixgbe_mac_82599EB) + if (hw->mac.type == ixgbe_mac_82599EB) { ixgbe_check_sfp_event(adapter, eicr); + + /* Handle Flow Director Full threshold interrupt */ + if (eicr & IXGBE_EICR_FLOW_DIR) { + int i; + IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_FLOW_DIR); + /* Disable transmits before FDIR Re-initialization */ + netif_tx_stop_all_queues(netdev); + for (i = 0; i < adapter->num_tx_queues; i++) { + struct ixgbe_ring *tx_ring = + &adapter->tx_ring[i]; + if (test_and_clear_bit(__IXGBE_FDIR_INIT_DONE, + &tx_ring->reinit_state)) + schedule_work(&adapter->fdir_reinit_task); + } + } + } if (!test_bit(__IXGBE_DOWN, &adapter->state)) IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_OTHER); return IRQ_HANDLED; } +static inline void ixgbe_irq_enable_queues(struct ixgbe_adapter *adapter, + u64 qmask) +{ + u32 mask; + + if (adapter->hw.mac.type == ixgbe_mac_82598EB) { + mask = (IXGBE_EIMS_RTX_QUEUE & qmask); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, mask); + } else { + mask = (qmask & 0xFFFFFFFF); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS_EX(0), mask); + mask = (qmask >> 32); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS_EX(1), mask); + } + /* skip the flush */ +} + +static inline void ixgbe_irq_disable_queues(struct ixgbe_adapter *adapter, + u64 qmask) +{ + u32 mask; + + if (adapter->hw.mac.type == ixgbe_mac_82598EB) { + mask = (IXGBE_EIMS_RTX_QUEUE & qmask); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, mask); + } else { + mask = (qmask & 0xFFFFFFFF); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(0), mask); + mask = (qmask >> 32); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(1), mask); + } + /* skip the flush */ +} + static irqreturn_t ixgbe_msix_clean_tx(int irq, void *data) { struct ixgbe_q_vector *q_vector = data; @@ -1079,17 +1226,16 @@ static irqreturn_t ixgbe_msix_clean_tx(int irq, void *data) r_idx = find_first_bit(q_vector->txr_idx, adapter->num_tx_queues); for (i = 0; i < q_vector->txr_count; i++) { tx_ring = &(adapter->tx_ring[r_idx]); -#ifdef CONFIG_IXGBE_DCA - if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) - ixgbe_update_tx_dca(adapter, tx_ring); -#endif tx_ring->total_bytes = 0; tx_ring->total_packets = 0; - ixgbe_clean_tx_irq(adapter, tx_ring); r_idx = find_next_bit(q_vector->txr_idx, adapter->num_tx_queues, r_idx + 1); } + /* disable interrupts on this vector only */ + ixgbe_irq_disable_queues(adapter, ((u64)1 << q_vector->v_idx)); + napi_schedule(&q_vector->napi); + return IRQ_HANDLED; } @@ -1121,7 +1267,7 @@ static irqreturn_t ixgbe_msix_clean_rx(int irq, void *data) r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues); rx_ring = &(adapter->rx_ring[r_idx]); /* disable interrupts on this vector only */ - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, rx_ring->v_idx); + ixgbe_irq_disable_queues(adapter, ((u64)1 << q_vector->v_idx)); napi_schedule(&q_vector->napi); return IRQ_HANDLED; @@ -1129,8 +1275,36 @@ static irqreturn_t ixgbe_msix_clean_rx(int irq, void *data) static irqreturn_t ixgbe_msix_clean_many(int irq, void *data) { - ixgbe_msix_clean_rx(irq, data); - ixgbe_msix_clean_tx(irq, data); + struct ixgbe_q_vector *q_vector = data; + struct ixgbe_adapter *adapter = q_vector->adapter; + struct ixgbe_ring *ring; + int r_idx; + int i; + + if (!q_vector->txr_count && !q_vector->rxr_count) + return IRQ_HANDLED; + + r_idx = find_first_bit(q_vector->txr_idx, adapter->num_tx_queues); + for (i = 0; i < q_vector->txr_count; i++) { + ring = &(adapter->tx_ring[r_idx]); + ring->total_bytes = 0; + ring->total_packets = 0; + r_idx = find_next_bit(q_vector->txr_idx, adapter->num_tx_queues, + r_idx + 1); + } + + r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues); + for (i = 0; i < q_vector->rxr_count; i++) { + ring = &(adapter->rx_ring[r_idx]); + ring->total_bytes = 0; + ring->total_packets = 0; + r_idx = find_next_bit(q_vector->rxr_idx, adapter->num_rx_queues, + r_idx + 1); + } + + /* disable interrupts on this vector only */ + ixgbe_irq_disable_queues(adapter, ((u64)1 << q_vector->v_idx)); + napi_schedule(&q_vector->napi); return IRQ_HANDLED; } @@ -1167,29 +1341,42 @@ static int ixgbe_clean_rxonly(struct napi_struct *napi, int budget) if (adapter->itr_setting & 1) ixgbe_set_itr_msix(q_vector); if (!test_bit(__IXGBE_DOWN, &adapter->state)) - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, rx_ring->v_idx); + ixgbe_irq_enable_queues(adapter, + ((u64)1 << q_vector->v_idx)); } return work_done; } /** - * ixgbe_clean_rxonly_many - msix (aka one shot) rx clean routine + * ixgbe_clean_rxtx_many - msix (aka one shot) rx clean routine * @napi: napi struct with our devices info in it * @budget: amount of work driver is allowed to do this pass, in packets * * This function will clean more than one rx queue associated with a * q_vector. **/ -static int ixgbe_clean_rxonly_many(struct napi_struct *napi, int budget) +static int ixgbe_clean_rxtx_many(struct napi_struct *napi, int budget) { struct ixgbe_q_vector *q_vector = container_of(napi, struct ixgbe_q_vector, napi); struct ixgbe_adapter *adapter = q_vector->adapter; - struct ixgbe_ring *rx_ring = NULL; + struct ixgbe_ring *ring = NULL; int work_done = 0, i; long r_idx; - u16 enable_mask = 0; + bool tx_clean_complete = true; + + r_idx = find_first_bit(q_vector->txr_idx, adapter->num_tx_queues); + for (i = 0; i < q_vector->txr_count; i++) { + ring = &(adapter->tx_ring[r_idx]); +#ifdef CONFIG_IXGBE_DCA + if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) + ixgbe_update_tx_dca(adapter, ring); +#endif + tx_clean_complete &= ixgbe_clean_tx_irq(q_vector, ring); + r_idx = find_next_bit(q_vector->txr_idx, adapter->num_tx_queues, + r_idx + 1); + } /* attempt to distribute budget to each queue fairly, but don't allow * the budget to go below 1 because we'll exit polling */ @@ -1197,47 +1384,87 @@ static int ixgbe_clean_rxonly_many(struct napi_struct *napi, int budget) budget = max(budget, 1); r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues); for (i = 0; i < q_vector->rxr_count; i++) { - rx_ring = &(adapter->rx_ring[r_idx]); + ring = &(adapter->rx_ring[r_idx]); #ifdef CONFIG_IXGBE_DCA if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) - ixgbe_update_rx_dca(adapter, rx_ring); + ixgbe_update_rx_dca(adapter, ring); #endif - ixgbe_clean_rx_irq(q_vector, rx_ring, &work_done, budget); - enable_mask |= rx_ring->v_idx; + ixgbe_clean_rx_irq(q_vector, ring, &work_done, budget); r_idx = find_next_bit(q_vector->rxr_idx, adapter->num_rx_queues, r_idx + 1); } r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues); - rx_ring = &(adapter->rx_ring[r_idx]); + ring = &(adapter->rx_ring[r_idx]); /* If all Rx work done, exit the polling mode */ if (work_done < budget) { napi_complete(napi); if (adapter->itr_setting & 1) ixgbe_set_itr_msix(q_vector); if (!test_bit(__IXGBE_DOWN, &adapter->state)) - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, enable_mask); + ixgbe_irq_enable_queues(adapter, + ((u64)1 << q_vector->v_idx)); return 0; } return work_done; } + +/** + * ixgbe_clean_txonly - msix (aka one shot) tx clean routine + * @napi: napi struct with our devices info in it + * @budget: amount of work driver is allowed to do this pass, in packets + * + * This function is optimized for cleaning one queue only on a single + * q_vector!!! + **/ +static int ixgbe_clean_txonly(struct napi_struct *napi, int budget) +{ + struct ixgbe_q_vector *q_vector = + container_of(napi, struct ixgbe_q_vector, napi); + struct ixgbe_adapter *adapter = q_vector->adapter; + struct ixgbe_ring *tx_ring = NULL; + int work_done = 0; + long r_idx; + + r_idx = find_first_bit(q_vector->txr_idx, adapter->num_tx_queues); + tx_ring = &(adapter->tx_ring[r_idx]); +#ifdef CONFIG_IXGBE_DCA + if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) + ixgbe_update_tx_dca(adapter, tx_ring); +#endif + + if (!ixgbe_clean_tx_irq(q_vector, tx_ring)) + work_done = budget; + + /* If all Rx work done, exit the polling mode */ + if (work_done < budget) { + napi_complete(napi); + if (adapter->itr_setting & 1) + ixgbe_set_itr_msix(q_vector); + if (!test_bit(__IXGBE_DOWN, &adapter->state)) + ixgbe_irq_enable_queues(adapter, ((u64)1 << q_vector->v_idx)); + } + + return work_done; +} + static inline void map_vector_to_rxq(struct ixgbe_adapter *a, int v_idx, int r_idx) { - a->q_vector[v_idx].adapter = a; - set_bit(r_idx, a->q_vector[v_idx].rxr_idx); - a->q_vector[v_idx].rxr_count++; - a->rx_ring[r_idx].v_idx = 1 << v_idx; + struct ixgbe_q_vector *q_vector = a->q_vector[v_idx]; + + set_bit(r_idx, q_vector->rxr_idx); + q_vector->rxr_count++; } static inline void map_vector_to_txq(struct ixgbe_adapter *a, int v_idx, - int r_idx) + int t_idx) { - a->q_vector[v_idx].adapter = a; - set_bit(r_idx, a->q_vector[v_idx].txr_idx); - a->q_vector[v_idx].txr_count++; - a->tx_ring[r_idx].v_idx = 1 << v_idx; + struct ixgbe_q_vector *q_vector = a->q_vector[v_idx]; + + set_bit(t_idx, q_vector->txr_idx); + q_vector->txr_count++; } /** @@ -1333,7 +1560,7 @@ static int ixgbe_request_msix_irqs(struct ixgbe_adapter *adapter) (!(_v)->txr_count) ? &ixgbe_msix_clean_rx : \ &ixgbe_msix_clean_many) for (vector = 0; vector < q_vectors; vector++) { - handler = SET_HANDLER(&adapter->q_vector[vector]); + handler = SET_HANDLER(adapter->q_vector[vector]); if(handler == &ixgbe_msix_clean_rx) { sprintf(adapter->name[vector], "%s-%s-%d", @@ -1349,7 +1576,7 @@ static int ixgbe_request_msix_irqs(struct ixgbe_adapter *adapter) err = request_irq(adapter->msix_entries[vector].vector, handler, 0, adapter->name[vector], - &(adapter->q_vector[vector])); + adapter->q_vector[vector]); if (err) { DPRINTK(PROBE, ERR, "request_irq failed for MSIX interrupt " @@ -1372,7 +1599,7 @@ static int ixgbe_request_msix_irqs(struct ixgbe_adapter *adapter) free_queue_irqs: for (i = vector - 1; i >= 0; i--) free_irq(adapter->msix_entries[--vector].vector, - &(adapter->q_vector[i])); + adapter->q_vector[i]); adapter->flags &= ~IXGBE_FLAG_MSIX_ENABLED; pci_disable_msix(adapter->pdev); kfree(adapter->msix_entries); @@ -1383,7 +1610,7 @@ out: static void ixgbe_set_itr(struct ixgbe_adapter *adapter) { - struct ixgbe_q_vector *q_vector = adapter->q_vector; + struct ixgbe_q_vector *q_vector = adapter->q_vector[0]; u8 current_itr; u32 new_itr = q_vector->eitr; struct ixgbe_ring *rx_ring = &adapter->rx_ring[0]; @@ -1416,14 +1643,13 @@ static void ixgbe_set_itr(struct ixgbe_adapter *adapter) } if (new_itr != q_vector->eitr) { - u32 itr_reg; + /* do an exponential smoothing */ + new_itr = ((q_vector->eitr * 90)/100) + ((new_itr * 10)/100); /* save the algorithm value here, not the smoothed one */ q_vector->eitr = new_itr; - /* do an exponential smoothing */ - new_itr = ((q_vector->eitr * 90)/100) + ((new_itr * 10)/100); - itr_reg = EITR_INTS_PER_SEC_TO_REG(new_itr); - ixgbe_write_eitr(adapter, 0, itr_reg); + + ixgbe_write_eitr(q_vector); } return; @@ -1436,7 +1662,8 @@ static void ixgbe_set_itr(struct ixgbe_adapter *adapter) static inline void ixgbe_irq_enable(struct ixgbe_adapter *adapter) { u32 mask; - mask = IXGBE_EIMS_ENABLE_MASK; + + mask = (IXGBE_EIMS_ENABLE_MASK & ~IXGBE_EIMS_RTX_QUEUE); if (adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE) mask |= IXGBE_EIMS_GPI_SDP1; if (adapter->hw.mac.type == ixgbe_mac_82599EB) { @@ -1444,16 +1671,12 @@ static inline void ixgbe_irq_enable(struct ixgbe_adapter *adapter) mask |= IXGBE_EIMS_GPI_SDP1; mask |= IXGBE_EIMS_GPI_SDP2; } + if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE || + adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE) + mask |= IXGBE_EIMS_FLOW_DIR; IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, mask); - if (adapter->hw.mac.type == ixgbe_mac_82599EB) { - /* enable the rest of the queue vectors */ - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS_EX(1), - (IXGBE_EIMS_RTX_QUEUE << 16)); - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS_EX(2), - ((IXGBE_EIMS_RTX_QUEUE << 16) | - IXGBE_EIMS_RTX_QUEUE)); - } + ixgbe_irq_enable_queues(adapter, ~0); IXGBE_WRITE_FLUSH(&adapter->hw); } @@ -1467,6 +1690,7 @@ static irqreturn_t ixgbe_intr(int irq, void *data) struct net_device *netdev = data; struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_hw *hw = &adapter->hw; + struct ixgbe_q_vector *q_vector = adapter->q_vector[0]; u32 eicr; /* @@ -1494,13 +1718,13 @@ static irqreturn_t ixgbe_intr(int irq, void *data) ixgbe_check_fan_failure(adapter, eicr); - if (napi_schedule_prep(&adapter->q_vector[0].napi)) { + if (napi_schedule_prep(&(q_vector->napi))) { adapter->tx_ring[0].total_packets = 0; adapter->tx_ring[0].total_bytes = 0; adapter->rx_ring[0].total_packets = 0; adapter->rx_ring[0].total_bytes = 0; /* would disable interrupts here but EIAM disabled it */ - __napi_schedule(&adapter->q_vector[0].napi); + __napi_schedule(&(q_vector->napi)); } return IRQ_HANDLED; @@ -1511,7 +1735,7 @@ static inline void ixgbe_reset_q_vectors(struct ixgbe_adapter *adapter) int i, q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS; for (i = 0; i < q_vectors; i++) { - struct ixgbe_q_vector *q_vector = &adapter->q_vector[i]; + struct ixgbe_q_vector *q_vector = adapter->q_vector[i]; bitmap_zero(q_vector->rxr_idx, MAX_RX_QUEUES); bitmap_zero(q_vector->txr_idx, MAX_TX_QUEUES); q_vector->rxr_count = 0; @@ -1562,7 +1786,7 @@ static void ixgbe_free_irq(struct ixgbe_adapter *adapter) i--; for (; i >= 0; i--) { free_irq(adapter->msix_entries[i].vector, - &(adapter->q_vector[i])); + adapter->q_vector[i]); } ixgbe_reset_q_vectors(adapter); @@ -1577,10 +1801,12 @@ static void ixgbe_free_irq(struct ixgbe_adapter *adapter) **/ static inline void ixgbe_irq_disable(struct ixgbe_adapter *adapter) { - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, ~0); - if (adapter->hw.mac.type == ixgbe_mac_82599EB) { + if (adapter->hw.mac.type == ixgbe_mac_82598EB) { + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, ~0); + } else { + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, 0xFFFF0000); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(0), ~0); IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(1), ~0); - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(2), ~0); } IXGBE_WRITE_FLUSH(&adapter->hw); if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) { @@ -1592,18 +1818,6 @@ static inline void ixgbe_irq_disable(struct ixgbe_adapter *adapter) } } -static inline void ixgbe_irq_enable_queues(struct ixgbe_adapter *adapter) -{ - u32 mask = IXGBE_EIMS_RTX_QUEUE; - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, mask); - if (adapter->hw.mac.type == ixgbe_mac_82599EB) { - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS_EX(1), mask << 16); - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS_EX(2), - (mask << 16 | mask)); - } - /* skip the flush */ -} - /** * ixgbe_configure_msi_and_legacy - Initialize PIN (INTA...) and MSI interrupts * @@ -1673,11 +1887,34 @@ static void ixgbe_configure_srrctl(struct ixgbe_adapter *adapter, int index) u32 srrctl; int queue0 = 0; unsigned long mask; + struct ixgbe_ring_feature *feature = adapter->ring_feature; if (adapter->hw.mac.type == ixgbe_mac_82599EB) { - queue0 = index; + if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { + int dcb_i = feature[RING_F_DCB].indices; + if (dcb_i == 8) + queue0 = index >> 4; + else if (dcb_i == 4) + queue0 = index >> 5; + else + dev_err(&adapter->pdev->dev, "Invalid DCB " + "configuration\n"); +#ifdef IXGBE_FCOE + if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) { + struct ixgbe_ring_feature *f; + + rx_ring = &adapter->rx_ring[queue0]; + f = &adapter->ring_feature[RING_F_FCOE]; + if ((queue0 == 0) && (index > rx_ring->reg_idx)) + queue0 = f->mask + index - + rx_ring->reg_idx - 1; + } +#endif /* IXGBE_FCOE */ + } else { + queue0 = index; + } } else { - mask = (unsigned long) adapter->ring_feature[RING_F_RSS].mask; + mask = (unsigned long) feature[RING_F_RSS].mask; queue0 = index & mask; index = index & mask; } @@ -1689,33 +1926,55 @@ static void ixgbe_configure_srrctl(struct ixgbe_adapter *adapter, int index) srrctl &= ~IXGBE_SRRCTL_BSIZEHDR_MASK; srrctl &= ~IXGBE_SRRCTL_BSIZEPKT_MASK; + srrctl |= (IXGBE_RX_HDR_SIZE << IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT) & + IXGBE_SRRCTL_BSIZEHDR_MASK; + if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) { - u16 bufsz = IXGBE_RXBUFFER_2048; - /* grow the amount we can receive on large page machines */ - if (bufsz < (PAGE_SIZE / 2)) - bufsz = (PAGE_SIZE / 2); - /* cap the bufsz at our largest descriptor size */ - bufsz = min((u16)IXGBE_MAX_RXBUFFER, bufsz); - - srrctl |= bufsz >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; +#if (PAGE_SIZE / 2) > IXGBE_MAX_RXBUFFER + srrctl |= IXGBE_MAX_RXBUFFER >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; +#else + srrctl |= (PAGE_SIZE / 2) >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; +#endif srrctl |= IXGBE_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS; - srrctl |= ((IXGBE_RX_HDR_SIZE << - IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT) & - IXGBE_SRRCTL_BSIZEHDR_MASK); } else { + srrctl |= ALIGN(rx_ring->rx_buf_len, 1024) >> + IXGBE_SRRCTL_BSIZEPKT_SHIFT; srrctl |= IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF; - - if (rx_ring->rx_buf_len == MAXIMUM_ETHERNET_VLAN_SIZE) - srrctl |= IXGBE_RXBUFFER_2048 >> - IXGBE_SRRCTL_BSIZEPKT_SHIFT; - else - srrctl |= rx_ring->rx_buf_len >> - IXGBE_SRRCTL_BSIZEPKT_SHIFT; } IXGBE_WRITE_REG(&adapter->hw, IXGBE_SRRCTL(index), srrctl); } +static u32 ixgbe_setup_mrqc(struct ixgbe_adapter *adapter) +{ + u32 mrqc = 0; + int mask; + + if (!(adapter->hw.mac.type == ixgbe_mac_82599EB)) + return mrqc; + + mask = adapter->flags & (IXGBE_FLAG_RSS_ENABLED +#ifdef CONFIG_IXGBE_DCB + | IXGBE_FLAG_DCB_ENABLED +#endif + ); + + switch (mask) { + case (IXGBE_FLAG_RSS_ENABLED): + mrqc = IXGBE_MRQC_RSSEN; + break; +#ifdef CONFIG_IXGBE_DCB + case (IXGBE_FLAG_DCB_ENABLED): + mrqc = IXGBE_MRQC_RT8TCEN; + break; +#endif /* CONFIG_IXGBE_DCB */ + default: + break; + } + + return mrqc; +} + /** * ixgbe_configure_rx - Configure 8259x Receive Unit after Reset * @adapter: board private structure @@ -1736,11 +1995,17 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter) u32 fctrl, hlreg0; u32 reta = 0, mrqc = 0; u32 rdrxctl; + u32 rscctrl; int rx_buf_len; /* Decide whether to use packet split mode or not */ adapter->flags |= IXGBE_FLAG_RX_PS_ENABLED; +#ifdef IXGBE_FCOE + if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) + adapter->flags &= ~IXGBE_FLAG_RX_PS_ENABLED; +#endif /* IXGBE_FCOE */ + /* Set the RX buffer length according to the mode */ if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) { rx_buf_len = IXGBE_RX_HDR_SIZE; @@ -1749,11 +2014,13 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter) u32 psrtype = IXGBE_PSRTYPE_TCPHDR | IXGBE_PSRTYPE_UDPHDR | IXGBE_PSRTYPE_IPV4HDR | - IXGBE_PSRTYPE_IPV6HDR; + IXGBE_PSRTYPE_IPV6HDR | + IXGBE_PSRTYPE_L2HDR; IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(0), psrtype); } } else { - if (netdev->mtu <= ETH_DATA_LEN) + if (!(adapter->flags & IXGBE_FLAG2_RSC_ENABLED) && + (netdev->mtu <= ETH_DATA_LEN)) rx_buf_len = MAXIMUM_ETHERNET_VLAN_SIZE; else rx_buf_len = ALIGN(max_frame, 1024); @@ -1770,6 +2037,10 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter) hlreg0 &= ~IXGBE_HLREG0_JUMBOEN; else hlreg0 |= IXGBE_HLREG0_JUMBOEN; +#ifdef IXGBE_FCOE + if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) + hlreg0 |= IXGBE_HLREG0_JUMBOEN; +#endif IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg0); rdlen = adapter->rx_ring[0].count * sizeof(union ixgbe_adv_rx_desc); @@ -1777,8 +2048,10 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter) rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL); IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxctrl & ~IXGBE_RXCTRL_RXEN); - /* Setup the HW Rx Head and Tail Descriptor Pointers and - * the Base and Length of the Rx Descriptor Ring */ + /* + * Setup the HW Rx Head and Tail Descriptor Pointers and + * the Base and Length of the Rx Descriptor Ring + */ for (i = 0; i < adapter->num_rx_queues; i++) { rdba = adapter->rx_ring[i].dma; j = adapter->rx_ring[i].reg_idx; @@ -1791,6 +2064,17 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter) adapter->rx_ring[i].tail = IXGBE_RDT(j); adapter->rx_ring[i].rx_buf_len = rx_buf_len; +#ifdef IXGBE_FCOE + if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) { + struct ixgbe_ring_feature *f; + f = &adapter->ring_feature[RING_F_FCOE]; + if ((rx_buf_len < IXGBE_FCOE_JUMBO_FRAME_SIZE) && + (i >= f->mask) && (i < f->mask + f->indices)) + adapter->rx_ring[i].rx_buf_len = + IXGBE_FCOE_JUMBO_FRAME_SIZE; + } + +#endif /* IXGBE_FCOE */ ixgbe_configure_srrctl(adapter, j); } @@ -1811,23 +2095,8 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter) } /* Program MRQC for the distribution of queues */ - if (hw->mac.type == ixgbe_mac_82599EB) { - int mask = adapter->flags & ( - IXGBE_FLAG_RSS_ENABLED - | IXGBE_FLAG_DCB_ENABLED - ); + mrqc = ixgbe_setup_mrqc(adapter); - switch (mask) { - case (IXGBE_FLAG_RSS_ENABLED): - mrqc = IXGBE_MRQC_RSSEN; - break; - case (IXGBE_FLAG_DCB_ENABLED): - mrqc = IXGBE_MRQC_RT8TCEN; - break; - default: - break; - } - } if (adapter->flags & IXGBE_FLAG_RSS_ENABLED) { /* Fill out redirection table */ for (i = 0, j = 0; i < 128; i++, j++) { @@ -1875,8 +2144,45 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter) if (hw->mac.type == ixgbe_mac_82599EB) { rdrxctl = IXGBE_READ_REG(hw, IXGBE_RDRXCTL); rdrxctl |= IXGBE_RDRXCTL_CRCSTRIP; + rdrxctl &= ~IXGBE_RDRXCTL_RSCFRSTSIZE; IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, rdrxctl); } + + if (adapter->flags & IXGBE_FLAG2_RSC_ENABLED) { + /* Enable 82599 HW-RSC */ + for (i = 0; i < adapter->num_rx_queues; i++) { + j = adapter->rx_ring[i].reg_idx; + rscctrl = IXGBE_READ_REG(hw, IXGBE_RSCCTL(j)); + rscctrl |= IXGBE_RSCCTL_RSCEN; + /* + * we must limit the number of descriptors so that the + * total size of max desc * buf_len is not greater + * than 65535 + */ + if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) { +#if (MAX_SKB_FRAGS > 16) + rscctrl |= IXGBE_RSCCTL_MAXDESC_16; +#elif (MAX_SKB_FRAGS > 8) + rscctrl |= IXGBE_RSCCTL_MAXDESC_8; +#elif (MAX_SKB_FRAGS > 4) + rscctrl |= IXGBE_RSCCTL_MAXDESC_4; +#else + rscctrl |= IXGBE_RSCCTL_MAXDESC_1; +#endif + } else { + if (rx_buf_len < IXGBE_RXBUFFER_4096) + rscctrl |= IXGBE_RSCCTL_MAXDESC_16; + else if (rx_buf_len < IXGBE_RXBUFFER_8192) + rscctrl |= IXGBE_RSCCTL_MAXDESC_8; + else + rscctrl |= IXGBE_RSCCTL_MAXDESC_4; + } + IXGBE_WRITE_REG(hw, IXGBE_RSCCTL(j), rscctrl); + } + /* Disable RSC for ACK packets */ + IXGBE_WRITE_REG(hw, IXGBE_RSCDBU, + (IXGBE_RSCDBU_RSCACKDIS | IXGBE_READ_REG(hw, IXGBE_RSCDBU))); + } } static void ixgbe_vlan_rx_add_vid(struct net_device *netdev, u16 vid) @@ -2015,11 +2321,7 @@ static void ixgbe_set_rx_mode(struct net_device *netdev) IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl); /* reprogram secondary unicast list */ - addr_count = netdev->uc_count; - if (addr_count) - addr_list = netdev->uc_list->dmi_addr; - hw->mac.ops.update_uc_addr_list(hw, addr_list, addr_count, - ixgbe_addr_list_itr); + hw->mac.ops.update_uc_addr_list(hw, &netdev->uc.list); /* reprogram multicast list */ addr_count = netdev->mc_count; @@ -2041,13 +2343,16 @@ static void ixgbe_napi_enable_all(struct ixgbe_adapter *adapter) for (q_idx = 0; q_idx < q_vectors; q_idx++) { struct napi_struct *napi; - q_vector = &adapter->q_vector[q_idx]; - if (!q_vector->rxr_count) - continue; + q_vector = adapter->q_vector[q_idx]; napi = &q_vector->napi; - if ((adapter->flags & IXGBE_FLAG_MSIX_ENABLED) && - (q_vector->rxr_count > 1)) - napi->poll = &ixgbe_clean_rxonly_many; + if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) { + if (!q_vector->rxr_count || !q_vector->txr_count) { + if (q_vector->txr_count == 1) + napi->poll = &ixgbe_clean_txonly; + else if (q_vector->rxr_count == 1) + napi->poll = &ixgbe_clean_rxonly; + } + } napi_enable(napi); } @@ -2064,9 +2369,7 @@ static void ixgbe_napi_disable_all(struct ixgbe_adapter *adapter) q_vectors = 1; for (q_idx = 0; q_idx < q_vectors; q_idx++) { - q_vector = &adapter->q_vector[q_idx]; - if (!q_vector->rxr_count) - continue; + q_vector = adapter->q_vector[q_idx]; napi_disable(&q_vector->napi); } } @@ -2124,6 +2427,7 @@ static void ixgbe_configure_dcb(struct ixgbe_adapter *adapter) static void ixgbe_configure(struct ixgbe_adapter *adapter) { struct net_device *netdev = adapter->netdev; + struct ixgbe_hw *hw = &adapter->hw; int i; ixgbe_set_rx_mode(netdev); @@ -2140,6 +2444,20 @@ static void ixgbe_configure(struct ixgbe_adapter *adapter) netif_set_gso_max_size(netdev, 65536); #endif +#ifdef IXGBE_FCOE + if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) + ixgbe_configure_fcoe(adapter); + +#endif /* IXGBE_FCOE */ + if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE) { + for (i = 0; i < adapter->num_tx_queues; i++) + adapter->tx_ring[i].atr_sample_rate = + adapter->atr_sample_rate; + ixgbe_init_fdir_signature_82599(hw, adapter->fdir_pballoc); + } else if (adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE) { + ixgbe_init_fdir_perfect_82599(hw, adapter->fdir_pballoc); + } + ixgbe_configure_tx(adapter); ixgbe_configure_rx(adapter); for (i = 0; i < adapter->num_rx_queues; i++) @@ -2294,6 +2612,13 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter) IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie); } +#ifdef IXGBE_FCOE + /* adjust max frame to be able to do baby jumbo for FCoE */ + if ((adapter->flags & IXGBE_FLAG_FCOE_ENABLED) && + (max_frame < IXGBE_FCOE_JUMBO_FRAME_SIZE)) + max_frame = IXGBE_FCOE_JUMBO_FRAME_SIZE; + +#endif /* IXGBE_FCOE */ mhadd = IXGBE_READ_REG(hw, IXGBE_MHADD); if (max_frame != (mhadd >> IXGBE_MHADD_MFS_SHIFT)) { mhadd &= ~IXGBE_MHADD_MFS_MASK; @@ -2356,6 +2681,17 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter) ixgbe_irq_enable(adapter); + /* + * If this adapter has a fan, check to see if we had a failure + * before we enabled the interrupt. + */ + if (adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE) { + u32 esdp = IXGBE_READ_REG(hw, IXGBE_ESDP); + if (esdp & IXGBE_ESDP_SDP1) + DPRINTK(DRV, CRIT, + "Fan has stopped, replace the adapter\n"); + } + /* * For hot-pluggable SFP+ devices, a new SFP+ module may have * arrived before interrupts were enabled. We need to kick off @@ -2378,6 +2714,10 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter) DPRINTK(PROBE, ERR, "link_config FAILED %d\n", err); } + for (i = 0; i < adapter->num_tx_queues; i++) + set_bit(__IXGBE_FDIR_INIT_DONE, + &(adapter->tx_ring[i].reinit_state)); + /* enable transmits */ netif_tx_start_all_queues(netdev); @@ -2404,20 +2744,37 @@ int ixgbe_up(struct ixgbe_adapter *adapter) /* hardware has been reset, we need to reload some things */ ixgbe_configure(adapter); - ixgbe_napi_add_all(adapter); - return ixgbe_up_complete(adapter); } void ixgbe_reset(struct ixgbe_adapter *adapter) { struct ixgbe_hw *hw = &adapter->hw; - if (hw->mac.ops.init_hw(hw)) - dev_err(&adapter->pdev->dev, "Hardware Error\n"); + int err; + + err = hw->mac.ops.init_hw(hw); + switch (err) { + case 0: + case IXGBE_ERR_SFP_NOT_PRESENT: + break; + case IXGBE_ERR_MASTER_REQUESTS_PENDING: + dev_err(&adapter->pdev->dev, "master disable timed out\n"); + break; + case IXGBE_ERR_EEPROM_VERSION: + /* We are running on a pre-production device, log a warning */ + dev_warn(&adapter->pdev->dev, "This device is a pre-production " + "adapter/LOM. Please be aware there may be issues " + "associated with your hardware. If you are " + "experiencing problems please contact your Intel or " + "hardware representative who provided you with this " + "hardware.\n"); + break; + default: + dev_err(&adapter->pdev->dev, "Hardware Error: %d\n", err); + } /* reprogram the RAR[0] in case user changed it. */ hw->mac.ops.set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV); - } /** @@ -2445,8 +2802,13 @@ static void ixgbe_clean_rx_ring(struct ixgbe_adapter *adapter, rx_buffer_info->dma = 0; } if (rx_buffer_info->skb) { - dev_kfree_skb(rx_buffer_info->skb); + struct sk_buff *skb = rx_buffer_info->skb; rx_buffer_info->skb = NULL; + do { + struct sk_buff *this = skb; + skb = skb->prev; + dev_kfree_skb(this); + } while (skb); } if (!rx_buffer_info->page) continue; @@ -2560,6 +2922,10 @@ void ixgbe_down(struct ixgbe_adapter *adapter) del_timer_sync(&adapter->watchdog_timer); cancel_work_sync(&adapter->watchdog_task); + if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE || + adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE) + cancel_work_sync(&adapter->fdir_reinit_task); + /* disable transmits in the hardware now that interrupts are off */ for (i = 0; i < adapter->num_tx_queues; i++) { j = adapter->tx_ring[i].reg_idx; @@ -2575,13 +2941,6 @@ void ixgbe_down(struct ixgbe_adapter *adapter) netif_carrier_off(netdev); -#ifdef CONFIG_IXGBE_DCA - if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) { - adapter->flags &= ~IXGBE_FLAG_DCA_ENABLED; - dca_remove_requester(&adapter->pdev->dev); - } - -#endif if (!pci_channel_offline(adapter->pdev)) ixgbe_reset(adapter); ixgbe_clean_all_tx_rings(adapter); @@ -2589,13 +2948,7 @@ void ixgbe_down(struct ixgbe_adapter *adapter) #ifdef CONFIG_IXGBE_DCA /* since we reset the hardware DCA settings were cleared */ - if (dca_add_requester(&adapter->pdev->dev) == 0) { - adapter->flags |= IXGBE_FLAG_DCA_ENABLED; - /* always use CB2 mode, difference is masked - * in the CB driver */ - IXGBE_WRITE_REG(hw, IXGBE_DCA_CTRL, 2); - ixgbe_setup_dca(adapter); - } + ixgbe_setup_dca(adapter); #endif } @@ -2620,7 +2973,7 @@ static int ixgbe_poll(struct napi_struct *napi, int budget) } #endif - tx_clean_complete = ixgbe_clean_tx_irq(adapter, adapter->tx_ring); + tx_clean_complete = ixgbe_clean_tx_irq(q_vector, adapter->tx_ring); ixgbe_clean_rx_irq(q_vector, adapter->rx_ring, &work_done, budget); if (!tx_clean_complete) @@ -2632,7 +2985,7 @@ static int ixgbe_poll(struct napi_struct *napi, int budget) if (adapter->itr_setting & 1) ixgbe_set_itr(adapter); if (!test_bit(__IXGBE_DOWN, &adapter->state)) - ixgbe_irq_enable_queues(adapter); + ixgbe_irq_enable_queues(adapter, IXGBE_EIMS_RTX_QUEUE); } return work_done; } @@ -2668,17 +3021,15 @@ static void ixgbe_reset_task(struct work_struct *work) static inline bool ixgbe_set_dcb_queues(struct ixgbe_adapter *adapter) { bool ret = false; + struct ixgbe_ring_feature *f = &adapter->ring_feature[RING_F_DCB]; - if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { - adapter->ring_feature[RING_F_DCB].mask = 0x7 << 3; - adapter->num_rx_queues = - adapter->ring_feature[RING_F_DCB].indices; - adapter->num_tx_queues = - adapter->ring_feature[RING_F_DCB].indices; - ret = true; - } else { - ret = false; - } + if (!(adapter->flags & IXGBE_FLAG_DCB_ENABLED)) + return ret; + + f->mask = 0x7 << 3; + adapter->num_rx_queues = f->indices; + adapter->num_tx_queues = f->indices; + ret = true; return ret; } @@ -2695,13 +3046,12 @@ static inline bool ixgbe_set_dcb_queues(struct ixgbe_adapter *adapter) static inline bool ixgbe_set_rss_queues(struct ixgbe_adapter *adapter) { bool ret = false; + struct ixgbe_ring_feature *f = &adapter->ring_feature[RING_F_RSS]; if (adapter->flags & IXGBE_FLAG_RSS_ENABLED) { - adapter->ring_feature[RING_F_RSS].mask = 0xF; - adapter->num_rx_queues = - adapter->ring_feature[RING_F_RSS].indices; - adapter->num_tx_queues = - adapter->ring_feature[RING_F_RSS].indices; + f->mask = 0xF; + adapter->num_rx_queues = f->indices; + adapter->num_tx_queues = f->indices; ret = true; } else { ret = false; @@ -2710,6 +3060,79 @@ static inline bool ixgbe_set_rss_queues(struct ixgbe_adapter *adapter) return ret; } +/** + * ixgbe_set_fdir_queues: Allocate queues for Flow Director + * @adapter: board private structure to initialize + * + * Flow Director is an advanced Rx filter, attempting to get Rx flows back + * to the original CPU that initiated the Tx session. This runs in addition + * to RSS, so if a packet doesn't match an FDIR filter, we can still spread the + * Rx load across CPUs using RSS. + * + **/ +static bool inline ixgbe_set_fdir_queues(struct ixgbe_adapter *adapter) +{ + bool ret = false; + struct ixgbe_ring_feature *f_fdir = &adapter->ring_feature[RING_F_FDIR]; + + f_fdir->indices = min((int)num_online_cpus(), f_fdir->indices); + f_fdir->mask = 0; + + /* Flow Director must have RSS enabled */ + if (adapter->flags & IXGBE_FLAG_RSS_ENABLED && + ((adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE || + (adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE)))) { + adapter->num_tx_queues = f_fdir->indices; + adapter->num_rx_queues = f_fdir->indices; + ret = true; + } else { + adapter->flags &= ~IXGBE_FLAG_FDIR_HASH_CAPABLE; + adapter->flags &= ~IXGBE_FLAG_FDIR_PERFECT_CAPABLE; + } + return ret; +} + +#ifdef IXGBE_FCOE +/** + * ixgbe_set_fcoe_queues: Allocate queues for Fiber Channel over Ethernet (FCoE) + * @adapter: board private structure to initialize + * + * FCoE RX FCRETA can use up to 8 rx queues for up to 8 different exchanges. + * The ring feature mask is not used as a mask for FCoE, as it can take any 8 + * rx queues out of the max number of rx queues, instead, it is used as the + * index of the first rx queue used by FCoE. + * + **/ +static inline bool ixgbe_set_fcoe_queues(struct ixgbe_adapter *adapter) +{ + bool ret = false; + struct ixgbe_ring_feature *f = &adapter->ring_feature[RING_F_FCOE]; + + f->indices = min((int)num_online_cpus(), f->indices); + if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) { +#ifdef CONFIG_IXGBE_DCB + if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { + DPRINTK(PROBE, INFO, "FCOE enabled with DCB \n"); + ixgbe_set_dcb_queues(adapter); + } +#endif + if (adapter->flags & IXGBE_FLAG_RSS_ENABLED) { + DPRINTK(PROBE, INFO, "FCOE enabled with RSS \n"); + ixgbe_set_rss_queues(adapter); + } + /* adding FCoE rx rings to the end */ + f->mask = adapter->num_rx_queues; + adapter->num_rx_queues += f->indices; + if (adapter->num_tx_queues == 0) + adapter->num_tx_queues = f->indices; + + ret = true; + } + + return ret; +} + +#endif /* IXGBE_FCOE */ /* * ixgbe_set_num_queues: Allocate queues for device, feature dependant * @adapter: board private structure to initialize @@ -2723,11 +3146,19 @@ static inline bool ixgbe_set_rss_queues(struct ixgbe_adapter *adapter) **/ static void ixgbe_set_num_queues(struct ixgbe_adapter *adapter) { +#ifdef IXGBE_FCOE + if (ixgbe_set_fcoe_queues(adapter)) + goto done; + +#endif /* IXGBE_FCOE */ #ifdef CONFIG_IXGBE_DCB if (ixgbe_set_dcb_queues(adapter)) goto done; #endif + if (ixgbe_set_fdir_queues(adapter)) + goto done; + if (ixgbe_set_rss_queues(adapter)) goto done; @@ -2778,9 +3209,6 @@ static void ixgbe_acquire_msix_vectors(struct ixgbe_adapter *adapter, adapter->flags &= ~IXGBE_FLAG_MSIX_ENABLED; kfree(adapter->msix_entries); adapter->msix_entries = NULL; - adapter->flags &= ~IXGBE_FLAG_DCB_ENABLED; - adapter->flags &= ~IXGBE_FLAG_RSS_ENABLED; - ixgbe_set_num_queues(adapter); } else { adapter->flags |= IXGBE_FLAG_MSIX_ENABLED; /* Woot! */ /* @@ -2901,6 +3329,64 @@ static inline bool ixgbe_cache_ring_dcb(struct ixgbe_adapter *adapter) } #endif +/** + * ixgbe_cache_ring_fdir - Descriptor ring to register mapping for Flow Director + * @adapter: board private structure to initialize + * + * Cache the descriptor ring offsets for Flow Director to the assigned rings. + * + **/ +static bool inline ixgbe_cache_ring_fdir(struct ixgbe_adapter *adapter) +{ + int i; + bool ret = false; + + if (adapter->flags & IXGBE_FLAG_RSS_ENABLED && + ((adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE) || + (adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE))) { + for (i = 0; i < adapter->num_rx_queues; i++) + adapter->rx_ring[i].reg_idx = i; + for (i = 0; i < adapter->num_tx_queues; i++) + adapter->tx_ring[i].reg_idx = i; + ret = true; + } + + return ret; +} + +#ifdef IXGBE_FCOE +/** + * ixgbe_cache_ring_fcoe - Descriptor ring to register mapping for the FCoE + * @adapter: board private structure to initialize + * + * Cache the descriptor ring offsets for FCoE mode to the assigned rings. + * + */ +static inline bool ixgbe_cache_ring_fcoe(struct ixgbe_adapter *adapter) +{ + int i, fcoe_i = 0; + bool ret = false; + struct ixgbe_ring_feature *f = &adapter->ring_feature[RING_F_FCOE]; + + if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) { +#ifdef CONFIG_IXGBE_DCB + if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { + ixgbe_cache_ring_dcb(adapter); + fcoe_i = adapter->rx_ring[0].reg_idx + 1; + } +#endif /* CONFIG_IXGBE_DCB */ + if (adapter->flags & IXGBE_FLAG_RSS_ENABLED) { + ixgbe_cache_ring_rss(adapter); + fcoe_i = f->mask; + } + for (i = 0; i < f->indices; i++, fcoe_i++) + adapter->rx_ring[f->mask + i].reg_idx = fcoe_i; + ret = true; + } + return ret; +} + +#endif /* IXGBE_FCOE */ /** * ixgbe_cache_ring_register - Descriptor ring to register mapping * @adapter: board private structure to initialize @@ -2918,11 +3404,19 @@ static void ixgbe_cache_ring_register(struct ixgbe_adapter *adapter) adapter->rx_ring[0].reg_idx = 0; adapter->tx_ring[0].reg_idx = 0; +#ifdef IXGBE_FCOE + if (ixgbe_cache_ring_fcoe(adapter)) + return; + +#endif /* IXGBE_FCOE */ #ifdef CONFIG_IXGBE_DCB if (ixgbe_cache_ring_dcb(adapter)) return; #endif + if (ixgbe_cache_ring_fdir(adapter)) + return; + if (ixgbe_cache_ring_rss(adapter)) return; } @@ -3004,31 +3498,23 @@ static int ixgbe_set_interrupt_capability(struct ixgbe_adapter *adapter) * mean we disable MSI-X capabilities of the adapter. */ adapter->msix_entries = kcalloc(v_budget, sizeof(struct msix_entry), GFP_KERNEL); - if (!adapter->msix_entries) { - adapter->flags &= ~IXGBE_FLAG_DCB_ENABLED; - adapter->flags &= ~IXGBE_FLAG_RSS_ENABLED; - ixgbe_set_num_queues(adapter); - kfree(adapter->tx_ring); - kfree(adapter->rx_ring); - err = ixgbe_alloc_queues(adapter); - if (err) { - DPRINTK(PROBE, ERR, "Unable to allocate memory " - "for queues\n"); - goto out; - } + if (adapter->msix_entries) { + for (vector = 0; vector < v_budget; vector++) + adapter->msix_entries[vector].entry = vector; - goto try_msi; + ixgbe_acquire_msix_vectors(adapter, v_budget); + + if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) + goto out; } - for (vector = 0; vector < v_budget; vector++) - adapter->msix_entries[vector].entry = vector; + adapter->flags &= ~IXGBE_FLAG_DCB_ENABLED; + adapter->flags &= ~IXGBE_FLAG_RSS_ENABLED; + adapter->flags &= ~IXGBE_FLAG_FDIR_HASH_CAPABLE; + adapter->flags &= ~IXGBE_FLAG_FDIR_PERFECT_CAPABLE; + adapter->atr_sample_rate = 0; + ixgbe_set_num_queues(adapter); - ixgbe_acquire_msix_vectors(adapter, v_budget); - - if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) - goto out; - -try_msi: err = pci_enable_msi(adapter->pdev); if (!err) { adapter->flags |= IXGBE_FLAG_MSI_ENABLED; @@ -3043,6 +3529,79 @@ out: return err; } +/** + * ixgbe_alloc_q_vectors - Allocate memory for interrupt vectors + * @adapter: board private structure to initialize + * + * We allocate one q_vector per queue interrupt. If allocation fails we + * return -ENOMEM. + **/ +static int ixgbe_alloc_q_vectors(struct ixgbe_adapter *adapter) +{ + int q_idx, num_q_vectors; + struct ixgbe_q_vector *q_vector; + int napi_vectors; + int (*poll)(struct napi_struct *, int); + + if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) { + num_q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS; + napi_vectors = adapter->num_rx_queues; + poll = &ixgbe_clean_rxtx_many; + } else { + num_q_vectors = 1; + napi_vectors = 1; + poll = &ixgbe_poll; + } + + for (q_idx = 0; q_idx < num_q_vectors; q_idx++) { + q_vector = kzalloc(sizeof(struct ixgbe_q_vector), GFP_KERNEL); + if (!q_vector) + goto err_out; + q_vector->adapter = adapter; + q_vector->eitr = adapter->eitr_param; + q_vector->v_idx = q_idx; + netif_napi_add(adapter->netdev, &q_vector->napi, (*poll), 64); + adapter->q_vector[q_idx] = q_vector; + } + + return 0; + +err_out: + while (q_idx) { + q_idx--; + q_vector = adapter->q_vector[q_idx]; + netif_napi_del(&q_vector->napi); + kfree(q_vector); + adapter->q_vector[q_idx] = NULL; + } + return -ENOMEM; +} + +/** + * ixgbe_free_q_vectors - Free memory allocated for interrupt vectors + * @adapter: board private structure to initialize + * + * This function frees the memory allocated to the q_vectors. In addition if + * NAPI is enabled it will delete any references to the NAPI struct prior + * to freeing the q_vector. + **/ +static void ixgbe_free_q_vectors(struct ixgbe_adapter *adapter) +{ + int q_idx, num_q_vectors; + + if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) + num_q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS; + else + num_q_vectors = 1; + + for (q_idx = 0; q_idx < num_q_vectors; q_idx++) { + struct ixgbe_q_vector *q_vector = adapter->q_vector[q_idx]; + adapter->q_vector[q_idx] = NULL; + netif_napi_del(&q_vector->napi); + kfree(q_vector); + } +} + void ixgbe_reset_interrupt_capability(struct ixgbe_adapter *adapter) { if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) { @@ -3074,18 +3633,25 @@ int ixgbe_init_interrupt_scheme(struct ixgbe_adapter *adapter) /* Number of supported queues */ ixgbe_set_num_queues(adapter); - err = ixgbe_alloc_queues(adapter); - if (err) { - DPRINTK(PROBE, ERR, "Unable to allocate memory for queues\n"); - goto err_alloc_queues; - } - err = ixgbe_set_interrupt_capability(adapter); if (err) { DPRINTK(PROBE, ERR, "Unable to setup interrupt capabilities\n"); goto err_set_interrupt; } + err = ixgbe_alloc_q_vectors(adapter); + if (err) { + DPRINTK(PROBE, ERR, "Unable to allocate memory for queue " + "vectors\n"); + goto err_alloc_q_vectors; + } + + err = ixgbe_alloc_queues(adapter); + if (err) { + DPRINTK(PROBE, ERR, "Unable to allocate memory for queues\n"); + goto err_alloc_queues; + } + DPRINTK(DRV, INFO, "Multiqueue %s: Rx Queue count = %u, " "Tx Queue count = %u\n", (adapter->num_rx_queues > 1) ? "Enabled" : @@ -3095,11 +3661,30 @@ int ixgbe_init_interrupt_scheme(struct ixgbe_adapter *adapter) return 0; +err_alloc_queues: + ixgbe_free_q_vectors(adapter); +err_alloc_q_vectors: + ixgbe_reset_interrupt_capability(adapter); err_set_interrupt: + return err; +} + +/** + * ixgbe_clear_interrupt_scheme - Clear the current interrupt scheme settings + * @adapter: board private structure to clear interrupt scheme on + * + * We go through and clear interrupt specific resources and reset the structure + * to pre-load conditions + **/ +void ixgbe_clear_interrupt_scheme(struct ixgbe_adapter *adapter) +{ kfree(adapter->tx_ring); kfree(adapter->rx_ring); -err_alloc_queues: - return err; + adapter->tx_ring = NULL; + adapter->rx_ring = NULL; + + ixgbe_free_q_vectors(adapter); + ixgbe_reset_interrupt_capability(adapter); } /** @@ -3185,10 +3770,24 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter) adapter->ring_feature[RING_F_RSS].indices = rss; adapter->flags |= IXGBE_FLAG_RSS_ENABLED; adapter->ring_feature[RING_F_DCB].indices = IXGBE_MAX_DCB_INDICES; - if (hw->mac.type == ixgbe_mac_82598EB) + if (hw->mac.type == ixgbe_mac_82598EB) { + if (hw->device_id == IXGBE_DEV_ID_82598AT) + adapter->flags |= IXGBE_FLAG_FAN_FAIL_CAPABLE; adapter->max_msix_q_vectors = MAX_MSIX_Q_VECTORS_82598; - else if (hw->mac.type == ixgbe_mac_82599EB) + } else if (hw->mac.type == ixgbe_mac_82599EB) { adapter->max_msix_q_vectors = MAX_MSIX_Q_VECTORS_82599; + adapter->flags |= IXGBE_FLAG2_RSC_CAPABLE; + adapter->flags |= IXGBE_FLAG2_RSC_ENABLED; + adapter->flags |= IXGBE_FLAG_FDIR_HASH_CAPABLE; + adapter->ring_feature[RING_F_FDIR].indices = + IXGBE_MAX_FDIR_INDICES; + adapter->atr_sample_rate = 20; + adapter->fdir_pballoc = 0; +#ifdef IXGBE_FCOE + adapter->flags |= IXGBE_FLAG_FCOE_ENABLED; + adapter->ring_feature[RING_F_FCOE].indices = IXGBE_FCRETA_SIZE; +#endif /* IXGBE_FCOE */ + } #ifdef CONFIG_IXGBE_DCB /* Configure DCB traffic classes */ @@ -3203,6 +3802,7 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter) adapter->dcb_cfg.bw_percentage[DCB_TX_CONFIG][0] = 100; adapter->dcb_cfg.bw_percentage[DCB_RX_CONFIG][0] = 100; adapter->dcb_cfg.rx_pba_cfg = pba_equal; + adapter->dcb_cfg.pfc_mode_enable = false; adapter->dcb_cfg.round_robin_enable = false; adapter->dcb_set_bitmap = 0x00; ixgbe_copy_dcb_cfg(&adapter->dcb_cfg, &adapter->temp_dcb_cfg, @@ -3213,6 +3813,9 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter) /* default flow control settings */ hw->fc.requested_mode = ixgbe_fc_full; hw->fc.current_mode = ixgbe_fc_full; /* init for ethtool output */ +#ifdef CONFIG_DCB + adapter->last_lfc_mode = hw->fc.current_mode; +#endif hw->fc.high_water = IXGBE_DEFAULT_FCRTH; hw->fc.low_water = IXGBE_DEFAULT_FCRTL; hw->fc.pause_time = IXGBE_DEFAULT_FCPAUSE; @@ -3503,6 +4106,8 @@ static int ixgbe_open(struct net_device *netdev) if (test_bit(__IXGBE_TESTING, &adapter->state)) return -EBUSY; + netif_carrier_off(netdev); + /* allocate transmit descriptors */ err = ixgbe_setup_all_tx_resources(adapter); if (err) @@ -3515,8 +4120,6 @@ static int ixgbe_open(struct net_device *netdev) ixgbe_configure(adapter); - ixgbe_napi_add_all(adapter); - err = ixgbe_request_irq(adapter); if (err) goto err_req_irq; @@ -3568,55 +4171,6 @@ static int ixgbe_close(struct net_device *netdev) return 0; } -/** - * ixgbe_napi_add_all - prep napi structs for use - * @adapter: private struct - * - * helper function to napi_add each possible q_vector->napi - */ -void ixgbe_napi_add_all(struct ixgbe_adapter *adapter) -{ - int q_idx, q_vectors; - struct net_device *netdev = adapter->netdev; - int (*poll)(struct napi_struct *, int); - - /* check if we already have our netdev->napi_list populated */ - if (&netdev->napi_list != netdev->napi_list.next) - return; - - if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) { - poll = &ixgbe_clean_rxonly; - /* Only enable as many vectors as we have rx queues. */ - q_vectors = adapter->num_rx_queues; - } else { - poll = &ixgbe_poll; - /* only one q_vector for legacy modes */ - q_vectors = 1; - } - - for (q_idx = 0; q_idx < q_vectors; q_idx++) { - struct ixgbe_q_vector *q_vector = &adapter->q_vector[q_idx]; - netif_napi_add(adapter->netdev, &q_vector->napi, (*poll), 64); - } -} - -void ixgbe_napi_del_all(struct ixgbe_adapter *adapter) -{ - int q_idx; - int q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS; - - /* legacy and MSI only use one vector */ - if (!(adapter->flags & IXGBE_FLAG_MSIX_ENABLED)) - q_vectors = 1; - - for (q_idx = 0; q_idx < q_vectors; q_idx++) { - struct ixgbe_q_vector *q_vector = &adapter->q_vector[q_idx]; - if (!q_vector->rxr_count) - continue; - netif_napi_del(&q_vector->napi); - } -} - #ifdef CONFIG_PM static int ixgbe_resume(struct pci_dev *pdev) { @@ -3626,7 +4180,8 @@ static int ixgbe_resume(struct pci_dev *pdev) pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); - err = pci_enable_device(pdev); + + err = pci_enable_device_mem(pdev); if (err) { printk(KERN_ERR "ixgbe: Cannot enable PCI device from " "suspend\n"); @@ -3634,8 +4189,7 @@ static int ixgbe_resume(struct pci_dev *pdev) } pci_set_master(pdev); - pci_enable_wake(pdev, PCI_D3hot, 0); - pci_enable_wake(pdev, PCI_D3cold, 0); + pci_wake_from_d3(pdev, false); err = ixgbe_init_interrupt_scheme(adapter); if (err) { @@ -3679,11 +4233,7 @@ static int __ixgbe_shutdown(struct pci_dev *pdev, bool *enable_wake) ixgbe_free_all_tx_resources(adapter); ixgbe_free_all_rx_resources(adapter); } - ixgbe_reset_interrupt_capability(adapter); - ixgbe_napi_del_all(adapter); - INIT_LIST_HEAD(&netdev->napi_list); - kfree(adapter->tx_ring); - kfree(adapter->rx_ring); + ixgbe_clear_interrupt_scheme(adapter); #ifdef CONFIG_PM retval = pci_save_state(pdev); @@ -3711,13 +4261,10 @@ static int __ixgbe_shutdown(struct pci_dev *pdev, bool *enable_wake) IXGBE_WRITE_REG(hw, IXGBE_WUFC, 0); } - if (wufc && hw->mac.type == ixgbe_mac_82599EB) { - pci_enable_wake(pdev, PCI_D3hot, 1); - pci_enable_wake(pdev, PCI_D3cold, 1); - } else { - pci_enable_wake(pdev, PCI_D3hot, 0); - pci_enable_wake(pdev, PCI_D3cold, 0); - } + if (wufc && hw->mac.type == ixgbe_mac_82599EB) + pci_wake_from_d3(pdev, true); + else + pci_wake_from_d3(pdev, false); *enable_wake = !!wufc; @@ -3772,9 +4319,13 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter) u32 i, missed_rx = 0, mpc, bprc, lxon, lxoff, xon_off_tot; if (hw->mac.type == ixgbe_mac_82599EB) { + u64 rsc_count = 0; for (i = 0; i < 16; i++) adapter->hw_rx_no_dma_resources += IXGBE_READ_REG(hw, IXGBE_QPRDC(i)); + for (i = 0; i < adapter->num_rx_queues; i++) + rsc_count += adapter->rx_ring[i].rsc_count; + adapter->rsc_count = rsc_count; } adapter->stats.crcerrs += IXGBE_READ_REG(hw, IXGBE_CRCERRS); @@ -3821,6 +4372,16 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter) IXGBE_READ_REG(hw, IXGBE_TORH); /* to clear */ adapter->stats.lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXCNT); adapter->stats.lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXCNT); + adapter->stats.fdirmatch += IXGBE_READ_REG(hw, IXGBE_FDIRMATCH); + adapter->stats.fdirmiss += IXGBE_READ_REG(hw, IXGBE_FDIRMISS); +#ifdef IXGBE_FCOE + adapter->stats.fccrc += IXGBE_READ_REG(hw, IXGBE_FCCRC); + adapter->stats.fcoerpdc += IXGBE_READ_REG(hw, IXGBE_FCOERPDC); + adapter->stats.fcoeprc += IXGBE_READ_REG(hw, IXGBE_FCOEPRC); + adapter->stats.fcoeptc += IXGBE_READ_REG(hw, IXGBE_FCOEPTC); + adapter->stats.fcoedwrc += IXGBE_READ_REG(hw, IXGBE_FCOEDWRC); + adapter->stats.fcoedwtc += IXGBE_READ_REG(hw, IXGBE_FCOEDWTC); +#endif /* IXGBE_FCOE */ } else { adapter->stats.lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXC); adapter->stats.lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXC); @@ -3888,64 +4449,43 @@ static void ixgbe_watchdog(unsigned long data) { struct ixgbe_adapter *adapter = (struct ixgbe_adapter *)data; struct ixgbe_hw *hw = &adapter->hw; + u64 eics = 0; + int i; - /* Do the watchdog outside of interrupt context due to the lovely - * delays that some of the newer hardware requires */ - if (!test_bit(__IXGBE_DOWN, &adapter->state)) { - u64 eics = 0; - int i; + /* + * Do the watchdog outside of interrupt context due to the lovely + * delays that some of the newer hardware requires + */ - for (i = 0; i < adapter->num_msix_vectors - NON_Q_VECTORS; i++) - eics |= (1 << i); + if (test_bit(__IXGBE_DOWN, &adapter->state)) + goto watchdog_short_circuit; - /* Cause software interrupt to ensure rx rings are cleaned */ - switch (hw->mac.type) { - case ixgbe_mac_82598EB: - if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) { - IXGBE_WRITE_REG(hw, IXGBE_EICS, (u32)eics); - } else { - /* - * for legacy and MSI interrupts don't set any - * bits that are enabled for EIAM, because this - * operation would set *both* EIMS and EICS for - * any bit in EIAM - */ - IXGBE_WRITE_REG(hw, IXGBE_EICS, - (IXGBE_EICS_TCP_TIMER | IXGBE_EICS_OTHER)); - } - break; - case ixgbe_mac_82599EB: - if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) { - /* - * EICS(0..15) first 0-15 q vectors - * EICS[1] (16..31) q vectors 16-31 - * EICS[2] (0..31) q vectors 32-63 - */ - IXGBE_WRITE_REG(hw, IXGBE_EICS, - (u32)(eics & 0xFFFF)); - IXGBE_WRITE_REG(hw, IXGBE_EICS_EX(1), - (u32)(eics & 0xFFFF0000)); - IXGBE_WRITE_REG(hw, IXGBE_EICS_EX(2), - (u32)(eics >> 32)); - } else { - /* - * for legacy and MSI interrupts don't set any - * bits that are enabled for EIAM, because this - * operation would set *both* EIMS and EICS for - * any bit in EIAM - */ - IXGBE_WRITE_REG(hw, IXGBE_EICS, - (IXGBE_EICS_TCP_TIMER | IXGBE_EICS_OTHER)); - } - break; - default: - break; - } - /* Reset the timer */ - mod_timer(&adapter->watchdog_timer, - round_jiffies(jiffies + 2 * HZ)); + if (!(adapter->flags & IXGBE_FLAG_MSIX_ENABLED)) { + /* + * for legacy and MSI interrupts don't set any bits + * that are enabled for EIAM, because this operation + * would set *both* EIMS and EICS for any bit in EIAM + */ + IXGBE_WRITE_REG(hw, IXGBE_EICS, + (IXGBE_EICS_TCP_TIMER | IXGBE_EICS_OTHER)); + goto watchdog_reschedule; } + /* get one bit for every active tx/rx interrupt vector */ + for (i = 0; i < adapter->num_msix_vectors - NON_Q_VECTORS; i++) { + struct ixgbe_q_vector *qv = adapter->q_vector[i]; + if (qv->rxr_count || qv->txr_count) + eics |= ((u64)1 << i); + } + + /* Cause software interrupt to ensure rx rings are cleaned */ + ixgbe_irq_rearm_queues(adapter, eics); + +watchdog_reschedule: + /* Reset the timer */ + mod_timer(&adapter->watchdog_timer, round_jiffies(jiffies + 2 * HZ)); + +watchdog_short_circuit: schedule_work(&adapter->watchdog_task); } @@ -3998,6 +4538,30 @@ static void ixgbe_sfp_config_module_task(struct work_struct *work) adapter->flags &= ~IXGBE_FLAG_IN_SFP_MOD_TASK; } +/** + * ixgbe_fdir_reinit_task - worker thread to reinit FDIR filter table + * @work: pointer to work_struct containing our data + **/ +static void ixgbe_fdir_reinit_task(struct work_struct *work) +{ + struct ixgbe_adapter *adapter = container_of(work, + struct ixgbe_adapter, + fdir_reinit_task); + struct ixgbe_hw *hw = &adapter->hw; + int i; + + if (ixgbe_reinit_fdir_tables_82599(hw) == 0) { + for (i = 0; i < adapter->num_tx_queues; i++) + set_bit(__IXGBE_FDIR_INIT_DONE, + &(adapter->tx_ring[i].reinit_state)); + } else { + DPRINTK(PROBE, ERR, "failed to finish FDIR re-initialization, " + "ignored adding FDIR ATR filters \n"); + } + /* Done FDIR Re-initialization, enable transmits */ + netif_tx_start_all_queues(adapter->netdev); +} + /** * ixgbe_watchdog_task - worker thread to bring link up * @work: pointer to work_struct containing our data @@ -4011,16 +4575,32 @@ static void ixgbe_watchdog_task(struct work_struct *work) struct ixgbe_hw *hw = &adapter->hw; u32 link_speed = adapter->link_speed; bool link_up = adapter->link_up; + int i; + struct ixgbe_ring *tx_ring; + int some_tx_pending = 0; adapter->flags |= IXGBE_FLAG_IN_WATCHDOG_TASK; if (adapter->flags & IXGBE_FLAG_NEED_LINK_UPDATE) { hw->mac.ops.check_link(hw, &link_speed, &link_up, false); + if (link_up) { +#ifdef CONFIG_DCB + if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { + for (i = 0; i < MAX_TRAFFIC_CLASS; i++) + hw->mac.ops.fc_enable(hw, i); + } else { + hw->mac.ops.fc_enable(hw, 0); + } +#else + hw->mac.ops.fc_enable(hw, 0); +#endif + } + if (link_up || time_after(jiffies, (adapter->link_check_timeout + IXGBE_TRY_LINK_TIMEOUT))) { - IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMC_LSC); adapter->flags &= ~IXGBE_FLAG_NEED_LINK_UPDATE; + IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMC_LSC); } adapter->link_up = link_up; adapter->link_speed = link_speed; @@ -4068,6 +4648,25 @@ static void ixgbe_watchdog_task(struct work_struct *work) } } + if (!netif_carrier_ok(netdev)) { + for (i = 0; i < adapter->num_tx_queues; i++) { + tx_ring = &adapter->tx_ring[i]; + if (tx_ring->next_to_use != tx_ring->next_to_clean) { + some_tx_pending = 1; + break; + } + } + + if (some_tx_pending) { + /* We've lost link, so the controller stops DMA, + * but we've got queued Tx work that's never going + * to get done, so reset controller to flush Tx. + * (Do the reset outside of interrupt context). + */ + schedule_work(&adapter->reset_task); + } + } + ixgbe_update_stats(adapter); adapter->flags &= ~IXGBE_FLAG_IN_WATCHDOG_TASK; } @@ -4196,12 +4795,18 @@ static bool ixgbe_tx_csum(struct ixgbe_adapter *adapter, if (ip_hdr(skb)->protocol == IPPROTO_TCP) type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_L4T_TCP; + else if (ip_hdr(skb)->protocol == IPPROTO_SCTP) + type_tucmd_mlhl |= + IXGBE_ADVTXD_TUCMD_L4T_SCTP; break; case cpu_to_be16(ETH_P_IPV6): /* XXX what about other V6 headers?? */ if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP) type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_L4T_TCP; + else if (ipv6_hdr(skb)->nexthdr == IPPROTO_SCTP) + type_tucmd_mlhl |= + IXGBE_ADVTXD_TUCMD_L4T_SCTP; break; default: if (unlikely(net_ratelimit())) { @@ -4234,10 +4839,12 @@ static bool ixgbe_tx_csum(struct ixgbe_adapter *adapter, static int ixgbe_tx_map(struct ixgbe_adapter *adapter, struct ixgbe_ring *tx_ring, - struct sk_buff *skb, unsigned int first) + struct sk_buff *skb, u32 tx_flags, + unsigned int first) { struct ixgbe_tx_buffer *tx_buffer_info; - unsigned int len = skb_headlen(skb); + unsigned int len; + unsigned int total = skb->len; unsigned int offset = 0, size, count = 0, i; unsigned int nr_frags = skb_shinfo(skb)->nr_frags; unsigned int f; @@ -4252,16 +4859,22 @@ static int ixgbe_tx_map(struct ixgbe_adapter *adapter, map = skb_shinfo(skb)->dma_maps; + if (tx_flags & IXGBE_TX_FLAGS_FCOE) + /* excluding fcoe_crc_eof for FCoE */ + total -= sizeof(struct fcoe_crc_eof); + + len = min(skb_headlen(skb), total); while (len) { tx_buffer_info = &tx_ring->tx_buffer_info[i]; size = min(len, (uint)IXGBE_MAX_DATA_PER_TXD); tx_buffer_info->length = size; - tx_buffer_info->dma = map[0] + offset; + tx_buffer_info->dma = skb_shinfo(skb)->dma_head + offset; tx_buffer_info->time_stamp = jiffies; tx_buffer_info->next_to_watch = i; len -= size; + total -= size; offset += size; count++; @@ -4276,7 +4889,7 @@ static int ixgbe_tx_map(struct ixgbe_adapter *adapter, struct skb_frag_struct *frag; frag = &skb_shinfo(skb)->frags[f]; - len = frag->size; + len = min((unsigned int)frag->size, total); offset = 0; while (len) { @@ -4288,14 +4901,17 @@ static int ixgbe_tx_map(struct ixgbe_adapter *adapter, size = min(len, (uint)IXGBE_MAX_DATA_PER_TXD); tx_buffer_info->length = size; - tx_buffer_info->dma = map[f + 1] + offset; + tx_buffer_info->dma = map[f] + offset; tx_buffer_info->time_stamp = jiffies; tx_buffer_info->next_to_watch = i; len -= size; + total -= size; offset += size; count++; } + if (total == 0) + break; } tx_ring->tx_buffer_info[i].skb = skb; @@ -4337,6 +4953,13 @@ static void ixgbe_tx_queue(struct ixgbe_adapter *adapter, olinfo_status |= IXGBE_TXD_POPTS_TXSM << IXGBE_ADVTXD_POPTS_SHIFT; + if (tx_flags & IXGBE_TX_FLAGS_FCOE) { + olinfo_status |= IXGBE_ADVTXD_CC; + olinfo_status |= (1 << IXGBE_ADVTXD_IDX_SHIFT); + if (tx_flags & IXGBE_TX_FLAGS_FSO) + cmd_type_len |= IXGBE_ADVTXD_DCMD_TSE; + } + olinfo_status |= ((paylen - hdr_len) << IXGBE_ADVTXD_PAYLEN_SHIFT); i = tx_ring->next_to_use; @@ -4366,6 +4989,58 @@ static void ixgbe_tx_queue(struct ixgbe_adapter *adapter, writel(i, adapter->hw.hw_addr + tx_ring->tail); } +static void ixgbe_atr(struct ixgbe_adapter *adapter, struct sk_buff *skb, + int queue, u32 tx_flags) +{ + /* Right now, we support IPv4 only */ + struct ixgbe_atr_input atr_input; + struct tcphdr *th; + struct udphdr *uh; + struct iphdr *iph = ip_hdr(skb); + struct ethhdr *eth = (struct ethhdr *)skb->data; + u16 vlan_id, src_port, dst_port, flex_bytes; + u32 src_ipv4_addr, dst_ipv4_addr; + u8 l4type = 0; + + /* check if we're UDP or TCP */ + if (iph->protocol == IPPROTO_TCP) { + th = tcp_hdr(skb); + src_port = th->source; + dst_port = th->dest; + l4type |= IXGBE_ATR_L4TYPE_TCP; + /* l4type IPv4 type is 0, no need to assign */ + } else if(iph->protocol == IPPROTO_UDP) { + uh = udp_hdr(skb); + src_port = uh->source; + dst_port = uh->dest; + l4type |= IXGBE_ATR_L4TYPE_UDP; + /* l4type IPv4 type is 0, no need to assign */ + } else { + /* Unsupported L4 header, just bail here */ + return; + } + + memset(&atr_input, 0, sizeof(struct ixgbe_atr_input)); + + vlan_id = (tx_flags & IXGBE_TX_FLAGS_VLAN_MASK) >> + IXGBE_TX_FLAGS_VLAN_SHIFT; + src_ipv4_addr = iph->saddr; + dst_ipv4_addr = iph->daddr; + flex_bytes = eth->h_proto; + + ixgbe_atr_set_vlan_id_82599(&atr_input, vlan_id); + ixgbe_atr_set_src_port_82599(&atr_input, dst_port); + ixgbe_atr_set_dst_port_82599(&atr_input, src_port); + ixgbe_atr_set_flex_byte_82599(&atr_input, flex_bytes); + ixgbe_atr_set_l4type_82599(&atr_input, l4type); + /* src and dst are inverted, think how the receiver sees them */ + ixgbe_atr_set_src_ipv4_82599(&atr_input, dst_ipv4_addr); + ixgbe_atr_set_dst_ipv4_82599(&atr_input, src_ipv4_addr); + + /* This assumes the Rx queue and Tx queue are bound to the same CPU */ + ixgbe_fdir_add_signature_filter_82599(&adapter->hw, &atr_input, queue); +} + static int __ixgbe_maybe_stop_tx(struct net_device *netdev, struct ixgbe_ring *tx_ring, int size) { @@ -4400,6 +5075,9 @@ static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb) { struct ixgbe_adapter *adapter = netdev_priv(dev); + if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE) + return smp_processor_id(); + if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) return 0; /* All traffic should default to class 0 */ @@ -4433,10 +5111,16 @@ static int ixgbe_xmit_frame(struct sk_buff *skb, struct net_device *netdev) tx_flags <<= IXGBE_TX_FLAGS_VLAN_SHIFT; tx_flags |= IXGBE_TX_FLAGS_VLAN; } - /* three things can cause us to need a context descriptor */ + + if ((adapter->flags & IXGBE_FLAG_FCOE_ENABLED) && + (skb->protocol == htons(ETH_P_FCOE))) + tx_flags |= IXGBE_TX_FLAGS_FCOE; + + /* four things can cause us to need a context descriptor */ if (skb_is_gso(skb) || (skb->ip_summed == CHECKSUM_PARTIAL) || - (tx_flags & IXGBE_TX_FLAGS_VLAN)) + (tx_flags & IXGBE_TX_FLAGS_VLAN) || + (tx_flags & IXGBE_TX_FLAGS_FCOE)) count++; count += TXD_USE_COUNT(skb_headlen(skb)); @@ -4448,27 +5132,49 @@ static int ixgbe_xmit_frame(struct sk_buff *skb, struct net_device *netdev) return NETDEV_TX_BUSY; } - if (skb->protocol == htons(ETH_P_IP)) - tx_flags |= IXGBE_TX_FLAGS_IPV4; first = tx_ring->next_to_use; - tso = ixgbe_tso(adapter, tx_ring, skb, tx_flags, &hdr_len); - if (tso < 0) { - dev_kfree_skb_any(skb); - return NETDEV_TX_OK; + if (tx_flags & IXGBE_TX_FLAGS_FCOE) { +#ifdef IXGBE_FCOE + /* setup tx offload for FCoE */ + tso = ixgbe_fso(adapter, tx_ring, skb, tx_flags, &hdr_len); + if (tso < 0) { + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + if (tso) + tx_flags |= IXGBE_TX_FLAGS_FSO; +#endif /* IXGBE_FCOE */ + } else { + if (skb->protocol == htons(ETH_P_IP)) + tx_flags |= IXGBE_TX_FLAGS_IPV4; + tso = ixgbe_tso(adapter, tx_ring, skb, tx_flags, &hdr_len); + if (tso < 0) { + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + + if (tso) + tx_flags |= IXGBE_TX_FLAGS_TSO; + else if (ixgbe_tx_csum(adapter, tx_ring, skb, tx_flags) && + (skb->ip_summed == CHECKSUM_PARTIAL)) + tx_flags |= IXGBE_TX_FLAGS_CSUM; } - if (tso) - tx_flags |= IXGBE_TX_FLAGS_TSO; - else if (ixgbe_tx_csum(adapter, tx_ring, skb, tx_flags) && - (skb->ip_summed == CHECKSUM_PARTIAL)) - tx_flags |= IXGBE_TX_FLAGS_CSUM; - - count = ixgbe_tx_map(adapter, tx_ring, skb, first); - + count = ixgbe_tx_map(adapter, tx_ring, skb, tx_flags, first); if (count) { + /* add the ATR filter if ATR is on */ + if (tx_ring->atr_sample_rate) { + ++tx_ring->atr_count; + if ((tx_ring->atr_count >= tx_ring->atr_sample_rate) && + test_bit(__IXGBE_FDIR_INIT_DONE, + &tx_ring->reinit_state)) { + ixgbe_atr(adapter, skb, tx_ring->queue_index, + tx_flags); + tx_ring->atr_count = 0; + } + } ixgbe_tx_queue(adapter, tx_ring, tx_flags, count, skb->len, hdr_len); - netdev->trans_start = jiffies; ixgbe_maybe_stop_tx(netdev, tx_ring, DESC_NEEDED); } else { @@ -4519,6 +5225,82 @@ static int ixgbe_set_mac(struct net_device *netdev, void *p) return 0; } +static int +ixgbe_mdio_read(struct net_device *netdev, int prtad, int devad, u16 addr) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct ixgbe_hw *hw = &adapter->hw; + u16 value; + int rc; + + if (prtad != hw->phy.mdio.prtad) + return -EINVAL; + rc = hw->phy.ops.read_reg(hw, addr, devad, &value); + if (!rc) + rc = value; + return rc; +} + +static int ixgbe_mdio_write(struct net_device *netdev, int prtad, int devad, + u16 addr, u16 value) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct ixgbe_hw *hw = &adapter->hw; + + if (prtad != hw->phy.mdio.prtad) + return -EINVAL; + return hw->phy.ops.write_reg(hw, addr, devad, value); +} + +static int ixgbe_ioctl(struct net_device *netdev, struct ifreq *req, int cmd) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + return mdio_mii_ioctl(&adapter->hw.phy.mdio, if_mii(req), cmd); +} + +/** + * ixgbe_add_sanmac_netdev - Add the SAN MAC address to the corresponding + * netdev->dev_addrs + * @netdev: network interface device structure + * + * Returns non-zero on failure + **/ +static int ixgbe_add_sanmac_netdev(struct net_device *dev) +{ + int err = 0; + struct ixgbe_adapter *adapter = netdev_priv(dev); + struct ixgbe_mac_info *mac = &adapter->hw.mac; + + if (is_valid_ether_addr(mac->san_addr)) { + rtnl_lock(); + err = dev_addr_add(dev, mac->san_addr, NETDEV_HW_ADDR_T_SAN); + rtnl_unlock(); + } + return err; +} + +/** + * ixgbe_del_sanmac_netdev - Removes the SAN MAC address to the corresponding + * netdev->dev_addrs + * @netdev: network interface device structure + * + * Returns non-zero on failure + **/ +static int ixgbe_del_sanmac_netdev(struct net_device *dev) +{ + int err = 0; + struct ixgbe_adapter *adapter = netdev_priv(dev); + struct ixgbe_mac_info *mac = &adapter->hw.mac; + + if (is_valid_ether_addr(mac->san_addr)) { + rtnl_lock(); + err = dev_addr_del(dev, mac->san_addr, NETDEV_HW_ADDR_T_SAN); + rtnl_unlock(); + } + return err; +} + #ifdef CONFIG_NET_POLL_CONTROLLER /* * Polling 'interrupt' - used by things like netconsole to send skbs @@ -4552,9 +5334,14 @@ static const struct net_device_ops ixgbe_netdev_ops = { .ndo_vlan_rx_register = ixgbe_vlan_rx_register, .ndo_vlan_rx_add_vid = ixgbe_vlan_rx_add_vid, .ndo_vlan_rx_kill_vid = ixgbe_vlan_rx_kill_vid, + .ndo_do_ioctl = ixgbe_ioctl, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = ixgbe_netpoll, #endif +#ifdef IXGBE_FCOE + .ndo_fcoe_ddp_setup = ixgbe_fcoe_ddp_get, + .ndo_fcoe_ddp_done = ixgbe_fcoe_ddp_put, +#endif /* IXGBE_FCOE */ }; /** @@ -4577,9 +5364,12 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, const struct ixgbe_info *ii = ixgbe_info_tbl[ent->driver_data]; static int cards_found; int i, err, pci_using_dac; +#ifdef IXGBE_FCOE + u16 device_caps; +#endif u32 part_num, eec; - err = pci_enable_device(pdev); + err = pci_enable_device_mem(pdev); if (err) return err; @@ -4599,9 +5389,11 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, pci_using_dac = 0; } - err = pci_request_regions(pdev, ixgbe_driver_name); + err = pci_request_selected_regions(pdev, pci_select_bars(pdev, + IORESOURCE_MEM), ixgbe_driver_name); if (err) { - dev_err(&pdev->dev, "pci_request_regions failed 0x%x\n", err); + dev_err(&pdev->dev, + "pci_request_selected_regions failed 0x%x\n", err); goto err_pci_reg; } @@ -4665,6 +5457,13 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, /* PHY */ memcpy(&hw->phy.ops, ii->phy_ops, sizeof(hw->phy.ops)); hw->phy.sfp_type = ixgbe_sfp_type_unknown; + /* ixgbe_identify_phy_generic will set prtad and mmds properly */ + hw->phy.mdio.prtad = MDIO_PRTAD_NONE; + hw->phy.mdio.mmds = 0; + hw->phy.mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22; + hw->phy.mdio.dev = netdev; + hw->phy.mdio.mdio_read = ixgbe_mdio_read; + hw->phy.mdio.mdio_write = ixgbe_mdio_write; /* set up this timer and work struct before calling get_invariants * which might start the timer @@ -4682,29 +5481,42 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, INIT_WORK(&adapter->sfp_config_module_task, ixgbe_sfp_config_module_task); - err = ii->get_invariants(hw); - if (err == IXGBE_ERR_SFP_NOT_PRESENT) { - /* start a kernel thread to watch for a module to arrive */ - set_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state); - mod_timer(&adapter->sfp_timer, - round_jiffies(jiffies + (2 * HZ))); - err = 0; - } else if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { - DPRINTK(PROBE, ERR, "failed to load because an " - "unsupported SFP+ module type was detected.\n"); - goto err_hw_init; - } else if (err) { - goto err_hw_init; - } + ii->get_invariants(hw); /* setup the private structure */ err = ixgbe_sw_init(adapter); if (err) goto err_sw_init; + /* + * If there is a fan on this device and it has failed log the + * failure. + */ + if (adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE) { + u32 esdp = IXGBE_READ_REG(hw, IXGBE_ESDP); + if (esdp & IXGBE_ESDP_SDP1) + DPRINTK(PROBE, CRIT, + "Fan has stopped, replace the adapter\n"); + } + /* reset_hw fills in the perm_addr as well */ err = hw->mac.ops.reset_hw(hw); - if (err) { + if (err == IXGBE_ERR_SFP_NOT_PRESENT && + hw->mac.type == ixgbe_mac_82598EB) { + /* + * Start a kernel thread to watch for a module to arrive. + * Only do this for 82598, since 82599 will generate + * interrupts on module arrival. + */ + set_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state); + mod_timer(&adapter->sfp_timer, + round_jiffies(jiffies + (2 * HZ))); + err = 0; + } else if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { + dev_err(&adapter->pdev->dev, "failed to load because an " + "unsupported SFP+ module type was detected.\n"); + goto err_sw_init; + } else if (err) { dev_err(&adapter->pdev->dev, "HW Init failed: %d\n", err); goto err_sw_init; } @@ -4720,6 +5532,9 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, netdev->features |= NETIF_F_TSO6; netdev->features |= NETIF_F_GRO; + if (adapter->hw.mac.type == ixgbe_mac_82599EB) + netdev->features |= NETIF_F_SCTP_CSUM; + netdev->vlan_features |= NETIF_F_TSO; netdev->vlan_features |= NETIF_F_TSO6; netdev->vlan_features |= NETIF_F_IP_CSUM; @@ -4732,9 +5547,32 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, netdev->dcbnl_ops = &dcbnl_ops; #endif +#ifdef IXGBE_FCOE + if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) { + if (hw->mac.ops.get_device_caps) { + hw->mac.ops.get_device_caps(hw, &device_caps); + if (!(device_caps & IXGBE_DEVICE_CAPS_FCOE_OFFLOADS)) { + netdev->features |= NETIF_F_FCOE_CRC; + netdev->features |= NETIF_F_FSO; + netdev->fcoe_ddp_xid = IXGBE_FCOE_DDP_MAX - 1; + DPRINTK(DRV, INFO, "FCoE enabled, " + "disabling Flow Director\n"); + adapter->flags &= ~IXGBE_FLAG_FDIR_HASH_CAPABLE; + adapter->flags &= + ~IXGBE_FLAG_FDIR_PERFECT_CAPABLE; + adapter->atr_sample_rate = 0; + } else { + adapter->flags &= ~IXGBE_FLAG_FCOE_ENABLED; + } + } + } +#endif /* IXGBE_FCOE */ if (pci_using_dac) netdev->features |= NETIF_F_HIGHDMA; + if (adapter->flags & IXGBE_FLAG2_RSC_ENABLED) + netdev->features |= NETIF_F_LRO; + /* make sure the EEPROM is good */ if (hw->eeprom.ops.validate_checksum(hw, NULL) < 0) { dev_err(&pdev->dev, "The EEPROM Checksum Is Not Valid\n"); @@ -4766,6 +5604,9 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, case IXGBE_DEV_ID_82599_KX4: adapter->wol = (IXGBE_WUFC_MAG | IXGBE_WUFC_EX | IXGBE_WUFC_MC | IXGBE_WUFC_BC); + /* Enable ACPI wakeup in GRC */ + IXGBE_WRITE_REG(hw, IXGBE_GRC, + (IXGBE_READ_REG(hw, IXGBE_GRC) & ~IXGBE_GRC_APME)); break; default: adapter->wol = 0; @@ -4774,6 +5615,9 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, device_init_wakeup(&adapter->pdev->dev, true); device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol); + /* pick up the PCI bus settings for reporting later */ + hw->mac.ops.get_bus_info(hw); + /* print bus type/speed/width info */ dev_info(&pdev->dev, "(PCI Express:%s:%s) %pM\n", ((hw->bus.speed == ixgbe_bus_speed_5000) ? "5.0Gb/s": @@ -4805,24 +5649,37 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, hw->eeprom.ops.read(hw, 0x29, &adapter->eeprom_version); /* reset the hardware with the new settings */ - hw->mac.ops.start_hw(hw); - - netif_carrier_off(netdev); + err = hw->mac.ops.start_hw(hw); + if (err == IXGBE_ERR_EEPROM_VERSION) { + /* We are running on a pre-production device, log a warning */ + dev_warn(&pdev->dev, "This device is a pre-production " + "adapter/LOM. Please be aware there may be issues " + "associated with your hardware. If you are " + "experiencing problems please contact your Intel or " + "hardware representative who provided you with this " + "hardware.\n"); + } strcpy(netdev->name, "eth%d"); err = register_netdev(netdev); if (err) goto err_register; + /* carrier off reporting is important to ethtool even BEFORE open */ + netif_carrier_off(netdev); + + if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE || + adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE) + INIT_WORK(&adapter->fdir_reinit_task, ixgbe_fdir_reinit_task); + #ifdef CONFIG_IXGBE_DCA if (dca_add_requester(&pdev->dev) == 0) { adapter->flags |= IXGBE_FLAG_DCA_ENABLED; - /* always use CB2 mode, difference is masked - * in the CB driver */ - IXGBE_WRITE_REG(hw, IXGBE_DCA_CTRL, 2); ixgbe_setup_dca(adapter); } #endif + /* add san mac addr to netdev */ + ixgbe_add_sanmac_netdev(netdev); dev_info(&pdev->dev, "Intel(R) 10 Gigabit Network Connection\n"); cards_found++; @@ -4830,9 +5687,8 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, err_register: ixgbe_release_hw_control(adapter); -err_hw_init: + ixgbe_clear_interrupt_scheme(adapter); err_sw_init: - ixgbe_reset_interrupt_capability(adapter); err_eeprom: clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state); del_timer_sync(&adapter->sfp_timer); @@ -4843,7 +5699,8 @@ err_eeprom: err_ioremap: free_netdev(netdev); err_alloc_etherdev: - pci_release_regions(pdev); + pci_release_selected_regions(pdev, pci_select_bars(pdev, + IORESOURCE_MEM)); err_pci_reg: err_dma: pci_disable_device(pdev); @@ -4877,6 +5734,9 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev) cancel_work_sync(&adapter->sfp_task); cancel_work_sync(&adapter->multispeed_fiber_task); cancel_work_sync(&adapter->sfp_config_module_task); + if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE || + adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE) + cancel_work_sync(&adapter->fdir_reinit_task); flush_scheduled_work(); #ifdef CONFIG_IXGBE_DCA @@ -4887,19 +5747,27 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev) } #endif +#ifdef IXGBE_FCOE + if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) + ixgbe_cleanup_fcoe(adapter); + +#endif /* IXGBE_FCOE */ + + /* remove the added san mac */ + ixgbe_del_sanmac_netdev(netdev); + if (netdev->reg_state == NETREG_REGISTERED) unregister_netdev(netdev); - ixgbe_reset_interrupt_capability(adapter); + ixgbe_clear_interrupt_scheme(adapter); ixgbe_release_hw_control(adapter); iounmap(adapter->hw.hw_addr); - pci_release_regions(pdev); + pci_release_selected_regions(pdev, pci_select_bars(pdev, + IORESOURCE_MEM)); DPRINTK(PROBE, INFO, "complete\n"); - kfree(adapter->tx_ring); - kfree(adapter->rx_ring); free_netdev(netdev); @@ -4927,6 +5795,9 @@ static pci_ers_result_t ixgbe_io_error_detected(struct pci_dev *pdev, netif_device_detach(netdev); + if (state == pci_channel_io_perm_failure) + return PCI_ERS_RESULT_DISCONNECT; + if (netif_running(netdev)) ixgbe_down(adapter); pci_disable_device(pdev); @@ -4948,7 +5819,7 @@ static pci_ers_result_t ixgbe_io_slot_reset(struct pci_dev *pdev) pci_ers_result_t result; int err; - if (pci_enable_device(pdev)) { + if (pci_enable_device_mem(pdev)) { DPRINTK(PROBE, ERR, "Cannot re-enable PCI device after reset.\n"); result = PCI_ERS_RESULT_DISCONNECT; @@ -4956,8 +5827,7 @@ static pci_ers_result_t ixgbe_io_slot_reset(struct pci_dev *pdev) pci_set_master(pdev); pci_restore_state(pdev); - pci_enable_wake(pdev, PCI_D3hot, 0); - pci_enable_wake(pdev, PCI_D3cold, 0); + pci_wake_from_d3(pdev, false); ixgbe_reset(adapter); IXGBE_WRITE_REG(&adapter->hw, IXGBE_WUS, ~0); diff --git a/drivers/net/ixgbe/ixgbe_phy.c b/drivers/net/ixgbe/ixgbe_phy.c index 14e9606aa3b3..453e966762f0 100644 --- a/drivers/net/ixgbe/ixgbe_phy.c +++ b/drivers/net/ixgbe/ixgbe_phy.c @@ -44,7 +44,6 @@ static void ixgbe_lower_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl); static s32 ixgbe_set_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl, bool data); static bool ixgbe_get_i2c_data(u32 *i2cctl); static void ixgbe_i2c_bus_clear(struct ixgbe_hw *hw); -static bool ixgbe_validate_phy_addr(struct ixgbe_hw *hw, u32 phy_addr); static enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id); static s32 ixgbe_get_phy_id(struct ixgbe_hw *hw); @@ -61,8 +60,7 @@ s32 ixgbe_identify_phy_generic(struct ixgbe_hw *hw) if (hw->phy.type == ixgbe_phy_unknown) { for (phy_addr = 0; phy_addr < IXGBE_MAX_PHY_ADDR; phy_addr++) { - if (ixgbe_validate_phy_addr(hw, phy_addr)) { - hw->phy.addr = phy_addr; + if (mdio45_probe(&hw->phy.mdio, phy_addr) == 0) { ixgbe_get_phy_id(hw); hw->phy.type = ixgbe_get_phy_type_from_id(hw->phy.id); @@ -77,26 +75,6 @@ s32 ixgbe_identify_phy_generic(struct ixgbe_hw *hw) return status; } -/** - * ixgbe_validate_phy_addr - Determines phy address is valid - * @hw: pointer to hardware structure - * - **/ -static bool ixgbe_validate_phy_addr(struct ixgbe_hw *hw, u32 phy_addr) -{ - u16 phy_id = 0; - bool valid = false; - - hw->phy.addr = phy_addr; - hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_ID_HIGH, - IXGBE_MDIO_PMA_PMD_DEV_TYPE, &phy_id); - - if (phy_id != 0xFFFF && phy_id != 0x0) - valid = true; - - return valid; -} - /** * ixgbe_get_phy_id - Get the phy type * @hw: pointer to hardware structure @@ -108,14 +86,12 @@ static s32 ixgbe_get_phy_id(struct ixgbe_hw *hw) u16 phy_id_high = 0; u16 phy_id_low = 0; - status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_ID_HIGH, - IXGBE_MDIO_PMA_PMD_DEV_TYPE, + status = hw->phy.ops.read_reg(hw, MDIO_DEVID1, MDIO_MMD_PMAPMD, &phy_id_high); if (status == 0) { hw->phy.id = (u32)(phy_id_high << 16); - status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_ID_LOW, - IXGBE_MDIO_PMA_PMD_DEV_TYPE, + status = hw->phy.ops.read_reg(hw, MDIO_DEVID2, MDIO_MMD_PMAPMD, &phy_id_low); hw->phy.id |= (u32)(phy_id_low & IXGBE_PHY_REVISION_MASK); hw->phy.revision = (u32)(phy_id_low & ~IXGBE_PHY_REVISION_MASK); @@ -160,9 +136,8 @@ s32 ixgbe_reset_phy_generic(struct ixgbe_hw *hw) * Perform soft PHY reset to the PHY_XS. * This will cause a soft reset to the PHY */ - return hw->phy.ops.write_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL, - IXGBE_MDIO_PHY_XS_DEV_TYPE, - IXGBE_MDIO_PHY_XS_RESET); + return hw->phy.ops.write_reg(hw, MDIO_CTRL1, MDIO_MMD_PHYXS, + MDIO_CTRL1_RESET); } /** @@ -192,7 +167,7 @@ s32 ixgbe_read_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr, /* Setup and write the address cycle command */ command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) | (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) | - (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) | + (hw->phy.mdio.prtad << IXGBE_MSCA_PHY_ADDR_SHIFT) | (IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND)); IXGBE_WRITE_REG(hw, IXGBE_MSCA, command); @@ -223,7 +198,8 @@ s32 ixgbe_read_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr, */ command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) | (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) | - (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) | + (hw->phy.mdio.prtad << + IXGBE_MSCA_PHY_ADDR_SHIFT) | (IXGBE_MSCA_READ | IXGBE_MSCA_MDI_COMMAND)); IXGBE_WRITE_REG(hw, IXGBE_MSCA, command); @@ -292,7 +268,7 @@ s32 ixgbe_write_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr, /* Setup and write the address cycle command */ command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) | (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) | - (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) | + (hw->phy.mdio.prtad << IXGBE_MSCA_PHY_ADDR_SHIFT) | (IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND)); IXGBE_WRITE_REG(hw, IXGBE_MSCA, command); @@ -323,7 +299,8 @@ s32 ixgbe_write_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr, */ command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) | (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) | - (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) | + (hw->phy.mdio.prtad << + IXGBE_MSCA_PHY_ADDR_SHIFT) | (IXGBE_MSCA_WRITE | IXGBE_MSCA_MDI_COMMAND)); IXGBE_WRITE_REG(hw, IXGBE_MSCA, command); @@ -365,7 +342,7 @@ s32 ixgbe_setup_phy_link_generic(struct ixgbe_hw *hw) s32 status = IXGBE_NOT_IMPLEMENTED; u32 time_out; u32 max_time_out = 10; - u16 autoneg_reg = IXGBE_MII_AUTONEG_REG; + u16 autoneg_reg; /* * Set advertisement settings in PHY based on autoneg_advertised @@ -373,36 +350,31 @@ s32 ixgbe_setup_phy_link_generic(struct ixgbe_hw *hw) * tnx devices cannot be "forced" to a autoneg 10G and fail. But can * for a 1G. */ - hw->phy.ops.read_reg(hw, IXGBE_MII_SPEED_SELECTION_REG, - IXGBE_MDIO_AUTO_NEG_DEV_TYPE, &autoneg_reg); + hw->phy.ops.read_reg(hw, MDIO_AN_ADVERTISE, MDIO_MMD_AN, &autoneg_reg); if (hw->phy.autoneg_advertised == IXGBE_LINK_SPEED_1GB_FULL) - autoneg_reg &= 0xEFFF; /* 0 in bit 12 is 1G operation */ + autoneg_reg &= ~MDIO_AN_10GBT_CTRL_ADV10G; else - autoneg_reg |= 0x1000; /* 1 in bit 12 is 10G/1G operation */ + autoneg_reg |= MDIO_AN_10GBT_CTRL_ADV10G; - hw->phy.ops.write_reg(hw, IXGBE_MII_SPEED_SELECTION_REG, - IXGBE_MDIO_AUTO_NEG_DEV_TYPE, autoneg_reg); + hw->phy.ops.write_reg(hw, MDIO_AN_ADVERTISE, MDIO_MMD_AN, autoneg_reg); /* Restart PHY autonegotiation and wait for completion */ - hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_CONTROL, - IXGBE_MDIO_AUTO_NEG_DEV_TYPE, &autoneg_reg); + hw->phy.ops.read_reg(hw, MDIO_CTRL1, MDIO_MMD_AN, &autoneg_reg); - autoneg_reg |= IXGBE_MII_RESTART; + autoneg_reg |= MDIO_AN_CTRL1_RESTART; - hw->phy.ops.write_reg(hw, IXGBE_MDIO_AUTO_NEG_CONTROL, - IXGBE_MDIO_AUTO_NEG_DEV_TYPE, autoneg_reg); + hw->phy.ops.write_reg(hw, MDIO_CTRL1, MDIO_MMD_AN, autoneg_reg); /* Wait for autonegotiation to finish */ for (time_out = 0; time_out < max_time_out; time_out++) { udelay(10); /* Restart PHY autonegotiation and wait for completion */ - status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_STATUS, - IXGBE_MDIO_AUTO_NEG_DEV_TYPE, + status = hw->phy.ops.read_reg(hw, MDIO_STAT1, MDIO_MMD_AN, &autoneg_reg); - autoneg_reg &= IXGBE_MII_AUTONEG_COMPLETE; - if (autoneg_reg == IXGBE_MII_AUTONEG_COMPLETE) { + autoneg_reg &= MDIO_AN_STAT1_COMPLETE; + if (autoneg_reg == MDIO_AN_STAT1_COMPLETE) { status = 0; break; } @@ -457,23 +429,21 @@ s32 ixgbe_reset_phy_nl(struct ixgbe_hw *hw) s32 ret_val = 0; u32 i; - hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL, - IXGBE_MDIO_PHY_XS_DEV_TYPE, &phy_data); + hw->phy.ops.read_reg(hw, MDIO_CTRL1, MDIO_MMD_PHYXS, &phy_data); /* reset the PHY and poll for completion */ - hw->phy.ops.write_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL, - IXGBE_MDIO_PHY_XS_DEV_TYPE, - (phy_data | IXGBE_MDIO_PHY_XS_RESET)); + hw->phy.ops.write_reg(hw, MDIO_CTRL1, MDIO_MMD_PHYXS, + (phy_data | MDIO_CTRL1_RESET)); for (i = 0; i < 100; i++) { - hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL, - IXGBE_MDIO_PHY_XS_DEV_TYPE, &phy_data); - if ((phy_data & IXGBE_MDIO_PHY_XS_RESET) == 0) + hw->phy.ops.read_reg(hw, MDIO_CTRL1, MDIO_MMD_PHYXS, + &phy_data); + if ((phy_data & MDIO_CTRL1_RESET) == 0) break; msleep(10); } - if ((phy_data & IXGBE_MDIO_PHY_XS_RESET) != 0) { + if ((phy_data & MDIO_CTRL1_RESET) != 0) { hw_dbg(hw, "PHY reset did not complete.\n"); ret_val = IXGBE_ERR_PHY; goto out; @@ -509,7 +479,7 @@ s32 ixgbe_reset_phy_nl(struct ixgbe_hw *hw) for (i = 0; i < edata; i++) { hw->eeprom.ops.read(hw, data_offset, &eword); hw->phy.ops.write_reg(hw, phy_offset, - IXGBE_TWINAX_DEV, eword); + MDIO_MMD_PMAPMD, eword); hw_dbg(hw, "Wrote %4.4x to %4.4x\n", eword, phy_offset); data_offset++; @@ -552,18 +522,30 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) { s32 status = IXGBE_ERR_PHY_ADDR_INVALID; u32 vendor_oui = 0; + enum ixgbe_sfp_type stored_sfp_type = hw->phy.sfp_type; u8 identifier = 0; u8 comp_codes_1g = 0; u8 comp_codes_10g = 0; u8 oui_bytes[3] = {0, 0, 0}; - u8 transmission_media = 0; + u8 cable_tech = 0; u16 enforce_sfp = 0; + if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_fiber) { + hw->phy.sfp_type = ixgbe_sfp_type_not_present; + status = IXGBE_ERR_SFP_NOT_PRESENT; + goto out; + } + status = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_IDENTIFIER, &identifier); - if (status == IXGBE_ERR_SFP_NOT_PRESENT) { + if (status == IXGBE_ERR_SFP_NOT_PRESENT || status == IXGBE_ERR_I2C) { + status = IXGBE_ERR_SFP_NOT_PRESENT; hw->phy.sfp_type = ixgbe_sfp_type_not_present; + if (hw->phy.type != ixgbe_phy_nl) { + hw->phy.id = 0; + hw->phy.type = ixgbe_phy_unknown; + } goto out; } @@ -572,8 +554,8 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) &comp_codes_1g); hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_10GBE_COMP_CODES, &comp_codes_10g); - hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_TRANSMISSION_MEDIA, - &transmission_media); + hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_CABLE_TECHNOLOGY, + &cable_tech); /* ID Module * ========= @@ -586,7 +568,7 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) * 6 SFP_SR/LR_CORE1 - 82599-specific */ if (hw->mac.type == ixgbe_mac_82598EB) { - if (transmission_media & IXGBE_SFF_TWIN_AX_CAPABLE) + if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE) hw->phy.sfp_type = ixgbe_sfp_type_da_cu; else if (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE) hw->phy.sfp_type = ixgbe_sfp_type_sr; @@ -595,7 +577,7 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) else hw->phy.sfp_type = ixgbe_sfp_type_unknown; } else if (hw->mac.type == ixgbe_mac_82599EB) { - if (transmission_media & IXGBE_SFF_TWIN_AX_CAPABLE) + if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE) if (hw->bus.lan_id == 0) hw->phy.sfp_type = ixgbe_sfp_type_da_cu_core0; @@ -620,8 +602,19 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) hw->phy.sfp_type = ixgbe_sfp_type_unknown; } + if (hw->phy.sfp_type != stored_sfp_type) + hw->phy.sfp_setup_needed = true; + + /* Determine if the SFP+ PHY is dual speed or not. */ + hw->phy.multispeed_fiber = false; + if (((comp_codes_1g & IXGBE_SFF_1GBASESX_CAPABLE) && + (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE)) || + ((comp_codes_1g & IXGBE_SFF_1GBASELX_CAPABLE) && + (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE))) + hw->phy.multispeed_fiber = true; + /* Determine PHY vendor */ - if (hw->phy.type == ixgbe_phy_unknown) { + if (hw->phy.type != ixgbe_phy_nl) { hw->phy.id = identifier; hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_VENDOR_OUI_BYTE0, @@ -640,8 +633,7 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) switch (vendor_oui) { case IXGBE_SFF_VENDOR_OUI_TYCO: - if (transmission_media & - IXGBE_SFF_TWIN_AX_CAPABLE) + if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE) hw->phy.type = ixgbe_phy_tw_tyco; break; case IXGBE_SFF_VENDOR_OUI_FTL: @@ -654,31 +646,42 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) hw->phy.type = ixgbe_phy_sfp_intel; break; default: - if (transmission_media & - IXGBE_SFF_TWIN_AX_CAPABLE) + if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE) hw->phy.type = ixgbe_phy_tw_unknown; else hw->phy.type = ixgbe_phy_sfp_unknown; break; } } - if (hw->mac.type == ixgbe_mac_82598EB || - (hw->phy.sfp_type != ixgbe_sfp_type_sr && - hw->phy.sfp_type != ixgbe_sfp_type_lr && - hw->phy.sfp_type != ixgbe_sfp_type_srlr_core0 && - hw->phy.sfp_type != ixgbe_sfp_type_srlr_core1)) { + + /* All passive DA cables are supported */ + if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE) { status = 0; goto out; } - hw->eeprom.ops.read(hw, IXGBE_PHY_ENFORCE_INTEL_SFP_OFFSET, - &enforce_sfp); - if (!(enforce_sfp & IXGBE_PHY_ALLOW_ANY_SFP)) { + /* 1G SFP modules are not supported */ + if (comp_codes_10g == 0) { + hw->phy.type = ixgbe_phy_sfp_unsupported; + status = IXGBE_ERR_SFP_NOT_SUPPORTED; + goto out; + } + + /* Anything else 82598-based is supported */ + if (hw->mac.type == ixgbe_mac_82598EB) { + status = 0; + goto out; + } + + /* This is guaranteed to be 82599, no need to check for NULL */ + hw->mac.ops.get_device_caps(hw, &enforce_sfp); + if (!(enforce_sfp & IXGBE_DEVICE_CAPS_ALLOW_ANY_SFP)) { /* Make sure we're a supported PHY type */ if (hw->phy.type == ixgbe_phy_sfp_intel) { status = 0; } else { hw_dbg(hw, "SFP+ module not supported\n"); + hw->phy.type = ixgbe_phy_sfp_unsupported; status = IXGBE_ERR_SFP_NOT_SUPPORTED; } } else { @@ -1279,7 +1282,7 @@ s32 ixgbe_check_phy_link_tnx(struct ixgbe_hw *hw, ixgbe_link_speed *speed, udelay(10); status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_VENDOR_SPECIFIC_1_STATUS, - IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, + MDIO_MMD_VEND1, &phy_data); phy_link = phy_data & IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS; @@ -1307,8 +1310,7 @@ s32 ixgbe_get_phy_firmware_version_tnx(struct ixgbe_hw *hw, { s32 status = 0; - status = hw->phy.ops.read_reg(hw, TNX_FW_REV, - IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, + status = hw->phy.ops.read_reg(hw, TNX_FW_REV, MDIO_MMD_VEND1, firmware_version); return status; diff --git a/drivers/net/ixgbe/ixgbe_phy.h b/drivers/net/ixgbe/ixgbe_phy.h index cc5f1b3287e1..9b700f5bf1ed 100644 --- a/drivers/net/ixgbe/ixgbe_phy.h +++ b/drivers/net/ixgbe/ixgbe_phy.h @@ -39,11 +39,12 @@ #define IXGBE_SFF_VENDOR_OUI_BYTE2 0x27 #define IXGBE_SFF_1GBE_COMP_CODES 0x6 #define IXGBE_SFF_10GBE_COMP_CODES 0x3 -#define IXGBE_SFF_TRANSMISSION_MEDIA 0x9 +#define IXGBE_SFF_CABLE_TECHNOLOGY 0x8 /* Bitmasks */ -#define IXGBE_SFF_TWIN_AX_CAPABLE 0x80 +#define IXGBE_SFF_DA_PASSIVE_CABLE 0x4 #define IXGBE_SFF_1GBASESX_CAPABLE 0x1 +#define IXGBE_SFF_1GBASELX_CAPABLE 0x2 #define IXGBE_SFF_10GBASESR_CAPABLE 0x10 #define IXGBE_SFF_10GBASELR_CAPABLE 0x20 #define IXGBE_I2C_EEPROM_READ_MASK 0x100 diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index 030ff0a9ea67..fa87309dc087 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -29,6 +29,8 @@ #define _IXGBE_TYPE_H_ #include +#include +#include /* Vendor ID */ #define IXGBE_INTEL_VENDOR_ID 0x8086 @@ -45,9 +47,9 @@ #define IXGBE_DEV_ID_82598_DA_DUAL_PORT 0x10F1 #define IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM 0x10E1 #define IXGBE_DEV_ID_82598EB_XF_LR 0x10F4 -#define IXGBE_DEV_ID_82599 0x10D8 #define IXGBE_DEV_ID_82599_KX4 0x10F7 #define IXGBE_DEV_ID_82599_SFP 0x10FB +#define IXGBE_DEV_ID_82599_XAUI_LOM 0x10FC /* General Registers */ #define IXGBE_CTRL 0x00000 @@ -229,6 +231,34 @@ #define IXGBE_RETA(_i) (0x05C00 + ((_i) * 4)) /* 32 of these (0-31) */ #define IXGBE_RSSRK(_i) (0x05C80 + ((_i) * 4)) /* 10 of these (0-9) */ +/* Flow Director registers */ +#define IXGBE_FDIRCTRL 0x0EE00 +#define IXGBE_FDIRHKEY 0x0EE68 +#define IXGBE_FDIRSKEY 0x0EE6C +#define IXGBE_FDIRDIP4M 0x0EE3C +#define IXGBE_FDIRSIP4M 0x0EE40 +#define IXGBE_FDIRTCPM 0x0EE44 +#define IXGBE_FDIRUDPM 0x0EE48 +#define IXGBE_FDIRIP6M 0x0EE74 +#define IXGBE_FDIRM 0x0EE70 + +/* Flow Director Stats registers */ +#define IXGBE_FDIRFREE 0x0EE38 +#define IXGBE_FDIRLEN 0x0EE4C +#define IXGBE_FDIRUSTAT 0x0EE50 +#define IXGBE_FDIRFSTAT 0x0EE54 +#define IXGBE_FDIRMATCH 0x0EE58 +#define IXGBE_FDIRMISS 0x0EE5C + +/* Flow Director Programming registers */ +#define IXGBE_FDIRSIPv6(_i) (0x0EE0C + ((_i) * 4)) /* 3 of these (0-2) */ +#define IXGBE_FDIRIPSA 0x0EE18 +#define IXGBE_FDIRIPDA 0x0EE1C +#define IXGBE_FDIRPORT 0x0EE20 +#define IXGBE_FDIRVLAN 0x0EE24 +#define IXGBE_FDIRHASH 0x0EE28 +#define IXGBE_FDIRCMD 0x0EE2C + /* Transmit DMA registers */ #define IXGBE_TDBAL(_i) (0x06000 + ((_i) * 0x40)) /* 32 of these (0-31)*/ #define IXGBE_TDBAH(_i) (0x06004 + ((_i) * 0x40)) @@ -443,6 +473,21 @@ #define IXGBE_SECTXCTRL_STORE_FORWARD_ENABLE 0x4 +/* HW RSC registers */ +#define IXGBE_RSCCTL(_i) (((_i) < 64) ? (0x0102C + ((_i) * 0x40)) : \ + (0x0D02C + ((_i - 64) * 0x40))) +#define IXGBE_RSCDBU 0x03028 +#define IXGBE_RSCCTL_RSCEN 0x01 +#define IXGBE_RSCCTL_MAXDESC_1 0x00 +#define IXGBE_RSCCTL_MAXDESC_4 0x04 +#define IXGBE_RSCCTL_MAXDESC_8 0x08 +#define IXGBE_RSCCTL_MAXDESC_16 0x0C +#define IXGBE_RXDADV_RSCCNT_SHIFT 17 +#define IXGBE_GPIE_RSC_DELAY_SHIFT 11 +#define IXGBE_RXDADV_RSCCNT_MASK 0x001E0000 +#define IXGBE_RSCDBU_RSCACKDIS 0x00000080 +#define IXGBE_RDRXCTL_RSCFRSTSIZE 0x003E0000 + /* DCB registers */ #define IXGBE_RTRPCS 0x02430 #define IXGBE_RTTDCS 0x04900 @@ -462,6 +507,63 @@ #define IXGBE_RTTDTECC_NO_BCN 0x00000100 #define IXGBE_RTTBCNRC 0x04984 +/* FCoE registers */ +#define IXGBE_FCPTRL 0x02410 /* FC User Desc. PTR Low */ +#define IXGBE_FCPTRH 0x02414 /* FC USer Desc. PTR High */ +#define IXGBE_FCBUFF 0x02418 /* FC Buffer Control */ +#define IXGBE_FCDMARW 0x02420 /* FC Receive DMA RW */ +#define IXGBE_FCINVST0 0x03FC0 /* FC Invalid DMA Context Status Reg 0 */ +#define IXGBE_FCINVST(_i) (IXGBE_FCINVST0 + ((_i) * 4)) +#define IXGBE_FCBUFF_VALID (1 << 0) /* DMA Context Valid */ +#define IXGBE_FCBUFF_BUFFSIZE (3 << 3) /* User Buffer Size */ +#define IXGBE_FCBUFF_WRCONTX (1 << 7) /* 0: Initiator, 1: Target */ +#define IXGBE_FCBUFF_BUFFCNT 0x0000ff00 /* Number of User Buffers */ +#define IXGBE_FCBUFF_OFFSET 0xffff0000 /* User Buffer Offset */ +#define IXGBE_FCBUFF_BUFFSIZE_SHIFT 3 +#define IXGBE_FCBUFF_BUFFCNT_SHIFT 8 +#define IXGBE_FCBUFF_OFFSET_SHIFT 16 +#define IXGBE_FCDMARW_WE (1 << 14) /* Write enable */ +#define IXGBE_FCDMARW_RE (1 << 15) /* Read enable */ +#define IXGBE_FCDMARW_FCOESEL 0x000001ff /* FC X_ID: 11 bits */ +#define IXGBE_FCDMARW_LASTSIZE 0xffff0000 /* Last User Buffer Size */ +#define IXGBE_FCDMARW_LASTSIZE_SHIFT 16 + +/* FCoE SOF/EOF */ +#define IXGBE_TEOFF 0x04A94 /* Tx FC EOF */ +#define IXGBE_TSOFF 0x04A98 /* Tx FC SOF */ +#define IXGBE_REOFF 0x05158 /* Rx FC EOF */ +#define IXGBE_RSOFF 0x051F8 /* Rx FC SOF */ +/* FCoE Filter Context Registers */ +#define IXGBE_FCFLT 0x05108 /* FC FLT Context */ +#define IXGBE_FCFLTRW 0x05110 /* FC Filter RW Control */ +#define IXGBE_FCPARAM 0x051d8 /* FC Offset Parameter */ +#define IXGBE_FCFLT_VALID (1 << 0) /* Filter Context Valid */ +#define IXGBE_FCFLT_FIRST (1 << 1) /* Filter First */ +#define IXGBE_FCFLT_SEQID 0x00ff0000 /* Sequence ID */ +#define IXGBE_FCFLT_SEQCNT 0xff000000 /* Sequence Count */ +#define IXGBE_FCFLTRW_RVALDT (1 << 13) /* Fast Re-Validation */ +#define IXGBE_FCFLTRW_WE (1 << 14) /* Write Enable */ +#define IXGBE_FCFLTRW_RE (1 << 15) /* Read Enable */ +/* FCoE Receive Control */ +#define IXGBE_FCRXCTRL 0x05100 /* FC Receive Control */ +#define IXGBE_FCRXCTRL_FCOELLI (1 << 0) /* Low latency interrupt */ +#define IXGBE_FCRXCTRL_SAVBAD (1 << 1) /* Save Bad Frames */ +#define IXGBE_FCRXCTRL_FRSTRDH (1 << 2) /* EN 1st Read Header */ +#define IXGBE_FCRXCTRL_LASTSEQH (1 << 3) /* EN Last Header in Seq */ +#define IXGBE_FCRXCTRL_ALLH (1 << 4) /* EN All Headers */ +#define IXGBE_FCRXCTRL_FRSTSEQH (1 << 5) /* EN 1st Seq. Header */ +#define IXGBE_FCRXCTRL_ICRC (1 << 6) /* Ignore Bad FC CRC */ +#define IXGBE_FCRXCTRL_FCCRCBO (1 << 7) /* FC CRC Byte Ordering */ +#define IXGBE_FCRXCTRL_FCOEVER 0x00000f00 /* FCoE Version: 4 bits */ +#define IXGBE_FCRXCTRL_FCOEVER_SHIFT 8 +/* FCoE Redirection */ +#define IXGBE_FCRECTL 0x0ED00 /* FC Redirection Control */ +#define IXGBE_FCRETA0 0x0ED10 /* FC Redirection Table 0 */ +#define IXGBE_FCRETA(_i) (IXGBE_FCRETA0 + ((_i) * 4)) /* FCoE Redir */ +#define IXGBE_FCRECTL_ENA 0x1 /* FCoE Redir Table Enable */ +#define IXGBE_FCRETA_SIZE 8 /* Max entries in FCRETA */ +#define IXGBE_FCRETA_ENTRY_MASK 0x0000007f /* 7 bits for the queue index */ + /* Stats registers */ #define IXGBE_CRCERRS 0x04000 #define IXGBE_ILLERRC 0x04004 @@ -533,6 +635,13 @@ #define IXGBE_QPRDC(_i) (0x01430 + ((_i) * 0x40)) /* 16 of these */ #define IXGBE_QBTC_L(_i) (0x08700 + ((_i) * 0x8)) /* 16 of these */ #define IXGBE_QBTC_H(_i) (0x08704 + ((_i) * 0x8)) /* 16 of these */ +#define IXGBE_FCCRC 0x05118 /* Count of Good Eth CRC w/ Bad FC CRC */ +#define IXGBE_FCOERPDC 0x0241C /* FCoE Rx Packets Dropped Count */ +#define IXGBE_FCLAST 0x02424 /* FCoE Last Error Count */ +#define IXGBE_FCOEPRC 0x02428 /* Number of FCoE Packets Received */ +#define IXGBE_FCOEDWRC 0x0242C /* Number of FCoE DWords Received */ +#define IXGBE_FCOEPTC 0x08784 /* Number of FCoE Packets Transmitted */ +#define IXGBE_FCOEDWTC 0x08788 /* Number of FCoE DWords Transmitted */ /* Management */ #define IXGBE_MAVTV(_i) (0x05010 + ((_i) * 4)) /* 8 of these (0-7) */ @@ -833,13 +942,7 @@ /* Omer bit masks */ #define IXGBE_CORECTL_WRITE_CMD 0x00010000 -/* Device Type definitions for new protocol MDIO commands */ -#define IXGBE_MDIO_PMA_PMD_DEV_TYPE 0x1 -#define IXGBE_MDIO_PCS_DEV_TYPE 0x3 -#define IXGBE_MDIO_PHY_XS_DEV_TYPE 0x4 -#define IXGBE_MDIO_AUTO_NEG_DEV_TYPE 0x7 -#define IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE 0x1E /* Device 30 */ -#define IXGBE_TWINAX_DEV 1 +/* MDIO definitions */ #define IXGBE_MDIO_COMMAND_TIMEOUT 100 /* PHY Timeout for 1 GB mode */ @@ -850,31 +953,10 @@ #define IXGBE_MDIO_VENDOR_SPECIFIC_1_10G_SPEED 0x0018 #define IXGBE_MDIO_VENDOR_SPECIFIC_1_1G_SPEED 0x0010 -#define IXGBE_MDIO_AUTO_NEG_CONTROL 0x0 /* AUTO_NEG Control Reg */ -#define IXGBE_MDIO_AUTO_NEG_STATUS 0x1 /* AUTO_NEG Status Reg */ -#define IXGBE_MDIO_PHY_XS_CONTROL 0x0 /* PHY_XS Control Reg */ -#define IXGBE_MDIO_PHY_XS_RESET 0x8000 /* PHY_XS Reset */ -#define IXGBE_MDIO_PHY_ID_HIGH 0x2 /* PHY ID High Reg*/ -#define IXGBE_MDIO_PHY_ID_LOW 0x3 /* PHY ID Low Reg*/ -#define IXGBE_MDIO_PHY_SPEED_ABILITY 0x4 /* Speed Ability Reg */ -#define IXGBE_MDIO_PHY_SPEED_10G 0x0001 /* 10G capable */ -#define IXGBE_MDIO_PHY_SPEED_1G 0x0010 /* 1G capable */ -#define IXGBE_MDIO_PHY_EXT_ABILITY 0xB /* Ext Ability Reg */ -#define IXGBE_MDIO_PHY_10GBASET_ABILITY 0x0004 /* 10GBaseT capable */ -#define IXGBE_MDIO_PHY_1000BASET_ABILITY 0x0020 /* 1000BaseT capable */ - #define IXGBE_MDIO_PMA_PMD_SDA_SCL_ADDR 0xC30A /* PHY_XS SDA/SCL Addr Reg */ #define IXGBE_MDIO_PMA_PMD_SDA_SCL_DATA 0xC30B /* PHY_XS SDA/SCL Data Reg */ #define IXGBE_MDIO_PMA_PMD_SDA_SCL_STAT 0xC30C /* PHY_XS SDA/SCL Status Reg */ -/* MII clause 22/28 definitions */ -#define IXGBE_MDIO_PHY_LOW_POWER_MODE 0x0800 - -#define IXGBE_MII_SPEED_SELECTION_REG 0x10 -#define IXGBE_MII_RESTART 0x200 -#define IXGBE_MII_AUTONEG_COMPLETE 0x20 -#define IXGBE_MII_AUTONEG_REG 0x0 - #define IXGBE_PHY_REVISION_MASK 0xFFFFFFF0 #define IXGBE_MAX_PHY_ADDR 32 @@ -898,8 +980,6 @@ #define IXGBE_CONTROL_NL 0x000F #define IXGBE_CONTROL_EOL_NL 0x0FFF #define IXGBE_CONTROL_SOL_NL 0x0000 -#define IXGBE_PHY_ENFORCE_INTEL_SFP_OFFSET 0x002C -#define IXGBE_PHY_ALLOW_ANY_SFP 0x1 /* General purpose Interrupt Enable */ #define IXGBE_SDP0_GPIEN 0x00000001 /* SDP0 */ @@ -958,6 +1038,8 @@ #define IXGBE_VT_CTL_DIS_DEFPL 0x20000000 /* disable default pool */ #define IXGBE_VT_CTL_REPLEN 0x40000000 /* replication enabled */ #define IXGBE_VT_CTL_VT_ENABLE 0x00000001 /* Enable VT Mode */ +#define IXGBE_VT_CTL_POOL_SHIFT 7 +#define IXGBE_VT_CTL_POOL_MASK (0x3F << IXGBE_VT_CTL_POOL_SHIFT) /* VMOLR bitmasks */ #define IXGBE_VMOLR_AUPE 0x01000000 /* accept untagged packets */ @@ -1148,6 +1230,7 @@ /* Interrupt Vector Allocation Registers */ #define IXGBE_IVAR_REG_NUM 25 +#define IXGBE_IVAR_REG_NUM_82599 64 #define IXGBE_IVAR_TXRX_ENTRY 96 #define IXGBE_IVAR_RX_ENTRY 64 #define IXGBE_IVAR_RX_QUEUE(_i) (0 + (_i)) @@ -1163,6 +1246,7 @@ /* ETYPE Queue Filter/Select Bit Masks */ #define IXGBE_MAX_ETQF_FILTERS 8 +#define IXGBE_ETQF_FCOE 0x08000000 /* bit 27 */ #define IXGBE_ETQF_BCN 0x10000000 /* bit 28 */ #define IXGBE_ETQF_1588 0x40000000 /* bit 30 */ #define IXGBE_ETQF_FILTER_EN 0x80000000 /* bit 31 */ @@ -1185,6 +1269,7 @@ */ #define IXGBE_ETQF_FILTER_EAPOL 0 #define IXGBE_ETQF_FILTER_BCN 1 +#define IXGBE_ETQF_FILTER_FCOE 2 #define IXGBE_ETQF_FILTER_1588 3 /* VLAN Control Bit Masks */ #define IXGBE_VLNCTRL_VET 0x0000FFFF /* bits 0-15 */ @@ -1208,8 +1293,10 @@ #define IXGBE_STATUS_LAN_ID_1 0x00000004 /* LAN ID 1 */ /* ESDP Bit Masks */ -#define IXGBE_ESDP_SDP0 0x00000001 -#define IXGBE_ESDP_SDP1 0x00000002 +#define IXGBE_ESDP_SDP0 0x00000001 /* SDP0 Data Value */ +#define IXGBE_ESDP_SDP1 0x00000002 /* SDP1 Data Value */ +#define IXGBE_ESDP_SDP2 0x00000004 /* SDP2 Data Value */ +#define IXGBE_ESDP_SDP3 0x00000008 /* SDP3 Data Value */ #define IXGBE_ESDP_SDP4 0x00000010 /* SDP4 Data Value */ #define IXGBE_ESDP_SDP5 0x00000020 /* SDP5 Data Value */ #define IXGBE_ESDP_SDP6 0x00000040 /* SDP6 Data Value */ @@ -1309,8 +1396,6 @@ #define IXGBE_LINK_UP_TIME 90 /* 9.0 Seconds */ #define IXGBE_AUTO_NEG_TIME 45 /* 4.5 Seconds */ -#define FIBER_LINK_UP_LIMIT 50 - /* PCS1GLSTA Bit Masks */ #define IXGBE_PCS1GLSTA_LINK_OK 1 #define IXGBE_PCS1GLSTA_SYNK_OK 0x10 @@ -1382,6 +1467,8 @@ #define IXGBE_FW_PTR 0x0F #define IXGBE_PBANUM0_PTR 0x15 #define IXGBE_PBANUM1_PTR 0x16 +#define IXGBE_DEVICE_CAPS 0x2C +#define IXGBE_SAN_MAC_ADDR_PTR 0x28 #define IXGBE_PCIE_MSIX_82599_CAPS 0x72 #define IXGBE_PCIE_MSIX_82598_CAPS 0x62 @@ -1425,6 +1512,13 @@ #define IXGBE_EERD_ATTEMPTS 100000 #endif +#define IXGBE_SAN_MAC_ADDR_PORT0_OFFSET 0x0 +#define IXGBE_SAN_MAC_ADDR_PORT1_OFFSET 0x3 +#define IXGBE_DEVICE_CAPS_ALLOW_ANY_SFP 0x1 +#define IXGBE_DEVICE_CAPS_FCOE_OFFLOADS 0x2 +#define IXGBE_FW_PASSTHROUGH_PATCH_CONFIG_PTR 0x4 +#define IXGBE_FW_PATCH_VERSION_4 0x7 + /* PCI Bus Info */ #define IXGBE_PCI_LINK_STATUS 0xB2 #define IXGBE_PCI_LINK_WIDTH 0x3F0 @@ -1553,7 +1647,8 @@ #define IXGBE_MTQC_RT_ENA 0x1 /* DCB Enable */ #define IXGBE_MTQC_VT_ENA 0x2 /* VMDQ2 Enable */ #define IXGBE_MTQC_64Q_1PB 0x0 /* 64 queues 1 pack buffer */ -#define IXGBE_MTQC_64VF 0x8 /* 2 TX Queues per pool w/64VF's */ +#define IXGBE_MTQC_32VF 0x8 /* 4 TX Queues per pool w/32VF's */ +#define IXGBE_MTQC_64VF 0x4 /* 2 TX Queues per pool w/64VF's */ #define IXGBE_MTQC_8TC_8TQ 0xC /* 8 TC if RT_ENA or 8 TQ if VT_ENA */ /* Receive Descriptor bit definitions */ @@ -1585,6 +1680,11 @@ #define IXGBE_RXD_ERR_IPE 0x80 /* IP Checksum Error */ #define IXGBE_RXDADV_ERR_MASK 0xfff00000 /* RDESC.ERRORS mask */ #define IXGBE_RXDADV_ERR_SHIFT 20 /* RDESC.ERRORS shift */ +#define IXGBE_RXDADV_ERR_FCEOFE 0x80000000 /* FCoEFe/IPE */ +#define IXGBE_RXDADV_ERR_FCERR 0x00700000 /* FCERR/FDIRERR */ +#define IXGBE_RXDADV_ERR_FDIR_LEN 0x00100000 /* FDIR Length error */ +#define IXGBE_RXDADV_ERR_FDIR_DROP 0x00200000 /* FDIR Drop error */ +#define IXGBE_RXDADV_ERR_FDIR_COLL 0x00400000 /* FDIR Collision error */ #define IXGBE_RXDADV_ERR_HBO 0x00800000 /*Header Buffer Overflow */ #define IXGBE_RXDADV_ERR_CE 0x01000000 /* CRC Error */ #define IXGBE_RXDADV_ERR_LE 0x02000000 /* Length Error */ @@ -1604,12 +1704,19 @@ #define IXGBE_RXDADV_STAT_FLM IXGBE_RXD_STAT_FLM /* FDir Match */ #define IXGBE_RXDADV_STAT_VP IXGBE_RXD_STAT_VP /* IEEE VLAN Pkt */ #define IXGBE_RXDADV_STAT_MASK 0x000fffff /* Stat/NEXTP: bit 0-19 */ +#define IXGBE_RXDADV_STAT_FCEOFS 0x00000040 /* FCoE EOF/SOF Stat */ +#define IXGBE_RXDADV_STAT_FCSTAT 0x00000030 /* FCoE Pkt Stat */ +#define IXGBE_RXDADV_STAT_FCSTAT_NOMTCH 0x00000000 /* 00: No Ctxt Match */ +#define IXGBE_RXDADV_STAT_FCSTAT_NODDP 0x00000010 /* 01: Ctxt w/o DDP */ +#define IXGBE_RXDADV_STAT_FCSTAT_FCPRSP 0x00000020 /* 10: Recv. FCP_RSP */ +#define IXGBE_RXDADV_STAT_FCSTAT_DDP 0x00000030 /* 11: Ctxt w/ DDP */ /* PSRTYPE bit definitions */ #define IXGBE_PSRTYPE_TCPHDR 0x00000010 #define IXGBE_PSRTYPE_UDPHDR 0x00000020 #define IXGBE_PSRTYPE_IPV4HDR 0x00000100 #define IXGBE_PSRTYPE_IPV6HDR 0x00000200 +#define IXGBE_PSRTYPE_L2HDR 0x00001000 /* SRRCTL bit definitions */ #define IXGBE_SRRCTL_BSIZEPKT_SHIFT 10 /* so many KBs */ @@ -1710,6 +1817,82 @@ #endif +enum ixgbe_fdir_pballoc_type { + IXGBE_FDIR_PBALLOC_64K = 0, + IXGBE_FDIR_PBALLOC_128K, + IXGBE_FDIR_PBALLOC_256K, +}; +#define IXGBE_FDIR_PBALLOC_SIZE_SHIFT 16 + +/* Flow Director register values */ +#define IXGBE_FDIRCTRL_PBALLOC_64K 0x00000001 +#define IXGBE_FDIRCTRL_PBALLOC_128K 0x00000002 +#define IXGBE_FDIRCTRL_PBALLOC_256K 0x00000003 +#define IXGBE_FDIRCTRL_INIT_DONE 0x00000008 +#define IXGBE_FDIRCTRL_PERFECT_MATCH 0x00000010 +#define IXGBE_FDIRCTRL_REPORT_STATUS 0x00000020 +#define IXGBE_FDIRCTRL_REPORT_STATUS_ALWAYS 0x00000080 +#define IXGBE_FDIRCTRL_DROP_Q_SHIFT 8 +#define IXGBE_FDIRCTRL_FLEX_SHIFT 16 +#define IXGBE_FDIRCTRL_SEARCHLIM 0x00800000 +#define IXGBE_FDIRCTRL_MAX_LENGTH_SHIFT 24 +#define IXGBE_FDIRCTRL_FULL_THRESH_MASK 0xF0000000 +#define IXGBE_FDIRCTRL_FULL_THRESH_SHIFT 28 + +#define IXGBE_FDIRTCPM_DPORTM_SHIFT 16 +#define IXGBE_FDIRUDPM_DPORTM_SHIFT 16 +#define IXGBE_FDIRIP6M_DIPM_SHIFT 16 +#define IXGBE_FDIRM_VLANID 0x00000001 +#define IXGBE_FDIRM_VLANP 0x00000002 +#define IXGBE_FDIRM_POOL 0x00000004 +#define IXGBE_FDIRM_L3P 0x00000008 +#define IXGBE_FDIRM_L4P 0x00000010 +#define IXGBE_FDIRM_FLEX 0x00000020 +#define IXGBE_FDIRM_DIPv6 0x00000040 + +#define IXGBE_FDIRFREE_FREE_MASK 0xFFFF +#define IXGBE_FDIRFREE_FREE_SHIFT 0 +#define IXGBE_FDIRFREE_COLL_MASK 0x7FFF0000 +#define IXGBE_FDIRFREE_COLL_SHIFT 16 +#define IXGBE_FDIRLEN_MAXLEN_MASK 0x3F +#define IXGBE_FDIRLEN_MAXLEN_SHIFT 0 +#define IXGBE_FDIRLEN_MAXHASH_MASK 0x7FFF0000 +#define IXGBE_FDIRLEN_MAXHASH_SHIFT 16 +#define IXGBE_FDIRUSTAT_ADD_MASK 0xFFFF +#define IXGBE_FDIRUSTAT_ADD_SHIFT 0 +#define IXGBE_FDIRUSTAT_REMOVE_MASK 0xFFFF0000 +#define IXGBE_FDIRUSTAT_REMOVE_SHIFT 16 +#define IXGBE_FDIRFSTAT_FADD_MASK 0x00FF +#define IXGBE_FDIRFSTAT_FADD_SHIFT 0 +#define IXGBE_FDIRFSTAT_FREMOVE_MASK 0xFF00 +#define IXGBE_FDIRFSTAT_FREMOVE_SHIFT 8 +#define IXGBE_FDIRPORT_DESTINATION_SHIFT 16 +#define IXGBE_FDIRVLAN_FLEX_SHIFT 16 +#define IXGBE_FDIRHASH_BUCKET_VALID_SHIFT 15 +#define IXGBE_FDIRHASH_SIG_SW_INDEX_SHIFT 16 + +#define IXGBE_FDIRCMD_CMD_MASK 0x00000003 +#define IXGBE_FDIRCMD_CMD_ADD_FLOW 0x00000001 +#define IXGBE_FDIRCMD_CMD_REMOVE_FLOW 0x00000002 +#define IXGBE_FDIRCMD_CMD_QUERY_REM_FILT 0x00000003 +#define IXGBE_FDIRCMD_CMD_QUERY_REM_HASH 0x00000007 +#define IXGBE_FDIRCMD_FILTER_UPDATE 0x00000008 +#define IXGBE_FDIRCMD_IPv6DMATCH 0x00000010 +#define IXGBE_FDIRCMD_L4TYPE_UDP 0x00000020 +#define IXGBE_FDIRCMD_L4TYPE_TCP 0x00000040 +#define IXGBE_FDIRCMD_L4TYPE_SCTP 0x00000060 +#define IXGBE_FDIRCMD_IPV6 0x00000080 +#define IXGBE_FDIRCMD_CLEARHT 0x00000100 +#define IXGBE_FDIRCMD_DROP 0x00000200 +#define IXGBE_FDIRCMD_INT 0x00000400 +#define IXGBE_FDIRCMD_LAST 0x00000800 +#define IXGBE_FDIRCMD_COLLISION 0x00001000 +#define IXGBE_FDIRCMD_QUEUE_EN 0x00008000 +#define IXGBE_FDIRCMD_RX_QUEUE_SHIFT 16 +#define IXGBE_FDIRCMD_VT_POOL_SHIFT 24 +#define IXGBE_FDIR_INIT_DONE_POLL 10 +#define IXGBE_FDIRCMD_CMD_POLL 10 + /* Transmit Descriptor - Legacy */ struct ixgbe_legacy_tx_desc { u64 buffer_addr; /* Address of the descriptor's data buffer */ @@ -1836,6 +2019,16 @@ struct ixgbe_adv_tx_context_desc { #define IXGBE_ADVTXD_POPTS_IPSEC 0x00000400 /* IPSec offload request */ #define IXGBE_ADVTXD_TUCMD_IPSEC_TYPE_ESP 0x00002000 /* IPSec Type ESP */ #define IXGBE_ADVTXD_TUCMD_IPSEC_ENCRYPT_EN 0x00004000/* ESP Encrypt Enable */ +#define IXGBE_ADVTXT_TUCMD_FCOE 0x00008000 /* FCoE Frame Type */ +#define IXGBE_ADVTXD_FCOEF_EOF_MASK (0x3 << 10) /* FC EOF index */ +#define IXGBE_ADVTXD_FCOEF_SOF ((1 << 2) << 10) /* FC SOF index */ +#define IXGBE_ADVTXD_FCOEF_PARINC ((1 << 3) << 10) /* Rel_Off in F_CTL */ +#define IXGBE_ADVTXD_FCOEF_ORIE ((1 << 4) << 10) /* Orientation: End */ +#define IXGBE_ADVTXD_FCOEF_ORIS ((1 << 5) << 10) /* Orientation: Start */ +#define IXGBE_ADVTXD_FCOEF_EOF_N (0x0 << 10) /* 00: EOFn */ +#define IXGBE_ADVTXD_FCOEF_EOF_T (0x1 << 10) /* 01: EOFt */ +#define IXGBE_ADVTXD_FCOEF_EOF_NI (0x2 << 10) /* 10: EOFni */ +#define IXGBE_ADVTXD_FCOEF_EOF_A (0x3 << 10) /* 11: EOFa */ #define IXGBE_ADVTXD_L4LEN_SHIFT 8 /* Adv ctxt L4LEN shift */ #define IXGBE_ADVTXD_MSS_SHIFT 16 /* Adv ctxt MSS shift */ @@ -1861,7 +2054,7 @@ typedef u32 ixgbe_physical_layer; #define IXGBE_PHYSICAL_LAYER_UNKNOWN 0 #define IXGBE_PHYSICAL_LAYER_10GBASE_T 0x0001 #define IXGBE_PHYSICAL_LAYER_1000BASE_T 0x0002 -#define IXGBE_PHYSICAL_LAYER_100BASE_T 0x0004 +#define IXGBE_PHYSICAL_LAYER_100BASE_TX 0x0004 #define IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU 0x0008 #define IXGBE_PHYSICAL_LAYER_10GBASE_LR 0x0010 #define IXGBE_PHYSICAL_LAYER_10GBASE_LRM 0x0020 @@ -1870,6 +2063,47 @@ typedef u32 ixgbe_physical_layer; #define IXGBE_PHYSICAL_LAYER_10GBASE_CX4 0x0100 #define IXGBE_PHYSICAL_LAYER_1000BASE_KX 0x0200 #define IXGBE_PHYSICAL_LAYER_1000BASE_BX 0x0400 +#define IXGBE_PHYSICAL_LAYER_10GBASE_KR 0x0800 +#define IXGBE_PHYSICAL_LAYER_10GBASE_XAUI 0x1000 + +/* Software ATR hash keys */ +#define IXGBE_ATR_BUCKET_HASH_KEY 0xE214AD3D +#define IXGBE_ATR_SIGNATURE_HASH_KEY 0x14364D17 + +/* Software ATR input stream offsets and masks */ +#define IXGBE_ATR_VLAN_OFFSET 0 +#define IXGBE_ATR_SRC_IPV6_OFFSET 2 +#define IXGBE_ATR_SRC_IPV4_OFFSET 14 +#define IXGBE_ATR_DST_IPV6_OFFSET 18 +#define IXGBE_ATR_DST_IPV4_OFFSET 30 +#define IXGBE_ATR_SRC_PORT_OFFSET 34 +#define IXGBE_ATR_DST_PORT_OFFSET 36 +#define IXGBE_ATR_FLEX_BYTE_OFFSET 38 +#define IXGBE_ATR_VM_POOL_OFFSET 40 +#define IXGBE_ATR_L4TYPE_OFFSET 41 + +#define IXGBE_ATR_L4TYPE_MASK 0x3 +#define IXGBE_ATR_L4TYPE_IPV6_MASK 0x4 +#define IXGBE_ATR_L4TYPE_UDP 0x1 +#define IXGBE_ATR_L4TYPE_TCP 0x2 +#define IXGBE_ATR_L4TYPE_SCTP 0x3 +#define IXGBE_ATR_HASH_MASK 0x7fff + +/* Flow Director ATR input struct. */ +struct ixgbe_atr_input { + /* Byte layout in order, all values with MSB first: + * + * vlan_id - 2 bytes + * src_ip - 16 bytes + * dst_ip - 16 bytes + * src_port - 2 bytes + * dst_port - 2 bytes + * flex_bytes - 2 bytes + * vm_pool - 1 byte + * l4type - 1 byte + */ + u8 byte_stream[42]; +}; enum ixgbe_eeprom_type { ixgbe_eeprom_uninitialized = 0, @@ -1897,6 +2131,7 @@ enum ixgbe_phy_type { ixgbe_phy_sfp_ftl, ixgbe_phy_sfp_unknown, ixgbe_phy_sfp_intel, + ixgbe_phy_sfp_unsupported, ixgbe_phy_generic }; @@ -2005,7 +2240,8 @@ struct ixgbe_fc_info { u16 pause_time; /* Flow Control Pause timer */ bool send_xon; /* Flow control send XON */ bool strict_ieee; /* Strict IEEE mode */ - bool disable_fc_autoneg; /* Turn off autoneg FC mode */ + bool disable_fc_autoneg; /* Do not autonegotiate FC */ + bool fc_was_autonegged; /* Is current_mode the result of autonegging? */ enum ixgbe_fc_mode current_mode; /* FC mode in effect */ enum ixgbe_fc_mode requested_mode; /* FC mode requested by caller */ }; @@ -2075,6 +2311,12 @@ struct ixgbe_hw_stats { u64 fdirfstat_fremove; u64 fdirmatch; u64 fdirmiss; + u64 fccrc; + u64 fcoerpdc; + u64 fcoeprc; + u64 fcoeptc; + u64 fcoedwrc; + u64 fcoedwtc; }; /* forward declaration */ @@ -2101,6 +2343,8 @@ struct ixgbe_mac_operations { enum ixgbe_media_type (*get_media_type)(struct ixgbe_hw *); u32 (*get_supported_physical_layer)(struct ixgbe_hw *); s32 (*get_mac_addr)(struct ixgbe_hw *, u8 *); + s32 (*get_san_mac_addr)(struct ixgbe_hw *, u8 *); + s32 (*get_device_caps)(struct ixgbe_hw *, u16 *); s32 (*stop_adapter)(struct ixgbe_hw *); s32 (*get_bus_info)(struct ixgbe_hw *); void (*set_lan_id)(struct ixgbe_hw *); @@ -2129,8 +2373,7 @@ struct ixgbe_mac_operations { s32 (*set_vmdq)(struct ixgbe_hw *, u32, u32); s32 (*clear_vmdq)(struct ixgbe_hw *, u32, u32); s32 (*init_rx_addrs)(struct ixgbe_hw *); - s32 (*update_uc_addr_list)(struct ixgbe_hw *, u8 *, u32, - ixgbe_mc_addr_itr); + s32 (*update_uc_addr_list)(struct ixgbe_hw *, struct list_head *); s32 (*update_mc_addr_list)(struct ixgbe_hw *, u8 *, u32, ixgbe_mc_addr_itr); s32 (*enable_mc)(struct ixgbe_hw *); @@ -2140,12 +2383,13 @@ struct ixgbe_mac_operations { s32 (*init_uta_tables)(struct ixgbe_hw *); /* Flow Control */ - s32 (*setup_fc)(struct ixgbe_hw *, s32); + s32 (*fc_enable)(struct ixgbe_hw *, s32); }; struct ixgbe_phy_operations { s32 (*identify)(struct ixgbe_hw *); s32 (*identify_sfp)(struct ixgbe_hw *); + s32 (*init)(struct ixgbe_hw *); s32 (*reset)(struct ixgbe_hw *); s32 (*read_reg)(struct ixgbe_hw *, u32, u32, u16 *); s32 (*write_reg)(struct ixgbe_hw *, u32, u32, u16); @@ -2173,6 +2417,7 @@ struct ixgbe_mac_info { enum ixgbe_mac_type type; u8 addr[IXGBE_ETH_LENGTH_OF_ADDRESS]; u8 perm_addr[IXGBE_ETH_LENGTH_OF_ADDRESS]; + u8 san_addr[IXGBE_ETH_LENGTH_OF_ADDRESS]; s32 mc_filter_type; u32 mcft_size; u32 vft_size; @@ -2185,14 +2430,16 @@ struct ixgbe_mac_info { bool orig_link_settings_stored; bool autoneg; bool autoneg_succeeded; + bool autotry_restart; }; struct ixgbe_phy_info { struct ixgbe_phy_operations ops; + struct mdio_if_info mdio; enum ixgbe_phy_type type; - u32 addr; u32 id; enum ixgbe_sfp_type sfp_type; + bool sfp_setup_needed; u32 revision; enum ixgbe_media_type media_type; bool reset_disable; @@ -2249,6 +2496,8 @@ struct ixgbe_info { #define IXGBE_ERR_SFP_NOT_SUPPORTED -19 #define IXGBE_ERR_SFP_NOT_PRESENT -20 #define IXGBE_ERR_SFP_NO_INIT_SEQ_PRESENT -21 +#define IXGBE_ERR_FDIR_REINIT_FAILED -23 +#define IXGBE_ERR_EEPROM_VERSION -24 #define IXGBE_NOT_IMPLEMENTED 0x7FFFFFFF #endif /* _IXGBE_TYPE_H_ */ diff --git a/drivers/net/ixp2000/ixpdev.c b/drivers/net/ixp2000/ixpdev.c index d3bf2f017cc2..2a0174b62e96 100644 --- a/drivers/net/ixp2000/ixpdev.c +++ b/drivers/net/ixp2000/ixpdev.c @@ -270,6 +270,18 @@ static int ixpdev_close(struct net_device *dev) return 0; } +static const struct net_device_ops ixpdev_netdev_ops = { + .ndo_open = ixpdev_open, + .ndo_stop = ixpdev_close, + .ndo_start_xmit = ixpdev_xmit, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = ixpdev_poll_controller, +#endif +}; + struct net_device *ixpdev_alloc(int channel, int sizeof_priv) { struct net_device *dev; @@ -279,12 +291,7 @@ struct net_device *ixpdev_alloc(int channel, int sizeof_priv) if (dev == NULL) return NULL; - dev->hard_start_xmit = ixpdev_xmit; - dev->open = ixpdev_open; - dev->stop = ixpdev_close; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = ixpdev_poll_controller; -#endif + dev->netdev_ops = &ixpdev_netdev_ops; dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; diff --git a/drivers/net/jazzsonic.c b/drivers/net/jazzsonic.c index 14248cfc3dfd..d12106b47bf2 100644 --- a/drivers/net/jazzsonic.c +++ b/drivers/net/jazzsonic.c @@ -96,6 +96,18 @@ static int jazzsonic_close(struct net_device* dev) return err; } +static const struct net_device_ops sonic_netdev_ops = { + .ndo_open = jazzsonic_open, + .ndo_stop = jazzsonic_close, + .ndo_start_xmit = sonic_send_packet, + .ndo_get_stats = sonic_get_stats, + .ndo_set_multicast_list = sonic_multicast_list, + .ndo_tx_timeout = sonic_tx_timeout, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, +}; + static int __init sonic_probe1(struct net_device *dev) { static unsigned version_printed; @@ -179,12 +191,7 @@ static int __init sonic_probe1(struct net_device *dev) lp->rra_laddr = lp->rda_laddr + (SIZEOF_SONIC_RD * SONIC_NUM_RDS * SONIC_BUS_SCALE(lp->dma_bitmode)); - dev->open = jazzsonic_open; - dev->stop = jazzsonic_close; - dev->hard_start_xmit = sonic_send_packet; - dev->get_stats = sonic_get_stats; - dev->set_multicast_list = &sonic_multicast_list; - dev->tx_timeout = sonic_tx_timeout; + dev->netdev_ops = &sonic_netdev_ops; dev->watchdog_timeo = TX_TIMEOUT; /* diff --git a/drivers/net/jme.c b/drivers/net/jme.c index 621a7c0c46ba..1e3c63d67b91 100644 --- a/drivers/net/jme.c +++ b/drivers/net/jme.c @@ -1939,7 +1939,6 @@ jme_start_xmit(struct sk_buff *skb, struct net_device *netdev) TXCS_SELECT_QUEUE0 | TXCS_QUEUE0S | TXCS_ENABLE); - netdev->trans_start = jiffies; tx_dbg(jme, "xmit: %d+%d@%lu\n", idx, skb_shinfo(skb)->nr_frags + 2, diff --git a/drivers/net/korina.c b/drivers/net/korina.c index 38d6649a29c4..b4cf602c32b0 100644 --- a/drivers/net/korina.c +++ b/drivers/net/korina.c @@ -133,6 +133,7 @@ struct korina_private { int dma_halt_cnt; int dma_run_cnt; struct napi_struct napi; + struct timer_list media_check_timer; struct mii_if_info mii_if; struct net_device *dev; int phy_addr; @@ -664,6 +665,15 @@ static void korina_check_media(struct net_device *dev, unsigned int init_media) &lp->eth_regs->ethmac2); } +static void korina_poll_media(unsigned long data) +{ + struct net_device *dev = (struct net_device *) data; + struct korina_private *lp = netdev_priv(dev); + + korina_check_media(dev, 0); + mod_timer(&lp->media_check_timer, jiffies + HZ); +} + static void korina_set_carrier(struct mii_if_info *mii) { if (mii->force_media) { @@ -1034,6 +1044,7 @@ static int korina_open(struct net_device *dev) dev->name, lp->und_irq); goto err_free_ovr_irq; } + mod_timer(&lp->media_check_timer, jiffies + 1); out: return ret; @@ -1053,6 +1064,8 @@ static int korina_close(struct net_device *dev) struct korina_private *lp = netdev_priv(dev); u32 tmp; + del_timer(&lp->media_check_timer); + /* Disable interrupts */ disable_irq(lp->rx_irq); disable_irq(lp->tx_irq); @@ -1081,6 +1094,21 @@ static int korina_close(struct net_device *dev) return 0; } +static const struct net_device_ops korina_netdev_ops = { + .ndo_open = korina_open, + .ndo_stop = korina_close, + .ndo_start_xmit = korina_send_packet, + .ndo_set_multicast_list = korina_multicast_list, + .ndo_tx_timeout = korina_tx_timeout, + .ndo_do_ioctl = korina_ioctl, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = korina_poll_controller, +#endif +}; + static int korina_probe(struct platform_device *pdev) { struct korina_device *bif = platform_get_drvdata(pdev); @@ -1149,17 +1177,9 @@ static int korina_probe(struct platform_device *pdev) dev->irq = lp->rx_irq; lp->dev = dev; - dev->open = korina_open; - dev->stop = korina_close; - dev->hard_start_xmit = korina_send_packet; - dev->set_multicast_list = &korina_multicast_list; + dev->netdev_ops = &korina_netdev_ops; dev->ethtool_ops = &netdev_ethtool_ops; - dev->tx_timeout = korina_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; - dev->do_ioctl = &korina_ioctl; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = korina_poll_controller; -#endif netif_napi_add(dev, &lp->napi, korina_poll, 64); lp->phy_addr = (((lp->rx_irq == 0x2c? 1:0) << 8) | 0x05); @@ -1176,6 +1196,7 @@ static int korina_probe(struct platform_device *pdev) ": cannot register net device %d\n", rc); goto probe_err_register; } + setup_timer(&lp->media_check_timer, korina_poll_media, (unsigned long) dev); out: return rc; diff --git a/drivers/net/ks8842.c b/drivers/net/ks8842.c new file mode 100644 index 000000000000..39b0aea2aab3 --- /dev/null +++ b/drivers/net/ks8842.c @@ -0,0 +1,732 @@ +/* + * ks8842_main.c timberdale KS8842 ethernet driver + * Copyright (c) 2009 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* Supports: + * The Micrel KS8842 behind the timberdale FPGA + */ + +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "ks8842" + +/* Timberdale specific Registers */ +#define REG_TIMB_RST 0x1c + +/* KS8842 registers */ + +#define REG_SELECT_BANK 0x0e + +/* bank 0 registers */ +#define REG_QRFCR 0x04 + +/* bank 2 registers */ +#define REG_MARL 0x00 +#define REG_MARM 0x02 +#define REG_MARH 0x04 + +/* bank 3 registers */ +#define REG_GRR 0x06 + +/* bank 16 registers */ +#define REG_TXCR 0x00 +#define REG_TXSR 0x02 +#define REG_RXCR 0x04 +#define REG_TXMIR 0x08 +#define REG_RXMIR 0x0A + +/* bank 17 registers */ +#define REG_TXQCR 0x00 +#define REG_RXQCR 0x02 +#define REG_TXFDPR 0x04 +#define REG_RXFDPR 0x06 +#define REG_QMU_DATA_LO 0x08 +#define REG_QMU_DATA_HI 0x0A + +/* bank 18 registers */ +#define REG_IER 0x00 +#define IRQ_LINK_CHANGE 0x8000 +#define IRQ_TX 0x4000 +#define IRQ_RX 0x2000 +#define IRQ_RX_OVERRUN 0x0800 +#define IRQ_TX_STOPPED 0x0200 +#define IRQ_RX_STOPPED 0x0100 +#define IRQ_RX_ERROR 0x0080 +#define ENABLED_IRQS (IRQ_LINK_CHANGE | IRQ_TX | IRQ_RX | IRQ_RX_STOPPED | \ + IRQ_TX_STOPPED | IRQ_RX_OVERRUN | IRQ_RX_ERROR) +#define REG_ISR 0x02 +#define REG_RXSR 0x04 +#define RXSR_VALID 0x8000 +#define RXSR_BROADCAST 0x80 +#define RXSR_MULTICAST 0x40 +#define RXSR_UNICAST 0x20 +#define RXSR_FRAMETYPE 0x08 +#define RXSR_TOO_LONG 0x04 +#define RXSR_RUNT 0x02 +#define RXSR_CRC_ERROR 0x01 +#define RXSR_ERROR (RXSR_TOO_LONG | RXSR_RUNT | RXSR_CRC_ERROR) + +/* bank 32 registers */ +#define REG_SW_ID_AND_ENABLE 0x00 +#define REG_SGCR1 0x02 +#define REG_SGCR2 0x04 +#define REG_SGCR3 0x06 + +/* bank 39 registers */ +#define REG_MACAR1 0x00 +#define REG_MACAR2 0x02 +#define REG_MACAR3 0x04 + +/* bank 45 registers */ +#define REG_P1MBCR 0x00 +#define REG_P1MBSR 0x02 + +/* bank 46 registers */ +#define REG_P2MBCR 0x00 +#define REG_P2MBSR 0x02 + +/* bank 48 registers */ +#define REG_P1CR2 0x02 + +/* bank 49 registers */ +#define REG_P1CR4 0x02 +#define REG_P1SR 0x04 + +struct ks8842_adapter { + void __iomem *hw_addr; + int irq; + struct tasklet_struct tasklet; + spinlock_t lock; /* spinlock to be interrupt safe */ + struct platform_device *pdev; +}; + +static inline void ks8842_select_bank(struct ks8842_adapter *adapter, u16 bank) +{ + iowrite16(bank, adapter->hw_addr + REG_SELECT_BANK); +} + +static inline void ks8842_write8(struct ks8842_adapter *adapter, u16 bank, + u8 value, int offset) +{ + ks8842_select_bank(adapter, bank); + iowrite8(value, adapter->hw_addr + offset); +} + +static inline void ks8842_write16(struct ks8842_adapter *adapter, u16 bank, + u16 value, int offset) +{ + ks8842_select_bank(adapter, bank); + iowrite16(value, adapter->hw_addr + offset); +} + +static inline void ks8842_enable_bits(struct ks8842_adapter *adapter, u16 bank, + u16 bits, int offset) +{ + u16 reg; + ks8842_select_bank(adapter, bank); + reg = ioread16(adapter->hw_addr + offset); + reg |= bits; + iowrite16(reg, adapter->hw_addr + offset); +} + +static inline void ks8842_clear_bits(struct ks8842_adapter *adapter, u16 bank, + u16 bits, int offset) +{ + u16 reg; + ks8842_select_bank(adapter, bank); + reg = ioread16(adapter->hw_addr + offset); + reg &= ~bits; + iowrite16(reg, adapter->hw_addr + offset); +} + +static inline void ks8842_write32(struct ks8842_adapter *adapter, u16 bank, + u32 value, int offset) +{ + ks8842_select_bank(adapter, bank); + iowrite32(value, adapter->hw_addr + offset); +} + +static inline u8 ks8842_read8(struct ks8842_adapter *adapter, u16 bank, + int offset) +{ + ks8842_select_bank(adapter, bank); + return ioread8(adapter->hw_addr + offset); +} + +static inline u16 ks8842_read16(struct ks8842_adapter *adapter, u16 bank, + int offset) +{ + ks8842_select_bank(adapter, bank); + return ioread16(adapter->hw_addr + offset); +} + +static inline u32 ks8842_read32(struct ks8842_adapter *adapter, u16 bank, + int offset) +{ + ks8842_select_bank(adapter, bank); + return ioread32(adapter->hw_addr + offset); +} + +static void ks8842_reset(struct ks8842_adapter *adapter) +{ + /* The KS8842 goes haywire when doing softare reset + * a work around in the timberdale IP is implemented to + * do a hardware reset instead + ks8842_write16(adapter, 3, 1, REG_GRR); + msleep(10); + iowrite16(0, adapter->hw_addr + REG_GRR); + */ + iowrite16(32, adapter->hw_addr + REG_SELECT_BANK); + iowrite32(0x1, adapter->hw_addr + REG_TIMB_RST); + msleep(20); +} + +static void ks8842_update_link_status(struct net_device *netdev, + struct ks8842_adapter *adapter) +{ + /* check the status of the link */ + if (ks8842_read16(adapter, 45, REG_P1MBSR) & 0x4) { + netif_carrier_on(netdev); + netif_wake_queue(netdev); + } else { + netif_stop_queue(netdev); + netif_carrier_off(netdev); + } +} + +static void ks8842_enable_tx(struct ks8842_adapter *adapter) +{ + ks8842_enable_bits(adapter, 16, 0x01, REG_TXCR); +} + +static void ks8842_disable_tx(struct ks8842_adapter *adapter) +{ + ks8842_clear_bits(adapter, 16, 0x01, REG_TXCR); +} + +static void ks8842_enable_rx(struct ks8842_adapter *adapter) +{ + ks8842_enable_bits(adapter, 16, 0x01, REG_RXCR); +} + +static void ks8842_disable_rx(struct ks8842_adapter *adapter) +{ + ks8842_clear_bits(adapter, 16, 0x01, REG_RXCR); +} + +static void ks8842_reset_hw(struct ks8842_adapter *adapter) +{ + /* reset the HW */ + ks8842_reset(adapter); + + /* Enable QMU Transmit flow control / transmit padding / Transmit CRC */ + ks8842_write16(adapter, 16, 0x000E, REG_TXCR); + + /* enable the receiver, uni + multi + broadcast + flow ctrl + + crc strip */ + ks8842_write16(adapter, 16, 0x8 | 0x20 | 0x40 | 0x80 | 0x400, + REG_RXCR); + + /* TX frame pointer autoincrement */ + ks8842_write16(adapter, 17, 0x4000, REG_TXFDPR); + + /* RX frame pointer autoincrement */ + ks8842_write16(adapter, 17, 0x4000, REG_RXFDPR); + + /* RX 2 kb high watermark */ + ks8842_write16(adapter, 0, 0x1000, REG_QRFCR); + + /* aggresive back off in half duplex */ + ks8842_enable_bits(adapter, 32, 1 << 8, REG_SGCR1); + + /* enable no excessive collison drop */ + ks8842_enable_bits(adapter, 32, 1 << 3, REG_SGCR2); + + /* Enable port 1 force flow control / back pressure / transmit / recv */ + ks8842_write16(adapter, 48, 0x1E07, REG_P1CR2); + + /* restart port auto-negotiation */ + ks8842_enable_bits(adapter, 49, 1 << 13, REG_P1CR4); + /* only advertise 10Mbps */ + ks8842_clear_bits(adapter, 49, 3 << 2, REG_P1CR4); + + /* Enable the transmitter */ + ks8842_enable_tx(adapter); + + /* Enable the receiver */ + ks8842_enable_rx(adapter); + + /* clear all interrupts */ + ks8842_write16(adapter, 18, 0xffff, REG_ISR); + + /* enable interrupts */ + ks8842_write16(adapter, 18, ENABLED_IRQS, REG_IER); + + /* enable the switch */ + ks8842_write16(adapter, 32, 0x1, REG_SW_ID_AND_ENABLE); +} + +static void ks8842_read_mac_addr(struct ks8842_adapter *adapter, u8 *dest) +{ + int i; + u16 mac; + + for (i = 0; i < ETH_ALEN; i++) + dest[ETH_ALEN - i - 1] = ks8842_read8(adapter, 2, REG_MARL + i); + + /* make sure the switch port uses the same MAC as the QMU */ + mac = ks8842_read16(adapter, 2, REG_MARL); + ks8842_write16(adapter, 39, mac, REG_MACAR1); + mac = ks8842_read16(adapter, 2, REG_MARM); + ks8842_write16(adapter, 39, mac, REG_MACAR2); + mac = ks8842_read16(adapter, 2, REG_MARH); + ks8842_write16(adapter, 39, mac, REG_MACAR3); +} + +static inline u16 ks8842_tx_fifo_space(struct ks8842_adapter *adapter) +{ + return ks8842_read16(adapter, 16, REG_TXMIR) & 0x1fff; +} + +static int ks8842_tx_frame(struct sk_buff *skb, struct net_device *netdev) +{ + struct ks8842_adapter *adapter = netdev_priv(netdev); + int len = skb->len; + u32 *ptr = (u32 *)skb->data; + u32 ctrl; + + dev_dbg(&adapter->pdev->dev, + "%s: len %u head %p data %p tail %p end %p\n", + __func__, skb->len, skb->head, skb->data, + skb_tail_pointer(skb), skb_end_pointer(skb)); + + /* check FIFO buffer space, we need space for CRC and command bits */ + if (ks8842_tx_fifo_space(adapter) < len + 8) + return NETDEV_TX_BUSY; + + /* the control word, enable IRQ, port 1 and the length */ + ctrl = 0x8000 | 0x100 | (len << 16); + ks8842_write32(adapter, 17, ctrl, REG_QMU_DATA_LO); + + netdev->stats.tx_bytes += len; + + /* copy buffer */ + while (len > 0) { + iowrite32(*ptr, adapter->hw_addr + REG_QMU_DATA_LO); + len -= sizeof(u32); + ptr++; + } + + /* enqueue packet */ + ks8842_write16(adapter, 17, 1, REG_TXQCR); + + dev_kfree_skb(skb); + + return NETDEV_TX_OK; +} + +static void ks8842_rx_frame(struct net_device *netdev, + struct ks8842_adapter *adapter) +{ + u32 status = ks8842_read32(adapter, 17, REG_QMU_DATA_LO); + int len = (status >> 16) & 0x7ff; + + status &= 0xffff; + + dev_dbg(&adapter->pdev->dev, "%s - rx_data: status: %x\n", + __func__, status); + + /* check the status */ + if ((status & RXSR_VALID) && !(status & RXSR_ERROR)) { + struct sk_buff *skb = netdev_alloc_skb(netdev, len + 2); + + dev_dbg(&adapter->pdev->dev, "%s, got package, len: %d\n", + __func__, len); + if (skb) { + u32 *data; + + netdev->stats.rx_packets++; + netdev->stats.rx_bytes += len; + if (status & RXSR_MULTICAST) + netdev->stats.multicast++; + + /* Align socket buffer in 4-byte boundary for + better performance. */ + skb_reserve(skb, 2); + data = (u32 *)skb_put(skb, len); + + ks8842_select_bank(adapter, 17); + while (len > 0) { + *data++ = ioread32(adapter->hw_addr + + REG_QMU_DATA_LO); + len -= sizeof(u32); + } + + skb->protocol = eth_type_trans(skb, netdev); + netif_rx(skb); + } else + netdev->stats.rx_dropped++; + } else { + dev_dbg(&adapter->pdev->dev, "RX error, status: %x\n", status); + netdev->stats.rx_errors++; + if (status & RXSR_TOO_LONG) + netdev->stats.rx_length_errors++; + if (status & RXSR_CRC_ERROR) + netdev->stats.rx_crc_errors++; + if (status & RXSR_RUNT) + netdev->stats.rx_frame_errors++; + } + + /* set high watermark to 3K */ + ks8842_clear_bits(adapter, 0, 1 << 12, REG_QRFCR); + + /* release the frame */ + ks8842_write16(adapter, 17, 0x01, REG_RXQCR); + + /* set high watermark to 2K */ + ks8842_enable_bits(adapter, 0, 1 << 12, REG_QRFCR); +} + +void ks8842_handle_rx(struct net_device *netdev, struct ks8842_adapter *adapter) +{ + u16 rx_data = ks8842_read16(adapter, 16, REG_RXMIR) & 0x1fff; + dev_dbg(&adapter->pdev->dev, "%s Entry - rx_data: %d\n", + __func__, rx_data); + while (rx_data) { + ks8842_rx_frame(netdev, adapter); + rx_data = ks8842_read16(adapter, 16, REG_RXMIR) & 0x1fff; + } +} + +void ks8842_handle_tx(struct net_device *netdev, struct ks8842_adapter *adapter) +{ + u16 sr = ks8842_read16(adapter, 16, REG_TXSR); + dev_dbg(&adapter->pdev->dev, "%s - entry, sr: %x\n", __func__, sr); + netdev->stats.tx_packets++; + if (netif_queue_stopped(netdev)) + netif_wake_queue(netdev); +} + +void ks8842_handle_rx_overrun(struct net_device *netdev, + struct ks8842_adapter *adapter) +{ + dev_dbg(&adapter->pdev->dev, "%s: entry\n", __func__); + netdev->stats.rx_errors++; + netdev->stats.rx_fifo_errors++; +} + +void ks8842_tasklet(unsigned long arg) +{ + struct net_device *netdev = (struct net_device *)arg; + struct ks8842_adapter *adapter = netdev_priv(netdev); + u16 isr; + unsigned long flags; + u16 entry_bank; + + /* read current bank to be able to set it back */ + spin_lock_irqsave(&adapter->lock, flags); + entry_bank = ioread16(adapter->hw_addr + REG_SELECT_BANK); + spin_unlock_irqrestore(&adapter->lock, flags); + + isr = ks8842_read16(adapter, 18, REG_ISR); + dev_dbg(&adapter->pdev->dev, "%s - ISR: 0x%x\n", __func__, isr); + + /* Ack */ + ks8842_write16(adapter, 18, isr, REG_ISR); + + if (!netif_running(netdev)) + return; + + if (isr & IRQ_LINK_CHANGE) + ks8842_update_link_status(netdev, adapter); + + if (isr & (IRQ_RX | IRQ_RX_ERROR)) + ks8842_handle_rx(netdev, adapter); + + if (isr & IRQ_TX) + ks8842_handle_tx(netdev, adapter); + + if (isr & IRQ_RX_OVERRUN) + ks8842_handle_rx_overrun(netdev, adapter); + + if (isr & IRQ_TX_STOPPED) { + ks8842_disable_tx(adapter); + ks8842_enable_tx(adapter); + } + + if (isr & IRQ_RX_STOPPED) { + ks8842_disable_rx(adapter); + ks8842_enable_rx(adapter); + } + + /* re-enable interrupts, put back the bank selection register */ + spin_lock_irqsave(&adapter->lock, flags); + ks8842_write16(adapter, 18, ENABLED_IRQS, REG_IER); + iowrite16(entry_bank, adapter->hw_addr + REG_SELECT_BANK); + spin_unlock_irqrestore(&adapter->lock, flags); +} + +static irqreturn_t ks8842_irq(int irq, void *devid) +{ + struct ks8842_adapter *adapter = devid; + u16 isr; + u16 entry_bank = ioread16(adapter->hw_addr + REG_SELECT_BANK); + irqreturn_t ret = IRQ_NONE; + + isr = ks8842_read16(adapter, 18, REG_ISR); + dev_dbg(&adapter->pdev->dev, "%s - ISR: 0x%x\n", __func__, isr); + + if (isr) { + /* disable IRQ */ + ks8842_write16(adapter, 18, 0x00, REG_IER); + + /* schedule tasklet */ + tasklet_schedule(&adapter->tasklet); + + ret = IRQ_HANDLED; + } + + iowrite16(entry_bank, adapter->hw_addr + REG_SELECT_BANK); + + return ret; +} + + +/* Netdevice operations */ + +static int ks8842_open(struct net_device *netdev) +{ + struct ks8842_adapter *adapter = netdev_priv(netdev); + int err; + + dev_dbg(&adapter->pdev->dev, "%s - entry\n", __func__); + + /* reset the HW */ + ks8842_reset_hw(adapter); + + ks8842_update_link_status(netdev, adapter); + + err = request_irq(adapter->irq, ks8842_irq, IRQF_SHARED, DRV_NAME, + adapter); + if (err) { + printk(KERN_ERR "Failed to request IRQ: %d: %d\n", + adapter->irq, err); + return err; + } + + return 0; +} + +static int ks8842_close(struct net_device *netdev) +{ + struct ks8842_adapter *adapter = netdev_priv(netdev); + + dev_dbg(&adapter->pdev->dev, "%s - entry\n", __func__); + + /* free the irq */ + free_irq(adapter->irq, adapter); + + /* disable the switch */ + ks8842_write16(adapter, 32, 0x0, REG_SW_ID_AND_ENABLE); + + return 0; +} + +static int ks8842_xmit_frame(struct sk_buff *skb, struct net_device *netdev) +{ + int ret; + struct ks8842_adapter *adapter = netdev_priv(netdev); + + dev_dbg(&adapter->pdev->dev, "%s: entry\n", __func__); + + ret = ks8842_tx_frame(skb, netdev); + + if (ks8842_tx_fifo_space(adapter) < netdev->mtu + 8) + netif_stop_queue(netdev); + + return ret; +} + +static int ks8842_set_mac(struct net_device *netdev, void *p) +{ + struct ks8842_adapter *adapter = netdev_priv(netdev); + unsigned long flags; + struct sockaddr *addr = p; + char *mac = (u8 *)addr->sa_data; + int i; + + dev_dbg(&adapter->pdev->dev, "%s: entry\n", __func__); + + if (!is_valid_ether_addr(addr->sa_data)) + return -EADDRNOTAVAIL; + + memcpy(netdev->dev_addr, mac, netdev->addr_len); + + spin_lock_irqsave(&adapter->lock, flags); + for (i = 0; i < ETH_ALEN; i++) { + ks8842_write8(adapter, 2, mac[ETH_ALEN - i - 1], REG_MARL + i); + ks8842_write8(adapter, 39, mac[ETH_ALEN - i - 1], + REG_MACAR1 + i); + } + spin_unlock_irqrestore(&adapter->lock, flags); + return 0; +} + +static void ks8842_tx_timeout(struct net_device *netdev) +{ + struct ks8842_adapter *adapter = netdev_priv(netdev); + unsigned long flags; + + dev_dbg(&adapter->pdev->dev, "%s: entry\n", __func__); + + spin_lock_irqsave(&adapter->lock, flags); + /* disable interrupts */ + ks8842_write16(adapter, 18, 0, REG_IER); + ks8842_write16(adapter, 18, 0xFFFF, REG_ISR); + spin_unlock_irqrestore(&adapter->lock, flags); + + ks8842_reset_hw(adapter); + + ks8842_update_link_status(netdev, adapter); +} + +static const struct net_device_ops ks8842_netdev_ops = { + .ndo_open = ks8842_open, + .ndo_stop = ks8842_close, + .ndo_start_xmit = ks8842_xmit_frame, + .ndo_set_mac_address = ks8842_set_mac, + .ndo_tx_timeout = ks8842_tx_timeout, + .ndo_validate_addr = eth_validate_addr +}; + +static struct ethtool_ops ks8842_ethtool_ops = { + .get_link = ethtool_op_get_link, +}; + +static int __devinit ks8842_probe(struct platform_device *pdev) +{ + int err = -ENOMEM; + struct resource *iomem; + struct net_device *netdev; + struct ks8842_adapter *adapter; + u16 id; + + iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!request_mem_region(iomem->start, resource_size(iomem), DRV_NAME)) + goto err_mem_region; + + netdev = alloc_etherdev(sizeof(struct ks8842_adapter)); + if (!netdev) + goto err_alloc_etherdev; + + SET_NETDEV_DEV(netdev, &pdev->dev); + + adapter = netdev_priv(netdev); + adapter->hw_addr = ioremap(iomem->start, resource_size(iomem)); + if (!adapter->hw_addr) + goto err_ioremap; + + adapter->irq = platform_get_irq(pdev, 0); + if (adapter->irq < 0) { + err = adapter->irq; + goto err_get_irq; + } + + adapter->pdev = pdev; + + tasklet_init(&adapter->tasklet, ks8842_tasklet, (unsigned long)netdev); + spin_lock_init(&adapter->lock); + + netdev->netdev_ops = &ks8842_netdev_ops; + netdev->ethtool_ops = &ks8842_ethtool_ops; + + ks8842_read_mac_addr(adapter, netdev->dev_addr); + + id = ks8842_read16(adapter, 32, REG_SW_ID_AND_ENABLE); + + strcpy(netdev->name, "eth%d"); + err = register_netdev(netdev); + if (err) + goto err_register; + + platform_set_drvdata(pdev, netdev); + + printk(KERN_INFO DRV_NAME + " Found chip, family: 0x%x, id: 0x%x, rev: 0x%x\n", + (id >> 8) & 0xff, (id >> 4) & 0xf, (id >> 1) & 0x7); + + return 0; + +err_register: +err_get_irq: + iounmap(adapter->hw_addr); +err_ioremap: + free_netdev(netdev); +err_alloc_etherdev: + release_mem_region(iomem->start, resource_size(iomem)); +err_mem_region: + return err; +} + +static int __devexit ks8842_remove(struct platform_device *pdev) +{ + struct net_device *netdev = platform_get_drvdata(pdev); + struct ks8842_adapter *adapter = netdev_priv(netdev); + struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + unregister_netdev(netdev); + tasklet_kill(&adapter->tasklet); + iounmap(adapter->hw_addr); + free_netdev(netdev); + release_mem_region(iomem->start, resource_size(iomem)); + platform_set_drvdata(pdev, NULL); + return 0; +} + + +static struct platform_driver ks8842_platform_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, + .probe = ks8842_probe, + .remove = ks8842_remove, +}; + +static int __init ks8842_init(void) +{ + return platform_driver_register(&ks8842_platform_driver); +} + +static void __exit ks8842_exit(void) +{ + platform_driver_unregister(&ks8842_platform_driver); +} + +module_init(ks8842_init); +module_exit(ks8842_exit); + +MODULE_DESCRIPTION("Timberdale KS8842 ethernet driver"); +MODULE_AUTHOR("Mocean Laboratories "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:ks8842"); + diff --git a/drivers/net/lasi_82596.c b/drivers/net/lasi_82596.c index efbae4b8398e..a0c578585a50 100644 --- a/drivers/net/lasi_82596.c +++ b/drivers/net/lasi_82596.c @@ -161,12 +161,12 @@ lan_init_chip(struct parisc_device *dev) if (!dev->irq) { printk(KERN_ERR "%s: IRQ not found for i82596 at 0x%lx\n", - __FILE__, dev->hpa.start); + __FILE__, (unsigned long)dev->hpa.start); return -ENODEV; } - printk(KERN_INFO "Found i82596 at 0x%lx, IRQ %d\n", dev->hpa.start, - dev->irq); + printk(KERN_INFO "Found i82596 at 0x%lx, IRQ %d\n", + (unsigned long)dev->hpa.start, dev->irq); netdevice = alloc_etherdev(sizeof(struct i596_private)); if (!netdevice) diff --git a/drivers/net/lib82596.c b/drivers/net/lib82596.c index 7415f517491d..070fa4500871 100644 --- a/drivers/net/lib82596.c +++ b/drivers/net/lib82596.c @@ -1036,6 +1036,19 @@ static void print_eth(unsigned char *add, char *str) printk(KERN_DEBUG "i596 0x%p, %pM --> %pM %02X%02X, %s\n", add, add + 6, add, add[12], add[13], str); } +static const struct net_device_ops i596_netdev_ops = { + .ndo_open = i596_open, + .ndo_stop = i596_close, + .ndo_start_xmit = i596_start_xmit, + .ndo_set_multicast_list = set_multicast_list, + .ndo_tx_timeout = i596_tx_timeout, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = i596_poll_controller, +#endif +}; static int __devinit i82596_probe(struct net_device *dev) { @@ -1062,16 +1075,8 @@ static int __devinit i82596_probe(struct net_device *dev) return -ENOMEM; } - /* The 82596-specific entries in the device structure. */ - dev->open = i596_open; - dev->stop = i596_close; - dev->hard_start_xmit = i596_start_xmit; - dev->set_multicast_list = set_multicast_list; - dev->tx_timeout = i596_tx_timeout; + dev->netdev_ops = &i596_netdev_ops; dev->watchdog_timeo = TX_TIMEOUT; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = i596_poll_controller; -#endif memset(dma, 0, sizeof(struct i596_dma)); lp->dma = dma; diff --git a/drivers/net/lib8390.c b/drivers/net/lib8390.c index 789b6cb744b2..f28c23343009 100644 --- a/drivers/net/lib8390.c +++ b/drivers/net/lib8390.c @@ -370,7 +370,7 @@ static int __ei_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock(&ei_local->page_lock); enable_irq_lockdep_irqrestore(dev->irq, &flags); dev->stats.tx_errors++; - return 1; + return NETDEV_TX_BUSY; } /* diff --git a/drivers/net/ll_temac.h b/drivers/net/ll_temac.h new file mode 100644 index 000000000000..1af66a1e6911 --- /dev/null +++ b/drivers/net/ll_temac.h @@ -0,0 +1,374 @@ + +#ifndef XILINX_LL_TEMAC_H +#define XILINX_LL_TEMAC_H + +#include +#include +#include +#include +#include + +/* packet size info */ +#define XTE_HDR_SIZE 14 /* size of Ethernet header */ +#define XTE_TRL_SIZE 4 /* size of Ethernet trailer (FCS) */ +#define XTE_JUMBO_MTU 9000 +#define XTE_MAX_JUMBO_FRAME_SIZE (XTE_JUMBO_MTU + XTE_HDR_SIZE + XTE_TRL_SIZE) + +/* Configuration options */ + +/* Accept all incoming packets. + * This option defaults to disabled (cleared) */ +#define XTE_OPTION_PROMISC (1 << 0) +/* Jumbo frame support for Tx & Rx. + * This option defaults to disabled (cleared) */ +#define XTE_OPTION_JUMBO (1 << 1) +/* VLAN Rx & Tx frame support. + * This option defaults to disabled (cleared) */ +#define XTE_OPTION_VLAN (1 << 2) +/* Enable recognition of flow control frames on Rx + * This option defaults to enabled (set) */ +#define XTE_OPTION_FLOW_CONTROL (1 << 4) +/* Strip FCS and PAD from incoming frames. + * Note: PAD from VLAN frames is not stripped. + * This option defaults to disabled (set) */ +#define XTE_OPTION_FCS_STRIP (1 << 5) +/* Generate FCS field and add PAD automatically for outgoing frames. + * This option defaults to enabled (set) */ +#define XTE_OPTION_FCS_INSERT (1 << 6) +/* Enable Length/Type error checking for incoming frames. When this option is +set, the MAC will filter frames that have a mismatched type/length field +and if XTE_OPTION_REPORT_RXERR is set, the user is notified when these +types of frames are encountered. When this option is cleared, the MAC will +allow these types of frames to be received. +This option defaults to enabled (set) */ +#define XTE_OPTION_LENTYPE_ERR (1 << 7) +/* Enable the transmitter. + * This option defaults to enabled (set) */ +#define XTE_OPTION_TXEN (1 << 11) +/* Enable the receiver +* This option defaults to enabled (set) */ +#define XTE_OPTION_RXEN (1 << 12) + +/* Default options set when device is initialized or reset */ +#define XTE_OPTION_DEFAULTS \ + (XTE_OPTION_TXEN | \ + XTE_OPTION_FLOW_CONTROL | \ + XTE_OPTION_RXEN) + +/* XPS_LL_TEMAC SDMA registers definition */ + +#define TX_NXTDESC_PTR 0x00 /* r */ +#define TX_CURBUF_ADDR 0x01 /* r */ +#define TX_CURBUF_LENGTH 0x02 /* r */ +#define TX_CURDESC_PTR 0x03 /* rw */ +#define TX_TAILDESC_PTR 0x04 /* rw */ +#define TX_CHNL_CTRL 0x05 /* rw */ +/* + 0:7 24:31 IRQTimeout + 8:15 16:23 IRQCount + 16:20 11:15 Reserved + 21 10 0 + 22 9 UseIntOnEnd + 23 8 LdIRQCnt + 24 7 IRQEn + 25:28 3:6 Reserved + 29 2 IrqErrEn + 30 1 IrqDlyEn + 31 0 IrqCoalEn +*/ +#define CHNL_CTRL_IRQ_IOE (1 << 9) +#define CHNL_CTRL_IRQ_EN (1 << 7) +#define CHNL_CTRL_IRQ_ERR_EN (1 << 2) +#define CHNL_CTRL_IRQ_DLY_EN (1 << 1) +#define CHNL_CTRL_IRQ_COAL_EN (1 << 0) +#define TX_IRQ_REG 0x06 /* rw */ +/* + 0:7 24:31 DltTmrValue + 8:15 16:23 ClscCntrValue + 16:17 14:15 Reserved + 18:21 10:13 ClscCnt + 22:23 8:9 DlyCnt + 24:28 3::7 Reserved + 29 2 ErrIrq + 30 1 DlyIrq + 31 0 CoalIrq + */ +#define TX_CHNL_STS 0x07 /* r */ +/* + 0:9 22:31 Reserved + 10 21 TailPErr + 11 20 CmpErr + 12 19 AddrErr + 13 18 NxtPErr + 14 17 CurPErr + 15 16 BsyWr + 16:23 8:15 Reserved + 24 7 Error + 25 6 IOE + 26 5 SOE + 27 4 Cmplt + 28 3 SOP + 29 2 EOP + 30 1 EngBusy + 31 0 Reserved +*/ + +#define RX_NXTDESC_PTR 0x08 /* r */ +#define RX_CURBUF_ADDR 0x09 /* r */ +#define RX_CURBUF_LENGTH 0x0a /* r */ +#define RX_CURDESC_PTR 0x0b /* rw */ +#define RX_TAILDESC_PTR 0x0c /* rw */ +#define RX_CHNL_CTRL 0x0d /* rw */ +/* + 0:7 24:31 IRQTimeout + 8:15 16:23 IRQCount + 16:20 11:15 Reserved + 21 10 0 + 22 9 UseIntOnEnd + 23 8 LdIRQCnt + 24 7 IRQEn + 25:28 3:6 Reserved + 29 2 IrqErrEn + 30 1 IrqDlyEn + 31 0 IrqCoalEn + */ +#define RX_IRQ_REG 0x0e /* rw */ +#define IRQ_COAL (1 << 0) +#define IRQ_DLY (1 << 1) +#define IRQ_ERR (1 << 2) +#define IRQ_DMAERR (1 << 7) /* this is not documented ??? */ +/* + 0:7 24:31 DltTmrValue + 8:15 16:23 ClscCntrValue + 16:17 14:15 Reserved + 18:21 10:13 ClscCnt + 22:23 8:9 DlyCnt + 24:28 3::7 Reserved +*/ +#define RX_CHNL_STS 0x0f /* r */ +#define CHNL_STS_ENGBUSY (1 << 1) +#define CHNL_STS_EOP (1 << 2) +#define CHNL_STS_SOP (1 << 3) +#define CHNL_STS_CMPLT (1 << 4) +#define CHNL_STS_SOE (1 << 5) +#define CHNL_STS_IOE (1 << 6) +#define CHNL_STS_ERR (1 << 7) + +#define CHNL_STS_BSYWR (1 << 16) +#define CHNL_STS_CURPERR (1 << 17) +#define CHNL_STS_NXTPERR (1 << 18) +#define CHNL_STS_ADDRERR (1 << 19) +#define CHNL_STS_CMPERR (1 << 20) +#define CHNL_STS_TAILERR (1 << 21) +/* + 0:9 22:31 Reserved + 10 21 TailPErr + 11 20 CmpErr + 12 19 AddrErr + 13 18 NxtPErr + 14 17 CurPErr + 15 16 BsyWr + 16:23 8:15 Reserved + 24 7 Error + 25 6 IOE + 26 5 SOE + 27 4 Cmplt + 28 3 SOP + 29 2 EOP + 30 1 EngBusy + 31 0 Reserved +*/ + +#define DMA_CONTROL_REG 0x10 /* rw */ +#define DMA_CONTROL_RST (1 << 0) +#define DMA_TAIL_ENABLE (1 << 2) + +/* XPS_LL_TEMAC direct registers definition */ + +#define XTE_RAF0_OFFSET 0x00 +#define RAF0_RST (1 << 0) +#define RAF0_MCSTREJ (1 << 1) +#define RAF0_BCSTREJ (1 << 2) +#define XTE_TPF0_OFFSET 0x04 +#define XTE_IFGP0_OFFSET 0x08 +#define XTE_ISR0_OFFSET 0x0c +#define ISR0_HARDACSCMPLT (1 << 0) +#define ISR0_AUTONEG (1 << 1) +#define ISR0_RXCMPLT (1 << 2) +#define ISR0_RXREJ (1 << 3) +#define ISR0_RXFIFOOVR (1 << 4) +#define ISR0_TXCMPLT (1 << 5) +#define ISR0_RXDCMLCK (1 << 6) + +#define XTE_IPR0_OFFSET 0x10 +#define XTE_IER0_OFFSET 0x14 + +#define XTE_MSW0_OFFSET 0x20 +#define XTE_LSW0_OFFSET 0x24 +#define XTE_CTL0_OFFSET 0x28 +#define XTE_RDY0_OFFSET 0x2c + +#define XTE_RSE_MIIM_RR_MASK 0x0002 +#define XTE_RSE_MIIM_WR_MASK 0x0004 +#define XTE_RSE_CFG_RR_MASK 0x0020 +#define XTE_RSE_CFG_WR_MASK 0x0040 +#define XTE_RDY0_HARD_ACS_RDY_MASK (0x10000) + +/* XPS_LL_TEMAC indirect registers offset definition */ + +#define XTE_RXC0_OFFSET 0x00000200 /* Rx configuration word 0 */ +#define XTE_RXC1_OFFSET 0x00000240 /* Rx configuration word 1 */ +#define XTE_RXC1_RXRST_MASK (1 << 31) /* Receiver reset */ +#define XTE_RXC1_RXJMBO_MASK (1 << 30) /* Jumbo frame enable */ +#define XTE_RXC1_RXFCS_MASK (1 << 29) /* FCS not stripped */ +#define XTE_RXC1_RXEN_MASK (1 << 28) /* Receiver enable */ +#define XTE_RXC1_RXVLAN_MASK (1 << 27) /* VLAN enable */ +#define XTE_RXC1_RXHD_MASK (1 << 26) /* Half duplex */ +#define XTE_RXC1_RXLT_MASK (1 << 25) /* Length/type check disable */ + +#define XTE_TXC_OFFSET 0x00000280 /* Tx configuration */ +#define XTE_TXC_TXRST_MASK (1 << 31) /* Transmitter reset */ +#define XTE_TXC_TXJMBO_MASK (1 << 30) /* Jumbo frame enable */ +#define XTE_TXC_TXFCS_MASK (1 << 29) /* Generate FCS */ +#define XTE_TXC_TXEN_MASK (1 << 28) /* Transmitter enable */ +#define XTE_TXC_TXVLAN_MASK (1 << 27) /* VLAN enable */ +#define XTE_TXC_TXHD_MASK (1 << 26) /* Half duplex */ + +#define XTE_FCC_OFFSET 0x000002C0 /* Flow control config */ +#define XTE_FCC_RXFLO_MASK (1 << 29) /* Rx flow control enable */ +#define XTE_FCC_TXFLO_MASK (1 << 30) /* Tx flow control enable */ + +#define XTE_EMCFG_OFFSET 0x00000300 /* EMAC configuration */ +#define XTE_EMCFG_LINKSPD_MASK 0xC0000000 /* Link speed */ +#define XTE_EMCFG_HOSTEN_MASK (1 << 26) /* Host interface enable */ +#define XTE_EMCFG_LINKSPD_10 0x00000000 /* 10 Mbit LINKSPD_MASK */ +#define XTE_EMCFG_LINKSPD_100 (1 << 30) /* 100 Mbit LINKSPD_MASK */ +#define XTE_EMCFG_LINKSPD_1000 (1 << 31) /* 1000 Mbit LINKSPD_MASK */ + +#define XTE_GMIC_OFFSET 0x00000320 /* RGMII/SGMII config */ +#define XTE_MC_OFFSET 0x00000340 /* MDIO configuration */ +#define XTE_UAW0_OFFSET 0x00000380 /* Unicast address word 0 */ +#define XTE_UAW1_OFFSET 0x00000384 /* Unicast address word 1 */ + +#define XTE_MAW0_OFFSET 0x00000388 /* Multicast addr word 0 */ +#define XTE_MAW1_OFFSET 0x0000038C /* Multicast addr word 1 */ +#define XTE_AFM_OFFSET 0x00000390 /* Promiscuous mode */ +#define XTE_AFM_EPPRM_MASK (1 << 31) /* Promiscuous mode enable */ + +/* Interrupt Request status */ +#define XTE_TIS_OFFSET 0x000003A0 +#define TIS_FRIS (1 << 0) +#define TIS_MRIS (1 << 1) +#define TIS_MWIS (1 << 2) +#define TIS_ARIS (1 << 3) +#define TIS_AWIS (1 << 4) +#define TIS_CRIS (1 << 5) +#define TIS_CWIS (1 << 6) + +#define XTE_TIE_OFFSET 0x000003A4 /* Interrupt enable */ + +/** MII Mamagement Control register (MGTCR) */ +#define XTE_MGTDR_OFFSET 0x000003B0 /* MII data */ +#define XTE_MIIMAI_OFFSET 0x000003B4 /* MII control */ + +#define CNTLREG_WRITE_ENABLE_MASK 0x8000 +#define CNTLREG_EMAC1SEL_MASK 0x0400 +#define CNTLREG_ADDRESSCODE_MASK 0x03ff + +/* CDMAC descriptor status bit definitions */ + +#define STS_CTRL_APP0_ERR (1 << 31) +#define STS_CTRL_APP0_IRQONEND (1 << 30) +/* undoccumented */ +#define STS_CTRL_APP0_STOPONEND (1 << 29) +#define STS_CTRL_APP0_CMPLT (1 << 28) +#define STS_CTRL_APP0_SOP (1 << 27) +#define STS_CTRL_APP0_EOP (1 << 26) +#define STS_CTRL_APP0_ENGBUSY (1 << 25) +/* undocumented */ +#define STS_CTRL_APP0_ENGRST (1 << 24) + +#define TX_CONTROL_CALC_CSUM_MASK 1 + +#define XTE_ALIGN 32 +#define BUFFER_ALIGN(adr) ((XTE_ALIGN - ((u32) adr)) % XTE_ALIGN) + +#define MULTICAST_CAM_TABLE_NUM 4 + +/* TX/RX CURDESC_PTR points to first descriptor */ +/* TX/RX TAILDESC_PTR points to last descriptor in linked list */ + +/** + * struct cdmac_bd - LocalLink buffer descriptor format + * + * app0 bits: + * 0 Error + * 1 IrqOnEnd generate an interrupt at completion of DMA op + * 2 reserved + * 3 completed Current descriptor completed + * 4 SOP TX - marks first desc/ RX marks first desct + * 5 EOP TX marks last desc/RX marks last desc + * 6 EngBusy DMA is processing + * 7 reserved + * 8:31 application specific + */ +struct cdmac_bd { + u32 next; /* Physical address of next buffer descriptor */ + u32 phys; + u32 len; + u32 app0; + u32 app1; /* TX start << 16 | insert */ + u32 app2; /* TX csum */ + u32 app3; + u32 app4; /* skb for TX length for RX */ +}; + +struct temac_local { + struct net_device *ndev; + struct device *dev; + + /* Connection to PHY device */ + struct phy_device *phy_dev; /* Pointer to PHY device */ + struct device_node *phy_node; + + /* MDIO bus data */ + struct mii_bus *mii_bus; /* MII bus reference */ + int mdio_irqs[PHY_MAX_ADDR]; /* IRQs table for MDIO bus */ + + /* IO registers and IRQs */ + void __iomem *regs; + dcr_host_t sdma_dcrs; + int tx_irq; + int rx_irq; + int emac_num; + + struct sk_buff **rx_skb; + spinlock_t rx_lock; + struct mutex indirect_mutex; + u32 options; /* Current options word */ + int last_link; + + /* Buffer descriptors */ + struct cdmac_bd *tx_bd_v; + dma_addr_t tx_bd_p; + struct cdmac_bd *rx_bd_v; + dma_addr_t rx_bd_p; + int tx_bd_ci; + int tx_bd_next; + int tx_bd_tail; + int rx_bd_ci; +}; + +/* xilinx_temac.c */ +u32 temac_ior(struct temac_local *lp, int offset); +void temac_iow(struct temac_local *lp, int offset, u32 value); +int temac_indirect_busywait(struct temac_local *lp); +u32 temac_indirect_in32(struct temac_local *lp, int reg); +void temac_indirect_out32(struct temac_local *lp, int reg, u32 value); + + +/* xilinx_temac_mdio.c */ +int temac_mdio_setup(struct temac_local *lp, struct device_node *np); +void temac_mdio_teardown(struct temac_local *lp); + +#endif /* XILINX_LL_TEMAC_H */ diff --git a/drivers/net/ll_temac_main.c b/drivers/net/ll_temac_main.c new file mode 100644 index 000000000000..96e7248876c1 --- /dev/null +++ b/drivers/net/ll_temac_main.c @@ -0,0 +1,969 @@ +/* + * Driver for Xilinx TEMAC Ethernet device + * + * Copyright (c) 2008 Nissin Systems Co., Ltd., Yoshio Kashiwagi + * Copyright (c) 2005-2008 DLA Systems, David H. Lynch Jr. + * Copyright (c) 2008-2009 Secret Lab Technologies Ltd. + * + * This is a driver for the Xilinx ll_temac ipcore which is often used + * in the Virtex and Spartan series of chips. + * + * Notes: + * - The ll_temac hardware uses indirect access for many of the TEMAC + * registers, include the MDIO bus. However, indirect access to MDIO + * registers take considerably more clock cycles than to TEMAC registers. + * MDIO accesses are long, so threads doing them should probably sleep + * rather than busywait. However, since only one indirect access can be + * in progress at any given time, that means that *all* indirect accesses + * could end up sleeping (to wait for an MDIO access to complete). + * Fortunately none of the indirect accesses are on the 'hot' path for tx + * or rx, so this should be okay. + * + * TODO: + * - Fix driver to work on more than just Virtex5. Right now the driver + * assumes that the locallink DMA registers are accessed via DCR + * instructions. + * - Factor out locallink DMA code into separate driver + * - Fix multicast assignment. + * - Fix support for hardware checksumming. + * - Testing. Lots and lots of testing. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* needed for sizeof(tcphdr) */ +#include /* needed for sizeof(udphdr) */ +#include +#include +#include +#include + +#include "ll_temac.h" + +#define TX_BD_NUM 64 +#define RX_BD_NUM 128 + +/* --------------------------------------------------------------------- + * Low level register access functions + */ + +u32 temac_ior(struct temac_local *lp, int offset) +{ + return in_be32((u32 *)(lp->regs + offset)); +} + +void temac_iow(struct temac_local *lp, int offset, u32 value) +{ + out_be32((u32 *) (lp->regs + offset), value); +} + +int temac_indirect_busywait(struct temac_local *lp) +{ + long end = jiffies + 2; + + while (!(temac_ior(lp, XTE_RDY0_OFFSET) & XTE_RDY0_HARD_ACS_RDY_MASK)) { + if (end - jiffies <= 0) { + WARN_ON(1); + return -ETIMEDOUT; + } + msleep(1); + } + return 0; +} + +/** + * temac_indirect_in32 + * + * lp->indirect_mutex must be held when calling this function + */ +u32 temac_indirect_in32(struct temac_local *lp, int reg) +{ + u32 val; + + if (temac_indirect_busywait(lp)) + return -ETIMEDOUT; + temac_iow(lp, XTE_CTL0_OFFSET, reg); + if (temac_indirect_busywait(lp)) + return -ETIMEDOUT; + val = temac_ior(lp, XTE_LSW0_OFFSET); + + return val; +} + +/** + * temac_indirect_out32 + * + * lp->indirect_mutex must be held when calling this function + */ +void temac_indirect_out32(struct temac_local *lp, int reg, u32 value) +{ + if (temac_indirect_busywait(lp)) + return; + temac_iow(lp, XTE_LSW0_OFFSET, value); + temac_iow(lp, XTE_CTL0_OFFSET, CNTLREG_WRITE_ENABLE_MASK | reg); +} + +static u32 temac_dma_in32(struct temac_local *lp, int reg) +{ + return dcr_read(lp->sdma_dcrs, reg); +} + +static void temac_dma_out32(struct temac_local *lp, int reg, u32 value) +{ + dcr_write(lp->sdma_dcrs, reg, value); +} + +/** + * temac_dma_bd_init - Setup buffer descriptor rings + */ +static int temac_dma_bd_init(struct net_device *ndev) +{ + struct temac_local *lp = netdev_priv(ndev); + struct sk_buff *skb; + int i; + + lp->rx_skb = kzalloc(sizeof(struct sk_buff)*RX_BD_NUM, GFP_KERNEL); + /* allocate the tx and rx ring buffer descriptors. */ + /* returns a virtual addres and a physical address. */ + lp->tx_bd_v = dma_alloc_coherent(ndev->dev.parent, + sizeof(*lp->tx_bd_v) * TX_BD_NUM, + &lp->tx_bd_p, GFP_KERNEL); + lp->rx_bd_v = dma_alloc_coherent(ndev->dev.parent, + sizeof(*lp->rx_bd_v) * RX_BD_NUM, + &lp->rx_bd_p, GFP_KERNEL); + + memset(lp->tx_bd_v, 0, sizeof(*lp->tx_bd_v) * TX_BD_NUM); + for (i = 0; i < TX_BD_NUM; i++) { + lp->tx_bd_v[i].next = lp->tx_bd_p + + sizeof(*lp->tx_bd_v) * ((i + 1) % TX_BD_NUM); + } + + memset(lp->rx_bd_v, 0, sizeof(*lp->rx_bd_v) * RX_BD_NUM); + for (i = 0; i < RX_BD_NUM; i++) { + lp->rx_bd_v[i].next = lp->rx_bd_p + + sizeof(*lp->rx_bd_v) * ((i + 1) % RX_BD_NUM); + + skb = alloc_skb(XTE_MAX_JUMBO_FRAME_SIZE + + XTE_ALIGN, GFP_ATOMIC); + if (skb == 0) { + dev_err(&ndev->dev, "alloc_skb error %d\n", i); + return -1; + } + lp->rx_skb[i] = skb; + skb_reserve(skb, BUFFER_ALIGN(skb->data)); + /* returns physical address of skb->data */ + lp->rx_bd_v[i].phys = dma_map_single(ndev->dev.parent, + skb->data, + XTE_MAX_JUMBO_FRAME_SIZE, + DMA_FROM_DEVICE); + lp->rx_bd_v[i].len = XTE_MAX_JUMBO_FRAME_SIZE; + lp->rx_bd_v[i].app0 = STS_CTRL_APP0_IRQONEND; + } + + temac_dma_out32(lp, TX_CHNL_CTRL, 0x10220400 | + CHNL_CTRL_IRQ_EN | + CHNL_CTRL_IRQ_DLY_EN | + CHNL_CTRL_IRQ_COAL_EN); + /* 0x10220483 */ + /* 0x00100483 */ + temac_dma_out32(lp, RX_CHNL_CTRL, 0xff010000 | + CHNL_CTRL_IRQ_EN | + CHNL_CTRL_IRQ_DLY_EN | + CHNL_CTRL_IRQ_COAL_EN | + CHNL_CTRL_IRQ_IOE); + /* 0xff010283 */ + + temac_dma_out32(lp, RX_CURDESC_PTR, lp->rx_bd_p); + temac_dma_out32(lp, RX_TAILDESC_PTR, + lp->rx_bd_p + (sizeof(*lp->rx_bd_v) * (RX_BD_NUM - 1))); + temac_dma_out32(lp, TX_CURDESC_PTR, lp->tx_bd_p); + + return 0; +} + +/* --------------------------------------------------------------------- + * net_device_ops + */ + +static int temac_set_mac_address(struct net_device *ndev, void *address) +{ + struct temac_local *lp = netdev_priv(ndev); + + if (address) + memcpy(ndev->dev_addr, address, ETH_ALEN); + + if (!is_valid_ether_addr(ndev->dev_addr)) + random_ether_addr(ndev->dev_addr); + + /* set up unicast MAC address filter set its mac address */ + mutex_lock(&lp->indirect_mutex); + temac_indirect_out32(lp, XTE_UAW0_OFFSET, + (ndev->dev_addr[0]) | + (ndev->dev_addr[1] << 8) | + (ndev->dev_addr[2] << 16) | + (ndev->dev_addr[3] << 24)); + /* There are reserved bits in EUAW1 + * so don't affect them Set MAC bits [47:32] in EUAW1 */ + temac_indirect_out32(lp, XTE_UAW1_OFFSET, + (ndev->dev_addr[4] & 0x000000ff) | + (ndev->dev_addr[5] << 8)); + mutex_unlock(&lp->indirect_mutex); + + return 0; +} + +static void temac_set_multicast_list(struct net_device *ndev) +{ + struct temac_local *lp = netdev_priv(ndev); + u32 multi_addr_msw, multi_addr_lsw, val; + int i; + + mutex_lock(&lp->indirect_mutex); + if (ndev->flags & (IFF_ALLMULTI | IFF_PROMISC) + || ndev->mc_count > MULTICAST_CAM_TABLE_NUM) { + /* + * We must make the kernel realise we had to move + * into promisc mode or we start all out war on + * the cable. If it was a promisc request the + * flag is already set. If not we assert it. + */ + ndev->flags |= IFF_PROMISC; + temac_indirect_out32(lp, XTE_AFM_OFFSET, XTE_AFM_EPPRM_MASK); + dev_info(&ndev->dev, "Promiscuous mode enabled.\n"); + } else if (ndev->mc_count) { + struct dev_mc_list *mclist = ndev->mc_list; + for (i = 0; mclist && i < ndev->mc_count; i++) { + + if (i >= MULTICAST_CAM_TABLE_NUM) + break; + multi_addr_msw = ((mclist->dmi_addr[3] << 24) | + (mclist->dmi_addr[2] << 16) | + (mclist->dmi_addr[1] << 8) | + (mclist->dmi_addr[0])); + temac_indirect_out32(lp, XTE_MAW0_OFFSET, + multi_addr_msw); + multi_addr_lsw = ((mclist->dmi_addr[5] << 8) | + (mclist->dmi_addr[4]) | (i << 16)); + temac_indirect_out32(lp, XTE_MAW1_OFFSET, + multi_addr_lsw); + mclist = mclist->next; + } + } else { + val = temac_indirect_in32(lp, XTE_AFM_OFFSET); + temac_indirect_out32(lp, XTE_AFM_OFFSET, + val & ~XTE_AFM_EPPRM_MASK); + temac_indirect_out32(lp, XTE_MAW0_OFFSET, 0); + temac_indirect_out32(lp, XTE_MAW1_OFFSET, 0); + dev_info(&ndev->dev, "Promiscuous mode disabled.\n"); + } + mutex_unlock(&lp->indirect_mutex); +} + +struct temac_option { + int flg; + u32 opt; + u32 reg; + u32 m_or; + u32 m_and; +} temac_options[] = { + /* Turn on jumbo packet support for both Rx and Tx */ + { + .opt = XTE_OPTION_JUMBO, + .reg = XTE_TXC_OFFSET, + .m_or = XTE_TXC_TXJMBO_MASK, + }, + { + .opt = XTE_OPTION_JUMBO, + .reg = XTE_RXC1_OFFSET, + .m_or =XTE_RXC1_RXJMBO_MASK, + }, + /* Turn on VLAN packet support for both Rx and Tx */ + { + .opt = XTE_OPTION_VLAN, + .reg = XTE_TXC_OFFSET, + .m_or =XTE_TXC_TXVLAN_MASK, + }, + { + .opt = XTE_OPTION_VLAN, + .reg = XTE_RXC1_OFFSET, + .m_or =XTE_RXC1_RXVLAN_MASK, + }, + /* Turn on FCS stripping on receive packets */ + { + .opt = XTE_OPTION_FCS_STRIP, + .reg = XTE_RXC1_OFFSET, + .m_or =XTE_RXC1_RXFCS_MASK, + }, + /* Turn on FCS insertion on transmit packets */ + { + .opt = XTE_OPTION_FCS_INSERT, + .reg = XTE_TXC_OFFSET, + .m_or =XTE_TXC_TXFCS_MASK, + }, + /* Turn on length/type field checking on receive packets */ + { + .opt = XTE_OPTION_LENTYPE_ERR, + .reg = XTE_RXC1_OFFSET, + .m_or =XTE_RXC1_RXLT_MASK, + }, + /* Turn on flow control */ + { + .opt = XTE_OPTION_FLOW_CONTROL, + .reg = XTE_FCC_OFFSET, + .m_or =XTE_FCC_RXFLO_MASK, + }, + /* Turn on flow control */ + { + .opt = XTE_OPTION_FLOW_CONTROL, + .reg = XTE_FCC_OFFSET, + .m_or =XTE_FCC_TXFLO_MASK, + }, + /* Turn on promiscuous frame filtering (all frames are received ) */ + { + .opt = XTE_OPTION_PROMISC, + .reg = XTE_AFM_OFFSET, + .m_or =XTE_AFM_EPPRM_MASK, + }, + /* Enable transmitter if not already enabled */ + { + .opt = XTE_OPTION_TXEN, + .reg = XTE_TXC_OFFSET, + .m_or =XTE_TXC_TXEN_MASK, + }, + /* Enable receiver? */ + { + .opt = XTE_OPTION_RXEN, + .reg = XTE_RXC1_OFFSET, + .m_or =XTE_RXC1_RXEN_MASK, + }, + {} +}; + +/** + * temac_setoptions + */ +static u32 temac_setoptions(struct net_device *ndev, u32 options) +{ + struct temac_local *lp = netdev_priv(ndev); + struct temac_option *tp = &temac_options[0]; + int reg; + + mutex_lock(&lp->indirect_mutex); + while (tp->opt) { + reg = temac_indirect_in32(lp, tp->reg) & ~tp->m_or; + if (options & tp->opt) + reg |= tp->m_or; + temac_indirect_out32(lp, tp->reg, reg); + tp++; + } + lp->options |= options; + mutex_unlock(&lp->indirect_mutex); + + return (0); +} + +/* Initilize temac */ +static void temac_device_reset(struct net_device *ndev) +{ + struct temac_local *lp = netdev_priv(ndev); + u32 timeout; + u32 val; + + /* Perform a software reset */ + + /* 0x300 host enable bit ? */ + /* reset PHY through control register ?:1 */ + + dev_dbg(&ndev->dev, "%s()\n", __func__); + + mutex_lock(&lp->indirect_mutex); + /* Reset the receiver and wait for it to finish reset */ + temac_indirect_out32(lp, XTE_RXC1_OFFSET, XTE_RXC1_RXRST_MASK); + timeout = 1000; + while (temac_indirect_in32(lp, XTE_RXC1_OFFSET) & XTE_RXC1_RXRST_MASK) { + udelay(1); + if (--timeout == 0) { + dev_err(&ndev->dev, + "temac_device_reset RX reset timeout!!\n"); + break; + } + } + + /* Reset the transmitter and wait for it to finish reset */ + temac_indirect_out32(lp, XTE_TXC_OFFSET, XTE_TXC_TXRST_MASK); + timeout = 1000; + while (temac_indirect_in32(lp, XTE_TXC_OFFSET) & XTE_TXC_TXRST_MASK) { + udelay(1); + if (--timeout == 0) { + dev_err(&ndev->dev, + "temac_device_reset TX reset timeout!!\n"); + break; + } + } + + /* Disable the receiver */ + val = temac_indirect_in32(lp, XTE_RXC1_OFFSET); + temac_indirect_out32(lp, XTE_RXC1_OFFSET, val & ~XTE_RXC1_RXEN_MASK); + + /* Reset Local Link (DMA) */ + temac_dma_out32(lp, DMA_CONTROL_REG, DMA_CONTROL_RST); + timeout = 1000; + while (temac_dma_in32(lp, DMA_CONTROL_REG) & DMA_CONTROL_RST) { + udelay(1); + if (--timeout == 0) { + dev_err(&ndev->dev, + "temac_device_reset DMA reset timeout!!\n"); + break; + } + } + temac_dma_out32(lp, DMA_CONTROL_REG, DMA_TAIL_ENABLE); + + temac_dma_bd_init(ndev); + + temac_indirect_out32(lp, XTE_RXC0_OFFSET, 0); + temac_indirect_out32(lp, XTE_RXC1_OFFSET, 0); + temac_indirect_out32(lp, XTE_TXC_OFFSET, 0); + temac_indirect_out32(lp, XTE_FCC_OFFSET, XTE_FCC_RXFLO_MASK); + + mutex_unlock(&lp->indirect_mutex); + + /* Sync default options with HW + * but leave receiver and transmitter disabled. */ + temac_setoptions(ndev, + lp->options & ~(XTE_OPTION_TXEN | XTE_OPTION_RXEN)); + + temac_set_mac_address(ndev, NULL); + + /* Set address filter table */ + temac_set_multicast_list(ndev); + if (temac_setoptions(ndev, lp->options)) + dev_err(&ndev->dev, "Error setting TEMAC options\n"); + + /* Init Driver variable */ + ndev->trans_start = 0; +} + +void temac_adjust_link(struct net_device *ndev) +{ + struct temac_local *lp = netdev_priv(ndev); + struct phy_device *phy = lp->phy_dev; + u32 mii_speed; + int link_state; + + /* hash together the state values to decide if something has changed */ + link_state = phy->speed | (phy->duplex << 1) | phy->link; + + mutex_lock(&lp->indirect_mutex); + if (lp->last_link != link_state) { + mii_speed = temac_indirect_in32(lp, XTE_EMCFG_OFFSET); + mii_speed &= ~XTE_EMCFG_LINKSPD_MASK; + + switch (phy->speed) { + case SPEED_1000: mii_speed |= XTE_EMCFG_LINKSPD_1000; break; + case SPEED_100: mii_speed |= XTE_EMCFG_LINKSPD_100; break; + case SPEED_10: mii_speed |= XTE_EMCFG_LINKSPD_10; break; + } + + /* Write new speed setting out to TEMAC */ + temac_indirect_out32(lp, XTE_EMCFG_OFFSET, mii_speed); + lp->last_link = link_state; + phy_print_status(phy); + } + mutex_unlock(&lp->indirect_mutex); +} + +static void temac_start_xmit_done(struct net_device *ndev) +{ + struct temac_local *lp = netdev_priv(ndev); + struct cdmac_bd *cur_p; + unsigned int stat = 0; + + cur_p = &lp->tx_bd_v[lp->tx_bd_ci]; + stat = cur_p->app0; + + while (stat & STS_CTRL_APP0_CMPLT) { + dma_unmap_single(ndev->dev.parent, cur_p->phys, cur_p->len, + DMA_TO_DEVICE); + if (cur_p->app4) + dev_kfree_skb_irq((struct sk_buff *)cur_p->app4); + cur_p->app0 = 0; + + ndev->stats.tx_packets++; + ndev->stats.tx_bytes += cur_p->len; + + lp->tx_bd_ci++; + if (lp->tx_bd_ci >= TX_BD_NUM) + lp->tx_bd_ci = 0; + + cur_p = &lp->tx_bd_v[lp->tx_bd_ci]; + stat = cur_p->app0; + } + + netif_wake_queue(ndev); +} + +static int temac_start_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + struct temac_local *lp = netdev_priv(ndev); + struct cdmac_bd *cur_p; + dma_addr_t start_p, tail_p; + int ii; + unsigned long num_frag; + skb_frag_t *frag; + + num_frag = skb_shinfo(skb)->nr_frags; + frag = &skb_shinfo(skb)->frags[0]; + start_p = lp->tx_bd_p + sizeof(*lp->tx_bd_v) * lp->tx_bd_tail; + cur_p = &lp->tx_bd_v[lp->tx_bd_tail]; + + if (cur_p->app0 & STS_CTRL_APP0_CMPLT) { + if (!netif_queue_stopped(ndev)) { + netif_stop_queue(ndev); + return NETDEV_TX_BUSY; + } + return NETDEV_TX_BUSY; + } + + cur_p->app0 = 0; + if (skb->ip_summed == CHECKSUM_PARTIAL) { + const struct iphdr *ip = ip_hdr(skb); + int length = 0, start = 0, insert = 0; + + switch (ip->protocol) { + case IPPROTO_TCP: + start = sizeof(struct iphdr) + ETH_HLEN; + insert = sizeof(struct iphdr) + ETH_HLEN + 16; + length = ip->tot_len - sizeof(struct iphdr); + break; + case IPPROTO_UDP: + start = sizeof(struct iphdr) + ETH_HLEN; + insert = sizeof(struct iphdr) + ETH_HLEN + 6; + length = ip->tot_len - sizeof(struct iphdr); + break; + default: + break; + } + cur_p->app1 = ((start << 16) | insert); + cur_p->app2 = csum_tcpudp_magic(ip->saddr, ip->daddr, + length, ip->protocol, 0); + skb->data[insert] = 0; + skb->data[insert + 1] = 0; + } + cur_p->app0 |= STS_CTRL_APP0_SOP; + cur_p->len = skb_headlen(skb); + cur_p->phys = dma_map_single(ndev->dev.parent, skb->data, skb->len, + DMA_TO_DEVICE); + cur_p->app4 = (unsigned long)skb; + + for (ii = 0; ii < num_frag; ii++) { + lp->tx_bd_tail++; + if (lp->tx_bd_tail >= TX_BD_NUM) + lp->tx_bd_tail = 0; + + cur_p = &lp->tx_bd_v[lp->tx_bd_tail]; + cur_p->phys = dma_map_single(ndev->dev.parent, + (void *)page_address(frag->page) + + frag->page_offset, + frag->size, DMA_TO_DEVICE); + cur_p->len = frag->size; + cur_p->app0 = 0; + frag++; + } + cur_p->app0 |= STS_CTRL_APP0_EOP; + + tail_p = lp->tx_bd_p + sizeof(*lp->tx_bd_v) * lp->tx_bd_tail; + lp->tx_bd_tail++; + if (lp->tx_bd_tail >= TX_BD_NUM) + lp->tx_bd_tail = 0; + + /* Kick off the transfer */ + temac_dma_out32(lp, TX_TAILDESC_PTR, tail_p); /* DMA start */ + + return 0; +} + + +static void ll_temac_recv(struct net_device *ndev) +{ + struct temac_local *lp = netdev_priv(ndev); + struct sk_buff *skb, *new_skb; + unsigned int bdstat; + struct cdmac_bd *cur_p; + dma_addr_t tail_p; + int length; + unsigned long skb_vaddr; + unsigned long flags; + + spin_lock_irqsave(&lp->rx_lock, flags); + + tail_p = lp->rx_bd_p + sizeof(*lp->rx_bd_v) * lp->rx_bd_ci; + cur_p = &lp->rx_bd_v[lp->rx_bd_ci]; + + bdstat = cur_p->app0; + while ((bdstat & STS_CTRL_APP0_CMPLT)) { + + skb = lp->rx_skb[lp->rx_bd_ci]; + length = cur_p->app4; + + skb_vaddr = virt_to_bus(skb->data); + dma_unmap_single(ndev->dev.parent, skb_vaddr, length, + DMA_FROM_DEVICE); + + skb_put(skb, length); + skb->dev = ndev; + skb->protocol = eth_type_trans(skb, ndev); + skb->ip_summed = CHECKSUM_NONE; + + netif_rx(skb); + + ndev->stats.rx_packets++; + ndev->stats.rx_bytes += length; + + new_skb = alloc_skb(XTE_MAX_JUMBO_FRAME_SIZE + XTE_ALIGN, + GFP_ATOMIC); + if (new_skb == 0) { + dev_err(&ndev->dev, "no memory for new sk_buff\n"); + spin_unlock_irqrestore(&lp->rx_lock, flags); + return; + } + + skb_reserve(new_skb, BUFFER_ALIGN(new_skb->data)); + + cur_p->app0 = STS_CTRL_APP0_IRQONEND; + cur_p->phys = dma_map_single(ndev->dev.parent, new_skb->data, + XTE_MAX_JUMBO_FRAME_SIZE, + DMA_FROM_DEVICE); + cur_p->len = XTE_MAX_JUMBO_FRAME_SIZE; + lp->rx_skb[lp->rx_bd_ci] = new_skb; + + lp->rx_bd_ci++; + if (lp->rx_bd_ci >= RX_BD_NUM) + lp->rx_bd_ci = 0; + + cur_p = &lp->rx_bd_v[lp->rx_bd_ci]; + bdstat = cur_p->app0; + } + temac_dma_out32(lp, RX_TAILDESC_PTR, tail_p); + + spin_unlock_irqrestore(&lp->rx_lock, flags); +} + +static irqreturn_t ll_temac_tx_irq(int irq, void *_ndev) +{ + struct net_device *ndev = _ndev; + struct temac_local *lp = netdev_priv(ndev); + unsigned int status; + + status = temac_dma_in32(lp, TX_IRQ_REG); + temac_dma_out32(lp, TX_IRQ_REG, status); + + if (status & (IRQ_COAL | IRQ_DLY)) + temac_start_xmit_done(lp->ndev); + if (status & 0x080) + dev_err(&ndev->dev, "DMA error 0x%x\n", status); + + return IRQ_HANDLED; +} + +static irqreturn_t ll_temac_rx_irq(int irq, void *_ndev) +{ + struct net_device *ndev = _ndev; + struct temac_local *lp = netdev_priv(ndev); + unsigned int status; + + /* Read and clear the status registers */ + status = temac_dma_in32(lp, RX_IRQ_REG); + temac_dma_out32(lp, RX_IRQ_REG, status); + + if (status & (IRQ_COAL | IRQ_DLY)) + ll_temac_recv(lp->ndev); + + return IRQ_HANDLED; +} + +static int temac_open(struct net_device *ndev) +{ + struct temac_local *lp = netdev_priv(ndev); + int rc; + + dev_dbg(&ndev->dev, "temac_open()\n"); + + if (lp->phy_node) { + lp->phy_dev = of_phy_connect(lp->ndev, lp->phy_node, + temac_adjust_link, 0, 0); + if (!lp->phy_dev) { + dev_err(lp->dev, "of_phy_connect() failed\n"); + return -ENODEV; + } + + phy_start(lp->phy_dev); + } + + rc = request_irq(lp->tx_irq, ll_temac_tx_irq, 0, ndev->name, ndev); + if (rc) + goto err_tx_irq; + rc = request_irq(lp->rx_irq, ll_temac_rx_irq, 0, ndev->name, ndev); + if (rc) + goto err_rx_irq; + + temac_device_reset(ndev); + return 0; + + err_rx_irq: + free_irq(lp->tx_irq, ndev); + err_tx_irq: + if (lp->phy_dev) + phy_disconnect(lp->phy_dev); + lp->phy_dev = NULL; + dev_err(lp->dev, "request_irq() failed\n"); + return rc; +} + +static int temac_stop(struct net_device *ndev) +{ + struct temac_local *lp = netdev_priv(ndev); + + dev_dbg(&ndev->dev, "temac_close()\n"); + + free_irq(lp->tx_irq, ndev); + free_irq(lp->rx_irq, ndev); + + if (lp->phy_dev) + phy_disconnect(lp->phy_dev); + lp->phy_dev = NULL; + + return 0; +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +static void +temac_poll_controller(struct net_device *ndev) +{ + struct temac_local *lp = netdev_priv(ndev); + + disable_irq(lp->tx_irq); + disable_irq(lp->rx_irq); + + ll_temac_rx_irq(lp->tx_irq, lp); + ll_temac_tx_irq(lp->rx_irq, lp); + + enable_irq(lp->tx_irq); + enable_irq(lp->rx_irq); +} +#endif + +static const struct net_device_ops temac_netdev_ops = { + .ndo_open = temac_open, + .ndo_stop = temac_stop, + .ndo_start_xmit = temac_start_xmit, + .ndo_set_mac_address = temac_set_mac_address, + //.ndo_set_multicast_list = temac_set_multicast_list, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = temac_poll_controller, +#endif +}; + +/* --------------------------------------------------------------------- + * SYSFS device attributes + */ +static ssize_t temac_show_llink_regs(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct net_device *ndev = dev_get_drvdata(dev); + struct temac_local *lp = netdev_priv(ndev); + int i, len = 0; + + for (i = 0; i < 0x11; i++) + len += sprintf(buf + len, "%.8x%s", temac_dma_in32(lp, i), + (i % 8) == 7 ? "\n" : " "); + len += sprintf(buf + len, "\n"); + + return len; +} + +static DEVICE_ATTR(llink_regs, 0440, temac_show_llink_regs, NULL); + +static struct attribute *temac_device_attrs[] = { + &dev_attr_llink_regs.attr, + NULL, +}; + +static const struct attribute_group temac_attr_group = { + .attrs = temac_device_attrs, +}; + +static int __init +temac_of_probe(struct of_device *op, const struct of_device_id *match) +{ + struct device_node *np; + struct temac_local *lp; + struct net_device *ndev; + const void *addr; + int size, rc = 0; + unsigned int dcrs; + + /* Init network device structure */ + ndev = alloc_etherdev(sizeof(*lp)); + if (!ndev) { + dev_err(&op->dev, "could not allocate device.\n"); + return -ENOMEM; + } + ether_setup(ndev); + dev_set_drvdata(&op->dev, ndev); + SET_NETDEV_DEV(ndev, &op->dev); + ndev->flags &= ~IFF_MULTICAST; /* clear multicast */ + ndev->features = NETIF_F_SG | NETIF_F_FRAGLIST; + ndev->netdev_ops = &temac_netdev_ops; +#if 0 + ndev->features |= NETIF_F_IP_CSUM; /* Can checksum TCP/UDP over IPv4. */ + ndev->features |= NETIF_F_HW_CSUM; /* Can checksum all the packets. */ + ndev->features |= NETIF_F_IPV6_CSUM; /* Can checksum IPV6 TCP/UDP */ + ndev->features |= NETIF_F_HIGHDMA; /* Can DMA to high memory. */ + ndev->features |= NETIF_F_HW_VLAN_TX; /* Transmit VLAN hw accel */ + ndev->features |= NETIF_F_HW_VLAN_RX; /* Receive VLAN hw acceleration */ + ndev->features |= NETIF_F_HW_VLAN_FILTER; /* Receive VLAN filtering */ + ndev->features |= NETIF_F_VLAN_CHALLENGED; /* cannot handle VLAN pkts */ + ndev->features |= NETIF_F_GSO; /* Enable software GSO. */ + ndev->features |= NETIF_F_MULTI_QUEUE; /* Has multiple TX/RX queues */ + ndev->features |= NETIF_F_LRO; /* large receive offload */ +#endif + + /* setup temac private info structure */ + lp = netdev_priv(ndev); + lp->ndev = ndev; + lp->dev = &op->dev; + lp->options = XTE_OPTION_DEFAULTS; + spin_lock_init(&lp->rx_lock); + mutex_init(&lp->indirect_mutex); + + /* map device registers */ + lp->regs = of_iomap(op->node, 0); + if (!lp->regs) { + dev_err(&op->dev, "could not map temac regs.\n"); + goto nodev; + } + + /* Find the DMA node, map the DMA registers, and decode the DMA IRQs */ + np = of_parse_phandle(op->node, "llink-connected", 0); + if (!np) { + dev_err(&op->dev, "could not find DMA node\n"); + goto nodev; + } + + dcrs = dcr_resource_start(np, 0); + if (dcrs == 0) { + dev_err(&op->dev, "could not get DMA register address\n"); + goto nodev;; + } + lp->sdma_dcrs = dcr_map(np, dcrs, dcr_resource_len(np, 0)); + dev_dbg(&op->dev, "DCR base: %x\n", dcrs); + + lp->rx_irq = irq_of_parse_and_map(np, 0); + lp->tx_irq = irq_of_parse_and_map(np, 1); + if (!lp->rx_irq || !lp->tx_irq) { + dev_err(&op->dev, "could not determine irqs\n"); + rc = -ENOMEM; + goto nodev; + } + + of_node_put(np); /* Finished with the DMA node; drop the reference */ + + /* Retrieve the MAC address */ + addr = of_get_property(op->node, "local-mac-address", &size); + if ((!addr) || (size != 6)) { + dev_err(&op->dev, "could not find MAC address\n"); + rc = -ENODEV; + goto nodev; + } + temac_set_mac_address(ndev, (void *)addr); + + rc = temac_mdio_setup(lp, op->node); + if (rc) + dev_warn(&op->dev, "error registering MDIO bus\n"); + + lp->phy_node = of_parse_phandle(op->node, "phy-handle", 0); + if (lp->phy_node) + dev_dbg(lp->dev, "using PHY node %s (%p)\n", np->full_name, np); + + /* Add the device attributes */ + rc = sysfs_create_group(&lp->dev->kobj, &temac_attr_group); + if (rc) { + dev_err(lp->dev, "Error creating sysfs files\n"); + goto nodev; + } + + rc = register_netdev(lp->ndev); + if (rc) { + dev_err(lp->dev, "register_netdev() error (%i)\n", rc); + goto err_register_ndev; + } + + return 0; + + err_register_ndev: + sysfs_remove_group(&lp->dev->kobj, &temac_attr_group); + nodev: + free_netdev(ndev); + ndev = NULL; + return rc; +} + +static int __devexit temac_of_remove(struct of_device *op) +{ + struct net_device *ndev = dev_get_drvdata(&op->dev); + struct temac_local *lp = netdev_priv(ndev); + + temac_mdio_teardown(lp); + unregister_netdev(ndev); + sysfs_remove_group(&lp->dev->kobj, &temac_attr_group); + if (lp->phy_node) + of_node_put(lp->phy_node); + lp->phy_node = NULL; + dev_set_drvdata(&op->dev, NULL); + free_netdev(ndev); + return 0; +} + +static struct of_device_id temac_of_match[] __devinitdata = { + { .compatible = "xlnx,xps-ll-temac-1.01.b", }, + {}, +}; +MODULE_DEVICE_TABLE(of, temac_of_match); + +static struct of_platform_driver temac_of_driver = { + .match_table = temac_of_match, + .probe = temac_of_probe, + .remove = __devexit_p(temac_of_remove), + .driver = { + .owner = THIS_MODULE, + .name = "xilinx_temac", + }, +}; + +static int __init temac_init(void) +{ + return of_register_platform_driver(&temac_of_driver); +} +module_init(temac_init); + +static void __exit temac_exit(void) +{ + of_unregister_platform_driver(&temac_of_driver); +} +module_exit(temac_exit); + +MODULE_DESCRIPTION("Xilinx LL_TEMAC Ethernet driver"); +MODULE_AUTHOR("Yoshio Kashiwagi"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/ll_temac_mdio.c b/drivers/net/ll_temac_mdio.c new file mode 100644 index 000000000000..da0e462308d5 --- /dev/null +++ b/drivers/net/ll_temac_mdio.c @@ -0,0 +1,120 @@ +/* + * MDIO bus driver for the Xilinx TEMAC device + * + * Copyright (c) 2009 Secret Lab Technologies, Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "ll_temac.h" + +/* --------------------------------------------------------------------- + * MDIO Bus functions + */ +static int temac_mdio_read(struct mii_bus *bus, int phy_id, int reg) +{ + struct temac_local *lp = bus->priv; + u32 rc; + + /* Write the PHY address to the MIIM Access Initiator register. + * When the transfer completes, the PHY register value will appear + * in the LSW0 register */ + mutex_lock(&lp->indirect_mutex); + temac_iow(lp, XTE_LSW0_OFFSET, (phy_id << 5) | reg); + rc = temac_indirect_in32(lp, XTE_MIIMAI_OFFSET); + mutex_unlock(&lp->indirect_mutex); + + dev_dbg(lp->dev, "temac_mdio_read(phy_id=%i, reg=%x) == %x\n", + phy_id, reg, rc); + + return rc; +} + +static int temac_mdio_write(struct mii_bus *bus, int phy_id, int reg, u16 val) +{ + struct temac_local *lp = bus->priv; + + dev_dbg(lp->dev, "temac_mdio_write(phy_id=%i, reg=%x, val=%x)\n", + phy_id, reg, val); + + /* First write the desired value into the write data register + * and then write the address into the access initiator register + */ + mutex_lock(&lp->indirect_mutex); + temac_indirect_out32(lp, XTE_MGTDR_OFFSET, val); + temac_indirect_out32(lp, XTE_MIIMAI_OFFSET, (phy_id << 5) | reg); + mutex_unlock(&lp->indirect_mutex); + + return 0; +} + +int temac_mdio_setup(struct temac_local *lp, struct device_node *np) +{ + struct mii_bus *bus; + const u32 *bus_hz; + int clk_div; + int rc, size; + struct resource res; + + /* Calculate a reasonable divisor for the clock rate */ + clk_div = 0x3f; /* worst-case default setting */ + bus_hz = of_get_property(np, "clock-frequency", &size); + if (bus_hz && size >= sizeof(*bus_hz)) { + clk_div = (*bus_hz) / (2500 * 1000 * 2) - 1; + if (clk_div < 1) + clk_div = 1; + if (clk_div > 0x3f) + clk_div = 0x3f; + } + + /* Enable the MDIO bus by asserting the enable bit and writing + * in the clock config */ + mutex_lock(&lp->indirect_mutex); + temac_indirect_out32(lp, XTE_MC_OFFSET, 1 << 6 | clk_div); + mutex_unlock(&lp->indirect_mutex); + + bus = mdiobus_alloc(); + if (!bus) + return -ENOMEM; + + of_address_to_resource(np, 0, &res); + snprintf(bus->id, MII_BUS_ID_SIZE, "%.8llx", + (unsigned long long)res.start); + bus->priv = lp; + bus->name = "Xilinx TEMAC MDIO"; + bus->read = temac_mdio_read; + bus->write = temac_mdio_write; + bus->parent = lp->dev; + bus->irq = lp->mdio_irqs; /* preallocated IRQ table */ + + lp->mii_bus = bus; + + rc = of_mdiobus_register(bus, np); + if (rc) + goto err_register; + + mutex_lock(&lp->indirect_mutex); + dev_dbg(lp->dev, "MDIO bus registered; MC:%x\n", + temac_indirect_in32(lp, XTE_MC_OFFSET)); + mutex_unlock(&lp->indirect_mutex); + return 0; + + err_register: + mdiobus_free(bus); + return rc; +} + +void temac_mdio_teardown(struct temac_local *lp) +{ + mdiobus_unregister(lp->mii_bus); + kfree(lp->mii_bus->irq); + mdiobus_free(lp->mii_bus); + lp->mii_bus = NULL; +} + diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index b7d438a367f3..da472c687481 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -62,6 +62,7 @@ struct pcpu_lstats { unsigned long packets; unsigned long bytes; + unsigned long drops; }; /* @@ -71,18 +72,22 @@ struct pcpu_lstats { static int loopback_xmit(struct sk_buff *skb, struct net_device *dev) { struct pcpu_lstats *pcpu_lstats, *lb_stats; + int len; skb_orphan(skb); - skb->protocol = eth_type_trans(skb,dev); + skb->protocol = eth_type_trans(skb, dev); /* it's OK to use per_cpu_ptr() because BHs are off */ pcpu_lstats = dev->ml_priv; lb_stats = per_cpu_ptr(pcpu_lstats, smp_processor_id()); - lb_stats->bytes += skb->len; - lb_stats->packets++; - netif_rx(skb); + len = skb->len; + if (likely(netif_rx(skb) == NET_RX_SUCCESS)) { + lb_stats->bytes += len; + lb_stats->packets++; + } else + lb_stats->drops++; return 0; } @@ -93,6 +98,7 @@ static struct net_device_stats *loopback_get_stats(struct net_device *dev) struct net_device_stats *stats = &dev->stats; unsigned long bytes = 0; unsigned long packets = 0; + unsigned long drops = 0; int i; pcpu_lstats = dev->ml_priv; @@ -102,11 +108,14 @@ static struct net_device_stats *loopback_get_stats(struct net_device *dev) lb_stats = per_cpu_ptr(pcpu_lstats, i); bytes += lb_stats->bytes; packets += lb_stats->packets; + drops += lb_stats->drops; } stats->rx_packets = packets; stats->tx_packets = packets; - stats->rx_bytes = bytes; - stats->tx_bytes = bytes; + stats->rx_dropped = drops; + stats->rx_errors = drops; + stats->rx_bytes = bytes; + stats->tx_bytes = bytes; return stats; } @@ -161,6 +170,7 @@ static void loopback_setup(struct net_device *dev) dev->tx_queue_len = 0; dev->type = ARPHRD_LOOPBACK; /* 0x0001*/ dev->flags = IFF_LOOPBACK; + dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_TSO | NETIF_F_NO_CSUM diff --git a/drivers/net/mac8390.c b/drivers/net/mac8390.c index 22e74a0e0361..f8fa0c3f0f64 100644 --- a/drivers/net/mac8390.c +++ b/drivers/net/mac8390.c @@ -620,19 +620,12 @@ static int __init mac8390_initdev(struct net_device * dev, struct nubus_dev * nd /* Good, done, now spit out some messages */ printk(KERN_INFO "%s: %s in slot %X (type %s)\n", - dev->name, ndev->board->name, ndev->board->slot, cardname[type]); - printk(KERN_INFO "MAC "); - { - int i; - for (i = 0; i < 6; i++) { - printk("%2.2x", dev->dev_addr[i]); - if (i < 5) - printk(":"); - } - } - printk(" IRQ %d, %d KB shared memory at %#lx, %d-bit access.\n", - dev->irq, (int)((dev->mem_end - dev->mem_start)/0x1000) * 4, - dev->mem_start, access_bitmode?32:16); + dev->name, ndev->board->name, ndev->board->slot, cardname[type]); + printk(KERN_INFO + "MAC %pM IRQ %d, %d KB shared memory at %#lx, %d-bit access.\n", + dev->dev_addr, dev->irq, + (unsigned int)(dev->mem_end - dev->mem_start) >> 10, + dev->mem_start, access_bitmode ? 32 : 16); return 0; } diff --git a/drivers/net/mac89x0.c b/drivers/net/mac89x0.c index 384e072de2e7..dab45339d3a8 100644 --- a/drivers/net/mac89x0.c +++ b/drivers/net/mac89x0.c @@ -73,8 +73,6 @@ static char *version = or override something. */ #include -#define PRINTK(x) printk x - /* Sources: @@ -402,7 +400,7 @@ net_send_packet(struct sk_buff *skb, struct net_device *dev) /* Gasp! It hasn't. But that shouldn't happen since we're waiting for TxOk, so return 1 and requeue this packet. */ local_irq_restore(flags); - return 1; + return NETDEV_TX_BUSY; } /* Write the contents of the packet */ diff --git a/drivers/net/macb.c b/drivers/net/macb.c index e82aee41d77e..5b5c25368d1e 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -599,6 +599,21 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } +#ifdef CONFIG_NET_POLL_CONTROLLER +/* + * Polling receive - used by netconsole and other diagnostic tools + * to allow network i/o with interrupts disabled. + */ +static void macb_poll_controller(struct net_device *dev) +{ + unsigned long flags; + + local_irq_save(flags); + macb_interrupt(dev->irq, dev); + local_irq_restore(flags); +} +#endif + static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct macb *bp = netdev_priv(dev); @@ -630,7 +645,7 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev) "BUG! Tx Ring full when queue awake!\n"); dev_dbg(&bp->pdev->dev, "tx_head = %u, tx_tail = %u\n", bp->tx_head, bp->tx_tail); - return 1; + return NETDEV_TX_BUSY; } entry = bp->tx_head; @@ -1094,6 +1109,9 @@ static const struct net_device_ops macb_netdev_ops = { .ndo_validate_addr = eth_validate_addr, .ndo_change_mtu = eth_change_mtu, .ndo_set_mac_address = eth_mac_addr, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = macb_poll_controller, +#endif }; static int __init macb_probe(struct platform_device *pdev) diff --git a/drivers/net/mace.c b/drivers/net/mace.c index feebbd92aff2..1427755c224d 100644 --- a/drivers/net/mace.c +++ b/drivers/net/mace.c @@ -94,6 +94,16 @@ static void __mace_set_address(struct net_device *dev, void *addr); */ static unsigned char *dummy_buf; +static const struct net_device_ops mace_netdev_ops = { + .ndo_open = mace_open, + .ndo_stop = mace_close, + .ndo_start_xmit = mace_xmit_start, + .ndo_set_multicast_list = mace_set_multicast, + .ndo_set_mac_address = mace_set_address, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, +}; + static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_id *match) { struct device_node *mace = macio_get_of_node(mdev); @@ -207,11 +217,7 @@ static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_i } } - dev->open = mace_open; - dev->stop = mace_close; - dev->hard_start_xmit = mace_xmit_start; - dev->set_multicast_list = mace_set_multicast; - dev->set_mac_address = mace_set_address; + dev->netdev_ops = &mace_netdev_ops; /* * Most of what is below could be moved to mace_open() @@ -541,7 +547,7 @@ static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); mp->tx_fullup = 1; spin_unlock_irqrestore(&mp->lock, flags); - return 1; /* can't take it at the moment */ + return NETDEV_TX_BUSY; /* can't take it at the moment */ } spin_unlock_irqrestore(&mp->lock, flags); diff --git a/drivers/net/macmace.c b/drivers/net/macmace.c index 274e99bb63ac..44f3c2896f20 100644 --- a/drivers/net/macmace.c +++ b/drivers/net/macmace.c @@ -180,6 +180,17 @@ static void mace_dma_off(struct net_device *dev) psc_write_word(PSC_ENETWR_CMD + PSC_SET1, 0x1100); } +static const struct net_device_ops mace_netdev_ops = { + .ndo_open = mace_open, + .ndo_stop = mace_close, + .ndo_start_xmit = mace_xmit_start, + .ndo_tx_timeout = mace_tx_timeout, + .ndo_set_multicast_list = mace_set_multicast, + .ndo_set_mac_address = mace_set_address, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, +}; + /* * Not really much of a probe. The hardware table tells us if this * model of Macintrash has a MACE (AV macintoshes) @@ -240,13 +251,8 @@ static int __devinit mace_probe(struct platform_device *pdev) return -ENODEV; } - dev->open = mace_open; - dev->stop = mace_close; - dev->hard_start_xmit = mace_xmit_start; - dev->tx_timeout = mace_tx_timeout; + dev->netdev_ops = &mace_netdev_ops; dev->watchdog_timeo = TX_TIMEOUT; - dev->set_multicast_list = mace_set_multicast; - dev->set_mac_address = mace_set_address; printk(KERN_INFO "%s: 68K MACE, hardware address %pM\n", dev->name, dev->dev_addr); diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 214a8cf2b708..99eed9f37c84 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -232,7 +232,7 @@ static int macvlan_open(struct net_device *dev) if (macvlan_addr_busy(vlan->port, dev->dev_addr)) goto out; - err = dev_unicast_add(lowerdev, dev->dev_addr, ETH_ALEN); + err = dev_unicast_add(lowerdev, dev->dev_addr); if (err < 0) goto out; if (dev->flags & IFF_ALLMULTI) { @@ -244,7 +244,7 @@ static int macvlan_open(struct net_device *dev) return 0; del_unicast: - dev_unicast_delete(lowerdev, dev->dev_addr, ETH_ALEN); + dev_unicast_delete(lowerdev, dev->dev_addr); out: return err; } @@ -258,7 +258,7 @@ static int macvlan_stop(struct net_device *dev) if (dev->flags & IFF_ALLMULTI) dev_set_allmulti(lowerdev, -1); - dev_unicast_delete(lowerdev, dev->dev_addr, ETH_ALEN); + dev_unicast_delete(lowerdev, dev->dev_addr); macvlan_hash_del(vlan); return 0; @@ -282,10 +282,11 @@ static int macvlan_set_mac_address(struct net_device *dev, void *p) if (macvlan_addr_busy(vlan->port, addr->sa_data)) return -EBUSY; - if ((err = dev_unicast_add(lowerdev, addr->sa_data, ETH_ALEN))) + err = dev_unicast_add(lowerdev, addr->sa_data); + if (err) return err; - dev_unicast_delete(lowerdev, dev->dev_addr, ETH_ALEN); + dev_unicast_delete(lowerdev, dev->dev_addr); macvlan_hash_change_addr(vlan, addr->sa_data); } @@ -358,6 +359,7 @@ static int macvlan_init(struct net_device *dev) (lowerdev->state & MACVLAN_STATE_MASK); dev->features = lowerdev->features & MACVLAN_FEATURES; dev->iflink = lowerdev->ifindex; + dev->hard_header_len = lowerdev->hard_header_len; macvlan_set_lockdep_class(dev); @@ -374,36 +376,20 @@ static void macvlan_ethtool_get_drvinfo(struct net_device *dev, static u32 macvlan_ethtool_get_rx_csum(struct net_device *dev) { const struct macvlan_dev *vlan = netdev_priv(dev); - struct net_device *lowerdev = vlan->lowerdev; - - if (lowerdev->ethtool_ops == NULL || - lowerdev->ethtool_ops->get_rx_csum == NULL) - return 0; - return lowerdev->ethtool_ops->get_rx_csum(lowerdev); + return dev_ethtool_get_rx_csum(vlan->lowerdev); } static int macvlan_ethtool_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { const struct macvlan_dev *vlan = netdev_priv(dev); - struct net_device *lowerdev = vlan->lowerdev; - - if (!lowerdev->ethtool_ops || - !lowerdev->ethtool_ops->get_settings) - return -EOPNOTSUPP; - - return lowerdev->ethtool_ops->get_settings(lowerdev, cmd); + return dev_ethtool_get_settings(vlan->lowerdev, cmd); } static u32 macvlan_ethtool_get_flags(struct net_device *dev) { const struct macvlan_dev *vlan = netdev_priv(dev); - struct net_device *lowerdev = vlan->lowerdev; - - if (!lowerdev->ethtool_ops || - !lowerdev->ethtool_ops->get_flags) - return 0; - return lowerdev->ethtool_ops->get_flags(lowerdev); + return dev_ethtool_get_flags(vlan->lowerdev); } static const struct ethtool_ops macvlan_ethtool_ops = { @@ -430,6 +416,7 @@ static void macvlan_setup(struct net_device *dev) { ether_setup(dev); + dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; dev->netdev_ops = &macvlan_netdev_ops; dev->destructor = free_netdev; dev->header_ops = &macvlan_hard_header_ops, diff --git a/drivers/net/mdio.c b/drivers/net/mdio.c new file mode 100644 index 000000000000..dc45e9856c35 --- /dev/null +++ b/drivers/net/mdio.c @@ -0,0 +1,431 @@ +/* + * mdio.c: Generic support for MDIO-compatible transceivers + * Copyright 2006-2009 Solarflare Communications Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, incorporated herein by reference. + */ + +#include +#include +#include +#include +#include +#include + +/** + * mdio45_probe - probe for an MDIO (clause 45) device + * @mdio: MDIO interface + * @prtad: Expected PHY address + * + * This sets @prtad and @mmds in the MDIO interface if successful. + * Returns 0 on success, negative on error. + */ +int mdio45_probe(struct mdio_if_info *mdio, int prtad) +{ + int mmd, stat2, devs1, devs2; + + /* Assume PHY must have at least one of PMA/PMD, WIS, PCS, PHY + * XS or DTE XS; give up if none is present. */ + for (mmd = 1; mmd <= 5; mmd++) { + /* Is this MMD present? */ + stat2 = mdio->mdio_read(mdio->dev, prtad, mmd, MDIO_STAT2); + if (stat2 < 0 || + (stat2 & MDIO_STAT2_DEVPRST) != MDIO_STAT2_DEVPRST_VAL) + continue; + + /* It should tell us about all the other MMDs */ + devs1 = mdio->mdio_read(mdio->dev, prtad, mmd, MDIO_DEVS1); + devs2 = mdio->mdio_read(mdio->dev, prtad, mmd, MDIO_DEVS2); + if (devs1 < 0 || devs2 < 0) + continue; + + mdio->prtad = prtad; + mdio->mmds = devs1 | (devs2 << 16); + return 0; + } + + return -ENODEV; +} +EXPORT_SYMBOL(mdio45_probe); + +/** + * mdio_set_flag - set or clear flag in an MDIO register + * @mdio: MDIO interface + * @prtad: PHY address + * @devad: MMD address + * @addr: Register address + * @mask: Mask for flag (single bit set) + * @sense: New value of flag + * + * This debounces changes: it does not write the register if the flag + * already has the proper value. Returns 0 on success, negative on error. + */ +int mdio_set_flag(const struct mdio_if_info *mdio, + int prtad, int devad, u16 addr, int mask, + bool sense) +{ + int old_val = mdio->mdio_read(mdio->dev, prtad, devad, addr); + int new_val; + + if (old_val < 0) + return old_val; + if (sense) + new_val = old_val | mask; + else + new_val = old_val & ~mask; + if (old_val == new_val) + return 0; + return mdio->mdio_write(mdio->dev, prtad, devad, addr, new_val); +} +EXPORT_SYMBOL(mdio_set_flag); + +/** + * mdio_link_ok - is link status up/OK + * @mdio: MDIO interface + * @mmd_mask: Mask for MMDs to check + * + * Returns 1 if the PHY reports link status up/OK, 0 otherwise. + * @mmd_mask is normally @mdio->mmds, but if loopback is enabled + * the MMDs being bypassed should be excluded from the mask. + */ +int mdio45_links_ok(const struct mdio_if_info *mdio, u32 mmd_mask) +{ + int devad, reg; + + if (!mmd_mask) { + /* Use absence of XGMII faults in lieu of link state */ + reg = mdio->mdio_read(mdio->dev, mdio->prtad, + MDIO_MMD_PHYXS, MDIO_STAT2); + return reg >= 0 && !(reg & MDIO_STAT2_RXFAULT); + } + + for (devad = 0; mmd_mask; devad++) { + if (mmd_mask & (1 << devad)) { + mmd_mask &= ~(1 << devad); + + /* Read twice because link state is latched and a + * read moves the current state into the register */ + mdio->mdio_read(mdio->dev, mdio->prtad, + devad, MDIO_STAT1); + reg = mdio->mdio_read(mdio->dev, mdio->prtad, + devad, MDIO_STAT1); + if (reg < 0 || !(reg & MDIO_STAT1_LSTATUS)) + return false; + } + } + + return true; +} +EXPORT_SYMBOL(mdio45_links_ok); + +/** + * mdio45_nway_restart - restart auto-negotiation for this interface + * @mdio: MDIO interface + * + * Returns 0 on success, negative on error. + */ +int mdio45_nway_restart(const struct mdio_if_info *mdio) +{ + if (!(mdio->mmds & MDIO_DEVS_AN)) + return -EOPNOTSUPP; + + mdio_set_flag(mdio, mdio->prtad, MDIO_MMD_AN, MDIO_CTRL1, + MDIO_AN_CTRL1_RESTART, true); + return 0; +} +EXPORT_SYMBOL(mdio45_nway_restart); + +static u32 mdio45_get_an(const struct mdio_if_info *mdio, u16 addr) +{ + u32 result = 0; + int reg; + + reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_AN, addr); + if (reg & ADVERTISE_10HALF) + result |= ADVERTISED_10baseT_Half; + if (reg & ADVERTISE_10FULL) + result |= ADVERTISED_10baseT_Full; + if (reg & ADVERTISE_100HALF) + result |= ADVERTISED_100baseT_Half; + if (reg & ADVERTISE_100FULL) + result |= ADVERTISED_100baseT_Full; + return result; +} + +/** + * mdio45_ethtool_gset_npage - get settings for ETHTOOL_GSET + * @mdio: MDIO interface + * @ecmd: Ethtool request structure + * @npage_adv: Modes currently advertised on next pages + * @npage_lpa: Modes advertised by link partner on next pages + * + * Since the CSRs for auto-negotiation using next pages are not fully + * standardised, this function does not attempt to decode them. The + * caller must pass them in. + */ +void mdio45_ethtool_gset_npage(const struct mdio_if_info *mdio, + struct ethtool_cmd *ecmd, + u32 npage_adv, u32 npage_lpa) +{ + int reg; + + ecmd->transceiver = XCVR_INTERNAL; + ecmd->phy_address = mdio->prtad; + ecmd->mdio_support = + mdio->mode_support & (MDIO_SUPPORTS_C45 | MDIO_SUPPORTS_C22); + + reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD, + MDIO_CTRL2); + switch (reg & MDIO_PMA_CTRL2_TYPE) { + case MDIO_PMA_CTRL2_10GBT: + case MDIO_PMA_CTRL2_1000BT: + case MDIO_PMA_CTRL2_100BTX: + case MDIO_PMA_CTRL2_10BT: + ecmd->port = PORT_TP; + ecmd->supported = SUPPORTED_TP; + reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD, + MDIO_SPEED); + if (reg & MDIO_SPEED_10G) + ecmd->supported |= SUPPORTED_10000baseT_Full; + if (reg & MDIO_PMA_SPEED_1000) + ecmd->supported |= (SUPPORTED_1000baseT_Full | + SUPPORTED_1000baseT_Half); + if (reg & MDIO_PMA_SPEED_100) + ecmd->supported |= (SUPPORTED_100baseT_Full | + SUPPORTED_100baseT_Half); + if (reg & MDIO_PMA_SPEED_10) + ecmd->supported |= (SUPPORTED_10baseT_Full | + SUPPORTED_10baseT_Half); + ecmd->advertising = ADVERTISED_TP; + break; + + case MDIO_PMA_CTRL2_10GBCX4: + ecmd->port = PORT_OTHER; + ecmd->supported = 0; + ecmd->advertising = 0; + break; + + case MDIO_PMA_CTRL2_10GBKX4: + case MDIO_PMA_CTRL2_10GBKR: + case MDIO_PMA_CTRL2_1000BKX: + ecmd->port = PORT_OTHER; + ecmd->supported = SUPPORTED_Backplane; + reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD, + MDIO_PMA_EXTABLE); + if (reg & MDIO_PMA_EXTABLE_10GBKX4) + ecmd->supported |= SUPPORTED_10000baseKX4_Full; + if (reg & MDIO_PMA_EXTABLE_10GBKR) + ecmd->supported |= SUPPORTED_10000baseKR_Full; + if (reg & MDIO_PMA_EXTABLE_1000BKX) + ecmd->supported |= SUPPORTED_1000baseKX_Full; + reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD, + MDIO_PMA_10GBR_FECABLE); + if (reg & MDIO_PMA_10GBR_FECABLE_ABLE) + ecmd->supported |= SUPPORTED_10000baseR_FEC; + ecmd->advertising = ADVERTISED_Backplane; + break; + + /* All the other defined modes are flavours of optical */ + default: + ecmd->port = PORT_FIBRE; + ecmd->supported = SUPPORTED_FIBRE; + ecmd->advertising = ADVERTISED_FIBRE; + break; + } + + if (mdio->mmds & MDIO_DEVS_AN) { + ecmd->supported |= SUPPORTED_Autoneg; + reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_AN, + MDIO_CTRL1); + if (reg & MDIO_AN_CTRL1_ENABLE) { + ecmd->autoneg = AUTONEG_ENABLE; + ecmd->advertising |= + ADVERTISED_Autoneg | + mdio45_get_an(mdio, MDIO_AN_ADVERTISE) | + npage_adv; + } else { + ecmd->autoneg = AUTONEG_DISABLE; + } + } else { + ecmd->autoneg = AUTONEG_DISABLE; + } + + if (ecmd->autoneg) { + u32 modes = 0; + int an_stat = mdio->mdio_read(mdio->dev, mdio->prtad, + MDIO_MMD_AN, MDIO_STAT1); + + /* If AN is complete and successful, report best common + * mode, otherwise report best advertised mode. */ + if (an_stat & MDIO_AN_STAT1_COMPLETE) { + ecmd->lp_advertising = + mdio45_get_an(mdio, MDIO_AN_LPA) | npage_lpa; + if (an_stat & MDIO_AN_STAT1_LPABLE) + ecmd->lp_advertising |= ADVERTISED_Autoneg; + modes = ecmd->advertising & ecmd->lp_advertising; + } + if ((modes & ~ADVERTISED_Autoneg) == 0) + modes = ecmd->advertising; + + if (modes & (ADVERTISED_10000baseT_Full | + ADVERTISED_10000baseKX4_Full | + ADVERTISED_10000baseKR_Full)) { + ecmd->speed = SPEED_10000; + ecmd->duplex = DUPLEX_FULL; + } else if (modes & (ADVERTISED_1000baseT_Full | + ADVERTISED_1000baseT_Half | + ADVERTISED_1000baseKX_Full)) { + ecmd->speed = SPEED_1000; + ecmd->duplex = !(modes & ADVERTISED_1000baseT_Half); + } else if (modes & (ADVERTISED_100baseT_Full | + ADVERTISED_100baseT_Half)) { + ecmd->speed = SPEED_100; + ecmd->duplex = !!(modes & ADVERTISED_100baseT_Full); + } else { + ecmd->speed = SPEED_10; + ecmd->duplex = !!(modes & ADVERTISED_10baseT_Full); + } + } else { + /* Report forced settings */ + reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD, + MDIO_CTRL1); + ecmd->speed = (((reg & MDIO_PMA_CTRL1_SPEED1000) ? 100 : 1) * + ((reg & MDIO_PMA_CTRL1_SPEED100) ? 100 : 10)); + ecmd->duplex = (reg & MDIO_CTRL1_FULLDPLX || + ecmd->speed == SPEED_10000); + } + + /* 10GBASE-T MDI/MDI-X */ + if (ecmd->port == PORT_TP && ecmd->speed == SPEED_10000) { + switch (mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD, + MDIO_PMA_10GBT_SWAPPOL)) { + case MDIO_PMA_10GBT_SWAPPOL_ABNX | MDIO_PMA_10GBT_SWAPPOL_CDNX: + ecmd->eth_tp_mdix = ETH_TP_MDI; + break; + case 0: + ecmd->eth_tp_mdix = ETH_TP_MDI_X; + break; + default: + /* It's complicated... */ + ecmd->eth_tp_mdix = ETH_TP_MDI_INVALID; + break; + } + } +} +EXPORT_SYMBOL(mdio45_ethtool_gset_npage); + +/** + * mdio45_ethtool_spauseparam_an - set auto-negotiated pause parameters + * @mdio: MDIO interface + * @ecmd: Ethtool request structure + * + * This function assumes that the PHY has an auto-negotiation MMD. It + * will enable and disable advertising of flow control as appropriate. + */ +void mdio45_ethtool_spauseparam_an(const struct mdio_if_info *mdio, + const struct ethtool_pauseparam *ecmd) +{ + int adv, old_adv; + + WARN_ON(!(mdio->mmds & MDIO_DEVS_AN)); + + old_adv = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_AN, + MDIO_AN_ADVERTISE); + adv = old_adv & ~(ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); + if (ecmd->autoneg) + adv |= mii_advertise_flowctrl( + (ecmd->rx_pause ? FLOW_CTRL_RX : 0) | + (ecmd->tx_pause ? FLOW_CTRL_TX : 0)); + if (adv != old_adv) { + mdio->mdio_write(mdio->dev, mdio->prtad, MDIO_MMD_AN, + MDIO_AN_ADVERTISE, adv); + mdio45_nway_restart(mdio); + } +} +EXPORT_SYMBOL(mdio45_ethtool_spauseparam_an); + +/** + * mdio_mii_ioctl - MII ioctl interface for MDIO (clause 22 or 45) PHYs + * @mdio: MDIO interface + * @mii_data: MII ioctl data structure + * @cmd: MII ioctl command + * + * Returns 0 on success, negative on error. + */ +int mdio_mii_ioctl(const struct mdio_if_info *mdio, + struct mii_ioctl_data *mii_data, int cmd) +{ + int prtad, devad; + u16 addr = mii_data->reg_num; + + /* Validate/convert cmd to one of SIOC{G,S}MIIREG */ + switch (cmd) { + case SIOCGMIIPHY: + if (mdio->prtad == MDIO_PRTAD_NONE) + return -EOPNOTSUPP; + mii_data->phy_id = mdio->prtad; + cmd = SIOCGMIIREG; + break; + case SIOCGMIIREG: + break; + case SIOCSMIIREG: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + break; + default: + return -EOPNOTSUPP; + } + + /* Validate/convert phy_id */ + if ((mdio->mode_support & MDIO_SUPPORTS_C45) && + mdio_phy_id_is_c45(mii_data->phy_id)) { + prtad = mdio_phy_id_prtad(mii_data->phy_id); + devad = mdio_phy_id_devad(mii_data->phy_id); + } else if ((mdio->mode_support & MDIO_SUPPORTS_C22) && + mii_data->phy_id < 0x20) { + prtad = mii_data->phy_id; + devad = MDIO_DEVAD_NONE; + addr &= 0x1f; + } else if ((mdio->mode_support & MDIO_EMULATE_C22) && + mdio->prtad != MDIO_PRTAD_NONE && + mii_data->phy_id == mdio->prtad) { + /* Remap commonly-used MII registers. */ + prtad = mdio->prtad; + switch (addr) { + case MII_BMCR: + case MII_BMSR: + case MII_PHYSID1: + case MII_PHYSID2: + devad = __ffs(mdio->mmds); + break; + case MII_ADVERTISE: + case MII_LPA: + if (!(mdio->mmds & MDIO_DEVS_AN)) + return -EINVAL; + devad = MDIO_MMD_AN; + if (addr == MII_ADVERTISE) + addr = MDIO_AN_ADVERTISE; + else + addr = MDIO_AN_LPA; + break; + default: + return -EINVAL; + } + } else { + return -EINVAL; + } + + if (cmd == SIOCGMIIREG) { + int rc = mdio->mdio_read(mdio->dev, prtad, devad, addr); + if (rc < 0) + return rc; + mii_data->val_out = rc; + return 0; + } else { + return mdio->mdio_write(mdio->dev, prtad, devad, addr, + mii_data->val_in); + } +} +EXPORT_SYMBOL(mdio_mii_ioctl); diff --git a/drivers/net/meth.c b/drivers/net/meth.c index dbd3436912b8..5d04d94f2a21 100644 --- a/drivers/net/meth.c +++ b/drivers/net/meth.c @@ -770,9 +770,17 @@ static int meth_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) } } -/* - * Return statistics to the caller - */ +static const struct net_device_ops meth_netdev_ops = { + .ndo_open = meth_open, + .ndo_stop = meth_release, + .ndo_start_xmit = meth_tx, + .ndo_do_ioctl = meth_ioctl, + .ndo_tx_timeout = meth_tx_timeout, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, +}; + /* * The init function. */ @@ -786,16 +794,10 @@ static int __init meth_probe(struct platform_device *pdev) if (!dev) return -ENOMEM; - dev->open = meth_open; - dev->stop = meth_release; - dev->hard_start_xmit = meth_tx; - dev->do_ioctl = meth_ioctl; -#ifdef HAVE_TX_TIMEOUT - dev->tx_timeout = meth_tx_timeout; - dev->watchdog_timeo = timeout; -#endif - dev->irq = MACE_ETHERNET_IRQ; - dev->base_addr = (unsigned long)&mace->eth; + dev->netdev_ops = &meth_netdev_ops; + dev->watchdog_timeo = timeout; + dev->irq = MACE_ETHERNET_IRQ; + dev->base_addr = (unsigned long)&mace->eth; memcpy(dev->dev_addr, o2meth_eaddr, 6); priv = netdev_priv(dev); diff --git a/drivers/net/mii.c b/drivers/net/mii.c index 92056051f269..d81a5d22a3a9 100644 --- a/drivers/net/mii.c +++ b/drivers/net/mii.c @@ -31,7 +31,27 @@ #include #include #include -#include +#include + +static u32 mii_get_an(struct mii_if_info *mii, u16 addr) +{ + u32 result = 0; + int advert; + + advert = mii->mdio_read(mii->dev, mii->phy_id, addr); + if (advert & LPA_LPACK) + result |= ADVERTISED_Autoneg; + if (advert & ADVERTISE_10HALF) + result |= ADVERTISED_10baseT_Half; + if (advert & ADVERTISE_10FULL) + result |= ADVERTISED_10baseT_Full; + if (advert & ADVERTISE_100HALF) + result |= ADVERTISED_100baseT_Half; + if (advert & ADVERTISE_100FULL) + result |= ADVERTISED_100baseT_Full; + + return result; +} /** * mii_ethtool_gset - get settings that are specified in @ecmd @@ -43,8 +63,8 @@ int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) { struct net_device *dev = mii->dev; - u32 advert, bmcr, lpa, nego; - u32 advert2 = 0, bmcr2 = 0, lpa2 = 0; + u16 bmcr, bmsr, ctrl1000 = 0, stat1000 = 0; + u32 nego; ecmd->supported = (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | @@ -62,50 +82,51 @@ int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) /* this isn't fully supported at higher layers */ ecmd->phy_address = mii->phy_id; + ecmd->mdio_support = MDIO_SUPPORTS_C22; ecmd->advertising = ADVERTISED_TP | ADVERTISED_MII; - advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE); - if (mii->supports_gmii) - advert2 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000); - - if (advert & ADVERTISE_10HALF) - ecmd->advertising |= ADVERTISED_10baseT_Half; - if (advert & ADVERTISE_10FULL) - ecmd->advertising |= ADVERTISED_10baseT_Full; - if (advert & ADVERTISE_100HALF) - ecmd->advertising |= ADVERTISED_100baseT_Half; - if (advert & ADVERTISE_100FULL) - ecmd->advertising |= ADVERTISED_100baseT_Full; - if (advert2 & ADVERTISE_1000HALF) - ecmd->advertising |= ADVERTISED_1000baseT_Half; - if (advert2 & ADVERTISE_1000FULL) - ecmd->advertising |= ADVERTISED_1000baseT_Full; bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR); - lpa = mii->mdio_read(dev, mii->phy_id, MII_LPA); + bmsr = mii->mdio_read(dev, mii->phy_id, MII_BMSR); if (mii->supports_gmii) { - bmcr2 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000); - lpa2 = mii->mdio_read(dev, mii->phy_id, MII_STAT1000); + ctrl1000 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000); + stat1000 = mii->mdio_read(dev, mii->phy_id, MII_STAT1000); } if (bmcr & BMCR_ANENABLE) { ecmd->advertising |= ADVERTISED_Autoneg; ecmd->autoneg = AUTONEG_ENABLE; - nego = mii_nway_result(advert & lpa); - if ((bmcr2 & (ADVERTISE_1000HALF | ADVERTISE_1000FULL)) & - (lpa2 >> 2)) - ecmd->speed = SPEED_1000; - else if (nego == LPA_100FULL || nego == LPA_100HALF) - ecmd->speed = SPEED_100; - else - ecmd->speed = SPEED_10; - if ((lpa2 & LPA_1000FULL) || nego == LPA_100FULL || - nego == LPA_10FULL) { - ecmd->duplex = DUPLEX_FULL; - mii->full_duplex = 1; + ecmd->advertising |= mii_get_an(mii, MII_ADVERTISE); + if (ctrl1000 & ADVERTISE_1000HALF) + ecmd->advertising |= ADVERTISED_1000baseT_Half; + if (ctrl1000 & ADVERTISE_1000FULL) + ecmd->advertising |= ADVERTISED_1000baseT_Full; + + if (bmsr & BMSR_ANEGCOMPLETE) { + ecmd->lp_advertising = mii_get_an(mii, MII_LPA); + if (stat1000 & LPA_1000HALF) + ecmd->lp_advertising |= + ADVERTISED_1000baseT_Half; + if (stat1000 & LPA_1000FULL) + ecmd->lp_advertising |= + ADVERTISED_1000baseT_Full; } else { - ecmd->duplex = DUPLEX_HALF; - mii->full_duplex = 0; + ecmd->lp_advertising = 0; + } + + nego = ecmd->advertising & ecmd->lp_advertising; + + if (nego & (ADVERTISED_1000baseT_Full | + ADVERTISED_1000baseT_Half)) { + ecmd->speed = SPEED_1000; + ecmd->duplex = !!(nego & ADVERTISED_1000baseT_Full); + } else if (nego & (ADVERTISED_100baseT_Full | + ADVERTISED_100baseT_Half)) { + ecmd->speed = SPEED_100; + ecmd->duplex = !!(nego & ADVERTISED_100baseT_Full); + } else { + ecmd->speed = SPEED_10; + ecmd->duplex = !!(nego & ADVERTISED_10baseT_Full); } } else { ecmd->autoneg = AUTONEG_DISABLE; @@ -116,6 +137,8 @@ int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) ecmd->duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF; } + mii->full_duplex = ecmd->duplex; + /* ignore maxtxpkt, maxrxpkt for now */ return 0; diff --git a/drivers/net/mipsnet.c b/drivers/net/mipsnet.c index 664835b822fb..b3b9a147d09a 100644 --- a/drivers/net/mipsnet.c +++ b/drivers/net/mipsnet.c @@ -237,6 +237,16 @@ static void mipsnet_set_mclist(struct net_device *dev) { } +static const struct net_device_ops mipsnet_netdev_ops = { + .ndo_open = mipsnet_open, + .ndo_stop = mipsnet_close, + .ndo_start_xmit = mipsnet_xmit, + .ndo_set_multicast_list = mipsnet_set_mclist, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, +}; + static int __init mipsnet_probe(struct platform_device *dev) { struct net_device *netdev; @@ -250,10 +260,7 @@ static int __init mipsnet_probe(struct platform_device *dev) platform_set_drvdata(dev, netdev); - netdev->open = mipsnet_open; - netdev->stop = mipsnet_close; - netdev->hard_start_xmit = mipsnet_xmit; - netdev->set_multicast_list = mipsnet_set_mclist; + netdev->netdev_ops = &mipsnet_netdev_ops; /* * TODO: probe for these or load them from PARAM diff --git a/drivers/net/mlx4/Makefile b/drivers/net/mlx4/Makefile index 21040a0d81fe..1fd068e1d930 100644 --- a/drivers/net/mlx4/Makefile +++ b/drivers/net/mlx4/Makefile @@ -5,5 +5,5 @@ mlx4_core-y := alloc.o catas.o cmd.o cq.o eq.o fw.o icm.o intf.o main.o mcg.o \ obj-$(CONFIG_MLX4_EN) += mlx4_en.o -mlx4_en-y := en_main.o en_tx.o en_rx.o en_params.o en_port.o en_cq.o \ +mlx4_en-y := en_main.o en_tx.o en_rx.o en_ethtool.o en_port.o en_cq.o \ en_resources.o en_netdev.o diff --git a/drivers/net/mlx4/en_cq.c b/drivers/net/mlx4/en_cq.c index a276125b709b..21786ad4455e 100644 --- a/drivers/net/mlx4/en_cq.c +++ b/drivers/net/mlx4/en_cq.c @@ -89,6 +89,9 @@ int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq) *cq->mcq.arm_db = 0; memset(cq->buf, 0, cq->buf_size); + if (!cq->is_tx) + cq->size = priv->rx_ring[cq->ring].actual_size; + err = mlx4_cq_alloc(mdev->dev, cq->size, &cq->wqres.mtt, &mdev->priv_uar, cq->wqres.db.dma, &cq->mcq, cq->vector, cq->is_tx); if (err) diff --git a/drivers/net/mlx4/en_params.c b/drivers/net/mlx4/en_ethtool.c similarity index 86% rename from drivers/net/mlx4/en_params.c rename to drivers/net/mlx4/en_ethtool.c index c1bd040b9e05..091f99052c91 100644 --- a/drivers/net/mlx4/en_params.c +++ b/drivers/net/mlx4/en_ethtool.c @@ -38,64 +38,6 @@ #include "mlx4_en.h" #include "en_port.h" -#define MLX4_EN_PARM_INT(X, def_val, desc) \ - static unsigned int X = def_val;\ - module_param(X , uint, 0444); \ - MODULE_PARM_DESC(X, desc); - - -/* - * Device scope module parameters - */ - - -/* Use a XOR rathern than Toeplitz hash function for RSS */ -MLX4_EN_PARM_INT(rss_xor, 0, "Use XOR hash function for RSS"); - -/* RSS hash type mask - default to */ -MLX4_EN_PARM_INT(rss_mask, 0xf, "RSS hash type bitmask"); - -/* Number of LRO sessions per Rx ring (rounded up to a power of two) */ -MLX4_EN_PARM_INT(num_lro, MLX4_EN_MAX_LRO_DESCRIPTORS, - "Number of LRO sessions per ring or disabled (0)"); - -/* Priority pausing */ -MLX4_EN_PARM_INT(pfctx, 0, "Priority based Flow Control policy on TX[7:0]." - " Per priority bit mask"); -MLX4_EN_PARM_INT(pfcrx, 0, "Priority based Flow Control policy on RX[7:0]." - " Per priority bit mask"); - -int mlx4_en_get_profile(struct mlx4_en_dev *mdev) -{ - struct mlx4_en_profile *params = &mdev->profile; - int i; - - params->rss_xor = (rss_xor != 0); - params->rss_mask = rss_mask & 0x1f; - params->num_lro = min_t(int, num_lro , MLX4_EN_MAX_LRO_DESCRIPTORS); - for (i = 1; i <= MLX4_MAX_PORTS; i++) { - params->prof[i].rx_pause = 1; - params->prof[i].rx_ppp = pfcrx; - params->prof[i].tx_pause = 1; - params->prof[i].tx_ppp = pfctx; - params->prof[i].tx_ring_size = MLX4_EN_DEF_TX_RING_SIZE; - params->prof[i].rx_ring_size = MLX4_EN_DEF_RX_RING_SIZE; - } - if (pfcrx || pfctx) { - params->prof[1].tx_ring_num = MLX4_EN_TX_RING_NUM; - params->prof[2].tx_ring_num = MLX4_EN_TX_RING_NUM; - } else { - params->prof[1].tx_ring_num = 1; - params->prof[2].tx_ring_num = 1; - } - - return 0; -} - - -/* - * Ethtool support - */ static void mlx4_en_update_lro_stats(struct mlx4_en_priv *priv) { @@ -326,8 +268,7 @@ static int mlx4_en_set_coalesce(struct net_device *dev, priv->rx_frames = (coal->rx_max_coalesced_frames == MLX4_EN_AUTO_CONF) ? - MLX4_EN_RX_COAL_TARGET / - priv->dev->mtu + 1 : + MLX4_EN_RX_COAL_TARGET : coal->rx_max_coalesced_frames; priv->rx_usecs = (coal->rx_coalesce_usecs == MLX4_EN_AUTO_CONF) ? @@ -371,7 +312,7 @@ static int mlx4_en_set_pauseparam(struct net_device *dev, priv->prof->rx_pause, priv->prof->rx_ppp); if (err) - mlx4_err(mdev, "Failed setting pause params to\n"); + en_err(priv, "Failed setting pause params\n"); return err; } @@ -421,13 +362,13 @@ static int mlx4_en_set_ringparam(struct net_device *dev, err = mlx4_en_alloc_resources(priv); if (err) { - mlx4_err(mdev, "Failed reallocating port resources\n"); + en_err(priv, "Failed reallocating port resources\n"); goto out; } if (port_up) { err = mlx4_en_start_port(dev); if (err) - mlx4_err(mdev, "Failed starting port\n"); + en_err(priv, "Failed starting port\n"); } out: diff --git a/drivers/net/mlx4/en_main.c b/drivers/net/mlx4/en_main.c index 510633fd57f6..9ed4a158f895 100644 --- a/drivers/net/mlx4/en_main.c +++ b/drivers/net/mlx4/en_main.c @@ -51,6 +51,55 @@ static const char mlx4_en_version[] = DRV_NAME ": Mellanox ConnectX HCA Ethernet driver v" DRV_VERSION " (" DRV_RELDATE ")\n"; +#define MLX4_EN_PARM_INT(X, def_val, desc) \ + static unsigned int X = def_val;\ + module_param(X , uint, 0444); \ + MODULE_PARM_DESC(X, desc); + + +/* + * Device scope module parameters + */ + + +/* Use a XOR rathern than Toeplitz hash function for RSS */ +MLX4_EN_PARM_INT(rss_xor, 0, "Use XOR hash function for RSS"); + +/* RSS hash type mask - default to */ +MLX4_EN_PARM_INT(rss_mask, 0xf, "RSS hash type bitmask"); + +/* Number of LRO sessions per Rx ring (rounded up to a power of two) */ +MLX4_EN_PARM_INT(num_lro, MLX4_EN_MAX_LRO_DESCRIPTORS, + "Number of LRO sessions per ring or disabled (0)"); + +/* Priority pausing */ +MLX4_EN_PARM_INT(pfctx, 0, "Priority based Flow Control policy on TX[7:0]." + " Per priority bit mask"); +MLX4_EN_PARM_INT(pfcrx, 0, "Priority based Flow Control policy on RX[7:0]." + " Per priority bit mask"); + +static int mlx4_en_get_profile(struct mlx4_en_dev *mdev) +{ + struct mlx4_en_profile *params = &mdev->profile; + int i; + + params->rss_xor = (rss_xor != 0); + params->rss_mask = rss_mask & 0x1f; + params->num_lro = min_t(int, num_lro , MLX4_EN_MAX_LRO_DESCRIPTORS); + for (i = 1; i <= MLX4_MAX_PORTS; i++) { + params->prof[i].rx_pause = 1; + params->prof[i].rx_ppp = pfcrx; + params->prof[i].tx_pause = 1; + params->prof[i].tx_ppp = pfctx; + params->prof[i].tx_ring_size = MLX4_EN_DEF_TX_RING_SIZE; + params->prof[i].rx_ring_size = MLX4_EN_DEF_RX_RING_SIZE; + params->prof[i].tx_ring_num = MLX4_EN_NUM_TX_RINGS + + (!!pfcrx) * MLX4_EN_NUM_PPP_RINGS; + } + + return 0; +} + static void mlx4_en_event(struct mlx4_dev *dev, void *endev_ptr, enum mlx4_dev_event event, int port) { @@ -194,28 +243,11 @@ static void *mlx4_en_add(struct mlx4_dev *dev) /* Create a netdev for each port */ mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) { mlx4_info(mdev, "Activating port:%d\n", i); - if (mlx4_en_init_netdev(mdev, i, &mdev->profile.prof[i])) { + if (mlx4_en_init_netdev(mdev, i, &mdev->profile.prof[i])) mdev->pndev[i] = NULL; - goto err_free_netdev; - } } return mdev; - -err_free_netdev: - mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) { - if (mdev->pndev[i]) - mlx4_en_destroy_netdev(mdev->pndev[i]); - } - - mutex_lock(&mdev->state_lock); - mdev->device_up = false; - mutex_unlock(&mdev->state_lock); - flush_workqueue(mdev->workqueue); - - /* Stop event queue before we drop down to release shared SW state */ - destroy_workqueue(mdev->workqueue); - err_mr: mlx4_mr_free(dev, &mdev->mr); err_uar: diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c index 7bcc49de1637..93f4abd990a9 100644 --- a/drivers/net/mlx4/en_netdev.c +++ b/drivers/net/mlx4/en_netdev.c @@ -51,14 +51,14 @@ static void mlx4_en_vlan_rx_register(struct net_device *dev, struct vlan_group * struct mlx4_en_dev *mdev = priv->mdev; int err; - mlx4_dbg(HW, priv, "Registering VLAN group:%p\n", grp); + en_dbg(HW, priv, "Registering VLAN group:%p\n", grp); priv->vlgrp = grp; mutex_lock(&mdev->state_lock); if (mdev->device_up && priv->port_up) { err = mlx4_SET_VLAN_FLTR(mdev->dev, priv->port, grp); if (err) - mlx4_err(mdev, "Failed configuring VLAN filter\n"); + en_err(priv, "Failed configuring VLAN filter\n"); } mutex_unlock(&mdev->state_lock); } @@ -72,15 +72,15 @@ static void mlx4_en_vlan_rx_add_vid(struct net_device *dev, unsigned short vid) if (!priv->vlgrp) return; - mlx4_dbg(HW, priv, "adding VLAN:%d (vlgrp entry:%p)\n", - vid, vlan_group_get_device(priv->vlgrp, vid)); + en_dbg(HW, priv, "adding VLAN:%d (vlgrp entry:%p)\n", + vid, vlan_group_get_device(priv->vlgrp, vid)); /* Add VID to port VLAN filter */ mutex_lock(&mdev->state_lock); if (mdev->device_up && priv->port_up) { err = mlx4_SET_VLAN_FLTR(mdev->dev, priv->port, priv->vlgrp); if (err) - mlx4_err(mdev, "Failed configuring VLAN filter\n"); + en_err(priv, "Failed configuring VLAN filter\n"); } mutex_unlock(&mdev->state_lock); } @@ -94,9 +94,8 @@ static void mlx4_en_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) if (!priv->vlgrp) return; - mlx4_dbg(HW, priv, "Killing VID:%d (vlgrp:%p vlgrp " - "entry:%p)\n", vid, priv->vlgrp, - vlan_group_get_device(priv->vlgrp, vid)); + en_dbg(HW, priv, "Killing VID:%d (vlgrp:%p vlgrp entry:%p)\n", + vid, priv->vlgrp, vlan_group_get_device(priv->vlgrp, vid)); vlan_group_set_device(priv->vlgrp, vid, NULL); /* Remove VID from port VLAN filter */ @@ -104,7 +103,7 @@ static void mlx4_en_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) if (mdev->device_up && priv->port_up) { err = mlx4_SET_VLAN_FLTR(mdev->dev, priv->port, priv->vlgrp); if (err) - mlx4_err(mdev, "Failed configuring VLAN filter\n"); + en_err(priv, "Failed configuring VLAN filter\n"); } mutex_unlock(&mdev->state_lock); } @@ -150,9 +149,10 @@ static void mlx4_en_do_set_mac(struct work_struct *work) err = mlx4_register_mac(mdev->dev, priv->port, priv->mac, &priv->mac_index); if (err) - mlx4_err(mdev, "Failed changing HW MAC address\n"); + en_err(priv, "Failed changing HW MAC address\n"); } else - mlx4_dbg(HW, priv, "Port is down, exiting...\n"); + en_dbg(HW, priv, "Port is down while " + "registering mac, exiting...\n"); mutex_unlock(&mdev->state_lock); } @@ -174,7 +174,6 @@ static void mlx4_en_clear_list(struct net_device *dev) static void mlx4_en_cache_mclist(struct net_device *dev) { struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_en_dev *mdev = priv->mdev; struct dev_mc_list *mclist; struct dev_mc_list *tmp; struct dev_mc_list *plist = NULL; @@ -182,7 +181,7 @@ static void mlx4_en_cache_mclist(struct net_device *dev) for (mclist = dev->mc_list; mclist; mclist = mclist->next) { tmp = kmalloc(sizeof(struct dev_mc_list), GFP_ATOMIC); if (!tmp) { - mlx4_err(mdev, "failed to allocate multicast list\n"); + en_err(priv, "failed to allocate multicast list\n"); mlx4_en_clear_list(dev); return; } @@ -219,13 +218,13 @@ static void mlx4_en_do_set_multicast(struct work_struct *work) mutex_lock(&mdev->state_lock); if (!mdev->device_up) { - mlx4_dbg(HW, priv, "Card is not up, ignoring " - "multicast change.\n"); + en_dbg(HW, priv, "Card is not up, " + "ignoring multicast change.\n"); goto out; } if (!priv->port_up) { - mlx4_dbg(HW, priv, "Port is down, ignoring " - "multicast change.\n"); + en_dbg(HW, priv, "Port is down, " + "ignoring multicast change.\n"); goto out; } @@ -236,29 +235,27 @@ static void mlx4_en_do_set_multicast(struct work_struct *work) if (dev->flags & IFF_PROMISC) { if (!(priv->flags & MLX4_EN_FLAG_PROMISC)) { if (netif_msg_rx_status(priv)) - mlx4_warn(mdev, "Port:%d entering promiscuous mode\n", - priv->port); + en_warn(priv, "Entering promiscuous mode\n"); priv->flags |= MLX4_EN_FLAG_PROMISC; /* Enable promiscouos mode */ err = mlx4_SET_PORT_qpn_calc(mdev->dev, priv->port, priv->base_qpn, 1); if (err) - mlx4_err(mdev, "Failed enabling " - "promiscous mode\n"); + en_err(priv, "Failed enabling " + "promiscous mode\n"); /* Disable port multicast filter (unconditionally) */ err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, 0, MLX4_MCAST_DISABLE); if (err) - mlx4_err(mdev, "Failed disabling " - "multicast filter\n"); + en_err(priv, "Failed disabling " + "multicast filter\n"); /* Disable port VLAN filter */ err = mlx4_SET_VLAN_FLTR(mdev->dev, priv->port, NULL); if (err) - mlx4_err(mdev, "Failed disabling " - "VLAN filter\n"); + en_err(priv, "Failed disabling VLAN filter\n"); } goto out; } @@ -269,20 +266,19 @@ static void mlx4_en_do_set_multicast(struct work_struct *work) if (priv->flags & MLX4_EN_FLAG_PROMISC) { if (netif_msg_rx_status(priv)) - mlx4_warn(mdev, "Port:%d leaving promiscuous mode\n", - priv->port); + en_warn(priv, "Leaving promiscuous mode\n"); priv->flags &= ~MLX4_EN_FLAG_PROMISC; /* Disable promiscouos mode */ err = mlx4_SET_PORT_qpn_calc(mdev->dev, priv->port, priv->base_qpn, 0); if (err) - mlx4_err(mdev, "Failed disabling promiscous mode\n"); + en_err(priv, "Failed disabling promiscous mode\n"); /* Enable port VLAN filter */ err = mlx4_SET_VLAN_FLTR(mdev->dev, priv->port, priv->vlgrp); if (err) - mlx4_err(mdev, "Failed enabling VLAN filter\n"); + en_err(priv, "Failed enabling VLAN filter\n"); } /* Enable/disable the multicast filter according to IFF_ALLMULTI */ @@ -290,12 +286,12 @@ static void mlx4_en_do_set_multicast(struct work_struct *work) err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, 0, MLX4_MCAST_DISABLE); if (err) - mlx4_err(mdev, "Failed disabling multicast filter\n"); + en_err(priv, "Failed disabling multicast filter\n"); } else { err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, 0, MLX4_MCAST_DISABLE); if (err) - mlx4_err(mdev, "Failed disabling multicast filter\n"); + en_err(priv, "Failed disabling multicast filter\n"); /* Flush mcast filter and init it with broadcast address */ mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, ETH_BCAST, @@ -314,7 +310,7 @@ static void mlx4_en_do_set_multicast(struct work_struct *work) err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, 0, MLX4_MCAST_ENABLE); if (err) - mlx4_err(mdev, "Failed enabling multicast filter\n"); + en_err(priv, "Failed enabling multicast filter\n"); mlx4_en_clear_list(dev); } @@ -346,10 +342,10 @@ static void mlx4_en_tx_timeout(struct net_device *dev) struct mlx4_en_dev *mdev = priv->mdev; if (netif_msg_timer(priv)) - mlx4_warn(mdev, "Tx timeout called on port:%d\n", priv->port); + en_warn(priv, "Tx timeout called on port:%d\n", priv->port); priv->port_stats.tx_timeout++; - mlx4_dbg(DRV, priv, "Scheduling watchdog\n"); + en_dbg(DRV, priv, "Scheduling watchdog\n"); queue_work(mdev->workqueue, &priv->watchdog_task); } @@ -371,15 +367,15 @@ static void mlx4_en_set_default_moderation(struct mlx4_en_priv *priv) int i; /* If we haven't received a specific coalescing setting - * (module param), we set the moderation paramters as follows: + * (module param), we set the moderation parameters as follows: * - moder_cnt is set to the number of mtu sized packets to * satisfy our coelsing target. * - moder_time is set to a fixed value. */ - priv->rx_frames = MLX4_EN_RX_COAL_TARGET / priv->dev->mtu + 1; + priv->rx_frames = MLX4_EN_RX_COAL_TARGET; priv->rx_usecs = MLX4_EN_RX_COAL_TIME; - mlx4_dbg(INTR, priv, "Default coalesing params for mtu:%d - " - "rx_frames:%d rx_usecs:%d\n", + en_dbg(INTR, priv, "Default coalesing params for mtu:%d - " + "rx_frames:%d rx_usecs:%d\n", priv->dev->mtu, priv->rx_frames, priv->rx_usecs); /* Setup cq moderation params */ @@ -412,7 +408,6 @@ static void mlx4_en_set_default_moderation(struct mlx4_en_priv *priv) static void mlx4_en_auto_moderation(struct mlx4_en_priv *priv) { unsigned long period = (unsigned long) (jiffies - priv->last_moder_jiffies); - struct mlx4_en_dev *mdev = priv->mdev; struct mlx4_en_cq *cq; unsigned long packets; unsigned long rate; @@ -472,11 +467,11 @@ static void mlx4_en_auto_moderation(struct mlx4_en_priv *priv) moder_time = priv->rx_usecs; } - mlx4_dbg(INTR, priv, "tx rate:%lu rx_rate:%lu\n", - tx_pkt_diff * HZ / period, rx_pkt_diff * HZ / period); + en_dbg(INTR, priv, "tx rate:%lu rx_rate:%lu\n", + tx_pkt_diff * HZ / period, rx_pkt_diff * HZ / period); - mlx4_dbg(INTR, priv, "Rx moder_time changed from:%d to %d period:%lu " - "[jiff] packets:%lu avg_pkt_size:%lu rate:%lu [p/s])\n", + en_dbg(INTR, priv, "Rx moder_time changed from:%d to %d period:%lu " + "[jiff] packets:%lu avg_pkt_size:%lu rate:%lu [p/s])\n", priv->last_moder_time, moder_time, period, packets, avg_pkt_size, rate); @@ -487,8 +482,7 @@ static void mlx4_en_auto_moderation(struct mlx4_en_priv *priv) cq->moder_time = moder_time; err = mlx4_en_set_cq_moder(priv, cq); if (err) { - mlx4_err(mdev, "Failed modifying moderation for cq:%d " - "on port:%d\n", i, priv->port); + en_err(priv, "Failed modifying moderation for cq:%d\n", i); break; } } @@ -511,8 +505,7 @@ static void mlx4_en_do_get_stats(struct work_struct *work) err = mlx4_en_DUMP_ETH_STATS(mdev, priv->port, 0); if (err) - mlx4_dbg(HW, priv, "Could not update stats for " - "port:%d\n", priv->port); + en_dbg(HW, priv, "Could not update stats \n"); mutex_lock(&mdev->state_lock); if (mdev->device_up) { @@ -536,12 +529,10 @@ static void mlx4_en_linkstate(struct work_struct *work) * report to system log */ if (priv->last_link_state != linkstate) { if (linkstate == MLX4_DEV_EVENT_PORT_DOWN) { - if (netif_msg_link(priv)) - mlx4_info(mdev, "Port %d - link down\n", priv->port); + en_dbg(LINK, priv, "Link Down\n"); netif_carrier_off(priv->dev); } else { - if (netif_msg_link(priv)) - mlx4_info(mdev, "Port %d - link up\n", priv->port); + en_dbg(LINK, priv, "Link Up\n"); netif_carrier_on(priv->dev); } } @@ -556,58 +547,53 @@ int mlx4_en_start_port(struct net_device *dev) struct mlx4_en_dev *mdev = priv->mdev; struct mlx4_en_cq *cq; struct mlx4_en_tx_ring *tx_ring; - struct mlx4_en_rx_ring *rx_ring; int rx_index = 0; int tx_index = 0; - u16 stride; int err = 0; int i; int j; if (priv->port_up) { - mlx4_dbg(DRV, priv, "start port called while port already up\n"); + en_dbg(DRV, priv, "start port called while port already up\n"); return 0; } /* Calculate Rx buf size */ dev->mtu = min(dev->mtu, priv->max_mtu); mlx4_en_calc_rx_buf(dev); - mlx4_dbg(DRV, priv, "Rx buf size:%d\n", priv->rx_skb_size); - stride = roundup_pow_of_two(sizeof(struct mlx4_en_rx_desc) + - DS_SIZE * priv->num_frags); + en_dbg(DRV, priv, "Rx buf size:%d\n", priv->rx_skb_size); + /* Configure rx cq's and rings */ + err = mlx4_en_activate_rx_rings(priv); + if (err) { + en_err(priv, "Failed to activate RX rings\n"); + return err; + } for (i = 0; i < priv->rx_ring_num; i++) { cq = &priv->rx_cq[i]; - rx_ring = &priv->rx_ring[i]; err = mlx4_en_activate_cq(priv, cq); if (err) { - mlx4_err(mdev, "Failed activating Rx CQ\n"); + en_err(priv, "Failed activating Rx CQ\n"); goto cq_err; } for (j = 0; j < cq->size; j++) cq->buf[j].owner_sr_opcode = MLX4_CQE_OWNER_MASK; err = mlx4_en_set_cq_moder(priv, cq); if (err) { - mlx4_err(mdev, "Failed setting cq moderation parameters"); + en_err(priv, "Failed setting cq moderation parameters"); mlx4_en_deactivate_cq(priv, cq); goto cq_err; } mlx4_en_arm_cq(priv, cq); - + priv->rx_ring[i].cqn = cq->mcq.cqn; ++rx_index; } - err = mlx4_en_activate_rx_rings(priv); - if (err) { - mlx4_err(mdev, "Failed to activate RX rings\n"); - goto cq_err; - } - err = mlx4_en_config_rss_steer(priv); if (err) { - mlx4_err(mdev, "Failed configuring rss steering\n"); - goto rx_err; + en_err(priv, "Failed configuring rss steering\n"); + goto cq_err; } /* Configure tx cq's and rings */ @@ -616,16 +602,16 @@ int mlx4_en_start_port(struct net_device *dev) cq = &priv->tx_cq[i]; err = mlx4_en_activate_cq(priv, cq); if (err) { - mlx4_err(mdev, "Failed allocating Tx CQ\n"); + en_err(priv, "Failed allocating Tx CQ\n"); goto tx_err; } err = mlx4_en_set_cq_moder(priv, cq); if (err) { - mlx4_err(mdev, "Failed setting cq moderation parameters"); + en_err(priv, "Failed setting cq moderation parameters"); mlx4_en_deactivate_cq(priv, cq); goto tx_err; } - mlx4_dbg(DRV, priv, "Resetting index of collapsed CQ:%d to -1\n", i); + en_dbg(DRV, priv, "Resetting index of collapsed CQ:%d to -1\n", i); cq->buf->wqe_index = cpu_to_be16(0xffff); /* Configure ring */ @@ -633,7 +619,7 @@ int mlx4_en_start_port(struct net_device *dev) err = mlx4_en_activate_tx_ring(priv, tx_ring, cq->mcq.cqn, priv->rx_ring[0].srq.srqn); if (err) { - mlx4_err(mdev, "Failed allocating Tx ring\n"); + en_err(priv, "Failed allocating Tx ring\n"); mlx4_en_deactivate_cq(priv, cq); goto tx_err; } @@ -651,30 +637,30 @@ int mlx4_en_start_port(struct net_device *dev) priv->prof->rx_pause, priv->prof->rx_ppp); if (err) { - mlx4_err(mdev, "Failed setting port general configurations" - " for port %d, with error %d\n", priv->port, err); + en_err(priv, "Failed setting port general configurations " + "for port %d, with error %d\n", priv->port, err); goto tx_err; } /* Set default qp number */ err = mlx4_SET_PORT_qpn_calc(mdev->dev, priv->port, priv->base_qpn, 0); if (err) { - mlx4_err(mdev, "Failed setting default qp numbers\n"); + en_err(priv, "Failed setting default qp numbers\n"); goto tx_err; } /* Set port mac number */ - mlx4_dbg(DRV, priv, "Setting mac for port %d\n", priv->port); + en_dbg(DRV, priv, "Setting mac for port %d\n", priv->port); err = mlx4_register_mac(mdev->dev, priv->port, priv->mac, &priv->mac_index); if (err) { - mlx4_err(mdev, "Failed setting port mac\n"); + en_err(priv, "Failed setting port mac\n"); goto tx_err; } /* Init port */ - mlx4_dbg(HW, priv, "Initializing port\n"); + en_dbg(HW, priv, "Initializing port\n"); err = mlx4_INIT_PORT(mdev->dev, priv->port); if (err) { - mlx4_err(mdev, "Failed Initializing port\n"); + en_err(priv, "Failed Initializing port\n"); goto mac_err; } @@ -682,7 +668,7 @@ int mlx4_en_start_port(struct net_device *dev) queue_work(mdev->workqueue, &priv->mcast_task); priv->port_up = true; - netif_start_queue(dev); + netif_tx_start_all_queues(dev); return 0; mac_err: @@ -694,12 +680,11 @@ tx_err: } mlx4_en_release_rss_steer(priv); -rx_err: - for (i = 0; i < priv->rx_ring_num; i++) - mlx4_en_deactivate_rx_ring(priv, &priv->rx_ring[i]); cq_err: while (rx_index--) mlx4_en_deactivate_cq(priv, &priv->rx_cq[rx_index]); + for (i = 0; i < priv->rx_ring_num; i++) + mlx4_en_deactivate_rx_ring(priv, &priv->rx_ring[i]); return err; /* need to close devices */ } @@ -712,18 +697,17 @@ void mlx4_en_stop_port(struct net_device *dev) int i; if (!priv->port_up) { - mlx4_dbg(DRV, priv, "stop port (%d) called while port already down\n", - priv->port); + en_dbg(DRV, priv, "stop port called while port already down\n"); return; } - netif_stop_queue(dev); /* Synchronize with tx routine */ netif_tx_lock_bh(dev); - priv->port_up = false; + netif_tx_stop_all_queues(dev); netif_tx_unlock_bh(dev); /* close port*/ + priv->port_up = false; mlx4_CLOSE_PORT(mdev->dev, priv->port); /* Unregister Mac address for the port */ @@ -758,13 +742,13 @@ static void mlx4_en_restart(struct work_struct *work) struct mlx4_en_dev *mdev = priv->mdev; struct net_device *dev = priv->dev; - mlx4_dbg(DRV, priv, "Watchdog task called for port %d\n", priv->port); + en_dbg(DRV, priv, "Watchdog task called for port %d\n", priv->port); mutex_lock(&mdev->state_lock); if (priv->port_up) { mlx4_en_stop_port(dev); if (mlx4_en_start_port(dev)) - mlx4_err(mdev, "Failed restarting port %d\n", priv->port); + en_err(priv, "Failed restarting port %d\n", priv->port); } mutex_unlock(&mdev->state_lock); } @@ -780,14 +764,14 @@ static int mlx4_en_open(struct net_device *dev) mutex_lock(&mdev->state_lock); if (!mdev->device_up) { - mlx4_err(mdev, "Cannot open - device down/disabled\n"); + en_err(priv, "Cannot open - device down/disabled\n"); err = -EBUSY; goto out; } /* Reset HW statistics and performance counters */ if (mlx4_en_DUMP_ETH_STATS(mdev, priv->port, 1)) - mlx4_dbg(HW, priv, "Failed dumping statistics\n"); + en_dbg(HW, priv, "Failed dumping statistics\n"); memset(&priv->stats, 0, sizeof(priv->stats)); memset(&priv->pstats, 0, sizeof(priv->pstats)); @@ -804,7 +788,7 @@ static int mlx4_en_open(struct net_device *dev) mlx4_en_set_default_moderation(priv); err = mlx4_en_start_port(dev); if (err) - mlx4_err(mdev, "Failed starting port:%d\n", priv->port); + en_err(priv, "Failed starting port:%d\n", priv->port); out: mutex_unlock(&mdev->state_lock); @@ -817,8 +801,7 @@ static int mlx4_en_close(struct net_device *dev) struct mlx4_en_priv *priv = netdev_priv(dev); struct mlx4_en_dev *mdev = priv->mdev; - if (netif_msg_ifdown(priv)) - mlx4_info(mdev, "Close called for port:%d\n", priv->port); + en_dbg(IFDOWN, priv, "Close port called\n"); mutex_lock(&mdev->state_lock); @@ -850,7 +833,6 @@ void mlx4_en_free_resources(struct mlx4_en_priv *priv) int mlx4_en_alloc_resources(struct mlx4_en_priv *priv) { - struct mlx4_en_dev *mdev = priv->mdev; struct mlx4_en_port_profile *prof = priv->prof; int i; @@ -879,7 +861,7 @@ int mlx4_en_alloc_resources(struct mlx4_en_priv *priv) return 0; err: - mlx4_err(mdev, "Failed to allocate NIC resources\n"); + en_err(priv, "Failed to allocate NIC resources\n"); return -ENOMEM; } @@ -889,7 +871,7 @@ void mlx4_en_destroy_netdev(struct net_device *dev) struct mlx4_en_priv *priv = netdev_priv(dev); struct mlx4_en_dev *mdev = priv->mdev; - mlx4_dbg(DRV, priv, "Destroying netdev on port:%d\n", priv->port); + en_dbg(DRV, priv, "Destroying netdev on port:%d\n", priv->port); /* Unregister device - this will close the port if it was up */ if (priv->registered) @@ -899,7 +881,6 @@ void mlx4_en_destroy_netdev(struct net_device *dev) mlx4_free_hwq_res(mdev->dev, &priv->res, MLX4_EN_PAGE_SIZE); cancel_delayed_work(&priv->stats_task); - cancel_delayed_work(&priv->refill_task); /* flush any pending task for this netdev */ flush_workqueue(mdev->workqueue); @@ -918,11 +899,11 @@ static int mlx4_en_change_mtu(struct net_device *dev, int new_mtu) struct mlx4_en_dev *mdev = priv->mdev; int err = 0; - mlx4_dbg(DRV, priv, "Change MTU called - current:%d new:%d\n", + en_dbg(DRV, priv, "Change MTU called - current:%d new:%d\n", dev->mtu, new_mtu); if ((new_mtu < MLX4_EN_MIN_MTU) || (new_mtu > priv->max_mtu)) { - mlx4_err(mdev, "Bad MTU size:%d.\n", new_mtu); + en_err(priv, "Bad MTU size:%d.\n", new_mtu); return -EPERM; } dev->mtu = new_mtu; @@ -932,13 +913,13 @@ static int mlx4_en_change_mtu(struct net_device *dev, int new_mtu) if (!mdev->device_up) { /* NIC is probably restarting - let watchdog task reset * the port */ - mlx4_dbg(DRV, priv, "Change MTU called with card down!?\n"); + en_dbg(DRV, priv, "Change MTU called with card down!?\n"); } else { mlx4_en_stop_port(dev); mlx4_en_set_default_moderation(priv); err = mlx4_en_start_port(dev); if (err) { - mlx4_err(mdev, "Failed restarting port:%d\n", + en_err(priv, "Failed restarting port:%d\n", priv->port); queue_work(mdev->workqueue, &priv->watchdog_task); } @@ -952,6 +933,7 @@ static const struct net_device_ops mlx4_netdev_ops = { .ndo_open = mlx4_en_open, .ndo_stop = mlx4_en_close, .ndo_start_xmit = mlx4_en_xmit, + .ndo_select_queue = mlx4_en_select_queue, .ndo_get_stats = mlx4_en_get_stats, .ndo_set_multicast_list = mlx4_en_set_multicast, .ndo_set_mac_address = mlx4_en_set_mac, @@ -974,7 +956,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, int i; int err; - dev = alloc_etherdev(sizeof(struct mlx4_en_priv)); + dev = alloc_etherdev_mq(sizeof(struct mlx4_en_priv), prof->tx_ring_num); if (dev == NULL) { mlx4_err(mdev, "Net device allocation failed\n"); return -ENOMEM; @@ -1003,7 +985,6 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, spin_lock_init(&priv->stats_lock); INIT_WORK(&priv->mcast_task, mlx4_en_do_set_multicast); INIT_WORK(&priv->mac_task, mlx4_en_do_set_mac); - INIT_DELAYED_WORK(&priv->refill_task, mlx4_en_rx_refill); INIT_WORK(&priv->watchdog_task, mlx4_en_restart); INIT_WORK(&priv->linkstate_task, mlx4_en_linkstate); INIT_DELAYED_WORK(&priv->stats_task, mlx4_en_do_get_stats); @@ -1012,7 +993,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, priv->max_mtu = mdev->dev->caps.eth_mtu_cap[priv->port]; priv->mac = mdev->dev->caps.def_mac[priv->port]; if (ILLEGAL_MAC(priv->mac)) { - mlx4_err(mdev, "Port: %d, invalid mac burned: 0x%llx, quiting\n", + en_err(priv, "Port: %d, invalid mac burned: 0x%llx, quiting\n", priv->port, priv->mac); err = -EINVAL; goto out; @@ -1031,19 +1012,17 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, err = mlx4_alloc_hwq_res(mdev->dev, &priv->res, MLX4_EN_PAGE_SIZE, MLX4_EN_PAGE_SIZE); if (err) { - mlx4_err(mdev, "Failed to allocate page for rx qps\n"); + en_err(priv, "Failed to allocate page for rx qps\n"); goto out; } priv->allocated = 1; - /* Populate Tx priority mappings */ - mlx4_en_set_prio_map(priv, priv->tx_prio_map, prof->tx_ring_num); - /* * Initialize netdev entry points */ dev->netdev_ops = &mlx4_netdev_ops; dev->watchdog_timeo = MLX4_EN_WATCHDOG_TIMEOUT; + dev->real_num_tx_queues = MLX4_EN_NUM_TX_RINGS; SET_ETHTOOL_OPS(dev, &mlx4_en_ethtool_ops); @@ -1057,7 +1036,9 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, * Set driver features */ dev->features |= NETIF_F_SG; + dev->vlan_features |= NETIF_F_SG; dev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; + dev->vlan_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; dev->features |= NETIF_F_HIGHDMA; dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | @@ -1067,6 +1048,8 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, if (mdev->LSO_support) { dev->features |= NETIF_F_TSO; dev->features |= NETIF_F_TSO6; + dev->vlan_features |= NETIF_F_TSO; + dev->vlan_features |= NETIF_F_TSO6; } mdev->pndev[port] = dev; @@ -1074,9 +1057,13 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, netif_carrier_off(dev); err = register_netdev(dev); if (err) { - mlx4_err(mdev, "Netdev registration failed\n"); + en_err(priv, "Netdev registration failed for port %d\n", port); goto out; } + + en_warn(priv, "Using %d TX rings\n", prof->tx_ring_num); + en_warn(priv, "Using %d RX rings\n", prof->rx_ring_num); + priv->registered = 1; queue_delayed_work(mdev->workqueue, &priv->stats_task, STATS_DELAY); return 0; diff --git a/drivers/net/mlx4/en_rx.c b/drivers/net/mlx4/en_rx.c index 9ee873e872b3..91bdfdfd431f 100644 --- a/drivers/net/mlx4/en_rx.c +++ b/drivers/net/mlx4/en_rx.c @@ -114,8 +114,8 @@ static int mlx4_en_init_allocator(struct mlx4_en_priv *priv, goto out; page_alloc->offset = priv->frag_info[i].frag_align; - mlx4_dbg(DRV, priv, "Initialized allocator:%d with page:%p\n", - i, page_alloc->page); + en_dbg(DRV, priv, "Initialized allocator:%d with page:%p\n", + i, page_alloc->page); } return 0; @@ -136,8 +136,8 @@ static void mlx4_en_destroy_allocator(struct mlx4_en_priv *priv, for (i = 0; i < priv->num_frags; i++) { page_alloc = &ring->page_alloc[i]; - mlx4_dbg(DRV, priv, "Freeing allocator:%d count:%d\n", - i, page_count(page_alloc->page)); + en_dbg(DRV, priv, "Freeing allocator:%d count:%d\n", + i, page_count(page_alloc->page)); put_page(page_alloc->page); page_alloc->page = NULL; @@ -202,12 +202,34 @@ static inline void mlx4_en_update_rx_prod_db(struct mlx4_en_rx_ring *ring) *ring->wqres.db.db = cpu_to_be32(ring->prod & 0xffff); } -static int mlx4_en_fill_rx_buffers(struct mlx4_en_priv *priv) +static void mlx4_en_free_rx_desc(struct mlx4_en_priv *priv, + struct mlx4_en_rx_ring *ring, + int index) { struct mlx4_en_dev *mdev = priv->mdev; + struct skb_frag_struct *skb_frags; + struct mlx4_en_rx_desc *rx_desc = ring->buf + (index << ring->log_stride); + dma_addr_t dma; + int nr; + + skb_frags = ring->rx_info + (index << priv->log_rx_info); + for (nr = 0; nr < priv->num_frags; nr++) { + en_dbg(DRV, priv, "Freeing fragment:%d\n", nr); + dma = be64_to_cpu(rx_desc->data[nr].addr); + + en_dbg(DRV, priv, "Unmaping buffer at dma:0x%llx\n", (u64) dma); + pci_unmap_single(mdev->pdev, dma, skb_frags[nr].size, + PCI_DMA_FROMDEVICE); + put_page(skb_frags[nr].page); + } +} + +static int mlx4_en_fill_rx_buffers(struct mlx4_en_priv *priv) +{ struct mlx4_en_rx_ring *ring; int ring_ind; int buf_ind; + int new_size; for (buf_ind = 0; buf_ind < priv->prof->rx_ring_size; buf_ind++) { for (ring_ind = 0; ring_ind < priv->rx_ring_num; ring_ind++) { @@ -216,121 +238,55 @@ static int mlx4_en_fill_rx_buffers(struct mlx4_en_priv *priv) if (mlx4_en_prepare_rx_desc(priv, ring, ring->actual_size)) { if (ring->actual_size < MLX4_EN_MIN_RX_SIZE) { - mlx4_err(mdev, "Failed to allocate " - "enough rx buffers\n"); + en_err(priv, "Failed to allocate " + "enough rx buffers\n"); return -ENOMEM; } else { - if (netif_msg_rx_err(priv)) - mlx4_warn(mdev, - "Only %d buffers allocated\n", - ring->actual_size); - goto out; + new_size = rounddown_pow_of_two(ring->actual_size); + en_warn(priv, "Only %d buffers allocated " + "reducing ring size to %d", + ring->actual_size, new_size); + goto reduce_rings; } } ring->actual_size++; ring->prod++; } } -out: return 0; -} -static int mlx4_en_fill_rx_buf(struct net_device *dev, - struct mlx4_en_rx_ring *ring) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - int num = 0; - int err; - - while ((u32) (ring->prod - ring->cons) < ring->actual_size) { - err = mlx4_en_prepare_rx_desc(priv, ring, ring->prod & - ring->size_mask); - if (err) { - if (netif_msg_rx_err(priv)) - mlx4_warn(priv->mdev, - "Failed preparing rx descriptor\n"); - priv->port_stats.rx_alloc_failed++; - break; +reduce_rings: + for (ring_ind = 0; ring_ind < priv->rx_ring_num; ring_ind++) { + ring = &priv->rx_ring[ring_ind]; + while (ring->actual_size > new_size) { + ring->actual_size--; + ring->prod--; + mlx4_en_free_rx_desc(priv, ring, ring->actual_size); } - ++num; - ++ring->prod; + ring->size_mask = ring->actual_size - 1; } - if ((u32) (ring->prod - ring->cons) == ring->size) - ring->full = 1; - return num; + return 0; } static void mlx4_en_free_rx_buf(struct mlx4_en_priv *priv, struct mlx4_en_rx_ring *ring) { - struct mlx4_en_dev *mdev = priv->mdev; - struct skb_frag_struct *skb_frags; - struct mlx4_en_rx_desc *rx_desc; - dma_addr_t dma; int index; - int nr; - mlx4_dbg(DRV, priv, "Freeing Rx buf - cons:%d prod:%d\n", - ring->cons, ring->prod); + en_dbg(DRV, priv, "Freeing Rx buf - cons:%d prod:%d\n", + ring->cons, ring->prod); /* Unmap and free Rx buffers */ - BUG_ON((u32) (ring->prod - ring->cons) > ring->size); + BUG_ON((u32) (ring->prod - ring->cons) > ring->actual_size); while (ring->cons != ring->prod) { index = ring->cons & ring->size_mask; - rx_desc = ring->buf + (index << ring->log_stride); - skb_frags = ring->rx_info + (index << priv->log_rx_info); - mlx4_dbg(DRV, priv, "Processing descriptor:%d\n", index); - - for (nr = 0; nr < priv->num_frags; nr++) { - mlx4_dbg(DRV, priv, "Freeing fragment:%d\n", nr); - dma = be64_to_cpu(rx_desc->data[nr].addr); - - mlx4_dbg(DRV, priv, "Unmaping buffer at dma:0x%llx\n", (u64) dma); - pci_unmap_single(mdev->pdev, dma, skb_frags[nr].size, - PCI_DMA_FROMDEVICE); - put_page(skb_frags[nr].page); - } + en_dbg(DRV, priv, "Processing descriptor:%d\n", index); + mlx4_en_free_rx_desc(priv, ring, index); ++ring->cons; } } - -void mlx4_en_rx_refill(struct work_struct *work) -{ - struct delayed_work *delay = to_delayed_work(work); - struct mlx4_en_priv *priv = container_of(delay, struct mlx4_en_priv, - refill_task); - struct mlx4_en_dev *mdev = priv->mdev; - struct net_device *dev = priv->dev; - struct mlx4_en_rx_ring *ring; - int need_refill = 0; - int i; - - mutex_lock(&mdev->state_lock); - if (!mdev->device_up || !priv->port_up) - goto out; - - /* We only get here if there are no receive buffers, so we can't race - * with Rx interrupts while filling buffers */ - for (i = 0; i < priv->rx_ring_num; i++) { - ring = &priv->rx_ring[i]; - if (ring->need_refill) { - if (mlx4_en_fill_rx_buf(dev, ring)) { - ring->need_refill = 0; - mlx4_en_update_rx_prod_db(ring); - } else - need_refill = 1; - } - } - if (need_refill) - queue_delayed_work(mdev->workqueue, &priv->refill_task, HZ); - -out: - mutex_unlock(&mdev->state_lock); -} - - int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv, struct mlx4_en_rx_ring *ring, u32 size, u16 stride) { @@ -354,10 +310,10 @@ int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv, sizeof(struct skb_frag_struct)); ring->rx_info = vmalloc(tmp); if (!ring->rx_info) { - mlx4_err(mdev, "Failed allocating rx_info ring\n"); + en_err(priv, "Failed allocating rx_info ring\n"); return -ENOMEM; } - mlx4_dbg(DRV, priv, "Allocated rx_info ring at addr:%p size:%d\n", + en_dbg(DRV, priv, "Allocated rx_info ring at addr:%p size:%d\n", ring->rx_info, tmp); err = mlx4_alloc_hwq_res(mdev->dev, &ring->wqres, @@ -367,7 +323,7 @@ int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv, err = mlx4_en_map_buffer(&ring->wqres.buf); if (err) { - mlx4_err(mdev, "Failed to map RX buffer\n"); + en_err(priv, "Failed to map RX buffer\n"); goto err_hwq; } ring->buf = ring->wqres.buf.direct.buf; @@ -385,7 +341,7 @@ int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv, sizeof(struct net_lro_desc), GFP_KERNEL); if (!ring->lro.lro_arr) { - mlx4_err(mdev, "Failed to allocate lro array\n"); + en_err(priv, "Failed to allocate lro array\n"); goto err_map; } ring->lro.get_frag_header = mlx4_en_get_frag_header; @@ -436,13 +392,10 @@ int mlx4_en_activate_rx_rings(struct mlx4_en_priv *priv) /* Initialize page allocators */ err = mlx4_en_init_allocator(priv, ring); if (err) { - mlx4_err(mdev, "Failed initializing ring allocator\n"); + en_err(priv, "Failed initializing ring allocator\n"); ring_ind--; goto err_allocator; } - - /* Fill Rx buffers */ - ring->full = 0; } err = mlx4_en_fill_rx_buffers(priv); if (err) @@ -454,7 +407,7 @@ int mlx4_en_activate_rx_rings(struct mlx4_en_priv *priv) mlx4_en_update_rx_prod_db(ring); /* Configure SRQ representing the ring */ - ring->srq.max = ring->size; + ring->srq.max = ring->actual_size; ring->srq.max_gs = max_gs; ring->srq.wqe_shift = ilog2(ring->stride); @@ -467,7 +420,7 @@ int mlx4_en_activate_rx_rings(struct mlx4_en_priv *priv) err = mlx4_srq_alloc(mdev->dev, mdev->priv_pdn, &ring->wqres.mtt, ring->wqres.db.dma, &ring->srq); if (err){ - mlx4_err(mdev, "Failed to allocate srq\n"); + en_err(priv, "Failed to allocate srq\n"); ring_ind--; goto err_srq; } @@ -582,7 +535,7 @@ static struct sk_buff *mlx4_en_rx_skb(struct mlx4_en_priv *priv, skb = dev_alloc_skb(SMALL_PACKET_SIZE + NET_IP_ALIGN); if (!skb) { - mlx4_dbg(RX_ERR, priv, "Failed allocating skb\n"); + en_dbg(RX_ERR, priv, "Failed allocating skb\n"); return NULL; } skb->dev = priv->dev; @@ -630,38 +583,10 @@ static struct sk_buff *mlx4_en_rx_skb(struct mlx4_en_priv *priv, return skb; } -static void mlx4_en_copy_desc(struct mlx4_en_priv *priv, - struct mlx4_en_rx_ring *ring, - int from, int to, int num) -{ - struct skb_frag_struct *skb_frags_from; - struct skb_frag_struct *skb_frags_to; - struct mlx4_en_rx_desc *rx_desc_from; - struct mlx4_en_rx_desc *rx_desc_to; - int from_index, to_index; - int nr, i; - - for (i = 0; i < num; i++) { - from_index = (from + i) & ring->size_mask; - to_index = (to + i) & ring->size_mask; - skb_frags_from = ring->rx_info + (from_index << priv->log_rx_info); - skb_frags_to = ring->rx_info + (to_index << priv->log_rx_info); - rx_desc_from = ring->buf + (from_index << ring->log_stride); - rx_desc_to = ring->buf + (to_index << ring->log_stride); - - for (nr = 0; nr < priv->num_frags; nr++) { - skb_frags_to[nr].page = skb_frags_from[nr].page; - skb_frags_to[nr].page_offset = skb_frags_from[nr].page_offset; - rx_desc_to->data[nr].addr = rx_desc_from->data[nr].addr; - } - } -} - int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int budget) { struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_en_dev *mdev = priv->mdev; struct mlx4_cqe *cqe; struct mlx4_en_rx_ring *ring = &priv->rx_ring[cq->ring]; struct skb_frag_struct *skb_frags; @@ -698,14 +623,14 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud /* Drop packet on bad receive or bad checksum */ if (unlikely((cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) == MLX4_CQE_OPCODE_ERROR)) { - mlx4_err(mdev, "CQE completed in error - vendor " + en_err(priv, "CQE completed in error - vendor " "syndrom:%d syndrom:%d\n", ((struct mlx4_err_cqe *) cqe)->vendor_err_syndrome, ((struct mlx4_err_cqe *) cqe)->syndrome); goto next; } if (unlikely(cqe->badfcs_enc & MLX4_CQE_BAD_FCS)) { - mlx4_dbg(RX_ERR, priv, "Accepted frame with bad FCS\n"); + en_dbg(RX_ERR, priv, "Accepted frame with bad FCS\n"); goto next; } @@ -805,11 +730,6 @@ out: wmb(); /* ensure HW sees CQ consumer before we post new buffers */ ring->cons = cq->mcq.cons_index; ring->prod += polled; /* Polled descriptors were realocated in place */ - if (unlikely(!ring->full)) { - mlx4_en_copy_desc(priv, ring, ring->cons - polled, - ring->prod - polled, polled); - mlx4_en_fill_rx_buf(dev, ring); - } mlx4_en_update_rx_prod_db(ring); return polled; } @@ -855,7 +775,7 @@ static int mlx4_en_last_alloc_offset(struct mlx4_en_priv *priv, u16 stride, u16 u16 res = MLX4_EN_ALLOC_SIZE % stride; u16 offset = MLX4_EN_ALLOC_SIZE - stride - res + align; - mlx4_dbg(DRV, priv, "Calculated last offset for stride:%d align:%d " + en_dbg(DRV, priv, "Calculated last offset for stride:%d align:%d " "res:%d offset:%d\n", stride, align, res, offset); return offset; } @@ -900,10 +820,10 @@ void mlx4_en_calc_rx_buf(struct net_device *dev) priv->rx_skb_size = eff_mtu; priv->log_rx_info = ROUNDUP_LOG2(i * sizeof(struct skb_frag_struct)); - mlx4_dbg(DRV, priv, "Rx buffer scatter-list (effective-mtu:%d " + en_dbg(DRV, priv, "Rx buffer scatter-list (effective-mtu:%d " "num_frags:%d):\n", eff_mtu, priv->num_frags); for (i = 0; i < priv->num_frags; i++) { - mlx4_dbg(DRV, priv, " frag:%d - size:%d prefix:%d align:%d " + en_dbg(DRV, priv, " frag:%d - size:%d prefix:%d align:%d " "stride:%d last_offset:%d\n", i, priv->frag_info[i].frag_size, priv->frag_info[i].frag_prefix_size, @@ -923,12 +843,12 @@ void mlx4_en_set_default_rss_map(struct mlx4_en_priv *priv, int i; rss_map->size = roundup_pow_of_two(num_entries); - mlx4_dbg(DRV, priv, "Setting default RSS map of %d entires\n", - rss_map->size); + en_dbg(DRV, priv, "Setting default RSS map of %d entires\n", + rss_map->size); for (i = 0; i < rss_map->size; i++) { rss_map->map[i] = i % num_rings; - mlx4_dbg(DRV, priv, "Entry %d ---> ring %d\n", i, rss_map->map[i]); + en_dbg(DRV, priv, "Entry %d ---> ring %d\n", i, rss_map->map[i]); } } @@ -943,13 +863,13 @@ static int mlx4_en_config_rss_qp(struct mlx4_en_priv *priv, context = kmalloc(sizeof *context , GFP_KERNEL); if (!context) { - mlx4_err(mdev, "Failed to allocate qp context\n"); + en_err(priv, "Failed to allocate qp context\n"); return -ENOMEM; } err = mlx4_qp_alloc(mdev->dev, qpn, qp); if (err) { - mlx4_err(mdev, "Failed to allocate qp #%d\n", qpn); + en_err(priv, "Failed to allocate qp #%x\n", qpn); goto out; } qp->event = mlx4_en_sqp_event; @@ -981,12 +901,11 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv) int err = 0; int good_qps = 0; - mlx4_dbg(DRV, priv, "Configuring rss steering for port %u\n", priv->port); + en_dbg(DRV, priv, "Configuring rss steering\n"); err = mlx4_qp_reserve_range(mdev->dev, rss_map->size, rss_map->size, &rss_map->base_qpn); if (err) { - mlx4_err(mdev, "Failed reserving %d qps for port %u\n", - rss_map->size, priv->port); + en_err(priv, "Failed reserving %d qps\n", rss_map->size); return err; } @@ -1006,13 +925,13 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv) /* Configure RSS indirection qp */ err = mlx4_qp_reserve_range(mdev->dev, 1, 1, &priv->base_qpn); if (err) { - mlx4_err(mdev, "Failed to reserve range for RSS " - "indirection qp\n"); + en_err(priv, "Failed to reserve range for RSS " + "indirection qp\n"); goto rss_err; } err = mlx4_qp_alloc(mdev->dev, priv->base_qpn, &rss_map->indir_qp); if (err) { - mlx4_err(mdev, "Failed to allocate RSS indirection QP\n"); + en_err(priv, "Failed to allocate RSS indirection QP\n"); goto reserve_err; } rss_map->indir_qp.event = mlx4_en_sqp_event; diff --git a/drivers/net/mlx4/en_tx.c b/drivers/net/mlx4/en_tx.c index e5c98a98ad37..08c43f2ae72b 100644 --- a/drivers/net/mlx4/en_tx.c +++ b/drivers/net/mlx4/en_tx.c @@ -68,15 +68,15 @@ int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv, tmp = size * sizeof(struct mlx4_en_tx_info); ring->tx_info = vmalloc(tmp); if (!ring->tx_info) { - mlx4_err(mdev, "Failed allocating tx_info ring\n"); + en_err(priv, "Failed allocating tx_info ring\n"); return -ENOMEM; } - mlx4_dbg(DRV, priv, "Allocated tx_info ring at addr:%p size:%d\n", + en_dbg(DRV, priv, "Allocated tx_info ring at addr:%p size:%d\n", ring->tx_info, tmp); ring->bounce_buf = kmalloc(MAX_DESC_SIZE, GFP_KERNEL); if (!ring->bounce_buf) { - mlx4_err(mdev, "Failed allocating bounce buffer\n"); + en_err(priv, "Failed allocating bounce buffer\n"); err = -ENOMEM; goto err_tx; } @@ -85,31 +85,31 @@ int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv, err = mlx4_alloc_hwq_res(mdev->dev, &ring->wqres, ring->buf_size, 2 * PAGE_SIZE); if (err) { - mlx4_err(mdev, "Failed allocating hwq resources\n"); + en_err(priv, "Failed allocating hwq resources\n"); goto err_bounce; } err = mlx4_en_map_buffer(&ring->wqres.buf); if (err) { - mlx4_err(mdev, "Failed to map TX buffer\n"); + en_err(priv, "Failed to map TX buffer\n"); goto err_hwq_res; } ring->buf = ring->wqres.buf.direct.buf; - mlx4_dbg(DRV, priv, "Allocated TX ring (addr:%p) - buf:%p size:%d " - "buf_size:%d dma:%llx\n", ring, ring->buf, ring->size, - ring->buf_size, (unsigned long long) ring->wqres.buf.direct.map); + en_dbg(DRV, priv, "Allocated TX ring (addr:%p) - buf:%p size:%d " + "buf_size:%d dma:%llx\n", ring, ring->buf, ring->size, + ring->buf_size, (unsigned long long) ring->wqres.buf.direct.map); err = mlx4_qp_reserve_range(mdev->dev, 1, 1, &ring->qpn); if (err) { - mlx4_err(mdev, "Failed reserving qp for tx ring.\n"); + en_err(priv, "Failed reserving qp for tx ring.\n"); goto err_map; } err = mlx4_qp_alloc(mdev->dev, ring->qpn, &ring->qp); if (err) { - mlx4_err(mdev, "Failed allocating qp %d\n", ring->qpn); + en_err(priv, "Failed allocating qp %d\n", ring->qpn); goto err_reserve; } ring->qp.event = mlx4_en_sqp_event; @@ -135,7 +135,7 @@ void mlx4_en_destroy_tx_ring(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ring) { struct mlx4_en_dev *mdev = priv->mdev; - mlx4_dbg(DRV, priv, "Destroying tx ring, qpn: %d\n", ring->qpn); + en_dbg(DRV, priv, "Destroying tx ring, qpn: %d\n", ring->qpn); mlx4_qp_remove(mdev->dev, &ring->qp); mlx4_qp_free(mdev->dev, &ring->qp); @@ -274,12 +274,12 @@ int mlx4_en_free_tx_buf(struct net_device *dev, struct mlx4_en_tx_ring *ring) /* Skip last polled descriptor */ ring->cons += ring->last_nr_txbb; - mlx4_dbg(DRV, priv, "Freeing Tx buf - cons:0x%x prod:0x%x\n", + en_dbg(DRV, priv, "Freeing Tx buf - cons:0x%x prod:0x%x\n", ring->cons, ring->prod); if ((u32) (ring->prod - ring->cons) > ring->size) { if (netif_msg_tx_err(priv)) - mlx4_warn(priv->mdev, "Tx consumer passed producer!\n"); + en_warn(priv, "Tx consumer passed producer!\n"); return 0; } @@ -292,39 +292,11 @@ int mlx4_en_free_tx_buf(struct net_device *dev, struct mlx4_en_tx_ring *ring) } if (cnt) - mlx4_dbg(DRV, priv, "Freed %d uncompleted tx descriptors\n", cnt); + en_dbg(DRV, priv, "Freed %d uncompleted tx descriptors\n", cnt); return cnt; } -void mlx4_en_set_prio_map(struct mlx4_en_priv *priv, u16 *prio_map, u32 ring_num) -{ - int block = 8 / ring_num; - int extra = 8 - (block * ring_num); - int num = 0; - u16 ring = 1; - int prio; - - if (ring_num == 1) { - for (prio = 0; prio < 8; prio++) - prio_map[prio] = 0; - return; - } - - for (prio = 0; prio < 8; prio++) { - if (extra && (num == block + 1)) { - ring++; - num = 0; - extra--; - } else if (!extra && (num == block)) { - ring++; - num = 0; - } - prio_map[prio] = ring; - mlx4_dbg(DRV, priv, " prio:%d --> ring:%d\n", prio, ring); - num++; - } -} static void mlx4_en_process_tx_cq(struct net_device *dev, struct mlx4_en_cq *cq) { @@ -386,18 +358,8 @@ static void mlx4_en_process_tx_cq(struct net_device *dev, struct mlx4_en_cq *cq) if (unlikely(ring->blocked)) { if ((u32) (ring->prod - ring->cons) <= ring->size - HEADROOM - MAX_DESC_TXBBS) { - - /* TODO: support multiqueue netdevs. Currently, we block - * when *any* ring is full. Note that: - * - 2 Tx rings can unblock at the same time and call - * netif_wake_queue(), which is OK since this - * operation is idempotent. - * - We might wake the queue just after another ring - * stopped it. This is no big deal because the next - * transmission on that ring would stop the queue. - */ ring->blocked = 0; - netif_wake_queue(dev); + netif_tx_wake_queue(netdev_get_tx_queue(dev, cq->ring)); priv->port_stats.wake_queue++; } } @@ -539,7 +501,6 @@ static int get_real_size(struct sk_buff *skb, struct net_device *dev, int *lso_header_size) { struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_en_dev *mdev = priv->mdev; int real_size; if (skb_is_gso(skb)) { @@ -553,17 +514,10 @@ static int get_real_size(struct sk_buff *skb, struct net_device *dev, real_size += DS_SIZE; else { if (netif_msg_tx_err(priv)) - mlx4_warn(mdev, "Non-linear headers\n"); - dev_kfree_skb_any(skb); + en_warn(priv, "Non-linear headers\n"); return 0; } } - if (unlikely(*lso_header_size > MAX_LSO_HDR_SIZE)) { - if (netif_msg_tx_err(priv)) - mlx4_warn(mdev, "LSO header size too big\n"); - dev_kfree_skb_any(skb); - return 0; - } } else { *lso_header_size = 0; if (!is_inline(skb, NULL)) @@ -617,21 +571,20 @@ static void build_inline_wqe(struct mlx4_en_tx_desc *tx_desc, struct sk_buff *sk tx_desc->ctrl.fence_size = (real_size / 16) & 0x3f; } -static int get_vlan_info(struct mlx4_en_priv *priv, struct sk_buff *skb, - u16 *vlan_tag) +u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb) { - int tx_ind; + struct mlx4_en_priv *priv = netdev_priv(dev); + u16 vlan_tag = 0; - /* Obtain VLAN information if present */ - if (priv->vlgrp && vlan_tx_tag_present(skb)) { - *vlan_tag = vlan_tx_tag_get(skb); - /* Set the Tx ring to use according to vlan priority */ - tx_ind = priv->tx_prio_map[*vlan_tag >> 13]; - } else { - *vlan_tag = 0; - tx_ind = 0; + /* If we support per priority flow control and the packet contains + * a vlan tag, send the packet to the TX ring assigned to that priority + */ + if (priv->prof->rx_ppp && priv->vlgrp && vlan_tx_tag_present(skb)) { + vlan_tag = vlan_tx_tag_get(skb); + return MLX4_EN_NUM_TX_RINGS + (vlan_tag >> 13); } - return tx_ind; + + return skb_tx_hash(dev, skb); } int mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) @@ -651,38 +604,34 @@ int mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) dma_addr_t dma; u32 index; __be32 op_own; - u16 vlan_tag; + u16 vlan_tag = 0; int i; int lso_header_size; void *fragptr; - if (unlikely(!skb->len)) { - dev_kfree_skb_any(skb); - return NETDEV_TX_OK; - } real_size = get_real_size(skb, dev, &lso_header_size); if (unlikely(!real_size)) - return NETDEV_TX_OK; + goto tx_drop; /* Allign descriptor to TXBB size */ desc_size = ALIGN(real_size, TXBB_SIZE); nr_txbb = desc_size / TXBB_SIZE; if (unlikely(nr_txbb > MAX_DESC_TXBBS)) { if (netif_msg_tx_err(priv)) - mlx4_warn(mdev, "Oversized header or SG list\n"); - dev_kfree_skb_any(skb); - return NETDEV_TX_OK; + en_warn(priv, "Oversized header or SG list\n"); + goto tx_drop; } - tx_ind = get_vlan_info(priv, skb, &vlan_tag); + tx_ind = skb->queue_mapping; ring = &priv->tx_ring[tx_ind]; + if (priv->vlgrp && vlan_tx_tag_present(skb)) + vlan_tag = vlan_tx_tag_get(skb); /* Check available TXBBs And 2K spare for prefetch */ if (unlikely(((int)(ring->prod - ring->cons)) > ring->size - HEADROOM - MAX_DESC_TXBBS)) { - /* every full Tx ring stops queue. - * TODO: implement multi-queue support (per-queue stop) */ - netif_stop_queue(dev); + /* every full Tx ring stops queue */ + netif_tx_stop_queue(netdev_get_tx_queue(dev, tx_ind)); ring->blocked = 1; priv->port_stats.queue_stopped++; @@ -692,14 +641,6 @@ int mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_BUSY; } - /* Now that we know what Tx ring to use */ - if (unlikely(!priv->port_up)) { - if (netif_msg_tx_err(priv)) - mlx4_warn(mdev, "xmit: port down!\n"); - dev_kfree_skb_any(skb); - return NETDEV_TX_OK; - } - /* Track current inflight packets for performance analysis */ AVG_PERF_COUNTER(priv->pstats.inflight_avg, (u32) (ring->prod - ring->cons - 1)); @@ -819,11 +760,15 @@ int mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) /* Ring doorbell! */ wmb(); writel(ring->doorbell_qpn, mdev->uar_map + MLX4_SEND_DOORBELL); - dev->trans_start = jiffies; /* Poll CQ here */ mlx4_en_xmit_poll(priv, tx_ind); return 0; + +tx_drop: + dev_kfree_skb_any(skb); + priv->stats.tx_dropped++; + return NETDEV_TX_OK; } diff --git a/drivers/net/mlx4/eq.c b/drivers/net/mlx4/eq.c index 8830dcb92ec8..b9ceddde46c0 100644 --- a/drivers/net/mlx4/eq.c +++ b/drivers/net/mlx4/eq.c @@ -497,8 +497,10 @@ static void mlx4_free_irqs(struct mlx4_dev *dev) if (eq_table->have_irq) free_irq(dev->pdev->irq, dev); for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i) - if (eq_table->eq[i].have_irq) + if (eq_table->eq[i].have_irq) { free_irq(eq_table->eq[i].irq, eq_table->eq + i); + eq_table->eq[i].have_irq = 0; + } kfree(eq_table->irq_names); } @@ -623,8 +625,10 @@ int mlx4_init_eq_table(struct mlx4_dev *dev) err = mlx4_create_eq(dev, dev->caps.num_cqs + MLX4_NUM_SPARE_EQE, (dev->flags & MLX4_FLAG_MSI_X) ? i : 0, &priv->eq_table.eq[i]); - if (err) + if (err) { + --i; goto err_out_unmap; + } } err = mlx4_create_eq(dev, MLX4_NUM_ASYNC_EQE + MLX4_NUM_SPARE_EQE, diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c index 30bea9689694..018348c01193 100644 --- a/drivers/net/mlx4/main.c +++ b/drivers/net/mlx4/main.c @@ -100,6 +100,10 @@ module_param_named(use_prio, use_prio, bool, 0444); MODULE_PARM_DESC(use_prio, "Enable steering by VLAN priority on ETH ports " "(0/1, default 0)"); +static int log_mtts_per_seg = ilog2(MLX4_MTT_ENTRY_PER_SEG); +module_param_named(log_mtts_per_seg, log_mtts_per_seg, int, 0444); +MODULE_PARM_DESC(log_mtts_per_seg, "Log2 number of MTT entries per segment (1-5)"); + int mlx4_check_port_params(struct mlx4_dev *dev, enum mlx4_port_type *port_type) { @@ -203,12 +207,13 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) dev->caps.max_cqes = dev_cap->max_cq_sz - 1; dev->caps.reserved_cqs = dev_cap->reserved_cqs; dev->caps.reserved_eqs = dev_cap->reserved_eqs; + dev->caps.mtts_per_seg = 1 << log_mtts_per_seg; dev->caps.reserved_mtts = DIV_ROUND_UP(dev_cap->reserved_mtts, - MLX4_MTT_ENTRY_PER_SEG); + dev->caps.mtts_per_seg); dev->caps.reserved_mrws = dev_cap->reserved_mrws; dev->caps.reserved_uars = dev_cap->reserved_uars; dev->caps.reserved_pds = dev_cap->reserved_pds; - dev->caps.mtt_entry_sz = MLX4_MTT_ENTRY_PER_SEG * dev_cap->mtt_entry_sz; + dev->caps.mtt_entry_sz = dev->caps.mtts_per_seg * dev_cap->mtt_entry_sz; dev->caps.max_msg_sz = dev_cap->max_msg_sz; dev->caps.page_size_cap = ~(u32) (dev_cap->min_page_sz - 1); dev->caps.flags = dev_cap->flags; @@ -1304,6 +1309,11 @@ static int __init mlx4_verify_params(void) return -1; } + if ((log_mtts_per_seg < 1) || (log_mtts_per_seg > 5)) { + printk(KERN_WARNING "mlx4_core: bad log_mtts_per_seg: %d\n", log_mtts_per_seg); + return -1; + } + return 0; } diff --git a/drivers/net/mlx4/mlx4_en.h b/drivers/net/mlx4/mlx4_en.h index ef840abbcd39..c7c5e86804ff 100644 --- a/drivers/net/mlx4/mlx4_en.h +++ b/drivers/net/mlx4/mlx4_en.h @@ -49,26 +49,42 @@ #include "en_port.h" #define DRV_NAME "mlx4_en" -#define DRV_VERSION "1.4.0" -#define DRV_RELDATE "Sep 2008" +#define DRV_VERSION "1.4.1.1" +#define DRV_RELDATE "June 2009" #define MLX4_EN_MSG_LEVEL (NETIF_MSG_LINK | NETIF_MSG_IFDOWN) -#define mlx4_dbg(mlevel, priv, format, arg...) \ - if (NETIF_MSG_##mlevel & priv->msg_enable) \ - printk(KERN_DEBUG "%s %s: " format , DRV_NAME ,\ - (dev_name(&priv->mdev->pdev->dev)) , ## arg) +#define en_print(level, priv, format, arg...) \ + { \ + if ((priv)->registered) \ + printk(level "%s: %s: " format, DRV_NAME, \ + (priv->dev)->name, ## arg); \ + else \ + printk(level "%s: %s: Port %d: " format, \ + DRV_NAME, dev_name(&priv->mdev->pdev->dev), \ + (priv)->port, ## arg); \ + } + +#define en_dbg(mlevel, priv, format, arg...) \ + { \ + if (NETIF_MSG_##mlevel & priv->msg_enable) \ + en_print(KERN_DEBUG, priv, format, ## arg) \ + } +#define en_warn(priv, format, arg...) \ + en_print(KERN_WARNING, priv, format, ## arg) +#define en_err(priv, format, arg...) \ + en_print(KERN_ERR, priv, format, ## arg) #define mlx4_err(mdev, format, arg...) \ printk(KERN_ERR "%s %s: " format , DRV_NAME ,\ - (dev_name(&mdev->pdev->dev)) , ## arg) + dev_name(&mdev->pdev->dev) , ## arg) #define mlx4_info(mdev, format, arg...) \ printk(KERN_INFO "%s %s: " format , DRV_NAME ,\ - (dev_name(&mdev->pdev->dev)) , ## arg) + dev_name(&mdev->pdev->dev) , ## arg) #define mlx4_warn(mdev, format, arg...) \ printk(KERN_WARNING "%s %s: " format , DRV_NAME ,\ - (dev_name(&mdev->pdev->dev)) , ## arg) + dev_name(&mdev->pdev->dev) , ## arg) /* * Device constants @@ -83,7 +99,6 @@ #define RSS_FACTOR 2 #define TXBB_SIZE 64 #define HEADROOM (2048 / TXBB_SIZE + 1) -#define MAX_LSO_HDR_SIZE 92 #define STAMP_STRIDE 64 #define STAMP_DWORDS (STAMP_STRIDE / 4) #define STAMP_SHIFT 31 @@ -123,12 +138,14 @@ enum { #define MLX4_EN_MIN_RX_SIZE (MLX4_EN_ALLOC_SIZE / SMP_CACHE_BYTES) #define MLX4_EN_MIN_TX_SIZE (4096 / TXBB_SIZE) -#define MLX4_EN_TX_RING_NUM 9 -#define MLX4_EN_DEF_TX_RING_SIZE 1024 +#define MLX4_EN_SMALL_PKT_SIZE 64 +#define MLX4_EN_NUM_TX_RINGS 8 +#define MLX4_EN_NUM_PPP_RINGS 8 +#define MLX4_EN_DEF_TX_RING_SIZE 512 #define MLX4_EN_DEF_RX_RING_SIZE 1024 -/* Target number of bytes to coalesce with interrupt moderation */ -#define MLX4_EN_RX_COAL_TARGET 0x20000 +/* Target number of packets to coalesce with interrupt moderation */ +#define MLX4_EN_RX_COAL_TARGET 44 #define MLX4_EN_RX_COAL_TIME 0x10 #define MLX4_EN_TX_COAL_PKTS 5 @@ -278,8 +295,6 @@ struct mlx4_en_rx_ring { u32 prod; u32 cons; u32 buf_size; - int need_refill; - int full; void *buf; void *rx_info; unsigned long bytes; @@ -462,7 +477,6 @@ struct mlx4_en_priv { int base_qpn; struct mlx4_en_rss_map rss_map; - u16 tx_prio_map[8]; u32 flags; #define MLX4_EN_FLAG_PROMISC 0x1 u32 tx_ring_num; @@ -478,7 +492,6 @@ struct mlx4_en_priv { struct mlx4_en_cq rx_cq[MAX_RX_RINGS]; struct work_struct mcast_task; struct work_struct mac_task; - struct delayed_work refill_task; struct work_struct watchdog_task; struct work_struct linkstate_task; struct delayed_work stats_task; @@ -500,8 +513,6 @@ void mlx4_en_stop_port(struct net_device *dev); void mlx4_en_free_resources(struct mlx4_en_priv *priv); int mlx4_en_alloc_resources(struct mlx4_en_priv *priv); -int mlx4_en_get_profile(struct mlx4_en_dev *mdev); - int mlx4_en_create_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq, int entries, int ring, enum cq_type mode); void mlx4_en_destroy_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq); @@ -512,6 +523,7 @@ int mlx4_en_arm_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq); void mlx4_en_poll_tx_cq(unsigned long data); void mlx4_en_tx_irq(struct mlx4_cq *mcq); +u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb); int mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev); int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ring, @@ -546,11 +558,9 @@ void mlx4_en_calc_rx_buf(struct net_device *dev); void mlx4_en_set_default_rss_map(struct mlx4_en_priv *priv, struct mlx4_en_rss_map *rss_map, int num_entries, int num_rings); -void mlx4_en_set_prio_map(struct mlx4_en_priv *priv, u16 *prio_map, u32 ring_num); int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv); void mlx4_en_release_rss_steer(struct mlx4_en_priv *priv); int mlx4_en_free_tx_buf(struct net_device *dev, struct mlx4_en_tx_ring *ring); -void mlx4_en_rx_refill(struct work_struct *work); void mlx4_en_rx_irq(struct mlx4_cq *mcq); int mlx4_SET_MCAST_FLTR(struct mlx4_dev *dev, u8 port, u64 mac, u64 clear, u8 mode); diff --git a/drivers/net/mlx4/mr.c b/drivers/net/mlx4/mr.c index 0caf74cae8bc..f96948be0a44 100644 --- a/drivers/net/mlx4/mr.c +++ b/drivers/net/mlx4/mr.c @@ -209,7 +209,7 @@ int mlx4_mtt_init(struct mlx4_dev *dev, int npages, int page_shift, } else mtt->page_shift = page_shift; - for (mtt->order = 0, i = MLX4_MTT_ENTRY_PER_SEG; i < npages; i <<= 1) + for (mtt->order = 0, i = dev->caps.mtts_per_seg; i < npages; i <<= 1) ++mtt->order; mtt->first_seg = mlx4_alloc_mtt_range(dev, mtt->order); @@ -350,7 +350,7 @@ int mlx4_mr_enable(struct mlx4_dev *dev, struct mlx4_mr *mr) mpt_entry->pd_flags |= cpu_to_be32(MLX4_MPT_PD_FLAG_FAST_REG | MLX4_MPT_PD_FLAG_RAE); mpt_entry->mtt_sz = cpu_to_be32((1 << mr->mtt.order) * - MLX4_MTT_ENTRY_PER_SEG); + dev->caps.mtts_per_seg); } else { mpt_entry->flags |= cpu_to_be32(MLX4_MPT_FLAG_SW_OWNS); } @@ -391,7 +391,7 @@ static int mlx4_write_mtt_chunk(struct mlx4_dev *dev, struct mlx4_mtt *mtt, (start_index + npages - 1) / (PAGE_SIZE / sizeof (u64))) return -EINVAL; - if (start_index & (MLX4_MTT_ENTRY_PER_SEG - 1)) + if (start_index & (dev->caps.mtts_per_seg - 1)) return -EINVAL; mtts = mlx4_table_find(&priv->mr_table.mtt_table, mtt->first_seg + @@ -399,10 +399,14 @@ static int mlx4_write_mtt_chunk(struct mlx4_dev *dev, struct mlx4_mtt *mtt, if (!mtts) return -ENOMEM; + dma_sync_single_for_cpu(&dev->pdev->dev, dma_handle, + npages * sizeof (u64), DMA_TO_DEVICE); + for (i = 0; i < npages; ++i) mtts[i] = cpu_to_be64(page_list[i] | MLX4_MTT_FLAG_PRESENT); - dma_sync_single(&dev->pdev->dev, dma_handle, npages * sizeof (u64), DMA_TO_DEVICE); + dma_sync_single_for_device(&dev->pdev->dev, dma_handle, + npages * sizeof (u64), DMA_TO_DEVICE); return 0; } @@ -546,11 +550,14 @@ int mlx4_map_phys_fmr(struct mlx4_dev *dev, struct mlx4_fmr *fmr, u64 *page_list /* Make sure MPT status is visible before writing MTT entries */ wmb(); + dma_sync_single_for_cpu(&dev->pdev->dev, fmr->dma_handle, + npages * sizeof(u64), DMA_TO_DEVICE); + for (i = 0; i < npages; ++i) fmr->mtts[i] = cpu_to_be64(page_list[i] | MLX4_MTT_FLAG_PRESENT); - dma_sync_single(&dev->pdev->dev, fmr->dma_handle, - npages * sizeof(u64), DMA_TO_DEVICE); + dma_sync_single_for_device(&dev->pdev->dev, fmr->dma_handle, + npages * sizeof(u64), DMA_TO_DEVICE); fmr->mpt->key = cpu_to_be32(key); fmr->mpt->lkey = cpu_to_be32(key); diff --git a/drivers/net/mlx4/profile.c b/drivers/net/mlx4/profile.c index cebdf3243ca1..bd22df95adf9 100644 --- a/drivers/net/mlx4/profile.c +++ b/drivers/net/mlx4/profile.c @@ -98,7 +98,7 @@ u64 mlx4_make_profile(struct mlx4_dev *dev, profile[MLX4_RES_EQ].size = dev_cap->eqc_entry_sz; profile[MLX4_RES_DMPT].size = dev_cap->dmpt_entry_sz; profile[MLX4_RES_CMPT].size = dev_cap->cmpt_entry_sz; - profile[MLX4_RES_MTT].size = MLX4_MTT_ENTRY_PER_SEG * dev_cap->mtt_entry_sz; + profile[MLX4_RES_MTT].size = dev->caps.mtts_per_seg * dev_cap->mtt_entry_sz; profile[MLX4_RES_MCG].size = MLX4_MGM_ENTRY_SIZE; profile[MLX4_RES_QP].num = request->num_qp; diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 6bb5af35eda6..0f32db3e92ad 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -55,6 +55,7 @@ #include #include #include +#include static char mv643xx_eth_driver_name[] = "mv643xx_eth"; static char mv643xx_eth_driver_version[] = "1.4"; @@ -88,7 +89,24 @@ static char mv643xx_eth_driver_version[] = "1.4"; #define MAC_ADDR_LOW 0x0014 #define MAC_ADDR_HIGH 0x0018 #define SDMA_CONFIG 0x001c +#define TX_BURST_SIZE_16_64BIT 0x01000000 +#define TX_BURST_SIZE_4_64BIT 0x00800000 +#define BLM_TX_NO_SWAP 0x00000020 +#define BLM_RX_NO_SWAP 0x00000010 +#define RX_BURST_SIZE_16_64BIT 0x00000008 +#define RX_BURST_SIZE_4_64BIT 0x00000004 #define PORT_SERIAL_CONTROL 0x003c +#define SET_MII_SPEED_TO_100 0x01000000 +#define SET_GMII_SPEED_TO_1000 0x00800000 +#define SET_FULL_DUPLEX_MODE 0x00200000 +#define MAX_RX_PACKET_9700BYTE 0x000a0000 +#define DISABLE_AUTO_NEG_SPEED_GMII 0x00002000 +#define DO_NOT_FORCE_LINK_FAIL 0x00000400 +#define SERIAL_PORT_CONTROL_RESERVED 0x00000200 +#define DISABLE_AUTO_NEG_FOR_FLOW_CTRL 0x00000008 +#define DISABLE_AUTO_NEG_FOR_DUPLEX 0x00000004 +#define FORCE_LINK_PASS 0x00000002 +#define SERIAL_PORT_ENABLE 0x00000001 #define PORT_STATUS 0x0044 #define TX_FIFO_EMPTY 0x00000400 #define TX_IN_PROGRESS 0x00000080 @@ -106,7 +124,9 @@ static char mv643xx_eth_driver_version[] = "1.4"; #define TX_BW_BURST 0x005c #define INT_CAUSE 0x0060 #define INT_TX_END 0x07f80000 +#define INT_TX_END_0 0x00080000 #define INT_RX 0x000003fc +#define INT_RX_0 0x00000004 #define INT_EXT 0x00000002 #define INT_CAUSE_EXT 0x0064 #define INT_EXT_LINK_PHY 0x00110000 @@ -135,15 +155,8 @@ static char mv643xx_eth_driver_version[] = "1.4"; /* - * SDMA configuration register. + * SDMA configuration register default value. */ -#define RX_BURST_SIZE_4_64BIT (2 << 1) -#define RX_BURST_SIZE_16_64BIT (4 << 1) -#define BLM_RX_NO_SWAP (1 << 4) -#define BLM_TX_NO_SWAP (1 << 5) -#define TX_BURST_SIZE_4_64BIT (2 << 22) -#define TX_BURST_SIZE_16_64BIT (4 << 22) - #if defined(__BIG_ENDIAN) #define PORT_SDMA_CONFIG_DEFAULT_VALUE \ (RX_BURST_SIZE_4_64BIT | \ @@ -160,22 +173,11 @@ static char mv643xx_eth_driver_version[] = "1.4"; /* - * Port serial control register. + * Misc definitions. */ -#define SET_MII_SPEED_TO_100 (1 << 24) -#define SET_GMII_SPEED_TO_1000 (1 << 23) -#define SET_FULL_DUPLEX_MODE (1 << 21) -#define MAX_RX_PACKET_9700BYTE (5 << 17) -#define DISABLE_AUTO_NEG_SPEED_GMII (1 << 13) -#define DO_NOT_FORCE_LINK_FAIL (1 << 10) -#define SERIAL_PORT_CONTROL_RESERVED (1 << 9) -#define DISABLE_AUTO_NEG_FOR_FLOW_CTRL (1 << 3) -#define DISABLE_AUTO_NEG_FOR_DUPLEX (1 << 2) -#define FORCE_LINK_PASS (1 << 1) -#define SERIAL_PORT_ENABLE (1 << 0) - -#define DEFAULT_RX_QUEUE_SIZE 128 -#define DEFAULT_TX_QUEUE_SIZE 256 +#define DEFAULT_RX_QUEUE_SIZE 128 +#define DEFAULT_TX_QUEUE_SIZE 256 +#define SKB_DMA_REALIGN ((PAGE_SIZE - NET_SKB_PAD) % SMP_CACHE_BYTES) /* @@ -393,6 +395,7 @@ struct mv643xx_eth_private { struct work_struct tx_timeout_task; struct napi_struct napi; + u32 int_mask; u8 oom; u8 work_link; u8 work_tx; @@ -651,23 +654,20 @@ static int rxq_refill(struct rx_queue *rxq, int budget) refilled = 0; while (refilled < budget && rxq->rx_desc_count < rxq->rx_ring_size) { struct sk_buff *skb; - int unaligned; int rx; struct rx_desc *rx_desc; skb = __skb_dequeue(&mp->rx_recycle); if (skb == NULL) - skb = dev_alloc_skb(mp->skb_size + - dma_get_cache_alignment() - 1); + skb = dev_alloc_skb(mp->skb_size); if (skb == NULL) { mp->oom = 1; goto oom; } - unaligned = (u32)skb->data & (dma_get_cache_alignment() - 1); - if (unaligned) - skb_reserve(skb, dma_get_cache_alignment() - unaligned); + if (SKB_DMA_REALIGN) + skb_reserve(skb, SKB_DMA_REALIGN); refilled++; rxq->rx_desc_count++; @@ -969,8 +969,7 @@ static int txq_reclaim(struct tx_queue *txq, int budget, int force) if (skb != NULL) { if (skb_queue_len(&mp->rx_recycle) < mp->rx_ring_size && - skb_recycle_check(skb, mp->skb_size + - dma_get_cache_alignment() - 1)) + skb_recycle_check(skb, mp->skb_size)) __skb_queue_head(&mp->rx_recycle, skb); else dev_kfree_skb(skb); @@ -1723,20 +1722,20 @@ static void uc_addr_set(struct mv643xx_eth_private *mp, unsigned char *addr) static u32 uc_addr_filter_mask(struct net_device *dev) { - struct dev_addr_list *uc_ptr; + struct netdev_hw_addr *ha; u32 nibbles; if (dev->flags & IFF_PROMISC) return 0; nibbles = 1 << (dev->dev_addr[5] & 0x0f); - for (uc_ptr = dev->uc_list; uc_ptr != NULL; uc_ptr = uc_ptr->next) { - if (memcmp(dev->dev_addr, uc_ptr->da_addr, 5)) + list_for_each_entry(ha, &dev->uc.list, list) { + if (memcmp(dev->dev_addr, ha->addr, 5)) return 0; - if ((dev->dev_addr[5] ^ uc_ptr->da_addr[5]) & 0xf0) + if ((dev->dev_addr[5] ^ ha->addr[5]) & 0xf0) return 0; - nibbles |= 1 << (uc_ptr->da_addr[5] & 0x0f); + nibbles |= 1 << (ha->addr[5] & 0x0f); } return nibbles; @@ -1751,12 +1750,12 @@ static void mv643xx_eth_program_unicast_filter(struct net_device *dev) uc_addr_set(mp, dev->dev_addr); - port_config = rdlp(mp, PORT_CONFIG); + port_config = rdlp(mp, PORT_CONFIG) & ~UNICAST_PROMISCUOUS_MODE; + nibbles = uc_addr_filter_mask(dev); if (!nibbles) { port_config |= UNICAST_PROMISCUOUS_MODE; - wrlp(mp, PORT_CONFIG, port_config); - return; + nibbles = 0xffff; } for (i = 0; i < 16; i += 4) { @@ -1777,7 +1776,6 @@ static void mv643xx_eth_program_unicast_filter(struct net_device *dev) wrl(mp, off, v); } - port_config &= ~UNICAST_PROMISCUOUS_MODE; wrlp(mp, PORT_CONFIG, port_config); } @@ -1810,7 +1808,6 @@ static void mv643xx_eth_program_multicast_filter(struct net_device *dev) if (dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) { int port_num; u32 accept; - int i; oom: port_num = mp->port_num; @@ -2067,15 +2064,16 @@ static int mv643xx_eth_collect_events(struct mv643xx_eth_private *mp) u32 int_cause; u32 int_cause_ext; - int_cause = rdlp(mp, INT_CAUSE) & (INT_TX_END | INT_RX | INT_EXT); + int_cause = rdlp(mp, INT_CAUSE) & mp->int_mask; if (int_cause == 0) return 0; int_cause_ext = 0; - if (int_cause & INT_EXT) + if (int_cause & INT_EXT) { + int_cause &= ~INT_EXT; int_cause_ext = rdlp(mp, INT_CAUSE_EXT); + } - int_cause &= INT_TX_END | INT_RX; if (int_cause) { wrlp(mp, INT_CAUSE, ~int_cause); mp->work_tx_end |= ((int_cause & INT_TX_END) >> 19) & @@ -2182,6 +2180,7 @@ static int mv643xx_eth_poll(struct napi_struct *napi, int budget) if (mp->work_link) { mp->work_link = 0; handle_link_event(mp); + work_done++; continue; } @@ -2220,7 +2219,7 @@ static int mv643xx_eth_poll(struct napi_struct *napi, int budget) if (mp->oom) mod_timer(&mp->rx_oom, jiffies + (HZ / 10)); napi_complete(napi); - wrlp(mp, INT_MASK, INT_TX_END | INT_RX | INT_EXT); + wrlp(mp, INT_MASK, mp->int_mask); } return work_done; @@ -2341,6 +2340,14 @@ static void mv643xx_eth_recalc_skb_size(struct mv643xx_eth_private *mp) * size field are ignored by the hardware. */ mp->skb_size = (skb_size + 7) & ~7; + + /* + * If NET_SKB_PAD is smaller than a cache line, + * netdev_alloc_skb() will cause skb->data to be misaligned + * to a cache line boundary. If this is the case, include + * some extra space to allow re-aligning the data area. + */ + mp->skb_size += SKB_DMA_REALIGN; } static int mv643xx_eth_open(struct net_device *dev) @@ -2366,6 +2373,8 @@ static int mv643xx_eth_open(struct net_device *dev) skb_queue_head_init(&mp->rx_recycle); + mp->int_mask = INT_EXT; + for (i = 0; i < mp->rxq_count; i++) { err = rxq_init(mp, i); if (err) { @@ -2375,6 +2384,7 @@ static int mv643xx_eth_open(struct net_device *dev) } rxq_refill(mp->rxq + i, INT_MAX); + mp->int_mask |= INT_RX_0 << i; } if (mp->oom) { @@ -2389,12 +2399,13 @@ static int mv643xx_eth_open(struct net_device *dev) txq_deinit(mp->txq + i); goto out_free; } + mp->int_mask |= INT_TX_END_0 << i; } port_start(mp); wrlp(mp, INT_MASK_EXT, INT_EXT_LINK_PHY | INT_EXT_TX); - wrlp(mp, INT_MASK, INT_TX_END | INT_RX | INT_EXT); + wrlp(mp, INT_MASK, mp->int_mask); return 0; @@ -2538,7 +2549,7 @@ static void mv643xx_eth_netpoll(struct net_device *dev) mv643xx_eth_irq(dev->irq, dev); - wrlp(mp, INT_MASK, INT_TX_END | INT_RX | INT_EXT); + wrlp(mp, INT_MASK, mp->int_mask); } #endif diff --git a/drivers/net/mvme147.c b/drivers/net/mvme147.c index 435e5a847c43..93c709d63e2f 100644 --- a/drivers/net/mvme147.c +++ b/drivers/net/mvme147.c @@ -57,6 +57,17 @@ typedef void (*writerap_t)(void *, unsigned short); typedef void (*writerdp_t)(void *, unsigned short); typedef unsigned short (*readrdp_t)(void *); +static const struct net_device_ops lance_netdev_ops = { + .ndo_open = m147lance_open, + .ndo_stop = m147lance_close, + .ndo_start_xmit = lance_start_xmit, + .ndo_set_multicast_list = lance_set_multicast, + .ndo_tx_timeout = lance_tx_timeout, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, +}; + /* Initialise the one and only on-board 7990 */ struct net_device * __init mvme147lance_probe(int unit) { @@ -81,11 +92,7 @@ struct net_device * __init mvme147lance_probe(int unit) /* Fill the dev fields */ dev->base_addr = (unsigned long)MVME147_LANCE_BASE; - dev->open = &m147lance_open; - dev->stop = &m147lance_close; - dev->hard_start_xmit = &lance_start_xmit; - dev->set_multicast_list = &lance_set_multicast; - dev->tx_timeout = &lance_tx_timeout; + dev->netdev_ops = &lance_netdev_ops; dev->dma = 0; addr=(u_long *)ETHERNET_ADDRESS; diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index f2c4a665e93f..1f6e36ea669e 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -75,7 +75,7 @@ #include "myri10ge_mcp.h" #include "myri10ge_mcp_gen_header.h" -#define MYRI10GE_VERSION_STR "1.4.4-1.401" +#define MYRI10GE_VERSION_STR "1.5.0-1.418" MODULE_DESCRIPTION("Myricom 10G driver (10GbE)"); MODULE_AUTHOR("Maintainer: help@myri.com"); @@ -255,6 +255,7 @@ struct myri10ge_priv { u32 read_write_dma; u32 link_changes; u32 msg_enable; + unsigned int board_number; }; static char *myri10ge_fw_unaligned = "myri10ge_ethp_z8e.dat"; @@ -266,6 +267,13 @@ static char *myri10ge_fw_name = NULL; module_param(myri10ge_fw_name, charp, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(myri10ge_fw_name, "Firmware image name"); +#define MYRI10GE_MAX_BOARDS 8 +static char *myri10ge_fw_names[MYRI10GE_MAX_BOARDS] = + {[0 ... (MYRI10GE_MAX_BOARDS - 1)] = NULL }; +module_param_array_named(myri10ge_fw_names, myri10ge_fw_names, charp, NULL, + 0444); +MODULE_PARM_DESC(myri10ge_fw_name, "Firmware image names per board"); + static int myri10ge_ecrc_enable = 1; module_param(myri10ge_ecrc_enable, int, S_IRUGO); MODULE_PARM_DESC(myri10ge_ecrc_enable, "Enable Extended CRC on PCI-E"); @@ -319,10 +327,6 @@ static int myri10ge_debug = -1; /* defaults above */ module_param(myri10ge_debug, int, 0); MODULE_PARM_DESC(myri10ge_debug, "Debug level (0=none,...,16=all)"); -static int myri10ge_lro = 1; -module_param(myri10ge_lro, int, S_IRUGO); -MODULE_PARM_DESC(myri10ge_lro, "Enable large receive offload"); - static int myri10ge_lro_max_pkts = MYRI10GE_LRO_MAX_PKTS; module_param(myri10ge_lro_max_pkts, int, S_IRUGO); MODULE_PARM_DESC(myri10ge_lro_max_pkts, @@ -361,6 +365,8 @@ static inline void put_be32(__be32 val, __be32 __iomem * p) __raw_writel((__force __u32) val, (__force void __iomem *)p); } +static struct net_device_stats *myri10ge_get_stats(struct net_device *dev); + static int myri10ge_send_cmd(struct myri10ge_priv *mgp, u32 cmd, struct myri10ge_cmd *data, int atomic) @@ -1290,7 +1296,7 @@ myri10ge_rx_done(struct myri10ge_slice_state *ss, struct myri10ge_rx_buf *rx, remainder -= MYRI10GE_ALLOC_SIZE; } - if (mgp->csum_flag && myri10ge_lro) { + if (dev->features & NETIF_F_LRO) { rx_frags[0].page_offset += MXGEFW_PAD; rx_frags[0].size -= MXGEFW_PAD; len -= MXGEFW_PAD; @@ -1412,6 +1418,7 @@ myri10ge_clean_rx_done(struct myri10ge_slice_state *ss, int budget) { struct myri10ge_rx_done *rx_done = &ss->rx_done; struct myri10ge_priv *mgp = ss->mgp; + struct net_device *netdev = mgp->dev; unsigned long rx_bytes = 0; unsigned long rx_packets = 0; unsigned long rx_ok; @@ -1445,7 +1452,7 @@ myri10ge_clean_rx_done(struct myri10ge_slice_state *ss, int budget) ss->stats.rx_packets += rx_packets; ss->stats.rx_bytes += rx_bytes; - if (myri10ge_lro) + if (netdev->features & NETIF_F_LRO) lro_flush_all(&rx_done->lro_mgr); /* restock receive rings if needed */ @@ -1686,7 +1693,7 @@ myri10ge_get_ringparam(struct net_device *netdev, ring->rx_mini_max_pending = mgp->ss[0].rx_small.mask + 1; ring->rx_max_pending = mgp->ss[0].rx_big.mask + 1; ring->rx_jumbo_max_pending = 0; - ring->tx_max_pending = mgp->ss[0].rx_small.mask + 1; + ring->tx_max_pending = mgp->ss[0].tx.mask + 1; ring->rx_mini_pending = ring->rx_mini_max_pending; ring->rx_pending = ring->rx_max_pending; ring->rx_jumbo_pending = ring->rx_jumbo_max_pending; @@ -1706,12 +1713,17 @@ static u32 myri10ge_get_rx_csum(struct net_device *netdev) static int myri10ge_set_rx_csum(struct net_device *netdev, u32 csum_enabled) { struct myri10ge_priv *mgp = netdev_priv(netdev); + int err = 0; if (csum_enabled) mgp->csum_flag = MXGEFW_FLAGS_CKSUM; - else + else { + u32 flags = ethtool_op_get_flags(netdev); + err = ethtool_op_set_flags(netdev, (flags & ~ETH_FLAG_LRO)); mgp->csum_flag = 0; - return 0; + + } + return err; } static int myri10ge_set_tso(struct net_device *netdev, u32 tso_enabled) @@ -1803,6 +1815,8 @@ myri10ge_get_ethtool_stats(struct net_device *netdev, int slice; int i; + /* force stats update */ + (void)myri10ge_get_stats(netdev); for (i = 0; i < MYRI10GE_NET_STATS_LEN; i++) data[i] = ((unsigned long *)&mgp->stats)[i]; @@ -1892,7 +1906,9 @@ static const struct ethtool_ops myri10ge_ethtool_ops = { .get_sset_count = myri10ge_get_sset_count, .get_ethtool_stats = myri10ge_get_ethtool_stats, .set_msglevel = myri10ge_set_msglevel, - .get_msglevel = myri10ge_get_msglevel + .get_msglevel = myri10ge_get_msglevel, + .get_flags = ethtool_op_get_flags, + .set_flags = ethtool_op_set_flags }; static int myri10ge_allocate_rings(struct myri10ge_slice_state *ss) @@ -2671,7 +2687,7 @@ again: /* we are out of transmit resources */ tx->stop_queue++; netif_tx_stop_queue(netdev_queue); - return 1; + return NETDEV_TX_BUSY; } /* Setup checksum offloading, if needed */ @@ -2876,7 +2892,6 @@ again: tx->stop_queue++; netif_tx_stop_queue(netdev_queue); } - dev->trans_start = jiffies; return 0; abort_linearize: @@ -2969,6 +2984,7 @@ static struct net_device_stats *myri10ge_get_stats(struct net_device *dev) struct net_device_stats *stats = &mgp->stats; int i; + spin_lock(&mgp->stats_lock); memset(stats, 0, sizeof(*stats)); for (i = 0; i < mgp->num_slices; i++) { slice_stats = &mgp->ss[i].stats; @@ -2979,6 +2995,7 @@ static struct net_device_stats *myri10ge_get_stats(struct net_device *dev) stats->rx_dropped += slice_stats->rx_dropped; stats->tx_dropped += slice_stats->tx_dropped; } + spin_unlock(&mgp->stats_lock); return stats; } @@ -3253,6 +3270,8 @@ abort: static void myri10ge_select_firmware(struct myri10ge_priv *mgp) { + int overridden = 0; + if (myri10ge_force_firmware == 0) { int link_width, exp_cap; u16 lnk; @@ -3286,10 +3305,18 @@ static void myri10ge_select_firmware(struct myri10ge_priv *mgp) } } if (myri10ge_fw_name != NULL) { - dev_info(&mgp->pdev->dev, "overriding firmware to %s\n", - myri10ge_fw_name); + overridden = 1; mgp->fw_name = myri10ge_fw_name; } + if (mgp->board_number < MYRI10GE_MAX_BOARDS && + myri10ge_fw_names[mgp->board_number] != NULL && + strlen(myri10ge_fw_names[mgp->board_number])) { + mgp->fw_name = myri10ge_fw_names[mgp->board_number]; + overridden = 1; + } + if (overridden) + dev_info(&mgp->pdev->dev, "overriding firmware to %s\n", + mgp->fw_name); } #ifdef CONFIG_PM @@ -3754,6 +3781,7 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) int status = -ENXIO; int dac_enabled; unsigned hdr_offset, ss_offset; + static int board_number; netdev = alloc_etherdev_mq(sizeof(*mgp), MYRI10GE_MAX_SLICES); if (netdev == NULL) { @@ -3770,6 +3798,7 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) mgp->pause = myri10ge_flow_control; mgp->intr_coal_delay = myri10ge_intr_coal_delay; mgp->msg_enable = netif_msg_init(myri10ge_debug, MYRI10GE_MSG_DEFAULT); + mgp->board_number = board_number; init_waitqueue_head(&mgp->down_wq); if (pci_enable_device(pdev)) { @@ -3884,6 +3913,13 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (dac_enabled) netdev->features |= NETIF_F_HIGHDMA; + netdev->features |= NETIF_F_LRO; + + netdev->vlan_features |= mgp->features; + if (mgp->fw_ver_tiny < 37) + netdev->vlan_features &= ~NETIF_F_TSO6; + if (mgp->fw_ver_tiny < 32) + netdev->vlan_features &= ~NETIF_F_TSO; /* make sure we can get an irq, and that MSI can be * setup (if available). Also ensure netdev->irq @@ -3902,6 +3938,7 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) setup_timer(&mgp->watchdog_timer, myri10ge_watchdog_timer, (unsigned long)mgp); + spin_lock_init(&mgp->stats_lock); SET_ETHTOOL_OPS(netdev, &myri10ge_ethtool_ops); INIT_WORK(&mgp->watchdog_work, myri10ge_watchdog); status = register_netdev(netdev); @@ -3919,6 +3956,7 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netdev->irq, mgp->tx_boundary, mgp->fw_name, (mgp->wc_enabled ? "Enabled" : "Disabled")); + board_number++; return 0; abort_with_state: @@ -4008,6 +4046,8 @@ static struct pci_device_id myri10ge_pci_tbl[] = { {0}, }; +MODULE_DEVICE_TABLE(pci, myri10ge_pci_tbl); + static struct pci_driver myri10ge_driver = { .name = "myri10ge", .probe = myri10ge_probe, diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c index 9a802adba9a3..5f0758bda6b3 100644 --- a/drivers/net/myri_sbus.c +++ b/drivers/net/myri_sbus.c @@ -640,7 +640,7 @@ static int myri_start_xmit(struct sk_buff *skb, struct net_device *dev) if (!TX_BUFFS_AVAIL(head, tail)) { DTX(("no buffs available, returning 1\n")); - return 1; + return NETDEV_TX_BUSY; } spin_lock_irqsave(&mp->irq_lock, flags); diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c index 7d83896b8c26..3fcebb70151c 100644 --- a/drivers/net/ne2k-pci.c +++ b/drivers/net/ne2k-pci.c @@ -374,7 +374,7 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev, dev->ethtool_ops = &ne2k_pci_ethtool_ops; NS8390_init(dev, 0); - memcpy(dev->dev_addr, SA_prom, 6); + memcpy(dev->dev_addr, SA_prom, dev->addr_len); memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); i = register_netdev(dev); diff --git a/drivers/net/ne3210.c b/drivers/net/ne3210.c index 6a843f7350ab..a00bbfb9aed0 100644 --- a/drivers/net/ne3210.c +++ b/drivers/net/ne3210.c @@ -104,7 +104,7 @@ static int __init ne3210_eisa_probe (struct device *device) } SET_NETDEV_DEV(dev, device); - device->driver_data = dev; + dev_set_drvdata(device, dev); ioaddr = edev->base_addr; if (!request_region(ioaddr, NE3210_IO_EXTENT, DRV_NAME)) { @@ -225,7 +225,7 @@ static int __init ne3210_eisa_probe (struct device *device) static int __devexit ne3210_eisa_remove (struct device *device) { - struct net_device *dev = device->driver_data; + struct net_device *dev = dev_get_drvdata(device); unsigned long ioaddr = to_eisa_device (device)->base_addr; unregister_netdev (dev); diff --git a/drivers/net/netx-eth.c b/drivers/net/netx-eth.c index 1861d5bbd96b..946366dcc992 100644 --- a/drivers/net/netx-eth.c +++ b/drivers/net/netx-eth.c @@ -301,6 +301,17 @@ netx_eth_phy_write(struct net_device *ndev, int phy_id, int reg, int value) while (readl(NETX_MIIMU) & MIIMU_SNRDY); } +static const struct net_device_ops netx_eth_netdev_ops = { + .ndo_open = netx_eth_open, + .ndo_stop = netx_eth_close, + .ndo_start_xmit = netx_eth_hard_start_xmit, + .ndo_tx_timeout = netx_eth_timeout, + .ndo_set_multicast_list = netx_eth_set_multicast_list, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, +}; + static int netx_eth_enable(struct net_device *ndev) { struct netx_eth_priv *priv = netdev_priv(ndev); @@ -309,12 +320,8 @@ static int netx_eth_enable(struct net_device *ndev) ether_setup(ndev); - ndev->open = netx_eth_open; - ndev->stop = netx_eth_close; - ndev->hard_start_xmit = netx_eth_hard_start_xmit; - ndev->tx_timeout = netx_eth_timeout; + ndev->netdev_ops = &netx_eth_netdev_ops; ndev->watchdog_timeo = msecs_to_jiffies(5000); - ndev->set_multicast_list = netx_eth_set_multicast_list; priv->msg_enable = NETIF_MSG_LINK; priv->mii.phy_id_mask = 0x1f; diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index c40815169f35..970cedeb5f37 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -34,10 +34,6 @@ #include #include #include -#include -#include -#include -#include #include #include #include @@ -46,21 +42,16 @@ #include #include #include +#include #include #include -#include #include -#include -#include #include -#include #include #include -#include -#include #include "netxen_nic_hw.h" @@ -84,10 +75,10 @@ (sizeof(struct netxen_rx_buffer) * rds_ring->num_desc) #define STATUS_DESC_RINGSIZE(sds_ring) \ (sizeof(struct status_desc) * (sds_ring)->num_desc) -#define TX_BUFF_RINGSIZE(adapter) \ - (sizeof(struct netxen_cmd_buffer) * adapter->num_txd) -#define TX_DESC_RINGSIZE(adapter) \ - (sizeof(struct cmd_desc_type0) * adapter->num_txd) +#define TX_BUFF_RINGSIZE(tx_ring) \ + (sizeof(struct netxen_cmd_buffer) * tx_ring->num_desc) +#define TX_DESC_RINGSIZE(tx_ring) \ + (sizeof(struct cmd_desc_type0) * tx_ring->num_desc) #define find_diff_among(a,b,range) ((a)<(b)?((b)-(a)):((b)+(range)-(a))) @@ -118,6 +109,7 @@ #define NX_P3_A2 0x30 #define NX_P3_B0 0x40 #define NX_P3_B1 0x41 +#define NX_P3_B2 0x42 #define NX_IS_REVISION_P2(REVISION) (REVISION <= NX_P2_C1) #define NX_IS_REVISION_P3(REVISION) (REVISION >= NX_P3_A0) @@ -177,6 +169,7 @@ #define MAX_NUM_CARDS 4 #define MAX_BUFFERS_PER_CMD 32 +#define TX_STOP_THRESH ((MAX_SKB_FRAGS >> 2) + 4) /* * Following are the states of the Phantom. Phantom will set them and @@ -203,18 +196,10 @@ #define MAX_RCV_DESCRIPTORS_10G 4096 #define MAX_JUMBO_RCV_DESCRIPTORS 1024 #define MAX_LRO_RCV_DESCRIPTORS 8 -#define MAX_RCVSTATUS_DESCRIPTORS MAX_RCV_DESCRIPTORS -#define MAX_JUMBO_RCV_DESC MAX_JUMBO_RCV_DESCRIPTORS -#define MAX_RCV_DESC MAX_RCV_DESCRIPTORS -#define MAX_RCVSTATUS_DESC MAX_RCV_DESCRIPTORS -#define MAX_EPG_DESCRIPTORS (MAX_CMD_DESCRIPTORS * 8) -#define NUM_RCV_DESC (MAX_RCV_DESC + MAX_JUMBO_RCV_DESCRIPTORS + \ - MAX_LRO_RCV_DESCRIPTORS) -#define MIN_TX_COUNT 4096 -#define MIN_RX_COUNT 4096 #define NETXEN_CTX_SIGNATURE 0xdee0 +#define NETXEN_CTX_SIGNATURE_V2 0x0002dee0 +#define NETXEN_CTX_RESET 0xbad0 #define NETXEN_RCV_PRODUCER(ringid) (ringid) -#define MAX_FRAME_SIZE 0x10000 /* 64K MAX size for LSO */ #define PHAN_PEG_RCV_INITIALIZED 0xff01 #define PHAN_PEG_RCV_START_INITIALIZE 0xff00 @@ -253,12 +238,19 @@ typedef u32 netxen_ctx_msg; #define netxen_set_msg_opcode(config_word, val) \ ((config_word) &= ~(0xf<<28), (config_word) |= (val & 0xf) << 28) -struct netxen_rcv_context { - __le64 rcv_ring_addr; - __le32 rcv_ring_size; +struct netxen_rcv_ring { + __le64 addr; + __le32 size; __le32 rsrvd; }; +struct netxen_sts_ring { + __le64 addr; + __le32 size; + __le16 msi_index; + __le16 rsvd; +} ; + struct netxen_ring_ctx { /* one command ring */ @@ -268,13 +260,18 @@ struct netxen_ring_ctx { __le32 rsrvd; /* three receive rings */ - struct netxen_rcv_context rcv_ctx[3]; + struct netxen_rcv_ring rcv_rings[NUM_RCV_DESC_RINGS]; - /* one status ring */ __le64 sts_ring_addr; __le32 sts_ring_size; __le32 ctx_id; + + __le64 rsrvd_2[3]; + __le32 sts_ring_count; + __le32 rsrvd_3; + struct netxen_sts_ring sts_rings[NUM_STS_DESC_RINGS]; + } __attribute__ ((aligned(64))); /* @@ -373,6 +370,7 @@ struct rcv_desc { /* opcode field in status_desc */ #define NETXEN_NIC_RXPKT_DESC 0x04 #define NETXEN_OLD_RXPKT_DESC 0x3f +#define NETXEN_NIC_RESPONSE_DESC 0x05 /* for status field in status_desc */ #define STATUS_NEED_CKSUM (1) @@ -382,13 +380,11 @@ struct rcv_desc { #define STATUS_OWNER_HOST (0x1ULL << 56) #define STATUS_OWNER_PHANTOM (0x2ULL << 56) -/* Note: sizeof(status_desc) should always be a mutliple of 2 */ - -#define netxen_get_sts_desc_lro_cnt(status_desc) \ - ((status_desc)->lro & 0x7F) -#define netxen_get_sts_desc_lro_last_frag(status_desc) \ - (((status_desc)->lro & 0x80) >> 7) - +/* Status descriptor: + 0-3 port, 4-7 status, 8-11 type, 12-27 total_length + 28-43 reference_handle, 44-47 protocol, 48-52 pkt_offset + 53-55 desc_cnt, 56-57 owner, 58-63 opcode + */ #define netxen_get_sts_port(sts_data) \ ((sts_data) & 0x0F) #define netxen_get_sts_status(sts_data) \ @@ -403,41 +399,15 @@ struct rcv_desc { (((sts_data) >> 44) & 0x0F) #define netxen_get_sts_pkt_offset(sts_data) \ (((sts_data) >> 48) & 0x1F) +#define netxen_get_sts_desc_cnt(sts_data) \ + (((sts_data) >> 53) & 0x7) #define netxen_get_sts_opcode(sts_data) \ (((sts_data) >> 58) & 0x03F) struct status_desc { - /* Bit pattern: 0-3 port, 4-7 status, 8-11 type, 12-27 total_length - 28-43 reference_handle, 44-47 protocol, 48-52 pkt_offset - 53-55 desc_cnt, 56-57 owner, 58-63 opcode - */ - __le64 status_desc_data; - union { - struct { - __le32 hash_value; - u8 hash_type; - u8 msg_type; - u8 unused; - union { - /* Bit pattern: 0-6 lro_count indicates frag - * sequence, 7 last_frag indicates last frag - */ - u8 lro; - - /* chained buffers */ - u8 nr_frags; - }; - }; - struct { - __le16 frag_handles[4]; - }; - }; + __le64 status_desc_data[2]; } __attribute__ ((aligned(16))); -enum { - NETXEN_RCV_PEG_0 = 0, - NETXEN_RCV_PEG_1 -}; /* The version of the main data structure */ #define NETXEN_BDINFO_VERSION 1 @@ -447,85 +417,35 @@ enum { /* Max number of Gig ports on a Phantom board */ #define NETXEN_MAX_PORTS 4 -typedef enum { - NETXEN_BRDTYPE_P1_BD = 0x0000, - NETXEN_BRDTYPE_P1_SB = 0x0001, - NETXEN_BRDTYPE_P1_SMAX = 0x0002, - NETXEN_BRDTYPE_P1_SOCK = 0x0003, +#define NETXEN_BRDTYPE_P1_BD 0x0000 +#define NETXEN_BRDTYPE_P1_SB 0x0001 +#define NETXEN_BRDTYPE_P1_SMAX 0x0002 +#define NETXEN_BRDTYPE_P1_SOCK 0x0003 - NETXEN_BRDTYPE_P2_SOCK_31 = 0x0008, - NETXEN_BRDTYPE_P2_SOCK_35 = 0x0009, - NETXEN_BRDTYPE_P2_SB35_4G = 0x000a, - NETXEN_BRDTYPE_P2_SB31_10G = 0x000b, - NETXEN_BRDTYPE_P2_SB31_2G = 0x000c, +#define NETXEN_BRDTYPE_P2_SOCK_31 0x0008 +#define NETXEN_BRDTYPE_P2_SOCK_35 0x0009 +#define NETXEN_BRDTYPE_P2_SB35_4G 0x000a +#define NETXEN_BRDTYPE_P2_SB31_10G 0x000b +#define NETXEN_BRDTYPE_P2_SB31_2G 0x000c - NETXEN_BRDTYPE_P2_SB31_10G_IMEZ = 0x000d, - NETXEN_BRDTYPE_P2_SB31_10G_HMEZ = 0x000e, - NETXEN_BRDTYPE_P2_SB31_10G_CX4 = 0x000f, +#define NETXEN_BRDTYPE_P2_SB31_10G_IMEZ 0x000d +#define NETXEN_BRDTYPE_P2_SB31_10G_HMEZ 0x000e +#define NETXEN_BRDTYPE_P2_SB31_10G_CX4 0x000f - NETXEN_BRDTYPE_P3_REF_QG = 0x0021, - NETXEN_BRDTYPE_P3_HMEZ = 0x0022, - NETXEN_BRDTYPE_P3_10G_CX4_LP = 0x0023, - NETXEN_BRDTYPE_P3_4_GB = 0x0024, - NETXEN_BRDTYPE_P3_IMEZ = 0x0025, - NETXEN_BRDTYPE_P3_10G_SFP_PLUS = 0x0026, - NETXEN_BRDTYPE_P3_10000_BASE_T = 0x0027, - NETXEN_BRDTYPE_P3_XG_LOM = 0x0028, - NETXEN_BRDTYPE_P3_4_GB_MM = 0x0029, - NETXEN_BRDTYPE_P3_10G_SFP_CT = 0x002a, - NETXEN_BRDTYPE_P3_10G_SFP_QT = 0x002b, - NETXEN_BRDTYPE_P3_10G_CX4 = 0x0031, - NETXEN_BRDTYPE_P3_10G_XFP = 0x0032, - NETXEN_BRDTYPE_P3_10G_TP = 0x0080 - -} netxen_brdtype_t; - -typedef enum { - NETXEN_BRDMFG_INVENTEC = 1 -} netxen_brdmfg; - -typedef enum { - MEM_ORG_128Mbx4 = 0x0, /* DDR1 only */ - MEM_ORG_128Mbx8 = 0x1, /* DDR1 only */ - MEM_ORG_128Mbx16 = 0x2, /* DDR1 only */ - MEM_ORG_256Mbx4 = 0x3, - MEM_ORG_256Mbx8 = 0x4, - MEM_ORG_256Mbx16 = 0x5, - MEM_ORG_512Mbx4 = 0x6, - MEM_ORG_512Mbx8 = 0x7, - MEM_ORG_512Mbx16 = 0x8, - MEM_ORG_1Gbx4 = 0x9, - MEM_ORG_1Gbx8 = 0xa, - MEM_ORG_1Gbx16 = 0xb, - MEM_ORG_2Gbx4 = 0xc, - MEM_ORG_2Gbx8 = 0xd, - MEM_ORG_2Gbx16 = 0xe, - MEM_ORG_128Mbx32 = 0x10002, /* GDDR only */ - MEM_ORG_256Mbx32 = 0x10005 /* GDDR only */ -} netxen_mn_mem_org_t; - -typedef enum { - MEM_ORG_512Kx36 = 0x0, - MEM_ORG_1Mx36 = 0x1, - MEM_ORG_2Mx36 = 0x2 -} netxen_sn_mem_org_t; - -typedef enum { - MEM_DEPTH_4MB = 0x1, - MEM_DEPTH_8MB = 0x2, - MEM_DEPTH_16MB = 0x3, - MEM_DEPTH_32MB = 0x4, - MEM_DEPTH_64MB = 0x5, - MEM_DEPTH_128MB = 0x6, - MEM_DEPTH_256MB = 0x7, - MEM_DEPTH_512MB = 0x8, - MEM_DEPTH_1GB = 0x9, - MEM_DEPTH_2GB = 0xa, - MEM_DEPTH_4GB = 0xb, - MEM_DEPTH_8GB = 0xc, - MEM_DEPTH_16GB = 0xd, - MEM_DEPTH_32GB = 0xe -} netxen_mem_depth_t; +#define NETXEN_BRDTYPE_P3_REF_QG 0x0021 +#define NETXEN_BRDTYPE_P3_HMEZ 0x0022 +#define NETXEN_BRDTYPE_P3_10G_CX4_LP 0x0023 +#define NETXEN_BRDTYPE_P3_4_GB 0x0024 +#define NETXEN_BRDTYPE_P3_IMEZ 0x0025 +#define NETXEN_BRDTYPE_P3_10G_SFP_PLUS 0x0026 +#define NETXEN_BRDTYPE_P3_10000_BASE_T 0x0027 +#define NETXEN_BRDTYPE_P3_XG_LOM 0x0028 +#define NETXEN_BRDTYPE_P3_4_GB_MM 0x0029 +#define NETXEN_BRDTYPE_P3_10G_SFP_CT 0x002a +#define NETXEN_BRDTYPE_P3_10G_SFP_QT 0x002b +#define NETXEN_BRDTYPE_P3_10G_CX4 0x0031 +#define NETXEN_BRDTYPE_P3_10G_XFP 0x0032 +#define NETXEN_BRDTYPE_P3_10G_TP 0x0080 struct netxen_board_info { u32 header_version; @@ -676,17 +596,15 @@ struct netxen_new_user_info { #define PRIMARY_IMAGE_BAD 0xffffffff /* Flash memory map */ -typedef enum { - NETXEN_CRBINIT_START = 0, /* Crbinit section */ - NETXEN_BRDCFG_START = 0x4000, /* board config */ - NETXEN_INITCODE_START = 0x6000, /* pegtune code */ - NETXEN_BOOTLD_START = 0x10000, /* bootld */ - NETXEN_IMAGE_START = 0x43000, /* compressed image */ - NETXEN_SECONDARY_START = 0x200000, /* backup images */ - NETXEN_PXE_START = 0x3E0000, /* user defined region */ - NETXEN_USER_START = 0x3E8000, /* User defined region for new boards */ - NETXEN_FIXED_START = 0x3F0000 /* backup of crbinit */ -} netxen_flash_map_t; +#define NETXEN_CRBINIT_START 0 /* crbinit section */ +#define NETXEN_BRDCFG_START 0x4000 /* board config */ +#define NETXEN_INITCODE_START 0x6000 /* pegtune code */ +#define NETXEN_BOOTLD_START 0x10000 /* bootld */ +#define NETXEN_IMAGE_START 0x43000 /* compressed image */ +#define NETXEN_SECONDARY_START 0x200000 /* backup images */ +#define NETXEN_PXE_START 0x3E0000 /* PXE boot rom */ +#define NETXEN_USER_START 0x3E8000 /* Firmare info */ +#define NETXEN_FIXED_START 0x3F0000 /* backup of crbinit */ #define NX_FW_VERSION_OFFSET (NETXEN_USER_START+0x408) #define NX_FW_SIZE_OFFSET (NETXEN_USER_START+0x40c) @@ -708,21 +626,8 @@ typedef enum { #define NETXEN_FLASH_SECONDARY_SIZE (NETXEN_USER_START-NETXEN_SECONDARY_START) #define NETXEN_NUM_PRIMARY_SECTORS (0x20) #define NETXEN_NUM_CONFIG_SECTORS (1) -#define PFX "NetXen: " extern char netxen_nic_driver_name[]; -/* Note: Make sure to not call this before adapter->port is valid */ -#if !defined(NETXEN_DEBUG) -#define DPRINTK(klevel, fmt, args...) do { \ - } while (0) -#else -#define DPRINTK(klevel, fmt, args...) do { \ - printk(KERN_##klevel PFX "%s: %s: " fmt, __func__,\ - (adapter != NULL && adapter->netdev != NULL) ? \ - adapter->netdev->name : NULL, \ - ## args); } while(0) -#endif - /* Number of status descriptors to handle per interrupt */ #define MAX_STATUS_HANDLE (64) @@ -732,7 +637,7 @@ extern char netxen_nic_driver_name[]; */ struct netxen_skb_frag { u64 dma; - ulong length; + u64 length; }; #define _netxen_set_bits(config_word, start, bits, val) {\ @@ -793,34 +698,24 @@ struct netxen_hardware_context { u8 cut_through; u8 revision_id; + u8 pci_func; + u8 linkup; u16 port_type; - int board_type; - u32 linkup; - /* Address of cmd ring in Phantom */ - struct cmd_desc_type0 *cmd_desc_head; - dma_addr_t cmd_desc_phys_addr; - struct netxen_adapter *adapter; - int pci_func; + u16 board_type; }; #define MINIMUM_ETHERNET_FRAME_SIZE 64 /* With FCS */ #define ETHERNET_FCS_SIZE 4 struct netxen_adapter_stats { - u64 rcvdbadskb; u64 xmitcalled; - u64 xmitedframes; u64 xmitfinished; - u64 badskblen; - u64 nocmddescriptor; - u64 polled; u64 rxdropped; u64 txdropped; u64 csummed; u64 no_rcv; u64 rxbytes; u64 txbytes; - u64 ints; }; /* @@ -852,14 +747,25 @@ struct nx_host_sds_ring { struct napi_struct napi; struct list_head free_list[NUM_RCV_DESC_RINGS]; - u16 clean_tx; - u16 post_rxd; int irq; dma_addr_t phys_addr; char name[IFNAMSIZ+4]; }; +struct nx_host_tx_ring { + u32 producer; + __le32 *hw_consumer; + u32 sw_consumer; + u32 crb_cmd_producer; + u32 crb_cmd_consumer; + u32 num_desc; + + struct netxen_cmd_buffer *cmd_buf_arr; + struct cmd_desc_type0 *desc_head; + dma_addr_t phys_addr; +}; + /* * Receive context. There is one such structure per instance of the * receive processing. Any state information that is relevant to @@ -871,8 +777,11 @@ struct netxen_recv_context { u16 context_id; u16 virt_port; - struct nx_host_rds_ring rds_rings[NUM_RCV_DESC_RINGS]; - struct nx_host_sds_ring sds_rings[NUM_STS_DESC_RINGS]; + struct nx_host_rds_ring *rds_rings; + struct nx_host_sds_ring *sds_rings; + + struct netxen_ring_ctx *hwctx; + dma_addr_t phys_addr; }; /* New HW context creation */ @@ -1111,8 +1020,8 @@ typedef struct { #define NETXEN_MAC_DEL 2 typedef struct nx_mac_list_s { - struct nx_mac_list_s *next; - uint8_t mac_addr[MAX_ADDR_LEN]; + struct list_head list; + uint8_t mac_addr[ETH_ALEN+2]; } nx_mac_list_t; /* @@ -1154,31 +1063,118 @@ typedef struct { #define NX_MAC_EVENT 0x1 -enum { - NX_NIC_H2C_OPCODE_START = 0, - NX_NIC_H2C_OPCODE_CONFIG_RSS, - NX_NIC_H2C_OPCODE_CONFIG_RSS_TBL, - NX_NIC_H2C_OPCODE_CONFIG_INTR_COALESCE, - NX_NIC_H2C_OPCODE_CONFIG_LED, - NX_NIC_H2C_OPCODE_CONFIG_PROMISCUOUS, - NX_NIC_H2C_OPCODE_CONFIG_L2_MAC, - NX_NIC_H2C_OPCODE_LRO_REQUEST, - NX_NIC_H2C_OPCODE_GET_SNMP_STATS, - NX_NIC_H2C_OPCODE_PROXY_START_REQUEST, - NX_NIC_H2C_OPCODE_PROXY_STOP_REQUEST, - NX_NIC_H2C_OPCODE_PROXY_SET_MTU, - NX_NIC_H2C_OPCODE_PROXY_SET_VPORT_MISS_MODE, - NX_H2P_OPCODE_GET_FINGER_PRINT_REQUEST, - NX_H2P_OPCODE_INSTALL_LICENSE_REQUEST, - NX_H2P_OPCODE_GET_LICENSE_CAPABILITY_REQUEST, - NX_NIC_H2C_OPCODE_GET_NET_STATS, - NX_NIC_H2C_OPCODE_LAST -}; +/* + * Driver --> Firmware + */ +#define NX_NIC_H2C_OPCODE_START 0 +#define NX_NIC_H2C_OPCODE_CONFIG_RSS 1 +#define NX_NIC_H2C_OPCODE_CONFIG_RSS_TBL 2 +#define NX_NIC_H2C_OPCODE_CONFIG_INTR_COALESCE 3 +#define NX_NIC_H2C_OPCODE_CONFIG_LED 4 +#define NX_NIC_H2C_OPCODE_CONFIG_PROMISCUOUS 5 +#define NX_NIC_H2C_OPCODE_CONFIG_L2_MAC 6 +#define NX_NIC_H2C_OPCODE_LRO_REQUEST 7 +#define NX_NIC_H2C_OPCODE_GET_SNMP_STATS 8 +#define NX_NIC_H2C_OPCODE_PROXY_START_REQUEST 9 +#define NX_NIC_H2C_OPCODE_PROXY_STOP_REQUEST 10 +#define NX_NIC_H2C_OPCODE_PROXY_SET_MTU 11 +#define NX_NIC_H2C_OPCODE_PROXY_SET_VPORT_MISS_MODE 12 +#define NX_NIC_H2C_OPCODE_GET_FINGER_PRINT_REQUEST 13 +#define NX_NIC_H2C_OPCODE_INSTALL_LICENSE_REQUEST 14 +#define NX_NIC_H2C_OPCODE_GET_LICENSE_CAPABILITY_REQUEST 15 +#define NX_NIC_H2C_OPCODE_GET_NET_STATS 16 +#define NX_NIC_H2C_OPCODE_PROXY_UPDATE_P2V 17 +#define NX_NIC_H2C_OPCODE_CONFIG_IPADDR 18 +#define NX_NIC_H2C_OPCODE_CONFIG_LOOPBACK 19 +#define NX_NIC_H2C_OPCODE_PROXY_STOP_DONE 20 +#define NX_NIC_H2C_OPCODE_GET_LINKEVENT 21 +#define NX_NIC_C2C_OPCODE 22 +#define NX_NIC_H2C_OPCODE_LAST 23 + +/* + * Firmware --> Driver + */ + +#define NX_NIC_C2H_OPCODE_START 128 +#define NX_NIC_C2H_OPCODE_CONFIG_RSS_RESPONSE 129 +#define NX_NIC_C2H_OPCODE_CONFIG_RSS_TBL_RESPONSE 130 +#define NX_NIC_C2H_OPCODE_CONFIG_MAC_RESPONSE 131 +#define NX_NIC_C2H_OPCODE_CONFIG_PROMISCUOUS_RESPONSE 132 +#define NX_NIC_C2H_OPCODE_CONFIG_L2_MAC_RESPONSE 133 +#define NX_NIC_C2H_OPCODE_LRO_DELETE_RESPONSE 134 +#define NX_NIC_C2H_OPCODE_LRO_ADD_FAILURE_RESPONSE 135 +#define NX_NIC_C2H_OPCODE_GET_SNMP_STATS 136 +#define NX_NIC_C2H_OPCODE_GET_FINGER_PRINT_REPLY 137 +#define NX_NIC_C2H_OPCODE_INSTALL_LICENSE_REPLY 138 +#define NX_NIC_C2H_OPCODE_GET_LICENSE_CAPABILITIES_REPLY 139 +#define NX_NIC_C2H_OPCODE_GET_NET_STATS_RESPONSE 140 +#define NX_NIC_C2H_OPCODE_GET_LINKEVENT_RESPONSE 141 +#define NX_NIC_C2H_OPCODE_LAST 142 #define VPORT_MISS_MODE_DROP 0 /* drop all unmatched */ #define VPORT_MISS_MODE_ACCEPT_ALL 1 /* accept all packets */ #define VPORT_MISS_MODE_ACCEPT_MULTI 2 /* accept unmatched multicast */ +#define NX_FW_CAPABILITY_LINK_NOTIFICATION (1 << 5) +#define NX_FW_CAPABILITY_SWITCHING (1 << 6) + +/* module types */ +#define LINKEVENT_MODULE_NOT_PRESENT 1 +#define LINKEVENT_MODULE_OPTICAL_UNKNOWN 2 +#define LINKEVENT_MODULE_OPTICAL_SRLR 3 +#define LINKEVENT_MODULE_OPTICAL_LRM 4 +#define LINKEVENT_MODULE_OPTICAL_SFP_1G 5 +#define LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLE 6 +#define LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLELEN 7 +#define LINKEVENT_MODULE_TWINAX 8 + +#define LINKSPEED_10GBPS 10000 +#define LINKSPEED_1GBPS 1000 +#define LINKSPEED_100MBPS 100 +#define LINKSPEED_10MBPS 10 + +#define LINKSPEED_ENCODED_10MBPS 0 +#define LINKSPEED_ENCODED_100MBPS 1 +#define LINKSPEED_ENCODED_1GBPS 2 + +#define LINKEVENT_AUTONEG_DISABLED 0 +#define LINKEVENT_AUTONEG_ENABLED 1 + +#define LINKEVENT_HALF_DUPLEX 0 +#define LINKEVENT_FULL_DUPLEX 1 + +#define LINKEVENT_LINKSPEED_MBPS 0 +#define LINKEVENT_LINKSPEED_ENCODED 1 + +/* firmware response header: + * 63:58 - message type + * 57:56 - owner + * 55:53 - desc count + * 52:48 - reserved + * 47:40 - completion id + * 39:32 - opcode + * 31:16 - error code + * 15:00 - reserved + */ +#define netxen_get_nic_msgtype(msg_hdr) \ + ((msg_hdr >> 58) & 0x3F) +#define netxen_get_nic_msg_compid(msg_hdr) \ + ((msg_hdr >> 40) & 0xFF) +#define netxen_get_nic_msg_opcode(msg_hdr) \ + ((msg_hdr >> 32) & 0xFF) +#define netxen_get_nic_msg_errcode(msg_hdr) \ + ((msg_hdr >> 16) & 0xFFFF) + +typedef struct { + union { + struct { + u64 hdr; + u64 body[7]; + }; + u64 words[8]; + }; +} nx_fw_msg_t; + typedef struct { __le64 qhdr; __le64 req_hdr; @@ -1218,99 +1214,96 @@ struct netxen_adapter { struct net_device *netdev; struct pci_dev *pdev; - int pci_using_dac; - struct net_device_stats net_stats; - int mtu; - int portnum; - u8 physical_port; - u16 tx_context_id; - - uint8_t mc_enabled; - uint8_t max_mc_count; - nx_mac_list_t *mac_list; - - struct netxen_legacy_intr_set legacy_intr; - - struct work_struct watchdog_task; - struct timer_list watchdog_timer; - struct work_struct tx_timeout_task; + struct list_head mac_list; u32 curr_window; u32 crb_win; rwlock_t adapter_lock; - u32 cmd_producer; - __le32 *cmd_consumer; - u32 last_cmd_consumer; - u32 crb_addr_cmd_producer; - u32 crb_addr_cmd_consumer; spinlock_t tx_clean_lock; - u32 num_txd; - u32 num_rxd; - u32 num_jumbo_rxd; - u32 num_lro_rxd; + u16 num_txd; + u16 num_rxd; + u16 num_jumbo_rxd; + u16 num_lro_rxd; - int max_rds_rings; - int max_sds_rings; + u8 max_rds_rings; + u8 max_sds_rings; + u8 driver_mismatch; + u8 msix_supported; + u8 rx_csum; + u8 pci_using_dac; + u8 portnum; + u8 physical_port; - u32 flags; - u32 irq; - int driver_mismatch; - u32 temp; + u8 mc_enabled; + u8 max_mc_count; + u8 rss_supported; + u8 resv2; + u32 resv3; - u32 fw_major; - u32 fw_version; - - int msix_supported; - struct msix_entry msix_entries[MSIX_ENTRIES_PER_ADAPTER]; - - struct netxen_adapter_stats stats; + u8 has_link_events; + u8 resv1; + u16 tx_context_id; + u16 mtu; + u16 is_up; u16 link_speed; u16 link_duplex; - u16 state; u16 link_autoneg; - int rx_csum; + u16 module_type; - struct netxen_cmd_buffer *cmd_buf_arr; /* Command buffers for xmit */ + u32 capabilities; + u32 flags; + u32 irq; + u32 temp; + + u32 msi_tgt_status; + u32 resv4; + + struct netxen_adapter_stats stats; - /* - * Receive instances. These can be either one per port, - * or one per peg, etc. - */ struct netxen_recv_context recv_ctx; + struct nx_host_tx_ring *tx_ring; - int is_up; - struct netxen_dummy_dma dummy_dma; - nx_nic_intr_coalesce_t coal; - - /* Context interface shared between card and host */ - struct netxen_ring_ctx *ctx_desc; - dma_addr_t ctx_desc_phys_addr; - int intr_scheme; - int msi_mode; int (*enable_phy_interrupts) (struct netxen_adapter *); int (*disable_phy_interrupts) (struct netxen_adapter *); - int (*macaddr_set) (struct netxen_adapter *, netxen_ethernet_macaddr_t); + int (*macaddr_set) (struct netxen_adapter *, u8 *); int (*set_mtu) (struct netxen_adapter *, int); int (*set_promisc) (struct netxen_adapter *, u32); + void (*set_multi) (struct net_device *); int (*phy_read) (struct netxen_adapter *, long reg, u32 *); int (*phy_write) (struct netxen_adapter *, long reg, u32 val); int (*init_port) (struct netxen_adapter *, int); int (*stop_port) (struct netxen_adapter *); - int (*hw_read_wx)(struct netxen_adapter *, ulong, void *, int); - int (*hw_write_wx)(struct netxen_adapter *, ulong, void *, int); + u32 (*hw_read_wx)(struct netxen_adapter *, ulong); + int (*hw_write_wx)(struct netxen_adapter *, ulong, u32); int (*pci_mem_read)(struct netxen_adapter *, u64, void *, int); int (*pci_mem_write)(struct netxen_adapter *, u64, void *, int); int (*pci_write_immediate)(struct netxen_adapter *, u64, u32); u32 (*pci_read_immediate)(struct netxen_adapter *, u64); - void (*pci_write_normalize)(struct netxen_adapter *, u64, u32); - u32 (*pci_read_normalize)(struct netxen_adapter *, u64); unsigned long (*pci_set_window)(struct netxen_adapter *, unsigned long long); -}; /* netxen_adapter structure */ + + struct netxen_legacy_intr_set legacy_intr; + + struct msix_entry msix_entries[MSIX_ENTRIES_PER_ADAPTER]; + + struct netxen_dummy_dma dummy_dma; + + struct work_struct watchdog_task; + struct timer_list watchdog_timer; + struct work_struct tx_timeout_task; + + struct net_device_stats net_stats; + + nx_nic_intr_coalesce_t coal; + + u32 fw_major; + u32 fw_version; + const struct firmware *fw; +}; /* * NetXen dma watchdog control structure @@ -1330,46 +1323,6 @@ struct netxen_adapter { #define netxen_get_dma_watchdog_disabled(config_word) \ (((config_word) >> 1) & 0x1) -/* Max number of xmit producer threads that can run simultaneously */ -#define MAX_XMIT_PRODUCERS 16 - -#define PCI_OFFSET_FIRST_RANGE(adapter, off) \ - ((adapter)->ahw.pci_base0 + (off)) -#define PCI_OFFSET_SECOND_RANGE(adapter, off) \ - ((adapter)->ahw.pci_base1 + (off) - SECOND_PAGE_GROUP_START) -#define PCI_OFFSET_THIRD_RANGE(adapter, off) \ - ((adapter)->ahw.pci_base2 + (off) - THIRD_PAGE_GROUP_START) - -static inline void __iomem *pci_base_offset(struct netxen_adapter *adapter, - unsigned long off) -{ - if ((off < FIRST_PAGE_GROUP_END) && (off >= FIRST_PAGE_GROUP_START)) { - return (adapter->ahw.pci_base0 + off); - } else if ((off < SECOND_PAGE_GROUP_END) && - (off >= SECOND_PAGE_GROUP_START)) { - return (adapter->ahw.pci_base1 + off - SECOND_PAGE_GROUP_START); - } else if ((off < THIRD_PAGE_GROUP_END) && - (off >= THIRD_PAGE_GROUP_START)) { - return (adapter->ahw.pci_base2 + off - THIRD_PAGE_GROUP_START); - } - return NULL; -} - -static inline void __iomem *pci_base(struct netxen_adapter *adapter, - unsigned long off) -{ - if ((off < FIRST_PAGE_GROUP_END) && (off >= FIRST_PAGE_GROUP_START)) { - return adapter->ahw.pci_base0; - } else if ((off < SECOND_PAGE_GROUP_END) && - (off >= SECOND_PAGE_GROUP_START)) { - return adapter->ahw.pci_base1; - } else if ((off < THIRD_PAGE_GROUP_END) && - (off >= THIRD_PAGE_GROUP_START)) { - return adapter->ahw.pci_base2; - } - return NULL; -} - int netxen_niu_xgbe_enable_phy_interrupts(struct netxen_adapter *adapter); int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter); int netxen_niu_xgbe_disable_phy_interrupts(struct netxen_adapter *adapter); @@ -1382,21 +1335,22 @@ int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter, /* Functions available from netxen_nic_hw.c */ int netxen_nic_set_mtu_xgb(struct netxen_adapter *adapter, int new_mtu); int netxen_nic_set_mtu_gb(struct netxen_adapter *adapter, int new_mtu); -void netxen_nic_reg_write(struct netxen_adapter *adapter, u64 off, u32 val); -int netxen_nic_reg_read(struct netxen_adapter *adapter, u64 off); -void netxen_nic_write_w0(struct netxen_adapter *adapter, u32 index, u32 value); -void netxen_nic_read_w0(struct netxen_adapter *adapter, u32 index, u32 *value); -void netxen_nic_write_w1(struct netxen_adapter *adapter, u32 index, u32 value); -void netxen_nic_read_w1(struct netxen_adapter *adapter, u32 index, u32 *value); + +int netxen_p2_nic_set_mac_addr(struct netxen_adapter *adapter, u8 *addr); +int netxen_p3_nic_set_mac_addr(struct netxen_adapter *adapter, u8 *addr); + +#define NXRD32(adapter, off) \ + (adapter->hw_read_wx(adapter, off)) +#define NXWR32(adapter, off, val) \ + (adapter->hw_write_wx(adapter, off, val)) int netxen_nic_get_board_info(struct netxen_adapter *adapter); void netxen_nic_get_firmware_info(struct netxen_adapter *adapter); int netxen_nic_wol_supported(struct netxen_adapter *adapter); -int netxen_nic_hw_read_wx_128M(struct netxen_adapter *adapter, - ulong off, void *data, int len); +u32 netxen_nic_hw_read_wx_128M(struct netxen_adapter *adapter, ulong off); int netxen_nic_hw_write_wx_128M(struct netxen_adapter *adapter, - ulong off, void *data, int len); + ulong off, u32 data); int netxen_nic_pci_mem_read_128M(struct netxen_adapter *adapter, u64 off, void *data, int size); int netxen_nic_pci_mem_write_128M(struct netxen_adapter *adapter, @@ -1412,16 +1366,13 @@ unsigned long netxen_nic_pci_set_window_128M(struct netxen_adapter *adapter, void netxen_nic_pci_change_crbwindow_128M(struct netxen_adapter *adapter, u32 wndw); -int netxen_nic_hw_read_wx_2M(struct netxen_adapter *adapter, - ulong off, void *data, int len); +u32 netxen_nic_hw_read_wx_2M(struct netxen_adapter *adapter, ulong off); int netxen_nic_hw_write_wx_2M(struct netxen_adapter *adapter, - ulong off, void *data, int len); + ulong off, u32 data); int netxen_nic_pci_mem_read_2M(struct netxen_adapter *adapter, u64 off, void *data, int size); int netxen_nic_pci_mem_write_2M(struct netxen_adapter *adapter, u64 off, void *data, int size); -void netxen_crb_writelit_adapter(struct netxen_adapter *adapter, - unsigned long off, int data); int netxen_nic_pci_write_immediate_2M(struct netxen_adapter *adapter, u64 off, u32 data); u32 netxen_nic_pci_read_immediate_2M(struct netxen_adapter *adapter, u64 off); @@ -1435,8 +1386,9 @@ unsigned long netxen_nic_pci_set_window_2M(struct netxen_adapter *adapter, void netxen_free_adapter_offload(struct netxen_adapter *adapter); int netxen_initialize_adapter_offload(struct netxen_adapter *adapter); int netxen_phantom_init(struct netxen_adapter *adapter, int pegtune_val); -int netxen_receive_peg_ready(struct netxen_adapter *adapter); int netxen_load_firmware(struct netxen_adapter *adapter); +void netxen_request_firmware(struct netxen_adapter *adapter); +void netxen_release_firmware(struct netxen_adapter *adapter); int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose); int netxen_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp); @@ -1475,6 +1427,8 @@ void netxen_p3_free_mac_list(struct netxen_adapter *adapter); int netxen_p3_nic_set_promisc(struct netxen_adapter *adapter, u32); int netxen_config_intr_coalesce(struct netxen_adapter *adapter); int netxen_config_rss(struct netxen_adapter *adapter, int enable); +int netxen_linkevent_request(struct netxen_adapter *adapter, int enable); +void netxen_advert_link_change(struct netxen_adapter *adapter, int linkup); int nx_fw_cmd_set_mtu(struct netxen_adapter *adapter, int mtu); int netxen_nic_change_mtu(struct net_device *netdev, int new_mtu); @@ -1483,7 +1437,7 @@ int netxen_nic_set_mac(struct net_device *netdev, void *p); struct net_device_stats *netxen_nic_get_stats(struct net_device *netdev); void netxen_nic_update_cmd_producer(struct netxen_adapter *adapter, - uint32_t crb_producer); + struct nx_host_tx_ring *tx_ring); /* * NetXen Board information @@ -1491,7 +1445,7 @@ void netxen_nic_update_cmd_producer(struct netxen_adapter *adapter, #define NETXEN_MAX_SHORT_NAME 32 struct netxen_brdinfo { - netxen_brdtype_t brdtype; /* type of board */ + int brdtype; /* type of board */ long ports; /* max no of physical ports */ char short_name[NETXEN_MAX_SHORT_NAME]; }; @@ -1541,17 +1495,15 @@ dma_watchdog_shutdown_request(struct netxen_adapter *adapter) u32 ctrl; /* check if already inactive */ - if (adapter->hw_read_wx(adapter, - NETXEN_CAM_RAM(NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL), &ctrl, 4)) - printk(KERN_ERR "failed to read dma watchdog status\n"); + ctrl = adapter->hw_read_wx(adapter, + NETXEN_CAM_RAM(NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL)); if (netxen_get_dma_watchdog_enabled(ctrl) == 0) return 1; /* Send the disable request */ netxen_set_dma_watchdog_disable_req(ctrl); - netxen_crb_writelit_adapter(adapter, - NETXEN_CAM_RAM(NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL), ctrl); + NXWR32(adapter, NETXEN_CAM_RAM(NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL), ctrl); return 0; } @@ -1561,9 +1513,8 @@ dma_watchdog_shutdown_poll_result(struct netxen_adapter *adapter) { u32 ctrl; - if (adapter->hw_read_wx(adapter, - NETXEN_CAM_RAM(NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL), &ctrl, 4)) - printk(KERN_ERR "failed to read dma watchdog status\n"); + ctrl = adapter->hw_read_wx(adapter, + NETXEN_CAM_RAM(NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL)); return (netxen_get_dma_watchdog_enabled(ctrl) == 0); } @@ -1573,9 +1524,8 @@ dma_watchdog_wakeup(struct netxen_adapter *adapter) { u32 ctrl; - if (adapter->hw_read_wx(adapter, - NETXEN_CAM_RAM(NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL), &ctrl, 4)) - printk(KERN_ERR "failed to read dma watchdog status\n"); + ctrl = adapter->hw_read_wx(adapter, + NETXEN_CAM_RAM(NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL)); if (netxen_get_dma_watchdog_enabled(ctrl)) return 1; @@ -1583,13 +1533,20 @@ dma_watchdog_wakeup(struct netxen_adapter *adapter) /* send the wakeup request */ netxen_set_dma_watchdog_enable_req(ctrl); - netxen_crb_writelit_adapter(adapter, - NETXEN_CAM_RAM(NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL), ctrl); + NXWR32(adapter, NETXEN_CAM_RAM(NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL), ctrl); return 0; } +static inline u32 netxen_tx_avail(struct nx_host_tx_ring *tx_ring) +{ + smp_mb(); + return find_diff_among(tx_ring->producer, + tx_ring->sw_consumer, tx_ring->num_desc); + +} + int netxen_get_flash_mac_addr(struct netxen_adapter *adapter, __le64 *mac); int netxen_p3_get_mac_addr(struct netxen_adapter *adapter, __le64 *mac); extern void netxen_change_ringparam(struct netxen_adapter *adapter); diff --git a/drivers/net/netxen/netxen_nic_ctx.c b/drivers/net/netxen/netxen_nic_ctx.c index 9234473bc08a..4754f5cffad0 100644 --- a/drivers/net/netxen/netxen_nic_ctx.c +++ b/drivers/net/netxen/netxen_nic_ctx.c @@ -41,8 +41,7 @@ netxen_api_lock(struct netxen_adapter *adapter) for (;;) { /* Acquire PCIE HW semaphore5 */ - netxen_nic_read_w0(adapter, - NETXEN_PCIE_REG(PCIE_SEM5_LOCK), &done); + done = NXRD32(adapter, NETXEN_PCIE_REG(PCIE_SEM5_LOCK)); if (done == 1) break; @@ -56,7 +55,7 @@ netxen_api_lock(struct netxen_adapter *adapter) } #if 0 - netxen_nic_write_w1(adapter, + NXWR32(adapter, NETXEN_API_LOCK_ID, NX_OS_API_LOCK_DRIVER); #endif return 0; @@ -65,11 +64,8 @@ netxen_api_lock(struct netxen_adapter *adapter) static int netxen_api_unlock(struct netxen_adapter *adapter) { - u32 val; - /* Release PCIE HW semaphore5 */ - netxen_nic_read_w0(adapter, - NETXEN_PCIE_REG(PCIE_SEM5_UNLOCK), &val); + NXRD32(adapter, NETXEN_PCIE_REG(PCIE_SEM5_UNLOCK)); return 0; } @@ -86,7 +82,7 @@ netxen_poll_rsp(struct netxen_adapter *adapter) if (++timeout > NX_OS_CRB_RETRY_COUNT) return NX_CDRP_RSP_TIMEOUT; - netxen_nic_read_w1(adapter, NX_CDRP_CRB_OFFSET, &rsp); + rsp = NXRD32(adapter, NX_CDRP_CRB_OFFSET); } while (!NX_CDRP_IS_RSP(rsp)); return rsp; @@ -106,16 +102,15 @@ netxen_issue_cmd(struct netxen_adapter *adapter, if (netxen_api_lock(adapter)) return NX_RCODE_TIMEOUT; - netxen_nic_write_w1(adapter, NX_SIGN_CRB_OFFSET, signature); + NXWR32(adapter, NX_SIGN_CRB_OFFSET, signature); - netxen_nic_write_w1(adapter, NX_ARG1_CRB_OFFSET, arg1); + NXWR32(adapter, NX_ARG1_CRB_OFFSET, arg1); - netxen_nic_write_w1(adapter, NX_ARG2_CRB_OFFSET, arg2); + NXWR32(adapter, NX_ARG2_CRB_OFFSET, arg2); - netxen_nic_write_w1(adapter, NX_ARG3_CRB_OFFSET, arg3); + NXWR32(adapter, NX_ARG3_CRB_OFFSET, arg3); - netxen_nic_write_w1(adapter, NX_CDRP_CRB_OFFSET, - NX_CDRP_FORM_CMD(cmd)); + NXWR32(adapter, NX_CDRP_CRB_OFFSET, NX_CDRP_FORM_CMD(cmd)); rsp = netxen_poll_rsp(adapter); @@ -125,7 +120,7 @@ netxen_issue_cmd(struct netxen_adapter *adapter, rcode = NX_RCODE_TIMEOUT; } else if (rsp == NX_CDRP_RSP_FAIL) { - netxen_nic_read_w1(adapter, NX_ARG1_CRB_OFFSET, &rcode); + rcode = NXRD32(adapter, NX_ARG1_CRB_OFFSET); printk(KERN_ERR "%s: failed card response code:0x%x\n", netxen_nic_driver_name, rcode); @@ -328,6 +323,8 @@ nx_fw_cmd_create_tx_ctx(struct netxen_adapter *adapter) int err = 0; u64 offset, phys_addr; dma_addr_t rq_phys_addr, rsp_phys_addr; + struct nx_host_tx_ring *tx_ring = adapter->tx_ring; + struct netxen_recv_context *recv_ctx = &adapter->recv_ctx; rq_size = SIZEOF_HOSTRQ_TX(nx_hostrq_tx_ctx_t); rq_addr = pci_alloc_consistent(adapter->pdev, @@ -362,15 +359,13 @@ nx_fw_cmd_create_tx_ctx(struct netxen_adapter *adapter) prq->dummy_dma_addr = cpu_to_le64(adapter->dummy_dma.phys_addr); - offset = adapter->ctx_desc_phys_addr+sizeof(struct netxen_ring_ctx); + offset = recv_ctx->phys_addr + sizeof(struct netxen_ring_ctx); prq->cmd_cons_dma_addr = cpu_to_le64(offset); prq_cds = &prq->cds_ring; - prq_cds->host_phys_addr = - cpu_to_le64(adapter->ahw.cmd_desc_phys_addr); - - prq_cds->ring_size = cpu_to_le32(adapter->num_txd); + prq_cds->host_phys_addr = cpu_to_le64(tx_ring->phys_addr); + prq_cds->ring_size = cpu_to_le32(tx_ring->num_desc); phys_addr = rq_phys_addr; err = netxen_issue_cmd(adapter, @@ -383,8 +378,7 @@ nx_fw_cmd_create_tx_ctx(struct netxen_adapter *adapter) if (err == NX_RCODE_SUCCESS) { temp = le32_to_cpu(prsp->cds_ring.host_producer_crb); - adapter->crb_addr_cmd_producer = - NETXEN_NIC_REG(temp - 0x200); + tx_ring->crb_cmd_producer = NETXEN_NIC_REG(temp - 0x200); #if 0 adapter->tx_state = le32_to_cpu(prsp->host_ctx_state); @@ -448,7 +442,19 @@ static struct netxen_recv_crb recv_crb_registers[] = { NETXEN_NIC_REG(0x120) }, /* crb_sts_consumer: */ - NETXEN_NIC_REG(0x138), + { + NETXEN_NIC_REG(0x138), + NETXEN_NIC_REG_2(0x000), + NETXEN_NIC_REG_2(0x004), + NETXEN_NIC_REG_2(0x008), + }, + /* sw_int_mask */ + { + CRB_SW_INT_MASK_0, + NETXEN_NIC_REG_2(0x044), + NETXEN_NIC_REG_2(0x048), + NETXEN_NIC_REG_2(0x04c), + }, }, /* Instance 1 */ { @@ -461,7 +467,19 @@ static struct netxen_recv_crb recv_crb_registers[] = { NETXEN_NIC_REG(0x164) }, /* crb_sts_consumer: */ - NETXEN_NIC_REG(0x17c), + { + NETXEN_NIC_REG(0x17c), + NETXEN_NIC_REG_2(0x020), + NETXEN_NIC_REG_2(0x024), + NETXEN_NIC_REG_2(0x028), + }, + /* sw_int_mask */ + { + CRB_SW_INT_MASK_1, + NETXEN_NIC_REG_2(0x064), + NETXEN_NIC_REG_2(0x068), + NETXEN_NIC_REG_2(0x06c), + }, }, /* Instance 2 */ { @@ -474,7 +492,19 @@ static struct netxen_recv_crb recv_crb_registers[] = { NETXEN_NIC_REG(0x208) }, /* crb_sts_consumer: */ - NETXEN_NIC_REG(0x220), + { + NETXEN_NIC_REG(0x220), + NETXEN_NIC_REG_2(0x03c), + NETXEN_NIC_REG_2(0x03c), + NETXEN_NIC_REG_2(0x03c), + }, + /* sw_int_mask */ + { + CRB_SW_INT_MASK_2, + NETXEN_NIC_REG_2(0x03c), + NETXEN_NIC_REG_2(0x03c), + NETXEN_NIC_REG_2(0x03c), + }, }, /* Instance 3 */ { @@ -487,7 +517,19 @@ static struct netxen_recv_crb recv_crb_registers[] = { NETXEN_NIC_REG(0x24c) }, /* crb_sts_consumer: */ - NETXEN_NIC_REG(0x264), + { + NETXEN_NIC_REG(0x264), + NETXEN_NIC_REG_2(0x03c), + NETXEN_NIC_REG_2(0x03c), + NETXEN_NIC_REG_2(0x03c), + }, + /* sw_int_mask */ + { + CRB_SW_INT_MASK_3, + NETXEN_NIC_REG_2(0x03c), + NETXEN_NIC_REG_2(0x03c), + NETXEN_NIC_REG_2(0x03c), + }, }, }; @@ -497,84 +539,91 @@ netxen_init_old_ctx(struct netxen_adapter *adapter) struct netxen_recv_context *recv_ctx; struct nx_host_rds_ring *rds_ring; struct nx_host_sds_ring *sds_ring; + struct nx_host_tx_ring *tx_ring; int ring; - int func_id = adapter->portnum; - - adapter->ctx_desc->cmd_ring_addr = - cpu_to_le64(adapter->ahw.cmd_desc_phys_addr); - adapter->ctx_desc->cmd_ring_size = - cpu_to_le32(adapter->num_txd); + int port = adapter->portnum; + struct netxen_ring_ctx *hwctx; + u32 signature; + tx_ring = adapter->tx_ring; recv_ctx = &adapter->recv_ctx; + hwctx = recv_ctx->hwctx; + + hwctx->cmd_ring_addr = cpu_to_le64(tx_ring->phys_addr); + hwctx->cmd_ring_size = cpu_to_le32(tx_ring->num_desc); + for (ring = 0; ring < adapter->max_rds_rings; ring++) { rds_ring = &recv_ctx->rds_rings[ring]; - adapter->ctx_desc->rcv_ctx[ring].rcv_ring_addr = + hwctx->rcv_rings[ring].addr = cpu_to_le64(rds_ring->phys_addr); - adapter->ctx_desc->rcv_ctx[ring].rcv_ring_size = + hwctx->rcv_rings[ring].size = cpu_to_le32(rds_ring->num_desc); } - sds_ring = &recv_ctx->sds_rings[0]; - adapter->ctx_desc->sts_ring_addr = cpu_to_le64(sds_ring->phys_addr); - adapter->ctx_desc->sts_ring_size = cpu_to_le32(sds_ring->num_desc); - adapter->pci_write_normalize(adapter, CRB_CTX_ADDR_REG_LO(func_id), - lower32(adapter->ctx_desc_phys_addr)); - adapter->pci_write_normalize(adapter, CRB_CTX_ADDR_REG_HI(func_id), - upper32(adapter->ctx_desc_phys_addr)); - adapter->pci_write_normalize(adapter, CRB_CTX_SIGNATURE_REG(func_id), - NETXEN_CTX_SIGNATURE | func_id); + for (ring = 0; ring < adapter->max_sds_rings; ring++) { + sds_ring = &recv_ctx->sds_rings[ring]; + + if (ring == 0) { + hwctx->sts_ring_addr = cpu_to_le64(sds_ring->phys_addr); + hwctx->sts_ring_size = cpu_to_le32(sds_ring->num_desc); + } + hwctx->sts_rings[ring].addr = cpu_to_le64(sds_ring->phys_addr); + hwctx->sts_rings[ring].size = cpu_to_le32(sds_ring->num_desc); + hwctx->sts_rings[ring].msi_index = cpu_to_le16(ring); + } + hwctx->sts_ring_count = cpu_to_le32(adapter->max_sds_rings); + + signature = (adapter->max_sds_rings > 1) ? + NETXEN_CTX_SIGNATURE_V2 : NETXEN_CTX_SIGNATURE; + + NXWR32(adapter, CRB_CTX_ADDR_REG_LO(port), + lower32(recv_ctx->phys_addr)); + NXWR32(adapter, CRB_CTX_ADDR_REG_HI(port), + upper32(recv_ctx->phys_addr)); + NXWR32(adapter, CRB_CTX_SIGNATURE_REG(port), + signature | port); return 0; } -static uint32_t sw_int_mask[4] = { - CRB_SW_INT_MASK_0, CRB_SW_INT_MASK_1, - CRB_SW_INT_MASK_2, CRB_SW_INT_MASK_3 -}; - int netxen_alloc_hw_resources(struct netxen_adapter *adapter) { - struct netxen_hardware_context *hw = &adapter->ahw; - u32 state = 0; void *addr; int err = 0; int ring; struct netxen_recv_context *recv_ctx; struct nx_host_rds_ring *rds_ring; struct nx_host_sds_ring *sds_ring; + struct nx_host_tx_ring *tx_ring; struct pci_dev *pdev = adapter->pdev; struct net_device *netdev = adapter->netdev; + int port = adapter->portnum; - err = netxen_receive_peg_ready(adapter); - if (err) { - printk(KERN_ERR "Rcv Peg initialization not complete:%x.\n", - state); - return err; - } + recv_ctx = &adapter->recv_ctx; + tx_ring = adapter->tx_ring; addr = pci_alloc_consistent(pdev, sizeof(struct netxen_ring_ctx) + sizeof(uint32_t), - &adapter->ctx_desc_phys_addr); - + &recv_ctx->phys_addr); if (addr == NULL) { dev_err(&pdev->dev, "failed to allocate hw context\n"); return -ENOMEM; } + memset(addr, 0, sizeof(struct netxen_ring_ctx)); - adapter->ctx_desc = (struct netxen_ring_ctx *)addr; - adapter->ctx_desc->ctx_id = cpu_to_le32(adapter->portnum); - adapter->ctx_desc->cmd_consumer_offset = - cpu_to_le64(adapter->ctx_desc_phys_addr + + recv_ctx->hwctx = (struct netxen_ring_ctx *)addr; + recv_ctx->hwctx->ctx_id = cpu_to_le32(port); + recv_ctx->hwctx->cmd_consumer_offset = + cpu_to_le64(recv_ctx->phys_addr + sizeof(struct netxen_ring_ctx)); - adapter->cmd_consumer = + tx_ring->hw_consumer = (__le32 *)(((char *)addr) + sizeof(struct netxen_ring_ctx)); /* cmd desc ring */ - addr = pci_alloc_consistent(pdev, - TX_DESC_RINGSIZE(adapter), - &hw->cmd_desc_phys_addr); + addr = pci_alloc_consistent(pdev, TX_DESC_RINGSIZE(tx_ring), + &tx_ring->phys_addr); if (addr == NULL) { dev_err(&pdev->dev, "%s: failed to allocate tx desc ring\n", @@ -582,9 +631,7 @@ int netxen_alloc_hw_resources(struct netxen_adapter *adapter) return -ENOMEM; } - hw->cmd_desc_head = (struct cmd_desc_type0 *)addr; - - recv_ctx = &adapter->recv_ctx; + tx_ring->desc_head = (struct cmd_desc_type0 *)addr; for (ring = 0; ring < adapter->max_rds_rings; ring++) { rds_ring = &recv_ctx->rds_rings[ring]; @@ -602,8 +649,7 @@ int netxen_alloc_hw_resources(struct netxen_adapter *adapter) if (adapter->fw_major < 4) rds_ring->crb_rcv_producer = - recv_crb_registers[adapter->portnum]. - crb_rcv_producer[ring]; + recv_crb_registers[port].crb_rcv_producer[ring]; } for (ring = 0; ring < adapter->max_sds_rings; ring++) { @@ -620,13 +666,16 @@ int netxen_alloc_hw_resources(struct netxen_adapter *adapter) goto err_out_free; } sds_ring->desc_head = (struct status_desc *)addr; + + sds_ring->crb_sts_consumer = + recv_crb_registers[port].crb_sts_consumer[ring]; + + sds_ring->crb_intr_mask = + recv_crb_registers[port].sw_int_mask[ring]; } if (adapter->fw_major >= 4) { - adapter->intr_scheme = INTR_SCHEME_PERPORT; - adapter->msi_mode = MSI_MODE_MULTIFUNC; - err = nx_fw_cmd_create_rx_ctx(adapter); if (err) goto err_out_free; @@ -634,23 +683,11 @@ int netxen_alloc_hw_resources(struct netxen_adapter *adapter) if (err) goto err_out_free; } else { - sds_ring = &recv_ctx->sds_rings[0]; - sds_ring->crb_sts_consumer = - recv_crb_registers[adapter->portnum].crb_sts_consumer; - - adapter->intr_scheme = adapter->pci_read_normalize(adapter, - CRB_NIC_CAPABILITIES_FW); - adapter->msi_mode = adapter->pci_read_normalize(adapter, - CRB_NIC_MSI_MODE_FW); - recv_ctx->sds_rings[0].crb_intr_mask = - sw_int_mask[adapter->portnum]; - err = netxen_init_old_ctx(adapter); if (err) { netxen_free_hw_resources(adapter); return err; } - } return 0; @@ -665,32 +702,40 @@ void netxen_free_hw_resources(struct netxen_adapter *adapter) struct netxen_recv_context *recv_ctx; struct nx_host_rds_ring *rds_ring; struct nx_host_sds_ring *sds_ring; + struct nx_host_tx_ring *tx_ring; int ring; + int port = adapter->portnum; + if (adapter->fw_major >= 4) { nx_fw_cmd_destroy_tx_ctx(adapter); nx_fw_cmd_destroy_rx_ctx(adapter); - } - - if (adapter->ctx_desc != NULL) { - pci_free_consistent(adapter->pdev, - sizeof(struct netxen_ring_ctx) + - sizeof(uint32_t), - adapter->ctx_desc, - adapter->ctx_desc_phys_addr); - adapter->ctx_desc = NULL; - } - - if (adapter->ahw.cmd_desc_head != NULL) { - pci_free_consistent(adapter->pdev, - sizeof(struct cmd_desc_type0) * - adapter->num_txd, - adapter->ahw.cmd_desc_head, - adapter->ahw.cmd_desc_phys_addr); - adapter->ahw.cmd_desc_head = NULL; + } else { + netxen_api_lock(adapter); + NXWR32(adapter, CRB_CTX_SIGNATURE_REG(port), + NETXEN_CTX_RESET | port); + netxen_api_unlock(adapter); } recv_ctx = &adapter->recv_ctx; + + if (recv_ctx->hwctx != NULL) { + pci_free_consistent(adapter->pdev, + sizeof(struct netxen_ring_ctx) + + sizeof(uint32_t), + recv_ctx->hwctx, + recv_ctx->phys_addr); + recv_ctx->hwctx = NULL; + } + + tx_ring = adapter->tx_ring; + if (tx_ring->desc_head != NULL) { + pci_free_consistent(adapter->pdev, + TX_DESC_RINGSIZE(tx_ring), + tx_ring->desc_head, tx_ring->phys_addr); + tx_ring->desc_head = NULL; + } + for (ring = 0; ring < adapter->max_rds_rings; ring++) { rds_ring = &recv_ctx->rds_rings[ring]; diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c index a677ff895184..e16ea46c24b8 100644 --- a/drivers/net/netxen/netxen_nic_ethtool.c +++ b/drivers/net/netxen/netxen_nic_ethtool.c @@ -30,7 +30,6 @@ #include #include -#include #include #include #include @@ -53,13 +52,9 @@ struct netxen_nic_stats { #define NETXEN_NIC_INVALID_DATA 0xDEADBEEF static const struct netxen_nic_stats netxen_nic_gstrings_stats[] = { - {"rcvd_bad_skb", NETXEN_NIC_STAT(stats.rcvdbadskb)}, {"xmit_called", NETXEN_NIC_STAT(stats.xmitcalled)}, - {"xmited_frames", NETXEN_NIC_STAT(stats.xmitedframes)}, {"xmit_finished", NETXEN_NIC_STAT(stats.xmitfinished)}, - {"bad_skb_len", NETXEN_NIC_STAT(stats.badskblen)}, - {"no_cmd_desc", NETXEN_NIC_STAT(stats.nocmddescriptor)}, - {"polled", NETXEN_NIC_STAT(stats.polled)}, + {"rx_dropped", NETXEN_NIC_STAT(stats.rxdropped)}, {"tx_dropped", NETXEN_NIC_STAT(stats.txdropped)}, {"csummed", NETXEN_NIC_STAT(stats.csummed)}, {"no_rcv", NETXEN_NIC_STAT(stats.no_rcv)}, @@ -97,12 +92,9 @@ netxen_nic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) strncpy(drvinfo->driver, netxen_nic_driver_name, 32); strncpy(drvinfo->version, NETXEN_NIC_LINUX_VERSIONID, 32); write_lock_irqsave(&adapter->adapter_lock, flags); - fw_major = adapter->pci_read_normalize(adapter, - NETXEN_FW_VERSION_MAJOR); - fw_minor = adapter->pci_read_normalize(adapter, - NETXEN_FW_VERSION_MINOR); - fw_build = adapter->pci_read_normalize(adapter, - NETXEN_FW_VERSION_SUB); + fw_major = NXRD32(adapter, NETXEN_FW_VERSION_MAJOR); + fw_minor = NXRD32(adapter, NETXEN_FW_VERSION_MINOR); + fw_build = NXRD32(adapter, NETXEN_FW_VERSION_SUB); write_unlock_irqrestore(&adapter->adapter_lock, flags); sprintf(drvinfo->fw_version, "%d.%d.%d", fw_major, fw_minor, fw_build); @@ -115,6 +107,7 @@ static int netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) { struct netxen_adapter *adapter = netdev_priv(dev); + int check_sfp_module = 0; /* read which mode */ if (adapter->ahw.port_type == NETXEN_NIC_GBE) { @@ -139,7 +132,7 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) } else if (adapter->ahw.port_type == NETXEN_NIC_XGBE) { u32 val; - adapter->hw_read_wx(adapter, NETXEN_PORT_MODE_ADDR, &val, 4); + val = NXRD32(adapter, NETXEN_PORT_MODE_ADDR); if (val == NETXEN_PORT_MODE_802_3_AP) { ecmd->supported = SUPPORTED_1000baseT_Full; ecmd->advertising = ADVERTISED_1000baseT_Full; @@ -148,13 +141,19 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) ecmd->advertising = ADVERTISED_10000baseT_Full; } + if (netif_running(dev) && adapter->has_link_events) { + ecmd->speed = adapter->link_speed; + ecmd->autoneg = adapter->link_autoneg; + ecmd->duplex = adapter->link_duplex; + goto skip; + } + ecmd->port = PORT_TP; if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) { u16 pcifn = adapter->ahw.pci_func; - adapter->hw_read_wx(adapter, - P3_LINK_SPEED_REG(pcifn), &val, 4); + val = NXRD32(adapter, P3_LINK_SPEED_REG(pcifn)); ecmd->speed = P3_LINK_SPEED_MHZ * P3_LINK_SPEED_VAL(pcifn, val); } else @@ -165,10 +164,11 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) } else return -EIO; +skip: ecmd->phy_address = adapter->physical_port; ecmd->transceiver = XCVR_EXTERNAL; - switch ((netxen_brdtype_t)adapter->ahw.board_type) { + switch (adapter->ahw.board_type) { case NETXEN_BRDTYPE_P2_SB35_4G: case NETXEN_BRDTYPE_P2_SB31_2G: case NETXEN_BRDTYPE_P3_REF_QG: @@ -195,7 +195,7 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) case NETXEN_BRDTYPE_P3_HMEZ: ecmd->supported |= SUPPORTED_MII; ecmd->advertising |= ADVERTISED_MII; - ecmd->port = PORT_FIBRE; + ecmd->port = PORT_MII; ecmd->autoneg = AUTONEG_DISABLE; break; case NETXEN_BRDTYPE_P3_10G_SFP_PLUS: @@ -203,6 +203,8 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) case NETXEN_BRDTYPE_P3_10G_SFP_QT: ecmd->advertising |= ADVERTISED_TP; ecmd->supported |= SUPPORTED_TP; + check_sfp_module = netif_running(dev) && + adapter->has_link_events; case NETXEN_BRDTYPE_P2_SB31_10G: case NETXEN_BRDTYPE_P3_10G_XFP: ecmd->supported |= SUPPORTED_FIBRE; @@ -217,6 +219,8 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) ecmd->advertising |= (ADVERTISED_FIBRE | ADVERTISED_TP); ecmd->port = PORT_FIBRE; + check_sfp_module = netif_running(dev) && + adapter->has_link_events; } else { ecmd->autoneg = AUTONEG_ENABLE; ecmd->supported |= (SUPPORTED_TP |SUPPORTED_Autoneg); @@ -227,10 +231,28 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) break; default: printk(KERN_ERR "netxen-nic: Unsupported board model %d\n", - (netxen_brdtype_t)adapter->ahw.board_type); + adapter->ahw.board_type); return -EIO; } + if (check_sfp_module) { + switch (adapter->module_type) { + case LINKEVENT_MODULE_OPTICAL_UNKNOWN: + case LINKEVENT_MODULE_OPTICAL_SRLR: + case LINKEVENT_MODULE_OPTICAL_LRM: + case LINKEVENT_MODULE_OPTICAL_SFP_1G: + ecmd->port = PORT_FIBRE; + break; + case LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLE: + case LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLELEN: + case LINKEVENT_MODULE_TWINAX: + ecmd->port = PORT_TP; + break; + default: + ecmd->port = -1; + } + } + return 0; } @@ -398,12 +420,11 @@ netxen_nic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p) regs->version = (1 << 24) | (adapter->ahw.revision_id << 16) | (adapter->pdev)->device; /* which mode */ - adapter->hw_read_wx(adapter, NETXEN_NIU_MODE, ®s_buff[0], 4); + regs_buff[0] = NXRD32(adapter, NETXEN_NIU_MODE); mode = regs_buff[0]; /* Common registers to all the modes */ - adapter->hw_read_wx(adapter, - NETXEN_NIU_STRAP_VALUE_SAVE_HIGHER, ®s_buff[2], 4); + regs_buff[2] = NXRD32(adapter, NETXEN_NIU_STRAP_VALUE_SAVE_HIGHER); /* GB/XGB Mode */ mode = (mode / 2) - 1; window = 0; @@ -414,9 +435,8 @@ netxen_nic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p) window = adapter->physical_port * NETXEN_NIC_PORT_WINDOW; - adapter->hw_read_wx(adapter, - niu_registers[mode].reg[i - 3] + window, - ®s_buff[i], 4); + regs_buff[i] = NXRD32(adapter, + niu_registers[mode].reg[i - 3] + window); } } @@ -440,7 +460,7 @@ static u32 netxen_nic_test_link(struct net_device *dev) return !val; } } else if (adapter->ahw.port_type == NETXEN_NIC_XGBE) { - val = adapter->pci_read_normalize(adapter, CRB_XG_STATE); + val = NXRD32(adapter, CRB_XG_STATE); return (val == XG_LINK_UP) ? 0 : 1; } return -EIO; @@ -504,10 +524,9 @@ netxen_nic_get_pauseparam(struct net_device *dev, if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS)) return; /* get flow control settings */ - netxen_nic_read_w0(adapter,NETXEN_NIU_GB_MAC_CONFIG_0(port), - &val); + val = NXRD32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port)); pause->rx_pause = netxen_gb_get_rx_flowctl(val); - netxen_nic_read_w0(adapter, NETXEN_NIU_GB_PAUSE_CTL, &val); + val = NXRD32(adapter, NETXEN_NIU_GB_PAUSE_CTL); switch (port) { case 0: pause->tx_pause = !(netxen_gb_get_gb0_mask(val)); @@ -527,7 +546,7 @@ netxen_nic_get_pauseparam(struct net_device *dev, if ((port < 0) || (port > NETXEN_NIU_MAX_XG_PORTS)) return; pause->rx_pause = 1; - netxen_nic_read_w0(adapter, NETXEN_NIU_XG_PAUSE_CTL, &val); + val = NXRD32(adapter, NETXEN_NIU_XG_PAUSE_CTL); if (port == 0) pause->tx_pause = !(netxen_xg_get_xg0_mask(val)); else @@ -550,18 +569,17 @@ netxen_nic_set_pauseparam(struct net_device *dev, if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS)) return -EIO; /* set flow control */ - netxen_nic_read_w0(adapter, - NETXEN_NIU_GB_MAC_CONFIG_0(port), &val); + val = NXRD32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port)); if (pause->rx_pause) netxen_gb_rx_flowctl(val); else netxen_gb_unset_rx_flowctl(val); - netxen_nic_write_w0(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), + NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), val); /* set autoneg */ - netxen_nic_read_w0(adapter, NETXEN_NIU_GB_PAUSE_CTL, &val); + val = NXRD32(adapter, NETXEN_NIU_GB_PAUSE_CTL); switch (port) { case 0: if (pause->tx_pause) @@ -589,11 +607,11 @@ netxen_nic_set_pauseparam(struct net_device *dev, netxen_gb_set_gb3_mask(val); break; } - netxen_nic_write_w0(adapter, NETXEN_NIU_GB_PAUSE_CTL, val); + NXWR32(adapter, NETXEN_NIU_GB_PAUSE_CTL, val); } else if (adapter->ahw.port_type == NETXEN_NIC_XGBE) { if ((port < 0) || (port > NETXEN_NIU_MAX_XG_PORTS)) return -EIO; - netxen_nic_read_w0(adapter, NETXEN_NIU_XG_PAUSE_CTL, &val); + val = NXRD32(adapter, NETXEN_NIU_XG_PAUSE_CTL); if (port == 0) { if (pause->tx_pause) netxen_xg_unset_xg0_mask(val); @@ -605,7 +623,7 @@ netxen_nic_set_pauseparam(struct net_device *dev, else netxen_xg_set_xg1_mask(val); } - netxen_nic_write_w0(adapter, NETXEN_NIU_XG_PAUSE_CTL, val); + NXWR32(adapter, NETXEN_NIU_XG_PAUSE_CTL, val); } else { printk(KERN_ERR "%s: Unknown board type: %x\n", netxen_nic_driver_name, @@ -619,14 +637,14 @@ static int netxen_nic_reg_test(struct net_device *dev) struct netxen_adapter *adapter = netdev_priv(dev); u32 data_read, data_written; - netxen_nic_read_w0(adapter, NETXEN_PCIX_PH_REG(0), &data_read); + data_read = NXRD32(adapter, NETXEN_PCIX_PH_REG(0)); if ((data_read & 0xffff) != PHAN_VENDOR_ID) return 1; data_written = (u32)0xa5a5a5a5; - netxen_nic_reg_write(adapter, CRB_SCRATCHPAD_TEST, data_written); - data_read = adapter->pci_read_normalize(adapter, CRB_SCRATCHPAD_TEST); + NXWR32(adapter, CRB_SCRATCHPAD_TEST, data_written); + data_read = NXRD32(adapter, CRB_SCRATCHPAD_TEST); if (data_written != data_read) return 1; @@ -743,11 +761,11 @@ netxen_nic_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) return; - wol_cfg = netxen_nic_reg_read(adapter, NETXEN_WOL_CONFIG_NV); + wol_cfg = NXRD32(adapter, NETXEN_WOL_CONFIG_NV); if (wol_cfg & (1UL << adapter->portnum)) wol->supported |= WAKE_MAGIC; - wol_cfg = netxen_nic_reg_read(adapter, NETXEN_WOL_CONFIG); + wol_cfg = NXRD32(adapter, NETXEN_WOL_CONFIG); if (wol_cfg & (1UL << adapter->portnum)) wol->wolopts |= WAKE_MAGIC; } @@ -764,16 +782,16 @@ netxen_nic_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) if (wol->wolopts & ~WAKE_MAGIC) return -EOPNOTSUPP; - wol_cfg = netxen_nic_reg_read(adapter, NETXEN_WOL_CONFIG_NV); + wol_cfg = NXRD32(adapter, NETXEN_WOL_CONFIG_NV); if (!(wol_cfg & (1 << adapter->portnum))) return -EOPNOTSUPP; - wol_cfg = netxen_nic_reg_read(adapter, NETXEN_WOL_CONFIG); + wol_cfg = NXRD32(adapter, NETXEN_WOL_CONFIG); if (wol->wolopts & WAKE_MAGIC) wol_cfg |= 1UL << adapter->portnum; else wol_cfg &= ~(1UL << adapter->portnum); - netxen_nic_reg_write(adapter, NETXEN_WOL_CONFIG, wol_cfg); + NXWR32(adapter, NETXEN_WOL_CONFIG, wol_cfg); return 0; } diff --git a/drivers/net/netxen/netxen_nic_hdr.h b/drivers/net/netxen/netxen_nic_hdr.h index 016c62129c76..3cc047844af3 100644 --- a/drivers/net/netxen/netxen_nic_hdr.h +++ b/drivers/net/netxen/netxen_nic_hdr.h @@ -31,16 +31,8 @@ #ifndef __NETXEN_NIC_HDR_H_ #define __NETXEN_NIC_HDR_H_ -#include #include -#include -#include -#include -#include -#include #include -#include -#include /* for memset */ /* * The basic unit of access when reading/writing control registers. @@ -363,6 +355,7 @@ enum { #define NETXEN_HW_CRB_HUB_AGT_ADR_LPC \ ((NETXEN_HW_H6_CH_HUB_ADR << 7) | NETXEN_HW_LPC_CRB_AGT_ADR) +#define NETXEN_SRE_MISC (NETXEN_CRB_SRE + 0x0002c) #define NETXEN_SRE_INT_STATUS (NETXEN_CRB_SRE + 0x00034) #define NETXEN_SRE_PBI_ACTIVE_STATUS (NETXEN_CRB_SRE + 0x01014) #define NETXEN_SRE_L1RE_CTL (NETXEN_CRB_SRE + 0x03000) diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index 5026811c04ce..ce3b89d2cbb6 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -32,7 +32,6 @@ #include "netxen_nic_hw.h" #include "netxen_nic_phan_reg.h" -#include #include #define MASK(n) ((1ULL<<(n))-1) @@ -48,8 +47,49 @@ #define CRB_HI(off) ((crb_hub_agt[CRB_BLK(off)] << 20) | ((off) & 0xf0000)) #define CRB_INDIRECT_2M (0x1e0000UL) +#ifndef readq +static inline u64 readq(void __iomem *addr) +{ + return readl(addr) | (((u64) readl(addr + 4)) << 32LL); +} +#endif + +#ifndef writeq +static inline void writeq(u64 val, void __iomem *addr) +{ + writel(((u32) (val)), (addr)); + writel(((u32) (val >> 32)), (addr + 4)); +} +#endif + +#define ADDR_IN_RANGE(addr, low, high) \ + (((addr) < (high)) && ((addr) >= (low))) + +#define PCI_OFFSET_FIRST_RANGE(adapter, off) \ + ((adapter)->ahw.pci_base0 + (off)) +#define PCI_OFFSET_SECOND_RANGE(adapter, off) \ + ((adapter)->ahw.pci_base1 + (off) - SECOND_PAGE_GROUP_START) +#define PCI_OFFSET_THIRD_RANGE(adapter, off) \ + ((adapter)->ahw.pci_base2 + (off) - THIRD_PAGE_GROUP_START) + +static void __iomem *pci_base_offset(struct netxen_adapter *adapter, + unsigned long off) +{ + if (ADDR_IN_RANGE(off, FIRST_PAGE_GROUP_START, FIRST_PAGE_GROUP_END)) + return PCI_OFFSET_FIRST_RANGE(adapter, off); + + if (ADDR_IN_RANGE(off, SECOND_PAGE_GROUP_START, SECOND_PAGE_GROUP_END)) + return PCI_OFFSET_SECOND_RANGE(adapter, off); + + if (ADDR_IN_RANGE(off, THIRD_PAGE_GROUP_START, THIRD_PAGE_GROUP_END)) + return PCI_OFFSET_THIRD_RANGE(adapter, off); + + return NULL; +} + #define CRB_WIN_LOCK_TIMEOUT 100000000 -static crb_128M_2M_block_map_t crb_128M_2M_map[64] = { +static crb_128M_2M_block_map_t +crb_128M_2M_map[64] __cacheline_aligned_in_smp = { {{{0, 0, 0, 0} } }, /* 0: PCI */ {{{1, 0x0100000, 0x0102000, 0x120000}, /* 1: PCIE */ {1, 0x0110000, 0x0120000, 0x130000}, @@ -279,39 +319,8 @@ static unsigned crb_hub_agt[64] = /* PCI Windowing for DDR regions. */ -#define ADDR_IN_RANGE(addr, low, high) \ - (((addr) <= (high)) && ((addr) >= (low))) - #define NETXEN_WINDOW_ONE 0x2000000 /*CRB Window: bit 25 of CRB address */ -#define NETXEN_NIC_ZERO_PAUSE_ADDR 0ULL -#define NETXEN_NIC_UNIT_PAUSE_ADDR 0x200ULL -#define NETXEN_NIC_EPG_PAUSE_ADDR1 0x2200010000c28001ULL -#define NETXEN_NIC_EPG_PAUSE_ADDR2 0x0100088866554433ULL - -#define NETXEN_NIC_WINDOW_MARGIN 0x100000 - -int netxen_nic_set_mac(struct net_device *netdev, void *p) -{ - struct netxen_adapter *adapter = netdev_priv(netdev); - struct sockaddr *addr = p; - - if (netif_running(netdev)) - return -EBUSY; - - if (!is_valid_ether_addr(addr->sa_data)) - return -EADDRNOTAVAIL; - - memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); - - /* For P3, MAC addr is not set in NIU */ - if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) - if (adapter->macaddr_set) - adapter->macaddr_set(adapter, addr->sa_data); - - return 0; -} - #define NETXEN_UNICAST_ADDR(port, index) \ (NETXEN_UNICAST_ADDR_BASE+(port*32)+(index*8)) #define NETXEN_MCAST_ADDR(port, index) \ @@ -331,22 +340,20 @@ netxen_nic_enable_mcast_filter(struct netxen_adapter *adapter) if (adapter->mc_enabled) return 0; - adapter->hw_read_wx(adapter, NETXEN_MAC_ADDR_CNTL_REG, &val, 4); + val = NXRD32(adapter, NETXEN_MAC_ADDR_CNTL_REG); val |= (1UL << (28+port)); - adapter->hw_write_wx(adapter, NETXEN_MAC_ADDR_CNTL_REG, &val, 4); + NXWR32(adapter, NETXEN_MAC_ADDR_CNTL_REG, val); /* add broadcast addr to filter */ val = 0xffffff; - netxen_crb_writelit_adapter(adapter, NETXEN_UNICAST_ADDR(port, 0), val); - netxen_crb_writelit_adapter(adapter, - NETXEN_UNICAST_ADDR(port, 0)+4, val); + NXWR32(adapter, NETXEN_UNICAST_ADDR(port, 0), val); + NXWR32(adapter, NETXEN_UNICAST_ADDR(port, 0)+4, val); /* add station addr to filter */ val = MAC_HI(addr); - netxen_crb_writelit_adapter(adapter, NETXEN_UNICAST_ADDR(port, 1), val); + NXWR32(adapter, NETXEN_UNICAST_ADDR(port, 1), val); val = MAC_LO(addr); - netxen_crb_writelit_adapter(adapter, - NETXEN_UNICAST_ADDR(port, 1)+4, val); + NXWR32(adapter, NETXEN_UNICAST_ADDR(port, 1)+4, val); adapter->mc_enabled = 1; return 0; @@ -362,18 +369,17 @@ netxen_nic_disable_mcast_filter(struct netxen_adapter *adapter) if (!adapter->mc_enabled) return 0; - adapter->hw_read_wx(adapter, NETXEN_MAC_ADDR_CNTL_REG, &val, 4); + val = NXRD32(adapter, NETXEN_MAC_ADDR_CNTL_REG); val &= ~(1UL << (28+port)); - adapter->hw_write_wx(adapter, NETXEN_MAC_ADDR_CNTL_REG, &val, 4); + NXWR32(adapter, NETXEN_MAC_ADDR_CNTL_REG, val); val = MAC_HI(addr); - netxen_crb_writelit_adapter(adapter, NETXEN_UNICAST_ADDR(port, 0), val); + NXWR32(adapter, NETXEN_UNICAST_ADDR(port, 0), val); val = MAC_LO(addr); - netxen_crb_writelit_adapter(adapter, - NETXEN_UNICAST_ADDR(port, 0)+4, val); + NXWR32(adapter, NETXEN_UNICAST_ADDR(port, 0)+4, val); - netxen_crb_writelit_adapter(adapter, NETXEN_UNICAST_ADDR(port, 1), 0); - netxen_crb_writelit_adapter(adapter, NETXEN_UNICAST_ADDR(port, 1)+4, 0); + NXWR32(adapter, NETXEN_UNICAST_ADDR(port, 1), 0); + NXWR32(adapter, NETXEN_UNICAST_ADDR(port, 1)+4, 0); adapter->mc_enabled = 0; return 0; @@ -389,10 +395,8 @@ netxen_nic_set_mcast_addr(struct netxen_adapter *adapter, lo = MAC_LO(addr); hi = MAC_HI(addr); - netxen_crb_writelit_adapter(adapter, - NETXEN_MCAST_ADDR(port, index), hi); - netxen_crb_writelit_adapter(adapter, - NETXEN_MCAST_ADDR(port, index)+4, lo); + NXWR32(adapter, NETXEN_MCAST_ADDR(port, index), hi); + NXWR32(adapter, NETXEN_MCAST_ADDR(port, index)+4, lo); return 0; } @@ -445,100 +449,58 @@ void netxen_p2_nic_set_multi(struct net_device *netdev) netxen_nic_set_mcast_addr(adapter, index, null_addr); } -static int nx_p3_nic_add_mac(struct netxen_adapter *adapter, - u8 *addr, nx_mac_list_t **add_list, nx_mac_list_t **del_list) -{ - nx_mac_list_t *cur, *prev; - - /* if in del_list, move it to adapter->mac_list */ - for (cur = *del_list, prev = NULL; cur;) { - if (memcmp(addr, cur->mac_addr, ETH_ALEN) == 0) { - if (prev == NULL) - *del_list = cur->next; - else - prev->next = cur->next; - cur->next = adapter->mac_list; - adapter->mac_list = cur; - return 0; - } - prev = cur; - cur = cur->next; - } - - /* make sure to add each mac address only once */ - for (cur = adapter->mac_list; cur; cur = cur->next) { - if (memcmp(addr, cur->mac_addr, ETH_ALEN) == 0) - return 0; - } - /* not in del_list, create new entry and add to add_list */ - cur = kmalloc(sizeof(*cur), in_atomic()? GFP_ATOMIC : GFP_KERNEL); - if (cur == NULL) { - printk(KERN_ERR "%s: cannot allocate memory. MAC filtering may" - "not work properly from now.\n", __func__); - return -1; - } - - memcpy(cur->mac_addr, addr, ETH_ALEN); - cur->next = *add_list; - *add_list = cur; - return 0; -} - static int netxen_send_cmd_descs(struct netxen_adapter *adapter, - struct cmd_desc_type0 *cmd_desc_arr, int nr_elements) + struct cmd_desc_type0 *cmd_desc_arr, int nr_desc) { - uint32_t i, producer; + u32 i, producer, consumer; struct netxen_cmd_buffer *pbuf; struct cmd_desc_type0 *cmd_desc; - - if (nr_elements > MAX_PENDING_DESC_BLOCK_SIZE || nr_elements == 0) { - printk(KERN_WARNING "%s: Too many command descriptors in a " - "request\n", __func__); - return -EINVAL; - } + struct nx_host_tx_ring *tx_ring; i = 0; + tx_ring = adapter->tx_ring; netif_tx_lock_bh(adapter->netdev); - producer = adapter->cmd_producer; + producer = tx_ring->producer; + consumer = tx_ring->sw_consumer; + + if (nr_desc >= find_diff_among(producer, consumer, tx_ring->num_desc)) { + netif_tx_unlock_bh(adapter->netdev); + return -EBUSY; + } + do { cmd_desc = &cmd_desc_arr[i]; - pbuf = &adapter->cmd_buf_arr[producer]; + pbuf = &tx_ring->cmd_buf_arr[producer]; pbuf->skb = NULL; pbuf->frag_count = 0; - /* adapter->ahw.cmd_desc_head[producer] = *cmd_desc; */ - memcpy(&adapter->ahw.cmd_desc_head[producer], + memcpy(&tx_ring->desc_head[producer], &cmd_desc_arr[i], sizeof(struct cmd_desc_type0)); - producer = get_next_index(producer, - adapter->num_txd); + producer = get_next_index(producer, tx_ring->num_desc); i++; - } while (i != nr_elements); + } while (i != nr_desc); - adapter->cmd_producer = producer; + tx_ring->producer = producer; - /* write producer index to start the xmit */ - - netxen_nic_update_cmd_producer(adapter, adapter->cmd_producer); + netxen_nic_update_cmd_producer(adapter, tx_ring); netif_tx_unlock_bh(adapter->netdev); return 0; } -static int nx_p3_sre_macaddr_change(struct net_device *dev, - u8 *addr, unsigned op) +static int +nx_p3_sre_macaddr_change(struct netxen_adapter *adapter, u8 *addr, unsigned op) { - struct netxen_adapter *adapter = netdev_priv(dev); nx_nic_req_t req; nx_mac_req_t *mac_req; u64 word; - int rv; memset(&req, 0, sizeof(nx_nic_req_t)); req.qhdr = cpu_to_le64(NX_NIC_REQUEST << 23); @@ -550,28 +512,51 @@ static int nx_p3_sre_macaddr_change(struct net_device *dev, mac_req->op = op; memcpy(mac_req->mac_addr, addr, 6); - rv = netxen_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1); - if (rv != 0) { - printk(KERN_ERR "ERROR. Could not send mac update\n"); - return rv; + return netxen_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1); +} + +static int nx_p3_nic_add_mac(struct netxen_adapter *adapter, + u8 *addr, struct list_head *del_list) +{ + struct list_head *head; + nx_mac_list_t *cur; + + /* look up if already exists */ + list_for_each(head, del_list) { + cur = list_entry(head, nx_mac_list_t, list); + + if (memcmp(addr, cur->mac_addr, ETH_ALEN) == 0) { + list_move_tail(head, &adapter->mac_list); + return 0; + } } - return 0; + cur = kzalloc(sizeof(nx_mac_list_t), GFP_ATOMIC); + if (cur == NULL) { + printk(KERN_ERR "%s: failed to add mac address filter\n", + adapter->netdev->name); + return -ENOMEM; + } + memcpy(cur->mac_addr, addr, ETH_ALEN); + list_add_tail(&cur->list, &adapter->mac_list); + return nx_p3_sre_macaddr_change(adapter, + cur->mac_addr, NETXEN_MAC_ADD); } void netxen_p3_nic_set_multi(struct net_device *netdev) { struct netxen_adapter *adapter = netdev_priv(netdev); - nx_mac_list_t *cur, *next, *del_list, *add_list = NULL; struct dev_mc_list *mc_ptr; u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; u32 mode = VPORT_MISS_MODE_DROP; + LIST_HEAD(del_list); + struct list_head *head; + nx_mac_list_t *cur; - del_list = adapter->mac_list; - adapter->mac_list = NULL; + list_splice_tail_init(&adapter->mac_list, &del_list); - nx_p3_nic_add_mac(adapter, netdev->dev_addr, &add_list, &del_list); - nx_p3_nic_add_mac(adapter, bcast_addr, &add_list, &del_list); + nx_p3_nic_add_mac(adapter, netdev->dev_addr, &del_list); + nx_p3_nic_add_mac(adapter, bcast_addr, &del_list); if (netdev->flags & IFF_PROMISC) { mode = VPORT_MISS_MODE_ACCEPT_ALL; @@ -587,25 +572,20 @@ void netxen_p3_nic_set_multi(struct net_device *netdev) if (netdev->mc_count > 0) { for (mc_ptr = netdev->mc_list; mc_ptr; mc_ptr = mc_ptr->next) { - nx_p3_nic_add_mac(adapter, mc_ptr->dmi_addr, - &add_list, &del_list); + nx_p3_nic_add_mac(adapter, mc_ptr->dmi_addr, &del_list); } } send_fw_cmd: adapter->set_promisc(adapter, mode); - for (cur = del_list; cur;) { - nx_p3_sre_macaddr_change(netdev, cur->mac_addr, NETXEN_MAC_DEL); - next = cur->next; + head = &del_list; + while (!list_empty(head)) { + cur = list_entry(head->next, nx_mac_list_t, list); + + nx_p3_sre_macaddr_change(adapter, + cur->mac_addr, NETXEN_MAC_DEL); + list_del(&cur->list); kfree(cur); - cur = next; - } - for (cur = add_list; cur;) { - nx_p3_sre_macaddr_change(netdev, cur->mac_addr, NETXEN_MAC_ADD); - next = cur->next; - cur->next = adapter->mac_list; - adapter->mac_list = cur; - cur = next; } } @@ -630,17 +610,25 @@ int netxen_p3_nic_set_promisc(struct netxen_adapter *adapter, u32 mode) void netxen_p3_free_mac_list(struct netxen_adapter *adapter) { - nx_mac_list_t *cur, *next; + nx_mac_list_t *cur; + struct list_head *head = &adapter->mac_list; - cur = adapter->mac_list; - - while (cur) { - next = cur->next; + while (!list_empty(head)) { + cur = list_entry(head->next, nx_mac_list_t, list); + nx_p3_sre_macaddr_change(adapter, + cur->mac_addr, NETXEN_MAC_DEL); + list_del(&cur->list); kfree(cur); - cur = next; } } +int netxen_p3_nic_set_mac_addr(struct netxen_adapter *adapter, u8 *addr) +{ + /* assuming caller has already copied new addr to netdev */ + netxen_p3_nic_set_multi(adapter->netdev); + return 0; +} + #define NETXEN_CONFIG_INTR_COALESCE 3 /* @@ -717,6 +705,28 @@ int netxen_config_rss(struct netxen_adapter *adapter, int enable) return rv; } +int netxen_linkevent_request(struct netxen_adapter *adapter, int enable) +{ + nx_nic_req_t req; + u64 word; + int rv; + + memset(&req, 0, sizeof(nx_nic_req_t)); + req.qhdr = cpu_to_le64(NX_HOST_REQUEST << 23); + + word = NX_NIC_H2C_OPCODE_GET_LINKEVENT | ((u64)adapter->portnum << 16); + req.req_hdr = cpu_to_le64(word); + req.words[0] = cpu_to_le64(enable | (enable << 8)); + + rv = netxen_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1); + if (rv != 0) { + printk(KERN_ERR "%s: could not configure link notification\n", + adapter->netdev->name); + } + + return rv; +} + /* * netxen_nic_change_mtu - Change the Maximum Transfer Unit * @returns 0 on success, negative on failure @@ -812,8 +822,8 @@ int netxen_p3_get_mac_addr(struct netxen_adapter *adapter, __le64 *mac) crbaddr = CRB_MAC_BLOCK_START + (4 * ((pci_func/2) * 3)) + (4 * (pci_func & 1)); - adapter->hw_read_wx(adapter, crbaddr, &mac_lo, 4); - adapter->hw_read_wx(adapter, crbaddr+4, &mac_hi, 4); + mac_lo = NXRD32(adapter, crbaddr); + mac_hi = NXRD32(adapter, crbaddr+4); if (pci_func & 1) *mac = le64_to_cpu((mac_lo >> 16) | ((u64)mac_hi << 16)); @@ -831,8 +841,7 @@ static int crb_win_lock(struct netxen_adapter *adapter) while (!done) { /* acquire semaphore3 from PCI HW block */ - adapter->hw_read_wx(adapter, - NETXEN_PCIE_REG(PCIE_SEM7_LOCK), &done, 4); + done = NXRD32(adapter, NETXEN_PCIE_REG(PCIE_SEM7_LOCK)); if (done == 1) break; if (timeout >= CRB_WIN_LOCK_TIMEOUT) @@ -840,8 +849,7 @@ static int crb_win_lock(struct netxen_adapter *adapter) timeout++; udelay(1); } - netxen_crb_writelit_adapter(adapter, - NETXEN_CRB_WIN_LOCK_ID, adapter->portnum); + NXWR32(adapter, NETXEN_CRB_WIN_LOCK_ID, adapter->portnum); return 0; } @@ -849,8 +857,7 @@ static void crb_win_unlock(struct netxen_adapter *adapter) { int val; - adapter->hw_read_wx(adapter, - NETXEN_PCIE_REG(PCIE_SEM7_UNLOCK), &val, 4); + val = NXRD32(adapter, NETXEN_PCIE_REG(PCIE_SEM7_UNLOCK)); } /* @@ -907,17 +914,15 @@ netxen_nic_pci_change_crbwindow_128M(struct netxen_adapter *adapter, u32 wndw) * In: 'off' is offset from base in 128M pci map */ static int -netxen_nic_pci_get_crb_addr_2M(struct netxen_adapter *adapter, - ulong *off, int len) +netxen_nic_pci_get_crb_addr_2M(struct netxen_adapter *adapter, ulong *off) { - unsigned long end = *off + len; crb_128M_2M_sub_block_map_t *m; if (*off >= NETXEN_CRB_MAX) return -1; - if (*off >= NETXEN_PCI_CAMQM && (end <= NETXEN_PCI_CAMQM_2M_END)) { + if (*off >= NETXEN_PCI_CAMQM && (*off < NETXEN_PCI_CAMQM_2M_END)) { *off = (*off - NETXEN_PCI_CAMQM) + NETXEN_PCI_CAMQM_2M_BASE + (ulong)adapter->ahw.pci_base0; return 0; @@ -927,14 +932,13 @@ netxen_nic_pci_get_crb_addr_2M(struct netxen_adapter *adapter, return -1; *off -= NETXEN_PCI_CRBSPACE; - end = *off + len; /* * Try direct map */ m = &crb_128M_2M_map[CRB_BLK(*off)].sub_block[CRB_SUBBLK(*off)]; - if (m->valid && (m->start_128M <= *off) && (m->end_128M >= end)) { + if (m->valid && (m->start_128M <= *off) && (m->end_128M > *off)) { *off = *off + m->start_2M - m->start_128M + (ulong)adapter->ahw.pci_base0; return 0; @@ -972,214 +976,11 @@ netxen_nic_pci_set_crbwindow_2M(struct netxen_adapter *adapter, ulong *off) (ulong)adapter->ahw.pci_base0; } -static int -netxen_do_load_firmware(struct netxen_adapter *adapter, const char *fwname, - const struct firmware *fw) -{ - u64 *ptr64; - u32 i, flashaddr, size; - struct pci_dev *pdev = adapter->pdev; - - if (fw) - dev_info(&pdev->dev, "loading firmware from file %s\n", fwname); - else - dev_info(&pdev->dev, "loading firmware from flash\n"); - - if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) - adapter->pci_write_normalize(adapter, - NETXEN_ROMUSB_GLB_CAS_RST, 1); - - if (fw) { - __le64 data; - - size = (NETXEN_IMAGE_START - NETXEN_BOOTLD_START) / 8; - - ptr64 = (u64 *)&fw->data[NETXEN_BOOTLD_START]; - flashaddr = NETXEN_BOOTLD_START; - - for (i = 0; i < size; i++) { - data = cpu_to_le64(ptr64[i]); - adapter->pci_mem_write(adapter, flashaddr, &data, 8); - flashaddr += 8; - } - - size = *(u32 *)&fw->data[NX_FW_SIZE_OFFSET]; - size = (__force u32)cpu_to_le32(size) / 8; - - ptr64 = (u64 *)&fw->data[NETXEN_IMAGE_START]; - flashaddr = NETXEN_IMAGE_START; - - for (i = 0; i < size; i++) { - data = cpu_to_le64(ptr64[i]); - - if (adapter->pci_mem_write(adapter, - flashaddr, &data, 8)) - return -EIO; - - flashaddr += 8; - } - } else { - u32 data; - - size = (NETXEN_IMAGE_START - NETXEN_BOOTLD_START) / 4; - flashaddr = NETXEN_BOOTLD_START; - - for (i = 0; i < size; i++) { - if (netxen_rom_fast_read(adapter, - flashaddr, (int *)&data) != 0) - return -EIO; - - if (adapter->pci_mem_write(adapter, - flashaddr, &data, 4)) - return -EIO; - - flashaddr += 4; - } - } - msleep(1); - - if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) - adapter->pci_write_normalize(adapter, - NETXEN_ROMUSB_GLB_SW_RESET, 0x80001d); - else { - adapter->pci_write_normalize(adapter, - NETXEN_ROMUSB_GLB_CHIP_CLK_CTRL, 0x3fff); - adapter->pci_write_normalize(adapter, - NETXEN_ROMUSB_GLB_CAS_RST, 0); - } - - return 0; -} - -static int -netxen_validate_firmware(struct netxen_adapter *adapter, const char *fwname, - const struct firmware *fw) -{ - __le32 val; - u32 major, minor, build, ver, min_ver, bios; - struct pci_dev *pdev = adapter->pdev; - - if (fw->size < NX_FW_MIN_SIZE) - return -EINVAL; - - val = cpu_to_le32(*(u32 *)&fw->data[NX_FW_MAGIC_OFFSET]); - if ((__force u32)val != NETXEN_BDINFO_MAGIC) - return -EINVAL; - - val = cpu_to_le32(*(u32 *)&fw->data[NX_FW_VERSION_OFFSET]); - major = (__force u32)val & 0xff; - minor = ((__force u32)val >> 8) & 0xff; - build = (__force u32)val >> 16; - - if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) - min_ver = NETXEN_VERSION_CODE(4, 0, 216); - else - min_ver = NETXEN_VERSION_CODE(3, 4, 216); - - ver = NETXEN_VERSION_CODE(major, minor, build); - - if ((major > _NETXEN_NIC_LINUX_MAJOR) || (ver < min_ver)) { - dev_err(&pdev->dev, - "%s: firmware version %d.%d.%d unsupported\n", - fwname, major, minor, build); - return -EINVAL; - } - - val = cpu_to_le32(*(u32 *)&fw->data[NX_BIOS_VERSION_OFFSET]); - netxen_rom_fast_read(adapter, NX_BIOS_VERSION_OFFSET, (int *)&bios); - if ((__force u32)val != bios) { - dev_err(&pdev->dev, "%s: firmware bios is incompatible\n", - fwname); - return -EINVAL; - } - - /* check if flashed firmware is newer */ - if (netxen_rom_fast_read(adapter, - NX_FW_VERSION_OFFSET, (int *)&val)) - return -EIO; - major = (__force u32)val & 0xff; - minor = ((__force u32)val >> 8) & 0xff; - build = (__force u32)val >> 16; - if (NETXEN_VERSION_CODE(major, minor, build) > ver) - return -EINVAL; - - netxen_nic_reg_write(adapter, NETXEN_CAM_RAM(0x1fc), - NETXEN_BDINFO_MAGIC); - return 0; -} - -static char *fw_name[] = { "nxromimg.bin", "nx3fwct.bin", "nx3fwmn.bin" }; - -int netxen_load_firmware(struct netxen_adapter *adapter) -{ - u32 capability, flashed_ver; - const struct firmware *fw; - int fw_type; - struct pci_dev *pdev = adapter->pdev; - int rc = 0; - - if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { - fw_type = NX_P2_MN_ROMIMAGE; - goto request_fw; - } else { - fw_type = NX_P3_CT_ROMIMAGE; - goto request_fw; - } - -request_mn: - capability = 0; - - netxen_rom_fast_read(adapter, - NX_FW_VERSION_OFFSET, (int *)&flashed_ver); - if (flashed_ver >= NETXEN_VERSION_CODE(4, 0, 220)) { - adapter->hw_read_wx(adapter, - NX_PEG_TUNE_CAPABILITY, &capability, 4); - if (capability & NX_PEG_TUNE_MN_PRESENT) { - fw_type = NX_P3_MN_ROMIMAGE; - goto request_fw; - } - } - -request_fw: - rc = request_firmware(&fw, fw_name[fw_type], &pdev->dev); - if (rc != 0) { - if (fw_type == NX_P3_CT_ROMIMAGE) { - msleep(1); - goto request_mn; - } - - fw = NULL; - goto load_fw; - } - - rc = netxen_validate_firmware(adapter, fw_name[fw_type], fw); - if (rc != 0) { - release_firmware(fw); - - if (fw_type == NX_P3_CT_ROMIMAGE) { - msleep(1); - goto request_mn; - } - - fw = NULL; - } - -load_fw: - rc = netxen_do_load_firmware(adapter, fw_name[fw_type], fw); - - if (fw) - release_firmware(fw); - return rc; -} - int -netxen_nic_hw_write_wx_128M(struct netxen_adapter *adapter, - ulong off, void *data, int len) +netxen_nic_hw_write_wx_128M(struct netxen_adapter *adapter, ulong off, u32 data) { void __iomem *addr; - BUG_ON(len != 4); - if (ADDR_IN_WINDOW1(off)) { addr = NETXEN_CRB_NORMALIZE(adapter, off); } else { /* Window 0 */ @@ -1192,7 +993,7 @@ netxen_nic_hw_write_wx_128M(struct netxen_adapter *adapter, return 1; } - writel(*(u32 *) data, addr); + writel(data, addr); if (!ADDR_IN_WINDOW1(off)) netxen_nic_pci_change_crbwindow_128M(adapter, 1); @@ -1200,13 +1001,11 @@ netxen_nic_hw_write_wx_128M(struct netxen_adapter *adapter, return 0; } -int -netxen_nic_hw_read_wx_128M(struct netxen_adapter *adapter, - ulong off, void *data, int len) +u32 +netxen_nic_hw_read_wx_128M(struct netxen_adapter *adapter, ulong off) { void __iomem *addr; - - BUG_ON(len != 4); + u32 data; if (ADDR_IN_WINDOW1(off)) { /* Window 1 */ addr = NETXEN_CRB_NORMALIZE(adapter, off); @@ -1220,24 +1019,21 @@ netxen_nic_hw_read_wx_128M(struct netxen_adapter *adapter, return 1; } - *(u32 *)data = readl(addr); + data = readl(addr); if (!ADDR_IN_WINDOW1(off)) netxen_nic_pci_change_crbwindow_128M(adapter, 1); - return 0; + return data; } int -netxen_nic_hw_write_wx_2M(struct netxen_adapter *adapter, - ulong off, void *data, int len) +netxen_nic_hw_write_wx_2M(struct netxen_adapter *adapter, ulong off, u32 data) { unsigned long flags = 0; int rv; - BUG_ON(len != 4); - - rv = netxen_nic_pci_get_crb_addr_2M(adapter, &off, len); + rv = netxen_nic_pci_get_crb_addr_2M(adapter, &off); if (rv == -1) { printk(KERN_ERR "%s: invalid offset: 0x%016lx\n", @@ -1250,26 +1046,24 @@ netxen_nic_hw_write_wx_2M(struct netxen_adapter *adapter, write_lock_irqsave(&adapter->adapter_lock, flags); crb_win_lock(adapter); netxen_nic_pci_set_crbwindow_2M(adapter, &off); - writel(*(uint32_t *)data, (void __iomem *)off); + writel(data, (void __iomem *)off); crb_win_unlock(adapter); write_unlock_irqrestore(&adapter->adapter_lock, flags); } else - writel(*(uint32_t *)data, (void __iomem *)off); + writel(data, (void __iomem *)off); return 0; } -int -netxen_nic_hw_read_wx_2M(struct netxen_adapter *adapter, - ulong off, void *data, int len) +u32 +netxen_nic_hw_read_wx_2M(struct netxen_adapter *adapter, ulong off) { unsigned long flags = 0; int rv; + u32 data; - BUG_ON(len != 4); - - rv = netxen_nic_pci_get_crb_addr_2M(adapter, &off, len); + rv = netxen_nic_pci_get_crb_addr_2M(adapter, &off); if (rv == -1) { printk(KERN_ERR "%s: invalid offset: 0x%016lx\n", @@ -1282,47 +1076,13 @@ netxen_nic_hw_read_wx_2M(struct netxen_adapter *adapter, write_lock_irqsave(&adapter->adapter_lock, flags); crb_win_lock(adapter); netxen_nic_pci_set_crbwindow_2M(adapter, &off); - *(uint32_t *)data = readl((void __iomem *)off); + data = readl((void __iomem *)off); crb_win_unlock(adapter); write_unlock_irqrestore(&adapter->adapter_lock, flags); } else - *(uint32_t *)data = readl((void __iomem *)off); + data = readl((void __iomem *)off); - return 0; -} - -void netxen_nic_reg_write(struct netxen_adapter *adapter, u64 off, u32 val) -{ - adapter->hw_write_wx(adapter, off, &val, 4); -} - -int netxen_nic_reg_read(struct netxen_adapter *adapter, u64 off) -{ - int val; - adapter->hw_read_wx(adapter, off, &val, 4); - return val; -} - -/* Change the window to 0, write and change back to window 1. */ -void netxen_nic_write_w0(struct netxen_adapter *adapter, u32 index, u32 value) -{ - adapter->hw_write_wx(adapter, index, &value, 4); -} - -/* Change the window to 0, read and change back to window 1. */ -void netxen_nic_read_w0(struct netxen_adapter *adapter, u32 index, u32 *value) -{ - adapter->hw_read_wx(adapter, index, value, 4); -} - -void netxen_nic_write_w1(struct netxen_adapter *adapter, u32 index, u32 value) -{ - adapter->hw_write_wx(adapter, index, &value, 4); -} - -void netxen_nic_read_w1(struct netxen_adapter *adapter, u32 index, u32 *value) -{ - adapter->hw_read_wx(adapter, index, value, 4); + return data; } /* @@ -1425,17 +1185,6 @@ u32 netxen_nic_pci_read_immediate_128M(struct netxen_adapter *adapter, u64 off) return readl((void __iomem *)(pci_base_offset(adapter, off))); } -void netxen_nic_pci_write_normalize_128M(struct netxen_adapter *adapter, - u64 off, u32 data) -{ - writel(data, NETXEN_CRB_NORMALIZE(adapter, off)); -} - -u32 netxen_nic_pci_read_normalize_128M(struct netxen_adapter *adapter, u64 off) -{ - return readl(NETXEN_CRB_NORMALIZE(adapter, off)); -} - unsigned long netxen_nic_pci_set_window_2M(struct netxen_adapter *adapter, unsigned long long addr) @@ -1447,12 +1196,10 @@ netxen_nic_pci_set_window_2M(struct netxen_adapter *adapter, /* DDR network side */ window = MN_WIN(addr); adapter->ahw.ddr_mn_window = window; - adapter->hw_write_wx(adapter, - adapter->ahw.mn_win_crb | NETXEN_PCI_CRBSPACE, - &window, 4); - adapter->hw_read_wx(adapter, - adapter->ahw.mn_win_crb | NETXEN_PCI_CRBSPACE, - &win_read, 4); + NXWR32(adapter, adapter->ahw.mn_win_crb | NETXEN_PCI_CRBSPACE, + window); + win_read = NXRD32(adapter, + adapter->ahw.mn_win_crb | NETXEN_PCI_CRBSPACE); if ((win_read << 17) != window) { printk(KERN_INFO "Written MNwin (0x%x) != " "Read MNwin (0x%x)\n", window, win_read); @@ -1467,12 +1214,10 @@ netxen_nic_pci_set_window_2M(struct netxen_adapter *adapter, window = OCM_WIN(addr); adapter->ahw.ddr_mn_window = window; - adapter->hw_write_wx(adapter, - adapter->ahw.mn_win_crb | NETXEN_PCI_CRBSPACE, - &window, 4); - adapter->hw_read_wx(adapter, - adapter->ahw.mn_win_crb | NETXEN_PCI_CRBSPACE, - &win_read, 4); + NXWR32(adapter, adapter->ahw.mn_win_crb | NETXEN_PCI_CRBSPACE, + window); + win_read = NXRD32(adapter, + adapter->ahw.mn_win_crb | NETXEN_PCI_CRBSPACE); if ((win_read >> 7) != window) { printk(KERN_INFO "%s: Written OCMwin (0x%x) != " "Read OCMwin (0x%x)\n", @@ -1485,12 +1230,10 @@ netxen_nic_pci_set_window_2M(struct netxen_adapter *adapter, /* QDR network side */ window = MS_WIN(addr); adapter->ahw.qdr_sn_window = window; - adapter->hw_write_wx(adapter, - adapter->ahw.ms_win_crb | NETXEN_PCI_CRBSPACE, - &window, 4); - adapter->hw_read_wx(adapter, - adapter->ahw.ms_win_crb | NETXEN_PCI_CRBSPACE, - &win_read, 4); + NXWR32(adapter, adapter->ahw.ms_win_crb | NETXEN_PCI_CRBSPACE, + window); + win_read = NXRD32(adapter, + adapter->ahw.ms_win_crb | NETXEN_PCI_CRBSPACE); if (win_read != window) { printk(KERN_INFO "%s: Written MSwin (0x%x) != " "Read MSwin (0x%x)\n", @@ -1936,27 +1679,20 @@ netxen_nic_pci_mem_write_2M(struct netxen_adapter *adapter, for (i = 0; i < loop; i++) { temp = off8 + (i << 3); - adapter->hw_write_wx(adapter, - mem_crb+MIU_TEST_AGT_ADDR_LO, &temp, 4); + NXWR32(adapter, mem_crb+MIU_TEST_AGT_ADDR_LO, temp); temp = 0; - adapter->hw_write_wx(adapter, - mem_crb+MIU_TEST_AGT_ADDR_HI, &temp, 4); + NXWR32(adapter, mem_crb+MIU_TEST_AGT_ADDR_HI, temp); temp = word[i] & 0xffffffff; - adapter->hw_write_wx(adapter, - mem_crb+MIU_TEST_AGT_WRDATA_LO, &temp, 4); + NXWR32(adapter, mem_crb+MIU_TEST_AGT_WRDATA_LO, temp); temp = (word[i] >> 32) & 0xffffffff; - adapter->hw_write_wx(adapter, - mem_crb+MIU_TEST_AGT_WRDATA_HI, &temp, 4); + NXWR32(adapter, mem_crb+MIU_TEST_AGT_WRDATA_HI, temp); temp = MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE; - adapter->hw_write_wx(adapter, - mem_crb+MIU_TEST_AGT_CTRL, &temp, 4); + NXWR32(adapter, mem_crb+MIU_TEST_AGT_CTRL, temp); temp = MIU_TA_CTL_START | MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE; - adapter->hw_write_wx(adapter, - mem_crb+MIU_TEST_AGT_CTRL, &temp, 4); + NXWR32(adapter, mem_crb+MIU_TEST_AGT_CTRL, temp); for (j = 0; j < MAX_CTL_CHECK; j++) { - adapter->hw_read_wx(adapter, - mem_crb + MIU_TEST_AGT_CTRL, &temp, 4); + temp = NXRD32(adapter, mem_crb + MIU_TEST_AGT_CTRL); if ((temp & MIU_TA_CTL_BUSY) == 0) break; } @@ -2013,21 +1749,16 @@ netxen_nic_pci_mem_read_2M(struct netxen_adapter *adapter, for (i = 0; i < loop; i++) { temp = off8 + (i << 3); - adapter->hw_write_wx(adapter, - mem_crb + MIU_TEST_AGT_ADDR_LO, &temp, 4); + NXWR32(adapter, mem_crb + MIU_TEST_AGT_ADDR_LO, temp); temp = 0; - adapter->hw_write_wx(adapter, - mem_crb + MIU_TEST_AGT_ADDR_HI, &temp, 4); + NXWR32(adapter, mem_crb + MIU_TEST_AGT_ADDR_HI, temp); temp = MIU_TA_CTL_ENABLE; - adapter->hw_write_wx(adapter, - mem_crb + MIU_TEST_AGT_CTRL, &temp, 4); + NXWR32(adapter, mem_crb + MIU_TEST_AGT_CTRL, temp); temp = MIU_TA_CTL_START | MIU_TA_CTL_ENABLE; - adapter->hw_write_wx(adapter, - mem_crb + MIU_TEST_AGT_CTRL, &temp, 4); + NXWR32(adapter, mem_crb + MIU_TEST_AGT_CTRL, temp); for (j = 0; j < MAX_CTL_CHECK; j++) { - adapter->hw_read_wx(adapter, - mem_crb + MIU_TEST_AGT_CTRL, &temp, 4); + temp = NXRD32(adapter, mem_crb + MIU_TEST_AGT_CTRL); if ((temp & MIU_TA_CTL_BUSY) == 0) break; } @@ -2042,8 +1773,8 @@ netxen_nic_pci_mem_read_2M(struct netxen_adapter *adapter, start = off0[i] >> 2; end = (off0[i] + sz[i] - 1) >> 2; for (k = start; k <= end; k++) { - adapter->hw_read_wx(adapter, - mem_crb + MIU_TEST_AGT_RDDATA(k), &temp, 4); + temp = NXRD32(adapter, + mem_crb + MIU_TEST_AGT_RDDATA(k)); word[i] |= ((uint64_t)temp << (32 * k)); } } @@ -2086,29 +1817,14 @@ netxen_nic_pci_mem_read_2M(struct netxen_adapter *adapter, int netxen_nic_pci_write_immediate_2M(struct netxen_adapter *adapter, u64 off, u32 data) { - adapter->hw_write_wx(adapter, off, &data, 4); + NXWR32(adapter, off, data); return 0; } u32 netxen_nic_pci_read_immediate_2M(struct netxen_adapter *adapter, u64 off) { - u32 temp; - adapter->hw_read_wx(adapter, off, &temp, 4); - return temp; -} - -void netxen_nic_pci_write_normalize_2M(struct netxen_adapter *adapter, - u64 off, u32 data) -{ - adapter->hw_write_wx(adapter, off, &data, 4); -} - -u32 netxen_nic_pci_read_normalize_2M(struct netxen_adapter *adapter, u64 off) -{ - u32 temp; - adapter->hw_read_wx(adapter, off, &temp, 4); - return temp; + return NXRD32(adapter, off); } int netxen_nic_get_board_info(struct netxen_adapter *adapter) @@ -2142,13 +1858,12 @@ int netxen_nic_get_board_info(struct netxen_adapter *adapter) adapter->ahw.board_type = board_type; if (board_type == NETXEN_BRDTYPE_P3_4_GB_MM) { - u32 gpio = netxen_nic_reg_read(adapter, - NETXEN_ROMUSB_GLB_PAD_GPIO_I); + u32 gpio = NXRD32(adapter, NETXEN_ROMUSB_GLB_PAD_GPIO_I); if ((gpio & 0x8000) == 0) board_type = NETXEN_BRDTYPE_P3_10G_TP; } - switch ((netxen_brdtype_t)board_type) { + switch (board_type) { case NETXEN_BRDTYPE_P2_SB35_4G: adapter->ahw.port_type = NETXEN_NIC_GBE; break; @@ -2195,8 +1910,7 @@ int netxen_nic_get_board_info(struct netxen_adapter *adapter) int netxen_nic_set_mtu_gb(struct netxen_adapter *adapter, int new_mtu) { new_mtu += MTU_FUDGE_FACTOR; - netxen_nic_write_w0(adapter, - NETXEN_NIU_GB_MAX_FRAME_SIZE(adapter->physical_port), + NXWR32(adapter, NETXEN_NIU_GB_MAX_FRAME_SIZE(adapter->physical_port), new_mtu); return 0; } @@ -2205,21 +1919,12 @@ int netxen_nic_set_mtu_xgb(struct netxen_adapter *adapter, int new_mtu) { new_mtu += MTU_FUDGE_FACTOR; if (adapter->physical_port == 0) - netxen_nic_write_w0(adapter, NETXEN_NIU_XGE_MAX_FRAME_SIZE, - new_mtu); + NXWR32(adapter, NETXEN_NIU_XGE_MAX_FRAME_SIZE, new_mtu); else - netxen_nic_write_w0(adapter, NETXEN_NIU_XG1_MAX_FRAME_SIZE, - new_mtu); + NXWR32(adapter, NETXEN_NIU_XG1_MAX_FRAME_SIZE, new_mtu); return 0; } -void -netxen_crb_writelit_adapter(struct netxen_adapter *adapter, - unsigned long off, int data) -{ - adapter->hw_write_wx(adapter, off, &data, 4); -} - void netxen_nic_set_link_parameters(struct netxen_adapter *adapter) { __u32 status; @@ -2234,8 +1939,7 @@ void netxen_nic_set_link_parameters(struct netxen_adapter *adapter) } if (adapter->ahw.port_type == NETXEN_NIC_GBE) { - adapter->hw_read_wx(adapter, - NETXEN_PORT_MODE_ADDR, &port_mode, 4); + port_mode = NXRD32(adapter, NETXEN_PORT_MODE_ADDR); if (port_mode == NETXEN_PORT_MODE_802_3_AP) { adapter->link_speed = SPEED_1000; adapter->link_duplex = DUPLEX_FULL; @@ -2312,9 +2016,9 @@ void netxen_nic_get_firmware_info(struct netxen_adapter *adapter) addr += sizeof(u32); } - adapter->hw_read_wx(adapter, NETXEN_FW_VERSION_MAJOR, &fw_major, 4); - adapter->hw_read_wx(adapter, NETXEN_FW_VERSION_MINOR, &fw_minor, 4); - adapter->hw_read_wx(adapter, NETXEN_FW_VERSION_SUB, &fw_build, 4); + fw_major = NXRD32(adapter, NETXEN_FW_VERSION_MAJOR); + fw_minor = NXRD32(adapter, NETXEN_FW_VERSION_MINOR); + fw_build = NXRD32(adapter, NETXEN_FW_VERSION_SUB); adapter->fw_major = fw_major; adapter->fw_version = NETXEN_VERSION_CODE(fw_major, fw_minor, fw_build); @@ -2337,9 +2041,8 @@ void netxen_nic_get_firmware_info(struct netxen_adapter *adapter) fw_major, fw_minor, fw_build); if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) { - adapter->hw_read_wx(adapter, - NETXEN_MIU_MN_CONTROL, &i, 4); - adapter->ahw.cut_through = (i & 0x4) ? 1 : 0; + i = NXRD32(adapter, NETXEN_SRE_MISC); + adapter->ahw.cut_through = (i & 0x8000) ? 1 : 0; dev_info(&pdev->dev, "firmware running in %s mode\n", adapter->ahw.cut_through ? "cut-through" : "legacy"); } @@ -2353,9 +2056,9 @@ netxen_nic_wol_supported(struct netxen_adapter *adapter) if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) return 0; - wol_cfg = netxen_nic_reg_read(adapter, NETXEN_WOL_CONFIG_NV); + wol_cfg = NXRD32(adapter, NETXEN_WOL_CONFIG_NV); if (wol_cfg & (1UL << adapter->portnum)) { - wol_cfg = netxen_nic_reg_read(adapter, NETXEN_WOL_CONFIG); + wol_cfg = NXRD32(adapter, NETXEN_WOL_CONFIG); if (wol_cfg & (1 << adapter->portnum)) return 1; } diff --git a/drivers/net/netxen/netxen_nic_hw.h b/drivers/net/netxen/netxen_nic_hw.h index 04b47a7993cd..d4e833339781 100644 --- a/drivers/net/netxen/netxen_nic_hw.h +++ b/drivers/net/netxen/netxen_nic_hw.h @@ -36,35 +36,13 @@ /* Hardware memory size of 128 meg */ #define NETXEN_MEMADDR_MAX (128 * 1024 * 1024) -#ifndef readq -static inline u64 readq(void __iomem * addr) -{ - return readl(addr) | (((u64) readl(addr + 4)) << 32LL); -} -#endif - -#ifndef writeq -static inline void writeq(u64 val, void __iomem * addr) -{ - writel(((u32) (val)), (addr)); - writel(((u32) (val >> 32)), (addr + 4)); -} -#endif - struct netxen_adapter; #define NETXEN_PCI_MAPSIZE_BYTES (NETXEN_PCI_MAPSIZE << 20) -struct netxen_port; void netxen_nic_set_link_parameters(struct netxen_adapter *adapter); -typedef u8 netxen_ethernet_macaddr_t[6]; - /* Nibble or Byte mode for phy interface (GbE mode only) */ -typedef enum { - NETXEN_NIU_10_100_MB = 0, - NETXEN_NIU_1000_MB -} netxen_niu_gbe_ifmode_t; #define _netxen_crb_get_bit(var, bit) ((var >> bit) & 0x1) @@ -222,30 +200,28 @@ typedef enum { /* * PHY-Specific MII control/status registers. */ -typedef enum { - NETXEN_NIU_GB_MII_MGMT_ADDR_CONTROL = 0, - NETXEN_NIU_GB_MII_MGMT_ADDR_STATUS = 1, - NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_ID_0 = 2, - NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_ID_1 = 3, - NETXEN_NIU_GB_MII_MGMT_ADDR_AUTONEG = 4, - NETXEN_NIU_GB_MII_MGMT_ADDR_LNKPART = 5, - NETXEN_NIU_GB_MII_MGMT_ADDR_AUTONEG_MORE = 6, - NETXEN_NIU_GB_MII_MGMT_ADDR_NEXTPAGE_XMIT = 7, - NETXEN_NIU_GB_MII_MGMT_ADDR_LNKPART_NEXTPAGE = 8, - NETXEN_NIU_GB_MII_MGMT_ADDR_1000BT_CONTROL = 9, - NETXEN_NIU_GB_MII_MGMT_ADDR_1000BT_STATUS = 10, - NETXEN_NIU_GB_MII_MGMT_ADDR_EXTENDED_STATUS = 15, - NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_CONTROL = 16, - NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS = 17, - NETXEN_NIU_GB_MII_MGMT_ADDR_INT_ENABLE = 18, - NETXEN_NIU_GB_MII_MGMT_ADDR_INT_STATUS = 19, - NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_CONTROL_MORE = 20, - NETXEN_NIU_GB_MII_MGMT_ADDR_RECV_ERROR_COUNT = 21, - NETXEN_NIU_GB_MII_MGMT_ADDR_LED_CONTROL = 24, - NETXEN_NIU_GB_MII_MGMT_ADDR_LED_OVERRIDE = 25, - NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_CONTROL_MORE_YET = 26, - NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS_MORE = 27 -} netxen_niu_phy_register_t; +#define NETXEN_NIU_GB_MII_MGMT_ADDR_CONTROL 0 +#define NETXEN_NIU_GB_MII_MGMT_ADDR_STATUS 1 +#define NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_ID_0 2 +#define NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_ID_1 3 +#define NETXEN_NIU_GB_MII_MGMT_ADDR_AUTONEG 4 +#define NETXEN_NIU_GB_MII_MGMT_ADDR_LNKPART 5 +#define NETXEN_NIU_GB_MII_MGMT_ADDR_AUTONEG_MORE 6 +#define NETXEN_NIU_GB_MII_MGMT_ADDR_NEXTPAGE_XMIT 7 +#define NETXEN_NIU_GB_MII_MGMT_ADDR_LNKPART_NEXTPAGE 8 +#define NETXEN_NIU_GB_MII_MGMT_ADDR_1000BT_CONTROL 9 +#define NETXEN_NIU_GB_MII_MGMT_ADDR_1000BT_STATUS 10 +#define NETXEN_NIU_GB_MII_MGMT_ADDR_EXTENDED_STATUS 15 +#define NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_CONTROL 16 +#define NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS 17 +#define NETXEN_NIU_GB_MII_MGMT_ADDR_INT_ENABLE 18 +#define NETXEN_NIU_GB_MII_MGMT_ADDR_INT_STATUS 19 +#define NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_CONTROL_MORE 20 +#define NETXEN_NIU_GB_MII_MGMT_ADDR_RECV_ERROR_COUNT 21 +#define NETXEN_NIU_GB_MII_MGMT_ADDR_LED_CONTROL 24 +#define NETXEN_NIU_GB_MII_MGMT_ADDR_LED_OVERRIDE 25 +#define NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_CONTROL_MORE_YET 26 +#define NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS_MORE 27 /* * PHY-Specific Status Register (reg 17). @@ -417,14 +393,6 @@ int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, int netxen_niu_xg_set_promiscuous_mode(struct netxen_adapter *adapter, u32 mode); -/* set the MAC address for a given MAC */ -int netxen_niu_macaddr_set(struct netxen_adapter *adapter, - netxen_ethernet_macaddr_t addr); - -/* XG version */ -int netxen_niu_xg_macaddr_set(struct netxen_adapter *adapter, - netxen_ethernet_macaddr_t addr); - /* Generic enable for GbE ports. Will detect the speed of the link. */ int netxen_niu_gbe_init_port(struct netxen_adapter *adapter, int port); diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 0759c35f16ac..055bb61d6e77 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -108,42 +108,6 @@ static void crb_addr_transform_setup(void) crb_addr_transform(I2C0); } -int netxen_init_firmware(struct netxen_adapter *adapter) -{ - u32 state = 0, loops = 0, err = 0; - - /* Window 1 call */ - state = adapter->pci_read_normalize(adapter, CRB_CMDPEG_STATE); - - if (state == PHAN_INITIALIZE_ACK) - return 0; - - while (state != PHAN_INITIALIZE_COMPLETE && loops < 2000) { - msleep(1); - /* Window 1 call */ - state = adapter->pci_read_normalize(adapter, CRB_CMDPEG_STATE); - - loops++; - } - if (loops >= 2000) { - printk(KERN_ERR "Cmd Peg initialization not complete:%x.\n", - state); - err = -EIO; - return err; - } - /* Window 1 call */ - adapter->pci_write_normalize(adapter, - CRB_NIC_CAPABILITIES_HOST, INTR_SCHEME_PERPORT); - adapter->pci_write_normalize(adapter, - CRB_NIC_MSI_MODE_HOST, MSI_MODE_MULTIFUNC); - adapter->pci_write_normalize(adapter, - CRB_MPORT_MODE, MPORT_MULTI_FUNCTION_MODE); - adapter->pci_write_normalize(adapter, - CRB_CMDPEG_STATE, PHAN_INITIALIZE_ACK); - - return err; -} - void netxen_release_rx_buffers(struct netxen_adapter *adapter) { struct netxen_recv_context *recv_ctx; @@ -173,9 +137,10 @@ void netxen_release_tx_buffers(struct netxen_adapter *adapter) struct netxen_cmd_buffer *cmd_buf; struct netxen_skb_frag *buffrag; int i, j; + struct nx_host_tx_ring *tx_ring = adapter->tx_ring; - cmd_buf = adapter->cmd_buf_arr; - for (i = 0; i < adapter->num_txd; i++) { + cmd_buf = tx_ring->cmd_buf_arr; + for (i = 0; i < tx_ring->num_desc; i++) { buffrag = cmd_buf->frag_array; if (buffrag->dma) { pci_unmap_single(adapter->pdev, buffrag->dma, @@ -203,20 +168,27 @@ void netxen_free_sw_resources(struct netxen_adapter *adapter) { struct netxen_recv_context *recv_ctx; struct nx_host_rds_ring *rds_ring; + struct nx_host_tx_ring *tx_ring; int ring; recv_ctx = &adapter->recv_ctx; + + if (recv_ctx->rds_rings == NULL) + goto skip_rds; + for (ring = 0; ring < adapter->max_rds_rings; ring++) { rds_ring = &recv_ctx->rds_rings[ring]; - if (rds_ring->rx_buf_arr) { - vfree(rds_ring->rx_buf_arr); - rds_ring->rx_buf_arr = NULL; - } + vfree(rds_ring->rx_buf_arr); + rds_ring->rx_buf_arr = NULL; } + kfree(recv_ctx->rds_rings); - if (adapter->cmd_buf_arr) - vfree(adapter->cmd_buf_arr); - return; +skip_rds: + if (adapter->tx_ring == NULL) + return; + + tx_ring = adapter->tx_ring; + vfree(tx_ring->cmd_buf_arr); } int netxen_alloc_sw_resources(struct netxen_adapter *adapter) @@ -224,23 +196,45 @@ int netxen_alloc_sw_resources(struct netxen_adapter *adapter) struct netxen_recv_context *recv_ctx; struct nx_host_rds_ring *rds_ring; struct nx_host_sds_ring *sds_ring; + struct nx_host_tx_ring *tx_ring; struct netxen_rx_buffer *rx_buf; - int ring, i, num_rx_bufs; + int ring, i, size; struct netxen_cmd_buffer *cmd_buf_arr; struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; - cmd_buf_arr = - (struct netxen_cmd_buffer *)vmalloc(TX_BUFF_RINGSIZE(adapter)); - if (cmd_buf_arr == NULL) { - printk(KERN_ERR "%s: Failed to allocate cmd buffer ring\n", + size = sizeof(struct nx_host_tx_ring); + tx_ring = kzalloc(size, GFP_KERNEL); + if (tx_ring == NULL) { + dev_err(&pdev->dev, "%s: failed to allocate tx ring struct\n", netdev->name); return -ENOMEM; } - memset(cmd_buf_arr, 0, TX_BUFF_RINGSIZE(adapter)); - adapter->cmd_buf_arr = cmd_buf_arr; + adapter->tx_ring = tx_ring; + + tx_ring->num_desc = adapter->num_txd; + + cmd_buf_arr = vmalloc(TX_BUFF_RINGSIZE(tx_ring)); + if (cmd_buf_arr == NULL) { + dev_err(&pdev->dev, "%s: failed to allocate cmd buffer ring\n", + netdev->name); + return -ENOMEM; + } + memset(cmd_buf_arr, 0, TX_BUFF_RINGSIZE(tx_ring)); + tx_ring->cmd_buf_arr = cmd_buf_arr; recv_ctx = &adapter->recv_ctx; + + size = adapter->max_rds_rings * sizeof (struct nx_host_rds_ring); + rds_ring = kzalloc(size, GFP_KERNEL); + if (rds_ring == NULL) { + dev_err(&pdev->dev, "%s: failed to allocate rds ring struct\n", + netdev->name); + return -ENOMEM; + } + recv_ctx->rds_rings = rds_ring; + for (ring = 0; ring < adapter->max_rds_rings; ring++) { rds_ring = &recv_ctx->rds_rings[ring]; switch (ring) { @@ -292,9 +286,8 @@ int netxen_alloc_sw_resources(struct netxen_adapter *adapter) * Now go through all of them, set reference handles * and put them in the queues. */ - num_rx_bufs = rds_ring->num_desc; rx_buf = rds_ring->rx_buf_arr; - for (i = 0; i < num_rx_bufs; i++) { + for (i = 0; i < rds_ring->num_desc; i++) { list_add_tail(&rx_buf->list, &rds_ring->free_list); rx_buf->ref_handle = i; @@ -307,8 +300,6 @@ int netxen_alloc_sw_resources(struct netxen_adapter *adapter) for (ring = 0; ring < adapter->max_sds_rings; ring++) { sds_ring = &recv_ctx->sds_rings[ring]; sds_ring->irq = adapter->msix_entries[ring].vector; - sds_ring->clean_tx = (ring == 0); - sds_ring->post_rxd = (ring == 0); sds_ring->adapter = adapter; sds_ring->num_desc = adapter->num_rxd; @@ -325,13 +316,15 @@ err_out: void netxen_initialize_adapter_ops(struct netxen_adapter *adapter) { + adapter->macaddr_set = netxen_p2_nic_set_mac_addr; + adapter->set_multi = netxen_p2_nic_set_multi; + switch (adapter->ahw.port_type) { case NETXEN_NIC_GBE: adapter->enable_phy_interrupts = netxen_niu_gbe_enable_phy_interrupts; adapter->disable_phy_interrupts = netxen_niu_gbe_disable_phy_interrupts; - adapter->macaddr_set = netxen_niu_macaddr_set; adapter->set_mtu = netxen_nic_set_mtu_gb; adapter->set_promisc = netxen_niu_set_promiscuous_mode; adapter->phy_read = netxen_niu_gbe_phy_read; @@ -345,7 +338,6 @@ void netxen_initialize_adapter_ops(struct netxen_adapter *adapter) netxen_niu_xgbe_enable_phy_interrupts; adapter->disable_phy_interrupts = netxen_niu_xgbe_disable_phy_interrupts; - adapter->macaddr_set = netxen_niu_xg_macaddr_set; adapter->set_mtu = netxen_nic_set_mtu_xgb; adapter->init_port = netxen_niu_xg_init_port; adapter->set_promisc = netxen_niu_xg_set_promiscuous_mode; @@ -359,6 +351,8 @@ void netxen_initialize_adapter_ops(struct netxen_adapter *adapter) if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) { adapter->set_mtu = nx_fw_cmd_set_mtu; adapter->set_promisc = netxen_p3_nic_set_promisc; + adapter->macaddr_set = netxen_p3_nic_set_mac_addr; + adapter->set_multi = netxen_p3_nic_set_multi; } } @@ -400,8 +394,7 @@ static int rom_lock(struct netxen_adapter *adapter) while (!done) { /* acquire semaphore2 from PCI HW block */ - netxen_nic_read_w0(adapter, NETXEN_PCIE_REG(PCIE_SEM2_LOCK), - &done); + done = NXRD32(adapter, NETXEN_PCIE_REG(PCIE_SEM2_LOCK)); if (done == 1) break; if (timeout >= rom_lock_timeout) @@ -418,7 +411,7 @@ static int rom_lock(struct netxen_adapter *adapter) cpu_relax(); /*This a nop instr on i386 */ } } - netxen_nic_reg_write(adapter, NETXEN_ROM_LOCK_ID, ROM_LOCK_DRIVER); + NXWR32(adapter, NETXEN_ROM_LOCK_ID, ROM_LOCK_DRIVER); return 0; } @@ -430,7 +423,7 @@ static int netxen_wait_rom_done(struct netxen_adapter *adapter) cond_resched(); while (done == 0) { - done = netxen_nic_reg_read(adapter, NETXEN_ROMUSB_GLB_STATUS); + done = NXRD32(adapter, NETXEN_ROMUSB_GLB_STATUS); done &= 2; timeout++; if (timeout >= rom_max_timeout) { @@ -443,30 +436,28 @@ static int netxen_wait_rom_done(struct netxen_adapter *adapter) static void netxen_rom_unlock(struct netxen_adapter *adapter) { - u32 val; - /* release semaphore2 */ - netxen_nic_read_w0(adapter, NETXEN_PCIE_REG(PCIE_SEM2_UNLOCK), &val); + NXRD32(adapter, NETXEN_PCIE_REG(PCIE_SEM2_UNLOCK)); } static int do_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp) { - netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ADDRESS, addr); - netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_DUMMY_BYTE_CNT, 0); - netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ABYTE_CNT, 3); - netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_INSTR_OPCODE, 0xb); + NXWR32(adapter, NETXEN_ROMUSB_ROM_ADDRESS, addr); + NXWR32(adapter, NETXEN_ROMUSB_ROM_DUMMY_BYTE_CNT, 0); + NXWR32(adapter, NETXEN_ROMUSB_ROM_ABYTE_CNT, 3); + NXWR32(adapter, NETXEN_ROMUSB_ROM_INSTR_OPCODE, 0xb); if (netxen_wait_rom_done(adapter)) { printk("Error waiting for rom done\n"); return -EIO; } /* reset abyte_cnt and dummy_byte_cnt */ - netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ABYTE_CNT, 0); + NXWR32(adapter, NETXEN_ROMUSB_ROM_ABYTE_CNT, 0); udelay(10); - netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_DUMMY_BYTE_CNT, 0); + NXWR32(adapter, NETXEN_ROMUSB_ROM_DUMMY_BYTE_CNT, 0); - *valp = netxen_nic_reg_read(adapter, NETXEN_ROMUSB_ROM_RDATA); + *valp = NXRD32(adapter, NETXEN_ROMUSB_ROM_RDATA); return 0; } @@ -530,8 +521,7 @@ int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose) /* resetall */ rom_lock(adapter); - netxen_crb_writelit_adapter(adapter, NETXEN_ROMUSB_GLB_SW_RESET, - 0xffffffff); + NXWR32(adapter, NETXEN_ROMUSB_GLB_SW_RESET, 0xffffffff); netxen_rom_unlock(adapter); if (verbose) { @@ -655,7 +645,7 @@ int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose) } } - adapter->hw_write_wx(adapter, off, &buf[i].data, 4); + NXWR32(adapter, off, buf[i].data); msleep(init_delay); } @@ -665,36 +655,230 @@ int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose) /* unreset_net_cache */ if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { - adapter->hw_read_wx(adapter, - NETXEN_ROMUSB_GLB_SW_RESET, &val, 4); - netxen_crb_writelit_adapter(adapter, - NETXEN_ROMUSB_GLB_SW_RESET, (val & 0xffffff0f)); + val = NXRD32(adapter, NETXEN_ROMUSB_GLB_SW_RESET); + NXWR32(adapter, NETXEN_ROMUSB_GLB_SW_RESET, (val & 0xffffff0f)); } /* p2dn replyCount */ - netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_D + 0xec, 0x1e); + NXWR32(adapter, NETXEN_CRB_PEG_NET_D + 0xec, 0x1e); /* disable_peg_cache 0 */ - netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_D + 0x4c, 8); + NXWR32(adapter, NETXEN_CRB_PEG_NET_D + 0x4c, 8); /* disable_peg_cache 1 */ - netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_I + 0x4c, 8); + NXWR32(adapter, NETXEN_CRB_PEG_NET_I + 0x4c, 8); /* peg_clr_all */ /* peg_clr 0 */ - netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_0 + 0x8, 0); - netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_0 + 0xc, 0); + NXWR32(adapter, NETXEN_CRB_PEG_NET_0 + 0x8, 0); + NXWR32(adapter, NETXEN_CRB_PEG_NET_0 + 0xc, 0); /* peg_clr 1 */ - netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_1 + 0x8, 0); - netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_1 + 0xc, 0); + NXWR32(adapter, NETXEN_CRB_PEG_NET_1 + 0x8, 0); + NXWR32(adapter, NETXEN_CRB_PEG_NET_1 + 0xc, 0); /* peg_clr 2 */ - netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_2 + 0x8, 0); - netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_2 + 0xc, 0); + NXWR32(adapter, NETXEN_CRB_PEG_NET_2 + 0x8, 0); + NXWR32(adapter, NETXEN_CRB_PEG_NET_2 + 0xc, 0); /* peg_clr 3 */ - netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_3 + 0x8, 0); - netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_3 + 0xc, 0); + NXWR32(adapter, NETXEN_CRB_PEG_NET_3 + 0x8, 0); + NXWR32(adapter, NETXEN_CRB_PEG_NET_3 + 0xc, 0); return 0; } +int +netxen_load_firmware(struct netxen_adapter *adapter) +{ + u64 *ptr64; + u32 i, flashaddr, size; + const struct firmware *fw = adapter->fw; + + if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) + NXWR32(adapter, NETXEN_ROMUSB_GLB_CAS_RST, 1); + + if (fw) { + __le64 data; + + size = (NETXEN_IMAGE_START - NETXEN_BOOTLD_START) / 8; + + ptr64 = (u64 *)&fw->data[NETXEN_BOOTLD_START]; + flashaddr = NETXEN_BOOTLD_START; + + for (i = 0; i < size; i++) { + data = cpu_to_le64(ptr64[i]); + adapter->pci_mem_write(adapter, flashaddr, &data, 8); + flashaddr += 8; + } + + size = *(u32 *)&fw->data[NX_FW_SIZE_OFFSET]; + size = (__force u32)cpu_to_le32(size) / 8; + + ptr64 = (u64 *)&fw->data[NETXEN_IMAGE_START]; + flashaddr = NETXEN_IMAGE_START; + + for (i = 0; i < size; i++) { + data = cpu_to_le64(ptr64[i]); + + if (adapter->pci_mem_write(adapter, + flashaddr, &data, 8)) + return -EIO; + + flashaddr += 8; + } + } else { + u32 data; + + size = (NETXEN_IMAGE_START - NETXEN_BOOTLD_START) / 4; + flashaddr = NETXEN_BOOTLD_START; + + for (i = 0; i < size; i++) { + if (netxen_rom_fast_read(adapter, + flashaddr, (int *)&data) != 0) + return -EIO; + + if (adapter->pci_mem_write(adapter, + flashaddr, &data, 4)) + return -EIO; + + flashaddr += 4; + } + } + msleep(1); + + if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) + NXWR32(adapter, NETXEN_ROMUSB_GLB_SW_RESET, 0x80001d); + else { + NXWR32(adapter, NETXEN_ROMUSB_GLB_CHIP_CLK_CTRL, 0x3fff); + NXWR32(adapter, NETXEN_ROMUSB_GLB_CAS_RST, 0); + } + + return 0; +} + +static int +netxen_validate_firmware(struct netxen_adapter *adapter, const char *fwname) +{ + __le32 val; + u32 major, minor, build, ver, min_ver, bios; + struct pci_dev *pdev = adapter->pdev; + const struct firmware *fw = adapter->fw; + + if (fw->size < NX_FW_MIN_SIZE) + return -EINVAL; + + val = cpu_to_le32(*(u32 *)&fw->data[NX_FW_MAGIC_OFFSET]); + if ((__force u32)val != NETXEN_BDINFO_MAGIC) + return -EINVAL; + + val = cpu_to_le32(*(u32 *)&fw->data[NX_FW_VERSION_OFFSET]); + major = (__force u32)val & 0xff; + minor = ((__force u32)val >> 8) & 0xff; + build = (__force u32)val >> 16; + + if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) + min_ver = NETXEN_VERSION_CODE(4, 0, 216); + else + min_ver = NETXEN_VERSION_CODE(3, 4, 216); + + ver = NETXEN_VERSION_CODE(major, minor, build); + + if ((major > _NETXEN_NIC_LINUX_MAJOR) || (ver < min_ver)) { + dev_err(&pdev->dev, + "%s: firmware version %d.%d.%d unsupported\n", + fwname, major, minor, build); + return -EINVAL; + } + + val = cpu_to_le32(*(u32 *)&fw->data[NX_BIOS_VERSION_OFFSET]); + netxen_rom_fast_read(adapter, NX_BIOS_VERSION_OFFSET, (int *)&bios); + if ((__force u32)val != bios) { + dev_err(&pdev->dev, "%s: firmware bios is incompatible\n", + fwname); + return -EINVAL; + } + + /* check if flashed firmware is newer */ + if (netxen_rom_fast_read(adapter, + NX_FW_VERSION_OFFSET, (int *)&val)) + return -EIO; + major = (__force u32)val & 0xff; + minor = ((__force u32)val >> 8) & 0xff; + build = (__force u32)val >> 16; + if (NETXEN_VERSION_CODE(major, minor, build) > ver) + return -EINVAL; + + NXWR32(adapter, NETXEN_CAM_RAM(0x1fc), NETXEN_BDINFO_MAGIC); + return 0; +} + +static char *fw_name[] = { "nxromimg.bin", "nx3fwct.bin", "nx3fwmn.bin" }; + +void netxen_request_firmware(struct netxen_adapter *adapter) +{ + u32 capability, flashed_ver; + int fw_type; + struct pci_dev *pdev = adapter->pdev; + int rc = 0; + + if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { + fw_type = NX_P2_MN_ROMIMAGE; + goto request_fw; + } else { + fw_type = NX_P3_CT_ROMIMAGE; + goto request_fw; + } + +request_mn: + capability = 0; + + netxen_rom_fast_read(adapter, + NX_FW_VERSION_OFFSET, (int *)&flashed_ver); + if (flashed_ver >= NETXEN_VERSION_CODE(4, 0, 220)) { + capability = NXRD32(adapter, NX_PEG_TUNE_CAPABILITY); + if (capability & NX_PEG_TUNE_MN_PRESENT) { + fw_type = NX_P3_MN_ROMIMAGE; + goto request_fw; + } + } + +request_fw: + rc = request_firmware(&adapter->fw, fw_name[fw_type], &pdev->dev); + if (rc != 0) { + if (fw_type == NX_P3_CT_ROMIMAGE) { + msleep(1); + goto request_mn; + } + + adapter->fw = NULL; + goto done; + } + + rc = netxen_validate_firmware(adapter, fw_name[fw_type]); + if (rc != 0) { + release_firmware(adapter->fw); + + if (fw_type == NX_P3_CT_ROMIMAGE) { + msleep(1); + goto request_mn; + } + + adapter->fw = NULL; + goto done; + } + +done: + if (adapter->fw) + dev_info(&pdev->dev, "loading firmware from file %s\n", + fw_name[fw_type]); + else + dev_info(&pdev->dev, "loading firmware from flash\n"); +} + + +void +netxen_release_firmware(struct netxen_adapter *adapter) +{ + if (adapter->fw) + release_firmware(adapter->fw); +} + int netxen_initialize_adapter_offload(struct netxen_adapter *adapter) { uint64_t addr; @@ -715,12 +899,12 @@ int netxen_initialize_adapter_offload(struct netxen_adapter *adapter) hi = (addr >> 32) & 0xffffffff; lo = addr & 0xffffffff; - adapter->pci_write_normalize(adapter, CRB_HOST_DUMMY_BUF_ADDR_HI, hi); - adapter->pci_write_normalize(adapter, CRB_HOST_DUMMY_BUF_ADDR_LO, lo); + NXWR32(adapter, CRB_HOST_DUMMY_BUF_ADDR_HI, hi); + NXWR32(adapter, CRB_HOST_DUMMY_BUF_ADDR_LO, lo); if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) { uint32_t temp = 0; - adapter->hw_write_wx(adapter, CRB_HOST_DUMMY_BUF, &temp, 4); + NXWR32(adapter, CRB_HOST_DUMMY_BUF, temp); } return 0; @@ -760,38 +944,41 @@ int netxen_phantom_init(struct netxen_adapter *adapter, int pegtune_val) u32 val = 0; int retries = 60; - if (!pegtune_val) { - do { - val = adapter->pci_read_normalize(adapter, - CRB_CMDPEG_STATE); + if (pegtune_val) + return 0; - if (val == PHAN_INITIALIZE_COMPLETE || - val == PHAN_INITIALIZE_ACK) - return 0; + do { + val = NXRD32(adapter, CRB_CMDPEG_STATE); - msleep(500); - - } while (--retries); - - if (!retries) { - pegtune_val = adapter->pci_read_normalize(adapter, - NETXEN_ROMUSB_GLB_PEGTUNE_DONE); - printk(KERN_WARNING "netxen_phantom_init: init failed, " - "pegtune_val=%x\n", pegtune_val); - return -1; + switch (val) { + case PHAN_INITIALIZE_COMPLETE: + case PHAN_INITIALIZE_ACK: + return 0; + case PHAN_INITIALIZE_FAILED: + goto out_err; + default: + break; } - } - return 0; + msleep(500); + + } while (--retries); + + NXWR32(adapter, CRB_CMDPEG_STATE, PHAN_INITIALIZE_FAILED); + +out_err: + dev_warn(&adapter->pdev->dev, "firmware init failed\n"); + return -EIO; } -int netxen_receive_peg_ready(struct netxen_adapter *adapter) +static int +netxen_receive_peg_ready(struct netxen_adapter *adapter) { u32 val = 0; int retries = 2000; do { - val = adapter->pci_read_normalize(adapter, CRB_RCVPEG_STATE); + val = NXRD32(adapter, CRB_RCVPEG_STATE); if (val == PHAN_PEG_RCV_INITIALIZED) return 0; @@ -809,6 +996,93 @@ int netxen_receive_peg_ready(struct netxen_adapter *adapter) return 0; } +int netxen_init_firmware(struct netxen_adapter *adapter) +{ + int err; + + err = netxen_receive_peg_ready(adapter); + if (err) + return err; + + NXWR32(adapter, CRB_NIC_CAPABILITIES_HOST, INTR_SCHEME_PERPORT); + NXWR32(adapter, CRB_NIC_MSI_MODE_HOST, MSI_MODE_MULTIFUNC); + NXWR32(adapter, CRB_MPORT_MODE, MPORT_MULTI_FUNCTION_MODE); + NXWR32(adapter, CRB_CMDPEG_STATE, PHAN_INITIALIZE_ACK); + + if (adapter->fw_version >= NETXEN_VERSION_CODE(4, 0, 222)) { + adapter->capabilities = NXRD32(adapter, CRB_FW_CAPABILITIES_1); + } + + return err; +} + +static void +netxen_handle_linkevent(struct netxen_adapter *adapter, nx_fw_msg_t *msg) +{ + u32 cable_OUI; + u16 cable_len; + u16 link_speed; + u8 link_status, module, duplex, autoneg; + struct net_device *netdev = adapter->netdev; + + adapter->has_link_events = 1; + + cable_OUI = msg->body[1] & 0xffffffff; + cable_len = (msg->body[1] >> 32) & 0xffff; + link_speed = (msg->body[1] >> 48) & 0xffff; + + link_status = msg->body[2] & 0xff; + duplex = (msg->body[2] >> 16) & 0xff; + autoneg = (msg->body[2] >> 24) & 0xff; + + module = (msg->body[2] >> 8) & 0xff; + if (module == LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLE) { + printk(KERN_INFO "%s: unsupported cable: OUI 0x%x, length %d\n", + netdev->name, cable_OUI, cable_len); + } else if (module == LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLELEN) { + printk(KERN_INFO "%s: unsupported cable length %d\n", + netdev->name, cable_len); + } + + netxen_advert_link_change(adapter, link_status); + + /* update link parameters */ + if (duplex == LINKEVENT_FULL_DUPLEX) + adapter->link_duplex = DUPLEX_FULL; + else + adapter->link_duplex = DUPLEX_HALF; + adapter->module_type = module; + adapter->link_autoneg = autoneg; + adapter->link_speed = link_speed; +} + +static void +netxen_handle_fw_message(int desc_cnt, int index, + struct nx_host_sds_ring *sds_ring) +{ + nx_fw_msg_t msg; + struct status_desc *desc; + int i = 0, opcode; + + while (desc_cnt > 0 && i < 8) { + desc = &sds_ring->desc_head[index]; + msg.words[i++] = le64_to_cpu(desc->status_desc_data[0]); + msg.words[i++] = le64_to_cpu(desc->status_desc_data[1]); + + index = get_next_index(index, sds_ring->num_desc); + desc_cnt--; + } + + opcode = netxen_get_nic_msg_opcode(msg.body[0]); + switch (opcode) { + case NX_NIC_C2H_OPCODE_GET_LINKEVENT_RESPONSE: + netxen_handle_linkevent(sds_ring->adapter, &msg); + break; + default: + break; + } +} + static int netxen_alloc_rx_skb(struct netxen_adapter *adapter, struct nx_host_rds_ring *rds_ring, @@ -874,7 +1148,8 @@ no_skb: static struct netxen_rx_buffer * netxen_process_rcv(struct netxen_adapter *adapter, - int ring, int index, int length, int cksum, int pkt_offset) + int ring, int index, int length, int cksum, int pkt_offset, + struct nx_host_sds_ring *sds_ring) { struct net_device *netdev = adapter->netdev; struct netxen_recv_context *recv_ctx = &adapter->recv_ctx; @@ -902,7 +1177,7 @@ netxen_process_rcv(struct netxen_adapter *adapter, skb->protocol = eth_type_trans(skb, netdev); - netif_receive_skb(skb); + napi_gro_receive(&sds_ring->napi, skb); adapter->stats.no_rcv++; adapter->stats.rxbytes += length; @@ -927,35 +1202,53 @@ netxen_process_rcv_ring(struct nx_host_sds_ring *sds_ring, int max) int count = 0; u64 sts_data; - int opcode, ring, index, length, cksum, pkt_offset; + int opcode, ring, index, length, cksum, pkt_offset, desc_cnt; while (count < max) { desc = &sds_ring->desc_head[consumer]; - sts_data = le64_to_cpu(desc->status_desc_data); + sts_data = le64_to_cpu(desc->status_desc_data[0]); if (!(sts_data & STATUS_OWNER_HOST)) break; + desc_cnt = netxen_get_sts_desc_cnt(sts_data); ring = netxen_get_sts_type(sts_data); + if (ring > RCV_RING_JUMBO) - continue; + goto skip; opcode = netxen_get_sts_opcode(sts_data); + switch (opcode) { + case NETXEN_NIC_RXPKT_DESC: + case NETXEN_OLD_RXPKT_DESC: + break; + case NETXEN_NIC_RESPONSE_DESC: + netxen_handle_fw_message(desc_cnt, consumer, sds_ring); + default: + goto skip; + } + + WARN_ON(desc_cnt > 1); + index = netxen_get_sts_refhandle(sts_data); length = netxen_get_sts_totallength(sts_data); cksum = netxen_get_sts_status(sts_data); pkt_offset = netxen_get_sts_pkt_offset(sts_data); rxbuf = netxen_process_rcv(adapter, ring, index, - length, cksum, pkt_offset); + length, cksum, pkt_offset, sds_ring); if (rxbuf) list_add_tail(&rxbuf->list, &sds_ring->free_list[ring]); - desc->status_desc_data = cpu_to_le64(STATUS_OWNER_PHANTOM); - - consumer = get_next_index(consumer, sds_ring->num_desc); +skip: + for (; desc_cnt > 0; desc_cnt--) { + desc = &sds_ring->desc_head[consumer]; + desc->status_desc_data[0] = + cpu_to_le64(STATUS_OWNER_PHANTOM); + consumer = get_next_index(consumer, sds_ring->num_desc); + } count++; } @@ -980,8 +1273,7 @@ netxen_process_rcv_ring(struct nx_host_sds_ring *sds_ring, int max) if (count) { sds_ring->consumer = consumer; - adapter->pci_write_normalize(adapter, - sds_ring->crb_sts_consumer, consumer); + NXWR32(adapter, sds_ring->crb_sts_consumer, consumer); } return count; @@ -990,23 +1282,23 @@ netxen_process_rcv_ring(struct nx_host_sds_ring *sds_ring, int max) /* Process Command status ring */ int netxen_process_cmd_ring(struct netxen_adapter *adapter) { - u32 last_consumer, consumer; + u32 sw_consumer, hw_consumer; int count = 0, i; struct netxen_cmd_buffer *buffer; struct pci_dev *pdev = adapter->pdev; struct net_device *netdev = adapter->netdev; struct netxen_skb_frag *frag; int done = 0; + struct nx_host_tx_ring *tx_ring = adapter->tx_ring; if (!spin_trylock(&adapter->tx_clean_lock)) return 1; - last_consumer = adapter->last_cmd_consumer; - barrier(); /* cmd_consumer can change underneath */ - consumer = le32_to_cpu(*(adapter->cmd_consumer)); + sw_consumer = tx_ring->sw_consumer; + hw_consumer = le32_to_cpu(*(tx_ring->hw_consumer)); - while (last_consumer != consumer) { - buffer = &adapter->cmd_buf_arr[last_consumer]; + while (sw_consumer != hw_consumer) { + buffer = &tx_ring->cmd_buf_arr[sw_consumer]; if (buffer->skb) { frag = &buffer->frag_array[0]; pci_unmap_single(pdev, frag->dma, frag->length, @@ -1024,19 +1316,20 @@ int netxen_process_cmd_ring(struct netxen_adapter *adapter) buffer->skb = NULL; } - last_consumer = get_next_index(last_consumer, - adapter->num_txd); + sw_consumer = get_next_index(sw_consumer, tx_ring->num_desc); if (++count >= MAX_STATUS_HANDLE) break; } - if (count) { - adapter->last_cmd_consumer = last_consumer; + if (count && netif_running(netdev)) { + tx_ring->sw_consumer = sw_consumer; + smp_mb(); - if (netif_queue_stopped(netdev) && netif_running(netdev)) { + + if (netif_queue_stopped(netdev) && netif_carrier_ok(netdev)) { netif_tx_lock(netdev); - netif_wake_queue(netdev); - smp_mb(); + if (netxen_tx_avail(tx_ring) > TX_STOP_THRESH) + netif_wake_queue(netdev); netif_tx_unlock(netdev); } } @@ -1053,9 +1346,8 @@ int netxen_process_cmd_ring(struct netxen_adapter *adapter) * There is still a possible race condition and the host could miss an * interrupt. The card has to take care of this. */ - barrier(); /* cmd_consumer can change underneath */ - consumer = le32_to_cpu(*(adapter->cmd_consumer)); - done = (last_consumer == consumer); + hw_consumer = le32_to_cpu(*(tx_ring->hw_consumer)); + done = (sw_consumer == hw_consumer); spin_unlock(&adapter->tx_clean_lock); return (done); @@ -1099,8 +1391,7 @@ netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ringid, if (count) { rds_ring->producer = producer; - adapter->pci_write_normalize(adapter, - rds_ring->crb_rcv_producer, + NXWR32(adapter, rds_ring->crb_rcv_producer, (producer-1) & (rds_ring->num_desc-1)); if (adapter->fw_major < 4) { @@ -1160,10 +1451,8 @@ netxen_post_rx_buffers_nodb(struct netxen_adapter *adapter, if (count) { rds_ring->producer = producer; - adapter->pci_write_normalize(adapter, - rds_ring->crb_rcv_producer, + NXWR32(adapter, rds_ring->crb_rcv_producer, (producer - 1) & (rds_ring->num_desc - 1)); - wmb(); } spin_unlock(&rds_ring->lock); } diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index aef77289bd34..2919a2d12bf4 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -29,7 +29,7 @@ */ #include -#include +#include #include "netxen_nic_hw.h" #include "netxen_nic.h" @@ -107,10 +107,14 @@ static uint32_t crb_cmd_producer[4] = { void netxen_nic_update_cmd_producer(struct netxen_adapter *adapter, - uint32_t crb_producer) + struct nx_host_tx_ring *tx_ring) { - adapter->pci_write_normalize(adapter, - adapter->crb_addr_cmd_producer, crb_producer); + NXWR32(adapter, tx_ring->crb_cmd_producer, tx_ring->producer); + + if (netxen_tx_avail(tx_ring) <= TX_STOP_THRESH) { + netif_stop_queue(adapter->netdev); + smp_mb(); + } } static uint32_t crb_cmd_consumer[4] = { @@ -120,10 +124,9 @@ static uint32_t crb_cmd_consumer[4] = { static inline void netxen_nic_update_cmd_consumer(struct netxen_adapter *adapter, - u32 crb_consumer) + struct nx_host_tx_ring *tx_ring) { - adapter->pci_write_normalize(adapter, - adapter->crb_addr_cmd_consumer, crb_consumer); + NXWR32(adapter, tx_ring->crb_cmd_consumer, tx_ring->sw_consumer); } static uint32_t msi_tgt_status[8] = { @@ -139,37 +142,54 @@ static inline void netxen_nic_disable_int(struct nx_host_sds_ring *sds_ring) { struct netxen_adapter *adapter = sds_ring->adapter; - adapter->pci_write_normalize(adapter, sds_ring->crb_intr_mask, 0); + NXWR32(adapter, sds_ring->crb_intr_mask, 0); } static inline void netxen_nic_enable_int(struct nx_host_sds_ring *sds_ring) { struct netxen_adapter *adapter = sds_ring->adapter; - adapter->pci_write_normalize(adapter, sds_ring->crb_intr_mask, 0x1); + NXWR32(adapter, sds_ring->crb_intr_mask, 0x1); if (!NETXEN_IS_MSI_FAMILY(adapter)) adapter->pci_write_immediate(adapter, adapter->legacy_intr.tgt_mask_reg, 0xfbff); } +static int +netxen_alloc_sds_rings(struct netxen_recv_context *recv_ctx, int count) +{ + int size = sizeof(struct nx_host_sds_ring) * count; + + recv_ctx->sds_rings = kzalloc(size, GFP_KERNEL); + + return (recv_ctx->sds_rings == NULL); +} + static void +netxen_free_sds_rings(struct netxen_recv_context *recv_ctx) +{ + if (recv_ctx->sds_rings != NULL) + kfree(recv_ctx->sds_rings); +} + +static int netxen_napi_add(struct netxen_adapter *adapter, struct net_device *netdev) { int ring; struct nx_host_sds_ring *sds_ring; struct netxen_recv_context *recv_ctx = &adapter->recv_ctx; - if (adapter->flags & NETXEN_NIC_MSIX_ENABLED) - adapter->max_sds_rings = (num_online_cpus() >= 4) ? 4 : 2; - else - adapter->max_sds_rings = 1; + if (netxen_alloc_sds_rings(recv_ctx, adapter->max_sds_rings)) + return 1; for (ring = 0; ring < adapter->max_sds_rings; ring++) { sds_ring = &recv_ctx->sds_rings[ring]; netif_napi_add(netdev, &sds_ring->napi, netxen_nic_poll, NETXEN_NETDEV_WEIGHT); } + + return 0; } static void @@ -195,8 +215,9 @@ netxen_napi_disable(struct netxen_adapter *adapter) for (ring = 0; ring < adapter->max_sds_rings; ring++) { sds_ring = &recv_ctx->sds_rings[ring]; - netxen_nic_disable_int(sds_ring); napi_disable(&sds_ring->napi); + netxen_nic_disable_int(sds_ring); + synchronize_irq(sds_ring->irq); } } @@ -240,7 +261,7 @@ nx_update_dma_mask(struct netxen_adapter *adapter) change = 0; - shift = netxen_nic_reg_read(adapter, CRB_DMA_SHIFT); + shift = NXRD32(adapter, CRB_DMA_SHIFT); if (shift >= 32) return 0; @@ -268,10 +289,21 @@ static void netxen_check_options(struct netxen_adapter *adapter) else if (adapter->ahw.port_type == NETXEN_NIC_GBE) adapter->num_rxd = MAX_RCV_DESCRIPTORS_1G; - if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) + adapter->msix_supported = 0; + if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) { adapter->msix_supported = !!use_msi_x; - else - adapter->msix_supported = 0; + adapter->rss_supported = !!use_msi_x; + } else if (adapter->fw_version >= NETXEN_VERSION_CODE(3, 4, 336)) { + switch (adapter->ahw.board_type) { + case NETXEN_BRDTYPE_P2_SB31_10G: + case NETXEN_BRDTYPE_P2_SB31_10G_CX4: + adapter->msix_supported = !!use_msi_x; + adapter->rss_supported = !!use_msi_x; + break; + default: + break; + } + } adapter->num_txd = MAX_CMD_DESCRIPTORS_HOST; adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS; @@ -287,43 +319,34 @@ netxen_check_hw_init(struct netxen_adapter *adapter, int first_boot) if (first_boot == 0x55555555) { /* This is the first boot after power up */ - adapter->pci_write_normalize(adapter, - NETXEN_CAM_RAM(0x1fc), NETXEN_BDINFO_MAGIC); + NXWR32(adapter, NETXEN_CAM_RAM(0x1fc), NETXEN_BDINFO_MAGIC); if (!NX_IS_REVISION_P2(adapter->ahw.revision_id)) return 0; /* PCI bus master workaround */ - adapter->hw_read_wx(adapter, - NETXEN_PCIE_REG(0x4), &first_boot, 4); + first_boot = NXRD32(adapter, NETXEN_PCIE_REG(0x4)); if (!(first_boot & 0x4)) { first_boot |= 0x4; - adapter->hw_write_wx(adapter, - NETXEN_PCIE_REG(0x4), &first_boot, 4); - adapter->hw_read_wx(adapter, - NETXEN_PCIE_REG(0x4), &first_boot, 4); + NXWR32(adapter, NETXEN_PCIE_REG(0x4), first_boot); + first_boot = NXRD32(adapter, NETXEN_PCIE_REG(0x4)); } /* This is the first boot after power up */ - adapter->hw_read_wx(adapter, - NETXEN_ROMUSB_GLB_SW_RESET, &first_boot, 4); + first_boot = NXRD32(adapter, NETXEN_ROMUSB_GLB_SW_RESET); if (first_boot != 0x80000f) { /* clear the register for future unloads/loads */ - adapter->pci_write_normalize(adapter, - NETXEN_CAM_RAM(0x1fc), 0); + NXWR32(adapter, NETXEN_CAM_RAM(0x1fc), 0); return -EIO; } /* Start P2 boot loader */ - val = adapter->pci_read_normalize(adapter, - NETXEN_ROMUSB_GLB_PEGTUNE_DONE); - adapter->pci_write_normalize(adapter, - NETXEN_ROMUSB_GLB_PEGTUNE_DONE, val | 0x1); + val = NXRD32(adapter, NETXEN_ROMUSB_GLB_PEGTUNE_DONE); + NXWR32(adapter, NETXEN_ROMUSB_GLB_PEGTUNE_DONE, val | 0x1); timeout = 0; do { msleep(1); - val = adapter->pci_read_normalize(adapter, - NETXEN_CAM_RAM(0x1fc)); + val = NXRD32(adapter, NETXEN_CAM_RAM(0x1fc)); if (++timeout > 5000) return -EIO; @@ -342,24 +365,19 @@ static void netxen_set_port_mode(struct netxen_adapter *adapter) (val == NETXEN_BRDTYPE_P3_XG_LOM)) { if (port_mode == NETXEN_PORT_MODE_802_3_AP) { data = NETXEN_PORT_MODE_802_3_AP; - adapter->hw_write_wx(adapter, - NETXEN_PORT_MODE_ADDR, &data, 4); + NXWR32(adapter, NETXEN_PORT_MODE_ADDR, data); } else if (port_mode == NETXEN_PORT_MODE_XG) { data = NETXEN_PORT_MODE_XG; - adapter->hw_write_wx(adapter, - NETXEN_PORT_MODE_ADDR, &data, 4); + NXWR32(adapter, NETXEN_PORT_MODE_ADDR, data); } else if (port_mode == NETXEN_PORT_MODE_AUTO_NEG_1G) { data = NETXEN_PORT_MODE_AUTO_NEG_1G; - adapter->hw_write_wx(adapter, - NETXEN_PORT_MODE_ADDR, &data, 4); + NXWR32(adapter, NETXEN_PORT_MODE_ADDR, data); } else if (port_mode == NETXEN_PORT_MODE_AUTO_NEG_XG) { data = NETXEN_PORT_MODE_AUTO_NEG_XG; - adapter->hw_write_wx(adapter, - NETXEN_PORT_MODE_ADDR, &data, 4); + NXWR32(adapter, NETXEN_PORT_MODE_ADDR, data); } else { data = NETXEN_PORT_MODE_AUTO_NEG; - adapter->hw_write_wx(adapter, - NETXEN_PORT_MODE_ADDR, &data, 4); + NXWR32(adapter, NETXEN_PORT_MODE_ADDR, data); } if ((wol_port_mode != NETXEN_PORT_MODE_802_3_AP) && @@ -368,8 +386,7 @@ static void netxen_set_port_mode(struct netxen_adapter *adapter) (wol_port_mode != NETXEN_PORT_MODE_AUTO_NEG_XG)) { wol_port_mode = NETXEN_PORT_MODE_AUTO_NEG; } - adapter->hw_write_wx(adapter, NETXEN_WOL_PORT_MODE, - &wol_port_mode, 4); + NXWR32(adapter, NETXEN_WOL_PORT_MODE, wol_port_mode); } } @@ -389,11 +406,11 @@ static void netxen_set_msix_bit(struct pci_dev *pdev, int enable) } } -static void netxen_init_msix_entries(struct netxen_adapter *adapter) +static void netxen_init_msix_entries(struct netxen_adapter *adapter, int count) { int i; - for (i = 0; i < MSIX_ENTRIES_PER_ADAPTER; i++) + for (i = 0; i < count; i++) adapter->msix_entries[i].entry = i; } @@ -424,20 +441,38 @@ netxen_read_mac_addr(struct netxen_adapter *adapter) if (!is_valid_ether_addr(netdev->perm_addr)) dev_warn(&pdev->dev, "Bad MAC address %pM.\n", netdev->dev_addr); - else - adapter->macaddr_set(adapter, netdev->dev_addr); return 0; } +int netxen_nic_set_mac(struct net_device *netdev, void *p) +{ + struct netxen_adapter *adapter = netdev_priv(netdev); + struct sockaddr *addr = p; + + if (!is_valid_ether_addr(addr->sa_data)) + return -EINVAL; + + if (netif_running(netdev)) { + netif_device_detach(netdev); + netxen_napi_disable(adapter); + } + + memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); + adapter->macaddr_set(adapter, addr->sa_data); + + if (netif_running(netdev)) { + netif_device_attach(netdev); + netxen_napi_enable(adapter); + } + return 0; +} + static void netxen_set_multicast_list(struct net_device *dev) { struct netxen_adapter *adapter = netdev_priv(dev); - if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) - netxen_p3_nic_set_multi(dev); - else - netxen_p2_nic_set_multi(dev); + adapter->set_multi(dev); } static const struct net_device_ops netxen_netdev_ops = { @@ -460,10 +495,17 @@ netxen_setup_intr(struct netxen_adapter *adapter) { struct netxen_legacy_intr_set *legacy_intrp; struct pci_dev *pdev = adapter->pdev; + int err, num_msix; + + if (adapter->rss_supported) { + num_msix = (num_online_cpus() >= MSIX_ENTRIES_PER_ADAPTER) ? + MSIX_ENTRIES_PER_ADAPTER : 2; + } else + num_msix = 1; + + adapter->max_sds_rings = 1; adapter->flags &= ~(NETXEN_NIC_MSI_ENABLED | NETXEN_NIC_MSIX_ENABLED); - adapter->intr_scheme = -1; - adapter->msi_mode = -1; if (adapter->ahw.revision_id >= NX_P3_B0) legacy_intrp = &legacy_intr[adapter->ahw.pci_func]; @@ -478,24 +520,36 @@ netxen_setup_intr(struct netxen_adapter *adapter) if (adapter->msix_supported) { - netxen_init_msix_entries(adapter); - if (pci_enable_msix(pdev, adapter->msix_entries, - MSIX_ENTRIES_PER_ADAPTER)) - goto request_msi; + netxen_init_msix_entries(adapter, num_msix); + err = pci_enable_msix(pdev, adapter->msix_entries, num_msix); + if (err == 0) { + adapter->flags |= NETXEN_NIC_MSIX_ENABLED; + netxen_set_msix_bit(pdev, 1); - adapter->flags |= NETXEN_NIC_MSIX_ENABLED; - netxen_set_msix_bit(pdev, 1); - dev_info(&pdev->dev, "using msi-x interrupts\n"); + if (adapter->rss_supported) + adapter->max_sds_rings = num_msix; - } else { -request_msi: - if (use_msi && !pci_enable_msi(pdev)) { - adapter->flags |= NETXEN_NIC_MSI_ENABLED; - dev_info(&pdev->dev, "using msi interrupts\n"); - } else - dev_info(&pdev->dev, "using legacy interrupts\n"); - adapter->msix_entries[0].vector = pdev->irq; + dev_info(&pdev->dev, "using msi-x interrupts\n"); + return; + } + + if (err > 0) + pci_disable_msix(pdev); + + /* fall through for msi */ } + + if (use_msi && !pci_enable_msi(pdev)) { + adapter->flags |= NETXEN_NIC_MSI_ENABLED; + adapter->msi_tgt_status = + msi_tgt_status[adapter->ahw.pci_func]; + dev_info(&pdev->dev, "using msi interrupts\n"); + adapter->msix_entries[0].vector = pdev->irq; + return; + } + + dev_info(&pdev->dev, "using legacy interrupts\n"); + adapter->msix_entries[0].vector = pdev->irq; } static void @@ -552,8 +606,6 @@ netxen_setup_pci_map(struct netxen_adapter *adapter) adapter->hw_read_wx = netxen_nic_hw_read_wx_128M; adapter->pci_read_immediate = netxen_nic_pci_read_immediate_128M; adapter->pci_write_immediate = netxen_nic_pci_write_immediate_128M; - adapter->pci_read_normalize = netxen_nic_pci_read_normalize_128M; - adapter->pci_write_normalize = netxen_nic_pci_write_normalize_128M; adapter->pci_set_window = netxen_nic_pci_set_window_128M; adapter->pci_mem_read = netxen_nic_pci_mem_read_128M; adapter->pci_mem_write = netxen_nic_pci_mem_write_128M; @@ -575,9 +627,6 @@ netxen_setup_pci_map(struct netxen_adapter *adapter) adapter->pci_read_immediate = netxen_nic_pci_read_immediate_2M; adapter->pci_write_immediate = netxen_nic_pci_write_immediate_2M; - adapter->pci_read_normalize = netxen_nic_pci_read_normalize_2M; - adapter->pci_write_normalize = - netxen_nic_pci_write_normalize_2M; adapter->pci_set_window = netxen_nic_pci_set_window_2M; adapter->pci_mem_read = netxen_nic_pci_mem_read_2M; adapter->pci_mem_write = netxen_nic_pci_mem_write_2M; @@ -643,25 +692,22 @@ err_out: } static int -netxen_start_firmware(struct netxen_adapter *adapter) +netxen_start_firmware(struct netxen_adapter *adapter, int request_fw) { int val, err, first_boot; struct pci_dev *pdev = adapter->pdev; int first_driver = 0; - if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) { - if (adapter->ahw.pci_func == 0) - first_driver = 1; - } else { - if (adapter->portnum == 0) - first_driver = 1; - } + + if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) + first_driver = (adapter->portnum == 0); + else + first_driver = (adapter->ahw.pci_func == 0); if (!first_driver) - return 0; + goto wait_init; - first_boot = adapter->pci_read_normalize(adapter, - NETXEN_CAM_RAM(0x1fc)); + first_boot = NXRD32(adapter, NETXEN_CAM_RAM(0x1fc)); err = netxen_check_hw_init(adapter, first_boot); if (err) { @@ -669,14 +715,16 @@ netxen_start_firmware(struct netxen_adapter *adapter) return err; } + if (request_fw) + netxen_request_firmware(adapter); + if (first_boot != 0x55555555) { - adapter->pci_write_normalize(adapter, - CRB_CMDPEG_STATE, 0); + NXWR32(adapter, CRB_CMDPEG_STATE, 0); netxen_pinit_from_rom(adapter, 0); msleep(1); } - netxen_nic_reg_write(adapter, CRB_DMA_SHIFT, 0x55555555); + NXWR32(adapter, CRB_DMA_SHIFT, 0x55555555); if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) netxen_set_port_mode(adapter); @@ -688,8 +736,7 @@ netxen_start_firmware(struct netxen_adapter *adapter) val = 0x7654; if (adapter->ahw.port_type == NETXEN_NIC_XGBE) val |= 0x0f000000; - netxen_crb_writelit_adapter(adapter, - NETXEN_MAC_ADDR_CNTL_REG, val); + NXWR32(adapter, NETXEN_MAC_ADDR_CNTL_REG, val); } @@ -703,8 +750,9 @@ netxen_start_firmware(struct netxen_adapter *adapter) val = (_NETXEN_NIC_LINUX_MAJOR << 16) | ((_NETXEN_NIC_LINUX_MINOR << 8)) | (_NETXEN_NIC_LINUX_SUBVERSION); - adapter->pci_write_normalize(adapter, CRB_DRIVER_VERSION, val); + NXWR32(adapter, CRB_DRIVER_VERSION, val); +wait_init: /* Handshake with the card before we register the devices. */ err = netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE); if (err) { @@ -726,15 +774,6 @@ netxen_nic_request_irq(struct netxen_adapter *adapter) struct net_device *netdev = adapter->netdev; struct netxen_recv_context *recv_ctx = &adapter->recv_ctx; - if ((adapter->msi_mode != MSI_MODE_MULTIFUNC) || - (adapter->intr_scheme != INTR_SCHEME_PERPORT)) { - printk(KERN_ERR "%s: Firmware interrupt scheme is " - "incompatible with driver\n", - netdev->name); - adapter->driver_mismatch = 1; - return -EINVAL; - } - if (adapter->flags & NETXEN_NIC_MSIX_ENABLED) handler = netxen_msix_intr; else if (adapter->flags & NETXEN_NIC_MSI_ENABLED) @@ -747,7 +786,7 @@ netxen_nic_request_irq(struct netxen_adapter *adapter) for (ring = 0; ring < adapter->max_sds_rings; ring++) { sds_ring = &recv_ctx->sds_rings[ring]; - sprintf(sds_ring->name, "%16s[%d]", netdev->name, ring); + sprintf(sds_ring->name, "%s[%d]", netdev->name, ring); err = request_irq(sds_ring->irq, handler, flags, sds_ring->name, sds_ring); if (err) @@ -782,22 +821,26 @@ netxen_nic_up(struct netxen_adapter *adapter, struct net_device *netdev) netxen_nic_driver_name, adapter->portnum); return err; } - adapter->macaddr_set(adapter, netdev->dev_addr); + if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) + adapter->macaddr_set(adapter, netdev->dev_addr); - netxen_nic_set_link_parameters(adapter); - - netxen_set_multicast_list(netdev); - if (adapter->set_mtu) - adapter->set_mtu(adapter, netdev->mtu); + adapter->set_multi(netdev); + adapter->set_mtu(adapter, netdev->mtu); adapter->ahw.linkup = 0; - mod_timer(&adapter->watchdog_timer, jiffies); netxen_napi_enable(adapter); if (adapter->max_sds_rings > 1) netxen_config_rss(adapter, 1); + if (adapter->capabilities & NX_FW_CAPABILITY_LINK_NOTIFICATION) + netxen_linkevent_request(adapter, 1); + else + netxen_nic_set_link_parameters(adapter); + + mod_timer(&adapter->watchdog_timer, jiffies); + return 0; } @@ -806,11 +849,15 @@ netxen_nic_down(struct netxen_adapter *adapter, struct net_device *netdev) { netif_carrier_off(netdev); netif_stop_queue(netdev); - netxen_napi_disable(adapter); if (adapter->stop_port) adapter->stop_port(adapter); + if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) + netxen_p3_free_mac_list(adapter); + + netxen_napi_disable(adapter); + netxen_release_tx_buffers(adapter); FLUSH_SCHEDULED_WORK(); @@ -825,6 +872,7 @@ netxen_nic_attach(struct netxen_adapter *adapter) struct pci_dev *pdev = adapter->pdev; int err, ring; struct nx_host_rds_ring *rds_ring; + struct nx_host_tx_ring *tx_ring; err = netxen_init_firmware(adapter); if (err != 0) { @@ -854,13 +902,15 @@ netxen_nic_attach(struct netxen_adapter *adapter) } if (adapter->fw_major < 4) { - adapter->crb_addr_cmd_producer = - crb_cmd_producer[adapter->portnum]; - adapter->crb_addr_cmd_consumer = - crb_cmd_consumer[adapter->portnum]; + tx_ring = adapter->tx_ring; + tx_ring->crb_cmd_producer = crb_cmd_producer[adapter->portnum]; + tx_ring->crb_cmd_consumer = crb_cmd_consumer[adapter->portnum]; - netxen_nic_update_cmd_producer(adapter, 0); - netxen_nic_update_cmd_consumer(adapter, 0); + tx_ring->producer = 0; + tx_ring->sw_consumer = 0; + + netxen_nic_update_cmd_producer(adapter, tx_ring); + netxen_nic_update_cmd_consumer(adapter, tx_ring); } for (ring = 0; ring < adapter->max_rds_rings; ring++) { @@ -889,10 +939,9 @@ err_out_free_sw: static void netxen_nic_detach(struct netxen_adapter *adapter) { - netxen_nic_free_irq(adapter); - netxen_release_rx_buffers(adapter); netxen_free_hw_resources(adapter); + netxen_nic_free_irq(adapter); netxen_free_sw_resources(adapter); adapter->is_up = 0; @@ -957,6 +1006,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) rwlock_init(&adapter->adapter_lock); spin_lock_init(&adapter->tx_clean_lock); + INIT_LIST_HEAD(&adapter->mac_list); err = netxen_setup_pci_map(adapter); if (err) @@ -979,6 +1029,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) SET_ETHTOOL_OPS(netdev, &netxen_nic_ethtool_ops); netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO); + netdev->features |= (NETIF_F_GRO); netdev->vlan_features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO); if (NX_IS_REVISION_P3(revision_id)) { @@ -1011,7 +1062,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) break; } - err = netxen_start_firmware(adapter); + err = netxen_start_firmware(adapter, 1); if (err) goto err_out_iounmap; @@ -1024,8 +1075,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) */ adapter->physical_port = adapter->portnum; if (adapter->fw_major < 4) { - i = adapter->pci_read_normalize(adapter, - CRB_V2P(adapter->portnum)); + i = NXRD32(adapter, CRB_V2P(adapter->portnum)); if (i != 0x55555555) adapter->physical_port = i; } @@ -1036,10 +1086,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netdev->irq = adapter->msix_entries[0].vector; - netxen_napi_add(adapter, netdev); - - err = netxen_receive_peg_ready(adapter); - if (err) + if (netxen_napi_add(adapter, netdev)) goto err_out_disable_msi; init_timer(&adapter->watchdog_timer); @@ -1113,18 +1160,18 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev) if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC) { netxen_nic_detach(adapter); - - if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) - netxen_p3_free_mac_list(adapter); } if (adapter->portnum == 0) netxen_free_adapter_offload(adapter); netxen_teardown_intr(adapter); + netxen_free_sds_rings(&adapter->recv_ctx); netxen_cleanup_pci_map(adapter); + netxen_release_firmware(adapter); + pci_release_regions(pdev); pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); @@ -1132,6 +1179,7 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev) free_netdev(netdev); } +#ifdef CONFIG_PM static int netxen_nic_suspend(struct pci_dev *pdev, pm_message_t state) { @@ -1176,7 +1224,7 @@ netxen_nic_resume(struct pci_dev *pdev) adapter->curr_window = 255; - err = netxen_start_firmware(adapter); + err = netxen_start_firmware(adapter, 0); if (err) { dev_err(&pdev->dev, "failed to start firmware\n"); return err; @@ -1196,6 +1244,7 @@ netxen_nic_resume(struct pci_dev *pdev) return 0; } +#endif static int netxen_nic_open(struct net_device *netdev) { @@ -1315,7 +1364,7 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) { struct netxen_adapter *adapter = netdev_priv(netdev); - struct netxen_hardware_context *hw = &adapter->ahw; + struct nx_host_tx_ring *tx_ring = adapter->tx_ring; unsigned int first_seg_len = skb->len - skb->data_len; struct netxen_cmd_buffer *pbuf; struct netxen_skb_frag *buffrag; @@ -1324,30 +1373,26 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) dma_addr_t temp_dma; int i, k; - u32 producer, consumer; + u32 producer; int frag_count, no_of_desc; - u32 num_txd = adapter->num_txd; + u32 num_txd = tx_ring->num_desc; bool is_tso = false; frag_count = skb_shinfo(skb)->nr_frags + 1; - /* There 4 fragments per descriptor */ + /* 4 fragments per cmd des */ no_of_desc = (frag_count + 3) >> 2; - producer = adapter->cmd_producer; - smp_mb(); - consumer = adapter->last_cmd_consumer; - if ((no_of_desc+2) > find_diff_among(producer, consumer, num_txd)) { + if (unlikely(no_of_desc + 2) > netxen_tx_avail(tx_ring)) { netif_stop_queue(netdev); - smp_mb(); return NETDEV_TX_BUSY; } - /* Copy the descriptors into the hardware */ - hwdesc = &hw->cmd_desc_head[producer]; + producer = tx_ring->producer; + + hwdesc = &tx_ring->desc_head[producer]; netxen_clear_cmddesc((u64 *)hwdesc); - /* Take skb->data itself */ - pbuf = &adapter->cmd_buf_arr[producer]; + pbuf = &tx_ring->cmd_buf_arr[producer]; is_tso = netxen_tso_check(netdev, hwdesc, skb); @@ -1376,9 +1421,9 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) if ((i & 0x3) == 0) { k = 0; producer = get_next_index(producer, num_txd); - hwdesc = &hw->cmd_desc_head[producer]; + hwdesc = &tx_ring->desc_head[producer]; netxen_clear_cmddesc((u64 *)hwdesc); - pbuf = &adapter->cmd_buf_arr[producer]; + pbuf = &tx_ring->cmd_buf_arr[producer]; pbuf->skb = NULL; } frag = &skb_shinfo(skb)->frags[i - 1]; @@ -1430,8 +1475,8 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) more_hdr = 0; } /* copy the MAC/IP/TCP headers to the cmd descriptor list */ - hwdesc = &hw->cmd_desc_head[producer]; - pbuf = &adapter->cmd_buf_arr[producer]; + hwdesc = &tx_ring->desc_head[producer]; + pbuf = &tx_ring->cmd_buf_arr[producer]; pbuf->skb = NULL; /* copy the first 64 bytes */ @@ -1440,8 +1485,8 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) producer = get_next_index(producer, num_txd); if (more_hdr) { - hwdesc = &hw->cmd_desc_head[producer]; - pbuf = &adapter->cmd_buf_arr[producer]; + hwdesc = &tx_ring->desc_head[producer]; + pbuf = &tx_ring->cmd_buf_arr[producer]; pbuf->skb = NULL; /* copy the next 64 bytes - should be enough except * for pathological case @@ -1454,13 +1499,12 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) } } - adapter->cmd_producer = producer; + tx_ring->producer = producer; adapter->stats.txbytes += skb->len; - netxen_nic_update_cmd_producer(adapter, adapter->cmd_producer); + netxen_nic_update_cmd_producer(adapter, tx_ring); adapter->stats.xmitcalled++; - netdev->trans_start = jiffies; return NETDEV_TX_OK; @@ -1476,7 +1520,7 @@ static int netxen_nic_check_temp(struct netxen_adapter *adapter) uint32_t temp, temp_state, temp_val; int rv = 0; - temp = adapter->pci_read_normalize(adapter, CRB_TEMP_STATE); + temp = NXRD32(adapter, CRB_TEMP_STATE); temp_state = nx_get_temp_state(temp); temp_val = nx_get_temp_val(temp); @@ -1510,26 +1554,9 @@ static int netxen_nic_check_temp(struct netxen_adapter *adapter) return rv; } -static void netxen_nic_handle_phy_intr(struct netxen_adapter *adapter) +void netxen_advert_link_change(struct netxen_adapter *adapter, int linkup) { struct net_device *netdev = adapter->netdev; - u32 val, port, linkup; - - port = adapter->physical_port; - - if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) { - val = adapter->pci_read_normalize(adapter, CRB_XG_STATE_P3); - val = XG_LINK_STATE_P3(adapter->ahw.pci_func, val); - linkup = (val == XG_LINK_UP_P3); - } else { - val = adapter->pci_read_normalize(adapter, CRB_XG_STATE); - if (adapter->ahw.port_type == NETXEN_NIC_GBE) - linkup = (val >> port) & 1; - else { - val = (val >> port*8) & 0xff; - linkup = (val == XG_LINK_UP); - } - } if (adapter->ahw.linkup && !linkup) { printk(KERN_INFO "%s: %s NIC Link is down\n", @@ -1540,7 +1567,9 @@ static void netxen_nic_handle_phy_intr(struct netxen_adapter *adapter) netif_stop_queue(netdev); } - netxen_nic_set_link_parameters(adapter); + if (!adapter->has_link_events) + netxen_nic_set_link_parameters(adapter); + } else if (!adapter->ahw.linkup && linkup) { printk(KERN_INFO "%s: %s NIC Link is up\n", netxen_nic_driver_name, netdev->name); @@ -1550,10 +1579,34 @@ static void netxen_nic_handle_phy_intr(struct netxen_adapter *adapter) netif_wake_queue(netdev); } - netxen_nic_set_link_parameters(adapter); + if (!adapter->has_link_events) + netxen_nic_set_link_parameters(adapter); } } +static void netxen_nic_handle_phy_intr(struct netxen_adapter *adapter) +{ + u32 val, port, linkup; + + port = adapter->physical_port; + + if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) { + val = NXRD32(adapter, CRB_XG_STATE_P3); + val = XG_LINK_STATE_P3(adapter->ahw.pci_func, val); + linkup = (val == XG_LINK_UP_P3); + } else { + val = NXRD32(adapter, CRB_XG_STATE); + if (adapter->ahw.port_type == NETXEN_NIC_GBE) + linkup = (val >> port) & 1; + else { + val = (val >> port*8) & 0xff; + linkup = (val == XG_LINK_UP); + } + } + + netxen_advert_link_change(adapter, linkup); +} + static void netxen_watchdog(unsigned long v) { struct netxen_adapter *adapter = (struct netxen_adapter *)v; @@ -1569,7 +1622,8 @@ void netxen_watchdog_task(struct work_struct *work) if ((adapter->portnum == 0) && netxen_nic_check_temp(adapter)) return; - netxen_nic_handle_phy_intr(adapter); + if (!adapter->has_link_events) + netxen_nic_handle_phy_intr(adapter); if (netif_running(adapter->netdev)) mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ); @@ -1598,10 +1652,6 @@ static void netxen_tx_timeout_task(struct work_struct *work) netif_wake_queue(adapter->netdev); } -/* - * netxen_nic_get_stats - Get System Network Statistics - * @netdev: network interface device structure - */ struct net_device_stats *netxen_nic_get_stats(struct net_device *netdev) { struct netxen_adapter *adapter = netdev_priv(netdev); @@ -1609,22 +1659,11 @@ struct net_device_stats *netxen_nic_get_stats(struct net_device *netdev) memset(stats, 0, sizeof(*stats)); - /* total packets received */ stats->rx_packets = adapter->stats.no_rcv; - /* total packets transmitted */ - stats->tx_packets = adapter->stats.xmitedframes + - adapter->stats.xmitfinished; - /* total bytes received */ + stats->tx_packets = adapter->stats.xmitfinished; stats->rx_bytes = adapter->stats.rxbytes; - /* total bytes transmitted */ stats->tx_bytes = adapter->stats.txbytes; - /* bad packets received */ - stats->rx_errors = adapter->stats.rcvdbadskb; - /* packet transmit problems */ - stats->tx_errors = adapter->stats.nocmddescriptor; - /* no space in linux buffers */ stats->rx_dropped = adapter->stats.rxdropped; - /* no space available in linux */ stats->tx_dropped = adapter->stats.txdropped; return stats; @@ -1651,15 +1690,14 @@ static irqreturn_t netxen_intr(int irq, void *data) } else { unsigned long our_int = 0; - our_int = adapter->pci_read_normalize(adapter, CRB_INT_VECTOR); + our_int = NXRD32(adapter, CRB_INT_VECTOR); /* not our interrupt */ if (!test_and_clear_bit((7 + adapter->portnum), &our_int)) return IRQ_NONE; /* claim interrupt */ - adapter->pci_write_normalize(adapter, - CRB_INT_VECTOR, (our_int & 0xffffffff)); + NXWR32(adapter, CRB_INT_VECTOR, (our_int & 0xffffffff)); } /* clear interrupt */ @@ -1685,7 +1723,7 @@ static irqreturn_t netxen_msi_intr(int irq, void *data) /* clear interrupt */ adapter->pci_write_immediate(adapter, - msi_tgt_status[adapter->ahw.pci_func], 0xffffffff); + adapter->msi_tgt_status, 0xffffffff); napi_schedule(&sds_ring->napi); return IRQ_HANDLED; @@ -1736,8 +1774,10 @@ static struct pci_driver netxen_driver = { .id_table = netxen_pci_tbl, .probe = netxen_nic_probe, .remove = __devexit_p(netxen_nic_remove), +#ifdef CONFIG_PM .suspend = netxen_nic_suspend, .resume = netxen_nic_resume +#endif }; /* Driver Registration on NetXen card */ diff --git a/drivers/net/netxen/netxen_nic_niu.c b/drivers/net/netxen/netxen_nic_niu.c index d85203203d4d..5941c79be723 100644 --- a/drivers/net/netxen/netxen_nic_niu.c +++ b/drivers/net/netxen/netxen_nic_niu.c @@ -43,8 +43,7 @@ static int phy_lock(struct netxen_adapter *adapter) int done = 0, timeout = 0; while (!done) { - done = netxen_nic_reg_read(adapter, - NETXEN_PCIE_REG(PCIE_SEM3_LOCK)); + done = NXRD32(adapter, NETXEN_PCIE_REG(PCIE_SEM3_LOCK)); if (done == 1) break; if (timeout >= phy_lock_timeout) { @@ -59,8 +58,7 @@ static int phy_lock(struct netxen_adapter *adapter) } } - netxen_crb_writelit_adapter(adapter, - NETXEN_PHY_LOCK_ID, PHY_LOCK_DRIVER); + NXWR32(adapter, NETXEN_PHY_LOCK_ID, PHY_LOCK_DRIVER); return 0; } @@ -105,9 +103,7 @@ int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long reg, * so it cannot be in reset */ - if (adapter->hw_read_wx(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(0), - &mac_cfg0, 4)) - return -EIO; + mac_cfg0 = NXRD32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(0)); if (netxen_gb_get_soft_reset(mac_cfg0)) { __u32 temp; temp = 0; @@ -115,9 +111,7 @@ int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long reg, netxen_gb_rx_reset_pb(temp); netxen_gb_tx_reset_mac(temp); netxen_gb_rx_reset_mac(temp); - if (adapter->hw_write_wx(adapter, - NETXEN_NIU_GB_MAC_CONFIG_0(0), - &temp, 4)) + if (NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(0), temp)) return -EIO; restore = 1; } @@ -125,43 +119,32 @@ int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long reg, address = 0; netxen_gb_mii_mgmt_reg_addr(address, reg); netxen_gb_mii_mgmt_phy_addr(address, phy); - if (adapter->hw_write_wx(adapter, NETXEN_NIU_GB_MII_MGMT_ADDR(0), - &address, 4)) + if (NXWR32(adapter, NETXEN_NIU_GB_MII_MGMT_ADDR(0), address)) return -EIO; command = 0; /* turn off any prior activity */ - if (adapter->hw_write_wx(adapter, NETXEN_NIU_GB_MII_MGMT_COMMAND(0), - &command, 4)) + if (NXWR32(adapter, NETXEN_NIU_GB_MII_MGMT_COMMAND(0), command)) return -EIO; /* send read command */ netxen_gb_mii_mgmt_set_read_cycle(command); - if (adapter->hw_write_wx(adapter, NETXEN_NIU_GB_MII_MGMT_COMMAND(0), - &command, 4)) + if (NXWR32(adapter, NETXEN_NIU_GB_MII_MGMT_COMMAND(0), command)) return -EIO; status = 0; do { - if (adapter->hw_read_wx(adapter, - NETXEN_NIU_GB_MII_MGMT_INDICATE(0), - &status, 4)) - return -EIO; + status = NXRD32(adapter, NETXEN_NIU_GB_MII_MGMT_INDICATE(0)); timeout++; } while ((netxen_get_gb_mii_mgmt_busy(status) || netxen_get_gb_mii_mgmt_notvalid(status)) && (timeout++ < NETXEN_NIU_PHY_WAITMAX)); if (timeout < NETXEN_NIU_PHY_WAITMAX) { - if (adapter->hw_read_wx(adapter, - NETXEN_NIU_GB_MII_MGMT_STATUS(0), - readval, 4)) - return -EIO; + *readval = NXRD32(adapter, NETXEN_NIU_GB_MII_MGMT_STATUS(0)); result = 0; } else result = -1; if (restore) - if (adapter->hw_write_wx(adapter, - NETXEN_NIU_GB_MAC_CONFIG_0(0), - &mac_cfg0, 4)) + if (NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(0), mac_cfg0)) return -EIO; phy_unlock(adapter); return result; @@ -197,9 +180,7 @@ int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter, long reg, * cannot be in reset */ - if (adapter->hw_read_wx(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(0), - &mac_cfg0, 4)) - return -EIO; + mac_cfg0 = NXRD32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(0)); if (netxen_gb_get_soft_reset(mac_cfg0)) { __u32 temp; temp = 0; @@ -208,35 +189,27 @@ int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter, long reg, netxen_gb_tx_reset_mac(temp); netxen_gb_rx_reset_mac(temp); - if (adapter->hw_write_wx(adapter, - NETXEN_NIU_GB_MAC_CONFIG_0(0), - &temp, 4)) + if (NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(0), temp)) return -EIO; restore = 1; } command = 0; /* turn off any prior activity */ - if (adapter->hw_write_wx(adapter, NETXEN_NIU_GB_MII_MGMT_COMMAND(0), - &command, 4)) + if (NXWR32(adapter, NETXEN_NIU_GB_MII_MGMT_COMMAND(0), command)) return -EIO; address = 0; netxen_gb_mii_mgmt_reg_addr(address, reg); netxen_gb_mii_mgmt_phy_addr(address, phy); - if (adapter->hw_write_wx(adapter, NETXEN_NIU_GB_MII_MGMT_ADDR(0), - &address, 4)) + if (NXWR32(adapter, NETXEN_NIU_GB_MII_MGMT_ADDR(0), address)) return -EIO; - if (adapter->hw_write_wx(adapter, NETXEN_NIU_GB_MII_MGMT_CTRL(0), - &val, 4)) + if (NXWR32(adapter, NETXEN_NIU_GB_MII_MGMT_CTRL(0), val)) return -EIO; status = 0; do { - if (adapter->hw_read_wx(adapter, - NETXEN_NIU_GB_MII_MGMT_INDICATE(0), - &status, 4)) - return -EIO; + status = NXRD32(adapter, NETXEN_NIU_GB_MII_MGMT_INDICATE(0)); timeout++; } while ((netxen_get_gb_mii_mgmt_busy(status)) && (timeout++ < NETXEN_NIU_PHY_WAITMAX)); @@ -248,9 +221,7 @@ int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter, long reg, /* restore the state of port 0 MAC in case we tampered with it */ if (restore) - if (adapter->hw_write_wx(adapter, - NETXEN_NIU_GB_MAC_CONFIG_0(0), - &mac_cfg0, 4)) + if (NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(0), mac_cfg0)) return -EIO; return result; @@ -258,7 +229,7 @@ int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter, long reg, int netxen_niu_xgbe_enable_phy_interrupts(struct netxen_adapter *adapter) { - netxen_crb_writelit_adapter(adapter, NETXEN_NIU_INT_MASK, 0x3f); + NXWR32(adapter, NETXEN_NIU_INT_MASK, 0x3f); return 0; } @@ -281,7 +252,7 @@ int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter) int netxen_niu_xgbe_disable_phy_interrupts(struct netxen_adapter *adapter) { - netxen_crb_writelit_adapter(adapter, NETXEN_NIU_INT_MASK, 0x7f); + NXWR32(adapter, NETXEN_NIU_INT_MASK, 0x7f); return 0; } @@ -315,36 +286,27 @@ static int netxen_niu_gbe_clear_phy_interrupts(struct netxen_adapter *adapter) static void netxen_niu_gbe_set_mii_mode(struct netxen_adapter *adapter, int port, long enable) { - netxen_crb_writelit_adapter(adapter, NETXEN_NIU_MODE, 0x2); - netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), - 0x80000000); - netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), - 0x0000f0025); - netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB_MAC_CONFIG_1(port), - 0xf1ff); - netxen_crb_writelit_adapter(adapter, - NETXEN_NIU_GB0_GMII_MODE + (port << 3), 0); - netxen_crb_writelit_adapter(adapter, - NETXEN_NIU_GB0_MII_MODE + (port << 3), 1); - netxen_crb_writelit_adapter(adapter, - (NETXEN_NIU_GB0_HALF_DUPLEX + port * 4), 0); - netxen_crb_writelit_adapter(adapter, - NETXEN_NIU_GB_MII_MGMT_CONFIG(port), 0x7); + NXWR32(adapter, NETXEN_NIU_MODE, 0x2); + NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), 0x80000000); + NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), 0x0000f0025); + NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_1(port), 0xf1ff); + NXWR32(adapter, NETXEN_NIU_GB0_GMII_MODE + (port << 3), 0); + NXWR32(adapter, NETXEN_NIU_GB0_MII_MODE + (port << 3), 1); + NXWR32(adapter, (NETXEN_NIU_GB0_HALF_DUPLEX + port * 4), 0); + NXWR32(adapter, NETXEN_NIU_GB_MII_MGMT_CONFIG(port), 0x7); if (enable) { /* * Do NOT enable flow control until a suitable solution for * shutting down pause frames is found. */ - netxen_crb_writelit_adapter(adapter, - NETXEN_NIU_GB_MAC_CONFIG_0(port), - 0x5); + NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), 0x5); } if (netxen_niu_gbe_enable_phy_interrupts(adapter)) - printk(KERN_ERR PFX "ERROR enabling PHY interrupts\n"); + printk(KERN_ERR "ERROR enabling PHY interrupts\n"); if (netxen_niu_gbe_clear_phy_interrupts(adapter)) - printk(KERN_ERR PFX "ERROR clearing PHY interrupts\n"); + printk(KERN_ERR "ERROR clearing PHY interrupts\n"); } /* @@ -353,36 +315,27 @@ static void netxen_niu_gbe_set_mii_mode(struct netxen_adapter *adapter, static void netxen_niu_gbe_set_gmii_mode(struct netxen_adapter *adapter, int port, long enable) { - netxen_crb_writelit_adapter(adapter, NETXEN_NIU_MODE, 0x2); - netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), - 0x80000000); - netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), - 0x0000f0025); - netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB_MAC_CONFIG_1(port), - 0xf2ff); - netxen_crb_writelit_adapter(adapter, - NETXEN_NIU_GB0_MII_MODE + (port << 3), 0); - netxen_crb_writelit_adapter(adapter, - NETXEN_NIU_GB0_GMII_MODE + (port << 3), 1); - netxen_crb_writelit_adapter(adapter, - (NETXEN_NIU_GB0_HALF_DUPLEX + port * 4), 0); - netxen_crb_writelit_adapter(adapter, - NETXEN_NIU_GB_MII_MGMT_CONFIG(port), 0x7); + NXWR32(adapter, NETXEN_NIU_MODE, 0x2); + NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), 0x80000000); + NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), 0x0000f0025); + NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_1(port), 0xf2ff); + NXWR32(adapter, NETXEN_NIU_GB0_MII_MODE + (port << 3), 0); + NXWR32(adapter, NETXEN_NIU_GB0_GMII_MODE + (port << 3), 1); + NXWR32(adapter, (NETXEN_NIU_GB0_HALF_DUPLEX + port * 4), 0); + NXWR32(adapter, NETXEN_NIU_GB_MII_MGMT_CONFIG(port), 0x7); if (enable) { /* * Do NOT enable flow control until a suitable solution for * shutting down pause frames is found. */ - netxen_crb_writelit_adapter(adapter, - NETXEN_NIU_GB_MAC_CONFIG_0(port), - 0x5); + NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), 0x5); } if (netxen_niu_gbe_enable_phy_interrupts(adapter)) - printk(KERN_ERR PFX "ERROR enabling PHY interrupts\n"); + printk(KERN_ERR "ERROR enabling PHY interrupts\n"); if (netxen_niu_gbe_clear_phy_interrupts(adapter)) - printk(KERN_ERR PFX "ERROR clearing PHY interrupts\n"); + printk(KERN_ERR "ERROR clearing PHY interrupts\n"); } int netxen_niu_gbe_init_port(struct netxen_adapter *adapter, int port) @@ -416,25 +369,20 @@ int netxen_niu_gbe_init_port(struct netxen_adapter *adapter, int port) * plugged in. */ - netxen_crb_writelit_adapter(adapter, - NETXEN_NIU_GB_MAC_CONFIG_0 - (port), + NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), NETXEN_GB_MAC_SOFT_RESET); - netxen_crb_writelit_adapter(adapter, - NETXEN_NIU_GB_MAC_CONFIG_0 - (port), - NETXEN_GB_MAC_RESET_PROT_BLK - | NETXEN_GB_MAC_ENABLE_TX_RX - | - NETXEN_GB_MAC_PAUSED_FRMS); + NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), + NETXEN_GB_MAC_RESET_PROT_BLK | + NETXEN_GB_MAC_ENABLE_TX_RX | + NETXEN_GB_MAC_PAUSED_FRMS); if (netxen_niu_gbe_clear_phy_interrupts(adapter)) - printk(KERN_ERR PFX + printk(KERN_ERR "ERROR clearing PHY interrupts\n"); if (netxen_niu_gbe_enable_phy_interrupts(adapter)) - printk(KERN_ERR PFX + printk(KERN_ERR "ERROR enabling PHY interrupts\n"); if (netxen_niu_gbe_clear_phy_interrupts(adapter)) - printk(KERN_ERR PFX + printk(KERN_ERR "ERROR clearing PHY interrupts\n"); result = -1; } @@ -447,91 +395,13 @@ int netxen_niu_gbe_init_port(struct netxen_adapter *adapter, int port) int netxen_niu_xg_init_port(struct netxen_adapter *adapter, int port) { if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { - netxen_crb_writelit_adapter(adapter, - NETXEN_NIU_XGE_CONFIG_1+(0x10000*port), 0x1447); - netxen_crb_writelit_adapter(adapter, - NETXEN_NIU_XGE_CONFIG_0+(0x10000*port), 0x5); + NXWR32(adapter, NETXEN_NIU_XGE_CONFIG_1+(0x10000*port), 0x1447); + NXWR32(adapter, NETXEN_NIU_XGE_CONFIG_0+(0x10000*port), 0x5); } return 0; } -/* - * Return the current station MAC address. - * Note that the passed-in value must already be in network byte order. - */ -static int netxen_niu_macaddr_get(struct netxen_adapter *adapter, - netxen_ethernet_macaddr_t * addr) -{ - u32 stationhigh; - u32 stationlow; - int phy = adapter->physical_port; - u8 val[8]; - - if (addr == NULL) - return -EINVAL; - if ((phy < 0) || (phy > 3)) - return -EINVAL; - - if (adapter->hw_read_wx(adapter, NETXEN_NIU_GB_STATION_ADDR_0(phy), - &stationhigh, 4)) - return -EIO; - if (adapter->hw_read_wx(adapter, NETXEN_NIU_GB_STATION_ADDR_1(phy), - &stationlow, 4)) - return -EIO; - ((__le32 *)val)[1] = cpu_to_le32(stationhigh); - ((__le32 *)val)[0] = cpu_to_le32(stationlow); - - memcpy(addr, val + 2, 6); - - return 0; -} - -/* - * Set the station MAC address. - * Note that the passed-in value must already be in network byte order. - */ -int netxen_niu_macaddr_set(struct netxen_adapter *adapter, - netxen_ethernet_macaddr_t addr) -{ - u8 temp[4]; - u32 val; - int phy = adapter->physical_port; - unsigned char mac_addr[6]; - int i; - - if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) - return 0; - - for (i = 0; i < 10; i++) { - temp[0] = temp[1] = 0; - memcpy(temp + 2, addr, 2); - val = le32_to_cpu(*(__le32 *)temp); - if (adapter->hw_write_wx(adapter, - NETXEN_NIU_GB_STATION_ADDR_1(phy), &val, 4)) - return -EIO; - - memcpy(temp, ((u8 *) addr) + 2, sizeof(__le32)); - val = le32_to_cpu(*(__le32 *)temp); - if (adapter->hw_write_wx(adapter, - NETXEN_NIU_GB_STATION_ADDR_0(phy), &val, 4)) - return -2; - - netxen_niu_macaddr_get(adapter, - (netxen_ethernet_macaddr_t *) mac_addr); - if (memcmp(mac_addr, addr, 6) == 0) - break; - } - - if (i == 10) { - printk(KERN_ERR "%s: cannot set Mac addr for %s\n", - netxen_nic_driver_name, adapter->netdev->name); - printk(KERN_ERR "MAC address set: %pM.\n", addr); - printk(KERN_ERR "MAC address get: %pM.\n", mac_addr); - } - return 0; -} - /* Disable a GbE interface */ int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter) { @@ -545,8 +415,7 @@ int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter) return -EINVAL; mac_cfg0 = 0; netxen_gb_soft_reset(mac_cfg0); - if (adapter->hw_write_wx(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), - &mac_cfg0, 4)) + if (NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), mac_cfg0)) return -EIO; return 0; } @@ -564,8 +433,8 @@ int netxen_niu_disable_xg_port(struct netxen_adapter *adapter) return -EINVAL; mac_cfg = 0; - if (adapter->hw_write_wx(adapter, - NETXEN_NIU_XGE_CONFIG_0 + (0x10000 * port), &mac_cfg, 4)) + if (NXWR32(adapter, + NETXEN_NIU_XGE_CONFIG_0 + (0x10000 * port), mac_cfg)) return -EIO; return 0; } @@ -581,9 +450,7 @@ int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, return -EINVAL; /* save previous contents */ - if (adapter->hw_read_wx(adapter, NETXEN_NIU_GB_DROP_WRONGADDR, - ®, 4)) - return -EIO; + reg = NXRD32(adapter, NETXEN_NIU_GB_DROP_WRONGADDR); if (mode == NETXEN_NIU_PROMISC_MODE) { switch (port) { case 0: @@ -619,67 +486,11 @@ int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, return -EIO; } } - if (adapter->hw_write_wx(adapter, NETXEN_NIU_GB_DROP_WRONGADDR, - ®, 4)) + if (NXWR32(adapter, NETXEN_NIU_GB_DROP_WRONGADDR, reg)) return -EIO; return 0; } -/* - * Set the MAC address for an XG port - * Note that the passed-in value must already be in network byte order. - */ -int netxen_niu_xg_macaddr_set(struct netxen_adapter *adapter, - netxen_ethernet_macaddr_t addr) -{ - int phy = adapter->physical_port; - u8 temp[4]; - u32 val; - - if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) - return 0; - - if ((phy < 0) || (phy > NETXEN_NIU_MAX_XG_PORTS)) - return -EIO; - - temp[0] = temp[1] = 0; - switch (phy) { - case 0: - memcpy(temp + 2, addr, 2); - val = le32_to_cpu(*(__le32 *)temp); - if (adapter->hw_write_wx(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_1, - &val, 4)) - return -EIO; - - memcpy(&temp, ((u8 *) addr) + 2, sizeof(__le32)); - val = le32_to_cpu(*(__le32 *)temp); - if (adapter->hw_write_wx(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_HI, - &val, 4)) - return -EIO; - break; - - case 1: - memcpy(temp + 2, addr, 2); - val = le32_to_cpu(*(__le32 *)temp); - if (adapter->hw_write_wx(adapter, NETXEN_NIU_XG1_STATION_ADDR_0_1, - &val, 4)) - return -EIO; - - memcpy(&temp, ((u8 *) addr) + 2, sizeof(__le32)); - val = le32_to_cpu(*(__le32 *)temp); - if (adapter->hw_write_wx(adapter, NETXEN_NIU_XG1_STATION_ADDR_0_HI, - &val, 4)) - return -EIO; - break; - - default: - printk(KERN_ERR "Unknown port %d\n", phy); - break; - } - - return 0; -} - int netxen_niu_xg_set_promiscuous_mode(struct netxen_adapter *adapter, u32 mode) { @@ -689,9 +500,7 @@ int netxen_niu_xg_set_promiscuous_mode(struct netxen_adapter *adapter, if (port > NETXEN_NIU_MAX_XG_PORTS) return -EINVAL; - if (adapter->hw_read_wx(adapter, - NETXEN_NIU_XGE_CONFIG_1 + (0x10000 * port), ®, 4)) - return -EIO; + reg = NXRD32(adapter, NETXEN_NIU_XGE_CONFIG_1 + (0x10000 * port)); if (mode == NETXEN_NIU_PROMISC_MODE) reg = (reg | 0x2000UL); else @@ -702,8 +511,40 @@ int netxen_niu_xg_set_promiscuous_mode(struct netxen_adapter *adapter, else reg = (reg & ~0x1000UL); - netxen_crb_writelit_adapter(adapter, - NETXEN_NIU_XGE_CONFIG_1 + (0x10000 * port), reg); + NXWR32(adapter, NETXEN_NIU_XGE_CONFIG_1 + (0x10000 * port), reg); + + return 0; +} + +int netxen_p2_nic_set_mac_addr(struct netxen_adapter *adapter, u8 *addr) +{ + u32 mac_hi, mac_lo; + u32 reg_hi, reg_lo; + + u8 phy = adapter->physical_port; + u8 phy_count = (adapter->ahw.port_type == NETXEN_NIC_XGBE) ? + NETXEN_NIU_MAX_XG_PORTS : NETXEN_NIU_MAX_GBE_PORTS; + + if (phy >= phy_count) + return -EINVAL; + + mac_lo = ((u32)addr[0] << 16) | ((u32)addr[1] << 24); + mac_hi = addr[2] | ((u32)addr[3] << 8) | + ((u32)addr[4] << 16) | ((u32)addr[5] << 24); + + if (adapter->ahw.port_type == NETXEN_NIC_XGBE) { + reg_lo = NETXEN_NIU_XGE_STATION_ADDR_0_1 + (0x10000 * phy); + reg_hi = NETXEN_NIU_XGE_STATION_ADDR_0_HI + (0x10000 * phy); + } else { + reg_lo = NETXEN_NIU_GB_STATION_ADDR_1(phy); + reg_hi = NETXEN_NIU_GB_STATION_ADDR_0(phy); + } + + /* write twice to flush */ + if (NXWR32(adapter, reg_lo, mac_lo) || NXWR32(adapter, reg_hi, mac_hi)) + return -EIO; + if (NXWR32(adapter, reg_lo, mac_lo) || NXWR32(adapter, reg_hi, mac_hi)) + return -EIO; return 0; } diff --git a/drivers/net/netxen/netxen_nic_phan_reg.h b/drivers/net/netxen/netxen_nic_phan_reg.h index 50183335e43a..b73a62ca74f8 100644 --- a/drivers/net/netxen/netxen_nic_phan_reg.h +++ b/drivers/net/netxen/netxen_nic_phan_reg.h @@ -36,23 +36,25 @@ */ #define NIC_CRB_BASE NETXEN_CAM_RAM(0x200) #define NETXEN_NIC_REG(X) (NIC_CRB_BASE+(X)) +#define NIC_CRB_BASE_2 NETXEN_CAM_RAM(0x700) +#define NETXEN_NIC_REG_2(X) (NIC_CRB_BASE_2+(X)) #define CRB_PHAN_CNTRL_LO_OFFSET NETXEN_NIC_REG(0x00) #define CRB_PHAN_CNTRL_HI_OFFSET NETXEN_NIC_REG(0x04) #define CRB_CMD_PRODUCER_OFFSET NETXEN_NIC_REG(0x08) #define CRB_CMD_CONSUMER_OFFSET NETXEN_NIC_REG(0x0c) -#define CRB_PAUSE_ADDR_LO NETXEN_NIC_REG(0x10) /* C0 EPG BUG */ +#define CRB_PAUSE_ADDR_LO NETXEN_NIC_REG(0x10) #define CRB_PAUSE_ADDR_HI NETXEN_NIC_REG(0x14) #define NX_CDRP_CRB_OFFSET NETXEN_NIC_REG(0x18) #define NX_ARG1_CRB_OFFSET NETXEN_NIC_REG(0x1c) #define NX_ARG2_CRB_OFFSET NETXEN_NIC_REG(0x20) #define NX_ARG3_CRB_OFFSET NETXEN_NIC_REG(0x24) #define NX_SIGN_CRB_OFFSET NETXEN_NIC_REG(0x28) -#define CRB_CMD_INTR_LOOP NETXEN_NIC_REG(0x20) /* 4 regs for perf */ +#define CRB_CMD_INTR_LOOP NETXEN_NIC_REG(0x20) #define CRB_CMD_DMA_LOOP NETXEN_NIC_REG(0x24) #define CRB_RCV_INTR_LOOP NETXEN_NIC_REG(0x28) #define CRB_RCV_DMA_LOOP NETXEN_NIC_REG(0x2c) -#define CRB_ENABLE_TX_INTR NETXEN_NIC_REG(0x30) /* phantom init status */ +#define CRB_ENABLE_TX_INTR NETXEN_NIC_REG(0x30) #define CRB_MMAP_ADDR_3 NETXEN_NIC_REG(0x34) #define CRB_CMDPEG_CMDRING NETXEN_NIC_REG(0x38) #define CRB_HOST_DUMMY_BUF_ADDR_HI NETXEN_NIC_REG(0x3c) @@ -65,7 +67,7 @@ #define CRB_MMAP_SIZE_1 NETXEN_NIC_REG(0x58) #define CRB_MMAP_SIZE_2 NETXEN_NIC_REG(0x5c) #define CRB_MMAP_SIZE_3 NETXEN_NIC_REG(0x60) -#define CRB_GLOBAL_INT_COAL NETXEN_NIC_REG(0x64) /* interrupt coalescing */ +#define CRB_GLOBAL_INT_COAL NETXEN_NIC_REG(0x64) #define CRB_INT_COAL_MODE NETXEN_NIC_REG(0x68) #define CRB_MAX_RCV_BUFS NETXEN_NIC_REG(0x6c) #define CRB_TX_INT_THRESHOLD NETXEN_NIC_REG(0x70) @@ -83,13 +85,13 @@ #define CRB_AGENT_TX_TYPE NETXEN_NIC_REG(0xa0) #define CRB_AGENT_TX_ADDR NETXEN_NIC_REG(0xa4) #define CRB_AGENT_TX_MSS NETXEN_NIC_REG(0xa8) -#define CRB_TX_STATE NETXEN_NIC_REG(0xac) /* Debug -performance */ +#define CRB_TX_STATE NETXEN_NIC_REG(0xac) #define CRB_TX_COUNT NETXEN_NIC_REG(0xb0) #define CRB_RX_STATE NETXEN_NIC_REG(0xb4) #define CRB_RX_PERF_DEBUG_1 NETXEN_NIC_REG(0xb8) -#define CRB_RX_LRO_CONTROL NETXEN_NIC_REG(0xbc) /* LRO On/OFF */ +#define CRB_RX_LRO_CONTROL NETXEN_NIC_REG(0xbc) #define CRB_RX_LRO_START_NUM NETXEN_NIC_REG(0xc0) -#define CRB_MPORT_MODE NETXEN_NIC_REG(0xc4) /* Multiport Mode */ +#define CRB_MPORT_MODE NETXEN_NIC_REG(0xc4) #define CRB_CMD_RING_SIZE NETXEN_NIC_REG(0xc8) #define CRB_DMA_SHIFT NETXEN_NIC_REG(0xcc) #define CRB_INT_VECTOR NETXEN_NIC_REG(0xd4) @@ -109,8 +111,6 @@ #define CRB_CMD_CONSUMER_OFFSET_1 NETXEN_NIC_REG(0x1b0) #define CRB_CMD_PRODUCER_OFFSET_2 NETXEN_NIC_REG(0x1b8) #define CRB_CMD_CONSUMER_OFFSET_2 NETXEN_NIC_REG(0x1bc) - -// 1c0 to 1cc used for signature reg #define CRB_CMD_PRODUCER_OFFSET_3 NETXEN_NIC_REG(0x1d0) #define CRB_CMD_CONSUMER_OFFSET_3 NETXEN_NIC_REG(0x1d4) #define CRB_TEMP_STATE NETXEN_NIC_REG(0x1b4) @@ -120,13 +120,13 @@ #define CRB_V2P_2 NETXEN_NIC_REG(0x298) #define CRB_V2P_3 NETXEN_NIC_REG(0x29c) #define CRB_V2P(port) (CRB_V2P_0+((port)*4)) -#define CRB_DRIVER_VERSION NETXEN_NIC_REG(0x2a0) -/* sw int status/mask registers */ +#define CRB_DRIVER_VERSION NETXEN_NIC_REG(0x2a0) #define CRB_SW_INT_MASK_0 NETXEN_NIC_REG(0x1d8) #define CRB_SW_INT_MASK_1 NETXEN_NIC_REG(0x1e0) #define CRB_SW_INT_MASK_2 NETXEN_NIC_REG(0x1e4) #define CRB_SW_INT_MASK_3 NETXEN_NIC_REG(0x1e8) +#define CRB_FW_CAPABILITIES_1 NETXEN_CAM_RAM(0x128) #define CRB_MAC_BLOCK_START NETXEN_CAM_RAM(0x1c0) /* @@ -136,7 +136,7 @@ #define CRB_NIC_CAPABILITIES_HOST NETXEN_NIC_REG(0x1a8) #define CRB_NIC_CAPABILITIES_FW NETXEN_NIC_REG(0x1dc) #define CRB_NIC_MSI_MODE_HOST NETXEN_NIC_REG(0x270) -#define CRB_NIC_MSI_MODE_FW NETXEN_NIC_REG(0x274) +#define CRB_NIC_MSI_MODE_FW NETXEN_NIC_REG(0x274) #define INTR_SCHEME_PERPORT 0x1 #define MSI_MODE_MULTIFUNC 0x1 @@ -162,7 +162,8 @@ struct netxen_recv_crb { u32 crb_rcv_producer[NUM_RCV_DESC_RINGS]; - u32 crb_sts_consumer; + u32 crb_sts_consumer[NUM_STS_DESC_RINGS]; + u32 sw_int_mask[NUM_STS_DESC_RINGS]; }; /* diff --git a/drivers/net/ni65.c b/drivers/net/ni65.c index 6474f02bf783..1f10ed603e20 100644 --- a/drivers/net/ni65.c +++ b/drivers/net/ni65.c @@ -1165,7 +1165,7 @@ static int ni65_send_packet(struct sk_buff *skb, struct net_device *dev) if (test_and_set_bit(0, (void*)&p->lock)) { printk(KERN_ERR "%s: Queue was locked.\n", dev->name); - return 1; + return NETDEV_TX_BUSY; } { diff --git a/drivers/net/niu.c b/drivers/net/niu.c index 2b1745328cf7..d2146d4a10f3 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c @@ -22,6 +22,7 @@ #include #include #include +#include #include @@ -1317,7 +1318,7 @@ static int bcm8704_reset(struct niu *np) err = mdio_read(np, np->phy_addr, BCM8704_PHYXS_DEV_ADDR, MII_BMCR); - if (err < 0) + if (err < 0 || err == 0xffff) return err; err |= BMCR_RESET; err = mdio_write(np, np->phy_addr, BCM8704_PHYXS_DEV_ADDR, @@ -2042,7 +2043,7 @@ static int link_status_10g_bcm8706(struct niu *np, int *link_up_p) err = mdio_read(np, np->phy_addr, BCM8704_PMA_PMD_DEV_ADDR, BCM8704_PMD_RCV_SIGDET); - if (err < 0) + if (err < 0 || err == 0xffff) goto out; if (!(err & PMD_RCV_SIGDET_GLOBAL)) { err = 0; @@ -2083,8 +2084,6 @@ static int link_status_10g_bcm8706(struct niu *np, int *link_up_p) out: *link_up_p = link_up; - if (np->flags & NIU_FLAGS_HOTPLUG_PHY) - err = 0; return err; } @@ -2220,10 +2219,17 @@ static int link_status_10g_hotplug(struct niu *np, int *link_up_p) if (phy_present != phy_present_prev) { /* state change */ if (phy_present) { + /* A NEM was just plugged in */ np->flags |= NIU_FLAGS_HOTPLUG_PHY_PRESENT; if (np->phy_ops->xcvr_init) err = np->phy_ops->xcvr_init(np); if (err) { + err = mdio_read(np, np->phy_addr, + BCM8704_PHYXS_DEV_ADDR, MII_BMCR); + if (err == 0xffff) { + /* No mdio, back-to-back XAUI */ + goto out; + } /* debounce */ np->flags &= ~NIU_FLAGS_HOTPLUG_PHY_PRESENT; } @@ -2234,13 +2240,21 @@ static int link_status_10g_hotplug(struct niu *np, int *link_up_p) np->dev->name); } } - if (np->flags & NIU_FLAGS_HOTPLUG_PHY_PRESENT) +out: + if (np->flags & NIU_FLAGS_HOTPLUG_PHY_PRESENT) { err = link_status_10g_bcm8706(np, link_up_p); + if (err == 0xffff) { + /* No mdio, back-to-back XAUI: it is C10NEM */ + *link_up_p = 1; + np->link_config.active_speed = SPEED_10000; + np->link_config.active_duplex = DUPLEX_FULL; + } + } } spin_unlock_irqrestore(&np->lock, flags); - return err; + return 0; } static int niu_link_status(struct niu *np, int *link_up_p) @@ -2312,6 +2326,12 @@ static const struct niu_phy_ops phy_ops_10g_fiber_hotplug = { .link_status = link_status_10g_hotplug, }; +static const struct niu_phy_ops phy_ops_niu_10g_hotplug = { + .serdes_init = serdes_init_niu_10g_fiber, + .xcvr_init = xcvr_init_10g_bcm8706, + .link_status = link_status_10g_hotplug, +}; + static const struct niu_phy_ops phy_ops_10g_copper = { .serdes_init = serdes_init_10g, .link_status = link_status_10g, /* XXX */ @@ -2358,6 +2378,11 @@ static const struct niu_phy_template phy_template_10g_fiber_hotplug = { .phy_addr_base = 8, }; +static const struct niu_phy_template phy_template_niu_10g_hotplug = { + .ops = &phy_ops_niu_10g_hotplug, + .phy_addr_base = 8, +}; + static const struct niu_phy_template phy_template_10g_copper = { .ops = &phy_ops_10g_copper, .phy_addr_base = 10, @@ -2542,8 +2567,16 @@ static int niu_determine_phy_disposition(struct niu *np) case NIU_FLAGS_10G | NIU_FLAGS_FIBER: /* 10G Fiber */ default: - tp = &phy_template_niu_10g_fiber; - phy_addr_off += np->port; + if (np->flags & NIU_FLAGS_HOTPLUG_PHY) { + tp = &phy_template_niu_10g_hotplug; + if (np->port == 0) + phy_addr_off = 8; + if (np->port == 1) + phy_addr_off = 12; + } else { + tp = &phy_template_niu_10g_fiber; + phy_addr_off += np->port; + } break; } } else { @@ -2630,11 +2663,11 @@ static int niu_init_link(struct niu *np) msleep(200); } err = niu_serdes_init(np); - if (err) + if (err && !(np->flags & NIU_FLAGS_HOTPLUG_PHY)) return err; msleep(200); err = niu_xcvr_init(np); - if (!err) + if (!err || (np->flags & NIU_FLAGS_HOTPLUG_PHY)) niu_link_status(np, &ignore); return 0; } @@ -6330,6 +6363,7 @@ static void niu_set_rx_mode(struct net_device *dev) struct niu *np = netdev_priv(dev); int i, alt_cnt, err; struct dev_addr_list *addr; + struct netdev_hw_addr *ha; unsigned long flags; u16 hash[16] = { 0, }; @@ -6342,7 +6376,7 @@ static void niu_set_rx_mode(struct net_device *dev) if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 0)) np->flags |= NIU_FLAGS_MCAST; - alt_cnt = dev->uc_count; + alt_cnt = dev->uc.count; if (alt_cnt > niu_num_alt_addr(np)) { alt_cnt = 0; np->flags |= NIU_FLAGS_PROMISC; @@ -6351,9 +6385,8 @@ static void niu_set_rx_mode(struct net_device *dev) if (alt_cnt) { int index = 0; - for (addr = dev->uc_list; addr; addr = addr->next) { - err = niu_set_alt_mac(np, index, - addr->da_addr); + list_for_each_entry(ha, &dev->uc.list, list) { + err = niu_set_alt_mac(np, index, ha->addr); if (err) printk(KERN_WARNING PFX "%s: Error %d " "adding alt mac %d\n", @@ -6745,8 +6778,6 @@ static int niu_start_xmit(struct sk_buff *skb, struct net_device *dev) netif_tx_wake_queue(txq); } - dev->trans_start = jiffies; - out: return NETDEV_TX_OK; @@ -9346,6 +9377,11 @@ static int __devinit niu_get_of_props(struct niu *np) if (model) strcpy(np->vpd.model, model); + if (of_find_property(dp, "hot-swappable-phy", &prop_len)) { + np->flags |= (NIU_FLAGS_10G | NIU_FLAGS_FIBER | + NIU_FLAGS_HOTPLUG_PHY); + } + return 0; #else return -EINVAL; diff --git a/drivers/net/niu.h b/drivers/net/niu.h index 8754e44cadae..3bd0b5933d59 100644 --- a/drivers/net/niu.h +++ b/drivers/net/niu.h @@ -3242,8 +3242,8 @@ struct niu { struct niu_parent *parent; u32 flags; -#define NIU_FLAGS_HOTPLUG_PHY_PRESENT 0x02000000 /* Removebale PHY detected*/ -#define NIU_FLAGS_HOTPLUG_PHY 0x01000000 /* Removebale PHY */ +#define NIU_FLAGS_HOTPLUG_PHY_PRESENT 0x02000000 /* Removeable PHY detected*/ +#define NIU_FLAGS_HOTPLUG_PHY 0x01000000 /* Removeable PHY */ #define NIU_FLAGS_VPD_VALID 0x00800000 /* VPD has valid version */ #define NIU_FLAGS_MSIX 0x00400000 /* MSI-X in use */ #define NIU_FLAGS_MCAST 0x00200000 /* multicast filter enabled */ diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c index d531614a90b5..1576ac07216e 100644 --- a/drivers/net/ns83820.c +++ b/drivers/net/ns83820.c @@ -1097,7 +1097,7 @@ again: if (unlikely(dev->CFG_cache & CFG_LNKSTS)) { netif_stop_queue(ndev); if (unlikely(dev->CFG_cache & CFG_LNKSTS)) - return 1; + return NETDEV_TX_BUSY; netif_start_queue(ndev); } @@ -1115,7 +1115,7 @@ again: netif_start_queue(ndev); goto again; } - return 1; + return NETDEV_TX_BUSY; } if (free_idx == dev->tx_intr_idx) { @@ -1204,9 +1204,7 @@ again: if (stopped && (dev->tx_done_idx != tx_done_idx) && start_tx_okay(dev)) netif_start_queue(ndev); - /* set the transmit start time to catch transmit timeouts */ - ndev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } static void ns83820_update_stats(struct ns83820 *dev) @@ -1626,7 +1624,7 @@ static void ns83820_tx_watch(unsigned long data) ); #endif - if (time_after(jiffies, ndev->trans_start + 1*HZ) && + if (time_after(jiffies, dev_trans_start(ndev) + 1*HZ) && dev->tx_done_idx != dev->tx_free_idx) { printk(KERN_DEBUG "%s: ns83820_tx_watch: %u %u %d\n", ndev->name, diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index 5eeb5a87b738..c254a7f5b9f5 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -1086,34 +1087,17 @@ static int pasemi_mac_phy_init(struct net_device *dev) struct pasemi_mac *mac = netdev_priv(dev); struct device_node *dn, *phy_dn; struct phy_device *phydev; - unsigned int phy_id; - const phandle *ph; - const unsigned int *prop; - struct resource r; - int ret; dn = pci_device_to_OF_node(mac->pdev); - ph = of_get_property(dn, "phy-handle", NULL); - if (!ph) - return -ENODEV; - phy_dn = of_find_node_by_phandle(*ph); - - prop = of_get_property(phy_dn, "reg", NULL); - ret = of_address_to_resource(phy_dn->parent, 0, &r); - if (ret) - goto err; - - phy_id = *prop; - snprintf(mac->phy_id, sizeof(mac->phy_id), "%x:%02x", - (int)r.start, phy_id); - + phy_dn = of_parse_phandle(dn, "phy-handle", 0); of_node_put(phy_dn); mac->link = 0; mac->speed = 0; mac->duplex = -1; - phydev = phy_connect(dev, mac->phy_id, &pasemi_adjust_link, 0, PHY_INTERFACE_MODE_SGMII); + phydev = of_phy_connect(dev, phy_dn, &pasemi_adjust_link, 0, + PHY_INTERFACE_MODE_SGMII); if (IS_ERR(phydev)) { printk(KERN_ERR "%s: Could not attach to phy\n", dev->name); @@ -1123,10 +1107,6 @@ static int pasemi_mac_phy_init(struct net_device *dev) mac->phydev = phydev; return 0; - -err: - of_node_put(phy_dn); - return -ENODEV; } @@ -1735,12 +1715,25 @@ out: return ret; } +static const struct net_device_ops pasemi_netdev_ops = { + .ndo_open = pasemi_mac_open, + .ndo_stop = pasemi_mac_close, + .ndo_start_xmit = pasemi_mac_start_tx, + .ndo_set_multicast_list = pasemi_mac_set_rx_mode, + .ndo_set_mac_address = pasemi_mac_set_mac_addr, + .ndo_change_mtu = pasemi_mac_change_mtu, + .ndo_validate_addr = eth_validate_addr, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = pasemi_mac_netpoll, +#endif +}; + static int __devinit pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct net_device *dev; struct pasemi_mac *mac; - int err; + int err, ret; err = pci_enable_device(pdev); if (err) @@ -1798,12 +1791,13 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } memcpy(dev->dev_addr, mac->mac_addr, sizeof(mac->mac_addr)); - mac->dma_if = mac_to_intf(mac); - if (mac->dma_if < 0) { + ret = mac_to_intf(mac); + if (ret < 0) { dev_err(&mac->pdev->dev, "Can't map DMA interface\n"); err = -ENODEV; goto out; } + mac->dma_if = ret; switch (pdev->device) { case 0xa005: @@ -1817,19 +1811,11 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto out; } - dev->open = pasemi_mac_open; - dev->stop = pasemi_mac_close; - dev->hard_start_xmit = pasemi_mac_start_tx; - dev->set_multicast_list = pasemi_mac_set_rx_mode; - dev->set_mac_address = pasemi_mac_set_mac_addr; + dev->netdev_ops = &pasemi_netdev_ops; dev->mtu = PE_DEF_MTU; /* 1500 MTU + ETH_HLEN + VLAN_HLEN + 2 64B cachelines */ mac->bufsz = dev->mtu + ETH_HLEN + ETH_FCS_LEN + LOCAL_SKB_ALIGN + 128; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = pasemi_mac_netpoll; -#endif - dev->change_mtu = pasemi_mac_change_mtu; dev->ethtool_ops = &pasemi_mac_ethtool_ops; if (err) diff --git a/drivers/net/pasemi_mac.h b/drivers/net/pasemi_mac.h index 1a115ec60b53..e2f4efa8ad46 100644 --- a/drivers/net/pasemi_mac.h +++ b/drivers/net/pasemi_mac.h @@ -100,7 +100,6 @@ struct pasemi_mac { int duplex; unsigned int msg_enable; - char phy_id[BUS_ID_SIZE]; }; /* Software status descriptor (ring_info) */ diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c index c95fd72c3bb9..8c1f6988f398 100644 --- a/drivers/net/pci-skeleton.c +++ b/drivers/net/pci-skeleton.c @@ -728,6 +728,17 @@ err_out: return rc; } +static const struct net_device_ops netdrv_netdev_ops = { + .ndo_open = netdrv_open, + .ndo_stop = netdrv_close, + .ndo_start_xmit = netdrv_start_xmit, + .ndo_set_multicast_list = netdrv_set_rx_mode, + .ndo_do_ioctl = netdrv_ioctl, + .ndo_tx_timeout = netdrv_tx_timeout, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, +}; static int __devinit netdrv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) @@ -769,13 +780,7 @@ static int __devinit netdrv_init_one (struct pci_dev *pdev, ((u16 *) (dev->dev_addr))[i] = le16_to_cpu (read_eeprom (ioaddr, i + 7, addr_len)); - /* The Rtl8139-specific entries in the device structure. */ - dev->open = netdrv_open; - dev->hard_start_xmit = netdrv_start_xmit; - dev->stop = netdrv_close; - dev->set_multicast_list = netdrv_set_rx_mode; - dev->do_ioctl = netdrv_ioctl; - dev->tx_timeout = netdrv_tx_timeout; + dev->netdev_ops = &netdrv_netdev_ops; dev->watchdog_timeo = TX_TIMEOUT; dev->irq = pdev->irq; diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c index 8f3872b8985d..f35c609ba020 100644 --- a/drivers/net/pcmcia/3c574_cs.c +++ b/drivers/net/pcmcia/3c574_cs.c @@ -1195,7 +1195,7 @@ static int el3_close(struct net_device *dev) static struct pcmcia_device_id tc574_ids[] = { PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0574), - PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x0556, "3CCFEM556.cis"), + PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x0556, "cis/3CCFEM556.cis"), PCMCIA_DEVICE_NULL, }; MODULE_DEVICE_TABLE(pcmcia, tc574_ids); diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c index cdf661a6092c..ec7cf5ac4f05 100644 --- a/drivers/net/pcmcia/3c589_cs.c +++ b/drivers/net/pcmcia/3c589_cs.c @@ -967,8 +967,8 @@ static struct pcmcia_device_id tc589_ids[] = { PCMCIA_MFC_DEVICE_PROD_ID1(0, "Motorola MARQUIS", 0xf03e4e77), PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0589), PCMCIA_DEVICE_PROD_ID12("Farallon", "ENet", 0x58d93fc4, 0x992c2202), - PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x0035, "3CXEM556.cis"), - PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x003d, "3CXEM556.cis"), + PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x0035, "cis/3CXEM556.cis"), + PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x003d, "cis/3CXEM556.cis"), PCMCIA_DEVICE_NULL, }; MODULE_DEVICE_TABLE(pcmcia, tc589_ids); diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index 15b8fe61695b..0e38d80fd255 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -1130,7 +1130,7 @@ static int axnet_start_xmit(struct sk_buff *skb, struct net_device *dev) outb_p(ENISR_ALL, e8390_base + EN0_IMR); spin_unlock_irqrestore(&ei_local->page_lock, flags); dev->stats.tx_errors++; - return 1; + return NETDEV_TX_BUSY; } /* diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c index 81e6660a433a..479d5b494371 100644 --- a/drivers/net/pcmcia/fmvj18x_cs.c +++ b/drivers/net/pcmcia/fmvj18x_cs.c @@ -877,7 +877,7 @@ static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev) if (length > ETH_FRAME_LEN) { printk(KERN_NOTICE "%s: Attempting to send a large packet" " (%d bytes).\n", dev->name, length); - return 1; + return NETDEV_TX_BUSY; } DEBUG(4, "%s: Transmitting a packet of length %lu.\n", diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index 48dbb35747d8..37e05d3ab893 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -1388,7 +1388,7 @@ static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_aborted_errors++; printk(KERN_DEBUG "%s: Internal error -- sent packet while busy.\n", dev->name); - return 1; + return NETDEV_TX_BUSY; } smc->saved_skb = skb; diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index a3685c0d22fc..ef37d22c7e1d 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c @@ -1399,7 +1399,7 @@ do_start_xmit(struct sk_buff *skb, struct net_device *dev) DEBUG(2 + (okay ? 2 : 0), "%s: avail. tx space=%u%s\n", dev->name, freespace, okay ? " (okay)":" (not enough)"); if (!okay) { /* not enough space */ - return 1; /* upper layer may decide to requeue this packet */ + return NETDEV_TX_BUSY; /* upper layer may decide to requeue this packet */ } /* send the packet */ PutWord(XIRCREG_EDP, (u_short)pktlen); diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 80124fac65fa..1c35e1d637a0 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -1227,7 +1227,6 @@ static void pcnet32_rx_entry(struct net_device *dev, dev->stats.rx_dropped++; return; } - skb->dev = dev; if (!rx_in_place) { skb_reserve(skb, NET_IP_ALIGN); skb_put(skb, pkt_len); /* Make room */ @@ -1406,7 +1405,7 @@ static int pcnet32_poll(struct napi_struct *napi, int budget) /* Set interrupt enable. */ lp->a.write_csr(ioaddr, CSR0, CSR0_INTEN); - mmiowb(); + spin_unlock_irqrestore(&lp->lock, flags); } return work_done; @@ -2598,7 +2597,7 @@ pcnet32_interrupt(int irq, void *dev_id) val = lp->a.read_csr(ioaddr, CSR3); val |= 0x5f00; lp->a.write_csr(ioaddr, CSR3, val); - mmiowb(); + __napi_schedule(&lp->napi); break; } diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 7a3ec9d39a9a..dd6f54d1b495 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -243,6 +243,7 @@ static int m88e1111_config_init(struct phy_device *phydev) temp &= ~(MII_M1111_HWCFG_MODE_MASK); temp |= MII_M1111_HWCFG_MODE_SGMII_NO_CLK; + temp |= MII_M1111_HWCFG_FIBER_COPPER_AUTO; err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); if (err < 0) diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index b754020cbe75..bd4e8d72dc08 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -113,7 +113,6 @@ int mdiobus_register(struct mii_bus *bus) bus->reset(bus); for (i = 0; i < PHY_MAX_ADDR; i++) { - bus->phy_map[i] = NULL; if ((bus->phy_mask & (1 << i)) == 0) { struct phy_device *phydev; @@ -150,6 +149,7 @@ void mdiobus_unregister(struct mii_bus *bus) for (i = 0; i < PHY_MAX_ADDR; i++) { if (bus->phy_map[i]) device_unregister(&bus->phy_map[i]->dev); + bus->phy_map[i] = NULL; } } EXPORT_SYMBOL(mdiobus_unregister); @@ -188,35 +188,12 @@ struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr) if (IS_ERR(phydev) || phydev == NULL) return phydev; - /* There's a PHY at this address - * We need to set: - * 1) IRQ - * 2) bus_id - * 3) parent - * 4) bus - * 5) mii_bus - * And, we need to register it */ - - phydev->irq = bus->irq != NULL ? bus->irq[addr] : PHY_POLL; - - phydev->dev.parent = bus->parent; - phydev->dev.bus = &mdio_bus_type; - dev_set_name(&phydev->dev, PHY_ID_FMT, bus->id, addr); - - phydev->bus = bus; - - /* Run all of the fixups for this PHY */ - phy_scan_fixups(phydev); - - err = device_register(&phydev->dev); + err = phy_device_register(phydev); if (err) { - printk(KERN_ERR "phy %d failed to register\n", addr); phy_device_free(phydev); - phydev = NULL; + return NULL; } - bus->phy_map[addr] = phydev; - return phydev; } EXPORT_SYMBOL(mdiobus_scan); diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 0a06e4fd37d9..eba937c46376 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -39,20 +39,21 @@ MODULE_DESCRIPTION("PHY library"); MODULE_AUTHOR("Andy Fleming"); MODULE_LICENSE("GPL"); -static struct phy_driver genphy_driver; -extern int mdio_bus_init(void); -extern void mdio_bus_exit(void); - void phy_device_free(struct phy_device *phydev) { kfree(phydev); } +EXPORT_SYMBOL(phy_device_free); static void phy_device_release(struct device *dev) { phy_device_free(to_phy_device(dev)); } +static struct phy_driver genphy_driver; +extern int mdio_bus_init(void); +extern void mdio_bus_exit(void); + static LIST_HEAD(phy_fixup_list); static DEFINE_MUTEX(phy_fixup_lock); @@ -166,6 +167,10 @@ struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id) dev->addr = addr; dev->phy_id = phy_id; dev->bus = bus; + dev->dev.parent = bus->parent; + dev->dev.bus = &mdio_bus_type; + dev->irq = bus->irq != NULL ? bus->irq[addr] : PHY_POLL; + dev_set_name(&dev->dev, PHY_ID_FMT, bus->id, addr); dev->state = PHY_DOWN; @@ -235,6 +240,38 @@ struct phy_device * get_phy_device(struct mii_bus *bus, int addr) return dev; } +EXPORT_SYMBOL(get_phy_device); + +/** + * phy_device_register - Register the phy device on the MDIO bus + * @phydev: phy_device structure to be added to the MDIO bus + */ +int phy_device_register(struct phy_device *phydev) +{ + int err; + + /* Don't register a phy if one is already registered at this + * address */ + if (phydev->bus->phy_map[phydev->addr]) + return -EINVAL; + phydev->bus->phy_map[phydev->addr] = phydev; + + /* Run all of the fixups for this PHY */ + phy_scan_fixups(phydev); + + err = device_register(&phydev->dev); + if (err) { + pr_err("phy %d failed to register\n", phydev->addr); + goto out; + } + + return 0; + + out: + phydev->bus->phy_map[phydev->addr] = NULL; + return err; +} +EXPORT_SYMBOL(phy_device_register); /** * phy_prepare_link - prepares the PHY layer to monitor link status @@ -254,6 +291,33 @@ void phy_prepare_link(struct phy_device *phydev, phydev->adjust_link = handler; } +/** + * phy_connect_direct - connect an ethernet device to a specific phy_device + * @dev: the network device to connect + * @phydev: the pointer to the phy device + * @handler: callback function for state change notifications + * @flags: PHY device's dev_flags + * @interface: PHY device's interface + */ +int phy_connect_direct(struct net_device *dev, struct phy_device *phydev, + void (*handler)(struct net_device *), u32 flags, + phy_interface_t interface) +{ + int rc; + + rc = phy_attach_direct(dev, phydev, flags, interface); + if (rc) + return rc; + + phy_prepare_link(phydev, handler); + phy_start_machine(phydev, NULL); + if (phydev->irq > 0) + phy_start_interrupts(phydev); + + return 0; +} +EXPORT_SYMBOL(phy_connect_direct); + /** * phy_connect - connect an ethernet device to a PHY device * @dev: the network device to connect @@ -275,18 +339,21 @@ struct phy_device * phy_connect(struct net_device *dev, const char *bus_id, phy_interface_t interface) { struct phy_device *phydev; + struct device *d; + int rc; - phydev = phy_attach(dev, bus_id, flags, interface); + /* Search the list of PHY devices on the mdio bus for the + * PHY with the requested name */ + d = bus_find_device_by_name(&mdio_bus_type, NULL, bus_id); + if (!d) { + pr_err("PHY %s not found\n", bus_id); + return ERR_PTR(-ENODEV); + } + phydev = to_phy_device(d); - if (IS_ERR(phydev)) - return phydev; - - phy_prepare_link(phydev, handler); - - phy_start_machine(phydev, NULL); - - if (phydev->irq > 0) - phy_start_interrupts(phydev); + rc = phy_connect_direct(dev, phydev, handler, flags, interface); + if (rc) + return ERR_PTR(rc); return phydev; } @@ -310,9 +377,9 @@ void phy_disconnect(struct phy_device *phydev) EXPORT_SYMBOL(phy_disconnect); /** - * phy_attach - attach a network device to a particular PHY device + * phy_attach_direct - attach a network device to a given PHY device pointer * @dev: network device to attach - * @bus_id: PHY device to attach + * @phydev: Pointer to phy_device to attach * @flags: PHY device's dev_flags * @interface: PHY device's interface * @@ -323,22 +390,10 @@ EXPORT_SYMBOL(phy_disconnect); * the attaching device, and given a callback for link status * change. The phy_device is returned to the attaching driver. */ -struct phy_device *phy_attach(struct net_device *dev, - const char *bus_id, u32 flags, phy_interface_t interface) +int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, + u32 flags, phy_interface_t interface) { - struct bus_type *bus = &mdio_bus_type; - struct phy_device *phydev; - struct device *d; - - /* Search the list of PHY devices on the mdio bus for the - * PHY with the requested name */ - d = bus_find_device_by_name(bus, NULL, bus_id); - if (d) { - phydev = to_phy_device(d); - } else { - printk(KERN_ERR "%s not found\n", bus_id); - return ERR_PTR(-ENODEV); - } + struct device *d = &phydev->dev; /* Assume that if there is no driver, that it doesn't * exist, and we should use the genphy driver. */ @@ -351,13 +406,12 @@ struct phy_device *phy_attach(struct net_device *dev, err = device_bind_driver(d); if (err) - return ERR_PTR(err); + return err; } if (phydev->attached_dev) { - printk(KERN_ERR "%s: %s already attached\n", - dev->name, bus_id); - return ERR_PTR(-EBUSY); + dev_err(&dev->dev, "PHY already attached\n"); + return -EBUSY; } phydev->attached_dev = dev; @@ -375,14 +429,49 @@ struct phy_device *phy_attach(struct net_device *dev, err = phy_scan_fixups(phydev); if (err < 0) - return ERR_PTR(err); + return err; err = phydev->drv->config_init(phydev); if (err < 0) - return ERR_PTR(err); + return err; } + return 0; +} +EXPORT_SYMBOL(phy_attach_direct); + +/** + * phy_attach - attach a network device to a particular PHY device + * @dev: network device to attach + * @bus_id: Bus ID of PHY device to attach + * @flags: PHY device's dev_flags + * @interface: PHY device's interface + * + * Description: Same as phy_attach_direct() except that a PHY bus_id + * string is passed instead of a pointer to a struct phy_device. + */ +struct phy_device *phy_attach(struct net_device *dev, + const char *bus_id, u32 flags, phy_interface_t interface) +{ + struct bus_type *bus = &mdio_bus_type; + struct phy_device *phydev; + struct device *d; + int rc; + + /* Search the list of PHY devices on the mdio bus for the + * PHY with the requested name */ + d = bus_find_device_by_name(bus, NULL, bus_id); + if (!d) { + pr_err("PHY %s not found\n", bus_id); + return ERR_PTR(-ENODEV); + } + phydev = to_phy_device(d); + + rc = phy_attach_direct(dev, phydev, flags, interface); + if (rc) + return ERR_PTR(rc); + return phydev; } EXPORT_SYMBOL(phy_attach); diff --git a/drivers/net/plip.c b/drivers/net/plip.c index 0be0f0b164f3..7a62f781fef2 100644 --- a/drivers/net/plip.c +++ b/drivers/net/plip.c @@ -955,12 +955,12 @@ plip_tx_packet(struct sk_buff *skb, struct net_device *dev) struct plip_local *snd = &nl->snd_data; if (netif_queue_stopped(dev)) - return 1; + return NETDEV_TX_BUSY; /* We may need to grab the bus */ if (!nl->port_owner) { if (parport_claim(nl->pardev)) - return 1; + return NETDEV_TX_BUSY; nl->port_owner = 1; } @@ -969,7 +969,7 @@ plip_tx_packet(struct sk_buff *skb, struct net_device *dev) if (skb->len > dev->mtu + dev->hard_header_len) { printk(KERN_WARNING "%s: packet too big, %d.\n", dev->name, (int)skb->len); netif_start_queue (dev); - return 1; + return NETDEV_TX_BUSY; } if (net_debug > 2) diff --git a/drivers/net/ppp_async.c b/drivers/net/ppp_async.c index 6de8399d6dd9..17c116bb332c 100644 --- a/drivers/net/ppp_async.c +++ b/drivers/net/ppp_async.c @@ -356,7 +356,6 @@ ppp_asynctty_receive(struct tty_struct *tty, const unsigned char *buf, if (!skb_queue_empty(&ap->rqueue)) tasklet_schedule(&ap->tsk); ap_put(ap); - tty_unthrottle(tty); } static void diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index 8ee91421db12..639d11bc444e 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -1054,6 +1054,7 @@ static void ppp_setup(struct net_device *dev) dev->type = ARPHRD_PPP; dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST; dev->features |= NETIF_F_NETNS_LOCAL; + dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; } /* diff --git a/drivers/net/ppp_synctty.c b/drivers/net/ppp_synctty.c index d2fa2db13586..aa3d39f38e22 100644 --- a/drivers/net/ppp_synctty.c +++ b/drivers/net/ppp_synctty.c @@ -397,7 +397,6 @@ ppp_sync_receive(struct tty_struct *tty, const unsigned char *buf, if (!skb_queue_empty(&ap->rqueue)) tasklet_schedule(&ap->tsk); sp_put(ap); - tty_unthrottle(tty); } static void diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c index 5b07dd8e5c04..e7935d09c896 100644 --- a/drivers/net/pppol2tp.c +++ b/drivers/net/pppol2tp.c @@ -433,8 +433,7 @@ static void pppol2tp_recv_dequeue_skb(struct pppol2tp_session *session, struct s * to the inner packet either */ secpath_reset(skb); - dst_release(skb->dst); - skb->dst = NULL; + skb_dst_drop(skb); nf_reset(skb); po = pppox_sk(session_sock); @@ -976,7 +975,7 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh /* Calculate UDP checksum if configured to do so */ if (sk_tun->sk_no_check == UDP_CSUM_NOXMIT) skb->ip_summed = CHECKSUM_NONE; - else if (!(skb->dst->dev->features & NETIF_F_V4_CSUM)) { + else if (!(skb_dst(skb)->dev->features & NETIF_F_V4_CSUM)) { skb->ip_summed = CHECKSUM_COMPLETE; csum = skb_checksum(skb, 0, udp_len, 0); uh->check = csum_tcpudp_magic(inet->saddr, inet->daddr, @@ -1172,14 +1171,14 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) nf_reset(skb); /* Get routing info from the tunnel socket */ - dst_release(skb->dst); - skb->dst = dst_clone(__sk_dst_get(sk_tun)); + skb_dst_drop(skb); + skb_dst_set(skb, dst_clone(__sk_dst_get(sk_tun))); pppol2tp_skb_set_owner_w(skb, sk_tun); /* Calculate UDP checksum if configured to do so */ if (sk_tun->sk_no_check == UDP_CSUM_NOXMIT) skb->ip_summed = CHECKSUM_NONE; - else if (!(skb->dst->dev->features & NETIF_F_V4_CSUM)) { + else if (!(skb_dst(skb)->dev->features & NETIF_F_V4_CSUM)) { skb->ip_summed = CHECKSUM_COMPLETE; csum = skb_checksum(skb, 0, udp_len, 0); uh->check = csum_tcpudp_magic(inet->saddr, inet->daddr, @@ -1238,8 +1237,7 @@ static void pppol2tp_tunnel_closeall(struct pppol2tp_tunnel *tunnel) struct pppol2tp_session *session; struct sock *sk; - if (tunnel == NULL) - BUG(); + BUG_ON(tunnel == NULL); PRINTK(tunnel->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, "%s: closing all sessions...\n", tunnel->name); diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c index 30900b30d532..d1a5fb4d6acb 100644 --- a/drivers/net/ps3_gelic_net.c +++ b/drivers/net/ps3_gelic_net.c @@ -214,9 +214,10 @@ static void gelic_card_free_chain(struct gelic_card *card, * * returns 0 on success, <0 on failure */ -static int gelic_card_init_chain(struct gelic_card *card, - struct gelic_descr_chain *chain, - struct gelic_descr *start_descr, int no) +static int __devinit gelic_card_init_chain(struct gelic_card *card, + struct gelic_descr_chain *chain, + struct gelic_descr *start_descr, + int no) { int i; struct gelic_descr *descr; @@ -407,7 +408,7 @@ rewind: * * returns 0 on success, < 0 on failure */ -static int gelic_card_alloc_rx_skbs(struct gelic_card *card) +static int __devinit gelic_card_alloc_rx_skbs(struct gelic_card *card) { struct gelic_descr_chain *chain; int ret; @@ -1422,8 +1423,8 @@ static const struct net_device_ops gelic_netdevice_ops = { * * fills out function pointers in the net_device structure */ -static void gelic_ether_setup_netdev_ops(struct net_device *netdev, - struct napi_struct *napi) +static void __devinit gelic_ether_setup_netdev_ops(struct net_device *netdev, + struct napi_struct *napi) { netdev->watchdog_timeo = GELIC_NET_WATCHDOG_TIMEOUT; /* NAPI */ @@ -1443,7 +1444,8 @@ static void gelic_ether_setup_netdev_ops(struct net_device *netdev, * gelic_ether_setup_netdev initializes the net_device structure * and register it. **/ -int gelic_net_setup_netdev(struct net_device *netdev, struct gelic_card *card) +int __devinit gelic_net_setup_netdev(struct net_device *netdev, + struct gelic_card *card) { int status; u64 v1, v2; @@ -1491,7 +1493,7 @@ int gelic_net_setup_netdev(struct net_device *netdev, struct gelic_card *card) * the card and net_device structures are linked to each other */ #define GELIC_ALIGN (32) -static struct gelic_card *gelic_alloc_card_net(struct net_device **netdev) +static struct gelic_card * __devinit gelic_alloc_card_net(struct net_device **netdev) { struct gelic_card *card; struct gelic_port *port; @@ -1542,7 +1544,7 @@ static struct gelic_card *gelic_alloc_card_net(struct net_device **netdev) return card; } -static void gelic_card_get_vlan_info(struct gelic_card *card) +static void __devinit gelic_card_get_vlan_info(struct gelic_card *card) { u64 v1, v2; int status; @@ -1616,7 +1618,7 @@ static void gelic_card_get_vlan_info(struct gelic_card *card) /** * ps3_gelic_driver_probe - add a device to the control of this driver */ -static int ps3_gelic_driver_probe(struct ps3_system_bus_device *dev) +static int __devinit ps3_gelic_driver_probe(struct ps3_system_bus_device *dev) { struct gelic_card *card; struct net_device *netdev; @@ -1648,7 +1650,7 @@ static int ps3_gelic_driver_probe(struct ps3_system_bus_device *dev) result = -ENOMEM; goto fail_alloc_card; } - ps3_system_bus_set_driver_data(dev, card); + ps3_system_bus_set_drvdata(dev, card); card->dev = dev; /* get internal vlan info */ @@ -1749,7 +1751,7 @@ fail_alloc_irq: bus_id(card), 0, 0); fail_status_indicator: - ps3_system_bus_set_driver_data(dev, NULL); + ps3_system_bus_set_drvdata(dev, NULL); kfree(netdev_card(netdev)->unalign); free_netdev(netdev); fail_alloc_card: @@ -1766,7 +1768,7 @@ fail_open: static int ps3_gelic_driver_remove(struct ps3_system_bus_device *dev) { - struct gelic_card *card = ps3_system_bus_get_driver_data(dev); + struct gelic_card *card = ps3_system_bus_get_drvdata(dev); struct net_device *netdev0; pr_debug("%s: called\n", __func__); @@ -1803,7 +1805,7 @@ static int ps3_gelic_driver_remove(struct ps3_system_bus_device *dev) kfree(netdev_card(netdev0)->unalign); free_netdev(netdev0); - ps3_system_bus_set_driver_data(dev, NULL); + ps3_system_bus_set_drvdata(dev, NULL); ps3_dma_region_free(dev->d_region); diff --git a/drivers/net/ps3_gelic_wireless.c b/drivers/net/ps3_gelic_wireless.c index 4f3ada622f9b..b6b3ca9bdb21 100644 --- a/drivers/net/ps3_gelic_wireless.c +++ b/drivers/net/ps3_gelic_wireless.c @@ -2442,7 +2442,7 @@ static const struct iw_handler_def gelic_wl_wext_handler_def = { #endif }; -static struct net_device *gelic_wl_alloc(struct gelic_card *card) +static struct net_device * __devinit gelic_wl_alloc(struct gelic_card *card) { struct net_device *netdev; struct gelic_port *port; @@ -2722,7 +2722,7 @@ static struct ethtool_ops gelic_wl_ethtool_ops = { .set_rx_csum = gelic_net_set_rx_csum, }; -static void gelic_wl_setup_netdev_ops(struct net_device *netdev) +static void __devinit gelic_wl_setup_netdev_ops(struct net_device *netdev) { struct gelic_wl_info *wl; wl = port_wl(netdev_priv(netdev)); @@ -2738,7 +2738,7 @@ static void gelic_wl_setup_netdev_ops(struct net_device *netdev) /* * driver probe/remove */ -int gelic_wl_driver_probe(struct gelic_card *card) +int __devinit gelic_wl_driver_probe(struct gelic_card *card) { int ret; struct net_device *netdev; diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c index cadc32c94c1e..3e4b67aaa6ea 100644 --- a/drivers/net/qla3xxx.c +++ b/drivers/net/qla3xxx.c @@ -2617,7 +2617,6 @@ static int ql3xxx_send(struct sk_buff *skb, struct net_device *ndev) &port_regs->CommonRegs.reqQProducerIndex, qdev->req_producer_index); - ndev->trans_start = jiffies; if (netif_msg_tx_queued(qdev)) printk(KERN_DEBUG PFX "%s: tx queued, slot %d, len %d\n", ndev->name, qdev->req_producer_index, skb->len); @@ -3143,6 +3142,7 @@ static int ql_adapter_initialize(struct ql3_adapter *qdev) (void __iomem *)port_regs; u32 delay = 10; int status = 0; + unsigned long hw_flags = 0; if(ql_mii_setup(qdev)) return -1; @@ -3151,7 +3151,8 @@ static int ql_adapter_initialize(struct ql3_adapter *qdev) ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg, (ISP_SERIAL_PORT_IF_WE | (ISP_SERIAL_PORT_IF_WE << 16))); - + /* Give the PHY time to come out of reset. */ + mdelay(100); qdev->port_link_state = LS_DOWN; netif_carrier_off(qdev->ndev); @@ -3351,7 +3352,9 @@ static int ql_adapter_initialize(struct ql3_adapter *qdev) value = ql_read_page0_reg(qdev, &port_regs->portStatus); if (value & PORT_STATUS_IC) break; + spin_unlock_irqrestore(&qdev->hw_lock, hw_flags); msleep(500); + spin_lock_irqsave(&qdev->hw_lock, hw_flags); } while (--delay); if (delay == 0) { @@ -3838,7 +3841,9 @@ static void ql_reset_work(struct work_struct *work) 16) | ISP_CONTROL_RI)); } + spin_unlock_irqrestore(&qdev->hw_lock, hw_flags); ssleep(1); + spin_lock_irqsave(&qdev->hw_lock, hw_flags); } while (--max_wait_time); spin_unlock_irqrestore(&qdev->hw_lock, hw_flags); diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h index fcb159e4df54..156e02e8905d 100644 --- a/drivers/net/qlge/qlge.h +++ b/drivers/net/qlge/qlge.h @@ -27,6 +27,8 @@ "%s: " fmt, __func__, ##args); \ } while (0) +#define WQ_ADDR_ALIGN 0x3 /* 4 byte alignment */ + #define QLGE_VENDOR_ID 0x1077 #define QLGE_DEVICE_ID_8012 0x8012 #define QLGE_DEVICE_ID_8000 0x8000 @@ -39,7 +41,18 @@ #define NUM_SMALL_BUFFERS 512 #define NUM_LARGE_BUFFERS 512 +#define DB_PAGE_SIZE 4096 +/* Calculate the number of (4k) pages required to + * contain a buffer queue of the given length. + */ +#define MAX_DB_PAGES_PER_BQ(x) \ + (((x * sizeof(u64)) / DB_PAGE_SIZE) + \ + (((x * sizeof(u64)) % DB_PAGE_SIZE) ? 1 : 0)) + +#define RX_RING_SHADOW_SPACE (sizeof(u64) + \ + MAX_DB_PAGES_PER_BQ(NUM_SMALL_BUFFERS) * sizeof(u64) + \ + MAX_DB_PAGES_PER_BQ(NUM_LARGE_BUFFERS) * sizeof(u64)) #define SMALL_BUFFER_SIZE 256 #define LARGE_BUFFER_SIZE PAGE_SIZE #define MAX_SPLIT_SIZE 1023 @@ -50,7 +63,7 @@ #define MAX_INTER_FRAME_WAIT 10 /* 10 usec max interframe-wait for coalescing */ #define DFLT_INTER_FRAME_WAIT (MAX_INTER_FRAME_WAIT/2) #define UDELAY_COUNT 3 -#define UDELAY_DELAY 10 +#define UDELAY_DELAY 100 #define TX_DESC_PER_IOCB 8 @@ -63,7 +76,16 @@ #define TX_DESC_PER_OAL 0 #endif -#define DB_PAGE_SIZE 4096 +/* MPI test register definitions. This register + * is used for determining alternate NIC function's + * PCI->func number. + */ +enum { + MPI_TEST_FUNC_PORT_CFG = 0x1002, + MPI_TEST_NIC1_FUNC_SHIFT = 1, + MPI_TEST_NIC2_FUNC_SHIFT = 5, + MPI_TEST_NIC_FUNC_MASK = 0x00000007, +}; /* * Processor Address Register (PROC_ADDR) bit definitions. @@ -1430,7 +1452,10 @@ struct ql_adapter { /* Hardware information */ u32 chip_rev_id; + u32 fw_rev_id; u32 func; /* PCI function for this adapter */ + u32 alt_func; /* PCI function for alternate adapter */ + u32 port; /* Port number this adapter */ spinlock_t adapter_lock; spinlock_t hw_lock; @@ -1580,6 +1605,8 @@ void ql_mpi_idc_work(struct work_struct *work); void ql_mpi_port_cfg_work(struct work_struct *work); int ql_mb_get_fw_state(struct ql_adapter *qdev); int ql_cam_route_initialize(struct ql_adapter *qdev); +int ql_read_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 *data); +int ql_mb_about_fw(struct ql_adapter *qdev); #if 1 #define QL_ALL_DUMP diff --git a/drivers/net/qlge/qlge_ethtool.c b/drivers/net/qlge/qlge_ethtool.c index 913b2a5fafc9..37c99fe79770 100644 --- a/drivers/net/qlge/qlge_ethtool.c +++ b/drivers/net/qlge/qlge_ethtool.c @@ -293,7 +293,10 @@ static void ql_get_drvinfo(struct net_device *ndev, struct ql_adapter *qdev = netdev_priv(ndev); strncpy(drvinfo->driver, qlge_driver_name, 32); strncpy(drvinfo->version, qlge_driver_version, 32); - strncpy(drvinfo->fw_version, "N/A", 32); + snprintf(drvinfo->fw_version, 32, "v%d.%d.%d", + (qdev->fw_rev_id & 0x00ff0000) >> 16, + (qdev->fw_rev_id & 0x0000ff00) >> 8, + (qdev->fw_rev_id & 0x000000ff)); strncpy(drvinfo->bus_info, pci_name(qdev->pdev), 32); drvinfo->n_stats = 0; drvinfo->testinfo_len = 0; @@ -401,6 +404,7 @@ const struct ethtool_ops qlge_ethtool_ops = { .get_rx_csum = ql_get_rx_csum, .set_rx_csum = ql_set_rx_csum, .get_tx_csum = ethtool_op_get_tx_csum, + .set_tx_csum = ethtool_op_set_tx_csum, .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, .get_tso = ethtool_op_get_tso, diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index c92ced247947..90d1f76c0e8b 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -675,11 +675,12 @@ static int ql_get_8000_flash_params(struct ql_adapter *qdev) int status; __le32 *p = (__le32 *)&qdev->flash; u32 offset; + u8 mac_addr[6]; /* Get flash offset for function and adjust * for dword access. */ - if (!qdev->func) + if (!qdev->port) offset = FUNC0_FLASH_OFFSET / sizeof(u32); else offset = FUNC1_FLASH_OFFSET / sizeof(u32); @@ -705,14 +706,26 @@ static int ql_get_8000_flash_params(struct ql_adapter *qdev) goto exit; } - if (!is_valid_ether_addr(qdev->flash.flash_params_8000.mac_addr)) { + /* Extract either manufacturer or BOFM modified + * MAC address. + */ + if (qdev->flash.flash_params_8000.data_type1 == 2) + memcpy(mac_addr, + qdev->flash.flash_params_8000.mac_addr1, + qdev->ndev->addr_len); + else + memcpy(mac_addr, + qdev->flash.flash_params_8000.mac_addr, + qdev->ndev->addr_len); + + if (!is_valid_ether_addr(mac_addr)) { QPRINTK(qdev, IFUP, ERR, "Invalid MAC address.\n"); status = -EINVAL; goto exit; } memcpy(qdev->ndev->dev_addr, - qdev->flash.flash_params_8000.mac_addr, + mac_addr, qdev->ndev->addr_len); exit: @@ -731,7 +744,7 @@ static int ql_get_8012_flash_params(struct ql_adapter *qdev) /* Second function's parameters follow the first * function's. */ - if (qdev->func) + if (qdev->port) offset = size; if (ql_sem_spinlock(qdev, SEM_FLASH_MASK)) @@ -837,6 +850,13 @@ exit: static int ql_8000_port_initialize(struct ql_adapter *qdev) { int status; + /* + * Get MPI firmware version for driver banner + * and ethool info. + */ + status = ql_mb_about_fw(qdev); + if (status) + goto exit; status = ql_mb_get_fw_state(qdev); if (status) goto exit; @@ -1518,6 +1538,22 @@ static void ql_process_mac_rx_intr(struct ql_adapter *qdev, return; } + /* Frame error, so drop the packet. */ + if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) { + QPRINTK(qdev, DRV, ERR, "Receive error, flags2 = 0x%x\n", + ib_mac_rsp->flags2); + dev_kfree_skb_any(skb); + return; + } + + /* The max framesize filter on this chip is set higher than + * MTU since FCoE uses 2k frames. + */ + if (skb->len > ndev->mtu + ETH_HLEN) { + dev_kfree_skb_any(skb); + return; + } + prefetch(skb->data); skb->dev = ndev; if (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) { @@ -1540,7 +1576,6 @@ static void ql_process_mac_rx_intr(struct ql_adapter *qdev, * csum or frame errors. */ if (qdev->rx_csum && - !(ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) && !(ib_mac_rsp->flags1 & IB_MAC_CSUM_ERR_MASK)) { /* TCP frame. */ if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_T) { @@ -2108,7 +2143,6 @@ static int qlge_send(struct sk_buff *skb, struct net_device *ndev) wmb(); ql_write_db_reg(tx_ring->prod_idx, tx_ring->prod_idx_db_reg); - ndev->trans_start = jiffies; QPRINTK(qdev, TX_QUEUED, DEBUG, "tx queued, slot %d, len %d\n", tx_ring->prod_idx, skb->len); @@ -2203,7 +2237,7 @@ static int ql_alloc_tx_resources(struct ql_adapter *qdev, &tx_ring->wq_base_dma); if ((tx_ring->wq_base == NULL) - || tx_ring->wq_base_dma & (tx_ring->wq_size - 1)) { + || tx_ring->wq_base_dma & WQ_ADDR_ALIGN) { QPRINTK(qdev, IFUP, ERR, "tx_ring alloc failed.\n"); return -ENOMEM; } @@ -2518,14 +2552,16 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring) { struct cqicb *cqicb = &rx_ring->cqicb; void *shadow_reg = qdev->rx_ring_shadow_reg_area + - (rx_ring->cq_id * sizeof(u64) * 4); + (rx_ring->cq_id * RX_RING_SHADOW_SPACE); u64 shadow_reg_dma = qdev->rx_ring_shadow_reg_dma + - (rx_ring->cq_id * sizeof(u64) * 4); + (rx_ring->cq_id * RX_RING_SHADOW_SPACE); void __iomem *doorbell_area = qdev->doorbell_area + (DB_PAGE_SIZE * (128 + rx_ring->cq_id)); int err = 0; u16 bq_len; u64 tmp; + __le64 *base_indirect_ptr; + int page_entries; /* Set up the shadow registers for this ring. */ rx_ring->prod_idx_sh_reg = shadow_reg; @@ -2534,8 +2570,8 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring) shadow_reg_dma += sizeof(u64); rx_ring->lbq_base_indirect = shadow_reg; rx_ring->lbq_base_indirect_dma = shadow_reg_dma; - shadow_reg += sizeof(u64); - shadow_reg_dma += sizeof(u64); + shadow_reg += (sizeof(u64) * MAX_DB_PAGES_PER_BQ(rx_ring->lbq_len)); + shadow_reg_dma += (sizeof(u64) * MAX_DB_PAGES_PER_BQ(rx_ring->lbq_len)); rx_ring->sbq_base_indirect = shadow_reg; rx_ring->sbq_base_indirect_dma = shadow_reg_dma; @@ -2572,7 +2608,14 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring) if (rx_ring->lbq_len) { cqicb->flags |= FLAGS_LL; /* Load lbq values */ tmp = (u64)rx_ring->lbq_base_dma;; - *((__le64 *) rx_ring->lbq_base_indirect) = cpu_to_le64(tmp); + base_indirect_ptr = (__le64 *) rx_ring->lbq_base_indirect; + page_entries = 0; + do { + *base_indirect_ptr = cpu_to_le64(tmp); + tmp += DB_PAGE_SIZE; + base_indirect_ptr++; + page_entries++; + } while (page_entries < MAX_DB_PAGES_PER_BQ(rx_ring->lbq_len)); cqicb->lbq_addr = cpu_to_le64(rx_ring->lbq_base_indirect_dma); bq_len = (rx_ring->lbq_buf_size == 65536) ? 0 : @@ -2589,7 +2632,14 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring) if (rx_ring->sbq_len) { cqicb->flags |= FLAGS_LS; /* Load sbq values */ tmp = (u64)rx_ring->sbq_base_dma;; - *((__le64 *) rx_ring->sbq_base_indirect) = cpu_to_le64(tmp); + base_indirect_ptr = (__le64 *) rx_ring->sbq_base_indirect; + page_entries = 0; + do { + *base_indirect_ptr = cpu_to_le64(tmp); + tmp += DB_PAGE_SIZE; + base_indirect_ptr++; + page_entries++; + } while (page_entries < MAX_DB_PAGES_PER_BQ(rx_ring->sbq_len)); cqicb->sbq_addr = cpu_to_le64(rx_ring->sbq_base_indirect_dma); cqicb->sbq_buf_size = @@ -3174,7 +3224,7 @@ static int ql_adapter_reset(struct ql_adapter *qdev) if (value & RST_FO_FR) { QPRINTK(qdev, IFDOWN, ERR, - "ETIMEOUT!!! errored out of resetting the chip!\n"); + "ETIMEDOUT!!! errored out of resetting the chip!\n"); status = -ETIMEDOUT; } @@ -3186,9 +3236,10 @@ static void ql_display_dev_info(struct net_device *ndev) struct ql_adapter *qdev = (struct ql_adapter *)netdev_priv(ndev); QPRINTK(qdev, PROBE, INFO, - "Function #%d, NIC Roll %d, NIC Rev = %d, " + "Function #%d, Port %d, NIC Roll %d, NIC Rev = %d, " "XG Roll = %d, XG Rev = %d.\n", qdev->func, + qdev->port, qdev->chip_rev_id & 0x0000000f, qdev->chip_rev_id >> 4 & 0x0000000f, qdev->chip_rev_id >> 8 & 0x0000000f, @@ -3264,7 +3315,6 @@ static int ql_adapter_up(struct ql_adapter *qdev) err = ql_adapter_initialize(qdev); if (err) { QPRINTK(qdev, IFUP, INFO, "Unable to initialize adapter.\n"); - spin_unlock(&qdev->hw_lock); goto err_init; } set_bit(QL_ADAPTER_UP, &qdev->flags); @@ -3361,7 +3411,6 @@ static int ql_configure_rings(struct ql_adapter *qdev) * completion handler rx_rings. */ qdev->rx_ring_count = qdev->tx_ring_count + qdev->rss_ring_count + 1; - netif_set_gso_max_size(qdev->ndev, 65536); for (i = 0; i < qdev->tx_ring_count; i++) { tx_ring = &qdev->tx_ring[i]; @@ -3644,12 +3693,53 @@ static struct nic_operations qla8000_nic_ops = { .port_initialize = ql_8000_port_initialize, }; - -static void ql_get_board_info(struct ql_adapter *qdev) +/* Find the pcie function number for the other NIC + * on this chip. Since both NIC functions share a + * common firmware we have the lowest enabled function + * do any common work. Examples would be resetting + * after a fatal firmware error, or doing a firmware + * coredump. + */ +static int ql_get_alt_pcie_func(struct ql_adapter *qdev) { + int status = 0; + u32 temp; + u32 nic_func1, nic_func2; + + status = ql_read_mpi_reg(qdev, MPI_TEST_FUNC_PORT_CFG, + &temp); + if (status) + return status; + + nic_func1 = ((temp >> MPI_TEST_NIC1_FUNC_SHIFT) & + MPI_TEST_NIC_FUNC_MASK); + nic_func2 = ((temp >> MPI_TEST_NIC2_FUNC_SHIFT) & + MPI_TEST_NIC_FUNC_MASK); + + if (qdev->func == nic_func1) + qdev->alt_func = nic_func2; + else if (qdev->func == nic_func2) + qdev->alt_func = nic_func1; + else + status = -EIO; + + return status; +} + +static int ql_get_board_info(struct ql_adapter *qdev) +{ + int status; qdev->func = (ql_read32(qdev, STS) & STS_FUNC_ID_MASK) >> STS_FUNC_ID_SHIFT; - if (qdev->func) { + if (qdev->func > 3) + return -EIO; + + status = ql_get_alt_pcie_func(qdev); + if (status) + return status; + + qdev->port = (qdev->func < qdev->alt_func) ? 0 : 1; + if (qdev->port) { qdev->xg_sem_mask = SEM_XGMAC1_MASK; qdev->port_link_up = STS_PL1; qdev->port_init = STS_PI1; @@ -3668,6 +3758,7 @@ static void ql_get_board_info(struct ql_adapter *qdev) qdev->nic_ops = &qla8012_nic_ops; else if (qdev->device_id == QLGE_DEVICE_ID_8000) qdev->nic_ops = &qla8000_nic_ops; + return status; } static void ql_release_all(struct pci_dev *pdev) @@ -3762,7 +3853,12 @@ static int __devinit ql_init_device(struct pci_dev *pdev, qdev->ndev = ndev; qdev->pdev = pdev; - ql_get_board_info(qdev); + err = ql_get_board_info(qdev); + if (err) { + dev_err(&pdev->dev, "Register access failed.\n"); + err = -EIO; + goto err_out; + } qdev->msg_enable = netif_msg_init(debug, default_msg); spin_lock_init(&qdev->hw_lock); spin_lock_init(&qdev->stats_lock); diff --git a/drivers/net/qlge/qlge_mpi.c b/drivers/net/qlge/qlge_mpi.c index 9f81b797f10b..71afbf8b9c50 100644 --- a/drivers/net/qlge/qlge_mpi.c +++ b/drivers/net/qlge/qlge_mpi.c @@ -90,14 +90,14 @@ static int ql_get_mb_sts(struct ql_adapter *qdev, struct mbox_params *mbcp) */ static int ql_wait_mbx_cmd_cmplt(struct ql_adapter *qdev) { - int count = 50; /* TODO: arbitrary for now. */ + int count = 100; u32 value; do { value = ql_read32(qdev, STS); if (value & STS_PI) return 0; - udelay(UDELAY_DELAY); /* 10us */ + mdelay(UDELAY_DELAY); /* 100ms */ } while (--count); return -ETIMEDOUT; } @@ -141,7 +141,7 @@ end: /* We are being asked by firmware to accept * a change to the port. This is only * a change to max frame sizes (Tx/Rx), pause - * paramters, or loopback mode. We wake up a worker + * parameters, or loopback mode. We wake up a worker * to handler processing this since a mailbox command * will need to be sent to ACK the request. */ @@ -371,7 +371,7 @@ static int ql_mpi_handler(struct ql_adapter *qdev, struct mbox_params *mbcp) /* We are being asked by firmware to accept * a change to the port. This is only * a change to max frame sizes (Tx/Rx), pause - * paramters, or loopback mode. + * parameters, or loopback mode. */ case AEN_IDC_REQ: status = ql_idc_req_aen(qdev); @@ -380,7 +380,7 @@ static int ql_mpi_handler(struct ql_adapter *qdev, struct mbox_params *mbcp) /* Process and inbound IDC event. * This will happen when we're trying to * change tx/rx max frame size, change pause - * paramters or loopback mode. + * parameters or loopback mode. */ case AEN_IDC_CMPLT: case AEN_IDC_EXT: @@ -453,6 +453,13 @@ static int ql_mpi_handler(struct ql_adapter *qdev, struct mbox_params *mbcp) } end: ql_write32(qdev, CSR, CSR_CMD_CLR_R2PCI_INT); + /* Restore the original mailbox count to + * what the caller asked for. This can get + * changed when a mailbox command is waiting + * for a response and an AEN arrives and + * is handled. + * */ + mbcp->out_count = orig_count; return status; } @@ -540,6 +547,40 @@ end: return status; } + +/* Get MPI firmware version. This will be used for + * driver banner and for ethtool info. + * Returns zero on success. + */ +int ql_mb_about_fw(struct ql_adapter *qdev) +{ + struct mbox_params mbc; + struct mbox_params *mbcp = &mbc; + int status = 0; + + memset(mbcp, 0, sizeof(struct mbox_params)); + + mbcp->in_count = 1; + mbcp->out_count = 3; + + mbcp->mbox_in[0] = MB_CMD_ABOUT_FW; + + status = ql_mailbox_command(qdev, mbcp); + if (status) + return status; + + if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) { + QPRINTK(qdev, DRV, ERR, + "Failed about firmware command\n"); + status = -EIO; + } + + /* Store the firmware version */ + qdev->fw_rev_id = mbcp->mbox_out[1]; + + return status; +} + /* Get functional state for MPI firmware. * Returns zero on success. */ @@ -754,7 +795,6 @@ void ql_mpi_port_cfg_work(struct work_struct *work) { struct ql_adapter *qdev = container_of(work, struct ql_adapter, mpi_port_cfg_work.work); - struct net_device *ndev = qdev->ndev; int status; status = ql_mb_get_port_cfg(qdev); @@ -764,9 +804,7 @@ void ql_mpi_port_cfg_work(struct work_struct *work) goto err; } - if (ndev->mtu <= 2500) - goto end; - else if (qdev->link_config & CFG_JUMBO_FRAME_SIZE && + if (qdev->link_config & CFG_JUMBO_FRAME_SIZE && qdev->max_frame_size == CFG_DEFAULT_MAX_FRAME_SIZE) goto end; @@ -831,13 +869,19 @@ void ql_mpi_work(struct work_struct *work) container_of(work, struct ql_adapter, mpi_work.work); struct mbox_params mbc; struct mbox_params *mbcp = &mbc; + int err = 0; mutex_lock(&qdev->mpi_mutex); while (ql_read32(qdev, STS) & STS_PI) { memset(mbcp, 0, sizeof(struct mbox_params)); mbcp->out_count = 1; - ql_mpi_handler(qdev, mbcp); + /* Don't continue if an async event + * did not complete properly. + */ + err = ql_mpi_handler(qdev, mbcp); + if (err) + break; } mutex_unlock(&qdev->mpi_mutex); diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c index 6f97b47d74a6..ed63d23a6452 100644 --- a/drivers/net/r6040.c +++ b/drivers/net/r6040.c @@ -49,8 +49,8 @@ #include #define DRV_NAME "r6040" -#define DRV_VERSION "0.22" -#define DRV_RELDATE "25Mar2009" +#define DRV_VERSION "0.23" +#define DRV_RELDATE "05May2009" /* PHY CHIP Address */ #define PHY1_ADDR 1 /* For MAC1 */ @@ -401,6 +401,9 @@ static void r6040_init_mac_regs(struct net_device *dev) * we may got called by r6040_tx_timeout which has left * some unsent tx buffers */ iowrite16(0x01, ioaddr + MTPR); + + /* Check media */ + mii_check_media(&lp->mii_if, 1, 1); } static void r6040_tx_timeout(struct net_device *dev) @@ -528,6 +531,8 @@ static int r6040_phy_mode_chk(struct net_device *dev) phy_dat = 0x0000; } + mii_check_media(&lp->mii_if, 0, 1); + return phy_dat; }; @@ -742,6 +747,14 @@ static int r6040_up(struct net_device *dev) struct r6040_private *lp = netdev_priv(dev); void __iomem *ioaddr = lp->base; int ret; + u16 val; + + /* Check presence of a second PHY */ + val = r6040_phy_read(ioaddr, lp->phy_addr, 2); + if (val == 0xFFFF) { + printk(KERN_ERR DRV_NAME " no second PHY attached\n"); + return -EIO; + } /* Initialise and alloc RX/TX buffers */ r6040_init_txbufs(dev); @@ -802,7 +815,6 @@ static void r6040_timer(unsigned long data) lp->phy_mode = phy_mode; lp->mcr0 = (lp->mcr0 & 0x7fff) | phy_mode; iowrite16(lp->mcr0, ioaddr); - printk(KERN_INFO "Link Change %x \n", ioread16(ioaddr)); } /* Timer active again */ diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 3b19e0ce290f..4b53b58d75fc 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -51,9 +51,6 @@ #define TX_BUFFS_AVAIL(tp) \ (tp->dirty_tx + NUM_TX_DESC - tp->cur_tx - 1) -/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ -static const int max_interrupt_work = 20; - /* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). The RTL chips use a 64 element hash table based on the Ethernet CRC. */ static const int multicast_filter_limit = 32; @@ -93,6 +90,7 @@ static const int multicast_filter_limit = 32; #define RTL_R32(reg) ((unsigned long) readl (ioaddr + (reg))) enum mac_version { + RTL_GIGA_MAC_NONE = 0x00, RTL_GIGA_MAC_VER_01 = 0x01, // 8169 RTL_GIGA_MAC_VER_02 = 0x02, // 8169S RTL_GIGA_MAC_VER_03 = 0x03, // 8110S @@ -478,7 +476,6 @@ struct rtl8169_private { u16 intr_event; u16 napi_event; u16 intr_mask; - int phy_auto_nego_reg; int phy_1000_ctrl_reg; #ifdef CONFIG_R8169_VLAN struct vlan_group *vlgrp; @@ -843,76 +840,81 @@ static int rtl8169_set_speed_xmii(struct net_device *dev, { struct rtl8169_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->mmio_addr; - int auto_nego, giga_ctrl; - - auto_nego = mdio_read(ioaddr, MII_ADVERTISE); - auto_nego &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL | - ADVERTISE_100HALF | ADVERTISE_100FULL); - giga_ctrl = mdio_read(ioaddr, MII_CTRL1000); - giga_ctrl &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF); + int giga_ctrl, bmcr; if (autoneg == AUTONEG_ENABLE) { + int auto_nego; + + auto_nego = mdio_read(ioaddr, MII_ADVERTISE); auto_nego |= (ADVERTISE_10HALF | ADVERTISE_10FULL | ADVERTISE_100HALF | ADVERTISE_100FULL); - giga_ctrl |= ADVERTISE_1000FULL | ADVERTISE_1000HALF; - } else { - if (speed == SPEED_10) - auto_nego |= ADVERTISE_10HALF | ADVERTISE_10FULL; - else if (speed == SPEED_100) - auto_nego |= ADVERTISE_100HALF | ADVERTISE_100FULL; - else if (speed == SPEED_1000) + auto_nego |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; + + giga_ctrl = mdio_read(ioaddr, MII_CTRL1000); + giga_ctrl &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF); + + /* The 8100e/8101e/8102e do Fast Ethernet only. */ + if ((tp->mac_version != RTL_GIGA_MAC_VER_07) && + (tp->mac_version != RTL_GIGA_MAC_VER_08) && + (tp->mac_version != RTL_GIGA_MAC_VER_09) && + (tp->mac_version != RTL_GIGA_MAC_VER_10) && + (tp->mac_version != RTL_GIGA_MAC_VER_13) && + (tp->mac_version != RTL_GIGA_MAC_VER_14) && + (tp->mac_version != RTL_GIGA_MAC_VER_15) && + (tp->mac_version != RTL_GIGA_MAC_VER_16)) { giga_ctrl |= ADVERTISE_1000FULL | ADVERTISE_1000HALF; - - if (duplex == DUPLEX_HALF) - auto_nego &= ~(ADVERTISE_10FULL | ADVERTISE_100FULL); - - if (duplex == DUPLEX_FULL) - auto_nego &= ~(ADVERTISE_10HALF | ADVERTISE_100HALF); - - /* This tweak comes straight from Realtek's driver. */ - if ((speed == SPEED_100) && (duplex == DUPLEX_HALF) && - ((tp->mac_version == RTL_GIGA_MAC_VER_13) || - (tp->mac_version == RTL_GIGA_MAC_VER_16))) { - auto_nego = ADVERTISE_100HALF | ADVERTISE_CSMA; - } - } - - /* The 8100e/8101e/8102e do Fast Ethernet only. */ - if ((tp->mac_version == RTL_GIGA_MAC_VER_07) || - (tp->mac_version == RTL_GIGA_MAC_VER_08) || - (tp->mac_version == RTL_GIGA_MAC_VER_09) || - (tp->mac_version == RTL_GIGA_MAC_VER_10) || - (tp->mac_version == RTL_GIGA_MAC_VER_13) || - (tp->mac_version == RTL_GIGA_MAC_VER_14) || - (tp->mac_version == RTL_GIGA_MAC_VER_15) || - (tp->mac_version == RTL_GIGA_MAC_VER_16)) { - if ((giga_ctrl & (ADVERTISE_1000FULL | ADVERTISE_1000HALF)) && - netif_msg_link(tp)) { + } else if (netif_msg_link(tp)) { printk(KERN_INFO "%s: PHY does not support 1000Mbps.\n", dev->name); } - giga_ctrl &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF); - } - auto_nego |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; + bmcr = BMCR_ANENABLE | BMCR_ANRESTART; + + if ((tp->mac_version == RTL_GIGA_MAC_VER_11) || + (tp->mac_version == RTL_GIGA_MAC_VER_12) || + (tp->mac_version >= RTL_GIGA_MAC_VER_17)) { + /* + * Wake up the PHY. + * Vendor specific (0x1f) and reserved (0x0e) MII + * registers. + */ + mdio_write(ioaddr, 0x1f, 0x0000); + mdio_write(ioaddr, 0x0e, 0x0000); + } + + mdio_write(ioaddr, MII_ADVERTISE, auto_nego); + mdio_write(ioaddr, MII_CTRL1000, giga_ctrl); + } else { + giga_ctrl = 0; + + if (speed == SPEED_10) + bmcr = 0; + else if (speed == SPEED_100) + bmcr = BMCR_SPEED100; + else + return -EINVAL; + + if (duplex == DUPLEX_FULL) + bmcr |= BMCR_FULLDPLX; - if ((tp->mac_version == RTL_GIGA_MAC_VER_11) || - (tp->mac_version == RTL_GIGA_MAC_VER_12) || - (tp->mac_version >= RTL_GIGA_MAC_VER_17)) { - /* - * Wake up the PHY. - * Vendor specific (0x1f) and reserved (0x0e) MII registers. - */ mdio_write(ioaddr, 0x1f, 0x0000); - mdio_write(ioaddr, 0x0e, 0x0000); } - tp->phy_auto_nego_reg = auto_nego; tp->phy_1000_ctrl_reg = giga_ctrl; - mdio_write(ioaddr, MII_ADVERTISE, auto_nego); - mdio_write(ioaddr, MII_CTRL1000, giga_ctrl); - mdio_write(ioaddr, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART); + mdio_write(ioaddr, MII_BMCR, bmcr); + + if ((tp->mac_version == RTL_GIGA_MAC_VER_02) || + (tp->mac_version == RTL_GIGA_MAC_VER_03)) { + if ((speed == SPEED_100) && (autoneg != AUTONEG_ENABLE)) { + mdio_write(ioaddr, 0x17, 0x2138); + mdio_write(ioaddr, 0x0e, 0x0260); + } else { + mdio_write(ioaddr, 0x17, 0x2108); + mdio_write(ioaddr, 0x0e, 0x0000); + } + } + return 0; } @@ -1295,7 +1297,8 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp, { 0xfc800000, 0x00800000, RTL_GIGA_MAC_VER_02 }, { 0xfc800000, 0x00000000, RTL_GIGA_MAC_VER_01 }, - { 0x00000000, 0x00000000, RTL_GIGA_MAC_VER_01 } /* Catch-all */ + /* Catch-all */ + { 0x00000000, 0x00000000, RTL_GIGA_MAC_NONE } }, *p = mac_info; u32 reg; @@ -1303,12 +1306,6 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp, while ((reg & p->mask) != p->val) p++; tp->mac_version = p->mac_version; - - if (p->mask == 0x00000000) { - struct pci_dev *pdev = tp->pci_dev; - - dev_info(&pdev->dev, "unknown MAC (%08x)\n", reg); - } } static void rtl8169_print_mac_version(struct rtl8169_private *tp) @@ -1884,6 +1881,7 @@ static const struct rtl_cfg_info { u16 intr_event; u16 napi_event; unsigned features; + u8 default_ver; } rtl_cfg_infos [] = { [RTL_CFG_0] = { .hw_start = rtl_hw_start_8169, @@ -1892,7 +1890,8 @@ static const struct rtl_cfg_info { .intr_event = SYSErr | LinkChg | RxOverflow | RxFIFOOver | TxErr | TxOK | RxOK | RxErr, .napi_event = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow, - .features = RTL_FEATURE_GMII + .features = RTL_FEATURE_GMII, + .default_ver = RTL_GIGA_MAC_VER_01, }, [RTL_CFG_1] = { .hw_start = rtl_hw_start_8168, @@ -1901,7 +1900,8 @@ static const struct rtl_cfg_info { .intr_event = SYSErr | LinkChg | RxOverflow | TxErr | TxOK | RxOK | RxErr, .napi_event = TxErr | TxOK | RxOK | RxOverflow, - .features = RTL_FEATURE_GMII | RTL_FEATURE_MSI + .features = RTL_FEATURE_GMII | RTL_FEATURE_MSI, + .default_ver = RTL_GIGA_MAC_VER_11, }, [RTL_CFG_2] = { .hw_start = rtl_hw_start_8101, @@ -1910,7 +1910,8 @@ static const struct rtl_cfg_info { .intr_event = SYSErr | LinkChg | RxOverflow | PCSTimeout | RxFIFOOver | TxErr | TxOK | RxOK | RxErr, .napi_event = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow, - .features = RTL_FEATURE_MSI + .features = RTL_FEATURE_MSI, + .default_ver = RTL_GIGA_MAC_VER_13, } }; @@ -2091,6 +2092,15 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) /* Identify chip attached to board */ rtl8169_get_mac_version(tp, ioaddr); + /* Use appropriate default if unknown */ + if (tp->mac_version == RTL_GIGA_MAC_NONE) { + if (netif_msg_probe(tp)) { + dev_notice(&pdev->dev, + "unknown MAC, using family default\n"); + } + tp->mac_version = cfg->default_ver; + } + rtl8169_print_mac_version(tp); for (i = 0; i < ARRAY_SIZE(rtl_chip_info); i++) { @@ -2098,13 +2108,9 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) break; } if (i == ARRAY_SIZE(rtl_chip_info)) { - /* Unknown chip: assume array element #0, original RTL-8169 */ - if (netif_msg_probe(tp)) { - dev_printk(KERN_DEBUG, &pdev->dev, - "unknown chip version, assuming %s\n", - rtl_chip_info[0].name); - } - i = 0; + dev_err(&pdev->dev, + "driver bug, MAC version not found in rtl_chip_info\n"); + goto err_out_msi_5; } tp->chipset = i; @@ -3269,8 +3275,6 @@ static int rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev) status = opts1 | len | (RingEnd * !((entry + 1) % NUM_TX_DESC)); txd->opts1 = cpu_to_le32(status); - dev->trans_start = jiffies; - tp->cur_tx += frags + 1; smp_wmb(); @@ -3371,7 +3375,7 @@ static void rtl8169_tx_interrupt(struct net_device *dev, rtl8169_unmap_tx_skb(tp->pci_dev, tx_skb, tp->TxDescArray + entry); if (status & LastFrag) { - dev_kfree_skb_irq(tx_skb->skb); + dev_kfree_skb(tx_skb->skb); tx_skb->skb = NULL; } dirty_tx++; @@ -3802,45 +3806,32 @@ static struct net_device_stats *rtl8169_get_stats(struct net_device *dev) return &dev->stats; } -#ifdef CONFIG_PM - -static int rtl8169_suspend(struct pci_dev *pdev, pm_message_t state) +static void rtl8169_net_suspend(struct net_device *dev) { - struct net_device *dev = pci_get_drvdata(pdev); - struct rtl8169_private *tp = netdev_priv(dev); - void __iomem *ioaddr = tp->mmio_addr; - if (!netif_running(dev)) - goto out_pci_suspend; + return; netif_device_detach(dev); netif_stop_queue(dev); +} - spin_lock_irq(&tp->lock); +#ifdef CONFIG_PM - rtl8169_asic_down(ioaddr); +static int rtl8169_suspend(struct device *device) +{ + struct pci_dev *pdev = to_pci_dev(device); + struct net_device *dev = pci_get_drvdata(pdev); - rtl8169_rx_missed(dev, ioaddr); - - spin_unlock_irq(&tp->lock); - -out_pci_suspend: - pci_save_state(pdev); - pci_enable_wake(pdev, pci_choose_state(pdev, state), - (tp->features & RTL_FEATURE_WOL) ? 1 : 0); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); + rtl8169_net_suspend(dev); return 0; } -static int rtl8169_resume(struct pci_dev *pdev) +static int rtl8169_resume(struct device *device) { + struct pci_dev *pdev = to_pci_dev(device); struct net_device *dev = pci_get_drvdata(pdev); - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - pci_enable_wake(pdev, PCI_D0, 0); - if (!netif_running(dev)) goto out; @@ -3851,23 +3842,50 @@ out: return 0; } +static struct dev_pm_ops rtl8169_pm_ops = { + .suspend = rtl8169_suspend, + .resume = rtl8169_resume, + .freeze = rtl8169_suspend, + .thaw = rtl8169_resume, + .poweroff = rtl8169_suspend, + .restore = rtl8169_resume, +}; + +#define RTL8169_PM_OPS (&rtl8169_pm_ops) + +#else /* !CONFIG_PM */ + +#define RTL8169_PM_OPS NULL + +#endif /* !CONFIG_PM */ + static void rtl_shutdown(struct pci_dev *pdev) { - rtl8169_suspend(pdev, PMSG_SUSPEND); -} + struct net_device *dev = pci_get_drvdata(pdev); + struct rtl8169_private *tp = netdev_priv(dev); + void __iomem *ioaddr = tp->mmio_addr; -#endif /* CONFIG_PM */ + rtl8169_net_suspend(dev); + + spin_lock_irq(&tp->lock); + + rtl8169_asic_down(ioaddr); + + spin_unlock_irq(&tp->lock); + + if (system_state == SYSTEM_POWER_OFF) { + pci_wake_from_d3(pdev, true); + pci_set_power_state(pdev, PCI_D3hot); + } +} static struct pci_driver rtl8169_pci_driver = { .name = MODULENAME, .id_table = rtl8169_pci_tbl, .probe = rtl8169_init_one, .remove = __devexit_p(rtl8169_remove_one), -#ifdef CONFIG_PM - .suspend = rtl8169_suspend, - .resume = rtl8169_resume, .shutdown = rtl_shutdown, -#endif + .driver.pm = RTL8169_PM_OPS, }; static int __init rtl8169_init_module(void) diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c index ec59e29807a6..8702e7acdee6 100644 --- a/drivers/net/rionet.c +++ b/drivers/net/rionet.c @@ -428,6 +428,15 @@ static const struct ethtool_ops rionet_ethtool_ops = { .get_link = ethtool_op_get_link, }; +static const struct net_device_ops rionet_netdev_ops = { + .ndo_open = rionet_open, + .ndo_stop = rionet_close, + .ndo_start_xmit = rionet_start_xmit, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, +}; + static int rionet_setup_netdev(struct rio_mport *mport) { int rc = 0; @@ -466,10 +475,7 @@ static int rionet_setup_netdev(struct rio_mport *mport) ndev->dev_addr[4] = device_id >> 8; ndev->dev_addr[5] = device_id & 0xff; - /* Fill in the driver function table */ - ndev->open = &rionet_open; - ndev->hard_start_xmit = &rionet_start_xmit; - ndev->stop = &rionet_close; + ndev->netdev_ops = &rionet_netdev_ops; ndev->mtu = RIO_MAX_MSG_SIZE - 14; ndev->features = NETIF_F_LLTX; SET_ETHTOOL_OPS(ndev, &rionet_ethtool_ops); diff --git a/drivers/net/rrunner.c b/drivers/net/rrunner.c index d890829a9acc..81dbcbb910f4 100644 --- a/drivers/net/rrunner.c +++ b/drivers/net/rrunner.c @@ -1425,7 +1425,7 @@ static int rr_start_xmit(struct sk_buff *skb, struct net_device *dev) if (!(new_skb = dev_alloc_skb(len + 8))) { dev_kfree_skb(skb); netif_wake_queue(dev); - return -EBUSY; + return NETDEV_TX_OK; } skb_reserve(new_skb, 8); skb_put(new_skb, len); diff --git a/drivers/net/s2io-regs.h b/drivers/net/s2io-regs.h index f8274f8941ea..416669fd68c6 100644 --- a/drivers/net/s2io-regs.h +++ b/drivers/net/s2io-regs.h @@ -271,11 +271,6 @@ struct XENA_dev_config { u64 mdio_control; #define MDIO_MMD_INDX_ADDR(val) vBIT(val, 0, 16) #define MDIO_MMD_DEV_ADDR(val) vBIT(val, 19, 5) -#define MDIO_MMD_PMA_DEV_ADDR 0x1 -#define MDIO_MMD_PMD_DEV_ADDR 0x1 -#define MDIO_MMD_WIS_DEV_ADDR 0x2 -#define MDIO_MMD_PCS_DEV_ADDR 0x3 -#define MDIO_MMD_PHYXS_DEV_ADDR 0x4 #define MDIO_MMS_PRT_ADDR(val) vBIT(val, 27, 5) #define MDIO_CTRL_START_TRANS(val) vBIT(val, 56, 4) #define MDIO_OP(val) vBIT(val, 60, 2) diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 1a4979f27fb5..458daa06ed41 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -63,6 +63,7 @@ #include #include #include +#include #include #include #include @@ -1763,7 +1764,7 @@ static int init_nic(struct s2io_nic *nic) * by then we return error. */ time = 0; - while (TRUE) { + while (true) { val64 = readq(&bar0->rti_command_mem); if (!(val64 & RTI_CMD_MEM_STROBE_NEW_CMD)) break; @@ -2136,7 +2137,7 @@ static int verify_pcc_quiescent(struct s2io_nic *sp, int flag) herc = (sp->device_type == XFRAME_II_DEVICE); - if (flag == FALSE) { + if (flag == false) { if ((!herc && (sp->pdev->revision >= 4)) || herc) { if (!(val64 & ADAPTER_STATUS_RMAC_PCC_IDLE)) ret = 1; @@ -3328,9 +3329,9 @@ static void s2io_updt_xpak_counter(struct net_device *dev) struct stat_block *stat_info = sp->mac_control.stats_info; /* Check the communication with the MDIO slave */ - addr = 0x0000; + addr = MDIO_CTRL1; val64 = 0x0; - val64 = s2io_mdio_read(MDIO_MMD_PMA_DEV_ADDR, addr, dev); + val64 = s2io_mdio_read(MDIO_MMD_PMAPMD, addr, dev); if((val64 == 0xFFFF) || (val64 == 0x0000)) { DBG_PRINT(ERR_DBG, "ERR: MDIO slave access failed - " @@ -3338,24 +3339,24 @@ static void s2io_updt_xpak_counter(struct net_device *dev) return; } - /* Check for the expecte value of 2040 at PMA address 0x0000 */ - if(val64 != 0x2040) + /* Check for the expected value of control reg 1 */ + if(val64 != MDIO_CTRL1_SPEED10G) { DBG_PRINT(ERR_DBG, "Incorrect value at PMA address 0x0000 - "); - DBG_PRINT(ERR_DBG, "Returned: %llx- Expected: 0x2040\n", - (unsigned long long)val64); + DBG_PRINT(ERR_DBG, "Returned: %llx- Expected: 0x%x\n", + (unsigned long long)val64, MDIO_CTRL1_SPEED10G); return; } /* Loading the DOM register to MDIO register */ addr = 0xA100; - s2io_mdio_write(MDIO_MMD_PMA_DEV_ADDR, addr, val16, dev); - val64 = s2io_mdio_read(MDIO_MMD_PMA_DEV_ADDR, addr, dev); + s2io_mdio_write(MDIO_MMD_PMAPMD, addr, val16, dev); + val64 = s2io_mdio_read(MDIO_MMD_PMAPMD, addr, dev); /* Reading the Alarm flags */ addr = 0xA070; val64 = 0x0; - val64 = s2io_mdio_read(MDIO_MMD_PMA_DEV_ADDR, addr, dev); + val64 = s2io_mdio_read(MDIO_MMD_PMAPMD, addr, dev); flag = CHECKBIT(val64, 0x7); type = 1; @@ -3387,7 +3388,7 @@ static void s2io_updt_xpak_counter(struct net_device *dev) /* Reading the Warning flags */ addr = 0xA074; val64 = 0x0; - val64 = s2io_mdio_read(MDIO_MMD_PMA_DEV_ADDR, addr, dev); + val64 = s2io_mdio_read(MDIO_MMD_PMAPMD, addr, dev); if(CHECKBIT(val64, 0x7)) stat_info->xpak_stat.warn_transceiver_temp_high++; @@ -3586,7 +3587,7 @@ static void s2io_reset(struct s2io_nic * sp) writeq(val64, &bar0->pcc_err_reg); } - sp->device_enabled_once = FALSE; + sp->device_enabled_once = false; } /** @@ -4298,7 +4299,6 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) s2io_stop_tx_queue(sp, fifo->fifo_no); } mac_control->stats_info->sw_stat.mem_allocated += skb->truesize; - dev->trans_start = jiffies; spin_unlock_irqrestore(&fifo->tx_lock, flags); if (sp->config.intr_type == MSI_X) @@ -5572,10 +5572,10 @@ static void s2io_ethtool_getpause_data(struct net_device *dev, val64 = readq(&bar0->rmac_pause_cfg); if (val64 & RMAC_PAUSE_GEN_ENABLE) - ep->tx_pause = TRUE; + ep->tx_pause = true; if (val64 & RMAC_PAUSE_RX_ENABLE) - ep->rx_pause = TRUE; - ep->autoneg = FALSE; + ep->rx_pause = true; + ep->autoneg = false; } /** @@ -6806,7 +6806,7 @@ static void s2io_set_link(struct work_struct *work) val64 |= ADAPTER_LED_ON; writeq(val64, &bar0->adapter_control); } - nic->device_enabled_once = TRUE; + nic->device_enabled_once = true; } else { DBG_PRINT(ERR_DBG, "%s: Error: ", dev->name); DBG_PRINT(ERR_DBG, "device is not Quiescent\n"); @@ -7754,7 +7754,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) struct s2io_nic *sp; struct net_device *dev; int i, j, ret; - int dma_flag = FALSE; + int dma_flag = false; u32 mac_up, mac_down; u64 val64 = 0, tmp64 = 0; struct XENA_dev_config __iomem *bar0 = NULL; @@ -7777,7 +7777,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { DBG_PRINT(INIT_DBG, "s2io_init_nic: Using 64bit DMA\n"); - dma_flag = TRUE; + dma_flag = true; if (pci_set_consistent_dma_mask (pdev, DMA_BIT_MASK(64))) { DBG_PRINT(ERR_DBG, @@ -7818,7 +7818,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) sp->dev = dev; sp->pdev = pdev; sp->high_dma_flag = dma_flag; - sp->device_enabled_once = FALSE; + sp->device_enabled_once = false; if (rx_ring_mode == 1) sp->rxd_mode = RXD_MODE_1; if (rx_ring_mode == 2) @@ -7964,7 +7964,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; - if (sp->high_dma_flag == TRUE) + if (sp->high_dma_flag == true) dev->features |= NETIF_F_HIGHDMA; dev->features |= NETIF_F_TSO; dev->features |= NETIF_F_TSO6; diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index 55cb943f23f8..d5c5be6c07b9 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -18,15 +18,6 @@ #define vBIT(val, loc, sz) (((u64)val) << (64-loc-sz)) #define INV(d) ((d&0xff)<<24) | (((d>>8)&0xff)<<16) | (((d>>16)&0xff)<<8)| ((d>>24)&0xff) -#ifndef BOOL -#define BOOL int -#endif - -#ifndef TRUE -#define TRUE 1 -#define FALSE 0 -#endif - #undef SUCCESS #define SUCCESS 0 #define FAILURE -1 diff --git a/drivers/net/s6gmac.c b/drivers/net/s6gmac.c new file mode 100644 index 000000000000..5345e47b35ac --- /dev/null +++ b/drivers/net/s6gmac.c @@ -0,0 +1,1073 @@ +/* + * Ethernet driver for S6105 on chip network device + * (c)2008 emlix GmbH http://www.emlix.com + * Authors: Oskar Schirmer + * Daniel Gloeckner + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "s6gmac" +#define DRV_PRMT DRV_NAME ": " + + +/* register declarations */ + +#define S6_GMAC_MACCONF1 0x000 +#define S6_GMAC_MACCONF1_TXENA 0 +#define S6_GMAC_MACCONF1_SYNCTX 1 +#define S6_GMAC_MACCONF1_RXENA 2 +#define S6_GMAC_MACCONF1_SYNCRX 3 +#define S6_GMAC_MACCONF1_TXFLOWCTRL 4 +#define S6_GMAC_MACCONF1_RXFLOWCTRL 5 +#define S6_GMAC_MACCONF1_LOOPBACK 8 +#define S6_GMAC_MACCONF1_RESTXFUNC 16 +#define S6_GMAC_MACCONF1_RESRXFUNC 17 +#define S6_GMAC_MACCONF1_RESTXMACCTRL 18 +#define S6_GMAC_MACCONF1_RESRXMACCTRL 19 +#define S6_GMAC_MACCONF1_SIMULRES 30 +#define S6_GMAC_MACCONF1_SOFTRES 31 +#define S6_GMAC_MACCONF2 0x004 +#define S6_GMAC_MACCONF2_FULL 0 +#define S6_GMAC_MACCONF2_CRCENA 1 +#define S6_GMAC_MACCONF2_PADCRCENA 2 +#define S6_GMAC_MACCONF2_LENGTHFCHK 4 +#define S6_GMAC_MACCONF2_HUGEFRAMENA 5 +#define S6_GMAC_MACCONF2_IFMODE 8 +#define S6_GMAC_MACCONF2_IFMODE_NIBBLE 1 +#define S6_GMAC_MACCONF2_IFMODE_BYTE 2 +#define S6_GMAC_MACCONF2_IFMODE_MASK 3 +#define S6_GMAC_MACCONF2_PREAMBLELEN 12 +#define S6_GMAC_MACCONF2_PREAMBLELEN_MASK 0x0F +#define S6_GMAC_MACIPGIFG 0x008 +#define S6_GMAC_MACIPGIFG_B2BINTERPGAP 0 +#define S6_GMAC_MACIPGIFG_B2BINTERPGAP_MASK 0x7F +#define S6_GMAC_MACIPGIFG_MINIFGENFORCE 8 +#define S6_GMAC_MACIPGIFG_B2BINTERPGAP2 16 +#define S6_GMAC_MACIPGIFG_B2BINTERPGAP1 24 +#define S6_GMAC_MACHALFDUPLEX 0x00C +#define S6_GMAC_MACHALFDUPLEX_COLLISWIN 0 +#define S6_GMAC_MACHALFDUPLEX_COLLISWIN_MASK 0x3F +#define S6_GMAC_MACHALFDUPLEX_RETXMAX 12 +#define S6_GMAC_MACHALFDUPLEX_RETXMAX_MASK 0x0F +#define S6_GMAC_MACHALFDUPLEX_EXCESSDEF 16 +#define S6_GMAC_MACHALFDUPLEX_NOBACKOFF 17 +#define S6_GMAC_MACHALFDUPLEX_BPNOBCKOF 18 +#define S6_GMAC_MACHALFDUPLEX_ALTBEBENA 19 +#define S6_GMAC_MACHALFDUPLEX_ALTBEBTRN 20 +#define S6_GMAC_MACHALFDUPLEX_ALTBEBTR_MASK 0x0F +#define S6_GMAC_MACMAXFRAMELEN 0x010 +#define S6_GMAC_MACMIICONF 0x020 +#define S6_GMAC_MACMIICONF_CSEL 0 +#define S6_GMAC_MACMIICONF_CSEL_DIV10 0 +#define S6_GMAC_MACMIICONF_CSEL_DIV12 1 +#define S6_GMAC_MACMIICONF_CSEL_DIV14 2 +#define S6_GMAC_MACMIICONF_CSEL_DIV18 3 +#define S6_GMAC_MACMIICONF_CSEL_DIV24 4 +#define S6_GMAC_MACMIICONF_CSEL_DIV34 5 +#define S6_GMAC_MACMIICONF_CSEL_DIV68 6 +#define S6_GMAC_MACMIICONF_CSEL_DIV168 7 +#define S6_GMAC_MACMIICONF_CSEL_MASK 7 +#define S6_GMAC_MACMIICONF_PREAMBLESUPR 4 +#define S6_GMAC_MACMIICONF_SCANAUTOINCR 5 +#define S6_GMAC_MACMIICMD 0x024 +#define S6_GMAC_MACMIICMD_READ 0 +#define S6_GMAC_MACMIICMD_SCAN 1 +#define S6_GMAC_MACMIIADDR 0x028 +#define S6_GMAC_MACMIIADDR_REG 0 +#define S6_GMAC_MACMIIADDR_REG_MASK 0x1F +#define S6_GMAC_MACMIIADDR_PHY 8 +#define S6_GMAC_MACMIIADDR_PHY_MASK 0x1F +#define S6_GMAC_MACMIICTRL 0x02C +#define S6_GMAC_MACMIISTAT 0x030 +#define S6_GMAC_MACMIIINDI 0x034 +#define S6_GMAC_MACMIIINDI_BUSY 0 +#define S6_GMAC_MACMIIINDI_SCAN 1 +#define S6_GMAC_MACMIIINDI_INVAL 2 +#define S6_GMAC_MACINTERFSTAT 0x03C +#define S6_GMAC_MACINTERFSTAT_LINKFAIL 3 +#define S6_GMAC_MACINTERFSTAT_EXCESSDEF 9 +#define S6_GMAC_MACSTATADDR1 0x040 +#define S6_GMAC_MACSTATADDR2 0x044 + +#define S6_GMAC_FIFOCONF0 0x048 +#define S6_GMAC_FIFOCONF0_HSTRSTWT 0 +#define S6_GMAC_FIFOCONF0_HSTRSTSR 1 +#define S6_GMAC_FIFOCONF0_HSTRSTFR 2 +#define S6_GMAC_FIFOCONF0_HSTRSTST 3 +#define S6_GMAC_FIFOCONF0_HSTRSTFT 4 +#define S6_GMAC_FIFOCONF0_WTMENREQ 8 +#define S6_GMAC_FIFOCONF0_SRFENREQ 9 +#define S6_GMAC_FIFOCONF0_FRFENREQ 10 +#define S6_GMAC_FIFOCONF0_STFENREQ 11 +#define S6_GMAC_FIFOCONF0_FTFENREQ 12 +#define S6_GMAC_FIFOCONF0_WTMENRPLY 16 +#define S6_GMAC_FIFOCONF0_SRFENRPLY 17 +#define S6_GMAC_FIFOCONF0_FRFENRPLY 18 +#define S6_GMAC_FIFOCONF0_STFENRPLY 19 +#define S6_GMAC_FIFOCONF0_FTFENRPLY 20 +#define S6_GMAC_FIFOCONF1 0x04C +#define S6_GMAC_FIFOCONF2 0x050 +#define S6_GMAC_FIFOCONF2_CFGLWM 0 +#define S6_GMAC_FIFOCONF2_CFGHWM 16 +#define S6_GMAC_FIFOCONF3 0x054 +#define S6_GMAC_FIFOCONF3_CFGFTTH 0 +#define S6_GMAC_FIFOCONF3_CFGHWMFT 16 +#define S6_GMAC_FIFOCONF4 0x058 +#define S6_GMAC_FIFOCONF_RSV_PREVDROP 0 +#define S6_GMAC_FIFOCONF_RSV_RUNT 1 +#define S6_GMAC_FIFOCONF_RSV_FALSECAR 2 +#define S6_GMAC_FIFOCONF_RSV_CODEERR 3 +#define S6_GMAC_FIFOCONF_RSV_CRCERR 4 +#define S6_GMAC_FIFOCONF_RSV_LENGTHERR 5 +#define S6_GMAC_FIFOCONF_RSV_LENRANGE 6 +#define S6_GMAC_FIFOCONF_RSV_OK 7 +#define S6_GMAC_FIFOCONF_RSV_MULTICAST 8 +#define S6_GMAC_FIFOCONF_RSV_BROADCAST 9 +#define S6_GMAC_FIFOCONF_RSV_DRIBBLE 10 +#define S6_GMAC_FIFOCONF_RSV_CTRLFRAME 11 +#define S6_GMAC_FIFOCONF_RSV_PAUSECTRL 12 +#define S6_GMAC_FIFOCONF_RSV_UNOPCODE 13 +#define S6_GMAC_FIFOCONF_RSV_VLANTAG 14 +#define S6_GMAC_FIFOCONF_RSV_LONGEVENT 15 +#define S6_GMAC_FIFOCONF_RSV_TRUNCATED 16 +#define S6_GMAC_FIFOCONF_RSV_MASK 0x3FFFF +#define S6_GMAC_FIFOCONF5 0x05C +#define S6_GMAC_FIFOCONF5_DROPLT64 18 +#define S6_GMAC_FIFOCONF5_CFGBYTM 19 +#define S6_GMAC_FIFOCONF5_RXDROPSIZE 20 +#define S6_GMAC_FIFOCONF5_RXDROPSIZE_MASK 0xF + +#define S6_GMAC_STAT_REGS 0x080 +#define S6_GMAC_STAT_SIZE_MIN 12 +#define S6_GMAC_STATTR64 0x080 +#define S6_GMAC_STATTR64_SIZE 18 +#define S6_GMAC_STATTR127 0x084 +#define S6_GMAC_STATTR127_SIZE 18 +#define S6_GMAC_STATTR255 0x088 +#define S6_GMAC_STATTR255_SIZE 18 +#define S6_GMAC_STATTR511 0x08C +#define S6_GMAC_STATTR511_SIZE 18 +#define S6_GMAC_STATTR1K 0x090 +#define S6_GMAC_STATTR1K_SIZE 18 +#define S6_GMAC_STATTRMAX 0x094 +#define S6_GMAC_STATTRMAX_SIZE 18 +#define S6_GMAC_STATTRMGV 0x098 +#define S6_GMAC_STATTRMGV_SIZE 18 +#define S6_GMAC_STATRBYT 0x09C +#define S6_GMAC_STATRBYT_SIZE 24 +#define S6_GMAC_STATRPKT 0x0A0 +#define S6_GMAC_STATRPKT_SIZE 18 +#define S6_GMAC_STATRFCS 0x0A4 +#define S6_GMAC_STATRFCS_SIZE 12 +#define S6_GMAC_STATRMCA 0x0A8 +#define S6_GMAC_STATRMCA_SIZE 18 +#define S6_GMAC_STATRBCA 0x0AC +#define S6_GMAC_STATRBCA_SIZE 22 +#define S6_GMAC_STATRXCF 0x0B0 +#define S6_GMAC_STATRXCF_SIZE 18 +#define S6_GMAC_STATRXPF 0x0B4 +#define S6_GMAC_STATRXPF_SIZE 12 +#define S6_GMAC_STATRXUO 0x0B8 +#define S6_GMAC_STATRXUO_SIZE 12 +#define S6_GMAC_STATRALN 0x0BC +#define S6_GMAC_STATRALN_SIZE 12 +#define S6_GMAC_STATRFLR 0x0C0 +#define S6_GMAC_STATRFLR_SIZE 16 +#define S6_GMAC_STATRCDE 0x0C4 +#define S6_GMAC_STATRCDE_SIZE 12 +#define S6_GMAC_STATRCSE 0x0C8 +#define S6_GMAC_STATRCSE_SIZE 12 +#define S6_GMAC_STATRUND 0x0CC +#define S6_GMAC_STATRUND_SIZE 12 +#define S6_GMAC_STATROVR 0x0D0 +#define S6_GMAC_STATROVR_SIZE 12 +#define S6_GMAC_STATRFRG 0x0D4 +#define S6_GMAC_STATRFRG_SIZE 12 +#define S6_GMAC_STATRJBR 0x0D8 +#define S6_GMAC_STATRJBR_SIZE 12 +#define S6_GMAC_STATRDRP 0x0DC +#define S6_GMAC_STATRDRP_SIZE 12 +#define S6_GMAC_STATTBYT 0x0E0 +#define S6_GMAC_STATTBYT_SIZE 24 +#define S6_GMAC_STATTPKT 0x0E4 +#define S6_GMAC_STATTPKT_SIZE 18 +#define S6_GMAC_STATTMCA 0x0E8 +#define S6_GMAC_STATTMCA_SIZE 18 +#define S6_GMAC_STATTBCA 0x0EC +#define S6_GMAC_STATTBCA_SIZE 18 +#define S6_GMAC_STATTXPF 0x0F0 +#define S6_GMAC_STATTXPF_SIZE 12 +#define S6_GMAC_STATTDFR 0x0F4 +#define S6_GMAC_STATTDFR_SIZE 12 +#define S6_GMAC_STATTEDF 0x0F8 +#define S6_GMAC_STATTEDF_SIZE 12 +#define S6_GMAC_STATTSCL 0x0FC +#define S6_GMAC_STATTSCL_SIZE 12 +#define S6_GMAC_STATTMCL 0x100 +#define S6_GMAC_STATTMCL_SIZE 12 +#define S6_GMAC_STATTLCL 0x104 +#define S6_GMAC_STATTLCL_SIZE 12 +#define S6_GMAC_STATTXCL 0x108 +#define S6_GMAC_STATTXCL_SIZE 12 +#define S6_GMAC_STATTNCL 0x10C +#define S6_GMAC_STATTNCL_SIZE 13 +#define S6_GMAC_STATTPFH 0x110 +#define S6_GMAC_STATTPFH_SIZE 12 +#define S6_GMAC_STATTDRP 0x114 +#define S6_GMAC_STATTDRP_SIZE 12 +#define S6_GMAC_STATTJBR 0x118 +#define S6_GMAC_STATTJBR_SIZE 12 +#define S6_GMAC_STATTFCS 0x11C +#define S6_GMAC_STATTFCS_SIZE 12 +#define S6_GMAC_STATTXCF 0x120 +#define S6_GMAC_STATTXCF_SIZE 12 +#define S6_GMAC_STATTOVR 0x124 +#define S6_GMAC_STATTOVR_SIZE 12 +#define S6_GMAC_STATTUND 0x128 +#define S6_GMAC_STATTUND_SIZE 12 +#define S6_GMAC_STATTFRG 0x12C +#define S6_GMAC_STATTFRG_SIZE 12 +#define S6_GMAC_STATCARRY(n) (0x130 + 4*(n)) +#define S6_GMAC_STATCARRYMSK(n) (0x138 + 4*(n)) +#define S6_GMAC_STATCARRY1_RDRP 0 +#define S6_GMAC_STATCARRY1_RJBR 1 +#define S6_GMAC_STATCARRY1_RFRG 2 +#define S6_GMAC_STATCARRY1_ROVR 3 +#define S6_GMAC_STATCARRY1_RUND 4 +#define S6_GMAC_STATCARRY1_RCSE 5 +#define S6_GMAC_STATCARRY1_RCDE 6 +#define S6_GMAC_STATCARRY1_RFLR 7 +#define S6_GMAC_STATCARRY1_RALN 8 +#define S6_GMAC_STATCARRY1_RXUO 9 +#define S6_GMAC_STATCARRY1_RXPF 10 +#define S6_GMAC_STATCARRY1_RXCF 11 +#define S6_GMAC_STATCARRY1_RBCA 12 +#define S6_GMAC_STATCARRY1_RMCA 13 +#define S6_GMAC_STATCARRY1_RFCS 14 +#define S6_GMAC_STATCARRY1_RPKT 15 +#define S6_GMAC_STATCARRY1_RBYT 16 +#define S6_GMAC_STATCARRY1_TRMGV 25 +#define S6_GMAC_STATCARRY1_TRMAX 26 +#define S6_GMAC_STATCARRY1_TR1K 27 +#define S6_GMAC_STATCARRY1_TR511 28 +#define S6_GMAC_STATCARRY1_TR255 29 +#define S6_GMAC_STATCARRY1_TR127 30 +#define S6_GMAC_STATCARRY1_TR64 31 +#define S6_GMAC_STATCARRY2_TDRP 0 +#define S6_GMAC_STATCARRY2_TPFH 1 +#define S6_GMAC_STATCARRY2_TNCL 2 +#define S6_GMAC_STATCARRY2_TXCL 3 +#define S6_GMAC_STATCARRY2_TLCL 4 +#define S6_GMAC_STATCARRY2_TMCL 5 +#define S6_GMAC_STATCARRY2_TSCL 6 +#define S6_GMAC_STATCARRY2_TEDF 7 +#define S6_GMAC_STATCARRY2_TDFR 8 +#define S6_GMAC_STATCARRY2_TXPF 9 +#define S6_GMAC_STATCARRY2_TBCA 10 +#define S6_GMAC_STATCARRY2_TMCA 11 +#define S6_GMAC_STATCARRY2_TPKT 12 +#define S6_GMAC_STATCARRY2_TBYT 13 +#define S6_GMAC_STATCARRY2_TFRG 14 +#define S6_GMAC_STATCARRY2_TUND 15 +#define S6_GMAC_STATCARRY2_TOVR 16 +#define S6_GMAC_STATCARRY2_TXCF 17 +#define S6_GMAC_STATCARRY2_TFCS 18 +#define S6_GMAC_STATCARRY2_TJBR 19 + +#define S6_GMAC_HOST_PBLKCTRL 0x140 +#define S6_GMAC_HOST_PBLKCTRL_TXENA 0 +#define S6_GMAC_HOST_PBLKCTRL_RXENA 1 +#define S6_GMAC_HOST_PBLKCTRL_TXSRES 2 +#define S6_GMAC_HOST_PBLKCTRL_RXSRES 3 +#define S6_GMAC_HOST_PBLKCTRL_TXBSIZ 8 +#define S6_GMAC_HOST_PBLKCTRL_RXBSIZ 12 +#define S6_GMAC_HOST_PBLKCTRL_SIZ_16 4 +#define S6_GMAC_HOST_PBLKCTRL_SIZ_32 5 +#define S6_GMAC_HOST_PBLKCTRL_SIZ_64 6 +#define S6_GMAC_HOST_PBLKCTRL_SIZ_128 7 +#define S6_GMAC_HOST_PBLKCTRL_SIZ_MASK 0xF +#define S6_GMAC_HOST_PBLKCTRL_STATENA 16 +#define S6_GMAC_HOST_PBLKCTRL_STATAUTOZ 17 +#define S6_GMAC_HOST_PBLKCTRL_STATCLEAR 18 +#define S6_GMAC_HOST_PBLKCTRL_RGMII 19 +#define S6_GMAC_HOST_INTMASK 0x144 +#define S6_GMAC_HOST_INTSTAT 0x148 +#define S6_GMAC_HOST_INT_TXBURSTOVER 3 +#define S6_GMAC_HOST_INT_TXPREWOVER 4 +#define S6_GMAC_HOST_INT_RXBURSTUNDER 5 +#define S6_GMAC_HOST_INT_RXPOSTRFULL 6 +#define S6_GMAC_HOST_INT_RXPOSTRUNDER 7 +#define S6_GMAC_HOST_RXFIFOHWM 0x14C +#define S6_GMAC_HOST_CTRLFRAMXP 0x150 +#define S6_GMAC_HOST_DSTADDRLO(n) (0x160 + 8*(n)) +#define S6_GMAC_HOST_DSTADDRHI(n) (0x164 + 8*(n)) +#define S6_GMAC_HOST_DSTMASKLO(n) (0x180 + 8*(n)) +#define S6_GMAC_HOST_DSTMASKHI(n) (0x184 + 8*(n)) + +#define S6_GMAC_BURST_PREWR 0x1B0 +#define S6_GMAC_BURST_PREWR_LEN 0 +#define S6_GMAC_BURST_PREWR_LEN_MASK ((1 << 20) - 1) +#define S6_GMAC_BURST_PREWR_CFE 20 +#define S6_GMAC_BURST_PREWR_PPE 21 +#define S6_GMAC_BURST_PREWR_FCS 22 +#define S6_GMAC_BURST_PREWR_PAD 23 +#define S6_GMAC_BURST_POSTRD 0x1D0 +#define S6_GMAC_BURST_POSTRD_LEN 0 +#define S6_GMAC_BURST_POSTRD_LEN_MASK ((1 << 20) - 1) +#define S6_GMAC_BURST_POSTRD_DROP 20 + + +/* data handling */ + +#define S6_NUM_TX_SKB 8 /* must be larger than TX fifo size */ +#define S6_NUM_RX_SKB 16 +#define S6_MAX_FRLEN 1536 + +struct s6gmac { + u32 reg; + u32 tx_dma; + u32 rx_dma; + u32 io; + u8 tx_chan; + u8 rx_chan; + spinlock_t lock; + u8 tx_skb_i, tx_skb_o; + u8 rx_skb_i, rx_skb_o; + struct sk_buff *tx_skb[S6_NUM_TX_SKB]; + struct sk_buff *rx_skb[S6_NUM_RX_SKB]; + unsigned long carry[sizeof(struct net_device_stats) / sizeof(long)]; + unsigned long stats[sizeof(struct net_device_stats) / sizeof(long)]; + struct phy_device *phydev; + struct { + struct mii_bus *bus; + int irq[PHY_MAX_ADDR]; + } mii; + struct { + unsigned int mbit; + u8 giga; + u8 isup; + u8 full; + } link; +}; + +static void s6gmac_rx_fillfifo(struct s6gmac *pd) +{ + struct sk_buff *skb; + while ((((u8)(pd->rx_skb_i - pd->rx_skb_o)) < S6_NUM_RX_SKB) + && (!s6dmac_fifo_full(pd->rx_dma, pd->rx_chan)) + && (skb = dev_alloc_skb(S6_MAX_FRLEN + 2))) { + pd->rx_skb[(pd->rx_skb_i++) % S6_NUM_RX_SKB] = skb; + s6dmac_put_fifo_cache(pd->rx_dma, pd->rx_chan, + pd->io, (u32)skb->data, S6_MAX_FRLEN); + } +} + +static void s6gmac_rx_interrupt(struct net_device *dev) +{ + struct s6gmac *pd = netdev_priv(dev); + u32 pfx; + struct sk_buff *skb; + while (((u8)(pd->rx_skb_i - pd->rx_skb_o)) > + s6dmac_pending_count(pd->rx_dma, pd->rx_chan)) { + skb = pd->rx_skb[(pd->rx_skb_o++) % S6_NUM_RX_SKB]; + pfx = readl(pd->reg + S6_GMAC_BURST_POSTRD); + if (pfx & (1 << S6_GMAC_BURST_POSTRD_DROP)) { + dev_kfree_skb_irq(skb); + } else { + skb_put(skb, (pfx >> S6_GMAC_BURST_POSTRD_LEN) + & S6_GMAC_BURST_POSTRD_LEN_MASK); + skb->dev = dev; + skb->protocol = eth_type_trans(skb, dev); + skb->ip_summed = CHECKSUM_UNNECESSARY; + netif_rx(skb); + } + } +} + +static void s6gmac_tx_interrupt(struct net_device *dev) +{ + struct s6gmac *pd = netdev_priv(dev); + while (((u8)(pd->tx_skb_i - pd->tx_skb_o)) > + s6dmac_pending_count(pd->tx_dma, pd->tx_chan)) { + dev_kfree_skb_irq(pd->tx_skb[(pd->tx_skb_o++) % S6_NUM_TX_SKB]); + } + if (!s6dmac_fifo_full(pd->tx_dma, pd->tx_chan)) + netif_wake_queue(dev); +} + +struct s6gmac_statinf { + unsigned reg_size : 4; /* 0: unused */ + unsigned reg_off : 6; + unsigned net_index : 6; +}; + +#define S6_STATS_B (8 * sizeof(u32)) +#define S6_STATS_C(b, r, f) [b] = { \ + BUILD_BUG_ON_ZERO(r##_SIZE < S6_GMAC_STAT_SIZE_MIN) + \ + BUILD_BUG_ON_ZERO((r##_SIZE - (S6_GMAC_STAT_SIZE_MIN - 1)) \ + >= (1<<4)) + \ + r##_SIZE - (S6_GMAC_STAT_SIZE_MIN - 1), \ + BUILD_BUG_ON_ZERO(((unsigned)((r - S6_GMAC_STAT_REGS) / sizeof(u32))) \ + >= ((1<<6)-1)) + \ + (r - S6_GMAC_STAT_REGS) / sizeof(u32), \ + BUILD_BUG_ON_ZERO((offsetof(struct net_device_stats, f)) \ + % sizeof(unsigned long)) + \ + BUILD_BUG_ON_ZERO((((unsigned)(offsetof(struct net_device_stats, f)) \ + / sizeof(unsigned long)) >= (1<<6))) + \ + BUILD_BUG_ON_ZERO((sizeof(((struct net_device_stats *)0)->f) \ + != sizeof(unsigned long))) + \ + (offsetof(struct net_device_stats, f)) / sizeof(unsigned long)}, + +static const struct s6gmac_statinf statinf[2][S6_STATS_B] = { { + S6_STATS_C(S6_GMAC_STATCARRY1_RBYT, S6_GMAC_STATRBYT, rx_bytes) + S6_STATS_C(S6_GMAC_STATCARRY1_RPKT, S6_GMAC_STATRPKT, rx_packets) + S6_STATS_C(S6_GMAC_STATCARRY1_RFCS, S6_GMAC_STATRFCS, rx_crc_errors) + S6_STATS_C(S6_GMAC_STATCARRY1_RMCA, S6_GMAC_STATRMCA, multicast) + S6_STATS_C(S6_GMAC_STATCARRY1_RALN, S6_GMAC_STATRALN, rx_frame_errors) + S6_STATS_C(S6_GMAC_STATCARRY1_RFLR, S6_GMAC_STATRFLR, rx_length_errors) + S6_STATS_C(S6_GMAC_STATCARRY1_RCDE, S6_GMAC_STATRCDE, rx_missed_errors) + S6_STATS_C(S6_GMAC_STATCARRY1_RUND, S6_GMAC_STATRUND, rx_length_errors) + S6_STATS_C(S6_GMAC_STATCARRY1_ROVR, S6_GMAC_STATROVR, rx_length_errors) + S6_STATS_C(S6_GMAC_STATCARRY1_RFRG, S6_GMAC_STATRFRG, rx_crc_errors) + S6_STATS_C(S6_GMAC_STATCARRY1_RJBR, S6_GMAC_STATRJBR, rx_crc_errors) + S6_STATS_C(S6_GMAC_STATCARRY1_RDRP, S6_GMAC_STATRDRP, rx_dropped) +}, { + S6_STATS_C(S6_GMAC_STATCARRY2_TBYT, S6_GMAC_STATTBYT, tx_bytes) + S6_STATS_C(S6_GMAC_STATCARRY2_TPKT, S6_GMAC_STATTPKT, tx_packets) + S6_STATS_C(S6_GMAC_STATCARRY2_TEDF, S6_GMAC_STATTEDF, tx_aborted_errors) + S6_STATS_C(S6_GMAC_STATCARRY2_TXCL, S6_GMAC_STATTXCL, tx_aborted_errors) + S6_STATS_C(S6_GMAC_STATCARRY2_TNCL, S6_GMAC_STATTNCL, collisions) + S6_STATS_C(S6_GMAC_STATCARRY2_TDRP, S6_GMAC_STATTDRP, tx_dropped) + S6_STATS_C(S6_GMAC_STATCARRY2_TJBR, S6_GMAC_STATTJBR, tx_errors) + S6_STATS_C(S6_GMAC_STATCARRY2_TFCS, S6_GMAC_STATTFCS, tx_errors) + S6_STATS_C(S6_GMAC_STATCARRY2_TOVR, S6_GMAC_STATTOVR, tx_errors) + S6_STATS_C(S6_GMAC_STATCARRY2_TUND, S6_GMAC_STATTUND, tx_errors) + S6_STATS_C(S6_GMAC_STATCARRY2_TFRG, S6_GMAC_STATTFRG, tx_errors) +} }; + +static void s6gmac_stats_collect(struct s6gmac *pd, + const struct s6gmac_statinf *inf) +{ + int b; + for (b = 0; b < S6_STATS_B; b++) { + if (inf[b].reg_size) { + pd->stats[inf[b].net_index] += + readl(pd->reg + S6_GMAC_STAT_REGS + + sizeof(u32) * inf[b].reg_off); + } + } +} + +static void s6gmac_stats_carry(struct s6gmac *pd, + const struct s6gmac_statinf *inf, u32 mask) +{ + int b; + while (mask) { + b = fls(mask) - 1; + mask &= ~(1 << b); + pd->carry[inf[b].net_index] += (1 << inf[b].reg_size); + } +} + +static inline u32 s6gmac_stats_pending(struct s6gmac *pd, int carry) +{ + int r = readl(pd->reg + S6_GMAC_STATCARRY(carry)) & + ~readl(pd->reg + S6_GMAC_STATCARRYMSK(carry)); + return r; +} + +static inline void s6gmac_stats_interrupt(struct s6gmac *pd, int carry) +{ + u32 mask; + mask = s6gmac_stats_pending(pd, carry); + if (mask) { + writel(mask, pd->reg + S6_GMAC_STATCARRY(carry)); + s6gmac_stats_carry(pd, &statinf[carry][0], mask); + } +} + +static irqreturn_t s6gmac_interrupt(int irq, void *dev_id) +{ + struct net_device *dev = (struct net_device *)dev_id; + struct s6gmac *pd = netdev_priv(dev); + if (!dev) + return IRQ_NONE; + spin_lock(&pd->lock); + if (s6dmac_termcnt_irq(pd->rx_dma, pd->rx_chan)) + s6gmac_rx_interrupt(dev); + s6gmac_rx_fillfifo(pd); + if (s6dmac_termcnt_irq(pd->tx_dma, pd->tx_chan)) + s6gmac_tx_interrupt(dev); + s6gmac_stats_interrupt(pd, 0); + s6gmac_stats_interrupt(pd, 1); + spin_unlock(&pd->lock); + return IRQ_HANDLED; +} + +static inline void s6gmac_set_dstaddr(struct s6gmac *pd, int n, + u32 addrlo, u32 addrhi, u32 masklo, u32 maskhi) +{ + writel(addrlo, pd->reg + S6_GMAC_HOST_DSTADDRLO(n)); + writel(addrhi, pd->reg + S6_GMAC_HOST_DSTADDRHI(n)); + writel(masklo, pd->reg + S6_GMAC_HOST_DSTMASKLO(n)); + writel(maskhi, pd->reg + S6_GMAC_HOST_DSTMASKHI(n)); +} + +static inline void s6gmac_stop_device(struct net_device *dev) +{ + struct s6gmac *pd = netdev_priv(dev); + writel(0, pd->reg + S6_GMAC_MACCONF1); +} + +static inline void s6gmac_init_device(struct net_device *dev) +{ + struct s6gmac *pd = netdev_priv(dev); + int is_rgmii = !!(pd->phydev->supported + & (SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Half)); +#if 0 + writel(1 << S6_GMAC_MACCONF1_SYNCTX | + 1 << S6_GMAC_MACCONF1_SYNCRX | + 1 << S6_GMAC_MACCONF1_TXFLOWCTRL | + 1 << S6_GMAC_MACCONF1_RXFLOWCTRL | + 1 << S6_GMAC_MACCONF1_RESTXFUNC | + 1 << S6_GMAC_MACCONF1_RESRXFUNC | + 1 << S6_GMAC_MACCONF1_RESTXMACCTRL | + 1 << S6_GMAC_MACCONF1_RESRXMACCTRL, + pd->reg + S6_GMAC_MACCONF1); +#endif + writel(1 << S6_GMAC_MACCONF1_SOFTRES, pd->reg + S6_GMAC_MACCONF1); + udelay(1000); + writel(1 << S6_GMAC_MACCONF1_TXENA | 1 << S6_GMAC_MACCONF1_RXENA, + pd->reg + S6_GMAC_MACCONF1); + writel(1 << S6_GMAC_HOST_PBLKCTRL_TXSRES | + 1 << S6_GMAC_HOST_PBLKCTRL_RXSRES, + pd->reg + S6_GMAC_HOST_PBLKCTRL); + writel(S6_GMAC_HOST_PBLKCTRL_SIZ_128 << S6_GMAC_HOST_PBLKCTRL_TXBSIZ | + S6_GMAC_HOST_PBLKCTRL_SIZ_128 << S6_GMAC_HOST_PBLKCTRL_RXBSIZ | + 1 << S6_GMAC_HOST_PBLKCTRL_STATENA | + 1 << S6_GMAC_HOST_PBLKCTRL_STATCLEAR | + is_rgmii << S6_GMAC_HOST_PBLKCTRL_RGMII, + pd->reg + S6_GMAC_HOST_PBLKCTRL); + writel(1 << S6_GMAC_MACCONF1_TXENA | + 1 << S6_GMAC_MACCONF1_RXENA | + (dev->flags & IFF_LOOPBACK ? 1 : 0) + << S6_GMAC_MACCONF1_LOOPBACK, + pd->reg + S6_GMAC_MACCONF1); + writel(dev->mtu && (dev->mtu < (S6_MAX_FRLEN - ETH_HLEN-ETH_FCS_LEN)) ? + dev->mtu+ETH_HLEN+ETH_FCS_LEN : S6_MAX_FRLEN, + pd->reg + S6_GMAC_MACMAXFRAMELEN); + writel((pd->link.full ? 1 : 0) << S6_GMAC_MACCONF2_FULL | + 1 << S6_GMAC_MACCONF2_PADCRCENA | + 1 << S6_GMAC_MACCONF2_LENGTHFCHK | + (pd->link.giga ? + S6_GMAC_MACCONF2_IFMODE_BYTE : + S6_GMAC_MACCONF2_IFMODE_NIBBLE) + << S6_GMAC_MACCONF2_IFMODE | + 7 << S6_GMAC_MACCONF2_PREAMBLELEN, + pd->reg + S6_GMAC_MACCONF2); + writel(0, pd->reg + S6_GMAC_MACSTATADDR1); + writel(0, pd->reg + S6_GMAC_MACSTATADDR2); + writel(1 << S6_GMAC_FIFOCONF0_WTMENREQ | + 1 << S6_GMAC_FIFOCONF0_SRFENREQ | + 1 << S6_GMAC_FIFOCONF0_FRFENREQ | + 1 << S6_GMAC_FIFOCONF0_STFENREQ | + 1 << S6_GMAC_FIFOCONF0_FTFENREQ, + pd->reg + S6_GMAC_FIFOCONF0); + writel(128 << S6_GMAC_FIFOCONF3_CFGFTTH | + 128 << S6_GMAC_FIFOCONF3_CFGHWMFT, + pd->reg + S6_GMAC_FIFOCONF3); + writel((S6_GMAC_FIFOCONF_RSV_MASK & ~( + 1 << S6_GMAC_FIFOCONF_RSV_RUNT | + 1 << S6_GMAC_FIFOCONF_RSV_CRCERR | + 1 << S6_GMAC_FIFOCONF_RSV_OK | + 1 << S6_GMAC_FIFOCONF_RSV_DRIBBLE | + 1 << S6_GMAC_FIFOCONF_RSV_CTRLFRAME | + 1 << S6_GMAC_FIFOCONF_RSV_PAUSECTRL | + 1 << S6_GMAC_FIFOCONF_RSV_UNOPCODE | + 1 << S6_GMAC_FIFOCONF_RSV_TRUNCATED)) | + 1 << S6_GMAC_FIFOCONF5_DROPLT64 | + pd->link.giga << S6_GMAC_FIFOCONF5_CFGBYTM | + 1 << S6_GMAC_FIFOCONF5_RXDROPSIZE, + pd->reg + S6_GMAC_FIFOCONF5); + writel(1 << S6_GMAC_FIFOCONF_RSV_RUNT | + 1 << S6_GMAC_FIFOCONF_RSV_CRCERR | + 1 << S6_GMAC_FIFOCONF_RSV_DRIBBLE | + 1 << S6_GMAC_FIFOCONF_RSV_CTRLFRAME | + 1 << S6_GMAC_FIFOCONF_RSV_PAUSECTRL | + 1 << S6_GMAC_FIFOCONF_RSV_UNOPCODE | + 1 << S6_GMAC_FIFOCONF_RSV_TRUNCATED, + pd->reg + S6_GMAC_FIFOCONF4); + s6gmac_set_dstaddr(pd, 0, + 0xFFFFFFFF, 0x0000FFFF, 0xFFFFFFFF, 0x0000FFFF); + s6gmac_set_dstaddr(pd, 1, + dev->dev_addr[5] | + dev->dev_addr[4] << 8 | + dev->dev_addr[3] << 16 | + dev->dev_addr[2] << 24, + dev->dev_addr[1] | + dev->dev_addr[0] << 8, + 0xFFFFFFFF, 0x0000FFFF); + s6gmac_set_dstaddr(pd, 2, + 0x00000000, 0x00000100, 0x00000000, 0x00000100); + s6gmac_set_dstaddr(pd, 3, + 0x00000000, 0x00000000, 0x00000000, 0x00000000); + writel(1 << S6_GMAC_HOST_PBLKCTRL_TXENA | + 1 << S6_GMAC_HOST_PBLKCTRL_RXENA | + S6_GMAC_HOST_PBLKCTRL_SIZ_128 << S6_GMAC_HOST_PBLKCTRL_TXBSIZ | + S6_GMAC_HOST_PBLKCTRL_SIZ_128 << S6_GMAC_HOST_PBLKCTRL_RXBSIZ | + 1 << S6_GMAC_HOST_PBLKCTRL_STATENA | + 1 << S6_GMAC_HOST_PBLKCTRL_STATCLEAR | + is_rgmii << S6_GMAC_HOST_PBLKCTRL_RGMII, + pd->reg + S6_GMAC_HOST_PBLKCTRL); +} + +static void s6mii_enable(struct s6gmac *pd) +{ + writel(readl(pd->reg + S6_GMAC_MACCONF1) & + ~(1 << S6_GMAC_MACCONF1_SOFTRES), + pd->reg + S6_GMAC_MACCONF1); + writel((readl(pd->reg + S6_GMAC_MACMIICONF) + & ~(S6_GMAC_MACMIICONF_CSEL_MASK << S6_GMAC_MACMIICONF_CSEL)) + | (S6_GMAC_MACMIICONF_CSEL_DIV168 << S6_GMAC_MACMIICONF_CSEL), + pd->reg + S6_GMAC_MACMIICONF); +} + +static int s6mii_busy(struct s6gmac *pd, int tmo) +{ + while (readl(pd->reg + S6_GMAC_MACMIIINDI)) { + if (--tmo == 0) + return -ETIME; + udelay(64); + } + return 0; +} + +static int s6mii_read(struct mii_bus *bus, int phy_addr, int regnum) +{ + struct s6gmac *pd = bus->priv; + s6mii_enable(pd); + if (s6mii_busy(pd, 256)) + return -ETIME; + writel(phy_addr << S6_GMAC_MACMIIADDR_PHY | + regnum << S6_GMAC_MACMIIADDR_REG, + pd->reg + S6_GMAC_MACMIIADDR); + writel(1 << S6_GMAC_MACMIICMD_READ, pd->reg + S6_GMAC_MACMIICMD); + writel(0, pd->reg + S6_GMAC_MACMIICMD); + if (s6mii_busy(pd, 256)) + return -ETIME; + return (u16)readl(pd->reg + S6_GMAC_MACMIISTAT); +} + +static int s6mii_write(struct mii_bus *bus, int phy_addr, int regnum, u16 value) +{ + struct s6gmac *pd = bus->priv; + s6mii_enable(pd); + if (s6mii_busy(pd, 256)) + return -ETIME; + writel(phy_addr << S6_GMAC_MACMIIADDR_PHY | + regnum << S6_GMAC_MACMIIADDR_REG, + pd->reg + S6_GMAC_MACMIIADDR); + writel(value, pd->reg + S6_GMAC_MACMIICTRL); + if (s6mii_busy(pd, 256)) + return -ETIME; + return 0; +} + +static int s6mii_reset(struct mii_bus *bus) +{ + struct s6gmac *pd = bus->priv; + s6mii_enable(pd); + if (s6mii_busy(pd, PHY_INIT_TIMEOUT)) + return -ETIME; + return 0; +} + +static void s6gmac_set_rgmii_txclock(struct s6gmac *pd) +{ + u32 pllsel = readl(S6_REG_GREG1 + S6_GREG1_PLLSEL); + pllsel &= ~(S6_GREG1_PLLSEL_GMAC_MASK << S6_GREG1_PLLSEL_GMAC); + switch (pd->link.mbit) { + case 10: + pllsel |= S6_GREG1_PLLSEL_GMAC_2500KHZ << S6_GREG1_PLLSEL_GMAC; + break; + case 100: + pllsel |= S6_GREG1_PLLSEL_GMAC_25MHZ << S6_GREG1_PLLSEL_GMAC; + break; + case 1000: + pllsel |= S6_GREG1_PLLSEL_GMAC_125MHZ << S6_GREG1_PLLSEL_GMAC; + break; + default: + return; + } + writel(pllsel, S6_REG_GREG1 + S6_GREG1_PLLSEL); +} + +static inline void s6gmac_linkisup(struct net_device *dev, int isup) +{ + struct s6gmac *pd = netdev_priv(dev); + struct phy_device *phydev = pd->phydev; + + pd->link.full = phydev->duplex; + pd->link.giga = (phydev->speed == 1000); + if (pd->link.mbit != phydev->speed) { + pd->link.mbit = phydev->speed; + s6gmac_set_rgmii_txclock(pd); + } + pd->link.isup = isup; + if (isup) + netif_carrier_on(dev); + phy_print_status(phydev); +} + +static void s6gmac_adjust_link(struct net_device *dev) +{ + struct s6gmac *pd = netdev_priv(dev); + struct phy_device *phydev = pd->phydev; + if (pd->link.isup && + (!phydev->link || + (pd->link.mbit != phydev->speed) || + (pd->link.full != phydev->duplex))) { + pd->link.isup = 0; + netif_tx_disable(dev); + if (!phydev->link) { + netif_carrier_off(dev); + phy_print_status(phydev); + } + } + if (!pd->link.isup && phydev->link) { + if (pd->link.full != phydev->duplex) { + u32 maccfg = readl(pd->reg + S6_GMAC_MACCONF2); + if (phydev->duplex) + maccfg |= 1 << S6_GMAC_MACCONF2_FULL; + else + maccfg &= ~(1 << S6_GMAC_MACCONF2_FULL); + writel(maccfg, pd->reg + S6_GMAC_MACCONF2); + } + + if (pd->link.giga != (phydev->speed == 1000)) { + u32 fifocfg = readl(pd->reg + S6_GMAC_FIFOCONF5); + u32 maccfg = readl(pd->reg + S6_GMAC_MACCONF2); + maccfg &= ~(S6_GMAC_MACCONF2_IFMODE_MASK + << S6_GMAC_MACCONF2_IFMODE); + if (phydev->speed == 1000) { + fifocfg |= 1 << S6_GMAC_FIFOCONF5_CFGBYTM; + maccfg |= S6_GMAC_MACCONF2_IFMODE_BYTE + << S6_GMAC_MACCONF2_IFMODE; + } else { + fifocfg &= ~(1 << S6_GMAC_FIFOCONF5_CFGBYTM); + maccfg |= S6_GMAC_MACCONF2_IFMODE_NIBBLE + << S6_GMAC_MACCONF2_IFMODE; + } + writel(fifocfg, pd->reg + S6_GMAC_FIFOCONF5); + writel(maccfg, pd->reg + S6_GMAC_MACCONF2); + } + + if (!s6dmac_fifo_full(pd->tx_dma, pd->tx_chan)) + netif_wake_queue(dev); + s6gmac_linkisup(dev, 1); + } +} + +static inline int s6gmac_phy_start(struct net_device *dev) +{ + struct s6gmac *pd = netdev_priv(dev); + int i = 0; + struct phy_device *p = NULL; + while ((!(p = pd->mii.bus->phy_map[i])) && (i < PHY_MAX_ADDR)) + i++; + p = phy_connect(dev, dev_name(&p->dev), &s6gmac_adjust_link, 0, + PHY_INTERFACE_MODE_RGMII); + if (IS_ERR(p)) { + printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name); + return PTR_ERR(p); + } + p->supported &= PHY_GBIT_FEATURES; + p->advertising = p->supported; + pd->phydev = p; + return 0; +} + +static inline void s6gmac_init_stats(struct net_device *dev) +{ + struct s6gmac *pd = netdev_priv(dev); + u32 mask; + mask = 1 << S6_GMAC_STATCARRY1_RDRP | + 1 << S6_GMAC_STATCARRY1_RJBR | + 1 << S6_GMAC_STATCARRY1_RFRG | + 1 << S6_GMAC_STATCARRY1_ROVR | + 1 << S6_GMAC_STATCARRY1_RUND | + 1 << S6_GMAC_STATCARRY1_RCDE | + 1 << S6_GMAC_STATCARRY1_RFLR | + 1 << S6_GMAC_STATCARRY1_RALN | + 1 << S6_GMAC_STATCARRY1_RMCA | + 1 << S6_GMAC_STATCARRY1_RFCS | + 1 << S6_GMAC_STATCARRY1_RPKT | + 1 << S6_GMAC_STATCARRY1_RBYT; + writel(mask, pd->reg + S6_GMAC_STATCARRY(0)); + writel(~mask, pd->reg + S6_GMAC_STATCARRYMSK(0)); + mask = 1 << S6_GMAC_STATCARRY2_TDRP | + 1 << S6_GMAC_STATCARRY2_TNCL | + 1 << S6_GMAC_STATCARRY2_TXCL | + 1 << S6_GMAC_STATCARRY2_TEDF | + 1 << S6_GMAC_STATCARRY2_TPKT | + 1 << S6_GMAC_STATCARRY2_TBYT | + 1 << S6_GMAC_STATCARRY2_TFRG | + 1 << S6_GMAC_STATCARRY2_TUND | + 1 << S6_GMAC_STATCARRY2_TOVR | + 1 << S6_GMAC_STATCARRY2_TFCS | + 1 << S6_GMAC_STATCARRY2_TJBR; + writel(mask, pd->reg + S6_GMAC_STATCARRY(1)); + writel(~mask, pd->reg + S6_GMAC_STATCARRYMSK(1)); +} + +static inline void s6gmac_init_dmac(struct net_device *dev) +{ + struct s6gmac *pd = netdev_priv(dev); + s6dmac_disable_chan(pd->tx_dma, pd->tx_chan); + s6dmac_disable_chan(pd->rx_dma, pd->rx_chan); + s6dmac_disable_error_irqs(pd->tx_dma, 1 << S6_HIFDMA_GMACTX); + s6dmac_disable_error_irqs(pd->rx_dma, 1 << S6_HIFDMA_GMACRX); +} + +static int s6gmac_tx(struct sk_buff *skb, struct net_device *dev) +{ + struct s6gmac *pd = netdev_priv(dev); + unsigned long flags; + spin_lock_irqsave(&pd->lock, flags); + dev->trans_start = jiffies; + writel(skb->len << S6_GMAC_BURST_PREWR_LEN | + 0 << S6_GMAC_BURST_PREWR_CFE | + 1 << S6_GMAC_BURST_PREWR_PPE | + 1 << S6_GMAC_BURST_PREWR_FCS | + ((skb->len < ETH_ZLEN) ? 1 : 0) << S6_GMAC_BURST_PREWR_PAD, + pd->reg + S6_GMAC_BURST_PREWR); + s6dmac_put_fifo_cache(pd->tx_dma, pd->tx_chan, + (u32)skb->data, pd->io, skb->len); + if (s6dmac_fifo_full(pd->tx_dma, pd->tx_chan)) + netif_stop_queue(dev); + if (((u8)(pd->tx_skb_i - pd->tx_skb_o)) >= S6_NUM_TX_SKB) { + printk(KERN_ERR "GMAC BUG: skb tx ring overflow [%x, %x]\n", + pd->tx_skb_o, pd->tx_skb_i); + BUG(); + } + pd->tx_skb[(pd->tx_skb_i++) % S6_NUM_TX_SKB] = skb; + spin_unlock_irqrestore(&pd->lock, flags); + return 0; +} + +static void s6gmac_tx_timeout(struct net_device *dev) +{ + struct s6gmac *pd = netdev_priv(dev); + unsigned long flags; + spin_lock_irqsave(&pd->lock, flags); + s6gmac_tx_interrupt(dev); + spin_unlock_irqrestore(&pd->lock, flags); +} + +static int s6gmac_open(struct net_device *dev) +{ + struct s6gmac *pd = netdev_priv(dev); + unsigned long flags; + phy_read_status(pd->phydev); + spin_lock_irqsave(&pd->lock, flags); + pd->link.mbit = 0; + s6gmac_linkisup(dev, pd->phydev->link); + s6gmac_init_device(dev); + s6gmac_init_stats(dev); + s6gmac_init_dmac(dev); + s6gmac_rx_fillfifo(pd); + s6dmac_enable_chan(pd->rx_dma, pd->rx_chan, + 2, 1, 0, 1, 0, 0, 0, 7, -1, 2, 0, 1); + s6dmac_enable_chan(pd->tx_dma, pd->tx_chan, + 2, 0, 1, 0, 0, 0, 0, 7, -1, 2, 0, 1); + writel(0 << S6_GMAC_HOST_INT_TXBURSTOVER | + 0 << S6_GMAC_HOST_INT_TXPREWOVER | + 0 << S6_GMAC_HOST_INT_RXBURSTUNDER | + 0 << S6_GMAC_HOST_INT_RXPOSTRFULL | + 0 << S6_GMAC_HOST_INT_RXPOSTRUNDER, + pd->reg + S6_GMAC_HOST_INTMASK); + spin_unlock_irqrestore(&pd->lock, flags); + phy_start(pd->phydev); + netif_start_queue(dev); + return 0; +} + +static int s6gmac_stop(struct net_device *dev) +{ + struct s6gmac *pd = netdev_priv(dev); + unsigned long flags; + netif_stop_queue(dev); + phy_stop(pd->phydev); + spin_lock_irqsave(&pd->lock, flags); + s6gmac_init_dmac(dev); + s6gmac_stop_device(dev); + while (pd->tx_skb_i != pd->tx_skb_o) + dev_kfree_skb(pd->tx_skb[(pd->tx_skb_o++) % S6_NUM_TX_SKB]); + while (pd->rx_skb_i != pd->rx_skb_o) + dev_kfree_skb(pd->rx_skb[(pd->rx_skb_o++) % S6_NUM_RX_SKB]); + spin_unlock_irqrestore(&pd->lock, flags); + return 0; +} + +static struct net_device_stats *s6gmac_stats(struct net_device *dev) +{ + struct s6gmac *pd = netdev_priv(dev); + struct net_device_stats *st = (struct net_device_stats *)&pd->stats; + int i; + do { + unsigned long flags; + spin_lock_irqsave(&pd->lock, flags); + for (i = 0; i < sizeof(pd->stats) / sizeof(unsigned long); i++) + pd->stats[i] = + pd->carry[i] << (S6_GMAC_STAT_SIZE_MIN - 1); + s6gmac_stats_collect(pd, &statinf[0][0]); + s6gmac_stats_collect(pd, &statinf[1][0]); + i = s6gmac_stats_pending(pd, 0) | + s6gmac_stats_pending(pd, 1); + spin_unlock_irqrestore(&pd->lock, flags); + } while (i); + st->rx_errors = st->rx_crc_errors + + st->rx_frame_errors + + st->rx_length_errors + + st->rx_missed_errors; + st->tx_errors += st->tx_aborted_errors; + return st; +} + +static int __devinit s6gmac_probe(struct platform_device *pdev) +{ + struct net_device *dev; + struct s6gmac *pd; + int res; + unsigned long i; + struct mii_bus *mb; + dev = alloc_etherdev(sizeof(*pd)); + if (!dev) { + printk(KERN_ERR DRV_PRMT "etherdev alloc failed, aborting.\n"); + return -ENOMEM; + } + dev->open = s6gmac_open; + dev->stop = s6gmac_stop; + dev->hard_start_xmit = s6gmac_tx; + dev->tx_timeout = s6gmac_tx_timeout; + dev->watchdog_timeo = HZ; + dev->get_stats = s6gmac_stats; + dev->irq = platform_get_irq(pdev, 0); + pd = netdev_priv(dev); + memset(pd, 0, sizeof(*pd)); + spin_lock_init(&pd->lock); + pd->reg = platform_get_resource(pdev, IORESOURCE_MEM, 0)->start; + i = platform_get_resource(pdev, IORESOURCE_DMA, 0)->start; + pd->tx_dma = DMA_MASK_DMAC(i); + pd->tx_chan = DMA_INDEX_CHNL(i); + i = platform_get_resource(pdev, IORESOURCE_DMA, 1)->start; + pd->rx_dma = DMA_MASK_DMAC(i); + pd->rx_chan = DMA_INDEX_CHNL(i); + pd->io = platform_get_resource(pdev, IORESOURCE_IO, 0)->start; + res = request_irq(dev->irq, &s6gmac_interrupt, 0, dev->name, dev); + if (res) { + printk(KERN_ERR DRV_PRMT "irq request failed: %d\n", dev->irq); + goto errirq; + } + res = register_netdev(dev); + if (res) { + printk(KERN_ERR DRV_PRMT "error registering device %s\n", + dev->name); + goto errdev; + } + mb = mdiobus_alloc(); + if (!mb) { + printk(KERN_ERR DRV_PRMT "error allocating mii bus\n"); + goto errmii; + } + mb->name = "s6gmac_mii"; + mb->read = s6mii_read; + mb->write = s6mii_write; + mb->reset = s6mii_reset; + mb->priv = pd; + snprintf(mb->id, MII_BUS_ID_SIZE, "0"); + mb->phy_mask = ~(1 << 0); + mb->irq = &pd->mii.irq[0]; + for (i = 0; i < PHY_MAX_ADDR; i++) { + int n = platform_get_irq(pdev, i + 1); + if (n < 0) + n = PHY_POLL; + pd->mii.irq[i] = n; + } + mdiobus_register(mb); + pd->mii.bus = mb; + res = s6gmac_phy_start(dev); + if (res) + return res; + platform_set_drvdata(pdev, dev); + return 0; +errmii: + unregister_netdev(dev); +errdev: + free_irq(dev->irq, dev); +errirq: + free_netdev(dev); + return res; +} + +static int __devexit s6gmac_remove(struct platform_device *pdev) +{ + struct net_device *dev = platform_get_drvdata(pdev); + if (dev) { + struct s6gmac *pd = netdev_priv(dev); + mdiobus_unregister(pd->mii.bus); + unregister_netdev(dev); + free_irq(dev->irq, dev); + free_netdev(dev); + platform_set_drvdata(pdev, NULL); + } + return 0; +} + +static struct platform_driver s6gmac_driver = { + .probe = s6gmac_probe, + .remove = __devexit_p(s6gmac_remove), + .driver = { + .name = "s6gmac", + .owner = THIS_MODULE, + }, +}; + +static int __init s6gmac_init(void) +{ + printk(KERN_INFO DRV_PRMT "S6 GMAC ethernet driver\n"); + return platform_driver_register(&s6gmac_driver); +} + + +static void __exit s6gmac_exit(void) +{ + platform_driver_unregister(&s6gmac_driver); +} + +module_init(s6gmac_init); +module_exit(s6gmac_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("S6105 on chip Ethernet driver"); +MODULE_AUTHOR("Oskar Schirmer "); diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c index ce7551e17ba7..d8c9cf1b901d 100644 --- a/drivers/net/sb1250-mac.c +++ b/drivers/net/sb1250-mac.c @@ -2084,7 +2084,7 @@ static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); spin_unlock_irqrestore(&sc->sbm_lock, flags); - return 1; + return NETDEV_TX_BUSY; } dev->trans_start = jiffies; @@ -2271,6 +2271,21 @@ static int sb1250_change_mtu(struct net_device *_dev, int new_mtu) return 0; } +static const struct net_device_ops sbmac_netdev_ops = { + .ndo_open = sbmac_open, + .ndo_stop = sbmac_close, + .ndo_start_xmit = sbmac_start_tx, + .ndo_set_multicast_list = sbmac_set_rx_mode, + .ndo_tx_timeout = sbmac_tx_timeout, + .ndo_do_ioctl = sbmac_mii_ioctl, + .ndo_change_mtu = sb1250_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = sbmac_netpoll, +#endif +}; + /********************************************************************** * SBMAC_INIT(dev) * @@ -2285,7 +2300,7 @@ static int sb1250_change_mtu(struct net_device *_dev, int new_mtu) static int sbmac_init(struct platform_device *pldev, long long base) { - struct net_device *dev = pldev->dev.driver_data; + struct net_device *dev = dev_get_drvdata(&pldev->dev); int idx = pldev->id; struct sbmac_softc *sc = netdev_priv(dev); unsigned char *eaddr; @@ -2327,21 +2342,11 @@ static int sbmac_init(struct platform_device *pldev, long long base) spin_lock_init(&(sc->sbm_lock)); - dev->open = sbmac_open; - dev->hard_start_xmit = sbmac_start_tx; - dev->stop = sbmac_close; - dev->set_multicast_list = sbmac_set_rx_mode; - dev->do_ioctl = sbmac_mii_ioctl; - dev->tx_timeout = sbmac_tx_timeout; - dev->watchdog_timeo = TX_TIMEOUT; + dev->netdev_ops = &sbmac_netdev_ops; + dev->watchdog_timeo = TX_TIMEOUT; netif_napi_add(dev, &sc->napi, sbmac_poll, 16); - dev->change_mtu = sb1250_change_mtu; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = sbmac_netpoll; -#endif - dev->irq = UNIT_INT(idx); /* This is needed for PASS2 for Rx H/W checksum feature */ @@ -2726,7 +2731,7 @@ static int __init sbmac_probe(struct platform_device *pldev) goto out_unmap; } - pldev->dev.driver_data = dev; + dev_set_drvdata(&pldev->dev, dev); SET_NETDEV_DEV(dev, &pldev->dev); sc = netdev_priv(dev); @@ -2751,7 +2756,7 @@ out_out: static int __exit sbmac_remove(struct platform_device *pldev) { - struct net_device *dev = pldev->dev.driver_data; + struct net_device *dev = dev_get_drvdata(&pldev->dev); struct sbmac_softc *sc = netdev_priv(dev); unregister_netdev(dev); diff --git a/drivers/net/sfc/Kconfig b/drivers/net/sfc/Kconfig index 12a82966b577..260aafaac235 100644 --- a/drivers/net/sfc/Kconfig +++ b/drivers/net/sfc/Kconfig @@ -1,7 +1,7 @@ config SFC tristate "Solarflare Solarstorm SFC4000 support" depends on PCI && INET - select MII + select MDIO select CRC32 select I2C select I2C_ALGOBIT diff --git a/drivers/net/sfc/boards.c b/drivers/net/sfc/boards.c index 5182ac5a1034..4a4c74c891b7 100644 --- a/drivers/net/sfc/boards.c +++ b/drivers/net/sfc/boards.c @@ -172,7 +172,6 @@ static const u8 sfe4002_lm87_regs[] = { static struct i2c_board_info sfe4002_hwmon_info = { I2C_BOARD_INFO("lm87", 0x2e), .platform_data = &sfe4002_lm87_channel, - .irq = -1, }; /****************************************************************************/ @@ -247,7 +246,6 @@ static const u8 sfn4112f_lm87_regs[] = { static struct i2c_board_info sfn4112f_hwmon_info = { I2C_BOARD_INFO("lm87", 0x2e), .platform_data = &sfn4112f_lm87_channel, - .irq = -1, }; #define SFN4112F_ACT_LED 0 diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 7269a426051c..343e8da1fa30 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -49,16 +49,6 @@ static struct workqueue_struct *reset_workqueue; * *************************************************************************/ -/* - * Enable large receive offload (LRO) aka soft segment reassembly (SSR) - * - * This sets the default for new devices. It can be controlled later - * using ethtool. - */ -static int lro = true; -module_param(lro, int, 0644); -MODULE_PARM_DESC(lro, "Large receive offload acceleration"); - /* * Use separate channels for TX and RX events * @@ -894,9 +884,9 @@ static int efx_wanted_rx_queues(void) int count; int cpu; - if (!alloc_cpumask_var(&core_mask, GFP_KERNEL)) { + if (unlikely(!alloc_cpumask_var(&core_mask, GFP_KERNEL))) { printk(KERN_WARNING - "efx.c: allocation failure, irq balancing hobbled\n"); + "sfc: RSS disabled due to allocation failure\n"); return 1; } @@ -1300,10 +1290,16 @@ out_requeue: static int efx_ioctl(struct net_device *net_dev, struct ifreq *ifr, int cmd) { struct efx_nic *efx = netdev_priv(net_dev); + struct mii_ioctl_data *data = if_mii(ifr); EFX_ASSERT_RESET_SERIALISED(efx); - return generic_mii_ioctl(&efx->mii, if_mii(ifr), cmd, NULL); + /* Convert phy_id from older PRTAD/DEVAD format */ + if ((cmd == SIOCGMIIREG || cmd == SIOCSMIIREG) && + (data->phy_id & 0xfc00) == 0x0400) + data->phy_id ^= MDIO_PHY_ID_C45 | 0x0400; + + return mdio_mii_ioctl(&efx->mdio, data, cmd); } /************************************************************************** @@ -1945,7 +1941,7 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type, mutex_init(&efx->mac_lock); efx->mac_op = &efx_dummy_mac_operations; efx->phy_op = &efx_dummy_phy_operations; - efx->mii.dev = net_dev; + efx->mdio.dev = net_dev; INIT_WORK(&efx->phy_work, efx_phy_work); INIT_WORK(&efx->mac_work, efx_mac_work); atomic_set(&efx->netif_stop_count, 1); @@ -2161,9 +2157,8 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev, if (!net_dev) return -ENOMEM; net_dev->features |= (NETIF_F_IP_CSUM | NETIF_F_SG | - NETIF_F_HIGHDMA | NETIF_F_TSO); - if (lro) - net_dev->features |= NETIF_F_GRO; + NETIF_F_HIGHDMA | NETIF_F_TSO | + NETIF_F_GRO); /* Mask for features that also apply to VLAN devices */ net_dev->vlan_features |= (NETIF_F_ALL_CSUM | NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_TSO); diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index 64309f4e8b19..997ea2a3d53f 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c @@ -10,6 +10,7 @@ #include #include +#include #include #include "net_driver.h" #include "workarounds.h" @@ -345,8 +346,8 @@ static int efx_ethtool_fill_self_tests(struct efx_nic *efx, unsigned int n = 0, i; enum efx_loopback_mode mode; - efx_fill_test(n++, strings, data, &tests->mii, - "core", 0, "mii", NULL); + efx_fill_test(n++, strings, data, &tests->mdio, + "core", 0, "mdio", NULL); efx_fill_test(n++, strings, data, &tests->nvram, "core", 0, "nvram", NULL); efx_fill_test(n++, strings, data, &tests->interrupt, @@ -529,14 +530,7 @@ static int efx_ethtool_nway_reset(struct net_device *net_dev) { struct efx_nic *efx = netdev_priv(net_dev); - if (efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_AN)) { - mdio_clause45_set_flag(efx, efx->mii.phy_id, MDIO_MMD_AN, - MDIO_MMDREG_CTRL1, - __ffs(BMCR_ANRESTART), true); - return 0; - } - - return -EOPNOTSUPP; + return mdio45_nway_restart(&efx->mdio); } static u32 efx_ethtool_get_link(struct net_device *net_dev) @@ -689,7 +683,7 @@ static int efx_ethtool_set_pauseparam(struct net_device *net_dev, return -EINVAL; } - if (!(efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_AN)) && + if (!(efx->phy_op->mmds & MDIO_DEVS_AN) && (wanted_fc & EFX_FC_AUTO)) { EFX_LOG(efx, "PHY does not support flow control " "autonegotiation\n"); @@ -717,7 +711,8 @@ static int efx_ethtool_set_pauseparam(struct net_device *net_dev, mutex_lock(&efx->mac_lock); efx->wanted_fc = wanted_fc; - mdio_clause45_set_pause(efx); + if (efx->phy_op->mmds & MDIO_DEVS_AN) + mdio45_ethtool_spauseparam_an(&efx->mdio, pause); __efx_reconfigure_port(efx); mutex_unlock(&efx->mac_lock); diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index 466a8abb0053..c049364aec46 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -2063,26 +2063,6 @@ int falcon_dma_stats(struct efx_nic *efx, unsigned int done_offset) ************************************************************************** */ -/* Use the top bit of the MII PHY id to indicate the PHY type - * (1G/10G), with the remaining bits as the actual PHY id. - * - * This allows us to avoid leaking information from the mii_if_info - * structure into other data structures. - */ -#define FALCON_PHY_ID_ID_WIDTH EFX_WIDTH(MD_PRT_DEV_ADR) -#define FALCON_PHY_ID_ID_MASK ((1 << FALCON_PHY_ID_ID_WIDTH) - 1) -#define FALCON_PHY_ID_WIDTH (FALCON_PHY_ID_ID_WIDTH + 1) -#define FALCON_PHY_ID_MASK ((1 << FALCON_PHY_ID_WIDTH) - 1) -#define FALCON_PHY_ID_10G (1 << (FALCON_PHY_ID_WIDTH - 1)) - - -/* Packing the clause 45 port and device fields into a single value */ -#define MD_PRT_ADR_COMP_LBN (MD_PRT_ADR_LBN - MD_DEV_ADR_LBN) -#define MD_PRT_ADR_COMP_WIDTH MD_PRT_ADR_WIDTH -#define MD_DEV_ADR_COMP_LBN 0 -#define MD_DEV_ADR_COMP_WIDTH MD_DEV_ADR_WIDTH - - /* Wait for GMII access to complete */ static int falcon_gmii_wait(struct efx_nic *efx) { @@ -2108,49 +2088,29 @@ static int falcon_gmii_wait(struct efx_nic *efx) return -ETIMEDOUT; } -/* Writes a GMII register of a PHY connected to Falcon using MDIO. */ -static void falcon_mdio_write(struct net_device *net_dev, int phy_id, - int addr, int value) +/* Write an MDIO register of a PHY connected to Falcon. */ +static int falcon_mdio_write(struct net_device *net_dev, + int prtad, int devad, u16 addr, u16 value) { struct efx_nic *efx = netdev_priv(net_dev); - unsigned int phy_id2 = phy_id & FALCON_PHY_ID_ID_MASK; efx_oword_t reg; + int rc; - /* The 'generic' prt/dev packing in mdio_10g.h is conveniently - * chosen so that the only current user, Falcon, can take the - * packed value and use them directly. - * Fail to build if this assumption is broken. - */ - BUILD_BUG_ON(FALCON_PHY_ID_10G != MDIO45_XPRT_ID_IS10G); - BUILD_BUG_ON(FALCON_PHY_ID_ID_WIDTH != MDIO45_PRT_DEV_WIDTH); - BUILD_BUG_ON(MD_PRT_ADR_COMP_LBN != MDIO45_PRT_ID_COMP_LBN); - BUILD_BUG_ON(MD_DEV_ADR_COMP_LBN != MDIO45_DEV_ID_COMP_LBN); - - if (phy_id2 == PHY_ADDR_INVALID) - return; - - /* See falcon_mdio_read for an explanation. */ - if (!(phy_id & FALCON_PHY_ID_10G)) { - int mmd = ffs(efx->phy_op->mmds) - 1; - EFX_TRACE(efx, "Fixing erroneous clause22 write\n"); - phy_id2 = mdio_clause45_pack(phy_id2, mmd) - & FALCON_PHY_ID_ID_MASK; - } - - EFX_REGDUMP(efx, "writing GMII %d register %02x with %04x\n", phy_id, - addr, value); + EFX_REGDUMP(efx, "writing MDIO %d register %d.%d with 0x%04x\n", + prtad, devad, addr, value); spin_lock_bh(&efx->phy_lock); - /* Check MII not currently being accessed */ - if (falcon_gmii_wait(efx) != 0) + /* Check MDIO not currently being accessed */ + rc = falcon_gmii_wait(efx); + if (rc) goto out; /* Write the address/ID register */ EFX_POPULATE_OWORD_1(reg, MD_PHY_ADR, addr); falcon_write(efx, ®, MD_PHY_ADR_REG_KER); - EFX_POPULATE_OWORD_1(reg, MD_PRT_DEV_ADR, phy_id2); + EFX_POPULATE_OWORD_2(reg, MD_PRT_ADR, prtad, MD_DEV_ADR, devad); falcon_write(efx, ®, MD_ID_REG_KER); /* Write data */ @@ -2163,7 +2123,8 @@ static void falcon_mdio_write(struct net_device *net_dev, int phy_id, falcon_write(efx, ®, MD_CS_REG_KER); /* Wait for data to be written */ - if (falcon_gmii_wait(efx) != 0) { + rc = falcon_gmii_wait(efx); + if (rc) { /* Abort the write operation */ EFX_POPULATE_OWORD_2(reg, MD_WRC, 0, @@ -2174,45 +2135,28 @@ static void falcon_mdio_write(struct net_device *net_dev, int phy_id, out: spin_unlock_bh(&efx->phy_lock); + return rc; } -/* Reads a GMII register from a PHY connected to Falcon. If no value - * could be read, -1 will be returned. */ -static int falcon_mdio_read(struct net_device *net_dev, int phy_id, int addr) +/* Read an MDIO register of a PHY connected to Falcon. */ +static int falcon_mdio_read(struct net_device *net_dev, + int prtad, int devad, u16 addr) { struct efx_nic *efx = netdev_priv(net_dev); - unsigned int phy_addr = phy_id & FALCON_PHY_ID_ID_MASK; efx_oword_t reg; - int value = -1; - - if (phy_addr == PHY_ADDR_INVALID) - return -1; - - /* Our PHY code knows whether it needs to talk clause 22(1G) or 45(10G) - * but the generic Linux code does not make any distinction or have - * any state for this. - * We spot the case where someone tried to talk 22 to a 45 PHY and - * redirect the request to the lowest numbered MMD as a clause45 - * request. This is enough to allow simple queries like id and link - * state to succeed. TODO: We may need to do more in future. - */ - if (!(phy_id & FALCON_PHY_ID_10G)) { - int mmd = ffs(efx->phy_op->mmds) - 1; - EFX_TRACE(efx, "Fixing erroneous clause22 read\n"); - phy_addr = mdio_clause45_pack(phy_addr, mmd) - & FALCON_PHY_ID_ID_MASK; - } + int rc; spin_lock_bh(&efx->phy_lock); - /* Check MII not currently being accessed */ - if (falcon_gmii_wait(efx) != 0) + /* Check MDIO not currently being accessed */ + rc = falcon_gmii_wait(efx); + if (rc) goto out; EFX_POPULATE_OWORD_1(reg, MD_PHY_ADR, addr); falcon_write(efx, ®, MD_PHY_ADR_REG_KER); - EFX_POPULATE_OWORD_1(reg, MD_PRT_DEV_ADR, phy_addr); + EFX_POPULATE_OWORD_2(reg, MD_PRT_ADR, prtad, MD_DEV_ADR, devad); falcon_write(efx, ®, MD_ID_REG_KER); /* Request data to be read */ @@ -2220,12 +2164,12 @@ static int falcon_mdio_read(struct net_device *net_dev, int phy_id, int addr) falcon_write(efx, ®, MD_CS_REG_KER); /* Wait for data to become available */ - value = falcon_gmii_wait(efx); - if (value == 0) { + rc = falcon_gmii_wait(efx); + if (rc == 0) { falcon_read(efx, ®, MD_RXD_REG_KER); - value = EFX_OWORD_FIELD(reg, MD_RXD); - EFX_REGDUMP(efx, "read from GMII %d register %02x, got %04x\n", - phy_id, addr, value); + rc = EFX_OWORD_FIELD(reg, MD_RXD); + EFX_REGDUMP(efx, "read from MDIO %d register %d.%d, got %04x\n", + prtad, devad, addr, rc); } else { /* Abort the read operation */ EFX_POPULATE_OWORD_2(reg, @@ -2233,22 +2177,13 @@ static int falcon_mdio_read(struct net_device *net_dev, int phy_id, int addr) MD_GC, 1); falcon_write(efx, ®, MD_CS_REG_KER); - EFX_LOG(efx, "read from GMII 0x%x register %02x, got " - "error %d\n", phy_id, addr, value); + EFX_LOG(efx, "read from MDIO %d register %d.%d, got error %d\n", + prtad, devad, addr, rc); } out: spin_unlock_bh(&efx->phy_lock); - - return value; -} - -static void falcon_init_mdio(struct mii_if_info *gmii) -{ - gmii->mdio_read = falcon_mdio_read; - gmii->mdio_write = falcon_mdio_write; - gmii->phy_id_mask = FALCON_PHY_ID_MASK; - gmii->reg_num_mask = ((1 << EFX_WIDTH(MD_PHY_ADR)) - 1); + return rc; } static int falcon_probe_phy(struct efx_nic *efx) @@ -2342,9 +2277,11 @@ int falcon_probe_port(struct efx_nic *efx) if (rc) return rc; - /* Set up GMII structure for PHY */ - efx->mii.supports_gmii = true; - falcon_init_mdio(&efx->mii); + /* Set up MDIO structure for PHY */ + efx->mdio.mmds = efx->phy_op->mmds; + efx->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22; + efx->mdio.mdio_read = falcon_mdio_read; + efx->mdio.mdio_write = falcon_mdio_write; /* Hardware flow ctrl. FalconA RX FIFO too small for pause generation */ if (falcon_rev(efx) >= FALCON_REV_B0) @@ -2761,7 +2698,7 @@ static int falcon_probe_nvconfig(struct efx_nic *efx) if (rc == -EINVAL) { EFX_ERR(efx, "NVRAM is invalid therefore using defaults\n"); efx->phy_type = PHY_TYPE_NONE; - efx->mii.phy_id = PHY_ADDR_INVALID; + efx->mdio.prtad = MDIO_PRTAD_NONE; board_rev = 0; rc = 0; } else if (rc) { @@ -2771,7 +2708,7 @@ static int falcon_probe_nvconfig(struct efx_nic *efx) struct falcon_nvconfig_board_v3 *v3 = &nvconfig->board_v3; efx->phy_type = v2->port0_phy_type; - efx->mii.phy_id = v2->port0_phy_addr; + efx->mdio.prtad = v2->port0_phy_addr; board_rev = le16_to_cpu(v2->board_revision); if (le16_to_cpu(nvconfig->board_struct_ver) >= 3) { @@ -2793,7 +2730,7 @@ static int falcon_probe_nvconfig(struct efx_nic *efx) /* Read the MAC addresses */ memcpy(efx->mac_address, nvconfig->mac_address[0], ETH_ALEN); - EFX_LOG(efx, "PHY is %d phy_id %d\n", efx->phy_type, efx->mii.phy_id); + EFX_LOG(efx, "PHY is %d phy_id %d\n", efx->phy_type, efx->mdio.prtad); efx_set_board_info(efx, board_rev); diff --git a/drivers/net/sfc/falcon_hwdefs.h b/drivers/net/sfc/falcon_hwdefs.h index bda8d5bb72e4..375e2a5961ec 100644 --- a/drivers/net/sfc/falcon_hwdefs.h +++ b/drivers/net/sfc/falcon_hwdefs.h @@ -456,9 +456,6 @@ #define MD_PRT_ADR_WIDTH 5 #define MD_DEV_ADR_LBN 6 #define MD_DEV_ADR_WIDTH 5 -/* Used for writing both at once */ -#define MD_PRT_DEV_ADR_LBN 6 -#define MD_PRT_DEV_ADR_WIDTH 10 /* PHY management status & mask register (DWORD read only) */ #define MD_STAT_REG_KER 0xc50 diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c index 5a03713685ac..2b3269c03263 100644 --- a/drivers/net/sfc/falcon_xmac.c +++ b/drivers/net/sfc/falcon_xmac.c @@ -133,7 +133,7 @@ bool falcon_xaui_link_ok(struct efx_nic *efx) /* If the link is up, then check the phy side of the xaui link */ if (efx->link_up && link_ok) if (efx->phy_op->mmds & (1 << MDIO_MMD_PHYXS)) - link_ok = mdio_clause45_phyxgxs_lane_sync(efx); + link_ok = efx_mdio_phyxgxs_lane_sync(efx); return link_ok; } diff --git a/drivers/net/sfc/mdio_10g.c b/drivers/net/sfc/mdio_10g.c index 9f5ec3eb3418..6c33459f9ea9 100644 --- a/drivers/net/sfc/mdio_10g.c +++ b/drivers/net/sfc/mdio_10g.c @@ -17,7 +17,7 @@ #include "boards.h" #include "workarounds.h" -unsigned mdio_id_oui(u32 id) +unsigned efx_mdio_id_oui(u32 id) { unsigned oui = 0; int i; @@ -32,52 +32,45 @@ unsigned mdio_id_oui(u32 id) return oui; } -int mdio_clause45_reset_mmd(struct efx_nic *port, int mmd, +int efx_mdio_reset_mmd(struct efx_nic *port, int mmd, int spins, int spintime) { u32 ctrl; - int phy_id = port->mii.phy_id; /* Catch callers passing values in the wrong units (or just silly) */ EFX_BUG_ON_PARANOID(spins * spintime >= 5000); - mdio_clause45_write(port, phy_id, mmd, MDIO_MMDREG_CTRL1, - (1 << MDIO_MMDREG_CTRL1_RESET_LBN)); + efx_mdio_write(port, mmd, MDIO_CTRL1, MDIO_CTRL1_RESET); /* Wait for the reset bit to clear. */ do { msleep(spintime); - ctrl = mdio_clause45_read(port, phy_id, mmd, MDIO_MMDREG_CTRL1); + ctrl = efx_mdio_read(port, mmd, MDIO_CTRL1); spins--; - } while (spins && (ctrl & (1 << MDIO_MMDREG_CTRL1_RESET_LBN))); + } while (spins && (ctrl & MDIO_CTRL1_RESET)); return spins ? spins : -ETIMEDOUT; } -static int mdio_clause45_check_mmd(struct efx_nic *efx, int mmd, - int fault_fatal) +static int efx_mdio_check_mmd(struct efx_nic *efx, int mmd, int fault_fatal) { int status; - int phy_id = efx->mii.phy_id; if (LOOPBACK_INTERNAL(efx)) return 0; if (mmd != MDIO_MMD_AN) { /* Read MMD STATUS2 to check it is responding. */ - status = mdio_clause45_read(efx, phy_id, mmd, - MDIO_MMDREG_STAT2); - if (((status >> MDIO_MMDREG_STAT2_PRESENT_LBN) & - ((1 << MDIO_MMDREG_STAT2_PRESENT_WIDTH) - 1)) != - MDIO_MMDREG_STAT2_PRESENT_VAL) { + status = efx_mdio_read(efx, mmd, MDIO_STAT2); + if ((status & MDIO_STAT2_DEVPRST) != MDIO_STAT2_DEVPRST_VAL) { EFX_ERR(efx, "PHY MMD %d not responding.\n", mmd); return -EIO; } } /* Read MMD STATUS 1 to check for fault. */ - status = mdio_clause45_read(efx, phy_id, mmd, MDIO_MMDREG_STAT1); - if ((status & (1 << MDIO_MMDREG_STAT1_FAULT_LBN)) != 0) { + status = efx_mdio_read(efx, mmd, MDIO_STAT1); + if (status & MDIO_STAT1_FAULT) { if (fault_fatal) { EFX_ERR(efx, "PHY MMD %d reporting fatal" " fault: status %x\n", mmd, status); @@ -94,8 +87,7 @@ static int mdio_clause45_check_mmd(struct efx_nic *efx, int mmd, #define MDIO45_RESET_TIME 1000 /* ms */ #define MDIO45_RESET_ITERS 100 -int mdio_clause45_wait_reset_mmds(struct efx_nic *efx, - unsigned int mmd_mask) +int efx_mdio_wait_reset_mmds(struct efx_nic *efx, unsigned int mmd_mask) { const int spintime = MDIO45_RESET_TIME / MDIO45_RESET_ITERS; int tries = MDIO45_RESET_ITERS; @@ -109,16 +101,13 @@ int mdio_clause45_wait_reset_mmds(struct efx_nic *efx, in_reset = 0; while (mask) { if (mask & 1) { - stat = mdio_clause45_read(efx, - efx->mii.phy_id, - mmd, - MDIO_MMDREG_CTRL1); + stat = efx_mdio_read(efx, mmd, MDIO_CTRL1); if (stat < 0) { EFX_ERR(efx, "failed to read status of" " MMD %d\n", mmd); return -EIO; } - if (stat & (1 << MDIO_MMDREG_CTRL1_RESET_LBN)) + if (stat & MDIO_CTRL1_RESET) in_reset |= (1 << mmd); } mask = mask >> 1; @@ -137,28 +126,26 @@ int mdio_clause45_wait_reset_mmds(struct efx_nic *efx, return rc; } -int mdio_clause45_check_mmds(struct efx_nic *efx, - unsigned int mmd_mask, unsigned int fatal_mask) +int efx_mdio_check_mmds(struct efx_nic *efx, + unsigned int mmd_mask, unsigned int fatal_mask) { - int mmd = 0, probe_mmd, devs0, devs1; + int mmd = 0, probe_mmd, devs1, devs2; u32 devices; /* Historically we have probed the PHYXS to find out what devices are * present,but that doesn't work so well if the PHYXS isn't expected * to exist, if so just find the first item in the list supplied. */ - probe_mmd = (mmd_mask & MDIO_MMDREG_DEVS_PHYXS) ? MDIO_MMD_PHYXS : + probe_mmd = (mmd_mask & MDIO_DEVS_PHYXS) ? MDIO_MMD_PHYXS : __ffs(mmd_mask); /* Check all the expected MMDs are present */ - devs0 = mdio_clause45_read(efx, efx->mii.phy_id, - probe_mmd, MDIO_MMDREG_DEVS0); - devs1 = mdio_clause45_read(efx, efx->mii.phy_id, - probe_mmd, MDIO_MMDREG_DEVS1); - if (devs0 < 0 || devs1 < 0) { + devs1 = efx_mdio_read(efx, probe_mmd, MDIO_DEVS1); + devs2 = efx_mdio_read(efx, probe_mmd, MDIO_DEVS2); + if (devs1 < 0 || devs2 < 0) { EFX_ERR(efx, "failed to read devices present\n"); return -EIO; } - devices = devs0 | (devs1 << 16); + devices = devs1 | (devs2 << 16); if ((devices & mmd_mask) != mmd_mask) { EFX_ERR(efx, "required MMDs not present: got %x, " "wanted %x\n", devices, mmd_mask); @@ -170,7 +157,7 @@ int mdio_clause45_check_mmds(struct efx_nic *efx, while (mmd_mask) { if (mmd_mask & 1) { int fault_fatal = fatal_mask & 1; - if (mdio_clause45_check_mmd(efx, mmd, fault_fatal)) + if (efx_mdio_check_mmd(efx, mmd, fault_fatal)) return -EIO; } mmd_mask = mmd_mask >> 1; @@ -181,13 +168,8 @@ int mdio_clause45_check_mmds(struct efx_nic *efx, return 0; } -bool mdio_clause45_links_ok(struct efx_nic *efx, unsigned int mmd_mask) +bool efx_mdio_links_ok(struct efx_nic *efx, unsigned int mmd_mask) { - int phy_id = efx->mii.phy_id; - u32 reg; - bool ok = true; - int mmd = 0; - /* If the port is in loopback, then we should only consider a subset * of mmd's */ if (LOOPBACK_INTERNAL(efx)) @@ -197,241 +179,75 @@ bool mdio_clause45_links_ok(struct efx_nic *efx, unsigned int mmd_mask) else if (efx_phy_mode_disabled(efx->phy_mode)) return false; else if (efx->loopback_mode == LOOPBACK_PHYXS) - mmd_mask &= ~(MDIO_MMDREG_DEVS_PHYXS | - MDIO_MMDREG_DEVS_PCS | - MDIO_MMDREG_DEVS_PMAPMD | - MDIO_MMDREG_DEVS_AN); + mmd_mask &= ~(MDIO_DEVS_PHYXS | + MDIO_DEVS_PCS | + MDIO_DEVS_PMAPMD | + MDIO_DEVS_AN); else if (efx->loopback_mode == LOOPBACK_PCS) - mmd_mask &= ~(MDIO_MMDREG_DEVS_PCS | - MDIO_MMDREG_DEVS_PMAPMD | - MDIO_MMDREG_DEVS_AN); + mmd_mask &= ~(MDIO_DEVS_PCS | + MDIO_DEVS_PMAPMD | + MDIO_DEVS_AN); else if (efx->loopback_mode == LOOPBACK_PMAPMD) - mmd_mask &= ~(MDIO_MMDREG_DEVS_PMAPMD | - MDIO_MMDREG_DEVS_AN); + mmd_mask &= ~(MDIO_DEVS_PMAPMD | + MDIO_DEVS_AN); - if (!mmd_mask) { - /* Use presence of XGMII faults in leui of link state */ - reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PHYXS, - MDIO_PHYXS_STATUS2); - return !(reg & (1 << MDIO_PHYXS_STATUS2_RX_FAULT_LBN)); - } - - while (mmd_mask) { - if (mmd_mask & 1) { - /* Double reads because link state is latched, and a - * read moves the current state into the register */ - reg = mdio_clause45_read(efx, phy_id, - mmd, MDIO_MMDREG_STAT1); - reg = mdio_clause45_read(efx, phy_id, - mmd, MDIO_MMDREG_STAT1); - ok = ok && (reg & (1 << MDIO_MMDREG_STAT1_LINK_LBN)); - } - mmd_mask = (mmd_mask >> 1); - mmd++; - } - return ok; + return mdio45_links_ok(&efx->mdio, mmd_mask); } -void mdio_clause45_transmit_disable(struct efx_nic *efx) +void efx_mdio_transmit_disable(struct efx_nic *efx) { - mdio_clause45_set_flag(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, - MDIO_MMDREG_TXDIS, MDIO_MMDREG_TXDIS_GLOBAL_LBN, - efx->phy_mode & PHY_MODE_TX_DISABLED); + efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD, + MDIO_PMA_TXDIS, MDIO_PMD_TXDIS_GLOBAL, + efx->phy_mode & PHY_MODE_TX_DISABLED); } -void mdio_clause45_phy_reconfigure(struct efx_nic *efx) +void efx_mdio_phy_reconfigure(struct efx_nic *efx) { - int phy_id = efx->mii.phy_id; - - mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_PMAPMD, - MDIO_MMDREG_CTRL1, MDIO_PMAPMD_CTRL1_LBACK_LBN, - efx->loopback_mode == LOOPBACK_PMAPMD); - mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_PCS, - MDIO_MMDREG_CTRL1, MDIO_MMDREG_CTRL1_LBACK_LBN, - efx->loopback_mode == LOOPBACK_PCS); - mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_PHYXS, - MDIO_MMDREG_CTRL1, MDIO_MMDREG_CTRL1_LBACK_LBN, - efx->loopback_mode == LOOPBACK_NETWORK); + efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD, + MDIO_CTRL1, MDIO_PMA_CTRL1_LOOPBACK, + efx->loopback_mode == LOOPBACK_PMAPMD); + efx_mdio_set_flag(efx, MDIO_MMD_PCS, + MDIO_CTRL1, MDIO_PCS_CTRL1_LOOPBACK, + efx->loopback_mode == LOOPBACK_PCS); + efx_mdio_set_flag(efx, MDIO_MMD_PHYXS, + MDIO_CTRL1, MDIO_PHYXS_CTRL1_LOOPBACK, + efx->loopback_mode == LOOPBACK_NETWORK); } -static void mdio_clause45_set_mmd_lpower(struct efx_nic *efx, - int lpower, int mmd) +static void efx_mdio_set_mmd_lpower(struct efx_nic *efx, + int lpower, int mmd) { - int phy = efx->mii.phy_id; - int stat = mdio_clause45_read(efx, phy, mmd, MDIO_MMDREG_STAT1); + int stat = efx_mdio_read(efx, mmd, MDIO_STAT1); EFX_TRACE(efx, "Setting low power mode for MMD %d to %d\n", mmd, lpower); - if (stat & (1 << MDIO_MMDREG_STAT1_LPABLE_LBN)) { - mdio_clause45_set_flag(efx, phy, mmd, MDIO_MMDREG_CTRL1, - MDIO_MMDREG_CTRL1_LPOWER_LBN, lpower); + if (stat & MDIO_STAT1_LPOWERABLE) { + efx_mdio_set_flag(efx, mmd, MDIO_CTRL1, + MDIO_CTRL1_LPOWER, lpower); } } -void mdio_clause45_set_mmds_lpower(struct efx_nic *efx, - int low_power, unsigned int mmd_mask) +void efx_mdio_set_mmds_lpower(struct efx_nic *efx, + int low_power, unsigned int mmd_mask) { int mmd = 0; - mmd_mask &= ~MDIO_MMDREG_DEVS_AN; + mmd_mask &= ~MDIO_DEVS_AN; while (mmd_mask) { if (mmd_mask & 1) - mdio_clause45_set_mmd_lpower(efx, low_power, mmd); + efx_mdio_set_mmd_lpower(efx, low_power, mmd); mmd_mask = (mmd_mask >> 1); mmd++; } } -static u32 mdio_clause45_get_an(struct efx_nic *efx, u16 addr) -{ - int phy_id = efx->mii.phy_id; - u32 result = 0; - int reg; - - reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, addr); - if (reg & ADVERTISE_10HALF) - result |= ADVERTISED_10baseT_Half; - if (reg & ADVERTISE_10FULL) - result |= ADVERTISED_10baseT_Full; - if (reg & ADVERTISE_100HALF) - result |= ADVERTISED_100baseT_Half; - if (reg & ADVERTISE_100FULL) - result |= ADVERTISED_100baseT_Full; - return result; -} - /** - * mdio_clause45_get_settings - Read (some of) the PHY settings over MDIO. - * @efx: Efx NIC - * @ecmd: Buffer for settings - * - * On return the 'port', 'speed', 'supported' and 'advertising' fields of - * ecmd have been filled out. - */ -void mdio_clause45_get_settings(struct efx_nic *efx, - struct ethtool_cmd *ecmd) -{ - mdio_clause45_get_settings_ext(efx, ecmd, 0, 0); -} - -/** - * mdio_clause45_get_settings_ext - Read (some of) the PHY settings over MDIO. - * @efx: Efx NIC - * @ecmd: Buffer for settings - * @xnp: Advertised Extended Next Page state - * @xnp_lpa: Link Partner's advertised XNP state - * - * On return the 'port', 'speed', 'supported' and 'advertising' fields of - * ecmd have been filled out. - */ -void mdio_clause45_get_settings_ext(struct efx_nic *efx, - struct ethtool_cmd *ecmd, - u32 npage_adv, u32 npage_lpa) -{ - int phy_id = efx->mii.phy_id; - int reg; - - ecmd->transceiver = XCVR_INTERNAL; - ecmd->phy_address = phy_id; - - reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, - MDIO_MMDREG_CTRL2); - switch (reg & MDIO_PMAPMD_CTRL2_TYPE_MASK) { - case MDIO_PMAPMD_CTRL2_10G_BT: - case MDIO_PMAPMD_CTRL2_1G_BT: - case MDIO_PMAPMD_CTRL2_100_BT: - case MDIO_PMAPMD_CTRL2_10_BT: - ecmd->port = PORT_TP; - ecmd->supported = SUPPORTED_TP; - reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, - MDIO_MMDREG_SPEED); - if (reg & (1 << MDIO_MMDREG_SPEED_10G_LBN)) - ecmd->supported |= SUPPORTED_10000baseT_Full; - if (reg & (1 << MDIO_MMDREG_SPEED_1000M_LBN)) - ecmd->supported |= (SUPPORTED_1000baseT_Full | - SUPPORTED_1000baseT_Half); - if (reg & (1 << MDIO_MMDREG_SPEED_100M_LBN)) - ecmd->supported |= (SUPPORTED_100baseT_Full | - SUPPORTED_100baseT_Half); - if (reg & (1 << MDIO_MMDREG_SPEED_10M_LBN)) - ecmd->supported |= (SUPPORTED_10baseT_Full | - SUPPORTED_10baseT_Half); - ecmd->advertising = ADVERTISED_TP; - break; - - /* We represent CX4 as fibre in the absence of anything better */ - case MDIO_PMAPMD_CTRL2_10G_CX4: - /* All the other defined modes are flavours of optical */ - default: - ecmd->port = PORT_FIBRE; - ecmd->supported = SUPPORTED_FIBRE; - ecmd->advertising = ADVERTISED_FIBRE; - break; - } - - if (efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_AN)) { - ecmd->supported |= SUPPORTED_Autoneg; - reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, - MDIO_MMDREG_CTRL1); - if (reg & BMCR_ANENABLE) { - ecmd->autoneg = AUTONEG_ENABLE; - ecmd->advertising |= - ADVERTISED_Autoneg | - mdio_clause45_get_an(efx, MDIO_AN_ADVERTISE) | - npage_adv; - } else - ecmd->autoneg = AUTONEG_DISABLE; - } else - ecmd->autoneg = AUTONEG_DISABLE; - - if (ecmd->autoneg) { - /* If AN is complete, report best common mode, - * otherwise report best advertised mode. */ - u32 modes = 0; - if (mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, - MDIO_MMDREG_STAT1) & - (1 << MDIO_AN_STATUS_AN_DONE_LBN)) - modes = (ecmd->advertising & - (mdio_clause45_get_an(efx, MDIO_AN_LPA) | - npage_lpa)); - if (modes == 0) - modes = ecmd->advertising; - - if (modes & ADVERTISED_10000baseT_Full) { - ecmd->speed = SPEED_10000; - ecmd->duplex = DUPLEX_FULL; - } else if (modes & (ADVERTISED_1000baseT_Full | - ADVERTISED_1000baseT_Half)) { - ecmd->speed = SPEED_1000; - ecmd->duplex = !!(modes & ADVERTISED_1000baseT_Full); - } else if (modes & (ADVERTISED_100baseT_Full | - ADVERTISED_100baseT_Half)) { - ecmd->speed = SPEED_100; - ecmd->duplex = !!(modes & ADVERTISED_100baseT_Full); - } else { - ecmd->speed = SPEED_10; - ecmd->duplex = !!(modes & ADVERTISED_10baseT_Full); - } - } else { - /* Report forced settings */ - reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, - MDIO_MMDREG_CTRL1); - ecmd->speed = (((reg & BMCR_SPEED1000) ? 100 : 1) * - ((reg & BMCR_SPEED100) ? 100 : 10)); - ecmd->duplex = (reg & BMCR_FULLDPLX || - ecmd->speed == SPEED_10000); - } -} - -/** - * mdio_clause45_set_settings - Set (some of) the PHY settings over MDIO. + * efx_mdio_set_settings - Set (some of) the PHY settings over MDIO. * @efx: Efx NIC * @ecmd: New settings */ -int mdio_clause45_set_settings(struct efx_nic *efx, - struct ethtool_cmd *ecmd) +int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) { - int phy_id = efx->mii.phy_id; struct ethtool_cmd prev; u32 required; int reg; @@ -488,95 +304,48 @@ int mdio_clause45_set_settings(struct efx_nic *efx, else if (ecmd->advertising & (ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full)) reg |= ADVERTISE_NPAGE; - reg |= efx_fc_advertise(efx->wanted_fc); - mdio_clause45_write(efx, phy_id, MDIO_MMD_AN, - MDIO_AN_ADVERTISE, reg); + reg |= mii_advertise_flowctrl(efx->wanted_fc); + efx_mdio_write(efx, MDIO_MMD_AN, MDIO_AN_ADVERTISE, reg); /* Set up the (extended) next page if necessary */ if (efx->phy_op->set_npage_adv) efx->phy_op->set_npage_adv(efx, ecmd->advertising); /* Enable and restart AN */ - reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, - MDIO_MMDREG_CTRL1); - reg |= BMCR_ANENABLE; + reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_CTRL1); + reg |= MDIO_AN_CTRL1_ENABLE; if (!(EFX_WORKAROUND_15195(efx) && LOOPBACK_MASK(efx) & efx->phy_op->loopbacks)) - reg |= BMCR_ANRESTART; + reg |= MDIO_AN_CTRL1_RESTART; if (xnp) - reg |= 1 << MDIO_AN_CTRL_XNP_LBN; + reg |= MDIO_AN_CTRL1_XNP; else - reg &= ~(1 << MDIO_AN_CTRL_XNP_LBN); - mdio_clause45_write(efx, phy_id, MDIO_MMD_AN, - MDIO_MMDREG_CTRL1, reg); + reg &= ~MDIO_AN_CTRL1_XNP; + efx_mdio_write(efx, MDIO_MMD_AN, MDIO_CTRL1, reg); } else { /* Disable AN */ - mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_AN, - MDIO_MMDREG_CTRL1, - __ffs(BMCR_ANENABLE), false); + efx_mdio_set_flag(efx, MDIO_MMD_AN, MDIO_CTRL1, + MDIO_AN_CTRL1_ENABLE, false); /* Set the basic control bits */ - reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, - MDIO_MMDREG_CTRL1); - reg &= ~(BMCR_SPEED1000 | BMCR_SPEED100 | BMCR_FULLDPLX | - 0x003c); + reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, MDIO_CTRL1); + reg &= ~(MDIO_CTRL1_SPEEDSEL | MDIO_CTRL1_FULLDPLX); if (ecmd->speed == SPEED_100) - reg |= BMCR_SPEED100; + reg |= MDIO_PMA_CTRL1_SPEED100; if (ecmd->duplex) - reg |= BMCR_FULLDPLX; - mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD, - MDIO_MMDREG_CTRL1, reg); + reg |= MDIO_CTRL1_FULLDPLX; + efx_mdio_write(efx, MDIO_MMD_PMAPMD, MDIO_CTRL1, reg); } return 0; } -void mdio_clause45_set_pause(struct efx_nic *efx) +enum efx_fc_type efx_mdio_get_pause(struct efx_nic *efx) { - int phy_id = efx->mii.phy_id; - int reg; - - if (efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_AN)) { - /* Set pause capability advertising */ - reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, - MDIO_AN_ADVERTISE); - reg &= ~(ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); - reg |= efx_fc_advertise(efx->wanted_fc); - mdio_clause45_write(efx, phy_id, MDIO_MMD_AN, - MDIO_AN_ADVERTISE, reg); - - /* Restart auto-negotiation */ - reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, - MDIO_MMDREG_CTRL1); - if (reg & BMCR_ANENABLE) { - reg |= BMCR_ANRESTART; - mdio_clause45_write(efx, phy_id, MDIO_MMD_AN, - MDIO_MMDREG_CTRL1, reg); - } - } -} - -enum efx_fc_type mdio_clause45_get_pause(struct efx_nic *efx) -{ - int phy_id = efx->mii.phy_id; int lpa; - if (!(efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_AN))) + if (!(efx->phy_op->mmds & MDIO_DEVS_AN)) return efx->wanted_fc; - lpa = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, MDIO_AN_LPA); + lpa = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_AN_LPA); return efx_fc_resolve(efx->wanted_fc, lpa); } - -void mdio_clause45_set_flag(struct efx_nic *efx, u8 prt, u8 dev, - u16 addr, int bit, bool sense) -{ - int old_val = mdio_clause45_read(efx, prt, dev, addr); - int new_val; - - if (sense) - new_val = old_val | (1 << bit); - else - new_val = old_val & ~(1 << bit); - if (old_val != new_val) - mdio_clause45_write(efx, prt, dev, addr, new_val); -} diff --git a/drivers/net/sfc/mdio_10g.h b/drivers/net/sfc/mdio_10g.h index 7014d2279c20..6b14421a7444 100644 --- a/drivers/net/sfc/mdio_10g.h +++ b/drivers/net/sfc/mdio_10g.h @@ -10,247 +10,53 @@ #ifndef EFX_MDIO_10G_H #define EFX_MDIO_10G_H +#include + /* - * Definitions needed for doing 10G MDIO as specified in clause 45 - * MDIO, which do not appear in Linux yet. Also some helper functions. + * Helper functions for doing 10G MDIO as specified in IEEE 802.3 clause 45. */ #include "efx.h" #include "boards.h" -/* Numbering of the MDIO Manageable Devices (MMDs) */ -/* Physical Medium Attachment/ Physical Medium Dependent sublayer */ -#define MDIO_MMD_PMAPMD (1) -/* WAN Interface Sublayer */ -#define MDIO_MMD_WIS (2) -/* Physical Coding Sublayer */ -#define MDIO_MMD_PCS (3) -/* PHY Extender Sublayer */ -#define MDIO_MMD_PHYXS (4) -/* Extender Sublayer */ -#define MDIO_MMD_DTEXS (5) -/* Transmission convergence */ -#define MDIO_MMD_TC (6) -/* Auto negotiation */ -#define MDIO_MMD_AN (7) -/* Clause 22 extension */ -#define MDIO_MMD_C22EXT 29 +static inline unsigned efx_mdio_id_rev(u32 id) { return id & 0xf; } +static inline unsigned efx_mdio_id_model(u32 id) { return (id >> 4) & 0x3f; } +extern unsigned efx_mdio_id_oui(u32 id); -/* Generic register locations */ -#define MDIO_MMDREG_CTRL1 (0) -#define MDIO_MMDREG_STAT1 (1) -#define MDIO_MMDREG_IDHI (2) -#define MDIO_MMDREG_IDLOW (3) -#define MDIO_MMDREG_SPEED (4) -#define MDIO_MMDREG_DEVS0 (5) -#define MDIO_MMDREG_DEVS1 (6) -#define MDIO_MMDREG_CTRL2 (7) -#define MDIO_MMDREG_STAT2 (8) -#define MDIO_MMDREG_TXDIS (9) - -/* Bits in MMDREG_CTRL1 */ -/* Reset */ -#define MDIO_MMDREG_CTRL1_RESET_LBN (15) -#define MDIO_MMDREG_CTRL1_RESET_WIDTH (1) -/* Loopback */ -/* Loopback bit for WIS, PCS, PHYSX and DTEXS */ -#define MDIO_MMDREG_CTRL1_LBACK_LBN (14) -#define MDIO_MMDREG_CTRL1_LBACK_WIDTH (1) -/* Low power */ -#define MDIO_MMDREG_CTRL1_LPOWER_LBN (11) -#define MDIO_MMDREG_CTRL1_LPOWER_WIDTH (1) - -/* Bits in MMDREG_STAT1 */ -#define MDIO_MMDREG_STAT1_FAULT_LBN (7) -#define MDIO_MMDREG_STAT1_FAULT_WIDTH (1) -/* Link state */ -#define MDIO_MMDREG_STAT1_LINK_LBN (2) -#define MDIO_MMDREG_STAT1_LINK_WIDTH (1) -/* Low power ability */ -#define MDIO_MMDREG_STAT1_LPABLE_LBN (1) -#define MDIO_MMDREG_STAT1_LPABLE_WIDTH (1) - -/* Bits in combined ID regs */ -static inline unsigned mdio_id_rev(u32 id) { return id & 0xf; } -static inline unsigned mdio_id_model(u32 id) { return (id >> 4) & 0x3f; } -extern unsigned mdio_id_oui(u32 id); - -/* Bits in MMDREG_DEVS0/1. Someone thoughtfully layed things out - * so the 'bit present' bit number of an MMD is the number of - * that MMD */ -#define DEV_PRESENT_BIT(_b) (1 << _b) - -#define MDIO_MMDREG_DEVS_PHYXS DEV_PRESENT_BIT(MDIO_MMD_PHYXS) -#define MDIO_MMDREG_DEVS_PCS DEV_PRESENT_BIT(MDIO_MMD_PCS) -#define MDIO_MMDREG_DEVS_PMAPMD DEV_PRESENT_BIT(MDIO_MMD_PMAPMD) -#define MDIO_MMDREG_DEVS_AN DEV_PRESENT_BIT(MDIO_MMD_AN) -#define MDIO_MMDREG_DEVS_C22EXT DEV_PRESENT_BIT(MDIO_MMD_C22EXT) - -/* Bits in MMDREG_SPEED */ -#define MDIO_MMDREG_SPEED_10G_LBN 0 -#define MDIO_MMDREG_SPEED_10G_WIDTH 1 -#define MDIO_MMDREG_SPEED_1000M_LBN 4 -#define MDIO_MMDREG_SPEED_1000M_WIDTH 1 -#define MDIO_MMDREG_SPEED_100M_LBN 5 -#define MDIO_MMDREG_SPEED_100M_WIDTH 1 -#define MDIO_MMDREG_SPEED_10M_LBN 6 -#define MDIO_MMDREG_SPEED_10M_WIDTH 1 - -/* Bits in MMDREG_STAT2 */ -#define MDIO_MMDREG_STAT2_PRESENT_VAL (2) -#define MDIO_MMDREG_STAT2_PRESENT_LBN (14) -#define MDIO_MMDREG_STAT2_PRESENT_WIDTH (2) - -/* Bits in MMDREG_TXDIS */ -#define MDIO_MMDREG_TXDIS_GLOBAL_LBN (0) -#define MDIO_MMDREG_TXDIS_GLOBAL_WIDTH (1) - -/* MMD-specific bits, ordered by MMD, then register */ -#define MDIO_PMAPMD_CTRL1_LBACK_LBN (0) -#define MDIO_PMAPMD_CTRL1_LBACK_WIDTH (1) - -/* PMA type (4 bits) */ -#define MDIO_PMAPMD_CTRL2_10G_CX4 (0x0) -#define MDIO_PMAPMD_CTRL2_10G_EW (0x1) -#define MDIO_PMAPMD_CTRL2_10G_LW (0x2) -#define MDIO_PMAPMD_CTRL2_10G_SW (0x3) -#define MDIO_PMAPMD_CTRL2_10G_LX4 (0x4) -#define MDIO_PMAPMD_CTRL2_10G_ER (0x5) -#define MDIO_PMAPMD_CTRL2_10G_LR (0x6) -#define MDIO_PMAPMD_CTRL2_10G_SR (0x7) -/* Reserved */ -#define MDIO_PMAPMD_CTRL2_10G_BT (0x9) -/* Reserved */ -/* Reserved */ -#define MDIO_PMAPMD_CTRL2_1G_BT (0xc) -/* Reserved */ -#define MDIO_PMAPMD_CTRL2_100_BT (0xe) -#define MDIO_PMAPMD_CTRL2_10_BT (0xf) -#define MDIO_PMAPMD_CTRL2_TYPE_MASK (0xf) - -/* PMA 10GBT registers */ -#define MDIO_PMAPMD_10GBT_TXPWR (131) -#define MDIO_PMAPMD_10GBT_TXPWR_SHORT_LBN (0) -#define MDIO_PMAPMD_10GBT_TXPWR_SHORT_WIDTH (1) - -/* PHY XGXS Status 2 */ -#define MDIO_PHYXS_STATUS2 (8) -#define MDIO_PHYXS_STATUS2_RX_FAULT_LBN 10 - -/* PHY XGXS lane state */ -#define MDIO_PHYXS_LANE_STATE (0x18) -#define MDIO_PHYXS_LANE_ALIGNED_LBN (12) - -/* AN registers */ -#define MDIO_AN_CTRL_XNP_LBN 13 -#define MDIO_AN_STATUS (1) -#define MDIO_AN_STATUS_XNP_LBN (7) -#define MDIO_AN_STATUS_PAGE_LBN (6) -#define MDIO_AN_STATUS_AN_DONE_LBN (5) -#define MDIO_AN_STATUS_LP_AN_CAP_LBN (0) - -#define MDIO_AN_ADVERTISE 16 -#define MDIO_AN_ADVERTISE_XNP_LBN 12 -#define MDIO_AN_LPA 19 -#define MDIO_AN_XNP 22 -#define MDIO_AN_LPA_XNP 25 - -#define MDIO_AN_10GBT_CTRL 32 -#define MDIO_AN_10GBT_CTRL_ADV_10G_LBN 12 -#define MDIO_AN_10GBT_STATUS (33) -#define MDIO_AN_10GBT_STATUS_MS_FLT_LBN (15) /* MASTER/SLAVE config fault */ -#define MDIO_AN_10GBT_STATUS_MS_LBN (14) /* MASTER/SLAVE config */ -#define MDIO_AN_10GBT_STATUS_LOC_OK_LBN (13) /* Local OK */ -#define MDIO_AN_10GBT_STATUS_REM_OK_LBN (12) /* Remote OK */ -#define MDIO_AN_10GBT_STATUS_LP_10G_LBN (11) /* Link partner is 10GBT capable */ -#define MDIO_AN_10GBT_STATUS_LP_LTA_LBN (10) /* LP loop timing ability */ -#define MDIO_AN_10GBT_STATUS_LP_TRR_LBN (9) /* LP Training Reset Request */ - - -/* Packing of the prt and dev arguments of clause 45 style MDIO into a - * single int so they can be passed into the mdio_read/write functions - * that currently exist. Note that as Falcon is the only current user, - * the packed form is chosen to match what Falcon needs to write into - * a register. This is checked at compile-time so do not change it. If - * your target chip needs things layed out differently you will need - * to unpack the arguments in your chip-specific mdio functions. - */ - /* These are defined by the standard. */ -#define MDIO45_PRT_ID_WIDTH (5) -#define MDIO45_DEV_ID_WIDTH (5) - -/* The prt ID is just packed in immediately to the left of the dev ID */ -#define MDIO45_PRT_DEV_WIDTH (MDIO45_PRT_ID_WIDTH + MDIO45_DEV_ID_WIDTH) - -#define MDIO45_PRT_ID_MASK ((1 << MDIO45_PRT_DEV_WIDTH) - 1) -/* This is the prt + dev extended by 1 bit to hold the 'is clause 45' flag. */ -#define MDIO45_XPRT_ID_WIDTH (MDIO45_PRT_DEV_WIDTH + 1) -#define MDIO45_XPRT_ID_MASK ((1 << MDIO45_XPRT_ID_WIDTH) - 1) -#define MDIO45_XPRT_ID_IS10G (1 << (MDIO45_XPRT_ID_WIDTH - 1)) - - -#define MDIO45_PRT_ID_COMP_LBN MDIO45_DEV_ID_WIDTH -#define MDIO45_PRT_ID_COMP_WIDTH MDIO45_PRT_ID_WIDTH -#define MDIO45_DEV_ID_COMP_LBN 0 -#define MDIO45_DEV_ID_COMP_WIDTH MDIO45_DEV_ID_WIDTH - -/* Compose port and device into a phy_id */ -static inline int mdio_clause45_pack(u8 prt, u8 dev) +static inline int efx_mdio_read(struct efx_nic *efx, int devad, int addr) { - efx_dword_t phy_id; - EFX_POPULATE_DWORD_2(phy_id, MDIO45_PRT_ID_COMP, prt, - MDIO45_DEV_ID_COMP, dev); - return MDIO45_XPRT_ID_IS10G | EFX_DWORD_VAL(phy_id); + return efx->mdio.mdio_read(efx->net_dev, efx->mdio.prtad, devad, addr); } -static inline void mdio_clause45_unpack(u32 val, u8 *prt, u8 *dev) +static inline void +efx_mdio_write(struct efx_nic *efx, int devad, int addr, int value) { - efx_dword_t phy_id; - EFX_POPULATE_DWORD_1(phy_id, EFX_DWORD_0, val); - *prt = EFX_DWORD_FIELD(phy_id, MDIO45_PRT_ID_COMP); - *dev = EFX_DWORD_FIELD(phy_id, MDIO45_DEV_ID_COMP); + efx->mdio.mdio_write(efx->net_dev, efx->mdio.prtad, devad, addr, value); } -static inline int mdio_clause45_read(struct efx_nic *efx, - u8 prt, u8 dev, u16 addr) +static inline u32 efx_mdio_read_id(struct efx_nic *efx, int mmd) { - return efx->mii.mdio_read(efx->net_dev, - mdio_clause45_pack(prt, dev), addr); -} - -static inline void mdio_clause45_write(struct efx_nic *efx, - u8 prt, u8 dev, u16 addr, int value) -{ - efx->mii.mdio_write(efx->net_dev, - mdio_clause45_pack(prt, dev), addr, value); -} - - -static inline u32 mdio_clause45_read_id(struct efx_nic *efx, int mmd) -{ - int phy_id = efx->mii.phy_id; - u16 id_low = mdio_clause45_read(efx, phy_id, mmd, MDIO_MMDREG_IDLOW); - u16 id_hi = mdio_clause45_read(efx, phy_id, mmd, MDIO_MMDREG_IDHI); + u16 id_low = efx_mdio_read(efx, mmd, MDIO_DEVID2); + u16 id_hi = efx_mdio_read(efx, mmd, MDIO_DEVID1); return (id_hi << 16) | (id_low); } -static inline bool mdio_clause45_phyxgxs_lane_sync(struct efx_nic *efx) +static inline bool efx_mdio_phyxgxs_lane_sync(struct efx_nic *efx) { int i, lane_status; bool sync; for (i = 0; i < 2; ++i) - lane_status = mdio_clause45_read(efx, efx->mii.phy_id, - MDIO_MMD_PHYXS, - MDIO_PHYXS_LANE_STATE); + lane_status = efx_mdio_read(efx, MDIO_MMD_PHYXS, + MDIO_PHYXS_LNSTAT); - sync = !!(lane_status & (1 << MDIO_PHYXS_LANE_ALIGNED_LBN)); + sync = !!(lane_status & MDIO_PHYXS_LNSTAT_ALIGN); if (!sync) EFX_LOG(efx, "XGXS lane status: %x\n", lane_status); return sync; } -extern const char *mdio_clause45_mmd_name(int mmd); +extern const char *efx_mdio_mmd_name(int mmd); /* * Reset a specific MMD and wait for reset to clear. @@ -258,54 +64,44 @@ extern const char *mdio_clause45_mmd_name(int mmd); * * This function will sleep */ -extern int mdio_clause45_reset_mmd(struct efx_nic *efx, int mmd, - int spins, int spintime); +extern int efx_mdio_reset_mmd(struct efx_nic *efx, int mmd, + int spins, int spintime); -/* As mdio_clause45_check_mmd but for multiple MMDs */ -int mdio_clause45_check_mmds(struct efx_nic *efx, - unsigned int mmd_mask, unsigned int fatal_mask); +/* As efx_mdio_check_mmd but for multiple MMDs */ +int efx_mdio_check_mmds(struct efx_nic *efx, + unsigned int mmd_mask, unsigned int fatal_mask); /* Check the link status of specified mmds in bit mask */ -extern bool mdio_clause45_links_ok(struct efx_nic *efx, - unsigned int mmd_mask); +extern bool efx_mdio_links_ok(struct efx_nic *efx, unsigned int mmd_mask); /* Generic transmit disable support though PMAPMD */ -extern void mdio_clause45_transmit_disable(struct efx_nic *efx); +extern void efx_mdio_transmit_disable(struct efx_nic *efx); /* Generic part of reconfigure: set/clear loopback bits */ -extern void mdio_clause45_phy_reconfigure(struct efx_nic *efx); +extern void efx_mdio_phy_reconfigure(struct efx_nic *efx); /* Set the power state of the specified MMDs */ -extern void mdio_clause45_set_mmds_lpower(struct efx_nic *efx, - int low_power, unsigned int mmd_mask); - -/* Read (some of) the PHY settings over MDIO */ -extern void mdio_clause45_get_settings(struct efx_nic *efx, - struct ethtool_cmd *ecmd); - -/* Read (some of) the PHY settings over MDIO */ -extern void -mdio_clause45_get_settings_ext(struct efx_nic *efx, struct ethtool_cmd *ecmd, - u32 xnp, u32 xnp_lpa); +extern void efx_mdio_set_mmds_lpower(struct efx_nic *efx, + int low_power, unsigned int mmd_mask); /* Set (some of) the PHY settings over MDIO */ -extern int mdio_clause45_set_settings(struct efx_nic *efx, - struct ethtool_cmd *ecmd); - -/* Set pause parameters to be advertised through AN (if available) */ -extern void mdio_clause45_set_pause(struct efx_nic *efx); +extern int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd); /* Get pause parameters from AN if available (otherwise return * requested pause parameters) */ -enum efx_fc_type mdio_clause45_get_pause(struct efx_nic *efx); +enum efx_fc_type efx_mdio_get_pause(struct efx_nic *efx); /* Wait for specified MMDs to exit reset within a timeout */ -extern int mdio_clause45_wait_reset_mmds(struct efx_nic *efx, - unsigned int mmd_mask); +extern int efx_mdio_wait_reset_mmds(struct efx_nic *efx, + unsigned int mmd_mask); /* Set or clear flag, debouncing */ -extern void mdio_clause45_set_flag(struct efx_nic *efx, u8 prt, u8 dev, - u16 addr, int bit, bool sense); +static inline void +efx_mdio_set_flag(struct efx_nic *efx, int devad, int addr, + int mask, bool state) +{ + mdio_set_flag(&efx->mdio, efx->mdio.prtad, devad, addr, mask, state); +} #endif /* EFX_MDIO_10G_H */ diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index e169e5dcd1e6..5eabede9ac18 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include #include @@ -458,8 +458,6 @@ enum phy_type { PHY_TYPE_MAX /* Insert any new items before this */ }; -#define PHY_ADDR_INVALID 0xff - #define EFX_IS10G(efx) ((efx)->link_speed == 10000) enum nic_state { @@ -497,8 +495,8 @@ struct efx_nic; /* Pseudo bit-mask flow control field */ enum efx_fc_type { - EFX_FC_RX = 1, - EFX_FC_TX = 2, + EFX_FC_RX = FLOW_CTRL_RX, + EFX_FC_TX = FLOW_CTRL_TX, EFX_FC_AUTO = 4, }; @@ -508,33 +506,15 @@ enum efx_mac_type { EFX_XMAC = 2, }; -static inline unsigned int efx_fc_advertise(enum efx_fc_type wanted_fc) -{ - unsigned int adv = 0; - if (wanted_fc & EFX_FC_RX) - adv = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; - if (wanted_fc & EFX_FC_TX) - adv ^= ADVERTISE_PAUSE_ASYM; - return adv; -} - static inline enum efx_fc_type efx_fc_resolve(enum efx_fc_type wanted_fc, unsigned int lpa) { - unsigned int adv = efx_fc_advertise(wanted_fc); + BUILD_BUG_ON(EFX_FC_AUTO & (EFX_FC_RX | EFX_FC_TX)); if (!(wanted_fc & EFX_FC_AUTO)) return wanted_fc; - if (adv & lpa & ADVERTISE_PAUSE_CAP) - return EFX_FC_RX | EFX_FC_TX; - if (adv & lpa & ADVERTISE_PAUSE_ASYM) { - if (adv & ADVERTISE_PAUSE_CAP) - return EFX_FC_RX; - if (lpa & ADVERTISE_PAUSE_CAP) - return EFX_FC_TX; - } - return 0; + return mii_resolve_flowctrl_fdx(mii_advertise_flowctrl(wanted_fc), lpa); } /** @@ -758,7 +738,7 @@ union efx_multicast_hash { * @phy_lock: PHY access lock * @phy_op: PHY interface * @phy_data: PHY private data (including PHY-specific stats) - * @mii: PHY interface + * @mdio: PHY MDIO interface * @phy_mode: PHY operating mode. Serialised by @mac_lock. * @mac_up: MAC link state * @link_up: Link status @@ -845,7 +825,7 @@ struct efx_nic { struct work_struct phy_work; struct efx_phy_operations *phy_op; void *phy_data; - struct mii_if_info mii; + struct mdio_if_info mdio; enum efx_phy_mode phy_mode; bool mac_up; diff --git a/drivers/net/sfc/rx.c b/drivers/net/sfc/rx.c index 66d7fe3db3e6..01f9432c31ef 100644 --- a/drivers/net/sfc/rx.c +++ b/drivers/net/sfc/rx.c @@ -450,17 +450,27 @@ static void efx_rx_packet_lro(struct efx_channel *channel, /* Pass the skb/page into the LRO engine */ if (rx_buf->page) { - struct napi_gro_fraginfo info; + struct sk_buff *skb = napi_get_frags(napi); - info.frags[0].page = rx_buf->page; - info.frags[0].page_offset = efx_rx_buf_offset(rx_buf); - info.frags[0].size = rx_buf->len; - info.nr_frags = 1; - info.ip_summed = CHECKSUM_UNNECESSARY; - info.len = rx_buf->len; + if (!skb) { + put_page(rx_buf->page); + goto out; + } - napi_gro_frags(napi, &info); + skb_shinfo(skb)->frags[0].page = rx_buf->page; + skb_shinfo(skb)->frags[0].page_offset = + efx_rx_buf_offset(rx_buf); + skb_shinfo(skb)->frags[0].size = rx_buf->len; + skb_shinfo(skb)->nr_frags = 1; + skb->len = rx_buf->len; + skb->data_len = rx_buf->len; + skb->truesize += rx_buf->len; + skb->ip_summed = CHECKSUM_UNNECESSARY; + + napi_gro_frags(napi); + +out: EFX_BUG_ON_PARANOID(rx_buf->skb); rx_buf->page = NULL; } else { diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c index 0a598084c513..b67ccca3fc1a 100644 --- a/drivers/net/sfc/selftest.c +++ b/drivers/net/sfc/selftest.c @@ -80,39 +80,38 @@ struct efx_loopback_state { * **************************************************************************/ -static int efx_test_mii(struct efx_nic *efx, struct efx_self_tests *tests) +static int efx_test_mdio(struct efx_nic *efx, struct efx_self_tests *tests) { int rc = 0; + int devad = __ffs(efx->mdio.mmds); u16 physid1, physid2; - struct mii_if_info *mii = &efx->mii; - struct net_device *net_dev = efx->net_dev; if (efx->phy_type == PHY_TYPE_NONE) return 0; mutex_lock(&efx->mac_lock); - tests->mii = -1; + tests->mdio = -1; - physid1 = mii->mdio_read(net_dev, mii->phy_id, MII_PHYSID1); - physid2 = mii->mdio_read(net_dev, mii->phy_id, MII_PHYSID2); + physid1 = efx_mdio_read(efx, devad, MDIO_DEVID1); + physid2 = efx_mdio_read(efx, devad, MDIO_DEVID2); if ((physid1 == 0x0000) || (physid1 == 0xffff) || (physid2 == 0x0000) || (physid2 == 0xffff)) { - EFX_ERR(efx, "no MII PHY present with ID %d\n", - mii->phy_id); + EFX_ERR(efx, "no MDIO PHY present with ID %d\n", + efx->mdio.prtad); rc = -EINVAL; goto out; } if (EFX_IS10G(efx)) { - rc = mdio_clause45_check_mmds(efx, efx->phy_op->mmds, 0); + rc = efx_mdio_check_mmds(efx, efx->phy_op->mmds, 0); if (rc) goto out; } out: mutex_unlock(&efx->mac_lock); - tests->mii = rc ? -1 : 1; + tests->mdio = rc ? -1 : 1; return rc; } @@ -439,6 +438,7 @@ static int efx_begin_loopback(struct efx_tx_queue *tx_queue) kfree_skb(skb); return -EPIPE; } + efx->net_dev->trans_start = jiffies; } return 0; @@ -673,7 +673,7 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests, /* Online (i.e. non-disruptive) testing * This checks interrupt generation, event delivery and PHY presence. */ - rc = efx_test_mii(efx, tests); + rc = efx_test_mdio(efx, tests); if (rc && !rc_test) rc_test = rc; diff --git a/drivers/net/sfc/selftest.h b/drivers/net/sfc/selftest.h index 39451cf938cf..f6feee04c96b 100644 --- a/drivers/net/sfc/selftest.h +++ b/drivers/net/sfc/selftest.h @@ -32,7 +32,7 @@ struct efx_loopback_self_tests { */ struct efx_self_tests { /* online tests */ - int mii; + int mdio; int nvram; int interrupt; int eventq_dma[EFX_MAX_CHANNELS]; diff --git a/drivers/net/sfc/sfe4001.c b/drivers/net/sfc/sfe4001.c index 4eac5da81e5a..cee00ad49b57 100644 --- a/drivers/net/sfc/sfe4001.c +++ b/drivers/net/sfc/sfe4001.c @@ -296,7 +296,6 @@ static int sfe4001_check_hw(struct efx_nic *efx) static struct i2c_board_info sfe4001_hwmon_info = { I2C_BOARD_INFO("max6647", 0x4e), - .irq = -1, }; /* This board uses an I2C expander to provider power to the PHY, which needs to @@ -389,12 +388,10 @@ static void sfn4111t_fini(struct efx_nic *efx) static struct i2c_board_info sfn4111t_a0_hwmon_info = { I2C_BOARD_INFO("max6647", 0x4e), - .irq = -1, }; static struct i2c_board_info sfn4111t_r5_hwmon_info = { I2C_BOARD_INFO("max6646", 0x4d), - .irq = -1, }; int sfn4111t_init(struct efx_nic *efx) diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c index e61dc4d4741c..f4d509015f75 100644 --- a/drivers/net/sfc/tenxpress.c +++ b/drivers/net/sfc/tenxpress.c @@ -23,10 +23,10 @@ * clause 22 extension MMD, but since it doesn't have all the generic * MMD registers it is pointless to include it here. */ -#define TENXPRESS_REQUIRED_DEVS (MDIO_MMDREG_DEVS_PMAPMD | \ - MDIO_MMDREG_DEVS_PCS | \ - MDIO_MMDREG_DEVS_PHYXS | \ - MDIO_MMDREG_DEVS_AN) +#define TENXPRESS_REQUIRED_DEVS (MDIO_DEVS_PMAPMD | \ + MDIO_DEVS_PCS | \ + MDIO_DEVS_PHYXS | \ + MDIO_DEVS_AN) #define SFX7101_LOOPBACKS ((1 << LOOPBACK_PHYXS) | \ (1 << LOOPBACK_PCS) | \ @@ -44,18 +44,6 @@ */ #define MAX_BAD_LP_TRIES (5) -/* LASI Control */ -#define PMA_PMD_LASI_CTRL 36866 -#define PMA_PMD_LASI_STATUS 36869 -#define PMA_PMD_LS_ALARM_LBN 0 -#define PMA_PMD_LS_ALARM_WIDTH 1 -#define PMA_PMD_TX_ALARM_LBN 1 -#define PMA_PMD_TX_ALARM_WIDTH 1 -#define PMA_PMD_RX_ALARM_LBN 2 -#define PMA_PMD_RX_ALARM_WIDTH 1 -#define PMA_PMD_AN_ALARM_LBN 3 -#define PMA_PMD_AN_ALARM_WIDTH 1 - /* Extended control register */ #define PMA_PMD_XCONTROL_REG 49152 #define PMA_PMD_EXT_GMII_EN_LBN 1 @@ -75,6 +63,7 @@ /* extended status register */ #define PMA_PMD_XSTATUS_REG 49153 +#define PMA_PMD_XSTAT_MDIX_LBN 14 #define PMA_PMD_XSTAT_FLP_LBN (12) /* LED control register */ @@ -153,10 +142,6 @@ #define LOOPBACK_NEAR_LBN (8) #define LOOPBACK_NEAR_WIDTH (1) -#define PCS_10GBASET_STAT1 32 -#define PCS_10GBASET_BLKLK_LBN 0 -#define PCS_10GBASET_BLKLK_WIDTH 1 - /* Boot status register */ #define PCS_BOOT_STATUS_REG 53248 #define PCS_BOOT_FATAL_ERROR_LBN 0 @@ -206,10 +191,8 @@ static ssize_t show_phy_short_reach(struct device *dev, struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev)); int reg; - reg = mdio_clause45_read(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, - MDIO_PMAPMD_10GBT_TXPWR); - return sprintf(buf, "%d\n", - !!(reg & (1 << MDIO_PMAPMD_10GBT_TXPWR_SHORT_LBN))); + reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, MDIO_PMA_10GBT_TXPWR); + return sprintf(buf, "%d\n", !!(reg & MDIO_PMA_10GBT_TXPWR_SHORT)); } static ssize_t set_phy_short_reach(struct device *dev, @@ -219,10 +202,9 @@ static ssize_t set_phy_short_reach(struct device *dev, struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev)); rtnl_lock(); - mdio_clause45_set_flag(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, - MDIO_PMAPMD_10GBT_TXPWR, - MDIO_PMAPMD_10GBT_TXPWR_SHORT_LBN, - count != 0 && *buf != '0'); + efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD, MDIO_PMA_10GBT_TXPWR, + MDIO_PMA_10GBT_TXPWR_SHORT, + count != 0 && *buf != '0'); efx_reconfigure_port(efx); rtnl_unlock(); @@ -238,9 +220,8 @@ int sft9001_wait_boot(struct efx_nic *efx) int boot_stat; for (;;) { - boot_stat = mdio_clause45_read(efx, efx->mii.phy_id, - MDIO_MMD_PCS, - PCS_BOOT_STATUS_REG); + boot_stat = efx_mdio_read(efx, MDIO_MMD_PCS, + PCS_BOOT_STATUS_REG); if (boot_stat >= 0) { EFX_LOG(efx, "PHY boot status = %#x\n", boot_stat); switch (boot_stat & @@ -286,38 +267,32 @@ int sft9001_wait_boot(struct efx_nic *efx) static int tenxpress_init(struct efx_nic *efx) { - int phy_id = efx->mii.phy_id; int reg; if (efx->phy_type == PHY_TYPE_SFX7101) { /* Enable 312.5 MHz clock */ - mdio_clause45_write(efx, phy_id, - MDIO_MMD_PCS, PCS_TEST_SELECT_REG, - 1 << CLK312_EN_LBN); + efx_mdio_write(efx, MDIO_MMD_PCS, PCS_TEST_SELECT_REG, + 1 << CLK312_EN_LBN); } else { /* Enable 312.5 MHz clock and GMII */ - reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, - PMA_PMD_XCONTROL_REG); + reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG); reg |= ((1 << PMA_PMD_EXT_GMII_EN_LBN) | (1 << PMA_PMD_EXT_CLK_OUT_LBN) | (1 << PMA_PMD_EXT_CLK312_LBN) | (1 << PMA_PMD_EXT_ROBUST_LBN)); - mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD, - PMA_PMD_XCONTROL_REG, reg); - mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_C22EXT, - GPHY_XCONTROL_REG, GPHY_ISOLATE_LBN, - false); + efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG, reg); + efx_mdio_set_flag(efx, MDIO_MMD_C22EXT, + GPHY_XCONTROL_REG, 1 << GPHY_ISOLATE_LBN, + false); } /* Set the LEDs up as: Green = Link, Amber = Link/Act, Red = Off */ if (efx->phy_type == PHY_TYPE_SFX7101) { - mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_PMAPMD, - PMA_PMD_LED_CTRL_REG, - PMA_PMA_LED_ACTIVITY_LBN, - true); - mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD, - PMA_PMD_LED_OVERR_REG, PMA_PMD_LED_DEFAULT); + efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD, PMA_PMD_LED_CTRL_REG, + 1 << PMA_PMA_LED_ACTIVITY_LBN, true); + efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_LED_OVERR_REG, + PMA_PMD_LED_DEFAULT); } return 0; @@ -337,22 +312,19 @@ static int tenxpress_phy_init(struct efx_nic *efx) if (!(efx->phy_mode & PHY_MODE_SPECIAL)) { if (efx->phy_type == PHY_TYPE_SFT9001A) { int reg; - reg = mdio_clause45_read(efx, efx->mii.phy_id, - MDIO_MMD_PMAPMD, - PMA_PMD_XCONTROL_REG); + reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, + PMA_PMD_XCONTROL_REG); reg |= (1 << PMA_PMD_EXT_SSR_LBN); - mdio_clause45_write(efx, efx->mii.phy_id, - MDIO_MMD_PMAPMD, - PMA_PMD_XCONTROL_REG, reg); + efx_mdio_write(efx, MDIO_MMD_PMAPMD, + PMA_PMD_XCONTROL_REG, reg); mdelay(200); } - rc = mdio_clause45_wait_reset_mmds(efx, - TENXPRESS_REQUIRED_DEVS); + rc = efx_mdio_wait_reset_mmds(efx, TENXPRESS_REQUIRED_DEVS); if (rc < 0) goto fail; - rc = mdio_clause45_check_mmds(efx, TENXPRESS_REQUIRED_DEVS, 0); + rc = efx_mdio_check_mmds(efx, TENXPRESS_REQUIRED_DEVS, 0); if (rc < 0) goto fail; } @@ -360,7 +332,6 @@ static int tenxpress_phy_init(struct efx_nic *efx) rc = tenxpress_init(efx); if (rc < 0) goto fail; - mdio_clause45_set_pause(efx); if (efx->phy_type == PHY_TYPE_SFT9001B) { rc = device_create_file(&efx->pci_dev->dev, @@ -395,17 +366,14 @@ static int tenxpress_special_reset(struct efx_nic *efx) efx_stats_disable(efx); /* Initiate reset */ - reg = mdio_clause45_read(efx, efx->mii.phy_id, - MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG); + reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG); reg |= (1 << PMA_PMD_EXT_SSR_LBN); - mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, - PMA_PMD_XCONTROL_REG, reg); + efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG, reg); mdelay(200); /* Wait for the blocks to come out of reset */ - rc = mdio_clause45_wait_reset_mmds(efx, - TENXPRESS_REQUIRED_DEVS); + rc = efx_mdio_wait_reset_mmds(efx, TENXPRESS_REQUIRED_DEVS); if (rc < 0) goto out; @@ -424,7 +392,6 @@ out: static void sfx7101_check_bad_lp(struct efx_nic *efx, bool link_ok) { struct tenxpress_phy_data *pd = efx->phy_data; - int phy_id = efx->mii.phy_id; bool bad_lp; int reg; @@ -432,11 +399,10 @@ static void sfx7101_check_bad_lp(struct efx_nic *efx, bool link_ok) bad_lp = false; } else { /* Check that AN has started but not completed. */ - reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, - MDIO_AN_STATUS); - if (!(reg & (1 << MDIO_AN_STATUS_LP_AN_CAP_LBN))) + reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_STAT1); + if (!(reg & MDIO_AN_STAT1_LPABLE)) return; /* LP status is unknown */ - bad_lp = !(reg & (1 << MDIO_AN_STATUS_AN_DONE_LBN)); + bad_lp = !(reg & MDIO_AN_STAT1_COMPLETE); if (bad_lp) pd->bad_lp_tries++; } @@ -448,8 +414,8 @@ static void sfx7101_check_bad_lp(struct efx_nic *efx, bool link_ok) /* Use the RX (red) LED as an error indicator once we've seen AN * failure several times in a row, and also log a message. */ if (!bad_lp || pd->bad_lp_tries == MAX_BAD_LP_TRIES) { - reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, - PMA_PMD_LED_OVERR_REG); + reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, + PMA_PMD_LED_OVERR_REG); reg &= ~(PMA_PMD_LED_MASK << PMA_PMD_LED_RX_LBN); if (!bad_lp) { reg |= PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN; @@ -460,23 +426,22 @@ static void sfx7101_check_bad_lp(struct efx_nic *efx, bool link_ok) " supports 10GBASE-T ONLY, so no link can" " be established\n"); } - mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD, - PMA_PMD_LED_OVERR_REG, reg); + efx_mdio_write(efx, MDIO_MMD_PMAPMD, + PMA_PMD_LED_OVERR_REG, reg); pd->bad_lp_tries = bad_lp; } } static bool sfx7101_link_ok(struct efx_nic *efx) { - return mdio_clause45_links_ok(efx, - MDIO_MMDREG_DEVS_PMAPMD | - MDIO_MMDREG_DEVS_PCS | - MDIO_MMDREG_DEVS_PHYXS); + return efx_mdio_links_ok(efx, + MDIO_DEVS_PMAPMD | + MDIO_DEVS_PCS | + MDIO_DEVS_PHYXS); } static bool sft9001_link_ok(struct efx_nic *efx, struct ethtool_cmd *ecmd) { - int phy_id = efx->mii.phy_id; u32 reg; if (efx_phy_mode_disabled(efx->phy_mode)) @@ -484,50 +449,43 @@ static bool sft9001_link_ok(struct efx_nic *efx, struct ethtool_cmd *ecmd) else if (efx->loopback_mode == LOOPBACK_GPHY) return true; else if (efx->loopback_mode) - return mdio_clause45_links_ok(efx, - MDIO_MMDREG_DEVS_PMAPMD | - MDIO_MMDREG_DEVS_PHYXS); + return efx_mdio_links_ok(efx, + MDIO_DEVS_PMAPMD | + MDIO_DEVS_PHYXS); /* We must use the same definition of link state as LASI, * otherwise we can miss a link state transition */ if (ecmd->speed == 10000) { - reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PCS, - PCS_10GBASET_STAT1); - return reg & (1 << PCS_10GBASET_BLKLK_LBN); + reg = efx_mdio_read(efx, MDIO_MMD_PCS, MDIO_PCS_10GBRT_STAT1); + return reg & MDIO_PCS_10GBRT_STAT1_BLKLK; } else { - reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_C22EXT, - C22EXT_STATUS_REG); + reg = efx_mdio_read(efx, MDIO_MMD_C22EXT, C22EXT_STATUS_REG); return reg & (1 << C22EXT_STATUS_LINK_LBN); } } static void tenxpress_ext_loopback(struct efx_nic *efx) { - int phy_id = efx->mii.phy_id; - - mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_PHYXS, - PHYXS_TEST1, LOOPBACK_NEAR_LBN, - efx->loopback_mode == LOOPBACK_PHYXS); + efx_mdio_set_flag(efx, MDIO_MMD_PHYXS, PHYXS_TEST1, + 1 << LOOPBACK_NEAR_LBN, + efx->loopback_mode == LOOPBACK_PHYXS); if (efx->phy_type != PHY_TYPE_SFX7101) - mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_C22EXT, - GPHY_XCONTROL_REG, - GPHY_LOOPBACK_NEAR_LBN, - efx->loopback_mode == LOOPBACK_GPHY); + efx_mdio_set_flag(efx, MDIO_MMD_C22EXT, GPHY_XCONTROL_REG, + 1 << GPHY_LOOPBACK_NEAR_LBN, + efx->loopback_mode == LOOPBACK_GPHY); } static void tenxpress_low_power(struct efx_nic *efx) { - int phy_id = efx->mii.phy_id; - if (efx->phy_type == PHY_TYPE_SFX7101) - mdio_clause45_set_mmds_lpower( + efx_mdio_set_mmds_lpower( efx, !!(efx->phy_mode & PHY_MODE_LOW_POWER), TENXPRESS_REQUIRED_DEVS); else - mdio_clause45_set_flag( - efx, phy_id, MDIO_MMD_PMAPMD, - PMA_PMD_XCONTROL_REG, PMA_PMD_EXT_LPOWER_LBN, + efx_mdio_set_flag( + efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG, + 1 << PMA_PMD_EXT_LPOWER_LBN, !!(efx->phy_mode & PHY_MODE_LOW_POWER)); } @@ -568,8 +526,8 @@ static void tenxpress_phy_reconfigure(struct efx_nic *efx) WARN_ON(rc); } - mdio_clause45_transmit_disable(efx); - mdio_clause45_phy_reconfigure(efx); + efx_mdio_transmit_disable(efx); + efx_mdio_phy_reconfigure(efx); tenxpress_ext_loopback(efx); phy_data->loopback_mode = efx->loopback_mode; @@ -585,7 +543,7 @@ static void tenxpress_phy_reconfigure(struct efx_nic *efx) efx->link_fd = ecmd.duplex == DUPLEX_FULL; efx->link_up = sft9001_link_ok(efx, &ecmd); } - efx->link_fc = mdio_clause45_get_pause(efx); + efx->link_fc = efx_mdio_get_pause(efx); } /* Poll PHY for interrupt */ @@ -599,7 +557,7 @@ static void tenxpress_phy_poll(struct efx_nic *efx) if (link_ok != efx->link_up) { change = true; } else { - unsigned int link_fc = mdio_clause45_get_pause(efx); + unsigned int link_fc = efx_mdio_get_pause(efx); if (link_fc != efx->link_fc) change = true; } @@ -609,10 +567,9 @@ static void tenxpress_phy_poll(struct efx_nic *efx) if (link_ok != efx->link_up) change = true; } else { - u32 status = mdio_clause45_read(efx, efx->mii.phy_id, - MDIO_MMD_PMAPMD, - PMA_PMD_LASI_STATUS); - if (status & (1 << PMA_PMD_LS_ALARM_LBN)) + int status = efx_mdio_read(efx, MDIO_MMD_PMAPMD, + MDIO_PMA_LASI_STAT); + if (status & MDIO_PMA_LASI_LSALARM) change = true; } @@ -634,8 +591,7 @@ static void tenxpress_phy_fini(struct efx_nic *efx) if (efx->phy_type == PHY_TYPE_SFX7101) { /* Power down the LNPGA */ reg = (1 << PMA_PMD_LNPGA_POWERDOWN_LBN); - mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, - PMA_PMD_XCONTROL_REG, reg); + efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG, reg); /* Waiting here ensures that the board fini, which can turn * off the power to the PHY, won't get run until the LNPGA @@ -661,8 +617,7 @@ void tenxpress_phy_blink(struct efx_nic *efx, bool blink) else reg = PMA_PMD_LED_DEFAULT; - mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, - PMA_PMD_LED_OVERR_REG, reg); + efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_LED_OVERR_REG, reg); } static const char *const sfx7101_test_names[] = { @@ -698,7 +653,6 @@ static const char *const sft9001_test_names[] = { static int sft9001_run_tests(struct efx_nic *efx, int *results, unsigned flags) { struct ethtool_cmd ecmd; - int phy_id = efx->mii.phy_id; int rc = 0, rc2, i, ctrl_reg, res_reg; if (flags & ETH_TEST_FL_OFFLINE) @@ -717,11 +671,10 @@ static int sft9001_run_tests(struct efx_nic *efx, int *results, unsigned flags) * must reset the PHY to resume normal service. */ ctrl_reg |= (1 << CDIAG_CTRL_BRK_LINK_LBN); } - mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD, - PMA_PMD_CDIAG_CTRL_REG, ctrl_reg); + efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_CDIAG_CTRL_REG, + ctrl_reg); i = 0; - while (mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, - PMA_PMD_CDIAG_CTRL_REG) & + while (efx_mdio_read(efx, MDIO_MMD_PMAPMD, PMA_PMD_CDIAG_CTRL_REG) & (1 << CDIAG_CTRL_IN_PROG_LBN)) { if (++i == 50) { rc = -ETIMEDOUT; @@ -729,15 +682,13 @@ static int sft9001_run_tests(struct efx_nic *efx, int *results, unsigned flags) } msleep(100); } - res_reg = mdio_clause45_read(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, - PMA_PMD_CDIAG_RES_REG); + res_reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, PMA_PMD_CDIAG_RES_REG); for (i = 0; i < 4; i++) { int pair_res = (res_reg >> (CDIAG_RES_A_LBN - i * CDIAG_RES_WIDTH)) & ((1 << CDIAG_RES_WIDTH) - 1); - int len_reg = mdio_clause45_read(efx, efx->mii.phy_id, - MDIO_MMD_PMAPMD, - PMA_PMD_CDIAG_LEN_REG + i); + int len_reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, + PMA_PMD_CDIAG_LEN_REG + i); if (pair_res == CDIAG_RES_OK) results[1 + i] = 1; else if (pair_res == CDIAG_RES_INVALID) @@ -769,36 +720,39 @@ out: static void tenxpress_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) { - int phy_id = efx->mii.phy_id; u32 adv = 0, lpa = 0; int reg; if (efx->phy_type != PHY_TYPE_SFX7101) { - reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_C22EXT, - C22EXT_MSTSLV_CTRL); + reg = efx_mdio_read(efx, MDIO_MMD_C22EXT, C22EXT_MSTSLV_CTRL); if (reg & (1 << C22EXT_MSTSLV_CTRL_ADV_1000_FD_LBN)) adv |= ADVERTISED_1000baseT_Full; - reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_C22EXT, - C22EXT_MSTSLV_STATUS); + reg = efx_mdio_read(efx, MDIO_MMD_C22EXT, C22EXT_MSTSLV_STATUS); if (reg & (1 << C22EXT_MSTSLV_STATUS_LP_1000_HD_LBN)) lpa |= ADVERTISED_1000baseT_Half; if (reg & (1 << C22EXT_MSTSLV_STATUS_LP_1000_FD_LBN)) lpa |= ADVERTISED_1000baseT_Full; } - reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, - MDIO_AN_10GBT_CTRL); - if (reg & (1 << MDIO_AN_10GBT_CTRL_ADV_10G_LBN)) + reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL); + if (reg & MDIO_AN_10GBT_CTRL_ADV10G) adv |= ADVERTISED_10000baseT_Full; - reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, - MDIO_AN_10GBT_STATUS); - if (reg & (1 << MDIO_AN_10GBT_STATUS_LP_10G_LBN)) + reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_AN_10GBT_STAT); + if (reg & MDIO_AN_10GBT_STAT_LP10G) lpa |= ADVERTISED_10000baseT_Full; - mdio_clause45_get_settings_ext(efx, ecmd, adv, lpa); + mdio45_ethtool_gset_npage(&efx->mdio, ecmd, adv, lpa); - if (efx->phy_type != PHY_TYPE_SFX7101) + if (efx->phy_type != PHY_TYPE_SFX7101) { ecmd->supported |= (SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Full); + if (ecmd->speed != SPEED_10000) { + ecmd->eth_tp_mdix = + (efx_mdio_read(efx, MDIO_MMD_PMAPMD, + PMA_PMD_XSTATUS_REG) & + (1 << PMA_PMD_XSTAT_MDIX_LBN)) + ? ETH_TP_MDI_X : ETH_TP_MDI; + } + } /* In loopback, the PHY automatically brings up the correct interface, * but doesn't advertise the correct speed. So override it */ @@ -813,29 +767,24 @@ static int tenxpress_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) if (!ecmd->autoneg) return -EINVAL; - return mdio_clause45_set_settings(efx, ecmd); + return efx_mdio_set_settings(efx, ecmd); } static void sfx7101_set_npage_adv(struct efx_nic *efx, u32 advertising) { - mdio_clause45_set_flag(efx, efx->mii.phy_id, MDIO_MMD_AN, - MDIO_AN_10GBT_CTRL, - MDIO_AN_10GBT_CTRL_ADV_10G_LBN, - advertising & ADVERTISED_10000baseT_Full); + efx_mdio_set_flag(efx, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL, + MDIO_AN_10GBT_CTRL_ADV10G, + advertising & ADVERTISED_10000baseT_Full); } static void sft9001_set_npage_adv(struct efx_nic *efx, u32 advertising) { - int phy_id = efx->mii.phy_id; - - mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_C22EXT, - C22EXT_MSTSLV_CTRL, - C22EXT_MSTSLV_CTRL_ADV_1000_FD_LBN, - advertising & ADVERTISED_1000baseT_Full); - mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_AN, - MDIO_AN_10GBT_CTRL, - MDIO_AN_10GBT_CTRL_ADV_10G_LBN, - advertising & ADVERTISED_10000baseT_Full); + efx_mdio_set_flag(efx, MDIO_MMD_C22EXT, C22EXT_MSTSLV_CTRL, + 1 << C22EXT_MSTSLV_CTRL_ADV_1000_FD_LBN, + advertising & ADVERTISED_1000baseT_Full); + efx_mdio_set_flag(efx, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL, + MDIO_AN_10GBT_CTRL_ADV10G, + advertising & ADVERTISED_10000baseT_Full); } struct efx_phy_operations falcon_sfx7101_phy_ops = { diff --git a/drivers/net/sfc/tx.c b/drivers/net/sfc/tx.c index d6681edb7014..14a14788566c 100644 --- a/drivers/net/sfc/tx.c +++ b/drivers/net/sfc/tx.c @@ -360,13 +360,6 @@ inline int efx_xmit(struct efx_nic *efx, /* Map fragments for DMA and add to TX queue */ rc = efx_enqueue_skb(tx_queue, skb); - if (unlikely(rc != NETDEV_TX_OK)) - goto out; - - /* Update last TX timer */ - efx->net_dev->trans_start = jiffies; - - out: return rc; } diff --git a/drivers/net/sfc/xenpack.h b/drivers/net/sfc/xenpack.h deleted file mode 100644 index b0d1f225b70a..000000000000 --- a/drivers/net/sfc/xenpack.h +++ /dev/null @@ -1,62 +0,0 @@ -/**************************************************************************** - * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2006 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. - */ - -#ifndef EFX_XENPACK_H -#define EFX_XENPACK_H - -/* Exported functions from Xenpack standard PHY control */ - -#include "mdio_10g.h" - -/****************************************************************************/ -/* XENPACK MDIO register extensions */ -#define MDIO_XP_LASI_RX_CTRL (0x9000) -#define MDIO_XP_LASI_TX_CTRL (0x9001) -#define MDIO_XP_LASI_CTRL (0x9002) -#define MDIO_XP_LASI_RX_STAT (0x9003) -#define MDIO_XP_LASI_TX_STAT (0x9004) -#define MDIO_XP_LASI_STAT (0x9005) - -/* Control/Status bits */ -#define XP_LASI_LS_ALARM (1 << 0) -#define XP_LASI_TX_ALARM (1 << 1) -#define XP_LASI_RX_ALARM (1 << 2) -/* These two are Quake vendor extensions to the standard XENPACK defines */ -#define XP_LASI_LS_INTB (1 << 3) -#define XP_LASI_TEST (1 << 7) - -/* Enable LASI interrupts for PHY */ -static inline void xenpack_enable_lasi_irqs(struct efx_nic *efx) -{ - int reg; - int phy_id = efx->mii.phy_id; - /* Read to clear LASI status register */ - reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, - MDIO_XP_LASI_STAT); - - mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD, - MDIO_XP_LASI_CTRL, XP_LASI_LS_ALARM); -} - -/* Read the LASI interrupt status to clear the interrupt. */ -static inline int xenpack_clear_lasi_irqs(struct efx_nic *efx) -{ - /* Read to clear link status alarm */ - return mdio_clause45_read(efx, efx->mii.phy_id, - MDIO_MMD_PMAPMD, MDIO_XP_LASI_STAT); -} - -/* Turn off LASI interrupts */ -static inline void xenpack_disable_lasi_irqs(struct efx_nic *efx) -{ - mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, - MDIO_XP_LASI_CTRL, 0); -} - -#endif /* EFX_XENPACK_H */ diff --git a/drivers/net/sfc/xfp_phy.c b/drivers/net/sfc/xfp_phy.c index bb1ef77d5f56..bb2e6afd0829 100644 --- a/drivers/net/sfc/xfp_phy.c +++ b/drivers/net/sfc/xfp_phy.c @@ -15,13 +15,12 @@ #include #include "efx.h" #include "mdio_10g.h" -#include "xenpack.h" #include "phy.h" #include "falcon.h" -#define XFP_REQUIRED_DEVS (MDIO_MMDREG_DEVS_PCS | \ - MDIO_MMDREG_DEVS_PMAPMD | \ - MDIO_MMDREG_DEVS_PHYXS) +#define XFP_REQUIRED_DEVS (MDIO_DEVS_PCS | \ + MDIO_DEVS_PMAPMD | \ + MDIO_DEVS_PHYXS) #define XFP_LOOPBACKS ((1 << LOOPBACK_PCS) | \ (1 << LOOPBACK_PMAPMD) | \ @@ -49,8 +48,7 @@ void xfp_set_led(struct efx_nic *p, int led, int mode) { int addr = MDIO_QUAKE_LED0_REG + led; - mdio_clause45_write(p, p->mii.phy_id, MDIO_MMD_PMAPMD, addr, - mode); + efx_mdio_write(p, MDIO_MMD_PMAPMD, addr, mode); } struct xfp_phy_data { @@ -63,14 +61,12 @@ struct xfp_phy_data { static int qt2025c_wait_reset(struct efx_nic *efx) { unsigned long timeout = jiffies + 10 * HZ; - int phy_id = efx->mii.phy_id; int reg, old_counter = 0; /* Wait for firmware heartbeat to start */ for (;;) { int counter; - reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PCS, - PCS_FW_HEARTBEAT_REG); + reg = efx_mdio_read(efx, MDIO_MMD_PCS, PCS_FW_HEARTBEAT_REG); if (reg < 0) return reg; counter = ((reg >> PCS_FW_HEARTB_LBN) & @@ -86,8 +82,7 @@ static int qt2025c_wait_reset(struct efx_nic *efx) /* Wait for firmware status to look good */ for (;;) { - reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PCS, - PCS_UC8051_STATUS_REG); + reg = efx_mdio_read(efx, MDIO_MMD_PCS, PCS_UC8051_STATUS_REG); if (reg < 0) return reg; if ((reg & @@ -109,9 +104,9 @@ static int xfp_reset_phy(struct efx_nic *efx) { int rc; - rc = mdio_clause45_reset_mmd(efx, MDIO_MMD_PHYXS, - XFP_MAX_RESET_TIME / XFP_RESET_WAIT, - XFP_RESET_WAIT); + rc = efx_mdio_reset_mmd(efx, MDIO_MMD_PHYXS, + XFP_MAX_RESET_TIME / XFP_RESET_WAIT, + XFP_RESET_WAIT); if (rc < 0) goto fail; @@ -126,8 +121,7 @@ static int xfp_reset_phy(struct efx_nic *efx) /* Check that all the MMDs we expect are present and responding. We * expect faults on some if the link is down, but not on the PHY XS */ - rc = mdio_clause45_check_mmds(efx, XFP_REQUIRED_DEVS, - MDIO_MMDREG_DEVS_PHYXS); + rc = efx_mdio_check_mmds(efx, XFP_REQUIRED_DEVS, MDIO_DEVS_PHYXS); if (rc < 0) goto fail; @@ -143,7 +137,7 @@ static int xfp_reset_phy(struct efx_nic *efx) static int xfp_phy_init(struct efx_nic *efx) { struct xfp_phy_data *phy_data; - u32 devid = mdio_clause45_read_id(efx, MDIO_MMD_PHYXS); + u32 devid = efx_mdio_read_id(efx, MDIO_MMD_PHYXS); int rc; phy_data = kzalloc(sizeof(struct xfp_phy_data), GFP_KERNEL); @@ -152,8 +146,8 @@ static int xfp_phy_init(struct efx_nic *efx) efx->phy_data = phy_data; EFX_INFO(efx, "PHY ID reg %x (OUI %06x model %02x revision %x)\n", - devid, mdio_id_oui(devid), mdio_id_model(devid), - mdio_id_rev(devid)); + devid, efx_mdio_id_oui(devid), efx_mdio_id_model(devid), + efx_mdio_id_rev(devid)); phy_data->phy_mode = efx->phy_mode; @@ -174,12 +168,13 @@ static int xfp_phy_init(struct efx_nic *efx) static void xfp_phy_clear_interrupt(struct efx_nic *efx) { - xenpack_clear_lasi_irqs(efx); + /* Read to clear link status alarm */ + efx_mdio_read(efx, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_STAT); } static int xfp_link_ok(struct efx_nic *efx) { - return mdio_clause45_links_ok(efx, XFP_REQUIRED_DEVS); + return efx_mdio_links_ok(efx, XFP_REQUIRED_DEVS); } static void xfp_phy_poll(struct efx_nic *efx) @@ -200,9 +195,9 @@ static void xfp_phy_reconfigure(struct efx_nic *efx) * or optical transceivers, varying somewhat between * firmware versions. Only 'static mode' appears to * cover everything. */ - mdio_clause45_set_flag( - efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, - PMA_PMD_FTX_CTRL2_REG, PMA_PMD_FTX_STATIC_LBN, + mdio_set_flag( + &efx->mdio, efx->mdio.prtad, MDIO_MMD_PMAPMD, + PMA_PMD_FTX_CTRL2_REG, 1 << PMA_PMD_FTX_STATIC_LBN, efx->phy_mode & PHY_MODE_TX_DISABLED || efx->phy_mode & PHY_MODE_LOW_POWER || efx->loopback_mode == LOOPBACK_PCS || @@ -213,10 +208,10 @@ static void xfp_phy_reconfigure(struct efx_nic *efx) (phy_data->phy_mode & PHY_MODE_TX_DISABLED)) xfp_reset_phy(efx); - mdio_clause45_transmit_disable(efx); + efx_mdio_transmit_disable(efx); } - mdio_clause45_phy_reconfigure(efx); + efx_mdio_phy_reconfigure(efx); phy_data->phy_mode = efx->phy_mode; efx->link_up = xfp_link_ok(efx); @@ -225,6 +220,10 @@ static void xfp_phy_reconfigure(struct efx_nic *efx) efx->link_fc = efx->wanted_fc; } +static void xfp_phy_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) +{ + mdio45_ethtool_gset(&efx->mdio, ecmd); +} static void xfp_phy_fini(struct efx_nic *efx) { @@ -243,8 +242,8 @@ struct efx_phy_operations falcon_xfp_phy_ops = { .poll = xfp_phy_poll, .fini = xfp_phy_fini, .clear_interrupt = xfp_phy_clear_interrupt, - .get_settings = mdio_clause45_get_settings, - .set_settings = mdio_clause45_set_settings, + .get_settings = xfp_phy_get_settings, + .set_settings = efx_mdio_set_settings, .mmds = XFP_REQUIRED_DEVS, .loopbacks = XFP_LOOPBACKS, }; diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c index 97d68560067d..5fb88ca6dd7f 100644 --- a/drivers/net/sgiseeq.c +++ b/drivers/net/sgiseeq.c @@ -709,6 +709,17 @@ static inline void setup_rx_ring(struct net_device *dev, dma_sync_desc_dev(dev, &buf[i]); } +static const struct net_device_ops sgiseeq_netdev_ops = { + .ndo_open = sgiseeq_open, + .ndo_stop = sgiseeq_close, + .ndo_start_xmit = sgiseeq_start_xmit, + .ndo_tx_timeout = timeout, + .ndo_set_multicast_list = sgiseeq_set_multicast, + .ndo_set_mac_address = sgiseeq_set_mac_address, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, +}; + static int __init sgiseeq_probe(struct platform_device *pdev) { struct sgiseeq_platform_data *pd = pdev->dev.platform_data; @@ -775,13 +786,8 @@ static int __init sgiseeq_probe(struct platform_device *pdev) SEEQ_CTRL_SFLAG | SEEQ_CTRL_ESHORT | SEEQ_CTRL_ENCARR; - dev->open = sgiseeq_open; - dev->stop = sgiseeq_close; - dev->hard_start_xmit = sgiseeq_start_xmit; - dev->tx_timeout = timeout; + dev->netdev_ops = &sgiseeq_netdev_ops; dev->watchdog_timeo = (200 * HZ) / 1000; - dev->set_multicast_list = sgiseeq_set_multicast; - dev->set_mac_address = sgiseeq_set_mac_address; dev->irq = irq; if (register_netdev(dev)) { diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c index 3ab28bb00c12..341882f959f3 100644 --- a/drivers/net/sh_eth.c +++ b/drivers/net/sh_eth.c @@ -2,7 +2,7 @@ * SuperH Ethernet device driver * * Copyright (C) 2006-2008 Nobuhiro Iwamatsu - * Copyright (C) 2008 Renesas Solutions Corp. + * Copyright (C) 2008-2009 Renesas Solutions Corp. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -33,6 +33,226 @@ #include "sh_eth.h" +/* There is CPU dependent code */ +#if defined(CONFIG_CPU_SUBTYPE_SH7724) +#define SH_ETH_RESET_DEFAULT 1 +static void sh_eth_set_duplex(struct net_device *ndev) +{ + struct sh_eth_private *mdp = netdev_priv(ndev); + u32 ioaddr = ndev->base_addr; + + if (mdp->duplex) /* Full */ + ctrl_outl(ctrl_inl(ioaddr + ECMR) | ECMR_DM, ioaddr + ECMR); + else /* Half */ + ctrl_outl(ctrl_inl(ioaddr + ECMR) & ~ECMR_DM, ioaddr + ECMR); +} + +static void sh_eth_set_rate(struct net_device *ndev) +{ + struct sh_eth_private *mdp = netdev_priv(ndev); + u32 ioaddr = ndev->base_addr; + + switch (mdp->speed) { + case 10: /* 10BASE */ + ctrl_outl(ctrl_inl(ioaddr + ECMR) & ~ECMR_RTM, ioaddr + ECMR); + break; + case 100:/* 100BASE */ + ctrl_outl(ctrl_inl(ioaddr + ECMR) | ECMR_RTM, ioaddr + ECMR); + break; + default: + break; + } +} + +/* SH7724 */ +static struct sh_eth_cpu_data sh_eth_my_cpu_data = { + .set_duplex = sh_eth_set_duplex, + .set_rate = sh_eth_set_rate, + + .ecsr_value = ECSR_PSRTO | ECSR_LCHNG | ECSR_ICD, + .ecsipr_value = ECSIPR_PSRTOIP | ECSIPR_LCHNGIP | ECSIPR_ICDIP, + .eesipr_value = DMAC_M_RFRMER | DMAC_M_ECI | 0x01ff009f, + + .tx_check = EESR_FTC | EESR_CND | EESR_DLC | EESR_CD | EESR_RTO, + .eesr_err_check = EESR_TWB | EESR_TABT | EESR_RABT | EESR_RDE | + EESR_RFRMER | EESR_TFE | EESR_TDE | EESR_ECI, + .tx_error_check = EESR_TWB | EESR_TABT | EESR_TDE | EESR_TFE, + + .apr = 1, + .mpr = 1, + .tpauser = 1, + .hw_swap = 1, +}; + +#elif defined(CONFIG_CPU_SUBTYPE_SH7763) +#define SH_ETH_HAS_TSU 1 +static void sh_eth_chip_reset(struct net_device *ndev) +{ + /* reset device */ + ctrl_outl(ARSTR_ARSTR, ARSTR); + mdelay(1); +} + +static void sh_eth_reset(struct net_device *ndev) +{ + u32 ioaddr = ndev->base_addr; + int cnt = 100; + + ctrl_outl(EDSR_ENALL, ioaddr + EDSR); + ctrl_outl(ctrl_inl(ioaddr + EDMR) | EDMR_SRST, ioaddr + EDMR); + while (cnt > 0) { + if (!(ctrl_inl(ioaddr + EDMR) & 0x3)) + break; + mdelay(1); + cnt--; + } + if (cnt < 0) + printk(KERN_ERR "Device reset fail\n"); + + /* Table Init */ + ctrl_outl(0x0, ioaddr + TDLAR); + ctrl_outl(0x0, ioaddr + TDFAR); + ctrl_outl(0x0, ioaddr + TDFXR); + ctrl_outl(0x0, ioaddr + TDFFR); + ctrl_outl(0x0, ioaddr + RDLAR); + ctrl_outl(0x0, ioaddr + RDFAR); + ctrl_outl(0x0, ioaddr + RDFXR); + ctrl_outl(0x0, ioaddr + RDFFR); +} + +static void sh_eth_set_duplex(struct net_device *ndev) +{ + struct sh_eth_private *mdp = netdev_priv(ndev); + u32 ioaddr = ndev->base_addr; + + if (mdp->duplex) /* Full */ + ctrl_outl(ctrl_inl(ioaddr + ECMR) | ECMR_DM, ioaddr + ECMR); + else /* Half */ + ctrl_outl(ctrl_inl(ioaddr + ECMR) & ~ECMR_DM, ioaddr + ECMR); +} + +static void sh_eth_set_rate(struct net_device *ndev) +{ + struct sh_eth_private *mdp = netdev_priv(ndev); + u32 ioaddr = ndev->base_addr; + + switch (mdp->speed) { + case 10: /* 10BASE */ + ctrl_outl(GECMR_10, ioaddr + GECMR); + break; + case 100:/* 100BASE */ + ctrl_outl(GECMR_100, ioaddr + GECMR); + break; + case 1000: /* 1000BASE */ + ctrl_outl(GECMR_1000, ioaddr + GECMR); + break; + default: + break; + } +} + +/* sh7763 */ +static struct sh_eth_cpu_data sh_eth_my_cpu_data = { + .chip_reset = sh_eth_chip_reset, + .set_duplex = sh_eth_set_duplex, + .set_rate = sh_eth_set_rate, + + .ecsr_value = ECSR_ICD | ECSR_MPD, + .ecsipr_value = ECSIPR_LCHNGIP | ECSIPR_ICDIP | ECSIPR_MPDIP, + .eesipr_value = DMAC_M_RFRMER | DMAC_M_ECI | 0x003fffff, + + .tx_check = EESR_TC1 | EESR_FTC, + .eesr_err_check = EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT | \ + EESR_RDE | EESR_RFRMER | EESR_TFE | EESR_TDE | \ + EESR_ECI, + .tx_error_check = EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_TDE | \ + EESR_TFE, + + .apr = 1, + .mpr = 1, + .tpauser = 1, + .bculr = 1, + .hw_swap = 1, + .rpadir = 1, + .no_trimd = 1, + .no_ade = 1, +}; + +#elif defined(CONFIG_CPU_SUBTYPE_SH7619) +#define SH_ETH_RESET_DEFAULT 1 +static struct sh_eth_cpu_data sh_eth_my_cpu_data = { + .eesipr_value = DMAC_M_RFRMER | DMAC_M_ECI | 0x003fffff, + + .apr = 1, + .mpr = 1, + .tpauser = 1, + .hw_swap = 1, +}; +#elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712) +#define SH_ETH_RESET_DEFAULT 1 +#define SH_ETH_HAS_TSU 1 +static struct sh_eth_cpu_data sh_eth_my_cpu_data = { + .eesipr_value = DMAC_M_RFRMER | DMAC_M_ECI | 0x003fffff, +}; +#endif + +static void sh_eth_set_default_cpu_data(struct sh_eth_cpu_data *cd) +{ + if (!cd->ecsr_value) + cd->ecsr_value = DEFAULT_ECSR_INIT; + + if (!cd->ecsipr_value) + cd->ecsipr_value = DEFAULT_ECSIPR_INIT; + + if (!cd->fcftr_value) + cd->fcftr_value = DEFAULT_FIFO_F_D_RFF | \ + DEFAULT_FIFO_F_D_RFD; + + if (!cd->fdr_value) + cd->fdr_value = DEFAULT_FDR_INIT; + + if (!cd->rmcr_value) + cd->rmcr_value = DEFAULT_RMCR_VALUE; + + if (!cd->tx_check) + cd->tx_check = DEFAULT_TX_CHECK; + + if (!cd->eesr_err_check) + cd->eesr_err_check = DEFAULT_EESR_ERR_CHECK; + + if (!cd->tx_error_check) + cd->tx_error_check = DEFAULT_TX_ERROR_CHECK; +} + +#if defined(SH_ETH_RESET_DEFAULT) +/* Chip Reset */ +static void sh_eth_reset(struct net_device *ndev) +{ + u32 ioaddr = ndev->base_addr; + + ctrl_outl(ctrl_inl(ioaddr + EDMR) | EDMR_SRST, ioaddr + EDMR); + mdelay(3); + ctrl_outl(ctrl_inl(ioaddr + EDMR) & ~EDMR_SRST, ioaddr + EDMR); +} +#endif + +#if defined(CONFIG_CPU_SH4) +static void sh_eth_set_receive_align(struct sk_buff *skb) +{ + int reserve; + + reserve = SH4_SKB_RX_ALIGN - ((u32)skb->data & (SH4_SKB_RX_ALIGN - 1)); + if (reserve) + skb_reserve(skb, reserve); +} +#else +static void sh_eth_set_receive_align(struct sk_buff *skb) +{ + skb_reserve(skb, SH2_SH3_SKB_RX_ALIGN); +} +#endif + + /* CPU <-> EDMAC endian convert */ static inline __u32 cpu_to_edmac(struct sh_eth_private *mdp, u32 x) { @@ -165,41 +385,6 @@ static struct mdiobb_ops bb_ops = { .get_mdio_data = sh_get_mdio, }; -/* Chip Reset */ -static void sh_eth_reset(struct net_device *ndev) -{ - u32 ioaddr = ndev->base_addr; - -#if defined(CONFIG_CPU_SUBTYPE_SH7763) - int cnt = 100; - - ctrl_outl(EDSR_ENALL, ioaddr + EDSR); - ctrl_outl(ctrl_inl(ioaddr + EDMR) | EDMR_SRST, ioaddr + EDMR); - while (cnt > 0) { - if (!(ctrl_inl(ioaddr + EDMR) & 0x3)) - break; - mdelay(1); - cnt--; - } - if (cnt < 0) - printk(KERN_ERR "Device reset fail\n"); - - /* Table Init */ - ctrl_outl(0x0, ioaddr + TDLAR); - ctrl_outl(0x0, ioaddr + TDFAR); - ctrl_outl(0x0, ioaddr + TDFXR); - ctrl_outl(0x0, ioaddr + TDFFR); - ctrl_outl(0x0, ioaddr + RDLAR); - ctrl_outl(0x0, ioaddr + RDFAR); - ctrl_outl(0x0, ioaddr + RDFXR); - ctrl_outl(0x0, ioaddr + RDFFR); -#else - ctrl_outl(ctrl_inl(ioaddr + EDMR) | EDMR_SRST, ioaddr + EDMR); - mdelay(3); - ctrl_outl(ctrl_inl(ioaddr + EDMR) & ~EDMR_SRST, ioaddr + EDMR); -#endif -} - /* free skb and descriptor buffer */ static void sh_eth_ring_free(struct net_device *ndev) { @@ -228,7 +413,7 @@ static void sh_eth_ring_free(struct net_device *ndev) /* format skb and descriptor buffer */ static void sh_eth_ring_format(struct net_device *ndev) { - u32 ioaddr = ndev->base_addr, reserve = 0; + u32 ioaddr = ndev->base_addr; struct sh_eth_private *mdp = netdev_priv(ndev); int i; struct sk_buff *skb; @@ -250,37 +435,27 @@ static void sh_eth_ring_format(struct net_device *ndev) mdp->rx_skbuff[i] = skb; if (skb == NULL) break; + dma_map_single(&ndev->dev, skb->tail, mdp->rx_buf_sz, + DMA_FROM_DEVICE); skb->dev = ndev; /* Mark as being used by this device. */ -#if defined(CONFIG_CPU_SUBTYPE_SH7763) - reserve = SH7763_SKB_ALIGN - - ((uint32_t)skb->data & (SH7763_SKB_ALIGN-1)); - if (reserve) - skb_reserve(skb, reserve); -#else - skb_reserve(skb, RX_OFFSET); -#endif + sh_eth_set_receive_align(skb); + /* RX descriptor */ rxdesc = &mdp->rx_ring[i]; - rxdesc->addr = (u32)skb->data & ~0x3UL; + rxdesc->addr = virt_to_phys(PTR_ALIGN(skb->data, 4)); rxdesc->status = cpu_to_edmac(mdp, RD_RACT | RD_RFP); /* The size of the buffer is 16 byte boundary. */ - rxdesc->buffer_length = (mdp->rx_buf_sz + 16) & ~0x0F; + rxdesc->buffer_length = ALIGN(mdp->rx_buf_sz, 16); /* Rx descriptor address set */ if (i == 0) { - ctrl_outl((u32)rxdesc, ioaddr + RDLAR); + ctrl_outl(mdp->rx_desc_dma, ioaddr + RDLAR); #if defined(CONFIG_CPU_SUBTYPE_SH7763) - ctrl_outl((u32)rxdesc, ioaddr + RDFAR); + ctrl_outl(mdp->rx_desc_dma, ioaddr + RDFAR); #endif } } - /* Rx descriptor address set */ -#if defined(CONFIG_CPU_SUBTYPE_SH7763) - ctrl_outl((u32)rxdesc, ioaddr + RDFXR); - ctrl_outl(0x1, ioaddr + RDFFR); -#endif - mdp->dirty_rx = (u32) (i - RX_RING_SIZE); /* Mark the last entry as wrapping the ring. */ @@ -296,19 +471,13 @@ static void sh_eth_ring_format(struct net_device *ndev) txdesc->buffer_length = 0; if (i == 0) { /* Tx descriptor address set */ - ctrl_outl((u32)txdesc, ioaddr + TDLAR); + ctrl_outl(mdp->tx_desc_dma, ioaddr + TDLAR); #if defined(CONFIG_CPU_SUBTYPE_SH7763) - ctrl_outl((u32)txdesc, ioaddr + TDFAR); + ctrl_outl(mdp->tx_desc_dma, ioaddr + TDFAR); #endif } } - /* Tx descriptor address set */ -#if defined(CONFIG_CPU_SUBTYPE_SH7763) - ctrl_outl((u32)txdesc, ioaddr + TDFXR); - ctrl_outl(0x1, ioaddr + TDFFR); -#endif - txdesc->status |= cpu_to_edmac(mdp, TD_TDLE); } @@ -331,7 +500,7 @@ static int sh_eth_ring_init(struct net_device *ndev) mdp->rx_skbuff = kmalloc(sizeof(*mdp->rx_skbuff) * RX_RING_SIZE, GFP_KERNEL); if (!mdp->rx_skbuff) { - printk(KERN_ERR "%s: Cannot allocate Rx skb\n", ndev->name); + dev_err(&ndev->dev, "Cannot allocate Rx skb\n"); ret = -ENOMEM; return ret; } @@ -339,7 +508,7 @@ static int sh_eth_ring_init(struct net_device *ndev) mdp->tx_skbuff = kmalloc(sizeof(*mdp->tx_skbuff) * TX_RING_SIZE, GFP_KERNEL); if (!mdp->tx_skbuff) { - printk(KERN_ERR "%s: Cannot allocate Tx skb\n", ndev->name); + dev_err(&ndev->dev, "Cannot allocate Tx skb\n"); ret = -ENOMEM; goto skb_ring_free; } @@ -350,8 +519,8 @@ static int sh_eth_ring_init(struct net_device *ndev) GFP_KERNEL); if (!mdp->rx_ring) { - printk(KERN_ERR "%s: Cannot allocate Rx Ring (size %d bytes)\n", - ndev->name, rx_ringsize); + dev_err(&ndev->dev, "Cannot allocate Rx Ring (size %d bytes)\n", + rx_ringsize); ret = -ENOMEM; goto desc_ring_free; } @@ -363,8 +532,8 @@ static int sh_eth_ring_init(struct net_device *ndev) mdp->tx_ring = dma_alloc_coherent(NULL, tx_ringsize, &mdp->tx_desc_dma, GFP_KERNEL); if (!mdp->tx_ring) { - printk(KERN_ERR "%s: Cannot allocate Tx Ring (size %d bytes)\n", - ndev->name, tx_ringsize); + dev_err(&ndev->dev, "Cannot allocate Tx Ring (size %d bytes)\n", + tx_ringsize); ret = -ENOMEM; goto desc_ring_free; } @@ -394,44 +563,43 @@ static int sh_eth_dev_init(struct net_device *ndev) /* Descriptor format */ sh_eth_ring_format(ndev); - ctrl_outl(RPADIR_INIT, ioaddr + RPADIR); + if (mdp->cd->rpadir) + ctrl_outl(mdp->cd->rpadir_value, ioaddr + RPADIR); /* all sh_eth int mask */ ctrl_outl(0, ioaddr + EESIPR); -#if defined(CONFIG_CPU_SUBTYPE_SH7763) - ctrl_outl(EDMR_EL, ioaddr + EDMR); -#else - ctrl_outl(0, ioaddr + EDMR); /* Endian change */ +#if defined(__LITTLE_ENDIAN__) + if (mdp->cd->hw_swap) + ctrl_outl(EDMR_EL, ioaddr + EDMR); + else #endif + ctrl_outl(0, ioaddr + EDMR); /* FIFO size set */ - ctrl_outl((FIFO_SIZE_T | FIFO_SIZE_R), ioaddr + FDR); + ctrl_outl(mdp->cd->fdr_value, ioaddr + FDR); ctrl_outl(0, ioaddr + TFTR); /* Frame recv control */ - ctrl_outl(0, ioaddr + RMCR); + ctrl_outl(mdp->cd->rmcr_value, ioaddr + RMCR); rx_int_var = mdp->rx_int_var = DESC_I_RINT8 | DESC_I_RINT5; tx_int_var = mdp->tx_int_var = DESC_I_TINT2; ctrl_outl(rx_int_var | tx_int_var, ioaddr + TRSCER); -#if defined(CONFIG_CPU_SUBTYPE_SH7763) - /* Burst sycle set */ - ctrl_outl(0x800, ioaddr + BCULR); -#endif + if (mdp->cd->bculr) + ctrl_outl(0x800, ioaddr + BCULR); /* Burst sycle set */ - ctrl_outl((FIFO_F_D_RFF | FIFO_F_D_RFD), ioaddr + FCFTR); + ctrl_outl(mdp->cd->fcftr_value, ioaddr + FCFTR); -#if !defined(CONFIG_CPU_SUBTYPE_SH7763) - ctrl_outl(0, ioaddr + TRIMD); -#endif + if (!mdp->cd->no_trimd) + ctrl_outl(0, ioaddr + TRIMD); /* Recv frame limit set register */ ctrl_outl(RFLR_VALUE, ioaddr + RFLR); ctrl_outl(ctrl_inl(ioaddr + EESR), ioaddr + EESR); - ctrl_outl((DMAC_M_RFRMER | DMAC_M_ECI | 0x003fffff), ioaddr + EESIPR); + ctrl_outl(mdp->cd->eesipr_value, ioaddr + EESIPR); /* PAUSE Prohibition */ val = (ctrl_inl(ioaddr + ECMR) & ECMR_DM) | @@ -439,24 +607,25 @@ static int sh_eth_dev_init(struct net_device *ndev) ctrl_outl(val, ioaddr + ECMR); + if (mdp->cd->set_rate) + mdp->cd->set_rate(ndev); + /* E-MAC Status Register clear */ - ctrl_outl(ECSR_INIT, ioaddr + ECSR); + ctrl_outl(mdp->cd->ecsr_value, ioaddr + ECSR); /* E-MAC Interrupt Enable register */ - ctrl_outl(ECSIPR_INIT, ioaddr + ECSIPR); + ctrl_outl(mdp->cd->ecsipr_value, ioaddr + ECSIPR); /* Set MAC address */ update_mac_address(ndev); /* mask reset */ -#if defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7763) - ctrl_outl(APR_AP, ioaddr + APR); - ctrl_outl(MPR_MP, ioaddr + MPR); - ctrl_outl(TPAUSER_UNLIMITED, ioaddr + TPAUSER); -#endif -#if defined(CONFIG_CPU_SUBTYPE_SH7710) - ctrl_outl(BCFR_UNLIMITED, ioaddr + BCFR); -#endif + if (mdp->cd->apr) + ctrl_outl(APR_AP, ioaddr + APR); + if (mdp->cd->mpr) + ctrl_outl(MPR_MP, ioaddr + MPR); + if (mdp->cd->tpauser) + ctrl_outl(TPAUSER_UNLIMITED, ioaddr + TPAUSER); /* Setting the Rx mode will start the Rx process. */ ctrl_outl(EDRRR_R, ioaddr + EDRRR); @@ -505,7 +674,7 @@ static int sh_eth_rx(struct net_device *ndev) int boguscnt = (mdp->dirty_rx + RX_RING_SIZE) - mdp->cur_rx; struct sk_buff *skb; u16 pkt_len = 0; - u32 desc_status, reserve = 0; + u32 desc_status; rxdesc = &mdp->rx_ring[entry]; while (!(rxdesc->status & cpu_to_edmac(mdp, RD_RACT))) { @@ -534,7 +703,10 @@ static int sh_eth_rx(struct net_device *ndev) if (desc_status & RD_RFS10) mdp->stats.rx_over_errors++; } else { - swaps((char *)(rxdesc->addr & ~0x3), pkt_len + 2); + if (!mdp->cd->hw_swap) + sh_eth_soft_swap( + phys_to_virt(ALIGN(rxdesc->addr, 4)), + pkt_len + 2); skb = mdp->rx_skbuff[entry]; mdp->rx_skbuff[entry] = NULL; skb_put(skb, pkt_len); @@ -545,6 +717,7 @@ static int sh_eth_rx(struct net_device *ndev) } rxdesc->status |= cpu_to_edmac(mdp, RD_RACT); entry = (++mdp->cur_rx) % RX_RING_SIZE; + rxdesc = &mdp->rx_ring[entry]; } /* Refill the Rx ring buffers. */ @@ -552,24 +725,20 @@ static int sh_eth_rx(struct net_device *ndev) entry = mdp->dirty_rx % RX_RING_SIZE; rxdesc = &mdp->rx_ring[entry]; /* The size of the buffer is 16 byte boundary. */ - rxdesc->buffer_length = (mdp->rx_buf_sz + 16) & ~0x0F; + rxdesc->buffer_length = ALIGN(mdp->rx_buf_sz, 16); if (mdp->rx_skbuff[entry] == NULL) { skb = dev_alloc_skb(mdp->rx_buf_sz); mdp->rx_skbuff[entry] = skb; if (skb == NULL) break; /* Better luck next round. */ + dma_map_single(&ndev->dev, skb->tail, mdp->rx_buf_sz, + DMA_FROM_DEVICE); skb->dev = ndev; -#if defined(CONFIG_CPU_SUBTYPE_SH7763) - reserve = SH7763_SKB_ALIGN - - ((uint32_t)skb->data & (SH7763_SKB_ALIGN-1)); - if (reserve) - skb_reserve(skb, reserve); -#else - skb_reserve(skb, RX_OFFSET); -#endif + sh_eth_set_receive_align(skb); + skb->ip_summed = CHECKSUM_NONE; - rxdesc->addr = (u32)skb->data & ~0x3UL; + rxdesc->addr = virt_to_phys(PTR_ALIGN(skb->data, 4)); } if (entry >= RX_RING_SIZE - 1) rxdesc->status |= @@ -593,6 +762,8 @@ static void sh_eth_error(struct net_device *ndev, int intr_status) struct sh_eth_private *mdp = netdev_priv(ndev); u32 ioaddr = ndev->base_addr; u32 felic_stat; + u32 link_stat; + u32 mask; if (intr_status & EESR_ECI) { felic_stat = ctrl_inl(ioaddr + ECSR); @@ -601,7 +772,14 @@ static void sh_eth_error(struct net_device *ndev, int intr_status) mdp->stats.tx_carrier_errors++; if (felic_stat & ECSR_LCHNG) { /* Link Changed */ - u32 link_stat = (ctrl_inl(ioaddr + PSR)); + if (mdp->cd->no_psr) { + if (mdp->link == PHY_DOWN) + link_stat = 0; + else + link_stat = PHY_ST_LINK; + } else { + link_stat = (ctrl_inl(ioaddr + PSR)); + } if (!(link_stat & PHY_ST_LINK)) { /* Link Down : disable tx and rx */ ctrl_outl(ctrl_inl(ioaddr + ECMR) & @@ -633,17 +811,15 @@ static void sh_eth_error(struct net_device *ndev, int intr_status) if (intr_status & EESR_RFRMER) { /* Receive Frame Overflow int */ mdp->stats.rx_frame_errors++; - printk(KERN_ERR "Receive Frame Overflow\n"); + dev_err(&ndev->dev, "Receive Frame Overflow\n"); } } -#if !defined(CONFIG_CPU_SUBTYPE_SH7763) - if (intr_status & EESR_ADE) { - if (intr_status & EESR_TDE) { - if (intr_status & EESR_TFE) - mdp->stats.tx_fifo_errors++; - } + + if (!mdp->cd->no_ade) { + if (intr_status & EESR_ADE && intr_status & EESR_TDE && + intr_status & EESR_TFE) + mdp->stats.tx_fifo_errors++; } -#endif if (intr_status & EESR_RDE) { /* Receive Descriptor Empty int */ @@ -651,24 +827,24 @@ static void sh_eth_error(struct net_device *ndev, int intr_status) if (ctrl_inl(ioaddr + EDRRR) ^ EDRRR_R) ctrl_outl(EDRRR_R, ioaddr + EDRRR); - printk(KERN_ERR "Receive Descriptor Empty\n"); + dev_err(&ndev->dev, "Receive Descriptor Empty\n"); } if (intr_status & EESR_RFE) { /* Receive FIFO Overflow int */ mdp->stats.rx_fifo_errors++; - printk(KERN_ERR "Receive FIFO Overflow\n"); + dev_err(&ndev->dev, "Receive FIFO Overflow\n"); } - if (intr_status & (EESR_TWB | EESR_TABT | -#if !defined(CONFIG_CPU_SUBTYPE_SH7763) - EESR_ADE | -#endif - EESR_TDE | EESR_TFE)) { + + mask = EESR_TWB | EESR_TABT | EESR_ADE | EESR_TDE | EESR_TFE; + if (mdp->cd->no_ade) + mask &= ~EESR_ADE; + if (intr_status & mask) { /* Tx error */ u32 edtrr = ctrl_inl(ndev->base_addr + EDTRR); /* dmesg */ - printk(KERN_ERR "%s:TX error. status=%8.8x cur_tx=%8.8x ", - ndev->name, intr_status, mdp->cur_tx); - printk(KERN_ERR "dirty_tx=%8.8x state=%8.8x EDTRR=%8.8x.\n", + dev_err(&ndev->dev, "TX error. status=%8.8x cur_tx=%8.8x ", + intr_status, mdp->cur_tx); + dev_err(&ndev->dev, "dirty_tx=%8.8x state=%8.8x EDTRR=%8.8x.\n", mdp->dirty_tx, (u32) ndev->state, edtrr); /* dirty buffer free */ sh_eth_txfree(ndev); @@ -687,6 +863,7 @@ static irqreturn_t sh_eth_interrupt(int irq, void *netdev) { struct net_device *ndev = netdev; struct sh_eth_private *mdp = netdev_priv(ndev); + struct sh_eth_cpu_data *cd = mdp->cd; irqreturn_t ret = IRQ_NONE; u32 ioaddr, boguscnt = RX_RING_SIZE; u32 intr_status = 0; @@ -699,7 +876,7 @@ static irqreturn_t sh_eth_interrupt(int irq, void *netdev) /* Clear interrupt */ if (intr_status & (EESR_FRC | EESR_RMAF | EESR_RRF | EESR_RTLF | EESR_RTSF | EESR_PRE | EESR_CERF | - TX_CHECK | EESR_ERR_CHECK)) { + cd->tx_check | cd->eesr_err_check)) { ctrl_outl(intr_status, ioaddr + EESR); ret = IRQ_HANDLED; } else @@ -716,12 +893,12 @@ static irqreturn_t sh_eth_interrupt(int irq, void *netdev) } /* Tx Check */ - if (intr_status & TX_CHECK) { + if (intr_status & cd->tx_check) { sh_eth_txfree(ndev); netif_wake_queue(ndev); } - if (intr_status & EESR_ERR_CHECK) + if (intr_status & cd->eesr_err_check) sh_eth_error(ndev, intr_status); if (--boguscnt < 0) { @@ -756,32 +933,15 @@ static void sh_eth_adjust_link(struct net_device *ndev) if (phydev->duplex != mdp->duplex) { new_state = 1; mdp->duplex = phydev->duplex; -#if defined(CONFIG_CPU_SUBTYPE_SH7763) - if (mdp->duplex) { /* FULL */ - ctrl_outl(ctrl_inl(ioaddr + ECMR) | ECMR_DM, - ioaddr + ECMR); - } else { /* Half */ - ctrl_outl(ctrl_inl(ioaddr + ECMR) & ~ECMR_DM, - ioaddr + ECMR); - } -#endif + if (mdp->cd->set_duplex) + mdp->cd->set_duplex(ndev); } if (phydev->speed != mdp->speed) { new_state = 1; mdp->speed = phydev->speed; -#if defined(CONFIG_CPU_SUBTYPE_SH7763) - switch (mdp->speed) { - case 10: /* 10BASE */ - ctrl_outl(GECMR_10, ioaddr + GECMR); break; - case 100:/* 100BASE */ - ctrl_outl(GECMR_100, ioaddr + GECMR); break; - case 1000: /* 1000BASE */ - ctrl_outl(GECMR_1000, ioaddr + GECMR); break; - default: - break; - } -#endif + if (mdp->cd->set_rate) + mdp->cd->set_rate(ndev); } if (mdp->link == PHY_DOWN) { ctrl_outl((ctrl_inl(ioaddr + ECMR) & ~ECMR_TXF) @@ -804,7 +964,7 @@ static void sh_eth_adjust_link(struct net_device *ndev) static int sh_eth_phy_init(struct net_device *ndev) { struct sh_eth_private *mdp = netdev_priv(ndev); - char phy_id[BUS_ID_SIZE]; + char phy_id[MII_BUS_ID_SIZE + 3]; struct phy_device *phydev = NULL; snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT, @@ -821,8 +981,9 @@ static int sh_eth_phy_init(struct net_device *ndev) dev_err(&ndev->dev, "phy_connect failed\n"); return PTR_ERR(phydev); } + dev_info(&ndev->dev, "attached phy %i to driver %s\n", - phydev->addr, phydev->drv->name); + phydev->addr, phydev->drv->name); mdp->phydev = phydev; @@ -860,7 +1021,7 @@ static int sh_eth_open(struct net_device *ndev) #endif ndev->name, ndev); if (ret) { - printk(KERN_ERR "Can not assign IRQ number to %s\n", CARDNAME); + dev_err(&ndev->dev, "Can not assign IRQ number\n"); return ret; } @@ -947,7 +1108,7 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev) if (!sh_eth_txfree(ndev)) { netif_stop_queue(ndev); spin_unlock_irqrestore(&mdp->lock, flags); - return 1; + return NETDEV_TX_BUSY; } } spin_unlock_irqrestore(&mdp->lock, flags); @@ -955,9 +1116,11 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev) entry = mdp->cur_tx % TX_RING_SIZE; mdp->tx_skbuff[entry] = skb; txdesc = &mdp->tx_ring[entry]; - txdesc->addr = (u32)(skb->data); + txdesc->addr = virt_to_phys(skb->data); /* soft swap. */ - swaps((char *)(txdesc->addr & ~0x3), skb->len + 2); + if (!mdp->cd->hw_swap) + sh_eth_soft_swap(phys_to_virt(ALIGN(txdesc->addr, 4)), + skb->len + 2); /* write back */ __flush_purge_region(skb->data, skb->len); if (skb->len < ETHERSMALL) @@ -1059,7 +1222,7 @@ static int sh_eth_do_ioctl(struct net_device *ndev, struct ifreq *rq, return phy_mii_ioctl(phydev, if_mii(rq), cmd); } - +#if defined(SH_ETH_HAS_TSU) /* Multicast reception directions set */ static void sh_eth_set_multicast_list(struct net_device *ndev) { @@ -1104,6 +1267,7 @@ static void sh_eth_tsu_init(u32 ioaddr) ctrl_outl(0, ioaddr + TSU_POST3); /* Disable CAM entry [16-23] */ ctrl_outl(0, ioaddr + TSU_POST4); /* Disable CAM entry [24-31] */ } +#endif /* SH_ETH_HAS_TSU */ /* MDIO bus release function */ static int sh_mdio_release(struct net_device *ndev) @@ -1193,7 +1357,9 @@ static const struct net_device_ops sh_eth_netdev_ops = { .ndo_stop = sh_eth_close, .ndo_start_xmit = sh_eth_start_xmit, .ndo_get_stats = sh_eth_get_stats, +#if defined(SH_ETH_HAS_TSU) .ndo_set_multicast_list = sh_eth_set_multicast_list, +#endif .ndo_tx_timeout = sh_eth_tx_timeout, .ndo_do_ioctl = sh_eth_do_ioctl, .ndo_validate_addr = eth_validate_addr, @@ -1219,7 +1385,7 @@ static int sh_eth_drv_probe(struct platform_device *pdev) ndev = alloc_etherdev(sizeof(struct sh_eth_private)); if (!ndev) { - printk(KERN_ERR "%s: could not allocate device.\n", CARDNAME); + dev_err(&pdev->dev, "Could not allocate device.\n"); ret = -ENOMEM; goto out; } @@ -1252,6 +1418,10 @@ static int sh_eth_drv_probe(struct platform_device *pdev) /* EDMAC endian */ mdp->edmac_endian = pd->edmac_endian; + /* set cpu data */ + mdp->cd = &sh_eth_my_cpu_data; + sh_eth_set_default_cpu_data(mdp->cd); + /* set function */ ndev->netdev_ops = &sh_eth_netdev_ops; ndev->watchdog_timeo = TX_TIMEOUT; @@ -1264,13 +1434,10 @@ static int sh_eth_drv_probe(struct platform_device *pdev) /* First device only init */ if (!devno) { -#if defined(ARSTR) - /* reset device */ - ctrl_outl(ARSTR_ARSTR, ARSTR); - mdelay(1); -#endif + if (mdp->cd->chip_reset) + mdp->cd->chip_reset(ndev); -#if defined(SH_TSU_ADDR) +#if defined(SH_ETH_HAS_TSU) /* TSU init (Init only)*/ sh_eth_tsu_init(SH_TSU_ADDR); #endif @@ -1287,8 +1454,8 @@ static int sh_eth_drv_probe(struct platform_device *pdev) goto out_unregister; /* pritnt device infomation */ - printk(KERN_INFO "%s: %s at 0x%x, ", - ndev->name, CARDNAME, (u32) ndev->base_addr); + pr_info("Base address at 0x%x, ", + (u32)ndev->base_addr); for (i = 0; i < 5; i++) printk("%02X:", ndev->dev_addr[i]); diff --git a/drivers/net/sh_eth.h b/drivers/net/sh_eth.h index 1537e13e623d..9afe5b4c855d 100644 --- a/drivers/net/sh_eth.h +++ b/drivers/net/sh_eth.h @@ -2,7 +2,7 @@ * SuperH Ethernet device driver * * Copyright (C) 2006-2008 Nobuhiro Iwamatsu - * Copyright (C) 2008 Renesas Solutions Corp. + * Copyright (C) 2008-2009 Renesas Solutions Corp. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -39,12 +39,12 @@ #define ETHERSMALL 60 #define PKT_BUF_SZ 1538 -#ifdef CONFIG_CPU_SUBTYPE_SH7763 +#if defined(CONFIG_CPU_SUBTYPE_SH7763) +/* This CPU register maps is very difference by other SH4 CPU */ -#define SH7763_SKB_ALIGN 32 /* Chip Base Address */ # define SH_TSU_ADDR 0xFEE01800 -# define ARSTR SH_TSU_ADDR +# define ARSTR SH_TSU_ADDR /* Chip Registers */ /* E-DMAC */ @@ -143,8 +143,60 @@ # define FWNLCR1 0xB0 # define FWALCR1 0x40 -#else /* CONFIG_CPU_SUBTYPE_SH7763 */ -# define RX_OFFSET 2 /* skb offset */ +#elif defined(CONFIG_CPU_SH4) /* #if defined(CONFIG_CPU_SUBTYPE_SH7763) */ +/* EtherC */ +#define ECMR 0x100 +#define RFLR 0x108 +#define ECSR 0x110 +#define ECSIPR 0x118 +#define PIR 0x120 +#define PSR 0x128 +#define RDMLR 0x140 +#define IPGR 0x150 +#define APR 0x154 +#define MPR 0x158 +#define TPAUSER 0x164 +#define RFCF 0x160 +#define TPAUSECR 0x168 +#define BCFRR 0x16c +#define MAHR 0x1c0 +#define MALR 0x1c8 +#define TROCR 0x1d0 +#define CDCR 0x1d4 +#define LCCR 0x1d8 +#define CNDCR 0x1dc +#define CEFCR 0x1e4 +#define FRECR 0x1e8 +#define TSFRCR 0x1ec +#define TLFRCR 0x1f0 +#define RFCR 0x1f4 +#define MAFCR 0x1f8 +#define RTRATE 0x1fc + +/* E-DMAC */ +#define EDMR 0x000 +#define EDTRR 0x008 +#define EDRRR 0x010 +#define TDLAR 0x018 +#define RDLAR 0x020 +#define EESR 0x028 +#define EESIPR 0x030 +#define TRSCER 0x038 +#define RMFCR 0x040 +#define TFTR 0x048 +#define FDR 0x050 +#define RMCR 0x058 +#define TFUCR 0x064 +#define RFOCR 0x068 +#define FCFTR 0x070 +#define RPADIR 0x078 +#define TRIMD 0x07c +#define RBWAR 0x0c8 +#define RDFAR 0x0cc +#define TBRAR 0x0d4 +#define TDFAR 0x0d8 +#else /* #elif defined(CONFIG_CPU_SH4) */ +/* This section is SH3 or SH2 */ #ifndef CONFIG_CPU_SUBTYPE_SH7619 /* Chip base address */ # define SH_TSU_ADDR 0xA7000804 @@ -243,6 +295,30 @@ #endif /* CONFIG_CPU_SUBTYPE_SH7763 */ +/* There are avoid compile error... */ +#if !defined(BCULR) +#define BCULR 0x0fc +#endif +#if !defined(TRIMD) +#define TRIMD 0x0fc +#endif +#if !defined(APR) +#define APR 0x0fc +#endif +#if !defined(MPR) +#define MPR 0x0fc +#endif +#if !defined(TPAUSER) +#define TPAUSER 0x0fc +#endif + +/* Driver's parameters */ +#if defined(CONFIG_CPU_SH4) +#define SH4_SKB_RX_ALIGN 32 +#else +#define SH2_SH3_SKB_RX_ALIGN 2 +#endif + /* * Register's bits */ @@ -261,11 +337,10 @@ enum GECMR_BIT { /* EDMR */ enum DMAC_M_BIT { + EDMR_EL = 0x40, /* Litte endian */ EDMR_DL1 = 0x20, EDMR_DL0 = 0x10, #ifdef CONFIG_CPU_SUBTYPE_SH7763 - EDMR_SRST = 0x03, - EMDR_DESC_R = 0x30, /* Descriptor reserve size */ - EDMR_EL = 0x40, /* Litte endian */ + EDMR_SRST = 0x03, #else /* CONFIG_CPU_SUBTYPE_SH7763 */ EDMR_SRST = 0x01, #endif @@ -307,47 +382,43 @@ enum PHY_STATUS_BIT { PHY_ST_LINK = 0x01, }; /* EESR */ enum EESR_BIT { -#ifndef CONFIG_CPU_SUBTYPE_SH7763 - EESR_TWB = 0x40000000, -#else - EESR_TWB = 0xC0000000, - EESR_TC1 = 0x20000000, - EESR_TUC = 0x10000000, - EESR_ROC = 0x80000000, -#endif - EESR_TABT = 0x04000000, - EESR_RABT = 0x02000000, EESR_RFRMER = 0x01000000, -#ifndef CONFIG_CPU_SUBTYPE_SH7763 - EESR_ADE = 0x00800000, -#endif - EESR_ECI = 0x00400000, - EESR_FTC = 0x00200000, EESR_TDE = 0x00100000, - EESR_TFE = 0x00080000, EESR_FRC = 0x00040000, - EESR_RDE = 0x00020000, EESR_RFE = 0x00010000, -#ifndef CONFIG_CPU_SUBTYPE_SH7763 - EESR_CND = 0x00000800, -#endif - EESR_DLC = 0x00000400, - EESR_CD = 0x00000200, EESR_RTO = 0x00000100, - EESR_RMAF = 0x00000080, EESR_CEEF = 0x00000040, - EESR_CELF = 0x00000020, EESR_RRF = 0x00000010, - EESR_RTLF = 0x00000008, EESR_RTSF = 0x00000004, - EESR_PRE = 0x00000002, EESR_CERF = 0x00000001, + EESR_TWB1 = 0x80000000, + EESR_TWB = 0x40000000, /* same as TWB0 */ + EESR_TC1 = 0x20000000, + EESR_TUC = 0x10000000, + EESR_ROC = 0x08000000, + EESR_TABT = 0x04000000, + EESR_RABT = 0x02000000, + EESR_RFRMER = 0x01000000, /* same as RFCOF */ + EESR_ADE = 0x00800000, + EESR_ECI = 0x00400000, + EESR_FTC = 0x00200000, /* same as TC or TC0 */ + EESR_TDE = 0x00100000, + EESR_TFE = 0x00080000, /* same as TFUF */ + EESR_FRC = 0x00040000, /* same as FR */ + EESR_RDE = 0x00020000, + EESR_RFE = 0x00010000, + EESR_CND = 0x00000800, + EESR_DLC = 0x00000400, + EESR_CD = 0x00000200, + EESR_RTO = 0x00000100, + EESR_RMAF = 0x00000080, + EESR_CEEF = 0x00000040, + EESR_CELF = 0x00000020, + EESR_RRF = 0x00000010, + EESR_RTLF = 0x00000008, + EESR_RTSF = 0x00000004, + EESR_PRE = 0x00000002, + EESR_CERF = 0x00000001, }; - -#ifdef CONFIG_CPU_SUBTYPE_SH7763 -# define TX_CHECK (EESR_TC1 | EESR_FTC) -# define EESR_ERR_CHECK (EESR_TWB | EESR_TABT | EESR_RABT | EESR_RDE \ - | EESR_RFRMER | EESR_TFE | EESR_TDE | EESR_ECI) -# define TX_ERROR_CEHCK (EESR_TWB | EESR_TABT | EESR_TDE | EESR_TFE) - -#else -# define TX_CHECK (EESR_FTC | EESR_CND | EESR_DLC | EESR_CD | EESR_RTO) -# define EESR_ERR_CHECK (EESR_TWB | EESR_TABT | EESR_RABT | EESR_RDE \ - | EESR_RFRMER | EESR_ADE | EESR_TFE | EESR_TDE | EESR_ECI) -# define TX_ERROR_CEHCK (EESR_TWB | EESR_TABT | EESR_ADE | EESR_TDE | EESR_TFE) -#endif +#define DEFAULT_TX_CHECK (EESR_FTC | EESR_CND | EESR_DLC | EESR_CD | \ + EESR_RTO) +#define DEFAULT_EESR_ERR_CHECK (EESR_TWB | EESR_TABT | EESR_RABT | \ + EESR_RDE | EESR_RFRMER | EESR_ADE | \ + EESR_TFE | EESR_TDE | EESR_ECI) +#define DEFAULT_TX_ERROR_CHECK (EESR_TWB | EESR_TABT | EESR_ADE | EESR_TDE | \ + EESR_TFE) /* EESIPR */ enum DMAC_IM_BIT { @@ -386,12 +457,8 @@ enum FCFTR_BIT { FCFTR_RFF0 = 0x00010000, FCFTR_RFD2 = 0x00000004, FCFTR_RFD1 = 0x00000002, FCFTR_RFD0 = 0x00000001, }; -#define FIFO_F_D_RFF (FCFTR_RFF2|FCFTR_RFF1|FCFTR_RFF0) -#ifndef CONFIG_CPU_SUBTYPE_SH7619 -#define FIFO_F_D_RFD (FCFTR_RFD2|FCFTR_RFD1|FCFTR_RFD0) -#else -#define FIFO_F_D_RFD (FCFTR_RFD0) -#endif +#define DEFAULT_FIFO_F_D_RFF (FCFTR_RFF2 | FCFTR_RFF1 | FCFTR_RFF0) +#define DEFAULT_FIFO_F_D_RFD (FCFTR_RFD2 | FCFTR_RFD1 | FCFTR_RFD0) /* Transfer descriptor bit */ enum TD_STS_BIT { @@ -404,60 +471,38 @@ enum TD_STS_BIT { #define TD_TFP (TD_TFP1|TD_TFP0) /* RMCR */ -enum RECV_RST_BIT { RMCR_RST = 0x01, }; +#define DEFAULT_RMCR_VALUE 0x00000000 + /* ECMR */ enum FELIC_MODE_BIT { -#ifdef CONFIG_CPU_SUBTYPE_SH7763 ECMR_TRCCM = 0x04000000, ECMR_RCSC = 0x00800000, ECMR_DPAD = 0x00200000, ECMR_RZPF = 0x00100000, -#endif ECMR_ZPF = 0x00080000, ECMR_PFR = 0x00040000, ECMR_RXF = 0x00020000, ECMR_TXF = 0x00010000, ECMR_MCT = 0x00002000, ECMR_PRCEF = 0x00001000, ECMR_PMDE = 0x00000200, ECMR_RE = 0x00000040, ECMR_TE = 0x00000020, - ECMR_ILB = 0x00000008, ECMR_ELB = 0x00000004, ECMR_DM = 0x00000002, - ECMR_PRM = 0x00000001, + ECMR_RTM = 0x00000010, ECMR_ILB = 0x00000008, ECMR_ELB = 0x00000004, + ECMR_DM = 0x00000002, ECMR_PRM = 0x00000001, }; -#ifdef CONFIG_CPU_SUBTYPE_SH7763 -#define ECMR_CHG_DM (ECMR_TRCCM | ECMR_RZPF | ECMR_ZPF |\ - ECMR_PFR | ECMR_RXF | ECMR_TXF | ECMR_MCT) -#elif CONFIG_CPU_SUBTYPE_SH7619 -#define ECMR_CHG_DM (ECMR_ZPF | ECMR_PFR | ECMR_RXF | ECMR_TXF) -#else -#define ECMR_CHG_DM (ECMR_ZPF | ECMR_PFR | ECMR_RXF | ECMR_TXF | ECMR_MCT) -#endif - /* ECSR */ enum ECSR_STATUS_BIT { -#ifndef CONFIG_CPU_SUBTYPE_SH7763 ECSR_BRCRX = 0x20, ECSR_PSRTO = 0x10, -#endif ECSR_LCHNG = 0x04, ECSR_MPD = 0x02, ECSR_ICD = 0x01, }; -#ifdef CONFIG_CPU_SUBTYPE_SH7763 -# define ECSR_INIT (ECSR_ICD | ECSIPR_MPDIP) -#else -# define ECSR_INIT (ECSR_BRCRX | ECSR_PSRTO | \ - ECSR_LCHNG | ECSR_ICD | ECSIPR_MPDIP) -#endif +#define DEFAULT_ECSR_INIT (ECSR_BRCRX | ECSR_PSRTO | ECSR_LCHNG | \ + ECSR_ICD | ECSIPR_MPDIP) /* ECSIPR */ enum ECSIPR_STATUS_MASK_BIT { -#ifndef CONFIG_CPU_SUBTYPE_SH7763 ECSIPR_BRCRXIP = 0x20, ECSIPR_PSRTOIP = 0x10, -#endif ECSIPR_LCHNGIP = 0x04, ECSIPR_MPDIP = 0x02, ECSIPR_ICDIP = 0x01, }; -#ifdef CONFIG_CPU_SUBTYPE_SH7763 -# define ECSIPR_INIT (ECSIPR_LCHNGIP | ECSIPR_ICDIP | ECSIPR_MPDIP) -#else -# define ECSIPR_INIT (ECSIPR_BRCRXIP | ECSIPR_PSRTOIP | ECSIPR_LCHNGIP | \ - ECSIPR_ICDIP | ECSIPR_MPDIP) -#endif +#define DEFAULT_ECSIPR_INIT (ECSIPR_BRCRXIP | ECSIPR_PSRTOIP | \ + ECSIPR_LCHNGIP | ECSIPR_ICDIP | ECSIPR_MPDIP) /* APR */ enum APR_BIT { @@ -483,23 +528,12 @@ enum RPADIR_BIT { RPADIR_PADR = 0x0003f, }; -#if defined(CONFIG_CPU_SUBTYPE_SH7763) -# define RPADIR_INIT (0x00) -#else -# define RPADIR_INIT (RPADIR_PADS1) -#endif - /* RFLR */ #define RFLR_VALUE 0x1000 /* FDR */ -enum FIFO_SIZE_BIT { -#ifndef CONFIG_CPU_SUBTYPE_SH7619 - FIFO_SIZE_T = 0x00000700, FIFO_SIZE_R = 0x00000007, -#else - FIFO_SIZE_T = 0x00000100, FIFO_SIZE_R = 0x00000001, -#endif -}; +#define DEFAULT_FDR_INIT 0x00000707 + enum phy_offsets { PHY_CTRL = 0, PHY_STAT = 1, PHY_IDT1 = 2, PHY_IDT2 = 3, PHY_ANA = 4, PHY_ANL = 5, PHY_ANE = 6, @@ -633,7 +667,43 @@ struct sh_eth_rxdesc { u32 pad0; /* padding data */ } __attribute__((aligned(2), packed)); +/* This structure is used by each CPU dependency handling. */ +struct sh_eth_cpu_data { + /* optional functions */ + void (*chip_reset)(struct net_device *ndev); + void (*set_duplex)(struct net_device *ndev); + void (*set_rate)(struct net_device *ndev); + + /* mandatory initialize value */ + unsigned long eesipr_value; + + /* optional initialize value */ + unsigned long ecsr_value; + unsigned long ecsipr_value; + unsigned long fdr_value; + unsigned long fcftr_value; + unsigned long rpadir_value; + unsigned long rmcr_value; + + /* interrupt checking mask */ + unsigned long tx_check; + unsigned long eesr_err_check; + unsigned long tx_error_check; + + /* hardware features */ + unsigned no_psr:1; /* EtherC DO NOT have PSR */ + unsigned apr:1; /* EtherC have APR */ + unsigned mpr:1; /* EtherC have MPR */ + unsigned tpauser:1; /* EtherC have TPAUSER */ + unsigned bculr:1; /* EtherC have BCULR */ + unsigned hw_swap:1; /* E-DMAC have DE bit in EDMR */ + unsigned rpadir:1; /* E-DMAC have RPADIR */ + unsigned no_trimd:1; /* E-DMAC DO NOT have TRIMD */ + unsigned no_ade:1; /* E-DMAC DO NOT have ADE bit in EESR */ +}; + struct sh_eth_private { + struct sh_eth_cpu_data *cd; dma_addr_t rx_desc_dma; dma_addr_t tx_desc_dma; struct sh_eth_rxdesc *rx_ring; @@ -661,11 +731,7 @@ struct sh_eth_private { struct net_device_stats tsu_stats; /* TSU forward status */ }; -#ifdef CONFIG_CPU_SUBTYPE_SH7763 -/* SH7763 has endian control register */ -#define swaps(x, y) -#else -static void swaps(char *src, int len) +static inline void sh_eth_soft_swap(char *src, int len) { #ifdef __LITTLE_ENDIAN__ u32 *p = (u32 *)src; @@ -676,5 +742,5 @@ static void swaps(char *src, int len) *p = swab32(*p); #endif } -#endif /* CONFIG_CPU_SUBTYPE_SH7763 */ -#endif + +#endif /* #ifndef __SH_ETH_H__ */ diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c index 55ccd51d247e..1f040e8a000b 100644 --- a/drivers/net/sis190.c +++ b/drivers/net/sis190.c @@ -47,7 +47,7 @@ #define PHY_ID_ANY 0x1f #define MII_REG_ANY 0x1f -#define DRV_VERSION "1.2" +#define DRV_VERSION "1.3" #define DRV_NAME "sis190" #define SIS190_DRIVER_NAME DRV_NAME " Gigabit Ethernet driver " DRV_VERSION #define PFX DRV_NAME ": " @@ -317,6 +317,7 @@ static struct mii_chip_info { unsigned int type; u32 feature; } mii_chip_table[] = { + { "Atheros PHY", { 0x004d, 0xd010 }, LAN, 0 }, { "Atheros PHY AR8012", { 0x004d, 0xd020 }, LAN, 0 }, { "Broadcom PHY BCM5461", { 0x0020, 0x60c0 }, LAN, F_PHY_BCM5461 }, { "Broadcom PHY AC131", { 0x0143, 0xbc70 }, LAN, 0 }, @@ -347,7 +348,7 @@ static struct { u32 msg_enable; } debug = { -1 }; -MODULE_DESCRIPTION("SiS sis190 Gigabit Ethernet driver"); +MODULE_DESCRIPTION("SiS sis190/191 Gigabit Ethernet driver"); module_param(rx_copybreak, int, 0); MODULE_PARM_DESC(rx_copybreak, "Copy breakpoint for copy-only-tiny-frames"); module_param_named(debug, debug.msg_enable, int, 0); @@ -539,8 +540,8 @@ static bool sis190_try_rx_copy(struct sis190_private *tp, if (!skb) goto out; - pci_dma_sync_single_for_device(tp->pci_dev, addr, pkt_size, - PCI_DMA_FROMDEVICE); + pci_dma_sync_single_for_cpu(tp->pci_dev, addr, tp->rx_buf_sz, + PCI_DMA_FROMDEVICE); skb_reserve(skb, 2); skb_copy_to_linear_data(skb, sk_buff[0]->data, pkt_size); *sk_buff = skb; @@ -942,9 +943,9 @@ static void sis190_phy_task(struct work_struct *work) u32 ctl; const char *msg; } reg31[] = { - { LPA_1000XFULL | LPA_SLCT, 0x07000c00 | 0x00001000, + { LPA_1000FULL, 0x07000c00 | 0x00001000, "1000 Mbps Full Duplex" }, - { LPA_1000XHALF | LPA_SLCT, 0x07000c00, + { LPA_1000HALF, 0x07000c00, "1000 Mbps Half Duplex" }, { LPA_100FULL, 0x04000800 | 0x00001000, "100 Mbps Full Duplex" }, @@ -955,22 +956,35 @@ static void sis190_phy_task(struct work_struct *work) { LPA_10HALF, 0x04000400, "10 Mbps Half Duplex" }, { 0, 0x04000400, "unknown" } - }, *p; - u16 adv; + }, *p = NULL; + u16 adv, autoexp, gigadv, gigrec; val = mdio_read(ioaddr, phy_id, 0x1f); net_link(tp, KERN_INFO "%s: mii ext = %04x.\n", dev->name, val); val = mdio_read(ioaddr, phy_id, MII_LPA); adv = mdio_read(ioaddr, phy_id, MII_ADVERTISE); - net_link(tp, KERN_INFO "%s: mii lpa = %04x adv = %04x.\n", - dev->name, val, adv); + autoexp = mdio_read(ioaddr, phy_id, MII_EXPANSION); + net_link(tp, KERN_INFO "%s: mii lpa=%04x adv=%04x exp=%04x.\n", + dev->name, val, adv, autoexp); - val &= adv; + if (val & LPA_NPAGE && autoexp & EXPANSION_NWAY) { + /* check for gigabit speed */ + gigadv = mdio_read(ioaddr, phy_id, MII_CTRL1000); + gigrec = mdio_read(ioaddr, phy_id, MII_STAT1000); + val = (gigadv & (gigrec >> 2)); + if (val & ADVERTISE_1000FULL) + p = reg31; + else if (val & ADVERTISE_1000HALF) + p = reg31 + 1; + } + if (!p) { + val &= adv; - for (p = reg31; p->val; p++) { - if ((val & p->val) == p->val) - break; + for (p = reg31; p->val; p++) { + if ((val & p->val) == p->val) + break; + } } p->ctl |= SIS_R32(StationControl) & ~0x0f001c00; @@ -1204,8 +1218,6 @@ static int sis190_start_xmit(struct sk_buff *skb, struct net_device *dev) SIS_W32(TxControl, 0x1a00 | CmdReset | CmdTxEnb); - dev->trans_start = jiffies; - dirty_tx = tp->dirty_tx; if ((tp->cur_tx - NUM_TX_DESC) == dirty_tx) { netif_stop_queue(dev); @@ -1269,7 +1281,7 @@ static u16 sis190_default_phy(struct net_device *dev) else if (phy_lan) phy_default = phy_lan; else - phy_default = list_entry(&tp->first_phy, + phy_default = list_first_entry(&tp->first_phy, struct sis190_phy, list); } @@ -1315,12 +1327,15 @@ static void sis190_init_phy(struct net_device *dev, struct sis190_private *tp, ((mii_status & (BMSR_100FULL | BMSR_100HALF)) ? LAN : HOME) : p->type; tp->features |= p->feature; - } else + net_probe(tp, KERN_INFO "%s: %s transceiver at address %d.\n", + pci_name(tp->pci_dev), p->name, phy_id); + } else { phy->type = UNKNOWN; - - net_probe(tp, KERN_INFO "%s: %s transceiver at address %d.\n", - pci_name(tp->pci_dev), - (phy->type == UNKNOWN) ? "Unknown PHY" : p->name, phy_id); + net_probe(tp, KERN_INFO + "%s: unknown PHY 0x%x:0x%x transceiver at address %d\n", + pci_name(tp->pci_dev), + phy->id[0], (phy->id[1] & 0xfff0), phy_id); + } } static void sis190_mii_probe_88e1111_fixup(struct sis190_private *tp) diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index 2d4617b3e208..a9a897bb42d5 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -1584,7 +1584,7 @@ sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev) /* Don't transmit data before the complete of auto-negotiation */ if(!sis_priv->autong_complete){ netif_stop_queue(net_dev); - return 1; + return NETDEV_TX_BUSY; } spin_lock_irqsave(&sis_priv->lock, flags); diff --git a/drivers/net/skfp/h/smt.h b/drivers/net/skfp/h/smt.h index 1ff589988d10..2976757a36fb 100644 --- a/drivers/net/skfp/h/smt.h +++ b/drivers/net/skfp/h/smt.h @@ -413,7 +413,7 @@ struct smt_p_reason { #define SMT_RDF_SUCCESS 0x00000003 /* success (PMF) */ #define SMT_RDF_BADSET 0x00000004 /* bad set count (PMF) */ #define SMT_RDF_ILLEGAL 0x00000005 /* read only (PMF) */ -#define SMT_RDF_NOPARAM 0x6 /* paramter not supported (PMF) */ +#define SMT_RDF_NOPARAM 0x6 /* parameter not supported (PMF) */ #define SMT_RDF_RANGE 0x8 /* out of range */ #define SMT_RDF_AUTHOR 0x9 /* not autohorized */ #define SMT_RDF_LENGTH 0x0a /* length error */ diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c index e14aec0a7333..088fe26484e7 100644 --- a/drivers/net/skfp/skfddi.c +++ b/drivers/net/skfp/skfddi.c @@ -159,12 +159,6 @@ MODULE_AUTHOR("Mirko Lindner "); static int num_boards; /* total number of adapters configured */ -#ifdef DRIVERDEBUG -#define PRINTK(s, args...) printk(s, ## args) -#else -#define PRINTK(s, args...) -#endif // DRIVERDEBUG - static const struct net_device_ops skfp_netdev_ops = { .ndo_open = skfp_open, .ndo_stop = skfp_close, @@ -213,7 +207,7 @@ static int skfp_init_one(struct pci_dev *pdev, void __iomem *mem; int err; - PRINTK(KERN_INFO "entering skfp_init_one\n"); + pr_debug(KERN_INFO "entering skfp_init_one\n"); if (num_boards == 0) printk("%s\n", boot_msg); @@ -389,7 +383,7 @@ static int skfp_driver_init(struct net_device *dev) skfddi_priv *bp = &smc->os; int err = -EIO; - PRINTK(KERN_INFO "entering skfp_driver_init\n"); + pr_debug(KERN_INFO "entering skfp_driver_init\n"); // set the io address in private structures bp->base_addr = dev->base_addr; @@ -409,7 +403,7 @@ static int skfp_driver_init(struct net_device *dev) // Determine the required size of the 'shared' memory area. bp->SharedMemSize = mac_drv_check_space(); - PRINTK(KERN_INFO "Memory for HWM: %ld\n", bp->SharedMemSize); + pr_debug(KERN_INFO "Memory for HWM: %ld\n", bp->SharedMemSize); if (bp->SharedMemSize > 0) { bp->SharedMemSize += 16; // for descriptor alignment @@ -433,13 +427,13 @@ static int skfp_driver_init(struct net_device *dev) card_stop(smc); // Reset adapter. - PRINTK(KERN_INFO "mac_drv_init()..\n"); + pr_debug(KERN_INFO "mac_drv_init()..\n"); if (mac_drv_init(smc) != 0) { - PRINTK(KERN_INFO "mac_drv_init() failed.\n"); + pr_debug(KERN_INFO "mac_drv_init() failed.\n"); goto fail; } read_address(smc, NULL); - PRINTK(KERN_INFO "HW-Addr: %02x %02x %02x %02x %02x %02x\n", + pr_debug(KERN_INFO "HW-Addr: %02x %02x %02x %02x %02x %02x\n", smc->hw.fddi_canon_addr.a[0], smc->hw.fddi_canon_addr.a[1], smc->hw.fddi_canon_addr.a[2], @@ -495,7 +489,7 @@ static int skfp_open(struct net_device *dev) struct s_smc *smc = netdev_priv(dev); int err; - PRINTK(KERN_INFO "entering skfp_open\n"); + pr_debug(KERN_INFO "entering skfp_open\n"); /* Register IRQ - support shared interrupts by passing device ptr */ err = request_irq(dev->irq, skfp_interrupt, IRQF_SHARED, dev->name, dev); @@ -868,12 +862,12 @@ static void skfp_ctl_set_multicast_list_wo_lock(struct net_device *dev) /* Enable promiscuous mode, if necessary */ if (dev->flags & IFF_PROMISC) { mac_drv_rx_mode(smc, RX_ENABLE_PROMISC); - PRINTK(KERN_INFO "PROMISCUOUS MODE ENABLED\n"); + pr_debug(KERN_INFO "PROMISCUOUS MODE ENABLED\n"); } /* Else, update multicast address table */ else { mac_drv_rx_mode(smc, RX_DISABLE_PROMISC); - PRINTK(KERN_INFO "PROMISCUOUS MODE DISABLED\n"); + pr_debug(KERN_INFO "PROMISCUOUS MODE DISABLED\n"); // Reset all MC addresses mac_clear_multicast(smc); @@ -881,7 +875,7 @@ static void skfp_ctl_set_multicast_list_wo_lock(struct net_device *dev) if (dev->flags & IFF_ALLMULTI) { mac_drv_rx_mode(smc, RX_ENABLE_ALLMULTI); - PRINTK(KERN_INFO "ENABLE ALL MC ADDRESSES\n"); + pr_debug(KERN_INFO "ENABLE ALL MC ADDRESSES\n"); } else if (dev->mc_count > 0) { if (dev->mc_count <= FPMAX_MULTICAST) { /* use exact filtering */ @@ -894,12 +888,12 @@ static void skfp_ctl_set_multicast_list_wo_lock(struct net_device *dev) (struct fddi_addr *)dmi->dmi_addr, 1); - PRINTK(KERN_INFO "ENABLE MC ADDRESS:"); - PRINTK(" %02x %02x %02x ", + pr_debug(KERN_INFO "ENABLE MC ADDRESS:"); + pr_debug(" %02x %02x %02x ", dmi->dmi_addr[0], dmi->dmi_addr[1], dmi->dmi_addr[2]); - PRINTK("%02x %02x %02x\n", + pr_debug("%02x %02x %02x\n", dmi->dmi_addr[3], dmi->dmi_addr[4], dmi->dmi_addr[5]); @@ -909,11 +903,11 @@ static void skfp_ctl_set_multicast_list_wo_lock(struct net_device *dev) } else { // more MC addresses than HW supports mac_drv_rx_mode(smc, RX_ENABLE_ALLMULTI); - PRINTK(KERN_INFO "ENABLE ALL MC ADDRESSES\n"); + pr_debug(KERN_INFO "ENABLE ALL MC ADDRESSES\n"); } } else { // no MC addresses - PRINTK(KERN_INFO "DISABLE ALL MC ADDRESSES\n"); + pr_debug(KERN_INFO "DISABLE ALL MC ADDRESSES\n"); } /* Update adapter filters */ @@ -1067,7 +1061,7 @@ static int skfp_send_pkt(struct sk_buff *skb, struct net_device *dev) struct s_smc *smc = netdev_priv(dev); skfddi_priv *bp = &smc->os; - PRINTK(KERN_INFO "skfp_send_pkt\n"); + pr_debug(KERN_INFO "skfp_send_pkt\n"); /* * Verify that incoming transmit request is OK @@ -1088,7 +1082,7 @@ static int skfp_send_pkt(struct sk_buff *skb, struct net_device *dev) if (bp->QueueSkb == 0) { // return with tbusy set: queue full netif_stop_queue(dev); - return 1; + return NETDEV_TX_BUSY; } bp->QueueSkb--; skb_queue_tail(&bp->SendSkbQueue, skb); @@ -1137,13 +1131,13 @@ static void send_queued_packets(struct s_smc *smc) int frame_status; // HWM tx frame status. - PRINTK(KERN_INFO "send queued packets\n"); + pr_debug(KERN_INFO "send queued packets\n"); for (;;) { // send first buffer from queue skb = skb_dequeue(&bp->SendSkbQueue); if (!skb) { - PRINTK(KERN_INFO "queue empty\n"); + pr_debug(KERN_INFO "queue empty\n"); return; } // queue empty ! @@ -1174,11 +1168,11 @@ static void send_queued_packets(struct s_smc *smc) if ((frame_status & RING_DOWN) != 0) { // Ring is down. - PRINTK("Tx attempt while ring down.\n"); + pr_debug("Tx attempt while ring down.\n"); } else if ((frame_status & OUT_OF_TXD) != 0) { - PRINTK("%s: out of TXDs.\n", bp->dev->name); + pr_debug("%s: out of TXDs.\n", bp->dev->name); } else { - PRINTK("%s: out of transmit resources", + pr_debug("%s: out of transmit resources", bp->dev->name); } @@ -1255,7 +1249,7 @@ static void CheckSourceAddress(unsigned char *frame, unsigned char *hw_addr) static void ResetAdapter(struct s_smc *smc) { - PRINTK(KERN_INFO "[fddi: ResetAdapter]\n"); + pr_debug(KERN_INFO "[fddi: ResetAdapter]\n"); // Stop the adapter. @@ -1301,7 +1295,7 @@ void llc_restart_tx(struct s_smc *smc) { skfddi_priv *bp = &smc->os; - PRINTK(KERN_INFO "[llc_restart_tx]\n"); + pr_debug(KERN_INFO "[llc_restart_tx]\n"); // Try to send queued packets spin_unlock(&bp->DriverLock); @@ -1331,7 +1325,7 @@ void *mac_drv_get_space(struct s_smc *smc, unsigned int size) { void *virt; - PRINTK(KERN_INFO "mac_drv_get_space (%d bytes), ", size); + pr_debug(KERN_INFO "mac_drv_get_space (%d bytes), ", size); virt = (void *) (smc->os.SharedMemAddr + smc->os.SharedMemHeap); if ((smc->os.SharedMemHeap + size) > smc->os.SharedMemSize) { @@ -1340,9 +1334,9 @@ void *mac_drv_get_space(struct s_smc *smc, unsigned int size) } smc->os.SharedMemHeap += size; // Move heap pointer. - PRINTK(KERN_INFO "mac_drv_get_space end\n"); - PRINTK(KERN_INFO "virt addr: %lx\n", (ulong) virt); - PRINTK(KERN_INFO "bus addr: %lx\n", (ulong) + pr_debug(KERN_INFO "mac_drv_get_space end\n"); + pr_debug(KERN_INFO "virt addr: %lx\n", (ulong) virt); + pr_debug(KERN_INFO "bus addr: %lx\n", (ulong) (smc->os.SharedMemDMA + ((char *) virt - (char *)smc->os.SharedMemAddr))); return (virt); @@ -1372,7 +1366,7 @@ void *mac_drv_get_desc_mem(struct s_smc *smc, unsigned int size) char *virt; - PRINTK(KERN_INFO "mac_drv_get_desc_mem\n"); + pr_debug(KERN_INFO "mac_drv_get_desc_mem\n"); // Descriptor memory must be aligned on 16-byte boundary. @@ -1381,8 +1375,8 @@ void *mac_drv_get_desc_mem(struct s_smc *smc, unsigned int size) size = (u_int) (16 - (((unsigned long) virt) & 15UL)); size = size % 16; - PRINTK("Allocate %u bytes alignment gap ", size); - PRINTK("for descriptor memory.\n"); + pr_debug("Allocate %u bytes alignment gap ", size); + pr_debug("for descriptor memory.\n"); if (!mac_drv_get_space(smc, size)) { printk("fddi: Unable to align descriptor memory.\n"); @@ -1516,11 +1510,11 @@ void mac_drv_tx_complete(struct s_smc *smc, volatile struct s_smt_fp_txd *txd) { struct sk_buff *skb; - PRINTK(KERN_INFO "entering mac_drv_tx_complete\n"); + pr_debug(KERN_INFO "entering mac_drv_tx_complete\n"); // Check if this TxD points to a skb if (!(skb = txd->txd_os.skb)) { - PRINTK("TXD with no skb assigned.\n"); + pr_debug("TXD with no skb assigned.\n"); return; } txd->txd_os.skb = NULL; @@ -1536,7 +1530,7 @@ void mac_drv_tx_complete(struct s_smc *smc, volatile struct s_smt_fp_txd *txd) // free the skb dev_kfree_skb_irq(skb); - PRINTK(KERN_INFO "leaving mac_drv_tx_complete\n"); + pr_debug(KERN_INFO "leaving mac_drv_tx_complete\n"); } // mac_drv_tx_complete @@ -1603,7 +1597,7 @@ void mac_drv_rx_complete(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd, unsigned short ri; u_int RifLength; - PRINTK(KERN_INFO "entering mac_drv_rx_complete (len=%d)\n", len); + pr_debug(KERN_INFO "entering mac_drv_rx_complete (len=%d)\n", len); if (frag_count != 1) { // This is not allowed to happen. printk("fddi: Multi-fragment receive!\n"); @@ -1612,7 +1606,7 @@ void mac_drv_rx_complete(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd, } skb = rxd->rxd_os.skb; if (!skb) { - PRINTK(KERN_INFO "No skb in rxd\n"); + pr_debug(KERN_INFO "No skb in rxd\n"); smc->os.MacStat.gen.rx_errors++; goto RequeueRxd; } @@ -1642,7 +1636,7 @@ void mac_drv_rx_complete(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd, else { int n; // goos: RIF removal has still to be tested - PRINTK(KERN_INFO "RIF found\n"); + pr_debug(KERN_INFO "RIF found\n"); // Get RIF length from Routing Control (RC) field. cp = virt + FDDI_MAC_HDR_LEN; // Point behind MAC header. @@ -1687,7 +1681,7 @@ void mac_drv_rx_complete(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd, return; RequeueRxd: - PRINTK(KERN_INFO "Rx: re-queue RXD.\n"); + pr_debug(KERN_INFO "Rx: re-queue RXD.\n"); mac_drv_requeue_rxd(smc, rxd, frag_count); smc->os.MacStat.gen.rx_errors++; // Count receive packets // not indicated. @@ -1736,7 +1730,7 @@ void mac_drv_requeue_rxd(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd, skb = src_rxd->rxd_os.skb; if (skb == NULL) { // this should not happen - PRINTK("Requeue with no skb in rxd!\n"); + pr_debug("Requeue with no skb in rxd!\n"); skb = alloc_skb(MaxFrameSize + 3, GFP_ATOMIC); if (skb) { // we got a skb @@ -1751,7 +1745,7 @@ void mac_drv_requeue_rxd(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd, rxd->rxd_os.dma_addr = b_addr; } else { // no skb available, use local buffer - PRINTK("Queueing invalid buffer!\n"); + pr_debug("Queueing invalid buffer!\n"); rxd->rxd_os.skb = NULL; v_addr = smc->os.LocalRxBuffer; b_addr = smc->os.LocalRxBufferDMA; @@ -1798,7 +1792,7 @@ void mac_drv_fill_rxd(struct s_smc *smc) struct sk_buff *skb; volatile struct s_smt_fp_rxd *rxd; - PRINTK(KERN_INFO "entering mac_drv_fill_rxd\n"); + pr_debug(KERN_INFO "entering mac_drv_fill_rxd\n"); // Walk through the list of free receive buffers, passing receive // buffers to the HWM as long as RXDs are available. @@ -1806,7 +1800,7 @@ void mac_drv_fill_rxd(struct s_smc *smc) MaxFrameSize = smc->os.MaxFrameSize; // Check if there is any RXD left. while (HWM_GET_RX_FREE(smc) > 0) { - PRINTK(KERN_INFO ".\n"); + pr_debug(KERN_INFO ".\n"); rxd = HWM_GET_CURR_RXD(smc); skb = alloc_skb(MaxFrameSize + 3, GFP_ATOMIC); @@ -1826,7 +1820,7 @@ void mac_drv_fill_rxd(struct s_smc *smc) // keep the receiver running in hope of better times. // Multiple descriptors may point to this local buffer, // so data in it must be considered invalid. - PRINTK("Queueing invalid buffer!\n"); + pr_debug("Queueing invalid buffer!\n"); v_addr = smc->os.LocalRxBuffer; b_addr = smc->os.LocalRxBufferDMA; } @@ -1837,7 +1831,7 @@ void mac_drv_fill_rxd(struct s_smc *smc) hwm_rx_frag(smc, v_addr, b_addr, MaxFrameSize, FIRST_FRAG | LAST_FRAG); } - PRINTK(KERN_INFO "leaving mac_drv_fill_rxd\n"); + pr_debug(KERN_INFO "leaving mac_drv_fill_rxd\n"); } // mac_drv_fill_rxd @@ -1863,7 +1857,7 @@ void mac_drv_clear_rxd(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd, struct sk_buff *skb; - PRINTK("entering mac_drv_clear_rxd\n"); + pr_debug("entering mac_drv_clear_rxd\n"); if (frag_count != 1) // This is not allowed to happen. @@ -1919,19 +1913,19 @@ int mac_drv_rx_init(struct s_smc *smc, int len, int fc, { struct sk_buff *skb; - PRINTK("entering mac_drv_rx_init(len=%d)\n", len); + pr_debug("entering mac_drv_rx_init(len=%d)\n", len); // "Received" a SMT or NSA frame of the local SMT. if (len != la_len || len < FDDI_MAC_HDR_LEN || !look_ahead) { - PRINTK("fddi: Discard invalid local SMT frame\n"); - PRINTK(" len=%d, la_len=%d, (ULONG) look_ahead=%08lXh.\n", + pr_debug("fddi: Discard invalid local SMT frame\n"); + pr_debug(" len=%d, la_len=%d, (ULONG) look_ahead=%08lXh.\n", len, la_len, (unsigned long) look_ahead); return (0); } skb = alloc_skb(len + 3, GFP_ATOMIC); if (!skb) { - PRINTK("fddi: Local SMT: skb memory exhausted.\n"); + pr_debug("fddi: Local SMT: skb memory exhausted.\n"); return (0); } skb_reserve(skb, 3); @@ -1981,40 +1975,40 @@ void smt_timer_poll(struct s_smc *smc) ************************/ void ring_status_indication(struct s_smc *smc, u_long status) { - PRINTK("ring_status_indication( "); + pr_debug("ring_status_indication( "); if (status & RS_RES15) - PRINTK("RS_RES15 "); + pr_debug("RS_RES15 "); if (status & RS_HARDERROR) - PRINTK("RS_HARDERROR "); + pr_debug("RS_HARDERROR "); if (status & RS_SOFTERROR) - PRINTK("RS_SOFTERROR "); + pr_debug("RS_SOFTERROR "); if (status & RS_BEACON) - PRINTK("RS_BEACON "); + pr_debug("RS_BEACON "); if (status & RS_PATHTEST) - PRINTK("RS_PATHTEST "); + pr_debug("RS_PATHTEST "); if (status & RS_SELFTEST) - PRINTK("RS_SELFTEST "); + pr_debug("RS_SELFTEST "); if (status & RS_RES9) - PRINTK("RS_RES9 "); + pr_debug("RS_RES9 "); if (status & RS_DISCONNECT) - PRINTK("RS_DISCONNECT "); + pr_debug("RS_DISCONNECT "); if (status & RS_RES7) - PRINTK("RS_RES7 "); + pr_debug("RS_RES7 "); if (status & RS_DUPADDR) - PRINTK("RS_DUPADDR "); + pr_debug("RS_DUPADDR "); if (status & RS_NORINGOP) - PRINTK("RS_NORINGOP "); + pr_debug("RS_NORINGOP "); if (status & RS_VERSION) - PRINTK("RS_VERSION "); + pr_debug("RS_VERSION "); if (status & RS_STUCKBYPASSS) - PRINTK("RS_STUCKBYPASSS "); + pr_debug("RS_STUCKBYPASSS "); if (status & RS_EVENT) - PRINTK("RS_EVENT "); + pr_debug("RS_EVENT "); if (status & RS_RINGOPCHANGE) - PRINTK("RS_RINGOPCHANGE "); + pr_debug("RS_RINGOPCHANGE "); if (status & RS_RES0) - PRINTK("RS_RES0 "); - PRINTK("]\n"); + pr_debug("RS_RES0 "); + pr_debug("]\n"); } // ring_status_indication @@ -2057,17 +2051,17 @@ void smt_stat_counter(struct s_smc *smc, int stat) { // BOOLEAN RingIsUp ; - PRINTK(KERN_INFO "smt_stat_counter\n"); + pr_debug(KERN_INFO "smt_stat_counter\n"); switch (stat) { case 0: - PRINTK(KERN_INFO "Ring operational change.\n"); + pr_debug(KERN_INFO "Ring operational change.\n"); break; case 1: - PRINTK(KERN_INFO "Receive fifo overflow.\n"); + pr_debug(KERN_INFO "Receive fifo overflow.\n"); smc->os.MacStat.gen.rx_errors++; break; default: - PRINTK(KERN_INFO "Unknown status (%d).\n", stat); + pr_debug(KERN_INFO "Unknown status (%d).\n", stat); break; } } // smt_stat_counter @@ -2123,10 +2117,10 @@ void cfm_state_change(struct s_smc *smc, int c_state) s = "SC11_C_WRAP_S"; break; default: - PRINTK(KERN_INFO "cfm_state_change: unknown %d\n", c_state); + pr_debug(KERN_INFO "cfm_state_change: unknown %d\n", c_state); return; } - PRINTK(KERN_INFO "cfm_state_change: %s\n", s); + pr_debug(KERN_INFO "cfm_state_change: %s\n", s); #endif // DRIVERDEBUG } // cfm_state_change @@ -2181,7 +2175,7 @@ void ecm_state_change(struct s_smc *smc, int e_state) s = "unknown"; break; } - PRINTK(KERN_INFO "ecm_state_change: %s\n", s); + pr_debug(KERN_INFO "ecm_state_change: %s\n", s); #endif //DRIVERDEBUG } // ecm_state_change @@ -2236,7 +2230,7 @@ void rmt_state_change(struct s_smc *smc, int r_state) s = "unknown"; break; } - PRINTK(KERN_INFO "[rmt_state_change: %s]\n", s); + pr_debug(KERN_INFO "[rmt_state_change: %s]\n", s); #endif // DRIVERDEBUG } // rmt_state_change @@ -2256,7 +2250,7 @@ void rmt_state_change(struct s_smc *smc, int r_state) ************************/ void drv_reset_indication(struct s_smc *smc) { - PRINTK(KERN_INFO "entering drv_reset_indication\n"); + pr_debug(KERN_INFO "entering drv_reset_indication\n"); smc->os.ResetRequested = TRUE; // Set flag. diff --git a/drivers/net/skge.c b/drivers/net/skge.c index c11cdd08ec57..60d502eef4fc 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -2837,8 +2837,6 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); } - dev->trans_start = jiffies; - return NETDEV_TX_OK; } diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index a2ff9cb1e7ac..7681d28c53d7 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -50,7 +50,7 @@ #include "sky2.h" #define DRV_NAME "sky2" -#define DRV_VERSION "1.22" +#define DRV_VERSION "1.23" #define PFX DRV_NAME " " /* @@ -65,9 +65,9 @@ #define RX_DEF_PENDING RX_MAX_PENDING #define TX_RING_SIZE 512 -#define TX_DEF_PENDING (TX_RING_SIZE - 1) -#define TX_MIN_PENDING 64 +#define TX_DEF_PENDING 128 #define MAX_SKB_TX_LE (4 + (sizeof(dma_addr_t)/sizeof(u32))*MAX_SKB_FRAGS) +#define TX_MIN_PENDING (MAX_SKB_TX_LE+1) #define STATUS_RING_SIZE 2048 /* 2 ports * (TX + 2*RX) */ #define STATUS_LE_BYTES (STATUS_RING_SIZE*sizeof(struct sky2_status_le)) @@ -1151,7 +1151,14 @@ stopped: /* reset the Rx prefetch unit */ sky2_write32(hw, Y2_QADDR(rxq, PREF_UNIT_CTRL), PREF_UNIT_RST_SET); - mmiowb(); + + /* Reset the RAM Buffer receive queue */ + sky2_write8(hw, RB_ADDR(rxq, RB_CTRL), RB_RST_SET); + + /* Reset Rx MAC FIFO */ + sky2_write8(hw, SK_REG(sky2->port, RX_GMF_CTRL_T), GMF_RST_SET); + + sky2_read8(hw, B0_CTST); } /* Clean out receive buffer area, assumes receiver hardware stopped */ @@ -1169,6 +1176,7 @@ static void sky2_rx_clean(struct sky2_port *sky2) re->skb = NULL; } } + skb_queue_purge(&sky2->rx_recycle); } /* Basic MII support */ @@ -1245,6 +1253,12 @@ static void sky2_vlan_rx_register(struct net_device *dev, struct vlan_group *grp } #endif +/* Amount of required worst case padding in rx buffer */ +static inline unsigned sky2_rx_pad(const struct sky2_hw *hw) +{ + return (hw->flags & SKY2_HW_RAM_BUFFER) ? 8 : 2; +} + /* * Allocate an skb for receiving. If the MTU is large enough * make the skb non-linear with a fragment list of pages. @@ -1254,6 +1268,13 @@ static struct sk_buff *sky2_rx_alloc(struct sky2_port *sky2) struct sk_buff *skb; int i; + skb = __skb_dequeue(&sky2->rx_recycle); + if (!skb) + skb = netdev_alloc_skb(sky2->netdev, sky2->rx_data_size + + sky2_rx_pad(sky2->hw)); + if (!skb) + goto nomem; + if (sky2->hw->flags & SKY2_HW_RAM_BUFFER) { unsigned char *start; /* @@ -1262,18 +1283,10 @@ static struct sk_buff *sky2_rx_alloc(struct sky2_port *sky2) * The buffer returned from netdev_alloc_skb is * aligned except if slab debugging is enabled. */ - skb = netdev_alloc_skb(sky2->netdev, sky2->rx_data_size + 8); - if (!skb) - goto nomem; start = PTR_ALIGN(skb->data, 8); skb_reserve(skb, start - skb->data); - } else { - skb = netdev_alloc_skb(sky2->netdev, - sky2->rx_data_size + NET_IP_ALIGN); - if (!skb) - goto nomem; + } else skb_reserve(skb, NET_IP_ALIGN); - } for (i = 0; i < sky2->rx_nfrags; i++) { struct page *page = alloc_page(GFP_ATOMIC); @@ -1350,6 +1363,8 @@ static int sky2_rx_start(struct sky2_port *sky2) sky2->rx_data_size = size; + skb_queue_head_init(&sky2->rx_recycle); + /* Fill Rx ring */ for (i = 0; i < sky2->rx_pending; i++) { re = sky2->rx_ring + i; @@ -1488,6 +1503,7 @@ static int sky2_up(struct net_device *dev) imask = sky2_read32(hw, B0_IMSK); imask |= portirq_msk[port]; sky2_write32(hw, B0_IMSK, imask); + sky2_read32(hw, B0_IMSK); sky2_set_multicast(dev); @@ -1690,7 +1706,6 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) sky2_put_idx(hw, txqaddr[sky2->port], sky2->tx_prod); - dev->trans_start = jiffies; return NETDEV_TX_OK; mapping_unwind: @@ -1757,14 +1772,22 @@ static void sky2_tx_complete(struct sky2_port *sky2, u16 done) } if (le->ctrl & EOP) { + struct sk_buff *skb = re->skb; + if (unlikely(netif_msg_tx_done(sky2))) printk(KERN_DEBUG "%s: tx done %u\n", dev->name, idx); dev->stats.tx_packets++; - dev->stats.tx_bytes += re->skb->len; + dev->stats.tx_bytes += skb->len; + + if (skb_queue_len(&sky2->rx_recycle) < sky2->rx_pending + && skb_recycle_check(skb, sky2->rx_data_size + + sky2_rx_pad(sky2->hw))) + __skb_queue_head(&sky2->rx_recycle, skb); + else + dev_kfree_skb_any(skb); - dev_kfree_skb_any(re->skb); sky2->tx_next = RING_NEXT(idx, TX_RING_SIZE); } } @@ -1806,10 +1829,10 @@ static int sky2_down(struct net_device *dev) imask = sky2_read32(hw, B0_IMSK); imask &= ~portirq_msk[port]; sky2_write32(hw, B0_IMSK, imask); + sky2_read32(hw, B0_IMSK); - synchronize_irq(hw->pdev->irq); - - sky2_gmac_reset(hw, port); + /* Force flow control off */ + sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF); /* Stop transmitter */ sky2_write32(hw, Q_ADDR(txqaddr[port], Q_CSR), BMU_STOP); @@ -1822,9 +1845,6 @@ static int sky2_down(struct net_device *dev) ctrl &= ~(GM_GPCR_TX_ENA | GM_GPCR_RX_ENA); gma_write16(hw, port, GM_GP_CTRL, ctrl); - /* Make sure no packets are pending */ - napi_synchronize(&hw->napi); - sky2_write8(hw, SK_REG(port, GPHY_CTRL), GPC_RST_SET); /* Workaround shared GMAC reset */ @@ -1855,6 +1875,15 @@ 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); + /* Force any delayed status interrrupt and NAPI */ + sky2_write32(hw, STAT_LEV_TIMER_CNT, 0); + sky2_write32(hw, STAT_TX_TIMER_CNT, 0); + sky2_write32(hw, STAT_ISR_TIMER_CNT, 0); + sky2_read8(hw, STAT_ISR_TIMER_CTRL); + + synchronize_irq(hw->pdev->irq); + napi_synchronize(&hw->napi); + sky2_phy_power_down(hw, port); /* turn off LED's */ @@ -2344,11 +2373,45 @@ static inline void sky2_tx_done(struct net_device *dev, u16 last) } } +static inline void sky2_skb_rx(const struct sky2_port *sky2, + u32 status, struct sk_buff *skb) +{ +#ifdef SKY2_VLAN_TAG_USED + u16 vlan_tag = be16_to_cpu(sky2->rx_tag); + if (sky2->vlgrp && (status & GMR_FS_VLAN)) { + if (skb->ip_summed == CHECKSUM_NONE) + vlan_hwaccel_receive_skb(skb, sky2->vlgrp, vlan_tag); + else + vlan_gro_receive(&sky2->hw->napi, sky2->vlgrp, + vlan_tag, skb); + return; + } +#endif + if (skb->ip_summed == CHECKSUM_NONE) + netif_receive_skb(skb); + else + napi_gro_receive(&sky2->hw->napi, skb); +} + +static inline void sky2_rx_done(struct sky2_hw *hw, unsigned port, + unsigned packets, unsigned bytes) +{ + if (packets) { + struct net_device *dev = hw->dev[port]; + + dev->stats.rx_packets += packets; + dev->stats.rx_bytes += bytes; + dev->last_rx = jiffies; + sky2_rx_update(netdev_priv(dev), rxqaddr[port]); + } +} + /* Process status response ring */ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx) { int work_done = 0; - unsigned rx[2] = { 0, 0 }; + unsigned int total_bytes[2] = { 0 }; + unsigned int total_packets[2] = { 0 }; rmb(); do { @@ -2375,7 +2438,8 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx) le->opcode = 0; switch (opcode & ~HW_OWNER) { case OP_RXSTAT: - ++rx[port]; + total_packets[port]++; + total_bytes[port] += length; skb = sky2_receive(dev, length, status); if (unlikely(!skb)) { dev->stats.rx_dropped++; @@ -2393,18 +2457,8 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx) } skb->protocol = eth_type_trans(skb, dev); - dev->stats.rx_packets++; - dev->stats.rx_bytes += skb->len; - dev->last_rx = jiffies; -#ifdef SKY2_VLAN_TAG_USED - if (sky2->vlgrp && (status & GMR_FS_VLAN)) { - vlan_hwaccel_receive_skb(skb, - sky2->vlgrp, - be16_to_cpu(sky2->rx_tag)); - } else -#endif - netif_receive_skb(skb); + sky2_skb_rx(sky2, status, skb); /* Stop after net poll weight */ if (++work_done >= to_do) @@ -2474,11 +2528,8 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx) sky2_write32(hw, STAT_CTRL, SC_STAT_CLR_IRQ); exit_loop: - if (rx[0]) - sky2_rx_update(netdev_priv(hw->dev[0]), Q_R1); - - if (rx[1]) - sky2_rx_update(netdev_priv(hw->dev[1]), Q_R2); + sky2_rx_done(hw, 0, total_packets[0], total_bytes[0]); + sky2_rx_done(hw, 1, total_packets[1], total_bytes[1]); return work_done; } @@ -4365,6 +4416,22 @@ static int __devinit sky2_probe(struct pci_dev *pdev, goto err_out; } + /* Get configuration information + * Note: only regular PCI config access once to test for HW issues + * other PCI access through shared memory for speed and to + * avoid MMCONFIG problems. + */ + err = pci_read_config_dword(pdev, PCI_DEV_REG2, ®); + if (err) { + dev_err(&pdev->dev, "PCI read config failed\n"); + goto err_out; + } + + if (~reg == 0) { + dev_err(&pdev->dev, "PCI configuration read error\n"); + goto err_out; + } + err = pci_request_regions(pdev, DRV_NAME); if (err) { dev_err(&pdev->dev, "cannot obtain PCI resources\n"); @@ -4390,21 +4457,6 @@ static int __devinit sky2_probe(struct pci_dev *pdev, } } - /* Get configuration information - * Note: only regular PCI config access once to test for HW issues - * other PCI access through shared memory for speed and to - * avoid MMCONFIG problems. - */ - err = pci_read_config_dword(pdev, PCI_DEV_REG2, ®); - if (err) { - dev_err(&pdev->dev, "PCI read config failed\n"); - goto err_out_free_regions; - } - - /* size of available VPD, only impact sysfs */ - err = pci_vpd_truncate(pdev, 1ul << (((reg & PCI_VPD_ROM_SZ) >> 14) + 8)); - if (err) - dev_warn(&pdev->dev, "Can't set VPD size\n"); #ifdef __BIG_ENDIAN /* The sk98lin vendor driver uses hardware byte swapping but diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index 92fb24b27d45..b5549c9e5107 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -2028,6 +2028,7 @@ struct sky2_port { u16 rx_pending; u16 rx_data_size; u16 rx_nfrags; + struct sk_buff_head rx_recycle; #ifdef SKY2_VLAN_TAG_USED u16 rx_tag; diff --git a/drivers/net/smc-mca.c b/drivers/net/smc-mca.c index 8d36d40649ef..c791ef76c1d6 100644 --- a/drivers/net/smc-mca.c +++ b/drivers/net/smc-mca.c @@ -370,7 +370,7 @@ static int __init ultramca_probe(struct device *gen_dev) outb(reg4, ioaddr + 4); - gen_dev->driver_data = dev; + dev_set_drvdata(gen_dev, dev); /* The 8390 isn't at the base address, so fake the offset */ @@ -531,7 +531,7 @@ static int ultramca_close_card(struct net_device *dev) static int ultramca_remove(struct device *gen_dev) { struct mca_device *mca_dev = to_mca_device(gen_dev); - struct net_device *dev = (struct net_device *)gen_dev->driver_data; + struct net_device *dev = dev_get_drvdata(gen_dev); if (dev) { /* NB: ultra_close_card() does free_irq */ diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 293610334a77..bc4976ac8712 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -1774,6 +1774,20 @@ static int __devinit smc911x_findirq(struct net_device *dev) return probe_irq_off(cookie); } +static const struct net_device_ops smc911x_netdev_ops = { + .ndo_open = smc911x_open, + .ndo_stop = smc911x_close, + .ndo_start_xmit = smc911x_hard_start_xmit, + .ndo_tx_timeout = smc911x_timeout, + .ndo_set_multicast_list = smc911x_set_multicast_list, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = smc911x_poll_controller, +#endif +}; + /* * Function: smc911x_probe(unsigned long ioaddr) * @@ -1940,16 +1954,9 @@ static int __devinit smc911x_probe(struct net_device *dev) /* Fill in the fields of the device structure with ethernet values. */ ether_setup(dev); - dev->open = smc911x_open; - dev->stop = smc911x_close; - dev->hard_start_xmit = smc911x_hard_start_xmit; - dev->tx_timeout = smc911x_timeout; + dev->netdev_ops = &smc911x_netdev_ops; dev->watchdog_timeo = msecs_to_jiffies(watchdog); - dev->set_multicast_list = smc911x_set_multicast_list; dev->ethtool_ops = &smc911x_ethtool_ops; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = smc911x_poll_controller; -#endif INIT_WORK(&lp->phy_configure, smc911x_phy_configure); lp->mii.phy_id_mask = 0x1f; diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c index 9a7973a54116..e02471b2f2b5 100644 --- a/drivers/net/smc9194.c +++ b/drivers/net/smc9194.c @@ -503,7 +503,7 @@ static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * de /* THIS SHOULD NEVER HAPPEN. */ dev->stats.tx_aborted_errors++; printk(CARDNAME": Bad Craziness - sent packet while busy.\n" ); - return 1; + return NETDEV_TX_BUSY; } lp->saved_skb = skb; diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h index 329f890e2903..f1f773b17fe1 100644 --- a/drivers/net/smc91x.h +++ b/drivers/net/smc91x.h @@ -45,7 +45,8 @@ defined(CONFIG_MACH_ZYLONITE) ||\ defined(CONFIG_MACH_LITTLETON) ||\ defined(CONFIG_MACH_ZYLONITE2) ||\ - defined(CONFIG_ARCH_VIPER) + defined(CONFIG_ARCH_VIPER) ||\ + defined(CONFIG_MACH_STARGATE2) #include @@ -73,7 +74,7 @@ /* We actually can't write halfwords properly if not word aligned */ static inline void SMC_outw(u16 val, void __iomem *ioaddr, int reg) { - if (machine_is_mainstone() && reg & 2) { + if ((machine_is_mainstone() || machine_is_stargate2()) && reg & 2) { unsigned int v = val << 16; v |= readl(ioaddr + (reg & ~2)) & 0xffff; writel(v, ioaddr + (reg & ~2)); diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c index eb7db032a780..b60639bd181b 100644 --- a/drivers/net/smsc911x.c +++ b/drivers/net/smsc911x.c @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include "smsc911x.h" @@ -175,6 +176,12 @@ static inline void smsc911x_tx_writefifo(struct smsc911x_data *pdata, unsigned int *buf, unsigned int wordcount) { + if (pdata->config.flags & SMSC911X_SWAP_FIFO) { + while (wordcount--) + smsc911x_reg_write(pdata, TX_DATA_FIFO, swab32(*buf++)); + return; + } + if (pdata->config.flags & SMSC911X_USE_32BIT) { writesl(pdata->ioaddr + TX_DATA_FIFO, buf, wordcount); return; @@ -194,6 +201,12 @@ static inline void smsc911x_rx_readfifo(struct smsc911x_data *pdata, unsigned int *buf, unsigned int wordcount) { + if (pdata->config.flags & SMSC911X_SWAP_FIFO) { + while (wordcount--) + *buf++ = swab32(smsc911x_reg_read(pdata, RX_DATA_FIFO)); + return; + } + if (pdata->config.flags & SMSC911X_USE_32BIT) { readsl(pdata->ioaddr + RX_DATA_FIFO, buf, wordcount); return; @@ -1963,7 +1976,7 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev) retval = -ENODEV; goto out_0; } - res_size = res->end - res->start; + res_size = res->end - res->start + 1; irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!irq_res) { @@ -2096,12 +2109,58 @@ out_0: return retval; } +#ifdef CONFIG_PM +/* This implementation assumes the devices remains powered on its VDDVARIO + * pins during suspend. */ + +static int smsc911x_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct net_device *dev = platform_get_drvdata(pdev); + struct smsc911x_data *pdata = netdev_priv(dev); + + /* enable wake on LAN, energy detection and the external PME + * signal. */ + smsc911x_reg_write(pdata, PMT_CTRL, + PMT_CTRL_PM_MODE_D1_ | PMT_CTRL_WOL_EN_ | + PMT_CTRL_ED_EN_ | PMT_CTRL_PME_EN_); + + return 0; +} + +static int smsc911x_resume(struct platform_device *pdev) +{ + struct net_device *dev = platform_get_drvdata(pdev); + struct smsc911x_data *pdata = netdev_priv(dev); + unsigned int to = 100; + + /* Note 3.11 from the datasheet: + * "When the LAN9220 is in a power saving state, a write of any + * data to the BYTE_TEST register will wake-up the device." + */ + smsc911x_reg_write(pdata, BYTE_TEST, 0); + + /* poll the READY bit in PMT_CTRL. Any other access to the device is + * forbidden while this bit isn't set. Try for 100ms and return -EIO + * if it failed. */ + while (!(smsc911x_reg_read(pdata, PMT_CTRL) & PMT_CTRL_READY_) && --to) + udelay(1000); + + return (to == 0) ? -EIO : 0; +} + +#else +#define smsc911x_suspend NULL +#define smsc911x_resume NULL +#endif + static struct platform_driver smsc911x_driver = { .probe = smsc911x_drv_probe, - .remove = smsc911x_drv_remove, + .remove = __devexit_p(smsc911x_drv_remove), .driver = { .name = SMSC_CHIPNAME, }, + .suspend = smsc911x_suspend, + .resume = smsc911x_resume, }; /* Entry point for loading the module */ diff --git a/drivers/net/sonic.c b/drivers/net/sonic.c index 211e805c1223..753a1fba4609 100644 --- a/drivers/net/sonic.c +++ b/drivers/net/sonic.c @@ -223,7 +223,7 @@ static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev) if (!laddr) { printk(KERN_ERR "%s: failed to map tx DMA buffer.\n", dev->name); dev_kfree_skb(skb); - return 1; + return NETDEV_TX_BUSY; } sonic_tda_put(dev, entry, SONIC_TD_STATUS, 0); /* clear status */ diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index fcb943fca4f1..838cce8b8fff 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -1236,7 +1236,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) */ if ((np->cur_tx - np->dirty_tx) + skb_num_frags(skb) * 2 > TX_RING_SIZE) { netif_stop_queue(dev); - return 1; + return NETDEV_TX_BUSY; } #if defined(ZEROCOPY) && defined(HAS_BROKEN_FIRMWARE) diff --git a/drivers/net/sun3_82586.c b/drivers/net/sun3_82586.c index a39c0b9ba8b6..7bb27426dbd6 100644 --- a/drivers/net/sun3_82586.c +++ b/drivers/net/sun3_82586.c @@ -1023,7 +1023,7 @@ static int sun3_82586_send_packet(struct sk_buff *skb, struct net_device *dev) #if(NUM_XMIT_BUFFS > 1) if(test_and_set_bit(0,(void *) &p->lock)) { printk("%s: Queue was locked\n",dev->name); - return 1; + return NETDEV_TX_BUSY; } else #endif diff --git a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c index e5beb299cbd0..534dfe3eef6f 100644 --- a/drivers/net/sun3lance.c +++ b/drivers/net/sun3lance.c @@ -294,6 +294,16 @@ out: return ERR_PTR(err); } +static const struct net_device_ops lance_netdev_ops = { + .ndo_open = lance_open, + .ndo_stop = lance_close, + .ndo_start_xmit = lance_start_xmit, + .ndo_set_multicast_list = set_multicast_list, + .ndo_set_mac_address = NULL, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, +}; + static int __init lance_probe( struct net_device *dev) { unsigned long ioaddr; @@ -397,12 +407,7 @@ static int __init lance_probe( struct net_device *dev) if (did_version++ == 0) printk( version ); - /* The LANCE-specific entries in the device structure. */ - dev->open = &lance_open; - dev->hard_start_xmit = &lance_start_xmit; - dev->stop = &lance_close; - dev->set_multicast_list = &set_multicast_list; - dev->set_mac_address = NULL; + dev->netdev_ops = &lance_netdev_ops; // KLUDGE -- REMOVE ME set_bit(__LINK_STATE_PRESENT, &dev->state); @@ -521,7 +526,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ) if (netif_queue_stopped(dev)) { int tickssofar = jiffies - dev->trans_start; if (tickssofar < 20) - return( 1 ); + return NETDEV_TX_BUSY; DPRINTK( 1, ( "%s: transmit timed out, status %04x, resetting.\n", dev->name, DREG )); @@ -572,7 +577,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ) if (test_and_set_bit( 0, (void*)&lp->lock ) != 0) { printk( "%s: tx queue lock!.\n", dev->name); /* don't clear dev->tbusy flag. */ - return 1; + return NETDEV_TX_BUSY; } AREG = CSR0; diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index c399b1955c1e..545f81b34ad7 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c @@ -369,7 +369,6 @@ struct netdev_private { struct sk_buff* tx_skbuff[TX_RING_SIZE]; dma_addr_t tx_ring_dma; dma_addr_t rx_ring_dma; - struct net_device_stats stats; struct timer_list timer; /* Media monitoring timer. */ /* Frequently used values: keep some adjacent for cache effect. */ spinlock_t lock; @@ -975,7 +974,7 @@ static void tx_timeout(struct net_device *dev) dev->if_port = 0; dev->trans_start = jiffies; - np->stats.tx_errors++; + dev->stats.tx_errors++; if (np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 4) { netif_wake_queue(dev); } @@ -1123,7 +1122,7 @@ reset_tx (struct net_device *dev) else dev_kfree_skb (skb); np->tx_skbuff[i] = NULL; - np->stats.tx_dropped++; + dev->stats.tx_dropped++; } } np->cur_tx = np->dirty_tx = 0; @@ -1181,15 +1180,15 @@ static irqreturn_t intr_handler(int irq, void *dev_instance) if (netif_msg_tx_err(np)) printk("%s: Transmit error status %4.4x.\n", dev->name, tx_status); - np->stats.tx_errors++; + dev->stats.tx_errors++; if (tx_status & 0x10) - np->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; if (tx_status & 0x08) - np->stats.collisions++; + dev->stats.collisions++; if (tx_status & 0x04) - np->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; if (tx_status & 0x02) - np->stats.tx_window_errors++; + dev->stats.tx_window_errors++; /* ** This reset has been verified on @@ -1313,11 +1312,15 @@ static void rx_poll(unsigned long data) if (netif_msg_rx_err(np)) printk(KERN_DEBUG " netdev_rx() Rx error was %8.8x.\n", frame_status); - np->stats.rx_errors++; - if (frame_status & 0x00100000) np->stats.rx_length_errors++; - if (frame_status & 0x00010000) np->stats.rx_fifo_errors++; - if (frame_status & 0x00060000) np->stats.rx_frame_errors++; - if (frame_status & 0x00080000) np->stats.rx_crc_errors++; + dev->stats.rx_errors++; + if (frame_status & 0x00100000) + dev->stats.rx_length_errors++; + if (frame_status & 0x00010000) + dev->stats.rx_fifo_errors++; + if (frame_status & 0x00060000) + dev->stats.rx_frame_errors++; + if (frame_status & 0x00080000) + dev->stats.rx_crc_errors++; if (frame_status & 0x00100000) { printk(KERN_WARNING "%s: Oversized Ethernet frame," " status %8.8x.\n", @@ -1485,22 +1488,22 @@ static struct net_device_stats *get_stats(struct net_device *dev) the vulnerability window is very small and statistics are non-critical. */ /* The chip only need report frame silently dropped. */ - np->stats.rx_missed_errors += ioread8(ioaddr + RxMissed); - np->stats.tx_packets += ioread16(ioaddr + TxFramesOK); - np->stats.rx_packets += ioread16(ioaddr + RxFramesOK); - np->stats.collisions += ioread8(ioaddr + StatsLateColl); - np->stats.collisions += ioread8(ioaddr + StatsMultiColl); - np->stats.collisions += ioread8(ioaddr + StatsOneColl); - np->stats.tx_carrier_errors += ioread8(ioaddr + StatsCarrierError); + dev->stats.rx_missed_errors += ioread8(ioaddr + RxMissed); + dev->stats.tx_packets += ioread16(ioaddr + TxFramesOK); + dev->stats.rx_packets += ioread16(ioaddr + RxFramesOK); + dev->stats.collisions += ioread8(ioaddr + StatsLateColl); + dev->stats.collisions += ioread8(ioaddr + StatsMultiColl); + dev->stats.collisions += ioread8(ioaddr + StatsOneColl); + dev->stats.tx_carrier_errors += ioread8(ioaddr + StatsCarrierError); ioread8(ioaddr + StatsTxDefer); for (i = StatsTxDefer; i <= StatsMcastRx; i++) ioread8(ioaddr + i); - np->stats.tx_bytes += ioread16(ioaddr + TxOctetsLow); - np->stats.tx_bytes += ioread16(ioaddr + TxOctetsHigh) << 16; - np->stats.rx_bytes += ioread16(ioaddr + RxOctetsLow); - np->stats.rx_bytes += ioread16(ioaddr + RxOctetsHigh) << 16; + dev->stats.tx_bytes += ioread16(ioaddr + TxOctetsLow); + dev->stats.tx_bytes += ioread16(ioaddr + TxOctetsHigh) << 16; + dev->stats.rx_bytes += ioread16(ioaddr + RxOctetsLow); + dev->stats.rx_bytes += ioread16(ioaddr + RxOctetsHigh) << 16; - return &np->stats; + return &dev->stats; } static void set_rx_mode(struct net_device *dev) diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index 4e9bd380a5c2..4ef729198e10 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -2275,7 +2275,7 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock_irq(&hp->happy_lock); printk(KERN_ERR "%s: BUG! Tx Ring full when queue awake!\n", dev->name); - return 1; + return NETDEV_TX_BUSY; } entry = hp->tx_new; diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c index 0ce2db6ce2bf..d737f6b8f876 100644 --- a/drivers/net/tc35815.c +++ b/drivers/net/tc35815.c @@ -688,14 +688,11 @@ static void tc_handle_link_change(struct net_device *dev) if (status_change && netif_msg_link(lp)) { phy_print_status(phydev); -#ifdef DEBUG - printk(KERN_DEBUG - "%s: MII BMCR %04x BMSR %04x LPA %04x\n", - dev->name, - phy_read(phydev, MII_BMCR), - phy_read(phydev, MII_BMSR), - phy_read(phydev, MII_LPA)); -#endif + pr_debug("%s: MII BMCR %04x BMSR %04x LPA %04x\n", + dev->name, + phy_read(phydev, MII_BMCR), + phy_read(phydev, MII_BMSR), + phy_read(phydev, MII_LPA)); } } diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c index 7f4a9683ba1e..3c2679cd196b 100644 --- a/drivers/net/tehuti.c +++ b/drivers/net/tehuti.c @@ -948,8 +948,7 @@ static void print_rxfd(struct rxf_desc *rxfd); static void bdx_rxdb_destroy(struct rxdb *db) { - if (db) - vfree(db); + vfree(db); } static struct rxdb *bdx_rxdb_create(int nelem) @@ -1482,10 +1481,8 @@ static void bdx_tx_db_close(struct txdb *d) { BDX_ASSERT(d == NULL); - if (d->start) { - vfree(d->start); - d->start = NULL; - } + vfree(d->start); + d->start = NULL; } /************************************************************************* @@ -1718,8 +1715,9 @@ static int bdx_tx_transmit(struct sk_buff *skb, struct net_device *ndev) WRITE_REG(priv, f->m.reg_WPTR, f->m.wptr & TXF_WPTR_WR_PTR); #endif - ndev->trans_start = jiffies; - +#ifdef BDX_LLTX + ndev->trans_start = jiffies; /* NETIF_F_LLTX driver :( */ +#endif priv->net_stats.tx_packets++; priv->net_stats.tx_bytes += skb->len; diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 201be425643a..46a3f86125be 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -68,8 +68,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.98" -#define DRV_MODULE_RELDATE "February 25, 2009" +#define DRV_MODULE_VERSION "3.99" +#define DRV_MODULE_RELDATE "April 20, 2009" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 @@ -1950,7 +1950,8 @@ static void tg3_frob_aux_power(struct tg3 *tp) GRC_LCLCTRL_GPIO_OUTPUT0 | GRC_LCLCTRL_GPIO_OUTPUT1), 100); - } else if (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5761) { + } else if (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5761 || + tp->pdev->device == TG3PCI_DEVICE_TIGON3_5761S) { /* The 5761 non-e device swaps GPIO 0 and GPIO 2. */ u32 grc_local_ctrl = GRC_LCLCTRL_GPIO_OE0 | GRC_LCLCTRL_GPIO_OE1 | @@ -2455,8 +2456,6 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) } } - __tg3_set_mac_addr(tp, 0); - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { u32 val; @@ -4656,6 +4655,7 @@ static int tg3_poll(struct napi_struct *napi, int budget) * so we must read it before checking for more work. */ tp->last_tag = sblk->status_tag; + tp->last_irq_tag = tp->last_tag; rmb(); } else sblk->status &= ~SD_STATUS_UPDATED; @@ -4811,7 +4811,7 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id) * Reading the PCI State register will confirm whether the * interrupt is ours and will flush the status block. */ - if (unlikely(sblk->status_tag == tp->last_tag)) { + if (unlikely(sblk->status_tag == tp->last_irq_tag)) { if ((tp->tg3_flags & TG3_FLAG_CHIP_RESETTING) || (tr32(TG3PCI_PCISTATE) & PCISTATE_INT_NOT_ACTIVE)) { handled = 0; @@ -4831,18 +4831,22 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id) * excessive spurious interrupts can be worse in some cases. */ tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001); + + /* + * In a shared interrupt configuration, sometimes other devices' + * interrupts will scream. We record the current status tag here + * so that the above check can report that the screaming interrupts + * are unhandled. Eventually they will be silenced. + */ + tp->last_irq_tag = sblk->status_tag; + if (tg3_irq_sync(tp)) goto out; - if (napi_schedule_prep(&tp->napi)) { - prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]); - /* Update last_tag to mark that this status has been - * seen. Because interrupt may be shared, we may be - * racing with tg3_poll(), so only update last_tag - * if tg3_poll() is not scheduled. - */ - tp->last_tag = sblk->status_tag; - __napi_schedule(&tp->napi); - } + + prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]); + + napi_schedule(&tp->napi); + out: return IRQ_RETVAL(handled); } @@ -5017,7 +5021,7 @@ static int tigon3_dma_hwbug_workaround(struct tg3 *tp, struct sk_buff *skb, /* New SKB is guaranteed to be linear. */ entry = *start; ret = skb_dma_map(&tp->pdev->dev, new_skb, DMA_TO_DEVICE); - new_addr = skb_shinfo(new_skb)->dma_maps[0]; + new_addr = skb_shinfo(new_skb)->dma_head; /* Make sure new skb does not cross any 4G boundaries. * Drop the packet if it does. @@ -5151,7 +5155,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) sp = skb_shinfo(skb); - mapping = sp->dma_maps[0]; + mapping = sp->dma_head; tp->tx_buffers[entry].skb = skb; @@ -5169,7 +5173,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; len = frag->size; - mapping = sp->dma_maps[i + 1]; + mapping = sp->dma_maps[i]; tp->tx_buffers[entry].skb = NULL; tg3_set_txd(tp, entry, mapping, len, @@ -5190,9 +5194,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) } out_unlock: - mmiowb(); - - dev->trans_start = jiffies; + mmiowb(); return NETDEV_TX_OK; } @@ -5329,7 +5331,7 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev) sp = skb_shinfo(skb); - mapping = sp->dma_maps[0]; + mapping = sp->dma_head; tp->tx_buffers[entry].skb = skb; @@ -5354,7 +5356,7 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev) skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; len = frag->size; - mapping = sp->dma_maps[i + 1]; + mapping = sp->dma_maps[i]; tp->tx_buffers[entry].skb = NULL; @@ -5403,9 +5405,7 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev) } out_unlock: - mmiowb(); - - dev->trans_start = jiffies; + mmiowb(); return NETDEV_TX_OK; } @@ -6156,6 +6156,7 @@ static int tg3_chip_reset(struct tg3 *tp) tp->hw_status->status_tag = 0; } tp->last_tag = 0; + tp->last_irq_tag = 0; smp_mb(); synchronize_irq(tp->pdev->irq); @@ -6350,6 +6351,8 @@ static int tg3_halt(struct tg3 *tp, int kind, int silent) tg3_abort_hw(tp, silent); err = tg3_chip_reset(tp); + __tg3_set_mac_addr(tp, 0); + tg3_write_sig_legacy(tp, kind); tg3_write_sig_post_reset(tp, kind); @@ -6711,6 +6714,13 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32(TG3_CPMU_HST_ACC, val); } + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) { + val = tr32(PCIE_PWR_MGMT_THRESH) & ~PCIE_PWR_MGMT_L1_THRESH_MSK; + val |= PCIE_PWR_MGMT_EXT_ASPM_TMR_EN | + PCIE_PWR_MGMT_L1_THRESH_4MS; + tw32(PCIE_PWR_MGMT_THRESH, val); + } + /* This works around an issue with Athlon chipsets on * B3 tigon3 silicon. This bit has no effect on any * other revision. But do not set this on PCI Express @@ -7138,7 +7148,6 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) udelay(100); tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0); - tp->last_tag = 0; if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { tw32_f(DMAC_MODE, DMAC_MODE_ENABLE); @@ -8539,6 +8548,9 @@ static int tg3_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u32 i, offset, len, b_offset, b_count; __be32 val; + if (tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) + return -EINVAL; + if (tp->link_config.phy_is_low_power) return -EAGAIN; @@ -8604,7 +8616,8 @@ static int tg3_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, if (tp->link_config.phy_is_low_power) return -EAGAIN; - if (eeprom->magic != TG3_EEPROM_MAGIC) + if ((tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) || + eeprom->magic != TG3_EEPROM_MAGIC) return -EINVAL; offset = eeprom->offset; @@ -9201,6 +9214,9 @@ static int tg3_test_nvram(struct tg3 *tp) __be32 *buf; int i, j, k, err = 0, size; + if (tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) + return 0; + if (tg3_nvram_read(tp, 0, &magic) != 0) return -EIO; @@ -10183,7 +10199,8 @@ static void __devinit tg3_get_nvram_size(struct tg3 *tp) { u32 val; - if (tg3_nvram_read(tp, 0, &val) != 0) + if ((tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) || + tg3_nvram_read(tp, 0, &val) != 0) return; /* Selfboot format */ @@ -10565,6 +10582,7 @@ static void __devinit tg3_get_57780_nvram_info(struct tg3 *tp) } break; default: + tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM; return; } @@ -11365,7 +11383,8 @@ static void __devinit tg3_read_partno(struct tg3 *tp) unsigned int i; u32 magic; - if (tg3_nvram_read(tp, 0x0, &magic)) + if ((tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) || + tg3_nvram_read(tp, 0x0, &magic)) goto out_not_found; if (magic == TG3_EEPROM_MAGIC) { @@ -11457,6 +11476,15 @@ static void __devinit tg3_read_partno(struct tg3 *tp) out_not_found: if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) strcpy(tp->board_part_number, "BCM95906"); + else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 && + tp->pdev->device == TG3PCI_DEVICE_TIGON3_57780) + strcpy(tp->board_part_number, "BCM57780"); + else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 && + tp->pdev->device == TG3PCI_DEVICE_TIGON3_57760) + strcpy(tp->board_part_number, "BCM57760"); + else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 && + tp->pdev->device == TG3PCI_DEVICE_TIGON3_57790) + strcpy(tp->board_part_number, "BCM57790"); else strcpy(tp->board_part_number, "none"); } @@ -11667,6 +11695,14 @@ static void __devinit tg3_read_fw_ver(struct tg3 *tp) { u32 val; + if (tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) { + tp->fw_ver[0] = 's'; + tp->fw_ver[1] = 'b'; + tp->fw_ver[2] = '\0'; + + return; + } + if (tg3_nvram_read(tp, 0, &val)) return; @@ -11952,7 +11988,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->tg3_flags2 &= ~TG3_FLG2_HW_TSO_2; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) + tp->pci_chip_rev_id == CHIPREV_ID_57780_A0 || + tp->pci_chip_rev_id == CHIPREV_ID_57780_A1) tp->tg3_flags3 |= TG3_FLG3_CLKREQ_BUG; } } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) { @@ -12144,7 +12181,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) tp->grc_local_ctrl |= GRC_LCLCTRL_GPIO_UART_SEL; - if (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5761) { + if (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5761 || + tp->pdev->device == TG3PCI_DEVICE_TIGON3_5761S) { /* Turn off the debug UART. */ tp->grc_local_ctrl |= GRC_LCLCTRL_GPIO_UART_SEL; if (tp->tg3_flags2 & TG3_FLG2_IS_NIC) @@ -12454,7 +12492,8 @@ static int __devinit tg3_get_device_address(struct tg3 *tp) } if (!addr_ok) { /* Next, try NVRAM. */ - if (!tg3_nvram_read_be32(tp, mac_offset + 0, &hi) && + if (!(tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) && + !tg3_nvram_read_be32(tp, mac_offset + 0, &hi) && !tg3_nvram_read_be32(tp, mac_offset + 4, &lo)) { memcpy(&dev->dev_addr[0], ((char *)&hi) + 2, 2); memcpy(&dev->dev_addr[2], (char *)&lo, sizeof(lo)); diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index cb4c62abdd21..b3347c41a1a3 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -95,6 +95,8 @@ #define CHIPREV_ID_5752_A1 0x6001 #define CHIPREV_ID_5714_A2 0x9002 #define CHIPREV_ID_5906_A1 0xc001 +#define CHIPREV_ID_57780_A0 0x57780000 +#define CHIPREV_ID_57780_A1 0x57780001 #define GET_ASIC_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 12) #define ASIC_REV_5700 0x07 #define ASIC_REV_5701 0x00 @@ -1697,6 +1699,8 @@ #define PCIE_PWR_MGMT_THRESH 0x00007d28 #define PCIE_PWR_MGMT_L1_THRESH_MSK 0x0000ff00 +#define PCIE_PWR_MGMT_L1_THRESH_4MS 0x0000ff00 +#define PCIE_PWR_MGMT_EXT_ASPM_TMR_EN 0x01000000 /* OTP bit definitions */ @@ -2501,6 +2505,7 @@ struct tg3 { struct tg3_hw_status *hw_status; dma_addr_t status_mapping; u32 last_tag; + u32 last_irq_tag; u32 msg_enable; @@ -2635,6 +2640,7 @@ struct tg3 { #define TG3_FLG3_CLKREQ_BUG 0x00000800 #define TG3_FLG3_PHY_ENABLE_APD 0x00001000 #define TG3_FLG3_5755_PLUS 0x00002000 +#define TG3_FLG3_NO_NVRAM 0x00004000 struct timer_list timer; u16 timer_counter; diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c index aa6964922d5e..384cb5e28397 100644 --- a/drivers/net/tlan.c +++ b/drivers/net/tlan.c @@ -1111,7 +1111,7 @@ static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev ) dev->name, priv->txHead, priv->txTail ); netif_stop_queue(dev); priv->txBusyCount++; - return 1; + return NETDEV_TX_BUSY; } tail_list->forward = 0; diff --git a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c index 534c0f38483c..b40b6de2d086 100644 --- a/drivers/net/tokenring/3c359.c +++ b/drivers/net/tokenring/3c359.c @@ -79,7 +79,7 @@ MODULE_AUTHOR("Mike Phillips ") ; MODULE_DESCRIPTION("3Com 3C359 Velocity XL Token Ring Adapter Driver \n") ; MODULE_FIRMWARE(FW_NAME); -/* Module paramters */ +/* Module parameters */ /* Ring Speed 0,4,16 * 0 = Autosense @@ -1243,7 +1243,7 @@ static int xl_xmit(struct sk_buff *skb, struct net_device *dev) return 0; } else { spin_unlock_irqrestore(&xl_priv->xl_lock,flags) ; - return 1; + return NETDEV_TX_BUSY; } } diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c index 2e70ee8f1459..b3715efdce56 100644 --- a/drivers/net/tokenring/lanstreamer.c +++ b/drivers/net/tokenring/lanstreamer.c @@ -169,7 +169,7 @@ static char *open_min_error[] = { "Monitor Contention failer for RPL", "FDX Protocol Error" }; -/* Module paramters */ +/* Module parameters */ /* Ring Speed 0,4,16 * 0 = Autosense @@ -1187,7 +1187,7 @@ static int streamer_xmit(struct sk_buff *skb, struct net_device *dev) } else { netif_stop_queue(dev); spin_unlock_irqrestore(&streamer_priv->streamer_lock,flags); - return 1; + return NETDEV_TX_BUSY; } } diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c index d068a9d36883..451b54136ede 100644 --- a/drivers/net/tokenring/olympic.c +++ b/drivers/net/tokenring/olympic.c @@ -132,7 +132,7 @@ static char *open_min_error[] = {"No error", "Function Failure", "Signal Lost", "Reserved", "Reserved", "No Monitor Detected for RPL", "Monitor Contention failer for RPL", "FDX Protocol Error"}; -/* Module paramters */ +/* Module parameters */ MODULE_AUTHOR("Mike Phillips ") ; MODULE_DESCRIPTION("Olympic PCI/Cardbus Chipset Driver") ; @@ -1055,7 +1055,7 @@ static int olympic_xmit(struct sk_buff *skb, struct net_device *dev) return 0; } else { spin_unlock_irqrestore(&olympic_priv->olympic_lock,flags); - return 1; + return NETDEV_TX_BUSY; } } diff --git a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c index a91d9c55d78e..54ad4ed03374 100644 --- a/drivers/net/tokenring/smctr.c +++ b/drivers/net/tokenring/smctr.c @@ -4601,7 +4601,7 @@ static int smctr_send_packet(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); if(tp->QueueSkb == 0) - return (1); /* Return with tbusy set: queue full */ + return NETDEV_TX_BUSY; /* Return with tbusy set: queue full */ tp->QueueSkb--; skb_queue_tail(&tp->SendSkbQueue, skb); diff --git a/drivers/net/tokenring/tms380tr.c b/drivers/net/tokenring/tms380tr.c index b11bb72dc7ab..a2eab72b507a 100644 --- a/drivers/net/tokenring/tms380tr.c +++ b/drivers/net/tokenring/tms380tr.c @@ -633,7 +633,7 @@ static int tms380tr_hardware_send_packet(struct sk_buff *skb, struct net_device if (tms380tr_debug > 0) printk(KERN_DEBUG "%s: No free TPL\n", dev->name); spin_unlock_irqrestore(&tp->lock, flags); - return 1; + return NETDEV_TX_BUSY; } dmabuf = 0; diff --git a/drivers/net/tulip/Kconfig b/drivers/net/tulip/Kconfig index d913405bc393..1cc8cf4425d1 100644 --- a/drivers/net/tulip/Kconfig +++ b/drivers/net/tulip/Kconfig @@ -27,6 +27,18 @@ config DE2104X To compile this driver as a module, choose M here. The module will be called de2104x. +config DE2104X_DSL + int "Descriptor Skip Length in 32 bit longwords" + depends on DE2104X + range 0 31 + default 0 + help + Setting this value allows to align ring buffer descriptors into their + own cache lines. Value of 4 corresponds to the typical 32 byte line + (the descriptor is 16 bytes). This is necessary on systems that lack + cache coherence, an example is PowerMac 5500. Otherwise 0 is safe. + Default is 0, and range is 0 to 31. + config TULIP tristate "DECchip Tulip (dc2114x) PCI support" depends on PCI diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index d4c5ecc51f77..81f054dbb88d 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -82,6 +82,13 @@ MODULE_PARM_DESC (rx_copybreak, "de2104x Breakpoint at which Rx packets are copi NETIF_MSG_RX_ERR | \ NETIF_MSG_TX_ERR) +/* Descriptor skip length in 32 bit longwords. */ +#ifndef CONFIG_DE2104X_DSL +#define DSL 0 +#else +#define DSL CONFIG_DE2104X_DSL +#endif + #define DE_RX_RING_SIZE 64 #define DE_TX_RING_SIZE 64 #define DE_RING_BYTES \ @@ -153,6 +160,7 @@ enum { CmdReset = (1 << 0), CacheAlign16 = 0x00008000, BurstLen4 = 0x00000400, + DescSkipLen = (DSL << 2), /* Rx/TxPoll bits */ NormalTxPoll = (1 << 0), @@ -246,7 +254,7 @@ static const u32 de_intr_mask = * Set the programmable burst length to 4 longwords for all: * DMA errors result without these values. Cache align 16 long. */ -static const u32 de_bus_mode = CacheAlign16 | BurstLen4; +static const u32 de_bus_mode = CacheAlign16 | BurstLen4 | DescSkipLen; struct de_srom_media_block { u8 opts; @@ -266,6 +274,9 @@ struct de_desc { __le32 opts2; __le32 addr1; __le32 addr2; +#if DSL + __le32 skip[DSL]; +#endif }; struct media_info { @@ -601,7 +612,7 @@ static int de_start_xmit (struct sk_buff *skb, struct net_device *dev) if (tx_free == 0) { netif_stop_queue(dev); spin_unlock_irq(&de->lock); - return 1; + return NETDEV_TX_BUSY; } tx_free--; diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c index f9491bd787d1..eb72d2e9ab3d 100644 --- a/drivers/net/tulip/de4x5.c +++ b/drivers/net/tulip/de4x5.c @@ -1099,7 +1099,7 @@ de4x5_hw_init(struct net_device *dev, u_long iobase, struct device *gendev) struct pci_dev *pdev = NULL; int i, status=0; - gendev->driver_data = dev; + dev_set_drvdata(gendev, dev); /* Ensure we're not sleeping */ if (lp->bus == EISA) { @@ -1461,12 +1461,12 @@ de4x5_queue_pkt(struct sk_buff *skb, struct net_device *dev) { struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; - int status = 0; + int status = NETDEV_TX_OK; u_long flags = 0; netif_stop_queue(dev); if (!lp->tx_enable) { /* Cannot send for now */ - return -1; + return NETDEV_TX_LOCKED; } /* @@ -1480,7 +1480,7 @@ de4x5_queue_pkt(struct sk_buff *skb, struct net_device *dev) /* Test if cache is already locked - requeue skb if so */ if (test_and_set_bit(0, (void *)&lp->cache.lock) && !lp->interrupt) - return -1; + return NETDEV_TX_LOCKED; /* Transmit descriptor ring full or stale skb */ if (netif_queue_stopped(dev) || (u_long) lp->tx_skb[lp->tx_new] > 1) { @@ -2094,7 +2094,7 @@ static int __devexit de4x5_eisa_remove (struct device *device) struct net_device *dev; u_long iobase; - dev = device->driver_data; + dev = dev_get_drvdata(device); iobase = dev->base_addr; unregister_netdev (dev); @@ -2338,7 +2338,7 @@ static void __devexit de4x5_pci_remove (struct pci_dev *pdev) struct net_device *dev; u_long iobase; - dev = pdev->dev.driver_data; + dev = dev_get_drvdata(&pdev->dev); iobase = dev->base_addr; unregister_netdev (dev); diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c index f2e669974c78..8e78f003f08f 100644 --- a/drivers/net/tulip/dmfe.c +++ b/drivers/net/tulip/dmfe.c @@ -686,7 +686,7 @@ static int dmfe_start_xmit(struct sk_buff *skb, struct DEVICE *dev) spin_unlock_irqrestore(&db->lock, flags); printk(KERN_ERR DRV_NAME ": No Tx resource %ld\n", db->tx_queue_cnt); - return 1; + return NETDEV_TX_BUSY; } /* Disable NIC interrupt */ diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c index 8761a5a5bd79..9277ce8febe4 100644 --- a/drivers/net/tulip/uli526x.c +++ b/drivers/net/tulip/uli526x.c @@ -591,7 +591,7 @@ static int uli526x_start_xmit(struct sk_buff *skb, struct net_device *dev) if (db->tx_packet_cnt >= TX_FREE_DESC_CNT) { spin_unlock_irqrestore(&db->lock, flags); printk(KERN_ERR DRV_NAME ": No Tx resource %ld\n", db->tx_packet_cnt); - return 1; + return NETDEV_TX_BUSY; } /* Disable NIC interrupt */ diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c index 264e61404f34..842b1a2c40d4 100644 --- a/drivers/net/tulip/winbond-840.c +++ b/drivers/net/tulip/winbond-840.c @@ -1601,8 +1601,7 @@ static int w840_suspend (struct pci_dev *pdev, pm_message_t state) /* no more hardware accesses behind this line. */ - BUG_ON(np->csr6); - if (ioread32(ioaddr + IntrEnable)) BUG(); + BUG_ON(np->csr6 || ioread32(ioaddr + IntrEnable)); /* pci_power_off(pdev, -1); */ diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 735bf41c654a..11a0ba47b677 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -540,31 +540,38 @@ static inline struct sk_buff *tun_alloc_skb(struct tun_struct *tun, /* Get packet from user space buffer */ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, - struct iovec *iv, size_t count, + const struct iovec *iv, size_t count, int noblock) { struct tun_pi pi = { 0, cpu_to_be16(ETH_P_IP) }; struct sk_buff *skb; size_t len = count, align = 0; struct virtio_net_hdr gso = { 0 }; + int offset = 0; if (!(tun->flags & TUN_NO_PI)) { if ((len -= sizeof(pi)) > count) return -EINVAL; - if(memcpy_fromiovec((void *)&pi, iv, sizeof(pi))) + if (memcpy_fromiovecend((void *)&pi, iv, 0, sizeof(pi))) return -EFAULT; + offset += sizeof(pi); } if (tun->flags & TUN_VNET_HDR) { if ((len -= sizeof(gso)) > count) return -EINVAL; - if (memcpy_fromiovec((void *)&gso, iv, sizeof(gso))) + if (memcpy_fromiovecend((void *)&gso, iv, offset, sizeof(gso))) return -EFAULT; + if ((gso.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) && + gso.csum_start + gso.csum_offset + 2 > gso.hdr_len) + gso.hdr_len = gso.csum_start + gso.csum_offset + 2; + if (gso.hdr_len > len) return -EINVAL; + offset += sizeof(gso); } if ((tun->flags & TUN_TYPE_MASK) == TUN_TAP_DEV) { @@ -581,7 +588,7 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, return PTR_ERR(skb); } - if (skb_copy_datagram_from_iovec(skb, 0, iv, len)) { + if (skb_copy_datagram_from_iovec(skb, 0, iv, offset, len)) { tun->dev->stats.rx_dropped++; kfree_skb(skb); return -EFAULT; @@ -673,7 +680,7 @@ static ssize_t tun_chr_aio_write(struct kiocb *iocb, const struct iovec *iv, DBG(KERN_INFO "%s: tun_chr_write %ld\n", tun->dev->name, count); - result = tun_get_user(tun, (struct iovec *)iv, iov_length(iv, count), + result = tun_get_user(tun, iv, iov_length(iv, count), file->f_flags & O_NONBLOCK); tun_put(tun); @@ -683,7 +690,7 @@ static ssize_t tun_chr_aio_write(struct kiocb *iocb, const struct iovec *iv, /* Put packet to the user space buffer */ static __inline__ ssize_t tun_put_user(struct tun_struct *tun, struct sk_buff *skb, - struct iovec *iv, int len) + const struct iovec *iv, int len) { struct tun_pi pi = { 0, skb->protocol }; ssize_t total = 0; @@ -697,7 +704,7 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun, pi.flags |= TUN_PKT_STRIP; } - if (memcpy_toiovec(iv, (void *) &pi, sizeof(pi))) + if (memcpy_toiovecend(iv, (void *) &pi, 0, sizeof(pi))) return -EFAULT; total += sizeof(pi); } @@ -730,14 +737,15 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun, gso.csum_offset = skb->csum_offset; } /* else everything is zero */ - if (unlikely(memcpy_toiovec(iv, (void *)&gso, sizeof(gso)))) + if (unlikely(memcpy_toiovecend(iv, (void *)&gso, total, + sizeof(gso)))) return -EFAULT; total += sizeof(gso); } len = min_t(int, skb->len, len); - skb_copy_datagram_iovec(skb, 0, iv, len); + skb_copy_datagram_const_iovec(skb, 0, iv, total, len); total += len; tun->dev->stats.tx_packets++; @@ -792,7 +800,7 @@ static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv, } netif_wake_queue(tun->dev); - ret = tun_put_user(tun, skb, (struct iovec *) iv, len); + ret = tun_put_user(tun, skb, iv, len); kfree_skb(skb); break; } @@ -840,12 +848,12 @@ static void tun_sock_write_space(struct sock *sk) if (!sock_writeable(sk)) return; - if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) - wake_up_interruptible_sync(sk->sk_sleep); - if (!test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags)) return; + if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) + wake_up_interruptible_sync(sk->sk_sleep); + tun = container_of(sk, struct tun_sock, sk)->tun; kill_fasync(&tun->fasync, SIGIO, POLL_OUT); } @@ -861,6 +869,52 @@ static struct proto tun_proto = { .obj_size = sizeof(struct tun_sock), }; +static int tun_flags(struct tun_struct *tun) +{ + int flags = 0; + + if (tun->flags & TUN_TUN_DEV) + flags |= IFF_TUN; + else + flags |= IFF_TAP; + + if (tun->flags & TUN_NO_PI) + flags |= IFF_NO_PI; + + if (tun->flags & TUN_ONE_QUEUE) + flags |= IFF_ONE_QUEUE; + + if (tun->flags & TUN_VNET_HDR) + flags |= IFF_VNET_HDR; + + return flags; +} + +static ssize_t tun_show_flags(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct tun_struct *tun = netdev_priv(to_net_dev(dev)); + return sprintf(buf, "0x%x\n", tun_flags(tun)); +} + +static ssize_t tun_show_owner(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct tun_struct *tun = netdev_priv(to_net_dev(dev)); + return sprintf(buf, "%d\n", tun->owner); +} + +static ssize_t tun_show_group(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct tun_struct *tun = netdev_priv(to_net_dev(dev)); + return sprintf(buf, "%d\n", tun->group); +} + +static DEVICE_ATTR(tun_flags, 0444, tun_show_flags, NULL); +static DEVICE_ATTR(owner, 0444, tun_show_owner, NULL); +static DEVICE_ATTR(group, 0444, tun_show_group, NULL); + static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) { struct sock *sk; @@ -870,6 +924,8 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) dev = __dev_get_by_name(net, ifr->ifr_name); if (dev) { + if (ifr->ifr_flags & IFF_TUN_EXCL) + return -EBUSY; if ((ifr->ifr_flags & IFF_TUN) && dev->netdev_ops == &tun_netdev_ops) tun = netdev_priv(dev); else if ((ifr->ifr_flags & IFF_TAP) && dev->netdev_ops == &tap_netdev_ops) @@ -944,6 +1000,11 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) if (err < 0) goto err_free_sk; + if (device_create_file(&tun->dev->dev, &dev_attr_tun_flags) || + device_create_file(&tun->dev->dev, &dev_attr_owner) || + device_create_file(&tun->dev->dev, &dev_attr_group)) + printk(KERN_ERR "Failed to create tun sysfs files\n"); + sk->sk_destruct = tun_sock_destruct; err = tun_attach(tun, file); @@ -996,21 +1057,7 @@ static int tun_get_iff(struct net *net, struct file *file, struct ifreq *ifr) strcpy(ifr->ifr_name, tun->dev->name); - ifr->ifr_flags = 0; - - if (ifr->ifr_flags & TUN_TUN_DEV) - ifr->ifr_flags |= IFF_TUN; - else - ifr->ifr_flags |= IFF_TAP; - - if (tun->flags & TUN_NO_PI) - ifr->ifr_flags |= IFF_NO_PI; - - if (tun->flags & TUN_ONE_QUEUE) - ifr->ifr_flags |= IFF_ONE_QUEUE; - - if (tun->flags & TUN_VNET_HDR) - ifr->ifr_flags |= IFF_VNET_HDR; + ifr->ifr_flags = tun_flags(tun); tun_put(tun); return 0; @@ -1275,21 +1322,22 @@ static int tun_chr_open(struct inode *inode, struct file * file) static int tun_chr_close(struct inode *inode, struct file *file) { struct tun_file *tfile = file->private_data; - struct tun_struct *tun = __tun_get(tfile); + struct tun_struct *tun; + rtnl_lock(); + tun = __tun_get(tfile); if (tun) { DBG(KERN_INFO "%s: tun_chr_close\n", tun->dev->name); - rtnl_lock(); __tun_detach(tun); /* If desireable, unregister the netdevice. */ if (!(tun->flags & TUN_PERSIST)) unregister_netdevice(tun->dev); - rtnl_unlock(); } + rtnl_unlock(); tun = tfile->tun; if (tun) @@ -1318,6 +1366,7 @@ static const struct file_operations tun_fops = { static struct miscdevice tun_miscdev = { .minor = TUN_MINOR, .name = "tun", + .devnode = "net/tun", .fops = &tun_fops, }; diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index 44f8392da117..40c6eba775ce 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2007 Freescale Semicondutor, Inc. All rights reserved. + * Copyright (C) 2006-2009 Freescale Semicondutor, Inc. All rights reserved. * * Author: Shlomi Gridish * Li Yang @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -270,7 +271,7 @@ static int fill_init_enet_entries(struct ucc_geth_private *ugeth, u8 num_entries, u32 thread_size, u32 thread_alignment, - enum qe_risc_allocation risc, + unsigned int risc, int skip_page_for_first_entry) { u32 init_enet_offset; @@ -307,7 +308,7 @@ static int fill_init_enet_entries(struct ucc_geth_private *ugeth, static int return_init_enet_entries(struct ucc_geth_private *ugeth, u32 *p_start, u8 num_entries, - enum qe_risc_allocation risc, + unsigned int risc, int skip_page_for_first_entry) { u32 init_enet_offset; @@ -342,7 +343,7 @@ static int dump_init_enet_entries(struct ucc_geth_private *ugeth, u32 __iomem *p_start, u8 num_entries, u32 thread_size, - enum qe_risc_allocation risc, + unsigned int risc, int skip_page_for_first_entry) { u32 init_enet_offset; @@ -1409,6 +1410,9 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth) (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) { upsmr |= UCC_GETH_UPSMR_TBIM; } + if ((ugeth->phy_interface == PHY_INTERFACE_MODE_SGMII)) + upsmr |= UCC_GETH_UPSMR_SGMM; + out_be32(&uf_regs->upsmr, upsmr); /* Disable autonegotiation in tbi mode, because by default it @@ -1530,6 +1534,49 @@ static void adjust_link(struct net_device *dev) spin_unlock_irqrestore(&ugeth->lock, flags); } +/* Initialize TBI PHY interface for communicating with the + * SERDES lynx PHY on the chip. We communicate with this PHY + * through the MDIO bus on each controller, treating it as a + * "normal" PHY at the address found in the UTBIPA register. We assume + * that the UTBIPA register is valid. Either the MDIO bus code will set + * it to a value that doesn't conflict with other PHYs on the bus, or the + * value doesn't matter, as there are no other PHYs on the bus. + */ +static void uec_configure_serdes(struct net_device *dev) +{ + struct ucc_geth_private *ugeth = netdev_priv(dev); + struct ucc_geth_info *ug_info = ugeth->ug_info; + struct phy_device *tbiphy; + + if (!ug_info->tbi_node) { + dev_warn(&dev->dev, "SGMII mode requires that the device " + "tree specify a tbi-handle\n"); + return; + } + + tbiphy = of_phy_find_device(ug_info->tbi_node); + if (!tbiphy) { + dev_err(&dev->dev, "error: Could not get TBI device\n"); + return; + } + + /* + * If the link is already up, we must already be ok, and don't need to + * configure and reset the TBI<->SerDes link. Maybe U-Boot configured + * everything for us? Resetting it takes the link down and requires + * several seconds for it to come back. + */ + if (phy_read(tbiphy, ENET_TBI_MII_SR) & TBISR_LSTATUS) + return; + + /* Single clk mode, mii mode off(for serdes communication) */ + phy_write(tbiphy, ENET_TBI_MII_ANA, TBIANA_SETTINGS); + + phy_write(tbiphy, ENET_TBI_MII_TBICON, TBICON_CLK_SELECT); + + phy_write(tbiphy, ENET_TBI_MII_CR, TBICR_SETTINGS); +} + /* Configure the PHY for dev. * returns 0 if success. -1 if failure */ @@ -1543,14 +1590,19 @@ static int init_phy(struct net_device *dev) priv->oldspeed = 0; priv->oldduplex = -1; - phydev = phy_connect(dev, ug_info->phy_bus_id, &adjust_link, 0, - priv->phy_interface); + if (!ug_info->phy_node) + return 0; - if (IS_ERR(phydev)) { + phydev = of_phy_connect(dev, ug_info->phy_node, &adjust_link, 0, + priv->phy_interface); + if (!phydev) { printk("%s: Could not attach to PHY\n", dev->name); - return PTR_ERR(phydev); + return -ENODEV; } + if (priv->phy_interface == PHY_INTERFACE_MODE_SGMII) + uec_configure_serdes(dev); + phydev->supported &= (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Half | @@ -2135,6 +2187,14 @@ static int ucc_struct_init(struct ucc_geth_private *ugeth) return -ENOMEM; } + /* read the number of risc engines, update the riscTx and riscRx + * if there are 4 riscs in QE + */ + if (qe_get_num_of_risc() == 4) { + ug_info->riscTx = QE_RISC_ALLOCATION_FOUR_RISCS; + ug_info->riscRx = QE_RISC_ALLOCATION_FOUR_RISCS; + } + ugeth->ug_regs = ioremap(uf_info->regs, sizeof(*ugeth->ug_regs)); if (!ugeth->ug_regs) { if (netif_msg_probe(ugeth)) @@ -3217,7 +3277,7 @@ static int ucc_geth_tx(struct net_device *dev, u8 txQ) dev->stats.tx_packets++; /* Free the sk buffer associated with this TxBD */ - dev_kfree_skb_irq(ugeth-> + dev_kfree_skb(ugeth-> tx_skbuff[txQ][ugeth->skb_dirtytx[txQ]]); ugeth->tx_skbuff[txQ][ugeth->skb_dirtytx[txQ]] = NULL; ugeth->skb_dirtytx[txQ] = @@ -3251,9 +3311,15 @@ static int ucc_geth_poll(struct napi_struct *napi, int budget) for (i = 0; i < ug_info->numQueuesRx; i++) howmany += ucc_geth_rx(ugeth, i, budget - howmany); + /* Tx event processing */ + spin_lock(&ugeth->lock); + for (i = 0; i < ug_info->numQueuesTx; i++) + ucc_geth_tx(ugeth->ndev, i); + spin_unlock(&ugeth->lock); + if (howmany < budget) { napi_complete(napi); - setbits32(ugeth->uccf->p_uccm, UCCE_RX_EVENTS); + setbits32(ugeth->uccf->p_uccm, UCCE_RX_EVENTS | UCCE_TX_EVENTS); } return howmany; @@ -3267,8 +3333,6 @@ static irqreturn_t ucc_geth_irq_handler(int irq, void *info) struct ucc_geth_info *ug_info; register u32 ucce; register u32 uccm; - register u32 tx_mask; - u8 i; ugeth_vdbg("%s: IN", __func__); @@ -3282,27 +3346,14 @@ static irqreturn_t ucc_geth_irq_handler(int irq, void *info) out_be32(uccf->p_ucce, ucce); /* check for receive events that require processing */ - if (ucce & UCCE_RX_EVENTS) { + if (ucce & (UCCE_RX_EVENTS | UCCE_TX_EVENTS)) { if (napi_schedule_prep(&ugeth->napi)) { - uccm &= ~UCCE_RX_EVENTS; + uccm &= ~(UCCE_RX_EVENTS | UCCE_TX_EVENTS); out_be32(uccf->p_uccm, uccm); __napi_schedule(&ugeth->napi); } } - /* Tx event processing */ - if (ucce & UCCE_TX_EVENTS) { - spin_lock(&ugeth->lock); - tx_mask = UCC_GETH_UCCE_TXB0; - for (i = 0; i < ug_info->numQueuesTx; i++) { - if (ucce & tx_mask) - ucc_geth_tx(dev, i); - ucce &= ~tx_mask; - tx_mask <<= 1; - } - spin_unlock(&ugeth->lock); - } - /* Errors and other events */ if (ucce & UCCE_OTHER) { if (ucce & UCC_GETH_UCCE_BSY) @@ -3331,6 +3382,37 @@ static void ucc_netpoll(struct net_device *dev) } #endif /* CONFIG_NET_POLL_CONTROLLER */ +static int ucc_geth_set_mac_addr(struct net_device *dev, void *p) +{ + struct ucc_geth_private *ugeth = netdev_priv(dev); + struct sockaddr *addr = p; + + if (!is_valid_ether_addr(addr->sa_data)) + return -EADDRNOTAVAIL; + + memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); + + /* + * If device is not running, we will set mac addr register + * when opening the device. + */ + if (!netif_running(dev)) + return 0; + + spin_lock_irq(&ugeth->lock); + init_mac_station_addr_regs(dev->dev_addr[0], + dev->dev_addr[1], + dev->dev_addr[2], + dev->dev_addr[3], + dev->dev_addr[4], + dev->dev_addr[5], + &ugeth->ug_regs->macstnaddr1, + &ugeth->ug_regs->macstnaddr2); + spin_unlock_irq(&ugeth->lock); + + return 0; +} + /* Called when something needs to use the ethernet device */ /* Returns 0 for success. */ static int ucc_geth_open(struct net_device *dev) @@ -3498,6 +3580,8 @@ static phy_interface_t to_phy_interface(const char *phy_connection_type) return PHY_INTERFACE_MODE_RGMII_RXID; if (strcasecmp(phy_connection_type, "rtbi") == 0) return PHY_INTERFACE_MODE_RTBI; + if (strcasecmp(phy_connection_type, "sgmii") == 0) + return PHY_INTERFACE_MODE_SGMII; return PHY_INTERFACE_MODE_MII; } @@ -3507,7 +3591,7 @@ static const struct net_device_ops ucc_geth_netdev_ops = { .ndo_stop = ucc_geth_close, .ndo_start_xmit = ucc_geth_start_xmit, .ndo_validate_addr = eth_validate_addr, - .ndo_set_mac_address = eth_mac_addr, + .ndo_set_mac_address = ucc_geth_set_mac_addr, .ndo_change_mtu = eth_change_mtu, .ndo_set_multicast_list = ucc_geth_set_multi, .ndo_tx_timeout = ucc_geth_timeout, @@ -3520,14 +3604,12 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma { struct device *device = &ofdev->dev; struct device_node *np = ofdev->node; - struct device_node *mdio; struct net_device *dev = NULL; struct ucc_geth_private *ugeth = NULL; struct ucc_geth_info *ug_info; struct resource res; struct device_node *phy; int err, ucc_num, max_speed = 0; - const phandle *ph; const u32 *fixed_link; const unsigned int *prop; const char *sprop; @@ -3544,6 +3626,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma PHY_INTERFACE_MODE_RMII, PHY_INTERFACE_MODE_RGMII, PHY_INTERFACE_MODE_GMII, PHY_INTERFACE_MODE_RGMII, PHY_INTERFACE_MODE_TBI, PHY_INTERFACE_MODE_RTBI, + PHY_INTERFACE_MODE_SGMII, }; ugeth_vdbg("%s: IN", __func__); @@ -3627,40 +3710,16 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma ug_info->uf_info.irq = irq_of_parse_and_map(np, 0); fixed_link = of_get_property(np, "fixed-link", NULL); if (fixed_link) { - snprintf(ug_info->phy_bus_id, sizeof(ug_info->phy_bus_id), - PHY_ID_FMT, "0", fixed_link[0]); phy = NULL; } else { - char bus_name[MII_BUS_ID_SIZE]; - - ph = of_get_property(np, "phy-handle", NULL); - phy = of_find_node_by_phandle(*ph); - + phy = of_parse_phandle(np, "phy-handle", 0); if (phy == NULL) return -ENODEV; - - /* set the PHY address */ - prop = of_get_property(phy, "reg", NULL); - if (prop == NULL) - return -1; - - /* Set the bus id */ - mdio = of_get_parent(phy); - - if (mdio == NULL) - return -ENODEV; - - err = of_address_to_resource(mdio, 0, &res); - - if (err) { - of_node_put(mdio); - return err; - } - fsl_pq_mdio_bus_name(bus_name, mdio); - of_node_put(mdio); - snprintf(ug_info->phy_bus_id, sizeof(ug_info->phy_bus_id), - "%s:%02x", bus_name, *prop); } + ug_info->phy_node = phy; + + /* Find the TBI PHY node. If it's not there, we don't support SGMII */ + ug_info->tbi_node = of_parse_phandle(np, "tbi-handle", 0); /* get the phy interface type, or default to MII */ prop = of_get_property(np, "phy-connection-type", NULL); @@ -3686,6 +3745,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma case PHY_INTERFACE_MODE_RGMII_TXID: case PHY_INTERFACE_MODE_TBI: case PHY_INTERFACE_MODE_RTBI: + case PHY_INTERFACE_MODE_SGMII: max_speed = SPEED_1000; break; default: @@ -3702,7 +3762,15 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma ug_info->uf_info.utfet = UCC_GETH_UTFET_GIGA_INIT; ug_info->uf_info.utftt = UCC_GETH_UTFTT_GIGA_INIT; ug_info->numThreadsTx = UCC_GETH_NUM_OF_THREADS_4; - ug_info->numThreadsRx = UCC_GETH_NUM_OF_THREADS_4; + + /* If QE's snum number is 46 which means we need to support + * 4 UECs at 1000Base-T simultaneously, we need to allocate + * more Threads to Rx. + */ + if (qe_get_num_of_snums() == 46) + ug_info->numThreadsRx = UCC_GETH_NUM_OF_THREADS_6; + else + ug_info->numThreadsRx = UCC_GETH_NUM_OF_THREADS_4; } if (netif_msg_probe(&debug)) @@ -3735,7 +3803,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma dev->netdev_ops = &ucc_geth_netdev_ops; dev->watchdog_timeo = TX_TIMEOUT; INIT_WORK(&ugeth->timeout_work, ucc_geth_timeout_work); - netif_napi_add(dev, &ugeth->napi, ucc_geth_poll, UCC_GETH_DEV_WEIGHT); + netif_napi_add(dev, &ugeth->napi, ucc_geth_poll, 64); dev->mtu = 1500; ugeth->msg_enable = netif_msg_init(debug.msg_enable, UGETH_MSG_DEFAULT); diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h index 2f8ee7c87efe..195ab267ead7 100644 --- a/drivers/net/ucc_geth.h +++ b/drivers/net/ucc_geth.h @@ -1,5 +1,5 @@ /* - * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved. + * Copyright (C) Freescale Semicondutor, Inc. 2006-2009. All rights reserved. * * Author: Shlomi Gridish * @@ -193,6 +193,31 @@ struct ucc_geth { #define ENET_TBI_MII_JD 0x10 /* Jitter diagnostics */ #define ENET_TBI_MII_TBICON 0x11 /* TBI control */ +/* TBI MDIO register bit fields*/ +#define TBISR_LSTATUS 0x0004 +#define TBICON_CLK_SELECT 0x0020 +#define TBIANA_ASYMMETRIC_PAUSE 0x0100 +#define TBIANA_SYMMETRIC_PAUSE 0x0080 +#define TBIANA_HALF_DUPLEX 0x0040 +#define TBIANA_FULL_DUPLEX 0x0020 +#define TBICR_PHY_RESET 0x8000 +#define TBICR_ANEG_ENABLE 0x1000 +#define TBICR_RESTART_ANEG 0x0200 +#define TBICR_FULL_DUPLEX 0x0100 +#define TBICR_SPEED1_SET 0x0040 + +#define TBIANA_SETTINGS ( \ + TBIANA_ASYMMETRIC_PAUSE \ + | TBIANA_SYMMETRIC_PAUSE \ + | TBIANA_FULL_DUPLEX \ + ) +#define TBICR_SETTINGS ( \ + TBICR_PHY_RESET \ + | TBICR_ANEG_ENABLE \ + | TBICR_FULL_DUPLEX \ + | TBICR_SPEED1_SET \ + ) + /* UCC GETH MACCFG1 (MAC Configuration 1 Register) */ #define MACCFG1_FLOW_RX 0x00000020 /* Flow Control Rx */ @@ -852,7 +877,6 @@ struct ucc_geth_hardware_statistics { /* Driver definitions */ #define TX_BD_RING_LEN 0x10 #define RX_BD_RING_LEN 0x10 -#define UCC_GETH_DEV_WEIGHT TX_BD_RING_LEN #define TX_RING_MOD_MASK(size) (size-1) #define RX_RING_MOD_MASK(size) (size-1) @@ -1100,7 +1124,8 @@ struct ucc_geth_info { u32 eventRegMask; u16 pausePeriod; u16 extensionField; - char phy_bus_id[BUS_ID_SIZE]; + struct device_node *phy_node; + struct device_node *tbi_node; u8 weightfactor[NUM_TX_QUEUES]; u8 interruptcoalescingmaxvalue[NUM_RX_QUEUES]; u8 l2qt[UCC_GETH_VLAN_PRIORITY_MAX]; @@ -1120,8 +1145,8 @@ struct ucc_geth_info { enum ucc_geth_maccfg2_pad_and_crc_mode padAndCrc; enum ucc_geth_num_of_threads numThreadsTx; enum ucc_geth_num_of_threads numThreadsRx; - enum qe_risc_allocation riscTx; - enum qe_risc_allocation riscRx; + unsigned int riscTx; + unsigned int riscRx; }; /* structure representing UCC GETH */ diff --git a/drivers/net/ucc_geth_ethtool.c b/drivers/net/ucc_geth_ethtool.c index 6fcb500257bc..61fe80dda3e3 100644 --- a/drivers/net/ucc_geth_ethtool.c +++ b/drivers/net/ucc_geth_ethtool.c @@ -7,7 +7,7 @@ * * Limitation: * Can only get/set setttings of the first queue. - * Need to re-open the interface manually after changing some paramters. + * Need to re-open the interface manually after changing some parameters. * * 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 diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig index dfc6cf765fbd..a906d3998131 100644 --- a/drivers/net/usb/Kconfig +++ b/drivers/net/usb/Kconfig @@ -169,10 +169,12 @@ config USB_NET_CDCETHER The Linux-USB CDC Ethernet Gadget driver is an open implementation. This driver should work with at least the following devices: + * Dell Wireless 5530 HSPA * Ericsson PipeRider (all variants) + * Ericsson Mobile Broadband Module (all variants) * Motorola (DM100 and SB4100) * Broadcom Cable Modem (reference design) - * Toshiba PCX1100U + * Toshiba (PCX1100U and F3507g) * ... This driver creates an interface named "ethX", where X depends on @@ -359,4 +361,12 @@ config USB_HSO To compile this driver as a module, choose M here: the module will be called hso. +config USB_NET_INT51X1 + tristate "Intellon PLC based usb adapter" + depends on USB_USBNET + help + Choose this option if you're using a 14Mb USB-based PLC + (Powerline Communications) solution with an Intellon + INT51x1/INT5200 chip, like the "devolo dLan duo". + endmenu diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile index c8aef62cf2b7..b870b0b1cbe0 100644 --- a/drivers/net/usb/Makefile +++ b/drivers/net/usb/Makefile @@ -20,4 +20,5 @@ obj-$(CONFIG_USB_NET_CDC_SUBSET) += cdc_subset.o obj-$(CONFIG_USB_NET_ZAURUS) += zaurus.o obj-$(CONFIG_USB_NET_MCS7830) += mcs7830.o obj-$(CONFIG_USB_USBNET) += usbnet.o +obj-$(CONFIG_USB_NET_INT51X1) += int51x1.o diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c index 55e8ecc3a9e5..4a6aff579403 100644 --- a/drivers/net/usb/cdc_ether.c +++ b/drivers/net/usb/cdc_ether.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -389,36 +388,6 @@ static void cdc_status(struct usbnet *dev, struct urb *urb) } } -static u8 nibble(unsigned char c) -{ - if (likely(isdigit(c))) - return c - '0'; - c = toupper(c); - if (likely(isxdigit(c))) - return 10 + c - 'A'; - return 0; -} - -static inline int -get_ethernet_addr(struct usbnet *dev, struct usb_cdc_ether_desc *e) -{ - int tmp, i; - unsigned char buf [13]; - - tmp = usb_string(dev->udev, e->iMACAddress, buf, sizeof buf); - if (tmp != 12) { - dev_dbg(&dev->udev->dev, - "bad MAC string %d fetch, %d\n", e->iMACAddress, tmp); - if (tmp >= 0) - tmp = -EINVAL; - return tmp; - } - for (i = tmp = 0; i < 6; i++, tmp += 2) - dev->net->dev_addr [i] = - (nibble(buf [tmp]) << 4) + nibble(buf [tmp + 1]); - return 0; -} - static int cdc_bind(struct usbnet *dev, struct usb_interface *intf) { int status; @@ -428,7 +397,7 @@ static int cdc_bind(struct usbnet *dev, struct usb_interface *intf) if (status < 0) return status; - status = get_ethernet_addr(dev, info->ether); + status = usbnet_get_ethernet_addr(dev, info->ether->iMACAddress); if (status < 0) { usb_set_intfdata(info->data, NULL); usb_driver_release_interface(driver_of(intf), info->data); @@ -564,6 +533,31 @@ static const struct usb_device_id products [] = { USB_DEVICE_AND_INTERFACE_INFO(0x0bdb, 0x1900, USB_CLASS_COMM, USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE), .driver_info = (unsigned long) &cdc_info, +}, { + /* Ericsson F3507g ver. 2 */ + USB_DEVICE_AND_INTERFACE_INFO(0x0bdb, 0x1902, USB_CLASS_COMM, + USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE), + .driver_info = (unsigned long) &cdc_info, +}, { + /* Ericsson F3607gw */ + USB_DEVICE_AND_INTERFACE_INFO(0x0bdb, 0x1904, USB_CLASS_COMM, + USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE), + .driver_info = (unsigned long) &cdc_info, +}, { + /* Ericsson F3307 */ + USB_DEVICE_AND_INTERFACE_INFO(0x0bdb, 0x1906, USB_CLASS_COMM, + USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE), + .driver_info = (unsigned long) &cdc_info, +}, { + /* Toshiba F3507g */ + USB_DEVICE_AND_INTERFACE_INFO(0x0930, 0x130b, USB_CLASS_COMM, + USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE), + .driver_info = (unsigned long) &cdc_info, +}, { + /* Dell F3507g */ + USB_DEVICE_AND_INTERFACE_INFO(0x413c, 0x8147, USB_CLASS_COMM, + USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE), + .driver_info = (unsigned long) &cdc_info, }, { }, // END }; diff --git a/drivers/net/usb/cdc_subset.c b/drivers/net/usb/cdc_subset.c index c66b9c324f54..ca39ace0b0eb 100644 --- a/drivers/net/usb/cdc_subset.c +++ b/drivers/net/usb/cdc_subset.c @@ -307,9 +307,10 @@ static const struct usb_device_id products [] = { USB_DEVICE (0x1286, 0x8001), // "blob" bootloader .driver_info = (unsigned long) &blob_info, }, { - // Linux Ethernet/RNDIS gadget on pxa210/25x/26x, second config - // e.g. Gumstix, current OpenZaurus, ... - USB_DEVICE_VER (0x0525, 0xa4a2, 0x0203, 0x0203), + // Linux Ethernet/RNDIS gadget, mostly on PXA, second config + // e.g. Gumstix, current OpenZaurus, ... or anything else + // that just enables this gadget option. + USB_DEVICE (0x0525, 0xa4a2), .driver_info = (unsigned long) &linuxdev_info, }, #endif diff --git a/drivers/net/usb/dm9601.c b/drivers/net/usb/dm9601.c index 6fc4f82b0beb..7ae82446b93a 100644 --- a/drivers/net/usb/dm9601.c +++ b/drivers/net/usb/dm9601.c @@ -497,10 +497,10 @@ static int dm9601_rx_fixup(struct usbnet *dev, struct sk_buff *skb) int len; /* format: - b0: rx status - b1: packet length (incl crc) low - b2: packet length (incl crc) high - b3..n-4: packet data + b1: rx status + b2: packet length (incl crc) low + b3: packet length (incl crc) high + b4..n-4: packet data bn-3..bn: ethernet crc */ @@ -533,8 +533,8 @@ static struct sk_buff *dm9601_tx_fixup(struct usbnet *dev, struct sk_buff *skb, int len; /* format: - b0: packet length low - b1: packet length high + b1: packet length low + b2: packet length high b3..n: packet data */ diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index f84b78d94c40..f8c6d7ea7264 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -482,7 +482,7 @@ static ssize_t hso_sysfs_show_porttype(struct device *dev, struct device_attribute *attr, char *buf) { - struct hso_device *hso_dev = dev->driver_data; + struct hso_device *hso_dev = dev_get_drvdata(dev); char *port_name; if (!hso_dev) @@ -816,7 +816,7 @@ static int hso_net_start_xmit(struct sk_buff *skb, struct net_device *net) } dev_kfree_skb(skb); /* we're done */ - return result; + return NETDEV_TX_OK; } static void hso_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info) @@ -899,15 +899,14 @@ static void packetizeRx(struct hso_net *odev, unsigned char *ip_pkt, continue; } /* Allocate an sk_buff */ - odev->skb_rx_buf = dev_alloc_skb(frame_len); + odev->skb_rx_buf = netdev_alloc_skb(odev->net, + frame_len); if (!odev->skb_rx_buf) { /* We got no receive buffer. */ D1("could not allocate memory"); odev->rx_parse_state = WAIT_SYNC; return; } - /* Here's where it came from */ - odev->skb_rx_buf->dev = odev->net; /* Copy what we got so far. make room for iphdr * after tail. */ @@ -2313,7 +2312,7 @@ static int hso_serial_common_create(struct hso_serial *serial, int num_urbs, serial->parent->dev = tty_register_device(tty_drv, minor, &serial->parent->interface->dev); dev = serial->parent->dev; - dev->driver_data = serial->parent; + dev_set_drvdata(dev, serial->parent); i = device_create_file(dev, &dev_attr_hsotype); /* fill in specific data for later use */ @@ -2481,10 +2480,10 @@ static int add_net_device(struct hso_device *hso_dev) return 0; } -static int hso_radio_toggle(void *data, enum rfkill_state state) +static int hso_rfkill_set_block(void *data, bool blocked) { struct hso_device *hso_dev = data; - int enabled = (state == RFKILL_STATE_ON); + int enabled = !blocked; int rv; mutex_lock(&hso_dev->mutex); @@ -2498,6 +2497,10 @@ static int hso_radio_toggle(void *data, enum rfkill_state state) return rv; } +static const struct rfkill_ops hso_rfkill_ops = { + .set_block = hso_rfkill_set_block, +}; + /* Creates and sets up everything for rfkill */ static void hso_create_rfkill(struct hso_device *hso_dev, struct usb_interface *interface) @@ -2506,29 +2509,25 @@ static void hso_create_rfkill(struct hso_device *hso_dev, struct device *dev = &hso_net->net->dev; char *rfkn; - hso_net->rfkill = rfkill_allocate(&interface_to_usbdev(interface)->dev, - RFKILL_TYPE_WWAN); - if (!hso_net->rfkill) { - dev_err(dev, "%s - Out of memory\n", __func__); - return; - } rfkn = kzalloc(20, GFP_KERNEL); - if (!rfkn) { - rfkill_free(hso_net->rfkill); - hso_net->rfkill = NULL; + if (!rfkn) dev_err(dev, "%s - Out of memory\n", __func__); - return; - } + snprintf(rfkn, 20, "hso-%d", interface->altsetting->desc.bInterfaceNumber); - hso_net->rfkill->name = rfkn; - hso_net->rfkill->state = RFKILL_STATE_ON; - hso_net->rfkill->data = hso_dev; - hso_net->rfkill->toggle_radio = hso_radio_toggle; - if (rfkill_register(hso_net->rfkill) < 0) { + + hso_net->rfkill = rfkill_alloc(rfkn, + &interface_to_usbdev(interface)->dev, + RFKILL_TYPE_WWAN, + &hso_rfkill_ops, hso_dev); + if (!hso_net->rfkill) { + dev_err(dev, "%s - Out of memory\n", __func__); + kfree(rfkn); + return; + } + if (rfkill_register(hso_net->rfkill) < 0) { + rfkill_destroy(hso_net->rfkill); kfree(rfkn); - hso_net->rfkill->name = NULL; - rfkill_free(hso_net->rfkill); hso_net->rfkill = NULL; dev_err(dev, "%s - Failed to register rfkill\n", __func__); return; @@ -3165,8 +3164,10 @@ static void hso_free_interface(struct usb_interface *interface) hso_stop_net_device(network_table[i]); cancel_work_sync(&network_table[i]->async_put_intf); cancel_work_sync(&network_table[i]->async_get_intf); - if (rfk) + if (rfk) { rfkill_unregister(rfk); + rfkill_destroy(rfk); + } hso_free_net_device(network_table[i]); } } diff --git a/drivers/net/usb/int51x1.c b/drivers/net/usb/int51x1.c new file mode 100644 index 000000000000..55cf7081de10 --- /dev/null +++ b/drivers/net/usb/int51x1.c @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2009 Peter Holik + * + * Intellon usb PLC (Powerline Communications) usb net driver + * + * http://www.tandel.be/downloads/INT51X1_Datasheet.pdf + * + * Based on the work of Jan 'RedBully' Seiffert + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or. + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define INT51X1_VENDOR_ID 0x09e1 +#define INT51X1_PRODUCT_ID 0x5121 + +#define INT51X1_HEADER_SIZE 2 /* 2 byte header */ + +#define PACKET_TYPE_PROMISCUOUS (1 << 0) +#define PACKET_TYPE_ALL_MULTICAST (1 << 1) /* no filter */ +#define PACKET_TYPE_DIRECTED (1 << 2) +#define PACKET_TYPE_BROADCAST (1 << 3) +#define PACKET_TYPE_MULTICAST (1 << 4) /* filtered */ + +#define SET_ETHERNET_PACKET_FILTER 0x43 + +static int int51x1_rx_fixup(struct usbnet *dev, struct sk_buff *skb) +{ + int len; + + if (!(pskb_may_pull(skb, INT51X1_HEADER_SIZE))) { + deverr(dev, "unexpected tiny rx frame"); + return 0; + } + + len = le16_to_cpu(*(__le16 *)&skb->data[skb->len - 2]); + + skb_trim(skb, len); + + return 1; +} + +static struct sk_buff *int51x1_tx_fixup(struct usbnet *dev, + struct sk_buff *skb, gfp_t flags) +{ + int pack_len = skb->len; + int pack_with_header_len = pack_len + INT51X1_HEADER_SIZE; + int headroom = skb_headroom(skb); + int tailroom = skb_tailroom(skb); + int need_tail = 0; + __le16 *len; + + /* if packet and our header is smaler than 64 pad to 64 (+ ZLP) */ + if ((pack_with_header_len) < dev->maxpacket) + need_tail = dev->maxpacket - pack_with_header_len + 1; + /* + * usbnet would send a ZLP if packetlength mod urbsize == 0 for us, + * but we need to know ourself, because this would add to the length + * we send down to the device... + */ + else if (!(pack_with_header_len % dev->maxpacket)) + need_tail = 1; + + if (!skb_cloned(skb) && + (headroom + tailroom >= need_tail + INT51X1_HEADER_SIZE)) { + if (headroom < INT51X1_HEADER_SIZE || tailroom < need_tail) { + skb->data = memmove(skb->head + INT51X1_HEADER_SIZE, + skb->data, skb->len); + skb_set_tail_pointer(skb, skb->len); + } + } else { + struct sk_buff *skb2; + + skb2 = skb_copy_expand(skb, + INT51X1_HEADER_SIZE, + need_tail, + flags); + dev_kfree_skb_any(skb); + if (!skb2) + return NULL; + skb = skb2; + } + + pack_len += need_tail; + pack_len &= 0x07ff; + + len = (__le16 *) __skb_push(skb, INT51X1_HEADER_SIZE); + *len = cpu_to_le16(pack_len); + + if(need_tail) + memset(__skb_put(skb, need_tail), 0, need_tail); + + return skb; +} + +static void int51x1_async_cmd_callback(struct urb *urb) +{ + struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context; + int status = urb->status; + + if (status < 0) + dev_warn(&urb->dev->dev, "async callback failed with %d\n", status); + + kfree(req); + usb_free_urb(urb); +} + +static void int51x1_set_multicast(struct net_device *netdev) +{ + struct usb_ctrlrequest *req; + int status; + struct urb *urb; + struct usbnet *dev = netdev_priv(netdev); + u16 filter = PACKET_TYPE_DIRECTED | PACKET_TYPE_BROADCAST; + + if (netdev->flags & IFF_PROMISC) { + /* do not expect to see traffic of other PLCs */ + filter |= PACKET_TYPE_PROMISCUOUS; + devinfo(dev, "promiscuous mode enabled"); + } else if (netdev->mc_count || + (netdev->flags & IFF_ALLMULTI)) { + filter |= PACKET_TYPE_ALL_MULTICAST; + devdbg(dev, "receive all multicast enabled"); + } else { + /* ~PROMISCUOUS, ~MULTICAST */ + devdbg(dev, "receive own packets only"); + } + + urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!urb) { + devwarn(dev, "Error allocating URB"); + return; + } + + req = kmalloc(sizeof(*req), GFP_ATOMIC); + if (!req) { + devwarn(dev, "Error allocating control msg"); + goto out; + } + + req->bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE; + req->bRequest = SET_ETHERNET_PACKET_FILTER; + req->wValue = cpu_to_le16(filter); + req->wIndex = 0; + req->wLength = 0; + + usb_fill_control_urb(urb, dev->udev, usb_sndctrlpipe(dev->udev, 0), + (void *)req, NULL, 0, + int51x1_async_cmd_callback, + (void *)req); + + status = usb_submit_urb(urb, GFP_ATOMIC); + if (status < 0) { + devwarn(dev, "Error submitting control msg, sts=%d", status); + goto out1; + } + return; +out1: + kfree(req); +out: + usb_free_urb(urb); +} + +static const struct net_device_ops int51x1_netdev_ops = { + .ndo_open = usbnet_open, + .ndo_stop = usbnet_stop, + .ndo_start_xmit = usbnet_start_xmit, + .ndo_tx_timeout = usbnet_tx_timeout, + .ndo_change_mtu = usbnet_change_mtu, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_multicast_list = int51x1_set_multicast, +}; + +static int int51x1_bind(struct usbnet *dev, struct usb_interface *intf) +{ + int status = usbnet_get_ethernet_addr(dev, 3); + + if (status) + return status; + + dev->net->hard_header_len += INT51X1_HEADER_SIZE; + dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len; + dev->net->netdev_ops = &int51x1_netdev_ops; + + return usbnet_get_endpoints(dev, intf); +} + +static const struct driver_info int51x1_info = { + .description = "Intellon usb powerline adapter", + .bind = int51x1_bind, + .rx_fixup = int51x1_rx_fixup, + .tx_fixup = int51x1_tx_fixup, + .in = 1, + .out = 2, + .flags = FLAG_ETHER, +}; + +static const struct usb_device_id products[] = { + { + USB_DEVICE(INT51X1_VENDOR_ID, INT51X1_PRODUCT_ID), + .driver_info = (unsigned long) &int51x1_info, + }, + {}, +}; +MODULE_DEVICE_TABLE(usb, products); + +static struct usb_driver int51x1_driver = { + .name = "int51x1", + .id_table = products, + .probe = usbnet_probe, + .disconnect = usbnet_disconnect, + .suspend = usbnet_suspend, + .resume = usbnet_resume, +}; + +static int __init int51x1_init(void) +{ + return usb_register(&int51x1_driver); +} +module_init(int51x1_init); + +static void __exit int51x1_exit(void) +{ + usb_deregister(&int51x1_driver); +} +module_exit(int51x1_exit); + +MODULE_AUTHOR("Peter Holik"); +MODULE_DESCRIPTION("Intellon usb powerline adapter"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c index 3d0d0b0b37c5..e01314789718 100644 --- a/drivers/net/usb/kaweth.c +++ b/drivers/net/usb/kaweth.c @@ -31,7 +31,6 @@ ****************************************************************/ /* TODO: - * Fix in_interrupt() problem * Develop test procedures for USB net interfaces * Run test procedures * Fix bugs from previous two steps @@ -606,14 +605,30 @@ static void kaweth_usb_receive(struct urb *urb) struct sk_buff *skb; - if(unlikely(status == -ECONNRESET || status == -ESHUTDOWN)) - /* we are killed - set a flag and wake the disconnect handler */ - { + if (unlikely(status == -EPIPE)) { + kaweth->stats.rx_errors++; kaweth->end = 1; wake_up(&kaweth->term_wait); + dbg("Status was -EPIPE."); return; } - + if (unlikely(status == -ECONNRESET || status == -ESHUTDOWN)) { + /* we are killed - set a flag and wake the disconnect handler */ + kaweth->end = 1; + wake_up(&kaweth->term_wait); + dbg("Status was -ECONNRESET or -ESHUTDOWN."); + return; + } + if (unlikely(status == -EPROTO || status == -ETIME || + status == -EILSEQ)) { + kaweth->stats.rx_errors++; + dbg("Status was -EPROTO, -ETIME, or -EILSEQ."); + return; + } + if (unlikely(status == -EOVERFLOW)) { + kaweth->stats.rx_errors++; + dbg("Status was -EOVERFLOW."); + } spin_lock(&kaweth->device_lock); if (IS_BLOCKED(kaweth->status)) { spin_unlock(&kaweth->device_lock); @@ -883,13 +898,16 @@ static void kaweth_set_rx_mode(struct net_device *net) ****************************************************************/ static void kaweth_async_set_rx_mode(struct kaweth_device *kaweth) { + int result; __u16 packet_filter_bitmap = kaweth->packet_filter_bitmap; + kaweth->packet_filter_bitmap = 0; if (packet_filter_bitmap == 0) return; - { - int result; + if (in_interrupt()) + return; + result = kaweth_control(kaweth, usb_sndctrlpipe(kaweth->dev, 0), KAWETH_COMMAND_SET_PACKET_FILTER, @@ -906,7 +924,6 @@ static void kaweth_async_set_rx_mode(struct kaweth_device *kaweth) else { dbg("Set Rx mode to %d", packet_filter_bitmap); } - } } /**************************************************************** diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c index 2138535f2339..73acbd244aa1 100644 --- a/drivers/net/usb/pegasus.c +++ b/drivers/net/usb/pegasus.c @@ -297,7 +297,7 @@ static int update_eth_regs_async(pegasus_t * pegasus) pegasus->dr.bRequestType = PEGASUS_REQT_WRITE; pegasus->dr.bRequest = PEGASUS_REQ_SET_REGS; - pegasus->dr.wValue = 0; + pegasus->dr.wValue = cpu_to_le16(0); pegasus->dr.wIndex = cpu_to_le16(EthCtrl0); pegasus->dr.wLength = cpu_to_le16(3); pegasus->ctrl_urb->transfer_buffer_length = 3; @@ -446,11 +446,12 @@ static int write_eprom_word(pegasus_t * pegasus, __u8 index, __u16 data) int i; __u8 tmp, d[4] = { 0x3f, 0, 0, EPROM_WRITE }; int ret; + __le16 le_data = cpu_to_le16(data); set_registers(pegasus, EpromOffset, 4, d); enable_eprom_write(pegasus); set_register(pegasus, EpromOffset, index); - set_registers(pegasus, EpromData, 2, &data); + set_registers(pegasus, EpromData, 2, &le_data); set_register(pegasus, EpromCtrl, EPROM_WRITE); for (i = 0; i < REG_TIMEOUT; i++) { @@ -923,29 +924,32 @@ static struct net_device_stats *pegasus_netdev_stats(struct net_device *dev) static inline void disable_net_traffic(pegasus_t * pegasus) { - int tmp = 0; + __le16 tmp = cpu_to_le16(0); - set_registers(pegasus, EthCtrl0, 2, &tmp); + set_registers(pegasus, EthCtrl0, sizeof(tmp), &tmp); } static inline void get_interrupt_interval(pegasus_t * pegasus) { - __u8 data[2]; + u16 data; + u8 interval; - read_eprom_word(pegasus, 4, (__u16 *) data); + read_eprom_word(pegasus, 4, &data); + interval = data >> 8; if (pegasus->usb->speed != USB_SPEED_HIGH) { - if (data[1] < 0x80) { + if (interval < 0x80) { if (netif_msg_timer(pegasus)) dev_info(&pegasus->intf->dev, "intr interval " "changed from %ums to %ums\n", - data[1], 0x80); - data[1] = 0x80; + interval, 0x80); + interval = 0x80; + data = (data & 0x00FF) | ((u16)interval << 8); #ifdef PEGASUS_WRITE_EEPROM - write_eprom_word(pegasus, 4, *(__u16 *) data); + write_eprom_word(pegasus, 4, data); #endif } } - pegasus->intr_interval = data[1]; + pegasus->intr_interval = interval; } static void set_carrier(struct net_device *net) @@ -1299,7 +1303,8 @@ static int pegasus_blacklisted(struct usb_device *udev) /* Special quirk to keep the driver from handling the Belkin Bluetooth * dongle which happens to have the same ID. */ - if ((udd->idVendor == VENDOR_BELKIN && udd->idProduct == 0x0121) && + if ((udd->idVendor == cpu_to_le16(VENDOR_BELKIN)) && + (udd->idProduct == cpu_to_le16(0x0121)) && (udd->bDeviceClass == USB_CLASS_WIRELESS_CONTROLLER) && (udd->bDeviceProtocol == 1)) return 1; diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c index f9fb454ffa8b..fcc6fa0905d1 100644 --- a/drivers/net/usb/rtl8150.c +++ b/drivers/net/usb/rtl8150.c @@ -221,7 +221,8 @@ static void ctrl_callback(struct urb *urb) case -ENOENT: break; default: - dev_warn(&urb->dev->dev, "ctrl urb status %d\n", status); + if (printk_ratelimit()) + dev_warn(&urb->dev->dev, "ctrl urb status %d\n", status); } dev = urb->context; clear_bit(RX_REG_SET, &dev->flags); @@ -442,10 +443,12 @@ static void read_bulk_callback(struct urb *urb) case -ENOENT: return; /* the urb is in unlink state */ case -ETIME: - dev_warn(&urb->dev->dev, "may be reset is needed?..\n"); + if (printk_ratelimit()) + dev_warn(&urb->dev->dev, "may be reset is needed?..\n"); goto goon; default: - dev_warn(&urb->dev->dev, "Rx status %d\n", status); + if (printk_ratelimit()) + dev_warn(&urb->dev->dev, "Rx status %d\n", status); goto goon; } diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index 5a7283372b53..89a91f8c22de 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c @@ -1134,7 +1134,7 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) if (skb->len == size) { if (pdata->use_rx_csum) smsc95xx_rx_csum_offload(skb); - + skb_trim(skb, skb->len - 4); /* remove fcs */ skb->truesize = size + sizeof(struct sk_buff); return 1; @@ -1152,7 +1152,7 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) if (pdata->use_rx_csum) smsc95xx_rx_csum_offload(ax_skb); - + skb_trim(ax_skb, ax_skb->len - 4); /* remove fcs */ ax_skb->truesize = size + sizeof(struct sk_buff); usbnet_skb_return(dev, ax_skb); diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index f3a2fce6166c..22c0585a0319 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -156,6 +157,36 @@ int usbnet_get_endpoints(struct usbnet *dev, struct usb_interface *intf) } EXPORT_SYMBOL_GPL(usbnet_get_endpoints); +static u8 nibble(unsigned char c) +{ + if (likely(isdigit(c))) + return c - '0'; + c = toupper(c); + if (likely(isxdigit(c))) + return 10 + c - 'A'; + return 0; +} + +int usbnet_get_ethernet_addr(struct usbnet *dev, int iMACAddress) +{ + int tmp, i; + unsigned char buf [13]; + + tmp = usb_string(dev->udev, iMACAddress, buf, sizeof buf); + if (tmp != 12) { + dev_dbg(&dev->udev->dev, + "bad MAC string %d fetch, %d\n", iMACAddress, tmp); + if (tmp >= 0) + tmp = -EINVAL; + return tmp; + } + for (i = tmp = 0; i < 6; i++, tmp += 2) + dev->net->dev_addr [i] = + (nibble(buf [tmp]) << 4) + nibble(buf [tmp + 1]); + return 0; +} +EXPORT_SYMBOL_GPL(usbnet_get_ethernet_addr); + static void intr_complete (struct urb *urb); static int init_status (struct usbnet *dev, struct usb_interface *intf) @@ -398,7 +429,7 @@ static void rx_complete (struct urb *urb) /* stalls need manual reset. this is rare ... except that * when going through USB 2.0 TTs, unplug appears this way. - * we avoid the highspeed version of the ETIMEOUT/EILSEQ + * we avoid the highspeed version of the ETIMEDOUT/EILSEQ * storm, recovering as needed. */ case -EPIPE: @@ -1185,12 +1216,6 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) #endif net->netdev_ops = &usbnet_netdev_ops; -#ifdef CONFIG_COMPAT_NET_DEV_OPS - net->hard_start_xmit = usbnet_start_xmit; - net->open = usbnet_open; - net->stop = usbnet_stop; - net->tx_timeout = usbnet_tx_timeout; -#endif net->watchdog_timeo = TX_TIMEOUT_JIFFIES; net->ethtool_ops = &usbnet_ethtool_ops; diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 8e56fcf0a0e3..87197dd9c788 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -176,8 +176,6 @@ static int veth_xmit(struct sk_buff *skb, struct net_device *dev) if (dev->features & NETIF_F_NO_CSUM) skb->ip_summed = rcv_priv->ip_summed; - dst_release(skb->dst); - skb->dst = NULL; skb->mark = 0; secpath_reset(skb); nf_reset(skb); diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index 45daba726b66..d3489a3c4c03 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -388,7 +388,6 @@ struct rhine_private { long pioaddr; struct net_device *dev; struct napi_struct napi; - struct net_device_stats stats; spinlock_t lock; /* Frequently used values: keep some adjacent for cache effect. */ @@ -1209,7 +1208,7 @@ static void rhine_tx_timeout(struct net_device *dev) enable_irq(rp->pdev->irq); dev->trans_start = jiffies; - rp->stats.tx_errors++; + dev->stats.tx_errors++; netif_wake_queue(dev); } @@ -1237,7 +1236,7 @@ static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev) /* packet too long, drop it */ dev_kfree_skb(skb); rp->tx_skbuff[entry] = NULL; - rp->stats.tx_dropped++; + dev->stats.tx_dropped++; return 0; } @@ -1378,29 +1377,33 @@ static void rhine_tx(struct net_device *dev) printk(KERN_DEBUG "%s: Transmit error, " "Tx status %8.8x.\n", dev->name, txstatus); - rp->stats.tx_errors++; - if (txstatus & 0x0400) rp->stats.tx_carrier_errors++; - if (txstatus & 0x0200) rp->stats.tx_window_errors++; - if (txstatus & 0x0100) rp->stats.tx_aborted_errors++; - if (txstatus & 0x0080) rp->stats.tx_heartbeat_errors++; + dev->stats.tx_errors++; + if (txstatus & 0x0400) + dev->stats.tx_carrier_errors++; + if (txstatus & 0x0200) + dev->stats.tx_window_errors++; + if (txstatus & 0x0100) + dev->stats.tx_aborted_errors++; + if (txstatus & 0x0080) + dev->stats.tx_heartbeat_errors++; if (((rp->quirks & rqRhineI) && txstatus & 0x0002) || (txstatus & 0x0800) || (txstatus & 0x1000)) { - rp->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; rp->tx_ring[entry].tx_status = cpu_to_le32(DescOwn); break; /* Keep the skb - we try again */ } /* Transmitter restarted in 'abnormal' handler. */ } else { if (rp->quirks & rqRhineI) - rp->stats.collisions += (txstatus >> 3) & 0x0F; + dev->stats.collisions += (txstatus >> 3) & 0x0F; else - rp->stats.collisions += txstatus & 0x0F; + dev->stats.collisions += txstatus & 0x0F; if (debug > 6) printk(KERN_DEBUG "collisions: %1.1x:%1.1x\n", (txstatus >> 3) & 0xF, txstatus & 0xF); - rp->stats.tx_bytes += rp->tx_skbuff[entry]->len; - rp->stats.tx_packets++; + dev->stats.tx_bytes += rp->tx_skbuff[entry]->len; + dev->stats.tx_packets++; } /* Free the original skb. */ if (rp->tx_skbuff_dma[entry]) { @@ -1455,21 +1458,24 @@ static int rhine_rx(struct net_device *dev, int limit) printk(KERN_WARNING "%s: Oversized Ethernet " "frame %p vs %p.\n", dev->name, rp->rx_head_desc, &rp->rx_ring[entry]); - rp->stats.rx_length_errors++; + dev->stats.rx_length_errors++; } else if (desc_status & RxErr) { /* There was a error. */ if (debug > 2) printk(KERN_DEBUG "rhine_rx() Rx " "error was %8.8x.\n", desc_status); - rp->stats.rx_errors++; - if (desc_status & 0x0030) rp->stats.rx_length_errors++; - if (desc_status & 0x0048) rp->stats.rx_fifo_errors++; - if (desc_status & 0x0004) rp->stats.rx_frame_errors++; + dev->stats.rx_errors++; + if (desc_status & 0x0030) + dev->stats.rx_length_errors++; + if (desc_status & 0x0048) + dev->stats.rx_fifo_errors++; + if (desc_status & 0x0004) + dev->stats.rx_frame_errors++; if (desc_status & 0x0002) { /* this can also be updated outside the interrupt handler */ spin_lock(&rp->lock); - rp->stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; spin_unlock(&rp->lock); } } @@ -1513,8 +1519,8 @@ static int rhine_rx(struct net_device *dev, int limit) } skb->protocol = eth_type_trans(skb, dev); netif_receive_skb(skb); - rp->stats.rx_bytes += pkt_len; - rp->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len; + dev->stats.rx_packets++; } entry = (++rp->cur_rx) % RX_RING_SIZE; rp->rx_head_desc = &rp->rx_ring[entry]; @@ -1599,8 +1605,8 @@ static void rhine_error(struct net_device *dev, int intr_status) if (intr_status & IntrLinkChange) rhine_check_media(dev, 0); if (intr_status & IntrStatsMax) { - rp->stats.rx_crc_errors += ioread16(ioaddr + RxCRCErrs); - rp->stats.rx_missed_errors += ioread16(ioaddr + RxMissed); + dev->stats.rx_crc_errors += ioread16(ioaddr + RxCRCErrs); + dev->stats.rx_missed_errors += ioread16(ioaddr + RxMissed); clear_tally_counters(ioaddr); } if (intr_status & IntrTxAborted) { @@ -1654,12 +1660,12 @@ static struct net_device_stats *rhine_get_stats(struct net_device *dev) unsigned long flags; spin_lock_irqsave(&rp->lock, flags); - rp->stats.rx_crc_errors += ioread16(ioaddr + RxCRCErrs); - rp->stats.rx_missed_errors += ioread16(ioaddr + RxMissed); + dev->stats.rx_crc_errors += ioread16(ioaddr + RxCRCErrs); + dev->stats.rx_missed_errors += ioread16(ioaddr + RxMissed); clear_tally_counters(ioaddr); spin_unlock_irqrestore(&rp->lock, flags); - return &rp->stats; + return &dev->stats; } static void rhine_set_rx_mode(struct net_device *dev) diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index 754a4b182c1d..3ba35956327a 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -989,8 +989,10 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi if (ret < 0) goto err_iounmap; - if (velocity_get_link(dev)) + if (!velocity_get_link(dev)) { netif_carrier_off(dev); + vptr->mii_status |= VELOCITY_LINK_FAIL; + } velocity_print_info(vptr); pci_set_drvdata(pdev, dev); @@ -1385,7 +1387,7 @@ static void velocity_free_td_ring(struct velocity_info *vptr) static int velocity_rx_srv(struct velocity_info *vptr, int status) { - struct net_device_stats *stats = &vptr->stats; + struct net_device_stats *stats = &vptr->dev->stats; int rd_curr = vptr->rx.curr; int works = 0; @@ -1519,7 +1521,7 @@ static inline void velocity_iph_realign(struct velocity_info *vptr, static int velocity_receive_frame(struct velocity_info *vptr, int idx) { void (*pci_action)(struct pci_dev *, dma_addr_t, size_t, int); - struct net_device_stats *stats = &vptr->stats; + struct net_device_stats *stats = &vptr->dev->stats; struct velocity_rd_info *rd_info = &(vptr->rx.info[idx]); struct rx_desc *rd = &(vptr->rx.ring[idx]); int pkt_len = le16_to_cpu(rd->rdesc0.len) & 0x3fff; @@ -1532,7 +1534,7 @@ static int velocity_receive_frame(struct velocity_info *vptr, int idx) } if (rd->rdesc0.RSR & RSR_MAR) - vptr->stats.multicast++; + stats->multicast++; skb = rd_info->skb; @@ -1634,7 +1636,7 @@ static int velocity_tx_srv(struct velocity_info *vptr, u32 status) int idx; int works = 0; struct velocity_td_info *tdinfo; - struct net_device_stats *stats = &vptr->stats; + struct net_device_stats *stats = &vptr->dev->stats; for (qnum = 0; qnum < vptr->tx.numq; qnum++) { for (idx = vptr->tx.tail[qnum]; vptr->tx.used[qnum] > 0; @@ -1845,7 +1847,7 @@ static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_ */ if (tdinfo->skb_dma) { - pktlen = (skb->len > ETH_ZLEN ? : ETH_ZLEN); + pktlen = max_t(unsigned int, skb->len, ETH_ZLEN); for (i = 0; i < tdinfo->nskb_dma; i++) { #ifdef VELOCITY_ZERO_COPY_SUPPORT pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i], le16_to_cpu(td->tdesc1.len), PCI_DMA_TODEVICE); @@ -2324,22 +2326,22 @@ static struct net_device_stats *velocity_get_stats(struct net_device *dev) /* If the hardware is down, don't touch MII */ if(!netif_running(dev)) - return &vptr->stats; + return &dev->stats; spin_lock_irq(&vptr->lock); velocity_update_hw_mibs(vptr); spin_unlock_irq(&vptr->lock); - vptr->stats.rx_packets = vptr->mib_counter[HW_MIB_ifRxAllPkts]; - vptr->stats.rx_errors = vptr->mib_counter[HW_MIB_ifRxErrorPkts]; - vptr->stats.rx_length_errors = vptr->mib_counter[HW_MIB_ifInRangeLengthErrors]; + dev->stats.rx_packets = vptr->mib_counter[HW_MIB_ifRxAllPkts]; + dev->stats.rx_errors = vptr->mib_counter[HW_MIB_ifRxErrorPkts]; + dev->stats.rx_length_errors = vptr->mib_counter[HW_MIB_ifInRangeLengthErrors]; // unsigned long rx_dropped; /* no space in linux buffers */ - vptr->stats.collisions = vptr->mib_counter[HW_MIB_ifTxEtherCollisions]; + dev->stats.collisions = vptr->mib_counter[HW_MIB_ifTxEtherCollisions]; /* detailed rx_errors: */ // unsigned long rx_length_errors; // unsigned long rx_over_errors; /* receiver ring buff overflow */ - vptr->stats.rx_crc_errors = vptr->mib_counter[HW_MIB_ifRxPktCRCE]; + dev->stats.rx_crc_errors = vptr->mib_counter[HW_MIB_ifRxPktCRCE]; // unsigned long rx_frame_errors; /* recv'd frame alignment error */ // unsigned long rx_fifo_errors; /* recv'r fifo overrun */ // unsigned long rx_missed_errors; /* receiver missed packet */ @@ -2347,7 +2349,7 @@ static struct net_device_stats *velocity_get_stats(struct net_device *dev) /* detailed tx_errors */ // unsigned long tx_fifo_errors; - return &vptr->stats; + return &dev->stats; } diff --git a/drivers/net/via-velocity.h b/drivers/net/via-velocity.h index ea43e1832afb..4cd3f6c97379 100644 --- a/drivers/net/via-velocity.h +++ b/drivers/net/via-velocity.h @@ -1503,7 +1503,6 @@ struct velocity_info { struct pci_dev *pdev; struct net_device *dev; - struct net_device_stats stats; struct vlan_group *vlgrp; u8 ip_addr[4]; diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 4d1d47953fc6..2a6e81d5b579 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -283,10 +283,11 @@ static void try_fill_recv_maxbufs(struct virtnet_info *vi) for (;;) { struct virtio_net_hdr *hdr; - skb = netdev_alloc_skb(vi->dev, MAX_PACKET_LEN); + skb = netdev_alloc_skb(vi->dev, MAX_PACKET_LEN + NET_IP_ALIGN); if (unlikely(!skb)) break; + skb_reserve(skb, NET_IP_ALIGN); skb_put(skb, MAX_PACKET_LEN); hdr = skb_vnet_hdr(skb); @@ -470,7 +471,7 @@ static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb) } if (skb_is_gso(skb)) { - hdr->hdr_len = skb_transport_header(skb) - skb->data; + hdr->hdr_len = skb_headlen(skb); hdr->gso_size = skb_shinfo(skb)->gso_size; if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4) hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4; @@ -622,12 +623,9 @@ static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd, unsigned int tmp; int i; - if (!virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ)) { - BUG(); /* Caller should know better */ - return false; - } - - BUG_ON(out + in > VIRTNET_SEND_COMMAND_SG_MAX); + /* Caller should know better */ + BUG_ON(!virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ) || + (out + in > VIRTNET_SEND_COMMAND_SG_MAX)); out++; /* Add header */ in++; /* Add return status */ @@ -642,8 +640,7 @@ static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd, sg_set_buf(&sg[i + 1], sg_virt(s), s->length); sg_set_buf(&sg[out + in - 1], &status, sizeof(status)); - if (vi->cvq->vq_ops->add_buf(vi->cvq, sg, out, in, vi) != 0) - BUG(); + BUG_ON(vi->cvq->vq_ops->add_buf(vi->cvq, sg, out, in, vi)); vi->cvq->vq_ops->kick(vi->cvq); @@ -684,6 +681,7 @@ static void virtnet_set_rx_mode(struct net_device *dev) u8 promisc, allmulti; struct virtio_net_ctrl_mac *mac_data; struct dev_addr_list *addr; + struct netdev_hw_addr *ha; void *buf; int i; @@ -711,7 +709,7 @@ static void virtnet_set_rx_mode(struct net_device *dev) allmulti ? "en" : "dis"); /* MAC filter - use one buffer for both lists */ - mac_data = buf = kzalloc(((dev->uc_count + dev->mc_count) * ETH_ALEN) + + mac_data = buf = kzalloc(((dev->uc.count + dev->mc_count) * ETH_ALEN) + (2 * sizeof(mac_data->entries)), GFP_ATOMIC); if (!buf) { dev_warn(&dev->dev, "No memory for MAC address buffer\n"); @@ -721,16 +719,16 @@ static void virtnet_set_rx_mode(struct net_device *dev) sg_init_table(sg, 2); /* Store the unicast list and count in the front of the buffer */ - mac_data->entries = dev->uc_count; - addr = dev->uc_list; - for (i = 0; i < dev->uc_count; i++, addr = addr->next) - memcpy(&mac_data->macs[i][0], addr->da_addr, ETH_ALEN); + mac_data->entries = dev->uc.count; + i = 0; + list_for_each_entry(ha, &dev->uc.list, list) + memcpy(&mac_data->macs[i++][0], ha->addr, ETH_ALEN); sg_set_buf(&sg[0], mac_data, - sizeof(mac_data->entries) + (dev->uc_count * ETH_ALEN)); + sizeof(mac_data->entries) + (dev->uc.count * ETH_ALEN)); /* multicast list and count fill the end */ - mac_data = (void *)&mac_data->macs[dev->uc_count][0]; + mac_data = (void *)&mac_data->macs[dev->uc.count][0]; mac_data->entries = dev->mc_count; addr = dev->mc_list; @@ -845,6 +843,10 @@ static int virtnet_probe(struct virtio_device *vdev) int err; struct net_device *dev; struct virtnet_info *vi; + struct virtqueue *vqs[3]; + vq_callback_t *callbacks[] = { skb_recv_done, skb_xmit_done, NULL}; + const char *names[] = { "input", "output", "control" }; + int nvqs; /* Allocate ourselves a network device with room for our info */ dev = alloc_etherdev(sizeof(struct virtnet_info)); @@ -905,25 +907,19 @@ static int virtnet_probe(struct virtio_device *vdev) if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF)) vi->mergeable_rx_bufs = true; - /* We expect two virtqueues, receive then send. */ - vi->rvq = vdev->config->find_vq(vdev, 0, skb_recv_done); - if (IS_ERR(vi->rvq)) { - err = PTR_ERR(vi->rvq); - goto free; - } + /* We expect two virtqueues, receive then send, + * and optionally control. */ + nvqs = virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ) ? 3 : 2; - vi->svq = vdev->config->find_vq(vdev, 1, skb_xmit_done); - if (IS_ERR(vi->svq)) { - err = PTR_ERR(vi->svq); - goto free_recv; - } + err = vdev->config->find_vqs(vdev, nvqs, vqs, callbacks, names); + if (err) + goto free; + + vi->rvq = vqs[0]; + vi->svq = vqs[1]; if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ)) { - vi->cvq = vdev->config->find_vq(vdev, 2, NULL); - if (IS_ERR(vi->cvq)) { - err = PTR_ERR(vi->svq); - goto free_send; - } + vi->cvq = vqs[2]; if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VLAN)) dev->features |= NETIF_F_HW_VLAN_FILTER; @@ -941,7 +937,7 @@ static int virtnet_probe(struct virtio_device *vdev) err = register_netdev(dev); if (err) { pr_debug("virtio_net: registering device failed\n"); - goto free_ctrl; + goto free_vqs; } /* Last of all, set up some receive buffers. */ @@ -962,13 +958,8 @@ static int virtnet_probe(struct virtio_device *vdev) unregister: unregister_netdev(dev); -free_ctrl: - if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ)) - vdev->config->del_vq(vi->cvq); -free_send: - vdev->config->del_vq(vi->svq); -free_recv: - vdev->config->del_vq(vi->rvq); +free_vqs: + vdev->config->del_vqs(vdev); free: free_netdev(dev); return err; @@ -994,12 +985,10 @@ static void virtnet_remove(struct virtio_device *vdev) BUG_ON(vi->num != 0); - vdev->config->del_vq(vi->svq); - vdev->config->del_vq(vi->rvq); - if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ)) - vdev->config->del_vq(vi->cvq); unregister_netdev(vi->dev); + vdev->config->del_vqs(vi->vdev); + while (vi->pages) __free_pages(get_a_page(vi, GFP_KERNEL), 0); diff --git a/drivers/net/vxge/vxge-config.c b/drivers/net/vxge/vxge-config.c index 6b41c884a337..58d2551c78ed 100644 --- a/drivers/net/vxge/vxge-config.c +++ b/drivers/net/vxge/vxge-config.c @@ -454,7 +454,7 @@ __vxge_hw_verify_pci_e_info(struct __vxge_hw_device *hldev) return VXGE_HW_OK; } -static enum vxge_hw_status +enum vxge_hw_status __vxge_hw_device_is_privilaged(struct __vxge_hw_device *hldev) { if ((hldev->host_type == VXGE_HW_NO_MR_NO_SR_NORMAL_FUNCTION || @@ -676,10 +676,12 @@ enum vxge_hw_status __vxge_hw_device_initialize(struct __vxge_hw_device *hldev) { enum vxge_hw_status status = VXGE_HW_OK; - /* Validate the pci-e link width and speed */ - status = __vxge_hw_verify_pci_e_info(hldev); - if (status != VXGE_HW_OK) - goto exit; + if (VXGE_HW_OK == __vxge_hw_device_is_privilaged(hldev)) { + /* Validate the pci-e link width and speed */ + status = __vxge_hw_verify_pci_e_info(hldev); + if (status != VXGE_HW_OK) + goto exit; + } vxge_hw_wrr_rebalance(hldev); exit: @@ -1884,17 +1886,13 @@ void __vxge_hw_mempool_destroy(struct vxge_hw_mempool *mempool) mempool->memblock_size, dma_object); } - if (mempool->items_arr) - vfree(mempool->items_arr); + vfree(mempool->items_arr); - if (mempool->memblocks_dma_arr) - vfree(mempool->memblocks_dma_arr); + vfree(mempool->memblocks_dma_arr); - if (mempool->memblocks_priv_arr) - vfree(mempool->memblocks_priv_arr); + vfree(mempool->memblocks_priv_arr); - if (mempool->memblocks_arr) - vfree(mempool->memblocks_arr); + vfree(mempool->memblocks_arr); vfree(mempool); } diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index b7f08f3e524b..6034497536a4 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -677,7 +677,7 @@ vxge_xmit_compl(struct __vxge_hw_fifo *fifo_hw, void *dtr, return VXGE_HW_OK; } -/* select a vpath to trasmit the packet */ +/* select a vpath to transmit the packet */ static u32 vxge_get_vpath_no(struct vxgedev *vdev, struct sk_buff *skb, int *do_lock) { @@ -992,7 +992,9 @@ vxge_xmit(struct sk_buff *skb, struct net_device *dev) VXGE_HW_FIFO_TXD_TX_CKO_UDP_EN); vxge_hw_fifo_txdl_post(fifo_hw, dtr); - dev->trans_start = jiffies; +#ifdef NETIF_F_LLTX + dev->trans_start = jiffies; /* NETIF_F_LLTX driver :( */ +#endif spin_unlock_irqrestore(&fifo->tx_lock, flags); VXGE_COMPLETE_VPATH_TX(fifo); @@ -4201,6 +4203,16 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) max_vpath_supported++; } + /* Enable SRIOV mode, if firmware has SRIOV support and if it is a PF */ + if ((VXGE_HW_FUNCTION_MODE_SRIOV == + ll_config.device_hw_info.function_mode) && + (max_config_dev > 1) && (pdev->is_physfn)) { + ret = pci_enable_sriov(pdev, max_config_dev - 1); + if (ret) + vxge_debug_ll_config(VXGE_ERR, + "Failed to enable SRIOV: %d \n", ret); + } + /* * Configure vpaths and get driver configured number of vpaths * which is less than or equal to the maximum vpaths per function. @@ -4364,6 +4376,7 @@ _exit6: vxge_device_unregister(hldev); _exit5: + pci_disable_sriov(pdev); vxge_hw_device_terminate(hldev); _exit4: iounmap(attr.bar1); @@ -4427,6 +4440,8 @@ vxge_remove(struct pci_dev *pdev) iounmap(vdev->bar0); iounmap(vdev->bar1); + pci_disable_sriov(pdev); + /* we are safe to free it now */ free_netdev(dev); diff --git a/drivers/net/vxge/vxge-traffic.c b/drivers/net/vxge/vxge-traffic.c index c2eeac4125f3..370f55cbbad7 100644 --- a/drivers/net/vxge/vxge-traffic.c +++ b/drivers/net/vxge/vxge-traffic.c @@ -1923,7 +1923,7 @@ enum vxge_hw_status __vxge_hw_vpath_alarm_process( if (vpath == NULL) { alarm_event = VXGE_HW_SET_LEVEL(VXGE_HW_EVENT_UNKNOWN, alarm_event); - goto out; + goto out2; } hldev = vpath->hldev; @@ -2161,7 +2161,7 @@ enum vxge_hw_status __vxge_hw_vpath_alarm_process( } out: hldev->stats.sw_dev_err_stats.vpath_alarms++; - +out2: if ((alarm_event == VXGE_HW_EVENT_ALARM_CLEARED) || (alarm_event == VXGE_HW_EVENT_UNKNOWN)) return VXGE_HW_OK; diff --git a/drivers/net/vxge/vxge-version.h b/drivers/net/vxge/vxge-version.h index 7da02c545ed5..82786ffb7dd9 100644 --- a/drivers/net/vxge/vxge-version.h +++ b/drivers/net/vxge/vxge-version.h @@ -17,7 +17,7 @@ #define VXGE_VERSION_MAJOR "2" #define VXGE_VERSION_MINOR "0" -#define VXGE_VERSION_FIX "1" -#define VXGE_VERSION_BUILD "17129" +#define VXGE_VERSION_FIX "4" +#define VXGE_VERSION_BUILD "17795" #define VXGE_VERSION_FOR "k" #endif diff --git a/drivers/net/wan/cycx_x25.c b/drivers/net/wan/cycx_x25.c index 35dea3bea95d..f525f9fe74db 100644 --- a/drivers/net/wan/cycx_x25.c +++ b/drivers/net/wan/cycx_x25.c @@ -615,7 +615,7 @@ static int cycx_netdevice_hard_start_xmit(struct sk_buff *skb, case WAN_DISCONNECTED: if (cycx_x25_chan_connect(dev)) { netif_stop_queue(dev); - return -EBUSY; + return NETDEV_TX_BUSY; } /* fall thru */ case WAN_CONNECTED: @@ -624,7 +624,7 @@ static int cycx_netdevice_hard_start_xmit(struct sk_buff *skb, netif_stop_queue(dev); if (cycx_x25_chan_send(dev, skb)) - return -EBUSY; + return NETDEV_TX_BUSY; break; default: @@ -656,7 +656,7 @@ static int cycx_netdevice_hard_start_xmit(struct sk_buff *skb, if (cycx_x25_chan_send(dev, skb)) { /* prepare for future retransmissions */ skb_push(skb, 1); - return -EBUSY; + return NETDEV_TX_BUSY; } } diff --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c index e8d155c3e59f..2fa275a58f9d 100644 --- a/drivers/net/wan/dlci.c +++ b/drivers/net/wan/dlci.c @@ -205,15 +205,15 @@ static int dlci_transmit(struct sk_buff *skb, struct net_device *dev) { case DLCI_RET_OK: dev->stats.tx_packets++; - ret = 0; + ret = NETDEV_TX_OK; break; case DLCI_RET_ERR: dev->stats.tx_errors++; - ret = 0; + ret = NETDEV_TX_OK; break; case DLCI_RET_DROP: dev->stats.tx_dropped++; - ret = 1; + ret = NETDEV_TX_BUSY; break; } /* Alan Cox recommends always returning 0, and always freeing the packet */ diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c index 800530101093..bfa0161a02d3 100644 --- a/drivers/net/wan/hdlc_fr.c +++ b/drivers/net/wan/hdlc_fr.c @@ -1054,6 +1054,7 @@ static void pvc_setup(struct net_device *dev) dev->flags = IFF_POINTOPOINT; dev->hard_header_len = 10; dev->addr_len = 2; + dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; } static const struct net_device_ops pvc_ops = { diff --git a/drivers/net/wan/ixp4xx_hss.c b/drivers/net/wan/ixp4xx_hss.c index 765a7f5d6aa4..bb719b6114cb 100644 --- a/drivers/net/wan/ixp4xx_hss.c +++ b/drivers/net/wan/ixp4xx_hss.c @@ -579,7 +579,8 @@ static inline void queue_put_desc(unsigned int queue, u32 phys, debug_desc(phys, desc); BUG_ON(phys & 0x1F); qmgr_put_entry(queue, phys); - BUG_ON(qmgr_stat_overflow(queue)); + /* Don't check for queue overflow here, we've allocated sufficient + length and queues >= 32 don't support this check anyway. */ } @@ -731,8 +732,8 @@ static int hss_hdlc_poll(struct napi_struct *napi, int budget) dma_unmap_single(&dev->dev, desc->data, RX_SIZE, DMA_FROM_DEVICE); #else - dma_sync_single(&dev->dev, desc->data, - RX_SIZE, DMA_FROM_DEVICE); + dma_sync_single_for_cpu(&dev->dev, desc->data, + RX_SIZE, DMA_FROM_DEVICE); memcpy_swab32((u32 *)skb->data, (u32 *)port->rx_buff_tab[n], ALIGN(desc->pkt_len, 4) / 4); #endif @@ -789,10 +790,10 @@ static void hss_hdlc_txdone_irq(void *pdev) free_buffer_irq(port->tx_buff_tab[n_desc]); port->tx_buff_tab[n_desc] = NULL; - start = qmgr_stat_empty(port->plat->txreadyq); + start = qmgr_stat_below_low_watermark(port->plat->txreadyq); queue_put_desc(port->plat->txreadyq, tx_desc_phys(port, n_desc), desc); - if (start) { + if (start) { /* TX-ready queue was empty */ #if DEBUG_TX printk(KERN_DEBUG "%s: hss_hdlc_txdone_irq xmit" " ready\n", dev->name); @@ -867,13 +868,13 @@ static int hss_hdlc_xmit(struct sk_buff *skb, struct net_device *dev) queue_put_desc(queue_ids[port->id].tx, tx_desc_phys(port, n), desc); dev->trans_start = jiffies; - if (qmgr_stat_empty(txreadyq)) { + if (qmgr_stat_below_low_watermark(txreadyq)) { /* empty */ #if DEBUG_TX printk(KERN_DEBUG "%s: hss_hdlc_xmit queue full\n", dev->name); #endif netif_stop_queue(dev); /* we could miss TX ready interrupt */ - if (!qmgr_stat_empty(txreadyq)) { + if (!qmgr_stat_below_low_watermark(txreadyq)) { #if DEBUG_TX printk(KERN_DEBUG "%s: hss_hdlc_xmit ready again\n", dev->name); diff --git a/drivers/net/wan/lapbether.c b/drivers/net/wan/lapbether.c index 2dd78d20eb05..aff4f6bdf3d5 100644 --- a/drivers/net/wan/lapbether.c +++ b/drivers/net/wan/lapbether.c @@ -149,46 +149,40 @@ static int lapbeth_data_indication(struct net_device *dev, struct sk_buff *skb) */ static int lapbeth_xmit(struct sk_buff *skb, struct net_device *dev) { - int err = -ENODEV; + int err; /* * Just to be *really* sure not to send anything if the interface * is down, the ethernet device may have gone. */ - if (!netif_running(dev)) { + if (!netif_running(dev)) goto drop; - } switch (skb->data[0]) { case 0x00: - err = 0; break; case 0x01: if ((err = lapb_connect_request(dev)) != LAPB_OK) printk(KERN_ERR "lapbeth: lapb_connect_request " "error: %d\n", err); - goto drop_ok; + goto drop; case 0x02: if ((err = lapb_disconnect_request(dev)) != LAPB_OK) printk(KERN_ERR "lapbeth: lapb_disconnect_request " "err: %d\n", err); /* Fall thru */ default: - goto drop_ok; + goto drop; } skb_pull(skb, 1); if ((err = lapb_data_request(dev, skb)) != LAPB_OK) { printk(KERN_ERR "lapbeth: lapb_data_request error - %d\n", err); - err = -ENOMEM; goto drop; } - err = 0; out: - return err; -drop_ok: - err = 0; + return NETDEV_TX_OK; drop: kfree_skb(skb); goto out; diff --git a/drivers/net/wan/pc300_drv.c b/drivers/net/wan/pc300_drv.c index c23fde0c0344..79dabc557bd3 100644 --- a/drivers/net/wan/pc300_drv.c +++ b/drivers/net/wan/pc300_drv.c @@ -225,6 +225,7 @@ static char rcsid[] = #include #include #include +#include #include #include #include @@ -3246,6 +3247,16 @@ static inline void show_version(void) rcsvers, rcsdate, __DATE__, __TIME__); } /* show_version */ +static const struct net_device_ops cpc_netdev_ops = { + .ndo_open = cpc_open, + .ndo_stop = cpc_close, + .ndo_tx_timeout = cpc_tx_timeout, + .ndo_set_mac_address = NULL, + .ndo_change_mtu = cpc_change_mtu, + .ndo_do_ioctl = cpc_ioctl, + .ndo_validate_addr = eth_validate_addr, +}; + static void cpc_init_card(pc300_t * card) { int i, devcount = 0; @@ -3357,18 +3368,11 @@ static void cpc_init_card(pc300_t * card) dev->mem_start = card->hw.ramphys; dev->mem_end = card->hw.ramphys + card->hw.ramsize - 1; dev->irq = card->hw.irq; - dev->init = NULL; dev->tx_queue_len = PC300_TX_QUEUE_LEN; dev->mtu = PC300_DEF_MTU; - dev->open = cpc_open; - dev->stop = cpc_close; - dev->tx_timeout = cpc_tx_timeout; + dev->netdev_ops = &cpc_netdev_ops; dev->watchdog_timeo = PC300_TX_TIMEOUT; - dev->set_multicast_list = NULL; - dev->set_mac_address = NULL; - dev->change_mtu = cpc_change_mtu; - dev->do_ioctl = cpc_ioctl; if (register_hdlc_device(dev) == 0) { printk("%s: Cyclades-PC300/", dev->name); diff --git a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c index f4211fe0f445..3fb9dbc88a1a 100644 --- a/drivers/net/wan/sbni.c +++ b/drivers/net/wan/sbni.c @@ -469,7 +469,7 @@ sbni_start_xmit( struct sk_buff *skb, struct net_device *dev ) } } - return 1; + return NETDEV_TX_BUSY; } #else /* CONFIG_SBNI_MULTILINE */ diff --git a/drivers/net/wan/wanxl.c b/drivers/net/wan/wanxl.c index 8130b79a8a99..e4ad7b6b52eb 100644 --- a/drivers/net/wan/wanxl.c +++ b/drivers/net/wan/wanxl.c @@ -283,7 +283,7 @@ static int wanxl_xmit(struct sk_buff *skb, struct net_device *dev) #endif netif_stop_queue(dev); spin_unlock_irq(&port->lock); - return 1; /* request packet to be queued */ + return NETDEV_TX_BUSY; /* request packet to be queued */ } #ifdef DEBUG_PKT diff --git a/drivers/net/wimax/i2400m/control.c b/drivers/net/wimax/i2400m/control.c index b3cadb626fe0..07308686dbcf 100644 --- a/drivers/net/wimax/i2400m/control.c +++ b/drivers/net/wimax/i2400m/control.c @@ -292,8 +292,6 @@ void i2400m_report_tlv_system_state(struct i2400m *i2400m, d_fnstart(3, dev, "(i2400m %p ss %p [%u])\n", i2400m, ss, i2400m_state); - if (unlikely(i2400m->ready == 0)) /* act if up */ - goto out; if (i2400m->state != i2400m_state) { i2400m->state = i2400m_state; wake_up_all(&i2400m->state_wq); @@ -341,7 +339,6 @@ void i2400m_report_tlv_system_state(struct i2400m *i2400m, i2400m->bus_reset(i2400m, I2400M_RT_WARM); break; }; -out: d_fnend(3, dev, "(i2400m %p ss %p [%u]) = void\n", i2400m, ss, i2400m_state); } @@ -372,8 +369,6 @@ void i2400m_report_tlv_media_status(struct i2400m *i2400m, d_fnstart(3, dev, "(i2400m %p ms %p [%u])\n", i2400m, ms, status); - if (unlikely(i2400m->ready == 0)) /* act if up */ - goto out; switch (status) { case I2400M_MEDIA_STATUS_LINK_UP: netif_carrier_on(net_dev); @@ -393,14 +388,59 @@ void i2400m_report_tlv_media_status(struct i2400m *i2400m, dev_err(dev, "HW BUG? unknown media status %u\n", status); }; -out: d_fnend(3, dev, "(i2400m %p ms %p [%u]) = void\n", i2400m, ms, status); } /* - * Parse a 'state report' and extract carrier on/off information + * Process a TLV from a 'state report' + * + * @i2400m: device descriptor + * @tlv: pointer to the TLV header; it has been already validated for + * consistent size. + * @tag: for error messages + * + * Act on the TLVs from a 'state report'. + */ +static +void i2400m_report_state_parse_tlv(struct i2400m *i2400m, + const struct i2400m_tlv_hdr *tlv, + const char *tag) +{ + struct device *dev = i2400m_dev(i2400m); + const struct i2400m_tlv_media_status *ms; + const struct i2400m_tlv_system_state *ss; + const struct i2400m_tlv_rf_switches_status *rfss; + + if (0 == i2400m_tlv_match(tlv, I2400M_TLV_SYSTEM_STATE, sizeof(*ss))) { + ss = container_of(tlv, typeof(*ss), hdr); + d_printf(2, dev, "%s: system state TLV " + "found (0x%04x), state 0x%08x\n", + tag, I2400M_TLV_SYSTEM_STATE, + le32_to_cpu(ss->state)); + i2400m_report_tlv_system_state(i2400m, ss); + } + if (0 == i2400m_tlv_match(tlv, I2400M_TLV_RF_STATUS, sizeof(*rfss))) { + rfss = container_of(tlv, typeof(*rfss), hdr); + d_printf(2, dev, "%s: RF status TLV " + "found (0x%04x), sw 0x%02x hw 0x%02x\n", + tag, I2400M_TLV_RF_STATUS, + le32_to_cpu(rfss->sw_rf_switch), + le32_to_cpu(rfss->hw_rf_switch)); + i2400m_report_tlv_rf_switches_status(i2400m, rfss); + } + if (0 == i2400m_tlv_match(tlv, I2400M_TLV_MEDIA_STATUS, sizeof(*ms))) { + ms = container_of(tlv, typeof(*ms), hdr); + d_printf(2, dev, "%s: Media Status TLV: %u\n", + tag, le32_to_cpu(ms->media_status)); + i2400m_report_tlv_media_status(i2400m, ms); + } +} + + +/* + * Parse a 'state report' and extract information * * @i2400m: device descriptor * @l3l4_hdr: pointer to message; it has been already validated for @@ -409,13 +449,7 @@ out: * declaration is assumed to be congruent with @size (as in * sizeof(*l3l4_hdr) + l3l4_hdr->length == size) * - * Extract from the report state the system state TLV and infer from - * there if we have a carrier or not. Update our local state and tell - * netdev. - * - * When setting the carrier, it's fine to set OFF twice (for example), - * as netif_carrier_off() will not generate two OFF events (just on - * the transitions). + * Walk over the TLVs in a report state and act on them. */ static void i2400m_report_state_hook(struct i2400m *i2400m, @@ -424,9 +458,6 @@ void i2400m_report_state_hook(struct i2400m *i2400m, { struct device *dev = i2400m_dev(i2400m); const struct i2400m_tlv_hdr *tlv; - const struct i2400m_tlv_system_state *ss; - const struct i2400m_tlv_rf_switches_status *rfss; - const struct i2400m_tlv_media_status *ms; size_t tlv_size = le16_to_cpu(l3l4_hdr->length); d_fnstart(4, dev, "(i2400m %p, l3l4_hdr %p, size %zu, %s)\n", @@ -434,34 +465,8 @@ void i2400m_report_state_hook(struct i2400m *i2400m, tlv = NULL; while ((tlv = i2400m_tlv_buffer_walk(i2400m, &l3l4_hdr->pl, - tlv_size, tlv))) { - if (0 == i2400m_tlv_match(tlv, I2400M_TLV_SYSTEM_STATE, - sizeof(*ss))) { - ss = container_of(tlv, typeof(*ss), hdr); - d_printf(2, dev, "%s: system state TLV " - "found (0x%04x), state 0x%08x\n", - tag, I2400M_TLV_SYSTEM_STATE, - le32_to_cpu(ss->state)); - i2400m_report_tlv_system_state(i2400m, ss); - } - if (0 == i2400m_tlv_match(tlv, I2400M_TLV_RF_STATUS, - sizeof(*rfss))) { - rfss = container_of(tlv, typeof(*rfss), hdr); - d_printf(2, dev, "%s: RF status TLV " - "found (0x%04x), sw 0x%02x hw 0x%02x\n", - tag, I2400M_TLV_RF_STATUS, - le32_to_cpu(rfss->sw_rf_switch), - le32_to_cpu(rfss->hw_rf_switch)); - i2400m_report_tlv_rf_switches_status(i2400m, rfss); - } - if (0 == i2400m_tlv_match(tlv, I2400M_TLV_MEDIA_STATUS, - sizeof(*ms))) { - ms = container_of(tlv, typeof(*ms), hdr); - d_printf(2, dev, "%s: Media Status TLV: %u\n", - tag, le32_to_cpu(ms->media_status)); - i2400m_report_tlv_media_status(i2400m, ms); - } - } + tlv_size, tlv))) + i2400m_report_state_parse_tlv(i2400m, tlv, tag); d_fnend(4, dev, "(i2400m %p, l3l4_hdr %p, size %zu, %s) = void\n", i2400m, l3l4_hdr, size, tag); } @@ -500,8 +505,15 @@ void i2400m_report_hook(struct i2400m *i2400m, * it. */ case I2400M_MT_REPORT_POWERSAVE_READY: /* zzzzz */ if (l3l4_hdr->status == cpu_to_le16(I2400M_MS_DONE_OK)) { - d_printf(1, dev, "ready for powersave, requesting\n"); - i2400m_cmd_enter_powersave(i2400m); + if (i2400m_power_save_disabled) + d_printf(1, dev, "ready for powersave, " + "not requesting (disabled by module " + "parameter)\n"); + else { + d_printf(1, dev, "ready for powersave, " + "requesting\n"); + i2400m_cmd_enter_powersave(i2400m); + } } break; }; @@ -683,8 +695,9 @@ struct sk_buff *i2400m_msg_to_dev(struct i2400m *i2400m, d_fnstart(3, dev, "(i2400m %p buf %p len %zu)\n", i2400m, buf, buf_len); + rmb(); /* Make sure we see what i2400m_dev_reset_handle() */ if (i2400m->boot_mode) - return ERR_PTR(-ENODEV); + return ERR_PTR(-EL3RST); msg_l3l4_hdr = buf; /* Check msg & payload consistency */ @@ -721,6 +734,8 @@ struct sk_buff *i2400m_msg_to_dev(struct i2400m *i2400m, ack_timeout = HZ; }; + if (unlikely(i2400m->trace_msg_from_user)) + wimax_msg(&i2400m->wimax_dev, "echo", buf, buf_len, GFP_KERNEL); /* The RX path in rx.c will put any response for this message * in i2400m->ack_skb and wake us up. If we cancel the wait, * we need to change the value of i2400m->ack_skb to something @@ -755,6 +770,9 @@ struct sk_buff *i2400m_msg_to_dev(struct i2400m *i2400m, ack_l3l4_hdr = wimax_msg_data_len(ack_skb, &ack_len); /* Check the ack and deliver it if it is ok */ + if (unlikely(i2400m->trace_msg_from_user)) + wimax_msg(&i2400m->wimax_dev, "echo", + ack_l3l4_hdr, ack_len, GFP_KERNEL); result = i2400m_msg_size_check(i2400m, ack_l3l4_hdr, ack_len); if (result < 0) { dev_err(dev, "HW BUG? reply to message 0x%04x: %d\n", @@ -1379,16 +1397,16 @@ error: * * @i2400m: device descriptor * - * Gracefully stops the device, moving it to the lowest power - * consumption state possible. + * Release resources acquired during the running of the device; in + * theory, should also tell the device to go to sleep, switch off the + * radio, all that, but at this point, in most cases (driver + * disconnection, reset handling) we can't even talk to the device. */ void i2400m_dev_shutdown(struct i2400m *i2400m) { - int result = -ENODEV; struct device *dev = i2400m_dev(i2400m); d_fnstart(3, dev, "(i2400m %p)\n", i2400m); - result = i2400m->bus_reset(i2400m, I2400M_RT_WARM); - d_fnend(3, dev, "(i2400m %p) = void [%d]\n", i2400m, result); + d_fnend(3, dev, "(i2400m %p) = void\n", i2400m); return; } diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c index 07a54bad237b..304f0443ca4b 100644 --- a/drivers/net/wimax/i2400m/driver.c +++ b/drivers/net/wimax/i2400m/driver.c @@ -62,6 +62,7 @@ * unregister_netdev() */ #include "i2400m.h" +#include #include #include #include @@ -81,6 +82,14 @@ module_param_named(rx_reorder_disabled, i2400m_rx_reorder_disabled, int, 0644); MODULE_PARM_DESC(rx_reorder_disabled, "If true, RX reordering will be disabled."); +int i2400m_power_save_disabled; /* 0 (power saving enabled) by default */ +module_param_named(power_save_disabled, i2400m_power_save_disabled, int, 0644); +MODULE_PARM_DESC(power_save_disabled, + "If true, the driver will not tell the device to enter " + "power saving mode when it reports it is ready for it. " + "False by default (so the device is told to do power " + "saving)."); + /** * i2400m_queue_work - schedule work on a i2400m's queue * @@ -171,7 +180,6 @@ int i2400m_schedule_work(struct i2400m *i2400m, int result; struct i2400m_work *iw; - BUG_ON(i2400m->work_queue == NULL); result = -ENOMEM; iw = kzalloc(sizeof(*iw), gfp_flags); if (iw == NULL) @@ -234,9 +242,6 @@ int i2400m_op_msg_from_user(struct wimax_dev *wimax_dev, result = PTR_ERR(ack_skb); if (IS_ERR(ack_skb)) goto error_msg_to_dev; - if (unlikely(i2400m->trace_msg_from_user)) - wimax_msg(&i2400m->wimax_dev, "trace", - msg_buf, msg_len, GFP_KERNEL); result = wimax_msg_send(&i2400m->wimax_dev, ack_skb); error_msg_to_dev: d_fnend(4, dev, "(wimax_dev %p [i2400m %p] msg_buf %p msg_len %zu " @@ -379,6 +384,11 @@ error: * Uploads firmware and brings up all the resources needed to be able * to communicate with the device. * + * The workqueue has to be setup early, at least before RX handling + * (it's only real user for now) so it can process reports as they + * arrive. We also want to destroy it if we retry, to make sure it is + * flushed...easier like this. + * * TX needs to be setup before the bus-specific code (otherwise on * shutdown, the bus-tx code could try to access it). */ @@ -389,7 +399,7 @@ int __i2400m_dev_start(struct i2400m *i2400m, enum i2400m_bri flags) struct wimax_dev *wimax_dev = &i2400m->wimax_dev; struct net_device *net_dev = wimax_dev->net_dev; struct device *dev = i2400m_dev(i2400m); - int times = 3; + int times = i2400m->bus_bm_retries; d_fnstart(3, dev, "(i2400m %p)\n", i2400m); retry: @@ -404,15 +414,15 @@ retry: result = i2400m_rx_setup(i2400m); if (result < 0) goto error_rx_setup; - result = i2400m->bus_dev_start(i2400m); - if (result < 0) - goto error_bus_dev_start; i2400m->work_queue = create_singlethread_workqueue(wimax_dev->name); if (i2400m->work_queue == NULL) { result = -ENOMEM; dev_err(dev, "cannot create workqueue\n"); goto error_create_workqueue; } + result = i2400m->bus_dev_start(i2400m); + if (result < 0) + goto error_bus_dev_start; result = i2400m_firmware_check(i2400m); /* fw versions ok? */ if (result < 0) goto error_fw_check; @@ -434,17 +444,17 @@ retry: error_dev_initialize: error_check_mac_addr: error_fw_check: - destroy_workqueue(i2400m->work_queue); -error_create_workqueue: i2400m->bus_dev_stop(i2400m); error_bus_dev_start: + destroy_workqueue(i2400m->work_queue); +error_create_workqueue: i2400m_rx_release(i2400m); error_rx_setup: i2400m_tx_release(i2400m); error_tx_setup: error_bootstrap: - if (result == -ERESTARTSYS && times-- > 0) { - flags = I2400M_BRI_SOFT; + if (result == -EL3RST && times-- > 0) { + flags = I2400M_BRI_SOFT|I2400M_BRI_MAC_REINIT; goto retry; } d_fnend(3, dev, "(net_dev %p [i2400m %p]) = %d\n", @@ -473,7 +483,9 @@ int i2400m_dev_start(struct i2400m *i2400m, enum i2400m_bri bm_flags) * * Returns: 0 if ok, < 0 errno code on error. * - * Releases all the resources allocated to communicate with the device. + * Releases all the resources allocated to communicate with the + * device. Note we cannot destroy the workqueue earlier as until RX is + * fully destroyed, it could still try to schedule jobs. */ static void __i2400m_dev_stop(struct i2400m *i2400m) @@ -485,8 +497,8 @@ void __i2400m_dev_stop(struct i2400m *i2400m) wimax_state_change(wimax_dev, __WIMAX_ST_QUIESCING); i2400m_dev_shutdown(i2400m); i2400m->ready = 0; - destroy_workqueue(i2400m->work_queue); i2400m->bus_dev_stop(i2400m); + destroy_workqueue(i2400m->work_queue); i2400m_rx_release(i2400m); i2400m_tx_release(i2400m); wimax_state_change(wimax_dev, WIMAX_ST_DOWN); @@ -548,7 +560,7 @@ void __i2400m_dev_reset_handle(struct work_struct *ws) * i2400m_dev_stop() [we are shutting down anyway, so * ignore it] or we are resetting somewhere else. */ dev_err(dev, "device rebooted\n"); - i2400m_msg_to_dev_cancel_wait(i2400m, -ERESTARTSYS); + i2400m_msg_to_dev_cancel_wait(i2400m, -EL3RST); complete(&i2400m->msg_completion); goto out; } @@ -598,6 +610,8 @@ out: */ int i2400m_dev_reset_handle(struct i2400m *i2400m) { + i2400m->boot_mode = 1; + wmb(); /* Make sure i2400m_msg_to_dev() sees boot_mode */ return i2400m_schedule_work(i2400m, __i2400m_dev_reset_handle, GFP_ATOMIC); } @@ -650,6 +664,7 @@ int i2400m_setup(struct i2400m *i2400m, enum i2400m_bri bm_flags) result = i2400m_read_mac_addr(i2400m); if (result < 0) goto error_read_mac_addr; + random_ether_addr(i2400m->src_mac_addr); result = register_netdev(net_dev); /* Okey dokey, bring it up */ if (result < 0) { diff --git a/drivers/net/wimax/i2400m/fw.c b/drivers/net/wimax/i2400m/fw.c index 675c6ce810c0..e81750e54452 100644 --- a/drivers/net/wimax/i2400m/fw.c +++ b/drivers/net/wimax/i2400m/fw.c @@ -397,7 +397,7 @@ static int i2400m_download_chunk(struct i2400m *i2400m, const void *chunk, unsigned int direct, unsigned int do_csum) { int ret; - size_t chunk_len = ALIGN(__chunk_len, I2400M_PL_PAD); + size_t chunk_len = ALIGN(__chunk_len, I2400M_PL_ALIGN); struct device *dev = i2400m_dev(i2400m); struct { struct i2400m_bootrom_header cmd; @@ -532,14 +532,14 @@ int i2400m_dnload_finalize(struct i2400m *i2400m, cmd = (void *) bcf + offset; if (i2400m->sboot == 0) { struct i2400m_bootrom_header jump_ack; - d_printf(3, dev, "unsecure boot, jumping to 0x%08x\n", + d_printf(1, dev, "unsecure boot, jumping to 0x%08x\n", le32_to_cpu(cmd->target_addr)); i2400m_brh_set_opcode(cmd, I2400M_BRH_JUMP); cmd->data_size = 0; ret = i2400m_bm_cmd(i2400m, cmd, sizeof(*cmd), &jump_ack, sizeof(jump_ack), 0); } else { - d_printf(3, dev, "secure boot, jumping to 0x%08x\n", + d_printf(1, dev, "secure boot, jumping to 0x%08x\n", le32_to_cpu(cmd->target_addr)); cmd_buf = i2400m->bm_cmd_buf; memcpy(&cmd_buf->cmd, cmd, sizeof(*cmd)); @@ -696,8 +696,7 @@ error_dev_gone: return result; error_timeout: - dev_err(dev, "Timed out waiting for reboot ack, resetting\n"); - i2400m->bus_reset(i2400m, I2400M_RT_BUS); + dev_err(dev, "Timed out waiting for reboot ack\n"); result = -ETIMEDOUT; goto exit_timeout; } @@ -770,40 +769,21 @@ error_read_mac: static int i2400m_dnload_init_nonsigned(struct i2400m *i2400m) { -#define POKE(a, d) { \ - .address = cpu_to_le32(a), \ - .data = cpu_to_le32(d) \ -} - static const struct { - __le32 address; - __le32 data; - } i2400m_pokes[] = { - POKE(0x081A58, 0xA7810230), - POKE(0x080040, 0x00000000), - POKE(0x080048, 0x00000082), - POKE(0x08004C, 0x0000081F), - POKE(0x080054, 0x00000085), - POKE(0x080058, 0x00000180), - POKE(0x08005C, 0x00000018), - POKE(0x080060, 0x00000010), - POKE(0x080574, 0x00000001), - POKE(0x080550, 0x00000005), - POKE(0xAE0000, 0x00000000), - }; -#undef POKE - unsigned i; - int ret; + unsigned i = 0; + int ret = 0; struct device *dev = i2400m_dev(i2400m); - - dev_warn(dev, "WARNING!!! non-signed boot UNTESTED PATH!\n"); - d_fnstart(5, dev, "(i2400m %p)\n", i2400m); - for (i = 0; i < ARRAY_SIZE(i2400m_pokes); i++) { - ret = i2400m_download_chunk(i2400m, &i2400m_pokes[i].data, - sizeof(i2400m_pokes[i].data), - i2400m_pokes[i].address, 1, 1); - if (ret < 0) - break; + if (i2400m->bus_bm_pokes_table) { + while (i2400m->bus_bm_pokes_table[i].address) { + ret = i2400m_download_chunk( + i2400m, + &i2400m->bus_bm_pokes_table[i].data, + sizeof(i2400m->bus_bm_pokes_table[i].data), + i2400m->bus_bm_pokes_table[i].address, 1, 1); + if (ret < 0) + break; + i++; + } } d_fnend(5, dev, "(i2400m %p) = %d\n", i2400m, ret); return ret; @@ -980,11 +960,12 @@ int i2400m_fw_dnload(struct i2400m *i2400m, const struct i2400m_bcf_hdr *bcf, { int ret = 0; struct device *dev = i2400m_dev(i2400m); - int count = I2400M_BOOT_RETRIES; + int count = i2400m->bus_bm_retries; d_fnstart(5, dev, "(i2400m %p bcf %p size %zu)\n", i2400m, bcf, bcf_size); i2400m->boot_mode = 1; + wmb(); /* Make sure other readers see it */ hw_reboot: if (count-- == 0) { ret = -ERESTARTSYS; @@ -1033,6 +1014,7 @@ hw_reboot: d_printf(2, dev, "fw %s successfully uploaded\n", i2400m->fw_name); i2400m->boot_mode = 0; + wmb(); /* Make sure i2400m_msg_to_dev() sees boot_mode */ error_dnload_finalize: error_dnload_bcf: error_dnload_init: diff --git a/drivers/net/wimax/i2400m/i2400m-sdio.h b/drivers/net/wimax/i2400m/i2400m-sdio.h index 08c2fb739234..9c4e3189f7b5 100644 --- a/drivers/net/wimax/i2400m/i2400m-sdio.h +++ b/drivers/net/wimax/i2400m/i2400m-sdio.h @@ -78,6 +78,8 @@ enum { /* The number of ticks to wait for the device to signal that * it is ready */ I2400MS_INIT_SLEEP_INTERVAL = 10, + /* How long to wait for the device to settle after reset */ + I2400MS_SETTLE_TIME = 40, }; @@ -105,6 +107,10 @@ struct i2400ms { char tx_wq_name[32]; struct dentry *debugfs_dentry; + + wait_queue_head_t bm_wfa_wq; + int bm_wait_result; + size_t bm_ack_size; }; @@ -129,4 +135,7 @@ extern ssize_t i2400ms_bus_bm_cmd_send(struct i2400m *, extern ssize_t i2400ms_bus_bm_wait_for_ack(struct i2400m *, struct i2400m_bootrom_header *, size_t); +extern void i2400ms_bus_bm_release(struct i2400m *); +extern int i2400ms_bus_bm_setup(struct i2400m *); + #endif /* #ifndef __I2400M_SDIO_H__ */ diff --git a/drivers/net/wimax/i2400m/i2400m.h b/drivers/net/wimax/i2400m/i2400m.h index 3ae2df38b59a..60330f313f27 100644 --- a/drivers/net/wimax/i2400m/i2400m.h +++ b/drivers/net/wimax/i2400m/i2400m.h @@ -150,11 +150,33 @@ enum { /* Firmware uploading */ I2400M_BOOT_RETRIES = 3, + I3200_BOOT_RETRIES = 3, /* Size of the Boot Mode Command buffer */ I2400M_BM_CMD_BUF_SIZE = 16 * 1024, I2400M_BM_ACK_BUF_SIZE = 256, }; +/** + * struct i2400m_poke_table - Hardware poke table for the Intel 2400m + * + * This structure will be used to create a device specific poke table + * to put the device in a consistant state at boot time. + * + * @address: The device address to poke + * + * @data: The data value to poke to the device address + * + */ +struct i2400m_poke_table{ + __le32 address; + __le32 data; +}; + +#define I2400M_FW_POKE(a, d) { \ + .address = cpu_to_le32(a), \ + .data = cpu_to_le32(d) \ +} + /** * i2400m_reset_type - methods to reset a device @@ -224,6 +246,17 @@ struct i2400m_roq; * process, so it cannot rely on common infrastructure being laid * out. * + * @bus_bm_retries: [fill] How many times shall a firmware upload / + * device initialization be retried? Different models of the same + * device might need different values, hence it is set by the + * bus-specific driver. Note this value is used in two places, + * i2400m_fw_dnload() and __i2400m_dev_start(); they won't become + * multiplicative (__i2400m_dev_start() calling N times + * i2400m_fw_dnload() and this trying N times to download the + * firmware), as if __i2400m_dev_start() only retries if the + * firmware crashed while initializing the device (not in a + * general case). + * * @bus_bm_cmd_send: [fill] Function called to send a boot-mode * command. Flags are defined in 'enum i2400m_bm_cmd_flags'. This * is synchronous and has to return 0 if ok or < 0 errno code in @@ -252,6 +285,12 @@ struct i2400m_roq; * address provided in boot mode is kind of broken and needs to * be re-read later on. * + * @bus_bm_pokes_table: [fill/optional] A table of device addresses + * and values that will be poked at device init time to move the + * device to the correct state for the type of boot/firmware being + * used. This table MUST be terminated with (0x000000, + * 0x00000000) or bad things will happen. + * * * @wimax_dev: WiMAX generic device for linkage into the kernel WiMAX * stack. Due to the way a net_device is allocated, we need to @@ -323,6 +362,10 @@ struct i2400m_roq; * delivered. Then the driver can release them to the host. See * drivers/net/i2400m/rx.c for details. * + * @src_mac_addr: MAC address used to make ethernet packets be coming + * from. This is generated at i2400m_setup() time and used during + * the life cycle of the instance. See i2400m_fake_eth_header(). + * * @init_mutex: Mutex used for serializing the device bringup * sequence; this way if the device reboots in the middle, we * don't try to do a bringup again while we are tearing down the @@ -389,12 +432,14 @@ struct i2400m { unsigned ready:1; /* all probing steps done */ unsigned rx_reorder:1; /* RX reorder is enabled */ u8 trace_msg_from_user; /* echo rx msgs to 'trace' pipe */ - /* typed u8 so debugfs/u8 can tweak */ + /* typed u8 so /sys/kernel/debug/u8 can tweak */ enum i2400m_system_state state; wait_queue_head_t state_wq; /* Woken up when on state updates */ size_t bus_tx_block_size; size_t bus_pl_size_max; + unsigned bus_bm_retries; + int (*bus_dev_start)(struct i2400m *); void (*bus_dev_stop)(struct i2400m *); void (*bus_tx_kick)(struct i2400m *); @@ -406,6 +451,7 @@ struct i2400m { struct i2400m_bootrom_header *, size_t); const char **bus_fw_names; unsigned bus_bm_mac_addr_impaired:1; + const struct i2400m_poke_table *bus_bm_pokes_table; spinlock_t tx_lock; /* protect TX state */ void *tx_buf; @@ -421,6 +467,7 @@ struct i2400m { unsigned rx_pl_num, rx_pl_max, rx_pl_min, rx_num, rx_size_acc, rx_size_min, rx_size_max; struct i2400m_roq *rx_roq; /* not under rx_lock! */ + u8 src_mac_addr[ETH_HLEN]; struct mutex msg_mutex; /* serialize command execution */ struct completion msg_completion; @@ -704,6 +751,7 @@ static const __le32 i2400m_SBOOT_BARKER[4] = { cpu_to_le32(I2400M_SBOOT_BARKER) }; +extern int i2400m_power_save_disabled; /* * Utility functions diff --git a/drivers/net/wimax/i2400m/netdev.c b/drivers/net/wimax/i2400m/netdev.c index 6b1fe7a81f25..9653f478b382 100644 --- a/drivers/net/wimax/i2400m/netdev.c +++ b/drivers/net/wimax/i2400m/netdev.c @@ -404,10 +404,12 @@ static void i2400m_rx_fake_eth_header(struct net_device *net_dev, void *_eth_hdr, __be16 protocol) { + struct i2400m *i2400m = net_dev_to_i2400m(net_dev); struct ethhdr *eth_hdr = _eth_hdr; memcpy(eth_hdr->h_dest, net_dev->dev_addr, sizeof(eth_hdr->h_dest)); - memset(eth_hdr->h_source, 0, sizeof(eth_hdr->h_dest)); + memcpy(eth_hdr->h_source, i2400m->src_mac_addr, + sizeof(eth_hdr->h_source)); eth_hdr->h_proto = protocol; } diff --git a/drivers/net/wimax/i2400m/op-rfkill.c b/drivers/net/wimax/i2400m/op-rfkill.c index 487ec58cea46..43927b5d7ad6 100644 --- a/drivers/net/wimax/i2400m/op-rfkill.c +++ b/drivers/net/wimax/i2400m/op-rfkill.c @@ -54,8 +54,10 @@ int i2400m_radio_is(struct i2400m *i2400m, enum wimax_rf_state state) /* state == WIMAX_RF_ON */ return i2400m->state != I2400M_SS_RF_OFF && i2400m->state != I2400M_SS_RF_SHUTDOWN; - else + else { BUG(); + return -EINVAL; /* shut gcc warnings on certain arches */ + } } diff --git a/drivers/net/wimax/i2400m/rx.c b/drivers/net/wimax/i2400m/rx.c index f9fc38902322..07c32e68909f 100644 --- a/drivers/net/wimax/i2400m/rx.c +++ b/drivers/net/wimax/i2400m/rx.c @@ -177,7 +177,8 @@ void i2400m_report_hook_work(struct work_struct *ws) struct i2400m_work *iw = container_of(ws, struct i2400m_work, ws); struct i2400m_report_hook_args *args = (void *) iw->pl; - i2400m_report_hook(iw->i2400m, args->l3l4_hdr, args->size); + if (iw->i2400m->ready) + i2400m_report_hook(iw->i2400m, args->l3l4_hdr, args->size); kfree_skb(args->skb_rx); i2400m_put(iw->i2400m); kfree(iw); @@ -309,6 +310,9 @@ void i2400m_rx_ctl(struct i2400m *i2400m, struct sk_buff *skb_rx, skb_get(skb_rx); i2400m_queue_work(i2400m, i2400m_report_hook_work, GFP_KERNEL, &args, sizeof(args)); + if (unlikely(i2400m->trace_msg_from_user)) + wimax_msg(&i2400m->wimax_dev, "echo", + l3l4_hdr, size, GFP_KERNEL); result = wimax_msg(&i2400m->wimax_dev, NULL, l3l4_hdr, size, GFP_KERNEL); if (result < 0) @@ -1144,7 +1148,7 @@ int i2400m_rx(struct i2400m *i2400m, struct sk_buff *skb) num_pls = le16_to_cpu(msg_hdr->num_pls); pl_itr = sizeof(*msg_hdr) + /* Check payload descriptor(s) */ num_pls * sizeof(msg_hdr->pld[0]); - pl_itr = ALIGN(pl_itr, I2400M_PL_PAD); + pl_itr = ALIGN(pl_itr, I2400M_PL_ALIGN); if (pl_itr > skb->len) { /* got all the payload descriptors? */ dev_err(dev, "RX: HW BUG? message too short (%u bytes) for " "%u payload descriptors (%zu each, total %zu)\n", @@ -1162,7 +1166,7 @@ int i2400m_rx(struct i2400m *i2400m, struct sk_buff *skb) single_last = num_pls == 1 || i == num_pls - 1; i2400m_rx_payload(i2400m, skb, single_last, &msg_hdr->pld[i], skb->data + pl_itr); - pl_itr += ALIGN(pl_size, I2400M_PL_PAD); + pl_itr += ALIGN(pl_size, I2400M_PL_ALIGN); cond_resched(); /* Don't monopolize */ } kfree_skb(skb); diff --git a/drivers/net/wimax/i2400m/sdio-fw.c b/drivers/net/wimax/i2400m/sdio-fw.c index 3487205d8f50..7d6ec0f475f8 100644 --- a/drivers/net/wimax/i2400m/sdio-fw.c +++ b/drivers/net/wimax/i2400m/sdio-fw.c @@ -46,17 +46,24 @@ * Inaky Perez-Gonzalez * - SDIO rehash for changes in the bus-driver model * + * Dirk Brandewie + * - Make it IRQ based, not polling + * * THE PROCEDURE * * See fw.c for the generic description of this procedure. * * This file implements only the SDIO specifics. It boils down to how * to send a command and waiting for an acknowledgement from the - * device. We do polled reads. + * device. + * + * All this code is sequential -- all i2400ms_bus_bm_*() functions are + * executed in the same thread, except i2400ms_bm_irq() [on its own by + * the SDIO driver]. This makes it possible to avoid locking. * * COMMAND EXECUTION * - * THe generic firmware upload code will call i2400m_bus_bm_cmd_send() + * The generic firmware upload code will call i2400m_bus_bm_cmd_send() * to send commands. * * The SDIO devices expects things in 256 byte blocks, so it will pad @@ -64,12 +71,15 @@ * * ACK RECEPTION * - * This works in polling mode -- the fw loader says when to wait for - * data and for that it calls i2400ms_bus_bm_wait_for_ack(). + * This works in IRQ mode -- the fw loader says when to wait for data + * and for that it calls i2400ms_bus_bm_wait_for_ack(). * - * This will poll the device for data until it is received. We need to - * receive at least as much bytes as where asked for (although it'll - * always be a multiple of 256 bytes). + * This checks if there is any data available (RX size > 0); if not, + * waits for the IRQ handler to notify about it. Once there is data, + * it is read and passed to the caller. Doing it this way we don't + * need much coordination/locking, and it makes it much more difficult + * for an interrupt to be lost and the wait_for_ack() function getting + * stuck even when data is pending. */ #include #include "i2400m-sdio.h" @@ -78,6 +88,7 @@ #define D_SUBMODULE fw #include "sdio-debug-levels.h" + /* * Send a boot-mode command to the SDIO function * @@ -139,7 +150,7 @@ error_too_big: /* - * Read an ack from the device's boot-mode (polling) + * Read an ack from the device's boot-mode * * @i2400m: * @_ack: pointer to where to store the read data @@ -150,75 +161,49 @@ error_too_big: * The ACK for a BM command is always at least sizeof(*ack) bytes, so * check for that. We don't need to check for device reboots * - * NOTE: We do an artificial timeout of 1 sec over the SDIO timeout; - * this way we have control over it...there is no way that I know - * of setting an SDIO transaction timeout. */ ssize_t i2400ms_bus_bm_wait_for_ack(struct i2400m *i2400m, struct i2400m_bootrom_header *ack, size_t ack_size) { - int result; - ssize_t rx_size; - u64 timeout; + ssize_t result; struct i2400ms *i2400ms = container_of(i2400m, struct i2400ms, i2400m); struct sdio_func *func = i2400ms->func; struct device *dev = &func->dev; + int size; BUG_ON(sizeof(*ack) > ack_size); d_fnstart(5, dev, "(i2400m %p ack %p size %zu)\n", i2400m, ack, ack_size); - timeout = get_jiffies_64() + 2 * HZ; - sdio_claim_host(func); - while (1) { - if (time_after64(get_jiffies_64(), timeout)) { - rx_size = -ETIMEDOUT; - dev_err(dev, "timeout waiting for ack data\n"); - goto error_timedout; - } + spin_lock(&i2400m->rx_lock); + i2400ms->bm_ack_size = -EINPROGRESS; + spin_unlock(&i2400m->rx_lock); - /* Find the RX size, check if it fits or not -- it if - * doesn't fit, fail, as we have no way to dispose of - * the extra data. */ - rx_size = __i2400ms_rx_get_size(i2400ms); - if (rx_size < 0) - goto error_rx_get_size; - result = -ENOSPC; /* Check it fits */ - if (rx_size < sizeof(*ack)) { - rx_size = -EIO; - dev_err(dev, "HW BUG? received is too small (%zu vs " - "%zu needed)\n", sizeof(*ack), rx_size); - goto error_too_small; - } - if (rx_size > I2400M_BM_ACK_BUF_SIZE) { - dev_err(dev, "SW BUG? BM_ACK_BUF is too small (%u vs " - "%zu needed)\n", I2400M_BM_ACK_BUF_SIZE, - rx_size); - goto error_too_small; - } - - /* Read it */ - result = sdio_memcpy_fromio(func, i2400m->bm_ack_buf, - I2400MS_DATA_ADDR, rx_size); - if (result == -ETIMEDOUT || result == -ETIME) - continue; - if (result < 0) { - dev_err(dev, "BM SDIO receive (%zu B) failed: %d\n", - rx_size, result); - goto error_read; - } else - break; + result = wait_event_timeout(i2400ms->bm_wfa_wq, + i2400ms->bm_ack_size != -EINPROGRESS, + 2 * HZ); + if (result == 0) { + result = -ETIMEDOUT; + dev_err(dev, "BM: error waiting for an ack\n"); + goto error_timeout; } - rx_size = min((ssize_t)ack_size, rx_size); - memcpy(ack, i2400m->bm_ack_buf, rx_size); -error_read: -error_too_small: -error_rx_get_size: -error_timedout: - sdio_release_host(func); - d_fnend(5, dev, "(i2400m %p ack %p size %zu) = %ld\n", - i2400m, ack, ack_size, (long) rx_size); - return rx_size; + + spin_lock(&i2400m->rx_lock); + result = i2400ms->bm_ack_size; + BUG_ON(result == -EINPROGRESS); + if (result < 0) /* so we exit when rx_release() is called */ + dev_err(dev, "BM: %s failed: %zd\n", __func__, result); + else { + size = min(ack_size, i2400ms->bm_ack_size); + memcpy(ack, i2400m->bm_ack_buf, size); + } + i2400ms->bm_ack_size = -EINPROGRESS; + spin_unlock(&i2400m->rx_lock); + +error_timeout: + d_fnend(5, dev, "(i2400m %p ack %p size %zu) = %zd\n", + i2400m, ack, ack_size, result); + return result; } diff --git a/drivers/net/wimax/i2400m/sdio-rx.c b/drivers/net/wimax/i2400m/sdio-rx.c index a3008b904f7d..321beadf6e47 100644 --- a/drivers/net/wimax/i2400m/sdio-rx.c +++ b/drivers/net/wimax/i2400m/sdio-rx.c @@ -69,6 +69,13 @@ #define D_SUBMODULE rx #include "sdio-debug-levels.h" +static const __le32 i2400m_ACK_BARKER[4] = { + __constant_cpu_to_le32(I2400M_ACK_BARKER), + __constant_cpu_to_le32(I2400M_ACK_BARKER), + __constant_cpu_to_le32(I2400M_ACK_BARKER), + __constant_cpu_to_le32(I2400M_ACK_BARKER) +}; + /* * Read and return the amount of bytes available for RX @@ -131,25 +138,35 @@ void i2400ms_rx(struct i2400ms *i2400ms) ret = rx_size; goto error_get_size; } + ret = -ENOMEM; skb = alloc_skb(rx_size, GFP_ATOMIC); if (NULL == skb) { dev_err(dev, "RX: unable to alloc skb\n"); goto error_alloc_skb; } - ret = sdio_memcpy_fromio(func, skb->data, I2400MS_DATA_ADDR, rx_size); if (ret < 0) { dev_err(dev, "RX: SDIO data read failed: %d\n", ret); goto error_memcpy_fromio; } - /* Check if device has reset */ - if (!memcmp(skb->data, i2400m_NBOOT_BARKER, - sizeof(i2400m_NBOOT_BARKER)) - || !memcmp(skb->data, i2400m_SBOOT_BARKER, - sizeof(i2400m_SBOOT_BARKER))) { + + rmb(); /* make sure we get boot_mode from dev_reset_handle */ + if (i2400m->boot_mode == 1) { + spin_lock(&i2400m->rx_lock); + i2400ms->bm_ack_size = rx_size; + spin_unlock(&i2400m->rx_lock); + memcpy(i2400m->bm_ack_buf, skb->data, rx_size); + wake_up(&i2400ms->bm_wfa_wq); + dev_err(dev, "RX: SDIO boot mode message\n"); + kfree_skb(skb); + } else if (unlikely(!memcmp(skb->data, i2400m_NBOOT_BARKER, + sizeof(i2400m_NBOOT_BARKER)) + || !memcmp(skb->data, i2400m_SBOOT_BARKER, + sizeof(i2400m_SBOOT_BARKER)))) { ret = i2400m_dev_reset_handle(i2400m); + dev_err(dev, "RX: SDIO reboot barker\n"); kfree_skb(skb); } else { skb_put(skb, rx_size); @@ -179,7 +196,6 @@ void i2400ms_irq(struct sdio_func *func) { int ret; struct i2400ms *i2400ms = sdio_get_drvdata(func); - struct i2400m *i2400m = &i2400ms->i2400m; struct device *dev = &func->dev; int val; @@ -194,10 +210,7 @@ void i2400ms_irq(struct sdio_func *func) goto error_no_irq; } sdio_writeb(func, 1, I2400MS_INTR_CLEAR_ADDR, &ret); - if (WARN_ON(i2400m->boot_mode != 0)) - dev_err(dev, "RX: SW BUG? boot mode and IRQ is up?\n"); - else - i2400ms_rx(i2400ms); + i2400ms_rx(i2400ms); error_no_irq: d_fnend(6, dev, "(i2400ms %p) = void\n", i2400ms); return; @@ -214,8 +227,15 @@ int i2400ms_rx_setup(struct i2400ms *i2400ms) int result; struct sdio_func *func = i2400ms->func; struct device *dev = &func->dev; + struct i2400m *i2400m = &i2400ms->i2400m; d_fnstart(5, dev, "(i2400ms %p)\n", i2400ms); + + init_waitqueue_head(&i2400ms->bm_wfa_wq); + spin_lock(&i2400m->rx_lock); + i2400ms->bm_wait_result = -EINPROGRESS; + spin_unlock(&i2400m->rx_lock); + sdio_claim_host(func); result = sdio_claim_irq(func, i2400ms_irq); if (result < 0) { @@ -245,8 +265,13 @@ void i2400ms_rx_release(struct i2400ms *i2400ms) int result; struct sdio_func *func = i2400ms->func; struct device *dev = &func->dev; + struct i2400m *i2400m = &i2400ms->i2400m; d_fnstart(5, dev, "(i2400ms %p)\n", i2400ms); + spin_lock(&i2400m->rx_lock); + i2400ms->bm_ack_size = -EINTR; + spin_unlock(&i2400m->rx_lock); + wake_up_all(&i2400ms->bm_wfa_wq); sdio_claim_host(func); sdio_writeb(func, 0, I2400MS_INTR_ENABLE_ADDR, &result); sdio_release_irq(func); diff --git a/drivers/net/wimax/i2400m/sdio.c b/drivers/net/wimax/i2400m/sdio.c index 5ac5e76701cd..2538825d1c66 100644 --- a/drivers/net/wimax/i2400m/sdio.c +++ b/drivers/net/wimax/i2400m/sdio.c @@ -78,6 +78,14 @@ static const char *i2400ms_bus_fw_names[] = { }; +static const struct i2400m_poke_table i2400ms_pokes[] = { + I2400M_FW_POKE(0x6BE260, 0x00000088), + I2400M_FW_POKE(0x080550, 0x00000005), + I2400M_FW_POKE(0xAE0000, 0x00000000), + I2400M_FW_POKE(0x000000, 0x00000000), /* MUST be 0 terminated or bad + * things will happen */ +}; + /* * Enable the SDIO function * @@ -148,19 +156,14 @@ int i2400ms_bus_dev_start(struct i2400m *i2400m) d_fnstart(3, dev, "(i2400m %p)\n", i2400m); msleep(200); - result = i2400ms_rx_setup(i2400ms); - if (result < 0) - goto error_rx_setup; result = i2400ms_tx_setup(i2400ms); if (result < 0) goto error_tx_setup; d_fnend(3, dev, "(i2400m %p) = %d\n", i2400m, result); return result; - i2400ms_tx_release(i2400ms); error_tx_setup: - i2400ms_rx_release(i2400ms); -error_rx_setup: + i2400ms_tx_release(i2400ms); d_fnend(3, dev, "(i2400m %p) = void\n", i2400m); return result; } @@ -174,7 +177,6 @@ void i2400ms_bus_dev_stop(struct i2400m *i2400m) struct device *dev = &func->dev; d_fnstart(3, dev, "(i2400m %p)\n", i2400m); - i2400ms_rx_release(i2400ms); i2400ms_tx_release(i2400ms); d_fnend(3, dev, "(i2400m %p) = void\n", i2400m); } @@ -255,7 +257,7 @@ error_kzalloc: static int i2400ms_bus_reset(struct i2400m *i2400m, enum i2400m_reset_type rt) { - int result; + int result = 0; struct i2400ms *i2400ms = container_of(i2400m, struct i2400ms, i2400m); struct device *dev = i2400m_dev(i2400m); @@ -280,8 +282,25 @@ int i2400ms_bus_reset(struct i2400m *i2400m, enum i2400m_reset_type rt) sizeof(i2400m_COLD_BOOT_BARKER)); else if (rt == I2400M_RT_BUS) { do_bus_reset: - dev_err(dev, "FIXME: SDIO bus reset not implemented\n"); - result = rt == I2400M_RT_WARM ? -ENODEV : -ENOSYS; + /* call netif_tx_disable() before sending IOE disable, + * so that all the tx from network layer are stopped + * while IOE is being reset. Make sure it is called + * only after register_netdev() was issued. + */ + if (i2400m->wimax_dev.net_dev->reg_state == NETREG_REGISTERED) + netif_tx_disable(i2400m->wimax_dev.net_dev); + + i2400ms_rx_release(i2400ms); + sdio_claim_host(i2400ms->func); + sdio_disable_func(i2400ms->func); + sdio_release_host(i2400ms->func); + + /* Wait for the device to settle */ + msleep(40); + + result = i2400ms_enable_function(i2400ms->func); + if (result >= 0) + i2400ms_rx_setup(i2400ms); } else BUG(); if (result < 0 && rt != I2400M_RT_BUS) { @@ -404,10 +423,22 @@ int i2400ms_probe(struct sdio_func *func, i2400m->bus_dev_stop = i2400ms_bus_dev_stop; i2400m->bus_tx_kick = i2400ms_bus_tx_kick; i2400m->bus_reset = i2400ms_bus_reset; + /* The iwmc3200-wimax sometimes requires the driver to try + * hard when we paint it into a corner. */ + i2400m->bus_bm_retries = I3200_BOOT_RETRIES; i2400m->bus_bm_cmd_send = i2400ms_bus_bm_cmd_send; i2400m->bus_bm_wait_for_ack = i2400ms_bus_bm_wait_for_ack; i2400m->bus_fw_names = i2400ms_bus_fw_names; i2400m->bus_bm_mac_addr_impaired = 1; + i2400m->bus_bm_pokes_table = &i2400ms_pokes[0]; + + sdio_claim_host(func); + result = sdio_set_block_size(func, I2400MS_BLK_SIZE); + sdio_release_host(func); + if (result < 0) { + dev_err(dev, "Failed to set block size: %d\n", result); + goto error_set_blk_size; + } result = i2400ms_enable_function(i2400ms->func); if (result < 0) { @@ -415,13 +446,9 @@ int i2400ms_probe(struct sdio_func *func, goto error_func_enable; } - sdio_claim_host(func); - result = sdio_set_block_size(func, I2400MS_BLK_SIZE); - if (result < 0) { - dev_err(dev, "Failed to set block size: %d\n", result); - goto error_set_blk_size; - } - sdio_release_host(func); + result = i2400ms_rx_setup(i2400ms); + if (result < 0) + goto error_rx_setup; result = i2400m_setup(i2400m, I2400M_BRI_NO_REBOOT); if (result < 0) { @@ -440,12 +467,14 @@ int i2400ms_probe(struct sdio_func *func, error_debugfs_add: i2400m_release(i2400m); error_setup: - sdio_set_drvdata(func, NULL); + i2400ms_rx_release(i2400ms); +error_rx_setup: sdio_claim_host(func); -error_set_blk_size: sdio_disable_func(func); sdio_release_host(func); error_func_enable: +error_set_blk_size: + sdio_set_drvdata(func, NULL); free_netdev(net_dev); error_alloc_netdev: return result; @@ -462,6 +491,7 @@ void i2400ms_remove(struct sdio_func *func) d_fnstart(3, dev, "SDIO func %p\n", func); debugfs_remove_recursive(i2400ms->debugfs_dentry); + i2400ms_rx_release(i2400ms); i2400m_release(i2400m); sdio_set_drvdata(func, NULL); sdio_claim_host(func); diff --git a/drivers/net/wimax/i2400m/tx.c b/drivers/net/wimax/i2400m/tx.c index 613a88ffd651..fa16ccf8e26a 100644 --- a/drivers/net/wimax/i2400m/tx.c +++ b/drivers/net/wimax/i2400m/tx.c @@ -277,6 +277,48 @@ enum { #define TAIL_FULL ((void *)~(unsigned long)NULL) +/* + * Calculate how much tail room is available + * + * Note the trick here. This path is ONLY caleed for Case A (see + * i2400m_tx_fifo_push() below), where we have: + * + * Case A + * N ___________ + * | tail room | + * | | + * |<- IN ->| + * | | + * | data | + * | | + * |<- OUT ->| + * | | + * | head room | + * 0 ----------- + * + * When calculating the tail_room, tx_in might get to be zero if + * i2400m->tx_in is right at the end of the buffer (really full + * buffer) if there is no head room. In this case, tail_room would be + * I2400M_TX_BUF_SIZE, although it is actually zero. Hence the final + * mod (%) operation. However, when doing this kind of optimization, + * i2400m->tx_in being zero would fail, so we treat is an a special + * case. + */ +static inline +size_t __i2400m_tx_tail_room(struct i2400m *i2400m) +{ + size_t tail_room; + size_t tx_in; + + if (unlikely(i2400m->tx_in) == 0) + return I2400M_TX_BUF_SIZE; + tx_in = i2400m->tx_in % I2400M_TX_BUF_SIZE; + tail_room = I2400M_TX_BUF_SIZE - tx_in; + tail_room %= I2400M_TX_BUF_SIZE; + return tail_room; +} + + /* * Allocate @size bytes in the TX fifo, return a pointer to it * @@ -338,7 +380,7 @@ void *i2400m_tx_fifo_push(struct i2400m *i2400m, size_t size, size_t padding) return NULL; } /* Is there space at the tail? */ - tail_room = I2400M_TX_BUF_SIZE - i2400m->tx_in % I2400M_TX_BUF_SIZE; + tail_room = __i2400m_tx_tail_room(i2400m); if (tail_room < needed_size) { if (i2400m->tx_out % I2400M_TX_BUF_SIZE < i2400m->tx_in % I2400M_TX_BUF_SIZE) { @@ -367,17 +409,29 @@ void *i2400m_tx_fifo_push(struct i2400m *i2400m, size_t size, size_t padding) * (I2400M_PL_PAD for the payloads, I2400M_TX_PLD_SIZE for the * header). * + * Tail room can get to be zero if a message was opened when there was + * space only for a header. _tx_close() will mark it as to-skip (as it + * will have no payloads) and there will be no more space to flush, so + * nothing has to be done here. This is probably cheaper than ensuring + * in _tx_new() that there is some space for payloads...as we could + * always possibly hit the same problem if the payload wouldn't fit. + * * Note: * * Assumes i2400m->tx_lock is taken, and we use that as a barrier + * + * This path is only taken for Case A FIFO situations [see + * i2400m_tx_fifo_push()] */ static void i2400m_tx_skip_tail(struct i2400m *i2400m) { struct device *dev = i2400m_dev(i2400m); size_t tx_in = i2400m->tx_in % I2400M_TX_BUF_SIZE; - size_t tail_room = I2400M_TX_BUF_SIZE - tx_in; + size_t tail_room = __i2400m_tx_tail_room(i2400m); struct i2400m_msg_hdr *msg = i2400m->tx_buf + tx_in; + if (unlikely(tail_room == 0)) + return; BUG_ON(tail_room < sizeof(*msg)); msg->size = tail_room | I2400M_TX_SKIP; d_printf(2, dev, "skip tail: skipping %zu bytes @%zu\n", @@ -474,10 +528,18 @@ void i2400m_tx_close(struct i2400m *i2400m) struct i2400m_msg_hdr *tx_msg_moved; size_t aligned_size, padding, hdr_size; void *pad_buf; + unsigned num_pls; if (tx_msg->size & I2400M_TX_SKIP) /* a skipper? nothing to do */ goto out; - + num_pls = le16_to_cpu(tx_msg->num_pls); + /* We can get this situation when a new message was started + * and there was no space to add payloads before hitting the + tail (and taking padding into consideration). */ + if (num_pls == 0) { + tx_msg->size |= I2400M_TX_SKIP; + goto out; + } /* Relocate the message header * * Find the current header size, align it to 16 and if we need @@ -491,7 +553,7 @@ void i2400m_tx_close(struct i2400m *i2400m) */ hdr_size = sizeof(*tx_msg) + le16_to_cpu(tx_msg->num_pls) * sizeof(tx_msg->pld[0]); - hdr_size = ALIGN(hdr_size, I2400M_PL_PAD); + hdr_size = ALIGN(hdr_size, I2400M_PL_ALIGN); tx_msg->offset = I2400M_TX_PLD_SIZE - hdr_size; tx_msg_moved = (void *) tx_msg + tx_msg->offset; memmove(tx_msg_moved, tx_msg, hdr_size); @@ -574,7 +636,7 @@ int i2400m_tx(struct i2400m *i2400m, const void *buf, size_t buf_len, d_fnstart(3, dev, "(i2400m %p skb %p [%zu bytes] pt %u)\n", i2400m, buf, buf_len, pl_type); - padded_len = ALIGN(buf_len, I2400M_PL_PAD); + padded_len = ALIGN(buf_len, I2400M_PL_ALIGN); d_printf(5, dev, "padded_len %zd buf_len %zd\n", padded_len, buf_len); /* If there is no current TX message, create one; if the * current one is out of payload slots or we have a singleton, @@ -591,6 +653,8 @@ try_new: i2400m_tx_close(i2400m); i2400m_tx_new(i2400m); } + if (i2400m->tx_msg == NULL) + goto error_tx_new; if (i2400m->tx_msg->size + padded_len > I2400M_TX_BUF_SIZE / 2) { d_printf(2, dev, "TX: message too big, going new\n"); i2400m_tx_close(i2400m); @@ -773,7 +837,6 @@ void i2400m_tx_msg_sent(struct i2400m *i2400m) n = i2400m->tx_out / I2400M_TX_BUF_SIZE; i2400m->tx_out %= I2400M_TX_BUF_SIZE; i2400m->tx_in -= n * I2400M_TX_BUF_SIZE; - netif_start_queue(i2400m->wimax_dev.net_dev); spin_unlock_irqrestore(&i2400m->tx_lock, flags); d_fnend(3, dev, "(i2400m %p) = void\n", i2400m); } diff --git a/drivers/net/wimax/i2400m/usb.c b/drivers/net/wimax/i2400m/usb.c index 17851321b7fd..cfdaf69da9d1 100644 --- a/drivers/net/wimax/i2400m/usb.c +++ b/drivers/net/wimax/i2400m/usb.c @@ -254,8 +254,10 @@ do_bus_reset: dev_err(dev, "USB reset failed (%d), giving up!\n", result); } - } else + } else { + result = -EINVAL; /* shut gcc up in certain arches */ BUG(); + } if (result < 0 && result != -EINVAL /* device is gone */ && rt != I2400M_RT_BUS) { @@ -399,6 +401,7 @@ int i2400mu_probe(struct usb_interface *iface, i2400m->bus_dev_stop = i2400mu_bus_dev_stop; i2400m->bus_tx_kick = i2400mu_bus_tx_kick; i2400m->bus_reset = i2400mu_bus_reset; + i2400m->bus_bm_retries = I2400M_BOOT_RETRIES; i2400m->bus_bm_cmd_send = i2400mu_bus_bm_cmd_send; i2400m->bus_bm_wait_for_ack = i2400mu_bus_bm_wait_for_ack; i2400m->bus_fw_names = i2400mu_bus_fw_names; diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 3d94e7dfea69..5bc00db21b24 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -146,14 +146,14 @@ config LIBERTAS_CS A driver for Marvell Libertas 8385 CompactFlash devices. config LIBERTAS_SDIO - tristate "Marvell Libertas 8385 and 8686 SDIO 802.11b/g cards" + tristate "Marvell Libertas 8385/8686/8688 SDIO 802.11b/g cards" depends on LIBERTAS && MMC ---help--- - A driver for Marvell Libertas 8385 and 8686 SDIO devices. + A driver for Marvell Libertas 8385/8686/8688 SDIO devices. config LIBERTAS_SPI tristate "Marvell Libertas 8686 SPI 802.11b/g cards" - depends on LIBERTAS && SPI && GENERIC_GPIO + depends on LIBERTAS && SPI ---help--- A driver for Marvell Libertas 8686 SPI devices. @@ -310,7 +310,7 @@ config PRISM54 If you want to compile the driver as a module ( = code which can be inserted in and removed from the running kernel whenever you want), say M here and read . - The module will be called prism54.ko. + The module will be called prism54. config USB_ZD1201 tristate "USB ZD1201 based Wireless device support" @@ -333,6 +333,7 @@ config USB_ZD1201 config USB_NET_RNDIS_WLAN tristate "Wireless RNDIS USB support" depends on USB && WLAN_80211 && EXPERIMENTAL + depends on CFG80211 select USB_USBNET select USB_NET_CDCETHER select USB_NET_RNDIS_HOST @@ -434,6 +435,13 @@ config RTL8187 Thanks to Realtek for their support! +# If possible, automatically enable LEDs for RTL8187. + +config RTL8187_LEDS + bool + depends on RTL8187 && MAC80211_LEDS && (LEDS_CLASS = y || LEDS_CLASS = RTL8187) + default y + config ADM8211 tristate "ADMtek ADM8211 support" depends on MAC80211 && PCI && WLAN_80211 && EXPERIMENTAL @@ -484,9 +492,7 @@ config MWL8K will be called mwl8k. If unsure, say N. source "drivers/net/wireless/p54/Kconfig" -source "drivers/net/wireless/ath5k/Kconfig" -source "drivers/net/wireless/ath9k/Kconfig" -source "drivers/net/wireless/ar9170/Kconfig" +source "drivers/net/wireless/ath/Kconfig" source "drivers/net/wireless/ipw2x00/Kconfig" source "drivers/net/wireless/iwlwifi/Kconfig" source "drivers/net/wireless/hostap/Kconfig" @@ -495,5 +501,7 @@ source "drivers/net/wireless/b43legacy/Kconfig" source "drivers/net/wireless/zd1211rw/Kconfig" source "drivers/net/wireless/rt2x00/Kconfig" source "drivers/net/wireless/orinoco/Kconfig" +source "drivers/net/wireless/wl12xx/Kconfig" +source "drivers/net/wireless/iwmc3200wifi/Kconfig" endmenu diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 50e7fba7f0ea..7a4647e78fd3 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -55,8 +55,10 @@ obj-$(CONFIG_RT2X00) += rt2x00/ obj-$(CONFIG_P54_COMMON) += p54/ -obj-$(CONFIG_ATH5K) += ath5k/ -obj-$(CONFIG_ATH9K) += ath9k/ -obj-$(CONFIG_AR9170_USB) += ar9170/ +obj-$(CONFIG_ATH_COMMON) += ath/ obj-$(CONFIG_MAC80211_HWSIM) += mac80211_hwsim.o + +obj-$(CONFIG_WL12XX) += wl12xx/ + +obj-$(CONFIG_IWM) += iwmc3200wifi/ diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index f71821795018..2b9e379994a1 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -1311,18 +1311,20 @@ static int adm8211_config(struct ieee80211_hw *dev, u32 changed) return 0; } -static int adm8211_config_interface(struct ieee80211_hw *dev, - struct ieee80211_vif *vif, - struct ieee80211_if_conf *conf) +static void adm8211_bss_info_changed(struct ieee80211_hw *dev, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *conf, + u32 changes) { struct adm8211_priv *priv = dev->priv; + if (!(changes & BSS_CHANGED_BSSID)) + return; + if (memcmp(conf->bssid, priv->bssid, ETH_ALEN)) { adm8211_set_bssid(dev, conf->bssid); memcpy(priv->bssid, conf->bssid, ETH_ALEN); } - - return 0; } static void adm8211_configure_filter(struct ieee80211_hw *dev, @@ -1753,7 +1755,7 @@ static const struct ieee80211_ops adm8211_ops = { .add_interface = adm8211_add_interface, .remove_interface = adm8211_remove_interface, .config = adm8211_config, - .config_interface = adm8211_config_interface, + .bss_info_changed = adm8211_bss_info_changed, .configure_filter = adm8211_configure_filter, .get_stats = adm8211_get_stats, .get_tx_stats = adm8211_get_tx_stats, diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 9eabf4d1f2e7..c70604f0329e 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -1935,7 +1935,7 @@ static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) { netif_stop_queue (dev); if (npacks > MAXTXQ) { dev->stats.tx_fifo_errors++; - return 1; + return NETDEV_TX_BUSY; } skb_queue_tail (&ai->txq, skb); return 0; @@ -2139,7 +2139,7 @@ static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) { if (i == MAX_FIDS / 2) { dev->stats.tx_fifo_errors++; - return 1; + return NETDEV_TX_BUSY; } } /* check min length*/ @@ -2193,7 +2193,8 @@ static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) { if (test_bit(FLAG_MPI, &priv->flags)) { /* Not implemented yet for MPI350 */ netif_stop_queue(dev); - return -ENETDOWN; + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; } if ( skb == NULL ) { @@ -2210,7 +2211,7 @@ static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) { if (i == MAX_FIDS) { dev->stats.tx_fifo_errors++; - return 1; + return NETDEV_TX_BUSY; } } /* check min length*/ diff --git a/drivers/net/wireless/arlan-main.c b/drivers/net/wireless/arlan-main.c index a54a67c425c8..d84caf198a23 100644 --- a/drivers/net/wireless/arlan-main.c +++ b/drivers/net/wireless/arlan-main.c @@ -1199,7 +1199,7 @@ bad_end: arlan_process_interrupt(dev); netif_stop_queue (dev); ARLAN_DEBUG_EXIT("arlan_tx"); - return 1; + return NETDEV_TX_BUSY; } diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c index 8d93ca4651b9..4efbdbe6d6bf 100644 --- a/drivers/net/wireless/at76c50x-usb.c +++ b/drivers/net/wireless/at76c50x-usb.c @@ -1965,13 +1965,18 @@ static int at76_config(struct ieee80211_hw *hw, u32 changed) return 0; } -static int at76_config_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_if_conf *conf) +static void at76_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *conf, + u32 changed) { struct at76_priv *priv = hw->priv; at76_dbg(DBG_MAC80211, "%s():", __func__); + + if (!(changed & BSS_CHANGED_BSSID)) + return; + at76_dbg_dump(DBG_MAC80211, conf->bssid, ETH_ALEN, "bssid:"); mutex_lock(&priv->mtx); @@ -1983,8 +1988,6 @@ static int at76_config_interface(struct ieee80211_hw *hw, at76_join(priv); mutex_unlock(&priv->mtx); - - return 0; } /* must be atomic */ @@ -2076,7 +2079,7 @@ static const struct ieee80211_ops at76_ops = { .add_interface = at76_add_interface, .remove_interface = at76_remove_interface, .config = at76_config, - .config_interface = at76_config_interface, + .bss_info_changed = at76_bss_info_changed, .configure_filter = at76_configure_filter, .start = at76_mac80211_start, .stop = at76_mac80211_stop, @@ -2250,6 +2253,7 @@ static int at76_init_new_device(struct at76_priv *priv, /* mac80211 initialisation */ priv->hw->wiphy->max_scan_ssids = 1; + priv->hw->wiphy->max_scan_ie_len = 0; priv->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &at76_supported_band; priv->hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | @@ -2311,8 +2315,7 @@ static void at76_delete_device(struct at76_priv *priv) del_timer_sync(&ledtrig_tx_timer); - if (priv->rx_skb) - kfree_skb(priv->rx_skb); + kfree_skb(priv->rx_skb); usb_put_dev(priv->udev); diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig new file mode 100644 index 000000000000..d26e7b485315 --- /dev/null +++ b/drivers/net/wireless/ath/Kconfig @@ -0,0 +1,8 @@ +config ATH_COMMON + tristate "Atheros Wireless Cards" + depends on ATH5K || ATH9K || AR9170_USB + +source "drivers/net/wireless/ath/ath5k/Kconfig" +source "drivers/net/wireless/ath/ath9k/Kconfig" +source "drivers/net/wireless/ath/ar9170/Kconfig" + diff --git a/drivers/net/wireless/ath/Makefile b/drivers/net/wireless/ath/Makefile new file mode 100644 index 000000000000..4bb0132ada37 --- /dev/null +++ b/drivers/net/wireless/ath/Makefile @@ -0,0 +1,6 @@ +obj-$(CONFIG_ATH5K) += ath5k/ +obj-$(CONFIG_ATH9K) += ath9k/ +obj-$(CONFIG_AR9170_USB) += ar9170/ + +obj-$(CONFIG_ATH_COMMON) += ath.o +ath-objs := main.o regd.o diff --git a/drivers/net/wireless/ar9170/Kconfig b/drivers/net/wireless/ath/ar9170/Kconfig similarity index 96% rename from drivers/net/wireless/ar9170/Kconfig rename to drivers/net/wireless/ath/ar9170/Kconfig index de4281fda129..b99e3263ee6d 100644 --- a/drivers/net/wireless/ar9170/Kconfig +++ b/drivers/net/wireless/ath/ar9170/Kconfig @@ -2,6 +2,7 @@ config AR9170_USB tristate "Atheros AR9170 802.11n USB support" depends on USB && MAC80211 && WLAN_80211 && EXPERIMENTAL select FW_LOADER + select ATH_COMMON help This is a driver for the Atheros "otus" 802.11n USB devices. diff --git a/drivers/net/wireless/ar9170/Makefile b/drivers/net/wireless/ath/ar9170/Makefile similarity index 100% rename from drivers/net/wireless/ar9170/Makefile rename to drivers/net/wireless/ath/ar9170/Makefile diff --git a/drivers/net/wireless/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h similarity index 75% rename from drivers/net/wireless/ar9170/ar9170.h rename to drivers/net/wireless/ath/ar9170/ar9170.h index f4fb2e94aea0..bb97981fb248 100644 --- a/drivers/net/wireless/ar9170/ar9170.h +++ b/drivers/net/wireless/ath/ar9170/ar9170.h @@ -40,7 +40,7 @@ #include #include -#include +#include #include #ifdef CONFIG_AR9170_LEDS #include @@ -48,6 +48,8 @@ #include "eeprom.h" #include "hw.h" +#include "../regd.h" + #define PAYLOAD_MAX (AR9170_MAX_CMD_LEN/4 - 1) enum ar9170_bw { @@ -58,6 +60,21 @@ enum ar9170_bw { __AR9170_NUM_BW, }; +static inline enum ar9170_bw nl80211_to_ar9170(enum nl80211_channel_type type) +{ + switch (type) { + case NL80211_CHAN_NO_HT: + case NL80211_CHAN_HT20: + return AR9170_BW_20; + case NL80211_CHAN_HT40MINUS: + return AR9170_BW_40_BELOW; + case NL80211_CHAN_HT40PLUS: + return AR9170_BW_40_ABOVE; + default: + BUG(); + } +} + enum ar9170_rf_init_mode { AR9170_RFI_NONE, AR9170_RFI_WARM, @@ -74,6 +91,7 @@ struct ar9170_led { struct led_classdev l; char name[32]; unsigned int toggled; + bool last_state; bool registered; }; @@ -84,20 +102,31 @@ enum ar9170_device_state { AR9170_STOPPED, AR9170_IDLE, AR9170_STARTED, - AR9170_ASSOCIATED, }; +struct ar9170_rxstream_mpdu_merge { + struct ar9170_rx_head plcp; + bool has_plcp; +}; + +#define AR9170_QUEUE_TIMEOUT 64 +#define AR9170_TX_TIMEOUT 8 +#define AR9170_JANITOR_DELAY 128 +#define AR9170_TX_INVALID_RATE 0xffffffff + struct ar9170 { struct ieee80211_hw *hw; struct mutex mutex; enum ar9170_device_state state; + unsigned long bad_hw_nagger; int (*open)(struct ar9170 *); void (*stop)(struct ar9170 *); - int (*tx)(struct ar9170 *, struct sk_buff *, bool, unsigned int); + int (*tx)(struct ar9170 *, struct sk_buff *); int (*exec_cmd)(struct ar9170 *, enum ar9170_cmd, u32 , void *, u32 , void *); void (*callback_cmd)(struct ar9170 *, u32 , void *); + int (*flush)(struct ar9170 *); /* interface mode settings */ struct ieee80211_vif *vif; @@ -117,7 +146,8 @@ struct ar9170 { struct work_struct filter_config_work; u64 cur_mc_hash, want_mc_hash; u32 cur_filter, want_filter; - unsigned int filter_changed; + unsigned long filter_changed; + unsigned int filter_state; bool sniffer_enabled; /* PHY */ @@ -151,21 +181,35 @@ struct ar9170 { /* EEPROM */ struct ar9170_eeprom eeprom; + struct ath_regulatory regulatory; - /* global tx status for unregistered Stations. */ - struct sk_buff_head global_tx_status; - struct sk_buff_head global_tx_status_waste; - struct delayed_work tx_status_janitor; + /* tx queues - as seen by hw - */ + struct sk_buff_head tx_pending[__AR9170_NUM_TXQ]; + struct sk_buff_head tx_status[__AR9170_NUM_TXQ]; + struct delayed_work tx_janitor; + + /* rxstream mpdu merge */ + struct ar9170_rxstream_mpdu_merge rx_mpdu; + struct sk_buff *rx_failover; + int rx_failover_missing; }; struct ar9170_sta_info { - struct sk_buff_head tx_status[__AR9170_NUM_TXQ]; }; -#define IS_STARTED(a) (a->state >= AR9170_STARTED) -#define IS_ACCEPTING_CMD(a) (a->state >= AR9170_IDLE) +#define AR9170_TX_FLAG_WAIT_FOR_ACK BIT(0) +#define AR9170_TX_FLAG_NO_ACK BIT(1) +#define AR9170_TX_FLAG_BLOCK_ACK BIT(2) -#define AR9170_FILTER_CHANGED_PROMISC BIT(0) +struct ar9170_tx_info { + unsigned long timeout; + unsigned int flags; +}; + +#define IS_STARTED(a) (((struct ar9170 *)a)->state >= AR9170_STARTED) +#define IS_ACCEPTING_CMD(a) (((struct ar9170 *)a)->state >= AR9170_IDLE) + +#define AR9170_FILTER_CHANGED_MODE BIT(0) #define AR9170_FILTER_CHANGED_MULTICAST BIT(1) #define AR9170_FILTER_CHANGED_FRAMEFILTER BIT(2) @@ -174,8 +218,9 @@ void *ar9170_alloc(size_t priv_size); int ar9170_register(struct ar9170 *ar, struct device *pdev); void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb); void ar9170_unregister(struct ar9170 *ar); -void ar9170_handle_tx_status(struct ar9170 *ar, struct sk_buff *skb, - bool update_statistics, u16 tx_status); +void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb); +void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len); +int ar9170_nag_limiter(struct ar9170 *ar); /* MAC */ int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb); @@ -185,6 +230,9 @@ int ar9170_update_multicast(struct ar9170 *ar); int ar9170_update_frame_filter(struct ar9170 *ar); int ar9170_set_operating_mode(struct ar9170 *ar); int ar9170_set_beacon_timers(struct ar9170 *ar); +int ar9170_set_dyn_sifs_ack(struct ar9170 *ar); +int ar9170_set_slot_time(struct ar9170 *ar); +int ar9170_set_basic_rates(struct ar9170 *ar); int ar9170_set_hwretry_limit(struct ar9170 *ar, u32 max_retry); int ar9170_update_beacon(struct ar9170 *ar); void ar9170_new_beacon(struct work_struct *work); diff --git a/drivers/net/wireless/ar9170/cmd.c b/drivers/net/wireless/ath/ar9170/cmd.c similarity index 100% rename from drivers/net/wireless/ar9170/cmd.c rename to drivers/net/wireless/ath/ar9170/cmd.c diff --git a/drivers/net/wireless/ar9170/cmd.h b/drivers/net/wireless/ath/ar9170/cmd.h similarity index 100% rename from drivers/net/wireless/ar9170/cmd.h rename to drivers/net/wireless/ath/ar9170/cmd.h diff --git a/drivers/net/wireless/ar9170/eeprom.h b/drivers/net/wireless/ath/ar9170/eeprom.h similarity index 100% rename from drivers/net/wireless/ar9170/eeprom.h rename to drivers/net/wireless/ath/ar9170/eeprom.h diff --git a/drivers/net/wireless/ar9170/hw.h b/drivers/net/wireless/ath/ar9170/hw.h similarity index 96% rename from drivers/net/wireless/ar9170/hw.h rename to drivers/net/wireless/ath/ar9170/hw.h index 53e250a4278f..6cbfb2f83391 100644 --- a/drivers/net/wireless/ar9170/hw.h +++ b/drivers/net/wireless/ath/ar9170/hw.h @@ -207,6 +207,9 @@ enum ar9170_cmd { #define AR9170_MAC_REG_AC1_AC0_TXOP (AR9170_MAC_REG_BASE + 0xB44) #define AR9170_MAC_REG_AC3_AC2_TXOP (AR9170_MAC_REG_BASE + 0xB48) +#define AR9170_MAC_REG_AMPDU_FACTOR (AR9170_MAC_REG_BASE + 0xB9C) +#define AR9170_MAC_REG_AMPDU_DENSITY (AR9170_MAC_REG_BASE + 0xBA0) + #define AR9170_MAC_REG_ACK_TABLE (AR9170_MAC_REG_BASE + 0xC00) #define AR9170_MAC_REG_AMPDU_RX_THRESH (AR9170_MAC_REG_BASE + 0xC50) @@ -312,7 +315,7 @@ struct ar9170_rx_head { u8 plcp[12]; } __packed; -struct ar9170_rx_tail { +struct ar9170_rx_phystatus { union { struct { u8 rssi_ant0, rssi_ant1, rssi_ant2, @@ -324,6 +327,9 @@ struct ar9170_rx_tail { u8 evm_stream0[6], evm_stream1[6]; u8 phy_err; +} __packed; + +struct ar9170_rx_macstatus { u8 SAidx, DAidx; u8 error; u8 status; @@ -339,7 +345,7 @@ struct ar9170_rx_tail { #define AR9170_RX_ENC_SOFTWARE 0x8 -static inline u8 ar9170_get_decrypt_type(struct ar9170_rx_tail *t) +static inline u8 ar9170_get_decrypt_type(struct ar9170_rx_macstatus *t) { return (t->SAidx & 0xc0) >> 4 | (t->DAidx & 0xc0) >> 6; @@ -357,10 +363,9 @@ static inline u8 ar9170_get_decrypt_type(struct ar9170_rx_tail *t) #define AR9170_RX_STATUS_MPDU_MASK 0x30 #define AR9170_RX_STATUS_MPDU_SINGLE 0x00 -#define AR9170_RX_STATUS_MPDU_FIRST 0x10 -#define AR9170_RX_STATUS_MPDU_MIDDLE 0x20 -#define AR9170_RX_STATUS_MPDU_LAST 0x30 - +#define AR9170_RX_STATUS_MPDU_FIRST 0x20 +#define AR9170_RX_STATUS_MPDU_MIDDLE 0x30 +#define AR9170_RX_STATUS_MPDU_LAST 0x10 #define AR9170_RX_ERROR_RXTO 0x01 #define AR9170_RX_ERROR_OVERRUN 0x02 @@ -369,9 +374,9 @@ static inline u8 ar9170_get_decrypt_type(struct ar9170_rx_tail *t) #define AR9170_RX_ERROR_WRONG_RA 0x10 #define AR9170_RX_ERROR_PLCP 0x20 #define AR9170_RX_ERROR_MMIC 0x40 +#define AR9170_RX_ERROR_FATAL 0x80 struct ar9170_cmd_tx_status { - __le16 unkn; u8 dst[ETH_ALEN]; __le32 rate; __le16 status; @@ -389,6 +394,7 @@ struct ar9170_cmd_ba_failed_count { struct ar9170_cmd_response { u8 flag; u8 type; + __le16 padding; union { struct ar9170_cmd_tx_status tx_status; @@ -414,4 +420,7 @@ enum ar9170_txq { __AR9170_NUM_TXQ, }; +#define AR9170_TXQ_DEPTH 32 +#define AR9170_TX_MAX_PENDING 128 + #endif /* __AR9170_HW_H */ diff --git a/drivers/net/wireless/ar9170/led.c b/drivers/net/wireless/ath/ar9170/led.c similarity index 94% rename from drivers/net/wireless/ar9170/led.c rename to drivers/net/wireless/ath/ar9170/led.c index 341cead7f606..63fda6cd2101 100644 --- a/drivers/net/wireless/ar9170/led.c +++ b/drivers/net/wireless/ath/ar9170/led.c @@ -74,7 +74,7 @@ static void ar9170_update_leds(struct work_struct *work) mutex_lock(&ar->mutex); for (i = 0; i < AR9170_NUM_LEDS; i++) - if (ar->leds[i].toggled) { + if (ar->leds[i].registered && ar->leds[i].toggled) { led_val |= 1 << i; tmp = 70 + 200 / (ar->leds[i].toggled); @@ -101,9 +101,15 @@ static void ar9170_led_brightness_set(struct led_classdev *led, struct ar9170_led *arl = container_of(led, struct ar9170_led, l); struct ar9170 *ar = arl->ar; - arl->toggled++; + if (unlikely(!arl->registered)) + return ; - if (likely(IS_ACCEPTING_CMD(ar) && brightness)) + if (arl->last_state != !!brightness) { + arl->toggled++; + arl->last_state = !!brightness; + } + + if (likely(IS_ACCEPTING_CMD(ar) && arl->toggled)) queue_delayed_work(ar->hw->workqueue, &ar->led_work, HZ/10); } @@ -136,13 +142,14 @@ void ar9170_unregister_leds(struct ar9170 *ar) { int i; - cancel_delayed_work_sync(&ar->led_work); - for (i = 0; i < AR9170_NUM_LEDS; i++) if (ar->leds[i].registered) { led_classdev_unregister(&ar->leds[i].l); ar->leds[i].registered = false; + ar->leds[i].toggled = 0; } + + cancel_delayed_work_sync(&ar->led_work); } int ar9170_register_leds(struct ar9170 *ar) diff --git a/drivers/net/wireless/ar9170/mac.c b/drivers/net/wireless/ath/ar9170/mac.c similarity index 86% rename from drivers/net/wireless/ar9170/mac.c rename to drivers/net/wireless/ath/ar9170/mac.c index c8fa3073169f..d9f1f46de183 100644 --- a/drivers/net/wireless/ar9170/mac.c +++ b/drivers/net/wireless/ath/ar9170/mac.c @@ -38,6 +38,55 @@ #include "ar9170.h" #include "cmd.h" +int ar9170_set_dyn_sifs_ack(struct ar9170 *ar) +{ + u32 val; + + if (conf_is_ht40(&ar->hw->conf)) + val = 0x010a; + else { + if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ) + val = 0x105; + else + val = 0x104; + } + + return ar9170_write_reg(ar, AR9170_MAC_REG_DYNAMIC_SIFS_ACK, val); +} + +int ar9170_set_slot_time(struct ar9170 *ar) +{ + u32 slottime = 20; + + if (!ar->vif) + return 0; + + if ((ar->hw->conf.channel->band == IEEE80211_BAND_5GHZ) || + ar->vif->bss_conf.use_short_slot) + slottime = 9; + + return ar9170_write_reg(ar, AR9170_MAC_REG_SLOT_TIME, slottime << 10); +} + +int ar9170_set_basic_rates(struct ar9170 *ar) +{ + u8 cck, ofdm; + + if (!ar->vif) + return 0; + + ofdm = ar->vif->bss_conf.basic_rates >> 4; + + /* FIXME: is still necessary? */ + if (ar->hw->conf.channel->band == IEEE80211_BAND_5GHZ) + cck = 0; + else + cck = ar->vif->bss_conf.basic_rates & 0xf; + + return ar9170_write_reg(ar, AR9170_MAC_REG_BASIC_RATE, + ofdm << 8 | cck); +} + int ar9170_set_qos(struct ar9170 *ar) { ar9170_regwrite_begin(ar); @@ -72,6 +121,24 @@ int ar9170_set_qos(struct ar9170 *ar) return ar9170_regwrite_result(); } +static int ar9170_set_ampdu_density(struct ar9170 *ar, u8 mpdudensity) +{ + u32 val; + + /* don't allow AMPDU density > 8us */ + if (mpdudensity > 6) + return -EINVAL; + + /* Watch out! Otus uses slightly different density values. */ + val = 0x140a00 | (mpdudensity ? (mpdudensity + 1) : 0); + + ar9170_regwrite_begin(ar); + ar9170_regwrite(AR9170_MAC_REG_AMPDU_DENSITY, val); + ar9170_regwrite_finish(); + + return ar9170_regwrite_result(); +} + int ar9170_init_mac(struct ar9170 *ar) { ar9170_regwrite_begin(ar); @@ -265,9 +332,9 @@ int ar9170_set_operating_mode(struct ar9170 *ar) case NL80211_IFTYPE_ADHOC: pm_mode |= AR9170_MAC_REG_POWERMGT_IBSS; break; -/* case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_AP: pm_mode |= AR9170_MAC_REG_POWERMGT_AP; - break;*/ + break; case NL80211_IFTYPE_WDS: pm_mode |= AR9170_MAC_REG_POWERMGT_AP_WDS; break; @@ -296,6 +363,11 @@ int ar9170_set_operating_mode(struct ar9170 *ar) if (err) return err; + /* set AMPDU density to 8us. */ + err = ar9170_set_ampdu_density(ar, 6); + if (err) + return err; + ar9170_regwrite_begin(ar); ar9170_regwrite(AR9170_MAC_REG_POWERMANAGEMENT, pm_mode); @@ -316,9 +388,9 @@ int ar9170_set_beacon_timers(struct ar9170 *ar) u32 v = 0; u32 pretbtt = 0; - v |= ar->hw->conf.beacon_int; - if (ar->vif) { + v |= ar->vif->bss_conf.beacon_int; + switch (ar->vif->type) { case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_ADHOC: @@ -326,7 +398,7 @@ int ar9170_set_beacon_timers(struct ar9170 *ar) break; case NL80211_IFTYPE_AP: v |= BIT(24); - pretbtt = (ar->hw->conf.beacon_int - 6) << 16; + pretbtt = (ar->vif->bss_conf.beacon_int - 6) << 16; break; default: break; @@ -375,10 +447,10 @@ int ar9170_update_beacon(struct ar9170 *ar) /* XXX: use skb->cb info */ if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ) ar9170_regwrite(AR9170_MAC_REG_BCN_PLCP, - ((skb->len + 4) << (3+16)) + 0x0400); + ((skb->len + 4) << (3 + 16)) + 0x0400); else ar9170_regwrite(AR9170_MAC_REG_BCN_PLCP, - ((skb->len + 4) << (3+16)) + 0x0400); + ((skb->len + 4) << 16) + 0x001b); ar9170_regwrite(AR9170_MAC_REG_BCN_LENGTH, skb->len + 4); ar9170_regwrite(AR9170_MAC_REG_BCN_ADDR, AR9170_BEACON_BUFFER_ADDRESS); diff --git a/drivers/net/wireless/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c similarity index 55% rename from drivers/net/wireless/ar9170/main.c rename to drivers/net/wireless/ath/ar9170/main.c index 5996ff9f7f47..9d38cf60a0db 100644 --- a/drivers/net/wireless/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -142,73 +142,153 @@ static struct ieee80211_channel ar9170_5ghz_chantable[] = { }; #undef CHAN +#define AR9170_HT_CAP \ +{ \ + .ht_supported = true, \ + .cap = IEEE80211_HT_CAP_MAX_AMSDU | \ + IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \ + IEEE80211_HT_CAP_SGI_40 | \ + IEEE80211_HT_CAP_DSSSCCK40 | \ + IEEE80211_HT_CAP_SM_PS, \ + .ampdu_factor = 3, \ + .ampdu_density = 6, \ + .mcs = { \ + .rx_mask = { 0xFF, 0xFF, 0, 0, 0, 0, 0, 0, 0, 0, }, \ + }, \ +} + static struct ieee80211_supported_band ar9170_band_2GHz = { .channels = ar9170_2ghz_chantable, .n_channels = ARRAY_SIZE(ar9170_2ghz_chantable), .bitrates = ar9170_g_ratetable, .n_bitrates = ar9170_g_ratetable_size, + .ht_cap = AR9170_HT_CAP, }; -#ifdef AR9170_QUEUE_DEBUG -/* - * In case some wants works with AR9170's crazy tx_status queueing techniques. - * He might need this rather useful probing function. - * - * NOTE: caller must hold the queue's spinlock! - */ - -static void ar9170_print_txheader(struct ar9170 *ar, struct sk_buff *skb) -{ - struct ar9170_tx_control *txc = (void *) skb->data; - struct ieee80211_hdr *hdr = (void *)txc->frame_data; - - printk(KERN_DEBUG "%s: => FRAME [skb:%p, queue:%d, DA:[%pM] " - "mac_control:%04x, phy_control:%08x]\n", - wiphy_name(ar->hw->wiphy), skb, skb_get_queue_mapping(skb), - ieee80211_get_DA(hdr), le16_to_cpu(txc->mac_control), - le32_to_cpu(txc->phy_control)); -} - -static void ar9170_dump_station_tx_status_queue(struct ar9170 *ar, - struct sk_buff_head *queue) -{ - struct sk_buff *skb; - int i = 0; - - printk(KERN_DEBUG "---[ cut here ]---\n"); - printk(KERN_DEBUG "%s: %d entries in tx_status queue.\n", - wiphy_name(ar->hw->wiphy), skb_queue_len(queue)); - - skb_queue_walk(queue, skb) { - struct ar9170_tx_control *txc = (void *) skb->data; - struct ieee80211_hdr *hdr = (void *)txc->frame_data; - - printk(KERN_DEBUG "index:%d => \n", i); - ar9170_print_txheader(ar, skb); - } - printk(KERN_DEBUG "---[ end ]---\n"); -} -#endif /* AR9170_QUEUE_DEBUG */ - static struct ieee80211_supported_band ar9170_band_5GHz = { .channels = ar9170_5ghz_chantable, .n_channels = ARRAY_SIZE(ar9170_5ghz_chantable), .bitrates = ar9170_a_ratetable, .n_bitrates = ar9170_a_ratetable_size, + .ht_cap = AR9170_HT_CAP, }; -void ar9170_handle_tx_status(struct ar9170 *ar, struct sk_buff *skb, - bool valid_status, u16 tx_status) +static void ar9170_tx(struct ar9170 *ar); + +#ifdef AR9170_QUEUE_DEBUG +static void ar9170_print_txheader(struct ar9170 *ar, struct sk_buff *skb) +{ + struct ar9170_tx_control *txc = (void *) skb->data; + struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb); + struct ar9170_tx_info *arinfo = (void *) txinfo->rate_driver_data; + struct ieee80211_hdr *hdr = (void *) txc->frame_data; + + printk(KERN_DEBUG "%s: => FRAME [skb:%p, q:%d, DA:[%pM] flags:%x " + "mac_ctrl:%04x, phy_ctrl:%08x, timeout:[%d ms]]\n", + wiphy_name(ar->hw->wiphy), skb, skb_get_queue_mapping(skb), + ieee80211_get_DA(hdr), arinfo->flags, + le16_to_cpu(txc->mac_control), le32_to_cpu(txc->phy_control), + jiffies_to_msecs(arinfo->timeout - jiffies)); +} + +static void __ar9170_dump_txqueue(struct ar9170 *ar, + struct sk_buff_head *queue) +{ + struct sk_buff *skb; + int i = 0; + + printk(KERN_DEBUG "---[ cut here ]---\n"); + printk(KERN_DEBUG "%s: %d entries in queue.\n", + wiphy_name(ar->hw->wiphy), skb_queue_len(queue)); + + skb_queue_walk(queue, skb) { + printk(KERN_DEBUG "index:%d => \n", i++); + ar9170_print_txheader(ar, skb); + } + if (i != skb_queue_len(queue)) + printk(KERN_DEBUG "WARNING: queue frame counter " + "mismatch %d != %d\n", skb_queue_len(queue), i); + printk(KERN_DEBUG "---[ end ]---\n"); +} + +static void ar9170_dump_txqueue(struct ar9170 *ar, + struct sk_buff_head *queue) +{ + unsigned long flags; + + spin_lock_irqsave(&queue->lock, flags); + __ar9170_dump_txqueue(ar, queue); + spin_unlock_irqrestore(&queue->lock, flags); +} + +static void __ar9170_dump_txstats(struct ar9170 *ar) +{ + int i; + + printk(KERN_DEBUG "%s: QoS queue stats\n", + wiphy_name(ar->hw->wiphy)); + + for (i = 0; i < __AR9170_NUM_TXQ; i++) + printk(KERN_DEBUG "%s: queue:%d limit:%d len:%d waitack:%d\n", + wiphy_name(ar->hw->wiphy), i, ar->tx_stats[i].limit, + ar->tx_stats[i].len, skb_queue_len(&ar->tx_status[i])); +} + +static void ar9170_dump_txstats(struct ar9170 *ar) { - struct ieee80211_tx_info *txinfo; - unsigned int retries = 0, queue = skb_get_queue_mapping(skb); unsigned long flags; spin_lock_irqsave(&ar->tx_stats_lock, flags); - ar->tx_stats[queue].len--; - if (ieee80211_queue_stopped(ar->hw, queue)) - ieee80211_wake_queue(ar->hw, queue); + __ar9170_dump_txstats(ar); spin_unlock_irqrestore(&ar->tx_stats_lock, flags); +} +#endif /* AR9170_QUEUE_DEBUG */ + +/* caller must guarantee exclusive access for _bin_ queue. */ +static void ar9170_recycle_expired(struct ar9170 *ar, + struct sk_buff_head *queue, + struct sk_buff_head *bin) +{ + struct sk_buff *skb, *old = NULL; + unsigned long flags; + + spin_lock_irqsave(&queue->lock, flags); + while ((skb = skb_peek(queue))) { + struct ieee80211_tx_info *txinfo; + struct ar9170_tx_info *arinfo; + + txinfo = IEEE80211_SKB_CB(skb); + arinfo = (void *) txinfo->rate_driver_data; + + if (time_is_before_jiffies(arinfo->timeout)) { +#ifdef AR9170_QUEUE_DEBUG + printk(KERN_DEBUG "%s: [%ld > %ld] frame expired => " + "recycle \n", wiphy_name(ar->hw->wiphy), + jiffies, arinfo->timeout); + ar9170_print_txheader(ar, skb); +#endif /* AR9170_QUEUE_DEBUG */ + __skb_unlink(skb, queue); + __skb_queue_tail(bin, skb); + } else { + break; + } + + if (unlikely(old == skb)) { + /* bail out - queue is shot. */ + + WARN_ON(1); + break; + } + old = skb; + } + spin_unlock_irqrestore(&queue->lock, flags); +} + +static void ar9170_tx_status(struct ar9170 *ar, struct sk_buff *skb, + u16 tx_status) +{ + struct ieee80211_tx_info *txinfo; + unsigned int retries = 0; txinfo = IEEE80211_SKB_CB(skb); ieee80211_tx_info_clear_status(txinfo); @@ -230,45 +310,61 @@ void ar9170_handle_tx_status(struct ar9170 *ar, struct sk_buff *skb, break; } - if (valid_status) - txinfo->status.rates[0].count = retries + 1; - + txinfo->status.rates[0].count = retries + 1; skb_pull(skb, sizeof(struct ar9170_tx_control)); ieee80211_tx_status_irqsafe(ar->hw, skb); } -static struct sk_buff *ar9170_find_skb_in_queue(struct ar9170 *ar, - const u8 *mac, - const u32 queue, - struct sk_buff_head *q) +void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ar9170_tx_info *arinfo = (void *) info->rate_driver_data; + unsigned int queue = skb_get_queue_mapping(skb); unsigned long flags; - struct sk_buff *skb; - spin_lock_irqsave(&q->lock, flags); - skb_queue_walk(q, skb) { - struct ar9170_tx_control *txc = (void *) skb->data; - struct ieee80211_hdr *hdr = (void *) txc->frame_data; - u32 txc_queue = (le32_to_cpu(txc->phy_control) & - AR9170_TX_PHY_QOS_MASK) >> - AR9170_TX_PHY_QOS_SHIFT; + spin_lock_irqsave(&ar->tx_stats_lock, flags); + ar->tx_stats[queue].len--; - if ((queue != txc_queue) || - (compare_ether_addr(ieee80211_get_DA(hdr), mac))) - continue; - - __skb_unlink(skb, q); - spin_unlock_irqrestore(&q->lock, flags); - return skb; + if (skb_queue_empty(&ar->tx_pending[queue])) { +#ifdef AR9170_QUEUE_STOP_DEBUG + printk(KERN_DEBUG "%s: wake queue %d\n", + wiphy_name(ar->hw->wiphy), queue); + __ar9170_dump_txstats(ar); +#endif /* AR9170_QUEUE_STOP_DEBUG */ + ieee80211_wake_queue(ar->hw, queue); + } + spin_unlock_irqrestore(&ar->tx_stats_lock, flags); + + if (arinfo->flags & AR9170_TX_FLAG_BLOCK_ACK) { + dev_kfree_skb_any(skb); + } else if (arinfo->flags & AR9170_TX_FLAG_WAIT_FOR_ACK) { + arinfo->timeout = jiffies + + msecs_to_jiffies(AR9170_TX_TIMEOUT); + + skb_queue_tail(&ar->tx_status[queue], skb); + } else if (arinfo->flags & AR9170_TX_FLAG_NO_ACK) { + ar9170_tx_status(ar, skb, AR9170_TX_STATUS_FAILED); + } else { +#ifdef AR9170_QUEUE_DEBUG + printk(KERN_DEBUG "%s: unsupported frame flags!\n", + wiphy_name(ar->hw->wiphy)); + ar9170_print_txheader(ar, skb); +#endif /* AR9170_QUEUE_DEBUG */ + dev_kfree_skb_any(skb); + } + + if (!ar->tx_stats[queue].len && + !skb_queue_empty(&ar->tx_pending[queue])) { + ar9170_tx(ar); } - spin_unlock_irqrestore(&q->lock, flags); - return NULL; } -static struct sk_buff *ar9170_find_queued_skb(struct ar9170 *ar, const u8 *mac, - const u32 queue) +static struct sk_buff *ar9170_get_queued_skb(struct ar9170 *ar, + const u8 *mac, + struct sk_buff_head *queue, + const u32 rate) { - struct ieee80211_sta *sta; + unsigned long flags; struct sk_buff *skb; /* @@ -279,85 +375,94 @@ static struct sk_buff *ar9170_find_queued_skb(struct ar9170 *ar, const u8 *mac, * the firmware provided (-> destination MAC, and phy_control) - * and hope that we picked the right one... */ - rcu_read_lock(); - sta = ieee80211_find_sta(ar->hw, mac); - if (likely(sta)) { - struct ar9170_sta_info *sta_priv = (void *) sta->drv_priv; - skb = skb_dequeue(&sta_priv->tx_status[queue]); - rcu_read_unlock(); - if (likely(skb)) - return skb; - } else - rcu_read_unlock(); + spin_lock_irqsave(&queue->lock, flags); + skb_queue_walk(queue, skb) { + struct ar9170_tx_control *txc = (void *) skb->data; + struct ieee80211_hdr *hdr = (void *) txc->frame_data; + u32 r; - /* scan the waste queue for candidates */ - skb = ar9170_find_skb_in_queue(ar, mac, queue, - &ar->global_tx_status_waste); - if (!skb) { - /* so it still _must_ be in the global list. */ - skb = ar9170_find_skb_in_queue(ar, mac, queue, - &ar->global_tx_status); + if (mac && compare_ether_addr(ieee80211_get_DA(hdr), mac)) { +#ifdef AR9170_QUEUE_DEBUG + printk(KERN_DEBUG "%s: skip frame => DA %pM != %pM\n", + wiphy_name(ar->hw->wiphy), mac, + ieee80211_get_DA(hdr)); + ar9170_print_txheader(ar, skb); +#endif /* AR9170_QUEUE_DEBUG */ + continue; + } + + r = (le32_to_cpu(txc->phy_control) & AR9170_TX_PHY_MCS_MASK) >> + AR9170_TX_PHY_MCS_SHIFT; + + if ((rate != AR9170_TX_INVALID_RATE) && (r != rate)) { +#ifdef AR9170_QUEUE_DEBUG + printk(KERN_DEBUG "%s: skip frame => rate %d != %d\n", + wiphy_name(ar->hw->wiphy), rate, r); + ar9170_print_txheader(ar, skb); +#endif /* AR9170_QUEUE_DEBUG */ + continue; + } + + __skb_unlink(skb, queue); + spin_unlock_irqrestore(&queue->lock, flags); + return skb; } #ifdef AR9170_QUEUE_DEBUG - if (unlikely((!skb) && net_ratelimit())) { - printk(KERN_ERR "%s: ESS:[%pM] does not have any " - "outstanding frames in this queue (%d).\n", - wiphy_name(ar->hw->wiphy), mac, queue); - } + printk(KERN_ERR "%s: ESS:[%pM] does not have any " + "outstanding frames in queue.\n", + wiphy_name(ar->hw->wiphy), mac); + __ar9170_dump_txqueue(ar, queue); #endif /* AR9170_QUEUE_DEBUG */ - return skb; + spin_unlock_irqrestore(&queue->lock, flags); + + return NULL; } /* - * This worker tries to keep the global tx_status queue empty. - * So we can guarantee that incoming tx_status reports for - * unregistered stations are always synced with the actual - * frame - which we think - belongs to. + * This worker tries to keeps an maintain tx_status queues. + * So we can guarantee that incoming tx_status reports are + * actually for a pending frame. */ -static void ar9170_tx_status_janitor(struct work_struct *work) +static void ar9170_tx_janitor(struct work_struct *work) { struct ar9170 *ar = container_of(work, struct ar9170, - tx_status_janitor.work); - struct sk_buff *skb; + tx_janitor.work); + struct sk_buff_head waste; + unsigned int i; + bool resched = false; if (unlikely(!IS_STARTED(ar))) return ; - mutex_lock(&ar->mutex); - /* recycle the garbage back to mac80211... one by one. */ - while ((skb = skb_dequeue(&ar->global_tx_status_waste))) { + skb_queue_head_init(&waste); + + for (i = 0; i < __AR9170_NUM_TXQ; i++) { #ifdef AR9170_QUEUE_DEBUG - printk(KERN_DEBUG "%s: dispose queued frame =>\n", - wiphy_name(ar->hw->wiphy)); - ar9170_print_txheader(ar, skb); + printk(KERN_DEBUG "%s: garbage collector scans queue:%d\n", + wiphy_name(ar->hw->wiphy), i); + ar9170_dump_txqueue(ar, &ar->tx_pending[i]); + ar9170_dump_txqueue(ar, &ar->tx_status[i]); #endif /* AR9170_QUEUE_DEBUG */ - ar9170_handle_tx_status(ar, skb, false, - AR9170_TX_STATUS_FAILED); + + ar9170_recycle_expired(ar, &ar->tx_status[i], &waste); + ar9170_recycle_expired(ar, &ar->tx_pending[i], &waste); + skb_queue_purge(&waste); + + if (!skb_queue_empty(&ar->tx_status[i]) || + !skb_queue_empty(&ar->tx_pending[i])) + resched = true; } - while ((skb = skb_dequeue(&ar->global_tx_status))) { -#ifdef AR9170_QUEUE_DEBUG - printk(KERN_DEBUG "%s: moving frame into waste queue =>\n", - wiphy_name(ar->hw->wiphy)); - - ar9170_print_txheader(ar, skb); -#endif /* AR9170_QUEUE_DEBUG */ - skb_queue_tail(&ar->global_tx_status_waste, skb); - } - - /* recall the janitor in 100ms - if there's garbage in the can. */ - if (skb_queue_len(&ar->global_tx_status_waste) > 0) - queue_delayed_work(ar->hw->workqueue, &ar->tx_status_janitor, - msecs_to_jiffies(100)); - - mutex_unlock(&ar->mutex); + if (resched) + queue_delayed_work(ar->hw->workqueue, + &ar->tx_janitor, + msecs_to_jiffies(AR9170_JANITOR_DELAY)); } -static void ar9170_handle_command_response(struct ar9170 *ar, - void *buf, u32 len) +void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len) { struct ar9170_cmd_response *cmd = (void *) buf; @@ -381,15 +486,21 @@ static void ar9170_handle_command_response(struct ar9170 *ar, */ struct sk_buff *skb; - u32 queue = (le32_to_cpu(cmd->tx_status.rate) & - AR9170_TX_PHY_QOS_MASK) >> AR9170_TX_PHY_QOS_SHIFT; + u32 phy = le32_to_cpu(cmd->tx_status.rate); + u32 q = (phy & AR9170_TX_PHY_QOS_MASK) >> + AR9170_TX_PHY_QOS_SHIFT; +#ifdef AR9170_QUEUE_DEBUG + printk(KERN_DEBUG "%s: recv tx_status for %pM, p:%08x, q:%d\n", + wiphy_name(ar->hw->wiphy), cmd->tx_status.dst, phy, q); +#endif /* AR9170_QUEUE_DEBUG */ - skb = ar9170_find_queued_skb(ar, cmd->tx_status.dst, queue); + skb = ar9170_get_queued_skb(ar, cmd->tx_status.dst, + &ar->tx_status[q], + AR9170_TX_INVALID_RATE); if (unlikely(!skb)) return ; - ar9170_handle_tx_status(ar, skb, true, - le16_to_cpu(cmd->tx_status.status)); + ar9170_tx_status(ar, skb, le16_to_cpu(cmd->tx_status.status)); break; } @@ -429,6 +540,38 @@ static void ar9170_handle_command_response(struct ar9170 *ar, /* retransmission issue / SIFS/EIFS collision ?! */ break; + /* firmware debug */ + case 0xca: + printk(KERN_DEBUG "ar9170 FW: %.*s\n", len - 4, (char *)buf + 4); + break; + case 0xcb: + len -= 4; + + switch (len) { + case 1: + printk(KERN_DEBUG "ar9170 FW: u8: %#.2x\n", + *((char *)buf + 4)); + break; + case 2: + printk(KERN_DEBUG "ar9170 FW: u8: %#.4x\n", + le16_to_cpup((__le16 *)((char *)buf + 4))); + break; + case 4: + printk(KERN_DEBUG "ar9170 FW: u8: %#.8x\n", + le32_to_cpup((__le32 *)((char *)buf + 4))); + break; + case 8: + printk(KERN_DEBUG "ar9170 FW: u8: %#.16lx\n", + (unsigned long)le64_to_cpup( + (__le64 *)((char *)buf + 4))); + break; + } + break; + case 0xcc: + print_hex_dump_bytes("ar9170 FW:", DUMP_PREFIX_NONE, + (char *)buf + 4, len - 4); + break; + default: printk(KERN_INFO "received unhandled event %x\n", cmd->type); print_hex_dump_bytes("dump:", DUMP_PREFIX_NONE, buf, len); @@ -436,214 +579,430 @@ static void ar9170_handle_command_response(struct ar9170 *ar, } } -/* - * If the frame alignment is right (or the kernel has - * CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS), and there - * is only a single MPDU in the USB frame, then we can - * submit to mac80211 the SKB directly. However, since - * there may be multiple packets in one SKB in stream - * mode, and we need to observe the proper ordering, - * this is non-trivial. - */ -static void ar9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len) +static void ar9170_rx_reset_rx_mpdu(struct ar9170 *ar) { - struct sk_buff *skb; - struct ar9170_rx_head *head = (void *)buf; - struct ar9170_rx_tail *tail; - struct ieee80211_rx_status status; - int mpdu_len, i; - u8 error, antennas = 0, decrypt; - __le16 fc; - int reserved; + memset(&ar->rx_mpdu.plcp, 0, sizeof(struct ar9170_rx_head)); + ar->rx_mpdu.has_plcp = false; +} - if (unlikely(!IS_STARTED(ar))) - return ; +int ar9170_nag_limiter(struct ar9170 *ar) +{ + bool print_message; + + /* + * we expect all sorts of errors in promiscuous mode. + * don't bother with it, it's OK! + */ + if (ar->sniffer_enabled) + return false; + + /* + * only go for frequent errors! The hardware tends to + * do some stupid thing once in a while under load, in + * noisy environments or just for fun! + */ + if (time_before(jiffies, ar->bad_hw_nagger) && net_ratelimit()) + print_message = true; + else + print_message = false; + + /* reset threshold for "once in a while" */ + ar->bad_hw_nagger = jiffies + HZ / 4; + return print_message; +} + +static int ar9170_rx_mac_status(struct ar9170 *ar, + struct ar9170_rx_head *head, + struct ar9170_rx_macstatus *mac, + struct ieee80211_rx_status *status) +{ + u8 error, decrypt; - /* Received MPDU */ - mpdu_len = len; - mpdu_len -= sizeof(struct ar9170_rx_head); - mpdu_len -= sizeof(struct ar9170_rx_tail); BUILD_BUG_ON(sizeof(struct ar9170_rx_head) != 12); - BUILD_BUG_ON(sizeof(struct ar9170_rx_tail) != 24); - - if (mpdu_len <= FCS_LEN) - return; - - tail = (void *)(buf + sizeof(struct ar9170_rx_head) + mpdu_len); - - for (i = 0; i < 3; i++) - if (tail->rssi[i] != 0x80) - antennas |= BIT(i); - - /* post-process RSSI */ - for (i = 0; i < 7; i++) - if (tail->rssi[i] & 0x80) - tail->rssi[i] = ((tail->rssi[i] & 0x7f) + 1) & 0x7f; - - memset(&status, 0, sizeof(status)); - - status.band = ar->channel->band; - status.freq = ar->channel->center_freq; - status.signal = ar->noise[0] + tail->rssi_combined; - status.noise = ar->noise[0]; - status.antenna = antennas; - - switch (tail->status & AR9170_RX_STATUS_MODULATION_MASK) { - case AR9170_RX_STATUS_MODULATION_CCK: - if (tail->status & AR9170_RX_STATUS_SHORT_PREAMBLE) - status.flag |= RX_FLAG_SHORTPRE; - switch (head->plcp[0]) { - case 0x0a: - status.rate_idx = 0; - break; - case 0x14: - status.rate_idx = 1; - break; - case 0x37: - status.rate_idx = 2; - break; - case 0x6e: - status.rate_idx = 3; - break; - default: - if ((!ar->sniffer_enabled) && (net_ratelimit())) - printk(KERN_ERR "%s: invalid plcp cck rate " - "(%x).\n", wiphy_name(ar->hw->wiphy), - head->plcp[0]); - return; - } - break; - case AR9170_RX_STATUS_MODULATION_OFDM: - switch (head->plcp[0] & 0xF) { - case 0xB: - status.rate_idx = 0; - break; - case 0xF: - status.rate_idx = 1; - break; - case 0xA: - status.rate_idx = 2; - break; - case 0xE: - status.rate_idx = 3; - break; - case 0x9: - status.rate_idx = 4; - break; - case 0xD: - status.rate_idx = 5; - break; - case 0x8: - status.rate_idx = 6; - break; - case 0xC: - status.rate_idx = 7; - break; - default: - if ((!ar->sniffer_enabled) && (net_ratelimit())) - printk(KERN_ERR "%s: invalid plcp ofdm rate " - "(%x).\n", wiphy_name(ar->hw->wiphy), - head->plcp[0]); - return; - } - if (status.band == IEEE80211_BAND_2GHZ) - status.rate_idx += 4; - break; - case AR9170_RX_STATUS_MODULATION_HT: - case AR9170_RX_STATUS_MODULATION_DUPOFDM: - /* XXX */ - - if (net_ratelimit()) - printk(KERN_ERR "%s: invalid modulation\n", - wiphy_name(ar->hw->wiphy)); - return; - } - - error = tail->error; + BUILD_BUG_ON(sizeof(struct ar9170_rx_macstatus) != 4); + error = mac->error; if (error & AR9170_RX_ERROR_MMIC) { - status.flag |= RX_FLAG_MMIC_ERROR; + status->flag |= RX_FLAG_MMIC_ERROR; error &= ~AR9170_RX_ERROR_MMIC; } if (error & AR9170_RX_ERROR_PLCP) { - status.flag |= RX_FLAG_FAILED_PLCP_CRC; + status->flag |= RX_FLAG_FAILED_PLCP_CRC; error &= ~AR9170_RX_ERROR_PLCP; + + if (!(ar->filter_state & FIF_PLCPFAIL)) + return -EINVAL; } if (error & AR9170_RX_ERROR_FCS) { - status.flag |= RX_FLAG_FAILED_FCS_CRC; + status->flag |= RX_FLAG_FAILED_FCS_CRC; error &= ~AR9170_RX_ERROR_FCS; + + if (!(ar->filter_state & FIF_FCSFAIL)) + return -EINVAL; } - decrypt = ar9170_get_decrypt_type(tail); + decrypt = ar9170_get_decrypt_type(mac); if (!(decrypt & AR9170_RX_ENC_SOFTWARE) && decrypt != AR9170_ENC_ALG_NONE) - status.flag |= RX_FLAG_DECRYPTED; + status->flag |= RX_FLAG_DECRYPTED; /* ignore wrong RA errors */ error &= ~AR9170_RX_ERROR_WRONG_RA; if (error & AR9170_RX_ERROR_DECRYPT) { error &= ~AR9170_RX_ERROR_DECRYPT; - /* * Rx decryption is done in place, * the original data is lost anyway. */ - return ; + + return -EINVAL; } /* drop any other error frames */ - if ((error) && (net_ratelimit())) { - printk(KERN_DEBUG "%s: errors: %#x\n", - wiphy_name(ar->hw->wiphy), error); - return; + if (unlikely(error)) { + /* TODO: update netdevice's RX dropped/errors statistics */ + + if (ar9170_nag_limiter(ar)) + printk(KERN_DEBUG "%s: received frame with " + "suspicious error code (%#x).\n", + wiphy_name(ar->hw->wiphy), error); + + return -EINVAL; } - buf += sizeof(struct ar9170_rx_head); - fc = *(__le16 *)buf; + status->band = ar->channel->band; + status->freq = ar->channel->center_freq; - if (ieee80211_is_data_qos(fc) ^ ieee80211_has_a4(fc)) - reserved = 32 + 2; - else - reserved = 32; + switch (mac->status & AR9170_RX_STATUS_MODULATION_MASK) { + case AR9170_RX_STATUS_MODULATION_CCK: + if (mac->status & AR9170_RX_STATUS_SHORT_PREAMBLE) + status->flag |= RX_FLAG_SHORTPRE; + switch (head->plcp[0]) { + case 0x0a: + status->rate_idx = 0; + break; + case 0x14: + status->rate_idx = 1; + break; + case 0x37: + status->rate_idx = 2; + break; + case 0x6e: + status->rate_idx = 3; + break; + default: + if (ar9170_nag_limiter(ar)) + printk(KERN_ERR "%s: invalid plcp cck rate " + "(%x).\n", wiphy_name(ar->hw->wiphy), + head->plcp[0]); + return -EINVAL; + } + break; - skb = dev_alloc_skb(mpdu_len + reserved); - if (!skb) - return; + case AR9170_RX_STATUS_MODULATION_OFDM: + switch (head->plcp[0] & 0xf) { + case 0xb: + status->rate_idx = 0; + break; + case 0xf: + status->rate_idx = 1; + break; + case 0xa: + status->rate_idx = 2; + break; + case 0xe: + status->rate_idx = 3; + break; + case 0x9: + status->rate_idx = 4; + break; + case 0xd: + status->rate_idx = 5; + break; + case 0x8: + status->rate_idx = 6; + break; + case 0xc: + status->rate_idx = 7; + break; + default: + if (ar9170_nag_limiter(ar)) + printk(KERN_ERR "%s: invalid plcp ofdm rate " + "(%x).\n", wiphy_name(ar->hw->wiphy), + head->plcp[0]); + return -EINVAL; + } + if (status->band == IEEE80211_BAND_2GHZ) + status->rate_idx += 4; + break; - skb_reserve(skb, reserved); - memcpy(skb_put(skb, mpdu_len), buf, mpdu_len); - ieee80211_rx_irqsafe(ar->hw, skb, &status); + case AR9170_RX_STATUS_MODULATION_HT: + if (head->plcp[3] & 0x80) + status->flag |= RX_FLAG_40MHZ; + if (head->plcp[6] & 0x80) + status->flag |= RX_FLAG_SHORT_GI; + + status->rate_idx = clamp(0, 75, head->plcp[6] & 0x7f); + status->flag |= RX_FLAG_HT; + break; + + case AR9170_RX_STATUS_MODULATION_DUPOFDM: + /* XXX */ + if (ar9170_nag_limiter(ar)) + printk(KERN_ERR "%s: invalid modulation\n", + wiphy_name(ar->hw->wiphy)); + return -EINVAL; + } + + return 0; +} + +static void ar9170_rx_phy_status(struct ar9170 *ar, + struct ar9170_rx_phystatus *phy, + struct ieee80211_rx_status *status) +{ + int i; + + BUILD_BUG_ON(sizeof(struct ar9170_rx_phystatus) != 20); + + for (i = 0; i < 3; i++) + if (phy->rssi[i] != 0x80) + status->antenna |= BIT(i); + + /* post-process RSSI */ + for (i = 0; i < 7; i++) + if (phy->rssi[i] & 0x80) + phy->rssi[i] = ((phy->rssi[i] & 0x7f) + 1) & 0x7f; + + /* TODO: we could do something with phy_errors */ + status->signal = ar->noise[0] + phy->rssi_combined; + status->noise = ar->noise[0]; +} + +static struct sk_buff *ar9170_rx_copy_data(u8 *buf, int len) +{ + struct sk_buff *skb; + int reserved = 0; + struct ieee80211_hdr *hdr = (void *) buf; + + if (ieee80211_is_data_qos(hdr->frame_control)) { + u8 *qc = ieee80211_get_qos_ctl(hdr); + reserved += NET_IP_ALIGN; + + if (*qc & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT) + reserved += NET_IP_ALIGN; + } + + if (ieee80211_has_a4(hdr->frame_control)) + reserved += NET_IP_ALIGN; + + reserved = 32 + (reserved & NET_IP_ALIGN); + + skb = dev_alloc_skb(len + reserved); + if (likely(skb)) { + skb_reserve(skb, reserved); + memcpy(skb_put(skb, len), buf, len); + } + + return skb; +} + +/* + * If the frame alignment is right (or the kernel has + * CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS), and there + * is only a single MPDU in the USB frame, then we could + * submit to mac80211 the SKB directly. However, since + * there may be multiple packets in one SKB in stream + * mode, and we need to observe the proper ordering, + * this is non-trivial. + */ + +static void ar9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len) +{ + struct ar9170_rx_head *head; + struct ar9170_rx_macstatus *mac; + struct ar9170_rx_phystatus *phy = NULL; + struct ieee80211_rx_status status; + struct sk_buff *skb; + int mpdu_len; + + if (unlikely(!IS_STARTED(ar) || len < (sizeof(*mac)))) + return ; + + /* Received MPDU */ + mpdu_len = len - sizeof(*mac); + + mac = (void *)(buf + mpdu_len); + if (unlikely(mac->error & AR9170_RX_ERROR_FATAL)) { + /* this frame is too damaged and can't be used - drop it */ + + return ; + } + + switch (mac->status & AR9170_RX_STATUS_MPDU_MASK) { + case AR9170_RX_STATUS_MPDU_FIRST: + /* first mpdu packet has the plcp header */ + if (likely(mpdu_len >= sizeof(struct ar9170_rx_head))) { + head = (void *) buf; + memcpy(&ar->rx_mpdu.plcp, (void *) buf, + sizeof(struct ar9170_rx_head)); + + mpdu_len -= sizeof(struct ar9170_rx_head); + buf += sizeof(struct ar9170_rx_head); + ar->rx_mpdu.has_plcp = true; + } else { + if (ar9170_nag_limiter(ar)) + printk(KERN_ERR "%s: plcp info is clipped.\n", + wiphy_name(ar->hw->wiphy)); + return ; + } + break; + + case AR9170_RX_STATUS_MPDU_LAST: + /* last mpdu has a extra tail with phy status information */ + + if (likely(mpdu_len >= sizeof(struct ar9170_rx_phystatus))) { + mpdu_len -= sizeof(struct ar9170_rx_phystatus); + phy = (void *)(buf + mpdu_len); + } else { + if (ar9170_nag_limiter(ar)) + printk(KERN_ERR "%s: frame tail is clipped.\n", + wiphy_name(ar->hw->wiphy)); + return ; + } + + case AR9170_RX_STATUS_MPDU_MIDDLE: + /* middle mpdus are just data */ + if (unlikely(!ar->rx_mpdu.has_plcp)) { + if (!ar9170_nag_limiter(ar)) + return ; + + printk(KERN_ERR "%s: rx stream did not start " + "with a first_mpdu frame tag.\n", + wiphy_name(ar->hw->wiphy)); + + return ; + } + + head = &ar->rx_mpdu.plcp; + break; + + case AR9170_RX_STATUS_MPDU_SINGLE: + /* single mpdu - has plcp (head) and phy status (tail) */ + head = (void *) buf; + + mpdu_len -= sizeof(struct ar9170_rx_head); + mpdu_len -= sizeof(struct ar9170_rx_phystatus); + + buf += sizeof(struct ar9170_rx_head); + phy = (void *)(buf + mpdu_len); + break; + + default: + BUG_ON(1); + break; + } + + if (unlikely(mpdu_len < FCS_LEN)) + return ; + + memset(&status, 0, sizeof(status)); + if (unlikely(ar9170_rx_mac_status(ar, head, mac, &status))) + return ; + + if (phy) + ar9170_rx_phy_status(ar, phy, &status); + + skb = ar9170_rx_copy_data(buf, mpdu_len); + if (likely(skb)) + ieee80211_rx_irqsafe(ar->hw, skb, &status); } void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb) { - unsigned int i, tlen, resplen; + unsigned int i, tlen, resplen, wlen = 0, clen = 0; u8 *tbuf, *respbuf; tbuf = skb->data; tlen = skb->len; while (tlen >= 4) { - int clen = tbuf[1] << 8 | tbuf[0]; - int wlen = (clen + 3) & ~3; + clen = tbuf[1] << 8 | tbuf[0]; + wlen = ALIGN(clen, 4); - /* - * parse stream (if any) - */ + /* check if this is stream has a valid tag.*/ if (tbuf[2] != 0 || tbuf[3] != 0x4e) { - printk(KERN_ERR "%s: missing tag!\n", - wiphy_name(ar->hw->wiphy)); + /* + * TODO: handle the highly unlikely event that the + * corrupted stream has the TAG at the right position. + */ + + /* check if the frame can be repaired. */ + if (!ar->rx_failover_missing) { + /* this is no "short read". */ + if (ar9170_nag_limiter(ar)) { + printk(KERN_ERR "%s: missing tag!\n", + wiphy_name(ar->hw->wiphy)); + goto err_telluser; + } else + goto err_silent; + } + + if (ar->rx_failover_missing > tlen) { + if (ar9170_nag_limiter(ar)) { + printk(KERN_ERR "%s: possible multi " + "stream corruption!\n", + wiphy_name(ar->hw->wiphy)); + goto err_telluser; + } else + goto err_silent; + } + + memcpy(skb_put(ar->rx_failover, tlen), tbuf, tlen); + ar->rx_failover_missing -= tlen; + + if (ar->rx_failover_missing <= 0) { + /* + * nested ar9170_rx call! + * termination is guranteed, even when the + * combined frame also have a element with + * a bad tag. + */ + + ar->rx_failover_missing = 0; + ar9170_rx(ar, ar->rx_failover); + + skb_reset_tail_pointer(ar->rx_failover); + skb_trim(ar->rx_failover, 0); + } + return ; } + + /* check if stream is clipped */ if (wlen > tlen - 4) { - printk(KERN_ERR "%s: invalid RX (%d, %d, %d)\n", - wiphy_name(ar->hw->wiphy), clen, wlen, tlen); - print_hex_dump(KERN_DEBUG, "data: ", - DUMP_PREFIX_OFFSET, - 16, 1, tbuf, tlen, true); + if (ar->rx_failover_missing) { + /* TODO: handle double stream corruption. */ + if (ar9170_nag_limiter(ar)) { + printk(KERN_ERR "%s: double rx stream " + "corruption!\n", + wiphy_name(ar->hw->wiphy)); + goto err_telluser; + } else + goto err_silent; + } + + /* + * save incomplete data set. + * the firmware will resend the missing bits when + * the rx - descriptor comes round again. + */ + + memcpy(skb_put(ar->rx_failover, tlen), tbuf, tlen); + ar->rx_failover_missing = clen - tlen; return ; } resplen = clen; @@ -668,12 +1027,44 @@ void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb) if (i == 12) ar9170_handle_command_response(ar, respbuf, resplen); else - ar9170_handle_mpdu(ar, respbuf, resplen); + ar9170_handle_mpdu(ar, respbuf, clen); } - if (tlen) - printk(KERN_ERR "%s: buffer remains!\n", - wiphy_name(ar->hw->wiphy)); + if (tlen) { + if (net_ratelimit()) + printk(KERN_ERR "%s: %d bytes of unprocessed " + "data left in rx stream!\n", + wiphy_name(ar->hw->wiphy), tlen); + + goto err_telluser; + } + + return ; + +err_telluser: + printk(KERN_ERR "%s: damaged RX stream data [want:%d, " + "data:%d, rx:%d, pending:%d ]\n", + wiphy_name(ar->hw->wiphy), clen, wlen, tlen, + ar->rx_failover_missing); + + if (ar->rx_failover_missing) + print_hex_dump_bytes("rxbuf:", DUMP_PREFIX_OFFSET, + ar->rx_failover->data, + ar->rx_failover->len); + + print_hex_dump_bytes("stream:", DUMP_PREFIX_OFFSET, + skb->data, skb->len); + + printk(KERN_ERR "%s: please check your hardware and cables, if " + "you see this message frequently.\n", + wiphy_name(ar->hw->wiphy)); + +err_silent: + if (ar->rx_failover_missing) { + skb_reset_tail_pointer(ar->rx_failover); + skb_trim(ar->rx_failover, 0); + ar->rx_failover_missing = 0; + } } #define AR9170_FILL_QUEUE(queue, ai_fs, cwmin, cwmax, _txop) \ @@ -691,10 +1082,12 @@ static int ar9170_op_start(struct ieee80211_hw *hw) mutex_lock(&ar->mutex); + ar->filter_changed = 0; + /* reinitialize queues statistics */ memset(&ar->tx_stats, 0, sizeof(ar->tx_stats)); - for (i = 0; i < ARRAY_SIZE(ar->tx_stats); i++) - ar->tx_stats[i].limit = 8; + for (i = 0; i < __AR9170_NUM_TXQ; i++) + ar->tx_stats[i].limit = AR9170_TXQ_DEPTH; /* reset QoS defaults */ AR9170_FILL_QUEUE(ar->edcf[0], 3, 15, 1023, 0); /* BEST EFFORT*/ @@ -703,6 +1096,8 @@ static int ar9170_op_start(struct ieee80211_hw *hw) AR9170_FILL_QUEUE(ar->edcf[3], 2, 3, 7, 47); /* VOICE */ AR9170_FILL_QUEUE(ar->edcf[4], 2, 3, 7, 0); /* SPECIAL */ + ar->bad_hw_nagger = jiffies; + err = ar->open(ar); if (err) goto out; @@ -738,17 +1133,17 @@ out: static void ar9170_op_stop(struct ieee80211_hw *hw) { struct ar9170 *ar = hw->priv; + unsigned int i; if (IS_STARTED(ar)) ar->state = AR9170_IDLE; - mutex_lock(&ar->mutex); + flush_workqueue(ar->hw->workqueue); - cancel_delayed_work_sync(&ar->tx_status_janitor); + cancel_delayed_work_sync(&ar->tx_janitor); cancel_work_sync(&ar->filter_config_work); cancel_work_sync(&ar->beacon_work); - skb_queue_purge(&ar->global_tx_status_waste); - skb_queue_purge(&ar->global_tx_status); + mutex_lock(&ar->mutex); if (IS_ACCEPTING_CMD(ar)) { ar9170_set_leds_state(ar, 0); @@ -758,51 +1153,32 @@ static void ar9170_op_stop(struct ieee80211_hw *hw) ar->stop(ar); } + for (i = 0; i < __AR9170_NUM_TXQ; i++) { + skb_queue_purge(&ar->tx_pending[i]); + skb_queue_purge(&ar->tx_status[i]); + } mutex_unlock(&ar->mutex); } -int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) +static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb) { - struct ar9170 *ar = hw->priv; struct ieee80211_hdr *hdr; struct ar9170_tx_control *txc; struct ieee80211_tx_info *info; - struct ieee80211_rate *rate = NULL; struct ieee80211_tx_rate *txrate; + struct ar9170_tx_info *arinfo; unsigned int queue = skb_get_queue_mapping(skb); - unsigned long flags = 0; - struct ar9170_sta_info *sta_info = NULL; - u32 power, chains; u16 keytype = 0; u16 len, icv = 0; - int err; - bool tx_status; - if (unlikely(!IS_STARTED(ar))) - goto err_free; + BUILD_BUG_ON(sizeof(*arinfo) > sizeof(info->rate_driver_data)); hdr = (void *)skb->data; info = IEEE80211_SKB_CB(skb); len = skb->len; - spin_lock_irqsave(&ar->tx_stats_lock, flags); - if (ar->tx_stats[queue].limit < ar->tx_stats[queue].len) { - spin_unlock_irqrestore(&ar->tx_stats_lock, flags); - return NETDEV_TX_OK; - } - - ar->tx_stats[queue].len++; - ar->tx_stats[queue].count++; - if (ar->tx_stats[queue].limit == ar->tx_stats[queue].len) - ieee80211_stop_queue(hw, queue); - - spin_unlock_irqrestore(&ar->tx_stats_lock, flags); - txc = (void *)skb_push(skb, sizeof(*txc)); - tx_status = (((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) != 0) || - ((info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) != 0)); - if (info->control.hw_key) { icv = info->control.hw_key->icv_len; @@ -818,7 +1194,7 @@ int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) break; default: WARN_ON(1); - goto err_dequeue; + goto err_out; } } @@ -835,16 +1211,65 @@ int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) if (info->flags & IEEE80211_TX_CTL_NO_ACK) txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_NO_ACK); - if (info->flags & IEEE80211_TX_CTL_AMPDU) - txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_AGGR); - txrate = &info->control.rates[0]; - if (txrate->flags & IEEE80211_TX_RC_USE_CTS_PROTECT) txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_PROT_CTS); else if (txrate->flags & IEEE80211_TX_RC_USE_RTS_CTS) txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_PROT_RTS); + arinfo = (void *)info->rate_driver_data; + arinfo->timeout = jiffies + msecs_to_jiffies(AR9170_QUEUE_TIMEOUT); + + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && + (is_valid_ether_addr(ieee80211_get_DA(hdr)))) { + if (info->flags & IEEE80211_TX_CTL_AMPDU) { + if (unlikely(!info->control.sta)) + goto err_out; + + txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_AGGR); + arinfo->flags = AR9170_TX_FLAG_BLOCK_ACK; + goto out; + } + + txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_RATE_PROBE); + /* + * WARNING: + * Putting the QoS queue bits into an unexplored territory is + * certainly not elegant. + * + * In my defense: This idea provides a reasonable way to + * smuggle valuable information to the tx_status callback. + * Also, the idea behind this bit-abuse came straight from + * the original driver code. + */ + + txc->phy_control |= + cpu_to_le32(queue << AR9170_TX_PHY_QOS_SHIFT); + arinfo->flags = AR9170_TX_FLAG_WAIT_FOR_ACK; + } else { + arinfo->flags = AR9170_TX_FLAG_NO_ACK; + } + +out: + return 0; + +err_out: + skb_pull(skb, sizeof(*txc)); + return -EINVAL; +} + +static void ar9170_tx_prepare_phy(struct ar9170 *ar, struct sk_buff *skb) +{ + struct ar9170_tx_control *txc; + struct ieee80211_tx_info *info; + struct ieee80211_rate *rate = NULL; + struct ieee80211_tx_rate *txrate; + u32 power, chains; + + txc = (void *) skb->data; + info = IEEE80211_SKB_CB(skb); + txrate = &info->control.rates[0]; + if (txrate->flags & IEEE80211_TX_RC_GREEN_FIELD) txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_GREENFIELD); @@ -864,9 +1289,12 @@ int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) u32 r = txrate->idx; u8 *txpower; + /* heavy clip control */ + txc->phy_control |= cpu_to_le32((r & 0x7) << 7); + r <<= AR9170_TX_PHY_MCS_SHIFT; - if (WARN_ON(r & ~AR9170_TX_PHY_MCS_MASK)) - goto err_dequeue; + BUG_ON(r & ~AR9170_TX_PHY_MCS_MASK); + txc->phy_control |= cpu_to_le32(r & AR9170_TX_PHY_MCS_MASK); txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_MOD_HT); @@ -928,53 +1356,154 @@ int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) chains = AR9170_TX_PHY_TXCHAIN_1; } txc->phy_control |= cpu_to_le32(chains << AR9170_TX_PHY_TXCHAIN_SHIFT); +} - if (tx_status) { - txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_RATE_PROBE); - /* - * WARNING: - * Putting the QoS queue bits into an unexplored territory is - * certainly not elegant. - * - * In my defense: This idea provides a reasonable way to - * smuggle valuable information to the tx_status callback. - * Also, the idea behind this bit-abuse came straight from - * the original driver code. - */ +static void ar9170_tx(struct ar9170 *ar) +{ + struct sk_buff *skb; + unsigned long flags; + struct ieee80211_tx_info *info; + struct ar9170_tx_info *arinfo; + unsigned int i, frames, frames_failed, remaining_space; + int err; + bool schedule_garbagecollector = false; - txc->phy_control |= - cpu_to_le32(queue << AR9170_TX_PHY_QOS_SHIFT); + BUILD_BUG_ON(sizeof(*arinfo) > sizeof(info->rate_driver_data)); - if (info->control.sta) { - sta_info = (void *) info->control.sta->drv_priv; - skb_queue_tail(&sta_info->tx_status[queue], skb); - } else { - skb_queue_tail(&ar->global_tx_status, skb); + if (unlikely(!IS_STARTED(ar))) + return ; - queue_delayed_work(ar->hw->workqueue, - &ar->tx_status_janitor, - msecs_to_jiffies(100)); + remaining_space = AR9170_TX_MAX_PENDING; + + for (i = 0; i < __AR9170_NUM_TXQ; i++) { + spin_lock_irqsave(&ar->tx_stats_lock, flags); + if (ar->tx_stats[i].len >= ar->tx_stats[i].limit) { +#ifdef AR9170_QUEUE_DEBUG + printk(KERN_DEBUG "%s: queue %d full\n", + wiphy_name(ar->hw->wiphy), i); + + __ar9170_dump_txstats(ar); + printk(KERN_DEBUG "stuck frames: ===> \n"); + ar9170_dump_txqueue(ar, &ar->tx_pending[i]); + ar9170_dump_txqueue(ar, &ar->tx_status[i]); +#endif /* AR9170_QUEUE_DEBUG */ + ieee80211_stop_queue(ar->hw, i); + spin_unlock_irqrestore(&ar->tx_stats_lock, flags); + continue; + } + + frames = min(ar->tx_stats[i].limit - ar->tx_stats[i].len, + skb_queue_len(&ar->tx_pending[i])); + + if (remaining_space < frames) { +#ifdef AR9170_QUEUE_DEBUG + printk(KERN_DEBUG "%s: tx quota reached queue:%d, " + "remaining slots:%d, needed:%d\n", + wiphy_name(ar->hw->wiphy), i, remaining_space, + frames); + + ar9170_dump_txstats(ar); +#endif /* AR9170_QUEUE_DEBUG */ + frames = remaining_space; + } + + ar->tx_stats[i].len += frames; + ar->tx_stats[i].count += frames; + spin_unlock_irqrestore(&ar->tx_stats_lock, flags); + + if (!frames) + continue; + + frames_failed = 0; + while (frames) { + skb = skb_dequeue(&ar->tx_pending[i]); + if (unlikely(!skb)) { + frames_failed += frames; + frames = 0; + break; + } + + info = IEEE80211_SKB_CB(skb); + arinfo = (void *) info->rate_driver_data; + + /* TODO: cancel stuck frames */ + arinfo->timeout = jiffies + + msecs_to_jiffies(AR9170_TX_TIMEOUT); + +#ifdef AR9170_QUEUE_DEBUG + printk(KERN_DEBUG "%s: send frame q:%d =>\n", + wiphy_name(ar->hw->wiphy), i); + ar9170_print_txheader(ar, skb); +#endif /* AR9170_QUEUE_DEBUG */ + + err = ar->tx(ar, skb); + if (unlikely(err)) { + frames_failed++; + dev_kfree_skb_any(skb); + } else { + remaining_space--; + schedule_garbagecollector = true; + } + + frames--; + } + +#ifdef AR9170_QUEUE_DEBUG + printk(KERN_DEBUG "%s: ar9170_tx report for queue %d\n", + wiphy_name(ar->hw->wiphy), i); + + printk(KERN_DEBUG "%s: unprocessed pending frames left:\n", + wiphy_name(ar->hw->wiphy)); + ar9170_dump_txqueue(ar, &ar->tx_pending[i]); +#endif /* AR9170_QUEUE_DEBUG */ + + if (unlikely(frames_failed)) { +#ifdef AR9170_QUEUE_DEBUG + printk(KERN_DEBUG "%s: frames failed =>\n", + wiphy_name(ar->hw->wiphy), frames_failed); +#endif /* AR9170_QUEUE_DEBUG */ + + spin_lock_irqsave(&ar->tx_stats_lock, flags); + ar->tx_stats[i].len -= frames_failed; + ar->tx_stats[i].count -= frames_failed; + ieee80211_wake_queue(ar->hw, i); + spin_unlock_irqrestore(&ar->tx_stats_lock, flags); } } - err = ar->tx(ar, skb, tx_status, 0); - if (unlikely(tx_status && err)) { - if (info->control.sta) - skb_unlink(skb, &sta_info->tx_status[queue]); - else - skb_unlink(skb, &ar->global_tx_status); + if (schedule_garbagecollector) + queue_delayed_work(ar->hw->workqueue, + &ar->tx_janitor, + msecs_to_jiffies(AR9170_JANITOR_DELAY)); +} + +int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + struct ar9170 *ar = hw->priv; + struct ieee80211_tx_info *info; + + if (unlikely(!IS_STARTED(ar))) + goto err_free; + + if (unlikely(ar9170_tx_prepare(ar, skb))) + goto err_free; + + info = IEEE80211_SKB_CB(skb); + if (info->flags & IEEE80211_TX_CTL_AMPDU) { + /* drop frame, we do not allow TX A-MPDU aggregation yet. */ + goto err_free; + } else { + unsigned int queue = skb_get_queue_mapping(skb); + + ar9170_tx_prepare_phy(ar, skb); + skb_queue_tail(&ar->tx_pending[queue], skb); } + ar9170_tx(ar); return NETDEV_TX_OK; -err_dequeue: - spin_lock_irqsave(&ar->tx_stats_lock, flags); - ar->tx_stats[queue].len--; - ar->tx_stats[queue].count--; - spin_unlock_irqrestore(&ar->tx_stats_lock, flags); - err_free: - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); return NETDEV_TX_OK; } @@ -1037,11 +1566,6 @@ static int ar9170_op_config(struct ieee80211_hw *hw, u32 changed) mutex_lock(&ar->mutex); - if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED) { - /* TODO */ - err = 0; - } - if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) { /* TODO */ err = 0; @@ -1068,48 +1592,28 @@ static int ar9170_op_config(struct ieee80211_hw *hw, u32 changed) goto out; } - if (changed & IEEE80211_CONF_CHANGE_BEACON_INTERVAL) { + if (changed & BSS_CHANGED_BEACON_INT) { err = ar9170_set_beacon_timers(ar); if (err) goto out; } if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { - err = ar9170_set_channel(ar, hw->conf.channel, - AR9170_RFI_NONE, AR9170_BW_20); - if (err) - goto out; + /* adjust slot time for 5 GHz */ - if (hw->conf.channel->band == IEEE80211_BAND_5GHZ) - err = ar9170_write_reg(ar, AR9170_MAC_REG_SLOT_TIME, - 9 << 10); - } - -out: - mutex_unlock(&ar->mutex); - return err; -} - -static int ar9170_op_config_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_if_conf *conf) -{ - struct ar9170 *ar = hw->priv; - int err = 0; - - mutex_lock(&ar->mutex); - - if (conf->changed & IEEE80211_IFCC_BSSID) { - memcpy(ar->bssid, conf->bssid, ETH_ALEN); - err = ar9170_set_operating_mode(ar); - } - - if (conf->changed & IEEE80211_IFCC_BEACON) { - err = ar9170_update_beacon(ar); - + err = ar9170_set_slot_time(ar); + if (err) + goto out; + + err = ar9170_set_dyn_sifs_ack(ar); + if (err) + goto out; + + err = ar9170_set_channel(ar, hw->conf.channel, + AR9170_RFI_NONE, + nl80211_to_ar9170(hw->conf.channel_type)); if (err) goto out; - err = ar9170_set_beacon_timers(ar); } out: @@ -1123,24 +1627,30 @@ static void ar9170_set_filters(struct work_struct *work) filter_config_work); int err; - mutex_lock(&ar->mutex); if (unlikely(!IS_STARTED(ar))) - goto unlock; + return ; - if (ar->filter_changed & AR9170_FILTER_CHANGED_PROMISC) { + mutex_lock(&ar->mutex); + if (test_and_clear_bit(AR9170_FILTER_CHANGED_MODE, + &ar->filter_changed)) { err = ar9170_set_operating_mode(ar); if (err) goto unlock; } - if (ar->filter_changed & AR9170_FILTER_CHANGED_MULTICAST) { + if (test_and_clear_bit(AR9170_FILTER_CHANGED_MULTICAST, + &ar->filter_changed)) { err = ar9170_update_multicast(ar); if (err) goto unlock; } - if (ar->filter_changed & AR9170_FILTER_CHANGED_FRAMEFILTER) + if (test_and_clear_bit(AR9170_FILTER_CHANGED_FRAMEFILTER, + &ar->filter_changed)) { err = ar9170_update_frame_filter(ar); + if (err) + goto unlock; + } unlock: mutex_unlock(&ar->mutex); @@ -1155,8 +1665,8 @@ static void ar9170_op_configure_filter(struct ieee80211_hw *hw, /* mask supported flags */ *new_flags &= FIF_ALLMULTI | FIF_CONTROL | FIF_BCN_PRBRESP_PROMISC | - FIF_PROMISC_IN_BSS; - + FIF_PROMISC_IN_BSS | FIF_FCSFAIL | FIF_PLCPFAIL; + ar->filter_state = *new_flags; /* * We can support more by setting the sniffer bit and * then checking the error flags, later. @@ -1170,7 +1680,7 @@ static void ar9170_op_configure_filter(struct ieee80211_hw *hw, int i; /* always get broadcast frames */ - mchash = 1ULL << (0xff>>2); + mchash = 1ULL << (0xff >> 2); for (i = 0; i < mc_count; i++) { if (WARN_ON(!mclist)) @@ -1180,7 +1690,7 @@ static void ar9170_op_configure_filter(struct ieee80211_hw *hw, } ar->want_mc_hash = mchash; } - ar->filter_changed |= AR9170_FILTER_CHANGED_MULTICAST; + set_bit(AR9170_FILTER_CHANGED_MULTICAST, &ar->filter_changed); } if (changed_flags & FIF_CONTROL) { @@ -1196,12 +1706,14 @@ static void ar9170_op_configure_filter(struct ieee80211_hw *hw, else ar->want_filter = ar->cur_filter & ~filter; - ar->filter_changed |= AR9170_FILTER_CHANGED_FRAMEFILTER; + set_bit(AR9170_FILTER_CHANGED_FRAMEFILTER, + &ar->filter_changed); } if (changed_flags & FIF_PROMISC_IN_BSS) { ar->sniffer_enabled = ((*new_flags) & FIF_PROMISC_IN_BSS) != 0; - ar->filter_changed |= AR9170_FILTER_CHANGED_PROMISC; + set_bit(AR9170_FILTER_CHANGED_MODE, + &ar->filter_changed); } if (likely(IS_STARTED(ar))) @@ -1218,48 +1730,54 @@ static void ar9170_op_bss_info_changed(struct ieee80211_hw *hw, mutex_lock(&ar->mutex); - ar9170_regwrite_begin(ar); + if (changed & BSS_CHANGED_BSSID) { + memcpy(ar->bssid, bss_conf->bssid, ETH_ALEN); + err = ar9170_set_operating_mode(ar); + if (err) + goto out; + } + + if (changed & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED)) { + err = ar9170_update_beacon(ar); + if (err) + goto out; + + err = ar9170_set_beacon_timers(ar); + if (err) + goto out; + } if (changed & BSS_CHANGED_ASSOC) { - ar->state = bss_conf->assoc ? AR9170_ASSOCIATED : ar->state; - #ifndef CONFIG_AR9170_LEDS /* enable assoc LED. */ err = ar9170_set_leds_state(ar, bss_conf->assoc ? 2 : 0); #endif /* CONFIG_AR9170_LEDS */ } + if (changed & BSS_CHANGED_BEACON_INT) { + err = ar9170_set_beacon_timers(ar); + if (err) + goto out; + } + if (changed & BSS_CHANGED_HT) { /* TODO */ err = 0; } if (changed & BSS_CHANGED_ERP_SLOT) { - u32 slottime = 20; - - if (bss_conf->use_short_slot) - slottime = 9; - - ar9170_regwrite(AR9170_MAC_REG_SLOT_TIME, slottime << 10); + err = ar9170_set_slot_time(ar); + if (err) + goto out; } if (changed & BSS_CHANGED_BASIC_RATES) { - u32 cck, ofdm; - - if (hw->conf.channel->band == IEEE80211_BAND_5GHZ) { - ofdm = bss_conf->basic_rates; - cck = 0; - } else { - /* four cck rates */ - cck = bss_conf->basic_rates & 0xf; - ofdm = bss_conf->basic_rates >> 4; - } - ar9170_regwrite(AR9170_MAC_REG_BASIC_RATE, - ofdm << 8 | cck); + err = ar9170_set_basic_rates(ar); + if (err) + goto out; } - ar9170_regwrite_finish(); - err = ar9170_regwrite_result(); +out: mutex_unlock(&ar->mutex); } @@ -1298,7 +1816,7 @@ static int ar9170_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, switch (key->alg) { case ALG_WEP: - if (key->keylen == LEN_WEP40) + if (key->keylen == WLAN_KEY_LEN_WEP40) ktype = AR9170_ENC_ALG_WEP64; else ktype = AR9170_ENC_ALG_WEP128; @@ -1411,43 +1929,6 @@ static void ar9170_sta_notify(struct ieee80211_hw *hw, enum sta_notify_cmd cmd, struct ieee80211_sta *sta) { - struct ar9170 *ar = hw->priv; - struct ar9170_sta_info *info = (void *) sta->drv_priv; - struct sk_buff *skb; - unsigned int i; - - switch (cmd) { - case STA_NOTIFY_ADD: - for (i = 0; i < ar->hw->queues; i++) - skb_queue_head_init(&info->tx_status[i]); - break; - - case STA_NOTIFY_REMOVE: - - /* - * transfer all outstanding frames that need a tx_status - * reports to the global tx_status queue - */ - - for (i = 0; i < ar->hw->queues; i++) { - while ((skb = skb_dequeue(&info->tx_status[i]))) { -#ifdef AR9170_QUEUE_DEBUG - printk(KERN_DEBUG "%s: queueing frame in " - "global tx_status queue =>\n", - wiphy_name(ar->hw->wiphy)); - - ar9170_print_txheader(ar, skb); -#endif /* AR9170_QUEUE_DEBUG */ - skb_queue_tail(&ar->global_tx_status, skb); - } - } - queue_delayed_work(ar->hw->workqueue, &ar->tx_status_janitor, - msecs_to_jiffies(100)); - break; - - default: - break; - } } static int ar9170_get_stats(struct ieee80211_hw *hw, @@ -1486,7 +1967,7 @@ static int ar9170_conf_tx(struct ieee80211_hw *hw, u16 queue, int ret; mutex_lock(&ar->mutex); - if ((param) && !(queue > ar->hw->queues)) { + if ((param) && !(queue > __AR9170_NUM_TXQ)) { memcpy(&ar->edcf[ar9170_qos_hwmap[queue]], param, sizeof(*param)); @@ -1498,6 +1979,24 @@ static int ar9170_conf_tx(struct ieee80211_hw *hw, u16 queue, return ret; } +static int ar9170_ampdu_action(struct ieee80211_hw *hw, + enum ieee80211_ampdu_mlme_action action, + struct ieee80211_sta *sta, u16 tid, u16 *ssn) +{ + switch (action) { + case IEEE80211_AMPDU_RX_START: + case IEEE80211_AMPDU_RX_STOP: + /* + * Something goes wrong -- RX locks up + * after a while of receiving aggregated + * frames -- not enabling for now. + */ + return -EOPNOTSUPP; + default: + return -EOPNOTSUPP; + } +} + static const struct ieee80211_ops ar9170_ops = { .start = ar9170_op_start, .stop = ar9170_op_stop, @@ -1505,7 +2004,6 @@ static const struct ieee80211_ops ar9170_ops = { .add_interface = ar9170_op_add_interface, .remove_interface = ar9170_op_remove_interface, .config = ar9170_op_config, - .config_interface = ar9170_op_config_interface, .configure_filter = ar9170_op_configure_filter, .conf_tx = ar9170_conf_tx, .bss_info_changed = ar9170_op_bss_info_changed, @@ -1514,29 +2012,45 @@ static const struct ieee80211_ops ar9170_ops = { .sta_notify = ar9170_sta_notify, .get_stats = ar9170_get_stats, .get_tx_stats = ar9170_get_tx_stats, + .ampdu_action = ar9170_ampdu_action, }; void *ar9170_alloc(size_t priv_size) { struct ieee80211_hw *hw; struct ar9170 *ar; + struct sk_buff *skb; int i; + /* + * this buffer is used for rx stream reconstruction. + * Under heavy load this device (or the transport layer?) + * tends to split the streams into seperate rx descriptors. + */ + + skb = __dev_alloc_skb(AR9170_MAX_RX_BUFFER_SIZE, GFP_KERNEL); + if (!skb) + goto err_nomem; + hw = ieee80211_alloc_hw(priv_size, &ar9170_ops); if (!hw) - return ERR_PTR(-ENOMEM); + goto err_nomem; ar = hw->priv; ar->hw = hw; + ar->rx_failover = skb; mutex_init(&ar->mutex); spin_lock_init(&ar->cmdlock); spin_lock_init(&ar->tx_stats_lock); - skb_queue_head_init(&ar->global_tx_status); - skb_queue_head_init(&ar->global_tx_status_waste); + for (i = 0; i < __AR9170_NUM_TXQ; i++) { + skb_queue_head_init(&ar->tx_status[i]); + skb_queue_head_init(&ar->tx_pending[i]); + } + ar9170_rx_reset_rx_mpdu(ar); INIT_WORK(&ar->filter_config_work, ar9170_set_filters); INIT_WORK(&ar->beacon_work, ar9170_new_beacon); - INIT_DELAYED_WORK(&ar->tx_status_janitor, ar9170_tx_status_janitor); + INIT_DELAYED_WORK(&ar->tx_janitor, ar9170_tx_janitor); /* all hw supports 2.4 GHz, so set channel to 1 by default */ ar->channel = &ar9170_2ghz_chantable[0]; @@ -1561,6 +2075,10 @@ void *ar9170_alloc(size_t priv_size) ar->noise[i] = -95; /* ATH_DEFAULT_NOISE_FLOOR */ return ar; + +err_nomem: + kfree_skb(skb); + return ERR_PTR(-ENOMEM); } static int ar9170_read_eeprom(struct ar9170 *ar) @@ -1619,12 +2137,24 @@ static int ar9170_read_eeprom(struct ar9170 *ar) else ar->hw->channel_change_time = 80 * 1000; + ar->regulatory.current_rd = le16_to_cpu(ar->eeprom.reg_domain[0]); + ar->regulatory.current_rd_ext = le16_to_cpu(ar->eeprom.reg_domain[1]); + /* second part of wiphy init */ SET_IEEE80211_PERM_ADDR(ar->hw, addr); return bands ? 0 : -EINVAL; } +static int ar9170_reg_notifier(struct wiphy *wiphy, + struct regulatory_request *request) +{ + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct ar9170 *ar = hw->priv; + + return ath_reg_notifier_apply(wiphy, request, &ar->regulatory); +} + int ar9170_register(struct ar9170 *ar, struct device *pdev) { int err; @@ -1634,10 +2164,18 @@ int ar9170_register(struct ar9170 *ar, struct device *pdev) if (err) goto err_out; + err = ath_regd_init(&ar->regulatory, ar->hw->wiphy, + ar9170_reg_notifier); + if (err) + goto err_out; + err = ieee80211_register_hw(ar->hw); if (err) goto err_out; + if (!ath_is_world_regd(&ar->regulatory)) + regulatory_hint(ar->hw->wiphy, ar->regulatory.alpha2); + err = ar9170_init_leds(ar); if (err) goto err_unreg; @@ -1666,6 +2204,7 @@ void ar9170_unregister(struct ar9170 *ar) ar9170_unregister_leds(ar); #endif /* CONFIG_AR9170_LEDS */ + kfree_skb(ar->rx_failover); ieee80211_unregister_hw(ar->hw); mutex_destroy(&ar->mutex); } diff --git a/drivers/net/wireless/ar9170/phy.c b/drivers/net/wireless/ath/ar9170/phy.c similarity index 99% rename from drivers/net/wireless/ar9170/phy.c rename to drivers/net/wireless/ath/ar9170/phy.c index 6ce20754b8e7..df86f70cd817 100644 --- a/drivers/net/wireless/ar9170/phy.c +++ b/drivers/net/wireless/ath/ar9170/phy.c @@ -401,7 +401,7 @@ int ar9170_init_phy(struct ar9170 *ar, enum ieee80211_band band) int i, err; u32 val; bool is_2ghz = band == IEEE80211_BAND_2GHZ; - bool is_40mhz = false; /* XXX: for now */ + bool is_40mhz = conf_is_ht40(&ar->hw->conf); ar9170_regwrite_begin(ar); @@ -1200,7 +1200,7 @@ int ar9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel, return -ENOSYS; } - if (0 /* 2 streams capable */) + if (ar->eeprom.tx_mask != 1) tmp |= 0x100; err = ar9170_write_reg(ar, 0x1c5804, tmp); @@ -1214,7 +1214,7 @@ int ar9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel, freqpar = ar9170_get_hw_dyn_params(channel, bw); vals[0] = cpu_to_le32(channel->center_freq * 1000); - vals[1] = cpu_to_le32(bw == AR9170_BW_20 ? 0 : 1); + vals[1] = cpu_to_le32(conf_is_ht40(&ar->hw->conf)); vals[2] = cpu_to_le32(offs << 2 | 1); vals[3] = cpu_to_le32(freqpar->coeff_exp); vals[4] = cpu_to_le32(freqpar->coeff_man); diff --git a/drivers/net/wireless/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c similarity index 83% rename from drivers/net/wireless/ar9170/usb.c rename to drivers/net/wireless/ath/ar9170/usb.c index fddda477095c..754b1f8d8da9 100644 --- a/drivers/net/wireless/ar9170/usb.c +++ b/drivers/net/wireless/ath/ar9170/usb.c @@ -51,9 +51,14 @@ MODULE_AUTHOR("Johannes Berg "); MODULE_AUTHOR("Christian Lamparter "); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Atheros AR9170 802.11n USB wireless"); +MODULE_FIRMWARE("ar9170.fw"); MODULE_FIRMWARE("ar9170-1.fw"); MODULE_FIRMWARE("ar9170-2.fw"); +enum ar9170_requirements { + AR9170_REQ_FW1_ONLY = 1, +}; + static struct usb_device_id ar9170_usb_ids[] = { /* Atheros 9170 */ { USB_DEVICE(0x0cf3, 0x9170) }, @@ -81,25 +86,74 @@ static struct usb_device_id ar9170_usb_ids[] = { { USB_DEVICE(0x2019, 0x5304) }, /* IO-Data WNGDNUS2 */ { USB_DEVICE(0x04bb, 0x093f) }, + /* AVM FRITZ!WLAN USB Stick N */ + { USB_DEVICE(0x057C, 0x8401) }, + /* AVM FRITZ!WLAN USB Stick N 2.4 */ + { USB_DEVICE(0x057C, 0x8402), .driver_info = AR9170_REQ_FW1_ONLY }, /* terminate */ {} }; MODULE_DEVICE_TABLE(usb, ar9170_usb_ids); -static void ar9170_usb_tx_urb_complete_free(struct urb *urb) +static void ar9170_usb_submit_urb(struct ar9170_usb *aru) +{ + struct urb *urb; + unsigned long flags; + int err; + + if (unlikely(!IS_STARTED(&aru->common))) + return ; + + spin_lock_irqsave(&aru->tx_urb_lock, flags); + if (aru->tx_submitted_urbs >= AR9170_NUM_TX_URBS) { + spin_unlock_irqrestore(&aru->tx_urb_lock, flags); + return ; + } + aru->tx_submitted_urbs++; + + urb = usb_get_from_anchor(&aru->tx_pending); + if (!urb) { + aru->tx_submitted_urbs--; + spin_unlock_irqrestore(&aru->tx_urb_lock, flags); + + return ; + } + spin_unlock_irqrestore(&aru->tx_urb_lock, flags); + + aru->tx_pending_urbs--; + usb_anchor_urb(urb, &aru->tx_submitted); + + err = usb_submit_urb(urb, GFP_ATOMIC); + if (unlikely(err)) { + if (ar9170_nag_limiter(&aru->common)) + dev_err(&aru->udev->dev, "submit_urb failed (%d).\n", + err); + + usb_unanchor_urb(urb); + aru->tx_submitted_urbs--; + ar9170_tx_callback(&aru->common, urb->context); + } + + usb_free_urb(urb); +} + +static void ar9170_usb_tx_urb_complete_frame(struct urb *urb) { struct sk_buff *skb = urb->context; struct ar9170_usb *aru = (struct ar9170_usb *) usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0)); - if (!aru) { + if (unlikely(!aru)) { dev_kfree_skb_irq(skb); return ; } - ar9170_handle_tx_status(&aru->common, skb, false, - AR9170_TX_STATUS_COMPLETE); + aru->tx_submitted_urbs--; + + ar9170_tx_callback(&aru->common, skb); + + ar9170_usb_submit_urb(aru); } static void ar9170_usb_tx_urb_complete(struct urb *urb) @@ -126,8 +180,8 @@ static void ar9170_usb_irq_completed(struct urb *urb) goto resubmit; } - print_hex_dump_bytes("ar9170 irq: ", DUMP_PREFIX_OFFSET, - urb->transfer_buffer, urb->actual_length); + ar9170_handle_command_response(&aru->common, urb->transfer_buffer, + urb->actual_length); resubmit: usb_anchor_urb(urb, &aru->rx_submitted); @@ -177,16 +231,15 @@ resubmit: usb_anchor_urb(urb, &aru->rx_submitted); err = usb_submit_urb(urb, GFP_ATOMIC); - if (err) { + if (unlikely(err)) { usb_unanchor_urb(urb); - dev_kfree_skb_irq(skb); + goto free; } return ; free: dev_kfree_skb_irq(skb); - return; } static int ar9170_usb_prep_rx_urb(struct ar9170_usb *aru, @@ -282,21 +335,47 @@ err_out: return err; } -static void ar9170_usb_cancel_urbs(struct ar9170_usb *aru) +static int ar9170_usb_flush(struct ar9170 *ar) { - int ret; + struct ar9170_usb *aru = (void *) ar; + struct urb *urb; + int ret, err = 0; - aru->common.state = AR9170_UNKNOWN_STATE; + if (IS_STARTED(ar)) + aru->common.state = AR9170_IDLE; - usb_unlink_anchored_urbs(&aru->tx_submitted); + usb_wait_anchor_empty_timeout(&aru->tx_pending, + msecs_to_jiffies(800)); + while ((urb = usb_get_from_anchor(&aru->tx_pending))) { + ar9170_tx_callback(&aru->common, (void *) urb->context); + usb_free_urb(urb); + } - /* give the LED OFF command and the deauth frame a chance to air. */ + /* lets wait a while until the tx - queues are dried out */ ret = usb_wait_anchor_empty_timeout(&aru->tx_submitted, msecs_to_jiffies(100)); if (ret == 0) - dev_err(&aru->udev->dev, "kill pending tx urbs.\n"); - usb_poison_anchored_urbs(&aru->tx_submitted); + err = -ETIMEDOUT; + usb_kill_anchored_urbs(&aru->tx_submitted); + + if (IS_ACCEPTING_CMD(ar)) + aru->common.state = AR9170_STARTED; + + return err; +} + +static void ar9170_usb_cancel_urbs(struct ar9170_usb *aru) +{ + int err; + + aru->common.state = AR9170_UNKNOWN_STATE; + + err = ar9170_usb_flush(&aru->common); + if (err) + dev_err(&aru->udev->dev, "stuck tx urbs!\n"); + + usb_poison_anchored_urbs(&aru->tx_submitted); usb_poison_anchored_urbs(&aru->rx_submitted); } @@ -337,7 +416,7 @@ static int ar9170_usb_exec_cmd(struct ar9170 *ar, enum ar9170_cmd cmd, usb_anchor_urb(urb, &aru->tx_submitted); err = usb_submit_urb(urb, GFP_ATOMIC); - if (err) { + if (unlikely(err)) { usb_unanchor_urb(urb); usb_free_urb(urb); goto err_unbuf; @@ -350,7 +429,7 @@ static int ar9170_usb_exec_cmd(struct ar9170 *ar, enum ar9170_cmd cmd, goto err_unbuf; } - if (outlen >= 0 && aru->readlen != outlen) { + if (aru->readlen != outlen) { err = -EMSGSIZE; goto err_unbuf; } @@ -380,12 +459,10 @@ err_free: return err; } -static int ar9170_usb_tx(struct ar9170 *ar, struct sk_buff *skb, - bool txstatus_needed, unsigned int extra_len) +static int ar9170_usb_tx(struct ar9170 *ar, struct sk_buff *skb) { struct ar9170_usb *aru = (struct ar9170_usb *) ar; struct urb *urb; - int err; if (unlikely(!IS_STARTED(ar))) { /* Seriously, what were you drink... err... thinking!? */ @@ -398,18 +475,17 @@ static int ar9170_usb_tx(struct ar9170 *ar, struct sk_buff *skb, usb_fill_bulk_urb(urb, aru->udev, usb_sndbulkpipe(aru->udev, AR9170_EP_TX), - skb->data, skb->len + extra_len, (txstatus_needed ? - ar9170_usb_tx_urb_complete : - ar9170_usb_tx_urb_complete_free), skb); + skb->data, skb->len, + ar9170_usb_tx_urb_complete_frame, skb); urb->transfer_flags |= URB_ZERO_PACKET; - usb_anchor_urb(urb, &aru->tx_submitted); - err = usb_submit_urb(urb, GFP_ATOMIC); - if (unlikely(err)) - usb_unanchor_urb(urb); + usb_anchor_urb(urb, &aru->tx_pending); + aru->tx_pending_urbs++; usb_free_urb(urb); - return err; + + ar9170_usb_submit_urb(aru); + return 0; } static void ar9170_usb_callback_cmd(struct ar9170 *ar, u32 len , void *buffer) @@ -418,7 +494,7 @@ static void ar9170_usb_callback_cmd(struct ar9170 *ar, u32 len , void *buffer) unsigned long flags; u32 in, out; - if (!buffer) + if (unlikely(!buffer)) return ; in = le32_to_cpup((__le32 *)buffer); @@ -504,17 +580,29 @@ static int ar9170_usb_request_firmware(struct ar9170_usb *aru) { int err = 0; + err = request_firmware(&aru->firmware, "ar9170.fw", + &aru->udev->dev); + if (!err) { + aru->init_values = NULL; + return 0; + } + + if (aru->req_one_stage_fw) { + dev_err(&aru->udev->dev, "ar9170.fw firmware file " + "not found and is required for this device\n"); + return -EINVAL; + } + + dev_err(&aru->udev->dev, "ar9170.fw firmware file " + "not found, trying old firmware...\n"); + err = request_firmware(&aru->init_values, "ar9170-1.fw", &aru->udev->dev); - if (err) { - dev_err(&aru->udev->dev, "file with init values not found.\n"); - return err; - } err = request_firmware(&aru->firmware, "ar9170-2.fw", &aru->udev->dev); if (err) { release_firmware(aru->init_values); - dev_err(&aru->udev->dev, "firmware file not found.\n"); + dev_err(&aru->udev->dev, "file with init values not found.\n"); return err; } @@ -548,6 +636,9 @@ static int ar9170_usb_upload_firmware(struct ar9170_usb *aru) { int err; + if (!aru->init_values) + goto upload_fw_start; + /* First, upload initial values to device RAM */ err = ar9170_usb_upload(aru, aru->init_values->data, aru->init_values->size, 0x102800, false); @@ -557,6 +648,8 @@ static int ar9170_usb_upload_firmware(struct ar9170_usb *aru) return err; } +upload_fw_start: + /* Then, upload the firmware itself and start it */ return ar9170_usb_upload(aru, aru->firmware->data, aru->firmware->size, 0x200000, true); @@ -592,10 +685,8 @@ static void ar9170_usb_stop(struct ar9170 *ar) if (IS_ACCEPTING_CMD(ar)) aru->common.state = AR9170_STOPPED; - /* lets wait a while until the tx - queues are dried out */ - ret = usb_wait_anchor_empty_timeout(&aru->tx_submitted, - msecs_to_jiffies(1000)); - if (ret == 0) + ret = ar9170_usb_flush(ar); + if (ret) dev_err(&aru->udev->dev, "kill pending tx urbs.\n"); usb_poison_anchored_urbs(&aru->tx_submitted); @@ -656,6 +747,15 @@ err_out: return err; } +static bool ar9170_requires_one_stage(const struct usb_device_id *id) +{ + if (!id->driver_info) + return false; + if (id->driver_info == AR9170_REQ_FW1_ONLY) + return true; + return false; +} + static int ar9170_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) { @@ -676,19 +776,30 @@ static int ar9170_usb_probe(struct usb_interface *intf, aru->intf = intf; ar = &aru->common; + aru->req_one_stage_fw = ar9170_requires_one_stage(id); + usb_set_intfdata(intf, aru); SET_IEEE80211_DEV(ar->hw, &udev->dev); init_usb_anchor(&aru->rx_submitted); + init_usb_anchor(&aru->tx_pending); init_usb_anchor(&aru->tx_submitted); init_completion(&aru->cmd_wait); + spin_lock_init(&aru->tx_urb_lock); + + aru->tx_pending_urbs = 0; + aru->tx_submitted_urbs = 0; aru->common.stop = ar9170_usb_stop; + aru->common.flush = ar9170_usb_flush; aru->common.open = ar9170_usb_open; aru->common.tx = ar9170_usb_tx; aru->common.exec_cmd = ar9170_usb_exec_cmd; aru->common.callback_cmd = ar9170_usb_callback_cmd; +#ifdef CONFIG_PM + udev->reset_resume = 1; +#endif /* CONFIG_PM */ err = ar9170_usb_reset(aru); if (err) goto err_freehw; @@ -773,11 +884,6 @@ static int ar9170_resume(struct usb_interface *intf) usb_unpoison_anchored_urbs(&aru->rx_submitted); usb_unpoison_anchored_urbs(&aru->tx_submitted); - /* - * FIXME: firmware upload will fail on resume. - * but this is better than a hang! - */ - err = ar9170_usb_init_device(aru); if (err) goto err_unrx; @@ -805,6 +911,7 @@ static struct usb_driver ar9170_driver = { #ifdef CONFIG_PM .suspend = ar9170_suspend, .resume = ar9170_resume, + .reset_resume = ar9170_resume, #endif /* CONFIG_PM */ }; diff --git a/drivers/net/wireless/ar9170/usb.h b/drivers/net/wireless/ath/ar9170/usb.h similarity index 92% rename from drivers/net/wireless/ar9170/usb.h rename to drivers/net/wireless/ath/ar9170/usb.h index f5852924cd64..d098f4d5d2f2 100644 --- a/drivers/net/wireless/ar9170/usb.h +++ b/drivers/net/wireless/ath/ar9170/usb.h @@ -43,7 +43,7 @@ #include #include #include -#include +#include #include #include #include "eeprom.h" @@ -51,6 +51,7 @@ #include "ar9170.h" #define AR9170_NUM_RX_URBS 16 +#define AR9170_NUM_TX_URBS 8 struct firmware; @@ -60,9 +61,15 @@ struct ar9170_usb { struct usb_interface *intf; struct usb_anchor rx_submitted; + struct usb_anchor tx_pending; struct usb_anchor tx_submitted; - spinlock_t cmdlock; + bool req_one_stage_fw; + + spinlock_t tx_urb_lock; + unsigned int tx_submitted_urbs; + unsigned int tx_pending_urbs; + struct completion cmd_wait; int readlen; u8 *readbuf; diff --git a/drivers/net/wireless/ath5k/Kconfig b/drivers/net/wireless/ath/ath5k/Kconfig similarity index 90% rename from drivers/net/wireless/ath5k/Kconfig rename to drivers/net/wireless/ath/ath5k/Kconfig index 75383a5df992..daf0c83527d8 100644 --- a/drivers/net/wireless/ath5k/Kconfig +++ b/drivers/net/wireless/ath/ath5k/Kconfig @@ -1,6 +1,7 @@ config ATH5K tristate "Atheros 5xxx wireless cards support" depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL + select ATH_COMMON select MAC80211_LEDS select LEDS_CLASS select NEW_LEDS @@ -27,11 +28,10 @@ config ATH5K_DEBUG Say Y, if and you will get debug options for ath5k. To use this, you need to mount debugfs: - mkdir /debug/ - mount -t debugfs debug /debug/ + mount -t debugfs debug /sys/kernel/debug You will get access to files under: - /debug/ath5k/phy0/ + /sys/kernel/debug/ath5k/phy0/ To enable debug, pass the debug level to the debug module parameter. For example: diff --git a/drivers/net/wireless/ath5k/Makefile b/drivers/net/wireless/ath/ath5k/Makefile similarity index 93% rename from drivers/net/wireless/ath5k/Makefile rename to drivers/net/wireless/ath/ath5k/Makefile index 84a74c5248e5..090dc6d268a3 100644 --- a/drivers/net/wireless/ath5k/Makefile +++ b/drivers/net/wireless/ath/ath5k/Makefile @@ -11,5 +11,6 @@ ath5k-y += reset.o ath5k-y += attach.o ath5k-y += base.o ath5k-y += led.o +ath5k-y += rfkill.o ath5k-$(CONFIG_ATH5K_DEBUG) += debug.o obj-$(CONFIG_ATH5K) += ath5k.o diff --git a/drivers/net/wireless/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h similarity index 97% rename from drivers/net/wireless/ath5k/ath5k.h rename to drivers/net/wireless/ath/ath5k/ath5k.h index 0b616e72fe05..6358233bac99 100644 --- a/drivers/net/wireless/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -27,6 +27,8 @@ #include #include +#include "../regd.h" + /* RX/TX descriptor hw structs * TODO: Driver part should only see sw structs */ #include "desc.h" @@ -207,7 +209,6 @@ #define AR5K_TUNE_MAX_TXPOWER 63 #define AR5K_TUNE_DEFAULT_TXPOWER 25 #define AR5K_TUNE_TPC_TXPOWER false -#define AR5K_TUNE_ANT_DIVERSITY true #define AR5K_TUNE_HWTXTRIES 4 #define AR5K_INIT_CARR_SENSE_EN 1 @@ -418,6 +419,17 @@ enum ath5k_driver_mode { AR5K_MODE_MAX = 5 }; +enum ath5k_ant_mode { + AR5K_ANTMODE_DEFAULT = 0, /* default antenna setup */ + AR5K_ANTMODE_FIXED_A = 1, /* only antenna A is present */ + AR5K_ANTMODE_FIXED_B = 2, /* only antenna B is present */ + AR5K_ANTMODE_SINGLE_AP = 3, /* sta locked on a single ap */ + AR5K_ANTMODE_SECTOR_AP = 4, /* AP with tx antenna set on tx desc */ + AR5K_ANTMODE_SECTOR_STA = 5, /* STA with tx antenna set on tx desc */ + AR5K_ANTMODE_DEBUG = 6, /* Debug mode -A -> Rx, B-> Tx- */ + AR5K_ANTMODE_MAX, +}; + /****************\ TX DEFINITIONS @@ -1039,8 +1051,6 @@ struct ath5k_hw { bool ah_5ghz; bool ah_2ghz; -#define ah_regdomain ah_capabilities.cap_regdomain.reg_current -#define ah_regdomain_hw ah_capabilities.cap_regdomain.reg_hw #define ah_modes ah_capabilities.cap_mode #define ah_ee_version ah_capabilities.cap_eeprom.ee_version @@ -1051,8 +1061,11 @@ struct ath5k_hw { bool ah_software_retry; u32 ah_limit_tx_retries; - u32 ah_antenna[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX]; - bool ah_ant_diversity; + /* Antenna Control */ + u32 ah_ant_ctl[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX]; + u8 ah_ant_mode; + u8 ah_tx_ant; + u8 ah_def_ant; u8 ah_sta_id[ETH_ALEN]; @@ -1065,6 +1078,7 @@ struct ath5k_hw { u32 ah_gpio[AR5K_MAX_GPIO]; int ah_gpio_npins; + struct ath_regulatory ah_regulatory; struct ath5k_capabilities ah_capabilities; struct ath5k_txq_info ah_txq[AR5K_NUM_TX_QUEUES]; @@ -1099,11 +1113,12 @@ struct ath5k_hw { /* Values in 0.25dB units */ s16 txp_min_pwr; s16 txp_max_pwr; + /* Values in 0.5dB units */ s16 txp_offset; s16 txp_ofdm; - /* Values in dB units */ - s16 txp_cck_ofdm_pwr_delta; s16 txp_cck_ofdm_gainf_delta; + /* Value in dB units */ + s16 txp_cck_ofdm_pwr_delta; } ah_txpower; struct { @@ -1241,6 +1256,10 @@ extern u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio); extern int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val); extern void ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio, u32 interrupt_level); +/* rfkill Functions */ +extern void ath5k_rfkill_hw_start(struct ath5k_hw *ah); +extern void ath5k_rfkill_hw_stop(struct ath5k_hw *ah); + /* Misc functions */ int ath5k_hw_set_capabilities(struct ath5k_hw *ah); extern int ath5k_hw_get_capability(struct ath5k_hw *ah, enum ath5k_capability_type cap_type, u32 capability, u32 *result); @@ -1263,14 +1282,21 @@ extern int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *chann /* PHY calibration */ extern int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, struct ieee80211_channel *channel); extern int ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq); +/* Spur mitigation */ +bool ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah, + struct ieee80211_channel *channel); +void ath5k_hw_set_spur_mitigation_filter(struct ath5k_hw *ah, + struct ieee80211_channel *channel); /* Misc PHY functions */ extern u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan); -extern void ath5k_hw_set_def_antenna(struct ath5k_hw *ah, unsigned int ant); -extern unsigned int ath5k_hw_get_def_antenna(struct ath5k_hw *ah); extern int ath5k_hw_phy_disable(struct ath5k_hw *ah); +/* Antenna control */ +extern void ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode); +extern void ath5k_hw_set_def_antenna(struct ath5k_hw *ah, u8 ant); +extern unsigned int ath5k_hw_get_def_antenna(struct ath5k_hw *ah); /* TX power setup */ extern int ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel, u8 ee_mode, u8 txpower); -extern int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 ee_mode, u8 txpower); +extern int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 txpower); /* * Functions used internaly diff --git a/drivers/net/wireless/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c similarity index 99% rename from drivers/net/wireless/ath5k/attach.c rename to drivers/net/wireless/ath/ath5k/attach.c index 70d376c63aac..c41ef58393e7 100644 --- a/drivers/net/wireless/ath5k/attach.c +++ b/drivers/net/wireless/ath/ath5k/attach.c @@ -133,7 +133,6 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) ah->ah_cw_min = AR5K_TUNE_CWMIN; ah->ah_limit_tx_retries = AR5K_INIT_TX_RETRY; ah->ah_software_retry = false; - ah->ah_ant_diversity = AR5K_TUNE_ANT_DIVERSITY; /* * Set the mac version based on the pci id diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c similarity index 93% rename from drivers/net/wireless/ath5k/base.c rename to drivers/net/wireless/ath/ath5k/base.c index 32df27a9c7a2..ea045151f953 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -61,9 +61,13 @@ static int ath5k_calinterval = 10; /* Calibrate PHY every 10 secs (TODO: Fixme) */ static int modparam_nohwcrypt; -module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444); +module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); +static int modparam_all_channels; +module_param_named(all_channels, modparam_all_channels, bool, S_IRUGO); +MODULE_PARM_DESC(all_channels, "Expose all channels the device can use."); + /******************\ * Internal defines * @@ -223,9 +227,6 @@ static int ath5k_add_interface(struct ieee80211_hw *hw, static void ath5k_remove_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf); static int ath5k_config(struct ieee80211_hw *hw, u32 changed); -static int ath5k_config_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_if_conf *conf); static void ath5k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *new_flags, @@ -241,8 +242,8 @@ static int ath5k_get_tx_stats(struct ieee80211_hw *hw, static u64 ath5k_get_tsf(struct ieee80211_hw *hw); static void ath5k_set_tsf(struct ieee80211_hw *hw, u64 tsf); static void ath5k_reset_tsf(struct ieee80211_hw *hw); -static int ath5k_beacon_update(struct ath5k_softc *sc, - struct sk_buff *skb); +static int ath5k_beacon_update(struct ieee80211_hw *hw, + struct ieee80211_vif *vif); static void ath5k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, @@ -255,7 +256,6 @@ static const struct ieee80211_ops ath5k_hw_ops = { .add_interface = ath5k_add_interface, .remove_interface = ath5k_remove_interface, .config = ath5k_config, - .config_interface = ath5k_config_interface, .configure_filter = ath5k_configure_filter, .set_key = ath5k_set_key, .get_stats = ath5k_get_stats, @@ -516,6 +516,7 @@ ath5k_pci_probe(struct pci_dev *pdev, IEEE80211_HW_NOISE_DBM; hw->wiphy->interface_modes = + BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_MESH_POINT); @@ -537,6 +538,7 @@ ath5k_pci_probe(struct pci_dev *pdev, sc->iobase = mem; /* So we can unmap it on detach */ sc->cachelsz = csz * sizeof(u32); /* convert to bytes */ sc->opmode = NL80211_IFTYPE_STATION; + sc->bintval = 1000; mutex_init(&sc->lock); spin_lock_init(&sc->rxbuflock); spin_lock_init(&sc->txbuflock); @@ -685,6 +687,13 @@ ath5k_pci_resume(struct pci_dev *pdev) if (err) return err; + /* + * Suspend/Resume resets the PCI configuration space, so we have to + * re-disable the RETRY_TIMEOUT register (0x41) to keep + * PCI Tx retries from interfering with C3 CPU state + */ + pci_write_config_byte(pdev, 0x41, 0); + err = request_irq(pdev->irq, ath5k_intr, IRQF_SHARED, "ath", sc); if (err) { ATH5K_ERR(sc, "request_irq failed\n"); @@ -705,6 +714,15 @@ err_no_irq: * Driver Initialization * \***********************/ +static int ath5k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) +{ + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct ath5k_softc *sc = hw->priv; + struct ath_regulatory *reg = &sc->ah->ah_regulatory; + + return ath_reg_notifier_apply(wiphy, request, reg); +} + static int ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) { @@ -793,12 +811,23 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) memset(sc->bssidmask, 0xff, ETH_ALEN); ath5k_hw_set_bssid_mask(sc->ah, sc->bssidmask); + ah->ah_regulatory.current_rd = + ah->ah_capabilities.cap_eeprom.ee_regdomain; + ret = ath_regd_init(&ah->ah_regulatory, hw->wiphy, ath5k_reg_notifier); + if (ret) { + ATH5K_ERR(sc, "can't initialize regulatory system\n"); + goto err_queues; + } + ret = ieee80211_register_hw(hw); if (ret) { ATH5K_ERR(sc, "can't register ieee80211 hw\n"); goto err_queues; } + if (!ath_is_world_regd(&sc->ah->ah_regulatory)) + regulatory_hint(hw->wiphy, sc->ah->ah_regulatory.alpha2); + ath5k_init_leds(sc); return 0; @@ -862,6 +891,20 @@ ath5k_ieee2mhz(short chan) return 2212 + chan * 20; } +/* + * Returns true for the channel numbers used without all_channels modparam. + */ +static bool ath5k_is_standard_channel(short chan) +{ + return ((chan <= 14) || + /* UNII 1,2 */ + ((chan & 3) == 0 && chan >= 36 && chan <= 64) || + /* midband */ + ((chan & 3) == 0 && chan >= 100 && chan <= 140) || + /* UNII-3 */ + ((chan & 3) == 1 && chan >= 149 && chan <= 165)); +} + static unsigned int ath5k_copy_channels(struct ath5k_hw *ah, struct ieee80211_channel *channels, @@ -899,6 +942,9 @@ ath5k_copy_channels(struct ath5k_hw *ah, if (!ath5k_channel_ok(ah, freq, chfreq)) continue; + if (!modparam_all_channels && !ath5k_is_standard_channel(ch)) + continue; + /* Write channel info and increment counter */ channels[count].center_freq = freq; channels[count].band = (chfreq == CHANNEL_2GHZ) ? @@ -1238,7 +1284,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL, (sc->power_level * 2), hw_rate, - info->control.rates[0].count, keyidx, 0, flags, + info->control.rates[0].count, keyidx, ah->ah_tx_ant, flags, cts_rate, duration); if (ret) goto err_unmap; @@ -1574,9 +1620,8 @@ ath5k_rx_start(struct ath5k_softc *sc) ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "cachelsz %u rxbufsize %u\n", sc->cachelsz, sc->rxbufsize); - sc->rxlink = NULL; - spin_lock_bh(&sc->rxbuflock); + sc->rxlink = NULL; list_for_each_entry(bf, &sc->rxbuf, list) { ret = ath5k_rxbuf_setup(sc, bf); if (ret != 0) { @@ -1585,9 +1630,9 @@ ath5k_rx_start(struct ath5k_softc *sc) } } bf = list_first_entry(&sc->rxbuf, struct ath5k_buf, list); + ath5k_hw_set_rxdp(ah, bf->daddr); spin_unlock_bh(&sc->rxbuflock); - ath5k_hw_set_rxdp(ah, bf->daddr); ath5k_hw_start_rx_dma(ah); /* enable recv descriptors */ ath5k_mode_setup(sc); /* set filters, etc. */ ath5k_hw_start_rx_pcu(ah); /* re-enable PCU/DMA engine */ @@ -1699,35 +1744,6 @@ ath5k_check_ibss_tsf(struct ath5k_softc *sc, struct sk_buff *skb, } } -static void ath5k_tasklet_beacon(unsigned long data) -{ - struct ath5k_softc *sc = (struct ath5k_softc *) data; - - /* - * Software beacon alert--time to send a beacon. - * - * In IBSS mode we use this interrupt just to - * keep track of the next TBTT (target beacon - * transmission time) in order to detect wether - * automatic TSF updates happened. - */ - if (sc->opmode == NL80211_IFTYPE_ADHOC) { - /* XXX: only if VEOL suppported */ - u64 tsf = ath5k_hw_get_tsf64(sc->ah); - sc->nexttbtt += sc->bintval; - ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, - "SWBA nexttbtt: %x hw_tu: %x " - "TSF: %llx\n", - sc->nexttbtt, - TSF_TO_TU(tsf), - (unsigned long long) tsf); - } else { - spin_lock(&sc->block); - ath5k_beacon_send(sc); - spin_unlock(&sc->block); - } -} - static void ath5k_tasklet_rx(unsigned long data) { @@ -1736,7 +1752,7 @@ ath5k_tasklet_rx(unsigned long data) struct sk_buff *skb, *next_skb; dma_addr_t next_skb_addr; struct ath5k_softc *sc = (void *)data; - struct ath5k_buf *bf, *bf_last; + struct ath5k_buf *bf; struct ath5k_desc *ds; int ret; int hdrlen; @@ -1747,7 +1763,6 @@ ath5k_tasklet_rx(unsigned long data) ATH5K_WARN(sc, "empty rx buf pool\n"); goto unlock; } - bf_last = list_entry(sc->rxbuf.prev, struct ath5k_buf, list); do { rxs.flag = 0; @@ -1756,24 +1771,9 @@ ath5k_tasklet_rx(unsigned long data) skb = bf->skb; ds = bf->desc; - /* - * last buffer must not be freed to ensure proper hardware - * function. When the hardware finishes also a packet next to - * it, we are sure, it doesn't use it anymore and we can go on. - */ - if (bf_last == bf) - bf->flags |= 1; - if (bf->flags) { - struct ath5k_buf *bf_next = list_entry(bf->list.next, - struct ath5k_buf, list); - ret = sc->ah->ah_proc_rx_desc(sc->ah, bf_next->desc, - &rs); - if (ret) - break; - bf->flags &= ~1; - /* skip the overwritten one (even status is martian) */ - goto next; - } + /* bail if HW is still using self-linked descriptor */ + if (ath5k_hw_get_rxdp(sc->ah) == bf->daddr) + break; ret = sc->ah->ah_proc_rx_desc(sc->ah, ds, &rs); if (unlikely(ret == -EINPROGRESS)) @@ -2014,7 +2014,8 @@ ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ath5k_hw *ah = sc->ah; struct ath5k_desc *ds; - int ret, antenna = 0; + int ret = 0; + u8 antenna; u32 flags; bf->skbaddr = pci_map_single(sc->pdev, skb->data, skb->len, @@ -2028,23 +2029,35 @@ ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) } ds = bf->desc; + antenna = ah->ah_tx_ant; flags = AR5K_TXDESC_NOACK; if (sc->opmode == NL80211_IFTYPE_ADHOC && ath5k_hw_hasveol(ah)) { ds->ds_link = bf->daddr; /* self-linked */ flags |= AR5K_TXDESC_VEOL; - /* - * Let hardware handle antenna switching if txantenna is not set - */ - } else { + } else ds->ds_link = 0; - /* - * Switch antenna every 4 beacons if txantenna is not set - * XXX assumes two antennas - */ - if (antenna == 0) - antenna = sc->bsent & 4 ? 2 : 1; - } + + /* + * If we use multiple antennas on AP and use + * the Sectored AP scenario, switch antenna every + * 4 beacons to make sure everybody hears our AP. + * When a client tries to associate, hw will keep + * track of the tx antenna to be used for this client + * automaticaly, based on ACKed packets. + * + * Note: AP still listens and transmits RTS on the + * default antenna which is supposed to be an omni. + * + * Note2: On sectored scenarios it's possible to have + * multiple antennas (1omni -the default- and 14 sectors) + * so if we choose to actually support this mode we need + * to allow user to set how many antennas we have and tweak + * the code below to send beacons on all of them. + */ + if (ah->ah_ant_mode == AR5K_ANTMODE_SECTOR_AP) + antenna = sc->bsent & 4 ? 2 : 1; + /* FIXME: If we are in g mode and rate is a CCK rate * subtract ah->ah_txpower.txp_cck_ofdm_pwr_delta @@ -2065,6 +2078,13 @@ err_unmap: return ret; } +static void ath5k_beacon_disable(struct ath5k_softc *sc) +{ + sc->imask &= ~(AR5K_INT_BMISS | AR5K_INT_SWBA); + ath5k_hw_set_imr(sc->ah, sc->imask); + ath5k_hw_stop_tx_dma(sc->ah, sc->bhalq); +} + /* * Transmit a beacon frame at SWBA. Dynamic updates to the * frame contents are done as needed and the slot time is @@ -2097,7 +2117,7 @@ ath5k_beacon_send(struct ath5k_softc *sc) sc->bmisscount++; ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "missed %u consecutive beacons\n", sc->bmisscount); - if (sc->bmisscount > 3) { /* NB: 3 is a guess */ + if (sc->bmisscount > 10) { /* NB: 10 is a guess */ ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "stuck beacon time (%u missed)\n", sc->bmisscount); @@ -2118,10 +2138,14 @@ ath5k_beacon_send(struct ath5k_softc *sc) * are still pending on the queue. */ if (unlikely(ath5k_hw_stop_tx_dma(ah, sc->bhalq))) { - ATH5K_WARN(sc, "beacon queue %u didn't stop?\n", sc->bhalq); + ATH5K_WARN(sc, "beacon queue %u didn't start/stop ?\n", sc->bhalq); /* NB: hw still stops DMA, so proceed */ } + /* refresh the beacon for AP mode */ + if (sc->opmode == NL80211_IFTYPE_AP) + ath5k_beacon_update(sc->hw, sc->vif); + ath5k_hw_set_txdp(ah, sc->bhalq, bf->daddr); ath5k_hw_start_tx_dma(ah, sc->bhalq); ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "TXDP[%u] = %llx (%p)\n", @@ -2278,6 +2302,35 @@ ath5k_beacon_config(struct ath5k_softc *sc) ath5k_hw_set_imr(ah, sc->imask); } +static void ath5k_tasklet_beacon(unsigned long data) +{ + struct ath5k_softc *sc = (struct ath5k_softc *) data; + + /* + * Software beacon alert--time to send a beacon. + * + * In IBSS mode we use this interrupt just to + * keep track of the next TBTT (target beacon + * transmission time) in order to detect wether + * automatic TSF updates happened. + */ + if (sc->opmode == NL80211_IFTYPE_ADHOC) { + /* XXX: only if VEOL suppported */ + u64 tsf = ath5k_hw_get_tsf64(sc->ah); + sc->nexttbtt += sc->bintval; + ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, + "SWBA nexttbtt: %x hw_tu: %x " + "TSF: %llx\n", + sc->nexttbtt, + TSF_TO_TU(tsf), + (unsigned long long) tsf); + } else { + spin_lock(&sc->block); + ath5k_beacon_send(sc); + spin_unlock(&sc->block); + } +} + /********************\ * Interrupt handling * @@ -2315,6 +2368,8 @@ ath5k_init(struct ath5k_softc *sc) if (ret) goto done; + ath5k_rfkill_hw_start(ah); + /* * Reset the key cache since some parts do not reset the * contents on initial power up or resume from suspend. @@ -2423,6 +2478,8 @@ ath5k_stop_hw(struct ath5k_softc *sc) tasklet_kill(&sc->restq); tasklet_kill(&sc->beacontq); + ath5k_rfkill_hw_stop(sc->ah); + return ret; } @@ -2452,7 +2509,7 @@ ath5k_intr(int irq, void *dev_id) tasklet_schedule(&sc->restq); } else { if (status & AR5K_INT_SWBA) { - tasklet_schedule(&sc->beacontq); + tasklet_hi_schedule(&sc->beacontq); } if (status & AR5K_INT_RXEOL) { /* @@ -2481,8 +2538,11 @@ ath5k_intr(int irq, void *dev_id) */ ath5k_hw_update_mib_counters(ah, &sc->ll_stats); } + if (status & AR5K_INT_GPIO) + tasklet_schedule(&sc->rf_kill.toggleq); + } - } while (ath5k_hw_is_intr_pending(ah) && counter-- > 0); + } while (ath5k_hw_is_intr_pending(ah) && --counter > 0); if (unlikely(!counter)) ATH5K_WARN(sc, "too many interrupts, giving up for now\n"); @@ -2696,9 +2756,6 @@ static int ath5k_add_interface(struct ieee80211_hw *hw, goto end; } - /* Set to a reasonable value. Note that this will - * be set to mac80211's value at ath5k_config(). */ - sc->bintval = 1000; ath5k_hw_set_lladdr(sc->ah, conf->mac_addr); ret = 0; @@ -2719,6 +2776,7 @@ ath5k_remove_interface(struct ieee80211_hw *hw, goto end; ath5k_hw_set_lladdr(sc->ah, mac); + ath5k_beacon_disable(sc); sc->vif = NULL; end: mutex_unlock(&sc->lock); @@ -2729,54 +2787,44 @@ end: */ static int ath5k_config(struct ieee80211_hw *hw, u32 changed) -{ - struct ath5k_softc *sc = hw->priv; - struct ieee80211_conf *conf = &hw->conf; - int ret; - - mutex_lock(&sc->lock); - - sc->bintval = conf->beacon_int; - sc->power_level = conf->power_level; - - ret = ath5k_chan_set(sc, conf->channel); - - mutex_unlock(&sc->lock); - return ret; -} - -static int -ath5k_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_if_conf *conf) { struct ath5k_softc *sc = hw->priv; struct ath5k_hw *ah = sc->ah; + struct ieee80211_conf *conf = &hw->conf; int ret = 0; mutex_lock(&sc->lock); - if (sc->vif != vif) { - ret = -EIO; + + ret = ath5k_chan_set(sc, conf->channel); + if (ret < 0) goto unlock; + + if ((changed & IEEE80211_CONF_CHANGE_POWER) && + (sc->power_level != conf->power_level)) { + sc->power_level = conf->power_level; + + /* Half dB steps */ + ath5k_hw_set_txpower_limit(ah, (conf->power_level * 2)); } - if (conf->changed & IEEE80211_IFCC_BSSID && conf->bssid) { - /* Cache for later use during resets */ - memcpy(ah->ah_bssid, conf->bssid, ETH_ALEN); - /* XXX: assoc id is set to 0 for now, mac80211 doesn't have - * a clean way of letting us retrieve this yet. */ - ath5k_hw_set_associd(ah, ah->ah_bssid, 0); - mmiowb(); - } - if (conf->changed & IEEE80211_IFCC_BEACON && - (vif->type == NL80211_IFTYPE_ADHOC || - vif->type == NL80211_IFTYPE_MESH_POINT || - vif->type == NL80211_IFTYPE_AP)) { - struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); - if (!beacon) { - ret = -ENOMEM; - goto unlock; - } - ath5k_beacon_update(sc, beacon); - } + + /* TODO: + * 1) Move this on config_interface and handle each case + * separately eg. when we have only one STA vif, use + * AR5K_ANTMODE_SINGLE_AP + * + * 2) Allow the user to change antenna mode eg. when only + * one antenna is present + * + * 3) Allow the user to set default/tx antenna when possible + * + * 4) Default mode should handle 90% of the cases, together + * with fixed a/b and single AP modes we should be able to + * handle 99%. Sectored modes are extreme cases and i still + * haven't found a usage for them. If we decide to support them, + * then we must allow the user to set how many tx antennas we + * have available + */ + ath5k_hw_set_antenna_mode(ah, AR5K_ANTMODE_DEFAULT); unlock: mutex_unlock(&sc->lock); @@ -3020,28 +3068,62 @@ ath5k_reset_tsf(struct ieee80211_hw *hw) ath5k_hw_reset_tsf(sc->ah); } +/* + * Updates the beacon that is sent by ath5k_beacon_send. For adhoc, + * this is called only once at config_bss time, for AP we do it every + * SWBA interrupt so that the TIM will reflect buffered frames. + * + * Called with the beacon lock. + */ static int -ath5k_beacon_update(struct ath5k_softc *sc, struct sk_buff *skb) +ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { - unsigned long flags; int ret; + struct ath5k_softc *sc = hw->priv; + struct sk_buff *skb; + + if (WARN_ON(!vif)) { + ret = -EINVAL; + goto out; + } + + skb = ieee80211_beacon_get(hw, vif); + + if (!skb) { + ret = -ENOMEM; + goto out; + } ath5k_debug_dump_skb(sc, skb, "BC ", 1); - spin_lock_irqsave(&sc->block, flags); ath5k_txbuf_free(sc, sc->bbuf); sc->bbuf->skb = skb; ret = ath5k_beacon_setup(sc, sc->bbuf); if (ret) sc->bbuf->skb = NULL; +out: + return ret; +} + +/* + * Update the beacon and reconfigure the beacon queues. + */ +static void +ath5k_beacon_reconfig(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + int ret; + unsigned long flags; + struct ath5k_softc *sc = hw->priv; + + spin_lock_irqsave(&sc->block, flags); + ret = ath5k_beacon_update(hw, vif); spin_unlock_irqrestore(&sc->block, flags); - if (!ret) { + if (ret == 0) { ath5k_beacon_config(sc); mmiowb(); } - - return ret; } + static void set_beacon_filter(struct ieee80211_hw *hw, bool enable) { @@ -3063,11 +3145,37 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw, u32 changes) { struct ath5k_softc *sc = hw->priv; + struct ath5k_hw *ah = sc->ah; + + mutex_lock(&sc->lock); + if (WARN_ON(sc->vif != vif)) + goto unlock; + + if (changes & BSS_CHANGED_BSSID) { + /* Cache for later use during resets */ + memcpy(ah->ah_bssid, bss_conf->bssid, ETH_ALEN); + /* XXX: assoc id is set to 0 for now, mac80211 doesn't have + * a clean way of letting us retrieve this yet. */ + ath5k_hw_set_associd(ah, ah->ah_bssid, 0); + mmiowb(); + } + + if (changes & BSS_CHANGED_BEACON_INT) + sc->bintval = bss_conf->beacon_int; + if (changes & BSS_CHANGED_ASSOC) { - mutex_lock(&sc->lock); sc->assoc = bss_conf->assoc; if (sc->opmode == NL80211_IFTYPE_STATION) set_beacon_filter(hw, sc->assoc); - mutex_unlock(&sc->lock); } + + if (changes & BSS_CHANGED_BEACON && + (vif->type == NL80211_IFTYPE_ADHOC || + vif->type == NL80211_IFTYPE_MESH_POINT || + vif->type == NL80211_IFTYPE_AP)) { + ath5k_beacon_reconfig(hw, vif); + } + + unlock: + mutex_unlock(&sc->lock); } diff --git a/drivers/net/wireless/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h similarity index 96% rename from drivers/net/wireless/ath5k/base.h rename to drivers/net/wireless/ath/ath5k/base.h index 822956114cd7..f9b7f2f819b7 100644 --- a/drivers/net/wireless/ath5k/base.h +++ b/drivers/net/wireless/ath/ath5k/base.h @@ -46,6 +46,7 @@ #include #include #include +#include #include "ath5k.h" #include "debug.h" @@ -56,7 +57,6 @@ struct ath5k_buf { struct list_head list; - unsigned int flags; /* rx descriptor flags */ struct ath5k_desc *desc; /* virtual addr of desc */ dma_addr_t daddr; /* physical addr of desc */ struct sk_buff *skb; /* skbuff for buf */ @@ -92,6 +92,15 @@ struct ath5k_led struct led_classdev led_dev; /* led classdev */ }; +/* Rfkill */ +struct ath5k_rfkill { + /* GPIO PIN for rfkill */ + u16 gpio; + /* polarity of rfkill GPIO PIN */ + bool polarity; + /* RFKILL toggle tasklet */ + struct tasklet_struct toggleq; +}; #if CHAN_DEBUG #define ATH_CHAN_MAX (26+26+26+200+200) @@ -168,6 +177,8 @@ struct ath5k_softc { struct tasklet_struct txtq; /* tx intr tasklet */ struct ath5k_led tx_led; /* tx led */ + struct ath5k_rfkill rf_kill; + spinlock_t block; /* protects beacon */ struct tasklet_struct beacontq; /* beacon intr tasklet */ struct ath5k_buf *bbuf; /* beacon buffer */ diff --git a/drivers/net/wireless/ath5k/caps.c b/drivers/net/wireless/ath/ath5k/caps.c similarity index 100% rename from drivers/net/wireless/ath5k/caps.c rename to drivers/net/wireless/ath/ath5k/caps.c diff --git a/drivers/net/wireless/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c similarity index 100% rename from drivers/net/wireless/ath5k/debug.c rename to drivers/net/wireless/ath/ath5k/debug.c diff --git a/drivers/net/wireless/ath5k/debug.h b/drivers/net/wireless/ath/ath5k/debug.h similarity index 100% rename from drivers/net/wireless/ath5k/debug.h rename to drivers/net/wireless/ath/ath5k/debug.h diff --git a/drivers/net/wireless/ath5k/desc.c b/drivers/net/wireless/ath/ath5k/desc.c similarity index 100% rename from drivers/net/wireless/ath5k/desc.c rename to drivers/net/wireless/ath/ath5k/desc.c diff --git a/drivers/net/wireless/ath5k/desc.h b/drivers/net/wireless/ath/ath5k/desc.h similarity index 100% rename from drivers/net/wireless/ath5k/desc.h rename to drivers/net/wireless/ath/ath5k/desc.h diff --git a/drivers/net/wireless/ath5k/dma.c b/drivers/net/wireless/ath/ath5k/dma.c similarity index 99% rename from drivers/net/wireless/ath5k/dma.c rename to drivers/net/wireless/ath/ath5k/dma.c index b65b4feb2d28..941b51130a6f 100644 --- a/drivers/net/wireless/ath5k/dma.c +++ b/drivers/net/wireless/ath/ath5k/dma.c @@ -80,8 +80,6 @@ int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah) * ath5k_hw_get_rxdp - Get RX Descriptor's address * * @ah: The &struct ath5k_hw - * - * XXX: Is RXDP read and clear ? */ u32 ath5k_hw_get_rxdp(struct ath5k_hw *ah) { diff --git a/drivers/net/wireless/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c similarity index 96% rename from drivers/net/wireless/ath5k/eeprom.c rename to drivers/net/wireless/ath/ath5k/eeprom.c index c0fb3b09ba45..c56b494d417a 100644 --- a/drivers/net/wireless/ath5k/eeprom.c +++ b/drivers/net/wireless/ath/ath5k/eeprom.c @@ -156,6 +156,17 @@ ath5k_eeprom_init_header(struct ath5k_hw *ah) ee->ee_db[AR5K_EEPROM_MODE_11G][0] = (val >> 3) & 0x7; } + AR5K_EEPROM_READ(AR5K_EEPROM_IS_HB63, val); + + if ((ah->ah_mac_version == (AR5K_SREV_AR2425 >> 4)) && val) + ee->ee_is_hb63 = true; + else + ee->ee_is_hb63 = false; + + AR5K_EEPROM_READ(AR5K_EEPROM_RFKILL, val); + ee->ee_rfkill_pin = (u8) AR5K_REG_MS(val, AR5K_EEPROM_RFKILL_GPIO_SEL); + ee->ee_rfkill_pol = val & AR5K_EEPROM_RFKILL_POLARITY ? true : false; + return 0; } @@ -197,16 +208,16 @@ static int ath5k_eeprom_read_ants(struct ath5k_hw *ah, u32 *offset, ee->ee_ant_control[mode][i++] = (val >> 6) & 0x3f; ee->ee_ant_control[mode][i++] = val & 0x3f; - /* Get antenna modes */ - ah->ah_antenna[mode][0] = + /* Get antenna switch tables */ + ah->ah_ant_ctl[mode][AR5K_ANT_CTL] = (ee->ee_ant_control[mode][0] << 4); - ah->ah_antenna[mode][AR5K_ANT_FIXED_A] = + ah->ah_ant_ctl[mode][AR5K_ANT_SWTABLE_A] = ee->ee_ant_control[mode][1] | (ee->ee_ant_control[mode][2] << 6) | (ee->ee_ant_control[mode][3] << 12) | (ee->ee_ant_control[mode][4] << 18) | (ee->ee_ant_control[mode][5] << 24); - ah->ah_antenna[mode][AR5K_ANT_FIXED_B] = + ah->ah_ant_ctl[mode][AR5K_ANT_SWTABLE_B] = ee->ee_ant_control[mode][6] | (ee->ee_ant_control[mode][7] << 6) | (ee->ee_ant_control[mode][8] << 12) | @@ -640,9 +651,9 @@ ath5k_eeprom_init_11bg_2413(struct ath5k_hw *ah, unsigned int mode, int offset) static inline void ath5k_get_pcdac_intercepts(struct ath5k_hw *ah, u8 min, u8 max, u8 *vp) { - const static u16 intercepts3[] = + static const u16 intercepts3[] = { 0, 5, 10, 20, 30, 50, 70, 85, 90, 95, 100 }; - const static u16 intercepts3_2[] = + static const u16 intercepts3_2[] = { 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 }; const u16 *ip; int i; @@ -1694,9 +1705,40 @@ ath5k_eeprom_read_ctl_info(struct ath5k_hw *ah) return 0; } +static int +ath5k_eeprom_read_spur_chans(struct ath5k_hw *ah) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + u32 offset; + u16 val; + int ret = 0, i; + + offset = AR5K_EEPROM_CTL(ee->ee_version) + + AR5K_EEPROM_N_CTLS(ee->ee_version); + + if (ee->ee_version < AR5K_EEPROM_VERSION_5_3) { + /* No spur info for 5GHz */ + ee->ee_spur_chans[0][0] = AR5K_EEPROM_NO_SPUR; + /* 2 channels for 2GHz (2464/2420) */ + ee->ee_spur_chans[0][1] = AR5K_EEPROM_5413_SPUR_CHAN_1; + ee->ee_spur_chans[1][1] = AR5K_EEPROM_5413_SPUR_CHAN_2; + ee->ee_spur_chans[2][1] = AR5K_EEPROM_NO_SPUR; + } else if (ee->ee_version >= AR5K_EEPROM_VERSION_5_3) { + for (i = 0; i < AR5K_EEPROM_N_SPUR_CHANS; i++) { + AR5K_EEPROM_READ(offset, val); + ee->ee_spur_chans[i][0] = val; + AR5K_EEPROM_READ(offset + AR5K_EEPROM_N_SPUR_CHANS, + val); + ee->ee_spur_chans[i][1] = val; + offset++; + } + } + + return ret; +} /* - * Initialize eeprom power tables + * Initialize eeprom data structure */ int ath5k_eeprom_init(struct ath5k_hw *ah) @@ -1719,6 +1761,10 @@ ath5k_eeprom_init(struct ath5k_hw *ah) if (err < 0) return err; + err = ath5k_eeprom_read_spur_chans(ah); + if (err < 0) + return err; + return 0; } @@ -1754,16 +1800,3 @@ int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac) return 0; } - -bool ath5k_eeprom_is_hb63(struct ath5k_hw *ah) -{ - u16 data; - - ath5k_hw_eeprom_read(ah, AR5K_EEPROM_IS_HB63, &data); - - if ((ah->ah_mac_version == (AR5K_SREV_AR2425 >> 4)) && data) - return true; - else - return false; -} - diff --git a/drivers/net/wireless/ath5k/eeprom.h b/drivers/net/wireless/ath/ath5k/eeprom.h similarity index 94% rename from drivers/net/wireless/ath5k/eeprom.h rename to drivers/net/wireless/ath/ath5k/eeprom.h index b0c0606dea0b..64be73a5edae 100644 --- a/drivers/net/wireless/ath5k/eeprom.h +++ b/drivers/net/wireless/ath/ath5k/eeprom.h @@ -26,6 +26,13 @@ #define AR5K_EEPROM_MAGIC_5210 0x0000145a /* 5210 */ #define AR5K_EEPROM_IS_HB63 0x000b /* Talon detect */ + +#define AR5K_EEPROM_RFKILL 0x0f +#define AR5K_EEPROM_RFKILL_GPIO_SEL 0x0000001c +#define AR5K_EEPROM_RFKILL_GPIO_SEL_S 2 +#define AR5K_EEPROM_RFKILL_POLARITY 0x00000002 +#define AR5K_EEPROM_RFKILL_POLARITY_S 1 + #define AR5K_EEPROM_REG_DOMAIN 0x00bf /* EEPROM regdom */ #define AR5K_EEPROM_CHECKSUM 0x00c0 /* EEPROM checksum */ #define AR5K_EEPROM_INFO_BASE 0x00c0 /* EEPROM header */ @@ -66,11 +73,6 @@ #define AR5K_EEPROM_HDR_RFKILL(_v) (((_v) >> 14) & 0x1) /* Device has RFKill support */ #define AR5K_EEPROM_HDR_T_5GHZ_DIS(_v) (((_v) >> 15) & 0x1) /* Disable turbo for 5Ghz */ -#define AR5K_EEPROM_RFKILL_GPIO_SEL 0x0000001c -#define AR5K_EEPROM_RFKILL_GPIO_SEL_S 2 -#define AR5K_EEPROM_RFKILL_POLARITY 0x00000002 -#define AR5K_EEPROM_RFKILL_POLARITY_S 1 - /* Newer EEPROMs are using a different offset */ #define AR5K_EEPROM_OFF(_v, _v3_0, _v3_3) \ (((_v) >= AR5K_EEPROM_VERSION_3_3) ? _v3_3 : _v3_0) @@ -211,6 +213,23 @@ #define AR5K_EEPROM_I_GAIN 10 #define AR5K_EEPROM_CCK_OFDM_DELTA 15 #define AR5K_EEPROM_N_IQ_CAL 2 +/* 5GHz/2GHz */ +enum ath5k_eeprom_freq_bands{ + AR5K_EEPROM_BAND_5GHZ = 0, + AR5K_EEPROM_BAND_2GHZ = 1, + AR5K_EEPROM_N_FREQ_BANDS, +}; +/* Spur chans per freq band */ +#define AR5K_EEPROM_N_SPUR_CHANS 5 +/* fbin value for chan 2464 x2 */ +#define AR5K_EEPROM_5413_SPUR_CHAN_1 1640 +/* fbin value for chan 2420 x2 */ +#define AR5K_EEPROM_5413_SPUR_CHAN_2 1200 +#define AR5K_EEPROM_SPUR_CHAN_MASK 0x3FFF +#define AR5K_EEPROM_NO_SPUR 0x8000 +#define AR5K_SPUR_CHAN_WIDTH 87 +#define AR5K_SPUR_SYMBOL_WIDTH_BASE_100Hz 3125 +#define AR5K_SPUR_SYMBOL_WIDTH_TURBO_100Hz 6250 #define AR5K_EEPROM_READ(_o, _v) do { \ ret = ath5k_hw_eeprom_read(ah, (_o), &(_v)); \ @@ -221,11 +240,11 @@ #define AR5K_EEPROM_READ_HDR(_o, _v) \ AR5K_EEPROM_READ(_o, ah->ah_capabilities.cap_eeprom._v); \ -enum ath5k_ant_setting { - AR5K_ANT_VARIABLE = 0, /* variable by programming */ - AR5K_ANT_FIXED_A = 1, /* fixed to 11a frequencies */ - AR5K_ANT_FIXED_B = 2, /* fixed to 11b frequencies */ - AR5K_ANT_MAX = 3, +enum ath5k_ant_table { + AR5K_ANT_CTL = 0, /* Idle switch table settings */ + AR5K_ANT_SWTABLE_A = 1, /* Switch table for antenna A */ + AR5K_ANT_SWTABLE_B = 2, /* Switch table for antenna B */ + AR5K_ANT_MAX, }; enum ath5k_ctl_mode { @@ -369,6 +388,9 @@ struct ath5k_eeprom_info { u16 ee_version; u16 ee_header; u16 ee_ant_gain; + u8 ee_rfkill_pin; + bool ee_rfkill_pol; + bool ee_is_hb63; u16 ee_misc0; u16 ee_misc1; u16 ee_misc2; @@ -436,6 +458,10 @@ struct ath5k_eeprom_info { s8 ee_pga_desired_size_turbo[AR5K_EEPROM_N_MODES]; s8 ee_pd_gain_overlap; + /* Spur mitigation data (fbin values for spur channels) */ + u16 ee_spur_chans[AR5K_EEPROM_N_SPUR_CHANS][AR5K_EEPROM_N_FREQ_BANDS]; + + /* Antenna raw switch tables */ u32 ee_antenna[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX]; }; diff --git a/drivers/net/wireless/ath5k/gpio.c b/drivers/net/wireless/ath/ath5k/gpio.c similarity index 100% rename from drivers/net/wireless/ath5k/gpio.c rename to drivers/net/wireless/ath/ath5k/gpio.c diff --git a/drivers/net/wireless/ath5k/initvals.c b/drivers/net/wireless/ath/ath5k/initvals.c similarity index 99% rename from drivers/net/wireless/ath5k/initvals.c rename to drivers/net/wireless/ath/ath5k/initvals.c index 61fb621ed20d..18eb5190ce4b 100644 --- a/drivers/net/wireless/ath5k/initvals.c +++ b/drivers/net/wireless/ath/ath5k/initvals.c @@ -537,8 +537,6 @@ static const struct ath5k_ini ar5212_ini_common_start[] = { { AR5K_DCU_TX_FILTER_1(15), 0x00000000 }, { AR5K_DCU_TX_FILTER_CLR, 0x00000000 }, { AR5K_DCU_TX_FILTER_SET, 0x00000000 }, - { AR5K_DCU_TX_FILTER_CLR, 0x00000000 }, - { AR5K_DCU_TX_FILTER_SET, 0x00000000 }, { AR5K_STA_ID1, 0x00000000 }, { AR5K_BSS_ID0, 0x00000000 }, { AR5K_BSS_ID1, 0x00000000 }, @@ -669,7 +667,7 @@ static const struct ath5k_ini ar5212_ini_common_start[] = { /*{ AR5K_PHY(650), 0x000001b5 },*/ { AR5K_PHY(651), 0x00000000 }, { AR5K_PHY_TXPOWER_RATE3, 0x20202020 }, - { AR5K_PHY_TXPOWER_RATE2, 0x20202020 }, + { AR5K_PHY_TXPOWER_RATE4, 0x20202020 }, /*{ AR5K_PHY(655), 0x13c889af },*/ { AR5K_PHY(656), 0x38490a20 }, { AR5K_PHY(657), 0x00007bb6 }, @@ -718,7 +716,7 @@ static const struct ath5k_ini_mode ar5212_ini_mode_start[] = { { AR5K_PHY_SETTLING, { 0x1372161c, 0x13721c25, 0x13721722, 0x137216a2, 0x13721c25 } }, { AR5K_PHY_AGCCTL, - { 0x00009d10, 0x00009d10, 0x00009d18, 0x00009d18, 0x00009d18 } }, + { 0x00009d10, 0x00009d10, 0x00009d18, 0x00009d18, 0x00009d10 } }, { AR5K_PHY_NF, { 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 } }, { AR5K_PHY_WEAK_OFDM_HIGH_THR, @@ -799,7 +797,7 @@ static const struct ath5k_ini_mode rf5112_ini_mode_end[] = { { AR5K_PHY_DESIRED_SIZE, { 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0 } }, { AR5K_PHY_SIG, - { 0x7e800d2e, 0x7e800d2e, 0x7ee80d2e, 0x7ee80d2e, 0x7ee80d2e } }, + { 0x7e800d2e, 0x7e800d2e, 0x7ee80d2e, 0x7ee80d2e, 0x7e800d2e } }, { AR5K_PHY_AGCCOARSE, { 0x3137665e, 0x3137665e, 0x3137665e, 0x3137665e, 0x3137665e } }, { AR5K_PHY_WEAK_OFDM_LOW_THR, diff --git a/drivers/net/wireless/ath5k/led.c b/drivers/net/wireless/ath/ath5k/led.c similarity index 94% rename from drivers/net/wireless/ath5k/led.c rename to drivers/net/wireless/ath/ath5k/led.c index 19555fb79c9b..876725f08b6c 100644 --- a/drivers/net/wireless/ath5k/led.c +++ b/drivers/net/wireless/ath/ath5k/led.c @@ -53,8 +53,6 @@ /* Devices we match on for LED config info (typically laptops) */ static const struct pci_device_id ath5k_led_devices[] = { - /* IBM-specific AR5212 */ - { PCI_VDEVICE(ATHEROS, PCI_DEVICE_ID_ATHEROS_AR5212_IBM), ATH_LED(0, 0) }, /* AR5211 */ { PCI_VDEVICE(ATHEROS, PCI_DEVICE_ID_ATHEROS_AR5211), ATH_LED(0, 0) }, /* HP Compaq nc6xx, nc4000, nx6000 */ @@ -67,6 +65,12 @@ static const struct pci_device_id ath5k_led_devices[] = { { ATH_SDEVICE(PCI_VENDOR_ID_AMBIT, 0x0428), ATH_LED(3, 0) }, /* Acer Extensa 5620z (nekoreeve@gmail.com) */ { ATH_SDEVICE(PCI_VENDOR_ID_QMI, 0x0105), ATH_LED(3, 0) }, + /* Fukato Datacask Jupiter 1014a (mrb74@gmx.at) */ + { ATH_SDEVICE(PCI_VENDOR_ID_AZWAVE, 0x1026), ATH_LED(3, 0) }, + /* IBM ThinkPad AR5BXB6 (legovini@spiro.fisica.unipd.it) */ + { ATH_SDEVICE(PCI_VENDOR_ID_IBM, 0x058a), ATH_LED(1, 0) }, + /* IBM-specific AR5212 (all others) */ + { PCI_VDEVICE(ATHEROS, PCI_DEVICE_ID_ATHEROS_AR5212_IBM), ATH_LED(0, 0) }, { } }; @@ -78,7 +82,7 @@ void ath5k_led_enable(struct ath5k_softc *sc) } } -void ath5k_led_on(struct ath5k_softc *sc) +static void ath5k_led_on(struct ath5k_softc *sc) { if (!test_bit(ATH_STAT_LEDSOFT, sc->status)) return; diff --git a/drivers/net/wireless/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c similarity index 98% rename from drivers/net/wireless/ath5k/pcu.c rename to drivers/net/wireless/ath/ath5k/pcu.c index 55122f1e1986..2942f13c9c4a 100644 --- a/drivers/net/wireless/ath5k/pcu.c +++ b/drivers/net/wireless/ath/ath5k/pcu.c @@ -733,11 +733,12 @@ void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval) /* * Set the beacon register and enable all timers. */ - /* When in AP mode zero timer0 to start TSF */ - if (ah->ah_op_mode == NL80211_IFTYPE_AP) + /* When in AP or Mesh Point mode zero timer0 to start TSF */ + if (ah->ah_op_mode == NL80211_IFTYPE_AP || + ah->ah_op_mode == NL80211_IFTYPE_MESH_POINT) ath5k_hw_reg_write(ah, 0, AR5K_TIMER0); - else - ath5k_hw_reg_write(ah, next_beacon, AR5K_TIMER0); + + ath5k_hw_reg_write(ah, next_beacon, AR5K_TIMER0); ath5k_hw_reg_write(ah, timer1, AR5K_TIMER1); ath5k_hw_reg_write(ah, timer2, AR5K_TIMER2); ath5k_hw_reg_write(ah, timer3, AR5K_TIMER3); @@ -1003,7 +1004,7 @@ int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry) * Note2: Windows driver (ndiswrapper) sets this to * 0x00000714 instead of 0x00000007 */ - if (ah->ah_version > AR5K_AR5211) { + if (ah->ah_version >= AR5K_AR5211) { ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL, AR5K_KEYTABLE_TYPE(entry)); @@ -1038,9 +1039,9 @@ int ath5k_keycache_type(const struct ieee80211_key_conf *key) case ALG_CCMP: return AR5K_KEYTABLE_TYPE_CCM; case ALG_WEP: - if (key->keylen == LEN_WEP40) + if (key->keylen == WLAN_KEY_LEN_WEP40) return AR5K_KEYTABLE_TYPE_40; - else if (key->keylen == LEN_WEP104) + else if (key->keylen == WLAN_KEY_LEN_WEP104) return AR5K_KEYTABLE_TYPE_104; return -EINVAL; default: diff --git a/drivers/net/wireless/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c similarity index 83% rename from drivers/net/wireless/ath5k/phy.c rename to drivers/net/wireless/ath/ath5k/phy.c index b48b29dca3d2..a876ca8d69ef 100644 --- a/drivers/net/wireless/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -168,9 +168,6 @@ int ath5k_hw_rfgain_opt_init(struct ath5k_hw *ah) * tx power and a Peak to Average Power Detector (PAPD) will try * to measure the gain. * - * TODO: Use propper tx power setting for the probe packet so - * that we don't observe a serious power drop on the receiver - * * XXX: How about forcing a tx packet (bypassing PCU arbitrator etc) * just after we enable the probe so that we don't mess with * standard traffic ? Maybe it's time to use sw interrupts and @@ -186,7 +183,7 @@ static void ath5k_hw_request_rfgain_probe(struct ath5k_hw *ah) /* Send the packet with 2dB below max power as * patent doc suggest */ - ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txpower.txp_max_pwr - 4, + ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txpower.txp_ofdm - 4, AR5K_PHY_PAPD_PROBE_TXPOWER) | AR5K_PHY_PAPD_PROBE_TX_NEXT, AR5K_PHY_PAPD_PROBE); @@ -1356,6 +1353,257 @@ int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, return ret; } +/***************************\ +* Spur mitigation functions * +\***************************/ + +bool ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah, + struct ieee80211_channel *channel) +{ + u8 refclk_freq; + + if ((ah->ah_radio == AR5K_RF5112) || + (ah->ah_radio == AR5K_RF5413) || + (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4))) + refclk_freq = 40; + else + refclk_freq = 32; + + if ((channel->center_freq % refclk_freq != 0) && + ((channel->center_freq % refclk_freq < 10) || + (channel->center_freq % refclk_freq > 22))) + return true; + else + return false; +} + +void +ath5k_hw_set_spur_mitigation_filter(struct ath5k_hw *ah, + struct ieee80211_channel *channel) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + u32 mag_mask[4] = {0, 0, 0, 0}; + u32 pilot_mask[2] = {0, 0}; + /* Note: fbin values are scaled up by 2 */ + u16 spur_chan_fbin, chan_fbin, symbol_width, spur_detection_window; + s32 spur_delta_phase, spur_freq_sigma_delta; + s32 spur_offset, num_symbols_x16; + u8 num_symbol_offsets, i, freq_band; + + /* Convert current frequency to fbin value (the same way channels + * are stored on EEPROM, check out ath5k_eeprom_bin2freq) and scale + * up by 2 so we can compare it later */ + if (channel->hw_value & CHANNEL_2GHZ) { + chan_fbin = (channel->center_freq - 2300) * 10; + freq_band = AR5K_EEPROM_BAND_2GHZ; + } else { + chan_fbin = (channel->center_freq - 4900) * 10; + freq_band = AR5K_EEPROM_BAND_5GHZ; + } + + /* Check if any spur_chan_fbin from EEPROM is + * within our current channel's spur detection range */ + spur_chan_fbin = AR5K_EEPROM_NO_SPUR; + spur_detection_window = AR5K_SPUR_CHAN_WIDTH; + /* XXX: Half/Quarter channels ?*/ + if (channel->hw_value & CHANNEL_TURBO) + spur_detection_window *= 2; + + for (i = 0; i < AR5K_EEPROM_N_SPUR_CHANS; i++) { + spur_chan_fbin = ee->ee_spur_chans[i][freq_band]; + + /* Note: mask cleans AR5K_EEPROM_NO_SPUR flag + * so it's zero if we got nothing from EEPROM */ + if (spur_chan_fbin == AR5K_EEPROM_NO_SPUR) { + spur_chan_fbin &= AR5K_EEPROM_SPUR_CHAN_MASK; + break; + } + + if ((chan_fbin - spur_detection_window <= + (spur_chan_fbin & AR5K_EEPROM_SPUR_CHAN_MASK)) && + (chan_fbin + spur_detection_window >= + (spur_chan_fbin & AR5K_EEPROM_SPUR_CHAN_MASK))) { + spur_chan_fbin &= AR5K_EEPROM_SPUR_CHAN_MASK; + break; + } + } + + /* We need to enable spur filter for this channel */ + if (spur_chan_fbin) { + spur_offset = spur_chan_fbin - chan_fbin; + /* + * Calculate deltas: + * spur_freq_sigma_delta -> spur_offset / sample_freq << 21 + * spur_delta_phase -> spur_offset / chip_freq << 11 + * Note: Both values have 100KHz resolution + */ + /* XXX: Half/Quarter rate channels ? */ + switch (channel->hw_value) { + case CHANNEL_A: + /* Both sample_freq and chip_freq are 40MHz */ + spur_delta_phase = (spur_offset << 17) / 25; + spur_freq_sigma_delta = (spur_delta_phase >> 10); + symbol_width = AR5K_SPUR_SYMBOL_WIDTH_BASE_100Hz; + break; + case CHANNEL_G: + /* sample_freq -> 40MHz chip_freq -> 44MHz + * (for b compatibility) */ + spur_freq_sigma_delta = (spur_offset << 8) / 55; + spur_delta_phase = (spur_offset << 17) / 25; + symbol_width = AR5K_SPUR_SYMBOL_WIDTH_BASE_100Hz; + break; + case CHANNEL_T: + case CHANNEL_TG: + /* Both sample_freq and chip_freq are 80MHz */ + spur_delta_phase = (spur_offset << 16) / 25; + spur_freq_sigma_delta = (spur_delta_phase >> 10); + symbol_width = AR5K_SPUR_SYMBOL_WIDTH_TURBO_100Hz; + break; + default: + return; + } + + /* Calculate pilot and magnitude masks */ + + /* Scale up spur_offset by 1000 to switch to 100HZ resolution + * and divide by symbol_width to find how many symbols we have + * Note: number of symbols is scaled up by 16 */ + num_symbols_x16 = ((spur_offset * 1000) << 4) / symbol_width; + + /* Spur is on a symbol if num_symbols_x16 % 16 is zero */ + if (!(num_symbols_x16 & 0xF)) + /* _X_ */ + num_symbol_offsets = 3; + else + /* _xx_ */ + num_symbol_offsets = 4; + + for (i = 0; i < num_symbol_offsets; i++) { + + /* Calculate pilot mask */ + s32 curr_sym_off = + (num_symbols_x16 / 16) + i + 25; + + /* Pilot magnitude mask seems to be a way to + * declare the boundaries for our detection + * window or something, it's 2 for the middle + * value(s) where the symbol is expected to be + * and 1 on the boundary values */ + u8 plt_mag_map = + (i == 0 || i == (num_symbol_offsets - 1)) + ? 1 : 2; + + if (curr_sym_off >= 0 && curr_sym_off <= 32) { + if (curr_sym_off <= 25) + pilot_mask[0] |= 1 << curr_sym_off; + else if (curr_sym_off >= 27) + pilot_mask[0] |= 1 << (curr_sym_off - 1); + } else if (curr_sym_off >= 33 && curr_sym_off <= 52) + pilot_mask[1] |= 1 << (curr_sym_off - 33); + + /* Calculate magnitude mask (for viterbi decoder) */ + if (curr_sym_off >= -1 && curr_sym_off <= 14) + mag_mask[0] |= + plt_mag_map << (curr_sym_off + 1) * 2; + else if (curr_sym_off >= 15 && curr_sym_off <= 30) + mag_mask[1] |= + plt_mag_map << (curr_sym_off - 15) * 2; + else if (curr_sym_off >= 31 && curr_sym_off <= 46) + mag_mask[2] |= + plt_mag_map << (curr_sym_off - 31) * 2; + else if (curr_sym_off >= 46 && curr_sym_off <= 53) + mag_mask[3] |= + plt_mag_map << (curr_sym_off - 47) * 2; + + } + + /* Write settings on hw to enable spur filter */ + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_BIN_MASK_CTL, + AR5K_PHY_BIN_MASK_CTL_RATE, 0xff); + /* XXX: Self correlator also ? */ + AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, + AR5K_PHY_IQ_PILOT_MASK_EN | + AR5K_PHY_IQ_CHAN_MASK_EN | + AR5K_PHY_IQ_SPUR_FILT_EN); + + /* Set delta phase and freq sigma delta */ + ath5k_hw_reg_write(ah, + AR5K_REG_SM(spur_delta_phase, + AR5K_PHY_TIMING_11_SPUR_DELTA_PHASE) | + AR5K_REG_SM(spur_freq_sigma_delta, + AR5K_PHY_TIMING_11_SPUR_FREQ_SD) | + AR5K_PHY_TIMING_11_USE_SPUR_IN_AGC, + AR5K_PHY_TIMING_11); + + /* Write pilot masks */ + ath5k_hw_reg_write(ah, pilot_mask[0], AR5K_PHY_TIMING_7); + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_8, + AR5K_PHY_TIMING_8_PILOT_MASK_2, + pilot_mask[1]); + + ath5k_hw_reg_write(ah, pilot_mask[0], AR5K_PHY_TIMING_9); + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_10, + AR5K_PHY_TIMING_10_PILOT_MASK_2, + pilot_mask[1]); + + /* Write magnitude masks */ + ath5k_hw_reg_write(ah, mag_mask[0], AR5K_PHY_BIN_MASK_1); + ath5k_hw_reg_write(ah, mag_mask[1], AR5K_PHY_BIN_MASK_2); + ath5k_hw_reg_write(ah, mag_mask[2], AR5K_PHY_BIN_MASK_3); + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_BIN_MASK_CTL, + AR5K_PHY_BIN_MASK_CTL_MASK_4, + mag_mask[3]); + + ath5k_hw_reg_write(ah, mag_mask[0], AR5K_PHY_BIN_MASK2_1); + ath5k_hw_reg_write(ah, mag_mask[1], AR5K_PHY_BIN_MASK2_2); + ath5k_hw_reg_write(ah, mag_mask[2], AR5K_PHY_BIN_MASK2_3); + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_BIN_MASK2_4, + AR5K_PHY_BIN_MASK2_4_MASK_4, + mag_mask[3]); + + } else if (ath5k_hw_reg_read(ah, AR5K_PHY_IQ) & + AR5K_PHY_IQ_SPUR_FILT_EN) { + /* Clean up spur mitigation settings and disable fliter */ + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_BIN_MASK_CTL, + AR5K_PHY_BIN_MASK_CTL_RATE, 0); + AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_IQ, + AR5K_PHY_IQ_PILOT_MASK_EN | + AR5K_PHY_IQ_CHAN_MASK_EN | + AR5K_PHY_IQ_SPUR_FILT_EN); + ath5k_hw_reg_write(ah, 0, AR5K_PHY_TIMING_11); + + /* Clear pilot masks */ + ath5k_hw_reg_write(ah, 0, AR5K_PHY_TIMING_7); + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_8, + AR5K_PHY_TIMING_8_PILOT_MASK_2, + 0); + + ath5k_hw_reg_write(ah, 0, AR5K_PHY_TIMING_9); + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_10, + AR5K_PHY_TIMING_10_PILOT_MASK_2, + 0); + + /* Clear magnitude masks */ + ath5k_hw_reg_write(ah, 0, AR5K_PHY_BIN_MASK_1); + ath5k_hw_reg_write(ah, 0, AR5K_PHY_BIN_MASK_2); + ath5k_hw_reg_write(ah, 0, AR5K_PHY_BIN_MASK_3); + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_BIN_MASK_CTL, + AR5K_PHY_BIN_MASK_CTL_MASK_4, + 0); + + ath5k_hw_reg_write(ah, 0, AR5K_PHY_BIN_MASK2_1); + ath5k_hw_reg_write(ah, 0, AR5K_PHY_BIN_MASK2_2); + ath5k_hw_reg_write(ah, 0, AR5K_PHY_BIN_MASK2_3); + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_BIN_MASK2_4, + AR5K_PHY_BIN_MASK2_4_MASK_4, + 0); + } +} + +/********************\ + Misc PHY functions +\********************/ + int ath5k_hw_phy_disable(struct ath5k_hw *ah) { ATH5K_TRACE(ah->ah_sc); @@ -1365,10 +1613,6 @@ int ath5k_hw_phy_disable(struct ath5k_hw *ah) return 0; } -/********************\ - Misc PHY functions -\********************/ - /* * Get the PHY Chip revision */ @@ -1417,25 +1661,189 @@ u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan) return ret; } +/*****************\ +* Antenna control * +\*****************/ + void /*TODO:Boundary check*/ -ath5k_hw_set_def_antenna(struct ath5k_hw *ah, unsigned int ant) +ath5k_hw_set_def_antenna(struct ath5k_hw *ah, u8 ant) { ATH5K_TRACE(ah->ah_sc); - /*Just a try M.F.*/ + if (ah->ah_version != AR5K_AR5210) - ath5k_hw_reg_write(ah, ant, AR5K_DEFAULT_ANTENNA); + ath5k_hw_reg_write(ah, ant & 0x7, AR5K_DEFAULT_ANTENNA); } unsigned int ath5k_hw_get_def_antenna(struct ath5k_hw *ah) { ATH5K_TRACE(ah->ah_sc); - /*Just a try M.F.*/ + if (ah->ah_version != AR5K_AR5210) - return ath5k_hw_reg_read(ah, AR5K_DEFAULT_ANTENNA); + return ath5k_hw_reg_read(ah, AR5K_DEFAULT_ANTENNA) & 0x7; return false; /*XXX: What do we return for 5210 ?*/ } +/* + * Enable/disable fast rx antenna diversity + */ +static void +ath5k_hw_set_fast_div(struct ath5k_hw *ah, u8 ee_mode, bool enable) +{ + switch (ee_mode) { + case AR5K_EEPROM_MODE_11G: + /* XXX: This is set to + * disabled on initvals !!! */ + case AR5K_EEPROM_MODE_11A: + if (enable) + AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_AGCCTL, + AR5K_PHY_AGCCTL_OFDM_DIV_DIS); + else + AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL, + AR5K_PHY_AGCCTL_OFDM_DIV_DIS); + break; + case AR5K_EEPROM_MODE_11B: + AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL, + AR5K_PHY_AGCCTL_OFDM_DIV_DIS); + break; + default: + return; + } + + if (enable) { + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_RESTART, + AR5K_PHY_RESTART_DIV_GC, 0xc); + + AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_FAST_ANT_DIV, + AR5K_PHY_FAST_ANT_DIV_EN); + } else { + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_RESTART, + AR5K_PHY_RESTART_DIV_GC, 0x8); + + AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_FAST_ANT_DIV, + AR5K_PHY_FAST_ANT_DIV_EN); + } +} + +/* + * Set antenna operating mode + */ +void +ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode) +{ + struct ieee80211_channel *channel = &ah->ah_current_channel; + bool use_def_for_tx, update_def_on_tx, use_def_for_rts, fast_div; + bool use_def_for_sg; + u8 def_ant, tx_ant, ee_mode; + u32 sta_id1 = 0; + + def_ant = ah->ah_def_ant; + + ATH5K_TRACE(ah->ah_sc); + + switch (channel->hw_value & CHANNEL_MODES) { + case CHANNEL_A: + case CHANNEL_T: + case CHANNEL_XR: + ee_mode = AR5K_EEPROM_MODE_11A; + break; + case CHANNEL_G: + case CHANNEL_TG: + ee_mode = AR5K_EEPROM_MODE_11G; + break; + case CHANNEL_B: + ee_mode = AR5K_EEPROM_MODE_11B; + break; + default: + ATH5K_ERR(ah->ah_sc, + "invalid channel: %d\n", channel->center_freq); + return; + } + + switch (ant_mode) { + case AR5K_ANTMODE_DEFAULT: + tx_ant = 0; + use_def_for_tx = false; + update_def_on_tx = false; + use_def_for_rts = false; + use_def_for_sg = false; + fast_div = true; + break; + case AR5K_ANTMODE_FIXED_A: + def_ant = 1; + tx_ant = 0; + use_def_for_tx = true; + update_def_on_tx = false; + use_def_for_rts = true; + use_def_for_sg = true; + fast_div = false; + break; + case AR5K_ANTMODE_FIXED_B: + def_ant = 2; + tx_ant = 0; + use_def_for_tx = true; + update_def_on_tx = false; + use_def_for_rts = true; + use_def_for_sg = true; + fast_div = false; + break; + case AR5K_ANTMODE_SINGLE_AP: + def_ant = 1; /* updated on tx */ + tx_ant = 0; + use_def_for_tx = true; + update_def_on_tx = true; + use_def_for_rts = true; + use_def_for_sg = true; + fast_div = true; + break; + case AR5K_ANTMODE_SECTOR_AP: + tx_ant = 1; /* variable */ + use_def_for_tx = false; + update_def_on_tx = false; + use_def_for_rts = true; + use_def_for_sg = false; + fast_div = false; + break; + case AR5K_ANTMODE_SECTOR_STA: + tx_ant = 1; /* variable */ + use_def_for_tx = true; + update_def_on_tx = false; + use_def_for_rts = true; + use_def_for_sg = false; + fast_div = true; + break; + case AR5K_ANTMODE_DEBUG: + def_ant = 1; + tx_ant = 2; + use_def_for_tx = false; + update_def_on_tx = false; + use_def_for_rts = false; + use_def_for_sg = false; + fast_div = false; + break; + default: + return; + } + + ah->ah_tx_ant = tx_ant; + ah->ah_ant_mode = ant_mode; + + sta_id1 |= use_def_for_tx ? AR5K_STA_ID1_DEFAULT_ANTENNA : 0; + sta_id1 |= update_def_on_tx ? AR5K_STA_ID1_DESC_ANTENNA : 0; + sta_id1 |= use_def_for_rts ? AR5K_STA_ID1_RTS_DEF_ANTENNA : 0; + sta_id1 |= use_def_for_sg ? AR5K_STA_ID1_SELFGEN_DEF_ANT : 0; + + AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, AR5K_STA_ID1_ANTENNA_SETTINGS); + + if (sta_id1) + AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, sta_id1); + + /* Note: set diversity before default antenna + * because it won't work correctly */ + ath5k_hw_set_fast_div(ah, ee_mode, fast_div); + ath5k_hw_set_def_antenna(ah, def_ant); +} + /****************\ * TX power setup * @@ -1489,6 +1897,9 @@ ath5k_get_linear_pcdac_min(const u8 *stepL, const u8 *stepR, s16 min_pwrL, min_pwrR; s16 pwr_i; + if (WARN_ON(stepL[0] == stepL[1] || stepR[0] == stepR[1])) + return 0; + if (pwrL[0] == pwrL[1]) min_pwrL = pwrL[0]; else { @@ -1750,8 +2161,6 @@ done: * Get the max edge power for this channel if * we have such data from EEPROM's Conformance Test * Limits (CTL), and limit max power if needed. - * - * FIXME: Only works for world regulatory domains */ static void ath5k_get_max_ctl_power(struct ath5k_hw *ah, @@ -1767,26 +2176,23 @@ ath5k_get_max_ctl_power(struct ath5k_hw *ah, u8 ctl_idx = 0xFF; u32 target = channel->center_freq; - /* Find out a CTL for our mode that's not mapped - * on a specific reg domain. - * - * TODO: Map our current reg domain to one of the 3 available - * reg domain ids so that we can support more CTLs. */ + ctl_mode = ath_regd_get_band_ctl(&ah->ah_regulatory, channel->band); + switch (channel->hw_value & CHANNEL_MODES) { case CHANNEL_A: - ctl_mode = AR5K_CTL_11A | AR5K_CTL_NO_REGDOMAIN; + ctl_mode |= AR5K_CTL_11A; break; case CHANNEL_G: - ctl_mode = AR5K_CTL_11G | AR5K_CTL_NO_REGDOMAIN; + ctl_mode |= AR5K_CTL_11G; break; case CHANNEL_B: - ctl_mode = AR5K_CTL_11B | AR5K_CTL_NO_REGDOMAIN; + ctl_mode |= AR5K_CTL_11B; break; case CHANNEL_T: - ctl_mode = AR5K_CTL_TURBO | AR5K_CTL_NO_REGDOMAIN; + ctl_mode |= AR5K_CTL_TURBO; break; case CHANNEL_TG: - ctl_mode = AR5K_CTL_TURBOG | AR5K_CTL_NO_REGDOMAIN; + ctl_mode |= AR5K_CTL_TURBOG; break; case CHANNEL_XR: /* Fall through */ @@ -2482,8 +2888,19 @@ ath5k_setup_rate_powertable(struct ath5k_hw *ah, u16 max_pwr, for (i = 8; i <= 15; i++) rates[i] -= ah->ah_txpower.txp_cck_ofdm_gainf_delta; - ah->ah_txpower.txp_min_pwr = rates[7]; - ah->ah_txpower.txp_max_pwr = rates[0]; + /* Now that we have all rates setup use table offset to + * match the power range set by user with the power indices + * on PCDAC/PDADC table */ + for (i = 0; i < 16; i++) { + rates[i] += ah->ah_txpower.txp_offset; + /* Don't get out of bounds */ + if (rates[i] > 63) + rates[i] = 63; + } + + /* Min/max in 0.25dB units */ + ah->ah_txpower.txp_min_pwr = 2 * rates[7]; + ah->ah_txpower.txp_max_pwr = 2 * rates[0]; ah->ah_txpower.txp_ofdm = rates[7]; } @@ -2591,16 +3008,37 @@ ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel, return 0; } -int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 mode, u8 txpower) +int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 txpower) { /*Just a try M.F.*/ struct ieee80211_channel *channel = &ah->ah_current_channel; + u8 ee_mode; ATH5K_TRACE(ah->ah_sc); + + switch (channel->hw_value & CHANNEL_MODES) { + case CHANNEL_A: + case CHANNEL_T: + case CHANNEL_XR: + ee_mode = AR5K_EEPROM_MODE_11A; + break; + case CHANNEL_G: + case CHANNEL_TG: + ee_mode = AR5K_EEPROM_MODE_11G; + break; + case CHANNEL_B: + ee_mode = AR5K_EEPROM_MODE_11B; + break; + default: + ATH5K_ERR(ah->ah_sc, + "invalid channel: %d\n", channel->center_freq); + return -EINVAL; + } + ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_TXPOWER, "changing txpower to %d\n", txpower); - return ath5k_hw_txpower(ah, channel, mode, txpower); + return ath5k_hw_txpower(ah, channel, ee_mode, txpower); } #undef _ATH5K_PHY diff --git a/drivers/net/wireless/ath5k/qcu.c b/drivers/net/wireless/ath/ath5k/qcu.c similarity index 98% rename from drivers/net/wireless/ath5k/qcu.c rename to drivers/net/wireless/ath/ath5k/qcu.c index 5094c394a4b2..73407b3f53ef 100644 --- a/drivers/net/wireless/ath5k/qcu.c +++ b/drivers/net/wireless/ath/ath5k/qcu.c @@ -160,7 +160,8 @@ u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue) if (ah->ah_version == AR5K_AR5210) return false; - pending = (AR5K_QUEUE_STATUS(queue) & AR5K_QCU_STS_FRMPENDCNT); + pending = ath5k_hw_reg_read(ah, AR5K_QUEUE_STATUS(queue)); + pending &= AR5K_QCU_STS_FRMPENDCNT; /* It's possible to have no frames pending even if TXE * is set. To indicate that q has not stopped return @@ -401,14 +402,16 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue), (AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL << AR5K_DCU_MISC_ARBLOCK_CTL_S) | + AR5K_DCU_MISC_ARBLOCK_IGNORE | AR5K_DCU_MISC_POST_FR_BKOFF_DIS | AR5K_DCU_MISC_BCN_ENABLE); break; case AR5K_TX_QUEUE_CAB: AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), - AR5K_QCU_MISC_FRSHED_DBA_GT | + AR5K_QCU_MISC_FRSHED_BCN_SENT_GT | AR5K_QCU_MISC_CBREXP_DIS | + AR5K_QCU_MISC_RDY_VEOL_POLICY | AR5K_QCU_MISC_CBREXP_BCN_DIS); ath5k_hw_reg_write(ah, ((AR5K_TUNE_BEACON_INTERVAL - diff --git a/drivers/net/wireless/ath5k/reg.h b/drivers/net/wireless/ath/ath5k/reg.h similarity index 99% rename from drivers/net/wireless/ath5k/reg.h rename to drivers/net/wireless/ath/ath5k/reg.h index 7070d1543cdc..6809b54a2ad7 100644 --- a/drivers/net/wireless/ath5k/reg.h +++ b/drivers/net/wireless/ath/ath5k/reg.h @@ -1148,6 +1148,11 @@ #define AR5K_STA_ID1_CBCIV_ENDIAN 0x40000000 /* ??? */ #define AR5K_STA_ID1_KEYSRCH_MCAST 0x80000000 /* Do key cache search for mcast frames */ +#define AR5K_STA_ID1_ANTENNA_SETTINGS (AR5K_STA_ID1_DEFAULT_ANTENNA | \ + AR5K_STA_ID1_DESC_ANTENNA | \ + AR5K_STA_ID1_RTS_DEF_ANTENNA | \ + AR5K_STA_ID1_SELFGEN_DEF_ANT) + /* * First BSSID register (MAC address, lower 32bits) */ @@ -2028,7 +2033,9 @@ #define AR5K_PHY_AGCCTL 0x9860 /* Register address */ #define AR5K_PHY_AGCCTL_CAL 0x00000001 /* Enable PHY calibration */ #define AR5K_PHY_AGCCTL_NF 0x00000002 /* Enable Noise Floor calibration */ +#define AR5K_PHY_AGCCTL_OFDM_DIV_DIS 0x00000008 /* Disable antenna diversity on OFDM modes */ #define AR5K_PHY_AGCCTL_NF_EN 0x00008000 /* Enable nf calibration to happen (?) */ +#define AR5K_PHY_AGCTL_FLTR_CAL 0x00010000 /* Allow filter calibration (?) */ #define AR5K_PHY_AGCCTL_NF_NOUPDATE 0x00020000 /* Don't update nf automaticaly */ /* @@ -2528,7 +2535,7 @@ * PHY CCK Cross-correlator Barker RSSI threshold register [5212+] */ #define AR5K_PHY_CCK_CROSSCORR 0xa208 -#define AR5K_PHY_CCK_CROSSCORR_WEAK_SIG_THR 0x0000000f +#define AR5K_PHY_CCK_CROSSCORR_WEAK_SIG_THR 0x0000003f #define AR5K_PHY_CCK_CROSSCORR_WEAK_SIG_THR_S 0 /* Same address is used for antenna diversity activation */ diff --git a/drivers/net/wireless/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c similarity index 95% rename from drivers/net/wireless/ath5k/reset.c rename to drivers/net/wireless/ath/ath5k/reset.c index 5f72c111c2e8..bd0a97a38d34 100644 --- a/drivers/net/wireless/ath5k/reset.c +++ b/drivers/net/wireless/ath/ath5k/reset.c @@ -54,9 +54,8 @@ static inline int ath5k_hw_write_ofdm_timings(struct ath5k_hw *ah, u32 coef_scaled, coef_exp, coef_man, ds_coef_exp, ds_coef_man, clock; - if (!(ah->ah_version == AR5K_AR5212) || - !(channel->hw_value & CHANNEL_OFDM)) - BUG(); + BUG_ON(!(ah->ah_version == AR5K_AR5212) || + !(channel->hw_value & CHANNEL_OFDM)); /* Get coefficient * ALGO: coef = (5 * clock * carrier_freq) / 2) @@ -508,7 +507,7 @@ static void ath5k_hw_set_sleep_clock(struct ath5k_hw *ah, bool enable) if (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4)) scal = AR5K_PHY_SCAL_32MHZ_2417; - else if (ath5k_eeprom_is_hb63(ah)) + else if (ee->ee_is_hb63) scal = AR5K_PHY_SCAL_32MHZ_HB63; else scal = AR5K_PHY_SCAL_32MHZ; @@ -537,26 +536,6 @@ static void ath5k_hw_set_sleep_clock(struct ath5k_hw *ah, bool enable) return; } -static bool ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah, - struct ieee80211_channel *channel) -{ - u8 refclk_freq; - - if ((ah->ah_radio == AR5K_RF5112) || - (ah->ah_radio == AR5K_RF5413) || - (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4))) - refclk_freq = 40; - else - refclk_freq = 32; - - if ((channel->center_freq % refclk_freq != 0) && - ((channel->center_freq % refclk_freq < 10) || - (channel->center_freq % refclk_freq > 22))) - return true; - else - return false; -} - /* TODO: Half/Quarter rate */ static void ath5k_hw_tweak_initval_settings(struct ath5k_hw *ah, struct ieee80211_channel *channel) @@ -599,9 +578,10 @@ static void ath5k_hw_tweak_initval_settings(struct ath5k_hw *ah, /* Set DAC/ADC delays */ if (ah->ah_version == AR5K_AR5212) { u32 scal; + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; if (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4)) scal = AR5K_PHY_SCAL_32MHZ_2417; - else if (ath5k_eeprom_is_hb63(ah)) + else if (ee->ee_is_hb63) scal = AR5K_PHY_SCAL_32MHZ_HB63; else scal = AR5K_PHY_SCAL_32MHZ; @@ -698,13 +678,13 @@ static void ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah, /* Set antenna idle switch table */ AR5K_REG_WRITE_BITS(ah, AR5K_PHY_ANT_CTL, AR5K_PHY_ANT_CTL_SWTABLE_IDLE, - (ah->ah_antenna[ee_mode][0] | + (ah->ah_ant_ctl[ee_mode][0] | AR5K_PHY_ANT_CTL_TXRX_EN)); - /* Set antenna switch table */ - ath5k_hw_reg_write(ah, ah->ah_antenna[ee_mode][ant[0]], + /* Set antenna switch tables */ + ath5k_hw_reg_write(ah, ah->ah_ant_ctl[ee_mode][ant[0]], AR5K_PHY_ANT_SWITCH_TABLE_0); - ath5k_hw_reg_write(ah, ah->ah_antenna[ee_mode][ant[1]], + ath5k_hw_reg_write(ah, ah->ah_ant_ctl[ee_mode][ant[1]], AR5K_PHY_ANT_SWITCH_TABLE_1); /* Noise floor threshold */ @@ -998,10 +978,10 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, ath5k_hw_tweak_initval_settings(ah, channel); /* - * Set TX power (FIXME) + * Set TX power */ ret = ath5k_hw_txpower(ah, channel, ee_mode, - AR5K_TUNE_DEFAULT_TXPOWER); + ah->ah_txpower.txp_max_pwr / 2); if (ret) return ret; @@ -1024,9 +1004,22 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, /* Write OFDM timings on 5212*/ if (ah->ah_version == AR5K_AR5212 && channel->hw_value & CHANNEL_OFDM) { + struct ath5k_eeprom_info *ee = + &ah->ah_capabilities.cap_eeprom; + ret = ath5k_hw_write_ofdm_timings(ah, channel); if (ret) return ret; + + /* Note: According to docs we can have a newer + * EEPROM on old hardware, so we need to verify + * that our hardware is new enough to have spur + * mitigation registers (delta phase etc) */ + if (ah->ah_mac_srev >= AR5K_SREV_AR5424 || + (ah->ah_mac_srev >= AR5K_SREV_AR5424 && + ee->ee_version >= AR5K_EEPROM_VERSION_5_3)) + ath5k_hw_set_spur_mitigation_filter(ah, + channel); } /*Enable/disable 802.11b mode on 5111 @@ -1042,17 +1035,15 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, /* * In case a fixed antenna was set as default - * write the same settings on both AR5K_PHY_ANT_SWITCH_TABLE - * registers. + * use the same switch table twice. */ - if (s_ant != 0) { - if (s_ant == AR5K_ANT_FIXED_A) /* 1 - Main */ - ant[0] = ant[1] = AR5K_ANT_FIXED_A; - else /* 2 - Aux */ - ant[0] = ant[1] = AR5K_ANT_FIXED_B; - } else { - ant[0] = AR5K_ANT_FIXED_A; - ant[1] = AR5K_ANT_FIXED_B; + if (ah->ah_ant_mode == AR5K_ANTMODE_FIXED_A) + ant[0] = ant[1] = AR5K_ANT_SWTABLE_A; + else if (ah->ah_ant_mode == AR5K_ANTMODE_FIXED_B) + ant[0] = ant[1] = AR5K_ANT_SWTABLE_B; + else { + ant[0] = AR5K_ANT_SWTABLE_A; + ant[1] = AR5K_ANT_SWTABLE_B; } /* Commit values from EEPROM */ @@ -1260,6 +1251,8 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, */ ath5k_hw_noise_floor_calibration(ah, channel->center_freq); + /* Restore antenna mode */ + ath5k_hw_set_antenna_mode(ah, ah->ah_ant_mode); /* * Configure QCUs/DCUs @@ -1311,23 +1304,6 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, if (ah->ah_version != AR5K_AR5210) ath5k_hw_set_imr(ah, ah->ah_imr); - /* - * Setup RFKill interrupt if rfkill flag is set on eeprom. - * TODO: Use gpio pin and polarity infos from eeprom - * TODO: Handle this in ath5k_intr because it'll result - * a nasty interrupt storm. - */ -#if 0 - if (AR5K_EEPROM_HDR_RFKILL(ah->ah_capabilities.cap_eeprom.ee_header)) { - ath5k_hw_set_gpio_input(ah, 0); - ah->ah_gpio[0] = ath5k_hw_get_gpio(ah, 0); - if (ah->ah_gpio[0] == 0) - ath5k_hw_set_gpio_intr(ah, 0, 1); - else - ath5k_hw_set_gpio_intr(ah, 0, 0); - } -#endif - /* Enable 32KHz clock function for AR5212+ chips * Set clocks to 32KHz operation and use an * external 32KHz crystal when sleeping if one diff --git a/drivers/net/wireless/ath5k/rfbuffer.h b/drivers/net/wireless/ath/ath5k/rfbuffer.h similarity index 100% rename from drivers/net/wireless/ath5k/rfbuffer.h rename to drivers/net/wireless/ath/ath5k/rfbuffer.h diff --git a/drivers/net/wireless/ath5k/rfgain.h b/drivers/net/wireless/ath/ath5k/rfgain.h similarity index 100% rename from drivers/net/wireless/ath5k/rfgain.h rename to drivers/net/wireless/ath/ath5k/rfgain.h diff --git a/drivers/net/wireless/ath/ath5k/rfkill.c b/drivers/net/wireless/ath/ath5k/rfkill.c new file mode 100644 index 000000000000..41a877b73fce --- /dev/null +++ b/drivers/net/wireless/ath/ath5k/rfkill.c @@ -0,0 +1,121 @@ +/* + * RFKILL support for ath5k + * + * Copyright (c) 2009 Tobias Doerffel + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + */ + +#include "base.h" + + +static inline void ath5k_rfkill_disable(struct ath5k_softc *sc) +{ + ATH5K_DBG(sc, ATH5K_DEBUG_ANY, "rfkill disable (gpio:%d polarity:%d)\n", + sc->rf_kill.gpio, sc->rf_kill.polarity); + ath5k_hw_set_gpio_output(sc->ah, sc->rf_kill.gpio); + ath5k_hw_set_gpio(sc->ah, sc->rf_kill.gpio, !sc->rf_kill.polarity); +} + + +static inline void ath5k_rfkill_enable(struct ath5k_softc *sc) +{ + ATH5K_DBG(sc, ATH5K_DEBUG_ANY, "rfkill enable (gpio:%d polarity:%d)\n", + sc->rf_kill.gpio, sc->rf_kill.polarity); + ath5k_hw_set_gpio_output(sc->ah, sc->rf_kill.gpio); + ath5k_hw_set_gpio(sc->ah, sc->rf_kill.gpio, sc->rf_kill.polarity); +} + +static inline void ath5k_rfkill_set_intr(struct ath5k_softc *sc, bool enable) +{ + struct ath5k_hw *ah = sc->ah; + u32 curval; + + ath5k_hw_set_gpio_input(ah, sc->rf_kill.gpio); + curval = ath5k_hw_get_gpio(ah, sc->rf_kill.gpio); + ath5k_hw_set_gpio_intr(ah, sc->rf_kill.gpio, enable ? + !!curval : !curval); +} + +static bool +ath5k_is_rfkill_set(struct ath5k_softc *sc) +{ + /* configuring GPIO for input for some reason disables rfkill */ + /*ath5k_hw_set_gpio_input(sc->ah, sc->rf_kill.gpio);*/ + return ath5k_hw_get_gpio(sc->ah, sc->rf_kill.gpio) == + sc->rf_kill.polarity; +} + +static void +ath5k_tasklet_rfkill_toggle(unsigned long data) +{ + struct ath5k_softc *sc = (void *)data; + bool blocked; + + blocked = ath5k_is_rfkill_set(sc); + wiphy_rfkill_set_hw_state(sc->hw->wiphy, blocked); +} + + +void +ath5k_rfkill_hw_start(struct ath5k_hw *ah) +{ + struct ath5k_softc *sc = ah->ah_sc; + + /* read rfkill GPIO configuration from EEPROM header */ + sc->rf_kill.gpio = ah->ah_capabilities.cap_eeprom.ee_rfkill_pin; + sc->rf_kill.polarity = ah->ah_capabilities.cap_eeprom.ee_rfkill_pol; + + tasklet_init(&sc->rf_kill.toggleq, ath5k_tasklet_rfkill_toggle, + (unsigned long)sc); + + ath5k_rfkill_disable(sc); + + /* enable interrupt for rfkill switch */ + if (AR5K_EEPROM_HDR_RFKILL(ah->ah_capabilities.cap_eeprom.ee_header)) + ath5k_rfkill_set_intr(sc, true); +} + + +void +ath5k_rfkill_hw_stop(struct ath5k_hw *ah) +{ + struct ath5k_softc *sc = ah->ah_sc; + + /* disable interrupt for rfkill switch */ + if (AR5K_EEPROM_HDR_RFKILL(ah->ah_capabilities.cap_eeprom.ee_header)) + ath5k_rfkill_set_intr(sc, false); + + tasklet_kill(&sc->rf_kill.toggleq); + + /* enable RFKILL when stopping HW so Wifi LED is turned off */ + ath5k_rfkill_enable(sc); +} + diff --git a/drivers/net/wireless/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig similarity index 95% rename from drivers/net/wireless/ath9k/Kconfig rename to drivers/net/wireless/ath/ath9k/Kconfig index 90a8dd873786..2d79610bce12 100644 --- a/drivers/net/wireless/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig @@ -1,7 +1,7 @@ config ATH9K tristate "Atheros 802.11n wireless cards support" depends on PCI && MAC80211 && WLAN_80211 - depends on RFKILL || RFKILL=n + select ATH_COMMON select MAC80211_LEDS select LEDS_CLASS select NEW_LEDS diff --git a/drivers/net/wireless/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile similarity index 96% rename from drivers/net/wireless/ath9k/Makefile rename to drivers/net/wireless/ath/ath9k/Makefile index 1a4d4eab6fe8..783bc39eb2ff 100644 --- a/drivers/net/wireless/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile @@ -4,7 +4,6 @@ ath9k-y += hw.o \ calib.o \ ani.o \ phy.o \ - regd.o \ beacon.o \ main.o \ recv.o \ diff --git a/drivers/net/wireless/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c similarity index 100% rename from drivers/net/wireless/ath9k/ahb.c rename to drivers/net/wireless/ath/ath9k/ahb.c diff --git a/drivers/net/wireless/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c similarity index 99% rename from drivers/net/wireless/ath9k/ani.c rename to drivers/net/wireless/ath/ath9k/ani.c index 6c5e887d50d7..1aeafb511ddd 100644 --- a/drivers/net/wireless/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -569,8 +569,7 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah, DPRINTF(ah->ah_sc, ATH_DBG_ANI, "phyCnt1 0x%x, resetting " "counter value to 0x%x\n", - phyCnt1, - aniState->ofdmPhyErrBase); + phyCnt1, aniState->ofdmPhyErrBase); REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase); REG_WRITE(ah, AR_PHY_ERR_MASK_1, @@ -580,8 +579,7 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah, DPRINTF(ah->ah_sc, ATH_DBG_ANI, "phyCnt2 0x%x, resetting " "counter value to 0x%x\n", - phyCnt2, - aniState->cckPhyErrBase); + phyCnt2, aniState->cckPhyErrBase); REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase); REG_WRITE(ah, AR_PHY_ERR_MASK_2, @@ -667,7 +665,7 @@ u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah, u32 cc = REG_READ(ah, AR_CCCNT); if (cycles == 0 || cycles > cc) { - DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, + DPRINTF(ah->ah_sc, ATH_DBG_ANI, "cycle counter wrap. ExtBusy = 0\n"); good = 0; } else { diff --git a/drivers/net/wireless/ath9k/ani.h b/drivers/net/wireless/ath/ath9k/ani.h similarity index 100% rename from drivers/net/wireless/ath9k/ani.h rename to drivers/net/wireless/ath/ath9k/ani.h diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h similarity index 87% rename from drivers/net/wireless/ath9k/ath9k.h rename to drivers/net/wireless/ath/ath9k/ath9k.h index 2689a08a2844..5efc9345ca0d 100644 --- a/drivers/net/wireless/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -21,7 +21,6 @@ #include #include #include -#include #include "hw.h" #include "rc.h" @@ -53,11 +52,7 @@ struct ath_node; #define A_MAX(a, b) ((a) > (b) ? (a) : (b)) -#define ASSERT(exp) do { \ - if (unlikely(!(exp))) { \ - BUG(); \ - } \ - } while (0) +#define ASSERT(exp) BUG_ON(!(exp)) #define TSF_TO_TU(_h,_l) \ ((((u32)(_h)) << 22) | (((u32)(_l)) >> 10)) @@ -70,7 +65,6 @@ struct ath_config { u32 ath_aggr_prot; u16 txpowlimit; u8 cabqReadytime; - u8 swBeaconProcess; }; /*************************/ @@ -78,13 +72,17 @@ struct ath_config { /*************************/ #define ATH_TXBUF_RESET(_bf) do { \ - (_bf)->bf_status = 0; \ + (_bf)->bf_stale = false; \ (_bf)->bf_lastbf = NULL; \ (_bf)->bf_next = NULL; \ memset(&((_bf)->bf_state), 0, \ sizeof(struct ath_buf_state)); \ } while (0) +#define ATH_RXBUF_RESET(_bf) do { \ + (_bf)->bf_stale = false; \ + } while (0) + /** * enum buffer_type - Buffer type flags * @@ -110,7 +108,7 @@ struct ath_buf_state { int bfs_seqno; int bfs_tidno; int bfs_retries; - u32 bf_type; + u8 bf_type; u32 bfs_keyix; enum ath9k_key_type bfs_keytype; }; @@ -134,26 +132,21 @@ struct ath_buf { struct ath_buf *bf_lastbf; /* last buf of this unit (a frame or an aggregate) */ struct ath_buf *bf_next; /* next subframe in the aggregate */ - void *bf_mpdu; /* enclosing frame structure */ + struct sk_buff *bf_mpdu; /* enclosing frame structure */ struct ath_desc *bf_desc; /* virtual addr of desc */ dma_addr_t bf_daddr; /* physical addr of desc */ dma_addr_t bf_buf_addr; /* physical addr of data buffer */ - u32 bf_status; + bool bf_stale; u16 bf_flags; struct ath_buf_state bf_state; dma_addr_t bf_dmacontext; }; -#define ATH_RXBUF_RESET(_bf) ((_bf)->bf_status = 0) -#define ATH_BUFSTATUS_STALE 0x00000002 - struct ath_descdma { - const char *dd_name; struct ath_desc *dd_desc; dma_addr_t dd_desc_paddr; u32 dd_desc_len; struct ath_buf *dd_bufptr; - dma_addr_t dd_dmacontext; }; int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, @@ -299,26 +292,6 @@ struct ath_tx_control { #define ATH_TX_XRETRY 0x02 #define ATH_TX_BAR 0x04 -/* All RSSI values are noise floor adjusted */ -struct ath_tx_stat { - int rssi; - int rssictl[ATH_MAX_ANTENNA]; - int rssiextn[ATH_MAX_ANTENNA]; - int rateieee; - int rateKbps; - int ratecode; - int flags; - u32 airtime; /* time on air per final tx rate */ -}; - -struct aggr_rifs_param { - int param_max_frames; - int param_max_len; - int param_rl; - int param_al; - struct ath_rc_series *param_rcs; -}; - struct ath_node { struct ath_softc *an_sc; struct ath_atx_tid tid[WME_NUM_TID]; @@ -366,7 +339,7 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an); void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an); void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq); int ath_tx_init(struct ath_softc *sc, int nbufs); -int ath_tx_cleanup(struct ath_softc *sc); +void ath_tx_cleanup(struct ath_softc *sc); struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb); int ath_txq_update(struct ath_softc *sc, int qnum, struct ath9k_tx_queue_info *q); @@ -486,15 +459,6 @@ struct ath_led { bool registered; }; -/* Rfkill */ -#define ATH_RFKILL_POLL_INTERVAL 2000 /* msecs */ - -struct ath_rfkill { - struct rfkill *rfkill; - struct delayed_work rfkill_poll; - char rfkill_name[32]; -}; - /********************/ /* Main driver core */ /********************/ @@ -529,19 +493,19 @@ struct ath_rfkill { #define SC_OP_BEACONS BIT(1) #define SC_OP_RXAGGR BIT(2) #define SC_OP_TXAGGR BIT(3) -#define SC_OP_CHAINMASK_UPDATE BIT(4) -#define SC_OP_FULL_RESET BIT(5) -#define SC_OP_PREAMBLE_SHORT BIT(6) -#define SC_OP_PROTECT_ENABLE BIT(7) -#define SC_OP_RXFLUSH BIT(8) -#define SC_OP_LED_ASSOCIATED BIT(9) -#define SC_OP_RFKILL_REGISTERED BIT(10) -#define SC_OP_RFKILL_SW_BLOCKED BIT(11) -#define SC_OP_RFKILL_HW_BLOCKED BIT(12) -#define SC_OP_WAIT_FOR_BEACON BIT(13) -#define SC_OP_LED_ON BIT(14) -#define SC_OP_SCANNING BIT(15) -#define SC_OP_TSF_RESET BIT(16) +#define SC_OP_FULL_RESET BIT(4) +#define SC_OP_PREAMBLE_SHORT BIT(5) +#define SC_OP_PROTECT_ENABLE BIT(6) +#define SC_OP_RXFLUSH BIT(7) +#define SC_OP_LED_ASSOCIATED BIT(8) +#define SC_OP_WAIT_FOR_BEACON BIT(12) +#define SC_OP_LED_ON BIT(13) +#define SC_OP_SCANNING BIT(14) +#define SC_OP_TSF_RESET BIT(15) +#define SC_OP_WAIT_FOR_CAB BIT(16) +#define SC_OP_WAIT_FOR_PSPOLL_DATA BIT(17) +#define SC_OP_WAIT_FOR_TX_ACK BIT(18) +#define SC_OP_BEACON_SYNC BIT(19) struct ath_bus_ops { void (*read_cachesize)(struct ath_softc *sc, int *csz); @@ -603,8 +567,8 @@ struct ath_softc { struct ath_tx tx; struct ath_beacon beacon; struct ieee80211_rate rates[IEEE80211_NUM_BANDS][ATH_RATE_MAX]; - struct ath_rate_table *hw_rate_table[ATH9K_MODE_MAX]; - struct ath_rate_table *cur_rate_table; + const struct ath_rate_table *hw_rate_table[ATH9K_MODE_MAX]; + const struct ath_rate_table *cur_rate_table; struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; struct ath_led radio_led; @@ -617,13 +581,15 @@ struct ath_softc { int led_on_cnt; int led_off_cnt; - struct ath_rfkill rf_kill; + int beacon_interval; + struct ath_ani ani; struct ath9k_node_stats nodestats; #ifdef CONFIG_ATH9K_DEBUG struct ath9k_debug debug; #endif struct ath_bus_ops *bus_ops; + struct ath_beacon_config cur_beacon_conf; }; struct ath_wiphy { @@ -701,7 +667,10 @@ static inline void ath9k_ps_restore(struct ath_softc *sc) { if (atomic_dec_and_test(&sc->ps_usecount)) if ((sc->hw->conf.flags & IEEE80211_CONF_PS) && - !(sc->sc_flags & SC_OP_WAIT_FOR_BEACON)) + !(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON | + SC_OP_WAIT_FOR_CAB | + SC_OP_WAIT_FOR_PSPOLL_DATA | + SC_OP_WAIT_FOR_TX_ACK))) ath9k_hw_setpower(sc->sc_ah, sc->sc_ah->restore_mode); } @@ -722,36 +691,7 @@ void ath9k_wiphy_pause_all_forced(struct ath_softc *sc, bool ath9k_wiphy_scanning(struct ath_softc *sc); void ath9k_wiphy_work(struct work_struct *work); -/* - * Read and write, they both share the same lock. We do this to serialize - * reads and writes on Atheros 802.11n PCI devices only. This is required - * as the FIFO on these devices can only accept sanely 2 requests. After - * that the device goes bananas. Serializing the reads/writes prevents this - * from happening. - */ - -static inline void ath9k_iowrite32(struct ath_hw *ah, u32 reg_offset, u32 val) -{ - if (ah->config.serialize_regmode == SER_REG_MODE_ON) { - unsigned long flags; - spin_lock_irqsave(&ah->ah_sc->sc_serial_rw, flags); - iowrite32(val, ah->ah_sc->mem + reg_offset); - spin_unlock_irqrestore(&ah->ah_sc->sc_serial_rw, flags); - } else - iowrite32(val, ah->ah_sc->mem + reg_offset); -} - -static inline unsigned int ath9k_ioread32(struct ath_hw *ah, u32 reg_offset) -{ - u32 val; - if (ah->config.serialize_regmode == SER_REG_MODE_ON) { - unsigned long flags; - spin_lock_irqsave(&ah->ah_sc->sc_serial_rw, flags); - val = ioread32(ah->ah_sc->mem + reg_offset); - spin_unlock_irqrestore(&ah->ah_sc->sc_serial_rw, flags); - } else - val = ioread32(ah->ah_sc->mem + reg_offset); - return val; -} +void ath9k_iowrite32(struct ath_hw *ah, u32 reg_offset, u32 val); +unsigned int ath9k_ioread32(struct ath_hw *ah, u32 reg_offset); #endif /* ATH9K_H */ diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c similarity index 90% rename from drivers/net/wireless/ath9k/beacon.c rename to drivers/net/wireless/ath/ath9k/beacon.c index ec995730632d..3639a2e6987d 100644 --- a/drivers/net/wireless/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -43,7 +43,7 @@ static int ath_beaconq_config(struct ath_softc *sc) if (!ath9k_hw_set_txq_props(ah, sc->beacon.beaconq, &qi)) { DPRINTF(sc, ATH_DBG_FATAL, - "unable to update h/w beacon queue parameters\n"); + "Unable to update h/w beacon queue parameters\n"); return 0; } else { ath9k_hw_resettxqueue(ah, sc->beacon.beaconq); @@ -59,11 +59,11 @@ static int ath_beaconq_config(struct ath_softc *sc) static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp, struct ath_buf *bf) { - struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu; + struct sk_buff *skb = bf->bf_mpdu; struct ath_hw *ah = sc->sc_ah; struct ath_desc *ds; struct ath9k_11n_rate_series series[4]; - struct ath_rate_table *rt; + const struct ath_rate_table *rt; int flags, antenna, ctsrate = 0, ctsduration = 0; u8 rate; @@ -132,16 +132,13 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw, avp = (void *)vif->drv_priv; cabq = sc->beacon.cabq; - if (avp->av_bcbuf == NULL) { - DPRINTF(sc, ATH_DBG_BEACON, "avp=%p av_bcbuf=%p\n", - avp, avp->av_bcbuf); + if (avp->av_bcbuf == NULL) return NULL; - } /* Release the old beacon first */ bf = avp->av_bcbuf; - skb = (struct sk_buff *)bf->bf_mpdu; + skb = bf->bf_mpdu; if (skb) { dma_unmap_single(sc->dev, bf->bf_dmacontext, skb->len, DMA_TO_DEVICE); @@ -229,7 +226,7 @@ static void ath_beacon_start_adhoc(struct ath_softc *sc, return; bf = avp->av_bcbuf; - skb = (struct sk_buff *) bf->bf_mpdu; + skb = bf->bf_mpdu; ath_beacon_setup(sc, avp, bf); @@ -302,7 +299,7 @@ int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif) /* release the previous beacon frame, if it already exists. */ bf = avp->av_bcbuf; if (bf->bf_mpdu != NULL) { - skb = (struct sk_buff *)bf->bf_mpdu; + skb = bf->bf_mpdu; dma_unmap_single(sc->dev, bf->bf_dmacontext, skb->len, DMA_TO_DEVICE); dev_kfree_skb_any(skb); @@ -323,8 +320,7 @@ int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif) u64 tsfadjust; int intval; - intval = sc->hw->conf.beacon_int ? - sc->hw->conf.beacon_int : ATH_DEFAULT_BINTVAL; + intval = sc->beacon_interval ? : ATH_DEFAULT_BINTVAL; /* * Calculate the TSF offset for this beacon slot, i.e., the @@ -374,7 +370,7 @@ void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp) bf = avp->av_bcbuf; if (bf->bf_mpdu != NULL) { - struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu; + struct sk_buff *skb = bf->bf_mpdu; dma_unmap_single(sc->dev, bf->bf_dmacontext, skb->len, DMA_TO_DEVICE); dev_kfree_skb_any(skb); @@ -415,6 +411,7 @@ void ath_beacon_tasklet(unsigned long data) } else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) { DPRINTF(sc, ATH_DBG_BEACON, "beacon is officially stuck\n"); + sc->sc_flags |= SC_OP_TSF_RESET; ath_reset(sc, false); } @@ -434,8 +431,7 @@ void ath_beacon_tasklet(unsigned long data) * on the tsf to safeguard against missing an swba. */ - intval = sc->hw->conf.beacon_int ? - sc->hw->conf.beacon_int : ATH_DEFAULT_BINTVAL; + intval = sc->beacon_interval ? : ATH_DEFAULT_BINTVAL; tsf = ath9k_hw_gettsf64(ah); tsftu = TSF_TO_TU(tsf>>32, tsf); @@ -512,8 +508,7 @@ void ath_beacon_tasklet(unsigned long data) * slot. Slots that are not occupied will generate nothing. */ static void ath_beacon_config_ap(struct ath_softc *sc, - struct ath_beacon_config *conf, - struct ath_vif *avp) + struct ath_beacon_config *conf) { u32 nexttbtt, intval; @@ -558,14 +553,14 @@ static void ath_beacon_config_ap(struct ath_softc *sc, * we've associated with. */ static void ath_beacon_config_sta(struct ath_softc *sc, - struct ath_beacon_config *conf, - struct ath_vif *avp) + struct ath_beacon_config *conf) { struct ath9k_beacon_state bs; int dtimperiod, dtimcount, sleepduration; int cfpperiod, cfpcount; u32 nexttbtt = 0, intval, tsftu; u64 tsf; + int num_beacons, offset, dtim_dec_count, cfp_dec_count; memset(&bs, 0, sizeof(bs)); intval = conf->beacon_interval & ATH9K_BEACON_PERIOD; @@ -593,14 +588,27 @@ static void ath_beacon_config_sta(struct ath_softc *sc, */ tsf = ath9k_hw_gettsf64(sc->sc_ah); tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE; - do { + + num_beacons = tsftu / intval + 1; + offset = tsftu % intval; + nexttbtt = tsftu - offset; + if (offset) nexttbtt += intval; - if (--dtimcount < 0) { - dtimcount = dtimperiod - 1; - if (--cfpcount < 0) - cfpcount = cfpperiod - 1; - } - } while (nexttbtt < tsftu); + + /* DTIM Beacon every dtimperiod Beacon */ + dtim_dec_count = num_beacons % dtimperiod; + /* CFP every cfpperiod DTIM Beacon */ + cfp_dec_count = (num_beacons / dtimperiod) % cfpperiod; + if (dtim_dec_count) + cfp_dec_count++; + + dtimcount -= dtim_dec_count; + if (dtimcount < 0) + dtimcount += dtimperiod; + + cfpcount -= cfp_dec_count; + if (cfpcount < 0) + cfpcount += cfpperiod; bs.bs_intval = intval; bs.bs_nexttbtt = nexttbtt; @@ -659,7 +667,6 @@ static void ath_beacon_config_sta(struct ath_softc *sc, static void ath_beacon_config_adhoc(struct ath_softc *sc, struct ath_beacon_config *conf, - struct ath_vif *avp, struct ieee80211_vif *vif) { u64 tsf; @@ -667,6 +674,14 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc, intval = conf->beacon_interval & ATH9K_BEACON_PERIOD; + /* + * It looks like mac80211 may end up using beacon interval of zero in + * some cases (at least for mesh point). Avoid getting into an + * infinite loop by using a bit safer value instead.. + */ + if (intval == 0) + intval = 100; + /* Pull nexttbtt forward to reflect the current TSF */ nexttbtt = TSF_TO_TU(sc->beacon.bc_tstamp >> 32, sc->beacon.bc_tstamp); @@ -703,44 +718,50 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc, sc->beacon.bmisscnt = 0; ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_VEOL) + /* FIXME: Handle properly when vif is NULL */ + if (vif && sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_VEOL) ath_beacon_start_adhoc(sc, vif); } void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) { - struct ath_beacon_config conf; + struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; + enum nl80211_iftype iftype; /* Setup the beacon configuration parameters */ - memset(&conf, 0, sizeof(struct ath_beacon_config)); - conf.beacon_interval = sc->hw->conf.beacon_int ? - sc->hw->conf.beacon_int : ATH_DEFAULT_BINTVAL; - conf.listen_interval = 1; - conf.dtim_period = conf.beacon_interval; - conf.dtim_count = 1; - conf.bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf.beacon_interval; - if (vif) { - struct ath_vif *avp = (struct ath_vif *)vif->drv_priv; + struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; - switch(avp->av_opmode) { - case NL80211_IFTYPE_AP: - ath_beacon_config_ap(sc, &conf, avp); - break; - case NL80211_IFTYPE_ADHOC: - case NL80211_IFTYPE_MESH_POINT: - ath_beacon_config_adhoc(sc, &conf, avp, vif); - break; - case NL80211_IFTYPE_STATION: - ath_beacon_config_sta(sc, &conf, avp); - break; - default: - DPRINTF(sc, ATH_DBG_CONFIG, - "Unsupported beaconing mode\n"); - return; - } + iftype = vif->type; - sc->sc_flags |= SC_OP_BEACONS; + cur_conf->beacon_interval = bss_conf->beacon_int; + cur_conf->dtim_period = bss_conf->dtim_period; + cur_conf->listen_interval = 1; + cur_conf->dtim_count = 1; + cur_conf->bmiss_timeout = + ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval; + } else { + iftype = sc->sc_ah->opmode; } + + + switch (iftype) { + case NL80211_IFTYPE_AP: + ath_beacon_config_ap(sc, cur_conf); + break; + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_MESH_POINT: + ath_beacon_config_adhoc(sc, cur_conf, vif); + break; + case NL80211_IFTYPE_STATION: + ath_beacon_config_sta(sc, cur_conf); + break; + default: + DPRINTF(sc, ATH_DBG_CONFIG, + "Unsupported beaconing mode\n"); + return; + } + + sc->sc_flags |= SC_OP_BEACONS; } diff --git a/drivers/net/wireless/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c similarity index 90% rename from drivers/net/wireless/ath9k/calib.c rename to drivers/net/wireless/ath/ath9k/calib.c index e2d62e97131c..a32d7e7fecbe 100644 --- a/drivers/net/wireless/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -186,7 +186,7 @@ static bool getNoiseFloorThresh(struct ath_hw *ah, } static void ath9k_hw_setup_calibration(struct ath_hw *ah, - struct hal_cal_list *currCal) + struct ath9k_cal_list *currCal) { REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(0), AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX, @@ -220,7 +220,7 @@ static void ath9k_hw_setup_calibration(struct ath_hw *ah, } static void ath9k_hw_reset_calibration(struct ath_hw *ah, - struct hal_cal_list *currCal) + struct ath9k_cal_list *currCal) { int i; @@ -238,13 +238,12 @@ static void ath9k_hw_reset_calibration(struct ath_hw *ah, ah->cal_samples = 0; } -static void ath9k_hw_per_calibration(struct ath_hw *ah, +static bool ath9k_hw_per_calibration(struct ath_hw *ah, struct ath9k_channel *ichan, u8 rxchainmask, - struct hal_cal_list *currCal, - bool *isCalDone) + struct ath9k_cal_list *currCal) { - *isCalDone = false; + bool iscaldone = false; if (currCal->calState == CAL_RUNNING) { if (!(REG_READ(ah, AR_PHY_TIMING_CTRL4(0)) & @@ -263,7 +262,7 @@ static void ath9k_hw_per_calibration(struct ath_hw *ah, currCal->calData->calPostProc(ah, numChains); ichan->CalValid |= currCal->calData->calType; currCal->calState = CAL_DONE; - *isCalDone = true; + iscaldone = true; } else { ath9k_hw_setup_calibration(ah, currCal); } @@ -271,11 +270,13 @@ static void ath9k_hw_per_calibration(struct ath_hw *ah, } else if (!(ichan->CalValid & currCal->calData->calType)) { ath9k_hw_reset_calibration(ah, currCal); } + + return iscaldone; } /* Assumes you are talking about the currently configured channel */ static bool ath9k_hw_iscal_supported(struct ath_hw *ah, - enum hal_cal_types calType) + enum ath9k_cal_types calType) { struct ieee80211_conf *conf = &ah->ah_sc->hw->conf; @@ -284,8 +285,8 @@ static bool ath9k_hw_iscal_supported(struct ath_hw *ah, return true; case ADC_GAIN_CAL: case ADC_DC_CAL: - if (conf->channel->band == IEEE80211_BAND_5GHZ && - conf_is_ht20(conf)) + if (!(conf->channel->band == IEEE80211_BAND_2GHZ && + conf_is_ht20(conf))) return true; break; } @@ -498,7 +499,7 @@ static void ath9k_hw_adc_dccal_calibrate(struct ath_hw *ah, u8 numChains) { u32 iOddMeasOffset, iEvenMeasOffset, val, i; int32_t qOddMeasOffset, qEvenMeasOffset, qDcMismatch, iDcMismatch; - const struct hal_percal_data *calData = + const struct ath9k_percal_data *calData = ah->cal_list_curr->calData; u32 numSamples = (1 << (calData->calCountMax + 5)) * calData->calNumSamples; @@ -555,7 +556,7 @@ static void ath9k_hw_adc_dccal_calibrate(struct ath_hw *ah, u8 numChains) bool ath9k_hw_reset_calvalid(struct ath_hw *ah) { struct ieee80211_conf *conf = &ah->ah_sc->hw->conf; - struct hal_cal_list *currCal = ah->cal_list_curr; + struct ath9k_cal_list *currCal = ah->cal_list_curr; if (!ah->curchan) return true; @@ -841,30 +842,28 @@ static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah) } bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan, - u8 rxchainmask, bool longcal, - bool *isCalDone) + u8 rxchainmask, bool longcal) { - struct hal_cal_list *currCal = ah->cal_list_curr; - - *isCalDone = true; + bool iscaldone = true; + struct ath9k_cal_list *currCal = ah->cal_list_curr; if (currCal && (currCal->calState == CAL_RUNNING || currCal->calState == CAL_WAITING)) { - ath9k_hw_per_calibration(ah, chan, rxchainmask, currCal, - isCalDone); - if (*isCalDone) { + iscaldone = ath9k_hw_per_calibration(ah, chan, + rxchainmask, currCal); + if (iscaldone) { ah->cal_list_curr = currCal = currCal->calNext; if (currCal->calState == CAL_WAITING) { - *isCalDone = false; + iscaldone = false; ath9k_hw_reset_calibration(ah, currCal); } } } if (longcal) { - if (AR_SREV_9285(ah) && AR_SREV_9285_11_OR_LATER(ah)) + if (AR_SREV_9285_11_OR_LATER(ah)) ath9k_hw_9285_pa_cal(ah); if (OLC_FOR_AR9280_20_LATER) @@ -872,18 +871,15 @@ bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan, ath9k_hw_getnf(ah, chan); ath9k_hw_loadnf(ah, ah->curchan); ath9k_hw_start_nfcal(ah); - - if (chan->channelFlags & CHANNEL_CW_INT) - chan->channelFlags &= ~CHANNEL_CW_INT; } - return true; + return iscaldone; } static bool ar9285_clc(struct ath_hw *ah, struct ath9k_channel *chan) { REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); - if (chan->channelFlags & CHANNEL_HT20) { + if (IS_CHAN_HT20(chan)) { REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE); REG_SET_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN); REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, @@ -919,83 +915,66 @@ static bool ar9285_clc(struct ath_hw *ah, struct ath9k_channel *chan) return true; } -bool ath9k_hw_init_cal(struct ath_hw *ah, - struct ath9k_channel *chan) +bool ath9k_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) { - if (AR_SREV_9285(ah) && AR_SREV_9285_12_OR_LATER(ah)) { + if (AR_SREV_9285_12_OR_LATER(ah)) { if (!ar9285_clc(ah, chan)) return false; - } else if (AR_SREV_9280_10_OR_LATER(ah)) { - REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); - REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); - REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); + } else { + if (AR_SREV_9280_10_OR_LATER(ah)) { + REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); + REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); + } - /* Kick off the cal */ + /* Calibrate the AGC */ REG_WRITE(ah, AR_PHY_AGC_CONTROL, - REG_READ(ah, AR_PHY_AGC_CONTROL) | - AR_PHY_AGC_CONTROL_CAL); + REG_READ(ah, AR_PHY_AGC_CONTROL) | + AR_PHY_AGC_CONTROL_CAL); - if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, - AR_PHY_AGC_CONTROL_CAL, 0, - AH_WAIT_TIMEOUT)) { + /* Poll for offset calibration complete */ + if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, + 0, AH_WAIT_TIMEOUT)) { DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "offset calibration failed to complete in 1ms; " "noisy environment?\n"); return false; } - REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); - REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); - REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); - } - - /* Calibrate the AGC */ - REG_WRITE(ah, AR_PHY_AGC_CONTROL, - REG_READ(ah, AR_PHY_AGC_CONTROL) | - AR_PHY_AGC_CONTROL_CAL); - - if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, - 0, AH_WAIT_TIMEOUT)) { - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "offset calibration failed to complete in 1ms; " - "noisy environment?\n"); - return false; - } - - if (AR_SREV_9280_10_OR_LATER(ah)) { - REG_SET_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); - REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); + if (AR_SREV_9280_10_OR_LATER(ah)) { + REG_SET_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); + REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); + } } /* Do PA Calibration */ - if (AR_SREV_9285(ah) && AR_SREV_9285_11_OR_LATER(ah)) + if (AR_SREV_9285_11_OR_LATER(ah)) ath9k_hw_9285_pa_cal(ah); - /* Do NF Calibration */ + /* Do NF Calibration after DC offset and other calibrations */ REG_WRITE(ah, AR_PHY_AGC_CONTROL, - REG_READ(ah, AR_PHY_AGC_CONTROL) | - AR_PHY_AGC_CONTROL_NF); + REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_NF); ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL; + /* Enable IQ, ADC Gain and ADC DC offset CALs */ if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) { if (ath9k_hw_iscal_supported(ah, ADC_GAIN_CAL)) { INIT_CAL(&ah->adcgain_caldata); INSERT_CAL(ah, &ah->adcgain_caldata); DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "enabling ADC Gain Calibration.\n"); + "enabling ADC Gain Calibration.\n"); } if (ath9k_hw_iscal_supported(ah, ADC_DC_CAL)) { INIT_CAL(&ah->adcdc_caldata); INSERT_CAL(ah, &ah->adcdc_caldata); DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "enabling ADC DC Calibration.\n"); + "enabling ADC DC Calibration.\n"); } if (ath9k_hw_iscal_supported(ah, IQ_MISMATCH_CAL)) { INIT_CAL(&ah->iq_caldata); INSERT_CAL(ah, &ah->iq_caldata); DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "enabling IQ Calibration.\n"); + "enabling IQ Calibration.\n"); } ah->cal_list_curr = ah->cal_list; @@ -1009,49 +988,49 @@ bool ath9k_hw_init_cal(struct ath_hw *ah, return true; } -const struct hal_percal_data iq_cal_multi_sample = { +const struct ath9k_percal_data iq_cal_multi_sample = { IQ_MISMATCH_CAL, MAX_CAL_SAMPLES, PER_MIN_LOG_COUNT, ath9k_hw_iqcal_collect, ath9k_hw_iqcalibrate }; -const struct hal_percal_data iq_cal_single_sample = { +const struct ath9k_percal_data iq_cal_single_sample = { IQ_MISMATCH_CAL, MIN_CAL_SAMPLES, PER_MAX_LOG_COUNT, ath9k_hw_iqcal_collect, ath9k_hw_iqcalibrate }; -const struct hal_percal_data adc_gain_cal_multi_sample = { +const struct ath9k_percal_data adc_gain_cal_multi_sample = { ADC_GAIN_CAL, MAX_CAL_SAMPLES, PER_MIN_LOG_COUNT, ath9k_hw_adc_gaincal_collect, ath9k_hw_adc_gaincal_calibrate }; -const struct hal_percal_data adc_gain_cal_single_sample = { +const struct ath9k_percal_data adc_gain_cal_single_sample = { ADC_GAIN_CAL, MIN_CAL_SAMPLES, PER_MAX_LOG_COUNT, ath9k_hw_adc_gaincal_collect, ath9k_hw_adc_gaincal_calibrate }; -const struct hal_percal_data adc_dc_cal_multi_sample = { +const struct ath9k_percal_data adc_dc_cal_multi_sample = { ADC_DC_CAL, MAX_CAL_SAMPLES, PER_MIN_LOG_COUNT, ath9k_hw_adc_dccal_collect, ath9k_hw_adc_dccal_calibrate }; -const struct hal_percal_data adc_dc_cal_single_sample = { +const struct ath9k_percal_data adc_dc_cal_single_sample = { ADC_DC_CAL, MIN_CAL_SAMPLES, PER_MAX_LOG_COUNT, ath9k_hw_adc_dccal_collect, ath9k_hw_adc_dccal_calibrate }; -const struct hal_percal_data adc_init_dc_cal = { +const struct ath9k_percal_data adc_init_dc_cal = { ADC_DC_INIT_CAL, MIN_CAL_SAMPLES, INIT_LOG_COUNT, diff --git a/drivers/net/wireless/ath9k/calib.h b/drivers/net/wireless/ath/ath9k/calib.h similarity index 81% rename from drivers/net/wireless/ath9k/calib.h rename to drivers/net/wireless/ath/ath9k/calib.h index 1c74bd50700d..fe5367f14148 100644 --- a/drivers/net/wireless/ath9k/calib.h +++ b/drivers/net/wireless/ath/ath9k/calib.h @@ -17,13 +17,13 @@ #ifndef CALIB_H #define CALIB_H -extern const struct hal_percal_data iq_cal_multi_sample; -extern const struct hal_percal_data iq_cal_single_sample; -extern const struct hal_percal_data adc_gain_cal_multi_sample; -extern const struct hal_percal_data adc_gain_cal_single_sample; -extern const struct hal_percal_data adc_dc_cal_multi_sample; -extern const struct hal_percal_data adc_dc_cal_single_sample; -extern const struct hal_percal_data adc_init_dc_cal; +extern const struct ath9k_percal_data iq_cal_multi_sample; +extern const struct ath9k_percal_data iq_cal_single_sample; +extern const struct ath9k_percal_data adc_gain_cal_multi_sample; +extern const struct ath9k_percal_data adc_gain_cal_single_sample; +extern const struct ath9k_percal_data adc_dc_cal_multi_sample; +extern const struct ath9k_percal_data adc_dc_cal_single_sample; +extern const struct ath9k_percal_data adc_init_dc_cal; #define AR_PHY_CCA_MAX_GOOD_VALUE -85 #define AR_PHY_CCA_MAX_HIGH_VALUE -62 @@ -67,14 +67,14 @@ struct ar5416IniArray { } \ } while (0) -enum hal_cal_types { +enum ath9k_cal_types { ADC_DC_INIT_CAL = 0x1, ADC_GAIN_CAL = 0x2, ADC_DC_CAL = 0x4, IQ_MISMATCH_CAL = 0x8 }; -enum hal_cal_state { +enum ath9k_cal_state { CAL_INACTIVE, CAL_WAITING, CAL_RUNNING, @@ -87,18 +87,18 @@ enum hal_cal_state { #define PER_MIN_LOG_COUNT 2 #define PER_MAX_LOG_COUNT 10 -struct hal_percal_data { - enum hal_cal_types calType; +struct ath9k_percal_data { + enum ath9k_cal_types calType; u32 calNumSamples; u32 calCountMax; void (*calCollect) (struct ath_hw *); void (*calPostProc) (struct ath_hw *, u8); }; -struct hal_cal_list { - const struct hal_percal_data *calData; - enum hal_cal_state calState; - struct hal_cal_list *calNext; +struct ath9k_cal_list { + const struct ath9k_percal_data *calData; + enum ath9k_cal_state calState; + struct ath9k_cal_list *calNext; }; struct ath9k_nfcal_hist { @@ -116,8 +116,7 @@ int16_t ath9k_hw_getnf(struct ath_hw *ah, void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah); s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan); bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan, - u8 rxchainmask, bool longcal, - bool *isCalDone); + u8 rxchainmask, bool longcal); bool ath9k_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan); diff --git a/drivers/net/wireless/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c similarity index 87% rename from drivers/net/wireless/ath9k/debug.c rename to drivers/net/wireless/ath/ath9k/debug.c index fdf9528fa49b..6d20725d6451 100644 --- a/drivers/net/wireless/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -44,6 +44,44 @@ static int ath9k_debugfs_open(struct inode *inode, struct file *file) return 0; } +static ssize_t read_file_debug(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + char buf[32]; + unsigned int len; + + len = snprintf(buf, sizeof(buf), "0x%08x\n", sc->debug.debug_mask); + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t write_file_debug(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + unsigned long mask; + char buf[32]; + ssize_t len; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EINVAL; + + buf[len] = '\0'; + if (strict_strtoul(buf, 0, &mask)) + return -EINVAL; + + sc->debug.debug_mask = mask; + return count; +} + +static const struct file_operations fops_debug = { + .read = read_file_debug, + .write = write_file_debug, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE +}; + static ssize_t read_file_dma(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -224,111 +262,66 @@ static const struct file_operations fops_interrupt = { .owner = THIS_MODULE }; -static void ath_debug_stat_11n_rc(struct ath_softc *sc, struct sk_buff *skb) -{ - struct ath_tx_info_priv *tx_info_priv = NULL; - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - struct ieee80211_tx_rate *rates = tx_info->status.rates; - int final_ts_idx, idx; - - tx_info_priv = ATH_TX_INFO_PRIV(tx_info); - final_ts_idx = tx_info_priv->tx.ts_rateindex; - idx = sc->cur_rate_table->info[rates[final_ts_idx].idx].dot11rate; - - sc->debug.stats.n_rcstats[idx].success++; -} - -static void ath_debug_stat_legacy_rc(struct ath_softc *sc, struct sk_buff *skb) +void ath_debug_stat_rc(struct ath_softc *sc, struct sk_buff *skb) { struct ath_tx_info_priv *tx_info_priv = NULL; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_rate *rates = tx_info->status.rates; int final_ts_idx, idx; + struct ath_rc_stats *stats; tx_info_priv = ATH_TX_INFO_PRIV(tx_info); final_ts_idx = tx_info_priv->tx.ts_rateindex; idx = rates[final_ts_idx].idx; - - sc->debug.stats.legacy_rcstats[idx].success++; + stats = &sc->debug.stats.rcstats[idx]; + stats->success++; } -void ath_debug_stat_rc(struct ath_softc *sc, struct sk_buff *skb) -{ - if (conf_is_ht(&sc->hw->conf)) - ath_debug_stat_11n_rc(sc, skb); - else - ath_debug_stat_legacy_rc(sc, skb); -} - -/* FIXME: legacy rates, later on .. */ void ath_debug_stat_retries(struct ath_softc *sc, int rix, int xretries, int retries, u8 per) { - if (conf_is_ht(&sc->hw->conf)) { - int idx = sc->cur_rate_table->info[rix].dot11rate; + struct ath_rc_stats *stats = &sc->debug.stats.rcstats[rix]; - sc->debug.stats.n_rcstats[idx].xretries += xretries; - sc->debug.stats.n_rcstats[idx].retries += retries; - sc->debug.stats.n_rcstats[idx].per = per; - } -} - -static ssize_t ath_read_file_stat_11n_rc(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_softc *sc = file->private_data; - char buf[1024]; - unsigned int len = 0; - int i = 0; - - len += sprintf(buf, "%7s %13s %8s %8s %6s\n\n", "Rate", "Success", - "Retries", "XRetries", "PER"); - - for (i = 0; i <= 15; i++) { - len += snprintf(buf + len, sizeof(buf) - len, - "%5s%3d: %8u %8u %8u %8u\n", "MCS", i, - sc->debug.stats.n_rcstats[i].success, - sc->debug.stats.n_rcstats[i].retries, - sc->debug.stats.n_rcstats[i].xretries, - sc->debug.stats.n_rcstats[i].per); - } - - return simple_read_from_buffer(user_buf, count, ppos, buf, len); -} - -static ssize_t ath_read_file_stat_legacy_rc(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_softc *sc = file->private_data; - char buf[512]; - unsigned int len = 0; - int i = 0; - - len += sprintf(buf, "%7s %13s\n\n", "Rate", "Success"); - - for (i = 0; i < sc->cur_rate_table->rate_cnt; i++) { - len += snprintf(buf + len, sizeof(buf) - len, "%5u: %12u\n", - sc->cur_rate_table->info[i].ratekbps / 1000, - sc->debug.stats.legacy_rcstats[i].success); - } - - return simple_read_from_buffer(user_buf, count, ppos, buf, len); + stats->xretries += xretries; + stats->retries += retries; + stats->per = per; } static ssize_t read_file_rcstat(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct ath_softc *sc = file->private_data; + char *buf; + unsigned int len = 0, max; + int i = 0; + ssize_t retval; if (sc->cur_rate_table == NULL) return 0; - if (conf_is_ht(&sc->hw->conf)) - return ath_read_file_stat_11n_rc(file, user_buf, count, ppos); - else - return ath_read_file_stat_legacy_rc(file, user_buf, count ,ppos); + max = 80 + sc->cur_rate_table->rate_cnt * 64; + buf = kmalloc(max + 1, GFP_KERNEL); + if (buf == NULL) + return 0; + buf[max] = 0; + + len += sprintf(buf, "%5s %15s %8s %9s %3s\n\n", "Rate", "Success", + "Retries", "XRetries", "PER"); + + for (i = 0; i < sc->cur_rate_table->rate_cnt; i++) { + u32 ratekbps = sc->cur_rate_table->info[i].ratekbps; + struct ath_rc_stats *stats = &sc->debug.stats.rcstats[i]; + + len += snprintf(buf + len, max - len, + "%3u.%d: %8u %8u %8u %8u\n", ratekbps / 1000, + (ratekbps % 1000) / 100, stats->success, + stats->retries, stats->xretries, + stats->per); + } + + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + return retval; } static const struct file_operations fops_rcstat = { @@ -498,11 +491,19 @@ int ath9k_init_debug(struct ath_softc *sc) { sc->debug.debug_mask = ath9k_debug; + if (!ath9k_debugfs_root) + return -ENOENT; + sc->debug.debugfs_phy = debugfs_create_dir(wiphy_name(sc->hw->wiphy), ath9k_debugfs_root); if (!sc->debug.debugfs_phy) goto err; + sc->debug.debugfs_debug = debugfs_create_file("debug", + S_IRUGO | S_IWUSR, sc->debug.debugfs_phy, sc, &fops_debug); + if (!sc->debug.debugfs_debug) + goto err; + sc->debug.debugfs_dma = debugfs_create_file("dma", S_IRUGO, sc->debug.debugfs_phy, sc, &fops_dma); if (!sc->debug.debugfs_dma) @@ -540,6 +541,7 @@ void ath9k_exit_debug(struct ath_softc *sc) debugfs_remove(sc->debug.debugfs_rcstat); debugfs_remove(sc->debug.debugfs_interrupt); debugfs_remove(sc->debug.debugfs_dma); + debugfs_remove(sc->debug.debugfs_debug); debugfs_remove(sc->debug.debugfs_phy); } diff --git a/drivers/net/wireless/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h similarity index 84% rename from drivers/net/wireless/ath9k/debug.h rename to drivers/net/wireless/ath/ath9k/debug.h index 7b0e5419d2bc..edda15bf2c15 100644 --- a/drivers/net/wireless/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -19,20 +19,17 @@ enum ATH_DEBUG { ATH_DBG_RESET = 0x00000001, - ATH_DBG_REG_IO = 0x00000002, - ATH_DBG_QUEUE = 0x00000004, - ATH_DBG_EEPROM = 0x00000008, - ATH_DBG_CALIBRATE = 0x00000010, - ATH_DBG_CHANNEL = 0x00000020, - ATH_DBG_INTERRUPT = 0x00000040, - ATH_DBG_REGULATORY = 0x00000080, - ATH_DBG_ANI = 0x00000100, - ATH_DBG_POWER_MGMT = 0x00000200, - ATH_DBG_XMIT = 0x00000400, - ATH_DBG_BEACON = 0x00001000, - ATH_DBG_CONFIG = 0x00002000, - ATH_DBG_KEYCACHE = 0x00004000, - ATH_DBG_FATAL = 0x00008000, + ATH_DBG_QUEUE = 0x00000002, + ATH_DBG_EEPROM = 0x00000004, + ATH_DBG_CALIBRATE = 0x00000008, + ATH_DBG_INTERRUPT = 0x00000010, + ATH_DBG_REGULATORY = 0x00000020, + ATH_DBG_ANI = 0x00000040, + ATH_DBG_XMIT = 0x00000080, + ATH_DBG_BEACON = 0x00000100, + ATH_DBG_CONFIG = 0x00000200, + ATH_DBG_FATAL = 0x00000400, + ATH_DBG_PS = 0x00000800, ATH_DBG_ANY = 0xffffffff }; @@ -83,11 +80,7 @@ struct ath_interrupt_stats { u32 dtim; }; -struct ath_legacy_rc_stats { - u32 success; -}; - -struct ath_11n_rc_stats { +struct ath_rc_stats { u32 success; u32 retries; u32 xretries; @@ -96,13 +89,13 @@ struct ath_11n_rc_stats { struct ath_stats { struct ath_interrupt_stats istats; - struct ath_legacy_rc_stats legacy_rcstats[12]; /* max(11a,11b,11g) */ - struct ath_11n_rc_stats n_rcstats[16]; /* 0..15 MCS rates */ + struct ath_rc_stats rcstats[RATE_TABLE_SIZE]; }; struct ath9k_debug { int debug_mask; struct dentry *debugfs_phy; + struct dentry *debugfs_debug; struct dentry *debugfs_dma; struct dentry *debugfs_interrupt; struct dentry *debugfs_rcstat; diff --git a/drivers/net/wireless/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c similarity index 98% rename from drivers/net/wireless/ath9k/eeprom.c rename to drivers/net/wireless/ath/ath9k/eeprom.c index ffc36b0361c7..a2fda702b620 100644 --- a/drivers/net/wireless/ath9k/eeprom.c +++ b/drivers/net/wireless/ath/ath9k/eeprom.c @@ -694,7 +694,7 @@ static void ath9k_hw_get_4k_gain_boundaries_pdadcs(struct ath_hw *ah, #undef TMP_VAL_VPD_TABLE } -static bool ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah, +static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah, struct ath9k_channel *chan, int16_t *pTxPowerIndexOffset) { @@ -783,11 +783,11 @@ static bool ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah, ((pdadcValues[4 * j + 3] & 0xFF) << 24); REG_WRITE(ah, regOffset, reg32); - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "PDADC (%d,%4x): %4.4x %8.8x\n", i, regChainOffset, regOffset, reg32); - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "PDADC: Chain %d | " "PDADC %3d Value %3d | " "PDADC %3d Value %3d | " @@ -805,11 +805,9 @@ static bool ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah, } *pTxPowerIndexOffset = 0; - - return true; } -static bool ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, +static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, struct ath9k_channel *chan, int16_t *ratesArray, u16 cfgCtl, @@ -910,7 +908,7 @@ static bool ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, ah->eep_ops->get_eeprom_rev(ah) <= 2) twiceMaxEdgePower = AR5416_MAX_RATE_POWER; - DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, " "EXT_ADDITIVE %d\n", ctlMode, numCtlModes, isHt40CtlMode, @@ -918,7 +916,7 @@ static bool ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, for (i = 0; (i < AR5416_NUM_CTLS) && pEepData->ctlIndex[i]; i++) { - DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, " LOOP-Ctlidx %d: cfgCtl 0x%2.2x " "pCtlMode 0x%2.2x ctlIndex 0x%2.2x " "chan %d\n", @@ -941,7 +939,7 @@ static bool ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, IS_CHAN_2GHZ(chan), AR5416_EEP4K_NUM_BAND_EDGES); - DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, " MATCH-EE_IDX %d: ch %d is2 %d " "2xMinEdge %d chainmask %d chains %d\n", i, freq, IS_CHAN_2GHZ(chan), @@ -961,7 +959,7 @@ static bool ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower); - DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, " SEL-Min ctlMode %d pCtlMode %d " "2xMaxEdge %d sP %d minCtlPwr %d\n", ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower, @@ -1041,10 +1039,9 @@ static bool ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0]; ratesArray[rateExtCck] = targetPowerCckExt.tPow2x[0]; } - return true; } -static int ath9k_hw_4k_set_txpower(struct ath_hw *ah, +static void ath9k_hw_4k_set_txpower(struct ath_hw *ah, struct ath9k_channel *chan, u16 cfgCtl, u8 twiceAntennaReduction, @@ -1065,22 +1062,13 @@ static int ath9k_hw_4k_set_txpower(struct ath_hw *ah, ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; } - if (!ath9k_hw_set_4k_power_per_rate_table(ah, chan, + ath9k_hw_set_4k_power_per_rate_table(ah, chan, &ratesArray[0], cfgCtl, twiceAntennaReduction, twiceMaxRegulatoryPower, - powerLimit)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "ath9k_hw_set_txpower: unable to set " - "tx power per rate table\n"); - return -EIO; - } + powerLimit); - if (!ath9k_hw_set_4k_power_cal_table(ah, chan, &txPowerIndexOffset)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "ath9k_hw_set_txpower: unable to set power table\n"); - return -EIO; - } + ath9k_hw_set_4k_power_cal_table(ah, chan, &txPowerIndexOffset); for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); @@ -1168,7 +1156,6 @@ static int ath9k_hw_4k_set_txpower(struct ath_hw *ah, else ah->regulatory.max_power_level = ratesArray[i]; - return 0; } static void ath9k_hw_4k_set_addac(struct ath_hw *ah, @@ -2103,7 +2090,7 @@ static void ath9k_hw_get_def_gain_boundaries_pdadcs(struct ath_hw *ah, return; } -static bool ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, +static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, struct ath9k_channel *chan, int16_t *pTxPowerIndexOffset) { @@ -2234,11 +2221,11 @@ static bool ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, ((pdadcValues[4 * j + 3] & 0xFF) << 24); REG_WRITE(ah, regOffset, reg32); - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "PDADC (%d,%4x): %4.4x %8.8x\n", i, regChainOffset, regOffset, reg32); - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "PDADC: Chain %d | PDADC %3d " "Value %3d | PDADC %3d Value %3d | " "PDADC %3d Value %3d | PDADC %3d " @@ -2255,13 +2242,11 @@ static bool ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, } *pTxPowerIndexOffset = 0; - - return true; #undef SM_PD_GAIN #undef SM_PDGAIN_B } -static bool ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah, +static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah, struct ath9k_channel *chan, int16_t *ratesArray, u16 cfgCtl, @@ -2415,14 +2400,14 @@ static bool ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah, ah->eep_ops->get_eeprom_rev(ah) <= 2) twiceMaxEdgePower = AR5416_MAX_RATE_POWER; - DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, " "EXT_ADDITIVE %d\n", ctlMode, numCtlModes, isHt40CtlMode, (pCtlMode[ctlMode] & EXT_ADDITIVE)); for (i = 0; (i < AR5416_NUM_CTLS) && pEepData->ctlIndex[i]; i++) { - DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, " LOOP-Ctlidx %d: cfgCtl 0x%2.2x " "pCtlMode 0x%2.2x ctlIndex 0x%2.2x " "chan %d\n", @@ -2441,7 +2426,7 @@ static bool ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah, rep->ctlEdges[ar5416_get_ntxchains(tx_chainmask) - 1], IS_CHAN_2GHZ(chan), AR5416_NUM_BAND_EDGES); - DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, " MATCH-EE_IDX %d: ch %d is2 %d " "2xMinEdge %d chainmask %d chains %d\n", i, freq, IS_CHAN_2GHZ(chan), @@ -2460,7 +2445,7 @@ static bool ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah, minCtlPower = min(twiceMaxEdgePower, scaledPower); - DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, " SEL-Min ctlMode %d pCtlMode %d " "2xMaxEdge %d sP %d minCtlPwr %d\n", ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower, @@ -2549,10 +2534,9 @@ static bool ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah, targetPowerCckExt.tPow2x[0]; } } - return true; } -static int ath9k_hw_def_set_txpower(struct ath_hw *ah, +static void ath9k_hw_def_set_txpower(struct ath_hw *ah, struct ath9k_channel *chan, u16 cfgCtl, u8 twiceAntennaReduction, @@ -2575,22 +2559,13 @@ static int ath9k_hw_def_set_txpower(struct ath_hw *ah, ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; } - if (!ath9k_hw_set_def_power_per_rate_table(ah, chan, + ath9k_hw_set_def_power_per_rate_table(ah, chan, &ratesArray[0], cfgCtl, twiceAntennaReduction, twiceMaxRegulatoryPower, - powerLimit)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "ath9k_hw_set_txpower: unable to set " - "tx power per rate table\n"); - return -EIO; - } + powerLimit); - if (!ath9k_hw_set_def_power_cal_table(ah, chan, &txPowerIndexOffset)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "ath9k_hw_set_txpower: unable to set power table\n"); - return -EIO; - } + ath9k_hw_set_def_power_cal_table(ah, chan, &txPowerIndexOffset); for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); @@ -2717,8 +2692,6 @@ static int ath9k_hw_def_set_txpower(struct ath_hw *ah, "Invalid chainmask configuration\n"); break; } - - return 0; } static u8 ath9k_hw_def_get_num_ant_config(struct ath_hw *ah, diff --git a/drivers/net/wireless/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h similarity index 99% rename from drivers/net/wireless/ath9k/eeprom.h rename to drivers/net/wireless/ath/ath9k/eeprom.h index 25b68c881ff1..67b8bd12941a 100644 --- a/drivers/net/wireless/ath9k/eeprom.h +++ b/drivers/net/wireless/ath/ath9k/eeprom.h @@ -17,6 +17,8 @@ #ifndef EEPROM_H #define EEPROM_H +#include + #define AH_USE_EEPROM 0x1 #ifdef __BIG_ENDIAN @@ -492,7 +494,7 @@ struct eeprom_ops { struct ath9k_channel *chan); void (*set_board_values)(struct ath_hw *hw, struct ath9k_channel *chan); void (*set_addac)(struct ath_hw *hw, struct ath9k_channel *chan); - int (*set_txpower)(struct ath_hw *hw, struct ath9k_channel *chan, + void (*set_txpower)(struct ath_hw *hw, struct ath9k_channel *chan, u16 cfgCtl, u8 twiceAntennaReduction, u8 twiceMaxRegulatoryPower, u8 powerLimit); u16 (*get_spur_channel)(struct ath_hw *ah, u16 i, bool is2GHz); diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c similarity index 95% rename from drivers/net/wireless/ath9k/hw.c rename to drivers/net/wireless/ath/ath9k/hw.c index b15eaf8417ff..34935a8ee59d 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -84,6 +84,38 @@ static u32 ath9k_hw_mac_to_clks(struct ath_hw *ah, u32 usecs) return ath9k_hw_mac_clks(ah, usecs); } +/* + * Read and write, they both share the same lock. We do this to serialize + * reads and writes on Atheros 802.11n PCI devices only. This is required + * as the FIFO on these devices can only accept sanely 2 requests. After + * that the device goes bananas. Serializing the reads/writes prevents this + * from happening. + */ + +void ath9k_iowrite32(struct ath_hw *ah, u32 reg_offset, u32 val) +{ + if (ah->config.serialize_regmode == SER_REG_MODE_ON) { + unsigned long flags; + spin_lock_irqsave(&ah->ah_sc->sc_serial_rw, flags); + iowrite32(val, ah->ah_sc->mem + reg_offset); + spin_unlock_irqrestore(&ah->ah_sc->sc_serial_rw, flags); + } else + iowrite32(val, ah->ah_sc->mem + reg_offset); +} + +unsigned int ath9k_ioread32(struct ath_hw *ah, u32 reg_offset) +{ + u32 val; + if (ah->config.serialize_regmode == SER_REG_MODE_ON) { + unsigned long flags; + spin_lock_irqsave(&ah->ah_sc->sc_serial_rw, flags); + val = ioread32(ah->ah_sc->mem + reg_offset); + spin_unlock_irqrestore(&ah->ah_sc->sc_serial_rw, flags); + } else + val = ioread32(ah->ah_sc->mem + reg_offset); + return val; +} + bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout) { int i; @@ -97,7 +129,7 @@ bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout) udelay(AH_TIME_QUANTUM); } - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + DPRINTF(ah->ah_sc, ATH_DBG_ANY, "timeout (%d us) on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n", timeout, reg, REG_READ(ah, reg), mask, val); @@ -136,7 +168,7 @@ bool ath9k_get_channel_edges(struct ath_hw *ah, } u16 ath9k_hw_computetxtime(struct ath_hw *ah, - struct ath_rate_table *rates, + const struct ath_rate_table *rates, u32 frameLen, u16 rateix, bool shortPreamble) { @@ -181,7 +213,7 @@ u16 ath9k_hw_computetxtime(struct ath_hw *ah, } break; default: - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Unknown phy %u (rate ix %u)\n", rates->info[rateix].phy, rateix); txTime = 0; @@ -306,7 +338,7 @@ static bool ath9k_hw_chip_test(struct ath_hw *ah) REG_WRITE(ah, addr, wrData); rdData = REG_READ(ah, addr); if (rdData != wrData) { - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "address test failed " "addr: 0x%08x - wr:0x%08x != rd:0x%08x\n", addr, wrData, rdData); @@ -318,7 +350,7 @@ static bool ath9k_hw_chip_test(struct ath_hw *ah) REG_WRITE(ah, addr, wrData); rdData = REG_READ(ah, addr); if (wrData != rdData) { - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "address test failed " "addr: 0x%08x - wr:0x%08x != rd:0x%08x\n", addr, wrData, rdData); @@ -363,10 +395,7 @@ static void ath9k_hw_set_defaults(struct ath_hw *ah) ah->config.ack_6mb = 0x0; ah->config.cwm_ignore_extcca = 0; ah->config.pcie_powersave_enable = 0; - ah->config.pcie_l1skp_enable = 0; ah->config.pcie_clock_req = 0; - ah->config.pcie_power_reset = 0x100; - ah->config.pcie_restore = 0; ah->config.pcie_waen = 0; ah->config.analog_shiftreg = 1; ah->config.ht_enable = 1; @@ -375,13 +404,6 @@ static void ath9k_hw_set_defaults(struct ath_hw *ah) ah->config.cck_trig_high = 200; ah->config.cck_trig_low = 100; ah->config.enable_ani = 1; - ah->config.noise_immunity_level = 4; - ah->config.ofdm_weaksignal_det = 1; - ah->config.cck_weaksignal_thr = 0; - ah->config.spur_immunity_level = 2; - ah->config.firstep_level = 0; - ah->config.rssi_thr_high = 40; - ah->config.rssi_thr_low = 7; ah->config.diversity_control = 0; ah->config.antenna_switch_swap = 0; @@ -390,7 +412,7 @@ static void ath9k_hw_set_defaults(struct ath_hw *ah) ah->config.spurchans[i][1] = AR_NO_SPUR; } - ah->config.intr_mitigation = 1; + ah->config.intr_mitigation = true; /* * We need this for PCI devices only (Cardbus, PCI, miniPCI) @@ -463,8 +485,8 @@ static int ath9k_hw_rfattach(struct ath_hw *ah) rfStatus = ath9k_hw_init_rf(ah, &ecode); if (!rfStatus) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, - "RF setup failed, status %u\n", ecode); + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "RF setup failed, status: %u\n", ecode); return ecode; } @@ -488,10 +510,9 @@ static int ath9k_hw_rf_claim(struct ath_hw *ah) case AR_RAD2122_SREV_MAJOR: break; default: - DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "5G Radio Chip Rev 0x%02X is not " - "supported by this driver\n", - ah->hw_version.analog5GhzRev); + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Radio Chip Rev 0x%02X not supported\n", + val & AR_RADIO_SREV_MAJOR); return -EOPNOTSUPP; } @@ -513,12 +534,8 @@ static int ath9k_hw_init_macaddr(struct ath_hw *ah) ah->macaddr[2 * i] = eeval >> 8; ah->macaddr[2 * i + 1] = eeval & 0xff; } - if (sum == 0 || sum == 0xffff * 3) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "mac address read failed: %pM\n", - ah->macaddr); + if (sum == 0 || sum == 0xffff * 3) return -EADDRNOTAVAIL; - } return 0; } @@ -575,11 +592,8 @@ static int ath9k_hw_post_attach(struct ath_hw *ah) { int ecode; - if (!ath9k_hw_chip_test(ah)) { - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "hardware self-test failed\n"); + if (!ath9k_hw_chip_test(ah)) return -ENODEV; - } ecode = ath9k_hw_rf_claim(ah); if (ecode != 0) @@ -617,17 +631,14 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, ath9k_hw_set_defaults(ah); - if (ah->config.intr_mitigation != 0) - ah->intr_mitigation = true; - if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) { - DPRINTF(sc, ATH_DBG_RESET, "Couldn't reset chip\n"); + DPRINTF(sc, ATH_DBG_FATAL, "Couldn't reset chip\n"); ecode = -EIO; goto bad; } if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) { - DPRINTF(sc, ATH_DBG_RESET, "Couldn't wakeup chip\n"); + DPRINTF(sc, ATH_DBG_FATAL, "Couldn't wakeup chip\n"); ecode = -EIO; goto bad; } @@ -650,7 +661,7 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, (ah->hw_version.macVersion != AR_SREV_VERSION_5416_PCIE) && (ah->hw_version.macVersion != AR_SREV_VERSION_9160) && (!AR_SREV_9100(ah)) && (!AR_SREV_9280(ah)) && (!AR_SREV_9285(ah))) { - DPRINTF(sc, ATH_DBG_RESET, + DPRINTF(sc, ATH_DBG_FATAL, "Mac Chip Rev 0x%02x.%x is not supported by " "this driver\n", ah->hw_version.macVersion, ah->hw_version.macRev); @@ -690,10 +701,6 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, if (AR_SREV_9280_10_OR_LATER(ah)) ah->ani_function &= ~ATH9K_ANI_NOISE_IMMUNITY_LEVEL; - DPRINTF(sc, ATH_DBG_RESET, - "This Mac Chip Rev 0x%02x.%x is \n", - ah->hw_version.macVersion, ah->hw_version.macRev); - if (AR_SREV_9285_12_OR_LATER(ah)) { INIT_INI_ARRAY(&ah->iniModes, ar9285Modes_9285_1_2, @@ -859,11 +866,7 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, if (AR_SREV_9280_20(ah)) ath9k_hw_init_txgain_ini(ah); - if (!ath9k_hw_fill_cap_info(ah)) { - DPRINTF(sc, ATH_DBG_RESET, "failed ath9k_hw_fill_cap_info\n"); - ecode = -EINVAL; - goto bad; - } + ath9k_hw_fill_cap_info(ah); if ((ah->hw_version.devid == AR9280_DEVID_PCI) && test_bit(ATH9K_MODE_11A, ah->caps.wireless_modes)) { @@ -885,8 +888,8 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, ecode = ath9k_hw_init_macaddr(ah); if (ecode != 0) { - DPRINTF(sc, ATH_DBG_RESET, - "failed initializing mac address\n"); + DPRINTF(sc, ATH_DBG_FATAL, + "Failed to initialize MAC address\n"); goto bad; } @@ -1054,7 +1057,7 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah, AR_IMR_RXORN | AR_IMR_BCNMISC; - if (ah->intr_mitigation) + if (ah->config.intr_mitigation) ah->mask_reg |= AR_IMR_RXINTM | AR_IMR_RXMINTR; else ah->mask_reg |= AR_IMR_RXOK; @@ -1203,23 +1206,23 @@ static u32 ath9k_hw_def_ini_fixup(struct ath_hw *ah, switch (ah->hw_version.devid) { case AR9280_DEVID_PCI: if (reg == 0x7894) { - DPRINTF(ah->ah_sc, ATH_DBG_ANY, + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "ini VAL: %x EEPROM: %x\n", value, (pBase->version & 0xff)); if ((pBase->version & 0xff) > 0x0a) { - DPRINTF(ah->ah_sc, ATH_DBG_ANY, + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "PWDCLKIND: %d\n", pBase->pwdclkind); value &= ~AR_AN_TOP2_PWDCLKIND; value |= AR_AN_TOP2_PWDCLKIND & (pBase->pwdclkind << AR_AN_TOP2_PWDCLKIND_S); } else { - DPRINTF(ah->ah_sc, ATH_DBG_ANY, + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "PWDCLKIND Earlier Rev\n"); } - DPRINTF(ah->ah_sc, ATH_DBG_ANY, + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "final ini VAL: %x\n", value); } break; @@ -1249,6 +1252,21 @@ static void ath9k_olc_init(struct ath_hw *ah) ah->PDADCdelta = 0; } +static u32 ath9k_regd_get_ctl(struct ath_regulatory *reg, + struct ath9k_channel *chan) +{ + u32 ctl = ath_regd_get_band_ctl(reg, chan->chan->band); + + if (IS_CHAN_B(chan)) + ctl |= CTL_11B; + else if (IS_CHAN_G(chan)) + ctl |= CTL_11G; + else + ctl |= CTL_11A; + + return ctl; +} + static int ath9k_hw_process_ini(struct ath_hw *ah, struct ath9k_channel *chan, enum ath9k_ht_macmode macmode) @@ -1256,7 +1274,6 @@ static int ath9k_hw_process_ini(struct ath_hw *ah, int i, regWrites = 0; struct ieee80211_channel *channel = chan->chan; u32 modesIndex, freqIndex; - int status; switch (chan->chanmode) { case CHANNEL_A: @@ -1327,8 +1344,7 @@ static int ath9k_hw_process_ini(struct ath_hw *ah, if (AR_SREV_9280(ah)) REG_WRITE_ARRAY(&ah->iniModesRxGain, modesIndex, regWrites); - if (AR_SREV_9280(ah) || (AR_SREV_9285(ah) && - AR_SREV_9285_12_OR_LATER(ah))) + if (AR_SREV_9280(ah) || AR_SREV_9285_12_OR_LATER(ah)) REG_WRITE_ARRAY(&ah->iniModesTxGain, modesIndex, regWrites); for (i = 0; i < ah->iniCommon.ia_rows; i++) { @@ -1359,20 +1375,15 @@ static int ath9k_hw_process_ini(struct ath_hw *ah, if (OLC_FOR_AR9280_20_LATER) ath9k_olc_init(ah); - status = ah->eep_ops->set_txpower(ah, chan, - ath9k_regd_get_ctl(ah, chan), - channel->max_antenna_gain * 2, - channel->max_power * 2, - min((u32) MAX_RATE_POWER, - (u32) ah->regulatory.power_limit)); - if (status != 0) { - DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, - "error init'ing transmit power\n"); - return -EIO; - } + ah->eep_ops->set_txpower(ah, chan, + ath9k_regd_get_ctl(&ah->regulatory, chan), + channel->max_antenna_gain * 2, + channel->max_power * 2, + min((u32) MAX_RATE_POWER, + (u32) ah->regulatory.power_limit)); if (!ath9k_hw_set_rf_regs(ah, chan, freqIndex)) { - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "ar5416SetRfRegs failed\n"); return -EIO; } @@ -1600,11 +1611,9 @@ static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type) switch (type) { case ATH9K_RESET_POWER_ON: return ath9k_hw_set_reset_power_on(ah); - break; case ATH9K_RESET_WARM: case ATH9K_RESET_COLD: return ath9k_hw_set_reset(ah, type); - break; default: return false; } @@ -1678,7 +1687,7 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, REG_WRITE(ah, AR_PHY_RFBUS_REQ, AR_PHY_RFBUS_REQ_EN); if (!ath9k_hw_wait(ah, AR_PHY_RFBUS_GRANT, AR_PHY_RFBUS_GRANT_EN, AR_PHY_RFBUS_GRANT_EN, AH_WAIT_TIMEOUT)) { - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Could not kill baseband RX\n"); return false; } @@ -1686,29 +1695,21 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, ath9k_hw_set_regs(ah, chan, macmode); if (AR_SREV_9280_10_OR_LATER(ah)) { - if (!(ath9k_hw_ar9280_set_channel(ah, chan))) { - DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "failed to set channel\n"); - return false; - } + ath9k_hw_ar9280_set_channel(ah, chan); } else { if (!(ath9k_hw_set_channel(ah, chan))) { - DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "failed to set channel\n"); + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "Failed to set channel\n"); return false; } } - if (ah->eep_ops->set_txpower(ah, chan, - ath9k_regd_get_ctl(ah, chan), + ah->eep_ops->set_txpower(ah, chan, + ath9k_regd_get_ctl(&ah->regulatory, chan), channel->max_antenna_gain * 2, channel->max_power * 2, min((u32) MAX_RATE_POWER, - (u32) ah->regulatory.power_limit)) != 0) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "error init'ing transmit power\n"); - return false; - } + (u32) ah->regulatory.power_limit)); synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY; if (IS_CHAN_B(chan)) @@ -2185,6 +2186,18 @@ static void ath9k_hw_spur_mitigate(struct ath_hw *ah, struct ath9k_channel *chan REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask); } +static void ath9k_enable_rfkill(struct ath_hw *ah) +{ + REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, + AR_GPIO_INPUT_EN_VAL_RFSILENT_BB); + + REG_CLR_BIT(ah, AR_GPIO_INPUT_MUX2, + AR_GPIO_INPUT_MUX2_RFSILENT); + + ath9k_hw_cfg_gpio_input(ah, ah->rfkill_gpio); + REG_SET_BIT(ah, AR_PHY_TEST, RFSILENT_BB); +} + int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, bool bChannelChange) { @@ -2199,14 +2212,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, ah->txchainmask = sc->tx_chainmask; ah->rxchainmask = sc->rx_chainmask; - if (AR_SREV_9285(ah)) { - ah->txchainmask &= 0x1; - ah->rxchainmask &= 0x1; - } else if (AR_SREV_9280(ah)) { - ah->txchainmask &= 0x3; - ah->rxchainmask &= 0x3; - } - if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) return -EIO; @@ -2242,7 +2247,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, ath9k_hw_mark_phy_inactive(ah); if (!ath9k_hw_chip_reset(ah, chan)) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, "chip reset failed\n"); + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Chip reset failed\n"); return -EINVAL; } @@ -2304,13 +2309,11 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, REG_WRITE(ah, AR_RSSI_THR, INIT_RSSI_THR); - if (AR_SREV_9280_10_OR_LATER(ah)) { - if (!(ath9k_hw_ar9280_set_channel(ah, chan))) - return -EIO; - } else { + if (AR_SREV_9280_10_OR_LATER(ah)) + ath9k_hw_ar9280_set_channel(ah, chan); + else if (!(ath9k_hw_set_channel(ah, chan))) return -EIO; - } for (i = 0; i < AR_NUM_DCU; i++) REG_WRITE(ah, AR_DQCUMASK(i), 1 << i); @@ -2322,10 +2325,9 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, ath9k_hw_init_interrupt_masks(ah, ah->opmode); ath9k_hw_init_qos(ah); -#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) if (ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) ath9k_enable_rfkill(ah); -#endif + ath9k_hw_init_user_settings(ah); REG_WRITE(ah, AR_STA_ID1, @@ -2335,8 +2337,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, REG_WRITE(ah, AR_OBS, 8); - if (ah->intr_mitigation) { - + if (ah->config.intr_mitigation) { REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, 500); REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, 2000); } @@ -2385,8 +2386,8 @@ bool ath9k_hw_keyreset(struct ath_hw *ah, u16 entry) u32 keyType; if (entry >= ah->caps.keycache_size) { - DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, - "entry %u out of range\n", entry); + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "keychache entry %u out of range\n", entry); return false; } @@ -2422,8 +2423,8 @@ bool ath9k_hw_keysetmac(struct ath_hw *ah, u16 entry, const u8 *mac) u32 macHi, macLo; if (entry >= ah->caps.keycache_size) { - DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, - "entry %u out of range\n", entry); + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "keychache entry %u out of range\n", entry); return false; } @@ -2454,8 +2455,8 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry, u32 keyType; if (entry >= pCap->keycache_size) { - DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, - "entry %u out of range\n", entry); + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "keycache entry %u out of range\n", entry); return false; } @@ -2465,7 +2466,7 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry, break; case ATH9K_CIPHER_AES_CCM: if (!(pCap->hw_caps & ATH9K_HW_CAP_CIPHER_AESCCM)) { - DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, + DPRINTF(ah->ah_sc, ATH_DBG_ANY, "AES-CCM not supported by mac rev 0x%x\n", ah->hw_version.macRev); return false; @@ -2476,20 +2477,20 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry, keyType = AR_KEYTABLE_TYPE_TKIP; if (ATH9K_IS_MIC_ENABLED(ah) && entry + 64 >= pCap->keycache_size) { - DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, + DPRINTF(ah->ah_sc, ATH_DBG_ANY, "entry %u inappropriate for TKIP\n", entry); return false; } break; case ATH9K_CIPHER_WEP: - if (k->kv_len < LEN_WEP40) { - DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, + if (k->kv_len < WLAN_KEY_LEN_WEP40) { + DPRINTF(ah->ah_sc, ATH_DBG_ANY, "WEP key length %u too small\n", k->kv_len); return false; } - if (k->kv_len <= LEN_WEP40) + if (k->kv_len <= WLAN_KEY_LEN_WEP40) keyType = AR_KEYTABLE_TYPE_40; - else if (k->kv_len <= LEN_WEP104) + else if (k->kv_len <= WLAN_KEY_LEN_WEP104) keyType = AR_KEYTABLE_TYPE_104; else keyType = AR_KEYTABLE_TYPE_128; @@ -2498,7 +2499,7 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry, keyType = AR_KEYTABLE_TYPE_CLR; break; default: - DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "cipher %u not supported\n", k->kv_type); return false; } @@ -2508,7 +2509,7 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry, key2 = get_unaligned_le32(k->kv_val + 6); key3 = get_unaligned_le16(k->kv_val + 10); key4 = get_unaligned_le32(k->kv_val + 12); - if (k->kv_len <= LEN_WEP104) + if (k->kv_len <= WLAN_KEY_LEN_WEP104) key4 &= 0xff; /* @@ -2716,7 +2717,7 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip) AR_RTC_FORCE_WAKE_EN); } if (i == 0) { - DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Failed to wakeup in %uus\n", POWER_UP_TIME / 20); return false; } @@ -2737,9 +2738,8 @@ bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode) "UNDEFINED" }; - DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, "%s -> %s (%s)\n", - modes[ah->power_mode], modes[mode], - setChip ? "set chip " : ""); + DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s -> %s\n", + modes[ah->power_mode], modes[mode]); switch (mode) { case ATH9K_PM_AWAKE: @@ -2753,7 +2753,7 @@ bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode) ath9k_set_power_network_sleep(ah, setChip); break; default: - DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Unknown power mode %u\n", mode); return false; } @@ -2943,7 +2943,7 @@ bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked) *masked = isr & ATH9K_INT_COMMON; - if (ah->intr_mitigation) { + if (ah->config.intr_mitigation) { if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM)) *masked |= ATH9K_INT_RX; } @@ -3000,6 +3000,7 @@ bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked) DPRINTF(ah->ah_sc, ATH_DBG_ANY, "received PCI PERR interrupt\n"); } + *masked |= ATH9K_INT_FATAL; } if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) { DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, @@ -3061,7 +3062,7 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints) } if (ints & ATH9K_INT_RX) { mask |= AR_IMR_RXERR; - if (ah->intr_mitigation) + if (ah->config.intr_mitigation) mask |= AR_IMR_RXMINTR | AR_IMR_RXINTM; else mask |= AR_IMR_RXOK | AR_IMR_RXDESC; @@ -3259,7 +3260,7 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah, /* HW Capabilities */ /*******************/ -bool ath9k_hw_fill_cap_info(struct ath_hw *ah) +void ath9k_hw_fill_cap_info(struct ath_hw *ah) { struct ath9k_hw_capabilities *pCap = &ah->caps; u16 capField = 0, eeval; @@ -3343,8 +3344,6 @@ bool ath9k_hw_fill_cap_info(struct ath_hw *ah) pCap->hw_caps |= ATH9K_HW_CAP_MIC_TKIP; pCap->hw_caps |= ATH9K_HW_CAP_MIC_AESCCM; - pCap->hw_caps |= ATH9K_HW_CAP_CHAN_SPREAD; - if (ah->config.ht_enable) pCap->hw_caps |= ATH9K_HW_CAP_HT; else @@ -3368,7 +3367,6 @@ bool ath9k_hw_fill_cap_info(struct ath_hw *ah) pCap->keycache_size = AR_KEYTABLE_SIZE; pCap->hw_caps |= ATH9K_HW_CAP_FASTCC; - pCap->num_mr_retries = 4; pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD; if (AR_SREV_9285_10_OR_LATER(ah)) @@ -3378,14 +3376,6 @@ bool ath9k_hw_fill_cap_info(struct ath_hw *ah) else pCap->num_gpio_pins = AR_NUM_GPIO; - if (AR_SREV_9280_10_OR_LATER(ah)) { - pCap->hw_caps |= ATH9K_HW_CAP_WOW; - pCap->hw_caps |= ATH9K_HW_CAP_WOW_MATCHPATTERN_EXACT; - } else { - pCap->hw_caps &= ~ATH9K_HW_CAP_WOW; - pCap->hw_caps &= ~ATH9K_HW_CAP_WOW_MATCHPATTERN_EXACT; - } - if (AR_SREV_9160_10_OR_LATER(ah) || AR_SREV_9100(ah)) { pCap->hw_caps |= ATH9K_HW_CAP_CST; pCap->rts_aggr_limit = ATH_AMPDU_LIMIT_MAX; @@ -3411,7 +3401,8 @@ bool ath9k_hw_fill_cap_info(struct ath_hw *ah) (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCIE) || (ah->hw_version.macVersion == AR_SREV_VERSION_9160) || (ah->hw_version.macVersion == AR_SREV_VERSION_9100) || - (ah->hw_version.macVersion == AR_SREV_VERSION_9280)) + (ah->hw_version.macVersion == AR_SREV_VERSION_9280) || + (ah->hw_version.macVersion == AR_SREV_VERSION_9285)) pCap->hw_caps &= ~ATH9K_HW_CAP_AUTOSLEEP; else pCap->hw_caps |= ATH9K_HW_CAP_AUTOSLEEP; @@ -3445,8 +3436,6 @@ bool ath9k_hw_fill_cap_info(struct ath_hw *ah) ah->btactive_gpio = 6; ah->wlanactive_gpio = 5; } - - return true; } bool ath9k_hw_getcapability(struct ath_hw *ah, enum ath9k_capability_type type, @@ -3635,20 +3624,6 @@ void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val) AR_GPIO_BIT(gpio)); } -#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) -void ath9k_enable_rfkill(struct ath_hw *ah) -{ - REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, - AR_GPIO_INPUT_EN_VAL_RFSILENT_BB); - - REG_CLR_BIT(ah, AR_GPIO_INPUT_MUX2, - AR_GPIO_INPUT_MUX2_RFSILENT); - - ath9k_hw_cfg_gpio_input(ah, ah->rfkill_gpio); - REG_SET_BIT(ah, AR_PHY_TEST, RFSILENT_BB); -} -#endif - u32 ath9k_hw_getdefantenna(struct ath_hw *ah) { return REG_READ(ah, AR_DEF_ANTENNA) & 0x7; @@ -3754,22 +3729,19 @@ bool ath9k_hw_disable(struct ath_hw *ah) return ath9k_hw_set_reset_reg(ah, ATH9K_RESET_COLD); } -bool ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit) +void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit) { struct ath9k_channel *chan = ah->curchan; struct ieee80211_channel *channel = chan->chan; ah->regulatory.power_limit = min(limit, (u32) MAX_RATE_POWER); - if (ah->eep_ops->set_txpower(ah, chan, - ath9k_regd_get_ctl(ah, chan), - channel->max_antenna_gain * 2, - channel->max_power * 2, - min((u32) MAX_RATE_POWER, - (u32) ah->regulatory.power_limit)) != 0) - return false; - - return true; + ah->eep_ops->set_txpower(ah, chan, + ath9k_regd_get_ctl(&ah->regulatory, chan), + channel->max_antenna_gain * 2, + channel->max_power * 2, + min((u32) MAX_RATE_POWER, + (u32) ah->regulatory.power_limit)); } void ath9k_hw_setmac(struct ath_hw *ah, const u8 *mac) diff --git a/drivers/net/wireless/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h similarity index 86% rename from drivers/net/wireless/ath9k/hw.h rename to drivers/net/wireless/ath/ath9k/hw.h index 0b594e0ee260..9d0b31ad4603 100644 --- a/drivers/net/wireless/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -25,10 +25,11 @@ #include "ani.h" #include "eeprom.h" #include "calib.h" -#include "regd.h" #include "reg.h" #include "phy.h" +#include "../regd.h" + #define ATHEROS_VENDOR_ID 0x168c #define AR5416_DEVID_PCI 0x0023 #define AR5416_DEVID_PCIE 0x0024 @@ -124,29 +125,24 @@ enum wireless_mode { }; enum ath9k_hw_caps { - ATH9K_HW_CAP_CHAN_SPREAD = BIT(0), - ATH9K_HW_CAP_MIC_AESCCM = BIT(1), - ATH9K_HW_CAP_MIC_CKIP = BIT(2), - ATH9K_HW_CAP_MIC_TKIP = BIT(3), - ATH9K_HW_CAP_CIPHER_AESCCM = BIT(4), - ATH9K_HW_CAP_CIPHER_CKIP = BIT(5), - ATH9K_HW_CAP_CIPHER_TKIP = BIT(6), - ATH9K_HW_CAP_VEOL = BIT(7), - ATH9K_HW_CAP_BSSIDMASK = BIT(8), - ATH9K_HW_CAP_MCAST_KEYSEARCH = BIT(9), - ATH9K_HW_CAP_CHAN_HALFRATE = BIT(10), - ATH9K_HW_CAP_CHAN_QUARTERRATE = BIT(11), - ATH9K_HW_CAP_HT = BIT(12), - ATH9K_HW_CAP_GTT = BIT(13), - ATH9K_HW_CAP_FASTCC = BIT(14), - ATH9K_HW_CAP_RFSILENT = BIT(15), - ATH9K_HW_CAP_WOW = BIT(16), - ATH9K_HW_CAP_CST = BIT(17), - ATH9K_HW_CAP_ENHANCEDPM = BIT(18), - ATH9K_HW_CAP_AUTOSLEEP = BIT(19), - ATH9K_HW_CAP_4KB_SPLITTRANS = BIT(20), - ATH9K_HW_CAP_WOW_MATCHPATTERN_EXACT = BIT(21), - ATH9K_HW_CAP_BT_COEX = BIT(22) + ATH9K_HW_CAP_MIC_AESCCM = BIT(0), + ATH9K_HW_CAP_MIC_CKIP = BIT(1), + ATH9K_HW_CAP_MIC_TKIP = BIT(2), + ATH9K_HW_CAP_CIPHER_AESCCM = BIT(3), + ATH9K_HW_CAP_CIPHER_CKIP = BIT(4), + ATH9K_HW_CAP_CIPHER_TKIP = BIT(5), + ATH9K_HW_CAP_VEOL = BIT(6), + ATH9K_HW_CAP_BSSIDMASK = BIT(7), + ATH9K_HW_CAP_MCAST_KEYSEARCH = BIT(8), + ATH9K_HW_CAP_HT = BIT(9), + ATH9K_HW_CAP_GTT = BIT(10), + ATH9K_HW_CAP_FASTCC = BIT(11), + ATH9K_HW_CAP_RFSILENT = BIT(12), + ATH9K_HW_CAP_CST = BIT(13), + ATH9K_HW_CAP_ENHANCEDPM = BIT(14), + ATH9K_HW_CAP_AUTOSLEEP = BIT(15), + ATH9K_HW_CAP_4KB_SPLITTRANS = BIT(16), + ATH9K_HW_CAP_BT_COEX = BIT(17) }; enum ath9k_capability_type { @@ -166,7 +162,6 @@ struct ath9k_hw_capabilities { u16 keycache_size; u16 low_5ghz_chan, high_5ghz_chan; u16 low_2ghz_chan, high_2ghz_chan; - u16 num_mr_retries; u16 rts_aggr_limit; u8 tx_chainmask; u8 rx_chainmask; @@ -184,11 +179,8 @@ struct ath9k_ops_config { int ack_6mb; int cwm_ignore_extcca; u8 pcie_powersave_enable; - u8 pcie_l1skp_enable; u8 pcie_clock_req; u32 pcie_waen; - int pcie_power_reset; - u8 pcie_restore; u8 analog_shiftreg; u8 ht_enable; u32 ofdm_trig_low; @@ -196,17 +188,10 @@ struct ath9k_ops_config { u32 cck_trig_high; u32 cck_trig_low; u32 enable_ani; - u8 noise_immunity_level; - u32 ofdm_weaksignal_det; - u32 cck_weaksignal_thr; - u8 spur_immunity_level; - u8 firstep_level; - int8_t rssi_thr_high; - int8_t rssi_thr_low; u16 diversity_control; u16 antenna_switch_swap; int serialize_regmode; - int intr_mitigation; + bool intr_mitigation; #define SPUR_DISABLE 0 #define SPUR_ENABLE_IOCTL 1 #define SPUR_ENABLE_EEPROM 2 @@ -281,13 +266,6 @@ enum ath9k_int { #define CHANNEL_HT40PLUS 0x20000 #define CHANNEL_HT40MINUS 0x40000 -#define CHANNEL_INTERFERENCE 0x01 -#define CHANNEL_DFS 0x02 -#define CHANNEL_4MS_LIMIT 0x04 -#define CHANNEL_DFS_CLEAR 0x08 -#define CHANNEL_DISALLOW_ADHOC 0x10 -#define CHANNEL_PER_11D_ADHOC 0x20 - #define CHANNEL_A (CHANNEL_5GHZ|CHANNEL_OFDM) #define CHANNEL_B (CHANNEL_2GHZ|CHANNEL_CCK) #define CHANNEL_G (CHANNEL_2GHZ|CHANNEL_OFDM) @@ -318,10 +296,6 @@ struct ath9k_channel { int16_t rawNoiseFloor; }; -#define IS_CHAN_A(_c) ((((_c)->channelFlags & CHANNEL_A) == CHANNEL_A) || \ - (((_c)->channelFlags & CHANNEL_A_HT20) == CHANNEL_A_HT20) || \ - (((_c)->channelFlags & CHANNEL_A_HT40PLUS) == CHANNEL_A_HT40PLUS) || \ - (((_c)->channelFlags & CHANNEL_A_HT40MINUS) == CHANNEL_A_HT40MINUS)) #define IS_CHAN_G(_c) ((((_c)->channelFlags & (CHANNEL_G)) == CHANNEL_G) || \ (((_c)->channelFlags & CHANNEL_G_HT20) == CHANNEL_G_HT20) || \ (((_c)->channelFlags & CHANNEL_G_HT40PLUS) == CHANNEL_G_HT40PLUS) || \ @@ -329,7 +303,6 @@ struct ath9k_channel { #define IS_CHAN_OFDM(_c) (((_c)->channelFlags & CHANNEL_OFDM) != 0) #define IS_CHAN_5GHZ(_c) (((_c)->channelFlags & CHANNEL_5GHZ) != 0) #define IS_CHAN_2GHZ(_c) (((_c)->channelFlags & CHANNEL_2GHZ) != 0) -#define IS_CHAN_PASSIVE(_c) (((_c)->channelFlags & CHANNEL_PASSIVE) != 0) #define IS_CHAN_HALF_RATE(_c) (((_c)->channelFlags & CHANNEL_HALF) != 0) #define IS_CHAN_QUARTER_RATE(_c) (((_c)->channelFlags & CHANNEL_QUARTER) != 0) #define IS_CHAN_A_5MHZ_SPACED(_c) \ @@ -420,7 +393,7 @@ struct ath_hw { struct ath9k_hw_version hw_version; struct ath9k_ops_config config; struct ath9k_hw_capabilities caps; - struct ath9k_regulatory regulatory; + struct ath_regulatory regulatory; struct ath9k_channel channels[38]; struct ath9k_channel *curchan; @@ -463,14 +436,14 @@ struct ath_hw { enum ath9k_ant_setting diversity_control; /* Calibration */ - enum hal_cal_types supp_cals; - struct hal_cal_list iq_caldata; - struct hal_cal_list adcgain_caldata; - struct hal_cal_list adcdc_calinitdata; - struct hal_cal_list adcdc_caldata; - struct hal_cal_list *cal_list; - struct hal_cal_list *cal_list_last; - struct hal_cal_list *cal_list_curr; + enum ath9k_cal_types supp_cals; + struct ath9k_cal_list iq_caldata; + struct ath9k_cal_list adcgain_caldata; + struct ath9k_cal_list adcdc_calinitdata; + struct ath9k_cal_list adcdc_caldata; + struct ath9k_cal_list *cal_list; + struct ath9k_cal_list *cal_list_last; + struct ath9k_cal_list *cal_list_curr; #define totalPowerMeasI meas0.unsign #define totalPowerMeasQ meas1.unsign #define totalIqCorrMeas meas2.sign @@ -540,7 +513,6 @@ struct ath_hw { enum ath9k_ani_cmd ani_function; u32 intr_txqs; - bool intr_mitigation; enum ath9k_ht_extprotspacing extprotspacing; u8 txchainmask; u8 rxchainmask; @@ -573,7 +545,7 @@ struct ath_hw *ath9k_hw_attach(u16 devid, struct ath_softc *sc, int *error); void ath9k_hw_rfdetach(struct ath_hw *ah); int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, bool bChannelChange); -bool ath9k_hw_fill_cap_info(struct ath_hw *ah); +void ath9k_hw_fill_cap_info(struct ath_hw *ah); bool ath9k_hw_getcapability(struct ath_hw *ah, enum ath9k_capability_type type, u32 capability, u32 *result); bool ath9k_hw_setcapability(struct ath_hw *ah, enum ath9k_capability_type type, @@ -593,9 +565,6 @@ u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio); void ath9k_hw_cfg_output(struct ath_hw *ah, u32 gpio, u32 ah_signal_type); void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val); -#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) -void ath9k_enable_rfkill(struct ath_hw *ah); -#endif u32 ath9k_hw_getdefantenna(struct ath_hw *ah); void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna); bool ath9k_hw_setantennaswitch(struct ath_hw *ah, @@ -608,7 +577,8 @@ bool ath9k_hw_setantennaswitch(struct ath_hw *ah, bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout); u32 ath9k_hw_reverse_bits(u32 val, u32 n); bool ath9k_get_channel_edges(struct ath_hw *ah, u16 flags, u16 *low, u16 *high); -u16 ath9k_hw_computetxtime(struct ath_hw *ah, struct ath_rate_table *rates, +u16 ath9k_hw_computetxtime(struct ath_hw *ah, + const struct ath_rate_table *rates, u32 frameLen, u16 rateix, bool shortPreamble); void ath9k_hw_get_channel_centers(struct ath_hw *ah, struct ath9k_channel *chan, @@ -617,7 +587,7 @@ u32 ath9k_hw_getrxfilter(struct ath_hw *ah); void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits); bool ath9k_hw_phy_disable(struct ath_hw *ah); bool ath9k_hw_disable(struct ath_hw *ah); -bool ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit); +void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit); void ath9k_hw_setmac(struct ath_hw *ah, const u8 *mac); void ath9k_hw_setopmode(struct ath_hw *ah); void ath9k_hw_setmcastfilter(struct ath_hw *ah, u32 filter0, u32 filter1); diff --git a/drivers/net/wireless/ath9k/initvals.h b/drivers/net/wireless/ath/ath9k/initvals.h similarity index 100% rename from drivers/net/wireless/ath9k/initvals.h rename to drivers/net/wireless/ath/ath9k/initvals.h diff --git a/drivers/net/wireless/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c similarity index 93% rename from drivers/net/wireless/ath9k/mac.c rename to drivers/net/wireless/ath/ath9k/mac.c index e0a6dee45839..8ae4ec21667b 100644 --- a/drivers/net/wireless/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -49,7 +49,7 @@ bool ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp) bool ath9k_hw_txstart(struct ath_hw *ah, u32 q) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "queue %u\n", q); + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Enable TXE on queue: %u\n", q); REG_WRITE(ah, AR_Q_TXE, 1 << q); @@ -110,13 +110,15 @@ bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q) u32 wait_time = ATH9K_TX_STOP_DMA_TIMEOUT / ATH9K_TIME_QUANTUM; if (q >= pCap->total_queues) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "invalid queue num %u\n", q); + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Stopping TX DMA, " + "invalid queue: %u\n", q); return false; } qi = &ah->txq[q]; if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue\n"); + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Stopping TX DMA, " + "inactive queue: %u\n", q); return false; } @@ -146,7 +148,7 @@ bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q) break; DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, - "TSF have moved while trying to set " + "TSF has moved while trying to set " "quiet time TSF: 0x%08x\n", tsfLow); } @@ -158,8 +160,8 @@ bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q) wait = wait_time; while (ath9k_hw_numtxpending(ah, q)) { if ((--wait) == 0) { - DPRINTF(ah->ah_sc, ATH_DBG_XMIT, - "Failed to stop Tx DMA in 100 " + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, + "Failed to stop TX DMA in 100 " "msec after killing last frame\n"); break; } @@ -454,17 +456,19 @@ bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q, struct ath9k_tx_queue_info *qi; if (q >= pCap->total_queues) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "invalid queue num %u\n", q); + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Set TXQ properties, " + "invalid queue: %u\n", q); return false; } qi = &ah->txq[q]; if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue\n"); + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Set TXQ properties, " + "inactive queue: %u\n", q); return false; } - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "queue %p\n", qi); + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Set queue properties for: %u\n", q); qi->tqi_ver = qinfo->tqi_ver; qi->tqi_subtype = qinfo->tqi_subtype; @@ -521,13 +525,15 @@ bool ath9k_hw_get_txq_props(struct ath_hw *ah, int q, struct ath9k_tx_queue_info *qi; if (q >= pCap->total_queues) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "invalid queue num %u\n", q); + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Get TXQ properties, " + "invalid queue: %u\n", q); return false; } qi = &ah->txq[q]; if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue\n"); + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Get TXQ properties, " + "inactive queue: %u\n", q); return false; } @@ -575,22 +581,23 @@ int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type, ATH9K_TX_QUEUE_INACTIVE) break; if (q == pCap->total_queues) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, - "no available tx queue\n"); + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "No available TX queue\n"); return -1; } break; default: - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "bad tx queue type %u\n", type); + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Invalid TX queue type: %u\n", + type); return -1; } - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "queue %u\n", q); + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Setup TX queue: %u\n", q); qi = &ah->txq[q]; if (qi->tqi_type != ATH9K_TX_QUEUE_INACTIVE) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, - "tx queue %u already active\n", q); + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "TX queue: %u already active\n", q); return -1; } memset(qi, 0, sizeof(struct ath9k_tx_queue_info)); @@ -620,16 +627,18 @@ bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q) struct ath9k_tx_queue_info *qi; if (q >= pCap->total_queues) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "invalid queue num %u\n", q); + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Release TXQ, " + "invalid queue: %u\n", q); return false; } qi = &ah->txq[q]; if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue %u\n", q); + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Release TXQ, " + "inactive queue: %u\n", q); return false; } - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "release queue %u\n", q); + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Release TX queue: %u\n", q); qi->tqi_type = ATH9K_TX_QUEUE_INACTIVE; ah->txok_interrupt_mask &= ~(1 << q); @@ -650,17 +659,19 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) u32 cwMin, chanCwMin, value; if (q >= pCap->total_queues) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "invalid queue num %u\n", q); + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Reset TXQ, " + "invalid queue: %u\n", q); return false; } qi = &ah->txq[q]; if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue %u\n", q); + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Reset TXQ, " + "inactive queue: %u\n", q); return true; } - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "reset queue %u\n", q); + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Reset TX queue: %u\n", q); if (qi->tqi_cwmin == ATH9K_TXQ_USEDEFAULT) { if (chan && IS_CHAN_B(chan)) @@ -894,7 +905,7 @@ bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set) reg = REG_READ(ah, AR_OBS_BUS_1); DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "rx failed to go idle in 10 ms RXSM=0x%x\n", reg); + "RX failed to go idle in 10 ms RXSM=0x%x\n", reg); return false; } @@ -949,8 +960,8 @@ bool ath9k_hw_stopdmarecv(struct ath_hw *ah) } if (i == 0) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, - "dma failed to stop in %d ms " + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "DMA failed to stop in %d ms " "AR_CR=0x%08x AR_DIAG_SW=0x%08x\n", AH_RX_STOP_DMA_TIMEOUT / 1000, REG_READ(ah, AR_CR), diff --git a/drivers/net/wireless/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h similarity index 100% rename from drivers/net/wireless/ath9k/mac.h rename to drivers/net/wireless/ath/ath9k/mac.h diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c similarity index 85% rename from drivers/net/wireless/ath9k/main.c rename to drivers/net/wireless/ath/ath9k/main.c index 13d4e6756c99..66a6c1f5022a 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -35,14 +35,14 @@ MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption"); #define CHAN2G(_freq, _idx) { \ .center_freq = (_freq), \ .hw_value = (_idx), \ - .max_power = 30, \ + .max_power = 20, \ } #define CHAN5G(_freq, _idx) { \ .band = IEEE80211_BAND_5GHZ, \ .center_freq = (_freq), \ .hw_value = (_idx), \ - .max_power = 30, \ + .max_power = 20, \ } /* Some 2 GHz radios are actually tunable on 2312-2732 @@ -189,7 +189,7 @@ static u8 parse_mpdudensity(u8 mpdudensity) static void ath_setup_rates(struct ath_softc *sc, enum ieee80211_band band) { - struct ath_rate_table *rate_table = NULL; + const struct ath_rate_table *rate_table = NULL; struct ieee80211_supported_band *sband; struct ieee80211_rate *rate; int i, maxrates; @@ -231,6 +231,19 @@ static void ath_setup_rates(struct ath_softc *sc, enum ieee80211_band band) } } +static struct ath9k_channel *ath_get_curchannel(struct ath_softc *sc, + struct ieee80211_hw *hw) +{ + struct ieee80211_channel *curchan = hw->conf.channel; + struct ath9k_channel *channel; + u8 chan_idx; + + chan_idx = curchan->hw_value; + channel = &sc->sc_ah->channels[chan_idx]; + ath9k_update_ichannel(sc, hw, channel); + return channel; +} + /* * Set/change channels. If the channel is really being changed, it's done * by reseting the chip. To accomplish this we must first cleanup any pending @@ -280,27 +293,29 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, if (r) { DPRINTF(sc, ATH_DBG_FATAL, "Unable to reset channel (%u Mhz) " - "reset status %u\n", + "reset status %d\n", channel->center_freq, r); spin_unlock_bh(&sc->sc_resetlock); - return r; + goto ps_restore; } spin_unlock_bh(&sc->sc_resetlock); - sc->sc_flags &= ~SC_OP_CHAINMASK_UPDATE; sc->sc_flags &= ~SC_OP_FULL_RESET; if (ath_startrecv(sc) != 0) { DPRINTF(sc, ATH_DBG_FATAL, "Unable to restart recv logic\n"); - return -EIO; + r = -EIO; + goto ps_restore; } ath_cache_conf_rate(sc, &hw->conf); ath_update_txpow(sc); ath9k_hw_set_interrupts(ah, sc->imask); + + ps_restore: ath9k_ps_restore(sc); - return 0; + return r; } /* @@ -330,6 +345,12 @@ static void ath_ani_calibrate(unsigned long data) if (sc->sc_flags & SC_OP_SCANNING) goto set_timer; + /* Only calibrate if awake */ + if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE) + goto set_timer; + + ath9k_ps_wakeup(sc); + /* Long calibration runs independently of short calibration. */ if ((timestamp - sc->ani.longcal_timer) >= ATH_LONG_CALINTERVAL) { longcal = true; @@ -368,31 +389,21 @@ static void ath_ani_calibrate(unsigned long data) /* Perform calibration if necessary */ if (longcal || shortcal) { - bool iscaldone = false; + sc->ani.caldone = ath9k_hw_calibrate(ah, ah->curchan, + sc->rx_chainmask, longcal); - if (ath9k_hw_calibrate(ah, ah->curchan, - sc->rx_chainmask, longcal, - &iscaldone)) { - if (longcal) - sc->ani.noise_floor = - ath9k_hw_getchan_noise(ah, - ah->curchan); + if (longcal) + sc->ani.noise_floor = ath9k_hw_getchan_noise(ah, + ah->curchan); - DPRINTF(sc, ATH_DBG_ANI, - "calibrate chan %u/%x nf: %d\n", - ah->curchan->channel, - ah->curchan->channelFlags, - sc->ani.noise_floor); - } else { - DPRINTF(sc, ATH_DBG_ANY, - "calibrate chan %u/%x failed\n", - ah->curchan->channel, - ah->curchan->channelFlags); - } - sc->ani.caldone = iscaldone; + DPRINTF(sc, ATH_DBG_ANI," calibrate chan %u/%x nf: %d\n", + ah->curchan->channel, ah->curchan->channelFlags, + sc->ani.noise_floor); } } + ath9k_ps_restore(sc); + set_timer: /* * Set timer interval based on previous results. @@ -408,6 +419,18 @@ set_timer: mod_timer(&sc->ani.timer, jiffies + msecs_to_jiffies(cal_interval)); } +static void ath_start_ani(struct ath_softc *sc) +{ + unsigned long timestamp = jiffies_to_msecs(jiffies); + + sc->ani.longcal_timer = timestamp; + sc->ani.shortcal_timer = timestamp; + sc->ani.checkani_timer = timestamp; + + mod_timer(&sc->ani.timer, + jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL)); +} + /* * Update tx/rx chainmask. For legacy association, * hard code chainmask to 1x1, for 11n association, use @@ -416,7 +439,6 @@ set_timer: */ void ath_update_chainmask(struct ath_softc *sc, int is_ht) { - sc->sc_flags |= SC_OP_CHAINMASK_UPDATE; if (is_ht || (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BT_COEX)) { sc->tx_chainmask = sc->sc_ah->caps.tx_chainmask; @@ -436,12 +458,12 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta) an = (struct ath_node *)sta->drv_priv; - if (sc->sc_flags & SC_OP_TXAGGR) + if (sc->sc_flags & SC_OP_TXAGGR) { ath_tx_node_init(sc, an); - - an->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR + - sta->ht_cap.ampdu_factor); - an->mpdudensity = parse_mpdudensity(sta->ht_cap.ampdu_density); + an->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR + + sta->ht_cap.ampdu_factor); + an->mpdudensity = parse_mpdudensity(sta->ht_cap.ampdu_density); + } } static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta) @@ -457,133 +479,130 @@ static void ath9k_tasklet(unsigned long data) struct ath_softc *sc = (struct ath_softc *)data; u32 status = sc->intrstatus; - if (status & ATH9K_INT_FATAL) { - /* need a chip reset */ - ath_reset(sc, false); - return; - } else { + ath9k_ps_wakeup(sc); - if (status & - (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN)) { - spin_lock_bh(&sc->rx.rxflushlock); - ath_rx_tasklet(sc, 0); - spin_unlock_bh(&sc->rx.rxflushlock); - } - /* XXX: optimize this */ - if (status & ATH9K_INT_TX) - ath_tx_tasklet(sc); + if (status & ATH9K_INT_FATAL) { + ath_reset(sc, false); + ath9k_ps_restore(sc); + return; + } + + if (status & (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN)) { + spin_lock_bh(&sc->rx.rxflushlock); + ath_rx_tasklet(sc, 0); + spin_unlock_bh(&sc->rx.rxflushlock); + } + + if (status & ATH9K_INT_TX) + ath_tx_tasklet(sc); + + if ((status & ATH9K_INT_TSFOOR) && + (sc->hw->conf.flags & IEEE80211_CONF_PS)) { + /* + * TSF sync does not look correct; remain awake to sync with + * the next Beacon. + */ + DPRINTF(sc, ATH_DBG_PS, "TSFOOR - Sync with next Beacon\n"); + sc->sc_flags |= SC_OP_WAIT_FOR_BEACON | SC_OP_BEACON_SYNC; } /* re-enable hardware interrupt */ ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); + ath9k_ps_restore(sc); } irqreturn_t ath_isr(int irq, void *dev) { +#define SCHED_INTR ( \ + ATH9K_INT_FATAL | \ + ATH9K_INT_RXORN | \ + ATH9K_INT_RXEOL | \ + ATH9K_INT_RX | \ + ATH9K_INT_TX | \ + ATH9K_INT_BMISS | \ + ATH9K_INT_CST | \ + ATH9K_INT_TSFOOR) + struct ath_softc *sc = dev; struct ath_hw *ah = sc->sc_ah; enum ath9k_int status; bool sched = false; - do { - if (sc->sc_flags & SC_OP_INVALID) { - /* - * The hardware is not ready/present, don't - * touch anything. Note this can happen early - * on if the IRQ is shared. - */ - return IRQ_NONE; - } - if (!ath9k_hw_intrpend(ah)) { /* shared irq, not for us */ - return IRQ_NONE; - } + /* + * The hardware is not ready/present, don't + * touch anything. Note this can happen early + * on if the IRQ is shared. + */ + if (sc->sc_flags & SC_OP_INVALID) + return IRQ_NONE; + + /* shared irq, not for us */ + + if (!ath9k_hw_intrpend(ah)) + return IRQ_NONE; + + /* + * Figure out the reason(s) for the interrupt. Note + * that the hal returns a pseudo-ISR that may include + * bits we haven't explicitly enabled so we mask the + * value to insure we only process bits we requested. + */ + ath9k_hw_getisr(ah, &status); /* NB: clears ISR too */ + status &= sc->imask; /* discard unasked-for bits */ + + /* + * If there are no status bits set, then this interrupt was not + * for me (should have been caught above). + */ + if (!status) + return IRQ_NONE; + + /* Cache the status */ + sc->intrstatus = status; + + if (status & SCHED_INTR) + sched = true; + + /* + * If a FATAL or RXORN interrupt is received, we have to reset the + * chip immediately. + */ + if (status & (ATH9K_INT_FATAL | ATH9K_INT_RXORN)) + goto chip_reset; + + if (status & ATH9K_INT_SWBA) + tasklet_schedule(&sc->bcon_tasklet); + + if (status & ATH9K_INT_TXURN) + ath9k_hw_updatetxtriglevel(ah, true); + + if (status & ATH9K_INT_MIB) { /* - * Figure out the reason(s) for the interrupt. Note - * that the hal returns a pseudo-ISR that may include - * bits we haven't explicitly enabled so we mask the - * value to insure we only process bits we requested. + * Disable interrupts until we service the MIB + * interrupt; otherwise it will continue to + * fire. */ - ath9k_hw_getisr(ah, &status); /* NB: clears ISR too */ - - status &= sc->imask; /* discard unasked-for bits */ - + ath9k_hw_set_interrupts(ah, 0); /* - * If there are no status bits set, then this interrupt was not - * for me (should have been caught above). + * Let the hal handle the event. We assume + * it will clear whatever condition caused + * the interrupt. */ - if (!status) - return IRQ_NONE; + ath9k_hw_procmibevent(ah, &sc->nodestats); + ath9k_hw_set_interrupts(ah, sc->imask); + } - sc->intrstatus = status; - ath9k_ps_wakeup(sc); - - if (status & ATH9K_INT_FATAL) { - /* need a chip reset */ - sched = true; - } else if (status & ATH9K_INT_RXORN) { - /* need a chip reset */ - sched = true; - } else { - if (status & ATH9K_INT_SWBA) { - /* schedule a tasklet for beacon handling */ - tasklet_schedule(&sc->bcon_tasklet); - } - if (status & ATH9K_INT_RXEOL) { - /* - * NB: the hardware should re-read the link when - * RXE bit is written, but it doesn't work - * at least on older hardware revs. - */ - sched = true; - } - - if (status & ATH9K_INT_TXURN) - /* bump tx trigger level */ - ath9k_hw_updatetxtriglevel(ah, true); - /* XXX: optimize this */ - if (status & ATH9K_INT_RX) - sched = true; - if (status & ATH9K_INT_TX) - sched = true; - if (status & ATH9K_INT_BMISS) - sched = true; - /* carrier sense timeout */ - if (status & ATH9K_INT_CST) - sched = true; - if (status & ATH9K_INT_MIB) { - /* - * Disable interrupts until we service the MIB - * interrupt; otherwise it will continue to - * fire. - */ - ath9k_hw_set_interrupts(ah, 0); - /* - * Let the hal handle the event. We assume - * it will clear whatever condition caused - * the interrupt. - */ - ath9k_hw_procmibevent(ah, &sc->nodestats); - ath9k_hw_set_interrupts(ah, sc->imask); - } - if (status & ATH9K_INT_TIM_TIMER) { - if (!(ah->caps.hw_caps & - ATH9K_HW_CAP_AUTOSLEEP)) { - /* Clear RxAbort bit so that we can - * receive frames */ - ath9k_hw_setpower(ah, ATH9K_PM_AWAKE); - ath9k_hw_setrxabort(ah, 0); - sched = true; - sc->sc_flags |= SC_OP_WAIT_FOR_BEACON; - } - } - if (status & ATH9K_INT_TSFOOR) { - /* FIXME: Handle this interrupt for power save */ - sched = true; - } + if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) + if (status & ATH9K_INT_TIM_TIMER) { + /* Clear RxAbort bit so that we can + * receive frames */ + ath9k_hw_setpower(ah, ATH9K_PM_AWAKE); + ath9k_hw_setrxabort(sc->sc_ah, 0); + sc->sc_flags |= SC_OP_WAIT_FOR_BEACON; } - ath9k_ps_restore(sc); - } while (0); + +chip_reset: ath_debug_stat_interrupt(sc, status); @@ -594,6 +613,8 @@ irqreturn_t ath_isr(int irq, void *dev) } return IRQ_HANDLED; + +#undef SCHED_INTR } static u32 ath_get_extchanmode(struct ath_softc *sc, @@ -676,7 +697,7 @@ static int ath_setkey_tkip(struct ath_softc *sc, u16 keyix, const u8 *key, memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic)); if (!ath9k_hw_set_keycache_entry(sc->sc_ah, keyix, hk, NULL)) { /* TX MIC entry failed. No need to proceed further */ - DPRINTF(sc, ATH_DBG_KEYCACHE, + DPRINTF(sc, ATH_DBG_FATAL, "Setting TX MIC Key Failed\n"); return 0; } @@ -909,6 +930,13 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, if (avp->av_opmode == NL80211_IFTYPE_STATION) { sc->curaid = bss_conf->aid; ath9k_hw_write_associd(sc); + + /* + * Request a re-configuration of Beacon related timers + * on the receipt of the first Beacon frame (i.e., + * after time sync with the AP). + */ + sc->sc_flags |= SC_OP_BEACON_SYNC; } /* Configure the beacon */ @@ -920,11 +948,9 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, sc->nodestats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER; sc->nodestats.ns_avgtxrate = ATH_RATE_DUMMY_MARKER; - /* Start ANI */ - mod_timer(&sc->ani.timer, - jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL)); + ath_start_ani(sc); } else { - DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info DISSOC\n"); + DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info DISASSOC\n"); sc->curaid = 0; } } @@ -1098,14 +1124,17 @@ void ath_radio_enable(struct ath_softc *sc) int r; ath9k_ps_wakeup(sc); + ath9k_hw_configpcipowersave(ah, 0); + + if (!ah->curchan) + ah->curchan = ath_get_curchannel(sc, sc->hw); + spin_lock_bh(&sc->sc_resetlock); - r = ath9k_hw_reset(ah, ah->curchan, false); - if (r) { DPRINTF(sc, ATH_DBG_FATAL, "Unable to reset channel %u (%uMhz) ", - "reset status %u\n", + "reset status %d\n", channel->center_freq, r); } spin_unlock_bh(&sc->sc_resetlock); @@ -1152,23 +1181,25 @@ void ath_radio_disable(struct ath_softc *sc) ath_stoprecv(sc); /* turn off frame recv */ ath_flushrecv(sc); /* flush recv queue */ + if (!ah->curchan) + ah->curchan = ath_get_curchannel(sc, sc->hw); + spin_lock_bh(&sc->sc_resetlock); r = ath9k_hw_reset(ah, ah->curchan, false); if (r) { DPRINTF(sc, ATH_DBG_FATAL, "Unable to reset channel %u (%uMhz) " - "reset status %u\n", + "reset status %d\n", channel->center_freq, r); } spin_unlock_bh(&sc->sc_resetlock); ath9k_hw_phy_disable(ah); - ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP); + ath9k_hw_configpcipowersave(ah, 1); ath9k_ps_restore(sc); + ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP); } -#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) - /*******************/ /* Rfkill */ /*******************/ @@ -1181,134 +1212,28 @@ static bool ath_is_rfkill_set(struct ath_softc *sc) ah->rfkill_polarity; } -/* h/w rfkill poll function */ -static void ath_rfkill_poll(struct work_struct *work) +static void ath9k_rfkill_poll_state(struct ieee80211_hw *hw) { - struct ath_softc *sc = container_of(work, struct ath_softc, - rf_kill.rfkill_poll.work); - bool radio_on; + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + bool blocked = !!ath_is_rfkill_set(sc); - if (sc->sc_flags & SC_OP_INVALID) - return; + wiphy_rfkill_set_hw_state(hw->wiphy, blocked); - radio_on = !ath_is_rfkill_set(sc); - - /* - * enable/disable radio only when there is a - * state change in RF switch - */ - if (radio_on == !!(sc->sc_flags & SC_OP_RFKILL_HW_BLOCKED)) { - enum rfkill_state state; - - if (sc->sc_flags & SC_OP_RFKILL_SW_BLOCKED) { - state = radio_on ? RFKILL_STATE_SOFT_BLOCKED - : RFKILL_STATE_HARD_BLOCKED; - } else if (radio_on) { - ath_radio_enable(sc); - state = RFKILL_STATE_UNBLOCKED; - } else { - ath_radio_disable(sc); - state = RFKILL_STATE_HARD_BLOCKED; - } - - if (state == RFKILL_STATE_HARD_BLOCKED) - sc->sc_flags |= SC_OP_RFKILL_HW_BLOCKED; - else - sc->sc_flags &= ~SC_OP_RFKILL_HW_BLOCKED; - - rfkill_force_state(sc->rf_kill.rfkill, state); - } - - queue_delayed_work(sc->hw->workqueue, &sc->rf_kill.rfkill_poll, - msecs_to_jiffies(ATH_RFKILL_POLL_INTERVAL)); + if (blocked) + ath_radio_disable(sc); + else + ath_radio_enable(sc); } -/* s/w rfkill handler */ -static int ath_sw_toggle_radio(void *data, enum rfkill_state state) +static void ath_start_rfkill_poll(struct ath_softc *sc) { - struct ath_softc *sc = data; + struct ath_hw *ah = sc->sc_ah; - switch (state) { - case RFKILL_STATE_SOFT_BLOCKED: - if (!(sc->sc_flags & (SC_OP_RFKILL_HW_BLOCKED | - SC_OP_RFKILL_SW_BLOCKED))) - ath_radio_disable(sc); - sc->sc_flags |= SC_OP_RFKILL_SW_BLOCKED; - return 0; - case RFKILL_STATE_UNBLOCKED: - if ((sc->sc_flags & SC_OP_RFKILL_SW_BLOCKED)) { - sc->sc_flags &= ~SC_OP_RFKILL_SW_BLOCKED; - if (sc->sc_flags & SC_OP_RFKILL_HW_BLOCKED) { - DPRINTF(sc, ATH_DBG_FATAL, "Can't turn on the" - "radio as it is disabled by h/w\n"); - return -EPERM; - } - ath_radio_enable(sc); - } - return 0; - default: - return -EINVAL; - } + if (ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) + wiphy_rfkill_start_polling(sc->hw->wiphy); } -/* Init s/w rfkill */ -static int ath_init_sw_rfkill(struct ath_softc *sc) -{ - sc->rf_kill.rfkill = rfkill_allocate(wiphy_dev(sc->hw->wiphy), - RFKILL_TYPE_WLAN); - if (!sc->rf_kill.rfkill) { - DPRINTF(sc, ATH_DBG_FATAL, "Failed to allocate rfkill\n"); - return -ENOMEM; - } - - snprintf(sc->rf_kill.rfkill_name, sizeof(sc->rf_kill.rfkill_name), - "ath9k-%s::rfkill", wiphy_name(sc->hw->wiphy)); - sc->rf_kill.rfkill->name = sc->rf_kill.rfkill_name; - sc->rf_kill.rfkill->data = sc; - sc->rf_kill.rfkill->toggle_radio = ath_sw_toggle_radio; - sc->rf_kill.rfkill->state = RFKILL_STATE_UNBLOCKED; - sc->rf_kill.rfkill->user_claim_unsupported = 1; - - return 0; -} - -/* Deinitialize rfkill */ -static void ath_deinit_rfkill(struct ath_softc *sc) -{ - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) - cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll); - - if (sc->sc_flags & SC_OP_RFKILL_REGISTERED) { - rfkill_unregister(sc->rf_kill.rfkill); - sc->sc_flags &= ~SC_OP_RFKILL_REGISTERED; - sc->rf_kill.rfkill = NULL; - } -} - -static int ath_start_rfkill_poll(struct ath_softc *sc) -{ - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) - queue_delayed_work(sc->hw->workqueue, - &sc->rf_kill.rfkill_poll, 0); - - if (!(sc->sc_flags & SC_OP_RFKILL_REGISTERED)) { - if (rfkill_register(sc->rf_kill.rfkill)) { - DPRINTF(sc, ATH_DBG_FATAL, - "Unable to register rfkill\n"); - rfkill_free(sc->rf_kill.rfkill); - - /* Deinitialize the device */ - ath_cleanup(sc); - return -EIO; - } else { - sc->sc_flags |= SC_OP_RFKILL_REGISTERED; - } - } - - return 0; -} -#endif /* CONFIG_RFKILL */ - void ath_cleanup(struct ath_softc *sc) { ath_detach(sc); @@ -1327,9 +1252,6 @@ void ath_detach(struct ath_softc *sc) DPRINTF(sc, ATH_DBG_CONFIG, "Detach ATH hw\n"); -#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) - ath_deinit_rfkill(sc); -#endif ath_deinit_leds(sc); cancel_work_sync(&sc->chan_work); cancel_delayed_work_sync(&sc->wiphy_work); @@ -1362,6 +1284,17 @@ void ath_detach(struct ath_softc *sc) ath9k_ps_restore(sc); } +static int ath9k_reg_notifier(struct wiphy *wiphy, + struct regulatory_request *request) +{ + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + struct ath_regulatory *reg = &sc->sc_ah->regulatory; + + return ath_reg_notifier_apply(wiphy, request, reg); +} + static int ath_init(u16 devid, struct ath_softc *sc) { struct ath_hw *ah = NULL; @@ -1403,7 +1336,7 @@ static int ath_init(u16 devid, struct ath_softc *sc) /* Get the hardware key cache size. */ sc->keymax = ah->caps.keycache_size; if (sc->keymax > ATH_KEYMAX) { - DPRINTF(sc, ATH_DBG_KEYCACHE, + DPRINTF(sc, ATH_DBG_ANY, "Warning, using only %u entries in %u key cache\n", ATH_KEYMAX, sc->keymax); sc->keymax = ATH_KEYMAX; @@ -1416,7 +1349,7 @@ static int ath_init(u16 devid, struct ath_softc *sc) for (i = 0; i < sc->keymax; i++) ath9k_hw_keyreset(ah, (u16) i); - if (ath9k_regd_init(sc->sc_ah)) + if (error) goto bad; /* default to MONITOR mode */ @@ -1545,9 +1478,6 @@ static int ath_init(u16 devid, struct ath_softc *sc) sc->beacon.bslot_aphy[i] = NULL; } - /* save MISC configurations */ - sc->config.swBeaconProcess = 1; - /* setup channels and rates */ sc->sbands[IEEE80211_BAND_2GHZ].channels = ath9k_2ghz_chantable; @@ -1602,9 +1532,6 @@ void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_MESH_POINT); - hw->wiphy->reg_notifier = ath9k_reg_notifier; - hw->wiphy->strict_regulatory = true; - hw->queues = 4; hw->max_rates = 4; hw->channel_change_time = 5000; @@ -1625,8 +1552,8 @@ void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) int ath_attach(u16 devid, struct ath_softc *sc) { struct ieee80211_hw *hw = sc->hw; - const struct ieee80211_regdomain *regd; int error = 0, i; + struct ath_regulatory *reg; DPRINTF(sc, ATH_DBG_CONFIG, "Attach ATH hw\n"); @@ -1640,6 +1567,13 @@ int ath_attach(u16 devid, struct ath_softc *sc) ath_set_hw_capab(sc, hw); + error = ath_regd_init(&sc->sc_ah->regulatory, sc->hw->wiphy, + ath9k_reg_notifier); + if (error) + return error; + + reg = &sc->sc_ah->regulatory; + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) { setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap); if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) @@ -1655,42 +1589,14 @@ int ath_attach(u16 devid, struct ath_softc *sc) if (error != 0) goto error_attach; -#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) - /* Initialze h/w Rfkill */ - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) - INIT_DELAYED_WORK(&sc->rf_kill.rfkill_poll, ath_rfkill_poll); - - /* Initialize s/w rfkill */ - error = ath_init_sw_rfkill(sc); - if (error) - goto error_attach; -#endif - - if (ath9k_is_world_regd(sc->sc_ah)) { - /* Anything applied here (prior to wiphy registration) gets - * saved on the wiphy orig_* parameters */ - regd = ath9k_world_regdomain(sc->sc_ah); - hw->wiphy->custom_regulatory = true; - hw->wiphy->strict_regulatory = false; - } else { - /* This gets applied in the case of the absense of CRDA, - * it's our own custom world regulatory domain, similar to - * cfg80211's but we enable passive scanning */ - regd = ath9k_default_world_regdomain(); - } - wiphy_apply_custom_regulatory(hw->wiphy, regd); - ath9k_reg_apply_radar_flags(hw->wiphy); - ath9k_reg_apply_world_flags(hw->wiphy, NL80211_REGDOM_SET_BY_DRIVER); - INIT_WORK(&sc->chan_work, ath9k_wiphy_chan_work); INIT_DELAYED_WORK(&sc->wiphy_work, ath9k_wiphy_work); sc->wiphy_scheduler_int = msecs_to_jiffies(500); error = ieee80211_register_hw(hw); - if (!ath9k_is_world_regd(sc->sc_ah)) { - error = regulatory_hint(hw->wiphy, - sc->sc_ah->regulatory.alpha2); + if (!ath_is_world_regd(reg)) { + error = regulatory_hint(hw->wiphy, reg->alpha2); if (error) goto error_attach; } @@ -1698,6 +1604,7 @@ int ath_attach(u16 devid, struct ath_softc *sc) /* Initialize LED control */ ath_init_leds(sc); + ath_start_rfkill_poll(sc); return 0; @@ -1728,7 +1635,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) r = ath9k_hw_reset(ah, sc->sc_ah->curchan, false); if (r) DPRINTF(sc, ATH_DBG_FATAL, - "Unable to reset hardware; reset status %u\n", r); + "Unable to reset hardware; reset status %d\n", r); spin_unlock_bh(&sc->sc_resetlock); if (ath_startrecv(sc) != 0) @@ -1792,7 +1699,6 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, goto fail; } - dd->dd_name = name; dd->dd_desc_len = sizeof(struct ath_desc) * nbuf * ndesc; /* @@ -1822,7 +1728,7 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, } ds = dd->dd_desc; DPRINTF(sc, ATH_DBG_CONFIG, "%s DMA map: %p (%u) -> %llx (%u)\n", - dd->dd_name, ds, (u32) dd->dd_desc_len, + name, ds, (u32) dd->dd_desc_len, ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len); /* allocate buffers */ @@ -1971,7 +1877,7 @@ static int ath9k_start(struct ieee80211_hw *hw) struct ath_softc *sc = aphy->sc; struct ieee80211_channel *curchan = hw->conf.channel; struct ath9k_channel *init_channel; - int r, pos; + int r; DPRINTF(sc, ATH_DBG_CONFIG, "Starting driver with " "initial channel: %d MHz\n", curchan->center_freq); @@ -2001,11 +1907,9 @@ static int ath9k_start(struct ieee80211_hw *hw) /* setup initial channel */ - pos = curchan->hw_value; + sc->chan_idx = curchan->hw_value; - sc->chan_idx = pos; - init_channel = &sc->sc_ah->channels[pos]; - ath9k_update_ichannel(sc, hw, init_channel); + init_channel = ath_get_curchannel(sc, hw); /* Reset SERDES registers */ ath9k_hw_configpcipowersave(sc->sc_ah, 0); @@ -2021,7 +1925,7 @@ static int ath9k_start(struct ieee80211_hw *hw) r = ath9k_hw_reset(sc->sc_ah, init_channel, false); if (r) { DPRINTF(sc, ATH_DBG_FATAL, - "Unable to reset hardware; reset status %u " + "Unable to reset hardware; reset status %d " "(freq %u MHz)\n", r, curchan->center_freq); spin_unlock_bh(&sc->sc_resetlock); @@ -2043,8 +1947,7 @@ static int ath9k_start(struct ieee80211_hw *hw) * here except setup the interrupt mask. */ if (ath_startrecv(sc) != 0) { - DPRINTF(sc, ATH_DBG_FATAL, - "Unable to start recv logic\n"); + DPRINTF(sc, ATH_DBG_FATAL, "Unable to start recv logic\n"); r = -EIO; goto mutex_unlock; } @@ -2070,10 +1973,6 @@ static int ath9k_start(struct ieee80211_hw *hw) ieee80211_wake_queues(hw); -#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) - r = ath_start_rfkill_poll(sc); -#endif - mutex_unlock: mutex_unlock(&sc->mutex); @@ -2095,6 +1994,46 @@ static int ath9k_tx(struct ieee80211_hw *hw, goto exit; } + if (sc->hw->conf.flags & IEEE80211_CONF_PS) { + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + /* + * mac80211 does not set PM field for normal data frames, so we + * need to update that based on the current PS mode. + */ + if (ieee80211_is_data(hdr->frame_control) && + !ieee80211_is_nullfunc(hdr->frame_control) && + !ieee80211_has_pm(hdr->frame_control)) { + DPRINTF(sc, ATH_DBG_PS, "Add PM=1 for a TX frame " + "while in PS mode\n"); + hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); + } + } + + if (unlikely(sc->sc_ah->power_mode != ATH9K_PM_AWAKE)) { + /* + * We are using PS-Poll and mac80211 can request TX while in + * power save mode. Need to wake up hardware for the TX to be + * completed and if needed, also for RX of buffered frames. + */ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + ath9k_ps_wakeup(sc); + ath9k_hw_setrxabort(sc->sc_ah, 0); + if (ieee80211_is_pspoll(hdr->frame_control)) { + DPRINTF(sc, ATH_DBG_PS, "Sending PS-Poll to pick a " + "buffered frame\n"); + sc->sc_flags |= SC_OP_WAIT_FOR_PSPOLL_DATA; + } else { + DPRINTF(sc, ATH_DBG_PS, "Wake up to complete TX\n"); + sc->sc_flags |= SC_OP_WAIT_FOR_TX_ACK; + } + /* + * The actual restore operation will happen only after + * the sc_flags bit is cleared. We are just dropping + * the ps_usecount here. + */ + ath9k_ps_restore(sc); + } + memset(&txctl, 0, sizeof(struct ath_tx_control)); /* @@ -2171,10 +2110,8 @@ static void ath9k_stop(struct ieee80211_hw *hw) } else sc->rx.rxlink = NULL; -#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) - cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll); -#endif + wiphy_rfkill_stop_polling(sc->hw->wiphy); + /* disable HAL and put h/w to sleep */ ath9k_hw_disable(sc->sc_ah); ath9k_hw_configpcipowersave(sc->sc_ah, 1); @@ -2257,25 +2194,10 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, sc->imask |= ATH9K_INT_TSFOOR; } - /* - * Some hardware processes the TIM IE and fires an - * interrupt when the TIM bit is set. For hardware - * that does, if not overridden by configuration, - * enable the TIM interrupt when operating as station. - */ - if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_ENHANCEDPM) && - (conf->type == NL80211_IFTYPE_STATION) && - !sc->config.swBeaconProcess) - sc->imask |= ATH9K_INT_TIM; - ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); - if (conf->type == NL80211_IFTYPE_AP) { - /* TODO: is this a suitable place to start ANI for AP mode? */ - /* Start ANI */ - mod_timer(&sc->ani.timer, - jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL)); - } + if (conf->type == NL80211_IFTYPE_AP) + ath_start_ani(sc); out: mutex_unlock(&sc->mutex); @@ -2326,26 +2248,36 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; struct ieee80211_conf *conf = &hw->conf; + struct ath_hw *ah = sc->sc_ah; mutex_lock(&sc->mutex); if (changed & IEEE80211_CONF_CHANGE_PS) { if (conf->flags & IEEE80211_CONF_PS) { - if ((sc->imask & ATH9K_INT_TIM_TIMER) == 0) { - sc->imask |= ATH9K_INT_TIM_TIMER; - ath9k_hw_set_interrupts(sc->sc_ah, - sc->imask); + if (!(ah->caps.hw_caps & + ATH9K_HW_CAP_AUTOSLEEP)) { + if ((sc->imask & ATH9K_INT_TIM_TIMER) == 0) { + sc->imask |= ATH9K_INT_TIM_TIMER; + ath9k_hw_set_interrupts(sc->sc_ah, + sc->imask); + } + ath9k_hw_setrxabort(sc->sc_ah, 1); } - ath9k_hw_setrxabort(sc->sc_ah, 1); ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP); } else { ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE); - ath9k_hw_setrxabort(sc->sc_ah, 0); - sc->sc_flags &= ~SC_OP_WAIT_FOR_BEACON; - if (sc->imask & ATH9K_INT_TIM_TIMER) { - sc->imask &= ~ATH9K_INT_TIM_TIMER; - ath9k_hw_set_interrupts(sc->sc_ah, - sc->imask); + if (!(ah->caps.hw_caps & + ATH9K_HW_CAP_AUTOSLEEP)) { + ath9k_hw_setrxabort(sc->sc_ah, 0); + sc->sc_flags &= ~(SC_OP_WAIT_FOR_BEACON | + SC_OP_WAIT_FOR_CAB | + SC_OP_WAIT_FOR_PSPOLL_DATA | + SC_OP_WAIT_FOR_TX_ACK); + if (sc->imask & ATH9K_INT_TIM_TIMER) { + sc->imask &= ~ATH9K_INT_TIM_TIMER; + ath9k_hw_set_interrupts(sc->sc_ah, + sc->imask); + } } } } @@ -2387,114 +2319,6 @@ skip_chan_change: if (changed & IEEE80211_CONF_CHANGE_POWER) sc->config.txpowlimit = 2 * conf->power_level; - /* - * The HW TSF has to be reset when the beacon interval changes. - * We set the flag here, and ath_beacon_config_ap() would take this - * into account when it gets called through the subsequent - * config_interface() call - with IFCC_BEACON in the changed field. - */ - - if (changed & IEEE80211_CONF_CHANGE_BEACON_INTERVAL) - sc->sc_flags |= SC_OP_TSF_RESET; - - mutex_unlock(&sc->mutex); - - return 0; -} - -static int ath9k_config_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_if_conf *conf) -{ - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; - struct ath_hw *ah = sc->sc_ah; - struct ath_vif *avp = (void *)vif->drv_priv; - u32 rfilt = 0; - int error, i; - - mutex_lock(&sc->mutex); - - /* TODO: Need to decide which hw opmode to use for multi-interface - * cases */ - if (vif->type == NL80211_IFTYPE_AP && - ah->opmode != NL80211_IFTYPE_AP) { - ah->opmode = NL80211_IFTYPE_STATION; - ath9k_hw_setopmode(ah); - memcpy(sc->curbssid, sc->sc_ah->macaddr, ETH_ALEN); - sc->curaid = 0; - ath9k_hw_write_associd(sc); - /* Request full reset to get hw opmode changed properly */ - sc->sc_flags |= SC_OP_FULL_RESET; - } - - if ((conf->changed & IEEE80211_IFCC_BSSID) && - !is_zero_ether_addr(conf->bssid)) { - switch (vif->type) { - case NL80211_IFTYPE_STATION: - case NL80211_IFTYPE_ADHOC: - case NL80211_IFTYPE_MESH_POINT: - /* Set BSSID */ - memcpy(sc->curbssid, conf->bssid, ETH_ALEN); - memcpy(avp->bssid, conf->bssid, ETH_ALEN); - sc->curaid = 0; - ath9k_hw_write_associd(sc); - - /* Set aggregation protection mode parameters */ - sc->config.ath_aggr_prot = 0; - - DPRINTF(sc, ATH_DBG_CONFIG, - "RX filter 0x%x bssid %pM aid 0x%x\n", - rfilt, sc->curbssid, sc->curaid); - - /* need to reconfigure the beacon */ - sc->sc_flags &= ~SC_OP_BEACONS ; - - break; - default: - break; - } - } - - if ((vif->type == NL80211_IFTYPE_ADHOC) || - (vif->type == NL80211_IFTYPE_AP) || - (vif->type == NL80211_IFTYPE_MESH_POINT)) { - if ((conf->changed & IEEE80211_IFCC_BEACON) || - (conf->changed & IEEE80211_IFCC_BEACON_ENABLED && - conf->enable_beacon)) { - /* - * Allocate and setup the beacon frame. - * - * Stop any previous beacon DMA. This may be - * necessary, for example, when an ibss merge - * causes reconfiguration; we may be called - * with beacon transmission active. - */ - ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); - - error = ath_beacon_alloc(aphy, vif); - if (error != 0) { - mutex_unlock(&sc->mutex); - return error; - } - - ath_beacon_config(sc, vif); - } - } - - /* Check for WLAN_CAPABILITY_PRIVACY ? */ - if ((avp->av_opmode != NL80211_IFTYPE_STATION)) { - for (i = 0; i < IEEE80211_WEP_NKID; i++) - if (ath9k_hw_keyisvalid(sc->sc_ah, (u16)i)) - ath9k_hw_keysetmac(sc->sc_ah, - (u16)i, - sc->curbssid); - } - - /* Only legacy IBSS for now */ - if (vif->type == NL80211_IFTYPE_ADHOC) - ath_update_chainmask(sc, 0); - mutex_unlock(&sc->mutex); return 0; @@ -2523,8 +2347,10 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw, *total_flags &= SUPPORTED_FILTERS; sc->rx.rxfilter = *total_flags; + ath9k_ps_wakeup(sc); rfilt = ath_calcrxfilter(sc); ath9k_hw_setrxfilter(sc->sc_ah, rfilt); + ath9k_ps_restore(sc); DPRINTF(sc, ATH_DBG_CONFIG, "Set HW RX filter: 0x%x\n", sc->rx.rxfilter); } @@ -2562,6 +2388,8 @@ static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue, mutex_lock(&sc->mutex); + memset(&qi, 0, sizeof(struct ath9k_tx_queue_info)); + qi.tqi_aifs = params->aifs; qi.tqi_cwmin = params->cw_min; qi.tqi_cwmax = params->cw_max; @@ -2598,7 +2426,7 @@ static int ath9k_set_key(struct ieee80211_hw *hw, mutex_lock(&sc->mutex); ath9k_ps_wakeup(sc); - DPRINTF(sc, ATH_DBG_KEYCACHE, "Set HW Key\n"); + DPRINTF(sc, ATH_DBG_CONFIG, "Set HW Key\n"); switch (cmd) { case SET_KEY: @@ -2634,9 +2462,92 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, { struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; + struct ath_hw *ah = sc->sc_ah; + struct ath_vif *avp = (void *)vif->drv_priv; + u32 rfilt = 0; + int error, i; mutex_lock(&sc->mutex); + /* + * TODO: Need to decide which hw opmode to use for + * multi-interface cases + * XXX: This belongs into add_interface! + */ + if (vif->type == NL80211_IFTYPE_AP && + ah->opmode != NL80211_IFTYPE_AP) { + ah->opmode = NL80211_IFTYPE_STATION; + ath9k_hw_setopmode(ah); + memcpy(sc->curbssid, sc->sc_ah->macaddr, ETH_ALEN); + sc->curaid = 0; + ath9k_hw_write_associd(sc); + /* Request full reset to get hw opmode changed properly */ + sc->sc_flags |= SC_OP_FULL_RESET; + } + + if ((changed & BSS_CHANGED_BSSID) && + !is_zero_ether_addr(bss_conf->bssid)) { + switch (vif->type) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_MESH_POINT: + /* Set BSSID */ + memcpy(sc->curbssid, bss_conf->bssid, ETH_ALEN); + memcpy(avp->bssid, bss_conf->bssid, ETH_ALEN); + sc->curaid = 0; + ath9k_hw_write_associd(sc); + + /* Set aggregation protection mode parameters */ + sc->config.ath_aggr_prot = 0; + + DPRINTF(sc, ATH_DBG_CONFIG, + "RX filter 0x%x bssid %pM aid 0x%x\n", + rfilt, sc->curbssid, sc->curaid); + + /* need to reconfigure the beacon */ + sc->sc_flags &= ~SC_OP_BEACONS ; + + break; + default: + break; + } + } + + if ((vif->type == NL80211_IFTYPE_ADHOC) || + (vif->type == NL80211_IFTYPE_AP) || + (vif->type == NL80211_IFTYPE_MESH_POINT)) { + if ((changed & BSS_CHANGED_BEACON) || + (changed & BSS_CHANGED_BEACON_ENABLED && + bss_conf->enable_beacon)) { + /* + * Allocate and setup the beacon frame. + * + * Stop any previous beacon DMA. This may be + * necessary, for example, when an ibss merge + * causes reconfiguration; we may be called + * with beacon transmission active. + */ + ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); + + error = ath_beacon_alloc(aphy, vif); + if (!error) + ath_beacon_config(sc, vif); + } + } + + /* Check for WLAN_CAPABILITY_PRIVACY ? */ + if ((avp->av_opmode != NL80211_IFTYPE_STATION)) { + for (i = 0; i < IEEE80211_WEP_NKID; i++) + if (ath9k_hw_keyisvalid(sc->sc_ah, (u16)i)) + ath9k_hw_keysetmac(sc->sc_ah, + (u16)i, + sc->curbssid); + } + + /* Only legacy IBSS for now */ + if (vif->type == NL80211_IFTYPE_ADHOC) + ath_update_chainmask(sc, 0); + if (changed & BSS_CHANGED_ERP_PREAMBLE) { DPRINTF(sc, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n", bss_conf->use_short_preamble); @@ -2662,6 +2573,18 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, ath9k_bss_assoc_info(sc, vif, bss_conf); } + /* + * The HW TSF has to be reset when the beacon interval changes. + * We set the flag here, and ath_beacon_config_ap() would take this + * into account when it gets called through the subsequent + * config_interface() call - with IFCC_BEACON in the changed field. + */ + + if (changed & BSS_CHANGED_BEACON_INT) { + sc->sc_flags |= SC_OP_TSF_RESET; + sc->beacon_interval = bss_conf->beacon_int; + } + mutex_unlock(&sc->mutex); } @@ -2771,6 +2694,7 @@ static void ath9k_sw_scan_complete(struct ieee80211_hw *hw) mutex_lock(&sc->mutex); aphy->state = ATH_WIPHY_ACTIVE; sc->sc_flags &= ~SC_OP_SCANNING; + sc->sc_flags |= SC_OP_FULL_RESET; mutex_unlock(&sc->mutex); } @@ -2781,7 +2705,6 @@ struct ieee80211_ops ath9k_ops = { .add_interface = ath9k_add_interface, .remove_interface = ath9k_remove_interface, .config = ath9k_config, - .config_interface = ath9k_config_interface, .configure_filter = ath9k_configure_filter, .sta_notify = ath9k_sta_notify, .conf_tx = ath9k_conf_tx, @@ -2793,6 +2716,7 @@ struct ieee80211_ops ath9k_ops = { .ampdu_action = ath9k_ampdu_action, .sw_scan_start = ath9k_sw_scan_start, .sw_scan_complete = ath9k_sw_scan_complete, + .rfkill_poll = ath9k_rfkill_poll_state, }; static struct { diff --git a/drivers/net/wireless/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c similarity index 92% rename from drivers/net/wireless/ath9k/pci.c rename to drivers/net/wireless/ath/ath9k/pci.c index 168411d322a2..170c5b32e49b 100644 --- a/drivers/net/wireless/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -87,6 +87,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) struct ath_softc *sc; struct ieee80211_hw *hw; u8 csz; + u32 val; int ret = 0; struct ath_hw *ah; @@ -133,6 +134,14 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) pci_set_master(pdev); + /* + * Disable the RETRY_TIMEOUT register (0x41) to keep + * PCI Tx retries from interfering with C3 CPU state. + */ + pci_read_config_dword(pdev, 0x40, &val); + if ((val & 0x0000ff00) != 0) + pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); + ret = pci_request_region(pdev, 0, "ath9k"); if (ret) { dev_err(&pdev->dev, "PCI memory region reserve error\n"); @@ -227,11 +236,6 @@ static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state) ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); -#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) - cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll); -#endif - pci_save_state(pdev); pci_disable_device(pdev); pci_set_power_state(pdev, PCI_D3hot); @@ -244,28 +248,27 @@ static int ath_pci_resume(struct pci_dev *pdev) struct ieee80211_hw *hw = pci_get_drvdata(pdev); struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; + u32 val; int err; err = pci_enable_device(pdev); if (err) return err; pci_restore_state(pdev); + /* + * Suspend/Resume resets the PCI configuration space, so we have to + * re-disable the RETRY_TIMEOUT register (0x41) to keep + * PCI Tx retries from interfering with C3 CPU state + */ + pci_read_config_dword(pdev, 0x40, &val); + if ((val & 0x0000ff00) != 0) + pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); /* Enable LED */ ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); -#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) - /* - * check the h/w rfkill state on resume - * and start the rfkill poll timer - */ - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) - queue_delayed_work(sc->hw->workqueue, - &sc->rf_kill.rfkill_poll, 0); -#endif - return 0; } diff --git a/drivers/net/wireless/ath9k/phy.c b/drivers/net/wireless/ath/ath9k/phy.c similarity index 98% rename from drivers/net/wireless/ath9k/phy.c rename to drivers/net/wireless/ath/ath9k/phy.c index 8bcba906929a..aaa941561c36 100644 --- a/drivers/net/wireless/ath9k/phy.c +++ b/drivers/net/wireless/ath/ath9k/phy.c @@ -46,7 +46,7 @@ ath9k_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) channelSel = ((freq - 704) * 2 - 3040) / 10; bModeSynth = 1; } else { - DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Invalid channel %u MHz\n", freq); return false; } @@ -79,7 +79,7 @@ ath9k_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) channelSel = ath9k_hw_reverse_bits((freq - 4800) / 5, 8); aModeRefSel = ath9k_hw_reverse_bits(1, 2); } else { - DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Invalid channel %u MHz\n", freq); return false; } @@ -96,9 +96,8 @@ ath9k_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) return true; } -bool -ath9k_hw_ar9280_set_channel(struct ath_hw *ah, - struct ath9k_channel *chan) +void ath9k_hw_ar9280_set_channel(struct ath_hw *ah, + struct ath9k_channel *chan) { u16 bMode, fracMode, aModeRefSel = 0; u32 freq, ndiv, channelSel = 0, channelFrac = 0, reg32 = 0; @@ -169,8 +168,6 @@ ath9k_hw_ar9280_set_channel(struct ath_hw *ah, ah->curchan = chan; ah->curchan_rad_index = -1; - - return true; } static void diff --git a/drivers/net/wireless/ath9k/phy.h b/drivers/net/wireless/ath/ath9k/phy.h similarity index 99% rename from drivers/net/wireless/ath9k/phy.h rename to drivers/net/wireless/ath/ath9k/phy.h index 0f7f8e0c9c95..c70f530642f6 100644 --- a/drivers/net/wireless/ath9k/phy.h +++ b/drivers/net/wireless/ath/ath9k/phy.h @@ -17,7 +17,7 @@ #ifndef PHY_H #define PHY_H -bool ath9k_hw_ar9280_set_channel(struct ath_hw *ah, +void ath9k_hw_ar9280_set_channel(struct ath_hw *ah, struct ath9k_channel *chan); bool ath9k_hw_set_channel(struct ath_hw *ah, @@ -556,9 +556,6 @@ bool ath9k_hw_init_rf(struct ath_hw *ah, int r; \ for (r = 0; r < ((iniarray)->ia_rows); r++) { \ REG_WRITE(ah, INI_RA((iniarray), r, 0), (regData)[r]); \ - DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, \ - "RF 0x%x V 0x%x\n", \ - INI_RA((iniarray), r, 0), (regData)[r]); \ DO_DELAY(regWr); \ } \ } while (0) diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c similarity index 95% rename from drivers/net/wireless/ath9k/rc.c rename to drivers/net/wireless/ath/ath9k/rc.c index 824ccbb8b7b8..ba06e78b2f50 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -17,7 +17,7 @@ #include "ath9k.h" -static struct ath_rate_table ar5416_11na_ratetable = { +static const struct ath_rate_table ar5416_11na_ratetable = { 42, { { VALID, VALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ @@ -155,7 +155,7 @@ static struct ath_rate_table ar5416_11na_ratetable = { /* 4ms frame limit not used for NG mode. The values filled * for HT are the 64K max aggregate limit */ -static struct ath_rate_table ar5416_11ng_ratetable = { +static const struct ath_rate_table ar5416_11ng_ratetable = { 46, { { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */ @@ -302,7 +302,7 @@ static struct ath_rate_table ar5416_11ng_ratetable = { WLAN_RC_HT_FLAG, /* Phy rates allowed initially */ }; -static struct ath_rate_table ar5416_11a_ratetable = { +static const struct ath_rate_table ar5416_11a_ratetable = { 8, { { VALID, VALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ @@ -335,7 +335,7 @@ static struct ath_rate_table ar5416_11a_ratetable = { 0, /* Phy rates allowed initially */ }; -static struct ath_rate_table ar5416_11g_ratetable = { +static const struct ath_rate_table ar5416_11g_ratetable = { 12, { { VALID, VALID, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */ @@ -380,7 +380,7 @@ static struct ath_rate_table ar5416_11g_ratetable = { 0, /* Phy rates allowed initially */ }; -static struct ath_rate_table ar5416_11b_ratetable = { +static const struct ath_rate_table ar5416_11b_ratetable = { 4, { { VALID, VALID, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */ @@ -420,7 +420,7 @@ static inline int8_t median(int8_t a, int8_t b, int8_t c) } } -static void ath_rc_sort_validrates(struct ath_rate_table *rate_table, +static void ath_rc_sort_validrates(const struct ath_rate_table *rate_table, struct ath_rate_priv *ath_rc_priv) { u8 i, j, idx, idx_next; @@ -461,10 +461,11 @@ static inline int ath_rc_isvalid_txmask(struct ath_rate_priv *ath_rc_priv, return ath_rc_priv->valid_rate_index[index]; } -static inline int ath_rc_get_nextvalid_txrate(struct ath_rate_table *rate_table, - struct ath_rate_priv *ath_rc_priv, - u8 cur_valid_txrate, - u8 *next_idx) +static inline +int ath_rc_get_nextvalid_txrate(const struct ath_rate_table *rate_table, + struct ath_rate_priv *ath_rc_priv, + u8 cur_valid_txrate, + u8 *next_idx) { u8 i; @@ -500,7 +501,7 @@ static int ath_rc_valid_phyrate(u32 phy, u32 capflag, int ignore_cw) } static inline int -ath_rc_get_nextlowervalid_txrate(struct ath_rate_table *rate_table, +ath_rc_get_nextlowervalid_txrate(const struct ath_rate_table *rate_table, struct ath_rate_priv *ath_rc_priv, u8 cur_valid_txrate, u8 *next_idx) { @@ -517,14 +518,14 @@ ath_rc_get_nextlowervalid_txrate(struct ath_rate_table *rate_table, } static u8 ath_rc_init_validrates(struct ath_rate_priv *ath_rc_priv, - struct ath_rate_table *rate_table, + const struct ath_rate_table *rate_table, u32 capflag) { u8 i, hi = 0; u32 valid; for (i = 0; i < rate_table->rate_cnt; i++) { - valid = (ath_rc_priv->single_stream ? + valid = (!(ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG) ? rate_table->info[i].valid_single_stream : rate_table->info[i].valid); if (valid == 1) { @@ -547,7 +548,7 @@ static u8 ath_rc_init_validrates(struct ath_rate_priv *ath_rc_priv, } static u8 ath_rc_setvalid_rates(struct ath_rate_priv *ath_rc_priv, - struct ath_rate_table *rate_table, + const struct ath_rate_table *rate_table, struct ath_rateset *rateset, u32 capflag) { @@ -557,9 +558,9 @@ static u8 ath_rc_setvalid_rates(struct ath_rate_priv *ath_rc_priv, for (i = 0; i < rateset->rs_nrates; i++) { for (j = 0; j < rate_table->rate_cnt; j++) { u32 phy = rate_table->info[j].phy; - u32 valid = (ath_rc_priv->single_stream ? - rate_table->info[j].valid_single_stream : - rate_table->info[j].valid); + u32 valid = (!(ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG) ? + rate_table->info[j].valid_single_stream : + rate_table->info[j].valid); u8 rate = rateset->rs_rates[i]; u8 dot11rate = rate_table->info[j].dot11rate; @@ -592,7 +593,7 @@ static u8 ath_rc_setvalid_rates(struct ath_rate_priv *ath_rc_priv, } static u8 ath_rc_setvalid_htrates(struct ath_rate_priv *ath_rc_priv, - struct ath_rate_table *rate_table, + const struct ath_rate_table *rate_table, u8 *mcs_set, u32 capflag) { struct ath_rateset *rateset = (struct ath_rateset *)mcs_set; @@ -603,7 +604,7 @@ static u8 ath_rc_setvalid_htrates(struct ath_rate_priv *ath_rc_priv, for (i = 0; i < rateset->rs_nrates; i++) { for (j = 0; j < rate_table->rate_cnt; j++) { u32 phy = rate_table->info[j].phy; - u32 valid = (ath_rc_priv->single_stream ? + u32 valid = (!(ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG) ? rate_table->info[j].valid_single_stream : rate_table->info[j].valid); u8 rate = rateset->rs_rates[i]; @@ -630,7 +631,7 @@ static u8 ath_rc_setvalid_htrates(struct ath_rate_priv *ath_rc_priv, static u8 ath_rc_ratefind_ht(struct ath_softc *sc, struct ath_rate_priv *ath_rc_priv, - struct ath_rate_table *rate_table, + const struct ath_rate_table *rate_table, int *is_probing) { u32 dt, best_thruput, this_thruput, now_msec; @@ -740,14 +741,15 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc, if (rate > (ath_rc_priv->rate_table_size - 1)) rate = ath_rc_priv->rate_table_size - 1; - ASSERT((rate_table->info[rate].valid && !ath_rc_priv->single_stream) || + ASSERT((rate_table->info[rate].valid && + (ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG)) || (rate_table->info[rate].valid_single_stream && - ath_rc_priv->single_stream)); + !(ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG))); return rate; } -static void ath_rc_rate_set_series(struct ath_rate_table *rate_table, +static void ath_rc_rate_set_series(const struct ath_rate_table *rate_table, struct ieee80211_tx_rate *rate, struct ieee80211_tx_rate_control *txrc, u8 tries, u8 rix, int rtsctsenable) @@ -768,7 +770,7 @@ static void ath_rc_rate_set_series(struct ath_rate_table *rate_table, } static void ath_rc_rate_set_rtscts(struct ath_softc *sc, - struct ath_rate_table *rate_table, + const struct ath_rate_table *rate_table, struct ieee80211_tx_info *tx_info) { struct ieee80211_tx_rate *rates = tx_info->control.rates; @@ -806,12 +808,12 @@ static void ath_rc_rate_set_rtscts(struct ath_softc *sc, static u8 ath_rc_rate_getidx(struct ath_softc *sc, struct ath_rate_priv *ath_rc_priv, - struct ath_rate_table *rate_table, + const struct ath_rate_table *rate_table, u8 rix, u16 stepdown, u16 min_rate) { u32 j; - u8 nextindex; + u8 nextindex = 0; if (min_rate) { for (j = RATE_TABLE_SIZE; j > 0; j--) { @@ -837,7 +839,7 @@ static void ath_rc_ratefind(struct ath_softc *sc, struct ath_rate_priv *ath_rc_priv, struct ieee80211_tx_rate_control *txrc) { - struct ath_rate_table *rate_table; + const struct ath_rate_table *rate_table; struct sk_buff *skb = txrc->skb; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_rate *rates = tx_info->control.rates; @@ -936,7 +938,7 @@ static void ath_rc_ratefind(struct ath_softc *sc, } static bool ath_rc_update_per(struct ath_softc *sc, - struct ath_rate_table *rate_table, + const struct ath_rate_table *rate_table, struct ath_rate_priv *ath_rc_priv, struct ath_tx_info_priv *tx_info_priv, int tx_rate, int xretries, int retries, @@ -1141,7 +1143,7 @@ static void ath_rc_update_ht(struct ath_softc *sc, int rate; u8 last_per; bool state_change = false; - struct ath_rate_table *rate_table = sc->cur_rate_table; + const struct ath_rate_table *rate_table = sc->cur_rate_table; int size = ath_rc_priv->rate_table_size; if ((tx_rate < 0) || (tx_rate > rate_table->rate_cnt)) @@ -1275,7 +1277,7 @@ static void ath_rc_update_ht(struct ath_softc *sc, #undef CHK_RSSI } -static int ath_rc_get_rateindex(struct ath_rate_table *rate_table, +static int ath_rc_get_rateindex(const struct ath_rate_table *rate_table, struct ieee80211_tx_rate *rate) { int rix; @@ -1299,7 +1301,7 @@ static void ath_rc_tx_status(struct ath_softc *sc, int final_ts_idx, int xretries, int long_retry) { struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info); - struct ath_rate_table *rate_table; + const struct ath_rate_table *rate_table; struct ieee80211_tx_rate *rates = tx_info->status.rates; u8 flags; u32 i = 0, rix; @@ -1320,7 +1322,7 @@ static void ath_rc_tx_status(struct ath_softc *sc, * 40 to 20 => don't update */ if ((flags & IEEE80211_TX_RC_40_MHZ_WIDTH) && - (ath_rc_priv->rc_phy_mode != WLAN_RC_40_FLAG)) + !(ath_rc_priv->ht_cap & WLAN_RC_40_FLAG)) return; rix = ath_rc_get_rateindex(rate_table, &rates[i]); @@ -1345,18 +1347,19 @@ static void ath_rc_tx_status(struct ath_softc *sc, /* If HT40 and we have switched mode from 40 to 20 => don't update */ if ((flags & IEEE80211_TX_RC_40_MHZ_WIDTH) && - (ath_rc_priv->rc_phy_mode != WLAN_RC_40_FLAG)) { + !(ath_rc_priv->ht_cap & WLAN_RC_40_FLAG)) return; - } rix = ath_rc_get_rateindex(rate_table, &rates[i]); ath_rc_update_ht(sc, ath_rc_priv, tx_info_priv, rix, xretries, long_retry); } -static struct ath_rate_table *ath_choose_rate_table(struct ath_softc *sc, - enum ieee80211_band band, - bool is_ht, bool is_cw_40) +static const +struct ath_rate_table *ath_choose_rate_table(struct ath_softc *sc, + enum ieee80211_band band, + bool is_ht, + bool is_cw_40) { int mode = 0; @@ -1390,7 +1393,7 @@ static void ath_rc_init(struct ath_softc *sc, struct ath_rate_priv *ath_rc_priv, struct ieee80211_supported_band *sband, struct ieee80211_sta *sta, - struct ath_rate_table *rate_table) + const struct ath_rate_table *rate_table) { struct ath_rateset *rateset = &ath_rc_priv->neg_rates; u8 *ht_mcs = (u8 *)&ath_rc_priv->neg_ht_rates; @@ -1420,10 +1423,6 @@ static void ath_rc_init(struct ath_softc *sc, ath_rc_priv->valid_phy_rateidx[i][j] = 0; ath_rc_priv->valid_phy_ratecnt[i] = 0; } - ath_rc_priv->rc_phy_mode = ath_rc_priv->ht_cap & WLAN_RC_40_FLAG; - - /* Set stream capability */ - ath_rc_priv->single_stream = (ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG) ? 0 : 1; if (!rateset->rs_nrates) { /* No working rate, just initialize valid rates */ @@ -1572,12 +1571,13 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, struct ath_rate_priv *ath_rc_priv = priv_sta; __le16 fc = hdr->frame_control; - /* lowest rate for management and multicast/broadcast frames */ - if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1) || - !sta) { + /* lowest rate for management and NO_ACK frames */ + if (!ieee80211_is_data(fc) || + tx_info->flags & IEEE80211_TX_CTL_NO_ACK || !sta) { tx_info->control.rates[0].idx = rate_lowest_index(sband, sta); tx_info->control.rates[0].count = - is_multicast_ether_addr(hdr->addr1) ? 1 : ATH_MGT_TXMAXTRY; + (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) ? + 1 : ATH_MGT_TXMAXTRY; return; } @@ -1590,7 +1590,7 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband, { struct ath_softc *sc = priv; struct ath_rate_priv *ath_rc_priv = priv_sta; - struct ath_rate_table *rate_table = NULL; + const struct ath_rate_table *rate_table = NULL; bool is_cw40, is_sgi40; int i, j = 0; @@ -1639,7 +1639,7 @@ static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband, { struct ath_softc *sc = priv; struct ath_rate_priv *ath_rc_priv = priv_sta; - struct ath_rate_table *rate_table = NULL; + const struct ath_rate_table *rate_table = NULL; bool oper_cw40 = false, oper_sgi40; bool local_cw40 = (ath_rc_priv->ht_cap & WLAN_RC_40_FLAG) ? true : false; diff --git a/drivers/net/wireless/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h similarity index 98% rename from drivers/net/wireless/ath9k/rc.h rename to drivers/net/wireless/ath/ath9k/rc.h index 199a3ce57d64..e3abd76103fd 100644 --- a/drivers/net/wireless/ath9k/rc.h +++ b/drivers/net/wireless/ath/ath9k/rc.h @@ -24,7 +24,6 @@ struct ath_softc; #define ATH_RATE_MAX 30 #define RATE_TABLE_SIZE 64 #define MAX_TX_RATE_PHY 48 -#define WLAN_CTRL_FRAME_SIZE (2+2+6+4) /* VALID_ALL - valid for 20/40/Legacy, * VALID - Legacy only, @@ -158,7 +157,6 @@ struct ath_rateset { * @probe_interval: interval for ratectrl to probe for other rates * @prev_data_rix: rate idx of last data frame * @ht_cap: HT capabilities - * @single_stream: When TRUE, only single TX stream possible * @neg_rates: Negotatied rates * @neg_ht_rates: Negotiated HT rates */ @@ -176,10 +174,8 @@ struct ath_rate_priv { u8 max_valid_rate; u8 valid_rate_index[RATE_TABLE_SIZE]; u8 ht_cap; - u8 single_stream; u8 valid_phy_ratecnt[WLAN_RC_PHY_MAX]; u8 valid_phy_rateidx[WLAN_RC_PHY_MAX][RATE_TABLE_SIZE]; - u8 rc_phy_mode; u8 rate_max_phy; u32 rssi_time; u32 rssi_down_time; diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c similarity index 74% rename from drivers/net/wireless/ath9k/recv.c rename to drivers/net/wireless/ath/ath9k/recv.c index dd1f30156740..cece1c4c6bda 100644 --- a/drivers/net/wireless/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -283,54 +283,51 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) struct ath_buf *bf; int error = 0; - do { - spin_lock_init(&sc->rx.rxflushlock); - sc->sc_flags &= ~SC_OP_RXFLUSH; - spin_lock_init(&sc->rx.rxbuflock); + spin_lock_init(&sc->rx.rxflushlock); + sc->sc_flags &= ~SC_OP_RXFLUSH; + spin_lock_init(&sc->rx.rxbuflock); - sc->rx.bufsize = roundup(IEEE80211_MAX_MPDU_LEN, - min(sc->cachelsz, - (u16)64)); + sc->rx.bufsize = roundup(IEEE80211_MAX_MPDU_LEN, + min(sc->cachelsz, (u16)64)); - DPRINTF(sc, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n", - sc->cachelsz, sc->rx.bufsize); + DPRINTF(sc, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n", + sc->cachelsz, sc->rx.bufsize); - /* Initialize rx descriptors */ + /* Initialize rx descriptors */ - error = ath_descdma_setup(sc, &sc->rx.rxdma, &sc->rx.rxbuf, - "rx", nbufs, 1); - if (error != 0) { + error = ath_descdma_setup(sc, &sc->rx.rxdma, &sc->rx.rxbuf, + "rx", nbufs, 1); + if (error != 0) { + DPRINTF(sc, ATH_DBG_FATAL, + "failed to allocate rx descriptors: %d\n", error); + goto err; + } + + list_for_each_entry(bf, &sc->rx.rxbuf, list) { + skb = ath_rxbuf_alloc(sc, sc->rx.bufsize, GFP_KERNEL); + if (skb == NULL) { + error = -ENOMEM; + goto err; + } + + bf->bf_mpdu = skb; + bf->bf_buf_addr = dma_map_single(sc->dev, skb->data, + sc->rx.bufsize, + DMA_FROM_DEVICE); + if (unlikely(dma_mapping_error(sc->dev, + bf->bf_buf_addr))) { + dev_kfree_skb_any(skb); + bf->bf_mpdu = NULL; DPRINTF(sc, ATH_DBG_FATAL, - "failed to allocate rx descriptors: %d\n", error); - break; + "dma_mapping_error() on RX init\n"); + error = -ENOMEM; + goto err; } + bf->bf_dmacontext = bf->bf_buf_addr; + } + sc->rx.rxlink = NULL; - list_for_each_entry(bf, &sc->rx.rxbuf, list) { - skb = ath_rxbuf_alloc(sc, sc->rx.bufsize, GFP_KERNEL); - if (skb == NULL) { - error = -ENOMEM; - break; - } - - bf->bf_mpdu = skb; - bf->bf_buf_addr = dma_map_single(sc->dev, skb->data, - sc->rx.bufsize, - DMA_FROM_DEVICE); - if (unlikely(dma_mapping_error(sc->dev, - bf->bf_buf_addr))) { - dev_kfree_skb_any(skb); - bf->bf_mpdu = NULL; - DPRINTF(sc, ATH_DBG_CONFIG, - "dma_mapping_error() on RX init\n"); - error = -ENOMEM; - break; - } - bf->bf_dmacontext = bf->bf_buf_addr; - } - sc->rx.rxlink = NULL; - - } while (0); - +err: if (error) ath_rx_cleanup(sc); @@ -345,10 +342,8 @@ void ath_rx_cleanup(struct ath_softc *sc) list_for_each_entry(bf, &sc->rx.rxbuf, list) { skb = bf->bf_mpdu; if (skb) { - dma_unmap_single(sc->dev, - bf->bf_buf_addr, - sc->rx.bufsize, - DMA_FROM_DEVICE); + dma_unmap_single(sc->dev, bf->bf_buf_addr, + sc->rx.bufsize, DMA_FROM_DEVICE); dev_kfree_skb(skb); } } @@ -478,6 +473,162 @@ void ath_flushrecv(struct ath_softc *sc) spin_unlock_bh(&sc->rx.rxflushlock); } +static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb) +{ + /* Check whether the Beacon frame has DTIM indicating buffered bc/mc */ + struct ieee80211_mgmt *mgmt; + u8 *pos, *end, id, elen; + struct ieee80211_tim_ie *tim; + + mgmt = (struct ieee80211_mgmt *)skb->data; + pos = mgmt->u.beacon.variable; + end = skb->data + skb->len; + + while (pos + 2 < end) { + id = *pos++; + elen = *pos++; + if (pos + elen > end) + break; + + if (id == WLAN_EID_TIM) { + if (elen < sizeof(*tim)) + break; + tim = (struct ieee80211_tim_ie *) pos; + if (tim->dtim_count != 0) + break; + return tim->bitmap_ctrl & 0x01; + } + + pos += elen; + } + + return false; +} + +static void ath_rx_ps_back_to_sleep(struct ath_softc *sc) +{ + sc->sc_flags &= ~(SC_OP_WAIT_FOR_BEACON | SC_OP_WAIT_FOR_CAB); +} + +static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) +{ + struct ieee80211_mgmt *mgmt; + + if (skb->len < 24 + 8 + 2 + 2) + return; + + mgmt = (struct ieee80211_mgmt *)skb->data; + if (memcmp(sc->curbssid, mgmt->bssid, ETH_ALEN) != 0) + return; /* not from our current AP */ + + if (sc->sc_flags & SC_OP_BEACON_SYNC) { + sc->sc_flags &= ~SC_OP_BEACON_SYNC; + DPRINTF(sc, ATH_DBG_PS, "Reconfigure Beacon timers based on " + "timestamp from the AP\n"); + ath_beacon_config(sc, NULL); + } + + if (!(sc->hw->conf.flags & IEEE80211_CONF_PS)) { + /* We are not in PS mode anymore; remain awake */ + DPRINTF(sc, ATH_DBG_PS, "Not in PS mode anymore, remain " + "awake\n"); + sc->sc_flags &= ~(SC_OP_WAIT_FOR_BEACON | SC_OP_WAIT_FOR_CAB); + return; + } + + if (ath_beacon_dtim_pending_cab(skb)) { + /* + * Remain awake waiting for buffered broadcast/multicast + * frames. If the last broadcast/multicast frame is not + * received properly, the next beacon frame will work as + * a backup trigger for returning into NETWORK SLEEP state, + * so we are waiting for it as well. + */ + DPRINTF(sc, ATH_DBG_PS, "Received DTIM beacon indicating " + "buffered broadcast/multicast frame(s)\n"); + sc->sc_flags |= SC_OP_WAIT_FOR_CAB | SC_OP_WAIT_FOR_BEACON; + return; + } + + if (sc->sc_flags & SC_OP_WAIT_FOR_CAB) { + /* + * This can happen if a broadcast frame is dropped or the AP + * fails to send a frame indicating that all CAB frames have + * been delivered. + */ + DPRINTF(sc, ATH_DBG_PS, "PS wait for CAB frames timed out\n"); + } + + /* No more broadcast/multicast frames to be received at this point. */ + ath_rx_ps_back_to_sleep(sc); +} + +static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr; + + hdr = (struct ieee80211_hdr *)skb->data; + + /* Process Beacon and CAB receive in PS state */ + if ((sc->sc_flags & SC_OP_WAIT_FOR_BEACON) && + ieee80211_is_beacon(hdr->frame_control)) + ath_rx_ps_beacon(sc, skb); + else if ((sc->sc_flags & SC_OP_WAIT_FOR_CAB) && + (ieee80211_is_data(hdr->frame_control) || + ieee80211_is_action(hdr->frame_control)) && + is_multicast_ether_addr(hdr->addr1) && + !ieee80211_has_moredata(hdr->frame_control)) { + DPRINTF(sc, ATH_DBG_PS, "All PS CAB frames received, back to " + "sleep\n"); + /* + * No more broadcast/multicast frames to be received at this + * point. + */ + ath_rx_ps_back_to_sleep(sc); + } else if ((sc->sc_flags & SC_OP_WAIT_FOR_PSPOLL_DATA) && + !is_multicast_ether_addr(hdr->addr1) && + !ieee80211_has_morefrags(hdr->frame_control)) { + sc->sc_flags &= ~SC_OP_WAIT_FOR_PSPOLL_DATA; + DPRINTF(sc, ATH_DBG_PS, "Going back to sleep after having " + "received PS-Poll data (0x%x)\n", + sc->sc_flags & (SC_OP_WAIT_FOR_BEACON | + SC_OP_WAIT_FOR_CAB | + SC_OP_WAIT_FOR_PSPOLL_DATA | + SC_OP_WAIT_FOR_TX_ACK)); + } +} + +static void ath_rx_send_to_mac80211(struct ath_softc *sc, struct sk_buff *skb, + struct ieee80211_rx_status *rx_status) +{ + struct ieee80211_hdr *hdr; + + hdr = (struct ieee80211_hdr *)skb->data; + + /* Send the frame to mac80211 */ + if (is_multicast_ether_addr(hdr->addr1)) { + int i; + /* + * Deliver broadcast/multicast frames to all suitable + * virtual wiphys. + */ + /* TODO: filter based on channel configuration */ + for (i = 0; i < sc->num_sec_wiphy; i++) { + struct ath_wiphy *aphy = sc->sec_wiphy[i]; + struct sk_buff *nskb; + if (aphy == NULL) + continue; + nskb = skb_copy(skb, GFP_ATOMIC); + if (nskb) + __ieee80211_rx(aphy->hw, nskb, rx_status); + } + __ieee80211_rx(sc->hw, skb, rx_status); + } else { + /* Deliver unicast frames based on receiver address */ + __ieee80211_rx(ath_get_virt_hw(sc, hdr), skb, rx_status); + } +} + int ath_rx_tasklet(struct ath_softc *sc, int flush) { #define PA2DESC(_sc, _pa) \ @@ -627,7 +778,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error) { rx_status.flag |= RX_FLAG_DECRYPTED; - } else if ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_PROTECTED) + } else if (ieee80211_has_protected(fc) && !decrypt_error && skb->len >= hdrlen + 4) { keyix = skb->data[hdrlen + 3] >> 6; @@ -636,36 +787,11 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) } if (ah->sw_mgmt_crypto && (rx_status.flag & RX_FLAG_DECRYPTED) && - ieee80211_is_mgmt(hdr->frame_control)) { + ieee80211_is_mgmt(fc)) { /* Use software decrypt for management frames. */ rx_status.flag &= ~RX_FLAG_DECRYPTED; } - /* Send the frame to mac80211 */ - if (hdr->addr1[5] & 0x01) { - int i; - /* - * Deliver broadcast/multicast frames to all suitable - * virtual wiphys. - */ - /* TODO: filter based on channel configuration */ - for (i = 0; i < sc->num_sec_wiphy; i++) { - struct ath_wiphy *aphy = sc->sec_wiphy[i]; - struct sk_buff *nskb; - if (aphy == NULL) - continue; - nskb = skb_copy(skb, GFP_ATOMIC); - if (nskb) - __ieee80211_rx(aphy->hw, nskb, - &rx_status); - } - __ieee80211_rx(sc->hw, skb, &rx_status); - } else { - /* Deliver unicast frames based on receiver address */ - __ieee80211_rx(ath_get_virt_hw(sc, hdr), skb, - &rx_status); - } - /* We will now give hardware our shiny new allocated skb */ bf->bf_mpdu = requeue_skb; bf->bf_buf_addr = dma_map_single(sc->dev, requeue_skb->data, @@ -675,8 +801,9 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) bf->bf_buf_addr))) { dev_kfree_skb_any(requeue_skb); bf->bf_mpdu = NULL; - DPRINTF(sc, ATH_DBG_CONFIG, + DPRINTF(sc, ATH_DBG_FATAL, "dma_mapping_error() on RX\n"); + ath_rx_send_to_mac80211(sc, skb, &rx_status); break; } bf->bf_dmacontext = bf->bf_buf_addr; @@ -692,11 +819,13 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) sc->rx.rxotherant = 0; } - if (ieee80211_is_beacon(fc) && - (sc->sc_flags & SC_OP_WAIT_FOR_BEACON)) { - sc->sc_flags &= ~SC_OP_WAIT_FOR_BEACON; - ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP); - } + if (unlikely(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON | + SC_OP_WAIT_FOR_CAB | + SC_OP_WAIT_FOR_PSPOLL_DATA))) + ath_rx_ps(sc, skb); + + ath_rx_send_to_mac80211(sc, skb, &rx_status); + requeue: list_move_tail(&bf->list, &sc->rx.rxbuf); ath_rx_buf_link(sc, bf); diff --git a/drivers/net/wireless/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h similarity index 100% rename from drivers/net/wireless/ath9k/reg.h rename to drivers/net/wireless/ath/ath9k/reg.h diff --git a/drivers/net/wireless/ath9k/virtual.c b/drivers/net/wireless/ath/ath9k/virtual.c similarity index 100% rename from drivers/net/wireless/ath9k/virtual.c rename to drivers/net/wireless/ath/ath9k/virtual.c diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c similarity index 97% rename from drivers/net/wireless/ath9k/xmit.c rename to drivers/net/wireless/ath/ath9k/xmit.c index 689bdbf78808..b61a071788a5 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -283,7 +283,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0; bool rc_update = true; - skb = (struct sk_buff *)bf->bf_mpdu; + skb = bf->bf_mpdu; hdr = (struct ieee80211_hdr *)skb->data; rcu_read_lock(); @@ -380,8 +380,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, ath_tx_complete_buf(sc, bf, &bf_head, !txfail, sendbar); } else { /* retry the un-acked ones */ - if (bf->bf_next == NULL && - bf_last->bf_status & ATH_BUFSTATUS_STALE) { + if (bf->bf_next == NULL && bf_last->bf_stale) { struct ath_buf *tbf; tbf = ath_clone_txbuf(sc, bf_last); @@ -435,7 +434,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf, struct ath_atx_tid *tid) { - struct ath_rate_table *rate_table = sc->cur_rate_table; + const struct ath_rate_table *rate_table = sc->cur_rate_table; struct sk_buff *skb; struct ieee80211_tx_info *tx_info; struct ieee80211_tx_rate *rates; @@ -444,7 +443,7 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf, u16 aggr_limit, legacy = 0, maxampdu; int i; - skb = (struct sk_buff *)bf->bf_mpdu; + skb = bf->bf_mpdu; tx_info = IEEE80211_SKB_CB(skb); rates = tx_info->control.rates; tx_info_priv = (struct ath_tx_info_priv *)tx_info->rate_driver_data[0]; @@ -498,7 +497,7 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf, static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid, struct ath_buf *bf, u16 frmlen) { - struct ath_rate_table *rt = sc->cur_rate_table; + const struct ath_rate_table *rt = sc->cur_rate_table; struct sk_buff *skb = bf->bf_mpdu; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); u32 nsymbits, nsymbols, mpdudensity; @@ -712,6 +711,7 @@ int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) return 0; if (!(txtid->state & AGGR_ADDBA_COMPLETE)) { + txtid->state &= ~AGGR_ADDBA_PROGRESS; txtid->addba_exchangeattempts = 0; return 0; } @@ -972,7 +972,7 @@ int ath_cabq_update(struct ath_softc *sc) else if (sc->config.cabqReadytime > ATH9K_READY_TIME_HI_BOUND) sc->config.cabqReadytime = ATH9K_READY_TIME_HI_BOUND; - qi.tqi_readyTime = (sc->hw->conf.beacon_int * + qi.tqi_readyTime = (sc->beacon_interval * sc->config.cabqReadytime) / 100; ath_txq_update(sc, qnum, &qi); @@ -1004,7 +1004,7 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx) bf = list_first_entry(&txq->axq_q, struct ath_buf, list); - if (bf->bf_status & ATH_BUFSTATUS_STALE) { + if (bf->bf_stale) { list_del(&bf->list); spin_unlock_bh(&txq->axq_lock); @@ -1071,7 +1071,7 @@ void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx) r = ath9k_hw_reset(ah, sc->sc_ah->curchan, true); if (r) DPRINTF(sc, ATH_DBG_FATAL, - "Unable to reset hardware; reset status %u\n", + "Unable to reset hardware; reset status %d\n", r); spin_unlock_bh(&sc->sc_resetlock); } @@ -1408,7 +1408,7 @@ static int setup_tx_flags(struct ath_softc *sc, struct sk_buff *skb, static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf, int width, int half_gi, bool shortPreamble) { - struct ath_rate_table *rate_table = sc->cur_rate_table; + const struct ath_rate_table *rate_table = sc->cur_rate_table; u32 nbits, nsymbits, duration, nsymbols; u8 rc; int streams, pktlen; @@ -1440,7 +1440,7 @@ static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf, static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) { - struct ath_rate_table *rt = sc->cur_rate_table; + const struct ath_rate_table *rt = sc->cur_rate_table; struct ath9k_11n_rate_series series[4]; struct sk_buff *skb; struct ieee80211_tx_info *tx_info; @@ -1452,7 +1452,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4); - skb = (struct sk_buff *)bf->bf_mpdu; + skb = bf->bf_mpdu; tx_info = IEEE80211_SKB_CB(skb); rates = tx_info->control.rates; hdr = (struct ieee80211_hdr *)skb->data; @@ -1573,8 +1573,9 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf, skb->len, DMA_TO_DEVICE); if (unlikely(dma_mapping_error(sc->dev, bf->bf_dmacontext))) { bf->bf_mpdu = NULL; - DPRINTF(sc, ATH_DBG_CONFIG, - "dma_mapping_error() on TX\n"); + kfree(tx_info_priv); + tx_info->rate_driver_data[0] = NULL; + DPRINTF(sc, ATH_DBG_FATAL, "dma_mapping_error() on TX\n"); return -ENOMEM; } @@ -1586,7 +1587,7 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf, static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, struct ath_tx_control *txctl) { - struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu; + struct sk_buff *skb = bf->bf_mpdu; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ath_node *an = NULL; @@ -1790,6 +1791,16 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, skb_pull(skb, padsize); } + if (sc->sc_flags & SC_OP_WAIT_FOR_TX_ACK) { + sc->sc_flags &= ~SC_OP_WAIT_FOR_TX_ACK; + DPRINTF(sc, ATH_DBG_PS, "Going back to sleep after having " + "received TX status (0x%x)\n", + sc->sc_flags & (SC_OP_WAIT_FOR_BEACON | + SC_OP_WAIT_FOR_CAB | + SC_OP_WAIT_FOR_PSPOLL_DATA | + SC_OP_WAIT_FOR_TX_ACK)); + } + if (frame_type == ATH9K_NOT_INTERNAL) ieee80211_tx_status(hw, skb); else @@ -1860,7 +1871,7 @@ static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf, static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds, int nbad, int txok, bool update_rc) { - struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu; + struct sk_buff *skb = bf->bf_mpdu; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info); @@ -1941,7 +1952,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) * it with the STALE flag. */ bf_held = NULL; - if (bf->bf_status & ATH_BUFSTATUS_STALE) { + if (bf->bf_stale) { bf_held = bf; if (list_is_last(&bf_held->list, &txq->axq_q)) { txq->axq_link = NULL; @@ -1982,7 +1993,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) * however leave the last descriptor back as the holding * descriptor for hw. */ - lastbf->bf_status |= ATH_BUFSTATUS_STALE; + lastbf->bf_stale = true; INIT_LIST_HEAD(&bf_head); if (!list_is_singular(&lastbf->list)) list_cut_position(&bf_head, @@ -2048,44 +2059,38 @@ int ath_tx_init(struct ath_softc *sc, int nbufs) { int error = 0; - do { - spin_lock_init(&sc->tx.txbuflock); + spin_lock_init(&sc->tx.txbuflock); - error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf, - "tx", nbufs, 1); - if (error != 0) { - DPRINTF(sc, ATH_DBG_FATAL, - "Failed to allocate tx descriptors: %d\n", - error); - break; - } + error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf, + "tx", nbufs, 1); + if (error != 0) { + DPRINTF(sc, ATH_DBG_FATAL, + "Failed to allocate tx descriptors: %d\n", error); + goto err; + } - error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf, - "beacon", ATH_BCBUF, 1); - if (error != 0) { - DPRINTF(sc, ATH_DBG_FATAL, - "Failed to allocate beacon descriptors: %d\n", - error); - break; - } - - } while (0); + error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf, + "beacon", ATH_BCBUF, 1); + if (error != 0) { + DPRINTF(sc, ATH_DBG_FATAL, + "Failed to allocate beacon descriptors: %d\n", error); + goto err; + } +err: if (error != 0) ath_tx_cleanup(sc); return error; } -int ath_tx_cleanup(struct ath_softc *sc) +void ath_tx_cleanup(struct ath_softc *sc) { if (sc->beacon.bdma.dd_desc_len != 0) ath_descdma_cleanup(sc, &sc->beacon.bdma, &sc->beacon.bbuf); if (sc->tx.txdma.dd_desc_len != 0) ath_descdma_cleanup(sc, &sc->tx.txdma, &sc->tx.txbuf); - - return 0; } void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an) diff --git a/drivers/net/wireless/ath/main.c b/drivers/net/wireless/ath/main.c new file mode 100644 index 000000000000..9949b11cb151 --- /dev/null +++ b/drivers/net/wireless/ath/main.c @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2009 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +MODULE_AUTHOR("Atheros Communications"); +MODULE_DESCRIPTION("Shared library for Atheros wireless LAN cards."); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/ath9k/regd.c b/drivers/net/wireless/ath/regd.c similarity index 61% rename from drivers/net/wireless/ath9k/regd.c rename to drivers/net/wireless/ath/regd.c index 4ca625102291..eef370bd1211 100644 --- a/drivers/net/wireless/ath9k/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -16,7 +16,9 @@ #include #include -#include "ath9k.h" +#include +#include +#include "regd.h" #include "regd_common.h" /* @@ -55,7 +57,7 @@ /* Can be used for: * 0x60, 0x61, 0x62 */ -static const struct ieee80211_regdomain ath9k_world_regdom_60_61_62 = { +static const struct ieee80211_regdomain ath_world_regdom_60_61_62 = { .n_reg_rules = 5, .alpha2 = "99", .reg_rules = { @@ -65,7 +67,7 @@ static const struct ieee80211_regdomain ath9k_world_regdom_60_61_62 = { }; /* Can be used by 0x63 and 0x65 */ -static const struct ieee80211_regdomain ath9k_world_regdom_63_65 = { +static const struct ieee80211_regdomain ath_world_regdom_63_65 = { .n_reg_rules = 4, .alpha2 = "99", .reg_rules = { @@ -76,7 +78,7 @@ static const struct ieee80211_regdomain ath9k_world_regdom_63_65 = { }; /* Can be used by 0x64 only */ -static const struct ieee80211_regdomain ath9k_world_regdom_64 = { +static const struct ieee80211_regdomain ath_world_regdom_64 = { .n_reg_rules = 3, .alpha2 = "99", .reg_rules = { @@ -86,7 +88,7 @@ static const struct ieee80211_regdomain ath9k_world_regdom_64 = { }; /* Can be used by 0x66 and 0x69 */ -static const struct ieee80211_regdomain ath9k_world_regdom_66_69 = { +static const struct ieee80211_regdomain ath_world_regdom_66_69 = { .n_reg_rules = 3, .alpha2 = "99", .reg_rules = { @@ -96,7 +98,7 @@ static const struct ieee80211_regdomain ath9k_world_regdom_66_69 = { }; /* Can be used by 0x67, 0x6A and 0x68 */ -static const struct ieee80211_regdomain ath9k_world_regdom_67_68_6A = { +static const struct ieee80211_regdomain ath_world_regdom_67_68_6A = { .n_reg_rules = 4, .alpha2 = "99", .reg_rules = { @@ -112,49 +114,51 @@ static inline bool is_wwr_sku(u16 regd) (regd == WORLD); } -static u16 ath9k_regd_get_eepromRD(struct ath_hw *ah) +static u16 ath_regd_get_eepromRD(struct ath_regulatory *reg) { - return ah->regulatory.current_rd & ~WORLDWIDE_ROAMING_FLAG; + return reg->current_rd & ~WORLDWIDE_ROAMING_FLAG; } -bool ath9k_is_world_regd(struct ath_hw *ah) +bool ath_is_world_regd(struct ath_regulatory *reg) { - return is_wwr_sku(ath9k_regd_get_eepromRD(ah)); + return is_wwr_sku(ath_regd_get_eepromRD(reg)); } +EXPORT_SYMBOL(ath_is_world_regd); -const struct ieee80211_regdomain *ath9k_default_world_regdomain(void) +static const struct ieee80211_regdomain *ath_default_world_regdomain(void) { /* this is the most restrictive */ - return &ath9k_world_regdom_64; + return &ath_world_regdom_64; } -const struct ieee80211_regdomain *ath9k_world_regdomain(struct ath_hw *ah) +static const struct +ieee80211_regdomain *ath_world_regdomain(struct ath_regulatory *reg) { - switch (ah->regulatory.regpair->regDmnEnum) { + switch (reg->regpair->regDmnEnum) { case 0x60: case 0x61: case 0x62: - return &ath9k_world_regdom_60_61_62; + return &ath_world_regdom_60_61_62; case 0x63: case 0x65: - return &ath9k_world_regdom_63_65; + return &ath_world_regdom_63_65; case 0x64: - return &ath9k_world_regdom_64; + return &ath_world_regdom_64; case 0x66: case 0x69: - return &ath9k_world_regdom_66_69; + return &ath_world_regdom_66_69; case 0x67: case 0x68: case 0x6A: - return &ath9k_world_regdom_67_68_6A; + return &ath_world_regdom_67_68_6A; default: WARN_ON(1); - return ath9k_default_world_regdomain(); + return ath_default_world_regdomain(); } } /* Frequency is one where radar detection is required */ -static bool ath9k_is_radar_freq(u16 center_freq) +static bool ath_is_radar_freq(u16 center_freq) { return (center_freq >= 5260 && center_freq <= 5700); } @@ -168,9 +172,9 @@ static bool ath9k_is_radar_freq(u16 center_freq) * received a beacon on a channel we can enable active scan and * adhoc (or beaconing). */ -static void ath9k_reg_apply_beaconing_flags( - struct wiphy *wiphy, - enum nl80211_reg_initiator initiator) +static void +ath_reg_apply_beaconing_flags(struct wiphy *wiphy, + enum nl80211_reg_initiator initiator) { enum ieee80211_band band; struct ieee80211_supported_band *sband; @@ -191,13 +195,15 @@ static void ath9k_reg_apply_beaconing_flags( ch = &sband->channels[i]; - if (ath9k_is_radar_freq(ch->center_freq) || + if (ath_is_radar_freq(ch->center_freq) || (ch->flags & IEEE80211_CHAN_RADAR)) continue; if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) { - r = freq_reg_info(wiphy, ch->center_freq, - &bandwidth, ®_rule); + r = freq_reg_info(wiphy, + ch->center_freq, + bandwidth, + ®_rule); if (r) continue; /* @@ -227,9 +233,9 @@ static void ath9k_reg_apply_beaconing_flags( } /* Allows active scan scan on Ch 12 and 13 */ -static void ath9k_reg_apply_active_scan_flags( - struct wiphy *wiphy, - enum nl80211_reg_initiator initiator) +static void +ath_reg_apply_active_scan_flags(struct wiphy *wiphy, + enum nl80211_reg_initiator initiator) { struct ieee80211_supported_band *sband; struct ieee80211_channel *ch; @@ -261,7 +267,7 @@ static void ath9k_reg_apply_active_scan_flags( */ ch = &sband->channels[11]; /* CH 12 */ - r = freq_reg_info(wiphy, ch->center_freq, &bandwidth, ®_rule); + r = freq_reg_info(wiphy, ch->center_freq, bandwidth, ®_rule); if (!r) { if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN)) if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) @@ -269,7 +275,7 @@ static void ath9k_reg_apply_active_scan_flags( } ch = &sband->channels[12]; /* CH 13 */ - r = freq_reg_info(wiphy, ch->center_freq, &bandwidth, ®_rule); + r = freq_reg_info(wiphy, ch->center_freq, bandwidth, ®_rule); if (!r) { if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN)) if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) @@ -278,7 +284,7 @@ static void ath9k_reg_apply_active_scan_flags( } /* Always apply Radar/DFS rules on freq range 5260 MHz - 5700 MHz */ -void ath9k_reg_apply_radar_flags(struct wiphy *wiphy) +static void ath_reg_apply_radar_flags(struct wiphy *wiphy) { struct ieee80211_supported_band *sband; struct ieee80211_channel *ch; @@ -291,7 +297,7 @@ void ath9k_reg_apply_radar_flags(struct wiphy *wiphy) for (i = 0; i < sband->n_channels; i++) { ch = &sband->channels[i]; - if (!ath9k_is_radar_freq(ch->center_freq)) + if (!ath_is_radar_freq(ch->center_freq)) continue; /* We always enable radar detection/DFS on this * frequency range. Additionally we also apply on @@ -310,37 +316,31 @@ void ath9k_reg_apply_radar_flags(struct wiphy *wiphy) } } -void ath9k_reg_apply_world_flags(struct wiphy *wiphy, - enum nl80211_reg_initiator initiator) +static void ath_reg_apply_world_flags(struct wiphy *wiphy, + enum nl80211_reg_initiator initiator, + struct ath_regulatory *reg) { - struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; - struct ath_hw *ah = sc->sc_ah; - - switch (ah->regulatory.regpair->regDmnEnum) { + switch (reg->regpair->regDmnEnum) { case 0x60: case 0x63: case 0x66: case 0x67: - ath9k_reg_apply_beaconing_flags(wiphy, initiator); + ath_reg_apply_beaconing_flags(wiphy, initiator); break; case 0x68: - ath9k_reg_apply_beaconing_flags(wiphy, initiator); - ath9k_reg_apply_active_scan_flags(wiphy, initiator); + ath_reg_apply_beaconing_flags(wiphy, initiator); + ath_reg_apply_active_scan_flags(wiphy, initiator); break; } return; } -int ath9k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) +int ath_reg_notifier_apply(struct wiphy *wiphy, + struct regulatory_request *request, + struct ath_regulatory *reg) { - struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); - struct ath_wiphy *aphy = hw->priv; - struct ath_softc *sc = aphy->sc; - /* We always apply this */ - ath9k_reg_apply_radar_flags(wiphy); + ath_reg_apply_radar_flags(wiphy); switch (request->initiator) { case NL80211_REGDOM_SET_BY_DRIVER: @@ -348,39 +348,47 @@ int ath9k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) case NL80211_REGDOM_SET_BY_USER: break; case NL80211_REGDOM_SET_BY_COUNTRY_IE: - if (ath9k_is_world_regd(sc->sc_ah)) - ath9k_reg_apply_world_flags(wiphy, request->initiator); + if (ath_is_world_regd(reg)) + ath_reg_apply_world_flags(wiphy, request->initiator, + reg); break; } return 0; } +EXPORT_SYMBOL(ath_reg_notifier_apply); -bool ath9k_regd_is_eeprom_valid(struct ath_hw *ah) +static bool ath_regd_is_eeprom_valid(struct ath_regulatory *reg) { - u16 rd = ath9k_regd_get_eepromRD(ah); + u16 rd = ath_regd_get_eepromRD(reg); int i; if (rd & COUNTRY_ERD_FLAG) { /* EEPROM value is a country code */ u16 cc = rd & ~COUNTRY_ERD_FLAG; + printk(KERN_DEBUG + "ath: EEPROM indicates we should expect " + "a country code\n"); for (i = 0; i < ARRAY_SIZE(allCountries); i++) if (allCountries[i].countryCode == cc) return true; } else { /* EEPROM value is a regpair value */ + if (rd != CTRY_DEFAULT) + printk(KERN_DEBUG "ath: EEPROM indicates we " + "should expect a direct regpair map\n"); for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) if (regDomainPairs[i].regDmnEnum == rd) return true; } - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "invalid regulatory domain/country code 0x%x\n", rd); + printk(KERN_DEBUG + "ath: invalid regulatory domain/country code 0x%x\n", rd); return false; } /* EEPROM country code to regpair mapping */ static struct country_code_to_enum_rd* -ath9k_regd_find_country(u16 countryCode) +ath_regd_find_country(u16 countryCode) { int i; @@ -393,7 +401,7 @@ ath9k_regd_find_country(u16 countryCode) /* EEPROM rd code to regpair mapping */ static struct country_code_to_enum_rd* -ath9k_regd_find_country_by_rd(int regdmn) +ath_regd_find_country_by_rd(int regdmn) { int i; @@ -405,13 +413,13 @@ ath9k_regd_find_country_by_rd(int regdmn) } /* Returns the map of the EEPROM set RD to a country code */ -static u16 ath9k_regd_get_default_country(u16 rd) +static u16 ath_regd_get_default_country(u16 rd) { if (rd & COUNTRY_ERD_FLAG) { struct country_code_to_enum_rd *country = NULL; u16 cc = rd & ~COUNTRY_ERD_FLAG; - country = ath9k_regd_find_country(cc); + country = ath_regd_find_country(cc); if (country != NULL) return cc; } @@ -420,7 +428,7 @@ static u16 ath9k_regd_get_default_country(u16 rd) } static struct reg_dmn_pair_mapping* -ath9k_get_regpair(int regdmn) +ath_get_regpair(int regdmn) { int i; @@ -433,87 +441,135 @@ ath9k_get_regpair(int regdmn) return NULL; } -int ath9k_regd_init(struct ath_hw *ah) +static int +ath_regd_init_wiphy(struct ath_regulatory *reg, + struct wiphy *wiphy, + int (*reg_notifier)(struct wiphy *wiphy, + struct regulatory_request *request)) +{ + const struct ieee80211_regdomain *regd; + + wiphy->reg_notifier = reg_notifier; + wiphy->strict_regulatory = true; + + if (ath_is_world_regd(reg)) { + /* + * Anything applied here (prior to wiphy registration) gets + * saved on the wiphy orig_* parameters + */ + regd = ath_world_regdomain(reg); + wiphy->custom_regulatory = true; + wiphy->strict_regulatory = false; + } else { + /* + * This gets applied in the case of the absense of CRDA, + * it's our own custom world regulatory domain, similar to + * cfg80211's but we enable passive scanning. + */ + regd = ath_default_world_regdomain(); + } + wiphy_apply_custom_regulatory(wiphy, regd); + ath_reg_apply_radar_flags(wiphy); + ath_reg_apply_world_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER, reg); + return 0; +} + +int +ath_regd_init(struct ath_regulatory *reg, + struct wiphy *wiphy, + int (*reg_notifier)(struct wiphy *wiphy, + struct regulatory_request *request)) { struct country_code_to_enum_rd *country = NULL; u16 regdmn; - if (!ath9k_regd_is_eeprom_valid(ah)) { - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "Invalid EEPROM contents\n"); + if (!reg) + return -EINVAL; + + printk(KERN_DEBUG "ath: EEPROM regdomain: 0x%0x\n", reg->current_rd); + + if (!ath_regd_is_eeprom_valid(reg)) { + printk(KERN_ERR "ath: Invalid EEPROM contents\n"); return -EINVAL; } - regdmn = ath9k_regd_get_eepromRD(ah); - ah->regulatory.country_code = ath9k_regd_get_default_country(regdmn); + regdmn = ath_regd_get_eepromRD(reg); + reg->country_code = ath_regd_get_default_country(regdmn); - if (ah->regulatory.country_code == CTRY_DEFAULT && - regdmn == CTRY_DEFAULT) - ah->regulatory.country_code = CTRY_UNITED_STATES; - - if (ah->regulatory.country_code == CTRY_DEFAULT) { - country = NULL; - } else { - country = ath9k_regd_find_country(ah->regulatory.country_code); - if (country == NULL) { - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "Country is NULL!!!!, cc= %d\n", - ah->regulatory.country_code); - return -EINVAL; - } else - regdmn = country->regDmnEnum; + if (reg->country_code == CTRY_DEFAULT && + regdmn == CTRY_DEFAULT) { + printk(KERN_DEBUG "ath: EEPROM indicates default " + "country code should be used\n"); + reg->country_code = CTRY_UNITED_STATES; } - ah->regulatory.regpair = ath9k_get_regpair(regdmn); + if (reg->country_code == CTRY_DEFAULT) { + country = NULL; + } else { + printk(KERN_DEBUG "ath: doing EEPROM country->regdmn " + "map search\n"); + country = ath_regd_find_country(reg->country_code); + if (country == NULL) { + printk(KERN_DEBUG + "ath: no valid country maps found for " + "country code: 0x%0x\n", + reg->country_code); + return -EINVAL; + } else { + regdmn = country->regDmnEnum; + printk(KERN_DEBUG "ath: country maps to " + "regdmn code: 0x%0x\n", + regdmn); + } + } - if (!ah->regulatory.regpair) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + reg->regpair = ath_get_regpair(regdmn); + + if (!reg->regpair) { + printk(KERN_DEBUG "ath: " "No regulatory domain pair found, cannot continue\n"); return -EINVAL; } if (!country) - country = ath9k_regd_find_country_by_rd(regdmn); + country = ath_regd_find_country_by_rd(regdmn); if (country) { - ah->regulatory.alpha2[0] = country->isoName[0]; - ah->regulatory.alpha2[1] = country->isoName[1]; + reg->alpha2[0] = country->isoName[0]; + reg->alpha2[1] = country->isoName[1]; } else { - ah->regulatory.alpha2[0] = '0'; - ah->regulatory.alpha2[1] = '0'; + reg->alpha2[0] = '0'; + reg->alpha2[1] = '0'; } - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "Country alpha2 being used: %c%c\n" - "Regulatory.Regpair detected: 0x%0x\n", - ah->regulatory.alpha2[0], ah->regulatory.alpha2[1], - ah->regulatory.regpair->regDmnEnum); + printk(KERN_DEBUG "ath: Country alpha2 being used: %c%c\n", + reg->alpha2[0], reg->alpha2[1]); + printk(KERN_DEBUG "ath: Regpair used: 0x%0x\n", + reg->regpair->regDmnEnum); + ath_regd_init_wiphy(reg, wiphy, reg_notifier); return 0; } +EXPORT_SYMBOL(ath_regd_init); -u32 ath9k_regd_get_ctl(struct ath_hw *ah, struct ath9k_channel *chan) +u32 ath_regd_get_band_ctl(struct ath_regulatory *reg, + enum ieee80211_band band) { - u32 ctl = NO_CTL; - - if (!ah->regulatory.regpair || - (ah->regulatory.country_code == CTRY_DEFAULT && - is_wwr_sku(ath9k_regd_get_eepromRD(ah)))) { - if (IS_CHAN_B(chan)) - ctl = SD_NO_CTL | CTL_11B; - else if (IS_CHAN_G(chan)) - ctl = SD_NO_CTL | CTL_11G; - else - ctl = SD_NO_CTL | CTL_11A; - return ctl; + if (!reg->regpair || + (reg->country_code == CTRY_DEFAULT && + is_wwr_sku(ath_regd_get_eepromRD(reg)))) { + return SD_NO_CTL; } - if (IS_CHAN_B(chan)) - ctl = ah->regulatory.regpair->reg_2ghz_ctl | CTL_11B; - else if (IS_CHAN_G(chan)) - ctl = ah->regulatory.regpair->reg_2ghz_ctl | CTL_11G; - else - ctl = ah->regulatory.regpair->reg_5ghz_ctl | CTL_11A; + switch (band) { + case IEEE80211_BAND_2GHZ: + return reg->regpair->reg_2ghz_ctl; + case IEEE80211_BAND_5GHZ: + return reg->regpair->reg_5ghz_ctl; + default: + return NO_CTL; + } - return ctl; + return NO_CTL; } +EXPORT_SYMBOL(ath_regd_get_band_ctl); diff --git a/drivers/net/wireless/ath9k/regd.h b/drivers/net/wireless/ath/regd.h similarity index 85% rename from drivers/net/wireless/ath9k/regd.h rename to drivers/net/wireless/ath/regd.h index 9f5fbd4eea7a..07291ccb23f2 100644 --- a/drivers/net/wireless/ath9k/regd.h +++ b/drivers/net/wireless/ath/regd.h @@ -17,6 +17,25 @@ #ifndef REGD_H #define REGD_H +#include + +#include + +#define NO_CTL 0xff +#define SD_NO_CTL 0xE0 +#define NO_CTL 0xff +#define CTL_MODE_M 7 +#define CTL_11A 0 +#define CTL_11B 1 +#define CTL_11G 2 +#define CTL_2GHT20 5 +#define CTL_5GHT20 6 +#define CTL_2GHT40 7 +#define CTL_5GHT40 8 + +#define CTRY_DEBUG 0x1ff +#define CTRY_DEFAULT 0 + #define COUNTRY_ERD_FLAG 0x8000 #define WORLDWIDE_ROAMING_FLAG 0x4000 @@ -40,7 +59,7 @@ struct country_code_to_enum_rd { const char *isoName; }; -struct ath9k_regulatory { +struct ath_regulatory { char alpha2[2]; u16 country_code; u16 max_power_level; @@ -233,15 +252,14 @@ enum CountryCode { CTRY_BELGIUM2 = 5002 }; -bool ath9k_is_world_regd(struct ath_hw *ah); -const struct ieee80211_regdomain *ath9k_world_regdomain(struct ath_hw *ah); -const struct ieee80211_regdomain *ath9k_default_world_regdomain(void); -void ath9k_reg_apply_world_flags(struct wiphy *wiphy, - enum nl80211_reg_initiator initiator); -void ath9k_reg_apply_radar_flags(struct wiphy *wiphy); -int ath9k_regd_init(struct ath_hw *ah); -bool ath9k_regd_is_eeprom_valid(struct ath_hw *ah); -u32 ath9k_regd_get_ctl(struct ath_hw *ah, struct ath9k_channel *chan); -int ath9k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request); +bool ath_is_world_regd(struct ath_regulatory *reg); +int ath_regd_init(struct ath_regulatory *reg, struct wiphy *wiphy, + int (*reg_notifier)(struct wiphy *wiphy, + struct regulatory_request *request)); +u32 ath_regd_get_band_ctl(struct ath_regulatory *reg, + enum ieee80211_band band); +int ath_reg_notifier_apply(struct wiphy *wiphy, + struct regulatory_request *request, + struct ath_regulatory *reg); #endif diff --git a/drivers/net/wireless/ath9k/regd_common.h b/drivers/net/wireless/ath/regd_common.h similarity index 100% rename from drivers/net/wireless/ath9k/regd_common.h rename to drivers/net/wireless/ath/regd_common.h diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index 27eef8fb7107..291a94bd46fd 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c @@ -818,7 +818,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&priv->irqlock, flags); spin_unlock_bh(&priv->timerlock); netif_stop_queue(dev); - return 1; + return NETDEV_TX_BUSY; } frame_ctl = IEEE80211_FTYPE_DATA; diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c index 77406245dc7b..ddaa859c3491 100644 --- a/drivers/net/wireless/atmel_cs.c +++ b/drivers/net/wireless/atmel_cs.c @@ -279,7 +279,7 @@ static int atmel_config(struct pcmcia_device *link) struct pcmcia_device_id *did; dev = link->priv; - did = handle_to_dev(link).driver_data; + did = dev_get_drvdata(&handle_to_dev(link)); DEBUG(0, "atmel_config(0x%p)\n", link); diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig index aab71a70ba78..67f564e37225 100644 --- a/drivers/net/wireless/b43/Kconfig +++ b/drivers/net/wireless/b43/Kconfig @@ -3,7 +3,6 @@ config B43 depends on SSB_POSSIBLE && MAC80211 && WLAN_80211 && HAS_DMA select SSB select FW_LOADER - select HW_RANDOM ---help--- b43 is a driver for the Broadcom 43xx series wireless devices. @@ -99,11 +98,11 @@ config B43_LEDS depends on B43 && MAC80211_LEDS && (LEDS_CLASS = y || LEDS_CLASS = B43) default y -# This config option automatically enables b43 RFKILL support, -# if it's possible. -config B43_RFKILL +# This config option automatically enables b43 HW-RNG support, +# if the HW-RNG core is enabled. +config B43_HWRNG bool - depends on B43 && (RFKILL = y || RFKILL = B43) && RFKILL_INPUT && (INPUT_POLLDEV = y || INPUT_POLLDEV = B43) + depends on B43 && (HW_RANDOM = y || HW_RANDOM = B43) default y config B43_DEBUG diff --git a/drivers/net/wireless/b43/Makefile b/drivers/net/wireless/b43/Makefile index 281ef8310350..da379f4b0c3a 100644 --- a/drivers/net/wireless/b43/Makefile +++ b/drivers/net/wireless/b43/Makefile @@ -13,7 +13,7 @@ b43-y += lo.o b43-y += wa.o b43-y += dma.o b43-$(CONFIG_B43_PIO) += pio.o -b43-$(CONFIG_B43_RFKILL) += rfkill.o +b43-y += rfkill.o b43-$(CONFIG_B43_LEDS) += leds.o b43-$(CONFIG_B43_PCMCIA) += pcmcia.o b43-$(CONFIG_B43_DEBUG) += debugfs.o diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index beaf18d6e8a7..f580c2812d91 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -163,6 +163,7 @@ enum { #define B43_SHM_SH_WLCOREREV 0x0016 /* 802.11 core revision */ #define B43_SHM_SH_PCTLWDPOS 0x0008 #define B43_SHM_SH_RXPADOFF 0x0034 /* RX Padding data offset (PIO only) */ +#define B43_SHM_SH_FWCAPA 0x0042 /* Firmware capabilities (Opensource firmware only) */ #define B43_SHM_SH_PHYVER 0x0050 /* PHY version */ #define B43_SHM_SH_PHYTYPE 0x0052 /* PHY type */ #define B43_SHM_SH_ANTSWAP 0x005C /* Antenna swap threshold */ @@ -297,6 +298,10 @@ enum { #define B43_HF_MLADVW 0x001000000000ULL /* N PHY ML ADV workaround (rev >= 13 only) */ #define B43_HF_PR45960W 0x080000000000ULL /* PR 45960 workaround (rev >= 13 only) */ +/* Firmware capabilities field in SHM (Opensource firmware only) */ +#define B43_FWCAPA_HWCRYPTO 0x0001 +#define B43_FWCAPA_QOS 0x0002 + /* MacFilter offsets. */ #define B43_MACFILTER_SELF 0x0000 #define B43_MACFILTER_BSSID 0x0003 @@ -596,6 +601,13 @@ struct b43_wl { /* Pointer to the ieee80211 hardware data structure */ struct ieee80211_hw *hw; + /* The number of queues that were registered with the mac80211 subsystem + * initially. This is a backup copy of hw->queues in case hw->queues has + * to be dynamically lowered at runtime (Firmware does not support QoS). + * hw->queues has to be restored to the original value before unregistering + * from the mac80211 subsystem. */ + u16 mac80211_initially_registered_queues; + struct mutex mutex; spinlock_t irq_lock; /* R/W lock for data transmission. @@ -625,12 +637,11 @@ struct b43_wl { /* Stats about the wireless interface */ struct ieee80211_low_level_stats ieee_stats; +#ifdef CONFIG_B43_HWRNG struct hwrng rng; - u8 rng_initialized; + bool rng_initialized; char rng_name[30 + 1]; - - /* The RF-kill button */ - struct b43_rfkill rfkill; +#endif /* CONFIG_B43_HWRNG */ /* List of all wireless devices on this chip */ struct list_head devlist; @@ -750,6 +761,8 @@ struct b43_wldev { bool dfq_valid; /* Directed frame queue valid (IBSS PS mode, ATIM) */ bool radio_hw_enable; /* saved state of radio hardware enabled state */ bool suspend_in_progress; /* TRUE, if we are in a suspend/resume cycle */ + bool qos_enabled; /* TRUE, if QoS is used. */ + bool hwcrypto_enabled; /* TRUE, if HW crypto acceleration is enabled. */ /* PHY/Radio device. */ struct b43_phy phy; @@ -776,8 +789,8 @@ struct b43_wldev { /* Reason code of the last interrupt. */ u32 irq_reason; u32 dma_reason[6]; - /* saved irq enable/disable state bitfield. */ - u32 irq_savedstate; + /* The currently active generic-interrupt mask. */ + u32 irq_mask; /* Link Quality calculation context. */ struct b43_noise_calculation noisecalc; /* if > 0 MAC is suspended. if == 0 MAC is enabled. */ diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index eae680b53052..7964cc32b258 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -1285,7 +1285,7 @@ static struct b43_dmaring *select_ring_by_priority(struct b43_wldev *dev, { struct b43_dmaring *ring; - if (b43_modparam_qos) { + if (dev->qos_enabled) { /* 0 = highest priority */ switch (queue_prio) { default: diff --git a/drivers/net/wireless/b43/leds.c b/drivers/net/wireless/b43/leds.c index 76f4c7bad8b8..c8b317094c31 100644 --- a/drivers/net/wireless/b43/leds.c +++ b/drivers/net/wireless/b43/leds.c @@ -28,6 +28,7 @@ #include "b43.h" #include "leds.h" +#include "rfkill.h" static void b43_led_turn_on(struct b43_wldev *dev, u8 led_index, @@ -87,7 +88,7 @@ static void b43_led_brightness_set(struct led_classdev *led_dev, } static int b43_register_led(struct b43_wldev *dev, struct b43_led *led, - const char *name, char *default_trigger, + const char *name, const char *default_trigger, u8 led_index, bool activelow) { int err; @@ -164,10 +165,10 @@ static void b43_map_led(struct b43_wldev *dev, snprintf(name, sizeof(name), "b43-%s::radio", wiphy_name(hw->wiphy)); b43_register_led(dev, &dev->led_radio, name, - b43_rfkill_led_name(dev), + ieee80211_get_radio_led_name(hw), led_index, activelow); - /* Sync the RF-kill LED state with the switch state. */ - if (dev->radio_hw_enable) + /* Sync the RF-kill LED state with radio and switch states. */ + if (dev->phy.radio_on && b43_is_hw_radio_enabled(dev)) b43_led_turn_on(dev, led_index, activelow); break; case B43_LED_WEIRD: diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 79b685e300c7..6456afebdba1 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -80,8 +80,8 @@ static int modparam_nohwcrypt; module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444); MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); -int b43_modparam_qos = 1; -module_param_named(qos, b43_modparam_qos, int, 0444); +static int modparam_qos = 1; +module_param_named(qos, modparam_qos, int, 0444); MODULE_PARM_DESC(qos, "Enable QOS support (default on)"); static int modparam_btcoex = 1; @@ -538,6 +538,13 @@ void b43_hf_write(struct b43_wldev *dev, u64 value) b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFHI, hi); } +/* Read the firmware capabilities bitmask (Opensource firmware only) */ +static u16 b43_fwcapa_read(struct b43_wldev *dev) +{ + B43_WARN_ON(!dev->fw.opensource); + return b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_FWCAPA); +} + void b43_tsf_read(struct b43_wldev *dev, u64 *tsf) { u32 low, high; @@ -673,32 +680,6 @@ static void b43_short_slot_timing_disable(struct b43_wldev *dev) b43_set_slot_time(dev, 20); } -/* Enable a Generic IRQ. "mask" is the mask of which IRQs to enable. - * Returns the _previously_ enabled IRQ mask. - */ -static inline u32 b43_interrupt_enable(struct b43_wldev *dev, u32 mask) -{ - u32 old_mask; - - old_mask = b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); - b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, old_mask | mask); - - return old_mask; -} - -/* Disable a Generic IRQ. "mask" is the mask of which IRQs to disable. - * Returns the _previously_ enabled IRQ mask. - */ -static inline u32 b43_interrupt_disable(struct b43_wldev *dev, u32 mask) -{ - u32 old_mask; - - old_mask = b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); - b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, old_mask & ~mask); - - return old_mask; -} - /* Synchronize IRQ top- and bottom-half. * IRQs must be masked before calling this. * This must not be called with the irq_lock held. @@ -1593,7 +1574,7 @@ static void handle_irq_beacon(struct b43_wldev *dev) /* This is the bottom half of the asynchronous beacon update. */ /* Ignore interrupt in the future. */ - dev->irq_savedstate &= ~B43_IRQ_BEACON; + dev->irq_mask &= ~B43_IRQ_BEACON; cmd = b43_read32(dev, B43_MMIO_MACCMD); beacon0_valid = (cmd & B43_MACCMD_BEACON0_VALID); @@ -1602,7 +1583,7 @@ static void handle_irq_beacon(struct b43_wldev *dev) /* Schedule interrupt manually, if busy. */ if (beacon0_valid && beacon1_valid) { b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, B43_IRQ_BEACON); - dev->irq_savedstate |= B43_IRQ_BEACON; + dev->irq_mask |= B43_IRQ_BEACON; return; } @@ -1641,11 +1622,9 @@ static void b43_beacon_update_trigger_work(struct work_struct *work) if (likely(dev && (b43_status(dev) >= B43_STAT_INITIALIZED))) { spin_lock_irq(&wl->irq_lock); /* update beacon right away or defer to irq */ - dev->irq_savedstate = b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); handle_irq_beacon(dev); /* The handler might have updated the IRQ mask. */ - b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, - dev->irq_savedstate); + b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, dev->irq_mask); mmiowb(); spin_unlock_irq(&wl->irq_lock); } @@ -1879,7 +1858,7 @@ static void b43_interrupt_tasklet(struct b43_wldev *dev) if (reason & B43_IRQ_TX_OK) handle_irq_transmit_status(dev); - b43_interrupt_enable(dev, dev->irq_savedstate); + b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, dev->irq_mask); mmiowb(); spin_unlock_irqrestore(&dev->wl->irq_lock, flags); } @@ -1893,7 +1872,9 @@ static void b43_interrupt_ack(struct b43_wldev *dev, u32 reason) b43_write32(dev, B43_MMIO_DMA2_REASON, dev->dma_reason[2]); b43_write32(dev, B43_MMIO_DMA3_REASON, dev->dma_reason[3]); b43_write32(dev, B43_MMIO_DMA4_REASON, dev->dma_reason[4]); +/* Unused ring b43_write32(dev, B43_MMIO_DMA5_REASON, dev->dma_reason[5]); +*/ } /* Interrupt handler top-half */ @@ -1903,18 +1884,19 @@ static irqreturn_t b43_interrupt_handler(int irq, void *dev_id) struct b43_wldev *dev = dev_id; u32 reason; - if (!dev) - return IRQ_NONE; + B43_WARN_ON(!dev); spin_lock(&dev->wl->irq_lock); - if (b43_status(dev) < B43_STAT_STARTED) + if (unlikely(b43_status(dev) < B43_STAT_STARTED)) { + /* This can only happen on shared IRQ lines. */ goto out; + } reason = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON); if (reason == 0xffffffff) /* shared IRQ */ goto out; ret = IRQ_HANDLED; - reason &= b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); + reason &= dev->irq_mask; if (!reason) goto out; @@ -1928,16 +1910,18 @@ static irqreturn_t b43_interrupt_handler(int irq, void *dev_id) & 0x0001DC00; dev->dma_reason[4] = b43_read32(dev, B43_MMIO_DMA4_REASON) & 0x0000DC00; +/* Unused ring dev->dma_reason[5] = b43_read32(dev, B43_MMIO_DMA5_REASON) & 0x0000DC00; +*/ b43_interrupt_ack(dev, reason); /* disable all IRQs. They are enabled again in the bottom half. */ - dev->irq_savedstate = b43_interrupt_disable(dev, B43_IRQ_ALL); + b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0); /* save the reason code and call our bottom half. */ dev->irq_reason = reason; tasklet_schedule(&dev->isr_tasklet); - out: +out: mmiowb(); spin_unlock(&dev->wl->irq_lock); @@ -2330,12 +2314,34 @@ static int b43_upload_microcode(struct b43_wldev *dev) dev->fw.patch = fwpatch; dev->fw.opensource = (fwdate == 0xFFFF); + /* Default to use-all-queues. */ + dev->wl->hw->queues = dev->wl->mac80211_initially_registered_queues; + dev->qos_enabled = !!modparam_qos; + /* Default to firmware/hardware crypto acceleration. */ + dev->hwcrypto_enabled = 1; + if (dev->fw.opensource) { + u16 fwcapa; + /* Patchlevel info is encoded in the "time" field. */ dev->fw.patch = fwtime; - b43info(dev->wl, "Loading OpenSource firmware version %u.%u%s\n", - dev->fw.rev, dev->fw.patch, - dev->fw.pcm_request_failed ? " (Hardware crypto not supported)" : ""); + b43info(dev->wl, "Loading OpenSource firmware version %u.%u\n", + dev->fw.rev, dev->fw.patch); + + fwcapa = b43_fwcapa_read(dev); + if (!(fwcapa & B43_FWCAPA_HWCRYPTO) || dev->fw.pcm_request_failed) { + b43info(dev->wl, "Hardware crypto acceleration not supported by firmware\n"); + /* Disable hardware crypto and fall back to software crypto. */ + dev->hwcrypto_enabled = 0; + } + if (!(fwcapa & B43_FWCAPA_QOS)) { + b43info(dev->wl, "QoS not supported by firmware\n"); + /* Disable QoS. Tweak hw->queues to 1. It will be restored before + * ieee80211_unregister to make sure the networking core can + * properly free possible resources. */ + dev->wl->hw->queues = 1; + dev->qos_enabled = 0; + } } else { b43info(dev->wl, "Loading firmware version %u.%u " "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n", @@ -2980,6 +2986,7 @@ static void b43_security_init(struct b43_wldev *dev) b43_clear_keys(dev); } +#ifdef CONFIG_B43_HWRNG static int b43_rng_read(struct hwrng *rng, u32 *data) { struct b43_wl *wl = (struct b43_wl *)rng->priv; @@ -2995,17 +3002,21 @@ static int b43_rng_read(struct hwrng *rng, u32 *data) return (sizeof(u16)); } +#endif /* CONFIG_B43_HWRNG */ static void b43_rng_exit(struct b43_wl *wl) { +#ifdef CONFIG_B43_HWRNG if (wl->rng_initialized) hwrng_unregister(&wl->rng); +#endif /* CONFIG_B43_HWRNG */ } static int b43_rng_init(struct b43_wl *wl) { - int err; + int err = 0; +#ifdef CONFIG_B43_HWRNG snprintf(wl->rng_name, ARRAY_SIZE(wl->rng_name), "%s_%s", KBUILD_MODNAME, wiphy_name(wl->hw->wiphy)); wl->rng.name = wl->rng_name; @@ -3018,6 +3029,7 @@ static int b43_rng_init(struct b43_wl *wl) b43err(wl, "Failed to register the random " "number generator (%d)\n", err); } +#endif /* CONFIG_B43_HWRNG */ return err; } @@ -3485,14 +3497,9 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed) if (phy->ops->set_rx_antenna) phy->ops->set_rx_antenna(dev, antenna); - /* Update templates for AP/mesh mode. */ - if (b43_is_mode(wl, NL80211_IFTYPE_AP) || - b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT)) - b43_set_beacon_int(dev, conf->beacon_int); - if (!!conf->radio_enabled != phy->radio_on) { if (conf->radio_enabled) { - b43_software_rfkill(dev, RFKILL_STATE_UNBLOCKED); + b43_software_rfkill(dev, false); b43info(dev->wl, "Radio turned on by software\n"); if (!dev->radio_hw_enable) { b43info(dev->wl, "The hardware RF-kill button " @@ -3500,7 +3507,7 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed) "Press the button to turn it on.\n"); } } else { - b43_software_rfkill(dev, RFKILL_STATE_SOFT_BLOCKED); + b43_software_rfkill(dev, true); b43info(dev->wl, "Radio turned off by software\n"); } } @@ -3565,14 +3572,45 @@ static void b43_op_bss_info_changed(struct ieee80211_hw *hw, { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev; + unsigned long flags; mutex_lock(&wl->mutex); dev = wl->current_dev; if (!dev || b43_status(dev) < B43_STAT_STARTED) goto out_unlock_mutex; + + B43_WARN_ON(wl->vif != vif); + + spin_lock_irqsave(&wl->irq_lock, flags); + if (changed & BSS_CHANGED_BSSID) { + if (conf->bssid) + memcpy(wl->bssid, conf->bssid, ETH_ALEN); + else + memset(wl->bssid, 0, ETH_ALEN); + } + + if (b43_status(dev) >= B43_STAT_INITIALIZED) { + if (changed & BSS_CHANGED_BEACON && + (b43_is_mode(wl, NL80211_IFTYPE_AP) || + b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT) || + b43_is_mode(wl, NL80211_IFTYPE_ADHOC))) + b43_update_templates(wl); + + if (changed & BSS_CHANGED_BSSID) + b43_write_mac_bssid_templates(dev); + } + spin_unlock_irqrestore(&wl->irq_lock, flags); + b43_mac_suspend(dev); + /* Update templates for AP/mesh mode. */ + if (changed & BSS_CHANGED_BEACON_INT && + (b43_is_mode(wl, NL80211_IFTYPE_AP) || + b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT) || + b43_is_mode(wl, NL80211_IFTYPE_ADHOC))) + b43_set_beacon_int(dev, conf->beacon_int); + if (changed & BSS_CHANGED_BASIC_RATES) b43_update_basic_rates(dev, conf->basic_rates); @@ -3586,8 +3624,6 @@ static void b43_op_bss_info_changed(struct ieee80211_hw *hw, b43_mac_enable(dev); out_unlock_mutex: mutex_unlock(&wl->mutex); - - return; } static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, @@ -3620,7 +3656,7 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, if (!dev || b43_status(dev) < B43_STAT_INITIALIZED) goto out_unlock; - if (dev->fw.pcm_request_failed) { + if (dev->fw.pcm_request_failed || !dev->hwcrypto_enabled) { /* We don't have firmware for the crypto engine. * Must use software-crypto. */ err = -EOPNOTSUPP; @@ -3630,7 +3666,7 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, err = -EINVAL; switch (key->alg) { case ALG_WEP: - if (key->keylen == LEN_WEP40) + if (key->keylen == WLAN_KEY_LEN_WEP40) algorithm = B43_SEC_ALGO_WEP40; else algorithm = B43_SEC_ALGO_WEP104; @@ -3745,41 +3781,6 @@ static void b43_op_configure_filter(struct ieee80211_hw *hw, spin_unlock_irqrestore(&wl->irq_lock, flags); } -static int b43_op_config_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_if_conf *conf) -{ - struct b43_wl *wl = hw_to_b43_wl(hw); - struct b43_wldev *dev = wl->current_dev; - unsigned long flags; - - if (!dev) - return -ENODEV; - mutex_lock(&wl->mutex); - spin_lock_irqsave(&wl->irq_lock, flags); - B43_WARN_ON(wl->vif != vif); - if (conf->bssid) - memcpy(wl->bssid, conf->bssid, ETH_ALEN); - else - memset(wl->bssid, 0, ETH_ALEN); - if (b43_status(dev) >= B43_STAT_INITIALIZED) { - if (b43_is_mode(wl, NL80211_IFTYPE_AP) || - b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT)) { - B43_WARN_ON(vif->type != wl->if_type); - if (conf->changed & IEEE80211_IFCC_BEACON) - b43_update_templates(wl); - } else if (b43_is_mode(wl, NL80211_IFTYPE_ADHOC)) { - if (conf->changed & IEEE80211_IFCC_BEACON) - b43_update_templates(wl); - } - b43_write_mac_bssid_templates(dev); - } - spin_unlock_irqrestore(&wl->irq_lock, flags); - mutex_unlock(&wl->mutex); - - return 0; -} - /* Locking: wl->mutex */ static void b43_wireless_core_stop(struct b43_wldev *dev) { @@ -3793,7 +3794,7 @@ static void b43_wireless_core_stop(struct b43_wldev *dev) * setting the status to INITIALIZED, as the interrupt handler * won't care about IRQs then. */ spin_lock_irqsave(&wl->irq_lock, flags); - dev->irq_savedstate = b43_interrupt_disable(dev, B43_IRQ_ALL); + b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0); b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* flush */ spin_unlock_irqrestore(&wl->irq_lock, flags); b43_synchronize_irq(dev); @@ -3834,7 +3835,7 @@ static int b43_wireless_core_start(struct b43_wldev *dev) /* Start data flow (TX/RX). */ b43_mac_enable(dev); - b43_interrupt_enable(dev, dev->irq_savedstate); + b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, dev->irq_mask); /* Start maintainance work */ b43_periodic_tasks_setup(dev); @@ -3997,9 +3998,9 @@ static void setup_struct_wldev_for_init(struct b43_wldev *dev) /* IRQ related flags */ dev->irq_reason = 0; memset(dev->dma_reason, 0, sizeof(dev->dma_reason)); - dev->irq_savedstate = B43_IRQ_MASKTEMPLATE; + dev->irq_mask = B43_IRQ_MASKTEMPLATE; if (b43_modparam_verbose < B43_VERBOSITY_DEBUG) - dev->irq_savedstate &= ~B43_IRQ_PHY_TXERR; + dev->irq_mask &= ~B43_IRQ_PHY_TXERR; dev->mac_suspended = 1; @@ -4326,7 +4327,6 @@ static int b43_op_start(struct ieee80211_hw *hw) struct b43_wldev *dev = wl->current_dev; int did_init = 0; int err = 0; - bool do_rfkill_exit = 0; /* Kill all old instance specific information to make sure * the card won't use it in the short timeframe between start @@ -4340,18 +4340,12 @@ static int b43_op_start(struct ieee80211_hw *hw) wl->beacon1_uploaded = 0; wl->beacon_templates_virgin = 1; - /* First register RFkill. - * LEDs that are registered later depend on it. */ - b43_rfkill_init(dev); - mutex_lock(&wl->mutex); if (b43_status(dev) < B43_STAT_INITIALIZED) { err = b43_wireless_core_init(dev); - if (err) { - do_rfkill_exit = 1; + if (err) goto out_mutex_unlock; - } did_init = 1; } @@ -4360,17 +4354,16 @@ static int b43_op_start(struct ieee80211_hw *hw) if (err) { if (did_init) b43_wireless_core_exit(dev); - do_rfkill_exit = 1; goto out_mutex_unlock; } } + /* XXX: only do if device doesn't support rfkill irq */ + wiphy_rfkill_start_polling(hw->wiphy); + out_mutex_unlock: mutex_unlock(&wl->mutex); - if (do_rfkill_exit) - b43_rfkill_exit(dev); - return err; } @@ -4379,7 +4372,6 @@ static void b43_op_stop(struct ieee80211_hw *hw) struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev = wl->current_dev; - b43_rfkill_exit(dev); cancel_work_sync(&(wl->beacon_update_trigger)); mutex_lock(&wl->mutex); @@ -4449,7 +4441,6 @@ static const struct ieee80211_ops b43_hw_ops = { .remove_interface = b43_op_remove_interface, .config = b43_op_config, .bss_info_changed = b43_op_bss_info_changed, - .config_interface = b43_op_config_interface, .configure_filter = b43_op_configure_filter, .set_key = b43_op_set_key, .get_stats = b43_op_get_stats, @@ -4462,6 +4453,7 @@ static const struct ieee80211_ops b43_hw_ops = { .sta_notify = b43_op_sta_notify, .sw_scan_start = b43_op_sw_scan_start_notifier, .sw_scan_complete = b43_op_sw_scan_complete_notifier, + .rfkill_poll = b43_rfkill_poll, }; /* Hard-reset the chip. Do not call this directly. @@ -4764,6 +4756,7 @@ static int b43_wireless_init(struct ssb_device *dev) b43err(NULL, "Could not allocate ieee80211 device\n"); goto out; } + wl = hw_to_b43_wl(hw); /* fill hw info */ hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | @@ -4777,7 +4770,8 @@ static int b43_wireless_init(struct ssb_device *dev) BIT(NL80211_IFTYPE_WDS) | BIT(NL80211_IFTYPE_ADHOC); - hw->queues = b43_modparam_qos ? 4 : 1; + hw->queues = modparam_qos ? 4 : 1; + wl->mac80211_initially_registered_queues = hw->queues; hw->max_rates = 2; SET_IEEE80211_DEV(hw, dev->dev); if (is_valid_ether_addr(sprom->et1mac)) @@ -4785,9 +4779,7 @@ static int b43_wireless_init(struct ssb_device *dev) else SET_IEEE80211_PERM_ADDR(hw, sprom->il0mac); - /* Get and initialize struct b43_wl */ - wl = hw_to_b43_wl(hw); - memset(wl, 0, sizeof(*wl)); + /* Initialize struct b43_wl */ wl->hw = hw; spin_lock_init(&wl->irq_lock); rwlock_init(&wl->tx_lock); @@ -4853,8 +4845,13 @@ static void b43_remove(struct ssb_device *dev) cancel_work_sync(&wldev->restart_work); B43_WARN_ON(!wl); - if (wl->current_dev == wldev) + if (wl->current_dev == wldev) { + /* Restore the queues count before unregistering, because firmware detect + * might have modified it. Restoring is important, so the networking + * stack can properly free resources. */ + wl->hw->queues = wl->mac80211_initially_registered_queues; ieee80211_unregister_hw(wl->hw); + } b43_one_core_detach(dev); @@ -4949,7 +4946,7 @@ static struct ssb_driver b43_ssb_driver = { static void b43_print_driverinfo(void) { const char *feat_pci = "", *feat_pcmcia = "", *feat_nphy = "", - *feat_leds = "", *feat_rfkill = ""; + *feat_leds = ""; #ifdef CONFIG_B43_PCI_AUTOSELECT feat_pci = "P"; @@ -4962,15 +4959,12 @@ static void b43_print_driverinfo(void) #endif #ifdef CONFIG_B43_LEDS feat_leds = "L"; -#endif -#ifdef CONFIG_B43_RFKILL - feat_rfkill = "R"; #endif printk(KERN_INFO "Broadcom 43xx driver loaded " - "[ Features: %s%s%s%s%s, Firmware-ID: " + "[ Features: %s%s%s%s, Firmware-ID: " B43_SUPPORTED_FIRMWARE_ID " ]\n", feat_pci, feat_pcmcia, feat_nphy, - feat_leds, feat_rfkill); + feat_leds); } static int __init b43_init(void) diff --git a/drivers/net/wireless/b43/main.h b/drivers/net/wireless/b43/main.h index 40abcf5d1b43..950fb1b0546d 100644 --- a/drivers/net/wireless/b43/main.h +++ b/drivers/net/wireless/b43/main.h @@ -39,7 +39,6 @@ #define PAD_BYTES(nr_bytes) P4D_BYTES( __LINE__ , (nr_bytes)) -extern int b43_modparam_qos; extern int b43_modparam_verbose; /* Logmessage verbosity levels. Update the b43_modparam_verbose helptext, if diff --git a/drivers/net/wireless/b43/phy_a.c b/drivers/net/wireless/b43/phy_a.c index c836c077d51d..816e028a2620 100644 --- a/drivers/net/wireless/b43/phy_a.c +++ b/drivers/net/wireless/b43/phy_a.c @@ -480,11 +480,11 @@ static bool b43_aphy_op_supports_hwpctl(struct b43_wldev *dev) } static void b43_aphy_op_software_rfkill(struct b43_wldev *dev, - enum rfkill_state state) + bool blocked) { struct b43_phy *phy = &dev->phy; - if (state == RFKILL_STATE_UNBLOCKED) { + if (!blocked) { if (phy->radio_on) return; b43_radio_write16(dev, 0x0004, 0x00C0); diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c index e176b6e0d9cf..6d241622210e 100644 --- a/drivers/net/wireless/b43/phy_common.c +++ b/drivers/net/wireless/b43/phy_common.c @@ -84,7 +84,7 @@ int b43_phy_init(struct b43_wldev *dev) phy->channel = ops->get_default_chan(dev); - ops->software_rfkill(dev, RFKILL_STATE_UNBLOCKED); + ops->software_rfkill(dev, false); err = ops->init(dev); if (err) { b43err(dev->wl, "PHY init failed\n"); @@ -104,7 +104,7 @@ err_phy_exit: if (ops->exit) ops->exit(dev); err_block_rf: - ops->software_rfkill(dev, RFKILL_STATE_SOFT_BLOCKED); + ops->software_rfkill(dev, true); return err; } @@ -113,7 +113,7 @@ void b43_phy_exit(struct b43_wldev *dev) { const struct b43_phy_operations *ops = dev->phy.ops; - ops->software_rfkill(dev, RFKILL_STATE_SOFT_BLOCKED); + ops->software_rfkill(dev, true); if (ops->exit) ops->exit(dev); } @@ -295,18 +295,13 @@ err_restore_cookie: return err; } -void b43_software_rfkill(struct b43_wldev *dev, enum rfkill_state state) +void b43_software_rfkill(struct b43_wldev *dev, bool blocked) { struct b43_phy *phy = &dev->phy; - if (state == RFKILL_STATE_HARD_BLOCKED) { - /* We cannot hardware-block the device */ - state = RFKILL_STATE_SOFT_BLOCKED; - } - b43_mac_suspend(dev); - phy->ops->software_rfkill(dev, state); - phy->radio_on = (state == RFKILL_STATE_UNBLOCKED); + phy->ops->software_rfkill(dev, blocked); + phy->radio_on = !blocked; b43_mac_enable(dev); } diff --git a/drivers/net/wireless/b43/phy_common.h b/drivers/net/wireless/b43/phy_common.h index b2d99101947b..44cc918e4fc6 100644 --- a/drivers/net/wireless/b43/phy_common.h +++ b/drivers/net/wireless/b43/phy_common.h @@ -1,7 +1,7 @@ #ifndef LINUX_B43_PHY_COMMON_H_ #define LINUX_B43_PHY_COMMON_H_ -#include +#include struct b43_wldev; @@ -159,7 +159,7 @@ struct b43_phy_operations { /* Radio */ bool (*supports_hwpctl)(struct b43_wldev *dev); - void (*software_rfkill)(struct b43_wldev *dev, enum rfkill_state state); + void (*software_rfkill)(struct b43_wldev *dev, bool blocked); void (*switch_analog)(struct b43_wldev *dev, bool on); int (*switch_channel)(struct b43_wldev *dev, unsigned int new_channel); unsigned int (*get_default_chan)(struct b43_wldev *dev); @@ -364,7 +364,7 @@ int b43_switch_channel(struct b43_wldev *dev, unsigned int new_channel); /** * b43_software_rfkill - Turn the radio ON or OFF in software. */ -void b43_software_rfkill(struct b43_wldev *dev, enum rfkill_state state); +void b43_software_rfkill(struct b43_wldev *dev, bool blocked); /** * b43_phy_txpower_check - Check TX power output. diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c index e7b98f013b0f..5300232449f6 100644 --- a/drivers/net/wireless/b43/phy_g.c +++ b/drivers/net/wireless/b43/phy_g.c @@ -2592,7 +2592,7 @@ static bool b43_gphy_op_supports_hwpctl(struct b43_wldev *dev) } static void b43_gphy_op_software_rfkill(struct b43_wldev *dev, - enum rfkill_state state) + bool blocked) { struct b43_phy *phy = &dev->phy; struct b43_phy_g *gphy = phy->g; @@ -2600,7 +2600,7 @@ static void b43_gphy_op_software_rfkill(struct b43_wldev *dev, might_sleep(); - if (state == RFKILL_STATE_UNBLOCKED) { + if (!blocked) { /* Turn radio ON */ if (phy->radio_on) return; diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 58e319d6b1ed..ea0d3a3a6a64 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -488,7 +488,7 @@ static void b43_lpphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value) } static void b43_lpphy_op_software_rfkill(struct b43_wldev *dev, - enum rfkill_state state) + bool blocked) { //TODO } diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 8bcfda5f3f07..be7b5604947b 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -579,7 +579,7 @@ static void b43_nphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value) } static void b43_nphy_op_software_rfkill(struct b43_wldev *dev, - enum rfkill_state state) + bool blocked) {//TODO } diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c index 8cd9776752e6..69138e8c1db6 100644 --- a/drivers/net/wireless/b43/pio.c +++ b/drivers/net/wireless/b43/pio.c @@ -313,7 +313,7 @@ static struct b43_pio_txqueue *select_queue_by_priority(struct b43_wldev *dev, { struct b43_pio_txqueue *q; - if (b43_modparam_qos) { + if (dev->qos_enabled) { /* 0 = highest priority */ switch (queue_prio) { default: diff --git a/drivers/net/wireless/b43/rfkill.c b/drivers/net/wireless/b43/rfkill.c index afad42358693..31e55999893f 100644 --- a/drivers/net/wireless/b43/rfkill.c +++ b/drivers/net/wireless/b43/rfkill.c @@ -22,15 +22,11 @@ */ -#include "rfkill.h" #include "b43.h" -#include "phy_common.h" - -#include /* Returns TRUE, if the radio is enabled in hardware. */ -static bool b43_is_hw_radio_enabled(struct b43_wldev *dev) +bool b43_is_hw_radio_enabled(struct b43_wldev *dev) { if (dev->phy.rev >= 3) { if (!(b43_read32(dev, B43_MMIO_RADIO_HWENABLED_HI) @@ -45,166 +41,39 @@ static bool b43_is_hw_radio_enabled(struct b43_wldev *dev) } /* The poll callback for the hardware button. */ -static void b43_rfkill_poll(struct input_polled_dev *poll_dev) +void b43_rfkill_poll(struct ieee80211_hw *hw) { - struct b43_wldev *dev = poll_dev->private; - struct b43_wl *wl = dev->wl; + struct b43_wl *wl = hw_to_b43_wl(hw); + struct b43_wldev *dev = wl->current_dev; + struct ssb_bus *bus = dev->dev->bus; bool enabled; - bool report_change = 0; + bool brought_up = false; mutex_lock(&wl->mutex); if (unlikely(b43_status(dev) < B43_STAT_INITIALIZED)) { - mutex_unlock(&wl->mutex); - return; + if (ssb_bus_powerup(bus, 0)) { + mutex_unlock(&wl->mutex); + return; + } + ssb_device_enable(dev->dev, 0); + brought_up = true; } + enabled = b43_is_hw_radio_enabled(dev); + if (unlikely(enabled != dev->radio_hw_enable)) { dev->radio_hw_enable = enabled; - report_change = 1; b43info(wl, "Radio hardware status changed to %s\n", enabled ? "ENABLED" : "DISABLED"); + wiphy_rfkill_set_hw_state(hw->wiphy, !enabled); + if (enabled != dev->phy.radio_on) + b43_software_rfkill(dev, !enabled); } + + if (brought_up) { + ssb_device_disable(dev->dev, 0); + ssb_bus_may_powerdown(bus); + } + mutex_unlock(&wl->mutex); - - /* send the radio switch event to the system - note both a key press - * and a release are required */ - if (unlikely(report_change)) { - input_report_key(poll_dev->input, KEY_WLAN, 1); - input_report_key(poll_dev->input, KEY_WLAN, 0); - } -} - -/* Called when the RFKILL toggled in software. */ -static int b43_rfkill_soft_toggle(void *data, enum rfkill_state state) -{ - struct b43_wldev *dev = data; - struct b43_wl *wl = dev->wl; - int err = -EBUSY; - - if (!wl->rfkill.registered) - return 0; - - mutex_lock(&wl->mutex); - if (b43_status(dev) < B43_STAT_INITIALIZED) - goto out_unlock; - err = 0; - switch (state) { - case RFKILL_STATE_UNBLOCKED: - if (!dev->radio_hw_enable) { - /* No luck. We can't toggle the hardware RF-kill - * button from software. */ - err = -EBUSY; - goto out_unlock; - } - if (!dev->phy.radio_on) - b43_software_rfkill(dev, state); - break; - case RFKILL_STATE_SOFT_BLOCKED: - if (dev->phy.radio_on) - b43_software_rfkill(dev, state); - break; - default: - b43warn(wl, "Received unexpected rfkill state %d.\n", state); - break; - } -out_unlock: - mutex_unlock(&wl->mutex); - - return err; -} - -char *b43_rfkill_led_name(struct b43_wldev *dev) -{ - struct b43_rfkill *rfk = &(dev->wl->rfkill); - - if (!rfk->registered) - return NULL; - return rfkill_get_led_name(rfk->rfkill); -} - -void b43_rfkill_init(struct b43_wldev *dev) -{ - struct b43_wl *wl = dev->wl; - struct b43_rfkill *rfk = &(wl->rfkill); - int err; - - rfk->registered = 0; - - rfk->rfkill = rfkill_allocate(dev->dev->dev, RFKILL_TYPE_WLAN); - if (!rfk->rfkill) - goto out_error; - snprintf(rfk->name, sizeof(rfk->name), - "b43-%s", wiphy_name(wl->hw->wiphy)); - rfk->rfkill->name = rfk->name; - rfk->rfkill->state = RFKILL_STATE_UNBLOCKED; - rfk->rfkill->data = dev; - rfk->rfkill->toggle_radio = b43_rfkill_soft_toggle; - rfk->rfkill->user_claim_unsupported = 1; - - rfk->poll_dev = input_allocate_polled_device(); - if (!rfk->poll_dev) { - rfkill_free(rfk->rfkill); - goto err_freed_rfk; - } - - rfk->poll_dev->private = dev; - rfk->poll_dev->poll = b43_rfkill_poll; - rfk->poll_dev->poll_interval = 1000; /* msecs */ - - rfk->poll_dev->input->name = rfk->name; - rfk->poll_dev->input->id.bustype = BUS_HOST; - rfk->poll_dev->input->id.vendor = dev->dev->bus->boardinfo.vendor; - rfk->poll_dev->input->evbit[0] = BIT(EV_KEY); - set_bit(KEY_WLAN, rfk->poll_dev->input->keybit); - - err = rfkill_register(rfk->rfkill); - if (err) - goto err_free_polldev; - -#ifdef CONFIG_RFKILL_INPUT_MODULE - /* B43 RF-kill isn't useful without the rfkill-input subsystem. - * Try to load the module. */ - err = request_module("rfkill-input"); - if (err) - b43warn(wl, "Failed to load the rfkill-input module. " - "The built-in radio LED will not work.\n"); -#endif /* CONFIG_RFKILL_INPUT */ - -#if !defined(CONFIG_RFKILL_INPUT) && !defined(CONFIG_RFKILL_INPUT_MODULE) - b43warn(wl, "The rfkill-input subsystem is not available. " - "The built-in radio LED will not work.\n"); -#endif - - err = input_register_polled_device(rfk->poll_dev); - if (err) - goto err_unreg_rfk; - - rfk->registered = 1; - - return; -err_unreg_rfk: - rfkill_unregister(rfk->rfkill); -err_free_polldev: - input_free_polled_device(rfk->poll_dev); - rfk->poll_dev = NULL; -err_freed_rfk: - rfk->rfkill = NULL; -out_error: - rfk->registered = 0; - b43warn(wl, "RF-kill button init failed\n"); -} - -void b43_rfkill_exit(struct b43_wldev *dev) -{ - struct b43_rfkill *rfk = &(dev->wl->rfkill); - - if (!rfk->registered) - return; - rfk->registered = 0; - - input_unregister_polled_device(rfk->poll_dev); - rfkill_unregister(rfk->rfkill); - input_free_polled_device(rfk->poll_dev); - rfk->poll_dev = NULL; - rfk->rfkill = NULL; } diff --git a/drivers/net/wireless/b43/rfkill.h b/drivers/net/wireless/b43/rfkill.h index adacf936d815..f046c3ca0519 100644 --- a/drivers/net/wireless/b43/rfkill.h +++ b/drivers/net/wireless/b43/rfkill.h @@ -1,52 +1,11 @@ #ifndef B43_RFKILL_H_ #define B43_RFKILL_H_ +struct ieee80211_hw; struct b43_wldev; +void b43_rfkill_poll(struct ieee80211_hw *hw); -#ifdef CONFIG_B43_RFKILL - -#include -#include - - -struct b43_rfkill { - /* The RFKILL subsystem data structure */ - struct rfkill *rfkill; - /* The poll device for the RFKILL input button */ - struct input_polled_dev *poll_dev; - /* Did initialization succeed? Used for freeing. */ - bool registered; - /* The unique name of this rfkill switch */ - char name[sizeof("b43-phy4294967295")]; -}; - -/* The init function returns void, because we are not interested - * in failing the b43 init process when rfkill init failed. */ -void b43_rfkill_init(struct b43_wldev *dev); -void b43_rfkill_exit(struct b43_wldev *dev); - -char * b43_rfkill_led_name(struct b43_wldev *dev); - - -#else /* CONFIG_B43_RFKILL */ -/* No RFKILL support. */ - -struct b43_rfkill { - /* empty */ -}; - -static inline void b43_rfkill_init(struct b43_wldev *dev) -{ -} -static inline void b43_rfkill_exit(struct b43_wldev *dev) -{ -} -static inline char * b43_rfkill_led_name(struct b43_wldev *dev) -{ - return NULL; -} - -#endif /* CONFIG_B43_RFKILL */ +bool b43_is_hw_radio_enabled(struct b43_wldev *dev); #endif /* B43_RFKILL_H_ */ diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index a63d88841df8..55f36a7254d9 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -118,7 +118,6 @@ u8 b43_plcp_get_ratecode_ofdm(const u8 bitrate) void b43_generate_plcp_hdr(struct b43_plcp_hdr4 *plcp, const u16 octets, const u8 bitrate) { - __le32 *data = &(plcp->data); __u8 *raw = plcp->raw; if (b43_is_ofdm_rate(bitrate)) { @@ -127,7 +126,7 @@ void b43_generate_plcp_hdr(struct b43_plcp_hdr4 *plcp, d = b43_plcp_get_ratecode_ofdm(bitrate); B43_WARN_ON(octets & 0xF000); d |= (octets << 5); - *data = cpu_to_le32(d); + plcp->data = cpu_to_le32(d); } else { u32 plen; @@ -141,7 +140,7 @@ void b43_generate_plcp_hdr(struct b43_plcp_hdr4 *plcp, raw[1] = 0x04; } else raw[1] = 0x04; - *data |= cpu_to_le32(plen << 16); + plcp->data |= cpu_to_le32(plen << 16); raw[0] = b43_plcp_get_ratecode_cck(bitrate); } } diff --git a/drivers/net/wireless/b43legacy/Kconfig b/drivers/net/wireless/b43legacy/Kconfig index aef2298d37ac..94a463478053 100644 --- a/drivers/net/wireless/b43legacy/Kconfig +++ b/drivers/net/wireless/b43legacy/Kconfig @@ -3,7 +3,6 @@ config B43LEGACY depends on SSB_POSSIBLE && MAC80211 && WLAN_80211 && HAS_DMA select SSB select FW_LOADER - select HW_RANDOM ---help--- b43legacy is a driver for 802.11b devices from Broadcom (BCM4301 and BCM4303) and early model 802.11g chips (BCM4306 Ver. 2) used in the @@ -43,12 +42,11 @@ config B43LEGACY_LEDS depends on B43LEGACY && MAC80211_LEDS && (LEDS_CLASS = y || LEDS_CLASS = B43LEGACY) default y -# RFKILL support -# This config option automatically enables b43legacy RFKILL support, -# if it's possible. -config B43LEGACY_RFKILL +# This config option automatically enables b43 HW-RNG support, +# if the HW-RNG core is enabled. +config B43LEGACY_HWRNG bool - depends on B43LEGACY && (RFKILL = y || RFKILL = B43LEGACY) && RFKILL_INPUT && (INPUT_POLLDEV = y || INPUT_POLLDEV = B43LEGACY) + depends on B43LEGACY && (HW_RANDOM = y || HW_RANDOM = B43LEGACY) default y config B43LEGACY_DEBUG diff --git a/drivers/net/wireless/b43legacy/Makefile b/drivers/net/wireless/b43legacy/Makefile index 80cdb73bd140..227a77e84362 100644 --- a/drivers/net/wireless/b43legacy/Makefile +++ b/drivers/net/wireless/b43legacy/Makefile @@ -6,7 +6,7 @@ b43legacy-y += radio.o b43legacy-y += sysfs.o b43legacy-y += xmit.o # b43 RFKILL button support -b43legacy-$(CONFIG_B43LEGACY_RFKILL) += rfkill.o +b43legacy-y += rfkill.o # b43legacy LED support b43legacy-$(CONFIG_B43LEGACY_LEDS) += leds.o # b43legacy debugging diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h index 97b0e06dfe21..77fda148ac46 100644 --- a/drivers/net/wireless/b43legacy/b43legacy.h +++ b/drivers/net/wireless/b43legacy/b43legacy.h @@ -59,7 +59,8 @@ #define B43legacy_MMIO_XMITSTAT_1 0x174 #define B43legacy_MMIO_REV3PLUS_TSF_LOW 0x180 /* core rev >= 3 only */ #define B43legacy_MMIO_REV3PLUS_TSF_HIGH 0x184 /* core rev >= 3 only */ - +#define B43legacy_MMIO_TSF_CFP_REP 0x188 +#define B43legacy_MMIO_TSF_CFP_START 0x18C /* 32-bit DMA */ #define B43legacy_MMIO_DMA32_BASE0 0x200 #define B43legacy_MMIO_DMA32_BASE1 0x220 @@ -258,7 +259,6 @@ #define B43legacy_IRQ_ALL 0xFFFFFFFF #define B43legacy_IRQ_MASKTEMPLATE (B43legacy_IRQ_MAC_SUSPENDED | \ - B43legacy_IRQ_BEACON | \ B43legacy_IRQ_TBTT_INDI | \ B43legacy_IRQ_ATIM_END | \ B43legacy_IRQ_PMQ | \ @@ -596,12 +596,11 @@ struct b43legacy_wl { /* Stats about the wireless interface */ struct ieee80211_low_level_stats ieee_stats; +#ifdef CONFIG_B43LEGACY_HWRNG struct hwrng rng; u8 rng_initialized; char rng_name[30 + 1]; - - /* The RF-kill button */ - struct b43legacy_rfkill rfkill; +#endif /* List of all wireless devices on this chip */ struct list_head devlist; @@ -614,6 +613,8 @@ struct b43legacy_wl { struct sk_buff *current_beacon; bool beacon0_uploaded; bool beacon1_uploaded; + bool beacon_templates_virgin; /* Never wrote the templates? */ + struct work_struct beacon_update_trigger; }; /* Pointers to the firmware data and meta information about it. */ @@ -690,8 +691,8 @@ struct b43legacy_wldev { /* Reason code of the last interrupt. */ u32 irq_reason; u32 dma_reason[6]; - /* saved irq enable/disable state bitfield. */ - u32 irq_savedstate; + /* The currently active generic-interrupt mask. */ + u32 irq_mask; /* Link Quality calculation context. */ struct b43legacy_noise_calculation noisecalc; /* if > 0 MAC is suspended. if == 0 MAC is enabled. */ diff --git a/drivers/net/wireless/b43legacy/leds.c b/drivers/net/wireless/b43legacy/leds.c index 3ea55b18c700..37e9be893560 100644 --- a/drivers/net/wireless/b43legacy/leds.c +++ b/drivers/net/wireless/b43legacy/leds.c @@ -28,6 +28,7 @@ #include "b43legacy.h" #include "leds.h" +#include "rfkill.h" static void b43legacy_led_turn_on(struct b43legacy_wldev *dev, u8 led_index, @@ -86,7 +87,8 @@ static void b43legacy_led_brightness_set(struct led_classdev *led_dev, static int b43legacy_register_led(struct b43legacy_wldev *dev, struct b43legacy_led *led, - const char *name, char *default_trigger, + const char *name, + const char *default_trigger, u8 led_index, bool activelow) { int err; @@ -163,10 +165,10 @@ static void b43legacy_map_led(struct b43legacy_wldev *dev, snprintf(name, sizeof(name), "b43legacy-%s::radio", wiphy_name(hw->wiphy)); b43legacy_register_led(dev, &dev->led_radio, name, - b43legacy_rfkill_led_name(dev), + ieee80211_get_radio_led_name(hw), led_index, activelow); - /* Sync the RF-kill LED state with the switch state. */ - if (dev->radio_hw_enable) + /* Sync the RF-kill LED state with radio and switch states. */ + if (dev->phy.radio_on && b43legacy_is_hw_radio_enabled(dev)) b43legacy_led_turn_on(dev, led_index, activelow); break; case B43legacy_LED_WEIRD: diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 879edc786713..e5136fb65ddd 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -583,35 +583,6 @@ static void b43legacy_short_slot_timing_disable(struct b43legacy_wldev *dev) b43legacy_set_slot_time(dev, 20); } -/* Enable a Generic IRQ. "mask" is the mask of which IRQs to enable. - * Returns the _previously_ enabled IRQ mask. - */ -static inline u32 b43legacy_interrupt_enable(struct b43legacy_wldev *dev, - u32 mask) -{ - u32 old_mask; - - old_mask = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK); - b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, old_mask | - mask); - - return old_mask; -} - -/* Disable a Generic IRQ. "mask" is the mask of which IRQs to disable. - * Returns the _previously_ enabled IRQ mask. - */ -static inline u32 b43legacy_interrupt_disable(struct b43legacy_wldev *dev, - u32 mask) -{ - u32 old_mask; - - old_mask = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK); - b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, old_mask & ~mask); - - return old_mask; -} - /* Synchronize IRQ top- and bottom-half. * IRQs must be masked before calling this. * This must not be called with the irq_lock held. @@ -955,23 +926,54 @@ static void b43legacy_write_template_common(struct b43legacy_wldev *dev, size + sizeof(struct b43legacy_plcp_hdr6)); } +/* Convert a b43legacy antenna number value to the PHY TX control value. */ +static u16 b43legacy_antenna_to_phyctl(int antenna) +{ + switch (antenna) { + case B43legacy_ANTENNA0: + return B43legacy_TX4_PHY_ANT0; + case B43legacy_ANTENNA1: + return B43legacy_TX4_PHY_ANT1; + } + return B43legacy_TX4_PHY_ANTLAST; +} + static void b43legacy_write_beacon_template(struct b43legacy_wldev *dev, u16 ram_offset, - u16 shm_size_offset, u8 rate) + u16 shm_size_offset) { unsigned int i, len, variable_len; const struct ieee80211_mgmt *bcn; const u8 *ie; bool tim_found = 0; + unsigned int rate; + u16 ctl; + int antenna; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(dev->wl->current_beacon); bcn = (const struct ieee80211_mgmt *)(dev->wl->current_beacon->data); len = min((size_t)dev->wl->current_beacon->len, 0x200 - sizeof(struct b43legacy_plcp_hdr6)); + rate = ieee80211_get_tx_rate(dev->wl->hw, info)->hw_value; b43legacy_write_template_common(dev, (const u8 *)bcn, len, ram_offset, shm_size_offset, rate); + /* Write the PHY TX control parameters. */ + antenna = B43legacy_ANTENNA_DEFAULT; + antenna = b43legacy_antenna_to_phyctl(antenna); + ctl = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, + B43legacy_SHM_SH_BEACPHYCTL); + /* We can't send beacons with short preamble. Would get PHY errors. */ + ctl &= ~B43legacy_TX4_PHY_SHORTPRMBL; + ctl &= ~B43legacy_TX4_PHY_ANT; + ctl &= ~B43legacy_TX4_PHY_ENC; + ctl |= antenna; + ctl |= B43legacy_TX4_PHY_ENC_CCK; + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, + B43legacy_SHM_SH_BEACPHYCTL, ctl); + /* Find the position of the TIM and the DTIM_period value * and write them to SHM. */ ie = bcn->u.beacon.variable; @@ -1013,7 +1015,8 @@ static void b43legacy_write_beacon_template(struct b43legacy_wldev *dev, b43legacywarn(dev->wl, "Did not find a valid TIM IE in the " "beacon template packet. AP or IBSS operation " "may be broken.\n"); - } + } else + b43legacydbg(dev->wl, "Updated beacon template\n"); } static void b43legacy_write_probe_resp_plcp(struct b43legacy_wldev *dev, @@ -1025,7 +1028,7 @@ static void b43legacy_write_probe_resp_plcp(struct b43legacy_wldev *dev, __le16 dur; plcp.data = 0; - b43legacy_generate_plcp_hdr(&plcp, size + FCS_LEN, rate->bitrate); + b43legacy_generate_plcp_hdr(&plcp, size + FCS_LEN, rate->hw_value); dur = ieee80211_generic_frame_duration(dev->wl->hw, dev->wl->vif, size, @@ -1129,10 +1132,103 @@ static void b43legacy_write_probe_resp_template(struct b43legacy_wldev *dev, 0x200 - sizeof(struct b43legacy_plcp_hdr6)); b43legacy_write_template_common(dev, probe_resp_data, size, ram_offset, - shm_size_offset, rate->bitrate); + shm_size_offset, rate->hw_value); kfree(probe_resp_data); } +static void b43legacy_upload_beacon0(struct b43legacy_wldev *dev) +{ + struct b43legacy_wl *wl = dev->wl; + + if (wl->beacon0_uploaded) + return; + b43legacy_write_beacon_template(dev, 0x68, 0x18); + /* FIXME: Probe resp upload doesn't really belong here, + * but we don't use that feature anyway. */ + b43legacy_write_probe_resp_template(dev, 0x268, 0x4A, + &__b43legacy_ratetable[3]); + wl->beacon0_uploaded = 1; +} + +static void b43legacy_upload_beacon1(struct b43legacy_wldev *dev) +{ + struct b43legacy_wl *wl = dev->wl; + + if (wl->beacon1_uploaded) + return; + b43legacy_write_beacon_template(dev, 0x468, 0x1A); + wl->beacon1_uploaded = 1; +} + +static void handle_irq_beacon(struct b43legacy_wldev *dev) +{ + struct b43legacy_wl *wl = dev->wl; + u32 cmd, beacon0_valid, beacon1_valid; + + if (!b43legacy_is_mode(wl, NL80211_IFTYPE_AP)) + return; + + /* This is the bottom half of the asynchronous beacon update. */ + + /* Ignore interrupt in the future. */ + dev->irq_mask &= ~B43legacy_IRQ_BEACON; + + cmd = b43legacy_read32(dev, B43legacy_MMIO_MACCMD); + beacon0_valid = (cmd & B43legacy_MACCMD_BEACON0_VALID); + beacon1_valid = (cmd & B43legacy_MACCMD_BEACON1_VALID); + + /* Schedule interrupt manually, if busy. */ + if (beacon0_valid && beacon1_valid) { + b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_REASON, B43legacy_IRQ_BEACON); + dev->irq_mask |= B43legacy_IRQ_BEACON; + return; + } + + if (unlikely(wl->beacon_templates_virgin)) { + /* We never uploaded a beacon before. + * Upload both templates now, but only mark one valid. */ + wl->beacon_templates_virgin = 0; + b43legacy_upload_beacon0(dev); + b43legacy_upload_beacon1(dev); + cmd = b43legacy_read32(dev, B43legacy_MMIO_MACCMD); + cmd |= B43legacy_MACCMD_BEACON0_VALID; + b43legacy_write32(dev, B43legacy_MMIO_MACCMD, cmd); + } else { + if (!beacon0_valid) { + b43legacy_upload_beacon0(dev); + cmd = b43legacy_read32(dev, B43legacy_MMIO_MACCMD); + cmd |= B43legacy_MACCMD_BEACON0_VALID; + b43legacy_write32(dev, B43legacy_MMIO_MACCMD, cmd); + } else if (!beacon1_valid) { + b43legacy_upload_beacon1(dev); + cmd = b43legacy_read32(dev, B43legacy_MMIO_MACCMD); + cmd |= B43legacy_MACCMD_BEACON1_VALID; + b43legacy_write32(dev, B43legacy_MMIO_MACCMD, cmd); + } + } +} + +static void b43legacy_beacon_update_trigger_work(struct work_struct *work) +{ + struct b43legacy_wl *wl = container_of(work, struct b43legacy_wl, + beacon_update_trigger); + struct b43legacy_wldev *dev; + + mutex_lock(&wl->mutex); + dev = wl->current_dev; + if (likely(dev && (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED))) { + spin_lock_irq(&wl->irq_lock); + /* Update beacon right away or defer to IRQ. */ + handle_irq_beacon(dev); + /* The handler might have updated the IRQ mask. */ + b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, + dev->irq_mask); + mmiowb(); + spin_unlock_irq(&wl->irq_lock); + } + mutex_unlock(&wl->mutex); +} + /* Asynchronously update the packet templates in template RAM. * Locking: Requires wl->irq_lock to be locked. */ static void b43legacy_update_templates(struct b43legacy_wl *wl) @@ -1156,54 +1252,24 @@ static void b43legacy_update_templates(struct b43legacy_wl *wl) wl->current_beacon = beacon; wl->beacon0_uploaded = 0; wl->beacon1_uploaded = 0; + queue_work(wl->hw->workqueue, &wl->beacon_update_trigger); } static void b43legacy_set_beacon_int(struct b43legacy_wldev *dev, u16 beacon_int) { b43legacy_time_lock(dev); - if (dev->dev->id.revision >= 3) - b43legacy_write32(dev, 0x188, (beacon_int << 16)); - else { + if (dev->dev->id.revision >= 3) { + b43legacy_write32(dev, B43legacy_MMIO_TSF_CFP_REP, + (beacon_int << 16)); + b43legacy_write32(dev, B43legacy_MMIO_TSF_CFP_START, + (beacon_int << 10)); + } else { b43legacy_write16(dev, 0x606, (beacon_int >> 6)); b43legacy_write16(dev, 0x610, beacon_int); } b43legacy_time_unlock(dev); -} - -static void handle_irq_beacon(struct b43legacy_wldev *dev) -{ - struct b43legacy_wl *wl = dev->wl; - u32 cmd; - - if (!b43legacy_is_mode(wl, NL80211_IFTYPE_AP)) - return; - - /* This is the bottom half of the asynchronous beacon update. */ - - cmd = b43legacy_read32(dev, B43legacy_MMIO_MACCMD); - if (!(cmd & B43legacy_MACCMD_BEACON0_VALID)) { - if (!wl->beacon0_uploaded) { - b43legacy_write_beacon_template(dev, 0x68, - B43legacy_SHM_SH_BTL0, - B43legacy_CCK_RATE_1MB); - b43legacy_write_probe_resp_template(dev, 0x268, - B43legacy_SHM_SH_PRTLEN, - &__b43legacy_ratetable[3]); - wl->beacon0_uploaded = 1; - } - cmd |= B43legacy_MACCMD_BEACON0_VALID; - } - if (!(cmd & B43legacy_MACCMD_BEACON1_VALID)) { - if (!wl->beacon1_uploaded) { - b43legacy_write_beacon_template(dev, 0x468, - B43legacy_SHM_SH_BTL1, - B43legacy_CCK_RATE_1MB); - wl->beacon1_uploaded = 1; - } - cmd |= B43legacy_MACCMD_BEACON1_VALID; - } - b43legacy_write32(dev, B43legacy_MMIO_MACCMD, cmd); + b43legacydbg(dev->wl, "Set beacon interval to %u\n", beacon_int); } static void handle_irq_ucode_debug(struct b43legacy_wldev *dev) @@ -1302,7 +1368,7 @@ static void b43legacy_interrupt_tasklet(struct b43legacy_wldev *dev) if (reason & B43legacy_IRQ_TX_OK) handle_irq_transmit_status(dev); - b43legacy_interrupt_enable(dev, dev->irq_savedstate); + b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, dev->irq_mask); mmiowb(); spin_unlock_irqrestore(&dev->wl->irq_lock, flags); } @@ -1354,18 +1420,18 @@ static irqreturn_t b43legacy_interrupt_handler(int irq, void *dev_id) struct b43legacy_wldev *dev = dev_id; u32 reason; - if (!dev) - return IRQ_NONE; + B43legacy_WARN_ON(!dev); spin_lock(&dev->wl->irq_lock); - if (b43legacy_status(dev) < B43legacy_STAT_STARTED) + if (unlikely(b43legacy_status(dev) < B43legacy_STAT_STARTED)) + /* This can only happen on shared IRQ lines. */ goto out; reason = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON); if (reason == 0xffffffff) /* shared IRQ */ goto out; ret = IRQ_HANDLED; - reason &= b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK); + reason &= dev->irq_mask; if (!reason) goto out; @@ -1389,10 +1455,9 @@ static irqreturn_t b43legacy_interrupt_handler(int irq, void *dev_id) & 0x0000DC00; b43legacy_interrupt_ack(dev, reason); - /* disable all IRQs. They are enabled again in the bottom half. */ - dev->irq_savedstate = b43legacy_interrupt_disable(dev, - B43legacy_IRQ_ALL); - /* save the reason code and call our bottom half. */ + /* Disable all IRQs. They are enabled again in the bottom half. */ + b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, 0); + /* Save the reason code and call our bottom half. */ dev->irq_reason = reason; tasklet_schedule(&dev->isr_tasklet); out: @@ -1852,7 +1917,8 @@ void b43legacy_mac_enable(struct b43legacy_wldev *dev) /* Re-enable IRQs. */ spin_lock_irq(&dev->wl->irq_lock); - b43legacy_interrupt_enable(dev, dev->irq_savedstate); + b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, + dev->irq_mask); spin_unlock_irq(&dev->wl->irq_lock); } } @@ -1871,10 +1937,9 @@ void b43legacy_mac_suspend(struct b43legacy_wldev *dev) /* Mask IRQs before suspending MAC. Otherwise * the MAC stays busy and won't suspend. */ spin_lock_irq(&dev->wl->irq_lock); - tmp = b43legacy_interrupt_disable(dev, B43legacy_IRQ_ALL); + b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, 0); spin_unlock_irq(&dev->wl->irq_lock); b43legacy_synchronize_irq(dev); - dev->irq_savedstate = tmp; b43legacy_power_saving_ctl_bits(dev, -1, 1); b43legacy_write32(dev, B43legacy_MMIO_MACCTL, @@ -2297,6 +2362,7 @@ static void b43legacy_security_init(struct b43legacy_wldev *dev) dev->max_nr_keys - 8); } +#ifdef CONFIG_B43LEGACY_HWRNG static int b43legacy_rng_read(struct hwrng *rng, u32 *data) { struct b43legacy_wl *wl = (struct b43legacy_wl *)rng->priv; @@ -2312,17 +2378,21 @@ static int b43legacy_rng_read(struct hwrng *rng, u32 *data) return (sizeof(u16)); } +#endif static void b43legacy_rng_exit(struct b43legacy_wl *wl) { +#ifdef CONFIG_B43LEGACY_HWRNG if (wl->rng_initialized) hwrng_unregister(&wl->rng); +#endif } static int b43legacy_rng_init(struct b43legacy_wl *wl) { - int err; + int err = 0; +#ifdef CONFIG_B43LEGACY_HWRNG snprintf(wl->rng_name, ARRAY_SIZE(wl->rng_name), "%s_%s", KBUILD_MODNAME, wiphy_name(wl->hw->wiphy)); wl->rng.name = wl->rng_name; @@ -2336,6 +2406,7 @@ static int b43legacy_rng_init(struct b43legacy_wl *wl) "number generator (%d)\n", err); } +#endif return err; } @@ -2557,7 +2628,6 @@ static int b43legacy_op_dev_config(struct ieee80211_hw *hw, int antenna_tx; int antenna_rx; int err = 0; - u32 savedirqs; antenna_tx = B43legacy_ANTENNA_DEFAULT; antenna_rx = B43legacy_ANTENNA_DEFAULT; @@ -2597,7 +2667,7 @@ static int b43legacy_op_dev_config(struct ieee80211_hw *hw, spin_unlock_irqrestore(&wl->irq_lock, flags); goto out_unlock_mutex; } - savedirqs = b43legacy_interrupt_disable(dev, B43legacy_IRQ_ALL); + b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, 0); spin_unlock_irqrestore(&wl->irq_lock, flags); b43legacy_synchronize_irq(dev); @@ -2619,11 +2689,6 @@ static int b43legacy_op_dev_config(struct ieee80211_hw *hw, /* Antennas for RX and management frame TX. */ b43legacy_mgmtframe_txantenna(dev, antenna_tx); - /* Update templates for AP mode. */ - if (b43legacy_is_mode(wl, NL80211_IFTYPE_AP)) - b43legacy_set_beacon_int(dev, conf->beacon_int); - - if (!!conf->radio_enabled != phy->radio_on) { if (conf->radio_enabled) { b43legacy_radio_turn_on(dev); @@ -2641,7 +2706,7 @@ static int b43legacy_op_dev_config(struct ieee80211_hw *hw, } spin_lock_irqsave(&wl->irq_lock, flags); - b43legacy_interrupt_enable(dev, savedirqs); + b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, dev->irq_mask); mmiowb(); spin_unlock_irqrestore(&wl->irq_lock, flags); out_unlock_mutex: @@ -2704,9 +2769,9 @@ static void b43legacy_op_bss_info_changed(struct ieee80211_hw *hw, struct b43legacy_wldev *dev; struct b43legacy_phy *phy; unsigned long flags; - u32 savedirqs; mutex_lock(&wl->mutex); + B43legacy_WARN_ON(wl->vif != vif); dev = wl->current_dev; phy = &dev->phy; @@ -2719,12 +2784,35 @@ static void b43legacy_op_bss_info_changed(struct ieee80211_hw *hw, spin_unlock_irqrestore(&wl->irq_lock, flags); goto out_unlock_mutex; } - savedirqs = b43legacy_interrupt_disable(dev, B43legacy_IRQ_ALL); + b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, 0); + + if (changed & BSS_CHANGED_BSSID) { + b43legacy_synchronize_irq(dev); + + if (conf->bssid) + memcpy(wl->bssid, conf->bssid, ETH_ALEN); + else + memset(wl->bssid, 0, ETH_ALEN); + } + + if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) { + if (changed & BSS_CHANGED_BEACON && + (b43legacy_is_mode(wl, NL80211_IFTYPE_AP) || + b43legacy_is_mode(wl, NL80211_IFTYPE_ADHOC))) + b43legacy_update_templates(wl); + + if (changed & BSS_CHANGED_BSSID) + b43legacy_write_mac_bssid_templates(dev); + } spin_unlock_irqrestore(&wl->irq_lock, flags); - b43legacy_synchronize_irq(dev); b43legacy_mac_suspend(dev); + if (changed & BSS_CHANGED_BEACON_INT && + (b43legacy_is_mode(wl, NL80211_IFTYPE_AP) || + b43legacy_is_mode(wl, NL80211_IFTYPE_ADHOC))) + b43legacy_set_beacon_int(dev, conf->beacon_int); + if (changed & BSS_CHANGED_BASIC_RATES) b43legacy_update_basic_rates(dev, conf->basic_rates); @@ -2738,14 +2826,12 @@ static void b43legacy_op_bss_info_changed(struct ieee80211_hw *hw, b43legacy_mac_enable(dev); spin_lock_irqsave(&wl->irq_lock, flags); - b43legacy_interrupt_enable(dev, savedirqs); + b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, dev->irq_mask); /* XXX: why? */ mmiowb(); spin_unlock_irqrestore(&wl->irq_lock, flags); out_unlock_mutex: mutex_unlock(&wl->mutex); - - return; } static void b43legacy_op_configure_filter(struct ieee80211_hw *hw, @@ -2787,40 +2873,6 @@ static void b43legacy_op_configure_filter(struct ieee80211_hw *hw, spin_unlock_irqrestore(&wl->irq_lock, flags); } -static int b43legacy_op_config_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_if_conf *conf) -{ - struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); - struct b43legacy_wldev *dev = wl->current_dev; - unsigned long flags; - - if (!dev) - return -ENODEV; - mutex_lock(&wl->mutex); - spin_lock_irqsave(&wl->irq_lock, flags); - B43legacy_WARN_ON(wl->vif != vif); - if (conf->bssid) - memcpy(wl->bssid, conf->bssid, ETH_ALEN); - else - memset(wl->bssid, 0, ETH_ALEN); - if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) { - if (b43legacy_is_mode(wl, NL80211_IFTYPE_AP)) { - B43legacy_WARN_ON(vif->type != NL80211_IFTYPE_AP); - if (conf->changed & IEEE80211_IFCC_BEACON) - b43legacy_update_templates(wl); - } else if (b43legacy_is_mode(wl, NL80211_IFTYPE_ADHOC)) { - if (conf->changed & IEEE80211_IFCC_BEACON) - b43legacy_update_templates(wl); - } - b43legacy_write_mac_bssid_templates(dev); - } - spin_unlock_irqrestore(&wl->irq_lock, flags); - mutex_unlock(&wl->mutex); - - return 0; -} - /* Locking: wl->mutex */ static void b43legacy_wireless_core_stop(struct b43legacy_wldev *dev) { @@ -2834,8 +2886,7 @@ static void b43legacy_wireless_core_stop(struct b43legacy_wldev *dev) * setting the status to INITIALIZED, as the interrupt handler * won't care about IRQs then. */ spin_lock_irqsave(&wl->irq_lock, flags); - dev->irq_savedstate = b43legacy_interrupt_disable(dev, - B43legacy_IRQ_ALL); + b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, 0); b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK); /* flush */ spin_unlock_irqrestore(&wl->irq_lock, flags); b43legacy_synchronize_irq(dev); @@ -2875,7 +2926,7 @@ static int b43legacy_wireless_core_start(struct b43legacy_wldev *dev) /* Start data flow (TX/RX) */ b43legacy_mac_enable(dev); - b43legacy_interrupt_enable(dev, dev->irq_savedstate); + b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, dev->irq_mask); /* Start maintenance work */ b43legacy_periodic_tasks_setup(dev); @@ -3038,7 +3089,7 @@ static void setup_struct_wldev_for_init(struct b43legacy_wldev *dev) /* IRQ related flags */ dev->irq_reason = 0; memset(dev->dma_reason, 0, sizeof(dev->dma_reason)); - dev->irq_savedstate = B43legacy_IRQ_MASKTEMPLATE; + dev->irq_mask = B43legacy_IRQ_MASKTEMPLATE; dev->mac_suspended = 1; @@ -3380,11 +3431,6 @@ static int b43legacy_op_start(struct ieee80211_hw *hw) struct b43legacy_wldev *dev = wl->current_dev; int did_init = 0; int err = 0; - bool do_rfkill_exit = 0; - - /* First register RFkill. - * LEDs that are registered later depend on it. */ - b43legacy_rfkill_init(dev); /* Kill all old instance specific information to make sure * the card won't use it in the short timeframe between start @@ -3392,15 +3438,16 @@ static int b43legacy_op_start(struct ieee80211_hw *hw) memset(wl->bssid, 0, ETH_ALEN); memset(wl->mac_addr, 0, ETH_ALEN); wl->filter_flags = 0; + wl->beacon0_uploaded = 0; + wl->beacon1_uploaded = 0; + wl->beacon_templates_virgin = 1; mutex_lock(&wl->mutex); if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) { err = b43legacy_wireless_core_init(dev); - if (err) { - do_rfkill_exit = 1; + if (err) goto out_mutex_unlock; - } did_init = 1; } @@ -3409,17 +3456,15 @@ static int b43legacy_op_start(struct ieee80211_hw *hw) if (err) { if (did_init) b43legacy_wireless_core_exit(dev); - do_rfkill_exit = 1; goto out_mutex_unlock; } } + wiphy_rfkill_start_polling(hw->wiphy); + out_mutex_unlock: mutex_unlock(&wl->mutex); - if (do_rfkill_exit) - b43legacy_rfkill_exit(dev); - return err; } @@ -3428,7 +3473,7 @@ static void b43legacy_op_stop(struct ieee80211_hw *hw) struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); struct b43legacy_wldev *dev = wl->current_dev; - b43legacy_rfkill_exit(dev); + cancel_work_sync(&(wl->beacon_update_trigger)); mutex_lock(&wl->mutex); if (b43legacy_status(dev) >= B43legacy_STAT_STARTED) @@ -3457,13 +3502,13 @@ static const struct ieee80211_ops b43legacy_hw_ops = { .remove_interface = b43legacy_op_remove_interface, .config = b43legacy_op_dev_config, .bss_info_changed = b43legacy_op_bss_info_changed, - .config_interface = b43legacy_op_config_interface, .configure_filter = b43legacy_op_configure_filter, .get_stats = b43legacy_op_get_stats, .get_tx_stats = b43legacy_op_get_tx_stats, .start = b43legacy_op_start, .stop = b43legacy_op_stop, .set_tim = b43legacy_op_beacon_set_tim, + .rfkill_poll = b43legacy_rfkill_poll, }; /* Hard-reset the chip. Do not call this directly. @@ -3760,6 +3805,7 @@ static int b43legacy_wireless_init(struct ssb_device *dev) spin_lock_init(&wl->leds_lock); mutex_init(&wl->mutex); INIT_LIST_HEAD(&wl->devlist); + INIT_WORK(&wl->beacon_update_trigger, b43legacy_beacon_update_trigger_work); ssb_set_devtypedata(dev, wl); b43legacyinfo(wl, "Broadcom %04X WLAN found\n", dev->bus->chip_id); diff --git a/drivers/net/wireless/b43legacy/pio.c b/drivers/net/wireless/b43legacy/pio.c index 746d5361bba0..51866c9a2769 100644 --- a/drivers/net/wireless/b43legacy/pio.c +++ b/drivers/net/wireless/b43legacy/pio.c @@ -443,7 +443,7 @@ int b43legacy_pio_init(struct b43legacy_wldev *dev) pio->queue3 = queue; if (dev->dev->id.revision < 3) - dev->irq_savedstate |= B43legacy_IRQ_PIO_WORKAROUND; + dev->irq_mask |= B43legacy_IRQ_PIO_WORKAROUND; b43legacydbg(dev->wl, "PIO initialized\n"); err = 0; diff --git a/drivers/net/wireless/b43legacy/rfkill.c b/drivers/net/wireless/b43legacy/rfkill.c index b32bf6a94f19..8783022db11e 100644 --- a/drivers/net/wireless/b43legacy/rfkill.c +++ b/drivers/net/wireless/b43legacy/rfkill.c @@ -22,15 +22,12 @@ */ -#include "rfkill.h" #include "radio.h" #include "b43legacy.h" -#include - /* Returns TRUE, if the radio is enabled in hardware. */ -static bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev) +bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev) { if (dev->phy.rev >= 3) { if (!(b43legacy_read32(dev, B43legacy_MMIO_RADIO_HWENABLED_HI) @@ -45,165 +42,43 @@ static bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev) } /* The poll callback for the hardware button. */ -static void b43legacy_rfkill_poll(struct input_polled_dev *poll_dev) +void b43legacy_rfkill_poll(struct ieee80211_hw *hw) { - struct b43legacy_wldev *dev = poll_dev->private; - struct b43legacy_wl *wl = dev->wl; + struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); + struct b43legacy_wldev *dev = wl->current_dev; + struct ssb_bus *bus = dev->dev->bus; bool enabled; - bool report_change = 0; + bool brought_up = false; mutex_lock(&wl->mutex); if (unlikely(b43legacy_status(dev) < B43legacy_STAT_INITIALIZED)) { - mutex_unlock(&wl->mutex); - return; + if (ssb_bus_powerup(bus, 0)) { + mutex_unlock(&wl->mutex); + return; + } + ssb_device_enable(dev->dev, 0); + brought_up = true; } + enabled = b43legacy_is_hw_radio_enabled(dev); + if (unlikely(enabled != dev->radio_hw_enable)) { dev->radio_hw_enable = enabled; - report_change = 1; b43legacyinfo(wl, "Radio hardware status changed to %s\n", enabled ? "ENABLED" : "DISABLED"); - } - mutex_unlock(&wl->mutex); - - /* send the radio switch event to the system - note both a key press - * and a release are required */ - if (unlikely(report_change)) { - input_report_key(poll_dev->input, KEY_WLAN, 1); - input_report_key(poll_dev->input, KEY_WLAN, 0); - } -} - -/* Called when the RFKILL toggled in software. - * This is called without locking. */ -static int b43legacy_rfkill_soft_toggle(void *data, enum rfkill_state state) -{ - struct b43legacy_wldev *dev = data; - struct b43legacy_wl *wl = dev->wl; - int err = -EBUSY; - - if (!wl->rfkill.registered) - return 0; - - mutex_lock(&wl->mutex); - if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) - goto out_unlock; - err = 0; - switch (state) { - case RFKILL_STATE_UNBLOCKED: - if (!dev->radio_hw_enable) { - /* No luck. We can't toggle the hardware RF-kill - * button from software. */ - err = -EBUSY; - goto out_unlock; + wiphy_rfkill_set_hw_state(hw->wiphy, !enabled); + if (enabled != dev->phy.radio_on) { + if (enabled) + b43legacy_radio_turn_on(dev); + else + b43legacy_radio_turn_off(dev, 0); } - if (!dev->phy.radio_on) - b43legacy_radio_turn_on(dev); - break; - 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: + if (brought_up) { + ssb_device_disable(dev->dev, 0); + ssb_bus_may_powerdown(bus); + } + mutex_unlock(&wl->mutex); - - return err; } - -char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev) -{ - struct b43legacy_rfkill *rfk = &(dev->wl->rfkill); - - if (!rfk->registered) - return NULL; - return rfkill_get_led_name(rfk->rfkill); -} - -void b43legacy_rfkill_init(struct b43legacy_wldev *dev) -{ - struct b43legacy_wl *wl = dev->wl; - struct b43legacy_rfkill *rfk = &(wl->rfkill); - int err; - - rfk->registered = 0; - - rfk->rfkill = rfkill_allocate(dev->dev->dev, RFKILL_TYPE_WLAN); - if (!rfk->rfkill) - goto out_error; - snprintf(rfk->name, sizeof(rfk->name), - "b43legacy-%s", wiphy_name(wl->hw->wiphy)); - rfk->rfkill->name = rfk->name; - rfk->rfkill->state = RFKILL_STATE_UNBLOCKED; - rfk->rfkill->data = dev; - rfk->rfkill->toggle_radio = b43legacy_rfkill_soft_toggle; - rfk->rfkill->user_claim_unsupported = 1; - - rfk->poll_dev = input_allocate_polled_device(); - if (!rfk->poll_dev) { - rfkill_free(rfk->rfkill); - goto err_freed_rfk; - } - - rfk->poll_dev->private = dev; - rfk->poll_dev->poll = b43legacy_rfkill_poll; - rfk->poll_dev->poll_interval = 1000; /* msecs */ - - rfk->poll_dev->input->name = rfk->name; - rfk->poll_dev->input->id.bustype = BUS_HOST; - rfk->poll_dev->input->id.vendor = dev->dev->bus->boardinfo.vendor; - rfk->poll_dev->input->evbit[0] = BIT(EV_KEY); - set_bit(KEY_WLAN, rfk->poll_dev->input->keybit); - - err = rfkill_register(rfk->rfkill); - if (err) - goto err_free_polldev; - -#ifdef CONFIG_RFKILL_INPUT_MODULE - /* B43legacy RF-kill isn't useful without the rfkill-input subsystem. - * Try to load the module. */ - err = request_module("rfkill-input"); - if (err) - b43legacywarn(wl, "Failed to load the rfkill-input module." - "The built-in radio LED will not work.\n"); -#endif /* CONFIG_RFKILL_INPUT */ - - err = input_register_polled_device(rfk->poll_dev); - if (err) - goto err_unreg_rfk; - - rfk->registered = 1; - - return; -err_unreg_rfk: - rfkill_unregister(rfk->rfkill); -err_free_polldev: - input_free_polled_device(rfk->poll_dev); - rfk->poll_dev = NULL; -err_freed_rfk: - rfk->rfkill = NULL; -out_error: - rfk->registered = 0; - b43legacywarn(wl, "RF-kill button init failed\n"); -} - -void b43legacy_rfkill_exit(struct b43legacy_wldev *dev) -{ - struct b43legacy_rfkill *rfk = &(dev->wl->rfkill); - - if (!rfk->registered) - return; - rfk->registered = 0; - - input_unregister_polled_device(rfk->poll_dev); - rfkill_unregister(rfk->rfkill); - input_free_polled_device(rfk->poll_dev); - rfk->poll_dev = NULL; - rfk->rfkill = NULL; -} - diff --git a/drivers/net/wireless/b43legacy/rfkill.h b/drivers/net/wireless/b43legacy/rfkill.h index 11150a8032f0..75585571c544 100644 --- a/drivers/net/wireless/b43legacy/rfkill.h +++ b/drivers/net/wireless/b43legacy/rfkill.h @@ -1,59 +1,11 @@ #ifndef B43legacy_RFKILL_H_ #define B43legacy_RFKILL_H_ +struct ieee80211_hw; struct b43legacy_wldev; -#ifdef CONFIG_B43LEGACY_RFKILL +void b43legacy_rfkill_poll(struct ieee80211_hw *hw); -#include -#include -#include - - - -struct b43legacy_rfkill { - /* The RFKILL subsystem data structure */ - struct rfkill *rfkill; - /* The poll device for the RFKILL input button */ - struct input_polled_dev *poll_dev; - /* Did initialization succeed? Used for freeing. */ - bool registered; - /* The unique name of this rfkill switch */ - char name[sizeof("b43legacy-phy4294967295")]; -}; - -/* The init function returns void, because we are not interested - * in failing the b43 init process when rfkill init failed. */ -void b43legacy_rfkill_init(struct b43legacy_wldev *dev); -void b43legacy_rfkill_exit(struct b43legacy_wldev *dev); - -char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev); - - -#else /* CONFIG_B43LEGACY_RFKILL */ -/* No RFKILL support. */ - -struct b43legacy_rfkill { - /* empty */ -}; - -static inline void b43legacy_rfkill_alloc(struct b43legacy_wldev *dev) -{ -} -static inline void b43legacy_rfkill_free(struct b43legacy_wldev *dev) -{ -} -static inline void b43legacy_rfkill_init(struct b43legacy_wldev *dev) -{ -} -static inline void b43legacy_rfkill_exit(struct b43legacy_wldev *dev) -{ -} -static inline char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev) -{ - return NULL; -} - -#endif /* CONFIG_B43LEGACY_RFKILL */ +bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev); #endif /* B43legacy_RFKILL_H_ */ diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c index 12fca99f7578..b8e39dd06e99 100644 --- a/drivers/net/wireless/b43legacy/xmit.c +++ b/drivers/net/wireless/b43legacy/xmit.c @@ -274,7 +274,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, /* PHY TX Control word */ if (rate_ofdm) - phy_ctl |= B43legacy_TX4_PHY_OFDM; + phy_ctl |= B43legacy_TX4_PHY_ENC_OFDM; if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) phy_ctl |= B43legacy_TX4_PHY_SHORTPRMBL; switch (info->antenna_sel_tx) { diff --git a/drivers/net/wireless/b43legacy/xmit.h b/drivers/net/wireless/b43legacy/xmit.h index 62e09d02788f..91633087a20b 100644 --- a/drivers/net/wireless/b43legacy/xmit.h +++ b/drivers/net/wireless/b43legacy/xmit.h @@ -67,7 +67,9 @@ struct b43legacy_txhdr_fw3 { #define B43legacy_TX4_EFT_RTSFBOFDM 0x0010 /* RTS/CTS fallback rate type */ /* PHY TX control word */ -#define B43legacy_TX4_PHY_OFDM 0x0001 /* Data frame rate type */ +#define B43legacy_TX4_PHY_ENC 0x0003 /* Data frame encoding */ +#define B43legacy_TX4_PHY_ENC_CCK 0x0000 /* CCK */ +#define B43legacy_TX4_PHY_ENC_OFDM 0x0001 /* Data frame rate type */ #define B43legacy_TX4_PHY_SHORTPRMBL 0x0010 /* Use short preamble */ #define B43legacy_TX4_PHY_ANT 0x03C0 /* Antenna selection */ #define B43legacy_TX4_PHY_ANT0 0x0000 /* Use antenna 0 */ diff --git a/drivers/net/wireless/hostap/Kconfig b/drivers/net/wireless/hostap/Kconfig index 932d207bce23..c15db2293515 100644 --- a/drivers/net/wireless/hostap/Kconfig +++ b/drivers/net/wireless/hostap/Kconfig @@ -29,7 +29,7 @@ config HOSTAP PLX/PCI/CS version of the driver to actually use the driver. The driver can be compiled as a module and it will be called - "hostap.ko". + hostap. config HOSTAP_FIRMWARE bool "Support downloading firmware images with Host AP driver" @@ -68,7 +68,7 @@ config HOSTAP_PLX driver. The driver can be compiled as a module and will be named - "hostap_plx.ko". + hostap_plx. config HOSTAP_PCI tristate "Host AP driver for Prism2.5 PCI adaptors" @@ -81,7 +81,7 @@ config HOSTAP_PCI driver. The driver can be compiled as a module and will be named - "hostap_pci.ko". + hostap_pci. config HOSTAP_CS tristate "Host AP driver for Prism2/2.5/3 PC Cards" @@ -94,4 +94,4 @@ config HOSTAP_CS driver. The driver can be compiled as a module and will be named - "hostap_cs.ko". + hostap_cs. diff --git a/drivers/net/wireless/hostap/hostap_80211_tx.c b/drivers/net/wireless/hostap/hostap_80211_tx.c index 6693423f63fe..d313b005114e 100644 --- a/drivers/net/wireless/hostap/hostap_80211_tx.c +++ b/drivers/net/wireless/hostap/hostap_80211_tx.c @@ -377,7 +377,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct hostap_interface *iface; local_info_t *local; - int ret = 1; + int ret = NETDEV_TX_BUSY; u16 fc; struct hostap_tx_data tx; ap_tx_ret tx_ret; diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c index 3dad1cf8f241..ff9b5c882184 100644 --- a/drivers/net/wireless/hostap/hostap_hw.c +++ b/drivers/net/wireless/hostap/hostap_hw.c @@ -1423,7 +1423,7 @@ static int prism2_hw_init2(struct net_device *dev, int initial) prism2_check_sta_fw_version(local); if (hfa384x_get_rid(dev, HFA384X_RID_CNFOWNMACADDR, - &dev->dev_addr, 6, 1) < 0) { + dev->dev_addr, 6, 1) < 0) { printk("%s: could not get own MAC address\n", dev->name); } diff --git a/drivers/net/wireless/hostap/hostap_plx.c b/drivers/net/wireless/hostap/hostap_plx.c index cbf15d703201..0e5d51086a44 100644 --- a/drivers/net/wireless/hostap/hostap_plx.c +++ b/drivers/net/wireless/hostap/hostap_plx.c @@ -435,7 +435,7 @@ static int prism2_plx_probe(struct pci_dev *pdev, unsigned long pccard_attr_mem; unsigned int pccard_attr_len; void __iomem *attr_mem = NULL; - unsigned int cor_offset, cor_index; + unsigned int cor_offset = 0, cor_index = 0; u32 reg; local_info_t *local = NULL; struct net_device *dev = NULL; diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c index 97e5647ff050..742432388ca3 100644 --- a/drivers/net/wireless/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/ipw2x00/ipw2100.c @@ -3488,7 +3488,7 @@ static DEVICE_ATTR(pci, S_IRUGO, show_pci, NULL); static ssize_t show_cfg(struct device *d, struct device_attribute *attr, char *buf) { - struct ipw2100_priv *p = d->driver_data; + struct ipw2100_priv *p = dev_get_drvdata(d); return sprintf(buf, "0x%08x\n", (int)p->config); } @@ -3497,7 +3497,7 @@ static DEVICE_ATTR(cfg, S_IRUGO, show_cfg, NULL); static ssize_t show_status(struct device *d, struct device_attribute *attr, char *buf) { - struct ipw2100_priv *p = d->driver_data; + struct ipw2100_priv *p = dev_get_drvdata(d); return sprintf(buf, "0x%08x\n", (int)p->status); } @@ -3506,7 +3506,7 @@ static DEVICE_ATTR(status, S_IRUGO, show_status, NULL); static ssize_t show_capability(struct device *d, struct device_attribute *attr, char *buf) { - struct ipw2100_priv *p = d->driver_data; + struct ipw2100_priv *p = dev_get_drvdata(d); return sprintf(buf, "0x%08x\n", (int)p->capability); } @@ -4224,7 +4224,7 @@ static ssize_t show_rf_kill(struct device *d, struct device_attribute *attr, 1 - SW based RF kill active (sysfs) 2 - HW based RF kill active 3 - Both HW and SW baed RF kill active */ - struct ipw2100_priv *priv = (struct ipw2100_priv *)d->driver_data; + struct ipw2100_priv *priv = dev_get_drvdata(d); int val = ((priv->status & STATUS_RF_KILL_SW) ? 0x1 : 0x0) | (rf_kill_active(priv) ? 0x2 : 0x0); return sprintf(buf, "%i\n", val); diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index bd4dbcfe1bbe..44c29b3f6728 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c @@ -1527,7 +1527,7 @@ static DEVICE_ATTR(led, S_IWUSR | S_IRUGO, show_led, store_led); static ssize_t show_status(struct device *d, struct device_attribute *attr, char *buf) { - struct ipw_priv *p = d->driver_data; + struct ipw_priv *p = dev_get_drvdata(d); return sprintf(buf, "0x%08x\n", (int)p->status); } @@ -1536,7 +1536,7 @@ static DEVICE_ATTR(status, S_IRUGO, show_status, NULL); static ssize_t show_cfg(struct device *d, struct device_attribute *attr, char *buf) { - struct ipw_priv *p = d->driver_data; + struct ipw_priv *p = dev_get_drvdata(d); return sprintf(buf, "0x%08x\n", (int)p->config); } @@ -1545,7 +1545,7 @@ static DEVICE_ATTR(cfg, S_IRUGO, show_cfg, NULL); static ssize_t show_nic_type(struct device *d, struct device_attribute *attr, char *buf) { - struct ipw_priv *priv = d->driver_data; + struct ipw_priv *priv = dev_get_drvdata(d); return sprintf(buf, "TYPE: %d\n", priv->nic_type); } @@ -1555,7 +1555,7 @@ static ssize_t show_ucode_version(struct device *d, struct device_attribute *attr, char *buf) { u32 len = sizeof(u32), tmp = 0; - struct ipw_priv *p = d->driver_data; + struct ipw_priv *p = dev_get_drvdata(d); if (ipw_get_ordinal(p, IPW_ORD_STAT_UCODE_VERSION, &tmp, &len)) return 0; @@ -1569,7 +1569,7 @@ static ssize_t show_rtc(struct device *d, struct device_attribute *attr, char *buf) { u32 len = sizeof(u32), tmp = 0; - struct ipw_priv *p = d->driver_data; + struct ipw_priv *p = dev_get_drvdata(d); if (ipw_get_ordinal(p, IPW_ORD_STAT_RTC, &tmp, &len)) return 0; @@ -1586,14 +1586,15 @@ static DEVICE_ATTR(rtc, S_IWUSR | S_IRUGO, show_rtc, NULL); static ssize_t show_eeprom_delay(struct device *d, struct device_attribute *attr, char *buf) { - int n = ((struct ipw_priv *)d->driver_data)->eeprom_delay; + struct ipw_priv *p = dev_get_drvdata(d); + int n = p->eeprom_delay; return sprintf(buf, "%i\n", n); } static ssize_t store_eeprom_delay(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { - struct ipw_priv *p = d->driver_data; + struct ipw_priv *p = dev_get_drvdata(d); sscanf(buf, "%i", &p->eeprom_delay); return strnlen(buf, count); } @@ -1605,7 +1606,7 @@ static ssize_t show_command_event_reg(struct device *d, struct device_attribute *attr, char *buf) { u32 reg = 0; - struct ipw_priv *p = d->driver_data; + struct ipw_priv *p = dev_get_drvdata(d); reg = ipw_read_reg32(p, IPW_INTERNAL_CMD_EVENT); return sprintf(buf, "0x%08x\n", reg); @@ -1615,7 +1616,7 @@ static ssize_t store_command_event_reg(struct device *d, const char *buf, size_t count) { u32 reg; - struct ipw_priv *p = d->driver_data; + struct ipw_priv *p = dev_get_drvdata(d); sscanf(buf, "%x", ®); ipw_write_reg32(p, IPW_INTERNAL_CMD_EVENT, reg); @@ -1629,7 +1630,7 @@ static ssize_t show_mem_gpio_reg(struct device *d, struct device_attribute *attr, char *buf) { u32 reg = 0; - struct ipw_priv *p = d->driver_data; + struct ipw_priv *p = dev_get_drvdata(d); reg = ipw_read_reg32(p, 0x301100); return sprintf(buf, "0x%08x\n", reg); @@ -1639,7 +1640,7 @@ static ssize_t store_mem_gpio_reg(struct device *d, const char *buf, size_t count) { u32 reg; - struct ipw_priv *p = d->driver_data; + struct ipw_priv *p = dev_get_drvdata(d); sscanf(buf, "%x", ®); ipw_write_reg32(p, 0x301100, reg); @@ -1653,7 +1654,7 @@ static ssize_t show_indirect_dword(struct device *d, struct device_attribute *attr, char *buf) { u32 reg = 0; - struct ipw_priv *priv = d->driver_data; + struct ipw_priv *priv = dev_get_drvdata(d); if (priv->status & STATUS_INDIRECT_DWORD) reg = ipw_read_reg32(priv, priv->indirect_dword); @@ -1666,7 +1667,7 @@ static ssize_t store_indirect_dword(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { - struct ipw_priv *priv = d->driver_data; + struct ipw_priv *priv = dev_get_drvdata(d); sscanf(buf, "%x", &priv->indirect_dword); priv->status |= STATUS_INDIRECT_DWORD; @@ -1680,7 +1681,7 @@ static ssize_t show_indirect_byte(struct device *d, struct device_attribute *attr, char *buf) { u8 reg = 0; - struct ipw_priv *priv = d->driver_data; + struct ipw_priv *priv = dev_get_drvdata(d); if (priv->status & STATUS_INDIRECT_BYTE) reg = ipw_read_reg8(priv, priv->indirect_byte); @@ -1693,7 +1694,7 @@ static ssize_t store_indirect_byte(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { - struct ipw_priv *priv = d->driver_data; + struct ipw_priv *priv = dev_get_drvdata(d); sscanf(buf, "%x", &priv->indirect_byte); priv->status |= STATUS_INDIRECT_BYTE; @@ -1707,7 +1708,7 @@ static ssize_t show_direct_dword(struct device *d, struct device_attribute *attr, char *buf) { u32 reg = 0; - struct ipw_priv *priv = d->driver_data; + struct ipw_priv *priv = dev_get_drvdata(d); if (priv->status & STATUS_DIRECT_DWORD) reg = ipw_read32(priv, priv->direct_dword); @@ -1720,7 +1721,7 @@ static ssize_t store_direct_dword(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { - struct ipw_priv *priv = d->driver_data; + struct ipw_priv *priv = dev_get_drvdata(d); sscanf(buf, "%x", &priv->direct_dword); priv->status |= STATUS_DIRECT_DWORD; @@ -1747,7 +1748,7 @@ static ssize_t show_rf_kill(struct device *d, struct device_attribute *attr, 1 - SW based RF kill active (sysfs) 2 - HW based RF kill active 3 - Both HW and SW baed RF kill active */ - struct ipw_priv *priv = d->driver_data; + struct ipw_priv *priv = dev_get_drvdata(d); int val = ((priv->status & STATUS_RF_KILL_SW) ? 0x1 : 0x0) | (rf_kill_active(priv) ? 0x2 : 0x0); return sprintf(buf, "%i\n", val); @@ -1791,7 +1792,7 @@ static int ipw_radio_kill_sw(struct ipw_priv *priv, int disable_radio) static ssize_t store_rf_kill(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { - struct ipw_priv *priv = d->driver_data; + struct ipw_priv *priv = dev_get_drvdata(d); ipw_radio_kill_sw(priv, buf[0] == '1'); @@ -1803,7 +1804,7 @@ static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill); static ssize_t show_speed_scan(struct device *d, struct device_attribute *attr, char *buf) { - struct ipw_priv *priv = (struct ipw_priv *)d->driver_data; + struct ipw_priv *priv = dev_get_drvdata(d); int pos = 0, len = 0; if (priv->config & CFG_SPEED_SCAN) { while (priv->speed_scan[pos] != 0) @@ -1818,7 +1819,7 @@ static ssize_t show_speed_scan(struct device *d, struct device_attribute *attr, static ssize_t store_speed_scan(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { - struct ipw_priv *priv = (struct ipw_priv *)d->driver_data; + struct ipw_priv *priv = dev_get_drvdata(d); int channel, pos = 0; const char *p = buf; @@ -1857,14 +1858,14 @@ static DEVICE_ATTR(speed_scan, S_IWUSR | S_IRUGO, show_speed_scan, static ssize_t show_net_stats(struct device *d, struct device_attribute *attr, char *buf) { - struct ipw_priv *priv = (struct ipw_priv *)d->driver_data; + struct ipw_priv *priv = dev_get_drvdata(d); return sprintf(buf, "%c\n", (priv->config & CFG_NET_STATS) ? '1' : '0'); } static ssize_t store_net_stats(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { - struct ipw_priv *priv = (struct ipw_priv *)d->driver_data; + struct ipw_priv *priv = dev_get_drvdata(d); if (buf[0] == '1') priv->config |= CFG_NET_STATS; else @@ -3176,11 +3177,8 @@ static int ipw_load_firmware(struct ipw_priv *priv, u8 * data, size_t len) /* Start the Dma */ rc = ipw_fw_dma_enable(priv); - if (priv->sram_desc.last_cb_index > 0) { - /* the DMA is already ready this would be a bug. */ - BUG(); - goto out; - } + /* the DMA is already ready this would be a bug. */ + BUG_ON(priv->sram_desc.last_cb_index > 0); do { chunk = (struct fw_chunk *)(data + offset); @@ -11526,7 +11524,8 @@ static int ipw_prom_stop(struct net_device *dev) static int ipw_prom_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { IPW_DEBUG_INFO("prom dev->xmit\n"); - return -EOPNOTSUPP; + dev_kfree_skb(skb); + return NETDEV_TX_OK; } static const struct net_device_ops ipw_prom_netdev_ops = { diff --git a/drivers/net/wireless/ipw2x00/libipw_module.c b/drivers/net/wireless/ipw2x00/libipw_module.c index 92a26922e792..8ce6e961c5da 100644 --- a/drivers/net/wireless/ipw2x00/libipw_module.c +++ b/drivers/net/wireless/ipw2x00/libipw_module.c @@ -154,10 +154,6 @@ struct net_device *alloc_ieee80211(int sizeof_priv) goto failed; } ieee = netdev_priv(dev); -#ifdef CONFIG_COMPAT_NET_DEV_OPS - dev->hard_start_xmit = ieee80211_xmit; - dev->change_mtu = ieee80211_change_mtu; -#endif ieee->dev = dev; diff --git a/drivers/net/wireless/ipw2x00/libipw_tx.c b/drivers/net/wireless/ipw2x00/libipw_tx.c index 65a8195b3d90..da2ad5437ce5 100644 --- a/drivers/net/wireless/ipw2x00/libipw_tx.c +++ b/drivers/net/wireless/ipw2x00/libipw_tx.c @@ -539,7 +539,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&ieee->lock, flags); netif_stop_queue(dev); dev->stats.tx_errors++; - return 1; + return NETDEV_TX_BUSY; } EXPORT_SYMBOL(ieee80211_xmit); diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index 8304f6406a17..e092af09d6bf 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -5,16 +5,11 @@ config IWLWIFI select FW_LOADER select MAC80211_LEDS if IWLWIFI_LEDS select LEDS_CLASS if IWLWIFI_LEDS - select RFKILL if IWLWIFI_RFKILL config IWLWIFI_LEDS bool "Enable LED support in iwlagn and iwl3945 drivers" depends on IWLWIFI -config IWLWIFI_RFKILL - bool "Enable RF kill support in iwlagn and iwl3945 drivers" - depends on IWLWIFI - config IWLWIFI_SPECTRUM_MEASUREMENT bool "Enable Spectrum Measurement in iwlagn driver" depends on IWLWIFI @@ -75,7 +70,7 @@ config IWLAGN If you want to compile the driver as a module ( = code which can be inserted in and removed from the running kernel whenever you want), say M here and read . The - module will be called iwlagn.ko. + module will be called iwlagn. config IWL4965 @@ -113,7 +108,7 @@ config IWL3945 If you want to compile the driver as a module ( = code which can be inserted in and removed from the running kernel whenever you want), say M here and read . The - module will be called iwl3945.ko. + module will be called iwl3945. config IWL3945_SPECTRUM_MEASUREMENT bool "Enable Spectrum Measurement in iwl3945 driver" diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index d79d97ad61a5..1d4e0a226fd4 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -4,7 +4,6 @@ iwlcore-objs += iwl-rx.o iwl-tx.o iwl-sta.o iwl-calib.o iwlcore-objs += iwl-scan.o iwlcore-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o iwlcore-$(CONFIG_IWLWIFI_LEDS) += iwl-led.o -iwlcore-$(CONFIG_IWLWIFI_RFKILL) += iwl-rfkill.o iwlcore-$(CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT) += iwl-spectrum.o obj-$(CONFIG_IWLAGN) += iwlagn.o diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.c b/drivers/net/wireless/iwlwifi/iwl-3945-led.c index ac22f59be9ef..225e5f889346 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.c @@ -44,6 +44,15 @@ #include "iwl-core.h" #include "iwl-dev.h" +#ifdef CONFIG_IWLWIFI_DEBUG +static const char *led_type_str[] = { + __stringify(IWL_LED_TRG_TX), + __stringify(IWL_LED_TRG_RX), + __stringify(IWL_LED_TRG_ASSOC), + __stringify(IWL_LED_TRG_RADIO), + NULL +}; +#endif /* CONFIG_IWLWIFI_DEBUG */ static const struct { u16 brightness; @@ -61,7 +70,7 @@ static const struct { {10, 110, 110}, {5, 130, 130}, {0, 167, 167}, - /*SOLID_ON*/ + /* SOLID_ON */ {-1, IWL_LED_SOLID, 0} }; @@ -142,6 +151,26 @@ static int iwl3945_led_off(struct iwl_priv *priv, int led_id) return iwl_send_led_cmd(priv, &led_cmd); } +/* + * Set led on in case of association + * */ +static int iwl3945_led_associate(struct iwl_priv *priv, int led_id) +{ + IWL_DEBUG_LED(priv, "Associated\n"); + + priv->allow_blinking = 1; + return iwl3945_led_on(priv, led_id); +} +/* Set Led off in case of disassociation */ +static int iwl3945_led_disassociate(struct iwl_priv *priv, int led_id) +{ + IWL_DEBUG_LED(priv, "Disassociated\n"); + + priv->allow_blinking = 0; + + return 0; +} + /* * brightness call back function for Tx/Rx LED */ @@ -165,26 +194,21 @@ static void iwl3945_led_brightness_set(struct led_classdev *led_cdev, enum led_brightness brightness) { struct iwl_led *led = container_of(led_cdev, - struct iwl_led, led_dev); + struct iwl_led, led_dev); struct iwl_priv *priv = led->priv; if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; + IWL_DEBUG_LED(priv, "Led type = %s brightness = %d\n", + led_type_str[led->type], brightness); + switch (brightness) { case LED_FULL: - if (led->type == IWL_LED_TRG_ASSOC) { - priv->allow_blinking = 1; - IWL_DEBUG_LED(priv, "MAC is associated\n"); - } if (led->led_on) led->led_on(priv, IWL_LED_LINK); break; case LED_OFF: - if (led->type == IWL_LED_TRG_ASSOC) { - priv->allow_blinking = 0; - IWL_DEBUG_LED(priv, "MAC is disassociated\n"); - } if (led->led_off) led->led_off(priv, IWL_LED_LINK); break; @@ -197,8 +221,6 @@ static void iwl3945_led_brightness_set(struct led_classdev *led_cdev, } } - - /* * Register led class with the system */ @@ -237,12 +259,12 @@ static int iwl3945_led_register_led(struct iwl_priv *priv, static inline u8 get_blink_rate(struct iwl_priv *priv) { int index; - u64 current_tpt = priv->rxtxpackets; - s64 tpt = current_tpt - priv->led_tpt; + s64 tpt = priv->rxtxpackets; if (tpt < 0) tpt = -tpt; - priv->led_tpt = current_tpt; + + IWL_DEBUG_LED(priv, "tpt %lld \n", (long long)tpt); if (!priv->allow_blinking) index = IWL_MAX_BLINK_TBL; @@ -250,13 +272,9 @@ static inline u8 get_blink_rate(struct iwl_priv *priv) for (index = 0; index < IWL_MAX_BLINK_TBL; index++) if (tpt > (blink_tbl[index].brightness * IWL_1MB_RATE)) break; - return index; -} -static inline int is_rf_kill(struct iwl_priv *priv) -{ - return test_bit(STATUS_RF_KILL_HW, &priv->status) || - test_bit(STATUS_RF_KILL_SW, &priv->status); + IWL_DEBUG_LED(priv, "LED BLINK IDX=%d\n", index); + return index; } /* @@ -272,7 +290,7 @@ void iwl3945_led_background(struct iwl_priv *priv) priv->last_blink_time = 0; return; } - if (is_rf_kill(priv)) { + if (iwl_is_rfkill(priv)) { priv->last_blink_time = 0; return; } @@ -341,8 +359,8 @@ int iwl3945_led_register(struct iwl_priv *priv) IWL_LED_TRG_ASSOC, 0, trigger); /* for assoc always turn led on */ - priv->led[IWL_LED_TRG_ASSOC].led_on = iwl3945_led_on; - priv->led[IWL_LED_TRG_ASSOC].led_off = iwl3945_led_on; + priv->led[IWL_LED_TRG_ASSOC].led_on = iwl3945_led_associate; + priv->led[IWL_LED_TRG_ASSOC].led_off = iwl3945_led_disassociate; priv->led[IWL_LED_TRG_ASSOC].led_pattern = NULL; if (ret) diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index af6b9d444778..5eb538d18a80 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -38,6 +38,7 @@ #include "iwl-commands.h" #include "iwl-3945.h" +#include "iwl-sta.h" #define RS_NAME "iwl-3945-rs" @@ -683,11 +684,10 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, if (sta) rate_mask = sta->supp_rates[sband->band]; - /* Send management frames and broadcast/multicast data using lowest - * rate. */ + /* Send management frames and NO_ACK data using lowest rate. */ fc = le16_to_cpu(hdr->frame_control); if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA || - is_multicast_ether_addr(hdr->addr1) || + info->flags & IEEE80211_TX_CTL_NO_ACK || !sta || !priv_sta) { IWL_DEBUG_RATE(priv, "leave: No STA priv data to update!\n"); if (!rate_mask) @@ -696,6 +696,8 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, else info->control.rates[0].idx = rate_lowest_index(sband, sta); + if (info->flags & IEEE80211_TX_CTL_NO_ACK) + info->control.rates[0].count = 1; return; } @@ -713,13 +715,13 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) && !rs_sta->ibss_sta_added) { - u8 sta_id = iwl3945_hw_find_station(priv, hdr->addr1); + u8 sta_id = iwl_find_station(priv, hdr->addr1); if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_RATE(priv, "LQ: ADD station %pm\n", hdr->addr1); - sta_id = iwl3945_add_station(priv, - hdr->addr1, 0, CMD_ASYNC); + sta_id = iwl_add_station(priv, hdr->addr1, false, + CMD_ASYNC, NULL); } if (sta_id != IWL_INVALID_STATION) rs_sta->ibss_sta_added = 1; @@ -974,7 +976,7 @@ void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) rcu_read_lock(); - sta = ieee80211_find_sta(hw, priv->stations_39[sta_id].sta.sta.addr); + sta = ieee80211_find_sta(hw, priv->stations[sta_id].sta.sta.addr); if (!sta) { rcu_read_unlock(); return; diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 527525cc0919..46288e724889 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -98,7 +98,6 @@ const struct iwl3945_rate_info iwl3945_rates[IWL_RATE_COUNT_3945] = { * ... and set IWL_EVT_DISABLE to 1. */ void iwl3945_disable_events(struct iwl_priv *priv) { - int ret; int i; u32 base; /* SRAM address of event log header */ u32 disable_ptr; /* SRAM address of event-disable bitmap array */ @@ -159,26 +158,17 @@ void iwl3945_disable_events(struct iwl_priv *priv) return; } - ret = iwl_grab_nic_access(priv); - if (ret) { - IWL_WARN(priv, "Can not read from adapter at this time.\n"); - return; - } - disable_ptr = iwl_read_targ_mem(priv, base + (4 * sizeof(u32))); array_size = iwl_read_targ_mem(priv, base + (5 * sizeof(u32))); - iwl_release_nic_access(priv); if (IWL_EVT_DISABLE && (array_size == IWL_EVT_DISABLE_SIZE)) { IWL_DEBUG_INFO(priv, "Disabling selected uCode log events at 0x%x\n", disable_ptr); - ret = iwl_grab_nic_access(priv); for (i = 0; i < IWL_EVT_DISABLE_SIZE; i++) iwl_write_targ_mem(priv, disable_ptr + (i * sizeof(u32)), evt_disable[i]); - iwl_release_nic_access(priv); } else { IWL_DEBUG_INFO(priv, "Selected uCode log events may be disabled\n"); IWL_DEBUG_INFO(priv, " by writing \"1\"s into disable bitmap\n"); @@ -779,35 +769,6 @@ void iwl3945_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq) return ; } -u8 iwl3945_hw_find_station(struct iwl_priv *priv, const u8 *addr) -{ - int i, start = IWL_AP_ID; - int ret = IWL_INVALID_STATION; - unsigned long flags; - - if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) || - (priv->iw_mode == NL80211_IFTYPE_AP)) - start = IWL_STA_ID; - - if (is_broadcast_ether_addr(addr)) - return priv->hw_params.bcast_sta_id; - - spin_lock_irqsave(&priv->sta_lock, flags); - for (i = start; i < priv->hw_params.max_stations; i++) - if ((priv->stations_39[i].used) && - (!compare_ether_addr - (priv->stations_39[i].sta.sta.addr, addr))) { - ret = i; - goto out; - } - - IWL_DEBUG_INFO(priv, "can not find STA %pM (total %d)\n", - addr, priv->num_stations); - out: - spin_unlock_irqrestore(&priv->sta_lock, flags); - return ret; -} - /** * iwl3945_hw_build_tx_cmd_rate - Add rate portion to TX_CMD: * @@ -885,13 +846,13 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv, struct iwl_cmd *cmd, u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id, u16 tx_rate, u8 flags) { unsigned long flags_spin; - struct iwl3945_station_entry *station; + struct iwl_station_entry *station; if (sta_id == IWL_INVALID_STATION) return IWL_INVALID_STATION; spin_lock_irqsave(&priv->sta_lock, flags_spin); - station = &priv->stations_39[sta_id]; + station = &priv->stations[sta_id]; station->sta.sta.modify_mask = STA_MODIFY_TX_RATE_MSK; station->sta.rate_n_flags = cpu_to_le16(tx_rate); @@ -899,8 +860,7 @@ u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id, u16 tx_rate, u8 flags) spin_unlock_irqrestore(&priv->sta_lock, flags_spin); - iwl_send_add_sta(priv, - (struct iwl_addsta_cmd *)&station->sta, flags); + iwl_send_add_sta(priv, &station->sta, flags); IWL_DEBUG_RATE(priv, "SCALE sync station %d to rate %d\n", sta_id, tx_rate); return sta_id; @@ -908,55 +868,30 @@ u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id, u16 tx_rate, u8 flags) static int iwl3945_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src) { - int ret; - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - ret = iwl_grab_nic_access(priv); - if (ret) { - spin_unlock_irqrestore(&priv->lock, flags); - return ret; - } - if (src == IWL_PWR_SRC_VAUX) { if (pci_pme_capable(priv->pci_dev, PCI_D3cold)) { iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_PWR_SRC_VAUX, ~APMG_PS_CTRL_MSK_PWR_SRC); - iwl_release_nic_access(priv); iwl_poll_bit(priv, CSR_GPIO_IN, CSR_GPIO_IN_VAL_VAUX_PWR_SRC, CSR_GPIO_IN_BIT_AUX_POWER, 5000); - } else { - iwl_release_nic_access(priv); } } else { iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_PWR_SRC_VMAIN, ~APMG_PS_CTRL_MSK_PWR_SRC); - iwl_release_nic_access(priv); iwl_poll_bit(priv, CSR_GPIO_IN, CSR_GPIO_IN_VAL_VMAIN_PWR_SRC, CSR_GPIO_IN_BIT_AUX_POWER, 5000); /* uS */ } - spin_unlock_irqrestore(&priv->lock, flags); - return ret; + return 0; } static int iwl3945_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) { - int rc; - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - rc = iwl_grab_nic_access(priv); - if (rc) { - spin_unlock_irqrestore(&priv->lock, flags); - return rc; - } - iwl_write_direct32(priv, FH39_RCSR_RBD_BASE(0), rxq->dma_addr); iwl_write_direct32(priv, FH39_RCSR_RPTR_ADDR(0), rxq->rb_stts_dma); iwl_write_direct32(priv, FH39_RCSR_WPTR(0), 0); @@ -973,23 +908,11 @@ static int iwl3945_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) /* fake read to flush all prev I/O */ iwl_read_direct32(priv, FH39_RSSR_CTRL); - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->lock, flags); - return 0; } static int iwl3945_tx_reset(struct iwl_priv *priv) { - int rc; - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - rc = iwl_grab_nic_access(priv); - if (rc) { - spin_unlock_irqrestore(&priv->lock, flags); - return rc; - } /* bypass mode */ iwl_write_prph(priv, ALM_SCD_MODE_REG, 0x2); @@ -1017,8 +940,6 @@ static int iwl3945_tx_reset(struct iwl_priv *priv) FH39_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RSP_WAIT_TH | FH39_TSSR_TX_MSG_CONFIG_REG_VAL_RSP_WAIT_TH); - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->lock, flags); return 0; } @@ -1061,7 +982,7 @@ static int iwl3945_txq_ctx_reset(struct iwl_priv *priv) static int iwl3945_apm_init(struct iwl_priv *priv) { - int ret = 0; + int ret; iwl_power_initialize(priv); @@ -1083,10 +1004,6 @@ static int iwl3945_apm_init(struct iwl_priv *priv) goto out; } - ret = iwl_grab_nic_access(priv); - if (ret) - goto out; - /* enable DMA */ iwl_write_prph(priv, APMG_CLK_CTRL_REG, APMG_CLK_VAL_DMA_CLK_RQT | APMG_CLK_VAL_BSM_CLK_RQT); @@ -1097,7 +1014,6 @@ static int iwl3945_apm_init(struct iwl_priv *priv) iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, APMG_PCIDEV_STT_VAL_L1_ACT_DIS); - iwl_release_nic_access(priv); out: return ret; } @@ -1110,6 +1026,11 @@ static void iwl3945_nic_config(struct iwl_priv *priv) spin_lock_irqsave(&priv->lock, flags); + /* Determine HW type */ + pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &rev_id); + + IWL_DEBUG_INFO(priv, "HW Revision ID = 0x%X\n", rev_id); + if (rev_id & PCI_CFG_REV_ID_BIT_RTP) IWL_DEBUG_INFO(priv, "RTP type \n"); else if (rev_id & PCI_CFG_REV_ID_BIT_BASIC_SKU) { @@ -1163,7 +1084,6 @@ static void iwl3945_nic_config(struct iwl_priv *priv) int iwl3945_hw_nic_init(struct iwl_priv *priv) { - u8 rev_id; int rc; unsigned long flags; struct iwl_rx_queue *rxq = &priv->rxq; @@ -1172,12 +1092,6 @@ int iwl3945_hw_nic_init(struct iwl_priv *priv) priv->cfg->ops->lib->apm_ops.init(priv); spin_unlock_irqrestore(&priv->lock, flags); - /* Determine HW type */ - rc = pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &rev_id); - if (rc) - return rc; - IWL_DEBUG_INFO(priv, "HW Revision ID = 0x%X\n", rev_id); - rc = priv->cfg->ops->lib->apm_ops.set_pwr_src(priv, IWL_PWR_SRC_VMAIN); if (rc) return rc; @@ -1198,22 +1112,13 @@ int iwl3945_hw_nic_init(struct iwl_priv *priv) iwl3945_rx_init(priv, rxq); - spin_lock_irqsave(&priv->lock, flags); /* Look at using this instead: rxq->need_update = 1; iwl_rx_queue_update_write_ptr(priv, rxq); */ - rc = iwl_grab_nic_access(priv); - if (rc) { - spin_unlock_irqrestore(&priv->lock, flags); - return rc; - } iwl_write_direct32(priv, FH39_RCSR_WPTR(0), rxq->write & ~7); - iwl_release_nic_access(priv); - - spin_unlock_irqrestore(&priv->lock, flags); rc = iwl3945_txq_ctx_reset(priv); if (rc) @@ -1245,14 +1150,6 @@ void iwl3945_hw_txq_ctx_free(struct iwl_priv *priv) void iwl3945_hw_txq_ctx_stop(struct iwl_priv *priv) { int txq_id; - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - if (iwl_grab_nic_access(priv)) { - spin_unlock_irqrestore(&priv->lock, flags); - iwl3945_hw_txq_ctx_free(priv); - return; - } /* stop SCD */ iwl_write_prph(priv, ALM_SCD_MODE_REG, 0); @@ -1265,9 +1162,6 @@ void iwl3945_hw_txq_ctx_stop(struct iwl_priv *priv) 1000); } - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->lock, flags); - iwl3945_hw_txq_ctx_free(priv); } @@ -1312,12 +1206,8 @@ static void iwl3945_apm_stop(struct iwl_priv *priv) static int iwl3945_apm_reset(struct iwl_priv *priv) { - int rc; - unsigned long flags; - iwl3945_apm_stop_master(priv); - spin_lock_irqsave(&priv->lock, flags); iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); udelay(10); @@ -1327,36 +1217,31 @@ static int iwl3945_apm_reset(struct iwl_priv *priv) iwl_poll_direct_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); - rc = iwl_grab_nic_access(priv); - if (!rc) { - iwl_write_prph(priv, APMG_CLK_CTRL_REG, - APMG_CLK_VAL_BSM_CLK_RQT); + iwl_write_prph(priv, APMG_CLK_CTRL_REG, + APMG_CLK_VAL_BSM_CLK_RQT); - iwl_write_prph(priv, APMG_RTC_INT_MSK_REG, 0x0); - iwl_write_prph(priv, APMG_RTC_INT_STT_REG, + iwl_write_prph(priv, APMG_RTC_INT_MSK_REG, 0x0); + iwl_write_prph(priv, APMG_RTC_INT_STT_REG, 0xFFFFFFFF); - /* enable DMA */ - iwl_write_prph(priv, APMG_CLK_EN_REG, - APMG_CLK_VAL_DMA_CLK_RQT | - APMG_CLK_VAL_BSM_CLK_RQT); - udelay(10); + /* enable DMA */ + iwl_write_prph(priv, APMG_CLK_EN_REG, + APMG_CLK_VAL_DMA_CLK_RQT | + APMG_CLK_VAL_BSM_CLK_RQT); + udelay(10); - iwl_set_bits_prph(priv, APMG_PS_CTRL_REG, + iwl_set_bits_prph(priv, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_RESET_REQ); - udelay(5); - iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG, + udelay(5); + iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_RESET_REQ); - iwl_release_nic_access(priv); - } /* Clear the 'host command active' bit... */ clear_bit(STATUS_HCMD_ACTIVE, &priv->status); wake_up_interruptible(&priv->wait_command_queue); - spin_unlock_irqrestore(&priv->lock, flags); - return rc; + return 0; } /** @@ -1964,6 +1849,193 @@ int iwl3945_hw_reg_set_txpower(struct iwl_priv *priv, s8 power) return 0; } +static int iwl3945_send_rxon_assoc(struct iwl_priv *priv) +{ + int rc = 0; + struct iwl_rx_packet *res = NULL; + struct iwl3945_rxon_assoc_cmd rxon_assoc; + struct iwl_host_cmd cmd = { + .id = REPLY_RXON_ASSOC, + .len = sizeof(rxon_assoc), + .meta.flags = CMD_WANT_SKB, + .data = &rxon_assoc, + }; + const struct iwl_rxon_cmd *rxon1 = &priv->staging_rxon; + const struct iwl_rxon_cmd *rxon2 = &priv->active_rxon; + + if ((rxon1->flags == rxon2->flags) && + (rxon1->filter_flags == rxon2->filter_flags) && + (rxon1->cck_basic_rates == rxon2->cck_basic_rates) && + (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) { + IWL_DEBUG_INFO(priv, "Using current RXON_ASSOC. Not resending.\n"); + return 0; + } + + rxon_assoc.flags = priv->staging_rxon.flags; + rxon_assoc.filter_flags = priv->staging_rxon.filter_flags; + rxon_assoc.ofdm_basic_rates = priv->staging_rxon.ofdm_basic_rates; + rxon_assoc.cck_basic_rates = priv->staging_rxon.cck_basic_rates; + rxon_assoc.reserved = 0; + + rc = iwl_send_cmd_sync(priv, &cmd); + if (rc) + return rc; + + res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; + if (res->hdr.flags & IWL_CMD_FAILED_MSK) { + IWL_ERR(priv, "Bad return from REPLY_RXON_ASSOC command\n"); + rc = -EIO; + } + + priv->alloc_rxb_skb--; + dev_kfree_skb_any(cmd.meta.u.skb); + + return rc; +} + +/** + * iwl3945_commit_rxon - commit staging_rxon to hardware + * + * The RXON command in staging_rxon is committed to the hardware and + * the active_rxon structure is updated with the new data. This + * function correctly transitions out of the RXON_ASSOC_MSK state if + * a HW tune is required based on the RXON structure changes. + */ +static int iwl3945_commit_rxon(struct iwl_priv *priv) +{ + /* cast away the const for active_rxon in this function */ + struct iwl3945_rxon_cmd *active_rxon = (void *)&priv->active_rxon; + struct iwl3945_rxon_cmd *staging_rxon = (void *)&priv->staging_rxon; + int rc = 0; + bool new_assoc = + !!(priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK); + + if (!iwl_is_alive(priv)) + return -1; + + /* always get timestamp with Rx frame */ + staging_rxon->flags |= RXON_FLG_TSF2HOST_MSK; + + /* select antenna */ + staging_rxon->flags &= + ~(RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_SEL_MSK); + staging_rxon->flags |= iwl3945_get_antenna_flags(priv); + + rc = iwl_check_rxon_cmd(priv); + if (rc) { + IWL_ERR(priv, "Invalid RXON configuration. Not committing.\n"); + return -EINVAL; + } + + /* If we don't need to send a full RXON, we can use + * iwl3945_rxon_assoc_cmd which is used to reconfigure filter + * and other flags for the current radio configuration. */ + if (!iwl_full_rxon_required(priv)) { + rc = iwl_send_rxon_assoc(priv); + if (rc) { + IWL_ERR(priv, "Error setting RXON_ASSOC " + "configuration (%d).\n", rc); + return rc; + } + + memcpy(active_rxon, staging_rxon, sizeof(*active_rxon)); + + return 0; + } + + /* If we are currently associated and the new config requires + * an RXON_ASSOC and the new config wants the associated mask enabled, + * we must clear the associated from the active configuration + * before we apply the new config */ + if (iwl_is_associated(priv) && new_assoc) { + IWL_DEBUG_INFO(priv, "Toggling associated bit on current RXON\n"); + active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK; + + /* + * reserved4 and 5 could have been filled by the iwlcore code. + * Let's clear them before pushing to the 3945. + */ + active_rxon->reserved4 = 0; + active_rxon->reserved5 = 0; + rc = iwl_send_cmd_pdu(priv, REPLY_RXON, + sizeof(struct iwl3945_rxon_cmd), + &priv->active_rxon); + + /* If the mask clearing failed then we set + * active_rxon back to what it was previously */ + if (rc) { + active_rxon->filter_flags |= RXON_FILTER_ASSOC_MSK; + IWL_ERR(priv, "Error clearing ASSOC_MSK on current " + "configuration (%d).\n", rc); + return rc; + } + } + + IWL_DEBUG_INFO(priv, "Sending RXON\n" + "* with%s RXON_FILTER_ASSOC_MSK\n" + "* channel = %d\n" + "* bssid = %pM\n", + (new_assoc ? "" : "out"), + le16_to_cpu(staging_rxon->channel), + staging_rxon->bssid_addr); + + /* + * reserved4 and 5 could have been filled by the iwlcore code. + * Let's clear them before pushing to the 3945. + */ + staging_rxon->reserved4 = 0; + staging_rxon->reserved5 = 0; + + iwl_set_rxon_hwcrypto(priv, !priv->hw_params.sw_crypto); + + /* Apply the new configuration */ + rc = iwl_send_cmd_pdu(priv, REPLY_RXON, + sizeof(struct iwl3945_rxon_cmd), + staging_rxon); + if (rc) { + IWL_ERR(priv, "Error setting new configuration (%d).\n", rc); + return rc; + } + + memcpy(active_rxon, staging_rxon, sizeof(*active_rxon)); + + iwl_clear_stations_table(priv); + + /* If we issue a new RXON command which required a tune then we must + * send a new TXPOWER command or we won't be able to Tx any frames */ + rc = priv->cfg->ops->lib->send_tx_power(priv); + if (rc) { + IWL_ERR(priv, "Error setting Tx power (%d).\n", rc); + return rc; + } + + /* Add the broadcast address so we can send broadcast frames */ + if (iwl_add_station(priv, iwl_bcast_addr, false, CMD_SYNC, NULL) == + IWL_INVALID_STATION) { + IWL_ERR(priv, "Error adding BROADCAST address for transmit.\n"); + return -EIO; + } + + /* If we have set the ASSOC_MSK and we are in BSS mode then + * add the IWL_AP_ID to the station rate table */ + if (iwl_is_associated(priv) && + (priv->iw_mode == NL80211_IFTYPE_STATION)) + if (iwl_add_station(priv, priv->active_rxon.bssid_addr, + true, CMD_SYNC, NULL) == IWL_INVALID_STATION) { + IWL_ERR(priv, "Error adding AP address for transmit\n"); + return -EIO; + } + + /* Init the hardware's rate fallback order based on the band */ + rc = iwl3945_init_hw_rate_table(priv); + if (rc) { + IWL_ERR(priv, "Error setting HW rate table: %02X\n", rc); + return -EIO; + } + + return 0; +} + /* will add 3945 channel switch cmd handling later */ int iwl3945_hw_channel_switch(struct iwl_priv *priv, u16 channel) { @@ -2314,14 +2386,6 @@ int iwl3945_txpower_set_from_eeprom(struct iwl_priv *priv) int iwl3945_hw_rxq_stop(struct iwl_priv *priv) { int rc; - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - rc = iwl_grab_nic_access(priv); - if (rc) { - spin_unlock_irqrestore(&priv->lock, flags); - return rc; - } iwl_write_direct32(priv, FH39_RCSR_CONFIG(0), 0); rc = iwl_poll_direct_bit(priv, FH39_RSSR_STATUS, @@ -2329,28 +2393,17 @@ int iwl3945_hw_rxq_stop(struct iwl_priv *priv) if (rc < 0) IWL_ERR(priv, "Can't stop Rx DMA.\n"); - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->lock, flags); - return 0; } int iwl3945_hw_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq) { - int rc; - unsigned long flags; int txq_id = txq->q.id; struct iwl3945_shared *shared_data = priv->shared_virt; shared_data->tx_base_ptr[txq_id] = cpu_to_le32((u32)txq->q.dma_addr); - spin_lock_irqsave(&priv->lock, flags); - rc = iwl_grab_nic_access(priv); - if (rc) { - spin_unlock_irqrestore(&priv->lock, flags); - return rc; - } iwl_write_direct32(priv, FH39_CBCC_CTRL(txq_id), 0); iwl_write_direct32(priv, FH39_CBCC_BASE(txq_id), 0); @@ -2360,11 +2413,9 @@ int iwl3945_hw_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq) FH39_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD | FH39_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL | FH39_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE); - iwl_release_nic_access(priv); /* fake read to flush all prev. writes */ iwl_read32(priv, FH39_TSSR_CBB_BASE); - spin_unlock_irqrestore(&priv->lock, flags); return 0; } @@ -2384,13 +2435,25 @@ static u16 iwl3945_get_hcmd_size(u8 cmd_id, u16 len) } } + static u16 iwl3945_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data) { - u16 size = (u16)sizeof(struct iwl3945_addsta_cmd); - memcpy(data, cmd, size); - return size; + struct iwl3945_addsta_cmd *addsta = (struct iwl3945_addsta_cmd *)data; + addsta->mode = cmd->mode; + memcpy(&addsta->sta, &cmd->sta, sizeof(struct sta_id_modify)); + memcpy(&addsta->key, &cmd->key, sizeof(struct iwl4965_keyinfo)); + addsta->station_flags = cmd->station_flags; + addsta->station_flags_msk = cmd->station_flags_msk; + addsta->tid_disable_tx = cpu_to_le16(0); + addsta->rate_n_flags = cmd->rate_n_flags; + addsta->add_immediate_ba_tid = cmd->add_immediate_ba_tid; + addsta->remove_immediate_ba_tid = cmd->remove_immediate_ba_tid; + addsta->add_immediate_ba_ssn = cmd->add_immediate_ba_ssn; + + return (u16)sizeof(struct iwl3945_addsta_cmd); } + /** * iwl3945_init_hw_rate_table - Initialize the hardware rate fallback table */ @@ -2672,10 +2735,6 @@ static int iwl3945_load_bsm(struct iwl_priv *priv) inst_len = priv->ucode_init.len; data_len = priv->ucode_init_data.len; - rc = iwl_grab_nic_access(priv); - if (rc) - return rc; - iwl_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst); iwl_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata); iwl_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, inst_len); @@ -2689,10 +2748,8 @@ static int iwl3945_load_bsm(struct iwl_priv *priv) le32_to_cpu(*image)); rc = iwl3945_verify_bsm(priv); - if (rc) { - iwl_release_nic_access(priv); + if (rc) return rc; - } /* Tell BSM to copy from BSM SRAM into instruction SRAM, when asked */ iwl_write_prph(priv, BSM_WR_MEM_SRC_REG, 0x0); @@ -2724,11 +2781,14 @@ static int iwl3945_load_bsm(struct iwl_priv *priv) iwl_write_prph(priv, BSM_WR_CTRL_REG, BSM_WR_CTRL_REG_BIT_START_EN); - iwl_release_nic_access(priv); - return 0; } +static struct iwl_hcmd_ops iwl3945_hcmd = { + .rxon_assoc = iwl3945_send_rxon_assoc, + .commit_rxon = iwl3945_commit_rxon, +}; + static struct iwl_lib_ops iwl3945_lib = { .txq_attach_buf_to_tfd = iwl3945_hw_txq_attach_buf_to_tfd, .txq_free_tfd = iwl3945_hw_txq_free_tfd, @@ -2758,6 +2818,9 @@ static struct iwl_lib_ops iwl3945_lib = { }, .send_tx_power = iwl3945_send_tx_power, .is_valid_rtc_data_addr = iwl3945_hw_valid_rtc_data_addr, + .post_associate = iwl3945_post_associate, + .isr = iwl_isr_legacy, + .config_ap = iwl3945_config_ap, }; static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = { @@ -2767,6 +2830,7 @@ static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = { static struct iwl_ops iwl3945_ops = { .lib = &iwl3945_lib, + .hcmd = &iwl3945_hcmd, .utils = &iwl3945_hcmd_utils, }; @@ -2779,7 +2843,8 @@ static struct iwl_cfg iwl3945_bg_cfg = { .eeprom_size = IWL3945_EEPROM_IMG_SIZE, .eeprom_ver = EEPROM_3945_EEPROM_VERSION, .ops = &iwl3945_ops, - .mod_params = &iwl3945_mod_params + .mod_params = &iwl3945_mod_params, + .use_isr_legacy = true }; static struct iwl_cfg iwl3945_abg_cfg = { @@ -2791,7 +2856,8 @@ static struct iwl_cfg iwl3945_abg_cfg = { .eeprom_size = IWL3945_EEPROM_IMG_SIZE, .eeprom_ver = EEPROM_3945_EEPROM_VERSION, .ops = &iwl3945_ops, - .mod_params = &iwl3945_mod_params + .mod_params = &iwl3945_mod_params, + .use_isr_legacy = true }; struct pci_device_id iwl3945_hw_card_ids[] = { diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index 55188844657b..fbb3a573463e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -36,10 +36,6 @@ #include #include -/*used for rfkill*/ -#include -#include - /* Hardware specific file defines the PCI IDs table for that hardware module */ extern struct pci_device_id iwl3945_hw_card_ids[]; @@ -155,14 +151,12 @@ struct iwl3945_frame { #define STATUS_HCMD_SYNC_ACTIVE 1 /* sync host command in progress */ #define STATUS_INT_ENABLED 2 #define STATUS_RF_KILL_HW 3 -#define STATUS_RF_KILL_SW 4 #define STATUS_INIT 5 #define STATUS_ALIVE 6 #define STATUS_READY 7 #define STATUS_TEMPERATURE 8 #define STATUS_GEO_CONFIGURED 9 #define STATUS_EXIT_PENDING 10 -#define STATUS_IN_SUSPEND 11 #define STATUS_STATISTICS 12 #define STATUS_SCANNING 13 #define STATUS_SCAN_ABORTING 14 @@ -203,11 +197,6 @@ struct iwl3945_ibss_seq { * for use by iwl-*.c * *****************************************************************************/ -struct iwl3945_addsta_cmd; -extern int iwl3945_send_add_station(struct iwl_priv *priv, - struct iwl3945_addsta_cmd *sta, u8 flags); -extern u8 iwl3945_add_station(struct iwl_priv *priv, const u8 *bssid, - int is_ap, u8 flags); extern int iwl3945_power_init_handle(struct iwl_priv *priv); extern int iwl3945_eeprom_init(struct iwl_priv *priv); extern int iwl3945_calc_db_from_ratio(int sig_ratio); @@ -278,6 +267,8 @@ extern void iwl3945_hw_rx_statistics(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); extern void iwl3945_disable_events(struct iwl_priv *priv); extern int iwl4965_get_temperature(const struct iwl_priv *priv); +extern void iwl3945_post_associate(struct iwl_priv *priv); +extern void iwl3945_config_ap(struct iwl_priv *priv); /** * iwl3945_hw_find_station - Find station id for a given BSSID diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 847a6220c5e6..8f3d4bc6a03f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -163,10 +163,6 @@ static int iwl4965_load_bsm(struct iwl_priv *priv) inst_len = priv->ucode_init.len; data_len = priv->ucode_init_data.len; - ret = iwl_grab_nic_access(priv); - if (ret) - return ret; - iwl_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst); iwl_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata); iwl_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, inst_len); @@ -179,10 +175,8 @@ static int iwl4965_load_bsm(struct iwl_priv *priv) _iwl_write_prph(priv, reg_offset, le32_to_cpu(*image)); ret = iwl4965_verify_bsm(priv); - if (ret) { - iwl_release_nic_access(priv); + if (ret) return ret; - } /* Tell BSM to copy from BSM SRAM into instruction SRAM, when asked */ iwl_write_prph(priv, BSM_WR_MEM_SRC_REG, 0x0); @@ -211,7 +205,6 @@ static int iwl4965_load_bsm(struct iwl_priv *priv) * (e.g. when powering back up after power-save shutdown) */ iwl_write_prph(priv, BSM_WR_CTRL_REG, BSM_WR_CTRL_REG_BIT_START_EN); - iwl_release_nic_access(priv); return 0; } @@ -229,20 +222,12 @@ static int iwl4965_set_ucode_ptrs(struct iwl_priv *priv) { dma_addr_t pinst; dma_addr_t pdata; - unsigned long flags; int ret = 0; /* bits 35:4 for 4965 */ pinst = priv->ucode_code.p_addr >> 4; pdata = priv->ucode_data_backup.p_addr >> 4; - spin_lock_irqsave(&priv->lock, flags); - ret = iwl_grab_nic_access(priv); - if (ret) { - spin_unlock_irqrestore(&priv->lock, flags); - return ret; - } - /* Tell bootstrap uCode where to find image to load */ iwl_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst); iwl_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata); @@ -253,10 +238,6 @@ static int iwl4965_set_ucode_ptrs(struct iwl_priv *priv) * that all new ptr/size info is in place */ iwl_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, priv->ucode_code.len | BSM_DRAM_INST_LOAD); - iwl_release_nic_access(priv); - - spin_unlock_irqrestore(&priv->lock, flags); - IWL_DEBUG_INFO(priv, "Runtime uCode pointers are set.\n"); return ret; @@ -312,10 +293,12 @@ restart: queue_work(priv->workqueue, &priv->restart); } -static int is_fat_channel(__le32 rxon_flags) +static bool is_fat_channel(__le32 rxon_flags) { - return (rxon_flags & RXON_FLG_CHANNEL_MODE_PURE_40_MSK) || - (rxon_flags & RXON_FLG_CHANNEL_MODE_MIXED_MSK); + int chan_mod = le32_to_cpu(rxon_flags & RXON_FLG_CHANNEL_MODE_MSK) + >> RXON_FLG_CHANNEL_MODE_POS; + return ((chan_mod == CHANNEL_MODE_PURE_40) || + (chan_mod == CHANNEL_MODE_MIXED)); } /* @@ -358,10 +341,6 @@ static int iwl4965_apm_init(struct iwl_priv *priv) goto out; } - ret = iwl_grab_nic_access(priv); - if (ret) - goto out; - /* enable DMA */ iwl_write_prph(priv, APMG_CLK_CTRL_REG, APMG_CLK_VAL_DMA_CLK_RQT | APMG_CLK_VAL_BSM_CLK_RQT); @@ -372,7 +351,6 @@ static int iwl4965_apm_init(struct iwl_priv *priv) iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, APMG_PCIDEV_STT_VAL_L1_ACT_DIS); - iwl_release_nic_access(priv); out: return ret; } @@ -454,11 +432,9 @@ static void iwl4965_apm_stop(struct iwl_priv *priv) static int iwl4965_apm_reset(struct iwl_priv *priv) { int ret = 0; - unsigned long flags; iwl4965_apm_stop_master(priv); - spin_lock_irqsave(&priv->lock, flags); iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); @@ -475,9 +451,6 @@ static int iwl4965_apm_reset(struct iwl_priv *priv) udelay(10); - ret = iwl_grab_nic_access(priv); - if (ret) - goto out; /* Enable DMA and BSM Clock */ iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT | APMG_CLK_VAL_BSM_CLK_RQT); @@ -488,14 +461,10 @@ static int iwl4965_apm_reset(struct iwl_priv *priv) iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, APMG_PCIDEV_STT_VAL_L1_ACT_DIS); - iwl_release_nic_access(priv); - clear_bit(STATUS_HCMD_ACTIVE, &priv->status); wake_up_interruptible(&priv->wait_command_queue); out: - spin_unlock_irqrestore(&priv->lock, flags); - return ret; } @@ -681,18 +650,11 @@ static int iwl4965_alive_notify(struct iwl_priv *priv) { u32 a; unsigned long flags; - int ret; int i, chan; u32 reg_val; spin_lock_irqsave(&priv->lock, flags); - ret = iwl_grab_nic_access(priv); - if (ret) { - spin_unlock_irqrestore(&priv->lock, flags); - return ret; - } - /* Clear 4965's internal Tx Scheduler data base */ priv->scd_base_addr = iwl_read_prph(priv, IWL49_SCD_SRAM_BASE_ADDR); a = priv->scd_base_addr + IWL49_SCD_CONTEXT_DATA_OFFSET; @@ -759,10 +721,9 @@ static int iwl4965_alive_notify(struct iwl_priv *priv) iwl4965_tx_queue_set_status(priv, &priv->txq[i], ac, 0); } - iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); - return ret; + return 0; } static struct iwl_sensitivity_ranges iwl4965_sensitivity = { @@ -788,6 +749,12 @@ static struct iwl_sensitivity_ranges iwl4965_sensitivity = { .nrg_th_ofdm = 100, }; +static void iwl4965_set_ct_threshold(struct iwl_priv *priv) +{ + /* want Kelvin */ + priv->hw_params.ct_kill_threshold = CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD); +} + /** * iwl4965_hw_set_hw_params * @@ -822,7 +789,8 @@ static int iwl4965_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.rx_chains_num = 2; priv->hw_params.valid_tx_ant = ANT_A | ANT_B; priv->hw_params.valid_rx_ant = ANT_A | ANT_B; - priv->hw_params.ct_kill_threshold = CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD); + if (priv->cfg->ops->lib->temp_ops.set_ct_kill) + priv->cfg->ops->lib->temp_ops.set_ct_kill(priv); priv->hw_params.sens = &iwl4965_sensitivity; @@ -1524,7 +1492,7 @@ static int iwl4965_send_tx_power(struct iwl_priv *priv) struct iwl4965_txpowertable_cmd cmd = { 0 }; int ret; u8 band = 0; - u8 is_fat = 0; + bool is_fat = false; u8 ctrl_chan_high = 0; if (test_bit(STATUS_SCANNING, &priv->status)) { @@ -1602,7 +1570,7 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel) { int rc; u8 band = 0; - u8 is_fat = 0; + bool is_fat = false; u8 ctrl_chan_high = 0; struct iwl4965_channel_switch_cmd cmd = { 0 }; const struct iwl_channel_info *ch_info; @@ -1833,8 +1801,6 @@ static void iwl4965_tx_queue_stop_scheduler(struct iwl_priv *priv, static int iwl4965_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, u16 ssn_idx, u8 tx_fifo) { - int ret = 0; - if ((IWL49_FIRST_AMPDU_QUEUE > txq_id) || (IWL49_FIRST_AMPDU_QUEUE + IWL49_NUM_AMPDU_QUEUES <= txq_id)) { IWL_WARN(priv, @@ -1844,10 +1810,6 @@ static int iwl4965_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, return -EINVAL; } - ret = iwl_grab_nic_access(priv); - if (ret) - return ret; - iwl4965_tx_queue_stop_scheduler(priv, txq_id); iwl_clear_bits_prph(priv, IWL49_SCD_QUEUECHAIN_SEL, (1 << txq_id)); @@ -1861,8 +1823,6 @@ static int iwl4965_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, iwl_txq_ctx_deactivate(priv, txq_id); iwl4965_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 0); - iwl_release_nic_access(priv); - return 0; } @@ -1904,7 +1864,6 @@ static int iwl4965_txq_agg_enable(struct iwl_priv *priv, int txq_id, int tx_fifo, int sta_id, int tid, u16 ssn_idx) { unsigned long flags; - int ret; u16 ra_tid; if ((IWL49_FIRST_AMPDU_QUEUE > txq_id) || @@ -1922,11 +1881,6 @@ static int iwl4965_txq_agg_enable(struct iwl_priv *priv, int txq_id, iwl_sta_tx_modify_enable_tid(priv, sta_id, tid); spin_lock_irqsave(&priv->lock, flags); - ret = iwl_grab_nic_access(priv); - if (ret) { - spin_unlock_irqrestore(&priv->lock, flags); - return ret; - } /* Stop this Tx queue before configuring it */ iwl4965_tx_queue_stop_scheduler(priv, txq_id); @@ -1959,7 +1913,6 @@ static int iwl4965_txq_agg_enable(struct iwl_priv *priv, int txq_id, /* Set up Status area in SRAM, map to Tx DMA/FIFO, activate the queue */ iwl4965_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 1); - iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); return 0; @@ -2268,9 +2221,10 @@ static void iwl4965_cancel_deferred_work(struct iwl_priv *priv) cancel_work_sync(&priv->txpower_work); } - static struct iwl_hcmd_ops iwl4965_hcmd = { .rxon_assoc = iwl4965_send_rxon_assoc, + .commit_rxon = iwl_commit_rxon, + .set_rxon_chain = iwl_set_rxon_chain, }; static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = { @@ -2323,7 +2277,13 @@ static struct iwl_lib_ops iwl4965_lib = { }, .send_tx_power = iwl4965_send_tx_power, .update_chain_flags = iwl_update_chain_flags, - .temperature = iwl4965_temperature_calib, + .post_associate = iwl_post_associate, + .config_ap = iwl_config_ap, + .isr = iwl_isr_legacy, + .temp_ops = { + .temperature = iwl4965_temperature_calib, + .set_ct_kill = iwl4965_set_ct_threshold, + }, }; static struct iwl_ops iwl4965_ops = { @@ -2343,6 +2303,7 @@ struct iwl_cfg iwl4965_agn_cfg = { .eeprom_calib_ver = EEPROM_4965_TX_POWER_VERSION, .ops = &iwl4965_ops, .mod_params = &iwl4965_mod_params, + .use_isr_legacy = true }; /* Module firmware */ @@ -2350,8 +2311,6 @@ MODULE_FIRMWARE(IWL4965_MODULE_FIRMWARE(IWL4965_UCODE_API_MAX)); module_param_named(antenna, iwl4965_mod_params.antenna, int, 0444); MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])"); -module_param_named(disable, iwl4965_mod_params.disable, int, 0444); -MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])"); module_param_named(swcrypto, iwl4965_mod_params.sw_crypto, int, 0444); MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])"); module_param_named(debug, iwl4965_mod_params.debug, uint, 0444); diff --git a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h index 15cac70e36e2..4ef6804a455a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h @@ -87,6 +87,18 @@ #define IWL50_NUM_AMPDU_QUEUES 10 #define IWL50_FIRST_AMPDU_QUEUE 10 +/* 5150 only */ +#define IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF (-5) + +static inline s32 iwl_temp_calib_to_offset(struct iwl_priv *priv) +{ + u16 *temp_calib = (u16 *)iwl_eeprom_query_addr(priv, + EEPROM_5000_TEMPERATURE); + /* offset = temperature - voltage / coef */ + s32 offset = (s32)(temp_calib[0] - temp_calib[1] / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF); + return offset; +} + /* Fixed (non-configurable) rx data from phy */ /** diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 9452461ce864..b3c648ce8c7b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -124,10 +124,6 @@ static int iwl5000_apm_init(struct iwl_priv *priv) return ret; } - ret = iwl_grab_nic_access(priv); - if (ret) - return ret; - /* enable DMA */ iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT); @@ -137,8 +133,6 @@ static int iwl5000_apm_init(struct iwl_priv *priv) iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, APMG_PCIDEV_STT_VAL_L1_ACT_DIS); - iwl_release_nic_access(priv); - return ret; } @@ -165,12 +159,9 @@ static void iwl5000_apm_stop(struct iwl_priv *priv) static int iwl5000_apm_reset(struct iwl_priv *priv) { int ret = 0; - unsigned long flags; iwl5000_apm_stop_master(priv); - spin_lock_irqsave(&priv->lock, flags); - iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); udelay(10); @@ -193,10 +184,6 @@ static int iwl5000_apm_reset(struct iwl_priv *priv) goto out; } - ret = iwl_grab_nic_access(priv); - if (ret) - goto out; - /* enable DMA */ iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT); @@ -205,11 +192,7 @@ static int iwl5000_apm_reset(struct iwl_priv *priv) /* disable L1-Active */ iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, APMG_PCIDEV_STT_VAL_L1_ACT_DIS); - - iwl_release_nic_access(priv); - out: - spin_unlock_irqrestore(&priv->lock, flags); return ret; } @@ -252,11 +235,9 @@ static void iwl5000_nic_config(struct iwl_priv *priv) * (PCIe power is lost before PERST# is asserted), * causing ME FW to lose ownership and not being able to obtain it back. */ - iwl_grab_nic_access(priv); iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG, APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS, ~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS); - iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); } @@ -434,15 +415,19 @@ static const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv, return &priv->eeprom[address]; } -static s32 iwl5150_get_ct_threshold(struct iwl_priv *priv) +static void iwl5150_set_ct_threshold(struct iwl_priv *priv) { - const s32 volt2temp_coef = -5; - u16 *temp_calib = (u16 *)iwl_eeprom_query_addr(priv, - EEPROM_5000_TEMPERATURE); - /* offset = temperate - voltage / coef */ - s32 offset = temp_calib[0] - temp_calib[1] / volt2temp_coef; - s32 threshold = (s32)CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD) - offset; - return threshold * volt2temp_coef; + const s32 volt2temp_coef = IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF; + s32 threshold = (s32)CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD) - + iwl_temp_calib_to_offset(priv); + + priv->hw_params.ct_kill_threshold = threshold * volt2temp_coef; +} + +static void iwl5000_set_ct_threshold(struct iwl_priv *priv) +{ + /* want Celsius */ + priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD; } /* @@ -533,19 +518,9 @@ static int iwl5000_load_section(struct iwl_priv *priv, struct fw_desc *image, u32 dst_addr) { - int ret = 0; - unsigned long flags; - dma_addr_t phy_addr = image->p_addr; u32 byte_cnt = image->len; - spin_lock_irqsave(&priv->lock, flags); - ret = iwl_grab_nic_access(priv); - if (ret) { - spin_unlock_irqrestore(&priv->lock, flags); - return ret; - } - iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL), FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE); @@ -574,8 +549,6 @@ static int iwl5000_load_section(struct iwl_priv *priv, FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE | FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD); - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->lock, flags); return 0; } @@ -736,18 +709,11 @@ static int iwl5000_alive_notify(struct iwl_priv *priv) { u32 a; unsigned long flags; - int ret; int i, chan; u32 reg_val; spin_lock_irqsave(&priv->lock, flags); - ret = iwl_grab_nic_access(priv); - if (ret) { - spin_unlock_irqrestore(&priv->lock, flags); - return ret; - } - priv->scd_base_addr = iwl_read_prph(priv, IWL50_SCD_SRAM_BASE_ADDR); a = priv->scd_base_addr + IWL50_SCD_CONTEXT_DATA_OFFSET; for (; a < priv->scd_base_addr + IWL50_SCD_TX_STTS_BITMAP_OFFSET; @@ -815,7 +781,6 @@ static int iwl5000_alive_notify(struct iwl_priv *priv) iwl_txq_ctx_activate(priv, 8); iwl_txq_ctx_activate(priv, 9); - iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); @@ -868,17 +833,8 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant; priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant; - switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { - case CSR_HW_REV_TYPE_5150: - /* 5150 wants in Kelvin */ - priv->hw_params.ct_kill_threshold = - iwl5150_get_ct_threshold(priv); - break; - default: - /* all others want Celsius */ - priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD; - break; - } + if (priv->cfg->ops->lib->temp_ops.set_ct_kill) + priv->cfg->ops->lib->temp_ops.set_ct_kill(priv); /* Set initial calibration set */ switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { @@ -900,7 +856,6 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) break; } - return 0; } @@ -1006,7 +961,6 @@ static int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id, int tx_fifo, int sta_id, int tid, u16 ssn_idx) { unsigned long flags; - int ret; u16 ra_tid; if ((IWL50_FIRST_AMPDU_QUEUE > txq_id) || @@ -1024,11 +978,6 @@ static int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id, iwl_sta_tx_modify_enable_tid(priv, sta_id, tid); spin_lock_irqsave(&priv->lock, flags); - ret = iwl_grab_nic_access(priv); - if (ret) { - spin_unlock_irqrestore(&priv->lock, flags); - return ret; - } /* Stop this Tx queue before configuring it */ iwl5000_tx_queue_stop_scheduler(priv, txq_id); @@ -1064,7 +1013,6 @@ static int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id, /* Set up Status area in SRAM, map to Tx DMA/FIFO, activate the queue */ iwl5000_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 1); - iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); return 0; @@ -1073,8 +1021,6 @@ static int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id, static int iwl5000_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, u16 ssn_idx, u8 tx_fifo) { - int ret; - if ((IWL50_FIRST_AMPDU_QUEUE > txq_id) || (IWL50_FIRST_AMPDU_QUEUE + IWL50_NUM_AMPDU_QUEUES <= txq_id)) { IWL_ERR(priv, @@ -1084,10 +1030,6 @@ static int iwl5000_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, return -EINVAL; } - ret = iwl_grab_nic_access(priv); - if (ret) - return ret; - iwl5000_tx_queue_stop_scheduler(priv, txq_id); iwl_clear_bits_prph(priv, IWL50_SCD_AGGR_SEL, (1 << txq_id)); @@ -1101,15 +1043,16 @@ static int iwl5000_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, iwl_txq_ctx_deactivate(priv, txq_id); iwl5000_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 0); - iwl_release_nic_access(priv); - return 0; } u16 iwl5000_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data) { u16 size = (u16)sizeof(struct iwl_addsta_cmd); - memcpy(data, cmd, size); + struct iwl_addsta_cmd *addsta = (struct iwl_addsta_cmd *)data; + memcpy(addsta, cmd, size); + /* resrved in 5000 */ + addsta->rate_n_flags = cpu_to_le16(0); return size; } @@ -1434,6 +1377,17 @@ static void iwl5000_temperature(struct iwl_priv *priv) priv->temperature = le32_to_cpu(priv->statistics.general.temperature); } +static void iwl5150_temperature(struct iwl_priv *priv) +{ + u32 vt = 0; + s32 offset = iwl_temp_calib_to_offset(priv); + + vt = le32_to_cpu(priv->statistics.general.temperature); + vt = vt / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF + offset; + /* now vt hold the temperature in Kelvin */ + priv->temperature = KELVIN_TO_CELSIUS(vt); +} + /* Calc max signal level (dBm) among 3 possible receivers */ int iwl5000_calc_rssi(struct iwl_priv *priv, struct iwl_rx_phy_res *rx_resp) @@ -1474,6 +1428,8 @@ int iwl5000_calc_rssi(struct iwl_priv *priv, struct iwl_hcmd_ops iwl5000_hcmd = { .rxon_assoc = iwl5000_send_rxon_assoc, + .commit_rxon = iwl_commit_rxon, + .set_rxon_chain = iwl_set_rxon_chain, }; struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = { @@ -1502,7 +1458,6 @@ struct iwl_lib_ops iwl5000_lib = { .init_alive_start = iwl5000_init_alive_start, .alive_notify = iwl5000_alive_notify, .send_tx_power = iwl5000_send_tx_power, - .temperature = iwl5000_temperature, .update_chain_flags = iwl_update_chain_flags, .apm_ops = { .init = iwl5000_apm_init, @@ -1527,6 +1482,63 @@ struct iwl_lib_ops iwl5000_lib = { .calib_version = iwl5000_eeprom_calib_version, .query_addr = iwl5000_eeprom_query_addr, }, + .post_associate = iwl_post_associate, + .isr = iwl_isr_ict, + .config_ap = iwl_config_ap, + .temp_ops = { + .temperature = iwl5000_temperature, + .set_ct_kill = iwl5000_set_ct_threshold, + }, +}; + +static struct iwl_lib_ops iwl5150_lib = { + .set_hw_params = iwl5000_hw_set_hw_params, + .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl, + .txq_inval_byte_cnt_tbl = iwl5000_txq_inval_byte_cnt_tbl, + .txq_set_sched = iwl5000_txq_set_sched, + .txq_agg_enable = iwl5000_txq_agg_enable, + .txq_agg_disable = iwl5000_txq_agg_disable, + .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, + .txq_free_tfd = iwl_hw_txq_free_tfd, + .txq_init = iwl_hw_tx_queue_init, + .rx_handler_setup = iwl5000_rx_handler_setup, + .setup_deferred_work = iwl5000_setup_deferred_work, + .is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr, + .load_ucode = iwl5000_load_ucode, + .init_alive_start = iwl5000_init_alive_start, + .alive_notify = iwl5000_alive_notify, + .send_tx_power = iwl5000_send_tx_power, + .update_chain_flags = iwl_update_chain_flags, + .apm_ops = { + .init = iwl5000_apm_init, + .reset = iwl5000_apm_reset, + .stop = iwl5000_apm_stop, + .config = iwl5000_nic_config, + .set_pwr_src = iwl_set_pwr_src, + }, + .eeprom_ops = { + .regulatory_bands = { + EEPROM_5000_REG_BAND_1_CHANNELS, + EEPROM_5000_REG_BAND_2_CHANNELS, + EEPROM_5000_REG_BAND_3_CHANNELS, + EEPROM_5000_REG_BAND_4_CHANNELS, + EEPROM_5000_REG_BAND_5_CHANNELS, + EEPROM_5000_REG_BAND_24_FAT_CHANNELS, + EEPROM_5000_REG_BAND_52_FAT_CHANNELS + }, + .verify_signature = iwlcore_eeprom_verify_signature, + .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, + .release_semaphore = iwlcore_eeprom_release_semaphore, + .calib_version = iwl5000_eeprom_calib_version, + .query_addr = iwl5000_eeprom_query_addr, + }, + .post_associate = iwl_post_associate, + .isr = iwl_isr_ict, + .config_ap = iwl_config_ap, + .temp_ops = { + .temperature = iwl5150_temperature, + .set_ct_kill = iwl5150_set_ct_threshold, + }, }; struct iwl_ops iwl5000_ops = { @@ -1535,6 +1547,12 @@ struct iwl_ops iwl5000_ops = { .utils = &iwl5000_hcmd_utils, }; +static struct iwl_ops iwl5150_ops = { + .lib = &iwl5150_lib, + .hcmd = &iwl5000_hcmd, + .utils = &iwl5000_hcmd_utils, +}; + struct iwl_mod_params iwl50_mod_params = { .num_of_queues = IWL50_NUM_QUEUES, .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, @@ -1630,7 +1648,7 @@ struct iwl_cfg iwl5150_agn_cfg = { .ucode_api_max = IWL5150_UCODE_API_MAX, .ucode_api_min = IWL5150_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, - .ops = &iwl5000_ops, + .ops = &iwl5150_ops, .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, .eeprom_ver = EEPROM_5050_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION, @@ -1643,9 +1661,6 @@ struct iwl_cfg iwl5150_agn_cfg = { MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL5150_MODULE_FIRMWARE(IWL5150_UCODE_API_MAX)); -module_param_named(disable50, iwl50_mod_params.disable, int, 0444); -MODULE_PARM_DESC(disable50, - "manually disable the 50XX radio (default 0 [radio on])"); module_param_named(swcrypto50, iwl50_mod_params.sw_crypto, bool, 0444); MODULE_PARM_DESC(swcrypto50, "using software crypto engine (default 0 [hardware])\n"); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index cab7842a73aa..ff20e5048a55 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -52,7 +52,7 @@ /* max allowed rate miss before sync LQ cmd */ #define IWL_MISSED_RATE_MAX 15 /* max time to accum history 2 seconds */ -#define IWL_RATE_SCALE_FLUSH_INTVL (2*HZ) +#define IWL_RATE_SCALE_FLUSH_INTVL (3*HZ) static u8 rs_ht_to_legacy[] = { IWL_RATE_6M_INDEX, IWL_RATE_6M_INDEX, @@ -100,6 +100,7 @@ struct iwl_scale_tbl_info { u8 is_fat; /* 1 = 40 MHz channel width */ u8 is_dup; /* 1 = duplicated data streams */ u8 action; /* change modulation; IWL_[LEGACY/SISO/MIMO]_SWITCH_* */ + u8 max_search; /* maximun number of tables we can search */ s32 *expected_tpt; /* throughput metrics; expected_tpt_G, etc. */ u32 current_rate; /* rate_n_flags, uCode API format */ struct iwl_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */ @@ -135,7 +136,7 @@ struct iwl_lq_sta { u32 table_count; u32 total_failed; /* total failed frames, any/all rates */ u32 total_success; /* total successful frames, any/all rates */ - u32 flush_timer; /* time staying in mode before new search */ + u64 flush_timer; /* time staying in mode before new search */ u8 action_counter; /* # mode-switch actions tried */ u8 is_green; @@ -160,6 +161,7 @@ struct iwl_lq_sta { #ifdef CONFIG_MAC80211_DEBUGFS struct dentry *rs_sta_dbgfs_scale_table_file; struct dentry *rs_sta_dbgfs_stats_table_file; + struct dentry *rs_sta_dbgfs_rate_scale_data_file; struct dentry *rs_sta_dbgfs_tx_agg_tid_en_file; u32 dbg_fixed_rate; #endif @@ -167,10 +169,12 @@ struct iwl_lq_sta { /* used to be in sta_info */ int last_txrate_idx; + /* last tx rate_n_flags */ + u32 last_rate_n_flags; }; static void rs_rate_scale_perform(struct iwl_priv *priv, - struct ieee80211_hdr *hdr, + struct sk_buff *skb, struct ieee80211_sta *sta, struct iwl_lq_sta *lq_sta); static void rs_fill_link_cmd(const struct iwl_priv *priv, @@ -191,7 +195,7 @@ static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta, * 1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54, 60 MBits * "G" is the only table that supports CCK (the first 4 rates). */ -/*FIXME:RS:need to separate tables for MIMO2/MIMO3*/ + static s32 expected_tpt_A[IWL_RATE_COUNT] = { 0, 0, 0, 0, 40, 57, 72, 98, 121, 154, 177, 186, 186 }; @@ -208,11 +212,11 @@ static s32 expected_tpt_siso20MHzSGI[IWL_RATE_COUNT] = { 0, 0, 0, 0, 46, 46, 82, 110, 132, 168, 192, 202, 211 }; -static s32 expected_tpt_mimo20MHz[IWL_RATE_COUNT] = { +static s32 expected_tpt_mimo2_20MHz[IWL_RATE_COUNT] = { 0, 0, 0, 0, 74, 74, 123, 155, 179, 214, 236, 244, 251 }; -static s32 expected_tpt_mimo20MHzSGI[IWL_RATE_COUNT] = { +static s32 expected_tpt_mimo2_20MHzSGI[IWL_RATE_COUNT] = { 0, 0, 0, 0, 81, 81, 131, 164, 188, 222, 243, 251, 257 }; @@ -224,14 +228,50 @@ static s32 expected_tpt_siso40MHzSGI[IWL_RATE_COUNT] = { 0, 0, 0, 0, 83, 83, 135, 169, 193, 229, 250, 257, 264 }; -static s32 expected_tpt_mimo40MHz[IWL_RATE_COUNT] = { +static s32 expected_tpt_mimo2_40MHz[IWL_RATE_COUNT] = { 0, 0, 0, 0, 123, 123, 182, 214, 235, 264, 279, 285, 289 }; -static s32 expected_tpt_mimo40MHzSGI[IWL_RATE_COUNT] = { +static s32 expected_tpt_mimo2_40MHzSGI[IWL_RATE_COUNT] = { 0, 0, 0, 0, 131, 131, 191, 222, 242, 270, 284, 289, 293 }; +/* Expected throughput metric MIMO3 */ +static s32 expected_tpt_mimo3_20MHz[IWL_RATE_COUNT] = { + 0, 0, 0, 0, 99, 99, 153, 186, 208, 239, 256, 263, 268 +}; + +static s32 expected_tpt_mimo3_20MHzSGI[IWL_RATE_COUNT] = { + 0, 0, 0, 0, 106, 106, 162, 194, 215, 246, 262, 268, 273 +}; + +static s32 expected_tpt_mimo3_40MHz[IWL_RATE_COUNT] = { + 0, 0, 0, 0, 152, 152, 211, 239, 255, 279, 290, 294, 297 +}; + +static s32 expected_tpt_mimo3_40MHzSGI[IWL_RATE_COUNT] = { + 0, 0, 0, 0, 160, 160, 219, 245, 261, 284, 294, 297, 300 +}; + +/* mbps, mcs */ +const static struct iwl_rate_mcs_info iwl_rate_mcs[IWL_RATE_COUNT] = { + {"1", ""}, + {"2", ""}, + {"5.5", ""}, + {"11", ""}, + {"6", "BPSK 1/2"}, + {"9", "BPSK 1/2"}, + {"12", "QPSK 1/2"}, + {"18", "QPSK 3/4"}, + {"24", "16QAM 1/2"}, + {"36", "16QAM 3/4"}, + {"48", "64QAM 2/3"}, + {"54", "64QAM 3/4"}, + {"60", "64QAM 5/6"} +}; + +#define MCS_INDEX_PER_STREAM (8) + static inline u8 rs_extract_rate(u32 rate_n_flags) { return (u8)(rate_n_flags & 0xFF); @@ -543,6 +583,7 @@ static int rs_get_tbl_info_from_mcs(const u32 rate_n_flags, tbl->is_dup = 0; tbl->ant_type = (ant_msk >> RATE_MCS_ANT_POS); tbl->lq_type = LQ_NONE; + tbl->max_search = IWL_MAX_SEARCH; /* legacy rate format */ if (!(rate_n_flags & RATE_MCS_HT_MSK)) { @@ -576,8 +617,10 @@ static int rs_get_tbl_info_from_mcs(const u32 rate_n_flags, tbl->lq_type = LQ_MIMO2; /* MIMO3 */ } else { - if (num_of_ant == 3) + if (num_of_ant == 3) { + tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH; tbl->lq_type = LQ_MIMO3; + } } } return 0; @@ -611,19 +654,19 @@ static int rs_toggle_antenna(u32 valid_ant, u32 *rate_n_flags, return 1; } -/* FIXME:RS: in 4965 we don't use greenfield at all */ -/* FIXME:RS: don't use greenfield for now in TX */ -#if 0 -static inline u8 rs_use_green(struct iwl_priv *priv, struct ieee80211_conf *conf) +/* in 4965 we don't use greenfield at all */ +static inline u8 rs_use_green(struct iwl_priv *priv, + struct ieee80211_conf *conf) { - return (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) && - priv->current_ht_config.is_green_field && - !priv->current_ht_config.non_GF_STA_present; -} -#endif -static inline u8 rs_use_green(struct iwl_priv *priv, struct ieee80211_conf *conf) -{ - return 0; + u8 is_green; + + if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) + is_green = 0; + else + is_green = (conf_is_ht(conf) && + priv->current_ht_config.is_green_field && + !priv->current_ht_config.non_GF_STA_present); + return is_green; } /** @@ -735,6 +778,7 @@ static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta, tbl->is_fat = 0; tbl->is_SGI = 0; + tbl->max_search = IWL_MAX_SEARCH; } rate_mask = rs_get_supported_rates(lq_sta, NULL, tbl->lq_type); @@ -793,7 +837,7 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, IWL_DEBUG_RATE_LIMIT(priv, "get frame ack response, update rate scale window\n"); if (!ieee80211_is_data(hdr->frame_control) || - is_multicast_ether_addr(hdr->addr1)) + info->flags & IEEE80211_TX_CTL_NO_ACK) return; /* This packet was aggregated but doesn't carry rate scale info */ @@ -902,6 +946,7 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, * else look up the rate that was, finally, successful. */ tx_rate = le32_to_cpu(table->rs_table[index].rate_n_flags); + lq_sta->last_rate_n_flags = tx_rate; rs_get_tbl_info_from_mcs(tx_rate, priv->band, &tbl_type, &rs_index); /* Update frame history window with "success" if Tx got ACKed ... */ @@ -958,7 +1003,7 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, /* See if there's a better rate or modulation mode to try. */ if (sta && sta->supp_rates[sband->band]) - rs_rate_scale_perform(priv, hdr, sta, lq_sta); + rs_rate_scale_perform(priv, skb, sta, lq_sta); out: return; } @@ -988,6 +1033,8 @@ static void rs_set_stay_in_table(struct iwl_priv *priv, u8 is_legacy, lq_sta->table_count = 0; lq_sta->total_failed = 0; lq_sta->total_success = 0; + lq_sta->flush_timer = jiffies; + lq_sta->action_counter = 0; } /* @@ -1011,17 +1058,26 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta, tbl->expected_tpt = expected_tpt_siso20MHzSGI; else tbl->expected_tpt = expected_tpt_siso20MHz; - - } else if (is_mimo(tbl->lq_type)) { /* FIXME:need to separate mimo2/3 */ + } else if (is_mimo2(tbl->lq_type)) { if (tbl->is_fat && !lq_sta->is_dup) if (tbl->is_SGI) - tbl->expected_tpt = expected_tpt_mimo40MHzSGI; + tbl->expected_tpt = expected_tpt_mimo2_40MHzSGI; else - tbl->expected_tpt = expected_tpt_mimo40MHz; + tbl->expected_tpt = expected_tpt_mimo2_40MHz; else if (tbl->is_SGI) - tbl->expected_tpt = expected_tpt_mimo20MHzSGI; + tbl->expected_tpt = expected_tpt_mimo2_20MHzSGI; else - tbl->expected_tpt = expected_tpt_mimo20MHz; + tbl->expected_tpt = expected_tpt_mimo2_20MHz; + } else if (is_mimo3(tbl->lq_type)) { + if (tbl->is_fat && !lq_sta->is_dup) + if (tbl->is_SGI) + tbl->expected_tpt = expected_tpt_mimo3_40MHzSGI; + else + tbl->expected_tpt = expected_tpt_mimo3_40MHz; + else if (tbl->is_SGI) + tbl->expected_tpt = expected_tpt_mimo3_20MHzSGI; + else + tbl->expected_tpt = expected_tpt_mimo3_20MHz; } else tbl->expected_tpt = expected_tpt_G; } @@ -1130,7 +1186,7 @@ static s32 rs_get_best_rate(struct iwl_priv *priv, } /* - * Set up search table for MIMO + * Set up search table for MIMO2 */ static int rs_switch_to_mimo2(struct iwl_priv *priv, struct iwl_lq_sta *lq_sta, @@ -1158,10 +1214,10 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv, tbl->lq_type = LQ_MIMO2; tbl->is_dup = lq_sta->is_dup; tbl->action = 0; + tbl->max_search = IWL_MAX_SEARCH; rate_mask = lq_sta->active_mimo2_rate; - if (priv->current_ht_config.supported_chan_width - == IWL_CHANNEL_WIDTH_40MHZ) + if (iwl_is_fat_tx_allowed(priv, &sta->ht_cap)) tbl->is_fat = 1; else tbl->is_fat = 0; @@ -1183,7 +1239,73 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv, rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index); IWL_DEBUG_RATE(priv, "LQ: MIMO2 best rate %d mask %X\n", rate, rate_mask); + if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) { + IWL_DEBUG_RATE(priv, "Can't switch with index %d rate mask %x\n", + rate, rate_mask); + return -1; + } + tbl->current_rate = rate_n_flags_from_tbl(priv, tbl, rate, is_green); + IWL_DEBUG_RATE(priv, "LQ: Switch to new mcs %X index is green %X\n", + tbl->current_rate, is_green); + return 0; +} + +/* + * Set up search table for MIMO3 + */ +static int rs_switch_to_mimo3(struct iwl_priv *priv, + struct iwl_lq_sta *lq_sta, + struct ieee80211_conf *conf, + struct ieee80211_sta *sta, + struct iwl_scale_tbl_info *tbl, int index) +{ + u16 rate_mask; + s32 rate; + s8 is_green = lq_sta->is_green; + + if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported) + return -1; + + if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2) + == WLAN_HT_CAP_SM_PS_STATIC) + return -1; + + /* Need both Tx chains/antennas to support MIMO */ + if (priv->hw_params.tx_chains_num < 3) + return -1; + + IWL_DEBUG_RATE(priv, "LQ: try to switch to MIMO3\n"); + + tbl->lq_type = LQ_MIMO3; + tbl->is_dup = lq_sta->is_dup; + tbl->action = 0; + tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH; + rate_mask = lq_sta->active_mimo3_rate; + + if (iwl_is_fat_tx_allowed(priv, &sta->ht_cap)) + tbl->is_fat = 1; + else + tbl->is_fat = 0; + + /* FIXME: - don't toggle SGI here + if (tbl->is_fat) { + if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY) + tbl->is_SGI = 1; + else + tbl->is_SGI = 0; + } else if (priv->current_ht_config.sgf & HT_SHORT_GI_20MHZ_ONLY) + tbl->is_SGI = 1; + else + tbl->is_SGI = 0; + */ + + rs_set_expected_tpt_table(lq_sta, tbl); + + rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index); + + IWL_DEBUG_RATE(priv, "LQ: MIMO3 best rate %d mask %X\n", + rate, rate_mask); if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) { IWL_DEBUG_RATE(priv, "Can't switch with index %d rate mask %x\n", rate, rate_mask); @@ -1217,10 +1339,10 @@ static int rs_switch_to_siso(struct iwl_priv *priv, tbl->is_dup = lq_sta->is_dup; tbl->lq_type = LQ_SISO; tbl->action = 0; + tbl->max_search = IWL_MAX_SEARCH; rate_mask = lq_sta->active_siso_rate; - if (priv->current_ht_config.supported_chan_width - == IWL_CHANNEL_WIDTH_40MHZ) + if (iwl_is_fat_tx_allowed(priv, &sta->ht_cap)) tbl->is_fat = 1; else tbl->is_fat = 0; @@ -1274,15 +1396,15 @@ static int rs_move_legacy_other(struct iwl_priv *priv, u8 valid_tx_ant = priv->hw_params.valid_tx_ant; u8 tx_chains_num = priv->hw_params.tx_chains_num; int ret = 0; + u8 update_search_tbl_counter = 0; for (; ;) { + lq_sta->action_counter++; switch (tbl->action) { case IWL_LEGACY_SWITCH_ANTENNA1: case IWL_LEGACY_SWITCH_ANTENNA2: IWL_DEBUG_RATE(priv, "LQ: Legacy toggle Antenna\n"); - lq_sta->action_counter++; - if ((tbl->action == IWL_LEGACY_SWITCH_ANTENNA1 && tx_chains_num <= 1) || (tbl->action == IWL_LEGACY_SWITCH_ANTENNA2 && @@ -1298,6 +1420,7 @@ static int rs_move_legacy_other(struct iwl_priv *priv, if (rs_toggle_antenna(valid_tx_ant, &search_tbl->current_rate, search_tbl)) { + update_search_tbl_counter = 1; rs_set_expected_tpt_table(lq_sta, search_tbl); goto out; } @@ -1342,9 +1465,29 @@ static int rs_move_legacy_other(struct iwl_priv *priv, goto out; } break; + + case IWL_LEGACY_SWITCH_MIMO3_ABC: + IWL_DEBUG_RATE(priv, "LQ: Legacy switch to MIMO3\n"); + + /* Set up search table to try MIMO3 */ + memcpy(search_tbl, tbl, sz); + search_tbl->is_SGI = 0; + + search_tbl->ant_type = ANT_ABC; + + if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type)) + break; + + ret = rs_switch_to_mimo3(priv, lq_sta, conf, sta, + search_tbl, index); + if (!ret) { + lq_sta->action_counter = 0; + goto out; + } + break; } tbl->action++; - if (tbl->action > IWL_LEGACY_SWITCH_MIMO2_BC) + if (tbl->action > IWL_LEGACY_SWITCH_MIMO3_ABC) tbl->action = IWL_LEGACY_SWITCH_ANTENNA1; if (tbl->action == start_action) @@ -1357,8 +1500,10 @@ static int rs_move_legacy_other(struct iwl_priv *priv, out: lq_sta->search_better_tbl = 1; tbl->action++; - if (tbl->action > IWL_LEGACY_SWITCH_MIMO2_BC) + if (tbl->action > IWL_LEGACY_SWITCH_MIMO3_ABC) tbl->action = IWL_LEGACY_SWITCH_ANTENNA1; + if (update_search_tbl_counter) + search_tbl->action = tbl->action; return 0; } @@ -1381,6 +1526,7 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, u8 start_action = tbl->action; u8 valid_tx_ant = priv->hw_params.valid_tx_ant; u8 tx_chains_num = priv->hw_params.tx_chains_num; + u8 update_search_tbl_counter = 0; int ret; for (;;) { @@ -1401,8 +1547,10 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, memcpy(search_tbl, tbl, sz); if (rs_toggle_antenna(valid_tx_ant, - &search_tbl->current_rate, search_tbl)) + &search_tbl->current_rate, search_tbl)) { + update_search_tbl_counter = 1; goto out; + } break; case IWL_SISO_SWITCH_MIMO2_AB: case IWL_SISO_SWITCH_MIMO2_AC: @@ -1456,10 +1604,25 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, search_tbl->current_rate = rate_n_flags_from_tbl(priv, search_tbl, index, is_green); + update_search_tbl_counter = 1; goto out; + case IWL_SISO_SWITCH_MIMO3_ABC: + IWL_DEBUG_RATE(priv, "LQ: SISO switch to MIMO3\n"); + memcpy(search_tbl, tbl, sz); + search_tbl->is_SGI = 0; + search_tbl->ant_type = ANT_ABC; + + if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type)) + break; + + ret = rs_switch_to_mimo3(priv, lq_sta, conf, sta, + search_tbl, index); + if (!ret) + goto out; + break; } tbl->action++; - if (tbl->action > IWL_SISO_SWITCH_GI) + if (tbl->action > IWL_LEGACY_SWITCH_MIMO3_ABC) tbl->action = IWL_SISO_SWITCH_ANTENNA1; if (tbl->action == start_action) @@ -1471,15 +1634,18 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, out: lq_sta->search_better_tbl = 1; tbl->action++; - if (tbl->action > IWL_SISO_SWITCH_GI) + if (tbl->action > IWL_SISO_SWITCH_MIMO3_ABC) tbl->action = IWL_SISO_SWITCH_ANTENNA1; + if (update_search_tbl_counter) + search_tbl->action = tbl->action; + return 0; } /* - * Try to switch to new modulation mode from MIMO + * Try to switch to new modulation mode from MIMO2 */ -static int rs_move_mimo_to_other(struct iwl_priv *priv, +static int rs_move_mimo2_to_other(struct iwl_priv *priv, struct iwl_lq_sta *lq_sta, struct ieee80211_conf *conf, struct ieee80211_sta *sta, int index) @@ -1494,6 +1660,7 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv, u8 start_action = tbl->action; u8 valid_tx_ant = priv->hw_params.valid_tx_ant; u8 tx_chains_num = priv->hw_params.tx_chains_num; + u8 update_search_tbl_counter = 0; int ret; for (;;) { @@ -1501,7 +1668,7 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv, switch (tbl->action) { case IWL_MIMO2_SWITCH_ANTENNA1: case IWL_MIMO2_SWITCH_ANTENNA2: - IWL_DEBUG_RATE(priv, "LQ: MIMO toggle Antennas\n"); + IWL_DEBUG_RATE(priv, "LQ: MIMO2 toggle Antennas\n"); if (tx_chains_num <= 2) break; @@ -1511,8 +1678,10 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv, memcpy(search_tbl, tbl, sz); if (rs_toggle_antenna(valid_tx_ant, - &search_tbl->current_rate, search_tbl)) + &search_tbl->current_rate, search_tbl)) { + update_search_tbl_counter = 1; goto out; + } break; case IWL_MIMO2_SWITCH_SISO_A: case IWL_MIMO2_SWITCH_SISO_B: @@ -1549,7 +1718,165 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv, HT_SHORT_GI_40MHZ)) break; - IWL_DEBUG_RATE(priv, "LQ: MIMO toggle SGI/NGI\n"); + IWL_DEBUG_RATE(priv, "LQ: MIMO2 toggle SGI/NGI\n"); + + /* Set up new search table for MIMO2 */ + memcpy(search_tbl, tbl, sz); + search_tbl->is_SGI = !tbl->is_SGI; + rs_set_expected_tpt_table(lq_sta, search_tbl); + /* + * If active table already uses the fastest possible + * modulation (dual stream with short guard interval), + * and it's working well, there's no need to look + * for a better type of modulation! + */ + if (tbl->is_SGI) { + s32 tpt = lq_sta->last_tpt / 100; + if (tpt >= search_tbl->expected_tpt[index]) + break; + } + search_tbl->current_rate = + rate_n_flags_from_tbl(priv, search_tbl, + index, is_green); + update_search_tbl_counter = 1; + goto out; + + case IWL_MIMO2_SWITCH_MIMO3_ABC: + IWL_DEBUG_RATE(priv, "LQ: MIMO2 switch to MIMO3\n"); + memcpy(search_tbl, tbl, sz); + search_tbl->is_SGI = 0; + search_tbl->ant_type = ANT_ABC; + + if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type)) + break; + + ret = rs_switch_to_mimo3(priv, lq_sta, conf, sta, + search_tbl, index); + if (!ret) + goto out; + + break; + } + tbl->action++; + if (tbl->action > IWL_MIMO2_SWITCH_MIMO3_ABC) + tbl->action = IWL_MIMO2_SWITCH_ANTENNA1; + + if (tbl->action == start_action) + break; + } + search_tbl->lq_type = LQ_NONE; + return 0; + out: + lq_sta->search_better_tbl = 1; + tbl->action++; + if (tbl->action > IWL_MIMO2_SWITCH_MIMO3_ABC) + tbl->action = IWL_MIMO2_SWITCH_ANTENNA1; + if (update_search_tbl_counter) + search_tbl->action = tbl->action; + + return 0; + +} + +/* + * Try to switch to new modulation mode from MIMO3 + */ +static int rs_move_mimo3_to_other(struct iwl_priv *priv, + struct iwl_lq_sta *lq_sta, + struct ieee80211_conf *conf, + struct ieee80211_sta *sta, int index) +{ + s8 is_green = lq_sta->is_green; + struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); + struct iwl_scale_tbl_info *search_tbl = + &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); + struct iwl_rate_scale_data *window = &(tbl->win[index]); + u32 sz = (sizeof(struct iwl_scale_tbl_info) - + (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); + u8 start_action = tbl->action; + u8 valid_tx_ant = priv->hw_params.valid_tx_ant; + u8 tx_chains_num = priv->hw_params.tx_chains_num; + int ret; + u8 update_search_tbl_counter = 0; + + for (;;) { + lq_sta->action_counter++; + switch (tbl->action) { + case IWL_MIMO3_SWITCH_ANTENNA1: + case IWL_MIMO3_SWITCH_ANTENNA2: + IWL_DEBUG_RATE(priv, "LQ: MIMO3 toggle Antennas\n"); + + if (tx_chains_num <= 3) + break; + + if (window->success_ratio >= IWL_RS_GOOD_RATIO) + break; + + memcpy(search_tbl, tbl, sz); + if (rs_toggle_antenna(valid_tx_ant, + &search_tbl->current_rate, search_tbl)) + goto out; + break; + case IWL_MIMO3_SWITCH_SISO_A: + case IWL_MIMO3_SWITCH_SISO_B: + case IWL_MIMO3_SWITCH_SISO_C: + IWL_DEBUG_RATE(priv, "LQ: MIMO3 switch to SISO\n"); + + /* Set up new search table for SISO */ + memcpy(search_tbl, tbl, sz); + + if (tbl->action == IWL_MIMO3_SWITCH_SISO_A) + search_tbl->ant_type = ANT_A; + else if (tbl->action == IWL_MIMO3_SWITCH_SISO_B) + search_tbl->ant_type = ANT_B; + else + search_tbl->ant_type = ANT_C; + + if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type)) + break; + + ret = rs_switch_to_siso(priv, lq_sta, conf, sta, + search_tbl, index); + if (!ret) + goto out; + + break; + + case IWL_MIMO3_SWITCH_MIMO2_AB: + case IWL_MIMO3_SWITCH_MIMO2_AC: + case IWL_MIMO3_SWITCH_MIMO2_BC: + IWL_DEBUG_RATE(priv, "LQ: MIMO3 switch to MIMO2\n"); + + memcpy(search_tbl, tbl, sz); + search_tbl->is_SGI = 0; + if (tbl->action == IWL_MIMO3_SWITCH_MIMO2_AB) + search_tbl->ant_type = ANT_AB; + else if (tbl->action == IWL_MIMO3_SWITCH_MIMO2_AC) + search_tbl->ant_type = ANT_AC; + else + search_tbl->ant_type = ANT_BC; + + if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type)) + break; + + ret = rs_switch_to_mimo2(priv, lq_sta, conf, sta, + search_tbl, index); + if (!ret) + goto out; + + break; + + case IWL_MIMO3_SWITCH_GI: + if (!tbl->is_fat && + !(priv->current_ht_config.sgf & + HT_SHORT_GI_20MHZ)) + break; + if (tbl->is_fat && + !(priv->current_ht_config.sgf & + HT_SHORT_GI_40MHZ)) + break; + + IWL_DEBUG_RATE(priv, "LQ: MIMO3 toggle SGI/NGI\n"); /* Set up new search table for MIMO */ memcpy(search_tbl, tbl, sz); @@ -1569,12 +1896,12 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv, search_tbl->current_rate = rate_n_flags_from_tbl(priv, search_tbl, index, is_green); + update_search_tbl_counter = 1; goto out; - } tbl->action++; - if (tbl->action > IWL_MIMO2_SWITCH_GI) - tbl->action = IWL_MIMO2_SWITCH_ANTENNA1; + if (tbl->action > IWL_MIMO3_SWITCH_GI) + tbl->action = IWL_MIMO3_SWITCH_ANTENNA1; if (tbl->action == start_action) break; @@ -1584,8 +1911,11 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv, out: lq_sta->search_better_tbl = 1; tbl->action++; - if (tbl->action > IWL_MIMO2_SWITCH_GI) - tbl->action = IWL_MIMO2_SWITCH_ANTENNA1; + if (tbl->action > IWL_MIMO3_SWITCH_GI) + tbl->action = IWL_MIMO3_SWITCH_ANTENNA1; + if (update_search_tbl_counter) + search_tbl->action = tbl->action; + return 0; } @@ -1616,8 +1946,8 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta) /* Elapsed time using current modulation mode */ if (lq_sta->flush_timer) flush_interval_passed = - time_after(jiffies, - (unsigned long)(lq_sta->flush_timer + + time_after(jiffies, + (unsigned long)(lq_sta->flush_timer + IWL_RATE_SCALE_FLUSH_INTVL)); /* @@ -1676,12 +2006,14 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta) * Do rate scaling and search for new modulation mode. */ static void rs_rate_scale_perform(struct iwl_priv *priv, - struct ieee80211_hdr *hdr, + struct sk_buff *skb, struct ieee80211_sta *sta, struct iwl_lq_sta *lq_sta) { struct ieee80211_hw *hw = priv->hw; struct ieee80211_conf *conf = &hw->conf; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; int low = IWL_RATE_INVALID; int high = IWL_RATE_INVALID; int index; @@ -1707,11 +2039,10 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, IWL_DEBUG_RATE(priv, "rate scale calculate new rate for skb\n"); - /* Send management frames and broadcast/multicast data using - * lowest rate. */ + /* Send management frames and NO_ACK data using lowest rate. */ /* TODO: this could probably be improved.. */ if (!ieee80211_is_data(hdr->frame_control) || - is_multicast_ether_addr(hdr->addr1)) + info->flags & IEEE80211_TX_CTL_NO_ACK) return; if (!sta || !lq_sta) @@ -1732,6 +2063,10 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, active_tbl = 1 - lq_sta->active_tbl; tbl = &(lq_sta->lq_info[active_tbl]); + if (is_legacy(tbl->lq_type)) + lq_sta->is_green = 0; + else + lq_sta->is_green = rs_use_green(priv, conf); is_green = lq_sta->is_green; /* current tx rate */ @@ -1951,6 +2286,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, update_lq = 1; index = low; } + break; case 1: /* Increase starting rate, update uCode's rate table */ @@ -1997,8 +2333,10 @@ lq_update: rs_move_legacy_other(priv, lq_sta, conf, sta, index); else if (is_siso(tbl->lq_type)) rs_move_siso_to_other(priv, lq_sta, conf, sta, index); + else if (is_mimo2(tbl->lq_type)) + rs_move_mimo2_to_other(priv, lq_sta, conf, sta, index); else - rs_move_mimo_to_other(priv, lq_sta, conf, sta, index); + rs_move_mimo3_to_other(priv, lq_sta, conf, sta, index); /* If new "search" mode was selected, set up in uCode table */ if (lq_sta->search_better_tbl) { @@ -2014,8 +2352,11 @@ lq_update: tbl->current_rate, index); rs_fill_link_cmd(priv, lq_sta, tbl->current_rate); iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC); - } + } else + done_search = 1; + } + if (done_search && !lq_sta->stay_in_tbl) { /* If the "active" (non-search) mode was legacy, * and we've tried switching antennas, * but we haven't been able to try HT modes (not available), @@ -2023,8 +2364,7 @@ lq_update: * before next round of mode comparisons. */ tbl1 = &(lq_sta->lq_info[lq_sta->active_tbl]); if (is_legacy(tbl1->lq_type) && !conf_is_ht(conf) && - lq_sta->action_counter >= 1) { - lq_sta->action_counter = 0; + lq_sta->action_counter > tbl1->max_search) { IWL_DEBUG_RATE(priv, "LQ: STAY in legacy table\n"); rs_set_stay_in_table(priv, 1, lq_sta); } @@ -2033,7 +2373,7 @@ lq_update: * have been tried and compared, stay in this best modulation * mode for a while before next round of mode comparisons. */ if (lq_sta->enable_counter && - (lq_sta->action_counter >= IWL_ACTION_LIMIT)) { + (lq_sta->action_counter >= tbl1->max_search)) { if ((lq_sta->last_tpt > IWL_AGG_TPT_THREHOLD) && (lq_sta->tx_agg_tid_en & (1 << tid)) && (tid != MAX_TID_COUNT)) { @@ -2047,20 +2387,8 @@ lq_update: lq_sta, sta); } } - lq_sta->action_counter = 0; rs_set_stay_in_table(priv, 0, lq_sta); } - - /* - * Else, don't search for a new modulation mode. - * Put new timestamp in stay-in-modulation-mode flush timer if: - * 1) Not changing rates right now - * 2) Not just finishing up a search - * 3) flush timer is empty - */ - } else { - if ((!update_lq) && (!done_search) && (!lq_sta->flush_timer)) - lq_sta->flush_timer = jiffies; } out: @@ -2156,16 +2484,17 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta, if (sta) mask_bit = sta->supp_rates[sband->band]; - /* Send management frames and broadcast/multicast data using lowest - * rate. */ + /* Send management frames and NO_ACK data using lowest rate. */ if (!ieee80211_is_data(hdr->frame_control) || - is_multicast_ether_addr(hdr->addr1) || !sta || !lq_sta) { + info->flags & IEEE80211_TX_CTL_NO_ACK || !sta || !lq_sta) { if (!mask_bit) info->control.rates[0].idx = rate_lowest_index(sband, NULL); else info->control.rates[0].idx = rate_lowest_index(sband, sta); + if (info->flags & IEEE80211_TX_CTL_NO_ACK) + info->control.rates[0].count = 1; return; } @@ -2178,8 +2507,8 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta, if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n", hdr->addr1); - sta_id = iwl_add_station_flags(priv, hdr->addr1, - 0, CMD_ASYNC, NULL); + sta_id = iwl_add_station(priv, hdr->addr1, + false, CMD_ASYNC, NULL); } if ((sta_id != IWL_INVALID_STATION)) { lq_sta->lq.sta_id = sta_id; @@ -2189,12 +2518,33 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta, } } - if (rate_idx < 0 || rate_idx > IWL_RATE_COUNT) - rate_idx = rate_lowest_index(sband, sta); - else if (sband->band == IEEE80211_BAND_5GHZ) + if (lq_sta->last_rate_n_flags & RATE_MCS_HT_MSK) { rate_idx -= IWL_FIRST_OFDM_RATE; - + /* 6M and 9M shared same MCS index */ + rate_idx = (rate_idx > 0) ? (rate_idx - 1) : 0; + if (rs_extract_rate(lq_sta->last_rate_n_flags) >= + IWL_RATE_MIMO3_6M_PLCP) + rate_idx = rate_idx + (2 * MCS_INDEX_PER_STREAM); + else if (rs_extract_rate(lq_sta->last_rate_n_flags) >= + IWL_RATE_MIMO2_6M_PLCP) + rate_idx = rate_idx + MCS_INDEX_PER_STREAM; + info->control.rates[0].flags = IEEE80211_TX_RC_MCS; + if (lq_sta->last_rate_n_flags & RATE_MCS_SGI_MSK) + info->control.rates[0].flags |= IEEE80211_TX_RC_SHORT_GI; + if (lq_sta->last_rate_n_flags & RATE_MCS_DUP_MSK) + info->control.rates[0].flags |= IEEE80211_TX_RC_DUP_DATA; + if (lq_sta->last_rate_n_flags & RATE_MCS_FAT_MSK) + info->control.rates[0].flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; + if (lq_sta->last_rate_n_flags & RATE_MCS_GF_MSK) + info->control.rates[0].flags |= IEEE80211_TX_RC_GREEN_FIELD; + } else { + if (rate_idx < 0 || rate_idx > IWL_RATE_COUNT) + rate_idx = rate_lowest_index(sband, sta); + else if (sband->band == IEEE80211_BAND_5GHZ) + rate_idx -= IWL_FIRST_OFDM_RATE; + } info->control.rates[0].idx = rate_idx; + } static void *rs_alloc_sta(void *priv_rate, struct ieee80211_sta *sta, @@ -2246,15 +2596,16 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, lq_sta->ibss_sta_added = 0; if (priv->iw_mode == NL80211_IFTYPE_AP) { - u8 sta_id = iwl_find_station(priv, sta->addr); + u8 sta_id = iwl_find_station(priv, + sta->addr); /* for IBSS the call are from tasklet */ IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n", sta->addr); if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n", sta->addr); - sta_id = iwl_add_station_flags(priv, sta->addr, - 0, CMD_ASYNC, NULL); + sta_id = iwl_add_station(priv, sta->addr, false, + CMD_ASYNC, NULL); } if ((sta_id != IWL_INVALID_STATION)) { lq_sta->lq.sta_id = sta_id; @@ -2436,9 +2787,10 @@ static void rs_fill_link_cmd(const struct iwl_priv *priv, repeat_rate--; } - lq_cmd->agg_params.agg_frame_cnt_limit = 64; - lq_cmd->agg_params.agg_dis_start_th = 3; - lq_cmd->agg_params.agg_time_limit = cpu_to_le16(4000); + lq_cmd->agg_params.agg_frame_cnt_limit = LINK_QUAL_AGG_FRAME_LIMIT_MAX; + lq_cmd->agg_params.agg_dis_start_th = LINK_QUAL_AGG_DISABLE_START_DEF; + lq_cmd->agg_params.agg_time_limit = + cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF); } static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) @@ -2539,6 +2891,7 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, char *buff; int desc = 0; int i = 0; + int index = 0; ssize_t ret; struct iwl_lq_sta *lq_sta = file->private_data; @@ -2568,8 +2921,11 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, ((is_mimo2(tbl->lq_type)) ? "MIMO2" : "MIMO3")); desc += sprintf(buff+desc, " %s", (tbl->is_fat) ? "40MHz" : "20MHz"); - desc += sprintf(buff+desc, " %s\n", (tbl->is_SGI) ? "SGI" : ""); + desc += sprintf(buff+desc, " %s %s\n", (tbl->is_SGI) ? "SGI" : "", + (lq_sta->is_green) ? "GF enabled" : ""); } + desc += sprintf(buff+desc, "last tx rate=0x%X\n", + lq_sta->last_rate_n_flags); 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, @@ -2590,10 +2946,19 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, lq_sta->lq.general_params.start_rate_index[2], lq_sta->lq.general_params.start_rate_index[3]); - - for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) - desc += sprintf(buff+desc, " rate[%d] 0x%X\n", - i, le32_to_cpu(lq_sta->lq.rs_table[i].rate_n_flags)); + for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) { + index = iwl_hwrate_to_plcp_idx( + le32_to_cpu(lq_sta->lq.rs_table[i].rate_n_flags)); + if (is_legacy(tbl->lq_type)) { + desc += sprintf(buff+desc, " rate[%d] 0x%X %smbps\n", + i, le32_to_cpu(lq_sta->lq.rs_table[i].rate_n_flags), + iwl_rate_mcs[index].mbps); + } else { + desc += sprintf(buff+desc, " rate[%d] 0x%X %smbps (%s)\n", + i, le32_to_cpu(lq_sta->lq.rs_table[i].rate_n_flags), + iwl_rate_mcs[index].mbps, iwl_rate_mcs[index].mcs); + } + } ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc); kfree(buff); @@ -2620,13 +2985,14 @@ static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file, return -ENOMEM; for (i = 0; i < LQ_SIZE; i++) { - desc += sprintf(buff+desc, "%s type=%d SGI=%d FAT=%d DUP=%d\n" + desc += sprintf(buff+desc, "%s type=%d SGI=%d FAT=%d DUP=%d GF=%d\n" "rate=0x%X\n", lq_sta->active_tbl == i ? "*" : "x", lq_sta->lq_info[i].lq_type, lq_sta->lq_info[i].is_SGI, lq_sta->lq_info[i].is_fat, lq_sta->lq_info[i].is_dup, + lq_sta->is_green, lq_sta->lq_info[i].current_rate); for (j = 0; j < IWL_RATE_COUNT; j++) { desc += sprintf(buff+desc, @@ -2646,6 +3012,43 @@ static const struct file_operations rs_sta_dbgfs_stats_table_ops = { .open = open_file_generic, }; +static ssize_t rs_sta_dbgfs_rate_scale_data_read(struct file *file, + char __user *user_buf, size_t count, loff_t *ppos) +{ + char buff[120]; + int desc = 0; + ssize_t ret; + + struct iwl_lq_sta *lq_sta = file->private_data; + struct iwl_priv *priv; + struct iwl_scale_tbl_info *tbl = &lq_sta->lq_info[lq_sta->active_tbl]; + + priv = lq_sta->drv; + + if (is_Ht(tbl->lq_type)) + desc += sprintf(buff+desc, + "Bit Rate= %d Mb/s\n", + tbl->expected_tpt[lq_sta->last_txrate_idx]); + else + desc += sprintf(buff+desc, + "Bit Rate= %d Mb/s\n", + iwl_rates[lq_sta->last_txrate_idx].ieee >> 1); + desc += sprintf(buff+desc, + "Signal Level= %d dBm\tNoise Level= %d dBm\n", + priv->last_rx_rssi, priv->last_rx_noise); + desc += sprintf(buff+desc, + "Tsf= 0x%llx\tBeacon time= 0x%08X\n", + priv->last_tsf, priv->last_beacon_time); + + ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc); + return ret; +} + +static const struct file_operations rs_sta_dbgfs_rate_scale_data_ops = { + .read = rs_sta_dbgfs_rate_scale_data_read, + .open = open_file_generic, +}; + static void rs_add_debugfs(void *priv, void *priv_sta, struct dentry *dir) { @@ -2656,6 +3059,9 @@ static void rs_add_debugfs(void *priv, void *priv_sta, lq_sta->rs_sta_dbgfs_stats_table_file = debugfs_create_file("rate_stats_table", 0600, dir, lq_sta, &rs_sta_dbgfs_stats_table_ops); + lq_sta->rs_sta_dbgfs_rate_scale_data_file = + debugfs_create_file("rate_scale_data", 0600, dir, + lq_sta, &rs_sta_dbgfs_rate_scale_data_ops); lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file = debugfs_create_u8("tx_agg_tid_enable", 0600, dir, &lq_sta->tx_agg_tid_en); @@ -2667,6 +3073,7 @@ static void rs_remove_debugfs(void *priv, void *priv_sta) struct iwl_lq_sta *lq_sta = priv_sta; debugfs_remove(lq_sta->rs_sta_dbgfs_scale_table_file); debugfs_remove(lq_sta->rs_sta_dbgfs_stats_table_file); + debugfs_remove(lq_sta->rs_sta_dbgfs_rate_scale_data_file); debugfs_remove(lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file); } #endif diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h index ab59acc405d9..25050bf315a2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h @@ -241,6 +241,7 @@ enum { #define IWL_LEGACY_SWITCH_MIMO2_AB 3 #define IWL_LEGACY_SWITCH_MIMO2_AC 4 #define IWL_LEGACY_SWITCH_MIMO2_BC 5 +#define IWL_LEGACY_SWITCH_MIMO3_ABC 6 /* possible actions when in siso mode */ #define IWL_SISO_SWITCH_ANTENNA1 0 @@ -249,6 +250,8 @@ enum { #define IWL_SISO_SWITCH_MIMO2_AC 3 #define IWL_SISO_SWITCH_MIMO2_BC 4 #define IWL_SISO_SWITCH_GI 5 +#define IWL_SISO_SWITCH_MIMO3_ABC 6 + /* possible actions when in mimo mode */ #define IWL_MIMO2_SWITCH_ANTENNA1 0 @@ -257,6 +260,23 @@ enum { #define IWL_MIMO2_SWITCH_SISO_B 3 #define IWL_MIMO2_SWITCH_SISO_C 4 #define IWL_MIMO2_SWITCH_GI 5 +#define IWL_MIMO2_SWITCH_MIMO3_ABC 6 + + +/* possible actions when in mimo3 mode */ +#define IWL_MIMO3_SWITCH_ANTENNA1 0 +#define IWL_MIMO3_SWITCH_ANTENNA2 1 +#define IWL_MIMO3_SWITCH_SISO_A 2 +#define IWL_MIMO3_SWITCH_SISO_B 3 +#define IWL_MIMO3_SWITCH_SISO_C 4 +#define IWL_MIMO3_SWITCH_MIMO2_AB 5 +#define IWL_MIMO3_SWITCH_MIMO2_AC 6 +#define IWL_MIMO3_SWITCH_MIMO2_BC 7 +#define IWL_MIMO3_SWITCH_GI 8 + + +#define IWL_MAX_11N_MIMO3_SEARCH IWL_MIMO3_SWITCH_GI +#define IWL_MAX_SEARCH IWL_MIMO2_SWITCH_MIMO3_ABC /*FIXME:RS:add possible actions for MIMO3*/ @@ -307,6 +327,13 @@ enum iwl_table_type { #define ANT_BC (ANT_B | ANT_C) #define ANT_ABC (ANT_AB | ANT_C) +#define IWL_MAX_MCS_DISPLAY_SIZE 12 + +struct iwl_rate_mcs_info { + char mbps[IWL_MAX_MCS_DISPLAY_SIZE]; + char mcs[IWL_MAX_MCS_DISPLAY_SIZE]; +}; + static inline u8 num_of_ant(u8 mask) { return !!((mask) & ANT_A) + diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index f46ba2475776..6d1519e1f011 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -102,7 +102,7 @@ MODULE_ALIAS("iwl4965"); * function correctly transitions out of the RXON_ASSOC_MSK state if * a HW tune is required based on the RXON structure changes. */ -static int iwl_commit_rxon(struct iwl_priv *priv) +int iwl_commit_rxon(struct iwl_priv *priv) { /* cast away the const for active_rxon in this function */ struct iwl_rxon_cmd *active_rxon = (void *)&priv->active_rxon; @@ -190,8 +190,7 @@ static int iwl_commit_rxon(struct iwl_priv *priv) iwl_clear_stations_table(priv); - if (!priv->error_recovering) - priv->start_calib = 0; + priv->start_calib = 0; /* Add the broadcast address so we can send broadcast frames */ if (iwl_rxon_add_station(priv, iwl_bcast_addr, 0) == @@ -246,8 +245,9 @@ static int iwl_commit_rxon(struct iwl_priv *priv) void iwl_update_chain_flags(struct iwl_priv *priv) { - iwl_set_rxon_chain(priv); - iwl_commit_rxon(priv); + if (priv->cfg->ops->hcmd->set_rxon_chain) + priv->cfg->ops->hcmd->set_rxon_chain(priv); + iwlcore_commit_rxon(priv); } static void iwl_clear_free_frames(struct iwl_priv *priv) @@ -503,24 +503,12 @@ int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, int iwl_hw_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq) { - int ret; - unsigned long flags; int txq_id = txq->q.id; - spin_lock_irqsave(&priv->lock, flags); - ret = iwl_grab_nic_access(priv); - if (ret) { - spin_unlock_irqrestore(&priv->lock, flags); - return ret; - } - /* Circular buffer (TFD queue in DRAM) physical base address */ iwl_write_direct32(priv, FH_MEM_CBBC_QUEUE(txq_id), txq->q.dma_addr >> 8); - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->lock, flags); - return 0; } @@ -531,76 +519,6 @@ int iwl_hw_tx_queue_init(struct iwl_priv *priv, * ******************************************************************************/ -static void iwl_ht_conf(struct iwl_priv *priv, - struct ieee80211_bss_conf *bss_conf) -{ - struct ieee80211_sta_ht_cap *ht_conf; - struct iwl_ht_info *iwl_conf = &priv->current_ht_config; - struct ieee80211_sta *sta; - - IWL_DEBUG_MAC80211(priv, "enter: \n"); - - if (!iwl_conf->is_ht) - return; - - - /* - * It is totally wrong to base global information on something - * that is valid only when associated, alas, this driver works - * that way and I don't know how to fix it. - */ - - rcu_read_lock(); - sta = ieee80211_find_sta(priv->hw, priv->bssid); - if (!sta) { - rcu_read_unlock(); - return; - } - ht_conf = &sta->ht_cap; - - if (ht_conf->cap & IEEE80211_HT_CAP_SGI_20) - iwl_conf->sgf |= HT_SHORT_GI_20MHZ; - if (ht_conf->cap & IEEE80211_HT_CAP_SGI_40) - iwl_conf->sgf |= HT_SHORT_GI_40MHZ; - - iwl_conf->is_green_field = !!(ht_conf->cap & IEEE80211_HT_CAP_GRN_FLD); - iwl_conf->max_amsdu_size = - !!(ht_conf->cap & IEEE80211_HT_CAP_MAX_AMSDU); - - iwl_conf->supported_chan_width = - !!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40); - - /* - * XXX: The HT configuration needs to be moved into iwl_mac_config() - * to be done there correctly. - */ - - iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE; - if (conf_is_ht40_minus(&priv->hw->conf)) - iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_BELOW; - else if (conf_is_ht40_plus(&priv->hw->conf)) - iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_ABOVE; - - /* If no above or below channel supplied disable FAT channel */ - if (iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_ABOVE && - iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_BELOW) - iwl_conf->supported_chan_width = 0; - - iwl_conf->sm_ps = (u8)((ht_conf->cap & IEEE80211_HT_CAP_SM_PS) >> 2); - - memcpy(&iwl_conf->mcs, &ht_conf->mcs, 16); - - iwl_conf->tx_chan_width = iwl_conf->supported_chan_width != 0; - iwl_conf->ht_protection = - bss_conf->ht.operation_mode & IEEE80211_HT_OP_MODE_PROTECTION; - iwl_conf->non_GF_STA_present = - !!(bss_conf->ht.operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); - - rcu_read_unlock(); - - IWL_DEBUG_MAC80211(priv, "leave\n"); -} - #define MAX_UCODE_BEACON_INTERVAL 4096 static u16 iwl_adjust_beacon_interval(u16 beacon_val) @@ -636,7 +554,8 @@ static void iwl_setup_rxon_timing(struct iwl_priv *priv) beacon_int = iwl_adjust_beacon_interval(priv->beacon_int); priv->rxon_timing.atim_window = 0; } else { - beacon_int = iwl_adjust_beacon_interval(conf->beacon_int); + beacon_int = iwl_adjust_beacon_interval( + priv->vif->bss_conf.beacon_int); /* TODO: we need to get atim_window from upper stack * for now we set to 0 */ @@ -657,23 +576,6 @@ static void iwl_setup_rxon_timing(struct iwl_priv *priv) le16_to_cpu(priv->rxon_timing.atim_window)); } -static int iwl_set_mode(struct iwl_priv *priv, int mode) -{ - iwl_connection_init_rx_config(priv, mode); - iwl_set_rxon_chain(priv); - memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); - - iwl_clear_stations_table(priv); - - /* dont commit rxon if rf-kill is on*/ - if (!iwl_is_ready_rf(priv)) - return -EAGAIN; - - iwl_commit_rxon(priv); - - return 0; -} - /****************************************************************************** * * Generic RX handler implementations @@ -795,6 +697,7 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv, struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags); unsigned long status = priv->status; + unsigned long reg_flags; IWL_DEBUG_RF_KILL(priv, "Card state received: HW:%s SW:%s\n", (flags & HW_CARD_DISABLED) ? "Kill" : "On", @@ -806,32 +709,25 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv, iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); - if (!iwl_grab_nic_access(priv)) { - iwl_write_direct32( - priv, HBUS_TARG_MBX_C, - HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED); - - iwl_release_nic_access(priv); - } + iwl_write_direct32(priv, HBUS_TARG_MBX_C, + HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED); if (!(flags & RXON_CARD_DISABLED)) { iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); - if (!iwl_grab_nic_access(priv)) { - iwl_write_direct32( - priv, HBUS_TARG_MBX_C, + iwl_write_direct32(priv, HBUS_TARG_MBX_C, HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED); - iwl_release_nic_access(priv); - } } if (flags & RF_CARD_DISABLED) { iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); iwl_read32(priv, CSR_UCODE_DRV_GP1); + spin_lock_irqsave(&priv->reg_lock, reg_flags); if (!iwl_grab_nic_access(priv)) iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->reg_lock, reg_flags); } } @@ -841,33 +737,19 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv, clear_bit(STATUS_RF_KILL_HW, &priv->status); - if (flags & SW_CARD_DISABLED) - set_bit(STATUS_RF_KILL_SW, &priv->status); - else - clear_bit(STATUS_RF_KILL_SW, &priv->status); - if (!(flags & RXON_CARD_DISABLED)) iwl_scan_cancel(priv); if ((test_bit(STATUS_RF_KILL_HW, &status) != - test_bit(STATUS_RF_KILL_HW, &priv->status)) || - (test_bit(STATUS_RF_KILL_SW, &status) != - test_bit(STATUS_RF_KILL_SW, &priv->status))) - queue_work(priv->workqueue, &priv->rf_kill); + test_bit(STATUS_RF_KILL_HW, &priv->status))) + wiphy_rfkill_set_hw_state(priv->hw->wiphy, + test_bit(STATUS_RF_KILL_HW, &priv->status)); else wake_up_interruptible(&priv->wait_command_queue); } int iwl_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src) { - int ret; - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - ret = iwl_grab_nic_access(priv); - if (ret) - goto err; - if (src == IWL_PWR_SRC_VAUX) { if (pci_pme_capable(priv->pci_dev, PCI_D3cold)) iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG, @@ -879,10 +761,7 @@ int iwl_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src) ~APMG_PS_CTRL_MSK_PWR_SRC); } - iwl_release_nic_access(priv); -err: - spin_unlock_irqrestore(&priv->lock, flags); - return ret; + return 0; } /** @@ -946,6 +825,7 @@ void iwl_rx_handle(struct iwl_priv *priv) unsigned long flags; u8 fill_rx = 0; u32 count = 8; + int total_empty; /* uCode's read index (stored in shared DRAM) indicates the last Rx * buffer that the driver may process (last buffer filled by ucode). */ @@ -956,7 +836,12 @@ void iwl_rx_handle(struct iwl_priv *priv) if (i == r) IWL_DEBUG_RX(priv, "r = %d, i = %d\n", r, i); - if (iwl_rx_queue_space(rxq) > (RX_QUEUE_SIZE / 2)) + /* calculate total frames need to be restock after handling RX */ + total_empty = r - priv->rxq.write_actual; + if (total_empty < 0) + total_empty += RX_QUEUE_SIZE; + + if (total_empty > (RX_QUEUE_SIZE / 2)) fill_rx = 1; while (i != r) { @@ -995,6 +880,7 @@ void iwl_rx_handle(struct iwl_priv *priv) IWL_DEBUG_RX(priv, "r = %d, i = %d, %s, 0x%02x\n", r, i, get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd); priv->rx_handlers[pkt->hdr.cmd] (priv, rxb); + priv->isr_stats.rx_handlers[pkt->hdr.cmd]++; } else { /* No handling needed */ IWL_DEBUG_RX(priv, @@ -1032,7 +918,7 @@ void iwl_rx_handle(struct iwl_priv *priv) count++; if (count >= 8) { priv->rxq.read = i; - iwl_rx_queue_restock(priv); + iwl_rx_replenish_now(priv); count = 0; } } @@ -1040,7 +926,10 @@ void iwl_rx_handle(struct iwl_priv *priv) /* Backtrack one entry */ priv->rxq.read = i; - iwl_rx_queue_restock(priv); + if (fill_rx) + iwl_rx_replenish_now(priv); + else + iwl_rx_queue_restock(priv); } /* call this function to flush any scheduled tasklet */ @@ -1051,24 +940,7 @@ static inline void iwl_synchronize_irq(struct iwl_priv *priv) tasklet_kill(&priv->irq_tasklet); } -static void iwl_error_recovery(struct iwl_priv *priv) -{ - unsigned long flags; - - memcpy(&priv->staging_rxon, &priv->recovery_rxon, - sizeof(priv->staging_rxon)); - priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl_commit_rxon(priv); - - iwl_rxon_add_station(priv, priv->bssid, 1); - - spin_lock_irqsave(&priv->lock, flags); - priv->assoc_id = le16_to_cpu(priv->staging_rxon.assoc_id); - priv->error_recovering = 0; - spin_unlock_irqrestore(&priv->lock, flags); -} - -static void iwl_irq_tasklet(struct iwl_priv *priv) +static void iwl_irq_tasklet_legacy(struct iwl_priv *priv) { u32 inta, handled = 0; u32 inta_fh; @@ -1116,6 +988,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) /* Tell the device to stop sending interrupts */ iwl_disable_interrupts(priv); + priv->isr_stats.hw++; iwl_irq_handle_error(priv); handled |= CSR_INT_BIT_HW_ERR; @@ -1128,13 +1001,17 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) #ifdef CONFIG_IWLWIFI_DEBUG if (priv->debug_level & (IWL_DL_ISR)) { /* NIC fires this, but we don't use it, redundant with WAKEUP */ - if (inta & CSR_INT_BIT_SCD) + if (inta & CSR_INT_BIT_SCD) { IWL_DEBUG_ISR(priv, "Scheduler finished to transmit " "the frame/frames.\n"); + priv->isr_stats.sch++; + } /* Alive notification via Rx interrupt will do the real work */ - if (inta & CSR_INT_BIT_ALIVE) + if (inta & CSR_INT_BIT_ALIVE) { IWL_DEBUG_ISR(priv, "Alive interrupt\n"); + priv->isr_stats.alive++; + } } #endif /* Safely ignore these bits for debug checks below */ @@ -1150,6 +1027,8 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) IWL_DEBUG_RF_KILL(priv, "RF_KILL bit toggled to %s.\n", hw_rf_kill ? "disable radio" : "enable radio"); + priv->isr_stats.rfkill++; + /* driver only loads ucode once setting the interface up. * the driver allows loading the ucode even if the radio * is killed. Hence update the killswitch state here. The @@ -1160,7 +1039,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) set_bit(STATUS_RF_KILL_HW, &priv->status); else clear_bit(STATUS_RF_KILL_HW, &priv->status); - queue_work(priv->workqueue, &priv->rf_kill); + wiphy_rfkill_set_hw_state(priv->hw->wiphy, hw_rf_kill); } handled |= CSR_INT_BIT_RF_KILL; @@ -1169,6 +1048,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) /* Chip got too hot and stopped itself */ if (inta & CSR_INT_BIT_CT_KILL) { IWL_ERR(priv, "Microcode CT kill error detected.\n"); + priv->isr_stats.ctkill++; handled |= CSR_INT_BIT_CT_KILL; } @@ -1176,6 +1056,8 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) if (inta & CSR_INT_BIT_SW_ERR) { IWL_ERR(priv, "Microcode SW error detected. " " Restarting 0x%X.\n", inta); + priv->isr_stats.sw++; + priv->isr_stats.sw_err = inta; iwl_irq_handle_error(priv); handled |= CSR_INT_BIT_SW_ERR; } @@ -1191,6 +1073,8 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) iwl_txq_update_write_ptr(priv, &priv->txq[4]); iwl_txq_update_write_ptr(priv, &priv->txq[5]); + priv->isr_stats.wakeup++; + handled |= CSR_INT_BIT_WAKEUP; } @@ -1199,23 +1083,27 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) * notifications from uCode come through here*/ if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) { iwl_rx_handle(priv); + priv->isr_stats.rx++; handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX); } if (inta & CSR_INT_BIT_FH_TX) { IWL_DEBUG_ISR(priv, "Tx interrupt\n"); + priv->isr_stats.tx++; handled |= CSR_INT_BIT_FH_TX; /* FH finished to write, send event */ priv->ucode_write_complete = 1; wake_up_interruptible(&priv->wait_command_queue); } - if (inta & ~handled) + if (inta & ~handled) { IWL_ERR(priv, "Unhandled INTA bits 0x%08x\n", inta & ~handled); + priv->isr_stats.unhandled++; + } - if (inta & ~CSR_INI_SET_MASK) { + if (inta & ~(priv->inta_mask)) { IWL_WARN(priv, "Disabled INTA bits 0x%08x were pending\n", - inta & ~CSR_INI_SET_MASK); + inta & ~priv->inta_mask); IWL_WARN(priv, " with FH_INT = 0x%08x\n", inta_fh); } @@ -1236,6 +1124,200 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); } +/* tasklet for iwlagn interrupt */ +static void iwl_irq_tasklet(struct iwl_priv *priv) +{ + u32 inta = 0; + u32 handled = 0; + unsigned long flags; +#ifdef CONFIG_IWLWIFI_DEBUG + u32 inta_mask; +#endif + + spin_lock_irqsave(&priv->lock, flags); + + /* Ack/clear/reset pending uCode interrupts. + * Note: Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS, + */ + iwl_write32(priv, CSR_INT, priv->inta); + + inta = priv->inta; + +#ifdef CONFIG_IWLWIFI_DEBUG + if (priv->debug_level & IWL_DL_ISR) { + /* just for debug */ + inta_mask = iwl_read32(priv, CSR_INT_MASK); + IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x\n ", + inta, inta_mask); + } +#endif + /* saved interrupt in inta variable now we can reset priv->inta */ + priv->inta = 0; + + /* Now service all interrupt bits discovered above. */ + if (inta & CSR_INT_BIT_HW_ERR) { + IWL_ERR(priv, "Microcode HW error detected. Restarting.\n"); + + /* Tell the device to stop sending interrupts */ + iwl_disable_interrupts(priv); + + priv->isr_stats.hw++; + iwl_irq_handle_error(priv); + + handled |= CSR_INT_BIT_HW_ERR; + + spin_unlock_irqrestore(&priv->lock, flags); + + return; + } + +#ifdef CONFIG_IWLWIFI_DEBUG + if (priv->debug_level & (IWL_DL_ISR)) { + /* NIC fires this, but we don't use it, redundant with WAKEUP */ + if (inta & CSR_INT_BIT_SCD) { + IWL_DEBUG_ISR(priv, "Scheduler finished to transmit " + "the frame/frames.\n"); + priv->isr_stats.sch++; + } + + /* Alive notification via Rx interrupt will do the real work */ + if (inta & CSR_INT_BIT_ALIVE) { + IWL_DEBUG_ISR(priv, "Alive interrupt\n"); + priv->isr_stats.alive++; + } + } +#endif + /* Safely ignore these bits for debug checks below */ + inta &= ~(CSR_INT_BIT_SCD | CSR_INT_BIT_ALIVE); + + /* HW RF KILL switch toggled */ + if (inta & CSR_INT_BIT_RF_KILL) { + int hw_rf_kill = 0; + if (!(iwl_read32(priv, CSR_GP_CNTRL) & + CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) + hw_rf_kill = 1; + + IWL_DEBUG_RF_KILL(priv, "RF_KILL bit toggled to %s.\n", + hw_rf_kill ? "disable radio" : "enable radio"); + + priv->isr_stats.rfkill++; + + /* driver only loads ucode once setting the interface up. + * the driver allows loading the ucode even if the radio + * is killed. Hence update the killswitch state here. The + * rfkill handler will care about restarting if needed. + */ + if (!test_bit(STATUS_ALIVE, &priv->status)) { + if (hw_rf_kill) + set_bit(STATUS_RF_KILL_HW, &priv->status); + else + clear_bit(STATUS_RF_KILL_HW, &priv->status); + wiphy_rfkill_set_hw_state(priv->hw->wiphy, hw_rf_kill); + } + + handled |= CSR_INT_BIT_RF_KILL; + } + + /* Chip got too hot and stopped itself */ + if (inta & CSR_INT_BIT_CT_KILL) { + IWL_ERR(priv, "Microcode CT kill error detected.\n"); + priv->isr_stats.ctkill++; + handled |= CSR_INT_BIT_CT_KILL; + } + + /* Error detected by uCode */ + if (inta & CSR_INT_BIT_SW_ERR) { + IWL_ERR(priv, "Microcode SW error detected. " + " Restarting 0x%X.\n", inta); + priv->isr_stats.sw++; + priv->isr_stats.sw_err = inta; + iwl_irq_handle_error(priv); + handled |= CSR_INT_BIT_SW_ERR; + } + + /* uCode wakes up after power-down sleep */ + if (inta & CSR_INT_BIT_WAKEUP) { + IWL_DEBUG_ISR(priv, "Wakeup interrupt\n"); + iwl_rx_queue_update_write_ptr(priv, &priv->rxq); + iwl_txq_update_write_ptr(priv, &priv->txq[0]); + iwl_txq_update_write_ptr(priv, &priv->txq[1]); + iwl_txq_update_write_ptr(priv, &priv->txq[2]); + iwl_txq_update_write_ptr(priv, &priv->txq[3]); + iwl_txq_update_write_ptr(priv, &priv->txq[4]); + iwl_txq_update_write_ptr(priv, &priv->txq[5]); + + priv->isr_stats.wakeup++; + + handled |= CSR_INT_BIT_WAKEUP; + } + + /* All uCode command responses, including Tx command responses, + * Rx "responses" (frame-received notification), and other + * notifications from uCode come through here*/ + if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX | + CSR_INT_BIT_RX_PERIODIC)) { + IWL_DEBUG_ISR(priv, "Rx interrupt\n"); + if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) { + handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX); + iwl_write32(priv, CSR_FH_INT_STATUS, + CSR49_FH_INT_RX_MASK); + } + if (inta & CSR_INT_BIT_RX_PERIODIC) { + handled |= CSR_INT_BIT_RX_PERIODIC; + iwl_write32(priv, CSR_INT, CSR_INT_BIT_RX_PERIODIC); + } + /* Sending RX interrupt require many steps to be done in the + * the device: + * 1- write interrupt to current index in ICT table. + * 2- dma RX frame. + * 3- update RX shared data to indicate last write index. + * 4- send interrupt. + * This could lead to RX race, driver could receive RX interrupt + * but the shared data changes does not reflect this. + * this could lead to RX race, RX periodic will solve this race + */ + iwl_write32(priv, CSR_INT_PERIODIC_REG, + CSR_INT_PERIODIC_DIS); + iwl_rx_handle(priv); + /* Only set RX periodic if real RX is received. */ + if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) + iwl_write32(priv, CSR_INT_PERIODIC_REG, + CSR_INT_PERIODIC_ENA); + + priv->isr_stats.rx++; + } + + if (inta & CSR_INT_BIT_FH_TX) { + iwl_write32(priv, CSR_FH_INT_STATUS, CSR49_FH_INT_TX_MASK); + IWL_DEBUG_ISR(priv, "Tx interrupt\n"); + priv->isr_stats.tx++; + handled |= CSR_INT_BIT_FH_TX; + /* FH finished to write, send event */ + priv->ucode_write_complete = 1; + wake_up_interruptible(&priv->wait_command_queue); + } + + if (inta & ~handled) { + IWL_ERR(priv, "Unhandled INTA bits 0x%08x\n", inta & ~handled); + priv->isr_stats.unhandled++; + } + + if (inta & ~(priv->inta_mask)) { + IWL_WARN(priv, "Disabled INTA bits 0x%08x were pending\n", + inta & ~priv->inta_mask); + } + + + /* Re-enable all interrupts */ + /* only Re-enable if diabled by irq */ + if (test_bit(STATUS_INT_ENABLED, &priv->status)) + iwl_enable_interrupts(priv); + + spin_unlock_irqrestore(&priv->lock, flags); + +} + + /****************************************************************************** * * uCode download functions @@ -1501,10 +1583,6 @@ static int iwl_read_ucode(struct iwl_priv *priv) return ret; } -/* temporary */ -static int iwl_mac_beacon_update(struct ieee80211_hw *hw, - struct sk_buff *skb); - /** * iwl_alive_start - called after REPLY_ALIVE notification received * from protocol/runtime uCode (initialization uCode's @@ -1561,7 +1639,10 @@ static void iwl_alive_start(struct iwl_priv *priv) } else { /* Initialize our rx_config data */ iwl_connection_init_rx_config(priv, priv->iw_mode); - iwl_set_rxon_chain(priv); + + if (priv->cfg->ops->hcmd->set_rxon_chain) + priv->cfg->ops->hcmd->set_rxon_chain(priv); + memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); } @@ -1571,7 +1652,7 @@ static void iwl_alive_start(struct iwl_priv *priv) iwl_reset_run_time_calib(priv); /* Configure the adapter for unassociated operation */ - iwl_commit_rxon(priv); + iwlcore_commit_rxon(priv); /* At this point, the NIC is initialized and operational */ iwl_rf_kill_ct_config(priv); @@ -1582,9 +1663,6 @@ static void iwl_alive_start(struct iwl_priv *priv) set_bit(STATUS_READY, &priv->status); wake_up_interruptible(&priv->wait_command_queue); - if (priv->error_recovering) - iwl_error_recovery(priv); - iwl_power_update_mode(priv, 1); /* reassociate for ADHOC mode */ @@ -1642,36 +1720,30 @@ static void __iwl_down(struct iwl_priv *priv) ieee80211_stop_queues(priv->hw); /* If we have not previously called iwl_init() then - * clear all bits but the RF Kill and SUSPEND bits and return */ + * clear all bits but the RF Kill bit and return */ if (!iwl_is_init(priv)) { priv->status = test_bit(STATUS_RF_KILL_HW, &priv->status) << STATUS_RF_KILL_HW | - test_bit(STATUS_RF_KILL_SW, &priv->status) << - STATUS_RF_KILL_SW | test_bit(STATUS_GEO_CONFIGURED, &priv->status) << STATUS_GEO_CONFIGURED | - test_bit(STATUS_IN_SUSPEND, &priv->status) << - STATUS_IN_SUSPEND | test_bit(STATUS_EXIT_PENDING, &priv->status) << STATUS_EXIT_PENDING; goto exit; } - /* ...otherwise clear out all the status bits but the RF Kill and - * SUSPEND bits and continue taking the NIC down. */ + /* ...otherwise clear out all the status bits but the RF Kill + * bit and continue taking the NIC down. */ priv->status &= test_bit(STATUS_RF_KILL_HW, &priv->status) << STATUS_RF_KILL_HW | - test_bit(STATUS_RF_KILL_SW, &priv->status) << - STATUS_RF_KILL_SW | test_bit(STATUS_GEO_CONFIGURED, &priv->status) << STATUS_GEO_CONFIGURED | - test_bit(STATUS_IN_SUSPEND, &priv->status) << - STATUS_IN_SUSPEND | test_bit(STATUS_FW_ERROR, &priv->status) << STATUS_FW_ERROR | test_bit(STATUS_EXIT_PENDING, &priv->status) << STATUS_EXIT_PENDING; + /* device going down, Stop using ICT table */ + iwl_disable_ict(priv); spin_lock_irqsave(&priv->lock, flags); iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); @@ -1680,18 +1752,13 @@ static void __iwl_down(struct iwl_priv *priv) iwl_txq_ctx_stop(priv); iwl_rxq_stop(priv); - spin_lock_irqsave(&priv->lock, flags); - if (!iwl_grab_nic_access(priv)) { - iwl_write_prph(priv, APMG_CLK_DIS_REG, - APMG_CLK_VAL_DMA_CLK_RQT); - iwl_release_nic_access(priv); - } - spin_unlock_irqrestore(&priv->lock, flags); + iwl_write_prph(priv, APMG_CLK_DIS_REG, + APMG_CLK_VAL_DMA_CLK_RQT); udelay(5); /* FIXME: apm_ops.suspend(priv) */ - if (exit_pending || test_bit(STATUS_IN_SUSPEND, &priv->status)) + if (exit_pending) priv->cfg->ops->lib->apm_ops.stop(priv); else priv->cfg->ops->lib->apm_ops.reset(priv); @@ -1715,6 +1782,49 @@ static void iwl_down(struct iwl_priv *priv) iwl_cancel_deferred_work(priv); } +#define HW_READY_TIMEOUT (50) + +static int iwl_set_hw_ready(struct iwl_priv *priv) +{ + int ret = 0; + + iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_NIC_READY); + + /* See if we got it */ + ret = iwl_poll_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_NIC_READY, + CSR_HW_IF_CONFIG_REG_BIT_NIC_READY, + HW_READY_TIMEOUT); + if (ret != -ETIMEDOUT) + priv->hw_ready = true; + else + priv->hw_ready = false; + + IWL_DEBUG_INFO(priv, "hardware %s\n", + (priv->hw_ready == 1) ? "ready" : "not ready"); + return ret; +} + +static int iwl_prepare_card_hw(struct iwl_priv *priv) +{ + int ret = 0; + + IWL_DEBUG_INFO(priv, "iwl_prepare_card_hw enter \n"); + + iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_PREPARE); + + ret = iwl_poll_bit(priv, CSR_HW_IF_CONFIG_REG, + ~CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, + CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, 150000); + + if (ret != -ETIMEDOUT) + iwl_set_hw_ready(priv); + + return ret; +} + #define MAX_HW_RESTARTS 5 static int __iwl_up(struct iwl_priv *priv) @@ -1732,6 +1842,13 @@ static int __iwl_up(struct iwl_priv *priv) return -EIO; } + iwl_prepare_card_hw(priv); + + if (!priv->hw_ready) { + IWL_WARN(priv, "Exit HW not ready\n"); + return -EIO; + } + /* If platform's RF_KILL switch is NOT set to KILL */ if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) clear_bit(STATUS_RF_KILL_HW, &priv->status); @@ -1739,9 +1856,10 @@ static int __iwl_up(struct iwl_priv *priv) set_bit(STATUS_RF_KILL_HW, &priv->status); if (iwl_is_rfkill(priv)) { + wiphy_rfkill_set_hw_state(priv->hw->wiphy, true); + iwl_enable_interrupts(priv); - IWL_WARN(priv, "Radio disabled by %s RF Kill switch\n", - test_bit(STATUS_RF_KILL_HW, &priv->status) ? "HW" : "SW"); + IWL_WARN(priv, "Radio disabled by HW RF Kill switch\n"); return 0; } @@ -1787,9 +1905,6 @@ static int __iwl_up(struct iwl_priv *priv) continue; } - /* Clear out the uCode error bit if it is set */ - clear_bit(STATUS_FW_ERROR, &priv->status); - /* start card; "initialize" will load runtime ucode */ iwl_nic_start(priv); @@ -1836,6 +1951,9 @@ static void iwl_bg_alive_start(struct work_struct *data) if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; + /* enable dram interrupt */ + iwl_reset_ict(priv); + mutex_lock(&priv->mutex); iwl_alive_start(priv); mutex_unlock(&priv->mutex); @@ -1874,7 +1992,6 @@ static void iwl_bg_up(struct work_struct *data) mutex_lock(&priv->mutex); __iwl_up(priv); mutex_unlock(&priv->mutex); - iwl_rfkill_set_hw_state(priv); } static void iwl_bg_restart(struct work_struct *data) @@ -1884,8 +2001,17 @@ static void iwl_bg_restart(struct work_struct *data) if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; - iwl_down(priv); - queue_work(priv->workqueue, &priv->up); + if (test_and_clear_bit(STATUS_FW_ERROR, &priv->status)) { + mutex_lock(&priv->mutex); + priv->vif = NULL; + priv->is_open = 0; + mutex_unlock(&priv->mutex); + iwl_down(priv); + ieee80211_restart_hw(priv->hw); + } else { + iwl_down(priv); + queue_work(priv->workqueue, &priv->up); + } } static void iwl_bg_rx_replenish(struct work_struct *data) @@ -1903,7 +2029,7 @@ static void iwl_bg_rx_replenish(struct work_struct *data) #define IWL_DELAY_NEXT_SCAN (HZ*2) -static void iwl_post_associate(struct iwl_priv *priv) +void iwl_post_associate(struct iwl_priv *priv) { struct ieee80211_conf *conf = NULL; int ret = 0; @@ -1925,13 +2051,12 @@ static void iwl_post_associate(struct iwl_priv *priv) if (!priv->vif || !priv->is_open) return; - iwl_power_cancel_timeout(priv); iwl_scan_cancel_timeout(priv, 200); conf = ieee80211_get_hw_conf(priv->hw); priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl_commit_rxon(priv); + iwlcore_commit_rxon(priv); iwl_setup_rxon_timing(priv); ret = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING, @@ -1944,7 +2069,9 @@ static void iwl_post_associate(struct iwl_priv *priv) iwl_set_rxon_ht(priv, &priv->current_ht_config); - iwl_set_rxon_chain(priv); + if (priv->cfg->ops->hcmd->set_rxon_chain) + priv->cfg->ops->hcmd->set_rxon_chain(priv); + priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id); IWL_DEBUG_ASSOC(priv, "assoc id %d beacon interval %d\n", @@ -1966,7 +2093,7 @@ static void iwl_post_associate(struct iwl_priv *priv) } - iwl_commit_rxon(priv); + iwlcore_commit_rxon(priv); switch (priv->iw_mode) { case NL80211_IFTYPE_STATION: @@ -1999,7 +2126,7 @@ static void iwl_post_associate(struct iwl_priv *priv) * If chain noise has already been run, then we need to enable * power management here */ if (priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE) - iwl_power_enable_management(priv); + iwl_power_update_mode(priv, 0); /* Enable Rx differential gain and sensitivity calibrations */ iwl_chain_noise_reset(priv); @@ -2025,7 +2152,6 @@ static int iwl_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 iwl_rxon_cmd)); /* fetch ucode file from disk, alloc and copy to bus-master buffers ... * ucode filename and max sizes are card-specific. */ @@ -2042,8 +2168,6 @@ static int iwl_mac_start(struct ieee80211_hw *hw) mutex_unlock(&priv->mutex); - iwl_rfkill_set_hw_state(priv); - if (ret) return ret; @@ -2052,9 +2176,6 @@ static int iwl_mac_start(struct ieee80211_hw *hw) IWL_DEBUG_INFO(priv, "Start UP work done.\n"); - if (test_bit(STATUS_IN_SUSPEND, &priv->status)) - return 0; - /* Wait for START_ALIVE from Run Time ucode. Otherwise callbacks from * mac80211 will not be run successfully. */ ret = wait_event_interruptible_timeout(priv->wait_command_queue, @@ -2080,10 +2201,8 @@ static void iwl_mac_stop(struct ieee80211_hw *hw) IWL_DEBUG_MAC80211(priv, "enter\n"); - if (!priv->is_open) { - IWL_DEBUG_MAC80211(priv, "leave - skip\n"); + if (!priv->is_open) return; - } priv->is_open = 0; @@ -2123,175 +2242,7 @@ static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) return NETDEV_TX_OK; } -static int iwl_mac_add_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) -{ - struct iwl_priv *priv = hw->priv; - unsigned long flags; - - IWL_DEBUG_MAC80211(priv, "enter: type %d\n", conf->type); - - if (priv->vif) { - IWL_DEBUG_MAC80211(priv, "leave - vif != NULL\n"); - return -EOPNOTSUPP; - } - - spin_lock_irqsave(&priv->lock, flags); - priv->vif = conf->vif; - priv->iw_mode = conf->type; - - spin_unlock_irqrestore(&priv->lock, flags); - - mutex_lock(&priv->mutex); - - if (conf->mac_addr) { - IWL_DEBUG_MAC80211(priv, "Set %pM\n", conf->mac_addr); - memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN); - } - - if (iwl_set_mode(priv, conf->type) == -EAGAIN) - /* we are not ready, will run again when ready */ - set_bit(STATUS_MODE_PENDING, &priv->status); - - mutex_unlock(&priv->mutex); - - IWL_DEBUG_MAC80211(priv, "leave\n"); - return 0; -} - -/** - * iwl_mac_config - mac80211 config callback - * - * We ignore conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME since it seems to - * be set inappropriately and the driver currently sets the hardware up to - * use it whenever needed. - */ -static int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) -{ - struct iwl_priv *priv = hw->priv; - const struct iwl_channel_info *ch_info; - struct ieee80211_conf *conf = &hw->conf; - unsigned long flags = 0; - int ret = 0; - u16 ch; - int scan_active = 0; - - mutex_lock(&priv->mutex); - IWL_DEBUG_MAC80211(priv, "enter to channel %d changed 0x%X\n", - conf->channel->hw_value, changed); - - if (unlikely(!priv->cfg->mod_params->disable_hw_scan && - test_bit(STATUS_SCANNING, &priv->status))) { - scan_active = 1; - IWL_DEBUG_MAC80211(priv, "leave - scanning\n"); - } - - - /* during scanning mac80211 will delay channel setting until - * scan finish with changed = 0 - */ - if (!changed || (changed & IEEE80211_CONF_CHANGE_CHANNEL)) { - if (scan_active) - goto set_ch_out; - - ch = ieee80211_frequency_to_channel(conf->channel->center_freq); - ch_info = iwl_get_channel_info(priv, conf->channel->band, ch); - if (!is_channel_valid(ch_info)) { - IWL_DEBUG_MAC80211(priv, "leave - invalid channel\n"); - ret = -EINVAL; - goto set_ch_out; - } - - if (priv->iw_mode == NL80211_IFTYPE_ADHOC && - !is_channel_ibss(ch_info)) { - IWL_ERR(priv, "channel %d in band %d not " - "IBSS channel\n", - conf->channel->hw_value, conf->channel->band); - ret = -EINVAL; - goto set_ch_out; - } - - priv->current_ht_config.is_ht = conf_is_ht(conf); - - spin_lock_irqsave(&priv->lock, flags); - - - /* if we are switching from ht to 2.4 clear flags - * from any ht related info since 2.4 does not - * support ht */ - if ((le16_to_cpu(priv->staging_rxon.channel) != ch)) - priv->staging_rxon.flags = 0; - - iwl_set_rxon_channel(priv, conf->channel); - - iwl_set_flags_for_band(priv, conf->channel->band); - spin_unlock_irqrestore(&priv->lock, flags); - set_ch_out: - /* The list of supported rates and rate mask can be different - * for each band; since the band may have changed, reset - * the rate mask to what mac80211 lists */ - iwl_set_rate(priv); - } - - if (changed & IEEE80211_CONF_CHANGE_PS) { - if (conf->flags & IEEE80211_CONF_PS) - ret = iwl_power_set_user_mode(priv, IWL_POWER_INDEX_3); - else - ret = iwl_power_set_user_mode(priv, IWL_POWER_MODE_CAM); - if (ret) - IWL_DEBUG_MAC80211(priv, "Error setting power level\n"); - - } - - if (changed & IEEE80211_CONF_CHANGE_POWER) { - IWL_DEBUG_MAC80211(priv, "TX Power old=%d new=%d\n", - priv->tx_power_user_lmt, conf->power_level); - - iwl_set_tx_power(priv, conf->power_level, false); - } - - /* call to ensure that 4965 rx_chain is set properly in monitor mode */ - iwl_set_rxon_chain(priv); - - if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED) { - if (conf->radio_enabled && - iwl_radio_kill_sw_enable_radio(priv)) { - IWL_DEBUG_MAC80211(priv, "leave - RF-KILL - " - "waiting for uCode\n"); - goto out; - } - - if (!conf->radio_enabled) - iwl_radio_kill_sw_disable_radio(priv); - } - - if (!conf->radio_enabled) { - IWL_DEBUG_MAC80211(priv, "leave - radio disabled\n"); - goto out; - } - - if (!iwl_is_ready(priv)) { - IWL_DEBUG_MAC80211(priv, "leave - not ready\n"); - goto out; - } - - if (scan_active) - goto out; - - if (memcmp(&priv->active_rxon, - &priv->staging_rxon, sizeof(priv->staging_rxon))) - iwl_commit_rxon(priv); - else - IWL_DEBUG_INFO(priv, "No re-sending same RXON configuration.\n"); - - -out: - IWL_DEBUG_MAC80211(priv, "leave\n"); - mutex_unlock(&priv->mutex); - return ret; -} - -static void iwl_config_ap(struct iwl_priv *priv) +void iwl_config_ap(struct iwl_priv *priv) { int ret = 0; unsigned long flags; @@ -2304,7 +2255,7 @@ static void iwl_config_ap(struct iwl_priv *priv) /* RXON - unassoc (to set timing command) */ priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl_commit_rxon(priv); + iwlcore_commit_rxon(priv); /* RXON Timing */ iwl_setup_rxon_timing(priv); @@ -2314,7 +2265,8 @@ static void iwl_config_ap(struct iwl_priv *priv) IWL_WARN(priv, "REPLY_RXON_TIMING failed - " "Attempting to continue.\n"); - iwl_set_rxon_chain(priv); + if (priv->cfg->ops->hcmd->set_rxon_chain) + priv->cfg->ops->hcmd->set_rxon_chain(priv); /* FIXME: what should be the assoc_id for AP? */ priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id); @@ -2340,7 +2292,7 @@ static void iwl_config_ap(struct iwl_priv *priv) } /* restore RXON assoc */ priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; - iwl_commit_rxon(priv); + iwlcore_commit_rxon(priv); spin_lock_irqsave(&priv->lock, flags); iwl_activate_qos(priv, 1); spin_unlock_irqrestore(&priv->lock, flags); @@ -2353,194 +2305,6 @@ static void iwl_config_ap(struct iwl_priv *priv) * clear sta table, add BCAST sta... */ } - -static int iwl_mac_config_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_if_conf *conf) -{ - struct iwl_priv *priv = hw->priv; - int rc; - - if (conf == NULL) - return -EIO; - - if (priv->vif != vif) { - IWL_DEBUG_MAC80211(priv, "leave - priv->vif != vif\n"); - return 0; - } - - if (priv->iw_mode == NL80211_IFTYPE_ADHOC && - conf->changed & IEEE80211_IFCC_BEACON) { - struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); - if (!beacon) - return -ENOMEM; - mutex_lock(&priv->mutex); - rc = iwl_mac_beacon_update(hw, beacon); - mutex_unlock(&priv->mutex); - if (rc) - return rc; - } - - if (!iwl_is_alive(priv)) - return -EAGAIN; - - mutex_lock(&priv->mutex); - - if (conf->bssid) - IWL_DEBUG_MAC80211(priv, "bssid: %pM\n", conf->bssid); - -/* - * very dubious code was here; the probe filtering flag is never set: - * - if (unlikely(test_bit(STATUS_SCANNING, &priv->status)) && - !(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) { - */ - - if (priv->iw_mode == NL80211_IFTYPE_AP) { - if (!conf->bssid) { - conf->bssid = priv->mac_addr; - memcpy(priv->bssid, priv->mac_addr, ETH_ALEN); - IWL_DEBUG_MAC80211(priv, "bssid was set to: %pM\n", - conf->bssid); - } - if (priv->ibss_beacon) - dev_kfree_skb(priv->ibss_beacon); - - priv->ibss_beacon = ieee80211_beacon_get(hw, vif); - } - - if (iwl_is_rfkill(priv)) - goto done; - - if (conf->bssid && !is_zero_ether_addr(conf->bssid) && - !is_multicast_ether_addr(conf->bssid)) { - /* If there is currently a HW scan going on in the background - * then we need to cancel it else the RXON below will fail. */ - if (iwl_scan_cancel_timeout(priv, 100)) { - IWL_WARN(priv, "Aborted scan still in progress " - "after 100ms\n"); - IWL_DEBUG_MAC80211(priv, "leaving - scan abort failed.\n"); - mutex_unlock(&priv->mutex); - return -EAGAIN; - } - memcpy(priv->staging_rxon.bssid_addr, conf->bssid, ETH_ALEN); - - /* TODO: Audit driver for usage of these members and see - * if mac80211 deprecates them (priv->bssid looks like it - * shouldn't be there, but I haven't scanned the IBSS code - * to verify) - jpk */ - memcpy(priv->bssid, conf->bssid, ETH_ALEN); - - if (priv->iw_mode == NL80211_IFTYPE_AP) - iwl_config_ap(priv); - else { - rc = iwl_commit_rxon(priv); - if ((priv->iw_mode == NL80211_IFTYPE_STATION) && rc) - iwl_rxon_add_station( - priv, priv->active_rxon.bssid_addr, 1); - } - - } else { - iwl_scan_cancel_timeout(priv, 100); - priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl_commit_rxon(priv); - } - - done: - IWL_DEBUG_MAC80211(priv, "leave\n"); - mutex_unlock(&priv->mutex); - - return 0; -} - -static void iwl_mac_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) -{ - struct iwl_priv *priv = hw->priv; - - IWL_DEBUG_MAC80211(priv, "enter\n"); - - mutex_lock(&priv->mutex); - - if (iwl_is_ready_rf(priv)) { - iwl_scan_cancel_timeout(priv, 100); - priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl_commit_rxon(priv); - } - if (priv->vif == conf->vif) { - priv->vif = NULL; - memset(priv->bssid, 0, ETH_ALEN); - } - mutex_unlock(&priv->mutex); - - IWL_DEBUG_MAC80211(priv, "leave\n"); - -} - -#define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6) -static void iwl_bss_info_changed(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *bss_conf, - u32 changes) -{ - struct iwl_priv *priv = hw->priv; - - IWL_DEBUG_MAC80211(priv, "changes = 0x%X\n", changes); - - if (changes & BSS_CHANGED_ERP_PREAMBLE) { - IWL_DEBUG_MAC80211(priv, "ERP_PREAMBLE %d\n", - bss_conf->use_short_preamble); - if (bss_conf->use_short_preamble) - priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; - else - priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK; - } - - if (changes & BSS_CHANGED_ERP_CTS_PROT) { - IWL_DEBUG_MAC80211(priv, "ERP_CTS %d\n", bss_conf->use_cts_prot); - if (bss_conf->use_cts_prot && (priv->band != IEEE80211_BAND_5GHZ)) - priv->staging_rxon.flags |= RXON_FLG_TGG_PROTECT_MSK; - else - priv->staging_rxon.flags &= ~RXON_FLG_TGG_PROTECT_MSK; - } - - if (changes & BSS_CHANGED_HT) { - iwl_ht_conf(priv, bss_conf); - iwl_set_rxon_chain(priv); - } - - if (changes & BSS_CHANGED_ASSOC) { - IWL_DEBUG_MAC80211(priv, "ASSOC %d\n", bss_conf->assoc); - /* This should never happen as this function should - * never be called from interrupt context. */ - if (WARN_ON_ONCE(in_interrupt())) - return; - if (bss_conf->assoc) { - priv->assoc_id = bss_conf->aid; - priv->beacon_int = bss_conf->beacon_int; - priv->power_data.dtim_period = bss_conf->dtim_period; - priv->timestamp = bss_conf->timestamp; - priv->assoc_capability = bss_conf->assoc_capability; - - /* we have just associated, don't start scan too early - * leave time for EAPOL exchange to complete - */ - priv->next_scan_jiffies = jiffies + - IWL_DELAY_NEXT_SCAN_AFTER_ASSOC; - mutex_lock(&priv->mutex); - iwl_post_associate(priv); - mutex_unlock(&priv->mutex); - } else { - priv->assoc_id = 0; - IWL_DEBUG_MAC80211(priv, "DISASSOC %d\n", bss_conf->assoc); - } - } else if (changes && iwl_is_associated(priv) && priv->assoc_id) { - IWL_DEBUG_MAC80211(priv, "Associated Changes %d\n", changes); - iwl_send_rxon_assoc(priv); - } - -} - static void iwl_mac_update_tkip_key(struct ieee80211_hw *hw, struct ieee80211_key_conf *keyconf, const u8 *addr, u32 iv32, u16 *phase1key) @@ -2623,49 +2387,6 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, return ret; } -static int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, - const struct ieee80211_tx_queue_params *params) -{ - struct iwl_priv *priv = hw->priv; - unsigned long flags; - int q; - - IWL_DEBUG_MAC80211(priv, "enter\n"); - - if (!iwl_is_ready_rf(priv)) { - IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n"); - return -EIO; - } - - if (queue >= AC_NUM) { - IWL_DEBUG_MAC80211(priv, "leave - queue >= AC_NUM %d\n", queue); - return 0; - } - - q = AC_NUM - 1 - queue; - - spin_lock_irqsave(&priv->lock, flags); - - priv->qos_data.def_qos_parm.ac[q].cw_min = cpu_to_le16(params->cw_min); - priv->qos_data.def_qos_parm.ac[q].cw_max = cpu_to_le16(params->cw_max); - priv->qos_data.def_qos_parm.ac[q].aifsn = params->aifs; - priv->qos_data.def_qos_parm.ac[q].edca_txop = - cpu_to_le16((params->txop * 32)); - - priv->qos_data.def_qos_parm.ac[q].reserved1 = 0; - priv->qos_data.qos_active = 1; - - if (priv->iw_mode == NL80211_IFTYPE_AP) - iwl_activate_qos(priv, 1); - else if (priv->assoc_id && iwl_is_associated(priv)) - iwl_activate_qos(priv, 0); - - spin_unlock_irqrestore(&priv->lock, flags); - - IWL_DEBUG_MAC80211(priv, "leave\n"); - return 0; -} - static int iwl_mac_ampdu_action(struct ieee80211_hw *hw, enum ieee80211_ampdu_mlme_action action, struct ieee80211_sta *sta, u16 tid, u16 *ssn) @@ -2708,41 +2429,6 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw, return 0; } -static int iwl_mac_get_tx_stats(struct ieee80211_hw *hw, - struct ieee80211_tx_queue_stats *stats) -{ - struct iwl_priv *priv = hw->priv; - int i, avail; - struct iwl_tx_queue *txq; - struct iwl_queue *q; - unsigned long flags; - - IWL_DEBUG_MAC80211(priv, "enter\n"); - - if (!iwl_is_ready_rf(priv)) { - IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n"); - return -EIO; - } - - spin_lock_irqsave(&priv->lock, flags); - - for (i = 0; i < AC_NUM; i++) { - txq = &priv->txq[i]; - q = &txq->q; - avail = iwl_queue_space(q); - - stats[i].len = q->n_window - avail; - stats[i].limit = q->n_window - q->high_mark; - stats[i].count = q->n_window; - - } - spin_unlock_irqrestore(&priv->lock, flags); - - IWL_DEBUG_MAC80211(priv, "leave\n"); - - return 0; -} - static int iwl_mac_get_stats(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats) { @@ -2755,120 +2441,6 @@ static int iwl_mac_get_stats(struct ieee80211_hw *hw, return 0; } -static void iwl_mac_reset_tsf(struct ieee80211_hw *hw) -{ - struct iwl_priv *priv = hw->priv; - unsigned long flags; - - mutex_lock(&priv->mutex); - IWL_DEBUG_MAC80211(priv, "enter\n"); - - spin_lock_irqsave(&priv->lock, flags); - memset(&priv->current_ht_config, 0, sizeof(struct iwl_ht_info)); - spin_unlock_irqrestore(&priv->lock, flags); - - iwl_reset_qos(priv); - - spin_lock_irqsave(&priv->lock, flags); - priv->assoc_id = 0; - priv->assoc_capability = 0; - priv->assoc_station_added = 0; - - /* new association get rid of ibss beacon skb */ - if (priv->ibss_beacon) - dev_kfree_skb(priv->ibss_beacon); - - priv->ibss_beacon = NULL; - - priv->beacon_int = priv->hw->conf.beacon_int; - priv->timestamp = 0; - if ((priv->iw_mode == NL80211_IFTYPE_STATION)) - priv->beacon_int = 0; - - spin_unlock_irqrestore(&priv->lock, flags); - - if (!iwl_is_ready_rf(priv)) { - IWL_DEBUG_MAC80211(priv, "leave - not ready\n"); - mutex_unlock(&priv->mutex); - return; - } - - /* we are restarting association process - * clear RXON_FILTER_ASSOC_MSK bit - */ - if (priv->iw_mode != NL80211_IFTYPE_AP) { - iwl_scan_cancel_timeout(priv, 100); - priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl_commit_rxon(priv); - } - - iwl_power_update_mode(priv, 0); - - /* Per mac80211.h: This is only used in IBSS mode... */ - if (priv->iw_mode != NL80211_IFTYPE_ADHOC) { - - /* switch to CAM during association period. - * the ucode will block any association/authentication - * frome during assiciation period if it can not hear - * the AP because of PM. the timer enable PM back is - * association do not complete - */ - if (priv->hw->conf.channel->flags & (IEEE80211_CHAN_PASSIVE_SCAN | - IEEE80211_CHAN_RADAR)) - iwl_power_disable_management(priv, 3000); - - IWL_DEBUG_MAC80211(priv, "leave - not in IBSS\n"); - mutex_unlock(&priv->mutex); - return; - } - - iwl_set_rate(priv); - - mutex_unlock(&priv->mutex); - - IWL_DEBUG_MAC80211(priv, "leave\n"); -} - -static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) -{ - struct iwl_priv *priv = hw->priv; - unsigned long flags; - __le64 timestamp; - - IWL_DEBUG_MAC80211(priv, "enter\n"); - - if (!iwl_is_ready_rf(priv)) { - IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n"); - return -EIO; - } - - if (priv->iw_mode != NL80211_IFTYPE_ADHOC) { - IWL_DEBUG_MAC80211(priv, "leave - not IBSS\n"); - return -EIO; - } - - spin_lock_irqsave(&priv->lock, flags); - - if (priv->ibss_beacon) - dev_kfree_skb(priv->ibss_beacon); - - priv->ibss_beacon = skb; - - priv->assoc_id = 0; - timestamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp; - priv->timestamp = le64_to_cpu(timestamp); - - IWL_DEBUG_MAC80211(priv, "leave\n"); - spin_unlock_irqrestore(&priv->lock, flags); - - iwl_reset_qos(priv); - - iwl_post_associate(priv); - - - return 0; -} - /***************************************************************************** * * sysfs attributes @@ -2888,7 +2460,7 @@ static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) static ssize_t show_debug_level(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl_priv *priv = d->driver_data; + struct iwl_priv *priv = dev_get_drvdata(d); return sprintf(buf, "0x%08X\n", priv->debug_level); } @@ -2896,7 +2468,7 @@ static ssize_t store_debug_level(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { - struct iwl_priv *priv = d->driver_data; + struct iwl_priv *priv = dev_get_drvdata(d); unsigned long val; int ret; @@ -2919,7 +2491,7 @@ static DEVICE_ATTR(debug_level, S_IWUSR | S_IRUGO, static ssize_t show_version(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl_priv *priv = d->driver_data; + struct iwl_priv *priv = dev_get_drvdata(d); struct iwl_alive_resp *palive = &priv->card_alive; ssize_t pos = 0; u16 eeprom_ver; @@ -2936,8 +2508,10 @@ static ssize_t show_version(struct device *d, if (priv->eeprom) { eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION); - pos += sprintf(buf + pos, "EEPROM version: 0x%x\n", - eeprom_ver); + pos += sprintf(buf + pos, "NVM Type: %s, version: 0x%x\n", + (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) + ? "OTP" : "EEPROM", eeprom_ver); + } else { pos += sprintf(buf + pos, "EEPROM not initialzed\n"); } @@ -2950,7 +2524,7 @@ static DEVICE_ATTR(version, S_IWUSR | S_IRUGO, show_version, NULL); static ssize_t show_temperature(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + struct iwl_priv *priv = dev_get_drvdata(d); if (!iwl_is_alive(priv)) return -EAGAIN; @@ -2963,7 +2537,7 @@ static DEVICE_ATTR(temperature, S_IRUGO, show_temperature, NULL); static ssize_t show_tx_power(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + struct iwl_priv *priv = dev_get_drvdata(d); if (!iwl_is_ready_rf(priv)) return sprintf(buf, "off\n"); @@ -2975,7 +2549,7 @@ static ssize_t store_tx_power(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { - struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + struct iwl_priv *priv = dev_get_drvdata(d); unsigned long val; int ret; @@ -2993,7 +2567,7 @@ static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, show_tx_power, store_tx_power); static ssize_t show_flags(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + struct iwl_priv *priv = dev_get_drvdata(d); return sprintf(buf, "0x%04X\n", priv->active_rxon.flags); } @@ -3002,7 +2576,7 @@ static ssize_t store_flags(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { - struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + struct iwl_priv *priv = dev_get_drvdata(d); unsigned long val; u32 flags; int ret = strict_strtoul(buf, 0, &val); @@ -3018,7 +2592,7 @@ static ssize_t store_flags(struct device *d, else { IWL_DEBUG_INFO(priv, "Commit rxon.flags = 0x%04X\n", flags); priv->staging_rxon.flags = cpu_to_le32(flags); - iwl_commit_rxon(priv); + iwlcore_commit_rxon(priv); } } mutex_unlock(&priv->mutex); @@ -3031,7 +2605,7 @@ static DEVICE_ATTR(flags, S_IWUSR | S_IRUGO, show_flags, store_flags); static ssize_t show_filter_flags(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + struct iwl_priv *priv = dev_get_drvdata(d); return sprintf(buf, "0x%04X\n", le32_to_cpu(priv->active_rxon.filter_flags)); @@ -3041,7 +2615,7 @@ static ssize_t store_filter_flags(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { - struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + struct iwl_priv *priv = dev_get_drvdata(d); unsigned long val; u32 filter_flags; int ret = strict_strtoul(buf, 0, &val); @@ -3059,7 +2633,7 @@ static ssize_t store_filter_flags(struct device *d, "0x%04X\n", filter_flags); priv->staging_rxon.filter_flags = cpu_to_le32(filter_flags); - iwl_commit_rxon(priv); + iwlcore_commit_rxon(priv); } } mutex_unlock(&priv->mutex); @@ -3102,32 +2676,37 @@ static ssize_t show_power_level(struct device *d, { struct iwl_priv *priv = dev_get_drvdata(d); int mode = priv->power_data.user_power_setting; - int system = priv->power_data.system_power_setting; int level = priv->power_data.power_mode; char *p = buf; - switch (system) { - case IWL_POWER_SYS_AUTO: - p += sprintf(p, "SYSTEM:auto"); - break; - case IWL_POWER_SYS_AC: - p += sprintf(p, "SYSTEM:ac"); - break; - case IWL_POWER_SYS_BATTERY: - p += sprintf(p, "SYSTEM:battery"); - break; - } - - p += sprintf(p, "\tMODE:%s", (mode < IWL_POWER_AUTO) ? - "fixed" : "auto"); - p += sprintf(p, "\tINDEX:%d", level); - p += sprintf(p, "\n"); + p += sprintf(p, "INDEX:%d\t", level); + p += sprintf(p, "USER:%d\n", mode); return p - buf + 1; } static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level, store_power_level); +static ssize_t show_qos(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + char *p = buf; + int q; + + for (q = 0; q < AC_NUM; q++) { + p += sprintf(p, "\tcw_min\tcw_max\taifsn\ttxop\n"); + p += sprintf(p, "AC[%d]\t%u\t%u\t%u\t%u\n", q, + priv->qos_data.def_qos_parm.ac[q].cw_min, + priv->qos_data.def_qos_parm.ac[q].cw_max, + priv->qos_data.def_qos_parm.ac[q].aifsn, + priv->qos_data.def_qos_parm.ac[q].edca_txop); + } + + return p - buf + 1; +} + +static DEVICE_ATTR(qos, S_IRUGO, show_qos, NULL); static ssize_t show_statistics(struct device *d, struct device_attribute *attr, char *buf) @@ -3183,14 +2762,12 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) INIT_WORK(&priv->up, iwl_bg_up); INIT_WORK(&priv->restart, iwl_bg_restart); INIT_WORK(&priv->rx_replenish, iwl_bg_rx_replenish); - INIT_WORK(&priv->rf_kill, iwl_bg_rf_kill); INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update); INIT_WORK(&priv->run_time_calib_work, iwl_bg_run_time_calib_work); INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start); INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start); iwl_setup_scan_deferred_work(priv); - iwl_setup_power_deferred_work(priv); if (priv->cfg->ops->lib->setup_deferred_work) priv->cfg->ops->lib->setup_deferred_work(priv); @@ -3199,8 +2776,12 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) priv->statistics_periodic.data = (unsigned long)priv; priv->statistics_periodic.function = iwl_bg_statistics_periodic; - tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) - iwl_irq_tasklet, (unsigned long)priv); + if (!priv->cfg->use_isr_legacy) + tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) + iwl_irq_tasklet, (unsigned long)priv); + else + tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) + iwl_irq_tasklet_legacy, (unsigned long)priv); } static void iwl_cancel_deferred_work(struct iwl_priv *priv) @@ -3210,7 +2791,6 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv) cancel_delayed_work_sync(&priv->init_alive_start); cancel_delayed_work(&priv->scan_check); - cancel_delayed_work_sync(&priv->set_power_save); cancel_delayed_work(&priv->alive_start); cancel_work_sync(&priv->beacon_update); del_timer_sync(&priv->statistics_periodic); @@ -3227,7 +2807,7 @@ static struct attribute *iwl_sysfs_entries[] = { &dev_attr_debug_level.attr, #endif &dev_attr_version.attr, - + &dev_attr_qos.attr, NULL }; @@ -3243,7 +2823,6 @@ static struct ieee80211_ops iwl_hw_ops = { .add_interface = iwl_mac_add_interface, .remove_interface = iwl_mac_remove_interface, .config = iwl_mac_config, - .config_interface = iwl_mac_config_interface, .configure_filter = iwl_configure_filter, .set_key = iwl_mac_set_key, .update_tkip_key = iwl_mac_update_tkip_key, @@ -3291,6 +2870,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) IWL_DEBUG_INFO(priv, "*** LOAD DRIVER ***\n"); priv->cfg = cfg; priv->pci_dev = pdev; + priv->inta_mask = CSR_INI_SET_MASK; #ifdef CONFIG_IWLWIFI_DEBUG priv->debug_level = priv->cfg->mod_params->debug; @@ -3341,6 +2921,10 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) (unsigned long long) pci_resource_len(pdev, 0)); IWL_DEBUG_INFO(priv, "pci_resource_base = %p\n", priv->hw_base); + /* this spin lock will be used in apm_ops.init and EEPROM access + * we should init now + */ + spin_lock_init(&priv->reg_lock); iwl_hw_detect(priv); IWL_INFO(priv, "Detected Intel Wireless WiFi Link %s REV=0x%X\n", priv->cfg->name, priv->hw_rev); @@ -3349,6 +2933,12 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) * PCI Tx retries from interfering with C3 CPU state */ pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00); + iwl_prepare_card_hw(priv); + if (!priv->hw_ready) { + IWL_WARN(priv, "Failed, HW not ready\n"); + goto out_iounmap; + } + /* amp init */ err = priv->cfg->ops->lib->apm_ops.init(priv); if (err < 0) { @@ -3390,18 +2980,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto out_free_eeprom; /* At this point both hw and priv are initialized. */ - /********************************** - * 7. Initialize module parameters - **********************************/ - - /* Disable radio (SW RF KILL) via parameter when loading driver */ - if (priv->cfg->mod_params->disable) { - set_bit(STATUS_RF_KILL_SW, &priv->status); - IWL_DEBUG_INFO(priv, "Radio disabled.\n"); - } - /******************** - * 8. Setup services + * 7. Setup services ********************/ spin_lock_irqsave(&priv->lock, flags); iwl_disable_interrupts(priv); @@ -3409,8 +2989,9 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pci_enable_msi(priv->pci_dev); - err = request_irq(priv->pci_dev->irq, iwl_isr, IRQF_SHARED, - DRV_NAME, priv); + iwl_alloc_isr_ict(priv); + err = request_irq(priv->pci_dev->irq, priv->cfg->ops->lib->isr, + IRQF_SHARED, DRV_NAME, priv); if (err) { IWL_ERR(priv, "Error allocating IRQ %d\n", priv->pci_dev->irq); goto out_disable_msi; @@ -3425,7 +3006,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) iwl_setup_rx_handlers(priv); /********************************** - * 9. Setup and register mac80211 + * 8. Setup and register mac80211 **********************************/ /* enable interrupts if needed: hw bug w/a */ @@ -3443,7 +3024,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) err = iwl_dbgfs_register(priv, DRV_NAME); if (err) - IWL_ERR(priv, "failed to create debugfs files\n"); + IWL_ERR(priv, "failed to create debugfs files. Ignoring error: %d\n", err); /* If platform's RF_KILL switch is NOT set to KILL */ if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) @@ -3451,12 +3032,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) else set_bit(STATUS_RF_KILL_HW, &priv->status); - err = iwl_rfkill_init(priv); - if (err) - IWL_ERR(priv, "Unable to initialize RFKILL system. " - "Ignoring error: %d\n", err); - else - iwl_rfkill_set_hw_state(priv); + wiphy_rfkill_set_hw_state(priv->hw->wiphy, + test_bit(STATUS_RF_KILL_HW, &priv->status)); iwl_power_initialize(priv); return 0; @@ -3467,6 +3044,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group); out_free_irq: free_irq(priv->pci_dev->irq, priv); + iwl_free_isr_ict(priv); out_disable_msi: pci_disable_msi(priv->pci_dev); iwl_uninit_drv(priv); @@ -3519,7 +3097,6 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev) iwl_synchronize_irq(priv); - iwl_rfkill_unregister(priv); iwl_dealloc_ucode_pci(priv); if (priv->rxq.bd) @@ -3548,51 +3125,14 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev) iwl_uninit_drv(priv); + iwl_free_isr_ict(priv); + if (priv->ibss_beacon) dev_kfree_skb(priv->ibss_beacon); ieee80211_free_hw(priv->hw); } -#ifdef CONFIG_PM - -static int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state) -{ - struct iwl_priv *priv = pci_get_drvdata(pdev); - - if (priv->is_open) { - set_bit(STATUS_IN_SUSPEND, &priv->status); - iwl_mac_stop(priv->hw); - priv->is_open = 1; - } - - pci_save_state(pdev); - pci_disable_device(pdev); - pci_set_power_state(pdev, PCI_D3hot); - - return 0; -} - -static int iwl_pci_resume(struct pci_dev *pdev) -{ - struct iwl_priv *priv = pci_get_drvdata(pdev); - int ret; - - pci_set_power_state(pdev, PCI_D0); - ret = pci_enable_device(pdev); - if (ret) - return ret; - pci_restore_state(pdev); - iwl_enable_interrupts(priv); - - if (priv->is_open) - iwl_mac_start(priv->hw); - - clear_bit(STATUS_IN_SUSPEND, &priv->status); - return 0; -} - -#endif /* CONFIG_PM */ /***************************************************************************** * diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c index 735f3f19928c..a5d63672ad39 100644 --- a/drivers/net/wireless/iwlwifi/iwl-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-calib.c @@ -857,7 +857,7 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, priv->cfg->ops->lib->update_chain_flags(priv); data->state = IWL_CHAIN_NOISE_DONE; - iwl_power_enable_management(priv); + iwl_power_update_mode(priv, 0); } EXPORT_SYMBOL(iwl_chain_noise_calibration); diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 29d40746da6a..c87033bf3ad2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -614,8 +614,18 @@ enum { #define RXON_FLG_CHANNEL_MODE_POS (25) #define RXON_FLG_CHANNEL_MODE_MSK cpu_to_le32(0x3 << 25) -#define RXON_FLG_CHANNEL_MODE_PURE_40_MSK cpu_to_le32(0x1 << 25) -#define RXON_FLG_CHANNEL_MODE_MIXED_MSK cpu_to_le32(0x2 << 25) + +/* channel mode */ +enum { + CHANNEL_MODE_LEGACY = 0, + CHANNEL_MODE_PURE_40 = 1, + CHANNEL_MODE_MIXED = 2, + CHANNEL_MODE_RESERVED = 3, +}; +#define RXON_FLG_CHANNEL_MODE_LEGACY cpu_to_le32(CHANNEL_MODE_LEGACY << RXON_FLG_CHANNEL_MODE_POS) +#define RXON_FLG_CHANNEL_MODE_PURE_40 cpu_to_le32(CHANNEL_MODE_PURE_40 << RXON_FLG_CHANNEL_MODE_POS) +#define RXON_FLG_CHANNEL_MODE_MIXED cpu_to_le32(CHANNEL_MODE_MIXED << RXON_FLG_CHANNEL_MODE_POS) + /* CTS to self (if spec allows) flag */ #define RXON_FLG_SELF_CTS_EN cpu_to_le32(0x1<<30) @@ -1057,7 +1067,7 @@ struct iwl_addsta_cmd { * Set modify_mask bit STA_MODIFY_TID_DISABLE_TX to use this field. */ __le16 tid_disable_tx; - __le16 reserved1; + __le16 rate_n_flags; /* 3945 only */ /* TID for which to add block-ack support. * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */ @@ -1903,6 +1913,18 @@ struct iwl_link_qual_general_params { u8 start_rate_index[LINK_QUAL_AC_NUM]; } __attribute__ ((packed)); +#define LINK_QUAL_AGG_TIME_LIMIT_DEF (4000) /* 4 milliseconds */ +#define LINK_QUAL_AGG_TIME_LIMIT_MAX (65535) +#define LINK_QUAL_AGG_TIME_LIMIT_MIN (0) + +#define LINK_QUAL_AGG_DISABLE_START_DEF (3) +#define LINK_QUAL_AGG_DISABLE_START_MAX (255) +#define LINK_QUAL_AGG_DISABLE_START_MIN (0) + +#define LINK_QUAL_AGG_FRAME_LIMIT_DEF (31) +#define LINK_QUAL_AGG_FRAME_LIMIT_MAX (64) +#define LINK_QUAL_AGG_FRAME_LIMIT_MIN (0) + /** * struct iwl_link_qual_agg_params * @@ -2469,11 +2491,12 @@ struct iwl_ssid_ie { u8 ssid[32]; } __attribute__ ((packed)); -#define PROBE_OPTION_MAX_API1 0x4 -#define PROBE_OPTION_MAX 0x14 +#define PROBE_OPTION_MAX_3945 4 +#define PROBE_OPTION_MAX 20 #define TX_CMD_LIFE_TIME_INFINITE cpu_to_le32(0xFFFFFFFF) #define IWL_GOOD_CRC_TH cpu_to_le16(1) #define IWL_MAX_SCAN_SIZE 1024 +#define IWL_MAX_PROBE_REQUEST 200 /* * REPLY_SCAN_CMD = 0x80 (command) @@ -2552,7 +2575,7 @@ struct iwl3945_scan_cmd { struct iwl3945_tx_cmd tx_cmd; /* For directed active scans (set to all-0s otherwise) */ - struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX_API1]; + struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX_3945]; /* * Probe request frame, followed by channel list. diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index c54fb93e9d72..6ab07165ea28 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -36,9 +36,9 @@ #include "iwl-debug.h" #include "iwl-core.h" #include "iwl-io.h" -#include "iwl-rfkill.h" #include "iwl-power.h" #include "iwl-sta.h" +#include "iwl-helpers.h" MODULE_DESCRIPTION("iwl core"); @@ -59,6 +59,8 @@ MODULE_LICENSE("GPL"); IWL_RATE_##pp##M_INDEX, \ IWL_RATE_##np##M_INDEX } +static irqreturn_t iwl_isr(int irq, void *data); + /* * Parameter order: * rate, ht rate, prev rate, next rate, prev tgg rate, next tgg rate @@ -273,6 +275,14 @@ void iwl_activate_qos(struct iwl_priv *priv, u8 force) } EXPORT_SYMBOL(iwl_activate_qos); +/* + * AC CWmin CW max AIFSN TXOP Limit TXOP Limit + * (802.11b) (802.11a/g) + * AC_BK 15 1023 7 0 0 + * AC_BE 15 1023 3 0 0 + * AC_VI 7 15 2 6.016ms 3.008ms + * AC_VO 3 7 2 3.264ms 1.504ms + */ void iwl_reset_qos(struct iwl_priv *priv) { u16 cw_min = 15; @@ -304,6 +314,7 @@ void iwl_reset_qos(struct iwl_priv *priv) if (priv->qos_data.qos_active) aifs = 3; + /* AC_BE */ priv->qos_data.def_qos_parm.ac[0].cw_min = cpu_to_le16(cw_min); priv->qos_data.def_qos_parm.ac[0].cw_max = cpu_to_le16(cw_max); priv->qos_data.def_qos_parm.ac[0].aifsn = aifs; @@ -311,6 +322,7 @@ void iwl_reset_qos(struct iwl_priv *priv) priv->qos_data.def_qos_parm.ac[0].reserved1 = 0; if (priv->qos_data.qos_active) { + /* AC_BK */ i = 1; priv->qos_data.def_qos_parm.ac[i].cw_min = cpu_to_le16(cw_min); priv->qos_data.def_qos_parm.ac[i].cw_max = cpu_to_le16(cw_max); @@ -318,11 +330,12 @@ void iwl_reset_qos(struct iwl_priv *priv) priv->qos_data.def_qos_parm.ac[i].edca_txop = 0; priv->qos_data.def_qos_parm.ac[i].reserved1 = 0; + /* AC_VI */ i = 2; priv->qos_data.def_qos_parm.ac[i].cw_min = cpu_to_le16((cw_min + 1) / 2 - 1); priv->qos_data.def_qos_parm.ac[i].cw_max = - cpu_to_le16(cw_max); + cpu_to_le16(cw_min); priv->qos_data.def_qos_parm.ac[i].aifsn = 2; if (is_legacy) priv->qos_data.def_qos_parm.ac[i].edca_txop = @@ -332,11 +345,12 @@ void iwl_reset_qos(struct iwl_priv *priv) cpu_to_le16(3008); priv->qos_data.def_qos_parm.ac[i].reserved1 = 0; + /* AC_VO */ i = 3; priv->qos_data.def_qos_parm.ac[i].cw_min = cpu_to_le16((cw_min + 1) / 4 - 1); priv->qos_data.def_qos_parm.ac[i].cw_max = - cpu_to_le16((cw_max + 1) / 2 - 1); + cpu_to_le16((cw_min + 1) / 2 - 1); priv->qos_data.def_qos_parm.ac[i].aifsn = 2; priv->qos_data.def_qos_parm.ac[i].reserved1 = 0; if (is_legacy) @@ -591,10 +605,10 @@ static u8 iwl_is_channel_extension(struct iwl_priv *priv, if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE) return !(ch_info->fat_extension_channel & - IEEE80211_CHAN_NO_FAT_ABOVE); + IEEE80211_CHAN_NO_HT40PLUS); else if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW) return !(ch_info->fat_extension_channel & - IEEE80211_CHAN_NO_FAT_BELOW); + IEEE80211_CHAN_NO_HT40MINUS); return 0; } @@ -605,19 +619,19 @@ u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv, struct iwl_ht_info *iwl_ht_conf = &priv->current_ht_config; if ((!iwl_ht_conf->is_ht) || - (iwl_ht_conf->supported_chan_width != IWL_CHANNEL_WIDTH_40MHZ) || - (iwl_ht_conf->extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_NONE)) + (iwl_ht_conf->supported_chan_width != IWL_CHANNEL_WIDTH_40MHZ)) return 0; + /* We do not check for IEEE80211_HT_CAP_SUP_WIDTH_20_40 + * the bit will not set if it is pure 40MHz case + */ if (sta_ht_inf) { - if ((!sta_ht_inf->ht_supported) || - (!(sta_ht_inf->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40))) + if (!sta_ht_inf->ht_supported) return 0; } - return iwl_is_channel_extension(priv, priv->band, - le16_to_cpu(priv->staging_rxon.channel), - iwl_ht_conf->extension_chan_offset); + le16_to_cpu(priv->staging_rxon.channel), + iwl_ht_conf->extension_chan_offset); } EXPORT_SYMBOL(iwl_is_fat_tx_allowed); @@ -735,6 +749,8 @@ int iwl_full_rxon_required(struct iwl_priv *priv) priv->active_rxon.ofdm_ht_single_stream_basic_rates) || (priv->staging_rxon.ofdm_ht_dual_stream_basic_rates != priv->active_rxon.ofdm_ht_dual_stream_basic_rates) || + (priv->staging_rxon.ofdm_ht_triple_stream_basic_rates != + priv->active_rxon.ofdm_ht_triple_stream_basic_rates) || (priv->staging_rxon.assoc_id != priv->active_rxon.assoc_id)) return 1; @@ -785,43 +801,62 @@ EXPORT_SYMBOL(iwl_rate_get_lowest_plcp); void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info) { struct iwl_rxon_cmd *rxon = &priv->staging_rxon; - u32 val; if (!ht_info->is_ht) { - rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK | - RXON_FLG_CHANNEL_MODE_PURE_40_MSK | + rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK | RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK | RXON_FLG_FAT_PROT_MSK | RXON_FLG_HT_PROT_MSK); return; } - /* Set up channel bandwidth: 20 MHz only, or 20/40 mixed if fat ok */ - if (iwl_is_fat_tx_allowed(priv, NULL)) - rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED_MSK; - else - rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK | - RXON_FLG_CHANNEL_MODE_PURE_40_MSK); + /* FIXME: if the definition of ht_protection changed, the "translation" + * will be needed for rxon->flags + */ + rxon->flags |= cpu_to_le32(ht_info->ht_protection << RXON_FLG_HT_OPERATING_MODE_POS); - /* Note: control channel is opposite of extension channel */ - switch (ht_info->extension_chan_offset) { - case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: - rxon->flags &= ~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK); - break; - case IEEE80211_HT_PARAM_CHA_SEC_BELOW: - rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK; - break; - case IEEE80211_HT_PARAM_CHA_SEC_NONE: - default: - rxon->flags &= ~RXON_FLG_CHANNEL_MODE_MIXED_MSK; - break; + /* Set up channel bandwidth: + * 20 MHz only, 20/40 mixed or pure 40 if fat ok */ + /* clear the HT channel mode before set the mode */ + rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK | + RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK); + if (iwl_is_fat_tx_allowed(priv, NULL)) { + /* pure 40 fat */ + if (ht_info->ht_protection == IEEE80211_HT_OP_MODE_PROTECTION_20MHZ) { + rxon->flags |= RXON_FLG_CHANNEL_MODE_PURE_40; + /* Note: control channel is opposite of extension channel */ + switch (ht_info->extension_chan_offset) { + case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: + rxon->flags &= ~RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK; + break; + case IEEE80211_HT_PARAM_CHA_SEC_BELOW: + rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK; + break; + } + } else { + /* Note: control channel is opposite of extension channel */ + switch (ht_info->extension_chan_offset) { + case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: + rxon->flags &= ~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK); + rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED; + break; + case IEEE80211_HT_PARAM_CHA_SEC_BELOW: + rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK; + rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED; + break; + case IEEE80211_HT_PARAM_CHA_SEC_NONE: + default: + /* channel location only valid if in Mixed mode */ + IWL_ERR(priv, "invalid extension channel offset\n"); + break; + } + } + } else { + rxon->flags |= RXON_FLG_CHANNEL_MODE_LEGACY; } - val = ht_info->ht_protection; - - rxon->flags |= cpu_to_le32(val << RXON_FLG_HT_OPERATING_MODE_POS); - - iwl_set_rxon_chain(priv); + if (priv->cfg->ops->hcmd->set_rxon_chain) + priv->cfg->ops->hcmd->set_rxon_chain(priv); IWL_DEBUG_ASSOC(priv, "supported HT rate 0x%X 0x%X 0x%X " "rxon flags 0x%X operation mode :0x%X " @@ -901,10 +936,11 @@ static u8 iwl_count_chain_bitmap(u32 chain_bitmap) * never called for monitor mode. The only way mac80211 informs us about * monitor mode is through configuring filters (call to configure_filter). */ -static bool iwl_is_monitor_mode(struct iwl_priv *priv) +bool iwl_is_monitor_mode(struct iwl_priv *priv) { return !!(priv->staging_rxon.filter_flags & RXON_FILTER_PROMISC_MSK); } +EXPORT_SYMBOL(iwl_is_monitor_mode); /** * iwl_set_rxon_chain - Set up Rx chain usage in "staging" RXON image @@ -956,10 +992,10 @@ void iwl_set_rxon_chain(struct iwl_priv *priv) if (iwl_is_monitor_mode(priv) && !(priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) && ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965)) { - rx_chain = 0x07 << RXON_RX_CHAIN_VALID_POS; - rx_chain |= 0x06 << RXON_RX_CHAIN_FORCE_SEL_POS; - rx_chain |= 0x07 << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS; - rx_chain |= 0x01 << RXON_RX_CHAIN_DRIVER_FORCE_POS; + rx_chain = ANT_ABC << RXON_RX_CHAIN_VALID_POS; + rx_chain |= ANT_BC << RXON_RX_CHAIN_FORCE_SEL_POS; + rx_chain |= ANT_ABC << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS; + rx_chain |= 0x1 << RXON_RX_CHAIN_DRIVER_FORCE_POS; } priv->staging_rxon.rx_chain = cpu_to_le16(rx_chain); @@ -1068,11 +1104,6 @@ void iwl_connection_init_rx_config(struct iwl_priv *priv, int mode) RXON_FILTER_ACCEPT_GRP_MSK; break; - case NL80211_IFTYPE_MONITOR: - priv->staging_rxon.dev_type = RXON_DEV_TYPE_SNIFFER; - priv->staging_rxon.filter_flags = RXON_FILTER_PROMISC_MSK | - RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_ACCEPT_GRP_MSK; - break; default: IWL_ERR(priv, "Unsupported interface type %d\n", mode); break; @@ -1111,16 +1142,18 @@ void iwl_connection_init_rx_config(struct iwl_priv *priv, int mode) priv->staging_rxon.cck_basic_rates = (IWL_CCK_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF; - priv->staging_rxon.flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK | - RXON_FLG_CHANNEL_MODE_PURE_40_MSK); + /* clear both MIX and PURE40 mode flag */ + priv->staging_rxon.flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED | + RXON_FLG_CHANNEL_MODE_PURE_40); memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); memcpy(priv->staging_rxon.wlap_bssid_addr, priv->mac_addr, ETH_ALEN); priv->staging_rxon.ofdm_ht_single_stream_basic_rates = 0xff; priv->staging_rxon.ofdm_ht_dual_stream_basic_rates = 0xff; + priv->staging_rxon.ofdm_ht_triple_stream_basic_rates = 0xff; } EXPORT_SYMBOL(iwl_connection_init_rx_config); -void iwl_set_rate(struct iwl_priv *priv) +static void iwl_set_rate(struct iwl_priv *priv) { const struct ieee80211_supported_band *hw = NULL; struct ieee80211_rate *rate; @@ -1166,7 +1199,6 @@ void iwl_set_rate(struct iwl_priv *priv) priv->staging_rxon.ofdm_basic_rates = (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF; } -EXPORT_SYMBOL(iwl_set_rate); void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { @@ -1230,11 +1262,6 @@ void iwl_irq_handle_error(struct iwl_priv *priv) IWL_DEBUG(priv, IWL_DL_FW_ERRORS, "Restarting adapter due to uCode error.\n"); - if (iwl_is_associated(priv)) { - memcpy(&priv->recovery_rxon, &priv->active_rxon, - sizeof(priv->recovery_rxon)); - priv->error_recovering = 1; - } if (priv->cfg->mod_params->restart_fw) queue_work(priv->workqueue, &priv->restart); } @@ -1298,19 +1325,20 @@ int iwl_setup_mac(struct iwl_priv *priv) hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM | IEEE80211_HW_AMPDU_AGGREGATION | - IEEE80211_HW_SPECTRUM_MGMT | - IEEE80211_HW_SUPPORTS_PS; + IEEE80211_HW_SPECTRUM_MGMT; hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); hw->wiphy->custom_regulatory = true; - hw->wiphy->max_scan_ssids = 1; + + hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX; + /* we create the 802.11 header and a zero-length SSID element */ + hw->wiphy->max_scan_ie_len = IWL_MAX_PROBE_REQUEST - 24 - 2; /* Default value; 4 EDCA QOS priorities */ hw->queues = 4; - hw->conf.beacon_int = 100; hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL; if (priv->bands[IEEE80211_BAND_2GHZ].n_channels) @@ -1357,7 +1385,6 @@ int iwl_init_drv(struct iwl_priv *priv) priv->ibss_beacon = NULL; spin_lock_init(&priv->lock); - spin_lock_init(&priv->power_data.lock); spin_lock_init(&priv->sta_lock); spin_lock_init(&priv->hcmd_lock); @@ -1378,7 +1405,9 @@ int iwl_init_drv(struct iwl_priv *priv) priv->current_ht_config.sm_ps = WLAN_HT_CAP_SM_PS_DISABLED; /* Choose which receivers/antennas to use */ - iwl_set_rxon_chain(priv); + if (priv->cfg->ops->hcmd->set_rxon_chain) + priv->cfg->ops->hcmd->set_rxon_chain(priv); + iwl_init_scan_params(priv); iwl_reset_qos(priv); @@ -1475,11 +1504,273 @@ void iwl_enable_interrupts(struct iwl_priv *priv) { IWL_DEBUG_ISR(priv, "Enabling interrupts\n"); set_bit(STATUS_INT_ENABLED, &priv->status); - iwl_write32(priv, CSR_INT_MASK, CSR_INI_SET_MASK); + iwl_write32(priv, CSR_INT_MASK, priv->inta_mask); } EXPORT_SYMBOL(iwl_enable_interrupts); -irqreturn_t iwl_isr(int irq, void *data) + +#define ICT_COUNT (PAGE_SIZE/sizeof(u32)) + +/* Free dram table */ +void iwl_free_isr_ict(struct iwl_priv *priv) +{ + if (priv->ict_tbl_vir) { + pci_free_consistent(priv->pci_dev, (sizeof(u32) * ICT_COUNT) + + PAGE_SIZE, priv->ict_tbl_vir, + priv->ict_tbl_dma); + priv->ict_tbl_vir = NULL; + } +} +EXPORT_SYMBOL(iwl_free_isr_ict); + + +/* allocate dram shared table it is a PAGE_SIZE aligned + * also reset all data related to ICT table interrupt. + */ +int iwl_alloc_isr_ict(struct iwl_priv *priv) +{ + + if (priv->cfg->use_isr_legacy) + return 0; + /* allocate shrared data table */ + priv->ict_tbl_vir = pci_alloc_consistent(priv->pci_dev, (sizeof(u32) * + ICT_COUNT) + PAGE_SIZE, + &priv->ict_tbl_dma); + if (!priv->ict_tbl_vir) + return -ENOMEM; + + /* align table to PAGE_SIZE boundry */ + priv->aligned_ict_tbl_dma = ALIGN(priv->ict_tbl_dma, PAGE_SIZE); + + IWL_DEBUG_ISR(priv, "ict dma addr %Lx dma aligned %Lx diff %d\n", + (unsigned long long)priv->ict_tbl_dma, + (unsigned long long)priv->aligned_ict_tbl_dma, + (int)(priv->aligned_ict_tbl_dma - priv->ict_tbl_dma)); + + priv->ict_tbl = priv->ict_tbl_vir + + (priv->aligned_ict_tbl_dma - priv->ict_tbl_dma); + + IWL_DEBUG_ISR(priv, "ict vir addr %p vir aligned %p diff %d\n", + priv->ict_tbl, priv->ict_tbl_vir, + (int)(priv->aligned_ict_tbl_dma - priv->ict_tbl_dma)); + + /* reset table and index to all 0 */ + memset(priv->ict_tbl_vir,0, (sizeof(u32) * ICT_COUNT) + PAGE_SIZE); + priv->ict_index = 0; + + /* add periodic RX interrupt */ + priv->inta_mask |= CSR_INT_BIT_RX_PERIODIC; + return 0; +} +EXPORT_SYMBOL(iwl_alloc_isr_ict); + +/* Device is going up inform it about using ICT interrupt table, + * also we need to tell the driver to start using ICT interrupt. + */ +int iwl_reset_ict(struct iwl_priv *priv) +{ + u32 val; + unsigned long flags; + + if (!priv->ict_tbl_vir) + return 0; + + spin_lock_irqsave(&priv->lock, flags); + iwl_disable_interrupts(priv); + + memset(&priv->ict_tbl[0],0, sizeof(u32) * ICT_COUNT); + + val = priv->aligned_ict_tbl_dma >> PAGE_SHIFT; + + val |= CSR_DRAM_INT_TBL_ENABLE; + val |= CSR_DRAM_INIT_TBL_WRAP_CHECK; + + IWL_DEBUG_ISR(priv, "CSR_DRAM_INT_TBL_REG =0x%X " + "aligned dma address %Lx\n", + val, (unsigned long long)priv->aligned_ict_tbl_dma); + + iwl_write32(priv, CSR_DRAM_INT_TBL_REG, val); + priv->use_ict = true; + priv->ict_index = 0; + iwl_write32(priv, CSR_INT, priv->inta_mask); + iwl_enable_interrupts(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} +EXPORT_SYMBOL(iwl_reset_ict); + +/* Device is going down disable ict interrupt usage */ +void iwl_disable_ict(struct iwl_priv *priv) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + priv->use_ict = false; + spin_unlock_irqrestore(&priv->lock, flags); +} +EXPORT_SYMBOL(iwl_disable_ict); + +/* interrupt handler using ict table, with this interrupt driver will + * stop using INTA register to get device's interrupt, reading this register + * is expensive, device will write interrupts in ICT dram table, increment + * index then will fire interrupt to driver, driver will OR all ICT table + * entries from current index up to table entry with 0 value. the result is + * the interrupt we need to service, driver will set the entries back to 0 and + * set index. + */ +irqreturn_t iwl_isr_ict(int irq, void *data) +{ + struct iwl_priv *priv = data; + u32 inta, inta_mask; + u32 val = 0; + + if (!priv) + return IRQ_NONE; + + /* dram interrupt table not set yet, + * use legacy interrupt. + */ + if (!priv->use_ict) + return iwl_isr(irq, data); + + spin_lock(&priv->lock); + + /* Disable (but don't clear!) interrupts here to avoid + * back-to-back ISRs and sporadic interrupts from our NIC. + * If we have something to service, the tasklet will re-enable ints. + * If we *don't* have something, we'll re-enable before leaving here. + */ + inta_mask = iwl_read32(priv, CSR_INT_MASK); /* just for debug */ + iwl_write32(priv, CSR_INT_MASK, 0x00000000); + + + /* Ignore interrupt if there's nothing in NIC to service. + * This may be due to IRQ shared with another device, + * or due to sporadic interrupts thrown from our NIC. */ + if (!priv->ict_tbl[priv->ict_index]) { + IWL_DEBUG_ISR(priv, "Ignore interrupt, inta == 0\n"); + goto none; + } + + /* read all entries that not 0 start with ict_index */ + while (priv->ict_tbl[priv->ict_index]) { + + val |= priv->ict_tbl[priv->ict_index]; + IWL_DEBUG_ISR(priv, "ICT index %d value 0x%08X\n", + priv->ict_index, + priv->ict_tbl[priv->ict_index]); + priv->ict_tbl[priv->ict_index] = 0; + priv->ict_index = iwl_queue_inc_wrap(priv->ict_index, + ICT_COUNT); + + } + + /* We should not get this value, just ignore it. */ + if (val == 0xffffffff) + val = 0; + + inta = (0xff & val) | ((0xff00 & val) << 16); + IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x ict 0x%08x\n", + inta, inta_mask, val); + + inta &= priv->inta_mask; + priv->inta |= inta; + + /* iwl_irq_tasklet() will service interrupts and re-enable them */ + if (likely(inta)) + tasklet_schedule(&priv->irq_tasklet); + else if (test_bit(STATUS_INT_ENABLED, &priv->status) && !priv->inta) { + /* Allow interrupt if was disabled by this handler and + * no tasklet was schedules, We should not enable interrupt, + * tasklet will enable it. + */ + iwl_enable_interrupts(priv); + } + + spin_unlock(&priv->lock); + return IRQ_HANDLED; + + none: + /* re-enable interrupts here since we don't have anything to service. + * only Re-enable if disabled by irq. + */ + if (test_bit(STATUS_INT_ENABLED, &priv->status) && !priv->inta) + iwl_enable_interrupts(priv); + + spin_unlock(&priv->lock); + return IRQ_NONE; +} +EXPORT_SYMBOL(iwl_isr_ict); + + +static irqreturn_t iwl_isr(int irq, void *data) +{ + struct iwl_priv *priv = data; + u32 inta, inta_mask; +#ifdef CONFIG_IWLWIFI_DEBUG + u32 inta_fh; +#endif + if (!priv) + return IRQ_NONE; + + spin_lock(&priv->lock); + + /* Disable (but don't clear!) interrupts here to avoid + * back-to-back ISRs and sporadic interrupts from our NIC. + * If we have something to service, the tasklet will re-enable ints. + * If we *don't* have something, we'll re-enable before leaving here. */ + inta_mask = iwl_read32(priv, CSR_INT_MASK); /* just for debug */ + iwl_write32(priv, CSR_INT_MASK, 0x00000000); + + /* Discover which interrupts are active/pending */ + inta = iwl_read32(priv, CSR_INT); + + /* Ignore interrupt if there's nothing in NIC to service. + * This may be due to IRQ shared with another device, + * or due to sporadic interrupts thrown from our NIC. */ + if (!inta) { + IWL_DEBUG_ISR(priv, "Ignore interrupt, inta == 0\n"); + goto none; + } + + if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) { + /* Hardware disappeared. It might have already raised + * an interrupt */ + IWL_WARN(priv, "HARDWARE GONE?? INTA == 0x%08x\n", inta); + goto unplugged; + } + +#ifdef CONFIG_IWLWIFI_DEBUG + if (priv->debug_level & (IWL_DL_ISR)) { + inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); + IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x, " + "fh 0x%08x\n", inta, inta_mask, inta_fh); + } +#endif + + priv->inta |= inta; + /* iwl_irq_tasklet() will service interrupts and re-enable them */ + if (likely(inta)) + tasklet_schedule(&priv->irq_tasklet); + else if (test_bit(STATUS_INT_ENABLED, &priv->status) && !priv->inta) + iwl_enable_interrupts(priv); + + unplugged: + spin_unlock(&priv->lock); + return IRQ_HANDLED; + + none: + /* re-enable interrupts here since we don't have anything to service. */ + /* only Re-enable if diabled by irq and no schedules tasklet. */ + if (test_bit(STATUS_INT_ENABLED, &priv->status) && !priv->inta) + iwl_enable_interrupts(priv); + + spin_unlock(&priv->lock); + return IRQ_NONE; +} + +irqreturn_t iwl_isr_legacy(int irq, void *data) { struct iwl_priv *priv = data; u32 inta, inta_mask; @@ -1536,7 +1827,7 @@ irqreturn_t iwl_isr(int irq, void *data) spin_unlock(&priv->lock); return IRQ_NONE; } -EXPORT_SYMBOL(iwl_isr); +EXPORT_SYMBOL(iwl_isr_legacy); int iwl_send_bt_config(struct iwl_priv *priv) { @@ -1580,10 +1871,6 @@ static int iwlcore_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len); - ret = iwl_grab_nic_access(priv); - if (ret) - return ret; - for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) { /* read data comes through single port, auto-incr addr */ /* NOTE: Use the debugless read so we don't flood kernel log @@ -1599,8 +1886,6 @@ static int iwlcore_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 } } - iwl_release_nic_access(priv); - return ret; } @@ -1618,10 +1903,6 @@ static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 *image, IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len); - ret = iwl_grab_nic_access(priv); - if (ret) - return ret; - iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, IWL49_RTC_INST_LOWER_BOUND); @@ -1642,8 +1923,6 @@ static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 *image, } } - iwl_release_nic_access(priv); - if (!errcnt) IWL_DEBUG_INFO(priv, "ucode image in INSTRUCTION memory is good\n"); @@ -1752,7 +2031,6 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv) u32 data2, line; u32 desc, time, count, base, data1; u32 blink1, blink2, ilink1, ilink2; - int ret; if (priv->ucode_type == UCODE_INIT) base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr); @@ -1764,12 +2042,6 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv) return; } - ret = iwl_grab_nic_access(priv); - if (ret) { - IWL_WARN(priv, "Can not read from adapter at this time.\n"); - return; - } - count = iwl_read_targ_mem(priv, base); if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) { @@ -1796,7 +2068,6 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv) IWL_ERR(priv, "0x%05X 0x%05X 0x%05X 0x%05X\n", blink1, blink2, ilink1, ilink2); - iwl_release_nic_access(priv); } EXPORT_SYMBOL(iwl_dump_nic_error_log); @@ -1805,7 +2076,6 @@ EXPORT_SYMBOL(iwl_dump_nic_error_log); /** * iwl_print_event_log - Dump error event log to syslog * - * NOTE: Must be called with iwl_grab_nic_access() already obtained! */ static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, u32 num_events, u32 mode) @@ -1851,7 +2121,6 @@ static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, void iwl_dump_nic_event_log(struct iwl_priv *priv) { - int ret; u32 base; /* SRAM byte address of event log header */ u32 capacity; /* event log capacity in # entries */ u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */ @@ -1869,12 +2138,6 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv) return; } - ret = iwl_grab_nic_access(priv); - if (ret) { - IWL_WARN(priv, "Can not read from adapter at this time.\n"); - return; - } - /* event log header */ capacity = iwl_read_targ_mem(priv, base); mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32))); @@ -1886,7 +2149,6 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv) /* bail out if nothing in log */ if (size == 0) { IWL_ERR(priv, "Start IWL Event Log Dump: nothing in log\n"); - iwl_release_nic_access(priv); return; } @@ -1901,7 +2163,6 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv) /* (then/else) start at top of log */ iwl_print_event_log(priv, 0, next_entry, mode); - iwl_release_nic_access(priv); } EXPORT_SYMBOL(iwl_dump_nic_event_log); @@ -1954,126 +2215,6 @@ int iwl_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_flag) } EXPORT_SYMBOL(iwl_send_card_state); -void iwl_radio_kill_sw_disable_radio(struct iwl_priv *priv) -{ - unsigned long flags; - - if (test_bit(STATUS_RF_KILL_SW, &priv->status)) - return; - - IWL_DEBUG_RF_KILL(priv, "Manual SW RF KILL set to: RADIO OFF\n"); - - iwl_scan_cancel(priv); - /* FIXME: This is a workaround for AP */ - if (priv->iw_mode != NL80211_IFTYPE_AP) { - spin_lock_irqsave(&priv->lock, flags); - iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, - CSR_UCODE_SW_BIT_RFKILL); - spin_unlock_irqrestore(&priv->lock, flags); - /* call the host command only if no hw rf-kill set */ - if (!test_bit(STATUS_RF_KILL_HW, &priv->status) && - iwl_is_ready(priv)) - iwl_send_card_state(priv, - CARD_STATE_CMD_DISABLE, 0); - set_bit(STATUS_RF_KILL_SW, &priv->status); - /* make sure mac80211 stop sending Tx frame */ - if (priv->mac80211_registered) - ieee80211_stop_queues(priv->hw); - } -} -EXPORT_SYMBOL(iwl_radio_kill_sw_disable_radio); - -int iwl_radio_kill_sw_enable_radio(struct iwl_priv *priv) -{ - unsigned long flags; - - if (!test_bit(STATUS_RF_KILL_SW, &priv->status)) - return 0; - - IWL_DEBUG_RF_KILL(priv, "Manual SW RF KILL set to: RADIO ON\n"); - - spin_lock_irqsave(&priv->lock, flags); - iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); - - /* If the driver is up it will receive CARD_STATE_NOTIFICATION - * notification where it will clear SW rfkill status. - * Setting it here would break the handler. Only if the - * interface is down we can set here since we don't - * receive any further notification. - */ - if (!priv->is_open) - clear_bit(STATUS_RF_KILL_SW, &priv->status); - spin_unlock_irqrestore(&priv->lock, flags); - - /* wake up ucode */ - msleep(10); - - 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(priv, "Can not turn radio back on - " - "disabled by HW switch\n"); - return 0; - } - - /* when driver is up while rfkill is on, it wont receive - * any CARD_STATE_NOTIFICATION notifications so we have to - * restart it in here - */ - if (priv->is_open && !test_bit(STATUS_ALIVE, &priv->status)) { - clear_bit(STATUS_RF_KILL_SW, &priv->status); - if (!iwl_is_rfkill(priv)) - queue_work(priv->workqueue, &priv->up); - } - - /* If the driver is already loaded, it will receive - * CARD_STATE_NOTIFICATION notifications and the handler will - * call restart to reload the driver. - */ - return 1; -} -EXPORT_SYMBOL(iwl_radio_kill_sw_enable_radio); - -void iwl_bg_rf_kill(struct work_struct *work) -{ - struct iwl_priv *priv = container_of(work, struct iwl_priv, rf_kill); - - wake_up_interruptible(&priv->wait_command_queue); - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - mutex_lock(&priv->mutex); - - if (!iwl_is_rfkill(priv)) { - IWL_DEBUG_RF_KILL(priv, - "HW and/or SW RF Kill no longer active, restarting " - "device\n"); - if (!test_bit(STATUS_EXIT_PENDING, &priv->status) && - test_bit(STATUS_ALIVE, &priv->status)) - queue_work(priv->workqueue, &priv->restart); - } else { - /* make sure mac80211 stop sending Tx frame */ - if (priv->mac80211_registered) - ieee80211_stop_queues(priv->hw); - - if (!test_bit(STATUS_RF_KILL_HW, &priv->status)) - IWL_DEBUG_RF_KILL(priv, "Can not turn radio back on - " - "disabled by SW switch\n"); - else - IWL_WARN(priv, "Radio Frequency Kill Switch is On:\n" - "Kill switch must be turned off for " - "wireless networking to work.\n"); - } - mutex_unlock(&priv->mutex); - iwl_rfkill_set_hw_state(priv); -} -EXPORT_SYMBOL(iwl_bg_rf_kill); - void iwl_rx_pm_sleep_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { @@ -2112,3 +2253,668 @@ void iwl_rx_reply_error(struct iwl_priv *priv, } EXPORT_SYMBOL(iwl_rx_reply_error); +void iwl_clear_isr_stats(struct iwl_priv *priv) +{ + memset(&priv->isr_stats, 0, sizeof(priv->isr_stats)); +} +EXPORT_SYMBOL(iwl_clear_isr_stats); + +int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, + const struct ieee80211_tx_queue_params *params) +{ + struct iwl_priv *priv = hw->priv; + unsigned long flags; + int q; + + IWL_DEBUG_MAC80211(priv, "enter\n"); + + if (!iwl_is_ready_rf(priv)) { + IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n"); + return -EIO; + } + + if (queue >= AC_NUM) { + IWL_DEBUG_MAC80211(priv, "leave - queue >= AC_NUM %d\n", queue); + return 0; + } + + q = AC_NUM - 1 - queue; + + spin_lock_irqsave(&priv->lock, flags); + + priv->qos_data.def_qos_parm.ac[q].cw_min = cpu_to_le16(params->cw_min); + priv->qos_data.def_qos_parm.ac[q].cw_max = cpu_to_le16(params->cw_max); + priv->qos_data.def_qos_parm.ac[q].aifsn = params->aifs; + priv->qos_data.def_qos_parm.ac[q].edca_txop = + cpu_to_le16((params->txop * 32)); + + priv->qos_data.def_qos_parm.ac[q].reserved1 = 0; + priv->qos_data.qos_active = 1; + + if (priv->iw_mode == NL80211_IFTYPE_AP) + iwl_activate_qos(priv, 1); + else if (priv->assoc_id && iwl_is_associated(priv)) + iwl_activate_qos(priv, 0); + + spin_unlock_irqrestore(&priv->lock, flags); + + IWL_DEBUG_MAC80211(priv, "leave\n"); + return 0; +} +EXPORT_SYMBOL(iwl_mac_conf_tx); + +static void iwl_ht_conf(struct iwl_priv *priv, + struct ieee80211_bss_conf *bss_conf) +{ + struct ieee80211_sta_ht_cap *ht_conf; + struct iwl_ht_info *iwl_conf = &priv->current_ht_config; + struct ieee80211_sta *sta; + + IWL_DEBUG_MAC80211(priv, "enter: \n"); + + if (!iwl_conf->is_ht) + return; + + + /* + * It is totally wrong to base global information on something + * that is valid only when associated, alas, this driver works + * that way and I don't know how to fix it. + */ + + rcu_read_lock(); + sta = ieee80211_find_sta(priv->hw, priv->bssid); + if (!sta) { + rcu_read_unlock(); + return; + } + ht_conf = &sta->ht_cap; + + if (ht_conf->cap & IEEE80211_HT_CAP_SGI_20) + iwl_conf->sgf |= HT_SHORT_GI_20MHZ; + if (ht_conf->cap & IEEE80211_HT_CAP_SGI_40) + iwl_conf->sgf |= HT_SHORT_GI_40MHZ; + + iwl_conf->is_green_field = !!(ht_conf->cap & IEEE80211_HT_CAP_GRN_FLD); + iwl_conf->max_amsdu_size = + !!(ht_conf->cap & IEEE80211_HT_CAP_MAX_AMSDU); + + iwl_conf->supported_chan_width = + !!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40); + + /* + * XXX: The HT configuration needs to be moved into iwl_mac_config() + * to be done there correctly. + */ + + iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE; + if (conf_is_ht40_minus(&priv->hw->conf)) + iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_BELOW; + else if (conf_is_ht40_plus(&priv->hw->conf)) + iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_ABOVE; + + /* If no above or below channel supplied disable FAT channel */ + if (iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_ABOVE && + iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_BELOW) + iwl_conf->supported_chan_width = 0; + + iwl_conf->sm_ps = (u8)((ht_conf->cap & IEEE80211_HT_CAP_SM_PS) >> 2); + + memcpy(&iwl_conf->mcs, &ht_conf->mcs, 16); + + iwl_conf->tx_chan_width = iwl_conf->supported_chan_width != 0; + iwl_conf->ht_protection = + bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION; + iwl_conf->non_GF_STA_present = + !!(bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); + + rcu_read_unlock(); + + IWL_DEBUG_MAC80211(priv, "leave\n"); +} + +#define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6) +void iwl_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, + u32 changes) +{ + struct iwl_priv *priv = hw->priv; + int ret; + + IWL_DEBUG_MAC80211(priv, "changes = 0x%X\n", changes); + + if (!iwl_is_alive(priv)) + return; + + mutex_lock(&priv->mutex); + + if (changes & BSS_CHANGED_BEACON && + priv->iw_mode == NL80211_IFTYPE_AP) { + dev_kfree_skb(priv->ibss_beacon); + priv->ibss_beacon = ieee80211_beacon_get(hw, vif); + } + + if (changes & BSS_CHANGED_BEACON_INT) { + priv->beacon_int = bss_conf->beacon_int; + /* TODO: in AP mode, do something to make this take effect */ + } + + if (changes & BSS_CHANGED_BSSID) { + IWL_DEBUG_MAC80211(priv, "BSSID %pM\n", bss_conf->bssid); + + /* + * If there is currently a HW scan going on in the + * background then we need to cancel it else the RXON + * below/in post_associate will fail. + */ + if (iwl_scan_cancel_timeout(priv, 100)) { + IWL_WARN(priv, "Aborted scan still in progress after 100ms\n"); + IWL_DEBUG_MAC80211(priv, "leaving - scan abort failed.\n"); + mutex_unlock(&priv->mutex); + return; + } + + /* mac80211 only sets assoc when in STATION mode */ + if (priv->iw_mode == NL80211_IFTYPE_ADHOC || + bss_conf->assoc) { + memcpy(priv->staging_rxon.bssid_addr, + bss_conf->bssid, ETH_ALEN); + + /* currently needed in a few places */ + memcpy(priv->bssid, bss_conf->bssid, ETH_ALEN); + } else { + priv->staging_rxon.filter_flags &= + ~RXON_FILTER_ASSOC_MSK; + } + + } + + /* + * This needs to be after setting the BSSID in case + * mac80211 decides to do both changes at once because + * it will invoke post_associate. + */ + if (priv->iw_mode == NL80211_IFTYPE_ADHOC && + changes & BSS_CHANGED_BEACON) { + struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); + + if (beacon) + iwl_mac_beacon_update(hw, beacon); + } + + if (changes & BSS_CHANGED_ERP_PREAMBLE) { + IWL_DEBUG_MAC80211(priv, "ERP_PREAMBLE %d\n", + bss_conf->use_short_preamble); + if (bss_conf->use_short_preamble) + priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; + else + priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK; + } + + if (changes & BSS_CHANGED_ERP_CTS_PROT) { + IWL_DEBUG_MAC80211(priv, "ERP_CTS %d\n", bss_conf->use_cts_prot); + if (bss_conf->use_cts_prot && (priv->band != IEEE80211_BAND_5GHZ)) + priv->staging_rxon.flags |= RXON_FLG_TGG_PROTECT_MSK; + else + priv->staging_rxon.flags &= ~RXON_FLG_TGG_PROTECT_MSK; + } + + if (changes & BSS_CHANGED_BASIC_RATES) { + /* XXX use this information + * + * To do that, remove code from iwl_set_rate() and put something + * like this here: + * + if (A-band) + priv->staging_rxon.ofdm_basic_rates = + bss_conf->basic_rates; + else + priv->staging_rxon.ofdm_basic_rates = + bss_conf->basic_rates >> 4; + priv->staging_rxon.cck_basic_rates = + bss_conf->basic_rates & 0xF; + */ + } + + if (changes & BSS_CHANGED_HT) { + iwl_ht_conf(priv, bss_conf); + + if (priv->cfg->ops->hcmd->set_rxon_chain) + priv->cfg->ops->hcmd->set_rxon_chain(priv); + } + + if (changes & BSS_CHANGED_ASSOC) { + IWL_DEBUG_MAC80211(priv, "ASSOC %d\n", bss_conf->assoc); + if (bss_conf->assoc) { + priv->assoc_id = bss_conf->aid; + priv->beacon_int = bss_conf->beacon_int; + priv->power_data.dtim_period = bss_conf->dtim_period; + priv->timestamp = bss_conf->timestamp; + priv->assoc_capability = bss_conf->assoc_capability; + + /* + * We have just associated, don't start scan too early + * leave time for EAPOL exchange to complete. + * + * XXX: do this in mac80211 + */ + priv->next_scan_jiffies = jiffies + + IWL_DELAY_NEXT_SCAN_AFTER_ASSOC; + if (!iwl_is_rfkill(priv)) + priv->cfg->ops->lib->post_associate(priv); + } else + priv->assoc_id = 0; + + } + + if (changes && iwl_is_associated(priv) && priv->assoc_id) { + IWL_DEBUG_MAC80211(priv, "Changes (%#x) while associated\n", + changes); + ret = iwl_send_rxon_assoc(priv); + if (!ret) { + /* Sync active_rxon with latest change. */ + memcpy((void *)&priv->active_rxon, + &priv->staging_rxon, + sizeof(struct iwl_rxon_cmd)); + } + } + + mutex_unlock(&priv->mutex); + + IWL_DEBUG_MAC80211(priv, "leave\n"); +} +EXPORT_SYMBOL(iwl_bss_info_changed); + +int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + struct iwl_priv *priv = hw->priv; + unsigned long flags; + __le64 timestamp; + + IWL_DEBUG_MAC80211(priv, "enter\n"); + + if (!iwl_is_ready_rf(priv)) { + IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n"); + return -EIO; + } + + if (priv->iw_mode != NL80211_IFTYPE_ADHOC) { + IWL_DEBUG_MAC80211(priv, "leave - not IBSS\n"); + return -EIO; + } + + spin_lock_irqsave(&priv->lock, flags); + + if (priv->ibss_beacon) + dev_kfree_skb(priv->ibss_beacon); + + priv->ibss_beacon = skb; + + priv->assoc_id = 0; + timestamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp; + priv->timestamp = le64_to_cpu(timestamp); + + IWL_DEBUG_MAC80211(priv, "leave\n"); + spin_unlock_irqrestore(&priv->lock, flags); + + iwl_reset_qos(priv); + + priv->cfg->ops->lib->post_associate(priv); + + + return 0; +} +EXPORT_SYMBOL(iwl_mac_beacon_update); + +int iwl_set_mode(struct iwl_priv *priv, int mode) +{ + if (mode == NL80211_IFTYPE_ADHOC) { + const struct iwl_channel_info *ch_info; + + ch_info = iwl_get_channel_info(priv, + priv->band, + le16_to_cpu(priv->staging_rxon.channel)); + + if (!ch_info || !is_channel_ibss(ch_info)) { + IWL_ERR(priv, "channel %d not IBSS channel\n", + le16_to_cpu(priv->staging_rxon.channel)); + return -EINVAL; + } + } + + iwl_connection_init_rx_config(priv, mode); + + if (priv->cfg->ops->hcmd->set_rxon_chain) + priv->cfg->ops->hcmd->set_rxon_chain(priv); + + memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); + + iwl_clear_stations_table(priv); + + /* dont commit rxon if rf-kill is on*/ + if (!iwl_is_ready_rf(priv)) + return -EAGAIN; + + iwlcore_commit_rxon(priv); + + return 0; +} +EXPORT_SYMBOL(iwl_set_mode); + +int iwl_mac_add_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + struct iwl_priv *priv = hw->priv; + unsigned long flags; + + IWL_DEBUG_MAC80211(priv, "enter: type %d\n", conf->type); + + if (priv->vif) { + IWL_DEBUG_MAC80211(priv, "leave - vif != NULL\n"); + return -EOPNOTSUPP; + } + + spin_lock_irqsave(&priv->lock, flags); + priv->vif = conf->vif; + priv->iw_mode = conf->type; + + spin_unlock_irqrestore(&priv->lock, flags); + + mutex_lock(&priv->mutex); + + if (conf->mac_addr) { + IWL_DEBUG_MAC80211(priv, "Set %pM\n", conf->mac_addr); + memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN); + } + + if (iwl_set_mode(priv, conf->type) == -EAGAIN) + /* we are not ready, will run again when ready */ + set_bit(STATUS_MODE_PENDING, &priv->status); + + mutex_unlock(&priv->mutex); + + IWL_DEBUG_MAC80211(priv, "leave\n"); + return 0; +} +EXPORT_SYMBOL(iwl_mac_add_interface); + +void iwl_mac_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + struct iwl_priv *priv = hw->priv; + + IWL_DEBUG_MAC80211(priv, "enter\n"); + + mutex_lock(&priv->mutex); + + if (iwl_is_ready_rf(priv)) { + iwl_scan_cancel_timeout(priv, 100); + priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; + iwlcore_commit_rxon(priv); + } + if (priv->vif == conf->vif) { + priv->vif = NULL; + memset(priv->bssid, 0, ETH_ALEN); + } + mutex_unlock(&priv->mutex); + + IWL_DEBUG_MAC80211(priv, "leave\n"); + +} +EXPORT_SYMBOL(iwl_mac_remove_interface); + +/** + * iwl_mac_config - mac80211 config callback + * + * We ignore conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME since it seems to + * be set inappropriately and the driver currently sets the hardware up to + * use it whenever needed. + */ +int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) +{ + struct iwl_priv *priv = hw->priv; + const struct iwl_channel_info *ch_info; + struct ieee80211_conf *conf = &hw->conf; + unsigned long flags = 0; + int ret = 0; + u16 ch; + int scan_active = 0; + + mutex_lock(&priv->mutex); + + IWL_DEBUG_MAC80211(priv, "enter to channel %d changed 0x%X\n", + conf->channel->hw_value, changed); + + if (unlikely(!priv->cfg->mod_params->disable_hw_scan && + test_bit(STATUS_SCANNING, &priv->status))) { + scan_active = 1; + IWL_DEBUG_MAC80211(priv, "leave - scanning\n"); + } + + + /* during scanning mac80211 will delay channel setting until + * scan finish with changed = 0 + */ + if (!changed || (changed & IEEE80211_CONF_CHANGE_CHANNEL)) { + if (scan_active) + goto set_ch_out; + + ch = ieee80211_frequency_to_channel(conf->channel->center_freq); + ch_info = iwl_get_channel_info(priv, conf->channel->band, ch); + if (!is_channel_valid(ch_info)) { + IWL_DEBUG_MAC80211(priv, "leave - invalid channel\n"); + ret = -EINVAL; + goto set_ch_out; + } + + if (priv->iw_mode == NL80211_IFTYPE_ADHOC && + !is_channel_ibss(ch_info)) { + IWL_ERR(priv, "channel %d in band %d not " + "IBSS channel\n", + conf->channel->hw_value, conf->channel->band); + ret = -EINVAL; + goto set_ch_out; + } + + priv->current_ht_config.is_ht = conf_is_ht(conf); + + spin_lock_irqsave(&priv->lock, flags); + + + /* if we are switching from ht to 2.4 clear flags + * from any ht related info since 2.4 does not + * support ht */ + if ((le16_to_cpu(priv->staging_rxon.channel) != ch)) + priv->staging_rxon.flags = 0; + + iwl_set_rxon_channel(priv, conf->channel); + + iwl_set_flags_for_band(priv, conf->channel->band); + spin_unlock_irqrestore(&priv->lock, flags); + set_ch_out: + /* The list of supported rates and rate mask can be different + * for each band; since the band may have changed, reset + * the rate mask to what mac80211 lists */ + iwl_set_rate(priv); + } + + if (changed & IEEE80211_CONF_CHANGE_PS && + priv->iw_mode == NL80211_IFTYPE_STATION) { + priv->power_data.power_disabled = + !(conf->flags & IEEE80211_CONF_PS); + ret = iwl_power_update_mode(priv, 0); + if (ret) + IWL_DEBUG_MAC80211(priv, "Error setting power level\n"); + } + + if (changed & IEEE80211_CONF_CHANGE_POWER) { + IWL_DEBUG_MAC80211(priv, "TX Power old=%d new=%d\n", + priv->tx_power_user_lmt, conf->power_level); + + iwl_set_tx_power(priv, conf->power_level, false); + } + + /* call to ensure that 4965 rx_chain is set properly in monitor mode */ + if (priv->cfg->ops->hcmd->set_rxon_chain) + priv->cfg->ops->hcmd->set_rxon_chain(priv); + + if (!iwl_is_ready(priv)) { + IWL_DEBUG_MAC80211(priv, "leave - not ready\n"); + goto out; + } + + if (scan_active) + goto out; + + if (memcmp(&priv->active_rxon, + &priv->staging_rxon, sizeof(priv->staging_rxon))) + iwlcore_commit_rxon(priv); + else + IWL_DEBUG_INFO(priv, "Not re-sending same RXON configuration.\n"); + + +out: + IWL_DEBUG_MAC80211(priv, "leave\n"); + mutex_unlock(&priv->mutex); + return ret; +} +EXPORT_SYMBOL(iwl_mac_config); + +int iwl_mac_get_tx_stats(struct ieee80211_hw *hw, + struct ieee80211_tx_queue_stats *stats) +{ + struct iwl_priv *priv = hw->priv; + int i, avail; + struct iwl_tx_queue *txq; + struct iwl_queue *q; + unsigned long flags; + + IWL_DEBUG_MAC80211(priv, "enter\n"); + + if (!iwl_is_ready_rf(priv)) { + IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n"); + return -EIO; + } + + spin_lock_irqsave(&priv->lock, flags); + + for (i = 0; i < AC_NUM; i++) { + txq = &priv->txq[i]; + q = &txq->q; + avail = iwl_queue_space(q); + + stats[i].len = q->n_window - avail; + stats[i].limit = q->n_window - q->high_mark; + stats[i].count = q->n_window; + + } + spin_unlock_irqrestore(&priv->lock, flags); + + IWL_DEBUG_MAC80211(priv, "leave\n"); + + return 0; +} +EXPORT_SYMBOL(iwl_mac_get_tx_stats); + +void iwl_mac_reset_tsf(struct ieee80211_hw *hw) +{ + struct iwl_priv *priv = hw->priv; + unsigned long flags; + + mutex_lock(&priv->mutex); + IWL_DEBUG_MAC80211(priv, "enter\n"); + + spin_lock_irqsave(&priv->lock, flags); + memset(&priv->current_ht_config, 0, sizeof(struct iwl_ht_info)); + spin_unlock_irqrestore(&priv->lock, flags); + + iwl_reset_qos(priv); + + spin_lock_irqsave(&priv->lock, flags); + priv->assoc_id = 0; + priv->assoc_capability = 0; + priv->assoc_station_added = 0; + + /* new association get rid of ibss beacon skb */ + if (priv->ibss_beacon) + dev_kfree_skb(priv->ibss_beacon); + + priv->ibss_beacon = NULL; + + priv->beacon_int = priv->vif->bss_conf.beacon_int; + priv->timestamp = 0; + if ((priv->iw_mode == NL80211_IFTYPE_STATION)) + priv->beacon_int = 0; + + spin_unlock_irqrestore(&priv->lock, flags); + + if (!iwl_is_ready_rf(priv)) { + IWL_DEBUG_MAC80211(priv, "leave - not ready\n"); + mutex_unlock(&priv->mutex); + return; + } + + /* we are restarting association process + * clear RXON_FILTER_ASSOC_MSK bit + */ + if (priv->iw_mode != NL80211_IFTYPE_AP) { + iwl_scan_cancel_timeout(priv, 100); + priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; + iwlcore_commit_rxon(priv); + } + + if (priv->iw_mode != NL80211_IFTYPE_ADHOC) { + IWL_DEBUG_MAC80211(priv, "leave - not in IBSS\n"); + mutex_unlock(&priv->mutex); + return; + } + + iwl_set_rate(priv); + + mutex_unlock(&priv->mutex); + + IWL_DEBUG_MAC80211(priv, "leave\n"); +} +EXPORT_SYMBOL(iwl_mac_reset_tsf); + +#ifdef CONFIG_PM + +int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct iwl_priv *priv = pci_get_drvdata(pdev); + + /* + * This function is called when system goes into suspend state + * mac80211 will call iwl_mac_stop() from the mac80211 suspend function + * first but since iwl_mac_stop() has no knowledge of who the caller is, + * it will not call apm_ops.stop() to stop the DMA operation. + * Calling apm_ops.stop here to make sure we stop the DMA. + */ + priv->cfg->ops->lib->apm_ops.stop(priv); + + pci_save_state(pdev); + pci_disable_device(pdev); + pci_set_power_state(pdev, PCI_D3hot); + + return 0; +} +EXPORT_SYMBOL(iwl_pci_suspend); + +int iwl_pci_resume(struct pci_dev *pdev) +{ + struct iwl_priv *priv = pci_get_drvdata(pdev); + int ret; + + pci_set_power_state(pdev, PCI_D0); + ret = pci_enable_device(pdev); + if (ret) + return ret; + pci_restore_state(pdev); + iwl_enable_interrupts(priv); + + return 0; +} +EXPORT_SYMBOL(iwl_pci_resume); + +#endif /* CONFIG_PM */ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index a8eac8c3c1fa..dabf663e36e5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -85,7 +85,10 @@ struct iwl_cmd; struct iwl_hcmd_ops { int (*rxon_assoc)(struct iwl_priv *priv); + int (*commit_rxon)(struct iwl_priv *priv); + void (*set_rxon_chain)(struct iwl_priv *priv); }; + struct iwl_hcmd_utils_ops { u16 (*get_hcmd_size)(u8 cmd_id, u16 len); u16 (*build_addsta_hcmd)(const struct iwl_addsta_cmd *cmd, u8 *data); @@ -100,6 +103,19 @@ struct iwl_hcmd_utils_ops { struct iwl_rx_phy_res *rx_resp); }; +struct iwl_apm_ops { + int (*init)(struct iwl_priv *priv); + int (*reset)(struct iwl_priv *priv); + void (*stop)(struct iwl_priv *priv); + void (*config)(struct iwl_priv *priv); + int (*set_pwr_src)(struct iwl_priv *priv, enum iwl_pwr_src src); +}; + +struct iwl_temp_ops { + void (*temperature)(struct iwl_priv *priv); + void (*set_ct_kill)(struct iwl_priv *priv); +}; + struct iwl_lib_ops { /* set hw dependent parameters */ int (*set_hw_params)(struct iwl_priv *priv); @@ -137,20 +153,21 @@ struct iwl_lib_ops { int (*is_valid_rtc_data_addr)(u32 addr); /* 1st ucode load */ int (*load_ucode)(struct iwl_priv *priv); - /* power management */ - struct { - int (*init)(struct iwl_priv *priv); - int (*reset)(struct iwl_priv *priv); - void (*stop)(struct iwl_priv *priv); - void (*config)(struct iwl_priv *priv); - int (*set_pwr_src)(struct iwl_priv *priv, enum iwl_pwr_src src); - } apm_ops; + /* power management */ + struct iwl_apm_ops apm_ops; + /* power */ int (*send_tx_power) (struct iwl_priv *priv); void (*update_chain_flags)(struct iwl_priv *priv); - void (*temperature) (struct iwl_priv *priv); + void (*post_associate) (struct iwl_priv *priv); + void (*config_ap) (struct iwl_priv *priv); + irqreturn_t (*isr) (int irq, void *data); + /* eeprom operations (as defined in iwl-eeprom.h) */ struct iwl_eeprom_ops eeprom_ops; + + /* temperature */ + struct iwl_temp_ops temp_ops; }; struct iwl_ops { @@ -160,13 +177,12 @@ struct iwl_ops { }; struct iwl_mod_params { - int disable; /* def: 0 = enable radio */ int sw_crypto; /* def: 0 = using hardware encryption */ u32 debug; /* def: 0 = minimal debug log messages */ int disable_hw_scan; /* def: 0 = use h/w scan */ int num_of_queues; /* def: HW dependent */ int num_of_ampdu_queues;/* def: HW dependent */ - int disable_11n; /* def: 0 = disable 11n capabilities */ + int disable_11n; /* def: 0 = 11n capabilities enabled */ int amsdu_size_8K; /* def: 1 = enable 8K amsdu size */ int antenna; /* def: 0 = both antennas (use diversity) */ int restart_fw; /* def: 1 = restart firmware */ @@ -214,6 +230,7 @@ struct iwl_cfg { u8 valid_tx_ant; u8 valid_rx_ant; bool need_pll_cfg; + bool use_isr_legacy; }; /*************************** @@ -225,6 +242,8 @@ struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg, void iwl_hw_detect(struct iwl_priv *priv); void iwl_reset_qos(struct iwl_priv *priv); void iwl_activate_qos(struct iwl_priv *priv, u8 force); +int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, + const struct ieee80211_tx_queue_params *params); void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt); int iwl_check_rxon_cmd(struct iwl_priv *priv); int iwl_full_rxon_required(struct iwl_priv *priv); @@ -249,6 +268,24 @@ int iwl_setup_mac(struct iwl_priv *priv); int iwl_set_hw_params(struct iwl_priv *priv); int iwl_init_drv(struct iwl_priv *priv); void iwl_uninit_drv(struct iwl_priv *priv); +bool iwl_is_monitor_mode(struct iwl_priv *priv); +void iwl_post_associate(struct iwl_priv *priv); +void iwl_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, + u32 changes); +int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb); +int iwl_commit_rxon(struct iwl_priv *priv); +int iwl_set_mode(struct iwl_priv *priv, int mode); +int iwl_mac_add_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf); +void iwl_mac_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf); +int iwl_mac_config(struct ieee80211_hw *hw, u32 changed); +void iwl_config_ap(struct iwl_priv *priv); +int iwl_mac_get_tx_stats(struct ieee80211_hw *hw, + struct ieee80211_tx_queue_stats *stats); +void iwl_mac_reset_tsf(struct ieee80211_hw *hw); /***************************************************** * RX handlers. @@ -271,10 +308,11 @@ int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q); void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq); void iwl_rx_replenish(struct iwl_priv *priv); +void iwl_rx_replenish_now(struct iwl_priv *priv); int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq); int iwl_rx_queue_restock(struct iwl_priv *priv); int iwl_rx_queue_space(const struct iwl_rx_queue *q); -void iwl_rx_allocate(struct iwl_priv *priv); +void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority); void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index); /* Handlers */ @@ -310,14 +348,6 @@ int iwl_txq_check_empty(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id); ****************************************************/ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force); -/***************************************************** - * RF -Kill - here and not in iwl-rfkill.h to be available when - * RF-kill subsystem is not compiled. - ****************************************************/ -void iwl_bg_rf_kill(struct work_struct *work); -void iwl_radio_kill_sw_disable_radio(struct iwl_priv *priv); -int iwl_radio_kill_sw_enable_radio(struct iwl_priv *priv); - /******************************************************************************* * Rate ******************************************************************************/ @@ -328,8 +358,6 @@ int iwl_hwrate_to_plcp_idx(u32 rate_n_flags); u8 iwl_rate_get_lowest_plcp(struct iwl_priv *priv); -void iwl_set_rate(struct iwl_priv *priv); - u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant_idx); static inline u32 iwl_ant_idx_to_flags(u8 ant_idx) @@ -358,8 +386,8 @@ int iwl_scan_cancel(struct iwl_priv *priv); int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms); int iwl_scan_initiate(struct iwl_priv *priv); int iwl_mac_hw_scan(struct ieee80211_hw *hw, struct cfg80211_scan_request *req); -u16 iwl_fill_probe_req(struct iwl_priv *priv, enum ieee80211_band band, - struct ieee80211_mgmt *frame, int left); +u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame, + const u8 *ie, int ie_len, int left); void iwl_setup_rx_scan_handlers(struct iwl_priv *priv); u16 iwl_get_active_dwell_time(struct iwl_priv *priv, enum ieee80211_band band, @@ -423,7 +451,13 @@ int iwl_send_card_state(struct iwl_priv *priv, u32 flags, *****************************************************/ void iwl_disable_interrupts(struct iwl_priv *priv); void iwl_enable_interrupts(struct iwl_priv *priv); -irqreturn_t iwl_isr(int irq, void *data); +irqreturn_t iwl_isr_legacy(int irq, void *data); +int iwl_reset_ict(struct iwl_priv *priv); +void iwl_disable_ict(struct iwl_priv *priv); +int iwl_alloc_isr_ict(struct iwl_priv *priv); +void iwl_free_isr_ict(struct iwl_priv *priv); +irqreturn_t iwl_isr_ict(int irq, void *data); + static inline u16 iwl_pcie_link_ctl(struct iwl_priv *priv) { int pos; @@ -432,12 +466,17 @@ static inline u16 iwl_pcie_link_ctl(struct iwl_priv *priv) pci_read_config_word(priv->pci_dev, pos + PCI_EXP_LNKCTL, &pci_lnk_ctl); return pci_lnk_ctl; } +#ifdef CONFIG_PM +int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state); +int iwl_pci_resume(struct pci_dev *pdev); +#endif /* CONFIG_PM */ /***************************************************** * Error Handling Debugging ******************************************************/ void iwl_dump_nic_error_log(struct iwl_priv *priv); void iwl_dump_nic_event_log(struct iwl_priv *priv); +void iwl_clear_isr_stats(struct iwl_priv *priv); /***************************************************** * GEOS @@ -451,14 +490,12 @@ void iwlcore_free_geos(struct iwl_priv *priv); #define STATUS_HCMD_SYNC_ACTIVE 1 /* sync host command in progress */ #define STATUS_INT_ENABLED 2 #define STATUS_RF_KILL_HW 3 -#define STATUS_RF_KILL_SW 4 #define STATUS_INIT 5 #define STATUS_ALIVE 6 #define STATUS_READY 7 #define STATUS_TEMPERATURE 8 #define STATUS_GEO_CONFIGURED 9 #define STATUS_EXIT_PENDING 10 -#define STATUS_IN_SUSPEND 11 #define STATUS_STATISTICS 12 #define STATUS_SCANNING 13 #define STATUS_SCAN_ABORTING 14 @@ -487,11 +524,6 @@ static inline int iwl_is_init(struct iwl_priv *priv) return test_bit(STATUS_INIT, &priv->status); } -static inline int iwl_is_rfkill_sw(struct iwl_priv *priv) -{ - return test_bit(STATUS_RF_KILL_SW, &priv->status); -} - static inline int iwl_is_rfkill_hw(struct iwl_priv *priv) { return test_bit(STATUS_RF_KILL_HW, &priv->status); @@ -499,7 +531,7 @@ static inline int iwl_is_rfkill_hw(struct iwl_priv *priv) static inline int iwl_is_rfkill(struct iwl_priv *priv) { - return iwl_is_rfkill_hw(priv) || iwl_is_rfkill_sw(priv); + return iwl_is_rfkill_hw(priv); } static inline int iwl_is_ready_rf(struct iwl_priv *priv) @@ -528,7 +560,14 @@ static inline int iwl_send_rxon_assoc(struct iwl_priv *priv) { return priv->cfg->ops->hcmd->rxon_assoc(priv); } - +static inline int iwlcore_commit_rxon(struct iwl_priv *priv) +{ + return priv->cfg->ops->hcmd->commit_rxon(priv); +} +static inline void iwlcore_config_ap(struct iwl_priv *priv) +{ + priv->cfg->ops->lib->config_ap(priv); +} static inline const struct ieee80211_supported_band *iwl_get_hw_mode( struct iwl_priv *priv, enum ieee80211_band band) { diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index 6e983149b83b..f03dae1b2f36 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -89,6 +89,7 @@ /* EEPROM reads */ #define CSR_EEPROM_REG (CSR_BASE+0x02c) #define CSR_EEPROM_GP (CSR_BASE+0x030) +#define CSR_OTP_GP_REG (CSR_BASE+0x034) #define CSR_GIO_REG (CSR_BASE+0x03C) #define CSR_GP_UCODE (CSR_BASE+0x044) #define CSR_UCODE_DRV_GP1 (CSR_BASE+0x054) @@ -96,8 +97,10 @@ #define CSR_UCODE_DRV_GP1_CLR (CSR_BASE+0x05c) #define CSR_UCODE_DRV_GP2 (CSR_BASE+0x060) #define CSR_LED_REG (CSR_BASE+0x094) +#define CSR_DRAM_INT_TBL_REG (CSR_BASE+0x0A0) #define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100) +#define CSR_INT_PERIODIC_REG (CSR_BASE+0x005) /* Analog phase-lock-loop configuration */ #define CSR_ANA_PLL_CFG (CSR_BASE+0x20c) /* @@ -123,16 +126,18 @@ #define CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A (0x00080000) #define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM (0x00200000) -#define CSR_HW_IF_CONFIG_REG_BIT_PCI_OWN_SEM (0x00400000) -#define CSR_HW_IF_CONFIG_REG_BIT_ME_OWN (0x02000000) -#define CSR_HW_IF_CONFIG_REG_BIT_WAKE_ME (0x08000000) +#define CSR_HW_IF_CONFIG_REG_BIT_NIC_READY (0x00400000) +#define CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE (0x02000000) +#define CSR_HW_IF_CONFIG_REG_PREPARE (0x08000000) +#define CSR_INT_PERIODIC_DIS (0x00) +#define CSR_INT_PERIODIC_ENA (0xFF) /* interrupt flags in INTA, set by uCode or hardware (e.g. dma), * acknowledged (reset) by host writing "1" to flagged bits. */ #define CSR_INT_BIT_FH_RX (1 << 31) /* Rx DMA, cmd responses, FH_INT[17:16] */ #define CSR_INT_BIT_HW_ERR (1 << 29) /* DMA hardware error FH_INT[31] */ -#define CSR_INT_BIT_DNLD (1 << 28) /* uCode Download */ +#define CSR_INT_BIT_RX_PERIODIC (1 << 28) /* Rx periodic */ #define CSR_INT_BIT_FH_TX (1 << 27) /* Tx DMA FH_INT[1:0] */ #define CSR_INT_BIT_SCD (1 << 26) /* TXQ pointer advanced */ #define CSR_INT_BIT_SW_ERR (1 << 25) /* uCode error */ @@ -226,6 +231,10 @@ #define CSR_EEPROM_GP_VALID_MSK (0x00000007) #define CSR_EEPROM_GP_BAD_SIGNATURE (0x00000000) #define CSR_EEPROM_GP_IF_OWNER_MSK (0x00000180) +#define CSR_OTP_GP_REG_DEVICE_SELECT (0x00010000) /* 0 - EEPROM, 1 - OTP */ +#define CSR_OTP_GP_REG_OTP_ACCESS_MODE (0x00020000) /* 0 - absolute, 1 - relative */ +#define CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK (0x00100000) /* bit 20 */ +#define CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK (0x00200000) /* bit 21 */ /* CSR GIO */ #define CSR_GIO_REG_VAL_L0S_ENABLED (0x00000002) @@ -251,6 +260,11 @@ /* HPET MEM debug */ #define CSR_DBG_HPET_MEM_REG_VAL (0xFFFF0000) + +/* DRAM INT TABLE */ +#define CSR_DRAM_INT_TBL_ENABLE (1 << 31) +#define CSR_DRAM_INIT_TBL_WRAP_CHECK (1 << 27) + /*=== HBUS (Host-side Bus) ===*/ #define HBUS_BASE (0x400) /* diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 65d1a7f2db9e..2cf014f523be 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -68,13 +68,14 @@ struct iwl_debugfs { struct dentry *dir_rf; struct dir_data_files { struct dentry *file_sram; - struct dentry *file_eeprom; + struct dentry *file_nvm; struct dentry *file_stations; struct dentry *file_rx_statistics; struct dentry *file_tx_statistics; struct dentry *file_log_event; struct dentry *file_channels; struct dentry *file_status; + struct dentry *file_interrupt; } dbgfs_data_files; struct dir_rf_files { struct dentry *file_disable_sensitivity; diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 64eb585f1578..11e08c068917 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -172,7 +172,6 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, struct iwl_priv *priv = (struct iwl_priv *)file->private_data; const size_t bufsz = sizeof(buf); - iwl_grab_nic_access(priv); for (i = priv->dbgfs->sram_len; i > 0; i -= 4) { val = iwl_read_targ_mem(priv, priv->dbgfs->sram_offset + \ priv->dbgfs->sram_len - i); @@ -192,7 +191,6 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, pos += scnprintf(buf + pos, bufsz - pos, "0x%08x ", val); } pos += scnprintf(buf + pos, bufsz - pos, "\n"); - iwl_release_nic_access(priv); ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); return ret; @@ -292,7 +290,7 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf, return ret; } -static ssize_t iwl_dbgfs_eeprom_read(struct file *file, +static ssize_t iwl_dbgfs_nvm_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -306,7 +304,7 @@ static ssize_t iwl_dbgfs_eeprom_read(struct file *file, buf_size = 4 * eeprom_len + 256; if (eeprom_len % 16) { - IWL_ERR(priv, "EEPROM size is not multiple of 16.\n"); + IWL_ERR(priv, "NVM size is not multiple of 16.\n"); return -ENODATA; } @@ -318,6 +316,13 @@ static ssize_t iwl_dbgfs_eeprom_read(struct file *file, } ptr = priv->eeprom; + if (!ptr) { + IWL_ERR(priv, "Invalid EEPROM/OTP memory\n"); + return -ENOMEM; + } + pos += scnprintf(buf + pos, buf_size - pos, "NVM Type: %s\n", + (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) + ? "OTP" : "EEPROM"); for (ofs = 0 ; ofs < eeprom_len ; ofs += 16) { pos += scnprintf(buf + pos, buf_size - pos, "0x%.4x ", ofs); hex_dump_to_buffer(ptr + ofs, 16 , 16, 2, buf + pos, @@ -375,51 +380,53 @@ static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf, } supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_2GHZ); - channels = supp_band->channels; + if (supp_band) { + channels = supp_band->channels; - pos += scnprintf(buf + pos, bufsz - pos, - "Displaying %d channels in 2.4GHz band 802.11bg):\n", - supp_band->n_channels); - - for (i = 0; i < supp_band->n_channels; i++) pos += scnprintf(buf + pos, bufsz - pos, - "%d: %ddBm: BSS%s%s, %s.\n", - ieee80211_frequency_to_channel( - channels[i].center_freq), - channels[i].max_power, - channels[i].flags & IEEE80211_CHAN_RADAR ? - " (IEEE 802.11h required)" : "", - (!(channels[i].flags & IEEE80211_CHAN_NO_IBSS) - || (channels[i].flags & - IEEE80211_CHAN_RADAR)) ? "" : - ", IBSS", - channels[i].flags & - IEEE80211_CHAN_PASSIVE_SCAN ? - "passive only" : "active/passive"); + "Displaying %d channels in 2.4GHz band 802.11bg):\n", + supp_band->n_channels); + for (i = 0; i < supp_band->n_channels; i++) + pos += scnprintf(buf + pos, bufsz - pos, + "%d: %ddBm: BSS%s%s, %s.\n", + ieee80211_frequency_to_channel( + channels[i].center_freq), + channels[i].max_power, + channels[i].flags & IEEE80211_CHAN_RADAR ? + " (IEEE 802.11h required)" : "", + ((channels[i].flags & IEEE80211_CHAN_NO_IBSS) + || (channels[i].flags & + IEEE80211_CHAN_RADAR)) ? "" : + ", IBSS", + channels[i].flags & + IEEE80211_CHAN_PASSIVE_SCAN ? + "passive only" : "active/passive"); + } supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_5GHZ); - channels = supp_band->channels; + if (supp_band) { + channels = supp_band->channels; - pos += scnprintf(buf + pos, bufsz - pos, - "Displaying %d channels in 5.2GHz band (802.11a)\n", - supp_band->n_channels); - - for (i = 0; i < supp_band->n_channels; i++) pos += scnprintf(buf + pos, bufsz - pos, - "%d: %ddBm: BSS%s%s, %s.\n", - ieee80211_frequency_to_channel( - channels[i].center_freq), - channels[i].max_power, - channels[i].flags & IEEE80211_CHAN_RADAR ? - " (IEEE 802.11h required)" : "", - ((channels[i].flags & IEEE80211_CHAN_NO_IBSS) - || (channels[i].flags & - IEEE80211_CHAN_RADAR)) ? "" : - ", IBSS", - channels[i].flags & - IEEE80211_CHAN_PASSIVE_SCAN ? - "passive only" : "active/passive"); + "Displaying %d channels in 5.2GHz band (802.11a)\n", + supp_band->n_channels); + for (i = 0; i < supp_band->n_channels; i++) + pos += scnprintf(buf + pos, bufsz - pos, + "%d: %ddBm: BSS%s%s, %s.\n", + ieee80211_frequency_to_channel( + channels[i].center_freq), + channels[i].max_power, + channels[i].flags & IEEE80211_CHAN_RADAR ? + " (IEEE 802.11h required)" : "", + ((channels[i].flags & IEEE80211_CHAN_NO_IBSS) + || (channels[i].flags & + IEEE80211_CHAN_RADAR)) ? "" : + ", IBSS", + channels[i].flags & + IEEE80211_CHAN_PASSIVE_SCAN ? + "passive only" : "active/passive"); + } ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); kfree(buf); return ret; @@ -442,8 +449,6 @@ static ssize_t iwl_dbgfs_status_read(struct file *file, test_bit(STATUS_INT_ENABLED, &priv->status)); pos += scnprintf(buf + pos, bufsz - pos, "STATUS_RF_KILL_HW:\t %d\n", test_bit(STATUS_RF_KILL_HW, &priv->status)); - pos += scnprintf(buf + pos, bufsz - pos, "STATUS_RF_KILL_SW:\t %d\n", - test_bit(STATUS_RF_KILL_SW, &priv->status)); pos += scnprintf(buf + pos, bufsz - pos, "STATUS_INIT:\t\t %d\n", test_bit(STATUS_INIT, &priv->status)); pos += scnprintf(buf + pos, bufsz - pos, "STATUS_ALIVE:\t\t %d\n", @@ -456,8 +461,6 @@ static ssize_t iwl_dbgfs_status_read(struct file *file, test_bit(STATUS_GEO_CONFIGURED, &priv->status)); pos += scnprintf(buf + pos, bufsz - pos, "STATUS_EXIT_PENDING:\t %d\n", test_bit(STATUS_EXIT_PENDING, &priv->status)); - pos += scnprintf(buf + pos, bufsz - pos, "STATUS_IN_SUSPEND:\t %d\n", - test_bit(STATUS_IN_SUSPEND, &priv->status)); pos += scnprintf(buf + pos, bufsz - pos, "STATUS_STATISTICS:\t %d\n", test_bit(STATUS_STATISTICS, &priv->status)); pos += scnprintf(buf + pos, bufsz - pos, "STATUS_SCANNING:\t %d\n", @@ -475,14 +478,104 @@ static ssize_t iwl_dbgfs_status_read(struct file *file, return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } +static ssize_t iwl_dbgfs_interrupt_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) { + + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + int pos = 0; + int cnt = 0; + char *buf; + int bufsz = 24 * 64; /* 24 items * 64 char per item */ + ssize_t ret; + + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) { + IWL_ERR(priv, "Can not allocate Buffer\n"); + return -ENOMEM; + } + + pos += scnprintf(buf + pos, bufsz - pos, + "Interrupt Statistics Report:\n"); + + pos += scnprintf(buf + pos, bufsz - pos, "HW Error:\t\t\t %u\n", + priv->isr_stats.hw); + pos += scnprintf(buf + pos, bufsz - pos, "SW Error:\t\t\t %u\n", + priv->isr_stats.sw); + if (priv->isr_stats.sw > 0) { + pos += scnprintf(buf + pos, bufsz - pos, + "\tLast Restarting Code: 0x%X\n", + priv->isr_stats.sw_err); + } +#ifdef CONFIG_IWLWIFI_DEBUG + pos += scnprintf(buf + pos, bufsz - pos, "Frame transmitted:\t\t %u\n", + priv->isr_stats.sch); + pos += scnprintf(buf + pos, bufsz - pos, "Alive interrupt:\t\t %u\n", + priv->isr_stats.alive); +#endif + pos += scnprintf(buf + pos, bufsz - pos, + "HW RF KILL switch toggled:\t %u\n", + priv->isr_stats.rfkill); + + pos += scnprintf(buf + pos, bufsz - pos, "CT KILL:\t\t\t %u\n", + priv->isr_stats.ctkill); + + pos += scnprintf(buf + pos, bufsz - pos, "Wakeup Interrupt:\t\t %u\n", + priv->isr_stats.wakeup); + + pos += scnprintf(buf + pos, bufsz - pos, + "Rx command responses:\t\t %u\n", + priv->isr_stats.rx); + for (cnt = 0; cnt < REPLY_MAX; cnt++) { + if (priv->isr_stats.rx_handlers[cnt] > 0) + pos += scnprintf(buf + pos, bufsz - pos, + "\tRx handler[%36s]:\t\t %u\n", + get_cmd_string(cnt), + priv->isr_stats.rx_handlers[cnt]); + } + + pos += scnprintf(buf + pos, bufsz - pos, "Tx/FH interrupt:\t\t %u\n", + priv->isr_stats.tx); + + pos += scnprintf(buf + pos, bufsz - pos, "Unexpected INTA:\t\t %u\n", + priv->isr_stats.unhandled); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; +} + +static ssize_t iwl_dbgfs_interrupt_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = file->private_data; + char buf[8]; + int buf_size; + u32 reset_flag; + + memset(buf, 0, sizeof(buf)); + buf_size = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + if (sscanf(buf, "%x", &reset_flag) != 1) + return -EFAULT; + if (reset_flag == 0) + iwl_clear_isr_stats(priv); + + return count; +} + + DEBUGFS_READ_WRITE_FILE_OPS(sram); DEBUGFS_WRITE_FILE_OPS(log_event); -DEBUGFS_READ_FILE_OPS(eeprom); +DEBUGFS_READ_FILE_OPS(nvm); DEBUGFS_READ_FILE_OPS(stations); DEBUGFS_READ_FILE_OPS(rx_statistics); DEBUGFS_READ_FILE_OPS(tx_statistics); DEBUGFS_READ_FILE_OPS(channels); DEBUGFS_READ_FILE_OPS(status); +DEBUGFS_READ_WRITE_FILE_OPS(interrupt); /* * Create the debugfs files and directories @@ -510,7 +603,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_DIR(data, dbgfs->dir_drv); DEBUGFS_ADD_DIR(rf, dbgfs->dir_drv); - DEBUGFS_ADD_FILE(eeprom, data); + DEBUGFS_ADD_FILE(nvm, data); DEBUGFS_ADD_FILE(sram, data); DEBUGFS_ADD_FILE(log_event, data); DEBUGFS_ADD_FILE(stations, data); @@ -518,6 +611,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(tx_statistics, data); DEBUGFS_ADD_FILE(channels, data); DEBUGFS_ADD_FILE(status, data); + DEBUGFS_ADD_FILE(interrupt, data); DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal); DEBUGFS_ADD_BOOL(disable_chain_noise, rf, &priv->disable_chain_noise_cal); @@ -540,7 +634,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) if (!priv->dbgfs) return; - DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_eeprom); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_nvm); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_rx_statistics); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_tx_statistics); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_sram); @@ -548,6 +642,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_stations); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_channels); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_status); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_interrupt); DEBUGFS_REMOVE(priv->dbgfs->dir_data); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index cf7f0db58fcf..e2d620f0b6e8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -41,7 +41,6 @@ #include "iwl-prph.h" #include "iwl-fh.h" #include "iwl-debug.h" -#include "iwl-rfkill.h" #include "iwl-4965-hw.h" #include "iwl-3945-hw.h" #include "iwl-3945-led.h" @@ -289,11 +288,11 @@ struct iwl_frame { #define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4) enum { - /* CMD_SIZE_NORMAL = 0, */ + CMD_SYNC = 0, + CMD_SIZE_NORMAL = 0, + CMD_NO_SKB = 0, CMD_SIZE_HUGE = (1 << 0), - /* CMD_SYNC = 0, */ CMD_ASYNC = (1 << 1), - /* CMD_NO_SKB = 0, */ CMD_WANT_SKB = (1 << 2), }; @@ -381,6 +380,7 @@ struct iwl_rx_queue { u32 read; u32 write; u32 free_count; + u32 write_actual; struct list_head rx_free; struct list_head rx_used; int need_update; @@ -498,22 +498,13 @@ struct iwl_qos_info { #define STA_PS_STATUS_WAKE 0 #define STA_PS_STATUS_SLEEP 1 -struct iwl3945_tid_data { - u16 seq_number; -}; - -struct iwl3945_hw_key { - enum ieee80211_key_alg alg; - int keylen; - u8 key[32]; -}; struct iwl3945_station_entry { struct iwl3945_addsta_cmd sta; - struct iwl3945_tid_data tid[MAX_TID_COUNT]; + struct iwl_tid_data tid[MAX_TID_COUNT]; u8 used; u8 ps_status; - struct iwl3945_hw_key keyinfo; + struct iwl_hw_key keyinfo; }; struct iwl_station_entry { @@ -822,6 +813,26 @@ enum { MEASUREMENT_ACTIVE = (1 << 1), }; +enum iwl_nvm_type { + NVM_DEVICE_TYPE_EEPROM = 0, + NVM_DEVICE_TYPE_OTP, +}; + +/* interrupt statistics */ +struct isr_statistics { + u32 hw; + u32 sw; + u32 sw_err; + u32 sch; + u32 alive; + u32 rfkill; + u32 ctkill; + u32 wakeup; + u32 rx; + u32 rx_handlers[REPLY_MAX]; + u32 tx; + u32 unhandled; +}; #define IWL_MAX_NUM_QUEUES 20 /* FIXME: do dynamic allocation */ @@ -877,15 +888,14 @@ struct iwl_priv { unsigned long scan_start_tsf; void *scan; int scan_bands; - int one_direct_scan; - u8 direct_ssid_len; - u8 direct_ssid[IW_ESSID_MAX_SIZE]; + struct cfg80211_scan_request *scan_request; u8 scan_tx_ant[IEEE80211_NUM_BANDS]; u8 mgmt_tx_ant; /* spinlock */ spinlock_t lock; /* protect general shared data */ spinlock_t hcmd_lock; /* protect hcmd */ + spinlock_t reg_lock; /* protect hw register access */ struct mutex mutex; /* basic pci-network driver stuff */ @@ -919,16 +929,12 @@ struct iwl_priv { const struct iwl_rxon_cmd active_rxon; struct iwl_rxon_cmd staging_rxon; - int error_recovering; struct iwl_rxon_cmd recovery_rxon; /* 1st responses from initialize and runtime uCode images. * 4965's initialize alive response contains some calibration data. */ struct iwl_init_alive_resp card_alive_init; struct iwl_alive_resp card_alive; -#if defined(CONFIG_IWLWIFI_RFKILL) - struct rfkill *rfkill; -#endif #ifdef CONFIG_IWLWIFI_LEDS unsigned long last_blink_time; @@ -978,6 +984,9 @@ struct iwl_priv { u64 bytes; } tx_stats[3], rx_stats[3]; + /* counts interrupts */ + struct isr_statistics isr_stats; + struct iwl_power_mgr power_data; struct iwl_notif_statistics statistics; @@ -1017,6 +1026,7 @@ struct iwl_priv { /* eeprom */ u8 *eeprom; + int nvm_device_type; struct iwl_eeprom_calib_info *calib_info; enum nl80211_iftype iw_mode; @@ -1034,7 +1044,16 @@ struct iwl_priv { /*End*/ struct iwl_hw_params hw_params; + /* INT ICT Table */ + u32 *ict_tbl; + dma_addr_t ict_tbl_dma; + dma_addr_t aligned_ict_tbl_dma; + int ict_index; + void *ict_tbl_vir; + u32 inta; + bool use_ict; + u32 inta_mask; /* Current association information needed to configure the * hardware */ u16 assoc_id; @@ -1049,7 +1068,6 @@ struct iwl_priv { struct work_struct calibrated_work; struct work_struct scan_completed; struct work_struct rx_replenish; - struct work_struct rf_kill; struct work_struct abort_scan; struct work_struct update_link_led; struct work_struct auth_work; @@ -1059,7 +1077,6 @@ struct iwl_priv { struct tasklet_struct irq_tasklet; - struct delayed_work set_power_save; struct delayed_work init_alive_start; struct delayed_work alive_start; struct delayed_work scan_check; @@ -1090,14 +1107,12 @@ struct iwl_priv { u32 disable_tx_power_cal; struct work_struct run_time_calib_work; struct timer_list statistics_periodic; - + bool hw_ready; /*For 3945*/ #define IWL_DEFAULT_TX_POWER 0x0F struct iwl3945_notif_statistics statistics_39; - struct iwl3945_station_entry stations_39[IWL_STATION_COUNT]; - u32 sta_supp_rates; }; /*iwl_priv */ diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 75517d05df08..7d7554a2f341 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -152,6 +152,32 @@ int iwlcore_eeprom_verify_signature(struct iwl_priv *priv) } EXPORT_SYMBOL(iwlcore_eeprom_verify_signature); +static int iwlcore_get_nvm_type(struct iwl_priv *priv) +{ + u32 otpgp; + int nvm_type; + + /* OTP only valid for CP/PP and after */ + switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { + case CSR_HW_REV_TYPE_3945: + case CSR_HW_REV_TYPE_4965: + case CSR_HW_REV_TYPE_5300: + case CSR_HW_REV_TYPE_5350: + case CSR_HW_REV_TYPE_5100: + case CSR_HW_REV_TYPE_5150: + nvm_type = NVM_DEVICE_TYPE_EEPROM; + break; + default: + otpgp = iwl_read32(priv, CSR_OTP_GP_REG); + if (otpgp & CSR_OTP_GP_REG_DEVICE_SELECT) + nvm_type = NVM_DEVICE_TYPE_OTP; + else + nvm_type = NVM_DEVICE_TYPE_EEPROM; + break; + } + return nvm_type; +} + /* * The device's EEPROM semaphore prevents conflicts between driver and uCode * when accessing the EEPROM; each access is a series of pulses to/from the @@ -198,6 +224,31 @@ const u8 *iwlcore_eeprom_query_addr(const struct iwl_priv *priv, size_t offset) } EXPORT_SYMBOL(iwlcore_eeprom_query_addr); +static int iwl_init_otp_access(struct iwl_priv *priv) +{ + int ret; + + /* Enable 40MHz radio clock */ + _iwl_write32(priv, CSR_GP_CNTRL, + _iwl_read32(priv, CSR_GP_CNTRL) | + CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + + /* wait for clock to be ready */ + ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, + 25000); + if (ret < 0) + IWL_ERR(priv, "Time out access OTP\n"); + else { + iwl_set_bits_prph(priv, APMG_PS_CTRL_REG, + APMG_PS_CTRL_VAL_RESET_REQ); + udelay(5); + iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG, + APMG_PS_CTRL_VAL_RESET_REQ); + } + return ret; +} + /** * iwl_eeprom_init - read EEPROM contents * @@ -209,11 +260,18 @@ int iwl_eeprom_init(struct iwl_priv *priv) { u16 *e; u32 gp = iwl_read32(priv, CSR_EEPROM_GP); - int sz = priv->cfg->eeprom_size; + int sz; int ret; u16 addr; + u32 otpgp; + + priv->nvm_device_type = iwlcore_get_nvm_type(priv); /* allocate eeprom */ + if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) + priv->cfg->eeprom_size = + OTP_BLOCK_SIZE * OTP_LOWER_BLOCKS_TOTAL; + sz = priv->cfg->eeprom_size; priv->eeprom = kzalloc(sz, GFP_KERNEL); if (!priv->eeprom) { ret = -ENOMEM; @@ -235,30 +293,77 @@ int iwl_eeprom_init(struct iwl_priv *priv) ret = -ENOENT; goto err; } - - /* eeprom is an array of 16bit values */ - for (addr = 0; addr < sz; addr += sizeof(u16)) { - u32 r; - - _iwl_write32(priv, CSR_EEPROM_REG, - CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); - - ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG, - CSR_EEPROM_REG_READ_VALID_MSK, - IWL_EEPROM_ACCESS_TIMEOUT); - if (ret < 0) { - IWL_ERR(priv, "Time out reading EEPROM[%d]\n", addr); - goto done; + if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) { + ret = iwl_init_otp_access(priv); + if (ret) { + IWL_ERR(priv, "Failed to initialize OTP access.\n"); + ret = -ENOENT; + goto err; + } + _iwl_write32(priv, CSR_EEPROM_GP, + iwl_read32(priv, CSR_EEPROM_GP) & + ~CSR_EEPROM_GP_IF_OWNER_MSK); + /* clear */ + _iwl_write32(priv, CSR_OTP_GP_REG, + iwl_read32(priv, CSR_OTP_GP_REG) | + CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK | + CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK); + + for (addr = 0; addr < sz; addr += sizeof(u16)) { + u32 r; + + _iwl_write32(priv, CSR_EEPROM_REG, + CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); + + ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG, + CSR_EEPROM_REG_READ_VALID_MSK, + IWL_EEPROM_ACCESS_TIMEOUT); + if (ret < 0) { + IWL_ERR(priv, "Time out reading OTP[%d]\n", addr); + goto done; + } + r = _iwl_read_direct32(priv, CSR_EEPROM_REG); + /* check for ECC errors: */ + otpgp = iwl_read32(priv, CSR_OTP_GP_REG); + if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) { + /* stop in this case */ + IWL_ERR(priv, "Uncorrectable OTP ECC error, Abort OTP read\n"); + goto done; + } + if (otpgp & CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK) { + /* continue in this case */ + _iwl_write32(priv, CSR_OTP_GP_REG, + iwl_read32(priv, CSR_OTP_GP_REG) | + CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK); + IWL_ERR(priv, "Correctable OTP ECC error, continue read\n"); + } + e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16)); + } + } else { + /* eeprom is an array of 16bit values */ + for (addr = 0; addr < sz; addr += sizeof(u16)) { + u32 r; + + _iwl_write32(priv, CSR_EEPROM_REG, + CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); + + ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG, + CSR_EEPROM_REG_READ_VALID_MSK, + IWL_EEPROM_ACCESS_TIMEOUT); + if (ret < 0) { + IWL_ERR(priv, "Time out reading EEPROM[%d]\n", addr); + goto done; + } + r = _iwl_read_direct32(priv, CSR_EEPROM_REG); + e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16)); } - r = _iwl_read_direct32(priv, CSR_EEPROM_REG); - e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16)); } ret = 0; done: priv->cfg->ops->lib->eeprom_ops.release_semaphore(priv); err: if (ret) - kfree(priv->eeprom); + iwl_eeprom_free(priv); alloc_err: return ret; } @@ -285,7 +390,7 @@ int iwl_eeprom_check_version(struct iwl_priv *priv) return 0; err: - IWL_ERR(priv, "Unsupported EEPROM VER=0x%x < 0x%x CALIB=0x%x < 0x%x\n", + IWL_ERR(priv, "Unsupported (too old) EEPROM VER=0x%x < 0x%x CALIB=0x%x < 0x%x\n", eeprom_ver, priv->cfg->eeprom_ver, calib_ver, priv->cfg->eeprom_calib_ver); return -EINVAL; @@ -301,6 +406,8 @@ EXPORT_SYMBOL(iwl_eeprom_query_addr); u16 iwl_eeprom_query16(const struct iwl_priv *priv, size_t offset) { + if (!priv->eeprom) + return 0; return (u16)priv->eeprom[offset] | ((u16)priv->eeprom[offset + 1] << 8); } EXPORT_SYMBOL(iwl_eeprom_query16); @@ -481,8 +588,8 @@ int iwl_init_channel_map(struct iwl_priv *priv) /* First write that fat is not enabled, and then enable * one by one */ ch_info->fat_extension_channel = - (IEEE80211_CHAN_NO_FAT_ABOVE | - IEEE80211_CHAN_NO_FAT_BELOW); + (IEEE80211_CHAN_NO_HT40PLUS | + IEEE80211_CHAN_NO_HT40MINUS); if (!(is_channel_valid(ch_info))) { IWL_DEBUG_INFO(priv, "Ch. %d Flags %x [%sGHz] - " @@ -561,7 +668,7 @@ int iwl_init_channel_map(struct iwl_priv *priv) fat_extension_chan = 0; else fat_extension_chan = - IEEE80211_CHAN_NO_FAT_BELOW; + IEEE80211_CHAN_NO_HT40MINUS; /* Set up driver's info for lower half */ iwl_set_fat_chan_info(priv, ieeeband, @@ -573,7 +680,7 @@ int iwl_init_channel_map(struct iwl_priv *priv) iwl_set_fat_chan_info(priv, ieeeband, (eeprom_ch_index[ch] + 4), &(eeprom_ch_info[ch]), - IEEE80211_CHAN_NO_FAT_ABOVE); + IEEE80211_CHAN_NO_HT40PLUS); } } diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index 3479153d96ca..195b4ef12c27 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -179,6 +179,10 @@ struct iwl_eeprom_channel { #define EEPROM_5050_TX_POWER_VERSION (4) #define EEPROM_5050_EEPROM_VERSION (0x21E) +/* OTP */ +#define OTP_LOWER_BLOCKS_TOTAL (3) +#define OTP_BLOCK_SIZE (0x400) + /* 2.4 GHz */ extern const u8 iwl_eeprom_band_1[14]; diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h index 083ea1ffbe87..d30cb0275d19 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-io.h @@ -131,9 +131,23 @@ static inline void __iwl_set_bit(const char *f, u32 l, IWL_DEBUG_IO(priv, "set_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val); _iwl_write32(priv, reg, val); } -#define iwl_set_bit(p, r, m) __iwl_set_bit(__FILE__, __LINE__, p, r, m) +static inline void iwl_set_bit(struct iwl_priv *p, u32 r, u32 m) +{ + unsigned long reg_flags; + + spin_lock_irqsave(&p->reg_lock, reg_flags); + __iwl_set_bit(__FILE__, __LINE__, p, r, m); + spin_unlock_irqrestore(&p->reg_lock, reg_flags); +} #else -#define iwl_set_bit(p, r, m) _iwl_set_bit(p, r, m) +static inline void iwl_set_bit(struct iwl_priv *p, u32 r, u32 m) +{ + unsigned long reg_flags; + + spin_lock_irqsave(&p->reg_lock, reg_flags); + _iwl_set_bit(p, r, m); + spin_unlock_irqrestore(&p->reg_lock, reg_flags); +} #endif static inline void _iwl_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask) @@ -148,19 +162,30 @@ static inline void __iwl_clear_bit(const char *f, u32 l, IWL_DEBUG_IO(priv, "clear_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val); _iwl_write32(priv, reg, val); } -#define iwl_clear_bit(p, r, m) __iwl_clear_bit(__FILE__, __LINE__, p, r, m) +static inline void iwl_clear_bit(struct iwl_priv *p, u32 r, u32 m) +{ + unsigned long reg_flags; + + spin_lock_irqsave(&p->reg_lock, reg_flags); + __iwl_clear_bit(__FILE__, __LINE__, p, r, m); + spin_unlock_irqrestore(&p->reg_lock, reg_flags); +} #else -#define iwl_clear_bit(p, r, m) _iwl_clear_bit(p, r, m) +static inline void iwl_clear_bit(struct iwl_priv *p, u32 r, u32 m) +{ + unsigned long reg_flags; + + spin_lock_irqsave(&p->reg_lock, reg_flags); + _iwl_clear_bit(p, r, m); + spin_unlock_irqrestore(&p->reg_lock, reg_flags); +} #endif static inline int _iwl_grab_nic_access(struct iwl_priv *priv) { int ret; u32 val; -#ifdef CONFIG_IWLWIFI_DEBUG - if (atomic_read(&priv->restrict_refcnt)) - return 0; -#endif + /* this bit wakes up the NIC */ _iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); ret = _iwl_poll_bit(priv, CSR_GP_CNTRL, @@ -170,12 +195,10 @@ static inline int _iwl_grab_nic_access(struct iwl_priv *priv) if (ret < 0) { val = _iwl_read32(priv, CSR_GP_CNTRL); IWL_ERR(priv, "MAC is in deep sleep!. CSR_GP_CNTRL = 0x%08X\n", val); + _iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI); return -EIO; } -#ifdef CONFIG_IWLWIFI_DEBUG - atomic_inc(&priv->restrict_refcnt); -#endif return 0; } @@ -183,9 +206,6 @@ static inline int _iwl_grab_nic_access(struct iwl_priv *priv) static inline int __iwl_grab_nic_access(const char *f, u32 l, struct iwl_priv *priv) { - if (atomic_read(&priv->restrict_refcnt)) - IWL_ERR(priv, "Grabbing access while already held %s %d.\n", f, l); - IWL_DEBUG_IO(priv, "grabbing nic access - %s %d\n", f, l); return _iwl_grab_nic_access(priv); } @@ -198,18 +218,13 @@ static inline int __iwl_grab_nic_access(const char *f, u32 l, static inline void _iwl_release_nic_access(struct iwl_priv *priv) { -#ifdef CONFIG_IWLWIFI_DEBUG - if (atomic_dec_and_test(&priv->restrict_refcnt)) -#endif - _iwl_clear_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + _iwl_clear_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); } #ifdef CONFIG_IWLWIFI_DEBUG static inline void __iwl_release_nic_access(const char *f, u32 l, struct iwl_priv *priv) { - if (atomic_read(&priv->restrict_refcnt) <= 0) - IWL_ERR(priv, "Release unheld nic access at line %s %d.\n", f, l); IWL_DEBUG_IO(priv, "releasing nic access - %s %d\n", f, l); _iwl_release_nic_access(priv); @@ -230,16 +245,37 @@ static inline u32 __iwl_read_direct32(const char *f, u32 l, struct iwl_priv *priv, u32 reg) { u32 value = _iwl_read_direct32(priv, reg); - if (!atomic_read(&priv->restrict_refcnt)) - IWL_ERR(priv, "Nic access not held from %s %d\n", f, l); IWL_DEBUG_IO(priv, "read_direct32(0x%4X) = 0x%08x - %s %d \n", reg, value, f, l); return value; } -#define iwl_read_direct32(priv, reg) \ - __iwl_read_direct32(__FILE__, __LINE__, priv, reg) +static inline u32 iwl_read_direct32(struct iwl_priv *priv, u32 reg) +{ + u32 value; + unsigned long reg_flags; + + spin_lock_irqsave(&priv->reg_lock, reg_flags); + iwl_grab_nic_access(priv); + value = __iwl_read_direct32(__FILE__, __LINE__, priv, reg); + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->reg_lock, reg_flags); + return value; +} + #else -#define iwl_read_direct32 _iwl_read_direct32 +static inline u32 iwl_read_direct32(struct iwl_priv *priv, u32 reg) +{ + u32 value; + unsigned long reg_flags; + + spin_lock_irqsave(&priv->reg_lock, reg_flags); + iwl_grab_nic_access(priv); + value = _iwl_read_direct32(priv, reg); + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->reg_lock, reg_flags); + return value; + +} #endif static inline void _iwl_write_direct32(struct iwl_priv *priv, @@ -247,19 +283,17 @@ static inline void _iwl_write_direct32(struct iwl_priv *priv, { _iwl_write32(priv, reg, value); } -#ifdef CONFIG_IWLWIFI_DEBUG -static void __iwl_write_direct32(const char *f , u32 line, - struct iwl_priv *priv, u32 reg, u32 value) +static inline void iwl_write_direct32(struct iwl_priv *priv, u32 reg, u32 value) { - if (!atomic_read(&priv->restrict_refcnt)) - IWL_ERR(priv, "Nic access not held from %s line %d\n", f, line); - _iwl_write_direct32(priv, reg, value); + unsigned long reg_flags; + + spin_lock_irqsave(&priv->reg_lock, reg_flags); + if (!iwl_grab_nic_access(priv)) { + _iwl_write_direct32(priv, reg, value); + iwl_release_nic_access(priv); + } + spin_unlock_irqrestore(&priv->reg_lock, reg_flags); } -#define iwl_write_direct32(priv, reg, value) \ - __iwl_write_direct32(__func__, __LINE__, priv, reg, value) -#else -#define iwl_write_direct32 _iwl_write_direct32 -#endif static inline void iwl_write_reg_buf(struct iwl_priv *priv, u32 reg, u32 len, u32 *values) @@ -268,14 +302,23 @@ static inline void iwl_write_reg_buf(struct iwl_priv *priv, if ((priv != NULL) && (values != NULL)) { for (; 0 < len; len -= count, reg += count, values++) - _iwl_write_direct32(priv, reg, *values); + iwl_write_direct32(priv, reg, *values); } } static inline int _iwl_poll_direct_bit(struct iwl_priv *priv, u32 addr, u32 mask, int timeout) { - return _iwl_poll_bit(priv, addr, mask, mask, timeout); + int t = 0; + + do { + if ((iwl_read_direct32(priv, addr) & mask) == mask) + return t; + udelay(IWL_POLL_INTERVAL); + t += IWL_POLL_INTERVAL; + } while (t < timeout); + + return -ETIMEDOUT; } #ifdef CONFIG_IWLWIFI_DEBUG @@ -305,20 +348,18 @@ static inline u32 _iwl_read_prph(struct iwl_priv *priv, u32 reg) rmb(); return _iwl_read_direct32(priv, HBUS_TARG_PRPH_RDAT); } -#ifdef CONFIG_IWLWIFI_DEBUG -static inline u32 __iwl_read_prph(const char *f, u32 line, - struct iwl_priv *priv, u32 reg) +static inline u32 iwl_read_prph(struct iwl_priv *priv, u32 reg) { - if (!atomic_read(&priv->restrict_refcnt)) - IWL_ERR(priv, "Nic access not held from %s line %d\n", f, line); - return _iwl_read_prph(priv, reg); -} + unsigned long reg_flags; + u32 val; -#define iwl_read_prph(priv, reg) \ - __iwl_read_prph(__func__, __LINE__, priv, reg) -#else -#define iwl_read_prph _iwl_read_prph -#endif + spin_lock_irqsave(&priv->reg_lock, reg_flags); + iwl_grab_nic_access(priv); + val = _iwl_read_prph(priv, reg); + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->reg_lock, reg_flags); + return val; +} static inline void _iwl_write_prph(struct iwl_priv *priv, u32 addr, u32 val) @@ -328,83 +369,107 @@ static inline void _iwl_write_prph(struct iwl_priv *priv, wmb(); _iwl_write_direct32(priv, HBUS_TARG_PRPH_WDAT, val); } -#ifdef CONFIG_IWLWIFI_DEBUG -static inline void __iwl_write_prph(const char *f, u32 line, - struct iwl_priv *priv, u32 addr, u32 val) -{ - if (!atomic_read(&priv->restrict_refcnt)) - IWL_ERR(priv, "Nic access not held from %s line %d\n", f, line); - _iwl_write_prph(priv, addr, val); -} -#define iwl_write_prph(priv, addr, val) \ - __iwl_write_prph(__func__, __LINE__, priv, addr, val); -#else -#define iwl_write_prph _iwl_write_prph -#endif +static inline void iwl_write_prph(struct iwl_priv *priv, u32 addr, u32 val) +{ + unsigned long reg_flags; + + spin_lock_irqsave(&priv->reg_lock, reg_flags); + if (!iwl_grab_nic_access(priv)) { + _iwl_write_prph(priv, addr, val); + iwl_release_nic_access(priv); + } + spin_unlock_irqrestore(&priv->reg_lock, reg_flags); +} #define _iwl_set_bits_prph(priv, reg, mask) \ _iwl_write_prph(priv, reg, (_iwl_read_prph(priv, reg) | mask)) -#ifdef CONFIG_IWLWIFI_DEBUG -static inline void __iwl_set_bits_prph(const char *f, u32 line, - struct iwl_priv *priv, - u32 reg, u32 mask) -{ - if (!atomic_read(&priv->restrict_refcnt)) - IWL_ERR(priv, "Nic access not held from %s line %d\n", f, line); +static inline void iwl_set_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask) +{ + unsigned long reg_flags; + + spin_lock_irqsave(&priv->reg_lock, reg_flags); + iwl_grab_nic_access(priv); _iwl_set_bits_prph(priv, reg, mask); + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->reg_lock, reg_flags); } -#define iwl_set_bits_prph(priv, reg, mask) \ - __iwl_set_bits_prph(__func__, __LINE__, priv, reg, mask) -#else -#define iwl_set_bits_prph _iwl_set_bits_prph -#endif #define _iwl_set_bits_mask_prph(priv, reg, bits, mask) \ _iwl_write_prph(priv, reg, ((_iwl_read_prph(priv, reg) & mask) | bits)) -#ifdef CONFIG_IWLWIFI_DEBUG -static inline void __iwl_set_bits_mask_prph(const char *f, u32 line, - struct iwl_priv *priv, u32 reg, u32 bits, u32 mask) +static inline void iwl_set_bits_mask_prph(struct iwl_priv *priv, u32 reg, + u32 bits, u32 mask) { - if (!atomic_read(&priv->restrict_refcnt)) - IWL_ERR(priv, "Nic access not held from %s line %d\n", f, line); + unsigned long reg_flags; + + spin_lock_irqsave(&priv->reg_lock, reg_flags); + iwl_grab_nic_access(priv); _iwl_set_bits_mask_prph(priv, reg, bits, mask); + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->reg_lock, reg_flags); } -#define iwl_set_bits_mask_prph(priv, reg, bits, mask) \ - __iwl_set_bits_mask_prph(__func__, __LINE__, priv, reg, bits, mask) -#else -#define iwl_set_bits_mask_prph _iwl_set_bits_mask_prph -#endif static inline void iwl_clear_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask) { - u32 val = _iwl_read_prph(priv, reg); + unsigned long reg_flags; + u32 val; + + spin_lock_irqsave(&priv->reg_lock, reg_flags); + iwl_grab_nic_access(priv); + val = _iwl_read_prph(priv, reg); _iwl_write_prph(priv, reg, (val & ~mask)); + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->reg_lock, reg_flags); } static inline u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr) { - iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, addr); + unsigned long reg_flags; + u32 value; + + spin_lock_irqsave(&priv->reg_lock, reg_flags); + iwl_grab_nic_access(priv); + + _iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, addr); rmb(); - return iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); + value = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); + + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->reg_lock, reg_flags); + return value; } static inline void iwl_write_targ_mem(struct iwl_priv *priv, u32 addr, u32 val) { - iwl_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr); - wmb(); - iwl_write_direct32(priv, HBUS_TARG_MEM_WDAT, val); + unsigned long reg_flags; + + spin_lock_irqsave(&priv->reg_lock, reg_flags); + if (!iwl_grab_nic_access(priv)) { + _iwl_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr); + wmb(); + _iwl_write_direct32(priv, HBUS_TARG_MEM_WDAT, val); + iwl_release_nic_access(priv); + } + spin_unlock_irqrestore(&priv->reg_lock, reg_flags); } static inline void iwl_write_targ_mem_buf(struct iwl_priv *priv, u32 addr, u32 len, u32 *values) { - iwl_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr); - wmb(); - for (; 0 < len; len -= sizeof(u32), values++) - iwl_write_direct32(priv, HBUS_TARG_MEM_WDAT, *values); + unsigned long reg_flags; + + spin_lock_irqsave(&priv->reg_lock, reg_flags); + if (!iwl_grab_nic_access(priv)) { + _iwl_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr); + wmb(); + for (; 0 < len; len -= sizeof(u32), values++) + _iwl_write_direct32(priv, HBUS_TARG_MEM_WDAT, *values); + + iwl_release_nic_access(priv); + } + spin_unlock_irqrestore(&priv->reg_lock, reg_flags); } #endif diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index 19680f72087f..5e64252f80f6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -176,10 +176,6 @@ static int iwl_led_associate(struct iwl_priv *priv, int led_id) static int iwl_led_disassociate(struct iwl_priv *priv, int led_id) { priv->allow_blinking = 0; - if (iwl_is_rfkill(priv)) - iwl4965_led_off_reg(priv, led_id); - else - iwl4965_led_on_reg(priv, led_id); return 0; } diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 47c894530eb5..f2ea3f05f6e1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -41,38 +41,33 @@ #include "iwl-power.h" /* - * Setting power level allow the card to go to sleep when not busy - * there are three factor that decide the power level to go to, they - * are list here with its priority - * 1- critical_power_setting this will be set according to card temperature. - * 2- system_power_setting this will be set by system PM manager. - * 3- user_power_setting this will be set by user either by writing to sys or - * mac80211 + * Setting power level allow the card to go to sleep when not busy. * - * if system_power_setting and user_power_setting is set to auto - * the power level will be decided according to association status and battery - * status. + * The power level is set to INDEX_1 (the least deep state) by + * default, and will, in the future, be the deepest state unless + * otherwise required by pm_qos network latency requirements. * + * Using INDEX_1 without pm_qos is ok because mac80211 will disable + * PS when even checking every beacon for the TIM bit would exceed + * the required latency. */ -#define MSEC_TO_USEC 1024 #define IWL_POWER_RANGE_0_MAX (2) #define IWL_POWER_RANGE_1_MAX (10) - -#define IWL_POWER_ON_BATTERY IWL_POWER_INDEX_5 -#define IWL_POWER_ON_AC_DISASSOC IWL_POWER_MODE_CAM -#define IWL_POWER_ON_AC_ASSOC IWL_POWER_MODE_CAM - - -#define IWL_CT_KILL_TEMPERATURE 110 -#define IWL_MIN_POWER_TEMPERATURE 100 -#define IWL_REDUCED_POWER_TEMPERATURE 95 - +#define NOSLP cpu_to_le16(0), 0, 0 +#define SLP IWL_POWER_DRIVER_ALLOW_SLEEP_MSK, 0, 0 +#define TU_TO_USEC 1024 +#define SLP_TOUT(T) cpu_to_le32((T) * TU_TO_USEC) +#define SLP_VEC(X0, X1, X2, X3, X4) {cpu_to_le32(X0), \ + cpu_to_le32(X1), \ + cpu_to_le32(X2), \ + cpu_to_le32(X3), \ + cpu_to_le32(X4)} /* default power management (not Tx power) table values */ -/* for TIM 0-10 */ -static struct iwl_power_vec_entry range_0[IWL_POWER_MAX] = { +/* for DTIM period 0 through IWL_POWER_RANGE_0_MAX */ +static const struct iwl_power_vec_entry range_0[IWL_POWER_NUM] = { {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0}, @@ -82,8 +77,8 @@ static struct iwl_power_vec_entry range_0[IWL_POWER_MAX] = { }; -/* for TIM = 3-10 */ -static struct iwl_power_vec_entry range_1[IWL_POWER_MAX] = { +/* for DTIM period IWL_POWER_RANGE_0_MAX + 1 through IWL_POWER_RANGE_1_MAX */ +static const struct iwl_power_vec_entry range_1[IWL_POWER_NUM] = { {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 3, 4, 7)}, 0}, @@ -92,8 +87,8 @@ static struct iwl_power_vec_entry range_1[IWL_POWER_MAX] = { {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(2, 4, 7, 10, 10)}, 2} }; -/* for TIM > 11 */ -static struct iwl_power_vec_entry range_2[IWL_POWER_MAX] = { +/* for DTIM period > IWL_POWER_RANGE_1_MAX */ +static const struct iwl_power_vec_entry range_2[IWL_POWER_NUM] = { {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 0xFF)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(2, 4, 6, 7, 0xFF)}, 0}, @@ -106,39 +101,15 @@ static struct iwl_power_vec_entry range_2[IWL_POWER_MAX] = { /* set card power command */ static int iwl_set_power(struct iwl_priv *priv, void *cmd) { - return iwl_send_cmd_pdu_async(priv, POWER_TABLE_CMD, - sizeof(struct iwl_powertable_cmd), - cmd, NULL); -} -/* decide the right power level according to association status - * and battery status - */ -static u16 iwl_get_auto_power_mode(struct iwl_priv *priv) -{ - u16 mode; - - switch (priv->power_data.user_power_setting) { - case IWL_POWER_AUTO: - /* if running on battery */ - if (priv->power_data.is_battery_active) - mode = IWL_POWER_ON_BATTERY; - else if (iwl_is_associated(priv)) - mode = IWL_POWER_ON_AC_ASSOC; - else - mode = IWL_POWER_ON_AC_DISASSOC; - break; - default: - mode = priv->power_data.user_power_setting; - break; - } - return mode; + return iwl_send_cmd_pdu(priv, POWER_TABLE_CMD, + sizeof(struct iwl_powertable_cmd), cmd); } /* initialize to default */ static void iwl_power_init_handle(struct iwl_priv *priv) { struct iwl_power_mgr *pow_data; - int size = sizeof(struct iwl_power_vec_entry) * IWL_POWER_MAX; + int size = sizeof(struct iwl_power_vec_entry) * IWL_POWER_NUM; struct iwl_powertable_cmd *cmd; int i; u16 lctl; @@ -157,7 +128,7 @@ static void iwl_power_init_handle(struct iwl_priv *priv) IWL_DEBUG_POWER(priv, "adjust power command flags\n"); - for (i = 0; i < IWL_POWER_MAX; i++) { + for (i = 0; i < IWL_POWER_NUM; i++) { cmd = &pow_data->pwr_range_0[i].cmd; if (lctl & PCI_CFG_LINK_CTRL_VAL_L0S_EN) @@ -247,33 +218,12 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force) update_chains = priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE || priv->chain_noise_data.state == IWL_CHAIN_NOISE_ALIVE; - /* If on battery, set to 3, - * if plugged into AC power, set to CAM ("continuously aware mode"), - * else user level */ + final_mode = priv->power_data.user_power_setting; - switch (setting->system_power_setting) { - case IWL_POWER_SYS_AUTO: - final_mode = iwl_get_auto_power_mode(priv); - break; - case IWL_POWER_SYS_BATTERY: - final_mode = IWL_POWER_INDEX_3; - break; - case IWL_POWER_SYS_AC: - final_mode = IWL_POWER_MODE_CAM; - break; - default: - final_mode = IWL_POWER_INDEX_3; - WARN_ON(1); - } - - if (setting->critical_power_setting > final_mode) - final_mode = setting->critical_power_setting; - - /* driver only support CAM for non STA network */ - if (priv->iw_mode != NL80211_IFTYPE_STATION) + if (setting->power_disabled) final_mode = IWL_POWER_MODE_CAM; - if (iwl_is_ready_rf(priv) && !setting->power_disabled && + if (iwl_is_ready_rf(priv) && ((setting->power_mode != final_mode) || force)) { struct iwl_powertable_cmd cmd; @@ -290,8 +240,6 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force) if (final_mode == IWL_POWER_MODE_CAM) clear_bit(STATUS_POWER_PMI, &priv->status); - else - set_bit(STATUS_POWER_PMI, &priv->status); if (priv->cfg->ops->lib->update_chain_flags && update_chains) priv->cfg->ops->lib->update_chain_flags(priv); @@ -307,51 +255,10 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force) } EXPORT_SYMBOL(iwl_power_update_mode); -/* Allow other iwl code to disable/enable power management active - * this will be useful for rate scale to disable PM during heavy - * Tx/Rx activities - */ -int iwl_power_disable_management(struct iwl_priv *priv, u32 ms) -{ - u16 prev_mode; - int ret = 0; - - if (priv->power_data.power_disabled) - return -EBUSY; - - prev_mode = priv->power_data.user_power_setting; - priv->power_data.user_power_setting = IWL_POWER_MODE_CAM; - ret = iwl_power_update_mode(priv, 0); - priv->power_data.power_disabled = 1; - priv->power_data.user_power_setting = prev_mode; - cancel_delayed_work(&priv->set_power_save); - if (ms) - queue_delayed_work(priv->workqueue, &priv->set_power_save, - msecs_to_jiffies(ms)); - - - return ret; -} -EXPORT_SYMBOL(iwl_power_disable_management); - -/* Allow other iwl code to disable/enable power management active - * this will be useful for rate scale to disable PM during high - * volume activities - */ -int iwl_power_enable_management(struct iwl_priv *priv) -{ - int ret = 0; - - priv->power_data.power_disabled = 0; - ret = iwl_power_update_mode(priv, 0); - return ret; -} -EXPORT_SYMBOL(iwl_power_enable_management); - /* set user_power_setting */ int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode) { - if (mode > IWL_POWER_MAX) + if (mode >= IWL_POWER_NUM) return -EINVAL; priv->power_data.user_power_setting = mode; @@ -360,86 +267,12 @@ int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode) } EXPORT_SYMBOL(iwl_power_set_user_mode); -/* set system_power_setting. This should be set by over all - * PM application. - */ -int iwl_power_set_system_mode(struct iwl_priv *priv, u16 mode) -{ - if (mode < IWL_POWER_SYS_MAX) - priv->power_data.system_power_setting = mode; - else - return -EINVAL; - return iwl_power_update_mode(priv, 0); -} -EXPORT_SYMBOL(iwl_power_set_system_mode); - /* initialize to default */ void iwl_power_initialize(struct iwl_priv *priv) { iwl_power_init_handle(priv); - priv->power_data.user_power_setting = IWL_POWER_AUTO; - priv->power_data.system_power_setting = IWL_POWER_SYS_AUTO; - priv->power_data.power_disabled = 0; - priv->power_data.is_battery_active = 0; - priv->power_data.critical_power_setting = 0; + priv->power_data.user_power_setting = IWL_POWER_INDEX_1; + /* default to disabled until mac80211 says otherwise */ + priv->power_data.power_disabled = 1; } EXPORT_SYMBOL(iwl_power_initialize); - -/* set critical_power_setting according to temperature value */ -int iwl_power_temperature_change(struct iwl_priv *priv) -{ - int ret = 0; - s32 temperature = KELVIN_TO_CELSIUS(priv->last_temperature); - u16 new_critical = priv->power_data.critical_power_setting; - - if (temperature > IWL_CT_KILL_TEMPERATURE) - return 0; - else if (temperature > IWL_MIN_POWER_TEMPERATURE) - new_critical = IWL_POWER_INDEX_5; - else if (temperature > IWL_REDUCED_POWER_TEMPERATURE) - new_critical = IWL_POWER_INDEX_3; - else - new_critical = IWL_POWER_MODE_CAM; - - if (new_critical != priv->power_data.critical_power_setting) - priv->power_data.critical_power_setting = new_critical; - - if (priv->power_data.critical_power_setting > - priv->power_data.power_mode) - ret = iwl_power_update_mode(priv, 0); - - return ret; -} -EXPORT_SYMBOL(iwl_power_temperature_change); - -static void iwl_bg_set_power_save(struct work_struct *work) -{ - struct iwl_priv *priv = container_of(work, - struct iwl_priv, set_power_save.work); - IWL_DEBUG_POWER(priv, "update power\n"); - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - mutex_lock(&priv->mutex); - - /* on starting association we disable power management - * until association, if association failed then this - * timer will expire and enable PM again. - */ - if (!iwl_is_associated(priv)) - iwl_power_enable_management(priv); - - mutex_unlock(&priv->mutex); -} -void iwl_setup_power_deferred_work(struct iwl_priv *priv) -{ - INIT_DELAYED_WORK(&priv->set_power_save, iwl_bg_set_power_save); -} -EXPORT_SYMBOL(iwl_setup_power_deferred_work); - -void iwl_power_cancel_timeout(struct iwl_priv *priv) -{ - cancel_delayed_work(&priv->set_power_save); -} -EXPORT_SYMBOL(iwl_power_cancel_timeout); diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h index 18963392121e..37ba3bb7a25a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.h +++ b/drivers/net/wireless/iwlwifi/iwl-power.h @@ -40,56 +40,29 @@ enum { IWL_POWER_INDEX_3, IWL_POWER_INDEX_4, IWL_POWER_INDEX_5, - IWL_POWER_AUTO, - IWL_POWER_MAX = IWL_POWER_AUTO, + IWL_POWER_NUM }; -enum { - IWL_POWER_SYS_AUTO, - IWL_POWER_SYS_AC, - IWL_POWER_SYS_BATTERY, - IWL_POWER_SYS_MAX, -}; - - /* Power management (not Tx power) structures */ -#define NOSLP cpu_to_le16(0), 0, 0 -#define SLP IWL_POWER_DRIVER_ALLOW_SLEEP_MSK, 0, 0 -#define SLP_TOUT(T) cpu_to_le32((T) * MSEC_TO_USEC) -#define SLP_VEC(X0, X1, X2, X3, X4) {cpu_to_le32(X0), \ - cpu_to_le32(X1), \ - cpu_to_le32(X2), \ - cpu_to_le32(X3), \ - cpu_to_le32(X4)} struct iwl_power_vec_entry { struct iwl_powertable_cmd cmd; u8 no_dtim; }; struct iwl_power_mgr { - spinlock_t lock; - struct iwl_power_vec_entry pwr_range_0[IWL_POWER_MAX]; - struct iwl_power_vec_entry pwr_range_1[IWL_POWER_MAX]; - struct iwl_power_vec_entry pwr_range_2[IWL_POWER_MAX]; + struct iwl_power_vec_entry pwr_range_0[IWL_POWER_NUM]; + struct iwl_power_vec_entry pwr_range_1[IWL_POWER_NUM]; + struct iwl_power_vec_entry pwr_range_2[IWL_POWER_NUM]; u32 dtim_period; /* final power level that used to calculate final power command */ u8 power_mode; - u8 user_power_setting; /* set by user through mac80211 or sysfs */ - u8 system_power_setting; /* set by kernel system tools */ - u8 critical_power_setting; /* set if driver over heated */ - u8 is_battery_active; /* DC/AC power */ - u8 power_disabled; /* flag to disable using power saving level */ + u8 user_power_setting; /* set by user through sysfs */ + u8 power_disabled; /* set by mac80211's CONF_PS */ }; -void iwl_setup_power_deferred_work(struct iwl_priv *priv); -void iwl_power_cancel_timeout(struct iwl_priv *priv); int iwl_power_update_mode(struct iwl_priv *priv, bool force); -int iwl_power_disable_management(struct iwl_priv *priv, u32 ms); -int iwl_power_enable_management(struct iwl_priv *priv); int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode); -int iwl_power_set_system_mode(struct iwl_priv *priv, u16 mode); void iwl_power_initialize(struct iwl_priv *priv); -int iwl_power_temperature_change(struct iwl_priv *priv); #endif /* __iwl_power_setting_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-rfkill.c b/drivers/net/wireless/iwlwifi/iwl-rfkill.c deleted file mode 100644 index 2ad9faf1508a..000000000000 --- a/drivers/net/wireless/iwlwifi/iwl-rfkill.c +++ /dev/null @@ -1,145 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved. - * - * Portions of this file are derived from the ipw3945 project, as well - * as portions of the ieee80211 subsystem header files. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * - * The full GNU General Public License is included in this distribution in the - * file called LICENSE. - * - * Contact Information: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - *****************************************************************************/ -#include -#include -#include - -#include - -#include "iwl-eeprom.h" -#include "iwl-dev.h" -#include "iwl-core.h" - -/* software rf-kill from user */ -static int iwl_rfkill_soft_rf_kill(void *data, enum rfkill_state state) -{ - struct iwl_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(priv, "we received soft RFKILL set to state %d\n", state); - mutex_lock(&priv->mutex); - - switch (state) { - 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_SOFT_BLOCKED: - iwl_radio_kill_sw_disable_radio(priv); - break; - default: - IWL_WARN(priv, "we received unexpected RFKILL state %d\n", - state); - break; - } -out_unlock: - mutex_unlock(&priv->mutex); - - return err; -} - -int iwl_rfkill_init(struct iwl_priv *priv) -{ - struct device *device = wiphy_dev(priv->hw->wiphy); - int ret = 0; - - BUG_ON(device == NULL); - - IWL_DEBUG_RF_KILL(priv, "Initializing RFKILL.\n"); - priv->rfkill = rfkill_allocate(device, RFKILL_TYPE_WLAN); - if (!priv->rfkill) { - IWL_ERR(priv, "Unable to allocate RFKILL device.\n"); - ret = -ENOMEM; - goto error; - } - - priv->rfkill->name = priv->cfg->name; - priv->rfkill->data = priv; - priv->rfkill->state = RFKILL_STATE_UNBLOCKED; - priv->rfkill->toggle_radio = iwl_rfkill_soft_rf_kill; - priv->rfkill->user_claim_unsupported = 1; - - priv->rfkill->dev.class->suspend = NULL; - priv->rfkill->dev.class->resume = NULL; - - ret = rfkill_register(priv->rfkill); - if (ret) { - IWL_ERR(priv, "Unable to register RFKILL: %d\n", ret); - goto free_rfkill; - } - - IWL_DEBUG_RF_KILL(priv, "RFKILL initialization complete.\n"); - return ret; - -free_rfkill: - if (priv->rfkill != NULL) - rfkill_free(priv->rfkill); - priv->rfkill = NULL; - -error: - IWL_DEBUG_RF_KILL(priv, "RFKILL initialization complete.\n"); - return ret; -} -EXPORT_SYMBOL(iwl_rfkill_init); - -void iwl_rfkill_unregister(struct iwl_priv *priv) -{ - - if (priv->rfkill) - rfkill_unregister(priv->rfkill); - - priv->rfkill = NULL; -} -EXPORT_SYMBOL(iwl_rfkill_unregister); - -/* set RFKILL to the right state. */ -void iwl_rfkill_set_hw_state(struct iwl_priv *priv) -{ - if (!priv->rfkill) - return; - - if (iwl_is_rfkill_hw(priv)) { - rfkill_force_state(priv->rfkill, RFKILL_STATE_HARD_BLOCKED); - return; - } - - if (!iwl_is_rfkill_sw(priv)) - rfkill_force_state(priv->rfkill, RFKILL_STATE_UNBLOCKED); - else - 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 deleted file mode 100644 index 633dafb4bf1b..000000000000 --- a/drivers/net/wireless/iwlwifi/iwl-rfkill.h +++ /dev/null @@ -1,48 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2007 - 2009 Intel Corporation. All rights reserved. - * - * Portions of this file are derived from the ipw3945 project, as well - * as portions of the ieee80211 subsystem header files. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * - * The full GNU General Public License is included in this distribution in the - * file called LICENSE. - * - * Contact Information: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - *****************************************************************************/ -#ifndef __iwl_rf_kill_h__ -#define __iwl_rf_kill_h__ - -struct iwl_priv; - -#include - -#ifdef CONFIG_IWLWIFI_RFKILL - -void iwl_rfkill_set_hw_state(struct iwl_priv *priv); -void iwl_rfkill_unregister(struct iwl_priv *priv); -int iwl_rfkill_init(struct iwl_priv *priv); -#else -static inline void iwl_rfkill_set_hw_state(struct iwl_priv *priv) {} -static inline void iwl_rfkill_unregister(struct iwl_priv *priv) {} -static inline int iwl_rfkill_init(struct iwl_priv *priv) { return 0; } -#endif - - - -#endif /* __iwl_rf_kill_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 8f65908f66f1..2b8d40b37a1c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -145,18 +145,14 @@ int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q) goto exit_unlock; } - ret = iwl_grab_nic_access(priv); - if (ret) - goto exit_unlock; - - /* Device expects a multiple of 8 */ - iwl_write_direct32(priv, rx_wrt_ptr_reg, q->write & ~0x7); - iwl_release_nic_access(priv); + q->write_actual = (q->write & ~0x7); + iwl_write_direct32(priv, rx_wrt_ptr_reg, q->write_actual); /* Else device is assumed to be awake */ } else { /* Device expects a multiple of 8 */ - iwl_write32(priv, rx_wrt_ptr_reg, q->write & ~0x7); + q->write_actual = (q->write & ~0x7); + iwl_write_direct32(priv, rx_wrt_ptr_reg, q->write_actual); } q->need_update = 0; @@ -218,7 +214,7 @@ int iwl_rx_queue_restock(struct iwl_priv *priv) /* If we've added more space for the firmware to place data, tell it. * Increment device's write pointer in multiples of 8. */ - if (write != (rxq->write & ~0x7)) { + if (rxq->write_actual != (rxq->write & ~0x7)) { spin_lock_irqsave(&rxq->lock, flags); rxq->need_update = 1; spin_unlock_irqrestore(&rxq->lock, flags); @@ -238,7 +234,7 @@ EXPORT_SYMBOL(iwl_rx_queue_restock); * Also restock the Rx queue via iwl_rx_queue_restock. * This is called as a scheduled work item (except for during initialization) */ -void iwl_rx_allocate(struct iwl_priv *priv) +void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority) { struct iwl_rx_queue *rxq = &priv->rxq; struct list_head *element; @@ -260,7 +256,8 @@ void iwl_rx_allocate(struct iwl_priv *priv) /* Alloc a new receive buffer */ rxb->skb = alloc_skb(priv->hw_params.rx_buf_size + 256, - GFP_KERNEL); + priority); + if (!rxb->skb) { IWL_CRIT(priv, "Can not allocate SKB buffers\n"); /* We don't reschedule replenish work here -- we will @@ -295,7 +292,7 @@ void iwl_rx_replenish(struct iwl_priv *priv) { unsigned long flags; - iwl_rx_allocate(priv); + iwl_rx_allocate(priv, GFP_KERNEL); spin_lock_irqsave(&priv->lock, flags); iwl_rx_queue_restock(priv); @@ -303,6 +300,14 @@ void iwl_rx_replenish(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_rx_replenish); +void iwl_rx_replenish_now(struct iwl_priv *priv) +{ + iwl_rx_allocate(priv, GFP_ATOMIC); + + iwl_rx_queue_restock(priv); +} +EXPORT_SYMBOL(iwl_rx_replenish_now); + /* Assumes that the skb field of the buffers in 'pool' is kept accurate. * If an SKB has been detached, the POOL needs to have its SKB set to NULL @@ -358,6 +363,7 @@ int iwl_rx_queue_alloc(struct iwl_priv *priv) /* Set us so that we have processed and used all buffers, but have * not restocked the Rx queue with fresh buffers */ rxq->read = rxq->write = 0; + rxq->write_actual = 0; rxq->free_count = 0; rxq->need_update = 0; return 0; @@ -396,6 +402,7 @@ void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq) /* Set us so that we have processed and used all buffers, but have * not restocked the Rx queue with fresh buffers */ rxq->read = rxq->write = 0; + rxq->write_actual = 0; rxq->free_count = 0; spin_unlock_irqrestore(&rxq->lock, flags); } @@ -403,18 +410,12 @@ EXPORT_SYMBOL(iwl_rx_queue_reset); int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) { - int ret; - unsigned long flags; u32 rb_size; const u32 rfdnlog = RX_QUEUE_SIZE_LOG; /* 256 RBDs */ - const u32 rb_timeout = 0; /* FIXME: RX_RB_TIMEOUT why this stalls RX */ + u32 rb_timeout = 0; /* FIXME: RX_RB_TIMEOUT for all devices? */ - 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->use_isr_legacy) + rb_timeout = RX_RB_TIMEOUT; if (priv->cfg->mod_params->amsdu_size_8K) rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K; @@ -452,35 +453,19 @@ int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) (rb_timeout << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS)| (rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS)); - iwl_release_nic_access(priv); - iwl_write32(priv, CSR_INT_COALESCING, 0x40); - spin_unlock_irqrestore(&priv->lock, flags); - return 0; } int iwl_rxq_stop(struct iwl_priv *priv) { - int ret; - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - ret = iwl_grab_nic_access(priv); - if (unlikely(ret)) { - spin_unlock_irqrestore(&priv->lock, flags); - return ret; - } /* stop Rx DMA */ iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); iwl_poll_direct_bit(priv, FH_MEM_RSSR_RX_STATUS_REG, FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000); - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->lock, flags); - return 0; } EXPORT_SYMBOL(iwl_rxq_stop); @@ -582,8 +567,8 @@ void iwl_rx_statistics(struct iwl_priv *priv, iwl_leds_background(priv); - if (priv->cfg->ops->lib->temperature && change) - priv->cfg->ops->lib->temperature(priv); + if (priv->cfg->ops->lib->temp_ops.temperature && change) + priv->cfg->ops->lib->temp_ops.temperature(priv); } EXPORT_SYMBOL(iwl_rx_statistics); @@ -1102,13 +1087,6 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, if (rx_start->phy_flags & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK) rx_status.flag |= RX_FLAG_SHORTPRE; - /* Take shortcut when only in monitor mode */ - if (priv->iw_mode == NL80211_IFTYPE_MONITOR) { - iwl_pass_packet_to_mac80211(priv, include_phy, - rxb, &rx_status); - return; - } - network_packet = iwl_is_network_packet(priv, header); if (network_packet) { priv->last_rx_rssi = rx_status.signal; diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 6330b91e37ce..e26875dbe859 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -445,13 +445,6 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw, unsigned long flags; struct iwl_priv *priv = hw->priv; int ret; - u8 *ssid = NULL; - size_t ssid_len = 0; - - if (req->n_ssids) { - ssid = req->ssids[0].ssid; - ssid_len = req->ssids[0].ssid_len; - } IWL_DEBUG_MAC80211(priv, "enter\n"); @@ -485,13 +478,7 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw, goto out_unlock; } - if (ssid_len) { - priv->one_direct_scan = 1; - priv->direct_ssid_len = ssid_len; - memcpy(priv->direct_ssid, ssid, priv->direct_ssid_len); - } else { - priv->one_direct_scan = 0; - } + priv->scan_request = req; ret = iwl_scan_initiate(priv); @@ -529,74 +516,15 @@ void iwl_bg_scan_check(struct work_struct *data) } EXPORT_SYMBOL(iwl_bg_scan_check); -/** - * iwl_supported_rate_to_ie - fill in the supported rate in IE field - * - * return : set the bit for each supported rate insert in ie - */ -static u16 iwl_supported_rate_to_ie(u8 *ie, u16 supported_rate, - u16 basic_rate, int *left) -{ - u16 ret_rates = 0, bit; - int i; - u8 *cnt = ie; - u8 *rates = ie + 1; - - for (bit = 1, i = 0; i < IWL_RATE_COUNT; i++, bit <<= 1) { - if (bit & supported_rate) { - ret_rates |= bit; - rates[*cnt] = iwl_rates[i].ieee | - ((bit & basic_rate) ? 0x80 : 0x00); - (*cnt)++; - (*left)--; - if ((*left <= 0) || - (*cnt >= IWL_SUPPORTED_RATES_IE_LEN)) - break; - } - } - - return ret_rates; -} - - -static void iwl_ht_cap_to_ie(const struct ieee80211_supported_band *sband, - u8 *pos, int *left) -{ - struct ieee80211_ht_cap *ht_cap; - - if (!sband || !sband->ht_cap.ht_supported) - return; - - if (*left < sizeof(struct ieee80211_ht_cap)) - return; - - *pos++ = sizeof(struct ieee80211_ht_cap); - ht_cap = (struct ieee80211_ht_cap *) pos; - - ht_cap->cap_info = cpu_to_le16(sband->ht_cap.cap); - memcpy(&ht_cap->mcs, &sband->ht_cap.mcs, 16); - ht_cap->ampdu_params_info = - (sband->ht_cap.ampdu_factor & IEEE80211_HT_AMPDU_PARM_FACTOR) | - ((sband->ht_cap.ampdu_density << 2) & - IEEE80211_HT_AMPDU_PARM_DENSITY); - *left -= sizeof(struct ieee80211_ht_cap); -} - /** * iwl_fill_probe_req - fill in all required fields and IE for probe request */ -u16 iwl_fill_probe_req(struct iwl_priv *priv, - enum ieee80211_band band, - struct ieee80211_mgmt *frame, - int left) +u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame, + const u8 *ies, int ie_len, int left) { int len = 0; u8 *pos = NULL; - u16 active_rates, ret_rates, cck_rates, active_rate_basic; - const struct ieee80211_supported_band *sband = - iwl_get_hw_mode(priv, band); - /* Make sure there is enough space for the probe request, * two mandatory IEs and the data */ @@ -624,62 +552,12 @@ u16 iwl_fill_probe_req(struct iwl_priv *priv, len += 2; - /* fill in supported rate */ - left -= 2; - if (left < 0) - return 0; + if (WARN_ON(left < ie_len)) + return len; - *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; + memcpy(pos, ies, ie_len); + len += ie_len; + left -= ie_len; return (u16)len; } @@ -699,11 +577,13 @@ static void iwl_bg_request_scan(struct work_struct *data) int ret = 0; u32 rate_flags = 0; u16 cmd_len; + u16 rx_chain = 0; enum ieee80211_band band; - u8 n_probes = 2; - u8 rx_chain = priv->hw_params.valid_rx_ant; + u8 n_probes = 0; + u8 rx_ant = priv->hw_params.valid_rx_ant; u8 rate; - DECLARE_SSID_BUF(ssid); + bool is_active = false; + int chan_mod; conf = ieee80211_get_hw_conf(priv->hw); @@ -795,19 +675,25 @@ static void iwl_bg_request_scan(struct work_struct *data) scan_suspend_time, interval); } - /* We should add the ability for user to lock to PASSIVE ONLY */ - if (priv->one_direct_scan) { - IWL_DEBUG_SCAN(priv, "Start direct scan for '%s'\n", - print_ssid(ssid, priv->direct_ssid, - priv->direct_ssid_len)); - scan->direct_scan[0].id = WLAN_EID_SSID; - scan->direct_scan[0].len = priv->direct_ssid_len; - memcpy(scan->direct_scan[0].ssid, - priv->direct_ssid, priv->direct_ssid_len); - n_probes++; - } else { - IWL_DEBUG_SCAN(priv, "Start indirect scan.\n"); - } + if (priv->scan_request->n_ssids) { + int i, p = 0; + IWL_DEBUG_SCAN(priv, "Kicking off active scan\n"); + for (i = 0; i < priv->scan_request->n_ssids; i++) { + /* always does wildcard anyway */ + if (!priv->scan_request->ssids[i].ssid_len) + continue; + scan->direct_scan[p].id = WLAN_EID_SSID; + scan->direct_scan[p].len = + priv->scan_request->ssids[i].ssid_len; + memcpy(scan->direct_scan[p].ssid, + priv->scan_request->ssids[i].ssid, + priv->scan_request->ssids[i].ssid_len); + n_probes++; + p++; + } + is_active = true; + } else + IWL_DEBUG_SCAN(priv, "Start passive scan.\n"); scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK; scan->tx_cmd.sta_id = priv->hw_params.bcast_sta_id; @@ -817,7 +703,9 @@ static void iwl_bg_request_scan(struct work_struct *data) if (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) { band = IEEE80211_BAND_2GHZ; scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK; - if (priv->active_rxon.flags & RXON_FLG_CHANNEL_MODE_PURE_40_MSK) { + chan_mod = le32_to_cpu(priv->active_rxon.flags & RXON_FLG_CHANNEL_MODE_MSK) + >> RXON_FLG_CHANNEL_MODE_POS; + if (chan_mod == CHANNEL_MODE_PURE_40) { rate = IWL_RATE_6M_PLCP; } else { rate = IWL_RATE_1M_PLCP; @@ -827,13 +715,18 @@ static void iwl_bg_request_scan(struct work_struct *data) } else if (priv->scan_bands & BIT(IEEE80211_BAND_5GHZ)) { band = IEEE80211_BAND_5GHZ; rate = IWL_RATE_6M_PLCP; - scan->good_CRC_th = IWL_GOOD_CRC_TH; + /* + * If active scaning is requested but a certain channel + * is marked passive, we can do active scanning if we + * detect transmissions. + */ + scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH : 0; /* Force use of chains B and C (0x6) for scan Rx for 4965 * Avoid A (0x1) because of its off-channel reception on A-band. */ if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) - rx_chain = 0x6; + rx_ant = ANT_BC; } else { IWL_WARN(priv, "Invalid scan band count\n"); goto done; @@ -845,26 +738,27 @@ static void iwl_bg_request_scan(struct work_struct *data) scan->tx_cmd.rate_n_flags = iwl_hw_set_rate_n_flags(rate, rate_flags); /* MIMO is not used here, but value is required */ - scan->rx_chain = RXON_RX_CHAIN_DRIVER_FORCE_MSK | - cpu_to_le16((0x7 << RXON_RX_CHAIN_VALID_POS) | - (rx_chain << RXON_RX_CHAIN_FORCE_SEL_POS) | - (0x7 << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS)); - - cmd_len = iwl_fill_probe_req(priv, band, - (struct ieee80211_mgmt *)scan->data, - IWL_MAX_SCAN_SIZE - sizeof(*scan)); + rx_chain |= ANT_ABC << RXON_RX_CHAIN_VALID_POS; + rx_chain |= ANT_ABC << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS; + rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_SEL_POS; + rx_chain |= 0x1 << RXON_RX_CHAIN_DRIVER_FORCE_POS; + scan->rx_chain = cpu_to_le16(rx_chain); + cmd_len = iwl_fill_probe_req(priv, + (struct ieee80211_mgmt *)scan->data, + priv->scan_request->ie, + priv->scan_request->ie_len, + IWL_MAX_SCAN_SIZE - sizeof(*scan)); scan->tx_cmd.len = cpu_to_le16(cmd_len); - if (priv->iw_mode == NL80211_IFTYPE_MONITOR) + if (iwl_is_monitor_mode(priv)) scan->filter_flags = RXON_FILTER_PROMISC_MSK; scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK | RXON_FILTER_BCON_AWARE_MSK); scan->channel_count = - iwl_get_channels_for_scan(priv, band, 1, /* active */ - n_probes, + iwl_get_channels_for_scan(priv, band, is_active, n_probes, (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]); if (scan->channel_count == 0) { diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index 44ab03a12e40..2addf735b193 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -86,8 +86,7 @@ static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id) spin_lock_irqsave(&priv->sta_lock, flags); - if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE) && - !(priv->stations_39[sta_id].used & IWL_STA_DRIVER_ACTIVE)) + if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) IWL_ERR(priv, "ACTIVATE a non DRIVER active station %d\n", sta_id); @@ -228,15 +227,16 @@ static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index, } /** - * iwl_add_station_flags - Add station to tables in driver and device + * iwl_add_station - Add station to tables in driver and device */ -u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap, - u8 flags, struct ieee80211_sta_ht_cap *ht_info) +u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap, u8 flags, + struct ieee80211_sta_ht_cap *ht_info) { - int i; - int sta_id = IWL_INVALID_STATION; struct iwl_station_entry *station; unsigned long flags_spin; + int i; + int sta_id = IWL_INVALID_STATION; + u16 rate; spin_lock_irqsave(&priv->sta_lock, flags_spin); if (is_ap) @@ -288,6 +288,12 @@ u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap, priv->iw_mode != NL80211_IFTYPE_ADHOC) iwl_set_ht_add_station(priv, sta_id, ht_info); + /* 3945 only */ + rate = (priv->band == IEEE80211_BAND_5GHZ) ? + IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP; + /* Turn on both antennas for the station... */ + station->sta.rate_n_flags = cpu_to_le16(rate | RATE_MCS_ANT_AB_MSK); + spin_unlock_irqrestore(&priv->sta_lock, flags_spin); /* Add station to device's station table */ @@ -295,7 +301,7 @@ u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap, return sta_id; } -EXPORT_SYMBOL(iwl_add_station_flags); +EXPORT_SYMBOL(iwl_add_station); static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, const char *addr) { @@ -408,7 +414,7 @@ static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr, /** * iwl_remove_station - Remove driver's knowledge of station. */ -int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap) +int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, bool is_ap) { int sta_id = IWL_INVALID_STATION; int i, ret = -EINVAL; @@ -490,7 +496,7 @@ void iwl_clear_stations_table(struct iwl_priv *priv) /* keep track of static keys */ for (i = 0; i < WEP_KEYS_MAX ; i++) { if (priv->wep_keys[i].key_size) - test_and_set_bit(i, &priv->ucode_key_table); + set_bit(i, &priv->ucode_key_table); } spin_unlock_irqrestore(&priv->sta_lock, flags); @@ -946,7 +952,7 @@ EXPORT_SYMBOL(iwl_send_lq_cmd); * calling this function (which runs REPLY_TX_LINK_QUALITY_CMD, * which requires station table entry to exist). */ -static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, int is_ap) +static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, bool is_ap) { int i, r; struct iwl_link_quality_cmd link_cmd = { @@ -979,8 +985,9 @@ static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, int is_ap) link_cmd.general_params.single_stream_ant_msk = first_antenna(priv->hw_params.valid_tx_ant); link_cmd.general_params.dual_stream_ant_msk = 3; - link_cmd.agg_params.agg_dis_start_th = 3; - link_cmd.agg_params.agg_time_limit = cpu_to_le16(4000); + link_cmd.agg_params.agg_dis_start_th = LINK_QUAL_AGG_DISABLE_START_DEF; + link_cmd.agg_params.agg_time_limit = + cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF); /* Update the rate scaling for control frame Tx to AP */ link_cmd.sta_id = is_ap ? IWL_AP_ID : priv->hw_params.bcast_sta_id; @@ -995,7 +1002,7 @@ static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, int is_ap) * there is only one AP station with id= IWL_AP_ID * NOTE: mutex must be held before calling this function */ -int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap) +int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap) { struct ieee80211_sta *sta; struct ieee80211_sta_ht_cap ht_config; @@ -1020,8 +1027,7 @@ int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap) rcu_read_unlock(); } - sta_id = iwl_add_station_flags(priv, addr, is_ap, - 0, cur_ht_config); + sta_id = iwl_add_station(priv, addr, is_ap, CMD_SYNC, cur_ht_config); /* Set up default rate scaling table in device's station table */ iwl_sta_init_lq(priv, addr, is_ap); @@ -1067,8 +1073,8 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) return sta_id; /* Create new station table entry */ - sta_id = iwl_add_station_flags(priv, hdr->addr1, - 0, CMD_ASYNC, NULL); + sta_id = iwl_add_station(priv, hdr->addr1, false, + CMD_ASYNC, NULL); if (sta_id != IWL_INVALID_STATION) return sta_id; @@ -1079,11 +1085,6 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) iwl_print_hex_dump(priv, IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr)); return priv->hw_params.bcast_sta_id; - /* If we are in monitor mode, use BCAST. This is required for - * packet injection. */ - case NL80211_IFTYPE_MONITOR: - return priv->hw_params.bcast_sta_id; - default: IWL_WARN(priv, "Unknown mode of operation: %d\n", priv->iw_mode); diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h index 59a586b6b56c..6deebade6361 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.h +++ b/drivers/net/wireless/iwlwifi/iwl-sta.h @@ -51,16 +51,15 @@ void iwl_update_tkip_key(struct iwl_priv *priv, struct ieee80211_key_conf *keyconf, const u8 *addr, u32 iv32, u16 *phase1key); -int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap); -int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap); +int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap); +int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, bool is_ap); void iwl_clear_stations_table(struct iwl_priv *priv); int iwl_get_free_ucode_key_index(struct iwl_priv *priv); int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr); int iwl_get_ra_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr); int iwl_send_add_sta(struct iwl_priv *priv, struct iwl_addsta_cmd *sta, u8 flags); -u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, - int is_ap, u8 flags, +u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap, u8 flags, struct ieee80211_sta_ht_cap *ht_info); void iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid); int iwl_sta_rx_agg_start(struct iwl_priv *priv, diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 71d5b8a1a73e..85ae7a62109c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -102,13 +102,8 @@ int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq) return ret; } - /* restore this queue's parameters in nic hardware. */ - ret = iwl_grab_nic_access(priv); - if (ret) - return ret; iwl_write_direct32(priv, HBUS_TARG_WRPTR, txq->q.write_ptr | (txq_id << 8)); - iwl_release_nic_access(priv); /* else not in power-save mode, uCode will never sleep when we're * trying to tx (during RFKILL, we're not trying to tx). */ @@ -429,11 +424,6 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv) goto error_kw; } spin_lock_irqsave(&priv->lock, flags); - ret = iwl_grab_nic_access(priv); - if (unlikely(ret)) { - spin_unlock_irqrestore(&priv->lock, flags); - goto error_reset; - } /* Turn off all Tx DMA fifos */ priv->cfg->ops->lib->txq_set_sched(priv, 0); @@ -441,7 +431,6 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv) /* Tell NIC where to find the "keep warm" buffer */ iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, priv->kw.dma >> 4); - iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); /* Alloc and init all Tx queues, including the command queue (#4) */ @@ -460,7 +449,6 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv) error: iwl_hw_txq_ctx_free(priv); - error_reset: iwl_free_dma_ptr(priv, &priv->kw); error_kw: iwl_free_dma_ptr(priv, &priv->scd_bc_tbls); @@ -478,10 +466,6 @@ void iwl_txq_ctx_stop(struct iwl_priv *priv) /* Turn off all Tx DMA fifos */ spin_lock_irqsave(&priv->lock, flags); - if (iwl_grab_nic_access(priv)) { - spin_unlock_irqrestore(&priv->lock, flags); - return; - } priv->cfg->ops->lib->txq_set_sched(priv, 0); @@ -492,7 +476,6 @@ void iwl_txq_ctx_stop(struct iwl_priv *priv) FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch), 1000); } - iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); /* Deallocate memory for all Tx queues */ @@ -728,7 +711,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) /* drop all data frame if we are not associated */ if (ieee80211_is_data(fc) && - (priv->iw_mode != NL80211_IFTYPE_MONITOR || + (!iwl_is_monitor_mode(priv) || !(info->flags & IEEE80211_TX_CTL_INJECTED)) && /* packet injection */ (!iwl_is_associated(priv) || ((priv->iw_mode == NL80211_IFTYPE_STATION) && !priv->assoc_id) || @@ -1183,8 +1166,10 @@ int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn) __func__, ra, tid); sta_id = iwl_find_station(priv, ra); - if (sta_id == IWL_INVALID_STATION) + if (sta_id == IWL_INVALID_STATION) { + IWL_ERR(priv, "Start AGG on invalid station\n"); return -ENXIO; + } if (priv->stations[sta_id].tid[tid].agg.state != IWL_AGG_OFF) { IWL_ERR(priv, "Start AGG when state is not IWL_AGG_OFF !\n"); @@ -1192,8 +1177,10 @@ int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn) } txq_id = iwl_txq_ctx_activate_free(priv); - if (txq_id == -1) + if (txq_id == -1) { + IWL_ERR(priv, "No free aggregation queue available\n"); return -ENXIO; + } spin_lock_irqsave(&priv->sta_lock, flags); tid_data = &priv->stations[sta_id].tid[tid]; @@ -1207,7 +1194,7 @@ int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn) return ret; if (tid_data->tfds_in_queue == 0) { - IWL_ERR(priv, "HW queue is empty\n"); + IWL_DEBUG_HT(priv, "HW queue is empty\n"); tid_data->agg.state = IWL_AGG_ON; ieee80211_start_tx_ba_cb_irqsafe(priv->hw, ra, tid); } else { diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index ff4d0e41d7c4..cb9bd4c8f25e 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -95,188 +95,6 @@ struct iwl_mod_params iwl3945_mod_params = { /* the rest are 0 by default */ }; -/*************** STATION TABLE MANAGEMENT **** - * mac80211 should be examined to determine if sta_info is duplicating - * the functionality provided here - */ - -/**************************************************************/ -#if 0 /* temporary disable till we add real remove station */ -/** - * iwl3945_remove_station - Remove driver's knowledge of station. - * - * NOTE: This does not remove station from device's station table. - */ -static u8 iwl3945_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap) -{ - int index = IWL_INVALID_STATION; - int i; - unsigned long flags; - - spin_lock_irqsave(&priv->sta_lock, flags); - - if (is_ap) - index = IWL_AP_ID; - else if (is_broadcast_ether_addr(addr)) - index = priv->hw_params.bcast_sta_id; - else - for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++) - if (priv->stations_39[i].used && - !compare_ether_addr(priv->stations_39[i].sta.sta.addr, - addr)) { - index = i; - break; - } - - if (unlikely(index == IWL_INVALID_STATION)) - goto out; - - if (priv->stations_39[index].used) { - priv->stations_39[index].used = 0; - priv->num_stations--; - } - - BUG_ON(priv->num_stations < 0); - -out: - spin_unlock_irqrestore(&priv->sta_lock, flags); - return 0; -} -#endif - -/** - * iwl3945_clear_stations_table - Clear the driver's station table - * - * NOTE: This does not clear or otherwise alter the device's station table. - */ -static void iwl3945_clear_stations_table(struct iwl_priv *priv) -{ - unsigned long flags; - - spin_lock_irqsave(&priv->sta_lock, flags); - - priv->num_stations = 0; - memset(priv->stations_39, 0, sizeof(priv->stations_39)); - - spin_unlock_irqrestore(&priv->sta_lock, flags); -} - -/** - * iwl3945_add_station - Add station to station tables in driver and device - */ -u8 iwl3945_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flags) -{ - int i; - int index = IWL_INVALID_STATION; - struct iwl3945_station_entry *station; - unsigned long flags_spin; - u8 rate; - - spin_lock_irqsave(&priv->sta_lock, flags_spin); - if (is_ap) - index = IWL_AP_ID; - else if (is_broadcast_ether_addr(addr)) - index = priv->hw_params.bcast_sta_id; - else - for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++) { - if (!compare_ether_addr(priv->stations_39[i].sta.sta.addr, - addr)) { - index = i; - break; - } - - if (!priv->stations_39[i].used && - index == IWL_INVALID_STATION) - index = i; - } - - /* These two conditions has the same outcome but keep them separate - since they have different meaning */ - if (unlikely(index == IWL_INVALID_STATION)) { - spin_unlock_irqrestore(&priv->sta_lock, flags_spin); - return index; - } - - if (priv->stations_39[index].used && - !compare_ether_addr(priv->stations_39[index].sta.sta.addr, addr)) { - spin_unlock_irqrestore(&priv->sta_lock, flags_spin); - return index; - } - - IWL_DEBUG_ASSOC(priv, "Add STA ID %d: %pM\n", index, addr); - station = &priv->stations_39[index]; - station->used = 1; - priv->num_stations++; - - /* Set up the REPLY_ADD_STA command to send to device */ - memset(&station->sta, 0, sizeof(struct iwl3945_addsta_cmd)); - memcpy(station->sta.sta.addr, addr, ETH_ALEN); - station->sta.mode = 0; - station->sta.sta.sta_id = index; - station->sta.station_flags = 0; - - if (priv->band == IEEE80211_BAND_5GHZ) - rate = IWL_RATE_6M_PLCP; - else - rate = IWL_RATE_1M_PLCP; - - /* Turn on both antennas for the station... */ - station->sta.rate_n_flags = - iwl3945_hw_set_rate_n_flags(rate, RATE_MCS_ANT_AB_MSK); - - spin_unlock_irqrestore(&priv->sta_lock, flags_spin); - - /* Add station to device's station table */ - iwl_send_add_sta(priv, - (struct iwl_addsta_cmd *)&station->sta, flags); - return index; - -} - -static int iwl3945_send_rxon_assoc(struct iwl_priv *priv) -{ - int rc = 0; - struct iwl_rx_packet *res = NULL; - struct iwl3945_rxon_assoc_cmd rxon_assoc; - struct iwl_host_cmd cmd = { - .id = REPLY_RXON_ASSOC, - .len = sizeof(rxon_assoc), - .meta.flags = CMD_WANT_SKB, - .data = &rxon_assoc, - }; - const struct iwl_rxon_cmd *rxon1 = &priv->staging_rxon; - const struct iwl_rxon_cmd *rxon2 = &priv->active_rxon; - - if ((rxon1->flags == rxon2->flags) && - (rxon1->filter_flags == rxon2->filter_flags) && - (rxon1->cck_basic_rates == rxon2->cck_basic_rates) && - (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) { - IWL_DEBUG_INFO(priv, "Using current RXON_ASSOC. Not resending.\n"); - return 0; - } - - rxon_assoc.flags = priv->staging_rxon.flags; - rxon_assoc.filter_flags = priv->staging_rxon.filter_flags; - rxon_assoc.ofdm_basic_rates = priv->staging_rxon.ofdm_basic_rates; - rxon_assoc.cck_basic_rates = priv->staging_rxon.cck_basic_rates; - rxon_assoc.reserved = 0; - - rc = iwl_send_cmd_sync(priv, &cmd); - if (rc) - return rc; - - res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; - if (res->hdr.flags & IWL_CMD_FAILED_MSK) { - IWL_ERR(priv, "Bad return from REPLY_RXON_ASSOC command\n"); - rc = -EIO; - } - - priv->alloc_rxb_skb--; - dev_kfree_skb_any(cmd.meta.u.skb); - - return rc; -} - /** * iwl3945_get_antenna_flags - Get antenna flags for RXON command * @priv: eeprom and antenna fields are used to determine antenna flags @@ -314,150 +132,6 @@ __le32 iwl3945_get_antenna_flags(const struct iwl_priv *priv) return 0; /* "diversity" is default if error */ } -/** - * iwl3945_commit_rxon - commit staging_rxon to hardware - * - * The RXON command in staging_rxon is committed to the hardware and - * the active_rxon structure is updated with the new data. This - * function correctly transitions out of the RXON_ASSOC_MSK state if - * a HW tune is required based on the RXON structure changes. - */ -static int iwl3945_commit_rxon(struct iwl_priv *priv) -{ - /* cast away the const for active_rxon in this function */ - struct iwl3945_rxon_cmd *active_rxon = (void *)&priv->active_rxon; - struct iwl3945_rxon_cmd *staging_rxon = (void *)&priv->staging_rxon; - int rc = 0; - bool new_assoc = - !!(priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK); - - if (!iwl_is_alive(priv)) - return -1; - - /* always get timestamp with Rx frame */ - staging_rxon->flags |= RXON_FLG_TSF2HOST_MSK; - - /* select antenna */ - staging_rxon->flags &= - ~(RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_SEL_MSK); - staging_rxon->flags |= iwl3945_get_antenna_flags(priv); - - rc = iwl_check_rxon_cmd(priv); - if (rc) { - IWL_ERR(priv, "Invalid RXON configuration. Not committing.\n"); - return -EINVAL; - } - - /* If we don't need to send a full RXON, we can use - * iwl3945_rxon_assoc_cmd which is used to reconfigure filter - * and other flags for the current radio configuration. */ - if (!iwl_full_rxon_required(priv)) { - rc = iwl3945_send_rxon_assoc(priv); - if (rc) { - IWL_ERR(priv, "Error setting RXON_ASSOC " - "configuration (%d).\n", rc); - return rc; - } - - memcpy(active_rxon, staging_rxon, sizeof(*active_rxon)); - - return 0; - } - - /* If we are currently associated and the new config requires - * an RXON_ASSOC and the new config wants the associated mask enabled, - * we must clear the associated from the active configuration - * before we apply the new config */ - if (iwl_is_associated(priv) && new_assoc) { - IWL_DEBUG_INFO(priv, "Toggling associated bit on current RXON\n"); - active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK; - - /* - * reserved4 and 5 could have been filled by the iwlcore code. - * Let's clear them before pushing to the 3945. - */ - active_rxon->reserved4 = 0; - active_rxon->reserved5 = 0; - rc = iwl_send_cmd_pdu(priv, REPLY_RXON, - sizeof(struct iwl3945_rxon_cmd), - &priv->active_rxon); - - /* If the mask clearing failed then we set - * active_rxon back to what it was previously */ - if (rc) { - active_rxon->filter_flags |= RXON_FILTER_ASSOC_MSK; - IWL_ERR(priv, "Error clearing ASSOC_MSK on current " - "configuration (%d).\n", rc); - return rc; - } - } - - IWL_DEBUG_INFO(priv, "Sending RXON\n" - "* with%s RXON_FILTER_ASSOC_MSK\n" - "* channel = %d\n" - "* bssid = %pM\n", - (new_assoc ? "" : "out"), - le16_to_cpu(staging_rxon->channel), - staging_rxon->bssid_addr); - - /* - * reserved4 and 5 could have been filled by the iwlcore code. - * Let's clear them before pushing to the 3945. - */ - staging_rxon->reserved4 = 0; - staging_rxon->reserved5 = 0; - - iwl_set_rxon_hwcrypto(priv, !priv->hw_params.sw_crypto); - - /* Apply the new configuration */ - rc = iwl_send_cmd_pdu(priv, REPLY_RXON, - sizeof(struct iwl3945_rxon_cmd), - staging_rxon); - if (rc) { - IWL_ERR(priv, "Error setting new configuration (%d).\n", rc); - return rc; - } - - memcpy(active_rxon, staging_rxon, sizeof(*active_rxon)); - - iwl3945_clear_stations_table(priv); - - /* If we issue a new RXON command which required a tune then we must - * send a new TXPOWER command or we won't be able to Tx any frames */ - rc = priv->cfg->ops->lib->send_tx_power(priv); - if (rc) { - IWL_ERR(priv, "Error setting Tx power (%d).\n", rc); - return rc; - } - - /* Add the broadcast address so we can send broadcast frames */ - if (iwl3945_add_station(priv, iwl_bcast_addr, 0, 0) == - IWL_INVALID_STATION) { - IWL_ERR(priv, "Error adding BROADCAST address for transmit.\n"); - return -EIO; - } - - /* If we have set the ASSOC_MSK and we are in BSS mode then - * add the IWL_AP_ID to the station rate table */ - if (iwl_is_associated(priv) && - (priv->iw_mode == NL80211_IFTYPE_STATION)) - if (iwl3945_add_station(priv, priv->active_rxon.bssid_addr, - 1, 0) - == IWL_INVALID_STATION) { - IWL_ERR(priv, "Error adding AP address for transmit\n"); - return -EIO; - } - - /* Init the hardware's rate fallback order based on the band */ - rc = iwl3945_init_hw_rate_table(priv); - if (rc) { - IWL_ERR(priv, "Error setting HW rate table: %02X\n", rc); - return -EIO; - } - - return 0; -} - static int iwl3945_set_ccmp_dynamic_key_info(struct iwl_priv *priv, struct ieee80211_key_conf *keyconf, u8 sta_id) @@ -477,32 +151,31 @@ static int iwl3945_set_ccmp_dynamic_key_info(struct iwl_priv *priv, key_flags &= ~STA_KEY_FLG_INVALID; spin_lock_irqsave(&priv->sta_lock, flags); - priv->stations_39[sta_id].keyinfo.alg = keyconf->alg; - priv->stations_39[sta_id].keyinfo.keylen = keyconf->keylen; - memcpy(priv->stations_39[sta_id].keyinfo.key, keyconf->key, + priv->stations[sta_id].keyinfo.alg = keyconf->alg; + priv->stations[sta_id].keyinfo.keylen = keyconf->keylen; + memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key, keyconf->keylen); - memcpy(priv->stations_39[sta_id].sta.key.key, keyconf->key, + memcpy(priv->stations[sta_id].sta.key.key, keyconf->key, keyconf->keylen); - if ((priv->stations_39[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK) + if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK) == STA_KEY_FLG_NO_ENC) - priv->stations_39[sta_id].sta.key.key_offset = + priv->stations[sta_id].sta.key.key_offset = iwl_get_free_ucode_key_index(priv); /* else, we are overriding an existing key => no need to allocated room * in uCode. */ - WARN(priv->stations_39[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET, + WARN(priv->stations[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET, "no space for a new key"); - priv->stations_39[sta_id].sta.key.key_flags = key_flags; - priv->stations_39[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; - priv->stations_39[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + priv->stations[sta_id].sta.key.key_flags = key_flags; + priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; IWL_DEBUG_INFO(priv, "hwcrypto: modify ucode station key info\n"); - ret = iwl_send_add_sta(priv, - (struct iwl_addsta_cmd *)&priv->stations_39[sta_id].sta, CMD_ASYNC); + ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); spin_unlock_irqrestore(&priv->sta_lock, flags); @@ -528,17 +201,16 @@ static int iwl3945_clear_sta_key_info(struct iwl_priv *priv, u8 sta_id) unsigned long flags; spin_lock_irqsave(&priv->sta_lock, flags); - memset(&priv->stations_39[sta_id].keyinfo, 0, sizeof(struct iwl3945_hw_key)); - memset(&priv->stations_39[sta_id].sta.key, 0, + memset(&priv->stations[sta_id].keyinfo, 0, sizeof(struct iwl_hw_key)); + memset(&priv->stations[sta_id].sta.key, 0, sizeof(struct iwl4965_keyinfo)); - priv->stations_39[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC; - priv->stations_39[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; - priv->stations_39[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + priv->stations[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC; + priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; spin_unlock_irqrestore(&priv->sta_lock, flags); IWL_DEBUG_INFO(priv, "hwcrypto: clear ucode station key info\n"); - iwl_send_add_sta(priv, - (struct iwl_addsta_cmd *)&priv->stations_39[sta_id].sta, 0); + iwl_send_add_sta(priv, &priv->stations[sta_id].sta, 0); return 0; } @@ -739,7 +411,8 @@ static void iwl3945_setup_rxon_timing(struct iwl_priv *priv) priv->rxon_timing.atim_window = 0; } else { priv->rxon_timing.beacon_interval = - iwl3945_adjust_beacon_interval(conf->beacon_int); + iwl3945_adjust_beacon_interval( + priv->vif->bss_conf.beacon_int); /* TODO: we need to get atim_window from upper stack * for now we set to 0 */ priv->rxon_timing.atim_window = 0; @@ -758,35 +431,6 @@ static void iwl3945_setup_rxon_timing(struct iwl_priv *priv) le16_to_cpu(priv->rxon_timing.atim_window)); } -static int iwl3945_set_mode(struct iwl_priv *priv, int mode) -{ - if (mode == NL80211_IFTYPE_ADHOC) { - const struct iwl_channel_info *ch_info; - - ch_info = iwl_get_channel_info(priv, - priv->band, - le16_to_cpu(priv->staging_rxon.channel)); - - if (!ch_info || !is_channel_ibss(ch_info)) { - IWL_ERR(priv, "channel %d not IBSS channel\n", - le16_to_cpu(priv->staging_rxon.channel)); - return -EINVAL; - } - } - - iwl_connection_init_rx_config(priv, mode); - - iwl3945_clear_stations_table(priv); - - /* don't commit rxon if rf-kill is on*/ - if (!iwl_is_ready_rf(priv)) - return -EAGAIN; - - iwl3945_commit_rxon(priv); - - return 0; -} - static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv, struct ieee80211_tx_info *info, struct iwl_cmd *cmd, @@ -794,8 +438,7 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv, int sta_id) { struct iwl3945_tx_cmd *tx = (struct iwl3945_tx_cmd *)cmd->cmd.payload; - struct iwl3945_hw_key *keyinfo = - &priv->stations_39[sta_id].keyinfo; + struct iwl_hw_key *keyinfo = &priv->stations[sta_id].keyinfo; switch (keyinfo->alg) { case ALG_CCMP: @@ -893,64 +536,6 @@ static void iwl3945_build_tx_cmd_basic(struct iwl_priv *priv, tx->next_frame_len = 0; } -/** - * iwl3945_get_sta_id - Find station's index within station table - */ -static int iwl3945_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) -{ - int sta_id; - u16 fc = le16_to_cpu(hdr->frame_control); - - /* If this frame is broadcast or management, use broadcast station id */ - if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) || - is_multicast_ether_addr(hdr->addr1)) - return priv->hw_params.bcast_sta_id; - - switch (priv->iw_mode) { - - /* If we are a client station in a BSS network, use the special - * AP station entry (that's the only station we communicate with) */ - case NL80211_IFTYPE_STATION: - return IWL_AP_ID; - - /* If we are an AP, then find the station, or use BCAST */ - case NL80211_IFTYPE_AP: - sta_id = iwl3945_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 NL80211_IFTYPE_ADHOC: { - /* Create new station table entry */ - sta_id = iwl3945_hw_find_station(priv, hdr->addr1); - if (sta_id != IWL_INVALID_STATION) - return sta_id; - - sta_id = iwl3945_add_station(priv, hdr->addr1, 0, CMD_ASYNC); - - if (sta_id != IWL_INVALID_STATION) - return sta_id; - - IWL_DEBUG_DROP(priv, "Station %pM not in station map. " - "Defaulting to broadcast...\n", - hdr->addr1); - iwl_print_hex_dump(priv, IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr)); - return priv->hw_params.bcast_sta_id; - } - /* If we are in monitor mode, use BCAST. This is required for - * packet injection. */ - case NL80211_IFTYPE_MONITOR: - return priv->hw_params.bcast_sta_id; - - default: - IWL_WARN(priv, "Unknown mode of operation: %d\n", - priv->iw_mode); - return priv->hw_params.bcast_sta_id; - } -} - /* * start REPLY_TX command process */ @@ -1004,7 +589,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) /* drop all data frame if we are not associated */ if (ieee80211_is_data(fc) && - (priv->iw_mode != NL80211_IFTYPE_MONITOR) && /* packet injection */ + (!iwl_is_monitor_mode(priv)) && /* packet injection */ (!iwl_is_associated(priv) || ((priv->iw_mode == NL80211_IFTYPE_STATION) && !priv->assoc_id))) { IWL_DEBUG_DROP(priv, "Dropping - !iwl_is_associated\n"); @@ -1016,7 +601,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) hdr_len = ieee80211_hdrlen(fc); /* Find (or create) index into station table for destination station */ - sta_id = iwl3945_get_sta_id(priv, hdr); + sta_id = iwl_get_sta_id(priv, hdr); if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n", hdr->addr1); @@ -1028,7 +613,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) if (ieee80211_is_data_qos(fc)) { qc = ieee80211_get_qos_ctl(hdr); tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; - seq_number = priv->stations_39[sta_id].tid[tid].seq_number & + seq_number = priv->stations[sta_id].tid[tid].seq_number & IEEE80211_SCTL_SEQ; hdr->seq_ctrl = cpu_to_le16(seq_number) | (hdr->seq_ctrl & @@ -1088,7 +673,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) if (!ieee80211_has_morefrags(hdr->frame_control)) { txq->need_update = 1; if (qc) - priv->stations_39[sta_id].tid[tid].seq_number = seq_number; + priv->stations[sta_id].tid[tid].seq_number = seq_number; } else { wait_write_ptr = 1; txq->need_update = 0; @@ -1424,18 +1009,12 @@ static void iwl3945_rx_card_state_notif(struct iwl_priv *priv, clear_bit(STATUS_RF_KILL_HW, &priv->status); - if (flags & SW_CARD_DISABLED) - set_bit(STATUS_RF_KILL_SW, &priv->status); - else - clear_bit(STATUS_RF_KILL_SW, &priv->status); - iwl_scan_cancel(priv); if ((test_bit(STATUS_RF_KILL_HW, &status) != - test_bit(STATUS_RF_KILL_HW, &priv->status)) || - (test_bit(STATUS_RF_KILL_SW, &status) != - test_bit(STATUS_RF_KILL_SW, &priv->status))) - queue_work(priv->workqueue, &priv->rf_kill); + test_bit(STATUS_RF_KILL_HW, &priv->status))) + wiphy_rfkill_set_hw_state(priv->hw->wiphy, + test_bit(STATUS_RF_KILL_HW, &priv->status)); else wake_up_interruptible(&priv->wait_command_queue); } @@ -1591,7 +1170,7 @@ static int iwl3945_rx_queue_restock(struct iwl_priv *priv) /* If we've added more space for the firmware to place data, tell it. * Increment device's write pointer in multiples of 8. */ - if ((write != (rxq->write & ~0x7)) + if ((rxq->write_actual != (rxq->write & ~0x7)) || (abs(rxq->write - rxq->read) > 7)) { spin_lock_irqsave(&rxq->lock, flags); rxq->need_update = 1; @@ -1612,21 +1191,30 @@ static int iwl3945_rx_queue_restock(struct iwl_priv *priv) * Also restock the Rx queue via iwl3945_rx_queue_restock. * This is called as a scheduled work item (except for during initialization) */ -static void iwl3945_rx_allocate(struct iwl_priv *priv) +static void iwl3945_rx_allocate(struct iwl_priv *priv, gfp_t priority) { struct iwl_rx_queue *rxq = &priv->rxq; struct list_head *element; struct iwl_rx_mem_buffer *rxb; unsigned long flags; - spin_lock_irqsave(&rxq->lock, flags); - while (!list_empty(&rxq->rx_used)) { + + while (1) { + spin_lock_irqsave(&rxq->lock, flags); + + if (list_empty(&rxq->rx_used)) { + spin_unlock_irqrestore(&rxq->lock, flags); + return; + } + element = rxq->rx_used.next; rxb = list_entry(element, struct iwl_rx_mem_buffer, list); + list_del(element); + spin_unlock_irqrestore(&rxq->lock, flags); /* Alloc a new receive buffer */ rxb->skb = alloc_skb(priv->hw_params.rx_buf_size, - __GFP_NOWARN | GFP_ATOMIC); + priority); if (!rxb->skb) { if (net_ratelimit()) IWL_CRIT(priv, ": Can not allocate SKB buffers\n"); @@ -1644,18 +1232,18 @@ static void iwl3945_rx_allocate(struct iwl_priv *priv) */ skb_reserve(rxb->skb, 4); - priv->alloc_rxb_skb++; - list_del(element); - /* Get physical address of RB/SKB */ rxb->real_dma_addr = pci_map_single(priv->pci_dev, rxb->skb->data, priv->hw_params.rx_buf_size, PCI_DMA_FROMDEVICE); + + spin_lock_irqsave(&rxq->lock, flags); list_add_tail(&rxb->list, &rxq->rx_free); + priv->alloc_rxb_skb++; rxq->free_count++; + spin_unlock_irqrestore(&rxq->lock, flags); } - spin_unlock_irqrestore(&rxq->lock, flags); } void iwl3945_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq) @@ -1685,33 +1273,30 @@ void iwl3945_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq) * not restocked the Rx queue with fresh buffers */ rxq->read = rxq->write = 0; rxq->free_count = 0; + rxq->write_actual = 0; spin_unlock_irqrestore(&rxq->lock, flags); } -/* - * this should be called while priv->lock is locked - */ -static void __iwl3945_rx_replenish(void *data) -{ - struct iwl_priv *priv = data; - - iwl3945_rx_allocate(priv); - iwl3945_rx_queue_restock(priv); -} - - void iwl3945_rx_replenish(void *data) { struct iwl_priv *priv = data; unsigned long flags; - iwl3945_rx_allocate(priv); + iwl3945_rx_allocate(priv, GFP_KERNEL); spin_lock_irqsave(&priv->lock, flags); iwl3945_rx_queue_restock(priv); spin_unlock_irqrestore(&priv->lock, flags); } +static void iwl3945_rx_replenish_now(struct iwl_priv *priv) +{ + iwl3945_rx_allocate(priv, GFP_ATOMIC); + + iwl3945_rx_queue_restock(priv); +} + + /* Assumes that the skb field of the buffers in 'pool' is kept accurate. * If an SKB has been detached, the POOL needs to have its SKB set to NULL * This free routine walks the list of POOL entries and if SKB is set to @@ -1834,13 +1419,19 @@ static void iwl3945_rx_handle(struct iwl_priv *priv) unsigned long flags; u8 fill_rx = 0; u32 count = 8; + int total_empty = 0; /* uCode's read index (stored in shared DRAM) indicates the last Rx * buffer that the driver may process (last buffer filled by ucode). */ r = le16_to_cpu(rxq->rb_stts->closed_rb_num) & 0x0FFF; i = rxq->read; - if (iwl_rx_queue_space(rxq) > (RX_QUEUE_SIZE / 2)) + /* calculate total frames need to be restock after handling RX */ + total_empty = r - priv->rxq.write_actual; + if (total_empty < 0) + total_empty += RX_QUEUE_SIZE; + + if (total_empty > (RX_QUEUE_SIZE / 2)) fill_rx = 1; /* Rx interrupt, but nothing sent from uCode */ if (i == r) @@ -1879,6 +1470,7 @@ static void iwl3945_rx_handle(struct iwl_priv *priv) "r = %d, i = %d, %s, 0x%02x\n", r, i, get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd); priv->rx_handlers[pkt->hdr.cmd] (priv, rxb); + priv->isr_stats.rx_handlers[pkt->hdr.cmd]++; } else { /* No handling needed */ IWL_DEBUG(priv, IWL_DL_HCMD | IWL_DL_RX | IWL_DL_ISR, @@ -1916,7 +1508,7 @@ static void iwl3945_rx_handle(struct iwl_priv *priv) count++; if (count >= 8) { priv->rxq.read = i; - __iwl3945_rx_replenish(priv); + iwl3945_rx_replenish_now(priv); count = 0; } } @@ -1924,7 +1516,10 @@ static void iwl3945_rx_handle(struct iwl_priv *priv) /* Backtrack one entry */ priv->rxq.read = i; - iwl3945_rx_queue_restock(priv); + if (fill_rx) + iwl3945_rx_replenish_now(priv); + else + iwl3945_rx_queue_restock(priv); } /* call this function to flush any scheduled tasklet */ @@ -1963,7 +1558,6 @@ static void iwl3945_dump_nic_error_log(struct iwl_priv *priv) u32 i; u32 desc, time, count, base, data1; u32 blink1, blink2, ilink1, ilink2; - int rc; base = le32_to_cpu(priv->card_alive.error_event_table_ptr); @@ -1972,11 +1566,6 @@ static void iwl3945_dump_nic_error_log(struct iwl_priv *priv) return; } - rc = iwl_grab_nic_access(priv); - if (rc) { - IWL_WARN(priv, "Can not read from adapter at this time.\n"); - return; - } count = iwl_read_targ_mem(priv, base); @@ -2011,8 +1600,6 @@ static void iwl3945_dump_nic_error_log(struct iwl_priv *priv) ilink1, ilink2, data1); } - iwl_release_nic_access(priv); - } #define EVENT_START_OFFSET (6 * sizeof(u32)) @@ -2020,7 +1607,6 @@ static void iwl3945_dump_nic_error_log(struct iwl_priv *priv) /** * iwl3945_print_event_log - Dump error event log to syslog * - * NOTE: Must be called with iwl_grab_nic_access() already obtained! */ static void iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx, u32 num_events, u32 mode) @@ -2063,7 +1649,6 @@ static void iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx, static void iwl3945_dump_nic_event_log(struct iwl_priv *priv) { - int rc; u32 base; /* SRAM byte address of event log header */ u32 capacity; /* event log capacity in # entries */ u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */ @@ -2077,12 +1662,6 @@ static void iwl3945_dump_nic_event_log(struct iwl_priv *priv) return; } - rc = iwl_grab_nic_access(priv); - if (rc) { - IWL_WARN(priv, "Can not read from adapter at this time.\n"); - return; - } - /* event log header */ capacity = iwl_read_targ_mem(priv, base); mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32))); @@ -2094,7 +1673,6 @@ static void iwl3945_dump_nic_event_log(struct iwl_priv *priv) /* bail out if nothing in log */ if (size == 0) { IWL_ERR(priv, "Start IWL Event Log Dump: nothing in log\n"); - iwl_release_nic_access(priv); return; } @@ -2110,24 +1688,6 @@ static void iwl3945_dump_nic_event_log(struct iwl_priv *priv) /* (then/else) start at top of log */ iwl3945_print_event_log(priv, 0, next_entry, mode); - iwl_release_nic_access(priv); -} - -static void iwl3945_error_recovery(struct iwl_priv *priv) -{ - unsigned long flags; - - memcpy(&priv->staging_rxon, &priv->recovery_rxon, - sizeof(priv->staging_rxon)); - priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl3945_commit_rxon(priv); - - iwl3945_add_station(priv, priv->bssid, 1, 0); - - spin_lock_irqsave(&priv->lock, flags); - priv->assoc_id = le16_to_cpu(priv->staging_rxon.assoc_id); - priv->error_recovering = 0; - spin_unlock_irqrestore(&priv->lock, flags); } static void iwl3945_irq_tasklet(struct iwl_priv *priv) @@ -2178,6 +1738,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv) /* Tell the device to stop sending interrupts */ iwl_disable_interrupts(priv); + priv->isr_stats.hw++; iwl_irq_handle_error(priv); handled |= CSR_INT_BIT_HW_ERR; @@ -2190,13 +1751,17 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv) #ifdef CONFIG_IWLWIFI_DEBUG if (priv->debug_level & (IWL_DL_ISR)) { /* NIC fires this, but we don't use it, redundant with WAKEUP */ - if (inta & CSR_INT_BIT_SCD) + if (inta & CSR_INT_BIT_SCD) { IWL_DEBUG_ISR(priv, "Scheduler finished to transmit " "the frame/frames.\n"); + priv->isr_stats.sch++; + } /* Alive notification via Rx interrupt will do the real work */ - if (inta & CSR_INT_BIT_ALIVE) + if (inta & CSR_INT_BIT_ALIVE) { IWL_DEBUG_ISR(priv, "Alive interrupt\n"); + priv->isr_stats.alive++; + } } #endif /* Safely ignore these bits for debug checks below */ @@ -2206,6 +1771,8 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv) if (inta & CSR_INT_BIT_SW_ERR) { IWL_ERR(priv, "Microcode SW error detected. " "Restarting 0x%X.\n", inta); + priv->isr_stats.sw++; + priv->isr_stats.sw_err = inta; iwl_irq_handle_error(priv); handled |= CSR_INT_BIT_SW_ERR; } @@ -2221,6 +1788,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv) iwl_txq_update_write_ptr(priv, &priv->txq[4]); iwl_txq_update_write_ptr(priv, &priv->txq[5]); + priv->isr_stats.wakeup++; handled |= CSR_INT_BIT_WAKEUP; } @@ -2229,27 +1797,28 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv) * notifications from uCode come through here*/ if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) { iwl3945_rx_handle(priv); + priv->isr_stats.rx++; handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX); } if (inta & CSR_INT_BIT_FH_TX) { IWL_DEBUG_ISR(priv, "Tx interrupt\n"); + priv->isr_stats.tx++; iwl_write32(priv, CSR_FH_INT_STATUS, (1 << 6)); - if (!iwl_grab_nic_access(priv)) { - iwl_write_direct32(priv, FH39_TCSR_CREDIT - (FH39_SRVC_CHNL), 0x0); - iwl_release_nic_access(priv); - } + iwl_write_direct32(priv, FH39_TCSR_CREDIT + (FH39_SRVC_CHNL), 0x0); handled |= CSR_INT_BIT_FH_TX; } - if (inta & ~handled) + if (inta & ~handled) { IWL_ERR(priv, "Unhandled INTA bits 0x%08x\n", inta & ~handled); + priv->isr_stats.unhandled++; + } - if (inta & ~CSR_INI_SET_MASK) { + if (inta & ~priv->inta_mask) { IWL_WARN(priv, "Disabled INTA bits 0x%08x were pending\n", - inta & ~CSR_INI_SET_MASK); + inta & ~priv->inta_mask); IWL_WARN(priv, " with FH_INT = 0x%08x\n", inta_fh); } @@ -2413,10 +1982,6 @@ static int iwl3945_verify_inst_full(struct iwl_priv *priv, __le32 *image, u32 le IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len); - rc = iwl_grab_nic_access(priv); - if (rc) - return rc; - iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, IWL39_RTC_INST_LOWER_BOUND); @@ -2437,7 +2002,6 @@ static int iwl3945_verify_inst_full(struct iwl_priv *priv, __le32 *image, u32 le } } - iwl_release_nic_access(priv); if (!errcnt) IWL_DEBUG_INFO(priv, @@ -2461,10 +2025,6 @@ static int iwl3945_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len); - rc = iwl_grab_nic_access(priv); - if (rc) - return rc; - for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) { /* read data comes through single port, auto-incr addr */ /* NOTE: Use the debugless read so we don't flood kernel log @@ -2485,8 +2045,6 @@ static int iwl3945_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 } } - iwl_release_nic_access(priv); - return rc; } @@ -2810,20 +2368,11 @@ static int iwl3945_set_ucode_ptrs(struct iwl_priv *priv) { dma_addr_t pinst; dma_addr_t pdata; - int rc = 0; - unsigned long flags; /* bits 31:0 for 3945 */ pinst = priv->ucode_code.p_addr; pdata = priv->ucode_data_backup.p_addr; - spin_lock_irqsave(&priv->lock, flags); - rc = iwl_grab_nic_access(priv); - if (rc) { - spin_unlock_irqrestore(&priv->lock, flags); - return rc; - } - /* Tell bootstrap uCode where to find image to load */ iwl_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst); iwl_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata); @@ -2835,13 +2384,9 @@ static int iwl3945_set_ucode_ptrs(struct iwl_priv *priv) iwl_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, priv->ucode_code.len | BSM_DRAM_INST_LOAD); - iwl_release_nic_access(priv); - - spin_unlock_irqrestore(&priv->lock, flags); - IWL_DEBUG_INFO(priv, "Runtime uCode pointers are set.\n"); - return rc; + return 0; } /** @@ -2887,11 +2432,6 @@ static void iwl3945_init_alive_start(struct iwl_priv *priv) queue_work(priv->workqueue, &priv->restart); } - -/* temporary */ -static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, - struct sk_buff *skb); - /** * iwl3945_alive_start - called after REPLY_ALIVE notification received * from protocol/runtime uCode (initialization uCode's @@ -2899,7 +2439,6 @@ static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, */ static void iwl3945_alive_start(struct iwl_priv *priv) { - int rc = 0; int thermal_spin = 0; u32 rfkill; @@ -2922,17 +2461,10 @@ static void iwl3945_alive_start(struct iwl_priv *priv) goto restart; } - iwl3945_clear_stations_table(priv); - - rc = iwl_grab_nic_access(priv); - if (rc) { - IWL_WARN(priv, "Can not read RFKILL status from adapter\n"); - return; - } + iwl_clear_stations_table(priv); rfkill = iwl_read_prph(priv, APMG_RFKILL_REG); IWL_DEBUG_INFO(priv, "RFKILL status: 0x%x\n", rfkill); - iwl_release_nic_access(priv); if (rfkill & 0x1) { clear_bit(STATUS_RF_KILL_HW, &priv->status); @@ -2952,9 +2484,6 @@ static void iwl3945_alive_start(struct iwl_priv *priv) /* After the ALIVE response, we can send commands to 3945 uCode */ set_bit(STATUS_ALIVE, &priv->status); - /* Clear out the uCode error bit if it is set */ - clear_bit(STATUS_FW_ERROR, &priv->status); - if (iwl_is_rfkill(priv)) return; @@ -2969,8 +2498,7 @@ static void iwl3945_alive_start(struct iwl_priv *priv) struct iwl3945_rxon_cmd *active_rxon = (struct iwl3945_rxon_cmd *)(&priv->active_rxon); - memcpy(&priv->staging_rxon, &priv->active_rxon, - sizeof(priv->staging_rxon)); + priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK; } else { /* Initialize our rx_config data */ @@ -2981,7 +2509,7 @@ static void iwl3945_alive_start(struct iwl_priv *priv) iwl_send_bt_config(priv); /* Configure the adapter for unassociated operation */ - iwl3945_commit_rxon(priv); + iwlcore_commit_rxon(priv); iwl3945_reg_txpower_periodic(priv); @@ -2991,17 +2519,17 @@ static void iwl3945_alive_start(struct iwl_priv *priv) set_bit(STATUS_READY, &priv->status); wake_up_interruptible(&priv->wait_command_queue); - if (priv->error_recovering) - iwl3945_error_recovery(priv); - /* reassociate for ADHOC mode */ if (priv->vif && (priv->iw_mode == NL80211_IFTYPE_ADHOC)) { struct sk_buff *beacon = ieee80211_beacon_get(priv->hw, priv->vif); if (beacon) - iwl3945_mac_beacon_update(priv->hw, beacon); + iwl_mac_beacon_update(priv->hw, beacon); } + if (test_and_clear_bit(STATUS_MODE_PENDING, &priv->status)) + iwl_set_mode(priv, priv->iw_mode); + return; restart: @@ -3024,7 +2552,7 @@ static void __iwl3945_down(struct iwl_priv *priv) set_bit(STATUS_EXIT_PENDING, &priv->status); iwl3945_led_unregister(priv); - iwl3945_clear_stations_table(priv); + iwl_clear_stations_table(priv); /* Unblock any waiting calls */ wake_up_interruptible_all(&priv->wait_command_queue); @@ -3047,31 +2575,23 @@ static void __iwl3945_down(struct iwl_priv *priv) ieee80211_stop_queues(priv->hw); /* If we have not previously called iwl3945_init() then - * clear all bits but the RF Kill and SUSPEND bits and return */ + * clear all bits but the RF Kill bits and return */ if (!iwl_is_init(priv)) { priv->status = test_bit(STATUS_RF_KILL_HW, &priv->status) << STATUS_RF_KILL_HW | - test_bit(STATUS_RF_KILL_SW, &priv->status) << - STATUS_RF_KILL_SW | test_bit(STATUS_GEO_CONFIGURED, &priv->status) << STATUS_GEO_CONFIGURED | - test_bit(STATUS_IN_SUSPEND, &priv->status) << - STATUS_IN_SUSPEND | test_bit(STATUS_EXIT_PENDING, &priv->status) << STATUS_EXIT_PENDING; goto exit; } - /* ...otherwise clear out all the status bits but the RF Kill and - * SUSPEND bits and continue taking the NIC down. */ + /* ...otherwise clear out all the status bits but the RF Kill + * bit and continue taking the NIC down. */ priv->status &= test_bit(STATUS_RF_KILL_HW, &priv->status) << STATUS_RF_KILL_HW | - test_bit(STATUS_RF_KILL_SW, &priv->status) << - STATUS_RF_KILL_SW | test_bit(STATUS_GEO_CONFIGURED, &priv->status) << STATUS_GEO_CONFIGURED | - test_bit(STATUS_IN_SUSPEND, &priv->status) << - STATUS_IN_SUSPEND | test_bit(STATUS_FW_ERROR, &priv->status) << STATUS_FW_ERROR | test_bit(STATUS_EXIT_PENDING, &priv->status) << @@ -3085,17 +2605,12 @@ static void __iwl3945_down(struct iwl_priv *priv) iwl3945_hw_txq_ctx_stop(priv); iwl3945_hw_rxq_stop(priv); - spin_lock_irqsave(&priv->lock, flags); - if (!iwl_grab_nic_access(priv)) { - iwl_write_prph(priv, APMG_CLK_DIS_REG, - APMG_CLK_VAL_DMA_CLK_RQT); - iwl_release_nic_access(priv); - } - spin_unlock_irqrestore(&priv->lock, flags); + iwl_write_prph(priv, APMG_CLK_DIS_REG, + APMG_CLK_VAL_DMA_CLK_RQT); udelay(5); - if (exit_pending || test_bit(STATUS_IN_SUSPEND, &priv->status)) + if (exit_pending) priv->cfg->ops->lib->apm_ops.stop(priv); else priv->cfg->ops->lib->apm_ops.reset(priv); @@ -3131,12 +2646,6 @@ static int __iwl3945_up(struct iwl_priv *priv) return -EIO; } - if (test_bit(STATUS_RF_KILL_SW, &priv->status)) { - IWL_WARN(priv, "Radio disabled by SW RF kill (module " - "parameter)\n"); - return -ENODEV; - } - if (!priv->ucode_data_backup.v_addr || !priv->ucode_data.v_addr) { IWL_ERR(priv, "ucode not available for device bring up\n"); return -EIO; @@ -3148,10 +2657,8 @@ static int __iwl3945_up(struct iwl_priv *priv) clear_bit(STATUS_RF_KILL_HW, &priv->status); else { set_bit(STATUS_RF_KILL_HW, &priv->status); - if (!test_bit(STATUS_IN_SUSPEND, &priv->status)) { - IWL_WARN(priv, "Radio disabled by HW RF Kill switch\n"); - return -ENODEV; - } + IWL_WARN(priv, "Radio disabled by HW RF Kill switch\n"); + return -ENODEV; } iwl_write32(priv, CSR_INT, 0xFFFFFFFF); @@ -3187,7 +2694,7 @@ static int __iwl3945_up(struct iwl_priv *priv) for (i = 0; i < MAX_HW_RESTARTS; i++) { - iwl3945_clear_stations_table(priv); + iwl_clear_stations_table(priv); /* load bootstrap state machine, * load bootstrap program into processor's memory, @@ -3255,15 +2762,14 @@ static void iwl3945_rfkill_poll(struct work_struct *data) { struct iwl_priv *priv = container_of(data, struct iwl_priv, rfkill_poll.work); - unsigned long status = priv->status; if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) clear_bit(STATUS_RF_KILL_HW, &priv->status); else set_bit(STATUS_RF_KILL_HW, &priv->status); - if (test_bit(STATUS_RF_KILL_HW, &status) != test_bit(STATUS_RF_KILL_HW, &priv->status)) - queue_work(priv->workqueue, &priv->rf_kill); + wiphy_rfkill_set_hw_state(priv->hw->wiphy, + test_bit(STATUS_RF_KILL_HW, &priv->status)); queue_delayed_work(priv->workqueue, &priv->rfkill_poll, round_jiffies_relative(2 * HZ)); @@ -3283,9 +2789,9 @@ static void iwl3945_bg_request_scan(struct work_struct *data) int rc = 0; struct iwl3945_scan_cmd *scan; struct ieee80211_conf *conf = NULL; - u8 n_probes = 2; + u8 n_probes = 0; enum ieee80211_band band; - DECLARE_SSID_BUF(ssid); + bool is_active = false; conf = ieee80211_get_hw_conf(priv->hw); @@ -3386,18 +2892,25 @@ static void iwl3945_bg_request_scan(struct work_struct *data) scan_suspend_time, interval); } - /* We should add the ability for user to lock to PASSIVE ONLY */ - if (priv->one_direct_scan) { - IWL_DEBUG_SCAN(priv, "Kicking off one direct scan for '%s'\n", - print_ssid(ssid, priv->direct_ssid, - priv->direct_ssid_len)); - scan->direct_scan[0].id = WLAN_EID_SSID; - scan->direct_scan[0].len = priv->direct_ssid_len; - memcpy(scan->direct_scan[0].ssid, - priv->direct_ssid, priv->direct_ssid_len); - n_probes++; + if (priv->scan_request->n_ssids) { + int i, p = 0; + IWL_DEBUG_SCAN(priv, "Kicking off active scan\n"); + for (i = 0; i < priv->scan_request->n_ssids; i++) { + /* always does wildcard anyway */ + if (!priv->scan_request->ssids[i].ssid_len) + continue; + scan->direct_scan[p].id = WLAN_EID_SSID; + scan->direct_scan[p].len = + priv->scan_request->ssids[i].ssid_len; + memcpy(scan->direct_scan[p].ssid, + priv->scan_request->ssids[i].ssid, + priv->scan_request->ssids[i].ssid_len); + n_probes++; + p++; + } + is_active = true; } else - IWL_DEBUG_SCAN(priv, "Kicking off one indirect scan.\n"); + IWL_DEBUG_SCAN(priv, "Kicking off passive scan.\n"); /* We don't build a direct scan probe request; the uCode will do * that based on the direct_mask added to each channel entry */ @@ -3414,7 +2927,12 @@ static void iwl3945_bg_request_scan(struct work_struct *data) band = IEEE80211_BAND_2GHZ; } else if (priv->scan_bands & BIT(IEEE80211_BAND_5GHZ)) { scan->tx_cmd.rate = IWL_RATE_6M_PLCP; - scan->good_CRC_th = IWL_GOOD_CRC_TH; + /* + * If active scaning is requested but a certain channel + * is marked passive, we can do active scanning if we + * detect transmissions. + */ + scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH : 0; band = IEEE80211_BAND_5GHZ; } else { IWL_WARN(priv, "Invalid scan band count\n"); @@ -3422,19 +2940,20 @@ static void iwl3945_bg_request_scan(struct work_struct *data) } scan->tx_cmd.len = cpu_to_le16( - iwl_fill_probe_req(priv, band, - (struct ieee80211_mgmt *)scan->data, - IWL_MAX_SCAN_SIZE - sizeof(*scan))); + iwl_fill_probe_req(priv, + (struct ieee80211_mgmt *)scan->data, + priv->scan_request->ie, + priv->scan_request->ie_len, + IWL_MAX_SCAN_SIZE - sizeof(*scan))); /* select Rx antennas */ scan->flags |= iwl3945_get_antenna_flags(priv); - if (priv->iw_mode == NL80211_IFTYPE_MONITOR) + if (iwl_is_monitor_mode(priv)) scan->filter_flags = RXON_FILTER_PROMISC_MSK; scan->channel_count = - iwl3945_get_channels_for_scan(priv, band, 1, /* active */ - n_probes, + iwl3945_get_channels_for_scan(priv, band, is_active, n_probes, (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]); if (scan->channel_count == 0) { @@ -3482,7 +3001,6 @@ static void iwl3945_bg_up(struct work_struct *data) mutex_lock(&priv->mutex); __iwl3945_up(priv); mutex_unlock(&priv->mutex); - iwl_rfkill_set_hw_state(priv); } static void iwl3945_bg_restart(struct work_struct *data) @@ -3492,8 +3010,17 @@ static void iwl3945_bg_restart(struct work_struct *data) if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; - iwl3945_down(priv); - queue_work(priv->workqueue, &priv->up); + if (test_and_clear_bit(STATUS_FW_ERROR, &priv->status)) { + mutex_lock(&priv->mutex); + priv->vif = NULL; + priv->is_open = 0; + mutex_unlock(&priv->mutex); + iwl3945_down(priv); + ieee80211_restart_hw(priv->hw); + } else { + iwl3945_down(priv); + queue_work(priv->workqueue, &priv->up); + } } static void iwl3945_bg_rx_replenish(struct work_struct *data) @@ -3511,7 +3038,7 @@ static void iwl3945_bg_rx_replenish(struct work_struct *data) #define IWL_DELAY_NEXT_SCAN (HZ*2) -static void iwl3945_post_associate(struct iwl_priv *priv) +void iwl3945_post_associate(struct iwl_priv *priv) { int rc = 0; struct ieee80211_conf *conf = NULL; @@ -3536,7 +3063,7 @@ static void iwl3945_post_associate(struct iwl_priv *priv) conf = ieee80211_get_hw_conf(priv->hw); priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl3945_commit_rxon(priv); + iwlcore_commit_rxon(priv); memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd)); iwl3945_setup_rxon_timing(priv); @@ -3569,7 +3096,7 @@ static void iwl3945_post_associate(struct iwl_priv *priv) } - iwl3945_commit_rxon(priv); + iwlcore_commit_rxon(priv); switch (priv->iw_mode) { case NL80211_IFTYPE_STATION: @@ -3579,7 +3106,7 @@ static void iwl3945_post_associate(struct iwl_priv *priv) case NL80211_IFTYPE_ADHOC: priv->assoc_id = 1; - iwl3945_add_station(priv, priv->bssid, 0, 0); + iwl_add_station(priv, priv->bssid, 0, CMD_SYNC, NULL); iwl3945_sync_sta(priv, IWL_STA_ID, (priv->band == IEEE80211_BAND_5GHZ) ? IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP, @@ -3601,8 +3128,6 @@ static void iwl3945_post_associate(struct iwl_priv *priv) priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN; } -static int iwl3945_mac_config(struct ieee80211_hw *hw, u32 changed); - /***************************************************************************** * * mac80211 entry point functions @@ -3621,7 +3146,6 @@ static int iwl3945_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(priv->staging_rxon)); /* fetch ucode file from disk, alloc and copy to bus-master buffers ... * ucode filename and max sizes are card-specific. */ @@ -3638,16 +3162,11 @@ static int iwl3945_mac_start(struct ieee80211_hw *hw) mutex_unlock(&priv->mutex); - iwl_rfkill_set_hw_state(priv); - if (ret) goto out_release_irq; IWL_DEBUG_INFO(priv, "Start UP work.\n"); - if (test_bit(STATUS_IN_SUSPEND, &priv->status)) - return 0; - /* Wait for START_ALIVE from ucode. Otherwise callbacks from * mac80211 will not be run successfully. */ ret = wait_event_interruptible_timeout(priv->wait_command_queue, @@ -3726,144 +3245,7 @@ static int iwl3945_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) return NETDEV_TX_OK; } -static int iwl3945_mac_add_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) -{ - struct iwl_priv *priv = hw->priv; - unsigned long flags; - - IWL_DEBUG_MAC80211(priv, "enter: type %d\n", conf->type); - - if (priv->vif) { - IWL_DEBUG_MAC80211(priv, "leave - vif != NULL\n"); - return -EOPNOTSUPP; - } - - spin_lock_irqsave(&priv->lock, flags); - priv->vif = conf->vif; - priv->iw_mode = conf->type; - - spin_unlock_irqrestore(&priv->lock, flags); - - mutex_lock(&priv->mutex); - - if (conf->mac_addr) { - IWL_DEBUG_MAC80211(priv, "Set: %pM\n", conf->mac_addr); - memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN); - } - - if (iwl_is_ready(priv)) - iwl3945_set_mode(priv, conf->type); - - mutex_unlock(&priv->mutex); - - IWL_DEBUG_MAC80211(priv, "leave\n"); - return 0; -} - -/** - * iwl3945_mac_config - mac80211 config callback - * - * We ignore conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME since it seems to - * be set inappropriately and the driver currently sets the hardware up to - * use it whenever needed. - */ -static int iwl3945_mac_config(struct ieee80211_hw *hw, u32 changed) -{ - struct iwl_priv *priv = hw->priv; - const struct iwl_channel_info *ch_info; - struct ieee80211_conf *conf = &hw->conf; - unsigned long flags; - int ret = 0; - - mutex_lock(&priv->mutex); - IWL_DEBUG_MAC80211(priv, "enter to channel %d\n", - conf->channel->hw_value); - - if (!iwl_is_ready(priv)) { - IWL_DEBUG_MAC80211(priv, "leave - not ready\n"); - ret = -EIO; - goto out; - } - - if (unlikely(!iwl3945_mod_params.disable_hw_scan && - test_bit(STATUS_SCANNING, &priv->status))) { - IWL_DEBUG_MAC80211(priv, "leave - scanning\n"); - set_bit(STATUS_CONF_PENDING, &priv->status); - mutex_unlock(&priv->mutex); - return 0; - } - - spin_lock_irqsave(&priv->lock, flags); - - ch_info = iwl_get_channel_info(priv, conf->channel->band, - conf->channel->hw_value); - if (!is_channel_valid(ch_info)) { - IWL_DEBUG_SCAN(priv, - "Channel %d [%d] is INVALID for this band.\n", - conf->channel->hw_value, conf->channel->band); - IWL_DEBUG_MAC80211(priv, "leave - invalid channel\n"); - spin_unlock_irqrestore(&priv->lock, flags); - ret = -EINVAL; - goto out; - } - - iwl_set_rxon_channel(priv, conf->channel); - - iwl_set_flags_for_band(priv, conf->channel->band); - - /* The list of supported rates and rate mask can be different - * for each phymode; since the phymode may have changed, reset - * the rate mask to what mac80211 lists */ - iwl_set_rate(priv); - - spin_unlock_irqrestore(&priv->lock, flags); - -#ifdef IEEE80211_CONF_CHANNEL_SWITCH - if (conf->flags & IEEE80211_CONF_CHANNEL_SWITCH) { - iwl3945_hw_channel_switch(priv, conf->channel); - goto out; - } -#endif - - if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED) { - if (conf->radio_enabled && - iwl_radio_kill_sw_enable_radio(priv)) { - IWL_DEBUG_MAC80211(priv, "leave - RF-KILL - " - "waiting for uCode\n"); - goto out; - } - - if (!conf->radio_enabled) { - iwl_radio_kill_sw_disable_radio(priv); - IWL_DEBUG_MAC80211(priv, "leave - radio disabled\n"); - goto out; - } - } - - if (iwl_is_rfkill(priv)) { - IWL_DEBUG_MAC80211(priv, "leave - RF kill\n"); - ret = -EIO; - goto out; - } - - iwl_set_rate(priv); - - if (memcmp(&priv->active_rxon, - &priv->staging_rxon, sizeof(priv->staging_rxon))) - iwl3945_commit_rxon(priv); - else - IWL_DEBUG_INFO(priv, "Not re-sending same RXON configuration\n"); - - IWL_DEBUG_MAC80211(priv, "leave\n"); - -out: - clear_bit(STATUS_CONF_PENDING, &priv->status); - mutex_unlock(&priv->mutex); - return ret; -} - -static void iwl3945_config_ap(struct iwl_priv *priv) +void iwl3945_config_ap(struct iwl_priv *priv) { int rc = 0; @@ -3875,7 +3257,7 @@ static void iwl3945_config_ap(struct iwl_priv *priv) /* RXON - unassoc (to set timing command) */ priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl3945_commit_rxon(priv); + iwlcore_commit_rxon(priv); /* RXON Timing */ memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd)); @@ -3911,8 +3293,8 @@ static void iwl3945_config_ap(struct iwl_priv *priv) } /* restore RXON assoc */ priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; - iwl3945_commit_rxon(priv); - iwl3945_add_station(priv, iwl_bcast_addr, 0, 0); + iwlcore_commit_rxon(priv); + iwl_add_station(priv, iwl_bcast_addr, 0, CMD_SYNC, NULL); } iwl3945_send_beacon_cmd(priv); @@ -3921,189 +3303,6 @@ static void iwl3945_config_ap(struct iwl_priv *priv) * clear sta table, add BCAST sta... */ } -static int iwl3945_mac_config_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_if_conf *conf) -{ - struct iwl_priv *priv = hw->priv; - int rc; - - if (conf == NULL) - return -EIO; - - if (priv->vif != vif) { - IWL_DEBUG_MAC80211(priv, "leave - priv->vif != vif\n"); - return 0; - } - - /* handle this temporarily here */ - if (priv->iw_mode == NL80211_IFTYPE_ADHOC && - conf->changed & IEEE80211_IFCC_BEACON) { - struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); - if (!beacon) - return -ENOMEM; - mutex_lock(&priv->mutex); - rc = iwl3945_mac_beacon_update(hw, beacon); - mutex_unlock(&priv->mutex); - if (rc) - return rc; - } - - if (!iwl_is_alive(priv)) - return -EAGAIN; - - mutex_lock(&priv->mutex); - - if (conf->bssid) - IWL_DEBUG_MAC80211(priv, "bssid: %pM\n", conf->bssid); - -/* - * very dubious code was here; the probe filtering flag is never set: - * - if (unlikely(test_bit(STATUS_SCANNING, &priv->status)) && - !(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) { - */ - - if (priv->iw_mode == NL80211_IFTYPE_AP) { - if (!conf->bssid) { - conf->bssid = priv->mac_addr; - memcpy(priv->bssid, priv->mac_addr, ETH_ALEN); - IWL_DEBUG_MAC80211(priv, "bssid was set to: %pM\n", - conf->bssid); - } - if (priv->ibss_beacon) - dev_kfree_skb(priv->ibss_beacon); - - priv->ibss_beacon = ieee80211_beacon_get(hw, vif); - } - - if (iwl_is_rfkill(priv)) - goto done; - - if (conf->bssid && !is_zero_ether_addr(conf->bssid) && - !is_multicast_ether_addr(conf->bssid)) { - /* If there is currently a HW scan going on in the background - * then we need to cancel it else the RXON below will fail. */ - if (iwl_scan_cancel_timeout(priv, 100)) { - IWL_WARN(priv, "Aborted scan still in progress " - "after 100ms\n"); - IWL_DEBUG_MAC80211(priv, "leaving:scan abort failed\n"); - mutex_unlock(&priv->mutex); - return -EAGAIN; - } - memcpy(priv->staging_rxon.bssid_addr, conf->bssid, ETH_ALEN); - - /* TODO: Audit driver for usage of these members and see - * if mac80211 deprecates them (priv->bssid looks like it - * shouldn't be there, but I haven't scanned the IBSS code - * to verify) - jpk */ - memcpy(priv->bssid, conf->bssid, ETH_ALEN); - - if (priv->iw_mode == NL80211_IFTYPE_AP) - iwl3945_config_ap(priv); - else { - rc = iwl3945_commit_rxon(priv); - if ((priv->iw_mode == NL80211_IFTYPE_STATION) && rc) - iwl3945_add_station(priv, - priv->active_rxon.bssid_addr, 1, 0); - } - - } else { - iwl_scan_cancel_timeout(priv, 100); - priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl3945_commit_rxon(priv); - } - - done: - IWL_DEBUG_MAC80211(priv, "leave\n"); - mutex_unlock(&priv->mutex); - - return 0; -} - -static void iwl3945_mac_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) -{ - struct iwl_priv *priv = hw->priv; - - IWL_DEBUG_MAC80211(priv, "enter\n"); - - mutex_lock(&priv->mutex); - - if (iwl_is_ready_rf(priv)) { - iwl_scan_cancel_timeout(priv, 100); - priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl3945_commit_rxon(priv); - } - if (priv->vif == conf->vif) { - priv->vif = NULL; - memset(priv->bssid, 0, ETH_ALEN); - } - mutex_unlock(&priv->mutex); - - IWL_DEBUG_MAC80211(priv, "leave\n"); -} - -#define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6) - -static void iwl3945_bss_info_changed(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *bss_conf, - u32 changes) -{ - struct iwl_priv *priv = hw->priv; - - IWL_DEBUG_MAC80211(priv, "changes = 0x%X\n", changes); - - if (changes & BSS_CHANGED_ERP_PREAMBLE) { - IWL_DEBUG_MAC80211(priv, "ERP_PREAMBLE %d\n", - bss_conf->use_short_preamble); - if (bss_conf->use_short_preamble) - priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; - else - priv->staging_rxon.flags &= - ~RXON_FLG_SHORT_PREAMBLE_MSK; - } - - if (changes & BSS_CHANGED_ERP_CTS_PROT) { - IWL_DEBUG_MAC80211(priv, "ERP_CTS %d\n", - bss_conf->use_cts_prot); - if (bss_conf->use_cts_prot && (priv->band != IEEE80211_BAND_5GHZ)) - priv->staging_rxon.flags |= RXON_FLG_TGG_PROTECT_MSK; - else - priv->staging_rxon.flags &= ~RXON_FLG_TGG_PROTECT_MSK; - } - - if (changes & BSS_CHANGED_ASSOC) { - IWL_DEBUG_MAC80211(priv, "ASSOC %d\n", bss_conf->assoc); - /* This should never happen as this function should - * never be called from interrupt context. */ - if (WARN_ON_ONCE(in_interrupt())) - return; - if (bss_conf->assoc) { - priv->assoc_id = bss_conf->aid; - priv->beacon_int = bss_conf->beacon_int; - priv->timestamp = bss_conf->timestamp; - priv->assoc_capability = bss_conf->assoc_capability; - priv->power_data.dtim_period = bss_conf->dtim_period; - priv->next_scan_jiffies = jiffies + - IWL_DELAY_NEXT_SCAN_AFTER_ASSOC; - mutex_lock(&priv->mutex); - iwl3945_post_associate(priv); - mutex_unlock(&priv->mutex); - } else { - priv->assoc_id = 0; - IWL_DEBUG_MAC80211(priv, - "DISASSOC %d\n", bss_conf->assoc); - } - } else if (changes && iwl_is_associated(priv) && priv->assoc_id) { - IWL_DEBUG_MAC80211(priv, - "Associated Changes %d\n", changes); - iwl3945_send_rxon_assoc(priv); - } - -} - static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_vif *vif, struct ieee80211_sta *sta, @@ -4126,7 +3325,7 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, static_key = !iwl_is_associated(priv); if (!static_key) { - sta_id = iwl3945_hw_find_station(priv, addr); + sta_id = iwl_find_station(priv, addr); if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_MAC80211(priv, "leave - %pM not in station map.\n", addr); @@ -4162,185 +3361,6 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, return ret; } -static int iwl3945_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, - const struct ieee80211_tx_queue_params *params) -{ - struct iwl_priv *priv = hw->priv; - unsigned long flags; - int q; - - IWL_DEBUG_MAC80211(priv, "enter\n"); - - if (!iwl_is_ready_rf(priv)) { - IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n"); - return -EIO; - } - - if (queue >= AC_NUM) { - IWL_DEBUG_MAC80211(priv, "leave - queue >= AC_NUM %d\n", queue); - return 0; - } - - q = AC_NUM - 1 - queue; - - spin_lock_irqsave(&priv->lock, flags); - - priv->qos_data.def_qos_parm.ac[q].cw_min = cpu_to_le16(params->cw_min); - priv->qos_data.def_qos_parm.ac[q].cw_max = cpu_to_le16(params->cw_max); - priv->qos_data.def_qos_parm.ac[q].aifsn = params->aifs; - priv->qos_data.def_qos_parm.ac[q].edca_txop = - cpu_to_le16((params->txop * 32)); - - priv->qos_data.def_qos_parm.ac[q].reserved1 = 0; - priv->qos_data.qos_active = 1; - - spin_unlock_irqrestore(&priv->lock, flags); - - mutex_lock(&priv->mutex); - if (priv->iw_mode == NL80211_IFTYPE_AP) - iwl_activate_qos(priv, 1); - else if (priv->assoc_id && iwl_is_associated(priv)) - iwl_activate_qos(priv, 0); - - mutex_unlock(&priv->mutex); - - IWL_DEBUG_MAC80211(priv, "leave\n"); - return 0; -} - -static int iwl3945_mac_get_tx_stats(struct ieee80211_hw *hw, - struct ieee80211_tx_queue_stats *stats) -{ - struct iwl_priv *priv = hw->priv; - int i, avail; - struct iwl_tx_queue *txq; - struct iwl_queue *q; - unsigned long flags; - - IWL_DEBUG_MAC80211(priv, "enter\n"); - - if (!iwl_is_ready_rf(priv)) { - IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n"); - return -EIO; - } - - spin_lock_irqsave(&priv->lock, flags); - - for (i = 0; i < AC_NUM; i++) { - txq = &priv->txq[i]; - q = &txq->q; - avail = iwl_queue_space(q); - - stats[i].len = q->n_window - avail; - stats[i].limit = q->n_window - q->high_mark; - stats[i].count = q->n_window; - - } - spin_unlock_irqrestore(&priv->lock, flags); - - IWL_DEBUG_MAC80211(priv, "leave\n"); - - return 0; -} - -static void iwl3945_mac_reset_tsf(struct ieee80211_hw *hw) -{ - struct iwl_priv *priv = hw->priv; - unsigned long flags; - - mutex_lock(&priv->mutex); - IWL_DEBUG_MAC80211(priv, "enter\n"); - - iwl_reset_qos(priv); - - spin_lock_irqsave(&priv->lock, flags); - priv->assoc_id = 0; - priv->assoc_capability = 0; - - /* new association get rid of ibss beacon skb */ - if (priv->ibss_beacon) - dev_kfree_skb(priv->ibss_beacon); - - priv->ibss_beacon = NULL; - - priv->beacon_int = priv->hw->conf.beacon_int; - priv->timestamp = 0; - if ((priv->iw_mode == NL80211_IFTYPE_STATION)) - priv->beacon_int = 0; - - spin_unlock_irqrestore(&priv->lock, flags); - - if (!iwl_is_ready_rf(priv)) { - IWL_DEBUG_MAC80211(priv, "leave - not ready\n"); - mutex_unlock(&priv->mutex); - return; - } - - /* we are restarting association process - * clear RXON_FILTER_ASSOC_MSK bit - */ - if (priv->iw_mode != NL80211_IFTYPE_AP) { - iwl_scan_cancel_timeout(priv, 100); - priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl3945_commit_rxon(priv); - } - - /* Per mac80211.h: This is only used in IBSS mode... */ - if (priv->iw_mode != NL80211_IFTYPE_ADHOC) { - - IWL_DEBUG_MAC80211(priv, "leave - not in IBSS\n"); - mutex_unlock(&priv->mutex); - return; - } - - iwl_set_rate(priv); - - mutex_unlock(&priv->mutex); - - IWL_DEBUG_MAC80211(priv, "leave\n"); - -} - -static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) -{ - struct iwl_priv *priv = hw->priv; - unsigned long flags; - __le64 timestamp; - - IWL_DEBUG_MAC80211(priv, "enter\n"); - - if (!iwl_is_ready_rf(priv)) { - IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n"); - return -EIO; - } - - if (priv->iw_mode != NL80211_IFTYPE_ADHOC) { - IWL_DEBUG_MAC80211(priv, "leave - not IBSS\n"); - return -EIO; - } - - spin_lock_irqsave(&priv->lock, flags); - - if (priv->ibss_beacon) - dev_kfree_skb(priv->ibss_beacon); - - priv->ibss_beacon = skb; - - priv->assoc_id = 0; - timestamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp; - priv->timestamp = le64_to_cpu(timestamp); - - IWL_DEBUG_MAC80211(priv, "leave\n"); - spin_unlock_irqrestore(&priv->lock, flags); - - iwl_reset_qos(priv); - - iwl3945_post_associate(priv); - - - return 0; -} - /***************************************************************************** * * sysfs attributes @@ -4359,7 +3379,7 @@ static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk static ssize_t show_debug_level(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl_priv *priv = d->driver_data; + struct iwl_priv *priv = dev_get_drvdata(d); return sprintf(buf, "0x%08X\n", priv->debug_level); } @@ -4367,7 +3387,7 @@ static ssize_t store_debug_level(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { - struct iwl_priv *priv = d->driver_data; + struct iwl_priv *priv = dev_get_drvdata(d); unsigned long val; int ret; @@ -4388,7 +3408,7 @@ static DEVICE_ATTR(debug_level, S_IWUSR | S_IRUGO, static ssize_t show_temperature(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + struct iwl_priv *priv = dev_get_drvdata(d); if (!iwl_is_alive(priv)) return -EAGAIN; @@ -4401,7 +3421,7 @@ static DEVICE_ATTR(temperature, S_IRUGO, show_temperature, NULL); static ssize_t show_tx_power(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + struct iwl_priv *priv = dev_get_drvdata(d); return sprintf(buf, "%d\n", priv->tx_power_user_lmt); } @@ -4409,7 +3429,7 @@ static ssize_t store_tx_power(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { - struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + struct iwl_priv *priv = dev_get_drvdata(d); char *p = (char *)buf; u32 val; @@ -4427,7 +3447,7 @@ static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, show_tx_power, store_tx_power); static ssize_t show_flags(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + struct iwl_priv *priv = dev_get_drvdata(d); return sprintf(buf, "0x%04X\n", priv->active_rxon.flags); } @@ -4436,7 +3456,7 @@ static ssize_t store_flags(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { - struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + struct iwl_priv *priv = dev_get_drvdata(d); u32 flags = simple_strtoul(buf, NULL, 0); mutex_lock(&priv->mutex); @@ -4448,7 +3468,7 @@ static ssize_t store_flags(struct device *d, IWL_DEBUG_INFO(priv, "Committing rxon.flags = 0x%04X\n", flags); priv->staging_rxon.flags = cpu_to_le32(flags); - iwl3945_commit_rxon(priv); + iwlcore_commit_rxon(priv); } } mutex_unlock(&priv->mutex); @@ -4461,7 +3481,7 @@ static DEVICE_ATTR(flags, S_IWUSR | S_IRUGO, show_flags, store_flags); static ssize_t show_filter_flags(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + struct iwl_priv *priv = dev_get_drvdata(d); return sprintf(buf, "0x%04X\n", le32_to_cpu(priv->active_rxon.filter_flags)); @@ -4471,7 +3491,7 @@ static ssize_t store_filter_flags(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { - struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + struct iwl_priv *priv = dev_get_drvdata(d); u32 filter_flags = simple_strtoul(buf, NULL, 0); mutex_lock(&priv->mutex); @@ -4484,7 +3504,7 @@ static ssize_t store_filter_flags(struct device *d, "0x%04X\n", filter_flags); priv->staging_rxon.filter_flags = cpu_to_le32(filter_flags); - iwl3945_commit_rxon(priv); + iwlcore_commit_rxon(priv); } } mutex_unlock(&priv->mutex); @@ -4624,26 +3644,11 @@ static ssize_t show_power_level(struct device *d, { struct iwl_priv *priv = dev_get_drvdata(d); int mode = priv->power_data.user_power_setting; - int system = priv->power_data.system_power_setting; int level = priv->power_data.power_mode; char *p = buf; - switch (system) { - case IWL_POWER_SYS_AUTO: - p += sprintf(p, "SYSTEM:auto"); - break; - case IWL_POWER_SYS_AC: - p += sprintf(p, "SYSTEM:ac"); - break; - case IWL_POWER_SYS_BATTERY: - p += sprintf(p, "SYSTEM:battery"); - break; - } - - p += sprintf(p, "\tMODE:%s", (mode < IWL_POWER_AUTO) ? - "fixed" : "auto"); - p += sprintf(p, "\tINDEX:%d", level); - p += sprintf(p, "\n"); + p += sprintf(p, "INDEX:%d\t", level); + p += sprintf(p, "USER:%d\n", mode); return p - buf + 1; } @@ -4756,7 +3761,7 @@ static DEVICE_ATTR(antenna, S_IWUSR | S_IRUGO, show_antenna, store_antenna); static ssize_t show_status(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + struct iwl_priv *priv = dev_get_drvdata(d); if (!iwl_is_alive(priv)) return -EAGAIN; return sprintf(buf, "0x%08x\n", (int)priv->status); @@ -4768,10 +3773,11 @@ static ssize_t dump_error_log(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { + struct iwl_priv *priv = dev_get_drvdata(d); char *p = (char *)buf; if (p[0] == '1') - iwl3945_dump_nic_error_log((struct iwl_priv *)d->driver_data); + iwl3945_dump_nic_error_log(priv); return strnlen(buf, count); } @@ -4782,10 +3788,11 @@ static ssize_t dump_event_log(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { + struct iwl_priv *priv = dev_get_drvdata(d); char *p = (char *)buf; if (p[0] == '1') - iwl3945_dump_nic_event_log((struct iwl_priv *)d->driver_data); + iwl3945_dump_nic_event_log(priv); return strnlen(buf, count); } @@ -4807,7 +3814,6 @@ static void iwl3945_setup_deferred_work(struct iwl_priv *priv) INIT_WORK(&priv->up, iwl3945_bg_up); INIT_WORK(&priv->restart, iwl3945_bg_restart); INIT_WORK(&priv->rx_replenish, iwl3945_bg_rx_replenish); - INIT_WORK(&priv->rf_kill, iwl_bg_rf_kill); INIT_WORK(&priv->beacon_update, iwl3945_bg_beacon_update); INIT_DELAYED_WORK(&priv->init_alive_start, iwl3945_bg_init_alive_start); INIT_DELAYED_WORK(&priv->alive_start, iwl3945_bg_alive_start); @@ -4864,16 +3870,15 @@ static struct ieee80211_ops iwl3945_hw_ops = { .tx = iwl3945_mac_tx, .start = iwl3945_mac_start, .stop = iwl3945_mac_stop, - .add_interface = iwl3945_mac_add_interface, - .remove_interface = iwl3945_mac_remove_interface, - .config = iwl3945_mac_config, - .config_interface = iwl3945_mac_config_interface, + .add_interface = iwl_mac_add_interface, + .remove_interface = iwl_mac_remove_interface, + .config = iwl_mac_config, .configure_filter = iwl_configure_filter, .set_key = iwl3945_mac_set_key, - .get_tx_stats = iwl3945_mac_get_tx_stats, - .conf_tx = iwl3945_mac_conf_tx, - .reset_tsf = iwl3945_mac_reset_tsf, - .bss_info_changed = iwl3945_bss_info_changed, + .get_tx_stats = iwl_mac_get_tx_stats, + .conf_tx = iwl_mac_conf_tx, + .reset_tsf = iwl_mac_reset_tsf, + .bss_info_changed = iwl_bss_info_changed, .hw_scan = iwl_mac_hw_scan }; @@ -4886,7 +3891,6 @@ static int iwl3945_init_drv(struct iwl_priv *priv) priv->ibss_beacon = NULL; spin_lock_init(&priv->lock); - spin_lock_init(&priv->power_data.lock); spin_lock_init(&priv->sta_lock); spin_lock_init(&priv->hcmd_lock); @@ -4895,7 +3899,7 @@ static int iwl3945_init_drv(struct iwl_priv *priv) mutex_init(&priv->mutex); /* Clear the driver's (not device's) station table */ - iwl3945_clear_stations_table(priv); + iwl_clear_stations_table(priv); priv->data_retry_limit = -1; priv->ieee_channels = NULL; @@ -4966,13 +3970,13 @@ static int iwl3945_setup_mac(struct iwl_priv *priv) hw->wiphy->custom_regulatory = true; - hw->wiphy->max_scan_ssids = 1; /* WILL FIX */ + hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX_3945; + /* we create the 802.11 header and a zero-length SSID element */ + hw->wiphy->max_scan_ie_len = IWL_MAX_PROBE_REQUEST - 24 - 2; /* Default value; 4 EDCA QOS priorities */ hw->queues = 4; - 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]; @@ -5037,6 +4041,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e IWL_DEBUG_INFO(priv, "*** LOAD DRIVER ***\n"); priv->cfg = cfg; priv->pci_dev = pdev; + priv->inta_mask = CSR_INI_SET_MASK; #ifdef CONFIG_IWLWIFI_DEBUG priv->debug_level = iwl3945_mod_params.debug; @@ -5083,6 +4088,11 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e * PCI Tx retries from interfering with C3 CPU state */ pci_write_config_byte(pdev, 0x41, 0x00); + /* this spin lock will be used in apm_ops.init and EEPROM access + * we should init now + */ + spin_lock_init(&priv->reg_lock); + /* amp init */ err = priv->cfg->ops->lib->apm_ops.init(priv); if (err < 0) { @@ -5128,20 +4138,8 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e IWL_INFO(priv, "Detected Intel Wireless WiFi Link %s\n", priv->cfg->name); - /*********************************** - * 7. Initialize Module Parameters - * **********************************/ - - /* Initialize module parameter values here */ - /* Disable radio (SW RF KILL) via parameter when loading driver */ - if (iwl3945_mod_params.disable) { - set_bit(STATUS_RF_KILL_SW, &priv->status); - IWL_DEBUG_INFO(priv, "Radio disabled.\n"); - } - - /*********************** - * 8. Setup Services + * 7. Setup Services * ********************/ spin_lock_irqsave(&priv->lock, flags); @@ -5150,8 +4148,8 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e pci_enable_msi(priv->pci_dev); - err = request_irq(priv->pci_dev->irq, iwl_isr, IRQF_SHARED, - DRV_NAME, priv); + err = request_irq(priv->pci_dev->irq, priv->cfg->ops->lib->isr, + IRQF_SHARED, DRV_NAME, priv); if (err) { IWL_ERR(priv, "Error allocating IRQ %d\n", priv->pci_dev->irq); goto out_disable_msi; @@ -5169,7 +4167,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e iwl3945_setup_rx_handlers(priv); /********************************* - * 9. Setup and Register mac80211 + * 8. Setup and Register mac80211 * *******************************/ iwl_enable_interrupts(priv); @@ -5178,12 +4176,9 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e if (err) goto out_remove_sysfs; - err = iwl_rfkill_init(priv); + err = iwl_dbgfs_register(priv, DRV_NAME); if (err) - IWL_ERR(priv, "Unable to initialize RFKILL system. " - "Ignoring error: %d\n", err); - else - iwl_rfkill_set_hw_state(priv); + IWL_ERR(priv, "failed to create debugfs files. Ignoring error: %d\n", err); /* Start monitoring the killswitch */ queue_delayed_work(priv->workqueue, &priv->rfkill_poll, @@ -5228,6 +4223,8 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev) IWL_DEBUG_INFO(priv, "*** UNLOAD DRIVER ***\n"); + iwl_dbgfs_unregister(priv); + set_bit(STATUS_EXIT_PENDING, &priv->status); if (priv->mac80211_registered) { @@ -5248,7 +4245,6 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev) sysfs_remove_group(&pdev->dev.kobj, &iwl3945_attribute_group); - iwl_rfkill_unregister(priv); cancel_delayed_work_sync(&priv->rfkill_poll); iwl3945_dealloc_ucode_pci(priv); @@ -5258,7 +4254,7 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev) iwl3945_hw_txq_ctx_free(priv); iwl3945_unset_hw_params(priv); - iwl3945_clear_stations_table(priv); + iwl_clear_stations_table(priv); /*netif_stop_queue(dev); */ flush_workqueue(priv->workqueue); @@ -5286,43 +4282,6 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev) ieee80211_free_hw(priv->hw); } -#ifdef CONFIG_PM - -static int iwl3945_pci_suspend(struct pci_dev *pdev, pm_message_t state) -{ - struct iwl_priv *priv = pci_get_drvdata(pdev); - - if (priv->is_open) { - set_bit(STATUS_IN_SUSPEND, &priv->status); - iwl3945_mac_stop(priv->hw); - priv->is_open = 1; - } - pci_save_state(pdev); - pci_disable_device(pdev); - pci_set_power_state(pdev, PCI_D3hot); - - return 0; -} - -static int iwl3945_pci_resume(struct pci_dev *pdev) -{ - struct iwl_priv *priv = pci_get_drvdata(pdev); - int ret; - - pci_set_power_state(pdev, PCI_D0); - ret = pci_enable_device(pdev); - if (ret) - return ret; - pci_restore_state(pdev); - - if (priv->is_open) - iwl3945_mac_start(priv->hw); - - clear_bit(STATUS_IN_SUSPEND, &priv->status); - return 0; -} - -#endif /* CONFIG_PM */ /***************************************************************************** * @@ -5336,8 +4295,8 @@ static struct pci_driver iwl3945_driver = { .probe = iwl3945_pci_probe, .remove = __devexit_p(iwl3945_pci_remove), #ifdef CONFIG_PM - .suspend = iwl3945_pci_suspend, - .resume = iwl3945_pci_resume, + .suspend = iwl_pci_suspend, + .resume = iwl_pci_resume, #endif }; @@ -5378,8 +4337,6 @@ MODULE_FIRMWARE(IWL3945_MODULE_FIRMWARE(IWL3945_UCODE_API_MAX)); module_param_named(antenna, iwl3945_mod_params.antenna, int, 0444); MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])"); -module_param_named(disable, iwl3945_mod_params.disable, int, 0444); -MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])"); module_param_named(swcrypto, iwl3945_mod_params.sw_crypto, int, 0444); MODULE_PARM_DESC(swcrypto, "using software crypto (default 1 [software])\n"); diff --git a/drivers/net/wireless/iwmc3200wifi/Kconfig b/drivers/net/wireless/iwmc3200wifi/Kconfig new file mode 100644 index 000000000000..1eccb6df46dd --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/Kconfig @@ -0,0 +1,23 @@ +config IWM + tristate "Intel Wireless Multicomm 3200 WiFi driver" + depends on MMC && WLAN_80211 && EXPERIMENTAL + depends on CFG80211 + select WIRELESS_EXT + select FW_LOADER + +config IWM_DEBUG + bool "Enable full debugging output in iwmc3200wifi" + depends on IWM && DEBUG_FS + ---help--- + This option will enable debug tracing and setting for iwm + + You can set the debug level and module through debugfs. By + default all modules are set to the IWL_DL_ERR level. + To see the list of debug modules and levels, see iwm/debug.h + + For example, if you want the full MLME debug output: + echo 0xff > /debug/iwm/phyN/debug/mlme + + Or, if you want the full debug, for all modules: + echo 0xff > /debug/iwm/phyN/debug/level + echo 0xff > /debug/iwm/phyN/debug/modules diff --git a/drivers/net/wireless/iwmc3200wifi/Makefile b/drivers/net/wireless/iwmc3200wifi/Makefile new file mode 100644 index 000000000000..927f022545c1 --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/Makefile @@ -0,0 +1,5 @@ +obj-$(CONFIG_IWM) := iwmc3200wifi.o +iwmc3200wifi-objs += main.o netdev.o rx.o tx.o sdio.o hal.o fw.o +iwmc3200wifi-objs += commands.o wext.o cfg80211.o eeprom.o + +iwmc3200wifi-$(CONFIG_IWM_DEBUG) += debugfs.o diff --git a/drivers/net/wireless/iwmc3200wifi/bus.h b/drivers/net/wireless/iwmc3200wifi/bus.h new file mode 100644 index 000000000000..836663eec257 --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/bus.h @@ -0,0 +1,57 @@ +/* + * Intel Wireless Multicomm 3200 WiFi driver + * + * Copyright (C) 2009 Intel Corporation + * Samuel Ortiz + * Zhu Yi + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#ifndef __IWM_BUS_H__ +#define __IWM_BUS_H__ + +#include "iwm.h" + +struct iwm_if_ops { + int (*enable)(struct iwm_priv *iwm); + int (*disable)(struct iwm_priv *iwm); + int (*send_chunk)(struct iwm_priv *iwm, u8* buf, int count); + + int (*debugfs_init)(struct iwm_priv *iwm, struct dentry *parent_dir); + void (*debugfs_exit)(struct iwm_priv *iwm); + + const char *umac_name; + const char *calib_lmac_name; + const char *lmac_name; +}; + +static inline int iwm_bus_send_chunk(struct iwm_priv *iwm, u8 *buf, int count) +{ + return iwm->bus_ops->send_chunk(iwm, buf, count); +} + +static inline int iwm_bus_enable(struct iwm_priv *iwm) +{ + return iwm->bus_ops->enable(iwm); +} + +static inline int iwm_bus_disable(struct iwm_priv *iwm) +{ + return iwm->bus_ops->disable(iwm); +} + +#endif diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c new file mode 100644 index 000000000000..96f714e6e12b --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c @@ -0,0 +1,409 @@ +/* + * Intel Wireless Multicomm 3200 WiFi driver + * + * Copyright (C) 2009 Intel Corporation + * Samuel Ortiz + * Zhu Yi + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#include +#include +#include +#include +#include + +#include "iwm.h" +#include "commands.h" +#include "cfg80211.h" +#include "debug.h" + +#define RATETAB_ENT(_rate, _rateid, _flags) \ + { \ + .bitrate = (_rate), \ + .hw_value = (_rateid), \ + .flags = (_flags), \ + } + +#define CHAN2G(_channel, _freq, _flags) { \ + .band = IEEE80211_BAND_2GHZ, \ + .center_freq = (_freq), \ + .hw_value = (_channel), \ + .flags = (_flags), \ + .max_antenna_gain = 0, \ + .max_power = 30, \ +} + +#define CHAN5G(_channel, _flags) { \ + .band = IEEE80211_BAND_5GHZ, \ + .center_freq = 5000 + (5 * (_channel)), \ + .hw_value = (_channel), \ + .flags = (_flags), \ + .max_antenna_gain = 0, \ + .max_power = 30, \ +} + +static struct ieee80211_rate iwm_rates[] = { + RATETAB_ENT(10, 0x1, 0), + RATETAB_ENT(20, 0x2, 0), + RATETAB_ENT(55, 0x4, 0), + RATETAB_ENT(110, 0x8, 0), + RATETAB_ENT(60, 0x10, 0), + RATETAB_ENT(90, 0x20, 0), + RATETAB_ENT(120, 0x40, 0), + RATETAB_ENT(180, 0x80, 0), + RATETAB_ENT(240, 0x100, 0), + RATETAB_ENT(360, 0x200, 0), + RATETAB_ENT(480, 0x400, 0), + RATETAB_ENT(540, 0x800, 0), +}; + +#define iwm_a_rates (iwm_rates + 4) +#define iwm_a_rates_size 8 +#define iwm_g_rates (iwm_rates + 0) +#define iwm_g_rates_size 12 + +static struct ieee80211_channel iwm_2ghz_channels[] = { + CHAN2G(1, 2412, 0), + CHAN2G(2, 2417, 0), + CHAN2G(3, 2422, 0), + CHAN2G(4, 2427, 0), + CHAN2G(5, 2432, 0), + CHAN2G(6, 2437, 0), + CHAN2G(7, 2442, 0), + CHAN2G(8, 2447, 0), + CHAN2G(9, 2452, 0), + CHAN2G(10, 2457, 0), + CHAN2G(11, 2462, 0), + CHAN2G(12, 2467, 0), + CHAN2G(13, 2472, 0), + CHAN2G(14, 2484, 0), +}; + +static struct ieee80211_channel iwm_5ghz_a_channels[] = { + CHAN5G(34, 0), CHAN5G(36, 0), + CHAN5G(38, 0), CHAN5G(40, 0), + CHAN5G(42, 0), CHAN5G(44, 0), + CHAN5G(46, 0), CHAN5G(48, 0), + CHAN5G(52, 0), CHAN5G(56, 0), + CHAN5G(60, 0), CHAN5G(64, 0), + CHAN5G(100, 0), CHAN5G(104, 0), + CHAN5G(108, 0), CHAN5G(112, 0), + CHAN5G(116, 0), CHAN5G(120, 0), + CHAN5G(124, 0), CHAN5G(128, 0), + CHAN5G(132, 0), CHAN5G(136, 0), + CHAN5G(140, 0), CHAN5G(149, 0), + CHAN5G(153, 0), CHAN5G(157, 0), + CHAN5G(161, 0), CHAN5G(165, 0), + CHAN5G(184, 0), CHAN5G(188, 0), + CHAN5G(192, 0), CHAN5G(196, 0), + CHAN5G(200, 0), CHAN5G(204, 0), + CHAN5G(208, 0), CHAN5G(212, 0), + CHAN5G(216, 0), +}; + +static struct ieee80211_supported_band iwm_band_2ghz = { + .channels = iwm_2ghz_channels, + .n_channels = ARRAY_SIZE(iwm_2ghz_channels), + .bitrates = iwm_g_rates, + .n_bitrates = iwm_g_rates_size, +}; + +static struct ieee80211_supported_band iwm_band_5ghz = { + .channels = iwm_5ghz_a_channels, + .n_channels = ARRAY_SIZE(iwm_5ghz_a_channels), + .bitrates = iwm_a_rates, + .n_bitrates = iwm_a_rates_size, +}; + +int iwm_cfg80211_inform_bss(struct iwm_priv *iwm) +{ + struct wiphy *wiphy = iwm_to_wiphy(iwm); + struct iwm_bss_info *bss, *next; + struct iwm_umac_notif_bss_info *umac_bss; + struct ieee80211_mgmt *mgmt; + struct ieee80211_channel *channel; + struct ieee80211_supported_band *band; + s32 signal; + int freq; + + list_for_each_entry_safe(bss, next, &iwm->bss_list, node) { + umac_bss = bss->bss; + mgmt = (struct ieee80211_mgmt *)(umac_bss->frame_buf); + + if (umac_bss->band == UMAC_BAND_2GHZ) + band = wiphy->bands[IEEE80211_BAND_2GHZ]; + else if (umac_bss->band == UMAC_BAND_5GHZ) + band = wiphy->bands[IEEE80211_BAND_5GHZ]; + else { + IWM_ERR(iwm, "Invalid band: %d\n", umac_bss->band); + return -EINVAL; + } + + freq = ieee80211_channel_to_frequency(umac_bss->channel); + channel = ieee80211_get_channel(wiphy, freq); + signal = umac_bss->rssi * 100; + + if (!cfg80211_inform_bss_frame(wiphy, channel, mgmt, + le16_to_cpu(umac_bss->frame_len), + signal, GFP_KERNEL)) + return -EINVAL; + } + + return 0; +} + +static int iwm_cfg80211_change_iface(struct wiphy *wiphy, int ifindex, + enum nl80211_iftype type, u32 *flags, + struct vif_params *params) +{ + struct net_device *ndev; + struct wireless_dev *wdev; + struct iwm_priv *iwm; + u32 old_mode; + + /* we're under RTNL */ + ndev = __dev_get_by_index(&init_net, ifindex); + if (!ndev) + return -ENODEV; + + wdev = ndev->ieee80211_ptr; + iwm = ndev_to_iwm(ndev); + old_mode = iwm->conf.mode; + + switch (type) { + case NL80211_IFTYPE_STATION: + iwm->conf.mode = UMAC_MODE_BSS; + break; + case NL80211_IFTYPE_ADHOC: + iwm->conf.mode = UMAC_MODE_IBSS; + break; + default: + return -EOPNOTSUPP; + } + + wdev->iftype = type; + + if ((old_mode == iwm->conf.mode) || !iwm->umac_profile) + return 0; + + iwm->umac_profile->mode = cpu_to_le32(iwm->conf.mode); + + if (iwm->umac_profile_active) { + int ret = iwm_invalidate_mlme_profile(iwm); + if (ret < 0) + IWM_ERR(iwm, "Couldn't invalidate profile\n"); + } + + return 0; +} + +static int iwm_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, + struct cfg80211_scan_request *request) +{ + struct iwm_priv *iwm = ndev_to_iwm(ndev); + int ret; + + if (!test_bit(IWM_STATUS_READY, &iwm->status)) { + IWM_ERR(iwm, "Scan while device is not ready\n"); + return -EIO; + } + + if (test_bit(IWM_STATUS_SCANNING, &iwm->status)) { + IWM_ERR(iwm, "Scanning already\n"); + return -EAGAIN; + } + + if (test_bit(IWM_STATUS_SCAN_ABORTING, &iwm->status)) { + IWM_ERR(iwm, "Scanning being aborted\n"); + return -EAGAIN; + } + + set_bit(IWM_STATUS_SCANNING, &iwm->status); + + ret = iwm_scan_ssids(iwm, request->ssids, request->n_ssids); + if (ret) { + clear_bit(IWM_STATUS_SCANNING, &iwm->status); + return ret; + } + + iwm->scan_request = request; + return 0; +} + +static int iwm_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) +{ + struct iwm_priv *iwm = wiphy_to_iwm(wiphy); + + if (changed & WIPHY_PARAM_RTS_THRESHOLD && + (iwm->conf.rts_threshold != wiphy->rts_threshold)) { + int ret; + + iwm->conf.rts_threshold = wiphy->rts_threshold; + + ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, + CFG_RTS_THRESHOLD, + iwm->conf.rts_threshold); + if (ret < 0) + return ret; + } + + if (changed & WIPHY_PARAM_FRAG_THRESHOLD && + (iwm->conf.frag_threshold != wiphy->frag_threshold)) { + int ret; + + iwm->conf.frag_threshold = wiphy->frag_threshold; + + ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_FA_CFG_FIX, + CFG_FRAG_THRESHOLD, + iwm->conf.frag_threshold); + if (ret < 0) + return ret; + } + + return 0; +} + +static int iwm_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_ibss_params *params) +{ + struct iwm_priv *iwm = wiphy_to_iwm(wiphy); + struct ieee80211_channel *chan = params->channel; + struct cfg80211_bss *bss; + + if (!test_bit(IWM_STATUS_READY, &iwm->status)) + return -EIO; + + /* UMAC doesn't support creating IBSS network with specified bssid. + * This should be removed after we have join only mode supported. */ + if (params->bssid) + return -EOPNOTSUPP; + + bss = cfg80211_get_ibss(iwm_to_wiphy(iwm), NULL, + params->ssid, params->ssid_len); + if (!bss) { + iwm_scan_one_ssid(iwm, params->ssid, params->ssid_len); + schedule_timeout_interruptible(2 * HZ); + bss = cfg80211_get_ibss(iwm_to_wiphy(iwm), NULL, + params->ssid, params->ssid_len); + } + /* IBSS join only mode is not supported by UMAC ATM */ + if (bss) { + cfg80211_put_bss(bss); + return -EOPNOTSUPP; + } + + iwm->channel = ieee80211_frequency_to_channel(chan->center_freq); + iwm->umac_profile->ibss.band = chan->band; + iwm->umac_profile->ibss.channel = iwm->channel; + iwm->umac_profile->ssid.ssid_len = params->ssid_len; + memcpy(iwm->umac_profile->ssid.ssid, params->ssid, params->ssid_len); + + if (params->bssid) + memcpy(&iwm->umac_profile->bssid[0], params->bssid, ETH_ALEN); + + return iwm_send_mlme_profile(iwm); +} + +static int iwm_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) +{ + struct iwm_priv *iwm = wiphy_to_iwm(wiphy); + + if (iwm->umac_profile_active) + return iwm_invalidate_mlme_profile(iwm); + + return 0; +} + +static struct cfg80211_ops iwm_cfg80211_ops = { + .change_virtual_intf = iwm_cfg80211_change_iface, + .scan = iwm_cfg80211_scan, + .set_wiphy_params = iwm_cfg80211_set_wiphy_params, + .join_ibss = iwm_cfg80211_join_ibss, + .leave_ibss = iwm_cfg80211_leave_ibss, +}; + +struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev) +{ + int ret = 0; + struct wireless_dev *wdev; + + /* + * We're trying to have the following memory + * layout: + * + * +-------------------------+ + * | struct wiphy | + * +-------------------------+ + * | struct iwm_priv | + * +-------------------------+ + * | bus private data | + * | (e.g. iwm_priv_sdio) | + * +-------------------------+ + * + */ + + wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); + if (!wdev) { + dev_err(dev, "Couldn't allocate wireless device\n"); + return ERR_PTR(-ENOMEM); + } + + wdev->wiphy = wiphy_new(&iwm_cfg80211_ops, + sizeof(struct iwm_priv) + sizeof_bus); + if (!wdev->wiphy) { + dev_err(dev, "Couldn't allocate wiphy device\n"); + ret = -ENOMEM; + goto out_err_new; + } + + set_wiphy_dev(wdev->wiphy, dev); + wdev->wiphy->max_scan_ssids = UMAC_WIFI_IF_PROBE_OPTION_MAX; + wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC); + wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &iwm_band_2ghz; + wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &iwm_band_5ghz; + wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; + + ret = wiphy_register(wdev->wiphy); + if (ret < 0) { + dev_err(dev, "Couldn't register wiphy device\n"); + goto out_err_register; + } + + return wdev; + + out_err_register: + wiphy_free(wdev->wiphy); + + out_err_new: + kfree(wdev); + + return ERR_PTR(ret); +} + +void iwm_wdev_free(struct iwm_priv *iwm) +{ + struct wireless_dev *wdev = iwm_to_wdev(iwm); + + if (!wdev) + return; + + wiphy_unregister(wdev->wiphy); + wiphy_free(wdev->wiphy); + kfree(wdev); +} diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.h b/drivers/net/wireless/iwmc3200wifi/cfg80211.h new file mode 100644 index 000000000000..56a34145acbf --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.h @@ -0,0 +1,31 @@ +/* + * Intel Wireless Multicomm 3200 WiFi driver + * + * Copyright (C) 2009 Intel Corporation + * Samuel Ortiz + * Zhu Yi + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#ifndef __IWM_CFG80211_H__ +#define __IWM_CFG80211_H__ + +int iwm_cfg80211_inform_bss(struct iwm_priv *iwm); +struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev); +void iwm_wdev_free(struct iwm_priv *iwm); + +#endif diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c new file mode 100644 index 000000000000..834a7f544e5d --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/commands.c @@ -0,0 +1,920 @@ +/* + * Intel Wireless Multicomm 3200 WiFi driver + * + * Copyright (C) 2009 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * Intel Corporation + * Samuel Ortiz + * Zhu Yi + * + */ + +#include +#include +#include +#include + +#include "iwm.h" +#include "bus.h" +#include "hal.h" +#include "umac.h" +#include "commands.h" +#include "debug.h" + +static int iwm_send_lmac_ptrough_cmd(struct iwm_priv *iwm, + u8 lmac_cmd_id, + const void *lmac_payload, + u16 lmac_payload_size, + u8 resp) +{ + struct iwm_udma_wifi_cmd udma_cmd = UDMA_LMAC_INIT; + struct iwm_umac_cmd umac_cmd; + struct iwm_lmac_cmd lmac_cmd; + + lmac_cmd.id = lmac_cmd_id; + + umac_cmd.id = UMAC_CMD_OPCODE_WIFI_PASS_THROUGH; + umac_cmd.resp = resp; + + return iwm_hal_send_host_cmd(iwm, &udma_cmd, &umac_cmd, &lmac_cmd, + lmac_payload, lmac_payload_size); +} + +int iwm_send_wifi_if_cmd(struct iwm_priv *iwm, void *payload, u16 payload_size, + bool resp) +{ + struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT; + struct iwm_umac_cmd umac_cmd; + + umac_cmd.id = UMAC_CMD_OPCODE_WIFI_IF_WRAPPER; + umac_cmd.resp = resp; + + return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, + payload, payload_size); +} + +static struct coex_event iwm_sta_xor_prio_tbl[COEX_EVENTS_NUM] = +{ + {4, 3, 0, COEX_UNASSOC_IDLE_FLAGS}, + {4, 3, 0, COEX_UNASSOC_MANUAL_SCAN_FLAGS}, + {4, 3, 0, COEX_UNASSOC_AUTO_SCAN_FLAGS}, + {4, 3, 0, COEX_CALIBRATION_FLAGS}, + {4, 3, 0, COEX_PERIODIC_CALIBRATION_FLAGS}, + {4, 3, 0, COEX_CONNECTION_ESTAB_FLAGS}, + {4, 3, 0, COEX_ASSOCIATED_IDLE_FLAGS}, + {4, 3, 0, COEX_ASSOC_MANUAL_SCAN_FLAGS}, + {4, 3, 0, COEX_ASSOC_AUTO_SCAN_FLAGS}, + {4, 3, 0, COEX_ASSOC_ACTIVE_LEVEL_FLAGS}, + {6, 3, 0, COEX_XOR_RF_ON_FLAGS}, + {4, 3, 0, COEX_RF_OFF_FLAGS}, + {6, 6, 0, COEX_STAND_ALONE_DEBUG_FLAGS}, + {4, 3, 0, COEX_IPAN_ASSOC_LEVEL_FLAGS}, + {4, 3, 0, COEX_RSRVD1_FLAGS}, + {4, 3, 0, COEX_RSRVD2_FLAGS} +}; + +static struct coex_event iwm_sta_cm_prio_tbl[COEX_EVENTS_NUM] = +{ + {1, 1, 0, COEX_UNASSOC_IDLE_FLAGS}, + {4, 3, 0, COEX_UNASSOC_MANUAL_SCAN_FLAGS}, + {3, 3, 0, COEX_UNASSOC_AUTO_SCAN_FLAGS}, + {5, 5, 0, COEX_CALIBRATION_FLAGS}, + {4, 4, 0, COEX_PERIODIC_CALIBRATION_FLAGS}, + {5, 4, 0, COEX_CONNECTION_ESTAB_FLAGS}, + {4, 4, 0, COEX_ASSOCIATED_IDLE_FLAGS}, + {4, 4, 0, COEX_ASSOC_MANUAL_SCAN_FLAGS}, + {4, 4, 0, COEX_ASSOC_AUTO_SCAN_FLAGS}, + {4, 4, 0, COEX_ASSOC_ACTIVE_LEVEL_FLAGS}, + {1, 1, 0, COEX_RF_ON_FLAGS}, + {1, 1, 0, COEX_RF_OFF_FLAGS}, + {6, 6, 0, COEX_STAND_ALONE_DEBUG_FLAGS}, + {5, 4, 0, COEX_IPAN_ASSOC_LEVEL_FLAGS}, + {1, 1, 0, COEX_RSRVD1_FLAGS}, + {1, 1, 0, COEX_RSRVD2_FLAGS} +}; + +int iwm_send_prio_table(struct iwm_priv *iwm) +{ + struct iwm_coex_prio_table_cmd coex_table_cmd; + u32 coex_enabled, mode_enabled; + + memset(&coex_table_cmd, 0, sizeof(struct iwm_coex_prio_table_cmd)); + + coex_table_cmd.flags = COEX_FLAGS_STA_TABLE_VALID_MSK; + + switch (iwm->conf.coexist_mode) { + case COEX_MODE_XOR: + case COEX_MODE_CM: + coex_enabled = 1; + break; + default: + coex_enabled = 0; + break; + } + + switch (iwm->conf.mode) { + case UMAC_MODE_BSS: + case UMAC_MODE_IBSS: + mode_enabled = 1; + break; + default: + mode_enabled = 0; + break; + } + + if (coex_enabled && mode_enabled) { + coex_table_cmd.flags |= COEX_FLAGS_COEX_ENABLE_MSK | + COEX_FLAGS_ASSOC_WAKEUP_UMASK_MSK | + COEX_FLAGS_UNASSOC_WAKEUP_UMASK_MSK; + + switch (iwm->conf.coexist_mode) { + case COEX_MODE_XOR: + memcpy(coex_table_cmd.sta_prio, iwm_sta_xor_prio_tbl, + sizeof(iwm_sta_xor_prio_tbl)); + break; + case COEX_MODE_CM: + memcpy(coex_table_cmd.sta_prio, iwm_sta_cm_prio_tbl, + sizeof(iwm_sta_cm_prio_tbl)); + break; + default: + IWM_ERR(iwm, "Invalid coex_mode 0x%x\n", + iwm->conf.coexist_mode); + break; + } + } else + IWM_WARN(iwm, "coexistense disabled\n"); + + return iwm_send_lmac_ptrough_cmd(iwm, COEX_PRIORITY_TABLE_CMD, + &coex_table_cmd, + sizeof(struct iwm_coex_prio_table_cmd), 1); +} + +int iwm_send_init_calib_cfg(struct iwm_priv *iwm, u8 calib_requested) +{ + struct iwm_lmac_cal_cfg_cmd cal_cfg_cmd; + + memset(&cal_cfg_cmd, 0, sizeof(struct iwm_lmac_cal_cfg_cmd)); + + cal_cfg_cmd.ucode_cfg.init.enable = cpu_to_le32(calib_requested); + cal_cfg_cmd.ucode_cfg.init.start = cpu_to_le32(calib_requested); + cal_cfg_cmd.ucode_cfg.init.send_res = cpu_to_le32(calib_requested); + cal_cfg_cmd.ucode_cfg.flags = + cpu_to_le32(CALIB_CFG_FLAG_SEND_COMPLETE_NTFY_AFTER_MSK); + + return iwm_send_lmac_ptrough_cmd(iwm, CALIBRATION_CFG_CMD, &cal_cfg_cmd, + sizeof(struct iwm_lmac_cal_cfg_cmd), 1); +} + +int iwm_send_periodic_calib_cfg(struct iwm_priv *iwm, u8 calib_requested) +{ + struct iwm_lmac_cal_cfg_cmd cal_cfg_cmd; + + memset(&cal_cfg_cmd, 0, sizeof(struct iwm_lmac_cal_cfg_cmd)); + + cal_cfg_cmd.ucode_cfg.periodic.enable = cpu_to_le32(calib_requested); + cal_cfg_cmd.ucode_cfg.periodic.start = cpu_to_le32(calib_requested); + + return iwm_send_lmac_ptrough_cmd(iwm, CALIBRATION_CFG_CMD, &cal_cfg_cmd, + sizeof(struct iwm_lmac_cal_cfg_cmd), 0); +} + +int iwm_store_rxiq_calib_result(struct iwm_priv *iwm) +{ + struct iwm_calib_rxiq *rxiq; + u8 *eeprom_rxiq = iwm_eeprom_access(iwm, IWM_EEPROM_CALIB_RXIQ); + int grplen = sizeof(struct iwm_calib_rxiq_group); + + rxiq = kzalloc(sizeof(struct iwm_calib_rxiq), GFP_KERNEL); + if (!rxiq) { + IWM_ERR(iwm, "Couldn't alloc memory for RX IQ\n"); + return -ENOMEM; + } + + eeprom_rxiq = iwm_eeprom_access(iwm, IWM_EEPROM_CALIB_RXIQ); + if (IS_ERR(eeprom_rxiq)) { + IWM_ERR(iwm, "Couldn't access EEPROM RX IQ entry\n"); + return PTR_ERR(eeprom_rxiq); + } + + iwm->calib_res[SHILOH_PHY_CALIBRATE_RX_IQ_CMD].buf = (u8 *)rxiq; + iwm->calib_res[SHILOH_PHY_CALIBRATE_RX_IQ_CMD].size = sizeof(*rxiq); + + rxiq->hdr.opcode = SHILOH_PHY_CALIBRATE_RX_IQ_CMD; + rxiq->hdr.first_grp = 0; + rxiq->hdr.grp_num = 1; + rxiq->hdr.all_data_valid = 1; + + memcpy(&rxiq->group[0], eeprom_rxiq, 4 * grplen); + memcpy(&rxiq->group[4], eeprom_rxiq + 6 * grplen, grplen); + + return 0; +} + +int iwm_send_calib_results(struct iwm_priv *iwm) +{ + int i, ret = 0; + + for (i = PHY_CALIBRATE_OPCODES_NUM; i < CALIBRATION_CMD_NUM; i++) { + if (test_bit(i - PHY_CALIBRATE_OPCODES_NUM, + &iwm->calib_done_map)) { + IWM_DBG_CMD(iwm, DBG, + "Send calibration %d result\n", i); + ret |= iwm_send_lmac_ptrough_cmd(iwm, + REPLY_PHY_CALIBRATION_CMD, + iwm->calib_res[i].buf, + iwm->calib_res[i].size, 0); + + kfree(iwm->calib_res[i].buf); + iwm->calib_res[i].buf = NULL; + iwm->calib_res[i].size = 0; + } + } + + return ret; +} + +int iwm_send_umac_reset(struct iwm_priv *iwm, __le32 reset_flags, bool resp) +{ + struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT; + struct iwm_umac_cmd umac_cmd; + struct iwm_umac_cmd_reset reset; + + reset.flags = reset_flags; + + umac_cmd.id = UMAC_CMD_OPCODE_RESET; + umac_cmd.resp = resp; + + return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, &reset, + sizeof(struct iwm_umac_cmd_reset)); +} + +int iwm_umac_set_config_fix(struct iwm_priv *iwm, u16 tbl, u16 key, u32 value) +{ + struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT; + struct iwm_umac_cmd umac_cmd; + struct iwm_umac_cmd_set_param_fix param; + + if ((tbl != UMAC_PARAM_TBL_CFG_FIX) && + (tbl != UMAC_PARAM_TBL_FA_CFG_FIX)) + return -EINVAL; + + umac_cmd.id = UMAC_CMD_OPCODE_SET_PARAM_FIX; + umac_cmd.resp = 0; + + param.tbl = cpu_to_le16(tbl); + param.key = cpu_to_le16(key); + param.value = cpu_to_le32(value); + + return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, ¶m, + sizeof(struct iwm_umac_cmd_set_param_fix)); +} + +int iwm_umac_set_config_var(struct iwm_priv *iwm, u16 key, + void *payload, u16 payload_size) +{ + struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT; + struct iwm_umac_cmd umac_cmd; + struct iwm_umac_cmd_set_param_var *param_hdr; + u8 *param; + int ret; + + param = kzalloc(payload_size + + sizeof(struct iwm_umac_cmd_set_param_var), GFP_KERNEL); + if (!param) { + IWM_ERR(iwm, "Couldn't allocate param\n"); + return -ENOMEM; + } + + param_hdr = (struct iwm_umac_cmd_set_param_var *)param; + + umac_cmd.id = UMAC_CMD_OPCODE_SET_PARAM_VAR; + umac_cmd.resp = 0; + + param_hdr->tbl = cpu_to_le16(UMAC_PARAM_TBL_CFG_VAR); + param_hdr->key = cpu_to_le16(key); + param_hdr->len = cpu_to_le16(payload_size); + memcpy(param + sizeof(struct iwm_umac_cmd_set_param_var), + payload, payload_size); + + ret = iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, param, + sizeof(struct iwm_umac_cmd_set_param_var) + + payload_size); + kfree(param); + + return ret; +} + +int iwm_send_umac_config(struct iwm_priv *iwm, + __le32 reset_flags) +{ + int ret; + + /* Use UMAC default values */ + ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, + CFG_POWER_INDEX, iwm->conf.power_index); + if (ret < 0) + return ret; + + ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_FA_CFG_FIX, + CFG_FRAG_THRESHOLD, + iwm->conf.frag_threshold); + if (ret < 0) + return ret; + + ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, + CFG_RTS_THRESHOLD, + iwm->conf.rts_threshold); + if (ret < 0) + return ret; + + ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, + CFG_CTS_TO_SELF, iwm->conf.cts_to_self); + if (ret < 0) + return ret; + + ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, + CFG_COEX_MODE, iwm->conf.coexist_mode); + if (ret < 0) + return ret; + + /* + ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, + CFG_ASSOCIATION_TIMEOUT, + iwm->conf.assoc_timeout); + if (ret < 0) + return ret; + + ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, + CFG_ROAM_TIMEOUT, + iwm->conf.roam_timeout); + if (ret < 0) + return ret; + + ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, + CFG_WIRELESS_MODE, + WIRELESS_MODE_11A | WIRELESS_MODE_11G); + if (ret < 0) + return ret; + */ + + ret = iwm_umac_set_config_var(iwm, CFG_NET_ADDR, + iwm_to_ndev(iwm)->dev_addr, ETH_ALEN); + if (ret < 0) + return ret; + + /* UMAC PM static configurations */ + ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, + CFG_PM_LEGACY_RX_TIMEOUT, 0x12C); + if (ret < 0) + return ret; + + ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, + CFG_PM_LEGACY_TX_TIMEOUT, 0x15E); + if (ret < 0) + return ret; + + ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, + CFG_PM_CTRL_FLAGS, 0x30001); + if (ret < 0) + return ret; + + ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, + CFG_PM_KEEP_ALIVE_IN_BEACONS, 0x80); + if (ret < 0) + return ret; + + /* reset UMAC */ + ret = iwm_send_umac_reset(iwm, reset_flags, 1); + if (ret < 0) + return ret; + + ret = iwm_notif_handle(iwm, UMAC_CMD_OPCODE_RESET, IWM_SRC_UMAC, + WAIT_NOTIF_TIMEOUT); + if (ret) { + IWM_ERR(iwm, "Wait for UMAC RESET timeout\n"); + return ret; + } + + return ret; +} + +int iwm_send_packet(struct iwm_priv *iwm, struct sk_buff *skb, int pool_id) +{ + struct iwm_udma_wifi_cmd udma_cmd; + struct iwm_umac_cmd umac_cmd; + struct iwm_tx_info *tx_info = skb_to_tx_info(skb); + + udma_cmd.eop = 1; /* always set eop for non-concatenated Tx */ + udma_cmd.credit_group = pool_id; + udma_cmd.ra_tid = tx_info->sta << 4 | tx_info->tid; + udma_cmd.lmac_offset = 0; + + umac_cmd.id = REPLY_TX; + umac_cmd.color = tx_info->color; + umac_cmd.resp = 0; + + return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, + skb->data, skb->len); +} + +static int iwm_target_read(struct iwm_priv *iwm, __le32 address, + u8 *response, u32 resp_size) +{ + struct iwm_udma_nonwifi_cmd target_cmd; + struct iwm_nonwifi_cmd *cmd; + u16 seq_num; + int ret = 0; + + target_cmd.opcode = UMAC_HDI_OUT_OPCODE_READ; + target_cmd.addr = address; + target_cmd.op1_sz = cpu_to_le32(resp_size); + target_cmd.op2 = 0; + target_cmd.handle_by_hw = 0; + target_cmd.resp = 1; + target_cmd.eop = 1; + + ret = iwm_hal_send_target_cmd(iwm, &target_cmd, NULL); + if (ret < 0) + IWM_ERR(iwm, "Couldn't send READ command\n"); + + /* When succeding, the send_target routine returns the seq number */ + seq_num = ret; + + ret = wait_event_interruptible_timeout(iwm->nonwifi_queue, + (cmd = iwm_get_pending_nonwifi_cmd(iwm, seq_num, + UMAC_HDI_OUT_OPCODE_READ)) != NULL, + 2 * HZ); + + if (!ret) { + IWM_ERR(iwm, "Didn't receive a target READ answer\n"); + return ret; + } + + memcpy(response, cmd->buf.hdr + sizeof(struct iwm_udma_in_hdr), + resp_size); + + kfree(cmd); + + return ret; +} + +int iwm_read_mac(struct iwm_priv *iwm, u8 *mac) +{ + int ret; + u8 mac_align[ALIGN(ETH_ALEN, 8)]; + + ret = iwm_target_read(iwm, cpu_to_le32(WICO_MAC_ADDRESS_ADDR), + mac_align, sizeof(mac_align)); + if (ret < 0) + return ret; + + if (is_valid_ether_addr(mac_align)) + memcpy(mac, mac_align, ETH_ALEN); + else { + IWM_ERR(iwm, "Invalid EEPROM MAC\n"); + memcpy(mac, iwm->conf.mac_addr, ETH_ALEN); + get_random_bytes(&mac[3], 3); + } + + return 0; +} + +int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx) +{ + struct iwm_umac_tx_key_id tx_key_id; + + if (!iwm->default_key || !iwm->default_key->in_use) + return -EINVAL; + + tx_key_id.hdr.oid = UMAC_WIFI_IF_CMD_GLOBAL_TX_KEY_ID; + tx_key_id.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_tx_key_id) - + sizeof(struct iwm_umac_wifi_if)); + + tx_key_id.key_idx = key_idx; + + return iwm_send_wifi_if_cmd(iwm, &tx_key_id, sizeof(tx_key_id), 1); +} + +static int iwm_check_profile(struct iwm_priv *iwm) +{ + if (!iwm->umac_profile_active) + return -EAGAIN; + + if (iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_WEP_40 && + iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_WEP_104 && + iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_TKIP && + iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_CCMP) { + IWM_ERR(iwm, "Wrong unicast cipher: 0x%x\n", + iwm->umac_profile->sec.ucast_cipher); + return -EAGAIN; + } + + if (iwm->umac_profile->sec.mcast_cipher != UMAC_CIPHER_TYPE_WEP_40 && + iwm->umac_profile->sec.mcast_cipher != UMAC_CIPHER_TYPE_WEP_104 && + iwm->umac_profile->sec.mcast_cipher != UMAC_CIPHER_TYPE_TKIP && + iwm->umac_profile->sec.mcast_cipher != UMAC_CIPHER_TYPE_CCMP) { + IWM_ERR(iwm, "Wrong multicast cipher: 0x%x\n", + iwm->umac_profile->sec.mcast_cipher); + return -EAGAIN; + } + + if ((iwm->umac_profile->sec.ucast_cipher == UMAC_CIPHER_TYPE_WEP_40 || + iwm->umac_profile->sec.ucast_cipher == UMAC_CIPHER_TYPE_WEP_104) && + (iwm->umac_profile->sec.ucast_cipher != + iwm->umac_profile->sec.mcast_cipher)) { + IWM_ERR(iwm, "Unicast and multicast ciphers differ for WEP\n"); + } + + return 0; +} + +int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key, + struct iwm_key *key) +{ + int ret; + u8 cmd[64], *sta_addr, *key_data, key_len; + s8 key_idx; + u16 cmd_size = 0; + struct iwm_umac_key_hdr *key_hdr = &key->hdr; + struct iwm_umac_key_wep40 *wep40 = (struct iwm_umac_key_wep40 *)cmd; + struct iwm_umac_key_wep104 *wep104 = (struct iwm_umac_key_wep104 *)cmd; + struct iwm_umac_key_tkip *tkip = (struct iwm_umac_key_tkip *)cmd; + struct iwm_umac_key_ccmp *ccmp = (struct iwm_umac_key_ccmp *)cmd; + + if (set_tx_key) + iwm->default_key = key; + + /* + * We check if our current profile is valid. + * If not, we dont push the key, we just cache them, + * so that with the next siwsessid call, the keys + * will be actually pushed. + */ + if (!remove) { + ret = iwm_check_profile(iwm); + if (ret < 0) + return ret; + } + + sta_addr = key->hdr.mac; + key_data = key->key; + key_len = key->key_len; + key_idx = key->hdr.key_idx; + + if (!remove) { + IWM_DBG_WEXT(iwm, DBG, "key_idx:%d set tx key:%d\n", + key_idx, set_tx_key); + IWM_DBG_WEXT(iwm, DBG, "key_len:%d\n", key_len); + IWM_DBG_WEXT(iwm, DBG, "MAC:%pM, idx:%d, multicast:%d\n", + key_hdr->mac, key_hdr->key_idx, key_hdr->multicast); + + IWM_DBG_WEXT(iwm, DBG, "profile: mcast:0x%x, ucast:0x%x\n", + iwm->umac_profile->sec.mcast_cipher, + iwm->umac_profile->sec.ucast_cipher); + IWM_DBG_WEXT(iwm, DBG, "profile: auth_type:0x%x, flags:0x%x\n", + iwm->umac_profile->sec.auth_type, + iwm->umac_profile->sec.flags); + + switch (key->alg) { + case UMAC_CIPHER_TYPE_WEP_40: + wep40->hdr.oid = UMAC_WIFI_IF_CMD_ADD_WEP40_KEY; + wep40->hdr.buf_size = + cpu_to_le16(sizeof(struct iwm_umac_key_wep40) - + sizeof(struct iwm_umac_wifi_if)); + + memcpy(&wep40->key_hdr, key_hdr, + sizeof(struct iwm_umac_key_hdr)); + memcpy(wep40->key, key_data, key_len); + wep40->static_key = 1; + + cmd_size = sizeof(struct iwm_umac_key_wep40); + break; + + case UMAC_CIPHER_TYPE_WEP_104: + wep104->hdr.oid = UMAC_WIFI_IF_CMD_ADD_WEP104_KEY; + wep104->hdr.buf_size = + cpu_to_le16(sizeof(struct iwm_umac_key_wep104) - + sizeof(struct iwm_umac_wifi_if)); + + memcpy(&wep104->key_hdr, key_hdr, + sizeof(struct iwm_umac_key_hdr)); + memcpy(wep104->key, key_data, key_len); + wep104->static_key = 1; + + cmd_size = sizeof(struct iwm_umac_key_wep104); + break; + + case UMAC_CIPHER_TYPE_CCMP: + key_hdr->key_idx++; + ccmp->hdr.oid = UMAC_WIFI_IF_CMD_ADD_CCMP_KEY; + ccmp->hdr.buf_size = + cpu_to_le16(sizeof(struct iwm_umac_key_ccmp) - + sizeof(struct iwm_umac_wifi_if)); + + memcpy(&ccmp->key_hdr, key_hdr, + sizeof(struct iwm_umac_key_hdr)); + + memcpy(ccmp->key, key_data, key_len); + + if (key->flags & IW_ENCODE_EXT_RX_SEQ_VALID) + memcpy(ccmp->iv_count, key->rx_seq, 6); + + cmd_size = sizeof(struct iwm_umac_key_ccmp); + break; + + case UMAC_CIPHER_TYPE_TKIP: + key_hdr->key_idx++; + tkip->hdr.oid = UMAC_WIFI_IF_CMD_ADD_TKIP_KEY; + tkip->hdr.buf_size = + cpu_to_le16(sizeof(struct iwm_umac_key_tkip) - + sizeof(struct iwm_umac_wifi_if)); + + memcpy(&tkip->key_hdr, key_hdr, + sizeof(struct iwm_umac_key_hdr)); + + memcpy(tkip->tkip_key, key_data, IWM_TKIP_KEY_SIZE); + memcpy(tkip->mic_tx_key, key_data + IWM_TKIP_KEY_SIZE, + IWM_TKIP_MIC_SIZE); + memcpy(tkip->mic_rx_key, + key_data + IWM_TKIP_KEY_SIZE + IWM_TKIP_MIC_SIZE, + IWM_TKIP_MIC_SIZE); + + if (key->flags & IW_ENCODE_EXT_RX_SEQ_VALID) + memcpy(ccmp->iv_count, key->rx_seq, 6); + + cmd_size = sizeof(struct iwm_umac_key_tkip); + break; + + default: + return -ENOTSUPP; + } + + if ((key->alg == UMAC_CIPHER_TYPE_CCMP) || + (key->alg == UMAC_CIPHER_TYPE_TKIP)) + /* + * UGLY_UGLY_UGLY + * Copied HACK from the MWG driver. + * Without it, the key is set before the second + * EAPOL frame is sent, and the latter is thus + * encrypted. + */ + schedule_timeout_interruptible(usecs_to_jiffies(300)); + + ret = iwm_send_wifi_if_cmd(iwm, cmd, cmd_size, 1); + if (ret < 0) + goto err; + + /* + * We need a default key only if it is set and + * if we're doing WEP. + */ + if (iwm->default_key == key && + ((key->alg == UMAC_CIPHER_TYPE_WEP_40) || + (key->alg == UMAC_CIPHER_TYPE_WEP_104))) { + ret = iwm_set_tx_key(iwm, key_idx); + if (ret < 0) + goto err; + } + } else { + struct iwm_umac_key_remove key_remove; + + key_remove.hdr.oid = UMAC_WIFI_IF_CMD_REMOVE_KEY; + key_remove.hdr.buf_size = + cpu_to_le16(sizeof(struct iwm_umac_key_remove) - + sizeof(struct iwm_umac_wifi_if)); + memcpy(&key_remove.key_hdr, key_hdr, + sizeof(struct iwm_umac_key_hdr)); + + ret = iwm_send_wifi_if_cmd(iwm, &key_remove, + sizeof(struct iwm_umac_key_remove), + 1); + if (ret < 0) + return ret; + + iwm->keys[key_idx].in_use = 0; + } + + return 0; + + err: + kfree(key); + return ret; +} + + +int iwm_send_mlme_profile(struct iwm_priv *iwm) +{ + int ret, i; + struct iwm_umac_profile profile; + + memcpy(&profile, iwm->umac_profile, sizeof(profile)); + + profile.hdr.oid = UMAC_WIFI_IF_CMD_SET_PROFILE; + profile.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_profile) - + sizeof(struct iwm_umac_wifi_if)); + + ret = iwm_send_wifi_if_cmd(iwm, &profile, sizeof(profile), 1); + if (ret < 0) { + IWM_ERR(iwm, "Send profile command failed\n"); + return ret; + } + + /* Wait for the profile to be active */ + ret = wait_event_interruptible_timeout(iwm->mlme_queue, + iwm->umac_profile_active == 1, + 3 * HZ); + if (!ret) + return -EBUSY; + + + for (i = 0; i < IWM_NUM_KEYS; i++) + if (iwm->keys[i].in_use) { + int default_key = 0; + struct iwm_key *key = &iwm->keys[i]; + + if (key == iwm->default_key) + default_key = 1; + + /* Wait for the profile before sending the keys */ + wait_event_interruptible_timeout(iwm->mlme_queue, + (test_bit(IWM_STATUS_ASSOCIATING, &iwm->status) || + test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)), + 3 * HZ); + + ret = iwm_set_key(iwm, 0, default_key, key); + if (ret < 0) + return ret; + } + + return 0; +} + +int iwm_invalidate_mlme_profile(struct iwm_priv *iwm) +{ + int ret; + struct iwm_umac_invalidate_profile invalid; + + invalid.hdr.oid = UMAC_WIFI_IF_CMD_INVALIDATE_PROFILE; + invalid.hdr.buf_size = + cpu_to_le16(sizeof(struct iwm_umac_invalidate_profile) - + sizeof(struct iwm_umac_wifi_if)); + + invalid.reason = WLAN_REASON_UNSPECIFIED; + + ret = iwm_send_wifi_if_cmd(iwm, &invalid, sizeof(invalid), 1); + if (ret < 0) + return ret; + + ret = wait_event_interruptible_timeout(iwm->mlme_queue, + (iwm->umac_profile_active == 0), + 2 * HZ); + if (!ret) + return -EBUSY; + + return 0; +} + +int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags) +{ + struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT; + struct iwm_umac_cmd umac_cmd; + struct iwm_umac_cmd_stats_req stats_req; + + stats_req.flags = cpu_to_le32(flags); + + umac_cmd.id = UMAC_CMD_OPCODE_STATISTIC_REQUEST; + umac_cmd.resp = 0; + + return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, &stats_req, + sizeof(struct iwm_umac_cmd_stats_req)); +} + +int iwm_send_umac_channel_list(struct iwm_priv *iwm) +{ + struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT; + struct iwm_umac_cmd umac_cmd; + struct iwm_umac_cmd_get_channel_list *ch_list; + int size = sizeof(struct iwm_umac_cmd_get_channel_list) + + sizeof(struct iwm_umac_channel_info) * 4; + int ret; + + ch_list = kzalloc(size, GFP_KERNEL); + if (!ch_list) { + IWM_ERR(iwm, "Couldn't allocate channel list cmd\n"); + return -ENOMEM; + } + + ch_list->ch[0].band = UMAC_BAND_2GHZ; + ch_list->ch[0].type = UMAC_CHANNEL_WIDTH_20MHZ; + ch_list->ch[0].flags = UMAC_CHANNEL_FLAG_VALID; + + ch_list->ch[1].band = UMAC_BAND_5GHZ; + ch_list->ch[1].type = UMAC_CHANNEL_WIDTH_20MHZ; + ch_list->ch[1].flags = UMAC_CHANNEL_FLAG_VALID; + + ch_list->ch[2].band = UMAC_BAND_2GHZ; + ch_list->ch[2].type = UMAC_CHANNEL_WIDTH_20MHZ; + ch_list->ch[2].flags = UMAC_CHANNEL_FLAG_VALID | UMAC_CHANNEL_FLAG_IBSS; + + ch_list->ch[3].band = UMAC_BAND_5GHZ; + ch_list->ch[3].type = UMAC_CHANNEL_WIDTH_20MHZ; + ch_list->ch[3].flags = UMAC_CHANNEL_FLAG_VALID | UMAC_CHANNEL_FLAG_IBSS; + + ch_list->count = cpu_to_le16(4); + + umac_cmd.id = UMAC_CMD_OPCODE_GET_CHAN_INFO_LIST; + umac_cmd.resp = 1; + + ret = iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, ch_list, size); + + kfree(ch_list); + + return ret; +} + +int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids, + int ssid_num) +{ + struct iwm_umac_cmd_scan_request req; + int i, ret; + + memset(&req, 0, sizeof(struct iwm_umac_cmd_scan_request)); + + req.hdr.oid = UMAC_WIFI_IF_CMD_SCAN_REQUEST; + req.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_cmd_scan_request) + - sizeof(struct iwm_umac_wifi_if)); + req.type = UMAC_WIFI_IF_SCAN_TYPE_USER; + req.timeout = 2; + req.seq_num = iwm->scan_id; + req.ssid_num = min(ssid_num, UMAC_WIFI_IF_PROBE_OPTION_MAX); + + for (i = 0; i < req.ssid_num; i++) { + memcpy(req.ssids[i].ssid, ssids[i].ssid, ssids[i].ssid_len); + req.ssids[i].ssid_len = ssids[i].ssid_len; + } + + ret = iwm_send_wifi_if_cmd(iwm, &req, sizeof(req), 0); + if (ret < 0) { + IWM_ERR(iwm, "Couldn't send scan request\n"); + return ret; + } + + iwm->scan_id = iwm->scan_id++ % IWM_SCAN_ID_MAX; + + return 0; +} + +int iwm_scan_one_ssid(struct iwm_priv *iwm, u8 *ssid, int ssid_len) +{ + struct cfg80211_ssid one_ssid; + + if (test_and_set_bit(IWM_STATUS_SCANNING, &iwm->status)) + return 0; + + one_ssid.ssid_len = min(ssid_len, IEEE80211_MAX_SSID_LEN); + memcpy(&one_ssid.ssid, ssid, one_ssid.ssid_len); + + return iwm_scan_ssids(iwm, &one_ssid, 1); +} + +int iwm_target_reset(struct iwm_priv *iwm) +{ + struct iwm_udma_nonwifi_cmd target_cmd; + + target_cmd.opcode = UMAC_HDI_OUT_OPCODE_REBOOT; + target_cmd.addr = 0; + target_cmd.op1_sz = 0; + target_cmd.op2 = 0; + target_cmd.handle_by_hw = 0; + target_cmd.resp = 0; + target_cmd.eop = 1; + + return iwm_hal_send_target_cmd(iwm, &target_cmd, NULL); +} diff --git a/drivers/net/wireless/iwmc3200wifi/commands.h b/drivers/net/wireless/iwmc3200wifi/commands.h new file mode 100644 index 000000000000..36b13a130595 --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/commands.h @@ -0,0 +1,419 @@ +/* + * Intel Wireless Multicomm 3200 WiFi driver + * + * Copyright (C) 2009 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * Intel Corporation + * Samuel Ortiz + * Zhu Yi + * + */ + +#ifndef __IWM_COMMANDS_H__ +#define __IWM_COMMANDS_H__ + +#include + +#define IWM_BARKER_REBOOT_NOTIFICATION 0xF +#define IWM_ACK_BARKER_NOTIFICATION 0x10 + +/* UMAC commands */ +#define UMAC_RST_CTRL_FLG_LARC_CLK_EN 0x0001 +#define UMAC_RST_CTRL_FLG_LARC_RESET 0x0002 +#define UMAC_RST_CTRL_FLG_FUNC_RESET 0x0004 +#define UMAC_RST_CTRL_FLG_DEV_RESET 0x0008 +#define UMAC_RST_CTRL_FLG_WIFI_CORE_EN 0x0010 +#define UMAC_RST_CTRL_FLG_WIFI_LINK_EN 0x0040 +#define UMAC_RST_CTRL_FLG_WIFI_MLME_EN 0x0080 +#define UMAC_RST_CTRL_FLG_NVM_RELOAD 0x0100 + +struct iwm_umac_cmd_reset { + __le32 flags; +} __attribute__ ((packed)); + +#define UMAC_PARAM_TBL_ORD_FIX 0x0 +#define UMAC_PARAM_TBL_ORD_VAR 0x1 +#define UMAC_PARAM_TBL_CFG_FIX 0x2 +#define UMAC_PARAM_TBL_CFG_VAR 0x3 +#define UMAC_PARAM_TBL_BSS_TRK 0x4 +#define UMAC_PARAM_TBL_FA_CFG_FIX 0x5 +#define UMAC_PARAM_TBL_STA 0x6 +#define UMAC_PARAM_TBL_CHN 0x7 +#define UMAC_PARAM_TBL_STATISTICS 0x8 + +/* fast access table */ +enum { + CFG_FRAG_THRESHOLD = 0, + CFG_FRAME_RETRY_LIMIT, + CFG_OS_QUEUE_UTIL_TH, + CFG_RX_FILTER, + /* <-- LAST --> */ + FAST_ACCESS_CFG_TBL_FIX_LAST +}; + +/* fixed size table */ +enum { + CFG_POWER_INDEX = 0, + CFG_PM_LEGACY_RX_TIMEOUT, + CFG_PM_LEGACY_TX_TIMEOUT, + CFG_PM_CTRL_FLAGS, + CFG_PM_KEEP_ALIVE_IN_BEACONS, + CFG_BT_ON_THRESHOLD, + CFG_RTS_THRESHOLD, + CFG_CTS_TO_SELF, + CFG_COEX_MODE, + CFG_WIRELESS_MODE, + CFG_ASSOCIATION_TIMEOUT, + CFG_ROAM_TIMEOUT, + CFG_CAPABILITY_SUPPORTED_RATES, + CFG_SCAN_ALLOWED_UNASSOC_FLAGS, + CFG_SCAN_ALLOWED_MAIN_ASSOC_FLAGS, + CFG_SCAN_ALLOWED_PAN_ASSOC_FLAGS, + CFG_SCAN_INTERNAL_PERIODIC_ENABLED, + CFG_SCAN_IMM_INTERNAL_PERIODIC_SCAN_ON_INIT, + CFG_SCAN_DEFAULT_PERIODIC_FREQ_SEC, + CFG_SCAN_NUM_PASSIVE_CHAN_PER_PARTIAL_SCAN, + CFG_TLC_SUPPORTED_TX_HT_RATES, + CFG_TLC_SUPPORTED_TX_RATES, + CFG_TLC_VALID_ANTENNA, + CFG_TLC_SPATIAL_STREAM_SUPPORTED, + CFG_TLC_RETRY_PER_RATE, + CFG_TLC_RETRY_PER_HT_RATE, + CFG_TLC_FIXED_RATE, + CFG_TLC_FIXED_RATE_FLAGS, + CFG_TLC_CONTROL_FLAGS, + CFG_TLC_SR_MIN_FAIL, + CFG_TLC_SR_MIN_PASS, + CFG_TLC_HT_STAY_IN_COL_PASS_THRESH, + CFG_TLC_HT_STAY_IN_COL_FAIL_THRESH, + CFG_TLC_LEGACY_STAY_IN_COL_PASS_THRESH, + CFG_TLC_LEGACY_STAY_IN_COL_FAIL_THRESH, + CFG_TLC_HT_FLUSH_STATS_PACKETS, + CFG_TLC_LEGACY_FLUSH_STATS_PACKETS, + CFG_TLC_LEGACY_FLUSH_STATS_MS, + CFG_TLC_HT_FLUSH_STATS_MS, + CFG_TLC_STAY_IN_COL_TIME_OUT, + CFG_TLC_AGG_SHORT_LIM, + CFG_TLC_AGG_LONG_LIM, + CFG_TLC_HT_SR_NO_DECREASE, + CFG_TLC_LEGACY_SR_NO_DECREASE, + CFG_TLC_SR_FORCE_DECREASE, + CFG_TLC_SR_ALLOW_INCREASE, + CFG_TLC_AGG_SET_LONG, + CFG_TLC_AUTO_AGGREGATION, + CFG_TLC_AGG_THRESHOLD, + CFG_TLC_TID_LOAD_THRESHOLD, + CFG_TLC_BLOCK_ACK_TIMEOUT, + CFG_TLC_NO_BA_COUNTED_AS_ONE, + CFG_TLC_NUM_BA_STREAMS_ALLOWED, + CFG_TLC_NUM_BA_STREAMS_PRESENT, + CFG_TLC_RENEW_ADDBA_DELAY, + CFG_TLC_NUM_OF_MULTISEC_TO_COUN_LOAD, + CFG_TLC_IS_STABLE_IN_HT, + CFG_RLC_CHAIN_CTRL, + CFG_TRK_TABLE_OP_MODE, + CFG_TRK_TABLE_RSSI_THRESHOLD, + CFG_TX_PWR_TARGET, /* Used By xVT */ + CFG_TX_PWR_LIMIT_USR, + CFG_TX_PWR_LIMIT_BSS, /* 11d limit */ + CFG_TX_PWR_LIMIT_BSS_CONSTRAINT, /* 11h constraint */ + CFG_TX_PWR_MODE, + CFG_MLME_DBG_NOTIF_BLOCK, + CFG_BT_OFF_BECONS_INTERVALS, + CFG_BT_FRAG_DURATION, + + /* <-- LAST --> */ + CFG_TBL_FIX_LAST +}; + +/* variable size table */ +enum { + CFG_NET_ADDR = 0, + CFG_PROFILE, + /* <-- LAST --> */ + CFG_TBL_VAR_LAST +}; + +struct iwm_umac_cmd_set_param_fix { + __le16 tbl; + __le16 key; + __le32 value; +} __attribute__ ((packed)); + +struct iwm_umac_cmd_set_param_var { + __le16 tbl; + __le16 key; + __le16 len; + __le16 reserved; +} __attribute__ ((packed)); + +struct iwm_umac_cmd_get_param { + __le16 tbl; + __le16 key; +} __attribute__ ((packed)); + +struct iwm_umac_cmd_get_param_resp { + __le16 tbl; + __le16 key; + __le16 len; + __le16 reserved; +} __attribute__ ((packed)); + +struct iwm_umac_cmd_eeprom_proxy_hdr { + __le32 type; + __le32 offset; + __le32 len; +} __attribute__ ((packed)); + +struct iwm_umac_cmd_eeprom_proxy { + struct iwm_umac_cmd_eeprom_proxy_hdr hdr; + u8 buf[0]; +} __attribute__ ((packed)); + +#define IWM_UMAC_CMD_EEPROM_TYPE_READ 0x1 +#define IWM_UMAC_CMD_EEPROM_TYPE_WRITE 0x2 + +#define UMAC_CHANNEL_FLAG_VALID BIT(0) +#define UMAC_CHANNEL_FLAG_IBSS BIT(1) +#define UMAC_CHANNEL_FLAG_ACTIVE BIT(3) +#define UMAC_CHANNEL_FLAG_RADAR BIT(4) +#define UMAC_CHANNEL_FLAG_DFS BIT(7) + +struct iwm_umac_channel_info { + u8 band; + u8 type; + u8 reserved; + u8 flags; + __le32 channels_mask; +} __attribute__ ((packed)); + +struct iwm_umac_cmd_get_channel_list { + __le16 count; + __le16 reserved; + struct iwm_umac_channel_info ch[0]; +} __attribute__ ((packed)); + + +/* UMAC WiFi interface commands */ + +/* Coexistence mode */ +#define COEX_MODE_SA 0x1 +#define COEX_MODE_XOR 0x2 +#define COEX_MODE_CM 0x3 +#define COEX_MODE_MAX 0x4 + +/* Wireless mode */ +#define WIRELESS_MODE_11A 0x1 +#define WIRELESS_MODE_11G 0x2 + +#define UMAC_PROFILE_EX_IE_REQUIRED 0x1 +#define UMAC_PROFILE_QOS_ALLOWED 0x2 + +/* Scanning */ +#define UMAC_WIFI_IF_PROBE_OPTION_MAX 10 + +#define UMAC_WIFI_IF_SCAN_TYPE_USER 0x0 +#define UMAC_WIFI_IF_SCAN_TYPE_UMAC_RESERVED 0x1 +#define UMAC_WIFI_IF_SCAN_TYPE_HOST_PERIODIC 0x2 +#define UMAC_WIFI_IF_SCAN_TYPE_MAX 0x3 + +struct iwm_umac_ssid { + u8 ssid_len; + u8 ssid[IEEE80211_MAX_SSID_LEN]; + u8 reserved[3]; +} __attribute__ ((packed)); + +struct iwm_umac_cmd_scan_request { + struct iwm_umac_wifi_if hdr; + __le32 type; /* UMAC_WIFI_IF_SCAN_TYPE_* */ + u8 ssid_num; + u8 seq_num; + u8 timeout; /* In seconds */ + u8 reserved; + struct iwm_umac_ssid ssids[UMAC_WIFI_IF_PROBE_OPTION_MAX]; +} __attribute__ ((packed)); + +#define UMAC_CIPHER_TYPE_NONE 0xFF +#define UMAC_CIPHER_TYPE_USE_GROUPCAST 0x00 +#define UMAC_CIPHER_TYPE_WEP_40 0x01 +#define UMAC_CIPHER_TYPE_WEP_104 0x02 +#define UMAC_CIPHER_TYPE_TKIP 0x04 +#define UMAC_CIPHER_TYPE_CCMP 0x08 + +/* Supported authentication types - bitmap */ +#define UMAC_AUTH_TYPE_OPEN 0x00 +#define UMAC_AUTH_TYPE_LEGACY_PSK 0x01 +#define UMAC_AUTH_TYPE_8021X 0x02 +#define UMAC_AUTH_TYPE_RSNA_PSK 0x04 + +/* iwm_umac_security.flag is WPA supported -- bits[0:0] */ +#define UMAC_SEC_FLG_WPA_ON_POS 0 +#define UMAC_SEC_FLG_WPA_ON_SEED 1 +#define UMAC_SEC_FLG_WPA_ON_MSK (UMAC_SEC_FLG_WPA_ON_SEED << \ + UMAC_SEC_FLG_WPA_ON_POS) + +/* iwm_umac_security.flag is WPA2 supported -- bits [1:1] */ +#define UMAC_SEC_FLG_RSNA_ON_POS 1 +#define UMAC_SEC_FLG_RSNA_ON_SEED 1 +#define UMAC_SEC_FLG_RSNA_ON_MSK (UMAC_SEC_FLG_RSNA_ON_SEED << \ + UMAC_SEC_FLG_RSNA_ON_POS) + +/* iwm_umac_security.flag is WSC mode on -- bits [2:2] */ +#define UMAC_SEC_FLG_WSC_ON_POS 2 +#define UMAC_SEC_FLG_WSC_ON_SEED 1 + +/* Legacy profile can use only WEP40 and WEP104 for encryption and + * OPEN or PSK for authentication */ +#define UMAC_SEC_FLG_LEGACY_PROFILE 0 + +struct iwm_umac_security { + u8 auth_type; + u8 ucast_cipher; + u8 mcast_cipher; + u8 flags; +} __attribute__ ((packed)); + +struct iwm_umac_ibss { + u8 beacon_interval; /* in millisecond */ + u8 atim; /* in millisecond */ + s8 join_only; + u8 band; + u8 channel; + u8 reserved[3]; +} __attribute__ ((packed)); + +#define UMAC_MODE_BSS 0 +#define UMAC_MODE_IBSS 1 + +#define UMAC_BSSID_MAX 4 + +struct iwm_umac_profile { + struct iwm_umac_wifi_if hdr; + __le32 mode; + struct iwm_umac_ssid ssid; + u8 bssid[UMAC_BSSID_MAX][ETH_ALEN]; + struct iwm_umac_security sec; + struct iwm_umac_ibss ibss; + __le32 channel_2ghz; + __le32 channel_5ghz; + __le16 flags; + u8 wireless_mode; + u8 bss_num; +} __attribute__ ((packed)); + +struct iwm_umac_invalidate_profile { + struct iwm_umac_wifi_if hdr; + u8 reason; + u8 reserved[3]; +} __attribute__ ((packed)); + +/* Encryption key commands */ +struct iwm_umac_key_wep40 { + struct iwm_umac_wifi_if hdr; + struct iwm_umac_key_hdr key_hdr; + u8 key[WLAN_KEY_LEN_WEP40]; + u8 static_key; + u8 reserved[2]; +} __attribute__ ((packed)); + +struct iwm_umac_key_wep104 { + struct iwm_umac_wifi_if hdr; + struct iwm_umac_key_hdr key_hdr; + u8 key[WLAN_KEY_LEN_WEP104]; + u8 static_key; + u8 reserved[2]; +} __attribute__ ((packed)); + +#define IWM_TKIP_KEY_SIZE 16 +#define IWM_TKIP_MIC_SIZE 8 +struct iwm_umac_key_tkip { + struct iwm_umac_wifi_if hdr; + struct iwm_umac_key_hdr key_hdr; + u8 iv_count[6]; + u8 reserved[2]; + u8 tkip_key[IWM_TKIP_KEY_SIZE]; + u8 mic_rx_key[IWM_TKIP_MIC_SIZE]; + u8 mic_tx_key[IWM_TKIP_MIC_SIZE]; +} __attribute__ ((packed)); + +struct iwm_umac_key_ccmp { + struct iwm_umac_wifi_if hdr; + struct iwm_umac_key_hdr key_hdr; + u8 iv_count[6]; + u8 reserved[2]; + u8 key[WLAN_KEY_LEN_CCMP]; +} __attribute__ ((packed)); + +struct iwm_umac_key_remove { + struct iwm_umac_wifi_if hdr; + struct iwm_umac_key_hdr key_hdr; +} __attribute__ ((packed)); + +struct iwm_umac_tx_key_id { + struct iwm_umac_wifi_if hdr; + u8 key_idx; + u8 reserved[3]; +} __attribute__ ((packed)); + +struct iwm_umac_cmd_stats_req { + __le32 flags; +} __attribute__ ((packed)); + +/* LMAC commands */ +int iwm_read_mac(struct iwm_priv *iwm, u8 *mac); +int iwm_send_prio_table(struct iwm_priv *iwm); +int iwm_send_init_calib_cfg(struct iwm_priv *iwm, u8 calib_requested); +int iwm_send_periodic_calib_cfg(struct iwm_priv *iwm, u8 calib_requested); +int iwm_send_calib_results(struct iwm_priv *iwm); +int iwm_store_rxiq_calib_result(struct iwm_priv *iwm); + +/* UMAC commands */ +int iwm_send_wifi_if_cmd(struct iwm_priv *iwm, void *payload, u16 payload_size, + bool resp); +int iwm_send_umac_reset(struct iwm_priv *iwm, __le32 reset_flags, bool resp); +int iwm_umac_set_config_fix(struct iwm_priv *iwm, u16 tbl, u16 key, u32 value); +int iwm_umac_set_config_var(struct iwm_priv *iwm, u16 key, + void *payload, u16 payload_size); +int iwm_send_umac_config(struct iwm_priv *iwm, __le32 reset_flags); +int iwm_send_mlme_profile(struct iwm_priv *iwm); +int iwm_invalidate_mlme_profile(struct iwm_priv *iwm); +int iwm_send_packet(struct iwm_priv *iwm, struct sk_buff *skb, int pool_id); +int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx); +int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key, + struct iwm_key *key); +int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags); +int iwm_send_umac_channel_list(struct iwm_priv *iwm); +int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids, + int ssid_num); +int iwm_scan_one_ssid(struct iwm_priv *iwm, u8 *ssid, int ssid_len); + +/* UDMA commands */ +int iwm_target_reset(struct iwm_priv *iwm); +#endif diff --git a/drivers/net/wireless/iwmc3200wifi/debug.h b/drivers/net/wireless/iwmc3200wifi/debug.h new file mode 100644 index 000000000000..8fbb42d9c21f --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/debug.h @@ -0,0 +1,124 @@ +/* + * Intel Wireless Multicomm 3200 WiFi driver + * + * Copyright (C) 2009 Intel Corporation + * Samuel Ortiz + * Zhu Yi + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#ifndef __IWM_DEBUG_H__ +#define __IWM_DEBUG_H__ + +#define IWM_ERR(p, f, a...) dev_err(iwm_to_dev(p), f, ## a) +#define IWM_WARN(p, f, a...) dev_warn(iwm_to_dev(p), f, ## a) +#define IWM_INFO(p, f, a...) dev_info(iwm_to_dev(p), f, ## a) +#define IWM_CRIT(p, f, a...) dev_crit(iwm_to_dev(p), f, ## a) + +#ifdef CONFIG_IWM_DEBUG + +#define IWM_DEBUG_MODULE(i, level, module, f, a...) \ +do { \ + if (unlikely(i->dbg.dbg_module[IWM_DM_##module] >= (IWM_DL_##level)))\ + dev_printk(KERN_INFO, (iwm_to_dev(i)), \ + "%s " f, __func__ , ## a); \ +} while (0) + +#define IWM_HEXDUMP(i, level, module, pref, buf, len) \ +do { \ + if (unlikely(i->dbg.dbg_module[IWM_DM_##module] >= (IWM_DL_##level)))\ + print_hex_dump(KERN_INFO, pref, DUMP_PREFIX_OFFSET, \ + 16, 1, buf, len, 1); \ +} while (0) + +#else + +#define IWM_DEBUG_MODULE(i, level, module, f, a...) +#define IWM_HEXDUMP(i, level, module, pref, buf, len) + +#endif /* CONFIG_IWM_DEBUG */ + +/* Debug modules */ +enum iwm_debug_module_id { + IWM_DM_BOOT = 0, + IWM_DM_FW, + IWM_DM_SDIO, + IWM_DM_NTF, + IWM_DM_RX, + IWM_DM_TX, + IWM_DM_MLME, + IWM_DM_CMD, + IWM_DM_WEXT, + __IWM_DM_NR, +}; +#define IWM_DM_DEFAULT 0 + +#define IWM_DBG_BOOT(i, l, f, a...) IWM_DEBUG_MODULE(i, l, BOOT, f, ## a) +#define IWM_DBG_FW(i, l, f, a...) IWM_DEBUG_MODULE(i, l, FW, f, ## a) +#define IWM_DBG_SDIO(i, l, f, a...) IWM_DEBUG_MODULE(i, l, SDIO, f, ## a) +#define IWM_DBG_NTF(i, l, f, a...) IWM_DEBUG_MODULE(i, l, NTF, f, ## a) +#define IWM_DBG_RX(i, l, f, a...) IWM_DEBUG_MODULE(i, l, RX, f, ## a) +#define IWM_DBG_TX(i, l, f, a...) IWM_DEBUG_MODULE(i, l, TX, f, ## a) +#define IWM_DBG_MLME(i, l, f, a...) IWM_DEBUG_MODULE(i, l, MLME, f, ## a) +#define IWM_DBG_CMD(i, l, f, a...) IWM_DEBUG_MODULE(i, l, CMD, f, ## a) +#define IWM_DBG_WEXT(i, l, f, a...) IWM_DEBUG_MODULE(i, l, WEXT, f, ## a) + +/* Debug levels */ +enum iwm_debug_level { + IWM_DL_NONE = 0, + IWM_DL_ERR, + IWM_DL_WARN, + IWM_DL_INFO, + IWM_DL_DBG, +}; +#define IWM_DL_DEFAULT IWM_DL_ERR + +struct iwm_debugfs { + struct iwm_priv *iwm; + struct dentry *rootdir; + struct dentry *devdir; + struct dentry *dbgdir; + struct dentry *txdir; + struct dentry *rxdir; + struct dentry *busdir; + + u32 dbg_level; + struct dentry *dbg_level_dentry; + + unsigned long dbg_modules; + struct dentry *dbg_modules_dentry; + + u8 dbg_module[__IWM_DM_NR]; + struct dentry *dbg_module_dentries[__IWM_DM_NR]; + + struct dentry *txq_dentry; + struct dentry *tx_credit_dentry; + struct dentry *rx_ticket_dentry; +}; + +#ifdef CONFIG_IWM_DEBUG +int iwm_debugfs_init(struct iwm_priv *iwm); +void iwm_debugfs_exit(struct iwm_priv *iwm); +#else +static inline int iwm_debugfs_init(struct iwm_priv *iwm) +{ + return 0; +} +static inline void iwm_debugfs_exit(struct iwm_priv *iwm) {} +#endif + +#endif diff --git a/drivers/net/wireless/iwmc3200wifi/debugfs.c b/drivers/net/wireless/iwmc3200wifi/debugfs.c new file mode 100644 index 000000000000..0fa7b9150d58 --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/debugfs.c @@ -0,0 +1,453 @@ +/* + * Intel Wireless Multicomm 3200 WiFi driver + * + * Copyright (C) 2009 Intel Corporation + * Samuel Ortiz + * Zhu Yi + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#include +#include +#include + +#include "iwm.h" +#include "bus.h" +#include "rx.h" +#include "debug.h" + +static struct { + u8 id; + char *name; +} iwm_debug_module[__IWM_DM_NR] = { + {IWM_DM_BOOT, "boot"}, + {IWM_DM_FW, "fw"}, + {IWM_DM_SDIO, "sdio"}, + {IWM_DM_NTF, "ntf"}, + {IWM_DM_RX, "rx"}, + {IWM_DM_TX, "tx"}, + {IWM_DM_MLME, "mlme"}, + {IWM_DM_CMD, "cmd"}, + {IWM_DM_WEXT, "wext"}, +}; + +#define add_dbg_module(dbg, name, id, initlevel) \ +do { \ + struct dentry *d; \ + dbg.dbg_module[id] = (initlevel); \ + d = debugfs_create_x8(name, 0600, dbg.dbgdir, \ + &(dbg.dbg_module[id])); \ + if (!IS_ERR(d)) \ + dbg.dbg_module_dentries[id] = d; \ +} while (0) + +static int iwm_debugfs_u32_read(void *data, u64 *val) +{ + struct iwm_priv *iwm = data; + + *val = iwm->dbg.dbg_level; + return 0; +} + +static int iwm_debugfs_dbg_level_write(void *data, u64 val) +{ + struct iwm_priv *iwm = data; + int i; + + iwm->dbg.dbg_level = val; + + for (i = 0; i < __IWM_DM_NR; i++) + iwm->dbg.dbg_module[i] = val; + + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(fops_iwm_dbg_level, + iwm_debugfs_u32_read, iwm_debugfs_dbg_level_write, + "%llu\n"); + +static int iwm_debugfs_dbg_modules_write(void *data, u64 val) +{ + struct iwm_priv *iwm = data; + int i, bit; + + iwm->dbg.dbg_modules = val; + + for (i = 0; i < __IWM_DM_NR; i++) + iwm->dbg.dbg_module[i] = 0; + + for_each_bit(bit, &iwm->dbg.dbg_modules, __IWM_DM_NR) + iwm->dbg.dbg_module[bit] = iwm->dbg.dbg_level; + + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(fops_iwm_dbg_modules, + iwm_debugfs_u32_read, iwm_debugfs_dbg_modules_write, + "%llu\n"); + +static int iwm_txrx_open(struct inode *inode, struct file *filp) +{ + filp->private_data = inode->i_private; + return 0; +} + + +static ssize_t iwm_debugfs_txq_read(struct file *filp, char __user *buffer, + size_t count, loff_t *ppos) +{ + struct iwm_priv *iwm = filp->private_data; + char *buf; + int i, buf_len = 4096; + size_t len = 0; + ssize_t ret; + + if (*ppos != 0) + return 0; + if (count < sizeof(buf)) + return -ENOSPC; + + buf = kzalloc(buf_len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + for (i = 0; i < IWM_TX_QUEUES; i++) { + struct iwm_tx_queue *txq = &iwm->txq[i]; + struct sk_buff *skb; + int j; + unsigned long flags; + + spin_lock_irqsave(&txq->queue.lock, flags); + + skb = (struct sk_buff *)&txq->queue; + + len += snprintf(buf + len, buf_len - len, "TXQ #%d\n", i); + len += snprintf(buf + len, buf_len - len, "\tStopped: %d\n", + __netif_subqueue_stopped(iwm_to_ndev(iwm), + txq->id)); + len += snprintf(buf + len, buf_len - len, "\tConcat count:%d\n", + txq->concat_count); + len += snprintf(buf + len, buf_len - len, "\tQueue len: %d\n", + skb_queue_len(&txq->queue)); + for (j = 0; j < skb_queue_len(&txq->queue); j++) { + struct iwm_tx_info *tx_info; + + skb = skb->next; + tx_info = skb_to_tx_info(skb); + + len += snprintf(buf + len, buf_len - len, + "\tSKB #%d\n", j); + len += snprintf(buf + len, buf_len - len, + "\t\tsta: %d\n", tx_info->sta); + len += snprintf(buf + len, buf_len - len, + "\t\tcolor: %d\n", tx_info->color); + len += snprintf(buf + len, buf_len - len, + "\t\ttid: %d\n", tx_info->tid); + } + + spin_unlock_irqrestore(&txq->queue.lock, flags); + } + + ret = simple_read_from_buffer(buffer, len, ppos, buf, buf_len); + kfree(buf); + + return ret; +} + +static ssize_t iwm_debugfs_tx_credit_read(struct file *filp, + char __user *buffer, + size_t count, loff_t *ppos) +{ + struct iwm_priv *iwm = filp->private_data; + struct iwm_tx_credit *credit = &iwm->tx_credit; + char *buf; + int i, buf_len = 4096; + size_t len = 0; + ssize_t ret; + + if (*ppos != 0) + return 0; + if (count < sizeof(buf)) + return -ENOSPC; + + buf = kzalloc(buf_len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + len += snprintf(buf + len, buf_len - len, + "NR pools: %d\n", credit->pool_nr); + len += snprintf(buf + len, buf_len - len, + "pools map: 0x%lx\n", credit->full_pools_map); + + len += snprintf(buf + len, buf_len - len, "\n### POOLS ###\n"); + for (i = 0; i < IWM_MACS_OUT_GROUPS; i++) { + len += snprintf(buf + len, buf_len - len, + "pools entry #%d\n", i); + len += snprintf(buf + len, buf_len - len, + "\tid: %d\n", + credit->pools[i].id); + len += snprintf(buf + len, buf_len - len, + "\tsid: %d\n", + credit->pools[i].sid); + len += snprintf(buf + len, buf_len - len, + "\tmin_pages: %d\n", + credit->pools[i].min_pages); + len += snprintf(buf + len, buf_len - len, + "\tmax_pages: %d\n", + credit->pools[i].max_pages); + len += snprintf(buf + len, buf_len - len, + "\talloc_pages: %d\n", + credit->pools[i].alloc_pages); + len += snprintf(buf + len, buf_len - len, + "\tfreed_pages: %d\n", + credit->pools[i].total_freed_pages); + } + + len += snprintf(buf + len, buf_len - len, "\n### SPOOLS ###\n"); + for (i = 0; i < IWM_MACS_OUT_SGROUPS; i++) { + len += snprintf(buf + len, buf_len - len, + "spools entry #%d\n", i); + len += snprintf(buf + len, buf_len - len, + "\tid: %d\n", + credit->spools[i].id); + len += snprintf(buf + len, buf_len - len, + "\tmax_pages: %d\n", + credit->spools[i].max_pages); + len += snprintf(buf + len, buf_len - len, + "\talloc_pages: %d\n", + credit->spools[i].alloc_pages); + + } + + ret = simple_read_from_buffer(buffer, len, ppos, buf, buf_len); + kfree(buf); + + return ret; +} + +static ssize_t iwm_debugfs_rx_ticket_read(struct file *filp, + char __user *buffer, + size_t count, loff_t *ppos) +{ + struct iwm_priv *iwm = filp->private_data; + struct iwm_rx_ticket_node *ticket, *next; + char *buf; + int buf_len = 4096, i; + size_t len = 0; + ssize_t ret; + + if (*ppos != 0) + return 0; + if (count < sizeof(buf)) + return -ENOSPC; + + buf = kzalloc(buf_len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + list_for_each_entry_safe(ticket, next, &iwm->rx_tickets, node) { + len += snprintf(buf + len, buf_len - len, "Ticket #%d\n", + ticket->ticket->id); + len += snprintf(buf + len, buf_len - len, "\taction: 0x%x\n", + ticket->ticket->action); + len += snprintf(buf + len, buf_len - len, "\tflags: 0x%x\n", + ticket->ticket->flags); + } + + for (i = 0; i < IWM_RX_ID_HASH; i++) { + struct iwm_rx_packet *packet, *nxt; + struct list_head *pkt_list = &iwm->rx_packets[i]; + if (!list_empty(pkt_list)) { + len += snprintf(buf + len, buf_len - len, + "Packet hash #%d\n", i); + list_for_each_entry_safe(packet, nxt, pkt_list, node) { + len += snprintf(buf + len, buf_len - len, + "\tPacket id: %d\n", + packet->id); + len += snprintf(buf + len, buf_len - len, + "\tPacket length: %lu\n", + packet->pkt_size); + } + } + } + + ret = simple_read_from_buffer(buffer, len, ppos, buf, buf_len); + kfree(buf); + + return ret; +} + + +static const struct file_operations iwm_debugfs_txq_fops = { + .owner = THIS_MODULE, + .open = iwm_txrx_open, + .read = iwm_debugfs_txq_read, +}; + +static const struct file_operations iwm_debugfs_tx_credit_fops = { + .owner = THIS_MODULE, + .open = iwm_txrx_open, + .read = iwm_debugfs_tx_credit_read, +}; + +static const struct file_operations iwm_debugfs_rx_ticket_fops = { + .owner = THIS_MODULE, + .open = iwm_txrx_open, + .read = iwm_debugfs_rx_ticket_read, +}; + +int iwm_debugfs_init(struct iwm_priv *iwm) +{ + int i, result; + char devdir[16]; + + iwm->dbg.rootdir = debugfs_create_dir(KBUILD_MODNAME, NULL); + result = PTR_ERR(iwm->dbg.rootdir); + if (!result || IS_ERR(iwm->dbg.rootdir)) { + if (result == -ENODEV) { + IWM_ERR(iwm, "DebugFS (CONFIG_DEBUG_FS) not " + "enabled in kernel config\n"); + result = 0; /* No debugfs support */ + } + IWM_ERR(iwm, "Couldn't create rootdir: %d\n", result); + goto error; + } + + snprintf(devdir, sizeof(devdir), "%s", wiphy_name(iwm_to_wiphy(iwm))); + + iwm->dbg.devdir = debugfs_create_dir(devdir, iwm->dbg.rootdir); + result = PTR_ERR(iwm->dbg.devdir); + if (IS_ERR(iwm->dbg.devdir) && (result != -ENODEV)) { + IWM_ERR(iwm, "Couldn't create devdir: %d\n", result); + goto error; + } + + iwm->dbg.dbgdir = debugfs_create_dir("debug", iwm->dbg.devdir); + result = PTR_ERR(iwm->dbg.dbgdir); + if (IS_ERR(iwm->dbg.dbgdir) && (result != -ENODEV)) { + IWM_ERR(iwm, "Couldn't create dbgdir: %d\n", result); + goto error; + } + + iwm->dbg.rxdir = debugfs_create_dir("rx", iwm->dbg.devdir); + result = PTR_ERR(iwm->dbg.rxdir); + if (IS_ERR(iwm->dbg.rxdir) && (result != -ENODEV)) { + IWM_ERR(iwm, "Couldn't create rx dir: %d\n", result); + goto error; + } + + iwm->dbg.txdir = debugfs_create_dir("tx", iwm->dbg.devdir); + result = PTR_ERR(iwm->dbg.txdir); + if (IS_ERR(iwm->dbg.txdir) && (result != -ENODEV)) { + IWM_ERR(iwm, "Couldn't create tx dir: %d\n", result); + goto error; + } + + iwm->dbg.busdir = debugfs_create_dir("bus", iwm->dbg.devdir); + result = PTR_ERR(iwm->dbg.busdir); + if (IS_ERR(iwm->dbg.busdir) && (result != -ENODEV)) { + IWM_ERR(iwm, "Couldn't create bus dir: %d\n", result); + goto error; + } + + if (iwm->bus_ops->debugfs_init) { + result = iwm->bus_ops->debugfs_init(iwm, iwm->dbg.busdir); + if (result < 0) { + IWM_ERR(iwm, "Couldn't create bus entry: %d\n", result); + goto error; + } + } + + + iwm->dbg.dbg_level = IWM_DL_NONE; + iwm->dbg.dbg_level_dentry = + debugfs_create_file("level", 0200, iwm->dbg.dbgdir, iwm, + &fops_iwm_dbg_level); + result = PTR_ERR(iwm->dbg.dbg_level_dentry); + if (IS_ERR(iwm->dbg.dbg_level_dentry) && (result != -ENODEV)) { + IWM_ERR(iwm, "Couldn't create dbg_level: %d\n", result); + goto error; + } + + + iwm->dbg.dbg_modules = IWM_DM_DEFAULT; + iwm->dbg.dbg_modules_dentry = + debugfs_create_file("modules", 0200, iwm->dbg.dbgdir, iwm, + &fops_iwm_dbg_modules); + result = PTR_ERR(iwm->dbg.dbg_modules_dentry); + if (IS_ERR(iwm->dbg.dbg_modules_dentry) && (result != -ENODEV)) { + IWM_ERR(iwm, "Couldn't create dbg_modules: %d\n", result); + goto error; + } + + for (i = 0; i < __IWM_DM_NR; i++) + add_dbg_module(iwm->dbg, iwm_debug_module[i].name, + iwm_debug_module[i].id, IWM_DL_DEFAULT); + + iwm->dbg.txq_dentry = debugfs_create_file("queues", 0200, + iwm->dbg.txdir, iwm, + &iwm_debugfs_txq_fops); + result = PTR_ERR(iwm->dbg.txq_dentry); + if (IS_ERR(iwm->dbg.txq_dentry) && (result != -ENODEV)) { + IWM_ERR(iwm, "Couldn't create tx queue: %d\n", result); + goto error; + } + + iwm->dbg.tx_credit_dentry = debugfs_create_file("credits", 0200, + iwm->dbg.txdir, iwm, + &iwm_debugfs_tx_credit_fops); + result = PTR_ERR(iwm->dbg.tx_credit_dentry); + if (IS_ERR(iwm->dbg.tx_credit_dentry) && (result != -ENODEV)) { + IWM_ERR(iwm, "Couldn't create tx credit: %d\n", result); + goto error; + } + + iwm->dbg.rx_ticket_dentry = debugfs_create_file("tickets", 0200, + iwm->dbg.rxdir, iwm, + &iwm_debugfs_rx_ticket_fops); + result = PTR_ERR(iwm->dbg.rx_ticket_dentry); + if (IS_ERR(iwm->dbg.rx_ticket_dentry) && (result != -ENODEV)) { + IWM_ERR(iwm, "Couldn't create rx ticket: %d\n", result); + goto error; + } + + return 0; + + error: + return result; +} + +void iwm_debugfs_exit(struct iwm_priv *iwm) +{ + int i; + + for (i = 0; i < __IWM_DM_NR; i++) + debugfs_remove(iwm->dbg.dbg_module_dentries[i]); + + debugfs_remove(iwm->dbg.dbg_modules_dentry); + debugfs_remove(iwm->dbg.dbg_level_dentry); + debugfs_remove(iwm->dbg.txq_dentry); + debugfs_remove(iwm->dbg.tx_credit_dentry); + debugfs_remove(iwm->dbg.rx_ticket_dentry); + if (iwm->bus_ops->debugfs_exit) + iwm->bus_ops->debugfs_exit(iwm); + + debugfs_remove(iwm->dbg.busdir); + debugfs_remove(iwm->dbg.dbgdir); + debugfs_remove(iwm->dbg.txdir); + debugfs_remove(iwm->dbg.rxdir); + debugfs_remove(iwm->dbg.devdir); + debugfs_remove(iwm->dbg.rootdir); +} diff --git a/drivers/net/wireless/iwmc3200wifi/eeprom.c b/drivers/net/wireless/iwmc3200wifi/eeprom.c new file mode 100644 index 000000000000..0f34b84fd2eb --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/eeprom.c @@ -0,0 +1,187 @@ +/* + * Intel Wireless Multicomm 3200 WiFi driver + * + * Copyright (C) 2009 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * Intel Corporation + * Samuel Ortiz + * Zhu Yi + * + */ + +#include + +#include "iwm.h" +#include "umac.h" +#include "commands.h" +#include "eeprom.h" + +static struct iwm_eeprom_entry eeprom_map[] = { + [IWM_EEPROM_SIG] = + {"Signature", IWM_EEPROM_SIG_OFF, IWM_EEPROM_SIG_LEN}, + + [IWM_EEPROM_VERSION] = + {"Version", IWM_EEPROM_VERSION_OFF, IWM_EEPROM_VERSION_LEN}, + + [IWM_EEPROM_OEM_HW_VERSION] = + {"OEM HW version", IWM_EEPROM_OEM_HW_VERSION_OFF, + IWM_EEPROM_OEM_HW_VERSION_LEN}, + + [IWM_EEPROM_MAC_VERSION] = + {"MAC version", IWM_EEPROM_MAC_VERSION_OFF, IWM_EEPROM_MAC_VERSION_LEN}, + + [IWM_EEPROM_CARD_ID] = + {"Card ID", IWM_EEPROM_CARD_ID_OFF, IWM_EEPROM_CARD_ID_LEN}, + + [IWM_EEPROM_RADIO_CONF] = + {"Radio config", IWM_EEPROM_RADIO_CONF_OFF, IWM_EEPROM_RADIO_CONF_LEN}, + + [IWM_EEPROM_SKU_CAP] = + {"SKU capabilities", IWM_EEPROM_SKU_CAP_OFF, IWM_EEPROM_SKU_CAP_LEN}, + + [IWM_EEPROM_CALIB_RXIQ_OFFSET] = + {"RX IQ offset", IWM_EEPROM_CALIB_RXIQ_OFF, IWM_EEPROM_INDIRECT_LEN}, + + [IWM_EEPROM_CALIB_RXIQ] = + {"Calib RX IQ", 0, IWM_EEPROM_CALIB_RXIQ_LEN}, +}; + + +static int iwm_eeprom_read(struct iwm_priv *iwm, u8 eeprom_id) +{ + int ret; + u32 entry_size, chunk_size, data_offset = 0, addr_offset = 0; + u32 addr; + struct iwm_udma_wifi_cmd udma_cmd; + struct iwm_umac_cmd umac_cmd; + struct iwm_umac_cmd_eeprom_proxy eeprom_cmd; + + if (eeprom_id > (IWM_EEPROM_LAST - 1)) + return -EINVAL; + + entry_size = eeprom_map[eeprom_id].length; + + if (eeprom_id >= IWM_EEPROM_INDIRECT_DATA) { + /* indirect data */ + u32 off_id = eeprom_id - IWM_EEPROM_INDIRECT_DATA + + IWM_EEPROM_INDIRECT_OFFSET; + + eeprom_map[eeprom_id].offset = + *(u16 *)(iwm->eeprom + eeprom_map[off_id].offset) << 1; + } + + addr = eeprom_map[eeprom_id].offset; + + udma_cmd.eop = 1; + udma_cmd.credit_group = 0x4; + udma_cmd.ra_tid = UMAC_HDI_ACT_TBL_IDX_HOST_CMD; + udma_cmd.lmac_offset = 0; + + umac_cmd.id = UMAC_CMD_OPCODE_EEPROM_PROXY; + umac_cmd.resp = 1; + + while (entry_size > 0) { + chunk_size = min_t(u32, entry_size, IWM_MAX_EEPROM_DATA_LEN); + + eeprom_cmd.hdr.type = + cpu_to_le32(IWM_UMAC_CMD_EEPROM_TYPE_READ); + eeprom_cmd.hdr.offset = cpu_to_le32(addr + addr_offset); + eeprom_cmd.hdr.len = cpu_to_le32(chunk_size); + + ret = iwm_hal_send_umac_cmd(iwm, &udma_cmd, + &umac_cmd, &eeprom_cmd, + sizeof(struct iwm_umac_cmd_eeprom_proxy)); + if (ret < 0) { + IWM_ERR(iwm, "Couldn't read eeprom\n"); + return ret; + } + + ret = iwm_notif_handle(iwm, UMAC_CMD_OPCODE_EEPROM_PROXY, + IWM_SRC_UMAC, 2*HZ); + if (ret < 0) { + IWM_ERR(iwm, "Did not get any eeprom answer\n"); + return ret; + } + + data_offset += chunk_size; + addr_offset += chunk_size; + entry_size -= chunk_size; + } + + return 0; +} + +u8 *iwm_eeprom_access(struct iwm_priv *iwm, u8 eeprom_id) +{ + if (!iwm->eeprom) + return ERR_PTR(-ENODEV); + + return iwm->eeprom + eeprom_map[eeprom_id].offset; +} + +int iwm_eeprom_init(struct iwm_priv *iwm) +{ + int i, ret = 0; + char name[32]; + + iwm->eeprom = kzalloc(IWM_EEPROM_LEN, GFP_KERNEL); + if (!iwm->eeprom) + return -ENOMEM; + + for (i = IWM_EEPROM_FIRST; i < IWM_EEPROM_LAST; i++) { +#ifdef CONFIG_IWM_B0_HW_SUPPORT + if (iwm->conf.hw_b0 && (i >= IWM_EEPROM_INDIRECT_OFFSET)) + break; +#endif + ret = iwm_eeprom_read(iwm, i); + if (ret < 0) { + IWM_ERR(iwm, "Couldn't read eeprom entry #%d: %s\n", + i, eeprom_map[i].name); + break; + } + } + + IWM_DBG_BOOT(iwm, DBG, "EEPROM dump:\n"); + for (i = IWM_EEPROM_FIRST; i < IWM_EEPROM_LAST; i++) { + memset(name, 0, 32); + sprintf(name, "%s: ", eeprom_map[i].name); + + IWM_HEXDUMP(iwm, DBG, BOOT, name, + iwm->eeprom + eeprom_map[i].offset, + eeprom_map[i].length); + } + + return ret; +} + +void iwm_eeprom_exit(struct iwm_priv *iwm) +{ + kfree(iwm->eeprom); +} diff --git a/drivers/net/wireless/iwmc3200wifi/eeprom.h b/drivers/net/wireless/iwmc3200wifi/eeprom.h new file mode 100644 index 000000000000..cdb31a6a1f5f --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/eeprom.h @@ -0,0 +1,114 @@ +/* + * Intel Wireless Multicomm 3200 WiFi driver + * + * Copyright (C) 2009 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * Intel Corporation + * Samuel Ortiz + * Zhu Yi + * + */ + +#ifndef __IWM_EEPROM_H__ +#define __IWM_EEPROM_H__ + +enum { + IWM_EEPROM_SIG = 0, + IWM_EEPROM_FIRST = IWM_EEPROM_SIG, + IWM_EEPROM_VERSION, + IWM_EEPROM_OEM_HW_VERSION, + IWM_EEPROM_MAC_VERSION, + IWM_EEPROM_CARD_ID, + IWM_EEPROM_RADIO_CONF, + IWM_EEPROM_SKU_CAP, + + IWM_EEPROM_INDIRECT_OFFSET, + IWM_EEPROM_CALIB_RXIQ_OFFSET = IWM_EEPROM_INDIRECT_OFFSET, + + IWM_EEPROM_INDIRECT_DATA, + IWM_EEPROM_CALIB_RXIQ = IWM_EEPROM_INDIRECT_DATA, + + IWM_EEPROM_LAST, +}; + +#define IWM_EEPROM_SIG_OFF 0x00 +#define IWM_EEPROM_VERSION_OFF (0x54 << 1) +#define IWM_EEPROM_OEM_HW_VERSION_OFF (0x56 << 1) +#define IWM_EEPROM_MAC_VERSION_OFF (0x30 << 1) +#define IWM_EEPROM_CARD_ID_OFF (0x5d << 1) +#define IWM_EEPROM_RADIO_CONF_OFF (0x58 << 1) +#define IWM_EEPROM_SKU_CAP_OFF (0x55 << 1) +#define IWM_EEPROM_CALIB_CONFIG_OFF (0x7c << 1) + +#define IWM_EEPROM_SIG_LEN 4 +#define IWM_EEPROM_VERSION_LEN 2 +#define IWM_EEPROM_OEM_HW_VERSION_LEN 2 +#define IWM_EEPROM_MAC_VERSION_LEN 1 +#define IWM_EEPROM_CARD_ID_LEN 2 +#define IWM_EEPROM_RADIO_CONF_LEN 2 +#define IWM_EEPROM_SKU_CAP_LEN 2 +#define IWM_EEPROM_INDIRECT_LEN 2 + +#define IWM_MAX_EEPROM_DATA_LEN 240 +#define IWM_EEPROM_LEN 0x800 + +#define IWM_EEPROM_MIN_ALLOWED_VERSION 0x0610 +#define IWM_EEPROM_MAX_ALLOWED_VERSION 0x0700 +#define IWM_EEPROM_CURRENT_VERSION 0x0612 + +#define IWM_EEPROM_SKU_CAP_BAND_24GHZ (1 << 4) +#define IWM_EEPROM_SKU_CAP_BAND_52GHZ (1 << 5) +#define IWM_EEPROM_SKU_CAP_11N_ENABLE (1 << 6) + +enum { + IWM_EEPROM_CALIB_CAL_HDR, + IWM_EEPROM_CALIB_TX_POWER, + IWM_EEPROM_CALIB_XTAL, + IWM_EEPROM_CALIB_TEMPERATURE, + IWM_EEPROM_CALIB_RX_BB_FILTER, + IWM_EEPROM_CALIB_RX_IQ, + IWM_EEPROM_CALIB_MAX, +}; + +#define IWM_EEPROM_CALIB_RXIQ_OFF (IWM_EEPROM_CALIB_CONFIG_OFF + \ + (IWM_EEPROM_CALIB_RX_IQ << 1)) +#define IWM_EEPROM_CALIB_RXIQ_LEN sizeof(struct iwm_lmac_calib_rxiq) + +struct iwm_eeprom_entry { + char *name; + u32 offset; + u32 length; +}; + +int iwm_eeprom_init(struct iwm_priv *iwm); +void iwm_eeprom_exit(struct iwm_priv *iwm); +u8 *iwm_eeprom_access(struct iwm_priv *iwm, u8 eeprom_id); + +#endif diff --git a/drivers/net/wireless/iwmc3200wifi/fw.c b/drivers/net/wireless/iwmc3200wifi/fw.c new file mode 100644 index 000000000000..ec1a15a5a0e4 --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/fw.c @@ -0,0 +1,388 @@ +/* + * Intel Wireless Multicomm 3200 WiFi driver + * + * Copyright (C) 2009 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * Intel Corporation + * Samuel Ortiz + * Zhu Yi + * + */ + +#include +#include + +#include "iwm.h" +#include "bus.h" +#include "hal.h" +#include "umac.h" +#include "debug.h" +#include "fw.h" +#include "commands.h" + +static const char fw_barker[] = "*WESTOPFORNOONE*"; + +/* + * @op_code: Op code we're looking for. + * @index: There can be several instances of the same opcode within + * the firmware. Index specifies which one we're looking for. + */ +static int iwm_fw_op_offset(struct iwm_priv *iwm, const struct firmware *fw, + u16 op_code, u32 index) +{ + int offset = -EINVAL, fw_offset; + u32 op_index = 0; + const u8 *fw_ptr; + struct iwm_fw_hdr_rec *rec; + + fw_offset = 0; + fw_ptr = fw->data; + + /* We first need to look for the firmware barker */ + if (memcmp(fw_ptr, fw_barker, IWM_HDR_BARKER_LEN)) { + IWM_ERR(iwm, "No barker string in this FW\n"); + return -EINVAL; + } + + if (fw->size < IWM_HDR_LEN) { + IWM_ERR(iwm, "FW is too small (%zu)\n", fw->size); + return -EINVAL; + } + + fw_offset += IWM_HDR_BARKER_LEN; + + while (fw_offset < fw->size) { + rec = (struct iwm_fw_hdr_rec *)(fw_ptr + fw_offset); + + IWM_DBG_FW(iwm, DBG, "FW: op_code: 0x%x, len: %d @ 0x%x\n", + rec->op_code, rec->len, fw_offset); + + if (rec->op_code == IWM_HDR_REC_OP_INVALID) { + IWM_DBG_FW(iwm, DBG, "Reached INVALID op code\n"); + break; + } + + if (rec->op_code == op_code) { + if (op_index == index) { + fw_offset += sizeof(struct iwm_fw_hdr_rec); + offset = fw_offset; + goto out; + } + op_index++; + } + + fw_offset += sizeof(struct iwm_fw_hdr_rec) + rec->len; + } + + out: + return offset; +} + +static int iwm_load_firmware_chunk(struct iwm_priv *iwm, + const struct firmware *fw, + struct iwm_fw_img_desc *img_desc) +{ + struct iwm_udma_nonwifi_cmd target_cmd; + u32 chunk_size; + const u8 *chunk_ptr; + int ret = 0; + + IWM_DBG_FW(iwm, INFO, "Loading FW chunk: %d bytes @ 0x%x\n", + img_desc->length, img_desc->address); + + target_cmd.opcode = UMAC_HDI_OUT_OPCODE_WRITE; + target_cmd.handle_by_hw = 1; + target_cmd.op2 = 0; + target_cmd.resp = 0; + target_cmd.eop = 1; + + chunk_size = img_desc->length; + chunk_ptr = fw->data + img_desc->offset; + + while (chunk_size > 0) { + u32 tmp_chunk_size; + + tmp_chunk_size = min_t(u32, chunk_size, + IWM_MAX_NONWIFI_CMD_BUFF_SIZE); + + target_cmd.addr = cpu_to_le32(img_desc->address + + (chunk_ptr - fw->data - img_desc->offset)); + target_cmd.op1_sz = cpu_to_le32(tmp_chunk_size); + + IWM_DBG_FW(iwm, DBG, "\t%d bytes @ 0x%x\n", + tmp_chunk_size, target_cmd.addr); + + ret = iwm_hal_send_target_cmd(iwm, &target_cmd, chunk_ptr); + if (ret < 0) { + IWM_ERR(iwm, "Couldn't load FW chunk\n"); + break; + } + + chunk_size -= tmp_chunk_size; + chunk_ptr += tmp_chunk_size; + } + + return ret; +} +/* + * To load a fw image to the target, we basically go through the + * fw, looking for OP_MEM_DESC records. Once we found one, we + * pass it to iwm_load_firmware_chunk(). + * The OP_MEM_DESC records contain the actuall memory chunk to be + * sent, but also the destination address. + */ +static int iwm_load_img(struct iwm_priv *iwm, const char *img_name) +{ + const struct firmware *fw; + struct iwm_fw_img_desc *img_desc; + struct iwm_fw_img_ver *ver; + int ret = 0, fw_offset; + u32 opcode_idx = 0, build_date; + char *build_tag; + + ret = request_firmware(&fw, img_name, iwm_to_dev(iwm)); + if (ret) { + IWM_ERR(iwm, "Request firmware failed"); + return ret; + } + + IWM_DBG_FW(iwm, INFO, "Start to load FW %s\n", img_name); + + while (1) { + fw_offset = iwm_fw_op_offset(iwm, fw, + IWM_HDR_REC_OP_MEM_DESC, + opcode_idx); + if (fw_offset < 0) + break; + + img_desc = (struct iwm_fw_img_desc *)(fw->data + fw_offset); + ret = iwm_load_firmware_chunk(iwm, fw, img_desc); + if (ret < 0) + goto err_release_fw; + opcode_idx++; + }; + + /* Read firmware version */ + fw_offset = iwm_fw_op_offset(iwm, fw, IWM_HDR_REC_OP_SW_VER, 0); + if (fw_offset < 0) + goto err_release_fw; + + ver = (struct iwm_fw_img_ver *)(fw->data + fw_offset); + + /* Read build tag */ + fw_offset = iwm_fw_op_offset(iwm, fw, IWM_HDR_REC_OP_BUILD_TAG, 0); + if (fw_offset < 0) + goto err_release_fw; + + build_tag = (char *)(fw->data + fw_offset); + + /* Read build date */ + fw_offset = iwm_fw_op_offset(iwm, fw, IWM_HDR_REC_OP_BUILD_DATE, 0); + if (fw_offset < 0) + goto err_release_fw; + + build_date = *(u32 *)(fw->data + fw_offset); + + IWM_INFO(iwm, "%s:\n", img_name); + IWM_INFO(iwm, "\tVersion: %02X.%02X\n", ver->major, ver->minor); + IWM_INFO(iwm, "\tBuild tag: %s\n", build_tag); + IWM_INFO(iwm, "\tBuild date: %x-%x-%x\n", + IWM_BUILD_YEAR(build_date), IWM_BUILD_MONTH(build_date), + IWM_BUILD_DAY(build_date)); + + + err_release_fw: + release_firmware(fw); + + return ret; +} + +static int iwm_load_umac(struct iwm_priv *iwm) +{ + struct iwm_udma_nonwifi_cmd target_cmd; + int ret; + + ret = iwm_load_img(iwm, iwm->bus_ops->umac_name); + if (ret < 0) + return ret; + + /* We've loaded the UMAC, we can tell the target to jump there */ + target_cmd.opcode = UMAC_HDI_OUT_OPCODE_JUMP; + target_cmd.addr = cpu_to_le32(UMAC_MU_FW_INST_DATA_12_ADDR); + target_cmd.op1_sz = 0; + target_cmd.op2 = 0; + target_cmd.handle_by_hw = 0; + target_cmd.resp = 1 ; + target_cmd.eop = 1; + + ret = iwm_hal_send_target_cmd(iwm, &target_cmd, NULL); + if (ret < 0) + IWM_ERR(iwm, "Couldn't send JMP command\n"); + + return ret; +} + +static int iwm_load_lmac(struct iwm_priv *iwm, const char *img_name) +{ + int ret; + + ret = iwm_load_img(iwm, img_name); + if (ret < 0) + return ret; + + return iwm_send_umac_reset(iwm, + cpu_to_le32(UMAC_RST_CTRL_FLG_LARC_CLK_EN), 0); +} + +/* + * We currently have to load 3 FWs: + * 1) The UMAC (Upper MAC). + * 2) The calibration LMAC (Lower MAC). + * We then send the calibration init command, so that the device can + * run a first calibration round. + * 3) The operational LMAC, which replaces the calibration one when it's + * done with the first calibration round. + * + * Once those 3 FWs have been loaded, we send the periodic calibration + * command, and then the device is available for regular 802.11 operations. + */ +int iwm_load_fw(struct iwm_priv *iwm) +{ + int ret; + + /* We first start downloading the UMAC */ + ret = iwm_load_umac(iwm); + if (ret < 0) { + IWM_ERR(iwm, "UMAC loading failed\n"); + return ret; + } + + /* Handle UMAC_ALIVE notification */ + ret = iwm_notif_handle(iwm, UMAC_NOTIFY_OPCODE_ALIVE, IWM_SRC_UMAC, + WAIT_NOTIF_TIMEOUT); + if (ret) { + IWM_ERR(iwm, "Handle UMAC_ALIVE failed: %d\n", ret); + return ret; + } + + /* UMAC is alive, we can download the calibration LMAC */ + ret = iwm_load_lmac(iwm, iwm->bus_ops->calib_lmac_name); + if (ret) { + IWM_ERR(iwm, "Calibration LMAC loading failed\n"); + return ret; + } + + /* Handle UMAC_INIT_COMPLETE notification */ + ret = iwm_notif_handle(iwm, UMAC_NOTIFY_OPCODE_INIT_COMPLETE, + IWM_SRC_UMAC, WAIT_NOTIF_TIMEOUT); + if (ret) { + IWM_ERR(iwm, "Handle INIT_COMPLETE failed for calibration " + "LMAC: %d\n", ret); + return ret; + } + + /* Read EEPROM data */ + ret = iwm_eeprom_init(iwm); + if (ret < 0) { + IWM_ERR(iwm, "Couldn't init eeprom array\n"); + return ret; + } + +#ifdef CONFIG_IWM_B0_HW_SUPPORT + if (iwm->conf.hw_b0) { + clear_bit(PHY_CALIBRATE_RX_IQ_CMD, &iwm->conf.init_calib_map); + clear_bit(PHY_CALIBRATE_RX_IQ_CMD, + &iwm->conf.periodic_calib_map); + } +#endif + /* Read RX IQ calibration result from EEPROM */ + if (test_bit(PHY_CALIBRATE_RX_IQ_CMD, &iwm->conf.init_calib_map)) { + iwm_store_rxiq_calib_result(iwm); + set_bit(PHY_CALIBRATE_RX_IQ_CMD, &iwm->calib_done_map); + } + + iwm_send_prio_table(iwm); + iwm_send_init_calib_cfg(iwm, iwm->conf.init_calib_map); + + while (iwm->calib_done_map != iwm->conf.init_calib_map) { + ret = iwm_notif_handle(iwm, CALIBRATION_RES_NOTIFICATION, + IWM_SRC_LMAC, WAIT_NOTIF_TIMEOUT); + if (ret) { + IWM_ERR(iwm, "Wait for calibration result timeout\n"); + goto out; + } + IWM_DBG_FW(iwm, DBG, "Got calibration result. calib_done_map: " + "0x%lx, requested calibrations: 0x%lx\n", + iwm->calib_done_map, iwm->conf.init_calib_map); + } + + /* Handle LMAC CALIBRATION_COMPLETE notification */ + ret = iwm_notif_handle(iwm, CALIBRATION_COMPLETE_NOTIFICATION, + IWM_SRC_LMAC, WAIT_NOTIF_TIMEOUT); + if (ret) { + IWM_ERR(iwm, "Wait for CALIBRATION_COMPLETE timeout\n"); + goto out; + } + + IWM_INFO(iwm, "LMAC calibration done: 0x%lx\n", iwm->calib_done_map); + + iwm_send_umac_reset(iwm, cpu_to_le32(UMAC_RST_CTRL_FLG_LARC_RESET), 1); + + ret = iwm_notif_handle(iwm, UMAC_CMD_OPCODE_RESET, IWM_SRC_UMAC, + WAIT_NOTIF_TIMEOUT); + if (ret) { + IWM_ERR(iwm, "Wait for UMAC RESET timeout\n"); + goto out; + } + + /* Download the operational LMAC */ + ret = iwm_load_lmac(iwm, iwm->bus_ops->lmac_name); + if (ret) { + IWM_ERR(iwm, "LMAC loading failed\n"); + goto out; + } + + ret = iwm_notif_handle(iwm, UMAC_NOTIFY_OPCODE_INIT_COMPLETE, + IWM_SRC_UMAC, WAIT_NOTIF_TIMEOUT); + if (ret) { + IWM_ERR(iwm, "Handle INIT_COMPLETE failed for LMAC: %d\n", ret); + goto out; + } + + iwm_send_prio_table(iwm); + iwm_send_calib_results(iwm); + iwm_send_periodic_calib_cfg(iwm, iwm->conf.periodic_calib_map); + + return 0; + + out: + iwm_eeprom_exit(iwm); + return ret; +} diff --git a/drivers/net/wireless/iwmc3200wifi/fw.h b/drivers/net/wireless/iwmc3200wifi/fw.h new file mode 100644 index 000000000000..c70a3b40dad3 --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/fw.h @@ -0,0 +1,100 @@ +/* + * Intel Wireless Multicomm 3200 WiFi driver + * + * Copyright (C) 2009 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * Intel Corporation + * Samuel Ortiz + * Zhu Yi + * + */ + +#ifndef __IWM_FW_H__ +#define __IWM_FW_H__ + +/** + * struct iwm_fw_hdr_rec - An iwm firmware image is a + * concatenation of various records. Each of them is + * defined by an ID (aka op code), a length, and the + * actual data. + * @op_code: The record ID, see IWM_HDR_REC_OP_* + * + * @len: The record payload length + * + * @buf: The record payload + */ +struct iwm_fw_hdr_rec { + u16 op_code; + u16 len; + u8 buf[0]; +}; + +/* Header's definitions */ +#define IWM_HDR_LEN (512) +#define IWM_HDR_BARKER_LEN (16) + +/* Header's opcodes */ +#define IWM_HDR_REC_OP_INVALID (0x00) +#define IWM_HDR_REC_OP_BUILD_DATE (0x01) +#define IWM_HDR_REC_OP_BUILD_TAG (0x02) +#define IWM_HDR_REC_OP_SW_VER (0x03) +#define IWM_HDR_REC_OP_HW_SKU (0x04) +#define IWM_HDR_REC_OP_BUILD_OPT (0x05) +#define IWM_HDR_REC_OP_MEM_DESC (0x06) +#define IWM_HDR_REC_USERDEFS (0x07) + +/* Header's records length (in bytes) */ +#define IWM_HDR_REC_LEN_BUILD_DATE (4) +#define IWM_HDR_REC_LEN_BUILD_TAG (64) +#define IWM_HDR_REC_LEN_SW_VER (4) +#define IWM_HDR_REC_LEN_HW_SKU (4) +#define IWM_HDR_REC_LEN_BUILD_OPT (4) +#define IWM_HDR_REC_LEN_MEM_DESC (12) +#define IWM_HDR_REC_LEN_USERDEF (64) + +#define IWM_BUILD_YEAR(date) ((date >> 16) & 0xffff) +#define IWM_BUILD_MONTH(date) ((date >> 8) & 0xff) +#define IWM_BUILD_DAY(date) (date & 0xff) + +struct iwm_fw_img_desc { + u32 offset; + u32 address; + u32 length; +}; + +struct iwm_fw_img_ver { + u8 minor; + u8 major; + u16 reserved; +}; + +int iwm_load_fw(struct iwm_priv *iwm); + +#endif diff --git a/drivers/net/wireless/iwmc3200wifi/hal.c b/drivers/net/wireless/iwmc3200wifi/hal.c new file mode 100644 index 000000000000..ee127fe4f43f --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/hal.c @@ -0,0 +1,464 @@ +/* + * Intel Wireless Multicomm 3200 WiFi driver + * + * Copyright (C) 2009 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * Intel Corporation + * Samuel Ortiz + * Zhu Yi + * + */ + +/* + * Hardware Abstraction Layer for iwm. + * + * This file mostly defines an abstraction API for + * sending various commands to the target. + * + * We have 2 types of commands: wifi and non-wifi ones. + * + * - wifi commands: + * They are used for sending LMAC and UMAC commands, + * and thus are the most commonly used ones. + * There are 2 different wifi command types, the regular + * one and the LMAC one. The former is used to send + * UMAC commands (see UMAC_CMD_OPCODE_* from umac.h) + * while the latter is used for sending commands to the + * LMAC. If you look at LMAC commands you'll se that they + * are actually regular iwlwifi target commands encapsulated + * into a special UMAC command called UMAC passthrough. + * This is due to the fact the the host talks exclusively + * to the UMAC and so there needs to be a special UMAC + * command for talking to the LMAC. + * This is how a wifi command is layed out: + * ------------------------ + * | iwm_udma_out_wifi_hdr | + * ------------------------ + * | SW meta_data (32 bits) | + * ------------------------ + * | iwm_dev_cmd_hdr | + * ------------------------ + * | payload | + * | .... | + * + * - non-wifi, or general commands: + * Those commands are handled by the device's bootrom, + * and are typically sent when the UMAC and the LMAC + * are not yet available. + * * This is how a non-wifi command is layed out: + * --------------------------- + * | iwm_udma_out_nonwifi_hdr | + * --------------------------- + * | payload | + * | .... | + + * + * All the commands start with a UDMA header, which is + * basically a 32 bits field. The 4 LSB there define + * an opcode that allows the target to differentiate + * between wifi (opcode is 0xf) and non-wifi commands + * (opcode is [0..0xe]). + * + * When a command (wifi or non-wifi) is supposed to receive + * an answer, we queue the command buffer. When we do receive + * a command response from the UMAC, we go through the list + * of pending command, and pass both the command and the answer + * to the rx handler. Each command is sent with a unique + * sequence id, and the answer is sent with the same one. This + * is how we're supposed to match an answer with its command. + * See rx.c:iwm_rx_handle_[non]wifi() and iwm_get_pending_[non]wifi() + * for the implementation details. + */ +#include +#include + +#include "iwm.h" +#include "bus.h" +#include "hal.h" +#include "umac.h" +#include "debug.h" + +static void iwm_nonwifi_cmd_init(struct iwm_priv *iwm, + struct iwm_nonwifi_cmd *cmd, + struct iwm_udma_nonwifi_cmd *udma_cmd) +{ + INIT_LIST_HEAD(&cmd->pending); + + spin_lock(&iwm->cmd_lock); + + cmd->resp_received = 0; + + cmd->seq_num = iwm->nonwifi_seq_num; + udma_cmd->seq_num = cpu_to_le16(cmd->seq_num); + + cmd->seq_num = iwm->nonwifi_seq_num++; + iwm->nonwifi_seq_num %= UMAC_NONWIFI_SEQ_NUM_MAX; + + if (udma_cmd->resp) + list_add_tail(&cmd->pending, &iwm->nonwifi_pending_cmd); + + spin_unlock(&iwm->cmd_lock); + + cmd->buf.start = cmd->buf.payload; + cmd->buf.len = 0; + + memcpy(&cmd->udma_cmd, udma_cmd, sizeof(*udma_cmd)); +} + +u16 iwm_alloc_wifi_cmd_seq(struct iwm_priv *iwm) +{ + u16 seq_num = iwm->wifi_seq_num; + + iwm->wifi_seq_num++; + iwm->wifi_seq_num %= UMAC_WIFI_SEQ_NUM_MAX; + + return seq_num; +} + +static void iwm_wifi_cmd_init(struct iwm_priv *iwm, + struct iwm_wifi_cmd *cmd, + struct iwm_udma_wifi_cmd *udma_cmd, + struct iwm_umac_cmd *umac_cmd, + struct iwm_lmac_cmd *lmac_cmd, + u16 payload_size) +{ + INIT_LIST_HEAD(&cmd->pending); + + spin_lock(&iwm->cmd_lock); + + cmd->seq_num = iwm_alloc_wifi_cmd_seq(iwm); + umac_cmd->seq_num = cpu_to_le16(cmd->seq_num); + + if (umac_cmd->resp) + list_add_tail(&cmd->pending, &iwm->wifi_pending_cmd); + + spin_unlock(&iwm->cmd_lock); + + cmd->buf.start = cmd->buf.payload; + cmd->buf.len = 0; + + if (lmac_cmd) { + cmd->buf.start -= sizeof(struct iwm_lmac_hdr); + + lmac_cmd->seq_num = cpu_to_le16(cmd->seq_num); + lmac_cmd->count = cpu_to_le16(payload_size); + + memcpy(&cmd->lmac_cmd, lmac_cmd, sizeof(*lmac_cmd)); + + umac_cmd->count = cpu_to_le16(sizeof(struct iwm_lmac_hdr)); + } else + umac_cmd->count = 0; + + umac_cmd->count = cpu_to_le16(payload_size + + le16_to_cpu(umac_cmd->count)); + udma_cmd->count = cpu_to_le16(sizeof(struct iwm_umac_fw_cmd_hdr) + + le16_to_cpu(umac_cmd->count)); + + memcpy(&cmd->udma_cmd, udma_cmd, sizeof(*udma_cmd)); + memcpy(&cmd->umac_cmd, umac_cmd, sizeof(*umac_cmd)); +} + +void iwm_cmd_flush(struct iwm_priv *iwm) +{ + struct iwm_wifi_cmd *wcmd, *wnext; + struct iwm_nonwifi_cmd *nwcmd, *nwnext; + + list_for_each_entry_safe(wcmd, wnext, &iwm->wifi_pending_cmd, pending) { + list_del(&wcmd->pending); + kfree(wcmd); + } + + list_for_each_entry_safe(nwcmd, nwnext, &iwm->nonwifi_pending_cmd, + pending) { + list_del(&nwcmd->pending); + kfree(nwcmd); + } +} + +struct iwm_wifi_cmd *iwm_get_pending_wifi_cmd(struct iwm_priv *iwm, u16 seq_num) +{ + struct iwm_wifi_cmd *cmd, *next; + + list_for_each_entry_safe(cmd, next, &iwm->wifi_pending_cmd, pending) + if (cmd->seq_num == seq_num) { + list_del(&cmd->pending); + return cmd; + } + + return NULL; +} + +struct iwm_nonwifi_cmd * +iwm_get_pending_nonwifi_cmd(struct iwm_priv *iwm, u8 seq_num, u8 cmd_opcode) +{ + struct iwm_nonwifi_cmd *cmd, *next; + + list_for_each_entry_safe(cmd, next, &iwm->nonwifi_pending_cmd, pending) + if ((cmd->seq_num == seq_num) && + (cmd->udma_cmd.opcode == cmd_opcode) && + (cmd->resp_received)) { + list_del(&cmd->pending); + return cmd; + } + + return NULL; +} + +static void iwm_build_udma_nonwifi_hdr(struct iwm_priv *iwm, + struct iwm_udma_out_nonwifi_hdr *hdr, + struct iwm_udma_nonwifi_cmd *cmd) +{ + memset(hdr, 0, sizeof(*hdr)); + + SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_OPCODE, cmd->opcode); + SET_VAL32(hdr->cmd, UDMA_HDI_OUT_NW_CMD_RESP, cmd->resp); + SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_EOT, 1); + SET_VAL32(hdr->cmd, UDMA_HDI_OUT_NW_CMD_HANDLE_BY_HW, + cmd->handle_by_hw); + SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_SIGNATURE, UMAC_HDI_OUT_SIGNATURE); + SET_VAL32(hdr->cmd, UDMA_HDI_OUT_CMD_NON_WIFI_HW_SEQ_NUM, + le16_to_cpu(cmd->seq_num)); + + hdr->addr = cmd->addr; + hdr->op1_sz = cmd->op1_sz; + hdr->op2 = cmd->op2; +} + +static int iwm_send_udma_nonwifi_cmd(struct iwm_priv *iwm, + struct iwm_nonwifi_cmd *cmd) +{ + struct iwm_udma_out_nonwifi_hdr *udma_hdr; + struct iwm_nonwifi_cmd_buff *buf; + struct iwm_udma_nonwifi_cmd *udma_cmd = &cmd->udma_cmd; + + buf = &cmd->buf; + + buf->start -= sizeof(struct iwm_umac_nonwifi_out_hdr); + buf->len += sizeof(struct iwm_umac_nonwifi_out_hdr); + + udma_hdr = (struct iwm_udma_out_nonwifi_hdr *)(buf->start); + + iwm_build_udma_nonwifi_hdr(iwm, udma_hdr, udma_cmd); + + IWM_DBG_CMD(iwm, DBG, + "Send UDMA nonwifi cmd: opcode = 0x%x, resp = 0x%x, " + "hw = 0x%x, seqnum = %d, addr = 0x%x, op1_sz = 0x%x, " + "op2 = 0x%x\n", udma_cmd->opcode, udma_cmd->resp, + udma_cmd->handle_by_hw, cmd->seq_num, udma_cmd->addr, + udma_cmd->op1_sz, udma_cmd->op2); + + return iwm_bus_send_chunk(iwm, buf->start, buf->len); +} + +void iwm_udma_wifi_hdr_set_eop(struct iwm_priv *iwm, u8 *buf, u8 eop) +{ + struct iwm_udma_out_wifi_hdr *hdr = (struct iwm_udma_out_wifi_hdr *)buf; + + SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_EOT, eop); +} + +void iwm_build_udma_wifi_hdr(struct iwm_priv *iwm, + struct iwm_udma_out_wifi_hdr *hdr, + struct iwm_udma_wifi_cmd *cmd) +{ + memset(hdr, 0, sizeof(*hdr)); + + SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_OPCODE, UMAC_HDI_OUT_OPCODE_WIFI); + SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_EOT, cmd->eop); + SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_SIGNATURE, UMAC_HDI_OUT_SIGNATURE); + + SET_VAL32(hdr->meta_data, UMAC_HDI_OUT_BYTE_COUNT, + le16_to_cpu(cmd->count)); + SET_VAL32(hdr->meta_data, UMAC_HDI_OUT_CREDIT_GRP, cmd->credit_group); + SET_VAL32(hdr->meta_data, UMAC_HDI_OUT_RATID, cmd->ra_tid); + SET_VAL32(hdr->meta_data, UMAC_HDI_OUT_LMAC_OFFSET, cmd->lmac_offset); +} + +void iwm_build_umac_hdr(struct iwm_priv *iwm, + struct iwm_umac_fw_cmd_hdr *hdr, + struct iwm_umac_cmd *cmd) +{ + memset(hdr, 0, sizeof(*hdr)); + + SET_VAL32(hdr->meta_data, UMAC_FW_CMD_BYTE_COUNT, + le16_to_cpu(cmd->count)); + SET_VAL32(hdr->meta_data, UMAC_FW_CMD_TX_STA_COLOR, cmd->color); + SET_VAL8(hdr->cmd.flags, UMAC_DEV_CMD_FLAGS_RESP_REQ, cmd->resp); + + hdr->cmd.cmd = cmd->id; + hdr->cmd.seq_num = cmd->seq_num; +} + +static int iwm_send_udma_wifi_cmd(struct iwm_priv *iwm, + struct iwm_wifi_cmd *cmd) +{ + struct iwm_umac_wifi_out_hdr *umac_hdr; + struct iwm_wifi_cmd_buff *buf; + struct iwm_udma_wifi_cmd *udma_cmd = &cmd->udma_cmd; + struct iwm_umac_cmd *umac_cmd = &cmd->umac_cmd; + int ret; + + buf = &cmd->buf; + + buf->start -= sizeof(struct iwm_umac_wifi_out_hdr); + buf->len += sizeof(struct iwm_umac_wifi_out_hdr); + + umac_hdr = (struct iwm_umac_wifi_out_hdr *)(buf->start); + + iwm_build_udma_wifi_hdr(iwm, &umac_hdr->hw_hdr, udma_cmd); + iwm_build_umac_hdr(iwm, &umac_hdr->sw_hdr, umac_cmd); + + IWM_DBG_CMD(iwm, DBG, + "Send UDMA wifi cmd: opcode = 0x%x, UMAC opcode = 0x%x, " + "eop = 0x%x, count = 0x%x, credit_group = 0x%x, " + "ra_tid = 0x%x, lmac_offset = 0x%x, seqnum = %d\n", + UMAC_HDI_OUT_OPCODE_WIFI, umac_cmd->id, + udma_cmd->eop, udma_cmd->count, udma_cmd->credit_group, + udma_cmd->ra_tid, udma_cmd->lmac_offset, cmd->seq_num); + + if (umac_cmd->id == UMAC_CMD_OPCODE_WIFI_PASS_THROUGH) + IWM_DBG_CMD(iwm, DBG, "\tLMAC opcode: 0x%x\n", + cmd->lmac_cmd.id); + + ret = iwm_tx_credit_alloc(iwm, udma_cmd->credit_group, buf->len); + + /* We keep sending UMAC reset regardless of the command credits. + * The UMAC is supposed to be reset anyway and the Tx credits are + * reinitialized afterwards. If we are lucky, the reset could + * still be done even though we have run out of credits for the + * command pool at this moment.*/ + if (ret && (umac_cmd->id != UMAC_CMD_OPCODE_RESET)) { + IWM_DBG_TX(iwm, DBG, "Failed to alloc tx credit for cmd %d\n", + umac_cmd->id); + return ret; + } + + return iwm_bus_send_chunk(iwm, buf->start, buf->len); +} + +/* target_cmd a.k.a udma_nonwifi_cmd can be sent when UMAC is not available */ +int iwm_hal_send_target_cmd(struct iwm_priv *iwm, + struct iwm_udma_nonwifi_cmd *udma_cmd, + const void *payload) +{ + struct iwm_nonwifi_cmd *cmd; + int ret; + + cmd = kzalloc(sizeof(struct iwm_nonwifi_cmd), GFP_KERNEL); + if (!cmd) { + IWM_ERR(iwm, "Couldn't alloc memory for hal cmd\n"); + return -ENOMEM; + } + + iwm_nonwifi_cmd_init(iwm, cmd, udma_cmd); + + if (cmd->udma_cmd.opcode == UMAC_HDI_OUT_OPCODE_WRITE || + cmd->udma_cmd.opcode == UMAC_HDI_OUT_OPCODE_WRITE_PERSISTENT) { + cmd->buf.len = le32_to_cpu(cmd->udma_cmd.op1_sz); + memcpy(&cmd->buf.payload, payload, cmd->buf.len); + } + + ret = iwm_send_udma_nonwifi_cmd(iwm, cmd); + + if (!udma_cmd->resp) + kfree(cmd); + + if (ret < 0) + return ret; + + return cmd->seq_num; +} + +static void iwm_build_lmac_hdr(struct iwm_priv *iwm, struct iwm_lmac_hdr *hdr, + struct iwm_lmac_cmd *cmd) +{ + memset(hdr, 0, sizeof(*hdr)); + + hdr->id = cmd->id; + hdr->flags = 0; /* Is this ever used? */ + hdr->seq_num = cmd->seq_num; +} + +/* + * iwm_hal_send_host_cmd(): sends commands to the UMAC or the LMAC. + * Sending command to the LMAC is equivalent to sending a + * regular UMAC command with the LMAC passtrough or the LMAC + * wrapper UMAC command IDs. + */ +int iwm_hal_send_host_cmd(struct iwm_priv *iwm, + struct iwm_udma_wifi_cmd *udma_cmd, + struct iwm_umac_cmd *umac_cmd, + struct iwm_lmac_cmd *lmac_cmd, + const void *payload, u16 payload_size) +{ + struct iwm_wifi_cmd *cmd; + struct iwm_lmac_hdr *hdr; + int lmac_hdr_len = 0; + int ret; + + cmd = kzalloc(sizeof(struct iwm_wifi_cmd), GFP_KERNEL); + if (!cmd) { + IWM_ERR(iwm, "Couldn't alloc memory for wifi hal cmd\n"); + return -ENOMEM; + } + + iwm_wifi_cmd_init(iwm, cmd, udma_cmd, umac_cmd, lmac_cmd, payload_size); + + if (lmac_cmd) { + hdr = (struct iwm_lmac_hdr *)(cmd->buf.start); + + iwm_build_lmac_hdr(iwm, hdr, &cmd->lmac_cmd); + lmac_hdr_len = sizeof(struct iwm_lmac_hdr); + } + + memcpy(cmd->buf.payload, payload, payload_size); + cmd->buf.len = le16_to_cpu(umac_cmd->count); + + ret = iwm_send_udma_wifi_cmd(iwm, cmd); + + /* We free the cmd if we're not expecting any response */ + if (!umac_cmd->resp) + kfree(cmd); + return ret; +} + +/* + * iwm_hal_send_umac_cmd(): This is a special case for + * iwm_hal_send_host_cmd() to send direct UMAC cmd (without + * LMAC involved). + */ +int iwm_hal_send_umac_cmd(struct iwm_priv *iwm, + struct iwm_udma_wifi_cmd *udma_cmd, + struct iwm_umac_cmd *umac_cmd, + const void *payload, u16 payload_size) +{ + return iwm_hal_send_host_cmd(iwm, udma_cmd, umac_cmd, NULL, + payload, payload_size); +} diff --git a/drivers/net/wireless/iwmc3200wifi/hal.h b/drivers/net/wireless/iwmc3200wifi/hal.h new file mode 100644 index 000000000000..0adfdc85765d --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/hal.h @@ -0,0 +1,236 @@ +/* + * Intel Wireless Multicomm 3200 WiFi driver + * + * Copyright (C) 2009 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * Intel Corporation + * Samuel Ortiz + * Zhu Yi + * + */ + +#ifndef _IWM_HAL_H_ +#define _IWM_HAL_H_ + +#include "umac.h" + +#define GET_VAL8(s, name) ((s >> name##_POS) & name##_SEED) +#define GET_VAL16(s, name) ((le16_to_cpu(s) >> name##_POS) & name##_SEED) +#define GET_VAL32(s, name) ((le32_to_cpu(s) >> name##_POS) & name##_SEED) + +#define SET_VAL8(s, name, val) \ +do { \ + s = (s & ~(name##_SEED << name##_POS)) | \ + ((val & name##_SEED) << name##_POS); \ +} while (0) + +#define SET_VAL16(s, name, val) \ +do { \ + s = cpu_to_le16((le16_to_cpu(s) & ~(name##_SEED << name##_POS)) | \ + ((val & name##_SEED) << name##_POS)); \ +} while (0) + +#define SET_VAL32(s, name, val) \ +do { \ + s = cpu_to_le32((le32_to_cpu(s) & ~(name##_SEED << name##_POS)) | \ + ((val & name##_SEED) << name##_POS)); \ +} while (0) + + +#define UDMA_UMAC_INIT { .eop = 1, \ + .credit_group = 0x4, \ + .ra_tid = UMAC_HDI_ACT_TBL_IDX_HOST_CMD, \ + .lmac_offset = 0 } +#define UDMA_LMAC_INIT { .eop = 1, \ + .credit_group = 0x4, \ + .ra_tid = UMAC_HDI_ACT_TBL_IDX_HOST_CMD, \ + .lmac_offset = 4 } + + +/* UDMA IN OP CODE -- cmd bits [3:0] */ +#define UDMA_IN_OPCODE_MASK 0xF + +#define UDMA_IN_OPCODE_GENERAL_RESP 0x0 +#define UDMA_IN_OPCODE_READ_RESP 0x1 +#define UDMA_IN_OPCODE_WRITE_RESP 0x2 +#define UDMA_IN_OPCODE_PERS_WRITE_RESP 0x5 +#define UDMA_IN_OPCODE_PERS_READ_RESP 0x6 +#define UDMA_IN_OPCODE_RD_MDFY_WR_RESP 0x7 +#define UDMA_IN_OPCODE_EP_MNGMT_MSG 0x8 +#define UDMA_IN_OPCODE_CRDT_CHNG_MSG 0x9 +#define UDMA_IN_OPCODE_CNTRL_DATABASE_MSG 0xA +#define UDMA_IN_OPCODE_SW_MSG 0xB +#define UDMA_IN_OPCODE_WIFI 0xF +#define UDMA_IN_OPCODE_WIFI_LMAC 0x1F +#define UDMA_IN_OPCODE_WIFI_UMAC 0x2F + +/* HW API: udma_hdi_nonwifi API (OUT and IN) */ + +/* iwm_udma_nonwifi_cmd request response -- bits [9:9] */ +#define UDMA_HDI_OUT_NW_CMD_RESP_POS 9 +#define UDMA_HDI_OUT_NW_CMD_RESP_SEED 0x1 + +/* iwm_udma_nonwifi_cmd handle by HW -- bits [11:11] */ +#define UDMA_HDI_OUT_NW_CMD_HANDLE_BY_HW_POS 11 +#define UDMA_HDI_OUT_NW_CMD_HANDLE_BY_HW_SEED 0x1 + +/* iwm_udma_nonwifi_cmd sequence-number -- bits [12:15] */ +#define UDMA_HDI_OUT_NW_CMD_SEQ_NUM_POS 12 +#define UDMA_HDI_OUT_NW_CMD_SEQ_NUM_SEED 0xF + +/* UDMA IN Non-WIFI HW sequence number -- bits [12:15] */ +#define UDMA_IN_NW_HW_SEQ_NUM_POS 12 +#define UDMA_IN_NW_HW_SEQ_NUM_SEED 0xF + +/* UDMA IN Non-WIFI HW signature -- bits [16:31] */ +#define UDMA_IN_NW_HW_SIG_POS 16 +#define UDMA_IN_NW_HW_SIG_SEED 0xFFFF + +/* fixed signature */ +#define UDMA_IN_NW_HW_SIG 0xCBBC + +/* UDMA IN Non-WIFI HW block length -- bits [32:35] */ +#define UDMA_IN_NW_HW_LENGTH_SEED 0xF +#define UDMA_IN_NW_HW_LENGTH_POS 32 + +/* End of HW API: udma_hdi_nonwifi API (OUT and IN) */ + +#define IWM_SDIO_FW_MAX_CHUNK_SIZE 2032 +#define IWM_MAX_WIFI_HEADERS_SIZE 32 +#define IWM_MAX_NONWIFI_HEADERS_SIZE 16 +#define IWM_MAX_NONWIFI_CMD_BUFF_SIZE (IWM_SDIO_FW_MAX_CHUNK_SIZE - \ + IWM_MAX_NONWIFI_HEADERS_SIZE) +#define IWM_MAX_WIFI_CMD_BUFF_SIZE (IWM_SDIO_FW_MAX_CHUNK_SIZE - \ + IWM_MAX_WIFI_HEADERS_SIZE) + +#define IWM_HAL_CONCATENATE_BUF_SIZE 8192 + +struct iwm_wifi_cmd_buff { + u16 len; + u8 *start; + u8 hdr[IWM_MAX_WIFI_HEADERS_SIZE]; + u8 payload[IWM_MAX_WIFI_CMD_BUFF_SIZE]; +}; + +struct iwm_nonwifi_cmd_buff { + u16 len; + u8 *start; + u8 hdr[IWM_MAX_NONWIFI_HEADERS_SIZE]; + u8 payload[IWM_MAX_NONWIFI_CMD_BUFF_SIZE]; +}; + +struct iwm_udma_nonwifi_cmd { + u8 opcode; + u8 eop; + u8 resp; + u8 handle_by_hw; + __le32 addr; + __le32 op1_sz; + __le32 op2; + __le16 seq_num; +}; + +struct iwm_udma_wifi_cmd { + __le16 count; + u8 eop; + u8 credit_group; + u8 ra_tid; + u8 lmac_offset; +}; + +struct iwm_umac_cmd { + u8 id; + __le16 count; + u8 resp; + __le16 seq_num; + u8 color; +}; + +struct iwm_lmac_cmd { + u8 id; + __le16 count; + u8 resp; + __le16 seq_num; +}; + +struct iwm_nonwifi_cmd { + u16 seq_num; + bool resp_received; + struct list_head pending; + struct iwm_udma_nonwifi_cmd udma_cmd; + struct iwm_umac_cmd umac_cmd; + struct iwm_lmac_cmd lmac_cmd; + struct iwm_nonwifi_cmd_buff buf; + u32 flags; +}; + +struct iwm_wifi_cmd { + u16 seq_num; + struct list_head pending; + struct iwm_udma_wifi_cmd udma_cmd; + struct iwm_umac_cmd umac_cmd; + struct iwm_lmac_cmd lmac_cmd; + struct iwm_wifi_cmd_buff buf; + u32 flags; +}; + +void iwm_cmd_flush(struct iwm_priv *iwm); + +struct iwm_wifi_cmd *iwm_get_pending_wifi_cmd(struct iwm_priv *iwm, + u16 seq_num); +struct iwm_nonwifi_cmd *iwm_get_pending_nonwifi_cmd(struct iwm_priv *iwm, + u8 seq_num, u8 cmd_opcode); + + +int iwm_hal_send_target_cmd(struct iwm_priv *iwm, + struct iwm_udma_nonwifi_cmd *ucmd, + const void *payload); + +int iwm_hal_send_host_cmd(struct iwm_priv *iwm, + struct iwm_udma_wifi_cmd *udma_cmd, + struct iwm_umac_cmd *umac_cmd, + struct iwm_lmac_cmd *lmac_cmd, + const void *payload, u16 payload_size); + +int iwm_hal_send_umac_cmd(struct iwm_priv *iwm, + struct iwm_udma_wifi_cmd *udma_cmd, + struct iwm_umac_cmd *umac_cmd, + const void *payload, u16 payload_size); + +u16 iwm_alloc_wifi_cmd_seq(struct iwm_priv *iwm); + +void iwm_udma_wifi_hdr_set_eop(struct iwm_priv *iwm, u8 *buf, u8 eop); +void iwm_build_udma_wifi_hdr(struct iwm_priv *iwm, + struct iwm_udma_out_wifi_hdr *hdr, + struct iwm_udma_wifi_cmd *cmd); +void iwm_build_umac_hdr(struct iwm_priv *iwm, + struct iwm_umac_fw_cmd_hdr *hdr, + struct iwm_umac_cmd *cmd); +#endif /* _IWM_HAL_H_ */ diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h new file mode 100644 index 000000000000..77c339f8516c --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/iwm.h @@ -0,0 +1,350 @@ +/* + * Intel Wireless Multicomm 3200 WiFi driver + * + * Copyright (C) 2009 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * Intel Corporation + * Samuel Ortiz + * Zhu Yi + * + */ + +#ifndef __IWM_H__ +#define __IWM_H__ + +#include +#include +#include + +#include "debug.h" +#include "hal.h" +#include "umac.h" +#include "lmac.h" +#include "eeprom.h" + +#define IWM_COPYRIGHT "Copyright(c) 2009 Intel Corporation" +#define IWM_AUTHOR "" + +#define CONFIG_IWM_B0_HW_SUPPORT 1 + +#define IWM_SRC_LMAC UMAC_HDI_IN_SOURCE_FHRX +#define IWM_SRC_UDMA UMAC_HDI_IN_SOURCE_UDMA +#define IWM_SRC_UMAC UMAC_HDI_IN_SOURCE_FW +#define IWM_SRC_NUM 3 + +#define IWM_POWER_INDEX_MIN 0 +#define IWM_POWER_INDEX_MAX 5 +#define IWM_POWER_INDEX_DEFAULT 3 + +struct iwm_conf { + u32 sdio_ior_timeout; + unsigned long init_calib_map; + unsigned long periodic_calib_map; + bool reset_on_fatal_err; + bool auto_connect; + bool wimax_not_present; + bool enable_qos; + u32 mode; + + u32 power_index; + u32 frag_threshold; + u32 rts_threshold; + bool cts_to_self; + + u32 assoc_timeout; + u32 roam_timeout; + u32 wireless_mode; + u32 coexist_mode; + + u8 ibss_band; + u8 ibss_channel; + + u8 mac_addr[ETH_ALEN]; +#ifdef CONFIG_IWM_B0_HW_SUPPORT + bool hw_b0; +#endif +}; + +enum { + COEX_MODE_SA = 1, + COEX_MODE_XOR, + COEX_MODE_CM, + COEX_MODE_MAX, +}; + +struct iwm_if_ops; +struct iwm_wifi_cmd; + +struct pool_entry { + int id; /* group id */ + int sid; /* super group id */ + int min_pages; /* min capacity in pages */ + int max_pages; /* max capacity in pages */ + int alloc_pages; /* allocated # of pages. incresed by driver */ + int total_freed_pages; /* total freed # of pages. incresed by UMAC */ +}; + +struct spool_entry { + int id; + int max_pages; + int alloc_pages; +}; + +struct iwm_tx_credit { + spinlock_t lock; + int pool_nr; + unsigned long full_pools_map; /* bitmap for # of filled tx pools */ + struct pool_entry pools[IWM_MACS_OUT_GROUPS]; + struct spool_entry spools[IWM_MACS_OUT_SGROUPS]; +}; + +struct iwm_notif { + struct list_head pending; + u32 cmd_id; + void *cmd; + u8 src; + void *buf; + unsigned long buf_size; +}; + +struct iwm_sta_info { + u8 addr[ETH_ALEN]; + bool valid; + bool qos; + u8 color; +}; + +struct iwm_tx_info { + u8 sta; + u8 color; + u8 tid; +}; + +struct iwm_rx_info { + unsigned long rx_size; + unsigned long rx_buf_size; +}; + +#define IWM_NUM_KEYS 4 + +struct iwm_umac_key_hdr { + u8 mac[ETH_ALEN]; + u8 key_idx; + u8 multicast; /* BCast encrypt & BCast decrypt of frames FROM mac */ +} __attribute__ ((packed)); + +struct iwm_key { + struct iwm_umac_key_hdr hdr; + u8 in_use; + u8 alg; + u32 flags; + u8 tx_seq[IW_ENCODE_SEQ_MAX_SIZE]; + u8 rx_seq[IW_ENCODE_SEQ_MAX_SIZE]; + u8 key_len; + u8 key[32]; +}; + +#define IWM_RX_ID_HASH 0xff +#define IWM_RX_ID_GET_HASH(id) ((id) % IWM_RX_ID_HASH) + +#define IWM_STA_TABLE_NUM 16 +#define IWM_TX_LIST_SIZE 64 +#define IWM_RX_LIST_SIZE 256 + +#define IWM_SCAN_ID_MAX 0xff + +#define IWM_STATUS_READY 0 +#define IWM_STATUS_SCANNING 1 +#define IWM_STATUS_SCAN_ABORTING 2 +#define IWM_STATUS_ASSOCIATING 3 +#define IWM_STATUS_ASSOCIATED 4 + +#define IWM_RADIO_RFKILL_OFF 0 +#define IWM_RADIO_RFKILL_HW 1 +#define IWM_RADIO_RFKILL_SW 2 + +struct iwm_tx_queue { + int id; + struct sk_buff_head queue; + struct workqueue_struct *wq; + struct work_struct worker; + u8 concat_buf[IWM_HAL_CONCATENATE_BUF_SIZE]; + int concat_count; + u8 *concat_ptr; +}; + +/* Queues 0 ~ 3 for AC data, 5 for iPAN */ +#define IWM_TX_QUEUES 5 +#define IWM_TX_DATA_QUEUES 4 +#define IWM_TX_CMD_QUEUE 4 + +struct iwm_bss_info { + struct list_head node; + struct cfg80211_bss *cfg_bss; + struct iwm_umac_notif_bss_info *bss; +}; + +typedef int (*iwm_handler)(struct iwm_priv *priv, u8 *buf, + unsigned long buf_size, struct iwm_wifi_cmd *cmd); + +#define IWM_WATCHDOG_PERIOD (6 * HZ) + +struct iwm_priv { + struct wireless_dev *wdev; + struct iwm_if_ops *bus_ops; + + struct iwm_conf conf; + + unsigned long status; + unsigned long radio; + + struct list_head pending_notif; + wait_queue_head_t notif_queue; + + wait_queue_head_t nonwifi_queue; + + unsigned long calib_done_map; + struct { + u8 *buf; + u32 size; + } calib_res[CALIBRATION_CMD_NUM]; + + struct iwm_umac_profile *umac_profile; + bool umac_profile_active; + + u8 bssid[ETH_ALEN]; + u8 channel; + u16 rate; + + struct iwm_sta_info sta_table[IWM_STA_TABLE_NUM]; + struct list_head bss_list; + + void (*nonwifi_rx_handlers[UMAC_HDI_IN_OPCODE_NONWIFI_MAX]) + (struct iwm_priv *priv, u8 *buf, unsigned long buf_size); + + const iwm_handler *umac_handlers; + const iwm_handler *lmac_handlers; + DECLARE_BITMAP(lmac_handler_map, LMAC_COMMAND_ID_NUM); + DECLARE_BITMAP(umac_handler_map, LMAC_COMMAND_ID_NUM); + DECLARE_BITMAP(udma_handler_map, LMAC_COMMAND_ID_NUM); + + struct list_head wifi_pending_cmd; + struct list_head nonwifi_pending_cmd; + u16 wifi_seq_num; + u8 nonwifi_seq_num; + spinlock_t cmd_lock; + + u32 core_enabled; + + u8 scan_id; + struct cfg80211_scan_request *scan_request; + + struct sk_buff_head rx_list; + struct list_head rx_tickets; + struct list_head rx_packets[IWM_RX_ID_HASH]; + struct workqueue_struct *rx_wq; + struct work_struct rx_worker; + + struct iwm_tx_credit tx_credit; + struct iwm_tx_queue txq[IWM_TX_QUEUES]; + + struct iwm_key keys[IWM_NUM_KEYS]; + struct iwm_key *default_key; + + wait_queue_head_t mlme_queue; + + struct iw_statistics wstats; + struct delayed_work stats_request; + + struct iwm_debugfs dbg; + + u8 *eeprom; + struct timer_list watchdog; + struct work_struct reset_worker; + struct mutex mutex; + struct rfkill *rfkill; + + char private[0] __attribute__((__aligned__(NETDEV_ALIGN))); +}; + +static inline void *iwm_private(struct iwm_priv *iwm) +{ + BUG_ON(!iwm); + return &iwm->private; +} + +#define hw_to_iwm(h) (h->iwm) +#define iwm_to_dev(i) (wiphy_dev(i->wdev->wiphy)) +#define iwm_to_wiphy(i) (i->wdev->wiphy) +#define wiphy_to_iwm(w) (struct iwm_priv *)(wiphy_priv(w)) +#define iwm_to_wdev(i) (i->wdev) +#define wdev_to_iwm(w) (struct iwm_priv *)(wdev_priv(w)) +#define iwm_to_ndev(i) (i->wdev->netdev) +#define ndev_to_iwm(n) (wdev_to_iwm(n->ieee80211_ptr)) +#define skb_to_rx_info(s) ((struct iwm_rx_info *)(s->cb)) +#define skb_to_tx_info(s) ((struct iwm_tx_info *)s->cb) + +extern const struct iw_handler_def iwm_iw_handler_def; + +void *iwm_if_alloc(int sizeof_bus, struct device *dev, + struct iwm_if_ops *if_ops); +void iwm_if_free(struct iwm_priv *iwm); +int iwm_if_add(struct iwm_priv *iwm); +void iwm_if_remove(struct iwm_priv *iwm); +int iwm_mode_to_nl80211_iftype(int mode); +int iwm_priv_init(struct iwm_priv *iwm); +void iwm_priv_deinit(struct iwm_priv *iwm); +void iwm_reset(struct iwm_priv *iwm); +void iwm_tx_credit_init_pools(struct iwm_priv *iwm, + struct iwm_umac_notif_alive *alive); +int iwm_tx_credit_alloc(struct iwm_priv *iwm, int id, int nb); +int iwm_notif_send(struct iwm_priv *iwm, struct iwm_wifi_cmd *cmd, + u8 cmd_id, u8 source, u8 *buf, unsigned long buf_size); +int iwm_notif_handle(struct iwm_priv *iwm, u32 cmd, u8 source, long timeout); +void iwm_init_default_profile(struct iwm_priv *iwm, + struct iwm_umac_profile *profile); +void iwm_link_on(struct iwm_priv *iwm); +void iwm_link_off(struct iwm_priv *iwm); +int iwm_up(struct iwm_priv *iwm); +int iwm_down(struct iwm_priv *iwm); + +/* TX API */ +void iwm_tx_credit_inc(struct iwm_priv *iwm, int id, int total_freed_pages); +void iwm_tx_worker(struct work_struct *work); +int iwm_xmit_frame(struct sk_buff *skb, struct net_device *netdev); + +/* RX API */ +void iwm_rx_setup_handlers(struct iwm_priv *iwm); +int iwm_rx_handle(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size); +int iwm_rx_handle_resp(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size, + struct iwm_wifi_cmd *cmd); +void iwm_rx_free(struct iwm_priv *iwm); + +#endif diff --git a/drivers/net/wireless/iwmc3200wifi/lmac.h b/drivers/net/wireless/iwmc3200wifi/lmac.h new file mode 100644 index 000000000000..db2e5eea1895 --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/lmac.h @@ -0,0 +1,457 @@ +/* + * Intel Wireless Multicomm 3200 WiFi driver + * + * Copyright (C) 2009 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * Intel Corporation + * Samuel Ortiz + * Zhu Yi + * + */ + +#ifndef __IWM_LMAC_H__ +#define __IWM_LMAC_H__ + +struct iwm_lmac_hdr { + u8 id; + u8 flags; + __le16 seq_num; +} __attribute__ ((packed)); + +/* LMAC commands */ +#define CALIB_CFG_FLAG_SEND_COMPLETE_NTFY_AFTER_MSK 0x1 + +struct iwm_lmac_cal_cfg_elt { + __le32 enable; /* 1 means LMAC needs to do something */ + __le32 start; /* 1 to start calibration, 0 to stop */ + __le32 send_res; /* 1 for sending back results */ + __le32 apply_res; /* 1 for applying calibration results to HW */ + __le32 reserved; +} __attribute__ ((packed)); + +struct iwm_lmac_cal_cfg_status { + struct iwm_lmac_cal_cfg_elt init; + struct iwm_lmac_cal_cfg_elt periodic; + __le32 flags; /* CALIB_CFG_FLAG_SEND_COMPLETE_NTFY_AFTER_MSK */ +} __attribute__ ((packed)); + +struct iwm_lmac_cal_cfg_cmd { + struct iwm_lmac_cal_cfg_status ucode_cfg; + struct iwm_lmac_cal_cfg_status driver_cfg; + __le32 reserved; +} __attribute__ ((packed)); + +struct iwm_lmac_cal_cfg_resp { + __le32 status; +} __attribute__ ((packed)); + +#define IWM_CARD_STATE_SW_HW_ENABLED 0x00 +#define IWM_CARD_STATE_HW_DISABLED 0x01 +#define IWM_CARD_STATE_SW_DISABLED 0x02 +#define IWM_CARD_STATE_CTKILL_DISABLED 0x04 +#define IWM_CARD_STATE_IS_RXON 0x10 + +struct iwm_lmac_card_state { + __le32 flags; +} __attribute__ ((packed)); + +/** + * COEX_PRIORITY_TABLE_CMD + * + * Priority entry for each state + * Will keep two tables, for STA and WIPAN + */ +enum { + /* UN-ASSOCIATION PART */ + COEX_UNASSOC_IDLE = 0, + COEX_UNASSOC_MANUAL_SCAN, + COEX_UNASSOC_AUTO_SCAN, + + /* CALIBRATION */ + COEX_CALIBRATION, + COEX_PERIODIC_CALIBRATION, + + /* CONNECTION */ + COEX_CONNECTION_ESTAB, + + /* ASSOCIATION PART */ + COEX_ASSOCIATED_IDLE, + COEX_ASSOC_MANUAL_SCAN, + COEX_ASSOC_AUTO_SCAN, + COEX_ASSOC_ACTIVE_LEVEL, + + /* RF ON/OFF */ + COEX_RF_ON, + COEX_RF_OFF, + COEX_STAND_ALONE_DEBUG, + + /* IPNN */ + COEX_IPAN_ASSOC_LEVEL, + + /* RESERVED */ + COEX_RSRVD1, + COEX_RSRVD2, + + COEX_EVENTS_NUM +}; + +#define COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK 0x1 +#define COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK 0x2 +#define COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_MSK 0x4 + +struct coex_event { + u8 req_prio; + u8 win_med_prio; + u8 reserved; + u8 flags; +} __attribute__ ((packed)); + +#define COEX_FLAGS_STA_TABLE_VALID_MSK 0x1 +#define COEX_FLAGS_UNASSOC_WAKEUP_UMASK_MSK 0x4 +#define COEX_FLAGS_ASSOC_WAKEUP_UMASK_MSK 0x8 +#define COEX_FLAGS_COEX_ENABLE_MSK 0x80 + +struct iwm_coex_prio_table_cmd { + u8 flags; + u8 reserved[3]; + struct coex_event sta_prio[COEX_EVENTS_NUM]; +} __attribute__ ((packed)); + +/* Coexistence definitions + * + * Constants to fill in the Priorities' Tables + * RP - Requested Priority + * WP - Win Medium Priority: priority assigned when the contention has been won + * FLAGS - Combination of COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK and + * COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK + */ + +#define COEX_UNASSOC_IDLE_FLAGS 0 +#define COEX_UNASSOC_MANUAL_SCAN_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \ + COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK) +#define COEX_UNASSOC_AUTO_SCAN_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \ + COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK) +#define COEX_CALIBRATION_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \ + COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK) +#define COEX_PERIODIC_CALIBRATION_FLAGS 0 +/* COEX_CONNECTION_ESTAB: we need DELAY_MEDIUM_FREE_NTFY to let WiMAX + * disconnect from network. */ +#define COEX_CONNECTION_ESTAB_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \ + COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK | \ + COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_MSK) +#define COEX_ASSOCIATED_IDLE_FLAGS 0 +#define COEX_ASSOC_MANUAL_SCAN_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \ + COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK) +#define COEX_ASSOC_AUTO_SCAN_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \ + COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK) +#define COEX_ASSOC_ACTIVE_LEVEL_FLAGS 0 +#define COEX_RF_ON_FLAGS 0 +#define COEX_RF_OFF_FLAGS 0 +#define COEX_STAND_ALONE_DEBUG_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \ + COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK) +#define COEX_IPAN_ASSOC_LEVEL_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \ + COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK | \ + COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_MSK) +#define COEX_RSRVD1_FLAGS 0 +#define COEX_RSRVD2_FLAGS 0 +/* XOR_RF_ON is the event wrapping all radio ownership. We need + * DELAY_MEDIUM_FREE_NTFY to let WiMAX disconnect from network. */ +#define COEX_XOR_RF_ON_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \ + COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK | \ + COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_MSK) + +/* LMAC OP CODES */ +#define REPLY_PAD 0x0 +#define REPLY_ALIVE 0x1 +#define REPLY_ERROR 0x2 +#define REPLY_ECHO 0x3 +#define REPLY_HALT 0x6 + +/* RXON state commands */ +#define REPLY_RX_ON 0x10 +#define REPLY_RX_ON_ASSOC 0x11 +#define REPLY_RX_OFF 0x12 +#define REPLY_QOS_PARAM 0x13 +#define REPLY_RX_ON_TIMING 0x14 +#define REPLY_INTERNAL_QOS_PARAM 0x15 +#define REPLY_RX_INT_TIMEOUT_CNFG 0x16 +#define REPLY_NULL 0x17 + +/* Multi-Station support */ +#define REPLY_ADD_STA 0x18 +#define REPLY_REMOVE_STA 0x19 +#define REPLY_RESET_ALL_STA 0x1a + +/* RX, TX */ +#define REPLY_ALM_RX 0x1b +#define REPLY_TX 0x1c +#define REPLY_TXFIFO_FLUSH 0x1e + +/* MISC commands */ +#define REPLY_MGMT_MCAST_KEY 0x1f +#define REPLY_WEPKEY 0x20 +#define REPLY_INIT_IV 0x21 +#define REPLY_WRITE_MIB 0x22 +#define REPLY_READ_MIB 0x23 +#define REPLY_RADIO_FE 0x24 +#define REPLY_TXFIFO_CFG 0x25 +#define REPLY_WRITE_READ 0x26 +#define REPLY_INSTALL_SEC_KEY 0x27 + + +#define REPLY_RATE_SCALE 0x47 +#define REPLY_LEDS_CMD 0x48 +#define REPLY_TX_LINK_QUALITY_CMD 0x4e +#define REPLY_ANA_MIB_OVERRIDE_CMD 0x4f +#define REPLY_WRITE2REG_CMD 0x50 + +/* winfi-wifi coexistence */ +#define COEX_PRIORITY_TABLE_CMD 0x5a +#define COEX_MEDIUM_NOTIFICATION 0x5b +#define COEX_EVENT_CMD 0x5c + +/* more Protocol and Protocol-test commands */ +#define REPLY_MAX_SLEEP_TIME_CMD 0x61 +#define CALIBRATION_CFG_CMD 0x65 +#define CALIBRATION_RES_NOTIFICATION 0x66 +#define CALIBRATION_COMPLETE_NOTIFICATION 0x67 + +/* Measurements */ +#define REPLY_QUIET_CMD 0x71 +#define REPLY_CHANNEL_SWITCH 0x72 +#define CHANNEL_SWITCH_NOTIFICATION 0x73 + +#define REPLY_SPECTRUM_MEASUREMENT_CMD 0x74 +#define SPECTRUM_MEASURE_NOTIFICATION 0x75 +#define REPLY_MEASUREMENT_ABORT_CMD 0x76 + +/* Power Management */ +#define POWER_TABLE_CMD 0x77 +#define SAVE_RESTORE_ADRESS_CMD 0x78 +#define REPLY_WATERMARK_CMD 0x79 +#define PM_DEBUG_STATISTIC_NOTIFIC 0x7B +#define PD_FLUSH_N_NOTIFICATION 0x7C + +/* Scan commands and notifications */ +#define REPLY_SCAN_REQUEST_CMD 0x80 +#define REPLY_SCAN_ABORT_CMD 0x81 +#define SCAN_START_NOTIFICATION 0x82 +#define SCAN_RESULTS_NOTIFICATION 0x83 +#define SCAN_COMPLETE_NOTIFICATION 0x84 + +/* Continuous TX commands */ +#define REPLY_CONT_TX_CMD 0x85 +#define END_OF_CONT_TX_NOTIFICATION 0x86 + +/* Timer/Eeprom commands */ +#define TIMER_CMD 0x87 +#define EEPROM_WRITE_CMD 0x88 + +/* PAPD commands */ +#define FEEDBACK_REQUEST_NOTIFICATION 0x8b +#define REPLY_CW_CMD 0x8c + +/* IBSS/AP commands Continue */ +#define BEACON_NOTIFICATION 0x90 +#define REPLY_TX_BEACON 0x91 +#define REPLY_REQUEST_ATIM 0x93 +#define WHO_IS_AWAKE_NOTIFICATION 0x94 +#define TX_PWR_DBM_LIMIT_CMD 0x95 +#define QUIET_NOTIFICATION 0x96 +#define TX_PWR_TABLE_CMD 0x97 +#define TX_ANT_CONFIGURATION_CMD 0x98 +#define MEASURE_ABORT_NOTIFICATION 0x99 +#define REPLY_CALIBRATION_TUNE 0x9a + +/* bt config command */ +#define REPLY_BT_CONFIG 0x9b +#define REPLY_STATISTICS_CMD 0x9c +#define STATISTICS_NOTIFICATION 0x9d + +/* RF-KILL commands and notifications */ +#define REPLY_CARD_STATE_CMD 0xa0 +#define CARD_STATE_NOTIFICATION 0xa1 + +/* Missed beacons notification */ +#define MISSED_BEACONS_NOTIFICATION 0xa2 +#define MISSED_BEACONS_NOTIFICATION_TH_CMD 0xa3 + +#define REPLY_CT_KILL_CONFIG_CMD 0xa4 + +/* HD commands and notifications */ +#define REPLY_HD_PARAMS_CMD 0xa6 +#define HD_PARAMS_NOTIFICATION 0xa7 +#define SENSITIVITY_CMD 0xa8 +#define U_APSD_PARAMS_CMD 0xa9 +#define NOISY_PLATFORM_CMD 0xaa +#define ILLEGAL_CMD 0xac +#define REPLY_PHY_CALIBRATION_CMD 0xb0 +#define REPLAY_RX_GAIN_CALIB_CMD 0xb1 + +/* WiPAN commands */ +#define REPLY_WIPAN_PARAMS_CMD 0xb2 +#define REPLY_WIPAN_RX_ON_CMD 0xb3 +#define REPLY_WIPAN_RX_ON_TIMING 0xb4 +#define REPLY_WIPAN_TX_PWR_TABLE_CMD 0xb5 +#define REPLY_WIPAN_RXON_ASSOC_CMD 0xb6 +#define REPLY_WIPAN_QOS_PARAM 0xb7 +#define WIPAN_REPLY_WEPKEY 0xb8 + +/* BeamForming commands */ +#define BEAMFORMER_CFG_CMD 0xba +#define BEAMFORMEE_NOTIFICATION 0xbb + +/* TGn new Commands */ +#define REPLY_RX_PHY_CMD 0xc0 +#define REPLY_RX_MPDU_CMD 0xc1 +#define REPLY_MULTICAST_HASH 0xc2 +#define REPLY_KDR_RX 0xc3 +#define REPLY_RX_DSP_EXT_INFO 0xc4 +#define REPLY_COMPRESSED_BA 0xc5 + +/* PNC commands */ +#define PNC_CONFIG_CMD 0xc8 +#define PNC_UPDATE_TABLE_CMD 0xc9 +#define XVT_GENERAL_CTRL_CMD 0xca +#define REPLY_LEGACY_RADIO_FE 0xdd + +/* WoWLAN commands */ +#define WOWLAN_PATTERNS 0xe0 +#define WOWLAN_WAKEUP_FILTER 0xe1 +#define WOWLAN_TSC_RSC_PARAM 0xe2 +#define WOWLAN_TKIP_PARAM 0xe3 +#define WOWLAN_KEK_KCK_MATERIAL 0xe4 +#define WOWLAN_GET_STATUSES 0xe5 +#define WOWLAN_TX_POWER_PER_DB 0xe6 +#define REPLY_WOWLAN_GET_STATUSES WOWLAN_GET_STATUSES + +#define REPLY_DEBUG_CMD 0xf0 +#define REPLY_DSP_DEBUG_CMD 0xf1 +#define REPLY_DEBUG_MONITOR_CMD 0xf2 +#define REPLY_DEBUG_XVT_CMD 0xf3 +#define REPLY_DEBUG_DC_CALIB 0xf4 +#define REPLY_DYNAMIC_BP 0xf5 + +/* General purpose Commands */ +#define REPLY_GP1_CMD 0xfa +#define REPLY_GP2_CMD 0xfb +#define REPLY_GP3_CMD 0xfc +#define REPLY_GP4_CMD 0xfd +#define REPLY_REPLAY_WRAPPER 0xfe +#define REPLY_FRAME_DURATION_CALC_CMD 0xff + +#define LMAC_COMMAND_ID_MAX 0xff +#define LMAC_COMMAND_ID_NUM (LMAC_COMMAND_ID_MAX + 1) + + +/* Calibration */ + +enum { + PHY_CALIBRATE_DC_CMD = 0, + PHY_CALIBRATE_LO_CMD = 1, + PHY_CALIBRATE_RX_BB_CMD = 2, + PHY_CALIBRATE_TX_IQ_CMD = 3, + PHY_CALIBRATE_RX_IQ_CMD = 4, + PHY_CALIBRATION_NOISE_CMD = 5, + PHY_CALIBRATE_AGC_TABLE_CMD = 6, + PHY_CALIBRATE_CRYSTAL_FRQ_CMD = 7, + PHY_CALIBRATE_OPCODES_NUM, + SHILOH_PHY_CALIBRATE_DC_CMD = 8, + SHILOH_PHY_CALIBRATE_LO_CMD = 9, + SHILOH_PHY_CALIBRATE_RX_BB_CMD = 10, + SHILOH_PHY_CALIBRATE_TX_IQ_CMD = 11, + SHILOH_PHY_CALIBRATE_RX_IQ_CMD = 12, + SHILOH_PHY_CALIBRATION_NOISE_CMD = 13, + SHILOH_PHY_CALIBRATE_AGC_TABLE_CMD = 14, + SHILOH_PHY_CALIBRATE_CRYSTAL_FRQ_CMD = 15, + SHILOH_PHY_CALIBRATE_BASE_BAND_CMD = 16, + SHILOH_PHY_CALIBRATE_TXIQ_PERIODIC_CMD = 17, + CALIBRATION_CMD_NUM, +}; + +struct iwm_lmac_calib_hdr { + u8 opcode; + u8 first_grp; + u8 grp_num; + u8 all_data_valid; +} __attribute__ ((packed)); + +#define IWM_LMAC_CALIB_FREQ_GROUPS_NR 7 +#define IWM_CALIB_FREQ_GROUPS_NR 5 +#define IWM_CALIB_DC_MODES_NR 12 + +struct iwm_calib_rxiq_entry { + u16 ptam_postdist_ars; + u16 ptam_postdist_arc; +} __attribute__ ((packed)); + +struct iwm_calib_rxiq_group { + struct iwm_calib_rxiq_entry mode[IWM_CALIB_DC_MODES_NR]; +} __attribute__ ((packed)); + +struct iwm_lmac_calib_rxiq { + struct iwm_calib_rxiq_group group[IWM_LMAC_CALIB_FREQ_GROUPS_NR]; +} __attribute__ ((packed)); + +struct iwm_calib_rxiq { + struct iwm_lmac_calib_hdr hdr; + struct iwm_calib_rxiq_group group[IWM_CALIB_FREQ_GROUPS_NR]; +} __attribute__ ((packed)); + +#define LMAC_STA_ID_SEED 0x0f +#define LMAC_STA_ID_POS 0 + +#define LMAC_STA_COLOR_SEED 0x7 +#define LMAC_STA_COLOR_POS 4 + +struct iwm_lmac_power_report { + u8 pa_status; + u8 pa_integ_res_A[3]; + u8 pa_integ_res_B[3]; + u8 pa_integ_res_C[3]; +} __attribute__ ((packed)); + +struct iwm_lmac_tx_resp { + u8 frame_cnt; /* 1-no aggregation, greater then 1 - aggregation */ + u8 bt_kill_cnt; + __le16 retry_cnt; + __le32 initial_tx_rate; + __le16 wireless_media_time; + struct iwm_lmac_power_report power_report; + __le32 tfd_info; + __le16 seq_ctl; + __le16 byte_cnt; + u8 tlc_rate_info; + u8 ra_tid; + __le16 frame_ctl; + __le32 status; +} __attribute__ ((packed)); + +#endif diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c new file mode 100644 index 000000000000..8be206d58222 --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/main.c @@ -0,0 +1,732 @@ +/* + * Intel Wireless Multicomm 3200 WiFi driver + * + * Copyright (C) 2009 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * Intel Corporation + * Samuel Ortiz + * Zhu Yi + * + */ + +#include +#include +#include +#include + +#include "iwm.h" +#include "debug.h" +#include "bus.h" +#include "umac.h" +#include "commands.h" +#include "hal.h" +#include "fw.h" +#include "rx.h" + +static struct iwm_conf def_iwm_conf = { + + .sdio_ior_timeout = 5000, + .init_calib_map = BIT(PHY_CALIBRATE_DC_CMD) | + BIT(PHY_CALIBRATE_LO_CMD) | + BIT(PHY_CALIBRATE_TX_IQ_CMD) | + BIT(PHY_CALIBRATE_RX_IQ_CMD), + .periodic_calib_map = BIT(PHY_CALIBRATE_DC_CMD) | + BIT(PHY_CALIBRATE_LO_CMD) | + BIT(PHY_CALIBRATE_TX_IQ_CMD) | + BIT(PHY_CALIBRATE_RX_IQ_CMD) | + BIT(SHILOH_PHY_CALIBRATE_BASE_BAND_CMD), + .reset_on_fatal_err = 1, + .auto_connect = 1, + .wimax_not_present = 0, + .enable_qos = 1, + .mode = UMAC_MODE_BSS, + + /* UMAC configuration */ + .power_index = 0, + .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD, + .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD, + .cts_to_self = 0, + + .assoc_timeout = 2, + .roam_timeout = 10, + .wireless_mode = WIRELESS_MODE_11A | WIRELESS_MODE_11G, + .coexist_mode = COEX_MODE_CM, + + /* IBSS */ + .ibss_band = UMAC_BAND_2GHZ, + .ibss_channel = 1, + + .mac_addr = {0x00, 0x02, 0xb3, 0x01, 0x02, 0x03}, +}; + +static int modparam_reset; +module_param_named(reset, modparam_reset, bool, 0644); +MODULE_PARM_DESC(reset, "reset on firmware errors (default 0 [not reset])"); + +int iwm_mode_to_nl80211_iftype(int mode) +{ + switch (mode) { + case UMAC_MODE_BSS: + return NL80211_IFTYPE_STATION; + case UMAC_MODE_IBSS: + return NL80211_IFTYPE_ADHOC; + default: + return NL80211_IFTYPE_UNSPECIFIED; + } + + return 0; +} + +static void iwm_statistics_request(struct work_struct *work) +{ + struct iwm_priv *iwm = + container_of(work, struct iwm_priv, stats_request.work); + + iwm_send_umac_stats_req(iwm, 0); +} + +int __iwm_up(struct iwm_priv *iwm); +int __iwm_down(struct iwm_priv *iwm); + +static void iwm_reset_worker(struct work_struct *work) +{ + struct iwm_priv *iwm; + struct iwm_umac_profile *profile = NULL; + int uninitialized_var(ret), retry = 0; + + iwm = container_of(work, struct iwm_priv, reset_worker); + + /* + * XXX: The iwm->mutex is introduced purely for this reset work, + * because the other users for iwm_up and iwm_down are only netdev + * ndo_open and ndo_stop which are already protected by rtnl. + * Please remove iwm->mutex together if iwm_reset_worker() is not + * required in the future. + */ + if (!mutex_trylock(&iwm->mutex)) { + IWM_WARN(iwm, "We are in the middle of interface bringing " + "UP/DOWN. Skip driver resetting.\n"); + return; + } + + if (iwm->umac_profile_active) { + profile = kmalloc(sizeof(struct iwm_umac_profile), GFP_KERNEL); + if (profile) + memcpy(profile, iwm->umac_profile, sizeof(*profile)); + else + IWM_ERR(iwm, "Couldn't alloc memory for profile\n"); + } + + __iwm_down(iwm); + + while (retry++ < 3) { + ret = __iwm_up(iwm); + if (!ret) + break; + + schedule_timeout_uninterruptible(10 * HZ); + } + + if (ret) { + IWM_WARN(iwm, "iwm_up() failed: %d\n", ret); + + kfree(profile); + goto out; + } + + if (profile) { + IWM_DBG_MLME(iwm, DBG, "Resend UMAC profile\n"); + memcpy(iwm->umac_profile, profile, sizeof(*profile)); + iwm_send_mlme_profile(iwm); + kfree(profile); + } + + out: + mutex_unlock(&iwm->mutex); +} + +static void iwm_watchdog(unsigned long data) +{ + struct iwm_priv *iwm = (struct iwm_priv *)data; + + IWM_WARN(iwm, "Watchdog expired: UMAC stalls!\n"); + + if (modparam_reset) + schedule_work(&iwm->reset_worker); +} + +int iwm_priv_init(struct iwm_priv *iwm) +{ + int i; + char name[32]; + + iwm->status = 0; + INIT_LIST_HEAD(&iwm->pending_notif); + init_waitqueue_head(&iwm->notif_queue); + init_waitqueue_head(&iwm->nonwifi_queue); + init_waitqueue_head(&iwm->mlme_queue); + memcpy(&iwm->conf, &def_iwm_conf, sizeof(struct iwm_conf)); + spin_lock_init(&iwm->tx_credit.lock); + INIT_LIST_HEAD(&iwm->wifi_pending_cmd); + INIT_LIST_HEAD(&iwm->nonwifi_pending_cmd); + iwm->wifi_seq_num = UMAC_WIFI_SEQ_NUM_BASE; + iwm->nonwifi_seq_num = UMAC_NONWIFI_SEQ_NUM_BASE; + spin_lock_init(&iwm->cmd_lock); + iwm->scan_id = 1; + INIT_DELAYED_WORK(&iwm->stats_request, iwm_statistics_request); + INIT_WORK(&iwm->reset_worker, iwm_reset_worker); + INIT_LIST_HEAD(&iwm->bss_list); + + skb_queue_head_init(&iwm->rx_list); + INIT_LIST_HEAD(&iwm->rx_tickets); + for (i = 0; i < IWM_RX_ID_HASH; i++) + INIT_LIST_HEAD(&iwm->rx_packets[i]); + + INIT_WORK(&iwm->rx_worker, iwm_rx_worker); + + iwm->rx_wq = create_singlethread_workqueue(KBUILD_MODNAME "_rx"); + if (!iwm->rx_wq) + return -EAGAIN; + + for (i = 0; i < IWM_TX_QUEUES; i++) { + INIT_WORK(&iwm->txq[i].worker, iwm_tx_worker); + snprintf(name, 32, KBUILD_MODNAME "_tx_%d", i); + iwm->txq[i].id = i; + iwm->txq[i].wq = create_singlethread_workqueue(name); + if (!iwm->txq[i].wq) + return -EAGAIN; + + skb_queue_head_init(&iwm->txq[i].queue); + } + + for (i = 0; i < IWM_NUM_KEYS; i++) + memset(&iwm->keys[i], 0, sizeof(struct iwm_key)); + + iwm->default_key = NULL; + + init_timer(&iwm->watchdog); + iwm->watchdog.function = iwm_watchdog; + iwm->watchdog.data = (unsigned long)iwm; + mutex_init(&iwm->mutex); + + return 0; +} + +void iwm_priv_deinit(struct iwm_priv *iwm) +{ + int i; + + for (i = 0; i < IWM_TX_QUEUES; i++) + destroy_workqueue(iwm->txq[i].wq); + + destroy_workqueue(iwm->rx_wq); +} + +/* + * We reset all the structures, and we reset the UMAC. + * After calling this routine, you're expected to reload + * the firmware. + */ +void iwm_reset(struct iwm_priv *iwm) +{ + struct iwm_notif *notif, *next; + + if (test_bit(IWM_STATUS_READY, &iwm->status)) + iwm_target_reset(iwm); + + iwm->status = 0; + iwm->scan_id = 1; + + list_for_each_entry_safe(notif, next, &iwm->pending_notif, pending) { + list_del(¬if->pending); + kfree(notif->buf); + kfree(notif); + } + + iwm_cmd_flush(iwm); + + flush_workqueue(iwm->rx_wq); + + iwm_link_off(iwm); +} + +/* + * Notification code: + * + * We're faced with the following issue: Any host command can + * have an answer or not, and if there's an answer to expect, + * it can be treated synchronously or asynchronously. + * To work around the synchronous answer case, we implemented + * our notification mechanism. + * When a code path needs to wait for a command response + * synchronously, it calls notif_handle(), which waits for the + * right notification to show up, and then process it. Before + * starting to wait, it registered as a waiter for this specific + * answer (by toggling a bit in on of the handler_map), so that + * the rx code knows that it needs to send a notification to the + * waiting processes. It does so by calling iwm_notif_send(), + * which adds the notification to the pending notifications list, + * and then wakes the waiting processes up. + */ +int iwm_notif_send(struct iwm_priv *iwm, struct iwm_wifi_cmd *cmd, + u8 cmd_id, u8 source, u8 *buf, unsigned long buf_size) +{ + struct iwm_notif *notif; + + notif = kzalloc(sizeof(struct iwm_notif), GFP_KERNEL); + if (!notif) { + IWM_ERR(iwm, "Couldn't alloc memory for notification\n"); + return -ENOMEM; + } + + INIT_LIST_HEAD(¬if->pending); + notif->cmd = cmd; + notif->cmd_id = cmd_id; + notif->src = source; + notif->buf = kzalloc(buf_size, GFP_KERNEL); + if (!notif->buf) { + IWM_ERR(iwm, "Couldn't alloc notification buffer\n"); + kfree(notif); + return -ENOMEM; + } + notif->buf_size = buf_size; + memcpy(notif->buf, buf, buf_size); + list_add_tail(¬if->pending, &iwm->pending_notif); + + wake_up_interruptible(&iwm->notif_queue); + + return 0; +} + +static struct iwm_notif *iwm_notif_find(struct iwm_priv *iwm, u32 cmd, + u8 source) +{ + struct iwm_notif *notif, *next; + + list_for_each_entry_safe(notif, next, &iwm->pending_notif, pending) { + if ((notif->cmd_id == cmd) && (notif->src == source)) { + list_del(¬if->pending); + return notif; + } + } + + return NULL; +} + +static struct iwm_notif *iwm_notif_wait(struct iwm_priv *iwm, u32 cmd, + u8 source, long timeout) +{ + int ret; + struct iwm_notif *notif; + unsigned long *map = NULL; + + switch (source) { + case IWM_SRC_LMAC: + map = &iwm->lmac_handler_map[0]; + break; + case IWM_SRC_UMAC: + map = &iwm->umac_handler_map[0]; + break; + case IWM_SRC_UDMA: + map = &iwm->udma_handler_map[0]; + break; + } + + set_bit(cmd, map); + + ret = wait_event_interruptible_timeout(iwm->notif_queue, + ((notif = iwm_notif_find(iwm, cmd, source)) != NULL), + timeout); + clear_bit(cmd, map); + + if (!ret) + return NULL; + + return notif; +} + +int iwm_notif_handle(struct iwm_priv *iwm, u32 cmd, u8 source, long timeout) +{ + int ret; + struct iwm_notif *notif; + + notif = iwm_notif_wait(iwm, cmd, source, timeout); + if (!notif) + return -ETIME; + + ret = iwm_rx_handle_resp(iwm, notif->buf, notif->buf_size, notif->cmd); + kfree(notif->buf); + kfree(notif); + + return ret; +} + +static int iwm_config_boot_params(struct iwm_priv *iwm) +{ + struct iwm_udma_nonwifi_cmd target_cmd; + int ret; + + /* check Wimax is off and config debug monitor */ + if (iwm->conf.wimax_not_present) { + u32 data1 = 0x1f; + u32 addr1 = 0x606BE258; + + u32 data2_set = 0x0; + u32 data2_clr = 0x1; + u32 addr2 = 0x606BE100; + + u32 data3 = 0x1; + u32 addr3 = 0x606BEC00; + + target_cmd.resp = 0; + target_cmd.handle_by_hw = 0; + target_cmd.eop = 1; + + target_cmd.opcode = UMAC_HDI_OUT_OPCODE_WRITE; + target_cmd.addr = cpu_to_le32(addr1); + target_cmd.op1_sz = cpu_to_le32(sizeof(u32)); + target_cmd.op2 = 0; + + ret = iwm_hal_send_target_cmd(iwm, &target_cmd, &data1); + if (ret < 0) { + IWM_ERR(iwm, "iwm_hal_send_target_cmd failed\n"); + return ret; + } + + target_cmd.opcode = UMAC_HDI_OUT_OPCODE_READ_MODIFY_WRITE; + target_cmd.addr = cpu_to_le32(addr2); + target_cmd.op1_sz = cpu_to_le32(data2_set); + target_cmd.op2 = cpu_to_le32(data2_clr); + + ret = iwm_hal_send_target_cmd(iwm, &target_cmd, &data1); + if (ret < 0) { + IWM_ERR(iwm, "iwm_hal_send_target_cmd failed\n"); + return ret; + } + + target_cmd.opcode = UMAC_HDI_OUT_OPCODE_WRITE; + target_cmd.addr = cpu_to_le32(addr3); + target_cmd.op1_sz = cpu_to_le32(sizeof(u32)); + target_cmd.op2 = 0; + + ret = iwm_hal_send_target_cmd(iwm, &target_cmd, &data3); + if (ret < 0) { + IWM_ERR(iwm, "iwm_hal_send_target_cmd failed\n"); + return ret; + } + } + + return 0; +} + +void iwm_init_default_profile(struct iwm_priv *iwm, + struct iwm_umac_profile *profile) +{ + memset(profile, 0, sizeof(struct iwm_umac_profile)); + + profile->sec.auth_type = UMAC_AUTH_TYPE_OPEN; + profile->sec.flags = UMAC_SEC_FLG_LEGACY_PROFILE; + profile->sec.ucast_cipher = UMAC_CIPHER_TYPE_NONE; + profile->sec.mcast_cipher = UMAC_CIPHER_TYPE_NONE; + + if (iwm->conf.enable_qos) + profile->flags |= cpu_to_le16(UMAC_PROFILE_QOS_ALLOWED); + + profile->wireless_mode = iwm->conf.wireless_mode; + profile->mode = cpu_to_le32(iwm->conf.mode); + + profile->ibss.atim = 0; + profile->ibss.beacon_interval = 100; + profile->ibss.join_only = 0; + profile->ibss.band = iwm->conf.ibss_band; + profile->ibss.channel = iwm->conf.ibss_channel; +} + +void iwm_link_on(struct iwm_priv *iwm) +{ + netif_carrier_on(iwm_to_ndev(iwm)); + netif_tx_wake_all_queues(iwm_to_ndev(iwm)); + + iwm_send_umac_stats_req(iwm, 0); +} + +void iwm_link_off(struct iwm_priv *iwm) +{ + struct iw_statistics *wstats = &iwm->wstats; + int i; + + netif_tx_stop_all_queues(iwm_to_ndev(iwm)); + netif_carrier_off(iwm_to_ndev(iwm)); + + for (i = 0; i < IWM_TX_QUEUES; i++) { + skb_queue_purge(&iwm->txq[i].queue); + + iwm->txq[i].concat_count = 0; + iwm->txq[i].concat_ptr = iwm->txq[i].concat_buf; + + flush_workqueue(iwm->txq[i].wq); + } + + iwm_rx_free(iwm); + + cancel_delayed_work_sync(&iwm->stats_request); + memset(wstats, 0, sizeof(struct iw_statistics)); + wstats->qual.updated = IW_QUAL_ALL_INVALID; + + del_timer_sync(&iwm->watchdog); +} + +static void iwm_bss_list_clean(struct iwm_priv *iwm) +{ + struct iwm_bss_info *bss, *next; + + list_for_each_entry_safe(bss, next, &iwm->bss_list, node) { + list_del(&bss->node); + kfree(bss->bss); + kfree(bss); + } +} + +static int iwm_channels_init(struct iwm_priv *iwm) +{ + int ret; + +#ifdef CONFIG_IWM_B0_HW_SUPPORT + if (iwm->conf.hw_b0) { + IWM_INFO(iwm, "Workaround EEPROM channels for B0 hardware\n"); + return 0; + } +#endif + + ret = iwm_send_umac_channel_list(iwm); + if (ret) { + IWM_ERR(iwm, "Send channel list failed\n"); + return ret; + } + + ret = iwm_notif_handle(iwm, UMAC_CMD_OPCODE_GET_CHAN_INFO_LIST, + IWM_SRC_UMAC, WAIT_NOTIF_TIMEOUT); + if (ret) { + IWM_ERR(iwm, "Didn't get a channel list notification\n"); + return ret; + } + + return 0; +} + +int __iwm_up(struct iwm_priv *iwm) +{ + int ret; + struct iwm_notif *notif_reboot, *notif_ack = NULL; + + ret = iwm_bus_enable(iwm); + if (ret) { + IWM_ERR(iwm, "Couldn't enable function\n"); + return ret; + } + + iwm_rx_setup_handlers(iwm); + + /* Wait for initial BARKER_REBOOT from hardware */ + notif_reboot = iwm_notif_wait(iwm, IWM_BARKER_REBOOT_NOTIFICATION, + IWM_SRC_UDMA, 2 * HZ); + if (!notif_reboot) { + IWM_ERR(iwm, "Wait for REBOOT_BARKER timeout\n"); + goto err_disable; + } + + /* We send the barker back */ + ret = iwm_bus_send_chunk(iwm, notif_reboot->buf, 16); + if (ret) { + IWM_ERR(iwm, "REBOOT barker response failed\n"); + kfree(notif_reboot); + goto err_disable; + } + + kfree(notif_reboot->buf); + kfree(notif_reboot); + + /* Wait for ACK_BARKER from hardware */ + notif_ack = iwm_notif_wait(iwm, IWM_ACK_BARKER_NOTIFICATION, + IWM_SRC_UDMA, 2 * HZ); + if (!notif_ack) { + IWM_ERR(iwm, "Wait for ACK_BARKER timeout\n"); + goto err_disable; + } + + kfree(notif_ack->buf); + kfree(notif_ack); + + /* We start to config static boot parameters */ + ret = iwm_config_boot_params(iwm); + if (ret) { + IWM_ERR(iwm, "Config boot parameters failed\n"); + goto err_disable; + } + + ret = iwm_read_mac(iwm, iwm_to_ndev(iwm)->dev_addr); + if (ret) { + IWM_ERR(iwm, "MAC reading failed\n"); + goto err_disable; + } + + /* We can load the FWs */ + ret = iwm_load_fw(iwm); + if (ret) { + IWM_ERR(iwm, "FW loading failed\n"); + goto err_disable; + } + + /* We configure the UMAC and enable the wifi module */ + ret = iwm_send_umac_config(iwm, + cpu_to_le32(UMAC_RST_CTRL_FLG_WIFI_CORE_EN) | + cpu_to_le32(UMAC_RST_CTRL_FLG_WIFI_LINK_EN) | + cpu_to_le32(UMAC_RST_CTRL_FLG_WIFI_MLME_EN)); + if (ret) { + IWM_ERR(iwm, "UMAC config failed\n"); + goto err_fw; + } + + ret = iwm_notif_handle(iwm, UMAC_NOTIFY_OPCODE_WIFI_CORE_STATUS, + IWM_SRC_UMAC, WAIT_NOTIF_TIMEOUT); + if (ret) { + IWM_ERR(iwm, "Didn't get a wifi core status notification\n"); + goto err_fw; + } + + if (iwm->core_enabled != (UMAC_NTFY_WIFI_CORE_STATUS_LINK_EN | + UMAC_NTFY_WIFI_CORE_STATUS_MLME_EN)) { + IWM_DBG_BOOT(iwm, DBG, "Not all cores enabled:0x%x\n", + iwm->core_enabled); + ret = iwm_notif_handle(iwm, UMAC_NOTIFY_OPCODE_WIFI_CORE_STATUS, + IWM_SRC_UMAC, WAIT_NOTIF_TIMEOUT); + if (ret) { + IWM_ERR(iwm, "Didn't get a core status notification\n"); + goto err_fw; + } + + if (iwm->core_enabled != (UMAC_NTFY_WIFI_CORE_STATUS_LINK_EN | + UMAC_NTFY_WIFI_CORE_STATUS_MLME_EN)) { + IWM_ERR(iwm, "Not all cores enabled: 0x%x\n", + iwm->core_enabled); + goto err_fw; + } else { + IWM_INFO(iwm, "All cores enabled\n"); + } + } + + iwm->umac_profile = kmalloc(sizeof(struct iwm_umac_profile), + GFP_KERNEL); + if (!iwm->umac_profile) { + IWM_ERR(iwm, "Couldn't alloc memory for profile\n"); + goto err_fw; + } + + iwm_init_default_profile(iwm, iwm->umac_profile); + + ret = iwm_channels_init(iwm); + if (ret < 0) { + IWM_ERR(iwm, "Couldn't init channels\n"); + goto err_profile; + } + + /* Set the READY bit to indicate interface is brought up successfully */ + set_bit(IWM_STATUS_READY, &iwm->status); + + return 0; + + err_profile: + kfree(iwm->umac_profile); + iwm->umac_profile = NULL; + + err_fw: + iwm_eeprom_exit(iwm); + + err_disable: + ret = iwm_bus_disable(iwm); + if (ret < 0) + IWM_ERR(iwm, "Couldn't disable function\n"); + + return -EIO; +} + +int iwm_up(struct iwm_priv *iwm) +{ + int ret; + + mutex_lock(&iwm->mutex); + ret = __iwm_up(iwm); + mutex_unlock(&iwm->mutex); + + return ret; +} + +int __iwm_down(struct iwm_priv *iwm) +{ + int ret; + + /* The interface is already down */ + if (!test_bit(IWM_STATUS_READY, &iwm->status)) + return 0; + + if (iwm->scan_request) { + cfg80211_scan_done(iwm->scan_request, true); + iwm->scan_request = NULL; + } + + clear_bit(IWM_STATUS_READY, &iwm->status); + + iwm_eeprom_exit(iwm); + kfree(iwm->umac_profile); + iwm->umac_profile = NULL; + iwm_bss_list_clean(iwm); + + iwm->default_key = NULL; + iwm->core_enabled = 0; + + ret = iwm_bus_disable(iwm); + if (ret < 0) { + IWM_ERR(iwm, "Couldn't disable function\n"); + return ret; + } + + return 0; +} + +int iwm_down(struct iwm_priv *iwm) +{ + int ret; + + mutex_lock(&iwm->mutex); + ret = __iwm_down(iwm); + mutex_unlock(&iwm->mutex); + + return ret; +} diff --git a/drivers/net/wireless/iwmc3200wifi/netdev.c b/drivers/net/wireless/iwmc3200wifi/netdev.c new file mode 100644 index 000000000000..aaa20c6885c8 --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/netdev.c @@ -0,0 +1,175 @@ +/* + * Intel Wireless Multicomm 3200 WiFi driver + * + * Copyright (C) 2009 Intel Corporation + * Samuel Ortiz + * Zhu Yi + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +/* + * This is the netdev related hooks for iwm. + * + * Some interesting code paths: + * + * iwm_open() (Called at netdev interface bringup time) + * -> iwm_up() (main.c) + * -> iwm_bus_enable() + * -> if_sdio_enable() (In case of an SDIO bus) + * -> sdio_enable_func() + * -> iwm_notif_wait(BARKER_REBOOT) (wait for reboot barker) + * -> iwm_notif_wait(ACK_BARKER) (wait for ACK barker) + * -> iwm_load_fw() (fw.c) + * -> iwm_load_umac() + * -> iwm_load_lmac() (Calibration LMAC) + * -> iwm_load_lmac() (Operational LMAC) + * -> iwm_send_umac_config() + * + * iwm_stop() (Called at netdev interface bringdown time) + * -> iwm_down() + * -> iwm_bus_disable() + * -> if_sdio_disable() (In case of an SDIO bus) + * -> sdio_disable_func() + */ +#include + +#include "iwm.h" +#include "cfg80211.h" +#include "debug.h" + +static int iwm_open(struct net_device *ndev) +{ + struct iwm_priv *iwm = ndev_to_iwm(ndev); + int ret = 0; + + if (!test_bit(IWM_RADIO_RFKILL_SW, &iwm->radio)) + ret = iwm_up(iwm); + + return ret; +} + +static int iwm_stop(struct net_device *ndev) +{ + struct iwm_priv *iwm = ndev_to_iwm(ndev); + int ret = 0; + + if (!test_bit(IWM_RADIO_RFKILL_SW, &iwm->radio)) + ret = iwm_down(iwm); + + return ret; +} + +/* + * iwm AC to queue mapping + * + * AC_VO -> queue 3 + * AC_VI -> queue 2 + * AC_BE -> queue 1 + * AC_BK -> queue 0 + */ +static const u16 iwm_1d_to_queue[8] = { 1, 0, 0, 1, 2, 2, 3, 3 }; + +static u16 iwm_select_queue(struct net_device *dev, struct sk_buff *skb) +{ + skb->priority = cfg80211_classify8021d(skb); + + return iwm_1d_to_queue[skb->priority]; +} + +static const struct net_device_ops iwm_netdev_ops = { + .ndo_open = iwm_open, + .ndo_stop = iwm_stop, + .ndo_start_xmit = iwm_xmit_frame, + .ndo_select_queue = iwm_select_queue, +}; + +void *iwm_if_alloc(int sizeof_bus, struct device *dev, + struct iwm_if_ops *if_ops) +{ + struct net_device *ndev; + struct wireless_dev *wdev; + struct iwm_priv *iwm; + int ret = 0; + + wdev = iwm_wdev_alloc(sizeof_bus, dev); + if (!wdev) { + dev_err(dev, "no memory for wireless device instance\n"); + return ERR_PTR(-ENOMEM); + } + + iwm = wdev_to_iwm(wdev); + iwm->bus_ops = if_ops; + iwm->wdev = wdev; + + ret = iwm_priv_init(iwm); + if (ret) { + dev_err(dev, "failed to init iwm_priv\n"); + goto out_wdev; + } + + wdev->iftype = iwm_mode_to_nl80211_iftype(iwm->conf.mode); + + ndev = alloc_netdev_mq(0, "wlan%d", ether_setup, IWM_TX_QUEUES); + if (!ndev) { + dev_err(dev, "no memory for network device instance\n"); + goto out_priv; + } + + ndev->netdev_ops = &iwm_netdev_ops; + ndev->wireless_handlers = &iwm_iw_handler_def; + ndev->ieee80211_ptr = wdev; + SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); + wdev->netdev = ndev; + + return iwm; + + out_priv: + iwm_priv_deinit(iwm); + + out_wdev: + iwm_wdev_free(iwm); + return ERR_PTR(ret); +} + +void iwm_if_free(struct iwm_priv *iwm) +{ + if (!iwm_to_ndev(iwm)) + return; + + free_netdev(iwm_to_ndev(iwm)); + iwm_wdev_free(iwm); + iwm_priv_deinit(iwm); +} + +int iwm_if_add(struct iwm_priv *iwm) +{ + struct net_device *ndev = iwm_to_ndev(iwm); + int ret; + + ret = register_netdev(ndev); + if (ret < 0) { + dev_err(&ndev->dev, "Failed to register netdev: %d\n", ret); + return ret; + } + + return 0; +} + +void iwm_if_remove(struct iwm_priv *iwm) +{ + unregister_netdev(iwm_to_ndev(iwm)); +} diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c new file mode 100644 index 000000000000..d73cf96c6dc6 --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/rx.c @@ -0,0 +1,1431 @@ +/* + * Intel Wireless Multicomm 3200 WiFi driver + * + * Copyright (C) 2009 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * Intel Corporation + * Samuel Ortiz + * Zhu Yi + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "iwm.h" +#include "debug.h" +#include "hal.h" +#include "umac.h" +#include "lmac.h" +#include "commands.h" +#include "rx.h" +#include "cfg80211.h" +#include "eeprom.h" + +static int iwm_rx_check_udma_hdr(struct iwm_udma_in_hdr *hdr) +{ + if ((le32_to_cpu(hdr->cmd) == UMAC_PAD_TERMINAL) || + (le32_to_cpu(hdr->size) == UMAC_PAD_TERMINAL)) + return -EINVAL; + + return 0; +} + +static inline int iwm_rx_resp_size(struct iwm_udma_in_hdr *hdr) +{ + return ALIGN(le32_to_cpu(hdr->size) + sizeof(struct iwm_udma_in_hdr), + 16); +} + +/* + * Notification handlers: + * + * For every possible notification we can receive from the + * target, we have a handler. + * When we get a target notification, and there is no one + * waiting for it, it's just processed through the rx code + * path: + * + * iwm_rx_handle() + * -> iwm_rx_handle_umac() + * -> iwm_rx_handle_wifi() + * -> iwm_rx_handle_resp() + * -> iwm_ntf_*() + * + * OR + * + * -> iwm_rx_handle_non_wifi() + * + * If there are processes waiting for this notification, then + * iwm_rx_handle_wifi() just wakes those processes up and they + * grab the pending notification. + */ +static int iwm_ntf_error(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, struct iwm_wifi_cmd *cmd) +{ + struct iwm_umac_notif_error *error; + struct iwm_fw_error_hdr *fw_err; + + error = (struct iwm_umac_notif_error *)buf; + fw_err = &error->err; + + + IWM_ERR(iwm, "%cMAC FW ERROR:\n", + (le32_to_cpu(fw_err->category) == UMAC_SYS_ERR_CAT_LMAC) ? 'L' : 'U'); + IWM_ERR(iwm, "\tCategory: %d\n", le32_to_cpu(fw_err->category)); + IWM_ERR(iwm, "\tStatus: 0x%x\n", le32_to_cpu(fw_err->status)); + IWM_ERR(iwm, "\tPC: 0x%x\n", le32_to_cpu(fw_err->pc)); + IWM_ERR(iwm, "\tblink1: %d\n", le32_to_cpu(fw_err->blink1)); + IWM_ERR(iwm, "\tblink2: %d\n", le32_to_cpu(fw_err->blink2)); + IWM_ERR(iwm, "\tilink1: %d\n", le32_to_cpu(fw_err->ilink1)); + IWM_ERR(iwm, "\tilink2: %d\n", le32_to_cpu(fw_err->ilink2)); + IWM_ERR(iwm, "\tData1: 0x%x\n", le32_to_cpu(fw_err->data1)); + IWM_ERR(iwm, "\tData2: 0x%x\n", le32_to_cpu(fw_err->data2)); + IWM_ERR(iwm, "\tLine number: %d\n", le32_to_cpu(fw_err->line_num)); + IWM_ERR(iwm, "\tUMAC status: 0x%x\n", le32_to_cpu(fw_err->umac_status)); + IWM_ERR(iwm, "\tLMAC status: 0x%x\n", le32_to_cpu(fw_err->lmac_status)); + IWM_ERR(iwm, "\tSDIO status: 0x%x\n", le32_to_cpu(fw_err->sdio_status)); + + return 0; +} + +static int iwm_ntf_umac_alive(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, struct iwm_wifi_cmd *cmd) +{ + struct iwm_umac_notif_alive *alive_resp = + (struct iwm_umac_notif_alive *)(buf); + u16 status = le16_to_cpu(alive_resp->status); + + if (status == UMAC_NTFY_ALIVE_STATUS_ERR) { + IWM_ERR(iwm, "Receive error UMAC_ALIVE\n"); + return -EIO; + } + + iwm_tx_credit_init_pools(iwm, alive_resp); + + return 0; +} + +static int iwm_ntf_init_complete(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, + struct iwm_wifi_cmd *cmd) +{ + struct iwm_umac_notif_init_complete *init_complete = + (struct iwm_umac_notif_init_complete *)(buf); + u16 status = le16_to_cpu(init_complete->status); + + if (status == UMAC_NTFY_INIT_COMPLETE_STATUS_ERR) { + IWM_DBG_NTF(iwm, DBG, "Hardware rf kill is on (radio off)\n"); + set_bit(IWM_RADIO_RFKILL_HW, &iwm->radio); + } else { + IWM_DBG_NTF(iwm, DBG, "Hardware rf kill is off (radio on)\n"); + clear_bit(IWM_RADIO_RFKILL_HW, &iwm->radio); + } + + return 0; +} + +static int iwm_ntf_tx_credit_update(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, + struct iwm_wifi_cmd *cmd) +{ + int pool_nr, total_freed_pages; + unsigned long pool_map; + int i, id; + struct iwm_umac_notif_page_dealloc *dealloc = + (struct iwm_umac_notif_page_dealloc *)buf; + + pool_nr = GET_VAL32(dealloc->changes, UMAC_DEALLOC_NTFY_CHANGES_CNT); + pool_map = GET_VAL32(dealloc->changes, UMAC_DEALLOC_NTFY_CHANGES_MSK); + + IWM_DBG_TX(iwm, DBG, "UMAC dealloc notification: pool nr %d, " + "update map 0x%lx\n", pool_nr, pool_map); + + spin_lock(&iwm->tx_credit.lock); + + for (i = 0; i < pool_nr; i++) { + id = GET_VAL32(dealloc->grp_info[i], + UMAC_DEALLOC_NTFY_GROUP_NUM); + if (test_bit(id, &pool_map)) { + total_freed_pages = GET_VAL32(dealloc->grp_info[i], + UMAC_DEALLOC_NTFY_PAGE_CNT); + iwm_tx_credit_inc(iwm, id, total_freed_pages); + } + } + + spin_unlock(&iwm->tx_credit.lock); + + return 0; +} + +static int iwm_ntf_umac_reset(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, struct iwm_wifi_cmd *cmd) +{ + IWM_DBG_NTF(iwm, DBG, "UMAC RESET done\n"); + + return 0; +} + +static int iwm_ntf_lmac_version(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, + struct iwm_wifi_cmd *cmd) +{ + IWM_DBG_NTF(iwm, INFO, "LMAC Version: %x.%x\n", buf[9], buf[8]); + + return 0; +} + +static int iwm_ntf_tx(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, struct iwm_wifi_cmd *cmd) +{ + struct iwm_lmac_tx_resp *tx_resp; + struct iwm_umac_wifi_in_hdr *hdr; + + tx_resp = (struct iwm_lmac_tx_resp *) + (buf + sizeof(struct iwm_umac_wifi_in_hdr)); + hdr = (struct iwm_umac_wifi_in_hdr *)buf; + + IWM_DBG_NTF(iwm, DBG, "REPLY_TX, buf size: %lu\n", buf_size); + + IWM_DBG_NTF(iwm, DBG, "Seqnum: %d\n", + le16_to_cpu(hdr->sw_hdr.cmd.seq_num)); + IWM_DBG_NTF(iwm, DBG, "\tFrame cnt: %d\n", tx_resp->frame_cnt); + IWM_DBG_NTF(iwm, DBG, "\tRetry cnt: %d\n", + le16_to_cpu(tx_resp->retry_cnt)); + IWM_DBG_NTF(iwm, DBG, "\tSeq ctl: %d\n", le16_to_cpu(tx_resp->seq_ctl)); + IWM_DBG_NTF(iwm, DBG, "\tByte cnt: %d\n", + le16_to_cpu(tx_resp->byte_cnt)); + IWM_DBG_NTF(iwm, DBG, "\tStatus: 0x%x\n", le32_to_cpu(tx_resp->status)); + + return 0; +} + + +static int iwm_ntf_calib_res(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, struct iwm_wifi_cmd *cmd) +{ + u8 opcode; + u8 *calib_buf; + struct iwm_lmac_calib_hdr *hdr = (struct iwm_lmac_calib_hdr *) + (buf + sizeof(struct iwm_umac_wifi_in_hdr)); + + opcode = hdr->opcode; + + BUG_ON(opcode >= CALIBRATION_CMD_NUM || + opcode < PHY_CALIBRATE_OPCODES_NUM); + + IWM_DBG_NTF(iwm, DBG, "Store calibration result for opcode: %d\n", + opcode); + + buf_size -= sizeof(struct iwm_umac_wifi_in_hdr); + calib_buf = iwm->calib_res[opcode].buf; + + if (!calib_buf || (iwm->calib_res[opcode].size < buf_size)) { + kfree(calib_buf); + calib_buf = kzalloc(buf_size, GFP_KERNEL); + if (!calib_buf) { + IWM_ERR(iwm, "Memory allocation failed: calib_res\n"); + return -ENOMEM; + } + iwm->calib_res[opcode].buf = calib_buf; + iwm->calib_res[opcode].size = buf_size; + } + + memcpy(calib_buf, hdr, buf_size); + set_bit(opcode - PHY_CALIBRATE_OPCODES_NUM, &iwm->calib_done_map); + + return 0; +} + +static int iwm_ntf_calib_complete(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, + struct iwm_wifi_cmd *cmd) +{ + IWM_DBG_NTF(iwm, DBG, "Calibration completed\n"); + + return 0; +} + +static int iwm_ntf_calib_cfg(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, struct iwm_wifi_cmd *cmd) +{ + struct iwm_lmac_cal_cfg_resp *cal_resp; + + cal_resp = (struct iwm_lmac_cal_cfg_resp *) + (buf + sizeof(struct iwm_umac_wifi_in_hdr)); + + IWM_DBG_NTF(iwm, DBG, "Calibration CFG command status: %d\n", + le32_to_cpu(cal_resp->status)); + + return 0; +} + +static int iwm_ntf_wifi_status(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, struct iwm_wifi_cmd *cmd) +{ + struct iwm_umac_notif_wifi_status *status = + (struct iwm_umac_notif_wifi_status *)buf; + + iwm->core_enabled |= le16_to_cpu(status->status); + + return 0; +} + +static struct iwm_rx_ticket_node * +iwm_rx_ticket_node_alloc(struct iwm_priv *iwm, struct iwm_rx_ticket *ticket) +{ + struct iwm_rx_ticket_node *ticket_node; + + ticket_node = kzalloc(sizeof(struct iwm_rx_ticket_node), GFP_KERNEL); + if (!ticket_node) { + IWM_ERR(iwm, "Couldn't allocate ticket node\n"); + return ERR_PTR(-ENOMEM); + } + + ticket_node->ticket = kzalloc(sizeof(struct iwm_rx_ticket), GFP_KERNEL); + if (!ticket_node->ticket) { + IWM_ERR(iwm, "Couldn't allocate RX ticket\n"); + kfree(ticket_node); + return ERR_PTR(-ENOMEM); + } + + memcpy(ticket_node->ticket, ticket, sizeof(struct iwm_rx_ticket)); + INIT_LIST_HEAD(&ticket_node->node); + + return ticket_node; +} + +static void iwm_rx_ticket_node_free(struct iwm_rx_ticket_node *ticket_node) +{ + kfree(ticket_node->ticket); + kfree(ticket_node); +} + +static struct iwm_rx_packet *iwm_rx_packet_get(struct iwm_priv *iwm, u16 id) +{ + u8 id_hash = IWM_RX_ID_GET_HASH(id); + struct list_head *packet_list; + struct iwm_rx_packet *packet, *next; + + packet_list = &iwm->rx_packets[id_hash]; + + list_for_each_entry_safe(packet, next, packet_list, node) + if (packet->id == id) + return packet; + + return NULL; +} + +static struct iwm_rx_packet *iwm_rx_packet_alloc(struct iwm_priv *iwm, u8 *buf, + u32 size, u16 id) +{ + struct iwm_rx_packet *packet; + + packet = kzalloc(sizeof(struct iwm_rx_packet), GFP_KERNEL); + if (!packet) { + IWM_ERR(iwm, "Couldn't allocate packet\n"); + return ERR_PTR(-ENOMEM); + } + + packet->skb = dev_alloc_skb(size); + if (!packet->skb) { + IWM_ERR(iwm, "Couldn't allocate packet SKB\n"); + kfree(packet); + return ERR_PTR(-ENOMEM); + } + + packet->pkt_size = size; + + skb_put(packet->skb, size); + memcpy(packet->skb->data, buf, size); + INIT_LIST_HEAD(&packet->node); + packet->id = id; + + return packet; +} + +void iwm_rx_free(struct iwm_priv *iwm) +{ + struct iwm_rx_ticket_node *ticket, *nt; + struct iwm_rx_packet *packet, *np; + int i; + + list_for_each_entry_safe(ticket, nt, &iwm->rx_tickets, node) { + list_del(&ticket->node); + iwm_rx_ticket_node_free(ticket); + } + + for (i = 0; i < IWM_RX_ID_HASH; i++) { + list_for_each_entry_safe(packet, np, &iwm->rx_packets[i], + node) { + list_del(&packet->node); + kfree_skb(packet->skb); + kfree(packet); + } + } +} + +static int iwm_ntf_rx_ticket(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, struct iwm_wifi_cmd *cmd) +{ + struct iwm_umac_notif_rx_ticket *ntf_rx_ticket = + (struct iwm_umac_notif_rx_ticket *)buf; + struct iwm_rx_ticket *ticket = + (struct iwm_rx_ticket *)ntf_rx_ticket->tickets; + int i, schedule_rx = 0; + + for (i = 0; i < ntf_rx_ticket->num_tickets; i++) { + struct iwm_rx_ticket_node *ticket_node; + + switch (le16_to_cpu(ticket->action)) { + case IWM_RX_TICKET_RELEASE: + case IWM_RX_TICKET_DROP: + /* We can push the packet to the stack */ + ticket_node = iwm_rx_ticket_node_alloc(iwm, ticket); + if (IS_ERR(ticket_node)) + return PTR_ERR(ticket_node); + + IWM_DBG_NTF(iwm, DBG, "TICKET RELEASE(%d)\n", + ticket->id); + list_add_tail(&ticket_node->node, &iwm->rx_tickets); + + /* + * We received an Rx ticket, most likely there's + * a packet pending for it, it's not worth going + * through the packet hash list to double check. + * Let's just fire the rx worker.. + */ + schedule_rx = 1; + + break; + + default: + IWM_ERR(iwm, "Invalid RX ticket action: 0x%x\n", + ticket->action); + } + + ticket++; + } + + if (schedule_rx) + queue_work(iwm->rx_wq, &iwm->rx_worker); + + return 0; +} + +static int iwm_ntf_rx_packet(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, struct iwm_wifi_cmd *cmd) +{ + struct iwm_umac_wifi_in_hdr *wifi_hdr; + struct iwm_rx_packet *packet; + u16 id, buf_offset; + u32 packet_size; + + IWM_DBG_NTF(iwm, DBG, "\n"); + + wifi_hdr = (struct iwm_umac_wifi_in_hdr *)buf; + id = le16_to_cpu(wifi_hdr->sw_hdr.cmd.seq_num); + buf_offset = sizeof(struct iwm_umac_wifi_in_hdr); + packet_size = buf_size - sizeof(struct iwm_umac_wifi_in_hdr); + + IWM_DBG_NTF(iwm, DBG, "CMD:0x%x, seqnum: %d, packet size: %d\n", + wifi_hdr->sw_hdr.cmd.cmd, id, packet_size); + IWM_DBG_RX(iwm, DBG, "Packet id: %d\n", id); + IWM_HEXDUMP(iwm, DBG, RX, "PACKET: ", buf + buf_offset, packet_size); + + packet = iwm_rx_packet_alloc(iwm, buf + buf_offset, packet_size, id); + if (IS_ERR(packet)) + return PTR_ERR(packet); + + list_add_tail(&packet->node, &iwm->rx_packets[IWM_RX_ID_GET_HASH(id)]); + + /* We might (unlikely) have received the packet _after_ the ticket */ + queue_work(iwm->rx_wq, &iwm->rx_worker); + + return 0; +} + +/* MLME handlers */ +static int iwm_mlme_assoc_start(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, + struct iwm_wifi_cmd *cmd) +{ + struct iwm_umac_notif_assoc_start *start; + + start = (struct iwm_umac_notif_assoc_start *)buf; + + set_bit(IWM_STATUS_ASSOCIATING, &iwm->status); + + IWM_DBG_MLME(iwm, INFO, "Association with %pM Started, reason: %d\n", + start->bssid, le32_to_cpu(start->roam_reason)); + + wake_up_interruptible(&iwm->mlme_queue); + + return 0; +} + +static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, + struct iwm_wifi_cmd *cmd) +{ + struct iwm_umac_notif_assoc_complete *complete = + (struct iwm_umac_notif_assoc_complete *)buf; + union iwreq_data wrqu; + + IWM_DBG_MLME(iwm, INFO, "Association with %pM completed, status: %d\n", + complete->bssid, complete->status); + + memset(&wrqu, 0, sizeof(wrqu)); + + clear_bit(IWM_STATUS_ASSOCIATING, &iwm->status); + + switch (le32_to_cpu(complete->status)) { + case UMAC_ASSOC_COMPLETE_SUCCESS: + set_bit(IWM_STATUS_ASSOCIATED, &iwm->status); + memcpy(iwm->bssid, complete->bssid, ETH_ALEN); + iwm->channel = complete->channel; + + iwm_link_on(iwm); + + memcpy(wrqu.ap_addr.sa_data, complete->bssid, ETH_ALEN); + break; + case UMAC_ASSOC_COMPLETE_FAILURE: + clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status); + memset(iwm->bssid, 0, ETH_ALEN); + iwm->channel = 0; + + iwm_link_off(iwm); + default: + break; + } + + if (iwm->conf.mode == UMAC_MODE_IBSS) { + cfg80211_ibss_joined(iwm_to_ndev(iwm), iwm->bssid, GFP_KERNEL); + return 0; + } + + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + wireless_send_event(iwm_to_ndev(iwm), SIOCGIWAP, &wrqu, NULL); + + return 0; +} + +static int iwm_mlme_profile_invalidate(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, + struct iwm_wifi_cmd *cmd) +{ + struct iwm_umac_notif_profile_invalidate *invalid; + + invalid = (struct iwm_umac_notif_profile_invalidate *)buf; + + IWM_DBG_MLME(iwm, INFO, "Profile Invalidated. Reason: %d\n", + le32_to_cpu(invalid->reason)); + + clear_bit(IWM_STATUS_ASSOCIATING, &iwm->status); + clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status); + + iwm->umac_profile_active = 0; + memset(iwm->bssid, 0, ETH_ALEN); + iwm->channel = 0; + + iwm_link_off(iwm); + + wake_up_interruptible(&iwm->mlme_queue); + + return 0; +} + +static int iwm_mlme_scan_complete(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, + struct iwm_wifi_cmd *cmd) +{ + int ret; + struct iwm_umac_notif_scan_complete *scan_complete = + (struct iwm_umac_notif_scan_complete *)buf; + u32 result = le32_to_cpu(scan_complete->result); + + IWM_DBG_MLME(iwm, INFO, "type:0x%x result:0x%x seq:%d\n", + le32_to_cpu(scan_complete->type), + le32_to_cpu(scan_complete->result), + scan_complete->seq_num); + + if (!test_and_clear_bit(IWM_STATUS_SCANNING, &iwm->status)) { + IWM_ERR(iwm, "Scan complete while device not scanning\n"); + return -EIO; + } + if (!iwm->scan_request) + return 0; + + ret = iwm_cfg80211_inform_bss(iwm); + + cfg80211_scan_done(iwm->scan_request, + (result & UMAC_SCAN_RESULT_ABORTED) ? 1 : !!ret); + iwm->scan_request = NULL; + + return ret; +} + +static int iwm_mlme_update_sta_table(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, + struct iwm_wifi_cmd *cmd) +{ + struct iwm_umac_notif_sta_info *umac_sta = + (struct iwm_umac_notif_sta_info *)buf; + struct iwm_sta_info *sta; + int i; + + switch (le32_to_cpu(umac_sta->opcode)) { + case UMAC_OPCODE_ADD_MODIFY: + sta = &iwm->sta_table[GET_VAL8(umac_sta->sta_id, LMAC_STA_ID)]; + + IWM_DBG_MLME(iwm, INFO, "%s STA: ID = %d, Color = %d, " + "addr = %pM, qos = %d\n", + sta->valid ? "Modify" : "Add", + GET_VAL8(umac_sta->sta_id, LMAC_STA_ID), + GET_VAL8(umac_sta->sta_id, LMAC_STA_COLOR), + umac_sta->mac_addr, + umac_sta->flags & UMAC_STA_FLAG_QOS); + + sta->valid = 1; + sta->qos = umac_sta->flags & UMAC_STA_FLAG_QOS; + sta->color = GET_VAL8(umac_sta->sta_id, LMAC_STA_COLOR); + memcpy(sta->addr, umac_sta->mac_addr, ETH_ALEN); + break; + case UMAC_OPCODE_REMOVE: + IWM_DBG_MLME(iwm, INFO, "Remove STA: ID = %d, Color = %d, " + "addr = %pM\n", + GET_VAL8(umac_sta->sta_id, LMAC_STA_ID), + GET_VAL8(umac_sta->sta_id, LMAC_STA_COLOR), + umac_sta->mac_addr); + + sta = &iwm->sta_table[GET_VAL8(umac_sta->sta_id, LMAC_STA_ID)]; + + if (!memcmp(sta->addr, umac_sta->mac_addr, ETH_ALEN)) + sta->valid = 0; + + break; + case UMAC_OPCODE_CLEAR_ALL: + for (i = 0; i < IWM_STA_TABLE_NUM; i++) + iwm->sta_table[i].valid = 0; + + break; + default: + break; + } + + return 0; +} + +static int iwm_mlme_update_bss_table(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, + struct iwm_wifi_cmd *cmd) +{ + struct wiphy *wiphy = iwm_to_wiphy(iwm); + struct ieee80211_mgmt *mgmt; + struct iwm_umac_notif_bss_info *umac_bss = + (struct iwm_umac_notif_bss_info *)buf; + struct ieee80211_channel *channel; + struct ieee80211_supported_band *band; + struct iwm_bss_info *bss, *next; + s32 signal; + int freq; + u16 frame_len = le16_to_cpu(umac_bss->frame_len); + size_t bss_len = sizeof(struct iwm_umac_notif_bss_info) + frame_len; + + mgmt = (struct ieee80211_mgmt *)(umac_bss->frame_buf); + + IWM_DBG_MLME(iwm, DBG, "New BSS info entry: %pM\n", mgmt->bssid); + IWM_DBG_MLME(iwm, DBG, "\tType: 0x%x\n", le32_to_cpu(umac_bss->type)); + IWM_DBG_MLME(iwm, DBG, "\tTimestamp: %d\n", + le32_to_cpu(umac_bss->timestamp)); + IWM_DBG_MLME(iwm, DBG, "\tTable Index: %d\n", + le16_to_cpu(umac_bss->table_idx)); + IWM_DBG_MLME(iwm, DBG, "\tBand: %d\n", umac_bss->band); + IWM_DBG_MLME(iwm, DBG, "\tChannel: %d\n", umac_bss->channel); + IWM_DBG_MLME(iwm, DBG, "\tRSSI: %d\n", umac_bss->rssi); + IWM_DBG_MLME(iwm, DBG, "\tFrame Length: %d\n", frame_len); + + list_for_each_entry_safe(bss, next, &iwm->bss_list, node) + if (bss->bss->table_idx == umac_bss->table_idx) + break; + + if (&bss->node != &iwm->bss_list) { + /* Remove the old BSS entry, we will add it back later. */ + list_del(&bss->node); + kfree(bss->bss); + } else { + /* New BSS entry */ + + bss = kzalloc(sizeof(struct iwm_bss_info), GFP_KERNEL); + if (!bss) { + IWM_ERR(iwm, "Couldn't allocate bss_info\n"); + return -ENOMEM; + } + } + + bss->bss = kzalloc(bss_len, GFP_KERNEL); + if (!bss) { + kfree(bss); + IWM_ERR(iwm, "Couldn't allocate bss\n"); + return -ENOMEM; + } + + INIT_LIST_HEAD(&bss->node); + memcpy(bss->bss, umac_bss, bss_len); + + if (umac_bss->band == UMAC_BAND_2GHZ) + band = wiphy->bands[IEEE80211_BAND_2GHZ]; + else if (umac_bss->band == UMAC_BAND_5GHZ) + band = wiphy->bands[IEEE80211_BAND_5GHZ]; + else { + IWM_ERR(iwm, "Invalid band: %d\n", umac_bss->band); + goto err; + } + + freq = ieee80211_channel_to_frequency(umac_bss->channel); + channel = ieee80211_get_channel(wiphy, freq); + signal = umac_bss->rssi * 100; + + bss->cfg_bss = cfg80211_inform_bss_frame(wiphy, channel, + mgmt, frame_len, + signal, GFP_KERNEL); + if (!bss->cfg_bss) + goto err; + + list_add_tail(&bss->node, &iwm->bss_list); + + return 0; + err: + kfree(bss->bss); + kfree(bss); + + return -EINVAL; +} + +static int iwm_mlme_remove_bss(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, struct iwm_wifi_cmd *cmd) +{ + struct iwm_umac_notif_bss_removed *bss_rm = + (struct iwm_umac_notif_bss_removed *)buf; + struct iwm_bss_info *bss, *next; + u16 table_idx; + int i; + + for (i = 0; i < le32_to_cpu(bss_rm->count); i++) { + table_idx = (le16_to_cpu(bss_rm->entries[i]) + & IWM_BSS_REMOVE_INDEX_MSK); + list_for_each_entry_safe(bss, next, &iwm->bss_list, node) + if (bss->bss->table_idx == cpu_to_le16(table_idx)) { + struct ieee80211_mgmt *mgmt; + + mgmt = (struct ieee80211_mgmt *) + (bss->bss->frame_buf); + IWM_DBG_MLME(iwm, ERR, + "BSS removed: %pM\n", + mgmt->bssid); + list_del(&bss->node); + kfree(bss->bss); + kfree(bss); + } + } + + return 0; +} + +static int iwm_mlme_mgt_frame(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, struct iwm_wifi_cmd *cmd) +{ + struct iwm_umac_notif_mgt_frame *mgt_frame = + (struct iwm_umac_notif_mgt_frame *)buf; + struct ieee80211_mgmt *mgt = (struct ieee80211_mgmt *)mgt_frame->frame; + u8 *ie; + unsigned int event; + union iwreq_data wrqu; + + IWM_HEXDUMP(iwm, DBG, MLME, "MGT: ", mgt_frame->frame, + le16_to_cpu(mgt_frame->len)); + + if (ieee80211_is_assoc_req(mgt->frame_control)) { + ie = mgt->u.assoc_req.variable;; + event = IWEVASSOCREQIE; + } else if (ieee80211_is_reassoc_req(mgt->frame_control)) { + ie = mgt->u.reassoc_req.variable;; + event = IWEVASSOCREQIE; + } else if (ieee80211_is_assoc_resp(mgt->frame_control)) { + ie = mgt->u.assoc_resp.variable;; + event = IWEVASSOCRESPIE; + } else if (ieee80211_is_reassoc_resp(mgt->frame_control)) { + ie = mgt->u.reassoc_resp.variable;; + event = IWEVASSOCRESPIE; + } else { + IWM_ERR(iwm, "Unsupported management frame"); + return 0; + } + + wrqu.data.length = le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt); + + IWM_HEXDUMP(iwm, DBG, MLME, "EVT: ", ie, wrqu.data.length); + wireless_send_event(iwm_to_ndev(iwm), event, &wrqu, ie); + + return 0; +} + +static int iwm_ntf_mlme(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, struct iwm_wifi_cmd *cmd) +{ + struct iwm_umac_notif_wifi_if *notif = + (struct iwm_umac_notif_wifi_if *)buf; + + switch (notif->status) { + case WIFI_IF_NTFY_ASSOC_START: + return iwm_mlme_assoc_start(iwm, buf, buf_size, cmd); + case WIFI_IF_NTFY_ASSOC_COMPLETE: + return iwm_mlme_assoc_complete(iwm, buf, buf_size, cmd); + case WIFI_IF_NTFY_PROFILE_INVALIDATE_COMPLETE: + return iwm_mlme_profile_invalidate(iwm, buf, buf_size, cmd); + case WIFI_IF_NTFY_CONNECTION_TERMINATED: + IWM_DBG_MLME(iwm, DBG, "Connection terminated\n"); + break; + case WIFI_IF_NTFY_SCAN_COMPLETE: + return iwm_mlme_scan_complete(iwm, buf, buf_size, cmd); + case WIFI_IF_NTFY_STA_TABLE_CHANGE: + return iwm_mlme_update_sta_table(iwm, buf, buf_size, cmd); + case WIFI_IF_NTFY_EXTENDED_IE_REQUIRED: + IWM_DBG_MLME(iwm, DBG, "Extended IE required\n"); + break; + case WIFI_IF_NTFY_BSS_TRK_TABLE_CHANGED: + return iwm_mlme_update_bss_table(iwm, buf, buf_size, cmd); + case WIFI_IF_NTFY_BSS_TRK_ENTRIES_REMOVED: + return iwm_mlme_remove_bss(iwm, buf, buf_size, cmd); + break; + case WIFI_IF_NTFY_MGMT_FRAME: + return iwm_mlme_mgt_frame(iwm, buf, buf_size, cmd); + case WIFI_DBG_IF_NTFY_SCAN_SUPER_JOB_START: + case WIFI_DBG_IF_NTFY_SCAN_SUPER_JOB_COMPLETE: + case WIFI_DBG_IF_NTFY_SCAN_CHANNEL_START: + case WIFI_DBG_IF_NTFY_SCAN_CHANNEL_RESULT: + case WIFI_DBG_IF_NTFY_SCAN_MINI_JOB_START: + case WIFI_DBG_IF_NTFY_SCAN_MINI_JOB_COMPLETE: + case WIFI_DBG_IF_NTFY_CNCT_ATC_START: + case WIFI_DBG_IF_NTFY_COEX_NOTIFICATION: + case WIFI_DBG_IF_NTFY_COEX_HANDLE_ENVELOP: + case WIFI_DBG_IF_NTFY_COEX_HANDLE_RELEASE_ENVELOP: + IWM_DBG_MLME(iwm, DBG, "MLME debug notification: 0x%x\n", + notif->status); + break; + default: + IWM_ERR(iwm, "Unhandled notification: 0x%x\n", notif->status); + break; + } + + return 0; +} + +#define IWM_STATS_UPDATE_INTERVAL (2 * HZ) + +static int iwm_ntf_statistics(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, struct iwm_wifi_cmd *cmd) +{ + struct iwm_umac_notif_stats *stats = (struct iwm_umac_notif_stats *)buf; + struct iw_statistics *wstats = &iwm->wstats; + u16 max_rate = 0; + int i; + + IWM_DBG_MLME(iwm, DBG, "Statistics notification received\n"); + + if (test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) { + for (i = 0; i < UMAC_NTF_RATE_SAMPLE_NR; i++) { + max_rate = max_t(u16, max_rate, + max(le16_to_cpu(stats->tx_rate[i]), + le16_to_cpu(stats->rx_rate[i]))); + } + /* UMAC passes rate info multiplies by 2 */ + iwm->rate = max_rate >> 1; + } + + wstats->status = 0; + + wstats->discard.nwid = le32_to_cpu(stats->rx_drop_other_bssid); + wstats->discard.code = le32_to_cpu(stats->rx_drop_decode); + wstats->discard.fragment = le32_to_cpu(stats->rx_drop_reassembly); + wstats->discard.retries = le32_to_cpu(stats->tx_drop_max_retry); + + wstats->miss.beacon = le32_to_cpu(stats->missed_beacons); + + /* according to cfg80211 */ + if (stats->rssi_dbm < -110) + wstats->qual.qual = 0; + else if (stats->rssi_dbm > -40) + wstats->qual.qual = 70; + else + wstats->qual.qual = stats->rssi_dbm + 110; + + wstats->qual.level = stats->rssi_dbm; + wstats->qual.noise = stats->noise_dbm; + wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; + + schedule_delayed_work(&iwm->stats_request, IWM_STATS_UPDATE_INTERVAL); + + mod_timer(&iwm->watchdog, round_jiffies(jiffies + IWM_WATCHDOG_PERIOD)); + + return 0; +} + +static int iwm_ntf_eeprom_proxy(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, + struct iwm_wifi_cmd *cmd) +{ + struct iwm_umac_cmd_eeprom_proxy *eeprom_proxy = + (struct iwm_umac_cmd_eeprom_proxy *) + (buf + sizeof(struct iwm_umac_wifi_in_hdr)); + struct iwm_umac_cmd_eeprom_proxy_hdr *hdr = &eeprom_proxy->hdr; + u32 hdr_offset = le32_to_cpu(hdr->offset); + u32 hdr_len = le32_to_cpu(hdr->len); + u32 hdr_type = le32_to_cpu(hdr->type); + + IWM_DBG_NTF(iwm, DBG, "type: 0x%x, len: %d, offset: 0x%x\n", + hdr_type, hdr_len, hdr_offset); + + if ((hdr_offset + hdr_len) > IWM_EEPROM_LEN) + return -EINVAL; + +#ifdef CONFIG_IWM_B0_HW_SUPPORT + if (hdr_offset == IWM_EEPROM_SKU_CAP_OFF) { + if (eeprom_proxy->buf[0] == 0xff) + iwm->conf.hw_b0 = 1; + } +#endif + + switch (hdr_type) { + case IWM_UMAC_CMD_EEPROM_TYPE_READ: + memcpy(iwm->eeprom + hdr_offset, eeprom_proxy->buf, hdr_len); + break; + case IWM_UMAC_CMD_EEPROM_TYPE_WRITE: + default: + return -ENOTSUPP; + } + + return 0; +} + +static int iwm_ntf_channel_info_list(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, + struct iwm_wifi_cmd *cmd) +{ + struct iwm_umac_cmd_get_channel_list *ch_list = + (struct iwm_umac_cmd_get_channel_list *) + (buf + sizeof(struct iwm_umac_wifi_in_hdr)); + struct wiphy *wiphy = iwm_to_wiphy(iwm); + struct ieee80211_supported_band *band; + int i; + + band = wiphy->bands[IEEE80211_BAND_2GHZ]; + + for (i = 0; i < band->n_channels; i++) { + unsigned long ch_mask_0 = + le32_to_cpu(ch_list->ch[0].channels_mask); + unsigned long ch_mask_2 = + le32_to_cpu(ch_list->ch[2].channels_mask); + + if (!test_bit(i, &ch_mask_0)) + band->channels[i].flags |= IEEE80211_CHAN_DISABLED; + + if (!test_bit(i, &ch_mask_2)) + band->channels[i].flags |= IEEE80211_CHAN_NO_IBSS; + } + + band = wiphy->bands[IEEE80211_BAND_5GHZ]; + + for (i = 0; i < min(band->n_channels, 32); i++) { + unsigned long ch_mask_1 = + le32_to_cpu(ch_list->ch[1].channels_mask); + unsigned long ch_mask_3 = + le32_to_cpu(ch_list->ch[3].channels_mask); + + if (!test_bit(i, &ch_mask_1)) + band->channels[i].flags |= IEEE80211_CHAN_DISABLED; + + if (!test_bit(i, &ch_mask_3)) + band->channels[i].flags |= IEEE80211_CHAN_NO_IBSS; + } + + return 0; +} + +static int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, + struct iwm_wifi_cmd *cmd) +{ + struct iwm_umac_wifi_if *hdr = + (struct iwm_umac_wifi_if *)cmd->buf.payload; + + IWM_DBG_NTF(iwm, DBG, "WIFI_IF_WRAPPER cmd is delivered to UMAC: " + "oid is %d\n", hdr->oid); + + switch (hdr->oid) { + case UMAC_WIFI_IF_CMD_SET_PROFILE: + iwm->umac_profile_active = 1; + wake_up_interruptible(&iwm->mlme_queue); + break; + default: + break; + } + + return 0; +} + +static int iwm_ntf_card_state(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, struct iwm_wifi_cmd *cmd) +{ + struct iwm_lmac_card_state *state = (struct iwm_lmac_card_state *) + (buf + sizeof(struct iwm_umac_wifi_in_hdr)); + u32 flags = le32_to_cpu(state->flags); + + IWM_INFO(iwm, "HW RF Kill %s, CT Kill %s\n", + flags & IWM_CARD_STATE_HW_DISABLED ? "ON" : "OFF", + flags & IWM_CARD_STATE_CTKILL_DISABLED ? "ON" : "OFF"); + + if (flags & IWM_CARD_STATE_HW_DISABLED) + set_bit(IWM_RADIO_RFKILL_HW, &iwm->radio); + else + clear_bit(IWM_RADIO_RFKILL_HW, &iwm->radio); + + return 0; +} + +static int iwm_rx_handle_wifi(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size) +{ + struct iwm_umac_wifi_in_hdr *wifi_hdr; + struct iwm_wifi_cmd *cmd; + u8 source, cmd_id; + u16 seq_num; + u32 count; + u8 resp; + + wifi_hdr = (struct iwm_umac_wifi_in_hdr *)buf; + cmd_id = wifi_hdr->sw_hdr.cmd.cmd; + + source = GET_VAL32(wifi_hdr->hw_hdr.cmd, UMAC_HDI_IN_CMD_SOURCE); + if (source >= IWM_SRC_NUM) { + IWM_CRIT(iwm, "invalid source %d\n", source); + return -EINVAL; + } + + count = (GET_VAL32(wifi_hdr->sw_hdr.meta_data, UMAC_FW_CMD_BYTE_COUNT)); + count += sizeof(struct iwm_umac_wifi_in_hdr) - + sizeof(struct iwm_dev_cmd_hdr); + if (count > buf_size) { + IWM_CRIT(iwm, "count %d, buf size:%ld\n", count, buf_size); + return -EINVAL; + } + + resp = GET_VAL32(wifi_hdr->sw_hdr.meta_data, UMAC_FW_CMD_STATUS); + + seq_num = le16_to_cpu(wifi_hdr->sw_hdr.cmd.seq_num); + + IWM_DBG_RX(iwm, DBG, "CMD:0x%x, source: 0x%x, seqnum: %d\n", + cmd_id, source, seq_num); + + /* + * If this is a response to a previously sent command, there must + * be a pending command for this sequence number. + */ + cmd = iwm_get_pending_wifi_cmd(iwm, seq_num); + + /* Notify the caller only for sync commands. */ + switch (source) { + case UMAC_HDI_IN_SOURCE_FHRX: + if (iwm->lmac_handlers[cmd_id] && + test_bit(cmd_id, &iwm->lmac_handler_map[0])) + return iwm_notif_send(iwm, cmd, cmd_id, source, + buf, count); + break; + case UMAC_HDI_IN_SOURCE_FW: + if (iwm->umac_handlers[cmd_id] && + test_bit(cmd_id, &iwm->umac_handler_map[0])) + return iwm_notif_send(iwm, cmd, cmd_id, source, + buf, count); + break; + case UMAC_HDI_IN_SOURCE_UDMA: + break; + } + + return iwm_rx_handle_resp(iwm, buf, count, cmd); +} + +int iwm_rx_handle_resp(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size, + struct iwm_wifi_cmd *cmd) +{ + u8 source, cmd_id; + struct iwm_umac_wifi_in_hdr *wifi_hdr; + int ret = 0; + + wifi_hdr = (struct iwm_umac_wifi_in_hdr *)buf; + cmd_id = wifi_hdr->sw_hdr.cmd.cmd; + + source = GET_VAL32(wifi_hdr->hw_hdr.cmd, UMAC_HDI_IN_CMD_SOURCE); + + IWM_DBG_RX(iwm, DBG, "CMD:0x%x, source: 0x%x\n", cmd_id, source); + + switch (source) { + case UMAC_HDI_IN_SOURCE_FHRX: + if (iwm->lmac_handlers[cmd_id]) + ret = iwm->lmac_handlers[cmd_id] + (iwm, buf, buf_size, cmd); + break; + case UMAC_HDI_IN_SOURCE_FW: + if (iwm->umac_handlers[cmd_id]) + ret = iwm->umac_handlers[cmd_id] + (iwm, buf, buf_size, cmd); + break; + case UMAC_HDI_IN_SOURCE_UDMA: + ret = -EINVAL; + break; + } + + kfree(cmd); + + return ret; +} + +static int iwm_rx_handle_nonwifi(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size) +{ + u8 seq_num; + struct iwm_udma_in_hdr *hdr = (struct iwm_udma_in_hdr *)buf; + struct iwm_nonwifi_cmd *cmd, *next; + + seq_num = GET_VAL32(hdr->cmd, UDMA_HDI_IN_CMD_NON_WIFI_HW_SEQ_NUM); + + /* + * We received a non wifi answer. + * Let's check if there's a pending command for it, and if so + * replace the command payload with the buffer, and then wake the + * callers up. + * That means we only support synchronised non wifi command response + * schemes. + */ + list_for_each_entry_safe(cmd, next, &iwm->nonwifi_pending_cmd, pending) + if (cmd->seq_num == seq_num) { + cmd->resp_received = 1; + cmd->buf.len = buf_size; + memcpy(cmd->buf.hdr, buf, buf_size); + wake_up_interruptible(&iwm->nonwifi_queue); + } + + return 0; +} + +static int iwm_rx_handle_umac(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size) +{ + int ret = 0; + u8 op_code; + unsigned long buf_offset = 0; + struct iwm_udma_in_hdr *hdr; + + /* + * To allow for a more efficient bus usage, UMAC + * messages are encapsulated into UDMA ones. This + * way we can have several UMAC messages in one bus + * transfer. + * A UDMA frame size is always aligned on 16 bytes, + * and a UDMA frame must not start with a UMAC_PAD_TERMINAL + * word. This is how we parse a bus frame into several + * UDMA ones. + */ + while (buf_offset < buf_size) { + + hdr = (struct iwm_udma_in_hdr *)(buf + buf_offset); + + if (iwm_rx_check_udma_hdr(hdr) < 0) { + IWM_DBG_RX(iwm, DBG, "End of frame\n"); + break; + } + + op_code = GET_VAL32(hdr->cmd, UMAC_HDI_IN_CMD_OPCODE); + + IWM_DBG_RX(iwm, DBG, "Op code: 0x%x\n", op_code); + + if (op_code == UMAC_HDI_IN_OPCODE_WIFI) { + ret |= iwm_rx_handle_wifi(iwm, buf + buf_offset, + buf_size - buf_offset); + } else if (op_code < UMAC_HDI_IN_OPCODE_NONWIFI_MAX) { + if (GET_VAL32(hdr->cmd, + UDMA_HDI_IN_CMD_NON_WIFI_HW_SIG) != + UDMA_HDI_IN_CMD_NON_WIFI_HW_SIG) { + IWM_ERR(iwm, "Incorrect hw signature\n"); + return -EINVAL; + } + ret |= iwm_rx_handle_nonwifi(iwm, buf + buf_offset, + buf_size - buf_offset); + } else { + IWM_ERR(iwm, "Invalid RX opcode: 0x%x\n", op_code); + ret |= -EINVAL; + } + + buf_offset += iwm_rx_resp_size(hdr); + } + + return ret; +} + +int iwm_rx_handle(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size) +{ + struct iwm_udma_in_hdr *hdr; + + hdr = (struct iwm_udma_in_hdr *)buf; + + switch (le32_to_cpu(hdr->cmd)) { + case UMAC_REBOOT_BARKER: + return iwm_notif_send(iwm, NULL, IWM_BARKER_REBOOT_NOTIFICATION, + IWM_SRC_UDMA, buf, buf_size); + case UMAC_ACK_BARKER: + return iwm_notif_send(iwm, NULL, IWM_ACK_BARKER_NOTIFICATION, + IWM_SRC_UDMA, NULL, 0); + default: + IWM_DBG_RX(iwm, DBG, "Received cmd: 0x%x\n", hdr->cmd); + return iwm_rx_handle_umac(iwm, buf, buf_size); + } + + return 0; +} + +static const iwm_handler iwm_umac_handlers[] = +{ + [UMAC_NOTIFY_OPCODE_ERROR] = iwm_ntf_error, + [UMAC_NOTIFY_OPCODE_ALIVE] = iwm_ntf_umac_alive, + [UMAC_NOTIFY_OPCODE_INIT_COMPLETE] = iwm_ntf_init_complete, + [UMAC_NOTIFY_OPCODE_WIFI_CORE_STATUS] = iwm_ntf_wifi_status, + [UMAC_NOTIFY_OPCODE_WIFI_IF_WRAPPER] = iwm_ntf_mlme, + [UMAC_NOTIFY_OPCODE_PAGE_DEALLOC] = iwm_ntf_tx_credit_update, + [UMAC_NOTIFY_OPCODE_RX_TICKET] = iwm_ntf_rx_ticket, + [UMAC_CMD_OPCODE_RESET] = iwm_ntf_umac_reset, + [UMAC_NOTIFY_OPCODE_STATS] = iwm_ntf_statistics, + [UMAC_CMD_OPCODE_EEPROM_PROXY] = iwm_ntf_eeprom_proxy, + [UMAC_CMD_OPCODE_GET_CHAN_INFO_LIST] = iwm_ntf_channel_info_list, + [REPLY_RX_MPDU_CMD] = iwm_ntf_rx_packet, + [UMAC_CMD_OPCODE_WIFI_IF_WRAPPER] = iwm_ntf_wifi_if_wrapper, +}; + +static const iwm_handler iwm_lmac_handlers[] = +{ + [REPLY_TX] = iwm_ntf_tx, + [REPLY_ALIVE] = iwm_ntf_lmac_version, + [CALIBRATION_RES_NOTIFICATION] = iwm_ntf_calib_res, + [CALIBRATION_COMPLETE_NOTIFICATION] = iwm_ntf_calib_complete, + [CALIBRATION_CFG_CMD] = iwm_ntf_calib_cfg, + [REPLY_RX_MPDU_CMD] = iwm_ntf_rx_packet, + [CARD_STATE_NOTIFICATION] = iwm_ntf_card_state, +}; + +void iwm_rx_setup_handlers(struct iwm_priv *iwm) +{ + iwm->umac_handlers = (iwm_handler *) iwm_umac_handlers; + iwm->lmac_handlers = (iwm_handler *) iwm_lmac_handlers; +} + +static void iwm_remove_iv(struct sk_buff *skb, u32 hdr_total_len) +{ + struct ieee80211_hdr *hdr; + unsigned int hdr_len; + + hdr = (struct ieee80211_hdr *)skb->data; + + if (!ieee80211_has_protected(hdr->frame_control)) + return; + + hdr_len = ieee80211_hdrlen(hdr->frame_control); + if (hdr_total_len <= hdr_len) + return; + + memmove(skb->data + (hdr_total_len - hdr_len), skb->data, hdr_len); + skb_pull(skb, (hdr_total_len - hdr_len)); +} + +static void iwm_rx_adjust_packet(struct iwm_priv *iwm, + struct iwm_rx_packet *packet, + struct iwm_rx_ticket_node *ticket_node) +{ + u32 payload_offset = 0, payload_len; + struct iwm_rx_ticket *ticket = ticket_node->ticket; + struct iwm_rx_mpdu_hdr *mpdu_hdr; + struct ieee80211_hdr *hdr; + + mpdu_hdr = (struct iwm_rx_mpdu_hdr *)packet->skb->data; + payload_offset += sizeof(struct iwm_rx_mpdu_hdr); + /* Padding is 0 or 2 bytes */ + payload_len = le16_to_cpu(mpdu_hdr->len) + + (le16_to_cpu(ticket->flags) & IWM_RX_TICKET_PAD_SIZE_MSK); + payload_len -= ticket->tail_len; + + IWM_DBG_RX(iwm, DBG, "Packet adjusted, len:%d, offset:%d, " + "ticket offset:%d ticket tail len:%d\n", + payload_len, payload_offset, ticket->payload_offset, + ticket->tail_len); + + IWM_HEXDUMP(iwm, DBG, RX, "RAW: ", packet->skb->data, packet->skb->len); + + skb_pull(packet->skb, payload_offset); + skb_trim(packet->skb, payload_len); + + iwm_remove_iv(packet->skb, ticket->payload_offset); + + hdr = (struct ieee80211_hdr *) packet->skb->data; + if (ieee80211_is_data_qos(hdr->frame_control)) { + /* UMAC handed QOS_DATA frame with 2 padding bytes appended + * to the qos_ctl field in IEEE 802.11 headers. */ + memmove(packet->skb->data + IEEE80211_QOS_CTL_LEN + 2, + packet->skb->data, + ieee80211_hdrlen(hdr->frame_control) - + IEEE80211_QOS_CTL_LEN); + hdr = (struct ieee80211_hdr *) skb_pull(packet->skb, + IEEE80211_QOS_CTL_LEN + 2); + hdr->frame_control &= ~cpu_to_le16(IEEE80211_STYPE_QOS_DATA); + } + + IWM_HEXDUMP(iwm, DBG, RX, "ADJUSTED: ", + packet->skb->data, packet->skb->len); +} + +static void classify8023(struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + + if (ieee80211_is_data_qos(hdr->frame_control)) { + u8 *qc = ieee80211_get_qos_ctl(hdr); + /* frame has qos control */ + skb->priority = *qc & IEEE80211_QOS_CTL_TID_MASK; + } else { + skb->priority = 0; + } +} + +static void iwm_rx_process_packet(struct iwm_priv *iwm, + struct iwm_rx_packet *packet, + struct iwm_rx_ticket_node *ticket_node) +{ + int ret; + struct sk_buff *skb = packet->skb; + struct wireless_dev *wdev = iwm_to_wdev(iwm); + struct net_device *ndev = iwm_to_ndev(iwm); + + IWM_DBG_RX(iwm, DBG, "Processing packet ID %d\n", packet->id); + + switch (le16_to_cpu(ticket_node->ticket->action)) { + case IWM_RX_TICKET_RELEASE: + IWM_DBG_RX(iwm, DBG, "RELEASE packet\n"); + classify8023(skb); + iwm_rx_adjust_packet(iwm, packet, ticket_node); + ret = ieee80211_data_to_8023(skb, ndev->dev_addr, wdev->iftype); + if (ret < 0) { + IWM_DBG_RX(iwm, DBG, "Couldn't convert 802.11 header - " + "%d\n", ret); + break; + } + + IWM_HEXDUMP(iwm, DBG, RX, "802.3: ", skb->data, skb->len); + + skb->dev = iwm_to_ndev(iwm); + skb->protocol = eth_type_trans(skb, ndev); + skb->ip_summed = CHECKSUM_UNNECESSARY; + memset(skb->cb, 0, sizeof(skb->cb)); + + ndev->stats.rx_packets++; + ndev->stats.rx_bytes += skb->len; + + if (netif_rx(skb) == NET_RX_DROP) { + IWM_ERR(iwm, "Packet dropped\n"); + ndev->stats.rx_dropped++; + } + break; + case IWM_RX_TICKET_DROP: + IWM_DBG_RX(iwm, DBG, "DROP packet\n"); + kfree_skb(packet->skb); + break; + default: + IWM_ERR(iwm, "Unknow ticket action: %d\n", + le16_to_cpu(ticket_node->ticket->action)); + kfree_skb(packet->skb); + } + + kfree(packet); + iwm_rx_ticket_node_free(ticket_node); +} + +/* + * Rx data processing: + * + * We're receiving Rx packet from the LMAC, and Rx ticket from + * the UMAC. + * To forward a target data packet upstream (i.e. to the + * kernel network stack), we must have received an Rx ticket + * that tells us we're allowed to release this packet (ticket + * action is IWM_RX_TICKET_RELEASE). The Rx ticket also indicates, + * among other things, where valid data actually starts in the Rx + * packet. + */ +void iwm_rx_worker(struct work_struct *work) +{ + struct iwm_priv *iwm; + struct iwm_rx_ticket_node *ticket, *next; + + iwm = container_of(work, struct iwm_priv, rx_worker); + + /* + * We go through the tickets list and if there is a pending + * packet for it, we push it upstream. + * We stop whenever a ticket is missing its packet, as we're + * supposed to send the packets in order. + */ + list_for_each_entry_safe(ticket, next, &iwm->rx_tickets, node) { + struct iwm_rx_packet *packet = + iwm_rx_packet_get(iwm, le16_to_cpu(ticket->ticket->id)); + + if (!packet) { + IWM_DBG_RX(iwm, DBG, "Skip rx_work: Wait for ticket %d " + "to be handled first\n", + le16_to_cpu(ticket->ticket->id)); + return; + } + + list_del(&ticket->node); + list_del(&packet->node); + iwm_rx_process_packet(iwm, packet, ticket); + } +} + diff --git a/drivers/net/wireless/iwmc3200wifi/rx.h b/drivers/net/wireless/iwmc3200wifi/rx.h new file mode 100644 index 000000000000..da0db91cee59 --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/rx.h @@ -0,0 +1,60 @@ +/* + * Intel Wireless Multicomm 3200 WiFi driver + * + * Copyright (C) 2009 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * Intel Corporation + * Samuel Ortiz + * Zhu Yi + * + */ + +#ifndef __IWM_RX_H__ +#define __IWM_RX_H__ + +#include + +#include "umac.h" + +struct iwm_rx_ticket_node { + struct list_head node; + struct iwm_rx_ticket *ticket; +}; + +struct iwm_rx_packet { + struct list_head node; + u16 id; + struct sk_buff *skb; + unsigned long pkt_size; +}; + +void iwm_rx_worker(struct work_struct *work); + +#endif diff --git a/drivers/net/wireless/iwmc3200wifi/sdio.c b/drivers/net/wireless/iwmc3200wifi/sdio.c new file mode 100644 index 000000000000..916681837fd2 --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/sdio.c @@ -0,0 +1,525 @@ +/* + * Intel Wireless Multicomm 3200 WiFi driver + * + * Copyright (C) 2009 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * Intel Corporation + * Samuel Ortiz + * Zhu Yi + * + */ + +/* + * This is the SDIO bus specific hooks for iwm. + * It also is the module's entry point. + * + * Interesting code paths: + * iwm_sdio_probe() (Called by an SDIO bus scan) + * -> iwm_if_alloc() (netdev.c) + * -> iwm_wdev_alloc() (cfg80211.c, allocates and register our wiphy) + * -> wiphy_new() + * -> wiphy_register() + * -> alloc_netdev_mq() + * -> register_netdev() + * + * iwm_sdio_remove() + * -> iwm_if_free() (netdev.c) + * -> unregister_netdev() + * -> iwm_wdev_free() (cfg80211.c) + * -> wiphy_unregister() + * -> wiphy_free() + * + * iwm_sdio_isr() (called in process context from the SDIO core code) + * -> queue_work(.., isr_worker) + * -- [async] --> iwm_sdio_isr_worker() + * -> iwm_rx_handle() + */ + +#include +#include +#include +#include +#include + +#include "iwm.h" +#include "debug.h" +#include "bus.h" +#include "sdio.h" + +static void iwm_sdio_isr_worker(struct work_struct *work) +{ + struct iwm_sdio_priv *hw; + struct iwm_priv *iwm; + struct iwm_rx_info *rx_info; + struct sk_buff *skb; + u8 *rx_buf; + unsigned long rx_size; + + hw = container_of(work, struct iwm_sdio_priv, isr_worker); + iwm = hw_to_iwm(hw); + + while (!skb_queue_empty(&iwm->rx_list)) { + skb = skb_dequeue(&iwm->rx_list); + rx_info = skb_to_rx_info(skb); + rx_size = rx_info->rx_size; + rx_buf = skb->data; + + IWM_HEXDUMP(iwm, DBG, SDIO, "RX: ", rx_buf, rx_size); + if (iwm_rx_handle(iwm, rx_buf, rx_size) < 0) + IWM_WARN(iwm, "RX error\n"); + + kfree_skb(skb); + } +} + +static void iwm_sdio_isr(struct sdio_func *func) +{ + struct iwm_priv *iwm; + struct iwm_sdio_priv *hw; + struct iwm_rx_info *rx_info; + struct sk_buff *skb; + unsigned long buf_size, read_size; + int ret; + u8 val; + + hw = sdio_get_drvdata(func); + iwm = hw_to_iwm(hw); + + buf_size = hw->blk_size; + + /* We're checking the status */ + val = sdio_readb(func, IWM_SDIO_INTR_STATUS_ADDR, &ret); + if (val == 0 || ret < 0) { + IWM_ERR(iwm, "Wrong INTR_STATUS\n"); + return; + } + + /* See if we have free buffers */ + if (skb_queue_len(&iwm->rx_list) > IWM_RX_LIST_SIZE) { + IWM_ERR(iwm, "No buffer for more Rx frames\n"); + return; + } + + /* We first read the transaction size */ + read_size = sdio_readb(func, IWM_SDIO_INTR_GET_SIZE_ADDR + 1, &ret); + read_size = read_size << 8; + + if (ret < 0) { + IWM_ERR(iwm, "Couldn't read the xfer size\n"); + return; + } + + /* We need to clear the INT register */ + sdio_writeb(func, 1, IWM_SDIO_INTR_CLEAR_ADDR, &ret); + if (ret < 0) { + IWM_ERR(iwm, "Couldn't clear the INT register\n"); + return; + } + + while (buf_size < read_size) + buf_size <<= 1; + + skb = dev_alloc_skb(buf_size); + if (!skb) { + IWM_ERR(iwm, "Couldn't alloc RX skb\n"); + return; + } + rx_info = skb_to_rx_info(skb); + rx_info->rx_size = read_size; + rx_info->rx_buf_size = buf_size; + + /* Now we can read the actual buffer */ + ret = sdio_memcpy_fromio(func, skb_put(skb, read_size), + IWM_SDIO_DATA_ADDR, read_size); + + /* The skb is put on a driver's specific Rx SKB list */ + skb_queue_tail(&iwm->rx_list, skb); + + /* We can now schedule the actual worker */ + queue_work(hw->isr_wq, &hw->isr_worker); +} + +static void iwm_sdio_rx_free(struct iwm_sdio_priv *hw) +{ + struct iwm_priv *iwm = hw_to_iwm(hw); + + flush_workqueue(hw->isr_wq); + + skb_queue_purge(&iwm->rx_list); +} + +/* Bus ops */ +static int if_sdio_enable(struct iwm_priv *iwm) +{ + struct iwm_sdio_priv *hw = iwm_to_if_sdio(iwm); + int ret; + + sdio_claim_host(hw->func); + + ret = sdio_enable_func(hw->func); + if (ret) { + IWM_ERR(iwm, "Couldn't enable the device: is TOP driver " + "loaded and functional?\n"); + goto release_host; + } + + iwm_reset(iwm); + + ret = sdio_claim_irq(hw->func, iwm_sdio_isr); + if (ret) { + IWM_ERR(iwm, "Failed to claim irq: %d\n", ret); + goto release_host; + } + + sdio_writeb(hw->func, 1, IWM_SDIO_INTR_ENABLE_ADDR, &ret); + if (ret < 0) { + IWM_ERR(iwm, "Couldn't enable INTR: %d\n", ret); + goto release_irq; + } + + sdio_release_host(hw->func); + + IWM_DBG_SDIO(iwm, INFO, "IWM SDIO enable\n"); + + return 0; + + release_irq: + sdio_release_irq(hw->func); + release_host: + sdio_release_host(hw->func); + + return ret; +} + +static int if_sdio_disable(struct iwm_priv *iwm) +{ + struct iwm_sdio_priv *hw = iwm_to_if_sdio(iwm); + int ret; + + iwm_reset(iwm); + + sdio_claim_host(hw->func); + sdio_writeb(hw->func, 0, IWM_SDIO_INTR_ENABLE_ADDR, &ret); + if (ret < 0) + IWM_WARN(iwm, "Couldn't disable INTR: %d\n", ret); + + sdio_release_irq(hw->func); + sdio_disable_func(hw->func); + sdio_release_host(hw->func); + + iwm_sdio_rx_free(hw); + + IWM_DBG_SDIO(iwm, INFO, "IWM SDIO disable\n"); + + return 0; +} + +static int if_sdio_send_chunk(struct iwm_priv *iwm, u8 *buf, int count) +{ + struct iwm_sdio_priv *hw = iwm_to_if_sdio(iwm); + int aligned_count = ALIGN(count, hw->blk_size); + int ret; + + if ((unsigned long)buf & 0x3) { + IWM_ERR(iwm, "buf <%p> is not dword aligned\n", buf); + /* TODO: Is this a hardware limitation? use get_unligned */ + return -EINVAL; + } + + sdio_claim_host(hw->func); + ret = sdio_memcpy_toio(hw->func, IWM_SDIO_DATA_ADDR, buf, + aligned_count); + sdio_release_host(hw->func); + + return ret; +} + +/* debugfs hooks */ +static int iwm_debugfs_sdio_open(struct inode *inode, struct file *filp) +{ + filp->private_data = inode->i_private; + return 0; +} + +static ssize_t iwm_debugfs_sdio_read(struct file *filp, char __user *buffer, + size_t count, loff_t *ppos) +{ + struct iwm_priv *iwm = filp->private_data; + struct iwm_sdio_priv *hw = iwm_to_if_sdio(iwm); + char *buf; + u8 cccr; + int buf_len = 4096, ret; + size_t len = 0; + + if (*ppos != 0) + return 0; + if (count < sizeof(buf)) + return -ENOSPC; + + buf = kzalloc(buf_len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + sdio_claim_host(hw->func); + + cccr = sdio_f0_readb(hw->func, SDIO_CCCR_IOEx, &ret); + if (ret) { + IWM_ERR(iwm, "Could not read SDIO_CCCR_IOEx\n"); + goto err; + } + len += snprintf(buf + len, buf_len - len, "CCCR_IOEx: 0x%x\n", cccr); + + cccr = sdio_f0_readb(hw->func, SDIO_CCCR_IORx, &ret); + if (ret) { + IWM_ERR(iwm, "Could not read SDIO_CCCR_IORx\n"); + goto err; + } + len += snprintf(buf + len, buf_len - len, "CCCR_IORx: 0x%x\n", cccr); + + + cccr = sdio_f0_readb(hw->func, SDIO_CCCR_IENx, &ret); + if (ret) { + IWM_ERR(iwm, "Could not read SDIO_CCCR_IENx\n"); + goto err; + } + len += snprintf(buf + len, buf_len - len, "CCCR_IENx: 0x%x\n", cccr); + + + cccr = sdio_f0_readb(hw->func, SDIO_CCCR_INTx, &ret); + if (ret) { + IWM_ERR(iwm, "Could not read SDIO_CCCR_INTx\n"); + goto err; + } + len += snprintf(buf + len, buf_len - len, "CCCR_INTx: 0x%x\n", cccr); + + + cccr = sdio_f0_readb(hw->func, SDIO_CCCR_ABORT, &ret); + if (ret) { + IWM_ERR(iwm, "Could not read SDIO_CCCR_ABORTx\n"); + goto err; + } + len += snprintf(buf + len, buf_len - len, "CCCR_ABORT: 0x%x\n", cccr); + + cccr = sdio_f0_readb(hw->func, SDIO_CCCR_IF, &ret); + if (ret) { + IWM_ERR(iwm, "Could not read SDIO_CCCR_IF\n"); + goto err; + } + len += snprintf(buf + len, buf_len - len, "CCCR_IF: 0x%x\n", cccr); + + + cccr = sdio_f0_readb(hw->func, SDIO_CCCR_CAPS, &ret); + if (ret) { + IWM_ERR(iwm, "Could not read SDIO_CCCR_CAPS\n"); + goto err; + } + len += snprintf(buf + len, buf_len - len, "CCCR_CAPS: 0x%x\n", cccr); + + cccr = sdio_f0_readb(hw->func, SDIO_CCCR_CIS, &ret); + if (ret) { + IWM_ERR(iwm, "Could not read SDIO_CCCR_CIS\n"); + goto err; + } + len += snprintf(buf + len, buf_len - len, "CCCR_CIS: 0x%x\n", cccr); + + ret = simple_read_from_buffer(buffer, len, ppos, buf, buf_len); +err: + sdio_release_host(hw->func); + + kfree(buf); + + return ret; +} + +static const struct file_operations iwm_debugfs_sdio_fops = { + .owner = THIS_MODULE, + .open = iwm_debugfs_sdio_open, + .read = iwm_debugfs_sdio_read, +}; + +static int if_sdio_debugfs_init(struct iwm_priv *iwm, struct dentry *parent_dir) +{ + int result; + struct iwm_sdio_priv *hw = iwm_to_if_sdio(iwm); + + hw->cccr_dentry = debugfs_create_file("cccr", 0200, + parent_dir, iwm, + &iwm_debugfs_sdio_fops); + result = PTR_ERR(hw->cccr_dentry); + if (IS_ERR(hw->cccr_dentry) && (result != -ENODEV)) { + IWM_ERR(iwm, "Couldn't create CCCR entry: %d\n", result); + return result; + } + + return 0; +} + +static void if_sdio_debugfs_exit(struct iwm_priv *iwm) +{ + struct iwm_sdio_priv *hw = iwm_to_if_sdio(iwm); + + debugfs_remove(hw->cccr_dentry); +} + +static struct iwm_if_ops if_sdio_ops = { + .enable = if_sdio_enable, + .disable = if_sdio_disable, + .send_chunk = if_sdio_send_chunk, + .debugfs_init = if_sdio_debugfs_init, + .debugfs_exit = if_sdio_debugfs_exit, + .umac_name = "iwmc3200wifi-umac-sdio.bin", + .calib_lmac_name = "iwmc3200wifi-calib-sdio.bin", + .lmac_name = "iwmc3200wifi-lmac-sdio.bin", +}; + +static int iwm_sdio_probe(struct sdio_func *func, + const struct sdio_device_id *id) +{ + struct iwm_priv *iwm; + struct iwm_sdio_priv *hw; + struct device *dev = &func->dev; + int ret; + + /* check if TOP has already initialized the card */ + sdio_claim_host(func); + ret = sdio_enable_func(func); + if (ret) { + dev_err(dev, "wait for TOP to enable the device\n"); + sdio_release_host(func); + return ret; + } + + ret = sdio_set_block_size(func, IWM_SDIO_BLK_SIZE); + + sdio_disable_func(func); + sdio_release_host(func); + + if (ret < 0) { + dev_err(dev, "Failed to set block size: %d\n", ret); + return ret; + } + + iwm = iwm_if_alloc(sizeof(struct iwm_sdio_priv), dev, &if_sdio_ops); + if (IS_ERR(iwm)) { + dev_err(dev, "allocate SDIO interface failed\n"); + return PTR_ERR(iwm); + } + + hw = iwm_private(iwm); + hw->iwm = iwm; + + ret = iwm_debugfs_init(iwm); + if (ret < 0) { + IWM_ERR(iwm, "Debugfs registration failed\n"); + goto if_free; + } + + sdio_set_drvdata(func, hw); + + hw->func = func; + hw->blk_size = IWM_SDIO_BLK_SIZE; + + hw->isr_wq = create_singlethread_workqueue(KBUILD_MODNAME "_sdio"); + if (!hw->isr_wq) { + ret = -ENOMEM; + goto debugfs_exit; + } + + INIT_WORK(&hw->isr_worker, iwm_sdio_isr_worker); + + ret = iwm_if_add(iwm); + if (ret) { + dev_err(dev, "add SDIO interface failed\n"); + goto destroy_wq; + } + + dev_info(dev, "IWM SDIO probe\n"); + + return 0; + + destroy_wq: + destroy_workqueue(hw->isr_wq); + debugfs_exit: + iwm_debugfs_exit(iwm); + if_free: + iwm_if_free(iwm); + return ret; +} + +static void iwm_sdio_remove(struct sdio_func *func) +{ + struct iwm_sdio_priv *hw = sdio_get_drvdata(func); + struct iwm_priv *iwm = hw_to_iwm(hw); + struct device *dev = &func->dev; + + iwm_if_remove(iwm); + destroy_workqueue(hw->isr_wq); + iwm_debugfs_exit(iwm); + iwm_if_free(iwm); + + sdio_set_drvdata(func, NULL); + + dev_info(dev, "IWM SDIO remove\n"); + + return; +} + +static const struct sdio_device_id iwm_sdio_ids[] = { + { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL, SDIO_DEVICE_ID_IWM) }, + { /* end: all zeroes */ }, +}; +MODULE_DEVICE_TABLE(sdio, iwm_sdio_ids); + +static struct sdio_driver iwm_sdio_driver = { + .name = "iwm_sdio", + .id_table = iwm_sdio_ids, + .probe = iwm_sdio_probe, + .remove = iwm_sdio_remove, +}; + +static int __init iwm_sdio_init_module(void) +{ + int ret; + + ret = sdio_register_driver(&iwm_sdio_driver); + + return ret; +} + +static void __exit iwm_sdio_exit_module(void) +{ + sdio_unregister_driver(&iwm_sdio_driver); +} + +module_init(iwm_sdio_init_module); +module_exit(iwm_sdio_exit_module); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR(IWM_COPYRIGHT " " IWM_AUTHOR); diff --git a/drivers/net/wireless/iwmc3200wifi/sdio.h b/drivers/net/wireless/iwmc3200wifi/sdio.h new file mode 100644 index 000000000000..b3c156b08dda --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/sdio.h @@ -0,0 +1,67 @@ +/* + * Intel Wireless Multicomm 3200 WiFi driver + * + * Copyright (C) 2009 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * Intel Corporation + * Samuel Ortiz + * Zhu Yi + * + */ + +#ifndef __IWM_SDIO_H__ +#define __IWM_SDIO_H__ + +#define SDIO_VENDOR_ID_INTEL 0x89 +#define SDIO_DEVICE_ID_IWM 0x1403 + +#define IWM_SDIO_DATA_ADDR 0x0 +#define IWM_SDIO_INTR_ENABLE_ADDR 0x14 +#define IWM_SDIO_INTR_STATUS_ADDR 0x13 +#define IWM_SDIO_INTR_CLEAR_ADDR 0x13 +#define IWM_SDIO_INTR_GET_SIZE_ADDR 0x2C + +#define IWM_SDIO_BLK_SIZE 256 + +#define iwm_to_if_sdio(i) (struct iwm_sdio_priv *)(iwm->private) + +struct iwm_sdio_priv { + struct sdio_func *func; + struct iwm_priv *iwm; + + struct workqueue_struct *isr_wq; + struct work_struct isr_worker; + + struct dentry *cccr_dentry; + + unsigned int blk_size; +}; + +#endif diff --git a/drivers/net/wireless/iwmc3200wifi/tx.c b/drivers/net/wireless/iwmc3200wifi/tx.c new file mode 100644 index 000000000000..e3b4f7902daf --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/tx.c @@ -0,0 +1,492 @@ +/* + * Intel Wireless Multicomm 3200 WiFi driver + * + * Copyright (C) 2009 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * Intel Corporation + * Samuel Ortiz + * Zhu Yi + * + */ + +/* + * iwm Tx theory of operation: + * + * 1) We receive a 802.3 frame from the stack + * 2) We convert it to a 802.11 frame [iwm_xmit_frame] + * 3) We queue it to its corresponding tx queue [iwm_xmit_frame] + * 4) We schedule the tx worker. There is one worker per tx + * queue. [iwm_xmit_frame] + * 5) The tx worker is scheduled + * 6) We go through every queued skb on the tx queue, and for each + * and every one of them: [iwm_tx_worker] + * a) We check if we have enough Tx credits (see below for a Tx + * credits description) for the frame length. [iwm_tx_worker] + * b) If we do, we aggregate the Tx frame into a UDMA one, by + * concatenating one REPLY_TX command per Tx frame. [iwm_tx_worker] + * c) When we run out of credits, or when we reach the maximum + * concatenation size, we actually send the concatenated UDMA + * frame. [iwm_tx_worker] + * + * When we run out of Tx credits, the skbs are filling the tx queue, + * and eventually we will stop the netdev queue. [iwm_tx_worker] + * The tx queue is emptied as we're getting new tx credits, by + * scheduling the tx_worker. [iwm_tx_credit_inc] + * The netdev queue is started again when we have enough tx credits, + * and when our tx queue has some reasonable amout of space available + * (i.e. half of the max size). [iwm_tx_worker] + */ + +#include +#include +#include + +#include "iwm.h" +#include "debug.h" +#include "commands.h" +#include "hal.h" +#include "umac.h" +#include "bus.h" + +#define IWM_UMAC_PAGE_ALLOC_WRAP 0xffff + +#define BYTES_TO_PAGES(n) (1 + ((n) >> ilog2(IWM_UMAC_PAGE_SIZE)) - \ + (((n) & (IWM_UMAC_PAGE_SIZE - 1)) == 0)) + +#define pool_id_to_queue(id) ((id < IWM_TX_CMD_QUEUE) ? id : id - 1) +#define queue_to_pool_id(q) ((q < IWM_TX_CMD_QUEUE) ? q : q + 1) + +/* require to hold tx_credit lock */ +static int iwm_tx_credit_get(struct iwm_tx_credit *tx_credit, int id) +{ + struct pool_entry *pool = &tx_credit->pools[id]; + struct spool_entry *spool = &tx_credit->spools[pool->sid]; + int spool_pages; + + /* number of pages can be taken from spool by this pool */ + spool_pages = spool->max_pages - spool->alloc_pages + + max(pool->min_pages - pool->alloc_pages, 0); + + return min(pool->max_pages - pool->alloc_pages, spool_pages); +} + +static bool iwm_tx_credit_ok(struct iwm_priv *iwm, int id, int nb) +{ + u32 npages = BYTES_TO_PAGES(nb); + + if (npages <= iwm_tx_credit_get(&iwm->tx_credit, id)) + return 1; + + set_bit(id, &iwm->tx_credit.full_pools_map); + + IWM_DBG_TX(iwm, DBG, "LINK: stop txq[%d], available credit: %d\n", + pool_id_to_queue(id), + iwm_tx_credit_get(&iwm->tx_credit, id)); + + return 0; +} + +void iwm_tx_credit_inc(struct iwm_priv *iwm, int id, int total_freed_pages) +{ + struct pool_entry *pool; + struct spool_entry *spool; + int freed_pages; + int queue; + + BUG_ON(id >= IWM_MACS_OUT_GROUPS); + + pool = &iwm->tx_credit.pools[id]; + spool = &iwm->tx_credit.spools[pool->sid]; + + freed_pages = total_freed_pages - pool->total_freed_pages; + IWM_DBG_TX(iwm, DBG, "Free %d pages for pool[%d]\n", freed_pages, id); + + if (!freed_pages) { + IWM_DBG_TX(iwm, DBG, "No pages are freed by UMAC\n"); + return; + } else if (freed_pages < 0) + freed_pages += IWM_UMAC_PAGE_ALLOC_WRAP + 1; + + if (pool->alloc_pages > pool->min_pages) { + int spool_pages = pool->alloc_pages - pool->min_pages; + spool_pages = min(spool_pages, freed_pages); + spool->alloc_pages -= spool_pages; + } + + pool->alloc_pages -= freed_pages; + pool->total_freed_pages = total_freed_pages; + + IWM_DBG_TX(iwm, DBG, "Pool[%d] pages alloc: %d, total_freed: %d, " + "Spool[%d] pages alloc: %d\n", id, pool->alloc_pages, + pool->total_freed_pages, pool->sid, spool->alloc_pages); + + if (test_bit(id, &iwm->tx_credit.full_pools_map) && + (pool->alloc_pages < pool->max_pages / 2)) { + clear_bit(id, &iwm->tx_credit.full_pools_map); + + queue = pool_id_to_queue(id); + + IWM_DBG_TX(iwm, DBG, "LINK: start txq[%d], available " + "credit: %d\n", queue, + iwm_tx_credit_get(&iwm->tx_credit, id)); + queue_work(iwm->txq[queue].wq, &iwm->txq[queue].worker); + } +} + +static void iwm_tx_credit_dec(struct iwm_priv *iwm, int id, int alloc_pages) +{ + struct pool_entry *pool; + struct spool_entry *spool; + int spool_pages; + + IWM_DBG_TX(iwm, DBG, "Allocate %d pages for pool[%d]\n", + alloc_pages, id); + + BUG_ON(id >= IWM_MACS_OUT_GROUPS); + + pool = &iwm->tx_credit.pools[id]; + spool = &iwm->tx_credit.spools[pool->sid]; + + spool_pages = pool->alloc_pages + alloc_pages - pool->min_pages; + + if (pool->alloc_pages >= pool->min_pages) + spool->alloc_pages += alloc_pages; + else if (spool_pages > 0) + spool->alloc_pages += spool_pages; + + pool->alloc_pages += alloc_pages; + + IWM_DBG_TX(iwm, DBG, "Pool[%d] pages alloc: %d, total_freed: %d, " + "Spool[%d] pages alloc: %d\n", id, pool->alloc_pages, + pool->total_freed_pages, pool->sid, spool->alloc_pages); +} + +int iwm_tx_credit_alloc(struct iwm_priv *iwm, int id, int nb) +{ + u32 npages = BYTES_TO_PAGES(nb); + int ret = 0; + + spin_lock(&iwm->tx_credit.lock); + + if (!iwm_tx_credit_ok(iwm, id, nb)) { + IWM_DBG_TX(iwm, DBG, "No credit avaliable for pool[%d]\n", id); + ret = -ENOSPC; + goto out; + } + + iwm_tx_credit_dec(iwm, id, npages); + + out: + spin_unlock(&iwm->tx_credit.lock); + return ret; +} + +/* + * Since we're on an SDIO or USB bus, we are not sharing memory + * for storing to be transmitted frames. The host needs to push + * them upstream. As a consequence there needs to be a way for + * the target to let us know if it can actually take more TX frames + * or not. This is what Tx credits are for. + * + * For each Tx HW queue, we have a Tx pool, and then we have one + * unique super pool (spool), which is actually a global pool of + * all the UMAC pages. + * For each Tx pool we have a min_pages, a max_pages fields, and a + * alloc_pages fields. The alloc_pages tracks the number of pages + * currently allocated from the tx pool. + * Here are the rules to check if given a tx frame we have enough + * tx credits for it: + * 1) We translate the frame length into a number of UMAC pages. + * Let's call them n_pages. + * 2) For the corresponding tx pool, we check if n_pages + + * pool->alloc_pages is higher than pool->min_pages. min_pages + * represent a set of pre-allocated pages on the tx pool. If + * that's the case, then we need to allocate those pages from + * the spool. We can do so until we reach spool->max_pages. + * 3) Each tx pool is not allowed to allocate more than pool->max_pages + * from the spool, so once we're over min_pages, we can allocate + * pages from the spool, but not more than max_pages. + * + * When the tx code path needs to send a tx frame, it checks first + * if it has enough tx credits, following those rules. [iwm_tx_credit_get] + * If it does, it then updates the pool and spool counters and + * then send the frame. [iwm_tx_credit_alloc and iwm_tx_credit_dec] + * On the other side, when the UMAC is done transmitting frames, it + * will send a credit update notification to the host. This is when + * the pool and spool counters gets to be decreased. [iwm_tx_credit_inc, + * called from rx.c:iwm_ntf_tx_credit_update] + * + */ +void iwm_tx_credit_init_pools(struct iwm_priv *iwm, + struct iwm_umac_notif_alive *alive) +{ + int i, sid, pool_pages; + + spin_lock(&iwm->tx_credit.lock); + + iwm->tx_credit.pool_nr = le16_to_cpu(alive->page_grp_count); + iwm->tx_credit.full_pools_map = 0; + memset(&iwm->tx_credit.spools[0], 0, sizeof(struct spool_entry)); + + IWM_DBG_TX(iwm, DBG, "Pools number is %d\n", iwm->tx_credit.pool_nr); + + for (i = 0; i < iwm->tx_credit.pool_nr; i++) { + __le32 page_grp_state = alive->page_grp_state[i]; + + iwm->tx_credit.pools[i].id = GET_VAL32(page_grp_state, + UMAC_ALIVE_PAGE_STS_GRP_NUM); + iwm->tx_credit.pools[i].sid = GET_VAL32(page_grp_state, + UMAC_ALIVE_PAGE_STS_SGRP_NUM); + iwm->tx_credit.pools[i].min_pages = GET_VAL32(page_grp_state, + UMAC_ALIVE_PAGE_STS_GRP_MIN_SIZE); + iwm->tx_credit.pools[i].max_pages = GET_VAL32(page_grp_state, + UMAC_ALIVE_PAGE_STS_GRP_MAX_SIZE); + iwm->tx_credit.pools[i].alloc_pages = 0; + iwm->tx_credit.pools[i].total_freed_pages = 0; + + sid = iwm->tx_credit.pools[i].sid; + pool_pages = iwm->tx_credit.pools[i].min_pages; + + if (iwm->tx_credit.spools[sid].max_pages == 0) { + iwm->tx_credit.spools[sid].id = sid; + iwm->tx_credit.spools[sid].max_pages = + GET_VAL32(page_grp_state, + UMAC_ALIVE_PAGE_STS_SGRP_MAX_SIZE); + iwm->tx_credit.spools[sid].alloc_pages = 0; + } + + iwm->tx_credit.spools[sid].alloc_pages += pool_pages; + + IWM_DBG_TX(iwm, DBG, "Pool idx: %d, id: %d, sid: %d, capacity " + "min: %d, max: %d, pool alloc: %d, total_free: %d, " + "super poll alloc: %d\n", + i, iwm->tx_credit.pools[i].id, + iwm->tx_credit.pools[i].sid, + iwm->tx_credit.pools[i].min_pages, + iwm->tx_credit.pools[i].max_pages, + iwm->tx_credit.pools[i].alloc_pages, + iwm->tx_credit.pools[i].total_freed_pages, + iwm->tx_credit.spools[sid].alloc_pages); + } + + spin_unlock(&iwm->tx_credit.lock); +} + +#define IWM_UDMA_HDR_LEN sizeof(struct iwm_umac_wifi_out_hdr) + +static int iwm_tx_build_packet(struct iwm_priv *iwm, struct sk_buff *skb, + int pool_id, u8 *buf) +{ + struct iwm_umac_wifi_out_hdr *hdr = (struct iwm_umac_wifi_out_hdr *)buf; + struct iwm_udma_wifi_cmd udma_cmd; + struct iwm_umac_cmd umac_cmd; + struct iwm_tx_info *tx_info = skb_to_tx_info(skb); + + udma_cmd.count = cpu_to_le16(skb->len + + sizeof(struct iwm_umac_fw_cmd_hdr)); + /* set EOP to 0 here. iwm_udma_wifi_hdr_set_eop() will be + * called later to set EOP for the last packet. */ + udma_cmd.eop = 0; + udma_cmd.credit_group = pool_id; + udma_cmd.ra_tid = tx_info->sta << 4 | tx_info->tid; + udma_cmd.lmac_offset = 0; + + umac_cmd.id = REPLY_TX; + umac_cmd.count = cpu_to_le16(skb->len); + umac_cmd.color = tx_info->color; + umac_cmd.resp = 0; + umac_cmd.seq_num = cpu_to_le16(iwm_alloc_wifi_cmd_seq(iwm)); + + iwm_build_udma_wifi_hdr(iwm, &hdr->hw_hdr, &udma_cmd); + iwm_build_umac_hdr(iwm, &hdr->sw_hdr, &umac_cmd); + + memcpy(buf + sizeof(*hdr), skb->data, skb->len); + + return 0; +} + +static int iwm_tx_send_concat_packets(struct iwm_priv *iwm, + struct iwm_tx_queue *txq) +{ + int ret; + + if (!txq->concat_count) + return 0; + + IWM_DBG_TX(iwm, DBG, "Send concatenated Tx: queue %d, %d bytes\n", + txq->id, txq->concat_count); + + /* mark EOP for the last packet */ + iwm_udma_wifi_hdr_set_eop(iwm, txq->concat_ptr, 1); + + ret = iwm_bus_send_chunk(iwm, txq->concat_buf, txq->concat_count); + + txq->concat_count = 0; + txq->concat_ptr = txq->concat_buf; + + return ret; +} + +#define CONFIG_IWM_TX_CONCATENATED 1 + +void iwm_tx_worker(struct work_struct *work) +{ + struct iwm_priv *iwm; + struct iwm_tx_info *tx_info = NULL; + struct sk_buff *skb; + int cmdlen, ret; + struct iwm_tx_queue *txq; + int pool_id; + + txq = container_of(work, struct iwm_tx_queue, worker); + iwm = container_of(txq, struct iwm_priv, txq[txq->id]); + + pool_id = queue_to_pool_id(txq->id); + + while (!test_bit(pool_id, &iwm->tx_credit.full_pools_map) && + !skb_queue_empty(&txq->queue)) { + + skb = skb_dequeue(&txq->queue); + tx_info = skb_to_tx_info(skb); + cmdlen = IWM_UDMA_HDR_LEN + skb->len; + + IWM_DBG_TX(iwm, DBG, "Tx frame on queue %d: skb: 0x%p, sta: " + "%d, color: %d\n", txq->id, skb, tx_info->sta, + tx_info->color); + +#if !CONFIG_IWM_TX_CONCATENATED + /* temporarily keep this to comparing the performance */ + ret = iwm_send_packet(iwm, skb, pool_id); +#else + + if (txq->concat_count + cmdlen > IWM_HAL_CONCATENATE_BUF_SIZE) + iwm_tx_send_concat_packets(iwm, txq); + + ret = iwm_tx_credit_alloc(iwm, pool_id, cmdlen); + if (ret) { + IWM_DBG_TX(iwm, DBG, "not enough tx_credit for queue " + "%d, Tx worker stopped\n", txq->id); + skb_queue_head(&txq->queue, skb); + break; + } + + txq->concat_ptr = txq->concat_buf + txq->concat_count; + iwm_tx_build_packet(iwm, skb, pool_id, txq->concat_ptr); + txq->concat_count += ALIGN(cmdlen, 16); +#endif + kfree_skb(skb); + } + + iwm_tx_send_concat_packets(iwm, txq); + + if (__netif_subqueue_stopped(iwm_to_ndev(iwm), txq->id) && + !test_bit(pool_id, &iwm->tx_credit.full_pools_map) && + (skb_queue_len(&txq->queue) < IWM_TX_LIST_SIZE / 2)) { + IWM_DBG_TX(iwm, DBG, "LINK: start netif_subqueue[%d]", txq->id); + netif_wake_subqueue(iwm_to_ndev(iwm), txq->id); + } +} + +int iwm_xmit_frame(struct sk_buff *skb, struct net_device *netdev) +{ + struct iwm_priv *iwm = ndev_to_iwm(netdev); + struct net_device *ndev = iwm_to_ndev(iwm); + struct wireless_dev *wdev = iwm_to_wdev(iwm); + u8 *dst_addr; + struct iwm_tx_info *tx_info; + struct iwm_tx_queue *txq; + struct iwm_sta_info *sta_info; + u8 sta_id; + u16 queue; + int ret; + + if (!test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) { + IWM_DBG_TX(iwm, DBG, "LINK: stop netif_all_queues: " + "not associated\n"); + netif_tx_stop_all_queues(netdev); + goto drop; + } + + queue = skb_get_queue_mapping(skb); + BUG_ON(queue >= IWM_TX_DATA_QUEUES); /* no iPAN yet */ + + txq = &iwm->txq[queue]; + + /* No free space for Tx, tx_worker is too slow */ + if (skb_queue_len(&txq->queue) > IWM_TX_LIST_SIZE) { + IWM_DBG_TX(iwm, DBG, "LINK: stop netif_subqueue[%d]\n", queue); + netif_stop_subqueue(netdev, queue); + return NETDEV_TX_BUSY; + } + + ret = ieee80211_data_from_8023(skb, netdev->dev_addr, wdev->iftype, + iwm->bssid, 0); + if (ret) { + IWM_ERR(iwm, "build wifi header failed\n"); + goto drop; + } + + dst_addr = ((struct ieee80211_hdr *)(skb->data))->addr1; + + for (sta_id = 0; sta_id < IWM_STA_TABLE_NUM; sta_id++) { + sta_info = &iwm->sta_table[sta_id]; + if (sta_info->valid && + !memcmp(dst_addr, sta_info->addr, ETH_ALEN)) + break; + } + + if (sta_id == IWM_STA_TABLE_NUM) { + IWM_ERR(iwm, "STA %pM not found in sta_table, Tx ignored\n", + dst_addr); + goto drop; + } + + tx_info = skb_to_tx_info(skb); + tx_info->sta = sta_id; + tx_info->color = sta_info->color; + /* UMAC uses TID 8 (vs. 0) for non QoS packets */ + if (sta_info->qos) + tx_info->tid = skb->priority; + else + tx_info->tid = IWM_UMAC_MGMT_TID; + + skb_queue_tail(&iwm->txq[queue].queue, skb); + + queue_work(iwm->txq[queue].wq, &iwm->txq[queue].worker); + + ndev->stats.tx_packets++; + ndev->stats.tx_bytes += skb->len; + return NETDEV_TX_OK; + + drop: + ndev->stats.tx_dropped++; + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; +} diff --git a/drivers/net/wireless/iwmc3200wifi/umac.h b/drivers/net/wireless/iwmc3200wifi/umac.h new file mode 100644 index 000000000000..4a95cce1f0a6 --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/umac.h @@ -0,0 +1,744 @@ +/* + * Intel Wireless Multicomm 3200 WiFi driver + * + * Copyright (C) 2009 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * Intel Corporation + * Samuel Ortiz + * Zhu Yi + * + */ + +#ifndef __IWM_UMAC_H__ +#define __IWM_UMAC_H__ + +struct iwm_udma_in_hdr { + __le32 cmd; + __le32 size; +} __attribute__ ((packed)); + +struct iwm_udma_out_nonwifi_hdr { + __le32 cmd; + __le32 addr; + __le32 op1_sz; + __le32 op2; +} __attribute__ ((packed)); + +struct iwm_udma_out_wifi_hdr { + __le32 cmd; + __le32 meta_data; +} __attribute__ ((packed)); + +/* Sequence numbering */ +#define UMAC_WIFI_SEQ_NUM_BASE 1 +#define UMAC_WIFI_SEQ_NUM_MAX 0x4000 +#define UMAC_NONWIFI_SEQ_NUM_BASE 1 +#define UMAC_NONWIFI_SEQ_NUM_MAX 0x10 + +/* MAC address address */ +#define WICO_MAC_ADDRESS_ADDR 0x604008F8 + +/* RA / TID */ +#define UMAC_HDI_ACT_TBL_IDX_TID_POS 0 +#define UMAC_HDI_ACT_TBL_IDX_TID_SEED 0xF + +#define UMAC_HDI_ACT_TBL_IDX_RA_POS 4 +#define UMAC_HDI_ACT_TBL_IDX_RA_SEED 0xF + +#define UMAC_HDI_ACT_TBL_IDX_RA_UMAC 0xF +#define UMAC_HDI_ACT_TBL_IDX_TID_UMAC 0x9 +#define UMAC_HDI_ACT_TBL_IDX_TID_LMAC 0xA + +#define UMAC_HDI_ACT_TBL_IDX_HOST_CMD \ + ((UMAC_HDI_ACT_TBL_IDX_RA_UMAC << UMAC_HDI_ACT_TBL_IDX_RA_POS) |\ + (UMAC_HDI_ACT_TBL_IDX_TID_UMAC << UMAC_HDI_ACT_TBL_IDX_TID_POS)) +#define UMAC_HDI_ACT_TBL_IDX_UMAC_CMD \ + ((UMAC_HDI_ACT_TBL_IDX_RA_UMAC << UMAC_HDI_ACT_TBL_IDX_RA_POS) |\ + (UMAC_HDI_ACT_TBL_IDX_TID_LMAC << UMAC_HDI_ACT_TBL_IDX_TID_POS)) + +/* iwm_umac_notif_alive.page_grp_state Group number -- bits [3:0] */ +#define UMAC_ALIVE_PAGE_STS_GRP_NUM_POS 0 +#define UMAC_ALIVE_PAGE_STS_GRP_NUM_SEED 0xF + +/* iwm_umac_notif_alive.page_grp_state Super group number -- bits [7:4] */ +#define UMAC_ALIVE_PAGE_STS_SGRP_NUM_POS 4 +#define UMAC_ALIVE_PAGE_STS_SGRP_NUM_SEED 0xF + +/* iwm_umac_notif_alive.page_grp_state Group min size -- bits [15:8] */ +#define UMAC_ALIVE_PAGE_STS_GRP_MIN_SIZE_POS 8 +#define UMAC_ALIVE_PAGE_STS_GRP_MIN_SIZE_SEED 0xFF + +/* iwm_umac_notif_alive.page_grp_state Group max size -- bits [23:16] */ +#define UMAC_ALIVE_PAGE_STS_GRP_MAX_SIZE_POS 16 +#define UMAC_ALIVE_PAGE_STS_GRP_MAX_SIZE_SEED 0xFF + +/* iwm_umac_notif_alive.page_grp_state Super group max size -- bits [31:24] */ +#define UMAC_ALIVE_PAGE_STS_SGRP_MAX_SIZE_POS 24 +#define UMAC_ALIVE_PAGE_STS_SGRP_MAX_SIZE_SEED 0xFF + +/* Barkers */ +#define UMAC_REBOOT_BARKER 0xdeadbeef +#define UMAC_ACK_BARKER 0xfeedbabe +#define UMAC_PAD_TERMINAL 0xadadadad + +/* UMAC JMP address */ +#define UMAC_MU_FW_INST_DATA_12_ADDR 0xBF0000 + +/* iwm_umac_hdi_out_hdr.cmd OP code -- bits [3:0] */ +#define UMAC_HDI_OUT_CMD_OPCODE_POS 0 +#define UMAC_HDI_OUT_CMD_OPCODE_SEED 0xF + +/* iwm_umac_hdi_out_hdr.cmd End-Of-Transfer -- bits [10:10] */ +#define UMAC_HDI_OUT_CMD_EOT_POS 10 +#define UMAC_HDI_OUT_CMD_EOT_SEED 0x1 + +/* iwm_umac_hdi_out_hdr.cmd UTFD only usage -- bits [11:11] */ +#define UMAC_HDI_OUT_CMD_UTFD_ONLY_POS 11 +#define UMAC_HDI_OUT_CMD_UTFD_ONLY_SEED 0x1 + +/* iwm_umac_hdi_out_hdr.cmd Non-WiFi HW sequence number -- bits [12:15] */ +#define UDMA_HDI_OUT_CMD_NON_WIFI_HW_SEQ_NUM_POS 12 +#define UDMA_HDI_OUT_CMD_NON_WIFI_HW_SEQ_NUM_SEED 0xF + +/* iwm_umac_hdi_out_hdr.cmd Signature -- bits [31:16] */ +#define UMAC_HDI_OUT_CMD_SIGNATURE_POS 16 +#define UMAC_HDI_OUT_CMD_SIGNATURE_SEED 0xFFFF + +/* iwm_umac_hdi_out_hdr.meta_data Byte count -- bits [11:0] */ +#define UMAC_HDI_OUT_BYTE_COUNT_POS 0 +#define UMAC_HDI_OUT_BYTE_COUNT_SEED 0xFFF + +/* iwm_umac_hdi_out_hdr.meta_data Credit group -- bits [15:12] */ +#define UMAC_HDI_OUT_CREDIT_GRP_POS 12 +#define UMAC_HDI_OUT_CREDIT_GRP_SEED 0xF + +/* iwm_umac_hdi_out_hdr.meta_data RA/TID -- bits [23:16] */ +#define UMAC_HDI_OUT_RATID_POS 16 +#define UMAC_HDI_OUT_RATID_SEED 0xFF + +/* iwm_umac_hdi_out_hdr.meta_data LMAC offset -- bits [31:24] */ +#define UMAC_HDI_OUT_LMAC_OFFSET_POS 24 +#define UMAC_HDI_OUT_LMAC_OFFSET_SEED 0xFF + +/* Signature */ +#define UMAC_HDI_OUT_SIGNATURE 0xCBBC + +/* buffer alignment */ +#define UMAC_HDI_BUF_ALIGN_MSK 0xF + +/* iwm_umac_hdi_in_hdr.cmd OP code -- bits [3:0] */ +#define UMAC_HDI_IN_CMD_OPCODE_POS 0 +#define UMAC_HDI_IN_CMD_OPCODE_SEED 0xF + +/* iwm_umac_hdi_in_hdr.cmd Non-WiFi API response -- bits [6:4] */ +#define UMAC_HDI_IN_CMD_NON_WIFI_RESP_POS 4 +#define UMAC_HDI_IN_CMD_NON_WIFI_RESP_SEED 0x7 + +/* iwm_umac_hdi_in_hdr.cmd WiFi API source -- bits [5:4] */ +#define UMAC_HDI_IN_CMD_SOURCE_POS 4 +#define UMAC_HDI_IN_CMD_SOURCE_SEED 0x3 + +/* iwm_umac_hdi_in_hdr.cmd WiFi API EOT -- bits [6:6] */ +#define UMAC_HDI_IN_CMD_EOT_POS 6 +#define UMAC_HDI_IN_CMD_EOT_SEED 0x1 + +/* iwm_umac_hdi_in_hdr.cmd timestamp present -- bits [7:7] */ +#define UMAC_HDI_IN_CMD_TIME_STAMP_PRESENT_POS 7 +#define UMAC_HDI_IN_CMD_TIME_STAMP_PRESENT_SEED 0x1 + +/* iwm_umac_hdi_in_hdr.cmd WiFi Non-last AMSDU -- bits [8:8] */ +#define UMAC_HDI_IN_CMD_NON_LAST_AMSDU_POS 8 +#define UMAC_HDI_IN_CMD_NON_LAST_AMSDU_SEED 0x1 + +/* iwm_umac_hdi_in_hdr.cmd WiFi HW sequence number -- bits [31:9] */ +#define UMAC_HDI_IN_CMD_HW_SEQ_NUM_POS 9 +#define UMAC_HDI_IN_CMD_HW_SEQ_NUM_SEED 0x7FFFFF + +/* iwm_umac_hdi_in_hdr.cmd Non-WiFi HW sequence number -- bits [12:15] */ +#define UDMA_HDI_IN_CMD_NON_WIFI_HW_SEQ_NUM_POS 12 +#define UDMA_HDI_IN_CMD_NON_WIFI_HW_SEQ_NUM_SEED 0xF + +/* iwm_umac_hdi_in_hdr.cmd Non-WiFi HW signature -- bits [16:31] */ +#define UDMA_HDI_IN_CMD_NON_WIFI_HW_SIG_POS 16 +#define UDMA_HDI_IN_CMD_NON_WIFI_HW_SIG_SEED 0xFFFF + +/* Fixed Non-WiFi signature */ +#define UDMA_HDI_IN_CMD_NON_WIFI_HW_SIG 0xCBBC + +/* IN NTFY op-codes */ +#define UMAC_NOTIFY_OPCODE_ALIVE 0xA1 +#define UMAC_NOTIFY_OPCODE_INIT_COMPLETE 0xA2 +#define UMAC_NOTIFY_OPCODE_WIFI_CORE_STATUS 0xA3 +#define UMAC_NOTIFY_OPCODE_ERROR 0xA4 +#define UMAC_NOTIFY_OPCODE_DEBUG 0xA5 +#define UMAC_NOTIFY_OPCODE_WIFI_IF_WRAPPER 0xB0 +#define UMAC_NOTIFY_OPCODE_STATS 0xB1 +#define UMAC_NOTIFY_OPCODE_PAGE_DEALLOC 0xB3 +#define UMAC_NOTIFY_OPCODE_RX_TICKET 0xB4 +#define UMAC_NOTIFY_OPCODE_MAX (UMAC_NOTIFY_OPCODE_RX_TICKET -\ + UMAC_NOTIFY_OPCODE_ALIVE + 1) +#define UMAC_NOTIFY_OPCODE_FIRST (UMAC_NOTIFY_OPCODE_ALIVE) + +/* HDI OUT OP CODE */ +#define UMAC_HDI_OUT_OPCODE_PING 0x0 +#define UMAC_HDI_OUT_OPCODE_READ 0x1 +#define UMAC_HDI_OUT_OPCODE_WRITE 0x2 +#define UMAC_HDI_OUT_OPCODE_JUMP 0x3 +#define UMAC_HDI_OUT_OPCODE_REBOOT 0x4 +#define UMAC_HDI_OUT_OPCODE_WRITE_PERSISTENT 0x5 +#define UMAC_HDI_OUT_OPCODE_READ_PERSISTENT 0x6 +#define UMAC_HDI_OUT_OPCODE_READ_MODIFY_WRITE 0x7 +/* #define UMAC_HDI_OUT_OPCODE_RESERVED 0x8..0xA */ +#define UMAC_HDI_OUT_OPCODE_WRITE_AUX_REG 0xB +#define UMAC_HDI_OUT_OPCODE_WIFI 0xF + +/* HDI IN OP CODE -- Non WiFi*/ +#define UMAC_HDI_IN_OPCODE_PING 0x0 +#define UMAC_HDI_IN_OPCODE_READ 0x1 +#define UMAC_HDI_IN_OPCODE_WRITE 0x2 +#define UMAC_HDI_IN_OPCODE_WRITE_PERSISTENT 0x5 +#define UMAC_HDI_IN_OPCODE_READ_PERSISTENT 0x6 +#define UMAC_HDI_IN_OPCODE_READ_MODIFY_WRITE 0x7 +#define UMAC_HDI_IN_OPCODE_EP_MGMT 0x8 +#define UMAC_HDI_IN_OPCODE_CREDIT_CHANGE 0x9 +#define UMAC_HDI_IN_OPCODE_CTRL_DATABASE 0xA +#define UMAC_HDI_IN_OPCODE_WRITE_AUX_REG 0xB +#define UMAC_HDI_IN_OPCODE_NONWIFI_MAX \ + (UMAC_HDI_IN_OPCODE_WRITE_AUX_REG + 1) +#define UMAC_HDI_IN_OPCODE_WIFI 0xF + +/* HDI IN SOURCE */ +#define UMAC_HDI_IN_SOURCE_FHRX 0x0 +#define UMAC_HDI_IN_SOURCE_UDMA 0x1 +#define UMAC_HDI_IN_SOURCE_FW 0x2 +#define UMAC_HDI_IN_SOURCE_RESERVED 0x3 + +/* OUT CMD op-codes */ +#define UMAC_CMD_OPCODE_ECHO 0x01 +#define UMAC_CMD_OPCODE_HALT 0x02 +#define UMAC_CMD_OPCODE_RESET 0x03 +#define UMAC_CMD_OPCODE_BULK_EP_INACT_TIMEOUT 0x09 +#define UMAC_CMD_OPCODE_URB_CANCEL_ACK 0x0A +#define UMAC_CMD_OPCODE_DCACHE_FLUSH 0x0B +#define UMAC_CMD_OPCODE_EEPROM_PROXY 0x0C +#define UMAC_CMD_OPCODE_TX_ECHO 0x0D +#define UMAC_CMD_OPCODE_DBG_MON 0x0E +#define UMAC_CMD_OPCODE_INTERNAL_TX 0x0F +#define UMAC_CMD_OPCODE_SET_PARAM_FIX 0x10 +#define UMAC_CMD_OPCODE_SET_PARAM_VAR 0x11 +#define UMAC_CMD_OPCODE_GET_PARAM 0x12 +#define UMAC_CMD_OPCODE_DBG_EVENT_WRAPPER 0x13 +#define UMAC_CMD_OPCODE_TARGET 0x14 +#define UMAC_CMD_OPCODE_STATISTIC_REQUEST 0x15 +#define UMAC_CMD_OPCODE_GET_CHAN_INFO_LIST 0x16 +#define UMAC_CMD_OPCODE_SET_PARAM_LIST 0x17 +#define UMAC_CMD_OPCODE_GET_PARAM_LIST 0x18 +#define UMAC_CMD_OPCODE_BASE_WRAPPER 0xFA +#define UMAC_CMD_OPCODE_LMAC_WRAPPER 0xFB +#define UMAC_CMD_OPCODE_HW_TEST_WRAPPER 0xFC +#define UMAC_CMD_OPCODE_WIFI_IF_WRAPPER 0xFD +#define UMAC_CMD_OPCODE_WIFI_WRAPPER 0xFE +#define UMAC_CMD_OPCODE_WIFI_PASS_THROUGH 0xFF + +/* UMAC WiFi interface op-codes */ +#define UMAC_WIFI_IF_CMD_SET_PROFILE 0x11 +#define UMAC_WIFI_IF_CMD_INVALIDATE_PROFILE 0x12 +#define UMAC_WIFI_IF_CMD_SET_EXCLUDE_LIST 0x13 +#define UMAC_WIFI_IF_CMD_SCAN_REQUEST 0x14 +#define UMAC_WIFI_IF_CMD_SCAN_CONFIG 0x15 +#define UMAC_WIFI_IF_CMD_ADD_WEP40_KEY 0x16 +#define UMAC_WIFI_IF_CMD_ADD_WEP104_KEY 0x17 +#define UMAC_WIFI_IF_CMD_ADD_TKIP_KEY 0x18 +#define UMAC_WIFI_IF_CMD_ADD_CCMP_KEY 0x19 +#define UMAC_WIFI_IF_CMD_REMOVE_KEY 0x1A +#define UMAC_WIFI_IF_CMD_GLOBAL_TX_KEY_ID 0x1B +#define UMAC_WIFI_IF_CMD_SET_HOST_EXTENDED_IE 0x1C +#define UMAC_WIFI_IF_CMD_GET_SUPPORTED_CHANNELS 0x1E +#define UMAC_WIFI_IF_CMD_TX_PWR_TRIGGER 0x20 + +/* UMAC WiFi interface ports */ +#define UMAC_WIFI_IF_FLG_PORT_DEF 0x00 +#define UMAC_WIFI_IF_FLG_PORT_PAN 0x01 +#define UMAC_WIFI_IF_FLG_PORT_PAN_INVALID WIFI_IF_FLG_PORT_DEF + +/* UMAC WiFi interface actions */ +#define UMAC_WIFI_IF_FLG_ACT_GET 0x10 +#define UMAC_WIFI_IF_FLG_ACT_SET 0x20 + +/* iwm_umac_fw_cmd_hdr.meta_data byte count -- bits [11:0] */ +#define UMAC_FW_CMD_BYTE_COUNT_POS 0 +#define UMAC_FW_CMD_BYTE_COUNT_SEED 0xFFF + +/* iwm_umac_fw_cmd_hdr.meta_data status -- bits [15:12] */ +#define UMAC_FW_CMD_STATUS_POS 12 +#define UMAC_FW_CMD_STATUS_SEED 0xF + +/* iwm_umac_fw_cmd_hdr.meta_data full TX command by Driver -- bits [16:16] */ +#define UMAC_FW_CMD_TX_DRV_FULL_CMD_POS 16 +#define UMAC_FW_CMD_TX_DRV_FULL_CMD_SEED 0x1 + +/* iwm_umac_fw_cmd_hdr.meta_data TX command by FW -- bits [17:17] */ +#define UMAC_FW_CMD_TX_FW_CMD_POS 17 +#define UMAC_FW_CMD_TX_FW_CMD_SEED 0x1 + +/* iwm_umac_fw_cmd_hdr.meta_data TX plaintext mode -- bits [18:18] */ +#define UMAC_FW_CMD_TX_PLAINTEXT_POS 18 +#define UMAC_FW_CMD_TX_PLAINTEXT_SEED 0x1 + +/* iwm_umac_fw_cmd_hdr.meta_data STA color -- bits [22:20] */ +#define UMAC_FW_CMD_TX_STA_COLOR_POS 20 +#define UMAC_FW_CMD_TX_STA_COLOR_SEED 0x7 + +/* iwm_umac_fw_cmd_hdr.meta_data TX life time (TU) -- bits [31:24] */ +#define UMAC_FW_CMD_TX_LIFETIME_TU_POS 24 +#define UMAC_FW_CMD_TX_LIFETIME_TU_SEED 0xFF + +/* iwm_dev_cmd_hdr.flags Response required -- bits [5:5] */ +#define UMAC_DEV_CMD_FLAGS_RESP_REQ_POS 5 +#define UMAC_DEV_CMD_FLAGS_RESP_REQ_SEED 0x1 + +/* iwm_dev_cmd_hdr.flags Aborted command -- bits [6:6] */ +#define UMAC_DEV_CMD_FLAGS_ABORT_POS 6 +#define UMAC_DEV_CMD_FLAGS_ABORT_SEED 0x1 + +/* iwm_dev_cmd_hdr.flags Internal command -- bits [7:7] */ +#define DEV_CMD_FLAGS_FLD_INTERNAL_POS 7 +#define DEV_CMD_FLAGS_FLD_INTERNAL_SEED 0x1 + +/* Rx */ +/* Rx actions */ +#define IWM_RX_TICKET_DROP 0x0 +#define IWM_RX_TICKET_RELEASE 0x1 +#define IWM_RX_TICKET_SNIFFER 0x2 +#define IWM_RX_TICKET_ENQUEUE 0x3 + +/* Rx flags */ +#define IWM_RX_TICKET_PAD_SIZE_MSK 0x2 +#define IWM_RX_TICKET_SPECIAL_SNAP_MSK 0x4 +#define IWM_RX_TICKET_AMSDU_MSK 0x8 +#define IWM_RX_TICKET_DROP_REASON_POS 4 +#define IWM_RX_TICKET_DROP_REASON_MSK (0x1F << RX_TICKET_FLAGS_DROP_REASON_POS) + +#define IWM_RX_DROP_NO_DROP 0x0 +#define IWM_RX_DROP_BAD_CRC 0x1 +/* L2P no address match */ +#define IWM_RX_DROP_LMAC_ADDR_FILTER 0x2 +/* Multicast address not in list */ +#define IWM_RX_DROP_MCAST_ADDR_FILTER 0x3 +/* Control frames are not sent to the driver */ +#define IWM_RX_DROP_CTL_FRAME 0x4 +/* Our frame is back */ +#define IWM_RX_DROP_OUR_TX 0x5 +/* Association class filtering */ +#define IWM_RX_DROP_CLASS_FILTER 0x6 +/* Duplicated frame */ +#define IWM_RX_DROP_DUPLICATE_FILTER 0x7 +/* Decryption error */ +#define IWM_RX_DROP_SEC_ERR 0x8 +/* Unencrypted frame while encryption is on */ +#define IWM_RX_DROP_SEC_NO_ENCRYPTION 0x9 +/* Replay check failure */ +#define IWM_RX_DROP_SEC_REPLAY_ERR 0xa +/* uCode and FW key color mismatch, check before replay */ +#define IWM_RX_DROP_SEC_KEY_COLOR_MISMATCH 0xb +#define IWM_RX_DROP_SEC_TKIP_COUNTER_MEASURE 0xc +/* No fragmentations Db is found */ +#define IWM_RX_DROP_FRAG_NO_RESOURCE 0xd +/* Fragmention Db has seqCtl mismatch Vs. non-1st frag */ +#define IWM_RX_DROP_FRAG_ERR 0xe +#define IWM_RX_DROP_FRAG_LOST 0xf +#define IWM_RX_DROP_FRAG_COMPLETE 0x10 +/* Should be handled by UMAC */ +#define IWM_RX_DROP_MANAGEMENT 0x11 +/* STA not found by UMAC */ +#define IWM_RX_DROP_NO_STATION 0x12 +/* NULL or QoS NULL */ +#define IWM_RX_DROP_NULL_DATA 0x13 +#define IWM_RX_DROP_BA_REORDER_OLD_SEQCTL 0x14 +#define IWM_RX_DROP_BA_REORDER_DUPLICATE 0x15 + +struct iwm_rx_ticket { + __le16 action; + __le16 id; + __le16 flags; + u8 payload_offset; /* includes: MAC header, pad, IV */ + u8 tail_len; /* includes: MIC, ICV, CRC (w/o STATUS) */ +} __attribute__ ((packed)); + +struct iwm_rx_mpdu_hdr { + __le16 len; + __le16 reserved; +} __attribute__ ((packed)); + +/* UMAC SW WIFI API */ + +struct iwm_dev_cmd_hdr { + u8 cmd; + u8 flags; + __le16 seq_num; +} __attribute__ ((packed)); + +struct iwm_umac_fw_cmd_hdr { + __le32 meta_data; + struct iwm_dev_cmd_hdr cmd; +} __attribute__ ((packed)); + +struct iwm_umac_wifi_out_hdr { + struct iwm_udma_out_wifi_hdr hw_hdr; + struct iwm_umac_fw_cmd_hdr sw_hdr; +} __attribute__ ((packed)); + +struct iwm_umac_nonwifi_out_hdr { + struct iwm_udma_out_nonwifi_hdr hw_hdr; +} __attribute__ ((packed)); + +struct iwm_umac_wifi_in_hdr { + struct iwm_udma_in_hdr hw_hdr; + struct iwm_umac_fw_cmd_hdr sw_hdr; +} __attribute__ ((packed)); + +struct iwm_umac_nonwifi_in_hdr { + struct iwm_udma_in_hdr hw_hdr; + __le32 time_stamp; +} __attribute__ ((packed)); + +#define IWM_UMAC_PAGE_SIZE 0x200 + +/* Notify structures */ +struct iwm_fw_version { + u8 minor; + u8 major; + __le16 id; +}; + +struct iwm_fw_build { + u8 type; + u8 subtype; + u8 platform; + u8 opt; +}; + +struct iwm_fw_alive_hdr { + struct iwm_fw_version ver; + struct iwm_fw_build build; + __le32 os_build; + __le32 log_hdr_addr; + __le32 log_buf_addr; + __le32 sys_timer_addr; +}; + +#define WAIT_NOTIF_TIMEOUT (2 * HZ) +#define SCAN_COMPLETE_TIMEOUT (3 * HZ) + +#define UMAC_NTFY_ALIVE_STATUS_ERR 0xDEAD +#define UMAC_NTFY_ALIVE_STATUS_OK 0xCAFE + +#define UMAC_NTFY_INIT_COMPLETE_STATUS_ERR 0xDEAD +#define UMAC_NTFY_INIT_COMPLETE_STATUS_OK 0xCAFE + +#define UMAC_NTFY_WIFI_CORE_STATUS_LINK_EN 0x40 +#define UMAC_NTFY_WIFI_CORE_STATUS_MLME_EN 0x80 + +#define IWM_MACS_OUT_GROUPS 6 +#define IWM_MACS_OUT_SGROUPS 1 + + +#define WIFI_IF_NTFY_ASSOC_START 0x80 +#define WIFI_IF_NTFY_ASSOC_COMPLETE 0x81 +#define WIFI_IF_NTFY_PROFILE_INVALIDATE_COMPLETE 0x82 +#define WIFI_IF_NTFY_CONNECTION_TERMINATED 0x83 +#define WIFI_IF_NTFY_SCAN_COMPLETE 0x84 +#define WIFI_IF_NTFY_STA_TABLE_CHANGE 0x85 +#define WIFI_IF_NTFY_EXTENDED_IE_REQUIRED 0x86 +#define WIFI_IF_NTFY_RADIO_PREEMPTION 0x87 +#define WIFI_IF_NTFY_BSS_TRK_TABLE_CHANGED 0x88 +#define WIFI_IF_NTFY_BSS_TRK_ENTRIES_REMOVED 0x89 +#define WIFI_IF_NTFY_LINK_QUALITY_STATISTICS 0x8A +#define WIFI_IF_NTFY_MGMT_FRAME 0x8B + +/* DEBUG INDICATIONS */ +#define WIFI_DBG_IF_NTFY_SCAN_SUPER_JOB_START 0xE0 +#define WIFI_DBG_IF_NTFY_SCAN_SUPER_JOB_COMPLETE 0xE1 +#define WIFI_DBG_IF_NTFY_SCAN_CHANNEL_START 0xE2 +#define WIFI_DBG_IF_NTFY_SCAN_CHANNEL_RESULT 0xE3 +#define WIFI_DBG_IF_NTFY_SCAN_MINI_JOB_START 0xE4 +#define WIFI_DBG_IF_NTFY_SCAN_MINI_JOB_COMPLETE 0xE5 +#define WIFI_DBG_IF_NTFY_CNCT_ATC_START 0xE6 +#define WIFI_DBG_IF_NTFY_COEX_NOTIFICATION 0xE7 +#define WIFI_DBG_IF_NTFY_COEX_HANDLE_ENVELOP 0xE8 +#define WIFI_DBG_IF_NTFY_COEX_HANDLE_RELEASE_ENVELOP 0xE9 + +/* Notification structures */ +struct iwm_umac_notif_wifi_if { + struct iwm_umac_wifi_in_hdr hdr; + u8 status; + u8 flags; + __le16 buf_size; +} __attribute__ ((packed)); + +#define UMAC_ROAM_REASON_FIRST_SELECTION 0x1 +#define UMAC_ROAM_REASON_AP_DEAUTH 0x2 +#define UMAC_ROAM_REASON_AP_CONNECT_LOST 0x3 +#define UMAC_ROAM_REASON_RSSI 0x4 +#define UMAC_ROAM_REASON_AP_ASSISTED_ROAM 0x5 +#define UMAC_ROAM_REASON_IBSS_COALESCING 0x6 + +struct iwm_umac_notif_assoc_start { + struct iwm_umac_notif_wifi_if mlme_hdr; + __le32 roam_reason; + u8 bssid[ETH_ALEN]; + u8 reserved[2]; +} __attribute__ ((packed)); + +#define UMAC_ASSOC_COMPLETE_SUCCESS 0x0 +#define UMAC_ASSOC_COMPLETE_FAILURE 0x1 + +struct iwm_umac_notif_assoc_complete { + struct iwm_umac_notif_wifi_if mlme_hdr; + __le32 status; + u8 bssid[ETH_ALEN]; + u8 band; + u8 channel; +} __attribute__ ((packed)); + +#define UMAC_PROFILE_INVALID_ASSOC_TIMEOUT 0x0 +#define UMAC_PROFILE_INVALID_ROAM_TIMEOUT 0x1 +#define UMAC_PROFILE_INVALID_REQUEST 0x2 +#define UMAC_PROFILE_INVALID_RF_PREEMPTED 0x3 + +struct iwm_umac_notif_profile_invalidate { + struct iwm_umac_notif_wifi_if mlme_hdr; + __le32 reason; +} __attribute__ ((packed)); + +#define UMAC_SCAN_RESULT_SUCCESS 0x0 +#define UMAC_SCAN_RESULT_ABORTED 0x1 +#define UMAC_SCAN_RESULT_REJECTED 0x2 +#define UMAC_SCAN_RESULT_FAILED 0x3 + +struct iwm_umac_notif_scan_complete { + struct iwm_umac_notif_wifi_if mlme_hdr; + __le32 type; + __le32 result; + u8 seq_num; +} __attribute__ ((packed)); + +#define UMAC_OPCODE_ADD_MODIFY 0x0 +#define UMAC_OPCODE_REMOVE 0x1 +#define UMAC_OPCODE_CLEAR_ALL 0x2 + +#define UMAC_STA_FLAG_QOS 0x1 + +struct iwm_umac_notif_sta_info { + struct iwm_umac_notif_wifi_if mlme_hdr; + __le32 opcode; + u8 mac_addr[ETH_ALEN]; + u8 sta_id; /* bits 0-3: station ID, bits 4-7: station color */ + u8 flags; +} __attribute__ ((packed)); + +#define UMAC_BAND_2GHZ 0 +#define UMAC_BAND_5GHZ 1 + +#define UMAC_CHANNEL_WIDTH_20MHZ 0 +#define UMAC_CHANNEL_WIDTH_40MHZ 1 + +struct iwm_umac_notif_bss_info { + struct iwm_umac_notif_wifi_if mlme_hdr; + __le32 type; + __le32 timestamp; + __le16 table_idx; + __le16 frame_len; + u8 band; + u8 channel; + s8 rssi; + u8 reserved; + u8 frame_buf[1]; +} __attribute__ ((packed)); + +#define IWM_BSS_REMOVE_INDEX_MSK 0x0fff +#define IWM_BSS_REMOVE_FLAGS_MSK 0xfc00 + +#define IWM_BSS_REMOVE_FLG_AGE 0x1000 +#define IWM_BSS_REMOVE_FLG_TIMEOUT 0x2000 +#define IWM_BSS_REMOVE_FLG_TABLE_FULL 0x4000 + +struct iwm_umac_notif_bss_removed { + struct iwm_umac_notif_wifi_if mlme_hdr; + __le32 count; + __le16 entries[0]; +} __attribute__ ((packed)); + +struct iwm_umac_notif_mgt_frame { + struct iwm_umac_notif_wifi_if mlme_hdr; + __le16 len; + u8 frame[1]; +} __attribute__ ((packed)); + +struct iwm_umac_notif_alive { + struct iwm_umac_wifi_in_hdr hdr; + __le16 status; + __le16 reserved1; + struct iwm_fw_alive_hdr alive_data; + __le16 reserved2; + __le16 page_grp_count; + __le32 page_grp_state[IWM_MACS_OUT_GROUPS]; +} __attribute__ ((packed)); + +struct iwm_umac_notif_init_complete { + __le16 status; + __le16 reserved; +} __attribute__ ((packed)); + +/* error categories */ +enum { + UMAC_SYS_ERR_CAT_NONE = 0, + UMAC_SYS_ERR_CAT_BOOT, + UMAC_SYS_ERR_CAT_UMAC, + UMAC_SYS_ERR_CAT_UAXM, + UMAC_SYS_ERR_CAT_LMAC, + UMAC_SYS_ERR_CAT_MAX +}; + +struct iwm_fw_error_hdr { + __le32 category; + __le32 status; + __le32 pc; + __le32 blink1; + __le32 blink2; + __le32 ilink1; + __le32 ilink2; + __le32 data1; + __le32 data2; + __le32 line_num; + __le32 umac_status; + __le32 lmac_status; + __le32 sdio_status; +} __attribute__ ((packed)); + +struct iwm_umac_notif_error { + struct iwm_umac_wifi_in_hdr hdr; + struct iwm_fw_error_hdr err; +} __attribute__ ((packed)); + +#define UMAC_DEALLOC_NTFY_CHANGES_CNT_POS 0 +#define UMAC_DEALLOC_NTFY_CHANGES_CNT_SEED 0xff +#define UMAC_DEALLOC_NTFY_CHANGES_MSK_POS 8 +#define UMAC_DEALLOC_NTFY_CHANGES_MSK_SEED 0xffffff +#define UMAC_DEALLOC_NTFY_PAGE_CNT_POS 0 +#define UMAC_DEALLOC_NTFY_PAGE_CNT_SEED 0xffffff +#define UMAC_DEALLOC_NTFY_GROUP_NUM_POS 24 +#define UMAC_DEALLOC_NTFY_GROUP_NUM_SEED 0xf + +struct iwm_umac_notif_page_dealloc { + struct iwm_umac_wifi_in_hdr hdr; + __le32 changes; + __le32 grp_info[IWM_MACS_OUT_GROUPS]; +} __attribute__ ((packed)); + +struct iwm_umac_notif_wifi_status { + struct iwm_umac_wifi_in_hdr hdr; + __le16 status; + __le16 reserved; +} __attribute__ ((packed)); + +struct iwm_umac_notif_rx_ticket { + struct iwm_umac_wifi_in_hdr hdr; + u8 num_tickets; + u8 reserved[3]; + struct iwm_rx_ticket tickets[1]; +} __attribute__ ((packed)); + +/* Tx/Rx rates window (number of max of last update window per second) */ +#define UMAC_NTF_RATE_SAMPLE_NR 4 + +#define IWM_UMAC_MGMT_TID 8 +#define IWM_UMAC_TID_NR 8 + +struct iwm_umac_notif_stats { + struct iwm_umac_wifi_in_hdr hdr; + __le32 flags; + __le32 timestamp; + __le16 tid_load[IWM_UMAC_TID_NR + 2]; /* 1 non-QoS + 1 dword align */ + __le16 tx_rate[UMAC_NTF_RATE_SAMPLE_NR]; + __le16 rx_rate[UMAC_NTF_RATE_SAMPLE_NR]; + s32 rssi_dbm; + s32 noise_dbm; + __le32 supp_rates; + __le32 missed_beacons; + __le32 rx_beacons; + __le32 rx_dir_pkts; + __le32 rx_nondir_pkts; + __le32 rx_multicast; + __le32 rx_errors; + __le32 rx_drop_other_bssid; + __le32 rx_drop_decode; + __le32 rx_drop_reassembly; + __le32 rx_drop_bad_len; + __le32 rx_drop_overflow; + __le32 rx_drop_crc; + __le32 rx_drop_missed; + __le32 tx_dir_pkts; + __le32 tx_nondir_pkts; + __le32 tx_failure; + __le32 tx_errors; + __le32 tx_drop_max_retry; + __le32 tx_err_abort; + __le32 tx_err_carrier; + __le32 rx_bytes; + __le32 tx_bytes; + __le32 tx_power; + __le32 tx_max_power; + __le32 roam_threshold; + __le32 ap_assoc_nr; + __le32 scan_full; + __le32 scan_abort; + __le32 ap_nr; + __le32 roam_nr; + __le32 roam_missed_beacons; + __le32 roam_rssi; + __le32 roam_unassoc; + __le32 roam_deauth; + __le32 roam_ap_loadblance; +} __attribute__ ((packed)); + +/* WiFi interface wrapper header */ +struct iwm_umac_wifi_if { + u8 oid; + u8 flags; + __le16 buf_size; +} __attribute__ ((packed)); + +#define IWM_SEQ_NUM_HOST_MSK 0x0000 +#define IWM_SEQ_NUM_UMAC_MSK 0x4000 +#define IWM_SEQ_NUM_LMAC_MSK 0x8000 +#define IWM_SEQ_NUM_MSK 0xC000 + +#endif diff --git a/drivers/net/wireless/iwmc3200wifi/wext.c b/drivers/net/wireless/iwmc3200wifi/wext.c new file mode 100644 index 000000000000..584c94d0f399 --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/wext.c @@ -0,0 +1,723 @@ +/* + * Intel Wireless Multicomm 3200 WiFi driver + * + * Copyright (C) 2009 Intel Corporation + * Samuel Ortiz + * Zhu Yi + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "iwm.h" +#include "umac.h" +#include "commands.h" +#include "debug.h" + +static struct iw_statistics *iwm_get_wireless_stats(struct net_device *dev) +{ + struct iwm_priv *iwm = ndev_to_iwm(dev); + struct iw_statistics *wstats = &iwm->wstats; + + if (!test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) { + memset(wstats, 0, sizeof(struct iw_statistics)); + wstats->qual.updated = IW_QUAL_ALL_INVALID; + } + + return wstats; +} + +static int iwm_wext_siwfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *freq, char *extra) +{ + struct iwm_priv *iwm = ndev_to_iwm(dev); + + if (freq->flags == IW_FREQ_AUTO) + return 0; + + /* frequency/channel can only be set in IBSS mode */ + if (iwm->conf.mode != UMAC_MODE_IBSS) + return -EOPNOTSUPP; + + return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra); +} + +static int iwm_wext_giwfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *freq, char *extra) +{ + struct iwm_priv *iwm = ndev_to_iwm(dev); + + if (iwm->conf.mode == UMAC_MODE_IBSS) + return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra); + + freq->e = 0; + freq->m = iwm->channel; + + return 0; +} + +static int iwm_wext_siwap(struct net_device *dev, struct iw_request_info *info, + struct sockaddr *ap_addr, char *extra) +{ + struct iwm_priv *iwm = ndev_to_iwm(dev); + + if (iwm->conf.mode == UMAC_MODE_IBSS) + return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra); + + if (!test_bit(IWM_STATUS_READY, &iwm->status)) + return -EIO; + + if (is_zero_ether_addr(ap_addr->sa_data) || + is_broadcast_ether_addr(ap_addr->sa_data)) { + IWM_DBG_WEXT(iwm, DBG, "clear mandatory bssid %pM\n", + iwm->umac_profile->bssid[0]); + memset(&iwm->umac_profile->bssid[0], 0, ETH_ALEN); + iwm->umac_profile->bss_num = 0; + } else { + IWM_DBG_WEXT(iwm, DBG, "add mandatory bssid %pM\n", + ap_addr->sa_data); + memcpy(&iwm->umac_profile->bssid[0], ap_addr->sa_data, + ETH_ALEN); + iwm->umac_profile->bss_num = 1; + } + + if (iwm->umac_profile_active) { + if (!memcmp(&iwm->umac_profile->bssid[0], iwm->bssid, ETH_ALEN)) + return 0; + + iwm_invalidate_mlme_profile(iwm); + } + + if (iwm->umac_profile->ssid.ssid_len) + return iwm_send_mlme_profile(iwm); + + return 0; +} + +static int iwm_wext_giwap(struct net_device *dev, struct iw_request_info *info, + struct sockaddr *ap_addr, char *extra) +{ + struct iwm_priv *iwm = ndev_to_iwm(dev); + + switch (iwm->conf.mode) { + case UMAC_MODE_IBSS: + return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra); + case UMAC_MODE_BSS: + if (test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) { + ap_addr->sa_family = ARPHRD_ETHER; + memcpy(&ap_addr->sa_data, iwm->bssid, ETH_ALEN); + } else + memset(&ap_addr->sa_data, 0, ETH_ALEN); + break; + default: + return -EOPNOTSUPP; + } + + return 0; +} + +static int iwm_wext_siwessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *ssid) +{ + struct iwm_priv *iwm = ndev_to_iwm(dev); + size_t len = data->length; + int ret; + + if (iwm->conf.mode == UMAC_MODE_IBSS) + return cfg80211_ibss_wext_siwessid(dev, info, data, ssid); + + if (!test_bit(IWM_STATUS_READY, &iwm->status)) + return -EIO; + + if (len > 0 && ssid[len - 1] == '\0') + len--; + + if (iwm->umac_profile_active) { + if (iwm->umac_profile->ssid.ssid_len == len && + !memcmp(iwm->umac_profile->ssid.ssid, ssid, len)) + return 0; + + ret = iwm_invalidate_mlme_profile(iwm); + if (ret < 0) { + IWM_ERR(iwm, "Couldn't invalidate profile\n"); + return ret; + } + } + + iwm->umac_profile->ssid.ssid_len = len; + memcpy(iwm->umac_profile->ssid.ssid, ssid, len); + + return iwm_send_mlme_profile(iwm); +} + +static int iwm_wext_giwessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *ssid) +{ + struct iwm_priv *iwm = ndev_to_iwm(dev); + + if (iwm->conf.mode == UMAC_MODE_IBSS) + return cfg80211_ibss_wext_giwessid(dev, info, data, ssid); + + if (!test_bit(IWM_STATUS_READY, &iwm->status)) + return -EIO; + + data->length = iwm->umac_profile->ssid.ssid_len; + if (data->length) { + memcpy(ssid, iwm->umac_profile->ssid.ssid, data->length); + data->flags = 1; + } else + data->flags = 0; + + return 0; +} + +static struct iwm_key * +iwm_key_init(struct iwm_priv *iwm, u8 key_idx, bool in_use, + struct iw_encode_ext *ext, u8 alg) +{ + struct iwm_key *key = &iwm->keys[key_idx]; + + memset(key, 0, sizeof(struct iwm_key)); + memcpy(key->hdr.mac, ext->addr.sa_data, ETH_ALEN); + key->hdr.key_idx = key_idx; + if (is_broadcast_ether_addr(ext->addr.sa_data)) + key->hdr.multicast = 1; + + key->in_use = in_use; + key->flags = ext->ext_flags; + key->alg = alg; + key->key_len = ext->key_len; + memcpy(key->key, ext->key, ext->key_len); + + return key; +} + +static int iwm_wext_giwrate(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rate, char *extra) +{ + struct iwm_priv *iwm = ndev_to_iwm(dev); + + rate->value = iwm->rate * 1000000; + + return 0; +} + +static int iwm_wext_siwencode(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *erq, char *key_buf) +{ + struct iwm_priv *iwm = ndev_to_iwm(dev); + struct iwm_key *uninitialized_var(key); + int idx, i, uninitialized_var(alg), remove = 0, ret; + + IWM_DBG_WEXT(iwm, DBG, "key len: %d\n", erq->length); + IWM_DBG_WEXT(iwm, DBG, "flags: 0x%x\n", erq->flags); + + if (!iwm->umac_profile) { + IWM_ERR(iwm, "UMAC profile not allocated yet\n"); + return -ENODEV; + } + + if (erq->length == WLAN_KEY_LEN_WEP40) { + alg = UMAC_CIPHER_TYPE_WEP_40; + iwm->umac_profile->sec.ucast_cipher = UMAC_CIPHER_TYPE_WEP_40; + iwm->umac_profile->sec.mcast_cipher = UMAC_CIPHER_TYPE_WEP_40; + } else if (erq->length == WLAN_KEY_LEN_WEP104) { + alg = UMAC_CIPHER_TYPE_WEP_104; + iwm->umac_profile->sec.ucast_cipher = UMAC_CIPHER_TYPE_WEP_104; + iwm->umac_profile->sec.mcast_cipher = UMAC_CIPHER_TYPE_WEP_104; + } + + if (erq->flags & IW_ENCODE_RESTRICTED) + iwm->umac_profile->sec.auth_type = UMAC_AUTH_TYPE_LEGACY_PSK; + else + iwm->umac_profile->sec.auth_type = UMAC_AUTH_TYPE_OPEN; + + idx = erq->flags & IW_ENCODE_INDEX; + if (idx == 0) { + if (iwm->default_key) + for (i = 0; i < IWM_NUM_KEYS; i++) { + if (iwm->default_key == &iwm->keys[i]) { + idx = i; + break; + } + } + else + iwm->default_key = &iwm->keys[idx]; + } else if (idx < 1 || idx > 4) { + return -EINVAL; + } else + idx--; + + if (erq->flags & IW_ENCODE_DISABLED) + remove = 1; + else if (erq->length == 0) { + if (!iwm->keys[idx].in_use) + return -EINVAL; + iwm->default_key = &iwm->keys[idx]; + } + + if (erq->length) { + key = &iwm->keys[idx]; + memset(key, 0, sizeof(struct iwm_key)); + memset(key->hdr.mac, 0xff, ETH_ALEN); + key->hdr.key_idx = idx; + key->hdr.multicast = 1; + key->in_use = !remove; + key->alg = alg; + key->key_len = erq->length; + memcpy(key->key, key_buf, erq->length); + + IWM_DBG_WEXT(iwm, DBG, "Setting key %d, default: %d\n", + idx, !!iwm->default_key); + } + + if (remove) { + if ((erq->flags & IW_ENCODE_NOKEY) || (erq->length == 0)) { + int j; + for (j = 0; j < IWM_NUM_KEYS; j++) + if (iwm->keys[j].in_use) { + struct iwm_key *k = &iwm->keys[j]; + + k->in_use = 0; + ret = iwm_set_key(iwm, remove, 0, k); + if (ret < 0) + return ret; + } + + iwm->umac_profile->sec.ucast_cipher = + UMAC_CIPHER_TYPE_NONE; + iwm->umac_profile->sec.mcast_cipher = + UMAC_CIPHER_TYPE_NONE; + iwm->umac_profile->sec.auth_type = + UMAC_AUTH_TYPE_OPEN; + + return 0; + } else { + key->in_use = 0; + return iwm_set_key(iwm, remove, 0, key); + } + } + + /* + * If we havent set a profile yet, we cant set keys. + * Keys will be pushed after we're associated. + */ + if (!iwm->umac_profile_active) + return 0; + + /* + * If there is a current active profile, but no + * default key, it's not worth trying to associate again. + */ + if (!iwm->default_key) + return 0; + + /* + * Here we have an active profile, but a key setting changed. + * We thus have to invalidate the current profile, and push the + * new one. Keys will be pushed when association takes place. + */ + ret = iwm_invalidate_mlme_profile(iwm); + if (ret < 0) { + IWM_ERR(iwm, "Couldn't invalidate profile\n"); + return ret; + } + + return iwm_send_mlme_profile(iwm); +} + +static int iwm_wext_giwencode(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *erq, char *key) +{ + struct iwm_priv *iwm = ndev_to_iwm(dev); + int idx, i; + + idx = erq->flags & IW_ENCODE_INDEX; + if (idx < 1 || idx > 4) { + idx = -1; + if (!iwm->default_key) { + erq->length = 0; + erq->flags |= IW_ENCODE_NOKEY; + return 0; + } else + for (i = 0; i < IWM_NUM_KEYS; i++) { + if (iwm->default_key == &iwm->keys[i]) { + idx = i; + break; + } + } + if (idx < 0) + return -EINVAL; + } else + idx--; + + erq->flags = idx + 1; + + if (!iwm->keys[idx].in_use) { + erq->length = 0; + erq->flags |= IW_ENCODE_DISABLED; + return 0; + } + + memcpy(key, iwm->keys[idx].key, + min_t(int, erq->length, iwm->keys[idx].key_len)); + erq->length = iwm->keys[idx].key_len; + erq->flags |= IW_ENCODE_ENABLED; + + if (iwm->umac_profile->mode == UMAC_MODE_BSS) { + switch (iwm->umac_profile->sec.auth_type) { + case UMAC_AUTH_TYPE_OPEN: + erq->flags |= IW_ENCODE_OPEN; + break; + default: + erq->flags |= IW_ENCODE_RESTRICTED; + break; + } + } + + return 0; +} + +static int iwm_set_wpa_version(struct iwm_priv *iwm, u8 wpa_version) +{ + if (wpa_version & IW_AUTH_WPA_VERSION_WPA2) + iwm->umac_profile->sec.flags = UMAC_SEC_FLG_RSNA_ON_MSK; + else if (wpa_version & IW_AUTH_WPA_VERSION_WPA) + iwm->umac_profile->sec.flags = UMAC_SEC_FLG_WPA_ON_MSK; + else + iwm->umac_profile->sec.flags = UMAC_SEC_FLG_LEGACY_PROFILE; + + return 0; +} + +static int iwm_wext_siwpower(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *wrq, char *extra) +{ + struct iwm_priv *iwm = ndev_to_iwm(dev); + u32 power_index; + + if (wrq->disabled) { + power_index = IWM_POWER_INDEX_MIN; + goto set; + } else + power_index = IWM_POWER_INDEX_DEFAULT; + + switch (wrq->flags & IW_POWER_MODE) { + case IW_POWER_ON: + case IW_POWER_MODE: + case IW_POWER_ALL_R: + break; + default: + return -EINVAL; + } + + set: + if (power_index == iwm->conf.power_index) + return 0; + + iwm->conf.power_index = power_index; + + return iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, + CFG_POWER_INDEX, iwm->conf.power_index); +} + +static int iwm_wext_giwpower(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct iwm_priv *iwm = ndev_to_iwm(dev); + + wrqu->power.disabled = (iwm->conf.power_index == IWM_POWER_INDEX_MIN); + + return 0; +} + +static int iwm_set_key_mgt(struct iwm_priv *iwm, u8 key_mgt) +{ + u8 *auth_type = &iwm->umac_profile->sec.auth_type; + + if (key_mgt == IW_AUTH_KEY_MGMT_802_1X) + *auth_type = UMAC_AUTH_TYPE_8021X; + else if (key_mgt == IW_AUTH_KEY_MGMT_PSK) { + if (iwm->umac_profile->sec.flags & + (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) + *auth_type = UMAC_AUTH_TYPE_RSNA_PSK; + else + *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK; + } else { + IWM_ERR(iwm, "Invalid key mgt: 0x%x\n", key_mgt); + return -EINVAL; + } + + return 0; +} + +static int iwm_set_cipher(struct iwm_priv *iwm, u8 cipher, u8 ucast) +{ + u8 *profile_cipher = ucast ? &iwm->umac_profile->sec.ucast_cipher : + &iwm->umac_profile->sec.mcast_cipher; + + switch (cipher) { + case IW_AUTH_CIPHER_NONE: + *profile_cipher = UMAC_CIPHER_TYPE_NONE; + break; + case IW_AUTH_CIPHER_WEP40: + *profile_cipher = UMAC_CIPHER_TYPE_WEP_40; + break; + case IW_AUTH_CIPHER_TKIP: + *profile_cipher = UMAC_CIPHER_TYPE_TKIP; + break; + case IW_AUTH_CIPHER_CCMP: + *profile_cipher = UMAC_CIPHER_TYPE_CCMP; + break; + case IW_AUTH_CIPHER_WEP104: + *profile_cipher = UMAC_CIPHER_TYPE_WEP_104; + break; + default: + IWM_ERR(iwm, "Unsupported cipher: 0x%x\n", cipher); + return -ENOTSUPP; + } + + return 0; +} + +static int iwm_set_auth_alg(struct iwm_priv *iwm, u8 auth_alg) +{ + u8 *auth_type = &iwm->umac_profile->sec.auth_type; + + switch (auth_alg) { + case IW_AUTH_ALG_OPEN_SYSTEM: + *auth_type = UMAC_AUTH_TYPE_OPEN; + break; + case IW_AUTH_ALG_SHARED_KEY: + if (iwm->umac_profile->sec.flags & + (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) { + if (*auth_type == UMAC_AUTH_TYPE_8021X) + return -EINVAL; + *auth_type = UMAC_AUTH_TYPE_RSNA_PSK; + } else { + *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK; + } + break; + case IW_AUTH_ALG_LEAP: + default: + IWM_ERR(iwm, "Unsupported auth alg: 0x%x\n", auth_alg); + return -ENOTSUPP; + } + + return 0; +} + +static int iwm_wext_siwauth(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *data, char *extra) +{ + struct iwm_priv *iwm = ndev_to_iwm(dev); + int ret; + + if ((data->flags) & + (IW_AUTH_WPA_VERSION | IW_AUTH_KEY_MGMT | + IW_AUTH_WPA_ENABLED | IW_AUTH_80211_AUTH_ALG)) { + /* We need to invalidate the current profile */ + if (iwm->umac_profile_active) { + ret = iwm_invalidate_mlme_profile(iwm); + if (ret < 0) { + IWM_ERR(iwm, "Couldn't invalidate profile\n"); + return ret; + } + } + } + + switch (data->flags & IW_AUTH_INDEX) { + case IW_AUTH_WPA_VERSION: + return iwm_set_wpa_version(iwm, data->value); + break; + case IW_AUTH_CIPHER_PAIRWISE: + return iwm_set_cipher(iwm, data->value, 1); + break; + case IW_AUTH_CIPHER_GROUP: + return iwm_set_cipher(iwm, data->value, 0); + break; + case IW_AUTH_KEY_MGMT: + return iwm_set_key_mgt(iwm, data->value); + break; + case IW_AUTH_80211_AUTH_ALG: + return iwm_set_auth_alg(iwm, data->value); + break; + default: + return -ENOTSUPP; + } + + return 0; +} + +static int iwm_wext_giwauth(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *data, char *extra) +{ + return 0; +} + +static int iwm_wext_siwencodeext(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *erq, char *extra) +{ + struct iwm_priv *iwm = ndev_to_iwm(dev); + struct iwm_key *key; + struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; + int uninitialized_var(alg), idx, i, remove = 0; + + IWM_DBG_WEXT(iwm, DBG, "alg: 0x%x\n", ext->alg); + IWM_DBG_WEXT(iwm, DBG, "key len: %d\n", ext->key_len); + IWM_DBG_WEXT(iwm, DBG, "ext_flags: 0x%x\n", ext->ext_flags); + IWM_DBG_WEXT(iwm, DBG, "flags: 0x%x\n", erq->flags); + IWM_DBG_WEXT(iwm, DBG, "length: 0x%x\n", erq->length); + + switch (ext->alg) { + case IW_ENCODE_ALG_NONE: + remove = 1; + break; + case IW_ENCODE_ALG_WEP: + if (ext->key_len == WLAN_KEY_LEN_WEP40) + alg = UMAC_CIPHER_TYPE_WEP_40; + else if (ext->key_len == WLAN_KEY_LEN_WEP104) + alg = UMAC_CIPHER_TYPE_WEP_104; + else { + IWM_ERR(iwm, "Invalid key length: %d\n", ext->key_len); + return -EINVAL; + } + + break; + case IW_ENCODE_ALG_TKIP: + alg = UMAC_CIPHER_TYPE_TKIP; + break; + case IW_ENCODE_ALG_CCMP: + alg = UMAC_CIPHER_TYPE_CCMP; + break; + default: + return -EOPNOTSUPP; + } + + idx = erq->flags & IW_ENCODE_INDEX; + + if (idx == 0) { + if (iwm->default_key) + for (i = 0; i < IWM_NUM_KEYS; i++) { + if (iwm->default_key == &iwm->keys[i]) { + idx = i; + break; + } + } + } else if (idx < 1 || idx > 4) { + return -EINVAL; + } else + idx--; + + if (erq->flags & IW_ENCODE_DISABLED) + remove = 1; + else if ((erq->length == 0) || + (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)) { + iwm->default_key = &iwm->keys[idx]; + if (iwm->umac_profile_active && ext->alg == IW_ENCODE_ALG_WEP) + return iwm_set_tx_key(iwm, idx); + } + + key = iwm_key_init(iwm, idx, !remove, ext, alg); + + return iwm_set_key(iwm, remove, !iwm->default_key, key); +} + +static const iw_handler iwm_handlers[] = +{ + (iw_handler) NULL, /* SIOCSIWCOMMIT */ + (iw_handler) cfg80211_wext_giwname, /* SIOCGIWNAME */ + (iw_handler) NULL, /* SIOCSIWNWID */ + (iw_handler) NULL, /* SIOCGIWNWID */ + (iw_handler) iwm_wext_siwfreq, /* SIOCSIWFREQ */ + (iw_handler) iwm_wext_giwfreq, /* SIOCGIWFREQ */ + (iw_handler) cfg80211_wext_siwmode, /* SIOCSIWMODE */ + (iw_handler) cfg80211_wext_giwmode, /* SIOCGIWMODE */ + (iw_handler) NULL, /* SIOCSIWSENS */ + (iw_handler) NULL, /* SIOCGIWSENS */ + (iw_handler) NULL /* not used */, /* SIOCSIWRANGE */ + (iw_handler) cfg80211_wext_giwrange, /* SIOCGIWRANGE */ + (iw_handler) NULL /* not used */, /* SIOCSIWPRIV */ + (iw_handler) NULL /* kernel code */, /* SIOCGIWPRIV */ + (iw_handler) NULL /* not used */, /* SIOCSIWSTATS */ + (iw_handler) NULL /* kernel code */, /* SIOCGIWSTATS */ + (iw_handler) NULL, /* SIOCSIWSPY */ + (iw_handler) NULL, /* SIOCGIWSPY */ + (iw_handler) NULL, /* SIOCSIWTHRSPY */ + (iw_handler) NULL, /* SIOCGIWTHRSPY */ + (iw_handler) iwm_wext_siwap, /* SIOCSIWAP */ + (iw_handler) iwm_wext_giwap, /* SIOCGIWAP */ + (iw_handler) NULL, /* SIOCSIWMLME */ + (iw_handler) NULL, /* SIOCGIWAPLIST */ + (iw_handler) cfg80211_wext_siwscan, /* SIOCSIWSCAN */ + (iw_handler) cfg80211_wext_giwscan, /* SIOCGIWSCAN */ + (iw_handler) iwm_wext_siwessid, /* SIOCSIWESSID */ + (iw_handler) iwm_wext_giwessid, /* SIOCGIWESSID */ + (iw_handler) NULL, /* SIOCSIWNICKN */ + (iw_handler) NULL, /* SIOCGIWNICKN */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* SIOCSIWRATE */ + (iw_handler) iwm_wext_giwrate, /* SIOCGIWRATE */ + (iw_handler) cfg80211_wext_siwrts, /* SIOCSIWRTS */ + (iw_handler) cfg80211_wext_giwrts, /* SIOCGIWRTS */ + (iw_handler) cfg80211_wext_siwfrag, /* SIOCSIWFRAG */ + (iw_handler) cfg80211_wext_giwfrag, /* SIOCGIWFRAG */ + (iw_handler) NULL, /* SIOCSIWTXPOW */ + (iw_handler) NULL, /* SIOCGIWTXPOW */ + (iw_handler) NULL, /* SIOCSIWRETRY */ + (iw_handler) NULL, /* SIOCGIWRETRY */ + (iw_handler) iwm_wext_siwencode, /* SIOCSIWENCODE */ + (iw_handler) iwm_wext_giwencode, /* SIOCGIWENCODE */ + (iw_handler) iwm_wext_siwpower, /* SIOCSIWPOWER */ + (iw_handler) iwm_wext_giwpower, /* SIOCGIWPOWER */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* SIOCSIWGENIE */ + (iw_handler) NULL, /* SIOCGIWGENIE */ + (iw_handler) iwm_wext_siwauth, /* SIOCSIWAUTH */ + (iw_handler) iwm_wext_giwauth, /* SIOCGIWAUTH */ + (iw_handler) iwm_wext_siwencodeext, /* SIOCSIWENCODEEXT */ + (iw_handler) NULL, /* SIOCGIWENCODEEXT */ + (iw_handler) NULL, /* SIOCSIWPMKSA */ + (iw_handler) NULL, /* -- hole -- */ +}; + +const struct iw_handler_def iwm_iw_handler_def = { + .num_standard = ARRAY_SIZE(iwm_handlers), + .standard = (iw_handler *) iwm_handlers, + .get_wireless_stats = iwm_get_wireless_stats, +}; + diff --git a/drivers/net/wireless/libertas/11d.c b/drivers/net/wireless/libertas/11d.c index 4bc46a60ae2f..9a5408e7d94a 100644 --- a/drivers/net/wireless/libertas/11d.c +++ b/drivers/net/wireless/libertas/11d.c @@ -207,7 +207,7 @@ static int generate_domain_info_11d(struct parsed_region_chan_11d lbs_deb_11d("nr_subband=%x\n", domaininfo->nr_subband); lbs_deb_hex(LBS_DEB_11D, "domaininfo", (char *)domaininfo, COUNTRY_CODE_LEN + 1 + - sizeof(struct ieeetypes_subbandset) * nr_subband); + sizeof(struct ieee_subbandset) * nr_subband); return 0; } @@ -302,11 +302,9 @@ done: * @param parsed_region_chan pointer to parsed_region_chan_11d * @return 0 */ -static int parse_domain_info_11d(struct ieeetypes_countryinfofullset* - countryinfo, +static int parse_domain_info_11d(struct ieee_ie_country_info_full_set *countryinfo, u8 band, - struct parsed_region_chan_11d * - parsed_region_chan) + struct parsed_region_chan_11d *parsed_region_chan) { u8 nr_subband, nrchan; u8 lastchan, firstchan; @@ -331,7 +329,7 @@ static int parse_domain_info_11d(struct ieeetypes_countryinfofullset* lbs_deb_hex(LBS_DEB_11D, "countryinfo", (u8 *) countryinfo, 30); if ((*(countryinfo->countrycode)) == 0 - || (countryinfo->len <= COUNTRY_CODE_LEN)) { + || (countryinfo->header.len <= COUNTRY_CODE_LEN)) { /* No region Info or Wrong region info: treat as No 11D info */ goto done; } @@ -349,8 +347,8 @@ static int parse_domain_info_11d(struct ieeetypes_countryinfofullset* memcpy(parsed_region_chan->countrycode, countryinfo->countrycode, COUNTRY_CODE_LEN); - nr_subband = (countryinfo->len - COUNTRY_CODE_LEN) / - sizeof(struct ieeetypes_subbandset); + nr_subband = (countryinfo->header.len - COUNTRY_CODE_LEN) / + sizeof(struct ieee_subbandset); for (j = 0, lastchan = 0; j < nr_subband; j++) { @@ -502,7 +500,7 @@ int lbs_cmd_802_11d_domain_info(struct lbs_private *priv, { struct cmd_ds_802_11d_domain_info *pdomaininfo = &cmd->params.domaininfo; - struct mrvlietypes_domainparamset *domain = &pdomaininfo->domain; + struct mrvl_ie_domain_param_set *domain = &pdomaininfo->domain; u8 nr_subband = priv->domainreg.nr_subband; lbs_deb_enter(LBS_DEB_11D); @@ -524,16 +522,16 @@ int lbs_cmd_802_11d_domain_info(struct lbs_private *priv, sizeof(domain->countrycode)); domain->header.len = - cpu_to_le16(nr_subband * sizeof(struct ieeetypes_subbandset) + + cpu_to_le16(nr_subband * sizeof(struct ieee_subbandset) + sizeof(domain->countrycode)); if (nr_subband) { memcpy(domain->subband, priv->domainreg.subband, - nr_subband * sizeof(struct ieeetypes_subbandset)); + nr_subband * sizeof(struct ieee_subbandset)); cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) + le16_to_cpu(domain->header.len) + - sizeof(struct mrvlietypesheader) + + sizeof(struct mrvl_ie_header) + S_DS_GEN); } else { cmd->size = @@ -556,7 +554,7 @@ done: int lbs_ret_802_11d_domain_info(struct cmd_ds_command *resp) { struct cmd_ds_802_11d_domain_info *domaininfo = &resp->params.domaininforesp; - struct mrvlietypes_domainparamset *domain = &domaininfo->domain; + struct mrvl_ie_domain_param_set *domain = &domaininfo->domain; u16 action = le16_to_cpu(domaininfo->action); s16 ret = 0; u8 nr_subband = 0; @@ -567,7 +565,7 @@ int lbs_ret_802_11d_domain_info(struct cmd_ds_command *resp) (int)le16_to_cpu(resp->size)); nr_subband = (le16_to_cpu(domain->header.len) - COUNTRY_CODE_LEN) / - sizeof(struct ieeetypes_subbandset); + sizeof(struct ieee_subbandset); lbs_deb_11d("domain info resp: nr_subband %d\n", nr_subband); diff --git a/drivers/net/wireless/libertas/11d.h b/drivers/net/wireless/libertas/11d.h index 4f4f47f0f878..fb75d3e321a0 100644 --- a/drivers/net/wireless/libertas/11d.h +++ b/drivers/net/wireless/libertas/11d.h @@ -20,35 +20,36 @@ struct cmd_ds_command; /** Data structure for Country IE*/ -struct ieeetypes_subbandset { +struct ieee_subbandset { u8 firstchan; u8 nrchan; u8 maxtxpwr; } __attribute__ ((packed)); -struct ieeetypes_countryinfoset { - u8 element_id; - u8 len; +struct ieee_ie_country_info_set { + struct ieee_ie_header header; + u8 countrycode[COUNTRY_CODE_LEN]; - struct ieeetypes_subbandset subband[1]; + struct ieee_subbandset subband[1]; }; -struct ieeetypes_countryinfofullset { - u8 element_id; - u8 len; +struct ieee_ie_country_info_full_set { + struct ieee_ie_header header; + u8 countrycode[COUNTRY_CODE_LEN]; - struct ieeetypes_subbandset subband[MRVDRV_MAX_SUBBAND_802_11D]; + struct ieee_subbandset subband[MRVDRV_MAX_SUBBAND_802_11D]; } __attribute__ ((packed)); -struct mrvlietypes_domainparamset { - struct mrvlietypesheader header; +struct mrvl_ie_domain_param_set { + struct mrvl_ie_header header; + u8 countrycode[COUNTRY_CODE_LEN]; - struct ieeetypes_subbandset subband[1]; + struct ieee_subbandset subband[1]; } __attribute__ ((packed)); struct cmd_ds_802_11d_domain_info { __le16 action; - struct mrvlietypes_domainparamset domain; + struct mrvl_ie_domain_param_set domain; } __attribute__ ((packed)); /** domain regulatory information */ @@ -57,7 +58,7 @@ struct lbs_802_11d_domain_reg { u8 countrycode[COUNTRY_CODE_LEN]; /** No. of subband*/ u8 nr_subband; - struct ieeetypes_subbandset subband[MRVDRV_MAX_SUBBAND_802_11D]; + struct ieee_subbandset subband[MRVDRV_MAX_SUBBAND_802_11D]; }; struct chan_power_11d { diff --git a/drivers/net/wireless/libertas/README b/drivers/net/wireless/libertas/README index d860fc375752..ab6a2d518af0 100644 --- a/drivers/net/wireless/libertas/README +++ b/drivers/net/wireless/libertas/README @@ -72,7 +72,7 @@ rdrf location that is to be read. This parameter must be specified in hexadecimal (its possible to preceed preceding the number with a "0x"). - Path: /debugfs/libertas_wireless/ethX/registers/ + Path: /sys/kernel/debug/libertas_wireless/ethX/registers/ Usage: echo "0xa123" > rdmac ; cat rdmac @@ -95,7 +95,7 @@ wrrf sleepparams This command is used to set the sleepclock configurations - Path: /debugfs/libertas_wireless/ethX/ + Path: /sys/kernel/debug/libertas_wireless/ethX/ Usage: cat sleepparams: reads the current sleepclock configuration @@ -115,7 +115,7 @@ subscribed_events The subscribed_events directory contains the interface for the subscribed events API. - Path: /debugfs/libertas_wireless/ethX/subscribed_events/ + Path: /sys/kernel/debug/libertas_wireless/ethX/subscribed_events/ Each event is represented by a filename. Each filename consists of the following three fields: @@ -165,7 +165,7 @@ subscribed_events extscan This command is used to do a specific scan. - Path: /debugfs/libertas_wireless/ethX/ + Path: /sys/kernel/debug/libertas_wireless/ethX/ Usage: echo "SSID" > extscan @@ -179,7 +179,7 @@ getscantable Display the current contents of the driver scan table (ie. get the scan results). - Path: /debugfs/libertas_wireless/ethX/ + Path: /sys/kernel/debug/libertas_wireless/ethX/ Usage: cat getscantable @@ -188,7 +188,7 @@ setuserscan Initiate a customized scan and retrieve the results - Path: /debugfs/libertas_wireless/ethX/ + Path: /sys/kernel/debug/libertas_wireless/ethX/ Usage: echo "[ARGS]" > setuserscan diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index a0e440cd8967..b9b374119033 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -12,15 +12,14 @@ #include "scan.h" #include "cmd.h" -static int lbs_adhoc_post(struct lbs_private *priv, struct cmd_header *resp); - static const u8 bssid_any[ETH_ALEN] __attribute__ ((aligned (2))) = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; static const u8 bssid_off[ETH_ALEN] __attribute__ ((aligned (2))) = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -/* The firmware needs certain bits masked out of the beacon-derviced capability - * field when associating/joining to BSSs. +/* The firmware needs the following bits masked out of the beacon-derived + * capability field when associating/joining to a BSS: + * 9 (QoS), 11 (APSD), 12 (unused), 14 (unused), 15 (unused) */ #define CAPINFO_MASK (~(0xda00)) @@ -102,6 +101,295 @@ static void lbs_set_basic_rate_flags(u8 *rates, size_t len) } +static u8 iw_auth_to_ieee_auth(u8 auth) +{ + if (auth == IW_AUTH_ALG_OPEN_SYSTEM) + return 0x00; + else if (auth == IW_AUTH_ALG_SHARED_KEY) + return 0x01; + else if (auth == IW_AUTH_ALG_LEAP) + return 0x80; + + lbs_deb_join("%s: invalid auth alg 0x%X\n", __func__, auth); + return 0; +} + +/** + * @brief This function prepares the authenticate command. AUTHENTICATE only + * sets the authentication suite for future associations, as the firmware + * handles authentication internally during the ASSOCIATE command. + * + * @param priv A pointer to struct lbs_private structure + * @param bssid The peer BSSID with which to authenticate + * @param auth The authentication mode to use (from wireless.h) + * + * @return 0 or -1 + */ +static int lbs_set_authentication(struct lbs_private *priv, u8 bssid[6], u8 auth) +{ + struct cmd_ds_802_11_authenticate cmd; + int ret = -1; + DECLARE_MAC_BUF(mac); + + lbs_deb_enter(LBS_DEB_JOIN); + + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + memcpy(cmd.bssid, bssid, ETH_ALEN); + + cmd.authtype = iw_auth_to_ieee_auth(auth); + + lbs_deb_join("AUTH_CMD: BSSID %s, auth 0x%x\n", + print_mac(mac, bssid), cmd.authtype); + + ret = lbs_cmd_with_response(priv, CMD_802_11_AUTHENTICATE, &cmd); + + lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); + return ret; +} + + +static int lbs_assoc_post(struct lbs_private *priv, + struct cmd_ds_802_11_associate_response *resp) +{ + int ret = 0; + union iwreq_data wrqu; + struct bss_descriptor *bss; + u16 status_code; + + lbs_deb_enter(LBS_DEB_ASSOC); + + if (!priv->in_progress_assoc_req) { + lbs_deb_assoc("ASSOC_RESP: no in-progress assoc request\n"); + ret = -1; + goto done; + } + bss = &priv->in_progress_assoc_req->bss; + + /* + * Older FW versions map the IEEE 802.11 Status Code in the association + * response to the following values returned in resp->statuscode: + * + * IEEE Status Code Marvell Status Code + * 0 -> 0x0000 ASSOC_RESULT_SUCCESS + * 13 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED + * 14 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED + * 15 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED + * 16 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED + * others -> 0x0003 ASSOC_RESULT_REFUSED + * + * Other response codes: + * 0x0001 -> ASSOC_RESULT_INVALID_PARAMETERS (unused) + * 0x0002 -> ASSOC_RESULT_TIMEOUT (internal timer expired waiting for + * association response from the AP) + */ + + status_code = le16_to_cpu(resp->statuscode); + if (priv->fwrelease < 0x09000000) { + switch (status_code) { + case 0x00: + break; + case 0x01: + lbs_deb_assoc("ASSOC_RESP: invalid parameters\n"); + break; + case 0x02: + lbs_deb_assoc("ASSOC_RESP: internal timer " + "expired while waiting for the AP\n"); + break; + case 0x03: + lbs_deb_assoc("ASSOC_RESP: association " + "refused by AP\n"); + break; + case 0x04: + lbs_deb_assoc("ASSOC_RESP: authentication " + "refused by AP\n"); + break; + default: + lbs_deb_assoc("ASSOC_RESP: failure reason 0x%02x " + " unknown\n", status_code); + break; + } + } else { + /* v9+ returns the AP's association response */ + lbs_deb_assoc("ASSOC_RESP: failure reason 0x%02x\n", status_code); + } + + if (status_code) { + lbs_mac_event_disconnected(priv); + ret = -1; + goto done; + } + + lbs_deb_hex(LBS_DEB_ASSOC, "ASSOC_RESP", + (void *) (resp + sizeof (resp->hdr)), + le16_to_cpu(resp->hdr.size) - sizeof (resp->hdr)); + + /* Send a Media Connected event, according to the Spec */ + priv->connect_status = LBS_CONNECTED; + + /* Update current SSID and BSSID */ + memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE); + priv->curbssparams.ssid_len = bss->ssid_len; + memcpy(priv->curbssparams.bssid, bss->bssid, ETH_ALEN); + + priv->SNR[TYPE_RXPD][TYPE_AVG] = 0; + priv->NF[TYPE_RXPD][TYPE_AVG] = 0; + + memset(priv->rawSNR, 0x00, sizeof(priv->rawSNR)); + memset(priv->rawNF, 0x00, sizeof(priv->rawNF)); + priv->nextSNRNF = 0; + priv->numSNRNF = 0; + + netif_carrier_on(priv->dev); + if (!priv->tx_pending_len) + netif_wake_queue(priv->dev); + + memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); + +done: + lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); + return ret; +} + +/** + * @brief This function prepares an association-class command. + * + * @param priv A pointer to struct lbs_private structure + * @param assoc_req The association request describing the BSS to associate + * or reassociate with + * @param command The actual command, either CMD_802_11_ASSOCIATE or + * CMD_802_11_REASSOCIATE + * + * @return 0 or -1 + */ +static int lbs_associate(struct lbs_private *priv, + struct assoc_request *assoc_req, + u16 command) +{ + struct cmd_ds_802_11_associate cmd; + int ret = 0; + struct bss_descriptor *bss = &assoc_req->bss; + u8 *pos = &(cmd.iebuf[0]); + u16 tmpcap, tmplen, tmpauth; + struct mrvl_ie_ssid_param_set *ssid; + struct mrvl_ie_ds_param_set *ds; + struct mrvl_ie_cf_param_set *cf; + struct mrvl_ie_rates_param_set *rates; + struct mrvl_ie_rsn_param_set *rsn; + struct mrvl_ie_auth_type *auth; + + lbs_deb_enter(LBS_DEB_ASSOC); + + BUG_ON((command != CMD_802_11_ASSOCIATE) && + (command != CMD_802_11_REASSOCIATE)); + + memset(&cmd, 0, sizeof(cmd)); + cmd.hdr.command = cpu_to_le16(command); + + /* Fill in static fields */ + memcpy(cmd.bssid, bss->bssid, ETH_ALEN); + cmd.listeninterval = cpu_to_le16(MRVDRV_DEFAULT_LISTEN_INTERVAL); + + /* Capability info */ + tmpcap = (bss->capability & CAPINFO_MASK); + if (bss->mode == IW_MODE_INFRA) + tmpcap |= WLAN_CAPABILITY_ESS; + cmd.capability = cpu_to_le16(tmpcap); + lbs_deb_assoc("ASSOC_CMD: capability 0x%04x\n", tmpcap); + + /* SSID */ + ssid = (struct mrvl_ie_ssid_param_set *) pos; + ssid->header.type = cpu_to_le16(TLV_TYPE_SSID); + tmplen = bss->ssid_len; + ssid->header.len = cpu_to_le16(tmplen); + memcpy(ssid->ssid, bss->ssid, tmplen); + pos += sizeof(ssid->header) + tmplen; + + ds = (struct mrvl_ie_ds_param_set *) pos; + ds->header.type = cpu_to_le16(TLV_TYPE_PHY_DS); + ds->header.len = cpu_to_le16(1); + ds->channel = bss->phy.ds.channel; + pos += sizeof(ds->header) + 1; + + cf = (struct mrvl_ie_cf_param_set *) pos; + cf->header.type = cpu_to_le16(TLV_TYPE_CF); + tmplen = sizeof(*cf) - sizeof (cf->header); + cf->header.len = cpu_to_le16(tmplen); + /* IE payload should be zeroed, firmware fills it in for us */ + pos += sizeof(*cf); + + rates = (struct mrvl_ie_rates_param_set *) pos; + rates->header.type = cpu_to_le16(TLV_TYPE_RATES); + memcpy(&rates->rates, &bss->rates, MAX_RATES); + tmplen = MAX_RATES; + if (get_common_rates(priv, rates->rates, &tmplen)) { + ret = -1; + goto done; + } + pos += sizeof(rates->header) + tmplen; + rates->header.len = cpu_to_le16(tmplen); + lbs_deb_assoc("ASSOC_CMD: num rates %u\n", tmplen); + + /* Copy the infra. association rates into Current BSS state structure */ + memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates)); + memcpy(&priv->curbssparams.rates, &rates->rates, tmplen); + + /* Set MSB on basic rates as the firmware requires, but _after_ + * copying to current bss rates. + */ + lbs_set_basic_rate_flags(rates->rates, tmplen); + + /* Firmware v9+ indicate authentication suites as a TLV */ + if (priv->fwrelease >= 0x09000000) { + DECLARE_MAC_BUF(mac); + + auth = (struct mrvl_ie_auth_type *) pos; + auth->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE); + auth->header.len = cpu_to_le16(2); + tmpauth = iw_auth_to_ieee_auth(priv->secinfo.auth_mode); + auth->auth = cpu_to_le16(tmpauth); + pos += sizeof(auth->header) + 2; + + lbs_deb_join("AUTH_CMD: BSSID %s, auth 0x%x\n", + print_mac(mac, bss->bssid), priv->secinfo.auth_mode); + } + + /* WPA/WPA2 IEs */ + if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) { + rsn = (struct mrvl_ie_rsn_param_set *) pos; + /* WPA_IE or WPA2_IE */ + rsn->header.type = cpu_to_le16((u16) assoc_req->wpa_ie[0]); + tmplen = (u16) assoc_req->wpa_ie[1]; + rsn->header.len = cpu_to_le16(tmplen); + memcpy(rsn->rsnie, &assoc_req->wpa_ie[2], tmplen); + lbs_deb_hex(LBS_DEB_JOIN, "ASSOC_CMD: WPA/RSN IE", (u8 *) rsn, + sizeof(rsn->header) + tmplen); + pos += sizeof(rsn->header) + tmplen; + } + + cmd.hdr.size = cpu_to_le16((sizeof(cmd) - sizeof(cmd.iebuf)) + + (u16)(pos - (u8 *) &cmd.iebuf)); + + /* update curbssparams */ + priv->curbssparams.channel = bss->phy.ds.channel; + + if (lbs_parse_dnld_countryinfo_11d(priv, bss)) { + ret = -1; + goto done; + } + + ret = lbs_cmd_with_response(priv, command, &cmd); + if (ret == 0) { + ret = lbs_assoc_post(priv, + (struct cmd_ds_802_11_associate_response *) &cmd); + } + +done: + lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); + return ret; +} + /** * @brief Associate to a specific BSS discovered in a scan * @@ -110,7 +398,7 @@ static void lbs_set_basic_rate_flags(u8 *rates, size_t len) * * @return 0-success, otherwise fail */ -static int lbs_associate(struct lbs_private *priv, +static int lbs_try_associate(struct lbs_private *priv, struct assoc_request *assoc_req) { int ret; @@ -118,11 +406,15 @@ static int lbs_associate(struct lbs_private *priv, lbs_deb_enter(LBS_DEB_ASSOC); - ret = lbs_prepare_and_send_command(priv, CMD_802_11_AUTHENTICATE, - 0, CMD_OPTION_WAITFORRSP, - 0, assoc_req->bss.bssid); - if (ret) - goto out; + /* FW v9 and higher indicate authentication suites as a TLV in the + * association command, not as a separate authentication command. + */ + if (priv->fwrelease < 0x09000000) { + ret = lbs_set_authentication(priv, assoc_req->bss.bssid, + priv->secinfo.auth_mode); + if (ret) + goto out; + } /* Use short preamble only when both the BSS and firmware support it */ if ((priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) && @@ -133,14 +425,78 @@ static int lbs_associate(struct lbs_private *priv, if (ret) goto out; - ret = lbs_prepare_and_send_command(priv, CMD_802_11_ASSOCIATE, - 0, CMD_OPTION_WAITFORRSP, 0, assoc_req); + ret = lbs_associate(priv, assoc_req, CMD_802_11_ASSOCIATE); out: lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); return ret; } +static int lbs_adhoc_post(struct lbs_private *priv, + struct cmd_ds_802_11_ad_hoc_result *resp) +{ + int ret = 0; + u16 command = le16_to_cpu(resp->hdr.command); + u16 result = le16_to_cpu(resp->hdr.result); + union iwreq_data wrqu; + struct bss_descriptor *bss; + DECLARE_SSID_BUF(ssid); + + lbs_deb_enter(LBS_DEB_JOIN); + + if (!priv->in_progress_assoc_req) { + lbs_deb_join("ADHOC_RESP: no in-progress association " + "request\n"); + ret = -1; + goto done; + } + bss = &priv->in_progress_assoc_req->bss; + + /* + * Join result code 0 --> SUCCESS + */ + if (result) { + lbs_deb_join("ADHOC_RESP: failed (result 0x%X)\n", result); + if (priv->connect_status == LBS_CONNECTED) + lbs_mac_event_disconnected(priv); + ret = -1; + goto done; + } + + /* Send a Media Connected event, according to the Spec */ + priv->connect_status = LBS_CONNECTED; + + if (command == CMD_RET(CMD_802_11_AD_HOC_START)) { + /* Update the created network descriptor with the new BSSID */ + memcpy(bss->bssid, resp->bssid, ETH_ALEN); + } + + /* Set the BSSID from the joined/started descriptor */ + memcpy(&priv->curbssparams.bssid, bss->bssid, ETH_ALEN); + + /* Set the new SSID to current SSID */ + memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE); + priv->curbssparams.ssid_len = bss->ssid_len; + + netif_carrier_on(priv->dev); + if (!priv->tx_pending_len) + netif_wake_queue(priv->dev); + + memset(&wrqu, 0, sizeof(wrqu)); + memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); + + lbs_deb_join("ADHOC_RESP: Joined/started '%s', BSSID %pM, channel %d\n", + print_ssid(ssid, bss->ssid, bss->ssid_len), + priv->curbssparams.bssid, + priv->curbssparams.channel); + +done: + lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); + return ret; +} + /** * @brief Join an adhoc network found in a previous scan * @@ -219,11 +575,10 @@ static int lbs_adhoc_join(struct lbs_private *priv, memcpy(&cmd.bss.bssid, &bss->bssid, ETH_ALEN); memcpy(&cmd.bss.ssid, &bss->ssid, bss->ssid_len); - memcpy(&cmd.bss.phyparamset, &bss->phyparamset, - sizeof(union ieeetypes_phyparamset)); + memcpy(&cmd.bss.ds, &bss->phy.ds, sizeof(struct ieee_ie_ds_param_set)); - memcpy(&cmd.bss.ssparamset, &bss->ssparamset, - sizeof(union IEEEtypes_ssparamset)); + memcpy(&cmd.bss.ibss, &bss->ss.ibss, + sizeof(struct ieee_ie_ibss_param_set)); cmd.bss.capability = cpu_to_le16(bss->capability & CAPINFO_MASK); lbs_deb_join("ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n", @@ -260,7 +615,7 @@ static int lbs_adhoc_join(struct lbs_private *priv, */ lbs_set_basic_rate_flags(cmd.bss.rates, ratesize); - cmd.bss.ssparamset.ibssparamset.atimwindow = cpu_to_le16(bss->atimwindow); + cmd.bss.ibss.atimwindow = bss->atimwindow; if (assoc_req->secinfo.wep_enabled) { u16 tmp = le16_to_cpu(cmd.bss.capability); @@ -287,8 +642,10 @@ static int lbs_adhoc_join(struct lbs_private *priv, } ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_JOIN, &cmd); - if (ret == 0) - ret = lbs_adhoc_post(priv, (struct cmd_header *) &cmd); + if (ret == 0) { + ret = lbs_adhoc_post(priv, + (struct cmd_ds_802_11_ad_hoc_result *)&cmd); + } out: lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); @@ -343,22 +700,24 @@ static int lbs_adhoc_start(struct lbs_private *priv, WARN_ON(!assoc_req->channel); /* set Physical parameter set */ - cmd.phyparamset.dsparamset.elementid = WLAN_EID_DS_PARAMS; - cmd.phyparamset.dsparamset.len = 1; - cmd.phyparamset.dsparamset.currentchan = assoc_req->channel; + cmd.ds.header.id = WLAN_EID_DS_PARAMS; + cmd.ds.header.len = 1; + cmd.ds.channel = assoc_req->channel; /* set IBSS parameter set */ - cmd.ssparamset.ibssparamset.elementid = WLAN_EID_IBSS_PARAMS; - cmd.ssparamset.ibssparamset.len = 2; - cmd.ssparamset.ibssparamset.atimwindow = 0; + cmd.ibss.header.id = WLAN_EID_IBSS_PARAMS; + cmd.ibss.header.len = 2; + cmd.ibss.atimwindow = cpu_to_le16(0); /* set capability info */ tmpcap = WLAN_CAPABILITY_IBSS; - if (assoc_req->secinfo.wep_enabled) { - lbs_deb_join("ADHOC_START: WEP enabled, setting privacy on\n"); + if (assoc_req->secinfo.wep_enabled || + assoc_req->secinfo.WPAenabled || + assoc_req->secinfo.WPA2enabled) { + lbs_deb_join("ADHOC_START: WEP/WPA enabled, privacy on\n"); tmpcap |= WLAN_CAPABILITY_PRIVACY; } else - lbs_deb_join("ADHOC_START: WEP disabled, setting privacy off\n"); + lbs_deb_join("ADHOC_START: WEP disabled, privacy off\n"); cmd.capability = cpu_to_le16(tmpcap); @@ -395,7 +754,8 @@ static int lbs_adhoc_start(struct lbs_private *priv, ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_START, &cmd); if (ret == 0) - ret = lbs_adhoc_post(priv, (struct cmd_header *) &cmd); + ret = lbs_adhoc_post(priv, + (struct cmd_ds_802_11_ad_hoc_result *)&cmd); out: lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); @@ -720,7 +1080,7 @@ static int assoc_helper_essid(struct lbs_private *priv, assoc_req->ssid_len, NULL, IW_MODE_INFRA, channel); if (bss != NULL) { memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor)); - ret = lbs_associate(priv, assoc_req); + ret = lbs_try_associate(priv, assoc_req); } else { lbs_deb_assoc("SSID not found; cannot associate\n"); } @@ -772,8 +1132,9 @@ static int assoc_helper_bssid(struct lbs_private *priv, memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor)); if (assoc_req->mode == IW_MODE_INFRA) { - ret = lbs_associate(priv, assoc_req); - lbs_deb_assoc("ASSOC: lbs_associate(bssid) returned %d\n", ret); + ret = lbs_try_associate(priv, assoc_req); + lbs_deb_assoc("ASSOC: lbs_try_associate(bssid) returned %d\n", + ret); } else if (assoc_req->mode == IW_MODE_ADHOC) { lbs_adhoc_join(priv, assoc_req); } @@ -1466,57 +1827,6 @@ struct assoc_request *lbs_get_association_request(struct lbs_private *priv) } -/** - * @brief This function prepares command of authenticate. - * - * @param priv A pointer to struct lbs_private structure - * @param cmd A pointer to cmd_ds_command structure - * @param pdata_buf Void cast of pointer to a BSSID to authenticate with - * - * @return 0 or -1 - */ -int lbs_cmd_80211_authenticate(struct lbs_private *priv, - struct cmd_ds_command *cmd, - void *pdata_buf) -{ - struct cmd_ds_802_11_authenticate *pauthenticate = &cmd->params.auth; - int ret = -1; - u8 *bssid = pdata_buf; - - lbs_deb_enter(LBS_DEB_JOIN); - - cmd->command = cpu_to_le16(CMD_802_11_AUTHENTICATE); - cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_authenticate) - + S_DS_GEN); - - /* translate auth mode to 802.11 defined wire value */ - switch (priv->secinfo.auth_mode) { - case IW_AUTH_ALG_OPEN_SYSTEM: - pauthenticate->authtype = 0x00; - break; - case IW_AUTH_ALG_SHARED_KEY: - pauthenticate->authtype = 0x01; - break; - case IW_AUTH_ALG_LEAP: - pauthenticate->authtype = 0x80; - break; - default: - lbs_deb_join("AUTH_CMD: invalid auth alg 0x%X\n", - priv->secinfo.auth_mode); - goto out; - } - - memcpy(pauthenticate->macaddr, bssid, ETH_ALEN); - - lbs_deb_join("AUTH_CMD: BSSID %pM, auth 0x%x\n", - bssid, pauthenticate->authtype); - ret = 0; - -out: - lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); - return ret; -} - /** * @brief Deauthenticate from a specific BSS * @@ -1550,285 +1860,3 @@ int lbs_cmd_80211_deauthenticate(struct lbs_private *priv, u8 bssid[ETH_ALEN], return ret; } -int lbs_cmd_80211_associate(struct lbs_private *priv, - struct cmd_ds_command *cmd, void *pdata_buf) -{ - struct cmd_ds_802_11_associate *passo = &cmd->params.associate; - int ret = 0; - struct assoc_request *assoc_req = pdata_buf; - struct bss_descriptor *bss = &assoc_req->bss; - u8 *pos; - u16 tmpcap, tmplen; - struct mrvlietypes_ssidparamset *ssid; - struct mrvlietypes_phyparamset *phy; - struct mrvlietypes_ssparamset *ss; - struct mrvlietypes_ratesparamset *rates; - struct mrvlietypes_rsnparamset *rsn; - - lbs_deb_enter(LBS_DEB_ASSOC); - - pos = (u8 *) passo; - - if (!priv) { - ret = -1; - goto done; - } - - cmd->command = cpu_to_le16(CMD_802_11_ASSOCIATE); - - memcpy(passo->peerstaaddr, bss->bssid, sizeof(passo->peerstaaddr)); - pos += sizeof(passo->peerstaaddr); - - /* set the listen interval */ - passo->listeninterval = cpu_to_le16(MRVDRV_DEFAULT_LISTEN_INTERVAL); - - pos += sizeof(passo->capability); - pos += sizeof(passo->listeninterval); - pos += sizeof(passo->bcnperiod); - pos += sizeof(passo->dtimperiod); - - ssid = (struct mrvlietypes_ssidparamset *) pos; - ssid->header.type = cpu_to_le16(TLV_TYPE_SSID); - tmplen = bss->ssid_len; - ssid->header.len = cpu_to_le16(tmplen); - memcpy(ssid->ssid, bss->ssid, tmplen); - pos += sizeof(ssid->header) + tmplen; - - phy = (struct mrvlietypes_phyparamset *) pos; - phy->header.type = cpu_to_le16(TLV_TYPE_PHY_DS); - tmplen = sizeof(phy->fh_ds.dsparamset); - phy->header.len = cpu_to_le16(tmplen); - memcpy(&phy->fh_ds.dsparamset, - &bss->phyparamset.dsparamset.currentchan, - tmplen); - pos += sizeof(phy->header) + tmplen; - - ss = (struct mrvlietypes_ssparamset *) pos; - ss->header.type = cpu_to_le16(TLV_TYPE_CF); - tmplen = sizeof(ss->cf_ibss.cfparamset); - ss->header.len = cpu_to_le16(tmplen); - pos += sizeof(ss->header) + tmplen; - - rates = (struct mrvlietypes_ratesparamset *) pos; - rates->header.type = cpu_to_le16(TLV_TYPE_RATES); - memcpy(&rates->rates, &bss->rates, MAX_RATES); - tmplen = MAX_RATES; - if (get_common_rates(priv, rates->rates, &tmplen)) { - ret = -1; - goto done; - } - pos += sizeof(rates->header) + tmplen; - rates->header.len = cpu_to_le16(tmplen); - lbs_deb_assoc("ASSOC_CMD: num rates %u\n", tmplen); - - /* Copy the infra. association rates into Current BSS state structure */ - memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates)); - memcpy(&priv->curbssparams.rates, &rates->rates, tmplen); - - /* Set MSB on basic rates as the firmware requires, but _after_ - * copying to current bss rates. - */ - lbs_set_basic_rate_flags(rates->rates, tmplen); - - if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) { - rsn = (struct mrvlietypes_rsnparamset *) pos; - /* WPA_IE or WPA2_IE */ - rsn->header.type = cpu_to_le16((u16) assoc_req->wpa_ie[0]); - tmplen = (u16) assoc_req->wpa_ie[1]; - rsn->header.len = cpu_to_le16(tmplen); - memcpy(rsn->rsnie, &assoc_req->wpa_ie[2], tmplen); - lbs_deb_hex(LBS_DEB_JOIN, "ASSOC_CMD: RSN IE", (u8 *) rsn, - sizeof(rsn->header) + tmplen); - pos += sizeof(rsn->header) + tmplen; - } - - /* update curbssparams */ - priv->curbssparams.channel = bss->phyparamset.dsparamset.currentchan; - - if (lbs_parse_dnld_countryinfo_11d(priv, bss)) { - ret = -1; - goto done; - } - - cmd->size = cpu_to_le16((u16) (pos - (u8 *) passo) + S_DS_GEN); - - /* set the capability info */ - tmpcap = (bss->capability & CAPINFO_MASK); - if (bss->mode == IW_MODE_INFRA) - tmpcap |= WLAN_CAPABILITY_ESS; - passo->capability = cpu_to_le16(tmpcap); - lbs_deb_assoc("ASSOC_CMD: capability 0x%04x\n", tmpcap); - -done: - lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); - return ret; -} - -int lbs_ret_80211_associate(struct lbs_private *priv, - struct cmd_ds_command *resp) -{ - int ret = 0; - union iwreq_data wrqu; - struct ieeetypes_assocrsp *passocrsp; - struct bss_descriptor *bss; - u16 status_code; - - lbs_deb_enter(LBS_DEB_ASSOC); - - if (!priv->in_progress_assoc_req) { - lbs_deb_assoc("ASSOC_RESP: no in-progress assoc request\n"); - ret = -1; - goto done; - } - bss = &priv->in_progress_assoc_req->bss; - - passocrsp = (struct ieeetypes_assocrsp *) &resp->params; - - /* - * Older FW versions map the IEEE 802.11 Status Code in the association - * response to the following values returned in passocrsp->statuscode: - * - * IEEE Status Code Marvell Status Code - * 0 -> 0x0000 ASSOC_RESULT_SUCCESS - * 13 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED - * 14 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED - * 15 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED - * 16 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED - * others -> 0x0003 ASSOC_RESULT_REFUSED - * - * Other response codes: - * 0x0001 -> ASSOC_RESULT_INVALID_PARAMETERS (unused) - * 0x0002 -> ASSOC_RESULT_TIMEOUT (internal timer expired waiting for - * association response from the AP) - */ - - status_code = le16_to_cpu(passocrsp->statuscode); - switch (status_code) { - case 0x00: - break; - case 0x01: - lbs_deb_assoc("ASSOC_RESP: invalid parameters\n"); - break; - case 0x02: - lbs_deb_assoc("ASSOC_RESP: internal timer " - "expired while waiting for the AP\n"); - break; - case 0x03: - lbs_deb_assoc("ASSOC_RESP: association " - "refused by AP\n"); - break; - case 0x04: - lbs_deb_assoc("ASSOC_RESP: authentication " - "refused by AP\n"); - break; - default: - lbs_deb_assoc("ASSOC_RESP: failure reason 0x%02x " - " unknown\n", status_code); - break; - } - - if (status_code) { - lbs_mac_event_disconnected(priv); - ret = -1; - goto done; - } - - lbs_deb_hex(LBS_DEB_ASSOC, "ASSOC_RESP", (void *)&resp->params, - le16_to_cpu(resp->size) - S_DS_GEN); - - /* Send a Media Connected event, according to the Spec */ - priv->connect_status = LBS_CONNECTED; - - /* Update current SSID and BSSID */ - memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE); - priv->curbssparams.ssid_len = bss->ssid_len; - memcpy(priv->curbssparams.bssid, bss->bssid, ETH_ALEN); - - priv->SNR[TYPE_RXPD][TYPE_AVG] = 0; - priv->NF[TYPE_RXPD][TYPE_AVG] = 0; - - memset(priv->rawSNR, 0x00, sizeof(priv->rawSNR)); - memset(priv->rawNF, 0x00, sizeof(priv->rawNF)); - priv->nextSNRNF = 0; - priv->numSNRNF = 0; - - netif_carrier_on(priv->dev); - if (!priv->tx_pending_len) - netif_wake_queue(priv->dev); - - memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN); - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); - -done: - lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); - return ret; -} - -static int lbs_adhoc_post(struct lbs_private *priv, struct cmd_header *resp) -{ - int ret = 0; - u16 command = le16_to_cpu(resp->command); - u16 result = le16_to_cpu(resp->result); - struct cmd_ds_802_11_ad_hoc_result *adhoc_resp; - union iwreq_data wrqu; - struct bss_descriptor *bss; - DECLARE_SSID_BUF(ssid); - - lbs_deb_enter(LBS_DEB_JOIN); - - adhoc_resp = (struct cmd_ds_802_11_ad_hoc_result *) resp; - - if (!priv->in_progress_assoc_req) { - lbs_deb_join("ADHOC_RESP: no in-progress association " - "request\n"); - ret = -1; - goto done; - } - bss = &priv->in_progress_assoc_req->bss; - - /* - * Join result code 0 --> SUCCESS - */ - if (result) { - lbs_deb_join("ADHOC_RESP: failed (result 0x%X)\n", result); - if (priv->connect_status == LBS_CONNECTED) - lbs_mac_event_disconnected(priv); - ret = -1; - goto done; - } - - /* Send a Media Connected event, according to the Spec */ - priv->connect_status = LBS_CONNECTED; - - if (command == CMD_RET(CMD_802_11_AD_HOC_START)) { - /* Update the created network descriptor with the new BSSID */ - memcpy(bss->bssid, adhoc_resp->bssid, ETH_ALEN); - } - - /* Set the BSSID from the joined/started descriptor */ - memcpy(&priv->curbssparams.bssid, bss->bssid, ETH_ALEN); - - /* Set the new SSID to current SSID */ - memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE); - priv->curbssparams.ssid_len = bss->ssid_len; - - netif_carrier_on(priv->dev); - if (!priv->tx_pending_len) - netif_wake_queue(priv->dev); - - memset(&wrqu, 0, sizeof(wrqu)); - memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN); - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); - - lbs_deb_join("ADHOC_RESP: Joined/started '%s', BSSID %pM, channel %d\n", - print_ssid(ssid, bss->ssid, bss->ssid_len), - priv->curbssparams.bssid, - priv->curbssparams.channel); - -done: - lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); - return ret; -} - diff --git a/drivers/net/wireless/libertas/assoc.h b/drivers/net/wireless/libertas/assoc.h index 8b7336dd02a3..6e765e9f91a3 100644 --- a/drivers/net/wireless/libertas/assoc.h +++ b/drivers/net/wireless/libertas/assoc.h @@ -8,22 +8,9 @@ void lbs_association_worker(struct work_struct *work); struct assoc_request *lbs_get_association_request(struct lbs_private *priv); -struct cmd_ds_command; -int lbs_cmd_80211_authenticate(struct lbs_private *priv, - struct cmd_ds_command *cmd, - void *pdata_buf); - int lbs_adhoc_stop(struct lbs_private *priv); int lbs_cmd_80211_deauthenticate(struct lbs_private *priv, u8 bssid[ETH_ALEN], u16 reason); -int lbs_cmd_80211_associate(struct lbs_private *priv, - struct cmd_ds_command *cmd, - void *pdata_buf); - -int lbs_ret_80211_ad_hoc_start(struct lbs_private *priv, - struct cmd_ds_command *resp); -int lbs_ret_80211_associate(struct lbs_private *priv, - struct cmd_ds_command *resp); #endif /* _LBS_ASSOC_H */ diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 8c3605cdc64c..01db705a38ec 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -119,6 +119,19 @@ int lbs_update_hw_spec(struct lbs_private *priv) lbs_deb_cmd("GET_HW_SPEC: hardware interface 0x%x, hardware spec 0x%04x\n", cmd.hwifversion, cmd.version); + /* Determine mesh_fw_ver from fwrelease and fwcapinfo */ + /* 5.0.16p0 9.0.0.p0 is known to NOT support any mesh */ + /* 5.110.22 have mesh command with 0xa3 command id */ + /* 10.0.0.p0 FW brings in mesh config command with different id */ + /* Check FW version MSB and initialize mesh_fw_ver */ + if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5) + priv->mesh_fw_ver = MESH_FW_OLD; + else if ((MRVL_FW_MAJOR_REV(priv->fwrelease) >= MRVL_FW_V10) && + (priv->fwcapinfo & MESH_CAPINFO_ENABLE_MASK)) + priv->mesh_fw_ver = MESH_FW_NEW; + else + priv->mesh_fw_ver = MESH_NONE; + /* Clamp region code to 8-bit since FW spec indicates that it should * only ever be 8-bit, even though the field size is 16-bit. Some firmware * returns non-zero high 8 bits here. @@ -1036,17 +1049,26 @@ static int __lbs_mesh_config_send(struct lbs_private *priv, uint16_t action, uint16_t type) { int ret; + u16 command = CMD_MESH_CONFIG_OLD; lbs_deb_enter(LBS_DEB_CMD); - cmd->hdr.command = cpu_to_le16(CMD_MESH_CONFIG); + /* + * Command id is 0xac for v10 FW along with mesh interface + * id in bits 14-13-12. + */ + if (priv->mesh_fw_ver == MESH_FW_NEW) + command = CMD_MESH_CONFIG | + (MESH_IFACE_ID << MESH_IFACE_BIT_OFFSET); + + cmd->hdr.command = cpu_to_le16(command); cmd->hdr.size = cpu_to_le16(sizeof(struct cmd_ds_mesh_config)); cmd->hdr.result = 0; cmd->type = cpu_to_le16(type); cmd->action = cpu_to_le16(action); - ret = lbs_cmd_with_response(priv, CMD_MESH_CONFIG, cmd); + ret = lbs_cmd_with_response(priv, command, cmd); lbs_deb_leave(LBS_DEB_CMD); return ret; @@ -1198,8 +1220,7 @@ static void lbs_submit_command(struct lbs_private *priv, command = le16_to_cpu(cmd->command); /* These commands take longer */ - if (command == CMD_802_11_SCAN || command == CMD_802_11_ASSOCIATE || - command == CMD_802_11_AUTHENTICATE) + if (command == CMD_802_11_SCAN || command == CMD_802_11_ASSOCIATE) timeo = 5 * HZ; lbs_deb_cmd("DNLD_CMD: command 0x%04x, seq %d, size %d\n", @@ -1393,15 +1414,6 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, ret = lbs_cmd_802_11_ps_mode(cmdptr, cmd_action); break; - case CMD_802_11_ASSOCIATE: - case CMD_802_11_REASSOCIATE: - ret = lbs_cmd_80211_associate(priv, cmdptr, pdata_buf); - break; - - case CMD_802_11_AUTHENTICATE: - ret = lbs_cmd_80211_authenticate(priv, cmdptr, pdata_buf); - break; - case CMD_MAC_REG_ACCESS: case CMD_BBP_REG_ACCESS: case CMD_RF_REG_ACCESS: @@ -1448,8 +1460,8 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, break; case CMD_802_11_LED_GPIO_CTRL: { - struct mrvlietypes_ledgpio *gpio = - (struct mrvlietypes_ledgpio*) + struct mrvl_ie_ledgpio *gpio = + (struct mrvl_ie_ledgpio*) cmdptr->params.ledgpio.data; memmove(&cmdptr->params.ledgpio, diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index bcf2a9756fb6..c42d3faa2660 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -5,7 +5,7 @@ #include #include #include - +#include #include #include "host.h" @@ -154,11 +154,11 @@ static int lbs_ret_802_11_rssi(struct lbs_private *priv, lbs_deb_enter(LBS_DEB_CMD); /* store the non average value */ - priv->SNR[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->SNR); - priv->NF[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->noisefloor); + priv->SNR[TYPE_BEACON][TYPE_NOAVG] = get_unaligned_le16(&rssirsp->SNR); + priv->NF[TYPE_BEACON][TYPE_NOAVG] = get_unaligned_le16(&rssirsp->noisefloor); - priv->SNR[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgSNR); - priv->NF[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgnoisefloor); + priv->SNR[TYPE_BEACON][TYPE_AVG] = get_unaligned_le16(&rssirsp->avgSNR); + priv->NF[TYPE_BEACON][TYPE_AVG] = get_unaligned_le16(&rssirsp->avgnoisefloor); priv->RSSI[TYPE_BEACON][TYPE_NOAVG] = CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_NOAVG], @@ -210,12 +210,6 @@ static inline int handle_cmd_response(struct lbs_private *priv, ret = lbs_ret_reg_access(priv, respcmd, resp); break; - case CMD_RET_802_11_ASSOCIATE: - case CMD_RET(CMD_802_11_ASSOCIATE): - case CMD_RET(CMD_802_11_REASSOCIATE): - ret = lbs_ret_80211_associate(priv, resp); - break; - case CMD_RET(CMD_802_11_SET_AFC): case CMD_RET(CMD_802_11_GET_AFC): spin_lock_irqsave(&priv->driver_lock, flags); @@ -225,7 +219,6 @@ static inline int handle_cmd_response(struct lbs_private *priv, break; - case CMD_RET(CMD_802_11_AUTHENTICATE): case CMD_RET(CMD_802_11_BEACON_STOP): break; diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c index 50e28a0cdfee..811ffc3ef414 100644 --- a/drivers/net/wireless/libertas/debugfs.c +++ b/drivers/net/wireless/libertas/debugfs.c @@ -183,12 +183,12 @@ out_unlock: */ static void *lbs_tlv_find(uint16_t tlv_type, const uint8_t *tlv, uint16_t size) { - struct mrvlietypesheader *tlv_h; + struct mrvl_ie_header *tlv_h; uint16_t length; ssize_t pos = 0; while (pos < size) { - tlv_h = (struct mrvlietypesheader *) tlv; + tlv_h = (struct mrvl_ie_header *) tlv; if (!tlv_h->len) return NULL; if (tlv_h->type == cpu_to_le16(tlv_type)) @@ -206,7 +206,7 @@ static ssize_t lbs_threshold_read(uint16_t tlv_type, uint16_t event_mask, size_t count, loff_t *ppos) { struct cmd_ds_802_11_subscribe_event *subscribed; - struct mrvlietypes_thresholds *got; + struct mrvl_ie_thresholds *got; struct lbs_private *priv = file->private_data; ssize_t ret = 0; size_t pos = 0; @@ -259,7 +259,7 @@ static ssize_t lbs_threshold_write(uint16_t tlv_type, uint16_t event_mask, loff_t *ppos) { struct cmd_ds_802_11_subscribe_event *events; - struct mrvlietypes_thresholds *tlv; + struct mrvl_ie_thresholds *tlv; struct lbs_private *priv = file->private_data; ssize_t buf_size; int value, freq, new_mask; diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h index e8dfde39abfc..48da157d6cda 100644 --- a/drivers/net/wireless/libertas/defs.h +++ b/drivers/net/wireless/libertas/defs.h @@ -227,6 +227,20 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in #define TxPD_CONTROL_WDS_FRAME (1<<17) #define TxPD_MESH_FRAME TxPD_CONTROL_WDS_FRAME +/** Mesh interface ID */ +#define MESH_IFACE_ID 0x0001 +/** Mesh id should be in bits 14-13-12 */ +#define MESH_IFACE_BIT_OFFSET 0x000c +/** Mesh enable bit in FW capability */ +#define MESH_CAPINFO_ENABLE_MASK (1<<16) + +/** FW definition from Marvell v5 */ +#define MRVL_FW_V5 (0x05) +/** FW definition from Marvell v10 */ +#define MRVL_FW_V10 (0x0a) +/** FW major revision definition */ +#define MRVL_FW_MAJOR_REV(x) ((x)>>24) + /** RxPD status */ #define MRVDRV_RXPD_STATUS_OK 0x0001 @@ -380,6 +394,13 @@ enum KEY_INFO_WPA { KEY_INFO_WPA_ENABLED = 0x04 }; +/** mesh_fw_ver */ +enum _mesh_fw_ver { + MESH_NONE = 0, /* MESH is not supported */ + MESH_FW_OLD, /* MESH is supported in FW V5 */ + MESH_FW_NEW, /* MESH is supported in FW V10 and newer */ +}; + /* Default values for fwt commands. */ #define FWT_DEFAULT_METRIC 0 #define FWT_DEFAULT_DIR 1 diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 27e81fd97c94..f9ec69e04734 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -101,6 +101,7 @@ struct lbs_mesh_stats { /** Private structure for the MV device */ struct lbs_private { int mesh_open; + int mesh_fw_ver; int infra_open; int mesh_autostart_enabled; @@ -337,7 +338,7 @@ struct bss_descriptor { u32 rssi; u32 channel; u16 beaconperiod; - u32 atimwindow; + __le16 atimwindow; /* IW_MODE_AUTO, IW_MODE_ADHOC, IW_MODE_INFRA */ u8 mode; @@ -347,10 +348,10 @@ struct bss_descriptor { unsigned long last_scanned; - union ieeetypes_phyparamset phyparamset; - union IEEEtypes_ssparamset ssparamset; + union ieee_phy_param_set phy; + union ieee_ss_param_set ss; - struct ieeetypes_countryinfofullset countryinfo; + struct ieee_ie_country_info_full_set countryinfo; u8 wpa_ie[MAX_WPA_IE_LEN]; size_t wpa_ie_len; diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index d4457ef808a6..fe8f0cb737bc 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h @@ -83,8 +83,11 @@ #define CMD_FWT_ACCESS 0x0095 #define CMD_802_11_MONITOR_MODE 0x0098 #define CMD_MESH_ACCESS 0x009b -#define CMD_MESH_CONFIG 0x00a3 +#define CMD_MESH_CONFIG_OLD 0x00a3 +#define CMD_MESH_CONFIG 0x00ac #define CMD_SET_BOOT2_VER 0x00a5 +#define CMD_FUNC_INIT 0x00a9 +#define CMD_FUNC_SHUTDOWN 0x00aa #define CMD_802_11_BEACON_CTRL 0x00b0 /* For the IEEE Power Save */ diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index a899aeb676bb..0a2e29140add 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h @@ -13,8 +13,19 @@ /* TxPD descriptor */ struct txpd { - /* Current Tx packet status */ - __le32 tx_status; + /* union to cope up with later FW revisions */ + union { + /* Current Tx packet status */ + __le32 tx_status; + struct { + /* BSS type: client, AP, etc. */ + u8 bss_type; + /* BSS number */ + u8 bss_num; + /* Reserved */ + __le16 reserved; + } bss; + } u; /* Tx control */ __le32 tx_control; __le32 tx_packet_location; @@ -36,8 +47,17 @@ struct txpd { /* RxPD Descriptor */ struct rxpd { - /* Current Rx packet status */ - __le16 status; + /* union to cope up with later FW revisions */ + union { + /* Current Rx packet status */ + __le16 status; + struct { + /* BSS type: client, AP, etc. */ + u8 bss_type; + /* BSS number */ + u8 bss_num; + } bss; + } u; /* SNR */ u8 snr; @@ -230,7 +250,9 @@ struct cmd_ds_gspi_bus_config { } __attribute__ ((packed)); struct cmd_ds_802_11_authenticate { - u8 macaddr[ETH_ALEN]; + struct cmd_header hdr; + + u8 bssid[ETH_ALEN]; u8 authtype; u8 reserved[10]; } __attribute__ ((packed)); @@ -243,22 +265,23 @@ struct cmd_ds_802_11_deauthenticate { } __attribute__ ((packed)); struct cmd_ds_802_11_associate { - u8 peerstaaddr[6]; + struct cmd_header hdr; + + u8 bssid[6]; __le16 capability; __le16 listeninterval; __le16 bcnperiod; u8 dtimperiod; - -#if 0 - mrvlietypes_ssidparamset_t ssidParamSet; - mrvlietypes_phyparamset_t phyparamset; - mrvlietypes_ssparamset_t ssparamset; - mrvlietypes_ratesparamset_t ratesParamSet; -#endif + u8 iebuf[512]; /* Enough for required and most optional IEs */ } __attribute__ ((packed)); -struct cmd_ds_802_11_associate_rsp { - struct ieeetypes_assocrsp assocRsp; +struct cmd_ds_802_11_associate_response { + struct cmd_header hdr; + + __le16 capability; + __le16 statuscode; + __le16 aid; + u8 iebuf[512]; } __attribute__ ((packed)); struct cmd_ds_802_11_set_wep { @@ -515,9 +538,11 @@ struct cmd_ds_802_11_ad_hoc_start { u8 bsstype; __le16 beaconperiod; u8 dtimperiod; /* Reserved on v9 and later */ - union IEEEtypes_ssparamset ssparamset; - union ieeetypes_phyparamset phyparamset; - __le16 probedelay; + struct ieee_ie_ibss_param_set ibss; + u8 reserved1[4]; + struct ieee_ie_ds_param_set ds; + u8 reserved2[4]; + __le16 probedelay; /* Reserved on v9 and later */ __le16 capability; u8 rates[MAX_RATES]; u8 tlv_memory_size_pad[100]; @@ -538,8 +563,10 @@ struct adhoc_bssdesc { u8 dtimperiod; __le64 timestamp; __le64 localtime; - union ieeetypes_phyparamset phyparamset; - union IEEEtypes_ssparamset ssparamset; + struct ieee_ie_ds_param_set ds; + u8 reserved1[4]; + struct ieee_ie_ibss_param_set ibss; + u8 reserved2[4]; __le16 capability; u8 rates[MAX_RATES]; @@ -745,8 +772,6 @@ struct cmd_ds_command { /* command Body */ union { struct cmd_ds_802_11_ps_mode psmode; - struct cmd_ds_802_11_associate associate; - struct cmd_ds_802_11_authenticate auth; struct cmd_ds_802_11_get_stat gstat; struct cmd_ds_802_3_get_stat gstat_8023; struct cmd_ds_802_11_rf_antenna rant; diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c index cedeac6322fe..2a5b083bf9bd 100644 --- a/drivers/net/wireless/libertas/if_cs.c +++ b/drivers/net/wireless/libertas/if_cs.c @@ -273,7 +273,28 @@ static int if_cs_poll_while_fw_download(struct if_cs_card *card, uint addr, u8 r */ #define IF_CS_PRODUCT_ID 0x0000001C #define IF_CS_CF8385_B1_REV 0x12 +#define IF_CS_CF8381_B3_REV 0x04 +/* + * Used to detect other cards than CF8385 since their revisions of silicon + * doesn't match those from CF8385, eg. CF8381 B3 works with this driver. + */ +#define CF8381_MANFID 0x02db +#define CF8381_CARDID 0x6064 +#define CF8385_MANFID 0x02df +#define CF8385_CARDID 0x8103 + +static inline int if_cs_hw_is_cf8381(struct pcmcia_device *p_dev) +{ + return (p_dev->manf_id == CF8381_MANFID && + p_dev->card_id == CF8381_CARDID); +} + +static inline int if_cs_hw_is_cf8385(struct pcmcia_device *p_dev) +{ + return (p_dev->manf_id == CF8385_MANFID && + p_dev->card_id == CF8385_CARDID); +} /********************************************************************/ /* I/O and interrupt handling */ @@ -757,6 +778,7 @@ static void if_cs_release(struct pcmcia_device *p_dev) static int if_cs_probe(struct pcmcia_device *p_dev) { int ret = -ENOMEM; + unsigned int prod_id; struct lbs_private *priv; struct if_cs_card *card; /* CIS parsing */ @@ -859,7 +881,14 @@ static int if_cs_probe(struct pcmcia_device *p_dev) p_dev->io.BasePort1 + p_dev->io.NumPorts1 - 1); /* Check if we have a current silicon */ - if (if_cs_read8(card, IF_CS_PRODUCT_ID) < IF_CS_CF8385_B1_REV) { + prod_id = if_cs_read8(card, IF_CS_PRODUCT_ID); + if (if_cs_hw_is_cf8381(p_dev) && prod_id < IF_CS_CF8381_B3_REV) { + lbs_pr_err("old chips like 8381 rev B3 aren't supported\n"); + ret = -ENODEV; + goto out2; + } + + if (if_cs_hw_is_cf8385(p_dev) && prod_id < IF_CS_CF8385_B1_REV) { lbs_pr_err("old chips like 8385 rev B1 aren't supported\n"); ret = -ENODEV; goto out2; @@ -950,7 +979,8 @@ static void if_cs_detach(struct pcmcia_device *p_dev) /********************************************************************/ static struct pcmcia_device_id if_cs_ids[] = { - PCMCIA_DEVICE_MANF_CARD(0x02df, 0x8103), + PCMCIA_DEVICE_MANF_CARD(CF8381_MANFID, CF8381_CARDID), + PCMCIA_DEVICE_MANF_CARD(CF8385_MANFID, CF8385_CARDID), PCMCIA_DEVICE_NULL, }; MODULE_DEVICE_TABLE(pcmcia, if_cs_ids); diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c index 76f4c653d641..8cdb88c6ca28 100644 --- a/drivers/net/wireless/libertas/if_sdio.c +++ b/drivers/net/wireless/libertas/if_sdio.c @@ -39,8 +39,24 @@ #include "decl.h" #include "defs.h" #include "dev.h" +#include "cmd.h" #include "if_sdio.h" +/* The if_sdio_remove() callback function is called when + * user removes this module from kernel space or ejects + * the card from the slot. The driver handles these 2 cases + * differently for SD8688 combo chip. + * If the user is removing the module, the FUNC_SHUTDOWN + * command for SD8688 is sent to the firmware. + * If the card is removed, there is no need to send this command. + * + * The variable 'user_rmmod' is used to distinguish these two + * scenarios. This flag is initialized as FALSE in case the card + * is removed, and will be set to TRUE for module removal when + * module_exit function is called. + */ +static u8 user_rmmod; + static char *lbs_helper_name = NULL; module_param_named(helper_name, lbs_helper_name, charp, 0644); @@ -48,8 +64,11 @@ static char *lbs_fw_name = NULL; module_param_named(fw_name, lbs_fw_name, charp, 0644); static const struct sdio_device_id if_sdio_ids[] = { - { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_LIBERTAS) }, - { /* end: all zeroes */ }, + { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, + SDIO_DEVICE_ID_MARVELL_LIBERTAS) }, + { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, + SDIO_DEVICE_ID_MARVELL_8688WLAN) }, + { /* end: all zeroes */ }, }; MODULE_DEVICE_TABLE(sdio, if_sdio_ids); @@ -63,16 +82,22 @@ struct if_sdio_model { static struct if_sdio_model if_sdio_models[] = { { /* 8385 */ - .model = 0x04, + .model = IF_SDIO_MODEL_8385, .helper = "sd8385_helper.bin", .firmware = "sd8385.bin", }, { /* 8686 */ - .model = 0x0B, + .model = IF_SDIO_MODEL_8686, .helper = "sd8686_helper.bin", .firmware = "sd8686.bin", }, + { + /* 8688 */ + .model = IF_SDIO_MODEL_8688, + .helper = "sd8688_helper.bin", + .firmware = "sd8688.bin", + }, }; struct if_sdio_packet { @@ -87,6 +112,7 @@ struct if_sdio_card { int model; unsigned long ioport; + unsigned int scratch_reg; const char *helper; const char *firmware; @@ -98,25 +124,29 @@ struct if_sdio_card { struct workqueue_struct *workqueue; struct work_struct packet_worker; + + u8 rx_unit; }; /********************************************************************/ /* I/O */ /********************************************************************/ +/* + * For SD8385/SD8686, this function reads firmware status after + * the image is downloaded, or reads RX packet length when + * interrupt (with IF_SDIO_H_INT_UPLD bit set) is received. + * For SD8688, this function reads firmware status only. + */ static u16 if_sdio_read_scratch(struct if_sdio_card *card, int *err) { - int ret, reg; + int ret; u16 scratch; - if (card->model == 0x04) - reg = IF_SDIO_SCRATCH_OLD; - else - reg = IF_SDIO_SCRATCH; - - scratch = sdio_readb(card->func, reg, &ret); + scratch = sdio_readb(card->func, card->scratch_reg, &ret); if (!ret) - scratch |= sdio_readb(card->func, reg + 1, &ret) << 8; + scratch |= sdio_readb(card->func, card->scratch_reg + 1, + &ret) << 8; if (err) *err = ret; @@ -127,6 +157,46 @@ static u16 if_sdio_read_scratch(struct if_sdio_card *card, int *err) return scratch; } +static u8 if_sdio_read_rx_unit(struct if_sdio_card *card) +{ + int ret; + u8 rx_unit; + + rx_unit = sdio_readb(card->func, IF_SDIO_RX_UNIT, &ret); + + if (ret) + rx_unit = 0; + + return rx_unit; +} + +static u16 if_sdio_read_rx_len(struct if_sdio_card *card, int *err) +{ + int ret; + u16 rx_len; + + switch (card->model) { + case IF_SDIO_MODEL_8385: + case IF_SDIO_MODEL_8686: + rx_len = if_sdio_read_scratch(card, &ret); + break; + case IF_SDIO_MODEL_8688: + default: /* for newer chipsets */ + rx_len = sdio_readb(card->func, IF_SDIO_RX_LEN, &ret); + if (!ret) + rx_len <<= card->rx_unit; + else + rx_len = 0xffff; /* invalid length */ + + break; + } + + if (err) + *err = ret; + + return rx_len; +} + static int if_sdio_handle_cmd(struct if_sdio_card *card, u8 *buffer, unsigned size) { @@ -207,7 +277,7 @@ static int if_sdio_handle_event(struct if_sdio_card *card, lbs_deb_enter(LBS_DEB_SDIO); - if (card->model == 0x04) { + if (card->model == IF_SDIO_MODEL_8385) { event = sdio_readb(card->func, IF_SDIO_EVENT, &ret); if (ret) goto out; @@ -245,7 +315,7 @@ static int if_sdio_card_to_host(struct if_sdio_card *card) lbs_deb_enter(LBS_DEB_SDIO); - size = if_sdio_read_scratch(card, &ret); + size = if_sdio_read_rx_len(card, &ret); if (ret) goto out; @@ -488,7 +558,6 @@ static int if_sdio_prog_helper(struct if_sdio_card *card) ret = 0; release: - sdio_set_block_size(card->func, 0); sdio_release_host(card->func); kfree(chunk_buffer); release_fw: @@ -624,7 +693,6 @@ static int if_sdio_prog_real(struct if_sdio_card *card) ret = 0; release: - sdio_set_block_size(card->func, 0); sdio_release_host(card->func); kfree(chunk_buffer); release_fw: @@ -653,6 +721,8 @@ static int if_sdio_prog_firmware(struct if_sdio_card *card) if (ret) goto out; + lbs_deb_sdio("firmware status = %#x\n", scratch); + if (scratch == IF_SDIO_FIRMWARE_OK) { lbs_deb_sdio("firmware already loaded\n"); goto success; @@ -667,6 +737,9 @@ static int if_sdio_prog_firmware(struct if_sdio_card *card) goto out; success: + sdio_claim_host(card->func); + sdio_set_block_size(card->func, IF_SDIO_BLOCK_SIZE); + sdio_release_host(card->func); ret = 0; out: @@ -820,10 +893,10 @@ static int if_sdio_probe(struct sdio_func *func, if (sscanf(func->card->info[i], "ID: %x", &model) == 1) break; - if (!strcmp(func->card->info[i], "IBIS Wireless SDIO Card")) { - model = 4; - break; - } + if (!strcmp(func->card->info[i], "IBIS Wireless SDIO Card")) { + model = IF_SDIO_MODEL_8385; + break; + } } if (i == func->card->num_info) { @@ -837,6 +910,20 @@ static int if_sdio_probe(struct sdio_func *func, card->func = func; card->model = model; + + switch (card->model) { + case IF_SDIO_MODEL_8385: + card->scratch_reg = IF_SDIO_SCRATCH_OLD; + break; + case IF_SDIO_MODEL_8686: + card->scratch_reg = IF_SDIO_SCRATCH; + break; + case IF_SDIO_MODEL_8688: + default: /* for newer chipsets */ + card->scratch_reg = IF_SDIO_FW_STATUS; + break; + } + spin_lock_init(&card->lock); card->workqueue = create_workqueue("libertas_sdio"); INIT_WORK(&card->packet_worker, if_sdio_host_to_card_worker); @@ -914,15 +1001,40 @@ static int if_sdio_probe(struct sdio_func *func, priv->fw_ready = 1; + sdio_claim_host(func); + + /* + * Get rx_unit if the chip is SD8688 or newer. + * SD8385 & SD8686 do not have rx_unit. + */ + if ((card->model != IF_SDIO_MODEL_8385) + && (card->model != IF_SDIO_MODEL_8686)) + card->rx_unit = if_sdio_read_rx_unit(card); + else + card->rx_unit = 0; + /* * Enable interrupts now that everything is set up */ - sdio_claim_host(func); sdio_writeb(func, 0x0f, IF_SDIO_H_INT_MASK, &ret); sdio_release_host(func); if (ret) goto reclaim; + /* + * FUNC_INIT is required for SD8688 WLAN/BT multiple functions + */ + if (card->model == IF_SDIO_MODEL_8688) { + struct cmd_header cmd; + + memset(&cmd, 0, sizeof(cmd)); + + lbs_deb_sdio("send function INIT command\n"); + if (__lbs_cmd(priv, CMD_FUNC_INIT, &cmd, sizeof(cmd), + lbs_cmd_copyback, (unsigned long) &cmd)) + lbs_pr_alert("CMD_FUNC_INIT cmd failed\n"); + } + ret = lbs_start_card(priv); if (ret) goto err_activate_card; @@ -968,6 +1080,22 @@ static void if_sdio_remove(struct sdio_func *func) card = sdio_get_drvdata(func); + if (user_rmmod && (card->model == IF_SDIO_MODEL_8688)) { + /* + * FUNC_SHUTDOWN is required for SD8688 WLAN/BT + * multiple functions + */ + struct cmd_header cmd; + + memset(&cmd, 0, sizeof(cmd)); + + lbs_deb_sdio("send function SHUTDOWN command\n"); + if (__lbs_cmd(card->priv, CMD_FUNC_SHUTDOWN, + &cmd, sizeof(cmd), lbs_cmd_copyback, + (unsigned long) &cmd)) + lbs_pr_alert("CMD_FUNC_SHUTDOWN cmd failed\n"); + } + card->priv->surpriseremoved = 1; lbs_deb_sdio("call remove card\n"); @@ -1015,6 +1143,9 @@ static int __init if_sdio_init_module(void) ret = sdio_register_driver(&if_sdio_driver); + /* Clear the flag in case user removes the card. */ + user_rmmod = 0; + lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); return ret; @@ -1024,6 +1155,9 @@ static void __exit if_sdio_exit_module(void) { lbs_deb_enter(LBS_DEB_SDIO); + /* Set the flag as user is removing this module. */ + user_rmmod = 1; + sdio_unregister_driver(&if_sdio_driver); lbs_deb_leave(LBS_DEB_SDIO); diff --git a/drivers/net/wireless/libertas/if_sdio.h b/drivers/net/wireless/libertas/if_sdio.h index 533bdfbf5d2a..60c9b2fcef03 100644 --- a/drivers/net/wireless/libertas/if_sdio.h +++ b/drivers/net/wireless/libertas/if_sdio.h @@ -12,6 +12,10 @@ #ifndef _LBS_IF_SDIO_H #define _LBS_IF_SDIO_H +#define IF_SDIO_MODEL_8385 0x04 +#define IF_SDIO_MODEL_8686 0x0b +#define IF_SDIO_MODEL_8688 0x10 + #define IF_SDIO_IOPORT 0x00 #define IF_SDIO_H_INT_MASK 0x04 @@ -38,8 +42,14 @@ #define IF_SDIO_SCRATCH 0x34 #define IF_SDIO_SCRATCH_OLD 0x80fe +#define IF_SDIO_FW_STATUS 0x40 #define IF_SDIO_FIRMWARE_OK 0xfedc +#define IF_SDIO_RX_LEN 0x42 +#define IF_SDIO_RX_UNIT 0x43 + #define IF_SDIO_EVENT 0x80fc +#define IF_SDIO_BLOCK_SIZE 256 + #endif diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c index 07311e71af92..6564282ce476 100644 --- a/drivers/net/wireless/libertas/if_spi.c +++ b/drivers/net/wireless/libertas/if_spi.c @@ -19,7 +19,6 @@ #include #include -#include #include #include #include @@ -44,20 +43,13 @@ struct if_spi_card { struct lbs_private *priv; struct libertas_spi_platform_data *pdata; - char helper_fw_name[FIRMWARE_NAME_MAX]; - char main_fw_name[FIRMWARE_NAME_MAX]; + char helper_fw_name[IF_SPI_FW_NAME_MAX]; + char main_fw_name[IF_SPI_FW_NAME_MAX]; /* The card ID and card revision, as reported by the hardware. */ u16 card_id; u8 card_rev; - /* Pin number for our GPIO chip-select. */ - /* TODO: Once the generic SPI layer has some additional features, we - * should take this out and use the normal chip select here. - * We need support for chip select delays, and not dropping chipselect - * after each word. */ - int gpio_cs; - /* The last time that we initiated an SPU operation */ unsigned long prev_xfer_time; @@ -119,9 +111,6 @@ static struct chip_ident chip_id_to_device_name[] = { * First we have to put a SPU register name on the bus. Then we can * either read from or write to that register. * - * For 16-bit transactions, byte order on the bus is big-endian. - * We don't have to worry about that here, though. - * The translation takes place in the SPI routines. */ static void spu_transaction_init(struct if_spi_card *card) @@ -133,12 +122,10 @@ static void spu_transaction_init(struct if_spi_card *card) * If not, we have to busy-wait to be on the safe side. */ ndelay(400); } - gpio_set_value(card->gpio_cs, 0); /* assert CS */ } static void spu_transaction_finish(struct if_spi_card *card) { - gpio_set_value(card->gpio_cs, 1); /* drop CS */ card->prev_xfer_time = jiffies; } @@ -147,7 +134,14 @@ static void spu_transaction_finish(struct if_spi_card *card) static int spu_write(struct if_spi_card *card, u16 reg, const u8 *buf, int len) { int err = 0; - u16 reg_out = reg | IF_SPI_WRITE_OPERATION_MASK; + u16 reg_out = cpu_to_le16(reg | IF_SPI_WRITE_OPERATION_MASK); + struct spi_message m; + struct spi_transfer reg_trans; + struct spi_transfer data_trans; + + spi_message_init(&m); + memset(®_trans, 0, sizeof(reg_trans)); + memset(&data_trans, 0, sizeof(data_trans)); /* You must give an even number of bytes to the SPU, even if it * doesn't care about the last one. */ @@ -156,29 +150,26 @@ static int spu_write(struct if_spi_card *card, u16 reg, const u8 *buf, int len) spu_transaction_init(card); /* write SPU register index */ - err = spi_write(card->spi, (u8 *)®_out, sizeof(u16)); - if (err) - goto out; + reg_trans.tx_buf = ®_out; + reg_trans.len = sizeof(reg_out); - err = spi_write(card->spi, buf, len); + data_trans.tx_buf = buf; + data_trans.len = len; -out: + spi_message_add_tail(®_trans, &m); + spi_message_add_tail(&data_trans, &m); + + err = spi_sync(card->spi, &m); spu_transaction_finish(card); return err; } static inline int spu_write_u16(struct if_spi_card *card, u16 reg, u16 val) { - return spu_write(card, reg, (u8 *)&val, sizeof(u16)); -} + u16 buff; -static inline int spu_write_u32(struct if_spi_card *card, u16 reg, u32 val) -{ - /* The lower 16 bits are written first. */ - u16 out[2]; - out[0] = val & 0xffff; - out[1] = (val & 0xffff0000) >> 16; - return spu_write(card, reg, (u8 *)&out, sizeof(u32)); + buff = cpu_to_le16(val); + return spu_write(card, reg, (u8 *)&buff, sizeof(u16)); } static inline int spu_reg_is_port_reg(u16 reg) @@ -195,10 +186,13 @@ static inline int spu_reg_is_port_reg(u16 reg) static int spu_read(struct if_spi_card *card, u16 reg, u8 *buf, int len) { - unsigned int i, delay; + unsigned int delay; int err = 0; - u16 zero = 0; - u16 reg_out = reg | IF_SPI_READ_OPERATION_MASK; + u16 reg_out = cpu_to_le16(reg | IF_SPI_READ_OPERATION_MASK); + struct spi_message m; + struct spi_transfer reg_trans; + struct spi_transfer dummy_trans; + struct spi_transfer data_trans; /* You must take an even number of bytes from the SPU, even if you * don't care about the last one. */ @@ -206,29 +200,34 @@ static int spu_read(struct if_spi_card *card, u16 reg, u8 *buf, int len) spu_transaction_init(card); + spi_message_init(&m); + memset(®_trans, 0, sizeof(reg_trans)); + memset(&dummy_trans, 0, sizeof(dummy_trans)); + memset(&data_trans, 0, sizeof(data_trans)); + /* write SPU register index */ - err = spi_write(card->spi, (u8 *)®_out, sizeof(u16)); - if (err) - goto out; + reg_trans.tx_buf = ®_out; + reg_trans.len = sizeof(reg_out); + spi_message_add_tail(®_trans, &m); delay = spu_reg_is_port_reg(reg) ? card->spu_port_delay : card->spu_reg_delay; if (card->use_dummy_writes) { /* Clock in dummy cycles while the SPU fills the FIFO */ - for (i = 0; i < delay / 16; ++i) { - err = spi_write(card->spi, (u8 *)&zero, sizeof(u16)); - if (err) - return err; - } + dummy_trans.len = delay / 8; + spi_message_add_tail(&dummy_trans, &m); } else { /* Busy-wait while the SPU fills the FIFO */ - ndelay(100 + (delay * 10)); + reg_trans.delay_usecs = + DIV_ROUND_UP((100 + (delay * 10)), 1000); } /* read in data */ - err = spi_read(card->spi, buf, len); + data_trans.rx_buf = buf; + data_trans.len = len; + spi_message_add_tail(&data_trans, &m); -out: + err = spi_sync(card->spi, &m); spu_transaction_finish(card); return err; } @@ -236,18 +235,25 @@ out: /* Read 16 bits from an SPI register */ static inline int spu_read_u16(struct if_spi_card *card, u16 reg, u16 *val) { - return spu_read(card, reg, (u8 *)val, sizeof(u16)); + u16 buf; + int ret; + + ret = spu_read(card, reg, (u8 *)&buf, sizeof(buf)); + if (ret == 0) + *val = le16_to_cpup(&buf); + return ret; } /* Read 32 bits from an SPI register. * The low 16 bits are read first. */ static int spu_read_u32(struct if_spi_card *card, u16 reg, u32 *val) { - u16 buf[2]; + u32 buf; int err; - err = spu_read(card, reg, (u8 *)buf, sizeof(u32)); + + err = spu_read(card, reg, (u8 *)&buf, sizeof(buf)); if (!err) - *val = buf[0] | (buf[1] << 16); + *val = le32_to_cpup(&buf); return err; } @@ -731,7 +737,7 @@ static int if_spi_c2h_data(struct if_spi_card *card) goto out; } else if (len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) { lbs_pr_err("%s: error: card has %d bytes of data, but " - "our maximum skb size is %u\n", + "our maximum skb size is %lu\n", __func__, len, MRVDRV_ETH_RX_PACKET_BUFFER_SIZE); err = -EINVAL; goto out; @@ -806,7 +812,6 @@ out: static void if_spi_e2h(struct if_spi_card *card) { int err = 0; - unsigned long flags; u32 cause; struct lbs_private *priv = card->priv; @@ -814,10 +819,14 @@ static void if_spi_e2h(struct if_spi_card *card) if (err) goto out; - spin_lock_irqsave(&priv->driver_lock, flags); - lbs_queue_event(priv, cause & 0xff); - spin_unlock_irqrestore(&priv->driver_lock, flags); + /* re-enable the card event interrupt */ + spu_write_u16(card, IF_SPI_HOST_INT_STATUS_REG, + ~IF_SPI_HICU_CARD_EVENT); + /* generate a card interrupt */ + spu_write_u16(card, IF_SPI_CARD_INT_CAUSE_REG, IF_SPI_CIC_HOST_EVENT); + + lbs_queue_event(priv, cause & 0xff); out: if (err) lbs_pr_err("%s: error %d\n", __func__, err); @@ -862,7 +871,12 @@ static int lbs_spi_thread(void *data) err = if_spi_c2h_data(card); if (err) goto err; - if (hiStatus & IF_SPI_HIST_CMD_DOWNLOAD_RDY) { + + /* workaround: in PS mode, the card does not set the Command + * Download Ready bit, but it sets TX Download Ready. */ + if (hiStatus & IF_SPI_HIST_CMD_DOWNLOAD_RDY || + (card->priv->psstate != PS_STATE_FULL_POWER && + (hiStatus & IF_SPI_HIST_TX_DOWNLOAD_RDY))) { /* This means two things. First of all, * if there was a previous command sent, the card has * successfully received it. @@ -1006,9 +1020,9 @@ static int if_spi_calculate_fw_names(u16 card_id, lbs_pr_err("Unsupported chip_id: 0x%02x\n", card_id); return -EAFNOSUPPORT; } - snprintf(helper_fw, FIRMWARE_NAME_MAX, "libertas/gspi%d_hlp.bin", + snprintf(helper_fw, IF_SPI_FW_NAME_MAX, "libertas/gspi%d_hlp.bin", chip_id_to_device_name[i].name); - snprintf(main_fw, FIRMWARE_NAME_MAX, "libertas/gspi%d.bin", + snprintf(main_fw, IF_SPI_FW_NAME_MAX, "libertas/gspi%d.bin", chip_id_to_device_name[i].name); return 0; } @@ -1020,6 +1034,7 @@ static int __devinit if_spi_probe(struct spi_device *spi) struct libertas_spi_platform_data *pdata = spi->dev.platform_data; int err = 0; u32 scratch; + struct sched_param param = { .sched_priority = 1 }; lbs_deb_enter(LBS_DEB_SPI); @@ -1043,7 +1058,6 @@ static int __devinit if_spi_probe(struct spi_device *spi) spi_set_drvdata(spi, card); card->pdata = pdata; card->spi = spi; - card->gpio_cs = pdata->gpio_cs; card->prev_xfer_time = jiffies; sema_init(&card->spi_ready, 0); @@ -1052,26 +1066,18 @@ static int __devinit if_spi_probe(struct spi_device *spi) INIT_LIST_HEAD(&card->data_packet_list); spin_lock_init(&card->buffer_lock); - /* set up GPIO CS line. TODO: use regular CS line */ - err = gpio_request(card->gpio_cs, "if_spi_gpio_chip_select"); - if (err) - goto free_card; - err = gpio_direction_output(card->gpio_cs, 1); - if (err) - goto free_gpio; - /* Initialize the SPI Interface Unit */ err = spu_init(card, pdata->use_dummy_writes); if (err) - goto free_gpio; + goto free_card; err = spu_get_chip_revision(card, &card->card_id, &card->card_rev); if (err) - goto free_gpio; + goto free_card; /* Firmware load */ err = spu_read_u32(card, IF_SPI_SCRATCH_4_REG, &scratch); if (err) - goto free_gpio; + goto free_card; if (scratch == SUCCESSFUL_FW_DOWNLOAD_MAGIC) lbs_deb_spi("Firmware is already loaded for " "Marvell WLAN 802.11 adapter\n"); @@ -1079,7 +1085,7 @@ static int __devinit if_spi_probe(struct spi_device *spi) err = if_spi_calculate_fw_names(card->card_id, card->helper_fw_name, card->main_fw_name); if (err) - goto free_gpio; + goto free_card; lbs_deb_spi("Initializing FW for Marvell WLAN 802.11 adapter " "(chip_id = 0x%04x, chip_rev = 0x%02x) " @@ -1090,23 +1096,23 @@ static int __devinit if_spi_probe(struct spi_device *spi) spi->max_speed_hz); err = if_spi_prog_helper_firmware(card); if (err) - goto free_gpio; + goto free_card; err = if_spi_prog_main_firmware(card); if (err) - goto free_gpio; + goto free_card; lbs_deb_spi("loaded FW for Marvell WLAN 802.11 adapter\n"); } err = spu_set_interrupt_mode(card, 0, 1); if (err) - goto free_gpio; + goto free_card; /* Register our card with libertas. * This will call alloc_etherdev */ priv = lbs_add_card(card, &spi->dev); if (!priv) { err = -ENOMEM; - goto free_gpio; + goto free_card; } card->priv = priv; priv->card = card; @@ -1123,6 +1129,9 @@ static int __devinit if_spi_probe(struct spi_device *spi) lbs_pr_err("error creating SPI thread: err=%d\n", err); goto remove_card; } + if (sched_setscheduler(card->spi_thread, SCHED_FIFO, ¶m)) + lbs_pr_err("Error setting scheduler, using default.\n"); + err = request_irq(spi->irq, if_spi_host_interrupt, IRQF_TRIGGER_FALLING, "libertas_spi", card); if (err) { @@ -1148,8 +1157,6 @@ terminate_thread: if_spi_terminate_spi_thread(card); remove_card: lbs_remove_card(priv); /* will call free_netdev */ -free_gpio: - gpio_free(card->gpio_cs); free_card: free_if_spi_card(card); out: @@ -1170,7 +1177,6 @@ static int __devexit libertas_spi_remove(struct spi_device *spi) free_irq(spi->irq, card); if_spi_terminate_spi_thread(card); lbs_remove_card(priv); /* will call free_netdev */ - gpio_free(card->gpio_cs); if (card->pdata->teardown) card->pdata->teardown(spi); free_if_spi_card(card); diff --git a/drivers/net/wireless/libertas/if_spi.h b/drivers/net/wireless/libertas/if_spi.h index 2103869cc5b0..f87eec410848 100644 --- a/drivers/net/wireless/libertas/if_spi.h +++ b/drivers/net/wireless/libertas/if_spi.h @@ -22,6 +22,9 @@ #define IF_SPI_CMD_BUF_SIZE 2400 /***************** Firmware *****************/ + +#define IF_SPI_FW_NAME_MAX 30 + struct chip_ident { u16 chip_id; u16 name; diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index ea3dc038be76..1844c5adf6e9 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -61,11 +61,9 @@ static ssize_t if_usb_firmware_set(struct device *dev, { struct lbs_private *priv = to_net_dev(dev)->ml_priv; struct if_usb_card *cardp = priv->card; - char fwname[FIRMWARE_NAME_MAX]; int ret; - sscanf(buf, "%29s", fwname); /* FIRMWARE_NAME_MAX - 1 = 29 */ - ret = if_usb_prog_firmware(cardp, fwname, BOOT_CMD_UPDATE_FW); + ret = if_usb_prog_firmware(cardp, buf, BOOT_CMD_UPDATE_FW); if (ret == 0) return count; @@ -88,11 +86,9 @@ static ssize_t if_usb_boot2_set(struct device *dev, { struct lbs_private *priv = to_net_dev(dev)->ml_priv; struct if_usb_card *cardp = priv->card; - char fwname[FIRMWARE_NAME_MAX]; int ret; - sscanf(buf, "%29s", fwname); /* FIRMWARE_NAME_MAX - 1 = 29 */ - ret = if_usb_prog_firmware(cardp, fwname, BOOT_CMD_UPDATE_BOOT2); + ret = if_usb_prog_firmware(cardp, buf, BOOT_CMD_UPDATE_BOOT2); if (ret == 0) return count; @@ -686,8 +682,7 @@ static inline void process_cmdrequest(int recvlength, uint8_t *recvbuff, return; } - if (!in_interrupt()) - BUG(); + BUG_ON(!in_interrupt()); spin_lock(&priv->driver_lock); diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 8ae935ac32f1..89575e448015 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1307,8 +1307,10 @@ int lbs_start_card(struct lbs_private *priv) lbs_update_channel(priv); - /* 5.0.16p0 is known to NOT support any mesh */ - if (priv->fwrelease > 0x05001000) { + /* Check mesh FW version and appropriately send the mesh start + * command + */ + if (priv->mesh_fw_ver == MESH_FW_OLD) { /* Enable mesh, if supported, and work out which TLV it uses. 0x100 + 291 is an unofficial value used in 5.110.20.pXX 0x100 + 37 is the official value used in 5.110.21.pXX @@ -1322,27 +1324,35 @@ int lbs_start_card(struct lbs_private *priv) It's just that 5.110.20.pXX will not have done anything useful */ - priv->mesh_tlv = 0x100 + 291; + priv->mesh_tlv = TLV_TYPE_OLD_MESH_ID; if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, priv->curbssparams.channel)) { - priv->mesh_tlv = 0x100 + 37; + priv->mesh_tlv = TLV_TYPE_MESH_ID; if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, priv->curbssparams.channel)) priv->mesh_tlv = 0; } - if (priv->mesh_tlv) { - lbs_add_mesh(priv); + } else if (priv->mesh_fw_ver == MESH_FW_NEW) { + /* 10.0.0.pXX new firmwares should succeed with TLV + * 0x100+37; Do not invoke command with old TLV. + */ + priv->mesh_tlv = TLV_TYPE_MESH_ID; + if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, + priv->curbssparams.channel)) + priv->mesh_tlv = 0; + } + if (priv->mesh_tlv) { + lbs_add_mesh(priv); - if (device_create_file(&dev->dev, &dev_attr_lbs_mesh)) - lbs_pr_err("cannot register lbs_mesh attribute\n"); + if (device_create_file(&dev->dev, &dev_attr_lbs_mesh)) + lbs_pr_err("cannot register lbs_mesh attribute\n"); - /* While rtap isn't related to mesh, only mesh-enabled - * firmware implements the rtap functionality via - * CMD_802_11_MONITOR_MODE. - */ - if (device_create_file(&dev->dev, &dev_attr_lbs_rtap)) - lbs_pr_err("cannot register lbs_rtap attribute\n"); - } + /* While rtap isn't related to mesh, only mesh-enabled + * firmware implements the rtap functionality via + * CMD_802_11_MONITOR_MODE. + */ + if (device_create_file(&dev->dev, &dev_attr_lbs_rtap)) + lbs_pr_err("cannot register lbs_rtap attribute\n"); } lbs_debugfs_init_one(priv, dev); diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c index 8e669775cb5d..65f02cc6752f 100644 --- a/drivers/net/wireless/libertas/rx.c +++ b/drivers/net/wireless/libertas/rx.c @@ -25,7 +25,6 @@ struct rfc1042hdr { } __attribute__ ((packed)); struct rxpackethdr { - struct rxpd rx_pd; struct eth803hdr eth803_hdr; struct rfc1042hdr rfc1042_hdr; } __attribute__ ((packed)); @@ -158,10 +157,18 @@ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb) if (priv->monitormode) return process_rxed_802_11_packet(priv, skb); - p_rx_pkt = (struct rxpackethdr *) skb->data; - p_rx_pd = &p_rx_pkt->rx_pd; - if (priv->mesh_dev && (p_rx_pd->rx_control & RxPD_MESH_FRAME)) - dev = priv->mesh_dev; + p_rx_pd = (struct rxpd *) skb->data; + p_rx_pkt = (struct rxpackethdr *) ((u8 *)p_rx_pd + + le32_to_cpu(p_rx_pd->pkt_ptr)); + if (priv->mesh_dev) { + if (priv->mesh_fw_ver == MESH_FW_OLD) { + if (p_rx_pd->rx_control & RxPD_MESH_FRAME) + dev = priv->mesh_dev; + } else if (priv->mesh_fw_ver == MESH_FW_NEW) { + if (p_rx_pd->u.bss.bss_num == MESH_IFACE_ID) + dev = priv->mesh_dev; + } + } lbs_deb_hex(LBS_DEB_RX, "RX Data: Before chop rxpd", skb->data, min_t(unsigned int, skb->len, 100)); @@ -174,20 +181,9 @@ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb) goto done; } - /* - * Check rxpd status and update 802.3 stat, - */ - if (!(p_rx_pd->status & cpu_to_le16(MRVDRV_RXPD_STATUS_OK))) { - lbs_deb_rx("rx err: frame received with bad status\n"); - lbs_pr_alert("rxpd not ok\n"); - dev->stats.rx_errors++; - ret = 0; - dev_kfree_skb(skb); - goto done; - } - - lbs_deb_rx("rx data: skb->len-sizeof(RxPd) = %d-%zd = %zd\n", - skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd)); + lbs_deb_rx("rx data: skb->len - pkt_ptr = %d-%zd = %zd\n", + skb->len, (size_t)le32_to_cpu(p_rx_pd->pkt_ptr), + skb->len - (size_t)le32_to_cpu(p_rx_pd->pkt_ptr)); lbs_deb_hex(LBS_DEB_RX, "RX Data: Dest", p_rx_pkt->eth803_hdr.dest_addr, sizeof(p_rx_pkt->eth803_hdr.dest_addr)); @@ -221,14 +217,14 @@ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb) /* Chop off the rxpd + the excess memory from the 802.2/llc/snap header * that was removed */ - hdrchop = (u8 *) p_ethhdr - (u8 *) p_rx_pkt; + hdrchop = (u8 *)p_ethhdr - (u8 *)p_rx_pd; } else { lbs_deb_hex(LBS_DEB_RX, "RX Data: LLC/SNAP", (u8 *) & p_rx_pkt->rfc1042_hdr, sizeof(p_rx_pkt->rfc1042_hdr)); /* Chop off the rxpd */ - hdrchop = (u8 *) & p_rx_pkt->eth803_hdr - (u8 *) p_rx_pkt; + hdrchop = (u8 *)&p_rx_pkt->eth803_hdr - (u8 *)p_rx_pd; } /* Chop off the leading header bytes so the skb points to the start of @@ -334,14 +330,6 @@ static int process_rxed_802_11_packet(struct lbs_private *priv, goto done; } - /* - * Check rxpd status and update 802.3 stat, - */ - if (!(prxpd->status & cpu_to_le16(MRVDRV_RXPD_STATUS_OK))) { - //lbs_deb_rx("rx err: frame received with bad status\n"); - dev->stats.rx_errors++; - } - lbs_deb_rx("rx data: skb->len-sizeof(RxPd) = %d-%zd = %zd\n", skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd)); @@ -353,8 +341,6 @@ static int process_rxed_802_11_packet(struct lbs_private *priv, radiotap_hdr.hdr.it_pad = 0; radiotap_hdr.hdr.it_len = cpu_to_le16 (sizeof(struct rx_radiotap_hdr)); radiotap_hdr.hdr.it_present = cpu_to_le32 (RX_RADIOTAP_PRESENT); - if (!(prxpd->status & cpu_to_le16(MRVDRV_RXPD_STATUS_OK))) - radiotap_hdr.flags |= IEEE80211_RADIOTAP_F_BADFCS; radiotap_hdr.rate = convert_mv_rate_to_radiotap(prxpd->rx_rate); /* XXX must check no carryout */ radiotap_hdr.antsignal = prxpd->snr + prxpd->nf; diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 8124db36aaff..601b54249677 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -27,12 +27,12 @@ + 40) /* 40 for WPAIE */ //! Memory needed to store a max sized channel List TLV for a firmware scan -#define CHAN_TLV_MAX_SIZE (sizeof(struct mrvlietypesheader) \ +#define CHAN_TLV_MAX_SIZE (sizeof(struct mrvl_ie_header) \ + (MRVDRV_MAX_CHANNELS_PER_SCAN \ * sizeof(struct chanscanparamset))) //! Memory needed to store a max number/size SSID TLV for a firmware scan -#define SSID_TLV_MAX_SIZE (1 * sizeof(struct mrvlietypes_ssidparamset)) +#define SSID_TLV_MAX_SIZE (1 * sizeof(struct mrvl_ie_ssid_param_set)) //! Maximum memory needed for a cmd_ds_802_11_scan with all TLVs at max #define MAX_SCAN_CFG_ALLOC (sizeof(struct cmd_ds_802_11_scan) \ @@ -211,7 +211,7 @@ static int lbs_scan_create_channel_list(struct lbs_private *priv, */ static int lbs_scan_add_ssid_tlv(struct lbs_private *priv, u8 *tlv) { - struct mrvlietypes_ssidparamset *ssid_tlv = (void *)tlv; + struct mrvl_ie_ssid_param_set *ssid_tlv = (void *)tlv; ssid_tlv->header.type = cpu_to_le16(TLV_TYPE_SSID); ssid_tlv->header.len = cpu_to_le16(priv->scan_ssid_len); @@ -249,7 +249,7 @@ static int lbs_scan_add_chanlist_tlv(uint8_t *tlv, int chan_count) { size_t size = sizeof(struct chanscanparamset) *chan_count; - struct mrvlietypes_chanlistparamset *chan_tlv = (void *)tlv; + struct mrvl_ie_chanlist_param_set *chan_tlv = (void *)tlv; chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); memcpy(chan_tlv->chanscanparam, chan_list, size); @@ -270,7 +270,7 @@ static int lbs_scan_add_chanlist_tlv(uint8_t *tlv, static int lbs_scan_add_rates_tlv(uint8_t *tlv) { int i; - struct mrvlietypes_ratesparamset *rate_tlv = (void *)tlv; + struct mrvl_ie_rates_param_set *rate_tlv = (void *)tlv; rate_tlv->header.type = cpu_to_le16(TLV_TYPE_RATES); tlv += sizeof(rate_tlv->header); @@ -513,12 +513,12 @@ void lbs_scan_worker(struct work_struct *work) static int lbs_process_bss(struct bss_descriptor *bss, uint8_t **pbeaconinfo, int *bytesleft) { - struct ieeetypes_fhparamset *pFH; - struct ieeetypes_dsparamset *pDS; - struct ieeetypes_cfparamset *pCF; - struct ieeetypes_ibssparamset *pibss; + struct ieee_ie_fh_param_set *fh; + struct ieee_ie_ds_param_set *ds; + struct ieee_ie_cf_param_set *cf; + struct ieee_ie_ibss_param_set *ibss; DECLARE_SSID_BUF(ssid); - struct ieeetypes_countryinfoset *pcountryinfo; + struct ieee_ie_country_info_set *pcountryinfo; uint8_t *pos, *end, *p; uint8_t n_ex_rates = 0, got_basic_rates = 0, n_basic_rates = 0; uint16_t beaconsize = 0; @@ -616,50 +616,49 @@ static int lbs_process_bss(struct bss_descriptor *bss, break; case WLAN_EID_FH_PARAMS: - pFH = (struct ieeetypes_fhparamset *) pos; - memmove(&bss->phyparamset.fhparamset, pFH, - sizeof(struct ieeetypes_fhparamset)); + fh = (struct ieee_ie_fh_param_set *) pos; + memcpy(&bss->phy.fh, fh, sizeof(*fh)); lbs_deb_scan("got FH IE\n"); break; case WLAN_EID_DS_PARAMS: - pDS = (struct ieeetypes_dsparamset *) pos; - bss->channel = pDS->currentchan; - memcpy(&bss->phyparamset.dsparamset, pDS, - sizeof(struct ieeetypes_dsparamset)); + ds = (struct ieee_ie_ds_param_set *) pos; + bss->channel = ds->channel; + memcpy(&bss->phy.ds, ds, sizeof(*ds)); lbs_deb_scan("got DS IE, channel %d\n", bss->channel); break; case WLAN_EID_CF_PARAMS: - pCF = (struct ieeetypes_cfparamset *) pos; - memcpy(&bss->ssparamset.cfparamset, pCF, - sizeof(struct ieeetypes_cfparamset)); + cf = (struct ieee_ie_cf_param_set *) pos; + memcpy(&bss->ss.cf, cf, sizeof(*cf)); lbs_deb_scan("got CF IE\n"); break; case WLAN_EID_IBSS_PARAMS: - pibss = (struct ieeetypes_ibssparamset *) pos; - bss->atimwindow = le16_to_cpu(pibss->atimwindow); - memmove(&bss->ssparamset.ibssparamset, pibss, - sizeof(struct ieeetypes_ibssparamset)); + ibss = (struct ieee_ie_ibss_param_set *) pos; + bss->atimwindow = ibss->atimwindow; + memcpy(&bss->ss.ibss, ibss, sizeof(*ibss)); lbs_deb_scan("got IBSS IE\n"); break; case WLAN_EID_COUNTRY: - pcountryinfo = (struct ieeetypes_countryinfoset *) pos; + pcountryinfo = (struct ieee_ie_country_info_set *) pos; lbs_deb_scan("got COUNTRY IE\n"); - if (pcountryinfo->len < sizeof(pcountryinfo->countrycode) - || pcountryinfo->len > 254) { - lbs_deb_scan("process_bss: 11D- Err CountryInfo len %d, min %zd, max 254\n", - pcountryinfo->len, sizeof(pcountryinfo->countrycode)); + if (pcountryinfo->header.len < sizeof(pcountryinfo->countrycode) + || pcountryinfo->header.len > 254) { + lbs_deb_scan("%s: 11D- Err CountryInfo len %d, min %zd, max 254\n", + __func__, + pcountryinfo->header.len, + sizeof(pcountryinfo->countrycode)); ret = -1; goto done; } - memcpy(&bss->countryinfo, pcountryinfo, pcountryinfo->len + 2); + memcpy(&bss->countryinfo, pcountryinfo, + pcountryinfo->header.len + 2); lbs_deb_hex(LBS_DEB_SCAN, "process_bss: 11d countryinfo", (uint8_t *) pcountryinfo, - (int) (pcountryinfo->len + 2)); + (int) (pcountryinfo->header.len + 2)); break; case WLAN_EID_EXT_SUPP_RATES: @@ -1130,7 +1129,7 @@ static int lbs_ret_80211_scan(struct lbs_private *priv, unsigned long dummy, goto done; } - bytesleft = le16_to_cpu(scanresp->bssdescriptsize); + bytesleft = get_unaligned_le16(&scanresp->bssdescriptsize); lbs_deb_scan("SCAN_RESP: bssdescriptsize %d\n", bytesleft); scanrespsize = le16_to_cpu(resp->size); diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c index f10aa39a6b68..160cfd8311c0 100644 --- a/drivers/net/wireless/libertas/tx.c +++ b/drivers/net/wireless/libertas/tx.c @@ -132,8 +132,12 @@ int lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) txpd->tx_packet_length = cpu_to_le16(pkt_len); txpd->tx_packet_location = cpu_to_le32(sizeof(struct txpd)); - if (dev == priv->mesh_dev) - txpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME); + if (dev == priv->mesh_dev) { + if (priv->mesh_fw_ver == MESH_FW_OLD) + txpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME); + else if (priv->mesh_fw_ver == MESH_FW_NEW) + txpd->u.bss.bss_num = MESH_IFACE_ID; + } lbs_deb_hex(LBS_DEB_TX, "txpd", (u8 *) &txpd, sizeof(struct txpd)); diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h index fb7a2d1a2525..99905df65b25 100644 --- a/drivers/net/wireless/libertas/types.h +++ b/drivers/net/wireless/libertas/types.h @@ -8,9 +8,14 @@ #include #include -struct ieeetypes_cfparamset { - u8 elementid; +struct ieee_ie_header { + u8 id; u8 len; +} __attribute__ ((packed)); + +struct ieee_ie_cf_param_set { + struct ieee_ie_header header; + u8 cfpcnt; u8 cfpperiod; __le16 cfpmaxduration; @@ -18,42 +23,35 @@ struct ieeetypes_cfparamset { } __attribute__ ((packed)); -struct ieeetypes_ibssparamset { - u8 elementid; - u8 len; +struct ieee_ie_ibss_param_set { + struct ieee_ie_header header; + __le16 atimwindow; } __attribute__ ((packed)); -union IEEEtypes_ssparamset { - struct ieeetypes_cfparamset cfparamset; - struct ieeetypes_ibssparamset ibssparamset; +union ieee_ss_param_set { + struct ieee_ie_cf_param_set cf; + struct ieee_ie_ibss_param_set ibss; } __attribute__ ((packed)); -struct ieeetypes_fhparamset { - u8 elementid; - u8 len; +struct ieee_ie_fh_param_set { + struct ieee_ie_header header; + __le16 dwelltime; u8 hopset; u8 hoppattern; u8 hopindex; } __attribute__ ((packed)); -struct ieeetypes_dsparamset { - u8 elementid; - u8 len; - u8 currentchan; +struct ieee_ie_ds_param_set { + struct ieee_ie_header header; + + u8 channel; } __attribute__ ((packed)); -union ieeetypes_phyparamset { - struct ieeetypes_fhparamset fhparamset; - struct ieeetypes_dsparamset dsparamset; -} __attribute__ ((packed)); - -struct ieeetypes_assocrsp { - __le16 capability; - __le16 statuscode; - __le16 aid; - u8 iebuffer[1]; +union ieee_phy_param_set { + struct ieee_ie_fh_param_set fh; + struct ieee_ie_ds_param_set ds; } __attribute__ ((packed)); /** TLV type ID definition */ @@ -94,30 +92,33 @@ struct ieeetypes_assocrsp { #define TLV_TYPE_TSFTIMESTAMP (PROPRIETARY_TLV_BASE_ID + 19) #define TLV_TYPE_RSSI_HIGH (PROPRIETARY_TLV_BASE_ID + 22) #define TLV_TYPE_SNR_HIGH (PROPRIETARY_TLV_BASE_ID + 23) +#define TLV_TYPE_AUTH_TYPE (PROPRIETARY_TLV_BASE_ID + 31) +#define TLV_TYPE_MESH_ID (PROPRIETARY_TLV_BASE_ID + 37) +#define TLV_TYPE_OLD_MESH_ID (PROPRIETARY_TLV_BASE_ID + 291) /** TLV related data structures*/ -struct mrvlietypesheader { +struct mrvl_ie_header { __le16 type; __le16 len; } __attribute__ ((packed)); -struct mrvlietypes_data { - struct mrvlietypesheader header; +struct mrvl_ie_data { + struct mrvl_ie_header header; u8 Data[1]; } __attribute__ ((packed)); -struct mrvlietypes_ratesparamset { - struct mrvlietypesheader header; +struct mrvl_ie_rates_param_set { + struct mrvl_ie_header header; u8 rates[1]; } __attribute__ ((packed)); -struct mrvlietypes_ssidparamset { - struct mrvlietypesheader header; +struct mrvl_ie_ssid_param_set { + struct mrvl_ie_header header; u8 ssid[1]; } __attribute__ ((packed)); -struct mrvlietypes_wildcardssidparamset { - struct mrvlietypesheader header; +struct mrvl_ie_wildcard_ssid_param_set { + struct mrvl_ie_header header; u8 MaxSsidlength; u8 ssid[1]; } __attribute__ ((packed)); @@ -142,91 +143,72 @@ struct chanscanparamset { __le16 maxscantime; } __attribute__ ((packed)); -struct mrvlietypes_chanlistparamset { - struct mrvlietypesheader header; +struct mrvl_ie_chanlist_param_set { + struct mrvl_ie_header header; struct chanscanparamset chanscanparam[1]; } __attribute__ ((packed)); -struct cfparamset { +struct mrvl_ie_cf_param_set { + struct mrvl_ie_header header; u8 cfpcnt; u8 cfpperiod; __le16 cfpmaxduration; __le16 cfpdurationremaining; } __attribute__ ((packed)); -struct ibssparamset { - __le16 atimwindow; +struct mrvl_ie_ds_param_set { + struct mrvl_ie_header header; + u8 channel; } __attribute__ ((packed)); -struct mrvlietypes_ssparamset { - struct mrvlietypesheader header; - union { - struct cfparamset cfparamset[1]; - struct ibssparamset ibssparamset[1]; - } cf_ibss; -} __attribute__ ((packed)); - -struct fhparamset { - __le16 dwelltime; - u8 hopset; - u8 hoppattern; - u8 hopindex; -} __attribute__ ((packed)); - -struct dsparamset { - u8 currentchan; -} __attribute__ ((packed)); - -struct mrvlietypes_phyparamset { - struct mrvlietypesheader header; - union { - struct fhparamset fhparamset[1]; - struct dsparamset dsparamset[1]; - } fh_ds; -} __attribute__ ((packed)); - -struct mrvlietypes_rsnparamset { - struct mrvlietypesheader header; +struct mrvl_ie_rsn_param_set { + struct mrvl_ie_header header; u8 rsnie[1]; } __attribute__ ((packed)); -struct mrvlietypes_tsftimestamp { - struct mrvlietypesheader header; +struct mrvl_ie_tsf_timestamp { + struct mrvl_ie_header header; __le64 tsftable[1]; } __attribute__ ((packed)); +/* v9 and later firmware only */ +struct mrvl_ie_auth_type { + struct mrvl_ie_header header; + __le16 auth; +} __attribute__ ((packed)); + /** Local Power capability */ -struct mrvlietypes_powercapability { - struct mrvlietypesheader header; +struct mrvl_ie_power_capability { + struct mrvl_ie_header header; s8 minpower; s8 maxpower; } __attribute__ ((packed)); /* used in CMD_802_11_SUBSCRIBE_EVENT for SNR, RSSI and Failure */ -struct mrvlietypes_thresholds { - struct mrvlietypesheader header; +struct mrvl_ie_thresholds { + struct mrvl_ie_header header; u8 value; u8 freq; } __attribute__ ((packed)); -struct mrvlietypes_beaconsmissed { - struct mrvlietypesheader header; +struct mrvl_ie_beacons_missed { + struct mrvl_ie_header header; u8 beaconmissed; u8 reserved; } __attribute__ ((packed)); -struct mrvlietypes_numprobes { - struct mrvlietypesheader header; +struct mrvl_ie_num_probes { + struct mrvl_ie_header header; __le16 numprobes; } __attribute__ ((packed)); -struct mrvlietypes_bcastprobe { - struct mrvlietypesheader header; +struct mrvl_ie_bcast_probe { + struct mrvl_ie_header header; __le16 bcastprobe; } __attribute__ ((packed)); -struct mrvlietypes_numssidprobe { - struct mrvlietypesheader header; +struct mrvl_ie_num_ssid_probe { + struct mrvl_ie_header header; __le16 numssidprobe; } __attribute__ ((packed)); @@ -235,8 +217,8 @@ struct led_pin { u8 pin; } __attribute__ ((packed)); -struct mrvlietypes_ledgpio { - struct mrvlietypesheader header; +struct mrvl_ie_ledgpio { + struct mrvl_ie_header header; struct led_pin ledpin[1]; } __attribute__ ((packed)); @@ -248,8 +230,8 @@ struct led_bhv { } __attribute__ ((packed)); -struct mrvlietypes_ledbhv { - struct mrvlietypesheader header; +struct mrvl_ie_ledbhv { + struct mrvl_ie_header header; struct led_bhv ledbhv[1]; } __attribute__ ((packed)); diff --git a/drivers/net/wireless/libertas_tf/if_usb.c b/drivers/net/wireless/libertas_tf/if_usb.c index 59634c33b1f9..392337b37b1d 100644 --- a/drivers/net/wireless/libertas_tf/if_usb.c +++ b/drivers/net/wireless/libertas_tf/if_usb.c @@ -461,8 +461,7 @@ static inline void process_cmdrequest(int recvlength, uint8_t *recvbuff, return; } - if (!in_interrupt()) - BUG(); + BUG_ON(!in_interrupt()); spin_lock(&priv->driver_lock); memcpy(priv->cmd_resp_buff, recvbuff + MESSAGE_HEADER_LEN, diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c index e7289e2e7f16..10a99e26d392 100644 --- a/drivers/net/wireless/libertas_tf/main.c +++ b/drivers/net/wireless/libertas_tf/main.c @@ -366,36 +366,6 @@ static int lbtf_op_config(struct ieee80211_hw *hw, u32 changed) return 0; } -static int lbtf_op_config_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_if_conf *conf) -{ - struct lbtf_private *priv = hw->priv; - struct sk_buff *beacon; - - switch (priv->vif->type) { - case NL80211_IFTYPE_AP: - case NL80211_IFTYPE_MESH_POINT: - beacon = ieee80211_beacon_get(hw, vif); - if (beacon) { - lbtf_beacon_set(priv, beacon); - kfree_skb(beacon); - lbtf_beacon_ctrl(priv, 1, hw->conf.beacon_int); - } - break; - default: - break; - } - - if (conf->bssid) { - u8 null_bssid[ETH_ALEN] = {0}; - bool activate = compare_ether_addr(conf->bssid, null_bssid); - lbtf_set_bssid(priv, activate, conf->bssid); - } - - return 0; -} - #define SUPPORTED_FIF_FLAGS (FIF_PROMISC_IN_BSS | FIF_ALLMULTI) static void lbtf_op_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, @@ -451,6 +421,29 @@ static void lbtf_op_bss_info_changed(struct ieee80211_hw *hw, u32 changes) { struct lbtf_private *priv = hw->priv; + struct sk_buff *beacon; + + if (changes & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_INT)) { + switch (priv->vif->type) { + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_MESH_POINT: + beacon = ieee80211_beacon_get(hw, vif); + if (beacon) { + lbtf_beacon_set(priv, beacon); + kfree_skb(beacon); + lbtf_beacon_ctrl(priv, 1, + bss_conf->beacon_int); + } + break; + default: + break; + } + } + + if (changes & BSS_CHANGED_BSSID) { + bool activate = !is_zero_ether_addr(bss_conf->bssid); + lbtf_set_bssid(priv, activate, bss_conf->bssid); + } if (changes & BSS_CHANGED_ERP_PREAMBLE) { if (bss_conf->use_short_preamble) @@ -459,8 +452,6 @@ static void lbtf_op_bss_info_changed(struct ieee80211_hw *hw, priv->preamble = CMD_TYPE_LONG_PREAMBLE; lbtf_set_radio_control(priv); } - - return; } static const struct ieee80211_ops lbtf_ops = { @@ -470,7 +461,6 @@ static const struct ieee80211_ops lbtf_ops = { .add_interface = lbtf_op_add_interface, .remove_interface = lbtf_op_remove_interface, .config = lbtf_op_config, - .config_interface = lbtf_op_config_interface, .configure_filter = lbtf_op_configure_filter, .bss_info_changed = lbtf_op_bss_info_changed, }; diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index d4fdc8b7d7d8..e789c6e9938c 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -280,7 +280,6 @@ struct mac80211_hwsim_data { struct ieee80211_rate rates[ARRAY_SIZE(hwsim_rates)]; struct ieee80211_channel *channel; - int radio_enabled; unsigned long beacon_int; /* in jiffies unit */ unsigned int rx_filter; int started; @@ -291,6 +290,14 @@ struct mac80211_hwsim_data { bool ps_poll_pending; struct dentry *debugfs; struct dentry *debugfs_ps; + + /* + * Only radios in the same group can communicate together (the + * channel has to match too). Each bit represents a group. A + * radio can be in more then one group. + */ + u64 group; + struct dentry *debugfs_group; }; @@ -410,9 +417,9 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, if (data == data2) continue; - if (!data2->started || !data2->radio_enabled || - !hwsim_ps_rx_ok(data2, skb) || - data->channel->center_freq != data2->channel->center_freq) + if (!data2->started || !hwsim_ps_rx_ok(data2, skb) || + data->channel->center_freq != data2->channel->center_freq || + !(data->group & data2->group)) continue; nskb = skb_copy(skb, GFP_ATOMIC); @@ -432,7 +439,6 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, static int mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { - struct mac80211_hwsim_data *data = hw->priv; bool ack; struct ieee80211_tx_info *txi; @@ -444,13 +450,6 @@ static int mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb) return NETDEV_TX_OK; } - if (!data->radio_enabled) { - printk(KERN_DEBUG "%s: dropped TX frame since radio " - "disabled\n", wiphy_name(hw->wiphy)); - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } - ack = mac80211_hwsim_tx_frame(hw, skb); txi = IEEE80211_SKB_CB(skb); @@ -537,7 +536,7 @@ static void mac80211_hwsim_beacon(unsigned long arg) struct ieee80211_hw *hw = (struct ieee80211_hw *) arg; struct mac80211_hwsim_data *data = hw->priv; - if (!data->started || !data->radio_enabled) + if (!data->started) return; ieee80211_iterate_active_interfaces_atomic( @@ -553,18 +552,14 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed) struct mac80211_hwsim_data *data = hw->priv; struct ieee80211_conf *conf = &hw->conf; - printk(KERN_DEBUG "%s:%s (freq=%d radio_enabled=%d beacon_int=%d)\n", + printk(KERN_DEBUG "%s:%s (freq=%d idle=%d ps=%d)\n", wiphy_name(hw->wiphy), __func__, - conf->channel->center_freq, conf->radio_enabled, - conf->beacon_int); + conf->channel->center_freq, + !!(conf->flags & IEEE80211_CONF_IDLE), + !!(conf->flags & IEEE80211_CONF_PS)); data->channel = conf->channel; - data->radio_enabled = conf->radio_enabled; - data->beacon_int = 1024 * conf->beacon_int / 1000 * HZ / 1000; - if (data->beacon_int < 1) - data->beacon_int = 1; - - if (!data->started || !data->radio_enabled) + if (!data->started || !data->beacon_int) del_timer(&data->beacon_timer); else mod_timer(&data->beacon_timer, jiffies + data->beacon_int); @@ -592,35 +587,26 @@ static void mac80211_hwsim_configure_filter(struct ieee80211_hw *hw, *total_flags = data->rx_filter; } -static int mac80211_hwsim_config_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_if_conf *conf) -{ - struct hwsim_vif_priv *vp = (void *)vif->drv_priv; - - hwsim_check_magic(vif); - if (conf->changed & IEEE80211_IFCC_BSSID) { - DECLARE_MAC_BUF(mac); - printk(KERN_DEBUG "%s:%s: BSSID changed: %pM\n", - wiphy_name(hw->wiphy), __func__, - conf->bssid); - memcpy(vp->bssid, conf->bssid, ETH_ALEN); - } - return 0; -} - static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, u32 changed) { struct hwsim_vif_priv *vp = (void *)vif->drv_priv; + struct mac80211_hwsim_data *data = hw->priv; hwsim_check_magic(vif); printk(KERN_DEBUG "%s:%s(changed=0x%x)\n", wiphy_name(hw->wiphy), __func__, changed); + if (changed & BSS_CHANGED_BSSID) { + printk(KERN_DEBUG "%s:%s: BSSID changed: %pM\n", + wiphy_name(hw->wiphy), __func__, + info->bssid); + memcpy(vp->bssid, info->bssid, ETH_ALEN); + } + if (changed & BSS_CHANGED_ASSOC) { printk(KERN_DEBUG " %s: ASSOC: assoc=%d aid=%d\n", wiphy_name(hw->wiphy), info->assoc, info->aid); @@ -628,6 +614,14 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw, vp->aid = info->aid; } + if (changed & BSS_CHANGED_BEACON_INT) { + printk(KERN_DEBUG " %s: BCNINT: %d\n", + wiphy_name(hw->wiphy), info->beacon_int); + data->beacon_int = 1024 * info->beacon_int / 1000 * HZ / 1000; + if (WARN_ON(!data->beacon_int)) + data->beacon_int = 1; + } + if (changed & BSS_CHANGED_ERP_CTS_PROT) { printk(KERN_DEBUG " %s: ERP_CTS_PROT: %d\n", wiphy_name(hw->wiphy), info->use_cts_prot); @@ -646,7 +640,7 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_HT) { printk(KERN_DEBUG " %s: HT: op_mode=0x%x\n", wiphy_name(hw->wiphy), - info->ht.operation_mode); + info->ht_operation_mode); } if (changed & BSS_CHANGED_BASIC_RATES) { @@ -704,7 +698,6 @@ static const struct ieee80211_ops mac80211_hwsim_ops = .remove_interface = mac80211_hwsim_remove_interface, .config = mac80211_hwsim_config, .configure_filter = mac80211_hwsim_configure_filter, - .config_interface = mac80211_hwsim_config_interface, .bss_info_changed = mac80211_hwsim_bss_info_changed, .sta_notify = mac80211_hwsim_sta_notify, .set_tim = mac80211_hwsim_set_tim, @@ -725,6 +718,7 @@ static void mac80211_hwsim_free(void) spin_unlock_bh(&hwsim_radio_lock); list_for_each_entry(data, &tmplist, list) { + debugfs_remove(data->debugfs_group); debugfs_remove(data->debugfs_ps); debugfs_remove(data->debugfs); ieee80211_unregister_hw(data->hw); @@ -782,8 +776,7 @@ static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif) pspoll->aid = cpu_to_le16(0xc000 | vp->aid); memcpy(pspoll->bssid, vp->bssid, ETH_ALEN); memcpy(pspoll->ta, mac, ETH_ALEN); - if (data->radio_enabled && - !mac80211_hwsim_tx_frame(data->hw, skb)) + if (!mac80211_hwsim_tx_frame(data->hw, skb)) printk(KERN_DEBUG "%s: PS-Poll frame not ack'ed\n", __func__); dev_kfree_skb(skb); } @@ -814,8 +807,7 @@ static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac, memcpy(hdr->addr1, vp->bssid, ETH_ALEN); memcpy(hdr->addr2, mac, ETH_ALEN); memcpy(hdr->addr3, vp->bssid, ETH_ALEN); - if (data->radio_enabled && - !mac80211_hwsim_tx_frame(data->hw, skb)) + if (!mac80211_hwsim_tx_frame(data->hw, skb)) printk(KERN_DEBUG "%s: nullfunc frame not ack'ed\n", __func__); dev_kfree_skb(skb); } @@ -877,6 +869,24 @@ DEFINE_SIMPLE_ATTRIBUTE(hwsim_fops_ps, hwsim_fops_ps_read, hwsim_fops_ps_write, "%llu\n"); +static int hwsim_fops_group_read(void *dat, u64 *val) +{ + struct mac80211_hwsim_data *data = dat; + *val = data->group; + return 0; +} + +static int hwsim_fops_group_write(void *dat, u64 val) +{ + struct mac80211_hwsim_data *data = dat; + data->group = val; + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(hwsim_fops_group, + hwsim_fops_group_read, hwsim_fops_group_write, + "%llx\n"); + static int __init init_mac80211_hwsim(void) { int i, err = 0; @@ -981,6 +991,8 @@ static int __init init_mac80211_hwsim(void) hw->wiphy->bands[band] = sband; } + /* By default all radios are belonging to the first group */ + data->group = 1; /* Work to be done prior to ieee80211_register_hw() */ switch (regtest) { @@ -1105,6 +1117,9 @@ static int __init init_mac80211_hwsim(void) data->debugfs_ps = debugfs_create_file("ps", 0666, data->debugfs, data, &hwsim_fops_ps); + data->debugfs_group = debugfs_create_file("group", 0666, + data->debugfs, data, + &hwsim_fops_group); setup_timer(&data->beacon_timer, mac80211_hwsim_beacon, (unsigned long) hw); diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index a9a970469c2a..a263d5c84c08 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -2369,7 +2369,7 @@ static int mwl8k_cmd_set_aid(struct ieee80211_hw *hw, if (info->use_cts_prot) { prot_mode = MWL8K_FRAME_PROT_11G; } else { - switch (info->ht.operation_mode & + switch (info->ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION) { case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ: prot_mode = MWL8K_FRAME_PROT_11N_HT_40MHZ_ONLY; @@ -3089,19 +3089,6 @@ static int mwl8k_config(struct ieee80211_hw *hw, u32 changed) return rc ? -EINVAL : 0; } -static int mwl8k_config_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_if_conf *conf) -{ - struct mwl8k_vif *mv_vif = MWL8K_VIF(vif); - u32 changed = conf->changed; - - if (changed & IEEE80211_IFCC_BSSID) - memcpy(mv_vif->bssid, conf->bssid, IEEE80211_ADDR_LEN); - - return 0; -} - struct mwl8k_bss_info_changed_worker { struct mwl8k_work_struct header; struct ieee80211_vif *vif; @@ -3183,8 +3170,12 @@ static void mwl8k_bss_info_changed(struct ieee80211_hw *hw, { struct mwl8k_bss_info_changed_worker *worker; struct mwl8k_priv *priv = hw->priv; + struct mwl8k_vif *mv_vif = MWL8K_VIF(vif); int rc; + if (changed & BSS_CHANGED_BSSID) + memcpy(mv_vif->bssid, info->bssid, IEEE80211_ADDR_LEN); + if ((changed & BSS_CHANGED_ASSOC) == 0) return; @@ -3442,7 +3433,6 @@ static const struct ieee80211_ops mwl8k_ops = { .add_interface = mwl8k_add_interface, .remove_interface = mwl8k_remove_interface, .config = mwl8k_config, - .config_interface = mwl8k_config_interface, .bss_info_changed = mwl8k_bss_info_changed, .configure_filter = mwl8k_configure_filter, .set_rts_threshold = mwl8k_set_rts_threshold, diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index ecf8b6ed5a47..db3df947d8ed 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -125,6 +125,7 @@ struct p54_led_dev { struct led_classdev led_dev; char name[P54_LED_MAX_NAME_LEN + 1]; + unsigned int toggled; unsigned int index; unsigned int registered; }; @@ -133,55 +134,74 @@ struct p54_led_dev { struct p54_common { struct ieee80211_hw *hw; - u32 rx_start; - u32 rx_end; - struct sk_buff_head tx_queue; + struct ieee80211_vif *vif; void (*tx)(struct ieee80211_hw *dev, struct sk_buff *skb); int (*open)(struct ieee80211_hw *dev); void (*stop)(struct ieee80211_hw *dev); - int mode; + struct sk_buff_head tx_queue; + struct mutex conf_mutex; + + /* memory management (as seen by the firmware) */ + u32 rx_start; + u32 rx_end; u16 rx_mtu; u8 headroom; u8 tailroom; - struct mutex conf_mutex; - u8 mac_addr[ETH_ALEN]; - u8 bssid[ETH_ALEN]; - u8 rx_diversity_mask; - u8 tx_diversity_mask; - struct pda_iq_autocal_entry *iq_autocal; - unsigned int iq_autocal_len; - struct p54_cal_database *output_limit; - struct p54_cal_database *curve_data; - struct p54_rssi_linear_approximation rssical_db[IEEE80211_NUM_BANDS]; - unsigned int filter_flags; - bool use_short_slot; - u16 rxhw; - u8 version; + + /* firmware/hardware info */ unsigned int tx_hdr_len; unsigned int fw_var; unsigned int fw_interface; - unsigned int output_power; - u32 tsf_low32; - u32 tsf_high32; - u32 basic_rate_mask; - u16 wakeup_timer; - u16 aid; + u8 version; + + /* (e)DCF / QOS state */ + bool use_short_slot; struct ieee80211_tx_queue_stats tx_stats[8]; struct p54_edcf_queue_param qos_params[8]; - struct ieee80211_low_level_stats stats; - struct delayed_work work; - struct sk_buff *cached_beacon; + + /* Radio data */ + u16 rxhw; + u8 rx_diversity_mask; + u8 tx_diversity_mask; + unsigned int output_power; int noise; - void *eeprom; - struct completion eeprom_comp; + /* calibration, output power limit and rssi<->dBm conversation data */ + struct pda_iq_autocal_entry *iq_autocal; + unsigned int iq_autocal_len; + struct p54_cal_database *curve_data; + struct p54_cal_database *output_limit; + struct p54_rssi_linear_approximation rssical_db[IEEE80211_NUM_BANDS]; + + /* BBP/MAC state */ + u8 mac_addr[ETH_ALEN]; + u8 bssid[ETH_ALEN]; + u16 wakeup_timer; + unsigned int filter_flags; + int mode; + u32 tsf_low32, tsf_high32; + u32 basic_rate_mask; + u16 aid; + struct sk_buff *cached_beacon; + + /* cryptographic engine information */ u8 privacy_caps; u8 rx_keycache_size; + unsigned long *used_rxkeys; + /* LED management */ #ifdef CONFIG_P54_LEDS - struct p54_led_dev assoc_led; - struct p54_led_dev tx_led; + struct p54_led_dev leds[4]; + struct delayed_work led_work; #endif /* CONFIG_P54_LEDS */ u16 softled_state; /* bit field of glowing LEDs */ + + /* statistics */ + struct ieee80211_low_level_stats stats; + struct delayed_work work; + + /* eeprom handling */ + void *eeprom; + struct completion eeprom_comp; }; int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb); diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index c8f0232ee5e0..b618bd14583f 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -249,7 +249,7 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) dev->queues = P54_QUEUE_AC_NUM; } - if (!modparam_nohwcrypt) + if (!modparam_nohwcrypt) { printk(KERN_INFO "%s: cryptographic accelerator " "WEP:%s, TKIP:%s, CCMP:%s\n", wiphy_name(dev->wiphy), @@ -259,6 +259,26 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) (priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP) ? "YES" : "no"); + if (priv->rx_keycache_size) { + /* + * NOTE: + * + * The firmware provides at most 255 (0 - 254) slots + * for keys which are then used to offload decryption. + * As a result the 255 entry (aka 0xff) can be used + * safely by the driver to mark keys that didn't fit + * into the full cache. This trick saves us from + * keeping a extra list for uploaded keys. + */ + + priv->used_rxkeys = kzalloc(BITS_TO_LONGS( + priv->rx_keycache_size), GFP_KERNEL); + + if (!priv->used_rxkeys) + return -ENOMEM; + } + } + return 0; } EXPORT_SYMBOL_GPL(p54_parse_firmware); @@ -749,8 +769,6 @@ static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) rx_status.signal = p54_rssi_to_dbm(dev, hdr->rssi); rx_status.noise = priv->noise; - /* XX correct? */ - rx_status.qual = (100 * hdr->rssi) / 127; if (hdr->rate & 0x10) rx_status.flag |= RX_FLAG_SHORTPRE; if (dev->conf.channel->band == IEEE80211_BAND_5GHZ) @@ -804,44 +822,37 @@ void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb) struct ieee80211_tx_info *info; struct p54_tx_info *range; unsigned long flags; - u32 freed = 0, last_addr = priv->rx_start; - if (unlikely(!skb || !dev || !skb_queue_len(&priv->tx_queue))) + if (unlikely(!skb || !dev || skb_queue_empty(&priv->tx_queue))) return; - /* - * don't try to free an already unlinked skb + /* There used to be a check here to see if the SKB was on the + * TX queue or not. This can never happen because all SKBs we + * see here successfully went through p54_assign_address() + * which means the SKB is on the ->tx_queue. */ - if (unlikely((!skb->next) || (!skb->prev))) - return; spin_lock_irqsave(&priv->tx_queue.lock, flags); info = IEEE80211_SKB_CB(skb); range = (void *)info->rate_driver_data; - if (skb->prev != (struct sk_buff *)&priv->tx_queue) { + if (!skb_queue_is_first(&priv->tx_queue, skb)) { struct ieee80211_tx_info *ni; struct p54_tx_info *mr; - ni = IEEE80211_SKB_CB(skb->prev); + ni = IEEE80211_SKB_CB(skb_queue_prev(&priv->tx_queue, skb)); mr = (struct p54_tx_info *)ni->rate_driver_data; - last_addr = mr->end_addr; } - if (skb->next != (struct sk_buff *)&priv->tx_queue) { + if (!skb_queue_is_last(&priv->tx_queue, skb)) { struct ieee80211_tx_info *ni; struct p54_tx_info *mr; - ni = IEEE80211_SKB_CB(skb->next); + ni = IEEE80211_SKB_CB(skb_queue_next(&priv->tx_queue, skb)); mr = (struct p54_tx_info *)ni->rate_driver_data; - freed = mr->start_addr - last_addr; - } else - freed = priv->rx_end - last_addr; + } __skb_unlink(skb, &priv->tx_queue); spin_unlock_irqrestore(&priv->tx_queue.lock, flags); dev_kfree_skb_any(skb); - - if (freed >= priv->headroom + sizeof(struct p54_hdr) + 48 + - IEEE80211_MAX_RTS_THRESHOLD + priv->tailroom) - p54_wake_free_queues(dev); + p54_wake_free_queues(dev); } EXPORT_SYMBOL_GPL(p54_free_skb); @@ -853,15 +864,13 @@ static struct sk_buff *p54_find_tx_entry(struct ieee80211_hw *dev, unsigned long flags; spin_lock_irqsave(&priv->tx_queue.lock, flags); - entry = priv->tx_queue.next; - while (entry != (struct sk_buff *)&priv->tx_queue) { + skb_queue_walk(&priv->tx_queue, entry) { struct p54_hdr *hdr = (struct p54_hdr *) entry->data; if (hdr->req_id == req_id) { spin_unlock_irqrestore(&priv->tx_queue.lock, flags); return entry; } - entry = entry->next; } spin_unlock_irqrestore(&priv->tx_queue.lock, flags); return NULL; @@ -875,37 +884,29 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) struct sk_buff *entry; u32 addr = le32_to_cpu(hdr->req_id) - priv->headroom; struct p54_tx_info *range = NULL; - u32 freed = 0; - u32 last_addr = priv->rx_start; unsigned long flags; int count, idx; spin_lock_irqsave(&priv->tx_queue.lock, flags); - entry = (struct sk_buff *) priv->tx_queue.next; - while (entry != (struct sk_buff *)&priv->tx_queue) { + skb_queue_walk(&priv->tx_queue, entry) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry); struct p54_hdr *entry_hdr; struct p54_tx_data *entry_data; unsigned int pad = 0, frame_len; range = (void *)info->rate_driver_data; - if (range->start_addr != addr) { - last_addr = range->end_addr; - entry = entry->next; + if (range->start_addr != addr) continue; - } - if (entry->next != (struct sk_buff *)&priv->tx_queue) { + if (!skb_queue_is_last(&priv->tx_queue, entry)) { struct ieee80211_tx_info *ni; struct p54_tx_info *mr; - ni = IEEE80211_SKB_CB(entry->next); + ni = IEEE80211_SKB_CB(skb_queue_next(&priv->tx_queue, + entry)); mr = (struct p54_tx_info *)ni->rate_driver_data; - freed = mr->start_addr - last_addr; - } else - freed = priv->rx_end - last_addr; + } - last_addr = range->end_addr; __skb_unlink(entry, &priv->tx_queue); spin_unlock_irqrestore(&priv->tx_queue.lock, flags); @@ -992,9 +993,7 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) spin_unlock_irqrestore(&priv->tx_queue.lock, flags); out: - if (freed >= priv->headroom + sizeof(struct p54_hdr) + 48 + - IEEE80211_MAX_RTS_THRESHOLD + priv->tailroom) - p54_wake_free_queues(dev); + p54_wake_free_queues(dev); } static void p54_rx_eeprom_readback(struct ieee80211_hw *dev, @@ -1044,6 +1043,7 @@ static void p54_rx_stats(struct ieee80211_hw *dev, struct sk_buff *skb) static void p54_rx_trap(struct ieee80211_hw *dev, struct sk_buff *skb) { + struct p54_common *priv = dev->priv; struct p54_hdr *hdr = (struct p54_hdr *) skb->data; struct p54_trap *trap = (struct p54_trap *) hdr->data; u16 event = le16_to_cpu(trap->event); @@ -1057,6 +1057,8 @@ static void p54_rx_trap(struct ieee80211_hw *dev, struct sk_buff *skb) wiphy_name(dev->wiphy), freq); break; case P54_TRAP_NO_BEACON: + if (priv->vif) + ieee80211_beacon_loss(priv->vif); break; case P54_TRAP_SCAN: break; @@ -1162,23 +1164,21 @@ static int p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, } } - entry = priv->tx_queue.next; - while (left--) { + skb_queue_walk(&priv->tx_queue, entry) { u32 hole_size; info = IEEE80211_SKB_CB(entry); range = (void *)info->rate_driver_data; hole_size = range->start_addr - last_addr; if (!target_skb && hole_size >= len) { - target_skb = entry->prev; + target_skb = skb_queue_prev(&priv->tx_queue, entry); hole_size -= len; target_addr = last_addr; } largest_hole = max(largest_hole, hole_size); last_addr = range->end_addr; - entry = entry->next; } if (!target_skb && priv->rx_end - last_addr >= len) { - target_skb = priv->tx_queue.prev; + target_skb = skb_peek_tail(&priv->tx_queue); largest_hole = max(largest_hole, priv->rx_end - last_addr - len); if (!skb_queue_empty(&priv->tx_queue)) { info = IEEE80211_SKB_CB(target_skb); @@ -1452,7 +1452,8 @@ static int p54_tx_fill(struct ieee80211_hw *dev, struct sk_buff *skb, if (info->control.sta) *aid = info->control.sta->aid; - else + + if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) *flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL; break; } @@ -1939,7 +1940,8 @@ static int p54_set_ps(struct ieee80211_hw *dev) int i; if (dev->conf.flags & IEEE80211_CONF_PS) - mode = P54_PSM | P54_PSM_DTIM | P54_PSM_MCBC; + mode = P54_PSM | P54_PSM_BEACON_TIMEOUT | P54_PSM_DTIM | + P54_PSM_CHECKSUM | P54_PSM_MCBC; else mode = P54_PSM_CAM; @@ -1957,9 +1959,10 @@ static int p54_set_ps(struct ieee80211_hw *dev) psm->intervals[i].periods = cpu_to_le16(1); } - psm->beacon_rssi_skip_max = 60; + psm->beacon_rssi_skip_max = 200; psm->rssi_delta_threshold = 0; - psm->nr = 0; + psm->nr = 10; + psm->exclude[0] = 0; priv->tx(dev, skb); @@ -2081,20 +2084,21 @@ out: static void p54_stop(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; - struct sk_buff *skb; mutex_lock(&priv->conf_mutex); priv->mode = NL80211_IFTYPE_UNSPECIFIED; priv->softled_state = 0; p54_set_leds(dev); +#ifdef CONFIG_P54_LEDS + cancel_delayed_work_sync(&priv->led_work); +#endif /* CONFIG_P54_LEDS */ cancel_delayed_work_sync(&priv->work); if (priv->cached_beacon) p54_tx_cancel(dev, priv->cached_beacon); priv->stop(dev); - while ((skb = skb_dequeue(&priv->tx_queue))) - kfree_skb(skb); + skb_queue_purge(&priv->tx_queue); priv->cached_beacon = NULL; priv->tsf_high32 = priv->tsf_low32 = 0; mutex_unlock(&priv->conf_mutex); @@ -2111,6 +2115,8 @@ static int p54_add_interface(struct ieee80211_hw *dev, return -EOPNOTSUPP; } + priv->vif = conf->vif; + switch (conf->type) { case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_ADHOC: @@ -2135,6 +2141,7 @@ static void p54_remove_interface(struct ieee80211_hw *dev, struct p54_common *priv = dev->priv; mutex_lock(&priv->conf_mutex); + priv->vif = NULL; if (priv->cached_beacon) p54_tx_cancel(dev, priv->cached_beacon); priv->mode = NL80211_IFTYPE_MONITOR; @@ -2174,41 +2181,6 @@ out: return ret; } -static int p54_config_interface(struct ieee80211_hw *dev, - struct ieee80211_vif *vif, - struct ieee80211_if_conf *conf) -{ - struct p54_common *priv = dev->priv; - int ret = 0; - - mutex_lock(&priv->conf_mutex); - if (conf->changed & IEEE80211_IFCC_BSSID) { - memcpy(priv->bssid, conf->bssid, ETH_ALEN); - ret = p54_setup_mac(dev); - if (ret) - goto out; - } - - if (conf->changed & IEEE80211_IFCC_BEACON) { - ret = p54_scan(dev, P54_SCAN_EXIT, 0); - if (ret) - goto out; - ret = p54_setup_mac(dev); - if (ret) - goto out; - ret = p54_beacon_update(dev, vif); - if (ret) - goto out; - ret = p54_set_edcf(dev); - if (ret) - goto out; - } - -out: - mutex_unlock(&priv->conf_mutex); - return ret; -} - static void p54_configure_filter(struct ieee80211_hw *dev, unsigned int changed_flags, unsigned int *total_flags, @@ -2312,8 +2284,32 @@ static void p54_bss_info_changed(struct ieee80211_hw *dev, u32 changed) { struct p54_common *priv = dev->priv; + int ret; - if (changed & BSS_CHANGED_ERP_SLOT) { + mutex_lock(&priv->conf_mutex); + if (changed & BSS_CHANGED_BSSID) { + memcpy(priv->bssid, info->bssid, ETH_ALEN); + ret = p54_setup_mac(dev); + if (ret) + goto out; + } + + if (changed & BSS_CHANGED_BEACON) { + ret = p54_scan(dev, P54_SCAN_EXIT, 0); + if (ret) + goto out; + ret = p54_setup_mac(dev); + if (ret) + goto out; + ret = p54_beacon_update(dev, vif); + if (ret) + goto out; + } + /* XXX: this mimics having two callbacks... clean up */ + out: + mutex_unlock(&priv->conf_mutex); + + if (changed & (BSS_CHANGED_ERP_SLOT | BSS_CHANGED_BEACON)) { priv->use_short_slot = info->use_short_slot; p54_set_edcf(dev); } @@ -2334,7 +2330,6 @@ static void p54_bss_info_changed(struct ieee80211_hw *dev, p54_setup_mac(dev); } } - } static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd, @@ -2344,61 +2339,84 @@ static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd, struct p54_common *priv = dev->priv; struct sk_buff *skb; struct p54_keycache *rxkey; + int slot, ret = 0; u8 algo = 0; if (modparam_nohwcrypt) return -EOPNOTSUPP; - if (cmd == DISABLE_KEY) - algo = 0; - else { + mutex_lock(&priv->conf_mutex); + if (cmd == SET_KEY) { switch (key->alg) { case ALG_TKIP: if (!(priv->privacy_caps & (BR_DESC_PRIV_CAP_MICHAEL | - BR_DESC_PRIV_CAP_TKIP))) - return -EOPNOTSUPP; + BR_DESC_PRIV_CAP_TKIP))) { + ret = -EOPNOTSUPP; + goto out_unlock; + } key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; algo = P54_CRYPTO_TKIPMICHAEL; break; case ALG_WEP: - if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_WEP)) - return -EOPNOTSUPP; + if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_WEP)) { + ret = -EOPNOTSUPP; + goto out_unlock; + } key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; algo = P54_CRYPTO_WEP; break; case ALG_CCMP: - if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP)) - return -EOPNOTSUPP; + if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP)) { + ret = -EOPNOTSUPP; + goto out_unlock; + } key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; algo = P54_CRYPTO_AESCCMP; break; default: - return -EOPNOTSUPP; + ret = -EOPNOTSUPP; + goto out_unlock; } + slot = bitmap_find_free_region(priv->used_rxkeys, + priv->rx_keycache_size, 0); + + if (slot < 0) { + /* + * The device supports the choosen algorithm, but the + * firmware does not provide enough key slots to store + * all of them. + * But encryption offload for outgoing frames is always + * possible, so we just pretend that the upload was + * successful and do the decryption in software. + */ + + /* mark the key as invalid. */ + key->hw_key_idx = 0xff; + goto out_unlock; + } + } else { + slot = key->hw_key_idx; + + if (slot == 0xff) { + /* This key was not uploaded into the rx key cache. */ + + goto out_unlock; + } + + bitmap_release_region(priv->used_rxkeys, slot, 0); + algo = 0; } - if (key->keyidx > priv->rx_keycache_size) { - /* - * The device supports the choosen algorithm, but the firmware - * does not provide enough key slots to store all of them. - * So, incoming frames have to be decoded by the mac80211 stack, - * but we can still offload encryption for outgoing frames. - */ - - return 0; - } - - mutex_lock(&priv->conf_mutex); skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*rxkey), - P54_CONTROL_TYPE_RX_KEYCACHE, GFP_ATOMIC); + P54_CONTROL_TYPE_RX_KEYCACHE, GFP_KERNEL); if (!skb) { - mutex_unlock(&priv->conf_mutex); - return -ENOMEM; + bitmap_release_region(priv->used_rxkeys, slot, 0); + ret = -ENOSPC; + goto out_unlock; } - /* TODO: some devices have 4 more free slots for rx keys */ rxkey = (struct p54_keycache *)skb_put(skb, sizeof(*rxkey)); - rxkey->entry = key->keyidx; + rxkey->entry = slot; rxkey->key_id = key->keyidx; rxkey->key_type = algo; if (sta) @@ -2416,11 +2434,51 @@ static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd, } priv->tx(dev, skb); + key->hw_key_idx = slot; + +out_unlock: mutex_unlock(&priv->conf_mutex); - return 0; + return ret; } #ifdef CONFIG_P54_LEDS +static void p54_update_leds(struct work_struct *work) +{ + struct p54_common *priv = container_of(work, struct p54_common, + led_work.work); + int err, i, tmp, blink_delay = 400; + bool rerun = false; + + /* Don't toggle the LED, when the device is down. */ + if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) + return ; + + for (i = 0; i < ARRAY_SIZE(priv->leds); i++) + if (priv->leds[i].toggled) { + priv->softled_state |= BIT(i); + + tmp = 70 + 200 / (priv->leds[i].toggled); + if (tmp < blink_delay) + blink_delay = tmp; + + if (priv->leds[i].led_dev.brightness == LED_OFF) + rerun = true; + + priv->leds[i].toggled = + !!priv->leds[i].led_dev.brightness; + } else + priv->softled_state &= ~BIT(i); + + err = p54_set_leds(priv->hw); + if (err && net_ratelimit()) + printk(KERN_ERR "%s: failed to update LEDs.\n", + wiphy_name(priv->hw->wiphy)); + + if (rerun) + queue_delayed_work(priv->hw->workqueue, &priv->led_work, + msecs_to_jiffies(blink_delay)); +} + static void p54_led_brightness_set(struct led_classdev *led_dev, enum led_brightness brightness) { @@ -2428,28 +2486,23 @@ static void p54_led_brightness_set(struct led_classdev *led_dev, led_dev); struct ieee80211_hw *dev = led->hw_dev; struct p54_common *priv = dev->priv; - int err; - /* Don't toggle the LED, when the device is down. */ if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) return ; - if (brightness != LED_OFF) - priv->softled_state |= BIT(led->index); - else - priv->softled_state &= ~BIT(led->index); - - err = p54_set_leds(dev); - if (err && net_ratelimit()) - printk(KERN_ERR "%s: failed to update %s LED.\n", - wiphy_name(dev->wiphy), led_dev->name); + if (brightness) { + led->toggled++; + queue_delayed_work(priv->hw->workqueue, &priv->led_work, + HZ/10); + } } static int p54_register_led(struct ieee80211_hw *dev, - struct p54_led_dev *led, unsigned int led_index, char *name, char *trigger) { + struct p54_common *priv = dev->priv; + struct p54_led_dev *led = &priv->leds[led_index]; int err; if (led->registered) @@ -2482,19 +2535,30 @@ static int p54_init_leds(struct ieee80211_hw *dev) * TODO: * Figure out if the EEPROM contains some hints about the number * of available/programmable LEDs of the device. - * But for now, we can assume that we have two programmable LEDs. */ - err = p54_register_led(dev, &priv->assoc_led, 0, "assoc", + INIT_DELAYED_WORK(&priv->led_work, p54_update_leds); + + err = p54_register_led(dev, 0, "assoc", ieee80211_get_assoc_led_name(dev)); if (err) return err; - err = p54_register_led(dev, &priv->tx_led, 1, "tx", + err = p54_register_led(dev, 1, "tx", ieee80211_get_tx_led_name(dev)); if (err) return err; + err = p54_register_led(dev, 2, "rx", + ieee80211_get_rx_led_name(dev)); + if (err) + return err; + + err = p54_register_led(dev, 3, "radio", + ieee80211_get_radio_led_name(dev)); + if (err) + return err; + err = p54_set_leds(dev); return err; } @@ -2502,11 +2566,11 @@ static int p54_init_leds(struct ieee80211_hw *dev) static void p54_unregister_leds(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; + int i; - if (priv->tx_led.registered) - led_classdev_unregister(&priv->tx_led.led_dev); - if (priv->assoc_led.registered) - led_classdev_unregister(&priv->assoc_led.led_dev); + for (i = 0; i < ARRAY_SIZE(priv->leds); i++) + if (priv->leds[i].registered) + led_classdev_unregister(&priv->leds[i].led_dev); } #endif /* CONFIG_P54_LEDS */ @@ -2520,7 +2584,6 @@ static const struct ieee80211_ops p54_ops = { .sta_notify = p54_sta_notify, .set_key = p54_set_key, .config = p54_config, - .config_interface = p54_config_interface, .bss_info_changed = p54_bss_info_changed, .configure_filter = p54_configure_filter, .conf_tx = p54_conf_tx, @@ -2607,21 +2670,10 @@ void p54_free_common(struct ieee80211_hw *dev) kfree(priv->iq_autocal); kfree(priv->output_limit); kfree(priv->curve_data); + kfree(priv->used_rxkeys); #ifdef CONFIG_P54_LEDS p54_unregister_leds(dev); #endif /* CONFIG_P54_LEDS */ } EXPORT_SYMBOL_GPL(p54_free_common); - -static int __init p54_init(void) -{ - return 0; -} - -static void __exit p54_exit(void) -{ -} - -module_init(p54_init); -module_exit(p54_exit); diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c index d1fe577de3d4..83116baeb110 100644 --- a/drivers/net/wireless/p54/p54spi.c +++ b/drivers/net/wireless/p54/p54spi.c @@ -96,7 +96,7 @@ static void p54spi_spi_write(struct p54s_priv *priv, u8 address, spi_message_add_tail(&t[0], &m); t[1].tx_buf = buf; - t[1].len = len; + t[1].len = len & ~1; spi_message_add_tail(&t[1], &m); if (len % 2) { @@ -167,18 +167,34 @@ static const struct p54spi_spi_reg p54spi_registers_array[] = static int p54spi_wait_bit(struct p54s_priv *priv, u16 reg, __le32 bits) { int i; - __le32 buffer; for (i = 0; i < 2000; i++) { - p54spi_spi_read(priv, reg, &buffer, sizeof(buffer)); - if (buffer == bits) + __le32 buffer = p54spi_read32(priv, reg); + if ((buffer & bits) == bits) return 1; - - msleep(1); } return 0; } +static int p54spi_spi_write_dma(struct p54s_priv *priv, __le32 base, + const void *buf, size_t len) +{ + if (!p54spi_wait_bit(priv, SPI_ADRS_DMA_WRITE_CTRL, + cpu_to_le32(HOST_ALLOWED))) { + dev_err(&priv->spi->dev, "spi_write_dma not allowed " + "to DMA write.\n"); + return -EAGAIN; + } + + p54spi_write16(priv, SPI_ADRS_DMA_WRITE_CTRL, + cpu_to_le16(SPI_DMA_WRITE_CTRL_ENABLE)); + + p54spi_write16(priv, SPI_ADRS_DMA_WRITE_LEN, cpu_to_le16(len)); + p54spi_write32(priv, SPI_ADRS_DMA_WRITE_BASE, base); + p54spi_spi_write(priv, SPI_ADRS_DMA_DATA, buf, len); + return 0; +} + static int p54spi_request_firmware(struct ieee80211_hw *dev) { struct p54s_priv *priv = dev->priv; @@ -228,8 +244,15 @@ static int p54spi_request_eeprom(struct ieee80211_hw *dev) static int p54spi_upload_firmware(struct ieee80211_hw *dev) { struct p54s_priv *priv = dev->priv; - unsigned long fw_len, fw_addr; - long _fw_len; + unsigned long fw_len, _fw_len; + unsigned int offset = 0; + int err = 0; + u8 *fw; + + fw_len = priv->firmware->size; + fw = kmemdup(priv->firmware->data, fw_len, GFP_KERNEL); + if (!fw) + return -ENOMEM; /* stop the device */ p54spi_write16(priv, SPI_ADRS_DEV_CTRL_STAT, cpu_to_le16( @@ -244,36 +267,17 @@ static int p54spi_upload_firmware(struct ieee80211_hw *dev) msleep(TARGET_BOOT_SLEEP); - fw_addr = ISL38XX_DEV_FIRMWARE_ADDR; - fw_len = priv->firmware->size; - while (fw_len > 0) { _fw_len = min_t(long, fw_len, SPI_MAX_PACKET_SIZE); - p54spi_write16(priv, SPI_ADRS_DMA_WRITE_CTRL, - cpu_to_le16(SPI_DMA_WRITE_CTRL_ENABLE)); - - if (p54spi_wait_bit(priv, SPI_ADRS_DMA_WRITE_CTRL, - cpu_to_le32(HOST_ALLOWED)) == 0) { - dev_err(&priv->spi->dev, "fw_upload not allowed " - "to DMA write."); - return -EAGAIN; - } - - p54spi_write16(priv, SPI_ADRS_DMA_WRITE_LEN, - cpu_to_le16(_fw_len)); - p54spi_write32(priv, SPI_ADRS_DMA_WRITE_BASE, - cpu_to_le32(fw_addr)); - - p54spi_spi_write(priv, SPI_ADRS_DMA_DATA, - &priv->firmware->data, _fw_len); + err = p54spi_spi_write_dma(priv, cpu_to_le32( + ISL38XX_DEV_FIRMWARE_ADDR + offset), + (fw + offset), _fw_len); + if (err < 0) + goto out; fw_len -= _fw_len; - fw_addr += _fw_len; - - /* FIXME: I think this doesn't work if firmware is large, - * this loop goes to second round. fw->data is not - * increased at all! */ + offset += _fw_len; } BUG_ON(fw_len != 0); @@ -292,7 +296,10 @@ static int p54spi_upload_firmware(struct ieee80211_hw *dev) p54spi_write16(priv, SPI_ADRS_DEV_CTRL_STAT, cpu_to_le16( SPI_CTRL_STAT_HOST_OVERRIDE | SPI_CTRL_STAT_RAM_BOOT)); msleep(TARGET_BOOT_SLEEP); - return 0; + +out: + kfree(fw); + return err; } static void p54spi_power_off(struct p54s_priv *priv) @@ -318,29 +325,21 @@ static inline void p54spi_int_ack(struct p54s_priv *priv, u32 val) p54spi_write32(priv, SPI_ADRS_HOST_INT_ACK, cpu_to_le32(val)); } -static void p54spi_wakeup(struct p54s_priv *priv) +static int p54spi_wakeup(struct p54s_priv *priv) { - unsigned long timeout; - u32 ints; - /* wake the chip */ p54spi_write32(priv, SPI_ADRS_ARM_INTERRUPTS, cpu_to_le32(SPI_TARGET_INT_WAKEUP)); /* And wait for the READY interrupt */ - timeout = jiffies + HZ; - - ints = p54spi_read32(priv, SPI_ADRS_HOST_INTERRUPTS); - while (!(ints & SPI_HOST_INT_READY)) { - if (time_after(jiffies, timeout)) - goto out; - ints = p54spi_read32(priv, SPI_ADRS_HOST_INTERRUPTS); + if (!p54spi_wait_bit(priv, SPI_ADRS_HOST_INTERRUPTS, + cpu_to_le32(SPI_HOST_INT_READY))) { + dev_err(&priv->spi->dev, "INT_READY timeout\n"); + return -EBUSY; } p54spi_int_ack(priv, SPI_HOST_INT_READY); - -out: - return; + return 0; } static inline void p54spi_sleep(struct p54s_priv *priv) @@ -372,27 +371,48 @@ static int p54spi_rx(struct p54s_priv *priv) { struct sk_buff *skb; u16 len; + u16 rx_head[2]; +#define READAHEAD_SZ (sizeof(rx_head)-sizeof(u16)) - p54spi_wakeup(priv); + if (p54spi_wakeup(priv) < 0) + return -EBUSY; - /* dummy read to flush SPI DMA controller bug */ - p54spi_read16(priv, SPI_ADRS_GEN_PURP_1); - - len = p54spi_read16(priv, SPI_ADRS_DMA_DATA); + /* Read data size and first data word in one SPI transaction + * This is workaround for firmware/DMA bug, + * when first data word gets lost under high load. + */ + p54spi_spi_read(priv, SPI_ADRS_DMA_DATA, rx_head, sizeof(rx_head)); + len = rx_head[0]; if (len == 0) { - dev_err(&priv->spi->dev, "rx request of zero bytes"); + p54spi_sleep(priv); + dev_err(&priv->spi->dev, "rx request of zero bytes\n"); return 0; } - skb = dev_alloc_skb(len); + /* Firmware may insert up to 4 padding bytes after the lmac header, + * but it does not amend the size of SPI data transfer. + * Such packets has correct data size in header, thus referencing + * past the end of allocated skb. Reserve extra 4 bytes for this case */ + skb = dev_alloc_skb(len + 4); if (!skb) { + p54spi_sleep(priv); dev_err(&priv->spi->dev, "could not alloc skb"); - return 0; + return -ENOMEM; } - p54spi_spi_read(priv, SPI_ADRS_DMA_DATA, skb_put(skb, len), len); + if (len <= READAHEAD_SZ) { + memcpy(skb_put(skb, len), rx_head + 1, len); + } else { + memcpy(skb_put(skb, READAHEAD_SZ), rx_head + 1, READAHEAD_SZ); + p54spi_spi_read(priv, SPI_ADRS_DMA_DATA, + skb_put(skb, len - READAHEAD_SZ), + len - READAHEAD_SZ); + } p54spi_sleep(priv); + /* Put additional bytes to compensate for the possible + * alignment-caused truncation */ + skb_put(skb, 4); if (p54_rx(priv->hw, skb) == 0) dev_kfree_skb(skb); @@ -414,39 +434,28 @@ static irqreturn_t p54spi_interrupt(int irq, void *config) static int p54spi_tx_frame(struct p54s_priv *priv, struct sk_buff *skb) { struct p54_hdr *hdr = (struct p54_hdr *) skb->data; - struct p54s_dma_regs dma_regs; - unsigned long timeout; int ret = 0; - u32 ints; - p54spi_wakeup(priv); + if (p54spi_wakeup(priv) < 0) + return -EBUSY; - dma_regs.cmd = cpu_to_le16(SPI_DMA_WRITE_CTRL_ENABLE); - dma_regs.len = cpu_to_le16(skb->len); - dma_regs.addr = hdr->req_id; + ret = p54spi_spi_write_dma(priv, hdr->req_id, skb->data, skb->len); + if (ret < 0) + goto out; - p54spi_spi_write(priv, SPI_ADRS_DMA_WRITE_CTRL, &dma_regs, - sizeof(dma_regs)); - - p54spi_spi_write(priv, SPI_ADRS_DMA_DATA, skb->data, skb->len); - - timeout = jiffies + 2 * HZ; - ints = p54spi_read32(priv, SPI_ADRS_HOST_INTERRUPTS); - while (!(ints & SPI_HOST_INT_WR_READY)) { - if (time_after(jiffies, timeout)) { - dev_err(&priv->spi->dev, "WR_READY timeout"); - ret = -1; - goto out; - } - ints = p54spi_read32(priv, SPI_ADRS_HOST_INTERRUPTS); + if (!p54spi_wait_bit(priv, SPI_ADRS_HOST_INTERRUPTS, + cpu_to_le32(SPI_HOST_INT_WR_READY))) { + dev_err(&priv->spi->dev, "WR_READY timeout\n"); + ret = -EAGAIN; + goto out; } p54spi_int_ack(priv, SPI_HOST_INT_WR_READY); - p54spi_sleep(priv); -out: if (FREE_AFTER_TX(skb)) p54_free_skb(priv->hw, skb); +out: + p54spi_sleep(priv); return ret; } @@ -516,8 +525,7 @@ static void p54spi_work(struct work_struct *work) mutex_lock(&priv->mutex); - if (priv->fw_state == FW_STATE_OFF && - priv->fw_state == FW_STATE_RESET) + if (priv->fw_state == FW_STATE_OFF) goto out; ints = p54spi_read32(priv, SPI_ADRS_HOST_INTERRUPTS); @@ -544,11 +552,6 @@ static void p54spi_work(struct work_struct *work) } ret = p54spi_wq_tx(priv); - if (ret < 0) - goto out; - - ints = p54spi_read32(priv, SPI_ADRS_HOST_INTERRUPTS); - out: mutex_unlock(&priv->mutex); } diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index 6cc6cbc9234f..0e877a104a89 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -81,6 +81,29 @@ static struct usb_device_id p54u_table[] __devinitdata = { MODULE_DEVICE_TABLE(usb, p54u_table); +static const struct { + u32 intf; + enum p54u_hw_type type; + const char *fw; + const char *fw_legacy; + char hw[20]; +} p54u_fwlist[__NUM_P54U_HWTYPES] = { + { + .type = P54U_NET2280, + .intf = FW_LM86, + .fw = "isl3886usb", + .fw_legacy = "isl3890usb", + .hw = "ISL3886 + net2280", + }, + { + .type = P54U_3887, + .intf = FW_LM87, + .fw = "isl3887usb", + .fw_legacy = "isl3887usb_bare", + .hw = "ISL3887", + }, +}; + static void p54u_rx_cb(struct urb *urb) { struct sk_buff *skb = (struct sk_buff *) urb->context; @@ -125,11 +148,7 @@ static void p54u_rx_cb(struct urb *urb) } skb_reset_tail_pointer(skb); skb_trim(skb, 0); - if (urb->transfer_buffer != skb_tail_pointer(skb)) { - /* this should not happen */ - WARN_ON(1); - urb->transfer_buffer = skb_tail_pointer(skb); - } + urb->transfer_buffer = skb_tail_pointer(skb); } skb_queue_tail(&priv->rx_queue, skb); usb_anchor_urb(urb, &priv->submitted); @@ -206,53 +225,6 @@ static int p54u_init_urbs(struct ieee80211_hw *dev) return ret; } -static void p54u_tx_3887(struct ieee80211_hw *dev, struct sk_buff *skb) -{ - struct p54u_priv *priv = dev->priv; - struct urb *addr_urb, *data_urb; - int err = 0; - - addr_urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!addr_urb) - return; - - data_urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!data_urb) { - usb_free_urb(addr_urb); - return; - } - - usb_fill_bulk_urb(addr_urb, priv->udev, - usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), - &((struct p54_hdr *)skb->data)->req_id, 4, - p54u_tx_dummy_cb, dev); - usb_fill_bulk_urb(data_urb, priv->udev, - usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), - skb->data, skb->len, FREE_AFTER_TX(skb) ? - p54u_tx_cb : p54u_tx_dummy_cb, skb); - addr_urb->transfer_flags |= URB_ZERO_PACKET; - data_urb->transfer_flags |= URB_ZERO_PACKET; - - usb_anchor_urb(addr_urb, &priv->submitted); - err = usb_submit_urb(addr_urb, GFP_ATOMIC); - if (err) { - usb_unanchor_urb(addr_urb); - goto out; - } - - usb_anchor_urb(data_urb, &priv->submitted); - err = usb_submit_urb(data_urb, GFP_ATOMIC); - if (err) - usb_unanchor_urb(data_urb); - - out: - usb_free_urb(addr_urb); - usb_free_urb(data_urb); - - if (err) - p54_free_skb(dev, skb); -} - static __le32 p54u_lm87_chksum(const __le32 *data, size_t length) { u32 chk = 0; @@ -425,20 +397,16 @@ static int p54u_bulk_msg(struct p54u_priv *priv, unsigned int ep, data, len, &alen, 2000); } -static const char p54u_romboot_3887[] = "~~~~"; -static const char p54u_firmware_upload_3887[] = "<\r"; - -static int p54u_device_reset_3887(struct ieee80211_hw *dev) +static int p54u_device_reset(struct ieee80211_hw *dev) { struct p54u_priv *priv = dev->priv; int ret, lock = (priv->intf->condition != USB_INTERFACE_BINDING); - u8 buf[4]; if (lock) { ret = usb_lock_device_for_reset(priv->udev, priv->intf); if (ret < 0) { dev_err(&priv->udev->dev, "(p54usb) unable to lock " - " device for reset: %d\n", ret); + "device for reset (%d)!\n", ret); return ret; } } @@ -447,26 +415,34 @@ static int p54u_device_reset_3887(struct ieee80211_hw *dev) if (lock) usb_unlock_device(priv->udev); - if (ret) { + if (ret) dev_err(&priv->udev->dev, "(p54usb) unable to reset " - "device: %d\n", ret); - return ret; - } + "device (%d)!\n", ret); + + return ret; +} + +static const char p54u_romboot_3887[] = "~~~~"; +static int p54u_firmware_reset_3887(struct ieee80211_hw *dev) +{ + struct p54u_priv *priv = dev->priv; + u8 buf[4]; + int ret; memcpy(&buf, p54u_romboot_3887, sizeof(buf)); ret = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(buf)); if (ret) dev_err(&priv->udev->dev, "(p54usb) unable to jump to " - "boot ROM: %d\n", ret); + "boot ROM (%d)!\n", ret); return ret; } +static const char p54u_firmware_upload_3887[] = "<\r"; static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) { struct p54u_priv *priv = dev->priv; - const struct firmware *fw_entry = NULL; int err, alen; u8 carry = 0; u8 *buf, *tmp; @@ -475,51 +451,29 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) struct x2_header *hdr; unsigned long timeout; + err = p54u_firmware_reset_3887(dev); + if (err) + return err; + tmp = buf = kmalloc(P54U_FW_BLOCK, GFP_KERNEL); if (!buf) { dev_err(&priv->udev->dev, "(p54usb) cannot allocate firmware" "upload buffer!\n"); - err = -ENOMEM; - goto err_bufalloc; + return -ENOMEM; } - err = p54u_device_reset_3887(dev); - if (err) - goto err_reset; - - err = request_firmware(&fw_entry, "isl3887usb", &priv->udev->dev); - if (err) { - dev_err(&priv->udev->dev, "p54usb: cannot find firmware " - "(isl3887usb)\n"); - err = request_firmware(&fw_entry, "isl3887usb_bare", - &priv->udev->dev); - if (err) - goto err_req_fw_failed; - } - - err = p54_parse_firmware(dev, fw_entry); - if (err) - goto err_upload_failed; - - if (priv->common.fw_interface != FW_LM87) { - dev_err(&priv->udev->dev, "wrong firmware, " - "please get a LM87 firmware and try again.\n"); - err = -EINVAL; - goto err_upload_failed; - } - - left = block_size = min((size_t)P54U_FW_BLOCK, fw_entry->size); + left = block_size = min((size_t)P54U_FW_BLOCK, priv->fw->size); strcpy(buf, p54u_firmware_upload_3887); left -= strlen(p54u_firmware_upload_3887); tmp += strlen(p54u_firmware_upload_3887); - data = fw_entry->data; - remains = fw_entry->size; + data = priv->fw->data; + remains = priv->fw->size; hdr = (struct x2_header *)(buf + strlen(p54u_firmware_upload_3887)); memcpy(hdr->signature, X2_SIGNATURE, X2_SIGNATURE_SIZE); hdr->fw_load_addr = cpu_to_le32(ISL38XX_DEV_FIRMWARE_ADDR); - hdr->fw_length = cpu_to_le32(fw_entry->size); + hdr->fw_length = cpu_to_le32(priv->fw->size); hdr->crc = cpu_to_le32(~crc32_le(~0, (void *)&hdr->fw_load_addr, sizeof(u32)*2)); left -= sizeof(*hdr); @@ -561,7 +515,8 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) left = block_size = min((unsigned int)P54U_FW_BLOCK, remains); } - *((__le32 *)buf) = cpu_to_le32(~crc32_le(~0, fw_entry->data, fw_entry->size)); + *((__le32 *)buf) = cpu_to_le32(~crc32_le(~0, priv->fw->data, + priv->fw->size)); err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32)); if (err) { dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n"); @@ -612,19 +567,14 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) if (err) goto err_upload_failed; - err_upload_failed: - release_firmware(fw_entry); - err_req_fw_failed: - err_reset: +err_upload_failed: kfree(buf); - err_bufalloc: return err; } static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev) { struct p54u_priv *priv = dev->priv; - const struct firmware *fw_entry = NULL; const struct p54p_csr *devreg = (const struct p54p_csr *) P54U_DEV_BASE; int err, alen; void *buf; @@ -639,33 +589,6 @@ static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev) return -ENOMEM; } - err = request_firmware(&fw_entry, "isl3886usb", &priv->udev->dev); - if (err) { - dev_err(&priv->udev->dev, "(p54usb) cannot find firmware " - "(isl3886usb)\n"); - err = request_firmware(&fw_entry, "isl3890usb", - &priv->udev->dev); - if (err) { - kfree(buf); - return err; - } - } - - err = p54_parse_firmware(dev, fw_entry); - if (err) { - kfree(buf); - release_firmware(fw_entry); - return err; - } - - if (priv->common.fw_interface != FW_LM86) { - dev_err(&priv->udev->dev, "wrong firmware, " - "please get a LM86(USB) firmware and try again.\n"); - kfree(buf); - release_firmware(fw_entry); - return -EINVAL; - } - #define P54U_WRITE(type, addr, data) \ do {\ err = p54u_write(priv, buf, type,\ @@ -765,8 +688,8 @@ static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev) P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg); /* finally, we can upload firmware now! */ - remains = fw_entry->size; - data = fw_entry->data; + remains = priv->fw->size; + data = priv->fw->data; offset = ISL38XX_DEV_FIRMWARE_ADDR; while (remains) { @@ -875,12 +798,54 @@ static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev) #undef P54U_WRITE #undef P54U_READ - fail: - release_firmware(fw_entry); +fail: kfree(buf); return err; } +static int p54u_load_firmware(struct ieee80211_hw *dev) +{ + struct p54u_priv *priv = dev->priv; + int err, i; + + BUILD_BUG_ON(ARRAY_SIZE(p54u_fwlist) != __NUM_P54U_HWTYPES); + + for (i = 0; i < __NUM_P54U_HWTYPES; i++) + if (p54u_fwlist[i].type == priv->hw_type) + break; + + if (i == __NUM_P54U_HWTYPES) + return -EOPNOTSUPP; + + err = request_firmware(&priv->fw, p54u_fwlist[i].fw, &priv->udev->dev); + if (err) { + dev_err(&priv->udev->dev, "(p54usb) cannot load firmware %s " + "(%d)!\n", p54u_fwlist[i].fw, err); + + err = request_firmware(&priv->fw, p54u_fwlist[i].fw_legacy, + &priv->udev->dev); + if (err) + return err; + } + + err = p54_parse_firmware(dev, priv->fw); + if (err) + goto out; + + if (priv->common.fw_interface != p54u_fwlist[i].intf) { + dev_err(&priv->udev->dev, "wrong firmware, please get " + "a firmware for \"%s\" and try again.\n", + p54u_fwlist[i].hw); + err = -EINVAL; + } + +out: + if (err) + release_firmware(priv->fw); + + return err; +} + static int p54u_open(struct ieee80211_hw *dev) { struct p54u_priv *priv = dev->priv; @@ -922,6 +887,7 @@ static int __devinit p54u_probe(struct usb_interface *intf, } priv = dev->priv; + priv->hw_type = P54U_INVALID_HW; SET_IEEE80211_DEV(dev, &intf->dev); usb_set_intfdata(intf, dev); @@ -953,37 +919,48 @@ static int __devinit p54u_probe(struct usb_interface *intf, priv->common.open = p54u_open; priv->common.stop = p54u_stop; if (recognized_pipes < P54U_PIPE_NUMBER) { +#ifdef CONFIG_PM + /* ISL3887 needs a full reset on resume */ + udev->reset_resume = 1; + err = p54u_device_reset(dev); +#endif + priv->hw_type = P54U_3887; - err = p54u_upload_firmware_3887(dev); - if (priv->common.fw_interface == FW_LM87) { - dev->extra_tx_headroom += sizeof(struct lm87_tx_hdr); - priv->common.tx_hdr_len = sizeof(struct lm87_tx_hdr); - priv->common.tx = p54u_tx_lm87; - } else - priv->common.tx = p54u_tx_3887; + dev->extra_tx_headroom += sizeof(struct lm87_tx_hdr); + priv->common.tx_hdr_len = sizeof(struct lm87_tx_hdr); + priv->common.tx = p54u_tx_lm87; + priv->upload_fw = p54u_upload_firmware_3887; } else { priv->hw_type = P54U_NET2280; dev->extra_tx_headroom += sizeof(struct net2280_tx_hdr); priv->common.tx_hdr_len = sizeof(struct net2280_tx_hdr); priv->common.tx = p54u_tx_net2280; - err = p54u_upload_firmware_net2280(dev); + priv->upload_fw = p54u_upload_firmware_net2280; } + err = p54u_load_firmware(dev); if (err) goto err_free_dev; + err = priv->upload_fw(dev); + if (err) + goto err_free_fw; + p54u_open(dev); err = p54_read_eeprom(dev); p54u_stop(dev); if (err) - goto err_free_dev; + goto err_free_fw; err = p54_register_common(dev, &udev->dev); if (err) - goto err_free_dev; + goto err_free_fw; return 0; - err_free_dev: +err_free_fw: + release_firmware(priv->fw); + +err_free_dev: ieee80211_free_hw(dev); usb_set_intfdata(intf, NULL); usb_put_dev(udev); @@ -1002,20 +979,64 @@ static void __devexit p54u_disconnect(struct usb_interface *intf) priv = dev->priv; usb_put_dev(interface_to_usbdev(intf)); + release_firmware(priv->fw); p54_free_common(dev); ieee80211_free_hw(dev); } static int p54u_pre_reset(struct usb_interface *intf) { + struct ieee80211_hw *dev = usb_get_intfdata(intf); + + if (!dev) + return -ENODEV; + + p54u_stop(dev); return 0; } +static int p54u_resume(struct usb_interface *intf) +{ + struct ieee80211_hw *dev = usb_get_intfdata(intf); + struct p54u_priv *priv; + + if (!dev) + return -ENODEV; + + priv = dev->priv; + if (unlikely(!(priv->upload_fw && priv->fw))) + return 0; + + return priv->upload_fw(dev); +} + static int p54u_post_reset(struct usb_interface *intf) { + struct ieee80211_hw *dev = usb_get_intfdata(intf); + struct p54u_priv *priv; + int err; + + err = p54u_resume(intf); + if (err) + return err; + + /* reinitialize old device state */ + priv = dev->priv; + if (priv->common.mode != NL80211_IFTYPE_UNSPECIFIED) + ieee80211_restart_hw(dev); + return 0; } +#ifdef CONFIG_PM + +static int p54u_suspend(struct usb_interface *intf, pm_message_t message) +{ + return p54u_pre_reset(intf); +} + +#endif /* CONFIG_PM */ + static struct usb_driver p54u_driver = { .name = "p54usb", .id_table = p54u_table, @@ -1023,6 +1044,11 @@ static struct usb_driver p54u_driver = { .disconnect = p54u_disconnect, .pre_reset = p54u_pre_reset, .post_reset = p54u_post_reset, +#ifdef CONFIG_PM + .suspend = p54u_suspend, + .resume = p54u_resume, + .reset_resume = p54u_resume, +#endif /* CONFIG_PM */ .soft_unbind = 1, }; diff --git a/drivers/net/wireless/p54/p54usb.h b/drivers/net/wireless/p54/p54usb.h index 8bc58982d8dd..e935b79f7f75 100644 --- a/drivers/net/wireless/p54/p54usb.h +++ b/drivers/net/wireless/p54/p54usb.h @@ -123,18 +123,26 @@ struct p54u_rx_info { struct ieee80211_hw *dev; }; +enum p54u_hw_type { + P54U_INVALID_HW, + P54U_NET2280, + P54U_3887, + + /* keep last */ + __NUM_P54U_HWTYPES, +}; + struct p54u_priv { struct p54_common common; struct usb_device *udev; struct usb_interface *intf; - enum { - P54U_NET2280 = 0, - P54U_3887 - } hw_type; + int (*upload_fw)(struct ieee80211_hw *dev); + enum p54u_hw_type hw_type; spinlock_t lock; struct sk_buff_head rx_queue; struct usb_anchor submitted; + const struct firmware *fw; }; #endif /* P54USB_H */ diff --git a/drivers/net/wireless/prism54/islpci_eth.c b/drivers/net/wireless/prism54/islpci_eth.c index ef3ef4551b31..8f6210993448 100644 --- a/drivers/net/wireless/prism54/islpci_eth.c +++ b/drivers/net/wireless/prism54/islpci_eth.c @@ -87,7 +87,6 @@ islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev) unsigned long flags; unsigned char wds_mac[6]; u32 curr_frag; - int err = 0; #if VERBOSE > SHOW_ERROR_MESSAGES DEBUG(SHOW_FUNCTION_CALLS, "islpci_eth_transmit \n"); @@ -107,8 +106,6 @@ islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev) isl38xx_w32_flush(priv->device_base, ISL38XX_DEV_INT_UPDATE, ISL38XX_DEV_INT_REG); udelay(ISL38XX_WRITEIO_DELAY); - - err = -EBUSY; goto drop_free; } /* Check alignment and WDS frame formatting. The start of the packet should @@ -152,7 +149,6 @@ islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev) if (unlikely(newskb == NULL)) { printk(KERN_ERR "%s: Cannot allocate skb\n", ndev->name); - err = -ENOMEM; goto drop_free; } newskb_offset = (4 - (long) newskb->data) & 0x03; @@ -197,8 +193,6 @@ islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev) if (unlikely(pci_map_address == 0)) { printk(KERN_WARNING "%s: cannot map buffer to PCI\n", ndev->name); - - err = -EIO; goto drop_free; } /* Place the fragment in the control block structure. */ @@ -246,7 +240,7 @@ islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev) ndev->stats.tx_dropped++; spin_unlock_irqrestore(&priv->slock, flags); dev_kfree_skb(skb); - return err; + return NETDEV_TX_OK; } static inline int diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index fa90d1d8d82e..b10b0383dfa5 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -892,7 +892,7 @@ static int ray_dev_init(struct net_device *dev) #endif /* RAY_IMMEDIATE_INIT */ /* copy mac and broadcast addresses to linux device */ - memcpy(&dev->dev_addr, &local->sparm.b4.a_mac_addr, ADDRLEN); + memcpy(dev->dev_addr, &local->sparm.b4.a_mac_addr, ADDRLEN); memset(dev->broadcast, 0xff, ETH_ALEN); DEBUG(2, "ray_dev_init ending\n"); @@ -923,7 +923,7 @@ static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev) if (!(pcmcia_dev_present(link))) { DEBUG(2, "ray_dev_start_xmit - device not present\n"); - return -1; + return NETDEV_TX_LOCKED; } DEBUG(3, "ray_dev_start_xmit(skb=%p, dev=%p)\n", skb, dev); if (local->authentication_state == NEED_TO_AUTH) { @@ -931,7 +931,7 @@ static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev) if (!build_auth_frame(local, local->auth_id, OPEN_AUTH_REQUEST)) { local->authentication_state = AUTHENTICATED; netif_stop_queue(dev); - return 1; + return NETDEV_TX_BUSY; } } @@ -944,7 +944,7 @@ static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev) case XMIT_NO_CCS: case XMIT_NEED_AUTH: netif_stop_queue(dev); - return 1; + return NETDEV_TX_BUSY; case XMIT_NO_INTR: case XMIT_MSG_BAD: case XMIT_OK: diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index bebf735cd4bd..3bec3dbd3450 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -2,7 +2,7 @@ * Driver for RNDIS based wireless USB devices. * * Copyright (C) 2007 by Bjorge Dijkstra - * Copyright (C) 2008 by Jussi Kivilinna + * Copyright (C) 2008-2009 by Jussi Kivilinna * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -42,6 +42,7 @@ #include #include #include +#include #include #include @@ -156,43 +157,55 @@ MODULE_PARM_DESC(workaround_interval, #define NDIS_802_11_LENGTH_RATES_EX 16 enum ndis_80211_net_type { - ndis_80211_type_freq_hop, - ndis_80211_type_direct_seq, - ndis_80211_type_ofdm_a, - ndis_80211_type_ofdm_g + NDIS_80211_TYPE_FREQ_HOP, + NDIS_80211_TYPE_DIRECT_SEQ, + NDIS_80211_TYPE_OFDM_A, + NDIS_80211_TYPE_OFDM_G }; enum ndis_80211_net_infra { - ndis_80211_infra_adhoc, - ndis_80211_infra_infra, - ndis_80211_infra_auto_unknown + NDIS_80211_INFRA_ADHOC, + NDIS_80211_INFRA_INFRA, + NDIS_80211_INFRA_AUTO_UNKNOWN }; enum ndis_80211_auth_mode { - ndis_80211_auth_open, - ndis_80211_auth_shared, - ndis_80211_auth_auto_switch, - ndis_80211_auth_wpa, - ndis_80211_auth_wpa_psk, - ndis_80211_auth_wpa_none, - ndis_80211_auth_wpa2, - ndis_80211_auth_wpa2_psk + NDIS_80211_AUTH_OPEN, + NDIS_80211_AUTH_SHARED, + NDIS_80211_AUTH_AUTO_SWITCH, + NDIS_80211_AUTH_WPA, + NDIS_80211_AUTH_WPA_PSK, + NDIS_80211_AUTH_WPA_NONE, + NDIS_80211_AUTH_WPA2, + NDIS_80211_AUTH_WPA2_PSK }; enum ndis_80211_encr_status { - ndis_80211_encr_wep_enabled, - ndis_80211_encr_disabled, - ndis_80211_encr_wep_key_absent, - ndis_80211_encr_not_supported, - ndis_80211_encr_tkip_enabled, - ndis_80211_encr_tkip_key_absent, - ndis_80211_encr_ccmp_enabled, - ndis_80211_encr_ccmp_key_absent + NDIS_80211_ENCR_WEP_ENABLED, + NDIS_80211_ENCR_DISABLED, + NDIS_80211_ENCR_WEP_KEY_ABSENT, + NDIS_80211_ENCR_NOT_SUPPORTED, + NDIS_80211_ENCR_TKIP_ENABLED, + NDIS_80211_ENCR_TKIP_KEY_ABSENT, + NDIS_80211_ENCR_CCMP_ENABLED, + NDIS_80211_ENCR_CCMP_KEY_ABSENT }; enum ndis_80211_priv_filter { - ndis_80211_priv_accept_all, - ndis_80211_priv_8021x_wep + NDIS_80211_PRIV_ACCEPT_ALL, + NDIS_80211_PRIV_8021X_WEP +}; + +enum ndis_80211_addkey_bits { + NDIS_80211_ADDKEY_8021X_AUTH = cpu_to_le32(1 << 28), + NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ = cpu_to_le32(1 << 29), + NDIS_80211_ADDKEY_PAIRWISE_KEY = cpu_to_le32(1 << 30), + NDIS_80211_ADDKEY_TRANSMIT_KEY = cpu_to_le32(1 << 31) +}; + +enum ndis_80211_addwep_bits { + NDIS_80211_ADDWEP_PERCLIENT_KEY = cpu_to_le32(1 << 30), + NDIS_80211_ADDWEP_TRANSMIT_KEY = cpu_to_le32(1 << 31) }; struct ndis_80211_ssid { @@ -308,7 +321,6 @@ enum wpa_key_mgmt { KEY_MGMT_802_1X, KEY_MGMT_PSK, KEY_MGMT_NONE, #define CAP_MODE_80211B 2 #define CAP_MODE_80211G 4 #define CAP_MODE_MASK 7 -#define CAP_SUPPORT_TXPOWER 8 #define WORK_LINK_UP (1<<0) #define WORK_LINK_DOWN (1<<1) @@ -316,25 +328,61 @@ enum wpa_key_mgmt { KEY_MGMT_802_1X, KEY_MGMT_PSK, KEY_MGMT_NONE, #define COMMAND_BUFFER_SIZE (CONTROL_BUFFER_SIZE + sizeof(struct rndis_set)) -/* RNDIS device private data */ -struct rndis_wext_private { - char name[32]; +static const struct ieee80211_channel rndis_channels[] = { + { .center_freq = 2412 }, + { .center_freq = 2417 }, + { .center_freq = 2422 }, + { .center_freq = 2427 }, + { .center_freq = 2432 }, + { .center_freq = 2437 }, + { .center_freq = 2442 }, + { .center_freq = 2447 }, + { .center_freq = 2452 }, + { .center_freq = 2457 }, + { .center_freq = 2462 }, + { .center_freq = 2467 }, + { .center_freq = 2472 }, + { .center_freq = 2484 }, +}; +static const struct ieee80211_rate rndis_rates[] = { + { .bitrate = 10 }, + { .bitrate = 20, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 55, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 110, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 60 }, + { .bitrate = 90 }, + { .bitrate = 120 }, + { .bitrate = 180 }, + { .bitrate = 240 }, + { .bitrate = 360 }, + { .bitrate = 480 }, + { .bitrate = 540 } +}; + +/* RNDIS device private data */ +struct rndis_wlan_private { struct usbnet *usbdev; + struct wireless_dev wdev; + + struct cfg80211_scan_request *scan_request; + struct workqueue_struct *workqueue; struct delayed_work stats_work; + struct delayed_work scan_work; struct work_struct work; struct mutex command_lock; spinlock_t stats_lock; unsigned long work_pending; + struct ieee80211_supported_band band; + struct ieee80211_channel channels[ARRAY_SIZE(rndis_channels)]; + struct ieee80211_rate rates[ARRAY_SIZE(rndis_rates)]; + struct iw_statistics iwstats; struct iw_statistics privstats; - int nick_len; - char nick[32]; - int caps; int multicast_size; @@ -357,6 +405,7 @@ struct rndis_wext_private { int encr_tx_key_index; char encr_keys[4][32]; int encr_key_len[4]; + char encr_key_wpa[4]; int wpa_version; int wpa_keymgmt; int wpa_authalg; @@ -368,8 +417,22 @@ struct rndis_wext_private { u8 command_buffer[COMMAND_BUFFER_SIZE]; }; +/* + * cfg80211 ops + */ +static int rndis_change_virtual_intf(struct wiphy *wiphy, int ifindex, + enum nl80211_iftype type, u32 *flags, + struct vif_params *params); -static const int rates_80211g[8] = { 6, 9, 12, 18, 24, 36, 48, 54 }; +static int rndis_scan(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_scan_request *request); + +static struct cfg80211_ops rndis_config_ops = { + .change_virtual_intf = rndis_change_virtual_intf, + .scan = rndis_scan, +}; + +static void *rndis_wiphy_privid = &rndis_wiphy_privid; static const int bcm4320_power_output[4] = { 25, 50, 75, 100 }; @@ -378,13 +441,13 @@ static const unsigned char ffff_bssid[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; -static struct rndis_wext_private *get_rndis_wext_priv(struct usbnet *dev) +static struct rndis_wlan_private *get_rndis_wlan_priv(struct usbnet *dev) { - return (struct rndis_wext_private *)dev->driver_priv; + return (struct rndis_wlan_private *)dev->driver_priv; } -static u32 get_bcm4320_power(struct rndis_wext_private *priv) +static u32 get_bcm4320_power(struct rndis_wlan_private *priv) { return BCM4320_DEFAULT_TXPOWER * bcm4320_power_output[priv->param_power_output] / 100; @@ -417,7 +480,7 @@ static int rndis_error_status(__le32 rndis_status) static int rndis_query_oid(struct usbnet *dev, __le32 oid, void *data, int *len) { - struct rndis_wext_private *priv = get_rndis_wext_priv(dev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(dev); union { void *buf; struct rndis_msg_hdr *header; @@ -463,7 +526,7 @@ static int rndis_query_oid(struct usbnet *dev, __le32 oid, void *data, int *len) static int rndis_set_oid(struct usbnet *dev, __le32 oid, void *data, int len) { - struct rndis_wext_private *priv = get_rndis_wext_priv(dev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(dev); union { void *buf; struct rndis_msg_hdr *header; @@ -584,7 +647,7 @@ static int rndis_set_config_parameter(struct usbnet *dev, char *param, ret = rndis_set_oid(dev, OID_GEN_RNDIS_CONFIG_PARAMETER, infobuf, info_len); if (ret != 0) - devdbg(dev, "setting rndis config paramater failed, %d.", ret); + devdbg(dev, "setting rndis config parameter failed, %d.", ret); kfree(infobuf); return ret; @@ -684,7 +747,7 @@ static int get_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid) static int set_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); int ret; ret = rndis_set_oid(usbdev, OID_802_11_SSID, ssid, sizeof(*ssid)); @@ -731,7 +794,7 @@ static int is_associated(struct usbnet *usbdev) static int disassociate(struct usbnet *usbdev, int reset_ssid) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct ndis_80211_ssid ssid; int i, ret = 0; @@ -763,7 +826,7 @@ static int disassociate(struct usbnet *usbdev, int reset_ssid) static int set_auth_mode(struct usbnet *usbdev, int wpa_version, int authalg) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); __le32 tmp; int auth_mode, ret; @@ -772,23 +835,23 @@ static int set_auth_mode(struct usbnet *usbdev, int wpa_version, int authalg) if (wpa_version & IW_AUTH_WPA_VERSION_WPA2) { if (priv->wpa_keymgmt & IW_AUTH_KEY_MGMT_802_1X) - auth_mode = ndis_80211_auth_wpa2; + auth_mode = NDIS_80211_AUTH_WPA2; else - auth_mode = ndis_80211_auth_wpa2_psk; + auth_mode = NDIS_80211_AUTH_WPA2_PSK; } else if (wpa_version & IW_AUTH_WPA_VERSION_WPA) { if (priv->wpa_keymgmt & IW_AUTH_KEY_MGMT_802_1X) - auth_mode = ndis_80211_auth_wpa; + auth_mode = NDIS_80211_AUTH_WPA; else if (priv->wpa_keymgmt & IW_AUTH_KEY_MGMT_PSK) - auth_mode = ndis_80211_auth_wpa_psk; + auth_mode = NDIS_80211_AUTH_WPA_PSK; else - auth_mode = ndis_80211_auth_wpa_none; + auth_mode = NDIS_80211_AUTH_WPA_NONE; } else if (authalg & IW_AUTH_ALG_SHARED_KEY) { if (authalg & IW_AUTH_ALG_OPEN_SYSTEM) - auth_mode = ndis_80211_auth_auto_switch; + auth_mode = NDIS_80211_AUTH_AUTO_SWITCH; else - auth_mode = ndis_80211_auth_shared; + auth_mode = NDIS_80211_AUTH_SHARED; } else - auth_mode = ndis_80211_auth_open; + auth_mode = NDIS_80211_AUTH_OPEN; tmp = cpu_to_le32(auth_mode); ret = rndis_set_oid(usbdev, OID_802_11_AUTHENTICATION_MODE, &tmp, @@ -806,16 +869,16 @@ static int set_auth_mode(struct usbnet *usbdev, int wpa_version, int authalg) static int set_priv_filter(struct usbnet *usbdev) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); __le32 tmp; devdbg(usbdev, "set_priv_filter: wpa_version=0x%x", priv->wpa_version); if (priv->wpa_version & IW_AUTH_WPA_VERSION_WPA2 || priv->wpa_version & IW_AUTH_WPA_VERSION_WPA) - tmp = cpu_to_le32(ndis_80211_priv_8021x_wep); + tmp = cpu_to_le32(NDIS_80211_PRIV_8021X_WEP); else - tmp = cpu_to_le32(ndis_80211_priv_accept_all); + tmp = cpu_to_le32(NDIS_80211_PRIV_ACCEPT_ALL); return rndis_set_oid(usbdev, OID_802_11_PRIVACY_FILTER, &tmp, sizeof(tmp)); @@ -824,7 +887,7 @@ static int set_priv_filter(struct usbnet *usbdev) static int set_encr_mode(struct usbnet *usbdev, int pairwise, int groupwise) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); __le32 tmp; int encr_mode, ret; @@ -833,18 +896,18 @@ static int set_encr_mode(struct usbnet *usbdev, int pairwise, int groupwise) groupwise); if (pairwise & IW_AUTH_CIPHER_CCMP) - encr_mode = ndis_80211_encr_ccmp_enabled; + encr_mode = NDIS_80211_ENCR_CCMP_ENABLED; else if (pairwise & IW_AUTH_CIPHER_TKIP) - encr_mode = ndis_80211_encr_tkip_enabled; + encr_mode = NDIS_80211_ENCR_TKIP_ENABLED; else if (pairwise & (IW_AUTH_CIPHER_WEP40 | IW_AUTH_CIPHER_WEP104)) - encr_mode = ndis_80211_encr_wep_enabled; + encr_mode = NDIS_80211_ENCR_WEP_ENABLED; else if (groupwise & IW_AUTH_CIPHER_CCMP) - encr_mode = ndis_80211_encr_ccmp_enabled; + encr_mode = NDIS_80211_ENCR_CCMP_ENABLED; else if (groupwise & IW_AUTH_CIPHER_TKIP) - encr_mode = ndis_80211_encr_tkip_enabled; + encr_mode = NDIS_80211_ENCR_TKIP_ENABLED; else - encr_mode = ndis_80211_encr_disabled; + encr_mode = NDIS_80211_ENCR_DISABLED; tmp = cpu_to_le32(encr_mode); ret = rndis_set_oid(usbdev, OID_802_11_ENCRYPTION_STATUS, &tmp, @@ -862,7 +925,7 @@ static int set_encr_mode(struct usbnet *usbdev, int pairwise, int groupwise) static int set_assoc_params(struct usbnet *usbdev) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); set_auth_mode(usbdev, priv->wpa_version, priv->wpa_authalg); set_priv_filter(usbdev); @@ -874,7 +937,7 @@ static int set_assoc_params(struct usbnet *usbdev) static int set_infra_mode(struct usbnet *usbdev, int mode) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); __le32 tmp; int ret, i; @@ -894,7 +957,7 @@ static int set_infra_mode(struct usbnet *usbdev, int mode) if (priv->wpa_keymgmt == 0 || priv->wpa_keymgmt == IW_AUTH_KEY_MGMT_802_1X) { for (i = 0; i < 4; i++) { - if (priv->encr_key_len[i] > 0) + if (priv->encr_key_len[i] > 0 && !priv->encr_key_wpa[i]) add_wep_key(usbdev, priv->encr_keys[i], priv->encr_key_len[i], i); } @@ -907,12 +970,12 @@ static int set_infra_mode(struct usbnet *usbdev, int mode) static void set_default_iw_params(struct usbnet *usbdev) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); priv->wpa_keymgmt = 0; priv->wpa_version = 0; - set_infra_mode(usbdev, ndis_80211_infra_infra); + set_infra_mode(usbdev, NDIS_80211_INFRA_INFRA); set_auth_mode(usbdev, IW_AUTH_WPA_VERSION_DISABLED, IW_AUTH_ALG_OPEN_SYSTEM); set_priv_filter(usbdev); @@ -933,7 +996,7 @@ static int deauthenticate(struct usbnet *usbdev) /* index must be 0 - N, as per NDIS */ static int add_wep_key(struct usbnet *usbdev, char *key, int key_len, int index) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct ndis_80211_wep_key ndis_key; int ret; @@ -948,7 +1011,7 @@ static int add_wep_key(struct usbnet *usbdev, char *key, int key_len, int index) memcpy(&ndis_key.material, key, key_len); if (index == priv->encr_tx_key_index) { - ndis_key.index |= cpu_to_le32(1 << 31); + ndis_key.index |= NDIS_80211_ADDWEP_TRANSMIT_KEY; ret = set_encr_mode(usbdev, IW_AUTH_CIPHER_WEP104, IW_AUTH_CIPHER_NONE); if (ret) @@ -965,16 +1028,85 @@ static int add_wep_key(struct usbnet *usbdev, char *key, int key_len, int index) } priv->encr_key_len[index] = key_len; + priv->encr_key_wpa[index] = 0; memcpy(&priv->encr_keys[index], key, key_len); return 0; } +static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len, + int index, const struct sockaddr *addr, + const u8 *rx_seq, int alg, int flags) +{ + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); + struct ndis_80211_key ndis_key; + int ret; + + if (index < 0 || index >= 4) + return -EINVAL; + if (key_len > sizeof(ndis_key.material) || key_len < 0) + return -EINVAL; + if ((flags & NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ) && !rx_seq) + return -EINVAL; + if ((flags & NDIS_80211_ADDKEY_PAIRWISE_KEY) && !addr) + return -EINVAL; + + devdbg(usbdev, "add_wpa_key(%i): flags:%i%i%i", index, + !!(flags & NDIS_80211_ADDKEY_TRANSMIT_KEY), + !!(flags & NDIS_80211_ADDKEY_PAIRWISE_KEY), + !!(flags & NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ)); + + memset(&ndis_key, 0, sizeof(ndis_key)); + + ndis_key.size = cpu_to_le32(sizeof(ndis_key) - + sizeof(ndis_key.material) + key_len); + ndis_key.length = cpu_to_le32(key_len); + ndis_key.index = cpu_to_le32(index) | flags; + + if (alg == IW_ENCODE_ALG_TKIP && key_len == 32) { + /* wpa_supplicant gives us the Michael MIC RX/TX keys in + * different order than NDIS spec, so swap the order here. */ + memcpy(ndis_key.material, key, 16); + memcpy(ndis_key.material + 16, key + 24, 8); + memcpy(ndis_key.material + 24, key + 16, 8); + } else + memcpy(ndis_key.material, key, key_len); + + if (flags & NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ) + memcpy(ndis_key.rsc, rx_seq, 6); + + if (flags & NDIS_80211_ADDKEY_PAIRWISE_KEY) { + /* pairwise key */ + memcpy(ndis_key.bssid, addr->sa_data, ETH_ALEN); + } else { + /* group key */ + if (priv->infra_mode == NDIS_80211_INFRA_ADHOC) + memset(ndis_key.bssid, 0xff, ETH_ALEN); + else + get_bssid(usbdev, ndis_key.bssid); + } + + ret = rndis_set_oid(usbdev, OID_802_11_ADD_KEY, &ndis_key, + le32_to_cpu(ndis_key.size)); + devdbg(usbdev, "add_wpa_key: OID_802_11_ADD_KEY -> %08X", ret); + if (ret != 0) + return ret; + + priv->encr_key_len[index] = key_len; + priv->encr_key_wpa[index] = 1; + + if (flags & NDIS_80211_ADDKEY_TRANSMIT_KEY) + priv->encr_tx_key_index = index; + + return 0; +} + + /* remove_key is for both wep and wpa */ static int remove_key(struct usbnet *usbdev, int index, u8 bssid[ETH_ALEN]) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct ndis_80211_remove_key remove_key; __le32 keyindex; int ret; @@ -983,6 +1115,7 @@ static int remove_key(struct usbnet *usbdev, int index, u8 bssid[ETH_ALEN]) return 0; priv->encr_key_len[index] = 0; + priv->encr_key_wpa[index] = 0; memset(&priv->encr_keys[index], 0, sizeof(priv->encr_keys[index])); if (priv->wpa_cipher_pair == IW_AUTH_CIPHER_TKIP || @@ -994,7 +1127,8 @@ static int remove_key(struct usbnet *usbdev, int index, u8 bssid[ETH_ALEN]) if (bssid) { /* pairwise key */ if (memcmp(bssid, ffff_bssid, ETH_ALEN) != 0) - remove_key.index |= cpu_to_le32(1 << 30); + remove_key.index |= + NDIS_80211_ADDKEY_PAIRWISE_KEY; memcpy(remove_key.bssid, bssid, sizeof(remove_key.bssid)); } else @@ -1027,7 +1161,7 @@ static int remove_key(struct usbnet *usbdev, int index, u8 bssid[ETH_ALEN]) static void set_multicast_list(struct usbnet *usbdev) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct dev_mc_list *mclist; __le32 filter; int ret, i, size; @@ -1085,6 +1219,173 @@ static void set_multicast_list(struct usbnet *usbdev) } +/* + * cfg80211 ops + */ +static int rndis_change_virtual_intf(struct wiphy *wiphy, int ifindex, + enum nl80211_iftype type, u32 *flags, + struct vif_params *params) +{ + struct net_device *dev; + struct usbnet *usbdev; + int mode; + + /* we're under RTNL */ + dev = __dev_get_by_index(&init_net, ifindex); + if (!dev) + return -ENODEV; + usbdev = netdev_priv(dev); + + switch (type) { + case NL80211_IFTYPE_ADHOC: + mode = NDIS_80211_INFRA_ADHOC; + break; + case NL80211_IFTYPE_STATION: + mode = NDIS_80211_INFRA_INFRA; + break; + default: + return -EINVAL; + } + + return set_infra_mode(usbdev, mode); +} + + +#define SCAN_DELAY_JIFFIES (HZ) +static int rndis_scan(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_scan_request *request) +{ + struct usbnet *usbdev = netdev_priv(dev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); + int ret; + __le32 tmp; + + devdbg(usbdev, "cfg80211.scan"); + + if (!request) + return -EINVAL; + + if (priv->scan_request && priv->scan_request != request) + return -EBUSY; + + priv->scan_request = request; + + tmp = cpu_to_le32(1); + ret = rndis_set_oid(usbdev, OID_802_11_BSSID_LIST_SCAN, &tmp, + sizeof(tmp)); + if (ret == 0) { + /* Wait before retrieving scan results from device */ + queue_delayed_work(priv->workqueue, &priv->scan_work, + SCAN_DELAY_JIFFIES); + } + + return ret; +} + + +static struct cfg80211_bss *rndis_bss_info_update(struct usbnet *usbdev, + struct ndis_80211_bssid_ex *bssid) +{ + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); + struct ieee80211_channel *channel; + s32 signal; + u64 timestamp; + u16 capability; + u16 beacon_interval; + struct ndis_80211_fixed_ies *fixed; + int ie_len, bssid_len; + u8 *ie; + + /* parse bssid structure */ + bssid_len = le32_to_cpu(bssid->length); + + if (bssid_len < sizeof(struct ndis_80211_bssid_ex) + + sizeof(struct ndis_80211_fixed_ies)) + return NULL; + + fixed = (struct ndis_80211_fixed_ies *)bssid->ies; + + ie = (void *)(bssid->ies + sizeof(struct ndis_80211_fixed_ies)); + ie_len = min(bssid_len - (int)sizeof(*bssid), + (int)le32_to_cpu(bssid->ie_length)); + ie_len -= sizeof(struct ndis_80211_fixed_ies); + if (ie_len < 0) + return NULL; + + /* extract data for cfg80211_inform_bss */ + channel = ieee80211_get_channel(priv->wdev.wiphy, + KHZ_TO_MHZ(le32_to_cpu(bssid->config.ds_config))); + if (!channel) + return NULL; + + signal = level_to_qual(le32_to_cpu(bssid->rssi)); + timestamp = le64_to_cpu(*(__le64 *)fixed->timestamp); + capability = le16_to_cpu(fixed->capabilities); + beacon_interval = le16_to_cpu(fixed->beacon_interval); + + return cfg80211_inform_bss(priv->wdev.wiphy, channel, bssid->mac, + timestamp, capability, beacon_interval, ie, ie_len, signal, + GFP_KERNEL); +} + + +static int rndis_check_bssid_list(struct usbnet *usbdev) +{ + void *buf = NULL; + struct ndis_80211_bssid_list_ex *bssid_list; + struct ndis_80211_bssid_ex *bssid; + int ret = -EINVAL, len, count, bssid_len; + + devdbg(usbdev, "check_bssid_list"); + + len = CONTROL_BUFFER_SIZE; + buf = kmalloc(len, GFP_KERNEL); + if (!buf) { + ret = -ENOMEM; + goto out; + } + + ret = rndis_query_oid(usbdev, OID_802_11_BSSID_LIST, buf, &len); + if (ret != 0) + goto out; + + bssid_list = buf; + bssid = bssid_list->bssid; + bssid_len = le32_to_cpu(bssid->length); + count = le32_to_cpu(bssid_list->num_items); + devdbg(usbdev, "check_bssid_list: %d BSSIDs found", count); + + while (count && ((void *)bssid + bssid_len) <= (buf + len)) { + rndis_bss_info_update(usbdev, bssid); + + bssid = (void *)bssid + bssid_len; + bssid_len = le32_to_cpu(bssid->length); + count--; + } + +out: + kfree(buf); + return ret; +} + + +static void rndis_get_scan_results(struct work_struct *work) +{ + struct rndis_wlan_private *priv = + container_of(work, struct rndis_wlan_private, scan_work.work); + struct usbnet *usbdev = priv->usbdev; + int ret; + + devdbg(usbdev, "get_scan_results"); + + ret = rndis_check_bssid_list(usbdev); + + cfg80211_scan_done(priv->scan_request, ret < 0); + + priv->scan_request = NULL; +} + + /* * wireless extension handlers */ @@ -1097,124 +1398,6 @@ static int rndis_iw_commit(struct net_device *dev, } -static int rndis_iw_get_range(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_range *range = (struct iw_range *)extra; - struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); - int len, ret, i, j, num, has_80211g_rates; - u8 rates[8]; - __le32 tx_power; - - devdbg(usbdev, "SIOCGIWRANGE"); - - /* clear iw_range struct */ - memset(range, 0, sizeof(*range)); - wrqu->data.length = sizeof(*range); - - range->txpower_capa = IW_TXPOW_MWATT; - range->num_txpower = 1; - if (priv->caps & CAP_SUPPORT_TXPOWER) { - len = sizeof(tx_power); - ret = rndis_query_oid(usbdev, OID_802_11_TX_POWER_LEVEL, - &tx_power, &len); - if (ret == 0 && le32_to_cpu(tx_power) != 0xFF) - range->txpower[0] = le32_to_cpu(tx_power); - else - range->txpower[0] = get_bcm4320_power(priv); - } else - range->txpower[0] = get_bcm4320_power(priv); - - len = sizeof(rates); - ret = rndis_query_oid(usbdev, OID_802_11_SUPPORTED_RATES, &rates, - &len); - has_80211g_rates = 0; - if (ret == 0) { - j = 0; - for (i = 0; i < len; i++) { - if (rates[i] == 0) - break; - range->bitrate[j] = (rates[i] & 0x7f) * 500000; - /* check for non 802.11b rates */ - if (range->bitrate[j] == 6000000 || - range->bitrate[j] == 9000000 || - (range->bitrate[j] >= 12000000 && - range->bitrate[j] != 22000000)) - has_80211g_rates = 1; - j++; - } - range->num_bitrates = j; - } else - range->num_bitrates = 0; - - /* fill in 802.11g rates */ - if (has_80211g_rates) { - num = range->num_bitrates; - for (i = 0; i < ARRAY_SIZE(rates_80211g); i++) { - for (j = 0; j < num; j++) { - if (range->bitrate[j] == - rates_80211g[i] * 1000000) - break; - } - if (j == num) - range->bitrate[range->num_bitrates++] = - rates_80211g[i] * 1000000; - if (range->num_bitrates == IW_MAX_BITRATES) - break; - } - - /* estimated max real througput in bps */ - range->throughput = 54 * 1000 * 1000 / 2; - - /* ~35% more with afterburner */ - if (priv->param_afterburner) - range->throughput = range->throughput / 100 * 135; - } else { - /* estimated max real througput in bps */ - range->throughput = 11 * 1000 * 1000 / 2; - } - - range->num_channels = 14; - - for (i = 0; (i < 14) && (i < IW_MAX_FREQUENCIES); i++) { - range->freq[i].i = i + 1; - range->freq[i].m = ieee80211_dsss_chan_to_freq(i + 1) * 100000; - range->freq[i].e = 1; - } - range->num_frequency = i; - - range->min_rts = 0; - range->max_rts = 2347; - range->min_frag = 256; - range->max_frag = 2346; - - range->max_qual.qual = 100; - range->max_qual.level = 154; - range->max_qual.updated = IW_QUAL_QUAL_UPDATED - | IW_QUAL_LEVEL_UPDATED - | IW_QUAL_NOISE_INVALID; - - range->we_version_compiled = WIRELESS_EXT; - range->we_version_source = WIRELESS_EXT; - - range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | - IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; - return 0; -} - - -static int rndis_iw_get_name(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); - - strcpy(wrqu->name, priv->name); - return 0; -} - - static int rndis_iw_set_essid(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *essid) { @@ -1314,7 +1497,7 @@ static int rndis_iw_set_auth(struct net_device *dev, { struct iw_param *p = &wrqu->param; struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); int ret = -ENOTSUPP; switch (p->flags & IW_AUTH_INDEX) { @@ -1395,7 +1578,7 @@ static int rndis_iw_get_auth(struct net_device *dev, { struct iw_param *p = &wrqu->param; struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); switch (p->flags & IW_AUTH_INDEX) { case IW_AUTH_WPA_VERSION: @@ -1422,60 +1605,11 @@ static int rndis_iw_get_auth(struct net_device *dev, } -static int rndis_iw_get_mode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); - - switch (priv->infra_mode) { - case ndis_80211_infra_adhoc: - wrqu->mode = IW_MODE_ADHOC; - break; - case ndis_80211_infra_infra: - wrqu->mode = IW_MODE_INFRA; - break; - /*case ndis_80211_infra_auto_unknown:*/ - default: - wrqu->mode = IW_MODE_AUTO; - break; - } - devdbg(usbdev, "SIOCGIWMODE: %08x", wrqu->mode); - return 0; -} - - -static int rndis_iw_set_mode(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct usbnet *usbdev = netdev_priv(dev); - int mode; - - devdbg(usbdev, "SIOCSIWMODE: %08x", wrqu->mode); - - switch (wrqu->mode) { - case IW_MODE_ADHOC: - mode = ndis_80211_infra_adhoc; - break; - case IW_MODE_INFRA: - mode = ndis_80211_infra_infra; - break; - /*case IW_MODE_AUTO:*/ - default: - mode = ndis_80211_infra_auto_unknown; - break; - } - - return set_infra_mode(usbdev, mode); -} - - static int rndis_iw_set_encode(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); int ret, index, key_len; u8 *key; @@ -1538,10 +1672,8 @@ static int rndis_iw_set_encode_ext(struct net_device *dev, { struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); - struct ndis_80211_key ndis_key; - int keyidx, ret; - u8 *addr; + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); + int keyidx, flags; keyidx = wrqu->encoding.flags & IW_ENCODE_INDEX; @@ -1564,250 +1696,16 @@ static int rndis_iw_set_encode_ext(struct net_device *dev, ext->alg == IW_ENCODE_ALG_NONE || ext->key_len == 0) return remove_key(usbdev, keyidx, NULL); - if (ext->key_len > sizeof(ndis_key.material)) - return -1; - - memset(&ndis_key, 0, sizeof(ndis_key)); - - ndis_key.size = cpu_to_le32(sizeof(ndis_key) - - sizeof(ndis_key.material) + ext->key_len); - ndis_key.length = cpu_to_le32(ext->key_len); - ndis_key.index = cpu_to_le32(keyidx); - - if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) { - memcpy(ndis_key.rsc, ext->rx_seq, 6); - ndis_key.index |= cpu_to_le32(1 << 29); - } - - addr = ext->addr.sa_data; - if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { - /* group key */ - if (priv->infra_mode == ndis_80211_infra_adhoc) - memset(ndis_key.bssid, 0xff, ETH_ALEN); - else - get_bssid(usbdev, ndis_key.bssid); - } else { - /* pairwise key */ - ndis_key.index |= cpu_to_le32(1 << 30); - memcpy(ndis_key.bssid, addr, ETH_ALEN); - } - + flags = 0; + if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) + flags |= NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ; + if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY)) + flags |= NDIS_80211_ADDKEY_PAIRWISE_KEY; if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) - ndis_key.index |= cpu_to_le32(1 << 31); + flags |= NDIS_80211_ADDKEY_TRANSMIT_KEY; - if (ext->alg == IW_ENCODE_ALG_TKIP && ext->key_len == 32) { - /* wpa_supplicant gives us the Michael MIC RX/TX keys in - * different order than NDIS spec, so swap the order here. */ - memcpy(ndis_key.material, ext->key, 16); - memcpy(ndis_key.material + 16, ext->key + 24, 8); - memcpy(ndis_key.material + 24, ext->key + 16, 8); - } else - memcpy(ndis_key.material, ext->key, ext->key_len); - - ret = rndis_set_oid(usbdev, OID_802_11_ADD_KEY, &ndis_key, - le32_to_cpu(ndis_key.size)); - devdbg(usbdev, "SIOCSIWENCODEEXT: OID_802_11_ADD_KEY -> %08X", ret); - if (ret != 0) - return ret; - - priv->encr_key_len[keyidx] = ext->key_len; - memcpy(&priv->encr_keys[keyidx], ndis_key.material, ext->key_len); - if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) - priv->encr_tx_key_index = keyidx; - - return 0; -} - - -static int rndis_iw_set_scan(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct usbnet *usbdev = netdev_priv(dev); - union iwreq_data evt; - int ret = -EINVAL; - __le32 tmp; - - devdbg(usbdev, "SIOCSIWSCAN"); - - if (wrqu->data.flags == 0) { - tmp = cpu_to_le32(1); - ret = rndis_set_oid(usbdev, OID_802_11_BSSID_LIST_SCAN, &tmp, - sizeof(tmp)); - evt.data.flags = 0; - evt.data.length = 0; - wireless_send_event(dev, SIOCGIWSCAN, &evt, NULL); - } - return ret; -} - - -static char *rndis_translate_scan(struct net_device *dev, - struct iw_request_info *info, char *cev, - char *end_buf, - struct ndis_80211_bssid_ex *bssid) -{ - struct usbnet *usbdev = netdev_priv(dev); - u8 *ie; - char *current_val; - int bssid_len, ie_len, i; - u32 beacon, atim; - struct iw_event iwe; - unsigned char sbuf[32]; - - bssid_len = le32_to_cpu(bssid->length); - - devdbg(usbdev, "BSSID %pM", bssid->mac); - iwe.cmd = SIOCGIWAP; - iwe.u.ap_addr.sa_family = ARPHRD_ETHER; - memcpy(iwe.u.ap_addr.sa_data, bssid->mac, ETH_ALEN); - cev = iwe_stream_add_event(info, cev, end_buf, &iwe, IW_EV_ADDR_LEN); - - devdbg(usbdev, "SSID(%d) %s", le32_to_cpu(bssid->ssid.length), - bssid->ssid.essid); - iwe.cmd = SIOCGIWESSID; - iwe.u.essid.length = le32_to_cpu(bssid->ssid.length); - iwe.u.essid.flags = 1; - cev = iwe_stream_add_point(info, cev, end_buf, &iwe, bssid->ssid.essid); - - devdbg(usbdev, "MODE %d", le32_to_cpu(bssid->net_infra)); - iwe.cmd = SIOCGIWMODE; - switch (le32_to_cpu(bssid->net_infra)) { - case ndis_80211_infra_adhoc: - iwe.u.mode = IW_MODE_ADHOC; - break; - case ndis_80211_infra_infra: - iwe.u.mode = IW_MODE_INFRA; - break; - /*case ndis_80211_infra_auto_unknown:*/ - default: - iwe.u.mode = IW_MODE_AUTO; - break; - } - cev = iwe_stream_add_event(info, cev, end_buf, &iwe, IW_EV_UINT_LEN); - - devdbg(usbdev, "FREQ %d kHz", le32_to_cpu(bssid->config.ds_config)); - iwe.cmd = SIOCGIWFREQ; - dsconfig_to_freq(le32_to_cpu(bssid->config.ds_config), &iwe.u.freq); - cev = iwe_stream_add_event(info, cev, end_buf, &iwe, IW_EV_FREQ_LEN); - - devdbg(usbdev, "QUAL %d", le32_to_cpu(bssid->rssi)); - iwe.cmd = IWEVQUAL; - iwe.u.qual.qual = level_to_qual(le32_to_cpu(bssid->rssi)); - iwe.u.qual.level = le32_to_cpu(bssid->rssi); - iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED - | IW_QUAL_LEVEL_UPDATED - | IW_QUAL_NOISE_INVALID; - cev = iwe_stream_add_event(info, cev, end_buf, &iwe, IW_EV_QUAL_LEN); - - devdbg(usbdev, "ENCODE %d", le32_to_cpu(bssid->privacy)); - iwe.cmd = SIOCGIWENCODE; - iwe.u.data.length = 0; - if (le32_to_cpu(bssid->privacy) == ndis_80211_priv_accept_all) - iwe.u.data.flags = IW_ENCODE_DISABLED; - else - iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; - - cev = iwe_stream_add_point(info, cev, end_buf, &iwe, NULL); - - devdbg(usbdev, "RATES:"); - current_val = cev + iwe_stream_lcp_len(info); - iwe.cmd = SIOCGIWRATE; - for (i = 0; i < sizeof(bssid->rates); i++) { - if (bssid->rates[i] & 0x7f) { - iwe.u.bitrate.value = - ((bssid->rates[i] & 0x7f) * - 500000); - devdbg(usbdev, " %d", iwe.u.bitrate.value); - current_val = iwe_stream_add_value(info, cev, - current_val, end_buf, &iwe, - IW_EV_PARAM_LEN); - } - } - - if ((current_val - cev) > iwe_stream_lcp_len(info)) - cev = current_val; - - beacon = le32_to_cpu(bssid->config.beacon_period); - devdbg(usbdev, "BCN_INT %d", beacon); - iwe.cmd = IWEVCUSTOM; - snprintf(sbuf, sizeof(sbuf), "bcn_int=%d", beacon); - iwe.u.data.length = strlen(sbuf); - cev = iwe_stream_add_point(info, cev, end_buf, &iwe, sbuf); - - atim = le32_to_cpu(bssid->config.atim_window); - devdbg(usbdev, "ATIM %d", atim); - iwe.cmd = IWEVCUSTOM; - snprintf(sbuf, sizeof(sbuf), "atim=%u", atim); - iwe.u.data.length = strlen(sbuf); - cev = iwe_stream_add_point(info, cev, end_buf, &iwe, sbuf); - - ie = (void *)(bssid->ies + sizeof(struct ndis_80211_fixed_ies)); - ie_len = min(bssid_len - (int)sizeof(*bssid), - (int)le32_to_cpu(bssid->ie_length)); - ie_len -= sizeof(struct ndis_80211_fixed_ies); - while (ie_len >= 2 && 2 + ie[1] <= ie_len) { - if ((ie[0] == WLAN_EID_GENERIC && ie[1] >= 4 && - memcmp(ie + 2, "\x00\x50\xf2\x01", 4) == 0) || - ie[0] == WLAN_EID_RSN) { - devdbg(usbdev, "IE: WPA%d", - (ie[0] == WLAN_EID_RSN) ? 2 : 1); - iwe.cmd = IWEVGENIE; - /* arbitrary cut-off at 64 */ - iwe.u.data.length = min(ie[1] + 2, 64); - cev = iwe_stream_add_point(info, cev, end_buf, &iwe, ie); - } - - ie_len -= 2 + ie[1]; - ie += 2 + ie[1]; - } - - return cev; -} - - -static int rndis_iw_get_scan(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct usbnet *usbdev = netdev_priv(dev); - void *buf = NULL; - char *cev = extra; - struct ndis_80211_bssid_list_ex *bssid_list; - struct ndis_80211_bssid_ex *bssid; - int ret = -EINVAL, len, count, bssid_len; - - devdbg(usbdev, "SIOCGIWSCAN"); - - len = CONTROL_BUFFER_SIZE; - buf = kmalloc(len, GFP_KERNEL); - if (!buf) { - ret = -ENOMEM; - goto out; - } - - ret = rndis_query_oid(usbdev, OID_802_11_BSSID_LIST, buf, &len); - - if (ret != 0) - goto out; - - bssid_list = buf; - bssid = bssid_list->bssid; - bssid_len = le32_to_cpu(bssid->length); - count = le32_to_cpu(bssid_list->num_items); - devdbg(usbdev, "SIOCGIWSCAN: %d BSSIDs found", count); - - while (count && ((void *)bssid + bssid_len) <= (buf + len)) { - cev = rndis_translate_scan(dev, info, cev, - extra + IW_SCAN_MAX_DATA, bssid); - bssid = (void *)bssid + bssid_len; - bssid_len = le32_to_cpu(bssid->length); - count--; - } - -out: - wrqu->data.length = cev - extra; - wrqu->data.flags = 0; - kfree(buf); - return ret; + return add_wpa_key(usbdev, ext->key, ext->key_len, keyidx, &ext->addr, + ext->rx_seq, ext->alg, flags); } @@ -1815,7 +1713,7 @@ static int rndis_iw_set_genie(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); int ret = 0; #ifdef DEBUG @@ -1849,7 +1747,7 @@ static int rndis_iw_get_genie(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); devdbg(usbdev, "SIOCGIWGENIE"); @@ -1936,39 +1834,6 @@ static int rndis_iw_get_frag(struct net_device *dev, } -static int rndis_iw_set_nick(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); - - devdbg(usbdev, "SIOCSIWNICK"); - - priv->nick_len = wrqu->data.length; - if (priv->nick_len > 32) - priv->nick_len = 32; - - memcpy(priv->nick, extra, priv->nick_len); - return 0; -} - - -static int rndis_iw_get_nick(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); - - wrqu->data.flags = 1; - wrqu->data.length = priv->nick_len; - memcpy(extra, priv->nick, priv->nick_len); - - devdbg(usbdev, "SIOCGIWNICK: '%s'", priv->nick); - - return 0; -} - - static int rndis_iw_set_freq(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { @@ -2021,20 +1886,12 @@ static int rndis_iw_get_txpower(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); __le32 tx_power; - int ret = 0, len; if (priv->radio_on) { - if (priv->caps & CAP_SUPPORT_TXPOWER) { - len = sizeof(tx_power); - ret = rndis_query_oid(usbdev, OID_802_11_TX_POWER_LEVEL, - &tx_power, &len); - if (ret != 0) - return ret; - } else - /* fake incase not supported */ - tx_power = cpu_to_le32(get_bcm4320_power(priv)); + /* fake since changing tx_power (by userlevel) not supported */ + tx_power = cpu_to_le32(get_bcm4320_power(priv)); wrqu->txpower.flags = IW_TXPOW_MWATT; wrqu->txpower.value = le32_to_cpu(tx_power); @@ -2047,7 +1904,7 @@ static int rndis_iw_get_txpower(struct net_device *dev, devdbg(usbdev, "SIOCGIWTXPOW: %d", wrqu->txpower.value); - return ret; + return 0; } @@ -2055,9 +1912,8 @@ static int rndis_iw_set_txpower(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); __le32 tx_power = 0; - int ret = 0; if (!wrqu->txpower.disabled) { if (wrqu->txpower.flags == IW_TXPOW_MWATT) @@ -2080,22 +1936,10 @@ static int rndis_iw_set_txpower(struct net_device *dev, devdbg(usbdev, "SIOCSIWTXPOW: %d", le32_to_cpu(tx_power)); if (le32_to_cpu(tx_power) != 0) { - if (priv->caps & CAP_SUPPORT_TXPOWER) { - /* turn radio on first */ - if (!priv->radio_on) - disassociate(usbdev, 1); - - ret = rndis_set_oid(usbdev, OID_802_11_TX_POWER_LEVEL, - &tx_power, sizeof(tx_power)); - if (ret != 0) - ret = -EOPNOTSUPP; - return ret; - } else { - /* txpower unsupported, just turn radio on */ - if (!priv->radio_on) - return disassociate(usbdev, 1); - return 0; /* all ready on */ - } + /* txpower unsupported, just turn radio on */ + if (!priv->radio_on) + return disassociate(usbdev, 1); + return 0; /* all ready on */ } /* tx_power == 0, turn off radio */ @@ -2125,7 +1969,7 @@ static int rndis_iw_set_mlme(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct iw_mlme *mlme = (struct iw_mlme *)extra; unsigned char bssid[ETH_ALEN]; @@ -2150,7 +1994,7 @@ static int rndis_iw_set_mlme(struct net_device *dev, static struct iw_statistics *rndis_get_wireless_stats(struct net_device *dev) { struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); unsigned long flags; spin_lock_irqsave(&priv->stats_lock, flags); @@ -2165,20 +2009,18 @@ static struct iw_statistics *rndis_get_wireless_stats(struct net_device *dev) static const iw_handler rndis_iw_handler[] = { IW_IOCTL(SIOCSIWCOMMIT) = rndis_iw_commit, - IW_IOCTL(SIOCGIWNAME) = rndis_iw_get_name, + IW_IOCTL(SIOCGIWNAME) = (iw_handler) cfg80211_wext_giwname, IW_IOCTL(SIOCSIWFREQ) = rndis_iw_set_freq, IW_IOCTL(SIOCGIWFREQ) = rndis_iw_get_freq, - IW_IOCTL(SIOCSIWMODE) = rndis_iw_set_mode, - IW_IOCTL(SIOCGIWMODE) = rndis_iw_get_mode, - IW_IOCTL(SIOCGIWRANGE) = rndis_iw_get_range, + IW_IOCTL(SIOCSIWMODE) = (iw_handler) cfg80211_wext_siwmode, + IW_IOCTL(SIOCGIWMODE) = (iw_handler) cfg80211_wext_giwmode, + IW_IOCTL(SIOCGIWRANGE) = (iw_handler) cfg80211_wext_giwrange, IW_IOCTL(SIOCSIWAP) = rndis_iw_set_bssid, IW_IOCTL(SIOCGIWAP) = rndis_iw_get_bssid, - IW_IOCTL(SIOCSIWSCAN) = rndis_iw_set_scan, - IW_IOCTL(SIOCGIWSCAN) = rndis_iw_get_scan, + IW_IOCTL(SIOCSIWSCAN) = (iw_handler) cfg80211_wext_siwscan, + IW_IOCTL(SIOCGIWSCAN) = (iw_handler) cfg80211_wext_giwscan, IW_IOCTL(SIOCSIWESSID) = rndis_iw_set_essid, IW_IOCTL(SIOCGIWESSID) = rndis_iw_get_essid, - IW_IOCTL(SIOCSIWNICKN) = rndis_iw_set_nick, - IW_IOCTL(SIOCGIWNICKN) = rndis_iw_get_nick, IW_IOCTL(SIOCGIWRATE) = rndis_iw_get_rate, IW_IOCTL(SIOCSIWRTS) = rndis_iw_set_rts, IW_IOCTL(SIOCGIWRTS) = rndis_iw_get_rts, @@ -2195,28 +2037,28 @@ static const iw_handler rndis_iw_handler[] = IW_IOCTL(SIOCSIWMLME) = rndis_iw_set_mlme, }; -static const iw_handler rndis_wext_private_handler[] = { +static const iw_handler rndis_wlan_private_handler[] = { }; -static const struct iw_priv_args rndis_wext_private_args[] = { +static const struct iw_priv_args rndis_wlan_private_args[] = { }; static const struct iw_handler_def rndis_iw_handlers = { .num_standard = ARRAY_SIZE(rndis_iw_handler), - .num_private = ARRAY_SIZE(rndis_wext_private_handler), - .num_private_args = ARRAY_SIZE(rndis_wext_private_args), + .num_private = ARRAY_SIZE(rndis_wlan_private_handler), + .num_private_args = ARRAY_SIZE(rndis_wlan_private_args), .standard = (iw_handler *)rndis_iw_handler, - .private = (iw_handler *)rndis_wext_private_handler, - .private_args = (struct iw_priv_args *)rndis_wext_private_args, + .private = (iw_handler *)rndis_wlan_private_handler, + .private_args = (struct iw_priv_args *)rndis_wlan_private_args, .get_wireless_stats = rndis_get_wireless_stats, }; -static void rndis_wext_worker(struct work_struct *work) +static void rndis_wlan_worker(struct work_struct *work) { - struct rndis_wext_private *priv = - container_of(work, struct rndis_wext_private, work); + struct rndis_wlan_private *priv = + container_of(work, struct rndis_wlan_private, work); struct usbnet *usbdev = priv->usbdev; union iwreq_data evt; unsigned char bssid[ETH_ALEN]; @@ -2277,10 +2119,10 @@ get_bssid: set_multicast_list(usbdev); } -static void rndis_wext_set_multicast_list(struct net_device *dev) +static void rndis_wlan_set_multicast_list(struct net_device *dev) { struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); if (test_bit(WORK_SET_MULTICAST_LIST, &priv->work_pending)) return; @@ -2289,9 +2131,9 @@ static void rndis_wext_set_multicast_list(struct net_device *dev) queue_work(priv->workqueue, &priv->work); } -static void rndis_wext_link_change(struct usbnet *usbdev, int state) +static void rndis_wlan_link_change(struct usbnet *usbdev, int state) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); /* queue work to avoid recursive calls into rndis_command */ set_bit(state ? WORK_LINK_UP : WORK_LINK_DOWN, &priv->work_pending); @@ -2299,22 +2141,14 @@ static void rndis_wext_link_change(struct usbnet *usbdev, int state) } -static int rndis_wext_get_caps(struct usbnet *usbdev) +static int rndis_wlan_get_caps(struct usbnet *usbdev) { struct { __le32 num_items; __le32 items[8]; } networks_supported; int len, retval, i, n; - __le32 tx_power; - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); - - /* determine if supports setting txpower */ - len = sizeof(tx_power); - retval = rndis_query_oid(usbdev, OID_802_11_TX_POWER_LEVEL, &tx_power, - &len); - if (retval == 0 && le32_to_cpu(tx_power) != 0xFF) - priv->caps |= CAP_SUPPORT_TXPOWER; + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); /* determine supported modes */ len = sizeof(networks_supported); @@ -2326,24 +2160,18 @@ static int rndis_wext_get_caps(struct usbnet *usbdev) n = 8; for (i = 0; i < n; i++) { switch (le32_to_cpu(networks_supported.items[i])) { - case ndis_80211_type_freq_hop: - case ndis_80211_type_direct_seq: + case NDIS_80211_TYPE_FREQ_HOP: + case NDIS_80211_TYPE_DIRECT_SEQ: priv->caps |= CAP_MODE_80211B; break; - case ndis_80211_type_ofdm_a: + case NDIS_80211_TYPE_OFDM_A: priv->caps |= CAP_MODE_80211A; break; - case ndis_80211_type_ofdm_g: + case NDIS_80211_TYPE_OFDM_G: priv->caps |= CAP_MODE_80211G; break; } } - if (priv->caps & CAP_MODE_80211A) - strcat(priv->name, "a"); - if (priv->caps & CAP_MODE_80211B) - strcat(priv->name, "b"); - if (priv->caps & CAP_MODE_80211G) - strcat(priv->name, "g"); } return retval; @@ -2353,8 +2181,8 @@ static int rndis_wext_get_caps(struct usbnet *usbdev) #define STATS_UPDATE_JIFFIES (HZ) static void rndis_update_wireless_stats(struct work_struct *work) { - struct rndis_wext_private *priv = - container_of(work, struct rndis_wext_private, stats_work.work); + struct rndis_wlan_private *priv = + container_of(work, struct rndis_wlan_private, stats_work.work); struct usbnet *usbdev = priv->usbdev; struct iw_statistics iwstats; __le32 rssi, tmp; @@ -2387,7 +2215,7 @@ static void rndis_update_wireless_stats(struct work_struct *work) if (ret == 0) { memset(&iwstats.qual, 0, sizeof(iwstats.qual)); iwstats.qual.qual = level_to_qual(le32_to_cpu(rssi)); - iwstats.qual.level = le32_to_cpu(rssi); + iwstats.qual.level = level_to_qual(le32_to_cpu(rssi)); iwstats.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED | IW_QUAL_NOISE_INVALID; @@ -2457,9 +2285,19 @@ end: } -static int bcm4320_early_init(struct usbnet *usbdev) +static int bcm4320a_early_init(struct usbnet *usbdev) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + /* bcm4320a doesn't handle configuration parameters well. Try + * set any and you get partially zeroed mac and broken device. + */ + + return 0; +} + + +static int bcm4320b_early_init(struct usbnet *usbdev) +{ + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); char buf[8]; /* Early initialization settings, setting these won't have effect @@ -2525,33 +2363,41 @@ static int bcm4320_early_init(struct usbnet *usbdev) } /* same as rndis_netdev_ops but with local multicast handler */ -static const struct net_device_ops rndis_wext_netdev_ops = { +static const struct net_device_ops rndis_wlan_netdev_ops = { .ndo_open = usbnet_open, .ndo_stop = usbnet_stop, .ndo_start_xmit = usbnet_start_xmit, .ndo_tx_timeout = usbnet_tx_timeout, .ndo_set_mac_address = eth_mac_addr, .ndo_validate_addr = eth_validate_addr, - .ndo_set_multicast_list = rndis_wext_set_multicast_list, + .ndo_set_multicast_list = rndis_wlan_set_multicast_list, }; -static int rndis_wext_bind(struct usbnet *usbdev, struct usb_interface *intf) +static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf) { - struct rndis_wext_private *priv; + struct wiphy *wiphy; + struct rndis_wlan_private *priv; int retval, len; __le32 tmp; - /* allocate rndis private data */ - priv = kzalloc(sizeof(struct rndis_wext_private), GFP_KERNEL); - if (!priv) + /* allocate wiphy and rndis private data + * NOTE: We only support a single virtual interface, so wiphy + * and wireless_dev are somewhat synonymous for this device. + */ + wiphy = wiphy_new(&rndis_config_ops, sizeof(struct rndis_wlan_private)); + if (!wiphy) return -ENOMEM; + priv = wiphy_priv(wiphy); + usbdev->net->ieee80211_ptr = &priv->wdev; + priv->wdev.wiphy = wiphy; + priv->wdev.iftype = NL80211_IFTYPE_STATION; + /* These have to be initialized before calling generic_rndis_bind(). - * Otherwise we'll be in big trouble in rndis_wext_early_init(). + * Otherwise we'll be in big trouble in rndis_wlan_early_init(). */ usbdev->driver_priv = priv; - strcpy(priv->name, "IEEE802.11"); usbdev->net->wireless_handlers = &rndis_iw_handlers; priv->usbdev = usbdev; @@ -2560,8 +2406,9 @@ static int rndis_wext_bind(struct usbnet *usbdev, struct usb_interface *intf) /* because rndis_command() sleeps we need to use workqueue */ priv->workqueue = create_singlethread_workqueue("rndis_wlan"); - INIT_WORK(&priv->work, rndis_wext_worker); + INIT_WORK(&priv->work, rndis_wlan_worker); INIT_DELAYED_WORK(&priv->stats_work, rndis_update_wireless_stats); + INIT_DELAYED_WORK(&priv->scan_work, rndis_get_scan_results); /* try bind rndis_host */ retval = generic_rndis_bind(usbdev, intf, FLAG_RNDIS_PHYM_WIRELESS); @@ -2573,9 +2420,9 @@ static int rndis_wext_bind(struct usbnet *usbdev, struct usb_interface *intf) * picks up rssi to closest station instead of to access point). * * rndis_host wants to avoid all OID as much as possible - * so do promisc/multicast handling in rndis_wext. + * so do promisc/multicast handling in rndis_wlan. */ - usbdev->net->netdev_ops = &rndis_wext_netdev_ops; + usbdev->net->netdev_ops = &rndis_wlan_netdev_ops; tmp = RNDIS_PACKET_TYPE_DIRECTED | RNDIS_PACKET_TYPE_BROADCAST; retval = rndis_set_oid(usbdev, OID_GEN_CURRENT_PACKET_FILTER, &tmp, @@ -2600,7 +2447,32 @@ static int rndis_wext_bind(struct usbnet *usbdev, struct usb_interface *intf) | IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID; - rndis_wext_get_caps(usbdev); + /* fill-out wiphy structure and register w/ cfg80211 */ + memcpy(wiphy->perm_addr, usbdev->net->dev_addr, ETH_ALEN); + wiphy->privid = rndis_wiphy_privid; + wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) + | BIT(NL80211_IFTYPE_ADHOC); + wiphy->max_scan_ssids = 1; + + /* TODO: fill-out band information based on priv->caps */ + rndis_wlan_get_caps(usbdev); + + memcpy(priv->channels, rndis_channels, sizeof(rndis_channels)); + memcpy(priv->rates, rndis_rates, sizeof(rndis_rates)); + priv->band.channels = priv->channels; + priv->band.n_channels = ARRAY_SIZE(rndis_channels); + priv->band.bitrates = priv->rates; + priv->band.n_bitrates = ARRAY_SIZE(rndis_rates); + wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band; + wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC; + + set_wiphy_dev(wiphy, &usbdev->udev->dev); + + if (wiphy_register(wiphy)) { + retval = -ENODEV; + goto fail; + } + set_default_iw_params(usbdev); /* turn radio on */ @@ -2615,36 +2487,40 @@ static int rndis_wext_bind(struct usbnet *usbdev, struct usb_interface *intf) fail: cancel_delayed_work_sync(&priv->stats_work); + cancel_delayed_work_sync(&priv->scan_work); cancel_work_sync(&priv->work); flush_workqueue(priv->workqueue); destroy_workqueue(priv->workqueue); - kfree(priv); + wiphy_free(wiphy); return retval; } -static void rndis_wext_unbind(struct usbnet *usbdev, struct usb_interface *intf) +static void rndis_wlan_unbind(struct usbnet *usbdev, struct usb_interface *intf) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); /* turn radio off */ disassociate(usbdev, 0); cancel_delayed_work_sync(&priv->stats_work); + cancel_delayed_work_sync(&priv->scan_work); cancel_work_sync(&priv->work); flush_workqueue(priv->workqueue); destroy_workqueue(priv->workqueue); if (priv && priv->wpa_ie_len) kfree(priv->wpa_ie); - kfree(priv); rndis_unbind(usbdev, intf); + + wiphy_unregister(priv->wdev.wiphy); + wiphy_free(priv->wdev.wiphy); } -static int rndis_wext_reset(struct usbnet *usbdev) +static int rndis_wlan_reset(struct usbnet *usbdev) { return deauthenticate(usbdev); } @@ -2653,40 +2529,40 @@ static int rndis_wext_reset(struct usbnet *usbdev) static const struct driver_info bcm4320b_info = { .description = "Wireless RNDIS device, BCM4320b based", .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT, - .bind = rndis_wext_bind, - .unbind = rndis_wext_unbind, + .bind = rndis_wlan_bind, + .unbind = rndis_wlan_unbind, .status = rndis_status, .rx_fixup = rndis_rx_fixup, .tx_fixup = rndis_tx_fixup, - .reset = rndis_wext_reset, - .early_init = bcm4320_early_init, - .link_change = rndis_wext_link_change, + .reset = rndis_wlan_reset, + .early_init = bcm4320b_early_init, + .link_change = rndis_wlan_link_change, }; static const struct driver_info bcm4320a_info = { .description = "Wireless RNDIS device, BCM4320a based", .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT, - .bind = rndis_wext_bind, - .unbind = rndis_wext_unbind, + .bind = rndis_wlan_bind, + .unbind = rndis_wlan_unbind, .status = rndis_status, .rx_fixup = rndis_rx_fixup, .tx_fixup = rndis_tx_fixup, - .reset = rndis_wext_reset, - .early_init = bcm4320_early_init, - .link_change = rndis_wext_link_change, + .reset = rndis_wlan_reset, + .early_init = bcm4320a_early_init, + .link_change = rndis_wlan_link_change, }; -static const struct driver_info rndis_wext_info = { +static const struct driver_info rndis_wlan_info = { .description = "Wireless RNDIS device", .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT, - .bind = rndis_wext_bind, - .unbind = rndis_wext_unbind, + .bind = rndis_wlan_bind, + .unbind = rndis_wlan_unbind, .status = rndis_status, .rx_fixup = rndis_rx_fixup, .tx_fixup = rndis_tx_fixup, - .reset = rndis_wext_reset, - .early_init = bcm4320_early_init, - .link_change = rndis_wext_link_change, + .reset = rndis_wlan_reset, + .early_init = bcm4320a_early_init, + .link_change = rndis_wlan_link_change, }; /*-------------------------------------------------------------------------*/ @@ -2796,11 +2672,11 @@ static const struct usb_device_id products [] = { { /* RNDIS is MSFT's un-official variant of CDC ACM */ USB_INTERFACE_INFO(USB_CLASS_COMM, 2 /* ACM */, 0x0ff), - .driver_info = (unsigned long) &rndis_wext_info, + .driver_info = (unsigned long) &rndis_wlan_info, }, { /* "ActiveSync" is an undocumented variant of RNDIS, used in WM5 */ USB_INTERFACE_INFO(USB_CLASS_MISC, 1, 1), - .driver_info = (unsigned long) &rndis_wext_info, + .driver_info = (unsigned long) &rndis_wlan_info, }, { }, // END }; diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index bfc5d9cf716e..8aab3e6754bd 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig @@ -9,11 +9,11 @@ menuconfig RT2X00 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". + a module) will be called rt2x00lib. 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". + called rt2x00pci and rt2x00usb. if RT2X00 @@ -26,7 +26,7 @@ config RT2400PCI This adds support for rt2400 wireless chipset family. Supported chips: RT2460. - When compiled as a module, this driver will be called "rt2400pci.ko". + When compiled as a module, this driver will be called rt2400pci. config RT2500PCI tristate "Ralink rt2500 (PCI/PCMCIA) support" @@ -37,7 +37,7 @@ config RT2500PCI This adds support for rt2500 wireless chipset family. Supported chips: RT2560. - When compiled as a module, this driver will be called "rt2500pci.ko". + When compiled as a module, this driver will be called rt2500pci. config RT61PCI tristate "Ralink rt2501/rt61 (PCI/PCMCIA) support" @@ -51,7 +51,7 @@ config RT61PCI 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". + When compiled as a module, this driver will be called rt61pci. config RT2500USB tristate "Ralink rt2500 (USB) support" @@ -62,7 +62,7 @@ config RT2500USB This adds support for rt2500 wireless chipset family. Supported chips: RT2571 & RT2572. - When compiled as a module, this driver will be called "rt2500usb.ko". + When compiled as a module, this driver will be called rt2500usb. config RT73USB tristate "Ralink rt2501/rt73 (USB) support" @@ -75,7 +75,21 @@ config RT73USB 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". + When compiled as a module, this driver will be called rt73usb. + +config RT2800USB + tristate "Ralink rt2800 (USB) support" + depends on USB + select RT2X00_LIB_USB + select RT2X00_LIB_HT + select RT2X00_LIB_FIRMWARE + select RT2X00_LIB_CRYPTO + select CRC_CCITT + ---help--- + This adds support for rt2800 wireless chipset family. + Supported chips: RT2770, RT2870 & RT3070. + + When compiled as a module, this driver will be called "rt2800usb.ko". config RT2X00_LIB_PCI tristate @@ -88,6 +102,9 @@ config RT2X00_LIB_USB config RT2X00_LIB tristate +config RT2X00_LIB_HT + boolean + config RT2X00_LIB_FIRMWARE boolean select FW_LOADER diff --git a/drivers/net/wireless/rt2x00/Makefile b/drivers/net/wireless/rt2x00/Makefile index f22d808d8c51..bfc7226f0afe 100644 --- a/drivers/net/wireless/rt2x00/Makefile +++ b/drivers/net/wireless/rt2x00/Makefile @@ -8,6 +8,7 @@ rt2x00lib-$(CONFIG_RT2X00_LIB_CRYPTO) += rt2x00crypto.o rt2x00lib-$(CONFIG_RT2X00_LIB_RFKILL) += rt2x00rfkill.o rt2x00lib-$(CONFIG_RT2X00_LIB_FIRMWARE) += rt2x00firmware.o rt2x00lib-$(CONFIG_RT2X00_LIB_LEDS) += rt2x00leds.o +rt2x00lib-$(CONFIG_RT2X00_LIB_HT) += rt2x00ht.o obj-$(CONFIG_RT2X00_LIB) += rt2x00lib.o obj-$(CONFIG_RT2X00_LIB_PCI) += rt2x00pci.o @@ -17,3 +18,4 @@ obj-$(CONFIG_RT2500PCI) += rt2500pci.o obj-$(CONFIG_RT61PCI) += rt61pci.o obj-$(CONFIG_RT2500USB) += rt2500usb.o obj-$(CONFIG_RT73USB) += rt73usb.o +obj-$(CONFIG_RT2800USB) += rt2800usb.o diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 0f08773328c6..435f945fe64d 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -335,10 +335,11 @@ static void rt2400pci_config_erp(struct rt2x00_dev *rt2x00dev, preamble_mask = erp->short_preamble << 3; rt2x00pci_register_read(rt2x00dev, TXCSR1, ®); - rt2x00_set_field32(®, TXCSR1_ACK_TIMEOUT, - erp->ack_timeout); + rt2x00_set_field32(®, TXCSR1_ACK_TIMEOUT, erp->ack_timeout); rt2x00_set_field32(®, TXCSR1_ACK_CONSUME_TIME, erp->ack_consume_time); + rt2x00_set_field32(®, TXCSR1_TSF_OFFSET, IEEE80211_HEADER); + rt2x00_set_field32(®, TXCSR1_AUTORESPONDER, 1); rt2x00pci_register_write(rt2x00dev, TXCSR1, reg); rt2x00pci_register_read(rt2x00dev, ARCSR2, ®); @@ -371,6 +372,11 @@ static void rt2400pci_config_erp(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, CSR11_SLOT_TIME, erp->slot_time); rt2x00pci_register_write(rt2x00dev, CSR11, reg); + rt2x00pci_register_read(rt2x00dev, CSR12, ®); + rt2x00_set_field32(®, CSR12_BEACON_INTERVAL, erp->beacon_int * 16); + rt2x00_set_field32(®, CSR12_CFP_MAX_DURATION, erp->beacon_int * 16); + rt2x00pci_register_write(rt2x00dev, CSR12, reg); + rt2x00pci_register_read(rt2x00dev, CSR18, ®); rt2x00_set_field32(®, CSR18_SIFS, erp->sifs); rt2x00_set_field32(®, CSR18_PIFS, erp->pifs); @@ -503,24 +509,6 @@ static void rt2400pci_config_retry_limit(struct rt2x00_dev *rt2x00dev, rt2x00pci_register_write(rt2x00dev, CSR11, reg); } -static void rt2400pci_config_duration(struct rt2x00_dev *rt2x00dev, - struct rt2x00lib_conf *libconf) -{ - u32 reg; - - rt2x00pci_register_read(rt2x00dev, TXCSR1, ®); - rt2x00_set_field32(®, TXCSR1_TSF_OFFSET, IEEE80211_HEADER); - rt2x00_set_field32(®, TXCSR1_AUTORESPONDER, 1); - rt2x00pci_register_write(rt2x00dev, TXCSR1, reg); - - rt2x00pci_register_read(rt2x00dev, CSR12, ®); - rt2x00_set_field32(®, CSR12_BEACON_INTERVAL, - libconf->conf->beacon_int * 16); - rt2x00_set_field32(®, CSR12_CFP_MAX_DURATION, - libconf->conf->beacon_int * 16); - rt2x00pci_register_write(rt2x00dev, CSR12, reg); -} - static void rt2400pci_config_ps(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_conf *libconf) { @@ -532,7 +520,7 @@ static void rt2400pci_config_ps(struct rt2x00_dev *rt2x00dev, if (state == STATE_SLEEP) { rt2x00pci_register_read(rt2x00dev, CSR20, ®); rt2x00_set_field32(®, CSR20_DELAY_AFTER_TBCN, - (libconf->conf->beacon_int - 20) * 16); + (rt2x00dev->beacon_int - 20) * 16); rt2x00_set_field32(®, CSR20_TBCN_BEFORE_WAKEUP, libconf->conf->listen_interval - 1); @@ -558,8 +546,6 @@ static void rt2400pci_config(struct rt2x00_dev *rt2x00dev, libconf->conf->power_level); if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS) rt2400pci_config_retry_limit(rt2x00dev, libconf); - if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL) - rt2400pci_config_duration(rt2x00dev, libconf); if (flags & IEEE80211_CONF_CHANGE_PS) rt2400pci_config_ps(rt2x00dev, libconf); } @@ -1361,7 +1347,7 @@ static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev) */ value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); rt2x00pci_register_read(rt2x00dev, CSR0, ®); - rt2x00_set_chip(rt2x00dev, RT2460, value, reg); + rt2x00_set_chip_rf(rt2x00dev, value, reg); if (!rt2x00_rf(&rt2x00dev->chip, RF2420) && !rt2x00_rf(&rt2x00dev->chip, RF2421)) { @@ -1580,7 +1566,6 @@ static const struct ieee80211_ops rt2400pci_mac80211_ops = { .add_interface = rt2x00mac_add_interface, .remove_interface = rt2x00mac_remove_interface, .config = rt2x00mac_config, - .config_interface = rt2x00mac_config_interface, .configure_filter = rt2x00mac_configure_filter, .get_stats = rt2x00mac_get_stats, .bss_info_changed = rt2x00mac_bss_info_changed, diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 276a8232aaa0..08b30d01e67d 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -341,10 +341,11 @@ static void rt2500pci_config_erp(struct rt2x00_dev *rt2x00dev, preamble_mask = erp->short_preamble << 3; rt2x00pci_register_read(rt2x00dev, TXCSR1, ®); - rt2x00_set_field32(®, TXCSR1_ACK_TIMEOUT, - erp->ack_timeout); + rt2x00_set_field32(®, TXCSR1_ACK_TIMEOUT, erp->ack_timeout); rt2x00_set_field32(®, TXCSR1_ACK_CONSUME_TIME, erp->ack_consume_time); + rt2x00_set_field32(®, TXCSR1_TSF_OFFSET, IEEE80211_HEADER); + rt2x00_set_field32(®, TXCSR1_AUTORESPONDER, 1); rt2x00pci_register_write(rt2x00dev, TXCSR1, reg); rt2x00pci_register_read(rt2x00dev, ARCSR2, ®); @@ -377,6 +378,11 @@ static void rt2500pci_config_erp(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, CSR11_SLOT_TIME, erp->slot_time); rt2x00pci_register_write(rt2x00dev, CSR11, reg); + rt2x00pci_register_read(rt2x00dev, CSR12, ®); + rt2x00_set_field32(®, CSR12_BEACON_INTERVAL, erp->beacon_int * 16); + rt2x00_set_field32(®, CSR12_CFP_MAX_DURATION, erp->beacon_int * 16); + rt2x00pci_register_write(rt2x00dev, CSR12, reg); + rt2x00pci_register_read(rt2x00dev, CSR18, ®); rt2x00_set_field32(®, CSR18_SIFS, erp->sifs); rt2x00_set_field32(®, CSR18_PIFS, erp->pifs); @@ -552,24 +558,6 @@ static void rt2500pci_config_retry_limit(struct rt2x00_dev *rt2x00dev, rt2x00pci_register_write(rt2x00dev, CSR11, reg); } -static void rt2500pci_config_duration(struct rt2x00_dev *rt2x00dev, - struct rt2x00lib_conf *libconf) -{ - u32 reg; - - rt2x00pci_register_read(rt2x00dev, TXCSR1, ®); - rt2x00_set_field32(®, TXCSR1_TSF_OFFSET, IEEE80211_HEADER); - rt2x00_set_field32(®, TXCSR1_AUTORESPONDER, 1); - rt2x00pci_register_write(rt2x00dev, TXCSR1, reg); - - rt2x00pci_register_read(rt2x00dev, CSR12, ®); - rt2x00_set_field32(®, CSR12_BEACON_INTERVAL, - libconf->conf->beacon_int * 16); - rt2x00_set_field32(®, CSR12_CFP_MAX_DURATION, - libconf->conf->beacon_int * 16); - rt2x00pci_register_write(rt2x00dev, CSR12, reg); -} - static void rt2500pci_config_ps(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_conf *libconf) { @@ -581,7 +569,7 @@ static void rt2500pci_config_ps(struct rt2x00_dev *rt2x00dev, if (state == STATE_SLEEP) { rt2x00pci_register_read(rt2x00dev, CSR20, ®); rt2x00_set_field32(®, CSR20_DELAY_AFTER_TBCN, - (libconf->conf->beacon_int - 20) * 16); + (rt2x00dev->beacon_int - 20) * 16); rt2x00_set_field32(®, CSR20_TBCN_BEFORE_WAKEUP, libconf->conf->listen_interval - 1); @@ -609,8 +597,6 @@ static void rt2500pci_config(struct rt2x00_dev *rt2x00dev, libconf->conf->power_level); if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS) rt2500pci_config_retry_limit(rt2x00dev, libconf); - if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL) - rt2500pci_config_duration(rt2x00dev, libconf); if (flags & IEEE80211_CONF_CHANGE_PS) rt2500pci_config_ps(rt2x00dev, libconf); } @@ -1525,7 +1511,7 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev) */ value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); rt2x00pci_register_read(rt2x00dev, CSR0, ®); - rt2x00_set_chip(rt2x00dev, RT2560, value, reg); + rt2x00_set_chip_rf(rt2x00dev, value, reg); if (!rt2x00_rf(&rt2x00dev->chip, RF2522) && !rt2x00_rf(&rt2x00dev->chip, RF2523) && @@ -1879,7 +1865,6 @@ static const struct ieee80211_ops rt2500pci_mac80211_ops = { .add_interface = rt2x00mac_add_interface, .remove_interface = rt2x00mac_remove_interface, .config = rt2x00mac_config, - .config_interface = rt2x00mac_config_interface, .configure_filter = rt2x00mac_configure_filter, .get_stats = rt2x00mac_get_stats, .bss_info_changed = rt2x00mac_bss_info_changed, diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 9e630e70fc97..66daf68ff0ee 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -503,6 +503,10 @@ static void rt2500usb_config_erp(struct rt2x00_dev *rt2x00dev, rt2500usb_register_write(rt2x00dev, TXRX_CSR11, erp->basic_rates); + rt2500usb_register_read(rt2x00dev, TXRX_CSR18, ®); + rt2x00_set_field16(®, TXRX_CSR18_INTERVAL, erp->beacon_int * 4); + rt2500usb_register_write(rt2x00dev, TXRX_CSR18, reg); + rt2500usb_register_write(rt2x00dev, MAC_CSR10, erp->slot_time); rt2500usb_register_write(rt2x00dev, MAC_CSR11, erp->sifs); rt2500usb_register_write(rt2x00dev, MAC_CSR12, erp->eifs); @@ -632,17 +636,6 @@ static void rt2500usb_config_txpower(struct rt2x00_dev *rt2x00dev, rt2500usb_rf_write(rt2x00dev, 3, rf3); } -static void rt2500usb_config_duration(struct rt2x00_dev *rt2x00dev, - struct rt2x00lib_conf *libconf) -{ - u16 reg; - - rt2500usb_register_read(rt2x00dev, TXRX_CSR18, ®); - rt2x00_set_field16(®, TXRX_CSR18_INTERVAL, - libconf->conf->beacon_int * 4); - rt2500usb_register_write(rt2x00dev, TXRX_CSR18, reg); -} - static void rt2500usb_config_ps(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_conf *libconf) { @@ -654,7 +647,7 @@ static void rt2500usb_config_ps(struct rt2x00_dev *rt2x00dev, if (state == STATE_SLEEP) { rt2500usb_register_read(rt2x00dev, MAC_CSR18, ®); rt2x00_set_field16(®, MAC_CSR18_DELAY_AFTER_BEACON, - libconf->conf->beacon_int - 20); + rt2x00dev->beacon_int - 20); rt2x00_set_field16(®, MAC_CSR18_BEACONS_BEFORE_WAKEUP, libconf->conf->listen_interval - 1); @@ -680,8 +673,6 @@ static void rt2500usb_config(struct rt2x00_dev *rt2x00dev, !(flags & IEEE80211_CONF_CHANGE_CHANNEL)) rt2500usb_config_txpower(rt2x00dev, libconf->conf->power_level); - if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL) - rt2500usb_config_duration(rt2x00dev, libconf); if (flags & IEEE80211_CONF_CHANGE_PS) rt2500usb_config_ps(rt2x00dev, libconf); } @@ -1559,7 +1550,7 @@ static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev) rt2500usb_register_read(rt2x00dev, MAC_CSR0, ®); rt2x00_set_chip(rt2x00dev, RT2570, value, reg); - if (!rt2x00_check_rev(&rt2x00dev->chip, 0)) { + if (!rt2x00_check_rev(&rt2x00dev->chip, 0x000ffff0, 0)) { ERROR(rt2x00dev, "Invalid RT chipset detected.\n"); return -ENODEV; } @@ -1908,7 +1899,6 @@ static const struct ieee80211_ops rt2500usb_mac80211_ops = { .add_interface = rt2x00mac_add_interface, .remove_interface = rt2x00mac_remove_interface, .config = rt2x00mac_config, - .config_interface = rt2x00mac_config_interface, .configure_filter = rt2x00mac_configure_filter, .set_key = rt2x00mac_set_key, .get_stats = rt2x00mac_get_stats, diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c new file mode 100644 index 000000000000..37561667925b --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -0,0 +1,3078 @@ +/* + Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the + Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + Module: rt2800usb + Abstract: rt2800usb device specific routines. + Supported chipsets: RT2800U. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "rt2x00.h" +#include "rt2x00usb.h" +#include "rt2800usb.h" + +/* + * Allow hardware encryption to be disabled. + */ +static int modparam_nohwcrypt = 1; +module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); +MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); + +/* + * Register access. + * All access to the CSR registers will go through the methods + * rt2x00usb_register_read and rt2x00usb_register_write. + * BBP and RF register require indirect register access, + * and use the CSR registers BBPCSR and RFCSR to achieve this. + * These indirect registers work with busy bits, + * and we will try maximal REGISTER_BUSY_COUNT times to access + * the register while taking a REGISTER_BUSY_DELAY us delay + * between each attampt. When the busy bit is still set at that time, + * the access attempt is considered to have failed, + * and we will print an error. + * The _lock versions must be used if you already hold the csr_mutex + */ +#define WAIT_FOR_BBP(__dev, __reg) \ + rt2x00usb_regbusy_read((__dev), BBP_CSR_CFG, BBP_CSR_CFG_BUSY, (__reg)) +#define WAIT_FOR_RFCSR(__dev, __reg) \ + rt2x00usb_regbusy_read((__dev), RF_CSR_CFG, RF_CSR_CFG_BUSY, (__reg)) +#define WAIT_FOR_RF(__dev, __reg) \ + rt2x00usb_regbusy_read((__dev), RF_CSR_CFG0, RF_CSR_CFG0_BUSY, (__reg)) +#define WAIT_FOR_MCU(__dev, __reg) \ + rt2x00usb_regbusy_read((__dev), H2M_MAILBOX_CSR, \ + H2M_MAILBOX_CSR_OWNER, (__reg)) + +static void rt2800usb_bbp_write(struct rt2x00_dev *rt2x00dev, + const unsigned int word, const u8 value) +{ + u32 reg; + + mutex_lock(&rt2x00dev->csr_mutex); + + /* + * Wait until the BBP becomes available, afterwards we + * can safely write the new data into the register. + */ + if (WAIT_FOR_BBP(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, BBP_CSR_CFG_VALUE, value); + rt2x00_set_field32(®, BBP_CSR_CFG_REGNUM, word); + rt2x00_set_field32(®, BBP_CSR_CFG_BUSY, 1); + rt2x00_set_field32(®, BBP_CSR_CFG_READ_CONTROL, 0); + + rt2x00usb_register_write_lock(rt2x00dev, BBP_CSR_CFG, reg); + } + + mutex_unlock(&rt2x00dev->csr_mutex); +} + +static void rt2800usb_bbp_read(struct rt2x00_dev *rt2x00dev, + const unsigned int word, u8 *value) +{ + u32 reg; + + mutex_lock(&rt2x00dev->csr_mutex); + + /* + * Wait until the BBP becomes available, afterwards we + * can safely write the read request into the register. + * After the data has been written, we wait until hardware + * returns the correct value, if at any time the register + * doesn't become available in time, reg will be 0xffffffff + * which means we return 0xff to the caller. + */ + if (WAIT_FOR_BBP(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, BBP_CSR_CFG_REGNUM, word); + rt2x00_set_field32(®, BBP_CSR_CFG_BUSY, 1); + rt2x00_set_field32(®, BBP_CSR_CFG_READ_CONTROL, 1); + + rt2x00usb_register_write_lock(rt2x00dev, BBP_CSR_CFG, reg); + + WAIT_FOR_BBP(rt2x00dev, ®); + } + + *value = rt2x00_get_field32(reg, BBP_CSR_CFG_VALUE); + + mutex_unlock(&rt2x00dev->csr_mutex); +} + +static void rt2800usb_rfcsr_write(struct rt2x00_dev *rt2x00dev, + const unsigned int word, const u8 value) +{ + u32 reg; + + mutex_lock(&rt2x00dev->csr_mutex); + + /* + * Wait until the RFCSR becomes available, afterwards we + * can safely write the new data into the register. + */ + if (WAIT_FOR_RFCSR(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, RF_CSR_CFG_DATA, value); + rt2x00_set_field32(®, RF_CSR_CFG_REGNUM, word); + rt2x00_set_field32(®, RF_CSR_CFG_WRITE, 1); + rt2x00_set_field32(®, RF_CSR_CFG_BUSY, 1); + + rt2x00usb_register_write_lock(rt2x00dev, RF_CSR_CFG, reg); + } + + mutex_unlock(&rt2x00dev->csr_mutex); +} + +static void rt2800usb_rfcsr_read(struct rt2x00_dev *rt2x00dev, + const unsigned int word, u8 *value) +{ + u32 reg; + + mutex_lock(&rt2x00dev->csr_mutex); + + /* + * Wait until the RFCSR becomes available, afterwards we + * can safely write the read request into the register. + * After the data has been written, we wait until hardware + * returns the correct value, if at any time the register + * doesn't become available in time, reg will be 0xffffffff + * which means we return 0xff to the caller. + */ + if (WAIT_FOR_RFCSR(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, RF_CSR_CFG_REGNUM, word); + rt2x00_set_field32(®, RF_CSR_CFG_WRITE, 0); + rt2x00_set_field32(®, RF_CSR_CFG_BUSY, 1); + + rt2x00usb_register_write_lock(rt2x00dev, BBP_CSR_CFG, reg); + + WAIT_FOR_RFCSR(rt2x00dev, ®); + } + + *value = rt2x00_get_field32(reg, RF_CSR_CFG_DATA); + + mutex_unlock(&rt2x00dev->csr_mutex); +} + +static void rt2800usb_rf_write(struct rt2x00_dev *rt2x00dev, + const unsigned int word, const u32 value) +{ + u32 reg; + + mutex_lock(&rt2x00dev->csr_mutex); + + /* + * Wait until the RF becomes available, afterwards we + * can safely write the new data into the register. + */ + if (WAIT_FOR_RF(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, RF_CSR_CFG0_REG_VALUE_BW, value); + rt2x00_set_field32(®, RF_CSR_CFG0_STANDBYMODE, 0); + rt2x00_set_field32(®, RF_CSR_CFG0_SEL, 0); + rt2x00_set_field32(®, RF_CSR_CFG0_BUSY, 1); + + rt2x00usb_register_write_lock(rt2x00dev, RF_CSR_CFG0, reg); + rt2x00_rf_write(rt2x00dev, word, value); + } + + mutex_unlock(&rt2x00dev->csr_mutex); +} + +static void rt2800usb_mcu_request(struct rt2x00_dev *rt2x00dev, + const u8 command, const u8 token, + const u8 arg0, const u8 arg1) +{ + u32 reg; + + mutex_lock(&rt2x00dev->csr_mutex); + + /* + * Wait until the MCU becomes available, afterwards we + * can safely write the new data into the register. + */ + if (WAIT_FOR_MCU(rt2x00dev, ®)) { + rt2x00_set_field32(®, H2M_MAILBOX_CSR_OWNER, 1); + rt2x00_set_field32(®, H2M_MAILBOX_CSR_CMD_TOKEN, token); + rt2x00_set_field32(®, H2M_MAILBOX_CSR_ARG0, arg0); + rt2x00_set_field32(®, H2M_MAILBOX_CSR_ARG1, arg1); + rt2x00usb_register_write_lock(rt2x00dev, H2M_MAILBOX_CSR, reg); + + reg = 0; + rt2x00_set_field32(®, HOST_CMD_CSR_HOST_COMMAND, command); + rt2x00usb_register_write_lock(rt2x00dev, HOST_CMD_CSR, reg); + } + + mutex_unlock(&rt2x00dev->csr_mutex); +} + +#ifdef CONFIG_RT2X00_LIB_DEBUGFS +static const struct rt2x00debug rt2800usb_rt2x00debug = { + .owner = THIS_MODULE, + .csr = { + .read = rt2x00usb_register_read, + .write = rt2x00usb_register_write, + .flags = RT2X00DEBUGFS_OFFSET, + .word_base = CSR_REG_BASE, + .word_size = sizeof(u32), + .word_count = CSR_REG_SIZE / sizeof(u32), + }, + .eeprom = { + .read = rt2x00_eeprom_read, + .write = rt2x00_eeprom_write, + .word_base = EEPROM_BASE, + .word_size = sizeof(u16), + .word_count = EEPROM_SIZE / sizeof(u16), + }, + .bbp = { + .read = rt2800usb_bbp_read, + .write = rt2800usb_bbp_write, + .word_base = BBP_BASE, + .word_size = sizeof(u8), + .word_count = BBP_SIZE / sizeof(u8), + }, + .rf = { + .read = rt2x00_rf_read, + .write = rt2800usb_rf_write, + .word_base = RF_BASE, + .word_size = sizeof(u32), + .word_count = RF_SIZE / sizeof(u32), + }, +}; +#endif /* CONFIG_RT2X00_LIB_DEBUGFS */ + +#ifdef CONFIG_RT2X00_LIB_RFKILL +static int rt2800usb_rfkill_poll(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + rt2x00usb_register_read(rt2x00dev, GPIO_CTRL_CFG, ®); + return rt2x00_get_field32(reg, GPIO_CTRL_CFG_BIT2); +} +#else +#define rt2800usb_rfkill_poll NULL +#endif /* CONFIG_RT2X00_LIB_RFKILL */ + +#ifdef CONFIG_RT2X00_LIB_LEDS +static void rt2800usb_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct rt2x00_led *led = + container_of(led_cdev, struct rt2x00_led, led_dev); + unsigned int enabled = brightness != LED_OFF; + unsigned int bg_mode = + (enabled && led->rt2x00dev->curr_band == IEEE80211_BAND_2GHZ); + unsigned int polarity = + rt2x00_get_field16(led->rt2x00dev->led_mcu_reg, + EEPROM_FREQ_LED_POLARITY); + unsigned int ledmode = + rt2x00_get_field16(led->rt2x00dev->led_mcu_reg, + EEPROM_FREQ_LED_MODE); + + if (led->type == LED_TYPE_RADIO) { + rt2800usb_mcu_request(led->rt2x00dev, MCU_LED, 0xff, ledmode, + enabled ? 0x20 : 0); + } else if (led->type == LED_TYPE_ASSOC) { + rt2800usb_mcu_request(led->rt2x00dev, MCU_LED, 0xff, ledmode, + enabled ? (bg_mode ? 0x60 : 0xa0) : 0x20); + } else if (led->type == LED_TYPE_QUALITY) { + /* + * The brightness is divided into 6 levels (0 - 5), + * The specs tell us the following levels: + * 0, 1 ,3, 7, 15, 31 + * to determine the level in a simple way we can simply + * work with bitshifting: + * (1 << level) - 1 + */ + rt2800usb_mcu_request(led->rt2x00dev, MCU_LED_STRENGTH, 0xff, + (1 << brightness / (LED_FULL / 6)) - 1, + polarity); + } +} + +static int rt2800usb_blink_set(struct led_classdev *led_cdev, + unsigned long *delay_on, + unsigned long *delay_off) +{ + struct rt2x00_led *led = + container_of(led_cdev, struct rt2x00_led, led_dev); + u32 reg; + + rt2x00usb_register_read(led->rt2x00dev, LED_CFG, ®); + rt2x00_set_field32(®, LED_CFG_ON_PERIOD, *delay_on); + rt2x00_set_field32(®, LED_CFG_OFF_PERIOD, *delay_off); + rt2x00_set_field32(®, LED_CFG_SLOW_BLINK_PERIOD, 3); + rt2x00_set_field32(®, LED_CFG_R_LED_MODE, 3); + rt2x00_set_field32(®, LED_CFG_G_LED_MODE, 12); + rt2x00_set_field32(®, LED_CFG_Y_LED_MODE, 3); + rt2x00_set_field32(®, LED_CFG_LED_POLAR, 1); + rt2x00usb_register_write(led->rt2x00dev, LED_CFG, reg); + + return 0; +} + +static void rt2800usb_init_led(struct rt2x00_dev *rt2x00dev, + struct rt2x00_led *led, + enum led_type type) +{ + led->rt2x00dev = rt2x00dev; + led->type = type; + led->led_dev.brightness_set = rt2800usb_brightness_set; + led->led_dev.blink_set = rt2800usb_blink_set; + led->flags = LED_INITIALIZED; +} +#endif /* CONFIG_RT2X00_LIB_LEDS */ + +/* + * Configuration handlers. + */ +static void rt2800usb_config_wcid_attr(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_crypto *crypto, + struct ieee80211_key_conf *key) +{ + struct mac_wcid_entry wcid_entry; + struct mac_iveiv_entry iveiv_entry; + u32 offset; + u32 reg; + + offset = MAC_WCID_ATTR_ENTRY(key->hw_key_idx); + + rt2x00usb_register_read(rt2x00dev, offset, ®); + rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_KEYTAB, + !!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)); + rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_CIPHER, + (crypto->cmd == SET_KEY) * crypto->cipher); + rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_BSS_IDX, + (crypto->cmd == SET_KEY) * crypto->bssidx); + rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_RX_WIUDF, crypto->cipher); + rt2x00usb_register_write(rt2x00dev, offset, reg); + + offset = MAC_IVEIV_ENTRY(key->hw_key_idx); + + memset(&iveiv_entry, 0, sizeof(iveiv_entry)); + if ((crypto->cipher == CIPHER_TKIP) || + (crypto->cipher == CIPHER_TKIP_NO_MIC) || + (crypto->cipher == CIPHER_AES)) + iveiv_entry.iv[3] |= 0x20; + iveiv_entry.iv[3] |= key->keyidx << 6; + rt2x00usb_register_multiwrite(rt2x00dev, offset, + &iveiv_entry, sizeof(iveiv_entry)); + + offset = MAC_WCID_ENTRY(key->hw_key_idx); + + memset(&wcid_entry, 0, sizeof(wcid_entry)); + if (crypto->cmd == SET_KEY) + memcpy(&wcid_entry, crypto->address, ETH_ALEN); + rt2x00usb_register_multiwrite(rt2x00dev, offset, + &wcid_entry, sizeof(wcid_entry)); +} + +static int rt2800usb_config_shared_key(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_crypto *crypto, + struct ieee80211_key_conf *key) +{ + struct hw_key_entry key_entry; + struct rt2x00_field32 field; + int timeout; + u32 offset; + u32 reg; + + if (crypto->cmd == SET_KEY) { + key->hw_key_idx = (4 * crypto->bssidx) + key->keyidx; + + memcpy(key_entry.key, crypto->key, + sizeof(key_entry.key)); + memcpy(key_entry.tx_mic, crypto->tx_mic, + sizeof(key_entry.tx_mic)); + memcpy(key_entry.rx_mic, crypto->rx_mic, + sizeof(key_entry.rx_mic)); + + offset = SHARED_KEY_ENTRY(key->hw_key_idx); + timeout = REGISTER_TIMEOUT32(sizeof(key_entry)); + rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE, + USB_VENDOR_REQUEST_OUT, + offset, &key_entry, + sizeof(key_entry), + timeout); + } + + /* + * The cipher types are stored over multiple registers + * starting with SHARED_KEY_MODE_BASE each word will have + * 32 bits and contains the cipher types for 2 bssidx each. + * Using the correct defines correctly will cause overhead, + * so just calculate the correct offset. + */ + field.bit_offset = 4 * (key->hw_key_idx % 8); + field.bit_mask = 0x7 << field.bit_offset; + + offset = SHARED_KEY_MODE_ENTRY(key->hw_key_idx / 8); + + rt2x00usb_register_read(rt2x00dev, offset, ®); + rt2x00_set_field32(®, field, + (crypto->cmd == SET_KEY) * crypto->cipher); + rt2x00usb_register_write(rt2x00dev, offset, reg); + + /* + * Update WCID information + */ + rt2800usb_config_wcid_attr(rt2x00dev, crypto, key); + + return 0; +} + +static int rt2800usb_config_pairwise_key(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_crypto *crypto, + struct ieee80211_key_conf *key) +{ + struct hw_key_entry key_entry; + int timeout; + u32 offset; + + if (crypto->cmd == SET_KEY) { + /* + * 1 pairwise key is possible per AID, this means that the AID + * equals our hw_key_idx. Make sure the WCID starts _after_ the + * last possible shared key entry. + */ + if (crypto->aid > (256 - 32)) + return -ENOSPC; + + key->hw_key_idx = 32 + crypto->aid; + + memcpy(key_entry.key, crypto->key, + sizeof(key_entry.key)); + memcpy(key_entry.tx_mic, crypto->tx_mic, + sizeof(key_entry.tx_mic)); + memcpy(key_entry.rx_mic, crypto->rx_mic, + sizeof(key_entry.rx_mic)); + + offset = PAIRWISE_KEY_ENTRY(key->hw_key_idx); + timeout = REGISTER_TIMEOUT32(sizeof(key_entry)); + rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE, + USB_VENDOR_REQUEST_OUT, + offset, &key_entry, + sizeof(key_entry), + timeout); + } + + /* + * Update WCID information + */ + rt2800usb_config_wcid_attr(rt2x00dev, crypto, key); + + return 0; +} + +static void rt2800usb_config_filter(struct rt2x00_dev *rt2x00dev, + const unsigned int filter_flags) +{ + u32 reg; + + /* + * Start configuration steps. + * Note that the version error will always be dropped + * and broadcast frames will always be accepted since + * there is no filter for it at this time. + */ + rt2x00usb_register_read(rt2x00dev, RX_FILTER_CFG, ®); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CRC_ERROR, + !(filter_flags & FIF_FCSFAIL)); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_PHY_ERROR, + !(filter_flags & FIF_PLCPFAIL)); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_NOT_TO_ME, + !(filter_flags & FIF_PROMISC_IN_BSS)); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_NOT_MY_BSSD, 0); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_VER_ERROR, 1); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_MULTICAST, + !(filter_flags & FIF_ALLMULTI)); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_BROADCAST, 0); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_DUPLICATE, 1); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CF_END_ACK, + !(filter_flags & FIF_CONTROL)); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CF_END, + !(filter_flags & FIF_CONTROL)); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_ACK, + !(filter_flags & FIF_CONTROL)); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CTS, + !(filter_flags & FIF_CONTROL)); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_RTS, + !(filter_flags & FIF_CONTROL)); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_PSPOLL, + !(filter_flags & FIF_CONTROL)); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_BA, 1); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_BAR, 0); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CNTL, + !(filter_flags & FIF_CONTROL)); + rt2x00usb_register_write(rt2x00dev, RX_FILTER_CFG, reg); +} + +static void rt2800usb_config_intf(struct rt2x00_dev *rt2x00dev, + struct rt2x00_intf *intf, + struct rt2x00intf_conf *conf, + const unsigned int flags) +{ + unsigned int beacon_base; + u32 reg; + + if (flags & CONFIG_UPDATE_TYPE) { + /* + * Clear current synchronisation setup. + * For the Beacon base registers we only need to clear + * the first byte since that byte contains the VALID and OWNER + * bits which (when set to 0) will invalidate the entire beacon. + */ + beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx); + rt2x00usb_register_write(rt2x00dev, beacon_base, 0); + + /* + * Enable synchronisation. + */ + rt2x00usb_register_read(rt2x00dev, BCN_TIME_CFG, ®); + rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 1); + rt2x00_set_field32(®, BCN_TIME_CFG_TSF_SYNC, conf->sync); + rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 1); + rt2x00usb_register_write(rt2x00dev, BCN_TIME_CFG, reg); + } + + if (flags & CONFIG_UPDATE_MAC) { + reg = le32_to_cpu(conf->mac[1]); + rt2x00_set_field32(®, MAC_ADDR_DW1_UNICAST_TO_ME_MASK, 0xff); + conf->mac[1] = cpu_to_le32(reg); + + rt2x00usb_register_multiwrite(rt2x00dev, MAC_ADDR_DW0, + conf->mac, sizeof(conf->mac)); + } + + if (flags & CONFIG_UPDATE_BSSID) { + reg = le32_to_cpu(conf->bssid[1]); + rt2x00_set_field32(®, MAC_BSSID_DW1_BSS_ID_MASK, 0); + rt2x00_set_field32(®, MAC_BSSID_DW1_BSS_BCN_NUM, 0); + conf->bssid[1] = cpu_to_le32(reg); + + rt2x00usb_register_multiwrite(rt2x00dev, MAC_BSSID_DW0, + conf->bssid, sizeof(conf->bssid)); + } +} + +static void rt2800usb_config_erp(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_erp *erp) +{ + u32 reg; + + rt2x00usb_register_read(rt2x00dev, TX_TIMEOUT_CFG, ®); + rt2x00_set_field32(®, TX_TIMEOUT_CFG_RX_ACK_TIMEOUT, + DIV_ROUND_UP(erp->ack_timeout, erp->slot_time)); + rt2x00usb_register_write(rt2x00dev, TX_TIMEOUT_CFG, reg); + + rt2x00usb_register_read(rt2x00dev, AUTO_RSP_CFG, ®); + rt2x00_set_field32(®, AUTO_RSP_CFG_BAC_ACK_POLICY, + !!erp->short_preamble); + rt2x00_set_field32(®, AUTO_RSP_CFG_AR_PREAMBLE, + !!erp->short_preamble); + rt2x00usb_register_write(rt2x00dev, AUTO_RSP_CFG, reg); + + rt2x00usb_register_read(rt2x00dev, OFDM_PROT_CFG, ®); + rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_CTRL, + erp->cts_protection ? 2 : 0); + rt2x00usb_register_write(rt2x00dev, OFDM_PROT_CFG, reg); + + rt2x00usb_register_write(rt2x00dev, LEGACY_BASIC_RATE, + erp->basic_rates); + rt2x00usb_register_write(rt2x00dev, HT_BASIC_RATE, 0x00008003); + + rt2x00usb_register_read(rt2x00dev, BKOFF_SLOT_CFG, ®); + rt2x00_set_field32(®, BKOFF_SLOT_CFG_SLOT_TIME, erp->slot_time); + rt2x00_set_field32(®, BKOFF_SLOT_CFG_CC_DELAY_TIME, 2); + rt2x00usb_register_write(rt2x00dev, BKOFF_SLOT_CFG, reg); + + rt2x00usb_register_read(rt2x00dev, XIFS_TIME_CFG, ®); + rt2x00_set_field32(®, XIFS_TIME_CFG_CCKM_SIFS_TIME, erp->sifs); + rt2x00_set_field32(®, XIFS_TIME_CFG_OFDM_SIFS_TIME, erp->sifs); + rt2x00_set_field32(®, XIFS_TIME_CFG_OFDM_XIFS_TIME, 4); + rt2x00_set_field32(®, XIFS_TIME_CFG_EIFS, erp->eifs); + rt2x00_set_field32(®, XIFS_TIME_CFG_BB_RXEND_ENABLE, 1); + rt2x00usb_register_write(rt2x00dev, XIFS_TIME_CFG, reg); + + rt2x00usb_register_read(rt2x00dev, BCN_TIME_CFG, ®); + rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_INTERVAL, + erp->beacon_int * 16); + rt2x00usb_register_write(rt2x00dev, BCN_TIME_CFG, reg); +} + +static void rt2800usb_config_ant(struct rt2x00_dev *rt2x00dev, + struct antenna_setup *ant) +{ + u8 r1; + u8 r3; + + rt2800usb_bbp_read(rt2x00dev, 1, &r1); + rt2800usb_bbp_read(rt2x00dev, 3, &r3); + + /* + * Configure the TX antenna. + */ + switch ((int)ant->tx) { + case 1: + rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 0); + break; + case 2: + rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 2); + break; + case 3: + /* Do nothing */ + break; + } + + /* + * Configure the RX antenna. + */ + switch ((int)ant->rx) { + case 1: + rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 0); + break; + case 2: + rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 1); + break; + case 3: + rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 2); + break; + } + + rt2800usb_bbp_write(rt2x00dev, 3, r3); + rt2800usb_bbp_write(rt2x00dev, 1, r1); +} + +static void rt2800usb_config_lna_gain(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_conf *libconf) +{ + u16 eeprom; + short lna_gain; + + if (libconf->rf.channel <= 14) { + rt2x00_eeprom_read(rt2x00dev, EEPROM_LNA, &eeprom); + lna_gain = rt2x00_get_field16(eeprom, EEPROM_LNA_BG); + } else if (libconf->rf.channel <= 64) { + rt2x00_eeprom_read(rt2x00dev, EEPROM_LNA, &eeprom); + lna_gain = rt2x00_get_field16(eeprom, EEPROM_LNA_A0); + } else if (libconf->rf.channel <= 128) { + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &eeprom); + lna_gain = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG2_LNA_A1); + } else { + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &eeprom); + lna_gain = rt2x00_get_field16(eeprom, EEPROM_RSSI_A2_LNA_A2); + } + + rt2x00dev->lna_gain = lna_gain; +} + +static void rt2800usb_config_channel_rt2x(struct rt2x00_dev *rt2x00dev, + struct ieee80211_conf *conf, + struct rf_channel *rf, + struct channel_info *info) +{ + rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset); + + if (rt2x00dev->default_ant.tx == 1) + rt2x00_set_field32(&rf->rf2, RF2_ANTENNA_TX1, 1); + + if (rt2x00dev->default_ant.rx == 1) { + rt2x00_set_field32(&rf->rf2, RF2_ANTENNA_RX1, 1); + rt2x00_set_field32(&rf->rf2, RF2_ANTENNA_RX2, 1); + } else if (rt2x00dev->default_ant.rx == 2) + rt2x00_set_field32(&rf->rf2, RF2_ANTENNA_RX2, 1); + + if (rf->channel > 14) { + /* + * When TX power is below 0, we should increase it by 7 to + * make it a positive value (Minumum value is -7). + * However this means that values between 0 and 7 have + * double meaning, and we should set a 7DBm boost flag. + */ + rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_A_7DBM_BOOST, + (info->tx_power1 >= 0)); + + if (info->tx_power1 < 0) + info->tx_power1 += 7; + + rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_A, + TXPOWER_A_TO_DEV(info->tx_power1)); + + rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_A_7DBM_BOOST, + (info->tx_power2 >= 0)); + + if (info->tx_power2 < 0) + info->tx_power2 += 7; + + rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_A, + TXPOWER_A_TO_DEV(info->tx_power2)); + } else { + rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_G, + TXPOWER_G_TO_DEV(info->tx_power1)); + rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_G, + TXPOWER_G_TO_DEV(info->tx_power2)); + } + + rt2x00_set_field32(&rf->rf4, RF4_HT40, conf_is_ht40(conf)); + + rt2800usb_rf_write(rt2x00dev, 1, rf->rf1); + rt2800usb_rf_write(rt2x00dev, 2, rf->rf2); + rt2800usb_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); + rt2800usb_rf_write(rt2x00dev, 4, rf->rf4); + + udelay(200); + + rt2800usb_rf_write(rt2x00dev, 1, rf->rf1); + rt2800usb_rf_write(rt2x00dev, 2, rf->rf2); + rt2800usb_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004); + rt2800usb_rf_write(rt2x00dev, 4, rf->rf4); + + udelay(200); + + rt2800usb_rf_write(rt2x00dev, 1, rf->rf1); + rt2800usb_rf_write(rt2x00dev, 2, rf->rf2); + rt2800usb_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); + rt2800usb_rf_write(rt2x00dev, 4, rf->rf4); +} + +static void rt2800usb_config_channel_rt3x(struct rt2x00_dev *rt2x00dev, + struct ieee80211_conf *conf, + struct rf_channel *rf, + struct channel_info *info) +{ + u8 rfcsr; + + rt2800usb_rfcsr_write(rt2x00dev, 2, rf->rf1); + rt2800usb_rfcsr_write(rt2x00dev, 2, rf->rf3); + + rt2800usb_rfcsr_read(rt2x00dev, 6, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR6_R, rf->rf2); + rt2800usb_rfcsr_write(rt2x00dev, 6, rfcsr); + + rt2800usb_rfcsr_read(rt2x00dev, 12, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR12_TX_POWER, + TXPOWER_G_TO_DEV(info->tx_power1)); + rt2800usb_rfcsr_write(rt2x00dev, 12, rfcsr); + + rt2800usb_rfcsr_read(rt2x00dev, 23, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR23_FREQ_OFFSET, rt2x00dev->freq_offset); + rt2800usb_rfcsr_write(rt2x00dev, 23, rfcsr); + + rt2800usb_rfcsr_write(rt2x00dev, 24, + rt2x00dev->calibration[conf_is_ht40(conf)]); + + rt2800usb_rfcsr_read(rt2x00dev, 23, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR7_RF_TUNING, 1); + rt2800usb_rfcsr_write(rt2x00dev, 23, rfcsr); +} + +static void rt2800usb_config_channel(struct rt2x00_dev *rt2x00dev, + struct ieee80211_conf *conf, + struct rf_channel *rf, + struct channel_info *info) +{ + u32 reg; + unsigned int tx_pin; + u8 bbp; + + if (rt2x00_rev(&rt2x00dev->chip) != RT3070_VERSION) + rt2800usb_config_channel_rt2x(rt2x00dev, conf, rf, info); + else + rt2800usb_config_channel_rt3x(rt2x00dev, conf, rf, info); + + /* + * Change BBP settings + */ + rt2800usb_bbp_write(rt2x00dev, 62, 0x37 - rt2x00dev->lna_gain); + rt2800usb_bbp_write(rt2x00dev, 63, 0x37 - rt2x00dev->lna_gain); + rt2800usb_bbp_write(rt2x00dev, 64, 0x37 - rt2x00dev->lna_gain); + rt2800usb_bbp_write(rt2x00dev, 86, 0); + + if (rf->channel <= 14) { + if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) { + rt2800usb_bbp_write(rt2x00dev, 82, 0x62); + rt2800usb_bbp_write(rt2x00dev, 75, 0x46); + } else { + rt2800usb_bbp_write(rt2x00dev, 82, 0x84); + rt2800usb_bbp_write(rt2x00dev, 75, 0x50); + } + } else { + rt2800usb_bbp_write(rt2x00dev, 82, 0xf2); + + if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) + rt2800usb_bbp_write(rt2x00dev, 75, 0x46); + else + rt2800usb_bbp_write(rt2x00dev, 75, 0x50); + } + + rt2x00usb_register_read(rt2x00dev, TX_BAND_CFG, ®); + rt2x00_set_field32(®, TX_BAND_CFG_HT40_PLUS, conf_is_ht40_plus(conf)); + rt2x00_set_field32(®, TX_BAND_CFG_A, rf->channel > 14); + rt2x00_set_field32(®, TX_BAND_CFG_BG, rf->channel <= 14); + rt2x00usb_register_write(rt2x00dev, TX_BAND_CFG, reg); + + tx_pin = 0; + + /* Turn on unused PA or LNA when not using 1T or 1R */ + if (rt2x00dev->default_ant.tx != 1) { + rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_A1_EN, 1); + rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G1_EN, 1); + } + + /* Turn on unused PA or LNA when not using 1T or 1R */ + if (rt2x00dev->default_ant.rx != 1) { + rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A1_EN, 1); + rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G1_EN, 1); + } + + rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A0_EN, 1); + rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G0_EN, 1); + rt2x00_set_field32(&tx_pin, TX_PIN_CFG_RFTR_EN, 1); + rt2x00_set_field32(&tx_pin, TX_PIN_CFG_TRSW_EN, 1); + rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G0_EN, rf->channel <= 14); + rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_A0_EN, rf->channel > 14); + + rt2x00usb_register_write(rt2x00dev, TX_PIN_CFG, tx_pin); + + rt2800usb_bbp_read(rt2x00dev, 4, &bbp); + rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 2 * conf_is_ht40(conf)); + rt2800usb_bbp_write(rt2x00dev, 4, bbp); + + rt2800usb_bbp_read(rt2x00dev, 3, &bbp); + rt2x00_set_field8(&bbp, BBP3_HT40_PLUS, conf_is_ht40_plus(conf)); + rt2800usb_bbp_write(rt2x00dev, 3, bbp); + + if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION) { + if (conf_is_ht40(conf)) { + rt2800usb_bbp_write(rt2x00dev, 69, 0x1a); + rt2800usb_bbp_write(rt2x00dev, 70, 0x0a); + rt2800usb_bbp_write(rt2x00dev, 73, 0x16); + } else { + rt2800usb_bbp_write(rt2x00dev, 69, 0x16); + rt2800usb_bbp_write(rt2x00dev, 70, 0x08); + rt2800usb_bbp_write(rt2x00dev, 73, 0x11); + } + } + + msleep(1); +} + +static void rt2800usb_config_txpower(struct rt2x00_dev *rt2x00dev, + const int txpower) +{ + u32 reg; + u32 value = TXPOWER_G_TO_DEV(txpower); + u8 r1; + + rt2800usb_bbp_read(rt2x00dev, 1, &r1); + rt2x00_set_field8(®, BBP1_TX_POWER, 0); + rt2800usb_bbp_write(rt2x00dev, 1, r1); + + rt2x00usb_register_read(rt2x00dev, TX_PWR_CFG_0, ®); + rt2x00_set_field32(®, TX_PWR_CFG_0_1MBS, value); + rt2x00_set_field32(®, TX_PWR_CFG_0_2MBS, value); + rt2x00_set_field32(®, TX_PWR_CFG_0_55MBS, value); + rt2x00_set_field32(®, TX_PWR_CFG_0_11MBS, value); + rt2x00_set_field32(®, TX_PWR_CFG_0_6MBS, value); + rt2x00_set_field32(®, TX_PWR_CFG_0_9MBS, value); + rt2x00_set_field32(®, TX_PWR_CFG_0_12MBS, value); + rt2x00_set_field32(®, TX_PWR_CFG_0_18MBS, value); + rt2x00usb_register_write(rt2x00dev, TX_PWR_CFG_0, reg); + + rt2x00usb_register_read(rt2x00dev, TX_PWR_CFG_1, ®); + rt2x00_set_field32(®, TX_PWR_CFG_1_24MBS, value); + rt2x00_set_field32(®, TX_PWR_CFG_1_36MBS, value); + rt2x00_set_field32(®, TX_PWR_CFG_1_48MBS, value); + rt2x00_set_field32(®, TX_PWR_CFG_1_54MBS, value); + rt2x00_set_field32(®, TX_PWR_CFG_1_MCS0, value); + rt2x00_set_field32(®, TX_PWR_CFG_1_MCS1, value); + rt2x00_set_field32(®, TX_PWR_CFG_1_MCS2, value); + rt2x00_set_field32(®, TX_PWR_CFG_1_MCS3, value); + rt2x00usb_register_write(rt2x00dev, TX_PWR_CFG_1, reg); + + rt2x00usb_register_read(rt2x00dev, TX_PWR_CFG_2, ®); + rt2x00_set_field32(®, TX_PWR_CFG_2_MCS4, value); + rt2x00_set_field32(®, TX_PWR_CFG_2_MCS5, value); + rt2x00_set_field32(®, TX_PWR_CFG_2_MCS6, value); + rt2x00_set_field32(®, TX_PWR_CFG_2_MCS7, value); + rt2x00_set_field32(®, TX_PWR_CFG_2_MCS8, value); + rt2x00_set_field32(®, TX_PWR_CFG_2_MCS9, value); + rt2x00_set_field32(®, TX_PWR_CFG_2_MCS10, value); + rt2x00_set_field32(®, TX_PWR_CFG_2_MCS11, value); + rt2x00usb_register_write(rt2x00dev, TX_PWR_CFG_2, reg); + + rt2x00usb_register_read(rt2x00dev, TX_PWR_CFG_3, ®); + rt2x00_set_field32(®, TX_PWR_CFG_3_MCS12, value); + rt2x00_set_field32(®, TX_PWR_CFG_3_MCS13, value); + rt2x00_set_field32(®, TX_PWR_CFG_3_MCS14, value); + rt2x00_set_field32(®, TX_PWR_CFG_3_MCS15, value); + rt2x00_set_field32(®, TX_PWR_CFG_3_UKNOWN1, value); + rt2x00_set_field32(®, TX_PWR_CFG_3_UKNOWN2, value); + rt2x00_set_field32(®, TX_PWR_CFG_3_UKNOWN3, value); + rt2x00_set_field32(®, TX_PWR_CFG_3_UKNOWN4, value); + rt2x00usb_register_write(rt2x00dev, TX_PWR_CFG_3, reg); + + rt2x00usb_register_read(rt2x00dev, TX_PWR_CFG_4, ®); + rt2x00_set_field32(®, TX_PWR_CFG_4_UKNOWN5, value); + rt2x00_set_field32(®, TX_PWR_CFG_4_UKNOWN6, value); + rt2x00_set_field32(®, TX_PWR_CFG_4_UKNOWN7, value); + rt2x00_set_field32(®, TX_PWR_CFG_4_UKNOWN8, value); + rt2x00usb_register_write(rt2x00dev, TX_PWR_CFG_4, reg); +} + +static void rt2800usb_config_retry_limit(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_conf *libconf) +{ + u32 reg; + + rt2x00usb_register_read(rt2x00dev, TX_RTY_CFG, ®); + rt2x00_set_field32(®, TX_RTY_CFG_SHORT_RTY_LIMIT, + libconf->conf->short_frame_max_tx_count); + rt2x00_set_field32(®, TX_RTY_CFG_LONG_RTY_LIMIT, + libconf->conf->long_frame_max_tx_count); + rt2x00_set_field32(®, TX_RTY_CFG_LONG_RTY_THRE, 2000); + rt2x00_set_field32(®, TX_RTY_CFG_NON_AGG_RTY_MODE, 0); + rt2x00_set_field32(®, TX_RTY_CFG_AGG_RTY_MODE, 0); + rt2x00_set_field32(®, TX_RTY_CFG_TX_AUTO_FB_ENABLE, 1); + rt2x00usb_register_write(rt2x00dev, TX_RTY_CFG, reg); +} + +static void rt2800usb_config_ps(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_conf *libconf) +{ + enum dev_state state = + (libconf->conf->flags & IEEE80211_CONF_PS) ? + STATE_SLEEP : STATE_AWAKE; + u32 reg; + + if (state == STATE_SLEEP) { + rt2x00usb_register_write(rt2x00dev, AUTOWAKEUP_CFG, 0); + + rt2x00usb_register_read(rt2x00dev, AUTOWAKEUP_CFG, ®); + rt2x00_set_field32(®, AUTOWAKEUP_CFG_AUTO_LEAD_TIME, 5); + rt2x00_set_field32(®, AUTOWAKEUP_CFG_TBCN_BEFORE_WAKE, + libconf->conf->listen_interval - 1); + rt2x00_set_field32(®, AUTOWAKEUP_CFG_AUTOWAKE, 1); + rt2x00usb_register_write(rt2x00dev, AUTOWAKEUP_CFG, reg); + + rt2x00dev->ops->lib->set_device_state(rt2x00dev, state); + } else { + rt2x00dev->ops->lib->set_device_state(rt2x00dev, state); + + rt2x00usb_register_read(rt2x00dev, AUTOWAKEUP_CFG, ®); + rt2x00_set_field32(®, AUTOWAKEUP_CFG_AUTO_LEAD_TIME, 0); + rt2x00_set_field32(®, AUTOWAKEUP_CFG_TBCN_BEFORE_WAKE, 0); + rt2x00_set_field32(®, AUTOWAKEUP_CFG_AUTOWAKE, 0); + rt2x00usb_register_write(rt2x00dev, AUTOWAKEUP_CFG, reg); + } +} + +static void rt2800usb_config(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_conf *libconf, + const unsigned int flags) +{ + /* Always recalculate LNA gain before changing configuration */ + rt2800usb_config_lna_gain(rt2x00dev, libconf); + + if (flags & IEEE80211_CONF_CHANGE_CHANNEL) + rt2800usb_config_channel(rt2x00dev, libconf->conf, + &libconf->rf, &libconf->channel); + if (flags & IEEE80211_CONF_CHANGE_POWER) + rt2800usb_config_txpower(rt2x00dev, libconf->conf->power_level); + if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS) + rt2800usb_config_retry_limit(rt2x00dev, libconf); + if (flags & IEEE80211_CONF_CHANGE_PS) + rt2800usb_config_ps(rt2x00dev, libconf); +} + +/* + * Link tuning + */ +static void rt2800usb_link_stats(struct rt2x00_dev *rt2x00dev, + struct link_qual *qual) +{ + u32 reg; + + /* + * Update FCS error count from register. + */ + rt2x00usb_register_read(rt2x00dev, RX_STA_CNT0, ®); + qual->rx_failed = rt2x00_get_field32(reg, RX_STA_CNT0_CRC_ERR); +} + +static u8 rt2800usb_get_default_vgc(struct rt2x00_dev *rt2x00dev) +{ + if (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ) { + if (rt2x00_rev(&rt2x00dev->chip) == RT3070_VERSION) + return 0x1c + (2 * rt2x00dev->lna_gain); + else + return 0x2e + rt2x00dev->lna_gain; + } + + if (!test_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags)) + return 0x32 + (rt2x00dev->lna_gain * 5) / 3; + else + return 0x3a + (rt2x00dev->lna_gain * 5) / 3; +} + +static inline void rt2800usb_set_vgc(struct rt2x00_dev *rt2x00dev, + struct link_qual *qual, u8 vgc_level) +{ + if (qual->vgc_level != vgc_level) { + rt2800usb_bbp_write(rt2x00dev, 66, vgc_level); + qual->vgc_level = vgc_level; + qual->vgc_level_reg = vgc_level; + } +} + +static void rt2800usb_reset_tuner(struct rt2x00_dev *rt2x00dev, + struct link_qual *qual) +{ + rt2800usb_set_vgc(rt2x00dev, qual, + rt2800usb_get_default_vgc(rt2x00dev)); +} + +static void rt2800usb_link_tuner(struct rt2x00_dev *rt2x00dev, + struct link_qual *qual, const u32 count) +{ + if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION) + return; + + /* + * When RSSI is better then -80 increase VGC level with 0x10 + */ + rt2800usb_set_vgc(rt2x00dev, qual, + rt2800usb_get_default_vgc(rt2x00dev) + + ((qual->rssi > -80) * 0x10)); +} + +/* + * Firmware functions + */ +static char *rt2800usb_get_firmware_name(struct rt2x00_dev *rt2x00dev) +{ + return FIRMWARE_RT2870; +} + +static bool rt2800usb_check_crc(const u8 *data, const size_t len) +{ + u16 fw_crc; + u16 crc; + + /* + * The last 2 bytes in the firmware array are the crc checksum itself, + * this means that we should never pass those 2 bytes to the crc + * algorithm. + */ + fw_crc = (data[len - 2] << 8 | data[len - 1]); + + /* + * Use the crc ccitt algorithm. + * This will return the same value as the legacy driver which + * used bit ordering reversion on the both the firmware bytes + * before input input as well as on the final output. + * Obviously using crc ccitt directly is much more efficient. + */ + crc = crc_ccitt(~0, data, len - 2); + + /* + * There is a small difference between the crc-itu-t + bitrev and + * the crc-ccitt crc calculation. In the latter method the 2 bytes + * will be swapped, use swab16 to convert the crc to the correct + * value. + */ + crc = swab16(crc); + + return fw_crc == crc; +} + +static int rt2800usb_check_firmware(struct rt2x00_dev *rt2x00dev, + const u8 *data, const size_t len) +{ + u16 chipset = (rt2x00_rev(&rt2x00dev->chip) >> 16) & 0xffff; + size_t offset = 0; + + /* + * Firmware files: + * There are 2 variations of the rt2870 firmware. + * a) size: 4kb + * b) size: 8kb + * Note that (b) contains 2 seperate firmware blobs of 4k + * within the file. The first blob is the same firmware as (a), + * but the second blob is for the additional chipsets. + */ + if (len != 4096 && len != 8192) + return FW_BAD_LENGTH; + + /* + * Check if we need the upper 4kb firmware data or not. + */ + if ((len == 4096) && + (chipset != 0x2860) && + (chipset != 0x2872) && + (chipset != 0x3070)) + return FW_BAD_VERSION; + + /* + * 8kb firmware files must be checked as if it were + * 2 seperate firmware files. + */ + while (offset < len) { + if (!rt2800usb_check_crc(data + offset, 4096)) + return FW_BAD_CRC; + + offset += 4096; + } + + return FW_OK; +} + +static int rt2800usb_load_firmware(struct rt2x00_dev *rt2x00dev, + const u8 *data, const size_t len) +{ + unsigned int i; + int status; + u32 reg; + u32 offset; + u32 length; + u16 chipset = (rt2x00_rev(&rt2x00dev->chip) >> 16) & 0xffff; + + /* + * Check which section of the firmware we need. + */ + if ((chipset == 0x2860) || + (chipset == 0x2872) || + (chipset == 0x3070)) { + offset = 0; + length = 4096; + } else { + offset = 4096; + length = 4096; + } + + /* + * Wait for stable hardware. + */ + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2x00usb_register_read(rt2x00dev, MAC_CSR0, ®); + if (reg && reg != ~0) + break; + msleep(1); + } + + if (i == REGISTER_BUSY_COUNT) { + ERROR(rt2x00dev, "Unstable hardware.\n"); + return -EBUSY; + } + + /* + * Write firmware to device. + */ + rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE, + USB_VENDOR_REQUEST_OUT, + FIRMWARE_IMAGE_BASE, + data + offset, length, + REGISTER_TIMEOUT32(length)); + + rt2x00usb_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0); + rt2x00usb_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0); + + /* + * Send firmware request to device to load firmware, + * we need to specify a long timeout time. + */ + status = rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE, + 0, USB_MODE_FIRMWARE, + REGISTER_TIMEOUT_FIRMWARE); + if (status < 0) { + ERROR(rt2x00dev, "Failed to write Firmware to device.\n"); + return status; + } + + msleep(10); + rt2x00usb_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0); + + /* + * Send signal to firmware during boot time. + */ + rt2800usb_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0xff, 0, 0); + + if ((chipset == 0x3070) || + (chipset == 0x3071) || + (chipset == 0x3572)) { + udelay(200); + rt2800usb_mcu_request(rt2x00dev, MCU_CURRENT, 0, 0, 0); + udelay(10); + } + + /* + * Wait for device to stabilize. + */ + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2x00usb_register_read(rt2x00dev, PBF_SYS_CTRL, ®); + if (rt2x00_get_field32(reg, PBF_SYS_CTRL_READY)) + break; + msleep(1); + } + + if (i == REGISTER_BUSY_COUNT) { + ERROR(rt2x00dev, "PBF system register not ready.\n"); + return -EBUSY; + } + + /* + * Initialize firmware. + */ + rt2x00usb_register_write(rt2x00dev, H2M_BBP_AGENT, 0); + rt2x00usb_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0); + msleep(1); + + return 0; +} + +/* + * Initialization functions. + */ +static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + unsigned int i; + + /* + * Wait untill BBP and RF are ready. + */ + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2x00usb_register_read(rt2x00dev, MAC_CSR0, ®); + if (reg && reg != ~0) + break; + msleep(1); + } + + if (i == REGISTER_BUSY_COUNT) { + ERROR(rt2x00dev, "Unstable hardware.\n"); + return -EBUSY; + } + + rt2x00usb_register_read(rt2x00dev, PBF_SYS_CTRL, ®); + rt2x00usb_register_write(rt2x00dev, PBF_SYS_CTRL, reg & ~0x00002000); + + rt2x00usb_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + rt2x00_set_field32(®, MAC_SYS_CTRL_RESET_CSR, 1); + rt2x00_set_field32(®, MAC_SYS_CTRL_RESET_BBP, 1); + rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, reg); + + rt2x00usb_register_write(rt2x00dev, USB_DMA_CFG, 0x00000000); + + rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE, 0, + USB_MODE_RESET, REGISTER_TIMEOUT); + + rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000); + + rt2x00usb_register_read(rt2x00dev, BCN_OFFSET0, ®); + rt2x00_set_field32(®, BCN_OFFSET0_BCN0, 0xe0); /* 0x3800 */ + rt2x00_set_field32(®, BCN_OFFSET0_BCN1, 0xe8); /* 0x3a00 */ + rt2x00_set_field32(®, BCN_OFFSET0_BCN2, 0xf0); /* 0x3c00 */ + rt2x00_set_field32(®, BCN_OFFSET0_BCN3, 0xf8); /* 0x3e00 */ + rt2x00usb_register_write(rt2x00dev, BCN_OFFSET0, reg); + + rt2x00usb_register_read(rt2x00dev, BCN_OFFSET1, ®); + rt2x00_set_field32(®, BCN_OFFSET1_BCN4, 0xc8); /* 0x3200 */ + rt2x00_set_field32(®, BCN_OFFSET1_BCN5, 0xd0); /* 0x3400 */ + rt2x00_set_field32(®, BCN_OFFSET1_BCN6, 0x77); /* 0x1dc0 */ + rt2x00_set_field32(®, BCN_OFFSET1_BCN7, 0x6f); /* 0x1bc0 */ + rt2x00usb_register_write(rt2x00dev, BCN_OFFSET1, reg); + + rt2x00usb_register_write(rt2x00dev, LEGACY_BASIC_RATE, 0x0000013f); + rt2x00usb_register_write(rt2x00dev, HT_BASIC_RATE, 0x00008003); + + rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000); + + rt2x00usb_register_read(rt2x00dev, BCN_TIME_CFG, ®); + rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_INTERVAL, 0); + rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 0); + rt2x00_set_field32(®, BCN_TIME_CFG_TSF_SYNC, 0); + rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 0); + rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 0); + rt2x00_set_field32(®, BCN_TIME_CFG_TX_TIME_COMPENSATE, 0); + rt2x00usb_register_write(rt2x00dev, BCN_TIME_CFG, reg); + + if (rt2x00_rev(&rt2x00dev->chip) == RT3070_VERSION) { + rt2x00usb_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400); + rt2x00usb_register_write(rt2x00dev, TX_SW_CFG1, 0x00000000); + rt2x00usb_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000); + } else { + rt2x00usb_register_write(rt2x00dev, TX_SW_CFG0, 0x00000000); + rt2x00usb_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606); + } + + rt2x00usb_register_read(rt2x00dev, TX_LINK_CFG, ®); + rt2x00_set_field32(®, TX_LINK_CFG_REMOTE_MFB_LIFETIME, 32); + rt2x00_set_field32(®, TX_LINK_CFG_MFB_ENABLE, 0); + rt2x00_set_field32(®, TX_LINK_CFG_REMOTE_UMFS_ENABLE, 0); + rt2x00_set_field32(®, TX_LINK_CFG_TX_MRQ_EN, 0); + rt2x00_set_field32(®, TX_LINK_CFG_TX_RDG_EN, 0); + rt2x00_set_field32(®, TX_LINK_CFG_TX_CF_ACK_EN, 1); + rt2x00_set_field32(®, TX_LINK_CFG_REMOTE_MFB, 0); + rt2x00_set_field32(®, TX_LINK_CFG_REMOTE_MFS, 0); + rt2x00usb_register_write(rt2x00dev, TX_LINK_CFG, reg); + + rt2x00usb_register_read(rt2x00dev, TX_TIMEOUT_CFG, ®); + rt2x00_set_field32(®, TX_TIMEOUT_CFG_MPDU_LIFETIME, 9); + rt2x00_set_field32(®, TX_TIMEOUT_CFG_TX_OP_TIMEOUT, 10); + rt2x00usb_register_write(rt2x00dev, TX_TIMEOUT_CFG, reg); + + rt2x00usb_register_read(rt2x00dev, MAX_LEN_CFG, ®); + rt2x00_set_field32(®, MAX_LEN_CFG_MAX_MPDU, AGGREGATION_SIZE); + if (rt2x00_rev(&rt2x00dev->chip) >= RT2880E_VERSION && + rt2x00_rev(&rt2x00dev->chip) < RT3070_VERSION) + rt2x00_set_field32(®, MAX_LEN_CFG_MAX_PSDU, 2); + else + rt2x00_set_field32(®, MAX_LEN_CFG_MAX_PSDU, 1); + rt2x00_set_field32(®, MAX_LEN_CFG_MIN_PSDU, 0); + rt2x00_set_field32(®, MAX_LEN_CFG_MIN_MPDU, 0); + rt2x00usb_register_write(rt2x00dev, MAX_LEN_CFG, reg); + + rt2x00usb_register_write(rt2x00dev, PBF_MAX_PCNT, 0x1f3fbf9f); + + rt2x00usb_register_read(rt2x00dev, AUTO_RSP_CFG, ®); + rt2x00_set_field32(®, AUTO_RSP_CFG_AUTORESPONDER, 1); + rt2x00_set_field32(®, AUTO_RSP_CFG_CTS_40_MMODE, 0); + rt2x00_set_field32(®, AUTO_RSP_CFG_CTS_40_MREF, 0); + rt2x00_set_field32(®, AUTO_RSP_CFG_DUAL_CTS_EN, 0); + rt2x00_set_field32(®, AUTO_RSP_CFG_ACK_CTS_PSM_BIT, 0); + rt2x00usb_register_write(rt2x00dev, AUTO_RSP_CFG, reg); + + rt2x00usb_register_read(rt2x00dev, CCK_PROT_CFG, ®); + rt2x00_set_field32(®, CCK_PROT_CFG_PROTECT_RATE, 8); + rt2x00_set_field32(®, CCK_PROT_CFG_PROTECT_CTRL, 0); + rt2x00_set_field32(®, CCK_PROT_CFG_PROTECT_NAV, 1); + rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_CCK, 1); + rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_OFDM, 1); + rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_MM20, 1); + rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_MM40, 1); + rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_GF20, 1); + rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_GF40, 1); + rt2x00usb_register_write(rt2x00dev, CCK_PROT_CFG, reg); + + rt2x00usb_register_read(rt2x00dev, OFDM_PROT_CFG, ®); + rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_RATE, 8); + rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_CTRL, 0); + rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_NAV, 1); + rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_CCK, 1); + rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_OFDM, 1); + rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_MM20, 1); + rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_MM40, 1); + rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_GF20, 1); + rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_GF40, 1); + rt2x00usb_register_write(rt2x00dev, OFDM_PROT_CFG, reg); + + rt2x00usb_register_read(rt2x00dev, MM20_PROT_CFG, ®); + rt2x00_set_field32(®, MM20_PROT_CFG_PROTECT_RATE, 0x4004); + rt2x00_set_field32(®, MM20_PROT_CFG_PROTECT_CTRL, 0); + rt2x00_set_field32(®, MM20_PROT_CFG_PROTECT_NAV, 1); + rt2x00_set_field32(®, MM20_PROT_CFG_TX_OP_ALLOW_CCK, 1); + rt2x00_set_field32(®, MM20_PROT_CFG_TX_OP_ALLOW_OFDM, 1); + rt2x00_set_field32(®, MM20_PROT_CFG_TX_OP_ALLOW_MM20, 1); + rt2x00_set_field32(®, MM20_PROT_CFG_TX_OP_ALLOW_MM40, 0); + rt2x00_set_field32(®, MM20_PROT_CFG_TX_OP_ALLOW_GF20, 1); + rt2x00_set_field32(®, MM20_PROT_CFG_TX_OP_ALLOW_GF40, 0); + rt2x00usb_register_write(rt2x00dev, MM20_PROT_CFG, reg); + + rt2x00usb_register_read(rt2x00dev, MM40_PROT_CFG, ®); + rt2x00_set_field32(®, MM40_PROT_CFG_PROTECT_RATE, 0x4084); + rt2x00_set_field32(®, MM40_PROT_CFG_PROTECT_CTRL, 0); + rt2x00_set_field32(®, MM40_PROT_CFG_PROTECT_NAV, 1); + rt2x00_set_field32(®, MM40_PROT_CFG_TX_OP_ALLOW_CCK, 1); + rt2x00_set_field32(®, MM40_PROT_CFG_TX_OP_ALLOW_OFDM, 1); + rt2x00_set_field32(®, MM40_PROT_CFG_TX_OP_ALLOW_MM20, 1); + rt2x00_set_field32(®, MM40_PROT_CFG_TX_OP_ALLOW_MM40, 1); + rt2x00_set_field32(®, MM40_PROT_CFG_TX_OP_ALLOW_GF20, 1); + rt2x00_set_field32(®, MM40_PROT_CFG_TX_OP_ALLOW_GF40, 1); + rt2x00usb_register_write(rt2x00dev, MM40_PROT_CFG, reg); + + rt2x00usb_register_read(rt2x00dev, GF20_PROT_CFG, ®); + rt2x00_set_field32(®, GF20_PROT_CFG_PROTECT_RATE, 0x4004); + rt2x00_set_field32(®, GF20_PROT_CFG_PROTECT_CTRL, 0); + rt2x00_set_field32(®, GF20_PROT_CFG_PROTECT_NAV, 1); + rt2x00_set_field32(®, GF20_PROT_CFG_TX_OP_ALLOW_CCK, 1); + rt2x00_set_field32(®, GF20_PROT_CFG_TX_OP_ALLOW_OFDM, 1); + rt2x00_set_field32(®, GF20_PROT_CFG_TX_OP_ALLOW_MM20, 1); + rt2x00_set_field32(®, GF20_PROT_CFG_TX_OP_ALLOW_MM40, 0); + rt2x00_set_field32(®, GF20_PROT_CFG_TX_OP_ALLOW_GF20, 1); + rt2x00_set_field32(®, GF20_PROT_CFG_TX_OP_ALLOW_GF40, 0); + rt2x00usb_register_write(rt2x00dev, GF20_PROT_CFG, reg); + + rt2x00usb_register_read(rt2x00dev, GF40_PROT_CFG, ®); + rt2x00_set_field32(®, GF40_PROT_CFG_PROTECT_RATE, 0x4084); + rt2x00_set_field32(®, GF40_PROT_CFG_PROTECT_CTRL, 0); + rt2x00_set_field32(®, GF40_PROT_CFG_PROTECT_NAV, 1); + rt2x00_set_field32(®, GF40_PROT_CFG_TX_OP_ALLOW_CCK, 1); + rt2x00_set_field32(®, GF40_PROT_CFG_TX_OP_ALLOW_OFDM, 1); + rt2x00_set_field32(®, GF40_PROT_CFG_TX_OP_ALLOW_MM20, 1); + rt2x00_set_field32(®, GF40_PROT_CFG_TX_OP_ALLOW_MM40, 1); + rt2x00_set_field32(®, GF40_PROT_CFG_TX_OP_ALLOW_GF20, 1); + rt2x00_set_field32(®, GF40_PROT_CFG_TX_OP_ALLOW_GF40, 1); + rt2x00usb_register_write(rt2x00dev, GF40_PROT_CFG, reg); + + rt2x00usb_register_write(rt2x00dev, PBF_CFG, 0xf40006); + + rt2x00usb_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); + rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_DMA_BUSY, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_RX_DMA_BUSY, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_WP_DMA_BURST_SIZE, 3); + rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_BIG_ENDIAN, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_RX_HDR_SCATTER, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_HDR_SEG_LEN, 0); + rt2x00usb_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); + + rt2x00usb_register_write(rt2x00dev, TXOP_CTRL_CFG, 0x0000583f); + rt2x00usb_register_write(rt2x00dev, TXOP_HLDR_ET, 0x00000002); + + rt2x00usb_register_read(rt2x00dev, TX_RTS_CFG, ®); + rt2x00_set_field32(®, TX_RTS_CFG_AUTO_RTS_RETRY_LIMIT, 32); + rt2x00_set_field32(®, TX_RTS_CFG_RTS_THRES, + IEEE80211_MAX_RTS_THRESHOLD); + rt2x00_set_field32(®, TX_RTS_CFG_RTS_FBK_EN, 0); + rt2x00usb_register_write(rt2x00dev, TX_RTS_CFG, reg); + + rt2x00usb_register_write(rt2x00dev, EXP_ACK_TIME, 0x002400ca); + rt2x00usb_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003); + + /* + * ASIC will keep garbage value after boot, clear encryption keys. + */ + for (i = 0; i < 256; i++) { + u32 wcid[2] = { 0xffffffff, 0x00ffffff }; + rt2x00usb_register_multiwrite(rt2x00dev, MAC_WCID_ENTRY(i), + wcid, sizeof(wcid)); + + rt2x00usb_register_write(rt2x00dev, MAC_WCID_ATTR_ENTRY(i), 1); + rt2x00usb_register_write(rt2x00dev, MAC_IVEIV_ENTRY(i), 0); + } + + for (i = 0; i < 16; i++) + rt2x00usb_register_write(rt2x00dev, + SHARED_KEY_MODE_ENTRY(i), 0); + + /* + * Clear all beacons + * For the Beacon base registers we only need to clear + * the first byte since that byte contains the VALID and OWNER + * bits which (when set to 0) will invalidate the entire beacon. + */ + rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE0, 0); + rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE1, 0); + rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE2, 0); + rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE3, 0); + rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE4, 0); + rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE5, 0); + rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE6, 0); + rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE7, 0); + + rt2x00usb_register_read(rt2x00dev, USB_CYC_CFG, ®); + rt2x00_set_field32(®, USB_CYC_CFG_CLOCK_CYCLE, 30); + rt2x00usb_register_write(rt2x00dev, USB_CYC_CFG, reg); + + rt2x00usb_register_read(rt2x00dev, HT_FBK_CFG0, ®); + rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS0FBK, 0); + rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS1FBK, 0); + rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS2FBK, 1); + rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS3FBK, 2); + rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS4FBK, 3); + rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS5FBK, 4); + rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS6FBK, 5); + rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS7FBK, 6); + rt2x00usb_register_write(rt2x00dev, HT_FBK_CFG0, reg); + + rt2x00usb_register_read(rt2x00dev, HT_FBK_CFG1, ®); + rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS8FBK, 8); + rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS9FBK, 8); + rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS10FBK, 9); + rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS11FBK, 10); + rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS12FBK, 11); + rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS13FBK, 12); + rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS14FBK, 13); + rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS15FBK, 14); + rt2x00usb_register_write(rt2x00dev, HT_FBK_CFG1, reg); + + rt2x00usb_register_read(rt2x00dev, LG_FBK_CFG0, ®); + rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS0FBK, 8); + rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS1FBK, 8); + rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS2FBK, 3); + rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS3FBK, 10); + rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS4FBK, 11); + rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS5FBK, 12); + rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS6FBK, 13); + rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS7FBK, 14); + rt2x00usb_register_write(rt2x00dev, LG_FBK_CFG0, reg); + + rt2x00usb_register_read(rt2x00dev, LG_FBK_CFG1, ®); + rt2x00_set_field32(®, LG_FBK_CFG0_CCKMCS0FBK, 0); + rt2x00_set_field32(®, LG_FBK_CFG0_CCKMCS1FBK, 0); + rt2x00_set_field32(®, LG_FBK_CFG0_CCKMCS2FBK, 1); + rt2x00_set_field32(®, LG_FBK_CFG0_CCKMCS3FBK, 2); + rt2x00usb_register_write(rt2x00dev, LG_FBK_CFG1, reg); + + /* + * We must clear the error counters. + * These registers are cleared on read, + * so we may pass a useless variable to store the value. + */ + rt2x00usb_register_read(rt2x00dev, RX_STA_CNT0, ®); + rt2x00usb_register_read(rt2x00dev, RX_STA_CNT1, ®); + rt2x00usb_register_read(rt2x00dev, RX_STA_CNT2, ®); + rt2x00usb_register_read(rt2x00dev, TX_STA_CNT0, ®); + rt2x00usb_register_read(rt2x00dev, TX_STA_CNT1, ®); + rt2x00usb_register_read(rt2x00dev, TX_STA_CNT2, ®); + + return 0; +} + +static int rt2800usb_wait_bbp_rf_ready(struct rt2x00_dev *rt2x00dev) +{ + unsigned int i; + u32 reg; + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2x00usb_register_read(rt2x00dev, MAC_STATUS_CFG, ®); + if (!rt2x00_get_field32(reg, MAC_STATUS_CFG_BBP_RF_BUSY)) + return 0; + + udelay(REGISTER_BUSY_DELAY); + } + + ERROR(rt2x00dev, "BBP/RF register access failed, aborting.\n"); + return -EACCES; +} + +static int rt2800usb_wait_bbp_ready(struct rt2x00_dev *rt2x00dev) +{ + unsigned int i; + u8 value; + + /* + * BBP was enabled after firmware was loaded, + * but we need to reactivate it now. + */ + rt2x00usb_register_write(rt2x00dev, H2M_BBP_AGENT, 0); + rt2x00usb_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0); + msleep(1); + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2800usb_bbp_read(rt2x00dev, 0, &value); + if ((value != 0xff) && (value != 0x00)) + return 0; + udelay(REGISTER_BUSY_DELAY); + } + + ERROR(rt2x00dev, "BBP register access failed, aborting.\n"); + return -EACCES; +} + +static int rt2800usb_init_bbp(struct rt2x00_dev *rt2x00dev) +{ + unsigned int i; + u16 eeprom; + u8 reg_id; + u8 value; + + if (unlikely(rt2800usb_wait_bbp_rf_ready(rt2x00dev) || + rt2800usb_wait_bbp_ready(rt2x00dev))) + return -EACCES; + + rt2800usb_bbp_write(rt2x00dev, 65, 0x2c); + rt2800usb_bbp_write(rt2x00dev, 66, 0x38); + rt2800usb_bbp_write(rt2x00dev, 69, 0x12); + rt2800usb_bbp_write(rt2x00dev, 70, 0x0a); + rt2800usb_bbp_write(rt2x00dev, 73, 0x10); + rt2800usb_bbp_write(rt2x00dev, 81, 0x37); + rt2800usb_bbp_write(rt2x00dev, 82, 0x62); + rt2800usb_bbp_write(rt2x00dev, 83, 0x6a); + rt2800usb_bbp_write(rt2x00dev, 84, 0x99); + rt2800usb_bbp_write(rt2x00dev, 86, 0x00); + rt2800usb_bbp_write(rt2x00dev, 91, 0x04); + rt2800usb_bbp_write(rt2x00dev, 92, 0x00); + rt2800usb_bbp_write(rt2x00dev, 103, 0x00); + rt2800usb_bbp_write(rt2x00dev, 105, 0x05); + + if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION) { + rt2800usb_bbp_write(rt2x00dev, 69, 0x16); + rt2800usb_bbp_write(rt2x00dev, 73, 0x12); + } + + if (rt2x00_rev(&rt2x00dev->chip) > RT2860D_VERSION) { + rt2800usb_bbp_write(rt2x00dev, 84, 0x19); + } + + if (rt2x00_rev(&rt2x00dev->chip) == RT3070_VERSION) { + rt2800usb_bbp_write(rt2x00dev, 70, 0x0a); + rt2800usb_bbp_write(rt2x00dev, 84, 0x99); + rt2800usb_bbp_write(rt2x00dev, 105, 0x05); + } + + for (i = 0; i < EEPROM_BBP_SIZE; i++) { + rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom); + + if (eeprom != 0xffff && eeprom != 0x0000) { + reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID); + value = rt2x00_get_field16(eeprom, EEPROM_BBP_VALUE); + rt2800usb_bbp_write(rt2x00dev, reg_id, value); + } + } + + return 0; +} + +static u8 rt2800usb_init_rx_filter(struct rt2x00_dev *rt2x00dev, + bool bw40, u8 rfcsr24, u8 filter_target) +{ + unsigned int i; + u8 bbp; + u8 rfcsr; + u8 passband; + u8 stopband; + u8 overtuned = 0; + + rt2800usb_rfcsr_write(rt2x00dev, 24, rfcsr24); + + rt2800usb_bbp_read(rt2x00dev, 4, &bbp); + rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 2 * bw40); + rt2800usb_bbp_write(rt2x00dev, 4, bbp); + + rt2800usb_rfcsr_read(rt2x00dev, 22, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR22_BASEBAND_LOOPBACK, 1); + rt2800usb_rfcsr_write(rt2x00dev, 22, rfcsr); + + /* + * Set power & frequency of passband test tone + */ + rt2800usb_bbp_write(rt2x00dev, 24, 0); + + for (i = 0; i < 100; i++) { + rt2800usb_bbp_write(rt2x00dev, 25, 0x90); + msleep(1); + + rt2800usb_bbp_read(rt2x00dev, 55, &passband); + if (passband) + break; + } + + /* + * Set power & frequency of stopband test tone + */ + rt2800usb_bbp_write(rt2x00dev, 24, 0x06); + + for (i = 0; i < 100; i++) { + rt2800usb_bbp_write(rt2x00dev, 25, 0x90); + msleep(1); + + rt2800usb_bbp_read(rt2x00dev, 55, &stopband); + + if ((passband - stopband) <= filter_target) { + rfcsr24++; + overtuned += ((passband - stopband) == filter_target); + } else + break; + + rt2800usb_rfcsr_write(rt2x00dev, 24, rfcsr24); + } + + rfcsr24 -= !!overtuned; + + rt2800usb_rfcsr_write(rt2x00dev, 24, rfcsr24); + return rfcsr24; +} + +static int rt2800usb_init_rfcsr(struct rt2x00_dev *rt2x00dev) +{ + u8 rfcsr; + u8 bbp; + + if (rt2x00_rev(&rt2x00dev->chip) != RT3070_VERSION) + return 0; + + /* + * Init RF calibration. + */ + rt2800usb_rfcsr_read(rt2x00dev, 30, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 1); + rt2800usb_rfcsr_write(rt2x00dev, 30, rfcsr); + msleep(1); + rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 0); + rt2800usb_rfcsr_write(rt2x00dev, 30, rfcsr); + + rt2800usb_rfcsr_write(rt2x00dev, 4, 0x40); + rt2800usb_rfcsr_write(rt2x00dev, 5, 0x03); + rt2800usb_rfcsr_write(rt2x00dev, 6, 0x02); + rt2800usb_rfcsr_write(rt2x00dev, 7, 0x70); + rt2800usb_rfcsr_write(rt2x00dev, 9, 0x0f); + rt2800usb_rfcsr_write(rt2x00dev, 10, 0x71); + rt2800usb_rfcsr_write(rt2x00dev, 11, 0x21); + rt2800usb_rfcsr_write(rt2x00dev, 12, 0x7b); + rt2800usb_rfcsr_write(rt2x00dev, 14, 0x90); + rt2800usb_rfcsr_write(rt2x00dev, 15, 0x58); + rt2800usb_rfcsr_write(rt2x00dev, 16, 0xb3); + rt2800usb_rfcsr_write(rt2x00dev, 17, 0x92); + rt2800usb_rfcsr_write(rt2x00dev, 18, 0x2c); + rt2800usb_rfcsr_write(rt2x00dev, 19, 0x02); + rt2800usb_rfcsr_write(rt2x00dev, 20, 0xba); + rt2800usb_rfcsr_write(rt2x00dev, 21, 0xdb); + rt2800usb_rfcsr_write(rt2x00dev, 24, 0x16); + rt2800usb_rfcsr_write(rt2x00dev, 25, 0x01); + rt2800usb_rfcsr_write(rt2x00dev, 27, 0x03); + rt2800usb_rfcsr_write(rt2x00dev, 29, 0x1f); + + /* + * Set RX Filter calibration for 20MHz and 40MHz + */ + rt2x00dev->calibration[0] = + rt2800usb_init_rx_filter(rt2x00dev, false, 0x07, 0x16); + rt2x00dev->calibration[1] = + rt2800usb_init_rx_filter(rt2x00dev, true, 0x27, 0x19); + + /* + * Set back to initial state + */ + rt2800usb_bbp_write(rt2x00dev, 24, 0); + + rt2800usb_rfcsr_read(rt2x00dev, 22, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR22_BASEBAND_LOOPBACK, 0); + rt2800usb_rfcsr_write(rt2x00dev, 22, rfcsr); + + /* + * set BBP back to BW20 + */ + rt2800usb_bbp_read(rt2x00dev, 4, &bbp); + rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 0); + rt2800usb_bbp_write(rt2x00dev, 4, bbp); + + return 0; +} + +/* + * Device state switch handlers. + */ +static void rt2800usb_toggle_rx(struct rt2x00_dev *rt2x00dev, + enum dev_state state) +{ + u32 reg; + + rt2x00usb_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, + (state == STATE_RADIO_RX_ON) || + (state == STATE_RADIO_RX_ON_LINK)); + rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, reg); +} + +static int rt2800usb_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev) +{ + unsigned int i; + u32 reg; + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2x00usb_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); + if (!rt2x00_get_field32(reg, WPDMA_GLO_CFG_TX_DMA_BUSY) && + !rt2x00_get_field32(reg, WPDMA_GLO_CFG_RX_DMA_BUSY)) + return 0; + + msleep(1); + } + + ERROR(rt2x00dev, "WPDMA TX/RX busy, aborting.\n"); + return -EACCES; +} + +static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + u16 word; + + /* + * Initialize all registers. + */ + if (unlikely(rt2800usb_wait_wpdma_ready(rt2x00dev) || + rt2800usb_init_registers(rt2x00dev) || + rt2800usb_init_bbp(rt2x00dev) || + rt2800usb_init_rfcsr(rt2x00dev))) + return -EIO; + + rt2x00usb_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_TX, 1); + rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, reg); + + udelay(50); + + rt2x00usb_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); + rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1); + rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 1); + rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 1); + rt2x00usb_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); + + + rt2x00usb_register_read(rt2x00dev, USB_DMA_CFG, ®); + rt2x00_set_field32(®, USB_DMA_CFG_PHY_CLEAR, 0); + /* Don't use bulk in aggregation when working with USB 1.1 */ + rt2x00_set_field32(®, USB_DMA_CFG_RX_BULK_AGG_EN, + (rt2x00dev->rx->usb_maxpacket == 512)); + rt2x00_set_field32(®, USB_DMA_CFG_RX_BULK_AGG_TIMEOUT, 128); + /* + * Total room for RX frames in kilobytes, PBF might still exceed + * this limit so reduce the number to prevent errors. + */ + rt2x00_set_field32(®, USB_DMA_CFG_RX_BULK_AGG_LIMIT, + ((RX_ENTRIES * DATA_FRAME_SIZE) / 1024) - 3); + rt2x00_set_field32(®, USB_DMA_CFG_RX_BULK_EN, 1); + rt2x00_set_field32(®, USB_DMA_CFG_TX_BULK_EN, 1); + rt2x00usb_register_write(rt2x00dev, USB_DMA_CFG, reg); + + rt2x00usb_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_TX, 1); + rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, 1); + rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, reg); + + /* + * Initialize LED control + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_LED1, &word); + rt2800usb_mcu_request(rt2x00dev, MCU_LED_1, 0xff, + word & 0xff, (word >> 8) & 0xff); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_LED2, &word); + rt2800usb_mcu_request(rt2x00dev, MCU_LED_2, 0xff, + word & 0xff, (word >> 8) & 0xff); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_LED3, &word); + rt2800usb_mcu_request(rt2x00dev, MCU_LED_3, 0xff, + word & 0xff, (word >> 8) & 0xff); + + return 0; +} + +static void rt2800usb_disable_radio(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + rt2x00usb_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); + rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0); + rt2x00usb_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); + + rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, 0); + rt2x00usb_register_write(rt2x00dev, PWR_PIN_CFG, 0); + rt2x00usb_register_write(rt2x00dev, TX_PIN_CFG, 0); + + /* Wait for DMA, ignore error */ + rt2800usb_wait_wpdma_ready(rt2x00dev); + + rt2x00usb_disable_radio(rt2x00dev); +} + +static int rt2800usb_set_state(struct rt2x00_dev *rt2x00dev, + enum dev_state state) +{ + if (state == STATE_AWAKE) + rt2800usb_mcu_request(rt2x00dev, MCU_WAKEUP, 0xff, 0, 0); + else + rt2800usb_mcu_request(rt2x00dev, MCU_SLEEP, 0xff, 0, 2); + + return 0; +} + +static int rt2800usb_set_device_state(struct rt2x00_dev *rt2x00dev, + enum dev_state state) +{ + int retval = 0; + + switch (state) { + case STATE_RADIO_ON: + /* + * Before the radio can be enabled, the device first has + * to be woken up. After that it needs a bit of time + * to be fully awake and the radio can be enabled. + */ + rt2800usb_set_state(rt2x00dev, STATE_AWAKE); + msleep(1); + retval = rt2800usb_enable_radio(rt2x00dev); + break; + case STATE_RADIO_OFF: + /* + * After the radio has been disablee, the device should + * be put to sleep for powersaving. + */ + rt2800usb_disable_radio(rt2x00dev); + rt2800usb_set_state(rt2x00dev, STATE_SLEEP); + break; + case STATE_RADIO_RX_ON: + case STATE_RADIO_RX_ON_LINK: + case STATE_RADIO_RX_OFF: + case STATE_RADIO_RX_OFF_LINK: + rt2800usb_toggle_rx(rt2x00dev, state); + break; + case STATE_RADIO_IRQ_ON: + case STATE_RADIO_IRQ_OFF: + /* No support, but no error either */ + break; + case STATE_DEEP_SLEEP: + case STATE_SLEEP: + case STATE_STANDBY: + case STATE_AWAKE: + retval = rt2800usb_set_state(rt2x00dev, state); + break; + default: + retval = -ENOTSUPP; + break; + } + + if (unlikely(retval)) + ERROR(rt2x00dev, "Device failed to enter state %d (%d).\n", + state, retval); + + return retval; +} + +/* + * TX descriptor initialization + */ +static void rt2800usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, + struct sk_buff *skb, + struct txentry_desc *txdesc) +{ + struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); + __le32 *txi = skbdesc->desc; + __le32 *txwi = &txi[TXINFO_DESC_SIZE / sizeof(__le32)]; + u32 word; + + /* + * Initialize TX Info descriptor + */ + rt2x00_desc_read(txwi, 0, &word); + rt2x00_set_field32(&word, TXWI_W0_FRAG, + test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags)); + rt2x00_set_field32(&word, TXWI_W0_MIMO_PS, 0); + rt2x00_set_field32(&word, TXWI_W0_CF_ACK, 0); + rt2x00_set_field32(&word, TXWI_W0_TS, + test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags)); + rt2x00_set_field32(&word, TXWI_W0_AMPDU, + test_bit(ENTRY_TXD_HT_AMPDU, &txdesc->flags)); + rt2x00_set_field32(&word, TXWI_W0_MPDU_DENSITY, txdesc->mpdu_density); + rt2x00_set_field32(&word, TXWI_W0_TX_OP, txdesc->ifs); + rt2x00_set_field32(&word, TXWI_W0_MCS, txdesc->mcs); + rt2x00_set_field32(&word, TXWI_W0_BW, + test_bit(ENTRY_TXD_HT_BW_40, &txdesc->flags)); + rt2x00_set_field32(&word, TXWI_W0_SHORT_GI, + test_bit(ENTRY_TXD_HT_SHORT_GI, &txdesc->flags)); + rt2x00_set_field32(&word, TXWI_W0_STBC, txdesc->stbc); + rt2x00_set_field32(&word, TXWI_W0_PHYMODE, txdesc->rate_mode); + rt2x00_desc_write(txwi, 0, word); + + rt2x00_desc_read(txwi, 1, &word); + rt2x00_set_field32(&word, TXWI_W1_ACK, + test_bit(ENTRY_TXD_ACK, &txdesc->flags)); + rt2x00_set_field32(&word, TXWI_W1_NSEQ, + test_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags)); + rt2x00_set_field32(&word, TXWI_W1_BW_WIN_SIZE, txdesc->ba_size); + rt2x00_set_field32(&word, TXWI_W1_WIRELESS_CLI_ID, + test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags) ? + txdesc->key_idx : 0xff); + rt2x00_set_field32(&word, TXWI_W1_MPDU_TOTAL_BYTE_COUNT, + skb->len - txdesc->l2pad); + rt2x00_set_field32(&word, TXWI_W1_PACKETID, + skbdesc->entry->entry_idx); + rt2x00_desc_write(txwi, 1, word); + + /* + * Always write 0 to IV/EIV fields, hardware will insert the IV + * from the IVEIV register when TXINFO_W0_WIV is set to 0. + * When TXINFO_W0_WIV is set to 1 it will use the IV data + * from the descriptor. The TXWI_W1_WIRELESS_CLI_ID indicates which + * crypto entry in the registers should be used to encrypt the frame. + */ + _rt2x00_desc_write(txwi, 2, 0 /* skbdesc->iv[0] */); + _rt2x00_desc_write(txwi, 3, 0 /* skbdesc->iv[1] */); + + /* + * Initialize TX descriptor + */ + rt2x00_desc_read(txi, 0, &word); + rt2x00_set_field32(&word, TXINFO_W0_USB_DMA_TX_PKT_LEN, + skb->len + TXWI_DESC_SIZE); + rt2x00_set_field32(&word, TXINFO_W0_WIV, + !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc->flags)); + rt2x00_set_field32(&word, TXINFO_W0_QSEL, 2); + rt2x00_set_field32(&word, TXINFO_W0_SW_USE_LAST_ROUND, 0); + rt2x00_set_field32(&word, TXINFO_W0_USB_DMA_NEXT_VALID, 0); + rt2x00_set_field32(&word, TXINFO_W0_USB_DMA_TX_BURST, + test_bit(ENTRY_TXD_BURST, &txdesc->flags)); + rt2x00_desc_write(txi, 0, word); +} + +/* + * TX data initialization + */ +static void rt2800usb_write_beacon(struct queue_entry *entry) +{ + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; + struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); + unsigned int beacon_base; + u32 reg; + + /* + * Add the descriptor in front of the skb. + */ + skb_push(entry->skb, entry->queue->desc_size); + memcpy(entry->skb->data, skbdesc->desc, skbdesc->desc_len); + skbdesc->desc = entry->skb->data; + + /* + * Disable beaconing while we are reloading the beacon data, + * otherwise we might be sending out invalid data. + */ + rt2x00usb_register_read(rt2x00dev, BCN_TIME_CFG, ®); + rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 0); + rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 0); + rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 0); + rt2x00usb_register_write(rt2x00dev, BCN_TIME_CFG, reg); + + /* + * Write entire beacon with descriptor to register. + */ + beacon_base = HW_BEACON_OFFSET(entry->entry_idx); + rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE, + USB_VENDOR_REQUEST_OUT, beacon_base, + entry->skb->data, entry->skb->len, + REGISTER_TIMEOUT32(entry->skb->len)); + + /* + * Clean up the beacon skb. + */ + dev_kfree_skb(entry->skb); + entry->skb = NULL; +} + +static int rt2800usb_get_tx_data_len(struct queue_entry *entry) +{ + int length; + + /* + * The length _must_ include 4 bytes padding, + * it should always be multiple of 4, + * but it must _not_ be a multiple of the USB packet size. + */ + length = roundup(entry->skb->len + 4, 4); + length += (4 * !(length % entry->queue->usb_maxpacket)); + + return length; +} + +static void rt2800usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, + const enum data_queue_qid queue) +{ + u32 reg; + + if (queue != QID_BEACON) { + rt2x00usb_kick_tx_queue(rt2x00dev, queue); + return; + } + + rt2x00usb_register_read(rt2x00dev, BCN_TIME_CFG, ®); + if (!rt2x00_get_field32(reg, BCN_TIME_CFG_BEACON_GEN)) { + rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 1); + rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 1); + rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 1); + rt2x00usb_register_write(rt2x00dev, BCN_TIME_CFG, reg); + } +} + +/* + * RX control handlers + */ +static void rt2800usb_fill_rxdone(struct queue_entry *entry, + struct rxdone_entry_desc *rxdesc) +{ + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; + struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); + __le32 *rxd = (__le32 *)entry->skb->data; + __le32 *rxwi; + u32 rxd0; + u32 rxwi0; + u32 rxwi1; + u32 rxwi2; + u32 rxwi3; + + /* + * Copy descriptor to the skbdesc->desc buffer, making it safe from + * moving of frame data in rt2x00usb. + */ + memcpy(skbdesc->desc, rxd, skbdesc->desc_len); + rxd = (__le32 *)skbdesc->desc; + rxwi = &rxd[RXD_DESC_SIZE / sizeof(__le32)]; + + /* + * It is now safe to read the descriptor on all architectures. + */ + rt2x00_desc_read(rxd, 0, &rxd0); + rt2x00_desc_read(rxwi, 0, &rxwi0); + rt2x00_desc_read(rxwi, 1, &rxwi1); + rt2x00_desc_read(rxwi, 2, &rxwi2); + rt2x00_desc_read(rxwi, 3, &rxwi3); + + if (rt2x00_get_field32(rxd0, RXD_W0_CRC_ERROR)) + rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; + + if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) { + rxdesc->cipher = rt2x00_get_field32(rxwi0, RXWI_W0_UDF); + rxdesc->cipher_status = + rt2x00_get_field32(rxd0, RXD_W0_CIPHER_ERROR); + } + + if (rt2x00_get_field32(rxd0, RXD_W0_DECRYPTED)) { + /* + * Hardware has stripped IV/EIV data from 802.11 frame during + * decryption. Unfortunately the descriptor doesn't contain + * any fields with the EIV/IV data either, so they can't + * be restored by rt2x00lib. + */ + rxdesc->flags |= RX_FLAG_IV_STRIPPED; + + if (rxdesc->cipher_status == RX_CRYPTO_SUCCESS) + rxdesc->flags |= RX_FLAG_DECRYPTED; + else if (rxdesc->cipher_status == RX_CRYPTO_FAIL_MIC) + rxdesc->flags |= RX_FLAG_MMIC_ERROR; + } + + if (rt2x00_get_field32(rxd0, RXD_W0_MY_BSS)) + rxdesc->dev_flags |= RXDONE_MY_BSS; + + if (rt2x00_get_field32(rxd0, RXD_W0_L2PAD)) + rxdesc->dev_flags |= RXDONE_L2PAD; + + if (rt2x00_get_field32(rxwi1, RXWI_W1_SHORT_GI)) + rxdesc->flags |= RX_FLAG_SHORT_GI; + + if (rt2x00_get_field32(rxwi1, RXWI_W1_BW)) + rxdesc->flags |= RX_FLAG_40MHZ; + + /* + * Detect RX rate, always use MCS as signal type. + */ + rxdesc->dev_flags |= RXDONE_SIGNAL_MCS; + rxdesc->rate_mode = rt2x00_get_field32(rxwi1, RXWI_W1_PHYMODE); + rxdesc->signal = rt2x00_get_field32(rxwi1, RXWI_W1_MCS); + + /* + * Mask of 0x8 bit to remove the short preamble flag. + */ + if (rxdesc->rate_mode == RATE_MODE_CCK) + rxdesc->signal &= ~0x8; + + rxdesc->rssi = + (rt2x00_get_field32(rxwi2, RXWI_W2_RSSI0) + + rt2x00_get_field32(rxwi2, RXWI_W2_RSSI1)) / 2; + + rxdesc->noise = + (rt2x00_get_field32(rxwi3, RXWI_W3_SNR0) + + rt2x00_get_field32(rxwi3, RXWI_W3_SNR1)) / 2; + + rxdesc->size = rt2x00_get_field32(rxwi0, RXWI_W0_MPDU_TOTAL_BYTE_COUNT); + + /* + * Remove RXWI descriptor from start of buffer. + */ + skb_pull(entry->skb, skbdesc->desc_len); + skb_trim(entry->skb, rxdesc->size); +} + +/* + * Device probe functions. + */ +static int rt2800usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) +{ + u16 word; + u8 *mac; + u8 default_lna_gain; + + rt2x00usb_eeprom_read(rt2x00dev, rt2x00dev->eeprom, EEPROM_SIZE); + + /* + * Start validation of the data that has been read. + */ + mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); + if (!is_valid_ether_addr(mac)) { + DECLARE_MAC_BUF(macbuf); + + random_ether_addr(mac); + EEPROM(rt2x00dev, "MAC: %s\n", print_mac(macbuf, mac)); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_ANTENNA_RXPATH, 2); + rt2x00_set_field16(&word, EEPROM_ANTENNA_TXPATH, 1); + rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF2820); + rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word); + EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word); + } else if (rt2x00_rev(&rt2x00dev->chip) < RT2883_VERSION) { + /* + * There is a max of 2 RX streams for RT2870 series + */ + if (rt2x00_get_field16(word, EEPROM_ANTENNA_RXPATH) > 2) + rt2x00_set_field16(&word, EEPROM_ANTENNA_RXPATH, 2); + rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_NIC_HW_RADIO, 0); + rt2x00_set_field16(&word, EEPROM_NIC_DYNAMIC_TX_AGC, 0); + rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA_BG, 0); + rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA_A, 0); + rt2x00_set_field16(&word, EEPROM_NIC_CARDBUS_ACCEL, 0); + rt2x00_set_field16(&word, EEPROM_NIC_BW40M_SB_BG, 0); + rt2x00_set_field16(&word, EEPROM_NIC_BW40M_SB_A, 0); + rt2x00_set_field16(&word, EEPROM_NIC_WPS_PBC, 0); + rt2x00_set_field16(&word, EEPROM_NIC_BW40M_BG, 0); + rt2x00_set_field16(&word, EEPROM_NIC_BW40M_A, 0); + rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC, word); + EEPROM(rt2x00dev, "NIC: 0x%04x\n", word); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &word); + if ((word & 0x00ff) == 0x00ff) { + rt2x00_set_field16(&word, EEPROM_FREQ_OFFSET, 0); + rt2x00_set_field16(&word, EEPROM_FREQ_LED_MODE, + LED_MODE_TXRX_ACTIVITY); + rt2x00_set_field16(&word, EEPROM_FREQ_LED_POLARITY, 0); + rt2x00_eeprom_write(rt2x00dev, EEPROM_FREQ, word); + rt2x00_eeprom_write(rt2x00dev, EEPROM_LED1, 0x5555); + rt2x00_eeprom_write(rt2x00dev, EEPROM_LED2, 0x2221); + rt2x00_eeprom_write(rt2x00dev, EEPROM_LED3, 0xa9f8); + EEPROM(rt2x00dev, "Freq: 0x%04x\n", word); + } + + /* + * During the LNA validation we are going to use + * lna0 as correct value. Note that EEPROM_LNA + * is never validated. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_LNA, &word); + default_lna_gain = rt2x00_get_field16(word, EEPROM_LNA_A0); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG, &word); + if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG_OFFSET0)) > 10) + rt2x00_set_field16(&word, EEPROM_RSSI_BG_OFFSET0, 0); + if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG_OFFSET1)) > 10) + rt2x00_set_field16(&word, EEPROM_RSSI_BG_OFFSET1, 0); + rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_BG, word); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &word); + if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG2_OFFSET2)) > 10) + rt2x00_set_field16(&word, EEPROM_RSSI_BG2_OFFSET2, 0); + if (rt2x00_get_field16(word, EEPROM_RSSI_BG2_LNA_A1) == 0x00 || + rt2x00_get_field16(word, EEPROM_RSSI_BG2_LNA_A1) == 0xff) + rt2x00_set_field16(&word, EEPROM_RSSI_BG2_LNA_A1, + default_lna_gain); + rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_BG2, word); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A, &word); + if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A_OFFSET0)) > 10) + rt2x00_set_field16(&word, EEPROM_RSSI_A_OFFSET0, 0); + if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A_OFFSET1)) > 10) + rt2x00_set_field16(&word, EEPROM_RSSI_A_OFFSET1, 0); + rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_A, word); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &word); + if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A2_OFFSET2)) > 10) + rt2x00_set_field16(&word, EEPROM_RSSI_A2_OFFSET2, 0); + if (rt2x00_get_field16(word, EEPROM_RSSI_A2_LNA_A2) == 0x00 || + rt2x00_get_field16(word, EEPROM_RSSI_A2_LNA_A2) == 0xff) + rt2x00_set_field16(&word, EEPROM_RSSI_A2_LNA_A2, + default_lna_gain); + rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_A2, word); + + return 0; +} + +static int rt2800usb_init_eeprom(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + u16 value; + u16 eeprom; + + /* + * Read EEPROM word for configuration. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom); + + /* + * Identify RF chipset. + */ + value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); + rt2x00usb_register_read(rt2x00dev, MAC_CSR0, ®); + rt2x00_set_chip(rt2x00dev, RT2870, value, reg); + + /* + * The check for rt2860 is not a typo, some rt2870 hardware + * identifies itself as rt2860 in the CSR register. + */ + if (!rt2x00_check_rev(&rt2x00dev->chip, 0xfff00000, 0x28600000) && + !rt2x00_check_rev(&rt2x00dev->chip, 0xfff00000, 0x28700000) && + !rt2x00_check_rev(&rt2x00dev->chip, 0xfff00000, 0x28800000) && + !rt2x00_check_rev(&rt2x00dev->chip, 0xffff0000, 0x30700000)) { + ERROR(rt2x00dev, "Invalid RT chipset detected.\n"); + return -ENODEV; + } + + if (!rt2x00_rf(&rt2x00dev->chip, RF2820) && + !rt2x00_rf(&rt2x00dev->chip, RF2850) && + !rt2x00_rf(&rt2x00dev->chip, RF2720) && + !rt2x00_rf(&rt2x00dev->chip, RF2750) && + !rt2x00_rf(&rt2x00dev->chip, RF3020) && + !rt2x00_rf(&rt2x00dev->chip, RF2020)) { + ERROR(rt2x00dev, "Invalid RF chipset detected.\n"); + return -ENODEV; + } + + /* + * Identify default antenna configuration. + */ + rt2x00dev->default_ant.tx = + rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH); + rt2x00dev->default_ant.rx = + rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH); + + /* + * Read frequency offset and RF programming sequence. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom); + rt2x00dev->freq_offset = rt2x00_get_field16(eeprom, EEPROM_FREQ_OFFSET); + + /* + * Read external LNA informations. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom); + + if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_A)) + __set_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags); + if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_BG)) + __set_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags); + + /* + * Detect if this device has an hardware controlled radio. + */ +#ifdef CONFIG_RT2X00_LIB_RFKILL + if (rt2x00_get_field16(eeprom, EEPROM_NIC_HW_RADIO)) + __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); +#endif /* CONFIG_RT2X00_LIB_RFKILL */ + + /* + * Store led settings, for correct led behaviour. + */ +#ifdef CONFIG_RT2X00_LIB_LEDS + rt2800usb_init_led(rt2x00dev, &rt2x00dev->led_radio, LED_TYPE_RADIO); + rt2800usb_init_led(rt2x00dev, &rt2x00dev->led_assoc, LED_TYPE_ASSOC); + rt2800usb_init_led(rt2x00dev, &rt2x00dev->led_qual, LED_TYPE_QUALITY); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, + &rt2x00dev->led_mcu_reg); +#endif /* CONFIG_RT2X00_LIB_LEDS */ + + return 0; +} + +/* + * RF value list for rt2870 + * Supports: 2.4 GHz (all) & 5.2 GHz (RF2850 & RF2750) + */ +static const struct rf_channel rf_vals[] = { + { 1, 0x18402ecc, 0x184c0786, 0x1816b455, 0x1800510b }, + { 2, 0x18402ecc, 0x184c0786, 0x18168a55, 0x1800519f }, + { 3, 0x18402ecc, 0x184c078a, 0x18168a55, 0x1800518b }, + { 4, 0x18402ecc, 0x184c078a, 0x18168a55, 0x1800519f }, + { 5, 0x18402ecc, 0x184c078e, 0x18168a55, 0x1800518b }, + { 6, 0x18402ecc, 0x184c078e, 0x18168a55, 0x1800519f }, + { 7, 0x18402ecc, 0x184c0792, 0x18168a55, 0x1800518b }, + { 8, 0x18402ecc, 0x184c0792, 0x18168a55, 0x1800519f }, + { 9, 0x18402ecc, 0x184c0796, 0x18168a55, 0x1800518b }, + { 10, 0x18402ecc, 0x184c0796, 0x18168a55, 0x1800519f }, + { 11, 0x18402ecc, 0x184c079a, 0x18168a55, 0x1800518b }, + { 12, 0x18402ecc, 0x184c079a, 0x18168a55, 0x1800519f }, + { 13, 0x18402ecc, 0x184c079e, 0x18168a55, 0x1800518b }, + { 14, 0x18402ecc, 0x184c07a2, 0x18168a55, 0x18005193 }, + + /* 802.11 UNI / HyperLan 2 */ + { 36, 0x18402ecc, 0x184c099a, 0x18158a55, 0x180ed1a3 }, + { 38, 0x18402ecc, 0x184c099e, 0x18158a55, 0x180ed193 }, + { 40, 0x18402ec8, 0x184c0682, 0x18158a55, 0x180ed183 }, + { 44, 0x18402ec8, 0x184c0682, 0x18158a55, 0x180ed1a3 }, + { 46, 0x18402ec8, 0x184c0686, 0x18158a55, 0x180ed18b }, + { 48, 0x18402ec8, 0x184c0686, 0x18158a55, 0x180ed19b }, + { 52, 0x18402ec8, 0x184c068a, 0x18158a55, 0x180ed193 }, + { 54, 0x18402ec8, 0x184c068a, 0x18158a55, 0x180ed1a3 }, + { 56, 0x18402ec8, 0x184c068e, 0x18158a55, 0x180ed18b }, + { 60, 0x18402ec8, 0x184c0692, 0x18158a55, 0x180ed183 }, + { 62, 0x18402ec8, 0x184c0692, 0x18158a55, 0x180ed193 }, + { 64, 0x18402ec8, 0x184c0692, 0x18158a55, 0x180ed1a3 }, + + /* 802.11 HyperLan 2 */ + { 100, 0x18402ec8, 0x184c06b2, 0x18178a55, 0x180ed783 }, + { 102, 0x18402ec8, 0x184c06b2, 0x18578a55, 0x180ed793 }, + { 104, 0x18402ec8, 0x185c06b2, 0x18578a55, 0x180ed1a3 }, + { 108, 0x18402ecc, 0x185c0a32, 0x18578a55, 0x180ed193 }, + { 110, 0x18402ecc, 0x184c0a36, 0x18178a55, 0x180ed183 }, + { 112, 0x18402ecc, 0x184c0a36, 0x18178a55, 0x180ed19b }, + { 116, 0x18402ecc, 0x184c0a3a, 0x18178a55, 0x180ed1a3 }, + { 118, 0x18402ecc, 0x184c0a3e, 0x18178a55, 0x180ed193 }, + { 120, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed183 }, + { 124, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed193 }, + { 126, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed15b }, + { 128, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed1a3 }, + { 132, 0x18402ec4, 0x184c0386, 0x18178a55, 0x180ed18b }, + { 134, 0x18402ec4, 0x184c0386, 0x18178a55, 0x180ed193 }, + { 136, 0x18402ec4, 0x184c0386, 0x18178a55, 0x180ed19b }, + { 140, 0x18402ec4, 0x184c038a, 0x18178a55, 0x180ed183 }, + + /* 802.11 UNII */ + { 149, 0x18402ec4, 0x184c038a, 0x18178a55, 0x180ed1a7 }, + { 151, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed187 }, + { 153, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed18f }, + { 157, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed19f }, + { 159, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed1a7 }, + { 161, 0x18402ec4, 0x184c0392, 0x18178a55, 0x180ed187 }, + { 165, 0x18402ec4, 0x184c0392, 0x18178a55, 0x180ed197 }, + { 167, 0x18402ec4, 0x184c03d2, 0x18179855, 0x1815531f }, + { 169, 0x18402ec4, 0x184c03d2, 0x18179855, 0x18155327 }, + { 171, 0x18402ec4, 0x184c03d6, 0x18179855, 0x18155307 }, + { 173, 0x18402ec4, 0x184c03d6, 0x18179855, 0x1815530f }, + + /* 802.11 Japan */ + { 184, 0x15002ccc, 0x1500491e, 0x1509be55, 0x150c0a0b }, + { 188, 0x15002ccc, 0x15004922, 0x1509be55, 0x150c0a13 }, + { 192, 0x15002ccc, 0x15004926, 0x1509be55, 0x150c0a1b }, + { 196, 0x15002ccc, 0x1500492a, 0x1509be55, 0x150c0a23 }, + { 208, 0x15002ccc, 0x1500493a, 0x1509be55, 0x150c0a13 }, + { 212, 0x15002ccc, 0x1500493e, 0x1509be55, 0x150c0a1b }, + { 216, 0x15002ccc, 0x15004982, 0x1509be55, 0x150c0a23 }, +}; + +/* + * RF value list for rt3070 + * Supports: 2.4 GHz + */ +static const struct rf_channel rf_vals_3070[] = { + {1, 241, 2, 2 }, + {2, 241, 2, 7 }, + {3, 242, 2, 2 }, + {4, 242, 2, 7 }, + {5, 243, 2, 2 }, + {6, 243, 2, 7 }, + {7, 244, 2, 2 }, + {8, 244, 2, 7 }, + {9, 245, 2, 2 }, + {10, 245, 2, 7 }, + {11, 246, 2, 2 }, + {12, 246, 2, 7 }, + {13, 247, 2, 2 }, + {14, 248, 2, 4 }, +}; + +static int rt2800usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) +{ + struct hw_mode_spec *spec = &rt2x00dev->spec; + struct channel_info *info; + char *tx_power1; + char *tx_power2; + unsigned int i; + u16 eeprom; + + /* + * Initialize all hw fields. + */ + rt2x00dev->hw->flags = + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | + IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_SUPPORTS_PS | + IEEE80211_HW_PS_NULLFUNC_STACK; + rt2x00dev->hw->extra_tx_headroom = TXINFO_DESC_SIZE + TXWI_DESC_SIZE; + + SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev); + SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, + rt2x00_eeprom_addr(rt2x00dev, + EEPROM_MAC_ADDR_0)); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom); + + /* + * Initialize HT information. + */ + spec->ht.ht_supported = true; + spec->ht.cap = + IEEE80211_HT_CAP_SUP_WIDTH_20_40 | + IEEE80211_HT_CAP_GRN_FLD | + IEEE80211_HT_CAP_SGI_20 | + IEEE80211_HT_CAP_SGI_40 | + IEEE80211_HT_CAP_TX_STBC | + IEEE80211_HT_CAP_RX_STBC | + IEEE80211_HT_CAP_PSMP_SUPPORT; + spec->ht.ampdu_factor = 3; + spec->ht.ampdu_density = 4; + spec->ht.mcs.tx_params = + IEEE80211_HT_MCS_TX_DEFINED | + IEEE80211_HT_MCS_TX_RX_DIFF | + ((rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH) - 1) << + IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT); + + switch (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH)) { + case 3: + spec->ht.mcs.rx_mask[2] = 0xff; + case 2: + spec->ht.mcs.rx_mask[1] = 0xff; + case 1: + spec->ht.mcs.rx_mask[0] = 0xff; + spec->ht.mcs.rx_mask[4] = 0x1; /* MCS32 */ + break; + } + + /* + * Initialize hw_mode information. + */ + spec->supported_bands = SUPPORT_BAND_2GHZ; + spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM; + + if (rt2x00_rf(&rt2x00dev->chip, RF2820) || + rt2x00_rf(&rt2x00dev->chip, RF2720)) { + spec->num_channels = 14; + spec->channels = rf_vals; + } else if (rt2x00_rf(&rt2x00dev->chip, RF2850) || + rt2x00_rf(&rt2x00dev->chip, RF2750)) { + spec->supported_bands |= SUPPORT_BAND_5GHZ; + spec->num_channels = ARRAY_SIZE(rf_vals); + spec->channels = rf_vals; + } else if (rt2x00_rf(&rt2x00dev->chip, RF3020) || + rt2x00_rf(&rt2x00dev->chip, RF2020)) { + spec->num_channels = ARRAY_SIZE(rf_vals_3070); + spec->channels = rf_vals_3070; + } + + /* + * Create channel information array + */ + info = kzalloc(spec->num_channels * sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + spec->channels_info = info; + + tx_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG1); + tx_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG2); + + for (i = 0; i < 14; i++) { + info[i].tx_power1 = TXPOWER_G_FROM_DEV(tx_power1[i]); + info[i].tx_power2 = TXPOWER_G_FROM_DEV(tx_power2[i]); + } + + if (spec->num_channels > 14) { + tx_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A1); + tx_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A2); + + for (i = 14; i < spec->num_channels; i++) { + info[i].tx_power1 = TXPOWER_A_FROM_DEV(tx_power1[i]); + info[i].tx_power2 = TXPOWER_A_FROM_DEV(tx_power2[i]); + } + } + + return 0; +} + +static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev) +{ + int retval; + + /* + * Allocate eeprom data. + */ + retval = rt2800usb_validate_eeprom(rt2x00dev); + if (retval) + return retval; + + retval = rt2800usb_init_eeprom(rt2x00dev); + if (retval) + return retval; + + /* + * Initialize hw specifications. + */ + retval = rt2800usb_probe_hw_mode(rt2x00dev); + if (retval) + return retval; + + /* + * This device requires firmware. + */ + __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags); + __set_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags); + __set_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags); + if (!modparam_nohwcrypt) + __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); + + /* + * Set the rssi offset. + */ + rt2x00dev->rssi_offset = DEFAULT_RSSI_OFFSET; + + return 0; +} + +/* + * IEEE80211 stack callback functions. + */ +static void rt2800usb_get_tkip_seq(struct ieee80211_hw *hw, u8 hw_key_idx, + u32 *iv32, u16 *iv16) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct mac_iveiv_entry iveiv_entry; + u32 offset; + + offset = MAC_IVEIV_ENTRY(hw_key_idx); + rt2x00usb_register_multiread(rt2x00dev, offset, + &iveiv_entry, sizeof(iveiv_entry)); + + memcpy(&iveiv_entry.iv[0], iv16, sizeof(iv16)); + memcpy(&iveiv_entry.iv[4], iv32, sizeof(iv32)); +} + +static int rt2800usb_set_rts_threshold(struct ieee80211_hw *hw, u32 value) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + u32 reg; + bool enabled = (value < IEEE80211_MAX_RTS_THRESHOLD); + + rt2x00usb_register_read(rt2x00dev, TX_RTS_CFG, ®); + rt2x00_set_field32(®, TX_RTS_CFG_RTS_THRES, value); + rt2x00usb_register_write(rt2x00dev, TX_RTS_CFG, reg); + + rt2x00usb_register_read(rt2x00dev, CCK_PROT_CFG, ®); + rt2x00_set_field32(®, CCK_PROT_CFG_RTS_TH_EN, enabled); + rt2x00usb_register_write(rt2x00dev, CCK_PROT_CFG, reg); + + rt2x00usb_register_read(rt2x00dev, OFDM_PROT_CFG, ®); + rt2x00_set_field32(®, OFDM_PROT_CFG_RTS_TH_EN, enabled); + rt2x00usb_register_write(rt2x00dev, OFDM_PROT_CFG, reg); + + rt2x00usb_register_read(rt2x00dev, MM20_PROT_CFG, ®); + rt2x00_set_field32(®, MM20_PROT_CFG_RTS_TH_EN, enabled); + rt2x00usb_register_write(rt2x00dev, MM20_PROT_CFG, reg); + + rt2x00usb_register_read(rt2x00dev, MM40_PROT_CFG, ®); + rt2x00_set_field32(®, MM40_PROT_CFG_RTS_TH_EN, enabled); + rt2x00usb_register_write(rt2x00dev, MM40_PROT_CFG, reg); + + rt2x00usb_register_read(rt2x00dev, GF20_PROT_CFG, ®); + rt2x00_set_field32(®, GF20_PROT_CFG_RTS_TH_EN, enabled); + rt2x00usb_register_write(rt2x00dev, GF20_PROT_CFG, reg); + + rt2x00usb_register_read(rt2x00dev, GF40_PROT_CFG, ®); + rt2x00_set_field32(®, GF40_PROT_CFG_RTS_TH_EN, enabled); + rt2x00usb_register_write(rt2x00dev, GF40_PROT_CFG, reg); + + return 0; +} + +static int rt2800usb_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, + const struct ieee80211_tx_queue_params *params) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct data_queue *queue; + struct rt2x00_field32 field; + int retval; + u32 reg; + u32 offset; + + /* + * First pass the configuration through rt2x00lib, that will + * update the queue settings and validate the input. After that + * we are free to update the registers based on the value + * in the queue parameter. + */ + retval = rt2x00mac_conf_tx(hw, queue_idx, params); + if (retval) + return retval; + + /* + * We only need to perform additional register initialization + * for WMM queues/ + */ + if (queue_idx >= 4) + return 0; + + queue = rt2x00queue_get_queue(rt2x00dev, queue_idx); + + /* Update WMM TXOP register */ + offset = WMM_TXOP0_CFG + (sizeof(u32) * (!!(queue_idx & 2))); + field.bit_offset = (queue_idx & 1) * 16; + field.bit_mask = 0xffff << field.bit_offset; + + rt2x00usb_register_read(rt2x00dev, offset, ®); + rt2x00_set_field32(®, field, queue->txop); + rt2x00usb_register_write(rt2x00dev, offset, reg); + + /* Update WMM registers */ + field.bit_offset = queue_idx * 4; + field.bit_mask = 0xf << field.bit_offset; + + rt2x00usb_register_read(rt2x00dev, WMM_AIFSN_CFG, ®); + rt2x00_set_field32(®, field, queue->aifs); + rt2x00usb_register_write(rt2x00dev, WMM_AIFSN_CFG, reg); + + rt2x00usb_register_read(rt2x00dev, WMM_CWMIN_CFG, ®); + rt2x00_set_field32(®, field, queue->cw_min); + rt2x00usb_register_write(rt2x00dev, WMM_CWMIN_CFG, reg); + + rt2x00usb_register_read(rt2x00dev, WMM_CWMAX_CFG, ®); + rt2x00_set_field32(®, field, queue->cw_max); + rt2x00usb_register_write(rt2x00dev, WMM_CWMAX_CFG, reg); + + /* Update EDCA registers */ + offset = EDCA_AC0_CFG + (sizeof(u32) * queue_idx); + + rt2x00usb_register_read(rt2x00dev, offset, ®); + rt2x00_set_field32(®, EDCA_AC0_CFG_TX_OP, queue->txop); + rt2x00_set_field32(®, EDCA_AC0_CFG_AIFSN, queue->aifs); + rt2x00_set_field32(®, EDCA_AC0_CFG_CWMIN, queue->cw_min); + rt2x00_set_field32(®, EDCA_AC0_CFG_CWMAX, queue->cw_max); + rt2x00usb_register_write(rt2x00dev, offset, reg); + + return 0; +} + +static u64 rt2800usb_get_tsf(struct ieee80211_hw *hw) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + u64 tsf; + u32 reg; + + rt2x00usb_register_read(rt2x00dev, TSF_TIMER_DW1, ®); + tsf = (u64) rt2x00_get_field32(reg, TSF_TIMER_DW1_HIGH_WORD) << 32; + rt2x00usb_register_read(rt2x00dev, TSF_TIMER_DW0, ®); + tsf |= rt2x00_get_field32(reg, TSF_TIMER_DW0_LOW_WORD); + + return tsf; +} + +static const struct ieee80211_ops rt2800usb_mac80211_ops = { + .tx = rt2x00mac_tx, + .start = rt2x00mac_start, + .stop = rt2x00mac_stop, + .add_interface = rt2x00mac_add_interface, + .remove_interface = rt2x00mac_remove_interface, + .config = rt2x00mac_config, + .configure_filter = rt2x00mac_configure_filter, + .set_key = rt2x00mac_set_key, + .get_stats = rt2x00mac_get_stats, + .get_tkip_seq = rt2800usb_get_tkip_seq, + .set_rts_threshold = rt2800usb_set_rts_threshold, + .bss_info_changed = rt2x00mac_bss_info_changed, + .conf_tx = rt2800usb_conf_tx, + .get_tx_stats = rt2x00mac_get_tx_stats, + .get_tsf = rt2800usb_get_tsf, +}; + +static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = { + .probe_hw = rt2800usb_probe_hw, + .get_firmware_name = rt2800usb_get_firmware_name, + .check_firmware = rt2800usb_check_firmware, + .load_firmware = rt2800usb_load_firmware, + .initialize = rt2x00usb_initialize, + .uninitialize = rt2x00usb_uninitialize, + .clear_entry = rt2x00usb_clear_entry, + .set_device_state = rt2800usb_set_device_state, + .rfkill_poll = rt2800usb_rfkill_poll, + .link_stats = rt2800usb_link_stats, + .reset_tuner = rt2800usb_reset_tuner, + .link_tuner = rt2800usb_link_tuner, + .write_tx_desc = rt2800usb_write_tx_desc, + .write_tx_data = rt2x00usb_write_tx_data, + .write_beacon = rt2800usb_write_beacon, + .get_tx_data_len = rt2800usb_get_tx_data_len, + .kick_tx_queue = rt2800usb_kick_tx_queue, + .kill_tx_queue = rt2x00usb_kill_tx_queue, + .fill_rxdone = rt2800usb_fill_rxdone, + .config_shared_key = rt2800usb_config_shared_key, + .config_pairwise_key = rt2800usb_config_pairwise_key, + .config_filter = rt2800usb_config_filter, + .config_intf = rt2800usb_config_intf, + .config_erp = rt2800usb_config_erp, + .config_ant = rt2800usb_config_ant, + .config = rt2800usb_config, +}; + +static const struct data_queue_desc rt2800usb_queue_rx = { + .entry_num = RX_ENTRIES, + .data_size = AGGREGATION_SIZE, + .desc_size = RXD_DESC_SIZE + RXWI_DESC_SIZE, + .priv_size = sizeof(struct queue_entry_priv_usb), +}; + +static const struct data_queue_desc rt2800usb_queue_tx = { + .entry_num = TX_ENTRIES, + .data_size = AGGREGATION_SIZE, + .desc_size = TXINFO_DESC_SIZE + TXWI_DESC_SIZE, + .priv_size = sizeof(struct queue_entry_priv_usb), +}; + +static const struct data_queue_desc rt2800usb_queue_bcn = { + .entry_num = 8 * BEACON_ENTRIES, + .data_size = MGMT_FRAME_SIZE, + .desc_size = TXINFO_DESC_SIZE + TXWI_DESC_SIZE, + .priv_size = sizeof(struct queue_entry_priv_usb), +}; + +static const struct rt2x00_ops rt2800usb_ops = { + .name = KBUILD_MODNAME, + .max_sta_intf = 1, + .max_ap_intf = 8, + .eeprom_size = EEPROM_SIZE, + .rf_size = RF_SIZE, + .tx_queues = NUM_TX_QUEUES, + .rx = &rt2800usb_queue_rx, + .tx = &rt2800usb_queue_tx, + .bcn = &rt2800usb_queue_bcn, + .lib = &rt2800usb_rt2x00_ops, + .hw = &rt2800usb_mac80211_ops, +#ifdef CONFIG_RT2X00_LIB_DEBUGFS + .debugfs = &rt2800usb_rt2x00debug, +#endif /* CONFIG_RT2X00_LIB_DEBUGFS */ +}; + +/* + * rt2800usb module information. + */ +static struct usb_device_id rt2800usb_device_table[] = { + /* Abocom */ + { USB_DEVICE(0x07b8, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07b8, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07b8, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07b8, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07b8, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1482, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* AirTies */ + { USB_DEVICE(0x1eda, 0x2310), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Amigo */ + { USB_DEVICE(0x0e0b, 0x9031), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0e0b, 0x9041), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Amit */ + { USB_DEVICE(0x15c5, 0x0008), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* ASUS */ + { USB_DEVICE(0x0b05, 0x1731), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0b05, 0x1732), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0b05, 0x1742), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0b05, 0x1760), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0b05, 0x1761), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* AzureWave */ + { USB_DEVICE(0x13d3, 0x3247), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x13d3, 0x3262), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x13d3, 0x3273), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x13d3, 0x3284), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Belkin */ + { USB_DEVICE(0x050d, 0x8053), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x050d, 0x805c), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x050d, 0x815c), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x050d, 0x825a), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Buffalo */ + { USB_DEVICE(0x0411, 0x00e8), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0411, 0x012e), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Conceptronic */ + { USB_DEVICE(0x14b2, 0x3c06), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x14b2, 0x3c07), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x14b2, 0x3c08), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x14b2, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x14b2, 0x3c11), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x14b2, 0x3c12), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x14b2, 0x3c23), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x14b2, 0x3c25), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x14b2, 0x3c27), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x14b2, 0x3c28), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Corega */ + { USB_DEVICE(0x07aa, 0x002f), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07aa, 0x003c), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07aa, 0x003f), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x18c5, 0x0008), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x18c5, 0x0012), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* D-Link */ + { USB_DEVICE(0x07d1, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07d1, 0x3c0a), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07d1, 0x3c0b), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07d1, 0x3c0d), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07d1, 0x3c0e), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07d1, 0x3c0f), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07d1, 0x3c11), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07d1, 0x3c13), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Edimax */ + { USB_DEVICE(0x7392, 0x7711), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x7392, 0x7717), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x7392, 0x7718), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Encore */ + { USB_DEVICE(0x203d, 0x1480), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* EnGenius */ + { USB_DEVICE(0X1740, 0x9701), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1740, 0x9702), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1740, 0x9703), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1740, 0x9705), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1740, 0x9706), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1740, 0x9801), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Gemtek */ + { USB_DEVICE(0x15a9, 0x0010), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Gigabyte */ + { USB_DEVICE(0x1044, 0x800b), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1044, 0x800c), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1044, 0x800d), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Hawking */ + { USB_DEVICE(0x0e66, 0x0001), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0e66, 0x0003), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0e66, 0x0009), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0e66, 0x000b), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* I-O DATA */ + { USB_DEVICE(0x04bb, 0x0945), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* LevelOne */ + { USB_DEVICE(0x1740, 0x0605), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1740, 0x0615), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Linksys */ + { USB_DEVICE(0x1737, 0x0070), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1737, 0x0071), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1737, 0x0077), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Logitec */ + { USB_DEVICE(0x0789, 0x0162), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0789, 0x0163), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0789, 0x0164), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Motorola */ + { USB_DEVICE(0x100d, 0x9031), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x100d, 0x9032), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Ovislink */ + { USB_DEVICE(0x1b75, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Pegatron */ + { USB_DEVICE(0x1d4d, 0x0002), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1d4d, 0x000c), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1d4d, 0x000e), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Philips */ + { USB_DEVICE(0x0471, 0x200f), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Planex */ + { USB_DEVICE(0x2019, 0xed06), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x2019, 0xab24), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x2019, 0xab25), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Qcom */ + { USB_DEVICE(0x18e8, 0x6259), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Quanta */ + { USB_DEVICE(0x1a32, 0x0304), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Ralink */ + { USB_DEVICE(0x0db0, 0x3820), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0db0, 0x6899), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x148f, 0x2070), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x148f, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x148f, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x148f, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x148f, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x148f, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x148f, 0x3572), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Samsung */ + { USB_DEVICE(0x04e8, 0x2018), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Siemens */ + { USB_DEVICE(0x129b, 0x1828), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Sitecom */ + { USB_DEVICE(0x0df6, 0x0017), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x002b), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x002c), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x002d), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x0039), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x003b), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x003c), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x003d), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x003e), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x003f), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x0040), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x0042), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* SMC */ + { USB_DEVICE(0x083a, 0x6618), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x083a, 0x7511), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x083a, 0x7512), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x083a, 0x7522), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x083a, 0x8522), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x083a, 0xa512), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x083a, 0xa618), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x083a, 0xb522), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x083a, 0xc522), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Sparklan */ + { USB_DEVICE(0x15a9, 0x0006), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Sweex */ + { USB_DEVICE(0x177f, 0x0153), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x177f, 0x0302), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x177f, 0x0313), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* U-Media*/ + { USB_DEVICE(0x157e, 0x300e), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* ZCOM */ + { USB_DEVICE(0x0cde, 0x0022), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0cde, 0x0025), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Zinwell */ + { USB_DEVICE(0x5a57, 0x0280), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x5a57, 0x0282), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x5a57, 0x0283), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x5a57, 0x5257), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Zyxel */ + { USB_DEVICE(0x0586, 0x3416), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0586, 0x341a), USB_DEVICE_DATA(&rt2800usb_ops) }, + { 0, } +}; + +MODULE_AUTHOR(DRV_PROJECT); +MODULE_VERSION(DRV_VERSION); +MODULE_DESCRIPTION("Ralink RT2800 USB Wireless LAN driver."); +MODULE_SUPPORTED_DEVICE("Ralink RT2870 USB chipset based cards"); +MODULE_DEVICE_TABLE(usb, rt2800usb_device_table); +MODULE_FIRMWARE(FIRMWARE_RT2870); +MODULE_LICENSE("GPL"); + +static struct usb_driver rt2800usb_driver = { + .name = KBUILD_MODNAME, + .id_table = rt2800usb_device_table, + .probe = rt2x00usb_probe, + .disconnect = rt2x00usb_disconnect, + .suspend = rt2x00usb_suspend, + .resume = rt2x00usb_resume, +}; + +static int __init rt2800usb_init(void) +{ + return usb_register(&rt2800usb_driver); +} + +static void __exit rt2800usb_exit(void) +{ + usb_deregister(&rt2800usb_driver); +} + +module_init(rt2800usb_init); +module_exit(rt2800usb_exit); diff --git a/drivers/net/wireless/rt2x00/rt2800usb.h b/drivers/net/wireless/rt2x00/rt2800usb.h new file mode 100644 index 000000000000..61a8be61d3f5 --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2800usb.h @@ -0,0 +1,1945 @@ +/* + Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the + Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + Module: rt2800usb + Abstract: Data structures and registers for the rt2800usb module. + Supported chipsets: RT2800U. + */ + +#ifndef RT2800USB_H +#define RT2800USB_H + +/* + * RF chip defines. + * + * RF2820 2.4G 2T3R + * RF2850 2.4G/5G 2T3R + * RF2720 2.4G 1T2R + * RF2750 2.4G/5G 1T2R + * RF3020 2.4G 1T1R + * RF2020 2.4G B/G + */ +#define RF2820 0x0001 +#define RF2850 0x0002 +#define RF2720 0x0003 +#define RF2750 0x0004 +#define RF3020 0x0005 +#define RF2020 0x0006 + +/* + * RT2870 version + */ +#define RT2860C_VERSION 0x28600100 +#define RT2860D_VERSION 0x28600101 +#define RT2880E_VERSION 0x28720200 +#define RT2883_VERSION 0x28830300 +#define RT3070_VERSION 0x30700200 + +/* + * Signal information. + * Defaul offset is required for RSSI <-> dBm conversion. + */ +#define DEFAULT_RSSI_OFFSET 120 /* FIXME */ + +/* + * Register layout information. + */ +#define CSR_REG_BASE 0x1000 +#define CSR_REG_SIZE 0x0800 +#define EEPROM_BASE 0x0000 +#define EEPROM_SIZE 0x0110 +#define BBP_BASE 0x0000 +#define BBP_SIZE 0x0080 +#define RF_BASE 0x0004 +#define RF_SIZE 0x0010 + +/* + * Number of TX queues. + */ +#define NUM_TX_QUEUES 4 + +/* + * USB registers. + */ + +/* + * HOST-MCU shared memory + */ +#define HOST_CMD_CSR 0x0404 +#define HOST_CMD_CSR_HOST_COMMAND FIELD32(0x000000ff) + +/* + * INT_SOURCE_CSR: Interrupt source register. + * Write one to clear corresponding bit. + * TX_FIFO_STATUS: FIFO Statistics is full, sw should read 0x171c + */ +#define INT_SOURCE_CSR 0x0200 +#define INT_SOURCE_CSR_RXDELAYINT FIELD32(0x00000001) +#define INT_SOURCE_CSR_TXDELAYINT FIELD32(0x00000002) +#define INT_SOURCE_CSR_RX_DONE FIELD32(0x00000004) +#define INT_SOURCE_CSR_AC0_DMA_DONE FIELD32(0x00000008) +#define INT_SOURCE_CSR_AC1_DMA_DONE FIELD32(0x00000010) +#define INT_SOURCE_CSR_AC2_DMA_DONE FIELD32(0x00000020) +#define INT_SOURCE_CSR_AC3_DMA_DONE FIELD32(0x00000040) +#define INT_SOURCE_CSR_HCCA_DMA_DONE FIELD32(0x00000080) +#define INT_SOURCE_CSR_MGMT_DMA_DONE FIELD32(0x00000100) +#define INT_SOURCE_CSR_MCU_COMMAND FIELD32(0x00000200) +#define INT_SOURCE_CSR_RXTX_COHERENT FIELD32(0x00000400) +#define INT_SOURCE_CSR_TBTT FIELD32(0x00000800) +#define INT_SOURCE_CSR_PRE_TBTT FIELD32(0x00001000) +#define INT_SOURCE_CSR_TX_FIFO_STATUS FIELD32(0x00002000) +#define INT_SOURCE_CSR_AUTO_WAKEUP FIELD32(0x00004000) +#define INT_SOURCE_CSR_GPTIMER FIELD32(0x00008000) +#define INT_SOURCE_CSR_RX_COHERENT FIELD32(0x00010000) +#define INT_SOURCE_CSR_TX_COHERENT FIELD32(0x00020000) + +/* + * INT_MASK_CSR: Interrupt MASK register. 1: the interrupt is mask OFF. + */ +#define INT_MASK_CSR 0x0204 +#define INT_MASK_CSR_RXDELAYINT FIELD32(0x00000001) +#define INT_MASK_CSR_TXDELAYINT FIELD32(0x00000002) +#define INT_MASK_CSR_RX_DONE FIELD32(0x00000004) +#define INT_MASK_CSR_AC0_DMA_DONE FIELD32(0x00000008) +#define INT_MASK_CSR_AC1_DMA_DONE FIELD32(0x00000010) +#define INT_MASK_CSR_AC2_DMA_DONE FIELD32(0x00000020) +#define INT_MASK_CSR_AC3_DMA_DONE FIELD32(0x00000040) +#define INT_MASK_CSR_HCCA_DMA_DONE FIELD32(0x00000080) +#define INT_MASK_CSR_MGMT_DMA_DONE FIELD32(0x00000100) +#define INT_MASK_CSR_MCU_COMMAND FIELD32(0x00000200) +#define INT_MASK_CSR_RXTX_COHERENT FIELD32(0x00000400) +#define INT_MASK_CSR_TBTT FIELD32(0x00000800) +#define INT_MASK_CSR_PRE_TBTT FIELD32(0x00001000) +#define INT_MASK_CSR_TX_FIFO_STATUS FIELD32(0x00002000) +#define INT_MASK_CSR_AUTO_WAKEUP FIELD32(0x00004000) +#define INT_MASK_CSR_GPTIMER FIELD32(0x00008000) +#define INT_MASK_CSR_RX_COHERENT FIELD32(0x00010000) +#define INT_MASK_CSR_TX_COHERENT FIELD32(0x00020000) + +/* + * WPDMA_GLO_CFG + */ +#define WPDMA_GLO_CFG 0x0208 +#define WPDMA_GLO_CFG_ENABLE_TX_DMA FIELD32(0x00000001) +#define WPDMA_GLO_CFG_TX_DMA_BUSY FIELD32(0x00000002) +#define WPDMA_GLO_CFG_ENABLE_RX_DMA FIELD32(0x00000004) +#define WPDMA_GLO_CFG_RX_DMA_BUSY FIELD32(0x00000008) +#define WPDMA_GLO_CFG_WP_DMA_BURST_SIZE FIELD32(0x00000030) +#define WPDMA_GLO_CFG_TX_WRITEBACK_DONE FIELD32(0x00000040) +#define WPDMA_GLO_CFG_BIG_ENDIAN FIELD32(0x00000080) +#define WPDMA_GLO_CFG_RX_HDR_SCATTER FIELD32(0x0000ff00) +#define WPDMA_GLO_CFG_HDR_SEG_LEN FIELD32(0xffff0000) + +/* + * WPDMA_RST_IDX + */ +#define WPDMA_RST_IDX 0x020c +#define WPDMA_RST_IDX_DTX_IDX0 FIELD32(0x00000001) +#define WPDMA_RST_IDX_DTX_IDX1 FIELD32(0x00000002) +#define WPDMA_RST_IDX_DTX_IDX2 FIELD32(0x00000004) +#define WPDMA_RST_IDX_DTX_IDX3 FIELD32(0x00000008) +#define WPDMA_RST_IDX_DTX_IDX4 FIELD32(0x00000010) +#define WPDMA_RST_IDX_DTX_IDX5 FIELD32(0x00000020) +#define WPDMA_RST_IDX_DRX_IDX0 FIELD32(0x00010000) + +/* + * DELAY_INT_CFG + */ +#define DELAY_INT_CFG 0x0210 +#define DELAY_INT_CFG_RXMAX_PTIME FIELD32(0x000000ff) +#define DELAY_INT_CFG_RXMAX_PINT FIELD32(0x00007f00) +#define DELAY_INT_CFG_RXDLY_INT_EN FIELD32(0x00008000) +#define DELAY_INT_CFG_TXMAX_PTIME FIELD32(0x00ff0000) +#define DELAY_INT_CFG_TXMAX_PINT FIELD32(0x7f000000) +#define DELAY_INT_CFG_TXDLY_INT_EN FIELD32(0x80000000) + +/* + * WMM_AIFSN_CFG: Aifsn for each EDCA AC + * AIFSN0: AC_BE + * AIFSN1: AC_BK + * AIFSN1: AC_VI + * AIFSN1: AC_VO + */ +#define WMM_AIFSN_CFG 0x0214 +#define WMM_AIFSN_CFG_AIFSN0 FIELD32(0x0000000f) +#define WMM_AIFSN_CFG_AIFSN1 FIELD32(0x000000f0) +#define WMM_AIFSN_CFG_AIFSN2 FIELD32(0x00000f00) +#define WMM_AIFSN_CFG_AIFSN3 FIELD32(0x0000f000) + +/* + * WMM_CWMIN_CSR: CWmin for each EDCA AC + * CWMIN0: AC_BE + * CWMIN1: AC_BK + * CWMIN1: AC_VI + * CWMIN1: AC_VO + */ +#define WMM_CWMIN_CFG 0x0218 +#define WMM_CWMIN_CFG_CWMIN0 FIELD32(0x0000000f) +#define WMM_CWMIN_CFG_CWMIN1 FIELD32(0x000000f0) +#define WMM_CWMIN_CFG_CWMIN2 FIELD32(0x00000f00) +#define WMM_CWMIN_CFG_CWMIN3 FIELD32(0x0000f000) + +/* + * WMM_CWMAX_CSR: CWmax for each EDCA AC + * CWMAX0: AC_BE + * CWMAX1: AC_BK + * CWMAX1: AC_VI + * CWMAX1: AC_VO + */ +#define WMM_CWMAX_CFG 0x021c +#define WMM_CWMAX_CFG_CWMAX0 FIELD32(0x0000000f) +#define WMM_CWMAX_CFG_CWMAX1 FIELD32(0x000000f0) +#define WMM_CWMAX_CFG_CWMAX2 FIELD32(0x00000f00) +#define WMM_CWMAX_CFG_CWMAX3 FIELD32(0x0000f000) + +/* + * AC_TXOP0: AC_BK/AC_BE TXOP register + * AC0TXOP: AC_BK in unit of 32us + * AC1TXOP: AC_BE in unit of 32us + */ +#define WMM_TXOP0_CFG 0x0220 +#define WMM_TXOP0_CFG_AC0TXOP FIELD32(0x0000ffff) +#define WMM_TXOP0_CFG_AC1TXOP FIELD32(0xffff0000) + +/* + * AC_TXOP1: AC_VO/AC_VI TXOP register + * AC2TXOP: AC_VI in unit of 32us + * AC3TXOP: AC_VO in unit of 32us + */ +#define WMM_TXOP1_CFG 0x0224 +#define WMM_TXOP1_CFG_AC2TXOP FIELD32(0x0000ffff) +#define WMM_TXOP1_CFG_AC3TXOP FIELD32(0xffff0000) + +/* + * GPIO_CTRL_CFG: + */ +#define GPIO_CTRL_CFG 0x0228 +#define GPIO_CTRL_CFG_BIT0 FIELD32(0x00000001) +#define GPIO_CTRL_CFG_BIT1 FIELD32(0x00000002) +#define GPIO_CTRL_CFG_BIT2 FIELD32(0x00000004) +#define GPIO_CTRL_CFG_BIT3 FIELD32(0x00000008) +#define GPIO_CTRL_CFG_BIT4 FIELD32(0x00000010) +#define GPIO_CTRL_CFG_BIT5 FIELD32(0x00000020) +#define GPIO_CTRL_CFG_BIT6 FIELD32(0x00000040) +#define GPIO_CTRL_CFG_BIT7 FIELD32(0x00000080) +#define GPIO_CTRL_CFG_BIT8 FIELD32(0x00000100) + +/* + * MCU_CMD_CFG + */ +#define MCU_CMD_CFG 0x022c + +/* + * AC_BK register offsets + */ +#define TX_BASE_PTR0 0x0230 +#define TX_MAX_CNT0 0x0234 +#define TX_CTX_IDX0 0x0238 +#define TX_DTX_IDX0 0x023c + +/* + * AC_BE register offsets + */ +#define TX_BASE_PTR1 0x0240 +#define TX_MAX_CNT1 0x0244 +#define TX_CTX_IDX1 0x0248 +#define TX_DTX_IDX1 0x024c + +/* + * AC_VI register offsets + */ +#define TX_BASE_PTR2 0x0250 +#define TX_MAX_CNT2 0x0254 +#define TX_CTX_IDX2 0x0258 +#define TX_DTX_IDX2 0x025c + +/* + * AC_VO register offsets + */ +#define TX_BASE_PTR3 0x0260 +#define TX_MAX_CNT3 0x0264 +#define TX_CTX_IDX3 0x0268 +#define TX_DTX_IDX3 0x026c + +/* + * HCCA register offsets + */ +#define TX_BASE_PTR4 0x0270 +#define TX_MAX_CNT4 0x0274 +#define TX_CTX_IDX4 0x0278 +#define TX_DTX_IDX4 0x027c + +/* + * MGMT register offsets + */ +#define TX_BASE_PTR5 0x0280 +#define TX_MAX_CNT5 0x0284 +#define TX_CTX_IDX5 0x0288 +#define TX_DTX_IDX5 0x028c + +/* + * RX register offsets + */ +#define RX_BASE_PTR 0x0290 +#define RX_MAX_CNT 0x0294 +#define RX_CRX_IDX 0x0298 +#define RX_DRX_IDX 0x029c + +/* + * USB_DMA_CFG + * RX_BULK_AGG_TIMEOUT: Rx Bulk Aggregation TimeOut in unit of 33ns. + * RX_BULK_AGG_LIMIT: Rx Bulk Aggregation Limit in unit of 256 bytes. + * PHY_CLEAR: phy watch dog enable. + * TX_CLEAR: Clear USB DMA TX path. + * TXOP_HALT: Halt TXOP count down when TX buffer is full. + * RX_BULK_AGG_EN: Enable Rx Bulk Aggregation. + * RX_BULK_EN: Enable USB DMA Rx. + * TX_BULK_EN: Enable USB DMA Tx. + * EP_OUT_VALID: OUT endpoint data valid. + * RX_BUSY: USB DMA RX FSM busy. + * TX_BUSY: USB DMA TX FSM busy. + */ +#define USB_DMA_CFG 0x02a0 +#define USB_DMA_CFG_RX_BULK_AGG_TIMEOUT FIELD32(0x000000ff) +#define USB_DMA_CFG_RX_BULK_AGG_LIMIT FIELD32(0x0000ff00) +#define USB_DMA_CFG_PHY_CLEAR FIELD32(0x00010000) +#define USB_DMA_CFG_TX_CLEAR FIELD32(0x00080000) +#define USB_DMA_CFG_TXOP_HALT FIELD32(0x00100000) +#define USB_DMA_CFG_RX_BULK_AGG_EN FIELD32(0x00200000) +#define USB_DMA_CFG_RX_BULK_EN FIELD32(0x00400000) +#define USB_DMA_CFG_TX_BULK_EN FIELD32(0x00800000) +#define USB_DMA_CFG_EP_OUT_VALID FIELD32(0x3f000000) +#define USB_DMA_CFG_RX_BUSY FIELD32(0x40000000) +#define USB_DMA_CFG_TX_BUSY FIELD32(0x80000000) + +/* + * USB_CYC_CFG + */ +#define USB_CYC_CFG 0x02a4 +#define USB_CYC_CFG_CLOCK_CYCLE FIELD32(0x000000ff) + +/* + * PBF_SYS_CTRL + * HOST_RAM_WRITE: enable Host program ram write selection + */ +#define PBF_SYS_CTRL 0x0400 +#define PBF_SYS_CTRL_READY FIELD32(0x00000080) +#define PBF_SYS_CTRL_HOST_RAM_WRITE FIELD32(0x00010000) + +/* + * PBF registers + * Most are for debug. Driver doesn't touch PBF register. + */ +#define PBF_CFG 0x0408 +#define PBF_MAX_PCNT 0x040c +#define PBF_CTRL 0x0410 +#define PBF_INT_STA 0x0414 +#define PBF_INT_ENA 0x0418 + +/* + * BCN_OFFSET0: + */ +#define BCN_OFFSET0 0x042c +#define BCN_OFFSET0_BCN0 FIELD32(0x000000ff) +#define BCN_OFFSET0_BCN1 FIELD32(0x0000ff00) +#define BCN_OFFSET0_BCN2 FIELD32(0x00ff0000) +#define BCN_OFFSET0_BCN3 FIELD32(0xff000000) + +/* + * BCN_OFFSET1: + */ +#define BCN_OFFSET1 0x0430 +#define BCN_OFFSET1_BCN4 FIELD32(0x000000ff) +#define BCN_OFFSET1_BCN5 FIELD32(0x0000ff00) +#define BCN_OFFSET1_BCN6 FIELD32(0x00ff0000) +#define BCN_OFFSET1_BCN7 FIELD32(0xff000000) + +/* + * PBF registers + * Most are for debug. Driver doesn't touch PBF register. + */ +#define TXRXQ_PCNT 0x0438 +#define PBF_DBG 0x043c + +/* + * RF registers + */ +#define RF_CSR_CFG 0x0500 +#define RF_CSR_CFG_DATA FIELD32(0x000000ff) +#define RF_CSR_CFG_REGNUM FIELD32(0x00001f00) +#define RF_CSR_CFG_WRITE FIELD32(0x00010000) +#define RF_CSR_CFG_BUSY FIELD32(0x00020000) + +/* + * MAC Control/Status Registers(CSR). + * Some values are set in TU, whereas 1 TU == 1024 us. + */ + +/* + * MAC_CSR0: ASIC revision number. + * ASIC_REV: 0 + * ASIC_VER: 2870 + */ +#define MAC_CSR0 0x1000 +#define MAC_CSR0_ASIC_REV FIELD32(0x0000ffff) +#define MAC_CSR0_ASIC_VER FIELD32(0xffff0000) + +/* + * MAC_SYS_CTRL: + */ +#define MAC_SYS_CTRL 0x1004 +#define MAC_SYS_CTRL_RESET_CSR FIELD32(0x00000001) +#define MAC_SYS_CTRL_RESET_BBP FIELD32(0x00000002) +#define MAC_SYS_CTRL_ENABLE_TX FIELD32(0x00000004) +#define MAC_SYS_CTRL_ENABLE_RX FIELD32(0x00000008) +#define MAC_SYS_CTRL_CONTINUOUS_TX FIELD32(0x00000010) +#define MAC_SYS_CTRL_LOOPBACK FIELD32(0x00000020) +#define MAC_SYS_CTRL_WLAN_HALT FIELD32(0x00000040) +#define MAC_SYS_CTRL_RX_TIMESTAMP FIELD32(0x00000080) + +/* + * MAC_ADDR_DW0: STA MAC register 0 + */ +#define MAC_ADDR_DW0 0x1008 +#define MAC_ADDR_DW0_BYTE0 FIELD32(0x000000ff) +#define MAC_ADDR_DW0_BYTE1 FIELD32(0x0000ff00) +#define MAC_ADDR_DW0_BYTE2 FIELD32(0x00ff0000) +#define MAC_ADDR_DW0_BYTE3 FIELD32(0xff000000) + +/* + * MAC_ADDR_DW1: STA MAC register 1 + * UNICAST_TO_ME_MASK: + * Used to mask off bits from byte 5 of the MAC address + * to determine the UNICAST_TO_ME bit for RX frames. + * The full mask is complemented by BSS_ID_MASK: + * MASK = BSS_ID_MASK & UNICAST_TO_ME_MASK + */ +#define MAC_ADDR_DW1 0x100c +#define MAC_ADDR_DW1_BYTE4 FIELD32(0x000000ff) +#define MAC_ADDR_DW1_BYTE5 FIELD32(0x0000ff00) +#define MAC_ADDR_DW1_UNICAST_TO_ME_MASK FIELD32(0x00ff0000) + +/* + * MAC_BSSID_DW0: BSSID register 0 + */ +#define MAC_BSSID_DW0 0x1010 +#define MAC_BSSID_DW0_BYTE0 FIELD32(0x000000ff) +#define MAC_BSSID_DW0_BYTE1 FIELD32(0x0000ff00) +#define MAC_BSSID_DW0_BYTE2 FIELD32(0x00ff0000) +#define MAC_BSSID_DW0_BYTE3 FIELD32(0xff000000) + +/* + * MAC_BSSID_DW1: BSSID register 1 + * BSS_ID_MASK: + * 0: 1-BSSID mode (BSS index = 0) + * 1: 2-BSSID mode (BSS index: Byte5, bit 0) + * 2: 4-BSSID mode (BSS index: byte5, bit 0 - 1) + * 3: 8-BSSID mode (BSS index: byte5, bit 0 - 2) + * This mask is used to mask off bits 0, 1 and 2 of byte 5 of the + * BSSID. This will make sure that those bits will be ignored + * when determining the MY_BSS of RX frames. + */ +#define MAC_BSSID_DW1 0x1014 +#define MAC_BSSID_DW1_BYTE4 FIELD32(0x000000ff) +#define MAC_BSSID_DW1_BYTE5 FIELD32(0x0000ff00) +#define MAC_BSSID_DW1_BSS_ID_MASK FIELD32(0x00030000) +#define MAC_BSSID_DW1_BSS_BCN_NUM FIELD32(0x001c0000) + +/* + * MAX_LEN_CFG: Maximum frame length register. + * MAX_MPDU: rt2860b max 16k bytes + * MAX_PSDU: Maximum PSDU length + * (power factor) 0:2^13, 1:2^14, 2:2^15, 3:2^16 + */ +#define MAX_LEN_CFG 0x1018 +#define MAX_LEN_CFG_MAX_MPDU FIELD32(0x00000fff) +#define MAX_LEN_CFG_MAX_PSDU FIELD32(0x00003000) +#define MAX_LEN_CFG_MIN_PSDU FIELD32(0x0000c000) +#define MAX_LEN_CFG_MIN_MPDU FIELD32(0x000f0000) + +/* + * BBP_CSR_CFG: BBP serial control register + * VALUE: Register value to program into BBP + * REG_NUM: Selected BBP register + * READ_CONTROL: 0 write BBP, 1 read BBP + * BUSY: ASIC is busy executing BBP commands + * BBP_PAR_DUR: 0 4 MAC clocks, 1 8 MAC clocks + * BBP_RW_MODE: 0 serial, 1 paralell + */ +#define BBP_CSR_CFG 0x101c +#define BBP_CSR_CFG_VALUE FIELD32(0x000000ff) +#define BBP_CSR_CFG_REGNUM FIELD32(0x0000ff00) +#define BBP_CSR_CFG_READ_CONTROL FIELD32(0x00010000) +#define BBP_CSR_CFG_BUSY FIELD32(0x00020000) +#define BBP_CSR_CFG_BBP_PAR_DUR FIELD32(0x00040000) +#define BBP_CSR_CFG_BBP_RW_MODE FIELD32(0x00080000) + +/* + * RF_CSR_CFG0: RF control register + * REGID_AND_VALUE: Register value to program into RF + * BITWIDTH: Selected RF register + * STANDBYMODE: 0 high when standby, 1 low when standby + * SEL: 0 RF_LE0 activate, 1 RF_LE1 activate + * BUSY: ASIC is busy executing RF commands + */ +#define RF_CSR_CFG0 0x1020 +#define RF_CSR_CFG0_REGID_AND_VALUE FIELD32(0x00ffffff) +#define RF_CSR_CFG0_BITWIDTH FIELD32(0x1f000000) +#define RF_CSR_CFG0_REG_VALUE_BW FIELD32(0x1fffffff) +#define RF_CSR_CFG0_STANDBYMODE FIELD32(0x20000000) +#define RF_CSR_CFG0_SEL FIELD32(0x40000000) +#define RF_CSR_CFG0_BUSY FIELD32(0x80000000) + +/* + * RF_CSR_CFG1: RF control register + * REGID_AND_VALUE: Register value to program into RF + * RFGAP: Gap between BB_CONTROL_RF and RF_LE + * 0: 3 system clock cycle (37.5usec) + * 1: 5 system clock cycle (62.5usec) + */ +#define RF_CSR_CFG1 0x1024 +#define RF_CSR_CFG1_REGID_AND_VALUE FIELD32(0x00ffffff) +#define RF_CSR_CFG1_RFGAP FIELD32(0x1f000000) + +/* + * RF_CSR_CFG2: RF control register + * VALUE: Register value to program into RF + * RFGAP: Gap between BB_CONTROL_RF and RF_LE + * 0: 3 system clock cycle (37.5usec) + * 1: 5 system clock cycle (62.5usec) + */ +#define RF_CSR_CFG2 0x1028 +#define RF_CSR_CFG2_VALUE FIELD32(0x00ffffff) + +/* + * LED_CFG: LED control + * color LED's: + * 0: off + * 1: blinking upon TX2 + * 2: periodic slow blinking + * 3: always on + * LED polarity: + * 0: active low + * 1: active high + */ +#define LED_CFG 0x102c +#define LED_CFG_ON_PERIOD FIELD32(0x000000ff) +#define LED_CFG_OFF_PERIOD FIELD32(0x0000ff00) +#define LED_CFG_SLOW_BLINK_PERIOD FIELD32(0x003f0000) +#define LED_CFG_R_LED_MODE FIELD32(0x03000000) +#define LED_CFG_G_LED_MODE FIELD32(0x0c000000) +#define LED_CFG_Y_LED_MODE FIELD32(0x30000000) +#define LED_CFG_LED_POLAR FIELD32(0x40000000) + +/* + * XIFS_TIME_CFG: MAC timing + * CCKM_SIFS_TIME: unit 1us. Applied after CCK RX/TX + * OFDM_SIFS_TIME: unit 1us. Applied after OFDM RX/TX + * OFDM_XIFS_TIME: unit 1us. Applied after OFDM RX + * when MAC doesn't reference BBP signal BBRXEND + * EIFS: unit 1us + * BB_RXEND_ENABLE: reference RXEND signal to begin XIFS defer + * + */ +#define XIFS_TIME_CFG 0x1100 +#define XIFS_TIME_CFG_CCKM_SIFS_TIME FIELD32(0x000000ff) +#define XIFS_TIME_CFG_OFDM_SIFS_TIME FIELD32(0x0000ff00) +#define XIFS_TIME_CFG_OFDM_XIFS_TIME FIELD32(0x000f0000) +#define XIFS_TIME_CFG_EIFS FIELD32(0x1ff00000) +#define XIFS_TIME_CFG_BB_RXEND_ENABLE FIELD32(0x20000000) + +/* + * BKOFF_SLOT_CFG: + */ +#define BKOFF_SLOT_CFG 0x1104 +#define BKOFF_SLOT_CFG_SLOT_TIME FIELD32(0x000000ff) +#define BKOFF_SLOT_CFG_CC_DELAY_TIME FIELD32(0x0000ff00) + +/* + * NAV_TIME_CFG: + */ +#define NAV_TIME_CFG 0x1108 +#define NAV_TIME_CFG_SIFS FIELD32(0x000000ff) +#define NAV_TIME_CFG_SLOT_TIME FIELD32(0x0000ff00) +#define NAV_TIME_CFG_EIFS FIELD32(0x01ff0000) +#define NAV_TIME_ZERO_SIFS FIELD32(0x02000000) + +/* + * CH_TIME_CFG: count as channel busy + */ +#define CH_TIME_CFG 0x110c + +/* + * PBF_LIFE_TIMER: TX/RX MPDU timestamp timer (free run) Unit: 1us + */ +#define PBF_LIFE_TIMER 0x1110 + +/* + * BCN_TIME_CFG: + * BEACON_INTERVAL: in unit of 1/16 TU + * TSF_TICKING: Enable TSF auto counting + * TSF_SYNC: Enable TSF sync, 00: disable, 01: infra mode, 10: ad-hoc mode + * BEACON_GEN: Enable beacon generator + */ +#define BCN_TIME_CFG 0x1114 +#define BCN_TIME_CFG_BEACON_INTERVAL FIELD32(0x0000ffff) +#define BCN_TIME_CFG_TSF_TICKING FIELD32(0x00010000) +#define BCN_TIME_CFG_TSF_SYNC FIELD32(0x00060000) +#define BCN_TIME_CFG_TBTT_ENABLE FIELD32(0x00080000) +#define BCN_TIME_CFG_BEACON_GEN FIELD32(0x00100000) +#define BCN_TIME_CFG_TX_TIME_COMPENSATE FIELD32(0xf0000000) + +/* + * TBTT_SYNC_CFG: + */ +#define TBTT_SYNC_CFG 0x1118 + +/* + * TSF_TIMER_DW0: Local lsb TSF timer, read-only + */ +#define TSF_TIMER_DW0 0x111c +#define TSF_TIMER_DW0_LOW_WORD FIELD32(0xffffffff) + +/* + * TSF_TIMER_DW1: Local msb TSF timer, read-only + */ +#define TSF_TIMER_DW1 0x1120 +#define TSF_TIMER_DW1_HIGH_WORD FIELD32(0xffffffff) + +/* + * TBTT_TIMER: TImer remains till next TBTT, read-only + */ +#define TBTT_TIMER 0x1124 + +/* + * INT_TIMER_CFG: + */ +#define INT_TIMER_CFG 0x1128 + +/* + * INT_TIMER_EN: GP-timer and pre-tbtt Int enable + */ +#define INT_TIMER_EN 0x112c + +/* + * CH_IDLE_STA: channel idle time + */ +#define CH_IDLE_STA 0x1130 + +/* + * CH_BUSY_STA: channel busy time + */ +#define CH_BUSY_STA 0x1134 + +/* + * MAC_STATUS_CFG: + * BBP_RF_BUSY: When set to 0, BBP and RF are stable. + * if 1 or higher one of the 2 registers is busy. + */ +#define MAC_STATUS_CFG 0x1200 +#define MAC_STATUS_CFG_BBP_RF_BUSY FIELD32(0x00000003) + +/* + * PWR_PIN_CFG: + */ +#define PWR_PIN_CFG 0x1204 + +/* + * AUTOWAKEUP_CFG: Manual power control / status register + * TBCN_BEFORE_WAKE: ForceWake has high privilege than PutToSleep when both set + * AUTOWAKE: 0:sleep, 1:awake + */ +#define AUTOWAKEUP_CFG 0x1208 +#define AUTOWAKEUP_CFG_AUTO_LEAD_TIME FIELD32(0x000000ff) +#define AUTOWAKEUP_CFG_TBCN_BEFORE_WAKE FIELD32(0x00007f00) +#define AUTOWAKEUP_CFG_AUTOWAKE FIELD32(0x00008000) + +/* + * EDCA_AC0_CFG: + */ +#define EDCA_AC0_CFG 0x1300 +#define EDCA_AC0_CFG_TX_OP FIELD32(0x000000ff) +#define EDCA_AC0_CFG_AIFSN FIELD32(0x00000f00) +#define EDCA_AC0_CFG_CWMIN FIELD32(0x0000f000) +#define EDCA_AC0_CFG_CWMAX FIELD32(0x000f0000) + +/* + * EDCA_AC1_CFG: + */ +#define EDCA_AC1_CFG 0x1304 +#define EDCA_AC1_CFG_TX_OP FIELD32(0x000000ff) +#define EDCA_AC1_CFG_AIFSN FIELD32(0x00000f00) +#define EDCA_AC1_CFG_CWMIN FIELD32(0x0000f000) +#define EDCA_AC1_CFG_CWMAX FIELD32(0x000f0000) + +/* + * EDCA_AC2_CFG: + */ +#define EDCA_AC2_CFG 0x1308 +#define EDCA_AC2_CFG_TX_OP FIELD32(0x000000ff) +#define EDCA_AC2_CFG_AIFSN FIELD32(0x00000f00) +#define EDCA_AC2_CFG_CWMIN FIELD32(0x0000f000) +#define EDCA_AC2_CFG_CWMAX FIELD32(0x000f0000) + +/* + * EDCA_AC3_CFG: + */ +#define EDCA_AC3_CFG 0x130c +#define EDCA_AC3_CFG_TX_OP FIELD32(0x000000ff) +#define EDCA_AC3_CFG_AIFSN FIELD32(0x00000f00) +#define EDCA_AC3_CFG_CWMIN FIELD32(0x0000f000) +#define EDCA_AC3_CFG_CWMAX FIELD32(0x000f0000) + +/* + * EDCA_TID_AC_MAP: + */ +#define EDCA_TID_AC_MAP 0x1310 + +/* + * TX_PWR_CFG_0: + */ +#define TX_PWR_CFG_0 0x1314 +#define TX_PWR_CFG_0_1MBS FIELD32(0x0000000f) +#define TX_PWR_CFG_0_2MBS FIELD32(0x000000f0) +#define TX_PWR_CFG_0_55MBS FIELD32(0x00000f00) +#define TX_PWR_CFG_0_11MBS FIELD32(0x0000f000) +#define TX_PWR_CFG_0_6MBS FIELD32(0x000f0000) +#define TX_PWR_CFG_0_9MBS FIELD32(0x00f00000) +#define TX_PWR_CFG_0_12MBS FIELD32(0x0f000000) +#define TX_PWR_CFG_0_18MBS FIELD32(0xf0000000) + +/* + * TX_PWR_CFG_1: + */ +#define TX_PWR_CFG_1 0x1318 +#define TX_PWR_CFG_1_24MBS FIELD32(0x0000000f) +#define TX_PWR_CFG_1_36MBS FIELD32(0x000000f0) +#define TX_PWR_CFG_1_48MBS FIELD32(0x00000f00) +#define TX_PWR_CFG_1_54MBS FIELD32(0x0000f000) +#define TX_PWR_CFG_1_MCS0 FIELD32(0x000f0000) +#define TX_PWR_CFG_1_MCS1 FIELD32(0x00f00000) +#define TX_PWR_CFG_1_MCS2 FIELD32(0x0f000000) +#define TX_PWR_CFG_1_MCS3 FIELD32(0xf0000000) + +/* + * TX_PWR_CFG_2: + */ +#define TX_PWR_CFG_2 0x131c +#define TX_PWR_CFG_2_MCS4 FIELD32(0x0000000f) +#define TX_PWR_CFG_2_MCS5 FIELD32(0x000000f0) +#define TX_PWR_CFG_2_MCS6 FIELD32(0x00000f00) +#define TX_PWR_CFG_2_MCS7 FIELD32(0x0000f000) +#define TX_PWR_CFG_2_MCS8 FIELD32(0x000f0000) +#define TX_PWR_CFG_2_MCS9 FIELD32(0x00f00000) +#define TX_PWR_CFG_2_MCS10 FIELD32(0x0f000000) +#define TX_PWR_CFG_2_MCS11 FIELD32(0xf0000000) + +/* + * TX_PWR_CFG_3: + */ +#define TX_PWR_CFG_3 0x1320 +#define TX_PWR_CFG_3_MCS12 FIELD32(0x0000000f) +#define TX_PWR_CFG_3_MCS13 FIELD32(0x000000f0) +#define TX_PWR_CFG_3_MCS14 FIELD32(0x00000f00) +#define TX_PWR_CFG_3_MCS15 FIELD32(0x0000f000) +#define TX_PWR_CFG_3_UKNOWN1 FIELD32(0x000f0000) +#define TX_PWR_CFG_3_UKNOWN2 FIELD32(0x00f00000) +#define TX_PWR_CFG_3_UKNOWN3 FIELD32(0x0f000000) +#define TX_PWR_CFG_3_UKNOWN4 FIELD32(0xf0000000) + +/* + * TX_PWR_CFG_4: + */ +#define TX_PWR_CFG_4 0x1324 +#define TX_PWR_CFG_4_UKNOWN5 FIELD32(0x0000000f) +#define TX_PWR_CFG_4_UKNOWN6 FIELD32(0x000000f0) +#define TX_PWR_CFG_4_UKNOWN7 FIELD32(0x00000f00) +#define TX_PWR_CFG_4_UKNOWN8 FIELD32(0x0000f000) + +/* + * TX_PIN_CFG: + */ +#define TX_PIN_CFG 0x1328 +#define TX_PIN_CFG_PA_PE_A0_EN FIELD32(0x00000001) +#define TX_PIN_CFG_PA_PE_G0_EN FIELD32(0x00000002) +#define TX_PIN_CFG_PA_PE_A1_EN FIELD32(0x00000004) +#define TX_PIN_CFG_PA_PE_G1_EN FIELD32(0x00000008) +#define TX_PIN_CFG_PA_PE_A0_POL FIELD32(0x00000010) +#define TX_PIN_CFG_PA_PE_G0_POL FIELD32(0x00000020) +#define TX_PIN_CFG_PA_PE_A1_POL FIELD32(0x00000040) +#define TX_PIN_CFG_PA_PE_G1_POL FIELD32(0x00000080) +#define TX_PIN_CFG_LNA_PE_A0_EN FIELD32(0x00000100) +#define TX_PIN_CFG_LNA_PE_G0_EN FIELD32(0x00000200) +#define TX_PIN_CFG_LNA_PE_A1_EN FIELD32(0x00000400) +#define TX_PIN_CFG_LNA_PE_G1_EN FIELD32(0x00000800) +#define TX_PIN_CFG_LNA_PE_A0_POL FIELD32(0x00001000) +#define TX_PIN_CFG_LNA_PE_G0_POL FIELD32(0x00002000) +#define TX_PIN_CFG_LNA_PE_A1_POL FIELD32(0x00004000) +#define TX_PIN_CFG_LNA_PE_G1_POL FIELD32(0x00008000) +#define TX_PIN_CFG_RFTR_EN FIELD32(0x00010000) +#define TX_PIN_CFG_RFTR_POL FIELD32(0x00020000) +#define TX_PIN_CFG_TRSW_EN FIELD32(0x00040000) +#define TX_PIN_CFG_TRSW_POL FIELD32(0x00080000) + +/* + * TX_BAND_CFG: 0x1 use upper 20MHz, 0x0 use lower 20MHz + */ +#define TX_BAND_CFG 0x132c +#define TX_BAND_CFG_HT40_PLUS FIELD32(0x00000001) +#define TX_BAND_CFG_A FIELD32(0x00000002) +#define TX_BAND_CFG_BG FIELD32(0x00000004) + +/* + * TX_SW_CFG0: + */ +#define TX_SW_CFG0 0x1330 + +/* + * TX_SW_CFG1: + */ +#define TX_SW_CFG1 0x1334 + +/* + * TX_SW_CFG2: + */ +#define TX_SW_CFG2 0x1338 + +/* + * TXOP_THRES_CFG: + */ +#define TXOP_THRES_CFG 0x133c + +/* + * TXOP_CTRL_CFG: + */ +#define TXOP_CTRL_CFG 0x1340 + +/* + * TX_RTS_CFG: + * RTS_THRES: unit:byte + * RTS_FBK_EN: enable rts rate fallback + */ +#define TX_RTS_CFG 0x1344 +#define TX_RTS_CFG_AUTO_RTS_RETRY_LIMIT FIELD32(0x000000ff) +#define TX_RTS_CFG_RTS_THRES FIELD32(0x00ffff00) +#define TX_RTS_CFG_RTS_FBK_EN FIELD32(0x01000000) + +/* + * TX_TIMEOUT_CFG: + * MPDU_LIFETIME: expiration time = 2^(9+MPDU LIFE TIME) us + * RX_ACK_TIMEOUT: unit:slot. Used for TX procedure + * TX_OP_TIMEOUT: TXOP timeout value for TXOP truncation. + * it is recommended that: + * (SLOT_TIME) > (TX_OP_TIMEOUT) > (RX_ACK_TIMEOUT) + */ +#define TX_TIMEOUT_CFG 0x1348 +#define TX_TIMEOUT_CFG_MPDU_LIFETIME FIELD32(0x000000f0) +#define TX_TIMEOUT_CFG_RX_ACK_TIMEOUT FIELD32(0x0000ff00) +#define TX_TIMEOUT_CFG_TX_OP_TIMEOUT FIELD32(0x00ff0000) + +/* + * TX_RTY_CFG: + * SHORT_RTY_LIMIT: short retry limit + * LONG_RTY_LIMIT: long retry limit + * LONG_RTY_THRE: Long retry threshoold + * NON_AGG_RTY_MODE: Non-Aggregate MPDU retry mode + * 0:expired by retry limit, 1: expired by mpdu life timer + * AGG_RTY_MODE: Aggregate MPDU retry mode + * 0:expired by retry limit, 1: expired by mpdu life timer + * TX_AUTO_FB_ENABLE: Tx retry PHY rate auto fallback enable + */ +#define TX_RTY_CFG 0x134c +#define TX_RTY_CFG_SHORT_RTY_LIMIT FIELD32(0x000000ff) +#define TX_RTY_CFG_LONG_RTY_LIMIT FIELD32(0x0000ff00) +#define TX_RTY_CFG_LONG_RTY_THRE FIELD32(0x0fff0000) +#define TX_RTY_CFG_NON_AGG_RTY_MODE FIELD32(0x10000000) +#define TX_RTY_CFG_AGG_RTY_MODE FIELD32(0x20000000) +#define TX_RTY_CFG_TX_AUTO_FB_ENABLE FIELD32(0x40000000) + +/* + * TX_LINK_CFG: + * REMOTE_MFB_LIFETIME: remote MFB life time. unit: 32us + * MFB_ENABLE: TX apply remote MFB 1:enable + * REMOTE_UMFS_ENABLE: remote unsolicit MFB enable + * 0: not apply remote remote unsolicit (MFS=7) + * TX_MRQ_EN: MCS request TX enable + * TX_RDG_EN: RDG TX enable + * TX_CF_ACK_EN: Piggyback CF-ACK enable + * REMOTE_MFB: remote MCS feedback + * REMOTE_MFS: remote MCS feedback sequence number + */ +#define TX_LINK_CFG 0x1350 +#define TX_LINK_CFG_REMOTE_MFB_LIFETIME FIELD32(0x000000ff) +#define TX_LINK_CFG_MFB_ENABLE FIELD32(0x00000100) +#define TX_LINK_CFG_REMOTE_UMFS_ENABLE FIELD32(0x00000200) +#define TX_LINK_CFG_TX_MRQ_EN FIELD32(0x00000400) +#define TX_LINK_CFG_TX_RDG_EN FIELD32(0x00000800) +#define TX_LINK_CFG_TX_CF_ACK_EN FIELD32(0x00001000) +#define TX_LINK_CFG_REMOTE_MFB FIELD32(0x00ff0000) +#define TX_LINK_CFG_REMOTE_MFS FIELD32(0xff000000) + +/* + * HT_FBK_CFG0: + */ +#define HT_FBK_CFG0 0x1354 +#define HT_FBK_CFG0_HTMCS0FBK FIELD32(0x0000000f) +#define HT_FBK_CFG0_HTMCS1FBK FIELD32(0x000000f0) +#define HT_FBK_CFG0_HTMCS2FBK FIELD32(0x00000f00) +#define HT_FBK_CFG0_HTMCS3FBK FIELD32(0x0000f000) +#define HT_FBK_CFG0_HTMCS4FBK FIELD32(0x000f0000) +#define HT_FBK_CFG0_HTMCS5FBK FIELD32(0x00f00000) +#define HT_FBK_CFG0_HTMCS6FBK FIELD32(0x0f000000) +#define HT_FBK_CFG0_HTMCS7FBK FIELD32(0xf0000000) + +/* + * HT_FBK_CFG1: + */ +#define HT_FBK_CFG1 0x1358 +#define HT_FBK_CFG1_HTMCS8FBK FIELD32(0x0000000f) +#define HT_FBK_CFG1_HTMCS9FBK FIELD32(0x000000f0) +#define HT_FBK_CFG1_HTMCS10FBK FIELD32(0x00000f00) +#define HT_FBK_CFG1_HTMCS11FBK FIELD32(0x0000f000) +#define HT_FBK_CFG1_HTMCS12FBK FIELD32(0x000f0000) +#define HT_FBK_CFG1_HTMCS13FBK FIELD32(0x00f00000) +#define HT_FBK_CFG1_HTMCS14FBK FIELD32(0x0f000000) +#define HT_FBK_CFG1_HTMCS15FBK FIELD32(0xf0000000) + +/* + * LG_FBK_CFG0: + */ +#define LG_FBK_CFG0 0x135c +#define LG_FBK_CFG0_OFDMMCS0FBK FIELD32(0x0000000f) +#define LG_FBK_CFG0_OFDMMCS1FBK FIELD32(0x000000f0) +#define LG_FBK_CFG0_OFDMMCS2FBK FIELD32(0x00000f00) +#define LG_FBK_CFG0_OFDMMCS3FBK FIELD32(0x0000f000) +#define LG_FBK_CFG0_OFDMMCS4FBK FIELD32(0x000f0000) +#define LG_FBK_CFG0_OFDMMCS5FBK FIELD32(0x00f00000) +#define LG_FBK_CFG0_OFDMMCS6FBK FIELD32(0x0f000000) +#define LG_FBK_CFG0_OFDMMCS7FBK FIELD32(0xf0000000) + +/* + * LG_FBK_CFG1: + */ +#define LG_FBK_CFG1 0x1360 +#define LG_FBK_CFG0_CCKMCS0FBK FIELD32(0x0000000f) +#define LG_FBK_CFG0_CCKMCS1FBK FIELD32(0x000000f0) +#define LG_FBK_CFG0_CCKMCS2FBK FIELD32(0x00000f00) +#define LG_FBK_CFG0_CCKMCS3FBK FIELD32(0x0000f000) + +/* + * CCK_PROT_CFG: CCK Protection + * PROTECT_RATE: Protection control frame rate for CCK TX(RTS/CTS/CFEnd) + * PROTECT_CTRL: Protection control frame type for CCK TX + * 0:none, 1:RTS/CTS, 2:CTS-to-self + * PROTECT_NAV: TXOP protection type for CCK TX + * 0:none, 1:ShortNAVprotect, 2:LongNAVProtect + * TX_OP_ALLOW_CCK: CCK TXOP allowance, 0:disallow + * TX_OP_ALLOW_OFDM: CCK TXOP allowance, 0:disallow + * TX_OP_ALLOW_MM20: CCK TXOP allowance, 0:disallow + * TX_OP_ALLOW_MM40: CCK TXOP allowance, 0:disallow + * TX_OP_ALLOW_GF20: CCK TXOP allowance, 0:disallow + * TX_OP_ALLOW_GF40: CCK TXOP allowance, 0:disallow + * RTS_TH_EN: RTS threshold enable on CCK TX + */ +#define CCK_PROT_CFG 0x1364 +#define CCK_PROT_CFG_PROTECT_RATE FIELD32(0x0000ffff) +#define CCK_PROT_CFG_PROTECT_CTRL FIELD32(0x00030000) +#define CCK_PROT_CFG_PROTECT_NAV FIELD32(0x000c0000) +#define CCK_PROT_CFG_TX_OP_ALLOW_CCK FIELD32(0x00100000) +#define CCK_PROT_CFG_TX_OP_ALLOW_OFDM FIELD32(0x00200000) +#define CCK_PROT_CFG_TX_OP_ALLOW_MM20 FIELD32(0x00400000) +#define CCK_PROT_CFG_TX_OP_ALLOW_MM40 FIELD32(0x00800000) +#define CCK_PROT_CFG_TX_OP_ALLOW_GF20 FIELD32(0x01000000) +#define CCK_PROT_CFG_TX_OP_ALLOW_GF40 FIELD32(0x02000000) +#define CCK_PROT_CFG_RTS_TH_EN FIELD32(0x04000000) + +/* + * OFDM_PROT_CFG: OFDM Protection + */ +#define OFDM_PROT_CFG 0x1368 +#define OFDM_PROT_CFG_PROTECT_RATE FIELD32(0x0000ffff) +#define OFDM_PROT_CFG_PROTECT_CTRL FIELD32(0x00030000) +#define OFDM_PROT_CFG_PROTECT_NAV FIELD32(0x000c0000) +#define OFDM_PROT_CFG_TX_OP_ALLOW_CCK FIELD32(0x00100000) +#define OFDM_PROT_CFG_TX_OP_ALLOW_OFDM FIELD32(0x00200000) +#define OFDM_PROT_CFG_TX_OP_ALLOW_MM20 FIELD32(0x00400000) +#define OFDM_PROT_CFG_TX_OP_ALLOW_MM40 FIELD32(0x00800000) +#define OFDM_PROT_CFG_TX_OP_ALLOW_GF20 FIELD32(0x01000000) +#define OFDM_PROT_CFG_TX_OP_ALLOW_GF40 FIELD32(0x02000000) +#define OFDM_PROT_CFG_RTS_TH_EN FIELD32(0x04000000) + +/* + * MM20_PROT_CFG: MM20 Protection + */ +#define MM20_PROT_CFG 0x136c +#define MM20_PROT_CFG_PROTECT_RATE FIELD32(0x0000ffff) +#define MM20_PROT_CFG_PROTECT_CTRL FIELD32(0x00030000) +#define MM20_PROT_CFG_PROTECT_NAV FIELD32(0x000c0000) +#define MM20_PROT_CFG_TX_OP_ALLOW_CCK FIELD32(0x00100000) +#define MM20_PROT_CFG_TX_OP_ALLOW_OFDM FIELD32(0x00200000) +#define MM20_PROT_CFG_TX_OP_ALLOW_MM20 FIELD32(0x00400000) +#define MM20_PROT_CFG_TX_OP_ALLOW_MM40 FIELD32(0x00800000) +#define MM20_PROT_CFG_TX_OP_ALLOW_GF20 FIELD32(0x01000000) +#define MM20_PROT_CFG_TX_OP_ALLOW_GF40 FIELD32(0x02000000) +#define MM20_PROT_CFG_RTS_TH_EN FIELD32(0x04000000) + +/* + * MM40_PROT_CFG: MM40 Protection + */ +#define MM40_PROT_CFG 0x1370 +#define MM40_PROT_CFG_PROTECT_RATE FIELD32(0x0000ffff) +#define MM40_PROT_CFG_PROTECT_CTRL FIELD32(0x00030000) +#define MM40_PROT_CFG_PROTECT_NAV FIELD32(0x000c0000) +#define MM40_PROT_CFG_TX_OP_ALLOW_CCK FIELD32(0x00100000) +#define MM40_PROT_CFG_TX_OP_ALLOW_OFDM FIELD32(0x00200000) +#define MM40_PROT_CFG_TX_OP_ALLOW_MM20 FIELD32(0x00400000) +#define MM40_PROT_CFG_TX_OP_ALLOW_MM40 FIELD32(0x00800000) +#define MM40_PROT_CFG_TX_OP_ALLOW_GF20 FIELD32(0x01000000) +#define MM40_PROT_CFG_TX_OP_ALLOW_GF40 FIELD32(0x02000000) +#define MM40_PROT_CFG_RTS_TH_EN FIELD32(0x04000000) + +/* + * GF20_PROT_CFG: GF20 Protection + */ +#define GF20_PROT_CFG 0x1374 +#define GF20_PROT_CFG_PROTECT_RATE FIELD32(0x0000ffff) +#define GF20_PROT_CFG_PROTECT_CTRL FIELD32(0x00030000) +#define GF20_PROT_CFG_PROTECT_NAV FIELD32(0x000c0000) +#define GF20_PROT_CFG_TX_OP_ALLOW_CCK FIELD32(0x00100000) +#define GF20_PROT_CFG_TX_OP_ALLOW_OFDM FIELD32(0x00200000) +#define GF20_PROT_CFG_TX_OP_ALLOW_MM20 FIELD32(0x00400000) +#define GF20_PROT_CFG_TX_OP_ALLOW_MM40 FIELD32(0x00800000) +#define GF20_PROT_CFG_TX_OP_ALLOW_GF20 FIELD32(0x01000000) +#define GF20_PROT_CFG_TX_OP_ALLOW_GF40 FIELD32(0x02000000) +#define GF20_PROT_CFG_RTS_TH_EN FIELD32(0x04000000) + +/* + * GF40_PROT_CFG: GF40 Protection + */ +#define GF40_PROT_CFG 0x1378 +#define GF40_PROT_CFG_PROTECT_RATE FIELD32(0x0000ffff) +#define GF40_PROT_CFG_PROTECT_CTRL FIELD32(0x00030000) +#define GF40_PROT_CFG_PROTECT_NAV FIELD32(0x000c0000) +#define GF40_PROT_CFG_TX_OP_ALLOW_CCK FIELD32(0x00100000) +#define GF40_PROT_CFG_TX_OP_ALLOW_OFDM FIELD32(0x00200000) +#define GF40_PROT_CFG_TX_OP_ALLOW_MM20 FIELD32(0x00400000) +#define GF40_PROT_CFG_TX_OP_ALLOW_MM40 FIELD32(0x00800000) +#define GF40_PROT_CFG_TX_OP_ALLOW_GF20 FIELD32(0x01000000) +#define GF40_PROT_CFG_TX_OP_ALLOW_GF40 FIELD32(0x02000000) +#define GF40_PROT_CFG_RTS_TH_EN FIELD32(0x04000000) + +/* + * EXP_CTS_TIME: + */ +#define EXP_CTS_TIME 0x137c + +/* + * EXP_ACK_TIME: + */ +#define EXP_ACK_TIME 0x1380 + +/* + * RX_FILTER_CFG: RX configuration register. + */ +#define RX_FILTER_CFG 0x1400 +#define RX_FILTER_CFG_DROP_CRC_ERROR FIELD32(0x00000001) +#define RX_FILTER_CFG_DROP_PHY_ERROR FIELD32(0x00000002) +#define RX_FILTER_CFG_DROP_NOT_TO_ME FIELD32(0x00000004) +#define RX_FILTER_CFG_DROP_NOT_MY_BSSD FIELD32(0x00000008) +#define RX_FILTER_CFG_DROP_VER_ERROR FIELD32(0x00000010) +#define RX_FILTER_CFG_DROP_MULTICAST FIELD32(0x00000020) +#define RX_FILTER_CFG_DROP_BROADCAST FIELD32(0x00000040) +#define RX_FILTER_CFG_DROP_DUPLICATE FIELD32(0x00000080) +#define RX_FILTER_CFG_DROP_CF_END_ACK FIELD32(0x00000100) +#define RX_FILTER_CFG_DROP_CF_END FIELD32(0x00000200) +#define RX_FILTER_CFG_DROP_ACK FIELD32(0x00000400) +#define RX_FILTER_CFG_DROP_CTS FIELD32(0x00000800) +#define RX_FILTER_CFG_DROP_RTS FIELD32(0x00001000) +#define RX_FILTER_CFG_DROP_PSPOLL FIELD32(0x00002000) +#define RX_FILTER_CFG_DROP_BA FIELD32(0x00004000) +#define RX_FILTER_CFG_DROP_BAR FIELD32(0x00008000) +#define RX_FILTER_CFG_DROP_CNTL FIELD32(0x00010000) + +/* + * AUTO_RSP_CFG: + * AUTORESPONDER: 0: disable, 1: enable + * BAC_ACK_POLICY: 0:long, 1:short preamble + * CTS_40_MMODE: Response CTS 40MHz duplicate mode + * CTS_40_MREF: Response CTS 40MHz duplicate mode + * AR_PREAMBLE: Auto responder preamble 0:long, 1:short preamble + * DUAL_CTS_EN: Power bit value in control frame + * ACK_CTS_PSM_BIT:Power bit value in control frame + */ +#define AUTO_RSP_CFG 0x1404 +#define AUTO_RSP_CFG_AUTORESPONDER FIELD32(0x00000001) +#define AUTO_RSP_CFG_BAC_ACK_POLICY FIELD32(0x00000002) +#define AUTO_RSP_CFG_CTS_40_MMODE FIELD32(0x00000004) +#define AUTO_RSP_CFG_CTS_40_MREF FIELD32(0x00000008) +#define AUTO_RSP_CFG_AR_PREAMBLE FIELD32(0x00000010) +#define AUTO_RSP_CFG_DUAL_CTS_EN FIELD32(0x00000040) +#define AUTO_RSP_CFG_ACK_CTS_PSM_BIT FIELD32(0x00000080) + +/* + * LEGACY_BASIC_RATE: + */ +#define LEGACY_BASIC_RATE 0x1408 + +/* + * HT_BASIC_RATE: + */ +#define HT_BASIC_RATE 0x140c + +/* + * HT_CTRL_CFG: + */ +#define HT_CTRL_CFG 0x1410 + +/* + * SIFS_COST_CFG: + */ +#define SIFS_COST_CFG 0x1414 + +/* + * RX_PARSER_CFG: + * Set NAV for all received frames + */ +#define RX_PARSER_CFG 0x1418 + +/* + * TX_SEC_CNT0: + */ +#define TX_SEC_CNT0 0x1500 + +/* + * RX_SEC_CNT0: + */ +#define RX_SEC_CNT0 0x1504 + +/* + * CCMP_FC_MUTE: + */ +#define CCMP_FC_MUTE 0x1508 + +/* + * TXOP_HLDR_ADDR0: + */ +#define TXOP_HLDR_ADDR0 0x1600 + +/* + * TXOP_HLDR_ADDR1: + */ +#define TXOP_HLDR_ADDR1 0x1604 + +/* + * TXOP_HLDR_ET: + */ +#define TXOP_HLDR_ET 0x1608 + +/* + * QOS_CFPOLL_RA_DW0: + */ +#define QOS_CFPOLL_RA_DW0 0x160c + +/* + * QOS_CFPOLL_RA_DW1: + */ +#define QOS_CFPOLL_RA_DW1 0x1610 + +/* + * QOS_CFPOLL_QC: + */ +#define QOS_CFPOLL_QC 0x1614 + +/* + * RX_STA_CNT0: RX PLCP error count & RX CRC error count + */ +#define RX_STA_CNT0 0x1700 +#define RX_STA_CNT0_CRC_ERR FIELD32(0x0000ffff) +#define RX_STA_CNT0_PHY_ERR FIELD32(0xffff0000) + +/* + * RX_STA_CNT1: RX False CCA count & RX LONG frame count + */ +#define RX_STA_CNT1 0x1704 +#define RX_STA_CNT1_FALSE_CCA FIELD32(0x0000ffff) +#define RX_STA_CNT1_PLCP_ERR FIELD32(0xffff0000) + +/* + * RX_STA_CNT2: + */ +#define RX_STA_CNT2 0x1708 +#define RX_STA_CNT2_RX_DUPLI_COUNT FIELD32(0x0000ffff) +#define RX_STA_CNT2_RX_FIFO_OVERFLOW FIELD32(0xffff0000) + +/* + * TX_STA_CNT0: TX Beacon count + */ +#define TX_STA_CNT0 0x170c +#define TX_STA_CNT0_TX_FAIL_COUNT FIELD32(0x0000ffff) +#define TX_STA_CNT0_TX_BEACON_COUNT FIELD32(0xffff0000) + +/* + * TX_STA_CNT1: TX tx count + */ +#define TX_STA_CNT1 0x1710 +#define TX_STA_CNT1_TX_SUCCESS FIELD32(0x0000ffff) +#define TX_STA_CNT1_TX_RETRANSMIT FIELD32(0xffff0000) + +/* + * TX_STA_CNT2: TX tx count + */ +#define TX_STA_CNT2 0x1714 +#define TX_STA_CNT2_TX_ZERO_LEN_COUNT FIELD32(0x0000ffff) +#define TX_STA_CNT2_TX_UNDER_FLOW_COUNT FIELD32(0xffff0000) + +/* + * TX_STA_FIFO: TX Result for specific PID status fifo register + */ +#define TX_STA_FIFO 0x1718 +#define TX_STA_FIFO_VALID FIELD32(0x00000001) +#define TX_STA_FIFO_PID_TYPE FIELD32(0x0000001e) +#define TX_STA_FIFO_TX_SUCCESS FIELD32(0x00000020) +#define TX_STA_FIFO_TX_AGGRE FIELD32(0x00000040) +#define TX_STA_FIFO_TX_ACK_REQUIRED FIELD32(0x00000080) +#define TX_STA_FIFO_WCID FIELD32(0x0000ff00) +#define TX_STA_FIFO_SUCCESS_RATE FIELD32(0xffff0000) + +/* + * TX_AGG_CNT: Debug counter + */ +#define TX_AGG_CNT 0x171c +#define TX_AGG_CNT_NON_AGG_TX_COUNT FIELD32(0x0000ffff) +#define TX_AGG_CNT_AGG_TX_COUNT FIELD32(0xffff0000) + +/* + * TX_AGG_CNT0: + */ +#define TX_AGG_CNT0 0x1720 +#define TX_AGG_CNT0_AGG_SIZE_1_COUNT FIELD32(0x0000ffff) +#define TX_AGG_CNT0_AGG_SIZE_2_COUNT FIELD32(0xffff0000) + +/* + * TX_AGG_CNT1: + */ +#define TX_AGG_CNT1 0x1724 +#define TX_AGG_CNT1_AGG_SIZE_3_COUNT FIELD32(0x0000ffff) +#define TX_AGG_CNT1_AGG_SIZE_4_COUNT FIELD32(0xffff0000) + +/* + * TX_AGG_CNT2: + */ +#define TX_AGG_CNT2 0x1728 +#define TX_AGG_CNT2_AGG_SIZE_5_COUNT FIELD32(0x0000ffff) +#define TX_AGG_CNT2_AGG_SIZE_6_COUNT FIELD32(0xffff0000) + +/* + * TX_AGG_CNT3: + */ +#define TX_AGG_CNT3 0x172c +#define TX_AGG_CNT3_AGG_SIZE_7_COUNT FIELD32(0x0000ffff) +#define TX_AGG_CNT3_AGG_SIZE_8_COUNT FIELD32(0xffff0000) + +/* + * TX_AGG_CNT4: + */ +#define TX_AGG_CNT4 0x1730 +#define TX_AGG_CNT4_AGG_SIZE_9_COUNT FIELD32(0x0000ffff) +#define TX_AGG_CNT4_AGG_SIZE_10_COUNT FIELD32(0xffff0000) + +/* + * TX_AGG_CNT5: + */ +#define TX_AGG_CNT5 0x1734 +#define TX_AGG_CNT5_AGG_SIZE_11_COUNT FIELD32(0x0000ffff) +#define TX_AGG_CNT5_AGG_SIZE_12_COUNT FIELD32(0xffff0000) + +/* + * TX_AGG_CNT6: + */ +#define TX_AGG_CNT6 0x1738 +#define TX_AGG_CNT6_AGG_SIZE_13_COUNT FIELD32(0x0000ffff) +#define TX_AGG_CNT6_AGG_SIZE_14_COUNT FIELD32(0xffff0000) + +/* + * TX_AGG_CNT7: + */ +#define TX_AGG_CNT7 0x173c +#define TX_AGG_CNT7_AGG_SIZE_15_COUNT FIELD32(0x0000ffff) +#define TX_AGG_CNT7_AGG_SIZE_16_COUNT FIELD32(0xffff0000) + +/* + * MPDU_DENSITY_CNT: + * TX_ZERO_DEL: TX zero length delimiter count + * RX_ZERO_DEL: RX zero length delimiter count + */ +#define MPDU_DENSITY_CNT 0x1740 +#define MPDU_DENSITY_CNT_TX_ZERO_DEL FIELD32(0x0000ffff) +#define MPDU_DENSITY_CNT_RX_ZERO_DEL FIELD32(0xffff0000) + +/* + * Security key table memory. + * MAC_WCID_BASE: 8-bytes (use only 6 bytes) * 256 entry + * PAIRWISE_KEY_TABLE_BASE: 32-byte * 256 entry + * MAC_IVEIV_TABLE_BASE: 8-byte * 256-entry + * MAC_WCID_ATTRIBUTE_BASE: 4-byte * 256-entry + * SHARED_KEY_TABLE_BASE: 32-byte * 16-entry + * SHARED_KEY_MODE_BASE: 4-byte * 16-entry + */ +#define MAC_WCID_BASE 0x1800 +#define PAIRWISE_KEY_TABLE_BASE 0x4000 +#define MAC_IVEIV_TABLE_BASE 0x6000 +#define MAC_WCID_ATTRIBUTE_BASE 0x6800 +#define SHARED_KEY_TABLE_BASE 0x6c00 +#define SHARED_KEY_MODE_BASE 0x7000 + +#define MAC_WCID_ENTRY(__idx) \ + ( MAC_WCID_BASE + ((__idx) * sizeof(struct mac_wcid_entry)) ) +#define PAIRWISE_KEY_ENTRY(__idx) \ + ( PAIRWISE_KEY_TABLE_BASE + ((__idx) * sizeof(struct hw_key_entry)) ) +#define MAC_IVEIV_ENTRY(__idx) \ + ( MAC_IVEIV_TABLE_BASE + ((__idx) & sizeof(struct mac_iveiv_entry)) ) +#define MAC_WCID_ATTR_ENTRY(__idx) \ + ( MAC_WCID_ATTRIBUTE_BASE + ((__idx) * sizeof(u32)) ) +#define SHARED_KEY_ENTRY(__idx) \ + ( SHARED_KEY_TABLE_BASE + ((__idx) * sizeof(struct hw_key_entry)) ) +#define SHARED_KEY_MODE_ENTRY(__idx) \ + ( SHARED_KEY_MODE_BASE + ((__idx) * sizeof(u32)) ) + +struct mac_wcid_entry { + u8 mac[6]; + u8 reserved[2]; +} __attribute__ ((packed)); + +struct hw_key_entry { + u8 key[16]; + u8 tx_mic[8]; + u8 rx_mic[8]; +} __attribute__ ((packed)); + +struct mac_iveiv_entry { + u8 iv[8]; +} __attribute__ ((packed)); + +/* + * MAC_WCID_ATTRIBUTE: + */ +#define MAC_WCID_ATTRIBUTE_KEYTAB FIELD32(0x00000001) +#define MAC_WCID_ATTRIBUTE_CIPHER FIELD32(0x0000000e) +#define MAC_WCID_ATTRIBUTE_BSS_IDX FIELD32(0x00000070) +#define MAC_WCID_ATTRIBUTE_RX_WIUDF FIELD32(0x00000380) + +/* + * SHARED_KEY_MODE: + */ +#define SHARED_KEY_MODE_BSS0_KEY0 FIELD32(0x00000007) +#define SHARED_KEY_MODE_BSS0_KEY1 FIELD32(0x00000070) +#define SHARED_KEY_MODE_BSS0_KEY2 FIELD32(0x00000700) +#define SHARED_KEY_MODE_BSS0_KEY3 FIELD32(0x00007000) +#define SHARED_KEY_MODE_BSS1_KEY0 FIELD32(0x00070000) +#define SHARED_KEY_MODE_BSS1_KEY1 FIELD32(0x00700000) +#define SHARED_KEY_MODE_BSS1_KEY2 FIELD32(0x07000000) +#define SHARED_KEY_MODE_BSS1_KEY3 FIELD32(0x70000000) + +/* + * HOST-MCU communication + */ + +/* + * H2M_MAILBOX_CSR: Host-to-MCU Mailbox. + */ +#define H2M_MAILBOX_CSR 0x7010 +#define H2M_MAILBOX_CSR_ARG0 FIELD32(0x000000ff) +#define H2M_MAILBOX_CSR_ARG1 FIELD32(0x0000ff00) +#define H2M_MAILBOX_CSR_CMD_TOKEN FIELD32(0x00ff0000) +#define H2M_MAILBOX_CSR_OWNER FIELD32(0xff000000) + +/* + * H2M_MAILBOX_CID: + */ +#define H2M_MAILBOX_CID 0x7014 +#define H2M_MAILBOX_CID_CMD0 FIELD32(0x000000ff) +#define H2M_MAILBOX_CID_CMD1 FIELD32(0x0000ff00) +#define H2M_MAILBOX_CID_CMD2 FIELD32(0x00ff0000) +#define H2M_MAILBOX_CID_CMD3 FIELD32(0xff000000) + +/* + * H2M_MAILBOX_STATUS: + */ +#define H2M_MAILBOX_STATUS 0x701c + +/* + * H2M_INT_SRC: + */ +#define H2M_INT_SRC 0x7024 + +/* + * H2M_BBP_AGENT: + */ +#define H2M_BBP_AGENT 0x7028 + +/* + * MCU_LEDCS: LED control for MCU Mailbox. + */ +#define MCU_LEDCS_LED_MODE FIELD8(0x1f) +#define MCU_LEDCS_POLARITY FIELD8(0x01) + +/* + * HW_CS_CTS_BASE: + * Carrier-sense CTS frame base address. + * It's where mac stores carrier-sense frame for carrier-sense function. + */ +#define HW_CS_CTS_BASE 0x7700 + +/* + * HW_DFS_CTS_BASE: + * FS CTS frame base address. It's where mac stores CTS frame for DFS. + */ +#define HW_DFS_CTS_BASE 0x7780 + +/* + * TXRX control registers - base address 0x3000 + */ + +/* + * TXRX_CSR1: + * rt2860b UNKNOWN reg use R/O Reg Addr 0x77d0 first.. + */ +#define TXRX_CSR1 0x77d0 + +/* + * HW_DEBUG_SETTING_BASE: + * since NULL frame won't be that long (256 byte) + * We steal 16 tail bytes to save debugging settings + */ +#define HW_DEBUG_SETTING_BASE 0x77f0 +#define HW_DEBUG_SETTING_BASE2 0x7770 + +/* + * HW_BEACON_BASE + * In order to support maximum 8 MBSS and its maximum length + * is 512 bytes for each beacon + * Three section discontinue memory segments will be used. + * 1. The original region for BCN 0~3 + * 2. Extract memory from FCE table for BCN 4~5 + * 3. Extract memory from Pair-wise key table for BCN 6~7 + * It occupied those memory of wcid 238~253 for BCN 6 + * and wcid 222~237 for BCN 7 + * + * IMPORTANT NOTE: Not sure why legacy driver does this, + * but HW_BEACON_BASE7 is 0x0200 bytes below HW_BEACON_BASE6. + */ +#define HW_BEACON_BASE0 0x7800 +#define HW_BEACON_BASE1 0x7a00 +#define HW_BEACON_BASE2 0x7c00 +#define HW_BEACON_BASE3 0x7e00 +#define HW_BEACON_BASE4 0x7200 +#define HW_BEACON_BASE5 0x7400 +#define HW_BEACON_BASE6 0x5dc0 +#define HW_BEACON_BASE7 0x5bc0 + +#define HW_BEACON_OFFSET(__index) \ + ( ((__index) < 4) ? ( HW_BEACON_BASE0 + (__index * 0x0200) ) : \ + (((__index) < 6) ? ( HW_BEACON_BASE4 + ((__index - 4) * 0x0200) ) : \ + (HW_BEACON_BASE6 - ((__index - 6) * 0x0200))) ) + +/* + * 8051 firmware image. + */ +#define FIRMWARE_RT2870 "rt2870.bin" +#define FIRMWARE_IMAGE_BASE 0x3000 + +/* + * BBP registers. + * The wordsize of the BBP is 8 bits. + */ + +/* + * BBP 1: TX Antenna + */ +#define BBP1_TX_POWER FIELD8(0x07) +#define BBP1_TX_ANTENNA FIELD8(0x18) + +/* + * BBP 3: RX Antenna + */ +#define BBP3_RX_ANTENNA FIELD8(0x18) +#define BBP3_HT40_PLUS FIELD8(0x20) + +/* + * BBP 4: Bandwidth + */ +#define BBP4_TX_BF FIELD8(0x01) +#define BBP4_BANDWIDTH FIELD8(0x18) + +/* + * RFCSR registers + * The wordsize of the RFCSR is 8 bits. + */ + +/* + * RFCSR 6: + */ +#define RFCSR6_R FIELD8(0x03) + +/* + * RFCSR 7: + */ +#define RFCSR7_RF_TUNING FIELD8(0x01) + +/* + * RFCSR 12: + */ +#define RFCSR12_TX_POWER FIELD8(0x1f) + +/* + * RFCSR 22: + */ +#define RFCSR22_BASEBAND_LOOPBACK FIELD8(0x01) + +/* + * RFCSR 23: + */ +#define RFCSR23_FREQ_OFFSET FIELD8(0x7f) + +/* + * RFCSR 30: + */ +#define RFCSR30_RF_CALIBRATION FIELD8(0x80) + +/* + * RF registers + */ + +/* + * RF 2 + */ +#define RF2_ANTENNA_RX2 FIELD32(0x00000040) +#define RF2_ANTENNA_TX1 FIELD32(0x00004000) +#define RF2_ANTENNA_RX1 FIELD32(0x00020000) + +/* + * RF 3 + */ +#define RF3_TXPOWER_G FIELD32(0x00003e00) +#define RF3_TXPOWER_A_7DBM_BOOST FIELD32(0x00000200) +#define RF3_TXPOWER_A FIELD32(0x00003c00) + +/* + * RF 4 + */ +#define RF4_TXPOWER_G FIELD32(0x000007c0) +#define RF4_TXPOWER_A_7DBM_BOOST FIELD32(0x00000040) +#define RF4_TXPOWER_A FIELD32(0x00000780) +#define RF4_FREQ_OFFSET FIELD32(0x001f8000) +#define RF4_HT40 FIELD32(0x00200000) + +/* + * EEPROM content. + * The wordsize of the EEPROM is 16 bits. + */ + +/* + * EEPROM Version + */ +#define EEPROM_VERSION 0x0001 +#define EEPROM_VERSION_FAE FIELD16(0x00ff) +#define EEPROM_VERSION_VERSION FIELD16(0xff00) + +/* + * HW MAC address. + */ +#define EEPROM_MAC_ADDR_0 0x0002 +#define EEPROM_MAC_ADDR_BYTE0 FIELD16(0x00ff) +#define EEPROM_MAC_ADDR_BYTE1 FIELD16(0xff00) +#define EEPROM_MAC_ADDR_1 0x0003 +#define EEPROM_MAC_ADDR_BYTE2 FIELD16(0x00ff) +#define EEPROM_MAC_ADDR_BYTE3 FIELD16(0xff00) +#define EEPROM_MAC_ADDR_2 0x0004 +#define EEPROM_MAC_ADDR_BYTE4 FIELD16(0x00ff) +#define EEPROM_MAC_ADDR_BYTE5 FIELD16(0xff00) + +/* + * EEPROM ANTENNA config + * RXPATH: 1: 1R, 2: 2R, 3: 3R + * TXPATH: 1: 1T, 2: 2T + */ +#define EEPROM_ANTENNA 0x001a +#define EEPROM_ANTENNA_RXPATH FIELD16(0x000f) +#define EEPROM_ANTENNA_TXPATH FIELD16(0x00f0) +#define EEPROM_ANTENNA_RF_TYPE FIELD16(0x0f00) + +/* + * EEPROM NIC config + * CARDBUS_ACCEL: 0 - enable, 1 - disable + */ +#define EEPROM_NIC 0x001b +#define EEPROM_NIC_HW_RADIO FIELD16(0x0001) +#define EEPROM_NIC_DYNAMIC_TX_AGC FIELD16(0x0002) +#define EEPROM_NIC_EXTERNAL_LNA_BG FIELD16(0x0004) +#define EEPROM_NIC_EXTERNAL_LNA_A FIELD16(0x0008) +#define EEPROM_NIC_CARDBUS_ACCEL FIELD16(0x0010) +#define EEPROM_NIC_BW40M_SB_BG FIELD16(0x0020) +#define EEPROM_NIC_BW40M_SB_A FIELD16(0x0040) +#define EEPROM_NIC_WPS_PBC FIELD16(0x0080) +#define EEPROM_NIC_BW40M_BG FIELD16(0x0100) +#define EEPROM_NIC_BW40M_A FIELD16(0x0200) + +/* + * EEPROM frequency + */ +#define EEPROM_FREQ 0x001d +#define EEPROM_FREQ_OFFSET FIELD16(0x00ff) +#define EEPROM_FREQ_LED_MODE FIELD16(0x7f00) +#define EEPROM_FREQ_LED_POLARITY FIELD16(0x1000) + +/* + * EEPROM LED + * POLARITY_RDY_G: Polarity RDY_G setting. + * POLARITY_RDY_A: Polarity RDY_A setting. + * POLARITY_ACT: Polarity ACT setting. + * POLARITY_GPIO_0: Polarity GPIO0 setting. + * POLARITY_GPIO_1: Polarity GPIO1 setting. + * POLARITY_GPIO_2: Polarity GPIO2 setting. + * POLARITY_GPIO_3: Polarity GPIO3 setting. + * POLARITY_GPIO_4: Polarity GPIO4 setting. + * LED_MODE: Led mode. + */ +#define EEPROM_LED1 0x001e +#define EEPROM_LED2 0x001f +#define EEPROM_LED3 0x0020 +#define EEPROM_LED_POLARITY_RDY_BG FIELD16(0x0001) +#define EEPROM_LED_POLARITY_RDY_A FIELD16(0x0002) +#define EEPROM_LED_POLARITY_ACT FIELD16(0x0004) +#define EEPROM_LED_POLARITY_GPIO_0 FIELD16(0x0008) +#define EEPROM_LED_POLARITY_GPIO_1 FIELD16(0x0010) +#define EEPROM_LED_POLARITY_GPIO_2 FIELD16(0x0020) +#define EEPROM_LED_POLARITY_GPIO_3 FIELD16(0x0040) +#define EEPROM_LED_POLARITY_GPIO_4 FIELD16(0x0080) +#define EEPROM_LED_LED_MODE FIELD16(0x1f00) + +/* + * EEPROM LNA + */ +#define EEPROM_LNA 0x0022 +#define EEPROM_LNA_BG FIELD16(0x00ff) +#define EEPROM_LNA_A0 FIELD16(0xff00) + +/* + * EEPROM RSSI BG offset + */ +#define EEPROM_RSSI_BG 0x0023 +#define EEPROM_RSSI_BG_OFFSET0 FIELD16(0x00ff) +#define EEPROM_RSSI_BG_OFFSET1 FIELD16(0xff00) + +/* + * EEPROM RSSI BG2 offset + */ +#define EEPROM_RSSI_BG2 0x0024 +#define EEPROM_RSSI_BG2_OFFSET2 FIELD16(0x00ff) +#define EEPROM_RSSI_BG2_LNA_A1 FIELD16(0xff00) + +/* + * EEPROM RSSI A offset + */ +#define EEPROM_RSSI_A 0x0025 +#define EEPROM_RSSI_A_OFFSET0 FIELD16(0x00ff) +#define EEPROM_RSSI_A_OFFSET1 FIELD16(0xff00) + +/* + * EEPROM RSSI A2 offset + */ +#define EEPROM_RSSI_A2 0x0026 +#define EEPROM_RSSI_A2_OFFSET2 FIELD16(0x00ff) +#define EEPROM_RSSI_A2_LNA_A2 FIELD16(0xff00) + +/* + * EEPROM TXpower delta: 20MHZ AND 40 MHZ use different power. + * This is delta in 40MHZ. + * VALUE: Tx Power dalta value (MAX=4) + * TYPE: 1: Plus the delta value, 0: minus the delta value + * TXPOWER: Enable: + */ +#define EEPROM_TXPOWER_DELTA 0x0028 +#define EEPROM_TXPOWER_DELTA_VALUE FIELD16(0x003f) +#define EEPROM_TXPOWER_DELTA_TYPE FIELD16(0x0040) +#define EEPROM_TXPOWER_DELTA_TXPOWER FIELD16(0x0080) + +/* + * EEPROM TXPOWER 802.11BG + */ +#define EEPROM_TXPOWER_BG1 0x0029 +#define EEPROM_TXPOWER_BG2 0x0030 +#define EEPROM_TXPOWER_BG_SIZE 7 +#define EEPROM_TXPOWER_BG_1 FIELD16(0x00ff) +#define EEPROM_TXPOWER_BG_2 FIELD16(0xff00) + +/* + * EEPROM TXPOWER 802.11A + */ +#define EEPROM_TXPOWER_A1 0x003c +#define EEPROM_TXPOWER_A2 0x0053 +#define EEPROM_TXPOWER_A_SIZE 6 +#define EEPROM_TXPOWER_A_1 FIELD16(0x00ff) +#define EEPROM_TXPOWER_A_2 FIELD16(0xff00) + +/* + * EEPROM TXpower byrate: 20MHZ power + */ +#define EEPROM_TXPOWER_BYRATE 0x006f + +/* + * EEPROM BBP. + */ +#define EEPROM_BBP_START 0x0078 +#define EEPROM_BBP_SIZE 16 +#define EEPROM_BBP_VALUE FIELD16(0x00ff) +#define EEPROM_BBP_REG_ID FIELD16(0xff00) + +/* + * MCU mailbox commands. + */ +#define MCU_SLEEP 0x30 +#define MCU_WAKEUP 0x31 +#define MCU_RADIO_OFF 0x35 +#define MCU_CURRENT 0x36 +#define MCU_LED 0x50 +#define MCU_LED_STRENGTH 0x51 +#define MCU_LED_1 0x52 +#define MCU_LED_2 0x53 +#define MCU_LED_3 0x54 +#define MCU_RADAR 0x60 +#define MCU_BOOT_SIGNAL 0x72 +#define MCU_BBP_SIGNAL 0x80 +#define MCU_POWER_SAVE 0x83 + +/* + * MCU mailbox tokens + */ +#define TOKEN_WAKUP 3 + +/* + * DMA descriptor defines. + */ +#define TXD_DESC_SIZE ( 4 * sizeof(__le32) ) +#define TXINFO_DESC_SIZE ( 1 * sizeof(__le32) ) +#define TXWI_DESC_SIZE ( 4 * sizeof(__le32) ) +#define RXD_DESC_SIZE ( 1 * sizeof(__le32) ) +#define RXWI_DESC_SIZE ( 4 * sizeof(__le32) ) + +/* + * TX descriptor format for TX, PRIO and Beacon Ring. + */ + +/* + * Word0 + */ +#define TXD_W0_SD_PTR0 FIELD32(0xffffffff) + +/* + * Word1 + */ +#define TXD_W1_SD_LEN1 FIELD32(0x00003fff) +#define TXD_W1_LAST_SEC1 FIELD32(0x00004000) +#define TXD_W1_BURST FIELD32(0x00008000) +#define TXD_W1_SD_LEN0 FIELD32(0x3fff0000) +#define TXD_W1_LAST_SEC0 FIELD32(0x40000000) +#define TXD_W1_DMA_DONE FIELD32(0x80000000) + +/* + * Word2 + */ +#define TXD_W2_SD_PTR1 FIELD32(0xffffffff) + +/* + * Word3 + * WIV: Wireless Info Valid. 1: Driver filled WI, 0: DMA needs to copy WI + * QSEL: Select on-chip FIFO ID for 2nd-stage output scheduler. + * 0:MGMT, 1:HCCA 2:EDCA + */ +#define TXD_W3_WIV FIELD32(0x01000000) +#define TXD_W3_QSEL FIELD32(0x06000000) +#define TXD_W3_TCO FIELD32(0x20000000) +#define TXD_W3_UCO FIELD32(0x40000000) +#define TXD_W3_ICO FIELD32(0x80000000) + +/* + * TX Info structure + */ + +/* + * Word0 + * WIV: Wireless Info Valid. 1: Driver filled WI, 0: DMA needs to copy WI + * QSEL: Select on-chip FIFO ID for 2nd-stage output scheduler. + * 0:MGMT, 1:HCCA 2:EDCA + * USB_DMA_NEXT_VALID: Used ONLY in USB bulk Aggregation, NextValid + * DMA_TX_BURST: used ONLY in USB bulk Aggregation. + * Force USB DMA transmit frame from current selected endpoint + */ +#define TXINFO_W0_USB_DMA_TX_PKT_LEN FIELD32(0x0000ffff) +#define TXINFO_W0_WIV FIELD32(0x01000000) +#define TXINFO_W0_QSEL FIELD32(0x06000000) +#define TXINFO_W0_SW_USE_LAST_ROUND FIELD32(0x08000000) +#define TXINFO_W0_USB_DMA_NEXT_VALID FIELD32(0x40000000) +#define TXINFO_W0_USB_DMA_TX_BURST FIELD32(0x80000000) + +/* + * TX WI structure + */ + +/* + * Word0 + * FRAG: 1 To inform TKIP engine this is a fragment. + * MIMO_PS: The remote peer is in dynamic MIMO-PS mode + * TX_OP: 0:HT TXOP rule , 1:PIFS TX ,2:Backoff, 3:sifs + * BW: Channel bandwidth 20MHz or 40 MHz + * STBC: 1: STBC support MCS =0-7, 2,3 : RESERVED + */ +#define TXWI_W0_FRAG FIELD32(0x00000001) +#define TXWI_W0_MIMO_PS FIELD32(0x00000002) +#define TXWI_W0_CF_ACK FIELD32(0x00000004) +#define TXWI_W0_TS FIELD32(0x00000008) +#define TXWI_W0_AMPDU FIELD32(0x00000010) +#define TXWI_W0_MPDU_DENSITY FIELD32(0x000000e0) +#define TXWI_W0_TX_OP FIELD32(0x00000300) +#define TXWI_W0_MCS FIELD32(0x007f0000) +#define TXWI_W0_BW FIELD32(0x00800000) +#define TXWI_W0_SHORT_GI FIELD32(0x01000000) +#define TXWI_W0_STBC FIELD32(0x06000000) +#define TXWI_W0_IFS FIELD32(0x08000000) +#define TXWI_W0_PHYMODE FIELD32(0xc0000000) + +/* + * Word1 + */ +#define TXWI_W1_ACK FIELD32(0x00000001) +#define TXWI_W1_NSEQ FIELD32(0x00000002) +#define TXWI_W1_BW_WIN_SIZE FIELD32(0x000000fc) +#define TXWI_W1_WIRELESS_CLI_ID FIELD32(0x0000ff00) +#define TXWI_W1_MPDU_TOTAL_BYTE_COUNT FIELD32(0x0fff0000) +#define TXWI_W1_PACKETID FIELD32(0xf0000000) + +/* + * Word2 + */ +#define TXWI_W2_IV FIELD32(0xffffffff) + +/* + * Word3 + */ +#define TXWI_W3_EIV FIELD32(0xffffffff) + +/* + * RX descriptor format for RX Ring. + */ + +/* + * Word0 + * UNICAST_TO_ME: This RX frame is unicast to me. + * MULTICAST: This is a multicast frame. + * BROADCAST: This is a broadcast frame. + * MY_BSS: this frame belongs to the same BSSID. + * CRC_ERROR: CRC error. + * CIPHER_ERROR: 0: decryption okay, 1:ICV error, 2:MIC error, 3:KEY not valid. + * AMSDU: rx with 802.3 header, not 802.11 header. + */ + +#define RXD_W0_BA FIELD32(0x00000001) +#define RXD_W0_DATA FIELD32(0x00000002) +#define RXD_W0_NULLDATA FIELD32(0x00000004) +#define RXD_W0_FRAG FIELD32(0x00000008) +#define RXD_W0_UNICAST_TO_ME FIELD32(0x00000010) +#define RXD_W0_MULTICAST FIELD32(0x00000020) +#define RXD_W0_BROADCAST FIELD32(0x00000040) +#define RXD_W0_MY_BSS FIELD32(0x00000080) +#define RXD_W0_CRC_ERROR FIELD32(0x00000100) +#define RXD_W0_CIPHER_ERROR FIELD32(0x00000600) +#define RXD_W0_AMSDU FIELD32(0x00000800) +#define RXD_W0_HTC FIELD32(0x00001000) +#define RXD_W0_RSSI FIELD32(0x00002000) +#define RXD_W0_L2PAD FIELD32(0x00004000) +#define RXD_W0_AMPDU FIELD32(0x00008000) +#define RXD_W0_DECRYPTED FIELD32(0x00010000) +#define RXD_W0_PLCP_RSSI FIELD32(0x00020000) +#define RXD_W0_CIPHER_ALG FIELD32(0x00040000) +#define RXD_W0_LAST_AMSDU FIELD32(0x00080000) +#define RXD_W0_PLCP_SIGNAL FIELD32(0xfff00000) + +/* + * RX WI structure + */ + +/* + * Word0 + */ +#define RXWI_W0_WIRELESS_CLI_ID FIELD32(0x000000ff) +#define RXWI_W0_KEY_INDEX FIELD32(0x00000300) +#define RXWI_W0_BSSID FIELD32(0x00001c00) +#define RXWI_W0_UDF FIELD32(0x0000e000) +#define RXWI_W0_MPDU_TOTAL_BYTE_COUNT FIELD32(0x0fff0000) +#define RXWI_W0_TID FIELD32(0xf0000000) + +/* + * Word1 + */ +#define RXWI_W1_FRAG FIELD32(0x0000000f) +#define RXWI_W1_SEQUENCE FIELD32(0x0000fff0) +#define RXWI_W1_MCS FIELD32(0x007f0000) +#define RXWI_W1_BW FIELD32(0x00800000) +#define RXWI_W1_SHORT_GI FIELD32(0x01000000) +#define RXWI_W1_STBC FIELD32(0x06000000) +#define RXWI_W1_PHYMODE FIELD32(0xc0000000) + +/* + * Word2 + */ +#define RXWI_W2_RSSI0 FIELD32(0x000000ff) +#define RXWI_W2_RSSI1 FIELD32(0x0000ff00) +#define RXWI_W2_RSSI2 FIELD32(0x00ff0000) + +/* + * Word3 + */ +#define RXWI_W3_SNR0 FIELD32(0x000000ff) +#define RXWI_W3_SNR1 FIELD32(0x0000ff00) + +/* + * Macro's for converting txpower from EEPROM to mac80211 value + * and from mac80211 value to register value. + */ +#define MIN_G_TXPOWER 0 +#define MIN_A_TXPOWER -7 +#define MAX_G_TXPOWER 31 +#define MAX_A_TXPOWER 15 +#define DEFAULT_TXPOWER 5 + +#define TXPOWER_G_FROM_DEV(__txpower) \ + ((__txpower) > MAX_G_TXPOWER) ? DEFAULT_TXPOWER : (__txpower) + +#define TXPOWER_G_TO_DEV(__txpower) \ + clamp_t(char, __txpower, MIN_G_TXPOWER, MAX_G_TXPOWER) + +#define TXPOWER_A_FROM_DEV(__txpower) \ + ((__txpower) > MAX_A_TXPOWER) ? DEFAULT_TXPOWER : (__txpower) + +#define TXPOWER_A_TO_DEV(__txpower) \ + clamp_t(char, __txpower, MIN_A_TXPOWER, MAX_A_TXPOWER) + +#endif /* RT2800USB_H */ diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 84bd6f19acb0..a498dde024e1 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -102,6 +102,15 @@ #define GET_DURATION(__size, __rate) (((__size) * 8 * 10) / (__rate)) #define GET_DURATION_RES(__size, __rate)(((__size) * 8 * 10) % (__rate)) +/* + * Determine the alignment requirement, + * to make sure the 802.11 payload is padded to a 4-byte boundrary + * we must determine the address of the payload and calculate the + * amount of bytes needed to move the data. + */ +#define ALIGN_SIZE(__skb, __header) \ + ( ((unsigned long)((__skb)->data + (__header))) & 3 ) + /* * Standard timing and size defines. * These values should follow the ieee80211 specifications. @@ -138,6 +147,7 @@ struct rt2x00_chip { #define RT2561 0x0302 #define RT2661 0x0401 #define RT2571 0x1300 +#define RT2870 0x1600 u16 rf; u32 rev; @@ -357,6 +367,7 @@ static inline struct rt2x00_intf* vif_to_intf(struct ieee80211_vif *vif) * for @tx_power_a, @tx_power_bg and @channels. * @channels: Device/chipset specific channel values (See &struct rf_channel). * @channels_info: Additional information for channels (See &struct channel_info). + * @ht: Driver HT Capabilities (See &ieee80211_sta_ht_cap). */ struct hw_mode_spec { unsigned int supported_bands; @@ -370,6 +381,8 @@ struct hw_mode_spec { unsigned int num_channels; const struct rf_channel *channels; const struct channel_info *channels_info; + + struct ieee80211_sta_ht_cap ht; }; /* @@ -404,6 +417,8 @@ struct rt2x00lib_erp { short pifs; short difs; short eifs; + + u16 beacon_int; }; /* @@ -590,6 +605,7 @@ enum rt2x00_flags { DRIVER_REQUIRE_SCHEDULED, DRIVER_REQUIRE_DMA, DRIVER_REQUIRE_COPY_IV, + DRIVER_REQUIRE_L2PAD, /* * Driver features @@ -606,6 +622,7 @@ enum rt2x00_flags { CONFIG_EXTERNAL_LNA_BG, CONFIG_DOUBLE_ANTENNA, CONFIG_DISABLE_LINK_TUNING, + CONFIG_CHANNEL_HT40, }; /* @@ -671,6 +688,12 @@ struct rt2x00_dev { */ unsigned long flags; + /* + * Device information, Bus IRQ and name (PCI, SoC) + */ + int irq; + const char *name; + /* * Chipset identification. */ @@ -771,6 +794,18 @@ struct rt2x00_dev { */ u8 freq_offset; + /* + * Calibration information (for rt2800usb & rt2800pci). + * [0] -> BW20 + * [1] -> BW40 + */ + u8 calibration[2]; + + /* + * Beacon interval. + */ + u16 beacon_int; + /* * Low level statistics which will have * to be kept up to date while device is running. @@ -860,6 +895,18 @@ static inline void rt2x00_set_chip(struct rt2x00_dev *rt2x00dev, rt2x00dev->chip.rev = rev; } +static inline void rt2x00_set_chip_rt(struct rt2x00_dev *rt2x00dev, + const u16 rt) +{ + rt2x00dev->chip.rt = rt; +} + +static inline void rt2x00_set_chip_rf(struct rt2x00_dev *rt2x00dev, + const u16 rf, const u32 rev) +{ + rt2x00_set_chip(rt2x00dev, rt2x00dev->chip.rt, rf, rev); +} + static inline char rt2x00_rt(const struct rt2x00_chip *chipset, const u16 chip) { return (chipset->rt == chip); @@ -875,11 +922,10 @@ static inline u32 rt2x00_rev(const struct rt2x00_chip *chipset) return chipset->rev; } -static inline u16 rt2x00_check_rev(const struct rt2x00_chip *chipset, - const u32 rev) +static inline bool rt2x00_check_rev(const struct rt2x00_chip *chipset, + const u32 mask, const u32 rev) { - return (((chipset->rev & 0xffff0) == rev) && - !!(chipset->rev & 0x0000f)); + return ((chipset->rev & mask) == rev); } /** @@ -925,9 +971,6 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, void rt2x00mac_remove_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf); int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed); -int rt2x00mac_config_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_if_conf *conf); void rt2x00mac_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index 9c2f5517af2a..3e019a12df2e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -106,6 +106,10 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev, } erp.basic_rates = bss_conf->basic_rates; + erp.beacon_int = bss_conf->beacon_int; + + /* Update global beacon interval time, this is needed for PS support */ + rt2x00dev->beacon_int = bss_conf->beacon_int; rt2x00dev->ops->lib->config_erp(rt2x00dev, &erp); } @@ -173,6 +177,11 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, libconf.conf = conf; if (ieee80211_flags & IEEE80211_CONF_CHANGE_CHANNEL) { + if (conf_is_ht40(conf)) + __set_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags); + else + __clear_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags); + memcpy(&libconf.rf, &rt2x00dev->spec.channels[conf->channel->hw_value], sizeof(libconf.rf)); diff --git a/drivers/net/wireless/rt2x00/rt2x00crypto.c b/drivers/net/wireless/rt2x00/rt2x00crypto.c index 0b41845d9543..bc4e81e21841 100644 --- a/drivers/net/wireless/rt2x00/rt2x00crypto.c +++ b/drivers/net/wireless/rt2x00/rt2x00crypto.c @@ -33,7 +33,7 @@ enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf *key) { switch (key->alg) { case ALG_WEP: - if (key->keylen == LEN_WEP40) + if (key->keylen == WLAN_KEY_LEN_WEP40) return CIPHER_WEP64; else return CIPHER_WEP128; @@ -65,7 +65,8 @@ void rt2x00crypto_create_tx_descriptor(struct queue_entry *entry, __set_bit(ENTRY_TXD_ENCRYPT_PAIRWISE, &txdesc->flags); txdesc->key_idx = hw_key->hw_key_idx; - txdesc->iv_offset = ieee80211_get_hdrlen_from_skb(entry->skb); + txdesc->iv_offset = txdesc->header_length; + txdesc->iv_len = hw_key->iv_len; if (!(hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV)) __set_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc->flags); @@ -103,47 +104,44 @@ unsigned int rt2x00crypto_tx_overhead(struct rt2x00_dev *rt2x00dev, return overhead; } -void rt2x00crypto_tx_copy_iv(struct sk_buff *skb, unsigned int iv_len) +void rt2x00crypto_tx_copy_iv(struct sk_buff *skb, struct txentry_desc *txdesc) { struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); - unsigned int header_length = ieee80211_get_hdrlen_from_skb(skb); - if (unlikely(!iv_len)) + if (unlikely(!txdesc->iv_len)) return; /* Copy IV/EIV data */ - memcpy(skbdesc->iv, skb->data + header_length, iv_len); + memcpy(skbdesc->iv, skb->data + txdesc->iv_offset, txdesc->iv_len); } -void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, unsigned int iv_len) +void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, struct txentry_desc *txdesc) { struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); - unsigned int header_length = ieee80211_get_hdrlen_from_skb(skb); - if (unlikely(!iv_len)) + if (unlikely(!txdesc->iv_len)) return; /* Copy IV/EIV data */ - memcpy(skbdesc->iv, skb->data + header_length, iv_len); + memcpy(skbdesc->iv, skb->data + txdesc->iv_offset, txdesc->iv_len); /* Move ieee80211 header */ - memmove(skb->data + iv_len, skb->data, header_length); + memmove(skb->data + txdesc->iv_len, skb->data, txdesc->iv_offset); /* Pull buffer to correct size */ - skb_pull(skb, iv_len); + skb_pull(skb, txdesc->iv_len); /* IV/EIV data has officially be stripped */ - skbdesc->flags |= FRAME_DESC_IV_STRIPPED; + skbdesc->flags |= SKBDESC_IV_STRIPPED; } -void rt2x00crypto_tx_insert_iv(struct sk_buff *skb) +void rt2x00crypto_tx_insert_iv(struct sk_buff *skb, unsigned int header_length) { struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); - unsigned int header_length = ieee80211_get_hdrlen_from_skb(skb); const unsigned int iv_len = ((!!(skbdesc->iv[0])) * 4) + ((!!(skbdesc->iv[1])) * 4); - if (!(skbdesc->flags & FRAME_DESC_IV_STRIPPED)) + if (!(skbdesc->flags & SKBDESC_IV_STRIPPED)) return; skb_push(skb, iv_len); @@ -155,14 +153,15 @@ void rt2x00crypto_tx_insert_iv(struct sk_buff *skb) memcpy(skb->data + header_length, skbdesc->iv, iv_len); /* IV/EIV data has returned into the frame */ - skbdesc->flags &= ~FRAME_DESC_IV_STRIPPED; + skbdesc->flags &= ~SKBDESC_IV_STRIPPED; } -void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, unsigned int align, +void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, bool l2pad, unsigned int header_length, struct rxdone_entry_desc *rxdesc) { unsigned int payload_len = rxdesc->size - header_length; + unsigned int align = ALIGN_SIZE(skb, header_length); unsigned int iv_len; unsigned int icv_len; unsigned int transfer = 0; @@ -192,32 +191,48 @@ void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, unsigned int align, } /* - * Make room for new data, note that we increase both - * headsize and tailsize when required. The tailsize is - * only needed when ICV data needs to be inserted and - * the padding is smaller than the ICV data. - * When alignment requirements is greater than the - * ICV data we must trim the skb to the correct size - * because we need to remove the extra bytes. + * Make room for new data. There are 2 possibilities + * either the alignment is already present between + * the 802.11 header and payload. In that case we + * we have to move the header less then the iv_len + * since we can use the already available l2pad bytes + * for the iv data. + * When the alignment must be added manually we must + * move the header more then iv_len since we must + * make room for the payload move as well. */ - skb_push(skb, iv_len + align); - if (align < icv_len) - skb_put(skb, icv_len - align); - else if (align > icv_len) - skb_trim(skb, rxdesc->size + iv_len + icv_len); + if (l2pad) { + skb_push(skb, iv_len - align); + skb_put(skb, icv_len); - /* Move ieee80211 header */ - memmove(skb->data + transfer, - skb->data + transfer + iv_len + align, - header_length); - transfer += header_length; + /* Move ieee80211 header */ + memmove(skb->data + transfer, + skb->data + transfer + (iv_len - align), + header_length); + transfer += header_length; + } else { + skb_push(skb, iv_len + align); + if (align < icv_len) + skb_put(skb, icv_len - align); + else if (align > icv_len) + skb_trim(skb, rxdesc->size + iv_len + icv_len); + + /* Move ieee80211 header */ + memmove(skb->data + transfer, + skb->data + transfer + iv_len + align, + header_length); + transfer += header_length; + } /* Copy IV/EIV data */ memcpy(skb->data + transfer, rxdesc->iv, iv_len); transfer += iv_len; - /* Move payload */ - if (align) { + /* + * Move payload for alignment purposes. Note that + * this is only needed when no l2 padding is present. + */ + if (!l2pad) { memmove(skb->data + transfer, skb->data + transfer + align, payload_len); diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 5752aaae906b..57813e72c808 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -227,6 +227,7 @@ void rt2x00lib_txdone(struct queue_entry *entry, struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb); struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); enum data_queue_qid qid = skb_get_queue_mapping(entry->skb); + unsigned int header_length = ieee80211_get_hdrlen_from_skb(entry->skb); u8 rate_idx, rate_flags; /* @@ -234,6 +235,12 @@ void rt2x00lib_txdone(struct queue_entry *entry, */ rt2x00queue_unmap_skb(rt2x00dev, entry->skb); + /* + * Remove L2 padding which was added during + */ + if (test_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags)) + rt2x00queue_payload_align(entry->skb, true, header_length); + /* * If the IV/EIV data was stripped from the frame before it was * passed to the hardware, we should now reinsert it again because @@ -241,7 +248,7 @@ void rt2x00lib_txdone(struct queue_entry *entry, * frame as it was passed to us. */ if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) - rt2x00crypto_tx_insert_iv(entry->skb); + rt2x00crypto_tx_insert_iv(entry->skb, header_length); /* * Send frame to debugfs immediately, after this call is completed @@ -253,7 +260,8 @@ void rt2x00lib_txdone(struct queue_entry *entry, * Update TX statistics. */ rt2x00dev->link.qual.tx_success += - test_bit(TXDONE_SUCCESS, &txdesc->flags); + test_bit(TXDONE_SUCCESS, &txdesc->flags) || + test_bit(TXDONE_UNKNOWN, &txdesc->flags); rt2x00dev->link.qual.tx_failed += test_bit(TXDONE_FAILURE, &txdesc->flags); @@ -271,14 +279,16 @@ void rt2x00lib_txdone(struct queue_entry *entry, tx_info->status.rates[1].idx = -1; /* terminate */ if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) { - if (test_bit(TXDONE_SUCCESS, &txdesc->flags)) + if (test_bit(TXDONE_SUCCESS, &txdesc->flags) || + test_bit(TXDONE_UNKNOWN, &txdesc->flags)) tx_info->flags |= IEEE80211_TX_STAT_ACK; else if (test_bit(TXDONE_FAILURE, &txdesc->flags)) rt2x00dev->low_level_stats.dot11ACKFailureCount++; } if (rate_flags & IEEE80211_TX_RC_USE_RTS_CTS) { - if (test_bit(TXDONE_SUCCESS, &txdesc->flags)) + if (test_bit(TXDONE_SUCCESS, &txdesc->flags) || + test_bit(TXDONE_UNKNOWN, &txdesc->flags)) rt2x00dev->low_level_stats.dot11RTSSuccessCount++; else if (test_bit(TXDONE_FAILURE, &txdesc->flags)) rt2x00dev->low_level_stats.dot11RTSFailureCount++; @@ -316,19 +326,54 @@ void rt2x00lib_txdone(struct queue_entry *entry, } EXPORT_SYMBOL_GPL(rt2x00lib_txdone); +static int rt2x00lib_rxdone_read_signal(struct rt2x00_dev *rt2x00dev, + struct rxdone_entry_desc *rxdesc) +{ + struct ieee80211_supported_band *sband; + const struct rt2x00_rate *rate; + unsigned int i; + int signal; + int type; + + /* + * For non-HT rates the MCS value needs to contain the + * actually used rate modulation (CCK or OFDM). + */ + if (rxdesc->dev_flags & RXDONE_SIGNAL_MCS) + signal = RATE_MCS(rxdesc->rate_mode, rxdesc->signal); + else + signal = rxdesc->signal; + + type = (rxdesc->dev_flags & RXDONE_SIGNAL_MASK); + + sband = &rt2x00dev->bands[rt2x00dev->curr_band]; + for (i = 0; i < sband->n_bitrates; i++) { + rate = rt2x00_get_rate(sband->bitrates[i].hw_value); + + if (((type == RXDONE_SIGNAL_PLCP) && + (rate->plcp == signal)) || + ((type == RXDONE_SIGNAL_BITRATE) && + (rate->bitrate == signal)) || + ((type == RXDONE_SIGNAL_MCS) && + (rate->mcs == signal))) { + return i; + } + } + + WARNING(rt2x00dev, "Frame received with unrecognized signal, " + "signal=0x%.4x, type=%d.\n", signal, type); + return 0; +} + void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry) { struct rxdone_entry_desc rxdesc; struct sk_buff *skb; struct ieee80211_rx_status *rx_status = &rt2x00dev->rx_status; - struct ieee80211_supported_band *sband; - const struct rt2x00_rate *rate; unsigned int header_length; - unsigned int align; - unsigned int i; - int idx = -1; - + bool l2pad; + int rate_idx; /* * Allocate a new sk_buffer. If no new buffer available, drop the * received frame and reuse the existing buffer. @@ -348,12 +393,15 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, memset(&rxdesc, 0, sizeof(rxdesc)); rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc); + /* Trim buffer to correct size */ + skb_trim(entry->skb, rxdesc.size); + /* * The data behind the ieee80211 header must be * aligned on a 4 byte boundary. */ header_length = ieee80211_get_hdrlen_from_skb(entry->skb); - align = ((unsigned long)(entry->skb->data + header_length)) & 3; + l2pad = !!(rxdesc.dev_flags & RXDONE_L2PAD); /* * Hardware might have stripped the IV/EIV/ICV data, @@ -362,40 +410,24 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, * in which case we should reinsert the data into the frame. */ if ((rxdesc.dev_flags & RXDONE_CRYPTO_IV) && - (rxdesc.flags & RX_FLAG_IV_STRIPPED)) { - rt2x00crypto_rx_insert_iv(entry->skb, align, - header_length, &rxdesc); - } else if (align) { - skb_push(entry->skb, align); - /* Move entire frame in 1 command */ - memmove(entry->skb->data, entry->skb->data + align, - rxdesc.size); - } - - /* Update data pointers, trim buffer to correct size */ - skb_trim(entry->skb, rxdesc.size); + (rxdesc.flags & RX_FLAG_IV_STRIPPED)) + rt2x00crypto_rx_insert_iv(entry->skb, l2pad, header_length, + &rxdesc); + else + rt2x00queue_payload_align(entry->skb, l2pad, header_length); /* - * Update RX statistics. + * Check if the frame was received using HT. In that case, + * the rate is the MCS index and should be passed to mac80211 + * directly. Otherwise we need to translate the signal to + * the correct bitrate index. */ - sband = &rt2x00dev->bands[rt2x00dev->curr_band]; - for (i = 0; i < sband->n_bitrates; i++) { - rate = rt2x00_get_rate(sband->bitrates[i].hw_value); - - if (((rxdesc.dev_flags & RXDONE_SIGNAL_PLCP) && - (rate->plcp == rxdesc.signal)) || - ((rxdesc.dev_flags & RXDONE_SIGNAL_BITRATE) && - (rate->bitrate == rxdesc.signal))) { - idx = i; - break; - } - } - - if (idx < 0) { - WARNING(rt2x00dev, "Frame received with unrecognized signal," - "signal=0x%.2x, type=%d.\n", rxdesc.signal, - (rxdesc.dev_flags & RXDONE_SIGNAL_MASK)); - idx = 0; + if (rxdesc.rate_mode == RATE_MODE_CCK || + rxdesc.rate_mode == RATE_MODE_OFDM) { + rate_idx = rt2x00lib_rxdone_read_signal(rt2x00dev, &rxdesc); + } else { + rxdesc.flags |= RX_FLAG_HT; + rate_idx = rxdesc.signal; } /* @@ -405,7 +437,7 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, rt2x00debug_update_crypto(rt2x00dev, &rxdesc); rx_status->mactime = rxdesc.timestamp; - rx_status->rate_idx = idx; + rx_status->rate_idx = rate_idx; rx_status->qual = rt2x00link_calculate_signal(rt2x00dev, rxdesc.rssi); rx_status->signal = rxdesc.rssi; rx_status->noise = rxdesc.noise; @@ -440,72 +472,84 @@ const struct rt2x00_rate rt2x00_supported_rates[12] = { .bitrate = 10, .ratemask = BIT(0), .plcp = 0x00, + .mcs = RATE_MCS(RATE_MODE_CCK, 0), }, { .flags = DEV_RATE_CCK | DEV_RATE_SHORT_PREAMBLE, .bitrate = 20, .ratemask = BIT(1), .plcp = 0x01, + .mcs = RATE_MCS(RATE_MODE_CCK, 1), }, { .flags = DEV_RATE_CCK | DEV_RATE_SHORT_PREAMBLE, .bitrate = 55, .ratemask = BIT(2), .plcp = 0x02, + .mcs = RATE_MCS(RATE_MODE_CCK, 2), }, { .flags = DEV_RATE_CCK | DEV_RATE_SHORT_PREAMBLE, .bitrate = 110, .ratemask = BIT(3), .plcp = 0x03, + .mcs = RATE_MCS(RATE_MODE_CCK, 3), }, { .flags = DEV_RATE_OFDM, .bitrate = 60, .ratemask = BIT(4), .plcp = 0x0b, + .mcs = RATE_MCS(RATE_MODE_OFDM, 0), }, { .flags = DEV_RATE_OFDM, .bitrate = 90, .ratemask = BIT(5), .plcp = 0x0f, + .mcs = RATE_MCS(RATE_MODE_OFDM, 1), }, { .flags = DEV_RATE_OFDM, .bitrate = 120, .ratemask = BIT(6), .plcp = 0x0a, + .mcs = RATE_MCS(RATE_MODE_OFDM, 2), }, { .flags = DEV_RATE_OFDM, .bitrate = 180, .ratemask = BIT(7), .plcp = 0x0e, + .mcs = RATE_MCS(RATE_MODE_OFDM, 3), }, { .flags = DEV_RATE_OFDM, .bitrate = 240, .ratemask = BIT(8), .plcp = 0x09, + .mcs = RATE_MCS(RATE_MODE_OFDM, 4), }, { .flags = DEV_RATE_OFDM, .bitrate = 360, .ratemask = BIT(9), .plcp = 0x0d, + .mcs = RATE_MCS(RATE_MODE_OFDM, 5), }, { .flags = DEV_RATE_OFDM, .bitrate = 480, .ratemask = BIT(10), .plcp = 0x08, + .mcs = RATE_MCS(RATE_MODE_OFDM, 6), }, { .flags = DEV_RATE_OFDM, .bitrate = 540, .ratemask = BIT(11), .plcp = 0x0c, + .mcs = RATE_MCS(RATE_MODE_OFDM, 7), }, }; @@ -581,6 +625,8 @@ static int rt2x00lib_probe_hw_modes(struct rt2x00_dev *rt2x00dev, rt2x00dev->bands[IEEE80211_BAND_2GHZ].bitrates = rates; hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &rt2x00dev->bands[IEEE80211_BAND_2GHZ]; + memcpy(&rt2x00dev->bands[IEEE80211_BAND_2GHZ].ht_cap, + &spec->ht, sizeof(spec->ht)); } /* @@ -597,6 +643,8 @@ static int rt2x00lib_probe_hw_modes(struct rt2x00_dev *rt2x00dev, rt2x00dev->bands[IEEE80211_BAND_5GHZ].bitrates = &rates[4]; hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &rt2x00dev->bands[IEEE80211_BAND_5GHZ]; + memcpy(&rt2x00dev->bands[IEEE80211_BAND_5GHZ].ht_cap, + &spec->ht, sizeof(spec->ht)); } return 0; diff --git a/drivers/net/wireless/rt2x00/rt2x00ht.c b/drivers/net/wireless/rt2x00/rt2x00ht.c new file mode 100644 index 000000000000..e3cec839e540 --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2x00ht.c @@ -0,0 +1,69 @@ +/* + Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the + Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + Module: rt2x00lib + Abstract: rt2x00 HT specific routines. + */ + +#include +#include + +#include "rt2x00.h" +#include "rt2x00lib.h" + +void rt2x00ht_create_tx_descriptor(struct queue_entry *entry, + struct txentry_desc *txdesc, + const struct rt2x00_rate *hwrate) +{ + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb); + struct ieee80211_tx_rate *txrate = &tx_info->control.rates[0]; + + if (tx_info->control.sta) + txdesc->mpdu_density = + tx_info->control.sta->ht_cap.ampdu_density; + else + txdesc->mpdu_density = 0; + + txdesc->ba_size = 7; /* FIXME: What value is needed? */ + txdesc->stbc = 0; /* FIXME: What value is needed? */ + + txdesc->mcs = rt2x00_get_rate_mcs(hwrate->mcs); + if (txrate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) + txdesc->mcs |= 0x08; + + /* + * Convert flags + */ + if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) + __set_bit(ENTRY_TXD_HT_AMPDU, &txdesc->flags); + + /* + * Determine HT Mix/Greenfield rate mode + */ + if (txrate->flags & IEEE80211_TX_RC_MCS) + txdesc->rate_mode = RATE_MODE_HT_MIX; + if (txrate->flags & IEEE80211_TX_RC_GREEN_FIELD) + txdesc->rate_mode = RATE_MODE_HT_GREENFIELD; + if (txrate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) + __set_bit(ENTRY_TXD_HT_BW_40, &txdesc->flags); + if (txrate->flags & IEEE80211_TX_RC_SHORT_GI) + __set_bit(ENTRY_TXD_HT_SHORT_GI, &txdesc->flags); +} diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index a631613177d0..0bf2715fa93a 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -32,8 +32,8 @@ * Interval defines * Both the link tuner as the rfkill will be called once per second. */ -#define LINK_TUNE_INTERVAL ( round_jiffies_relative(HZ) ) -#define RFKILL_POLL_INTERVAL ( 1000 ) +#define LINK_TUNE_INTERVAL round_jiffies_relative(HZ) +#define RFKILL_POLL_INTERVAL 1000 /* * rt2x00_rate: Per rate device information @@ -48,6 +48,7 @@ struct rt2x00_rate { unsigned short ratemask; unsigned short plcp; + unsigned short mcs; }; extern const struct rt2x00_rate rt2x00_supported_rates[12]; @@ -57,6 +58,14 @@ static inline const struct rt2x00_rate *rt2x00_get_rate(const u16 hw_value) return &rt2x00_supported_rates[hw_value & 0xff]; } +#define RATE_MCS(__mode, __mcs) \ + ( (((__mode) & 0x00ff) << 8) | ((__mcs) & 0x00ff) ) + +static inline int rt2x00_get_rate_mcs(const u16 mcs_value) +{ + return (mcs_value & 0x00ff); +} + /* * Radio control handlers. */ @@ -112,6 +121,23 @@ void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb); */ void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb); +/** + * rt2x00queue_payload_align - Align 802.11 payload to 4-byte boundary + * @skb: The skb to align + * @l2pad: Should L2 padding be used + * @header_length: Length of 802.11 header + * + * This function prepares the @skb to be send to the device or mac80211. + * If @l2pad is set to true padding will occur between the 802.11 header + * and payload. Otherwise the padding will be done in front of the 802.11 + * header. + * When @l2pad is set the function will check for the &SKBDESC_L2_PADDED + * flag in &skb_frame_desc. If that flag is set, the padding is removed + * and the flag cleared. Otherwise the padding is added and the flag is set. + */ +void rt2x00queue_payload_align(struct sk_buff *skb, + bool l2pad, unsigned int header_length); + /** * rt2x00queue_write_tx_frame - Write TX frame to hardware * @queue: Queue over which the frame should be send @@ -235,7 +261,7 @@ void rt2x00link_reset_tuner(struct rt2x00_dev *rt2x00dev, bool antenna); * @rt2x00dev: Pointer to &struct rt2x00_dev. * * Initialize work structure and all link tuning related - * paramters. This will not start the link tuning process itself. + * parameters. This will not start the link tuning process itself. */ void rt2x00link_register(struct rt2x00_dev *rt2x00dev); @@ -295,10 +321,12 @@ void rt2x00crypto_create_tx_descriptor(struct queue_entry *entry, struct txentry_desc *txdesc); unsigned int rt2x00crypto_tx_overhead(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb); -void rt2x00crypto_tx_copy_iv(struct sk_buff *skb, unsigned int iv_len); -void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, unsigned int iv_len); -void rt2x00crypto_tx_insert_iv(struct sk_buff *skb); -void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, unsigned int align, +void rt2x00crypto_tx_copy_iv(struct sk_buff *skb, + struct txentry_desc *txdesc); +void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, + struct txentry_desc *txdesc); +void rt2x00crypto_tx_insert_iv(struct sk_buff *skb, unsigned int header_length); +void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, bool l2pad, unsigned int header_length, struct rxdone_entry_desc *rxdesc); #else @@ -319,27 +347,42 @@ static inline unsigned int rt2x00crypto_tx_overhead(struct rt2x00_dev *rt2x00dev } static inline void rt2x00crypto_tx_copy_iv(struct sk_buff *skb, - unsigned int iv_len) + struct txentry_desc *txdesc) { } static inline void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, - unsigned int iv_len) + struct txentry_desc *txdesc) { } -static inline void rt2x00crypto_tx_insert_iv(struct sk_buff *skb) +static inline void rt2x00crypto_tx_insert_iv(struct sk_buff *skb, + unsigned int header_length) { } -static inline void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, - unsigned int align, +static inline void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, bool l2pad, unsigned int header_length, struct rxdone_entry_desc *rxdesc) { } #endif /* CONFIG_RT2X00_LIB_CRYPTO */ +/* + * HT handlers. + */ +#ifdef CONFIG_RT2X00_LIB_HT +void rt2x00ht_create_tx_descriptor(struct queue_entry *entry, + struct txentry_desc *txdesc, + const struct rt2x00_rate *hwrate); +#else +static inline void rt2x00ht_create_tx_descriptor(struct queue_entry *entry, + struct txentry_desc *txdesc, + const struct rt2x00_rate *hwrate) +{ +} +#endif /* CONFIG_RT2X00_LIB_HT */ + /* * RFkill handlers. */ diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c index 7eb5cd7e5f32..eb9b981b9139 100644 --- a/drivers/net/wireless/rt2x00/rt2x00link.c +++ b/drivers/net/wireless/rt2x00/rt2x00link.c @@ -387,7 +387,7 @@ void rt2x00link_reset_tuner(struct rt2x00_dev *rt2x00dev, bool antenna) rt2x00link_antenna_reset(rt2x00dev); } -void rt2x00link_reset_qual(struct rt2x00_dev *rt2x00dev) +static void rt2x00link_reset_qual(struct rt2x00_dev *rt2x00dev) { struct link_qual *qual = &rt2x00dev->link.qual; diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index c41a0b9e473d..c4c06b4e1f08 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -390,56 +390,6 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed) } EXPORT_SYMBOL_GPL(rt2x00mac_config); -int rt2x00mac_config_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_if_conf *conf) -{ - struct rt2x00_dev *rt2x00dev = hw->priv; - struct rt2x00_intf *intf = vif_to_intf(vif); - int update_bssid = 0; - int status = 0; - - /* - * Mac80211 might be calling this function while we are trying - * to remove the device or perhaps suspending it. - */ - if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) - return 0; - - spin_lock(&intf->lock); - - /* - * conf->bssid can be NULL if coming from the internal - * beacon update routine. - */ - if (conf->changed & IEEE80211_IFCC_BSSID && conf->bssid) { - update_bssid = 1; - memcpy(&intf->bssid, conf->bssid, ETH_ALEN); - } - - spin_unlock(&intf->lock); - - /* - * Call rt2x00_config_intf() outside of the spinlock context since - * the call will sleep for USB drivers. By using the ieee80211_if_conf - * values as arguments we make keep access to rt2x00_intf thread safe - * even without the lock. - */ - rt2x00lib_config_intf(rt2x00dev, intf, vif->type, NULL, - update_bssid ? conf->bssid : NULL); - - /* - * Update the beacon. - */ - if (conf->changed & (IEEE80211_IFCC_BEACON | - IEEE80211_IFCC_BEACON_ENABLED)) - status = rt2x00queue_update_beacon(rt2x00dev, vif, - conf->enable_beacon); - - return status; -} -EXPORT_SYMBOL_GPL(rt2x00mac_config_interface); - void rt2x00mac_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, @@ -623,6 +573,44 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, struct rt2x00_dev *rt2x00dev = hw->priv; struct rt2x00_intf *intf = vif_to_intf(vif); unsigned int delayed = 0; + int update_bssid = 0; + + /* + * Mac80211 might be calling this function while we are trying + * to remove the device or perhaps suspending it. + */ + if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) + return; + + spin_lock(&intf->lock); + + /* + * conf->bssid can be NULL if coming from the internal + * beacon update routine. + */ + if (changes & BSS_CHANGED_BSSID) { + update_bssid = 1; + memcpy(&intf->bssid, bss_conf->bssid, ETH_ALEN); + } + + spin_unlock(&intf->lock); + + /* + * Call rt2x00_config_intf() outside of the spinlock context since + * the call will sleep for USB drivers. By using the ieee80211_if_conf + * values as arguments we make keep access to rt2x00_intf thread safe + * even without the lock. + */ + if (changes & BSS_CHANGED_BSSID) + rt2x00lib_config_intf(rt2x00dev, intf, vif->type, NULL, + update_bssid ? bss_conf->bssid : NULL); + + /* + * Update the beacon. + */ + if (changes & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED)) + rt2x00queue_update_beacon(rt2x00dev, vif, + bss_conf->enable_beacon); /* * When the association status has changed we must reset the link diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c index 9730b4f8fd26..cdd5154bd4c0 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c @@ -170,7 +170,6 @@ static void rt2x00pci_free_queue_dma(struct rt2x00_dev *rt2x00dev, int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev) { - struct pci_dev *pci_dev = to_pci_dev(rt2x00dev->dev); struct data_queue *queue; int status; @@ -186,11 +185,11 @@ int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev) /* * Register interrupt handler. */ - status = request_irq(pci_dev->irq, rt2x00dev->ops->lib->irq_handler, - IRQF_SHARED, pci_name(pci_dev), rt2x00dev); + status = request_irq(rt2x00dev->irq, rt2x00dev->ops->lib->irq_handler, + IRQF_SHARED, rt2x00dev->name, rt2x00dev); if (status) { ERROR(rt2x00dev, "IRQ %d allocation failed (error %d).\n", - pci_dev->irq, status); + rt2x00dev->irq, status); goto exit; } @@ -270,6 +269,7 @@ int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) struct ieee80211_hw *hw; struct rt2x00_dev *rt2x00dev; int retval; + u16 chip; retval = pci_request_regions(pci_dev, pci_name(pci_dev)); if (retval) { @@ -307,6 +307,14 @@ int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) rt2x00dev->dev = &pci_dev->dev; rt2x00dev->ops = ops; rt2x00dev->hw = hw; + rt2x00dev->irq = pci_dev->irq; + rt2x00dev->name = pci_name(pci_dev); + + /* + * Determine RT chipset by reading PCI header. + */ + pci_read_config_word(pci_dev, PCI_DEVICE_ID, &chip); + rt2x00_set_chip_rt(rt2x00dev, chip); retval = rt2x00pci_alloc_reg(rt2x00dev); if (retval) diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index a5664bd8493e..44e5b3279ca7 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -148,6 +148,35 @@ void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb) dev_kfree_skb_any(skb); } +void rt2x00queue_payload_align(struct sk_buff *skb, + bool l2pad, unsigned int header_length) +{ + struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); + unsigned int frame_length = skb->len; + unsigned int align = ALIGN_SIZE(skb, header_length); + + if (!align) + return; + + if (l2pad) { + if (skbdesc->flags & SKBDESC_L2_PADDED) { + /* Remove L2 padding */ + memmove(skb->data + align, skb->data, header_length); + skb_pull(skb, align); + skbdesc->flags &= ~SKBDESC_L2_PADDED; + } else { + /* Add L2 padding */ + skb_push(skb, align); + memmove(skb->data, skb->data + align, header_length); + skbdesc->flags |= SKBDESC_L2_PADDED; + } + } else { + /* Generic payload alignment to 4-byte boundary */ + skb_push(skb, align); + memmove(skb->data, skb->data + align, frame_length); + } +} + static void rt2x00queue_create_tx_descriptor_seq(struct queue_entry *entry, struct txentry_desc *txdesc) { @@ -258,6 +287,12 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, txdesc->cw_max = entry->queue->cw_max; txdesc->aifs = entry->queue->aifs; + /* + * Header and alignment information. + */ + txdesc->header_length = ieee80211_get_hdrlen_from_skb(entry->skb); + txdesc->l2pad = ALIGN_SIZE(entry->skb, txdesc->header_length); + /* * Check whether this frame is to be acked. */ @@ -326,6 +361,7 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, * Apply TX descriptor handling by components */ rt2x00crypto_create_tx_descriptor(entry, txdesc); + rt2x00ht_create_tx_descriptor(entry, txdesc, hwrate); rt2x00queue_create_tx_descriptor_seq(entry, txdesc); rt2x00queue_create_tx_descriptor_plcp(entry, txdesc, hwrate); } @@ -368,7 +404,6 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb) struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX); struct txentry_desc txdesc; struct skb_frame_desc *skbdesc; - unsigned int iv_len = 0; u8 rate_idx, rate_flags; if (unlikely(rt2x00queue_full(queue))) @@ -390,9 +425,6 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb) entry->skb = skb; rt2x00queue_create_tx_descriptor(entry, &txdesc); - if (IEEE80211_SKB_CB(skb)->control.hw_key != NULL) - iv_len = IEEE80211_SKB_CB(skb)->control.hw_key->iv_len; - /* * All information is retrieved from the skb->cb array, * now we should claim ownership of the driver part of that @@ -415,11 +447,15 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb) if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc.flags) && !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc.flags)) { if (test_bit(DRIVER_REQUIRE_COPY_IV, &queue->rt2x00dev->flags)) - rt2x00crypto_tx_copy_iv(skb, iv_len); + rt2x00crypto_tx_copy_iv(skb, &txdesc); else - rt2x00crypto_tx_remove_iv(skb, iv_len); + rt2x00crypto_tx_remove_iv(skb, &txdesc); } + if (test_bit(DRIVER_REQUIRE_L2PAD, &queue->rt2x00dev->flags)) + rt2x00queue_payload_align(entry->skb, true, + txdesc.header_length); + /* * It could be possible that the queue was corrupted and this * call failed. Since we always return NETDEV_TX_OK to mac80211, diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index 97e2ab08f080..b5e06347c8a7 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -35,9 +35,12 @@ * for USB devices this restriction does not apply, but the value of * 2432 makes sense since it is big enough to contain the maximum fragment * size according to the ieee802.11 specs. + * The aggregation size depends on support from the driver, but should + * be something around 3840 bytes. */ -#define DATA_FRAME_SIZE 2432 -#define MGMT_FRAME_SIZE 256 +#define DATA_FRAME_SIZE 2432 +#define MGMT_FRAME_SIZE 256 +#define AGGREGATION_SIZE 3840 /** * DOC: Number of entries per queue @@ -87,13 +90,16 @@ enum data_queue_qid { * * @SKBDESC_DMA_MAPPED_RX: &skb_dma field has been mapped for RX * @SKBDESC_DMA_MAPPED_TX: &skb_dma field has been mapped for TX - * @FRAME_DESC_IV_STRIPPED: Frame contained a IV/EIV provided by + * @SKBDESC_IV_STRIPPED: Frame contained a IV/EIV provided by * mac80211 but was stripped for processing by the driver. + * @SKBDESC_L2_PADDED: Payload has been padded for 4-byte alignment, + * the padded bytes are located between header and payload. */ enum skb_frame_desc_flags { SKBDESC_DMA_MAPPED_RX = 1 << 0, SKBDESC_DMA_MAPPED_TX = 1 << 1, - FRAME_DESC_IV_STRIPPED = 1 << 2, + SKBDESC_IV_STRIPPED = 1 << 2, + SKBDESC_L2_PADDED = 1 << 3 }; /** @@ -145,16 +151,20 @@ static inline struct skb_frame_desc* get_skb_frame_desc(struct sk_buff *skb) * * @RXDONE_SIGNAL_PLCP: Signal field contains the plcp value. * @RXDONE_SIGNAL_BITRATE: Signal field contains the bitrate value. + * @RXDONE_SIGNAL_MCS: Signal field contains the mcs value. * @RXDONE_MY_BSS: Does this frame originate from device's BSS. * @RXDONE_CRYPTO_IV: Driver provided IV/EIV data. * @RXDONE_CRYPTO_ICV: Driver provided ICV data. + * @RXDONE_L2PAD: 802.11 payload has been padded to 4-byte boundary. */ enum rxdone_entry_desc_flags { - RXDONE_SIGNAL_PLCP = 1 << 0, - RXDONE_SIGNAL_BITRATE = 1 << 1, - RXDONE_MY_BSS = 1 << 2, - RXDONE_CRYPTO_IV = 1 << 3, - RXDONE_CRYPTO_ICV = 1 << 4, + RXDONE_SIGNAL_PLCP = BIT(0), + RXDONE_SIGNAL_BITRATE = BIT(1), + RXDONE_SIGNAL_MCS = BIT(2), + RXDONE_MY_BSS = BIT(3), + RXDONE_CRYPTO_IV = BIT(4), + RXDONE_CRYPTO_ICV = BIT(5), + RXDONE_L2PAD = BIT(6), }; /** @@ -163,7 +173,7 @@ enum rxdone_entry_desc_flags { * from &rxdone_entry_desc to a signal value type. */ #define RXDONE_SIGNAL_MASK \ - ( RXDONE_SIGNAL_PLCP | RXDONE_SIGNAL_BITRATE ) + ( RXDONE_SIGNAL_PLCP | RXDONE_SIGNAL_BITRATE | RXDONE_SIGNAL_MCS ) /** * struct rxdone_entry_desc: RX Entry descriptor @@ -177,6 +187,7 @@ enum rxdone_entry_desc_flags { * @size: Data size of the received frame. * @flags: MAC80211 receive flags (See &enum mac80211_rx_flags). * @dev_flags: Ralink receive flags (See &enum rxdone_entry_desc_flags). + * @rate_mode: Rate mode (See @enum rate_modulation). * @cipher: Cipher type used during decryption. * @cipher_status: Decryption status. * @iv: IV/EIV data used during decryption. @@ -190,6 +201,7 @@ struct rxdone_entry_desc { int size; int flags; int dev_flags; + u16 rate_mode; u8 cipher; u8 cipher_status; @@ -243,6 +255,9 @@ struct txdone_entry_desc { * @ENTRY_TXD_ENCRYPT_PAIRWISE: Use pairwise key table (instead of shared). * @ENTRY_TXD_ENCRYPT_IV: Generate IV/EIV in hardware. * @ENTRY_TXD_ENCRYPT_MMIC: Generate MIC in hardware. + * @ENTRY_TXD_HT_AMPDU: This frame is part of an AMPDU. + * @ENTRY_TXD_HT_BW_40: Use 40MHz Bandwidth. + * @ENTRY_TXD_HT_SHORT_GI: Use short GI. */ enum txentry_desc_flags { ENTRY_TXD_RTS_FRAME, @@ -258,6 +273,9 @@ enum txentry_desc_flags { ENTRY_TXD_ENCRYPT_PAIRWISE, ENTRY_TXD_ENCRYPT_IV, ENTRY_TXD_ENCRYPT_MMIC, + ENTRY_TXD_HT_AMPDU, + ENTRY_TXD_HT_BW_40, + ENTRY_TXD_HT_SHORT_GI, }; /** @@ -267,11 +285,17 @@ enum txentry_desc_flags { * * @flags: Descriptor flags (See &enum queue_entry_flags). * @queue: Queue identification (See &enum data_queue_qid). + * @header_length: Length of 802.11 header. + * @l2pad: Amount of padding to align 802.11 payload to 4-byte boundrary. * @length_high: PLCP length high word. * @length_low: PLCP length low word. * @signal: PLCP signal. * @service: PLCP service. + * @msc: MCS. + * @stbc: STBC. + * @ba_size: BA size. * @rate_mode: Rate mode (See @enum rate_modulation). + * @mpdu_density: MDPU density. * @retry_limit: Max number of retries. * @aifs: AIFS value. * @ifs: IFS value. @@ -280,18 +304,26 @@ enum txentry_desc_flags { * @cipher: Cipher type used for encryption. * @key_idx: Key index used for encryption. * @iv_offset: Position where IV should be inserted by hardware. + * @iv_len: Length of IV data. */ struct txentry_desc { unsigned long flags; enum data_queue_qid queue; + u16 header_length; + u16 l2pad; + u16 length_high; u16 length_low; u16 signal; u16 service; + u16 mcs; + u16 stbc; + u16 ba_size; u16 rate_mode; + u16 mpdu_density; short retry_limit; short aifs; @@ -302,6 +334,7 @@ struct txentry_desc { enum cipher cipher; u16 key_idx; u16 iv_offset; + u16 iv_len; }; /** diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 2ca8b7a9722c..49b29ff90c47 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -603,15 +603,22 @@ static void rt61pci_config_erp(struct rt2x00_dev *rt2x00dev, rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, ®); rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, erp->ack_timeout); + rt2x00_set_field32(®, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER); rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg); rt2x00pci_register_read(rt2x00dev, TXRX_CSR4, ®); + rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_ENABLE, 1); rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_PREAMBLE, !!erp->short_preamble); rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg); rt2x00pci_register_write(rt2x00dev, TXRX_CSR5, erp->basic_rates); + rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, ®); + rt2x00_set_field32(®, TXRX_CSR9_BEACON_INTERVAL, + erp->beacon_int * 16); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg); + rt2x00pci_register_read(rt2x00dev, MAC_CSR9, ®); rt2x00_set_field32(®, MAC_CSR9_SLOT_TIME, erp->slot_time); rt2x00pci_register_write(rt2x00dev, MAC_CSR9, reg); @@ -938,25 +945,6 @@ static void rt61pci_config_retry_limit(struct rt2x00_dev *rt2x00dev, rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg); } -static void rt61pci_config_duration(struct rt2x00_dev *rt2x00dev, - struct rt2x00lib_conf *libconf) -{ - u32 reg; - - rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, ®); - rt2x00_set_field32(®, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER); - rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg); - - rt2x00pci_register_read(rt2x00dev, TXRX_CSR4, ®); - rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_ENABLE, 1); - rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg); - - rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, ®); - rt2x00_set_field32(®, TXRX_CSR9_BEACON_INTERVAL, - libconf->conf->beacon_int * 16); - rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg); -} - static void rt61pci_config_ps(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_conf *libconf) { @@ -968,7 +956,7 @@ static void rt61pci_config_ps(struct rt2x00_dev *rt2x00dev, if (state == STATE_SLEEP) { rt2x00pci_register_read(rt2x00dev, MAC_CSR11, ®); rt2x00_set_field32(®, MAC_CSR11_DELAY_AFTER_TBCN, - libconf->conf->beacon_int - 10); + rt2x00dev->beacon_int - 10); rt2x00_set_field32(®, MAC_CSR11_TBCN_BEFORE_WAKEUP, libconf->conf->listen_interval - 1); rt2x00_set_field32(®, MAC_CSR11_WAKEUP_LATENCY, 5); @@ -1016,8 +1004,6 @@ static void rt61pci_config(struct rt2x00_dev *rt2x00dev, rt61pci_config_txpower(rt2x00dev, libconf->conf->power_level); if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS) rt61pci_config_retry_limit(rt2x00dev, libconf); - if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL) - rt61pci_config_duration(rt2x00dev, libconf); if (flags & IEEE80211_CONF_CHANGE_PS) rt61pci_config_ps(rt2x00dev, libconf); } @@ -2308,7 +2294,6 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) u32 reg; u16 value; u16 eeprom; - u16 device; /* * Read EEPROM word for configuration. @@ -2317,14 +2302,10 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Identify RF chipset. - * To determine the RT chip we have to read the - * PCI header of the device. */ - pci_read_config_word(to_pci_dev(rt2x00dev->dev), - PCI_CONFIG_HEADER_DEVICE, &device); value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); rt2x00pci_register_read(rt2x00dev, MAC_CSR0, ®); - rt2x00_set_chip(rt2x00dev, device, value, reg); + rt2x00_set_chip_rf(rt2x00dev, value, reg); if (!rt2x00_rf(&rt2x00dev->chip, RF5225) && !rt2x00_rf(&rt2x00dev->chip, RF5325) && @@ -2740,7 +2721,6 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = { .add_interface = rt2x00mac_add_interface, .remove_interface = rt2x00mac_remove_interface, .config = rt2x00mac_config, - .config_interface = rt2x00mac_config_interface, .configure_filter = rt2x00mac_configure_filter, .set_key = rt2x00mac_set_key, .get_stats = rt2x00mac_get_stats, diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h index 41e8959919f6..6c71f77c8165 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.h +++ b/drivers/net/wireless/rt2x00/rt61pci.h @@ -62,12 +62,6 @@ * PCI registers. */ -/* - * PCI Configuration Header - */ -#define PCI_CONFIG_HEADER_VENDOR 0x0000 -#define PCI_CONFIG_HEADER_DEVICE 0x0002 - /* * HOST_CMD_CSR: For HOST to interrupt embedded processor */ diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 853b2b279b64..c18848836f2d 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -566,15 +566,22 @@ static void rt73usb_config_erp(struct rt2x00_dev *rt2x00dev, rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, ®); rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, erp->ack_timeout); + rt2x00_set_field32(®, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER); rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg); rt2x00usb_register_read(rt2x00dev, TXRX_CSR4, ®); + rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_ENABLE, 1); rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_PREAMBLE, !!erp->short_preamble); rt2x00usb_register_write(rt2x00dev, TXRX_CSR4, reg); rt2x00usb_register_write(rt2x00dev, TXRX_CSR5, erp->basic_rates); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, ®); + rt2x00_set_field32(®, TXRX_CSR9_BEACON_INTERVAL, + erp->beacon_int * 16); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg); + rt2x00usb_register_read(rt2x00dev, MAC_CSR9, ®); rt2x00_set_field32(®, MAC_CSR9_SLOT_TIME, erp->slot_time); rt2x00usb_register_write(rt2x00dev, MAC_CSR9, reg); @@ -834,25 +841,6 @@ static void rt73usb_config_retry_limit(struct rt2x00_dev *rt2x00dev, rt2x00usb_register_write(rt2x00dev, TXRX_CSR4, reg); } -static void rt73usb_config_duration(struct rt2x00_dev *rt2x00dev, - struct rt2x00lib_conf *libconf) -{ - u32 reg; - - rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, ®); - rt2x00_set_field32(®, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER); - rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg); - - rt2x00usb_register_read(rt2x00dev, TXRX_CSR4, ®); - rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_ENABLE, 1); - rt2x00usb_register_write(rt2x00dev, TXRX_CSR4, reg); - - rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, ®); - rt2x00_set_field32(®, TXRX_CSR9_BEACON_INTERVAL, - libconf->conf->beacon_int * 16); - rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg); -} - static void rt73usb_config_ps(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_conf *libconf) { @@ -864,7 +852,7 @@ static void rt73usb_config_ps(struct rt2x00_dev *rt2x00dev, if (state == STATE_SLEEP) { rt2x00usb_register_read(rt2x00dev, MAC_CSR11, ®); rt2x00_set_field32(®, MAC_CSR11_DELAY_AFTER_TBCN, - libconf->conf->beacon_int - 10); + rt2x00dev->beacon_int - 10); rt2x00_set_field32(®, MAC_CSR11_TBCN_BEFORE_WAKEUP, libconf->conf->listen_interval - 1); rt2x00_set_field32(®, MAC_CSR11_WAKEUP_LATENCY, 5); @@ -906,8 +894,6 @@ static void rt73usb_config(struct rt2x00_dev *rt2x00dev, rt73usb_config_txpower(rt2x00dev, libconf->conf->power_level); if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS) rt73usb_config_retry_limit(rt2x00dev, libconf); - if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL) - rt73usb_config_duration(rt2x00dev, libconf); if (flags & IEEE80211_CONF_CHANGE_PS) rt73usb_config_ps(rt2x00dev, libconf); } @@ -1846,7 +1832,8 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00usb_register_read(rt2x00dev, MAC_CSR0, ®); rt2x00_set_chip(rt2x00dev, RT2571, value, reg); - if (!rt2x00_check_rev(&rt2x00dev->chip, 0x25730)) { + if (!rt2x00_check_rev(&rt2x00dev->chip, 0x000ffff0, 0x25730) || + rt2x00_check_rev(&rt2x00dev->chip, 0x0000000f, 0)) { ERROR(rt2x00dev, "Invalid RT chipset detected.\n"); return -ENODEV; } @@ -2259,7 +2246,6 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = { .add_interface = rt2x00mac_add_interface, .remove_interface = rt2x00mac_remove_interface, .config = rt2x00mac_config, - .config_interface = rt2x00mac_config_interface, .configure_filter = rt2x00mac_configure_filter, .set_key = rt2x00mac_set_key, .get_stats = rt2x00mac_get_stats, diff --git a/drivers/net/wireless/rtl818x/Makefile b/drivers/net/wireless/rtl818x/Makefile index c113b3e69046..37e3d4db0c40 100644 --- a/drivers/net/wireless/rtl818x/Makefile +++ b/drivers/net/wireless/rtl818x/Makefile @@ -1,5 +1,5 @@ rtl8180-objs := rtl8180_dev.o rtl8180_rtl8225.o rtl8180_sa2400.o rtl8180_max2820.o rtl8180_grf5101.o -rtl8187-objs := rtl8187_dev.o rtl8187_rtl8225.o +rtl8187-objs := rtl8187_dev.o rtl8187_rtl8225.o rtl8187_leds.o obj-$(CONFIG_RTL8180) += rtl8180.o obj-$(CONFIG_RTL8187) += rtl8187.o diff --git a/drivers/net/wireless/rtl818x/rtl8180_dev.c b/drivers/net/wireless/rtl818x/rtl8180_dev.c index 387c133ec0f2..7e65d7c31802 100644 --- a/drivers/net/wireless/rtl818x/rtl8180_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180_dev.c @@ -702,30 +702,26 @@ static int rtl8180_config(struct ieee80211_hw *dev, u32 changed) return 0; } -static int rtl8180_config_interface(struct ieee80211_hw *dev, - struct ieee80211_vif *vif, - struct ieee80211_if_conf *conf) -{ - struct rtl8180_priv *priv = dev->priv; - int i; - - for (i = 0; i < ETH_ALEN; i++) - rtl818x_iowrite8(priv, &priv->map->BSSID[i], conf->bssid[i]); - - if (is_valid_ether_addr(conf->bssid)) - rtl818x_iowrite8(priv, &priv->map->MSR, RTL818X_MSR_INFRA); - else - rtl818x_iowrite8(priv, &priv->map->MSR, RTL818X_MSR_NO_LINK); - - return 0; -} - static void rtl8180_bss_info_changed(struct ieee80211_hw *dev, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, u32 changed) { struct rtl8180_priv *priv = dev->priv; + int i; + + if (changed & BSS_CHANGED_BSSID) { + for (i = 0; i < ETH_ALEN; i++) + rtl818x_iowrite8(priv, &priv->map->BSSID[i], + info->bssid[i]); + + if (is_valid_ether_addr(info->bssid)) + rtl818x_iowrite8(priv, &priv->map->MSR, + RTL818X_MSR_INFRA); + else + rtl818x_iowrite8(priv, &priv->map->MSR, + RTL818X_MSR_NO_LINK); + } if (changed & BSS_CHANGED_ERP_SLOT && priv->rf->conf_erp) priv->rf->conf_erp(dev, info); @@ -770,7 +766,6 @@ static const struct ieee80211_ops rtl8180_ops = { .add_interface = rtl8180_add_interface, .remove_interface = rtl8180_remove_interface, .config = rtl8180_config, - .config_interface = rtl8180_config_interface, .bss_info_changed = rtl8180_bss_info_changed, .configure_filter = rtl8180_configure_filter, }; diff --git a/drivers/net/wireless/rtl818x/rtl8187.h b/drivers/net/wireless/rtl818x/rtl8187.h index edeff82a4d06..c09bfefc70f3 100644 --- a/drivers/net/wireless/rtl818x/rtl8187.h +++ b/drivers/net/wireless/rtl818x/rtl8187.h @@ -16,6 +16,7 @@ #define RTL8187_H #include "rtl818x.h" +#include "rtl8187_leds.h" #define RTL8187_EEPROM_TXPWR_BASE 0x05 #define RTL8187_EEPROM_MAC_ADDR 0x07 @@ -102,6 +103,12 @@ struct rtl8187_priv { struct usb_anchor anchored; struct delayed_work work; struct ieee80211_hw *dev; +#ifdef CONFIG_RTL8187_LEDS + struct rtl8187_led led_tx; + struct rtl8187_led led_rx; + struct delayed_work led_on; + struct delayed_work led_off; +#endif u16 txpwr_base; u8 asic_rev; u8 is_rtl8187b; diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c index d51ba0a88c23..294250e294dd 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c @@ -29,6 +29,9 @@ #include "rtl8187.h" #include "rtl8187_rtl8225.h" +#ifdef CONFIG_RTL8187_LEDS +#include "rtl8187_leds.h" +#endif MODULE_AUTHOR("Michael Wu "); MODULE_AUTHOR("Andrea Merello "); @@ -320,12 +323,7 @@ static void rtl8187_rx_cb(struct urb *urb) unsigned long f; spin_lock_irqsave(&priv->rx_queue.lock, f); - if (skb->next) - __skb_unlink(skb, &priv->rx_queue); - else { - spin_unlock_irqrestore(&priv->rx_queue.lock, f); - return; - } + __skb_unlink(skb, &priv->rx_queue); spin_unlock_irqrestore(&priv->rx_queue.lock, f); skb_put(skb, urb->actual_length); @@ -736,10 +734,10 @@ static const u8 rtl8187b_reg_table[][3] = { {0x85, 0x24, 0}, {0x88, 0x54, 0}, {0x8B, 0xB8, 0}, {0x8C, 0x07, 0}, {0x8D, 0x00, 0}, {0x94, 0x1B, 0}, {0x95, 0x12, 0}, {0x96, 0x00, 0}, {0x97, 0x06, 0}, {0x9D, 0x1A, 0}, {0x9F, 0x10, 0}, {0xB4, 0x22, 0}, - {0xBE, 0x80, 0}, {0xDB, 0x00, 0}, {0xEE, 0x00, 0}, {0x91, 0x03, 0}, + {0xBE, 0x80, 0}, {0xDB, 0x00, 0}, {0xEE, 0x00, 0}, {0x4C, 0x00, 2}, - {0x4C, 0x00, 2}, {0x9F, 0x00, 3}, {0x8C, 0x01, 0}, {0x8D, 0x10, 0}, - {0x8E, 0x08, 0}, {0x8F, 0x00, 0} + {0x9F, 0x00, 3}, {0x8C, 0x01, 0}, {0x8D, 0x10, 0}, {0x8E, 0x08, 0}, + {0x8F, 0x00, 0} }; static int rtl8187b_init_hw(struct ieee80211_hw *dev) @@ -1089,32 +1087,6 @@ static int rtl8187_config(struct ieee80211_hw *dev, u32 changed) return 0; } -static int rtl8187_config_interface(struct ieee80211_hw *dev, - struct ieee80211_vif *vif, - struct ieee80211_if_conf *conf) -{ - struct rtl8187_priv *priv = dev->priv; - int i; - u8 reg; - - mutex_lock(&priv->conf_mutex); - for (i = 0; i < ETH_ALEN; i++) - rtl818x_iowrite8(priv, &priv->map->BSSID[i], conf->bssid[i]); - - if (is_valid_ether_addr(conf->bssid)) { - reg = RTL818X_MSR_INFRA; - if (priv->is_rtl8187b) - reg |= RTL818X_MSR_ENEDCA; - rtl818x_iowrite8(priv, &priv->map->MSR, reg); - } else { - reg = RTL818X_MSR_NO_LINK; - rtl818x_iowrite8(priv, &priv->map->MSR, reg); - } - - mutex_unlock(&priv->conf_mutex); - return 0; -} - /* * With 8187B, AC_*_PARAM clashes with FEMR definition in struct rtl818x_csr for * example. Thus we have to use raw values for AC_*_PARAM register addresses. @@ -1192,6 +1164,27 @@ static void rtl8187_bss_info_changed(struct ieee80211_hw *dev, u32 changed) { struct rtl8187_priv *priv = dev->priv; + int i; + u8 reg; + + if (changed & BSS_CHANGED_BSSID) { + mutex_lock(&priv->conf_mutex); + for (i = 0; i < ETH_ALEN; i++) + rtl818x_iowrite8(priv, &priv->map->BSSID[i], + info->bssid[i]); + + if (is_valid_ether_addr(info->bssid)) { + reg = RTL818X_MSR_INFRA; + if (priv->is_rtl8187b) + reg |= RTL818X_MSR_ENEDCA; + rtl818x_iowrite8(priv, &priv->map->MSR, reg); + } else { + reg = RTL818X_MSR_NO_LINK; + rtl818x_iowrite8(priv, &priv->map->MSR, reg); + } + + mutex_unlock(&priv->conf_mutex); + } if (changed & (BSS_CHANGED_ERP_SLOT | BSS_CHANGED_ERP_PREAMBLE)) rtl8187_conf_erp(priv, info->use_short_slot, @@ -1273,7 +1266,6 @@ static const struct ieee80211_ops rtl8187_ops = { .add_interface = rtl8187_add_interface, .remove_interface = rtl8187_remove_interface, .config = rtl8187_config, - .config_interface = rtl8187_config_interface, .bss_info_changed = rtl8187_bss_info_changed, .configure_filter = rtl8187_configure_filter, .conf_tx = rtl8187_conf_tx @@ -1480,9 +1472,6 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, (*channel++).hw_value = txpwr >> 8; } - if (priv->is_rtl8187b) - printk(KERN_WARNING "rtl8187: 8187B chip detected.\n"); - /* * XXX: Once this driver supports anything that requires * beacons it must implement IEEE80211_TX_CTL_ASSIGN_SEQ. @@ -1514,6 +1503,12 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, wiphy_name(dev->wiphy), dev->wiphy->perm_addr, chip_name, priv->asic_rev, priv->rf->name); +#ifdef CONFIG_RTL8187_LEDS + eeprom_93cx6_read(&eeprom, 0x3F, ®); + reg &= 0xFF; + rtl8187_leds_init(dev, reg); +#endif + return 0; err_free_dmabuf: @@ -1533,6 +1528,9 @@ static void __devexit rtl8187_disconnect(struct usb_interface *intf) if (!dev) return; +#ifdef CONFIG_RTL8187_LEDS + rtl8187_leds_exit(dev); +#endif ieee80211_unregister_hw(dev); priv = dev->priv; diff --git a/drivers/net/wireless/rtl818x/rtl8187_leds.c b/drivers/net/wireless/rtl818x/rtl8187_leds.c new file mode 100644 index 000000000000..b44253592243 --- /dev/null +++ b/drivers/net/wireless/rtl818x/rtl8187_leds.c @@ -0,0 +1,218 @@ +/* + * Linux LED driver for RTL8187 + * + * Copyright 2009 Larry Finger + * + * Based on the LED handling in the r8187 driver, which is: + * Copyright (c) Realtek Semiconductor Corp. All rights reserved. + * + * Thanks to Realtek for their support! + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifdef CONFIG_RTL8187_LEDS + +#include +#include +#include + +#include "rtl8187.h" +#include "rtl8187_leds.h" + +static void led_turn_on(struct work_struct *work) +{ + /* As this routine does read/write operations on the hardware, it must + * be run from a work queue. + */ + u8 reg; + struct rtl8187_priv *priv = container_of(work, struct rtl8187_priv, + led_on.work); + struct rtl8187_led *led = &priv->led_tx; + + /* Don't change the LED, when the device is down. */ + if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) + return ; + + /* Skip if the LED is not registered. */ + if (!led->dev) + return; + mutex_lock(&priv->conf_mutex); + switch (led->ledpin) { + case LED_PIN_GPIO0: + rtl818x_iowrite8(priv, &priv->map->GPIO, 0x01); + rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0x00); + break; + case LED_PIN_LED0: + reg = rtl818x_ioread8(priv, &priv->map->PGSELECT) & ~(1 << 4); + rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg); + break; + case LED_PIN_LED1: + reg = rtl818x_ioread8(priv, &priv->map->PGSELECT) & ~(1 << 5); + rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg); + break; + case LED_PIN_HW: + default: + break; + } + mutex_unlock(&priv->conf_mutex); +} + +static void led_turn_off(struct work_struct *work) +{ + /* As this routine does read/write operations on the hardware, it must + * be run from a work queue. + */ + u8 reg; + struct rtl8187_priv *priv = container_of(work, struct rtl8187_priv, + led_off.work); + struct rtl8187_led *led = &priv->led_tx; + + /* Don't change the LED, when the device is down. */ + if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) + return ; + + /* Skip if the LED is not registered. */ + if (!led->dev) + return; + mutex_lock(&priv->conf_mutex); + switch (led->ledpin) { + case LED_PIN_GPIO0: + rtl818x_iowrite8(priv, &priv->map->GPIO, 0x01); + rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0x01); + break; + case LED_PIN_LED0: + reg = rtl818x_ioread8(priv, &priv->map->PGSELECT) | (1 << 4); + rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg); + break; + case LED_PIN_LED1: + reg = rtl818x_ioread8(priv, &priv->map->PGSELECT) | (1 << 5); + rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg); + break; + case LED_PIN_HW: + default: + break; + } + mutex_unlock(&priv->conf_mutex); +} + +/* Callback from the LED subsystem. */ +static void rtl8187_led_brightness_set(struct led_classdev *led_dev, + enum led_brightness brightness) +{ + struct rtl8187_led *led = container_of(led_dev, struct rtl8187_led, + led_dev); + struct ieee80211_hw *hw = led->dev; + struct rtl8187_priv *priv = hw->priv; + + if (brightness == LED_OFF) { + queue_delayed_work(hw->workqueue, &priv->led_off, 0); + /* The LED is off for 1/20 sec so that it just blinks. */ + queue_delayed_work(hw->workqueue, &priv->led_on, HZ / 20); + } else + queue_delayed_work(hw->workqueue, &priv->led_on, 0); +} + +static int rtl8187_register_led(struct ieee80211_hw *dev, + struct rtl8187_led *led, const char *name, + const char *default_trigger, u8 ledpin) +{ + int err; + struct rtl8187_priv *priv = dev->priv; + + if (led->dev) + return -EEXIST; + if (!default_trigger) + return -EINVAL; + led->dev = dev; + led->ledpin = ledpin; + strncpy(led->name, name, sizeof(led->name)); + + led->led_dev.name = led->name; + led->led_dev.default_trigger = default_trigger; + led->led_dev.brightness_set = rtl8187_led_brightness_set; + + err = led_classdev_register(&priv->udev->dev, &led->led_dev); + if (err) { + printk(KERN_INFO "LEDs: Failed to register %s\n", name); + led->dev = NULL; + return err; + } + return 0; +} + +static void rtl8187_unregister_led(struct rtl8187_led *led) +{ + led_classdev_unregister(&led->led_dev); + led->dev = NULL; +} + +void rtl8187_leds_init(struct ieee80211_hw *dev, u16 custid) +{ + struct rtl8187_priv *priv = dev->priv; + char name[RTL8187_LED_MAX_NAME_LEN + 1]; + u8 ledpin; + int err; + + /* According to the vendor driver, the LED operation depends on the + * customer ID encoded in the EEPROM + */ + printk(KERN_INFO "rtl8187: Customer ID is 0x%02X\n", custid); + switch (custid) { + case EEPROM_CID_RSVD0: + case EEPROM_CID_RSVD1: + case EEPROM_CID_SERCOMM_PS: + case EEPROM_CID_QMI: + case EEPROM_CID_DELL: + case EEPROM_CID_TOSHIBA: + ledpin = LED_PIN_GPIO0; + break; + case EEPROM_CID_ALPHA0: + ledpin = LED_PIN_LED0; + break; + case EEPROM_CID_HW: + ledpin = LED_PIN_HW; + break; + default: + ledpin = LED_PIN_GPIO0; + } + + INIT_DELAYED_WORK(&priv->led_on, led_turn_on); + INIT_DELAYED_WORK(&priv->led_off, led_turn_off); + + snprintf(name, sizeof(name), + "rtl8187-%s::tx", wiphy_name(dev->wiphy)); + err = rtl8187_register_led(dev, &priv->led_tx, name, + ieee80211_get_tx_led_name(dev), ledpin); + if (err) + goto error; + snprintf(name, sizeof(name), + "rtl8187-%s::rx", wiphy_name(dev->wiphy)); + err = rtl8187_register_led(dev, &priv->led_rx, name, + ieee80211_get_rx_led_name(dev), ledpin); + if (!err) { + queue_delayed_work(dev->workqueue, &priv->led_on, 0); + return; + } + /* registration of RX LED failed - unregister TX */ + rtl8187_unregister_led(&priv->led_tx); +error: + /* If registration of either failed, cancel delayed work */ + cancel_delayed_work_sync(&priv->led_off); + cancel_delayed_work_sync(&priv->led_on); +} + +void rtl8187_leds_exit(struct ieee80211_hw *dev) +{ + struct rtl8187_priv *priv = dev->priv; + + rtl8187_unregister_led(&priv->led_tx); + /* turn the LED off before exiting */ + queue_delayed_work(dev->workqueue, &priv->led_off, 0); + cancel_delayed_work_sync(&priv->led_off); + rtl8187_unregister_led(&priv->led_rx); +} +#endif /* def CONFIG_RTL8187_LED */ + diff --git a/drivers/net/wireless/rtl818x/rtl8187_leds.h b/drivers/net/wireless/rtl818x/rtl8187_leds.h new file mode 100644 index 000000000000..a0332027aead --- /dev/null +++ b/drivers/net/wireless/rtl818x/rtl8187_leds.h @@ -0,0 +1,57 @@ +/* + * Definitions for RTL8187 leds + * + * Copyright 2009 Larry Finger + * + * Based on the LED handling in the r8187 driver, which is: + * Copyright (c) Realtek Semiconductor Corp. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef RTL8187_LED_H +#define RTL8187_LED_H + +#ifdef CONFIG_RTL8187_LEDS + +#define RTL8187_LED_MAX_NAME_LEN 21 + +#include +#include + +enum { + LED_PIN_LED0, + LED_PIN_LED1, + LED_PIN_GPIO0, + LED_PIN_HW +}; + +enum { + EEPROM_CID_RSVD0 = 0x00, + EEPROM_CID_RSVD1 = 0xFF, + EEPROM_CID_ALPHA0 = 0x01, + EEPROM_CID_SERCOMM_PS = 0x02, + EEPROM_CID_HW = 0x03, + EEPROM_CID_TOSHIBA = 0x04, + EEPROM_CID_QMI = 0x07, + EEPROM_CID_DELL = 0x08 +}; + +struct rtl8187_led { + struct ieee80211_hw *dev; + /* The LED class device */ + struct led_classdev led_dev; + /* The pin/method used to control the led */ + u8 ledpin; + /* The unique name string for this LED device. */ + char name[RTL8187_LED_MAX_NAME_LEN + 1]; +}; + +void rtl8187_leds_init(struct ieee80211_hw *dev, u16 code); +void rtl8187_leds_exit(struct ieee80211_hw *dev); + +#endif /* def CONFIG_RTL8187_LED */ + +#endif /* RTL8187_LED_H */ diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c index f95204632690..38366a56b71f 100644 --- a/drivers/net/wireless/strip.c +++ b/drivers/net/wireless/strip.c @@ -1540,7 +1540,7 @@ static int strip_xmit(struct sk_buff *skb, struct net_device *dev) if (!netif_running(dev)) { printk(KERN_ERR "%s: xmit call when iface is down\n", dev->name); - return (1); + return NETDEV_TX_BUSY; } netif_stop_queue(dev); @@ -2509,7 +2509,7 @@ static void strip_dev_setup(struct net_device *dev) * netdev_priv(dev) Already holds a pointer to our struct strip */ - *(MetricomAddress *) & dev->broadcast = broadcast_address; + *(MetricomAddress *)dev->broadcast = broadcast_address; dev->dev_addr[0] = 0; dev->addr_len = sizeof(MetricomAddress); diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c index 3ab3eb957189..ab7fc5c0c8b4 100644 --- a/drivers/net/wireless/wavelan.c +++ b/drivers/net/wireless/wavelan.c @@ -2867,12 +2867,8 @@ static int wavelan_packet_xmit(struct sk_buff *skb, struct net_device * dev) spin_unlock_irqrestore(&lp->spinlock, flags); /* Check that we can continue */ if (lp->tx_n_in_use == (NTXBLOCKS - 1)) - return 1; + return NETDEV_TX_BUSY; } -#ifdef DEBUG_TX_ERROR - if (skb->next) - printk(KERN_INFO "skb has next\n"); -#endif /* Do we need some padding? */ /* Note : on wireless the propagation time is in the order of 1us, @@ -2884,10 +2880,10 @@ static int wavelan_packet_xmit(struct sk_buff *skb, struct net_device * dev) skb_copy_from_linear_data(skb, data, skb->len); /* Write packet on the card */ if(wv_packet_write(dev, data, ETH_ZLEN)) - return 1; /* We failed */ + return NETDEV_TX_BUSY; /* We failed */ } else if(wv_packet_write(dev, skb->data, skb->len)) - return 1; /* We failed */ + return NETDEV_TX_BUSY; /* We failed */ dev_kfree_skb(skb); diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c index e55b33961aeb..6af706408ac0 100644 --- a/drivers/net/wireless/wavelan_cs.c +++ b/drivers/net/wireless/wavelan_cs.c @@ -138,7 +138,7 @@ psa_read(struct net_device * dev, /*------------------------------------------------------------------*/ /* - * Write the Paramter Storage Area to the WaveLAN card's memory + * Write the Parameter Storage Area to the WaveLAN card's memory */ static void psa_write(struct net_device * dev, @@ -3107,11 +3107,6 @@ wavelan_packet_xmit(struct sk_buff * skb, * so the Tx buffer is now free */ } -#ifdef DEBUG_TX_ERROR - if (skb->next) - printk(KERN_INFO "skb has next\n"); -#endif - /* Check if we need some padding */ /* Note : on wireless the propagation time is in the order of 1us, * and we don't have the Ethernet specific requirement of beeing diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig new file mode 100644 index 000000000000..a82c4cd436d8 --- /dev/null +++ b/drivers/net/wireless/wl12xx/Kconfig @@ -0,0 +1,11 @@ +config WL12XX + tristate "TI wl1251/wl1271 support" + depends on MAC80211 && WLAN_80211 && SPI_MASTER && GENERIC_HARDIRQS && EXPERIMENTAL + select FW_LOADER + select CRC7 + ---help--- + This module adds support for wireless adapters based on + TI wl1251/wl1271 chipsets. + + If you choose to build a module, it'll be called wl12xx. Say N if + unsure. diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile new file mode 100644 index 000000000000..d43de27dc54c --- /dev/null +++ b/drivers/net/wireless/wl12xx/Makefile @@ -0,0 +1,4 @@ +wl12xx-objs = main.o spi.o event.o tx.o rx.o \ + ps.o cmd.o acx.o boot.o init.o wl1251.o \ + debugfs.o +obj-$(CONFIG_WL12XX) += wl12xx.o diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c new file mode 100644 index 000000000000..1cfd458ad5ab --- /dev/null +++ b/drivers/net/wireless/wl12xx/acx.c @@ -0,0 +1,689 @@ +#include "acx.h" + +#include +#include +#include + +#include "wl12xx.h" +#include "wl12xx_80211.h" +#include "reg.h" +#include "spi.h" +#include "ps.h" + +int wl12xx_acx_frame_rates(struct wl12xx *wl, u8 ctrl_rate, u8 ctrl_mod, + u8 mgt_rate, u8 mgt_mod) +{ + int ret; + struct acx_fw_gen_frame_rates rates; + + wl12xx_debug(DEBUG_ACX, "acx frame rates"); + + rates.header.id = ACX_FW_GEN_FRAME_RATES; + rates.header.len = sizeof(struct acx_fw_gen_frame_rates) - + sizeof(struct acx_header); + + rates.tx_ctrl_frame_rate = ctrl_rate; + rates.tx_ctrl_frame_mod = ctrl_mod; + rates.tx_mgt_frame_rate = mgt_rate; + rates.tx_mgt_frame_mod = mgt_mod; + + ret = wl12xx_cmd_configure(wl, &rates, sizeof(rates)); + if (ret < 0) { + wl12xx_error("Failed to set FW rates and modulation"); + return ret; + } + + return 0; +} + + +int wl12xx_acx_station_id(struct wl12xx *wl) +{ + int ret, i; + struct dot11_station_id mac; + + wl12xx_debug(DEBUG_ACX, "acx dot11_station_id"); + + mac.header.id = DOT11_STATION_ID; + mac.header.len = sizeof(mac) - sizeof(struct acx_header); + + for (i = 0; i < ETH_ALEN; i++) + mac.mac[i] = wl->mac_addr[ETH_ALEN - 1 - i]; + + ret = wl12xx_cmd_configure(wl, &mac, sizeof(mac)); + if (ret < 0) + return ret; + + return 0; +} + +int wl12xx_acx_default_key(struct wl12xx *wl, u8 key_id) +{ + struct acx_dot11_default_key default_key; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx dot11_default_key (%d)", key_id); + + default_key.header.id = DOT11_DEFAULT_KEY; + default_key.header.len = sizeof(default_key) - + sizeof(struct acx_header); + + default_key.id = key_id; + + ret = wl12xx_cmd_configure(wl, &default_key, sizeof(default_key)); + if (ret < 0) { + wl12xx_error("Couldnt set default key"); + return ret; + } + + wl->default_key = key_id; + + return 0; +} + +int wl12xx_acx_wake_up_conditions(struct wl12xx *wl, u8 listen_interval) +{ + struct acx_wake_up_condition wake_up; + + wl12xx_debug(DEBUG_ACX, "acx wake up conditions"); + + wake_up.header.id = ACX_WAKE_UP_CONDITIONS; + wake_up.header.len = sizeof(wake_up) - sizeof(struct acx_header); + + wake_up.wake_up_event = WAKE_UP_EVENT_DTIM_BITMAP; + wake_up.listen_interval = listen_interval; + + return wl12xx_cmd_configure(wl, &wake_up, sizeof(wake_up)); +} + +int wl12xx_acx_sleep_auth(struct wl12xx *wl, u8 sleep_auth) +{ + int ret; + struct acx_sleep_auth auth; + + wl12xx_debug(DEBUG_ACX, "acx sleep auth"); + + auth.header.id = ACX_SLEEP_AUTH; + auth.header.len = sizeof(auth) - sizeof(struct acx_header); + + auth.sleep_auth = sleep_auth; + + ret = wl12xx_cmd_configure(wl, &auth, sizeof(auth)); + if (ret < 0) + return ret; + + return 0; +} + +int wl12xx_acx_fw_version(struct wl12xx *wl, char *buf, size_t len) +{ + struct wl12xx_command cmd; + struct acx_revision *rev; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx fw rev"); + + memset(&cmd, 0, sizeof(cmd)); + + ret = wl12xx_cmd_interrogate(wl, ACX_FW_REV, sizeof(*rev), &cmd); + if (ret < 0) { + wl12xx_warning("ACX_FW_REV interrogate failed"); + return ret; + } + + rev = (struct acx_revision *) &cmd.parameters; + + /* be careful with the buffer sizes */ + strncpy(buf, rev->fw_version, min(len, sizeof(rev->fw_version))); + + /* + * if the firmware version string is exactly + * sizeof(rev->fw_version) long or fw_len is less than + * sizeof(rev->fw_version) it won't be null terminated + */ + buf[min(len, sizeof(rev->fw_version)) - 1] = '\0'; + + return 0; +} + +int wl12xx_acx_tx_power(struct wl12xx *wl, int power) +{ + struct acx_current_tx_power ie; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx dot11_cur_tx_pwr"); + + if (power < 0 || power > 25) + return -EINVAL; + + memset(&ie, 0, sizeof(ie)); + + ie.header.id = DOT11_CUR_TX_PWR; + ie.header.len = sizeof(ie) - sizeof(struct acx_header); + ie.current_tx_power = power * 10; + + ret = wl12xx_cmd_configure(wl, &ie, sizeof(ie)); + if (ret < 0) { + wl12xx_warning("configure of tx power failed: %d", ret); + return ret; + } + + return 0; +} + +int wl12xx_acx_feature_cfg(struct wl12xx *wl) +{ + struct acx_feature_config feature; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx feature cfg"); + + memset(&feature, 0, sizeof(feature)); + + feature.header.id = ACX_FEATURE_CFG; + feature.header.len = sizeof(feature) - sizeof(struct acx_header); + + /* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE are disabled */ + feature.data_flow_options = 0; + feature.options = 0; + + ret = wl12xx_cmd_configure(wl, &feature, sizeof(feature)); + if (ret < 0) + wl12xx_error("Couldnt set HW encryption"); + + return ret; +} + +int wl12xx_acx_mem_map(struct wl12xx *wl, void *mem_map, size_t len) +{ + struct wl12xx_command cmd; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx mem map"); + + ret = wl12xx_cmd_interrogate(wl, ACX_MEM_MAP, len, &cmd); + if (ret < 0) + return ret; + else if (cmd.status != CMD_STATUS_SUCCESS) + return -EIO; + + memcpy(mem_map, &cmd.parameters, len); + + return 0; +} + +int wl12xx_acx_data_path_params(struct wl12xx *wl, + struct acx_data_path_params_resp *data_path) +{ + struct acx_data_path_params params; + struct wl12xx_command cmd; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx data path params"); + + params.rx_packet_ring_chunk_size = DP_RX_PACKET_RING_CHUNK_SIZE; + params.tx_packet_ring_chunk_size = DP_TX_PACKET_RING_CHUNK_SIZE; + + params.rx_packet_ring_chunk_num = DP_RX_PACKET_RING_CHUNK_NUM; + params.tx_packet_ring_chunk_num = DP_TX_PACKET_RING_CHUNK_NUM; + + params.tx_complete_threshold = 1; + + params.tx_complete_ring_depth = FW_TX_CMPLT_BLOCK_SIZE; + + params.tx_complete_timeout = DP_TX_COMPLETE_TIME_OUT; + + params.header.id = ACX_DATA_PATH_PARAMS; + params.header.len = sizeof(params) - sizeof(struct acx_header); + + ret = wl12xx_cmd_configure(wl, ¶ms, sizeof(params)); + if (ret < 0) + return ret; + + + ret = wl12xx_cmd_interrogate(wl, ACX_DATA_PATH_PARAMS, + sizeof(struct acx_data_path_params_resp), + &cmd); + + if (ret < 0) { + wl12xx_warning("failed to read data path parameters: %d", ret); + return ret; + } else if (cmd.status != CMD_STATUS_SUCCESS) { + wl12xx_warning("data path parameter acx status failed"); + return -EIO; + } + + memcpy(data_path, &cmd.parameters, sizeof(*data_path)); + + return 0; +} + +int wl12xx_acx_rx_msdu_life_time(struct wl12xx *wl, u32 life_time) +{ + struct rx_msdu_lifetime msdu_lifetime; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx rx msdu life time"); + + msdu_lifetime.header.id = DOT11_RX_MSDU_LIFE_TIME; + msdu_lifetime.header.len = sizeof(msdu_lifetime) - + sizeof(struct acx_header); + msdu_lifetime.lifetime = life_time; + + ret = wl12xx_cmd_configure(wl, &msdu_lifetime, sizeof(msdu_lifetime)); + if (ret < 0) { + wl12xx_warning("failed to set rx msdu life time: %d", ret); + return ret; + } + + return 0; +} + +int wl12xx_acx_rx_config(struct wl12xx *wl, u32 config, u32 filter) +{ + struct acx_rx_config rx_config; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx rx config"); + + rx_config.header.id = ACX_RX_CFG; + rx_config.header.len = sizeof(rx_config) - sizeof(struct acx_header); + rx_config.config_options = config; + rx_config.filter_options = filter; + + ret = wl12xx_cmd_configure(wl, &rx_config, sizeof(rx_config)); + if (ret < 0) { + wl12xx_warning("failed to set rx config: %d", ret); + return ret; + } + + return 0; +} + +int wl12xx_acx_pd_threshold(struct wl12xx *wl) +{ + struct acx_packet_detection packet_detection; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx data pd threshold"); + + /* FIXME: threshold value not set */ + packet_detection.header.id = ACX_PD_THRESHOLD; + packet_detection.header.len = sizeof(packet_detection) - + sizeof(struct acx_header); + + ret = wl12xx_cmd_configure(wl, &packet_detection, + sizeof(packet_detection)); + if (ret < 0) { + wl12xx_warning("failed to set pd threshold: %d", ret); + return ret; + } + + return 0; +} + +int wl12xx_acx_slot(struct wl12xx *wl, enum acx_slot_type slot_time) +{ + struct acx_slot slot; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx slot"); + + slot.header.id = ACX_SLOT; + slot.header.len = sizeof(slot) - sizeof(struct acx_header); + + slot.wone_index = STATION_WONE_INDEX; + slot.slot_time = slot_time; + + ret = wl12xx_cmd_configure(wl, &slot, sizeof(slot)); + if (ret < 0) { + wl12xx_warning("failed to set slot time: %d", ret); + return ret; + } + + return 0; +} + +int wl12xx_acx_group_address_tbl(struct wl12xx *wl) +{ + struct multicast_grp_addr_start multicast; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx group address tbl"); + + /* MAC filtering */ + multicast.header.id = DOT11_GROUP_ADDRESS_TBL; + multicast.header.len = sizeof(multicast) - sizeof(struct acx_header); + + multicast.enabled = 0; + multicast.num_groups = 0; + memset(multicast.mac_table, 0, ADDRESS_GROUP_MAX_LEN); + + ret = wl12xx_cmd_configure(wl, &multicast, sizeof(multicast)); + if (ret < 0) { + wl12xx_warning("failed to set group addr table: %d", ret); + return ret; + } + + return 0; +} + +int wl12xx_acx_service_period_timeout(struct wl12xx *wl) +{ + struct acx_rx_timeout rx_timeout; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx service period timeout"); + + /* RX timeout */ + rx_timeout.header.id = ACX_SERVICE_PERIOD_TIMEOUT; + rx_timeout.header.len = sizeof(rx_timeout) - sizeof(struct acx_header); + + rx_timeout.ps_poll_timeout = RX_TIMEOUT_PS_POLL_DEF; + rx_timeout.upsd_timeout = RX_TIMEOUT_UPSD_DEF; + + ret = wl12xx_cmd_configure(wl, &rx_timeout, sizeof(rx_timeout)); + if (ret < 0) { + wl12xx_warning("failed to set service period timeout: %d", + ret); + return ret; + } + + return 0; +} + +int wl12xx_acx_rts_threshold(struct wl12xx *wl, u16 rts_threshold) +{ + struct acx_rts_threshold rts; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx rts threshold"); + + rts.header.id = DOT11_RTS_THRESHOLD; + rts.header.len = sizeof(rts) - sizeof(struct acx_header); + + rts.threshold = rts_threshold; + + ret = wl12xx_cmd_configure(wl, &rts, sizeof(rts)); + if (ret < 0) { + wl12xx_warning("failed to set rts threshold: %d", ret); + return ret; + } + + return 0; +} + +int wl12xx_acx_beacon_filter_opt(struct wl12xx *wl) +{ + struct acx_beacon_filter_option beacon_filter; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx beacon filter opt"); + + beacon_filter.header.id = ACX_BEACON_FILTER_OPT; + beacon_filter.header.len = sizeof(beacon_filter) - + sizeof(struct acx_header); + + beacon_filter.enable = 0; + beacon_filter.max_num_beacons = 0; + + ret = wl12xx_cmd_configure(wl, &beacon_filter, sizeof(beacon_filter)); + if (ret < 0) { + wl12xx_warning("failed to set beacon filter opt: %d", ret); + return ret; + } + + return 0; +} + +int wl12xx_acx_beacon_filter_table(struct wl12xx *wl) +{ + struct acx_beacon_filter_ie_table ie_table; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx beacon filter table"); + + ie_table.header.id = ACX_BEACON_FILTER_TABLE; + ie_table.header.len = sizeof(ie_table) - sizeof(struct acx_header); + + ie_table.num_ie = 0; + memset(ie_table.table, 0, BEACON_FILTER_TABLE_MAX_SIZE); + + ret = wl12xx_cmd_configure(wl, &ie_table, sizeof(ie_table)); + if (ret < 0) { + wl12xx_warning("failed to set beacon filter table: %d", ret); + return ret; + } + + return 0; +} + +int wl12xx_acx_sg_enable(struct wl12xx *wl) +{ + struct acx_bt_wlan_coex pta; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx sg enable"); + + pta.header.id = ACX_SG_ENABLE; + pta.header.len = sizeof(pta) - sizeof(struct acx_header); + + pta.enable = SG_ENABLE; + + ret = wl12xx_cmd_configure(wl, &pta, sizeof(pta)); + if (ret < 0) { + wl12xx_warning("failed to set softgemini enable: %d", ret); + return ret; + } + + return 0; +} + +int wl12xx_acx_sg_cfg(struct wl12xx *wl) +{ + struct acx_bt_wlan_coex_param param; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx sg cfg"); + + /* BT-WLAN coext parameters */ + param.header.id = ACX_SG_CFG; + param.header.len = sizeof(param) - sizeof(struct acx_header); + + param.min_rate = RATE_INDEX_24MBPS; + param.bt_hp_max_time = PTA_BT_HP_MAXTIME_DEF; + param.wlan_hp_max_time = PTA_WLAN_HP_MAX_TIME_DEF; + param.sense_disable_timer = PTA_SENSE_DISABLE_TIMER_DEF; + param.rx_time_bt_hp = PTA_PROTECTIVE_RX_TIME_DEF; + param.tx_time_bt_hp = PTA_PROTECTIVE_TX_TIME_DEF; + param.rx_time_bt_hp_fast = PTA_PROTECTIVE_RX_TIME_FAST_DEF; + param.tx_time_bt_hp_fast = PTA_PROTECTIVE_TX_TIME_FAST_DEF; + param.wlan_cycle_fast = PTA_CYCLE_TIME_FAST_DEF; + param.bt_anti_starvation_period = PTA_ANTI_STARVE_PERIOD_DEF; + param.next_bt_lp_packet = PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF; + param.wake_up_beacon = PTA_TIME_BEFORE_BEACON_DEF; + param.hp_dm_max_guard_time = PTA_HPDM_MAX_TIME_DEF; + param.next_wlan_packet = PTA_TIME_OUT_NEXT_WLAN_DEF; + param.antenna_type = PTA_ANTENNA_TYPE_DEF; + param.signal_type = PTA_SIGNALING_TYPE_DEF; + param.afh_leverage_on = PTA_AFH_LEVERAGE_ON_DEF; + param.quiet_cycle_num = PTA_NUMBER_QUIET_CYCLE_DEF; + param.max_cts = PTA_MAX_NUM_CTS_DEF; + param.wlan_packets_num = PTA_NUMBER_OF_WLAN_PACKETS_DEF; + param.bt_packets_num = PTA_NUMBER_OF_BT_PACKETS_DEF; + param.missed_rx_avalanche = PTA_RX_FOR_AVALANCHE_DEF; + param.wlan_elp_hp = PTA_ELP_HP_DEF; + param.bt_anti_starvation_cycles = PTA_ANTI_STARVE_NUM_CYCLE_DEF; + param.ack_mode_dual_ant = PTA_ACK_MODE_DEF; + param.pa_sd_enable = PTA_ALLOW_PA_SD_DEF; + param.pta_auto_mode_enable = PTA_AUTO_MODE_NO_CTS_DEF; + param.bt_hp_respected_num = PTA_BT_HP_RESPECTED_DEF; + + ret = wl12xx_cmd_configure(wl, ¶m, sizeof(param)); + if (ret < 0) { + wl12xx_warning("failed to set sg config: %d", ret); + return ret; + } + + return 0; +} + +int wl12xx_acx_cca_threshold(struct wl12xx *wl) +{ + struct acx_energy_detection detection; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx cca threshold"); + + detection.header.id = ACX_CCA_THRESHOLD; + detection.header.len = sizeof(detection) - sizeof(struct acx_header); + + detection.rx_cca_threshold = CCA_THRSH_DISABLE_ENERGY_D; + detection.tx_energy_detection = 0; + + ret = wl12xx_cmd_configure(wl, &detection, sizeof(detection)); + if (ret < 0) { + wl12xx_warning("failed to set cca threshold: %d", ret); + return ret; + } + + return 0; +} + +int wl12xx_acx_bcn_dtim_options(struct wl12xx *wl) +{ + struct acx_beacon_broadcast bb; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx bcn dtim options"); + + bb.header.id = ACX_BCN_DTIM_OPTIONS; + bb.header.len = sizeof(bb) - sizeof(struct acx_header); + + bb.beacon_rx_timeout = BCN_RX_TIMEOUT_DEF_VALUE; + bb.broadcast_timeout = BROADCAST_RX_TIMEOUT_DEF_VALUE; + bb.rx_broadcast_in_ps = RX_BROADCAST_IN_PS_DEF_VALUE; + bb.ps_poll_threshold = CONSECUTIVE_PS_POLL_FAILURE_DEF; + + ret = wl12xx_cmd_configure(wl, &bb, sizeof(bb)); + if (ret < 0) { + wl12xx_warning("failed to set rx config: %d", ret); + return ret; + } + + return 0; +} + +int wl12xx_acx_aid(struct wl12xx *wl, u16 aid) +{ + struct acx_aid acx_aid; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx aid"); + + acx_aid.header.id = ACX_AID; + acx_aid.header.len = sizeof(acx_aid) - sizeof(struct acx_header); + + acx_aid.aid = aid; + + ret = wl12xx_cmd_configure(wl, &acx_aid, sizeof(acx_aid)); + if (ret < 0) { + wl12xx_warning("failed to set aid: %d", ret); + return ret; + } + + return 0; +} + +int wl12xx_acx_event_mbox_mask(struct wl12xx *wl, u32 event_mask) +{ + struct acx_event_mask mask; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx event mbox mask"); + + mask.header.id = ACX_EVENT_MBOX_MASK; + mask.header.len = sizeof(mask) - sizeof(struct acx_header); + + /* high event mask is unused */ + mask.high_event_mask = 0xffffffff; + + mask.event_mask = event_mask; + + ret = wl12xx_cmd_configure(wl, &mask, sizeof(mask)); + if (ret < 0) { + wl12xx_warning("failed to set aid: %d", ret); + return ret; + } + + return 0; +} + +int wl12xx_acx_set_preamble(struct wl12xx *wl, enum acx_preamble_type preamble) +{ + struct acx_preamble ie; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx_set_preamble"); + + memset(&ie, 0, sizeof(ie)); + + ie.header.id = ACX_PREAMBLE_TYPE; + ie.header.len = sizeof(ie) - sizeof(struct acx_header); + ie.preamble = preamble; + ret = wl12xx_cmd_configure(wl, &ie, sizeof(ie)); + if (ret < 0) { + wl12xx_warning("Setting of preamble failed: %d", ret); + return ret; + } + return 0; +} + +int wl12xx_acx_cts_protect(struct wl12xx *wl, + enum acx_ctsprotect_type ctsprotect) +{ + struct acx_ctsprotect ie; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx_set_ctsprotect"); + + memset(&ie, 0, sizeof(ie)); + + ie.header.id = ACX_CTS_PROTECTION; + ie.header.len = sizeof(ie) - sizeof(struct acx_header); + ie.ctsprotect = ctsprotect; + ret = wl12xx_cmd_configure(wl, &ie, sizeof(ie)); + if (ret < 0) { + wl12xx_warning("Setting of ctsprotect failed: %d", ret); + return ret; + } + return 0; +} + +int wl12xx_acx_statistics(struct wl12xx *wl, struct acx_statistics *stats) +{ + struct wl12xx_command *answer; + int ret; + + wl12xx_debug(DEBUG_ACX, "acx statistics"); + + answer = kmalloc(sizeof(*answer), GFP_KERNEL); + if (!answer) { + wl12xx_warning("could not allocate memory for acx statistics"); + ret = -ENOMEM; + goto out; + } + + ret = wl12xx_cmd_interrogate(wl, ACX_STATISTICS, sizeof(*answer), + answer); + if (ret < 0) { + wl12xx_warning("acx statistics failed: %d", ret); + goto out; + } + + memcpy(stats, answer->parameters, sizeof(*stats)); + +out: + kfree(answer); + return ret; +} diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h new file mode 100644 index 000000000000..fb2d2340993c --- /dev/null +++ b/drivers/net/wireless/wl12xx/acx.h @@ -0,0 +1,1245 @@ +/* + * This file is part of wl12xx + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL12XX_ACX_H__ +#define __WL12XX_ACX_H__ + +#include "wl12xx.h" + +/* Target's information element */ +struct acx_header { + u16 id; + u16 len; +}; + +struct acx_error_counter { + struct acx_header header; + + /* The number of PLCP errors since the last time this */ + /* information element was interrogated. This field is */ + /* automatically cleared when it is interrogated.*/ + u32 PLCP_error; + + /* The number of FCS errors since the last time this */ + /* information element was interrogated. This field is */ + /* automatically cleared when it is interrogated.*/ + u32 FCS_error; + + /* The number of MPDUs without PLCP header errors received*/ + /* since the last time this information element was interrogated. */ + /* This field is automatically cleared when it is interrogated.*/ + u32 valid_frame; + + /* the number of missed sequence numbers in the squentially */ + /* values of frames seq numbers */ + u32 seq_num_miss; +} __attribute__ ((packed)); + +struct acx_revision { + struct acx_header header; + + /* + * The WiLink firmware version, an ASCII string x.x.x.x, + * that uniquely identifies the current firmware. + * The left most digit is incremented each time a + * significant change is made to the firmware, such as + * code redesign or new platform support. + * The second digit is incremented when major enhancements + * are added or major fixes are made. + * The third digit is incremented for each GA release. + * The fourth digit is incremented for each build. + * The first two digits identify a firmware release version, + * in other words, a unique set of features. + * The first three digits identify a GA release. + */ + char fw_version[20]; + + /* + * This 4 byte field specifies the WiLink hardware version. + * bits 0 - 15: Reserved. + * bits 16 - 23: Version ID - The WiLink version ID + * (1 = first spin, 2 = second spin, and so on). + * bits 24 - 31: Chip ID - The WiLink chip ID. + */ + u32 hw_version; +} __attribute__ ((packed)); + +enum wl12xx_psm_mode { + /* Active mode */ + WL12XX_PSM_CAM = 0, + + /* Power save mode */ + WL12XX_PSM_PS = 1, + + /* Extreme low power */ + WL12XX_PSM_ELP = 2, +}; + +struct acx_sleep_auth { + struct acx_header header; + + /* The sleep level authorization of the device. */ + /* 0 - Always active*/ + /* 1 - Power down mode: light / fast sleep*/ + /* 2 - ELP mode: Deep / Max sleep*/ + u8 sleep_auth; + u8 padding[3]; +} __attribute__ ((packed)); + +#define TIM_ELE_ID 5 +#define PARTIAL_VBM_MAX 251 + +struct tim { + u8 identity; + u8 length; + u8 dtim_count; + u8 dtim_period; + u8 bitmap_ctrl; + u8 pvb_field[PARTIAL_VBM_MAX]; /* Partial Virtual Bitmap */ +} __attribute__ ((packed)); + +/* Virtual Bit Map update */ +struct vbm_update_request { + __le16 len; + u8 padding[2]; + struct tim tim; +} __attribute__ ((packed)); + +enum { + HOSTIF_PCI_MASTER_HOST_INDIRECT, + HOSTIF_PCI_MASTER_HOST_DIRECT, + HOSTIF_SLAVE, + HOSTIF_PKT_RING, + HOSTIF_DONTCARE = 0xFF +}; + +#define DEFAULT_UCAST_PRIORITY 0 +#define DEFAULT_RX_Q_PRIORITY 0 +#define DEFAULT_NUM_STATIONS 1 +#define DEFAULT_RXQ_PRIORITY 0 /* low 0 .. 15 high */ +#define DEFAULT_RXQ_TYPE 0x07 /* All frames, Data/Ctrl/Mgmt */ +#define TRACE_BUFFER_MAX_SIZE 256 + +#define DP_RX_PACKET_RING_CHUNK_SIZE 1600 +#define DP_TX_PACKET_RING_CHUNK_SIZE 1600 +#define DP_RX_PACKET_RING_CHUNK_NUM 2 +#define DP_TX_PACKET_RING_CHUNK_NUM 2 +#define DP_TX_COMPLETE_TIME_OUT 20 +#define FW_TX_CMPLT_BLOCK_SIZE 16 + +struct acx_data_path_params { + struct acx_header header; + + u16 rx_packet_ring_chunk_size; + u16 tx_packet_ring_chunk_size; + + u8 rx_packet_ring_chunk_num; + u8 tx_packet_ring_chunk_num; + + /* + * Maximum number of packets that can be gathered + * in the TX complete ring before an interrupt + * is generated. + */ + u8 tx_complete_threshold; + + /* Number of pending TX complete entries in cyclic ring.*/ + u8 tx_complete_ring_depth; + + /* + * Max num microseconds since a packet enters the TX + * complete ring until an interrupt is generated. + */ + u32 tx_complete_timeout; +} __attribute__ ((packed)); + + +struct acx_data_path_params_resp { + struct acx_header header; + + u16 rx_packet_ring_chunk_size; + u16 tx_packet_ring_chunk_size; + + u8 rx_packet_ring_chunk_num; + u8 tx_packet_ring_chunk_num; + + u8 pad[2]; + + u32 rx_packet_ring_addr; + u32 tx_packet_ring_addr; + + u32 rx_control_addr; + u32 tx_control_addr; + + u32 tx_complete_addr; +} __attribute__ ((packed)); + +#define TX_MSDU_LIFETIME_MIN 0 +#define TX_MSDU_LIFETIME_MAX 3000 +#define TX_MSDU_LIFETIME_DEF 512 +#define RX_MSDU_LIFETIME_MIN 0 +#define RX_MSDU_LIFETIME_MAX 0xFFFFFFFF +#define RX_MSDU_LIFETIME_DEF 512000 + +struct rx_msdu_lifetime { + struct acx_header header; + + /* + * The maximum amount of time, in TU, before the + * firmware discards the MSDU. + */ + u32 lifetime; +} __attribute__ ((packed)); + +/* + * RX Config Options Table + * Bit Definition + * === ========== + * 31:14 Reserved + * 13 Copy RX Status - when set, write three receive status words + * to top of rx'd MPDUs. + * When cleared, do not write three status words (added rev 1.5) + * 12 Reserved + * 11 RX Complete upon FCS error - when set, give rx complete + * interrupt for FCS errors, after the rx filtering, e.g. unicast + * frames not to us with FCS error will not generate an interrupt. + * 10 SSID Filter Enable - When set, the WiLink discards all beacon, + * probe request, and probe response frames with an SSID that does + * not match the SSID specified by the host in the START/JOIN + * command. + * When clear, the WiLink receives frames with any SSID. + * 9 Broadcast Filter Enable - When set, the WiLink discards all + * broadcast frames. When clear, the WiLink receives all received + * broadcast frames. + * 8:6 Reserved + * 5 BSSID Filter Enable - When set, the WiLink discards any frames + * with a BSSID that does not match the BSSID specified by the + * host. + * When clear, the WiLink receives frames from any BSSID. + * 4 MAC Addr Filter - When set, the WiLink discards any frames + * with a destination address that does not match the MAC address + * of the adaptor. + * When clear, the WiLink receives frames destined to any MAC + * address. + * 3 Promiscuous - When set, the WiLink receives all valid frames + * (i.e., all frames that pass the FCS check). + * When clear, only frames that pass the other filters specified + * are received. + * 2 FCS - When set, the WiLink includes the FCS with the received + * frame. + * When cleared, the FCS is discarded. + * 1 PLCP header - When set, write all data from baseband to frame + * buffer including PHY header. + * 0 Reserved - Always equal to 0. + * + * RX Filter Options Table + * Bit Definition + * === ========== + * 31:12 Reserved - Always equal to 0. + * 11 Association - When set, the WiLink receives all association + * related frames (association request/response, reassocation + * request/response, and disassociation). When clear, these frames + * are discarded. + * 10 Auth/De auth - When set, the WiLink receives all authentication + * and de-authentication frames. When clear, these frames are + * discarded. + * 9 Beacon - When set, the WiLink receives all beacon frames. + * When clear, these frames are discarded. + * 8 Contention Free - When set, the WiLink receives all contention + * free frames. + * When clear, these frames are discarded. + * 7 Control - When set, the WiLink receives all control frames. + * When clear, these frames are discarded. + * 6 Data - When set, the WiLink receives all data frames. + * When clear, these frames are discarded. + * 5 FCS Error - When set, the WiLink receives frames that have FCS + * errors. + * When clear, these frames are discarded. + * 4 Management - When set, the WiLink receives all management + * frames. + * When clear, these frames are discarded. + * 3 Probe Request - When set, the WiLink receives all probe request + * frames. + * When clear, these frames are discarded. + * 2 Probe Response - When set, the WiLink receives all probe + * response frames. + * When clear, these frames are discarded. + * 1 RTS/CTS/ACK - When set, the WiLink receives all RTS, CTS and ACK + * frames. + * When clear, these frames are discarded. + * 0 Rsvd Type/Sub Type - When set, the WiLink receives all frames + * that have reserved frame types and sub types as defined by the + * 802.11 specification. + * When clear, these frames are discarded. + */ +struct acx_rx_config { + struct acx_header header; + + u32 config_options; + u32 filter_options; +} __attribute__ ((packed)); + +enum { + QOS_AC_BE = 0, + QOS_AC_BK, + QOS_AC_VI, + QOS_AC_VO, + QOS_HIGHEST_AC_INDEX = QOS_AC_VO, +}; + +#define MAX_NUM_OF_AC (QOS_HIGHEST_AC_INDEX+1) +#define FIRST_AC_INDEX QOS_AC_BE +#define MAX_NUM_OF_802_1d_TAGS 8 +#define AC_PARAMS_MAX_TSID 15 +#define MAX_APSD_CONF 0xffff + +#define QOS_TX_HIGH_MIN (0) +#define QOS_TX_HIGH_MAX (100) + +#define QOS_TX_HIGH_BK_DEF (25) +#define QOS_TX_HIGH_BE_DEF (35) +#define QOS_TX_HIGH_VI_DEF (35) +#define QOS_TX_HIGH_VO_DEF (35) + +#define QOS_TX_LOW_BK_DEF (15) +#define QOS_TX_LOW_BE_DEF (25) +#define QOS_TX_LOW_VI_DEF (25) +#define QOS_TX_LOW_VO_DEF (25) + +struct acx_tx_queue_qos_config { + struct acx_header header; + + u8 qid; + u8 pad[3]; + + /* Max number of blocks allowd in the queue */ + u16 high_threshold; + + /* Lowest memory blocks guaranteed for this queue */ + u16 low_threshold; +} __attribute__ ((packed)); + +struct acx_packet_detection { + struct acx_header header; + + u32 threshold; +} __attribute__ ((packed)); + + +enum acx_slot_type { + SLOT_TIME_LONG = 0, + SLOT_TIME_SHORT = 1, + DEFAULT_SLOT_TIME = SLOT_TIME_SHORT, + MAX_SLOT_TIMES = 0xFF +}; + +#define STATION_WONE_INDEX 0 + +struct acx_slot { + struct acx_header header; + + u8 wone_index; /* Reserved */ + u8 slot_time; + u8 reserved[6]; +} __attribute__ ((packed)); + + +#define ADDRESS_GROUP_MAX (8) +#define ADDRESS_GROUP_MAX_LEN (ETH_ALEN * ADDRESS_GROUP_MAX) + +struct multicast_grp_addr_start { + struct acx_header header; + + u8 enabled; + u8 num_groups; + u8 pad[2]; + u8 mac_table[ADDRESS_GROUP_MAX_LEN]; +} __attribute__ ((packed)); + + +#define RX_TIMEOUT_PS_POLL_MIN 0 +#define RX_TIMEOUT_PS_POLL_MAX (200000) +#define RX_TIMEOUT_PS_POLL_DEF (15) +#define RX_TIMEOUT_UPSD_MIN 0 +#define RX_TIMEOUT_UPSD_MAX (200000) +#define RX_TIMEOUT_UPSD_DEF (15) + +struct acx_rx_timeout { + struct acx_header header; + + /* + * The longest time the STA will wait to receive + * traffic from the AP after a PS-poll has been + * transmitted. + */ + u16 ps_poll_timeout; + + /* + * The longest time the STA will wait to receive + * traffic from the AP after a frame has been sent + * from an UPSD enabled queue. + */ + u16 upsd_timeout; +} __attribute__ ((packed)); + +#define RTS_THRESHOLD_MIN 0 +#define RTS_THRESHOLD_MAX 4096 +#define RTS_THRESHOLD_DEF 2347 + +struct acx_rts_threshold { + struct acx_header header; + + u16 threshold; + u8 pad[2]; +} __attribute__ ((packed)); + +struct acx_beacon_filter_option { + struct acx_header header; + + u8 enable; + + /* + * The number of beacons without the unicast TIM + * bit set that the firmware buffers before + * signaling the host about ready frames. + * When set to 0 and the filter is enabled, beacons + * without the unicast TIM bit set are dropped. + */ + u8 max_num_beacons; + u8 pad[2]; +} __attribute__ ((packed)); + +/* + * ACXBeaconFilterEntry (not 221) + * Byte Offset Size (Bytes) Definition + * =========== ============ ========== + * 0 1 IE identifier + * 1 1 Treatment bit mask + * + * ACXBeaconFilterEntry (221) + * Byte Offset Size (Bytes) Definition + * =========== ============ ========== + * 0 1 IE identifier + * 1 1 Treatment bit mask + * 2 3 OUI + * 5 1 Type + * 6 2 Version + * + * + * Treatment bit mask - The information element handling: + * bit 0 - The information element is compared and transferred + * in case of change. + * bit 1 - The information element is transferred to the host + * with each appearance or disappearance. + * Note that both bits can be set at the same time. + */ +#define BEACON_FILTER_TABLE_MAX_IE_NUM (32) +#define BEACON_FILTER_TABLE_MAX_VENDOR_SPECIFIC_IE_NUM (6) +#define BEACON_FILTER_TABLE_IE_ENTRY_SIZE (2) +#define BEACON_FILTER_TABLE_EXTRA_VENDOR_SPECIFIC_IE_SIZE (6) +#define BEACON_FILTER_TABLE_MAX_SIZE ((BEACON_FILTER_TABLE_MAX_IE_NUM * \ + BEACON_FILTER_TABLE_IE_ENTRY_SIZE) + \ + (BEACON_FILTER_TABLE_MAX_VENDOR_SPECIFIC_IE_NUM * \ + BEACON_FILTER_TABLE_EXTRA_VENDOR_SPECIFIC_IE_SIZE)) + +struct acx_beacon_filter_ie_table { + struct acx_header header; + + u8 num_ie; + u8 table[BEACON_FILTER_TABLE_MAX_SIZE]; + u8 pad[3]; +} __attribute__ ((packed)); + +enum { + SG_ENABLE = 0, + SG_DISABLE, + SG_SENSE_NO_ACTIVITY, + SG_SENSE_ACTIVE +}; + +struct acx_bt_wlan_coex { + struct acx_header header; + + /* + * 0 -> PTA enabled + * 1 -> PTA disabled + * 2 -> sense no active mode, i.e. + * an interrupt is sent upon + * BT activity. + * 3 -> PTA is switched on in response + * to the interrupt sending. + */ + u8 enable; + u8 pad[3]; +} __attribute__ ((packed)); + +#define PTA_ANTENNA_TYPE_DEF (0) +#define PTA_BT_HP_MAXTIME_DEF (2000) +#define PTA_WLAN_HP_MAX_TIME_DEF (5000) +#define PTA_SENSE_DISABLE_TIMER_DEF (1350) +#define PTA_PROTECTIVE_RX_TIME_DEF (1500) +#define PTA_PROTECTIVE_TX_TIME_DEF (1500) +#define PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF (3000) +#define PTA_SIGNALING_TYPE_DEF (1) +#define PTA_AFH_LEVERAGE_ON_DEF (0) +#define PTA_NUMBER_QUIET_CYCLE_DEF (0) +#define PTA_MAX_NUM_CTS_DEF (3) +#define PTA_NUMBER_OF_WLAN_PACKETS_DEF (2) +#define PTA_NUMBER_OF_BT_PACKETS_DEF (2) +#define PTA_PROTECTIVE_RX_TIME_FAST_DEF (1500) +#define PTA_PROTECTIVE_TX_TIME_FAST_DEF (3000) +#define PTA_CYCLE_TIME_FAST_DEF (8700) +#define PTA_RX_FOR_AVALANCHE_DEF (5) +#define PTA_ELP_HP_DEF (0) +#define PTA_ANTI_STARVE_PERIOD_DEF (500) +#define PTA_ANTI_STARVE_NUM_CYCLE_DEF (4) +#define PTA_ALLOW_PA_SD_DEF (1) +#define PTA_TIME_BEFORE_BEACON_DEF (6300) +#define PTA_HPDM_MAX_TIME_DEF (1600) +#define PTA_TIME_OUT_NEXT_WLAN_DEF (2550) +#define PTA_AUTO_MODE_NO_CTS_DEF (0) +#define PTA_BT_HP_RESPECTED_DEF (3) +#define PTA_WLAN_RX_MIN_RATE_DEF (24) +#define PTA_ACK_MODE_DEF (1) + +struct acx_bt_wlan_coex_param { + struct acx_header header; + + /* + * The minimum rate of a received WLAN packet in the STA, + * during protective mode, of which a new BT-HP request + * during this Rx will always be respected and gain the antenna. + */ + u32 min_rate; + + /* Max time the BT HP will be respected. */ + u16 bt_hp_max_time; + + /* Max time the WLAN HP will be respected. */ + u16 wlan_hp_max_time; + + /* + * The time between the last BT activity + * and the moment when the sense mode returns + * to SENSE_INACTIVE. + */ + u16 sense_disable_timer; + + /* Time before the next BT HP instance */ + u16 rx_time_bt_hp; + u16 tx_time_bt_hp; + + /* range: 10-20000 default: 1500 */ + u16 rx_time_bt_hp_fast; + u16 tx_time_bt_hp_fast; + + /* range: 2000-65535 default: 8700 */ + u16 wlan_cycle_fast; + + /* range: 0 - 15000 (Msec) default: 1000 */ + u16 bt_anti_starvation_period; + + /* range 400-10000(Usec) default: 3000 */ + u16 next_bt_lp_packet; + + /* Deafult: worst case for BT DH5 traffic */ + u16 wake_up_beacon; + + /* range: 0-50000(Usec) default: 1050 */ + u16 hp_dm_max_guard_time; + + /* + * This is to prevent both BT & WLAN antenna + * starvation. + * Range: 100-50000(Usec) default:2550 + */ + u16 next_wlan_packet; + + /* 0 -> shared antenna */ + u8 antenna_type; + + /* + * 0 -> TI legacy + * 1 -> Palau + */ + u8 signal_type; + + /* + * BT AFH status + * 0 -> no AFH + * 1 -> from dedicated GPIO + * 2 -> AFH on (from host) + */ + u8 afh_leverage_on; + + /* + * The number of cycles during which no + * TX will be sent after 1 cycle of RX + * transaction in protective mode + */ + u8 quiet_cycle_num; + + /* + * The maximum number of CTSs that will + * be sent for receiving RX packet in + * protective mode + */ + u8 max_cts; + + /* + * The number of WLAN packets + * transferred in common mode before + * switching to BT. + */ + u8 wlan_packets_num; + + /* + * The number of BT packets + * transferred in common mode before + * switching to WLAN. + */ + u8 bt_packets_num; + + /* range: 1-255 default: 5 */ + u8 missed_rx_avalanche; + + /* range: 0-1 default: 1 */ + u8 wlan_elp_hp; + + /* range: 0 - 15 default: 4 */ + u8 bt_anti_starvation_cycles; + + u8 ack_mode_dual_ant; + + /* + * Allow PA_SD assertion/de-assertion + * during enabled BT activity. + */ + u8 pa_sd_enable; + + /* + * Enable/Disable PTA in auto mode: + * Support Both Active & P.S modes + */ + u8 pta_auto_mode_enable; + + /* range: 0 - 20 default: 1 */ + u8 bt_hp_respected_num; +} __attribute__ ((packed)); + +#define CCA_THRSH_ENABLE_ENERGY_D 0x140A +#define CCA_THRSH_DISABLE_ENERGY_D 0xFFEF + +struct acx_energy_detection { + struct acx_header header; + + /* The RX Clear Channel Assessment threshold in the PHY */ + u16 rx_cca_threshold; + u8 tx_energy_detection; + u8 pad; +} __attribute__ ((packed)); + +#define BCN_RX_TIMEOUT_DEF_VALUE 10000 +#define BROADCAST_RX_TIMEOUT_DEF_VALUE 20000 +#define RX_BROADCAST_IN_PS_DEF_VALUE 1 +#define CONSECUTIVE_PS_POLL_FAILURE_DEF 4 + +struct acx_beacon_broadcast { + struct acx_header header; + + u16 beacon_rx_timeout; + u16 broadcast_timeout; + + /* Enables receiving of broadcast packets in PS mode */ + u8 rx_broadcast_in_ps; + + /* Consecutive PS Poll failures before updating the host */ + u8 ps_poll_threshold; + u8 pad[2]; +} __attribute__ ((packed)); + +struct acx_event_mask { + struct acx_header header; + + u32 event_mask; + u32 high_event_mask; /* Unused */ +} __attribute__ ((packed)); + +#define CFG_RX_FCS BIT(2) +#define CFG_RX_ALL_GOOD BIT(3) +#define CFG_UNI_FILTER_EN BIT(4) +#define CFG_BSSID_FILTER_EN BIT(5) +#define CFG_MC_FILTER_EN BIT(6) +#define CFG_MC_ADDR0_EN BIT(7) +#define CFG_MC_ADDR1_EN BIT(8) +#define CFG_BC_REJECT_EN BIT(9) +#define CFG_SSID_FILTER_EN BIT(10) +#define CFG_RX_INT_FCS_ERROR BIT(11) +#define CFG_RX_INT_ENCRYPTED BIT(12) +#define CFG_RX_WR_RX_STATUS BIT(13) +#define CFG_RX_FILTER_NULTI BIT(14) +#define CFG_RX_RESERVE BIT(15) +#define CFG_RX_TIMESTAMP_TSF BIT(16) + +#define CFG_RX_RSV_EN BIT(0) +#define CFG_RX_RCTS_ACK BIT(1) +#define CFG_RX_PRSP_EN BIT(2) +#define CFG_RX_PREQ_EN BIT(3) +#define CFG_RX_MGMT_EN BIT(4) +#define CFG_RX_FCS_ERROR BIT(5) +#define CFG_RX_DATA_EN BIT(6) +#define CFG_RX_CTL_EN BIT(7) +#define CFG_RX_CF_EN BIT(8) +#define CFG_RX_BCN_EN BIT(9) +#define CFG_RX_AUTH_EN BIT(10) +#define CFG_RX_ASSOC_EN BIT(11) + +#define SCAN_PASSIVE BIT(0) +#define SCAN_5GHZ_BAND BIT(1) +#define SCAN_TRIGGERED BIT(2) +#define SCAN_PRIORITY_HIGH BIT(3) + +struct acx_fw_gen_frame_rates { + struct acx_header header; + + u8 tx_ctrl_frame_rate; /* RATE_* */ + u8 tx_ctrl_frame_mod; /* CCK_* or PBCC_* */ + u8 tx_mgt_frame_rate; + u8 tx_mgt_frame_mod; +} __attribute__ ((packed)); + +/* STA MAC */ +struct dot11_station_id { + struct acx_header header; + + u8 mac[ETH_ALEN]; + u8 pad[2]; +} __attribute__ ((packed)); + +/* HW encryption keys */ +#define NUM_ACCESS_CATEGORIES_COPY 4 +#define MAX_KEY_SIZE 32 + +/* When set, disable HW encryption */ +#define DF_ENCRYPTION_DISABLE 0x01 +/* When set, disable HW decryption */ +#define DF_SNIFF_MODE_ENABLE 0x80 + +struct acx_feature_config { + struct acx_header header; + + u32 options; + u32 data_flow_options; +} __attribute__ ((packed)); + +enum acx_key_action { + KEY_ADD_OR_REPLACE = 1, + KEY_REMOVE = 2, + KEY_SET_ID = 3, + MAX_KEY_ACTION = 0xffff, +}; + +enum acx_key_type { + KEY_WEP_DEFAULT = 0, + KEY_WEP_ADDR = 1, + KEY_AES_GROUP = 4, + KEY_AES_PAIRWISE = 5, + KEY_WEP_GROUP = 6, + KEY_TKIP_MIC_GROUP = 10, + KEY_TKIP_MIC_PAIRWISE = 11, +}; + +/* + * + * key_type_e key size key format + * ---------- --------- ---------- + * 0x00 5, 13, 29 Key data + * 0x01 5, 13, 29 Key data + * 0x04 16 16 bytes of key data + * 0x05 16 16 bytes of key data + * 0x0a 32 16 bytes of TKIP key data + * 8 bytes of RX MIC key data + * 8 bytes of TX MIC key data + * 0x0b 32 16 bytes of TKIP key data + * 8 bytes of RX MIC key data + * 8 bytes of TX MIC key data + * + */ + +struct acx_set_key { + /* Ignored for default WEP key */ + u8 addr[ETH_ALEN]; + + /* key_action_e */ + u16 key_action; + + u16 reserved_1; + + /* key size in bytes */ + u8 key_size; + + /* key_type_e */ + u8 key_type; + u8 ssid_profile; + + /* + * TKIP, AES: frame's key id field. + * For WEP default key: key id; + */ + u8 id; + u8 reserved_2[6]; + u8 key[MAX_KEY_SIZE]; + u16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY]; + u32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY]; +} __attribute__ ((packed)); + +struct acx_current_tx_power { + struct acx_header header; + + u8 current_tx_power; + u8 padding[3]; +} __attribute__ ((packed)); + +struct acx_dot11_default_key { + struct acx_header header; + + u8 id; + u8 pad[3]; +} __attribute__ ((packed)); + +struct acx_tsf_info { + struct acx_header header; + + u32 current_tsf_msb; + u32 current_tsf_lsb; + u32 last_TBTT_msb; + u32 last_TBTT_lsb; + u8 last_dtim_count; + u8 pad[3]; +} __attribute__ ((packed)); + +/* 802.11 PS */ +enum acx_ps_mode { + STATION_ACTIVE_MODE, + STATION_POWER_SAVE_MODE +}; + +struct acx_ps_params { + u8 ps_mode; /* STATION_* */ + u8 send_null_data; /* Do we have to send NULL data packet ? */ + u8 retries; /* Number of retires for the initial NULL data packet */ + + /* + * TUs during which the target stays awake after switching + * to power save mode. + */ + u8 hang_over_period; + u16 null_data_rate; + u8 pad[2]; +} __attribute__ ((packed)); + +enum acx_wake_up_event { + WAKE_UP_EVENT_BEACON_BITMAP = 0x01, /* Wake on every Beacon*/ + WAKE_UP_EVENT_DTIM_BITMAP = 0x02, /* Wake on every DTIM*/ + WAKE_UP_EVENT_N_DTIM_BITMAP = 0x04, /* Wake on every Nth DTIM */ + WAKE_UP_EVENT_N_BEACONS_BITMAP = 0x08, /* Wake on every Nth Beacon */ + WAKE_UP_EVENT_BITS_MASK = 0x0F +}; + +struct acx_wake_up_condition { + struct acx_header header; + + u8 wake_up_event; /* Only one bit can be set */ + u8 listen_interval; + u8 pad[2]; +} __attribute__ ((packed)); + +struct acx_aid { + struct acx_header header; + + /* + * To be set when associated with an AP. + */ + u16 aid; + u8 pad[2]; +} __attribute__ ((packed)); + +enum acx_preamble_type { + ACX_PREAMBLE_LONG = 0, + ACX_PREAMBLE_SHORT = 1 +}; + +struct acx_preamble { + struct acx_header header; + /* + * When set, the WiLink transmits the frames with a short preamble and + * when cleared, the WiLink transmits the frames with a long preamble. + */ + u8 preamble; + u8 padding[3]; +} __attribute__ ((packed)); + +enum acx_ctsprotect_type { + CTSPROTECT_DISABLE = 0, + CTSPROTECT_ENABLE = 1 +}; + +struct acx_ctsprotect { + struct acx_header header; + u8 ctsprotect; + u8 padding[3]; +} __attribute__ ((packed)); + +struct acx_tx_statistics { + u32 internal_desc_overflow; +} __attribute__ ((packed)); + +struct acx_rx_statistics { + u32 out_of_mem; + u32 hdr_overflow; + u32 hw_stuck; + u32 dropped; + u32 fcs_err; + u32 xfr_hint_trig; + u32 path_reset; + u32 reset_counter; +} __attribute__ ((packed)); + +struct acx_dma_statistics { + u32 rx_requested; + u32 rx_errors; + u32 tx_requested; + u32 tx_errors; +} __attribute__ ((packed)); + +struct acx_isr_statistics { + /* host command complete */ + u32 cmd_cmplt; + + /* fiqisr() */ + u32 fiqs; + + /* (INT_STS_ND & INT_TRIG_RX_HEADER) */ + u32 rx_headers; + + /* (INT_STS_ND & INT_TRIG_RX_CMPLT) */ + u32 rx_completes; + + /* (INT_STS_ND & INT_TRIG_NO_RX_BUF) */ + u32 rx_mem_overflow; + + /* (INT_STS_ND & INT_TRIG_S_RX_RDY) */ + u32 rx_rdys; + + /* irqisr() */ + u32 irqs; + + /* (INT_STS_ND & INT_TRIG_TX_PROC) */ + u32 tx_procs; + + /* (INT_STS_ND & INT_TRIG_DECRYPT_DONE) */ + u32 decrypt_done; + + /* (INT_STS_ND & INT_TRIG_DMA0) */ + u32 dma0_done; + + /* (INT_STS_ND & INT_TRIG_DMA1) */ + u32 dma1_done; + + /* (INT_STS_ND & INT_TRIG_TX_EXC_CMPLT) */ + u32 tx_exch_complete; + + /* (INT_STS_ND & INT_TRIG_COMMAND) */ + u32 commands; + + /* (INT_STS_ND & INT_TRIG_RX_PROC) */ + u32 rx_procs; + + /* (INT_STS_ND & INT_TRIG_PM_802) */ + u32 hw_pm_mode_changes; + + /* (INT_STS_ND & INT_TRIG_ACKNOWLEDGE) */ + u32 host_acknowledges; + + /* (INT_STS_ND & INT_TRIG_PM_PCI) */ + u32 pci_pm; + + /* (INT_STS_ND & INT_TRIG_ACM_WAKEUP) */ + u32 wakeups; + + /* (INT_STS_ND & INT_TRIG_LOW_RSSI) */ + u32 low_rssi; +} __attribute__ ((packed)); + +struct acx_wep_statistics { + /* WEP address keys configured */ + u32 addr_key_count; + + /* default keys configured */ + u32 default_key_count; + + u32 reserved; + + /* number of times that WEP key not found on lookup */ + u32 key_not_found; + + /* number of times that WEP key decryption failed */ + u32 decrypt_fail; + + /* WEP packets decrypted */ + u32 packets; + + /* WEP decrypt interrupts */ + u32 interrupt; +} __attribute__ ((packed)); + +#define ACX_MISSED_BEACONS_SPREAD 10 + +struct acx_pwr_statistics { + /* the amount of enters into power save mode (both PD & ELP) */ + u32 ps_enter; + + /* the amount of enters into ELP mode */ + u32 elp_enter; + + /* the amount of missing beacon interrupts to the host */ + u32 missing_bcns; + + /* the amount of wake on host-access times */ + u32 wake_on_host; + + /* the amount of wake on timer-expire */ + u32 wake_on_timer_exp; + + /* the number of packets that were transmitted with PS bit set */ + u32 tx_with_ps; + + /* the number of packets that were transmitted with PS bit clear */ + u32 tx_without_ps; + + /* the number of received beacons */ + u32 rcvd_beacons; + + /* the number of entering into PowerOn (power save off) */ + u32 power_save_off; + + /* the number of entries into power save mode */ + u16 enable_ps; + + /* + * the number of exits from power save, not including failed PS + * transitions + */ + u16 disable_ps; + + /* + * the number of times the TSF counter was adjusted because + * of drift + */ + u32 fix_tsf_ps; + + /* Gives statistics about the spread continuous missed beacons. + * The 16 LSB are dedicated for the PS mode. + * The 16 MSB are dedicated for the PS mode. + * cont_miss_bcns_spread[0] - single missed beacon. + * cont_miss_bcns_spread[1] - two continuous missed beacons. + * cont_miss_bcns_spread[2] - three continuous missed beacons. + * ... + * cont_miss_bcns_spread[9] - ten and more continuous missed beacons. + */ + u32 cont_miss_bcns_spread[ACX_MISSED_BEACONS_SPREAD]; + + /* the number of beacons in awake mode */ + u32 rcvd_awake_beacons; +} __attribute__ ((packed)); + +struct acx_mic_statistics { + u32 rx_pkts; + u32 calc_failure; +} __attribute__ ((packed)); + +struct acx_aes_statistics { + u32 encrypt_fail; + u32 decrypt_fail; + u32 encrypt_packets; + u32 decrypt_packets; + u32 encrypt_interrupt; + u32 decrypt_interrupt; +} __attribute__ ((packed)); + +struct acx_event_statistics { + u32 heart_beat; + u32 calibration; + u32 rx_mismatch; + u32 rx_mem_empty; + u32 rx_pool; + u32 oom_late; + u32 phy_transmit_error; + u32 tx_stuck; +} __attribute__ ((packed)); + +struct acx_ps_statistics { + u32 pspoll_timeouts; + u32 upsd_timeouts; + u32 upsd_max_sptime; + u32 upsd_max_apturn; + u32 pspoll_max_apturn; + u32 pspoll_utilization; + u32 upsd_utilization; +} __attribute__ ((packed)); + +struct acx_rxpipe_statistics { + u32 rx_prep_beacon_drop; + u32 descr_host_int_trig_rx_data; + u32 beacon_buffer_thres_host_int_trig_rx_data; + u32 missed_beacon_host_int_trig_rx_data; + u32 tx_xfr_host_int_trig_rx_data; +} __attribute__ ((packed)); + +struct acx_statistics { + struct acx_header header; + + struct acx_tx_statistics tx; + struct acx_rx_statistics rx; + struct acx_dma_statistics dma; + struct acx_isr_statistics isr; + struct acx_wep_statistics wep; + struct acx_pwr_statistics pwr; + struct acx_aes_statistics aes; + struct acx_mic_statistics mic; + struct acx_event_statistics event; + struct acx_ps_statistics ps; + struct acx_rxpipe_statistics rxpipe; +} __attribute__ ((packed)); + +enum { + ACX_WAKE_UP_CONDITIONS = 0x0002, + ACX_MEM_CFG = 0x0003, + ACX_SLOT = 0x0004, + ACX_QUEUE_HEAD = 0x0005, /* for MASTER mode only */ + ACX_AC_CFG = 0x0007, + ACX_MEM_MAP = 0x0008, + ACX_AID = 0x000A, + ACX_RADIO_PARAM = 0x000B, /* Not used */ + ACX_CFG = 0x000C, /* Not used */ + ACX_FW_REV = 0x000D, + ACX_MEDIUM_USAGE = 0x000F, + ACX_RX_CFG = 0x0010, + ACX_TX_QUEUE_CFG = 0x0011, /* FIXME: only used by wl1251 */ + ACX_BSS_IN_PS = 0x0012, /* for AP only */ + ACX_STATISTICS = 0x0013, /* Debug API */ + ACX_FEATURE_CFG = 0x0015, + ACX_MISC_CFG = 0x0017, /* Not used */ + ACX_TID_CFG = 0x001A, + ACX_BEACON_FILTER_OPT = 0x001F, + ACX_LOW_RSSI = 0x0020, + ACX_NOISE_HIST = 0x0021, + ACX_HDK_VERSION = 0x0022, /* ??? */ + ACX_PD_THRESHOLD = 0x0023, + ACX_DATA_PATH_PARAMS = 0x0024, /* WO */ + ACX_DATA_PATH_RESP_PARAMS = 0x0024, /* RO */ + ACX_CCA_THRESHOLD = 0x0025, + ACX_EVENT_MBOX_MASK = 0x0026, +#ifdef FW_RUNNING_AS_AP + ACX_DTIM_PERIOD = 0x0027, /* for AP only */ +#else + ACX_WR_TBTT_AND_DTIM = 0x0027, /* STA only */ +#endif + ACX_ACI_OPTION_CFG = 0x0029, /* OBSOLETE (for 1251)*/ + ACX_GPIO_CFG = 0x002A, /* Not used */ + ACX_GPIO_SET = 0x002B, /* Not used */ + ACX_PM_CFG = 0x002C, /* To Be Documented */ + ACX_CONN_MONIT_PARAMS = 0x002D, + ACX_AVERAGE_RSSI = 0x002E, /* Not used */ + ACX_CONS_TX_FAILURE = 0x002F, + ACX_BCN_DTIM_OPTIONS = 0x0031, + ACX_SG_ENABLE = 0x0032, + ACX_SG_CFG = 0x0033, + ACX_ANTENNA_DIVERSITY_CFG = 0x0035, /* To Be Documented */ + ACX_LOW_SNR = 0x0037, /* To Be Documented */ + ACX_BEACON_FILTER_TABLE = 0x0038, + ACX_ARP_IP_FILTER = 0x0039, + ACX_ROAMING_STATISTICS_TBL = 0x003B, + ACX_RATE_POLICY = 0x003D, + ACX_CTS_PROTECTION = 0x003E, + ACX_SLEEP_AUTH = 0x003F, + ACX_PREAMBLE_TYPE = 0x0040, + ACX_ERROR_CNT = 0x0041, + ACX_FW_GEN_FRAME_RATES = 0x0042, + ACX_IBSS_FILTER = 0x0044, + ACX_SERVICE_PERIOD_TIMEOUT = 0x0045, + ACX_TSF_INFO = 0x0046, + ACX_CONFIG_PS_WMM = 0x0049, + ACX_ENABLE_RX_DATA_FILTER = 0x004A, + ACX_SET_RX_DATA_FILTER = 0x004B, + ACX_GET_DATA_FILTER_STATISTICS = 0x004C, + ACX_POWER_LEVEL_TABLE = 0x004D, + ACX_BET_ENABLE = 0x0050, + DOT11_STATION_ID = 0x1001, + DOT11_RX_MSDU_LIFE_TIME = 0x1004, + DOT11_CUR_TX_PWR = 0x100D, + DOT11_DEFAULT_KEY = 0x1010, + DOT11_RX_DOT11_MODE = 0x1012, + DOT11_RTS_THRESHOLD = 0x1013, + DOT11_GROUP_ADDRESS_TBL = 0x1014, + + MAX_DOT11_IE = DOT11_GROUP_ADDRESS_TBL, + + MAX_IE = 0xFFFF +}; + + +int wl12xx_acx_frame_rates(struct wl12xx *wl, u8 ctrl_rate, u8 ctrl_mod, + u8 mgt_rate, u8 mgt_mod); +int wl12xx_acx_station_id(struct wl12xx *wl); +int wl12xx_acx_default_key(struct wl12xx *wl, u8 key_id); +int wl12xx_acx_wake_up_conditions(struct wl12xx *wl, u8 listen_interval); +int wl12xx_acx_sleep_auth(struct wl12xx *wl, u8 sleep_auth); +int wl12xx_acx_fw_version(struct wl12xx *wl, char *buf, size_t len); +int wl12xx_acx_tx_power(struct wl12xx *wl, int power); +int wl12xx_acx_feature_cfg(struct wl12xx *wl); +int wl12xx_acx_mem_map(struct wl12xx *wl, void *mem_map, size_t len); +int wl12xx_acx_data_path_params(struct wl12xx *wl, + struct acx_data_path_params_resp *data_path); +int wl12xx_acx_rx_msdu_life_time(struct wl12xx *wl, u32 life_time); +int wl12xx_acx_rx_config(struct wl12xx *wl, u32 config, u32 filter); +int wl12xx_acx_pd_threshold(struct wl12xx *wl); +int wl12xx_acx_slot(struct wl12xx *wl, enum acx_slot_type slot_time); +int wl12xx_acx_group_address_tbl(struct wl12xx *wl); +int wl12xx_acx_service_period_timeout(struct wl12xx *wl); +int wl12xx_acx_rts_threshold(struct wl12xx *wl, u16 rts_threshold); +int wl12xx_acx_beacon_filter_opt(struct wl12xx *wl); +int wl12xx_acx_beacon_filter_table(struct wl12xx *wl); +int wl12xx_acx_sg_enable(struct wl12xx *wl); +int wl12xx_acx_sg_cfg(struct wl12xx *wl); +int wl12xx_acx_cca_threshold(struct wl12xx *wl); +int wl12xx_acx_bcn_dtim_options(struct wl12xx *wl); +int wl12xx_acx_aid(struct wl12xx *wl, u16 aid); +int wl12xx_acx_event_mbox_mask(struct wl12xx *wl, u32 event_mask); +int wl12xx_acx_set_preamble(struct wl12xx *wl, enum acx_preamble_type preamble); +int wl12xx_acx_cts_protect(struct wl12xx *wl, + enum acx_ctsprotect_type ctsprotect); +int wl12xx_acx_statistics(struct wl12xx *wl, struct acx_statistics *stats); + +#endif /* __WL12XX_ACX_H__ */ diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c new file mode 100644 index 000000000000..48ac08c429bd --- /dev/null +++ b/drivers/net/wireless/wl12xx/boot.c @@ -0,0 +1,295 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include + +#include "reg.h" +#include "boot.h" +#include "spi.h" +#include "event.h" + +static void wl12xx_boot_enable_interrupts(struct wl12xx *wl) +{ + enable_irq(wl->irq); +} + +void wl12xx_boot_target_enable_interrupts(struct wl12xx *wl) +{ + wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); + wl12xx_reg_write32(wl, HI_CFG, HI_CFG_DEF_VAL); +} + +int wl12xx_boot_soft_reset(struct wl12xx *wl) +{ + unsigned long timeout; + u32 boot_data; + + /* perform soft reset */ + wl12xx_reg_write32(wl, ACX_REG_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT); + + /* SOFT_RESET is self clearing */ + timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME); + while (1) { + boot_data = wl12xx_reg_read32(wl, ACX_REG_SLV_SOFT_RESET); + wl12xx_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data); + if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0) + break; + + if (time_after(jiffies, timeout)) { + /* 1.2 check pWhalBus->uSelfClearTime if the + * timeout was reached */ + wl12xx_error("soft reset timeout"); + return -1; + } + + udelay(SOFT_RESET_STALL_TIME); + } + + /* disable Rx/Tx */ + wl12xx_reg_write32(wl, ENABLE, 0x0); + + /* disable auto calibration on start*/ + wl12xx_reg_write32(wl, SPARE_A2, 0xffff); + + return 0; +} + +int wl12xx_boot_init_seq(struct wl12xx *wl) +{ + u32 scr_pad6, init_data, tmp, elp_cmd, ref_freq; + + /* + * col #1: INTEGER_DIVIDER + * col #2: FRACTIONAL_DIVIDER + * col #3: ATTN_BB + * col #4: ALPHA_BB + * col #5: STOP_TIME_BB + * col #6: BB_PLL_LOOP_FILTER + */ + static const u32 LUT[REF_FREQ_NUM][LUT_PARAM_NUM] = { + + { 83, 87381, 0xB, 5, 0xF00, 3}, /* REF_FREQ_19_2*/ + { 61, 141154, 0xB, 5, 0x1450, 2}, /* REF_FREQ_26_0*/ + { 41, 174763, 0xC, 6, 0x2D00, 1}, /* REF_FREQ_38_4*/ + { 40, 0, 0xC, 6, 0x2EE0, 1}, /* REF_FREQ_40_0*/ + { 47, 162280, 0xC, 6, 0x2760, 1} /* REF_FREQ_33_6 */ + }; + + /* read NVS params */ + scr_pad6 = wl12xx_reg_read32(wl, SCR_PAD6); + wl12xx_debug(DEBUG_BOOT, "scr_pad6 0x%x", scr_pad6); + + /* read ELP_CMD */ + elp_cmd = wl12xx_reg_read32(wl, ELP_CMD); + wl12xx_debug(DEBUG_BOOT, "elp_cmd 0x%x", elp_cmd); + + /* set the BB calibration time to be 300 usec (PLL_CAL_TIME) */ + ref_freq = scr_pad6 & 0x000000FF; + wl12xx_debug(DEBUG_BOOT, "ref_freq 0x%x", ref_freq); + + wl12xx_reg_write32(wl, PLL_CAL_TIME, 0x9); + + /* + * PG 1.2: set the clock buffer time to be 210 usec (CLK_BUF_TIME) + */ + wl12xx_reg_write32(wl, CLK_BUF_TIME, 0x6); + + /* + * set the clock detect feature to work in the restart wu procedure + * (ELP_CFG_MODE[14]) and Select the clock source type + * (ELP_CFG_MODE[13:12]) + */ + tmp = ((scr_pad6 & 0x0000FF00) << 4) | 0x00004000; + wl12xx_reg_write32(wl, ELP_CFG_MODE, tmp); + + /* PG 1.2: enable the BB PLL fix. Enable the PLL_LIMP_CLK_EN_CMD */ + elp_cmd |= 0x00000040; + wl12xx_reg_write32(wl, ELP_CMD, elp_cmd); + + /* PG 1.2: Set the BB PLL stable time to be 1000usec + * (PLL_STABLE_TIME) */ + wl12xx_reg_write32(wl, CFG_PLL_SYNC_CNT, 0x20); + + /* PG 1.2: read clock request time */ + init_data = wl12xx_reg_read32(wl, CLK_REQ_TIME); + + /* + * PG 1.2: set the clock request time to be ref_clk_settling_time - + * 1ms = 4ms + */ + if (init_data > 0x21) + tmp = init_data - 0x21; + else + tmp = 0; + wl12xx_reg_write32(wl, CLK_REQ_TIME, tmp); + + /* set BB PLL configurations in RF AFE */ + wl12xx_reg_write32(wl, 0x003058cc, 0x4B5); + + /* set RF_AFE_REG_5 */ + wl12xx_reg_write32(wl, 0x003058d4, 0x50); + + /* set RF_AFE_CTRL_REG_2 */ + wl12xx_reg_write32(wl, 0x00305948, 0x11c001); + + /* + * change RF PLL and BB PLL divider for VCO clock and adjust VCO + * bais current(RF_AFE_REG_13) + */ + wl12xx_reg_write32(wl, 0x003058f4, 0x1e); + + /* set BB PLL configurations */ + tmp = LUT[ref_freq][LUT_PARAM_INTEGER_DIVIDER] | 0x00017000; + wl12xx_reg_write32(wl, 0x00305840, tmp); + + /* set fractional divider according to Appendix C-BB PLL + * Calculations + */ + tmp = LUT[ref_freq][LUT_PARAM_FRACTIONAL_DIVIDER]; + wl12xx_reg_write32(wl, 0x00305844, tmp); + + /* set the initial data for the sigma delta */ + wl12xx_reg_write32(wl, 0x00305848, 0x3039); + + /* + * set the accumulator attenuation value, calibration loop1 + * (alpha), calibration loop2 (beta), calibration loop3 (gamma) and + * the VCO gain + */ + tmp = (LUT[ref_freq][LUT_PARAM_ATTN_BB] << 16) | + (LUT[ref_freq][LUT_PARAM_ALPHA_BB] << 12) | 0x1; + wl12xx_reg_write32(wl, 0x00305854, tmp); + + /* + * set the calibration stop time after holdoff time expires and set + * settling time HOLD_OFF_TIME_BB + */ + tmp = LUT[ref_freq][LUT_PARAM_STOP_TIME_BB] | 0x000A0000; + wl12xx_reg_write32(wl, 0x00305858, tmp); + + /* + * set BB PLL Loop filter capacitor3- BB_C3[2:0] and set BB PLL + * constant leakage current to linearize PFD to 0uA - + * BB_ILOOPF[7:3] + */ + tmp = LUT[ref_freq][LUT_PARAM_BB_PLL_LOOP_FILTER] | 0x00000030; + wl12xx_reg_write32(wl, 0x003058f8, tmp); + + /* + * set regulator output voltage for n divider to + * 1.35-BB_REFDIV[1:0], set charge pump current- BB_CPGAIN[4:2], + * set BB PLL Loop filter capacitor2- BB_C2[7:5], set gain of BB + * PLL auto-call to normal mode- BB_CALGAIN_3DB[8] + */ + wl12xx_reg_write32(wl, 0x003058f0, 0x29); + + /* enable restart wakeup sequence (ELP_CMD[0]) */ + wl12xx_reg_write32(wl, ELP_CMD, elp_cmd | 0x1); + + /* restart sequence completed */ + udelay(2000); + + return 0; +} + +int wl12xx_boot_run_firmware(struct wl12xx *wl) +{ + int loop, ret; + u32 chip_id, interrupt; + + wl->chip.op_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT); + + chip_id = wl12xx_reg_read32(wl, CHIP_ID_B); + + wl12xx_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id); + + if (chip_id != wl->chip.id) { + wl12xx_error("chip id doesn't match after firmware boot"); + return -EIO; + } + + /* wait for init to complete */ + loop = 0; + while (loop++ < INIT_LOOP) { + udelay(INIT_LOOP_DELAY); + interrupt = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); + + if (interrupt == 0xffffffff) { + wl12xx_error("error reading hardware complete " + "init indication"); + return -EIO; + } + /* check that ACX_INTR_INIT_COMPLETE is enabled */ + else if (interrupt & wl->chip.intr_init_complete) { + wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_ACK, + wl->chip.intr_init_complete); + break; + } + } + + if (loop >= INIT_LOOP) { + wl12xx_error("timeout waiting for the hardware to " + "complete initialization"); + return -EIO; + } + + /* get hardware config command mail box */ + wl->cmd_box_addr = wl12xx_reg_read32(wl, REG_COMMAND_MAILBOX_PTR); + + /* get hardware config event mail box */ + wl->event_box_addr = wl12xx_reg_read32(wl, REG_EVENT_MAILBOX_PTR); + + /* set the working partition to its "running" mode offset */ + wl12xx_set_partition(wl, + wl->chip.p_table[PART_WORK].mem.start, + wl->chip.p_table[PART_WORK].mem.size, + wl->chip.p_table[PART_WORK].reg.start, + wl->chip.p_table[PART_WORK].reg.size); + + wl12xx_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x", + wl->cmd_box_addr, wl->event_box_addr); + + /* + * in case of full asynchronous mode the firmware event must be + * ready to receive event from the command mailbox + */ + + /* enable gpio interrupts */ + wl12xx_boot_enable_interrupts(wl); + + wl->chip.op_target_enable_interrupts(wl); + + /* unmask all mbox events */ + wl->event_mask = 0xffffffff; + + ret = wl12xx_event_unmask(wl); + if (ret < 0) { + wl12xx_error("EVENT mask setting failed"); + return ret; + } + + wl12xx_event_mbox_config(wl); + + /* firmware startup completed */ + return 0; +} diff --git a/drivers/net/wireless/wl12xx/boot.h b/drivers/net/wireless/wl12xx/boot.h new file mode 100644 index 000000000000..4fa73132baae --- /dev/null +++ b/drivers/net/wireless/wl12xx/boot.h @@ -0,0 +1,40 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __BOOT_H__ +#define __BOOT_H__ + +#include "wl12xx.h" + +int wl12xx_boot_soft_reset(struct wl12xx *wl); +int wl12xx_boot_init_seq(struct wl12xx *wl); +int wl12xx_boot_run_firmware(struct wl12xx *wl); +void wl12xx_boot_target_enable_interrupts(struct wl12xx *wl); + +/* number of times we try to read the INIT interrupt */ +#define INIT_LOOP 20000 + +/* delay between retries */ +#define INIT_LOOP_DELAY 50 + +#endif diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c new file mode 100644 index 000000000000..f73ab602b7ae --- /dev/null +++ b/drivers/net/wireless/wl12xx/cmd.c @@ -0,0 +1,353 @@ +#include "cmd.h" + +#include +#include +#include + +#include "wl12xx.h" +#include "wl12xx_80211.h" +#include "reg.h" +#include "spi.h" +#include "ps.h" + +int wl12xx_cmd_send(struct wl12xx *wl, u16 type, void *buf, size_t buf_len) +{ + struct wl12xx_command cmd; + unsigned long timeout; + size_t cmd_len; + u32 intr; + int ret = 0; + + memset(&cmd, 0, sizeof(cmd)); + cmd.id = type; + cmd.status = 0; + memcpy(cmd.parameters, buf, buf_len); + cmd_len = ALIGN(buf_len, 4) + CMDMBOX_HEADER_LEN; + + wl12xx_ps_elp_wakeup(wl); + + wl12xx_spi_mem_write(wl, wl->cmd_box_addr, &cmd, cmd_len); + + wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD); + + timeout = jiffies + msecs_to_jiffies(WL12XX_COMMAND_TIMEOUT); + + intr = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); + while (!(intr & wl->chip.intr_cmd_complete)) { + if (time_after(jiffies, timeout)) { + wl12xx_error("command complete timeout"); + ret = -ETIMEDOUT; + goto out; + } + + msleep(1); + + intr = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); + } + + wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_ACK, + wl->chip.intr_cmd_complete); + +out: + wl12xx_ps_elp_sleep(wl); + + return ret; +} + +int wl12xx_cmd_test(struct wl12xx *wl, void *buf, size_t buf_len, u8 answer) +{ + int ret; + + wl12xx_debug(DEBUG_CMD, "cmd test"); + + ret = wl12xx_cmd_send(wl, CMD_TEST, buf, buf_len); + if (ret < 0) { + wl12xx_warning("TEST command failed"); + return ret; + } + + if (answer) { + struct wl12xx_command *cmd_answer; + + /* + * The test command got in, we can read the answer. + * The answer would be a wl12xx_command, where the + * parameter array contains the actual answer. + */ + + wl12xx_ps_elp_wakeup(wl); + + wl12xx_spi_mem_read(wl, wl->cmd_box_addr, buf, buf_len); + + wl12xx_ps_elp_sleep(wl); + + cmd_answer = buf; + if (cmd_answer->status != CMD_STATUS_SUCCESS) + wl12xx_error("TEST command answer error: %d", + cmd_answer->status); + } + + return 0; +} + + +int wl12xx_cmd_interrogate(struct wl12xx *wl, u16 ie_id, u16 ie_len, + void *answer) +{ + struct wl12xx_command *cmd; + struct acx_header header; + int ret; + + wl12xx_debug(DEBUG_CMD, "cmd interrogate"); + + header.id = ie_id; + header.len = ie_len - sizeof(header); + + ret = wl12xx_cmd_send(wl, CMD_INTERROGATE, &header, sizeof(header)); + if (ret < 0) { + wl12xx_error("INTERROGATE command failed"); + return ret; + } + + wl12xx_ps_elp_wakeup(wl); + + /* the interrogate command got in, we can read the answer */ + wl12xx_spi_mem_read(wl, wl->cmd_box_addr, answer, + CMDMBOX_HEADER_LEN + ie_len); + + wl12xx_ps_elp_sleep(wl); + + cmd = answer; + if (cmd->status != CMD_STATUS_SUCCESS) + wl12xx_error("INTERROGATE command error: %d", + cmd->status); + + return 0; + +} + +int wl12xx_cmd_configure(struct wl12xx *wl, void *ie, int ie_len) +{ + int ret; + + wl12xx_debug(DEBUG_CMD, "cmd configure"); + + ret = wl12xx_cmd_send(wl, CMD_CONFIGURE, ie, + ie_len); + if (ret < 0) { + wl12xx_warning("CONFIGURE command NOK"); + return ret; + } + + return 0; + +} + +int wl12xx_cmd_vbm(struct wl12xx *wl, u8 identity, + void *bitmap, u16 bitmap_len, u8 bitmap_control) +{ + struct vbm_update_request vbm; + int ret; + + wl12xx_debug(DEBUG_CMD, "cmd vbm"); + + /* Count and period will be filled by the target */ + vbm.tim.bitmap_ctrl = bitmap_control; + if (bitmap_len > PARTIAL_VBM_MAX) { + wl12xx_warning("cmd vbm len is %d B, truncating to %d", + bitmap_len, PARTIAL_VBM_MAX); + bitmap_len = PARTIAL_VBM_MAX; + } + memcpy(vbm.tim.pvb_field, bitmap, bitmap_len); + vbm.tim.identity = identity; + vbm.tim.length = bitmap_len + 3; + + vbm.len = cpu_to_le16(bitmap_len + 5); + + ret = wl12xx_cmd_send(wl, CMD_VBM, &vbm, sizeof(vbm)); + if (ret < 0) { + wl12xx_error("VBM command failed"); + return ret; + } + + return 0; +} + +int wl12xx_cmd_data_path(struct wl12xx *wl, u8 channel, u8 enable) +{ + int ret; + u16 cmd_rx, cmd_tx; + + wl12xx_debug(DEBUG_CMD, "cmd data path"); + + if (enable) { + cmd_rx = CMD_ENABLE_RX; + cmd_tx = CMD_ENABLE_TX; + } else { + cmd_rx = CMD_DISABLE_RX; + cmd_tx = CMD_DISABLE_TX; + } + + ret = wl12xx_cmd_send(wl, cmd_rx, &channel, sizeof(channel)); + if (ret < 0) { + wl12xx_error("rx %s cmd for channel %d failed", + enable ? "start" : "stop", channel); + return ret; + } + + wl12xx_debug(DEBUG_BOOT, "rx %s cmd channel %d", + enable ? "start" : "stop", channel); + + ret = wl12xx_cmd_send(wl, cmd_tx, &channel, sizeof(channel)); + if (ret < 0) { + wl12xx_error("tx %s cmd for channel %d failed", + enable ? "start" : "stop", channel); + return ret; + } + + wl12xx_debug(DEBUG_BOOT, "tx %s cmd channel %d", + enable ? "start" : "stop", channel); + + return 0; +} + +int wl12xx_cmd_join(struct wl12xx *wl, u8 bss_type, u8 dtim_interval, + u16 beacon_interval, u8 wait) +{ + unsigned long timeout; + struct cmd_join join = {}; + int ret, i; + u8 *bssid; + + /* FIXME: this should be in main.c */ + ret = wl12xx_acx_frame_rates(wl, DEFAULT_HW_GEN_TX_RATE, + DEFAULT_HW_GEN_MODULATION_TYPE, + wl->tx_mgmt_frm_rate, + wl->tx_mgmt_frm_mod); + if (ret < 0) + return ret; + + wl12xx_debug(DEBUG_CMD, "cmd join"); + + /* Reverse order BSSID */ + bssid = (u8 *)&join.bssid_lsb; + for (i = 0; i < ETH_ALEN; i++) + bssid[i] = wl->bssid[ETH_ALEN - i - 1]; + + join.rx_config_options = wl->rx_config; + join.rx_filter_options = wl->rx_filter; + + join.basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS | + RATE_MASK_5_5MBPS | RATE_MASK_11MBPS; + + join.beacon_interval = beacon_interval; + join.dtim_interval = dtim_interval; + join.bss_type = bss_type; + join.channel = wl->channel; + join.ctrl = JOIN_CMD_CTRL_TX_FLUSH; + + ret = wl12xx_cmd_send(wl, CMD_START_JOIN, &join, sizeof(join)); + if (ret < 0) { + wl12xx_error("failed to initiate cmd join"); + return ret; + } + + timeout = msecs_to_jiffies(JOIN_TIMEOUT); + + /* + * ugly hack: we should wait for JOIN_EVENT_COMPLETE_ID but to + * simplify locking we just sleep instead, for now + */ + if (wait) + msleep(10); + + return 0; +} + +int wl12xx_cmd_ps_mode(struct wl12xx *wl, u8 ps_mode) +{ + int ret; + struct acx_ps_params ps_params; + + /* FIXME: this should be in ps.c */ + ret = wl12xx_acx_wake_up_conditions(wl, wl->listen_int); + if (ret < 0) { + wl12xx_error("Couldnt set wake up conditions"); + return ret; + } + + wl12xx_debug(DEBUG_CMD, "cmd set ps mode"); + + ps_params.ps_mode = ps_mode; + ps_params.send_null_data = 1; + ps_params.retries = 5; + ps_params.hang_over_period = 128; + ps_params.null_data_rate = 1; /* 1 Mbps */ + + ret = wl12xx_cmd_send(wl, CMD_SET_PS_MODE, &ps_params, + sizeof(ps_params)); + if (ret < 0) { + wl12xx_error("cmd set_ps_mode failed"); + return ret; + } + + return 0; +} + +int wl12xx_cmd_read_memory(struct wl12xx *wl, u32 addr, u32 len, void *answer) +{ + struct cmd_read_write_memory mem_cmd, *mem_answer; + struct wl12xx_command cmd; + int ret; + + wl12xx_debug(DEBUG_CMD, "cmd read memory"); + + memset(&mem_cmd, 0, sizeof(mem_cmd)); + mem_cmd.addr = addr; + mem_cmd.size = len; + + ret = wl12xx_cmd_send(wl, CMD_READ_MEMORY, &mem_cmd, sizeof(mem_cmd)); + if (ret < 0) { + wl12xx_error("read memory command failed: %d", ret); + return ret; + } + + /* the read command got in, we can now read the answer */ + wl12xx_spi_mem_read(wl, wl->cmd_box_addr, &cmd, + CMDMBOX_HEADER_LEN + sizeof(mem_cmd)); + + if (cmd.status != CMD_STATUS_SUCCESS) + wl12xx_error("error in read command result: %d", cmd.status); + + mem_answer = (struct cmd_read_write_memory *) cmd.parameters; + memcpy(answer, mem_answer->value, len); + + return 0; +} + +int wl12xx_cmd_template_set(struct wl12xx *wl, u16 cmd_id, + void *buf, size_t buf_len) +{ + struct wl12xx_cmd_packet_template template; + int ret; + + wl12xx_debug(DEBUG_CMD, "cmd template %d", cmd_id); + + memset(&template, 0, sizeof(template)); + + WARN_ON(buf_len > WL12XX_MAX_TEMPLATE_SIZE); + buf_len = min_t(size_t, buf_len, WL12XX_MAX_TEMPLATE_SIZE); + template.size = cpu_to_le16(buf_len); + + if (buf) + memcpy(template.template, buf, buf_len); + + ret = wl12xx_cmd_send(wl, cmd_id, &template, + sizeof(template.size) + buf_len); + if (ret < 0) { + wl12xx_warning("cmd set_template failed: %d", ret); + return ret; + } + + return 0; +} diff --git a/drivers/net/wireless/wl12xx/cmd.h b/drivers/net/wireless/wl12xx/cmd.h new file mode 100644 index 000000000000..aa307dcd081f --- /dev/null +++ b/drivers/net/wireless/wl12xx/cmd.h @@ -0,0 +1,265 @@ +/* + * This file is part of wl12xx + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL12XX_CMD_H__ +#define __WL12XX_CMD_H__ + +#include "wl12xx.h" + +int wl12xx_cmd_send(struct wl12xx *wl, u16 type, void *buf, size_t buf_len); +int wl12xx_cmd_test(struct wl12xx *wl, void *buf, size_t buf_len, u8 answer); +int wl12xx_cmd_interrogate(struct wl12xx *wl, u16 ie_id, u16 ie_len, + void *answer); +int wl12xx_cmd_configure(struct wl12xx *wl, void *ie, int ie_len); +int wl12xx_cmd_vbm(struct wl12xx *wl, u8 identity, + void *bitmap, u16 bitmap_len, u8 bitmap_control); +int wl12xx_cmd_data_path(struct wl12xx *wl, u8 channel, u8 enable); +int wl12xx_cmd_join(struct wl12xx *wl, u8 bss_type, u8 dtim_interval, + u16 beacon_interval, u8 wait); +int wl12xx_cmd_ps_mode(struct wl12xx *wl, u8 ps_mode); +int wl12xx_cmd_read_memory(struct wl12xx *wl, u32 addr, u32 len, void *answer); +int wl12xx_cmd_template_set(struct wl12xx *wl, u16 cmd_id, + void *buf, size_t buf_len); + +/* unit ms */ +#define WL12XX_COMMAND_TIMEOUT 2000 + +#define WL12XX_MAX_TEMPLATE_SIZE 300 + +struct wl12xx_cmd_packet_template { + __le16 size; + u8 template[WL12XX_MAX_TEMPLATE_SIZE]; +} __attribute__ ((packed)); + +enum wl12xx_commands { + CMD_RESET = 0, + CMD_INTERROGATE = 1, /*use this to read information elements*/ + CMD_CONFIGURE = 2, /*use this to write information elements*/ + CMD_ENABLE_RX = 3, + CMD_ENABLE_TX = 4, + CMD_DISABLE_RX = 5, + CMD_DISABLE_TX = 6, + CMD_SCAN = 8, + CMD_STOP_SCAN = 9, + CMD_VBM = 10, + CMD_START_JOIN = 11, + CMD_SET_KEYS = 12, + CMD_READ_MEMORY = 13, + CMD_WRITE_MEMORY = 14, + CMD_BEACON = 19, + CMD_PROBE_RESP = 20, + CMD_NULL_DATA = 21, + CMD_PROBE_REQ = 22, + CMD_TEST = 23, + CMD_RADIO_CALIBRATE = 25, /* OBSOLETE */ + CMD_ENABLE_RX_PATH = 27, /* OBSOLETE */ + CMD_NOISE_HIST = 28, + CMD_RX_RESET = 29, + CMD_PS_POLL = 30, + CMD_QOS_NULL_DATA = 31, + CMD_LNA_CONTROL = 32, + CMD_SET_BCN_MODE = 33, + CMD_MEASUREMENT = 34, + CMD_STOP_MEASUREMENT = 35, + CMD_DISCONNECT = 36, + CMD_SET_PS_MODE = 37, + CMD_CHANNEL_SWITCH = 38, + CMD_STOP_CHANNEL_SWICTH = 39, + CMD_AP_DISCOVERY = 40, + CMD_STOP_AP_DISCOVERY = 41, + CMD_SPS_SCAN = 42, + CMD_STOP_SPS_SCAN = 43, + CMD_HEALTH_CHECK = 45, + CMD_DEBUG = 46, + CMD_TRIGGER_SCAN_TO = 47, + + NUM_COMMANDS, + MAX_COMMAND_ID = 0xFFFF, +}; + +#define MAX_CMD_PARAMS 572 + +struct wl12xx_command { + u16 id; + u16 status; + u8 parameters[MAX_CMD_PARAMS]; +}; + +enum { + CMD_MAILBOX_IDLE = 0, + CMD_STATUS_SUCCESS = 1, + CMD_STATUS_UNKNOWN_CMD = 2, + CMD_STATUS_UNKNOWN_IE = 3, + CMD_STATUS_REJECT_MEAS_SG_ACTIVE = 11, + CMD_STATUS_RX_BUSY = 13, + CMD_STATUS_INVALID_PARAM = 14, + CMD_STATUS_TEMPLATE_TOO_LARGE = 15, + CMD_STATUS_OUT_OF_MEMORY = 16, + CMD_STATUS_STA_TABLE_FULL = 17, + CMD_STATUS_RADIO_ERROR = 18, + CMD_STATUS_WRONG_NESTING = 19, + CMD_STATUS_TIMEOUT = 21, /* Driver internal use.*/ + CMD_STATUS_FW_RESET = 22, /* Driver internal use.*/ + MAX_COMMAND_STATUS = 0xff +}; + + +/* + * CMD_READ_MEMORY + * + * The host issues this command to read the WiLink device memory/registers. + * + * Note: The Base Band address has special handling (16 bits registers and + * addresses). For more information, see the hardware specification. + */ +/* + * CMD_WRITE_MEMORY + * + * The host issues this command to write the WiLink device memory/registers. + * + * The Base Band address has special handling (16 bits registers and + * addresses). For more information, see the hardware specification. + */ +#define MAX_READ_SIZE 256 + +struct cmd_read_write_memory { + /* The address of the memory to read from or write to.*/ + u32 addr; + + /* The amount of data in bytes to read from or write to the WiLink + * device.*/ + u32 size; + + /* The actual value read from or written to the Wilink. The source + of this field is the Host in WRITE command or the Wilink in READ + command. */ + u8 value[MAX_READ_SIZE]; +}; + +#define CMDMBOX_HEADER_LEN 4 +#define CMDMBOX_INFO_ELEM_HEADER_LEN 4 + + +struct basic_scan_parameters { + u32 rx_config_options; + u32 rx_filter_options; + + /* + * Scan options: + * bit 0: When this bit is set, passive scan. + * bit 1: Band, when this bit is set we scan + * in the 5Ghz band. + * bit 2: voice mode, 0 for normal scan. + * bit 3: scan priority, 1 for high priority. + */ + u16 scan_options; + + /* Number of channels to scan */ + u8 num_channels; + + /* Number opf probe requests to send, per channel */ + u8 num_probe_requests; + + /* Rate and modulation for probe requests */ + u16 tx_rate; + + u8 tid_trigger; + u8 ssid_len; + u32 ssid[8]; + +} __attribute__ ((packed)); + +struct basic_scan_channel_parameters { + u32 min_duration; /* in TU */ + u32 max_duration; /* in TU */ + u32 bssid_lsb; + u16 bssid_msb; + + /* + * bits 0-3: Early termination count. + * bits 4-5: Early termination condition. + */ + u8 early_termination; + + u8 tx_power_att; + u8 channel; + u8 pad[3]; +} __attribute__ ((packed)); + +/* SCAN parameters */ +#define SCAN_MAX_NUM_OF_CHANNELS 16 + +struct cmd_scan { + struct basic_scan_parameters params; + struct basic_scan_channel_parameters channels[SCAN_MAX_NUM_OF_CHANNELS]; +} __attribute__ ((packed)); + +enum { + BSS_TYPE_IBSS = 0, + BSS_TYPE_STA_BSS = 2, + BSS_TYPE_AP_BSS = 3, + MAX_BSS_TYPE = 0xFF +}; + +#define JOIN_CMD_CTRL_TX_FLUSH 0x80 /* Firmware flushes all Tx */ +#define JOIN_CMD_CTRL_EARLY_WAKEUP_ENABLE 0x01 /* Early wakeup time */ + + +struct cmd_join { + u32 bssid_lsb; + u16 bssid_msb; + u16 beacon_interval; /* in TBTTs */ + u32 rx_config_options; + u32 rx_filter_options; + + /* + * The target uses this field to determine the rate at + * which to transmit control frame responses (such as + * ACK or CTS frames). + */ + u16 basic_rate_set; + u8 dtim_interval; + u8 tx_ctrl_frame_rate; /* OBSOLETE */ + u8 tx_ctrl_frame_mod; /* OBSOLETE */ + /* + * bits 0-2: This bitwise field specifies the type + * of BSS to start or join (BSS_TYPE_*). + * bit 4: Band - The radio band in which to join + * or start. + * 0 - 2.4GHz band + * 1 - 5GHz band + * bits 3, 5-7: Reserved + */ + u8 bss_type; + u8 channel; + u8 ssid_len; + u8 ssid[IW_ESSID_MAX_SIZE]; + u8 ctrl; /* JOIN_CMD_CTRL_* */ + u8 tx_mgt_frame_rate; /* OBSOLETE */ + u8 tx_mgt_frame_mod; /* OBSOLETE */ + u8 reserved; +} __attribute__ ((packed)); + + +#endif /* __WL12XX_CMD_H__ */ diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c new file mode 100644 index 000000000000..cdb368ce4dae --- /dev/null +++ b/drivers/net/wireless/wl12xx/debugfs.c @@ -0,0 +1,508 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "debugfs.h" + +#include + +#include "wl12xx.h" +#include "acx.h" + +/* ms */ +#define WL12XX_DEBUGFS_STATS_LIFETIME 1000 + +/* debugfs macros idea from mac80211 */ + +#define DEBUGFS_READONLY_FILE(name, buflen, fmt, value...) \ +static ssize_t name## _read(struct file *file, char __user *userbuf, \ + size_t count, loff_t *ppos) \ +{ \ + struct wl12xx *wl = file->private_data; \ + char buf[buflen]; \ + int res; \ + \ + res = scnprintf(buf, buflen, fmt "\n", ##value); \ + return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ +} \ + \ +static const struct file_operations name## _ops = { \ + .read = name## _read, \ + .open = wl12xx_open_file_generic, \ +}; + +#define DEBUGFS_ADD(name, parent) \ + wl->debugfs.name = debugfs_create_file(#name, 0400, parent, \ + wl, &name## _ops); \ + if (IS_ERR(wl->debugfs.name)) { \ + ret = PTR_ERR(wl->debugfs.name); \ + wl->debugfs.name = NULL; \ + goto out; \ + } + +#define DEBUGFS_DEL(name) \ + do { \ + debugfs_remove(wl->debugfs.name); \ + wl->debugfs.name = NULL; \ + } while (0) + +#define DEBUGFS_FWSTATS_FILE(sub, name, buflen, fmt) \ +static ssize_t sub## _ ##name## _read(struct file *file, \ + char __user *userbuf, \ + size_t count, loff_t *ppos) \ +{ \ + struct wl12xx *wl = file->private_data; \ + char buf[buflen]; \ + int res; \ + \ + wl12xx_debugfs_update_stats(wl); \ + \ + res = scnprintf(buf, buflen, fmt "\n", \ + wl->stats.fw_stats->sub.name); \ + return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ +} \ + \ +static const struct file_operations sub## _ ##name## _ops = { \ + .read = sub## _ ##name## _read, \ + .open = wl12xx_open_file_generic, \ +}; + +#define DEBUGFS_FWSTATS_ADD(sub, name) \ + DEBUGFS_ADD(sub## _ ##name, wl->debugfs.fw_statistics) + +#define DEBUGFS_FWSTATS_DEL(sub, name) \ + DEBUGFS_DEL(sub## _ ##name) + +static void wl12xx_debugfs_update_stats(struct wl12xx *wl) +{ + mutex_lock(&wl->mutex); + + if (wl->state == WL12XX_STATE_ON && + time_after(jiffies, wl->stats.fw_stats_update + + msecs_to_jiffies(WL12XX_DEBUGFS_STATS_LIFETIME))) { + wl12xx_acx_statistics(wl, wl->stats.fw_stats); + wl->stats.fw_stats_update = jiffies; + } + + mutex_unlock(&wl->mutex); +} + +static int wl12xx_open_file_generic(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +DEBUGFS_FWSTATS_FILE(tx, internal_desc_overflow, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(rx, out_of_mem, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rx, hdr_overflow, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rx, hw_stuck, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rx, dropped, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rx, fcs_err, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rx, xfr_hint_trig, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rx, path_reset, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rx, reset_counter, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(dma, rx_requested, 20, "%u"); +DEBUGFS_FWSTATS_FILE(dma, rx_errors, 20, "%u"); +DEBUGFS_FWSTATS_FILE(dma, tx_requested, 20, "%u"); +DEBUGFS_FWSTATS_FILE(dma, tx_errors, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(isr, cmd_cmplt, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, fiqs, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, rx_headers, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, rx_mem_overflow, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, rx_rdys, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, irqs, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, tx_procs, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, decrypt_done, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, dma0_done, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, dma1_done, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, tx_exch_complete, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, commands, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, rx_procs, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, hw_pm_mode_changes, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, host_acknowledges, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, pci_pm, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, wakeups, 20, "%u"); +DEBUGFS_FWSTATS_FILE(isr, low_rssi, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(wep, addr_key_count, 20, "%u"); +DEBUGFS_FWSTATS_FILE(wep, default_key_count, 20, "%u"); +/* skipping wep.reserved */ +DEBUGFS_FWSTATS_FILE(wep, key_not_found, 20, "%u"); +DEBUGFS_FWSTATS_FILE(wep, decrypt_fail, 20, "%u"); +DEBUGFS_FWSTATS_FILE(wep, packets, 20, "%u"); +DEBUGFS_FWSTATS_FILE(wep, interrupt, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(pwr, ps_enter, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, elp_enter, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, missing_bcns, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, wake_on_host, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, wake_on_timer_exp, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, tx_with_ps, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, tx_without_ps, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, rcvd_beacons, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, power_save_off, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, enable_ps, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, disable_ps, 20, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, fix_tsf_ps, 20, "%u"); +/* skipping cont_miss_bcns_spread for now */ +DEBUGFS_FWSTATS_FILE(pwr, rcvd_awake_beacons, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(mic, rx_pkts, 20, "%u"); +DEBUGFS_FWSTATS_FILE(mic, calc_failure, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(aes, encrypt_fail, 20, "%u"); +DEBUGFS_FWSTATS_FILE(aes, decrypt_fail, 20, "%u"); +DEBUGFS_FWSTATS_FILE(aes, encrypt_packets, 20, "%u"); +DEBUGFS_FWSTATS_FILE(aes, decrypt_packets, 20, "%u"); +DEBUGFS_FWSTATS_FILE(aes, encrypt_interrupt, 20, "%u"); +DEBUGFS_FWSTATS_FILE(aes, decrypt_interrupt, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(event, heart_beat, 20, "%u"); +DEBUGFS_FWSTATS_FILE(event, calibration, 20, "%u"); +DEBUGFS_FWSTATS_FILE(event, rx_mismatch, 20, "%u"); +DEBUGFS_FWSTATS_FILE(event, rx_mem_empty, 20, "%u"); +DEBUGFS_FWSTATS_FILE(event, rx_pool, 20, "%u"); +DEBUGFS_FWSTATS_FILE(event, oom_late, 20, "%u"); +DEBUGFS_FWSTATS_FILE(event, phy_transmit_error, 20, "%u"); +DEBUGFS_FWSTATS_FILE(event, tx_stuck, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(ps, pspoll_timeouts, 20, "%u"); +DEBUGFS_FWSTATS_FILE(ps, upsd_timeouts, 20, "%u"); +DEBUGFS_FWSTATS_FILE(ps, upsd_max_sptime, 20, "%u"); +DEBUGFS_FWSTATS_FILE(ps, upsd_max_apturn, 20, "%u"); +DEBUGFS_FWSTATS_FILE(ps, pspoll_max_apturn, 20, "%u"); +DEBUGFS_FWSTATS_FILE(ps, pspoll_utilization, 20, "%u"); +DEBUGFS_FWSTATS_FILE(ps, upsd_utilization, 20, "%u"); + +DEBUGFS_FWSTATS_FILE(rxpipe, rx_prep_beacon_drop, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rxpipe, descr_host_int_trig_rx_data, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rxpipe, beacon_buffer_thres_host_int_trig_rx_data, + 20, "%u"); +DEBUGFS_FWSTATS_FILE(rxpipe, missed_beacon_host_int_trig_rx_data, 20, "%u"); +DEBUGFS_FWSTATS_FILE(rxpipe, tx_xfr_host_int_trig_rx_data, 20, "%u"); + +DEBUGFS_READONLY_FILE(retry_count, 20, "%u", wl->stats.retry_count); +DEBUGFS_READONLY_FILE(excessive_retries, 20, "%u", + wl->stats.excessive_retries); + +static ssize_t tx_queue_len_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct wl12xx *wl = file->private_data; + u32 queue_len; + char buf[20]; + int res; + + queue_len = skb_queue_len(&wl->tx_queue); + + res = scnprintf(buf, sizeof(buf), "%u\n", queue_len); + return simple_read_from_buffer(userbuf, count, ppos, buf, res); +} + +static const struct file_operations tx_queue_len_ops = { + .read = tx_queue_len_read, + .open = wl12xx_open_file_generic, +}; + +static void wl12xx_debugfs_delete_files(struct wl12xx *wl) +{ + DEBUGFS_FWSTATS_DEL(tx, internal_desc_overflow); + + DEBUGFS_FWSTATS_DEL(rx, out_of_mem); + DEBUGFS_FWSTATS_DEL(rx, hdr_overflow); + DEBUGFS_FWSTATS_DEL(rx, hw_stuck); + DEBUGFS_FWSTATS_DEL(rx, dropped); + DEBUGFS_FWSTATS_DEL(rx, fcs_err); + DEBUGFS_FWSTATS_DEL(rx, xfr_hint_trig); + DEBUGFS_FWSTATS_DEL(rx, path_reset); + DEBUGFS_FWSTATS_DEL(rx, reset_counter); + + DEBUGFS_FWSTATS_DEL(dma, rx_requested); + DEBUGFS_FWSTATS_DEL(dma, rx_errors); + DEBUGFS_FWSTATS_DEL(dma, tx_requested); + DEBUGFS_FWSTATS_DEL(dma, tx_errors); + + DEBUGFS_FWSTATS_DEL(isr, cmd_cmplt); + DEBUGFS_FWSTATS_DEL(isr, fiqs); + DEBUGFS_FWSTATS_DEL(isr, rx_headers); + DEBUGFS_FWSTATS_DEL(isr, rx_mem_overflow); + DEBUGFS_FWSTATS_DEL(isr, rx_rdys); + DEBUGFS_FWSTATS_DEL(isr, irqs); + DEBUGFS_FWSTATS_DEL(isr, tx_procs); + DEBUGFS_FWSTATS_DEL(isr, decrypt_done); + DEBUGFS_FWSTATS_DEL(isr, dma0_done); + DEBUGFS_FWSTATS_DEL(isr, dma1_done); + DEBUGFS_FWSTATS_DEL(isr, tx_exch_complete); + DEBUGFS_FWSTATS_DEL(isr, commands); + DEBUGFS_FWSTATS_DEL(isr, rx_procs); + DEBUGFS_FWSTATS_DEL(isr, hw_pm_mode_changes); + DEBUGFS_FWSTATS_DEL(isr, host_acknowledges); + DEBUGFS_FWSTATS_DEL(isr, pci_pm); + DEBUGFS_FWSTATS_DEL(isr, wakeups); + DEBUGFS_FWSTATS_DEL(isr, low_rssi); + + DEBUGFS_FWSTATS_DEL(wep, addr_key_count); + DEBUGFS_FWSTATS_DEL(wep, default_key_count); + /* skipping wep.reserved */ + DEBUGFS_FWSTATS_DEL(wep, key_not_found); + DEBUGFS_FWSTATS_DEL(wep, decrypt_fail); + DEBUGFS_FWSTATS_DEL(wep, packets); + DEBUGFS_FWSTATS_DEL(wep, interrupt); + + DEBUGFS_FWSTATS_DEL(pwr, ps_enter); + DEBUGFS_FWSTATS_DEL(pwr, elp_enter); + DEBUGFS_FWSTATS_DEL(pwr, missing_bcns); + DEBUGFS_FWSTATS_DEL(pwr, wake_on_host); + DEBUGFS_FWSTATS_DEL(pwr, wake_on_timer_exp); + DEBUGFS_FWSTATS_DEL(pwr, tx_with_ps); + DEBUGFS_FWSTATS_DEL(pwr, tx_without_ps); + DEBUGFS_FWSTATS_DEL(pwr, rcvd_beacons); + DEBUGFS_FWSTATS_DEL(pwr, power_save_off); + DEBUGFS_FWSTATS_DEL(pwr, enable_ps); + DEBUGFS_FWSTATS_DEL(pwr, disable_ps); + DEBUGFS_FWSTATS_DEL(pwr, fix_tsf_ps); + /* skipping cont_miss_bcns_spread for now */ + DEBUGFS_FWSTATS_DEL(pwr, rcvd_awake_beacons); + + DEBUGFS_FWSTATS_DEL(mic, rx_pkts); + DEBUGFS_FWSTATS_DEL(mic, calc_failure); + + DEBUGFS_FWSTATS_DEL(aes, encrypt_fail); + DEBUGFS_FWSTATS_DEL(aes, decrypt_fail); + DEBUGFS_FWSTATS_DEL(aes, encrypt_packets); + DEBUGFS_FWSTATS_DEL(aes, decrypt_packets); + DEBUGFS_FWSTATS_DEL(aes, encrypt_interrupt); + DEBUGFS_FWSTATS_DEL(aes, decrypt_interrupt); + + DEBUGFS_FWSTATS_DEL(event, heart_beat); + DEBUGFS_FWSTATS_DEL(event, calibration); + DEBUGFS_FWSTATS_DEL(event, rx_mismatch); + DEBUGFS_FWSTATS_DEL(event, rx_mem_empty); + DEBUGFS_FWSTATS_DEL(event, rx_pool); + DEBUGFS_FWSTATS_DEL(event, oom_late); + DEBUGFS_FWSTATS_DEL(event, phy_transmit_error); + DEBUGFS_FWSTATS_DEL(event, tx_stuck); + + DEBUGFS_FWSTATS_DEL(ps, pspoll_timeouts); + DEBUGFS_FWSTATS_DEL(ps, upsd_timeouts); + DEBUGFS_FWSTATS_DEL(ps, upsd_max_sptime); + DEBUGFS_FWSTATS_DEL(ps, upsd_max_apturn); + DEBUGFS_FWSTATS_DEL(ps, pspoll_max_apturn); + DEBUGFS_FWSTATS_DEL(ps, pspoll_utilization); + DEBUGFS_FWSTATS_DEL(ps, upsd_utilization); + + DEBUGFS_FWSTATS_DEL(rxpipe, rx_prep_beacon_drop); + DEBUGFS_FWSTATS_DEL(rxpipe, descr_host_int_trig_rx_data); + DEBUGFS_FWSTATS_DEL(rxpipe, beacon_buffer_thres_host_int_trig_rx_data); + DEBUGFS_FWSTATS_DEL(rxpipe, missed_beacon_host_int_trig_rx_data); + DEBUGFS_FWSTATS_DEL(rxpipe, tx_xfr_host_int_trig_rx_data); + + DEBUGFS_DEL(tx_queue_len); + DEBUGFS_DEL(retry_count); + DEBUGFS_DEL(excessive_retries); +} + +static int wl12xx_debugfs_add_files(struct wl12xx *wl) +{ + int ret = 0; + + DEBUGFS_FWSTATS_ADD(tx, internal_desc_overflow); + + DEBUGFS_FWSTATS_ADD(rx, out_of_mem); + DEBUGFS_FWSTATS_ADD(rx, hdr_overflow); + DEBUGFS_FWSTATS_ADD(rx, hw_stuck); + DEBUGFS_FWSTATS_ADD(rx, dropped); + DEBUGFS_FWSTATS_ADD(rx, fcs_err); + DEBUGFS_FWSTATS_ADD(rx, xfr_hint_trig); + DEBUGFS_FWSTATS_ADD(rx, path_reset); + DEBUGFS_FWSTATS_ADD(rx, reset_counter); + + DEBUGFS_FWSTATS_ADD(dma, rx_requested); + DEBUGFS_FWSTATS_ADD(dma, rx_errors); + DEBUGFS_FWSTATS_ADD(dma, tx_requested); + DEBUGFS_FWSTATS_ADD(dma, tx_errors); + + DEBUGFS_FWSTATS_ADD(isr, cmd_cmplt); + DEBUGFS_FWSTATS_ADD(isr, fiqs); + DEBUGFS_FWSTATS_ADD(isr, rx_headers); + DEBUGFS_FWSTATS_ADD(isr, rx_mem_overflow); + DEBUGFS_FWSTATS_ADD(isr, rx_rdys); + DEBUGFS_FWSTATS_ADD(isr, irqs); + DEBUGFS_FWSTATS_ADD(isr, tx_procs); + DEBUGFS_FWSTATS_ADD(isr, decrypt_done); + DEBUGFS_FWSTATS_ADD(isr, dma0_done); + DEBUGFS_FWSTATS_ADD(isr, dma1_done); + DEBUGFS_FWSTATS_ADD(isr, tx_exch_complete); + DEBUGFS_FWSTATS_ADD(isr, commands); + DEBUGFS_FWSTATS_ADD(isr, rx_procs); + DEBUGFS_FWSTATS_ADD(isr, hw_pm_mode_changes); + DEBUGFS_FWSTATS_ADD(isr, host_acknowledges); + DEBUGFS_FWSTATS_ADD(isr, pci_pm); + DEBUGFS_FWSTATS_ADD(isr, wakeups); + DEBUGFS_FWSTATS_ADD(isr, low_rssi); + + DEBUGFS_FWSTATS_ADD(wep, addr_key_count); + DEBUGFS_FWSTATS_ADD(wep, default_key_count); + /* skipping wep.reserved */ + DEBUGFS_FWSTATS_ADD(wep, key_not_found); + DEBUGFS_FWSTATS_ADD(wep, decrypt_fail); + DEBUGFS_FWSTATS_ADD(wep, packets); + DEBUGFS_FWSTATS_ADD(wep, interrupt); + + DEBUGFS_FWSTATS_ADD(pwr, ps_enter); + DEBUGFS_FWSTATS_ADD(pwr, elp_enter); + DEBUGFS_FWSTATS_ADD(pwr, missing_bcns); + DEBUGFS_FWSTATS_ADD(pwr, wake_on_host); + DEBUGFS_FWSTATS_ADD(pwr, wake_on_timer_exp); + DEBUGFS_FWSTATS_ADD(pwr, tx_with_ps); + DEBUGFS_FWSTATS_ADD(pwr, tx_without_ps); + DEBUGFS_FWSTATS_ADD(pwr, rcvd_beacons); + DEBUGFS_FWSTATS_ADD(pwr, power_save_off); + DEBUGFS_FWSTATS_ADD(pwr, enable_ps); + DEBUGFS_FWSTATS_ADD(pwr, disable_ps); + DEBUGFS_FWSTATS_ADD(pwr, fix_tsf_ps); + /* skipping cont_miss_bcns_spread for now */ + DEBUGFS_FWSTATS_ADD(pwr, rcvd_awake_beacons); + + DEBUGFS_FWSTATS_ADD(mic, rx_pkts); + DEBUGFS_FWSTATS_ADD(mic, calc_failure); + + DEBUGFS_FWSTATS_ADD(aes, encrypt_fail); + DEBUGFS_FWSTATS_ADD(aes, decrypt_fail); + DEBUGFS_FWSTATS_ADD(aes, encrypt_packets); + DEBUGFS_FWSTATS_ADD(aes, decrypt_packets); + DEBUGFS_FWSTATS_ADD(aes, encrypt_interrupt); + DEBUGFS_FWSTATS_ADD(aes, decrypt_interrupt); + + DEBUGFS_FWSTATS_ADD(event, heart_beat); + DEBUGFS_FWSTATS_ADD(event, calibration); + DEBUGFS_FWSTATS_ADD(event, rx_mismatch); + DEBUGFS_FWSTATS_ADD(event, rx_mem_empty); + DEBUGFS_FWSTATS_ADD(event, rx_pool); + DEBUGFS_FWSTATS_ADD(event, oom_late); + DEBUGFS_FWSTATS_ADD(event, phy_transmit_error); + DEBUGFS_FWSTATS_ADD(event, tx_stuck); + + DEBUGFS_FWSTATS_ADD(ps, pspoll_timeouts); + DEBUGFS_FWSTATS_ADD(ps, upsd_timeouts); + DEBUGFS_FWSTATS_ADD(ps, upsd_max_sptime); + DEBUGFS_FWSTATS_ADD(ps, upsd_max_apturn); + DEBUGFS_FWSTATS_ADD(ps, pspoll_max_apturn); + DEBUGFS_FWSTATS_ADD(ps, pspoll_utilization); + DEBUGFS_FWSTATS_ADD(ps, upsd_utilization); + + DEBUGFS_FWSTATS_ADD(rxpipe, rx_prep_beacon_drop); + DEBUGFS_FWSTATS_ADD(rxpipe, descr_host_int_trig_rx_data); + DEBUGFS_FWSTATS_ADD(rxpipe, beacon_buffer_thres_host_int_trig_rx_data); + DEBUGFS_FWSTATS_ADD(rxpipe, missed_beacon_host_int_trig_rx_data); + DEBUGFS_FWSTATS_ADD(rxpipe, tx_xfr_host_int_trig_rx_data); + + DEBUGFS_ADD(tx_queue_len, wl->debugfs.rootdir); + DEBUGFS_ADD(retry_count, wl->debugfs.rootdir); + DEBUGFS_ADD(excessive_retries, wl->debugfs.rootdir); + +out: + if (ret < 0) + wl12xx_debugfs_delete_files(wl); + + return ret; +} + +void wl12xx_debugfs_reset(struct wl12xx *wl) +{ + memset(wl->stats.fw_stats, 0, sizeof(*wl->stats.fw_stats)); + wl->stats.retry_count = 0; + wl->stats.excessive_retries = 0; +} + +int wl12xx_debugfs_init(struct wl12xx *wl) +{ + int ret; + + wl->debugfs.rootdir = debugfs_create_dir(KBUILD_MODNAME, NULL); + + if (IS_ERR(wl->debugfs.rootdir)) { + ret = PTR_ERR(wl->debugfs.rootdir); + wl->debugfs.rootdir = NULL; + goto err; + } + + wl->debugfs.fw_statistics = debugfs_create_dir("fw-statistics", + wl->debugfs.rootdir); + + if (IS_ERR(wl->debugfs.fw_statistics)) { + ret = PTR_ERR(wl->debugfs.fw_statistics); + wl->debugfs.fw_statistics = NULL; + goto err_root; + } + + wl->stats.fw_stats = kzalloc(sizeof(*wl->stats.fw_stats), + GFP_KERNEL); + + if (!wl->stats.fw_stats) { + ret = -ENOMEM; + goto err_fw; + } + + wl->stats.fw_stats_update = jiffies; + + ret = wl12xx_debugfs_add_files(wl); + + if (ret < 0) + goto err_file; + + return 0; + +err_file: + kfree(wl->stats.fw_stats); + wl->stats.fw_stats = NULL; + +err_fw: + debugfs_remove(wl->debugfs.fw_statistics); + wl->debugfs.fw_statistics = NULL; + +err_root: + debugfs_remove(wl->debugfs.rootdir); + wl->debugfs.rootdir = NULL; + +err: + return ret; +} + +void wl12xx_debugfs_exit(struct wl12xx *wl) +{ + wl12xx_debugfs_delete_files(wl); + + kfree(wl->stats.fw_stats); + wl->stats.fw_stats = NULL; + + debugfs_remove(wl->debugfs.fw_statistics); + wl->debugfs.fw_statistics = NULL; + + debugfs_remove(wl->debugfs.rootdir); + wl->debugfs.rootdir = NULL; + +} diff --git a/drivers/net/wireless/wl12xx/debugfs.h b/drivers/net/wireless/wl12xx/debugfs.h new file mode 100644 index 000000000000..562cdcbcc874 --- /dev/null +++ b/drivers/net/wireless/wl12xx/debugfs.h @@ -0,0 +1,33 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef WL12XX_DEBUGFS_H +#define WL12XX_DEBUGFS_H + +#include "wl12xx.h" + +int wl12xx_debugfs_init(struct wl12xx *wl); +void wl12xx_debugfs_exit(struct wl12xx *wl); +void wl12xx_debugfs_reset(struct wl12xx *wl); + +#endif /* WL12XX_DEBUGFS_H */ diff --git a/drivers/net/wireless/wl12xx/event.c b/drivers/net/wireless/wl12xx/event.c new file mode 100644 index 000000000000..99529ca89a7e --- /dev/null +++ b/drivers/net/wireless/wl12xx/event.c @@ -0,0 +1,127 @@ +/* + * This file is part of wl12xx + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "wl12xx.h" +#include "reg.h" +#include "spi.h" +#include "event.h" +#include "ps.h" + +static int wl12xx_event_scan_complete(struct wl12xx *wl, + struct event_mailbox *mbox) +{ + wl12xx_debug(DEBUG_EVENT, "status: 0x%x, channels: %d", + mbox->scheduled_scan_status, + mbox->scheduled_scan_channels); + + if (wl->scanning) { + mutex_unlock(&wl->mutex); + ieee80211_scan_completed(wl->hw, false); + mutex_lock(&wl->mutex); + wl->scanning = false; + } + + return 0; +} + +static void wl12xx_event_mbox_dump(struct event_mailbox *mbox) +{ + wl12xx_debug(DEBUG_EVENT, "MBOX DUMP:"); + wl12xx_debug(DEBUG_EVENT, "\tvector: 0x%x", mbox->events_vector); + wl12xx_debug(DEBUG_EVENT, "\tmask: 0x%x", mbox->events_mask); +} + +static int wl12xx_event_process(struct wl12xx *wl, struct event_mailbox *mbox) +{ + int ret; + u32 vector; + + wl12xx_event_mbox_dump(mbox); + + vector = mbox->events_vector & ~(mbox->events_mask); + wl12xx_debug(DEBUG_EVENT, "vector: 0x%x", vector); + + if (vector & SCAN_COMPLETE_EVENT_ID) { + ret = wl12xx_event_scan_complete(wl, mbox); + if (ret < 0) + return ret; + } + + if (vector & BSS_LOSE_EVENT_ID) { + wl12xx_debug(DEBUG_EVENT, "BSS_LOSE_EVENT"); + + if (wl->psm_requested && wl->psm) { + ret = wl12xx_ps_set_mode(wl, STATION_ACTIVE_MODE); + if (ret < 0) + return ret; + } + } + + return 0; +} + +int wl12xx_event_unmask(struct wl12xx *wl) +{ + int ret; + + ret = wl12xx_acx_event_mbox_mask(wl, ~(wl->event_mask)); + if (ret < 0) + return ret; + + return 0; +} + +void wl12xx_event_mbox_config(struct wl12xx *wl) +{ + wl->mbox_ptr[0] = wl12xx_reg_read32(wl, REG_EVENT_MAILBOX_PTR); + wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox); + + wl12xx_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x", + wl->mbox_ptr[0], wl->mbox_ptr[1]); +} + +int wl12xx_event_handle(struct wl12xx *wl, u8 mbox_num) +{ + struct event_mailbox mbox; + int ret; + + wl12xx_debug(DEBUG_EVENT, "EVENT on mbox %d", mbox_num); + + if (mbox_num > 1) + return -EINVAL; + + /* first we read the mbox descriptor */ + wl12xx_spi_mem_read(wl, wl->mbox_ptr[mbox_num], &mbox, + sizeof(struct event_mailbox)); + + /* process the descriptor */ + ret = wl12xx_event_process(wl, &mbox); + if (ret < 0) + return ret; + + /* then we let the firmware know it can go on...*/ + wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK); + + return 0; +} diff --git a/drivers/net/wireless/wl12xx/event.h b/drivers/net/wireless/wl12xx/event.h new file mode 100644 index 000000000000..1f4c2f7438a7 --- /dev/null +++ b/drivers/net/wireless/wl12xx/event.h @@ -0,0 +1,121 @@ +/* + * This file is part of wl12xx + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL12XX_EVENT_H__ +#define __WL12XX_EVENT_H__ + +/* + * Mbox events + * + * The event mechanism is based on a pair of event buffers (buffers A and + * B) at fixed locations in the target's memory. The host processes one + * buffer while the other buffer continues to collect events. If the host + * is not processing events, an interrupt is issued to signal that a buffer + * is ready. Once the host is done with processing events from one buffer, + * it signals the target (with an ACK interrupt) that the event buffer is + * free. + */ + +enum { + RESERVED1_EVENT_ID = BIT(0), + RESERVED2_EVENT_ID = BIT(1), + MEASUREMENT_START_EVENT_ID = BIT(2), + SCAN_COMPLETE_EVENT_ID = BIT(3), + CALIBRATION_COMPLETE_EVENT_ID = BIT(4), + ROAMING_TRIGGER_LOW_RSSI_EVENT_ID = BIT(5), + PS_REPORT_EVENT_ID = BIT(6), + SYNCHRONIZATION_TIMEOUT_EVENT_ID = BIT(7), + HEALTH_REPORT_EVENT_ID = BIT(8), + ACI_DETECTION_EVENT_ID = BIT(9), + DEBUG_REPORT_EVENT_ID = BIT(10), + MAC_STATUS_EVENT_ID = BIT(11), + DISCONNECT_EVENT_COMPLETE_ID = BIT(12), + JOIN_EVENT_COMPLETE_ID = BIT(13), + CHANNEL_SWITCH_COMPLETE_EVENT_ID = BIT(14), + BSS_LOSE_EVENT_ID = BIT(15), + ROAMING_TRIGGER_MAX_TX_RETRY_EVENT_ID = BIT(16), + MEASUREMENT_COMPLETE_EVENT_ID = BIT(17), + AP_DISCOVERY_COMPLETE_EVENT_ID = BIT(18), + SCHEDULED_SCAN_COMPLETE_EVENT_ID = BIT(19), + PSPOLL_DELIVERY_FAILURE_EVENT_ID = BIT(20), + RESET_BSS_EVENT_ID = BIT(21), + REGAINED_BSS_EVENT_ID = BIT(22), + ROAMING_TRIGGER_REGAINED_RSSI_EVENT_ID = BIT(23), + ROAMING_TRIGGER_LOW_SNR_EVENT_ID = BIT(24), + ROAMING_TRIGGER_REGAINED_SNR_EVENT_ID = BIT(25), + + DBG_EVENT_ID = BIT(26), + BT_PTA_SENSE_EVENT_ID = BIT(27), + BT_PTA_PREDICTION_EVENT_ID = BIT(28), + BT_PTA_AVALANCHE_EVENT_ID = BIT(29), + + PLT_RX_CALIBRATION_COMPLETE_EVENT_ID = BIT(30), + + EVENT_MBOX_ALL_EVENT_ID = 0x7fffffff, +}; + +struct event_debug_report { + u8 debug_event_id; + u8 num_params; + u16 pad; + u32 report_1; + u32 report_2; + u32 report_3; +} __attribute__ ((packed)); + +struct event_mailbox { + u32 events_vector; + u32 events_mask; + u32 reserved_1; + u32 reserved_2; + + char average_rssi_level; + u8 ps_status; + u8 channel_switch_status; + u8 scheduled_scan_status; + + /* Channels scanned by the scheduled scan */ + u16 scheduled_scan_channels; + + /* If bit 0 is set -> target's fatal error */ + u16 health_report; + u16 bad_fft_counter; + u8 bt_pta_sense_info; + u8 bt_pta_protective_info; + u32 reserved; + u32 debug_report[2]; + + /* Number of FCS errors since last event */ + u32 fcs_err_counter; + + struct event_debug_report report; + u8 average_snr_level; + u8 padding[19]; +} __attribute__ ((packed)); + +int wl12xx_event_unmask(struct wl12xx *wl); +void wl12xx_event_mbox_config(struct wl12xx *wl); +int wl12xx_event_handle(struct wl12xx *wl, u8 mbox); + +#endif diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c new file mode 100644 index 000000000000..2a573a6010bd --- /dev/null +++ b/drivers/net/wireless/wl12xx/init.c @@ -0,0 +1,200 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include + +#include "init.h" +#include "wl12xx_80211.h" +#include "acx.h" +#include "cmd.h" + +int wl12xx_hw_init_hwenc_config(struct wl12xx *wl) +{ + int ret; + + ret = wl12xx_acx_feature_cfg(wl); + if (ret < 0) { + wl12xx_warning("couldn't set feature config"); + return ret; + } + + ret = wl12xx_acx_default_key(wl, wl->default_key); + if (ret < 0) { + wl12xx_warning("couldn't set default key"); + return ret; + } + + return 0; +} + +int wl12xx_hw_init_templates_config(struct wl12xx *wl) +{ + int ret; + u8 partial_vbm[PARTIAL_VBM_MAX]; + + /* send empty templates for fw memory reservation */ + ret = wl12xx_cmd_template_set(wl, CMD_PROBE_REQ, NULL, + sizeof(struct wl12xx_probe_req_template)); + if (ret < 0) + return ret; + + ret = wl12xx_cmd_template_set(wl, CMD_NULL_DATA, NULL, + sizeof(struct wl12xx_null_data_template)); + if (ret < 0) + return ret; + + ret = wl12xx_cmd_template_set(wl, CMD_PS_POLL, NULL, + sizeof(struct wl12xx_ps_poll_template)); + if (ret < 0) + return ret; + + ret = wl12xx_cmd_template_set(wl, CMD_QOS_NULL_DATA, NULL, + sizeof + (struct wl12xx_qos_null_data_template)); + if (ret < 0) + return ret; + + ret = wl12xx_cmd_template_set(wl, CMD_PROBE_RESP, NULL, + sizeof + (struct wl12xx_probe_resp_template)); + if (ret < 0) + return ret; + + ret = wl12xx_cmd_template_set(wl, CMD_BEACON, NULL, + sizeof + (struct wl12xx_beacon_template)); + if (ret < 0) + return ret; + + /* tim templates, first reserve space then allocate an empty one */ + memset(partial_vbm, 0, PARTIAL_VBM_MAX); + ret = wl12xx_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, PARTIAL_VBM_MAX, 0); + if (ret < 0) + return ret; + + ret = wl12xx_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, 1, 0); + if (ret < 0) + return ret; + + return 0; +} + +int wl12xx_hw_init_rx_config(struct wl12xx *wl, u32 config, u32 filter) +{ + int ret; + + ret = wl12xx_acx_rx_msdu_life_time(wl, RX_MSDU_LIFETIME_DEF); + if (ret < 0) + return ret; + + ret = wl12xx_acx_rx_config(wl, config, filter); + if (ret < 0) + return ret; + + return 0; +} + +int wl12xx_hw_init_phy_config(struct wl12xx *wl) +{ + int ret; + + ret = wl12xx_acx_pd_threshold(wl); + if (ret < 0) + return ret; + + ret = wl12xx_acx_slot(wl, DEFAULT_SLOT_TIME); + if (ret < 0) + return ret; + + ret = wl12xx_acx_group_address_tbl(wl); + if (ret < 0) + return ret; + + ret = wl12xx_acx_service_period_timeout(wl); + if (ret < 0) + return ret; + + ret = wl12xx_acx_rts_threshold(wl, RTS_THRESHOLD_DEF); + if (ret < 0) + return ret; + + return 0; +} + +int wl12xx_hw_init_beacon_filter(struct wl12xx *wl) +{ + int ret; + + ret = wl12xx_acx_beacon_filter_opt(wl); + if (ret < 0) + return ret; + + ret = wl12xx_acx_beacon_filter_table(wl); + if (ret < 0) + return ret; + + return 0; +} + +int wl12xx_hw_init_pta(struct wl12xx *wl) +{ + int ret; + + ret = wl12xx_acx_sg_enable(wl); + if (ret < 0) + return ret; + + ret = wl12xx_acx_sg_cfg(wl); + if (ret < 0) + return ret; + + return 0; +} + +int wl12xx_hw_init_energy_detection(struct wl12xx *wl) +{ + int ret; + + ret = wl12xx_acx_cca_threshold(wl); + if (ret < 0) + return ret; + + return 0; +} + +int wl12xx_hw_init_beacon_broadcast(struct wl12xx *wl) +{ + int ret; + + ret = wl12xx_acx_bcn_dtim_options(wl); + if (ret < 0) + return ret; + + return 0; +} + +int wl12xx_hw_init_power_auth(struct wl12xx *wl) +{ + return wl12xx_acx_sleep_auth(wl, WL12XX_PSM_CAM); +} diff --git a/drivers/net/wireless/wl12xx/init.h b/drivers/net/wireless/wl12xx/init.h new file mode 100644 index 000000000000..c8b6cd0b7c3e --- /dev/null +++ b/drivers/net/wireless/wl12xx/init.h @@ -0,0 +1,40 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL12XX_INIT_H__ +#define __WL12XX_INIT_H__ + +#include "wl12xx.h" + +int wl12xx_hw_init_hwenc_config(struct wl12xx *wl); +int wl12xx_hw_init_templates_config(struct wl12xx *wl); +int wl12xx_hw_init_mem_config(struct wl12xx *wl); +int wl12xx_hw_init_rx_config(struct wl12xx *wl, u32 config, u32 filter); +int wl12xx_hw_init_phy_config(struct wl12xx *wl); +int wl12xx_hw_init_beacon_filter(struct wl12xx *wl); +int wl12xx_hw_init_pta(struct wl12xx *wl); +int wl12xx_hw_init_energy_detection(struct wl12xx *wl); +int wl12xx_hw_init_beacon_broadcast(struct wl12xx *wl); +int wl12xx_hw_init_power_auth(struct wl12xx *wl); + +#endif diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c new file mode 100644 index 000000000000..603d6114882e --- /dev/null +++ b/drivers/net/wireless/wl12xx/main.c @@ -0,0 +1,1358 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2008-2009 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wl12xx.h" +#include "wl12xx_80211.h" +#include "reg.h" +#include "wl1251.h" +#include "spi.h" +#include "event.h" +#include "tx.h" +#include "rx.h" +#include "ps.h" +#include "init.h" +#include "debugfs.h" + +static void wl12xx_disable_interrupts(struct wl12xx *wl) +{ + disable_irq(wl->irq); +} + +static void wl12xx_power_off(struct wl12xx *wl) +{ + wl->set_power(false); +} + +static void wl12xx_power_on(struct wl12xx *wl) +{ + wl->set_power(true); +} + +static irqreturn_t wl12xx_irq(int irq, void *cookie) +{ + struct wl12xx *wl; + + wl12xx_debug(DEBUG_IRQ, "IRQ"); + + wl = cookie; + + schedule_work(&wl->irq_work); + + return IRQ_HANDLED; +} + +static int wl12xx_fetch_firmware(struct wl12xx *wl) +{ + const struct firmware *fw; + int ret; + + ret = request_firmware(&fw, wl->chip.fw_filename, &wl->spi->dev); + + if (ret < 0) { + wl12xx_error("could not get firmware: %d", ret); + return ret; + } + + if (fw->size % 4) { + wl12xx_error("firmware size is not multiple of 32 bits: %zu", + fw->size); + ret = -EILSEQ; + goto out; + } + + wl->fw_len = fw->size; + wl->fw = kmalloc(wl->fw_len, GFP_KERNEL); + + if (!wl->fw) { + wl12xx_error("could not allocate memory for the firmware"); + ret = -ENOMEM; + goto out; + } + + memcpy(wl->fw, fw->data, wl->fw_len); + + ret = 0; + +out: + release_firmware(fw); + + return ret; +} + +static int wl12xx_fetch_nvs(struct wl12xx *wl) +{ + const struct firmware *fw; + int ret; + + ret = request_firmware(&fw, wl->chip.nvs_filename, &wl->spi->dev); + + if (ret < 0) { + wl12xx_error("could not get nvs file: %d", ret); + return ret; + } + + if (fw->size % 4) { + wl12xx_error("nvs size is not multiple of 32 bits: %zu", + fw->size); + ret = -EILSEQ; + goto out; + } + + wl->nvs_len = fw->size; + wl->nvs = kmalloc(wl->nvs_len, GFP_KERNEL); + + if (!wl->nvs) { + wl12xx_error("could not allocate memory for the nvs file"); + ret = -ENOMEM; + goto out; + } + + memcpy(wl->nvs, fw->data, wl->nvs_len); + + ret = 0; + +out: + release_firmware(fw); + + return ret; +} + +static void wl12xx_fw_wakeup(struct wl12xx *wl) +{ + u32 elp_reg; + + elp_reg = ELPCTRL_WAKE_UP; + wl12xx_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg); + elp_reg = wl12xx_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); + + if (!(elp_reg & ELPCTRL_WLAN_READY)) { + wl12xx_warning("WLAN not ready"); + elp_reg = ELPCTRL_WAKE_UP_WLAN_READY; + wl12xx_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg); + } +} + +static int wl12xx_chip_wakeup(struct wl12xx *wl) +{ + int ret = 0; + + wl12xx_power_on(wl); + msleep(wl->chip.power_on_sleep); + wl12xx_spi_reset(wl); + wl12xx_spi_init(wl); + + /* We don't need a real memory partition here, because we only want + * to use the registers at this point. */ + wl12xx_set_partition(wl, + 0x00000000, + 0x00000000, + REGISTERS_BASE, + REGISTERS_DOWN_SIZE); + + /* ELP module wake up */ + wl12xx_fw_wakeup(wl); + + /* whal_FwCtrl_BootSm() */ + + /* 0. read chip id from CHIP_ID */ + wl->chip.id = wl12xx_reg_read32(wl, CHIP_ID_B); + + /* 1. check if chip id is valid */ + + switch (wl->chip.id) { + case CHIP_ID_1251_PG12: + wl12xx_debug(DEBUG_BOOT, "chip id 0x%x (1251 PG12)", + wl->chip.id); + + wl1251_setup(wl); + + break; + case CHIP_ID_1271_PG10: + case CHIP_ID_1251_PG10: + case CHIP_ID_1251_PG11: + default: + wl12xx_error("unsupported chip id: 0x%x", wl->chip.id); + ret = -ENODEV; + goto out; + } + + if (wl->fw == NULL) { + ret = wl12xx_fetch_firmware(wl); + if (ret < 0) + goto out; + } + + /* No NVS from netlink, try to get it from the filesystem */ + if (wl->nvs == NULL) { + ret = wl12xx_fetch_nvs(wl); + if (ret < 0) + goto out; + } + +out: + return ret; +} + +static void wl12xx_filter_work(struct work_struct *work) +{ + struct wl12xx *wl = + container_of(work, struct wl12xx, filter_work); + int ret; + + mutex_lock(&wl->mutex); + + if (wl->state == WL12XX_STATE_OFF) + goto out; + + ret = wl12xx_cmd_join(wl, wl->bss_type, 1, 100, 0); + if (ret < 0) + goto out; + +out: + mutex_unlock(&wl->mutex); +} + +int wl12xx_plt_start(struct wl12xx *wl) +{ + int ret; + + wl12xx_notice("power up"); + + if (wl->state != WL12XX_STATE_OFF) { + wl12xx_error("cannot go into PLT state because not " + "in off state: %d", wl->state); + return -EBUSY; + } + + wl->state = WL12XX_STATE_PLT; + + ret = wl12xx_chip_wakeup(wl); + if (ret < 0) + return ret; + + ret = wl->chip.op_boot(wl); + if (ret < 0) + return ret; + + wl12xx_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver); + + ret = wl->chip.op_plt_init(wl); + if (ret < 0) + return ret; + + return 0; +} + +int wl12xx_plt_stop(struct wl12xx *wl) +{ + wl12xx_notice("power down"); + + if (wl->state != WL12XX_STATE_PLT) { + wl12xx_error("cannot power down because not in PLT " + "state: %d", wl->state); + return -EBUSY; + } + + wl12xx_disable_interrupts(wl); + wl12xx_power_off(wl); + + wl->state = WL12XX_STATE_OFF; + + return 0; +} + + +static int wl12xx_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + struct wl12xx *wl = hw->priv; + + skb_queue_tail(&wl->tx_queue, skb); + + schedule_work(&wl->tx_work); + + /* + * The workqueue is slow to process the tx_queue and we need stop + * the queue here, otherwise the queue will get too long. + */ + if (skb_queue_len(&wl->tx_queue) >= WL12XX_TX_QUEUE_MAX_LENGTH) { + ieee80211_stop_queues(wl->hw); + + /* + * FIXME: this is racy, the variable is not properly + * protected. Maybe fix this by removing the stupid + * variable altogether and checking the real queue state? + */ + wl->tx_queue_stopped = true; + } + + return NETDEV_TX_OK; +} + +static int wl12xx_op_start(struct ieee80211_hw *hw) +{ + struct wl12xx *wl = hw->priv; + int ret = 0; + + wl12xx_debug(DEBUG_MAC80211, "mac80211 start"); + + mutex_lock(&wl->mutex); + + if (wl->state != WL12XX_STATE_OFF) { + wl12xx_error("cannot start because not in off state: %d", + wl->state); + ret = -EBUSY; + goto out; + } + + ret = wl12xx_chip_wakeup(wl); + if (ret < 0) + return ret; + + ret = wl->chip.op_boot(wl); + if (ret < 0) + goto out; + + ret = wl->chip.op_hw_init(wl); + if (ret < 0) + goto out; + + ret = wl12xx_acx_station_id(wl); + if (ret < 0) + goto out; + + wl->state = WL12XX_STATE_ON; + + wl12xx_info("firmware booted (%s)", wl->chip.fw_ver); + +out: + if (ret < 0) + wl12xx_power_off(wl); + + mutex_unlock(&wl->mutex); + + return ret; +} + +static void wl12xx_op_stop(struct ieee80211_hw *hw) +{ + struct wl12xx *wl = hw->priv; + + wl12xx_info("down"); + + wl12xx_debug(DEBUG_MAC80211, "mac80211 stop"); + + mutex_lock(&wl->mutex); + + WARN_ON(wl->state != WL12XX_STATE_ON); + + if (wl->scanning) { + mutex_unlock(&wl->mutex); + ieee80211_scan_completed(wl->hw, true); + mutex_lock(&wl->mutex); + wl->scanning = false; + } + + wl->state = WL12XX_STATE_OFF; + + wl12xx_disable_interrupts(wl); + + mutex_unlock(&wl->mutex); + + cancel_work_sync(&wl->irq_work); + cancel_work_sync(&wl->tx_work); + cancel_work_sync(&wl->filter_work); + + mutex_lock(&wl->mutex); + + /* let's notify MAC80211 about the remaining pending TX frames */ + wl12xx_tx_flush(wl); + + wl12xx_power_off(wl); + + memset(wl->bssid, 0, ETH_ALEN); + wl->listen_int = 1; + wl->bss_type = MAX_BSS_TYPE; + + wl->data_in_count = 0; + wl->rx_counter = 0; + wl->rx_handled = 0; + wl->rx_current_buffer = 0; + wl->rx_last_id = 0; + wl->next_tx_complete = 0; + wl->elp = false; + wl->psm = 0; + wl->tx_queue_stopped = false; + wl->power_level = WL12XX_DEFAULT_POWER_LEVEL; + + wl12xx_debugfs_reset(wl); + + mutex_unlock(&wl->mutex); +} + +static int wl12xx_op_add_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + struct wl12xx *wl = hw->priv; + DECLARE_MAC_BUF(mac); + int ret = 0; + + wl12xx_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %s", + conf->type, print_mac(mac, conf->mac_addr)); + + mutex_lock(&wl->mutex); + + switch (conf->type) { + case NL80211_IFTYPE_STATION: + wl->bss_type = BSS_TYPE_STA_BSS; + break; + case NL80211_IFTYPE_ADHOC: + wl->bss_type = BSS_TYPE_IBSS; + break; + default: + ret = -EOPNOTSUPP; + goto out; + } + + if (memcmp(wl->mac_addr, conf->mac_addr, ETH_ALEN)) { + memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN); + SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr); + ret = wl12xx_acx_station_id(wl); + if (ret < 0) + goto out; + } + +out: + mutex_unlock(&wl->mutex); + return ret; +} + +static void wl12xx_op_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + wl12xx_debug(DEBUG_MAC80211, "mac80211 remove interface"); +} + +static int wl12xx_build_null_data(struct wl12xx *wl) +{ + struct wl12xx_null_data_template template; + + if (!is_zero_ether_addr(wl->bssid)) { + memcpy(template.header.da, wl->bssid, ETH_ALEN); + memcpy(template.header.bssid, wl->bssid, ETH_ALEN); + } else { + memset(template.header.da, 0xff, ETH_ALEN); + memset(template.header.bssid, 0xff, ETH_ALEN); + } + + memcpy(template.header.sa, wl->mac_addr, ETH_ALEN); + template.header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA | + IEEE80211_STYPE_NULLFUNC); + + return wl12xx_cmd_template_set(wl, CMD_NULL_DATA, &template, + sizeof(template)); + +} + +static int wl12xx_build_ps_poll(struct wl12xx *wl, u16 aid) +{ + struct wl12xx_ps_poll_template template; + + memcpy(template.bssid, wl->bssid, ETH_ALEN); + memcpy(template.ta, wl->mac_addr, ETH_ALEN); + template.aid = aid; + template.fc = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL); + + return wl12xx_cmd_template_set(wl, CMD_PS_POLL, &template, + sizeof(template)); + +} + +static int wl12xx_op_config(struct ieee80211_hw *hw, u32 changed) +{ + struct wl12xx *wl = hw->priv; + struct ieee80211_conf *conf = &hw->conf; + int channel, ret = 0; + + channel = ieee80211_frequency_to_channel(conf->channel->center_freq); + + wl12xx_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d", + channel, + conf->flags & IEEE80211_CONF_PS ? "on" : "off", + conf->power_level); + + mutex_lock(&wl->mutex); + + if (channel != wl->channel) { + /* FIXME: use beacon interval provided by mac80211 */ + ret = wl12xx_cmd_join(wl, wl->bss_type, 1, 100, 0); + if (ret < 0) + goto out; + + wl->channel = channel; + } + + ret = wl12xx_build_null_data(wl); + if (ret < 0) + goto out; + + if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) { + wl12xx_info("psm enabled"); + + wl->psm_requested = true; + + /* + * We enter PSM only if we're already associated. + * If we're not, we'll enter it when joining an SSID, + * through the bss_info_changed() hook. + */ + ret = wl12xx_ps_set_mode(wl, STATION_POWER_SAVE_MODE); + } else if (!(conf->flags & IEEE80211_CONF_PS) && + wl->psm_requested) { + wl12xx_info("psm disabled"); + + wl->psm_requested = false; + + if (wl->psm) + ret = wl12xx_ps_set_mode(wl, STATION_ACTIVE_MODE); + } + + if (conf->power_level != wl->power_level) { + ret = wl12xx_acx_tx_power(wl, conf->power_level); + if (ret < 0) + goto out; + + wl->power_level = conf->power_level; + } + +out: + mutex_unlock(&wl->mutex); + return ret; +} + +#define WL12XX_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \ + FIF_ALLMULTI | \ + FIF_FCSFAIL | \ + FIF_BCN_PRBRESP_PROMISC | \ + FIF_CONTROL | \ + FIF_OTHER_BSS) + +static void wl12xx_op_configure_filter(struct ieee80211_hw *hw, + unsigned int changed, + unsigned int *total, + int mc_count, + struct dev_addr_list *mc_list) +{ + struct wl12xx *wl = hw->priv; + + wl12xx_debug(DEBUG_MAC80211, "mac80211 configure filter"); + + *total &= WL12XX_SUPPORTED_FILTERS; + changed &= WL12XX_SUPPORTED_FILTERS; + + if (changed == 0) + /* no filters which we support changed */ + return; + + /* FIXME: wl->rx_config and wl->rx_filter are not protected */ + + wl->rx_config = WL12XX_DEFAULT_RX_CONFIG; + wl->rx_filter = WL12XX_DEFAULT_RX_FILTER; + + if (*total & FIF_PROMISC_IN_BSS) { + wl->rx_config |= CFG_BSSID_FILTER_EN; + wl->rx_config |= CFG_RX_ALL_GOOD; + } + if (*total & FIF_ALLMULTI) + /* + * CFG_MC_FILTER_EN in rx_config needs to be 0 to receive + * all multicast frames + */ + wl->rx_config &= ~CFG_MC_FILTER_EN; + if (*total & FIF_FCSFAIL) + wl->rx_filter |= CFG_RX_FCS_ERROR; + if (*total & FIF_BCN_PRBRESP_PROMISC) { + wl->rx_config &= ~CFG_BSSID_FILTER_EN; + wl->rx_config &= ~CFG_SSID_FILTER_EN; + } + if (*total & FIF_CONTROL) + wl->rx_filter |= CFG_RX_CTL_EN; + if (*total & FIF_OTHER_BSS) + wl->rx_filter &= ~CFG_BSSID_FILTER_EN; + + /* + * FIXME: workqueues need to be properly cancelled on stop(), for + * now let's just disable changing the filter settings. They will + * be updated any on config(). + */ + /* schedule_work(&wl->filter_work); */ +} + +/* HW encryption */ +static int wl12xx_set_key_type(struct wl12xx *wl, struct acx_set_key *key, + enum set_key_cmd cmd, + struct ieee80211_key_conf *mac80211_key, + const u8 *addr) +{ + switch (mac80211_key->alg) { + case ALG_WEP: + if (is_broadcast_ether_addr(addr)) + key->key_type = KEY_WEP_DEFAULT; + else + key->key_type = KEY_WEP_ADDR; + + mac80211_key->hw_key_idx = mac80211_key->keyidx; + break; + case ALG_TKIP: + if (is_broadcast_ether_addr(addr)) + key->key_type = KEY_TKIP_MIC_GROUP; + else + key->key_type = KEY_TKIP_MIC_PAIRWISE; + + mac80211_key->hw_key_idx = mac80211_key->keyidx; + break; + case ALG_CCMP: + if (is_broadcast_ether_addr(addr)) + key->key_type = KEY_AES_GROUP; + else + key->key_type = KEY_AES_PAIRWISE; + mac80211_key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + break; + default: + wl12xx_error("Unknown key algo 0x%x", mac80211_key->alg); + return -EOPNOTSUPP; + } + + return 0; +} + +static int wl12xx_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key) +{ + struct wl12xx *wl = hw->priv; + struct acx_set_key wl_key; + const u8 *addr; + int ret; + + static const u8 bcast_addr[ETH_ALEN] = + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + + wl12xx_debug(DEBUG_MAC80211, "mac80211 set key"); + + memset(&wl_key, 0, sizeof(wl_key)); + + addr = sta ? sta->addr : bcast_addr; + + wl12xx_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd); + wl12xx_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN); + wl12xx_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x", + key->alg, key->keyidx, key->keylen, key->flags); + wl12xx_dump(DEBUG_CRYPT, "KEY: ", key->key, key->keylen); + + mutex_lock(&wl->mutex); + + switch (cmd) { + case SET_KEY: + wl_key.key_action = KEY_ADD_OR_REPLACE; + break; + case DISABLE_KEY: + wl_key.key_action = KEY_REMOVE; + break; + default: + wl12xx_error("Unsupported key cmd 0x%x", cmd); + break; + } + + ret = wl12xx_set_key_type(wl, &wl_key, cmd, key, addr); + if (ret < 0) { + wl12xx_error("Set KEY type failed"); + goto out; + } + + if (wl_key.key_type != KEY_WEP_DEFAULT) + memcpy(wl_key.addr, addr, ETH_ALEN); + + if ((wl_key.key_type == KEY_TKIP_MIC_GROUP) || + (wl_key.key_type == KEY_TKIP_MIC_PAIRWISE)) { + /* + * We get the key in the following form: + * TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes) + * but the target is expecting: + * TKIP - RX MIC - TX MIC + */ + memcpy(wl_key.key, key->key, 16); + memcpy(wl_key.key + 16, key->key + 24, 8); + memcpy(wl_key.key + 24, key->key + 16, 8); + + } else { + memcpy(wl_key.key, key->key, key->keylen); + } + wl_key.key_size = key->keylen; + + wl_key.id = key->keyidx; + wl_key.ssid_profile = 0; + + wl12xx_dump(DEBUG_CRYPT, "TARGET KEY: ", &wl_key, sizeof(wl_key)); + + if (wl12xx_cmd_send(wl, CMD_SET_KEYS, &wl_key, sizeof(wl_key)) < 0) { + wl12xx_error("Set KEY failed"); + ret = -EOPNOTSUPP; + goto out; + } + +out: + mutex_unlock(&wl->mutex); + return ret; +} + +static int wl12xx_build_basic_rates(char *rates) +{ + u8 index = 0; + + rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB; + rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB; + rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_5MB; + rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_11MB; + + return index; +} + +static int wl12xx_build_extended_rates(char *rates) +{ + u8 index = 0; + + rates[index++] = IEEE80211_OFDM_RATE_6MB; + rates[index++] = IEEE80211_OFDM_RATE_9MB; + rates[index++] = IEEE80211_OFDM_RATE_12MB; + rates[index++] = IEEE80211_OFDM_RATE_18MB; + rates[index++] = IEEE80211_OFDM_RATE_24MB; + rates[index++] = IEEE80211_OFDM_RATE_36MB; + rates[index++] = IEEE80211_OFDM_RATE_48MB; + rates[index++] = IEEE80211_OFDM_RATE_54MB; + + return index; +} + + +static int wl12xx_build_probe_req(struct wl12xx *wl, u8 *ssid, size_t ssid_len) +{ + struct wl12xx_probe_req_template template; + struct wl12xx_ie_rates *rates; + char *ptr; + u16 size; + + ptr = (char *)&template; + size = sizeof(struct ieee80211_header); + + memset(template.header.da, 0xff, ETH_ALEN); + memset(template.header.bssid, 0xff, ETH_ALEN); + memcpy(template.header.sa, wl->mac_addr, ETH_ALEN); + template.header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); + + /* IEs */ + /* SSID */ + template.ssid.header.id = WLAN_EID_SSID; + template.ssid.header.len = ssid_len; + if (ssid_len && ssid) + memcpy(template.ssid.ssid, ssid, ssid_len); + size += sizeof(struct wl12xx_ie_header) + ssid_len; + ptr += size; + + /* Basic Rates */ + rates = (struct wl12xx_ie_rates *)ptr; + rates->header.id = WLAN_EID_SUPP_RATES; + rates->header.len = wl12xx_build_basic_rates(rates->rates); + size += sizeof(struct wl12xx_ie_header) + rates->header.len; + ptr += sizeof(struct wl12xx_ie_header) + rates->header.len; + + /* Extended rates */ + rates = (struct wl12xx_ie_rates *)ptr; + rates->header.id = WLAN_EID_EXT_SUPP_RATES; + rates->header.len = wl12xx_build_extended_rates(rates->rates); + size += sizeof(struct wl12xx_ie_header) + rates->header.len; + + wl12xx_dump(DEBUG_SCAN, "PROBE REQ: ", &template, size); + + return wl12xx_cmd_template_set(wl, CMD_PROBE_REQ, &template, + size); +} + +static int wl12xx_hw_scan(struct wl12xx *wl, u8 *ssid, size_t len, + u8 active_scan, u8 high_prio, u8 num_channels, + u8 probe_requests) +{ + int i, ret; + u32 split_scan = 0; + u16 scan_options = 0; + struct cmd_scan *params; + struct wl12xx_command *cmd_answer; + + if (wl->scanning) + return -EINVAL; + + params = kzalloc(sizeof(*params), GFP_KERNEL); + if (!params) + return -ENOMEM; + + params->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD); + params->params.rx_filter_options = + cpu_to_le32(CFG_RX_PRSP_EN | CFG_RX_MGMT_EN | CFG_RX_BCN_EN); + + /* High priority scan */ + if (!active_scan) + scan_options |= SCAN_PASSIVE; + if (high_prio) + scan_options |= SCAN_PRIORITY_HIGH; + params->params.scan_options = scan_options; + + params->params.num_channels = num_channels; + params->params.num_probe_requests = probe_requests; + params->params.tx_rate = cpu_to_le16(1 << 1); /* 2 Mbps */ + params->params.tid_trigger = 0; + + for (i = 0; i < num_channels; i++) { + params->channels[i].min_duration = cpu_to_le32(30000); + params->channels[i].max_duration = cpu_to_le32(60000); + memset(¶ms->channels[i].bssid_lsb, 0xff, 4); + memset(¶ms->channels[i].bssid_msb, 0xff, 2); + params->channels[i].early_termination = 0; + params->channels[i].tx_power_att = 0; + params->channels[i].channel = i + 1; + memset(params->channels[i].pad, 0, 3); + } + + for (i = num_channels; i < SCAN_MAX_NUM_OF_CHANNELS; i++) + memset(¶ms->channels[i], 0, + sizeof(struct basic_scan_channel_parameters)); + + if (len && ssid) { + params->params.ssid_len = len; + memcpy(params->params.ssid, ssid, len); + } else { + params->params.ssid_len = 0; + memset(params->params.ssid, 0, 32); + } + + ret = wl12xx_build_probe_req(wl, ssid, len); + if (ret < 0) { + wl12xx_error("PROBE request template failed"); + goto out; + } + + ret = wl12xx_cmd_send(wl, CMD_TRIGGER_SCAN_TO, &split_scan, + sizeof(u32)); + if (ret < 0) { + wl12xx_error("Split SCAN failed"); + goto out; + } + + wl12xx_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params)); + + wl->scanning = true; + + ret = wl12xx_cmd_send(wl, CMD_SCAN, params, sizeof(*params)); + if (ret < 0) + wl12xx_error("SCAN failed"); + + wl12xx_spi_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params)); + + cmd_answer = (struct wl12xx_command *) params; + if (cmd_answer->status != CMD_STATUS_SUCCESS) { + wl12xx_error("TEST command answer error: %d", + cmd_answer->status); + wl->scanning = false; + ret = -EIO; + goto out; + } + +out: + kfree(params); + return ret; + +} + +static int wl12xx_op_hw_scan(struct ieee80211_hw *hw, + struct cfg80211_scan_request *req) +{ + struct wl12xx *wl = hw->priv; + int ret; + u8 *ssid = NULL; + size_t ssid_len = 0; + + wl12xx_debug(DEBUG_MAC80211, "mac80211 hw scan"); + + if (req->n_ssids) { + ssid = req->ssids[0].ssid; + ssid_len = req->ssids[0].ssid_len; + } + + mutex_lock(&wl->mutex); + ret = wl12xx_hw_scan(hw->priv, ssid, ssid_len, 1, 0, 13, 3); + mutex_unlock(&wl->mutex); + + return ret; +} + +static int wl12xx_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) +{ + struct wl12xx *wl = hw->priv; + int ret; + + ret = wl12xx_acx_rts_threshold(wl, (u16) value); + + if (ret < 0) + wl12xx_warning("wl12xx_op_set_rts_threshold failed: %d", ret); + + return ret; +} + +static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, + u32 changed) +{ + enum acx_ps_mode mode; + struct wl12xx *wl = hw->priv; + struct sk_buff *beacon; + int ret; + + wl12xx_debug(DEBUG_MAC80211, "mac80211 bss info changed"); + + mutex_lock(&wl->mutex); + + if (changed & BSS_CHANGED_ASSOC) { + if (bss_conf->assoc) { + wl->aid = bss_conf->aid; + + ret = wl12xx_build_ps_poll(wl, wl->aid); + if (ret < 0) + goto out; + + ret = wl12xx_acx_aid(wl, wl->aid); + if (ret < 0) + goto out; + + /* If we want to go in PSM but we're not there yet */ + if (wl->psm_requested && !wl->psm) { + mode = STATION_POWER_SAVE_MODE; + ret = wl12xx_ps_set_mode(wl, mode); + if (ret < 0) + goto out; + } + } + } + if (changed & BSS_CHANGED_ERP_SLOT) { + if (bss_conf->use_short_slot) + ret = wl12xx_acx_slot(wl, SLOT_TIME_SHORT); + else + ret = wl12xx_acx_slot(wl, SLOT_TIME_LONG); + if (ret < 0) { + wl12xx_warning("Set slot time failed %d", ret); + goto out; + } + } + + if (changed & BSS_CHANGED_ERP_PREAMBLE) { + if (bss_conf->use_short_preamble) + wl12xx_acx_set_preamble(wl, ACX_PREAMBLE_SHORT); + else + wl12xx_acx_set_preamble(wl, ACX_PREAMBLE_LONG); + } + + if (changed & BSS_CHANGED_ERP_CTS_PROT) { + if (bss_conf->use_cts_prot) + ret = wl12xx_acx_cts_protect(wl, CTSPROTECT_ENABLE); + else + ret = wl12xx_acx_cts_protect(wl, CTSPROTECT_DISABLE); + if (ret < 0) { + wl12xx_warning("Set ctsprotect failed %d", ret); + goto out; + } + } + + if (changed & BSS_CHANGED_BSSID) { + memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN); + + ret = wl12xx_build_null_data(wl); + if (ret < 0) + goto out; + + if (wl->bss_type != BSS_TYPE_IBSS) { + ret = wl12xx_cmd_join(wl, wl->bss_type, 5, 100, 1); + if (ret < 0) + goto out; + } + } + + if (changed & BSS_CHANGED_BEACON) { + beacon = ieee80211_beacon_get(hw, vif); + ret = wl12xx_cmd_template_set(wl, CMD_BEACON, beacon->data, + beacon->len); + + if (ret < 0) { + dev_kfree_skb(beacon); + goto out; + } + + ret = wl12xx_cmd_template_set(wl, CMD_PROBE_RESP, beacon->data, + beacon->len); + + dev_kfree_skb(beacon); + + if (ret < 0) + goto out; + + ret = wl12xx_cmd_join(wl, wl->bss_type, 1, 100, 0); + + if (ret < 0) + goto out; + } + +out: + mutex_unlock(&wl->mutex); +} + + +/* can't be const, mac80211 writes to this */ +static struct ieee80211_rate wl12xx_rates[] = { + { .bitrate = 10, + .hw_value = 0x1, + .hw_value_short = 0x1, }, + { .bitrate = 20, + .hw_value = 0x2, + .hw_value_short = 0x2, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 55, + .hw_value = 0x4, + .hw_value_short = 0x4, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 110, + .hw_value = 0x20, + .hw_value_short = 0x20, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 60, + .hw_value = 0x8, + .hw_value_short = 0x8, }, + { .bitrate = 90, + .hw_value = 0x10, + .hw_value_short = 0x10, }, + { .bitrate = 120, + .hw_value = 0x40, + .hw_value_short = 0x40, }, + { .bitrate = 180, + .hw_value = 0x80, + .hw_value_short = 0x80, }, + { .bitrate = 240, + .hw_value = 0x200, + .hw_value_short = 0x200, }, + { .bitrate = 360, + .hw_value = 0x400, + .hw_value_short = 0x400, }, + { .bitrate = 480, + .hw_value = 0x800, + .hw_value_short = 0x800, }, + { .bitrate = 540, + .hw_value = 0x1000, + .hw_value_short = 0x1000, }, +}; + +/* can't be const, mac80211 writes to this */ +static struct ieee80211_channel wl12xx_channels[] = { + { .hw_value = 1, .center_freq = 2412}, + { .hw_value = 2, .center_freq = 2417}, + { .hw_value = 3, .center_freq = 2422}, + { .hw_value = 4, .center_freq = 2427}, + { .hw_value = 5, .center_freq = 2432}, + { .hw_value = 6, .center_freq = 2437}, + { .hw_value = 7, .center_freq = 2442}, + { .hw_value = 8, .center_freq = 2447}, + { .hw_value = 9, .center_freq = 2452}, + { .hw_value = 10, .center_freq = 2457}, + { .hw_value = 11, .center_freq = 2462}, + { .hw_value = 12, .center_freq = 2467}, + { .hw_value = 13, .center_freq = 2472}, +}; + +/* can't be const, mac80211 writes to this */ +static struct ieee80211_supported_band wl12xx_band_2ghz = { + .channels = wl12xx_channels, + .n_channels = ARRAY_SIZE(wl12xx_channels), + .bitrates = wl12xx_rates, + .n_bitrates = ARRAY_SIZE(wl12xx_rates), +}; + +static const struct ieee80211_ops wl12xx_ops = { + .start = wl12xx_op_start, + .stop = wl12xx_op_stop, + .add_interface = wl12xx_op_add_interface, + .remove_interface = wl12xx_op_remove_interface, + .config = wl12xx_op_config, + .configure_filter = wl12xx_op_configure_filter, + .tx = wl12xx_op_tx, + .set_key = wl12xx_op_set_key, + .hw_scan = wl12xx_op_hw_scan, + .bss_info_changed = wl12xx_op_bss_info_changed, + .set_rts_threshold = wl12xx_op_set_rts_threshold, +}; + +static int wl12xx_register_hw(struct wl12xx *wl) +{ + int ret; + + if (wl->mac80211_registered) + return 0; + + SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr); + + ret = ieee80211_register_hw(wl->hw); + if (ret < 0) { + wl12xx_error("unable to register mac80211 hw: %d", ret); + return ret; + } + + wl->mac80211_registered = true; + + wl12xx_notice("loaded"); + + return 0; +} + +static int wl12xx_init_ieee80211(struct wl12xx *wl) +{ + /* The tx descriptor buffer and the TKIP space */ + wl->hw->extra_tx_headroom = sizeof(struct tx_double_buffer_desc) + + WL12XX_TKIP_IV_SPACE; + + /* unit us */ + /* FIXME: find a proper value */ + wl->hw->channel_change_time = 10000; + + wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_NOISE_DBM; + + wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); + wl->hw->wiphy->max_scan_ssids = 1; + wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl12xx_band_2ghz; + + SET_IEEE80211_DEV(wl->hw, &wl->spi->dev); + + return 0; +} + +#define WL12XX_DEFAULT_CHANNEL 1 +static int __devinit wl12xx_probe(struct spi_device *spi) +{ + struct wl12xx_platform_data *pdata; + struct ieee80211_hw *hw; + struct wl12xx *wl; + int ret, i; + static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf}; + + pdata = spi->dev.platform_data; + if (!pdata) { + wl12xx_error("no platform data"); + return -ENODEV; + } + + hw = ieee80211_alloc_hw(sizeof(*wl), &wl12xx_ops); + if (!hw) { + wl12xx_error("could not alloc ieee80211_hw"); + return -ENOMEM; + } + + wl = hw->priv; + memset(wl, 0, sizeof(*wl)); + + wl->hw = hw; + dev_set_drvdata(&spi->dev, wl); + wl->spi = spi; + + wl->data_in_count = 0; + + skb_queue_head_init(&wl->tx_queue); + + INIT_WORK(&wl->tx_work, wl12xx_tx_work); + INIT_WORK(&wl->filter_work, wl12xx_filter_work); + wl->channel = WL12XX_DEFAULT_CHANNEL; + wl->scanning = false; + wl->default_key = 0; + wl->listen_int = 1; + wl->rx_counter = 0; + wl->rx_handled = 0; + wl->rx_current_buffer = 0; + wl->rx_last_id = 0; + wl->rx_config = WL12XX_DEFAULT_RX_CONFIG; + wl->rx_filter = WL12XX_DEFAULT_RX_FILTER; + wl->elp = false; + wl->psm = 0; + wl->psm_requested = false; + wl->tx_queue_stopped = false; + wl->power_level = WL12XX_DEFAULT_POWER_LEVEL; + + /* We use the default power on sleep time until we know which chip + * we're using */ + wl->chip.power_on_sleep = WL12XX_DEFAULT_POWER_ON_SLEEP; + + for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) + wl->tx_frames[i] = NULL; + + wl->next_tx_complete = 0; + + /* + * In case our MAC address is not correctly set, + * we use a random but Nokia MAC. + */ + memcpy(wl->mac_addr, nokia_oui, 3); + get_random_bytes(wl->mac_addr + 3, 3); + + wl->state = WL12XX_STATE_OFF; + mutex_init(&wl->mutex); + + wl->tx_mgmt_frm_rate = DEFAULT_HW_GEN_TX_RATE; + wl->tx_mgmt_frm_mod = DEFAULT_HW_GEN_MODULATION_TYPE; + + /* This is the only SPI value that we need to set here, the rest + * comes from the board-peripherals file */ + spi->bits_per_word = 32; + + ret = spi_setup(spi); + if (ret < 0) { + wl12xx_error("spi_setup failed"); + goto out_free; + } + + wl->set_power = pdata->set_power; + if (!wl->set_power) { + wl12xx_error("set power function missing in platform data"); + return -ENODEV; + } + + wl->irq = spi->irq; + if (wl->irq < 0) { + wl12xx_error("irq missing in platform data"); + return -ENODEV; + } + + ret = request_irq(wl->irq, wl12xx_irq, 0, DRIVER_NAME, wl); + if (ret < 0) { + wl12xx_error("request_irq() failed: %d", ret); + goto out_free; + } + + set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); + + disable_irq(wl->irq); + + ret = wl12xx_init_ieee80211(wl); + if (ret) + goto out_irq; + + ret = wl12xx_register_hw(wl); + if (ret) + goto out_irq; + + wl12xx_debugfs_init(wl); + + wl12xx_notice("initialized"); + + return 0; + + out_irq: + free_irq(wl->irq, wl); + + out_free: + ieee80211_free_hw(hw); + + return ret; +} + +static int __devexit wl12xx_remove(struct spi_device *spi) +{ + struct wl12xx *wl = dev_get_drvdata(&spi->dev); + + ieee80211_unregister_hw(wl->hw); + + wl12xx_debugfs_exit(wl); + + free_irq(wl->irq, wl); + kfree(wl->target_mem_map); + kfree(wl->data_path); + kfree(wl->fw); + wl->fw = NULL; + kfree(wl->nvs); + wl->nvs = NULL; + ieee80211_free_hw(wl->hw); + + return 0; +} + + +static struct spi_driver wl12xx_spi_driver = { + .driver = { + .name = "wl12xx", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + + .probe = wl12xx_probe, + .remove = __devexit_p(wl12xx_remove), +}; + +static int __init wl12xx_init(void) +{ + int ret; + + ret = spi_register_driver(&wl12xx_spi_driver); + if (ret < 0) { + wl12xx_error("failed to register spi driver: %d", ret); + goto out; + } + +out: + return ret; +} + +static void __exit wl12xx_exit(void) +{ + spi_unregister_driver(&wl12xx_spi_driver); + + wl12xx_notice("unloaded"); +} + +module_init(wl12xx_init); +module_exit(wl12xx_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Kalle Valo , " + "Luciano Coelho "); diff --git a/drivers/net/wireless/wl12xx/ps.c b/drivers/net/wireless/wl12xx/ps.c new file mode 100644 index 000000000000..83a10117330b --- /dev/null +++ b/drivers/net/wireless/wl12xx/ps.c @@ -0,0 +1,151 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "reg.h" +#include "ps.h" +#include "spi.h" + +#define WL12XX_WAKEUP_TIMEOUT 2000 + +/* Routines to toggle sleep mode while in ELP */ +void wl12xx_ps_elp_sleep(struct wl12xx *wl) +{ + if (wl->elp || !wl->psm) + return; + + wl12xx_debug(DEBUG_PSM, "chip to elp"); + + wl12xx_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP); + + wl->elp = true; +} + +int wl12xx_ps_elp_wakeup(struct wl12xx *wl) +{ + unsigned long timeout; + u32 elp_reg; + + if (!wl->elp) + return 0; + + wl12xx_debug(DEBUG_PSM, "waking up chip from elp"); + + timeout = jiffies + msecs_to_jiffies(WL12XX_WAKEUP_TIMEOUT); + + wl12xx_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP); + + elp_reg = wl12xx_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); + + /* + * FIXME: we should wait for irq from chip but, as a temporary + * solution to simplify locking, let's poll instead + */ + while (!(elp_reg & ELPCTRL_WLAN_READY)) { + if (time_after(jiffies, timeout)) { + wl12xx_error("elp wakeup timeout"); + return -ETIMEDOUT; + } + msleep(1); + elp_reg = wl12xx_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); + } + + wl12xx_debug(DEBUG_PSM, "wakeup time: %u ms", + jiffies_to_msecs(jiffies) - + (jiffies_to_msecs(timeout) - WL12XX_WAKEUP_TIMEOUT)); + + wl->elp = false; + + return 0; +} + +static int wl12xx_ps_set_elp(struct wl12xx *wl, bool enable) +{ + int ret; + + if (enable) { + wl12xx_debug(DEBUG_PSM, "sleep auth psm/elp"); + + /* + * FIXME: we should PSM_ELP, but because of firmware wakeup + * problems let's use only PSM_PS + */ + ret = wl12xx_acx_sleep_auth(wl, WL12XX_PSM_PS); + if (ret < 0) + return ret; + + wl12xx_ps_elp_sleep(wl); + } else { + wl12xx_debug(DEBUG_PSM, "sleep auth cam"); + + /* + * When the target is in ELP, we can only + * access the ELP control register. Thus, + * we have to wake the target up before + * changing the power authorization. + */ + + wl12xx_ps_elp_wakeup(wl); + + ret = wl12xx_acx_sleep_auth(wl, WL12XX_PSM_CAM); + if (ret < 0) + return ret; + } + + return 0; +} + +int wl12xx_ps_set_mode(struct wl12xx *wl, enum acx_ps_mode mode) +{ + int ret; + + switch (mode) { + case STATION_POWER_SAVE_MODE: + wl12xx_debug(DEBUG_PSM, "entering psm"); + ret = wl12xx_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE); + if (ret < 0) + return ret; + + ret = wl12xx_ps_set_elp(wl, true); + if (ret < 0) + return ret; + + wl->psm = 1; + break; + case STATION_ACTIVE_MODE: + default: + wl12xx_debug(DEBUG_PSM, "leaving psm"); + ret = wl12xx_ps_set_elp(wl, false); + if (ret < 0) + return ret; + + ret = wl12xx_cmd_ps_mode(wl, STATION_ACTIVE_MODE); + if (ret < 0) + return ret; + + wl->psm = 0; + break; + } + + return ret; +} + diff --git a/drivers/net/wireless/wl12xx/ps.h b/drivers/net/wireless/wl12xx/ps.h new file mode 100644 index 000000000000..5d7c52553830 --- /dev/null +++ b/drivers/net/wireless/wl12xx/ps.h @@ -0,0 +1,36 @@ +#ifndef __WL12XX_PS_H__ +#define __WL12XX_PS_H__ + +/* + * This file is part of wl12xx + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "wl12xx.h" +#include "acx.h" + +int wl12xx_ps_set_mode(struct wl12xx *wl, enum acx_ps_mode mode); +void wl12xx_ps_elp_sleep(struct wl12xx *wl); +int wl12xx_ps_elp_wakeup(struct wl12xx *wl); + + +#endif /* __WL12XX_PS_H__ */ diff --git a/drivers/net/wireless/wl12xx/reg.h b/drivers/net/wireless/wl12xx/reg.h new file mode 100644 index 000000000000..e421643215cd --- /dev/null +++ b/drivers/net/wireless/wl12xx/reg.h @@ -0,0 +1,745 @@ +/* + * This file is part of wl12xx + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __REG_H__ +#define __REG_H__ + +#include +#include "wl12xx.h" + +#define REGISTERS_BASE 0x00300000 +#define DRPW_BASE 0x00310000 + +#define REGISTERS_DOWN_SIZE 0x00008800 +#define REGISTERS_WORK_SIZE 0x0000b000 + +#define HW_ACCESS_ELP_CTRL_REG_ADDR 0x1FFFC + +/* ELP register commands */ +#define ELPCTRL_WAKE_UP 0x1 +#define ELPCTRL_WAKE_UP_WLAN_READY 0x5 +#define ELPCTRL_SLEEP 0x0 +/* ELP WLAN_READY bit */ +#define ELPCTRL_WLAN_READY 0x2 + +/* + * Interrupt registers. + * 64 bit interrupt sources registers ws ced. + * sme interupts were removed and new ones were added. + * Order was changed. + */ +#define FIQ_MASK (REGISTERS_BASE + 0x0400) +#define FIQ_MASK_L (REGISTERS_BASE + 0x0400) +#define FIQ_MASK_H (REGISTERS_BASE + 0x0404) +#define FIQ_MASK_SET (REGISTERS_BASE + 0x0408) +#define FIQ_MASK_SET_L (REGISTERS_BASE + 0x0408) +#define FIQ_MASK_SET_H (REGISTERS_BASE + 0x040C) +#define FIQ_MASK_CLR (REGISTERS_BASE + 0x0410) +#define FIQ_MASK_CLR_L (REGISTERS_BASE + 0x0410) +#define FIQ_MASK_CLR_H (REGISTERS_BASE + 0x0414) +#define IRQ_MASK (REGISTERS_BASE + 0x0418) +#define IRQ_MASK_L (REGISTERS_BASE + 0x0418) +#define IRQ_MASK_H (REGISTERS_BASE + 0x041C) +#define IRQ_MASK_SET (REGISTERS_BASE + 0x0420) +#define IRQ_MASK_SET_L (REGISTERS_BASE + 0x0420) +#define IRQ_MASK_SET_H (REGISTERS_BASE + 0x0424) +#define IRQ_MASK_CLR (REGISTERS_BASE + 0x0428) +#define IRQ_MASK_CLR_L (REGISTERS_BASE + 0x0428) +#define IRQ_MASK_CLR_H (REGISTERS_BASE + 0x042C) +#define ECPU_MASK (REGISTERS_BASE + 0x0448) +#define FIQ_STS_L (REGISTERS_BASE + 0x044C) +#define FIQ_STS_H (REGISTERS_BASE + 0x0450) +#define IRQ_STS_L (REGISTERS_BASE + 0x0454) +#define IRQ_STS_H (REGISTERS_BASE + 0x0458) +#define INT_STS_ND (REGISTERS_BASE + 0x0464) +#define INT_STS_RAW_L (REGISTERS_BASE + 0x0464) +#define INT_STS_RAW_H (REGISTERS_BASE + 0x0468) +#define INT_STS_CLR (REGISTERS_BASE + 0x04B4) +#define INT_STS_CLR_L (REGISTERS_BASE + 0x04B4) +#define INT_STS_CLR_H (REGISTERS_BASE + 0x04B8) +#define INT_ACK (REGISTERS_BASE + 0x046C) +#define INT_ACK_L (REGISTERS_BASE + 0x046C) +#define INT_ACK_H (REGISTERS_BASE + 0x0470) +#define INT_TRIG (REGISTERS_BASE + 0x0474) +#define INT_TRIG_L (REGISTERS_BASE + 0x0474) +#define INT_TRIG_H (REGISTERS_BASE + 0x0478) +#define HOST_STS_L (REGISTERS_BASE + 0x045C) +#define HOST_STS_H (REGISTERS_BASE + 0x0460) +#define HOST_MASK (REGISTERS_BASE + 0x0430) +#define HOST_MASK_L (REGISTERS_BASE + 0x0430) +#define HOST_MASK_H (REGISTERS_BASE + 0x0434) +#define HOST_MASK_SET (REGISTERS_BASE + 0x0438) +#define HOST_MASK_SET_L (REGISTERS_BASE + 0x0438) +#define HOST_MASK_SET_H (REGISTERS_BASE + 0x043C) +#define HOST_MASK_CLR (REGISTERS_BASE + 0x0440) +#define HOST_MASK_CLR_L (REGISTERS_BASE + 0x0440) +#define HOST_MASK_CLR_H (REGISTERS_BASE + 0x0444) + +/* Host Interrupts*/ +#define HINT_MASK (REGISTERS_BASE + 0x0494) +#define HINT_MASK_SET (REGISTERS_BASE + 0x0498) +#define HINT_MASK_CLR (REGISTERS_BASE + 0x049C) +#define HINT_STS_ND_MASKED (REGISTERS_BASE + 0x04A0) +/*1150 spec calls this HINT_STS_RAW*/ +#define HINT_STS_ND (REGISTERS_BASE + 0x04B0) +#define HINT_STS_CLR (REGISTERS_BASE + 0x04A4) +#define HINT_ACK (REGISTERS_BASE + 0x04A8) +#define HINT_TRIG (REGISTERS_BASE + 0x04AC) + +/* Device Configuration registers*/ +#define SOR_CFG (REGISTERS_BASE + 0x0800) +#define ECPU_CTRL (REGISTERS_BASE + 0x0804) +#define HI_CFG (REGISTERS_BASE + 0x0808) +#define EE_START (REGISTERS_BASE + 0x080C) + +#define CHIP_ID_B (REGISTERS_BASE + 0x5674) + +#define CHIP_ID_1251_PG10 (0x7010101) +#define CHIP_ID_1251_PG11 (0x7020101) +#define CHIP_ID_1251_PG12 (0x7030101) + +#define ENABLE (REGISTERS_BASE + 0x5450) + +/* Power Management registers */ +#define ELP_CFG_MODE (REGISTERS_BASE + 0x5804) +#define ELP_CMD (REGISTERS_BASE + 0x5808) +#define PLL_CAL_TIME (REGISTERS_BASE + 0x5810) +#define CLK_REQ_TIME (REGISTERS_BASE + 0x5814) +#define CLK_BUF_TIME (REGISTERS_BASE + 0x5818) + +#define CFG_PLL_SYNC_CNT (REGISTERS_BASE + 0x5820) + +/* Scratch Pad registers*/ +#define SCR_PAD0 (REGISTERS_BASE + 0x5608) +#define SCR_PAD1 (REGISTERS_BASE + 0x560C) +#define SCR_PAD2 (REGISTERS_BASE + 0x5610) +#define SCR_PAD3 (REGISTERS_BASE + 0x5614) +#define SCR_PAD4 (REGISTERS_BASE + 0x5618) +#define SCR_PAD4_SET (REGISTERS_BASE + 0x561C) +#define SCR_PAD4_CLR (REGISTERS_BASE + 0x5620) +#define SCR_PAD5 (REGISTERS_BASE + 0x5624) +#define SCR_PAD5_SET (REGISTERS_BASE + 0x5628) +#define SCR_PAD5_CLR (REGISTERS_BASE + 0x562C) +#define SCR_PAD6 (REGISTERS_BASE + 0x5630) +#define SCR_PAD7 (REGISTERS_BASE + 0x5634) +#define SCR_PAD8 (REGISTERS_BASE + 0x5638) +#define SCR_PAD9 (REGISTERS_BASE + 0x563C) + +/* Spare registers*/ +#define SPARE_A1 (REGISTERS_BASE + 0x0994) +#define SPARE_A2 (REGISTERS_BASE + 0x0998) +#define SPARE_A3 (REGISTERS_BASE + 0x099C) +#define SPARE_A4 (REGISTERS_BASE + 0x09A0) +#define SPARE_A5 (REGISTERS_BASE + 0x09A4) +#define SPARE_A6 (REGISTERS_BASE + 0x09A8) +#define SPARE_A7 (REGISTERS_BASE + 0x09AC) +#define SPARE_A8 (REGISTERS_BASE + 0x09B0) +#define SPARE_B1 (REGISTERS_BASE + 0x5420) +#define SPARE_B2 (REGISTERS_BASE + 0x5424) +#define SPARE_B3 (REGISTERS_BASE + 0x5428) +#define SPARE_B4 (REGISTERS_BASE + 0x542C) +#define SPARE_B5 (REGISTERS_BASE + 0x5430) +#define SPARE_B6 (REGISTERS_BASE + 0x5434) +#define SPARE_B7 (REGISTERS_BASE + 0x5438) +#define SPARE_B8 (REGISTERS_BASE + 0x543C) + +enum wl12xx_acx_int_reg { + ACX_REG_INTERRUPT_TRIG, + ACX_REG_INTERRUPT_TRIG_H, + +/*============================================= + Host Interrupt Mask Register - 32bit (RW) + ------------------------------------------ + Setting a bit in this register masks the + corresponding interrupt to the host. + 0 - RX0 - Rx first dubble buffer Data Interrupt + 1 - TXD - Tx Data Interrupt + 2 - TXXFR - Tx Transfer Interrupt + 3 - RX1 - Rx second dubble buffer Data Interrupt + 4 - RXXFR - Rx Transfer Interrupt + 5 - EVENT_A - Event Mailbox interrupt + 6 - EVENT_B - Event Mailbox interrupt + 7 - WNONHST - Wake On Host Interrupt + 8 - TRACE_A - Debug Trace interrupt + 9 - TRACE_B - Debug Trace interrupt + 10 - CDCMP - Command Complete Interrupt + 11 - + 12 - + 13 - + 14 - ICOMP - Initialization Complete Interrupt + 16 - SG SE - Soft Gemini - Sense enable interrupt + 17 - SG SD - Soft Gemini - Sense disable interrupt + 18 - - + 19 - - + 20 - - + 21- - + Default: 0x0001 +*==============================================*/ + ACX_REG_INTERRUPT_MASK, + +/*============================================= + Host Interrupt Mask Set 16bit, (Write only) + ------------------------------------------ + Setting a bit in this register sets + the corresponding bin in ACX_HINT_MASK register + without effecting the mask + state of other bits (0 = no effect). +==============================================*/ + ACX_REG_HINT_MASK_SET, + +/*============================================= + Host Interrupt Mask Clear 16bit,(Write only) + ------------------------------------------ + Setting a bit in this register clears + the corresponding bin in ACX_HINT_MASK register + without effecting the mask + state of other bits (0 = no effect). +=============================================*/ + ACX_REG_HINT_MASK_CLR, + +/*============================================= + Host Interrupt Status Nondestructive Read + 16bit,(Read only) + ------------------------------------------ + The host can read this register to determine + which interrupts are active. + Reading this register doesn't + effect its content. +=============================================*/ + ACX_REG_INTERRUPT_NO_CLEAR, + +/*============================================= + Host Interrupt Status Clear on Read Register + 16bit,(Read only) + ------------------------------------------ + The host can read this register to determine + which interrupts are active. + Reading this register clears it, + thus making all interrupts inactive. +==============================================*/ + ACX_REG_INTERRUPT_CLEAR, + +/*============================================= + Host Interrupt Acknowledge Register + 16bit,(Write only) + ------------------------------------------ + The host can set individual bits in this + register to clear (acknowledge) the corresp. + interrupt status bits in the HINT_STS_CLR and + HINT_STS_ND registers, thus making the + assotiated interrupt inactive. (0-no effect) +==============================================*/ + ACX_REG_INTERRUPT_ACK, + +/*=============================================== + Host Software Reset - 32bit RW + ------------------------------------------ + [31:1] Reserved + 0 SOFT_RESET Soft Reset - When this bit is set, + it holds the Wlan hardware in a soft reset state. + This reset disables all MAC and baseband processor + clocks except the CardBus/PCI interface clock. + It also initializes all MAC state machines except + the host interface. It does not reload the + contents of the EEPROM. When this bit is cleared + (not self-clearing), the Wlan hardware + exits the software reset state. +===============================================*/ + ACX_REG_SLV_SOFT_RESET, + +/*=============================================== + EEPROM Burst Read Start - 32bit RW + ------------------------------------------ + [31:1] Reserved + 0 ACX_EE_START - EEPROM Burst Read Start 0 + Setting this bit starts a burst read from + the external EEPROM. + If this bit is set (after reset) before an EEPROM read/write, + the burst read starts at EEPROM address 0. + Otherwise, it starts at the address + following the address of the previous access. + TheWlan hardware hardware clears this bit automatically. + + Default: 0x00000000 +*================================================*/ + ACX_REG_EE_START, + +/* Embedded ARM CPU Control */ + +/*=============================================== + Halt eCPU - 32bit RW + ------------------------------------------ + 0 HALT_ECPU Halt Embedded CPU - This bit is the + compliment of bit 1 (MDATA2) in the SOR_CFG register. + During a hardware reset, this bit holds + the inverse of MDATA2. + When downloading firmware from the host, + set this bit (pull down MDATA2). + The host clears this bit after downloading the firmware into + zero-wait-state SSRAM. + When loading firmware from Flash, clear this bit (pull up MDATA2) + so that the eCPU can run the bootloader code in Flash + HALT_ECPU eCPU State + -------------------- + 1 halt eCPU + 0 enable eCPU + ===============================================*/ + ACX_REG_ECPU_CONTROL, + + ACX_REG_TABLE_LEN +}; + +#define ACX_SLV_SOFT_RESET_BIT BIT(1) +#define ACX_REG_EEPROM_START_BIT BIT(1) + +/* Command/Information Mailbox Pointers */ + +/*=============================================== + Command Mailbox Pointer - 32bit RW + ------------------------------------------ + This register holds the start address of + the command mailbox located in the Wlan hardware memory. + The host must read this pointer after a reset to + find the location of the command mailbox. + The Wlan hardware initializes the command mailbox + pointer with the default address of the command mailbox. + The command mailbox pointer is not valid until after + the host receives the Init Complete interrupt from + the Wlan hardware. + ===============================================*/ +#define REG_COMMAND_MAILBOX_PTR (SCR_PAD0) + +/*=============================================== + Information Mailbox Pointer - 32bit RW + ------------------------------------------ + This register holds the start address of + the information mailbox located in the Wlan hardware memory. + The host must read this pointer after a reset to find + the location of the information mailbox. + The Wlan hardware initializes the information mailbox pointer + with the default address of the information mailbox. + The information mailbox pointer is not valid + until after the host receives the Init Complete interrupt from + the Wlan hardware. + ===============================================*/ +#define REG_EVENT_MAILBOX_PTR (SCR_PAD1) + + +/* Misc */ + +#define REG_ENABLE_TX_RX (ENABLE) +/* + * Rx configuration (filter) information element + * --------------------------------------------- + */ +#define REG_RX_CONFIG (RX_CFG) +#define REG_RX_FILTER (RX_FILTER_CFG) + + +#define RX_CFG_ENABLE_PHY_HEADER_PLCP 0x0002 + +/* promiscuous - receives all valid frames */ +#define RX_CFG_PROMISCUOUS 0x0008 + +/* receives frames from any BSSID */ +#define RX_CFG_BSSID 0x0020 + +/* receives frames destined to any MAC address */ +#define RX_CFG_MAC 0x0010 + +#define RX_CFG_ENABLE_ONLY_MY_DEST_MAC 0x0010 +#define RX_CFG_ENABLE_ANY_DEST_MAC 0x0000 +#define RX_CFG_ENABLE_ONLY_MY_BSSID 0x0020 +#define RX_CFG_ENABLE_ANY_BSSID 0x0000 + +/* discards all broadcast frames */ +#define RX_CFG_DISABLE_BCAST 0x0200 + +#define RX_CFG_ENABLE_ONLY_MY_SSID 0x0400 +#define RX_CFG_ENABLE_RX_CMPLT_FCS_ERROR 0x0800 +#define RX_CFG_COPY_RX_STATUS 0x2000 +#define RX_CFG_TSF 0x10000 + +#define RX_CONFIG_OPTION_ANY_DST_MY_BSS (RX_CFG_ENABLE_ANY_DEST_MAC | \ + RX_CFG_ENABLE_ONLY_MY_BSSID) + +#define RX_CONFIG_OPTION_MY_DST_ANY_BSS (RX_CFG_ENABLE_ONLY_MY_DEST_MAC\ + | RX_CFG_ENABLE_ANY_BSSID) + +#define RX_CONFIG_OPTION_ANY_DST_ANY_BSS (RX_CFG_ENABLE_ANY_DEST_MAC | \ + RX_CFG_ENABLE_ANY_BSSID) + +#define RX_CONFIG_OPTION_MY_DST_MY_BSS (RX_CFG_ENABLE_ONLY_MY_DEST_MAC\ + | RX_CFG_ENABLE_ONLY_MY_BSSID) + +#define RX_CONFIG_OPTION_FOR_SCAN (RX_CFG_ENABLE_PHY_HEADER_PLCP \ + | RX_CFG_ENABLE_RX_CMPLT_FCS_ERROR \ + | RX_CFG_COPY_RX_STATUS | RX_CFG_TSF) + +#define RX_CONFIG_OPTION_FOR_MEASUREMENT (RX_CFG_ENABLE_ANY_DEST_MAC) + +#define RX_CONFIG_OPTION_FOR_JOIN (RX_CFG_ENABLE_ONLY_MY_BSSID | \ + RX_CFG_ENABLE_ONLY_MY_DEST_MAC) + +#define RX_CONFIG_OPTION_FOR_IBSS_JOIN (RX_CFG_ENABLE_ONLY_MY_SSID | \ + RX_CFG_ENABLE_ONLY_MY_DEST_MAC) + +#define RX_FILTER_OPTION_DEF (CFG_RX_MGMT_EN | CFG_RX_DATA_EN\ + | CFG_RX_CTL_EN | CFG_RX_BCN_EN\ + | CFG_RX_AUTH_EN | CFG_RX_ASSOC_EN) + +#define RX_FILTER_OPTION_FILTER_ALL 0 + +#define RX_FILTER_OPTION_DEF_PRSP_BCN (CFG_RX_PRSP_EN | CFG_RX_MGMT_EN\ + | CFG_RX_RCTS_ACK | CFG_RX_BCN_EN) + +#define RX_FILTER_OPTION_JOIN (CFG_RX_MGMT_EN | CFG_RX_DATA_EN\ + | CFG_RX_BCN_EN | CFG_RX_AUTH_EN\ + | CFG_RX_ASSOC_EN | CFG_RX_RCTS_ACK\ + | CFG_RX_PRSP_EN) + + +/*=============================================== + Phy regs + ===============================================*/ +#define ACX_PHY_ADDR_REG SBB_ADDR +#define ACX_PHY_DATA_REG SBB_DATA +#define ACX_PHY_CTRL_REG SBB_CTL +#define ACX_PHY_REG_WR_MASK 0x00000001ul +#define ACX_PHY_REG_RD_MASK 0x00000002ul + + +/*=============================================== + EEPROM Read/Write Request 32bit RW + ------------------------------------------ + 1 EE_READ - EEPROM Read Request 1 - Setting this bit + loads a single byte of data into the EE_DATA + register from the EEPROM location specified in + the EE_ADDR register. + The Wlan hardware hardware clears this bit automatically. + EE_DATA is valid when this bit is cleared. + + 0 EE_WRITE - EEPROM Write Request - Setting this bit + writes a single byte of data from the EE_DATA register into the + EEPROM location specified in the EE_ADDR register. + The Wlan hardware hardware clears this bit automatically. +*===============================================*/ +#define ACX_EE_CTL_REG EE_CTL +#define EE_WRITE 0x00000001ul +#define EE_READ 0x00000002ul + +/*=============================================== + EEPROM Address - 32bit RW + ------------------------------------------ + This register specifies the address + within the EEPROM from/to which to read/write data. + ===============================================*/ +#define ACX_EE_ADDR_REG EE_ADDR + +/*=============================================== + EEPROM Data - 32bit RW + ------------------------------------------ + This register either holds the read 8 bits of + data from the EEPROM or the write data + to be written to the EEPROM. + ===============================================*/ +#define ACX_EE_DATA_REG EE_DATA + +/*=============================================== + EEPROM Base Address - 32bit RW + ------------------------------------------ + This register holds the upper nine bits + [23:15] of the 24-bit Wlan hardware memory + address for burst reads from EEPROM accesses. + The EEPROM provides the lower 15 bits of this address. + The MSB of the address from the EEPROM is ignored. + ===============================================*/ +#define ACX_EE_CFG EE_CFG + +/*=============================================== + GPIO Output Values -32bit, RW + ------------------------------------------ + [31:16] Reserved + [15: 0] Specify the output values (at the output driver inputs) for + GPIO[15:0], respectively. + ===============================================*/ +#define ACX_GPIO_OUT_REG GPIO_OUT +#define ACX_MAX_GPIO_LINES 15 + +/*=============================================== + Contention window -32bit, RW + ------------------------------------------ + [31:26] Reserved + [25:16] Max (0x3ff) + [15:07] Reserved + [06:00] Current contention window value - default is 0x1F + ===============================================*/ +#define ACX_CONT_WIND_CFG_REG CONT_WIND_CFG +#define ACX_CONT_WIND_MIN_MASK 0x0000007f +#define ACX_CONT_WIND_MAX 0x03ff0000 + +/* + * Indirect slave register/memory registers + * ---------------------------------------- + */ +#define HW_SLAVE_REG_ADDR_REG 0x00000004 +#define HW_SLAVE_REG_DATA_REG 0x00000008 +#define HW_SLAVE_REG_CTRL_REG 0x0000000c + +#define SLAVE_AUTO_INC 0x00010000 +#define SLAVE_NO_AUTO_INC 0x00000000 +#define SLAVE_HOST_LITTLE_ENDIAN 0x00000000 + +#define HW_SLAVE_MEM_ADDR_REG SLV_MEM_ADDR +#define HW_SLAVE_MEM_DATA_REG SLV_MEM_DATA +#define HW_SLAVE_MEM_CTRL_REG SLV_MEM_CTL +#define HW_SLAVE_MEM_ENDIAN_REG SLV_END_CTL + +#define HW_FUNC_EVENT_INT_EN 0x8000 +#define HW_FUNC_EVENT_MASK_REG 0x00000034 + +#define ACX_MAC_TIMESTAMP_REG (MAC_TIMESTAMP) + +/*=============================================== + HI_CFG Interface Configuration Register Values + ------------------------------------------ + ===============================================*/ +#define HI_CFG_UART_ENABLE 0x00000004 +#define HI_CFG_RST232_ENABLE 0x00000008 +#define HI_CFG_CLOCK_REQ_SELECT 0x00000010 +#define HI_CFG_HOST_INT_ENABLE 0x00000020 +#define HI_CFG_VLYNQ_OUTPUT_ENABLE 0x00000040 +#define HI_CFG_HOST_INT_ACTIVE_LOW 0x00000080 +#define HI_CFG_UART_TX_OUT_GPIO_15 0x00000100 +#define HI_CFG_UART_TX_OUT_GPIO_14 0x00000200 +#define HI_CFG_UART_TX_OUT_GPIO_7 0x00000400 + +/* + * NOTE: USE_ACTIVE_HIGH compilation flag should be defined in makefile + * for platforms using active high interrupt level + */ +#ifdef USE_ACTIVE_HIGH +#define HI_CFG_DEF_VAL \ + (HI_CFG_UART_ENABLE | \ + HI_CFG_RST232_ENABLE | \ + HI_CFG_CLOCK_REQ_SELECT | \ + HI_CFG_HOST_INT_ENABLE) +#else +#define HI_CFG_DEF_VAL \ + (HI_CFG_UART_ENABLE | \ + HI_CFG_RST232_ENABLE | \ + HI_CFG_CLOCK_REQ_SELECT | \ + HI_CFG_HOST_INT_ENABLE) + +#endif + +#define REF_FREQ_19_2 0 +#define REF_FREQ_26_0 1 +#define REF_FREQ_38_4 2 +#define REF_FREQ_40_0 3 +#define REF_FREQ_33_6 4 +#define REF_FREQ_NUM 5 + +#define LUT_PARAM_INTEGER_DIVIDER 0 +#define LUT_PARAM_FRACTIONAL_DIVIDER 1 +#define LUT_PARAM_ATTN_BB 2 +#define LUT_PARAM_ALPHA_BB 3 +#define LUT_PARAM_STOP_TIME_BB 4 +#define LUT_PARAM_BB_PLL_LOOP_FILTER 5 +#define LUT_PARAM_NUM 6 + +#define ACX_EEPROMLESS_IND_REG (SCR_PAD4) +#define USE_EEPROM 0 +#define SOFT_RESET_MAX_TIME 1000000 +#define SOFT_RESET_STALL_TIME 1000 +#define NVS_DATA_BUNDARY_ALIGNMENT 4 + + +/* Firmware image load chunk size */ +#define CHUNK_SIZE 512 + +/* Firmware image header size */ +#define FW_HDR_SIZE 8 + +#define ECPU_CONTROL_HALT 0x00000101 + + +/****************************************************************************** + + CHANNELS, BAND & REG DOMAINS definitions + +******************************************************************************/ + + +enum { + RADIO_BAND_2_4GHZ = 0, /* 2.4 Ghz band */ + RADIO_BAND_5GHZ = 1, /* 5 Ghz band */ + RADIO_BAND_JAPAN_4_9_GHZ = 2, + DEFAULT_BAND = RADIO_BAND_2_4GHZ, + INVALID_BAND = 0xFE, + MAX_RADIO_BANDS = 0xFF +}; + +enum { + NO_RATE = 0, + RATE_1MBPS = 0x0A, + RATE_2MBPS = 0x14, + RATE_5_5MBPS = 0x37, + RATE_6MBPS = 0x0B, + RATE_9MBPS = 0x0F, + RATE_11MBPS = 0x6E, + RATE_12MBPS = 0x0A, + RATE_18MBPS = 0x0E, + RATE_22MBPS = 0xDC, + RATE_24MBPS = 0x09, + RATE_36MBPS = 0x0D, + RATE_48MBPS = 0x08, + RATE_54MBPS = 0x0C +}; + +enum { + RATE_INDEX_1MBPS = 0, + RATE_INDEX_2MBPS = 1, + RATE_INDEX_5_5MBPS = 2, + RATE_INDEX_6MBPS = 3, + RATE_INDEX_9MBPS = 4, + RATE_INDEX_11MBPS = 5, + RATE_INDEX_12MBPS = 6, + RATE_INDEX_18MBPS = 7, + RATE_INDEX_22MBPS = 8, + RATE_INDEX_24MBPS = 9, + RATE_INDEX_36MBPS = 10, + RATE_INDEX_48MBPS = 11, + RATE_INDEX_54MBPS = 12, + RATE_INDEX_MAX = RATE_INDEX_54MBPS, + MAX_RATE_INDEX, + INVALID_RATE_INDEX = MAX_RATE_INDEX, + RATE_INDEX_ENUM_MAX_SIZE = 0x7FFFFFFF +}; + +enum { + RATE_MASK_1MBPS = 0x1, + RATE_MASK_2MBPS = 0x2, + RATE_MASK_5_5MBPS = 0x4, + RATE_MASK_11MBPS = 0x20, +}; + +#define SHORT_PREAMBLE_BIT BIT(0) /* CCK or Barker depending on the rate */ +#define OFDM_RATE_BIT BIT(6) +#define PBCC_RATE_BIT BIT(7) + +enum { + CCK_LONG = 0, + CCK_SHORT = SHORT_PREAMBLE_BIT, + PBCC_LONG = PBCC_RATE_BIT, + PBCC_SHORT = PBCC_RATE_BIT | SHORT_PREAMBLE_BIT, + OFDM = OFDM_RATE_BIT +}; + +/****************************************************************************** + +Transmit-Descriptor RATE-SET field definitions... + +Define a new "Rate-Set" for TX path that incorporates the +Rate & Modulation info into a single 16-bit field. + +TxdRateSet_t: +b15 - Indicates Preamble type (1=SHORT, 0=LONG). + Notes: + Must be LONG (0) for 1Mbps rate. + Does not apply (set to 0) for RevG-OFDM rates. +b14 - Indicates PBCC encoding (1=PBCC, 0=not). + Notes: + Does not apply (set to 0) for rates 1 and 2 Mbps. + Does not apply (set to 0) for RevG-OFDM rates. +b13 - Unused (set to 0). +b12-b0 - Supported Rate indicator bits as defined below. + +******************************************************************************/ + + +#define TNETW1251_CHIP_ID_PG1_0 0x07010101 +#define TNETW1251_CHIP_ID_PG1_1 0x07020101 +#define TNETW1251_CHIP_ID_PG1_2 0x07030101 + +/************************************************************************* + + Interrupt Trigger Register (Host -> WiLink) + +**************************************************************************/ + +/* Hardware to Embedded CPU Interrupts - first 32-bit register set */ + +/* + * Host Command Interrupt. Setting this bit masks + * the interrupt that the host issues to inform + * the FW that it has sent a command + * to the Wlan hardware Command Mailbox. + */ +#define INTR_TRIG_CMD BIT(0) + +/* + * Host Event Acknowlegde Interrupt. The host + * sets this bit to acknowledge that it received + * the unsolicited information from the event + * mailbox. + */ +#define INTR_TRIG_EVENT_ACK BIT(1) + +/* + * The host sets this bit to inform the Wlan + * FW that a TX packet is in the XFER + * Buffer #0. + */ +#define INTR_TRIG_TX_PROC0 BIT(2) + +/* + * The host sets this bit to inform the FW + * that it read a packet from RX XFER + * Buffer #0. + */ +#define INTR_TRIG_RX_PROC0 BIT(3) + +#define INTR_TRIG_DEBUG_ACK BIT(4) + +#define INTR_TRIG_STATE_CHANGED BIT(5) + + +/* Hardware to Embedded CPU Interrupts - second 32-bit register set */ + +/* + * The host sets this bit to inform the FW + * that it read a packet from RX XFER + * Buffer #1. + */ +#define INTR_TRIG_RX_PROC1 BIT(17) + +/* + * The host sets this bit to inform the Wlan + * hardware that a TX packet is in the XFER + * Buffer #1. + */ +#define INTR_TRIG_TX_PROC1 BIT(18) + +#endif diff --git a/drivers/net/wireless/wl12xx/rx.c b/drivers/net/wireless/wl12xx/rx.c new file mode 100644 index 000000000000..981ea259eb89 --- /dev/null +++ b/drivers/net/wireless/wl12xx/rx.c @@ -0,0 +1,208 @@ +/* + * This file is part of wl12xx + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include + +#include "wl12xx.h" +#include "reg.h" +#include "spi.h" +#include "rx.h" + +static void wl12xx_rx_header(struct wl12xx *wl, + struct wl12xx_rx_descriptor *desc) +{ + u32 rx_packet_ring_addr; + + rx_packet_ring_addr = wl->data_path->rx_packet_ring_addr; + if (wl->rx_current_buffer) + rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size; + + wl12xx_spi_mem_read(wl, rx_packet_ring_addr, desc, + sizeof(struct wl12xx_rx_descriptor)); +} + +static void wl12xx_rx_status(struct wl12xx *wl, + struct wl12xx_rx_descriptor *desc, + struct ieee80211_rx_status *status, + u8 beacon) +{ + memset(status, 0, sizeof(struct ieee80211_rx_status)); + + status->band = IEEE80211_BAND_2GHZ; + status->mactime = desc->timestamp; + + /* + * The rx status timestamp is a 32 bits value while the TSF is a + * 64 bits one. + * For IBSS merging, TSF is mandatory, so we have to get it + * somehow, so we ask for ACX_TSF_INFO. + * That could be moved to the get_tsf() hook, but unfortunately, + * this one must be atomic, while our SPI routines can sleep. + */ + if ((wl->bss_type == BSS_TYPE_IBSS) && beacon) { + u64 mactime; + int ret; + struct wl12xx_command cmd; + struct acx_tsf_info *tsf_info; + + memset(&cmd, 0, sizeof(cmd)); + + ret = wl12xx_cmd_interrogate(wl, ACX_TSF_INFO, + sizeof(struct acx_tsf_info), + &cmd); + if (ret < 0) { + wl12xx_warning("ACX_FW_REV interrogate failed"); + return; + } + + tsf_info = (struct acx_tsf_info *)&(cmd.parameters); + + mactime = tsf_info->current_tsf_lsb | + (tsf_info->current_tsf_msb << 31); + + status->mactime = mactime; + } + + status->signal = desc->rssi; + status->qual = (desc->rssi - WL12XX_RX_MIN_RSSI) * 100 / + (WL12XX_RX_MAX_RSSI - WL12XX_RX_MIN_RSSI); + status->qual = min(status->qual, 100); + status->qual = max(status->qual, 0); + + /* + * FIXME: guessing that snr needs to be divided by two, otherwise + * the values don't make any sense + */ + status->noise = desc->rssi - desc->snr / 2; + + status->freq = ieee80211_channel_to_frequency(desc->channel); + + status->flag |= RX_FLAG_TSFT; + + if (desc->flags & RX_DESC_ENCRYPTION_MASK) { + status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED; + + if (likely(!(desc->flags & RX_DESC_DECRYPT_FAIL))) + status->flag |= RX_FLAG_DECRYPTED; + + if (unlikely(desc->flags & RX_DESC_MIC_FAIL)) + status->flag |= RX_FLAG_MMIC_ERROR; + } + + if (unlikely(!(desc->flags & RX_DESC_VALID_FCS))) + status->flag |= RX_FLAG_FAILED_FCS_CRC; + + + /* FIXME: set status->rate_idx */ +} + +static void wl12xx_rx_body(struct wl12xx *wl, + struct wl12xx_rx_descriptor *desc) +{ + struct sk_buff *skb; + struct ieee80211_rx_status status; + u8 *rx_buffer, beacon = 0; + u16 length, *fc; + u32 curr_id, last_id_inc, rx_packet_ring_addr; + + length = WL12XX_RX_ALIGN(desc->length - PLCP_HEADER_LENGTH); + curr_id = (desc->flags & RX_DESC_SEQNUM_MASK) >> RX_DESC_PACKETID_SHIFT; + last_id_inc = (wl->rx_last_id + 1) % (RX_MAX_PACKET_ID + 1); + + if (last_id_inc != curr_id) { + wl12xx_warning("curr ID:%d, last ID inc:%d", + curr_id, last_id_inc); + wl->rx_last_id = curr_id; + } else { + wl->rx_last_id = last_id_inc; + } + + rx_packet_ring_addr = wl->data_path->rx_packet_ring_addr + + sizeof(struct wl12xx_rx_descriptor) + 20; + if (wl->rx_current_buffer) + rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size; + + skb = dev_alloc_skb(length); + if (!skb) { + wl12xx_error("Couldn't allocate RX frame"); + return; + } + + rx_buffer = skb_put(skb, length); + wl12xx_spi_mem_read(wl, rx_packet_ring_addr, rx_buffer, length); + + /* The actual lenght doesn't include the target's alignment */ + skb->len = desc->length - PLCP_HEADER_LENGTH; + + fc = (u16 *)skb->data; + + if ((*fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) + beacon = 1; + + wl12xx_rx_status(wl, desc, &status, beacon); + + wl12xx_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, skb->len, + beacon ? "beacon" : ""); + + ieee80211_rx(wl->hw, skb, &status); +} + +static void wl12xx_rx_ack(struct wl12xx *wl) +{ + u32 data, addr; + + if (wl->rx_current_buffer) { + addr = ACX_REG_INTERRUPT_TRIG_H; + data = INTR_TRIG_RX_PROC1; + } else { + addr = ACX_REG_INTERRUPT_TRIG; + data = INTR_TRIG_RX_PROC0; + } + + wl12xx_reg_write32(wl, addr, data); + + /* Toggle buffer ring */ + wl->rx_current_buffer = !wl->rx_current_buffer; +} + + +void wl12xx_rx(struct wl12xx *wl) +{ + struct wl12xx_rx_descriptor rx_desc; + + if (wl->state != WL12XX_STATE_ON) + return; + + /* We first read the frame's header */ + wl12xx_rx_header(wl, &rx_desc); + + /* Now we can read the body */ + wl12xx_rx_body(wl, &rx_desc); + + /* Finally, we need to ACK the RX */ + wl12xx_rx_ack(wl); + + return; +} diff --git a/drivers/net/wireless/wl12xx/rx.h b/drivers/net/wireless/wl12xx/rx.h new file mode 100644 index 000000000000..8a23fdea5016 --- /dev/null +++ b/drivers/net/wireless/wl12xx/rx.h @@ -0,0 +1,122 @@ +/* + * This file is part of wl12xx + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL12XX_RX_H__ +#define __WL12XX_RX_H__ + +#include + +/* + * RX PATH + * + * The Rx path uses a double buffer and an rx_contro structure, each located + * at a fixed address in the device memory. The host keeps track of which + * buffer is available and alternates between them on a per packet basis. + * The size of each of the two buffers is large enough to hold the longest + * 802.3 packet. + * The RX path goes like that: + * 1) The target generates an interrupt each time a new packet is received. + * There are 2 RX interrupts, one for each buffer. + * 2) The host reads the received packet from one of the double buffers. + * 3) The host triggers a target interrupt. + * 4) The target prepares the next RX packet. + */ + +#define WL12XX_RX_MAX_RSSI -30 +#define WL12XX_RX_MIN_RSSI -95 + +#define WL12XX_RX_ALIGN_TO 4 +#define WL12XX_RX_ALIGN(len) (((len) + WL12XX_RX_ALIGN_TO - 1) & \ + ~(WL12XX_RX_ALIGN_TO - 1)) + +#define SHORT_PREAMBLE_BIT BIT(0) +#define OFDM_RATE_BIT BIT(6) +#define PBCC_RATE_BIT BIT(7) + +#define PLCP_HEADER_LENGTH 8 +#define RX_DESC_PACKETID_SHIFT 11 +#define RX_MAX_PACKET_ID 3 + +#define RX_DESC_VALID_FCS 0x0001 +#define RX_DESC_MATCH_RXADDR1 0x0002 +#define RX_DESC_MCAST 0x0004 +#define RX_DESC_STAINTIM 0x0008 +#define RX_DESC_VIRTUAL_BM 0x0010 +#define RX_DESC_BCAST 0x0020 +#define RX_DESC_MATCH_SSID 0x0040 +#define RX_DESC_MATCH_BSSID 0x0080 +#define RX_DESC_ENCRYPTION_MASK 0x0300 +#define RX_DESC_MEASURMENT 0x0400 +#define RX_DESC_SEQNUM_MASK 0x1800 +#define RX_DESC_MIC_FAIL 0x2000 +#define RX_DESC_DECRYPT_FAIL 0x4000 + +struct wl12xx_rx_descriptor { + u32 timestamp; /* In microseconds */ + u16 length; /* Paylod length, including headers */ + u16 flags; + + /* + * 0 - 802.11 + * 1 - 802.3 + * 2 - IP + * 3 - Raw Codec + */ + u8 type; + + /* + * Recevied Rate: + * 0x0A - 1MBPS + * 0x14 - 2MBPS + * 0x37 - 5_5MBPS + * 0x0B - 6MBPS + * 0x0F - 9MBPS + * 0x6E - 11MBPS + * 0x0A - 12MBPS + * 0x0E - 18MBPS + * 0xDC - 22MBPS + * 0x09 - 24MBPS + * 0x0D - 36MBPS + * 0x08 - 48MBPS + * 0x0C - 54MBPS + */ + u8 rate; + + u8 mod_pre; /* Modulation and preamble */ + u8 channel; + + /* + * 0 - 2.4 Ghz + * 1 - 5 Ghz + */ + u8 band; + + s8 rssi; /* in dB */ + u8 rcpi; /* in dB */ + u8 snr; /* in dB */ +} __attribute__ ((packed)); + +void wl12xx_rx(struct wl12xx *wl); + +#endif diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/spi.c new file mode 100644 index 000000000000..abdf171a47e7 --- /dev/null +++ b/drivers/net/wireless/wl12xx/spi.c @@ -0,0 +1,358 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include + +#include "wl12xx.h" +#include "wl12xx_80211.h" +#include "reg.h" +#include "spi.h" +#include "ps.h" + +static int wl12xx_translate_reg_addr(struct wl12xx *wl, int addr) +{ + /* If the address is lower than REGISTERS_BASE, it means that this is + * a chip-specific register address, so look it up in the registers + * table */ + if (addr < REGISTERS_BASE) { + /* Make sure we don't go over the table */ + if (addr >= ACX_REG_TABLE_LEN) { + wl12xx_error("address out of range (%d)", addr); + return -EINVAL; + } + addr = wl->chip.acx_reg_table[addr]; + } + + return addr - wl->physical_reg_addr + wl->virtual_reg_addr; +} + +static int wl12xx_translate_mem_addr(struct wl12xx *wl, int addr) +{ + return addr - wl->physical_mem_addr + wl->virtual_mem_addr; +} + + +void wl12xx_spi_reset(struct wl12xx *wl) +{ + u8 *cmd; + struct spi_transfer t; + struct spi_message m; + + cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); + if (!cmd) { + wl12xx_error("could not allocate cmd for spi reset"); + return; + } + + memset(&t, 0, sizeof(t)); + spi_message_init(&m); + + memset(cmd, 0xff, WSPI_INIT_CMD_LEN); + + t.tx_buf = cmd; + t.len = WSPI_INIT_CMD_LEN; + spi_message_add_tail(&t, &m); + + spi_sync(wl->spi, &m); + + wl12xx_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN); +} + +void wl12xx_spi_init(struct wl12xx *wl) +{ + u8 crc[WSPI_INIT_CMD_CRC_LEN], *cmd; + struct spi_transfer t; + struct spi_message m; + + cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); + if (!cmd) { + wl12xx_error("could not allocate cmd for spi init"); + return; + } + + memset(crc, 0, sizeof(crc)); + memset(&t, 0, sizeof(t)); + spi_message_init(&m); + + /* + * Set WSPI_INIT_COMMAND + * the data is being send from the MSB to LSB + */ + cmd[2] = 0xff; + cmd[3] = 0xff; + cmd[1] = WSPI_INIT_CMD_START | WSPI_INIT_CMD_TX; + cmd[0] = 0; + cmd[7] = 0; + cmd[6] |= HW_ACCESS_WSPI_INIT_CMD_MASK << 3; + cmd[6] |= HW_ACCESS_WSPI_FIXED_BUSY_LEN & WSPI_INIT_CMD_FIXEDBUSY_LEN; + + if (HW_ACCESS_WSPI_FIXED_BUSY_LEN == 0) + cmd[5] |= WSPI_INIT_CMD_DIS_FIXEDBUSY; + else + cmd[5] |= WSPI_INIT_CMD_EN_FIXEDBUSY; + + cmd[5] |= WSPI_INIT_CMD_IOD | WSPI_INIT_CMD_IP | WSPI_INIT_CMD_CS + | WSPI_INIT_CMD_WSPI | WSPI_INIT_CMD_WS; + + crc[0] = cmd[1]; + crc[1] = cmd[0]; + crc[2] = cmd[7]; + crc[3] = cmd[6]; + crc[4] = cmd[5]; + + cmd[4] |= crc7(0, crc, WSPI_INIT_CMD_CRC_LEN) << 1; + cmd[4] |= WSPI_INIT_CMD_END; + + t.tx_buf = cmd; + t.len = WSPI_INIT_CMD_LEN; + spi_message_add_tail(&t, &m); + + spi_sync(wl->spi, &m); + + wl12xx_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN); +} + +/* Set the SPI partitions to access the chip addresses + * + * There are two VIRTUAL (SPI) partitions (the memory partition and the + * registers partition), which are mapped to two different areas of the + * PHYSICAL (hardware) memory. This function also makes other checks to + * ensure that the partitions are not overlapping. In the diagram below, the + * memory partition comes before the register partition, but the opposite is + * also supported. + * + * PHYSICAL address + * space + * + * | | + * ...+----+--> mem_start + * VIRTUAL address ... | | + * space ... | | [PART_0] + * ... | | + * 0x00000000 <--+----+... ...+----+--> mem_start + mem_size + * | | ... | | + * |MEM | ... | | + * | | ... | | + * part_size <--+----+... | | {unused area) + * | | ... | | + * |REG | ... | | + * part_size | | ... | | + * + <--+----+... ...+----+--> reg_start + * reg_size ... | | + * ... | | [PART_1] + * ... | | + * ...+----+--> reg_start + reg_size + * | | + * + */ +void wl12xx_set_partition(struct wl12xx *wl, + u32 mem_start, u32 mem_size, + u32 reg_start, u32 reg_size) +{ + u8 tx_buf[sizeof(u32) + 2 * sizeof(struct wl12xx_partition)]; + struct wl12xx_partition *partition; + struct spi_transfer t; + struct spi_message m; + u32 *cmd; + size_t len; + int addr; + + spi_message_init(&m); + memset(&t, 0, sizeof(t)); + memset(tx_buf, 0, sizeof(tx_buf)); + + cmd = (u32 *) tx_buf; + partition = (struct wl12xx_partition *) (tx_buf + sizeof(u32)); + addr = HW_ACCESS_PART0_SIZE_ADDR; + len = 2 * sizeof(struct wl12xx_partition); + + *cmd |= WSPI_CMD_WRITE; + *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; + *cmd |= addr & WSPI_CMD_BYTE_ADDR; + + wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", + mem_start, mem_size); + wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", + reg_start, reg_size); + + /* Make sure that the two partitions together don't exceed the + * address range */ + if ((mem_size + reg_size) > HW_ACCESS_MEMORY_MAX_RANGE) { + wl12xx_debug(DEBUG_SPI, "Total size exceeds maximum virtual" + " address range. Truncating partition[0]."); + mem_size = HW_ACCESS_MEMORY_MAX_RANGE - reg_size; + wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", + mem_start, mem_size); + wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", + reg_start, reg_size); + } + + if ((mem_start < reg_start) && + ((mem_start + mem_size) > reg_start)) { + /* Guarantee that the memory partition doesn't overlap the + * registers partition */ + wl12xx_debug(DEBUG_SPI, "End of partition[0] is " + "overlapping partition[1]. Adjusted."); + mem_size = reg_start - mem_start; + wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", + mem_start, mem_size); + wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", + reg_start, reg_size); + } else if ((reg_start < mem_start) && + ((reg_start + reg_size) > mem_start)) { + /* Guarantee that the register partition doesn't overlap the + * memory partition */ + wl12xx_debug(DEBUG_SPI, "End of partition[1] is" + " overlapping partition[0]. Adjusted."); + reg_size = mem_start - reg_start; + wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", + mem_start, mem_size); + wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", + reg_start, reg_size); + } + + partition[0].start = mem_start; + partition[0].size = mem_size; + partition[1].start = reg_start; + partition[1].size = reg_size; + + wl->physical_mem_addr = mem_start; + wl->physical_reg_addr = reg_start; + + wl->virtual_mem_addr = 0; + wl->virtual_reg_addr = mem_size; + + t.tx_buf = tx_buf; + t.len = sizeof(tx_buf); + spi_message_add_tail(&t, &m); + + spi_sync(wl->spi, &m); +} + +void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf, + size_t len) +{ + struct spi_transfer t[3]; + struct spi_message m; + char busy_buf[TNETWIF_READ_OFFSET_BYTES]; + u32 cmd; + + cmd = 0; + cmd |= WSPI_CMD_READ; + cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; + cmd |= addr & WSPI_CMD_BYTE_ADDR; + + spi_message_init(&m); + memset(t, 0, sizeof(t)); + + t[0].tx_buf = &cmd; + t[0].len = 4; + spi_message_add_tail(&t[0], &m); + + /* Busy and non busy words read */ + t[1].rx_buf = busy_buf; + t[1].len = TNETWIF_READ_OFFSET_BYTES; + spi_message_add_tail(&t[1], &m); + + t[2].rx_buf = buf; + t[2].len = len; + spi_message_add_tail(&t[2], &m); + + spi_sync(wl->spi, &m); + + /* FIXME: check busy words */ + + wl12xx_dump(DEBUG_SPI, "spi_read cmd -> ", &cmd, sizeof(cmd)); + wl12xx_dump(DEBUG_SPI, "spi_read buf <- ", buf, len); +} + +void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf, + size_t len) +{ + struct spi_transfer t[2]; + struct spi_message m; + u32 cmd; + + cmd = 0; + cmd |= WSPI_CMD_WRITE; + cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; + cmd |= addr & WSPI_CMD_BYTE_ADDR; + + spi_message_init(&m); + memset(t, 0, sizeof(t)); + + t[0].tx_buf = &cmd; + t[0].len = sizeof(cmd); + spi_message_add_tail(&t[0], &m); + + t[1].tx_buf = buf; + t[1].len = len; + spi_message_add_tail(&t[1], &m); + + spi_sync(wl->spi, &m); + + wl12xx_dump(DEBUG_SPI, "spi_write cmd -> ", &cmd, sizeof(cmd)); + wl12xx_dump(DEBUG_SPI, "spi_write buf -> ", buf, len); +} + +void wl12xx_spi_mem_read(struct wl12xx *wl, int addr, void *buf, + size_t len) +{ + int physical; + + physical = wl12xx_translate_mem_addr(wl, addr); + + wl12xx_spi_read(wl, physical, buf, len); +} + +void wl12xx_spi_mem_write(struct wl12xx *wl, int addr, void *buf, + size_t len) +{ + int physical; + + physical = wl12xx_translate_mem_addr(wl, addr); + + wl12xx_spi_write(wl, physical, buf, len); +} + +u32 wl12xx_mem_read32(struct wl12xx *wl, int addr) +{ + return wl12xx_read32(wl, wl12xx_translate_mem_addr(wl, addr)); +} + +void wl12xx_mem_write32(struct wl12xx *wl, int addr, u32 val) +{ + wl12xx_write32(wl, wl12xx_translate_mem_addr(wl, addr), val); +} + +u32 wl12xx_reg_read32(struct wl12xx *wl, int addr) +{ + return wl12xx_read32(wl, wl12xx_translate_reg_addr(wl, addr)); +} + +void wl12xx_reg_write32(struct wl12xx *wl, int addr, u32 val) +{ + wl12xx_write32(wl, wl12xx_translate_reg_addr(wl, addr), val); +} diff --git a/drivers/net/wireless/wl12xx/spi.h b/drivers/net/wireless/wl12xx/spi.h new file mode 100644 index 000000000000..fd3227e904a8 --- /dev/null +++ b/drivers/net/wireless/wl12xx/spi.h @@ -0,0 +1,109 @@ +/* + * This file is part of wl12xx + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL12XX_SPI_H__ +#define __WL12XX_SPI_H__ + +#include "cmd.h" +#include "acx.h" +#include "reg.h" + +#define HW_ACCESS_MEMORY_MAX_RANGE 0x1FFC0 + +#define HW_ACCESS_PART0_SIZE_ADDR 0x1FFC0 +#define HW_ACCESS_PART0_START_ADDR 0x1FFC4 +#define HW_ACCESS_PART1_SIZE_ADDR 0x1FFC8 +#define HW_ACCESS_PART1_START_ADDR 0x1FFCC + +#define HW_ACCESS_REGISTER_SIZE 4 + +#define HW_ACCESS_PRAM_MAX_RANGE 0x3c000 + +#define WSPI_CMD_READ 0x40000000 +#define WSPI_CMD_WRITE 0x00000000 +#define WSPI_CMD_FIXED 0x20000000 +#define WSPI_CMD_BYTE_LENGTH 0x1FFE0000 +#define WSPI_CMD_BYTE_LENGTH_OFFSET 17 +#define WSPI_CMD_BYTE_ADDR 0x0001FFFF + +#define WSPI_INIT_CMD_CRC_LEN 5 + +#define WSPI_INIT_CMD_START 0x00 +#define WSPI_INIT_CMD_TX 0x40 +/* the extra bypass bit is sampled by the TNET as '1' */ +#define WSPI_INIT_CMD_BYPASS_BIT 0x80 +#define WSPI_INIT_CMD_FIXEDBUSY_LEN 0x07 +#define WSPI_INIT_CMD_EN_FIXEDBUSY 0x80 +#define WSPI_INIT_CMD_DIS_FIXEDBUSY 0x00 +#define WSPI_INIT_CMD_IOD 0x40 +#define WSPI_INIT_CMD_IP 0x20 +#define WSPI_INIT_CMD_CS 0x10 +#define WSPI_INIT_CMD_WS 0x08 +#define WSPI_INIT_CMD_WSPI 0x01 +#define WSPI_INIT_CMD_END 0x01 + +#define WSPI_INIT_CMD_LEN 8 + +#define TNETWIF_READ_OFFSET_BYTES 8 +#define HW_ACCESS_WSPI_FIXED_BUSY_LEN \ + ((TNETWIF_READ_OFFSET_BYTES - 4) / sizeof(u32)) +#define HW_ACCESS_WSPI_INIT_CMD_MASK 0 + + +/* Raw target IO, address is not translated */ +void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf, size_t len); +void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf, size_t len); + +/* Memory target IO, address is tranlated to partition 0 */ +void wl12xx_spi_mem_read(struct wl12xx *wl, int addr, void *buf, size_t len); +void wl12xx_spi_mem_write(struct wl12xx *wl, int addr, void *buf, size_t len); +u32 wl12xx_mem_read32(struct wl12xx *wl, int addr); +void wl12xx_mem_write32(struct wl12xx *wl, int addr, u32 val); + +/* Registers IO */ +u32 wl12xx_reg_read32(struct wl12xx *wl, int addr); +void wl12xx_reg_write32(struct wl12xx *wl, int addr, u32 val); + +/* INIT and RESET words */ +void wl12xx_spi_reset(struct wl12xx *wl); +void wl12xx_spi_init(struct wl12xx *wl); +void wl12xx_set_partition(struct wl12xx *wl, + u32 part_start, u32 part_size, + u32 reg_start, u32 reg_size); + +static inline u32 wl12xx_read32(struct wl12xx *wl, int addr) +{ + u32 response; + + wl12xx_spi_read(wl, addr, &response, sizeof(u32)); + + return response; +} + +static inline void wl12xx_write32(struct wl12xx *wl, int addr, u32 val) +{ + wl12xx_spi_write(wl, addr, &val, sizeof(u32)); +} + +#endif /* __WL12XX_SPI_H__ */ diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c new file mode 100644 index 000000000000..62145e205a8c --- /dev/null +++ b/drivers/net/wireless/wl12xx/tx.c @@ -0,0 +1,557 @@ +/* + * This file is part of wl12xx + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include + +#include "wl12xx.h" +#include "reg.h" +#include "spi.h" +#include "tx.h" +#include "ps.h" + +static bool wl12xx_tx_double_buffer_busy(struct wl12xx *wl, u32 data_out_count) +{ + int used, data_in_count; + + data_in_count = wl->data_in_count; + + if (data_in_count < data_out_count) + /* data_in_count has wrapped */ + data_in_count += TX_STATUS_DATA_OUT_COUNT_MASK + 1; + + used = data_in_count - data_out_count; + + WARN_ON(used < 0); + WARN_ON(used > DP_TX_PACKET_RING_CHUNK_NUM); + + if (used >= DP_TX_PACKET_RING_CHUNK_NUM) + return true; + else + return false; +} + +static int wl12xx_tx_path_status(struct wl12xx *wl) +{ + u32 status, addr, data_out_count; + bool busy; + + addr = wl->data_path->tx_control_addr; + status = wl12xx_mem_read32(wl, addr); + data_out_count = status & TX_STATUS_DATA_OUT_COUNT_MASK; + busy = wl12xx_tx_double_buffer_busy(wl, data_out_count); + + if (busy) + return -EBUSY; + + return 0; +} + +static int wl12xx_tx_id(struct wl12xx *wl, struct sk_buff *skb) +{ + int i; + + for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) + if (wl->tx_frames[i] == NULL) { + wl->tx_frames[i] = skb; + return i; + } + + return -EBUSY; +} + +static void wl12xx_tx_control(struct tx_double_buffer_desc *tx_hdr, + struct ieee80211_tx_info *control, u16 fc) +{ + *(u16 *)&tx_hdr->control = 0; + + tx_hdr->control.rate_policy = 0; + + /* 802.11 packets */ + tx_hdr->control.packet_type = 0; + + if (control->flags & IEEE80211_TX_CTL_NO_ACK) + tx_hdr->control.ack_policy = 1; + + tx_hdr->control.tx_complete = 1; + + if ((fc & IEEE80211_FTYPE_DATA) && + ((fc & IEEE80211_STYPE_QOS_DATA) || + (fc & IEEE80211_STYPE_QOS_NULLFUNC))) + tx_hdr->control.qos = 1; +} + +/* RSN + MIC = 8 + 8 = 16 bytes (worst case - AES). */ +#define MAX_MSDU_SECURITY_LENGTH 16 +#define MAX_MPDU_SECURITY_LENGTH 16 +#define WLAN_QOS_HDR_LEN 26 +#define MAX_MPDU_HEADER_AND_SECURITY (MAX_MPDU_SECURITY_LENGTH + \ + WLAN_QOS_HDR_LEN) +#define HW_BLOCK_SIZE 252 +static void wl12xx_tx_frag_block_num(struct tx_double_buffer_desc *tx_hdr) +{ + u16 payload_len, frag_threshold, mem_blocks; + u16 num_mpdus, mem_blocks_per_frag; + + frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD; + tx_hdr->frag_threshold = cpu_to_le16(frag_threshold); + + payload_len = tx_hdr->length + MAX_MSDU_SECURITY_LENGTH; + + if (payload_len > frag_threshold) { + mem_blocks_per_frag = + ((frag_threshold + MAX_MPDU_HEADER_AND_SECURITY) / + HW_BLOCK_SIZE) + 1; + num_mpdus = payload_len / frag_threshold; + mem_blocks = num_mpdus * mem_blocks_per_frag; + payload_len -= num_mpdus * frag_threshold; + num_mpdus++; + + } else { + mem_blocks_per_frag = 0; + mem_blocks = 0; + num_mpdus = 1; + } + + mem_blocks += (payload_len / HW_BLOCK_SIZE) + 1; + + if (num_mpdus > 1) + mem_blocks += min(num_mpdus, mem_blocks_per_frag); + + tx_hdr->num_mem_blocks = mem_blocks; +} + +static int wl12xx_tx_fill_hdr(struct wl12xx *wl, struct sk_buff *skb, + struct ieee80211_tx_info *control) +{ + struct tx_double_buffer_desc *tx_hdr; + struct ieee80211_rate *rate; + int id; + u16 fc; + + if (!skb) + return -EINVAL; + + id = wl12xx_tx_id(wl, skb); + if (id < 0) + return id; + + fc = *(u16 *)skb->data; + tx_hdr = (struct tx_double_buffer_desc *) skb_push(skb, + sizeof(*tx_hdr)); + + tx_hdr->length = cpu_to_le16(skb->len - sizeof(*tx_hdr)); + rate = ieee80211_get_tx_rate(wl->hw, control); + tx_hdr->rate = cpu_to_le16(rate->hw_value); + tx_hdr->expiry_time = cpu_to_le32(1 << 16); + tx_hdr->id = id; + + /* FIXME: how to get the correct queue id? */ + tx_hdr->xmit_queue = 0; + + wl12xx_tx_control(tx_hdr, control, fc); + wl12xx_tx_frag_block_num(tx_hdr); + + return 0; +} + +/* We copy the packet to the target */ +static int wl12xx_tx_send_packet(struct wl12xx *wl, struct sk_buff *skb, + struct ieee80211_tx_info *control) +{ + struct tx_double_buffer_desc *tx_hdr; + int len; + u32 addr; + + if (!skb) + return -EINVAL; + + tx_hdr = (struct tx_double_buffer_desc *) skb->data; + + if (control->control.hw_key && + control->control.hw_key->alg == ALG_TKIP) { + int hdrlen; + u16 fc; + u8 *pos; + + fc = *(u16 *)(skb->data + sizeof(*tx_hdr)); + tx_hdr->length += WL12XX_TKIP_IV_SPACE; + + hdrlen = ieee80211_hdrlen(fc); + + pos = skb_push(skb, WL12XX_TKIP_IV_SPACE); + memmove(pos, pos + WL12XX_TKIP_IV_SPACE, + sizeof(*tx_hdr) + hdrlen); + } + + /* Revisit. This is a workaround for getting non-aligned packets. + This happens at least with EAPOL packets from the user space. + Our DMA requires packets to be aligned on a 4-byte boundary. + */ + if (unlikely((long)skb->data & 0x03)) { + int offset = (4 - (long)skb->data) & 0x03; + wl12xx_debug(DEBUG_TX, "skb offset %d", offset); + + /* check whether the current skb can be used */ + if (!skb_cloned(skb) && (skb_tailroom(skb) >= offset)) { + unsigned char *src = skb->data; + + /* align the buffer on a 4-byte boundary */ + skb_reserve(skb, offset); + memmove(skb->data, src, skb->len); + } else { + wl12xx_info("No handler, fixme!"); + return -EINVAL; + } + } + + /* Our skb->data at this point includes the HW header */ + len = WL12XX_TX_ALIGN(skb->len); + + if (wl->data_in_count & 0x1) + addr = wl->data_path->tx_packet_ring_addr + + wl->data_path->tx_packet_ring_chunk_size; + else + addr = wl->data_path->tx_packet_ring_addr; + + wl12xx_spi_mem_write(wl, addr, skb->data, len); + + wl12xx_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u rate 0x%x", + tx_hdr->id, skb, tx_hdr->length, tx_hdr->rate); + + return 0; +} + +static void wl12xx_tx_trigger(struct wl12xx *wl) +{ + u32 data, addr; + + if (wl->data_in_count & 0x1) { + addr = ACX_REG_INTERRUPT_TRIG_H; + data = INTR_TRIG_TX_PROC1; + } else { + addr = ACX_REG_INTERRUPT_TRIG; + data = INTR_TRIG_TX_PROC0; + } + + wl12xx_reg_write32(wl, addr, data); + + /* Bumping data in */ + wl->data_in_count = (wl->data_in_count + 1) & + TX_STATUS_DATA_OUT_COUNT_MASK; +} + +/* caller must hold wl->mutex */ +static int wl12xx_tx_frame(struct wl12xx *wl, struct sk_buff *skb) +{ + struct ieee80211_tx_info *info; + int ret = 0; + u8 idx; + + info = IEEE80211_SKB_CB(skb); + + if (info->control.hw_key) { + idx = info->control.hw_key->hw_key_idx; + if (unlikely(wl->default_key != idx)) { + ret = wl12xx_acx_default_key(wl, idx); + if (ret < 0) + return ret; + } + } + + ret = wl12xx_tx_path_status(wl); + if (ret < 0) + return ret; + + ret = wl12xx_tx_fill_hdr(wl, skb, info); + if (ret < 0) + return ret; + + ret = wl12xx_tx_send_packet(wl, skb, info); + if (ret < 0) + return ret; + + wl12xx_tx_trigger(wl); + + return ret; +} + +void wl12xx_tx_work(struct work_struct *work) +{ + struct wl12xx *wl = container_of(work, struct wl12xx, tx_work); + struct sk_buff *skb; + bool woken_up = false; + int ret; + + mutex_lock(&wl->mutex); + + if (unlikely(wl->state == WL12XX_STATE_OFF)) + goto out; + + while ((skb = skb_dequeue(&wl->tx_queue))) { + if (!woken_up) { + wl12xx_ps_elp_wakeup(wl); + woken_up = true; + } + + ret = wl12xx_tx_frame(wl, skb); + if (ret == -EBUSY) { + /* firmware buffer is full, stop queues */ + wl12xx_debug(DEBUG_TX, "tx_work: fw buffer full, " + "stop queues"); + ieee80211_stop_queues(wl->hw); + wl->tx_queue_stopped = true; + skb_queue_head(&wl->tx_queue, skb); + goto out; + } else if (ret < 0) { + dev_kfree_skb(skb); + goto out; + } + } + +out: + if (woken_up) + wl12xx_ps_elp_sleep(wl); + + mutex_unlock(&wl->mutex); +} + +static const char *wl12xx_tx_parse_status(u8 status) +{ + /* 8 bit status field, one character per bit plus null */ + static char buf[9]; + int i = 0; + + memset(buf, 0, sizeof(buf)); + + if (status & TX_DMA_ERROR) + buf[i++] = 'm'; + if (status & TX_DISABLED) + buf[i++] = 'd'; + if (status & TX_RETRY_EXCEEDED) + buf[i++] = 'r'; + if (status & TX_TIMEOUT) + buf[i++] = 't'; + if (status & TX_KEY_NOT_FOUND) + buf[i++] = 'k'; + if (status & TX_ENCRYPT_FAIL) + buf[i++] = 'e'; + if (status & TX_UNAVAILABLE_PRIORITY) + buf[i++] = 'p'; + + /* bit 0 is unused apparently */ + + return buf; +} + +static void wl12xx_tx_packet_cb(struct wl12xx *wl, + struct tx_result *result) +{ + struct ieee80211_tx_info *info; + struct sk_buff *skb; + int hdrlen, ret; + u8 *frame; + + skb = wl->tx_frames[result->id]; + if (skb == NULL) { + wl12xx_error("SKB for packet %d is NULL", result->id); + return; + } + + info = IEEE80211_SKB_CB(skb); + + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && + (result->status == TX_SUCCESS)) + info->flags |= IEEE80211_TX_STAT_ACK; + + info->status.rates[0].count = result->ack_failures + 1; + wl->stats.retry_count += result->ack_failures; + + /* + * We have to remove our private TX header before pushing + * the skb back to mac80211. + */ + frame = skb_pull(skb, sizeof(struct tx_double_buffer_desc)); + if (info->control.hw_key && + info->control.hw_key->alg == ALG_TKIP) { + hdrlen = ieee80211_get_hdrlen_from_skb(skb); + memmove(frame + WL12XX_TKIP_IV_SPACE, frame, hdrlen); + skb_pull(skb, WL12XX_TKIP_IV_SPACE); + } + + wl12xx_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x" + " status 0x%x (%s)", + result->id, skb, result->ack_failures, result->rate, + result->status, wl12xx_tx_parse_status(result->status)); + + + ieee80211_tx_status(wl->hw, skb); + + wl->tx_frames[result->id] = NULL; + + if (wl->tx_queue_stopped) { + wl12xx_debug(DEBUG_TX, "cb: queue was stopped"); + + skb = skb_dequeue(&wl->tx_queue); + + /* The skb can be NULL because tx_work might have been + scheduled before the queue was stopped making the + queue empty */ + + if (skb) { + ret = wl12xx_tx_frame(wl, skb); + if (ret == -EBUSY) { + /* firmware buffer is still full */ + wl12xx_debug(DEBUG_TX, "cb: fw buffer " + "still full"); + skb_queue_head(&wl->tx_queue, skb); + return; + } else if (ret < 0) { + dev_kfree_skb(skb); + return; + } + } + + wl12xx_debug(DEBUG_TX, "cb: waking queues"); + ieee80211_wake_queues(wl->hw); + wl->tx_queue_stopped = false; + } +} + +/* Called upon reception of a TX complete interrupt */ +void wl12xx_tx_complete(struct wl12xx *wl) +{ + int i, result_index, num_complete = 0; + struct tx_result result[FW_TX_CMPLT_BLOCK_SIZE], *result_ptr; + + if (unlikely(wl->state != WL12XX_STATE_ON)) + return; + + /* First we read the result */ + wl12xx_spi_mem_read(wl, wl->data_path->tx_complete_addr, + result, sizeof(result)); + + result_index = wl->next_tx_complete; + + for (i = 0; i < ARRAY_SIZE(result); i++) { + result_ptr = &result[result_index]; + + if (result_ptr->done_1 == 1 && + result_ptr->done_2 == 1) { + wl12xx_tx_packet_cb(wl, result_ptr); + + result_ptr->done_1 = 0; + result_ptr->done_2 = 0; + + result_index = (result_index + 1) & + (FW_TX_CMPLT_BLOCK_SIZE - 1); + num_complete++; + } else { + break; + } + } + + /* Every completed frame needs to be acknowledged */ + if (num_complete) { + /* + * If we've wrapped, we have to clear + * the results in 2 steps. + */ + if (result_index > wl->next_tx_complete) { + /* Only 1 write is needed */ + wl12xx_spi_mem_write(wl, + wl->data_path->tx_complete_addr + + (wl->next_tx_complete * + sizeof(struct tx_result)), + &result[wl->next_tx_complete], + num_complete * + sizeof(struct tx_result)); + + + } else if (result_index < wl->next_tx_complete) { + /* 2 writes are needed */ + wl12xx_spi_mem_write(wl, + wl->data_path->tx_complete_addr + + (wl->next_tx_complete * + sizeof(struct tx_result)), + &result[wl->next_tx_complete], + (FW_TX_CMPLT_BLOCK_SIZE - + wl->next_tx_complete) * + sizeof(struct tx_result)); + + wl12xx_spi_mem_write(wl, + wl->data_path->tx_complete_addr, + result, + (num_complete - + FW_TX_CMPLT_BLOCK_SIZE + + wl->next_tx_complete) * + sizeof(struct tx_result)); + + } else { + /* We have to write the whole array */ + wl12xx_spi_mem_write(wl, + wl->data_path->tx_complete_addr, + result, + FW_TX_CMPLT_BLOCK_SIZE * + sizeof(struct tx_result)); + } + + } + + wl->next_tx_complete = result_index; +} + +/* caller must hold wl->mutex */ +void wl12xx_tx_flush(struct wl12xx *wl) +{ + int i; + struct sk_buff *skb; + struct ieee80211_tx_info *info; + + /* TX failure */ +/* control->flags = 0; FIXME */ + + while ((skb = skb_dequeue(&wl->tx_queue))) { + info = IEEE80211_SKB_CB(skb); + + wl12xx_debug(DEBUG_TX, "flushing skb 0x%p", skb); + + if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)) + continue; + + ieee80211_tx_status(wl->hw, skb); + } + + for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) + if (wl->tx_frames[i] != NULL) { + skb = wl->tx_frames[i]; + info = IEEE80211_SKB_CB(skb); + + if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)) + continue; + + ieee80211_tx_status(wl->hw, skb); + wl->tx_frames[i] = NULL; + } +} diff --git a/drivers/net/wireless/wl12xx/tx.h b/drivers/net/wireless/wl12xx/tx.h new file mode 100644 index 000000000000..dc82691f4c14 --- /dev/null +++ b/drivers/net/wireless/wl12xx/tx.h @@ -0,0 +1,215 @@ +/* + * This file is part of wl12xx + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL12XX_TX_H__ +#define __WL12XX_TX_H__ + +#include + +/* + * + * TX PATH + * + * The Tx path uses a double buffer and a tx_control structure, each located + * at a fixed address in the device's memory. On startup, the host retrieves + * the pointers to these addresses. A double buffer allows for continuous data + * flow towards the device. The host keeps track of which buffer is available + * and alternates between these two buffers on a per packet basis. + * + * The size of each of the two buffers is large enough to hold the longest + * 802.3 packet - maximum size Ethernet packet + header + descriptor. + * TX complete indication will be received a-synchronously in a TX done cyclic + * buffer which is composed of 16 tx_result descriptors structures and is used + * in a cyclic manner. + * + * The TX (HOST) procedure is as follows: + * 1. Read the Tx path status, that will give the data_out_count. + * 2. goto 1, if not possible. + * i.e. if data_in_count - data_out_count >= HwBuffer size (2 for double + * buffer). + * 3. Copy the packet (preceded by double_buffer_desc), if possible. + * i.e. if data_in_count - data_out_count < HwBuffer size (2 for double + * buffer). + * 4. increment data_in_count. + * 5. Inform the firmware by generating a firmware internal interrupt. + * 6. FW will increment data_out_count after it reads the buffer. + * + * The TX Complete procedure: + * 1. To get a TX complete indication the host enables the tx_complete flag in + * the TX descriptor Structure. + * 2. For each packet with a Tx Complete field set, the firmware adds the + * transmit results to the cyclic buffer (txDoneRing) and sets both done_1 + * and done_2 to 1 to indicate driver ownership. + * 3. The firmware sends a Tx Complete interrupt to the host to trigger the + * host to process the new data. Note: interrupt will be send per packet if + * TX complete indication was requested in tx_control or per crossing + * aggregation threshold. + * 4. After receiving the Tx Complete interrupt, the host reads the + * TxDescriptorDone information in a cyclic manner and clears both done_1 + * and done_2 fields. + * + */ + +#define TX_COMPLETE_REQUIRED_BIT 0x80 +#define TX_STATUS_DATA_OUT_COUNT_MASK 0xf +#define WL12XX_TX_ALIGN_TO 4 +#define WL12XX_TX_ALIGN(len) (((len) + WL12XX_TX_ALIGN_TO - 1) & \ + ~(WL12XX_TX_ALIGN_TO - 1)) +#define WL12XX_TKIP_IV_SPACE 4 + +struct tx_control { + /* Rate Policy (class) index */ + unsigned rate_policy:3; + + /* When set, no ack policy is expected */ + unsigned ack_policy:1; + + /* + * Packet type: + * 0 -> 802.11 + * 1 -> 802.3 + * 2 -> IP + * 3 -> raw codec + */ + unsigned packet_type:2; + + /* If set, this is a QoS-Null or QoS-Data frame */ + unsigned qos:1; + + /* + * If set, the target triggers the tx complete INT + * upon frame sending completion. + */ + unsigned tx_complete:1; + + /* 2 bytes padding before packet header */ + unsigned xfer_pad:1; + + unsigned reserved:7; +} __attribute__ ((packed)); + + +struct tx_double_buffer_desc { + /* Length of payload, including headers. */ + u16 length; + + /* + * A bit mask that specifies the initial rate to be used + * Possible values are: + * 0x0001 - 1Mbits + * 0x0002 - 2Mbits + * 0x0004 - 5.5Mbits + * 0x0008 - 6Mbits + * 0x0010 - 9Mbits + * 0x0020 - 11Mbits + * 0x0040 - 12Mbits + * 0x0080 - 18Mbits + * 0x0100 - 22Mbits + * 0x0200 - 24Mbits + * 0x0400 - 36Mbits + * 0x0800 - 48Mbits + * 0x1000 - 54Mbits + */ + u16 rate; + + /* Time in us that a packet can spend in the target */ + u32 expiry_time; + + /* index of the TX queue used for this packet */ + u8 xmit_queue; + + /* Used to identify a packet */ + u8 id; + + struct tx_control control; + + /* + * The FW should cut the packet into fragments + * of this size. + */ + u16 frag_threshold; + + /* Numbers of HW queue blocks to be allocated */ + u8 num_mem_blocks; + + u8 reserved; +} __attribute__ ((packed)); + +enum { + TX_SUCCESS = 0, + TX_DMA_ERROR = BIT(7), + TX_DISABLED = BIT(6), + TX_RETRY_EXCEEDED = BIT(5), + TX_TIMEOUT = BIT(4), + TX_KEY_NOT_FOUND = BIT(3), + TX_ENCRYPT_FAIL = BIT(2), + TX_UNAVAILABLE_PRIORITY = BIT(1), +}; + +struct tx_result { + /* + * Ownership synchronization between the host and + * the firmware. If done_1 and done_2 are cleared, + * owned by the FW (no info ready). + */ + u8 done_1; + + /* same as double_buffer_desc->id */ + u8 id; + + /* + * Total air access duration consumed by this + * packet, including all retries and overheads. + */ + u16 medium_usage; + + /* Total media delay (from 1st EDCA AIFS counter until TX Complete). */ + u32 medium_delay; + + /* Time between host xfer and tx complete */ + u32 fw_hnadling_time; + + /* The LS-byte of the last TKIP sequence number. */ + u8 lsb_seq_num; + + /* Retry count */ + u8 ack_failures; + + /* At which rate we got a ACK */ + u16 rate; + + u16 reserved; + + /* TX_* */ + u8 status; + + /* See done_1 */ + u8 done_2; +} __attribute__ ((packed)); + +void wl12xx_tx_work(struct work_struct *work); +void wl12xx_tx_complete(struct wl12xx *wl); +void wl12xx_tx_flush(struct wl12xx *wl); + +#endif diff --git a/drivers/net/wireless/wl12xx/wl1251.c b/drivers/net/wireless/wl12xx/wl1251.c new file mode 100644 index 000000000000..ce1561a41fa4 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251.c @@ -0,0 +1,709 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2008-2009 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include + +#include "wl1251.h" +#include "reg.h" +#include "spi.h" +#include "boot.h" +#include "event.h" +#include "acx.h" +#include "tx.h" +#include "rx.h" +#include "ps.h" +#include "init.h" + +static struct wl12xx_partition_set wl1251_part_table[PART_TABLE_LEN] = { + [PART_DOWN] = { + .mem = { + .start = 0x00000000, + .size = 0x00016800 + }, + .reg = { + .start = REGISTERS_BASE, + .size = REGISTERS_DOWN_SIZE + }, + }, + + [PART_WORK] = { + .mem = { + .start = 0x00028000, + .size = 0x00014000 + }, + .reg = { + .start = REGISTERS_BASE, + .size = REGISTERS_WORK_SIZE + }, + }, + + /* WL1251 doesn't use the DRPW partition, so we don't set it here */ +}; + +static enum wl12xx_acx_int_reg wl1251_acx_reg_table[ACX_REG_TABLE_LEN] = { + [ACX_REG_INTERRUPT_TRIG] = (REGISTERS_BASE + 0x0474), + [ACX_REG_INTERRUPT_TRIG_H] = (REGISTERS_BASE + 0x0478), + [ACX_REG_INTERRUPT_MASK] = (REGISTERS_BASE + 0x0494), + [ACX_REG_HINT_MASK_SET] = (REGISTERS_BASE + 0x0498), + [ACX_REG_HINT_MASK_CLR] = (REGISTERS_BASE + 0x049C), + [ACX_REG_INTERRUPT_NO_CLEAR] = (REGISTERS_BASE + 0x04B0), + [ACX_REG_INTERRUPT_CLEAR] = (REGISTERS_BASE + 0x04A4), + [ACX_REG_INTERRUPT_ACK] = (REGISTERS_BASE + 0x04A8), + [ACX_REG_SLV_SOFT_RESET] = (REGISTERS_BASE + 0x0000), + [ACX_REG_EE_START] = (REGISTERS_BASE + 0x080C), + [ACX_REG_ECPU_CONTROL] = (REGISTERS_BASE + 0x0804) +}; + +static int wl1251_upload_firmware(struct wl12xx *wl) +{ + struct wl12xx_partition_set *p_table = wl->chip.p_table; + int addr, chunk_num, partition_limit; + size_t fw_data_len; + u8 *p; + + /* whal_FwCtrl_LoadFwImageSm() */ + + wl12xx_debug(DEBUG_BOOT, "chip id before fw upload: 0x%x", + wl12xx_reg_read32(wl, CHIP_ID_B)); + + /* 10.0 check firmware length and set partition */ + fw_data_len = (wl->fw[4] << 24) | (wl->fw[5] << 16) | + (wl->fw[6] << 8) | (wl->fw[7]); + + wl12xx_debug(DEBUG_BOOT, "fw_data_len %zu chunk_size %d", fw_data_len, + CHUNK_SIZE); + + if ((fw_data_len % 4) != 0) { + wl12xx_error("firmware length not multiple of four"); + return -EIO; + } + + wl12xx_set_partition(wl, + p_table[PART_DOWN].mem.start, + p_table[PART_DOWN].mem.size, + p_table[PART_DOWN].reg.start, + p_table[PART_DOWN].reg.size); + + /* 10.1 set partition limit and chunk num */ + chunk_num = 0; + partition_limit = p_table[PART_DOWN].mem.size; + + while (chunk_num < fw_data_len / CHUNK_SIZE) { + /* 10.2 update partition, if needed */ + addr = p_table[PART_DOWN].mem.start + + (chunk_num + 2) * CHUNK_SIZE; + if (addr > partition_limit) { + addr = p_table[PART_DOWN].mem.start + + chunk_num * CHUNK_SIZE; + partition_limit = chunk_num * CHUNK_SIZE + + p_table[PART_DOWN].mem.size; + wl12xx_set_partition(wl, + addr, + p_table[PART_DOWN].mem.size, + p_table[PART_DOWN].reg.start, + p_table[PART_DOWN].reg.size); + } + + /* 10.3 upload the chunk */ + addr = p_table[PART_DOWN].mem.start + chunk_num * CHUNK_SIZE; + p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE; + wl12xx_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x", + p, addr); + wl12xx_spi_mem_write(wl, addr, p, CHUNK_SIZE); + + chunk_num++; + } + + /* 10.4 upload the last chunk */ + addr = p_table[PART_DOWN].mem.start + chunk_num * CHUNK_SIZE; + p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE; + wl12xx_debug(DEBUG_BOOT, "uploading fw last chunk (%zu B) 0x%p to 0x%x", + fw_data_len % CHUNK_SIZE, p, addr); + wl12xx_spi_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE); + + return 0; +} + +static int wl1251_upload_nvs(struct wl12xx *wl) +{ + size_t nvs_len, nvs_bytes_written, burst_len; + int nvs_start, i; + u32 dest_addr, val; + u8 *nvs_ptr, *nvs; + + nvs = wl->nvs; + if (nvs == NULL) + return -ENODEV; + + nvs_ptr = nvs; + + nvs_len = wl->nvs_len; + nvs_start = wl->fw_len; + + /* + * Layout before the actual NVS tables: + * 1 byte : burst length. + * 2 bytes: destination address. + * n bytes: data to burst copy. + * + * This is ended by a 0 length, then the NVS tables. + */ + + while (nvs_ptr[0]) { + burst_len = nvs_ptr[0]; + dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8)); + + /* We move our pointer to the data */ + nvs_ptr += 3; + + for (i = 0; i < burst_len; i++) { + val = (nvs_ptr[0] | (nvs_ptr[1] << 8) + | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); + + wl12xx_debug(DEBUG_BOOT, + "nvs burst write 0x%x: 0x%x", + dest_addr, val); + wl12xx_mem_write32(wl, dest_addr, val); + + nvs_ptr += 4; + dest_addr += 4; + } + } + + /* + * We've reached the first zero length, the first NVS table + * is 7 bytes further. + */ + nvs_ptr += 7; + nvs_len -= nvs_ptr - nvs; + nvs_len = ALIGN(nvs_len, 4); + + /* Now we must set the partition correctly */ + wl12xx_set_partition(wl, nvs_start, + wl->chip.p_table[PART_DOWN].mem.size, + wl->chip.p_table[PART_DOWN].reg.start, + wl->chip.p_table[PART_DOWN].reg.size); + + /* And finally we upload the NVS tables */ + nvs_bytes_written = 0; + while (nvs_bytes_written < nvs_len) { + val = (nvs_ptr[0] | (nvs_ptr[1] << 8) + | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); + + val = cpu_to_le32(val); + + wl12xx_debug(DEBUG_BOOT, + "nvs write table 0x%x: 0x%x", + nvs_start, val); + wl12xx_mem_write32(wl, nvs_start, val); + + nvs_ptr += 4; + nvs_bytes_written += 4; + nvs_start += 4; + } + + return 0; +} + +static int wl1251_boot(struct wl12xx *wl) +{ + int ret = 0, minor_minor_e2_ver; + u32 tmp, boot_data; + + ret = wl12xx_boot_soft_reset(wl); + if (ret < 0) + goto out; + + /* 2. start processing NVS file */ + ret = wl->chip.op_upload_nvs(wl); + if (ret < 0) + goto out; + + /* write firmware's last address (ie. it's length) to + * ACX_EEPROMLESS_IND_REG */ + wl12xx_reg_write32(wl, ACX_EEPROMLESS_IND_REG, wl->fw_len); + + /* 6. read the EEPROM parameters */ + tmp = wl12xx_reg_read32(wl, SCR_PAD2); + + /* 7. read bootdata */ + wl->boot_attr.radio_type = (tmp & 0x0000FF00) >> 8; + wl->boot_attr.major = (tmp & 0x00FF0000) >> 16; + tmp = wl12xx_reg_read32(wl, SCR_PAD3); + + /* 8. check bootdata and call restart sequence */ + wl->boot_attr.minor = (tmp & 0x00FF0000) >> 16; + minor_minor_e2_ver = (tmp & 0xFF000000) >> 24; + + wl12xx_debug(DEBUG_BOOT, "radioType 0x%x majorE2Ver 0x%x " + "minorE2Ver 0x%x minor_minor_e2_ver 0x%x", + wl->boot_attr.radio_type, wl->boot_attr.major, + wl->boot_attr.minor, minor_minor_e2_ver); + + ret = wl12xx_boot_init_seq(wl); + if (ret < 0) + goto out; + + /* 9. NVS processing done */ + boot_data = wl12xx_reg_read32(wl, ACX_REG_ECPU_CONTROL); + + wl12xx_debug(DEBUG_BOOT, "halt boot_data 0x%x", boot_data); + + /* 10. check that ECPU_CONTROL_HALT bits are set in + * pWhalBus->uBootData and start uploading firmware + */ + if ((boot_data & ECPU_CONTROL_HALT) == 0) { + wl12xx_error("boot failed, ECPU_CONTROL_HALT not set"); + ret = -EIO; + goto out; + } + + ret = wl->chip.op_upload_fw(wl); + if (ret < 0) + goto out; + + /* 10.5 start firmware */ + ret = wl12xx_boot_run_firmware(wl); + if (ret < 0) + goto out; + + /* Get and save the firmware version */ + wl12xx_acx_fw_version(wl, wl->chip.fw_ver, sizeof(wl->chip.fw_ver)); + +out: + return ret; +} + +static int wl1251_mem_cfg(struct wl12xx *wl) +{ + struct wl1251_acx_config_memory mem_conf; + int ret, i; + + wl12xx_debug(DEBUG_ACX, "wl1251 mem cfg"); + + /* memory config */ + mem_conf.mem_config.num_stations = cpu_to_le16(DEFAULT_NUM_STATIONS); + mem_conf.mem_config.rx_mem_block_num = 35; + mem_conf.mem_config.tx_min_mem_block_num = 64; + mem_conf.mem_config.num_tx_queues = MAX_TX_QUEUES; + mem_conf.mem_config.host_if_options = HOSTIF_PKT_RING; + mem_conf.mem_config.num_ssid_profiles = 1; + mem_conf.mem_config.debug_buffer_size = + cpu_to_le16(TRACE_BUFFER_MAX_SIZE); + + /* RX queue config */ + mem_conf.rx_queue_config.dma_address = 0; + mem_conf.rx_queue_config.num_descs = ACX_RX_DESC_DEF; + mem_conf.rx_queue_config.priority = DEFAULT_RXQ_PRIORITY; + mem_conf.rx_queue_config.type = DEFAULT_RXQ_TYPE; + + /* TX queue config */ + for (i = 0; i < MAX_TX_QUEUES; i++) { + mem_conf.tx_queue_config[i].num_descs = ACX_TX_DESC_DEF; + mem_conf.tx_queue_config[i].attributes = i; + } + + mem_conf.header.id = ACX_MEM_CFG; + mem_conf.header.len = sizeof(struct wl1251_acx_config_memory) - + sizeof(struct acx_header); + mem_conf.header.len -= + (MAX_TX_QUEUE_CONFIGS - mem_conf.mem_config.num_tx_queues) * + sizeof(struct wl1251_acx_tx_queue_config); + + ret = wl12xx_cmd_configure(wl, &mem_conf, + sizeof(struct wl1251_acx_config_memory)); + if (ret < 0) + wl12xx_warning("wl1251 mem config failed: %d", ret); + + return ret; +} + +static int wl1251_hw_init_mem_config(struct wl12xx *wl) +{ + int ret; + + ret = wl1251_mem_cfg(wl); + if (ret < 0) + return ret; + + wl->target_mem_map = kzalloc(sizeof(struct wl1251_acx_mem_map), + GFP_KERNEL); + if (!wl->target_mem_map) { + wl12xx_error("couldn't allocate target memory map"); + return -ENOMEM; + } + + /* we now ask for the firmware built memory map */ + ret = wl12xx_acx_mem_map(wl, wl->target_mem_map, + sizeof(struct wl1251_acx_mem_map)); + if (ret < 0) { + wl12xx_error("couldn't retrieve firmware memory map"); + kfree(wl->target_mem_map); + wl->target_mem_map = NULL; + return ret; + } + + return 0; +} + +static void wl1251_set_ecpu_ctrl(struct wl12xx *wl, u32 flag) +{ + u32 cpu_ctrl; + + /* 10.5.0 run the firmware (I) */ + cpu_ctrl = wl12xx_reg_read32(wl, ACX_REG_ECPU_CONTROL); + + /* 10.5.1 run the firmware (II) */ + cpu_ctrl &= ~flag; + wl12xx_reg_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl); +} + +static void wl1251_target_enable_interrupts(struct wl12xx *wl) +{ + /* Enable target's interrupts */ + wl->intr_mask = WL1251_ACX_INTR_RX0_DATA | + WL1251_ACX_INTR_RX1_DATA | + WL1251_ACX_INTR_TX_RESULT | + WL1251_ACX_INTR_EVENT_A | + WL1251_ACX_INTR_EVENT_B | + WL1251_ACX_INTR_INIT_COMPLETE; + wl12xx_boot_target_enable_interrupts(wl); +} + +static void wl1251_irq_work(struct work_struct *work) +{ + u32 intr; + struct wl12xx *wl = + container_of(work, struct wl12xx, irq_work); + + mutex_lock(&wl->mutex); + + wl12xx_debug(DEBUG_IRQ, "IRQ work"); + + if (wl->state == WL12XX_STATE_OFF) + goto out; + + wl12xx_ps_elp_wakeup(wl); + + wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1251_ACX_INTR_ALL); + + intr = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR); + wl12xx_debug(DEBUG_IRQ, "intr: 0x%x", intr); + + if (wl->data_path) { + wl12xx_spi_mem_read(wl, wl->data_path->rx_control_addr, + &wl->rx_counter, sizeof(u32)); + + /* We handle a frmware bug here */ + switch ((wl->rx_counter - wl->rx_handled) & 0xf) { + case 0: + wl12xx_debug(DEBUG_IRQ, "RX: FW and host in sync"); + intr &= ~WL1251_ACX_INTR_RX0_DATA; + intr &= ~WL1251_ACX_INTR_RX1_DATA; + break; + case 1: + wl12xx_debug(DEBUG_IRQ, "RX: FW +1"); + intr |= WL1251_ACX_INTR_RX0_DATA; + intr &= ~WL1251_ACX_INTR_RX1_DATA; + break; + case 2: + wl12xx_debug(DEBUG_IRQ, "RX: FW +2"); + intr |= WL1251_ACX_INTR_RX0_DATA; + intr |= WL1251_ACX_INTR_RX1_DATA; + break; + default: + wl12xx_warning("RX: FW and host out of sync: %d", + wl->rx_counter - wl->rx_handled); + break; + } + + wl->rx_handled = wl->rx_counter; + + + wl12xx_debug(DEBUG_IRQ, "RX counter: %d", wl->rx_counter); + } + + intr &= wl->intr_mask; + + if (intr == 0) { + wl12xx_debug(DEBUG_IRQ, "INTR is 0"); + wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK, + ~(wl->intr_mask)); + + goto out_sleep; + } + + if (intr & WL1251_ACX_INTR_RX0_DATA) { + wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX0_DATA"); + wl12xx_rx(wl); + } + + if (intr & WL1251_ACX_INTR_RX1_DATA) { + wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX1_DATA"); + wl12xx_rx(wl); + } + + if (intr & WL1251_ACX_INTR_TX_RESULT) { + wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_TX_RESULT"); + wl12xx_tx_complete(wl); + } + + if (intr & (WL1251_ACX_INTR_EVENT_A | WL1251_ACX_INTR_EVENT_B)) { + wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT (0x%x)", intr); + if (intr & WL1251_ACX_INTR_EVENT_A) + wl12xx_event_handle(wl, 0); + else + wl12xx_event_handle(wl, 1); + } + + if (intr & WL1251_ACX_INTR_INIT_COMPLETE) + wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_INIT_COMPLETE"); + + wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); + +out_sleep: + wl12xx_ps_elp_sleep(wl); +out: + mutex_unlock(&wl->mutex); +} + +static int wl1251_hw_init_txq_fill(u8 qid, + struct acx_tx_queue_qos_config *config, + u32 num_blocks) +{ + config->qid = qid; + + switch (qid) { + case QOS_AC_BE: + config->high_threshold = + (QOS_TX_HIGH_BE_DEF * num_blocks) / 100; + config->low_threshold = + (QOS_TX_LOW_BE_DEF * num_blocks) / 100; + break; + case QOS_AC_BK: + config->high_threshold = + (QOS_TX_HIGH_BK_DEF * num_blocks) / 100; + config->low_threshold = + (QOS_TX_LOW_BK_DEF * num_blocks) / 100; + break; + case QOS_AC_VI: + config->high_threshold = + (QOS_TX_HIGH_VI_DEF * num_blocks) / 100; + config->low_threshold = + (QOS_TX_LOW_VI_DEF * num_blocks) / 100; + break; + case QOS_AC_VO: + config->high_threshold = + (QOS_TX_HIGH_VO_DEF * num_blocks) / 100; + config->low_threshold = + (QOS_TX_LOW_VO_DEF * num_blocks) / 100; + break; + default: + wl12xx_error("Invalid TX queue id: %d", qid); + return -EINVAL; + } + + return 0; +} + +static int wl1251_hw_init_tx_queue_config(struct wl12xx *wl) +{ + struct acx_tx_queue_qos_config config; + struct wl1251_acx_mem_map *wl_mem_map = wl->target_mem_map; + int ret, i; + + wl12xx_debug(DEBUG_ACX, "acx tx queue config"); + + config.header.id = ACX_TX_QUEUE_CFG; + config.header.len = sizeof(struct acx_tx_queue_qos_config) - + sizeof(struct acx_header); + + for (i = 0; i < MAX_NUM_OF_AC; i++) { + ret = wl1251_hw_init_txq_fill(i, &config, + wl_mem_map->num_tx_mem_blocks); + if (ret < 0) + return ret; + + ret = wl12xx_cmd_configure(wl, &config, sizeof(config)); + if (ret < 0) + return ret; + } + + return 0; +} + +static int wl1251_hw_init_data_path_config(struct wl12xx *wl) +{ + int ret; + + /* asking for the data path parameters */ + wl->data_path = kzalloc(sizeof(struct acx_data_path_params_resp), + GFP_KERNEL); + if (!wl->data_path) { + wl12xx_error("Couldnt allocate data path parameters"); + return -ENOMEM; + } + + ret = wl12xx_acx_data_path_params(wl, wl->data_path); + if (ret < 0) { + kfree(wl->data_path); + wl->data_path = NULL; + return ret; + } + + return 0; +} + +static int wl1251_hw_init(struct wl12xx *wl) +{ + struct wl1251_acx_mem_map *wl_mem_map; + int ret; + + ret = wl12xx_hw_init_hwenc_config(wl); + if (ret < 0) + return ret; + + /* Template settings */ + ret = wl12xx_hw_init_templates_config(wl); + if (ret < 0) + return ret; + + /* Default memory configuration */ + ret = wl1251_hw_init_mem_config(wl); + if (ret < 0) + return ret; + + /* Default data path configuration */ + ret = wl1251_hw_init_data_path_config(wl); + if (ret < 0) + goto out_free_memmap; + + /* RX config */ + ret = wl12xx_hw_init_rx_config(wl, + RX_CFG_PROMISCUOUS | RX_CFG_TSF, + RX_FILTER_OPTION_DEF); + /* RX_CONFIG_OPTION_ANY_DST_ANY_BSS, + RX_FILTER_OPTION_FILTER_ALL); */ + if (ret < 0) + goto out_free_data_path; + + /* TX queues config */ + ret = wl1251_hw_init_tx_queue_config(wl); + if (ret < 0) + goto out_free_data_path; + + /* PHY layer config */ + ret = wl12xx_hw_init_phy_config(wl); + if (ret < 0) + goto out_free_data_path; + + /* Beacon filtering */ + ret = wl12xx_hw_init_beacon_filter(wl); + if (ret < 0) + goto out_free_data_path; + + /* Bluetooth WLAN coexistence */ + ret = wl12xx_hw_init_pta(wl); + if (ret < 0) + goto out_free_data_path; + + /* Energy detection */ + ret = wl12xx_hw_init_energy_detection(wl); + if (ret < 0) + goto out_free_data_path; + + /* Beacons and boradcast settings */ + ret = wl12xx_hw_init_beacon_broadcast(wl); + if (ret < 0) + goto out_free_data_path; + + /* Enable data path */ + ret = wl12xx_cmd_data_path(wl, wl->channel, 1); + if (ret < 0) + goto out_free_data_path; + + /* Default power state */ + ret = wl12xx_hw_init_power_auth(wl); + if (ret < 0) + goto out_free_data_path; + + wl_mem_map = wl->target_mem_map; + wl12xx_info("%d tx blocks at 0x%x, %d rx blocks at 0x%x", + wl_mem_map->num_tx_mem_blocks, + wl->data_path->tx_control_addr, + wl_mem_map->num_rx_mem_blocks, + wl->data_path->rx_control_addr); + + return 0; + + out_free_data_path: + kfree(wl->data_path); + + out_free_memmap: + kfree(wl->target_mem_map); + + return ret; +} + +static int wl1251_plt_init(struct wl12xx *wl) +{ + int ret; + + ret = wl1251_hw_init_mem_config(wl); + if (ret < 0) + return ret; + + ret = wl12xx_cmd_data_path(wl, wl->channel, 1); + if (ret < 0) + return ret; + + return 0; +} + +void wl1251_setup(struct wl12xx *wl) +{ + /* FIXME: Is it better to use strncpy here or is this ok? */ + wl->chip.fw_filename = WL1251_FW_NAME; + wl->chip.nvs_filename = WL1251_NVS_NAME; + + /* Now we know what chip we're using, so adjust the power on sleep + * time accordingly */ + wl->chip.power_on_sleep = WL1251_POWER_ON_SLEEP; + + wl->chip.intr_cmd_complete = WL1251_ACX_INTR_CMD_COMPLETE; + wl->chip.intr_init_complete = WL1251_ACX_INTR_INIT_COMPLETE; + + wl->chip.op_upload_nvs = wl1251_upload_nvs; + wl->chip.op_upload_fw = wl1251_upload_firmware; + wl->chip.op_boot = wl1251_boot; + wl->chip.op_set_ecpu_ctrl = wl1251_set_ecpu_ctrl; + wl->chip.op_target_enable_interrupts = wl1251_target_enable_interrupts; + wl->chip.op_hw_init = wl1251_hw_init; + wl->chip.op_plt_init = wl1251_plt_init; + + wl->chip.p_table = wl1251_part_table; + wl->chip.acx_reg_table = wl1251_acx_reg_table; + + INIT_WORK(&wl->irq_work, wl1251_irq_work); +} diff --git a/drivers/net/wireless/wl12xx/wl1251.h b/drivers/net/wireless/wl12xx/wl1251.h new file mode 100644 index 000000000000..1f4a44330394 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1251.h @@ -0,0 +1,165 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2008 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL1251_H__ +#define __WL1251_H__ + +#include + +#include "wl12xx.h" +#include "acx.h" + +#define WL1251_FW_NAME "wl1251-fw.bin" +#define WL1251_NVS_NAME "wl1251-nvs.bin" + +#define WL1251_POWER_ON_SLEEP 10 /* in miliseconds */ + +void wl1251_setup(struct wl12xx *wl); + + +struct wl1251_acx_memory { + __le16 num_stations; /* number of STAs to be supported. */ + u16 reserved_1; + + /* + * Nmber of memory buffers for the RX mem pool. + * The actual number may be less if there are + * not enough blocks left for the minimum num + * of TX ones. + */ + u8 rx_mem_block_num; + u8 reserved_2; + u8 num_tx_queues; /* From 1 to 16 */ + u8 host_if_options; /* HOST_IF* */ + u8 tx_min_mem_block_num; + u8 num_ssid_profiles; + __le16 debug_buffer_size; +} __attribute__ ((packed)); + + +#define ACX_RX_DESC_MIN 1 +#define ACX_RX_DESC_MAX 127 +#define ACX_RX_DESC_DEF 32 +struct wl1251_acx_rx_queue_config { + u8 num_descs; + u8 pad; + u8 type; + u8 priority; + __le32 dma_address; +} __attribute__ ((packed)); + +#define ACX_TX_DESC_MIN 1 +#define ACX_TX_DESC_MAX 127 +#define ACX_TX_DESC_DEF 16 +struct wl1251_acx_tx_queue_config { + u8 num_descs; + u8 pad[2]; + u8 attributes; +} __attribute__ ((packed)); + +#define MAX_TX_QUEUE_CONFIGS 5 +#define MAX_TX_QUEUES 4 +struct wl1251_acx_config_memory { + struct acx_header header; + + struct wl1251_acx_memory mem_config; + struct wl1251_acx_rx_queue_config rx_queue_config; + struct wl1251_acx_tx_queue_config tx_queue_config[MAX_TX_QUEUE_CONFIGS]; +} __attribute__ ((packed)); + +struct wl1251_acx_mem_map { + struct acx_header header; + + void *code_start; + void *code_end; + + void *wep_defkey_start; + void *wep_defkey_end; + + void *sta_table_start; + void *sta_table_end; + + void *packet_template_start; + void *packet_template_end; + + void *queue_memory_start; + void *queue_memory_end; + + void *packet_memory_pool_start; + void *packet_memory_pool_end; + + void *debug_buffer1_start; + void *debug_buffer1_end; + + void *debug_buffer2_start; + void *debug_buffer2_end; + + /* Number of blocks FW allocated for TX packets */ + u32 num_tx_mem_blocks; + + /* Number of blocks FW allocated for RX packets */ + u32 num_rx_mem_blocks; +} __attribute__ ((packed)); + +/************************************************************************* + + Host Interrupt Register (WiLink -> Host) + +**************************************************************************/ + +/* RX packet is ready in Xfer buffer #0 */ +#define WL1251_ACX_INTR_RX0_DATA BIT(0) + +/* TX result(s) are in the TX complete buffer */ +#define WL1251_ACX_INTR_TX_RESULT BIT(1) + +/* OBSOLETE */ +#define WL1251_ACX_INTR_TX_XFR BIT(2) + +/* RX packet is ready in Xfer buffer #1 */ +#define WL1251_ACX_INTR_RX1_DATA BIT(3) + +/* Event was entered to Event MBOX #A */ +#define WL1251_ACX_INTR_EVENT_A BIT(4) + +/* Event was entered to Event MBOX #B */ +#define WL1251_ACX_INTR_EVENT_B BIT(5) + +/* OBSOLETE */ +#define WL1251_ACX_INTR_WAKE_ON_HOST BIT(6) + +/* Trace meassge on MBOX #A */ +#define WL1251_ACX_INTR_TRACE_A BIT(7) + +/* Trace meassge on MBOX #B */ +#define WL1251_ACX_INTR_TRACE_B BIT(8) + +/* Command processing completion */ +#define WL1251_ACX_INTR_CMD_COMPLETE BIT(9) + +/* Init sequence is done */ +#define WL1251_ACX_INTR_INIT_COMPLETE BIT(14) + +#define WL1251_ACX_INTR_ALL 0xFFFFFFFF + +#endif diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h new file mode 100644 index 000000000000..48641437414b --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -0,0 +1,409 @@ +/* + * This file is part of wl12xx + * + * Copyright (c) 1998-2007 Texas Instruments Incorporated + * Copyright (C) 2008-2009 Nokia Corporation + * + * Contact: Kalle Valo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL12XX_H__ +#define __WL12XX_H__ + +#include +#include +#include +#include + +#define DRIVER_NAME "wl12xx" +#define DRIVER_PREFIX DRIVER_NAME ": " + +enum { + DEBUG_NONE = 0, + DEBUG_IRQ = BIT(0), + DEBUG_SPI = BIT(1), + DEBUG_BOOT = BIT(2), + DEBUG_MAILBOX = BIT(3), + DEBUG_NETLINK = BIT(4), + DEBUG_EVENT = BIT(5), + DEBUG_TX = BIT(6), + DEBUG_RX = BIT(7), + DEBUG_SCAN = BIT(8), + DEBUG_CRYPT = BIT(9), + DEBUG_PSM = BIT(10), + DEBUG_MAC80211 = BIT(11), + DEBUG_CMD = BIT(12), + DEBUG_ACX = BIT(13), + DEBUG_ALL = ~0, +}; + +#define DEBUG_LEVEL (DEBUG_NONE) + +#define DEBUG_DUMP_LIMIT 1024 + +#define wl12xx_error(fmt, arg...) \ + printk(KERN_ERR DRIVER_PREFIX "ERROR " fmt "\n", ##arg) + +#define wl12xx_warning(fmt, arg...) \ + printk(KERN_WARNING DRIVER_PREFIX "WARNING " fmt "\n", ##arg) + +#define wl12xx_notice(fmt, arg...) \ + printk(KERN_INFO DRIVER_PREFIX fmt "\n", ##arg) + +#define wl12xx_info(fmt, arg...) \ + printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg) + +#define wl12xx_debug(level, fmt, arg...) \ + do { \ + if (level & DEBUG_LEVEL) \ + printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg); \ + } while (0) + +#define wl12xx_dump(level, prefix, buf, len) \ + do { \ + if (level & DEBUG_LEVEL) \ + print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ + DUMP_PREFIX_OFFSET, 16, 1, \ + buf, \ + min_t(size_t, len, DEBUG_DUMP_LIMIT), \ + 0); \ + } while (0) + +#define wl12xx_dump_ascii(level, prefix, buf, len) \ + do { \ + if (level & DEBUG_LEVEL) \ + print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ + DUMP_PREFIX_OFFSET, 16, 1, \ + buf, \ + min_t(size_t, len, DEBUG_DUMP_LIMIT), \ + true); \ + } while (0) + +#define WL12XX_DEFAULT_RX_CONFIG (CFG_UNI_FILTER_EN | \ + CFG_BSSID_FILTER_EN) + +#define WL12XX_DEFAULT_RX_FILTER (CFG_RX_PRSP_EN | \ + CFG_RX_MGMT_EN | \ + CFG_RX_DATA_EN | \ + CFG_RX_CTL_EN | \ + CFG_RX_BCN_EN | \ + CFG_RX_AUTH_EN | \ + CFG_RX_ASSOC_EN) + + +struct boot_attr { + u32 radio_type; + u8 mac_clock; + u8 arm_clock; + int firmware_debug; + u32 minor; + u32 major; + u32 bugfix; +}; + +enum wl12xx_state { + WL12XX_STATE_OFF, + WL12XX_STATE_ON, + WL12XX_STATE_PLT, +}; + +enum wl12xx_partition_type { + PART_DOWN, + PART_WORK, + PART_DRPW, + + PART_TABLE_LEN +}; + +struct wl12xx_partition { + u32 size; + u32 start; +}; + +struct wl12xx_partition_set { + struct wl12xx_partition mem; + struct wl12xx_partition reg; +}; + +struct wl12xx; + +/* FIXME: I'm not sure about this structure name */ +struct wl12xx_chip { + u32 id; + + const char *fw_filename; + const char *nvs_filename; + + char fw_ver[21]; + + unsigned int power_on_sleep; + int intr_cmd_complete; + int intr_init_complete; + + int (*op_upload_fw)(struct wl12xx *wl); + int (*op_upload_nvs)(struct wl12xx *wl); + int (*op_boot)(struct wl12xx *wl); + void (*op_set_ecpu_ctrl)(struct wl12xx *wl, u32 flag); + void (*op_target_enable_interrupts)(struct wl12xx *wl); + int (*op_hw_init)(struct wl12xx *wl); + int (*op_plt_init)(struct wl12xx *wl); + + struct wl12xx_partition_set *p_table; + enum wl12xx_acx_int_reg *acx_reg_table; +}; + +struct wl12xx_stats { + struct acx_statistics *fw_stats; + unsigned long fw_stats_update; + + unsigned int retry_count; + unsigned int excessive_retries; +}; + +struct wl12xx_debugfs { + struct dentry *rootdir; + struct dentry *fw_statistics; + + struct dentry *tx_internal_desc_overflow; + + struct dentry *rx_out_of_mem; + struct dentry *rx_hdr_overflow; + struct dentry *rx_hw_stuck; + struct dentry *rx_dropped; + struct dentry *rx_fcs_err; + struct dentry *rx_xfr_hint_trig; + struct dentry *rx_path_reset; + struct dentry *rx_reset_counter; + + struct dentry *dma_rx_requested; + struct dentry *dma_rx_errors; + struct dentry *dma_tx_requested; + struct dentry *dma_tx_errors; + + struct dentry *isr_cmd_cmplt; + struct dentry *isr_fiqs; + struct dentry *isr_rx_headers; + struct dentry *isr_rx_mem_overflow; + struct dentry *isr_rx_rdys; + struct dentry *isr_irqs; + struct dentry *isr_tx_procs; + struct dentry *isr_decrypt_done; + struct dentry *isr_dma0_done; + struct dentry *isr_dma1_done; + struct dentry *isr_tx_exch_complete; + struct dentry *isr_commands; + struct dentry *isr_rx_procs; + struct dentry *isr_hw_pm_mode_changes; + struct dentry *isr_host_acknowledges; + struct dentry *isr_pci_pm; + struct dentry *isr_wakeups; + struct dentry *isr_low_rssi; + + struct dentry *wep_addr_key_count; + struct dentry *wep_default_key_count; + /* skipping wep.reserved */ + struct dentry *wep_key_not_found; + struct dentry *wep_decrypt_fail; + struct dentry *wep_packets; + struct dentry *wep_interrupt; + + struct dentry *pwr_ps_enter; + struct dentry *pwr_elp_enter; + struct dentry *pwr_missing_bcns; + struct dentry *pwr_wake_on_host; + struct dentry *pwr_wake_on_timer_exp; + struct dentry *pwr_tx_with_ps; + struct dentry *pwr_tx_without_ps; + struct dentry *pwr_rcvd_beacons; + struct dentry *pwr_power_save_off; + struct dentry *pwr_enable_ps; + struct dentry *pwr_disable_ps; + struct dentry *pwr_fix_tsf_ps; + /* skipping cont_miss_bcns_spread for now */ + struct dentry *pwr_rcvd_awake_beacons; + + struct dentry *mic_rx_pkts; + struct dentry *mic_calc_failure; + + struct dentry *aes_encrypt_fail; + struct dentry *aes_decrypt_fail; + struct dentry *aes_encrypt_packets; + struct dentry *aes_decrypt_packets; + struct dentry *aes_encrypt_interrupt; + struct dentry *aes_decrypt_interrupt; + + struct dentry *event_heart_beat; + struct dentry *event_calibration; + struct dentry *event_rx_mismatch; + struct dentry *event_rx_mem_empty; + struct dentry *event_rx_pool; + struct dentry *event_oom_late; + struct dentry *event_phy_transmit_error; + struct dentry *event_tx_stuck; + + struct dentry *ps_pspoll_timeouts; + struct dentry *ps_upsd_timeouts; + struct dentry *ps_upsd_max_sptime; + struct dentry *ps_upsd_max_apturn; + struct dentry *ps_pspoll_max_apturn; + struct dentry *ps_pspoll_utilization; + struct dentry *ps_upsd_utilization; + + struct dentry *rxpipe_rx_prep_beacon_drop; + struct dentry *rxpipe_descr_host_int_trig_rx_data; + struct dentry *rxpipe_beacon_buffer_thres_host_int_trig_rx_data; + struct dentry *rxpipe_missed_beacon_host_int_trig_rx_data; + struct dentry *rxpipe_tx_xfr_host_int_trig_rx_data; + + struct dentry *tx_queue_len; + + struct dentry *retry_count; + struct dentry *excessive_retries; +}; + +struct wl12xx { + struct ieee80211_hw *hw; + bool mac80211_registered; + + struct spi_device *spi; + + void (*set_power)(bool enable); + int irq; + + enum wl12xx_state state; + struct mutex mutex; + + int physical_mem_addr; + int physical_reg_addr; + int virtual_mem_addr; + int virtual_reg_addr; + + struct wl12xx_chip chip; + + int cmd_box_addr; + int event_box_addr; + struct boot_attr boot_attr; + + u8 *fw; + size_t fw_len; + u8 *nvs; + size_t nvs_len; + + u8 bssid[ETH_ALEN]; + u8 mac_addr[ETH_ALEN]; + u8 bss_type; + u8 listen_int; + int channel; + + void *target_mem_map; + struct acx_data_path_params_resp *data_path; + + /* Number of TX packets transferred to the FW, modulo 16 */ + u32 data_in_count; + + /* Frames scheduled for transmission, not handled yet */ + struct sk_buff_head tx_queue; + bool tx_queue_stopped; + + struct work_struct tx_work; + struct work_struct filter_work; + + /* Pending TX frames */ + struct sk_buff *tx_frames[16]; + + /* + * Index pointing to the next TX complete entry + * in the cyclic XT complete array we get from + * the FW. + */ + u32 next_tx_complete; + + /* FW Rx counter */ + u32 rx_counter; + + /* Rx frames handled */ + u32 rx_handled; + + /* Current double buffer */ + u32 rx_current_buffer; + u32 rx_last_id; + + /* The target interrupt mask */ + u32 intr_mask; + struct work_struct irq_work; + + /* The mbox event mask */ + u32 event_mask; + + /* Mailbox pointers */ + u32 mbox_ptr[2]; + + /* Are we currently scanning */ + bool scanning; + + /* Our association ID */ + u16 aid; + + /* Default key (for WEP) */ + u32 default_key; + + unsigned int tx_mgmt_frm_rate; + unsigned int tx_mgmt_frm_mod; + + unsigned int rx_config; + unsigned int rx_filter; + + /* is firmware in elp mode */ + bool elp; + + /* we can be in psm, but not in elp, we have to differentiate */ + bool psm; + + /* PSM mode requested */ + bool psm_requested; + + /* in dBm */ + int power_level; + + struct wl12xx_stats stats; + struct wl12xx_debugfs debugfs; +}; + +int wl12xx_plt_start(struct wl12xx *wl); +int wl12xx_plt_stop(struct wl12xx *wl); + +#define DEFAULT_HW_GEN_MODULATION_TYPE CCK_LONG /* Long Preamble */ +#define DEFAULT_HW_GEN_TX_RATE RATE_2MBPS +#define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */ + +#define WL12XX_DEFAULT_POWER_LEVEL 20 + +#define WL12XX_TX_QUEUE_MAX_LENGTH 20 + +/* Different chips need different sleep times after power on. WL1271 needs + * 200ms, WL1251 needs only 10ms. By default we use 200ms, but as soon as we + * know the chip ID, we change the sleep value in the wl12xx chip structure, + * so in subsequent power ons, we don't waste more time then needed. */ +#define WL12XX_DEFAULT_POWER_ON_SLEEP 200 + +#define CHIP_ID_1251_PG10 (0x7010101) +#define CHIP_ID_1251_PG11 (0x7020101) +#define CHIP_ID_1251_PG12 (0x7030101) +#define CHIP_ID_1271_PG10 (0x4030101) + +#endif diff --git a/drivers/net/wireless/wl12xx/wl12xx_80211.h b/drivers/net/wireless/wl12xx/wl12xx_80211.h new file mode 100644 index 000000000000..657c2dbcb7d3 --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl12xx_80211.h @@ -0,0 +1,156 @@ +#ifndef __WL12XX_80211_H__ +#define __WL12XX_80211_H__ + +#include /* ETH_ALEN */ + +/* RATES */ +#define IEEE80211_CCK_RATE_1MB 0x02 +#define IEEE80211_CCK_RATE_2MB 0x04 +#define IEEE80211_CCK_RATE_5MB 0x0B +#define IEEE80211_CCK_RATE_11MB 0x16 +#define IEEE80211_OFDM_RATE_6MB 0x0C +#define IEEE80211_OFDM_RATE_9MB 0x12 +#define IEEE80211_OFDM_RATE_12MB 0x18 +#define IEEE80211_OFDM_RATE_18MB 0x24 +#define IEEE80211_OFDM_RATE_24MB 0x30 +#define IEEE80211_OFDM_RATE_36MB 0x48 +#define IEEE80211_OFDM_RATE_48MB 0x60 +#define IEEE80211_OFDM_RATE_54MB 0x6C +#define IEEE80211_BASIC_RATE_MASK 0x80 + +#define IEEE80211_CCK_RATE_1MB_MASK (1<<0) +#define IEEE80211_CCK_RATE_2MB_MASK (1<<1) +#define IEEE80211_CCK_RATE_5MB_MASK (1<<2) +#define IEEE80211_CCK_RATE_11MB_MASK (1<<3) +#define IEEE80211_OFDM_RATE_6MB_MASK (1<<4) +#define IEEE80211_OFDM_RATE_9MB_MASK (1<<5) +#define IEEE80211_OFDM_RATE_12MB_MASK (1<<6) +#define IEEE80211_OFDM_RATE_18MB_MASK (1<<7) +#define IEEE80211_OFDM_RATE_24MB_MASK (1<<8) +#define IEEE80211_OFDM_RATE_36MB_MASK (1<<9) +#define IEEE80211_OFDM_RATE_48MB_MASK (1<<10) +#define IEEE80211_OFDM_RATE_54MB_MASK (1<<11) + +#define IEEE80211_CCK_RATES_MASK 0x0000000F +#define IEEE80211_CCK_BASIC_RATES_MASK (IEEE80211_CCK_RATE_1MB_MASK | \ + IEEE80211_CCK_RATE_2MB_MASK) +#define IEEE80211_CCK_DEFAULT_RATES_MASK (IEEE80211_CCK_BASIC_RATES_MASK | \ + IEEE80211_CCK_RATE_5MB_MASK | \ + IEEE80211_CCK_RATE_11MB_MASK) + +#define IEEE80211_OFDM_RATES_MASK 0x00000FF0 +#define IEEE80211_OFDM_BASIC_RATES_MASK (IEEE80211_OFDM_RATE_6MB_MASK | \ + IEEE80211_OFDM_RATE_12MB_MASK | \ + IEEE80211_OFDM_RATE_24MB_MASK) +#define IEEE80211_OFDM_DEFAULT_RATES_MASK (IEEE80211_OFDM_BASIC_RATES_MASK | \ + IEEE80211_OFDM_RATE_9MB_MASK | \ + IEEE80211_OFDM_RATE_18MB_MASK | \ + IEEE80211_OFDM_RATE_36MB_MASK | \ + IEEE80211_OFDM_RATE_48MB_MASK | \ + IEEE80211_OFDM_RATE_54MB_MASK) +#define IEEE80211_DEFAULT_RATES_MASK (IEEE80211_OFDM_DEFAULT_RATES_MASK | \ + IEEE80211_CCK_DEFAULT_RATES_MASK) + + +/* This really should be 8, but not for our firmware */ +#define MAX_SUPPORTED_RATES 32 +#define COUNTRY_STRING_LEN 3 +#define MAX_COUNTRY_TRIPLETS 32 + +/* Headers */ +struct ieee80211_header { + __le16 frame_ctl; + __le16 duration_id; + u8 da[ETH_ALEN]; + u8 sa[ETH_ALEN]; + u8 bssid[ETH_ALEN]; + __le16 seq_ctl; + u8 payload[0]; +} __attribute__ ((packed)); + +struct wl12xx_ie_header { + u8 id; + u8 len; +} __attribute__ ((packed)); + +/* IEs */ + +struct wl12xx_ie_ssid { + struct wl12xx_ie_header header; + char ssid[IW_ESSID_MAX_SIZE]; +} __attribute__ ((packed)); + +struct wl12xx_ie_rates { + struct wl12xx_ie_header header; + u8 rates[MAX_SUPPORTED_RATES]; +} __attribute__ ((packed)); + +struct wl12xx_ie_ds_params { + struct wl12xx_ie_header header; + u8 channel; +} __attribute__ ((packed)); + +struct country_triplet { + u8 channel; + u8 num_channels; + u8 max_tx_power; +} __attribute__ ((packed)); + +struct wl12xx_ie_country { + struct wl12xx_ie_header header; + u8 country_string[COUNTRY_STRING_LEN]; + struct country_triplet triplets[MAX_COUNTRY_TRIPLETS]; +} __attribute__ ((packed)); + + +/* Templates */ + +struct wl12xx_beacon_template { + struct ieee80211_header header; + __le32 time_stamp[2]; + __le16 beacon_interval; + __le16 capability; + struct wl12xx_ie_ssid ssid; + struct wl12xx_ie_rates rates; + struct wl12xx_ie_rates ext_rates; + struct wl12xx_ie_ds_params ds_params; + struct wl12xx_ie_country country; +} __attribute__ ((packed)); + +struct wl12xx_null_data_template { + struct ieee80211_header header; +} __attribute__ ((packed)); + +struct wl12xx_ps_poll_template { + u16 fc; + u16 aid; + u8 bssid[ETH_ALEN]; + u8 ta[ETH_ALEN]; +} __attribute__ ((packed)); + +struct wl12xx_qos_null_data_template { + struct ieee80211_header header; + __le16 qos_ctl; +} __attribute__ ((packed)); + +struct wl12xx_probe_req_template { + struct ieee80211_header header; + struct wl12xx_ie_ssid ssid; + struct wl12xx_ie_rates rates; + struct wl12xx_ie_rates ext_rates; +} __attribute__ ((packed)); + + +struct wl12xx_probe_resp_template { + struct ieee80211_header header; + __le32 time_stamp[2]; + __le16 beacon_interval; + __le16 capability; + struct wl12xx_ie_ssid ssid; + struct wl12xx_ie_rates rates; + struct wl12xx_ie_rates ext_rates; + struct wl12xx_ie_ds_params ds_params; + struct wl12xx_ie_country country; +} __attribute__ ((packed)); + +#endif diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index 1f64d6033ab5..e3e96bb2c246 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -1348,6 +1348,7 @@ static int wl3501_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) if (rc) { ++dev->stats.tx_dropped; netif_stop_queue(dev); + rc = NETDEV_TX_OK; } else { ++dev->stats.tx_packets; dev->stats.tx_bytes += skb->len; diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c index 5fabd9c0f07a..4430b8d92e21 100644 --- a/drivers/net/wireless/zd1201.c +++ b/drivers/net/wireless/zd1201.c @@ -819,11 +819,11 @@ static int zd1201_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) if (err) { dev->stats.tx_errors++; netif_start_queue(dev); - return err; + } else { + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; + dev->trans_start = jiffies; } - dev->stats.tx_packets++; - dev->stats.tx_bytes += skb->len; - dev->trans_start = jiffies; kfree_skb(skb); return 0; diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index c3a51266de20..40b07b988224 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -420,9 +420,9 @@ static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs, if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) cs->control |= ZD_CS_NEED_RANDOM_BACKOFF; - /* Multicast */ - if (is_multicast_ether_addr(header->addr1)) - cs->control |= ZD_CS_MULTICAST; + /* No ACK expected (multicast, etc.) */ + if (info->flags & IEEE80211_TX_CTL_NO_ACK) + cs->control |= ZD_CS_NO_ACK; /* PS-POLL */ if (ieee80211_is_pspoll(header->frame_control)) @@ -755,52 +755,6 @@ static int zd_op_config(struct ieee80211_hw *hw, u32 changed) return zd_chip_set_channel(&mac->chip, conf->channel->hw_value); } -static int zd_op_config_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_if_conf *conf) -{ - struct zd_mac *mac = zd_hw_mac(hw); - int associated; - int r; - - if (mac->type == NL80211_IFTYPE_MESH_POINT || - mac->type == NL80211_IFTYPE_ADHOC) { - associated = true; - if (conf->changed & IEEE80211_IFCC_BEACON) { - struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); - - if (!beacon) - return -ENOMEM; - r = zd_mac_config_beacon(hw, beacon); - kfree_skb(beacon); - - if (r < 0) - return r; - } - - if (conf->changed & IEEE80211_IFCC_BEACON_ENABLED) { - u32 interval; - - if (conf->enable_beacon) - interval = BCN_MODE_IBSS | hw->conf.beacon_int; - else - interval = 0; - - r = zd_set_beacon_interval(&mac->chip, interval); - if (r < 0) - return r; - } - } else - associated = is_valid_ether_addr(conf->bssid); - - spin_lock_irq(&mac->lock); - mac->associated = associated; - spin_unlock_irq(&mac->lock); - - /* TODO: do hardware bssid filtering */ - return 0; -} - static void zd_process_intr(struct work_struct *work) { u16 int_status; @@ -923,9 +877,42 @@ static void zd_op_bss_info_changed(struct ieee80211_hw *hw, { struct zd_mac *mac = zd_hw_mac(hw); unsigned long flags; + int associated; dev_dbg_f(zd_mac_dev(mac), "changes: %x\n", changes); + if (mac->type == NL80211_IFTYPE_MESH_POINT || + mac->type == NL80211_IFTYPE_ADHOC) { + associated = true; + if (changes & BSS_CHANGED_BEACON) { + struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); + + if (beacon) { + zd_mac_config_beacon(hw, beacon); + kfree_skb(beacon); + } + } + + if (changes & BSS_CHANGED_BEACON_ENABLED) { + u32 interval; + + if (bss_conf->enable_beacon) + interval = BCN_MODE_IBSS | + bss_conf->beacon_int; + else + interval = 0; + + zd_set_beacon_interval(&mac->chip, interval); + } + } else + associated = is_valid_ether_addr(bss_conf->bssid); + + spin_lock_irq(&mac->lock); + mac->associated = associated; + spin_unlock_irq(&mac->lock); + + /* TODO: do hardware bssid filtering */ + if (changes & BSS_CHANGED_ERP_PREAMBLE) { spin_lock_irqsave(&mac->lock, flags); mac->short_preamble = bss_conf->use_short_preamble; @@ -952,7 +939,6 @@ static const struct ieee80211_ops zd_ops = { .add_interface = zd_op_add_interface, .remove_interface = zd_op_remove_interface, .config = zd_op_config, - .config_interface = zd_op_config_interface, .configure_filter = zd_op_configure_filter, .bss_info_changed = zd_op_bss_info_changed, .get_tsf = zd_op_get_tsf, diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h index 4c05d3ee4c37..7c2759118d13 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.h +++ b/drivers/net/wireless/zd1211rw/zd_mac.h @@ -87,7 +87,7 @@ struct zd_ctrlset { /* zd_ctrlset control field */ #define ZD_CS_NEED_RANDOM_BACKOFF 0x01 -#define ZD_CS_MULTICAST 0x02 +#define ZD_CS_NO_ACK 0x02 #define ZD_CS_FRAME_TYPE_MASK 0x0c #define ZD_CS_DATA_FRAME 0x00 diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index f0e5e943f6e3..14a19baff214 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -67,6 +67,7 @@ static struct usb_device_id usb_ids[] = { { USB_DEVICE(0x079b, 0x0062), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x1582, 0x6003), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x050d, 0x705c), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x083a, 0xe503), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x083a, 0xe506), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x083a, 0x4505), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x0471, 0x1236), .driver_info = DEVICE_ZD1211B }, diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index f67325387902..8d88daeed0c6 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -1212,7 +1212,7 @@ static int __devinit netfront_probe(struct xenbus_device *dev, } info = netdev_priv(netdev); - dev->dev.driver_data = info; + dev_set_drvdata(&dev->dev, info); err = register_netdev(info->netdev); if (err) { @@ -1233,7 +1233,7 @@ static int __devinit netfront_probe(struct xenbus_device *dev, fail: free_netdev(netdev); - dev->dev.driver_data = NULL; + dev_set_drvdata(&dev->dev, NULL); return err; } @@ -1275,7 +1275,7 @@ static void xennet_disconnect_backend(struct netfront_info *info) */ static int netfront_resume(struct xenbus_device *dev) { - struct netfront_info *info = dev->dev.driver_data; + struct netfront_info *info = dev_get_drvdata(&dev->dev); dev_dbg(&dev->dev, "%s\n", dev->nodename); @@ -1600,7 +1600,7 @@ static int xennet_connect(struct net_device *dev) static void backend_changed(struct xenbus_device *dev, enum xenbus_state backend_state) { - struct netfront_info *np = dev->dev.driver_data; + struct netfront_info *np = dev_get_drvdata(&dev->dev); struct net_device *netdev = np->netdev; dev_dbg(&dev->dev, "%s\n", xenbus_strstate(backend_state)); @@ -1774,7 +1774,7 @@ static struct xenbus_device_id netfront_ids[] = { static int __devexit xennet_remove(struct xenbus_device *dev) { - struct netfront_info *info = dev->dev.driver_data; + struct netfront_info *info = dev_get_drvdata(&dev->dev); dev_dbg(&dev->dev, "%s\n", dev->nodename); diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c index 7477ffdcddb4..3c7a5053f1da 100644 --- a/drivers/net/yellowfin.c +++ b/drivers/net/yellowfin.c @@ -717,7 +717,7 @@ static void yellowfin_tx_timeout(struct net_device *dev) if (yp->cur_tx - yp->dirty_tx < TX_QUEUE_SIZE) netif_wake_queue (dev); /* Typical path */ - dev->trans_start = jiffies; + dev->trans_start = jiffies; /* prevent tx timeout */ dev->stats.tx_errors++; } @@ -876,7 +876,6 @@ static int yellowfin_start_xmit(struct sk_buff *skb, struct net_device *dev) netif_start_queue (dev); /* Typical path */ else yp->tx_full = 1; - dev->trans_start = jiffies; if (yellowfin_debug > 4) { printk(KERN_DEBUG "%s: Yellowfin transmit frame #%d queued in slot %d.\n", diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index f821dbc952a4..d2fa27c5c1b2 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -1,21 +1,27 @@ config OF_DEVICE def_bool y - depends on OF && (SPARC || PPC_OF) + depends on OF && (SPARC || PPC_OF || MICROBLAZE) config OF_GPIO def_bool y - depends on OF && PPC_OF && GPIOLIB + depends on OF && (PPC_OF || MICROBLAZE) && GPIOLIB help OpenFirmware GPIO accessors config OF_I2C def_tristate I2C - depends on PPC_OF && I2C + depends on (PPC_OF || MICROBLAZE) && I2C help OpenFirmware I2C accessors config OF_SPI def_tristate SPI - depends on OF && PPC_OF && SPI + depends on OF && (PPC_OF || MICROBLAZE) && SPI help OpenFirmware SPI accessors + +config OF_MDIO + def_tristate PHYLIB + depends on OF && PHYLIB + help + OpenFirmware MDIO bus (Ethernet PHY) accessors diff --git a/drivers/of/Makefile b/drivers/of/Makefile index 4c3c6f8e36f5..bdfb5f5d4b06 100644 --- a/drivers/of/Makefile +++ b/drivers/of/Makefile @@ -3,3 +3,4 @@ obj-$(CONFIG_OF_DEVICE) += device.o platform.o obj-$(CONFIG_OF_GPIO) += gpio.o obj-$(CONFIG_OF_I2C) += of_i2c.o obj-$(CONFIG_OF_SPI) += of_spi.o +obj-$(CONFIG_OF_MDIO) += of_mdio.o diff --git a/drivers/of/base.c b/drivers/of/base.c index 41c5dfd85358..69f85c07d17f 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -447,6 +447,7 @@ struct of_modalias_table { static struct of_modalias_table of_modalias_table[] = { { "fsl,mcu-mpc8349emitx", "mcu-mpc8349emitx" }, { "mmc-spi-slot", "mmc_spi" }, + { "stm,m25p40", "m25p80" }, }; /** @@ -494,6 +495,30 @@ int of_modalias_node(struct device_node *node, char *modalias, int len) } EXPORT_SYMBOL_GPL(of_modalias_node); +/** + * of_parse_phandle - Resolve a phandle property to a device_node pointer + * @np: Pointer to device node holding phandle property + * @phandle_name: Name of property holding a phandle value + * @index: For properties holding a table of phandles, this is the index into + * the table + * + * Returns the device_node pointer with refcount incremented. Use + * of_node_put() on it when done. + */ +struct device_node * +of_parse_phandle(struct device_node *np, const char *phandle_name, int index) +{ + const phandle *phandle; + int size; + + phandle = of_get_property(np, phandle_name, &size); + if ((!phandle) || (size < sizeof(*phandle) * (index + 1))) + return NULL; + + return of_find_node_by_phandle(phandle[index]); +} +EXPORT_SYMBOL(of_parse_phandle); + /** * of_parse_phandles_with_args - Find a node pointed by phandle in a list * @np: pointer to a device tree node containing a list diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c new file mode 100644 index 000000000000..aee967d7f760 --- /dev/null +++ b/drivers/of/of_mdio.c @@ -0,0 +1,139 @@ +/* + * OF helpers for the MDIO (Ethernet PHY) API + * + * Copyright (c) 2009 Secret Lab Technologies, Ltd. + * + * This file is released under the GPLv2 + * + * This file provides helper functions for extracting PHY device information + * out of the OpenFirmware device tree and using it to populate an mii_bus. + */ + +#include +#include +#include +#include + +MODULE_AUTHOR("Grant Likely "); +MODULE_LICENSE("GPL"); + +/** + * of_mdiobus_register - Register mii_bus and create PHYs from the device tree + * @mdio: pointer to mii_bus structure + * @np: pointer to device_node of MDIO bus. + * + * This function registers the mii_bus structure and registers a phy_device + * for each child node of @np. + */ +int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np) +{ + struct phy_device *phy; + struct device_node *child; + int rc, i; + + /* Mask out all PHYs from auto probing. Instead the PHYs listed in + * the device tree are populated after the bus has been registered */ + mdio->phy_mask = ~0; + + /* Clear all the IRQ properties */ + if (mdio->irq) + for (i=0; iirq[i] = PHY_POLL; + + /* Register the MDIO bus */ + rc = mdiobus_register(mdio); + if (rc) + return rc; + + /* Loop over the child nodes and register a phy_device for each one */ + for_each_child_of_node(np, child) { + const u32 *addr; + int len; + + /* A PHY must have a reg property in the range [0-31] */ + addr = of_get_property(child, "reg", &len); + if (!addr || len < sizeof(*addr) || *addr >= 32 || *addr < 0) { + dev_err(&mdio->dev, "%s has invalid PHY address\n", + child->full_name); + continue; + } + + if (mdio->irq) { + mdio->irq[*addr] = irq_of_parse_and_map(child, 0); + if (!mdio->irq[*addr]) + mdio->irq[*addr] = PHY_POLL; + } + + phy = get_phy_device(mdio, *addr); + if (!phy) { + dev_err(&mdio->dev, "error probing PHY at address %i\n", + *addr); + continue; + } + phy_scan_fixups(phy); + + /* Associate the OF node with the device structure so it + * can be looked up later */ + of_node_get(child); + dev_archdata_set_node(&phy->dev.archdata, child); + + /* All data is now stored in the phy struct; register it */ + rc = phy_device_register(phy); + if (rc) { + phy_device_free(phy); + of_node_put(child); + continue; + } + + dev_dbg(&mdio->dev, "registered phy %s at address %i\n", + child->name, *addr); + } + + return 0; +} +EXPORT_SYMBOL(of_mdiobus_register); + +/** + * of_phy_find_device - Give a PHY node, find the phy_device + * @phy_np: Pointer to the phy's device tree node + * + * Returns a pointer to the phy_device. + */ +struct phy_device *of_phy_find_device(struct device_node *phy_np) +{ + struct device *d; + int match(struct device *dev, void *phy_np) + { + return dev_archdata_get_node(&dev->archdata) == phy_np; + } + + if (!phy_np) + return NULL; + + d = bus_find_device(&mdio_bus_type, NULL, phy_np, match); + return d ? to_phy_device(d) : NULL; +} +EXPORT_SYMBOL(of_phy_find_device); + +/** + * of_phy_connect - Connect to the phy described in the device tree + * @dev: pointer to net_device claiming the phy + * @phy_np: Pointer to device tree node for the PHY + * @hndlr: Link state callback for the network device + * @iface: PHY data interface type + * + * Returns a pointer to the phy_device if successfull. NULL otherwise + */ +struct phy_device *of_phy_connect(struct net_device *dev, + struct device_node *phy_np, + void (*hndlr)(struct net_device *), u32 flags, + phy_interface_t iface) +{ + struct phy_device *phy = of_phy_find_device(phy_np); + + if (!phy) + return NULL; + + return phy_connect_direct(dev, phy, hndlr, flags, iface) ? NULL : phy; +} +EXPORT_SYMBOL(of_phy_connect); diff --git a/drivers/parisc/eisa.c b/drivers/parisc/eisa.c index f415fdd9a885..5b89f404e668 100644 --- a/drivers/parisc/eisa.c +++ b/drivers/parisc/eisa.c @@ -373,7 +373,7 @@ static int __init eisa_probe(struct parisc_device *dev) if (result >= 0) { /* FIXME : Don't enumerate the bus twice. */ eisa_dev.root.dev = &dev->dev; - dev->dev.driver_data = &eisa_dev.root; + dev_set_drvdata(&dev->dev, &eisa_dev.root); eisa_dev.root.bus_base_addr = 0; eisa_dev.root.res = &eisa_dev.hba.io_space; eisa_dev.root.slots = result; diff --git a/drivers/parisc/iosapic.c b/drivers/parisc/iosapic.c index 73348c4047e9..4a9cc92d4d18 100644 --- a/drivers/parisc/iosapic.c +++ b/drivers/parisc/iosapic.c @@ -702,7 +702,7 @@ static unsigned int iosapic_startup_irq(unsigned int irq) } #ifdef CONFIG_SMP -static void iosapic_set_affinity_irq(unsigned int irq, +static int iosapic_set_affinity_irq(unsigned int irq, const struct cpumask *dest) { struct vector_info *vi = iosapic_get_vector(irq); @@ -712,7 +712,7 @@ static void iosapic_set_affinity_irq(unsigned int irq, dest_cpu = cpu_check_affinity(irq, dest); if (dest_cpu < 0) - return; + return -1; cpumask_copy(irq_desc[irq].affinity, cpumask_of(dest_cpu)); vi->txn_addr = txn_affinity_addr(irq, dest_cpu); @@ -724,6 +724,8 @@ static void iosapic_set_affinity_irq(unsigned int irq, iosapic_set_irt_data(vi, &dummy_d0, &d1); iosapic_wr_irt_entry(vi, d0, d1); spin_unlock_irqrestore(&iosapic_lock, flags); + + return 0; } #endif diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c index e5999c4cedc8..d46dd57450ac 100644 --- a/drivers/parisc/sba_iommu.c +++ b/drivers/parisc/sba_iommu.c @@ -2010,7 +2010,7 @@ void __init sba_init(void) void * sba_get_iommu(struct parisc_device *pci_hba) { struct parisc_device *sba_dev = parisc_parent(pci_hba); - struct sba_device *sba = sba_dev->dev.driver_data; + struct sba_device *sba = dev_get_drvdata(&sba_dev->dev); char t = sba_dev->id.hw_type; int iocnum = (pci_hba->hw_path >> 3); /* rope # */ @@ -2031,7 +2031,7 @@ void * sba_get_iommu(struct parisc_device *pci_hba) void sba_directed_lmmio(struct parisc_device *pci_hba, struct resource *r) { struct parisc_device *sba_dev = parisc_parent(pci_hba); - struct sba_device *sba = sba_dev->dev.driver_data; + struct sba_device *sba = dev_get_drvdata(&sba_dev->dev); char t = sba_dev->id.hw_type; int i; int rope = (pci_hba->hw_path & (ROPES_PER_IOC-1)); /* rope # */ @@ -2073,7 +2073,7 @@ void sba_directed_lmmio(struct parisc_device *pci_hba, struct resource *r) void sba_distributed_lmmio(struct parisc_device *pci_hba, struct resource *r ) { struct parisc_device *sba_dev = parisc_parent(pci_hba); - struct sba_device *sba = sba_dev->dev.driver_data; + struct sba_device *sba = dev_get_drvdata(&sba_dev->dev); char t = sba_dev->id.hw_type; int base, size; int rope = (pci_hba->hw_path & (ROPES_PER_IOC-1)); /* rope # */ diff --git a/drivers/parport/parport_gsc.c b/drivers/parport/parport_gsc.c index ea31a452b153..5d6de380e42b 100644 --- a/drivers/parport/parport_gsc.c +++ b/drivers/parport/parport_gsc.c @@ -376,14 +376,14 @@ static int __devinit parport_init_chip(struct parisc_device *dev) /* PARPORT_IRQ_NONE */ PARPORT_DMA_NONE, NULL); if (p) parport_count++; - dev->dev.driver_data = p; + dev_set_drvdata(&dev->dev, p); return 0; } static int __devexit parport_remove_chip(struct parisc_device *dev) { - struct parport *p = dev->dev.driver_data; + struct parport *p = dev_get_drvdata(&dev->dev); if (p) { struct parport_gsc_private *priv = p->private_data; struct parport_operations *ops = p->ops; diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c index 4e63cc9e2778..1032d5fdbd42 100644 --- a/drivers/parport/parport_pc.c +++ b/drivers/parport/parport_pc.c @@ -1,5 +1,5 @@ /* Low-level parallel-port routines for 8255-based PC-style hardware. - * + * * Authors: Phil Blundell * Tim Waugh * Jose Renau @@ -11,7 +11,7 @@ * Cleaned up include files - Russell King * DMA support - Bert De Jonghe * Many ECP bugs fixed. Fred Barnes & Jamie Lokier, 1999 - * More PCI support now conditional on CONFIG_PCI, 03/2001, Paul G. + * More PCI support now conditional on CONFIG_PCI, 03/2001, Paul G. * Various hacks, Fred Barnes, 04/2001 * Updated probing logic - Adam Belay */ @@ -56,10 +56,10 @@ #include #include #include +#include +#include -#include #include -#include #include #include @@ -82,7 +82,7 @@ #define ECR_TST 06 #define ECR_CNF 07 #define ECR_MODE_MASK 0xe0 -#define ECR_WRITE(p,v) frob_econtrol((p),0xff,(v)) +#define ECR_WRITE(p, v) frob_econtrol((p), 0xff, (v)) #undef DEBUG @@ -109,27 +109,27 @@ static int pci_registered_parport; static int pnp_registered_parport; /* frob_control, but for ECR */ -static void frob_econtrol (struct parport *pb, unsigned char m, +static void frob_econtrol(struct parport *pb, unsigned char m, unsigned char v) { unsigned char ectr = 0; if (m != 0xff) - ectr = inb (ECONTROL (pb)); + ectr = inb(ECONTROL(pb)); - DPRINTK (KERN_DEBUG "frob_econtrol(%02x,%02x): %02x -> %02x\n", + DPRINTK(KERN_DEBUG "frob_econtrol(%02x,%02x): %02x -> %02x\n", m, v, ectr, (ectr & ~m) ^ v); - outb ((ectr & ~m) ^ v, ECONTROL (pb)); + outb((ectr & ~m) ^ v, ECONTROL(pb)); } -static __inline__ void frob_set_mode (struct parport *p, int mode) +static inline void frob_set_mode(struct parport *p, int mode) { - frob_econtrol (p, ECR_MODE_MASK, mode << 5); + frob_econtrol(p, ECR_MODE_MASK, mode << 5); } #ifdef CONFIG_PARPORT_PC_FIFO -/* Safely change the mode bits in the ECR +/* Safely change the mode bits in the ECR Returns: 0 : Success -EBUSY: Could not drain FIFO in some finite amount of time, @@ -141,17 +141,18 @@ static int change_mode(struct parport *p, int m) unsigned char oecr; int mode; - DPRINTK(KERN_INFO "parport change_mode ECP-ISA to mode 0x%02x\n",m); + DPRINTK(KERN_INFO "parport change_mode ECP-ISA to mode 0x%02x\n", m); if (!priv->ecr) { - printk (KERN_DEBUG "change_mode: but there's no ECR!\n"); + printk(KERN_DEBUG "change_mode: but there's no ECR!\n"); return 0; } /* Bits <7:5> contain the mode. */ - oecr = inb (ECONTROL (p)); + oecr = inb(ECONTROL(p)); mode = (oecr >> 5) & 0x7; - if (mode == m) return 0; + if (mode == m) + return 0; if (mode >= 2 && !(priv->ctr & 0x20)) { /* This mode resets the FIFO, so we may @@ -163,19 +164,21 @@ static int change_mode(struct parport *p, int m) case ECR_ECP: /* ECP Parallel Port mode */ /* Busy wait for 200us */ for (counter = 0; counter < 40; counter++) { - if (inb (ECONTROL (p)) & 0x01) + if (inb(ECONTROL(p)) & 0x01) break; - if (signal_pending (current)) break; - udelay (5); + if (signal_pending(current)) + break; + udelay(5); } /* Poll slowly. */ - while (!(inb (ECONTROL (p)) & 0x01)) { - if (time_after_eq (jiffies, expire)) + while (!(inb(ECONTROL(p)) & 0x01)) { + if (time_after_eq(jiffies, expire)) /* The FIFO is stuck. */ return -EBUSY; - schedule_timeout_interruptible(msecs_to_jiffies(10)); - if (signal_pending (current)) + schedule_timeout_interruptible( + msecs_to_jiffies(10)); + if (signal_pending(current)) break; } } @@ -185,20 +188,20 @@ static int change_mode(struct parport *p, int m) /* We have to go through mode 001 */ oecr &= ~(7 << 5); oecr |= ECR_PS2 << 5; - ECR_WRITE (p, oecr); + ECR_WRITE(p, oecr); } /* Set the mode. */ oecr &= ~(7 << 5); oecr |= m << 5; - ECR_WRITE (p, oecr); + ECR_WRITE(p, oecr); return 0; } #ifdef CONFIG_PARPORT_1284 /* Find FIFO lossage; FIFO is reset */ #if 0 -static int get_fifo_residue (struct parport *p) +static int get_fifo_residue(struct parport *p) { int residue; int cnfga; @@ -206,26 +209,26 @@ static int get_fifo_residue (struct parport *p) /* Adjust for the contents of the FIFO. */ for (residue = priv->fifo_depth; ; residue--) { - if (inb (ECONTROL (p)) & 0x2) + if (inb(ECONTROL(p)) & 0x2) /* Full up. */ break; - outb (0, FIFO (p)); + outb(0, FIFO(p)); } - printk (KERN_DEBUG "%s: %d PWords were left in FIFO\n", p->name, + printk(KERN_DEBUG "%s: %d PWords were left in FIFO\n", p->name, residue); /* Reset the FIFO. */ - frob_set_mode (p, ECR_PS2); + frob_set_mode(p, ECR_PS2); /* Now change to config mode and clean up. FIXME */ - frob_set_mode (p, ECR_CNF); - cnfga = inb (CONFIGA (p)); - printk (KERN_DEBUG "%s: cnfgA contains 0x%02x\n", p->name, cnfga); + frob_set_mode(p, ECR_CNF); + cnfga = inb(CONFIGA(p)); + printk(KERN_DEBUG "%s: cnfgA contains 0x%02x\n", p->name, cnfga); if (!(cnfga & (1<<2))) { - printk (KERN_DEBUG "%s: Accounting for extra byte\n", p->name); + printk(KERN_DEBUG "%s: Accounting for extra byte\n", p->name); residue++; } @@ -233,9 +236,11 @@ static int get_fifo_residue (struct parport *p) * PWord != 1 byte. */ /* Back to PS2 mode. */ - frob_set_mode (p, ECR_PS2); + frob_set_mode(p, ECR_PS2); - DPRINTK (KERN_DEBUG "*** get_fifo_residue: done residue collecting (ecr = 0x%2.2x)\n", inb (ECONTROL (p))); + DPRINTK(KERN_DEBUG + "*** get_fifo_residue: done residue collecting (ecr = 0x%2.2x)\n", + inb(ECONTROL(p))); return residue; } #endif /* 0 */ @@ -257,8 +262,8 @@ static int clear_epp_timeout(struct parport *pb) /* To clear timeout some chips require double read */ parport_pc_read_status(pb); r = parport_pc_read_status(pb); - outb (r | 0x01, STATUS (pb)); /* Some reset by writing 1 */ - outb (r & 0xfe, STATUS (pb)); /* Others by writing 0 */ + outb(r | 0x01, STATUS(pb)); /* Some reset by writing 1 */ + outb(r & 0xfe, STATUS(pb)); /* Others by writing 0 */ r = parport_pc_read_status(pb); return !(r & 0x01); @@ -272,7 +277,8 @@ static int clear_epp_timeout(struct parport *pb) * of these are in parport_pc.h. */ -static void parport_pc_init_state(struct pardevice *dev, struct parport_state *s) +static void parport_pc_init_state(struct pardevice *dev, + struct parport_state *s) { s->u.pc.ctr = 0xc; if (dev->irq_func && @@ -289,22 +295,23 @@ static void parport_pc_save_state(struct parport *p, struct parport_state *s) const struct parport_pc_private *priv = p->physport->private_data; s->u.pc.ctr = priv->ctr; if (priv->ecr) - s->u.pc.ecr = inb (ECONTROL (p)); + s->u.pc.ecr = inb(ECONTROL(p)); } -static void parport_pc_restore_state(struct parport *p, struct parport_state *s) +static void parport_pc_restore_state(struct parport *p, + struct parport_state *s) { struct parport_pc_private *priv = p->physport->private_data; register unsigned char c = s->u.pc.ctr & priv->ctr_writable; - outb (c, CONTROL (p)); + outb(c, CONTROL(p)); priv->ctr = c; if (priv->ecr) - ECR_WRITE (p, s->u.pc.ecr); + ECR_WRITE(p, s->u.pc.ecr); } #ifdef CONFIG_PARPORT_1284 -static size_t parport_pc_epp_read_data (struct parport *port, void *buf, - size_t length, int flags) +static size_t parport_pc_epp_read_data(struct parport *port, void *buf, + size_t length, int flags) { size_t got = 0; @@ -316,54 +323,52 @@ static size_t parport_pc_epp_read_data (struct parport *port, void *buf, * nFault is 0 if there is at least 1 byte in the Warp's FIFO * pError is 1 if there are 16 bytes in the Warp's FIFO */ - status = inb (STATUS (port)); + status = inb(STATUS(port)); - while (!(status & 0x08) && (got < length)) { - if ((left >= 16) && (status & 0x20) && !(status & 0x08)) { + while (!(status & 0x08) && got < length) { + if (left >= 16 && (status & 0x20) && !(status & 0x08)) { /* can grab 16 bytes from warp fifo */ - if (!((long)buf & 0x03)) { - insl (EPPDATA (port), buf, 4); - } else { - insb (EPPDATA (port), buf, 16); - } + if (!((long)buf & 0x03)) + insl(EPPDATA(port), buf, 4); + else + insb(EPPDATA(port), buf, 16); buf += 16; got += 16; left -= 16; } else { /* grab single byte from the warp fifo */ - *((char *)buf) = inb (EPPDATA (port)); + *((char *)buf) = inb(EPPDATA(port)); buf++; got++; left--; } - status = inb (STATUS (port)); + status = inb(STATUS(port)); if (status & 0x01) { /* EPP timeout should never occur... */ - printk (KERN_DEBUG "%s: EPP timeout occurred while talking to " - "w91284pic (should not have done)\n", port->name); - clear_epp_timeout (port); + printk(KERN_DEBUG +"%s: EPP timeout occurred while talking to w91284pic (should not have done)\n", port->name); + clear_epp_timeout(port); } } return got; } if ((flags & PARPORT_EPP_FAST) && (length > 1)) { - if (!(((long)buf | length) & 0x03)) { - insl (EPPDATA (port), buf, (length >> 2)); - } else { - insb (EPPDATA (port), buf, length); - } - if (inb (STATUS (port)) & 0x01) { - clear_epp_timeout (port); + if (!(((long)buf | length) & 0x03)) + insl(EPPDATA(port), buf, (length >> 2)); + else + insb(EPPDATA(port), buf, length); + if (inb(STATUS(port)) & 0x01) { + clear_epp_timeout(port); return -EIO; } return length; } for (; got < length; got++) { - *((char*)buf) = inb (EPPDATA(port)); + *((char *)buf) = inb(EPPDATA(port)); buf++; - if (inb (STATUS (port)) & 0x01) { + if (inb(STATUS(port)) & 0x01) { /* EPP timeout */ - clear_epp_timeout (port); + clear_epp_timeout(port); break; } } @@ -371,28 +376,27 @@ static size_t parport_pc_epp_read_data (struct parport *port, void *buf, return got; } -static size_t parport_pc_epp_write_data (struct parport *port, const void *buf, - size_t length, int flags) +static size_t parport_pc_epp_write_data(struct parport *port, const void *buf, + size_t length, int flags) { size_t written = 0; if ((flags & PARPORT_EPP_FAST) && (length > 1)) { - if (!(((long)buf | length) & 0x03)) { - outsl (EPPDATA (port), buf, (length >> 2)); - } else { - outsb (EPPDATA (port), buf, length); - } - if (inb (STATUS (port)) & 0x01) { - clear_epp_timeout (port); + if (!(((long)buf | length) & 0x03)) + outsl(EPPDATA(port), buf, (length >> 2)); + else + outsb(EPPDATA(port), buf, length); + if (inb(STATUS(port)) & 0x01) { + clear_epp_timeout(port); return -EIO; } return length; } for (; written < length; written++) { - outb (*((char*)buf), EPPDATA(port)); + outb(*((char *)buf), EPPDATA(port)); buf++; - if (inb (STATUS(port)) & 0x01) { - clear_epp_timeout (port); + if (inb(STATUS(port)) & 0x01) { + clear_epp_timeout(port); break; } } @@ -400,24 +404,24 @@ static size_t parport_pc_epp_write_data (struct parport *port, const void *buf, return written; } -static size_t parport_pc_epp_read_addr (struct parport *port, void *buf, +static size_t parport_pc_epp_read_addr(struct parport *port, void *buf, size_t length, int flags) { size_t got = 0; if ((flags & PARPORT_EPP_FAST) && (length > 1)) { - insb (EPPADDR (port), buf, length); - if (inb (STATUS (port)) & 0x01) { - clear_epp_timeout (port); + insb(EPPADDR(port), buf, length); + if (inb(STATUS(port)) & 0x01) { + clear_epp_timeout(port); return -EIO; } return length; } for (; got < length; got++) { - *((char*)buf) = inb (EPPADDR (port)); + *((char *)buf) = inb(EPPADDR(port)); buf++; - if (inb (STATUS (port)) & 0x01) { - clear_epp_timeout (port); + if (inb(STATUS(port)) & 0x01) { + clear_epp_timeout(port); break; } } @@ -425,25 +429,25 @@ static size_t parport_pc_epp_read_addr (struct parport *port, void *buf, return got; } -static size_t parport_pc_epp_write_addr (struct parport *port, +static size_t parport_pc_epp_write_addr(struct parport *port, const void *buf, size_t length, int flags) { size_t written = 0; if ((flags & PARPORT_EPP_FAST) && (length > 1)) { - outsb (EPPADDR (port), buf, length); - if (inb (STATUS (port)) & 0x01) { - clear_epp_timeout (port); + outsb(EPPADDR(port), buf, length); + if (inb(STATUS(port)) & 0x01) { + clear_epp_timeout(port); return -EIO; } return length; } for (; written < length; written++) { - outb (*((char*)buf), EPPADDR (port)); + outb(*((char *)buf), EPPADDR(port)); buf++; - if (inb (STATUS (port)) & 0x01) { - clear_epp_timeout (port); + if (inb(STATUS(port)) & 0x01) { + clear_epp_timeout(port); break; } } @@ -451,74 +455,74 @@ static size_t parport_pc_epp_write_addr (struct parport *port, return written; } -static size_t parport_pc_ecpepp_read_data (struct parport *port, void *buf, - size_t length, int flags) +static size_t parport_pc_ecpepp_read_data(struct parport *port, void *buf, + size_t length, int flags) { size_t got; - frob_set_mode (port, ECR_EPP); - parport_pc_data_reverse (port); - parport_pc_write_control (port, 0x4); - got = parport_pc_epp_read_data (port, buf, length, flags); - frob_set_mode (port, ECR_PS2); + frob_set_mode(port, ECR_EPP); + parport_pc_data_reverse(port); + parport_pc_write_control(port, 0x4); + got = parport_pc_epp_read_data(port, buf, length, flags); + frob_set_mode(port, ECR_PS2); return got; } -static size_t parport_pc_ecpepp_write_data (struct parport *port, - const void *buf, size_t length, - int flags) +static size_t parport_pc_ecpepp_write_data(struct parport *port, + const void *buf, size_t length, + int flags) { size_t written; - frob_set_mode (port, ECR_EPP); - parport_pc_write_control (port, 0x4); - parport_pc_data_forward (port); - written = parport_pc_epp_write_data (port, buf, length, flags); - frob_set_mode (port, ECR_PS2); + frob_set_mode(port, ECR_EPP); + parport_pc_write_control(port, 0x4); + parport_pc_data_forward(port); + written = parport_pc_epp_write_data(port, buf, length, flags); + frob_set_mode(port, ECR_PS2); return written; } -static size_t parport_pc_ecpepp_read_addr (struct parport *port, void *buf, - size_t length, int flags) +static size_t parport_pc_ecpepp_read_addr(struct parport *port, void *buf, + size_t length, int flags) { size_t got; - frob_set_mode (port, ECR_EPP); - parport_pc_data_reverse (port); - parport_pc_write_control (port, 0x4); - got = parport_pc_epp_read_addr (port, buf, length, flags); - frob_set_mode (port, ECR_PS2); + frob_set_mode(port, ECR_EPP); + parport_pc_data_reverse(port); + parport_pc_write_control(port, 0x4); + got = parport_pc_epp_read_addr(port, buf, length, flags); + frob_set_mode(port, ECR_PS2); return got; } -static size_t parport_pc_ecpepp_write_addr (struct parport *port, +static size_t parport_pc_ecpepp_write_addr(struct parport *port, const void *buf, size_t length, int flags) { size_t written; - frob_set_mode (port, ECR_EPP); - parport_pc_write_control (port, 0x4); - parport_pc_data_forward (port); - written = parport_pc_epp_write_addr (port, buf, length, flags); - frob_set_mode (port, ECR_PS2); + frob_set_mode(port, ECR_EPP); + parport_pc_write_control(port, 0x4); + parport_pc_data_forward(port); + written = parport_pc_epp_write_addr(port, buf, length, flags); + frob_set_mode(port, ECR_PS2); return written; } #endif /* IEEE 1284 support */ #ifdef CONFIG_PARPORT_PC_FIFO -static size_t parport_pc_fifo_write_block_pio (struct parport *port, +static size_t parport_pc_fifo_write_block_pio(struct parport *port, const void *buf, size_t length) { int ret = 0; const unsigned char *bufp = buf; size_t left = length; unsigned long expire = jiffies + port->physport->cad->timeout; - const int fifo = FIFO (port); + const int fifo = FIFO(port); int poll_for = 8; /* 80 usecs */ const struct parport_pc_private *priv = port->physport->private_data; const int fifo_depth = priv->fifo_depth; @@ -526,25 +530,25 @@ static size_t parport_pc_fifo_write_block_pio (struct parport *port, port = port->physport; /* We don't want to be interrupted every character. */ - parport_pc_disable_irq (port); + parport_pc_disable_irq(port); /* set nErrIntrEn and serviceIntr */ - frob_econtrol (port, (1<<4) | (1<<2), (1<<4) | (1<<2)); + frob_econtrol(port, (1<<4) | (1<<2), (1<<4) | (1<<2)); /* Forward mode. */ - parport_pc_data_forward (port); /* Must be in PS2 mode */ + parport_pc_data_forward(port); /* Must be in PS2 mode */ while (left) { unsigned char byte; - unsigned char ecrval = inb (ECONTROL (port)); + unsigned char ecrval = inb(ECONTROL(port)); int i = 0; - if (need_resched() && time_before (jiffies, expire)) + if (need_resched() && time_before(jiffies, expire)) /* Can't yield the port. */ - schedule (); + schedule(); /* Anyone else waiting for the port? */ if (port->waithead) { - printk (KERN_DEBUG "Somebody wants the port\n"); + printk(KERN_DEBUG "Somebody wants the port\n"); break; } @@ -552,21 +556,22 @@ static size_t parport_pc_fifo_write_block_pio (struct parport *port, /* FIFO is full. Wait for interrupt. */ /* Clear serviceIntr */ - ECR_WRITE (port, ecrval & ~(1<<2)); - false_alarm: - ret = parport_wait_event (port, HZ); - if (ret < 0) break; + ECR_WRITE(port, ecrval & ~(1<<2)); +false_alarm: + ret = parport_wait_event(port, HZ); + if (ret < 0) + break; ret = 0; - if (!time_before (jiffies, expire)) { + if (!time_before(jiffies, expire)) { /* Timed out. */ - printk (KERN_DEBUG "FIFO write timed out\n"); + printk(KERN_DEBUG "FIFO write timed out\n"); break; } - ecrval = inb (ECONTROL (port)); + ecrval = inb(ECONTROL(port)); if (!(ecrval & (1<<2))) { if (need_resched() && - time_before (jiffies, expire)) - schedule (); + time_before(jiffies, expire)) + schedule(); goto false_alarm; } @@ -577,38 +582,38 @@ static size_t parport_pc_fifo_write_block_pio (struct parport *port, /* Can't fail now. */ expire = jiffies + port->cad->timeout; - poll: - if (signal_pending (current)) +poll: + if (signal_pending(current)) break; if (ecrval & 0x01) { /* FIFO is empty. Blast it full. */ const int n = left < fifo_depth ? left : fifo_depth; - outsb (fifo, bufp, n); + outsb(fifo, bufp, n); bufp += n; left -= n; /* Adjust the poll time. */ - if (i < (poll_for - 2)) poll_for--; + if (i < (poll_for - 2)) + poll_for--; continue; } else if (i++ < poll_for) { - udelay (10); - ecrval = inb (ECONTROL (port)); + udelay(10); + ecrval = inb(ECONTROL(port)); goto poll; } - /* Half-full (call me an optimist) */ + /* Half-full(call me an optimist) */ byte = *bufp++; - outb (byte, fifo); + outb(byte, fifo); left--; - } - -dump_parport_state ("leave fifo_write_block_pio", port); + } + dump_parport_state("leave fifo_write_block_pio", port); return length - left; } #ifdef HAS_DMA -static size_t parport_pc_fifo_write_block_dma (struct parport *port, +static size_t parport_pc_fifo_write_block_dma(struct parport *port, const void *buf, size_t length) { int ret = 0; @@ -621,7 +626,7 @@ static size_t parport_pc_fifo_write_block_dma (struct parport *port, unsigned long start = (unsigned long) buf; unsigned long end = (unsigned long) buf + length - 1; -dump_parport_state ("enter fifo_write_block_dma", port); + dump_parport_state("enter fifo_write_block_dma", port); if (end < MAX_DMA_ADDRESS) { /* If it would cross a 64k boundary, cap it at the end. */ if ((start ^ end) & ~0xffffUL) @@ -629,8 +634,9 @@ dump_parport_state ("enter fifo_write_block_dma", port); dma_addr = dma_handle = dma_map_single(dev, (void *)buf, length, DMA_TO_DEVICE); - } else { - /* above 16 MB we use a bounce buffer as ISA-DMA is not possible */ + } else { + /* above 16 MB we use a bounce buffer as ISA-DMA + is not possible */ maxlen = PAGE_SIZE; /* sizeof(priv->dma_buf) */ dma_addr = priv->dma_handle; dma_handle = 0; @@ -639,12 +645,12 @@ dump_parport_state ("enter fifo_write_block_dma", port); port = port->physport; /* We don't want to be interrupted every character. */ - parport_pc_disable_irq (port); + parport_pc_disable_irq(port); /* set nErrIntrEn and serviceIntr */ - frob_econtrol (port, (1<<4) | (1<<2), (1<<4) | (1<<2)); + frob_econtrol(port, (1<<4) | (1<<2), (1<<4) | (1<<2)); /* Forward mode. */ - parport_pc_data_forward (port); /* Must be in PS2 mode */ + parport_pc_data_forward(port); /* Must be in PS2 mode */ while (left) { unsigned long expire = jiffies + port->physport->cad->timeout; @@ -665,10 +671,10 @@ dump_parport_state ("enter fifo_write_block_dma", port); set_dma_count(port->dma, count); /* Set DMA mode */ - frob_econtrol (port, 1<<3, 1<<3); + frob_econtrol(port, 1<<3, 1<<3); /* Clear serviceIntr */ - frob_econtrol (port, 1<<2, 0); + frob_econtrol(port, 1<<2, 0); enable_dma(port->dma); release_dma_lock(dmaflag); @@ -676,20 +682,22 @@ dump_parport_state ("enter fifo_write_block_dma", port); /* assume DMA will be successful */ left -= count; buf += count; - if (dma_handle) dma_addr += count; + if (dma_handle) + dma_addr += count; /* Wait for interrupt. */ - false_alarm: - ret = parport_wait_event (port, HZ); - if (ret < 0) break; +false_alarm: + ret = parport_wait_event(port, HZ); + if (ret < 0) + break; ret = 0; - if (!time_before (jiffies, expire)) { + if (!time_before(jiffies, expire)) { /* Timed out. */ - printk (KERN_DEBUG "DMA write timed out\n"); + printk(KERN_DEBUG "DMA write timed out\n"); break; } /* Is serviceIntr set? */ - if (!(inb (ECONTROL (port)) & (1<<2))) { + if (!(inb(ECONTROL(port)) & (1<<2))) { cond_resched(); goto false_alarm; @@ -705,14 +713,15 @@ dump_parport_state ("enter fifo_write_block_dma", port); /* Anyone else waiting for the port? */ if (port->waithead) { - printk (KERN_DEBUG "Somebody wants the port\n"); + printk(KERN_DEBUG "Somebody wants the port\n"); break; } /* update for possible DMA residue ! */ buf -= count; left += count; - if (dma_handle) dma_addr -= count; + if (dma_handle) + dma_addr -= count; } /* Maybe got here through break, so adjust for DMA residue! */ @@ -723,12 +732,12 @@ dump_parport_state ("enter fifo_write_block_dma", port); release_dma_lock(dmaflag); /* Turn off DMA mode */ - frob_econtrol (port, 1<<3, 0); + frob_econtrol(port, 1<<3, 0); if (dma_handle) dma_unmap_single(dev, dma_handle, length, DMA_TO_DEVICE); -dump_parport_state ("leave fifo_write_block_dma", port); + dump_parport_state("leave fifo_write_block_dma", port); return length - left; } #endif @@ -738,13 +747,13 @@ static inline size_t parport_pc_fifo_write_block(struct parport *port, { #ifdef HAS_DMA if (port->dma != PARPORT_DMA_NONE) - return parport_pc_fifo_write_block_dma (port, buf, length); + return parport_pc_fifo_write_block_dma(port, buf, length); #endif - return parport_pc_fifo_write_block_pio (port, buf, length); + return parport_pc_fifo_write_block_pio(port, buf, length); } /* Parallel Port FIFO mode (ECP chipsets) */ -static size_t parport_pc_compat_write_block_pio (struct parport *port, +static size_t parport_pc_compat_write_block_pio(struct parport *port, const void *buf, size_t length, int flags) { @@ -756,14 +765,16 @@ static size_t parport_pc_compat_write_block_pio (struct parport *port, /* Special case: a timeout of zero means we cannot call schedule(). * Also if O_NONBLOCK is set then use the default implementation. */ if (port->physport->cad->timeout <= PARPORT_INACTIVITY_O_NONBLOCK) - return parport_ieee1284_write_compat (port, buf, + return parport_ieee1284_write_compat(port, buf, length, flags); /* Set up parallel port FIFO mode.*/ - parport_pc_data_forward (port); /* Must be in PS2 mode */ - parport_pc_frob_control (port, PARPORT_CONTROL_STROBE, 0); - r = change_mode (port, ECR_PPF); /* Parallel port FIFO */ - if (r) printk (KERN_DEBUG "%s: Warning change_mode ECR_PPF failed\n", port->name); + parport_pc_data_forward(port); /* Must be in PS2 mode */ + parport_pc_frob_control(port, PARPORT_CONTROL_STROBE, 0); + r = change_mode(port, ECR_PPF); /* Parallel port FIFO */ + if (r) + printk(KERN_DEBUG "%s: Warning change_mode ECR_PPF failed\n", + port->name); port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA; @@ -775,40 +786,39 @@ static size_t parport_pc_compat_write_block_pio (struct parport *port, * the FIFO is empty, so allow 4 seconds for each position * in the fifo. */ - expire = jiffies + (priv->fifo_depth * HZ * 4); + expire = jiffies + (priv->fifo_depth * HZ * 4); do { /* Wait for the FIFO to empty */ - r = change_mode (port, ECR_PS2); - if (r != -EBUSY) { + r = change_mode(port, ECR_PS2); + if (r != -EBUSY) break; - } - } while (time_before (jiffies, expire)); + } while (time_before(jiffies, expire)); if (r == -EBUSY) { - printk (KERN_DEBUG "%s: FIFO is stuck\n", port->name); + printk(KERN_DEBUG "%s: FIFO is stuck\n", port->name); /* Prevent further data transfer. */ - frob_set_mode (port, ECR_TST); + frob_set_mode(port, ECR_TST); /* Adjust for the contents of the FIFO. */ for (written -= priv->fifo_depth; ; written++) { - if (inb (ECONTROL (port)) & 0x2) { + if (inb(ECONTROL(port)) & 0x2) { /* Full up. */ break; } - outb (0, FIFO (port)); + outb(0, FIFO(port)); } /* Reset the FIFO and return to PS2 mode. */ - frob_set_mode (port, ECR_PS2); + frob_set_mode(port, ECR_PS2); } - r = parport_wait_peripheral (port, + r = parport_wait_peripheral(port, PARPORT_STATUS_BUSY, PARPORT_STATUS_BUSY); if (r) - printk (KERN_DEBUG - "%s: BUSY timeout (%d) in compat_write_block_pio\n", + printk(KERN_DEBUG + "%s: BUSY timeout (%d) in compat_write_block_pio\n", port->name, r); port->physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE; @@ -818,7 +828,7 @@ static size_t parport_pc_compat_write_block_pio (struct parport *port, /* ECP */ #ifdef CONFIG_PARPORT_1284 -static size_t parport_pc_ecp_write_block_pio (struct parport *port, +static size_t parport_pc_ecp_write_block_pio(struct parport *port, const void *buf, size_t length, int flags) { @@ -830,36 +840,38 @@ static size_t parport_pc_ecp_write_block_pio (struct parport *port, /* Special case: a timeout of zero means we cannot call schedule(). * Also if O_NONBLOCK is set then use the default implementation. */ if (port->physport->cad->timeout <= PARPORT_INACTIVITY_O_NONBLOCK) - return parport_ieee1284_ecp_write_data (port, buf, + return parport_ieee1284_ecp_write_data(port, buf, length, flags); /* Switch to forward mode if necessary. */ if (port->physport->ieee1284.phase != IEEE1284_PH_FWD_IDLE) { /* Event 47: Set nInit high. */ - parport_frob_control (port, + parport_frob_control(port, PARPORT_CONTROL_INIT | PARPORT_CONTROL_AUTOFD, PARPORT_CONTROL_INIT | PARPORT_CONTROL_AUTOFD); /* Event 49: PError goes high. */ - r = parport_wait_peripheral (port, + r = parport_wait_peripheral(port, PARPORT_STATUS_PAPEROUT, PARPORT_STATUS_PAPEROUT); if (r) { - printk (KERN_DEBUG "%s: PError timeout (%d) " + printk(KERN_DEBUG "%s: PError timeout (%d) " "in ecp_write_block_pio\n", port->name, r); } } /* Set up ECP parallel port mode.*/ - parport_pc_data_forward (port); /* Must be in PS2 mode */ - parport_pc_frob_control (port, + parport_pc_data_forward(port); /* Must be in PS2 mode */ + parport_pc_frob_control(port, PARPORT_CONTROL_STROBE | PARPORT_CONTROL_AUTOFD, 0); - r = change_mode (port, ECR_ECP); /* ECP FIFO */ - if (r) printk (KERN_DEBUG "%s: Warning change_mode ECR_ECP failed\n", port->name); + r = change_mode(port, ECR_ECP); /* ECP FIFO */ + if (r) + printk(KERN_DEBUG "%s: Warning change_mode ECR_ECP failed\n", + port->name); port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA; /* Write the data to the FIFO. */ @@ -873,55 +885,54 @@ static size_t parport_pc_ecp_write_block_pio (struct parport *port, expire = jiffies + (priv->fifo_depth * (HZ * 4)); do { /* Wait for the FIFO to empty */ - r = change_mode (port, ECR_PS2); - if (r != -EBUSY) { + r = change_mode(port, ECR_PS2); + if (r != -EBUSY) break; - } - } while (time_before (jiffies, expire)); + } while (time_before(jiffies, expire)); if (r == -EBUSY) { - printk (KERN_DEBUG "%s: FIFO is stuck\n", port->name); + printk(KERN_DEBUG "%s: FIFO is stuck\n", port->name); /* Prevent further data transfer. */ - frob_set_mode (port, ECR_TST); + frob_set_mode(port, ECR_TST); /* Adjust for the contents of the FIFO. */ for (written -= priv->fifo_depth; ; written++) { - if (inb (ECONTROL (port)) & 0x2) { + if (inb(ECONTROL(port)) & 0x2) { /* Full up. */ break; } - outb (0, FIFO (port)); + outb(0, FIFO(port)); } /* Reset the FIFO and return to PS2 mode. */ - frob_set_mode (port, ECR_PS2); + frob_set_mode(port, ECR_PS2); /* Host transfer recovery. */ - parport_pc_data_reverse (port); /* Must be in PS2 mode */ - udelay (5); - parport_frob_control (port, PARPORT_CONTROL_INIT, 0); - r = parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0); + parport_pc_data_reverse(port); /* Must be in PS2 mode */ + udelay(5); + parport_frob_control(port, PARPORT_CONTROL_INIT, 0); + r = parport_wait_peripheral(port, PARPORT_STATUS_PAPEROUT, 0); if (r) - printk (KERN_DEBUG "%s: PE,1 timeout (%d) " + printk(KERN_DEBUG "%s: PE,1 timeout (%d) " "in ecp_write_block_pio\n", port->name, r); - parport_frob_control (port, + parport_frob_control(port, PARPORT_CONTROL_INIT, PARPORT_CONTROL_INIT); - r = parport_wait_peripheral (port, + r = parport_wait_peripheral(port, PARPORT_STATUS_PAPEROUT, PARPORT_STATUS_PAPEROUT); - if (r) - printk (KERN_DEBUG "%s: PE,2 timeout (%d) " + if (r) + printk(KERN_DEBUG "%s: PE,2 timeout (%d) " "in ecp_write_block_pio\n", port->name, r); } - r = parport_wait_peripheral (port, - PARPORT_STATUS_BUSY, + r = parport_wait_peripheral(port, + PARPORT_STATUS_BUSY, PARPORT_STATUS_BUSY); - if(r) - printk (KERN_DEBUG + if (r) + printk(KERN_DEBUG "%s: BUSY timeout (%d) in ecp_write_block_pio\n", port->name, r); @@ -931,7 +942,7 @@ static size_t parport_pc_ecp_write_block_pio (struct parport *port, } #if 0 -static size_t parport_pc_ecp_read_block_pio (struct parport *port, +static size_t parport_pc_ecp_read_block_pio(struct parport *port, void *buf, size_t length, int flags) { @@ -944,13 +955,13 @@ static size_t parport_pc_ecp_read_block_pio (struct parport *port, char *bufp = buf; port = port->physport; -DPRINTK (KERN_DEBUG "parport_pc: parport_pc_ecp_read_block_pio\n"); -dump_parport_state ("enter fcn", port); + DPRINTK(KERN_DEBUG "parport_pc: parport_pc_ecp_read_block_pio\n"); + dump_parport_state("enter fcn", port); /* Special case: a timeout of zero means we cannot call schedule(). * Also if O_NONBLOCK is set then use the default implementation. */ if (port->cad->timeout <= PARPORT_INACTIVITY_O_NONBLOCK) - return parport_ieee1284_ecp_read_data (port, buf, + return parport_ieee1284_ecp_read_data(port, buf, length, flags); if (port->ieee1284.mode == IEEE1284_MODE_ECPRLE) { @@ -966,173 +977,178 @@ dump_parport_state ("enter fcn", port); * go through software emulation. Otherwise we may have to throw * away data. */ if (length < fifofull) - return parport_ieee1284_ecp_read_data (port, buf, + return parport_ieee1284_ecp_read_data(port, buf, length, flags); if (port->ieee1284.phase != IEEE1284_PH_REV_IDLE) { /* change to reverse-idle phase (must be in forward-idle) */ /* Event 38: Set nAutoFd low (also make sure nStrobe is high) */ - parport_frob_control (port, + parport_frob_control(port, PARPORT_CONTROL_AUTOFD | PARPORT_CONTROL_STROBE, PARPORT_CONTROL_AUTOFD); - parport_pc_data_reverse (port); /* Must be in PS2 mode */ - udelay (5); + parport_pc_data_reverse(port); /* Must be in PS2 mode */ + udelay(5); /* Event 39: Set nInit low to initiate bus reversal */ - parport_frob_control (port, + parport_frob_control(port, PARPORT_CONTROL_INIT, 0); /* Event 40: Wait for nAckReverse (PError) to go low */ - r = parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0); - if (r) { - printk (KERN_DEBUG "%s: PE timeout Event 40 (%d) " + r = parport_wait_peripheral(port, PARPORT_STATUS_PAPEROUT, 0); + if (r) { + printk(KERN_DEBUG "%s: PE timeout Event 40 (%d) " "in ecp_read_block_pio\n", port->name, r); return 0; } } /* Set up ECP FIFO mode.*/ -/* parport_pc_frob_control (port, +/* parport_pc_frob_control(port, PARPORT_CONTROL_STROBE | PARPORT_CONTROL_AUTOFD, PARPORT_CONTROL_AUTOFD); */ - r = change_mode (port, ECR_ECP); /* ECP FIFO */ - if (r) printk (KERN_DEBUG "%s: Warning change_mode ECR_ECP failed\n", port->name); + r = change_mode(port, ECR_ECP); /* ECP FIFO */ + if (r) + printk(KERN_DEBUG "%s: Warning change_mode ECR_ECP failed\n", + port->name); port->ieee1284.phase = IEEE1284_PH_REV_DATA; /* the first byte must be collected manually */ -dump_parport_state ("pre 43", port); + dump_parport_state("pre 43", port); /* Event 43: Wait for nAck to go low */ - r = parport_wait_peripheral (port, PARPORT_STATUS_ACK, 0); + r = parport_wait_peripheral(port, PARPORT_STATUS_ACK, 0); if (r) { /* timed out while reading -- no data */ - printk (KERN_DEBUG "PIO read timed out (initial byte)\n"); + printk(KERN_DEBUG "PIO read timed out (initial byte)\n"); goto out_no_data; } /* read byte */ - *bufp++ = inb (DATA (port)); + *bufp++ = inb(DATA(port)); left--; -dump_parport_state ("43-44", port); + dump_parport_state("43-44", port); /* Event 44: nAutoFd (HostAck) goes high to acknowledge */ - parport_pc_frob_control (port, + parport_pc_frob_control(port, PARPORT_CONTROL_AUTOFD, 0); -dump_parport_state ("pre 45", port); + dump_parport_state("pre 45", port); /* Event 45: Wait for nAck to go high */ -/* r = parport_wait_peripheral (port, PARPORT_STATUS_ACK, PARPORT_STATUS_ACK); */ -dump_parport_state ("post 45", port); -r = 0; + /* r = parport_wait_peripheral(port, PARPORT_STATUS_ACK, + PARPORT_STATUS_ACK); */ + dump_parport_state("post 45", port); + r = 0; if (r) { /* timed out while waiting for peripheral to respond to ack */ - printk (KERN_DEBUG "ECP PIO read timed out (waiting for nAck)\n"); + printk(KERN_DEBUG "ECP PIO read timed out (waiting for nAck)\n"); /* keep hold of the byte we've got already */ goto out_no_data; } /* Event 46: nAutoFd (HostAck) goes low to accept more data */ - parport_pc_frob_control (port, + parport_pc_frob_control(port, PARPORT_CONTROL_AUTOFD, PARPORT_CONTROL_AUTOFD); -dump_parport_state ("rev idle", port); + dump_parport_state("rev idle", port); /* Do the transfer. */ while (left > fifofull) { int ret; unsigned long expire = jiffies + port->cad->timeout; - unsigned char ecrval = inb (ECONTROL (port)); + unsigned char ecrval = inb(ECONTROL(port)); - if (need_resched() && time_before (jiffies, expire)) + if (need_resched() && time_before(jiffies, expire)) /* Can't yield the port. */ - schedule (); + schedule(); /* At this point, the FIFO may already be full. In - * that case ECP is already holding back the - * peripheral (assuming proper design) with a delayed - * handshake. Work fast to avoid a peripheral - * timeout. */ + * that case ECP is already holding back the + * peripheral (assuming proper design) with a delayed + * handshake. Work fast to avoid a peripheral + * timeout. */ if (ecrval & 0x01) { /* FIFO is empty. Wait for interrupt. */ -dump_parport_state ("FIFO empty", port); + dump_parport_state("FIFO empty", port); /* Anyone else waiting for the port? */ if (port->waithead) { - printk (KERN_DEBUG "Somebody wants the port\n"); + printk(KERN_DEBUG "Somebody wants the port\n"); break; } /* Clear serviceIntr */ - ECR_WRITE (port, ecrval & ~(1<<2)); - false_alarm: -dump_parport_state ("waiting", port); - ret = parport_wait_event (port, HZ); -DPRINTK (KERN_DEBUG "parport_wait_event returned %d\n", ret); + ECR_WRITE(port, ecrval & ~(1<<2)); +false_alarm: + dump_parport_state("waiting", port); + ret = parport_wait_event(port, HZ); + DPRINTK(KERN_DEBUG "parport_wait_event returned %d\n", + ret); if (ret < 0) break; ret = 0; - if (!time_before (jiffies, expire)) { + if (!time_before(jiffies, expire)) { /* Timed out. */ -dump_parport_state ("timeout", port); - printk (KERN_DEBUG "PIO read timed out\n"); + dump_parport_state("timeout", port); + printk(KERN_DEBUG "PIO read timed out\n"); break; } - ecrval = inb (ECONTROL (port)); + ecrval = inb(ECONTROL(port)); if (!(ecrval & (1<<2))) { if (need_resched() && - time_before (jiffies, expire)) { - schedule (); + time_before(jiffies, expire)) { + schedule(); } goto false_alarm; } /* Depending on how the FIFO threshold was - * set, how long interrupt service took, and - * how fast the peripheral is, we might be - * lucky and have a just filled FIFO. */ + * set, how long interrupt service took, and + * how fast the peripheral is, we might be + * lucky and have a just filled FIFO. */ continue; } if (ecrval & 0x02) { /* FIFO is full. */ -dump_parport_state ("FIFO full", port); - insb (fifo, bufp, fifo_depth); + dump_parport_state("FIFO full", port); + insb(fifo, bufp, fifo_depth); bufp += fifo_depth; left -= fifo_depth; continue; } -DPRINTK (KERN_DEBUG "*** ecp_read_block_pio: reading one byte from the FIFO\n"); + DPRINTK(KERN_DEBUG + "*** ecp_read_block_pio: reading one byte from the FIFO\n"); /* FIFO not filled. We will cycle this loop for a while - * and either the peripheral will fill it faster, - * tripping a fast empty with insb, or we empty it. */ - *bufp++ = inb (fifo); + * and either the peripheral will fill it faster, + * tripping a fast empty with insb, or we empty it. */ + *bufp++ = inb(fifo); left--; } /* scoop up anything left in the FIFO */ - while (left && !(inb (ECONTROL (port) & 0x01))) { - *bufp++ = inb (fifo); + while (left && !(inb(ECONTROL(port) & 0x01))) { + *bufp++ = inb(fifo); left--; } port->ieee1284.phase = IEEE1284_PH_REV_IDLE; -dump_parport_state ("rev idle2", port); + dump_parport_state("rev idle2", port); out_no_data: /* Go to forward idle mode to shut the peripheral up (event 47). */ - parport_frob_control (port, PARPORT_CONTROL_INIT, PARPORT_CONTROL_INIT); + parport_frob_control(port, PARPORT_CONTROL_INIT, PARPORT_CONTROL_INIT); /* event 49: PError goes high */ - r = parport_wait_peripheral (port, + r = parport_wait_peripheral(port, PARPORT_STATUS_PAPEROUT, PARPORT_STATUS_PAPEROUT); if (r) { - printk (KERN_DEBUG + printk(KERN_DEBUG "%s: PE timeout FWDIDLE (%d) in ecp_read_block_pio\n", port->name, r); } @@ -1141,14 +1157,14 @@ out_no_data: /* Finish up. */ { - int lost = get_fifo_residue (port); + int lost = get_fifo_residue(port); if (lost) /* Shouldn't happen with compliant peripherals. */ - printk (KERN_DEBUG "%s: DATA LOSS (%d bytes)!\n", + printk(KERN_DEBUG "%s: DATA LOSS (%d bytes)!\n", port->name, lost); } -dump_parport_state ("fwd idle", port); + dump_parport_state("fwd idle", port); return length - left; } #endif /* 0 */ @@ -1164,8 +1180,7 @@ dump_parport_state ("fwd idle", port); /* GCC is not inlining extern inline function later overwriten to non-inline, so we use outlined_ variants here. */ -static const struct parport_operations parport_pc_ops = -{ +static const struct parport_operations parport_pc_ops = { .write_data = parport_pc_write_data, .read_data = parport_pc_read_data, @@ -1202,88 +1217,107 @@ static const struct parport_operations parport_pc_ops = }; #ifdef CONFIG_PARPORT_PC_SUPERIO + +static struct superio_struct *find_free_superio(void) +{ + int i; + for (i = 0; i < NR_SUPERIOS; i++) + if (superios[i].io == 0) + return &superios[i]; + return NULL; +} + + /* Super-IO chipset detection, Winbond, SMSC */ static void __devinit show_parconfig_smsc37c669(int io, int key) { - int cr1,cr4,cra,cr23,cr26,cr27,i=0; - static const char *const modes[]={ + int cr1, cr4, cra, cr23, cr26, cr27; + struct superio_struct *s; + + static const char *const modes[] = { "SPP and Bidirectional (PS/2)", "EPP and SPP", "ECP", "ECP and EPP" }; - outb(key,io); - outb(key,io); - outb(1,io); - cr1=inb(io+1); - outb(4,io); - cr4=inb(io+1); - outb(0x0a,io); - cra=inb(io+1); - outb(0x23,io); - cr23=inb(io+1); - outb(0x26,io); - cr26=inb(io+1); - outb(0x27,io); - cr27=inb(io+1); - outb(0xaa,io); + outb(key, io); + outb(key, io); + outb(1, io); + cr1 = inb(io + 1); + outb(4, io); + cr4 = inb(io + 1); + outb(0x0a, io); + cra = inb(io + 1); + outb(0x23, io); + cr23 = inb(io + 1); + outb(0x26, io); + cr26 = inb(io + 1); + outb(0x27, io); + cr27 = inb(io + 1); + outb(0xaa, io); if (verbose_probing) { - printk (KERN_INFO "SMSC 37c669 LPT Config: cr_1=0x%02x, 4=0x%02x, " + printk(KERN_INFO + "SMSC 37c669 LPT Config: cr_1=0x%02x, 4=0x%02x, " "A=0x%2x, 23=0x%02x, 26=0x%02x, 27=0x%02x\n", - cr1,cr4,cra,cr23,cr26,cr27); - + cr1, cr4, cra, cr23, cr26, cr27); + /* The documentation calls DMA and IRQ-Lines by letters, so the board maker can/will wire them appropriately/randomly... G=reserved H=IDE-irq, */ - printk (KERN_INFO "SMSC LPT Config: io=0x%04x, irq=%c, dma=%c, " - "fifo threshold=%d\n", cr23*4, - (cr27 &0x0f) ? 'A'-1+(cr27 &0x0f): '-', - (cr26 &0x0f) ? 'A'-1+(cr26 &0x0f): '-', cra & 0x0f); + printk(KERN_INFO + "SMSC LPT Config: io=0x%04x, irq=%c, dma=%c, fifo threshold=%d\n", + cr23 * 4, + (cr27 & 0x0f) ? 'A' - 1 + (cr27 & 0x0f) : '-', + (cr26 & 0x0f) ? 'A' - 1 + (cr26 & 0x0f) : '-', + cra & 0x0f); printk(KERN_INFO "SMSC LPT Config: enabled=%s power=%s\n", - (cr23*4 >=0x100) ?"yes":"no", (cr1 & 4) ? "yes" : "no"); - printk(KERN_INFO "SMSC LPT Config: Port mode=%s, EPP version =%s\n", - (cr1 & 0x08 ) ? "Standard mode only (SPP)" : modes[cr4 & 0x03], - (cr4 & 0x40) ? "1.7" : "1.9"); + (cr23 * 4 >= 0x100) ? "yes" : "no", + (cr1 & 4) ? "yes" : "no"); + printk(KERN_INFO + "SMSC LPT Config: Port mode=%s, EPP version =%s\n", + (cr1 & 0x08) ? "Standard mode only (SPP)" + : modes[cr4 & 0x03], + (cr4 & 0x40) ? "1.7" : "1.9"); } - + /* Heuristics ! BIOS setup for this mainboard device limits the choices to standard settings, i.e. io-address and IRQ are related, however DMA can be 1 or 3, assume DMA_A=DMA1, DMA_C=DMA3 (this is true e.g. for TYAN 1564D Tomcat IV) */ - if(cr23*4 >=0x100) { /* if active */ - while((superios[i].io!= 0) && (i= 0x100) { /* if active */ + s = find_free_superio(); + if (s == NULL) printk(KERN_INFO "Super-IO: too many chips!\n"); else { int d; - switch (cr23*4) { - case 0x3bc: - superios[i].io = 0x3bc; - superios[i].irq = 7; - break; - case 0x378: - superios[i].io = 0x378; - superios[i].irq = 7; - break; - case 0x278: - superios[i].io = 0x278; - superios[i].irq = 5; + switch (cr23 * 4) { + case 0x3bc: + s->io = 0x3bc; + s->irq = 7; + break; + case 0x378: + s->io = 0x378; + s->irq = 7; + break; + case 0x278: + s->io = 0x278; + s->irq = 5; } - d=(cr26 &0x0f); - if((d==1) || (d==3)) - superios[i].dma= d; + d = (cr26 & 0x0f); + if (d == 1 || d == 3) + s->dma = d; else - superios[i].dma= PARPORT_DMA_NONE; + s->dma = PARPORT_DMA_NONE; } - } + } } static void __devinit show_parconfig_winbond(int io, int key) { - int cr30,cr60,cr61,cr70,cr74,crf0,i=0; + int cr30, cr60, cr61, cr70, cr74, crf0; + struct superio_struct *s; static const char *const modes[] = { "Standard (SPP) and Bidirectional(PS/2)", /* 0 */ "EPP-1.9 and SPP", @@ -1296,110 +1330,134 @@ static void __devinit show_parconfig_winbond(int io, int key) static char *const irqtypes[] = { "pulsed low, high-Z", "follows nACK" }; - + /* The registers are called compatible-PnP because the - register layout is modelled after ISA-PnP, the access - method is just another ... */ - outb(key,io); - outb(key,io); - outb(0x07,io); /* Register 7: Select Logical Device */ - outb(0x01,io+1); /* LD1 is Parallel Port */ - outb(0x30,io); - cr30=inb(io+1); - outb(0x60,io); - cr60=inb(io+1); - outb(0x61,io); - cr61=inb(io+1); - outb(0x70,io); - cr70=inb(io+1); - outb(0x74,io); - cr74=inb(io+1); - outb(0xf0,io); - crf0=inb(io+1); - outb(0xaa,io); + register layout is modelled after ISA-PnP, the access + method is just another ... */ + outb(key, io); + outb(key, io); + outb(0x07, io); /* Register 7: Select Logical Device */ + outb(0x01, io + 1); /* LD1 is Parallel Port */ + outb(0x30, io); + cr30 = inb(io + 1); + outb(0x60, io); + cr60 = inb(io + 1); + outb(0x61, io); + cr61 = inb(io + 1); + outb(0x70, io); + cr70 = inb(io + 1); + outb(0x74, io); + cr74 = inb(io + 1); + outb(0xf0, io); + crf0 = inb(io + 1); + outb(0xaa, io); if (verbose_probing) { - printk(KERN_INFO "Winbond LPT Config: cr_30=%02x 60,61=%02x%02x " - "70=%02x 74=%02x, f0=%02x\n", cr30,cr60,cr61,cr70,cr74,crf0); - printk(KERN_INFO "Winbond LPT Config: active=%s, io=0x%02x%02x irq=%d, ", - (cr30 & 0x01) ? "yes":"no", cr60,cr61,cr70&0x0f ); + printk(KERN_INFO + "Winbond LPT Config: cr_30=%02x 60,61=%02x%02x 70=%02x 74=%02x, f0=%02x\n", + cr30, cr60, cr61, cr70, cr74, crf0); + printk(KERN_INFO "Winbond LPT Config: active=%s, io=0x%02x%02x irq=%d, ", + (cr30 & 0x01) ? "yes" : "no", cr60, cr61, cr70 & 0x0f); if ((cr74 & 0x07) > 3) printk("dma=none\n"); else - printk("dma=%d\n",cr74 & 0x07); - printk(KERN_INFO "Winbond LPT Config: irqtype=%s, ECP fifo threshold=%d\n", - irqtypes[crf0>>7], (crf0>>3)&0x0f); - printk(KERN_INFO "Winbond LPT Config: Port mode=%s\n", modes[crf0 & 0x07]); + printk("dma=%d\n", cr74 & 0x07); + printk(KERN_INFO + "Winbond LPT Config: irqtype=%s, ECP fifo threshold=%d\n", + irqtypes[crf0>>7], (crf0>>3)&0x0f); + printk(KERN_INFO "Winbond LPT Config: Port mode=%s\n", + modes[crf0 & 0x07]); } - if(cr30 & 0x01) { /* the settings can be interrogated later ... */ - while((superios[i].io!= 0) && (i 3) ? + s->io = (cr60 << 8) | cr61; + s->irq = cr70 & 0x0f; + s->dma = (((cr74 & 0x07) > 3) ? PARPORT_DMA_NONE : (cr74 & 0x07)); } } } -static void __devinit decode_winbond(int efer, int key, int devid, int devrev, int oldid) +static void __devinit decode_winbond(int efer, int key, int devid, + int devrev, int oldid) { const char *type = "unknown"; - int id,progif=2; + int id, progif = 2; if (devid == devrev) /* simple heuristics, we happened to read some - non-winbond register */ + non-winbond register */ return; - id=(devid<<8) | devrev; + id = (devid << 8) | devrev; /* Values are from public data sheets pdf files, I can just - confirm 83977TF is correct :-) */ - if (id == 0x9771) type="83977F/AF"; - else if (id == 0x9773) type="83977TF / SMSC 97w33x/97w34x"; - else if (id == 0x9774) type="83977ATF"; - else if ((id & ~0x0f) == 0x5270) type="83977CTF / SMSC 97w36x"; - else if ((id & ~0x0f) == 0x52f0) type="83977EF / SMSC 97w35x"; - else if ((id & ~0x0f) == 0x5210) type="83627"; - else if ((id & ~0x0f) == 0x6010) type="83697HF"; - else if ((oldid &0x0f ) == 0x0a) { type="83877F"; progif=1;} - else if ((oldid &0x0f ) == 0x0b) { type="83877AF"; progif=1;} - else if ((oldid &0x0f ) == 0x0c) { type="83877TF"; progif=1;} - else if ((oldid &0x0f ) == 0x0d) { type="83877ATF"; progif=1;} - else progif=0; + confirm 83977TF is correct :-) */ + if (id == 0x9771) + type = "83977F/AF"; + else if (id == 0x9773) + type = "83977TF / SMSC 97w33x/97w34x"; + else if (id == 0x9774) + type = "83977ATF"; + else if ((id & ~0x0f) == 0x5270) + type = "83977CTF / SMSC 97w36x"; + else if ((id & ~0x0f) == 0x52f0) + type = "83977EF / SMSC 97w35x"; + else if ((id & ~0x0f) == 0x5210) + type = "83627"; + else if ((id & ~0x0f) == 0x6010) + type = "83697HF"; + else if ((oldid & 0x0f) == 0x0a) { + type = "83877F"; + progif = 1; + } else if ((oldid & 0x0f) == 0x0b) { + type = "83877AF"; + progif = 1; + } else if ((oldid & 0x0f) == 0x0c) { + type = "83877TF"; + progif = 1; + } else if ((oldid & 0x0f) == 0x0d) { + type = "83877ATF"; + progif = 1; + } else + progif = 0; if (verbose_probing) printk(KERN_INFO "Winbond chip at EFER=0x%x key=0x%02x " - "devid=%02x devrev=%02x oldid=%02x type=%s\n", + "devid=%02x devrev=%02x oldid=%02x type=%s\n", efer, key, devid, devrev, oldid, type); if (progif == 2) - show_parconfig_winbond(efer,key); + show_parconfig_winbond(efer, key); } static void __devinit decode_smsc(int efer, int key, int devid, int devrev) { - const char *type = "unknown"; + const char *type = "unknown"; void (*func)(int io, int key); - int id; + int id; - if (devid == devrev) + if (devid == devrev) /* simple heuristics, we happened to read some - non-smsc register */ + non-smsc register */ return; - func=NULL; - id=(devid<<8) | devrev; + func = NULL; + id = (devid << 8) | devrev; - if (id==0x0302) {type="37c669"; func=show_parconfig_smsc37c669;} - else if (id==0x6582) type="37c665IR"; - else if (devid==0x65) type="37c665GT"; - else if (devid==0x66) type="37c666GT"; + if (id == 0x0302) { + type = "37c669"; + func = show_parconfig_smsc37c669; + } else if (id == 0x6582) + type = "37c665IR"; + else if (devid == 0x65) + type = "37c665GT"; + else if (devid == 0x66) + type = "37c666GT"; if (verbose_probing) printk(KERN_INFO "SMSC chip at EFER=0x%x " @@ -1407,148 +1465,165 @@ static void __devinit decode_smsc(int efer, int key, int devid, int devrev) efer, key, devid, devrev, type); if (func) - func(efer,key); + func(efer, key); } static void __devinit winbond_check(int io, int key) { - int devid,devrev,oldid,x_devid,x_devrev,x_oldid; + int origval, devid, devrev, oldid, x_devid, x_devrev, x_oldid; if (!request_region(io, 3, __func__)) return; - /* First probe without key */ - outb(0x20,io); - x_devid=inb(io+1); - outb(0x21,io); - x_devrev=inb(io+1); - outb(0x09,io); - x_oldid=inb(io+1); + origval = inb(io); /* Save original value */ - outb(key,io); - outb(key,io); /* Write Magic Sequence to EFER, extended - funtion enable register */ - outb(0x20,io); /* Write EFIR, extended function index register */ - devid=inb(io+1); /* Read EFDR, extended function data register */ - outb(0x21,io); - devrev=inb(io+1); - outb(0x09,io); - oldid=inb(io+1); - outb(0xaa,io); /* Magic Seal */ + /* First probe without key */ + outb(0x20, io); + x_devid = inb(io + 1); + outb(0x21, io); + x_devrev = inb(io + 1); + outb(0x09, io); + x_oldid = inb(io + 1); + + outb(key, io); + outb(key, io); /* Write Magic Sequence to EFER, extended + funtion enable register */ + outb(0x20, io); /* Write EFIR, extended function index register */ + devid = inb(io + 1); /* Read EFDR, extended function data register */ + outb(0x21, io); + devrev = inb(io + 1); + outb(0x09, io); + oldid = inb(io + 1); + outb(0xaa, io); /* Magic Seal */ + + outb(origval, io); /* in case we poked some entirely different hardware */ if ((x_devid == devid) && (x_devrev == devrev) && (x_oldid == oldid)) goto out; /* protection against false positives */ - decode_winbond(io,key,devid,devrev,oldid); + decode_winbond(io, key, devid, devrev, oldid); out: release_region(io, 3); } -static void __devinit winbond_check2(int io,int key) +static void __devinit winbond_check2(int io, int key) { - int devid,devrev,oldid,x_devid,x_devrev,x_oldid; + int origval[3], devid, devrev, oldid, x_devid, x_devrev, x_oldid; if (!request_region(io, 3, __func__)) return; + origval[0] = inb(io); /* Save original values */ + origval[1] = inb(io + 1); + origval[2] = inb(io + 2); + /* First probe without the key */ - outb(0x20,io+2); - x_devid=inb(io+2); - outb(0x21,io+1); - x_devrev=inb(io+2); - outb(0x09,io+1); - x_oldid=inb(io+2); + outb(0x20, io + 2); + x_devid = inb(io + 2); + outb(0x21, io + 1); + x_devrev = inb(io + 2); + outb(0x09, io + 1); + x_oldid = inb(io + 2); - outb(key,io); /* Write Magic Byte to EFER, extended - funtion enable register */ - outb(0x20,io+2); /* Write EFIR, extended function index register */ - devid=inb(io+2); /* Read EFDR, extended function data register */ - outb(0x21,io+1); - devrev=inb(io+2); - outb(0x09,io+1); - oldid=inb(io+2); - outb(0xaa,io); /* Magic Seal */ + outb(key, io); /* Write Magic Byte to EFER, extended + funtion enable register */ + outb(0x20, io + 2); /* Write EFIR, extended function index register */ + devid = inb(io + 2); /* Read EFDR, extended function data register */ + outb(0x21, io + 1); + devrev = inb(io + 2); + outb(0x09, io + 1); + oldid = inb(io + 2); + outb(0xaa, io); /* Magic Seal */ - if ((x_devid == devid) && (x_devrev == devrev) && (x_oldid == oldid)) + outb(origval[0], io); /* in case we poked some entirely different hardware */ + outb(origval[1], io + 1); + outb(origval[2], io + 2); + + if (x_devid == devid && x_devrev == devrev && x_oldid == oldid) goto out; /* protection against false positives */ - decode_winbond(io,key,devid,devrev,oldid); + decode_winbond(io, key, devid, devrev, oldid); out: release_region(io, 3); } static void __devinit smsc_check(int io, int key) { - int id,rev,oldid,oldrev,x_id,x_rev,x_oldid,x_oldrev; + int origval, id, rev, oldid, oldrev, x_id, x_rev, x_oldid, x_oldrev; if (!request_region(io, 3, __func__)) return; + origval = inb(io); /* Save original value */ + /* First probe without the key */ - outb(0x0d,io); - x_oldid=inb(io+1); - outb(0x0e,io); - x_oldrev=inb(io+1); - outb(0x20,io); - x_id=inb(io+1); - outb(0x21,io); - x_rev=inb(io+1); + outb(0x0d, io); + x_oldid = inb(io + 1); + outb(0x0e, io); + x_oldrev = inb(io + 1); + outb(0x20, io); + x_id = inb(io + 1); + outb(0x21, io); + x_rev = inb(io + 1); - outb(key,io); - outb(key,io); /* Write Magic Sequence to EFER, extended - funtion enable register */ - outb(0x0d,io); /* Write EFIR, extended function index register */ - oldid=inb(io+1); /* Read EFDR, extended function data register */ - outb(0x0e,io); - oldrev=inb(io+1); - outb(0x20,io); - id=inb(io+1); - outb(0x21,io); - rev=inb(io+1); - outb(0xaa,io); /* Magic Seal */ + outb(key, io); + outb(key, io); /* Write Magic Sequence to EFER, extended + funtion enable register */ + outb(0x0d, io); /* Write EFIR, extended function index register */ + oldid = inb(io + 1); /* Read EFDR, extended function data register */ + outb(0x0e, io); + oldrev = inb(io + 1); + outb(0x20, io); + id = inb(io + 1); + outb(0x21, io); + rev = inb(io + 1); + outb(0xaa, io); /* Magic Seal */ - if ((x_id == id) && (x_oldrev == oldrev) && - (x_oldid == oldid) && (x_rev == rev)) + outb(origval, io); /* in case we poked some entirely different hardware */ + + if (x_id == id && x_oldrev == oldrev && + x_oldid == oldid && x_rev == rev) goto out; /* protection against false positives */ - decode_smsc(io,key,oldid,oldrev); + decode_smsc(io, key, oldid, oldrev); out: release_region(io, 3); } -static void __devinit detect_and_report_winbond (void) -{ +static void __devinit detect_and_report_winbond(void) +{ if (verbose_probing) printk(KERN_DEBUG "Winbond Super-IO detection, now testing ports 3F0,370,250,4E,2E ...\n"); - winbond_check(0x3f0,0x87); - winbond_check(0x370,0x87); - winbond_check(0x2e ,0x87); - winbond_check(0x4e ,0x87); - winbond_check(0x3f0,0x86); - winbond_check2(0x250,0x88); - winbond_check2(0x250,0x89); + winbond_check(0x3f0, 0x87); + winbond_check(0x370, 0x87); + winbond_check(0x2e , 0x87); + winbond_check(0x4e , 0x87); + winbond_check(0x3f0, 0x86); + winbond_check2(0x250, 0x88); + winbond_check2(0x250, 0x89); } -static void __devinit detect_and_report_smsc (void) +static void __devinit detect_and_report_smsc(void) { if (verbose_probing) printk(KERN_DEBUG "SMSC Super-IO detection, now testing Ports 2F0, 370 ...\n"); - smsc_check(0x3f0,0x55); - smsc_check(0x370,0x55); - smsc_check(0x3f0,0x44); - smsc_check(0x370,0x44); + smsc_check(0x3f0, 0x55); + smsc_check(0x370, 0x55); + smsc_check(0x3f0, 0x44); + smsc_check(0x370, 0x44); } static void __devinit detect_and_report_it87(void) { u16 dev; - u8 r; + u8 origval, r; if (verbose_probing) printk(KERN_DEBUG "IT8705 Super-IO detection, now testing port 2E ...\n"); - if (!request_region(0x2e, 1, __func__)) + if (!request_region(0x2e, 2, __func__)) return; + origval = inb(0x2e); /* Save original value */ outb(0x87, 0x2e); outb(0x01, 0x2e); outb(0x55, 0x2e); @@ -1568,39 +1643,46 @@ static void __devinit detect_and_report_it87(void) outb(r | 8, 0x2F); outb(0x02, 0x2E); /* Lock */ outb(0x02, 0x2F); + } else { + outb(origval, 0x2e); /* Oops, sorry to disturb */ } - release_region(0x2e, 1); + release_region(0x2e, 2); } #endif /* CONFIG_PARPORT_PC_SUPERIO */ -static int get_superio_dma (struct parport *p) +static struct superio_struct *find_superio(struct parport *p) { - int i=0; - while( (superios[i].io != p->base) && (ibase) + return &superios[i]; + return NULL; +} + +static int get_superio_dma(struct parport *p) +{ + struct superio_struct *s = find_superio(p); + if (s) + return s->dma; return PARPORT_DMA_NONE; } -static int get_superio_irq (struct parport *p) +static int get_superio_irq(struct parport *p) { - int i=0; - while( (superios[i].io != p->base) && (iirq; + return PARPORT_IRQ_NONE; } - + /* --- Mode detection ------------------------------------- */ /* * Checks for port existence, all ports support SPP MODE - * Returns: + * Returns: * 0 : No parallel port at this address - * PARPORT_MODE_PCSPP : SPP port detected + * PARPORT_MODE_PCSPP : SPP port detected * (if the user specified an ioport himself, * this shall always be the case!) * @@ -1610,7 +1692,7 @@ static int parport_SPP_supported(struct parport *pb) unsigned char r, w; /* - * first clear an eventually pending EPP timeout + * first clear an eventually pending EPP timeout * I (sailer@ife.ee.ethz.ch) have an SMSC chipset * that does not even respond to SPP cycles if an EPP * timeout is pending @@ -1619,19 +1701,19 @@ static int parport_SPP_supported(struct parport *pb) /* Do a simple read-write test to make sure the port exists. */ w = 0xc; - outb (w, CONTROL (pb)); + outb(w, CONTROL(pb)); /* Is there a control register that we can read from? Some * ports don't allow reads, so read_control just returns a * software copy. Some ports _do_ allow reads, so bypass the * software copy here. In addition, some bits aren't * writable. */ - r = inb (CONTROL (pb)); + r = inb(CONTROL(pb)); if ((r & 0xf) == w) { w = 0xe; - outb (w, CONTROL (pb)); - r = inb (CONTROL (pb)); - outb (0xc, CONTROL (pb)); + outb(w, CONTROL(pb)); + r = inb(CONTROL(pb)); + outb(0xc, CONTROL(pb)); if ((r & 0xf) == w) return PARPORT_MODE_PCSPP; } @@ -1639,18 +1721,18 @@ static int parport_SPP_supported(struct parport *pb) if (user_specified) /* That didn't work, but the user thinks there's a * port here. */ - printk (KERN_INFO "parport 0x%lx (WARNING): CTR: " + printk(KERN_INFO "parport 0x%lx (WARNING): CTR: " "wrote 0x%02x, read 0x%02x\n", pb->base, w, r); /* Try the data register. The data lines aren't tri-stated at * this stage, so we expect back what we wrote. */ w = 0xaa; - parport_pc_write_data (pb, w); - r = parport_pc_read_data (pb); + parport_pc_write_data(pb, w); + r = parport_pc_read_data(pb); if (r == w) { w = 0x55; - parport_pc_write_data (pb, w); - r = parport_pc_read_data (pb); + parport_pc_write_data(pb, w); + r = parport_pc_read_data(pb); if (r == w) return PARPORT_MODE_PCSPP; } @@ -1658,9 +1740,9 @@ static int parport_SPP_supported(struct parport *pb) if (user_specified) { /* Didn't work, but the user is convinced this is the * place. */ - printk (KERN_INFO "parport 0x%lx (WARNING): DATA: " + printk(KERN_INFO "parport 0x%lx (WARNING): DATA: " "wrote 0x%02x, read 0x%02x\n", pb->base, w, r); - printk (KERN_INFO "parport 0x%lx: You gave this address, " + printk(KERN_INFO "parport 0x%lx: You gave this address, " "but there is probably no parallel port there!\n", pb->base); } @@ -1691,33 +1773,33 @@ static int parport_ECR_present(struct parport *pb) struct parport_pc_private *priv = pb->private_data; unsigned char r = 0xc; - outb (r, CONTROL (pb)); - if ((inb (ECONTROL (pb)) & 0x3) == (r & 0x3)) { - outb (r ^ 0x2, CONTROL (pb)); /* Toggle bit 1 */ + outb(r, CONTROL(pb)); + if ((inb(ECONTROL(pb)) & 0x3) == (r & 0x3)) { + outb(r ^ 0x2, CONTROL(pb)); /* Toggle bit 1 */ - r = inb (CONTROL (pb)); - if ((inb (ECONTROL (pb)) & 0x2) == (r & 0x2)) + r = inb(CONTROL(pb)); + if ((inb(ECONTROL(pb)) & 0x2) == (r & 0x2)) goto no_reg; /* Sure that no ECR register exists */ } - - if ((inb (ECONTROL (pb)) & 0x3 ) != 0x1) + + if ((inb(ECONTROL(pb)) & 0x3) != 0x1) goto no_reg; - ECR_WRITE (pb, 0x34); - if (inb (ECONTROL (pb)) != 0x35) + ECR_WRITE(pb, 0x34); + if (inb(ECONTROL(pb)) != 0x35) goto no_reg; priv->ecr = 1; - outb (0xc, CONTROL (pb)); - + outb(0xc, CONTROL(pb)); + /* Go to mode 000 */ - frob_set_mode (pb, ECR_SPP); + frob_set_mode(pb, ECR_SPP); return 1; no_reg: - outb (0xc, CONTROL (pb)); - return 0; + outb(0xc, CONTROL(pb)); + return 0; } #ifdef CONFIG_PARPORT_1284 @@ -1727,7 +1809,7 @@ static int parport_ECR_present(struct parport *pb) * allows us to read data from the data lines. In theory we would get back * 0xff but any peripheral attached to the port may drag some or all of the * lines down to zero. So if we get back anything that isn't the contents - * of the data register we deem PS/2 support to be present. + * of the data register we deem PS/2 support to be present. * * Some SPP ports have "half PS/2" ability - you can't turn off the line * drivers, but an external peripheral with sufficiently beefy drivers of @@ -1735,26 +1817,28 @@ static int parport_ECR_present(struct parport *pb) * where they can then be read back as normal. Ports with this property * and the right type of device attached are likely to fail the SPP test, * (as they will appear to have stuck bits) and so the fact that they might - * be misdetected here is rather academic. + * be misdetected here is rather academic. */ static int parport_PS2_supported(struct parport *pb) { int ok = 0; - + clear_epp_timeout(pb); /* try to tri-state the buffer */ - parport_pc_data_reverse (pb); - + parport_pc_data_reverse(pb); + parport_pc_write_data(pb, 0x55); - if (parport_pc_read_data(pb) != 0x55) ok++; + if (parport_pc_read_data(pb) != 0x55) + ok++; parport_pc_write_data(pb, 0xaa); - if (parport_pc_read_data(pb) != 0xaa) ok++; + if (parport_pc_read_data(pb) != 0xaa) + ok++; /* cancel input mode */ - parport_pc_data_forward (pb); + parport_pc_data_forward(pb); if (ok) { pb->modes |= PARPORT_MODE_TRISTATE; @@ -1773,68 +1857,68 @@ static int parport_ECP_supported(struct parport *pb) int config, configb; int pword; struct parport_pc_private *priv = pb->private_data; - /* Translate ECP intrLine to ISA irq value */ - static const int intrline[]= { 0, 7, 9, 10, 11, 14, 15, 5 }; + /* Translate ECP intrLine to ISA irq value */ + static const int intrline[] = { 0, 7, 9, 10, 11, 14, 15, 5 }; /* If there is no ECR, we have no hope of supporting ECP. */ if (!priv->ecr) return 0; /* Find out FIFO depth */ - ECR_WRITE (pb, ECR_SPP << 5); /* Reset FIFO */ - ECR_WRITE (pb, ECR_TST << 5); /* TEST FIFO */ - for (i=0; i < 1024 && !(inb (ECONTROL (pb)) & 0x02); i++) - outb (0xaa, FIFO (pb)); + ECR_WRITE(pb, ECR_SPP << 5); /* Reset FIFO */ + ECR_WRITE(pb, ECR_TST << 5); /* TEST FIFO */ + for (i = 0; i < 1024 && !(inb(ECONTROL(pb)) & 0x02); i++) + outb(0xaa, FIFO(pb)); /* * Using LGS chipset it uses ECR register, but * it doesn't support ECP or FIFO MODE */ if (i == 1024) { - ECR_WRITE (pb, ECR_SPP << 5); + ECR_WRITE(pb, ECR_SPP << 5); return 0; } priv->fifo_depth = i; if (verbose_probing) - printk (KERN_DEBUG "0x%lx: FIFO is %d bytes\n", pb->base, i); + printk(KERN_DEBUG "0x%lx: FIFO is %d bytes\n", pb->base, i); /* Find out writeIntrThreshold */ - frob_econtrol (pb, 1<<2, 1<<2); - frob_econtrol (pb, 1<<2, 0); + frob_econtrol(pb, 1<<2, 1<<2); + frob_econtrol(pb, 1<<2, 0); for (i = 1; i <= priv->fifo_depth; i++) { - inb (FIFO (pb)); - udelay (50); - if (inb (ECONTROL (pb)) & (1<<2)) + inb(FIFO(pb)); + udelay(50); + if (inb(ECONTROL(pb)) & (1<<2)) break; } if (i <= priv->fifo_depth) { if (verbose_probing) - printk (KERN_DEBUG "0x%lx: writeIntrThreshold is %d\n", + printk(KERN_DEBUG "0x%lx: writeIntrThreshold is %d\n", pb->base, i); } else /* Number of bytes we know we can write if we get an - interrupt. */ + interrupt. */ i = 0; priv->writeIntrThreshold = i; /* Find out readIntrThreshold */ - frob_set_mode (pb, ECR_PS2); /* Reset FIFO and enable PS2 */ - parport_pc_data_reverse (pb); /* Must be in PS2 mode */ - frob_set_mode (pb, ECR_TST); /* Test FIFO */ - frob_econtrol (pb, 1<<2, 1<<2); - frob_econtrol (pb, 1<<2, 0); + frob_set_mode(pb, ECR_PS2); /* Reset FIFO and enable PS2 */ + parport_pc_data_reverse(pb); /* Must be in PS2 mode */ + frob_set_mode(pb, ECR_TST); /* Test FIFO */ + frob_econtrol(pb, 1<<2, 1<<2); + frob_econtrol(pb, 1<<2, 0); for (i = 1; i <= priv->fifo_depth; i++) { - outb (0xaa, FIFO (pb)); - if (inb (ECONTROL (pb)) & (1<<2)) + outb(0xaa, FIFO(pb)); + if (inb(ECONTROL(pb)) & (1<<2)) break; } if (i <= priv->fifo_depth) { if (verbose_probing) - printk (KERN_INFO "0x%lx: readIntrThreshold is %d\n", + printk(KERN_INFO "0x%lx: readIntrThreshold is %d\n", pb->base, i); } else /* Number of bytes we can read if we get an interrupt. */ @@ -1842,23 +1926,23 @@ static int parport_ECP_supported(struct parport *pb) priv->readIntrThreshold = i; - ECR_WRITE (pb, ECR_SPP << 5); /* Reset FIFO */ - ECR_WRITE (pb, 0xf4); /* Configuration mode */ - config = inb (CONFIGA (pb)); + ECR_WRITE(pb, ECR_SPP << 5); /* Reset FIFO */ + ECR_WRITE(pb, 0xf4); /* Configuration mode */ + config = inb(CONFIGA(pb)); pword = (config >> 4) & 0x7; switch (pword) { case 0: pword = 2; - printk (KERN_WARNING "0x%lx: Unsupported pword size!\n", + printk(KERN_WARNING "0x%lx: Unsupported pword size!\n", pb->base); break; case 2: pword = 4; - printk (KERN_WARNING "0x%lx: Unsupported pword size!\n", + printk(KERN_WARNING "0x%lx: Unsupported pword size!\n", pb->base); break; default: - printk (KERN_WARNING "0x%lx: Unknown implementation ID\n", + printk(KERN_WARNING "0x%lx: Unknown implementation ID\n", pb->base); /* Assume 1 */ case 1: @@ -1867,28 +1951,29 @@ static int parport_ECP_supported(struct parport *pb) priv->pword = pword; if (verbose_probing) { - printk (KERN_DEBUG "0x%lx: PWord is %d bits\n", pb->base, 8 * pword); - - printk (KERN_DEBUG "0x%lx: Interrupts are ISA-%s\n", pb->base, + printk(KERN_DEBUG "0x%lx: PWord is %d bits\n", + pb->base, 8 * pword); + + printk(KERN_DEBUG "0x%lx: Interrupts are ISA-%s\n", pb->base, config & 0x80 ? "Level" : "Pulses"); - configb = inb (CONFIGB (pb)); - printk (KERN_DEBUG "0x%lx: ECP port cfgA=0x%02x cfgB=0x%02x\n", + configb = inb(CONFIGB(pb)); + printk(KERN_DEBUG "0x%lx: ECP port cfgA=0x%02x cfgB=0x%02x\n", pb->base, config, configb); - printk (KERN_DEBUG "0x%lx: ECP settings irq=", pb->base); - if ((configb >>3) & 0x07) - printk("%d",intrline[(configb >>3) & 0x07]); + printk(KERN_DEBUG "0x%lx: ECP settings irq=", pb->base); + if ((configb >> 3) & 0x07) + printk("%d", intrline[(configb >> 3) & 0x07]); else printk(""); - printk (" dma="); - if( (configb & 0x03 ) == 0x00) + printk(" dma="); + if ((configb & 0x03) == 0x00) printk("\n"); else - printk("%d\n",configb & 0x07); + printk("%d\n", configb & 0x07); } /* Go back to mode 000 */ - frob_set_mode (pb, ECR_SPP); + frob_set_mode(pb, ECR_SPP); return 1; } @@ -1903,10 +1988,10 @@ static int parport_ECPPS2_supported(struct parport *pb) if (!priv->ecr) return 0; - oecr = inb (ECONTROL (pb)); - ECR_WRITE (pb, ECR_PS2 << 5); + oecr = inb(ECONTROL(pb)); + ECR_WRITE(pb, ECR_PS2 << 5); result = parport_PS2_supported(pb); - ECR_WRITE (pb, oecr); + ECR_WRITE(pb, oecr); return result; } @@ -1930,16 +2015,15 @@ static int parport_EPP_supported(struct parport *pb) */ /* If EPP timeout bit clear then EPP available */ - if (!clear_epp_timeout(pb)) { + if (!clear_epp_timeout(pb)) return 0; /* No way to clear timeout */ - } /* Check for Intel bug. */ if (priv->ecr) { unsigned char i; for (i = 0x00; i < 0x80; i += 0x20) { - ECR_WRITE (pb, i); - if (clear_epp_timeout (pb)) { + ECR_WRITE(pb, i); + if (clear_epp_timeout(pb)) { /* Phony EPP in ECP. */ return 0; } @@ -1963,17 +2047,16 @@ static int parport_ECPEPP_supported(struct parport *pb) int result; unsigned char oecr; - if (!priv->ecr) { + if (!priv->ecr) return 0; - } - oecr = inb (ECONTROL (pb)); + oecr = inb(ECONTROL(pb)); /* Search for SMC style EPP+ECP mode */ - ECR_WRITE (pb, 0x80); - outb (0x04, CONTROL (pb)); + ECR_WRITE(pb, 0x80); + outb(0x04, CONTROL(pb)); result = parport_EPP_supported(pb); - ECR_WRITE (pb, oecr); + ECR_WRITE(pb, oecr); if (result) { /* Set up access functions to use ECP+EPP hardware. */ @@ -1991,11 +2074,25 @@ static int parport_ECPEPP_supported(struct parport *pb) /* Don't bother probing for modes we know we won't use. */ static int __devinit parport_PS2_supported(struct parport *pb) { return 0; } #ifdef CONFIG_PARPORT_PC_FIFO -static int parport_ECP_supported(struct parport *pb) { return 0; } +static int parport_ECP_supported(struct parport *pb) +{ + return 0; +} #endif -static int __devinit parport_EPP_supported(struct parport *pb) { return 0; } -static int __devinit parport_ECPEPP_supported(struct parport *pb){return 0;} -static int __devinit parport_ECPPS2_supported(struct parport *pb){return 0;} +static int __devinit parport_EPP_supported(struct parport *pb) +{ + return 0; +} + +static int __devinit parport_ECPEPP_supported(struct parport *pb) +{ + return 0; +} + +static int __devinit parport_ECPPS2_supported(struct parport *pb) +{ + return 0; +} #endif /* No IEEE 1284 support */ @@ -2005,17 +2102,17 @@ static int __devinit parport_ECPPS2_supported(struct parport *pb){return 0;} static int programmable_irq_support(struct parport *pb) { int irq, intrLine; - unsigned char oecr = inb (ECONTROL (pb)); + unsigned char oecr = inb(ECONTROL(pb)); static const int lookup[8] = { PARPORT_IRQ_NONE, 7, 9, 10, 11, 14, 15, 5 }; - ECR_WRITE (pb, ECR_CNF << 5); /* Configuration MODE */ + ECR_WRITE(pb, ECR_CNF << 5); /* Configuration MODE */ - intrLine = (inb (CONFIGB (pb)) >> 3) & 0x07; + intrLine = (inb(CONFIGB(pb)) >> 3) & 0x07; irq = lookup[intrLine]; - ECR_WRITE (pb, oecr); + ECR_WRITE(pb, oecr); return irq; } @@ -2025,17 +2122,17 @@ static int irq_probe_ECP(struct parport *pb) unsigned long irqs; irqs = probe_irq_on(); - - ECR_WRITE (pb, ECR_SPP << 5); /* Reset FIFO */ - ECR_WRITE (pb, (ECR_TST << 5) | 0x04); - ECR_WRITE (pb, ECR_TST << 5); + + ECR_WRITE(pb, ECR_SPP << 5); /* Reset FIFO */ + ECR_WRITE(pb, (ECR_TST << 5) | 0x04); + ECR_WRITE(pb, ECR_TST << 5); /* If Full FIFO sure that writeIntrThreshold is generated */ - for (i=0; i < 1024 && !(inb (ECONTROL (pb)) & 0x02) ; i++) - outb (0xaa, FIFO (pb)); - + for (i = 0; i < 1024 && !(inb(ECONTROL(pb)) & 0x02) ; i++) + outb(0xaa, FIFO(pb)); + pb->irq = probe_irq_off(irqs); - ECR_WRITE (pb, ECR_SPP << 5); + ECR_WRITE(pb, ECR_SPP << 5); if (pb->irq <= 0) pb->irq = PARPORT_IRQ_NONE; @@ -2045,7 +2142,7 @@ static int irq_probe_ECP(struct parport *pb) /* * This detection seems that only works in National Semiconductors - * This doesn't work in SMC, LGS, and Winbond + * This doesn't work in SMC, LGS, and Winbond */ static int irq_probe_EPP(struct parport *pb) { @@ -2056,16 +2153,16 @@ static int irq_probe_EPP(struct parport *pb) unsigned char oecr; if (pb->modes & PARPORT_MODE_PCECR) - oecr = inb (ECONTROL (pb)); + oecr = inb(ECONTROL(pb)); irqs = probe_irq_on(); if (pb->modes & PARPORT_MODE_PCECR) - frob_econtrol (pb, 0x10, 0x10); - + frob_econtrol(pb, 0x10, 0x10); + clear_epp_timeout(pb); - parport_pc_frob_control (pb, 0x20, 0x20); - parport_pc_frob_control (pb, 0x10, 0x10); + parport_pc_frob_control(pb, 0x20, 0x20); + parport_pc_frob_control(pb, 0x10, 0x10); clear_epp_timeout(pb); /* Device isn't expecting an EPP read @@ -2074,9 +2171,9 @@ static int irq_probe_EPP(struct parport *pb) parport_pc_read_epp(pb); udelay(20); - pb->irq = probe_irq_off (irqs); + pb->irq = probe_irq_off(irqs); if (pb->modes & PARPORT_MODE_PCECR) - ECR_WRITE (pb, oecr); + ECR_WRITE(pb, oecr); parport_pc_write_control(pb, 0xc); if (pb->irq <= 0) @@ -2133,28 +2230,28 @@ static int parport_irq_probe(struct parport *pb) /* --- DMA detection -------------------------------------- */ /* Only if chipset conforms to ECP ISA Interface Standard */ -static int programmable_dma_support (struct parport *p) +static int programmable_dma_support(struct parport *p) { - unsigned char oecr = inb (ECONTROL (p)); + unsigned char oecr = inb(ECONTROL(p)); int dma; - frob_set_mode (p, ECR_CNF); - - dma = inb (CONFIGB(p)) & 0x07; + frob_set_mode(p, ECR_CNF); + + dma = inb(CONFIGB(p)) & 0x07; /* 000: Indicates jumpered 8-bit DMA if read-only. 100: Indicates jumpered 16-bit DMA if read-only. */ if ((dma & 0x03) == 0) dma = PARPORT_DMA_NONE; - ECR_WRITE (p, oecr); + ECR_WRITE(p, oecr); return dma; } -static int parport_dma_probe (struct parport *p) +static int parport_dma_probe(struct parport *p) { const struct parport_pc_private *priv = p->private_data; - if (priv->ecr) - p->dma = programmable_dma_support(p); /* ask ECP chipset first */ + if (priv->ecr) /* ask ECP chipset first */ + p->dma = programmable_dma_support(p); if (p->dma == PARPORT_DMA_NONE) { /* ask known Super-IO chips proper, although these claim ECP compatible, some don't report their DMA @@ -2193,6 +2290,9 @@ struct parport *parport_pc_probe_port(unsigned long int base, if (IS_ERR(pdev)) return NULL; dev = &pdev->dev; + + dev->coherent_dma_mask = DMA_BIT_MASK(24); + dev->dma_mask = &dev->coherent_dma_mask; } ops = kmalloc(sizeof(struct parport_operations), GFP_KERNEL); @@ -2212,7 +2312,7 @@ struct parport *parport_pc_probe_port(unsigned long int base, if (!base_res) goto out4; - memcpy(ops, &parport_pc_ops, sizeof (struct parport_operations)); + memcpy(ops, &parport_pc_ops, sizeof(struct parport_operations)); priv->ctr = 0xc; priv->ctr_writable = ~0x10; priv->ecr = 0; @@ -2239,7 +2339,7 @@ struct parport *parport_pc_probe_port(unsigned long int base, if (!parport_EPP_supported(p)) parport_ECPEPP_supported(p); } - if (!parport_SPP_supported (p)) + if (!parport_SPP_supported(p)) /* No port. */ goto out5; if (priv->ecr) @@ -2247,7 +2347,7 @@ struct parport *parport_pc_probe_port(unsigned long int base, else parport_PS2_supported(p); - p->size = (p->modes & PARPORT_MODE_EPP)?8:3; + p->size = (p->modes & PARPORT_MODE_EPP) ? 8 : 3; printk(KERN_INFO "%s: PC-style at 0x%lx", p->name, p->base); if (p->base_hi && priv->ecr) @@ -2271,7 +2371,7 @@ struct parport *parport_pc_probe_port(unsigned long int base, } } if (p->dma == PARPORT_DMA_AUTO) /* To use DMA, giving the irq - is mandatory (see above) */ + is mandatory (see above) */ p->dma = PARPORT_DMA_NONE; #ifdef CONFIG_PARPORT_PC_FIFO @@ -2288,16 +2388,23 @@ struct parport *parport_pc_probe_port(unsigned long int base, if (p->dma != PARPORT_DMA_NONE) { printk(", dma %d", p->dma); p->modes |= PARPORT_MODE_DMA; - } - else printk(", using FIFO"); - } - else + } else + printk(", using FIFO"); + } else /* We can't use the DMA channel after all. */ p->dma = PARPORT_DMA_NONE; #endif /* Allowed to use FIFO/DMA */ printk(" ["); -#define printmode(x) {if(p->modes&PARPORT_MODE_##x){printk("%s%s",f?",":"",#x);f++;}} + +#define printmode(x) \ + {\ + if (p->modes & PARPORT_MODE_##x) {\ + printk("%s%s", f ? "," : "", #x);\ + f++;\ + } \ + } + { int f = 0; printmode(PCSPP); @@ -2309,10 +2416,10 @@ struct parport *parport_pc_probe_port(unsigned long int base, } #undef printmode #ifndef CONFIG_PARPORT_1284 - printk ("(,...)"); + printk("(,...)"); #endif /* CONFIG_PARPORT_1284 */ printk("]\n"); - if (probedirq != PARPORT_IRQ_NONE) + if (probedirq != PARPORT_IRQ_NONE) printk(KERN_INFO "%s: irq %d detected\n", p->name, probedirq); /* If No ECP release the ports grabbed above. */ @@ -2328,7 +2435,7 @@ struct parport *parport_pc_probe_port(unsigned long int base, if (p->irq != PARPORT_IRQ_NONE) { if (request_irq(p->irq, parport_irq_handler, irqflags, p->name, p)) { - printk (KERN_WARNING "%s: irq %d in use, " + printk(KERN_WARNING "%s: irq %d in use, " "resorting to polled operation\n", p->name, p->irq); p->irq = PARPORT_IRQ_NONE; @@ -2338,8 +2445,8 @@ struct parport *parport_pc_probe_port(unsigned long int base, #ifdef CONFIG_PARPORT_PC_FIFO #ifdef HAS_DMA if (p->dma != PARPORT_DMA_NONE) { - if (request_dma (p->dma, p->name)) { - printk (KERN_WARNING "%s: dma %d in use, " + if (request_dma(p->dma, p->name)) { + printk(KERN_WARNING "%s: dma %d in use, " "resorting to PIO operation\n", p->name, p->dma); p->dma = PARPORT_DMA_NONE; @@ -2349,8 +2456,8 @@ struct parport *parport_pc_probe_port(unsigned long int base, PAGE_SIZE, &priv->dma_handle, GFP_KERNEL); - if (! priv->dma_buf) { - printk (KERN_WARNING "%s: " + if (!priv->dma_buf) { + printk(KERN_WARNING "%s: " "cannot get buffer for DMA, " "resorting to PIO operation\n", p->name); @@ -2369,10 +2476,10 @@ struct parport *parport_pc_probe_port(unsigned long int base, * Put the ECP detected port in PS2 mode. * Do this also for ports that have ECR but don't do ECP. */ - ECR_WRITE (p, 0x34); + ECR_WRITE(p, 0x34); parport_pc_write_data(p, 0); - parport_pc_data_forward (p); + parport_pc_data_forward(p); /* Now that we've told the sharing engine about the port, and found out its characteristics, let the high-level drivers @@ -2380,7 +2487,7 @@ struct parport *parport_pc_probe_port(unsigned long int base, spin_lock(&ports_lock); list_add(&priv->list, &ports_list); spin_unlock(&ports_lock); - parport_announce_port (p); + parport_announce_port(p); return p; @@ -2393,18 +2500,17 @@ out5: out4: parport_put_port(p); out3: - kfree (priv); + kfree(priv); out2: - kfree (ops); + kfree(ops); out1: if (pdev) platform_device_unregister(pdev); return NULL; } +EXPORT_SYMBOL(parport_pc_probe_port); -EXPORT_SYMBOL (parport_pc_probe_port); - -void parport_pc_unregister_port (struct parport *p) +void parport_pc_unregister_port(struct parport *p) { struct parport_pc_private *priv = p->private_data; struct parport_operations *ops = p->ops; @@ -2430,17 +2536,16 @@ void parport_pc_unregister_port (struct parport *p) priv->dma_buf, priv->dma_handle); #endif - kfree (p->private_data); + kfree(p->private_data); parport_put_port(p); - kfree (ops); /* hope no-one cached it */ + kfree(ops); /* hope no-one cached it */ } - -EXPORT_SYMBOL (parport_pc_unregister_port); +EXPORT_SYMBOL(parport_pc_unregister_port); #ifdef CONFIG_PCI /* ITE support maintained by Rich Liu */ -static int __devinit sio_ite_8872_probe (struct pci_dev *pdev, int autoirq, +static int __devinit sio_ite_8872_probe(struct pci_dev *pdev, int autoirq, int autodma, const struct parport_pc_via_data *via) { @@ -2452,73 +2557,74 @@ static int __devinit sio_ite_8872_probe (struct pci_dev *pdev, int autoirq, int irq; int i; - DPRINTK (KERN_DEBUG "sio_ite_8872_probe()\n"); - - // make sure which one chip - for(i = 0; i < 5; i++) { + DPRINTK(KERN_DEBUG "sio_ite_8872_probe()\n"); + + /* make sure which one chip */ + for (i = 0; i < 5; i++) { base_res = request_region(inta_addr[i], 32, "it887x"); if (base_res) { int test; - pci_write_config_dword (pdev, 0x60, + pci_write_config_dword(pdev, 0x60, 0xe5000000 | inta_addr[i]); - pci_write_config_dword (pdev, 0x78, + pci_write_config_dword(pdev, 0x78, 0x00000000 | inta_addr[i]); - test = inb (inta_addr[i]); - if (test != 0xff) break; + test = inb(inta_addr[i]); + if (test != 0xff) + break; release_region(inta_addr[i], 0x8); } } - if(i >= 5) { - printk (KERN_INFO "parport_pc: cannot find ITE8872 INTA\n"); + if (i >= 5) { + printk(KERN_INFO "parport_pc: cannot find ITE8872 INTA\n"); return 0; } - type = inb (inta_addr[i] + 0x18); + type = inb(inta_addr[i] + 0x18); type &= 0x0f; switch (type) { case 0x2: - printk (KERN_INFO "parport_pc: ITE8871 found (1P)\n"); + printk(KERN_INFO "parport_pc: ITE8871 found (1P)\n"); ite8872set = 0x64200000; break; case 0xa: - printk (KERN_INFO "parport_pc: ITE8875 found (1P)\n"); + printk(KERN_INFO "parport_pc: ITE8875 found (1P)\n"); ite8872set = 0x64200000; break; case 0xe: - printk (KERN_INFO "parport_pc: ITE8872 found (2S1P)\n"); + printk(KERN_INFO "parport_pc: ITE8872 found (2S1P)\n"); ite8872set = 0x64e00000; break; case 0x6: - printk (KERN_INFO "parport_pc: ITE8873 found (1S)\n"); + printk(KERN_INFO "parport_pc: ITE8873 found (1S)\n"); return 0; case 0x8: - DPRINTK (KERN_DEBUG "parport_pc: ITE8874 found (2S)\n"); + DPRINTK(KERN_DEBUG "parport_pc: ITE8874 found (2S)\n"); return 0; default: - printk (KERN_INFO "parport_pc: unknown ITE887x\n"); - printk (KERN_INFO "parport_pc: please mail 'lspci -nvv' " + printk(KERN_INFO "parport_pc: unknown ITE887x\n"); + printk(KERN_INFO "parport_pc: please mail 'lspci -nvv' " "output to Rich.Liu@ite.com.tw\n"); return 0; } - pci_read_config_byte (pdev, 0x3c, &ite8872_irq); - pci_read_config_dword (pdev, 0x1c, &ite8872_lpt); + pci_read_config_byte(pdev, 0x3c, &ite8872_irq); + pci_read_config_dword(pdev, 0x1c, &ite8872_lpt); ite8872_lpt &= 0x0000ff00; - pci_read_config_dword (pdev, 0x20, &ite8872_lpthi); + pci_read_config_dword(pdev, 0x20, &ite8872_lpthi); ite8872_lpthi &= 0x0000ff00; - pci_write_config_dword (pdev, 0x6c, 0xe3000000 | ite8872_lpt); - pci_write_config_dword (pdev, 0x70, 0xe3000000 | ite8872_lpthi); - pci_write_config_dword (pdev, 0x80, (ite8872_lpthi<<16) | ite8872_lpt); - // SET SPP&EPP , Parallel Port NO DMA , Enable All Function - // SET Parallel IRQ - pci_write_config_dword (pdev, 0x9c, + pci_write_config_dword(pdev, 0x6c, 0xe3000000 | ite8872_lpt); + pci_write_config_dword(pdev, 0x70, 0xe3000000 | ite8872_lpthi); + pci_write_config_dword(pdev, 0x80, (ite8872_lpthi<<16) | ite8872_lpt); + /* SET SPP&EPP , Parallel Port NO DMA , Enable All Function */ + /* SET Parallel IRQ */ + pci_write_config_dword(pdev, 0x9c, ite8872set | (ite8872_irq * 0x11111)); - DPRINTK (KERN_DEBUG "ITE887x: The IRQ is %d.\n", ite8872_irq); - DPRINTK (KERN_DEBUG "ITE887x: The PARALLEL I/O port is 0x%x.\n", + DPRINTK(KERN_DEBUG "ITE887x: The IRQ is %d.\n", ite8872_irq); + DPRINTK(KERN_DEBUG "ITE887x: The PARALLEL I/O port is 0x%x.\n", ite8872_lpt); - DPRINTK (KERN_DEBUG "ITE887x: The PARALLEL I/O porthi is 0x%x.\n", + DPRINTK(KERN_DEBUG "ITE887x: The PARALLEL I/O porthi is 0x%x.\n", ite8872_lpthi); /* Let the user (or defaults) steer us away from interrupts */ @@ -2530,14 +2636,14 @@ static int __devinit sio_ite_8872_probe (struct pci_dev *pdev, int autoirq, * Release the resource so that parport_pc_probe_port can get it. */ release_resource(base_res); - if (parport_pc_probe_port (ite8872_lpt, ite8872_lpthi, + if (parport_pc_probe_port(ite8872_lpt, ite8872_lpthi, irq, PARPORT_DMA_NONE, &pdev->dev, 0)) { - printk (KERN_INFO + printk(KERN_INFO "parport_pc: ITE 8872 parallel port: io=0x%X", - ite8872_lpt); + ite8872_lpt); if (irq != PARPORT_IRQ_NONE) - printk (", irq=%d", irq); - printk ("\n"); + printk(", irq=%d", irq); + printk("\n"); return 1; } @@ -2546,7 +2652,7 @@ static int __devinit sio_ite_8872_probe (struct pci_dev *pdev, int autoirq, /* VIA 8231 support by Pavel Fedin based on VIA 686a support code by Jeff Garzik */ -static int __devinitdata parport_init_mode = 0; +static int __devinitdata parport_init_mode; /* Data for two known VIA chips */ static struct parport_pc_via_data via_686a_data __devinitdata = { @@ -2568,7 +2674,7 @@ static struct parport_pc_via_data via_8231_data __devinitdata = { 0xF6 }; -static int __devinit sio_via_probe (struct pci_dev *pdev, int autoirq, +static int __devinit sio_via_probe(struct pci_dev *pdev, int autoirq, int autodma, const struct parport_pc_via_data *via) { @@ -2580,38 +2686,38 @@ static int __devinit sio_via_probe (struct pci_dev *pdev, int autoirq, printk(KERN_DEBUG "parport_pc: VIA 686A/8231 detected\n"); - switch(parport_init_mode) - { + switch (parport_init_mode) { case 1: - printk(KERN_DEBUG "parport_pc: setting SPP mode\n"); - siofunc = VIA_FUNCTION_PARPORT_SPP; - break; + printk(KERN_DEBUG "parport_pc: setting SPP mode\n"); + siofunc = VIA_FUNCTION_PARPORT_SPP; + break; case 2: - printk(KERN_DEBUG "parport_pc: setting PS/2 mode\n"); - siofunc = VIA_FUNCTION_PARPORT_SPP; - ppcontrol = VIA_PARPORT_BIDIR; - break; + printk(KERN_DEBUG "parport_pc: setting PS/2 mode\n"); + siofunc = VIA_FUNCTION_PARPORT_SPP; + ppcontrol = VIA_PARPORT_BIDIR; + break; case 3: - printk(KERN_DEBUG "parport_pc: setting EPP mode\n"); - siofunc = VIA_FUNCTION_PARPORT_EPP; - ppcontrol = VIA_PARPORT_BIDIR; - have_epp = 1; - break; + printk(KERN_DEBUG "parport_pc: setting EPP mode\n"); + siofunc = VIA_FUNCTION_PARPORT_EPP; + ppcontrol = VIA_PARPORT_BIDIR; + have_epp = 1; + break; case 4: - printk(KERN_DEBUG "parport_pc: setting ECP mode\n"); - siofunc = VIA_FUNCTION_PARPORT_ECP; - ppcontrol = VIA_PARPORT_BIDIR; - break; + printk(KERN_DEBUG "parport_pc: setting ECP mode\n"); + siofunc = VIA_FUNCTION_PARPORT_ECP; + ppcontrol = VIA_PARPORT_BIDIR; + break; case 5: - printk(KERN_DEBUG "parport_pc: setting EPP+ECP mode\n"); - siofunc = VIA_FUNCTION_PARPORT_ECP; - ppcontrol = VIA_PARPORT_BIDIR|VIA_PARPORT_ECPEPP; - have_epp = 1; - break; - default: - printk(KERN_DEBUG "parport_pc: probing current configuration\n"); - siofunc = VIA_FUNCTION_PROBE; - break; + printk(KERN_DEBUG "parport_pc: setting EPP+ECP mode\n"); + siofunc = VIA_FUNCTION_PARPORT_ECP; + ppcontrol = VIA_PARPORT_BIDIR|VIA_PARPORT_ECPEPP; + have_epp = 1; + break; + default: + printk(KERN_DEBUG + "parport_pc: probing current configuration\n"); + siofunc = VIA_FUNCTION_PROBE; + break; } /* * unlock super i/o configuration @@ -2622,38 +2728,36 @@ static int __devinit sio_via_probe (struct pci_dev *pdev, int autoirq, /* Bits 1-0: Parallel Port Mode / Enable */ outb(via->viacfg_function, VIA_CONFIG_INDEX); - tmp = inb (VIA_CONFIG_DATA); + tmp = inb(VIA_CONFIG_DATA); /* Bit 5: EPP+ECP enable; bit 7: PS/2 bidirectional port enable */ outb(via->viacfg_parport_control, VIA_CONFIG_INDEX); - tmp2 = inb (VIA_CONFIG_DATA); - if (siofunc == VIA_FUNCTION_PROBE) - { - siofunc = tmp & VIA_FUNCTION_PARPORT_DISABLE; - ppcontrol = tmp2; + tmp2 = inb(VIA_CONFIG_DATA); + if (siofunc == VIA_FUNCTION_PROBE) { + siofunc = tmp & VIA_FUNCTION_PARPORT_DISABLE; + ppcontrol = tmp2; + } else { + tmp &= ~VIA_FUNCTION_PARPORT_DISABLE; + tmp |= siofunc; + outb(via->viacfg_function, VIA_CONFIG_INDEX); + outb(tmp, VIA_CONFIG_DATA); + tmp2 &= ~(VIA_PARPORT_BIDIR|VIA_PARPORT_ECPEPP); + tmp2 |= ppcontrol; + outb(via->viacfg_parport_control, VIA_CONFIG_INDEX); + outb(tmp2, VIA_CONFIG_DATA); } - else - { - tmp &= ~VIA_FUNCTION_PARPORT_DISABLE; - tmp |= siofunc; - outb(via->viacfg_function, VIA_CONFIG_INDEX); - outb(tmp, VIA_CONFIG_DATA); - tmp2 &= ~(VIA_PARPORT_BIDIR|VIA_PARPORT_ECPEPP); - tmp2 |= ppcontrol; - outb(via->viacfg_parport_control, VIA_CONFIG_INDEX); - outb(tmp2, VIA_CONFIG_DATA); - } - + /* Parallel Port I/O Base Address, bits 9-2 */ outb(via->viacfg_parport_base, VIA_CONFIG_INDEX); port1 = inb(VIA_CONFIG_DATA) << 2; - - printk (KERN_DEBUG "parport_pc: Current parallel port base: 0x%X\n",port1); - if ((port1 == 0x3BC) && have_epp) - { - outb(via->viacfg_parport_base, VIA_CONFIG_INDEX); - outb((0x378 >> 2), VIA_CONFIG_DATA); - printk(KERN_DEBUG "parport_pc: Parallel port base changed to 0x378\n"); - port1 = 0x378; + + printk(KERN_DEBUG "parport_pc: Current parallel port base: 0x%X\n", + port1); + if (port1 == 0x3BC && have_epp) { + outb(via->viacfg_parport_base, VIA_CONFIG_INDEX); + outb((0x378 >> 2), VIA_CONFIG_DATA); + printk(KERN_DEBUG + "parport_pc: Parallel port base changed to 0x378\n"); + port1 = 0x378; } /* @@ -2667,36 +2771,39 @@ static int __devinit sio_via_probe (struct pci_dev *pdev, int autoirq, printk(KERN_INFO "parport_pc: VIA parallel port disabled in BIOS\n"); return 0; } - + /* Bits 7-4: PnP Routing for Parallel Port IRQ */ pci_read_config_byte(pdev, via->via_pci_parport_irq_reg, &tmp); irq = ((tmp & VIA_IRQCONTROL_PARALLEL) >> 4); - if (siofunc == VIA_FUNCTION_PARPORT_ECP) - { - /* Bits 3-2: PnP Routing for Parallel Port DMA */ - pci_read_config_byte(pdev, via->via_pci_parport_dma_reg, &tmp); - dma = ((tmp & VIA_DMACONTROL_PARALLEL) >> 2); - } - else - /* if ECP not enabled, DMA is not enabled, assumed bogus 'dma' value */ - dma = PARPORT_DMA_NONE; + if (siofunc == VIA_FUNCTION_PARPORT_ECP) { + /* Bits 3-2: PnP Routing for Parallel Port DMA */ + pci_read_config_byte(pdev, via->via_pci_parport_dma_reg, &tmp); + dma = ((tmp & VIA_DMACONTROL_PARALLEL) >> 2); + } else + /* if ECP not enabled, DMA is not enabled, assumed + bogus 'dma' value */ + dma = PARPORT_DMA_NONE; /* Let the user (or defaults) steer us away from interrupts and DMA */ if (autoirq == PARPORT_IRQ_NONE) { - irq = PARPORT_IRQ_NONE; - dma = PARPORT_DMA_NONE; + irq = PARPORT_IRQ_NONE; + dma = PARPORT_DMA_NONE; } if (autodma == PARPORT_DMA_NONE) - dma = PARPORT_DMA_NONE; + dma = PARPORT_DMA_NONE; switch (port1) { - case 0x3bc: port2 = 0x7bc; break; - case 0x378: port2 = 0x778; break; - case 0x278: port2 = 0x678; break; + case 0x3bc: + port2 = 0x7bc; break; + case 0x378: + port2 = 0x778; break; + case 0x278: + port2 = 0x678; break; default: - printk(KERN_INFO "parport_pc: Weird VIA parport base 0x%X, ignoring\n", - port1); + printk(KERN_INFO + "parport_pc: Weird VIA parport base 0x%X, ignoring\n", + port1); return 0; } @@ -2714,17 +2821,17 @@ static int __devinit sio_via_probe (struct pci_dev *pdev, int autoirq, } /* finally, do the probe with values obtained */ - if (parport_pc_probe_port (port1, port2, irq, dma, &pdev->dev, 0)) { - printk (KERN_INFO + if (parport_pc_probe_port(port1, port2, irq, dma, &pdev->dev, 0)) { + printk(KERN_INFO "parport_pc: VIA parallel port: io=0x%X", port1); if (irq != PARPORT_IRQ_NONE) - printk (", irq=%d", irq); + printk(", irq=%d", irq); if (dma != PARPORT_DMA_NONE) - printk (", dma=%d", dma); - printk ("\n"); + printk(", dma=%d", dma); + printk("\n"); return 1; } - + printk(KERN_WARNING "parport_pc: Strange, can't probe VIA parallel port: io=0x%X, irq=%d, dma=%d\n", port1, irq, dma); return 0; @@ -2732,8 +2839,8 @@ static int __devinit sio_via_probe (struct pci_dev *pdev, int autoirq, enum parport_pc_sio_types { - sio_via_686a = 0, /* Via VT82C686A motherboard Super I/O */ - sio_via_8231, /* Via VT8231 south bridge integrated Super IO */ + sio_via_686a = 0, /* Via VT82C686A motherboard Super I/O */ + sio_via_8231, /* Via VT8231 south bridge integrated Super IO */ sio_ite_8872, last_sio }; @@ -2804,15 +2911,15 @@ enum parport_pc_pci_cards { }; -/* each element directly indexed from enum list, above +/* each element directly indexed from enum list, above * (but offset by last_sio) */ static struct parport_pc_pci { int numports; struct { /* BAR (base address registers) numbers in the config - space header */ + space header */ int lo; - int hi; /* -1 if not there, >6 for offset-method (max - BAR is 6) */ + int hi; + /* -1 if not there, >6 for offset-method (max BAR is 6) */ } addr[4]; /* If set, this is called immediately after pci_enable_device. @@ -2857,7 +2964,7 @@ static struct parport_pc_pci { /* timedia_4018 */ { 2, { { 0, 1 }, { 2, 3 }, } }, /* timedia_9018a */ { 2, { { 0, 1 }, { 2, 3 }, } }, /* SYBA uses fixed offsets in - a 1K io window */ + a 1K io window */ /* syba_2p_epp AP138B */ { 2, { { 0, 0x078 }, { 0, 0x178 }, } }, /* syba_1p_ecp W83787 */ { 1, { { 0, 0x078 }, } }, /* titan_010l */ { 1, { { 3, -1 }, } }, @@ -2873,11 +2980,14 @@ static struct parport_pc_pci { /* oxsemi_pcie_pport */ { 1, { { 0, 1 }, } }, /* aks_0100 */ { 1, { { 0, -1 }, } }, /* mobility_pp */ { 1, { { 0, 1 }, } }, - /* netmos_9705 */ { 1, { { 0, -1 }, } }, /* untested */ - /* netmos_9715 */ { 2, { { 0, 1 }, { 2, 3 },} }, /* untested */ - /* netmos_9755 */ { 2, { { 0, 1 }, { 2, 3 },} }, /* untested */ - /* netmos_9805 */ { 1, { { 0, -1 }, } }, /* untested */ - /* netmos_9815 */ { 2, { { 0, -1 }, { 2, -1 }, } }, /* untested */ + + /* The netmos entries below are untested */ + /* netmos_9705 */ { 1, { { 0, -1 }, } }, + /* netmos_9715 */ { 2, { { 0, 1 }, { 2, 3 },} }, + /* netmos_9755 */ { 2, { { 0, 1 }, { 2, 3 },} }, + /* netmos_9805 */ { 1, { { 0, -1 }, } }, + /* netmos_9815 */ { 2, { { 0, -1 }, { 2, -1 }, } }, + /* quatech_sppxp100 */ { 1, { { 0, 1 }, } }, }; @@ -2906,7 +3016,7 @@ static const struct pci_device_id parport_pc_pci_tbl[] = { { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_BOCA_IOPPAR, PCI_ANY_ID, PCI_ANY_ID, 0, 0, boca_ioppar }, { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, - PCI_SUBVENDOR_ID_EXSYS, PCI_SUBDEVICE_ID_EXSYS_4014, 0,0, plx_9050 }, + PCI_SUBVENDOR_ID_EXSYS, PCI_SUBDEVICE_ID_EXSYS_4014, 0, 0, plx_9050 }, /* PCI_VENDOR_ID_TIMEDIA/SUNIX has many differing cards ...*/ { 0x1409, 0x7168, 0x1409, 0x4078, 0, 0, timedia_4078a }, { 0x1409, 0x7168, 0x1409, 0x4079, 0, 0, timedia_4079h }, @@ -2940,7 +3050,8 @@ static const struct pci_device_id parport_pc_pci_tbl[] = { { 0x9710, 0x9805, 0x1000, 0x0010, 0, 0, titan_1284p1 }, { 0x9710, 0x9815, 0x1000, 0x0020, 0, 0, titan_1284p2 }, /* PCI_VENDOR_ID_AVLAB/Intek21 has another bunch of cards ...*/ - { 0x14db, 0x2120, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1p}, /* AFAVLAB_TK9902 */ + /* AFAVLAB_TK9902 */ + { 0x14db, 0x2120, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1p}, { 0x14db, 0x2121, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_2p}, { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI952PP, PCI_ANY_ID, PCI_ANY_ID, 0, 0, oxsemi_952 }, @@ -2983,14 +3094,14 @@ static const struct pci_device_id parport_pc_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, quatech_sppxp100 }, { 0, } /* terminate list */ }; -MODULE_DEVICE_TABLE(pci,parport_pc_pci_tbl); +MODULE_DEVICE_TABLE(pci, parport_pc_pci_tbl); struct pci_parport_data { int num; struct parport *ports[2]; }; -static int parport_pc_pci_probe (struct pci_dev *dev, +static int parport_pc_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) { int err, count, n, i = id->driver_data; @@ -3003,7 +3114,8 @@ static int parport_pc_pci_probe (struct pci_dev *dev, /* This is a PCI card */ i -= last_sio; count = 0; - if ((err = pci_enable_device (dev)) != 0) + err = pci_enable_device(dev); + if (err) return err; data = kmalloc(sizeof(struct pci_parport_data), GFP_KERNEL); @@ -3011,7 +3123,7 @@ static int parport_pc_pci_probe (struct pci_dev *dev, return -ENOMEM; if (cards[i].preinit_hook && - cards[i].preinit_hook (dev, PARPORT_IRQ_NONE, PARPORT_DMA_NONE)) { + cards[i].preinit_hook(dev, PARPORT_IRQ_NONE, PARPORT_DMA_NONE)) { kfree(data); return -ENODEV; } @@ -3021,25 +3133,25 @@ static int parport_pc_pci_probe (struct pci_dev *dev, int hi = cards[i].addr[n].hi; int irq; unsigned long io_lo, io_hi; - io_lo = pci_resource_start (dev, lo); + io_lo = pci_resource_start(dev, lo); io_hi = 0; if ((hi >= 0) && (hi <= 6)) - io_hi = pci_resource_start (dev, hi); + io_hi = pci_resource_start(dev, hi); else if (hi > 6) io_lo += hi; /* Reinterpret the meaning of - "hi" as an offset (see SYBA - def.) */ + "hi" as an offset (see SYBA + def.) */ /* TODO: test if sharing interrupts works */ irq = dev->irq; if (irq == IRQ_NONE) { - printk (KERN_DEBUG + printk(KERN_DEBUG "PCI parallel port detected: %04x:%04x, I/O at %#lx(%#lx)\n", parport_pc_pci_tbl[i + last_sio].vendor, parport_pc_pci_tbl[i + last_sio].device, io_lo, io_hi); irq = PARPORT_IRQ_NONE; } else { - printk (KERN_DEBUG + printk(KERN_DEBUG "PCI parallel port detected: %04x:%04x, I/O at %#lx(%#lx), IRQ %d\n", parport_pc_pci_tbl[i + last_sio].vendor, parport_pc_pci_tbl[i + last_sio].device, @@ -3056,7 +3168,7 @@ static int parport_pc_pci_probe (struct pci_dev *dev, data->num = count; if (cards[i].postinit_hook) - cards[i].postinit_hook (dev, count == 0); + cards[i].postinit_hook(dev, count == 0); if (count) { pci_set_drvdata(dev, data); @@ -3090,7 +3202,7 @@ static struct pci_driver parport_pc_pci_driver = { .remove = __devexit_p(parport_pc_pci_remove), }; -static int __init parport_pc_init_superio (int autoirq, int autodma) +static int __init parport_pc_init_superio(int autoirq, int autodma) { const struct pci_device_id *id; struct pci_dev *pdev = NULL; @@ -3101,8 +3213,9 @@ static int __init parport_pc_init_superio (int autoirq, int autodma) if (id == NULL || id->driver_data >= last_sio) continue; - if (parport_pc_superio_info[id->driver_data].probe - (pdev, autoirq, autodma,parport_pc_superio_info[id->driver_data].via)) { + if (parport_pc_superio_info[id->driver_data].probe( + pdev, autoirq, autodma, + parport_pc_superio_info[id->driver_data].via)) { ret++; } } @@ -3111,7 +3224,10 @@ static int __init parport_pc_init_superio (int autoirq, int autodma) } #else static struct pci_driver parport_pc_pci_driver; -static int __init parport_pc_init_superio(int autoirq, int autodma) {return 0;} +static int __init parport_pc_init_superio(int autoirq, int autodma) +{ + return 0; +} #endif /* CONFIG_PCI */ #ifdef CONFIG_PNP @@ -3124,44 +3240,45 @@ static const struct pnp_device_id parport_pc_pnp_tbl[] = { { } }; -MODULE_DEVICE_TABLE(pnp,parport_pc_pnp_tbl); +MODULE_DEVICE_TABLE(pnp, parport_pc_pnp_tbl); -static int parport_pc_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *id) +static int parport_pc_pnp_probe(struct pnp_dev *dev, + const struct pnp_device_id *id) { struct parport *pdata; unsigned long io_lo, io_hi; int dma, irq; - if (pnp_port_valid(dev,0) && - !(pnp_port_flags(dev,0) & IORESOURCE_DISABLED)) { - io_lo = pnp_port_start(dev,0); + if (pnp_port_valid(dev, 0) && + !(pnp_port_flags(dev, 0) & IORESOURCE_DISABLED)) { + io_lo = pnp_port_start(dev, 0); } else return -EINVAL; - if (pnp_port_valid(dev,1) && - !(pnp_port_flags(dev,1) & IORESOURCE_DISABLED)) { - io_hi = pnp_port_start(dev,1); + if (pnp_port_valid(dev, 1) && + !(pnp_port_flags(dev, 1) & IORESOURCE_DISABLED)) { + io_hi = pnp_port_start(dev, 1); } else io_hi = 0; - if (pnp_irq_valid(dev,0) && - !(pnp_irq_flags(dev,0) & IORESOURCE_DISABLED)) { - irq = pnp_irq(dev,0); + if (pnp_irq_valid(dev, 0) && + !(pnp_irq_flags(dev, 0) & IORESOURCE_DISABLED)) { + irq = pnp_irq(dev, 0); } else irq = PARPORT_IRQ_NONE; - if (pnp_dma_valid(dev,0) && - !(pnp_dma_flags(dev,0) & IORESOURCE_DISABLED)) { - dma = pnp_dma(dev,0); + if (pnp_dma_valid(dev, 0) && + !(pnp_dma_flags(dev, 0) & IORESOURCE_DISABLED)) { + dma = pnp_dma(dev, 0); } else dma = PARPORT_DMA_NONE; dev_info(&dev->dev, "reported by %s\n", dev->protocol->name); - if (!(pdata = parport_pc_probe_port(io_lo, io_hi, - irq, dma, &dev->dev, 0))) + pdata = parport_pc_probe_port(io_lo, io_hi, irq, dma, &dev->dev, 0); + if (pdata == NULL) return -ENODEV; - pnp_set_drvdata(dev,pdata); + pnp_set_drvdata(dev, pdata); return 0; } @@ -3203,7 +3320,7 @@ static struct platform_driver parport_pc_platform_driver = { /* This is called by parport_pc_find_nonpci_ports (in asm/parport.h) */ static int __devinit __attribute__((unused)) -parport_pc_find_isa_ports (int autoirq, int autodma) +parport_pc_find_isa_ports(int autoirq, int autodma) { int count = 0; @@ -3227,7 +3344,7 @@ parport_pc_find_isa_ports (int autoirq, int autodma) * autoirq is PARPORT_IRQ_NONE, PARPORT_IRQ_AUTO, or PARPORT_IRQ_PROBEONLY * autodma is PARPORT_DMA_NONE or PARPORT_DMA_AUTO */ -static void __init parport_pc_find_ports (int autoirq, int autodma) +static void __init parport_pc_find_ports(int autoirq, int autodma) { int count = 0, err; @@ -3261,11 +3378,18 @@ static void __init parport_pc_find_ports (int autoirq, int autodma) * syntax and keep in mind that code below is a cleaned up version. */ -static int __initdata io[PARPORT_PC_MAX_PORTS+1] = { [0 ... PARPORT_PC_MAX_PORTS] = 0 }; -static int __initdata io_hi[PARPORT_PC_MAX_PORTS+1] = - { [0 ... PARPORT_PC_MAX_PORTS] = PARPORT_IOHI_AUTO }; -static int __initdata dmaval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_DMA_NONE }; -static int __initdata irqval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_IRQ_PROBEONLY }; +static int __initdata io[PARPORT_PC_MAX_PORTS+1] = { + [0 ... PARPORT_PC_MAX_PORTS] = 0 +}; +static int __initdata io_hi[PARPORT_PC_MAX_PORTS+1] = { + [0 ... PARPORT_PC_MAX_PORTS] = PARPORT_IOHI_AUTO +}; +static int __initdata dmaval[PARPORT_PC_MAX_PORTS] = { + [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_DMA_NONE +}; +static int __initdata irqval[PARPORT_PC_MAX_PORTS] = { + [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_IRQ_PROBEONLY +}; static int __init parport_parse_param(const char *s, int *val, int automatic, int none, int nofifo) @@ -3306,18 +3430,19 @@ static int __init parport_parse_dma(const char *dmastr, int *val) #ifdef CONFIG_PCI static int __init parport_init_mode_setup(char *str) { - printk(KERN_DEBUG "parport_pc.c: Specified parameter parport_init_mode=%s\n", str); + printk(KERN_DEBUG + "parport_pc.c: Specified parameter parport_init_mode=%s\n", str); - if (!strcmp (str, "spp")) - parport_init_mode=1; - if (!strcmp (str, "ps2")) - parport_init_mode=2; - if (!strcmp (str, "epp")) - parport_init_mode=3; - if (!strcmp (str, "ecp")) - parport_init_mode=4; - if (!strcmp (str, "ecpepp")) - parport_init_mode=5; + if (!strcmp(str, "spp")) + parport_init_mode = 1; + if (!strcmp(str, "ps2")) + parport_init_mode = 2; + if (!strcmp(str, "epp")) + parport_init_mode = 3; + if (!strcmp(str, "ecp")) + parport_init_mode = 4; + if (!strcmp(str, "ecpepp")) + parport_init_mode = 5; return 1; } #endif @@ -3341,7 +3466,8 @@ module_param(verbose_probing, int, 0644); #endif #ifdef CONFIG_PCI static char *init_mode; -MODULE_PARM_DESC(init_mode, "Initialise mode for VIA VT8231 port (spp, ps2, epp, ecp or ecpepp)"); +MODULE_PARM_DESC(init_mode, + "Initialise mode for VIA VT8231 port (spp, ps2, epp, ecp or ecpepp)"); module_param(init_mode, charp, 0); #endif @@ -3372,7 +3498,7 @@ static int __init parse_parport_params(void) irqval[0] = val; break; default: - printk (KERN_WARNING + printk(KERN_WARNING "parport_pc: irq specified " "without base address. Use 'io=' " "to specify one\n"); @@ -3385,7 +3511,7 @@ static int __init parse_parport_params(void) dmaval[0] = val; break; default: - printk (KERN_WARNING + printk(KERN_WARNING "parport_pc: dma specified " "without base address. Use 'io=' " "to specify one\n"); @@ -3396,7 +3522,7 @@ static int __init parse_parport_params(void) #else -static int parport_setup_ptr __initdata = 0; +static int parport_setup_ptr __initdata; /* * Acceptable parameters: @@ -3407,7 +3533,7 @@ static int parport_setup_ptr __initdata = 0; * * IRQ/DMA may be numeric or 'auto' or 'none' */ -static int __init parport_setup (char *str) +static int __init parport_setup(char *str) { char *endptr; char *sep; @@ -3419,15 +3545,15 @@ static int __init parport_setup (char *str) return 1; } - if (!strncmp (str, "auto", 4)) { + if (!strncmp(str, "auto", 4)) { irqval[0] = PARPORT_IRQ_AUTO; dmaval[0] = PARPORT_DMA_AUTO; return 1; } - val = simple_strtoul (str, &endptr, 0); + val = simple_strtoul(str, &endptr, 0); if (endptr == str) { - printk (KERN_WARNING "parport=%s not understood\n", str); + printk(KERN_WARNING "parport=%s not understood\n", str); return 1; } @@ -3461,7 +3587,7 @@ static int __init parse_parport_params(void) return io[0] == PARPORT_DISABLE; } -__setup ("parport=", parport_setup); +__setup("parport=", parport_setup); /* * Acceptable parameters: @@ -3469,7 +3595,7 @@ __setup ("parport=", parport_setup); * parport_init_mode=[spp|ps2|epp|ecp|ecpepp] */ #ifdef CONFIG_PCI -__setup("parport_init_mode=",parport_init_mode_setup); +__setup("parport_init_mode=", parport_init_mode_setup); #endif #endif @@ -3493,13 +3619,13 @@ static int __init parport_pc_init(void) for (i = 0; i < PARPORT_PC_MAX_PORTS; i++) { if (!io[i]) break; - if ((io_hi[i]) == PARPORT_IOHI_AUTO) - io_hi[i] = 0x400 + io[i]; + if (io_hi[i] == PARPORT_IOHI_AUTO) + io_hi[i] = 0x400 + io[i]; parport_pc_probe_port(io[i], io_hi[i], - irqval[i], dmaval[i], NULL, 0); + irqval[i], dmaval[i], NULL, 0); } } else - parport_pc_find_ports (irqval[0], dmaval[0]); + parport_pc_find_ports(irqval[0], dmaval[0]); return 0; } @@ -3507,9 +3633,9 @@ static int __init parport_pc_init(void) static void __exit parport_pc_exit(void) { if (pci_registered_parport) - pci_unregister_driver (&parport_pc_pci_driver); + pci_unregister_driver(&parport_pc_pci_driver); if (pnp_registered_parport) - pnp_unregister_driver (&parport_pc_pnp_driver); + pnp_unregister_driver(&parport_pc_pnp_driver); platform_driver_unregister(&parport_pc_platform_driver); while (!list_empty(&ports_list)) { diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index ba6af162fd39..1ebd6b4c743b 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -2,10 +2,11 @@ # Makefile for the PCI bus specific drivers. # -obj-y += access.o bus.o probe.o remove.o pci.o quirks.o slot.o \ +obj-y += access.o bus.o probe.o remove.o pci.o quirks.o \ pci-driver.o search.o pci-sysfs.o rom.o setup-res.o \ irq.o obj-$(CONFIG_PROC_FS) += proc.o +obj-$(CONFIG_SYSFS) += slot.o # Build PCI Express stuff if needed obj-$(CONFIG_PCIEPORTBUS) += pcie/ @@ -39,7 +40,6 @@ obj-$(CONFIG_ALPHA) += setup-bus.o setup-irq.o obj-$(CONFIG_ARM) += setup-bus.o setup-irq.o obj-$(CONFIG_PARISC) += setup-bus.o obj-$(CONFIG_SUPERH) += setup-bus.o setup-irq.o -obj-$(CONFIG_PPC32) += setup-irq.o obj-$(CONFIG_PPC) += setup-bus.o obj-$(CONFIG_MIPS) += setup-bus.o setup-irq.o obj-$(CONFIG_X86_VISWS) += setup-irq.o diff --git a/drivers/pci/access.c b/drivers/pci/access.c index 0f3706512686..db23200c4874 100644 --- a/drivers/pci/access.c +++ b/drivers/pci/access.c @@ -66,6 +66,25 @@ EXPORT_SYMBOL(pci_bus_write_config_byte); EXPORT_SYMBOL(pci_bus_write_config_word); EXPORT_SYMBOL(pci_bus_write_config_dword); +/** + * pci_bus_set_ops - Set raw operations of pci bus + * @bus: pci bus struct + * @ops: new raw operations + * + * Return previous raw operations + */ +struct pci_ops *pci_bus_set_ops(struct pci_bus *bus, struct pci_ops *ops) +{ + struct pci_ops *old_ops; + unsigned long flags; + + spin_lock_irqsave(&pci_lock, flags); + old_ops = bus->ops; + bus->ops = ops; + spin_unlock_irqrestore(&pci_lock, flags); + return old_ops; +} +EXPORT_SYMBOL(pci_bus_set_ops); /** * pci_read_vpd - Read one entry from Vital Product Data diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index 97a8194063b5..cef28a79103f 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c @@ -41,9 +41,14 @@ pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, void *alignf_data) { int i, ret = -ENOMEM; + resource_size_t max = -1; type_mask |= IORESOURCE_IO | IORESOURCE_MEM; + /* don't allocate too high if the pref mem doesn't support 64bit*/ + if (!(res->flags & IORESOURCE_MEM_64)) + max = PCIBIOS_MAX_MEM_32; + for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) { struct resource *r = bus->resource[i]; if (!r) @@ -62,7 +67,7 @@ pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, /* Ok, try it out.. */ ret = allocate_resource(r, res, size, r->start ? : min, - -1, align, + max, align, alignf, alignf_data); if (ret == 0) break; @@ -201,13 +206,18 @@ void pci_enable_bridges(struct pci_bus *bus) * Walk the given bus, including any bridged devices * on buses under this bus. Call the provided callback * on each device found. + * + * We check the return of @cb each time. If it returns anything + * other than 0, we break out. + * */ -void pci_walk_bus(struct pci_bus *top, void (*cb)(struct pci_dev *, void *), +void pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *), void *userdata) { struct pci_dev *dev; struct pci_bus *bus; struct list_head *next; + int retval; bus = top; down_read(&pci_bus_sem); @@ -231,8 +241,10 @@ void pci_walk_bus(struct pci_bus *top, void (*cb)(struct pci_dev *, void *), /* Run device routines with the device locked */ down(&dev->dev.sem); - cb(dev, userdata); + retval = cb(dev, userdata); up(&dev->dev.sem); + if (retval) + break; } up_read(&pci_bus_sem); } diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c index fa3a11365ec3..7b287cb38b7a 100644 --- a/drivers/pci/dmar.c +++ b/drivers/pci/dmar.c @@ -267,6 +267,84 @@ rmrr_parse_dev(struct dmar_rmrr_unit *rmrru) } return ret; } + +static LIST_HEAD(dmar_atsr_units); + +static int __init dmar_parse_one_atsr(struct acpi_dmar_header *hdr) +{ + struct acpi_dmar_atsr *atsr; + struct dmar_atsr_unit *atsru; + + atsr = container_of(hdr, struct acpi_dmar_atsr, header); + atsru = kzalloc(sizeof(*atsru), GFP_KERNEL); + if (!atsru) + return -ENOMEM; + + atsru->hdr = hdr; + atsru->include_all = atsr->flags & 0x1; + + list_add(&atsru->list, &dmar_atsr_units); + + return 0; +} + +static int __init atsr_parse_dev(struct dmar_atsr_unit *atsru) +{ + int rc; + struct acpi_dmar_atsr *atsr; + + if (atsru->include_all) + return 0; + + atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header); + rc = dmar_parse_dev_scope((void *)(atsr + 1), + (void *)atsr + atsr->header.length, + &atsru->devices_cnt, &atsru->devices, + atsr->segment); + if (rc || !atsru->devices_cnt) { + list_del(&atsru->list); + kfree(atsru); + } + + return rc; +} + +int dmar_find_matched_atsr_unit(struct pci_dev *dev) +{ + int i; + struct pci_bus *bus; + struct acpi_dmar_atsr *atsr; + struct dmar_atsr_unit *atsru; + + list_for_each_entry(atsru, &dmar_atsr_units, list) { + atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header); + if (atsr->segment == pci_domain_nr(dev->bus)) + goto found; + } + + return 0; + +found: + for (bus = dev->bus; bus; bus = bus->parent) { + struct pci_dev *bridge = bus->self; + + if (!bridge || !bridge->is_pcie || + bridge->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) + return 0; + + if (bridge->pcie_type == PCI_EXP_TYPE_ROOT_PORT) { + for (i = 0; i < atsru->devices_cnt; i++) + if (atsru->devices[i] == bridge) + return 1; + break; + } + } + + if (atsru->include_all) + return 1; + + return 0; +} #endif static void __init @@ -274,22 +352,28 @@ dmar_table_print_dmar_entry(struct acpi_dmar_header *header) { struct acpi_dmar_hardware_unit *drhd; struct acpi_dmar_reserved_memory *rmrr; + struct acpi_dmar_atsr *atsr; switch (header->type) { case ACPI_DMAR_TYPE_HARDWARE_UNIT: - drhd = (struct acpi_dmar_hardware_unit *)header; + drhd = container_of(header, struct acpi_dmar_hardware_unit, + header); printk (KERN_INFO PREFIX - "DRHD (flags: 0x%08x)base: 0x%016Lx\n", - drhd->flags, (unsigned long long)drhd->address); + "DRHD base: %#016Lx flags: %#x\n", + (unsigned long long)drhd->address, drhd->flags); break; case ACPI_DMAR_TYPE_RESERVED_MEMORY: - rmrr = (struct acpi_dmar_reserved_memory *)header; - + rmrr = container_of(header, struct acpi_dmar_reserved_memory, + header); printk (KERN_INFO PREFIX - "RMRR base: 0x%016Lx end: 0x%016Lx\n", + "RMRR base: %#016Lx end: %#016Lx\n", (unsigned long long)rmrr->base_address, (unsigned long long)rmrr->end_address); break; + case ACPI_DMAR_TYPE_ATSR: + atsr = container_of(header, struct acpi_dmar_atsr, header); + printk(KERN_INFO PREFIX "ATSR flags: %#x\n", atsr->flags); + break; } } @@ -361,6 +445,11 @@ parse_dmar_table(void) case ACPI_DMAR_TYPE_RESERVED_MEMORY: #ifdef CONFIG_DMAR ret = dmar_parse_one_rmrr(entry_header); +#endif + break; + case ACPI_DMAR_TYPE_ATSR: +#ifdef CONFIG_DMAR + ret = dmar_parse_one_atsr(entry_header); #endif break; default: @@ -431,11 +520,19 @@ int __init dmar_dev_scope_init(void) #ifdef CONFIG_DMAR { struct dmar_rmrr_unit *rmrr, *rmrr_n; + struct dmar_atsr_unit *atsr, *atsr_n; + list_for_each_entry_safe(rmrr, rmrr_n, &dmar_rmrr_units, list) { ret = rmrr_parse_dev(rmrr); if (ret) return ret; } + + list_for_each_entry_safe(atsr, atsr_n, &dmar_atsr_units, list) { + ret = atsr_parse_dev(atsr); + if (ret) + return ret; + } } #endif @@ -468,6 +565,9 @@ int __init dmar_table_init(void) #ifdef CONFIG_DMAR if (list_empty(&dmar_rmrr_units)) printk(KERN_INFO PREFIX "No RMRR found\n"); + + if (list_empty(&dmar_atsr_units)) + printk(KERN_INFO PREFIX "No ATSR found\n"); #endif #ifdef CONFIG_INTR_REMAP @@ -515,6 +615,7 @@ int alloc_iommu(struct dmar_drhd_unit *drhd) u32 ver; static int iommu_allocated = 0; int agaw = 0; + int msagaw = 0; iommu = kzalloc(sizeof(*iommu), GFP_KERNEL); if (!iommu) @@ -535,12 +636,20 @@ int alloc_iommu(struct dmar_drhd_unit *drhd) agaw = iommu_calculate_agaw(iommu); if (agaw < 0) { printk(KERN_ERR - "Cannot get a valid agaw for iommu (seq_id = %d)\n", + "Cannot get a valid agaw for iommu (seq_id = %d)\n", + iommu->seq_id); + goto error; + } + msagaw = iommu_calculate_max_sagaw(iommu); + if (msagaw < 0) { + printk(KERN_ERR + "Cannot get a valid max agaw for iommu (seq_id = %d)\n", iommu->seq_id); goto error; } #endif iommu->agaw = agaw; + iommu->msagaw = msagaw; /* the registers might be more than one page */ map_size = max_t(int, ecap_max_iotlb_offset(iommu->ecap), @@ -590,7 +699,8 @@ void free_iommu(struct intel_iommu *iommu) */ static inline void reclaim_free_desc(struct q_inval *qi) { - while (qi->desc_status[qi->free_tail] == QI_DONE) { + while (qi->desc_status[qi->free_tail] == QI_DONE || + qi->desc_status[qi->free_tail] == QI_ABORT) { qi->desc_status[qi->free_tail] = QI_FREE; qi->free_tail = (qi->free_tail + 1) % QI_LENGTH; qi->free_cnt++; @@ -600,10 +710,13 @@ static inline void reclaim_free_desc(struct q_inval *qi) static int qi_check_fault(struct intel_iommu *iommu, int index) { u32 fault; - int head; + int head, tail; struct q_inval *qi = iommu->qi; int wait_index = (index + 1) % QI_LENGTH; + if (qi->desc_status[wait_index] == QI_ABORT) + return -EAGAIN; + fault = readl(iommu->reg + DMAR_FSTS_REG); /* @@ -613,7 +726,11 @@ static int qi_check_fault(struct intel_iommu *iommu, int index) */ if (fault & DMA_FSTS_IQE) { head = readl(iommu->reg + DMAR_IQH_REG); - if ((head >> 4) == index) { + if ((head >> DMAR_IQ_SHIFT) == index) { + printk(KERN_ERR "VT-d detected invalid descriptor: " + "low=%llx, high=%llx\n", + (unsigned long long)qi->desc[index].low, + (unsigned long long)qi->desc[index].high); memcpy(&qi->desc[index], &qi->desc[wait_index], sizeof(struct qi_desc)); __iommu_flush_cache(iommu, &qi->desc[index], @@ -623,6 +740,32 @@ static int qi_check_fault(struct intel_iommu *iommu, int index) } } + /* + * If ITE happens, all pending wait_desc commands are aborted. + * No new descriptors are fetched until the ITE is cleared. + */ + if (fault & DMA_FSTS_ITE) { + head = readl(iommu->reg + DMAR_IQH_REG); + head = ((head >> DMAR_IQ_SHIFT) - 1 + QI_LENGTH) % QI_LENGTH; + head |= 1; + tail = readl(iommu->reg + DMAR_IQT_REG); + tail = ((tail >> DMAR_IQ_SHIFT) - 1 + QI_LENGTH) % QI_LENGTH; + + writel(DMA_FSTS_ITE, iommu->reg + DMAR_FSTS_REG); + + do { + if (qi->desc_status[head] == QI_IN_USE) + qi->desc_status[head] = QI_ABORT; + head = (head - 2 + QI_LENGTH) % QI_LENGTH; + } while (head != tail); + + if (qi->desc_status[wait_index] == QI_ABORT) + return -EAGAIN; + } + + if (fault & DMA_FSTS_ICE) + writel(DMA_FSTS_ICE, iommu->reg + DMAR_FSTS_REG); + return 0; } @@ -632,7 +775,7 @@ static int qi_check_fault(struct intel_iommu *iommu, int index) */ int qi_submit_sync(struct qi_desc *desc, struct intel_iommu *iommu) { - int rc = 0; + int rc; struct q_inval *qi = iommu->qi; struct qi_desc *hw, wait_desc; int wait_index, index; @@ -643,6 +786,9 @@ int qi_submit_sync(struct qi_desc *desc, struct intel_iommu *iommu) hw = qi->desc; +restart: + rc = 0; + spin_lock_irqsave(&qi->q_lock, flags); while (qi->free_cnt < 3) { spin_unlock_irqrestore(&qi->q_lock, flags); @@ -673,7 +819,7 @@ int qi_submit_sync(struct qi_desc *desc, struct intel_iommu *iommu) * update the HW tail register indicating the presence of * new descriptors. */ - writel(qi->free_head << 4, iommu->reg + DMAR_IQT_REG); + writel(qi->free_head << DMAR_IQ_SHIFT, iommu->reg + DMAR_IQT_REG); while (qi->desc_status[wait_index] != QI_DONE) { /* @@ -685,18 +831,21 @@ int qi_submit_sync(struct qi_desc *desc, struct intel_iommu *iommu) */ rc = qi_check_fault(iommu, index); if (rc) - goto out; + break; spin_unlock(&qi->q_lock); cpu_relax(); spin_lock(&qi->q_lock); } -out: - qi->desc_status[index] = qi->desc_status[wait_index] = QI_DONE; + + qi->desc_status[index] = QI_DONE; reclaim_free_desc(qi); spin_unlock_irqrestore(&qi->q_lock, flags); + if (rc == -EAGAIN) + goto restart; + return rc; } @@ -714,41 +863,26 @@ void qi_global_iec(struct intel_iommu *iommu) qi_submit_sync(&desc, iommu); } -int qi_flush_context(struct intel_iommu *iommu, u16 did, u16 sid, u8 fm, - u64 type, int non_present_entry_flush) +void qi_flush_context(struct intel_iommu *iommu, u16 did, u16 sid, u8 fm, + u64 type) { struct qi_desc desc; - if (non_present_entry_flush) { - if (!cap_caching_mode(iommu->cap)) - return 1; - else - did = 0; - } - desc.low = QI_CC_FM(fm) | QI_CC_SID(sid) | QI_CC_DID(did) | QI_CC_GRAN(type) | QI_CC_TYPE; desc.high = 0; - return qi_submit_sync(&desc, iommu); + qi_submit_sync(&desc, iommu); } -int qi_flush_iotlb(struct intel_iommu *iommu, u16 did, u64 addr, - unsigned int size_order, u64 type, - int non_present_entry_flush) +void qi_flush_iotlb(struct intel_iommu *iommu, u16 did, u64 addr, + unsigned int size_order, u64 type) { u8 dw = 0, dr = 0; struct qi_desc desc; int ih = 0; - if (non_present_entry_flush) { - if (!cap_caching_mode(iommu->cap)) - return 1; - else - did = 0; - } - if (cap_write_drain(iommu->cap)) dw = 1; @@ -760,7 +894,28 @@ int qi_flush_iotlb(struct intel_iommu *iommu, u16 did, u64 addr, desc.high = QI_IOTLB_ADDR(addr) | QI_IOTLB_IH(ih) | QI_IOTLB_AM(size_order); - return qi_submit_sync(&desc, iommu); + qi_submit_sync(&desc, iommu); +} + +void qi_flush_dev_iotlb(struct intel_iommu *iommu, u16 sid, u16 qdep, + u64 addr, unsigned mask) +{ + struct qi_desc desc; + + if (mask) { + BUG_ON(addr & ((1 << (VTD_PAGE_SHIFT + mask)) - 1)); + addr |= (1 << (VTD_PAGE_SHIFT + mask - 1)) - 1; + desc.high = QI_DEV_IOTLB_ADDR(addr) | QI_DEV_IOTLB_SIZE; + } else + desc.high = QI_DEV_IOTLB_ADDR(addr); + + if (qdep >= QI_DEV_IOTLB_MAX_INVS) + qdep = 0; + + desc.low = QI_DEV_IOTLB_SID(sid) | QI_DEV_IOTLB_QDEP(qdep) | + QI_DIOTLB_TYPE; + + qi_submit_sync(&desc, iommu); } /* @@ -790,7 +945,6 @@ void dmar_disable_qi(struct intel_iommu *iommu) cpu_relax(); iommu->gcmd &= ~DMA_GCMD_QIE; - writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG); IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, readl, @@ -804,7 +958,7 @@ end: */ static void __dmar_enable_qi(struct intel_iommu *iommu) { - u32 cmd, sts; + u32 sts; unsigned long flags; struct q_inval *qi = iommu->qi; @@ -818,9 +972,8 @@ static void __dmar_enable_qi(struct intel_iommu *iommu) dmar_writeq(iommu->reg + DMAR_IQA_REG, virt_to_phys(qi->desc)); - cmd = iommu->gcmd | DMA_GCMD_QIE; iommu->gcmd |= DMA_GCMD_QIE; - writel(cmd, iommu->reg + DMAR_GCMD_REG); + writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG); /* Make sure hardware complete it */ IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, readl, (sts & DMA_GSTS_QIES), sts); @@ -1096,7 +1249,7 @@ int dmar_set_interrupt(struct intel_iommu *iommu) set_irq_data(irq, NULL); iommu->irq = 0; destroy_irq(irq); - return 0; + return ret; } ret = request_irq(irq, dmar_fault, 0, iommu->name, iommu); diff --git a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig index 9aa4fe100a0d..66f29bc00be4 100644 --- a/drivers/pci/hotplug/Kconfig +++ b/drivers/pci/hotplug/Kconfig @@ -4,7 +4,7 @@ menuconfig HOTPLUG_PCI tristate "Support for PCI Hotplug" - depends on PCI && HOTPLUG + depends on PCI && HOTPLUG && SYSFS ---help--- Say Y here if you have a motherboard with a PCI Hotplug controller. This allows you to add and remove PCI cards while the machine is @@ -41,7 +41,7 @@ config HOTPLUG_PCI_FAKE config HOTPLUG_PCI_COMPAQ tristate "Compaq PCI Hotplug driver" - depends on X86 && PCI_BIOS && PCI_LEGACY + depends on X86 && PCI_BIOS help Say Y here if you have a motherboard with a Compaq PCI Hotplug controller. diff --git a/drivers/pci/hotplug/acpi_pcihp.c b/drivers/pci/hotplug/acpi_pcihp.c index fbc63d5e459f..eb159587d0bf 100644 --- a/drivers/pci/hotplug/acpi_pcihp.c +++ b/drivers/pci/hotplug/acpi_pcihp.c @@ -354,7 +354,7 @@ acpi_status acpi_get_hp_params_from_firmware(struct pci_bus *bus, status = acpi_run_hpp(handle, hpp); if (ACPI_SUCCESS(status)) break; - if (acpi_root_bridge(handle)) + if (acpi_is_root_bridge(handle)) break; status = acpi_get_parent(handle, &phandle); if (ACPI_FAILURE(status)) @@ -428,7 +428,7 @@ int acpi_get_hp_hw_control_from_firmware(struct pci_dev *pdev, u32 flags) status = acpi_run_oshp(handle); if (ACPI_SUCCESS(status)) goto got_one; - if (acpi_root_bridge(handle)) + if (acpi_is_root_bridge(handle)) break; chandle = handle; status = acpi_get_parent(chandle, &handle); @@ -449,42 +449,6 @@ got_one: } EXPORT_SYMBOL(acpi_get_hp_hw_control_from_firmware); -/* acpi_root_bridge - check to see if this acpi object is a root bridge - * - * @handle - the acpi object in question. - */ -int acpi_root_bridge(acpi_handle handle) -{ - acpi_status status; - struct acpi_device_info *info; - struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; - int i; - - status = acpi_get_object_info(handle, &buffer); - if (ACPI_SUCCESS(status)) { - info = buffer.pointer; - if ((info->valid & ACPI_VALID_HID) && - !strcmp(PCI_ROOT_HID_STRING, - info->hardware_id.value)) { - kfree(buffer.pointer); - return 1; - } - if (info->valid & ACPI_VALID_CID) { - for (i=0; i < info->compatibility_id.count; i++) { - if (!strcmp(PCI_ROOT_HID_STRING, - info->compatibility_id.id[i].value)) { - kfree(buffer.pointer); - return 1; - } - } - } - kfree(buffer.pointer); - } - return 0; -} -EXPORT_SYMBOL_GPL(acpi_root_bridge); - - static int is_ejectable(acpi_handle handle) { acpi_status status; diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c index 43c10bd261b4..4dd7114964ac 100644 --- a/drivers/pci/hotplug/acpiphp_core.c +++ b/drivers/pci/hotplug/acpiphp_core.c @@ -77,7 +77,6 @@ static int get_latch_status (struct hotplug_slot *slot, u8 *value); static int get_adapter_status (struct hotplug_slot *slot, u8 *value); static struct hotplug_slot_ops acpi_hotplug_slot_ops = { - .owner = THIS_MODULE, .enable_slot = enable_slot, .disable_slot = disable_slot, .set_attention_status = set_attention_status, diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 3a6064bce561..0cb0f830a993 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -678,18 +678,9 @@ static void remove_bridge(acpi_handle handle) static struct pci_dev * get_apic_pci_info(acpi_handle handle) { - struct acpi_pci_id id; - struct pci_bus *bus; struct pci_dev *dev; - if (ACPI_FAILURE(acpi_get_pci_id(handle, &id))) - return NULL; - - bus = pci_find_bus(id.segment, id.bus); - if (!bus) - return NULL; - - dev = pci_get_slot(bus, PCI_DEVFN(id.device, id.function)); + dev = acpi_get_pci_dev(handle); if (!dev) return NULL; @@ -1396,19 +1387,16 @@ static void acpiphp_sanitize_bus(struct pci_bus *bus) /* Program resources in newly inserted bridge */ static int acpiphp_configure_bridge (acpi_handle handle) { - struct acpi_pci_id pci_id; + struct pci_dev *dev; struct pci_bus *bus; - if (ACPI_FAILURE(acpi_get_pci_id(handle, &pci_id))) { + dev = acpi_get_pci_dev(handle); + if (!dev) { err("cannot get PCI domain and bus number for bridge\n"); return -EINVAL; } - bus = pci_find_bus(pci_id.segment, pci_id.bus); - if (!bus) { - err("cannot find bus %d:%d\n", - pci_id.segment, pci_id.bus); - return -EINVAL; - } + + bus = dev->bus; pci_bus_size_bridges(bus); pci_bus_assign_resources(bus); @@ -1416,6 +1404,7 @@ static int acpiphp_configure_bridge (acpi_handle handle) acpiphp_set_hpp_values(handle, bus); pci_enable_bridges(bus); acpiphp_configure_ioapics(handle); + pci_dev_put(dev); return 0; } @@ -1631,7 +1620,7 @@ find_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv) { int *count = (int *)context; - if (acpi_root_bridge(handle)) { + if (acpi_is_root_bridge(handle)) { acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, handle_hotplug_event_bridge, NULL); (*count)++; diff --git a/drivers/pci/hotplug/cpci_hotplug_core.c b/drivers/pci/hotplug/cpci_hotplug_core.c index de94f4feef8c..a5b9f6ae507b 100644 --- a/drivers/pci/hotplug/cpci_hotplug_core.c +++ b/drivers/pci/hotplug/cpci_hotplug_core.c @@ -72,7 +72,6 @@ static int get_adapter_status(struct hotplug_slot *slot, u8 * value); static int get_latch_status(struct hotplug_slot *slot, u8 * value); static struct hotplug_slot_ops cpci_hotplug_slot_ops = { - .owner = THIS_MODULE, .enable_slot = enable_slot, .disable_slot = disable_slot, .set_attention_status = set_attention_status, diff --git a/drivers/pci/hotplug/cpqphp.h b/drivers/pci/hotplug/cpqphp.h index afaf8f69f73e..53836001d511 100644 --- a/drivers/pci/hotplug/cpqphp.h +++ b/drivers/pci/hotplug/cpqphp.h @@ -150,25 +150,25 @@ struct ctrl_reg { /* offset */ /* offsets to the controller registers based on the above structure layout */ enum ctrl_offsets { - SLOT_RST = offsetof(struct ctrl_reg, slot_RST), + SLOT_RST = offsetof(struct ctrl_reg, slot_RST), SLOT_ENABLE = offsetof(struct ctrl_reg, slot_enable), MISC = offsetof(struct ctrl_reg, misc), LED_CONTROL = offsetof(struct ctrl_reg, led_control), INT_INPUT_CLEAR = offsetof(struct ctrl_reg, int_input_clear), - INT_MASK = offsetof(struct ctrl_reg, int_mask), - CTRL_RESERVED0 = offsetof(struct ctrl_reg, reserved0), + INT_MASK = offsetof(struct ctrl_reg, int_mask), + CTRL_RESERVED0 = offsetof(struct ctrl_reg, reserved0), CTRL_RESERVED1 = offsetof(struct ctrl_reg, reserved1), CTRL_RESERVED2 = offsetof(struct ctrl_reg, reserved1), - GEN_OUTPUT_AB = offsetof(struct ctrl_reg, gen_output_AB), - NON_INT_INPUT = offsetof(struct ctrl_reg, non_int_input), + GEN_OUTPUT_AB = offsetof(struct ctrl_reg, gen_output_AB), + NON_INT_INPUT = offsetof(struct ctrl_reg, non_int_input), CTRL_RESERVED3 = offsetof(struct ctrl_reg, reserved3), CTRL_RESERVED4 = offsetof(struct ctrl_reg, reserved4), CTRL_RESERVED5 = offsetof(struct ctrl_reg, reserved5), CTRL_RESERVED6 = offsetof(struct ctrl_reg, reserved6), CTRL_RESERVED7 = offsetof(struct ctrl_reg, reserved7), CTRL_RESERVED8 = offsetof(struct ctrl_reg, reserved8), - SLOT_MASK = offsetof(struct ctrl_reg, slot_mask), - CTRL_RESERVED9 = offsetof(struct ctrl_reg, reserved9), + SLOT_MASK = offsetof(struct ctrl_reg, slot_mask), + CTRL_RESERVED9 = offsetof(struct ctrl_reg, reserved9), CTRL_RESERVED10 = offsetof(struct ctrl_reg, reserved10), CTRL_RESERVED11 = offsetof(struct ctrl_reg, reserved11), SLOT_SERR = offsetof(struct ctrl_reg, slot_SERR), @@ -190,7 +190,9 @@ struct hrt { u32 reserved2; } __attribute__ ((packed)); -/* offsets to the hotplug resource table registers based on the above structure layout */ +/* offsets to the hotplug resource table registers based on the above + * structure layout + */ enum hrt_offsets { SIG0 = offsetof(struct hrt, sig0), SIG1 = offsetof(struct hrt, sig1), @@ -217,18 +219,20 @@ struct slot_rt { u16 pre_mem_length; } __attribute__ ((packed)); -/* offsets to the hotplug slot resource table registers based on the above structure layout */ +/* offsets to the hotplug slot resource table registers based on the above + * structure layout + */ enum slot_rt_offsets { DEV_FUNC = offsetof(struct slot_rt, dev_func), - PRIMARY_BUS = offsetof(struct slot_rt, primary_bus), - SECONDARY_BUS = offsetof(struct slot_rt, secondary_bus), - MAX_BUS = offsetof(struct slot_rt, max_bus), - IO_BASE = offsetof(struct slot_rt, io_base), - IO_LENGTH = offsetof(struct slot_rt, io_length), - MEM_BASE = offsetof(struct slot_rt, mem_base), - MEM_LENGTH = offsetof(struct slot_rt, mem_length), - PRE_MEM_BASE = offsetof(struct slot_rt, pre_mem_base), - PRE_MEM_LENGTH = offsetof(struct slot_rt, pre_mem_length), + PRIMARY_BUS = offsetof(struct slot_rt, primary_bus), + SECONDARY_BUS = offsetof(struct slot_rt, secondary_bus), + MAX_BUS = offsetof(struct slot_rt, max_bus), + IO_BASE = offsetof(struct slot_rt, io_base), + IO_LENGTH = offsetof(struct slot_rt, io_length), + MEM_BASE = offsetof(struct slot_rt, mem_base), + MEM_LENGTH = offsetof(struct slot_rt, mem_length), + PRE_MEM_BASE = offsetof(struct slot_rt, pre_mem_base), + PRE_MEM_LENGTH = offsetof(struct slot_rt, pre_mem_length), }; struct pci_func { @@ -286,8 +290,8 @@ struct event_info { struct controller { struct controller *next; u32 ctrl_int_comp; - struct mutex crit_sect; /* critical section mutex */ - void __iomem *hpc_reg; /* cookie for our pci controller location */ + struct mutex crit_sect; /* critical section mutex */ + void __iomem *hpc_reg; /* cookie for our pci controller location */ struct pci_resource *mem_head; struct pci_resource *p_mem_head; struct pci_resource *io_head; @@ -299,7 +303,7 @@ struct controller { u8 next_event; u8 interrupt; u8 cfgspc_irq; - u8 bus; /* bus number for the pci hotplug controller */ + u8 bus; /* bus number for the pci hotplug controller */ u8 rev; u8 slot_device_offset; u8 first_slot; @@ -401,46 +405,57 @@ struct resource_lists { /* debugfs functions for the hotplug controller info */ -extern void cpqhp_initialize_debugfs (void); -extern void cpqhp_shutdown_debugfs (void); -extern void cpqhp_create_debugfs_files (struct controller *ctrl); -extern void cpqhp_remove_debugfs_files (struct controller *ctrl); +extern void cpqhp_initialize_debugfs(void); +extern void cpqhp_shutdown_debugfs(void); +extern void cpqhp_create_debugfs_files(struct controller *ctrl); +extern void cpqhp_remove_debugfs_files(struct controller *ctrl); /* controller functions */ -extern void cpqhp_pushbutton_thread (unsigned long event_pointer); -extern irqreturn_t cpqhp_ctrl_intr (int IRQ, void *data); -extern int cpqhp_find_available_resources (struct controller *ctrl, void __iomem *rom_start); -extern int cpqhp_event_start_thread (void); -extern void cpqhp_event_stop_thread (void); -extern struct pci_func *cpqhp_slot_create (unsigned char busnumber); -extern struct pci_func *cpqhp_slot_find (unsigned char bus, unsigned char device, unsigned char index); -extern int cpqhp_process_SI (struct controller *ctrl, struct pci_func *func); -extern int cpqhp_process_SS (struct controller *ctrl, struct pci_func *func); -extern int cpqhp_hardware_test (struct controller *ctrl, int test_num); +extern void cpqhp_pushbutton_thread(unsigned long event_pointer); +extern irqreturn_t cpqhp_ctrl_intr(int IRQ, void *data); +extern int cpqhp_find_available_resources(struct controller *ctrl, + void __iomem *rom_start); +extern int cpqhp_event_start_thread(void); +extern void cpqhp_event_stop_thread(void); +extern struct pci_func *cpqhp_slot_create(unsigned char busnumber); +extern struct pci_func *cpqhp_slot_find(unsigned char bus, unsigned char device, + unsigned char index); +extern int cpqhp_process_SI(struct controller *ctrl, struct pci_func *func); +extern int cpqhp_process_SS(struct controller *ctrl, struct pci_func *func); +extern int cpqhp_hardware_test(struct controller *ctrl, int test_num); /* resource functions */ extern int cpqhp_resource_sort_and_combine (struct pci_resource **head); /* pci functions */ -extern int cpqhp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num); -extern int cpqhp_get_bus_dev (struct controller *ctrl, u8 *bus_num, u8 *dev_num, u8 slot); -extern int cpqhp_save_config (struct controller *ctrl, int busnumber, int is_hot_plug); -extern int cpqhp_save_base_addr_length (struct controller *ctrl, struct pci_func * func); -extern int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func); -extern int cpqhp_configure_board (struct controller *ctrl, struct pci_func * func); -extern int cpqhp_save_slot_config (struct controller *ctrl, struct pci_func * new_slot); -extern int cpqhp_valid_replace (struct controller *ctrl, struct pci_func * func); -extern void cpqhp_destroy_board_resources (struct pci_func * func); -extern int cpqhp_return_board_resources (struct pci_func * func, struct resource_lists * resources); -extern void cpqhp_destroy_resource_list (struct resource_lists * resources); -extern int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func); -extern int cpqhp_unconfigure_device (struct pci_func* func); +extern int cpqhp_set_irq(u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num); +extern int cpqhp_get_bus_dev(struct controller *ctrl, u8 *bus_num, u8 *dev_num, + u8 slot); +extern int cpqhp_save_config(struct controller *ctrl, int busnumber, + int is_hot_plug); +extern int cpqhp_save_base_addr_length(struct controller *ctrl, + struct pci_func *func); +extern int cpqhp_save_used_resources(struct controller *ctrl, + struct pci_func *func); +extern int cpqhp_configure_board(struct controller *ctrl, + struct pci_func *func); +extern int cpqhp_save_slot_config(struct controller *ctrl, + struct pci_func *new_slot); +extern int cpqhp_valid_replace(struct controller *ctrl, struct pci_func *func); +extern void cpqhp_destroy_board_resources(struct pci_func *func); +extern int cpqhp_return_board_resources (struct pci_func *func, + struct resource_lists *resources); +extern void cpqhp_destroy_resource_list(struct resource_lists *resources); +extern int cpqhp_configure_device(struct controller *ctrl, + struct pci_func *func); +extern int cpqhp_unconfigure_device(struct pci_func *func); /* Global variables */ extern int cpqhp_debug; extern int cpqhp_legacy_mode; extern struct controller *cpqhp_ctrl_list; extern struct pci_func *cpqhp_slot_list[256]; +extern struct irq_routing_table *cpqhp_routing_table; /* these can be gotten rid of, but for debugging they are purty */ extern u8 cpqhp_nic_irq; @@ -449,7 +464,7 @@ extern u8 cpqhp_disk_irq; /* inline functions */ -static inline char *slot_name(struct slot *slot) +static inline const char *slot_name(struct slot *slot) { return hotplug_slot_name(slot->hotplug_slot); } @@ -458,9 +473,9 @@ static inline char *slot_name(struct slot *slot) * return_resource * * Puts node back in the resource list pointed to by head - * */ -static inline void return_resource(struct pci_resource **head, struct pci_resource *node) +static inline void return_resource(struct pci_resource **head, + struct pci_resource *node) { if (!node || !head) return; @@ -471,7 +486,7 @@ static inline void return_resource(struct pci_resource **head, struct pci_resour static inline void set_SOGO(struct controller *ctrl) { u16 misc; - + misc = readw(ctrl->hpc_reg + MISC); misc = (misc | 0x0001) & 0xFFFB; writew(misc, ctrl->hpc_reg + MISC); @@ -481,7 +496,7 @@ static inline void set_SOGO(struct controller *ctrl) static inline void amber_LED_on(struct controller *ctrl, u8 slot) { u32 led_control; - + led_control = readl(ctrl->hpc_reg + LED_CONTROL); led_control |= (0x01010000L << slot); writel(led_control, ctrl->hpc_reg + LED_CONTROL); @@ -491,7 +506,7 @@ static inline void amber_LED_on(struct controller *ctrl, u8 slot) static inline void amber_LED_off(struct controller *ctrl, u8 slot) { u32 led_control; - + led_control = readl(ctrl->hpc_reg + LED_CONTROL); led_control &= ~(0x01010000L << slot); writel(led_control, ctrl->hpc_reg + LED_CONTROL); @@ -504,7 +519,7 @@ static inline int read_amber_LED(struct controller *ctrl, u8 slot) led_control = readl(ctrl->hpc_reg + LED_CONTROL); led_control &= (0x01010000L << slot); - + return led_control ? 1 : 0; } @@ -512,7 +527,7 @@ static inline int read_amber_LED(struct controller *ctrl, u8 slot) static inline void green_LED_on(struct controller *ctrl, u8 slot) { u32 led_control; - + led_control = readl(ctrl->hpc_reg + LED_CONTROL); led_control |= 0x0101L << slot; writel(led_control, ctrl->hpc_reg + LED_CONTROL); @@ -521,7 +536,7 @@ static inline void green_LED_on(struct controller *ctrl, u8 slot) static inline void green_LED_off(struct controller *ctrl, u8 slot) { u32 led_control; - + led_control = readl(ctrl->hpc_reg + LED_CONTROL); led_control &= ~(0x0101L << slot); writel(led_control, ctrl->hpc_reg + LED_CONTROL); @@ -531,7 +546,7 @@ static inline void green_LED_off(struct controller *ctrl, u8 slot) static inline void green_LED_blink(struct controller *ctrl, u8 slot) { u32 led_control; - + led_control = readl(ctrl->hpc_reg + LED_CONTROL); led_control &= ~(0x0101L << slot); led_control |= (0x0001L << slot); @@ -575,22 +590,21 @@ static inline u8 read_slot_enable(struct controller *ctrl) } -/* +/** * get_controller_speed - find the current frequency/mode of controller. * * @ctrl: controller to get frequency/mode for. * * Returns controller speed. - * */ static inline u8 get_controller_speed(struct controller *ctrl) { u8 curr_freq; - u16 misc; - + u16 misc; + if (ctrl->pcix_support) { curr_freq = readb(ctrl->hpc_reg + NEXT_CURR_FREQ); - if ((curr_freq & 0xB0) == 0xB0) + if ((curr_freq & 0xB0) == 0xB0) return PCI_SPEED_133MHz_PCIX; if ((curr_freq & 0xA0) == 0xA0) return PCI_SPEED_100MHz_PCIX; @@ -602,19 +616,18 @@ static inline u8 get_controller_speed(struct controller *ctrl) return PCI_SPEED_33MHz; } - misc = readw(ctrl->hpc_reg + MISC); - return (misc & 0x0800) ? PCI_SPEED_66MHz : PCI_SPEED_33MHz; + misc = readw(ctrl->hpc_reg + MISC); + return (misc & 0x0800) ? PCI_SPEED_66MHz : PCI_SPEED_33MHz; } - -/* + +/** * get_adapter_speed - find the max supported frequency/mode of adapter. * * @ctrl: hotplug controller. * @hp_slot: hotplug slot where adapter is installed. * * Returns adapter speed. - * */ static inline u8 get_adapter_speed(struct controller *ctrl, u8 hp_slot) { @@ -672,7 +685,8 @@ static inline int get_slot_enabled(struct controller *ctrl, struct slot *slot) } -static inline int cpq_get_latch_status(struct controller *ctrl, struct slot *slot) +static inline int cpq_get_latch_status(struct controller *ctrl, + struct slot *slot) { u32 status; u8 hp_slot; @@ -687,7 +701,8 @@ static inline int cpq_get_latch_status(struct controller *ctrl, struct slot *slo } -static inline int get_presence_status(struct controller *ctrl, struct slot *slot) +static inline int get_presence_status(struct controller *ctrl, + struct slot *slot) { int presence_save = 0; u8 hp_slot; @@ -696,7 +711,8 @@ static inline int get_presence_status(struct controller *ctrl, struct slot *slot hp_slot = slot->device - ctrl->slot_device_offset; tempdword = readl(ctrl->hpc_reg + INT_INPUT_CLEAR); - presence_save = (int) ((((~tempdword) >> 23) | ((~tempdword) >> 15)) >> hp_slot) & 0x02; + presence_save = (int) ((((~tempdword) >> 23) | ((~tempdword) >> 15)) + >> hp_slot) & 0x02; return presence_save; } @@ -718,5 +734,12 @@ static inline int wait_for_ctrl_irq(struct controller *ctrl) return retval; } -#endif +#include +static inline int cpqhp_routing_table_length(void) +{ + BUG_ON(cpqhp_routing_table == NULL); + return ((cpqhp_routing_table->size - sizeof(struct irq_routing_table)) / + sizeof(struct irq_info)); +} +#endif diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c index c2e1bcbb28a7..075b4f4b6e0d 100644 --- a/drivers/pci/hotplug/cpqphp_core.c +++ b/drivers/pci/hotplug/cpqphp_core.c @@ -25,8 +25,7 @@ * Send feedback to * * Jan 12, 2003 - Added 66/100/133MHz PCI-X support, - * Torben Mathiasen - * + * Torben Mathiasen */ #include @@ -45,7 +44,6 @@ #include "cpqphp.h" #include "cpqphp_nvram.h" -#include /* Global variables */ @@ -53,6 +51,7 @@ int cpqhp_debug; int cpqhp_legacy_mode; struct controller *cpqhp_ctrl_list; /* = NULL */ struct pci_func *cpqhp_slot_list[256]; +struct irq_routing_table *cpqhp_routing_table; /* local variables */ static void __iomem *smbios_table; @@ -78,33 +77,6 @@ MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); #define CPQHPC_MODULE_MINOR 208 -static int one_time_init (void); -static int set_attention_status (struct hotplug_slot *slot, u8 value); -static int process_SI (struct hotplug_slot *slot); -static int process_SS (struct hotplug_slot *slot); -static int hardware_test (struct hotplug_slot *slot, u32 value); -static int get_power_status (struct hotplug_slot *slot, u8 *value); -static int get_attention_status (struct hotplug_slot *slot, u8 *value); -static int get_latch_status (struct hotplug_slot *slot, u8 *value); -static int get_adapter_status (struct hotplug_slot *slot, u8 *value); -static int get_max_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); -static int get_cur_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); - -static struct hotplug_slot_ops cpqphp_hotplug_slot_ops = { - .owner = THIS_MODULE, - .set_attention_status = set_attention_status, - .enable_slot = process_SI, - .disable_slot = process_SS, - .hardware_test = hardware_test, - .get_power_status = get_power_status, - .get_attention_status = get_attention_status, - .get_latch_status = get_latch_status, - .get_adapter_status = get_adapter_status, - .get_max_bus_speed = get_max_bus_speed, - .get_cur_bus_speed = get_cur_bus_speed, -}; - - static inline int is_slot64bit(struct slot *slot) { return (readb(slot->p_sm_slot + SMBIOS_SLOT_WIDTH) == 0x06) ? 1 : 0; @@ -144,7 +116,7 @@ static void __iomem * detect_SMBIOS_pointer(void __iomem *begin, void __iomem *e break; } } - + if (!status) fp = NULL; @@ -171,7 +143,7 @@ static int init_SERR(struct controller * ctrl) tempdword = ctrl->first_slot; number_of_slots = readb(ctrl->hpc_reg + SLOT_MASK) & 0x0F; - // Loop through slots + /* Loop through slots */ while (number_of_slots) { physical_slot = tempdword; writeb(0, ctrl->hpc_reg + SLOT_SERR); @@ -182,41 +154,42 @@ static int init_SERR(struct controller * ctrl) return 0; } - -/* nice debugging output */ -static int pci_print_IRQ_route (void) +static int init_cpqhp_routing_table(void) { - struct irq_routing_table *routing_table; int len; - int loop; - u8 tbus, tdevice, tslot; - - routing_table = pcibios_get_irq_routing_table(); - if (routing_table == NULL) { - err("No BIOS Routing Table??? Not good\n"); + cpqhp_routing_table = pcibios_get_irq_routing_table(); + if (cpqhp_routing_table == NULL) return -ENOMEM; - } - len = (routing_table->size - sizeof(struct irq_routing_table)) / - sizeof(struct irq_info); - // Make sure I got at least one entry + len = cpqhp_routing_table_length(); if (len == 0) { - kfree(routing_table); + kfree(cpqhp_routing_table); + cpqhp_routing_table = NULL; return -1; } - dbg("bus dev func slot\n"); + return 0; +} +/* nice debugging output */ +static void pci_print_IRQ_route(void) +{ + int len; + int loop; + u8 tbus, tdevice, tslot; + + len = cpqhp_routing_table_length(); + + dbg("bus dev func slot\n"); for (loop = 0; loop < len; ++loop) { - tbus = routing_table->slots[loop].bus; - tdevice = routing_table->slots[loop].devfn; - tslot = routing_table->slots[loop].slot; + tbus = cpqhp_routing_table->slots[loop].bus; + tdevice = cpqhp_routing_table->slots[loop].devfn; + tslot = cpqhp_routing_table->slots[loop].slot; dbg("%d %d %d %d\n", tbus, tdevice >> 3, tdevice & 0x7, tslot); } - kfree(routing_table); - return 0; + return; } @@ -242,9 +215,9 @@ static void __iomem *get_subsequent_smbios_entry(void __iomem *smbios_start, void __iomem *p_max; if (!smbios_table || !curr) - return(NULL); + return NULL; - // set p_max to the end of the table + /* set p_max to the end of the table */ p_max = smbios_start + readw(smbios_table + ST_LENGTH); p_temp = curr; @@ -253,20 +226,19 @@ static void __iomem *get_subsequent_smbios_entry(void __iomem *smbios_start, while ((p_temp < p_max) && !bail) { /* Look for the double NULL terminator * The first condition is the previous byte - * and the second is the curr */ - if (!previous_byte && !(readb(p_temp))) { + * and the second is the curr + */ + if (!previous_byte && !(readb(p_temp))) bail = 1; - } previous_byte = readb(p_temp); p_temp++; } - if (p_temp < p_max) { + if (p_temp < p_max) return p_temp; - } else { + else return NULL; - } } @@ -292,21 +264,18 @@ static void __iomem *get_SMBIOS_entry(void __iomem *smbios_start, if (!smbios_table) return NULL; - if (!previous) { + if (!previous) previous = smbios_start; - } else { + else previous = get_subsequent_smbios_entry(smbios_start, smbios_table, previous); - } - while (previous) { - if (readb(previous + SMBIOS_GENERIC_TYPE) != type) { + while (previous) + if (readb(previous + SMBIOS_GENERIC_TYPE) != type) previous = get_subsequent_smbios_entry(smbios_start, smbios_table, previous); - } else { + else break; - } - } return previous; } @@ -322,144 +291,6 @@ static void release_slot(struct hotplug_slot *hotplug_slot) kfree(slot); } -#define SLOT_NAME_SIZE 10 - -static int ctrl_slot_setup(struct controller *ctrl, - void __iomem *smbios_start, - void __iomem *smbios_table) -{ - struct slot *slot; - struct hotplug_slot *hotplug_slot; - struct hotplug_slot_info *hotplug_slot_info; - u8 number_of_slots; - u8 slot_device; - u8 slot_number; - u8 ctrl_slot; - u32 tempdword; - char name[SLOT_NAME_SIZE]; - void __iomem *slot_entry= NULL; - int result = -ENOMEM; - - dbg("%s\n", __func__); - - tempdword = readl(ctrl->hpc_reg + INT_INPUT_CLEAR); - - number_of_slots = readb(ctrl->hpc_reg + SLOT_MASK) & 0x0F; - slot_device = readb(ctrl->hpc_reg + SLOT_MASK) >> 4; - slot_number = ctrl->first_slot; - - while (number_of_slots) { - slot = kzalloc(sizeof(*slot), GFP_KERNEL); - if (!slot) - goto error; - - slot->hotplug_slot = kzalloc(sizeof(*(slot->hotplug_slot)), - GFP_KERNEL); - if (!slot->hotplug_slot) - goto error_slot; - hotplug_slot = slot->hotplug_slot; - - hotplug_slot->info = - kzalloc(sizeof(*(hotplug_slot->info)), - GFP_KERNEL); - if (!hotplug_slot->info) - goto error_hpslot; - hotplug_slot_info = hotplug_slot->info; - - slot->ctrl = ctrl; - slot->bus = ctrl->bus; - slot->device = slot_device; - slot->number = slot_number; - dbg("slot->number = %u\n", slot->number); - - slot_entry = get_SMBIOS_entry(smbios_start, smbios_table, 9, - slot_entry); - - while (slot_entry && (readw(slot_entry + SMBIOS_SLOT_NUMBER) != - slot->number)) { - slot_entry = get_SMBIOS_entry(smbios_start, - smbios_table, 9, slot_entry); - } - - slot->p_sm_slot = slot_entry; - - init_timer(&slot->task_event); - slot->task_event.expires = jiffies + 5 * HZ; - slot->task_event.function = cpqhp_pushbutton_thread; - - //FIXME: these capabilities aren't used but if they are - // they need to be correctly implemented - slot->capabilities |= PCISLOT_REPLACE_SUPPORTED; - slot->capabilities |= PCISLOT_INTERLOCK_SUPPORTED; - - if (is_slot64bit(slot)) - slot->capabilities |= PCISLOT_64_BIT_SUPPORTED; - if (is_slot66mhz(slot)) - slot->capabilities |= PCISLOT_66_MHZ_SUPPORTED; - if (ctrl->speed == PCI_SPEED_66MHz) - slot->capabilities |= PCISLOT_66_MHZ_OPERATION; - - ctrl_slot = - slot_device - (readb(ctrl->hpc_reg + SLOT_MASK) >> 4); - - // Check presence - slot->capabilities |= - ((((~tempdword) >> 23) | - ((~tempdword) >> 15)) >> ctrl_slot) & 0x02; - // Check the switch state - slot->capabilities |= - ((~tempdword & 0xFF) >> ctrl_slot) & 0x01; - // Check the slot enable - slot->capabilities |= - ((read_slot_enable(ctrl) << 2) >> ctrl_slot) & 0x04; - - /* register this slot with the hotplug pci core */ - hotplug_slot->release = &release_slot; - hotplug_slot->private = slot; - snprintf(name, SLOT_NAME_SIZE, "%u", slot->number); - hotplug_slot->ops = &cpqphp_hotplug_slot_ops; - - hotplug_slot_info->power_status = get_slot_enabled(ctrl, slot); - hotplug_slot_info->attention_status = - cpq_get_attention_status(ctrl, slot); - hotplug_slot_info->latch_status = - cpq_get_latch_status(ctrl, slot); - hotplug_slot_info->adapter_status = - get_presence_status(ctrl, slot); - - dbg("registering bus %d, dev %d, number %d, " - "ctrl->slot_device_offset %d, slot %d\n", - slot->bus, slot->device, - slot->number, ctrl->slot_device_offset, - slot_number); - result = pci_hp_register(hotplug_slot, - ctrl->pci_dev->bus, - slot->device, - name); - if (result) { - err("pci_hp_register failed with error %d\n", result); - goto error_info; - } - - slot->next = ctrl->slot; - ctrl->slot = slot; - - number_of_slots--; - slot_device++; - slot_number++; - } - - return 0; -error_info: - kfree(hotplug_slot_info); -error_hpslot: - kfree(hotplug_slot); -error_slot: - kfree(slot); -error: - return result; -} - static int ctrl_slot_cleanup (struct controller * ctrl) { struct slot *old_slot, *next_slot; @@ -476,36 +307,32 @@ static int ctrl_slot_cleanup (struct controller * ctrl) cpqhp_remove_debugfs_files(ctrl); - //Free IRQ associated with hot plug device + /* Free IRQ associated with hot plug device */ free_irq(ctrl->interrupt, ctrl); - //Unmap the memory + /* Unmap the memory */ iounmap(ctrl->hpc_reg); - //Finally reclaim PCI mem + /* Finally reclaim PCI mem */ release_mem_region(pci_resource_start(ctrl->pci_dev, 0), pci_resource_len(ctrl->pci_dev, 0)); - return(0); + return 0; } -//============================================================================ -// function: get_slot_mapping -// -// Description: Attempts to determine a logical slot mapping for a PCI -// device. Won't work for more than one PCI-PCI bridge -// in a slot. -// -// Input: u8 bus_num - bus number of PCI device -// u8 dev_num - device number of PCI device -// u8 *slot - Pointer to u8 where slot number will -// be returned -// -// Output: SUCCESS or FAILURE -//============================================================================= +/** + * get_slot_mapping - determine logical slot mapping for PCI device + * + * Won't work for more than one PCI-PCI bridge in a slot. + * + * @bus_num - bus number of PCI device + * @dev_num - device number of PCI device + * @slot - Pointer to u8 where slot number will be returned + * + * Output: SUCCESS or FAILURE + */ static int get_slot_mapping(struct pci_bus *bus, u8 bus_num, u8 dev_num, u8 *slot) { - struct irq_routing_table *PCIIRQRoutingInfoLength; u32 work; long len; long loop; @@ -516,36 +343,25 @@ get_slot_mapping(struct pci_bus *bus, u8 bus_num, u8 dev_num, u8 *slot) bridgeSlot = 0xFF; - PCIIRQRoutingInfoLength = pcibios_get_irq_routing_table(); - if (!PCIIRQRoutingInfoLength) - return -1; - - len = (PCIIRQRoutingInfoLength->size - - sizeof(struct irq_routing_table)) / sizeof(struct irq_info); - // Make sure I got at least one entry - if (len == 0) { - kfree(PCIIRQRoutingInfoLength); - return -1; - } - + len = cpqhp_routing_table_length(); for (loop = 0; loop < len; ++loop) { - tbus = PCIIRQRoutingInfoLength->slots[loop].bus; - tdevice = PCIIRQRoutingInfoLength->slots[loop].devfn >> 3; - tslot = PCIIRQRoutingInfoLength->slots[loop].slot; + tbus = cpqhp_routing_table->slots[loop].bus; + tdevice = cpqhp_routing_table->slots[loop].devfn >> 3; + tslot = cpqhp_routing_table->slots[loop].slot; if ((tbus == bus_num) && (tdevice == dev_num)) { *slot = tslot; - kfree(PCIIRQRoutingInfoLength); return 0; } else { /* Did not get a match on the target PCI device. Check - * if the current IRQ table entry is a PCI-to-PCI bridge - * device. If so, and it's secondary bus matches the - * bus number for the target device, I need to save the - * bridge's slot number. If I can not find an entry for - * the target device, I will have to assume it's on the - * other side of the bridge, and assign it the bridge's - * slot. */ + * if the current IRQ table entry is a PCI-to-PCI + * bridge device. If so, and it's secondary bus + * matches the bus number for the target device, I need + * to save the bridge's slot number. If I can not find + * an entry for the target device, I will have to + * assume it's on the other side of the bridge, and + * assign it the bridge's slot. + */ bus->number = tbus; pci_bus_read_config_dword(bus, PCI_DEVFN(tdevice, 0), PCI_CLASS_REVISION, &work); @@ -555,25 +371,23 @@ get_slot_mapping(struct pci_bus *bus, u8 bus_num, u8 dev_num, u8 *slot) PCI_DEVFN(tdevice, 0), PCI_PRIMARY_BUS, &work); // See if bridge's secondary bus matches target bus. - if (((work >> 8) & 0x000000FF) == (long) bus_num) { + if (((work >> 8) & 0x000000FF) == (long) bus_num) bridgeSlot = tslot; - } } } } - // If we got here, we didn't find an entry in the IRQ mapping table - // for the target PCI device. If we did determine that the target - // device is on the other side of a PCI-to-PCI bridge, return the - // slot number for the bridge. + /* If we got here, we didn't find an entry in the IRQ mapping table for + * the target PCI device. If we did determine that the target device + * is on the other side of a PCI-to-PCI bridge, return the slot number + * for the bridge. + */ if (bridgeSlot != 0xFF) { *slot = bridgeSlot; - kfree(PCIIRQRoutingInfoLength); return 0; } - kfree(PCIIRQRoutingInfoLength); - // Couldn't find an entry in the routing table for this PCI device + /* Couldn't find an entry in the routing table for this PCI device */ return -1; } @@ -591,32 +405,32 @@ cpqhp_set_attention_status(struct controller *ctrl, struct pci_func *func, u8 hp_slot; if (func == NULL) - return(1); + return 1; hp_slot = func->device - ctrl->slot_device_offset; - // Wait for exclusive access to hardware + /* Wait for exclusive access to hardware */ mutex_lock(&ctrl->crit_sect); - if (status == 1) { + if (status == 1) amber_LED_on (ctrl, hp_slot); - } else if (status == 0) { + else if (status == 0) amber_LED_off (ctrl, hp_slot); - } else { - // Done with exclusive hardware access + else { + /* Done with exclusive hardware access */ mutex_unlock(&ctrl->crit_sect); - return(1); + return 1; } set_SOGO(ctrl); - // Wait for SOBS to be unset + /* Wait for SOBS to be unset */ wait_for_ctrl_irq (ctrl); - // Done with exclusive hardware access + /* Done with exclusive hardware access */ mutex_unlock(&ctrl->crit_sect); - return(0); + return 0; } @@ -719,7 +533,7 @@ static int hardware_test(struct hotplug_slot *hotplug_slot, u32 value) dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); - return cpqhp_hardware_test(ctrl, value); + return cpqhp_hardware_test(ctrl, value); } @@ -738,7 +552,7 @@ static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value) { struct slot *slot = hotplug_slot->private; struct controller *ctrl = slot->ctrl; - + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); *value = cpq_get_attention_status(ctrl, slot); @@ -793,6 +607,230 @@ static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_sp return 0; } +static struct hotplug_slot_ops cpqphp_hotplug_slot_ops = { + .set_attention_status = set_attention_status, + .enable_slot = process_SI, + .disable_slot = process_SS, + .hardware_test = hardware_test, + .get_power_status = get_power_status, + .get_attention_status = get_attention_status, + .get_latch_status = get_latch_status, + .get_adapter_status = get_adapter_status, + .get_max_bus_speed = get_max_bus_speed, + .get_cur_bus_speed = get_cur_bus_speed, +}; + +#define SLOT_NAME_SIZE 10 + +static int ctrl_slot_setup(struct controller *ctrl, + void __iomem *smbios_start, + void __iomem *smbios_table) +{ + struct slot *slot; + struct hotplug_slot *hotplug_slot; + struct hotplug_slot_info *hotplug_slot_info; + u8 number_of_slots; + u8 slot_device; + u8 slot_number; + u8 ctrl_slot; + u32 tempdword; + char name[SLOT_NAME_SIZE]; + void __iomem *slot_entry= NULL; + int result = -ENOMEM; + + dbg("%s\n", __func__); + + tempdword = readl(ctrl->hpc_reg + INT_INPUT_CLEAR); + + number_of_slots = readb(ctrl->hpc_reg + SLOT_MASK) & 0x0F; + slot_device = readb(ctrl->hpc_reg + SLOT_MASK) >> 4; + slot_number = ctrl->first_slot; + + while (number_of_slots) { + slot = kzalloc(sizeof(*slot), GFP_KERNEL); + if (!slot) + goto error; + + slot->hotplug_slot = kzalloc(sizeof(*(slot->hotplug_slot)), + GFP_KERNEL); + if (!slot->hotplug_slot) + goto error_slot; + hotplug_slot = slot->hotplug_slot; + + hotplug_slot->info = kzalloc(sizeof(*(hotplug_slot->info)), + GFP_KERNEL); + if (!hotplug_slot->info) + goto error_hpslot; + hotplug_slot_info = hotplug_slot->info; + + slot->ctrl = ctrl; + slot->bus = ctrl->bus; + slot->device = slot_device; + slot->number = slot_number; + dbg("slot->number = %u\n", slot->number); + + slot_entry = get_SMBIOS_entry(smbios_start, smbios_table, 9, + slot_entry); + + while (slot_entry && (readw(slot_entry + SMBIOS_SLOT_NUMBER) != + slot->number)) { + slot_entry = get_SMBIOS_entry(smbios_start, + smbios_table, 9, slot_entry); + } + + slot->p_sm_slot = slot_entry; + + init_timer(&slot->task_event); + slot->task_event.expires = jiffies + 5 * HZ; + slot->task_event.function = cpqhp_pushbutton_thread; + + /*FIXME: these capabilities aren't used but if they are + * they need to be correctly implemented + */ + slot->capabilities |= PCISLOT_REPLACE_SUPPORTED; + slot->capabilities |= PCISLOT_INTERLOCK_SUPPORTED; + + if (is_slot64bit(slot)) + slot->capabilities |= PCISLOT_64_BIT_SUPPORTED; + if (is_slot66mhz(slot)) + slot->capabilities |= PCISLOT_66_MHZ_SUPPORTED; + if (ctrl->speed == PCI_SPEED_66MHz) + slot->capabilities |= PCISLOT_66_MHZ_OPERATION; + + ctrl_slot = + slot_device - (readb(ctrl->hpc_reg + SLOT_MASK) >> 4); + + /* Check presence */ + slot->capabilities |= + ((((~tempdword) >> 23) | + ((~tempdword) >> 15)) >> ctrl_slot) & 0x02; + /* Check the switch state */ + slot->capabilities |= + ((~tempdword & 0xFF) >> ctrl_slot) & 0x01; + /* Check the slot enable */ + slot->capabilities |= + ((read_slot_enable(ctrl) << 2) >> ctrl_slot) & 0x04; + + /* register this slot with the hotplug pci core */ + hotplug_slot->release = &release_slot; + hotplug_slot->private = slot; + snprintf(name, SLOT_NAME_SIZE, "%u", slot->number); + hotplug_slot->ops = &cpqphp_hotplug_slot_ops; + + hotplug_slot_info->power_status = get_slot_enabled(ctrl, slot); + hotplug_slot_info->attention_status = + cpq_get_attention_status(ctrl, slot); + hotplug_slot_info->latch_status = + cpq_get_latch_status(ctrl, slot); + hotplug_slot_info->adapter_status = + get_presence_status(ctrl, slot); + + dbg("registering bus %d, dev %d, number %d, " + "ctrl->slot_device_offset %d, slot %d\n", + slot->bus, slot->device, + slot->number, ctrl->slot_device_offset, + slot_number); + result = pci_hp_register(hotplug_slot, + ctrl->pci_dev->bus, + slot->device, + name); + if (result) { + err("pci_hp_register failed with error %d\n", result); + goto error_info; + } + + slot->next = ctrl->slot; + ctrl->slot = slot; + + number_of_slots--; + slot_device++; + slot_number++; + } + + return 0; +error_info: + kfree(hotplug_slot_info); +error_hpslot: + kfree(hotplug_slot); +error_slot: + kfree(slot); +error: + return result; +} + +static int one_time_init(void) +{ + int loop; + int retval = 0; + + if (initialized) + return 0; + + power_mode = 0; + + retval = init_cpqhp_routing_table(); + if (retval) + goto error; + + if (cpqhp_debug) + pci_print_IRQ_route(); + + dbg("Initialize + Start the notification mechanism \n"); + + retval = cpqhp_event_start_thread(); + if (retval) + goto error; + + dbg("Initialize slot lists\n"); + for (loop = 0; loop < 256; loop++) + cpqhp_slot_list[loop] = NULL; + + /* FIXME: We also need to hook the NMI handler eventually. + * this also needs to be worked with Christoph + * register_NMI_handler(); + */ + /* Map rom address */ + cpqhp_rom_start = ioremap(ROM_PHY_ADDR, ROM_PHY_LEN); + if (!cpqhp_rom_start) { + err ("Could not ioremap memory region for ROM\n"); + retval = -EIO; + goto error; + } + + /* Now, map the int15 entry point if we are on compaq specific + * hardware + */ + compaq_nvram_init(cpqhp_rom_start); + + /* Map smbios table entry point structure */ + smbios_table = detect_SMBIOS_pointer(cpqhp_rom_start, + cpqhp_rom_start + ROM_PHY_LEN); + if (!smbios_table) { + err ("Could not find the SMBIOS pointer in memory\n"); + retval = -EIO; + goto error_rom_start; + } + + smbios_start = ioremap(readl(smbios_table + ST_ADDRESS), + readw(smbios_table + ST_LENGTH)); + if (!smbios_start) { + err ("Could not ioremap memory region taken from SMBIOS values\n"); + retval = -EIO; + goto error_smbios_start; + } + + initialized = 1; + + return retval; + +error_smbios_start: + iounmap(smbios_start); +error_rom_start: + iounmap(cpqhp_rom_start); +error: + return retval; +} + static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { u8 num_of_slots = 0; @@ -815,7 +853,9 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) return err; } - // Need to read VID early b/c it's used to differentiate CPQ and INTC discovery + /* Need to read VID early b/c it's used to differentiate CPQ and INTC + * discovery + */ rc = pci_read_config_word(pdev, PCI_VENDOR_ID, &vendor_id); if (rc || ((vendor_id != PCI_VENDOR_ID_COMPAQ) && (vendor_id != PCI_VENDOR_ID_INTEL))) { err(msg_HPC_non_compaq_or_intel); @@ -832,217 +872,209 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } /* Check for the proper subsytem ID's - * Intel uses a different SSID programming model than Compaq. + * Intel uses a different SSID programming model than Compaq. * For Intel, each SSID bit identifies a PHP capability. * Also Intel HPC's may have RID=0. */ - if ((pdev->revision > 2) || (vendor_id == PCI_VENDOR_ID_INTEL)) { - // TODO: This code can be made to support non-Compaq or Intel subsystem IDs - rc = pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vid); - if (rc) { - err("%s : pci_read_config_word failed\n", __func__); - goto err_disable_device; - } - dbg("Subsystem Vendor ID: %x\n", subsystem_vid); - if ((subsystem_vid != PCI_VENDOR_ID_COMPAQ) && (subsystem_vid != PCI_VENDOR_ID_INTEL)) { - err(msg_HPC_non_compaq_or_intel); - rc = -ENODEV; - goto err_disable_device; - } - - ctrl = kzalloc(sizeof(struct controller), GFP_KERNEL); - if (!ctrl) { - err("%s : out of memory\n", __func__); - rc = -ENOMEM; - goto err_disable_device; - } - - rc = pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &subsystem_deviceid); - if (rc) { - err("%s : pci_read_config_word failed\n", __func__); - goto err_free_ctrl; - } - - info("Hot Plug Subsystem Device ID: %x\n", subsystem_deviceid); - - /* Set Vendor ID, so it can be accessed later from other functions */ - ctrl->vendor_id = vendor_id; - - switch (subsystem_vid) { - case PCI_VENDOR_ID_COMPAQ: - if (pdev->revision >= 0x13) { /* CIOBX */ - ctrl->push_flag = 1; - ctrl->slot_switch_type = 1; - ctrl->push_button = 1; - ctrl->pci_config_space = 1; - ctrl->defeature_PHP = 1; - ctrl->pcix_support = 1; - ctrl->pcix_speed_capability = 1; - pci_read_config_byte(pdev, 0x41, &bus_cap); - if (bus_cap & 0x80) { - dbg("bus max supports 133MHz PCI-X\n"); - ctrl->speed_capability = PCI_SPEED_133MHz_PCIX; - break; - } - if (bus_cap & 0x40) { - dbg("bus max supports 100MHz PCI-X\n"); - ctrl->speed_capability = PCI_SPEED_100MHz_PCIX; - break; - } - if (bus_cap & 20) { - dbg("bus max supports 66MHz PCI-X\n"); - ctrl->speed_capability = PCI_SPEED_66MHz_PCIX; - break; - } - if (bus_cap & 10) { - dbg("bus max supports 66MHz PCI\n"); - ctrl->speed_capability = PCI_SPEED_66MHz; - break; - } - - break; - } - - switch (subsystem_deviceid) { - case PCI_SUB_HPC_ID: - /* Original 6500/7000 implementation */ - ctrl->slot_switch_type = 1; - ctrl->speed_capability = PCI_SPEED_33MHz; - ctrl->push_button = 0; - ctrl->pci_config_space = 1; - ctrl->defeature_PHP = 1; - ctrl->pcix_support = 0; - ctrl->pcix_speed_capability = 0; - break; - case PCI_SUB_HPC_ID2: - /* First Pushbutton implementation */ - ctrl->push_flag = 1; - ctrl->slot_switch_type = 1; - ctrl->speed_capability = PCI_SPEED_33MHz; - ctrl->push_button = 1; - ctrl->pci_config_space = 1; - ctrl->defeature_PHP = 1; - ctrl->pcix_support = 0; - ctrl->pcix_speed_capability = 0; - break; - case PCI_SUB_HPC_ID_INTC: - /* Third party (6500/7000) */ - ctrl->slot_switch_type = 1; - ctrl->speed_capability = PCI_SPEED_33MHz; - ctrl->push_button = 0; - ctrl->pci_config_space = 1; - ctrl->defeature_PHP = 1; - ctrl->pcix_support = 0; - ctrl->pcix_speed_capability = 0; - break; - case PCI_SUB_HPC_ID3: - /* First 66 Mhz implementation */ - ctrl->push_flag = 1; - ctrl->slot_switch_type = 1; - ctrl->speed_capability = PCI_SPEED_66MHz; - ctrl->push_button = 1; - ctrl->pci_config_space = 1; - ctrl->defeature_PHP = 1; - ctrl->pcix_support = 0; - ctrl->pcix_speed_capability = 0; - break; - case PCI_SUB_HPC_ID4: - /* First PCI-X implementation, 100MHz */ - ctrl->push_flag = 1; - ctrl->slot_switch_type = 1; - ctrl->speed_capability = PCI_SPEED_100MHz_PCIX; - ctrl->push_button = 1; - ctrl->pci_config_space = 1; - ctrl->defeature_PHP = 1; - ctrl->pcix_support = 1; - ctrl->pcix_speed_capability = 0; - break; - default: - err(msg_HPC_not_supported); - rc = -ENODEV; - goto err_free_ctrl; - } - break; - - case PCI_VENDOR_ID_INTEL: - /* Check for speed capability (0=33, 1=66) */ - if (subsystem_deviceid & 0x0001) { - ctrl->speed_capability = PCI_SPEED_66MHz; - } else { - ctrl->speed_capability = PCI_SPEED_33MHz; - } - - /* Check for push button */ - if (subsystem_deviceid & 0x0002) { - /* no push button */ - ctrl->push_button = 0; - } else { - /* push button supported */ - ctrl->push_button = 1; - } - - /* Check for slot switch type (0=mechanical, 1=not mechanical) */ - if (subsystem_deviceid & 0x0004) { - /* no switch */ - ctrl->slot_switch_type = 0; - } else { - /* switch */ - ctrl->slot_switch_type = 1; - } - - /* PHP Status (0=De-feature PHP, 1=Normal operation) */ - if (subsystem_deviceid & 0x0008) { - ctrl->defeature_PHP = 1; // PHP supported - } else { - ctrl->defeature_PHP = 0; // PHP not supported - } - - /* Alternate Base Address Register Interface (0=not supported, 1=supported) */ - if (subsystem_deviceid & 0x0010) { - ctrl->alternate_base_address = 1; // supported - } else { - ctrl->alternate_base_address = 0; // not supported - } - - /* PCI Config Space Index (0=not supported, 1=supported) */ - if (subsystem_deviceid & 0x0020) { - ctrl->pci_config_space = 1; // supported - } else { - ctrl->pci_config_space = 0; // not supported - } - - /* PCI-X support */ - if (subsystem_deviceid & 0x0080) { - /* PCI-X capable */ - ctrl->pcix_support = 1; - /* Frequency of operation in PCI-X mode */ - if (subsystem_deviceid & 0x0040) { - /* 133MHz PCI-X if bit 7 is 1 */ - ctrl->pcix_speed_capability = 1; - } else { - /* 100MHz PCI-X if bit 7 is 1 and bit 0 is 0, */ - /* 66MHz PCI-X if bit 7 is 1 and bit 0 is 1 */ - ctrl->pcix_speed_capability = 0; - } - } else { - /* Conventional PCI */ - ctrl->pcix_support = 0; - ctrl->pcix_speed_capability = 0; - } - break; - - default: - err(msg_HPC_not_supported); - rc = -ENODEV; - goto err_free_ctrl; - } - - } else { + if ((pdev->revision <= 2) && (vendor_id != PCI_VENDOR_ID_INTEL)) { err(msg_HPC_not_supported); return -ENODEV; } - // Tell the user that we found one. + /* TODO: This code can be made to support non-Compaq or Intel + * subsystem IDs + */ + rc = pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vid); + if (rc) { + err("%s : pci_read_config_word failed\n", __func__); + goto err_disable_device; + } + dbg("Subsystem Vendor ID: %x\n", subsystem_vid); + if ((subsystem_vid != PCI_VENDOR_ID_COMPAQ) && (subsystem_vid != PCI_VENDOR_ID_INTEL)) { + err(msg_HPC_non_compaq_or_intel); + rc = -ENODEV; + goto err_disable_device; + } + + ctrl = kzalloc(sizeof(struct controller), GFP_KERNEL); + if (!ctrl) { + err("%s : out of memory\n", __func__); + rc = -ENOMEM; + goto err_disable_device; + } + + rc = pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &subsystem_deviceid); + if (rc) { + err("%s : pci_read_config_word failed\n", __func__); + goto err_free_ctrl; + } + + info("Hot Plug Subsystem Device ID: %x\n", subsystem_deviceid); + + /* Set Vendor ID, so it can be accessed later from other + * functions + */ + ctrl->vendor_id = vendor_id; + + switch (subsystem_vid) { + case PCI_VENDOR_ID_COMPAQ: + if (pdev->revision >= 0x13) { /* CIOBX */ + ctrl->push_flag = 1; + ctrl->slot_switch_type = 1; + ctrl->push_button = 1; + ctrl->pci_config_space = 1; + ctrl->defeature_PHP = 1; + ctrl->pcix_support = 1; + ctrl->pcix_speed_capability = 1; + pci_read_config_byte(pdev, 0x41, &bus_cap); + if (bus_cap & 0x80) { + dbg("bus max supports 133MHz PCI-X\n"); + ctrl->speed_capability = PCI_SPEED_133MHz_PCIX; + break; + } + if (bus_cap & 0x40) { + dbg("bus max supports 100MHz PCI-X\n"); + ctrl->speed_capability = PCI_SPEED_100MHz_PCIX; + break; + } + if (bus_cap & 20) { + dbg("bus max supports 66MHz PCI-X\n"); + ctrl->speed_capability = PCI_SPEED_66MHz_PCIX; + break; + } + if (bus_cap & 10) { + dbg("bus max supports 66MHz PCI\n"); + ctrl->speed_capability = PCI_SPEED_66MHz; + break; + } + + break; + } + + switch (subsystem_deviceid) { + case PCI_SUB_HPC_ID: + /* Original 6500/7000 implementation */ + ctrl->slot_switch_type = 1; + ctrl->speed_capability = PCI_SPEED_33MHz; + ctrl->push_button = 0; + ctrl->pci_config_space = 1; + ctrl->defeature_PHP = 1; + ctrl->pcix_support = 0; + ctrl->pcix_speed_capability = 0; + break; + case PCI_SUB_HPC_ID2: + /* First Pushbutton implementation */ + ctrl->push_flag = 1; + ctrl->slot_switch_type = 1; + ctrl->speed_capability = PCI_SPEED_33MHz; + ctrl->push_button = 1; + ctrl->pci_config_space = 1; + ctrl->defeature_PHP = 1; + ctrl->pcix_support = 0; + ctrl->pcix_speed_capability = 0; + break; + case PCI_SUB_HPC_ID_INTC: + /* Third party (6500/7000) */ + ctrl->slot_switch_type = 1; + ctrl->speed_capability = PCI_SPEED_33MHz; + ctrl->push_button = 0; + ctrl->pci_config_space = 1; + ctrl->defeature_PHP = 1; + ctrl->pcix_support = 0; + ctrl->pcix_speed_capability = 0; + break; + case PCI_SUB_HPC_ID3: + /* First 66 Mhz implementation */ + ctrl->push_flag = 1; + ctrl->slot_switch_type = 1; + ctrl->speed_capability = PCI_SPEED_66MHz; + ctrl->push_button = 1; + ctrl->pci_config_space = 1; + ctrl->defeature_PHP = 1; + ctrl->pcix_support = 0; + ctrl->pcix_speed_capability = 0; + break; + case PCI_SUB_HPC_ID4: + /* First PCI-X implementation, 100MHz */ + ctrl->push_flag = 1; + ctrl->slot_switch_type = 1; + ctrl->speed_capability = PCI_SPEED_100MHz_PCIX; + ctrl->push_button = 1; + ctrl->pci_config_space = 1; + ctrl->defeature_PHP = 1; + ctrl->pcix_support = 1; + ctrl->pcix_speed_capability = 0; + break; + default: + err(msg_HPC_not_supported); + rc = -ENODEV; + goto err_free_ctrl; + } + break; + + case PCI_VENDOR_ID_INTEL: + /* Check for speed capability (0=33, 1=66) */ + if (subsystem_deviceid & 0x0001) + ctrl->speed_capability = PCI_SPEED_66MHz; + else + ctrl->speed_capability = PCI_SPEED_33MHz; + + /* Check for push button */ + if (subsystem_deviceid & 0x0002) + ctrl->push_button = 0; + else + ctrl->push_button = 1; + + /* Check for slot switch type (0=mechanical, 1=not mechanical) */ + if (subsystem_deviceid & 0x0004) + ctrl->slot_switch_type = 0; + else + ctrl->slot_switch_type = 1; + + /* PHP Status (0=De-feature PHP, 1=Normal operation) */ + if (subsystem_deviceid & 0x0008) + ctrl->defeature_PHP = 1; /* PHP supported */ + else + ctrl->defeature_PHP = 0; /* PHP not supported */ + + /* Alternate Base Address Register Interface + * (0=not supported, 1=supported) + */ + if (subsystem_deviceid & 0x0010) + ctrl->alternate_base_address = 1; + else + ctrl->alternate_base_address = 0; + + /* PCI Config Space Index (0=not supported, 1=supported) */ + if (subsystem_deviceid & 0x0020) + ctrl->pci_config_space = 1; + else + ctrl->pci_config_space = 0; + + /* PCI-X support */ + if (subsystem_deviceid & 0x0080) { + ctrl->pcix_support = 1; + if (subsystem_deviceid & 0x0040) + /* 133MHz PCI-X if bit 7 is 1 */ + ctrl->pcix_speed_capability = 1; + else + /* 100MHz PCI-X if bit 7 is 1 and bit 0 is 0, */ + /* 66MHz PCI-X if bit 7 is 1 and bit 0 is 1 */ + ctrl->pcix_speed_capability = 0; + } else { + /* Conventional PCI */ + ctrl->pcix_support = 0; + ctrl->pcix_speed_capability = 0; + } + break; + + default: + err(msg_HPC_not_supported); + rc = -ENODEV; + goto err_free_ctrl; + } + + /* Tell the user that we found one. */ info("Initializing the PCI hot plug controller residing on PCI bus %d\n", pdev->bus->number); @@ -1087,7 +1119,7 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) { goto err_free_bus; } - + dbg("pdev = %p\n", pdev); dbg("pci resource start %llx\n", (unsigned long long)pci_resource_start(pdev, 0)); dbg("pci resource len %llx\n", (unsigned long long)pci_resource_len(pdev, 0)); @@ -1109,7 +1141,7 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_free_mem_region; } - // Check for 66Mhz operation + /* Check for 66Mhz operation */ ctrl->speed = get_controller_speed(ctrl); @@ -1120,7 +1152,7 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) * ********************************************************/ - // find the physical slot number of the first hot plug slot + /* find the physical slot number of the first hot plug slot */ /* Get slot won't work for devices behind bridges, but * in this case it will always be called for the "base" @@ -1137,7 +1169,7 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_iounmap; } - // Store PCI Config Space for all devices on this bus + /* Store PCI Config Space for all devices on this bus */ rc = cpqhp_save_config(ctrl, ctrl->bus, readb(ctrl->hpc_reg + SLOT_MASK)); if (rc) { err("%s: unable to save PCI configuration data, error %d\n", @@ -1148,7 +1180,7 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* * Get IO, memory, and IRQ resources for new devices */ - // The next line is required for cpqhp_find_available_resources + /* The next line is required for cpqhp_find_available_resources */ ctrl->interrupt = pdev->irq; if (ctrl->interrupt < 0x10) { cpqhp_legacy_mode = 1; @@ -1182,7 +1214,7 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) __func__, rc); goto err_iounmap; } - + /* Mask all general input interrupts */ writel(0xFFFFFFFFL, ctrl->hpc_reg + INT_MASK); @@ -1196,12 +1228,14 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_iounmap; } - /* Enable Shift Out interrupt and clear it, also enable SERR on power fault */ + /* Enable Shift Out interrupt and clear it, also enable SERR on power + * fault + */ temp_word = readw(ctrl->hpc_reg + MISC); temp_word |= 0x4006; writew(temp_word, ctrl->hpc_reg + MISC); - // Changed 05/05/97 to clear all interrupts at start + /* Changed 05/05/97 to clear all interrupts at start */ writel(0xFFFFFFFFL, ctrl->hpc_reg + INT_INPUT_CLEAR); ctrl->ctrl_int_comp = readl(ctrl->hpc_reg + INT_INPUT_CLEAR); @@ -1216,13 +1250,14 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) cpqhp_ctrl_list = ctrl; } - // turn off empty slots here unless command line option "ON" set - // Wait for exclusive access to hardware + /* turn off empty slots here unless command line option "ON" set + * Wait for exclusive access to hardware + */ mutex_lock(&ctrl->crit_sect); num_of_slots = readb(ctrl->hpc_reg + SLOT_MASK) & 0x0F; - // find first device number for the ctrl + /* find first device number for the ctrl */ device = readb(ctrl->hpc_reg + SLOT_MASK) >> 4; while (num_of_slots) { @@ -1234,23 +1269,21 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) hp_slot = func->device - ctrl->slot_device_offset; dbg("hp_slot: %d\n", hp_slot); - // We have to save the presence info for these slots + /* We have to save the presence info for these slots */ temp_word = ctrl->ctrl_int_comp >> 16; func->presence_save = (temp_word >> hp_slot) & 0x01; func->presence_save |= (temp_word >> (hp_slot + 7)) & 0x02; - if (ctrl->ctrl_int_comp & (0x1L << hp_slot)) { + if (ctrl->ctrl_int_comp & (0x1L << hp_slot)) func->switch_save = 0; - } else { + else func->switch_save = 0x10; - } - if (!power_mode) { + if (!power_mode) if (!func->is_a_board) { green_LED_off(ctrl, hp_slot); slot_disable(ctrl, hp_slot); } - } device++; num_of_slots--; @@ -1258,7 +1291,7 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (!power_mode) { set_SOGO(ctrl); - // Wait for SOBS to be unset + /* Wait for SOBS to be unset */ wait_for_ctrl_irq(ctrl); } @@ -1269,7 +1302,7 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_free_irq; } - // Done with exclusive hardware access + /* Done with exclusive hardware access */ mutex_unlock(&ctrl->crit_sect); cpqhp_create_debugfs_files(ctrl); @@ -1291,77 +1324,6 @@ err_disable_device: return rc; } - -static int one_time_init(void) -{ - int loop; - int retval = 0; - - if (initialized) - return 0; - - power_mode = 0; - - retval = pci_print_IRQ_route(); - if (retval) - goto error; - - dbg("Initialize + Start the notification mechanism \n"); - - retval = cpqhp_event_start_thread(); - if (retval) - goto error; - - dbg("Initialize slot lists\n"); - for (loop = 0; loop < 256; loop++) { - cpqhp_slot_list[loop] = NULL; - } - - // FIXME: We also need to hook the NMI handler eventually. - // this also needs to be worked with Christoph - // register_NMI_handler(); - - // Map rom address - cpqhp_rom_start = ioremap(ROM_PHY_ADDR, ROM_PHY_LEN); - if (!cpqhp_rom_start) { - err ("Could not ioremap memory region for ROM\n"); - retval = -EIO; - goto error; - } - - /* Now, map the int15 entry point if we are on compaq specific hardware */ - compaq_nvram_init(cpqhp_rom_start); - - /* Map smbios table entry point structure */ - smbios_table = detect_SMBIOS_pointer(cpqhp_rom_start, - cpqhp_rom_start + ROM_PHY_LEN); - if (!smbios_table) { - err ("Could not find the SMBIOS pointer in memory\n"); - retval = -EIO; - goto error_rom_start; - } - - smbios_start = ioremap(readl(smbios_table + ST_ADDRESS), - readw(smbios_table + ST_LENGTH)); - if (!smbios_start) { - err ("Could not ioremap memory region taken from SMBIOS values\n"); - retval = -EIO; - goto error_smbios_start; - } - - initialized = 1; - - return retval; - -error_smbios_start: - iounmap(smbios_start); -error_rom_start: - iounmap(cpqhp_rom_start); -error: - return retval; -} - - static void __exit unload_cpqphpd(void) { struct pci_func *next; @@ -1381,10 +1343,10 @@ static void __exit unload_cpqphpd(void) if (ctrl->hpc_reg) { u16 misc; rc = read_slot_enable (ctrl); - + writeb(0, ctrl->hpc_reg + SLOT_SERR); writel(0xFFFFFFC0L | ~rc, ctrl->hpc_reg + INT_MASK); - + misc = readw(ctrl->hpc_reg + MISC); misc &= 0xFFFD; writew(misc, ctrl->hpc_reg + MISC); @@ -1464,38 +1426,34 @@ static void __exit unload_cpqphpd(void) } } - // Stop the notification mechanism + /* Stop the notification mechanism */ if (initialized) cpqhp_event_stop_thread(); - //unmap the rom address + /* unmap the rom address */ if (cpqhp_rom_start) iounmap(cpqhp_rom_start); if (smbios_start) iounmap(smbios_start); } - - static struct pci_device_id hpcd_pci_tbl[] = { { /* handle any PCI Hotplug controller */ .class = ((PCI_CLASS_SYSTEM_PCI_HOTPLUG << 8) | 0x00), .class_mask = ~0, - + /* no matter who makes it */ .vendor = PCI_ANY_ID, .device = PCI_ANY_ID, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, - + }, { /* end: all zeroes */ } }; MODULE_DEVICE_TABLE(pci, hpcd_pci_tbl); - - static struct pci_driver cpqhpc_driver = { .name = "compaq_pci_hotplug", .id_table = hpcd_pci_tbl, @@ -1503,8 +1461,6 @@ static struct pci_driver cpqhpc_driver = { /* remove: cpqhpc_remove_one, */ }; - - static int __init cpqhpc_init(void) { int result; @@ -1518,7 +1474,6 @@ static int __init cpqhpc_init(void) return result; } - static void __exit cpqhpc_cleanup(void) { dbg("unload_cpqphpd()\n"); @@ -1529,8 +1484,5 @@ static void __exit cpqhpc_cleanup(void) cpqhp_shutdown_debugfs(); } - module_init(cpqhpc_init); module_exit(cpqhpc_cleanup); - - diff --git a/drivers/pci/hotplug/cpqphp_ctrl.c b/drivers/pci/hotplug/cpqphp_ctrl.c index cc227a8c4b11..2fa47af992a8 100644 --- a/drivers/pci/hotplug/cpqphp_ctrl.c +++ b/drivers/pci/hotplug/cpqphp_ctrl.c @@ -81,14 +81,15 @@ static u8 handle_switch_change(u8 change, struct controller * ctrl) for (hp_slot = 0; hp_slot < 6; hp_slot++) { if (change & (0x1L << hp_slot)) { - /********************************** + /* * this one changed. - **********************************/ + */ func = cpqhp_slot_find(ctrl->bus, (hp_slot + ctrl->slot_device_offset), 0); /* this is the structure that tells the worker thread - *what to do */ + * what to do + */ taskInfo = &(ctrl->event_queue[ctrl->next_event]); ctrl->next_event = (ctrl->next_event + 1) % 10; taskInfo->hp_slot = hp_slot; @@ -100,17 +101,17 @@ static u8 handle_switch_change(u8 change, struct controller * ctrl) func->presence_save |= (temp_word >> (hp_slot + 7)) & 0x02; if (ctrl->ctrl_int_comp & (0x1L << hp_slot)) { - /********************************** + /* * Switch opened - **********************************/ + */ func->switch_save = 0; taskInfo->event_type = INT_SWITCH_OPEN; } else { - /********************************** + /* * Switch closed - **********************************/ + */ func->switch_save = 0x10; @@ -131,9 +132,8 @@ static struct slot *cpqhp_find_slot(struct controller *ctrl, u8 device) { struct slot *slot = ctrl->slot; - while (slot && (slot->device != device)) { + while (slot && (slot->device != device)) slot = slot->next; - } return slot; } @@ -152,17 +152,17 @@ static u8 handle_presence_change(u16 change, struct controller * ctrl) if (!change) return 0; - /********************************** + /* * Presence Change - **********************************/ + */ dbg("cpqsbd: Presence/Notify input change.\n"); dbg(" Changed bits are 0x%4.4x\n", change ); for (hp_slot = 0; hp_slot < 6; hp_slot++) { if (change & (0x0101 << hp_slot)) { - /********************************** + /* * this one changed. - **********************************/ + */ func = cpqhp_slot_find(ctrl->bus, (hp_slot + ctrl->slot_device_offset), 0); @@ -177,22 +177,23 @@ static u8 handle_presence_change(u16 change, struct controller * ctrl) return 0; /* If the switch closed, must be a button - * If not in button mode, nevermind */ + * If not in button mode, nevermind + */ if (func->switch_save && (ctrl->push_button == 1)) { temp_word = ctrl->ctrl_int_comp >> 16; temp_byte = (temp_word >> hp_slot) & 0x01; temp_byte |= (temp_word >> (hp_slot + 7)) & 0x02; if (temp_byte != func->presence_save) { - /************************************** + /* * button Pressed (doesn't do anything) - **************************************/ + */ dbg("hp_slot %d button pressed\n", hp_slot); taskInfo->event_type = INT_BUTTON_PRESS; } else { - /********************************** + /* * button Released - TAKE ACTION!!!! - **********************************/ + */ dbg("hp_slot %d button released\n", hp_slot); taskInfo->event_type = INT_BUTTON_RELEASE; @@ -210,7 +211,8 @@ static u8 handle_presence_change(u16 change, struct controller * ctrl) } } else { /* Switch is open, assume a presence change - * Save the presence state */ + * Save the presence state + */ temp_word = ctrl->ctrl_int_comp >> 16; func->presence_save = (temp_word >> hp_slot) & 0x01; func->presence_save |= (temp_word >> (hp_slot + 7)) & 0x02; @@ -241,17 +243,17 @@ static u8 handle_power_fault(u8 change, struct controller * ctrl) if (!change) return 0; - /********************************** + /* * power fault - **********************************/ + */ info("power fault interrupt\n"); for (hp_slot = 0; hp_slot < 6; hp_slot++) { if (change & (0x01 << hp_slot)) { - /********************************** + /* * this one changed. - **********************************/ + */ func = cpqhp_slot_find(ctrl->bus, (hp_slot + ctrl->slot_device_offset), 0); @@ -262,16 +264,16 @@ static u8 handle_power_fault(u8 change, struct controller * ctrl) rc++; if (ctrl->ctrl_int_comp & (0x00000100 << hp_slot)) { - /********************************** + /* * power fault Cleared - **********************************/ + */ func->status = 0x00; taskInfo->event_type = INT_POWER_FAULT_CLEAR; } else { - /********************************** + /* * power fault - **********************************/ + */ taskInfo->event_type = INT_POWER_FAULT; if (ctrl->rev < 4) { @@ -432,13 +434,15 @@ static struct pci_resource *do_pre_bridge_resource_split(struct pci_resource **h /* If we got here, there the bridge requires some of the resource, but - * we may be able to split some off of the front */ + * we may be able to split some off of the front + */ node = *head; if (node->length & (alignment -1)) { /* this one isn't an aligned length, so we'll make a new entry - * and split it up. */ + * and split it up. + */ split_node = kmalloc(sizeof(*split_node), GFP_KERNEL); if (!split_node) @@ -544,10 +548,10 @@ static struct pci_resource *get_io_resource(struct pci_resource **head, u32 size if (!(*head)) return NULL; - if ( cpqhp_resource_sort_and_combine(head) ) + if (cpqhp_resource_sort_and_combine(head)) return NULL; - if ( sort_by_size(head) ) + if (sort_by_size(head)) return NULL; for (node = *head; node; node = node->next) { @@ -556,7 +560,8 @@ static struct pci_resource *get_io_resource(struct pci_resource **head, u32 size if (node->base & (size - 1)) { /* this one isn't base aligned properly - * so we'll make a new entry and split it up */ + * so we'll make a new entry and split it up + */ temp_dword = (node->base | (size-1)) + 1; /* Short circuit if adjusted size is too small */ @@ -581,7 +586,8 @@ static struct pci_resource *get_io_resource(struct pci_resource **head, u32 size /* Don't need to check if too small since we already did */ if (node->length > size) { /* this one is longer than we need - * so we'll make a new entry and split it up */ + * so we'll make a new entry and split it up + */ split_node = kmalloc(sizeof(*split_node), GFP_KERNEL); if (!split_node) @@ -601,7 +607,8 @@ static struct pci_resource *get_io_resource(struct pci_resource **head, u32 size continue; /* If we got here, then it is the right size - * Now take it out of the list and break */ + * Now take it out of the list and break + */ if (*head == node) { *head = node->next; } else { @@ -642,14 +649,16 @@ static struct pci_resource *get_max_resource(struct pci_resource **head, u32 siz return NULL; for (max = *head; max; max = max->next) { - /* If not big enough we could probably just bail, - * instead we'll continue to the next. */ + /* If not big enough we could probably just bail, + * instead we'll continue to the next. + */ if (max->length < size) continue; if (max->base & (size - 1)) { /* this one isn't base aligned properly - * so we'll make a new entry and split it up */ + * so we'll make a new entry and split it up + */ temp_dword = (max->base | (size-1)) + 1; /* Short circuit if adjusted size is too small */ @@ -672,7 +681,8 @@ static struct pci_resource *get_max_resource(struct pci_resource **head, u32 siz if ((max->base + max->length) & (size - 1)) { /* this one isn't end aligned properly at the top - * so we'll make a new entry and split it up */ + * so we'll make a new entry and split it up + */ split_node = kmalloc(sizeof(*split_node), GFP_KERNEL); if (!split_node) @@ -744,7 +754,8 @@ static struct pci_resource *get_resource(struct pci_resource **head, u32 size) if (node->base & (size - 1)) { dbg("%s: not aligned\n", __func__); /* this one isn't base aligned properly - * so we'll make a new entry and split it up */ + * so we'll make a new entry and split it up + */ temp_dword = (node->base | (size-1)) + 1; /* Short circuit if adjusted size is too small */ @@ -769,7 +780,8 @@ static struct pci_resource *get_resource(struct pci_resource **head, u32 size) if (node->length > size) { dbg("%s: too big\n", __func__); /* this one is longer than we need - * so we'll make a new entry and split it up */ + * so we'll make a new entry and split it up + */ split_node = kmalloc(sizeof(*split_node), GFP_KERNEL); if (!split_node) @@ -886,19 +898,19 @@ irqreturn_t cpqhp_ctrl_intr(int IRQ, void *data) u32 Diff; u32 temp_dword; - + misc = readw(ctrl->hpc_reg + MISC); - /*************************************** + /* * Check to see if it was our interrupt - ***************************************/ + */ if (!(misc & 0x000C)) { return IRQ_NONE; } if (misc & 0x0004) { - /********************************** + /* * Serial Output interrupt Pending - **********************************/ + */ /* Clear the interrupt */ misc |= 0x0004; @@ -961,11 +973,8 @@ struct pci_func *cpqhp_slot_create(u8 busnumber) struct pci_func *next; new_slot = kzalloc(sizeof(*new_slot), GFP_KERNEL); - if (new_slot == NULL) { - /* I'm not dead yet! - * You will be. */ + if (new_slot == NULL) return new_slot; - } new_slot->next = NULL; new_slot->configured = 1; @@ -996,10 +1005,8 @@ static int slot_remove(struct pci_func * old_slot) return 1; next = cpqhp_slot_list[old_slot->bus]; - - if (next == NULL) { + if (next == NULL) return 1; - } if (next == old_slot) { cpqhp_slot_list[old_slot->bus] = old_slot->next; @@ -1008,9 +1015,8 @@ static int slot_remove(struct pci_func * old_slot) return 0; } - while ((next->next != old_slot) && (next->next != NULL)) { + while ((next->next != old_slot) && (next->next != NULL)) next = next->next; - } if (next->next == old_slot) { next->next = old_slot->next; @@ -1040,9 +1046,8 @@ static int bridge_slot_remove(struct pci_func *bridge) for (tempBus = secondaryBus; tempBus <= subordinateBus; tempBus++) { next = cpqhp_slot_list[tempBus]; - while (!slot_remove(next)) { + while (!slot_remove(next)) next = cpqhp_slot_list[tempBus]; - } } next = cpqhp_slot_list[bridge->bus]; @@ -1130,39 +1135,43 @@ static u8 set_controller_speed(struct controller *ctrl, u8 adapter_speed, u8 hp_ u8 slot_power = readb(ctrl->hpc_reg + SLOT_POWER); u16 reg16; u32 leds = readl(ctrl->hpc_reg + LED_CONTROL); - + if (ctrl->speed == adapter_speed) return 0; - + /* We don't allow freq/mode changes if we find another adapter running - * in another slot on this controller */ + * in another slot on this controller + */ for(slot = ctrl->slot; slot; slot = slot->next) { - if (slot->device == (hp_slot + ctrl->slot_device_offset)) + if (slot->device == (hp_slot + ctrl->slot_device_offset)) continue; if (!slot->hotplug_slot || !slot->hotplug_slot->info) continue; - if (slot->hotplug_slot->info->adapter_status == 0) + if (slot->hotplug_slot->info->adapter_status == 0) continue; /* If another adapter is running on the same segment but at a * lower speed/mode, we allow the new adapter to function at - * this rate if supported */ - if (ctrl->speed < adapter_speed) + * this rate if supported + */ + if (ctrl->speed < adapter_speed) return 0; return 1; } - + /* If the controller doesn't support freq/mode changes and the - * controller is running at a higher mode, we bail */ + * controller is running at a higher mode, we bail + */ if ((ctrl->speed > adapter_speed) && (!ctrl->pcix_speed_capability)) return 1; - + /* But we allow the adapter to run at a lower rate if possible */ if ((ctrl->speed < adapter_speed) && (!ctrl->pcix_speed_capability)) return 0; /* We try to set the max speed supported by both the adapter and - * controller */ + * controller + */ if (ctrl->speed_capability < adapter_speed) { if (ctrl->speed == ctrl->speed_capability) return 0; @@ -1171,22 +1180,22 @@ static u8 set_controller_speed(struct controller *ctrl, u8 adapter_speed, u8 hp_ writel(0x0L, ctrl->hpc_reg + LED_CONTROL); writeb(0x00, ctrl->hpc_reg + SLOT_ENABLE); - - set_SOGO(ctrl); + + set_SOGO(ctrl); wait_for_ctrl_irq(ctrl); - + if (adapter_speed != PCI_SPEED_133MHz_PCIX) reg = 0xF5; else - reg = 0xF4; + reg = 0xF4; pci_write_config_byte(ctrl->pci_dev, 0x41, reg); - + reg16 = readw(ctrl->hpc_reg + NEXT_CURR_FREQ); reg16 &= ~0x000F; switch(adapter_speed) { - case(PCI_SPEED_133MHz_PCIX): + case(PCI_SPEED_133MHz_PCIX): reg = 0x75; - reg16 |= 0xB; + reg16 |= 0xB; break; case(PCI_SPEED_100MHz_PCIX): reg = 0x74; @@ -1203,48 +1212,48 @@ static u8 set_controller_speed(struct controller *ctrl, u8 adapter_speed, u8 hp_ default: /* 33MHz PCI 2.2 */ reg = 0x71; break; - + } reg16 |= 0xB << 12; writew(reg16, ctrl->hpc_reg + NEXT_CURR_FREQ); - - mdelay(5); - + + mdelay(5); + /* Reenable interrupts */ writel(0, ctrl->hpc_reg + INT_MASK); - pci_write_config_byte(ctrl->pci_dev, 0x41, reg); - + pci_write_config_byte(ctrl->pci_dev, 0x41, reg); + /* Restart state machine */ reg = ~0xF; pci_read_config_byte(ctrl->pci_dev, 0x43, ®); pci_write_config_byte(ctrl->pci_dev, 0x43, reg); - + /* Only if mode change...*/ if (((ctrl->speed == PCI_SPEED_66MHz) && (adapter_speed == PCI_SPEED_66MHz_PCIX)) || ((ctrl->speed == PCI_SPEED_66MHz_PCIX) && (adapter_speed == PCI_SPEED_66MHz))) set_SOGO(ctrl); - + wait_for_ctrl_irq(ctrl); mdelay(1100); - + /* Restore LED/Slot state */ writel(leds, ctrl->hpc_reg + LED_CONTROL); writeb(slot_power, ctrl->hpc_reg + SLOT_ENABLE); - + set_SOGO(ctrl); wait_for_ctrl_irq(ctrl); ctrl->speed = adapter_speed; slot = cpqhp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); - info("Successfully changed frequency/mode for adapter in slot %d\n", + info("Successfully changed frequency/mode for adapter in slot %d\n", slot->number); return 0; } -/* the following routines constitute the bulk of the - hotplug controller logic +/* the following routines constitute the bulk of the + * hotplug controller logic */ @@ -1268,17 +1277,17 @@ static u32 board_replaced(struct pci_func *func, struct controller *ctrl) hp_slot = func->device - ctrl->slot_device_offset; - if (readl(ctrl->hpc_reg + INT_INPUT_CLEAR) & (0x01L << hp_slot)) { - /********************************** - * The switch is open. - **********************************/ + /* + * The switch is open. + */ + if (readl(ctrl->hpc_reg + INT_INPUT_CLEAR) & (0x01L << hp_slot)) rc = INTERLOCK_OPEN; - } else if (is_slot_enabled (ctrl, hp_slot)) { - /********************************** - * The board is already on - **********************************/ + /* + * The board is already on + */ + else if (is_slot_enabled (ctrl, hp_slot)) rc = CARD_FUNCTIONING; - } else { + else { mutex_lock(&ctrl->crit_sect); /* turn on board without attaching to the bus */ @@ -1299,7 +1308,7 @@ static u32 board_replaced(struct pci_func *func, struct controller *ctrl) /* Wait for SOBS to be unset */ wait_for_ctrl_irq (ctrl); - + adapter_speed = get_adapter_speed(ctrl, hp_slot); if (ctrl->speed != adapter_speed) if (set_controller_speed(ctrl, adapter_speed, hp_slot)) @@ -1352,7 +1361,8 @@ static u32 board_replaced(struct pci_func *func, struct controller *ctrl) * Get slot won't work for devices behind * bridges, but in this case it will always be * called for the "base" bus/dev/func of an - * adapter. */ + * adapter. + */ mutex_lock(&ctrl->crit_sect); @@ -1377,7 +1387,8 @@ static u32 board_replaced(struct pci_func *func, struct controller *ctrl) * Get slot won't work for devices behind bridges, but * in this case it will always be called for the "base" - * bus/dev/func of an adapter. */ + * bus/dev/func of an adapter. + */ mutex_lock(&ctrl->crit_sect); @@ -1434,7 +1445,8 @@ static u32 board_added(struct pci_func *func, struct controller *ctrl) wait_for_ctrl_irq (ctrl); /* Change bits in slot power register to force another shift out - * NOTE: this is to work around the timer bug */ + * NOTE: this is to work around the timer bug + */ temp_byte = readb(ctrl->hpc_reg + SLOT_POWER); writeb(0x00, ctrl->hpc_reg + SLOT_POWER); writeb(temp_byte, ctrl->hpc_reg + SLOT_POWER); @@ -1443,12 +1455,12 @@ static u32 board_added(struct pci_func *func, struct controller *ctrl) /* Wait for SOBS to be unset */ wait_for_ctrl_irq (ctrl); - + adapter_speed = get_adapter_speed(ctrl, hp_slot); if (ctrl->speed != adapter_speed) if (set_controller_speed(ctrl, adapter_speed, hp_slot)) rc = WRONG_BUS_FREQUENCY; - + /* turn off board without attaching to the bus */ disable_slot_power (ctrl, hp_slot); @@ -1461,7 +1473,7 @@ static u32 board_added(struct pci_func *func, struct controller *ctrl) if (rc) return rc; - + p_slot = cpqhp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); /* turn on board and blink green LED */ @@ -1521,7 +1533,7 @@ static u32 board_added(struct pci_func *func, struct controller *ctrl) } /* All F's is an empty slot or an invalid board */ - if (temp_register != 0xFFFFFFFF) { /* Check for a board in the slot */ + if (temp_register != 0xFFFFFFFF) { res_lists.io_head = ctrl->io_head; res_lists.mem_head = ctrl->mem_head; res_lists.p_mem_head = ctrl->p_mem_head; @@ -1570,9 +1582,8 @@ static u32 board_added(struct pci_func *func, struct controller *ctrl) index = 0; do { new_slot = cpqhp_slot_find(ctrl->bus, func->device, index++); - if (new_slot && !new_slot->pci_dev) { + if (new_slot && !new_slot->pci_dev) cpqhp_configure_device(ctrl, new_slot); - } } while (new_slot); mutex_lock(&ctrl->crit_sect); @@ -1859,12 +1870,12 @@ static void interrupt_event_handler(struct controller *ctrl) info(msg_button_on, p_slot->number); } mutex_lock(&ctrl->crit_sect); - + dbg("blink green LED and turn off amber\n"); - + amber_LED_off (ctrl, hp_slot); green_LED_blink (ctrl, hp_slot); - + set_SOGO(ctrl); /* Wait for SOBS to be unset */ @@ -1958,7 +1969,7 @@ void cpqhp_pushbutton_thread(unsigned long slot) if (cpqhp_process_SI(ctrl, func) != 0) { amber_LED_on(ctrl, hp_slot); green_LED_off(ctrl, hp_slot); - + set_SOGO(ctrl); /* Wait for SOBS to be unset */ @@ -2079,7 +2090,7 @@ int cpqhp_process_SS(struct controller *ctrl, struct pci_func *func) struct pci_bus *pci_bus = ctrl->pci_bus; int physical_slot=0; - device = func->device; + device = func->device; func = cpqhp_slot_find(ctrl->bus, device, index++); p_slot = cpqhp_find_slot(ctrl, device); if (p_slot) { @@ -2113,9 +2124,8 @@ int cpqhp_process_SS(struct controller *ctrl, struct pci_func *func) /* If the VGA Enable bit is set, remove isn't * supported */ - if (BCR & PCI_BRIDGE_CTL_VGA) { + if (BCR & PCI_BRIDGE_CTL_VGA) rc = REMOVE_NOT_SUPPORTED; - } } } @@ -2183,67 +2193,67 @@ int cpqhp_hardware_test(struct controller *ctrl, int test_num) num_of_slots = readb(ctrl->hpc_reg + SLOT_MASK) & 0x0f; switch (test_num) { - case 1: - /* Do stuff here! */ + case 1: + /* Do stuff here! */ - /* Do that funky LED thing */ - /* so we can restore them later */ - save_LED = readl(ctrl->hpc_reg + LED_CONTROL); - work_LED = 0x01010101; - switch_leds(ctrl, num_of_slots, &work_LED, 0); - switch_leds(ctrl, num_of_slots, &work_LED, 1); - switch_leds(ctrl, num_of_slots, &work_LED, 0); - switch_leds(ctrl, num_of_slots, &work_LED, 1); + /* Do that funky LED thing */ + /* so we can restore them later */ + save_LED = readl(ctrl->hpc_reg + LED_CONTROL); + work_LED = 0x01010101; + switch_leds(ctrl, num_of_slots, &work_LED, 0); + switch_leds(ctrl, num_of_slots, &work_LED, 1); + switch_leds(ctrl, num_of_slots, &work_LED, 0); + switch_leds(ctrl, num_of_slots, &work_LED, 1); - work_LED = 0x01010000; + work_LED = 0x01010000; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + switch_leds(ctrl, num_of_slots, &work_LED, 0); + switch_leds(ctrl, num_of_slots, &work_LED, 1); + work_LED = 0x00000101; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + switch_leds(ctrl, num_of_slots, &work_LED, 0); + switch_leds(ctrl, num_of_slots, &work_LED, 1); + + work_LED = 0x01010000; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + for (loop = 0; loop < num_of_slots; loop++) { + set_SOGO(ctrl); + + /* Wait for SOGO interrupt */ + wait_for_ctrl_irq (ctrl); + + /* Get ready for next iteration */ + long_delay((3*HZ)/10); + work_LED = work_LED >> 16; writel(work_LED, ctrl->hpc_reg + LED_CONTROL); - switch_leds(ctrl, num_of_slots, &work_LED, 0); - switch_leds(ctrl, num_of_slots, &work_LED, 1); - work_LED = 0x00000101; - writel(work_LED, ctrl->hpc_reg + LED_CONTROL); - switch_leds(ctrl, num_of_slots, &work_LED, 0); - switch_leds(ctrl, num_of_slots, &work_LED, 1); - - work_LED = 0x01010000; - writel(work_LED, ctrl->hpc_reg + LED_CONTROL); - for (loop = 0; loop < num_of_slots; loop++) { - set_SOGO(ctrl); - - /* Wait for SOGO interrupt */ - wait_for_ctrl_irq (ctrl); - - /* Get ready for next iteration */ - long_delay((3*HZ)/10); - work_LED = work_LED >> 16; - writel(work_LED, ctrl->hpc_reg + LED_CONTROL); - - set_SOGO(ctrl); - - /* Wait for SOGO interrupt */ - wait_for_ctrl_irq (ctrl); - - /* Get ready for next iteration */ - long_delay((3*HZ)/10); - work_LED = work_LED << 16; - writel(work_LED, ctrl->hpc_reg + LED_CONTROL); - work_LED = work_LED << 1; - writel(work_LED, ctrl->hpc_reg + LED_CONTROL); - } - - /* put it back the way it was */ - writel(save_LED, ctrl->hpc_reg + LED_CONTROL); set_SOGO(ctrl); - /* Wait for SOBS to be unset */ + /* Wait for SOGO interrupt */ wait_for_ctrl_irq (ctrl); - break; - case 2: - /* Do other stuff here! */ - break; - case 3: - /* and more... */ - break; + + /* Get ready for next iteration */ + long_delay((3*HZ)/10); + work_LED = work_LED << 16; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + work_LED = work_LED << 1; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + } + + /* put it back the way it was */ + writel(save_LED, ctrl->hpc_reg + LED_CONTROL); + + set_SOGO(ctrl); + + /* Wait for SOBS to be unset */ + wait_for_ctrl_irq (ctrl); + break; + case 2: + /* Do other stuff here! */ + break; + case 3: + /* and more... */ + break; } return 0; } @@ -2312,9 +2322,9 @@ static u32 configure_new_device(struct controller * ctrl, struct pci_func * func while ((function < max_functions) && (!stop_it)) { pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(func->device, function), 0x00, &ID); - if (ID == 0xFFFFFFFF) { /* There's nothing there. */ + if (ID == 0xFFFFFFFF) { function++; - } else { /* There's something there */ + } else { /* Setup slot structure. */ new_slot = cpqhp_slot_create(func->bus); @@ -2339,8 +2349,8 @@ static u32 configure_new_device(struct controller * ctrl, struct pci_func * func /* - Configuration logic that involves the hotplug data structures and - their bookkeeping + * Configuration logic that involves the hotplug data structures and + * their bookkeeping */ @@ -2393,7 +2403,7 @@ static int configure_new_function(struct controller *ctrl, struct pci_func *func if (rc) return rc; - if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { /* PCI-PCI Bridge */ + if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { /* set Primary bus */ dbg("set Primary bus = %d\n", func->bus); rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_PRIMARY_BUS, func->bus); @@ -2484,7 +2494,8 @@ static int configure_new_function(struct controller *ctrl, struct pci_func *func temp_resources.irqs = &irqs; /* Make copies of the nodes we are going to pass down so that - * if there is a problem,we can just use these to free resources */ + * if there is a problem,we can just use these to free resources + */ hold_bus_node = kmalloc(sizeof(*hold_bus_node), GFP_KERNEL); hold_IO_node = kmalloc(sizeof(*hold_IO_node), GFP_KERNEL); hold_mem_node = kmalloc(sizeof(*hold_mem_node), GFP_KERNEL); @@ -2556,7 +2567,8 @@ static int configure_new_function(struct controller *ctrl, struct pci_func *func temp_word = (p_mem_node->base + p_mem_node->length - 1) >> 16; rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word); - /* Adjust this to compensate for extra adjustment in first loop */ + /* Adjust this to compensate for extra adjustment in first loop + */ irqs.barber_pole--; rc = 0; @@ -2917,27 +2929,26 @@ static int configure_new_function(struct controller *ctrl, struct pci_func *func } /* End of base register loop */ if (cpqhp_legacy_mode) { /* Figure out which interrupt pin this function uses */ - rc = pci_bus_read_config_byte (pci_bus, devfn, + rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_INTERRUPT_PIN, &temp_byte); /* If this function needs an interrupt and we are behind * a bridge and the pin is tied to something that's * alread mapped, set this one the same */ - if (temp_byte && resources->irqs && - (resources->irqs->valid_INT & + if (temp_byte && resources->irqs && + (resources->irqs->valid_INT & (0x01 << ((temp_byte + resources->irqs->barber_pole - 1) & 0x03)))) { /* We have to share with something already set up */ - IRQ = resources->irqs->interrupt[(temp_byte + + IRQ = resources->irqs->interrupt[(temp_byte + resources->irqs->barber_pole - 1) & 0x03]; } else { /* Program IRQ based on card type */ rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code); - if (class_code == PCI_BASE_CLASS_STORAGE) { + if (class_code == PCI_BASE_CLASS_STORAGE) IRQ = cpqhp_disk_irq; - } else { + else IRQ = cpqhp_nic_irq; - } } /* IRQ Line */ diff --git a/drivers/pci/hotplug/cpqphp_nvram.c b/drivers/pci/hotplug/cpqphp_nvram.c index cb174888002b..76ba8a1c774d 100644 --- a/drivers/pci/hotplug/cpqphp_nvram.c +++ b/drivers/pci/hotplug/cpqphp_nvram.c @@ -94,12 +94,13 @@ static u8 evbuffer[1024]; static void __iomem *compaq_int15_entry_point; -static spinlock_t int15_lock; /* lock for ordering int15_bios_call() */ +/* lock for ordering int15_bios_call() */ +static spinlock_t int15_lock; /* This is a series of function that deals with - setting & getting the hotplug resource table in some environment variable. -*/ + * setting & getting the hotplug resource table in some environment variable. + */ /* * We really shouldn't be doing this unless there is a _very_ good reason to!!! @@ -113,7 +114,7 @@ static u32 add_byte( u32 **p_buffer, u8 value, u32 *used, u32 *avail) if ((*used + 1) > *avail) return(1); - + *((u8*)*p_buffer) = value; tByte = (u8**)p_buffer; (*tByte)++; @@ -170,10 +171,10 @@ static u32 access_EV (u16 operation, u8 *ev_name, u8 *buffer, u32 *buf_size) unsigned long flags; int op = operation; int ret_val; - + if (!compaq_int15_entry_point) return -ENODEV; - + spin_lock_irqsave(&int15_lock, flags); __asm__ ( "xorl %%ebx,%%ebx\n" \ @@ -187,7 +188,7 @@ static u32 access_EV (u16 operation, u8 *ev_name, u8 *buffer, u32 *buf_size) "D" (buffer), "m" (compaq_int15_entry_point) : "%ebx", "%edx"); spin_unlock_irqrestore(&int15_lock, flags); - + return((ret_val & 0xFF00) >> 8); } @@ -210,14 +211,16 @@ static int load_HRT (void __iomem *rom_start) available = 1024; - // Now load the EV + /* Now load the EV */ temp_dword = available; rc = access_EV(READ_EV, "CQTHPS", evbuffer, &temp_dword); evbuffer_length = temp_dword; - // We're maintaining the resource lists so write FF to invalidate old info + /* We're maintaining the resource lists so write FF to invalidate old + * info + */ temp_dword = 1; rc = access_EV(WRITE_EV, "CQTHPS", &temp_byte, &temp_dword); @@ -263,13 +266,13 @@ static u32 store_HRT (void __iomem *rom_start) p_EV_header = (struct ev_hrt_header *) pFill; ctrl = cpqhp_ctrl_list; - - // The revision of this structure + + /* The revision of this structure */ rc = add_byte( &pFill, 1 + ctrl->push_flag, &usedbytes, &available); if (rc) return(rc); - // The number of controllers + /* The number of controllers */ rc = add_byte( &pFill, 1, &usedbytes, &available); if (rc) return(rc); @@ -279,27 +282,27 @@ static u32 store_HRT (void __iomem *rom_start) numCtrl++; - // The bus number + /* The bus number */ rc = add_byte( &pFill, ctrl->bus, &usedbytes, &available); if (rc) return(rc); - // The device Number + /* The device Number */ rc = add_byte( &pFill, PCI_SLOT(ctrl->pci_dev->devfn), &usedbytes, &available); if (rc) return(rc); - // The function Number + /* The function Number */ rc = add_byte( &pFill, PCI_FUNC(ctrl->pci_dev->devfn), &usedbytes, &available); if (rc) return(rc); - // Skip the number of available entries + /* Skip the number of available entries */ rc = add_dword( &pFill, 0, &usedbytes, &available); if (rc) return(rc); - // Figure out memory Available + /* Figure out memory Available */ resNode = ctrl->mem_head; @@ -308,12 +311,12 @@ static u32 store_HRT (void __iomem *rom_start) while (resNode) { loop ++; - // base + /* base */ rc = add_dword( &pFill, resNode->base, &usedbytes, &available); if (rc) return(rc); - // length + /* length */ rc = add_dword( &pFill, resNode->length, &usedbytes, &available); if (rc) return(rc); @@ -321,10 +324,10 @@ static u32 store_HRT (void __iomem *rom_start) resNode = resNode->next; } - // Fill in the number of entries + /* Fill in the number of entries */ p_ev_ctrl->mem_avail = loop; - // Figure out prefetchable memory Available + /* Figure out prefetchable memory Available */ resNode = ctrl->p_mem_head; @@ -333,12 +336,12 @@ static u32 store_HRT (void __iomem *rom_start) while (resNode) { loop ++; - // base + /* base */ rc = add_dword( &pFill, resNode->base, &usedbytes, &available); if (rc) return(rc); - // length + /* length */ rc = add_dword( &pFill, resNode->length, &usedbytes, &available); if (rc) return(rc); @@ -346,10 +349,10 @@ static u32 store_HRT (void __iomem *rom_start) resNode = resNode->next; } - // Fill in the number of entries + /* Fill in the number of entries */ p_ev_ctrl->p_mem_avail = loop; - // Figure out IO Available + /* Figure out IO Available */ resNode = ctrl->io_head; @@ -358,12 +361,12 @@ static u32 store_HRT (void __iomem *rom_start) while (resNode) { loop ++; - // base + /* base */ rc = add_dword( &pFill, resNode->base, &usedbytes, &available); if (rc) return(rc); - // length + /* length */ rc = add_dword( &pFill, resNode->length, &usedbytes, &available); if (rc) return(rc); @@ -371,10 +374,10 @@ static u32 store_HRT (void __iomem *rom_start) resNode = resNode->next; } - // Fill in the number of entries + /* Fill in the number of entries */ p_ev_ctrl->io_avail = loop; - // Figure out bus Available + /* Figure out bus Available */ resNode = ctrl->bus_head; @@ -383,12 +386,12 @@ static u32 store_HRT (void __iomem *rom_start) while (resNode) { loop ++; - // base + /* base */ rc = add_dword( &pFill, resNode->base, &usedbytes, &available); if (rc) return(rc); - // length + /* length */ rc = add_dword( &pFill, resNode->length, &usedbytes, &available); if (rc) return(rc); @@ -396,15 +399,15 @@ static u32 store_HRT (void __iomem *rom_start) resNode = resNode->next; } - // Fill in the number of entries + /* Fill in the number of entries */ p_ev_ctrl->bus_avail = loop; ctrl = ctrl->next; } - + p_EV_header->num_of_ctrl = numCtrl; - // Now store the EV + /* Now store the EV */ temp_dword = usedbytes; @@ -449,20 +452,21 @@ int compaq_nvram_load (void __iomem *rom_start, struct controller *ctrl) struct ev_hrt_header *p_EV_header; if (!evbuffer_init) { - // Read the resource list information in from NVRAM + /* Read the resource list information in from NVRAM */ if (load_HRT(rom_start)) memset (evbuffer, 0, 1024); evbuffer_init = 1; } - // If we saved information in NVRAM, use it now + /* If we saved information in NVRAM, use it now */ p_EV_header = (struct ev_hrt_header *) evbuffer; - // The following code is for systems where version 1.0 of this - // driver has been loaded, but doesn't support the hardware. - // In that case, the driver would incorrectly store something - // in NVRAM. + /* The following code is for systems where version 1.0 of this + * driver has been loaded, but doesn't support the hardware. + * In that case, the driver would incorrectly store something + * in NVRAM. + */ if ((p_EV_header->Version == 2) || ((p_EV_header->Version == 1) && !ctrl->push_flag)) { p_byte = &(p_EV_header->next); @@ -479,7 +483,7 @@ int compaq_nvram_load (void __iomem *rom_start, struct controller *ctrl) function = p_ev_ctrl->function; while ((bus != ctrl->bus) || - (device != PCI_SLOT(ctrl->pci_dev->devfn)) || + (device != PCI_SLOT(ctrl->pci_dev->devfn)) || (function != PCI_FUNC(ctrl->pci_dev->devfn))) { nummem = p_ev_ctrl->mem_avail; numpmem = p_ev_ctrl->p_mem_avail; @@ -491,7 +495,7 @@ int compaq_nvram_load (void __iomem *rom_start, struct controller *ctrl) if (p_byte > ((u8*)p_EV_header + evbuffer_length)) return 2; - // Skip forward to the next entry + /* Skip forward to the next entry */ p_byte += (nummem + numpmem + numio + numbus) * 8; if (p_byte > ((u8*)p_EV_header + evbuffer_length)) @@ -629,8 +633,9 @@ int compaq_nvram_load (void __iomem *rom_start, struct controller *ctrl) ctrl->bus_head = bus_node; } - // If all of the following fail, we don't have any resources for - // hot plug add + /* If all of the following fail, we don't have any resources for + * hot plug add + */ rc = 1; rc &= cpqhp_resource_sort_and_combine(&(ctrl->mem_head)); rc &= cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head)); @@ -640,14 +645,14 @@ int compaq_nvram_load (void __iomem *rom_start, struct controller *ctrl) if (rc) return(rc); } else { - if ((evbuffer[0] != 0) && (!ctrl->push_flag)) + if ((evbuffer[0] != 0) && (!ctrl->push_flag)) return 1; } return 0; } - + int compaq_nvram_store (void __iomem *rom_start) { int rc = 1; diff --git a/drivers/pci/hotplug/cpqphp_pci.c b/drivers/pci/hotplug/cpqphp_pci.c index 6c0ed0fcb8ee..6173b9a4544e 100644 --- a/drivers/pci/hotplug/cpqphp_pci.c +++ b/drivers/pci/hotplug/cpqphp_pci.c @@ -37,7 +37,6 @@ #include "../pci.h" #include "cpqphp.h" #include "cpqphp_nvram.h" -#include u8 cpqhp_nic_irq; @@ -82,14 +81,14 @@ static void __iomem *detect_HRT_floating_pointer(void __iomem *begin, void __iom } -int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func) +int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func) { unsigned char bus; struct pci_bus *child; int num; if (func->pci_dev == NULL) - func->pci_dev = pci_find_slot(func->bus, PCI_DEVFN(func->device, func->function)); + func->pci_dev = pci_get_bus_and_slot(func->bus,PCI_DEVFN(func->device, func->function)); /* No pci device, we need to create it then */ if (func->pci_dev == NULL) { @@ -99,7 +98,7 @@ int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func) if (num) pci_bus_add_devices(ctrl->pci_dev->bus); - func->pci_dev = pci_find_slot(func->bus, PCI_DEVFN(func->device, func->function)); + func->pci_dev = pci_get_bus_and_slot(func->bus, PCI_DEVFN(func->device, func->function)); if (func->pci_dev == NULL) { dbg("ERROR: pci_dev still null\n"); return 0; @@ -112,20 +111,24 @@ int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func) pci_do_scan_bus(child); } + pci_dev_put(func->pci_dev); + return 0; } -int cpqhp_unconfigure_device(struct pci_func* func) +int cpqhp_unconfigure_device(struct pci_func* func) { int j; - + dbg("%s: bus/dev/func = %x/%x/%x\n", __func__, func->bus, func->device, func->function); for (j=0; j<8 ; j++) { - struct pci_dev* temp = pci_find_slot(func->bus, PCI_DEVFN(func->device, j)); - if (temp) + struct pci_dev* temp = pci_get_bus_and_slot(func->bus, PCI_DEVFN(func->device, j)); + if (temp) { + pci_dev_put(temp); pci_remove_bus_device(temp); + } } return 0; } @@ -178,32 +181,22 @@ int cpqhp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num) if (!rc) return !rc; - // set the Edge Level Control Register (ELCR) + /* set the Edge Level Control Register (ELCR) */ temp_word = inb(0x4d0); temp_word |= inb(0x4d1) << 8; temp_word |= 0x01 << irq_num; - // This should only be for x86 as it sets the Edge Level Control Register - outb((u8) (temp_word & 0xFF), 0x4d0); - outb((u8) ((temp_word & 0xFF00) >> 8), 0x4d1); - rc = 0; - } + /* This should only be for x86 as it sets the Edge Level + * Control Register + */ + outb((u8) (temp_word & 0xFF), 0x4d0); outb((u8) ((temp_word & + 0xFF00) >> 8), 0x4d1); rc = 0; } return rc; } -/* - * WTF??? This function isn't in the code, yet a function calls it, but the - * compiler optimizes it away? strange. Here as a placeholder to keep the - * compiler happy. - */ -static int PCI_ScanBusNonBridge (u8 bus, u8 device) -{ - return 0; -} - static int PCI_ScanBusForNonBridge(struct controller *ctrl, u8 bus_num, u8 * dev_num) { u16 tdevice; @@ -213,11 +206,11 @@ static int PCI_ScanBusForNonBridge(struct controller *ctrl, u8 bus_num, u8 * dev ctrl->pci_bus->number = bus_num; for (tdevice = 0; tdevice < 0xFF; tdevice++) { - //Scan for access first + /* Scan for access first */ if (PCI_RefinedAccessConfig(ctrl->pci_bus, tdevice, 0x08, &work) == -1) continue; dbg("Looking for nonbridge bus_num %d dev_num %d\n", bus_num, tdevice); - //Yep we got one. Not a bridge ? + /* Yep we got one. Not a bridge ? */ if ((work >> 8) != PCI_TO_PCI_BRIDGE_CLASS) { *dev_num = tdevice; dbg("found it !\n"); @@ -225,16 +218,16 @@ static int PCI_ScanBusForNonBridge(struct controller *ctrl, u8 bus_num, u8 * dev } } for (tdevice = 0; tdevice < 0xFF; tdevice++) { - //Scan for access first + /* Scan for access first */ if (PCI_RefinedAccessConfig(ctrl->pci_bus, tdevice, 0x08, &work) == -1) continue; dbg("Looking for bridge bus_num %d dev_num %d\n", bus_num, tdevice); - //Yep we got one. bridge ? + /* Yep we got one. bridge ? */ if ((work >> 8) == PCI_TO_PCI_BRIDGE_CLASS) { pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(tdevice, 0), PCI_SECONDARY_BUS, &tbus); + /* XXX: no recursion, wtf? */ dbg("Recurse on bus_num %d tdevice %d\n", tbus, tdevice); - if (PCI_ScanBusNonBridge(tbus, tdevice) == 0) - return 0; + return 0; } } @@ -244,39 +237,23 @@ static int PCI_ScanBusForNonBridge(struct controller *ctrl, u8 bus_num, u8 * dev static int PCI_GetBusDevHelper(struct controller *ctrl, u8 *bus_num, u8 *dev_num, u8 slot, u8 nobridge) { - struct irq_routing_table *PCIIRQRoutingInfoLength; - long len; - long loop; + int loop, len; u32 work; - u8 tbus, tdevice, tslot; - PCIIRQRoutingInfoLength = pcibios_get_irq_routing_table(); - if (!PCIIRQRoutingInfoLength) - return -1; - - len = (PCIIRQRoutingInfoLength->size - - sizeof(struct irq_routing_table)) / sizeof(struct irq_info); - // Make sure I got at least one entry - if (len == 0) { - kfree(PCIIRQRoutingInfoLength ); - return -1; - } - + len = cpqhp_routing_table_length(); for (loop = 0; loop < len; ++loop) { - tbus = PCIIRQRoutingInfoLength->slots[loop].bus; - tdevice = PCIIRQRoutingInfoLength->slots[loop].devfn; - tslot = PCIIRQRoutingInfoLength->slots[loop].slot; + tbus = cpqhp_routing_table->slots[loop].bus; + tdevice = cpqhp_routing_table->slots[loop].devfn; + tslot = cpqhp_routing_table->slots[loop].slot; if (tslot == slot) { *bus_num = tbus; *dev_num = tdevice; ctrl->pci_bus->number = tbus; pci_bus_read_config_dword (ctrl->pci_bus, *dev_num, PCI_VENDOR_ID, &work); - if (!nobridge || (work == 0xffffffff)) { - kfree(PCIIRQRoutingInfoLength ); + if (!nobridge || (work == 0xffffffff)) return 0; - } dbg("bus_num %d devfn %d\n", *bus_num, *dev_num); pci_bus_read_config_dword (ctrl->pci_bus, *dev_num, PCI_CLASS_REVISION, &work); @@ -287,28 +264,26 @@ static int PCI_GetBusDevHelper(struct controller *ctrl, u8 *bus_num, u8 *dev_num dbg("Scan bus for Non Bridge: bus %d\n", tbus); if (PCI_ScanBusForNonBridge(ctrl, tbus, dev_num) == 0) { *bus_num = tbus; - kfree(PCIIRQRoutingInfoLength ); return 0; } - } else { - kfree(PCIIRQRoutingInfoLength ); + } else return 0; - } - } } - kfree(PCIIRQRoutingInfoLength ); return -1; } int cpqhp_get_bus_dev (struct controller *ctrl, u8 * bus_num, u8 * dev_num, u8 slot) { - return PCI_GetBusDevHelper(ctrl, bus_num, dev_num, slot, 0); //plain (bridges allowed) + /* plain (bridges allowed) */ + return PCI_GetBusDevHelper(ctrl, bus_num, dev_num, slot, 0); } -/* More PCI configuration routines; this time centered around hotplug controller */ +/* More PCI configuration routines; this time centered around hotplug + * controller + */ /* @@ -339,12 +314,12 @@ int cpqhp_save_config(struct controller *ctrl, int busnumber, int is_hot_plug) int stop_it; int index; - // Decide which slots are supported + /* Decide which slots are supported */ if (is_hot_plug) { - //********************************* - // is_hot_plug is the slot mask - //********************************* + /* + * is_hot_plug is the slot mask + */ FirstSupported = is_hot_plug >> 4; LastSupported = FirstSupported + (is_hot_plug & 0x0F) - 1; } else { @@ -352,123 +327,127 @@ int cpqhp_save_config(struct controller *ctrl, int busnumber, int is_hot_plug) LastSupported = 0x1F; } - // Save PCI configuration space for all devices in supported slots + /* Save PCI configuration space for all devices in supported slots */ ctrl->pci_bus->number = busnumber; for (device = FirstSupported; device <= LastSupported; device++) { ID = 0xFFFFFFFF; - rc = pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(device, 0), PCI_VENDOR_ID, &ID); + rc = pci_bus_read_config_dword(ctrl->pci_bus, PCI_DEVFN(device, 0), PCI_VENDOR_ID, &ID); - if (ID != 0xFFFFFFFF) { // device in slot - rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, 0), 0x0B, &class_code); - if (rc) - return rc; - - rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, 0), PCI_HEADER_TYPE, &header_type); - if (rc) - return rc; - - // If multi-function device, set max_functions to 8 - if (header_type & 0x80) - max_functions = 8; - else - max_functions = 1; - - function = 0; - - do { - DevError = 0; - - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // P-P Bridge - // Recurse the subordinate bus - // get the subordinate bus number - rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, function), PCI_SECONDARY_BUS, &secondary_bus); - if (rc) { - return rc; - } else { - sub_bus = (int) secondary_bus; - - // Save secondary bus cfg spc - // with this recursive call. - rc = cpqhp_save_config(ctrl, sub_bus, 0); - if (rc) - return rc; - ctrl->pci_bus->number = busnumber; - } - } - - index = 0; - new_slot = cpqhp_slot_find(busnumber, device, index++); - while (new_slot && - (new_slot->function != (u8) function)) - new_slot = cpqhp_slot_find(busnumber, device, index++); - - if (!new_slot) { - // Setup slot structure. - new_slot = cpqhp_slot_create(busnumber); - - if (new_slot == NULL) - return(1); - } + if (ID == 0xFFFFFFFF) { + if (is_hot_plug) { + /* Setup slot structure with entry for empty + * slot + */ + new_slot = cpqhp_slot_create(busnumber); + if (new_slot == NULL) + return 1; new_slot->bus = (u8) busnumber; new_slot->device = (u8) device; - new_slot->function = (u8) function; - new_slot->is_a_board = 1; - new_slot->switch_save = 0x10; - // In case of unsupported board - new_slot->status = DevError; - new_slot->pci_dev = pci_find_slot(new_slot->bus, (new_slot->device << 3) | new_slot->function); + new_slot->function = 0; + new_slot->is_a_board = 0; + new_slot->presence_save = 0; + new_slot->switch_save = 0; + } + continue; + } - for (cloop = 0; cloop < 0x20; cloop++) { - rc = pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(device, function), cloop << 2, (u32 *) & (new_slot-> config_space [cloop])); + rc = pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(device, 0), 0x0B, &class_code); + if (rc) + return rc; + + rc = pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(device, 0), PCI_HEADER_TYPE, &header_type); + if (rc) + return rc; + + /* If multi-function device, set max_functions to 8 */ + if (header_type & 0x80) + max_functions = 8; + else + max_functions = 1; + + function = 0; + + do { + DevError = 0; + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { + /* Recurse the subordinate bus + * get the subordinate bus number + */ + rc = pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(device, function), PCI_SECONDARY_BUS, &secondary_bus); + if (rc) { + return rc; + } else { + sub_bus = (int) secondary_bus; + + /* Save secondary bus cfg spc + * with this recursive call. + */ + rc = cpqhp_save_config(ctrl, sub_bus, 0); if (rc) return rc; + ctrl->pci_bus->number = busnumber; } + } - function++; + index = 0; + new_slot = cpqhp_slot_find(busnumber, device, index++); + while (new_slot && + (new_slot->function != (u8) function)) + new_slot = cpqhp_slot_find(busnumber, device, index++); - stop_it = 0; - - // this loop skips to the next present function - // reading in Class Code and Header type. - - while ((function < max_functions)&&(!stop_it)) { - rc = pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(device, function), PCI_VENDOR_ID, &ID); - if (ID == 0xFFFFFFFF) { // nothing there. - function++; - } else { // Something there - rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, function), 0x0B, &class_code); - if (rc) - return rc; - - rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, function), PCI_HEADER_TYPE, &header_type); - if (rc) - return rc; - - stop_it++; - } - } - - } while (function < max_functions); - } // End of IF (device in slot?) - else if (is_hot_plug) { - // Setup slot structure with entry for empty slot - new_slot = cpqhp_slot_create(busnumber); - - if (new_slot == NULL) { - return(1); + if (!new_slot) { + /* Setup slot structure. */ + new_slot = cpqhp_slot_create(busnumber); + if (new_slot == NULL) + return 1; } new_slot->bus = (u8) busnumber; new_slot->device = (u8) device; - new_slot->function = 0; - new_slot->is_a_board = 0; - new_slot->presence_save = 0; - new_slot->switch_save = 0; - } - } // End of FOR loop + new_slot->function = (u8) function; + new_slot->is_a_board = 1; + new_slot->switch_save = 0x10; + /* In case of unsupported board */ + new_slot->status = DevError; + new_slot->pci_dev = pci_get_bus_and_slot(new_slot->bus, (new_slot->device << 3) | new_slot->function); - return(0); + for (cloop = 0; cloop < 0x20; cloop++) { + rc = pci_bus_read_config_dword(ctrl->pci_bus, PCI_DEVFN(device, function), cloop << 2, (u32 *) & (new_slot-> config_space [cloop])); + if (rc) + return rc; + } + + pci_dev_put(new_slot->pci_dev); + + function++; + + stop_it = 0; + + /* this loop skips to the next present function + * reading in Class Code and Header type. + */ + while ((function < max_functions) && (!stop_it)) { + rc = pci_bus_read_config_dword(ctrl->pci_bus, PCI_DEVFN(device, function), PCI_VENDOR_ID, &ID); + if (ID == 0xFFFFFFFF) { + function++; + continue; + } + rc = pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(device, function), 0x0B, &class_code); + if (rc) + return rc; + + rc = pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(device, function), PCI_HEADER_TYPE, &header_type); + if (rc) + return rc; + + stop_it++; + } + + } while (function < max_functions); + } /* End of FOR loop */ + + return 0; } @@ -489,7 +468,7 @@ int cpqhp_save_slot_config (struct controller *ctrl, struct pci_func * new_slot) u8 secondary_bus; int sub_bus; int max_functions; - int function; + int function = 0; int cloop = 0; int stop_it; @@ -498,63 +477,58 @@ int cpqhp_save_slot_config (struct controller *ctrl, struct pci_func * new_slot) ctrl->pci_bus->number = new_slot->bus; pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), PCI_VENDOR_ID, &ID); - if (ID != 0xFFFFFFFF) { // device in slot - pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), 0x0B, &class_code); - pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), PCI_HEADER_TYPE, &header_type); - - if (header_type & 0x80) // Multi-function device - max_functions = 8; - else - max_functions = 1; - - function = 0; - - do { - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // PCI-PCI Bridge - // Recurse the subordinate bus - pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_SECONDARY_BUS, &secondary_bus); - - sub_bus = (int) secondary_bus; - - // Save the config headers for the secondary bus. - rc = cpqhp_save_config(ctrl, sub_bus, 0); - if (rc) - return(rc); - ctrl->pci_bus->number = new_slot->bus; - - } // End of IF - - new_slot->status = 0; - - for (cloop = 0; cloop < 0x20; cloop++) { - pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), cloop << 2, (u32 *) & (new_slot-> config_space [cloop])); - } - - function++; - - stop_it = 0; - - // this loop skips to the next present function - // reading in the Class Code and the Header type. - - while ((function < max_functions) && (!stop_it)) { - pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_VENDOR_ID, &ID); - - if (ID == 0xFFFFFFFF) { // nothing there. - function++; - } else { // Something there - pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), 0x0B, &class_code); - - pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_HEADER_TYPE, &header_type); - - stop_it++; - } - } - - } while (function < max_functions); - } // End of IF (device in slot?) - else { + if (ID == 0xFFFFFFFF) return 2; + + pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), 0x0B, &class_code); + pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), PCI_HEADER_TYPE, &header_type); + + if (header_type & 0x80) /* Multi-function device */ + max_functions = 8; + else + max_functions = 1; + + while (function < max_functions) { + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { + /* Recurse the subordinate bus */ + pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_SECONDARY_BUS, &secondary_bus); + + sub_bus = (int) secondary_bus; + + /* Save the config headers for the secondary + * bus. + */ + rc = cpqhp_save_config(ctrl, sub_bus, 0); + if (rc) + return(rc); + ctrl->pci_bus->number = new_slot->bus; + + } + + new_slot->status = 0; + + for (cloop = 0; cloop < 0x20; cloop++) + pci_bus_read_config_dword(ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), cloop << 2, (u32 *) & (new_slot-> config_space [cloop])); + + function++; + + stop_it = 0; + + /* this loop skips to the next present function + * reading in the Class Code and the Header type. + */ + while ((function < max_functions) && (!stop_it)) { + pci_bus_read_config_dword(ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_VENDOR_ID, &ID); + + if (ID == 0xFFFFFFFF) + function++; + else { + pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), 0x0B, &class_code); + pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_HEADER_TYPE, &header_type); + stop_it++; + } + } + } return 0; @@ -590,11 +564,10 @@ int cpqhp_save_base_addr_length(struct controller *ctrl, struct pci_func * func) pci_bus->number = func->bus; devfn = PCI_DEVFN(func->device, func->function); - // Check for Bridge + /* Check for Bridge */ pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type); if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { - // PCI-PCI Bridge pci_bus_read_config_byte (pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus); sub_bus = (int) secondary_bus; @@ -610,23 +583,27 @@ int cpqhp_save_base_addr_length(struct controller *ctrl, struct pci_func * func) } pci_bus->number = func->bus; - //FIXME: this loop is duplicated in the non-bridge case. The two could be rolled together - // Figure out IO and memory base lengths + /* FIXME: this loop is duplicated in the non-bridge + * case. The two could be rolled together Figure out + * IO and memory base lengths + */ for (cloop = 0x10; cloop <= 0x14; cloop += 4) { temp_register = 0xFFFFFFFF; pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register); pci_bus_read_config_dword (pci_bus, devfn, cloop, &base); - - if (base) { // If this register is implemented + /* If this register is implemented */ + if (base) { if (base & 0x01L) { - // IO base - // set base = amount of IO space requested + /* IO base + * set base = amount of IO space + * requested + */ base = base & 0xFFFFFFFE; base = (~base) + 1; type = 1; } else { - // memory base + /* memory base */ base = base & 0xFFFFFFF0; base = (~base) + 1; @@ -637,32 +614,36 @@ int cpqhp_save_base_addr_length(struct controller *ctrl, struct pci_func * func) type = 0; } - // Save information in slot structure + /* Save information in slot structure */ func->base_length[(cloop - 0x10) >> 2] = base; func->base_type[(cloop - 0x10) >> 2] = type; - } // End of base register loop + } /* End of base register loop */ - - } else if ((header_type & 0x7F) == 0x00) { // PCI-PCI Bridge - // Figure out IO and memory base lengths + } else if ((header_type & 0x7F) == 0x00) { + /* Figure out IO and memory base lengths */ for (cloop = 0x10; cloop <= 0x24; cloop += 4) { temp_register = 0xFFFFFFFF; pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register); pci_bus_read_config_dword (pci_bus, devfn, cloop, &base); - if (base) { // If this register is implemented + /* If this register is implemented */ + if (base) { if (base & 0x01L) { - // IO base - // base = amount of IO space requested + /* IO base + * base = amount of IO space + * requested + */ base = base & 0xFFFFFFFE; base = (~base) + 1; type = 1; } else { - // memory base - // base = amount of memory space requested + /* memory base + * base = amount of memory + * space requested + */ base = base & 0xFFFFFFF0; base = (~base) + 1; @@ -673,16 +654,16 @@ int cpqhp_save_base_addr_length(struct controller *ctrl, struct pci_func * func) type = 0; } - // Save information in slot structure + /* Save information in slot structure */ func->base_length[(cloop - 0x10) >> 2] = base; func->base_type[(cloop - 0x10) >> 2] = type; - } // End of base register loop + } /* End of base register loop */ - } else { // Some other unknown header type + } else { /* Some other unknown header type */ } - // find the next device in this slot + /* find the next device in this slot */ func = cpqhp_slot_find(func->bus, func->device, index++); } @@ -728,18 +709,18 @@ int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func) pci_bus->number = func->bus; devfn = PCI_DEVFN(func->device, func->function); - // Save the command register + /* Save the command register */ pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &save_command); - // disable card + /* disable card */ command = 0x00; pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command); - // Check for Bridge + /* Check for Bridge */ pci_bus_read_config_byte(pci_bus, devfn, PCI_HEADER_TYPE, &header_type); - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // PCI-PCI Bridge - // Clear Bridge Control Register + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { + /* Clear Bridge Control Register */ command = 0x00; pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, command); pci_bus_read_config_byte(pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus); @@ -755,7 +736,7 @@ int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func) bus_node->next = func->bus_head; func->bus_head = bus_node; - // Save IO base and Limit registers + /* Save IO base and Limit registers */ pci_bus_read_config_byte(pci_bus, devfn, PCI_IO_BASE, &b_base); pci_bus_read_config_byte(pci_bus, devfn, PCI_IO_LIMIT, &b_length); @@ -771,7 +752,7 @@ int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func) func->io_head = io_node; } - // Save memory base and Limit registers + /* Save memory base and Limit registers */ pci_bus_read_config_word(pci_bus, devfn, PCI_MEMORY_BASE, &w_base); pci_bus_read_config_word(pci_bus, devfn, PCI_MEMORY_LIMIT, &w_length); @@ -787,7 +768,7 @@ int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func) func->mem_head = mem_node; } - // Save prefetchable memory base and Limit registers + /* Save prefetchable memory base and Limit registers */ pci_bus_read_config_word(pci_bus, devfn, PCI_PREF_MEMORY_BASE, &w_base); pci_bus_read_config_word(pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, &w_length); @@ -802,7 +783,7 @@ int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func) p_mem_node->next = func->p_mem_head; func->p_mem_head = p_mem_node; } - // Figure out IO and memory base lengths + /* Figure out IO and memory base lengths */ for (cloop = 0x10; cloop <= 0x14; cloop += 4) { pci_bus_read_config_dword (pci_bus, devfn, cloop, &save_base); @@ -812,11 +793,14 @@ int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func) temp_register = base; - if (base) { // If this register is implemented + /* If this register is implemented */ + if (base) { if (((base & 0x03L) == 0x01) && (save_command & 0x01)) { - // IO base - // set temp_register = amount of IO space requested + /* IO base + * set temp_register = amount + * of IO space requested + */ temp_register = base & 0xFFFFFFFE; temp_register = (~temp_register) + 1; @@ -834,7 +818,7 @@ int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func) } else if (((base & 0x0BL) == 0x08) && (save_command & 0x02)) { - // prefetchable memory base + /* prefetchable memory base */ temp_register = base & 0xFFFFFFF0; temp_register = (~temp_register) + 1; @@ -851,7 +835,7 @@ int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func) } else if (((base & 0x0BL) == 0x00) && (save_command & 0x02)) { - // prefetchable memory base + /* prefetchable memory base */ temp_register = base & 0xFFFFFFF0; temp_register = (~temp_register) + 1; @@ -868,9 +852,10 @@ int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func) } else return(1); } - } // End of base register loop - } else if ((header_type & 0x7F) == 0x00) { // Standard header - // Figure out IO and memory base lengths + } /* End of base register loop */ + /* Standard header */ + } else if ((header_type & 0x7F) == 0x00) { + /* Figure out IO and memory base lengths */ for (cloop = 0x10; cloop <= 0x24; cloop += 4) { pci_bus_read_config_dword(pci_bus, devfn, cloop, &save_base); @@ -880,11 +865,14 @@ int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func) temp_register = base; - if (base) { // If this register is implemented + /* If this register is implemented */ + if (base) { if (((base & 0x03L) == 0x01) && (save_command & 0x01)) { - // IO base - // set temp_register = amount of IO space requested + /* IO base + * set temp_register = amount + * of IO space requested + */ temp_register = base & 0xFFFFFFFE; temp_register = (~temp_register) + 1; @@ -901,7 +889,7 @@ int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func) } else if (((base & 0x0BL) == 0x08) && (save_command & 0x02)) { - // prefetchable memory base + /* prefetchable memory base */ temp_register = base & 0xFFFFFFF0; temp_register = (~temp_register) + 1; @@ -918,7 +906,7 @@ int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func) } else if (((base & 0x0BL) == 0x00) && (save_command & 0x02)) { - // prefetchable memory base + /* prefetchable memory base */ temp_register = base & 0xFFFFFFF0; temp_register = (~temp_register) + 1; @@ -935,15 +923,14 @@ int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func) } else return(1); } - } // End of base register loop - } else { // Some other unknown header type + } /* End of base register loop */ } - // find the next device in this slot + /* find the next device in this slot */ func = cpqhp_slot_find(func->bus, func->device, index++); } - return(0); + return 0; } @@ -975,16 +962,16 @@ int cpqhp_configure_board(struct controller *ctrl, struct pci_func * func) pci_bus->number = func->bus; devfn = PCI_DEVFN(func->device, func->function); - // Start at the top of config space so that the control - // registers are programmed last - for (cloop = 0x3C; cloop > 0; cloop -= 4) { + /* Start at the top of config space so that the control + * registers are programmed last + */ + for (cloop = 0x3C; cloop > 0; cloop -= 4) pci_bus_write_config_dword (pci_bus, devfn, cloop, func->config_space[cloop >> 2]); - } pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type); - // If this is a bridge device, restore subordinate devices - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // PCI-PCI Bridge + /* If this is a bridge device, restore subordinate devices */ + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { pci_bus_read_config_byte (pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus); sub_bus = (int) secondary_bus; @@ -1000,8 +987,9 @@ int cpqhp_configure_board(struct controller *ctrl, struct pci_func * func) } } else { - // Check all the base Address Registers to make sure - // they are the same. If not, the board is different. + /* Check all the base Address Registers to make sure + * they are the same. If not, the board is different. + */ for (cloop = 16; cloop < 40; cloop += 4) { pci_bus_read_config_dword (pci_bus, devfn, cloop, &temp); @@ -1058,27 +1046,28 @@ int cpqhp_valid_replace(struct controller *ctrl, struct pci_func * func) pci_bus_read_config_dword (pci_bus, devfn, PCI_VENDOR_ID, &temp_register); - // No adapter present + /* No adapter present */ if (temp_register == 0xFFFFFFFF) return(NO_ADAPTER_PRESENT); if (temp_register != func->config_space[0]) return(ADAPTER_NOT_SAME); - // Check for same revision number and class code + /* Check for same revision number and class code */ pci_bus_read_config_dword (pci_bus, devfn, PCI_CLASS_REVISION, &temp_register); - // Adapter not the same + /* Adapter not the same */ if (temp_register != func->config_space[0x08 >> 2]) return(ADAPTER_NOT_SAME); - // Check for Bridge + /* Check for Bridge */ pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type); - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // PCI-PCI Bridge - // In order to continue checking, we must program the - // bus registers in the bridge to respond to accesses - // for it's subordinate bus(es) + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { + /* In order to continue checking, we must program the + * bus registers in the bridge to respond to accesses + * for its subordinate bus(es) + */ temp_register = func->config_space[0x18 >> 2]; pci_bus_write_config_dword (pci_bus, devfn, PCI_PRIMARY_BUS, temp_register); @@ -1096,35 +1085,39 @@ int cpqhp_valid_replace(struct controller *ctrl, struct pci_func * func) } } - // Check to see if it is a standard config header + /* Check to see if it is a standard config header */ else if ((header_type & 0x7F) == PCI_HEADER_TYPE_NORMAL) { - // Check subsystem vendor and ID + /* Check subsystem vendor and ID */ pci_bus_read_config_dword (pci_bus, devfn, PCI_SUBSYSTEM_VENDOR_ID, &temp_register); if (temp_register != func->config_space[0x2C >> 2]) { - // If it's a SMART-2 and the register isn't filled - // in, ignore the difference because - // they just have an old rev of the firmware - + /* If it's a SMART-2 and the register isn't + * filled in, ignore the difference because + * they just have an old rev of the firmware + */ if (!((func->config_space[0] == 0xAE100E11) && (temp_register == 0x00L))) return(ADAPTER_NOT_SAME); } - // Figure out IO and memory base lengths + /* Figure out IO and memory base lengths */ for (cloop = 0x10; cloop <= 0x24; cloop += 4) { temp_register = 0xFFFFFFFF; pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register); pci_bus_read_config_dword (pci_bus, devfn, cloop, &base); - if (base) { // If this register is implemented + + /* If this register is implemented */ + if (base) { if (base & 0x01L) { - // IO base - // set base = amount of IO space requested + /* IO base + * set base = amount of IO + * space requested + */ base = base & 0xFFFFFFFE; base = (~base) + 1; type = 1; } else { - // memory base + /* memory base */ base = base & 0xFFFFFFF0; base = (~base) + 1; @@ -1135,23 +1128,24 @@ int cpqhp_valid_replace(struct controller *ctrl, struct pci_func * func) type = 0; } - // Check information in slot structure + /* Check information in slot structure */ if (func->base_length[(cloop - 0x10) >> 2] != base) return(ADAPTER_NOT_SAME); if (func->base_type[(cloop - 0x10) >> 2] != type) return(ADAPTER_NOT_SAME); - } // End of base register loop + } /* End of base register loop */ - } // End of (type 0 config space) else + } /* End of (type 0 config space) else */ else { - // this is not a type 0 or 1 config space header so - // we don't know how to do it + /* this is not a type 0 or 1 config space header so + * we don't know how to do it + */ return(DEVICE_TYPE_NOT_SUPPORTED); } - // Get the next function + /* Get the next function */ func = cpqhp_slot_find(func->bus, func->device, index++); } @@ -1168,7 +1162,7 @@ int cpqhp_valid_replace(struct controller *ctrl, struct pci_func * func) * this function is for hot plug ADD! * * returns 0 if success - */ + */ int cpqhp_find_available_resources(struct controller *ctrl, void __iomem *rom_start) { u8 temp; @@ -1187,10 +1181,10 @@ int cpqhp_find_available_resources(struct controller *ctrl, void __iomem *rom_st rom_resource_table = detect_HRT_floating_pointer(rom_start, rom_start+0xffff); dbg("rom_resource_table = %p\n", rom_resource_table); - if (rom_resource_table == NULL) { + if (rom_resource_table == NULL) return -ENODEV; - } - // Sum all resources and setup resource maps + + /* Sum all resources and setup resource maps */ unused_IRQ = readl(rom_resource_table + UNUSED_IRQ); dbg("unused_IRQ = %x\n", unused_IRQ); @@ -1222,13 +1216,11 @@ int cpqhp_find_available_resources(struct controller *ctrl, void __iomem *rom_st temp = 0; - if (!cpqhp_nic_irq) { + if (!cpqhp_nic_irq) cpqhp_nic_irq = ctrl->cfgspc_irq; - } - if (!cpqhp_disk_irq) { + if (!cpqhp_disk_irq) cpqhp_disk_irq = ctrl->cfgspc_irq; - } dbg("cpqhp_disk_irq, cpqhp_nic_irq= %d, %d\n", cpqhp_disk_irq, cpqhp_nic_irq); @@ -1262,13 +1254,13 @@ int cpqhp_find_available_resources(struct controller *ctrl, void __iomem *rom_st dev_func, io_base, io_length, mem_base, mem_length, pre_mem_base, pre_mem_length, primary_bus, secondary_bus, max_bus); - // If this entry isn't for our controller's bus, ignore it + /* If this entry isn't for our controller's bus, ignore it */ if (primary_bus != ctrl->bus) { i--; one_slot += sizeof (struct slot_rt); continue; } - // find out if this entry is for an occupied slot + /* find out if this entry is for an occupied slot */ ctrl->pci_bus->number = primary_bus; pci_bus_read_config_dword (ctrl->pci_bus, dev_func, PCI_VENDOR_ID, &temp_dword); dbg("temp_D_word = %x\n", temp_dword); @@ -1282,13 +1274,13 @@ int cpqhp_find_available_resources(struct controller *ctrl, void __iomem *rom_st func = cpqhp_slot_find(primary_bus, dev_func >> 3, index++); } - // If we can't find a match, skip this table entry + /* If we can't find a match, skip this table entry */ if (!func) { i--; one_slot += sizeof (struct slot_rt); continue; } - // this may not work and shouldn't be used + /* this may not work and shouldn't be used */ if (secondary_bus != primary_bus) bridged_slot = 1; else @@ -1301,7 +1293,7 @@ int cpqhp_find_available_resources(struct controller *ctrl, void __iomem *rom_st } - // If we've got a valid IO base, use it + /* If we've got a valid IO base, use it */ temp_dword = io_base + io_length; @@ -1325,7 +1317,7 @@ int cpqhp_find_available_resources(struct controller *ctrl, void __iomem *rom_st } } - // If we've got a valid memory base, use it + /* If we've got a valid memory base, use it */ temp_dword = mem_base + mem_length; if ((mem_base) && (temp_dword < 0x10000)) { mem_node = kmalloc(sizeof(*mem_node), GFP_KERNEL); @@ -1348,8 +1340,9 @@ int cpqhp_find_available_resources(struct controller *ctrl, void __iomem *rom_st } } - // If we've got a valid prefetchable memory base, and - // the base + length isn't greater than 0xFFFF + /* If we've got a valid prefetchable memory base, and + * the base + length isn't greater than 0xFFFF + */ temp_dword = pre_mem_base + pre_mem_length; if ((pre_mem_base) && (temp_dword < 0x10000)) { p_mem_node = kmalloc(sizeof(*p_mem_node), GFP_KERNEL); @@ -1372,9 +1365,10 @@ int cpqhp_find_available_resources(struct controller *ctrl, void __iomem *rom_st } } - // If we've got a valid bus number, use it - // The second condition is to ignore bus numbers on - // populated slots that don't have PCI-PCI bridges + /* If we've got a valid bus number, use it + * The second condition is to ignore bus numbers on + * populated slots that don't have PCI-PCI bridges + */ if (secondary_bus && (secondary_bus != primary_bus)) { bus_node = kmalloc(sizeof(*bus_node), GFP_KERNEL); if (!bus_node) @@ -1398,8 +1392,9 @@ int cpqhp_find_available_resources(struct controller *ctrl, void __iomem *rom_st one_slot += sizeof (struct slot_rt); } - // If all of the following fail, we don't have any resources for - // hot plug add + /* If all of the following fail, we don't have any resources for + * hot plug add + */ rc = 1; rc &= cpqhp_resource_sort_and_combine(&(ctrl->mem_head)); rc &= cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head)); diff --git a/drivers/pci/hotplug/ibmphp_core.c b/drivers/pci/hotplug/ibmphp_core.c index dd18f857dfb0..7485ffda950c 100644 --- a/drivers/pci/hotplug/ibmphp_core.c +++ b/drivers/pci/hotplug/ibmphp_core.c @@ -153,45 +153,47 @@ int ibmphp_init_devno(struct slot **cur_slot) return -1; } for (loop = 0; loop < len; loop++) { - if ((*cur_slot)->number == rtable->slots[loop].slot) { - if ((*cur_slot)->bus == rtable->slots[loop].bus) { + if ((*cur_slot)->number == rtable->slots[loop].slot && + (*cur_slot)->bus == rtable->slots[loop].bus) { + struct io_apic_irq_attr irq_attr; + (*cur_slot)->device = PCI_SLOT(rtable->slots[loop].devfn); for (i = 0; i < 4; i++) (*cur_slot)->irq[i] = IO_APIC_get_PCI_irq_vector((int) (*cur_slot)->bus, - (int) (*cur_slot)->device, i); + (int) (*cur_slot)->device, i, + &irq_attr); - debug("(*cur_slot)->irq[0] = %x\n", - (*cur_slot)->irq[0]); - debug("(*cur_slot)->irq[1] = %x\n", - (*cur_slot)->irq[1]); - debug("(*cur_slot)->irq[2] = %x\n", - (*cur_slot)->irq[2]); - debug("(*cur_slot)->irq[3] = %x\n", - (*cur_slot)->irq[3]); + debug("(*cur_slot)->irq[0] = %x\n", + (*cur_slot)->irq[0]); + debug("(*cur_slot)->irq[1] = %x\n", + (*cur_slot)->irq[1]); + debug("(*cur_slot)->irq[2] = %x\n", + (*cur_slot)->irq[2]); + debug("(*cur_slot)->irq[3] = %x\n", + (*cur_slot)->irq[3]); - debug("rtable->exlusive_irqs = %x\n", + debug("rtable->exlusive_irqs = %x\n", rtable->exclusive_irqs); - debug("rtable->slots[loop].irq[0].bitmap = %x\n", + debug("rtable->slots[loop].irq[0].bitmap = %x\n", rtable->slots[loop].irq[0].bitmap); - debug("rtable->slots[loop].irq[1].bitmap = %x\n", + debug("rtable->slots[loop].irq[1].bitmap = %x\n", rtable->slots[loop].irq[1].bitmap); - debug("rtable->slots[loop].irq[2].bitmap = %x\n", + debug("rtable->slots[loop].irq[2].bitmap = %x\n", rtable->slots[loop].irq[2].bitmap); - debug("rtable->slots[loop].irq[3].bitmap = %x\n", + debug("rtable->slots[loop].irq[3].bitmap = %x\n", rtable->slots[loop].irq[3].bitmap); - debug("rtable->slots[loop].irq[0].link = %x\n", + debug("rtable->slots[loop].irq[0].link = %x\n", rtable->slots[loop].irq[0].link); - debug("rtable->slots[loop].irq[1].link = %x\n", + debug("rtable->slots[loop].irq[1].link = %x\n", rtable->slots[loop].irq[1].link); - debug("rtable->slots[loop].irq[2].link = %x\n", + debug("rtable->slots[loop].irq[2].link = %x\n", rtable->slots[loop].irq[2].link); - debug("rtable->slots[loop].irq[3].link = %x\n", + debug("rtable->slots[loop].irq[3].link = %x\n", rtable->slots[loop].irq[3].link); - debug("end of init_devno\n"); - kfree(rtable); - return 0; - } + debug("end of init_devno\n"); + kfree(rtable); + return 0; } } @@ -1316,7 +1318,6 @@ error: } struct hotplug_slot_ops ibmphp_hotplug_slot_ops = { - .owner = THIS_MODULE, .set_attention_status = set_attention_status, .enable_slot = enable_slot, .disable_slot = ibmphp_disable_slot, @@ -1419,3 +1420,4 @@ static void __exit ibmphp_exit(void) } module_init(ibmphp_init); +module_exit(ibmphp_exit); diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c index 535fce0f07f9..844580489d4d 100644 --- a/drivers/pci/hotplug/pci_hotplug_core.c +++ b/drivers/pci/hotplug/pci_hotplug_core.c @@ -347,125 +347,129 @@ static struct pci_slot_attribute hotplug_slot_attr_test = { .store = test_write_file }; -static int has_power_file(struct pci_slot *pci_slot) +static bool has_power_file(struct pci_slot *pci_slot) { struct hotplug_slot *slot = pci_slot->hotplug; if ((!slot) || (!slot->ops)) - return -ENODEV; + return false; if ((slot->ops->enable_slot) || (slot->ops->disable_slot) || (slot->ops->get_power_status)) - return 0; - return -ENOENT; + return true; + return false; } -static int has_attention_file(struct pci_slot *pci_slot) +static bool has_attention_file(struct pci_slot *pci_slot) { struct hotplug_slot *slot = pci_slot->hotplug; if ((!slot) || (!slot->ops)) - return -ENODEV; + return false; if ((slot->ops->set_attention_status) || (slot->ops->get_attention_status)) - return 0; - return -ENOENT; + return true; + return false; } -static int has_latch_file(struct pci_slot *pci_slot) +static bool has_latch_file(struct pci_slot *pci_slot) { struct hotplug_slot *slot = pci_slot->hotplug; if ((!slot) || (!slot->ops)) - return -ENODEV; + return false; if (slot->ops->get_latch_status) - return 0; - return -ENOENT; + return true; + return false; } -static int has_adapter_file(struct pci_slot *pci_slot) +static bool has_adapter_file(struct pci_slot *pci_slot) { struct hotplug_slot *slot = pci_slot->hotplug; if ((!slot) || (!slot->ops)) - return -ENODEV; + return false; if (slot->ops->get_adapter_status) - return 0; - return -ENOENT; + return true; + return false; } -static int has_max_bus_speed_file(struct pci_slot *pci_slot) +static bool has_max_bus_speed_file(struct pci_slot *pci_slot) { struct hotplug_slot *slot = pci_slot->hotplug; if ((!slot) || (!slot->ops)) - return -ENODEV; + return false; if (slot->ops->get_max_bus_speed) - return 0; - return -ENOENT; + return true; + return false; } -static int has_cur_bus_speed_file(struct pci_slot *pci_slot) +static bool has_cur_bus_speed_file(struct pci_slot *pci_slot) { struct hotplug_slot *slot = pci_slot->hotplug; if ((!slot) || (!slot->ops)) - return -ENODEV; + return false; if (slot->ops->get_cur_bus_speed) - return 0; - return -ENOENT; + return true; + return false; } -static int has_test_file(struct pci_slot *pci_slot) +static bool has_test_file(struct pci_slot *pci_slot) { struct hotplug_slot *slot = pci_slot->hotplug; if ((!slot) || (!slot->ops)) - return -ENODEV; + return false; if (slot->ops->hardware_test) - return 0; - return -ENOENT; + return true; + return false; } static int fs_add_slot(struct pci_slot *slot) { int retval = 0; - if (has_power_file(slot) == 0) { - retval = sysfs_create_file(&slot->kobj, &hotplug_slot_attr_power.attr); + /* Create symbolic link to the hotplug driver module */ + pci_hp_create_module_link(slot); + + if (has_power_file(slot)) { + retval = sysfs_create_file(&slot->kobj, + &hotplug_slot_attr_power.attr); if (retval) goto exit_power; } - if (has_attention_file(slot) == 0) { + if (has_attention_file(slot)) { retval = sysfs_create_file(&slot->kobj, &hotplug_slot_attr_attention.attr); if (retval) goto exit_attention; } - if (has_latch_file(slot) == 0) { + if (has_latch_file(slot)) { retval = sysfs_create_file(&slot->kobj, &hotplug_slot_attr_latch.attr); if (retval) goto exit_latch; } - if (has_adapter_file(slot) == 0) { + if (has_adapter_file(slot)) { retval = sysfs_create_file(&slot->kobj, &hotplug_slot_attr_presence.attr); if (retval) goto exit_adapter; } - if (has_max_bus_speed_file(slot) == 0) { + if (has_max_bus_speed_file(slot)) { retval = sysfs_create_file(&slot->kobj, - &hotplug_slot_attr_max_bus_speed.attr); + &hotplug_slot_attr_max_bus_speed.attr); if (retval) goto exit_max_speed; } - if (has_cur_bus_speed_file(slot) == 0) { + if (has_cur_bus_speed_file(slot)) { retval = sysfs_create_file(&slot->kobj, - &hotplug_slot_attr_cur_bus_speed.attr); + &hotplug_slot_attr_cur_bus_speed.attr); if (retval) goto exit_cur_speed; } - if (has_test_file(slot) == 0) { + if (has_test_file(slot)) { retval = sysfs_create_file(&slot->kobj, &hotplug_slot_attr_test.attr); if (retval) @@ -475,55 +479,61 @@ static int fs_add_slot(struct pci_slot *slot) goto exit; exit_test: - if (has_cur_bus_speed_file(slot) == 0) - sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_cur_bus_speed.attr); - + if (has_cur_bus_speed_file(slot)) + sysfs_remove_file(&slot->kobj, + &hotplug_slot_attr_cur_bus_speed.attr); exit_cur_speed: - if (has_max_bus_speed_file(slot) == 0) - sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr); - + if (has_max_bus_speed_file(slot)) + sysfs_remove_file(&slot->kobj, + &hotplug_slot_attr_max_bus_speed.attr); exit_max_speed: - if (has_adapter_file(slot) == 0) - sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_presence.attr); - + if (has_adapter_file(slot)) + sysfs_remove_file(&slot->kobj, + &hotplug_slot_attr_presence.attr); exit_adapter: - if (has_latch_file(slot) == 0) + if (has_latch_file(slot)) sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_latch.attr); - exit_latch: - if (has_attention_file(slot) == 0) - sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_attention.attr); - + if (has_attention_file(slot)) + sysfs_remove_file(&slot->kobj, + &hotplug_slot_attr_attention.attr); exit_attention: - if (has_power_file(slot) == 0) + if (has_power_file(slot)) sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_power.attr); exit_power: + pci_hp_remove_module_link(slot); exit: return retval; } static void fs_remove_slot(struct pci_slot *slot) { - if (has_power_file(slot) == 0) + if (has_power_file(slot)) sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_power.attr); - if (has_attention_file(slot) == 0) - sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_attention.attr); + if (has_attention_file(slot)) + sysfs_remove_file(&slot->kobj, + &hotplug_slot_attr_attention.attr); - if (has_latch_file(slot) == 0) + if (has_latch_file(slot)) sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_latch.attr); - if (has_adapter_file(slot) == 0) - sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_presence.attr); + if (has_adapter_file(slot)) + sysfs_remove_file(&slot->kobj, + &hotplug_slot_attr_presence.attr); - if (has_max_bus_speed_file(slot) == 0) - sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr); + if (has_max_bus_speed_file(slot)) + sysfs_remove_file(&slot->kobj, + &hotplug_slot_attr_max_bus_speed.attr); - if (has_cur_bus_speed_file(slot) == 0) - sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_cur_bus_speed.attr); + if (has_cur_bus_speed_file(slot)) + sysfs_remove_file(&slot->kobj, + &hotplug_slot_attr_cur_bus_speed.attr); - if (has_test_file(slot) == 0) + if (has_test_file(slot)) sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_test.attr); + + pci_hp_remove_module_link(slot); } static struct hotplug_slot *get_slot_from_name (const char *name) @@ -540,10 +550,10 @@ static struct hotplug_slot *get_slot_from_name (const char *name) } /** - * pci_hp_register - register a hotplug_slot with the PCI hotplug subsystem + * __pci_hp_register - register a hotplug_slot with the PCI hotplug subsystem * @bus: bus this slot is on * @slot: pointer to the &struct hotplug_slot to register - * @slot_nr: slot number + * @devnr: device number * @name: name registered with kobject core * * Registers a hotplug slot with the pci hotplug subsystem, which will allow @@ -551,8 +561,9 @@ static struct hotplug_slot *get_slot_from_name (const char *name) * * Returns 0 if successful, anything else for an error. */ -int pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus, int slot_nr, - const char *name) +int __pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus, + int devnr, const char *name, + struct module *owner, const char *mod_name) { int result; struct pci_slot *pci_slot; @@ -567,14 +578,16 @@ int pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus, int slot_nr, return -EINVAL; } - mutex_lock(&pci_hp_mutex); + slot->ops->owner = owner; + slot->ops->mod_name = mod_name; + mutex_lock(&pci_hp_mutex); /* * No problems if we call this interface from both ACPI_PCI_SLOT * driver and call it here again. If we've already created the * pci_slot, the interface will simply bump the refcount. */ - pci_slot = pci_create_slot(bus, slot_nr, name, slot); + pci_slot = pci_create_slot(bus, devnr, name, slot); if (IS_ERR(pci_slot)) { result = PTR_ERR(pci_slot); goto out; @@ -684,6 +697,6 @@ MODULE_LICENSE("GPL"); module_param(debug, bool, 0644); MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); -EXPORT_SYMBOL_GPL(pci_hp_register); +EXPORT_SYMBOL_GPL(__pci_hp_register); EXPORT_SYMBOL_GPL(pci_hp_deregister); EXPORT_SYMBOL_GPL(pci_hp_change_slot_info); diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 0a368547e633..e6cf096498be 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -81,7 +81,6 @@ struct slot { struct hpc_ops *hpc_ops; struct hotplug_slot *hotplug_slot; struct list_head slot_list; - unsigned long last_emi_toggle; struct delayed_work work; /* work for button event */ struct mutex lock; }; @@ -203,8 +202,6 @@ struct hpc_ops { int (*set_attention_status)(struct slot *slot, u8 status); int (*get_latch_status)(struct slot *slot, u8 *status); int (*get_adapter_status)(struct slot *slot, u8 *status); - int (*get_emi_status)(struct slot *slot, u8 *status); - int (*toggle_emi)(struct slot *slot); int (*get_max_bus_speed)(struct slot *slot, enum pci_bus_speed *speed); int (*get_cur_bus_speed)(struct slot *slot, enum pci_bus_speed *speed); int (*get_max_lnk_width)(struct slot *slot, enum pcie_link_width *val); diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index fb254b2454de..2317557fdee6 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -73,7 +73,6 @@ static int get_max_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *val static int get_cur_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); static struct hotplug_slot_ops pciehp_hotplug_slot_ops = { - .owner = THIS_MODULE, .set_attention_status = set_attention_status, .enable_slot = enable_slot, .disable_slot = disable_slot, @@ -85,99 +84,6 @@ static struct hotplug_slot_ops pciehp_hotplug_slot_ops = { .get_cur_bus_speed = get_cur_bus_speed, }; -/* - * Check the status of the Electro Mechanical Interlock (EMI) - */ -static int get_lock_status(struct hotplug_slot *hotplug_slot, u8 *value) -{ - struct slot *slot = hotplug_slot->private; - return (slot->hpc_ops->get_emi_status(slot, value)); -} - -/* - * sysfs interface for the Electro Mechanical Interlock (EMI) - * 1 == locked, 0 == unlocked - */ -static ssize_t lock_read_file(struct hotplug_slot *slot, char *buf) -{ - int retval; - u8 value; - - retval = get_lock_status(slot, &value); - if (retval) - goto lock_read_exit; - retval = sprintf (buf, "%d\n", value); - -lock_read_exit: - return retval; -} - -/* - * Change the status of the Electro Mechanical Interlock (EMI) - * This is a toggle - in addition there must be at least 1 second - * in between toggles. - */ -static int set_lock_status(struct hotplug_slot *hotplug_slot, u8 status) -{ - struct slot *slot = hotplug_slot->private; - int retval; - u8 value; - - mutex_lock(&slot->ctrl->crit_sect); - - /* has it been >1 sec since our last toggle? */ - if ((get_seconds() - slot->last_emi_toggle) < 1) { - mutex_unlock(&slot->ctrl->crit_sect); - return -EINVAL; - } - - /* see what our current state is */ - retval = get_lock_status(hotplug_slot, &value); - if (retval || (value == status)) - goto set_lock_exit; - - slot->hpc_ops->toggle_emi(slot); -set_lock_exit: - mutex_unlock(&slot->ctrl->crit_sect); - return 0; -} - -/* - * sysfs interface which allows the user to toggle the Electro Mechanical - * Interlock. Valid values are either 0 or 1. 0 == unlock, 1 == lock - */ -static ssize_t lock_write_file(struct hotplug_slot *hotplug_slot, - const char *buf, size_t count) -{ - struct slot *slot = hotplug_slot->private; - unsigned long llock; - u8 lock; - int retval = 0; - - llock = simple_strtoul(buf, NULL, 10); - lock = (u8)(llock & 0xff); - - switch (lock) { - case 0: - case 1: - retval = set_lock_status(hotplug_slot, lock); - break; - default: - ctrl_err(slot->ctrl, "%d is an invalid lock value\n", - lock); - retval = -EINVAL; - } - if (retval) - return retval; - return count; -} - -static struct hotplug_slot_attribute hotplug_slot_attr_lock = { - .attr = {.name = "lock", .mode = S_IFREG | S_IRUGO | S_IWUSR}, - .show = lock_read_file, - .store = lock_write_file -}; - /** * release_slot - free up the memory used by a slot * @hotplug_slot: slot to free @@ -236,17 +142,6 @@ static int init_slots(struct controller *ctrl) get_attention_status(hotplug_slot, &info->attention_status); get_latch_status(hotplug_slot, &info->latch_status); get_adapter_status(hotplug_slot, &info->adapter_status); - /* create additional sysfs entries */ - if (EMI(ctrl)) { - retval = sysfs_create_file(&hotplug_slot->pci_slot->kobj, - &hotplug_slot_attr_lock.attr); - if (retval) { - pci_hp_deregister(hotplug_slot); - ctrl_err(ctrl, "Cannot create additional sysfs " - "entries\n"); - goto error_info; - } - } } return 0; @@ -261,13 +156,8 @@ error: static void cleanup_slots(struct controller *ctrl) { struct slot *slot; - - list_for_each_entry(slot, &ctrl->slot_list, slot_list) { - if (EMI(ctrl)) - sysfs_remove_file(&slot->hotplug_slot->pci_slot->kobj, - &hotplug_slot_attr_lock.attr); + list_for_each_entry(slot, &ctrl->slot_list, slot_list) pci_hp_deregister(slot->hotplug_slot); - } } /* diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 07bd32151146..52813257e5bf 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -422,35 +422,6 @@ static int hpc_query_power_fault(struct slot *slot) return !!(slot_status & PCI_EXP_SLTSTA_PFD); } -static int hpc_get_emi_status(struct slot *slot, u8 *status) -{ - struct controller *ctrl = slot->ctrl; - u16 slot_status; - int retval; - - retval = pciehp_readw(ctrl, PCI_EXP_SLTSTA, &slot_status); - if (retval) { - ctrl_err(ctrl, "Cannot check EMI status\n"); - return retval; - } - *status = !!(slot_status & PCI_EXP_SLTSTA_EIS); - return retval; -} - -static int hpc_toggle_emi(struct slot *slot) -{ - u16 slot_cmd; - u16 cmd_mask; - int rc; - - slot_cmd = PCI_EXP_SLTCTL_EIC; - cmd_mask = PCI_EXP_SLTCTL_EIC; - rc = pcie_write_cmd(slot->ctrl, slot_cmd, cmd_mask); - slot->last_emi_toggle = get_seconds(); - - return rc; -} - static int hpc_set_attention_status(struct slot *slot, u8 value) { struct controller *ctrl = slot->ctrl; @@ -874,8 +845,6 @@ static struct hpc_ops pciehp_hpc_ops = { .get_attention_status = hpc_get_attention_status, .get_latch_status = hpc_get_latch_status, .get_adapter_status = hpc_get_adapter_status, - .get_emi_status = hpc_get_emi_status, - .toggle_emi = hpc_toggle_emi, .get_max_bus_speed = hpc_get_max_lnk_speed, .get_cur_bus_speed = hpc_get_cur_lnk_speed, diff --git a/drivers/pci/hotplug/pcihp_skeleton.c b/drivers/pci/hotplug/pcihp_skeleton.c index e3dd6cf9e89f..5175d9b26f0b 100644 --- a/drivers/pci/hotplug/pcihp_skeleton.c +++ b/drivers/pci/hotplug/pcihp_skeleton.c @@ -82,7 +82,6 @@ static int get_latch_status (struct hotplug_slot *slot, u8 *value); static int get_adapter_status (struct hotplug_slot *slot, u8 *value); static struct hotplug_slot_ops skel_hotplug_slot_ops = { - .owner = THIS_MODULE, .enable_slot = enable_slot, .disable_slot = disable_slot, .set_attention_status = set_attention_status, diff --git a/drivers/pci/hotplug/rpaphp_core.c b/drivers/pci/hotplug/rpaphp_core.c index 95d02a08fdc7..c159223389ec 100644 --- a/drivers/pci/hotplug/rpaphp_core.c +++ b/drivers/pci/hotplug/rpaphp_core.c @@ -423,7 +423,6 @@ static int disable_slot(struct hotplug_slot *hotplug_slot) } struct hotplug_slot_ops rpaphp_hotplug_slot_ops = { - .owner = THIS_MODULE, .enable_slot = enable_slot, .disable_slot = disable_slot, .set_attention_status = set_attention_status, diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c index 3eee70928d45..a4494d78e7c2 100644 --- a/drivers/pci/hotplug/sgi_hotplug.c +++ b/drivers/pci/hotplug/sgi_hotplug.c @@ -83,7 +83,6 @@ static int disable_slot(struct hotplug_slot *slot); static inline int get_power_status(struct hotplug_slot *slot, u8 *value); static struct hotplug_slot_ops sn_hotplug_slot_ops = { - .owner = THIS_MODULE, .enable_slot = enable_slot, .disable_slot = disable_slot, .get_power_status = get_power_status, @@ -679,7 +678,7 @@ alloc_err: return rc; } -static int sn_pci_hotplug_init(void) +static int __init sn_pci_hotplug_init(void) { struct pci_bus *pci_bus = NULL; int rc; @@ -716,7 +715,7 @@ static int sn_pci_hotplug_init(void) return registered == 1 ? 0 : -ENODEV; } -static void sn_pci_hotplug_exit(void) +static void __exit sn_pci_hotplug_exit(void) { struct hotplug_slot *bss_hotplug_slot; diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c index fe8d149c2293..8a520a3d0f59 100644 --- a/drivers/pci/hotplug/shpchp_core.c +++ b/drivers/pci/hotplug/shpchp_core.c @@ -69,7 +69,6 @@ static int get_max_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *val static int get_cur_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); static struct hotplug_slot_ops shpchp_hotplug_slot_ops = { - .owner = THIS_MODULE, .set_attention_status = set_attention_status, .enable_slot = enable_slot, .disable_slot = disable_slot, diff --git a/drivers/pci/htirq.c b/drivers/pci/htirq.c index 6808d8333ecc..737a1c44b07a 100644 --- a/drivers/pci/htirq.c +++ b/drivers/pci/htirq.c @@ -98,6 +98,7 @@ int __ht_create_irq(struct pci_dev *dev, int idx, ht_irq_update_t *update) int max_irq; int pos; int irq; + int node; pos = pci_find_ht_capability(dev, HT_CAPTYPE_IRQ); if (!pos) @@ -125,7 +126,8 @@ int __ht_create_irq(struct pci_dev *dev, int idx, ht_irq_update_t *update) cfg->msg.address_lo = 0xffffffff; cfg->msg.address_hi = 0xffffffff; - irq = create_irq(); + node = dev_to_node(&dev->dev); + irq = create_irq_nr(0, node); if (irq <= 0) { kfree(cfg); diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index a563fbe559d0..e53eacd75c8d 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c @@ -39,6 +39,7 @@ #include #include #include +#include #include "pci.h" #define ROOT_SIZE VTD_PAGE_SIZE @@ -53,6 +54,8 @@ #define DEFAULT_DOMAIN_ADDRESS_WIDTH 48 +#define MAX_AGAW_WIDTH 64 + #define DOMAIN_MAX_ADDR(gaw) ((((u64)1) << gaw) - 1) #define IOVA_PFN(addr) ((addr) >> PAGE_SHIFT) @@ -131,8 +134,6 @@ static inline void context_set_fault_enable(struct context_entry *context) context->lo &= (((u64)-1) << 2) | 1; } -#define CONTEXT_TT_MULTI_LEVEL 0 - static inline void context_set_translation_type(struct context_entry *context, unsigned long value) { @@ -217,6 +218,14 @@ static inline bool dma_pte_present(struct dma_pte *pte) return (pte->val & 3) != 0; } +/* + * This domain is a statically identity mapping domain. + * 1. This domain creats a static 1:1 mapping to all usable memory. + * 2. It maps to each iommu if successful. + * 3. Each iommu mapps to this domain if successful. + */ +struct dmar_domain *si_domain; + /* devices under the same p2p bridge are owned in one domain */ #define DOMAIN_FLAG_P2P_MULTIPLE_DEVICES (1 << 0) @@ -225,6 +234,9 @@ static inline bool dma_pte_present(struct dma_pte *pte) */ #define DOMAIN_FLAG_VIRTUAL_MACHINE (1 << 1) +/* si_domain contains mulitple devices */ +#define DOMAIN_FLAG_STATIC_IDENTITY (1 << 2) + struct dmar_domain { int id; /* domain id */ unsigned long iommu_bmp; /* bitmap of iommus this domain uses*/ @@ -256,6 +268,7 @@ struct device_domain_info { u8 bus; /* PCI bus number */ u8 devfn; /* PCI devfn number */ struct pci_dev *dev; /* it's NULL for PCIE-to-PCI bridge */ + struct intel_iommu *iommu; /* IOMMU used by this device */ struct dmar_domain *domain; /* pointer to domain */ }; @@ -401,17 +414,13 @@ void free_iova_mem(struct iova *iova) static inline int width_to_agaw(int width); -/* calculate agaw for each iommu. - * "SAGAW" may be different across iommus, use a default agaw, and - * get a supported less agaw for iommus that don't support the default agaw. - */ -int iommu_calculate_agaw(struct intel_iommu *iommu) +static int __iommu_calculate_agaw(struct intel_iommu *iommu, int max_gaw) { unsigned long sagaw; int agaw = -1; sagaw = cap_sagaw(iommu->cap); - for (agaw = width_to_agaw(DEFAULT_DOMAIN_ADDRESS_WIDTH); + for (agaw = width_to_agaw(max_gaw); agaw >= 0; agaw--) { if (test_bit(agaw, &sagaw)) break; @@ -420,12 +429,32 @@ int iommu_calculate_agaw(struct intel_iommu *iommu) return agaw; } -/* in native case, each domain is related to only one iommu */ +/* + * Calculate max SAGAW for each iommu. + */ +int iommu_calculate_max_sagaw(struct intel_iommu *iommu) +{ + return __iommu_calculate_agaw(iommu, MAX_AGAW_WIDTH); +} + +/* + * calculate agaw for each iommu. + * "SAGAW" may be different across iommus, use a default agaw, and + * get a supported less agaw for iommus that don't support the default agaw. + */ +int iommu_calculate_agaw(struct intel_iommu *iommu) +{ + return __iommu_calculate_agaw(iommu, DEFAULT_DOMAIN_ADDRESS_WIDTH); +} + +/* This functionin only returns single iommu in a domain */ static struct intel_iommu *domain_get_iommu(struct dmar_domain *domain) { int iommu_id; + /* si_domain and vm domain should not get here. */ BUG_ON(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE); + BUG_ON(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY); iommu_id = find_first_bit(&domain->iommu_bmp, g_num_of_iommus); if (iommu_id < 0 || iommu_id >= g_num_of_iommus) @@ -809,7 +838,7 @@ static int iommu_alloc_root_entry(struct intel_iommu *iommu) static void iommu_set_root_entry(struct intel_iommu *iommu) { void *addr; - u32 cmd, sts; + u32 sts; unsigned long flag; addr = iommu->root_entry; @@ -817,12 +846,11 @@ static void iommu_set_root_entry(struct intel_iommu *iommu) spin_lock_irqsave(&iommu->register_lock, flag); dmar_writeq(iommu->reg + DMAR_RTADDR_REG, virt_to_phys(addr)); - cmd = iommu->gcmd | DMA_GCMD_SRTP; - writel(cmd, iommu->reg + DMAR_GCMD_REG); + writel(iommu->gcmd | DMA_GCMD_SRTP, iommu->reg + DMAR_GCMD_REG); /* Make sure hardware complete it */ IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, - readl, (sts & DMA_GSTS_RTPS), sts); + readl, (sts & DMA_GSTS_RTPS), sts); spin_unlock_irqrestore(&iommu->register_lock, flag); } @@ -834,39 +862,25 @@ static void iommu_flush_write_buffer(struct intel_iommu *iommu) if (!rwbf_quirk && !cap_rwbf(iommu->cap)) return; - val = iommu->gcmd | DMA_GCMD_WBF; spin_lock_irqsave(&iommu->register_lock, flag); - writel(val, iommu->reg + DMAR_GCMD_REG); + writel(iommu->gcmd | DMA_GCMD_WBF, iommu->reg + DMAR_GCMD_REG); /* Make sure hardware complete it */ IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, - readl, (!(val & DMA_GSTS_WBFS)), val); + readl, (!(val & DMA_GSTS_WBFS)), val); spin_unlock_irqrestore(&iommu->register_lock, flag); } /* return value determine if we need a write buffer flush */ -static int __iommu_flush_context(struct intel_iommu *iommu, - u16 did, u16 source_id, u8 function_mask, u64 type, - int non_present_entry_flush) +static void __iommu_flush_context(struct intel_iommu *iommu, + u16 did, u16 source_id, u8 function_mask, + u64 type) { u64 val = 0; unsigned long flag; - /* - * In the non-present entry flush case, if hardware doesn't cache - * non-present entry we do nothing and if hardware cache non-present - * entry, we flush entries of domain 0 (the domain id is used to cache - * any non-present entries) - */ - if (non_present_entry_flush) { - if (!cap_caching_mode(iommu->cap)) - return 1; - else - did = 0; - } - switch (type) { case DMA_CCMD_GLOBAL_INVL: val = DMA_CCMD_GLOBAL_INVL; @@ -891,33 +905,16 @@ static int __iommu_flush_context(struct intel_iommu *iommu, dmar_readq, (!(val & DMA_CCMD_ICC)), val); spin_unlock_irqrestore(&iommu->register_lock, flag); - - /* flush context entry will implicitly flush write buffer */ - return 0; } /* return value determine if we need a write buffer flush */ -static int __iommu_flush_iotlb(struct intel_iommu *iommu, u16 did, - u64 addr, unsigned int size_order, u64 type, - int non_present_entry_flush) +static void __iommu_flush_iotlb(struct intel_iommu *iommu, u16 did, + u64 addr, unsigned int size_order, u64 type) { int tlb_offset = ecap_iotlb_offset(iommu->ecap); u64 val = 0, val_iva = 0; unsigned long flag; - /* - * In the non-present entry flush case, if hardware doesn't cache - * non-present entry we do nothing and if hardware cache non-present - * entry, we flush entries of domain 0 (the domain id is used to cache - * any non-present entries) - */ - if (non_present_entry_flush) { - if (!cap_caching_mode(iommu->cap)) - return 1; - else - did = 0; - } - switch (type) { case DMA_TLB_GLOBAL_FLUSH: /* global flush doesn't need set IVA_REG */ @@ -965,37 +962,101 @@ static int __iommu_flush_iotlb(struct intel_iommu *iommu, u16 did, pr_debug("IOMMU: tlb flush request %Lx, actual %Lx\n", (unsigned long long)DMA_TLB_IIRG(type), (unsigned long long)DMA_TLB_IAIG(val)); - /* flush iotlb entry will implicitly flush write buffer */ - return 0; } -static int iommu_flush_iotlb_psi(struct intel_iommu *iommu, u16 did, - u64 addr, unsigned int pages, int non_present_entry_flush) +static struct device_domain_info *iommu_support_dev_iotlb( + struct dmar_domain *domain, int segment, u8 bus, u8 devfn) { - unsigned int mask; + int found = 0; + unsigned long flags; + struct device_domain_info *info; + struct intel_iommu *iommu = device_to_iommu(segment, bus, devfn); + + if (!ecap_dev_iotlb_support(iommu->ecap)) + return NULL; + + if (!iommu->qi) + return NULL; + + spin_lock_irqsave(&device_domain_lock, flags); + list_for_each_entry(info, &domain->devices, link) + if (info->bus == bus && info->devfn == devfn) { + found = 1; + break; + } + spin_unlock_irqrestore(&device_domain_lock, flags); + + if (!found || !info->dev) + return NULL; + + if (!pci_find_ext_capability(info->dev, PCI_EXT_CAP_ID_ATS)) + return NULL; + + if (!dmar_find_matched_atsr_unit(info->dev)) + return NULL; + + info->iommu = iommu; + + return info; +} + +static void iommu_enable_dev_iotlb(struct device_domain_info *info) +{ + if (!info) + return; + + pci_enable_ats(info->dev, VTD_PAGE_SHIFT); +} + +static void iommu_disable_dev_iotlb(struct device_domain_info *info) +{ + if (!info->dev || !pci_ats_enabled(info->dev)) + return; + + pci_disable_ats(info->dev); +} + +static void iommu_flush_dev_iotlb(struct dmar_domain *domain, + u64 addr, unsigned mask) +{ + u16 sid, qdep; + unsigned long flags; + struct device_domain_info *info; + + spin_lock_irqsave(&device_domain_lock, flags); + list_for_each_entry(info, &domain->devices, link) { + if (!info->dev || !pci_ats_enabled(info->dev)) + continue; + + sid = info->bus << 8 | info->devfn; + qdep = pci_ats_queue_depth(info->dev); + qi_flush_dev_iotlb(info->iommu, sid, qdep, addr, mask); + } + spin_unlock_irqrestore(&device_domain_lock, flags); +} + +static void iommu_flush_iotlb_psi(struct intel_iommu *iommu, u16 did, + u64 addr, unsigned int pages) +{ + unsigned int mask = ilog2(__roundup_pow_of_two(pages)); BUG_ON(addr & (~VTD_PAGE_MASK)); BUG_ON(pages == 0); - /* Fallback to domain selective flush if no PSI support */ - if (!cap_pgsel_inv(iommu->cap)) - return iommu->flush.flush_iotlb(iommu, did, 0, 0, - DMA_TLB_DSI_FLUSH, - non_present_entry_flush); - /* + * Fallback to domain selective flush if no PSI support or the size is + * too big. * PSI requires page size to be 2 ^ x, and the base address is naturally * aligned to the size */ - mask = ilog2(__roundup_pow_of_two(pages)); - /* Fallback to domain selective flush if size is too big */ - if (mask > cap_max_amask_val(iommu->cap)) - return iommu->flush.flush_iotlb(iommu, did, 0, 0, - DMA_TLB_DSI_FLUSH, non_present_entry_flush); - - return iommu->flush.flush_iotlb(iommu, did, addr, mask, - DMA_TLB_PSI_FLUSH, - non_present_entry_flush); + if (!cap_pgsel_inv(iommu->cap) || mask > cap_max_amask_val(iommu->cap)) + iommu->flush.flush_iotlb(iommu, did, 0, 0, + DMA_TLB_DSI_FLUSH); + else + iommu->flush.flush_iotlb(iommu, did, addr, mask, + DMA_TLB_PSI_FLUSH); + if (did) + iommu_flush_dev_iotlb(iommu->domains[did], addr, mask); } static void iommu_disable_protect_mem_regions(struct intel_iommu *iommu) @@ -1021,13 +1082,13 @@ static int iommu_enable_translation(struct intel_iommu *iommu) unsigned long flags; spin_lock_irqsave(&iommu->register_lock, flags); - writel(iommu->gcmd|DMA_GCMD_TE, iommu->reg + DMAR_GCMD_REG); + iommu->gcmd |= DMA_GCMD_TE; + writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG); /* Make sure hardware complete it */ IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, - readl, (sts & DMA_GSTS_TES), sts); + readl, (sts & DMA_GSTS_TES), sts); - iommu->gcmd |= DMA_GCMD_TE; spin_unlock_irqrestore(&iommu->register_lock, flags); return 0; } @@ -1043,7 +1104,7 @@ static int iommu_disable_translation(struct intel_iommu *iommu) /* Make sure hardware complete it */ IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, - readl, (!(sts & DMA_GSTS_TES)), sts); + readl, (!(sts & DMA_GSTS_TES)), sts); spin_unlock_irqrestore(&iommu->register_lock, flag); return 0; @@ -1142,48 +1203,71 @@ void free_dmar_iommu(struct intel_iommu *iommu) free_context_table(iommu); } -static struct dmar_domain * iommu_alloc_domain(struct intel_iommu *iommu) +static struct dmar_domain *alloc_domain(void) { - unsigned long num; - unsigned long ndomains; struct dmar_domain *domain; - unsigned long flags; domain = alloc_domain_mem(); if (!domain) return NULL; - ndomains = cap_ndoms(iommu->cap); - - spin_lock_irqsave(&iommu->lock, flags); - num = find_first_zero_bit(iommu->domain_ids, ndomains); - if (num >= ndomains) { - spin_unlock_irqrestore(&iommu->lock, flags); - free_domain_mem(domain); - printk(KERN_ERR "IOMMU: no free domain ids\n"); - return NULL; - } - - set_bit(num, iommu->domain_ids); - domain->id = num; memset(&domain->iommu_bmp, 0, sizeof(unsigned long)); - set_bit(iommu->seq_id, &domain->iommu_bmp); domain->flags = 0; - iommu->domains[num] = domain; - spin_unlock_irqrestore(&iommu->lock, flags); return domain; } -static void iommu_free_domain(struct dmar_domain *domain) +static int iommu_attach_domain(struct dmar_domain *domain, + struct intel_iommu *iommu) { + int num; + unsigned long ndomains; unsigned long flags; - struct intel_iommu *iommu; - iommu = domain_get_iommu(domain); + ndomains = cap_ndoms(iommu->cap); spin_lock_irqsave(&iommu->lock, flags); - clear_bit(domain->id, iommu->domain_ids); + + num = find_first_zero_bit(iommu->domain_ids, ndomains); + if (num >= ndomains) { + spin_unlock_irqrestore(&iommu->lock, flags); + printk(KERN_ERR "IOMMU: no free domain ids\n"); + return -ENOMEM; + } + + domain->id = num; + set_bit(num, iommu->domain_ids); + set_bit(iommu->seq_id, &domain->iommu_bmp); + iommu->domains[num] = domain; + spin_unlock_irqrestore(&iommu->lock, flags); + + return 0; +} + +static void iommu_detach_domain(struct dmar_domain *domain, + struct intel_iommu *iommu) +{ + unsigned long flags; + int num, ndomains; + int found = 0; + + spin_lock_irqsave(&iommu->lock, flags); + ndomains = cap_ndoms(iommu->cap); + num = find_first_bit(iommu->domain_ids, ndomains); + for (; num < ndomains; ) { + if (iommu->domains[num] == domain) { + found = 1; + break; + } + num = find_next_bit(iommu->domain_ids, + cap_ndoms(iommu->cap), num+1); + } + + if (found) { + clear_bit(num, iommu->domain_ids); + clear_bit(iommu->seq_id, &domain->iommu_bmp); + iommu->domains[num] = NULL; + } spin_unlock_irqrestore(&iommu->lock, flags); } @@ -1303,6 +1387,8 @@ static int domain_init(struct dmar_domain *domain, int guest_width) static void domain_exit(struct dmar_domain *domain) { + struct dmar_drhd_unit *drhd; + struct intel_iommu *iommu; u64 end; /* Domain 0 is reserved, so dont process it */ @@ -1321,12 +1407,15 @@ static void domain_exit(struct dmar_domain *domain) /* free page tables */ dma_pte_free_pagetable(domain, 0, end); - iommu_free_domain(domain); + for_each_active_iommu(iommu, drhd) + if (test_bit(iommu->seq_id, &domain->iommu_bmp)) + iommu_detach_domain(domain, iommu); + free_domain_mem(domain); } -static int domain_context_mapping_one(struct dmar_domain *domain, - int segment, u8 bus, u8 devfn) +static int domain_context_mapping_one(struct dmar_domain *domain, int segment, + u8 bus, u8 devfn, int translation) { struct context_entry *context; unsigned long flags; @@ -1336,10 +1425,14 @@ static int domain_context_mapping_one(struct dmar_domain *domain, unsigned long ndomains; int id; int agaw; + struct device_domain_info *info = NULL; pr_debug("Set context mapping for %02x:%02x.%d\n", bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); + BUG_ON(!domain->pgd); + BUG_ON(translation != CONTEXT_TT_PASS_THROUGH && + translation != CONTEXT_TT_MULTI_LEVEL); iommu = device_to_iommu(segment, bus, devfn); if (!iommu) @@ -1357,7 +1450,8 @@ static int domain_context_mapping_one(struct dmar_domain *domain, id = domain->id; pgd = domain->pgd; - if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) { + if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE || + domain->flags & DOMAIN_FLAG_STATIC_IDENTITY) { int found = 0; /* find an available domain id for this device in iommu */ @@ -1382,6 +1476,7 @@ static int domain_context_mapping_one(struct dmar_domain *domain, } set_bit(num, iommu->domain_ids); + set_bit(iommu->seq_id, &domain->iommu_bmp); iommu->domains[num] = domain; id = num; } @@ -1399,21 +1494,44 @@ static int domain_context_mapping_one(struct dmar_domain *domain, } context_set_domain_id(context, id); - context_set_address_width(context, iommu->agaw); - context_set_address_root(context, virt_to_phys(pgd)); - context_set_translation_type(context, CONTEXT_TT_MULTI_LEVEL); + + if (translation != CONTEXT_TT_PASS_THROUGH) { + info = iommu_support_dev_iotlb(domain, segment, bus, devfn); + translation = info ? CONTEXT_TT_DEV_IOTLB : + CONTEXT_TT_MULTI_LEVEL; + } + /* + * In pass through mode, AW must be programmed to indicate the largest + * AGAW value supported by hardware. And ASR is ignored by hardware. + */ + if (unlikely(translation == CONTEXT_TT_PASS_THROUGH)) + context_set_address_width(context, iommu->msagaw); + else { + context_set_address_root(context, virt_to_phys(pgd)); + context_set_address_width(context, iommu->agaw); + } + + context_set_translation_type(context, translation); context_set_fault_enable(context); context_set_present(context); domain_flush_cache(domain, context, sizeof(*context)); - /* it's a non-present to present mapping */ - if (iommu->flush.flush_context(iommu, domain->id, - (((u16)bus) << 8) | devfn, DMA_CCMD_MASK_NOBIT, - DMA_CCMD_DEVICE_INVL, 1)) + /* + * It's a non-present to present mapping. If hardware doesn't cache + * non-present entry we only need to flush the write-buffer. If the + * _does_ cache non-present entries, then it does so in the special + * domain #0, which we have to flush: + */ + if (cap_caching_mode(iommu->cap)) { + iommu->flush.flush_context(iommu, 0, + (((u16)bus) << 8) | devfn, + DMA_CCMD_MASK_NOBIT, + DMA_CCMD_DEVICE_INVL); + iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_DSI_FLUSH); + } else { iommu_flush_write_buffer(iommu); - else - iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_DSI_FLUSH, 0); - + } + iommu_enable_dev_iotlb(info); spin_unlock_irqrestore(&iommu->lock, flags); spin_lock_irqsave(&domain->iommu_lock, flags); @@ -1426,13 +1544,15 @@ static int domain_context_mapping_one(struct dmar_domain *domain, } static int -domain_context_mapping(struct dmar_domain *domain, struct pci_dev *pdev) +domain_context_mapping(struct dmar_domain *domain, struct pci_dev *pdev, + int translation) { int ret; struct pci_dev *tmp, *parent; ret = domain_context_mapping_one(domain, pci_domain_nr(pdev->bus), - pdev->bus->number, pdev->devfn); + pdev->bus->number, pdev->devfn, + translation); if (ret) return ret; @@ -1446,7 +1566,7 @@ domain_context_mapping(struct dmar_domain *domain, struct pci_dev *pdev) ret = domain_context_mapping_one(domain, pci_domain_nr(parent->bus), parent->bus->number, - parent->devfn); + parent->devfn, translation); if (ret) return ret; parent = parent->bus->self; @@ -1454,12 +1574,14 @@ domain_context_mapping(struct dmar_domain *domain, struct pci_dev *pdev) if (tmp->is_pcie) /* this is a PCIE-to-PCI bridge */ return domain_context_mapping_one(domain, pci_domain_nr(tmp->subordinate), - tmp->subordinate->number, 0); + tmp->subordinate->number, 0, + translation); else /* this is a legacy PCI bridge */ return domain_context_mapping_one(domain, pci_domain_nr(tmp->bus), tmp->bus->number, - tmp->devfn); + tmp->devfn, + translation); } static int domain_context_mapped(struct pci_dev *pdev) @@ -1540,9 +1662,8 @@ static void iommu_detach_dev(struct intel_iommu *iommu, u8 bus, u8 devfn) clear_context_table(iommu, bus, devfn); iommu->flush.flush_context(iommu, 0, 0, 0, - DMA_CCMD_GLOBAL_INVL, 0); - iommu->flush.flush_iotlb(iommu, 0, 0, 0, - DMA_TLB_GLOBAL_FLUSH, 0); + DMA_CCMD_GLOBAL_INVL); + iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH); } static void domain_remove_dev_info(struct dmar_domain *domain) @@ -1561,6 +1682,7 @@ static void domain_remove_dev_info(struct dmar_domain *domain) info->dev->dev.archdata.iommu = NULL; spin_unlock_irqrestore(&device_domain_lock, flags); + iommu_disable_dev_iotlb(info); iommu = device_to_iommu(info->segment, info->bus, info->devfn); iommu_detach_dev(iommu, info->bus, info->devfn); free_devinfo_mem(info); @@ -1597,6 +1719,7 @@ static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw) unsigned long flags; int bus = 0, devfn = 0; int segment; + int ret; domain = find_domain(pdev); if (domain) @@ -1629,6 +1752,10 @@ static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw) } } + domain = alloc_domain(); + if (!domain) + goto error; + /* Allocate new domain for the device */ drhd = dmar_find_matched_drhd_unit(pdev); if (!drhd) { @@ -1638,9 +1765,11 @@ static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw) } iommu = drhd->iommu; - domain = iommu_alloc_domain(iommu); - if (!domain) + ret = iommu_attach_domain(domain, iommu); + if (ret) { + domain_exit(domain); goto error; + } if (domain_init(domain, gaw)) { domain_exit(domain); @@ -1714,6 +1843,8 @@ error: return find_domain(pdev); } +static int iommu_identity_mapping; + static int iommu_prepare_identity_map(struct pci_dev *pdev, unsigned long long start, unsigned long long end) @@ -1726,8 +1857,11 @@ static int iommu_prepare_identity_map(struct pci_dev *pdev, printk(KERN_INFO "IOMMU: Setting identity map for device %s [0x%Lx - 0x%Lx]\n", pci_name(pdev), start, end); - /* page table init */ - domain = get_domain_for_dev(pdev, DEFAULT_DOMAIN_ADDRESS_WIDTH); + if (iommu_identity_mapping) + domain = si_domain; + else + /* page table init */ + domain = get_domain_for_dev(pdev, DEFAULT_DOMAIN_ADDRESS_WIDTH); if (!domain) return -ENOMEM; @@ -1756,7 +1890,7 @@ static int iommu_prepare_identity_map(struct pci_dev *pdev, goto error; /* context entry init */ - ret = domain_context_mapping(domain, pdev); + ret = domain_context_mapping(domain, pdev, CONTEXT_TT_MULTI_LEVEL); if (!ret) return 0; error: @@ -1857,13 +1991,141 @@ static inline void iommu_prepare_isa(void) } #endif /* !CONFIG_DMAR_FLPY_WA */ -static int __init init_dmars(void) +/* Initialize each context entry as pass through.*/ +static int __init init_context_pass_through(void) +{ + struct pci_dev *pdev = NULL; + struct dmar_domain *domain; + int ret; + + for_each_pci_dev(pdev) { + domain = get_domain_for_dev(pdev, DEFAULT_DOMAIN_ADDRESS_WIDTH); + ret = domain_context_mapping(domain, pdev, + CONTEXT_TT_PASS_THROUGH); + if (ret) + return ret; + } + return 0; +} + +static int md_domain_init(struct dmar_domain *domain, int guest_width); +static int si_domain_init(void) +{ + struct dmar_drhd_unit *drhd; + struct intel_iommu *iommu; + int ret = 0; + + si_domain = alloc_domain(); + if (!si_domain) + return -EFAULT; + + + for_each_active_iommu(iommu, drhd) { + ret = iommu_attach_domain(si_domain, iommu); + if (ret) { + domain_exit(si_domain); + return -EFAULT; + } + } + + if (md_domain_init(si_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) { + domain_exit(si_domain); + return -EFAULT; + } + + si_domain->flags = DOMAIN_FLAG_STATIC_IDENTITY; + + return 0; +} + +static void domain_remove_one_dev_info(struct dmar_domain *domain, + struct pci_dev *pdev); +static int identity_mapping(struct pci_dev *pdev) +{ + struct device_domain_info *info; + + if (likely(!iommu_identity_mapping)) + return 0; + + + list_for_each_entry(info, &si_domain->devices, link) + if (info->dev == pdev) + return 1; + return 0; +} + +static int domain_add_dev_info(struct dmar_domain *domain, + struct pci_dev *pdev) +{ + struct device_domain_info *info; + unsigned long flags; + + info = alloc_devinfo_mem(); + if (!info) + return -ENOMEM; + + info->segment = pci_domain_nr(pdev->bus); + info->bus = pdev->bus->number; + info->devfn = pdev->devfn; + info->dev = pdev; + info->domain = domain; + + spin_lock_irqsave(&device_domain_lock, flags); + list_add(&info->link, &domain->devices); + list_add(&info->global, &device_domain_list); + pdev->dev.archdata.iommu = info; + spin_unlock_irqrestore(&device_domain_lock, flags); + + return 0; +} + +static int iommu_prepare_static_identity_mapping(void) +{ + int i; + struct pci_dev *pdev = NULL; + int ret; + + ret = si_domain_init(); + if (ret) + return -EFAULT; + + printk(KERN_INFO "IOMMU: Setting identity map:\n"); + for_each_pci_dev(pdev) { + for (i = 0; i < e820.nr_map; i++) { + struct e820entry *ei = &e820.map[i]; + + if (ei->type == E820_RAM) { + ret = iommu_prepare_identity_map(pdev, + ei->addr, ei->addr + ei->size); + if (ret) { + printk(KERN_INFO "1:1 mapping to one domain failed.\n"); + return -EFAULT; + } + } + } + ret = domain_add_dev_info(si_domain, pdev); + if (ret) + return ret; + } + + return 0; +} + +int __init init_dmars(void) { struct dmar_drhd_unit *drhd; struct dmar_rmrr_unit *rmrr; struct pci_dev *pdev; struct intel_iommu *iommu; int i, ret; + int pass_through = 1; + + /* + * In case pass through can not be enabled, iommu tries to use identity + * mapping. + */ + if (iommu_pass_through) + iommu_identity_mapping = 1; /* * for each drhd @@ -1917,7 +2179,15 @@ static int __init init_dmars(void) printk(KERN_ERR "IOMMU: allocate root entry failed\n"); goto error; } + if (!ecap_pass_through(iommu->ecap)) + pass_through = 0; } + if (iommu_pass_through) + if (!pass_through) { + printk(KERN_INFO + "Pass Through is not supported by hardware.\n"); + iommu_pass_through = 0; + } /* * Start from the sane iommu hardware state. @@ -1972,45 +2242,61 @@ static int __init init_dmars(void) } } -#ifdef CONFIG_INTR_REMAP - if (!intr_remapping_enabled) { - ret = enable_intr_remapping(0); - if (ret) - printk(KERN_ERR - "IOMMU: enable interrupt remapping failed\n"); - } -#endif - /* - * For each rmrr - * for each dev attached to rmrr - * do - * locate drhd for dev, alloc domain for dev - * allocate free domain - * allocate page table entries for rmrr - * if context not allocated for bus - * allocate and init context - * set present in root table for this bus - * init context with domain, translation etc - * endfor - * endfor + * If pass through is set and enabled, context entries of all pci + * devices are intialized by pass through translation type. */ - for_each_rmrr_units(rmrr) { - for (i = 0; i < rmrr->devices_cnt; i++) { - pdev = rmrr->devices[i]; - /* some BIOS lists non-exist devices in DMAR table */ - if (!pdev) - continue; - ret = iommu_prepare_rmrr_dev(rmrr, pdev); - if (ret) - printk(KERN_ERR - "IOMMU: mapping reserved region failed\n"); + if (iommu_pass_through) { + ret = init_context_pass_through(); + if (ret) { + printk(KERN_ERR "IOMMU: Pass through init failed.\n"); + iommu_pass_through = 0; } } - iommu_prepare_gfx_mapping(); + /* + * If pass through is not set or not enabled, setup context entries for + * identity mappings for rmrr, gfx, and isa and may fall back to static + * identity mapping if iommu_identity_mapping is set. + */ + if (!iommu_pass_through) { + if (iommu_identity_mapping) + iommu_prepare_static_identity_mapping(); + /* + * For each rmrr + * for each dev attached to rmrr + * do + * locate drhd for dev, alloc domain for dev + * allocate free domain + * allocate page table entries for rmrr + * if context not allocated for bus + * allocate and init context + * set present in root table for this bus + * init context with domain, translation etc + * endfor + * endfor + */ + printk(KERN_INFO "IOMMU: Setting RMRR:\n"); + for_each_rmrr_units(rmrr) { + for (i = 0; i < rmrr->devices_cnt; i++) { + pdev = rmrr->devices[i]; + /* + * some BIOS lists non-exist devices in DMAR + * table. + */ + if (!pdev) + continue; + ret = iommu_prepare_rmrr_dev(rmrr, pdev); + if (ret) + printk(KERN_ERR + "IOMMU: mapping reserved region failed\n"); + } + } - iommu_prepare_isa(); + iommu_prepare_gfx_mapping(); + + iommu_prepare_isa(); + } /* * for each drhd @@ -2032,10 +2318,8 @@ static int __init init_dmars(void) iommu_set_root_entry(iommu); - iommu->flush.flush_context(iommu, 0, 0, 0, DMA_CCMD_GLOBAL_INVL, - 0); - iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH, - 0); + iommu->flush.flush_context(iommu, 0, 0, 0, DMA_CCMD_GLOBAL_INVL); + iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH); iommu_disable_protect_mem_regions(iommu); ret = iommu_enable_translation(iommu); @@ -2121,7 +2405,8 @@ get_valid_domain_for_dev(struct pci_dev *pdev) /* make sure context mapping is ok */ if (unlikely(!domain_context_mapped(pdev))) { - ret = domain_context_mapping(domain, pdev); + ret = domain_context_mapping(domain, pdev, + CONTEXT_TT_MULTI_LEVEL); if (ret) { printk(KERN_ERR "Domain context map for %s failed", @@ -2133,6 +2418,52 @@ get_valid_domain_for_dev(struct pci_dev *pdev) return domain; } +static int iommu_dummy(struct pci_dev *pdev) +{ + return pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO; +} + +/* Check if the pdev needs to go through non-identity map and unmap process.*/ +static int iommu_no_mapping(struct pci_dev *pdev) +{ + int found; + + if (!iommu_identity_mapping) + return iommu_dummy(pdev); + + found = identity_mapping(pdev); + if (found) { + if (pdev->dma_mask > DMA_BIT_MASK(32)) + return 1; + else { + /* + * 32 bit DMA is removed from si_domain and fall back + * to non-identity mapping. + */ + domain_remove_one_dev_info(si_domain, pdev); + printk(KERN_INFO "32bit %s uses non-identity mapping\n", + pci_name(pdev)); + return 0; + } + } else { + /* + * In case of a detached 64 bit DMA device from vm, the device + * is put into si_domain for identity mapping. + */ + if (pdev->dma_mask > DMA_BIT_MASK(32)) { + int ret; + ret = domain_add_dev_info(si_domain, pdev); + if (!ret) { + printk(KERN_INFO "64bit %s uses identity mapping\n", + pci_name(pdev)); + return 1; + } + } + } + + return iommu_dummy(pdev); +} + static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr, size_t size, int dir, u64 dma_mask) { @@ -2145,7 +2476,8 @@ static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr, struct intel_iommu *iommu; BUG_ON(dir == DMA_NONE); - if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO) + + if (iommu_no_mapping(pdev)) return paddr; domain = get_valid_domain_for_dev(pdev); @@ -2182,10 +2514,11 @@ static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr, if (ret) goto error; - /* it's a non-present to present mapping */ - ret = iommu_flush_iotlb_psi(iommu, domain->id, - start_paddr, size >> VTD_PAGE_SHIFT, 1); - if (ret) + /* it's a non-present to present mapping. Only flush if caching mode */ + if (cap_caching_mode(iommu->cap)) + iommu_flush_iotlb_psi(iommu, 0, start_paddr, + size >> VTD_PAGE_SHIFT); + else iommu_flush_write_buffer(iommu); return start_paddr + ((u64)paddr & (~PAGE_MASK)); @@ -2219,15 +2552,22 @@ static void flush_unmaps(void) if (!iommu) continue; - if (deferred_flush[i].next) { - iommu->flush.flush_iotlb(iommu, 0, 0, 0, - DMA_TLB_GLOBAL_FLUSH, 0); - for (j = 0; j < deferred_flush[i].next; j++) { - __free_iova(&deferred_flush[i].domain[j]->iovad, - deferred_flush[i].iova[j]); - } - deferred_flush[i].next = 0; + if (!deferred_flush[i].next) + continue; + + iommu->flush.flush_iotlb(iommu, 0, 0, 0, + DMA_TLB_GLOBAL_FLUSH); + for (j = 0; j < deferred_flush[i].next; j++) { + unsigned long mask; + struct iova *iova = deferred_flush[i].iova[j]; + + mask = (iova->pfn_hi - iova->pfn_lo + 1) << PAGE_SHIFT; + mask = ilog2(mask >> VTD_PAGE_SHIFT); + iommu_flush_dev_iotlb(deferred_flush[i].domain[j], + iova->pfn_lo << PAGE_SHIFT, mask); + __free_iova(&deferred_flush[i].domain[j]->iovad, iova); } + deferred_flush[i].next = 0; } list_size = 0; @@ -2278,8 +2618,9 @@ static void intel_unmap_page(struct device *dev, dma_addr_t dev_addr, struct iova *iova; struct intel_iommu *iommu; - if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO) + if (iommu_no_mapping(pdev)) return; + domain = find_domain(pdev); BUG_ON(!domain); @@ -2300,9 +2641,8 @@ static void intel_unmap_page(struct device *dev, dma_addr_t dev_addr, /* free page tables */ dma_pte_free_pagetable(domain, start_addr, start_addr + size); if (intel_iommu_strict) { - if (iommu_flush_iotlb_psi(iommu, - domain->id, start_addr, size >> VTD_PAGE_SHIFT, 0)) - iommu_flush_write_buffer(iommu); + iommu_flush_iotlb_psi(iommu, domain->id, start_addr, + size >> VTD_PAGE_SHIFT); /* free iova */ __free_iova(&domain->iovad, iova); } else { @@ -2370,7 +2710,7 @@ static void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist, struct scatterlist *sg; struct intel_iommu *iommu; - if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO) + if (iommu_no_mapping(pdev)) return; domain = find_domain(pdev); @@ -2393,9 +2733,8 @@ static void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist, /* free page tables */ dma_pte_free_pagetable(domain, start_addr, start_addr + size); - if (iommu_flush_iotlb_psi(iommu, domain->id, start_addr, - size >> VTD_PAGE_SHIFT, 0)) - iommu_flush_write_buffer(iommu); + iommu_flush_iotlb_psi(iommu, domain->id, start_addr, + size >> VTD_PAGE_SHIFT); /* free iova */ __free_iova(&domain->iovad, iova); @@ -2432,7 +2771,7 @@ static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int ne struct intel_iommu *iommu; BUG_ON(dir == DMA_NONE); - if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO) + if (iommu_no_mapping(pdev)) return intel_nontranslate_map_sg(hwdev, sglist, nelems, dir); domain = get_valid_domain_for_dev(pdev); @@ -2487,10 +2826,13 @@ static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int ne offset += size; } - /* it's a non-present to present mapping */ - if (iommu_flush_iotlb_psi(iommu, domain->id, - start_addr, offset >> VTD_PAGE_SHIFT, 1)) + /* it's a non-present to present mapping. Only flush if caching mode */ + if (cap_caching_mode(iommu->cap)) + iommu_flush_iotlb_psi(iommu, 0, start_addr, + offset >> VTD_PAGE_SHIFT); + else iommu_flush_write_buffer(iommu); + return nelems; } @@ -2649,9 +2991,9 @@ static int init_iommu_hw(void) iommu_set_root_entry(iommu); iommu->flush.flush_context(iommu, 0, 0, 0, - DMA_CCMD_GLOBAL_INVL, 0); + DMA_CCMD_GLOBAL_INVL); iommu->flush.flush_iotlb(iommu, 0, 0, 0, - DMA_TLB_GLOBAL_FLUSH, 0); + DMA_TLB_GLOBAL_FLUSH); iommu_disable_protect_mem_regions(iommu); iommu_enable_translation(iommu); } @@ -2666,9 +3008,9 @@ static void iommu_flush_all(void) for_each_active_iommu(iommu, drhd) { iommu->flush.flush_context(iommu, 0, 0, 0, - DMA_CCMD_GLOBAL_INVL, 0); + DMA_CCMD_GLOBAL_INVL); iommu->flush.flush_iotlb(iommu, 0, 0, 0, - DMA_TLB_GLOBAL_FLUSH, 0); + DMA_TLB_GLOBAL_FLUSH); } } @@ -2791,7 +3133,7 @@ int __init intel_iommu_init(void) * Check the need for DMA-remapping initialization now. * Above initialization will also be used by Interrupt-remapping. */ - if (no_iommu || swiotlb || dmar_disabled) + if (no_iommu || (swiotlb && !iommu_pass_through) || dmar_disabled) return -ENODEV; iommu_init_mempool(); @@ -2811,7 +3153,15 @@ int __init intel_iommu_init(void) init_timer(&unmap_timer); force_iommu = 1; - dma_ops = &intel_dma_ops; + + if (!iommu_pass_through) { + printk(KERN_INFO + "Multi-level page-table translation for DMAR.\n"); + dma_ops = &intel_dma_ops; + } else + printk(KERN_INFO + "DMAR: Pass through translation for DMAR.\n"); + init_iommu_sysfs(); register_iommu(&intel_iommu_ops); @@ -2819,31 +3169,6 @@ int __init intel_iommu_init(void) return 0; } -static int vm_domain_add_dev_info(struct dmar_domain *domain, - struct pci_dev *pdev) -{ - struct device_domain_info *info; - unsigned long flags; - - info = alloc_devinfo_mem(); - if (!info) - return -ENOMEM; - - info->segment = pci_domain_nr(pdev->bus); - info->bus = pdev->bus->number; - info->devfn = pdev->devfn; - info->dev = pdev; - info->domain = domain; - - spin_lock_irqsave(&device_domain_lock, flags); - list_add(&info->link, &domain->devices); - list_add(&info->global, &device_domain_list); - pdev->dev.archdata.iommu = info; - spin_unlock_irqrestore(&device_domain_lock, flags); - - return 0; -} - static void iommu_detach_dependent_devices(struct intel_iommu *iommu, struct pci_dev *pdev) { @@ -2871,7 +3196,7 @@ static void iommu_detach_dependent_devices(struct intel_iommu *iommu, } } -static void vm_domain_remove_one_dev_info(struct dmar_domain *domain, +static void domain_remove_one_dev_info(struct dmar_domain *domain, struct pci_dev *pdev) { struct device_domain_info *info; @@ -2897,6 +3222,7 @@ static void vm_domain_remove_one_dev_info(struct dmar_domain *domain, info->dev->dev.archdata.iommu = NULL; spin_unlock_irqrestore(&device_domain_lock, flags); + iommu_disable_dev_iotlb(info); iommu_detach_dev(iommu, info->bus, info->devfn); iommu_detach_dependent_devices(iommu, pdev); free_devinfo_mem(info); @@ -2947,6 +3273,7 @@ static void vm_domain_remove_all_dev_info(struct dmar_domain *domain) spin_unlock_irqrestore(&device_domain_lock, flags1); + iommu_disable_dev_iotlb(info); iommu = device_to_iommu(info->segment, info->bus, info->devfn); iommu_detach_dev(iommu, info->bus, info->devfn); iommu_detach_dependent_devices(iommu, info->dev); @@ -3002,7 +3329,7 @@ static struct dmar_domain *iommu_alloc_vm_domain(void) return domain; } -static int vm_domain_init(struct dmar_domain *domain, int guest_width) +static int md_domain_init(struct dmar_domain *domain, int guest_width) { int adjust_width; @@ -3093,7 +3420,7 @@ static int intel_iommu_domain_init(struct iommu_domain *domain) "intel_iommu_domain_init: dmar_domain == NULL\n"); return -ENOMEM; } - if (vm_domain_init(dmar_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) { + if (md_domain_init(dmar_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) { printk(KERN_ERR "intel_iommu_domain_init() failed\n"); vm_domain_exit(dmar_domain); @@ -3128,8 +3455,9 @@ static int intel_iommu_attach_device(struct iommu_domain *domain, old_domain = find_domain(pdev); if (old_domain) { - if (dmar_domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) - vm_domain_remove_one_dev_info(old_domain, pdev); + if (dmar_domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE || + dmar_domain->flags & DOMAIN_FLAG_STATIC_IDENTITY) + domain_remove_one_dev_info(old_domain, pdev); else domain_remove_dev_info(old_domain); } @@ -3151,11 +3479,11 @@ static int intel_iommu_attach_device(struct iommu_domain *domain, return -EFAULT; } - ret = domain_context_mapping(dmar_domain, pdev); + ret = domain_add_dev_info(dmar_domain, pdev); if (ret) return ret; - ret = vm_domain_add_dev_info(dmar_domain, pdev); + ret = domain_context_mapping(dmar_domain, pdev, CONTEXT_TT_MULTI_LEVEL); return ret; } @@ -3165,7 +3493,7 @@ static void intel_iommu_detach_device(struct iommu_domain *domain, struct dmar_domain *dmar_domain = domain->priv; struct pci_dev *pdev = to_pci_dev(dev); - vm_domain_remove_one_dev_info(dmar_domain, pdev); + domain_remove_one_dev_info(dmar_domain, pdev); } static int intel_iommu_map_range(struct iommu_domain *domain, diff --git a/drivers/pci/intr_remapping.c b/drivers/pci/intr_remapping.c index f5e0ea724a6f..4f5b8712931f 100644 --- a/drivers/pci/intr_remapping.c +++ b/drivers/pci/intr_remapping.c @@ -10,11 +10,21 @@ #include #include "intr_remapping.h" #include +#include +#include "pci.h" static struct ioapic_scope ir_ioapic[MAX_IO_APICS]; static int ir_ioapic_num; int intr_remapping_enabled; +static int disable_intremap; +static __init int setup_nointremap(char *str) +{ + disable_intremap = 1; + return 0; +} +early_param("nointremap", setup_nointremap); + struct irq_2_iommu { struct intel_iommu *iommu; u16 irte_index; @@ -23,15 +33,12 @@ struct irq_2_iommu { }; #ifdef CONFIG_GENERIC_HARDIRQS -static struct irq_2_iommu *get_one_free_irq_2_iommu(int cpu) +static struct irq_2_iommu *get_one_free_irq_2_iommu(int node) { struct irq_2_iommu *iommu; - int node; - - node = cpu_to_node(cpu); iommu = kzalloc_node(sizeof(*iommu), GFP_ATOMIC, node); - printk(KERN_DEBUG "alloc irq_2_iommu on cpu %d node %d\n", cpu, node); + printk(KERN_DEBUG "alloc irq_2_iommu on node %d\n", node); return iommu; } @@ -48,7 +55,7 @@ static struct irq_2_iommu *irq_2_iommu(unsigned int irq) return desc->irq_2_iommu; } -static struct irq_2_iommu *irq_2_iommu_alloc_cpu(unsigned int irq, int cpu) +static struct irq_2_iommu *irq_2_iommu_alloc_node(unsigned int irq, int node) { struct irq_desc *desc; struct irq_2_iommu *irq_iommu; @@ -56,7 +63,7 @@ static struct irq_2_iommu *irq_2_iommu_alloc_cpu(unsigned int irq, int cpu) /* * alloc irq desc if not allocated already. */ - desc = irq_to_desc_alloc_cpu(irq, cpu); + desc = irq_to_desc_alloc_node(irq, node); if (!desc) { printk(KERN_INFO "can not get irq_desc for %d\n", irq); return NULL; @@ -65,14 +72,14 @@ static struct irq_2_iommu *irq_2_iommu_alloc_cpu(unsigned int irq, int cpu) irq_iommu = desc->irq_2_iommu; if (!irq_iommu) - desc->irq_2_iommu = get_one_free_irq_2_iommu(cpu); + desc->irq_2_iommu = get_one_free_irq_2_iommu(node); return desc->irq_2_iommu; } static struct irq_2_iommu *irq_2_iommu_alloc(unsigned int irq) { - return irq_2_iommu_alloc_cpu(irq, boot_cpu_id); + return irq_2_iommu_alloc_node(irq, cpu_to_node(boot_cpu_id)); } #else /* !CONFIG_SPARSE_IRQ */ @@ -309,7 +316,8 @@ int modify_irte(int irq, struct irte *irte_modified) index = irq_iommu->irte_index + irq_iommu->sub_handle; irte = &iommu->ir_table->base[index]; - set_64bit((unsigned long *)irte, irte_modified->low); + set_64bit((unsigned long *)&irte->low, irte_modified->low); + set_64bit((unsigned long *)&irte->high, irte_modified->high); __iommu_flush_cache(iommu, irte, sizeof(*irte)); rc = qi_flush_iec(iommu, index, 0); @@ -364,12 +372,32 @@ struct intel_iommu *map_dev_to_ir(struct pci_dev *dev) return drhd->iommu; } +static int clear_entries(struct irq_2_iommu *irq_iommu) +{ + struct irte *start, *entry, *end; + struct intel_iommu *iommu; + int index; + + if (irq_iommu->sub_handle) + return 0; + + iommu = irq_iommu->iommu; + index = irq_iommu->irte_index + irq_iommu->sub_handle; + + start = iommu->ir_table->base + index; + end = start + (1 << irq_iommu->irte_mask); + + for (entry = start; entry < end; entry++) { + set_64bit((unsigned long *)&entry->low, 0); + set_64bit((unsigned long *)&entry->high, 0); + } + + return qi_flush_iec(iommu, index, irq_iommu->irte_mask); +} + int free_irte(int irq) { int rc = 0; - int index, i; - struct irte *irte; - struct intel_iommu *iommu; struct irq_2_iommu *irq_iommu; unsigned long flags; @@ -380,16 +408,7 @@ int free_irte(int irq) return -1; } - iommu = irq_iommu->iommu; - - index = irq_iommu->irte_index + irq_iommu->sub_handle; - irte = &iommu->ir_table->base[index]; - - if (!irq_iommu->sub_handle) { - for (i = 0; i < (1 << irq_iommu->irte_mask); i++) - set_64bit((unsigned long *)(irte + i), 0); - rc = qi_flush_iec(iommu, index, irq_iommu->irte_mask); - } + rc = clear_entries(irq_iommu); irq_iommu->iommu = NULL; irq_iommu->irte_index = 0; @@ -401,10 +420,95 @@ int free_irte(int irq) return rc; } +/* + * source validation type + */ +#define SVT_NO_VERIFY 0x0 /* no verification is required */ +#define SVT_VERIFY_SID_SQ 0x1 /* verify using SID and SQ fiels */ +#define SVT_VERIFY_BUS 0x2 /* verify bus of request-id */ + +/* + * source-id qualifier + */ +#define SQ_ALL_16 0x0 /* verify all 16 bits of request-id */ +#define SQ_13_IGNORE_1 0x1 /* verify most significant 13 bits, ignore + * the third least significant bit + */ +#define SQ_13_IGNORE_2 0x2 /* verify most significant 13 bits, ignore + * the second and third least significant bits + */ +#define SQ_13_IGNORE_3 0x3 /* verify most significant 13 bits, ignore + * the least three significant bits + */ + +/* + * set SVT, SQ and SID fields of irte to verify + * source ids of interrupt requests + */ +static void set_irte_sid(struct irte *irte, unsigned int svt, + unsigned int sq, unsigned int sid) +{ + irte->svt = svt; + irte->sq = sq; + irte->sid = sid; +} + +int set_ioapic_sid(struct irte *irte, int apic) +{ + int i; + u16 sid = 0; + + if (!irte) + return -1; + + for (i = 0; i < MAX_IO_APICS; i++) { + if (ir_ioapic[i].id == apic) { + sid = (ir_ioapic[i].bus << 8) | ir_ioapic[i].devfn; + break; + } + } + + if (sid == 0) { + pr_warning("Failed to set source-id of IOAPIC (%d)\n", apic); + return -1; + } + + set_irte_sid(irte, 1, 0, sid); + + return 0; +} + +int set_msi_sid(struct irte *irte, struct pci_dev *dev) +{ + struct pci_dev *bridge; + + if (!irte || !dev) + return -1; + + /* PCIe device or Root Complex integrated PCI device */ + if (dev->is_pcie || !dev->bus->parent) { + set_irte_sid(irte, SVT_VERIFY_SID_SQ, SQ_ALL_16, + (dev->bus->number << 8) | dev->devfn); + return 0; + } + + bridge = pci_find_upstream_pcie_bridge(dev); + if (bridge) { + if (bridge->is_pcie) /* this is a PCIE-to-PCI/PCIX bridge */ + set_irte_sid(irte, SVT_VERIFY_BUS, SQ_ALL_16, + (bridge->bus->number << 8) | dev->bus->number); + else /* this is a legacy PCI bridge */ + set_irte_sid(irte, SVT_VERIFY_SID_SQ, SQ_ALL_16, + (bridge->bus->number << 8) | bridge->devfn); + } + + return 0; +} + static void iommu_set_intr_remapping(struct intel_iommu *iommu, int mode) { u64 addr; - u32 cmd, sts; + u32 sts; unsigned long flags; addr = virt_to_phys((void *)iommu->ir_table->base); @@ -415,28 +519,13 @@ static void iommu_set_intr_remapping(struct intel_iommu *iommu, int mode) (addr) | IR_X2APIC_MODE(mode) | INTR_REMAP_TABLE_REG_SIZE); /* Set interrupt-remapping table pointer */ - cmd = iommu->gcmd | DMA_GCMD_SIRTP; iommu->gcmd |= DMA_GCMD_SIRTP; - writel(cmd, iommu->reg + DMAR_GCMD_REG); + writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG); IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, readl, (sts & DMA_GSTS_IRTPS), sts); spin_unlock_irqrestore(&iommu->register_lock, flags); - if (mode == 0) { - spin_lock_irqsave(&iommu->register_lock, flags); - - /* enable comaptiblity format interrupt pass through */ - cmd = iommu->gcmd | DMA_GCMD_CFI; - iommu->gcmd |= DMA_GCMD_CFI; - writel(cmd, iommu->reg + DMAR_GCMD_REG); - - IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, - readl, (sts & DMA_GSTS_CFIS), sts); - - spin_unlock_irqrestore(&iommu->register_lock, flags); - } - /* * global invalidation of interrupt entry cache before enabling * interrupt-remapping. @@ -446,9 +535,8 @@ static void iommu_set_intr_remapping(struct intel_iommu *iommu, int mode) spin_lock_irqsave(&iommu->register_lock, flags); /* Enable interrupt-remapping */ - cmd = iommu->gcmd | DMA_GCMD_IRE; iommu->gcmd |= DMA_GCMD_IRE; - writel(cmd, iommu->reg + DMAR_GCMD_REG); + writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG); IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, readl, (sts & DMA_GSTS_IRES), sts); @@ -516,6 +604,23 @@ end: spin_unlock_irqrestore(&iommu->register_lock, flags); } +int __init intr_remapping_supported(void) +{ + struct dmar_drhd_unit *drhd; + + if (disable_intremap) + return 0; + + for_each_drhd_unit(drhd) { + struct intel_iommu *iommu = drhd->iommu; + + if (!ecap_ir_support(iommu->ecap)) + return 0; + } + + return 1; +} + int __init enable_intr_remapping(int eim) { struct dmar_drhd_unit *drhd; @@ -606,6 +711,35 @@ error: return -1; } +static void ir_parse_one_ioapic_scope(struct acpi_dmar_device_scope *scope, + struct intel_iommu *iommu) +{ + struct acpi_dmar_pci_path *path; + u8 bus; + int count; + + bus = scope->bus; + path = (struct acpi_dmar_pci_path *)(scope + 1); + count = (scope->length - sizeof(struct acpi_dmar_device_scope)) + / sizeof(struct acpi_dmar_pci_path); + + while (--count > 0) { + /* + * Access PCI directly due to the PCI + * subsystem isn't initialized yet. + */ + bus = read_pci_config_byte(bus, path->dev, path->fn, + PCI_SECONDARY_BUS); + path++; + } + + ir_ioapic[ir_ioapic_num].bus = bus; + ir_ioapic[ir_ioapic_num].devfn = PCI_DEVFN(path->dev, path->fn); + ir_ioapic[ir_ioapic_num].iommu = iommu; + ir_ioapic[ir_ioapic_num].id = scope->enumeration_id; + ir_ioapic_num++; +} + static int ir_parse_ioapic_scope(struct acpi_dmar_header *header, struct intel_iommu *iommu) { @@ -630,9 +764,7 @@ static int ir_parse_ioapic_scope(struct acpi_dmar_header *header, " 0x%Lx\n", scope->enumeration_id, drhd->address); - ir_ioapic[ir_ioapic_num].iommu = iommu; - ir_ioapic[ir_ioapic_num].id = scope->enumeration_id; - ir_ioapic_num++; + ir_parse_one_ioapic_scope(scope, iommu); } start += scope->length; } diff --git a/drivers/pci/intr_remapping.h b/drivers/pci/intr_remapping.h index ca48f0df8ac9..63a263c18415 100644 --- a/drivers/pci/intr_remapping.h +++ b/drivers/pci/intr_remapping.h @@ -3,6 +3,8 @@ struct ioapic_scope { struct intel_iommu *iommu; unsigned int id; + unsigned int bus; /* PCI bus number */ + unsigned int devfn; /* PCI devfn number */ }; #define IR_X2APIC_MODE(mode) (mode ? (1 << 11) : 0) diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index b497daab3d4a..e3a87210e947 100644 --- a/drivers/pci/iov.c +++ b/drivers/pci/iov.c @@ -5,6 +5,7 @@ * * PCI Express I/O Virtualization (IOV) support. * Single Root IOV 1.0 + * Address Translation Service 1.0 */ #include @@ -110,7 +111,7 @@ static int virtfn_add(struct pci_dev *dev, int id, int reset) } if (reset) - pci_execute_reset_function(virtfn); + __pci_reset_function(virtfn); pci_device_add(virtfn, virtfn->bus); mutex_unlock(&iov->dev->sriov->lock); @@ -164,7 +165,7 @@ static void virtfn_remove(struct pci_dev *dev, int id, int reset) if (reset) { device_release_driver(&virtfn->dev); - pci_execute_reset_function(virtfn); + __pci_reset_function(virtfn); } sprintf(buf, "virtfn%u", id); @@ -487,13 +488,15 @@ found: iov->self = dev; pci_read_config_dword(dev, pos + PCI_SRIOV_CAP, &iov->cap); pci_read_config_byte(dev, pos + PCI_SRIOV_FUNC_LINK, &iov->link); + if (dev->pcie_type == PCI_EXP_TYPE_RC_END) + iov->link = PCI_DEVFN(PCI_SLOT(dev->devfn), iov->link); if (pdev) iov->dev = pci_dev_get(pdev); - else { + else iov->dev = dev; - mutex_init(&iov->lock); - } + + mutex_init(&iov->lock); dev->sriov = iov; dev->is_physfn = 1; @@ -513,11 +516,11 @@ static void sriov_release(struct pci_dev *dev) { BUG_ON(dev->sriov->nr_virtfn); - if (dev == dev->sriov->dev) - mutex_destroy(&dev->sriov->lock); - else + if (dev != dev->sriov->dev) pci_dev_put(dev->sriov->dev); + mutex_destroy(&dev->sriov->lock); + kfree(dev->sriov); dev->sriov = NULL; } @@ -679,3 +682,145 @@ irqreturn_t pci_sriov_migration(struct pci_dev *dev) return sriov_migration(dev) ? IRQ_HANDLED : IRQ_NONE; } EXPORT_SYMBOL_GPL(pci_sriov_migration); + +static int ats_alloc_one(struct pci_dev *dev, int ps) +{ + int pos; + u16 cap; + struct pci_ats *ats; + + pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ATS); + if (!pos) + return -ENODEV; + + ats = kzalloc(sizeof(*ats), GFP_KERNEL); + if (!ats) + return -ENOMEM; + + ats->pos = pos; + ats->stu = ps; + pci_read_config_word(dev, pos + PCI_ATS_CAP, &cap); + ats->qdep = PCI_ATS_CAP_QDEP(cap) ? PCI_ATS_CAP_QDEP(cap) : + PCI_ATS_MAX_QDEP; + dev->ats = ats; + + return 0; +} + +static void ats_free_one(struct pci_dev *dev) +{ + kfree(dev->ats); + dev->ats = NULL; +} + +/** + * pci_enable_ats - enable the ATS capability + * @dev: the PCI device + * @ps: the IOMMU page shift + * + * Returns 0 on success, or negative on failure. + */ +int pci_enable_ats(struct pci_dev *dev, int ps) +{ + int rc; + u16 ctrl; + + BUG_ON(dev->ats && dev->ats->is_enabled); + + if (ps < PCI_ATS_MIN_STU) + return -EINVAL; + + if (dev->is_physfn || dev->is_virtfn) { + struct pci_dev *pdev = dev->is_physfn ? dev : dev->physfn; + + mutex_lock(&pdev->sriov->lock); + if (pdev->ats) + rc = pdev->ats->stu == ps ? 0 : -EINVAL; + else + rc = ats_alloc_one(pdev, ps); + + if (!rc) + pdev->ats->ref_cnt++; + mutex_unlock(&pdev->sriov->lock); + if (rc) + return rc; + } + + if (!dev->is_physfn) { + rc = ats_alloc_one(dev, ps); + if (rc) + return rc; + } + + ctrl = PCI_ATS_CTRL_ENABLE; + if (!dev->is_virtfn) + ctrl |= PCI_ATS_CTRL_STU(ps - PCI_ATS_MIN_STU); + pci_write_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, ctrl); + + dev->ats->is_enabled = 1; + + return 0; +} + +/** + * pci_disable_ats - disable the ATS capability + * @dev: the PCI device + */ +void pci_disable_ats(struct pci_dev *dev) +{ + u16 ctrl; + + BUG_ON(!dev->ats || !dev->ats->is_enabled); + + pci_read_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, &ctrl); + ctrl &= ~PCI_ATS_CTRL_ENABLE; + pci_write_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, ctrl); + + dev->ats->is_enabled = 0; + + if (dev->is_physfn || dev->is_virtfn) { + struct pci_dev *pdev = dev->is_physfn ? dev : dev->physfn; + + mutex_lock(&pdev->sriov->lock); + pdev->ats->ref_cnt--; + if (!pdev->ats->ref_cnt) + ats_free_one(pdev); + mutex_unlock(&pdev->sriov->lock); + } + + if (!dev->is_physfn) + ats_free_one(dev); +} + +/** + * pci_ats_queue_depth - query the ATS Invalidate Queue Depth + * @dev: the PCI device + * + * Returns the queue depth on success, or negative on failure. + * + * The ATS spec uses 0 in the Invalidate Queue Depth field to + * indicate that the function can accept 32 Invalidate Request. + * But here we use the `real' values (i.e. 1~32) for the Queue + * Depth; and 0 indicates the function shares the Queue with + * other functions (doesn't exclusively own a Queue). + */ +int pci_ats_queue_depth(struct pci_dev *dev) +{ + int pos; + u16 cap; + + if (dev->is_virtfn) + return 0; + + if (dev->ats) + return dev->ats->qdep; + + pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ATS); + if (!pos) + return -ENODEV; + + pci_read_config_word(dev, pos + PCI_ATS_CAP, &cap); + + return PCI_ATS_CAP_QDEP(cap) ? PCI_ATS_CAP_QDEP(cap) : + PCI_ATS_MAX_QDEP; +} diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 362773247fbf..d9f06fbfa0bf 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -75,22 +75,17 @@ void arch_teardown_msi_irqs(struct pci_dev *dev) } #endif -static void __msi_set_enable(struct pci_dev *dev, int pos, int enable) +static void msi_set_enable(struct pci_dev *dev, int pos, int enable) { u16 control; - if (pos) { - pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control); - control &= ~PCI_MSI_FLAGS_ENABLE; - if (enable) - control |= PCI_MSI_FLAGS_ENABLE; - pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control); - } -} + BUG_ON(!pos); -static void msi_set_enable(struct pci_dev *dev, int enable) -{ - __msi_set_enable(dev, pci_find_capability(dev, PCI_CAP_ID_MSI), enable); + pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control); + control &= ~PCI_MSI_FLAGS_ENABLE; + if (enable) + control |= PCI_MSI_FLAGS_ENABLE; + pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control); } static void msix_set_enable(struct pci_dev *dev, int enable) @@ -131,9 +126,6 @@ static inline __attribute_const__ u32 msi_enabled_mask(u16 control) * mask all MSI interrupts by clearing the MSI enable bit does not work * reliably as devices without an INTx disable bit will then generate a * level IRQ which will never be cleared. - * - * Returns 1 if it succeeded in masking the interrupt and 0 if the device - * doesn't support MSI masking. */ static void msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag) { @@ -303,7 +295,7 @@ static void __pci_restore_msi_state(struct pci_dev *dev) pos = entry->msi_attrib.pos; pci_intx_for_msi(dev, 0); - msi_set_enable(dev, 0); + msi_set_enable(dev, pos, 0); write_msi_msg(dev->irq, &entry->msg); pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control); @@ -321,22 +313,22 @@ static void __pci_restore_msix_state(struct pci_dev *dev) if (!dev->msix_enabled) return; + BUG_ON(list_empty(&dev->msi_list)); + entry = list_entry(dev->msi_list.next, struct msi_desc, list); + pos = entry->msi_attrib.pos; + pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control); /* route the table */ pci_intx_for_msi(dev, 0); - msix_set_enable(dev, 0); + control |= PCI_MSIX_FLAGS_ENABLE | PCI_MSIX_FLAGS_MASKALL; + pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control); list_for_each_entry(entry, &dev->msi_list, list) { write_msi_msg(entry->irq, &entry->msg); msix_mask_irq(entry, entry->masked); } - BUG_ON(list_empty(&dev->msi_list)); - entry = list_entry(dev->msi_list.next, struct msi_desc, list); - pos = entry->msi_attrib.pos; - pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control); control &= ~PCI_MSIX_FLAGS_MASKALL; - control |= PCI_MSIX_FLAGS_ENABLE; pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control); } @@ -365,9 +357,9 @@ static int msi_capability_init(struct pci_dev *dev, int nvec) u16 control; unsigned mask; - msi_set_enable(dev, 0); /* Ensure msi is disabled as I set it up */ - pos = pci_find_capability(dev, PCI_CAP_ID_MSI); + msi_set_enable(dev, pos, 0); /* Disable MSI during set up */ + pci_read_config_word(dev, msi_control_reg(pos), &control); /* MSI Entry Initialization */ entry = alloc_msi_entry(dev); @@ -381,7 +373,7 @@ static int msi_capability_init(struct pci_dev *dev, int nvec) entry->msi_attrib.default_irq = dev->irq; /* Save IOAPIC IRQ */ entry->msi_attrib.pos = pos; - entry->mask_pos = msi_mask_bits_reg(pos, entry->msi_attrib.is_64); + entry->mask_pos = msi_mask_reg(pos, entry->msi_attrib.is_64); /* All MSIs are unmasked by default, Mask them all */ if (entry->msi_attrib.maskbit) pci_read_config_dword(dev, entry->mask_pos, &entry->masked); @@ -399,7 +391,7 @@ static int msi_capability_init(struct pci_dev *dev, int nvec) /* Set MSI enabled bits */ pci_intx_for_msi(dev, 0); - msi_set_enable(dev, 1); + msi_set_enable(dev, pos, 1); dev->msi_enabled = 1; dev->irq = entry->irq; @@ -427,11 +419,14 @@ static int msix_capability_init(struct pci_dev *dev, u8 bir; void __iomem *base; - msix_set_enable(dev, 0);/* Ensure msix is disabled as I set it up */ - pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); + pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control); + + /* Ensure MSI-X is disabled while it is set up */ + control &= ~PCI_MSIX_FLAGS_ENABLE; + pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control); + /* Request & Map MSI-X table region */ - pci_read_config_word(dev, msi_control_reg(pos), &control); nr_entries = multi_msix_capable(control); pci_read_config_dword(dev, msix_table_offset_reg(pos), &table_offset); @@ -442,7 +437,6 @@ static int msix_capability_init(struct pci_dev *dev, if (base == NULL) return -ENOMEM; - /* MSI-X Table Initialization */ for (i = 0; i < nvec; i++) { entry = alloc_msi_entry(dev); if (!entry) @@ -455,7 +449,6 @@ static int msix_capability_init(struct pci_dev *dev, entry->msi_attrib.default_irq = dev->irq; entry->msi_attrib.pos = pos; entry->mask_base = base; - msix_mask_irq(entry, 1); list_add_tail(&entry->list, &dev->msi_list); } @@ -480,22 +473,31 @@ static int msix_capability_init(struct pci_dev *dev, return ret; } + /* + * Some devices require MSI-X to be enabled before we can touch the + * MSI-X registers. We need to mask all the vectors to prevent + * interrupts coming in before they're fully set up. + */ + control |= PCI_MSIX_FLAGS_MASKALL | PCI_MSIX_FLAGS_ENABLE; + pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control); + i = 0; list_for_each_entry(entry, &dev->msi_list, list) { entries[i].vector = entry->irq; set_irq_msi(entry->irq, entry); + j = entries[i].entry; + entry->masked = readl(base + j * PCI_MSIX_ENTRY_SIZE + + PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET); + msix_mask_irq(entry, 1); i++; } - /* Set MSI-X enabled bits */ + + /* Set MSI-X enabled bits and unmask the function */ pci_intx_for_msi(dev, 0); - msix_set_enable(dev, 1); dev->msix_enabled = 1; - list_for_each_entry(entry, &dev->msi_list, list) { - int vector = entry->msi_attrib.entry_nr; - entry->masked = readl(base + vector * PCI_MSIX_ENTRY_SIZE + - PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET); - } + control &= ~PCI_MSIX_FLAGS_MASKALL; + pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control); return 0; } @@ -596,17 +598,20 @@ void pci_msi_shutdown(struct pci_dev *dev) struct msi_desc *desc; u32 mask; u16 ctrl; + unsigned pos; if (!pci_msi_enable || !dev || !dev->msi_enabled) return; - msi_set_enable(dev, 0); + BUG_ON(list_empty(&dev->msi_list)); + desc = list_first_entry(&dev->msi_list, struct msi_desc, list); + pos = desc->msi_attrib.pos; + + msi_set_enable(dev, pos, 0); pci_intx_for_msi(dev, 1); dev->msi_enabled = 0; - BUG_ON(list_empty(&dev->msi_list)); - desc = list_first_entry(&dev->msi_list, struct msi_desc, list); - pci_read_config_word(dev, desc->msi_attrib.pos + PCI_MSI_FLAGS, &ctrl); + pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &ctrl); mask = msi_capable_mask(ctrl); msi_mask_irq(desc, mask, ~mask); @@ -648,10 +653,7 @@ static int msi_free_irqs(struct pci_dev* dev) list_for_each_entry_safe(entry, tmp, &dev->msi_list, list) { if (entry->msi_attrib.is_msix) { - writel(1, entry->mask_base + entry->msi_attrib.entry_nr - * PCI_MSIX_ENTRY_SIZE - + PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET); - + msix_mask_irq(entry, 1); if (list_is_last(&entry->list, &dev->msi_list)) iounmap(entry->mask_base); } @@ -691,8 +693,8 @@ int pci_msix_table_size(struct pci_dev *dev) * indicates the successful configuration of MSI-X capability structure * with new allocated MSI-X irqs. A return of < 0 indicates a failure. * Or a return of > 0 indicates that driver request is exceeding the number - * of irqs available. Driver should use the returned value to re-send - * its request. + * of irqs or MSI-X vectors available. Driver should use the returned value to + * re-send its request. **/ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) { @@ -708,7 +710,7 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) nr_entries = pci_msix_table_size(dev); if (nvec > nr_entries) - return -EINVAL; + return nr_entries; /* Check for any invalid entries */ for (i = 0; i < nvec; i++) { diff --git a/drivers/pci/msi.h b/drivers/pci/msi.h index 71f4df2ef654..a0662842550b 100644 --- a/drivers/pci/msi.h +++ b/drivers/pci/msi.h @@ -16,21 +16,15 @@ #define msi_lower_address_reg(base) (base + PCI_MSI_ADDRESS_LO) #define msi_upper_address_reg(base) (base + PCI_MSI_ADDRESS_HI) #define msi_data_reg(base, is64bit) \ - ( (is64bit == 1) ? base+PCI_MSI_DATA_64 : base+PCI_MSI_DATA_32 ) -#define msi_mask_bits_reg(base, is64bit) \ - ( (is64bit == 1) ? base+PCI_MSI_MASK_BIT : base+PCI_MSI_MASK_BIT-4) -#define msi_disable(control) control &= ~PCI_MSI_FLAGS_ENABLE + (base + ((is64bit == 1) ? PCI_MSI_DATA_64 : PCI_MSI_DATA_32)) +#define msi_mask_reg(base, is64bit) \ + (base + ((is64bit == 1) ? PCI_MSI_MASK_64 : PCI_MSI_MASK_32)) #define is_64bit_address(control) (!!(control & PCI_MSI_FLAGS_64BIT)) #define is_mask_bit_support(control) (!!(control & PCI_MSI_FLAGS_MASKBIT)) #define msix_table_offset_reg(base) (base + 0x04) #define msix_pba_offset_reg(base) (base + 0x08) -#define msix_enable(control) control |= PCI_MSIX_FLAGS_ENABLE -#define msix_disable(control) control &= ~PCI_MSIX_FLAGS_ENABLE #define msix_table_size(control) ((control & PCI_MSIX_FLAGS_QSIZE)+1) -#define multi_msix_capable msix_table_size -#define msix_unmask(address) (address & ~PCI_MSIX_FLAGS_BITMASK) -#define msix_mask(address) (address | PCI_MSIX_FLAGS_BITMASK) -#define msix_is_pending(address) (address & PCI_MSIX_FLAGS_PENDMASK) +#define multi_msix_capable(control) msix_table_size((control)) #endif /* MSI_H */ diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 1a91bf9687af..6c93af5ced18 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -24,6 +24,11 @@ #include #include "pci.h" +const char *pci_power_names[] = { + "error", "D0", "D1", "D2", "D3hot", "D3cold", "unknown", +}; +EXPORT_SYMBOL_GPL(pci_power_names); + unsigned int pci_pm_d3_delay = PCI_PM_D3_WAIT; #ifdef CONFIG_PCI_DOMAINS @@ -480,6 +485,8 @@ static int pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state) pmcsr &= ~PCI_PM_CTRL_STATE_MASK; pmcsr |= state; break; + case PCI_D3hot: + case PCI_D3cold: case PCI_UNKNOWN: /* Boot-up */ if ((pmcsr & PCI_PM_CTRL_STATE_MASK) == PCI_D3hot && !(pmcsr & PCI_PM_CTRL_NO_SOFT_RESET)) @@ -1203,7 +1210,7 @@ void pci_pme_active(struct pci_dev *dev, bool enable) * Error code depending on the platform is returned if both the platform and * the native mechanism fail to enable the generation of wake-up events */ -int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable) +int pci_enable_wake(struct pci_dev *dev, pci_power_t state, bool enable) { int error = 0; bool pme_done = false; @@ -1282,15 +1289,14 @@ pci_power_t pci_target_state(struct pci_dev *dev) default: target_state = state; } + } else if (!dev->pm_cap) { + target_state = PCI_D0; } else if (device_may_wakeup(&dev->dev)) { /* * Find the deepest state from which the device can generate * wake-up events, make it the target state and enable device * to generate PME#. */ - if (!dev->pm_cap) - return PCI_POWER_ERROR; - if (dev->pme_support) { while (target_state && !(dev->pme_support & (1 << target_state))) @@ -1527,7 +1533,7 @@ pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge) if (!pin) return -1; - while (dev->bus->parent) { + while (!pci_is_root_bus(dev->bus)) { pin = pci_swizzle_interrupt_pin(dev, pin); dev = dev->bus->self; } @@ -1547,7 +1553,7 @@ u8 pci_common_swizzle(struct pci_dev *dev, u8 *pinp) { u8 pin = *pinp; - while (dev->bus->parent) { + while (!pci_is_root_bus(dev->bus)) { pin = pci_swizzle_interrupt_pin(dev, pin); dev = dev->bus->self; } @@ -2053,111 +2059,177 @@ int pci_set_dma_seg_boundary(struct pci_dev *dev, unsigned long mask) EXPORT_SYMBOL(pci_set_dma_seg_boundary); #endif -static int __pcie_flr(struct pci_dev *dev, int probe) +static int pcie_flr(struct pci_dev *dev, int probe) { - u16 status; + int i; + int pos; u32 cap; - int exppos = pci_find_capability(dev, PCI_CAP_ID_EXP); + u16 status; - if (!exppos) + pos = pci_find_capability(dev, PCI_CAP_ID_EXP); + if (!pos) return -ENOTTY; - pci_read_config_dword(dev, exppos + PCI_EXP_DEVCAP, &cap); + + pci_read_config_dword(dev, pos + PCI_EXP_DEVCAP, &cap); if (!(cap & PCI_EXP_DEVCAP_FLR)) return -ENOTTY; if (probe) return 0; - pci_block_user_cfg_access(dev); - /* Wait for Transaction Pending bit clean */ - pci_read_config_word(dev, exppos + PCI_EXP_DEVSTA, &status); - if (!(status & PCI_EXP_DEVSTA_TRPND)) - goto transaction_done; + for (i = 0; i < 4; i++) { + if (i) + msleep((1 << (i - 1)) * 100); - msleep(100); - pci_read_config_word(dev, exppos + PCI_EXP_DEVSTA, &status); - if (!(status & PCI_EXP_DEVSTA_TRPND)) - goto transaction_done; + pci_read_config_word(dev, pos + PCI_EXP_DEVSTA, &status); + if (!(status & PCI_EXP_DEVSTA_TRPND)) + goto clear; + } - dev_info(&dev->dev, "Busy after 100ms while trying to reset; " - "sleeping for 1 second\n"); - ssleep(1); - pci_read_config_word(dev, exppos + PCI_EXP_DEVSTA, &status); - if (status & PCI_EXP_DEVSTA_TRPND) - dev_info(&dev->dev, "Still busy after 1s; " - "proceeding with reset anyway\n"); + dev_err(&dev->dev, "transaction is not cleared; " + "proceeding with reset anyway\n"); -transaction_done: - pci_write_config_word(dev, exppos + PCI_EXP_DEVCTL, +clear: + pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_BCR_FLR); - mdelay(100); + msleep(100); - pci_unblock_user_cfg_access(dev); return 0; } -static int __pci_af_flr(struct pci_dev *dev, int probe) +static int pci_af_flr(struct pci_dev *dev, int probe) { - int cappos = pci_find_capability(dev, PCI_CAP_ID_AF); - u8 status; + int i; + int pos; u8 cap; + u8 status; - if (!cappos) + pos = pci_find_capability(dev, PCI_CAP_ID_AF); + if (!pos) return -ENOTTY; - pci_read_config_byte(dev, cappos + PCI_AF_CAP, &cap); + + pci_read_config_byte(dev, pos + PCI_AF_CAP, &cap); if (!(cap & PCI_AF_CAP_TP) || !(cap & PCI_AF_CAP_FLR)) return -ENOTTY; if (probe) return 0; - pci_block_user_cfg_access(dev); - /* Wait for Transaction Pending bit clean */ - pci_read_config_byte(dev, cappos + PCI_AF_STATUS, &status); - if (!(status & PCI_AF_STATUS_TP)) - goto transaction_done; + for (i = 0; i < 4; i++) { + if (i) + msleep((1 << (i - 1)) * 100); + pci_read_config_byte(dev, pos + PCI_AF_STATUS, &status); + if (!(status & PCI_AF_STATUS_TP)) + goto clear; + } + + dev_err(&dev->dev, "transaction is not cleared; " + "proceeding with reset anyway\n"); + +clear: + pci_write_config_byte(dev, pos + PCI_AF_CTRL, PCI_AF_CTRL_FLR); msleep(100); - pci_read_config_byte(dev, cappos + PCI_AF_STATUS, &status); - if (!(status & PCI_AF_STATUS_TP)) - goto transaction_done; - dev_info(&dev->dev, "Busy after 100ms while trying to" - " reset; sleeping for 1 second\n"); - ssleep(1); - pci_read_config_byte(dev, cappos + PCI_AF_STATUS, &status); - if (status & PCI_AF_STATUS_TP) - dev_info(&dev->dev, "Still busy after 1s; " - "proceeding with reset anyway\n"); - -transaction_done: - pci_write_config_byte(dev, cappos + PCI_AF_CTRL, PCI_AF_CTRL_FLR); - mdelay(100); - - pci_unblock_user_cfg_access(dev); return 0; } -static int __pci_reset_function(struct pci_dev *pdev, int probe) +static int pci_pm_reset(struct pci_dev *dev, int probe) { - int res; + u16 csr; - res = __pcie_flr(pdev, probe); - if (res != -ENOTTY) - return res; + if (!dev->pm_cap) + return -ENOTTY; - res = __pci_af_flr(pdev, probe); - if (res != -ENOTTY) - return res; + pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &csr); + if (csr & PCI_PM_CTRL_NO_SOFT_RESET) + return -ENOTTY; - return res; + if (probe) + return 0; + + if (dev->current_state != PCI_D0) + return -EINVAL; + + csr &= ~PCI_PM_CTRL_STATE_MASK; + csr |= PCI_D3hot; + pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, csr); + msleep(pci_pm_d3_delay); + + csr &= ~PCI_PM_CTRL_STATE_MASK; + csr |= PCI_D0; + pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, csr); + msleep(pci_pm_d3_delay); + + return 0; +} + +static int pci_parent_bus_reset(struct pci_dev *dev, int probe) +{ + u16 ctrl; + struct pci_dev *pdev; + + if (dev->subordinate) + return -ENOTTY; + + list_for_each_entry(pdev, &dev->bus->devices, bus_list) + if (pdev != dev) + return -ENOTTY; + + if (probe) + return 0; + + pci_read_config_word(dev->bus->self, PCI_BRIDGE_CONTROL, &ctrl); + ctrl |= PCI_BRIDGE_CTL_BUS_RESET; + pci_write_config_word(dev->bus->self, PCI_BRIDGE_CONTROL, ctrl); + msleep(100); + + ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET; + pci_write_config_word(dev->bus->self, PCI_BRIDGE_CONTROL, ctrl); + msleep(100); + + return 0; +} + +static int pci_dev_reset(struct pci_dev *dev, int probe) +{ + int rc; + + might_sleep(); + + if (!probe) { + pci_block_user_cfg_access(dev); + /* block PM suspend, driver probe, etc. */ + down(&dev->dev.sem); + } + + rc = pcie_flr(dev, probe); + if (rc != -ENOTTY) + goto done; + + rc = pci_af_flr(dev, probe); + if (rc != -ENOTTY) + goto done; + + rc = pci_pm_reset(dev, probe); + if (rc != -ENOTTY) + goto done; + + rc = pci_parent_bus_reset(dev, probe); +done: + if (!probe) { + up(&dev->dev.sem); + pci_unblock_user_cfg_access(dev); + } + + return rc; } /** - * pci_execute_reset_function() - Reset a PCI device function - * @dev: Device function to reset + * __pci_reset_function - reset a PCI device function + * @dev: PCI device to reset * * Some devices allow an individual function to be reset without affecting * other functions in the same device. The PCI device must be responsive @@ -2169,18 +2241,18 @@ static int __pci_reset_function(struct pci_dev *pdev, int probe) * device including MSI, bus mastering, BARs, decoding IO and memory spaces, * etc. * - * Returns 0 if the device function was successfully reset or -ENOTTY if the + * Returns 0 if the device function was successfully reset or negative if the * device doesn't support resetting a single function. */ -int pci_execute_reset_function(struct pci_dev *dev) +int __pci_reset_function(struct pci_dev *dev) { - return __pci_reset_function(dev, 0); + return pci_dev_reset(dev, 0); } -EXPORT_SYMBOL_GPL(pci_execute_reset_function); +EXPORT_SYMBOL_GPL(__pci_reset_function); /** - * pci_reset_function() - quiesce and reset a PCI device function - * @dev: Device function to reset + * pci_reset_function - quiesce and reset a PCI device function + * @dev: PCI device to reset * * Some devices allow an individual function to be reset without affecting * other functions in the same device. The PCI device must be responsive @@ -2188,32 +2260,33 @@ EXPORT_SYMBOL_GPL(pci_execute_reset_function); * * This function does not just reset the PCI portion of a device, but * clears all the state associated with the device. This function differs - * from pci_execute_reset_function in that it saves and restores device state + * from __pci_reset_function in that it saves and restores device state * over the reset. * - * Returns 0 if the device function was successfully reset or -ENOTTY if the + * Returns 0 if the device function was successfully reset or negative if the * device doesn't support resetting a single function. */ int pci_reset_function(struct pci_dev *dev) { - int r = __pci_reset_function(dev, 1); + int rc; - if (r < 0) - return r; + rc = pci_dev_reset(dev, 1); + if (rc) + return rc; - if (!dev->msi_enabled && !dev->msix_enabled && dev->irq != 0) - disable_irq(dev->irq); pci_save_state(dev); + /* + * both INTx and MSI are disabled after the Interrupt Disable bit + * is set and the Bus Master bit is cleared. + */ pci_write_config_word(dev, PCI_COMMAND, PCI_COMMAND_INTX_DISABLE); - r = pci_execute_reset_function(dev); + rc = pci_dev_reset(dev, 0); pci_restore_state(dev); - if (!dev->msi_enabled && !dev->msix_enabled && dev->irq != 0) - enable_irq(dev->irq); - return r; + return rc; } EXPORT_SYMBOL_GPL(pci_reset_function); @@ -2586,6 +2659,8 @@ static int __init pci_setup(char *str) } else if (!strncmp(str, "resource_alignment=", 19)) { pci_set_resource_alignment_param(str + 19, strlen(str + 19)); + } else if (!strncmp(str, "ecrc=", 5)) { + pcie_ecrc_get_policy(str + 5); } else { printk(KERN_ERR "PCI: Unknown option `%s'\n", str); diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index d03f6b99f292..f73bcbedf37c 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -229,6 +229,15 @@ struct pci_sriov { u8 __iomem *mstate; /* VF Migration State Array */ }; +/* Address Translation Service */ +struct pci_ats { + int pos; /* capability position */ + int stu; /* Smallest Translation Unit */ + int qdep; /* Invalidate Queue Depth */ + int ref_cnt; /* Physical Function reference count */ + int is_enabled:1; /* Enable bit is set */ +}; + #ifdef CONFIG_PCI_IOV extern int pci_iov_init(struct pci_dev *dev); extern void pci_iov_release(struct pci_dev *dev); @@ -236,6 +245,20 @@ extern int pci_iov_resource_bar(struct pci_dev *dev, int resno, enum pci_bar_type *type); extern void pci_restore_iov_state(struct pci_dev *dev); extern int pci_iov_bus_range(struct pci_bus *bus); + +extern int pci_enable_ats(struct pci_dev *dev, int ps); +extern void pci_disable_ats(struct pci_dev *dev); +extern int pci_ats_queue_depth(struct pci_dev *dev); +/** + * pci_ats_enabled - query the ATS status + * @dev: the PCI device + * + * Returns 1 if ATS capability is enabled, or 0 if not. + */ +static inline int pci_ats_enabled(struct pci_dev *dev) +{ + return dev->ats && dev->ats->is_enabled; +} #else static inline int pci_iov_init(struct pci_dev *dev) { @@ -257,6 +280,22 @@ static inline int pci_iov_bus_range(struct pci_bus *bus) { return 0; } + +static inline int pci_enable_ats(struct pci_dev *dev, int ps) +{ + return -ENODEV; +} +static inline void pci_disable_ats(struct pci_dev *dev) +{ +} +static inline int pci_ats_queue_depth(struct pci_dev *dev) +{ + return -ENODEV; +} +static inline int pci_ats_enabled(struct pci_dev *dev) +{ + return 0; +} #endif /* CONFIG_PCI_IOV */ #endif /* DRIVERS_PCI_H */ diff --git a/drivers/pci/pcie/aer/Kconfig b/drivers/pci/pcie/aer/Kconfig index c3bde588aa13..50e94e02378a 100644 --- a/drivers/pci/pcie/aer/Kconfig +++ b/drivers/pci/pcie/aer/Kconfig @@ -10,3 +10,18 @@ config PCIEAER This enables PCI Express Root Port Advanced Error Reporting (AER) driver support. Error reporting messages sent to Root Port will be handled by PCI Express AER driver. + + +# +# PCI Express ECRC +# +config PCIE_ECRC + bool "PCI Express ECRC settings control" + depends on PCIEAER + help + Used to override firmware/bios settings for PCI Express ECRC + (transaction layer end-to-end CRC checking). + + When in doubt, say N. + +source "drivers/pci/pcie/aer/Kconfig.debug" diff --git a/drivers/pci/pcie/aer/Kconfig.debug b/drivers/pci/pcie/aer/Kconfig.debug new file mode 100644 index 000000000000..b8c925c1f6aa --- /dev/null +++ b/drivers/pci/pcie/aer/Kconfig.debug @@ -0,0 +1,18 @@ +# +# PCI Express Root Port Device AER Debug Configuration +# + +config PCIEAER_INJECT + tristate "PCIE AER error injector support" + depends on PCIEAER + default n + help + This enables PCI Express Root Port Advanced Error Reporting + (AER) software error injector. + + Debuging PCIE AER code is quite difficult because it is hard + to trigger various real hardware errors. Software based + error injection can fake almost all kinds of errors with the + help of a user space helper tool aer-inject, which can be + gotten from: + http://www.kernel.org/pub/linux/utils/pci/aer-inject/ diff --git a/drivers/pci/pcie/aer/Makefile b/drivers/pci/pcie/aer/Makefile index 8da3bd8455a8..2cba67510dc8 100644 --- a/drivers/pci/pcie/aer/Makefile +++ b/drivers/pci/pcie/aer/Makefile @@ -4,6 +4,9 @@ obj-$(CONFIG_PCIEAER) += aerdriver.o +obj-$(CONFIG_PCIE_ECRC) += ecrc.o + aerdriver-objs := aerdrv_errprint.o aerdrv_core.o aerdrv.o aerdriver-$(CONFIG_ACPI) += aerdrv_acpi.o +obj-$(CONFIG_PCIEAER_INJECT) += aer_inject.o diff --git a/drivers/pci/pcie/aer/aer_inject.c b/drivers/pci/pcie/aer/aer_inject.c new file mode 100644 index 000000000000..d92ae21a59d8 --- /dev/null +++ b/drivers/pci/pcie/aer/aer_inject.c @@ -0,0 +1,473 @@ +/* + * PCIE AER software error injection support. + * + * Debuging PCIE AER code is quite difficult because it is hard to + * trigger various real hardware errors. Software based error + * injection can fake almost all kinds of errors with the help of a + * user space helper tool aer-inject, which can be gotten from: + * http://www.kernel.org/pub/linux/utils/pci/aer-inject/ + * + * Copyright 2009 Intel Corporation. + * Huang Ying + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; version 2 + * of the License. + * + */ + +#include +#include +#include +#include +#include +#include +#include "aerdrv.h" + +struct aer_error_inj +{ + u8 bus; + u8 dev; + u8 fn; + u32 uncor_status; + u32 cor_status; + u32 header_log0; + u32 header_log1; + u32 header_log2; + u32 header_log3; +}; + +struct aer_error +{ + struct list_head list; + unsigned int bus; + unsigned int devfn; + int pos_cap_err; + + u32 uncor_status; + u32 cor_status; + u32 header_log0; + u32 header_log1; + u32 header_log2; + u32 header_log3; + u32 root_status; + u32 source_id; +}; + +struct pci_bus_ops +{ + struct list_head list; + struct pci_bus *bus; + struct pci_ops *ops; +}; + +static LIST_HEAD(einjected); + +static LIST_HEAD(pci_bus_ops_list); + +/* Protect einjected and pci_bus_ops_list */ +static DEFINE_SPINLOCK(inject_lock); + +static void aer_error_init(struct aer_error *err, unsigned int bus, + unsigned int devfn, int pos_cap_err) +{ + INIT_LIST_HEAD(&err->list); + err->bus = bus; + err->devfn = devfn; + err->pos_cap_err = pos_cap_err; +} + +/* inject_lock must be held before calling */ +static struct aer_error *__find_aer_error(unsigned int bus, unsigned int devfn) +{ + struct aer_error *err; + + list_for_each_entry(err, &einjected, list) { + if (bus == err->bus && devfn == err->devfn) + return err; + } + return NULL; +} + +/* inject_lock must be held before calling */ +static struct aer_error *__find_aer_error_by_dev(struct pci_dev *dev) +{ + return __find_aer_error(dev->bus->number, dev->devfn); +} + +/* inject_lock must be held before calling */ +static struct pci_ops *__find_pci_bus_ops(struct pci_bus *bus) +{ + struct pci_bus_ops *bus_ops; + + list_for_each_entry(bus_ops, &pci_bus_ops_list, list) { + if (bus_ops->bus == bus) + return bus_ops->ops; + } + return NULL; +} + +static struct pci_bus_ops *pci_bus_ops_pop(void) +{ + unsigned long flags; + struct pci_bus_ops *bus_ops = NULL; + + spin_lock_irqsave(&inject_lock, flags); + if (list_empty(&pci_bus_ops_list)) + bus_ops = NULL; + else { + struct list_head *lh = pci_bus_ops_list.next; + list_del(lh); + bus_ops = list_entry(lh, struct pci_bus_ops, list); + } + spin_unlock_irqrestore(&inject_lock, flags); + return bus_ops; +} + +static u32 *find_pci_config_dword(struct aer_error *err, int where, + int *prw1cs) +{ + int rw1cs = 0; + u32 *target = NULL; + + if (err->pos_cap_err == -1) + return NULL; + + switch (where - err->pos_cap_err) { + case PCI_ERR_UNCOR_STATUS: + target = &err->uncor_status; + rw1cs = 1; + break; + case PCI_ERR_COR_STATUS: + target = &err->cor_status; + rw1cs = 1; + break; + case PCI_ERR_HEADER_LOG: + target = &err->header_log0; + break; + case PCI_ERR_HEADER_LOG+4: + target = &err->header_log1; + break; + case PCI_ERR_HEADER_LOG+8: + target = &err->header_log2; + break; + case PCI_ERR_HEADER_LOG+12: + target = &err->header_log3; + break; + case PCI_ERR_ROOT_STATUS: + target = &err->root_status; + rw1cs = 1; + break; + case PCI_ERR_ROOT_COR_SRC: + target = &err->source_id; + break; + } + if (prw1cs) + *prw1cs = rw1cs; + return target; +} + +static int pci_read_aer(struct pci_bus *bus, unsigned int devfn, int where, + int size, u32 *val) +{ + u32 *sim; + struct aer_error *err; + unsigned long flags; + struct pci_ops *ops; + + spin_lock_irqsave(&inject_lock, flags); + if (size != sizeof(u32)) + goto out; + err = __find_aer_error(bus->number, devfn); + if (!err) + goto out; + + sim = find_pci_config_dword(err, where, NULL); + if (sim) { + *val = *sim; + spin_unlock_irqrestore(&inject_lock, flags); + return 0; + } +out: + ops = __find_pci_bus_ops(bus); + spin_unlock_irqrestore(&inject_lock, flags); + return ops->read(bus, devfn, where, size, val); +} + +int pci_write_aer(struct pci_bus *bus, unsigned int devfn, int where, int size, + u32 val) +{ + u32 *sim; + struct aer_error *err; + unsigned long flags; + int rw1cs; + struct pci_ops *ops; + + spin_lock_irqsave(&inject_lock, flags); + if (size != sizeof(u32)) + goto out; + err = __find_aer_error(bus->number, devfn); + if (!err) + goto out; + + sim = find_pci_config_dword(err, where, &rw1cs); + if (sim) { + if (rw1cs) + *sim ^= val; + else + *sim = val; + spin_unlock_irqrestore(&inject_lock, flags); + return 0; + } +out: + ops = __find_pci_bus_ops(bus); + spin_unlock_irqrestore(&inject_lock, flags); + return ops->write(bus, devfn, where, size, val); +} + +static struct pci_ops pci_ops_aer = { + .read = pci_read_aer, + .write = pci_write_aer, +}; + +static void pci_bus_ops_init(struct pci_bus_ops *bus_ops, + struct pci_bus *bus, + struct pci_ops *ops) +{ + INIT_LIST_HEAD(&bus_ops->list); + bus_ops->bus = bus; + bus_ops->ops = ops; +} + +static int pci_bus_set_aer_ops(struct pci_bus *bus) +{ + struct pci_ops *ops; + struct pci_bus_ops *bus_ops; + unsigned long flags; + + bus_ops = kmalloc(sizeof(*bus_ops), GFP_KERNEL); + if (!bus_ops) + return -ENOMEM; + ops = pci_bus_set_ops(bus, &pci_ops_aer); + spin_lock_irqsave(&inject_lock, flags); + if (ops == &pci_ops_aer) + goto out; + pci_bus_ops_init(bus_ops, bus, ops); + list_add(&bus_ops->list, &pci_bus_ops_list); + bus_ops = NULL; +out: + spin_unlock_irqrestore(&inject_lock, flags); + if (bus_ops) + kfree(bus_ops); + return 0; +} + +static struct pci_dev *pcie_find_root_port(struct pci_dev *dev) +{ + while (1) { + if (!dev->is_pcie) + break; + if (dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT) + return dev; + if (!dev->bus->self) + break; + dev = dev->bus->self; + } + return NULL; +} + +static int find_aer_device_iter(struct device *device, void *data) +{ + struct pcie_device **result = data; + struct pcie_device *pcie_dev; + + if (device->bus == &pcie_port_bus_type) { + pcie_dev = to_pcie_device(device); + if (pcie_dev->service & PCIE_PORT_SERVICE_AER) { + *result = pcie_dev; + return 1; + } + } + return 0; +} + +static int find_aer_device(struct pci_dev *dev, struct pcie_device **result) +{ + return device_for_each_child(&dev->dev, result, find_aer_device_iter); +} + +static int aer_inject(struct aer_error_inj *einj) +{ + struct aer_error *err, *rperr; + struct aer_error *err_alloc = NULL, *rperr_alloc = NULL; + struct pci_dev *dev, *rpdev; + struct pcie_device *edev; + unsigned long flags; + unsigned int devfn = PCI_DEVFN(einj->dev, einj->fn); + int pos_cap_err, rp_pos_cap_err; + u32 sever; + int ret = 0; + + dev = pci_get_bus_and_slot(einj->bus, devfn); + if (!dev) + return -EINVAL; + rpdev = pcie_find_root_port(dev); + if (!rpdev) { + ret = -EINVAL; + goto out_put; + } + + pos_cap_err = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); + if (!pos_cap_err) { + ret = -EIO; + goto out_put; + } + pci_read_config_dword(dev, pos_cap_err + PCI_ERR_UNCOR_SEVER, &sever); + + rp_pos_cap_err = pci_find_ext_capability(rpdev, PCI_EXT_CAP_ID_ERR); + if (!rp_pos_cap_err) { + ret = -EIO; + goto out_put; + } + + err_alloc = kzalloc(sizeof(struct aer_error), GFP_KERNEL); + if (!err_alloc) { + ret = -ENOMEM; + goto out_put; + } + rperr_alloc = kzalloc(sizeof(struct aer_error), GFP_KERNEL); + if (!rperr_alloc) { + ret = -ENOMEM; + goto out_put; + } + + spin_lock_irqsave(&inject_lock, flags); + + err = __find_aer_error_by_dev(dev); + if (!err) { + err = err_alloc; + err_alloc = NULL; + aer_error_init(err, einj->bus, devfn, pos_cap_err); + list_add(&err->list, &einjected); + } + err->uncor_status |= einj->uncor_status; + err->cor_status |= einj->cor_status; + err->header_log0 = einj->header_log0; + err->header_log1 = einj->header_log1; + err->header_log2 = einj->header_log2; + err->header_log3 = einj->header_log3; + + rperr = __find_aer_error_by_dev(rpdev); + if (!rperr) { + rperr = rperr_alloc; + rperr_alloc = NULL; + aer_error_init(rperr, rpdev->bus->number, rpdev->devfn, + rp_pos_cap_err); + list_add(&rperr->list, &einjected); + } + if (einj->cor_status) { + if (rperr->root_status & PCI_ERR_ROOT_COR_RCV) + rperr->root_status |= PCI_ERR_ROOT_MULTI_COR_RCV; + else + rperr->root_status |= PCI_ERR_ROOT_COR_RCV; + rperr->source_id &= 0xffff0000; + rperr->source_id |= (einj->bus << 8) | devfn; + } + if (einj->uncor_status) { + if (rperr->root_status & PCI_ERR_ROOT_UNCOR_RCV) + rperr->root_status |= PCI_ERR_ROOT_MULTI_UNCOR_RCV; + if (sever & einj->uncor_status) { + rperr->root_status |= PCI_ERR_ROOT_FATAL_RCV; + if (!(rperr->root_status & PCI_ERR_ROOT_UNCOR_RCV)) + rperr->root_status |= PCI_ERR_ROOT_FIRST_FATAL; + } else + rperr->root_status |= PCI_ERR_ROOT_NONFATAL_RCV; + rperr->root_status |= PCI_ERR_ROOT_UNCOR_RCV; + rperr->source_id &= 0x0000ffff; + rperr->source_id |= ((einj->bus << 8) | devfn) << 16; + } + spin_unlock_irqrestore(&inject_lock, flags); + + ret = pci_bus_set_aer_ops(dev->bus); + if (ret) + goto out_put; + ret = pci_bus_set_aer_ops(rpdev->bus); + if (ret) + goto out_put; + + if (find_aer_device(rpdev, &edev)) + aer_irq(-1, edev); + else + ret = -EINVAL; +out_put: + if (err_alloc) + kfree(err_alloc); + if (rperr_alloc) + kfree(rperr_alloc); + pci_dev_put(dev); + return ret; +} + +static ssize_t aer_inject_write(struct file *filp, const char __user *ubuf, + size_t usize, loff_t *off) +{ + struct aer_error_inj einj; + int ret; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (usize != sizeof(struct aer_error_inj)) + return -EINVAL; + + if (copy_from_user(&einj, ubuf, usize)) + return -EFAULT; + + ret = aer_inject(&einj); + return ret ? ret : usize; +} + +static const struct file_operations aer_inject_fops = { + .write = aer_inject_write, + .owner = THIS_MODULE, +}; + +static struct miscdevice aer_inject_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "aer_inject", + .fops = &aer_inject_fops, +}; + +static int __init aer_inject_init(void) +{ + return misc_register(&aer_inject_device); +} + +static void __exit aer_inject_exit(void) +{ + struct aer_error *err, *err_next; + unsigned long flags; + struct pci_bus_ops *bus_ops; + + misc_deregister(&aer_inject_device); + + while ((bus_ops = pci_bus_ops_pop())) { + pci_bus_set_ops(bus_ops->bus, bus_ops->ops); + kfree(bus_ops); + } + + spin_lock_irqsave(&inject_lock, flags); + list_for_each_entry_safe(err, err_next, + &pci_bus_ops_list, list) { + list_del(&err->list); + kfree(err); + } + spin_unlock_irqrestore(&inject_lock, flags); +} + +module_init(aer_inject_init); +module_exit(aer_inject_exit); + +MODULE_DESCRIPTION("PCIE AER software error injector"); +MODULE_LICENSE("GPL"); diff --git a/drivers/pci/pcie/aer/aerdrv.c b/drivers/pci/pcie/aer/aerdrv.c index 32ade5af927e..4770f13b3ca1 100644 --- a/drivers/pci/pcie/aer/aerdrv.c +++ b/drivers/pci/pcie/aer/aerdrv.c @@ -77,7 +77,7 @@ void pci_no_aer(void) * * Invoked when Root Port detects AER messages. **/ -static irqreturn_t aer_irq(int irq, void *context) +irqreturn_t aer_irq(int irq, void *context) { unsigned int status, id; struct pcie_device *pdev = (struct pcie_device *)context; @@ -126,6 +126,7 @@ static irqreturn_t aer_irq(int irq, void *context) return IRQ_HANDLED; } +EXPORT_SYMBOL_GPL(aer_irq); /** * aer_alloc_rpc - allocate Root Port data structure diff --git a/drivers/pci/pcie/aer/aerdrv.h b/drivers/pci/pcie/aer/aerdrv.h index aa14482a4779..bbd7428ca2d0 100644 --- a/drivers/pci/pcie/aer/aerdrv.h +++ b/drivers/pci/pcie/aer/aerdrv.h @@ -11,6 +11,7 @@ #include #include #include +#include #define AER_NONFATAL 0 #define AER_FATAL 1 @@ -56,7 +57,11 @@ struct header_log_regs { unsigned int dw3; }; +#define AER_MAX_MULTI_ERR_DEVICES 5 /* Not likely to have more */ struct aer_err_info { + struct pci_dev *dev[AER_MAX_MULTI_ERR_DEVICES]; + int error_dev_num; + u16 id; int severity; /* 0:NONFATAL | 1:FATAL | 2:COR */ int flags; unsigned int status; /* COR/UNCOR Error Status */ @@ -120,6 +125,7 @@ extern void aer_delete_rootport(struct aer_rpc *rpc); extern int aer_init(struct pcie_device *dev); extern void aer_isr(struct work_struct *work); extern void aer_print_error(struct pci_dev *dev, struct aer_err_info *info); +extern irqreturn_t aer_irq(int irq, void *context); #ifdef CONFIG_ACPI extern int aer_osc_setup(struct pcie_device *pciedev); diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c index 307452f30035..3d8872704a58 100644 --- a/drivers/pci/pcie/aer/aerdrv_core.c +++ b/drivers/pci/pcie/aer/aerdrv_core.c @@ -26,7 +26,9 @@ #include "aerdrv.h" static int forceload; +static int nosourceid; module_param(forceload, bool, 0); +module_param(nosourceid, bool, 0); int pci_enable_pcie_error_reporting(struct pci_dev *dev) { @@ -109,19 +111,23 @@ int pci_cleanup_aer_correct_error_status(struct pci_dev *dev) #endif /* 0 */ -static void set_device_error_reporting(struct pci_dev *dev, void *data) +static int set_device_error_reporting(struct pci_dev *dev, void *data) { bool enable = *((bool *)data); - if (dev->pcie_type != PCIE_RC_PORT && - dev->pcie_type != PCIE_SW_UPSTREAM_PORT && - dev->pcie_type != PCIE_SW_DOWNSTREAM_PORT) - return; + if (dev->pcie_type == PCIE_RC_PORT || + dev->pcie_type == PCIE_SW_UPSTREAM_PORT || + dev->pcie_type == PCIE_SW_DOWNSTREAM_PORT) { + if (enable) + pci_enable_pcie_error_reporting(dev); + else + pci_disable_pcie_error_reporting(dev); + } if (enable) - pci_enable_pcie_error_reporting(dev); - else - pci_disable_pcie_error_reporting(dev); + pcie_set_ecrc_checking(dev); + + return 0; } /** @@ -139,73 +145,148 @@ static void set_downstream_devices_error_reporting(struct pci_dev *dev, pci_walk_bus(dev->subordinate, set_device_error_reporting, &enable); } -static int find_device_iter(struct device *device, void *data) +static inline int compare_device_id(struct pci_dev *dev, + struct aer_err_info *e_info) { - struct pci_dev *dev; - u16 id = *(unsigned long *)data; - u8 secondary, subordinate, d_bus = id >> 8; - - if (device->bus == &pci_bus_type) { - dev = to_pci_dev(device); - if (id == ((dev->bus->number << 8) | dev->devfn)) { - /* - * Device ID match - */ - *(unsigned long*)data = (unsigned long)device; - return 1; - } - + if (e_info->id == ((dev->bus->number << 8) | dev->devfn)) { /* - * If device is P2P, check if it is an upstream? + * Device ID match */ - if (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE) { - pci_read_config_byte(dev, PCI_SECONDARY_BUS, - &secondary); - pci_read_config_byte(dev, PCI_SUBORDINATE_BUS, - &subordinate); - if (d_bus >= secondary && d_bus <= subordinate) { - *(unsigned long*)data = (unsigned long)device; - return 1; - } - } + return 1; } return 0; } +static int add_error_device(struct aer_err_info *e_info, struct pci_dev *dev) +{ + if (e_info->error_dev_num < AER_MAX_MULTI_ERR_DEVICES) { + e_info->dev[e_info->error_dev_num] = dev; + e_info->error_dev_num++; + return 1; + } else + return 0; +} + + +#define PCI_BUS(x) (((x) >> 8) & 0xff) + +static int find_device_iter(struct pci_dev *dev, void *data) +{ + int pos; + u32 status; + u32 mask; + u16 reg16; + int result; + struct aer_err_info *e_info = (struct aer_err_info *)data; + + /* + * When bus id is equal to 0, it might be a bad id + * reported by root port. + */ + if (!nosourceid && (PCI_BUS(e_info->id) != 0)) { + result = compare_device_id(dev, e_info); + if (result) + add_error_device(e_info, dev); + + /* + * If there is no multiple error, we stop + * or continue based on the id comparing. + */ + if (!(e_info->flags & AER_MULTI_ERROR_VALID_FLAG)) + return result; + + /* + * If there are multiple errors and id does match, + * We need continue to search other devices under + * the root port. Return 0 means that. + */ + if (result) + return 0; + } + + /* + * When either + * 1) nosourceid==y; + * 2) bus id is equal to 0. Some ports might lose the bus + * id of error source id; + * 3) There are multiple errors and prior id comparing fails; + * We check AER status registers to find the initial reporter. + */ + if (atomic_read(&dev->enable_cnt) == 0) + return 0; + pos = pci_find_capability(dev, PCI_CAP_ID_EXP); + if (!pos) + return 0; + /* Check if AER is enabled */ + pci_read_config_word(dev, pos+PCI_EXP_DEVCTL, ®16); + if (!(reg16 & ( + PCI_EXP_DEVCTL_CERE | + PCI_EXP_DEVCTL_NFERE | + PCI_EXP_DEVCTL_FERE | + PCI_EXP_DEVCTL_URRE))) + return 0; + pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); + if (!pos) + return 0; + + status = 0; + mask = 0; + if (e_info->severity == AER_CORRECTABLE) { + pci_read_config_dword(dev, + pos + PCI_ERR_COR_STATUS, + &status); + pci_read_config_dword(dev, + pos + PCI_ERR_COR_MASK, + &mask); + if (status & ERR_CORRECTABLE_ERROR_MASK & ~mask) { + add_error_device(e_info, dev); + goto added; + } + } else { + pci_read_config_dword(dev, + pos + PCI_ERR_UNCOR_STATUS, + &status); + pci_read_config_dword(dev, + pos + PCI_ERR_UNCOR_MASK, + &mask); + if (status & ERR_UNCORRECTABLE_ERROR_MASK & ~mask) { + add_error_device(e_info, dev); + goto added; + } + } + + return 0; + +added: + if (e_info->flags & AER_MULTI_ERROR_VALID_FLAG) + return 0; + else + return 1; +} + /** * find_source_device - search through device hierarchy for source device * @parent: pointer to Root Port pci_dev data structure - * @id: device ID of agent who sends an error message to this Root Port + * @err_info: including detailed error information such like id * * Invoked when error is detected at the Root Port. */ -static struct device* find_source_device(struct pci_dev *parent, u16 id) +static void find_source_device(struct pci_dev *parent, + struct aer_err_info *e_info) { struct pci_dev *dev = parent; - struct device *device; - unsigned long device_addr; - int status; + int result; /* Is Root Port an agent that sends error message? */ - if (id == ((dev->bus->number << 8) | dev->devfn)) - return &dev->dev; + result = find_device_iter(dev, e_info); + if (result) + return; - do { - device_addr = id; - if ((status = device_for_each_child(&dev->dev, - &device_addr, find_device_iter))) { - device = (struct device*)device_addr; - dev = to_pci_dev(device); - if (id == ((dev->bus->number << 8) | dev->devfn)) - return device; - } - }while (status); - - return NULL; + pci_walk_bus(parent->subordinate, find_device_iter, e_info); } -static void report_error_detected(struct pci_dev *dev, void *data) +static int report_error_detected(struct pci_dev *dev, void *data) { pci_ers_result_t vote; struct pci_error_handlers *err_handler; @@ -230,16 +311,16 @@ static void report_error_detected(struct pci_dev *dev, void *data) dev->driver ? "no AER-aware driver" : "no driver"); } - return; + return 0; } err_handler = dev->driver->err_handler; vote = err_handler->error_detected(dev, result_data->state); result_data->result = merge_result(result_data->result, vote); - return; + return 0; } -static void report_mmio_enabled(struct pci_dev *dev, void *data) +static int report_mmio_enabled(struct pci_dev *dev, void *data) { pci_ers_result_t vote; struct pci_error_handlers *err_handler; @@ -249,15 +330,15 @@ static void report_mmio_enabled(struct pci_dev *dev, void *data) if (!dev->driver || !dev->driver->err_handler || !dev->driver->err_handler->mmio_enabled) - return; + return 0; err_handler = dev->driver->err_handler; vote = err_handler->mmio_enabled(dev); result_data->result = merge_result(result_data->result, vote); - return; + return 0; } -static void report_slot_reset(struct pci_dev *dev, void *data) +static int report_slot_reset(struct pci_dev *dev, void *data) { pci_ers_result_t vote; struct pci_error_handlers *err_handler; @@ -267,15 +348,15 @@ static void report_slot_reset(struct pci_dev *dev, void *data) if (!dev->driver || !dev->driver->err_handler || !dev->driver->err_handler->slot_reset) - return; + return 0; err_handler = dev->driver->err_handler; vote = err_handler->slot_reset(dev); result_data->result = merge_result(result_data->result, vote); - return; + return 0; } -static void report_resume(struct pci_dev *dev, void *data) +static int report_resume(struct pci_dev *dev, void *data) { struct pci_error_handlers *err_handler; @@ -284,11 +365,11 @@ static void report_resume(struct pci_dev *dev, void *data) if (!dev->driver || !dev->driver->err_handler || !dev->driver->err_handler->resume) - return; + return 0; err_handler = dev->driver->err_handler; err_handler->resume(dev); - return; + return 0; } /** @@ -305,7 +386,7 @@ static void report_resume(struct pci_dev *dev, void *data) static pci_ers_result_t broadcast_error_message(struct pci_dev *dev, enum pci_channel_state state, char *error_mesg, - void (*cb)(struct pci_dev *, void *)) + int (*cb)(struct pci_dev *, void *)) { struct aer_broadcast_data result_data; @@ -497,12 +578,12 @@ static pci_ers_result_t do_recovery(struct pcie_device *aerdev, */ static void handle_error_source(struct pcie_device * aerdev, struct pci_dev *dev, - struct aer_err_info info) + struct aer_err_info *info) { pci_ers_result_t status = 0; int pos; - if (info.severity == AER_CORRECTABLE) { + if (info->severity == AER_CORRECTABLE) { /* * Correctable error does not need software intevention. * No need to go through error recovery process. @@ -510,9 +591,9 @@ static void handle_error_source(struct pcie_device * aerdev, pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); if (pos) pci_write_config_dword(dev, pos + PCI_ERR_COR_STATUS, - info.status); + info->status); } else { - status = do_recovery(aerdev, dev, info.severity); + status = do_recovery(aerdev, dev, info->severity); if (status == PCI_ERS_RESULT_RECOVERED) { dev_printk(KERN_DEBUG, &dev->dev, "AER driver " "successfully recovered\n"); @@ -661,6 +742,28 @@ static int get_device_error_info(struct pci_dev *dev, struct aer_err_info *info) return AER_SUCCESS; } +static inline void aer_process_err_devices(struct pcie_device *p_device, + struct aer_err_info *e_info) +{ + int i; + + if (!e_info->dev[0]) { + dev_printk(KERN_DEBUG, &p_device->port->dev, + "can't find device of ID%04x\n", + e_info->id); + } + + for (i = 0; i < e_info->error_dev_num && e_info->dev[i]; i++) { + if (get_device_error_info(e_info->dev[i], e_info) == + AER_SUCCESS) { + aer_print_error(e_info->dev[i], e_info); + handle_error_source(p_device, + e_info->dev[i], + e_info); + } + } +} + /** * aer_isr_one_error - consume an error detected by root port * @p_device: pointer to error root port service device @@ -669,10 +772,16 @@ static int get_device_error_info(struct pci_dev *dev, struct aer_err_info *info) static void aer_isr_one_error(struct pcie_device *p_device, struct aer_err_source *e_src) { - struct device *s_device; - struct aer_err_info e_info = {0, 0, 0,}; + struct aer_err_info *e_info; int i; - u16 id; + + /* struct aer_err_info might be big, so we allocate it with slab */ + e_info = kmalloc(sizeof(struct aer_err_info), GFP_KERNEL); + if (e_info == NULL) { + dev_printk(KERN_DEBUG, &p_device->port->dev, + "Can't allocate mem when processing AER errors\n"); + return; + } /* * There is a possibility that both correctable error and @@ -684,31 +793,26 @@ static void aer_isr_one_error(struct pcie_device *p_device, if (!(e_src->status & i)) continue; + memset(e_info, 0, sizeof(struct aer_err_info)); + /* Init comprehensive error information */ if (i & PCI_ERR_ROOT_COR_RCV) { - id = ERR_COR_ID(e_src->id); - e_info.severity = AER_CORRECTABLE; + e_info->id = ERR_COR_ID(e_src->id); + e_info->severity = AER_CORRECTABLE; } else { - id = ERR_UNCOR_ID(e_src->id); - e_info.severity = ((e_src->status >> 6) & 1); + e_info->id = ERR_UNCOR_ID(e_src->id); + e_info->severity = ((e_src->status >> 6) & 1); } if (e_src->status & (PCI_ERR_ROOT_MULTI_COR_RCV | PCI_ERR_ROOT_MULTI_UNCOR_RCV)) - e_info.flags |= AER_MULTI_ERROR_VALID_FLAG; - if (!(s_device = find_source_device(p_device->port, id))) { - printk(KERN_DEBUG "%s->can't find device of ID%04x\n", - __func__, id); - continue; - } - if (get_device_error_info(to_pci_dev(s_device), &e_info) == - AER_SUCCESS) { - aer_print_error(to_pci_dev(s_device), &e_info); - handle_error_source(p_device, - to_pci_dev(s_device), - e_info); - } + e_info->flags |= AER_MULTI_ERROR_VALID_FLAG; + + find_source_device(p_device->port, e_info); + aer_process_err_devices(p_device, e_info); } + + kfree(e_info); } /** diff --git a/drivers/pci/pcie/aer/ecrc.c b/drivers/pci/pcie/aer/ecrc.c new file mode 100644 index 000000000000..ece97df4df6d --- /dev/null +++ b/drivers/pci/pcie/aer/ecrc.c @@ -0,0 +1,131 @@ +/* + * Enables/disables PCIe ECRC checking. + * + * (C) Copyright 2009 Hewlett-Packard Development Company, L.P. + * Andrew Patterson + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include "../../pci.h" + +#define ECRC_POLICY_DEFAULT 0 /* ECRC set by BIOS */ +#define ECRC_POLICY_OFF 1 /* ECRC off for performance */ +#define ECRC_POLICY_ON 2 /* ECRC on for data integrity */ + +static int ecrc_policy = ECRC_POLICY_DEFAULT; + +static const char *ecrc_policy_str[] = { + [ECRC_POLICY_DEFAULT] = "bios", + [ECRC_POLICY_OFF] = "off", + [ECRC_POLICY_ON] = "on" +}; + +/** + * enable_ercr_checking - enable PCIe ECRC checking for a device + * @dev: the PCI device + * + * Returns 0 on success, or negative on failure. + */ +static int enable_ecrc_checking(struct pci_dev *dev) +{ + int pos; + u32 reg32; + + if (!dev->is_pcie) + return -ENODEV; + + pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); + if (!pos) + return -ENODEV; + + pci_read_config_dword(dev, pos + PCI_ERR_CAP, ®32); + if (reg32 & PCI_ERR_CAP_ECRC_GENC) + reg32 |= PCI_ERR_CAP_ECRC_GENE; + if (reg32 & PCI_ERR_CAP_ECRC_CHKC) + reg32 |= PCI_ERR_CAP_ECRC_CHKE; + pci_write_config_dword(dev, pos + PCI_ERR_CAP, reg32); + + return 0; +} + +/** + * disable_ercr_checking - disables PCIe ECRC checking for a device + * @dev: the PCI device + * + * Returns 0 on success, or negative on failure. + */ +static int disable_ecrc_checking(struct pci_dev *dev) +{ + int pos; + u32 reg32; + + if (!dev->is_pcie) + return -ENODEV; + + pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); + if (!pos) + return -ENODEV; + + pci_read_config_dword(dev, pos + PCI_ERR_CAP, ®32); + reg32 &= ~(PCI_ERR_CAP_ECRC_GENE | PCI_ERR_CAP_ECRC_CHKE); + pci_write_config_dword(dev, pos + PCI_ERR_CAP, reg32); + + return 0; +} + +/** + * pcie_set_ecrc_checking - set/unset PCIe ECRC checking for a device based on global policy + * @dev: the PCI device + */ +void pcie_set_ecrc_checking(struct pci_dev *dev) +{ + switch (ecrc_policy) { + case ECRC_POLICY_DEFAULT: + return; + case ECRC_POLICY_OFF: + disable_ecrc_checking(dev); + break; + case ECRC_POLICY_ON: + enable_ecrc_checking(dev);; + break; + default: + return; + } +} + +/** + * pcie_ecrc_get_policy - parse kernel command-line ecrc option + */ +void pcie_ecrc_get_policy(char *str) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ecrc_policy_str); i++) + if (!strncmp(str, ecrc_policy_str[i], + strlen(ecrc_policy_str[i]))) + break; + if (i >= ARRAY_SIZE(ecrc_policy_str)) + return; + + ecrc_policy = i; +} diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index b0367f168af4..3d27c97e0486 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -26,40 +26,36 @@ #endif #define MODULE_PARAM_PREFIX "pcie_aspm." -struct endpoint_state { - unsigned int l0s_acceptable_latency; - unsigned int l1_acceptable_latency; +struct aspm_latency { + u32 l0s; /* L0s latency (nsec) */ + u32 l1; /* L1 latency (nsec) */ }; struct pcie_link_state { - struct list_head sibiling; - struct pci_dev *pdev; - bool downstream_has_switch; - - struct pcie_link_state *parent; - struct list_head children; - struct list_head link; + struct pci_dev *pdev; /* Upstream component of the Link */ + struct pcie_link_state *root; /* pointer to the root port link */ + struct pcie_link_state *parent; /* pointer to the parent Link state */ + struct list_head sibling; /* node in link_list */ + struct list_head children; /* list of child link states */ + struct list_head link; /* node in parent's children list */ /* ASPM state */ - unsigned int support_state; - unsigned int enabled_state; - unsigned int bios_aspm_state; - /* upstream component */ - unsigned int l0s_upper_latency; - unsigned int l1_upper_latency; - /* downstream component */ - unsigned int l0s_down_latency; - unsigned int l1_down_latency; - /* Clock PM state*/ - unsigned int clk_pm_capable; - unsigned int clk_pm_enabled; - unsigned int bios_clk_state; + u32 aspm_support:2; /* Supported ASPM state */ + u32 aspm_enabled:2; /* Enabled ASPM state */ + u32 aspm_default:2; /* Default ASPM state by BIOS */ + /* Clock PM state */ + u32 clkpm_capable:1; /* Clock PM capable? */ + u32 clkpm_enabled:1; /* Current Clock PM state */ + u32 clkpm_default:1; /* Default Clock PM state by BIOS */ + + /* Latencies */ + struct aspm_latency latency; /* Exit latency */ /* - * A pcie downstream port only has one slot under it, so at most there - * are 8 functions + * Endpoint acceptable latencies. A pcie downstream port only + * has one slot under it, so at most there are 8 functions. */ - struct endpoint_state endpoints[8]; + struct aspm_latency acceptable[8]; }; static int aspm_disabled, aspm_force; @@ -78,27 +74,23 @@ static const char *policy_str[] = { #define LINK_RETRAIN_TIMEOUT HZ -static int policy_to_aspm_state(struct pci_dev *pdev) +static int policy_to_aspm_state(struct pcie_link_state *link) { - struct pcie_link_state *link_state = pdev->link_state; - switch (aspm_policy) { case POLICY_PERFORMANCE: /* Disable ASPM and Clock PM */ return 0; case POLICY_POWERSAVE: /* Enable ASPM L0s/L1 */ - return PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1; + return PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1; case POLICY_DEFAULT: - return link_state->bios_aspm_state; + return link->aspm_default; } return 0; } -static int policy_to_clkpm_state(struct pci_dev *pdev) +static int policy_to_clkpm_state(struct pcie_link_state *link) { - struct pcie_link_state *link_state = pdev->link_state; - switch (aspm_policy) { case POLICY_PERFORMANCE: /* Disable ASPM and Clock PM */ @@ -107,73 +99,78 @@ static int policy_to_clkpm_state(struct pci_dev *pdev) /* Disable Clock PM */ return 1; case POLICY_DEFAULT: - return link_state->bios_clk_state; + return link->clkpm_default; } return 0; } -static void pcie_set_clock_pm(struct pci_dev *pdev, int enable) +static void pcie_set_clkpm_nocheck(struct pcie_link_state *link, int enable) { - struct pci_dev *child_dev; int pos; u16 reg16; - struct pcie_link_state *link_state = pdev->link_state; + struct pci_dev *child; + struct pci_bus *linkbus = link->pdev->subordinate; - list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { - pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP); + list_for_each_entry(child, &linkbus->devices, bus_list) { + pos = pci_find_capability(child, PCI_CAP_ID_EXP); if (!pos) return; - pci_read_config_word(child_dev, pos + PCI_EXP_LNKCTL, ®16); + pci_read_config_word(child, pos + PCI_EXP_LNKCTL, ®16); if (enable) reg16 |= PCI_EXP_LNKCTL_CLKREQ_EN; else reg16 &= ~PCI_EXP_LNKCTL_CLKREQ_EN; - pci_write_config_word(child_dev, pos + PCI_EXP_LNKCTL, reg16); + pci_write_config_word(child, pos + PCI_EXP_LNKCTL, reg16); } - link_state->clk_pm_enabled = !!enable; + link->clkpm_enabled = !!enable; } -static void pcie_check_clock_pm(struct pci_dev *pdev, int blacklist) +static void pcie_set_clkpm(struct pcie_link_state *link, int enable) { - int pos; + /* Don't enable Clock PM if the link is not Clock PM capable */ + if (!link->clkpm_capable && enable) + return; + /* Need nothing if the specified equals to current state */ + if (link->clkpm_enabled == enable) + return; + pcie_set_clkpm_nocheck(link, enable); +} + +static void pcie_clkpm_cap_init(struct pcie_link_state *link, int blacklist) +{ + int pos, capable = 1, enabled = 1; u32 reg32; u16 reg16; - int capable = 1, enabled = 1; - struct pci_dev *child_dev; - struct pcie_link_state *link_state = pdev->link_state; + struct pci_dev *child; + struct pci_bus *linkbus = link->pdev->subordinate; /* All functions should have the same cap and state, take the worst */ - list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { - pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP); + list_for_each_entry(child, &linkbus->devices, bus_list) { + pos = pci_find_capability(child, PCI_CAP_ID_EXP); if (!pos) return; - pci_read_config_dword(child_dev, pos + PCI_EXP_LNKCAP, ®32); + pci_read_config_dword(child, pos + PCI_EXP_LNKCAP, ®32); if (!(reg32 & PCI_EXP_LNKCAP_CLKPM)) { capable = 0; enabled = 0; break; } - pci_read_config_word(child_dev, pos + PCI_EXP_LNKCTL, ®16); + pci_read_config_word(child, pos + PCI_EXP_LNKCTL, ®16); if (!(reg16 & PCI_EXP_LNKCTL_CLKREQ_EN)) enabled = 0; } - link_state->clk_pm_enabled = enabled; - link_state->bios_clk_state = enabled; - if (!blacklist) { - link_state->clk_pm_capable = capable; - pcie_set_clock_pm(pdev, policy_to_clkpm_state(pdev)); - } else { - link_state->clk_pm_capable = 0; - pcie_set_clock_pm(pdev, 0); - } + link->clkpm_enabled = enabled; + link->clkpm_default = enabled; + link->clkpm_capable = (blacklist) ? 0 : capable; } -static bool pcie_aspm_downstream_has_switch(struct pci_dev *pdev) +static bool pcie_aspm_downstream_has_switch(struct pcie_link_state *link) { - struct pci_dev *child_dev; + struct pci_dev *child; + struct pci_bus *linkbus = link->pdev->subordinate; - list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { - if (child_dev->pcie_type == PCI_EXP_TYPE_UPSTREAM) + list_for_each_entry(child, &linkbus->devices, bus_list) { + if (child->pcie_type == PCI_EXP_TYPE_UPSTREAM) return true; } return false; @@ -184,289 +181,263 @@ static bool pcie_aspm_downstream_has_switch(struct pci_dev *pdev) * could use common clock. If they are, configure them to use the * common clock. That will reduce the ASPM state exit latency. */ -static void pcie_aspm_configure_common_clock(struct pci_dev *pdev) +static void pcie_aspm_configure_common_clock(struct pcie_link_state *link) { - int pos, child_pos, i = 0; - u16 reg16 = 0; - struct pci_dev *child_dev; - int same_clock = 1; + int ppos, cpos, same_clock = 1; + u16 reg16, parent_reg, child_reg[8]; unsigned long start_jiffies; - u16 child_regs[8], parent_reg; + struct pci_dev *child, *parent = link->pdev; + struct pci_bus *linkbus = parent->subordinate; /* - * all functions of a slot should have the same Slot Clock + * All functions of a slot should have the same Slot Clock * Configuration, so just check one function - * */ - child_dev = list_entry(pdev->subordinate->devices.next, struct pci_dev, - bus_list); - BUG_ON(!child_dev->is_pcie); + */ + child = list_entry(linkbus->devices.next, struct pci_dev, bus_list); + BUG_ON(!child->is_pcie); /* Check downstream component if bit Slot Clock Configuration is 1 */ - child_pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP); - pci_read_config_word(child_dev, child_pos + PCI_EXP_LNKSTA, ®16); + cpos = pci_find_capability(child, PCI_CAP_ID_EXP); + pci_read_config_word(child, cpos + PCI_EXP_LNKSTA, ®16); if (!(reg16 & PCI_EXP_LNKSTA_SLC)) same_clock = 0; /* Check upstream component if bit Slot Clock Configuration is 1 */ - pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); - pci_read_config_word(pdev, pos + PCI_EXP_LNKSTA, ®16); + ppos = pci_find_capability(parent, PCI_CAP_ID_EXP); + pci_read_config_word(parent, ppos + PCI_EXP_LNKSTA, ®16); if (!(reg16 & PCI_EXP_LNKSTA_SLC)) same_clock = 0; /* Configure downstream component, all functions */ - list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { - child_pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP); - pci_read_config_word(child_dev, child_pos + PCI_EXP_LNKCTL, - ®16); - child_regs[i] = reg16; + list_for_each_entry(child, &linkbus->devices, bus_list) { + cpos = pci_find_capability(child, PCI_CAP_ID_EXP); + pci_read_config_word(child, cpos + PCI_EXP_LNKCTL, ®16); + child_reg[PCI_FUNC(child->devfn)] = reg16; if (same_clock) reg16 |= PCI_EXP_LNKCTL_CCC; else reg16 &= ~PCI_EXP_LNKCTL_CCC; - pci_write_config_word(child_dev, child_pos + PCI_EXP_LNKCTL, - reg16); - i++; + pci_write_config_word(child, cpos + PCI_EXP_LNKCTL, reg16); } /* Configure upstream component */ - pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, ®16); + pci_read_config_word(parent, ppos + PCI_EXP_LNKCTL, ®16); parent_reg = reg16; if (same_clock) reg16 |= PCI_EXP_LNKCTL_CCC; else reg16 &= ~PCI_EXP_LNKCTL_CCC; - pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, reg16); + pci_write_config_word(parent, ppos + PCI_EXP_LNKCTL, reg16); - /* retrain link */ + /* Retrain link */ reg16 |= PCI_EXP_LNKCTL_RL; - pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, reg16); + pci_write_config_word(parent, ppos + PCI_EXP_LNKCTL, reg16); - /* Wait for link training end */ - /* break out after waiting for timeout */ + /* Wait for link training end. Break out after waiting for timeout */ start_jiffies = jiffies; for (;;) { - pci_read_config_word(pdev, pos + PCI_EXP_LNKSTA, ®16); + pci_read_config_word(parent, ppos + PCI_EXP_LNKSTA, ®16); if (!(reg16 & PCI_EXP_LNKSTA_LT)) break; if (time_after(jiffies, start_jiffies + LINK_RETRAIN_TIMEOUT)) break; msleep(1); } - /* training failed -> recover */ - if (reg16 & PCI_EXP_LNKSTA_LT) { - dev_printk (KERN_ERR, &pdev->dev, "ASPM: Could not configure" - " common clock\n"); - i = 0; - list_for_each_entry(child_dev, &pdev->subordinate->devices, - bus_list) { - child_pos = pci_find_capability(child_dev, - PCI_CAP_ID_EXP); - pci_write_config_word(child_dev, - child_pos + PCI_EXP_LNKCTL, - child_regs[i]); - i++; - } - pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, parent_reg); + if (!(reg16 & PCI_EXP_LNKSTA_LT)) + return; + + /* Training failed. Restore common clock configurations */ + dev_printk(KERN_ERR, &parent->dev, + "ASPM: Could not configure common clock\n"); + list_for_each_entry(child, &linkbus->devices, bus_list) { + cpos = pci_find_capability(child, PCI_CAP_ID_EXP); + pci_write_config_word(child, cpos + PCI_EXP_LNKCTL, + child_reg[PCI_FUNC(child->devfn)]); } + pci_write_config_word(parent, ppos + PCI_EXP_LNKCTL, parent_reg); } -/* - * calc_L0S_latency: Convert L0s latency encoding to ns - */ -static unsigned int calc_L0S_latency(unsigned int latency_encoding, int ac) +/* Convert L0s latency encoding to ns */ +static u32 calc_l0s_latency(u32 encoding) { - unsigned int ns = 64; - - if (latency_encoding == 0x7) { - if (ac) - ns = -1U; - else - ns = 5*1000; /* > 4us */ - } else - ns *= (1 << latency_encoding); - return ns; + if (encoding == 0x7) + return (5 * 1000); /* > 4us */ + return (64 << encoding); } -/* - * calc_L1_latency: Convert L1 latency encoding to ns - */ -static unsigned int calc_L1_latency(unsigned int latency_encoding, int ac) +/* Convert L0s acceptable latency encoding to ns */ +static u32 calc_l0s_acceptable(u32 encoding) { - unsigned int ns = 1000; + if (encoding == 0x7) + return -1U; + return (64 << encoding); +} - if (latency_encoding == 0x7) { - if (ac) - ns = -1U; - else - ns = 65*1000; /* > 64us */ - } else - ns *= (1 << latency_encoding); - return ns; +/* Convert L1 latency encoding to ns */ +static u32 calc_l1_latency(u32 encoding) +{ + if (encoding == 0x7) + return (65 * 1000); /* > 64us */ + return (1000 << encoding); +} + +/* Convert L1 acceptable latency encoding to ns */ +static u32 calc_l1_acceptable(u32 encoding) +{ + if (encoding == 0x7) + return -1U; + return (1000 << encoding); } static void pcie_aspm_get_cap_device(struct pci_dev *pdev, u32 *state, - unsigned int *l0s, unsigned int *l1, unsigned int *enabled) + u32 *l0s, u32 *l1, u32 *enabled) { int pos; u16 reg16; - u32 reg32; - unsigned int latency; + u32 reg32, encoding; + *l0s = *l1 = *enabled = 0; pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); pci_read_config_dword(pdev, pos + PCI_EXP_LNKCAP, ®32); *state = (reg32 & PCI_EXP_LNKCAP_ASPMS) >> 10; if (*state != PCIE_LINK_STATE_L0S && - *state != (PCIE_LINK_STATE_L1|PCIE_LINK_STATE_L0S)) + *state != (PCIE_LINK_STATE_L1 | PCIE_LINK_STATE_L0S)) *state = 0; if (*state == 0) return; - latency = (reg32 & PCI_EXP_LNKCAP_L0SEL) >> 12; - *l0s = calc_L0S_latency(latency, 0); + encoding = (reg32 & PCI_EXP_LNKCAP_L0SEL) >> 12; + *l0s = calc_l0s_latency(encoding); if (*state & PCIE_LINK_STATE_L1) { - latency = (reg32 & PCI_EXP_LNKCAP_L1EL) >> 15; - *l1 = calc_L1_latency(latency, 0); + encoding = (reg32 & PCI_EXP_LNKCAP_L1EL) >> 15; + *l1 = calc_l1_latency(encoding); } pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, ®16); - *enabled = reg16 & (PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1); + *enabled = reg16 & (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1); } -static void pcie_aspm_cap_init(struct pci_dev *pdev) +static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist) { - struct pci_dev *child_dev; - u32 state, tmp; - struct pcie_link_state *link_state = pdev->link_state; + u32 support, l0s, l1, enabled; + struct pci_dev *child, *parent = link->pdev; + struct pci_bus *linkbus = parent->subordinate; + + if (blacklist) { + /* Set support state to 0, so we will disable ASPM later */ + link->aspm_support = 0; + link->aspm_default = 0; + link->aspm_enabled = PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1; + return; + } + + /* Configure common clock before checking latencies */ + pcie_aspm_configure_common_clock(link); /* upstream component states */ - pcie_aspm_get_cap_device(pdev, &link_state->support_state, - &link_state->l0s_upper_latency, - &link_state->l1_upper_latency, - &link_state->enabled_state); + pcie_aspm_get_cap_device(parent, &support, &l0s, &l1, &enabled); + link->aspm_support = support; + link->latency.l0s = l0s; + link->latency.l1 = l1; + link->aspm_enabled = enabled; + /* downstream component states, all functions have the same setting */ - child_dev = list_entry(pdev->subordinate->devices.next, struct pci_dev, - bus_list); - pcie_aspm_get_cap_device(child_dev, &state, - &link_state->l0s_down_latency, - &link_state->l1_down_latency, - &tmp); - link_state->support_state &= state; - if (!link_state->support_state) + child = list_entry(linkbus->devices.next, struct pci_dev, bus_list); + pcie_aspm_get_cap_device(child, &support, &l0s, &l1, &enabled); + link->aspm_support &= support; + link->latency.l0s = max_t(u32, link->latency.l0s, l0s); + link->latency.l1 = max_t(u32, link->latency.l1, l1); + + if (!link->aspm_support) return; - link_state->enabled_state &= link_state->support_state; - link_state->bios_aspm_state = link_state->enabled_state; + + link->aspm_enabled &= link->aspm_support; + link->aspm_default = link->aspm_enabled; /* ENDPOINT states*/ - list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { + list_for_each_entry(child, &linkbus->devices, bus_list) { int pos; - u32 reg32; - unsigned int latency; - struct endpoint_state *ep_state = - &link_state->endpoints[PCI_FUNC(child_dev->devfn)]; + u32 reg32, encoding; + struct aspm_latency *acceptable = + &link->acceptable[PCI_FUNC(child->devfn)]; - if (child_dev->pcie_type != PCI_EXP_TYPE_ENDPOINT && - child_dev->pcie_type != PCI_EXP_TYPE_LEG_END) + if (child->pcie_type != PCI_EXP_TYPE_ENDPOINT && + child->pcie_type != PCI_EXP_TYPE_LEG_END) continue; - pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP); - pci_read_config_dword(child_dev, pos + PCI_EXP_DEVCAP, ®32); - latency = (reg32 & PCI_EXP_DEVCAP_L0S) >> 6; - latency = calc_L0S_latency(latency, 1); - ep_state->l0s_acceptable_latency = latency; - if (link_state->support_state & PCIE_LINK_STATE_L1) { - latency = (reg32 & PCI_EXP_DEVCAP_L1) >> 9; - latency = calc_L1_latency(latency, 1); - ep_state->l1_acceptable_latency = latency; + pos = pci_find_capability(child, PCI_CAP_ID_EXP); + pci_read_config_dword(child, pos + PCI_EXP_DEVCAP, ®32); + encoding = (reg32 & PCI_EXP_DEVCAP_L0S) >> 6; + acceptable->l0s = calc_l0s_acceptable(encoding); + if (link->aspm_support & PCIE_LINK_STATE_L1) { + encoding = (reg32 & PCI_EXP_DEVCAP_L1) >> 9; + acceptable->l1 = calc_l1_acceptable(encoding); } } } -static unsigned int __pcie_aspm_check_state_one(struct pci_dev *pdev, - unsigned int state) +/** + * __pcie_aspm_check_state_one - check latency for endpoint device. + * @endpoint: pointer to the struct pci_dev of endpoint device + * + * TBD: The latency from the endpoint to root complex vary per switch's + * upstream link state above the device. Here we just do a simple check + * which assumes all links above the device can be in L1 state, that + * is we just consider the worst case. If switch's upstream link can't + * be put into L0S/L1, then our check is too strictly. + */ +static u32 __pcie_aspm_check_state_one(struct pci_dev *endpoint, u32 state) { - struct pci_dev *parent_dev, *tmp_dev; - unsigned int latency, l1_latency = 0; - struct pcie_link_state *link_state; - struct endpoint_state *ep_state; + u32 l1_switch_latency = 0; + struct aspm_latency *acceptable; + struct pcie_link_state *link; - parent_dev = pdev->bus->self; - link_state = parent_dev->link_state; - state &= link_state->support_state; - if (state == 0) - return 0; - ep_state = &link_state->endpoints[PCI_FUNC(pdev->devfn)]; + link = endpoint->bus->self->link_state; + state &= link->aspm_support; + acceptable = &link->acceptable[PCI_FUNC(endpoint->devfn)]; - /* - * Check latency for endpoint device. - * TBD: The latency from the endpoint to root complex vary per - * switch's upstream link state above the device. Here we just do a - * simple check which assumes all links above the device can be in L1 - * state, that is we just consider the worst case. If switch's upstream - * link can't be put into L0S/L1, then our check is too strictly. - */ - tmp_dev = pdev; - while (state & (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1)) { - parent_dev = tmp_dev->bus->self; - link_state = parent_dev->link_state; - if (state & PCIE_LINK_STATE_L0S) { - latency = max_t(unsigned int, - link_state->l0s_upper_latency, - link_state->l0s_down_latency); - if (latency > ep_state->l0s_acceptable_latency) - state &= ~PCIE_LINK_STATE_L0S; - } - if (state & PCIE_LINK_STATE_L1) { - latency = max_t(unsigned int, - link_state->l1_upper_latency, - link_state->l1_down_latency); - if (latency + l1_latency > - ep_state->l1_acceptable_latency) - state &= ~PCIE_LINK_STATE_L1; - } - if (!parent_dev->bus->self) /* parent_dev is a root port */ - break; - else { - /* - * parent_dev is the downstream port of a switch, make - * tmp_dev the upstream port of the switch - */ - tmp_dev = parent_dev->bus->self; - /* - * every switch on the path to root complex need 1 more - * microsecond for L1. Spec doesn't mention L0S. - */ - if (state & PCIE_LINK_STATE_L1) - l1_latency += 1000; - } + while (link && state) { + if ((state & PCIE_LINK_STATE_L0S) && + (link->latency.l0s > acceptable->l0s)) + state &= ~PCIE_LINK_STATE_L0S; + if ((state & PCIE_LINK_STATE_L1) && + (link->latency.l1 + l1_switch_latency > acceptable->l1)) + state &= ~PCIE_LINK_STATE_L1; + link = link->parent; + /* + * Every switch on the path to root complex need 1 + * more microsecond for L1. Spec doesn't mention L0s. + */ + l1_switch_latency += 1000; } return state; } -static unsigned int pcie_aspm_check_state(struct pci_dev *pdev, - unsigned int state) +static u32 pcie_aspm_check_state(struct pcie_link_state *link, u32 state) { - struct pci_dev *child_dev; + pci_power_t power_state; + struct pci_dev *child; + struct pci_bus *linkbus = link->pdev->subordinate; /* If no child, ignore the link */ - if (list_empty(&pdev->subordinate->devices)) + if (list_empty(&linkbus->devices)) return state; - list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { - if (child_dev->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) { - /* - * If downstream component of a link is pci bridge, we - * disable ASPM for now for the link - * */ - state = 0; - break; - } - if ((child_dev->pcie_type != PCI_EXP_TYPE_ENDPOINT && - child_dev->pcie_type != PCI_EXP_TYPE_LEG_END)) + + list_for_each_entry(child, &linkbus->devices, bus_list) { + /* + * If downstream component of a link is pci bridge, we + * disable ASPM for now for the link + */ + if (child->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) + return 0; + + if ((child->pcie_type != PCI_EXP_TYPE_ENDPOINT && + child->pcie_type != PCI_EXP_TYPE_LEG_END)) continue; /* Device not in D0 doesn't need check latency */ - if (child_dev->current_state == PCI_D1 || - child_dev->current_state == PCI_D2 || - child_dev->current_state == PCI_D3hot || - child_dev->current_state == PCI_D3cold) + power_state = child->current_state; + if (power_state == PCI_D1 || power_state == PCI_D2 || + power_state == PCI_D3hot || power_state == PCI_D3cold) continue; - state = __pcie_aspm_check_state_one(child_dev, state); + state = __pcie_aspm_check_state_one(child, state); } return state; } @@ -482,90 +453,71 @@ static void __pcie_aspm_config_one_dev(struct pci_dev *pdev, unsigned int state) pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, reg16); } -static void __pcie_aspm_config_link(struct pci_dev *pdev, unsigned int state) +static void __pcie_aspm_config_link(struct pcie_link_state *link, u32 state) { - struct pci_dev *child_dev; - int valid = 1; - struct pcie_link_state *link_state = pdev->link_state; + struct pci_dev *child, *parent = link->pdev; + struct pci_bus *linkbus = parent->subordinate; /* If no child, disable the link */ - if (list_empty(&pdev->subordinate->devices)) + if (list_empty(&linkbus->devices)) state = 0; /* - * if the downstream component has pci bridge function, don't do ASPM - * now + * If the downstream component has pci bridge function, don't + * do ASPM now. */ - list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { - if (child_dev->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) { - valid = 0; - break; - } + list_for_each_entry(child, &linkbus->devices, bus_list) { + if (child->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) + return; } - if (!valid) - return; - /* - * spec 2.0 suggests all functions should be configured the same - * setting for ASPM. Enabling ASPM L1 should be done in upstream - * component first and then downstream, and vice versa for disabling - * ASPM L1. Spec doesn't mention L0S. + * Spec 2.0 suggests all functions should be configured the + * same setting for ASPM. Enabling ASPM L1 should be done in + * upstream component first and then downstream, and vice + * versa for disabling ASPM L1. Spec doesn't mention L0S. */ if (state & PCIE_LINK_STATE_L1) - __pcie_aspm_config_one_dev(pdev, state); + __pcie_aspm_config_one_dev(parent, state); - list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) - __pcie_aspm_config_one_dev(child_dev, state); + list_for_each_entry(child, &linkbus->devices, bus_list) + __pcie_aspm_config_one_dev(child, state); if (!(state & PCIE_LINK_STATE_L1)) - __pcie_aspm_config_one_dev(pdev, state); + __pcie_aspm_config_one_dev(parent, state); - link_state->enabled_state = state; + link->aspm_enabled = state; } -static struct pcie_link_state *get_root_port_link(struct pcie_link_state *link) +/* Check the whole hierarchy, and configure each link in the hierarchy */ +static void __pcie_aspm_configure_link_state(struct pcie_link_state *link, + u32 state) { - struct pcie_link_state *root_port_link = link; - while (root_port_link->parent) - root_port_link = root_port_link->parent; - return root_port_link; -} + struct pcie_link_state *leaf, *root = link->root; -/* check the whole hierarchy, and configure each link in the hierarchy */ -static void __pcie_aspm_configure_link_state(struct pci_dev *pdev, - unsigned int state) -{ - struct pcie_link_state *link_state = pdev->link_state; - struct pcie_link_state *root_port_link = get_root_port_link(link_state); - struct pcie_link_state *leaf; + state &= (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1); - state &= PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1; - - /* check all links who have specific root port link */ - list_for_each_entry(leaf, &link_list, sibiling) { - if (!list_empty(&leaf->children) || - get_root_port_link(leaf) != root_port_link) + /* Check all links who have specific root port link */ + list_for_each_entry(leaf, &link_list, sibling) { + if (!list_empty(&leaf->children) || (leaf->root != root)) continue; - state = pcie_aspm_check_state(leaf->pdev, state); + state = pcie_aspm_check_state(leaf, state); } - /* check root port link too in case it hasn't children */ - state = pcie_aspm_check_state(root_port_link->pdev, state); - - if (link_state->enabled_state == state) + /* Check root port link too in case it hasn't children */ + state = pcie_aspm_check_state(root, state); + if (link->aspm_enabled == state) return; - /* - * we must change the hierarchy. See comments in + * We must change the hierarchy. See comments in * __pcie_aspm_config_link for the order **/ if (state & PCIE_LINK_STATE_L1) { - list_for_each_entry(leaf, &link_list, sibiling) { - if (get_root_port_link(leaf) == root_port_link) - __pcie_aspm_config_link(leaf->pdev, state); + list_for_each_entry(leaf, &link_list, sibling) { + if (leaf->root == root) + __pcie_aspm_config_link(leaf, state); } } else { - list_for_each_entry_reverse(leaf, &link_list, sibiling) { - if (get_root_port_link(leaf) == root_port_link) - __pcie_aspm_config_link(leaf->pdev, state); + list_for_each_entry_reverse(leaf, &link_list, sibling) { + if (leaf->root == root) + __pcie_aspm_config_link(leaf, state); } } } @@ -574,45 +526,42 @@ static void __pcie_aspm_configure_link_state(struct pci_dev *pdev, * pcie_aspm_configure_link_state: enable/disable PCI express link state * @pdev: the root port or switch downstream port */ -static void pcie_aspm_configure_link_state(struct pci_dev *pdev, - unsigned int state) +static void pcie_aspm_configure_link_state(struct pcie_link_state *link, + u32 state) { down_read(&pci_bus_sem); mutex_lock(&aspm_lock); - __pcie_aspm_configure_link_state(pdev, state); + __pcie_aspm_configure_link_state(link, state); mutex_unlock(&aspm_lock); up_read(&pci_bus_sem); } -static void free_link_state(struct pci_dev *pdev) +static void free_link_state(struct pcie_link_state *link) { - kfree(pdev->link_state); - pdev->link_state = NULL; + link->pdev->link_state = NULL; + kfree(link); } static int pcie_aspm_sanity_check(struct pci_dev *pdev) { - struct pci_dev *child_dev; - int child_pos; + struct pci_dev *child; + int pos; u32 reg32; - /* - * Some functions in a slot might not all be PCIE functions, very - * strange. Disable ASPM for the whole slot + * Some functions in a slot might not all be PCIE functions, + * very strange. Disable ASPM for the whole slot */ - list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { - child_pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP); - if (!child_pos) + list_for_each_entry(child, &pdev->subordinate->devices, bus_list) { + pos = pci_find_capability(child, PCI_CAP_ID_EXP); + if (!pos) return -EINVAL; - /* * Disable ASPM for pre-1.1 PCIe device, we follow MS to use * RBER bit to determine if a function is 1.1 version device */ - pci_read_config_dword(child_dev, child_pos + PCI_EXP_DEVCAP, - ®32); + pci_read_config_dword(child, pos + PCI_EXP_DEVCAP, ®32); if (!(reg32 & PCI_EXP_DEVCAP_RBER) && !aspm_force) { - dev_printk(KERN_INFO, &child_dev->dev, "disabling ASPM" + dev_printk(KERN_INFO, &child->dev, "disabling ASPM" " on pre-1.1 PCIe device. You can enable it" " with 'pcie_aspm=force'\n"); return -EINVAL; @@ -621,6 +570,47 @@ static int pcie_aspm_sanity_check(struct pci_dev *pdev) return 0; } +static struct pcie_link_state *pcie_aspm_setup_link_state(struct pci_dev *pdev) +{ + struct pcie_link_state *link; + int blacklist = !!pcie_aspm_sanity_check(pdev); + + link = kzalloc(sizeof(*link), GFP_KERNEL); + if (!link) + return NULL; + INIT_LIST_HEAD(&link->sibling); + INIT_LIST_HEAD(&link->children); + INIT_LIST_HEAD(&link->link); + link->pdev = pdev; + if (pdev->pcie_type == PCI_EXP_TYPE_DOWNSTREAM) { + struct pcie_link_state *parent; + parent = pdev->bus->parent->self->link_state; + if (!parent) { + kfree(link); + return NULL; + } + link->parent = parent; + list_add(&link->link, &parent->children); + } + /* Setup a pointer to the root port link */ + if (!link->parent) + link->root = link; + else + link->root = link->parent->root; + + list_add(&link->sibling, &link_list); + + pdev->link_state = link; + + /* Check ASPM capability */ + pcie_aspm_cap_init(link, blacklist); + + /* Check Clock PM capability */ + pcie_clkpm_cap_init(link, blacklist); + + return link; +} + /* * pcie_aspm_init_link_state: Initiate PCI express link state. * It is called after the pcie and its children devices are scaned. @@ -628,75 +618,47 @@ static int pcie_aspm_sanity_check(struct pci_dev *pdev) */ void pcie_aspm_init_link_state(struct pci_dev *pdev) { - unsigned int state; - struct pcie_link_state *link_state; - int error = 0; - int blacklist; + u32 state; + struct pcie_link_state *link; if (aspm_disabled || !pdev->is_pcie || pdev->link_state) return; if (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT && - pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) + pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) return; + + /* VIA has a strange chipset, root port is under a bridge */ + if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT && + pdev->bus->self) + return; + down_read(&pci_bus_sem); if (list_empty(&pdev->subordinate->devices)) goto out; - blacklist = !!pcie_aspm_sanity_check(pdev); - mutex_lock(&aspm_lock); - - link_state = kzalloc(sizeof(*link_state), GFP_KERNEL); - if (!link_state) - goto unlock_out; - - link_state->downstream_has_switch = pcie_aspm_downstream_has_switch(pdev); - INIT_LIST_HEAD(&link_state->children); - INIT_LIST_HEAD(&link_state->link); - if (pdev->bus->self) {/* this is a switch */ - struct pcie_link_state *parent_link_state; - - parent_link_state = pdev->bus->parent->self->link_state; - if (!parent_link_state) { - kfree(link_state); - goto unlock_out; - } - list_add(&link_state->link, &parent_link_state->children); - link_state->parent = parent_link_state; - } - - pdev->link_state = link_state; - - if (!blacklist) { - pcie_aspm_configure_common_clock(pdev); - pcie_aspm_cap_init(pdev); + link = pcie_aspm_setup_link_state(pdev); + if (!link) + goto unlock; + /* + * Setup initial ASPM state + * + * If link has switch, delay the link config. The leaf link + * initialization will config the whole hierarchy. But we must + * make sure BIOS doesn't set unsupported link state. + */ + if (pcie_aspm_downstream_has_switch(link)) { + state = pcie_aspm_check_state(link, link->aspm_default); + __pcie_aspm_config_link(link, state); } else { - link_state->enabled_state = PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1; - link_state->bios_aspm_state = 0; - /* Set support state to 0, so we will disable ASPM later */ - link_state->support_state = 0; + state = policy_to_aspm_state(link); + __pcie_aspm_configure_link_state(link, state); } - link_state->pdev = pdev; - list_add(&link_state->sibiling, &link_list); - - if (link_state->downstream_has_switch) { - /* - * If link has switch, delay the link config. The leaf link - * initialization will config the whole hierarchy. but we must - * make sure BIOS doesn't set unsupported link state - **/ - state = pcie_aspm_check_state(pdev, link_state->bios_aspm_state); - __pcie_aspm_config_link(pdev, state); - } else - __pcie_aspm_configure_link_state(pdev, - policy_to_aspm_state(pdev)); - - pcie_check_clock_pm(pdev, blacklist); - -unlock_out: - if (error) - free_link_state(pdev); + /* Setup initial Clock PM state */ + state = (link->clkpm_capable) ? policy_to_clkpm_state(link) : 0; + pcie_set_clkpm(link, state); +unlock: mutex_unlock(&aspm_lock); out: up_read(&pci_bus_sem); @@ -725,11 +687,11 @@ void pcie_aspm_exit_link_state(struct pci_dev *pdev) /* All functions are removed, so just disable ASPM for the link */ __pcie_aspm_config_one_dev(parent, 0); - list_del(&link_state->sibiling); + list_del(&link_state->sibling); list_del(&link_state->link); /* Clock PM is for endpoint device */ - free_link_state(parent); + free_link_state(link_state); out: mutex_unlock(&aspm_lock); up_read(&pci_bus_sem); @@ -749,7 +711,7 @@ void pcie_aspm_pm_state_change(struct pci_dev *pdev) * devices changed PM state, we should recheck if latency meets all * functions' requirement */ - pcie_aspm_configure_link_state(pdev, link_state->enabled_state); + pcie_aspm_configure_link_state(link_state, link_state->aspm_enabled); } /* @@ -772,14 +734,12 @@ void pci_disable_link_state(struct pci_dev *pdev, int state) down_read(&pci_bus_sem); mutex_lock(&aspm_lock); link_state = parent->link_state; - link_state->support_state &= - ~(state & (PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1)); - if (state & PCIE_LINK_STATE_CLKPM) - link_state->clk_pm_capable = 0; - - __pcie_aspm_configure_link_state(parent, link_state->enabled_state); - if (!link_state->clk_pm_capable && link_state->clk_pm_enabled) - pcie_set_clock_pm(parent, 0); + link_state->aspm_support &= ~state; + __pcie_aspm_configure_link_state(link_state, link_state->aspm_enabled); + if (state & PCIE_LINK_STATE_CLKPM) { + link_state->clkpm_capable = 0; + pcie_set_clkpm(link_state, 0); + } mutex_unlock(&aspm_lock); up_read(&pci_bus_sem); } @@ -788,7 +748,6 @@ EXPORT_SYMBOL(pci_disable_link_state); static int pcie_aspm_set_policy(const char *val, struct kernel_param *kp) { int i; - struct pci_dev *pdev; struct pcie_link_state *link_state; for (i = 0; i < ARRAY_SIZE(policy_str); i++) @@ -802,14 +761,10 @@ static int pcie_aspm_set_policy(const char *val, struct kernel_param *kp) down_read(&pci_bus_sem); mutex_lock(&aspm_lock); aspm_policy = i; - list_for_each_entry(link_state, &link_list, sibiling) { - pdev = link_state->pdev; - __pcie_aspm_configure_link_state(pdev, - policy_to_aspm_state(pdev)); - if (link_state->clk_pm_capable && - link_state->clk_pm_enabled != policy_to_clkpm_state(pdev)) - pcie_set_clock_pm(pdev, policy_to_clkpm_state(pdev)); - + list_for_each_entry(link_state, &link_list, sibling) { + __pcie_aspm_configure_link_state(link_state, + policy_to_aspm_state(link_state)); + pcie_set_clkpm(link_state, policy_to_clkpm_state(link_state)); } mutex_unlock(&aspm_lock); up_read(&pci_bus_sem); @@ -838,7 +793,7 @@ static ssize_t link_state_show(struct device *dev, struct pci_dev *pci_device = to_pci_dev(dev); struct pcie_link_state *link_state = pci_device->link_state; - return sprintf(buf, "%d\n", link_state->enabled_state); + return sprintf(buf, "%d\n", link_state->aspm_enabled); } static ssize_t link_state_store(struct device *dev, @@ -846,7 +801,7 @@ static ssize_t link_state_store(struct device *dev, const char *buf, size_t n) { - struct pci_dev *pci_device = to_pci_dev(dev); + struct pci_dev *pdev = to_pci_dev(dev); int state; if (n < 1) @@ -854,7 +809,7 @@ static ssize_t link_state_store(struct device *dev, state = buf[0]-'0'; if (state >= 0 && state <= 3) { /* setup link aspm state */ - pcie_aspm_configure_link_state(pci_device, state); + pcie_aspm_configure_link_state(pdev->link_state, state); return n; } @@ -868,7 +823,7 @@ static ssize_t clk_ctl_show(struct device *dev, struct pci_dev *pci_device = to_pci_dev(dev); struct pcie_link_state *link_state = pci_device->link_state; - return sprintf(buf, "%d\n", link_state->clk_pm_enabled); + return sprintf(buf, "%d\n", link_state->clkpm_enabled); } static ssize_t clk_ctl_store(struct device *dev, @@ -876,7 +831,7 @@ static ssize_t clk_ctl_store(struct device *dev, const char *buf, size_t n) { - struct pci_dev *pci_device = to_pci_dev(dev); + struct pci_dev *pdev = to_pci_dev(dev); int state; if (n < 1) @@ -885,7 +840,7 @@ static ssize_t clk_ctl_store(struct device *dev, down_read(&pci_bus_sem); mutex_lock(&aspm_lock); - pcie_set_clock_pm(pci_device, !!state); + pcie_set_clkpm_nocheck(pdev->link_state, !!state); mutex_unlock(&aspm_lock); up_read(&pci_bus_sem); @@ -904,10 +859,10 @@ void pcie_aspm_create_sysfs_dev_files(struct pci_dev *pdev) pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) || !link_state) return; - if (link_state->support_state) + if (link_state->aspm_support) sysfs_add_file_to_group(&pdev->dev.kobj, &dev_attr_link_state.attr, power_group); - if (link_state->clk_pm_capable) + if (link_state->clkpm_capable) sysfs_add_file_to_group(&pdev->dev.kobj, &dev_attr_clk_ctl.attr, power_group); } @@ -920,10 +875,10 @@ void pcie_aspm_remove_sysfs_dev_files(struct pci_dev *pdev) pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) || !link_state) return; - if (link_state->support_state) + if (link_state->aspm_support) sysfs_remove_file_from_group(&pdev->dev.kobj, &dev_attr_link_state.attr, power_group); - if (link_state->clk_pm_capable) + if (link_state->clkpm_capable) sysfs_remove_file_from_group(&pdev->dev.kobj, &dev_attr_clk_ctl.attr, power_group); } diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c index e39982503863..13ffdc35ea0e 100644 --- a/drivers/pci/pcie/portdrv_core.c +++ b/drivers/pci/pcie/portdrv_core.c @@ -275,7 +275,7 @@ static void pcie_device_init(struct pci_dev *parent, struct pcie_device *dev, memset(device, 0, sizeof(struct device)); device->bus = &pcie_port_bus_type; device->driver = NULL; - device->driver_data = NULL; + dev_set_drvdata(device, NULL); device->release = release_pcie_device; /* callback to free pcie dev */ dev_set_name(device, "%s:pcie%02x", pci_name(parent), get_descriptor_id(port_type, service_type)); diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index f1ae2475ffff..40e75f6a5056 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -193,7 +193,7 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, res->flags |= pci_calc_resource_flags(l) | IORESOURCE_SIZEALIGN; if (type == pci_bar_io) { l &= PCI_BASE_ADDRESS_IO_MASK; - mask = PCI_BASE_ADDRESS_IO_MASK & 0xffff; + mask = PCI_BASE_ADDRESS_IO_MASK & IO_SPACE_LIMIT; } else { l &= PCI_BASE_ADDRESS_MEM_MASK; mask = (u32)PCI_BASE_ADDRESS_MEM_MASK; @@ -237,6 +237,8 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, dev_printk(KERN_DEBUG, &dev->dev, "reg %x 64bit mmio: %pR\n", pos, res); } + + res->flags |= IORESOURCE_MEM_64; } else { sz = pci_size(l, sz, mask); @@ -287,7 +289,7 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child) struct resource *res; int i; - if (!child->parent) /* It's a host bus, nothing to read */ + if (pci_is_root_bus(child)) /* It's a host bus, nothing to read */ return; if (dev->transparent) { @@ -362,7 +364,10 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child) } } if (base <= limit) { - res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM | IORESOURCE_PREFETCH; + res->flags = (mem_base_lo & PCI_PREF_RANGE_TYPE_MASK) | + IORESOURCE_MEM | IORESOURCE_PREFETCH; + if (res->flags & PCI_PREF_RANGE_TYPE_64) + res->flags |= IORESOURCE_MEM_64; res->start = base; res->end = limit + 0xfffff; dev_printk(KERN_DEBUG, &dev->dev, "bridge %sbit mmio pref: %pR\n", diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 3067673d54f6..56552d74abea 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -1133,6 +1133,7 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev) switch (dev->subsystem_device) { case 0x1751: /* M2N notebook */ case 0x1821: /* M5N notebook */ + case 0x1897: /* A6L notebook */ asus_hides_smbus = 1; } else if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB) @@ -1163,6 +1164,7 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev) switch (dev->subsystem_device) { case 0x12bc: /* HP D330L */ case 0x12bd: /* HP D530 */ + case 0x006a: /* HP Compaq nx9500 */ asus_hides_smbus = 1; } else if (dev->device == PCI_DEVICE_ID_INTEL_82875_HB) @@ -2016,6 +2018,28 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5709S, quirk_brcm_570x_limit_vpd); +/* Originally in EDAC sources for i82875P: + * Intel tells BIOS developers to hide device 6 which + * configures the overflow device access containing + * the DRBs - this is where we expose device 6. + * http://www.x86-secret.com/articles/tweak/pat/patsecrets-2.htm + */ +static void __devinit quirk_unhide_mch_dev6(struct pci_dev *dev) +{ + u8 reg; + + if (pci_read_config_byte(dev, 0xF4, ®) == 0 && !(reg & 0x02)) { + dev_info(&dev->dev, "Enabling MCH 'Overflow' Device\n"); + pci_write_config_byte(dev, 0xF4, reg | 0x02); + } +} + +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82865_HB, + quirk_unhide_mch_dev6); +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82875_HB, + quirk_unhide_mch_dev6); + + #ifdef CONFIG_PCI_MSI /* Some chipsets do not support MSI. We cannot easily rely on setting * PCI_BUS_FLAGS_NO_MSI in its bus flags because there are actually @@ -2461,6 +2485,8 @@ static void __devinit quirk_i82576_sriov(struct pci_dev *dev) DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x10c9, quirk_i82576_sriov); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x10e6, quirk_i82576_sriov); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x10e7, quirk_i82576_sriov); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x10e8, quirk_i82576_sriov); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x150a, quirk_i82576_sriov); #endif /* CONFIG_PCI_IOV */ diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c index 86503c14ce7e..176615e7231f 100644 --- a/drivers/pci/remove.c +++ b/drivers/pci/remove.c @@ -32,8 +32,6 @@ static void pci_stop_dev(struct pci_dev *dev) static void pci_destroy_dev(struct pci_dev *dev) { - pci_stop_dev(dev); - /* Remove the device from the device lists, and prevent any further * list accesses from this device */ down_write(&pci_bus_sem); diff --git a/drivers/pci/search.c b/drivers/pci/search.c index 710d4ea69568..e8cb5051c311 100644 --- a/drivers/pci/search.c +++ b/drivers/pci/search.c @@ -29,7 +29,7 @@ pci_find_upstream_pcie_bridge(struct pci_dev *pdev) if (pdev->is_pcie) return NULL; while (1) { - if (!pdev->bus->parent) + if (pci_is_root_bus(pdev->bus)) break; pdev = pdev->bus->self; /* a p2p bridge */ @@ -114,36 +114,6 @@ pci_find_next_bus(const struct pci_bus *from) } #ifdef CONFIG_PCI_LEGACY -/** - * pci_find_slot - locate PCI device from a given PCI slot - * @bus: number of PCI bus on which desired PCI device resides - * @devfn: encodes number of PCI slot in which the desired PCI - * device resides and the logical device number within that slot - * in case of multi-function devices. - * - * Given a PCI bus and slot/function number, the desired PCI device - * is located in system global list of PCI devices. If the device - * is found, a pointer to its data structure is returned. If no - * device is found, %NULL is returned. - * - * NOTE: Do not use this function any more; use pci_get_slot() instead, as - * the PCI device returned by this function can disappear at any moment in - * time. - */ -struct pci_dev *pci_find_slot(unsigned int bus, unsigned int devfn) -{ - struct pci_dev *dev = NULL; - - while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { - if (dev->bus->number == bus && dev->devfn == devfn) { - pci_dev_put(dev); - return dev; - } - } - return NULL; -} -EXPORT_SYMBOL(pci_find_slot); - /** * pci_find_device - begin or continue searching for a PCI device by vendor/device id * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index a00f85471b6e..b636e245445d 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -58,7 +58,6 @@ static void pbus_assign_resources_sorted(const struct pci_bus *bus) res = list->res; idx = res - &list->dev->resource[0]; if (pci_assign_resource(list->dev, idx)) { - /* FIXME: get rid of this */ res->start = 0; res->end = 0; res->flags = 0; @@ -143,6 +142,7 @@ static void pci_setup_bridge(struct pci_bus *bus) struct pci_dev *bridge = bus->self; struct pci_bus_region region; u32 l, bu, lu, io_upper16; + int pref_mem64; if (pci_is_enabled(bridge)) return; @@ -198,16 +198,22 @@ static void pci_setup_bridge(struct pci_bus *bus) pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, 0); /* Set up PREF base/limit. */ + pref_mem64 = 0; bu = lu = 0; pcibios_resource_to_bus(bridge, ®ion, bus->resource[2]); if (bus->resource[2]->flags & IORESOURCE_PREFETCH) { + int width = 8; l = (region.start >> 16) & 0xfff0; l |= region.end & 0xfff00000; - bu = upper_32_bits(region.start); - lu = upper_32_bits(region.end); - dev_info(&bridge->dev, " PREFETCH window: %#016llx-%#016llx\n", - (unsigned long long)region.start, - (unsigned long long)region.end); + if (bus->resource[2]->flags & IORESOURCE_MEM_64) { + pref_mem64 = 1; + bu = upper_32_bits(region.start); + lu = upper_32_bits(region.end); + width = 16; + } + dev_info(&bridge->dev, " PREFETCH window: %#0*llx-%#0*llx\n", + width, (unsigned long long)region.start, + width, (unsigned long long)region.end); } else { l = 0x0000fff0; @@ -215,9 +221,11 @@ static void pci_setup_bridge(struct pci_bus *bus) } pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l); - /* Set the upper 32 bits of PREF base & limit. */ - pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, bu); - pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, lu); + if (pref_mem64) { + /* Set the upper 32 bits of PREF base & limit. */ + pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, bu); + pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, lu); + } pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, bus->bridge_ctl); } @@ -255,8 +263,25 @@ static void pci_bridge_check_ranges(struct pci_bus *bus) pci_read_config_dword(bridge, PCI_PREF_MEMORY_BASE, &pmem); pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, 0x0); } - if (pmem) + if (pmem) { b_res[2].flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH; + if ((pmem & PCI_PREF_RANGE_TYPE_MASK) == PCI_PREF_RANGE_TYPE_64) + b_res[2].flags |= IORESOURCE_MEM_64; + } + + /* double check if bridge does support 64 bit pref */ + if (b_res[2].flags & IORESOURCE_MEM_64) { + u32 mem_base_hi, tmp; + pci_read_config_dword(bridge, PCI_PREF_BASE_UPPER32, + &mem_base_hi); + pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, + 0xffffffff); + pci_read_config_dword(bridge, PCI_PREF_BASE_UPPER32, &tmp); + if (!tmp) + b_res[2].flags &= ~IORESOURCE_MEM_64; + pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, + mem_base_hi); + } } /* Helper function for sizing routines: find first available @@ -336,6 +361,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long resource_size_t aligns[12]; /* Alignments from 1Mb to 2Gb */ int order, max_order; struct resource *b_res = find_free_bus_resource(bus, type); + unsigned int mem64_mask = 0; if (!b_res) return 0; @@ -344,9 +370,12 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long max_order = 0; size = 0; + mem64_mask = b_res->flags & IORESOURCE_MEM_64; + b_res->flags &= ~IORESOURCE_MEM_64; + list_for_each_entry(dev, &bus->devices, bus_list) { int i; - + for (i = 0; i < PCI_NUM_RESOURCES; i++) { struct resource *r = &dev->resource[i]; resource_size_t r_size; @@ -372,6 +401,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long aligns[order] += align; if (order > max_order) max_order = order; + mem64_mask &= r->flags & IORESOURCE_MEM_64; } } @@ -396,6 +426,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long b_res->start = min_align; b_res->end = size + min_align - 1; b_res->flags |= IORESOURCE_STARTALIGN; + b_res->flags |= mem64_mask; return 1; } diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c index 3039fcb86afc..b711fb7181e2 100644 --- a/drivers/pci/setup-res.c +++ b/drivers/pci/setup-res.c @@ -99,11 +99,11 @@ void pci_update_resource(struct pci_dev *dev, int resno) int pci_claim_resource(struct pci_dev *dev, int resource) { struct resource *res = &dev->resource[resource]; - struct resource *root = NULL; + struct resource *root; char *dtype = resource < PCI_BRIDGE_RESOURCES ? "device" : "bridge"; int err; - root = pcibios_select_root(dev, res); + root = pci_find_parent_resource(dev, res); err = -EINVAL; if (root != NULL) @@ -135,23 +135,16 @@ void pci_disable_bridge_window(struct pci_dev *dev) } #endif /* CONFIG_PCI_QUIRKS */ -int pci_assign_resource(struct pci_dev *dev, int resno) +static int __pci_assign_resource(struct pci_bus *bus, struct pci_dev *dev, + int resno) { - struct pci_bus *bus = dev->bus; struct resource *res = dev->resource + resno; resource_size_t size, min, align; int ret; size = resource_size(res); min = (res->flags & IORESOURCE_IO) ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM; - align = resource_alignment(res); - if (!align) { - dev_info(&dev->dev, "BAR %d: can't allocate resource (bogus " - "alignment) %pR flags %#lx\n", - resno, res, res->flags); - return -EINVAL; - } /* First, try exact prefetching match.. */ ret = pci_bus_alloc_resource(bus, res, size, align, min, @@ -169,10 +162,7 @@ int pci_assign_resource(struct pci_dev *dev, int resno) pcibios_align_resource, dev); } - if (ret) { - dev_info(&dev->dev, "BAR %d: can't allocate %s resource %pR\n", - resno, res->flags & IORESOURCE_IO ? "I/O" : "mem", res); - } else { + if (!ret) { res->flags &= ~IORESOURCE_STARTALIGN; if (resno < PCI_BRIDGE_RESOURCES) pci_update_resource(dev, resno); @@ -181,6 +171,39 @@ int pci_assign_resource(struct pci_dev *dev, int resno) return ret; } +int pci_assign_resource(struct pci_dev *dev, int resno) +{ + struct resource *res = dev->resource + resno; + resource_size_t align; + struct pci_bus *bus; + int ret; + + align = resource_alignment(res); + if (!align) { + dev_info(&dev->dev, "BAR %d: can't allocate resource (bogus " + "alignment) %pR flags %#lx\n", + resno, res, res->flags); + return -EINVAL; + } + + bus = dev->bus; + while ((ret = __pci_assign_resource(bus, dev, resno))) { + if (bus->parent && bus->self->transparent) + bus = bus->parent; + else + bus = NULL; + if (bus) + continue; + break; + } + + if (ret) + dev_info(&dev->dev, "BAR %d: can't allocate %s resource %pR\n", + resno, res->flags & IORESOURCE_IO ? "I/O" : "mem", res); + + return ret; +} + #if 0 int pci_assign_resource_fixed(struct pci_dev *dev, int resno) { diff --git a/drivers/pci/slot.c b/drivers/pci/slot.c index fe95ce20bcbd..eddb0748b0ea 100644 --- a/drivers/pci/slot.c +++ b/drivers/pci/slot.c @@ -307,6 +307,45 @@ void pci_destroy_slot(struct pci_slot *slot) } EXPORT_SYMBOL_GPL(pci_destroy_slot); +#if defined(CONFIG_HOTPLUG_PCI) || defined(CONFIG_HOTPLUG_PCI_MODULE) +#include +/** + * pci_hp_create_link - create symbolic link to the hotplug driver module. + * @slot: struct pci_slot + * + * Helper function for pci_hotplug_core.c to create symbolic link to + * the hotplug driver module. + */ +void pci_hp_create_module_link(struct pci_slot *pci_slot) +{ + struct hotplug_slot *slot = pci_slot->hotplug; + struct kobject *kobj = NULL; + int no_warn; + + if (!slot || !slot->ops) + return; + kobj = kset_find_obj(module_kset, slot->ops->mod_name); + if (!kobj) + return; + no_warn = sysfs_create_link(&pci_slot->kobj, kobj, "module"); + kobject_put(kobj); +} +EXPORT_SYMBOL_GPL(pci_hp_create_module_link); + +/** + * pci_hp_remove_link - remove symbolic link to the hotplug driver module. + * @slot: struct pci_slot + * + * Helper function for pci_hotplug_core.c to remove symbolic link to + * the hotplug driver module. + */ +void pci_hp_remove_module_link(struct pci_slot *pci_slot) +{ + sysfs_remove_link(&pci_slot->kobj, "module"); +} +EXPORT_SYMBOL_GPL(pci_hp_remove_module_link); +#endif + static int pci_slot_init(void) { struct kset *pci_bus_kset; diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig index 276473543982..fbf965b31c14 100644 --- a/drivers/pcmcia/Kconfig +++ b/drivers/pcmcia/Kconfig @@ -217,7 +217,7 @@ config PCMCIA_PXA2XX depends on ARM && ARCH_PXA && PCMCIA depends on (ARCH_LUBBOCK || MACH_MAINSTONE || PXA_SHARPSL \ || MACH_ARMCORE || ARCH_PXA_PALM || TRIZEPS_PCMCIA \ - || ARCH_VIPER || ARCH_PXA_ESERIES) + || ARCH_VIPER || ARCH_PXA_ESERIES || MACH_STARGATE2) help Say Y here to include support for the PXA2xx PCMCIA controller diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile index bbac46327227..047394d98ac2 100644 --- a/drivers/pcmcia/Makefile +++ b/drivers/pcmcia/Makefile @@ -73,5 +73,6 @@ pxa2xx-obj-$(CONFIG_TRIZEPS_PCMCIA) += pxa2xx_trizeps4.o pxa2xx-obj-$(CONFIG_MACH_PALMTX) += pxa2xx_palmtx.o pxa2xx-obj-$(CONFIG_MACH_PALMLD) += pxa2xx_palmld.o pxa2xx-obj-$(CONFIG_MACH_E740) += pxa2xx_e740.o +pxa2xx-obj-$(CONFIG_MACH_STARGATE2) += pxa2xx_stargate2.o obj-$(CONFIG_PCMCIA_PXA2XX) += pxa2xx_core.o $(pxa2xx-obj-y) diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 47cab31ff6e4..304ff6d5cf3b 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -394,7 +394,7 @@ static int pcmcia_device_probe(struct device * dev) p_drv = to_pcmcia_drv(dev->driver); s = p_dev->socket; - /* The PCMCIA code passes the match data in via dev->driver_data + /* The PCMCIA code passes the match data in via dev_set_drvdata(dev) * which is an ugly hack. Once the driver probe is called it may * and often will overwrite the match data so we must save it first * @@ -404,7 +404,7 @@ static int pcmcia_device_probe(struct device * dev) * call which will then check whether there are two * pseudo devices, and if not, add the second one. */ - did = p_dev->dev.driver_data; + did = dev_get_drvdata(&p_dev->dev); ds_dev_dbg(1, dev, "trying to bind to %s\n", p_drv->drv.name); @@ -499,7 +499,7 @@ static int pcmcia_device_remove(struct device * dev) * pseudo multi-function card, we need to unbind * all devices */ - did = p_dev->dev.driver_data; + did = dev_get_drvdata(&p_dev->dev); if (did && (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) && (p_dev->socket->device_count != 0) && (p_dev->device_no == 0)) @@ -828,7 +828,6 @@ static int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename) { struct pcmcia_socket *s = dev->socket; const struct firmware *fw; - char path[FIRMWARE_NAME_MAX]; int ret = -ENOMEM; int no_funcs; int old_funcs; @@ -839,16 +838,7 @@ static int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename) ds_dev_dbg(1, &dev->dev, "trying to load CIS file %s\n", filename); - if (strlen(filename) > (FIRMWARE_NAME_MAX - 1)) { - dev_printk(KERN_WARNING, &dev->dev, - "pcmcia: CIS filename is too long [%s]\n", - filename); - return -EINVAL; - } - - snprintf(path, sizeof(path), "%s", filename); - - if (request_firmware(&fw, path, &dev->dev) == 0) { + if (request_firmware(&fw, filename, &dev->dev) == 0) { if (fw->size >= CISTPL_MAX_CIS_SIZE) { ret = -EINVAL; dev_printk(KERN_ERR, &dev->dev, @@ -988,7 +978,7 @@ static inline int pcmcia_devmatch(struct pcmcia_device *dev, return 0; } - dev->dev.driver_data = (void *) did; + dev_set_drvdata(&dev->dev, did); return 1; } diff --git a/drivers/pcmcia/pcmcia_ioctl.c b/drivers/pcmcia/pcmcia_ioctl.c index 1703b20cad5d..6095f8daecd7 100644 --- a/drivers/pcmcia/pcmcia_ioctl.c +++ b/drivers/pcmcia/pcmcia_ioctl.c @@ -915,12 +915,9 @@ static int ds_ioctl(struct inode * inode, struct file * file, err = -EPERM; goto free_out; } else { - static int printed = 0; - if (!printed) { - printk(KERN_WARNING "2.6. kernels use pcmciamtd instead of memory_cs.c and do not require special\n"); - printk(KERN_WARNING "MTD handling any more.\n"); - printed++; - } + printk_once(KERN_WARNING + "2.6. kernels use pcmciamtd instead of memory_cs.c and do not require special\n"); + printk_once(KERN_WARNING "MTD handling any more.\n"); } err = -EINVAL; goto free_out; diff --git a/drivers/pcmcia/pxa2xx_stargate2.c b/drivers/pcmcia/pxa2xx_stargate2.c new file mode 100644 index 000000000000..490749ea677f --- /dev/null +++ b/drivers/pcmcia/pxa2xx_stargate2.c @@ -0,0 +1,174 @@ +/* + * linux/drivers/pcmcia/pxa2xx_stargate2.c + * + * Stargate 2 PCMCIA specific routines. + * + * Created: December 6, 2005 + * Author: Ed C. Epp + * Copyright: Intel Corp 2005 + * Jonathan Cameron 2009 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "soc_common.h" + +#define SG2_S0_BUFF_CTL 120 +#define SG2_S0_POWER_CTL 108 +#define SG2_S0_GPIO_RESET 82 +#define SG2_S0_GPIO_DETECT 53 +#define SG2_S0_GPIO_READY 81 + +static struct pcmcia_irqs irqs[] = { + { 0, IRQ_GPIO(SG2_S0_GPIO_DETECT), "PCMCIA0 CD" }, +}; + +static int sg2_pcmcia_hw_init(struct soc_pcmcia_socket *skt) +{ + skt->irq = IRQ_GPIO(SG2_S0_GPIO_READY); + return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); +} + +static void sg2_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) +{ + soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs)); +} + +static void sg2_pcmcia_socket_state(struct soc_pcmcia_socket *skt, + struct pcmcia_state *state) +{ + state->detect = !gpio_get_value(SG2_S0_GPIO_DETECT); + state->ready = !!gpio_get_value(SG2_S0_GPIO_READY); + state->bvd1 = 0; /* not available - battery detect on card */ + state->bvd2 = 0; /* not available */ + state->vs_3v = 1; /* not available - voltage detect for card */ + state->vs_Xv = 0; /* not available */ + state->wrprot = 0; /* not available - write protect */ +} + +static int sg2_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, + const socket_state_t *state) +{ + /* Enable card power */ + switch (state->Vcc) { + case 0: + /* sets power ctl register high */ + gpio_set_value(SG2_S0_POWER_CTL, 1); + break; + case 33: + case 50: + /* sets power control register low (clear) */ + gpio_set_value(SG2_S0_POWER_CTL, 0); + msleep(100); + break; + default: + pr_err("%s(): bad Vcc %u\n", + __func__, state->Vcc); + return -1; + } + + /* reset */ + gpio_set_value(SG2_S0_GPIO_RESET, !!(state->flags & SS_RESET)); + + return 0; +} + +static void sg2_pcmcia_socket_init(struct soc_pcmcia_socket *skt) +{ + soc_pcmcia_enable_irqs(skt, irqs, ARRAY_SIZE(irqs)); +} + +static void sg2_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) +{ + soc_pcmcia_disable_irqs(skt, irqs, ARRAY_SIZE(irqs)); +} + +static struct pcmcia_low_level sg2_pcmcia_ops __initdata = { + .owner = THIS_MODULE, + .hw_init = sg2_pcmcia_hw_init, + .hw_shutdown = sg2_pcmcia_hw_shutdown, + .socket_state = sg2_pcmcia_socket_state, + .configure_socket = sg2_pcmcia_configure_socket, + .socket_init = sg2_pcmcia_socket_init, + .socket_suspend = sg2_pcmcia_socket_suspend, + .nr = 1, +}; + +static struct platform_device *sg2_pcmcia_device; + +static int __init sg2_pcmcia_init(void) +{ + int ret; + + if (!machine_is_stargate2()) + return -ENODEV; + + sg2_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1); + if (!sg2_pcmcia_device) + return -ENOMEM; + + ret = gpio_request(SG2_S0_BUFF_CTL, "SG2 CF buff ctl"); + if (ret) + goto error_put_platform_device; + ret = gpio_request(SG2_S0_POWER_CTL, "SG2 CF power ctl"); + if (ret) + goto error_free_gpio_buff_ctl; + ret = gpio_request(SG2_S0_GPIO_RESET, "SG2 CF reset"); + if (ret) + goto error_free_gpio_power_ctl; + /* Set gpio directions */ + gpio_direction_output(SG2_S0_BUFF_CTL, 0); + gpio_direction_output(SG2_S0_POWER_CTL, 1); + gpio_direction_output(SG2_S0_GPIO_RESET, 1); + + ret = platform_device_add_data(sg2_pcmcia_device, + &sg2_pcmcia_ops, + sizeof(sg2_pcmcia_ops)); + if (ret) + goto error_free_gpio_reset; + + ret = platform_device_add(sg2_pcmcia_device); + if (ret) + goto error_free_gpio_reset; + + return 0; +error_free_gpio_reset: + gpio_free(SG2_S0_GPIO_RESET); +error_free_gpio_power_ctl: + gpio_free(SG2_S0_POWER_CTL); +error_free_gpio_buff_ctl: + gpio_free(SG2_S0_BUFF_CTL); +error_put_platform_device: + platform_device_put(sg2_pcmcia_device); + + return ret; +} + +static void __exit sg2_pcmcia_exit(void) +{ + platform_device_unregister(sg2_pcmcia_device); + gpio_free(SG2_S0_BUFF_CTL); + gpio_free(SG2_S0_POWER_CTL); + gpio_free(SG2_S0_GPIO_RESET); +} + +fs_initcall(sg2_pcmcia_init); +module_exit(sg2_pcmcia_exit); + +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:pxa2xx-pcmcia"); diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 284ebaca6e45..7232fe7104aa 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -21,7 +21,7 @@ config ACER_WMI depends on NEW_LEDS depends on BACKLIGHT_CLASS_DEVICE depends on SERIO_I8042 - depends on RFKILL + depends on RFKILL || RFKILL = n select ACPI_WMI ---help--- This is a driver for newer Acer (and Wistron) laptops. It adds @@ -34,10 +34,27 @@ config ACER_WMI If you have an ACPI-WMI compatible Acer/ Wistron laptop, say Y or M here. +config ACERHDF + tristate "Acer Aspire One temperature and fan driver" + depends on THERMAL && THERMAL_HWMON && ACPI + ---help--- + This is a driver for Acer Aspire One netbooks. It allows to access + the temperature sensor and to control the fan. + + After loading this driver the BIOS is still in control of the fan. + To let the kernel handle the fan, do: + echo -n enabled > /sys/class/thermal/thermal_zone0/mode + + For more information about this driver see + + + If you have an Acer Aspire One netbook, say Y or M + here. + config ASUS_LAPTOP - tristate "Asus Laptop Extras (EXPERIMENTAL)" + tristate "Asus Laptop Extras" depends on ACPI - depends on EXPERIMENTAL && !ACPI_ASUS + depends on !ACPI_ASUS select LEDS_CLASS select NEW_LEDS select BACKLIGHT_CLASS_DEVICE @@ -45,12 +62,12 @@ config ASUS_LAPTOP ---help--- This is the new Linux driver for Asus laptops. It may also support some MEDION, JVC or VICTOR laptops. It makes all the extra buttons generate - standard ACPI events that go through /proc/acpi/events. It also adds + standard ACPI events and input events. It also adds support for video output switching, LCD backlight control, Bluetooth and Wlan control, and most importantly, allows you to blink those fancy LEDs. For more information and a userspace daemon for handling the extra - buttons see . + buttons see . If you have an ACPI-compatible ASUS laptop, say Y or M here. @@ -60,7 +77,7 @@ config DELL_LAPTOP depends on DCDBAS depends on EXPERIMENTAL depends on BACKLIGHT_CLASS_DEVICE - depends on RFKILL + depends on RFKILL || RFKILL = n depends on POWER_SUPPLY default n ---help--- @@ -117,7 +134,7 @@ config HP_WMI tristate "HP WMI extras" depends on ACPI_WMI depends on INPUT - depends on RFKILL + depends on RFKILL || RFKILL = n help Say Y here if you want to support WMI-based hotkeys on HP laptops and to read data from WMI such as docking or ambient light sensor state. @@ -196,14 +213,13 @@ config THINKPAD_ACPI tristate "ThinkPad ACPI Laptop Extras" depends on ACPI depends on INPUT + depends on RFKILL || RFKILL = n select BACKLIGHT_LCD_SUPPORT select BACKLIGHT_CLASS_DEVICE select HWMON select NVRAM select NEW_LEDS select LEDS_CLASS - select NET - select RFKILL ---help--- This is a driver for the IBM and Lenovo ThinkPad laptops. It adds support for Fn-Fx key combinations, Bluetooth control, video @@ -338,12 +354,15 @@ config EEEPC_LAPTOP depends on ACPI depends on INPUT depends on EXPERIMENTAL + depends on RFKILL || RFKILL = n select BACKLIGHT_CLASS_DEVICE select HWMON - select RFKILL ---help--- This driver supports the Fn-Fx keys on Eee PC laptops. - It also adds the ability to switch camera/wlan on/off. + + It also gives access to some extra laptop functionalities like + Bluetooth, backlight and allows powering on/off some other + devices. If you have an Eee PC laptop, say Y or M here. @@ -370,7 +389,7 @@ config ACPI_WMI any ACPI-WMI devices. config ACPI_ASUS - tristate "ASUS/Medion Laptop Extras" + tristate "ASUS/Medion Laptop Extras (DEPRECATED)" depends on ACPI select BACKLIGHT_CLASS_DEVICE ---help--- @@ -391,7 +410,7 @@ config ACPI_ASUS parameters. More information and a userspace daemon for handling the extra buttons - at . + at . If you have an ACPI-compatible ASUS laptop, say Y or M here. This driver is still under development, so if your laptop is unsupported or @@ -405,9 +424,8 @@ config ACPI_TOSHIBA tristate "Toshiba Laptop Extras" depends on ACPI depends on INPUT + depends on RFKILL || RFKILL = n select INPUT_POLLDEV - select NET - select RFKILL select BACKLIGHT_CLASS_DEVICE ---help--- This driver adds support for access to certain system settings diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index e40c7bd1b87e..641b8bfa5538 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o obj-$(CONFIG_DELL_WMI) += dell-wmi.o obj-$(CONFIG_ACER_WMI) += acer-wmi.o +obj-$(CONFIG_ACERHDF) += acerhdf.o obj-$(CONFIG_HP_WMI) += hp-wmi.o obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index 0f6e43bf4fc2..be2fd6f91639 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -958,59 +958,47 @@ static void acer_rfkill_update(struct work_struct *ignored) status = get_u32(&state, ACER_CAP_WIRELESS); if (ACPI_SUCCESS(status)) - rfkill_force_state(wireless_rfkill, state ? - RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED); + rfkill_set_sw_state(wireless_rfkill, !state); if (has_cap(ACER_CAP_BLUETOOTH)) { status = get_u32(&state, ACER_CAP_BLUETOOTH); if (ACPI_SUCCESS(status)) - rfkill_force_state(bluetooth_rfkill, state ? - RFKILL_STATE_UNBLOCKED : - RFKILL_STATE_SOFT_BLOCKED); + rfkill_set_sw_state(bluetooth_rfkill, !state); } schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ)); } -static int acer_rfkill_set(void *data, enum rfkill_state state) +static int acer_rfkill_set(void *data, bool blocked) { acpi_status status; - u32 *cap = data; - status = set_u32((u32) (state == RFKILL_STATE_UNBLOCKED), *cap); + u32 cap = (unsigned long)data; + status = set_u32(!!blocked, cap); if (ACPI_FAILURE(status)) return -ENODEV; return 0; } -static struct rfkill * acer_rfkill_register(struct device *dev, -enum rfkill_type type, char *name, u32 cap) +static const struct rfkill_ops acer_rfkill_ops = { + .set_block = acer_rfkill_set, +}; + +static struct rfkill *acer_rfkill_register(struct device *dev, + enum rfkill_type type, + char *name, u32 cap) { int err; - u32 state; - u32 *data; struct rfkill *rfkill_dev; - rfkill_dev = rfkill_allocate(dev, type); + rfkill_dev = rfkill_alloc(name, dev, type, + &acer_rfkill_ops, + (void *)(unsigned long)cap); if (!rfkill_dev) return ERR_PTR(-ENOMEM); - rfkill_dev->name = name; - get_u32(&state, cap); - rfkill_dev->state = state ? RFKILL_STATE_UNBLOCKED : - RFKILL_STATE_SOFT_BLOCKED; - data = kzalloc(sizeof(u32), GFP_KERNEL); - if (!data) { - rfkill_free(rfkill_dev); - return ERR_PTR(-ENOMEM); - } - *data = cap; - rfkill_dev->data = data; - rfkill_dev->toggle_radio = acer_rfkill_set; - rfkill_dev->user_claim_unsupported = 1; err = rfkill_register(rfkill_dev); if (err) { - kfree(rfkill_dev->data); - rfkill_free(rfkill_dev); + rfkill_destroy(rfkill_dev); return ERR_PTR(err); } return rfkill_dev; @@ -1028,8 +1016,8 @@ static int acer_rfkill_init(struct device *dev) RFKILL_TYPE_BLUETOOTH, "acer-bluetooth", ACER_CAP_BLUETOOTH); if (IS_ERR(bluetooth_rfkill)) { - kfree(wireless_rfkill->data); rfkill_unregister(wireless_rfkill); + rfkill_destroy(wireless_rfkill); return PTR_ERR(bluetooth_rfkill); } } @@ -1042,11 +1030,13 @@ static int acer_rfkill_init(struct device *dev) static void acer_rfkill_exit(void) { cancel_delayed_work_sync(&acer_rfkill_work); - kfree(wireless_rfkill->data); + rfkill_unregister(wireless_rfkill); + rfkill_destroy(wireless_rfkill); + if (has_cap(ACER_CAP_BLUETOOTH)) { - kfree(bluetooth_rfkill->data); rfkill_unregister(bluetooth_rfkill); + rfkill_destroy(bluetooth_rfkill); } return; } diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c new file mode 100644 index 000000000000..bdfee177eefb --- /dev/null +++ b/drivers/platform/x86/acerhdf.c @@ -0,0 +1,602 @@ +/* + * acerhdf - A driver which monitors the temperature + * of the aspire one netbook, turns on/off the fan + * as soon as the upper/lower threshold is reached. + * + * (C) 2009 - Peter Feuerer peter (a) piie.net + * http://piie.net + * 2009 Borislav Petkov + * + * Inspired by and many thanks to: + * o acerfand - Rachel Greenham + * o acer_ec.pl - Michael Kurz michi.kurz (at) googlemail.com + * - Petr Tomasek tomasek (#) etf,cuni,cz + * - Carlos Corbacho cathectic (at) gmail.com + * o lkml - Matthew Garrett + * - Borislav Petkov + * - Andreas Mohr + * + * 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 pr_fmt(fmt) "acerhdf: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * The driver is started with "kernel mode off" by default. That means, the BIOS + * is still in control of the fan. In this mode the driver allows to read the + * temperature of the cpu and a userspace tool may take over control of the fan. + * If the driver is switched to "kernel mode" (e.g. via module parameter) the + * driver is in full control of the fan. If you want the module to be started in + * kernel mode by default, define the following: + */ +#undef START_IN_KERNEL_MODE + +#define DRV_VER "0.5.13" + +/* + * According to the Atom N270 datasheet, + * (http://download.intel.com/design/processor/datashts/320032.pdf) the + * CPU's optimal operating limits denoted in junction temperature as + * measured by the on-die thermal monitor are within 0 <= Tj <= 90. So, + * assume 89°C is critical temperature. + */ +#define ACERHDF_TEMP_CRIT 89 +#define ACERHDF_FAN_OFF 0 +#define ACERHDF_FAN_AUTO 1 + +/* + * No matter what value the user puts into the fanon variable, turn on the fan + * at 80 degree Celsius to prevent hardware damage + */ +#define ACERHDF_MAX_FANON 80 + +/* + * Maximum interval between two temperature checks is 15 seconds, as the die + * can get hot really fast under heavy load (plus we shouldn't forget about + * possible impact of _external_ aggressive sources such as heaters, sun etc.) + */ +#define ACERHDF_MAX_INTERVAL 15 + +#ifdef START_IN_KERNEL_MODE +static int kernelmode = 1; +#else +static int kernelmode; +#endif + +static unsigned int interval = 10; +static unsigned int fanon = 63; +static unsigned int fanoff = 58; +static unsigned int verbose; +static unsigned int fanstate = ACERHDF_FAN_AUTO; +static char force_bios[16]; +static unsigned int prev_interval; +struct thermal_zone_device *thz_dev; +struct thermal_cooling_device *cl_dev; +struct platform_device *acerhdf_dev; + +module_param(kernelmode, uint, 0); +MODULE_PARM_DESC(kernelmode, "Kernel mode fan control on / off"); +module_param(interval, uint, 0600); +MODULE_PARM_DESC(interval, "Polling interval of temperature check"); +module_param(fanon, uint, 0600); +MODULE_PARM_DESC(fanon, "Turn the fan on above this temperature"); +module_param(fanoff, uint, 0600); +MODULE_PARM_DESC(fanoff, "Turn the fan off below this temperature"); +module_param(verbose, uint, 0600); +MODULE_PARM_DESC(verbose, "Enable verbose dmesg output"); +module_param_string(force_bios, force_bios, 16, 0); +MODULE_PARM_DESC(force_bios, "Force BIOS version and omit BIOS check"); + +/* BIOS settings */ +struct bios_settings_t { + const char *vendor; + const char *version; + unsigned char fanreg; + unsigned char tempreg; + unsigned char fancmd[2]; /* fan off and auto commands */ +}; + +/* Register addresses and values for different BIOS versions */ +static const struct bios_settings_t bios_tbl[] = { + {"Acer", "v0.3109", 0x55, 0x58, {0x1f, 0x00} }, + {"Acer", "v0.3114", 0x55, 0x58, {0x1f, 0x00} }, + {"Acer", "v0.3301", 0x55, 0x58, {0xaf, 0x00} }, + {"Acer", "v0.3304", 0x55, 0x58, {0xaf, 0x00} }, + {"Acer", "v0.3305", 0x55, 0x58, {0xaf, 0x00} }, + {"Acer", "v0.3308", 0x55, 0x58, {0x21, 0x00} }, + {"Acer", "v0.3309", 0x55, 0x58, {0x21, 0x00} }, + {"Acer", "v0.3310", 0x55, 0x58, {0x21, 0x00} }, + {"Gateway", "v0.3103", 0x55, 0x58, {0x21, 0x00} }, + {"Packard Bell", "v0.3105", 0x55, 0x58, {0x21, 0x00} }, + {"", "", 0, 0, {0, 0} } +}; + +static const struct bios_settings_t *bios_cfg __read_mostly; + + +static int acerhdf_get_temp(int *temp) +{ + u8 read_temp; + + if (ec_read(bios_cfg->tempreg, &read_temp)) + return -EINVAL; + + *temp = read_temp; + + return 0; +} + +static int acerhdf_get_fanstate(int *state) +{ + u8 fan; + bool tmp; + + if (ec_read(bios_cfg->fanreg, &fan)) + return -EINVAL; + + tmp = (fan == bios_cfg->fancmd[ACERHDF_FAN_OFF]); + *state = tmp ? ACERHDF_FAN_OFF : ACERHDF_FAN_AUTO; + + return 0; +} + +static void acerhdf_change_fanstate(int state) +{ + unsigned char cmd; + + if (verbose) + pr_notice("fan %s\n", (state == ACERHDF_FAN_OFF) ? + "OFF" : "ON"); + + if ((state != ACERHDF_FAN_OFF) && (state != ACERHDF_FAN_AUTO)) { + pr_err("invalid fan state %d requested, setting to auto!\n", + state); + state = ACERHDF_FAN_AUTO; + } + + cmd = bios_cfg->fancmd[state]; + fanstate = state; + + ec_write(bios_cfg->fanreg, cmd); +} + +static void acerhdf_check_param(struct thermal_zone_device *thermal) +{ + if (fanon > ACERHDF_MAX_FANON) { + pr_err("fanon temperature too high, set to %d\n", + ACERHDF_MAX_FANON); + fanon = ACERHDF_MAX_FANON; + } + + if (kernelmode && prev_interval != interval) { + if (interval > ACERHDF_MAX_INTERVAL) { + pr_err("interval too high, set to %d\n", + ACERHDF_MAX_INTERVAL); + interval = ACERHDF_MAX_INTERVAL; + } + if (verbose) + pr_notice("interval changed to: %d\n", + interval); + thermal->polling_delay = interval*1000; + prev_interval = interval; + } +} + +/* + * This is the thermal zone callback which does the delayed polling of the fan + * state. We do check /sysfs-originating settings here in acerhdf_check_param() + * as late as the polling interval is since we can't do that in the respective + * accessors of the module parameters. + */ +static int acerhdf_get_ec_temp(struct thermal_zone_device *thermal, + unsigned long *t) +{ + int temp, err = 0; + + acerhdf_check_param(thermal); + + err = acerhdf_get_temp(&temp); + if (err) + return err; + + if (verbose) + pr_notice("temp %d\n", temp); + + *t = temp; + return 0; +} + +static int acerhdf_bind(struct thermal_zone_device *thermal, + struct thermal_cooling_device *cdev) +{ + /* if the cooling device is the one from acerhdf bind it */ + if (cdev != cl_dev) + return 0; + + if (thermal_zone_bind_cooling_device(thermal, 0, cdev)) { + pr_err("error binding cooling dev\n"); + return -EINVAL; + } + return 0; +} + +static int acerhdf_unbind(struct thermal_zone_device *thermal, + struct thermal_cooling_device *cdev) +{ + if (cdev != cl_dev) + return 0; + + if (thermal_zone_unbind_cooling_device(thermal, 0, cdev)) { + pr_err("error unbinding cooling dev\n"); + return -EINVAL; + } + return 0; +} + +static inline void acerhdf_revert_to_bios_mode(void) +{ + acerhdf_change_fanstate(ACERHDF_FAN_AUTO); + kernelmode = 0; + if (thz_dev) + thz_dev->polling_delay = 0; + pr_notice("kernel mode fan control OFF\n"); +} +static inline void acerhdf_enable_kernelmode(void) +{ + kernelmode = 1; + + thz_dev->polling_delay = interval*1000; + thermal_zone_device_update(thz_dev); + pr_notice("kernel mode fan control ON\n"); +} + +static int acerhdf_get_mode(struct thermal_zone_device *thermal, + enum thermal_device_mode *mode) +{ + if (verbose) + pr_notice("kernel mode fan control %d\n", kernelmode); + + *mode = (kernelmode) ? THERMAL_DEVICE_ENABLED + : THERMAL_DEVICE_DISABLED; + + return 0; +} + +/* + * set operation mode; + * enabled: the thermal layer of the kernel takes care about + * the temperature and the fan. + * disabled: the BIOS takes control of the fan. + */ +static int acerhdf_set_mode(struct thermal_zone_device *thermal, + enum thermal_device_mode mode) +{ + if (mode == THERMAL_DEVICE_DISABLED && kernelmode) + acerhdf_revert_to_bios_mode(); + else if (mode == THERMAL_DEVICE_ENABLED && !kernelmode) + acerhdf_enable_kernelmode(); + + return 0; +} + +static int acerhdf_get_trip_type(struct thermal_zone_device *thermal, int trip, + enum thermal_trip_type *type) +{ + if (trip == 0) + *type = THERMAL_TRIP_ACTIVE; + + return 0; +} + +static int acerhdf_get_trip_temp(struct thermal_zone_device *thermal, int trip, + unsigned long *temp) +{ + if (trip == 0) + *temp = fanon; + + return 0; +} + +static int acerhdf_get_crit_temp(struct thermal_zone_device *thermal, + unsigned long *temperature) +{ + *temperature = ACERHDF_TEMP_CRIT; + return 0; +} + +/* bind callback functions to thermalzone */ +struct thermal_zone_device_ops acerhdf_dev_ops = { + .bind = acerhdf_bind, + .unbind = acerhdf_unbind, + .get_temp = acerhdf_get_ec_temp, + .get_mode = acerhdf_get_mode, + .set_mode = acerhdf_set_mode, + .get_trip_type = acerhdf_get_trip_type, + .get_trip_temp = acerhdf_get_trip_temp, + .get_crit_temp = acerhdf_get_crit_temp, +}; + + +/* + * cooling device callback functions + * get maximal fan cooling state + */ +static int acerhdf_get_max_state(struct thermal_cooling_device *cdev, + unsigned long *state) +{ + *state = 1; + + return 0; +} + +static int acerhdf_get_cur_state(struct thermal_cooling_device *cdev, + unsigned long *state) +{ + int err = 0, tmp; + + err = acerhdf_get_fanstate(&tmp); + if (err) + return err; + + *state = (tmp == ACERHDF_FAN_AUTO) ? 1 : 0; + return 0; +} + +/* change current fan state - is overwritten when running in kernel mode */ +static int acerhdf_set_cur_state(struct thermal_cooling_device *cdev, + unsigned long state) +{ + int cur_temp, cur_state, err = 0; + + if (!kernelmode) + return 0; + + err = acerhdf_get_temp(&cur_temp); + if (err) { + pr_err("error reading temperature, hand off control to BIOS\n"); + goto err_out; + } + + err = acerhdf_get_fanstate(&cur_state); + if (err) { + pr_err("error reading fan state, hand off control to BIOS\n"); + goto err_out; + } + + if (state == 0) { + /* turn fan off only if below fanoff temperature */ + if ((cur_state == ACERHDF_FAN_AUTO) && + (cur_temp < fanoff)) + acerhdf_change_fanstate(ACERHDF_FAN_OFF); + } else { + if (cur_state == ACERHDF_FAN_OFF) + acerhdf_change_fanstate(ACERHDF_FAN_AUTO); + } + return 0; + +err_out: + acerhdf_revert_to_bios_mode(); + return -EINVAL; +} + +/* bind fan callbacks to fan device */ +struct thermal_cooling_device_ops acerhdf_cooling_ops = { + .get_max_state = acerhdf_get_max_state, + .get_cur_state = acerhdf_get_cur_state, + .set_cur_state = acerhdf_set_cur_state, +}; + +/* suspend / resume functionality */ +static int acerhdf_suspend(struct platform_device *dev, pm_message_t state) +{ + if (kernelmode) + acerhdf_change_fanstate(ACERHDF_FAN_AUTO); + + if (verbose) + pr_notice("going suspend\n"); + + return 0; +} + +static int acerhdf_resume(struct platform_device *device) +{ + if (verbose) + pr_notice("resuming\n"); + + return 0; +} + +static int __devinit acerhdf_probe(struct platform_device *device) +{ + return 0; +} + +static int acerhdf_remove(struct platform_device *device) +{ + return 0; +} + +struct platform_driver acerhdf_drv = { + .driver = { + .name = "acerhdf", + .owner = THIS_MODULE, + }, + .probe = acerhdf_probe, + .remove = acerhdf_remove, + .suspend = acerhdf_suspend, + .resume = acerhdf_resume, +}; + + +/* check hardware */ +static int acerhdf_check_hardware(void) +{ + char const *vendor, *version, *product; + int i; + + /* get BIOS data */ + vendor = dmi_get_system_info(DMI_SYS_VENDOR); + version = dmi_get_system_info(DMI_BIOS_VERSION); + product = dmi_get_system_info(DMI_PRODUCT_NAME); + + pr_info("Acer Aspire One Fan driver, v.%s\n", DRV_VER); + + if (!force_bios[0]) { + if (strncmp(product, "AO", 2)) { + pr_err("no Aspire One hardware found\n"); + return -EINVAL; + } + } else { + pr_info("forcing BIOS version: %s\n", version); + version = force_bios; + kernelmode = 0; + } + + if (verbose) + pr_info("BIOS info: %s %s, product: %s\n", + vendor, version, product); + + /* search BIOS version and vendor in BIOS settings table */ + for (i = 0; bios_tbl[i].version[0]; i++) { + if (!strcmp(bios_tbl[i].vendor, vendor) && + !strcmp(bios_tbl[i].version, version)) { + bios_cfg = &bios_tbl[i]; + break; + } + } + + if (!bios_cfg) { + pr_err("unknown (unsupported) BIOS version %s/%s, " + "please report, aborting!\n", vendor, version); + return -EINVAL; + } + + /* + * if started with kernel mode off, prevent the kernel from switching + * off the fan + */ + if (!kernelmode) { + pr_notice("Fan control off, to enable do:\n"); + pr_notice("echo -n \"enabled\" > " + "/sys/class/thermal/thermal_zone0/mode\n"); + } + + return 0; +} + +static int acerhdf_register_platform(void) +{ + int err = 0; + + err = platform_driver_register(&acerhdf_drv); + if (err) + return err; + + acerhdf_dev = platform_device_alloc("acerhdf", -1); + platform_device_add(acerhdf_dev); + + return 0; +} + +static void acerhdf_unregister_platform(void) +{ + if (!acerhdf_dev) + return; + + platform_device_del(acerhdf_dev); + platform_driver_unregister(&acerhdf_drv); +} + +static int acerhdf_register_thermal(void) +{ + cl_dev = thermal_cooling_device_register("acerhdf-fan", NULL, + &acerhdf_cooling_ops); + + if (IS_ERR(cl_dev)) + return -EINVAL; + + thz_dev = thermal_zone_device_register("acerhdf", 1, NULL, + &acerhdf_dev_ops, 0, 0, 0, + (kernelmode) ? interval*1000 : 0); + if (IS_ERR(thz_dev)) + return -EINVAL; + + return 0; +} + +static void acerhdf_unregister_thermal(void) +{ + if (cl_dev) { + thermal_cooling_device_unregister(cl_dev); + cl_dev = NULL; + } + + if (thz_dev) { + thermal_zone_device_unregister(thz_dev); + thz_dev = NULL; + } +} + +static int __init acerhdf_init(void) +{ + int err = 0; + + err = acerhdf_check_hardware(); + if (err) + goto out_err; + + err = acerhdf_register_platform(); + if (err) + goto err_unreg; + + err = acerhdf_register_thermal(); + if (err) + goto err_unreg; + + return 0; + +err_unreg: + acerhdf_unregister_thermal(); + acerhdf_unregister_platform(); + +out_err: + return -ENODEV; +} + +static void __exit acerhdf_exit(void) +{ + acerhdf_change_fanstate(ACERHDF_FAN_AUTO); + acerhdf_unregister_thermal(); + acerhdf_unregister_platform(); +} + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Peter Feuerer"); +MODULE_DESCRIPTION("Aspire One temperature and fan driver"); +MODULE_ALIAS("dmi:*:*Acer*:*:"); +MODULE_ALIAS("dmi:*:*Gateway*:*:"); +MODULE_ALIAS("dmi:*:*Packard Bell*:*:"); + +module_init(acerhdf_init); +module_exit(acerhdf_exit); diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index bfc1a8892a32..db657bbeec90 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -33,6 +33,8 @@ * Sam Lin - GPS support */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -53,9 +55,10 @@ #define ASUS_HOTK_NAME "Asus Laptop Support" #define ASUS_HOTK_CLASS "hotkey" #define ASUS_HOTK_DEVICE_NAME "Hotkey" -#define ASUS_HOTK_FILE "asus-laptop" +#define ASUS_HOTK_FILE KBUILD_MODNAME #define ASUS_HOTK_PREFIX "\\_SB.ATKD." + /* * Some events we use, same for all Asus */ @@ -207,13 +210,17 @@ MODULE_DEVICE_TABLE(acpi, asus_device_ids); static int asus_hotk_add(struct acpi_device *device); static int asus_hotk_remove(struct acpi_device *device, int type); +static void asus_hotk_notify(struct acpi_device *device, u32 event); + static struct acpi_driver asus_hotk_driver = { .name = ASUS_HOTK_NAME, .class = ASUS_HOTK_CLASS, .ids = asus_device_ids, + .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS, .ops = { .add = asus_hotk_add, .remove = asus_hotk_remove, + .notify = asus_hotk_notify, }, }; @@ -323,7 +330,7 @@ static int read_wireless_status(int mask) rv = acpi_evaluate_integer(wireless_status_handle, NULL, NULL, &status); if (ACPI_FAILURE(rv)) - printk(ASUS_WARNING "Error reading Wireless status\n"); + pr_warning("Error reading Wireless status\n"); else return (status & mask) ? 1 : 0; @@ -337,7 +344,7 @@ static int read_gps_status(void) rv = acpi_evaluate_integer(gps_status_handle, NULL, NULL, &status); if (ACPI_FAILURE(rv)) - printk(ASUS_WARNING "Error reading GPS status\n"); + pr_warning("Error reading GPS status\n"); else return status ? 1 : 0; @@ -377,7 +384,7 @@ static void write_status(acpi_handle handle, int out, int mask) } if (write_acpi_int(handle, NULL, out, NULL)) - printk(ASUS_WARNING " write failed %x\n", mask); + pr_warning(" write failed %x\n", mask); } /* /sys/class/led handlers */ @@ -420,7 +427,7 @@ static int set_lcd_state(int value) NULL, NULL, NULL); if (ACPI_FAILURE(status)) - printk(ASUS_WARNING "Error switching LCD\n"); + pr_warning("Error switching LCD\n"); } write_status(NULL, lcd, LCD_ON); @@ -444,7 +451,7 @@ static int read_brightness(struct backlight_device *bd) rv = acpi_evaluate_integer(brightness_get_handle, NULL, NULL, &value); if (ACPI_FAILURE(rv)) - printk(ASUS_WARNING "Error reading brightness\n"); + pr_warning("Error reading brightness\n"); return value; } @@ -457,7 +464,7 @@ static int set_brightness(struct backlight_device *bd, int value) /* 0 <= value <= 15 */ if (write_acpi_int(brightness_set_handle, NULL, value, NULL)) { - printk(ASUS_WARNING "Error changing brightness\n"); + pr_warning("Error changing brightness\n"); ret = -EIO; } @@ -587,7 +594,7 @@ static ssize_t store_ledd(struct device *dev, struct device_attribute *attr, rv = parse_arg(buf, count, &value); if (rv > 0) { if (write_acpi_int(ledd_set_handle, NULL, value, NULL)) - printk(ASUS_WARNING "LED display write failed\n"); + pr_warning("LED display write failed\n"); else hotk->ledd_status = (u32) value; } @@ -632,7 +639,7 @@ static void set_display(int value) { /* no sanity check needed for now */ if (write_acpi_int(display_set_handle, NULL, value, NULL)) - printk(ASUS_WARNING "Error setting display\n"); + pr_warning("Error setting display\n"); return; } @@ -647,7 +654,7 @@ static int read_display(void) rv = acpi_evaluate_integer(display_get_handle, NULL, NULL, &value); if (ACPI_FAILURE(rv)) - printk(ASUS_WARNING "Error reading display status\n"); + pr_warning("Error reading display status\n"); } value &= 0x0F; /* needed for some models, shouldn't hurt others */ @@ -689,7 +696,7 @@ static ssize_t store_disp(struct device *dev, struct device_attribute *attr, static void set_light_sens_switch(int value) { if (write_acpi_int(ls_switch_handle, NULL, value, NULL)) - printk(ASUS_WARNING "Error setting light sensor switch\n"); + pr_warning("Error setting light sensor switch\n"); hotk->light_switch = value; } @@ -714,7 +721,7 @@ static ssize_t store_lssw(struct device *dev, struct device_attribute *attr, static void set_light_sens_level(int value) { if (write_acpi_int(ls_level_handle, NULL, value, NULL)) - printk(ASUS_WARNING "Error setting light sensor level\n"); + pr_warning("Error setting light sensor level\n"); hotk->light_level = value; } @@ -812,7 +819,7 @@ static int asus_setkeycode(struct input_dev *dev, int scancode, int keycode) return -EINVAL; } -static void asus_hotk_notify(acpi_handle handle, u32 event, void *data) +static void asus_hotk_notify(struct acpi_device *device, u32 event) { static struct key_entry *key; u16 count; @@ -975,11 +982,11 @@ static int asus_hotk_get_info(void) */ status = acpi_get_table(ACPI_SIG_DSDT, 1, &asus_info); if (ACPI_FAILURE(status)) - printk(ASUS_WARNING "Couldn't get the DSDT table header\n"); + pr_warning("Couldn't get the DSDT table header\n"); /* We have to write 0 on init this far for all ASUS models */ if (write_acpi_int(hotk->handle, "INIT", 0, &buffer)) { - printk(ASUS_ERR "Hotkey initialization failed\n"); + pr_err("Hotkey initialization failed\n"); return -ENODEV; } @@ -987,9 +994,9 @@ static int asus_hotk_get_info(void) status = acpi_evaluate_integer(hotk->handle, "BSTS", NULL, &bsts_result); if (ACPI_FAILURE(status)) - printk(ASUS_WARNING "Error calling BSTS\n"); + pr_warning("Error calling BSTS\n"); else if (bsts_result) - printk(ASUS_NOTICE "BSTS called, 0x%02x returned\n", + pr_notice("BSTS called, 0x%02x returned\n", (uint) bsts_result); /* This too ... */ @@ -1020,7 +1027,7 @@ static int asus_hotk_get_info(void) return -ENOMEM; if (*string) - printk(ASUS_NOTICE " %s model detected\n", string); + pr_notice(" %s model detected\n", string); ASUS_HANDLE_INIT(mled_set); ASUS_HANDLE_INIT(tled_set); @@ -1077,7 +1084,7 @@ static int asus_input_init(void) hotk->inputdev = input_allocate_device(); if (!hotk->inputdev) { - printk(ASUS_INFO "Unable to allocate input device\n"); + pr_info("Unable to allocate input device\n"); return 0; } hotk->inputdev->name = "Asus Laptop extra buttons"; @@ -1096,7 +1103,7 @@ static int asus_input_init(void) } result = input_register_device(hotk->inputdev); if (result) { - printk(ASUS_INFO "Unable to register input device\n"); + pr_info("Unable to register input device\n"); input_free_device(hotk->inputdev); } return result; @@ -1113,7 +1120,7 @@ static int asus_hotk_check(void) if (hotk->device->status.present) { result = asus_hotk_get_info(); } else { - printk(ASUS_ERR "Hotkey device not present, aborting\n"); + pr_err("Hotkey device not present, aborting\n"); return -EINVAL; } @@ -1124,13 +1131,12 @@ static int asus_hotk_found; static int asus_hotk_add(struct acpi_device *device) { - acpi_status status = AE_OK; int result; if (!device) return -EINVAL; - printk(ASUS_NOTICE "Asus Laptop Support version %s\n", + pr_notice("Asus Laptop Support version %s\n", ASUS_LAPTOP_VERSION); hotk = kzalloc(sizeof(struct asus_hotk), GFP_KERNEL); @@ -1149,15 +1155,6 @@ static int asus_hotk_add(struct acpi_device *device) asus_hotk_add_fs(); - /* - * We install the handler, it will receive the hotk in parameter, so, we - * could add other data to the hotk struct - */ - status = acpi_install_notify_handler(hotk->handle, ACPI_ALL_NOTIFY, - asus_hotk_notify, hotk); - if (ACPI_FAILURE(status)) - printk(ASUS_ERR "Error installing notify handler\n"); - asus_hotk_found = 1; /* WLED and BLED are on by default */ @@ -1198,16 +1195,9 @@ end: static int asus_hotk_remove(struct acpi_device *device, int type) { - acpi_status status = 0; - if (!device || !acpi_driver_data(device)) return -EINVAL; - status = acpi_remove_notify_handler(hotk->handle, ACPI_ALL_NOTIFY, - asus_hotk_notify); - if (ACPI_FAILURE(status)) - printk(ASUS_ERR "Error removing notify handler\n"); - kfree(hotk->name); kfree(hotk); @@ -1260,8 +1250,7 @@ static int asus_backlight_init(struct device *dev) bd = backlight_device_register(ASUS_HOTK_FILE, dev, NULL, &asusbl_ops); if (IS_ERR(bd)) { - printk(ASUS_ERR - "Could not register asus backlight device\n"); + pr_err("Could not register asus backlight device\n"); asus_backlight_device = NULL; return PTR_ERR(bd); } @@ -1334,7 +1323,6 @@ out: static int __init asus_laptop_init(void) { - struct device *dev; int result; if (acpi_disabled) @@ -1356,24 +1344,10 @@ static int __init asus_laptop_init(void) return -ENODEV; } - dev = acpi_get_physical_device(hotk->device->handle); - - if (!acpi_video_backlight_support()) { - result = asus_backlight_init(dev); - if (result) - goto fail_backlight; - } else - printk(ASUS_INFO "Brightness ignored, must be controlled by " - "ACPI video driver\n"); - result = asus_input_init(); if (result) goto fail_input; - result = asus_led_init(dev); - if (result) - goto fail_led; - /* Register platform stuff */ result = platform_driver_register(&asuspf_driver); if (result) @@ -1394,8 +1368,27 @@ static int __init asus_laptop_init(void) if (result) goto fail_sysfs; + result = asus_led_init(&asuspf_device->dev); + if (result) + goto fail_led; + + if (!acpi_video_backlight_support()) { + result = asus_backlight_init(&asuspf_device->dev); + if (result) + goto fail_backlight; + } else + pr_info("Brightness ignored, must be controlled by " + "ACPI video driver\n"); + return 0; +fail_backlight: + asus_led_exit(); + +fail_led: + sysfs_remove_group(&asuspf_device->dev.kobj, + &asuspf_attribute_group); + fail_sysfs: platform_device_del(asuspf_device); @@ -1406,15 +1399,9 @@ fail_platform_device1: platform_driver_unregister(&asuspf_driver); fail_platform_driver: - asus_led_exit(); - -fail_led: asus_input_exit(); fail_input: - asus_backlight_exit(); - -fail_backlight: return result; } diff --git a/drivers/platform/x86/asus_acpi.c b/drivers/platform/x86/asus_acpi.c index ba1f7497e4b9..ddf5240ade8c 100644 --- a/drivers/platform/x86/asus_acpi.c +++ b/drivers/platform/x86/asus_acpi.c @@ -455,6 +455,8 @@ static struct asus_hotk *hotk; */ static int asus_hotk_add(struct acpi_device *device); static int asus_hotk_remove(struct acpi_device *device, int type); +static void asus_hotk_notify(struct acpi_device *device, u32 event); + static const struct acpi_device_id asus_device_ids[] = { {"ATK0100", 0}, {"", 0}, @@ -465,9 +467,11 @@ static struct acpi_driver asus_hotk_driver = { .name = "asus_acpi", .class = ACPI_HOTK_CLASS, .ids = asus_device_ids, + .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS, .ops = { .add = asus_hotk_add, .remove = asus_hotk_remove, + .notify = asus_hotk_notify, }, }; @@ -1101,12 +1105,20 @@ static int asus_hotk_remove_fs(struct acpi_device *device) return 0; } -static void asus_hotk_notify(acpi_handle handle, u32 event, void *data) +static void asus_hotk_notify(struct acpi_device *device, u32 event) { /* TODO Find a better way to handle events count. */ if (!hotk) return; + /* + * The BIOS *should* be sending us device events, but apparently + * Asus uses system events instead, so just ignore any device + * events we get. + */ + if (event > ACPI_MAX_SYS_NOTIFY) + return; + if ((event & ~((u32) BR_UP)) < 16) hotk->brightness = (event & ~((u32) BR_UP)); else if ((event & ~((u32) BR_DOWN)) < 16) @@ -1346,15 +1358,6 @@ static int asus_hotk_add(struct acpi_device *device) if (result) goto end; - /* - * We install the handler, it will receive the hotk in parameter, so, we - * could add other data to the hotk struct - */ - status = acpi_install_notify_handler(hotk->handle, ACPI_SYSTEM_NOTIFY, - asus_hotk_notify, hotk); - if (ACPI_FAILURE(status)) - printk(KERN_ERR " Error installing notify handler\n"); - /* For laptops without GPLV: init the hotk->brightness value */ if ((!hotk->methods->brightness_get) && (!hotk->methods->brightness_status) @@ -1389,16 +1392,9 @@ end: static int asus_hotk_remove(struct acpi_device *device, int type) { - acpi_status status = 0; - if (!device || !acpi_driver_data(device)) return -EINVAL; - status = acpi_remove_notify_handler(hotk->handle, ACPI_SYSTEM_NOTIFY, - asus_hotk_notify); - if (ACPI_FAILURE(status)) - printk(KERN_ERR "Asus ACPI: Error removing notify handler\n"); - asus_hotk_remove_fs(device); kfree(hotk); diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index af9f43021172..74909c4aaeea 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -174,10 +174,11 @@ dell_send_request(struct calling_interface_buffer *buffer, int class, result[3]: NVRAM format version number */ -static int dell_rfkill_set(int radio, enum rfkill_state state) +static int dell_rfkill_set(void *data, bool blocked) { struct calling_interface_buffer buffer; - int disable = (state == RFKILL_STATE_UNBLOCKED) ? 0 : 1; + int disable = blocked ? 1 : 0; + unsigned long radio = (unsigned long)data; memset(&buffer, 0, sizeof(struct calling_interface_buffer)); buffer.input[0] = (1 | (radio<<8) | (disable << 16)); @@ -186,56 +187,24 @@ static int dell_rfkill_set(int radio, enum rfkill_state state) return 0; } -static int dell_wifi_set(void *data, enum rfkill_state state) -{ - return dell_rfkill_set(1, state); -} - -static int dell_bluetooth_set(void *data, enum rfkill_state state) -{ - return dell_rfkill_set(2, state); -} - -static int dell_wwan_set(void *data, enum rfkill_state state) -{ - return dell_rfkill_set(3, state); -} - -static int dell_rfkill_get(int bit, enum rfkill_state *state) +static void dell_rfkill_query(struct rfkill *rfkill, void *data) { struct calling_interface_buffer buffer; int status; - int new_state = RFKILL_STATE_HARD_BLOCKED; + int bit = (unsigned long)data + 16; memset(&buffer, 0, sizeof(struct calling_interface_buffer)); dell_send_request(&buffer, 17, 11); status = buffer.output[1]; - if (status & (1<<16)) - new_state = RFKILL_STATE_SOFT_BLOCKED; - - if (status & (1<name = "dell-wifi"; - wifi_rfkill->toggle_radio = dell_wifi_set; - wifi_rfkill->get_state = dell_wifi_get; + } ret = rfkill_register(wifi_rfkill); if (ret) goto err_wifi; } if ((status & (1<<3|1<<9)) == (1<<3|1<<9)) { - bluetooth_rfkill = rfkill_allocate(NULL, RFKILL_TYPE_BLUETOOTH); - if (!bluetooth_rfkill) + bluetooth_rfkill = rfkill_alloc("dell-bluetooth", NULL, + RFKILL_TYPE_BLUETOOTH, + &dell_rfkill_ops, (void *) 2); + if (!bluetooth_rfkill) { + ret = -ENOMEM; goto err_bluetooth; - bluetooth_rfkill->name = "dell-bluetooth"; - bluetooth_rfkill->toggle_radio = dell_bluetooth_set; - bluetooth_rfkill->get_state = dell_bluetooth_get; + } ret = rfkill_register(bluetooth_rfkill); if (ret) goto err_bluetooth; } if ((status & (1<<4|1<<10)) == (1<<4|1<<10)) { - wwan_rfkill = rfkill_allocate(NULL, RFKILL_TYPE_WWAN); - if (!wwan_rfkill) + wwan_rfkill = rfkill_alloc("dell-wwan", NULL, RFKILL_TYPE_WWAN, + &dell_rfkill_ops, (void *) 3); + if (!wwan_rfkill) { + ret = -ENOMEM; goto err_wwan; - wwan_rfkill->name = "dell-wwan"; - wwan_rfkill->toggle_radio = dell_wwan_set; - wwan_rfkill->get_state = dell_wwan_get; + } ret = rfkill_register(wwan_rfkill); if (ret) goto err_wwan; @@ -285,22 +255,15 @@ static int dell_setup_rfkill(void) return 0; err_wwan: - if (wwan_rfkill) - rfkill_free(wwan_rfkill); - if (bluetooth_rfkill) { - rfkill_unregister(bluetooth_rfkill); - bluetooth_rfkill = NULL; - } -err_bluetooth: + rfkill_destroy(wwan_rfkill); if (bluetooth_rfkill) - rfkill_free(bluetooth_rfkill); - if (wifi_rfkill) { - rfkill_unregister(wifi_rfkill); - wifi_rfkill = NULL; - } -err_wifi: + rfkill_unregister(bluetooth_rfkill); +err_bluetooth: + rfkill_destroy(bluetooth_rfkill); if (wifi_rfkill) - rfkill_free(wifi_rfkill); + rfkill_unregister(wifi_rfkill); +err_wifi: + rfkill_destroy(wifi_rfkill); return ret; } diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c index 2fab94162147..0f900cc9fa7a 100644 --- a/drivers/platform/x86/dell-wmi.c +++ b/drivers/platform/x86/dell-wmi.c @@ -46,10 +46,53 @@ struct key_entry { u16 keycode; }; -enum { KE_KEY, KE_SW, KE_END }; +enum { KE_KEY, KE_SW, KE_IGNORE, KE_END }; + +/* + * Certain keys are flagged as KE_IGNORE. All of these are either + * notifications (rather than requests for change) or are also sent + * via the keyboard controller so should not be sent again. + */ static struct key_entry dell_wmi_keymap[] = { {KE_KEY, 0xe045, KEY_PROG1}, + {KE_KEY, 0xe009, KEY_EJECTCD}, + + /* These also contain the brightness level at offset 6 */ + {KE_KEY, 0xe006, KEY_BRIGHTNESSUP}, + {KE_KEY, 0xe005, KEY_BRIGHTNESSDOWN}, + + /* Battery health status button */ + {KE_KEY, 0xe007, KEY_BATTERY}, + + /* This is actually for all radios. Although physically a + * switch, the notification does not provide an indication of + * state and so it should be reported as a key */ + {KE_KEY, 0xe008, KEY_WLAN}, + + /* The next device is at offset 6, the active devices are at + offset 8 and the attached devices at offset 10 */ + {KE_KEY, 0xe00b, KEY_DISPLAYTOGGLE}, + + {KE_IGNORE, 0xe00c, KEY_KBDILLUMTOGGLE}, + + /* BIOS error detected */ + {KE_IGNORE, 0xe00d, KEY_RESERVED}, + + /* Wifi Catcher */ + {KE_KEY, 0xe011, KEY_PROG2}, + + /* Ambient light sensor toggle */ + {KE_IGNORE, 0xe013, KEY_RESERVED}, + + {KE_IGNORE, 0xe020, KEY_MUTE}, + {KE_IGNORE, 0xe02e, KEY_VOLUMEDOWN}, + {KE_IGNORE, 0xe030, KEY_VOLUMEUP}, + {KE_IGNORE, 0xe033, KEY_KBDILLUMUP}, + {KE_IGNORE, 0xe034, KEY_KBDILLUMDOWN}, + {KE_IGNORE, 0xe03a, KEY_CAPSLOCK}, + {KE_IGNORE, 0xe045, KEY_NUMLOCK}, + {KE_IGNORE, 0xe046, KEY_SCROLLLOCK}, {KE_END, 0} }; @@ -122,15 +165,20 @@ static void dell_wmi_notify(u32 value, void *context) if (obj && obj->type == ACPI_TYPE_BUFFER) { int *buffer = (int *)obj->buffer.pointer; - key = dell_wmi_get_entry_by_scancode(buffer[1]); + /* + * The upper bytes of the event may contain + * additional information, so mask them off for the + * scancode lookup + */ + key = dell_wmi_get_entry_by_scancode(buffer[1] & 0xFFFF); if (key) { input_report_key(dell_wmi_input_dev, key->keycode, 1); input_sync(dell_wmi_input_dev); input_report_key(dell_wmi_input_dev, key->keycode, 0); input_sync(dell_wmi_input_dev); - } else + } else if (buffer[1] & 0xFFFF) printk(KERN_INFO "dell-wmi: Unknown key %x pressed\n", - buffer[1]); + buffer[1] & 0xFFFF); } } diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 353a898c3693..4207b26ff990 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -62,7 +62,10 @@ enum { DISABLE_ASL_GPS = 0x0020, DISABLE_ASL_DISPLAYSWITCH = 0x0040, DISABLE_ASL_MODEM = 0x0080, - DISABLE_ASL_CARDREADER = 0x0100 + DISABLE_ASL_CARDREADER = 0x0100, + DISABLE_ASL_3G = 0x0200, + DISABLE_ASL_WIMAX = 0x0400, + DISABLE_ASL_HWCF = 0x0800 }; enum { @@ -87,7 +90,13 @@ enum { CM_ASL_USBPORT3, CM_ASL_MODEM, CM_ASL_CARDREADER, - CM_ASL_LID + CM_ASL_3G, + CM_ASL_WIMAX, + CM_ASL_HWCF, + CM_ASL_LID, + CM_ASL_TYPE, + CM_ASL_PANELPOWER, /*P901*/ + CM_ASL_TPD }; static const char *cm_getv[] = { @@ -96,7 +105,8 @@ static const char *cm_getv[] = { NULL, "PBLG", NULL, NULL, "CFVG", NULL, NULL, NULL, "USBG", NULL, NULL, "MODG", - "CRDG", "LIDG" + "CRDG", "M3GG", "WIMG", "HWCF", + "LIDG", "TYPE", "PBPG", "TPDG" }; static const char *cm_setv[] = { @@ -105,7 +115,8 @@ static const char *cm_setv[] = { "SDSP", "PBLS", "HDPS", NULL, "CFVS", NULL, NULL, NULL, "USBG", NULL, NULL, "MODS", - "CRDS", NULL + "CRDS", "M3GS", "WIMS", NULL, + NULL, NULL, "PBPS", "TPDS" }; #define EEEPC_EC "\\_SB.PCI0.SBRG.EC0." @@ -180,6 +191,8 @@ static struct key_entry eeepc_keymap[] = { */ static int eeepc_hotk_add(struct acpi_device *device); static int eeepc_hotk_remove(struct acpi_device *device, int type); +static int eeepc_hotk_resume(struct acpi_device *device); +static void eeepc_hotk_notify(struct acpi_device *device, u32 event); static const struct acpi_device_id eeepc_device_ids[] = { {EEEPC_HOTK_HID, 0}, @@ -191,9 +204,12 @@ static struct acpi_driver eeepc_hotk_driver = { .name = EEEPC_HOTK_NAME, .class = EEEPC_HOTK_CLASS, .ids = eeepc_device_ids, + .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS, .ops = { .add = eeepc_hotk_add, .remove = eeepc_hotk_remove, + .resume = eeepc_hotk_resume, + .notify = eeepc_hotk_notify, }, }; @@ -299,38 +315,30 @@ static int update_bl_status(struct backlight_device *bd) * Rfkill helpers */ -static int eeepc_wlan_rfkill_set(void *data, enum rfkill_state state) -{ - if (state == RFKILL_STATE_SOFT_BLOCKED) - return set_acpi(CM_ASL_WLAN, 0); - else - return set_acpi(CM_ASL_WLAN, 1); -} - -static int eeepc_wlan_rfkill_state(void *data, enum rfkill_state *state) +static bool eeepc_wlan_rfkill_blocked(void) { if (get_acpi(CM_ASL_WLAN) == 1) - *state = RFKILL_STATE_UNBLOCKED; - else - *state = RFKILL_STATE_SOFT_BLOCKED; - return 0; + return false; + return true; } -static int eeepc_bluetooth_rfkill_set(void *data, enum rfkill_state state) +static int eeepc_rfkill_set(void *data, bool blocked) { - if (state == RFKILL_STATE_SOFT_BLOCKED) - return set_acpi(CM_ASL_BLUETOOTH, 0); - else - return set_acpi(CM_ASL_BLUETOOTH, 1); + unsigned long asl = (unsigned long)data; + return set_acpi(asl, !blocked); } -static int eeepc_bluetooth_rfkill_state(void *data, enum rfkill_state *state) +static const struct rfkill_ops eeepc_rfkill_ops = { + .set_block = eeepc_rfkill_set, +}; + +static void __init eeepc_enable_camera(void) { - if (get_acpi(CM_ASL_BLUETOOTH) == 1) - *state = RFKILL_STATE_UNBLOCKED; - else - *state = RFKILL_STATE_SOFT_BLOCKED; - return 0; + /* + * If the following call to set_acpi() fails, it's because there's no + * camera so we can ignore the error. + */ + set_acpi(CM_ASL_CAMERA, 1); } /* @@ -384,13 +392,88 @@ static ssize_t show_sys_acpi(int cm, char *buf) EEEPC_CREATE_DEVICE_ATTR(camera, CM_ASL_CAMERA); EEEPC_CREATE_DEVICE_ATTR(cardr, CM_ASL_CARDREADER); EEEPC_CREATE_DEVICE_ATTR(disp, CM_ASL_DISPLAYSWITCH); -EEEPC_CREATE_DEVICE_ATTR(cpufv, CM_ASL_CPUFV); + +struct eeepc_cpufv { + int num; + int cur; +}; + +static int get_cpufv(struct eeepc_cpufv *c) +{ + c->cur = get_acpi(CM_ASL_CPUFV); + c->num = (c->cur >> 8) & 0xff; + c->cur &= 0xff; + if (c->cur < 0 || c->num <= 0 || c->num > 12) + return -ENODEV; + return 0; +} + +static ssize_t show_available_cpufv(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct eeepc_cpufv c; + int i; + ssize_t len = 0; + + if (get_cpufv(&c)) + return -ENODEV; + for (i = 0; i < c.num; i++) + len += sprintf(buf + len, "%d ", i); + len += sprintf(buf + len, "\n"); + return len; +} + +static ssize_t show_cpufv(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct eeepc_cpufv c; + + if (get_cpufv(&c)) + return -ENODEV; + return sprintf(buf, "%#x\n", (c.num << 8) | c.cur); +} + +static ssize_t store_cpufv(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct eeepc_cpufv c; + int rv, value; + + if (get_cpufv(&c)) + return -ENODEV; + rv = parse_arg(buf, count, &value); + if (rv < 0) + return rv; + if (!rv || value < 0 || value >= c.num) + return -EINVAL; + set_acpi(CM_ASL_CPUFV, value); + return rv; +} + +static struct device_attribute dev_attr_cpufv = { + .attr = { + .name = "cpufv", + .mode = 0644 }, + .show = show_cpufv, + .store = store_cpufv +}; + +static struct device_attribute dev_attr_available_cpufv = { + .attr = { + .name = "available_cpufv", + .mode = 0444 }, + .show = show_available_cpufv +}; static struct attribute *platform_attributes[] = { &dev_attr_camera.attr, &dev_attr_cardr.attr, &dev_attr_disp.attr, &dev_attr_cpufv.attr, + &dev_attr_available_cpufv.attr, NULL }; @@ -529,23 +612,19 @@ static int notify_brn(void) return -1; } -static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) +static void eeepc_rfkill_hotplug(void) { - enum rfkill_state state; struct pci_dev *dev; struct pci_bus *bus = pci_find_bus(0, 1); - - if (event != ACPI_NOTIFY_BUS_CHECK) - return; + bool blocked; if (!bus) { printk(EEEPC_WARNING "Unable to find PCI bus 1?\n"); return; } - eeepc_wlan_rfkill_state(ehotk->eeepc_wlan_rfkill, &state); - - if (state == RFKILL_STATE_UNBLOCKED) { + blocked = eeepc_wlan_rfkill_blocked(); + if (!blocked) { dev = pci_get_slot(bus, 0); if (dev) { /* Device already present */ @@ -566,10 +645,18 @@ static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) } } - rfkill_force_state(ehotk->eeepc_wlan_rfkill, state); + rfkill_set_sw_state(ehotk->eeepc_wlan_rfkill, blocked); } -static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data) +static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) +{ + if (event != ACPI_NOTIFY_BUS_CHECK) + return; + + eeepc_rfkill_hotplug(); +} + +static void eeepc_hotk_notify(struct acpi_device *device, u32 event) { static struct key_entry *key; u16 count; @@ -577,6 +664,8 @@ static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data) if (!ehotk) return; + if (event > ACPI_MAX_SYS_NOTIFY) + return; if (event >= NOTIFY_BRN_MIN && event <= NOTIFY_BRN_MAX) brn = notify_brn(); count = ehotk->event_count[event % 128]++; @@ -657,7 +746,6 @@ static void eeepc_unregister_rfkill_notifier(char *node) static int eeepc_hotk_add(struct acpi_device *device) { - acpi_status status = AE_OK; int result; if (!device) @@ -675,35 +763,22 @@ static int eeepc_hotk_add(struct acpi_device *device) result = eeepc_hotk_check(); if (result) goto ehotk_fail; - status = acpi_install_notify_handler(ehotk->handle, ACPI_SYSTEM_NOTIFY, - eeepc_hotk_notify, ehotk); - if (ACPI_FAILURE(status)) - printk(EEEPC_ERR "Error installing notify handler\n"); eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P6"); eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7"); if (get_acpi(CM_ASL_WLAN) != -1) { - ehotk->eeepc_wlan_rfkill = rfkill_allocate(&device->dev, - RFKILL_TYPE_WLAN); + ehotk->eeepc_wlan_rfkill = rfkill_alloc("eeepc-wlan", + &device->dev, + RFKILL_TYPE_WLAN, + &eeepc_rfkill_ops, + (void *)CM_ASL_WLAN); if (!ehotk->eeepc_wlan_rfkill) goto wlan_fail; - ehotk->eeepc_wlan_rfkill->name = "eeepc-wlan"; - ehotk->eeepc_wlan_rfkill->toggle_radio = eeepc_wlan_rfkill_set; - ehotk->eeepc_wlan_rfkill->get_state = eeepc_wlan_rfkill_state; - if (get_acpi(CM_ASL_WLAN) == 1) { - ehotk->eeepc_wlan_rfkill->state = - RFKILL_STATE_UNBLOCKED; - rfkill_set_default(RFKILL_TYPE_WLAN, - RFKILL_STATE_UNBLOCKED); - } else { - ehotk->eeepc_wlan_rfkill->state = - RFKILL_STATE_SOFT_BLOCKED; - rfkill_set_default(RFKILL_TYPE_WLAN, - RFKILL_STATE_SOFT_BLOCKED); - } + rfkill_init_sw_state(ehotk->eeepc_wlan_rfkill, + get_acpi(CM_ASL_WLAN) != 1); result = rfkill_register(ehotk->eeepc_wlan_rfkill); if (result) goto wlan_fail; @@ -711,28 +786,17 @@ static int eeepc_hotk_add(struct acpi_device *device) if (get_acpi(CM_ASL_BLUETOOTH) != -1) { ehotk->eeepc_bluetooth_rfkill = - rfkill_allocate(&device->dev, RFKILL_TYPE_BLUETOOTH); + rfkill_alloc("eeepc-bluetooth", + &device->dev, + RFKILL_TYPE_BLUETOOTH, + &eeepc_rfkill_ops, + (void *)CM_ASL_BLUETOOTH); if (!ehotk->eeepc_bluetooth_rfkill) goto bluetooth_fail; - ehotk->eeepc_bluetooth_rfkill->name = "eeepc-bluetooth"; - ehotk->eeepc_bluetooth_rfkill->toggle_radio = - eeepc_bluetooth_rfkill_set; - ehotk->eeepc_bluetooth_rfkill->get_state = - eeepc_bluetooth_rfkill_state; - if (get_acpi(CM_ASL_BLUETOOTH) == 1) { - ehotk->eeepc_bluetooth_rfkill->state = - RFKILL_STATE_UNBLOCKED; - rfkill_set_default(RFKILL_TYPE_BLUETOOTH, - RFKILL_STATE_UNBLOCKED); - } else { - ehotk->eeepc_bluetooth_rfkill->state = - RFKILL_STATE_SOFT_BLOCKED; - rfkill_set_default(RFKILL_TYPE_BLUETOOTH, - RFKILL_STATE_SOFT_BLOCKED); - } - + rfkill_init_sw_state(ehotk->eeepc_bluetooth_rfkill, + get_acpi(CM_ASL_BLUETOOTH) != 1); result = rfkill_register(ehotk->eeepc_bluetooth_rfkill); if (result) goto bluetooth_fail; @@ -741,13 +805,10 @@ static int eeepc_hotk_add(struct acpi_device *device) return 0; bluetooth_fail: - if (ehotk->eeepc_bluetooth_rfkill) - rfkill_free(ehotk->eeepc_bluetooth_rfkill); + rfkill_destroy(ehotk->eeepc_bluetooth_rfkill); rfkill_unregister(ehotk->eeepc_wlan_rfkill); - ehotk->eeepc_wlan_rfkill = NULL; wlan_fail: - if (ehotk->eeepc_wlan_rfkill) - rfkill_free(ehotk->eeepc_wlan_rfkill); + rfkill_destroy(ehotk->eeepc_wlan_rfkill); eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6"); eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7"); ehotk_fail: @@ -759,14 +820,8 @@ static int eeepc_hotk_add(struct acpi_device *device) static int eeepc_hotk_remove(struct acpi_device *device, int type) { - acpi_status status = 0; - if (!device || !acpi_driver_data(device)) return -EINVAL; - status = acpi_remove_notify_handler(ehotk->handle, ACPI_SYSTEM_NOTIFY, - eeepc_hotk_notify); - if (ACPI_FAILURE(status)) - printk(EEEPC_ERR "Error removing notify handler\n"); eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6"); eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7"); @@ -775,6 +830,33 @@ static int eeepc_hotk_remove(struct acpi_device *device, int type) return 0; } +static int eeepc_hotk_resume(struct acpi_device *device) +{ + if (ehotk->eeepc_wlan_rfkill) { + bool wlan; + + /* Workaround - it seems that _PTS disables the wireless + without notification or changing the value read by WLAN. + Normally this is fine because the correct value is restored + from the non-volatile storage on resume, but we need to do + it ourself if case suspend is aborted, or we lose wireless. + */ + wlan = get_acpi(CM_ASL_WLAN); + set_acpi(CM_ASL_WLAN, wlan); + + rfkill_set_sw_state(ehotk->eeepc_wlan_rfkill, + wlan != 1); + + eeepc_rfkill_hotplug(); + } + + if (ehotk->eeepc_bluetooth_rfkill) + rfkill_set_sw_state(ehotk->eeepc_bluetooth_rfkill, + get_acpi(CM_ASL_BLUETOOTH) != 1); + + return 0; +} + /* * Hwmon */ @@ -996,6 +1078,9 @@ static int __init eeepc_laptop_init(void) result = eeepc_hwmon_init(dev); if (result) goto fail_hwmon; + + eeepc_enable_camera(); + /* Register platform stuff */ result = platform_driver_register(&platform_driver); if (result) diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index 50d9019de2be..4ac2311c00af 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -47,7 +47,7 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4"); #define HPWMI_DISPLAY_QUERY 0x1 #define HPWMI_HDDTEMP_QUERY 0x2 #define HPWMI_ALS_QUERY 0x3 -#define HPWMI_DOCK_QUERY 0x4 +#define HPWMI_HARDWARE_QUERY 0x4 #define HPWMI_WIRELESS_QUERY 0x5 #define HPWMI_HOTKEY_QUERY 0xc @@ -75,10 +75,9 @@ struct key_entry { u16 keycode; }; -enum { KE_KEY, KE_SW, KE_END }; +enum { KE_KEY, KE_END }; static struct key_entry hp_wmi_keymap[] = { - {KE_SW, 0x01, SW_DOCK}, {KE_KEY, 0x02, KEY_BRIGHTNESSUP}, {KE_KEY, 0x03, KEY_BRIGHTNESSDOWN}, {KE_KEY, 0x20e6, KEY_PROG1}, @@ -151,61 +150,64 @@ static int hp_wmi_als_state(void) static int hp_wmi_dock_state(void) { - return hp_wmi_perform_query(HPWMI_DOCK_QUERY, 0, 0); + int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, 0); + + if (ret < 0) + return ret; + + return ret & 0x1; } -static int hp_wmi_wifi_set(void *data, enum rfkill_state state) +static int hp_wmi_tablet_state(void) { - if (state) - return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x101); - else - return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x100); + int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, 0); + + if (ret < 0) + return ret; + + return (ret & 0x4) ? 1 : 0; } -static int hp_wmi_bluetooth_set(void *data, enum rfkill_state state) +static int hp_wmi_set_block(void *data, bool blocked) { - if (state) - return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x202); - else - return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x200); + unsigned long b = (unsigned long) data; + int query = BIT(b + 8) | ((!!blocked) << b); + + return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, query); } -static int hp_wmi_wwan_set(void *data, enum rfkill_state state) -{ - if (state) - return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x404); - else - return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x400); -} +static const struct rfkill_ops hp_wmi_rfkill_ops = { + .set_block = hp_wmi_set_block, +}; -static int hp_wmi_wifi_state(void) +static bool hp_wmi_wifi_state(void) { int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0); if (wireless & 0x100) - return RFKILL_STATE_UNBLOCKED; + return false; else - return RFKILL_STATE_SOFT_BLOCKED; + return true; } -static int hp_wmi_bluetooth_state(void) +static bool hp_wmi_bluetooth_state(void) { int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0); if (wireless & 0x10000) - return RFKILL_STATE_UNBLOCKED; + return false; else - return RFKILL_STATE_SOFT_BLOCKED; + return true; } -static int hp_wmi_wwan_state(void) +static bool hp_wmi_wwan_state(void) { int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0); if (wireless & 0x1000000) - return RFKILL_STATE_UNBLOCKED; + return false; else - return RFKILL_STATE_SOFT_BLOCKED; + return true; } static ssize_t show_display(struct device *dev, struct device_attribute *attr, @@ -244,6 +246,15 @@ static ssize_t show_dock(struct device *dev, struct device_attribute *attr, return sprintf(buf, "%d\n", value); } +static ssize_t show_tablet(struct device *dev, struct device_attribute *attr, + char *buf) +{ + int value = hp_wmi_tablet_state(); + if (value < 0) + return -EINVAL; + return sprintf(buf, "%d\n", value); +} + static ssize_t set_als(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { @@ -256,6 +267,7 @@ static DEVICE_ATTR(display, S_IRUGO, show_display, NULL); static DEVICE_ATTR(hddtemp, S_IRUGO, show_hddtemp, NULL); static DEVICE_ATTR(als, S_IRUGO | S_IWUSR, show_als, set_als); static DEVICE_ATTR(dock, S_IRUGO, show_dock, NULL); +static DEVICE_ATTR(tablet, S_IRUGO, show_tablet, NULL); static struct key_entry *hp_wmi_get_entry_by_scancode(int code) { @@ -338,23 +350,23 @@ static void hp_wmi_notify(u32 value, void *context) key->keycode, 0); input_sync(hp_wmi_input_dev); break; - case KE_SW: - input_report_switch(hp_wmi_input_dev, - key->keycode, - hp_wmi_dock_state()); - input_sync(hp_wmi_input_dev); - break; } + } else if (eventcode == 0x1) { + input_report_switch(hp_wmi_input_dev, SW_DOCK, + hp_wmi_dock_state()); + input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE, + hp_wmi_tablet_state()); + input_sync(hp_wmi_input_dev); } else if (eventcode == 0x5) { if (wifi_rfkill) - rfkill_force_state(wifi_rfkill, - hp_wmi_wifi_state()); + rfkill_set_sw_state(wifi_rfkill, + hp_wmi_wifi_state()); if (bluetooth_rfkill) - rfkill_force_state(bluetooth_rfkill, - hp_wmi_bluetooth_state()); + rfkill_set_sw_state(bluetooth_rfkill, + hp_wmi_bluetooth_state()); if (wwan_rfkill) - rfkill_force_state(wwan_rfkill, - hp_wmi_wwan_state()); + rfkill_set_sw_state(wwan_rfkill, + hp_wmi_wwan_state()); } else printk(KERN_INFO "HP WMI: Unknown key pressed - %x\n", eventcode); @@ -381,18 +393,19 @@ static int __init hp_wmi_input_setup(void) set_bit(EV_KEY, hp_wmi_input_dev->evbit); set_bit(key->keycode, hp_wmi_input_dev->keybit); break; - case KE_SW: - set_bit(EV_SW, hp_wmi_input_dev->evbit); - set_bit(key->keycode, hp_wmi_input_dev->swbit); - - /* Set initial dock state */ - input_report_switch(hp_wmi_input_dev, key->keycode, - hp_wmi_dock_state()); - input_sync(hp_wmi_input_dev); - break; } } + set_bit(EV_SW, hp_wmi_input_dev->evbit); + set_bit(SW_DOCK, hp_wmi_input_dev->swbit); + set_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit); + + /* Set initial hardware state */ + input_report_switch(hp_wmi_input_dev, SW_DOCK, hp_wmi_dock_state()); + input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE, + hp_wmi_tablet_state()); + input_sync(hp_wmi_input_dev); + err = input_register_device(hp_wmi_input_dev); if (err) { @@ -409,6 +422,7 @@ static void cleanup_sysfs(struct platform_device *device) device_remove_file(&device->dev, &dev_attr_hddtemp); device_remove_file(&device->dev, &dev_attr_als); device_remove_file(&device->dev, &dev_attr_dock); + device_remove_file(&device->dev, &dev_attr_tablet); } static int __init hp_wmi_bios_setup(struct platform_device *device) @@ -426,38 +440,37 @@ static int __init hp_wmi_bios_setup(struct platform_device *device) if (err) goto add_sysfs_error; err = device_create_file(&device->dev, &dev_attr_dock); + if (err) + goto add_sysfs_error; + err = device_create_file(&device->dev, &dev_attr_tablet); if (err) goto add_sysfs_error; if (wireless & 0x1) { - wifi_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WLAN); - wifi_rfkill->name = "hp-wifi"; - wifi_rfkill->state = hp_wmi_wifi_state(); - wifi_rfkill->toggle_radio = hp_wmi_wifi_set; - wifi_rfkill->user_claim_unsupported = 1; + wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev, + RFKILL_TYPE_WLAN, + &hp_wmi_rfkill_ops, + (void *) 0); err = rfkill_register(wifi_rfkill); if (err) - goto add_sysfs_error; + goto register_wifi_error; } if (wireless & 0x2) { - bluetooth_rfkill = rfkill_allocate(&device->dev, - RFKILL_TYPE_BLUETOOTH); - bluetooth_rfkill->name = "hp-bluetooth"; - bluetooth_rfkill->state = hp_wmi_bluetooth_state(); - bluetooth_rfkill->toggle_radio = hp_wmi_bluetooth_set; - bluetooth_rfkill->user_claim_unsupported = 1; + bluetooth_rfkill = rfkill_alloc("hp-bluetooth", &device->dev, + RFKILL_TYPE_BLUETOOTH, + &hp_wmi_rfkill_ops, + (void *) 1); err = rfkill_register(bluetooth_rfkill); if (err) goto register_bluetooth_error; } if (wireless & 0x4) { - wwan_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WWAN); - wwan_rfkill->name = "hp-wwan"; - wwan_rfkill->state = hp_wmi_wwan_state(); - wwan_rfkill->toggle_radio = hp_wmi_wwan_set; - wwan_rfkill->user_claim_unsupported = 1; + wwan_rfkill = rfkill_alloc("hp-wwan", &device->dev, + RFKILL_TYPE_WWAN, + &hp_wmi_rfkill_ops, + (void *) 2); err = rfkill_register(wwan_rfkill); if (err) goto register_wwan_err; @@ -465,11 +478,15 @@ static int __init hp_wmi_bios_setup(struct platform_device *device) return 0; register_wwan_err: + rfkill_destroy(wwan_rfkill); if (bluetooth_rfkill) rfkill_unregister(bluetooth_rfkill); register_bluetooth_error: + rfkill_destroy(bluetooth_rfkill); if (wifi_rfkill) rfkill_unregister(wifi_rfkill); +register_wifi_error: + rfkill_destroy(wifi_rfkill); add_sysfs_error: cleanup_sysfs(device); return err; @@ -479,35 +496,35 @@ static int __exit hp_wmi_bios_remove(struct platform_device *device) { cleanup_sysfs(device); - if (wifi_rfkill) + if (wifi_rfkill) { rfkill_unregister(wifi_rfkill); - if (bluetooth_rfkill) + rfkill_destroy(wifi_rfkill); + } + if (bluetooth_rfkill) { rfkill_unregister(bluetooth_rfkill); - if (wwan_rfkill) + rfkill_destroy(wifi_rfkill); + } + if (wwan_rfkill) { rfkill_unregister(wwan_rfkill); + rfkill_destroy(wwan_rfkill); + } return 0; } static int hp_wmi_resume_handler(struct platform_device *device) { - struct key_entry *key; - /* - * Docking state may have changed while suspended, so trigger - * an input event for the current state. As this is a switch, + * Hardware state may have changed while suspended, so trigger + * input events for the current state. As this is a switch, * the input layer will only actually pass it on if the state * changed. */ - for (key = hp_wmi_keymap; key->type != KE_END; key++) { - switch (key->type) { - case KE_SW: - input_report_switch(hp_wmi_input_dev, key->keycode, - hp_wmi_dock_state()); - input_sync(hp_wmi_input_dev); - break; - } - } + + input_report_switch(hp_wmi_input_dev, SW_DOCK, hp_wmi_dock_state()); + input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE, + hp_wmi_tablet_state()); + input_sync(hp_wmi_input_dev); return 0; } diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index 552958545f94..dafaa4a92df5 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -128,11 +128,11 @@ enum sony_nc_rfkill { SONY_BLUETOOTH, SONY_WWAN, SONY_WIMAX, - SONY_RFKILL_MAX, + N_SONY_RFKILL, }; -static struct rfkill *sony_rfkill_devices[SONY_RFKILL_MAX]; -static int sony_rfkill_address[SONY_RFKILL_MAX] = {0x300, 0x500, 0x700, 0x900}; +static struct rfkill *sony_rfkill_devices[N_SONY_RFKILL]; +static int sony_rfkill_address[N_SONY_RFKILL] = {0x300, 0x500, 0x700, 0x900}; static void sony_nc_rfkill_update(void); /*********** Input Devices ***********/ @@ -1051,151 +1051,97 @@ static void sony_nc_rfkill_cleanup(void) { int i; - for (i = 0; i < SONY_RFKILL_MAX; i++) { - if (sony_rfkill_devices[i]) + for (i = 0; i < N_SONY_RFKILL; i++) { + if (sony_rfkill_devices[i]) { rfkill_unregister(sony_rfkill_devices[i]); + rfkill_destroy(sony_rfkill_devices[i]); + } } } -static int sony_nc_rfkill_get(void *data, enum rfkill_state *state) -{ - int result; - int argument = sony_rfkill_address[(long) data]; - - sony_call_snc_handle(0x124, 0x200, &result); - if (result & 0x1) { - sony_call_snc_handle(0x124, argument, &result); - if (result & 0xf) - *state = RFKILL_STATE_UNBLOCKED; - else - *state = RFKILL_STATE_SOFT_BLOCKED; - } else { - *state = RFKILL_STATE_HARD_BLOCKED; - } - - return 0; -} - -static int sony_nc_rfkill_set(void *data, enum rfkill_state state) +static int sony_nc_rfkill_set(void *data, bool blocked) { int result; int argument = sony_rfkill_address[(long) data] + 0x100; - if (state == RFKILL_STATE_UNBLOCKED) + if (!blocked) argument |= 0xff0000; return sony_call_snc_handle(0x124, argument, &result); } -static int sony_nc_setup_wifi_rfkill(struct acpi_device *device) +static const struct rfkill_ops sony_rfkill_ops = { + .set_block = sony_nc_rfkill_set, +}; + +static int sony_nc_setup_rfkill(struct acpi_device *device, + enum sony_nc_rfkill nc_type) { int err = 0; - struct rfkill *sony_wifi_rfkill; + struct rfkill *rfk; + enum rfkill_type type; + const char *name; - sony_wifi_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WLAN); - if (!sony_wifi_rfkill) - return -1; - sony_wifi_rfkill->name = "sony-wifi"; - sony_wifi_rfkill->toggle_radio = sony_nc_rfkill_set; - sony_wifi_rfkill->get_state = sony_nc_rfkill_get; - sony_wifi_rfkill->user_claim_unsupported = 1; - sony_wifi_rfkill->data = (void *)SONY_WIFI; - err = rfkill_register(sony_wifi_rfkill); - if (err) - rfkill_free(sony_wifi_rfkill); - else { - sony_rfkill_devices[SONY_WIFI] = sony_wifi_rfkill; - sony_nc_rfkill_set(sony_wifi_rfkill->data, - RFKILL_STATE_UNBLOCKED); + switch (nc_type) { + case SONY_WIFI: + type = RFKILL_TYPE_WLAN; + name = "sony-wifi"; + break; + case SONY_BLUETOOTH: + type = RFKILL_TYPE_BLUETOOTH; + name = "sony-bluetooth"; + break; + case SONY_WWAN: + type = RFKILL_TYPE_WWAN; + name = "sony-wwan"; + break; + case SONY_WIMAX: + type = RFKILL_TYPE_WIMAX; + name = "sony-wimax"; + break; + default: + return -EINVAL; } - return err; -} -static int sony_nc_setup_bluetooth_rfkill(struct acpi_device *device) -{ - int err = 0; - struct rfkill *sony_bluetooth_rfkill; + rfk = rfkill_alloc(name, &device->dev, type, + &sony_rfkill_ops, (void *)nc_type); + if (!rfk) + return -ENOMEM; - sony_bluetooth_rfkill = rfkill_allocate(&device->dev, - RFKILL_TYPE_BLUETOOTH); - if (!sony_bluetooth_rfkill) - return -1; - sony_bluetooth_rfkill->name = "sony-bluetooth"; - sony_bluetooth_rfkill->toggle_radio = sony_nc_rfkill_set; - sony_bluetooth_rfkill->get_state = sony_nc_rfkill_get; - sony_bluetooth_rfkill->user_claim_unsupported = 1; - sony_bluetooth_rfkill->data = (void *)SONY_BLUETOOTH; - err = rfkill_register(sony_bluetooth_rfkill); - if (err) - rfkill_free(sony_bluetooth_rfkill); - else { - sony_rfkill_devices[SONY_BLUETOOTH] = sony_bluetooth_rfkill; - sony_nc_rfkill_set(sony_bluetooth_rfkill->data, - RFKILL_STATE_UNBLOCKED); - } - return err; -} - -static int sony_nc_setup_wwan_rfkill(struct acpi_device *device) -{ - int err = 0; - struct rfkill *sony_wwan_rfkill; - - sony_wwan_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WWAN); - if (!sony_wwan_rfkill) - return -1; - sony_wwan_rfkill->name = "sony-wwan"; - sony_wwan_rfkill->toggle_radio = sony_nc_rfkill_set; - sony_wwan_rfkill->get_state = sony_nc_rfkill_get; - sony_wwan_rfkill->user_claim_unsupported = 1; - sony_wwan_rfkill->data = (void *)SONY_WWAN; - err = rfkill_register(sony_wwan_rfkill); - if (err) - rfkill_free(sony_wwan_rfkill); - else { - sony_rfkill_devices[SONY_WWAN] = sony_wwan_rfkill; - sony_nc_rfkill_set(sony_wwan_rfkill->data, - RFKILL_STATE_UNBLOCKED); - } - return err; -} - -static int sony_nc_setup_wimax_rfkill(struct acpi_device *device) -{ - int err = 0; - struct rfkill *sony_wimax_rfkill; - - sony_wimax_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WIMAX); - if (!sony_wimax_rfkill) - return -1; - sony_wimax_rfkill->name = "sony-wimax"; - sony_wimax_rfkill->toggle_radio = sony_nc_rfkill_set; - sony_wimax_rfkill->get_state = sony_nc_rfkill_get; - sony_wimax_rfkill->user_claim_unsupported = 1; - sony_wimax_rfkill->data = (void *)SONY_WIMAX; - err = rfkill_register(sony_wimax_rfkill); - if (err) - rfkill_free(sony_wimax_rfkill); - else { - sony_rfkill_devices[SONY_WIMAX] = sony_wimax_rfkill; - sony_nc_rfkill_set(sony_wimax_rfkill->data, - RFKILL_STATE_UNBLOCKED); + err = rfkill_register(rfk); + if (err) { + rfkill_destroy(rfk); + return err; } + sony_rfkill_devices[nc_type] = rfk; return err; } static void sony_nc_rfkill_update() { - int i; - enum rfkill_state state; + enum sony_nc_rfkill i; + int result; + bool hwblock; - for (i = 0; i < SONY_RFKILL_MAX; i++) { - if (sony_rfkill_devices[i]) { - sony_rfkill_devices[i]-> - get_state(sony_rfkill_devices[i]->data, - &state); - rfkill_force_state(sony_rfkill_devices[i], state); + sony_call_snc_handle(0x124, 0x200, &result); + hwblock = !(result & 0x1); + + for (i = 0; i < N_SONY_RFKILL; i++) { + int argument = sony_rfkill_address[i]; + + if (!sony_rfkill_devices[i]) + continue; + + if (hwblock) { + if (rfkill_set_hw_state(sony_rfkill_devices[i], true)) { + /* we already know we're blocked */ + } + continue; } + + sony_call_snc_handle(0x124, argument, &result); + rfkill_set_states(sony_rfkill_devices[i], + !(result & 0xf), false); } } @@ -1214,13 +1160,13 @@ static int sony_nc_rfkill_setup(struct acpi_device *device) } if (result & 0x1) - sony_nc_setup_wifi_rfkill(device); + sony_nc_setup_rfkill(device, SONY_WIFI); if (result & 0x2) - sony_nc_setup_bluetooth_rfkill(device); + sony_nc_setup_rfkill(device, SONY_BLUETOOTH); if (result & 0x1c) - sony_nc_setup_wwan_rfkill(device); + sony_nc_setup_rfkill(device, SONY_WWAN); if (result & 0x20) - sony_nc_setup_wimax_rfkill(device); + sony_nc_setup_rfkill(device, SONY_WIMAX); return 0; } diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 912be65b6261..a463fd72c495 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -22,7 +22,7 @@ */ #define TPACPI_VERSION "0.23" -#define TPACPI_SYSFS_VERSION 0x020300 +#define TPACPI_SYSFS_VERSION 0x020400 /* * Changelog: @@ -166,13 +166,6 @@ enum { #define TPACPI_MAX_ACPI_ARGS 3 -/* rfkill switches */ -enum { - TPACPI_RFK_BLUETOOTH_SW_ID = 0, - TPACPI_RFK_WWAN_SW_ID, - TPACPI_RFK_UWB_SW_ID, -}; - /* printk headers */ #define TPACPI_LOG TPACPI_FILE ": " #define TPACPI_EMERG KERN_EMERG TPACPI_LOG @@ -264,6 +257,8 @@ static struct { u32 wan:1; u32 uwb:1; u32 fan_ctrl_status_undef:1; + u32 second_fan:1; + u32 beep_needs_two_args:1; u32 input_device_registered:1; u32 platform_drv_registered:1; u32 platform_drv_attrs_registered:1; @@ -284,8 +279,10 @@ struct thinkpad_id_data { char *bios_version_str; /* Something like 1ZET51WW (1.03z) */ char *ec_version_str; /* Something like 1ZHT51WW-1.04a */ - u16 bios_model; /* Big Endian, TP-1Y = 0x5931, 0 = unknown */ + u16 bios_model; /* 1Y = 0x5931, 0 = unknown */ u16 ec_model; + u16 bios_release; /* 1ZETK1WW = 0x314b, 0 = unknown */ + u16 ec_release; char *model_str; /* ThinkPad T43 */ char *nummodel_str; /* 9384A9C for a 9384-A9C model */ @@ -362,6 +359,73 @@ static void tpacpi_log_usertask(const char * const what) } \ } while (0) +/* + * Quirk handling helpers + * + * ThinkPad IDs and versions seen in the field so far + * are two-characters from the set [0-9A-Z], i.e. base 36. + * + * We use values well outside that range as specials. + */ + +#define TPACPI_MATCH_ANY 0xffffU +#define TPACPI_MATCH_UNKNOWN 0U + +/* TPID('1', 'Y') == 0x5931 */ +#define TPID(__c1, __c2) (((__c2) << 8) | (__c1)) + +#define TPACPI_Q_IBM(__id1, __id2, __quirk) \ + { .vendor = PCI_VENDOR_ID_IBM, \ + .bios = TPID(__id1, __id2), \ + .ec = TPACPI_MATCH_ANY, \ + .quirks = (__quirk) } + +#define TPACPI_Q_LNV(__id1, __id2, __quirk) \ + { .vendor = PCI_VENDOR_ID_LENOVO, \ + .bios = TPID(__id1, __id2), \ + .ec = TPACPI_MATCH_ANY, \ + .quirks = (__quirk) } + +struct tpacpi_quirk { + unsigned int vendor; + u16 bios; + u16 ec; + unsigned long quirks; +}; + +/** + * tpacpi_check_quirks() - search BIOS/EC version on a list + * @qlist: array of &struct tpacpi_quirk + * @qlist_size: number of elements in @qlist + * + * Iterates over a quirks list until one is found that matches the + * ThinkPad's vendor, BIOS and EC model. + * + * Returns 0 if nothing matches, otherwise returns the quirks field of + * the matching &struct tpacpi_quirk entry. + * + * The match criteria is: vendor, ec and bios much match. + */ +static unsigned long __init tpacpi_check_quirks( + const struct tpacpi_quirk *qlist, + unsigned int qlist_size) +{ + while (qlist_size) { + if ((qlist->vendor == thinkpad_id.vendor || + qlist->vendor == TPACPI_MATCH_ANY) && + (qlist->bios == thinkpad_id.bios_model || + qlist->bios == TPACPI_MATCH_ANY) && + (qlist->ec == thinkpad_id.ec_model || + qlist->ec == TPACPI_MATCH_ANY)) + return qlist->quirks; + + qlist_size--; + qlist++; + } + return 0; +} + + /**************************************************************************** **************************************************************************** * @@ -1005,60 +1069,6 @@ static int __init tpacpi_check_std_acpi_brightness_support(void) return 0; } -static int __init tpacpi_new_rfkill(const unsigned int id, - struct rfkill **rfk, - const enum rfkill_type rfktype, - const char *name, - const bool set_default, - int (*toggle_radio)(void *, enum rfkill_state), - int (*get_state)(void *, enum rfkill_state *)) -{ - int res; - enum rfkill_state initial_state = RFKILL_STATE_SOFT_BLOCKED; - - res = get_state(NULL, &initial_state); - if (res < 0) { - printk(TPACPI_ERR - "failed to read initial state for %s, error %d; " - "will turn radio off\n", name, res); - } else if (set_default) { - /* try to set the initial state as the default for the rfkill - * type, since we ask the firmware to preserve it across S5 in - * NVRAM */ - if (rfkill_set_default(rfktype, - (initial_state == RFKILL_STATE_UNBLOCKED) ? - RFKILL_STATE_UNBLOCKED : - RFKILL_STATE_SOFT_BLOCKED) == -EPERM) - vdbg_printk(TPACPI_DBG_RFKILL, - "Default state for %s cannot be changed\n", - name); - } - - *rfk = rfkill_allocate(&tpacpi_pdev->dev, rfktype); - if (!*rfk) { - printk(TPACPI_ERR - "failed to allocate memory for rfkill class\n"); - return -ENOMEM; - } - - (*rfk)->name = name; - (*rfk)->get_state = get_state; - (*rfk)->toggle_radio = toggle_radio; - (*rfk)->state = initial_state; - - res = rfkill_register(*rfk); - if (res < 0) { - printk(TPACPI_ERR - "failed to register %s rfkill switch: %d\n", - name, res); - rfkill_free(*rfk); - *rfk = NULL; - return res; - } - - return 0; -} - static void printk_deprecated_attribute(const char * const what, const char * const details) { @@ -1068,12 +1078,339 @@ static void printk_deprecated_attribute(const char * const what, what, details); } +/************************************************************************* + * rfkill and radio control support helpers + */ + +/* + * ThinkPad-ACPI firmware handling model: + * + * WLSW (master wireless switch) is event-driven, and is common to all + * firmware-controlled radios. It cannot be controlled, just monitored, + * as expected. It overrides all radio state in firmware + * + * The kernel, a masked-off hotkey, and WLSW can change the radio state + * (TODO: verify how WLSW interacts with the returned radio state). + * + * The only time there are shadow radio state changes, is when + * masked-off hotkeys are used. + */ + +/* + * Internal driver API for radio state: + * + * int: < 0 = error, otherwise enum tpacpi_rfkill_state + * bool: true means radio blocked (off) + */ +enum tpacpi_rfkill_state { + TPACPI_RFK_RADIO_OFF = 0, + TPACPI_RFK_RADIO_ON +}; + +/* rfkill switches */ +enum tpacpi_rfk_id { + TPACPI_RFK_BLUETOOTH_SW_ID = 0, + TPACPI_RFK_WWAN_SW_ID, + TPACPI_RFK_UWB_SW_ID, + TPACPI_RFK_SW_MAX +}; + +static const char *tpacpi_rfkill_names[] = { + [TPACPI_RFK_BLUETOOTH_SW_ID] = "bluetooth", + [TPACPI_RFK_WWAN_SW_ID] = "wwan", + [TPACPI_RFK_UWB_SW_ID] = "uwb", + [TPACPI_RFK_SW_MAX] = NULL +}; + +/* ThinkPad-ACPI rfkill subdriver */ +struct tpacpi_rfk { + struct rfkill *rfkill; + enum tpacpi_rfk_id id; + const struct tpacpi_rfk_ops *ops; +}; + +struct tpacpi_rfk_ops { + /* firmware interface */ + int (*get_status)(void); + int (*set_status)(const enum tpacpi_rfkill_state); +}; + +static struct tpacpi_rfk *tpacpi_rfkill_switches[TPACPI_RFK_SW_MAX]; + +/* Query FW and update rfkill sw state for a given rfkill switch */ +static int tpacpi_rfk_update_swstate(const struct tpacpi_rfk *tp_rfk) +{ + int status; + + if (!tp_rfk) + return -ENODEV; + + status = (tp_rfk->ops->get_status)(); + if (status < 0) + return status; + + rfkill_set_sw_state(tp_rfk->rfkill, + (status == TPACPI_RFK_RADIO_OFF)); + + return status; +} + +/* Query FW and update rfkill sw state for all rfkill switches */ +static void tpacpi_rfk_update_swstate_all(void) +{ + unsigned int i; + + for (i = 0; i < TPACPI_RFK_SW_MAX; i++) + tpacpi_rfk_update_swstate(tpacpi_rfkill_switches[i]); +} + +/* + * Sync the HW-blocking state of all rfkill switches, + * do notice it causes the rfkill core to schedule uevents + */ +static void tpacpi_rfk_update_hwblock_state(bool blocked) +{ + unsigned int i; + struct tpacpi_rfk *tp_rfk; + + for (i = 0; i < TPACPI_RFK_SW_MAX; i++) { + tp_rfk = tpacpi_rfkill_switches[i]; + if (tp_rfk) { + if (rfkill_set_hw_state(tp_rfk->rfkill, + blocked)) { + /* ignore -- we track sw block */ + } + } + } +} + +/* Call to get the WLSW state from the firmware */ +static int hotkey_get_wlsw(void); + +/* Call to query WLSW state and update all rfkill switches */ +static bool tpacpi_rfk_check_hwblock_state(void) +{ + int res = hotkey_get_wlsw(); + int hw_blocked; + + /* When unknown or unsupported, we have to assume it is unblocked */ + if (res < 0) + return false; + + hw_blocked = (res == TPACPI_RFK_RADIO_OFF); + tpacpi_rfk_update_hwblock_state(hw_blocked); + + return hw_blocked; +} + +static int tpacpi_rfk_hook_set_block(void *data, bool blocked) +{ + struct tpacpi_rfk *tp_rfk = data; + int res; + + dbg_printk(TPACPI_DBG_RFKILL, + "request to change radio state to %s\n", + blocked ? "blocked" : "unblocked"); + + /* try to set radio state */ + res = (tp_rfk->ops->set_status)(blocked ? + TPACPI_RFK_RADIO_OFF : TPACPI_RFK_RADIO_ON); + + /* and update the rfkill core with whatever the FW really did */ + tpacpi_rfk_update_swstate(tp_rfk); + + return (res < 0) ? res : 0; +} + +static const struct rfkill_ops tpacpi_rfk_rfkill_ops = { + .set_block = tpacpi_rfk_hook_set_block, +}; + +static int __init tpacpi_new_rfkill(const enum tpacpi_rfk_id id, + const struct tpacpi_rfk_ops *tp_rfkops, + const enum rfkill_type rfktype, + const char *name, + const bool set_default) +{ + struct tpacpi_rfk *atp_rfk; + int res; + bool sw_state = false; + int sw_status; + + BUG_ON(id >= TPACPI_RFK_SW_MAX || tpacpi_rfkill_switches[id]); + + atp_rfk = kzalloc(sizeof(struct tpacpi_rfk), GFP_KERNEL); + if (atp_rfk) + atp_rfk->rfkill = rfkill_alloc(name, + &tpacpi_pdev->dev, + rfktype, + &tpacpi_rfk_rfkill_ops, + atp_rfk); + if (!atp_rfk || !atp_rfk->rfkill) { + printk(TPACPI_ERR + "failed to allocate memory for rfkill class\n"); + kfree(atp_rfk); + return -ENOMEM; + } + + atp_rfk->id = id; + atp_rfk->ops = tp_rfkops; + + sw_status = (tp_rfkops->get_status)(); + if (sw_status < 0) { + printk(TPACPI_ERR + "failed to read initial state for %s, error %d\n", + name, sw_status); + } else { + sw_state = (sw_status == TPACPI_RFK_RADIO_OFF); + if (set_default) { + /* try to keep the initial state, since we ask the + * firmware to preserve it across S5 in NVRAM */ + rfkill_init_sw_state(atp_rfk->rfkill, sw_state); + } + } + rfkill_set_hw_state(atp_rfk->rfkill, tpacpi_rfk_check_hwblock_state()); + + res = rfkill_register(atp_rfk->rfkill); + if (res < 0) { + printk(TPACPI_ERR + "failed to register %s rfkill switch: %d\n", + name, res); + rfkill_destroy(atp_rfk->rfkill); + kfree(atp_rfk); + return res; + } + + tpacpi_rfkill_switches[id] = atp_rfk; + return 0; +} + +static void tpacpi_destroy_rfkill(const enum tpacpi_rfk_id id) +{ + struct tpacpi_rfk *tp_rfk; + + BUG_ON(id >= TPACPI_RFK_SW_MAX); + + tp_rfk = tpacpi_rfkill_switches[id]; + if (tp_rfk) { + rfkill_unregister(tp_rfk->rfkill); + tpacpi_rfkill_switches[id] = NULL; + kfree(tp_rfk); + } +} + static void printk_deprecated_rfkill_attribute(const char * const what) { printk_deprecated_attribute(what, "Please switch to generic rfkill before year 2010"); } +/* sysfs enable ------------------------------------------------ */ +static ssize_t tpacpi_rfk_sysfs_enable_show(const enum tpacpi_rfk_id id, + struct device_attribute *attr, + char *buf) +{ + int status; + + printk_deprecated_rfkill_attribute(attr->attr.name); + + /* This is in the ABI... */ + if (tpacpi_rfk_check_hwblock_state()) { + status = TPACPI_RFK_RADIO_OFF; + } else { + status = tpacpi_rfk_update_swstate(tpacpi_rfkill_switches[id]); + if (status < 0) + return status; + } + + return snprintf(buf, PAGE_SIZE, "%d\n", + (status == TPACPI_RFK_RADIO_ON) ? 1 : 0); +} + +static ssize_t tpacpi_rfk_sysfs_enable_store(const enum tpacpi_rfk_id id, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long t; + int res; + + printk_deprecated_rfkill_attribute(attr->attr.name); + + if (parse_strtoul(buf, 1, &t)) + return -EINVAL; + + tpacpi_disclose_usertask(attr->attr.name, "set to %ld\n", t); + + /* This is in the ABI... */ + if (tpacpi_rfk_check_hwblock_state() && !!t) + return -EPERM; + + res = tpacpi_rfkill_switches[id]->ops->set_status((!!t) ? + TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF); + tpacpi_rfk_update_swstate(tpacpi_rfkill_switches[id]); + + return (res < 0) ? res : count; +} + +/* procfs -------------------------------------------------------------- */ +static int tpacpi_rfk_procfs_read(const enum tpacpi_rfk_id id, char *p) +{ + int len = 0; + + if (id >= TPACPI_RFK_SW_MAX) + len += sprintf(p + len, "status:\t\tnot supported\n"); + else { + int status; + + /* This is in the ABI... */ + if (tpacpi_rfk_check_hwblock_state()) { + status = TPACPI_RFK_RADIO_OFF; + } else { + status = tpacpi_rfk_update_swstate( + tpacpi_rfkill_switches[id]); + if (status < 0) + return status; + } + + len += sprintf(p + len, "status:\t\t%s\n", + (status == TPACPI_RFK_RADIO_ON) ? + "enabled" : "disabled"); + len += sprintf(p + len, "commands:\tenable, disable\n"); + } + + return len; +} + +static int tpacpi_rfk_procfs_write(const enum tpacpi_rfk_id id, char *buf) +{ + char *cmd; + int status = -1; + int res = 0; + + if (id >= TPACPI_RFK_SW_MAX) + return -ENODEV; + + while ((cmd = next_cmd(&buf))) { + if (strlencmp(cmd, "enable") == 0) + status = TPACPI_RFK_RADIO_ON; + else if (strlencmp(cmd, "disable") == 0) + status = TPACPI_RFK_RADIO_OFF; + else + return -EINVAL; + } + + if (status != -1) { + tpacpi_disclose_usertask("procfs", "attempt to %s %s\n", + (status == TPACPI_RFK_RADIO_ON) ? + "enable" : "disable", + tpacpi_rfkill_names[id]); + res = (tpacpi_rfkill_switches[id]->ops->set_status)(status); + tpacpi_rfk_update_swstate(tpacpi_rfkill_switches[id]); + } + + return res; +} + /************************************************************************* * thinkpad-acpi driver attributes */ @@ -1127,8 +1464,6 @@ static DRIVER_ATTR(version, S_IRUGO, #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES -static void tpacpi_send_radiosw_update(void); - /* wlsw_emulstate ------------------------------------------------------ */ static ssize_t tpacpi_driver_wlsw_emulstate_show(struct device_driver *drv, char *buf) @@ -1144,11 +1479,10 @@ static ssize_t tpacpi_driver_wlsw_emulstate_store(struct device_driver *drv, if (parse_strtoul(buf, 1, &t)) return -EINVAL; - if (tpacpi_wlsw_emulstate != t) { - tpacpi_wlsw_emulstate = !!t; - tpacpi_send_radiosw_update(); - } else + if (tpacpi_wlsw_emulstate != !!t) { tpacpi_wlsw_emulstate = !!t; + tpacpi_rfk_update_hwblock_state(!t); /* negative logic */ + } return count; } @@ -1463,17 +1797,23 @@ static struct attribute_set *hotkey_dev_attributes; /* HKEY.MHKG() return bits */ #define TP_HOTKEY_TABLET_MASK (1 << 3) -static int hotkey_get_wlsw(int *status) +static int hotkey_get_wlsw(void) { + int status; + + if (!tp_features.hotkey_wlsw) + return -ENODEV; + #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES - if (dbg_wlswemul) { - *status = !!tpacpi_wlsw_emulstate; - return 0; - } + if (dbg_wlswemul) + return (tpacpi_wlsw_emulstate) ? + TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF; #endif - if (!acpi_evalf(hkey_handle, status, "WLSW", "d")) + + if (!acpi_evalf(hkey_handle, &status, "WLSW", "d")) return -EIO; - return 0; + + return (status) ? TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF; } static int hotkey_get_tablet_mode(int *status) @@ -2107,12 +2447,16 @@ static ssize_t hotkey_radio_sw_show(struct device *dev, struct device_attribute *attr, char *buf) { - int res, s; - res = hotkey_get_wlsw(&s); + int res; + res = hotkey_get_wlsw(); if (res < 0) return res; - return snprintf(buf, PAGE_SIZE, "%d\n", !!s); + /* Opportunistic update */ + tpacpi_rfk_update_hwblock_state((res == TPACPI_RFK_RADIO_OFF)); + + return snprintf(buf, PAGE_SIZE, "%d\n", + (res == TPACPI_RFK_RADIO_OFF) ? 0 : 1); } static struct device_attribute dev_attr_hotkey_radio_sw = @@ -2223,30 +2567,52 @@ static struct attribute *hotkey_mask_attributes[] __initdata = { &dev_attr_hotkey_wakeup_hotunplug_complete.attr, }; -static void bluetooth_update_rfk(void); -static void wan_update_rfk(void); -static void uwb_update_rfk(void); +/* + * Sync both the hw and sw blocking state of all switches + */ static void tpacpi_send_radiosw_update(void) { int wlsw; - /* Sync these BEFORE sending any rfkill events */ - if (tp_features.bluetooth) - bluetooth_update_rfk(); - if (tp_features.wan) - wan_update_rfk(); - if (tp_features.uwb) - uwb_update_rfk(); + /* + * We must sync all rfkill controllers *before* issuing any + * rfkill input events, or we will race the rfkill core input + * handler. + * + * tpacpi_inputdev_send_mutex works as a syncronization point + * for the above. + * + * We optimize to avoid numerous calls to hotkey_get_wlsw. + */ - if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) { + wlsw = hotkey_get_wlsw(); + + /* Sync hw blocking state first if it is hw-blocked */ + if (wlsw == TPACPI_RFK_RADIO_OFF) + tpacpi_rfk_update_hwblock_state(true); + + /* Sync sw blocking state */ + tpacpi_rfk_update_swstate_all(); + + /* Sync hw blocking state last if it is hw-unblocked */ + if (wlsw == TPACPI_RFK_RADIO_ON) + tpacpi_rfk_update_hwblock_state(false); + + /* Issue rfkill input event for WLSW switch */ + if (!(wlsw < 0)) { mutex_lock(&tpacpi_inputdev_send_mutex); input_report_switch(tpacpi_inputdev, - SW_RFKILL_ALL, !!wlsw); + SW_RFKILL_ALL, (wlsw > 0)); input_sync(tpacpi_inputdev); mutex_unlock(&tpacpi_inputdev_send_mutex); } + + /* + * this can be unconditional, as we will poll state again + * if userspace uses the notify to read data + */ hotkey_radio_sw_notify_change(); } @@ -2585,7 +2951,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) /* update bright_acpimode... */ tpacpi_check_std_acpi_brightness_support(); - if (tp_features.bright_acpimode) { + if (tp_features.bright_acpimode && acpi_video_backlight_support()) { printk(TPACPI_INFO "This ThinkPad has standard ACPI backlight " "brightness control, supported by the ACPI " @@ -3056,8 +3422,6 @@ enum { #define TPACPI_RFK_BLUETOOTH_SW_NAME "tpacpi_bluetooth_sw" -static struct rfkill *tpacpi_bluetooth_rfkill; - static void bluetooth_suspend(pm_message_t state) { /* Try to make sure radio will resume powered off */ @@ -3067,83 +3431,47 @@ static void bluetooth_suspend(pm_message_t state) "bluetooth power down on resume request failed\n"); } -static int bluetooth_get_radiosw(void) +static int bluetooth_get_status(void) { int status; - if (!tp_features.bluetooth) - return -ENODEV; - - /* WLSW overrides bluetooth in firmware/hardware, reflect that */ - if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status) - return RFKILL_STATE_HARD_BLOCKED; - #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES if (dbg_bluetoothemul) return (tpacpi_bluetooth_emulstate) ? - RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; + TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF; #endif if (!acpi_evalf(hkey_handle, &status, "GBDC", "d")) return -EIO; return ((status & TP_ACPI_BLUETOOTH_RADIOSSW) != 0) ? - RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; + TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF; } -static void bluetooth_update_rfk(void) +static int bluetooth_set_status(enum tpacpi_rfkill_state state) { int status; - if (!tpacpi_bluetooth_rfkill) - return; - - status = bluetooth_get_radiosw(); - if (status < 0) - return; - rfkill_force_state(tpacpi_bluetooth_rfkill, status); - vdbg_printk(TPACPI_DBG_RFKILL, - "forced rfkill state to %d\n", - status); -} - -static int bluetooth_set_radiosw(int radio_on, int update_rfk) -{ - int status; - - if (!tp_features.bluetooth) - return -ENODEV; - - /* WLSW overrides bluetooth in firmware/hardware, but there is no - * reason to risk weird behaviour. */ - if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status - && radio_on) - return -EPERM; - - vdbg_printk(TPACPI_DBG_RFKILL, - "will %s bluetooth\n", radio_on ? "enable" : "disable"); + "will attempt to %s bluetooth\n", + (state == TPACPI_RFK_RADIO_ON) ? "enable" : "disable"); #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES if (dbg_bluetoothemul) { - tpacpi_bluetooth_emulstate = !!radio_on; - if (update_rfk) - bluetooth_update_rfk(); + tpacpi_bluetooth_emulstate = (state == TPACPI_RFK_RADIO_ON); return 0; } #endif /* We make sure to keep TP_ACPI_BLUETOOTH_RESUMECTRL off */ - if (radio_on) + if (state == TPACPI_RFK_RADIO_ON) status = TP_ACPI_BLUETOOTH_RADIOSSW; else status = 0; + if (!acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status)) return -EIO; - if (update_rfk) - bluetooth_update_rfk(); - return 0; } @@ -3152,35 +3480,16 @@ static ssize_t bluetooth_enable_show(struct device *dev, struct device_attribute *attr, char *buf) { - int status; - - printk_deprecated_rfkill_attribute("bluetooth_enable"); - - status = bluetooth_get_radiosw(); - if (status < 0) - return status; - - return snprintf(buf, PAGE_SIZE, "%d\n", - (status == RFKILL_STATE_UNBLOCKED) ? 1 : 0); + return tpacpi_rfk_sysfs_enable_show(TPACPI_RFK_BLUETOOTH_SW_ID, + attr, buf); } static ssize_t bluetooth_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - unsigned long t; - int res; - - printk_deprecated_rfkill_attribute("bluetooth_enable"); - - if (parse_strtoul(buf, 1, &t)) - return -EINVAL; - - tpacpi_disclose_usertask("bluetooth_enable", "set to %ld\n", t); - - res = bluetooth_set_radiosw(t, 1); - - return (res) ? res : count; + return tpacpi_rfk_sysfs_enable_store(TPACPI_RFK_BLUETOOTH_SW_ID, + attr, buf, count); } static struct device_attribute dev_attr_bluetooth_enable = @@ -3198,23 +3507,10 @@ static const struct attribute_group bluetooth_attr_group = { .attrs = bluetooth_attributes, }; -static int tpacpi_bluetooth_rfk_get(void *data, enum rfkill_state *state) -{ - int bts = bluetooth_get_radiosw(); - - if (bts < 0) - return bts; - - *state = bts; - return 0; -} - -static int tpacpi_bluetooth_rfk_set(void *data, enum rfkill_state state) -{ - dbg_printk(TPACPI_DBG_RFKILL, - "request to change radio state to %d\n", state); - return bluetooth_set_radiosw((state == RFKILL_STATE_UNBLOCKED), 0); -} +static const struct tpacpi_rfk_ops bluetooth_tprfk_ops = { + .get_status = bluetooth_get_status, + .set_status = bluetooth_set_status, +}; static void bluetooth_shutdown(void) { @@ -3230,13 +3526,12 @@ static void bluetooth_shutdown(void) static void bluetooth_exit(void) { - bluetooth_shutdown(); - - if (tpacpi_bluetooth_rfkill) - rfkill_unregister(tpacpi_bluetooth_rfkill); - sysfs_remove_group(&tpacpi_pdev->dev.kobj, &bluetooth_attr_group); + + tpacpi_destroy_rfkill(TPACPI_RFK_BLUETOOTH_SW_ID); + + bluetooth_shutdown(); } static int __init bluetooth_init(struct ibm_init_struct *iibm) @@ -3277,20 +3572,18 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm) if (!tp_features.bluetooth) return 1; - res = sysfs_create_group(&tpacpi_pdev->dev.kobj, - &bluetooth_attr_group); + res = tpacpi_new_rfkill(TPACPI_RFK_BLUETOOTH_SW_ID, + &bluetooth_tprfk_ops, + RFKILL_TYPE_BLUETOOTH, + TPACPI_RFK_BLUETOOTH_SW_NAME, + true); if (res) return res; - res = tpacpi_new_rfkill(TPACPI_RFK_BLUETOOTH_SW_ID, - &tpacpi_bluetooth_rfkill, - RFKILL_TYPE_BLUETOOTH, - TPACPI_RFK_BLUETOOTH_SW_NAME, - true, - tpacpi_bluetooth_rfk_set, - tpacpi_bluetooth_rfk_get); + res = sysfs_create_group(&tpacpi_pdev->dev.kobj, + &bluetooth_attr_group); if (res) { - bluetooth_exit(); + tpacpi_destroy_rfkill(TPACPI_RFK_BLUETOOTH_SW_ID); return res; } @@ -3300,46 +3593,12 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm) /* procfs -------------------------------------------------------------- */ static int bluetooth_read(char *p) { - int len = 0; - int status = bluetooth_get_radiosw(); - - if (!tp_features.bluetooth) - len += sprintf(p + len, "status:\t\tnot supported\n"); - else { - len += sprintf(p + len, "status:\t\t%s\n", - (status == RFKILL_STATE_UNBLOCKED) ? - "enabled" : "disabled"); - len += sprintf(p + len, "commands:\tenable, disable\n"); - } - - return len; + return tpacpi_rfk_procfs_read(TPACPI_RFK_BLUETOOTH_SW_ID, p); } static int bluetooth_write(char *buf) { - char *cmd; - int state = -1; - - if (!tp_features.bluetooth) - return -ENODEV; - - while ((cmd = next_cmd(&buf))) { - if (strlencmp(cmd, "enable") == 0) { - state = 1; - } else if (strlencmp(cmd, "disable") == 0) { - state = 0; - } else - return -EINVAL; - } - - if (state != -1) { - tpacpi_disclose_usertask("procfs bluetooth", - "attempt to %s\n", - state ? "enable" : "disable"); - bluetooth_set_radiosw(state, 1); - } - - return 0; + return tpacpi_rfk_procfs_write(TPACPI_RFK_BLUETOOTH_SW_ID, buf); } static struct ibm_struct bluetooth_driver_data = { @@ -3365,8 +3624,6 @@ enum { #define TPACPI_RFK_WWAN_SW_NAME "tpacpi_wwan_sw" -static struct rfkill *tpacpi_wan_rfkill; - static void wan_suspend(pm_message_t state) { /* Try to make sure radio will resume powered off */ @@ -3376,83 +3633,47 @@ static void wan_suspend(pm_message_t state) "WWAN power down on resume request failed\n"); } -static int wan_get_radiosw(void) +static int wan_get_status(void) { int status; - if (!tp_features.wan) - return -ENODEV; - - /* WLSW overrides WWAN in firmware/hardware, reflect that */ - if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status) - return RFKILL_STATE_HARD_BLOCKED; - #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES if (dbg_wwanemul) return (tpacpi_wwan_emulstate) ? - RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; + TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF; #endif if (!acpi_evalf(hkey_handle, &status, "GWAN", "d")) return -EIO; return ((status & TP_ACPI_WANCARD_RADIOSSW) != 0) ? - RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; + TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF; } -static void wan_update_rfk(void) +static int wan_set_status(enum tpacpi_rfkill_state state) { int status; - if (!tpacpi_wan_rfkill) - return; - - status = wan_get_radiosw(); - if (status < 0) - return; - rfkill_force_state(tpacpi_wan_rfkill, status); - vdbg_printk(TPACPI_DBG_RFKILL, - "forced rfkill state to %d\n", - status); -} - -static int wan_set_radiosw(int radio_on, int update_rfk) -{ - int status; - - if (!tp_features.wan) - return -ENODEV; - - /* WLSW overrides bluetooth in firmware/hardware, but there is no - * reason to risk weird behaviour. */ - if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status - && radio_on) - return -EPERM; - - vdbg_printk(TPACPI_DBG_RFKILL, - "will %s WWAN\n", radio_on ? "enable" : "disable"); + "will attempt to %s wwan\n", + (state == TPACPI_RFK_RADIO_ON) ? "enable" : "disable"); #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES if (dbg_wwanemul) { - tpacpi_wwan_emulstate = !!radio_on; - if (update_rfk) - wan_update_rfk(); + tpacpi_wwan_emulstate = (state == TPACPI_RFK_RADIO_ON); return 0; } #endif /* We make sure to keep TP_ACPI_WANCARD_RESUMECTRL off */ - if (radio_on) + if (state == TPACPI_RFK_RADIO_ON) status = TP_ACPI_WANCARD_RADIOSSW; else status = 0; + if (!acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status)) return -EIO; - if (update_rfk) - wan_update_rfk(); - return 0; } @@ -3461,35 +3682,16 @@ static ssize_t wan_enable_show(struct device *dev, struct device_attribute *attr, char *buf) { - int status; - - printk_deprecated_rfkill_attribute("wwan_enable"); - - status = wan_get_radiosw(); - if (status < 0) - return status; - - return snprintf(buf, PAGE_SIZE, "%d\n", - (status == RFKILL_STATE_UNBLOCKED) ? 1 : 0); + return tpacpi_rfk_sysfs_enable_show(TPACPI_RFK_WWAN_SW_ID, + attr, buf); } static ssize_t wan_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - unsigned long t; - int res; - - printk_deprecated_rfkill_attribute("wwan_enable"); - - if (parse_strtoul(buf, 1, &t)) - return -EINVAL; - - tpacpi_disclose_usertask("wwan_enable", "set to %ld\n", t); - - res = wan_set_radiosw(t, 1); - - return (res) ? res : count; + return tpacpi_rfk_sysfs_enable_store(TPACPI_RFK_WWAN_SW_ID, + attr, buf, count); } static struct device_attribute dev_attr_wan_enable = @@ -3507,23 +3709,10 @@ static const struct attribute_group wan_attr_group = { .attrs = wan_attributes, }; -static int tpacpi_wan_rfk_get(void *data, enum rfkill_state *state) -{ - int wans = wan_get_radiosw(); - - if (wans < 0) - return wans; - - *state = wans; - return 0; -} - -static int tpacpi_wan_rfk_set(void *data, enum rfkill_state state) -{ - dbg_printk(TPACPI_DBG_RFKILL, - "request to change radio state to %d\n", state); - return wan_set_radiosw((state == RFKILL_STATE_UNBLOCKED), 0); -} +static const struct tpacpi_rfk_ops wan_tprfk_ops = { + .get_status = wan_get_status, + .set_status = wan_set_status, +}; static void wan_shutdown(void) { @@ -3539,13 +3728,12 @@ static void wan_shutdown(void) static void wan_exit(void) { - wan_shutdown(); - - if (tpacpi_wan_rfkill) - rfkill_unregister(tpacpi_wan_rfkill); - sysfs_remove_group(&tpacpi_pdev->dev.kobj, &wan_attr_group); + + tpacpi_destroy_rfkill(TPACPI_RFK_WWAN_SW_ID); + + wan_shutdown(); } static int __init wan_init(struct ibm_init_struct *iibm) @@ -3584,20 +3772,19 @@ static int __init wan_init(struct ibm_init_struct *iibm) if (!tp_features.wan) return 1; - res = sysfs_create_group(&tpacpi_pdev->dev.kobj, - &wan_attr_group); + res = tpacpi_new_rfkill(TPACPI_RFK_WWAN_SW_ID, + &wan_tprfk_ops, + RFKILL_TYPE_WWAN, + TPACPI_RFK_WWAN_SW_NAME, + true); if (res) return res; - res = tpacpi_new_rfkill(TPACPI_RFK_WWAN_SW_ID, - &tpacpi_wan_rfkill, - RFKILL_TYPE_WWAN, - TPACPI_RFK_WWAN_SW_NAME, - true, - tpacpi_wan_rfk_set, - tpacpi_wan_rfk_get); + res = sysfs_create_group(&tpacpi_pdev->dev.kobj, + &wan_attr_group); + if (res) { - wan_exit(); + tpacpi_destroy_rfkill(TPACPI_RFK_WWAN_SW_ID); return res; } @@ -3607,48 +3794,12 @@ static int __init wan_init(struct ibm_init_struct *iibm) /* procfs -------------------------------------------------------------- */ static int wan_read(char *p) { - int len = 0; - int status = wan_get_radiosw(); - - tpacpi_disclose_usertask("procfs wan", "read"); - - if (!tp_features.wan) - len += sprintf(p + len, "status:\t\tnot supported\n"); - else { - len += sprintf(p + len, "status:\t\t%s\n", - (status == RFKILL_STATE_UNBLOCKED) ? - "enabled" : "disabled"); - len += sprintf(p + len, "commands:\tenable, disable\n"); - } - - return len; + return tpacpi_rfk_procfs_read(TPACPI_RFK_WWAN_SW_ID, p); } static int wan_write(char *buf) { - char *cmd; - int state = -1; - - if (!tp_features.wan) - return -ENODEV; - - while ((cmd = next_cmd(&buf))) { - if (strlencmp(cmd, "enable") == 0) { - state = 1; - } else if (strlencmp(cmd, "disable") == 0) { - state = 0; - } else - return -EINVAL; - } - - if (state != -1) { - tpacpi_disclose_usertask("procfs wan", - "attempt to %s\n", - state ? "enable" : "disable"); - wan_set_radiosw(state, 1); - } - - return 0; + return tpacpi_rfk_procfs_write(TPACPI_RFK_WWAN_SW_ID, buf); } static struct ibm_struct wan_driver_data = { @@ -3672,108 +3823,59 @@ enum { #define TPACPI_RFK_UWB_SW_NAME "tpacpi_uwb_sw" -static struct rfkill *tpacpi_uwb_rfkill; - -static int uwb_get_radiosw(void) +static int uwb_get_status(void) { int status; - if (!tp_features.uwb) - return -ENODEV; - - /* WLSW overrides UWB in firmware/hardware, reflect that */ - if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status) - return RFKILL_STATE_HARD_BLOCKED; - #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES if (dbg_uwbemul) return (tpacpi_uwb_emulstate) ? - RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; + TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF; #endif if (!acpi_evalf(hkey_handle, &status, "GUWB", "d")) return -EIO; return ((status & TP_ACPI_UWB_RADIOSSW) != 0) ? - RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; + TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF; } -static void uwb_update_rfk(void) +static int uwb_set_status(enum tpacpi_rfkill_state state) { int status; - if (!tpacpi_uwb_rfkill) - return; - - status = uwb_get_radiosw(); - if (status < 0) - return; - rfkill_force_state(tpacpi_uwb_rfkill, status); - vdbg_printk(TPACPI_DBG_RFKILL, - "forced rfkill state to %d\n", - status); -} - -static int uwb_set_radiosw(int radio_on, int update_rfk) -{ - int status; - - if (!tp_features.uwb) - return -ENODEV; - - /* WLSW overrides UWB in firmware/hardware, but there is no - * reason to risk weird behaviour. */ - if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status - && radio_on) - return -EPERM; - - vdbg_printk(TPACPI_DBG_RFKILL, - "will %s UWB\n", radio_on ? "enable" : "disable"); + "will attempt to %s UWB\n", + (state == TPACPI_RFK_RADIO_ON) ? "enable" : "disable"); #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES if (dbg_uwbemul) { - tpacpi_uwb_emulstate = !!radio_on; - if (update_rfk) - uwb_update_rfk(); + tpacpi_uwb_emulstate = (state == TPACPI_RFK_RADIO_ON); return 0; } #endif - status = (radio_on) ? TP_ACPI_UWB_RADIOSSW : 0; + if (state == TPACPI_RFK_RADIO_ON) + status = TP_ACPI_UWB_RADIOSSW; + else + status = 0; + if (!acpi_evalf(hkey_handle, NULL, "SUWB", "vd", status)) return -EIO; - if (update_rfk) - uwb_update_rfk(); - return 0; } /* --------------------------------------------------------------------- */ -static int tpacpi_uwb_rfk_get(void *data, enum rfkill_state *state) -{ - int uwbs = uwb_get_radiosw(); - - if (uwbs < 0) - return uwbs; - - *state = uwbs; - return 0; -} - -static int tpacpi_uwb_rfk_set(void *data, enum rfkill_state state) -{ - dbg_printk(TPACPI_DBG_RFKILL, - "request to change radio state to %d\n", state); - return uwb_set_radiosw((state == RFKILL_STATE_UNBLOCKED), 0); -} +static const struct tpacpi_rfk_ops uwb_tprfk_ops = { + .get_status = uwb_get_status, + .set_status = uwb_set_status, +}; static void uwb_exit(void) { - if (tpacpi_uwb_rfkill) - rfkill_unregister(tpacpi_uwb_rfkill); + tpacpi_destroy_rfkill(TPACPI_RFK_UWB_SW_ID); } static int __init uwb_init(struct ibm_init_struct *iibm) @@ -3813,13 +3915,10 @@ static int __init uwb_init(struct ibm_init_struct *iibm) return 1; res = tpacpi_new_rfkill(TPACPI_RFK_UWB_SW_ID, - &tpacpi_uwb_rfkill, + &uwb_tprfk_ops, RFKILL_TYPE_UWB, TPACPI_RFK_UWB_SW_NAME, - false, - tpacpi_uwb_rfk_set, - tpacpi_uwb_rfk_get); - + false); return res; } @@ -4745,7 +4844,7 @@ TPACPI_HANDLE(led, ec, "SLED", /* 570 */ "LED", /* all others */ ); /* R30, R31 */ -#define TPACPI_LED_NUMLEDS 8 +#define TPACPI_LED_NUMLEDS 16 static struct tpacpi_led_classdev *tpacpi_leds; static enum led_status_t tpacpi_led_state_cache[TPACPI_LED_NUMLEDS]; static const char * const tpacpi_led_names[TPACPI_LED_NUMLEDS] = { @@ -4758,15 +4857,20 @@ static const char * const tpacpi_led_names[TPACPI_LED_NUMLEDS] = { "tpacpi::dock_batt", "tpacpi::unknown_led", "tpacpi::standby", + "tpacpi::dock_status1", + "tpacpi::dock_status2", + "tpacpi::unknown_led2", + "tpacpi::unknown_led3", + "tpacpi::thinkvantage", }; -#define TPACPI_SAFE_LEDS 0x0081U +#define TPACPI_SAFE_LEDS 0x1081U static inline bool tpacpi_is_led_restricted(const unsigned int led) { #ifdef CONFIG_THINKPAD_ACPI_UNSAFE_LEDS return false; #else - return (TPACPI_SAFE_LEDS & (1 << led)) == 0; + return (1U & (TPACPI_SAFE_LEDS >> led)) == 0; #endif } @@ -4928,6 +5032,10 @@ static int __init tpacpi_init_led(unsigned int led) tpacpi_leds[led].led = led; + /* LEDs with no name don't get registered */ + if (!tpacpi_led_names[led]) + return 0; + tpacpi_leds[led].led_classdev.brightness_set = &led_sysfs_set; tpacpi_leds[led].led_classdev.blink_set = &led_sysfs_blink_set; if (led_supported == TPACPI_LED_570) @@ -4946,10 +5054,59 @@ static int __init tpacpi_init_led(unsigned int led) return rc; } +static const struct tpacpi_quirk led_useful_qtable[] __initconst = { + TPACPI_Q_IBM('1', 'E', 0x009f), /* A30 */ + TPACPI_Q_IBM('1', 'N', 0x009f), /* A31 */ + TPACPI_Q_IBM('1', 'G', 0x009f), /* A31 */ + + TPACPI_Q_IBM('1', 'I', 0x0097), /* T30 */ + TPACPI_Q_IBM('1', 'R', 0x0097), /* T40, T41, T42, R50, R51 */ + TPACPI_Q_IBM('7', '0', 0x0097), /* T43, R52 */ + TPACPI_Q_IBM('1', 'Y', 0x0097), /* T43 */ + TPACPI_Q_IBM('1', 'W', 0x0097), /* R50e */ + TPACPI_Q_IBM('1', 'V', 0x0097), /* R51 */ + TPACPI_Q_IBM('7', '8', 0x0097), /* R51e */ + TPACPI_Q_IBM('7', '6', 0x0097), /* R52 */ + + TPACPI_Q_IBM('1', 'K', 0x00bf), /* X30 */ + TPACPI_Q_IBM('1', 'Q', 0x00bf), /* X31, X32 */ + TPACPI_Q_IBM('1', 'U', 0x00bf), /* X40 */ + TPACPI_Q_IBM('7', '4', 0x00bf), /* X41 */ + TPACPI_Q_IBM('7', '5', 0x00bf), /* X41t */ + + TPACPI_Q_IBM('7', '9', 0x1f97), /* T60 (1) */ + TPACPI_Q_IBM('7', '7', 0x1f97), /* Z60* (1) */ + TPACPI_Q_IBM('7', 'F', 0x1f97), /* Z61* (1) */ + TPACPI_Q_IBM('7', 'B', 0x1fb7), /* X60 (1) */ + + /* (1) - may have excess leds enabled on MSB */ + + /* Defaults (order matters, keep last, don't reorder!) */ + { /* Lenovo */ + .vendor = PCI_VENDOR_ID_LENOVO, + .bios = TPACPI_MATCH_ANY, .ec = TPACPI_MATCH_ANY, + .quirks = 0x1fffU, + }, + { /* IBM ThinkPads with no EC version string */ + .vendor = PCI_VENDOR_ID_IBM, + .bios = TPACPI_MATCH_ANY, .ec = TPACPI_MATCH_UNKNOWN, + .quirks = 0x00ffU, + }, + { /* IBM ThinkPads with EC version string */ + .vendor = PCI_VENDOR_ID_IBM, + .bios = TPACPI_MATCH_ANY, .ec = TPACPI_MATCH_ANY, + .quirks = 0x00bfU, + }, +}; + +#undef TPACPI_LEDQ_IBM +#undef TPACPI_LEDQ_LNV + static int __init led_init(struct ibm_init_struct *iibm) { unsigned int i; int rc; + unsigned long useful_leds; vdbg_printk(TPACPI_DBG_INIT, "initializing LED subdriver\n"); @@ -4971,6 +5128,9 @@ static int __init led_init(struct ibm_init_struct *iibm) vdbg_printk(TPACPI_DBG_INIT, "LED commands are %s, mode %d\n", str_supported(led_supported), led_supported); + if (led_supported == TPACPI_LED_NONE) + return 1; + tpacpi_leds = kzalloc(sizeof(*tpacpi_leds) * TPACPI_LED_NUMLEDS, GFP_KERNEL); if (!tpacpi_leds) { @@ -4978,8 +5138,12 @@ static int __init led_init(struct ibm_init_struct *iibm) return -ENOMEM; } + useful_leds = tpacpi_check_quirks(led_useful_qtable, + ARRAY_SIZE(led_useful_qtable)); + for (i = 0; i < TPACPI_LED_NUMLEDS; i++) { - if (!tpacpi_is_led_restricted(i)) { + if (!tpacpi_is_led_restricted(i) && + test_bit(i, &useful_leds)) { rc = tpacpi_init_led(i); if (rc < 0) { led_exit(); @@ -4989,12 +5153,11 @@ static int __init led_init(struct ibm_init_struct *iibm) } #ifdef CONFIG_THINKPAD_ACPI_UNSAFE_LEDS - if (led_supported != TPACPI_LED_NONE) - printk(TPACPI_NOTICE - "warning: userspace override of important " - "firmware LEDs is enabled\n"); + printk(TPACPI_NOTICE + "warning: userspace override of important " + "firmware LEDs is enabled\n"); #endif - return (led_supported != TPACPI_LED_NONE)? 0 : 1; + return 0; } #define str_led_status(s) \ @@ -5024,7 +5187,7 @@ static int led_read(char *p) } len += sprintf(p + len, "commands:\t" - " on, off, blink ( is 0-7)\n"); + " on, off, blink ( is 0-15)\n"); return len; } @@ -5039,7 +5202,7 @@ static int led_write(char *buf) return -ENODEV; while ((cmd = next_cmd(&buf))) { - if (sscanf(cmd, "%d", &led) != 1 || led < 0 || led > 7) + if (sscanf(cmd, "%d", &led) != 1 || led < 0 || led > 15) return -EINVAL; if (strstr(cmd, "off")) { @@ -5073,8 +5236,17 @@ static struct ibm_struct led_driver_data = { TPACPI_HANDLE(beep, ec, "BEEP"); /* all except R30, R31 */ +#define TPACPI_BEEP_Q1 0x0001 + +static const struct tpacpi_quirk beep_quirk_table[] __initconst = { + TPACPI_Q_IBM('I', 'M', TPACPI_BEEP_Q1), /* 570 */ + TPACPI_Q_IBM('I', 'U', TPACPI_BEEP_Q1), /* 570E - unverified */ +}; + static int __init beep_init(struct ibm_init_struct *iibm) { + unsigned long quirks; + vdbg_printk(TPACPI_DBG_INIT, "initializing beep subdriver\n"); TPACPI_ACPIHANDLE_INIT(beep); @@ -5082,6 +5254,11 @@ static int __init beep_init(struct ibm_init_struct *iibm) vdbg_printk(TPACPI_DBG_INIT, "beep is %s\n", str_supported(beep_handle != NULL)); + quirks = tpacpi_check_quirks(beep_quirk_table, + ARRAY_SIZE(beep_quirk_table)); + + tp_features.beep_needs_two_args = !!(quirks & TPACPI_BEEP_Q1); + return (beep_handle)? 0 : 1; } @@ -5113,8 +5290,15 @@ static int beep_write(char *buf) /* beep_cmd set */ } else return -EINVAL; - if (!acpi_evalf(beep_handle, NULL, NULL, "vdd", beep_cmd, 0)) - return -EIO; + if (tp_features.beep_needs_two_args) { + if (!acpi_evalf(beep_handle, NULL, NULL, "vdd", + beep_cmd, 0)) + return -EIO; + } else { + if (!acpi_evalf(beep_handle, NULL, NULL, "vd", + beep_cmd)) + return -EIO; + } } return 0; @@ -5541,6 +5725,10 @@ static struct ibm_struct ecdump_driver_data = { * Bit 3-0: backlight brightness level * * brightness_get_raw returns status data in the HBRV layout + * + * WARNING: The X61 has been verified to use HBRV for something else, so + * this should be used _only_ on IBM ThinkPads, and maybe with some careful + * testing on the very early *60 Lenovo models... */ enum { @@ -5841,6 +6029,12 @@ static int __init brightness_init(struct ibm_init_struct *iibm) brightness_mode); } + /* Safety */ + if (thinkpad_id.vendor != PCI_VENDOR_ID_IBM && + (brightness_mode == TPACPI_BRGHT_MODE_ECNVRAM || + brightness_mode == TPACPI_BRGHT_MODE_EC)) + return -EINVAL; + if (tpacpi_brightness_get_raw(&b) < 0) return 1; @@ -6133,6 +6327,21 @@ static struct ibm_struct volume_driver_data = { * For firmware bugs, refer to: * http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues * + * ---- + * + * ThinkPad EC register 0x31 bit 0 (only on select models) + * + * When bit 0 of EC register 0x31 is zero, the tachometer registers + * show the speed of the main fan. When bit 0 of EC register 0x31 + * is one, the tachometer registers show the speed of the auxiliary + * fan. + * + * Fan control seems to affect both fans, regardless of the state + * of this bit. + * + * So far, only the firmware for the X60/X61 non-tablet versions + * seem to support this (firmware TP-7M). + * * TPACPI_FAN_WR_ACPI_FANS: * ThinkPad X31, X40, X41. Not available in the X60. * @@ -6159,6 +6368,8 @@ enum { /* Fan control constants */ fan_status_offset = 0x2f, /* EC register 0x2f */ fan_rpm_offset = 0x84, /* EC register 0x84: LSB, 0x85 MSB (RPM) * 0x84 must be read before 0x85 */ + fan_select_offset = 0x31, /* EC register 0x31 (Firmware 7M) + bit 0 selects which fan is active */ TP_EC_FAN_FULLSPEED = 0x40, /* EC fan mode: full speed */ TP_EC_FAN_AUTO = 0x80, /* EC fan mode: auto fan control */ @@ -6221,30 +6432,18 @@ TPACPI_HANDLE(sfan, ec, "SFAN", /* 570 */ * We assume 0x07 really means auto mode while this quirk is active, * as this is far more likely than the ThinkPad being in level 7, * which is only used by the firmware during thermal emergencies. + * + * Enable for TP-1Y (T43), TP-78 (R51e), TP-76 (R52), + * TP-70 (T43, R52), which are known to be buggy. */ -static void fan_quirk1_detect(void) +static void fan_quirk1_setup(void) { - /* In some ThinkPads, neither the EC nor the ACPI - * DSDT initialize the HFSP register, and it ends up - * being initially set to 0x07 when it *could* be - * either 0x07 or 0x80. - * - * Enable for TP-1Y (T43), TP-78 (R51e), - * TP-76 (R52), TP-70 (T43, R52), which are known - * to be buggy. */ if (fan_control_initial_status == 0x07) { - switch (thinkpad_id.ec_model) { - case 0x5931: /* TP-1Y */ - case 0x3837: /* TP-78 */ - case 0x3637: /* TP-76 */ - case 0x3037: /* TP-70 */ - printk(TPACPI_NOTICE - "fan_init: initial fan status is unknown, " - "assuming it is in auto mode\n"); - tp_features.fan_ctrl_status_undef = 1; - ;; - } + printk(TPACPI_NOTICE + "fan_init: initial fan status is unknown, " + "assuming it is in auto mode\n"); + tp_features.fan_ctrl_status_undef = 1; } } @@ -6264,6 +6463,38 @@ static void fan_quirk1_handle(u8 *fan_status) } } +/* Select main fan on X60/X61, NOOP on others */ +static bool fan_select_fan1(void) +{ + if (tp_features.second_fan) { + u8 val; + + if (ec_read(fan_select_offset, &val) < 0) + return false; + val &= 0xFEU; + if (ec_write(fan_select_offset, val) < 0) + return false; + } + return true; +} + +/* Select secondary fan on X60/X61 */ +static bool fan_select_fan2(void) +{ + u8 val; + + if (!tp_features.second_fan) + return false; + + if (ec_read(fan_select_offset, &val) < 0) + return false; + val |= 0x01U; + if (ec_write(fan_select_offset, val) < 0) + return false; + + return true; +} + /* * Call with fan_mutex held */ @@ -6341,6 +6572,8 @@ static int fan_get_speed(unsigned int *speed) switch (fan_status_access_mode) { case TPACPI_FAN_RD_TPEC: /* all except 570, 600e/x, 770e, 770x */ + if (unlikely(!fan_select_fan1())) + return -EIO; if (unlikely(!acpi_ec_read(fan_rpm_offset, &lo) || !acpi_ec_read(fan_rpm_offset + 1, &hi))) return -EIO; @@ -6357,6 +6590,34 @@ static int fan_get_speed(unsigned int *speed) return 0; } +static int fan2_get_speed(unsigned int *speed) +{ + u8 hi, lo; + bool rc; + + switch (fan_status_access_mode) { + case TPACPI_FAN_RD_TPEC: + /* all except 570, 600e/x, 770e, 770x */ + if (unlikely(!fan_select_fan2())) + return -EIO; + rc = !acpi_ec_read(fan_rpm_offset, &lo) || + !acpi_ec_read(fan_rpm_offset + 1, &hi); + fan_select_fan1(); /* play it safe */ + if (rc) + return -EIO; + + if (likely(speed)) + *speed = (hi << 8) | lo; + + break; + + default: + return -ENXIO; + } + + return 0; +} + static int fan_set_level(int level) { if (!fan_control_allowed) @@ -6762,6 +7023,25 @@ static struct device_attribute dev_attr_fan_fan1_input = __ATTR(fan1_input, S_IRUGO, fan_fan1_input_show, NULL); +/* sysfs fan fan2_input ------------------------------------------------ */ +static ssize_t fan_fan2_input_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int res; + unsigned int speed; + + res = fan2_get_speed(&speed); + if (res < 0) + return res; + + return snprintf(buf, PAGE_SIZE, "%u\n", speed); +} + +static struct device_attribute dev_attr_fan_fan2_input = + __ATTR(fan2_input, S_IRUGO, + fan_fan2_input_show, NULL); + /* sysfs fan fan_watchdog (hwmon driver) ------------------------------- */ static ssize_t fan_fan_watchdog_show(struct device_driver *drv, char *buf) @@ -6795,6 +7075,7 @@ static DRIVER_ATTR(fan_watchdog, S_IWUSR | S_IRUGO, static struct attribute *fan_attributes[] = { &dev_attr_fan_pwm1_enable.attr, &dev_attr_fan_pwm1.attr, &dev_attr_fan_fan1_input.attr, + NULL, /* for fan2_input */ NULL }; @@ -6802,9 +7083,36 @@ static const struct attribute_group fan_attr_group = { .attrs = fan_attributes, }; +#define TPACPI_FAN_Q1 0x0001 /* Unitialized HFSP */ +#define TPACPI_FAN_2FAN 0x0002 /* EC 0x31 bit 0 selects fan2 */ + +#define TPACPI_FAN_QI(__id1, __id2, __quirks) \ + { .vendor = PCI_VENDOR_ID_IBM, \ + .bios = TPACPI_MATCH_ANY, \ + .ec = TPID(__id1, __id2), \ + .quirks = __quirks } + +#define TPACPI_FAN_QL(__id1, __id2, __quirks) \ + { .vendor = PCI_VENDOR_ID_LENOVO, \ + .bios = TPACPI_MATCH_ANY, \ + .ec = TPID(__id1, __id2), \ + .quirks = __quirks } + +static const struct tpacpi_quirk fan_quirk_table[] __initconst = { + TPACPI_FAN_QI('1', 'Y', TPACPI_FAN_Q1), + TPACPI_FAN_QI('7', '8', TPACPI_FAN_Q1), + TPACPI_FAN_QI('7', '6', TPACPI_FAN_Q1), + TPACPI_FAN_QI('7', '0', TPACPI_FAN_Q1), + TPACPI_FAN_QL('7', 'M', TPACPI_FAN_2FAN), +}; + +#undef TPACPI_FAN_QL +#undef TPACPI_FAN_QI + static int __init fan_init(struct ibm_init_struct *iibm) { int rc; + unsigned long quirks; vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_FAN, "initializing fan subdriver\n"); @@ -6815,12 +7123,16 @@ static int __init fan_init(struct ibm_init_struct *iibm) fan_control_commands = 0; fan_watchdog_maxinterval = 0; tp_features.fan_ctrl_status_undef = 0; + tp_features.second_fan = 0; fan_control_desired_level = 7; TPACPI_ACPIHANDLE_INIT(fans); TPACPI_ACPIHANDLE_INIT(gfan); TPACPI_ACPIHANDLE_INIT(sfan); + quirks = tpacpi_check_quirks(fan_quirk_table, + ARRAY_SIZE(fan_quirk_table)); + if (gfan_handle) { /* 570, 600e/x, 770e, 770x */ fan_status_access_mode = TPACPI_FAN_RD_ACPI_GFAN; @@ -6830,7 +7142,13 @@ static int __init fan_init(struct ibm_init_struct *iibm) if (likely(acpi_ec_read(fan_status_offset, &fan_control_initial_status))) { fan_status_access_mode = TPACPI_FAN_RD_TPEC; - fan_quirk1_detect(); + if (quirks & TPACPI_FAN_Q1) + fan_quirk1_setup(); + if (quirks & TPACPI_FAN_2FAN) { + tp_features.second_fan = 1; + dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_FAN, + "secondary fan support enabled\n"); + } } else { printk(TPACPI_ERR "ThinkPad ACPI EC access misbehaving, " @@ -6886,6 +7204,11 @@ static int __init fan_init(struct ibm_init_struct *iibm) if (fan_status_access_mode != TPACPI_FAN_NONE || fan_control_access_mode != TPACPI_FAN_WR_NONE) { + if (tp_features.second_fan) { + /* attach second fan tachometer */ + fan_attributes[ARRAY_SIZE(fan_attributes)-2] = + &dev_attr_fan_fan2_input.attr; + } rc = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj, &fan_attr_group); if (rc < 0) @@ -7357,6 +7680,24 @@ err_out: /* Probing */ +static bool __pure __init tpacpi_is_fw_digit(const char c) +{ + return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z'); +} + +/* Most models: xxyTkkWW (#.##c); Ancient 570/600 and -SL lacks (#.##c) */ +static bool __pure __init tpacpi_is_valid_fw_id(const char* const s, + const char t) +{ + return s && strlen(s) >= 8 && + tpacpi_is_fw_digit(s[0]) && + tpacpi_is_fw_digit(s[1]) && + s[2] == t && s[3] == 'T' && + tpacpi_is_fw_digit(s[4]) && + tpacpi_is_fw_digit(s[5]) && + s[6] == 'W' && s[7] == 'W'; +} + /* returns 0 - probe ok, or < 0 - probe error. * Probe ok doesn't mean thinkpad found. * On error, kfree() cleanup on tp->* is not performed, caller must do it */ @@ -7383,10 +7724,15 @@ static int __must_check __init get_thinkpad_model_data( tp->bios_version_str = kstrdup(s, GFP_KERNEL); if (s && !tp->bios_version_str) return -ENOMEM; - if (!tp->bios_version_str) + + /* Really ancient ThinkPad 240X will fail this, which is fine */ + if (!tpacpi_is_valid_fw_id(tp->bios_version_str, 'E')) return 0; + tp->bios_model = tp->bios_version_str[0] | (tp->bios_version_str[1] << 8); + tp->bios_release = (tp->bios_version_str[4] << 8) + | tp->bios_version_str[5]; /* * ThinkPad T23 or newer, A31 or newer, R50e or newer, @@ -7405,8 +7751,21 @@ static int __must_check __init get_thinkpad_model_data( tp->ec_version_str = kstrdup(ec_fw_string, GFP_KERNEL); if (!tp->ec_version_str) return -ENOMEM; - tp->ec_model = ec_fw_string[0] - | (ec_fw_string[1] << 8); + + if (tpacpi_is_valid_fw_id(ec_fw_string, 'H')) { + tp->ec_model = ec_fw_string[0] + | (ec_fw_string[1] << 8); + tp->ec_release = (ec_fw_string[4] << 8) + | ec_fw_string[5]; + } else { + printk(TPACPI_NOTICE + "ThinkPad firmware release %s " + "doesn't match the known patterns\n", + ec_fw_string); + printk(TPACPI_NOTICE + "please report this to %s\n", + TPACPI_MAIL); + } break; } } diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 9f187265db8e..81d31ea507d1 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -45,7 +45,6 @@ #include #include #include -#include #include @@ -250,21 +249,15 @@ static acpi_status hci_read2(u32 reg, u32 *out1, u32 *out2, u32 *result) struct toshiba_acpi_dev { struct platform_device *p_dev; - struct rfkill *rfk_dev; - struct input_polled_dev *poll_dev; + struct rfkill *bt_rfk; const char *bt_name; - const char *rfk_name; - - bool last_rfk_state; struct mutex mutex; }; static struct toshiba_acpi_dev toshiba_acpi = { .bt_name = "Toshiba Bluetooth", - .rfk_name = "Toshiba RFKill Switch", - .last_rfk_state = false, }; /* Bluetooth rfkill handlers */ @@ -283,21 +276,6 @@ static u32 hci_get_bt_present(bool *present) return hci_result; } -static u32 hci_get_bt_on(bool *on) -{ - u32 hci_result; - u32 value, value2; - - value = 0; - value2 = 0x0001; - hci_read2(HCI_WIRELESS, &value, &value2, &hci_result); - if (hci_result == HCI_SUCCESS) - *on = (value & HCI_WIRELESS_BT_POWER) && - (value & HCI_WIRELESS_BT_ATTACH); - - return hci_result; -} - static u32 hci_get_radio_state(bool *radio_state) { u32 hci_result; @@ -311,70 +289,67 @@ static u32 hci_get_radio_state(bool *radio_state) return hci_result; } -static int bt_rfkill_toggle_radio(void *data, enum rfkill_state state) +static int bt_rfkill_set_block(void *data, bool blocked) { + struct toshiba_acpi_dev *dev = data; u32 result1, result2; u32 value; + int err; bool radio_state; - struct toshiba_acpi_dev *dev = data; - value = (state == RFKILL_STATE_UNBLOCKED); - - if (hci_get_radio_state(&radio_state) != HCI_SUCCESS) - return -EFAULT; - - switch (state) { - case RFKILL_STATE_UNBLOCKED: - if (!radio_state) - return -EPERM; - break; - case RFKILL_STATE_SOFT_BLOCKED: - break; - default: - return -EINVAL; - } + value = (blocked == false); mutex_lock(&dev->mutex); + if (hci_get_radio_state(&radio_state) != HCI_SUCCESS) { + err = -EBUSY; + goto out; + } + + if (!radio_state) { + err = 0; + goto out; + } + hci_write2(HCI_WIRELESS, value, HCI_WIRELESS_BT_POWER, &result1); hci_write2(HCI_WIRELESS, value, HCI_WIRELESS_BT_ATTACH, &result2); - mutex_unlock(&dev->mutex); if (result1 != HCI_SUCCESS || result2 != HCI_SUCCESS) - return -EFAULT; - - return 0; + err = -EBUSY; + else + err = 0; + out: + mutex_unlock(&dev->mutex); + return err; } -static void bt_poll_rfkill(struct input_polled_dev *poll_dev) +static void bt_rfkill_poll(struct rfkill *rfkill, void *data) { - bool state_changed; bool new_rfk_state; bool value; u32 hci_result; - struct toshiba_acpi_dev *dev = poll_dev->private; + struct toshiba_acpi_dev *dev = data; + + mutex_lock(&dev->mutex); hci_result = hci_get_radio_state(&value); - if (hci_result != HCI_SUCCESS) - return; /* Can't do anything useful */ + if (hci_result != HCI_SUCCESS) { + /* Can't do anything useful */ + mutex_unlock(&dev->mutex); + } new_rfk_state = value; - mutex_lock(&dev->mutex); - state_changed = new_rfk_state != dev->last_rfk_state; - dev->last_rfk_state = new_rfk_state; mutex_unlock(&dev->mutex); - if (unlikely(state_changed)) { - rfkill_force_state(dev->rfk_dev, - new_rfk_state ? - RFKILL_STATE_SOFT_BLOCKED : - RFKILL_STATE_HARD_BLOCKED); - input_report_switch(poll_dev->input, SW_RFKILL_ALL, - new_rfk_state); - input_sync(poll_dev->input); - } + if (rfkill_set_hw_state(rfkill, !new_rfk_state)) + bt_rfkill_set_block(data, true); } +static const struct rfkill_ops toshiba_rfk_ops = { + .set_block = bt_rfkill_set_block, + .poll = bt_rfkill_poll, +}; + static struct proc_dir_entry *toshiba_proc_dir /*= 0*/ ; static struct backlight_device *toshiba_backlight_device; static int force_fan; @@ -702,14 +677,11 @@ static struct backlight_ops toshiba_backlight_data = { static void toshiba_acpi_exit(void) { - if (toshiba_acpi.poll_dev) { - input_unregister_polled_device(toshiba_acpi.poll_dev); - input_free_polled_device(toshiba_acpi.poll_dev); + if (toshiba_acpi.bt_rfk) { + rfkill_unregister(toshiba_acpi.bt_rfk); + rfkill_destroy(toshiba_acpi.bt_rfk); } - if (toshiba_acpi.rfk_dev) - rfkill_unregister(toshiba_acpi.rfk_dev); - if (toshiba_backlight_device) backlight_device_unregister(toshiba_backlight_device); @@ -728,8 +700,6 @@ static int __init toshiba_acpi_init(void) acpi_status status = AE_OK; u32 hci_result; bool bt_present; - bool bt_on; - bool radio_on; int ret = 0; if (acpi_disabled) @@ -793,61 +763,21 @@ static int __init toshiba_acpi_init(void) /* Register rfkill switch for Bluetooth */ if (hci_get_bt_present(&bt_present) == HCI_SUCCESS && bt_present) { - toshiba_acpi.rfk_dev = rfkill_allocate(&toshiba_acpi.p_dev->dev, - RFKILL_TYPE_BLUETOOTH); - if (!toshiba_acpi.rfk_dev) { + toshiba_acpi.bt_rfk = rfkill_alloc(toshiba_acpi.bt_name, + &toshiba_acpi.p_dev->dev, + RFKILL_TYPE_BLUETOOTH, + &toshiba_rfk_ops, + &toshiba_acpi); + if (!toshiba_acpi.bt_rfk) { printk(MY_ERR "unable to allocate rfkill device\n"); toshiba_acpi_exit(); return -ENOMEM; } - toshiba_acpi.rfk_dev->name = toshiba_acpi.bt_name; - toshiba_acpi.rfk_dev->toggle_radio = bt_rfkill_toggle_radio; - toshiba_acpi.rfk_dev->user_claim_unsupported = 1; - toshiba_acpi.rfk_dev->data = &toshiba_acpi; - - if (hci_get_bt_on(&bt_on) == HCI_SUCCESS && bt_on) { - toshiba_acpi.rfk_dev->state = RFKILL_STATE_UNBLOCKED; - } else if (hci_get_radio_state(&radio_on) == HCI_SUCCESS && - radio_on) { - toshiba_acpi.rfk_dev->state = RFKILL_STATE_SOFT_BLOCKED; - } else { - toshiba_acpi.rfk_dev->state = RFKILL_STATE_HARD_BLOCKED; - } - - ret = rfkill_register(toshiba_acpi.rfk_dev); + ret = rfkill_register(toshiba_acpi.bt_rfk); if (ret) { printk(MY_ERR "unable to register rfkill device\n"); - toshiba_acpi_exit(); - return -ENOMEM; - } - - /* Register input device for kill switch */ - toshiba_acpi.poll_dev = input_allocate_polled_device(); - if (!toshiba_acpi.poll_dev) { - printk(MY_ERR - "unable to allocate kill-switch input device\n"); - toshiba_acpi_exit(); - return -ENOMEM; - } - toshiba_acpi.poll_dev->private = &toshiba_acpi; - toshiba_acpi.poll_dev->poll = bt_poll_rfkill; - toshiba_acpi.poll_dev->poll_interval = 1000; /* msecs */ - - toshiba_acpi.poll_dev->input->name = toshiba_acpi.rfk_name; - toshiba_acpi.poll_dev->input->id.bustype = BUS_HOST; - /* Toshiba USB ID */ - toshiba_acpi.poll_dev->input->id.vendor = 0x0930; - set_bit(EV_SW, toshiba_acpi.poll_dev->input->evbit); - set_bit(SW_RFKILL_ALL, toshiba_acpi.poll_dev->input->swbit); - input_report_switch(toshiba_acpi.poll_dev->input, - SW_RFKILL_ALL, TRUE); - input_sync(toshiba_acpi.poll_dev->input); - - ret = input_register_polled_device(toshiba_acpi.poll_dev); - if (ret) { - printk(MY_ERR - "unable to register kill-switch input device\n"); + rfkill_destroy(toshiba_acpi.bt_rfk); toshiba_acpi_exit(); return ret; } diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c index adf17856bacc..ef3a2cd3a7a0 100644 --- a/drivers/pnp/pnpacpi/rsparser.c +++ b/drivers/pnp/pnpacpi/rsparser.c @@ -123,7 +123,7 @@ static void pnpacpi_parse_allocated_irqresource(struct pnp_dev *dev, } flags = irq_flags(triggering, polarity, shareable); - irq = acpi_register_gsi(gsi, triggering, polarity); + irq = acpi_register_gsi(&dev->dev, gsi, triggering, polarity); if (irq >= 0) pcibios_penalize_isa_irq(irq, 1); else @@ -287,6 +287,25 @@ static void pnpacpi_parse_allocated_address_space(struct pnp_dev *dev, ACPI_DECODE_16); } +static void pnpacpi_parse_allocated_ext_address_space(struct pnp_dev *dev, + struct acpi_resource *res) +{ + struct acpi_resource_extended_address64 *p = &res->data.ext_address64; + + if (p->producer_consumer == ACPI_PRODUCER) + return; + + if (p->resource_type == ACPI_MEMORY_RANGE) + pnpacpi_parse_allocated_memresource(dev, + p->minimum, p->address_length, + p->info.mem.write_protect); + else if (p->resource_type == ACPI_IO_RANGE) + pnpacpi_parse_allocated_ioresource(dev, + p->minimum, p->address_length, + p->granularity == 0xfff ? ACPI_DECODE_10 : + ACPI_DECODE_16); +} + static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, void *data) { @@ -400,8 +419,7 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, break; case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: - if (res->data.ext_address64.producer_consumer == ACPI_PRODUCER) - return AE_OK; + pnpacpi_parse_allocated_ext_address_space(dev, res); break; case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: @@ -630,6 +648,28 @@ static __init void pnpacpi_parse_address_option(struct pnp_dev *dev, IORESOURCE_IO_FIXED); } +static __init void pnpacpi_parse_ext_address_option(struct pnp_dev *dev, + unsigned int option_flags, + struct acpi_resource *r) +{ + struct acpi_resource_extended_address64 *p = &r->data.ext_address64; + unsigned char flags = 0; + + if (p->address_length == 0) + return; + + if (p->resource_type == ACPI_MEMORY_RANGE) { + if (p->info.mem.write_protect == ACPI_READ_WRITE_MEMORY) + flags = IORESOURCE_MEM_WRITEABLE; + pnp_register_mem_resource(dev, option_flags, p->minimum, + p->minimum, 0, p->address_length, + flags); + } else if (p->resource_type == ACPI_IO_RANGE) + pnp_register_port_resource(dev, option_flags, p->minimum, + p->minimum, 0, p->address_length, + IORESOURCE_IO_FIXED); +} + struct acpipnp_parse_option_s { struct pnp_dev *dev; unsigned int option_flags; @@ -711,6 +751,7 @@ static __init acpi_status pnpacpi_option_resource(struct acpi_resource *res, break; case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: + pnpacpi_parse_ext_address_option(dev, option_flags, res); break; case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: @@ -765,6 +806,7 @@ static int pnpacpi_supported_resource(struct acpi_resource *res) case ACPI_RESOURCE_TYPE_ADDRESS16: case ACPI_RESOURCE_TYPE_ADDRESS32: case ACPI_RESOURCE_TYPE_ADDRESS64: + case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: return 1; } diff --git a/drivers/pnp/resource.c b/drivers/pnp/resource.c index f604061d2bb0..ba9765427886 100644 --- a/drivers/pnp/resource.c +++ b/drivers/pnp/resource.c @@ -638,6 +638,24 @@ int pnp_possible_config(struct pnp_dev *dev, int type, resource_size_t start, } EXPORT_SYMBOL(pnp_possible_config); +int pnp_range_reserved(resource_size_t start, resource_size_t end) +{ + struct pnp_dev *dev; + struct pnp_resource *pnp_res; + resource_size_t *dev_start, *dev_end; + + pnp_for_each_dev(dev) { + list_for_each_entry(pnp_res, &dev->resources, list) { + dev_start = &pnp_res->res.start; + dev_end = &pnp_res->res.end; + if (ranged_conflict(&start, &end, dev_start, dev_end)) + return 1; + } + } + return 0; +} +EXPORT_SYMBOL(pnp_range_reserved); + /* format is: pnp_reserve_irq=irq1[,irq2] .... */ static int __init pnp_setup_reserve_irq(char *str) { diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 33da1127992a..7eda34838bfe 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -82,6 +82,14 @@ config BATTERY_DA9030 Say Y here to enable support for batteries charger integrated into DA9030 PMIC. +config BATTERY_MAX17040 + tristate "Maxim MAX17040 Fuel Gauge" + depends on I2C + help + MAX17040 is fuel-gauge systems for lithium-ion (Li+) batteries + in handheld and portable equipment. The MAX17040 is configured + to operate with a single lithium cell + config CHARGER_PCF50633 tristate "NXP PCF50633 MBC" depends on MFD_PCF50633 diff --git a/drivers/power/Makefile b/drivers/power/Makefile index 2fcf41d13e5c..daf3179689aa 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile @@ -25,4 +25,5 @@ obj-$(CONFIG_BATTERY_TOSA) += tosa_battery.o obj-$(CONFIG_BATTERY_WM97XX) += wm97xx_battery.o obj-$(CONFIG_BATTERY_BQ27x00) += bq27x00_battery.o obj-$(CONFIG_BATTERY_DA9030) += da9030_battery.o -obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o \ No newline at end of file +obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o +obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o diff --git a/drivers/power/da9030_battery.c b/drivers/power/da9030_battery.c index 1662bb0f23a5..3364198134a1 100644 --- a/drivers/power/da9030_battery.c +++ b/drivers/power/da9030_battery.c @@ -22,8 +22,6 @@ #include #include -#define DA9030_STATUS_CHDET (1 << 3) - #define DA9030_FAULT_LOG 0x0a #define DA9030_FAULT_LOG_OVER_TEMP (1 << 7) #define DA9030_FAULT_LOG_VBAT_OVER (1 << 4) @@ -244,6 +242,8 @@ static void da9030_set_charge(struct da9030_charger *charger, int on) } da903x_write(charger->master, DA9030_CHARGE_CONTROL, val); + + power_supply_changed(&charger->psy); } static void da9030_charger_check_state(struct da9030_charger *charger) @@ -258,6 +258,12 @@ static void da9030_charger_check_state(struct da9030_charger *charger) da9030_set_charge(charger, 1); } } else { + /* Charger has been pulled out */ + if (!charger->chdet) { + da9030_set_charge(charger, 0); + return; + } + if (charger->adc.vbat_res >= charger->thresholds.vbat_charge_stop) { da9030_set_charge(charger, 0); @@ -395,13 +401,11 @@ static int da9030_battery_event(struct notifier_block *nb, unsigned long event, { struct da9030_charger *charger = container_of(nb, struct da9030_charger, nb); - int status; switch (event) { case DA9030_EVENT_CHDET: - status = da903x_query_status(charger->master, - DA9030_STATUS_CHDET); - da9030_set_charge(charger, status); + cancel_delayed_work_sync(&charger->work); + schedule_work(&charger->work.work); break; case DA9030_EVENT_VBATMON: da9030_battery_vbat_event(charger); @@ -565,7 +569,8 @@ static int da9030_battery_remove(struct platform_device *dev) da903x_unregister_notifier(charger->master, &charger->nb, DA9030_EVENT_CHDET | DA9030_EVENT_VBATMON | DA9030_EVENT_CHIOVER | DA9030_EVENT_TBAT); - cancel_delayed_work(&charger->work); + cancel_delayed_work_sync(&charger->work); + da9030_set_charge(charger, 0); power_supply_unregister(&charger->psy); kfree(charger); diff --git a/drivers/power/ds2760_battery.c b/drivers/power/ds2760_battery.c index a52d4a11652d..520b5c49ff30 100644 --- a/drivers/power/ds2760_battery.c +++ b/drivers/power/ds2760_battery.c @@ -62,6 +62,10 @@ static unsigned int cache_time = 1000; module_param(cache_time, uint, 0644); MODULE_PARM_DESC(cache_time, "cache time in milliseconds"); +static unsigned int pmod_enabled; +module_param(pmod_enabled, bool, 0644); +MODULE_PARM_DESC(pmod_enabled, "PMOD enable bit"); + /* Some batteries have their rated capacity stored a N * 10 mAh, while * others use an index into this table. */ static int rated_capacities[] = { @@ -259,6 +263,17 @@ static void ds2760_battery_update_status(struct ds2760_device_info *di) power_supply_changed(&di->bat); } +static void ds2760_battery_write_status(struct ds2760_device_info *di, + char status) +{ + if (status == di->raw[DS2760_STATUS_REG]) + return; + + w1_ds2760_write(di->w1_dev, &status, DS2760_STATUS_WRITE_REG, 1); + w1_ds2760_store_eeprom(di->w1_dev, DS2760_EEPROM_BLOCK1); + w1_ds2760_recall_eeprom(di->w1_dev, DS2760_EEPROM_BLOCK1); +} + static void ds2760_battery_work(struct work_struct *work) { struct ds2760_device_info *di = container_of(work, @@ -342,9 +357,9 @@ static enum power_supply_property ds2760_battery_props[] = { static int ds2760_battery_probe(struct platform_device *pdev) { + char status; int retval = 0; struct ds2760_device_info *di; - struct ds2760_platform_data *pdata; di = kzalloc(sizeof(*di), GFP_KERNEL); if (!di) { @@ -354,14 +369,13 @@ static int ds2760_battery_probe(struct platform_device *pdev) platform_set_drvdata(pdev, di); - pdata = pdev->dev.platform_data; - di->dev = &pdev->dev; - di->w1_dev = pdev->dev.parent; - di->bat.name = dev_name(&pdev->dev); - di->bat.type = POWER_SUPPLY_TYPE_BATTERY; - di->bat.properties = ds2760_battery_props; - di->bat.num_properties = ARRAY_SIZE(ds2760_battery_props); - di->bat.get_property = ds2760_battery_get_property; + di->dev = &pdev->dev; + di->w1_dev = pdev->dev.parent; + di->bat.name = dev_name(&pdev->dev); + di->bat.type = POWER_SUPPLY_TYPE_BATTERY; + di->bat.properties = ds2760_battery_props; + di->bat.num_properties = ARRAY_SIZE(ds2760_battery_props); + di->bat.get_property = ds2760_battery_get_property; di->bat.external_power_changed = ds2760_battery_external_power_changed; @@ -373,6 +387,16 @@ static int ds2760_battery_probe(struct platform_device *pdev) goto batt_failed; } + /* enable sleep mode feature */ + ds2760_battery_read_status(di); + status = di->raw[DS2760_STATUS_REG]; + if (pmod_enabled) + status |= DS2760_STATUS_PMOD; + else + status &= ~DS2760_STATUS_PMOD; + + ds2760_battery_write_status(di, status); + INIT_DELAYED_WORK(&di->monitor_work, ds2760_battery_work); di->monitor_wqueue = create_singlethread_workqueue(dev_name(&pdev->dev)); if (!di->monitor_wqueue) { diff --git a/drivers/power/max17040_battery.c b/drivers/power/max17040_battery.c new file mode 100644 index 000000000000..87b98bf27ae1 --- /dev/null +++ b/drivers/power/max17040_battery.c @@ -0,0 +1,309 @@ +/* + * max17040_battery.c + * fuel-gauge systems for lithium-ion (Li+) batteries + * + * Copyright (C) 2009 Samsung Electronics + * Minkyu Kang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX17040_VCELL_MSB 0x02 +#define MAX17040_VCELL_LSB 0x03 +#define MAX17040_SOC_MSB 0x04 +#define MAX17040_SOC_LSB 0x05 +#define MAX17040_MODE_MSB 0x06 +#define MAX17040_MODE_LSB 0x07 +#define MAX17040_VER_MSB 0x08 +#define MAX17040_VER_LSB 0x09 +#define MAX17040_RCOMP_MSB 0x0C +#define MAX17040_RCOMP_LSB 0x0D +#define MAX17040_CMD_MSB 0xFE +#define MAX17040_CMD_LSB 0xFF + +#define MAX17040_DELAY 1000 +#define MAX17040_BATTERY_FULL 95 + +struct max17040_chip { + struct i2c_client *client; + struct delayed_work work; + struct power_supply battery; + struct max17040_platform_data *pdata; + + /* State Of Connect */ + int online; + /* battery voltage */ + int vcell; + /* battery capacity */ + int soc; + /* State Of Charge */ + int status; +}; + +static int max17040_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct max17040_chip *chip = container_of(psy, + struct max17040_chip, battery); + + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + val->intval = chip->status; + break; + case POWER_SUPPLY_PROP_ONLINE: + val->intval = chip->online; + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + val->intval = chip->vcell; + break; + case POWER_SUPPLY_PROP_CAPACITY: + val->intval = chip->soc; + break; + default: + return -EINVAL; + } + return 0; +} + +static int max17040_write_reg(struct i2c_client *client, int reg, u8 value) +{ + int ret; + + ret = i2c_smbus_write_byte_data(client, reg, value); + + if (ret < 0) + dev_err(&client->dev, "%s: err %d\n", __func__, ret); + + return ret; +} + +static int max17040_read_reg(struct i2c_client *client, int reg) +{ + int ret; + + ret = i2c_smbus_read_byte_data(client, reg); + + if (ret < 0) + dev_err(&client->dev, "%s: err %d\n", __func__, ret); + + return ret; +} + +static void max17040_reset(struct i2c_client *client) +{ + max17040_write_reg(client, MAX17040_CMD_MSB, 0x54); + max17040_write_reg(client, MAX17040_CMD_LSB, 0x00); +} + +static void max17040_get_vcell(struct i2c_client *client) +{ + struct max17040_chip *chip = i2c_get_clientdata(client); + u8 msb; + u8 lsb; + + msb = max17040_read_reg(client, MAX17040_VCELL_MSB); + lsb = max17040_read_reg(client, MAX17040_VCELL_LSB); + + chip->vcell = (msb << 4) + (lsb >> 4); +} + +static void max17040_get_soc(struct i2c_client *client) +{ + struct max17040_chip *chip = i2c_get_clientdata(client); + u8 msb; + u8 lsb; + + msb = max17040_read_reg(client, MAX17040_SOC_MSB); + lsb = max17040_read_reg(client, MAX17040_SOC_LSB); + + chip->soc = msb; +} + +static void max17040_get_version(struct i2c_client *client) +{ + u8 msb; + u8 lsb; + + msb = max17040_read_reg(client, MAX17040_VER_MSB); + lsb = max17040_read_reg(client, MAX17040_VER_LSB); + + dev_info(&client->dev, "MAX17040 Fuel-Gauge Ver %d%d\n", msb, lsb); +} + +static void max17040_get_online(struct i2c_client *client) +{ + struct max17040_chip *chip = i2c_get_clientdata(client); + + if (chip->pdata->battery_online) + chip->online = chip->pdata->battery_online(); + else + chip->online = 1; +} + +static void max17040_get_status(struct i2c_client *client) +{ + struct max17040_chip *chip = i2c_get_clientdata(client); + + if (!chip->pdata->charger_online || !chip->pdata->charger_enable) { + chip->status = POWER_SUPPLY_STATUS_UNKNOWN; + return; + } + + if (chip->pdata->charger_online()) { + if (chip->pdata->charger_enable()) + chip->status = POWER_SUPPLY_STATUS_CHARGING; + else + chip->status = POWER_SUPPLY_STATUS_NOT_CHARGING; + } else { + chip->status = POWER_SUPPLY_STATUS_DISCHARGING; + } + + if (chip->soc > MAX17040_BATTERY_FULL) + chip->status = POWER_SUPPLY_STATUS_FULL; +} + +static void max17040_work(struct work_struct *work) +{ + struct max17040_chip *chip; + + chip = container_of(work, struct max17040_chip, work.work); + + max17040_get_vcell(chip->client); + max17040_get_soc(chip->client); + max17040_get_online(chip->client); + max17040_get_status(chip->client); + + schedule_delayed_work(&chip->work, MAX17040_DELAY); +} + +static enum power_supply_property max17040_battery_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_CAPACITY, +}; + +static int __devinit max17040_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct max17040_chip *chip; + int ret; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) + return -EIO; + + chip = kzalloc(sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->client = client; + chip->pdata = client->dev.platform_data; + + i2c_set_clientdata(client, chip); + + chip->battery.name = "battery"; + chip->battery.type = POWER_SUPPLY_TYPE_BATTERY; + chip->battery.get_property = max17040_get_property; + chip->battery.properties = max17040_battery_props; + chip->battery.num_properties = ARRAY_SIZE(max17040_battery_props); + + ret = power_supply_register(&client->dev, &chip->battery); + if (ret) { + dev_err(&client->dev, "failed: power supply register\n"); + i2c_set_clientdata(client, NULL); + kfree(chip); + return ret; + } + + max17040_reset(client); + max17040_get_version(client); + + INIT_DELAYED_WORK_DEFERRABLE(&chip->work, max17040_work); + schedule_delayed_work(&chip->work, MAX17040_DELAY); + + return 0; +} + +static int __devexit max17040_remove(struct i2c_client *client) +{ + struct max17040_chip *chip = i2c_get_clientdata(client); + + power_supply_unregister(&chip->battery); + cancel_delayed_work(&chip->work); + i2c_set_clientdata(client, NULL); + kfree(chip); + return 0; +} + +#ifdef CONFIG_PM + +static int max17040_suspend(struct i2c_client *client, + pm_message_t state) +{ + struct max17040_chip *chip = i2c_get_clientdata(client); + + cancel_delayed_work(&chip->work); + return 0; +} + +static int max17040_resume(struct i2c_client *client) +{ + struct max17040_chip *chip = i2c_get_clientdata(client); + + schedule_delayed_work(&chip->work, MAX17040_DELAY); + return 0; +} + +#else + +#define max17040_suspend NULL +#define max17040_resume NULL + +#endif /* CONFIG_PM */ + +static const struct i2c_device_id max17040_id[] = { + { "max17040", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, max17040_id); + +static struct i2c_driver max17040_i2c_driver = { + .driver = { + .name = "max17040", + }, + .probe = max17040_probe, + .remove = __devexit_p(max17040_remove), + .suspend = max17040_suspend, + .resume = max17040_resume, + .id_table = max17040_id, +}; + +static int __init max17040_init(void) +{ + return i2c_add_driver(&max17040_i2c_driver); +} +module_init(max17040_init); + +static void __exit max17040_exit(void) +{ + i2c_del_driver(&max17040_i2c_driver); +} +module_exit(max17040_exit); + +MODULE_AUTHOR("Minkyu Kang "); +MODULE_DESCRIPTION("MAX17040 Fuel Gauge"); +MODULE_LICENSE("GPL"); diff --git a/drivers/pps/Kconfig b/drivers/pps/Kconfig new file mode 100644 index 000000000000..cc2eb8edb514 --- /dev/null +++ b/drivers/pps/Kconfig @@ -0,0 +1,33 @@ +# +# PPS support configuration +# + +menu "PPS support" + +config PPS + tristate "PPS support" + depends on EXPERIMENTAL + ---help--- + PPS (Pulse Per Second) is a special pulse provided by some GPS + antennae. Userland can use it to get a high-precision time + reference. + + Some antennae's PPS signals are connected with the CD (Carrier + Detect) pin of the serial line they use to communicate with the + host. In this case use the SERIAL_LINE client support. + + Some antennae's PPS signals are connected with some special host + inputs so you have to enable the corresponding client support. + + To compile this driver as a module, choose M here: the module + will be called pps_core.ko. + +config PPS_DEBUG + bool "PPS debugging messages" + depends on PPS + help + Say Y here if you want the PPS support to produce a bunch of debug + messages to the system log. Select this if you are having a + problem with PPS support and want to see more of what is going on. + +endmenu diff --git a/drivers/pps/Makefile b/drivers/pps/Makefile new file mode 100644 index 000000000000..19ea582f431d --- /dev/null +++ b/drivers/pps/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for the PPS core. +# + +pps_core-y := pps.o kapi.o sysfs.o +obj-$(CONFIG_PPS) := pps_core.o + +ccflags-$(CONFIG_PPS_DEBUG) := -DDEBUG diff --git a/drivers/pps/kapi.c b/drivers/pps/kapi.c new file mode 100644 index 000000000000..35a0b192d768 --- /dev/null +++ b/drivers/pps/kapi.c @@ -0,0 +1,329 @@ +/* + * kernel API + * + * + * Copyright (C) 2005-2009 Rodolfo Giometti + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Global variables + */ + +DEFINE_SPINLOCK(pps_idr_lock); +DEFINE_IDR(pps_idr); + +/* + * Local functions + */ + +static void pps_add_offset(struct pps_ktime *ts, struct pps_ktime *offset) +{ + ts->nsec += offset->nsec; + while (ts->nsec >= NSEC_PER_SEC) { + ts->nsec -= NSEC_PER_SEC; + ts->sec++; + } + while (ts->nsec < 0) { + ts->nsec += NSEC_PER_SEC; + ts->sec--; + } + ts->sec += offset->sec; +} + +/* + * Exported functions + */ + +/* pps_get_source - find a PPS source + * @source: the PPS source ID. + * + * This function is used to find an already registered PPS source into the + * system. + * + * The function returns NULL if found nothing, otherwise it returns a pointer + * to the PPS source data struct (the refcounter is incremented by 1). + */ + +struct pps_device *pps_get_source(int source) +{ + struct pps_device *pps; + unsigned long flags; + + spin_lock_irqsave(&pps_idr_lock, flags); + + pps = idr_find(&pps_idr, source); + if (pps != NULL) + atomic_inc(&pps->usage); + + spin_unlock_irqrestore(&pps_idr_lock, flags); + + return pps; +} + +/* pps_put_source - free the PPS source data + * @pps: a pointer to the PPS source. + * + * This function is used to free a PPS data struct if its refcount is 0. + */ + +void pps_put_source(struct pps_device *pps) +{ + unsigned long flags; + + spin_lock_irqsave(&pps_idr_lock, flags); + BUG_ON(atomic_read(&pps->usage) == 0); + + if (!atomic_dec_and_test(&pps->usage)) { + pps = NULL; + goto exit; + } + + /* No more reference to the PPS source. We can safely remove the + * PPS data struct. + */ + idr_remove(&pps_idr, pps->id); + +exit: + spin_unlock_irqrestore(&pps_idr_lock, flags); + kfree(pps); +} + +/* pps_register_source - add a PPS source in the system + * @info: the PPS info struct + * @default_params: the default PPS parameters of the new source + * + * This function is used to add a new PPS source in the system. The new + * source is described by info's fields and it will have, as default PPS + * parameters, the ones specified into default_params. + * + * The function returns, in case of success, the PPS source ID. + */ + +int pps_register_source(struct pps_source_info *info, int default_params) +{ + struct pps_device *pps; + int id; + int err; + + /* Sanity checks */ + if ((info->mode & default_params) != default_params) { + printk(KERN_ERR "pps: %s: unsupported default parameters\n", + info->name); + err = -EINVAL; + goto pps_register_source_exit; + } + if ((info->mode & (PPS_ECHOASSERT | PPS_ECHOCLEAR)) != 0 && + info->echo == NULL) { + printk(KERN_ERR "pps: %s: echo function is not defined\n", + info->name); + err = -EINVAL; + goto pps_register_source_exit; + } + if ((info->mode & (PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)) == 0) { + printk(KERN_ERR "pps: %s: unspecified time format\n", + info->name); + err = -EINVAL; + goto pps_register_source_exit; + } + + /* Allocate memory for the new PPS source struct */ + pps = kzalloc(sizeof(struct pps_device), GFP_KERNEL); + if (pps == NULL) { + err = -ENOMEM; + goto pps_register_source_exit; + } + + /* These initializations must be done before calling idr_get_new() + * in order to avoid reces into pps_event(). + */ + pps->params.api_version = PPS_API_VERS; + pps->params.mode = default_params; + pps->info = *info; + + init_waitqueue_head(&pps->queue); + spin_lock_init(&pps->lock); + atomic_set(&pps->usage, 1); + + /* Get new ID for the new PPS source */ + if (idr_pre_get(&pps_idr, GFP_KERNEL) == 0) { + err = -ENOMEM; + goto kfree_pps; + } + + spin_lock_irq(&pps_idr_lock); + + /* Now really allocate the PPS source. + * After idr_get_new() calling the new source will be freely available + * into the kernel. + */ + err = idr_get_new(&pps_idr, pps, &id); + if (err < 0) { + spin_unlock_irq(&pps_idr_lock); + goto kfree_pps; + } + + id = id & MAX_ID_MASK; + if (id >= PPS_MAX_SOURCES) { + spin_unlock_irq(&pps_idr_lock); + + printk(KERN_ERR "pps: %s: too many PPS sources in the system\n", + info->name); + err = -EBUSY; + goto free_idr; + } + pps->id = id; + + spin_unlock_irq(&pps_idr_lock); + + /* Create the char device */ + err = pps_register_cdev(pps); + if (err < 0) { + printk(KERN_ERR "pps: %s: unable to create char device\n", + info->name); + goto free_idr; + } + + pr_info("new PPS source %s at ID %d\n", info->name, id); + + return id; + +free_idr: + spin_lock_irq(&pps_idr_lock); + idr_remove(&pps_idr, id); + spin_unlock_irq(&pps_idr_lock); + +kfree_pps: + kfree(pps); + +pps_register_source_exit: + printk(KERN_ERR "pps: %s: unable to register source\n", info->name); + + return err; +} +EXPORT_SYMBOL(pps_register_source); + +/* pps_unregister_source - remove a PPS source from the system + * @source: the PPS source ID + * + * This function is used to remove a previously registered PPS source from + * the system. + */ + +void pps_unregister_source(int source) +{ + struct pps_device *pps; + + spin_lock_irq(&pps_idr_lock); + pps = idr_find(&pps_idr, source); + + if (!pps) { + BUG(); + spin_unlock_irq(&pps_idr_lock); + return; + } + spin_unlock_irq(&pps_idr_lock); + + pps_unregister_cdev(pps); + pps_put_source(pps); +} +EXPORT_SYMBOL(pps_unregister_source); + +/* pps_event - register a PPS event into the system + * @source: the PPS source ID + * @ts: the event timestamp + * @event: the event type + * @data: userdef pointer + * + * This function is used by each PPS client in order to register a new + * PPS event into the system (it's usually called inside an IRQ handler). + * + * If an echo function is associated with the PPS source it will be called + * as: + * pps->info.echo(source, event, data); + */ + +void pps_event(int source, struct pps_ktime *ts, int event, void *data) +{ + struct pps_device *pps; + unsigned long flags; + + if ((event & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR)) == 0) { + printk(KERN_ERR "pps: unknown event (%x) for source %d\n", + event, source); + return; + } + + pps = pps_get_source(source); + if (!pps) + return; + + pr_debug("PPS event on source %d at %llu.%06u\n", + pps->id, (unsigned long long) ts->sec, ts->nsec); + + spin_lock_irqsave(&pps->lock, flags); + + /* Must call the echo function? */ + if ((pps->params.mode & (PPS_ECHOASSERT | PPS_ECHOCLEAR))) + pps->info.echo(source, event, data); + + /* Check the event */ + pps->current_mode = pps->params.mode; + if (event & PPS_CAPTUREASSERT) { + /* We have to add an offset? */ + if (pps->params.mode & PPS_OFFSETASSERT) + pps_add_offset(ts, &pps->params.assert_off_tu); + + /* Save the time stamp */ + pps->assert_tu = *ts; + pps->assert_sequence++; + pr_debug("capture assert seq #%u for source %d\n", + pps->assert_sequence, source); + } + if (event & PPS_CAPTURECLEAR) { + /* We have to add an offset? */ + if (pps->params.mode & PPS_OFFSETCLEAR) + pps_add_offset(ts, &pps->params.clear_off_tu); + + /* Save the time stamp */ + pps->clear_tu = *ts; + pps->clear_sequence++; + pr_debug("capture clear seq #%u for source %d\n", + pps->clear_sequence, source); + } + + pps->go = ~0; + wake_up_interruptible(&pps->queue); + + kill_fasync(&pps->async_queue, SIGIO, POLL_IN); + + spin_unlock_irqrestore(&pps->lock, flags); + + /* Now we can release the PPS source for (possible) deregistration */ + pps_put_source(pps); +} +EXPORT_SYMBOL(pps_event); diff --git a/drivers/pps/pps.c b/drivers/pps/pps.c new file mode 100644 index 000000000000..ac8cc8cea1e3 --- /dev/null +++ b/drivers/pps/pps.c @@ -0,0 +1,312 @@ +/* + * PPS core file + * + * + * Copyright (C) 2005-2009 Rodolfo Giometti + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Local variables + */ + +static dev_t pps_devt; +static struct class *pps_class; + +/* + * Char device methods + */ + +static unsigned int pps_cdev_poll(struct file *file, poll_table *wait) +{ + struct pps_device *pps = file->private_data; + + poll_wait(file, &pps->queue, wait); + + return POLLIN | POLLRDNORM; +} + +static int pps_cdev_fasync(int fd, struct file *file, int on) +{ + struct pps_device *pps = file->private_data; + return fasync_helper(fd, file, on, &pps->async_queue); +} + +static long pps_cdev_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct pps_device *pps = file->private_data; + struct pps_kparams params; + struct pps_fdata fdata; + unsigned long ticks; + void __user *uarg = (void __user *) arg; + int __user *iuarg = (int __user *) arg; + int err; + + switch (cmd) { + case PPS_GETPARAMS: + pr_debug("PPS_GETPARAMS: source %d\n", pps->id); + + /* Return current parameters */ + err = copy_to_user(uarg, &pps->params, + sizeof(struct pps_kparams)); + if (err) + return -EFAULT; + + break; + + case PPS_SETPARAMS: + pr_debug("PPS_SETPARAMS: source %d\n", pps->id); + + /* Check the capabilities */ + if (!capable(CAP_SYS_TIME)) + return -EPERM; + + err = copy_from_user(¶ms, uarg, sizeof(struct pps_kparams)); + if (err) + return -EFAULT; + if (!(params.mode & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR))) { + pr_debug("capture mode unspecified (%x)\n", + params.mode); + return -EINVAL; + } + + /* Check for supported capabilities */ + if ((params.mode & ~pps->info.mode) != 0) { + pr_debug("unsupported capabilities (%x)\n", + params.mode); + return -EINVAL; + } + + spin_lock_irq(&pps->lock); + + /* Save the new parameters */ + pps->params = params; + + /* Restore the read only parameters */ + if ((params.mode & (PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)) == 0) { + /* section 3.3 of RFC 2783 interpreted */ + pr_debug("time format unspecified (%x)\n", + params.mode); + pps->params.mode |= PPS_TSFMT_TSPEC; + } + if (pps->info.mode & PPS_CANWAIT) + pps->params.mode |= PPS_CANWAIT; + pps->params.api_version = PPS_API_VERS; + + spin_unlock_irq(&pps->lock); + + break; + + case PPS_GETCAP: + pr_debug("PPS_GETCAP: source %d\n", pps->id); + + err = put_user(pps->info.mode, iuarg); + if (err) + return -EFAULT; + + break; + + case PPS_FETCH: + pr_debug("PPS_FETCH: source %d\n", pps->id); + + err = copy_from_user(&fdata, uarg, sizeof(struct pps_fdata)); + if (err) + return -EFAULT; + + pps->go = 0; + + /* Manage the timeout */ + if (fdata.timeout.flags & PPS_TIME_INVALID) + err = wait_event_interruptible(pps->queue, pps->go); + else { + pr_debug("timeout %lld.%09d\n", + (long long) fdata.timeout.sec, + fdata.timeout.nsec); + ticks = fdata.timeout.sec * HZ; + ticks += fdata.timeout.nsec / (NSEC_PER_SEC / HZ); + + if (ticks != 0) { + err = wait_event_interruptible_timeout( + pps->queue, pps->go, ticks); + if (err == 0) + return -ETIMEDOUT; + } + } + + /* Check for pending signals */ + if (err == -ERESTARTSYS) { + pr_debug("pending signal caught\n"); + return -EINTR; + } + + /* Return the fetched timestamp */ + spin_lock_irq(&pps->lock); + + fdata.info.assert_sequence = pps->assert_sequence; + fdata.info.clear_sequence = pps->clear_sequence; + fdata.info.assert_tu = pps->assert_tu; + fdata.info.clear_tu = pps->clear_tu; + fdata.info.current_mode = pps->current_mode; + + spin_unlock_irq(&pps->lock); + + err = copy_to_user(uarg, &fdata, sizeof(struct pps_fdata)); + if (err) + return -EFAULT; + + break; + + default: + return -ENOTTY; + break; + } + + return 0; +} + +static int pps_cdev_open(struct inode *inode, struct file *file) +{ + struct pps_device *pps = container_of(inode->i_cdev, + struct pps_device, cdev); + int found; + + found = pps_get_source(pps->id) != 0; + if (!found) + return -ENODEV; + + file->private_data = pps; + + return 0; +} + +static int pps_cdev_release(struct inode *inode, struct file *file) +{ + struct pps_device *pps = file->private_data; + + /* Free the PPS source and wake up (possible) deregistration */ + pps_put_source(pps); + + return 0; +} + +/* + * Char device stuff + */ + +static const struct file_operations pps_cdev_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .poll = pps_cdev_poll, + .fasync = pps_cdev_fasync, + .unlocked_ioctl = pps_cdev_ioctl, + .open = pps_cdev_open, + .release = pps_cdev_release, +}; + +int pps_register_cdev(struct pps_device *pps) +{ + int err; + + pps->devno = MKDEV(MAJOR(pps_devt), pps->id); + cdev_init(&pps->cdev, &pps_cdev_fops); + pps->cdev.owner = pps->info.owner; + + err = cdev_add(&pps->cdev, pps->devno, 1); + if (err) { + printk(KERN_ERR "pps: %s: failed to add char device %d:%d\n", + pps->info.name, MAJOR(pps_devt), pps->id); + return err; + } + pps->dev = device_create(pps_class, pps->info.dev, pps->devno, NULL, + "pps%d", pps->id); + if (err) + goto del_cdev; + dev_set_drvdata(pps->dev, pps); + + pr_debug("source %s got cdev (%d:%d)\n", pps->info.name, + MAJOR(pps_devt), pps->id); + + return 0; + +del_cdev: + cdev_del(&pps->cdev); + + return err; +} + +void pps_unregister_cdev(struct pps_device *pps) +{ + device_destroy(pps_class, pps->devno); + cdev_del(&pps->cdev); +} + +/* + * Module stuff + */ + +static void __exit pps_exit(void) +{ + class_destroy(pps_class); + unregister_chrdev_region(pps_devt, PPS_MAX_SOURCES); +} + +static int __init pps_init(void) +{ + int err; + + pps_class = class_create(THIS_MODULE, "pps"); + if (!pps_class) { + printk(KERN_ERR "pps: failed to allocate class\n"); + return -ENOMEM; + } + pps_class->dev_attrs = pps_attrs; + + err = alloc_chrdev_region(&pps_devt, 0, PPS_MAX_SOURCES, "pps"); + if (err < 0) { + printk(KERN_ERR "pps: failed to allocate char device region\n"); + goto remove_class; + } + + pr_info("LinuxPPS API ver. %d registered\n", PPS_API_VERS); + pr_info("Software ver. %s - Copyright 2005-2007 Rodolfo Giometti " + "\n", PPS_VERSION); + + return 0; + +remove_class: + class_destroy(pps_class); + + return err; +} + +subsys_initcall(pps_init); +module_exit(pps_exit); + +MODULE_AUTHOR("Rodolfo Giometti "); +MODULE_DESCRIPTION("LinuxPPS support (RFC 2783) - ver. " PPS_VERSION); +MODULE_LICENSE("GPL"); diff --git a/drivers/pps/sysfs.c b/drivers/pps/sysfs.c new file mode 100644 index 000000000000..ef0978c71eee --- /dev/null +++ b/drivers/pps/sysfs.c @@ -0,0 +1,98 @@ +/* + * PPS sysfs support + * + * + * Copyright (C) 2007-2009 Rodolfo Giometti + * + * 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 +#include +#include +#include + +/* + * Attribute functions + */ + +static ssize_t pps_show_assert(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct pps_device *pps = dev_get_drvdata(dev); + + if (!(pps->info.mode & PPS_CAPTUREASSERT)) + return 0; + + return sprintf(buf, "%lld.%09d#%d\n", + (long long) pps->assert_tu.sec, pps->assert_tu.nsec, + pps->assert_sequence); +} + +static ssize_t pps_show_clear(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct pps_device *pps = dev_get_drvdata(dev); + + if (!(pps->info.mode & PPS_CAPTURECLEAR)) + return 0; + + return sprintf(buf, "%lld.%09d#%d\n", + (long long) pps->clear_tu.sec, pps->clear_tu.nsec, + pps->clear_sequence); +} + +static ssize_t pps_show_mode(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct pps_device *pps = dev_get_drvdata(dev); + + return sprintf(buf, "%4x\n", pps->info.mode); +} + +static ssize_t pps_show_echo(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct pps_device *pps = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", !!pps->info.echo); +} + +static ssize_t pps_show_name(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct pps_device *pps = dev_get_drvdata(dev); + + return sprintf(buf, "%s\n", pps->info.name); +} + +static ssize_t pps_show_path(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct pps_device *pps = dev_get_drvdata(dev); + + return sprintf(buf, "%s\n", pps->info.path); +} + +struct device_attribute pps_attrs[] = { + __ATTR(assert, S_IRUGO, pps_show_assert, NULL), + __ATTR(clear, S_IRUGO, pps_show_clear, NULL), + __ATTR(mode, S_IRUGO, pps_show_mode, NULL), + __ATTR(echo, S_IRUGO, pps_show_echo, NULL), + __ATTR(name, S_IRUGO, pps_show_name, NULL), + __ATTR(path, S_IRUGO, pps_show_path, NULL), + __ATTR_NULL, +}; diff --git a/drivers/ps3/ps3-sys-manager.c b/drivers/ps3/ps3-sys-manager.c index f17513dd9d4b..88cb74088611 100644 --- a/drivers/ps3/ps3-sys-manager.c +++ b/drivers/ps3/ps3-sys-manager.c @@ -706,7 +706,7 @@ static void ps3_sys_manager_work(struct ps3_system_bus_device *dev) ps3_vuart_read_async(dev, PS3_SM_RX_MSG_LEN_MIN); } -static int ps3_sys_manager_probe(struct ps3_system_bus_device *dev) +static int __devinit ps3_sys_manager_probe(struct ps3_system_bus_device *dev) { int result; struct ps3_sys_manager_ops ops; diff --git a/drivers/ps3/ps3av.c b/drivers/ps3/ps3av.c index 235e87fcb49f..e82d8c9c6cda 100644 --- a/drivers/ps3/ps3av.c +++ b/drivers/ps3/ps3av.c @@ -80,12 +80,12 @@ static const struct avset_video_mode { { 0, }, /* auto */ {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480I, A_N, 720, 480}, {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480P, A_N, 720, 480}, - {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_60HZ, A_N, 1280, 720}, + {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_60HZ, A_W, 1280, 720}, {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_60HZ, A_W, 1920, 1080}, {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_60HZ, A_W, 1920, 1080}, {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576I, A_N, 720, 576}, {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576P, A_N, 720, 576}, - {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_50HZ, A_N, 1280, 720}, + {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_50HZ, A_W, 1280, 720}, {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_50HZ, A_W, 1920, 1080}, {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_50HZ, A_W, 1920, 1080}, { RGB8, XRGB, PS3AV_CMD_VIDEO_VID_WXGA, A_W, 1280, 768}, @@ -937,7 +937,7 @@ int ps3av_audio_mute(int mute) EXPORT_SYMBOL_GPL(ps3av_audio_mute); -static int ps3av_probe(struct ps3_system_bus_device *dev) +static int __devinit ps3av_probe(struct ps3_system_bus_device *dev) { int res; int id; @@ -1048,7 +1048,7 @@ static struct ps3_vuart_port_driver ps3av_driver = { .shutdown = ps3av_shutdown, }; -static int ps3av_module_init(void) +static int __init ps3av_module_init(void) { int error; diff --git a/drivers/ps3/ps3av_cmd.c b/drivers/ps3/ps3av_cmd.c index 716596e8e5b0..f555fedd5073 100644 --- a/drivers/ps3/ps3av_cmd.c +++ b/drivers/ps3/ps3av_cmd.c @@ -21,9 +21,10 @@ #include #include #include + #include -#include #include +#include #include "vuart.h" diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c index 74d0bfa3f310..45415096c294 100644 --- a/drivers/rapidio/rio-scan.c +++ b/drivers/rapidio/rio-scan.c @@ -263,15 +263,21 @@ static void rio_route_set_ops(struct rio_dev *rdev) * device to the RIO device list. Creates the generic sysfs nodes * for an RIO device. */ -static void __devinit rio_add_device(struct rio_dev *rdev) +static int __devinit rio_add_device(struct rio_dev *rdev) { - device_add(&rdev->dev); + int err; + + err = device_add(&rdev->dev); + if (err) + return err; spin_lock(&rio_global_list_lock); list_add_tail(&rdev->global_list, &rio_devices); spin_unlock(&rio_global_list_lock); rio_create_sysfs_dev_files(rdev); + + return 0; } /** @@ -290,17 +296,18 @@ static void __devinit rio_add_device(struct rio_dev *rdev) * to a RIO device on success or NULL on failure. * */ -static struct rio_dev *rio_setup_device(struct rio_net *net, +static struct rio_dev __devinit *rio_setup_device(struct rio_net *net, struct rio_mport *port, u16 destid, u8 hopcount, int do_enum) { + int ret = 0; struct rio_dev *rdev; - struct rio_switch *rswitch; + struct rio_switch *rswitch = NULL; int result, rdid; rdev = kzalloc(sizeof(struct rio_dev), GFP_KERNEL); if (!rdev) - goto out; + return NULL; rdev->net = net; rio_mport_read_config_32(port, destid, hopcount, RIO_DEV_ID_CAR, @@ -343,23 +350,16 @@ static struct rio_dev *rio_setup_device(struct rio_net *net, rio_mport_read_config_32(port, destid, hopcount, RIO_SWP_INFO_CAR, &rdev->swpinfo); rswitch = kmalloc(sizeof(struct rio_switch), GFP_KERNEL); - if (!rswitch) { - kfree(rdev); - rdev = NULL; - goto out; - } + if (!rswitch) + goto cleanup; rswitch->switchid = next_switchid; rswitch->hopcount = hopcount; rswitch->destid = destid; rswitch->route_table = kzalloc(sizeof(u8)* RIO_MAX_ROUTE_ENTRIES(port->sys_size), GFP_KERNEL); - if (!rswitch->route_table) { - kfree(rdev); - rdev = NULL; - kfree(rswitch); - goto out; - } + if (!rswitch->route_table) + goto cleanup; /* Initialize switch route table */ for (rdid = 0; rdid < RIO_MAX_ROUTE_ENTRIES(port->sys_size); rdid++) @@ -390,10 +390,19 @@ static struct rio_dev *rio_setup_device(struct rio_net *net, rio_init_dbell_res(&rdev->riores[RIO_DOORBELL_RESOURCE], 0, 0xffff); - rio_add_device(rdev); + ret = rio_add_device(rdev); + if (ret) + goto cleanup; - out: return rdev; + +cleanup: + if (rswitch) { + kfree(rswitch->route_table); + kfree(rswitch); + } + kfree(rdev); + return NULL; } /** @@ -559,7 +568,7 @@ static void rio_net_add_mport(struct rio_net *net, struct rio_mport *port) * Recursively enumerates a RIO network. Transactions are sent via the * master port passed in @port. */ -static int rio_enum_peer(struct rio_net *net, struct rio_mport *port, +static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port, u8 hopcount) { int port_num; @@ -718,7 +727,7 @@ static int rio_enum_complete(struct rio_mport *port) * Recursively discovers a RIO network. Transactions are sent via the * master port passed in @port. */ -static int +static int __devinit rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid, u8 hopcount) { diff --git a/drivers/rapidio/rio-sysfs.c b/drivers/rapidio/rio-sysfs.c index 97a147f050d6..ba742e82c57d 100644 --- a/drivers/rapidio/rio-sysfs.c +++ b/drivers/rapidio/rio-sysfs.c @@ -214,9 +214,11 @@ static struct bin_attribute rio_config_attr = { */ int rio_create_sysfs_dev_files(struct rio_dev *rdev) { - sysfs_create_bin_file(&rdev->dev.kobj, &rio_config_attr); + int err = 0; - return 0; + err = sysfs_create_bin_file(&rdev->dev.kobj, &rio_config_attr); + + return err; } /** diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index e58c0ce65aa6..f4317798e47c 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -47,6 +47,16 @@ config REGULATOR_VIRTUAL_CONSUMER If unsure, say no. +config REGULATOR_USERSPACE_CONSUMER + tristate "Userspace regulator consumer support" + default n + help + There are some classes of devices that are controlled entirely + from user space. Usersapce consumer driver provides ability to + control power supplies for such devices. + + If unsure, say no. + config REGULATOR_BQ24022 tristate "TI bq24022 Dual Input 1-Cell Li-Ion Charger IC" default n @@ -56,6 +66,15 @@ config REGULATOR_BQ24022 charging select between 100 mA and 500 mA charging current limit. +config REGULATOR_MAX1586 + tristate "Maxim 1586/1587 voltage regulator" + depends on I2C + default n + help + This driver controls a Maxim 1586 or 1587 voltage output + regulator via I2C bus. The provided regulator is suitable + for PXA27x chips to control VCC_CORE and VCC_USIM voltages. + config REGULATOR_TWL4030 bool "TI TWL4030/TWL5030/TPS695x0 PMIC" depends on TWL4030_CORE @@ -91,4 +110,11 @@ config REGULATOR_PCF50633 Say Y here to support the voltage regulators and convertors on PCF50633 +config REGULATOR_LP3971 + tristate "National Semiconductors LP3971 PMIC regulator driver" + depends on I2C + help + Say Y here to support the voltage regulators and convertors + on National Semiconductors LP3971 PMIC + endif diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index bac133afc061..4d762c4cccfd 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -6,8 +6,11 @@ obj-$(CONFIG_REGULATOR) += core.o obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o +obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o obj-$(CONFIG_REGULATOR_BQ24022) += bq24022.o +obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o +obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o obj-$(CONFIG_REGULATOR_TWL4030) += twl4030-regulator.o obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o diff --git a/drivers/regulator/da903x.c b/drivers/regulator/da903x.c index c6628f5a0af7..b8b89ef10a84 100644 --- a/drivers/regulator/da903x.c +++ b/drivers/regulator/da903x.c @@ -504,7 +504,7 @@ static int __init da903x_regulator_init(void) { return platform_driver_register(&da903x_regulator_driver); } -module_init(da903x_regulator_init); +subsys_initcall(da903x_regulator_init); static void __exit da903x_regulator_exit(void) { diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c index 23d554628a76..cdc674fb46c3 100644 --- a/drivers/regulator/fixed.c +++ b/drivers/regulator/fixed.c @@ -44,10 +44,22 @@ static int fixed_voltage_get_voltage(struct regulator_dev *dev) return data->microvolts; } +static int fixed_voltage_list_voltage(struct regulator_dev *dev, + unsigned selector) +{ + struct fixed_voltage_data *data = rdev_get_drvdata(dev); + + if (selector != 0) + return -EINVAL; + + return data->microvolts; +} + static struct regulator_ops fixed_voltage_ops = { .is_enabled = fixed_voltage_is_enabled, .enable = fixed_voltage_enable, .get_voltage = fixed_voltage_get_voltage, + .list_voltage = fixed_voltage_list_voltage, }; static int regulator_fixed_voltage_probe(struct platform_device *pdev) @@ -69,7 +81,8 @@ static int regulator_fixed_voltage_probe(struct platform_device *pdev) } drvdata->desc.type = REGULATOR_VOLTAGE; drvdata->desc.owner = THIS_MODULE; - drvdata->desc.ops = &fixed_voltage_ops, + drvdata->desc.ops = &fixed_voltage_ops; + drvdata->desc.n_voltages = 1; drvdata->microvolts = config->microvolts; @@ -117,7 +130,7 @@ static int __init regulator_fixed_voltage_init(void) { return platform_driver_register(®ulator_fixed_voltage_driver); } -module_init(regulator_fixed_voltage_init); +subsys_initcall(regulator_fixed_voltage_init); static void __exit regulator_fixed_voltage_exit(void) { @@ -128,3 +141,4 @@ module_exit(regulator_fixed_voltage_exit); MODULE_AUTHOR("Mark Brown "); MODULE_DESCRIPTION("Fixed voltage regulator"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:reg-fixed-voltage"); diff --git a/drivers/regulator/lp3971.c b/drivers/regulator/lp3971.c new file mode 100644 index 000000000000..a61018a27698 --- /dev/null +++ b/drivers/regulator/lp3971.c @@ -0,0 +1,562 @@ +/* + * Regulator driver for National Semiconductors LP3971 PMIC chip + * + * Copyright (C) 2009 Samsung Electronics + * Author: Marek Szyprowski + * + * Based on wm8350.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include + +struct lp3971 { + struct device *dev; + struct mutex io_lock; + struct i2c_client *i2c; + int num_regulators; + struct regulator_dev **rdev; +}; + +static u8 lp3971_reg_read(struct lp3971 *lp3971, u8 reg); +static int lp3971_set_bits(struct lp3971 *lp3971, u8 reg, u16 mask, u16 val); + +#define LP3971_SYS_CONTROL1_REG 0x07 + +/* System control register 1 initial value, + bits 4 and 5 are EPROM programmable */ +#define SYS_CONTROL1_INIT_VAL 0x40 +#define SYS_CONTROL1_INIT_MASK 0xCF + +#define LP3971_BUCK_VOL_ENABLE_REG 0x10 +#define LP3971_BUCK_VOL_CHANGE_REG 0x20 + +/* Voltage control registers shift: + LP3971_BUCK1 -> 0 + LP3971_BUCK2 -> 4 + LP3971_BUCK3 -> 6 +*/ +#define BUCK_VOL_CHANGE_SHIFT(x) (((1 << x) & ~0x01) << 1) +#define BUCK_VOL_CHANGE_FLAG_GO 0x01 +#define BUCK_VOL_CHANGE_FLAG_TARGET 0x02 +#define BUCK_VOL_CHANGE_FLAG_MASK 0x03 + +#define LP3971_BUCK1_BASE 0x23 +#define LP3971_BUCK2_BASE 0x29 +#define LP3971_BUCK3_BASE 0x32 + +const static int buck_base_addr[] = { + LP3971_BUCK1_BASE, + LP3971_BUCK2_BASE, + LP3971_BUCK3_BASE, +}; + +#define LP3971_BUCK_TARGET_VOL1_REG(x) (buck_base_addr[x]) +#define LP3971_BUCK_TARGET_VOL2_REG(x) (buck_base_addr[x]+1) + +const static int buck_voltage_map[] = { + 0, 800, 850, 900, 950, 1000, 1050, 1100, + 1150, 1200, 1250, 1300, 1350, 1400, 1450, 1500, + 1550, 1600, 1650, 1700, 1800, 1900, 2500, 2800, + 3000, 3300, +}; + +#define BUCK_TARGET_VOL_MASK 0x3f +#define BUCK_TARGET_VOL_MIN_IDX 0x01 +#define BUCK_TARGET_VOL_MAX_IDX 0x19 + +#define LP3971_BUCK_RAMP_REG(x) (buck_base_addr[x]+2) + +#define LP3971_LDO_ENABLE_REG 0x12 +#define LP3971_LDO_VOL_CONTR_BASE 0x39 + +/* Voltage control registers: + LP3971_LDO1 -> LP3971_LDO_VOL_CONTR_BASE + 0 + LP3971_LDO2 -> LP3971_LDO_VOL_CONTR_BASE + 0 + LP3971_LDO3 -> LP3971_LDO_VOL_CONTR_BASE + 1 + LP3971_LDO4 -> LP3971_LDO_VOL_CONTR_BASE + 1 + LP3971_LDO5 -> LP3971_LDO_VOL_CONTR_BASE + 2 +*/ +#define LP3971_LDO_VOL_CONTR_REG(x) (LP3971_LDO_VOL_CONTR_BASE + (x >> 1)) + +/* Voltage control registers shift: + LP3971_LDO1 -> 0, LP3971_LDO2 -> 4 + LP3971_LDO3 -> 0, LP3971_LDO4 -> 4 + LP3971_LDO5 -> 0 +*/ +#define LDO_VOL_CONTR_SHIFT(x) ((x & 1) << 2) +#define LDO_VOL_CONTR_MASK 0x0f + +const static int ldo45_voltage_map[] = { + 1000, 1050, 1100, 1150, 1200, 1250, 1300, 1350, + 1400, 1500, 1800, 1900, 2500, 2800, 3000, 3300, +}; + +const static int ldo123_voltage_map[] = { + 1800, 1900, 2000, 2100, 2200, 2300, 2400, 2500, + 2600, 2700, 2800, 2900, 3000, 3100, 3200, 3300, +}; + +const static int *ldo_voltage_map[] = { + ldo123_voltage_map, /* LDO1 */ + ldo123_voltage_map, /* LDO2 */ + ldo123_voltage_map, /* LDO3 */ + ldo45_voltage_map, /* LDO4 */ + ldo45_voltage_map, /* LDO5 */ +}; + +#define LDO_VOL_VALUE_MAP(x) (ldo_voltage_map[(x - LP3971_LDO1)]) + +#define LDO_VOL_MIN_IDX 0x00 +#define LDO_VOL_MAX_IDX 0x0f + +static int lp3971_ldo_list_voltage(struct regulator_dev *dev, unsigned index) +{ + int ldo = rdev_get_id(dev) - LP3971_LDO1; + return 1000 * LDO_VOL_VALUE_MAP(ldo)[index]; +} + +static int lp3971_ldo_is_enabled(struct regulator_dev *dev) +{ + struct lp3971 *lp3971 = rdev_get_drvdata(dev); + int ldo = rdev_get_id(dev) - LP3971_LDO1; + u16 mask = 1 << (1 + ldo); + u16 val; + + val = lp3971_reg_read(lp3971, LP3971_LDO_ENABLE_REG); + return (val & mask) != 0; +} + +static int lp3971_ldo_enable(struct regulator_dev *dev) +{ + struct lp3971 *lp3971 = rdev_get_drvdata(dev); + int ldo = rdev_get_id(dev) - LP3971_LDO1; + u16 mask = 1 << (1 + ldo); + + return lp3971_set_bits(lp3971, LP3971_LDO_ENABLE_REG, mask, mask); +} + +static int lp3971_ldo_disable(struct regulator_dev *dev) +{ + struct lp3971 *lp3971 = rdev_get_drvdata(dev); + int ldo = rdev_get_id(dev) - LP3971_LDO1; + u16 mask = 1 << (1 + ldo); + + return lp3971_set_bits(lp3971, LP3971_LDO_ENABLE_REG, mask, 0); +} + +static int lp3971_ldo_get_voltage(struct regulator_dev *dev) +{ + struct lp3971 *lp3971 = rdev_get_drvdata(dev); + int ldo = rdev_get_id(dev) - LP3971_LDO1; + u16 val, reg; + + reg = lp3971_reg_read(lp3971, LP3971_LDO_VOL_CONTR_REG(ldo)); + val = (reg >> LDO_VOL_CONTR_SHIFT(ldo)) & LDO_VOL_CONTR_MASK; + + return 1000 * LDO_VOL_VALUE_MAP(ldo)[val]; +} + +static int lp3971_ldo_set_voltage(struct regulator_dev *dev, + int min_uV, int max_uV) +{ + struct lp3971 *lp3971 = rdev_get_drvdata(dev); + int ldo = rdev_get_id(dev) - LP3971_LDO1; + int min_vol = min_uV / 1000, max_vol = max_uV / 1000; + const int *vol_map = LDO_VOL_VALUE_MAP(ldo); + u16 val; + + if (min_vol < vol_map[LDO_VOL_MIN_IDX] || + min_vol > vol_map[LDO_VOL_MAX_IDX]) + return -EINVAL; + + for (val = LDO_VOL_MIN_IDX; val <= LDO_VOL_MAX_IDX; val++) + if (vol_map[val] >= min_vol) + break; + + if (vol_map[val] > max_vol) + return -EINVAL; + + return lp3971_set_bits(lp3971, LP3971_LDO_VOL_CONTR_REG(ldo), + LDO_VOL_CONTR_MASK << LDO_VOL_CONTR_SHIFT(ldo), val); +} + +static struct regulator_ops lp3971_ldo_ops = { + .list_voltage = lp3971_ldo_list_voltage, + .is_enabled = lp3971_ldo_is_enabled, + .enable = lp3971_ldo_enable, + .disable = lp3971_ldo_disable, + .get_voltage = lp3971_ldo_get_voltage, + .set_voltage = lp3971_ldo_set_voltage, +}; + +static int lp3971_dcdc_list_voltage(struct regulator_dev *dev, unsigned index) +{ + return 1000 * buck_voltage_map[index]; +} + +static int lp3971_dcdc_is_enabled(struct regulator_dev *dev) +{ + struct lp3971 *lp3971 = rdev_get_drvdata(dev); + int buck = rdev_get_id(dev) - LP3971_DCDC1; + u16 mask = 1 << (buck * 2); + u16 val; + + val = lp3971_reg_read(lp3971, LP3971_BUCK_VOL_ENABLE_REG); + return (val & mask) != 0; +} + +static int lp3971_dcdc_enable(struct regulator_dev *dev) +{ + struct lp3971 *lp3971 = rdev_get_drvdata(dev); + int buck = rdev_get_id(dev) - LP3971_DCDC1; + u16 mask = 1 << (buck * 2); + + return lp3971_set_bits(lp3971, LP3971_BUCK_VOL_ENABLE_REG, mask, mask); +} + +static int lp3971_dcdc_disable(struct regulator_dev *dev) +{ + struct lp3971 *lp3971 = rdev_get_drvdata(dev); + int buck = rdev_get_id(dev) - LP3971_DCDC1; + u16 mask = 1 << (buck * 2); + + return lp3971_set_bits(lp3971, LP3971_BUCK_VOL_ENABLE_REG, mask, 0); +} + +static int lp3971_dcdc_get_voltage(struct regulator_dev *dev) +{ + struct lp3971 *lp3971 = rdev_get_drvdata(dev); + int buck = rdev_get_id(dev) - LP3971_DCDC1; + u16 reg; + int val; + + reg = lp3971_reg_read(lp3971, LP3971_BUCK_TARGET_VOL1_REG(buck)); + reg &= BUCK_TARGET_VOL_MASK; + + if (reg <= BUCK_TARGET_VOL_MAX_IDX) + val = 1000 * buck_voltage_map[reg]; + else { + val = 0; + dev_warn(&dev->dev, "chip reported incorrect voltage value.\n"); + } + + return val; +} + +static int lp3971_dcdc_set_voltage(struct regulator_dev *dev, + int min_uV, int max_uV) +{ + struct lp3971 *lp3971 = rdev_get_drvdata(dev); + int buck = rdev_get_id(dev) - LP3971_DCDC1; + int min_vol = min_uV / 1000, max_vol = max_uV / 1000; + const int *vol_map = buck_voltage_map; + u16 val; + int ret; + + if (min_vol < vol_map[BUCK_TARGET_VOL_MIN_IDX] || + min_vol > vol_map[BUCK_TARGET_VOL_MAX_IDX]) + return -EINVAL; + + for (val = BUCK_TARGET_VOL_MIN_IDX; val <= BUCK_TARGET_VOL_MAX_IDX; + val++) + if (vol_map[val] >= min_vol) + break; + + if (vol_map[val] > max_vol) + return -EINVAL; + + ret = lp3971_set_bits(lp3971, LP3971_BUCK_TARGET_VOL1_REG(buck), + BUCK_TARGET_VOL_MASK, val); + if (ret) + return ret; + + ret = lp3971_set_bits(lp3971, LP3971_BUCK_VOL_CHANGE_REG, + BUCK_VOL_CHANGE_FLAG_MASK << BUCK_VOL_CHANGE_SHIFT(buck), + BUCK_VOL_CHANGE_FLAG_GO << BUCK_VOL_CHANGE_SHIFT(buck)); + if (ret) + return ret; + + return lp3971_set_bits(lp3971, LP3971_BUCK_VOL_CHANGE_REG, + BUCK_VOL_CHANGE_FLAG_MASK << BUCK_VOL_CHANGE_SHIFT(buck), + 0 << BUCK_VOL_CHANGE_SHIFT(buck)); +} + +static struct regulator_ops lp3971_dcdc_ops = { + .list_voltage = lp3971_dcdc_list_voltage, + .is_enabled = lp3971_dcdc_is_enabled, + .enable = lp3971_dcdc_enable, + .disable = lp3971_dcdc_disable, + .get_voltage = lp3971_dcdc_get_voltage, + .set_voltage = lp3971_dcdc_set_voltage, +}; + +static struct regulator_desc regulators[] = { + { + .name = "LDO1", + .id = LP3971_LDO1, + .ops = &lp3971_ldo_ops, + .n_voltages = ARRAY_SIZE(ldo123_voltage_map), + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + { + .name = "LDO2", + .id = LP3971_LDO2, + .ops = &lp3971_ldo_ops, + .n_voltages = ARRAY_SIZE(ldo123_voltage_map), + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + { + .name = "LDO3", + .id = LP3971_LDO3, + .ops = &lp3971_ldo_ops, + .n_voltages = ARRAY_SIZE(ldo123_voltage_map), + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + { + .name = "LDO4", + .id = LP3971_LDO4, + .ops = &lp3971_ldo_ops, + .n_voltages = ARRAY_SIZE(ldo45_voltage_map), + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + { + .name = "LDO5", + .id = LP3971_LDO5, + .ops = &lp3971_ldo_ops, + .n_voltages = ARRAY_SIZE(ldo45_voltage_map), + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + { + .name = "DCDC1", + .id = LP3971_DCDC1, + .ops = &lp3971_dcdc_ops, + .n_voltages = ARRAY_SIZE(buck_voltage_map), + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + { + .name = "DCDC2", + .id = LP3971_DCDC2, + .ops = &lp3971_dcdc_ops, + .n_voltages = ARRAY_SIZE(buck_voltage_map), + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + { + .name = "DCDC3", + .id = LP3971_DCDC3, + .ops = &lp3971_dcdc_ops, + .n_voltages = ARRAY_SIZE(buck_voltage_map), + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, +}; + +static int lp3971_i2c_read(struct i2c_client *i2c, char reg, int count, + u16 *dest) +{ + int ret; + + if (count != 1) + return -EIO; + ret = i2c_smbus_read_byte_data(i2c, reg); + if (ret < 0 || count != 1) + return -EIO; + + *dest = ret; + return 0; +} + +static int lp3971_i2c_write(struct i2c_client *i2c, char reg, int count, + const u16 *src) +{ + int ret; + + if (count != 1) + return -EIO; + ret = i2c_smbus_write_byte_data(i2c, reg, *src); + if (ret >= 0) + return 0; + + return ret; +} + +static u8 lp3971_reg_read(struct lp3971 *lp3971, u8 reg) +{ + u16 val = 0; + + mutex_lock(&lp3971->io_lock); + + lp3971_i2c_read(lp3971->i2c, reg, 1, &val); + + dev_dbg(lp3971->dev, "reg read 0x%02x -> 0x%02x\n", (int)reg, + (unsigned)val&0xff); + + mutex_unlock(&lp3971->io_lock); + + return val & 0xff; +} + +static int lp3971_set_bits(struct lp3971 *lp3971, u8 reg, u16 mask, u16 val) +{ + u16 tmp; + int ret; + + mutex_lock(&lp3971->io_lock); + + ret = lp3971_i2c_read(lp3971->i2c, reg, 1, &tmp); + tmp = (tmp & ~mask) | val; + if (ret == 0) { + ret = lp3971_i2c_write(lp3971->i2c, reg, 1, &tmp); + dev_dbg(lp3971->dev, "reg write 0x%02x -> 0x%02x\n", (int)reg, + (unsigned)val&0xff); + } + mutex_unlock(&lp3971->io_lock); + + return ret; +} + +static int setup_regulators(struct lp3971 *lp3971, + struct lp3971_platform_data *pdata) +{ + int i, err; + int num_regulators = pdata->num_regulators; + lp3971->num_regulators = num_regulators; + lp3971->rdev = kzalloc(sizeof(struct regulator_dev *) * num_regulators, + GFP_KERNEL); + + /* Instantiate the regulators */ + for (i = 0; i < num_regulators; i++) { + int id = pdata->regulators[i].id; + lp3971->rdev[i] = regulator_register(®ulators[id], + lp3971->dev, pdata->regulators[i].initdata, lp3971); + + err = IS_ERR(lp3971->rdev[i]); + if (err) { + dev_err(lp3971->dev, "regulator init failed: %d\n", + err); + goto error; + } + } + + return 0; +error: + for (i = 0; i < num_regulators; i++) + if (lp3971->rdev[i]) + regulator_unregister(lp3971->rdev[i]); + kfree(lp3971->rdev); + lp3971->rdev = NULL; + return err; +} + +static int __devinit lp3971_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct lp3971 *lp3971; + struct lp3971_platform_data *pdata = i2c->dev.platform_data; + int ret; + u16 val; + + lp3971 = kzalloc(sizeof(struct lp3971), GFP_KERNEL); + if (lp3971 == NULL) { + ret = -ENOMEM; + goto err; + } + + lp3971->i2c = i2c; + lp3971->dev = &i2c->dev; + i2c_set_clientdata(i2c, lp3971); + + mutex_init(&lp3971->io_lock); + + /* Detect LP3971 */ + ret = lp3971_i2c_read(i2c, LP3971_SYS_CONTROL1_REG, 1, &val); + if (ret == 0 && (val & SYS_CONTROL1_INIT_MASK) != SYS_CONTROL1_INIT_VAL) + ret = -ENODEV; + if (ret < 0) { + dev_err(&i2c->dev, "failed to detect device\n"); + goto err_detect; + } + + if (pdata) { + ret = setup_regulators(lp3971, pdata); + if (ret < 0) + goto err_detect; + } else + dev_warn(lp3971->dev, "No platform init data supplied\n"); + + return 0; + +err_detect: + i2c_set_clientdata(i2c, NULL); + kfree(lp3971); +err: + return ret; +} + +static int __devexit lp3971_i2c_remove(struct i2c_client *i2c) +{ + struct lp3971 *lp3971 = i2c_get_clientdata(i2c); + int i; + for (i = 0; i < lp3971->num_regulators; i++) + if (lp3971->rdev[i]) + regulator_unregister(lp3971->rdev[i]); + kfree(lp3971->rdev); + i2c_set_clientdata(i2c, NULL); + kfree(lp3971); + + return 0; +} + +static const struct i2c_device_id lp3971_i2c_id[] = { + { "lp3971", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, lp3971_i2c_id); + +static struct i2c_driver lp3971_i2c_driver = { + .driver = { + .name = "LP3971", + .owner = THIS_MODULE, + }, + .probe = lp3971_i2c_probe, + .remove = __devexit_p(lp3971_i2c_remove), + .id_table = lp3971_i2c_id, +}; + +static int __init lp3971_module_init(void) +{ + int ret = -ENODEV; + + ret = i2c_add_driver(&lp3971_i2c_driver); + if (ret != 0) + pr_err("Failed to register I2C driver: %d\n", ret); + + return ret; +} +module_init(lp3971_module_init); + +static void __exit lp3971_module_exit(void) +{ + i2c_del_driver(&lp3971_i2c_driver); +} +module_exit(lp3971_module_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Marek Szyprowski "); +MODULE_DESCRIPTION("LP3971 PMIC driver"); diff --git a/drivers/regulator/max1586.c b/drivers/regulator/max1586.c new file mode 100644 index 000000000000..2c082d3ef484 --- /dev/null +++ b/drivers/regulator/max1586.c @@ -0,0 +1,282 @@ +/* + * max1586.c -- Voltage and current regulation for the Maxim 1586 + * + * Copyright (C) 2008 Robert Jarzmik + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include + +#define MAX1586_V3_MAX_VSEL 31 +#define MAX1586_V6_MAX_VSEL 3 + +#define MAX1586_V3_MIN_UV 700000 +#define MAX1586_V3_MAX_UV 1475000 + +#define MAX1586_V6_MIN_UV 0 +#define MAX1586_V6_MAX_UV 3000000 + +#define I2C_V3_SELECT (0 << 5) +#define I2C_V6_SELECT (1 << 5) + +struct max1586_data { + struct i2c_client *client; + + /* min/max V3 voltage */ + unsigned int min_uV; + unsigned int max_uV; + + struct regulator_dev *rdev[0]; +}; + +/* + * V3 voltage + * On I2C bus, sending a "x" byte to the max1586 means : + * set V3 to 0.700V + (x & 0x1f) * 0.025V + * This voltage can be increased by external resistors + * R24 and R25=100kOhm as described in the data sheet. + * The gain is approximately: 1 + R24/R25 + R24/185.5kOhm + */ +static int max1586_v3_calc_voltage(struct max1586_data *max1586, + unsigned selector) +{ + unsigned range_uV = max1586->max_uV - max1586->min_uV; + + return max1586->min_uV + (selector * range_uV / MAX1586_V3_MAX_VSEL); +} + +static int max1586_v3_set(struct regulator_dev *rdev, int min_uV, int max_uV) +{ + struct max1586_data *max1586 = rdev_get_drvdata(rdev); + struct i2c_client *client = max1586->client; + unsigned range_uV = max1586->max_uV - max1586->min_uV; + unsigned selector; + u8 v3_prog; + + if (min_uV > max1586->max_uV || max_uV < max1586->min_uV) + return -EINVAL; + if (min_uV < max1586->min_uV) + min_uV = max1586->min_uV; + + selector = ((min_uV - max1586->min_uV) * MAX1586_V3_MAX_VSEL + + range_uV - 1) / range_uV; + if (max1586_v3_calc_voltage(max1586, selector) > max_uV) + return -EINVAL; + + dev_dbg(&client->dev, "changing voltage v3 to %dmv\n", + max1586_v3_calc_voltage(max1586, selector) / 1000); + + v3_prog = I2C_V3_SELECT | (u8) selector; + return i2c_smbus_write_byte(client, v3_prog); +} + +static int max1586_v3_list(struct regulator_dev *rdev, unsigned selector) +{ + struct max1586_data *max1586 = rdev_get_drvdata(rdev); + + if (selector > MAX1586_V3_MAX_VSEL) + return -EINVAL; + return max1586_v3_calc_voltage(max1586, selector); +} + +/* + * V6 voltage + * On I2C bus, sending a "x" byte to the max1586 means : + * set V6 to either 0V, 1.8V, 2.5V, 3V depending on (x & 0x3) + * As regulator framework doesn't accept voltages to be 0V, we use 1uV. + */ +static int max1586_v6_calc_voltage(unsigned selector) +{ + static int voltages_uv[] = { 1, 1800000, 2500000, 3000000 }; + + return voltages_uv[selector]; +} + +static int max1586_v6_set(struct regulator_dev *rdev, int min_uV, int max_uV) +{ + struct i2c_client *client = rdev_get_drvdata(rdev); + unsigned selector; + u8 v6_prog; + + if (min_uV < MAX1586_V6_MIN_UV || min_uV > MAX1586_V6_MAX_UV) + return -EINVAL; + if (max_uV < MAX1586_V6_MIN_UV || max_uV > MAX1586_V6_MAX_UV) + return -EINVAL; + + if (min_uV >= 3000000) + selector = 3; + if (min_uV < 3000000) + selector = 2; + if (min_uV < 2500000) + selector = 1; + if (min_uV < 1800000) + selector = 0; + + if (max1586_v6_calc_voltage(selector) > max_uV) + return -EINVAL; + + dev_dbg(&client->dev, "changing voltage v6 to %dmv\n", + max1586_v6_calc_voltage(selector) / 1000); + + v6_prog = I2C_V6_SELECT | (u8) selector; + return i2c_smbus_write_byte(client, v6_prog); +} + +static int max1586_v6_list(struct regulator_dev *rdev, unsigned selector) +{ + if (selector > MAX1586_V6_MAX_VSEL) + return -EINVAL; + return max1586_v6_calc_voltage(selector); +} + +/* + * The Maxim 1586 controls V3 and V6 voltages, but offers no way of reading back + * the set up value. + */ +static struct regulator_ops max1586_v3_ops = { + .set_voltage = max1586_v3_set, + .list_voltage = max1586_v3_list, +}; + +static struct regulator_ops max1586_v6_ops = { + .set_voltage = max1586_v6_set, + .list_voltage = max1586_v6_list, +}; + +static struct regulator_desc max1586_reg[] = { + { + .name = "Output_V3", + .id = MAX1586_V3, + .ops = &max1586_v3_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = MAX1586_V3_MAX_VSEL + 1, + .owner = THIS_MODULE, + }, + { + .name = "Output_V6", + .id = MAX1586_V6, + .ops = &max1586_v6_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = MAX1586_V6_MAX_VSEL + 1, + .owner = THIS_MODULE, + }, +}; + +static int max1586_pmic_probe(struct i2c_client *client, + const struct i2c_device_id *i2c_id) +{ + struct regulator_dev **rdev; + struct max1586_platform_data *pdata = client->dev.platform_data; + struct max1586_data *max1586; + int i, id, ret = -ENOMEM; + + max1586 = kzalloc(sizeof(struct max1586_data) + + sizeof(struct regulator_dev *) * (MAX1586_V6 + 1), + GFP_KERNEL); + if (!max1586) + goto out; + + max1586->client = client; + + if (!pdata->v3_gain) { + ret = -EINVAL; + goto out_unmap; + } + max1586->min_uV = MAX1586_V3_MIN_UV / 1000 * pdata->v3_gain / 1000; + max1586->max_uV = MAX1586_V3_MAX_UV / 1000 * pdata->v3_gain / 1000; + + rdev = max1586->rdev; + for (i = 0; i < pdata->num_subdevs && i <= MAX1586_V6; i++) { + id = pdata->subdevs[i].id; + if (!pdata->subdevs[i].platform_data) + continue; + if (id < MAX1586_V3 || id > MAX1586_V6) { + dev_err(&client->dev, "invalid regulator id %d\n", id); + goto err; + } + rdev[i] = regulator_register(&max1586_reg[id], &client->dev, + pdata->subdevs[i].platform_data, + max1586); + if (IS_ERR(rdev[i])) { + ret = PTR_ERR(rdev[i]); + dev_err(&client->dev, "failed to register %s\n", + max1586_reg[id].name); + goto err; + } + } + + i2c_set_clientdata(client, rdev); + dev_info(&client->dev, "Maxim 1586 regulator driver loaded\n"); + return 0; + +err: + while (--i >= 0) + regulator_unregister(rdev[i]); +out_unmap: + kfree(max1586); +out: + return ret; +} + +static int max1586_pmic_remove(struct i2c_client *client) +{ + struct regulator_dev **rdev = i2c_get_clientdata(client); + int i; + + for (i = 0; i <= MAX1586_V6; i++) + if (rdev[i]) + regulator_unregister(rdev[i]); + kfree(rdev); + i2c_set_clientdata(client, NULL); + + return 0; +} + +static const struct i2c_device_id max1586_id[] = { + { "max1586", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, max1586_id); + +static struct i2c_driver max1586_pmic_driver = { + .probe = max1586_pmic_probe, + .remove = max1586_pmic_remove, + .driver = { + .name = "max1586", + }, + .id_table = max1586_id, +}; + +static int __init max1586_pmic_init(void) +{ + return i2c_add_driver(&max1586_pmic_driver); +} +subsys_initcall(max1586_pmic_init); + +static void __exit max1586_pmic_exit(void) +{ + i2c_del_driver(&max1586_pmic_driver); +} +module_exit(max1586_pmic_exit); + +/* Module information */ +MODULE_DESCRIPTION("MAXIM 1586 voltage regulator driver"); +MODULE_AUTHOR("Robert Jarzmik"); +MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/pcf50633-regulator.c b/drivers/regulator/pcf50633-regulator.c index cd761d85c8fd..8e14900eb686 100644 --- a/drivers/regulator/pcf50633-regulator.c +++ b/drivers/regulator/pcf50633-regulator.c @@ -316,7 +316,7 @@ static int __init pcf50633_regulator_init(void) { return platform_driver_register(&pcf50633_regulator_driver); } -module_init(pcf50633_regulator_init); +subsys_initcall(pcf50633_regulator_init); static void __exit pcf50633_regulator_exit(void) { diff --git a/drivers/regulator/userspace-consumer.c b/drivers/regulator/userspace-consumer.c new file mode 100644 index 000000000000..06d2fa96a8b4 --- /dev/null +++ b/drivers/regulator/userspace-consumer.c @@ -0,0 +1,200 @@ +/* + * userspace-consumer.c + * + * Copyright 2009 CompuLab, Ltd. + * + * Author: Mike Rapoport + * + * Based of virtual consumer driver: + * Copyright 2008 Wolfson Microelectronics PLC. + * Author: Mark Brown + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include + +struct userspace_consumer_data { + const char *name; + + struct mutex lock; + bool enabled; + + int num_supplies; + struct regulator_bulk_data *supplies; +}; + +static ssize_t reg_show_name(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct userspace_consumer_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%s\n", data->name); +} + +static ssize_t reg_show_state(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct userspace_consumer_data *data = dev_get_drvdata(dev); + + if (data->enabled) + return sprintf(buf, "enabled\n"); + + return sprintf(buf, "disabled\n"); +} + +static ssize_t reg_set_state(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct userspace_consumer_data *data = dev_get_drvdata(dev); + bool enabled; + int ret; + + /* + * sysfs_streq() doesn't need the \n's, but we add them so the strings + * will be shared with show_state(), above. + */ + if (sysfs_streq(buf, "enabled\n") || sysfs_streq(buf, "1")) + enabled = true; + else if (sysfs_streq(buf, "disabled\n") || sysfs_streq(buf, "0")) + enabled = false; + else { + dev_err(dev, "Configuring invalid mode\n"); + return count; + } + + mutex_lock(&data->lock); + if (enabled != data->enabled) { + if (enabled) + ret = regulator_bulk_enable(data->num_supplies, + data->supplies); + else + ret = regulator_bulk_disable(data->num_supplies, + data->supplies); + + if (ret == 0) + data->enabled = enabled; + else + dev_err(dev, "Failed to configure state: %d\n", ret); + } + mutex_unlock(&data->lock); + + return count; +} + +static DEVICE_ATTR(name, 0444, reg_show_name, NULL); +static DEVICE_ATTR(state, 0644, reg_show_state, reg_set_state); + +static struct device_attribute *attributes[] = { + &dev_attr_name, + &dev_attr_state, +}; + +static int regulator_userspace_consumer_probe(struct platform_device *pdev) +{ + struct regulator_userspace_consumer_data *pdata; + struct userspace_consumer_data *drvdata; + int ret, i; + + pdata = pdev->dev.platform_data; + if (!pdata) + return -EINVAL; + + drvdata = kzalloc(sizeof(struct userspace_consumer_data), GFP_KERNEL); + if (drvdata == NULL) + return -ENOMEM; + + drvdata->name = pdata->name; + drvdata->num_supplies = pdata->num_supplies; + drvdata->supplies = pdata->supplies; + + mutex_init(&drvdata->lock); + + ret = regulator_bulk_get(&pdev->dev, drvdata->num_supplies, + drvdata->supplies); + if (ret) { + dev_err(&pdev->dev, "Failed to get supplies: %d\n", ret); + goto err_alloc_supplies; + } + + for (i = 0; i < ARRAY_SIZE(attributes); i++) { + ret = device_create_file(&pdev->dev, attributes[i]); + if (ret != 0) + goto err_create_attrs; + } + + if (pdata->init_on) + ret = regulator_bulk_enable(drvdata->num_supplies, + drvdata->supplies); + + drvdata->enabled = pdata->init_on; + + if (ret) { + dev_err(&pdev->dev, "Failed to set initial state: %d\n", ret); + goto err_create_attrs; + } + + platform_set_drvdata(pdev, drvdata); + + return 0; + +err_create_attrs: + for (i = 0; i < ARRAY_SIZE(attributes); i++) + device_remove_file(&pdev->dev, attributes[i]); + + regulator_bulk_free(drvdata->num_supplies, drvdata->supplies); + +err_alloc_supplies: + kfree(drvdata); + return ret; +} + +static int regulator_userspace_consumer_remove(struct platform_device *pdev) +{ + struct userspace_consumer_data *data = platform_get_drvdata(pdev); + int i; + + for (i = 0; i < ARRAY_SIZE(attributes); i++) + device_remove_file(&pdev->dev, attributes[i]); + + if (data->enabled) + regulator_bulk_disable(data->num_supplies, data->supplies); + + regulator_bulk_free(data->num_supplies, data->supplies); + kfree(data); + + return 0; +} + +static struct platform_driver regulator_userspace_consumer_driver = { + .probe = regulator_userspace_consumer_probe, + .remove = regulator_userspace_consumer_remove, + .driver = { + .name = "reg-userspace-consumer", + }, +}; + + +static int __init regulator_userspace_consumer_init(void) +{ + return platform_driver_register(®ulator_userspace_consumer_driver); +} +module_init(regulator_userspace_consumer_init); + +static void __exit regulator_userspace_consumer_exit(void) +{ + platform_driver_unregister(®ulator_userspace_consumer_driver); +} +module_exit(regulator_userspace_consumer_exit); + +MODULE_AUTHOR("Mike Rapoport "); +MODULE_DESCRIPTION("Userspace consumer for voltage and current regulators"); +MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/virtual.c b/drivers/regulator/virtual.c index 71403fa3ffa1..e7db5664722e 100644 --- a/drivers/regulator/virtual.c +++ b/drivers/regulator/virtual.c @@ -347,3 +347,4 @@ module_exit(regulator_virtual_consumer_exit); MODULE_AUTHOR("Mark Brown "); MODULE_DESCRIPTION("Virtual regulator consumer"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:reg-virt-consumer"); diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c index 771eca1066b5..17a00b0fafd1 100644 --- a/drivers/regulator/wm8350-regulator.c +++ b/drivers/regulator/wm8350-regulator.c @@ -1570,3 +1570,4 @@ module_exit(wm8350_regulator_exit); MODULE_AUTHOR("Liam Girdwood"); MODULE_DESCRIPTION("WM8350 voltage and current regulator driver"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:wm8350-regulator"); diff --git a/drivers/regulator/wm8400-regulator.c b/drivers/regulator/wm8400-regulator.c index 157426029071..d9a2c988c6e7 100644 --- a/drivers/regulator/wm8400-regulator.c +++ b/drivers/regulator/wm8400-regulator.c @@ -320,7 +320,7 @@ static int __devinit wm8400_regulator_probe(struct platform_device *pdev) struct regulator_dev *rdev; rdev = regulator_register(®ulators[pdev->id], &pdev->dev, - pdev->dev.platform_data, pdev->dev.driver_data); + pdev->dev.platform_data, dev_get_drvdata(&pdev->dev)); if (IS_ERR(rdev)) return PTR_ERR(rdev); @@ -359,7 +359,7 @@ static struct platform_driver wm8400_regulator_driver = { int wm8400_register_regulator(struct device *dev, int reg, struct regulator_init_data *initdata) { - struct wm8400 *wm8400 = dev->driver_data; + struct wm8400 *wm8400 = dev_get_drvdata(dev); if (wm8400->regulators[reg].name) return -EBUSY; @@ -369,8 +369,8 @@ int wm8400_register_regulator(struct device *dev, int reg, wm8400->regulators[reg].name = "wm8400-regulator"; wm8400->regulators[reg].id = reg; wm8400->regulators[reg].dev.parent = dev; - wm8400->regulators[reg].dev.driver_data = wm8400; wm8400->regulators[reg].dev.platform_data = initdata; + dev_set_drvdata(&wm8400->regulators[reg].dev, wm8400); return platform_device_register(&wm8400->regulators[reg]); } @@ -380,7 +380,7 @@ static int __init wm8400_regulator_init(void) { return platform_driver_register(&wm8400_regulator_driver); } -module_init(wm8400_regulator_init); +subsys_initcall(wm8400_regulator_init); static void __exit wm8400_regulator_exit(void) { diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 4e9851fc1746..81adbdbd5042 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -296,6 +296,15 @@ config RTC_DRV_RX8581 This driver can also be built as a module. If so the module will be called rtc-rx8581. +config RTC_DRV_RX8025 + tristate "Epson RX-8025SA/NB" + help + If you say yes here you get support for the Epson + RX-8025SA/NB RTC chips. + + This driver can also be built as a module. If so, the module + will be called rtc-rx8025. + endif # I2C comment "SPI RTC drivers" @@ -692,7 +701,7 @@ config RTC_DRV_GENERIC tristate "Generic RTC support" # Please consider writing a new RTC driver instead of using the generic # RTC abstraction - depends on PARISC || M68K || PPC + depends on PARISC || M68K || PPC || SUPERH32 help Say Y or M here to enable RTC support on systems using the generic RTC abstraction. If you do not know what you are doing, you should diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 6c0639a14f09..3c0f2b2ac927 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -62,6 +62,7 @@ obj-$(CONFIG_RTC_DRV_R9701) += rtc-r9701.o obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o +obj-$(CONFIG_RTC_DRV_RX8025) += rtc-rx8025.o obj-$(CONFIG_RTC_DRV_RX8581) += rtc-rx8581.o obj-$(CONFIG_RTC_DRV_S35390A) += rtc-s35390a.o obj-$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index 4348c4b0d453..4cdb31a362ca 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -371,19 +371,21 @@ EXPORT_SYMBOL_GPL(rtc_update_irq_enable); * @rtc: the rtc device * @num: how many irqs are being reported (usually one) * @events: mask of RTC_IRQF with one or more of RTC_PF, RTC_AF, RTC_UF - * Context: in_interrupt(), irqs blocked + * Context: any */ void rtc_update_irq(struct rtc_device *rtc, unsigned long num, unsigned long events) { - spin_lock(&rtc->irq_lock); - rtc->irq_data = (rtc->irq_data + (num << 8)) | events; - spin_unlock(&rtc->irq_lock); + unsigned long flags; - spin_lock(&rtc->irq_task_lock); + spin_lock_irqsave(&rtc->irq_lock, flags); + rtc->irq_data = (rtc->irq_data + (num << 8)) | events; + spin_unlock_irqrestore(&rtc->irq_lock, flags); + + spin_lock_irqsave(&rtc->irq_task_lock, flags); if (rtc->irq_task) rtc->irq_task->func(rtc->irq_task->private_data); - spin_unlock(&rtc->irq_task_lock); + spin_unlock_irqrestore(&rtc->irq_task_lock, flags); wake_up_interruptible(&rtc->irq_queue); kill_fasync(&rtc->async_queue, SIGIO, POLL_IN); diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c index 45152f4952d6..8a11de9552cd 100644 --- a/drivers/rtc/rtc-dev.c +++ b/drivers/rtc/rtc-dev.c @@ -60,8 +60,7 @@ static void rtc_uie_task(struct work_struct *work) err = rtc_read_time(rtc, &tm); - local_irq_disable(); - spin_lock(&rtc->irq_lock); + spin_lock_irq(&rtc->irq_lock); if (rtc->stop_uie_polling || err) { rtc->uie_task_active = 0; } else if (rtc->oldsecs != tm.tm_sec) { @@ -74,10 +73,9 @@ static void rtc_uie_task(struct work_struct *work) } else if (schedule_work(&rtc->uie_task) == 0) { rtc->uie_task_active = 0; } - spin_unlock(&rtc->irq_lock); + spin_unlock_irq(&rtc->irq_lock); if (num) rtc_update_irq(rtc, num, RTC_UF | RTC_IRQF); - local_irq_enable(); } static void rtc_uie_timer(unsigned long data) { diff --git a/drivers/rtc/rtc-ds1305.c b/drivers/rtc/rtc-ds1305.c index fc372df6534b..8f410e59d9f5 100644 --- a/drivers/rtc/rtc-ds1305.c +++ b/drivers/rtc/rtc-ds1305.c @@ -499,10 +499,7 @@ static void ds1305_work(struct work_struct *work) if (!test_bit(FLAG_EXITING, &ds1305->flags)) enable_irq(spi->irq); - /* rtc_update_irq() requires an IRQ-disabled context */ - local_irq_disable(); rtc_update_irq(ds1305->rtc, 1, RTC_AF | RTC_IRQF); - local_irq_enable(); } /* diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index 2c4a65302a9d..47a93c022d91 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -31,6 +31,8 @@ enum ds_type { ds_1338, ds_1339, ds_1340, + ds_1388, + ds_3231, m41t00, rx_8025, // rs5c372 too? different address... @@ -66,6 +68,7 @@ enum ds_type { #define DS1337_REG_CONTROL 0x0e # define DS1337_BIT_nEOSC 0x80 # define DS1339_BIT_BBSQI 0x20 +# define DS3231_BIT_BBSQW 0x40 /* same as BBSQI */ # define DS1337_BIT_RS2 0x10 # define DS1337_BIT_RS1 0x08 # define DS1337_BIT_INTCN 0x04 @@ -94,6 +97,7 @@ enum ds_type { struct ds1307 { + u8 offset; /* register's offset */ u8 regs[11]; enum ds_type type; unsigned long flags; @@ -128,6 +132,9 @@ static const struct chip_desc chips[] = { }, [ds_1340] = { }, +[ds_3231] = { + .alarm = 1, +}, [m41t00] = { }, [rx_8025] = { @@ -138,7 +145,9 @@ static const struct i2c_device_id ds1307_id[] = { { "ds1337", ds_1337 }, { "ds1338", ds_1338 }, { "ds1339", ds_1339 }, + { "ds1388", ds_1388 }, { "ds1340", ds_1340 }, + { "ds3231", ds_3231 }, { "m41t00", m41t00 }, { "rx8025", rx_8025 }, { } @@ -258,12 +267,7 @@ static void ds1307_work(struct work_struct *work) control &= ~DS1337_BIT_A1IE; i2c_smbus_write_byte_data(client, DS1337_REG_CONTROL, control); - /* rtc_update_irq() assumes that it is called - * from IRQ-disabled context. - */ - local_irq_disable(); rtc_update_irq(ds1307->rtc, 1, RTC_AF | RTC_IRQF); - local_irq_enable(); } out: @@ -291,7 +295,7 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t) /* read the RTC date and time registers all at once */ tmp = ds1307->read_block_data(ds1307->client, - DS1307_REG_SECS, 7, ds1307->regs); + ds1307->offset, 7, ds1307->regs); if (tmp != 7) { dev_err(dev, "%s error %d\n", "read", tmp); return -EIO; @@ -353,6 +357,7 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t) switch (ds1307->type) { case ds_1337: case ds_1339: + case ds_3231: buf[DS1307_REG_MONTH] |= DS1337_BIT_CENTURY; break; case ds_1340: @@ -367,7 +372,8 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t) "write", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); - result = ds1307->write_block_data(ds1307->client, 0, 7, buf); + result = ds1307->write_block_data(ds1307->client, + ds1307->offset, 7, buf); if (result < 0) { dev_err(dev, "%s error %d\n", "write", result); return result; @@ -624,6 +630,11 @@ static int __devinit ds1307_probe(struct i2c_client *client, struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); int want_irq = false; unsigned char *buf; + static const int bbsqi_bitpos[] = { + [ds_1337] = 0, + [ds_1339] = DS1339_BIT_BBSQI, + [ds_3231] = DS3231_BIT_BBSQW, + }; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA) && !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) @@ -632,9 +643,12 @@ static int __devinit ds1307_probe(struct i2c_client *client, if (!(ds1307 = kzalloc(sizeof(struct ds1307), GFP_KERNEL))) return -ENOMEM; - ds1307->client = client; i2c_set_clientdata(client, ds1307); - ds1307->type = id->driver_data; + + ds1307->client = client; + ds1307->type = id->driver_data; + ds1307->offset = 0; + buf = ds1307->regs; if (i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) { ds1307->read_block_data = i2c_smbus_read_i2c_block_data; @@ -647,6 +661,7 @@ static int __devinit ds1307_probe(struct i2c_client *client, switch (ds1307->type) { case ds_1337: case ds_1339: + case ds_3231: /* has IRQ? */ if (ds1307->client->irq > 0 && chip->alarm) { INIT_WORK(&ds1307->work, ds1307_work); @@ -666,12 +681,12 @@ static int __devinit ds1307_probe(struct i2c_client *client, ds1307->regs[0] &= ~DS1337_BIT_nEOSC; /* Using IRQ? Disable the square wave and both alarms. - * For ds1339, be sure alarms can trigger when we're - * running on Vbackup (BBSQI); we assume ds1337 will - * ignore that bit + * For some variants, be sure alarms can trigger when we're + * running on Vbackup (BBSQI/BBSQW) */ if (want_irq) { - ds1307->regs[0] |= DS1337_BIT_INTCN | DS1339_BIT_BBSQI; + ds1307->regs[0] |= DS1337_BIT_INTCN + | bbsqi_bitpos[ds1307->type]; ds1307->regs[0] &= ~(DS1337_BIT_A2IE | DS1337_BIT_A1IE); } @@ -751,6 +766,9 @@ static int __devinit ds1307_probe(struct i2c_client *client, hour); } break; + case ds_1388: + ds1307->offset = 1; /* Seconds starts at 1 */ + break; default: break; } @@ -814,6 +832,8 @@ read_rtc: case rx_8025: case ds_1337: case ds_1339: + case ds_1388: + case ds_3231: break; } diff --git a/drivers/rtc/rtc-ds1374.c b/drivers/rtc/rtc-ds1374.c index 4d32e328f6cd..32b27739ec2a 100644 --- a/drivers/rtc/rtc-ds1374.c +++ b/drivers/rtc/rtc-ds1374.c @@ -296,12 +296,7 @@ static void ds1374_work(struct work_struct *work) control &= ~(DS1374_REG_CR_WACE | DS1374_REG_CR_AIE); i2c_smbus_write_byte_data(client, DS1374_REG_CR, control); - /* rtc_update_irq() assumes that it is called - * from IRQ-disabled context. - */ - local_irq_disable(); rtc_update_irq(ds1374->rtc, 1, RTC_AF | RTC_IRQF); - local_irq_enable(); } out: diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c index 38d472b63406..717288527c6b 100644 --- a/drivers/rtc/rtc-ds1553.c +++ b/drivers/rtc/rtc-ds1553.c @@ -329,8 +329,7 @@ static int __devinit ds1553_rtc_probe(struct platform_device *pdev) if (pdata->irq > 0) { writeb(0, ioaddr + RTC_INTERRUPTS); if (request_irq(pdata->irq, ds1553_rtc_interrupt, - IRQF_DISABLED | IRQF_SHARED, - pdev->name, pdev) < 0) { + IRQF_DISABLED, pdev->name, pdev) < 0) { dev_warn(&pdev->dev, "interrupt not available.\n"); pdata->irq = 0; } diff --git a/drivers/rtc/rtc-ds1742.c b/drivers/rtc/rtc-ds1742.c index 8bc8501bffc8..09249459e9a4 100644 --- a/drivers/rtc/rtc-ds1742.c +++ b/drivers/rtc/rtc-ds1742.c @@ -57,6 +57,7 @@ struct rtc_plat_data { size_t size; resource_size_t baseaddr; unsigned long last_jiffies; + struct bin_attribute nvram_attr; }; static int ds1742_rtc_set_time(struct device *dev, struct rtc_time *tm) @@ -157,18 +158,6 @@ static ssize_t ds1742_nvram_write(struct kobject *kobj, return count; } -static struct bin_attribute ds1742_nvram_attr = { - .attr = { - .name = "nvram", - .mode = S_IRUGO | S_IWUSR, - }, - .read = ds1742_nvram_read, - .write = ds1742_nvram_write, - /* REVISIT: size in sysfs won't match actual size... if it's - * not a constant, each RTC should have its own attribute. - */ -}; - static int __devinit ds1742_rtc_probe(struct platform_device *pdev) { struct rtc_device *rtc; @@ -199,6 +188,12 @@ static int __devinit ds1742_rtc_probe(struct platform_device *pdev) pdata->size_nvram = pdata->size - RTC_SIZE; pdata->ioaddr_rtc = ioaddr + pdata->size_nvram; + pdata->nvram_attr.attr.name = "nvram"; + pdata->nvram_attr.attr.mode = S_IRUGO | S_IWUSR; + pdata->nvram_attr.read = ds1742_nvram_read; + pdata->nvram_attr.write = ds1742_nvram_write; + pdata->nvram_attr.size = pdata->size_nvram; + /* turn RTC on if it was not on */ ioaddr = pdata->ioaddr_rtc; sec = readb(ioaddr + RTC_SECONDS); @@ -221,11 +216,13 @@ static int __devinit ds1742_rtc_probe(struct platform_device *pdev) pdata->rtc = rtc; pdata->last_jiffies = jiffies; platform_set_drvdata(pdev, pdata); - ds1742_nvram_attr.size = max(ds1742_nvram_attr.size, - pdata->size_nvram); - ret = sysfs_create_bin_file(&pdev->dev.kobj, &ds1742_nvram_attr); - if (ret) + + ret = sysfs_create_bin_file(&pdev->dev.kobj, &pdata->nvram_attr); + if (ret) { + dev_err(&pdev->dev, "creating nvram file in sysfs failed\n"); goto out; + } + return 0; out: if (pdata->rtc) @@ -242,7 +239,7 @@ static int __devexit ds1742_rtc_remove(struct platform_device *pdev) { struct rtc_plat_data *pdata = platform_get_drvdata(pdev); - sysfs_remove_bin_file(&pdev->dev.kobj, &ds1742_nvram_attr); + sysfs_remove_bin_file(&pdev->dev.kobj, &pdata->nvram_attr); rtc_device_unregister(pdata->rtc); iounmap(pdata->ioaddr_nvram); release_mem_region(pdata->baseaddr, pdata->size); diff --git a/drivers/rtc/rtc-ep93xx.c b/drivers/rtc/rtc-ep93xx.c index f7a3283dd029..551332e4ed02 100644 --- a/drivers/rtc/rtc-ep93xx.c +++ b/drivers/rtc/rtc-ep93xx.c @@ -12,32 +12,56 @@ #include #include #include -#include +#include -#define EP93XX_RTC_REG(x) (EP93XX_RTC_BASE + (x)) -#define EP93XX_RTC_DATA EP93XX_RTC_REG(0x0000) -#define EP93XX_RTC_LOAD EP93XX_RTC_REG(0x000C) -#define EP93XX_RTC_SWCOMP EP93XX_RTC_REG(0x0108) +#define EP93XX_RTC_DATA 0x000 +#define EP93XX_RTC_MATCH 0x004 +#define EP93XX_RTC_STATUS 0x008 +#define EP93XX_RTC_STATUS_INTR (1<<0) +#define EP93XX_RTC_LOAD 0x00C +#define EP93XX_RTC_CONTROL 0x010 +#define EP93XX_RTC_CONTROL_MIE (1<<0) +#define EP93XX_RTC_SWCOMP 0x108 +#define EP93XX_RTC_SWCOMP_DEL_MASK 0x001f0000 +#define EP93XX_RTC_SWCOMP_DEL_SHIFT 16 +#define EP93XX_RTC_SWCOMP_INT_MASK 0x0000ffff +#define EP93XX_RTC_SWCOMP_INT_SHIFT 0 -#define DRV_VERSION "0.2" +#define DRV_VERSION "0.3" -static int ep93xx_get_swcomp(struct device *dev, unsigned short *preload, +/* + * struct device dev.platform_data is used to store our private data + * because struct rtc_device does not have a variable to hold it. + */ +struct ep93xx_rtc { + void __iomem *mmio_base; +}; + +static int ep93xx_rtc_get_swcomp(struct device *dev, unsigned short *preload, unsigned short *delete) { - unsigned short comp = __raw_readl(EP93XX_RTC_SWCOMP); + struct ep93xx_rtc *ep93xx_rtc = dev->platform_data; + unsigned long comp; + + comp = __raw_readl(ep93xx_rtc->mmio_base + EP93XX_RTC_SWCOMP); if (preload) - *preload = comp & 0xffff; + *preload = (comp & EP93XX_RTC_SWCOMP_INT_MASK) + >> EP93XX_RTC_SWCOMP_INT_SHIFT; if (delete) - *delete = (comp >> 16) & 0x1f; + *delete = (comp & EP93XX_RTC_SWCOMP_DEL_MASK) + >> EP93XX_RTC_SWCOMP_DEL_SHIFT; return 0; } static int ep93xx_rtc_read_time(struct device *dev, struct rtc_time *tm) { - unsigned long time = __raw_readl(EP93XX_RTC_DATA); + struct ep93xx_rtc *ep93xx_rtc = dev->platform_data; + unsigned long time; + + time = __raw_readl(ep93xx_rtc->mmio_base + EP93XX_RTC_DATA); rtc_time_to_tm(time, tm); return 0; @@ -45,7 +69,9 @@ static int ep93xx_rtc_read_time(struct device *dev, struct rtc_time *tm) static int ep93xx_rtc_set_mmss(struct device *dev, unsigned long secs) { - __raw_writel(secs + 1, EP93XX_RTC_LOAD); + struct ep93xx_rtc *ep93xx_rtc = dev->platform_data; + + __raw_writel(secs + 1, ep93xx_rtc->mmio_base + EP93XX_RTC_LOAD); return 0; } @@ -53,7 +79,7 @@ static int ep93xx_rtc_proc(struct device *dev, struct seq_file *seq) { unsigned short preload, delete; - ep93xx_get_swcomp(dev, &preload, &delete); + ep93xx_rtc_get_swcomp(dev, &preload, &delete); seq_printf(seq, "preload\t\t: %d\n", preload); seq_printf(seq, "delete\t\t: %d\n", delete); @@ -67,54 +93,104 @@ static const struct rtc_class_ops ep93xx_rtc_ops = { .proc = ep93xx_rtc_proc, }; -static ssize_t ep93xx_sysfs_show_comp_preload(struct device *dev, +static ssize_t ep93xx_rtc_show_comp_preload(struct device *dev, struct device_attribute *attr, char *buf) { unsigned short preload; - ep93xx_get_swcomp(dev, &preload, NULL); + ep93xx_rtc_get_swcomp(dev, &preload, NULL); return sprintf(buf, "%d\n", preload); } -static DEVICE_ATTR(comp_preload, S_IRUGO, ep93xx_sysfs_show_comp_preload, NULL); +static DEVICE_ATTR(comp_preload, S_IRUGO, ep93xx_rtc_show_comp_preload, NULL); -static ssize_t ep93xx_sysfs_show_comp_delete(struct device *dev, +static ssize_t ep93xx_rtc_show_comp_delete(struct device *dev, struct device_attribute *attr, char *buf) { unsigned short delete; - ep93xx_get_swcomp(dev, NULL, &delete); + ep93xx_rtc_get_swcomp(dev, NULL, &delete); return sprintf(buf, "%d\n", delete); } -static DEVICE_ATTR(comp_delete, S_IRUGO, ep93xx_sysfs_show_comp_delete, NULL); +static DEVICE_ATTR(comp_delete, S_IRUGO, ep93xx_rtc_show_comp_delete, NULL); -static int __devinit ep93xx_rtc_probe(struct platform_device *dev) +static int __init ep93xx_rtc_probe(struct platform_device *pdev) { - struct rtc_device *rtc = rtc_device_register("ep93xx", - &dev->dev, &ep93xx_rtc_ops, THIS_MODULE); + struct ep93xx_rtc *ep93xx_rtc; + struct resource *res; + struct rtc_device *rtc; + int err; - if (IS_ERR(rtc)) { - return PTR_ERR(rtc); + ep93xx_rtc = kzalloc(sizeof(struct ep93xx_rtc), GFP_KERNEL); + if (ep93xx_rtc == NULL) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) + return -ENXIO; + + res = request_mem_region(res->start, resource_size(res), pdev->name); + if (res == NULL) + return -EBUSY; + + ep93xx_rtc->mmio_base = ioremap(res->start, resource_size(res)); + if (ep93xx_rtc->mmio_base == NULL) { + err = -ENXIO; + goto fail; } - platform_set_drvdata(dev, rtc); + pdev->dev.platform_data = ep93xx_rtc; - device_create_file(&dev->dev, &dev_attr_comp_preload); - device_create_file(&dev->dev, &dev_attr_comp_delete); + rtc = rtc_device_register(pdev->name, + &pdev->dev, &ep93xx_rtc_ops, THIS_MODULE); + if (IS_ERR(rtc)) { + err = PTR_ERR(rtc); + goto fail; + } + + platform_set_drvdata(pdev, rtc); + + err = device_create_file(&pdev->dev, &dev_attr_comp_preload); + if (err) + goto fail; + err = device_create_file(&pdev->dev, &dev_attr_comp_delete); + if (err) { + device_remove_file(&pdev->dev, &dev_attr_comp_preload); + goto fail; + } return 0; + +fail: + if (ep93xx_rtc->mmio_base) { + iounmap(ep93xx_rtc->mmio_base); + pdev->dev.platform_data = NULL; + } + release_mem_region(res->start, resource_size(res)); + return err; } -static int __devexit ep93xx_rtc_remove(struct platform_device *dev) +static int __exit ep93xx_rtc_remove(struct platform_device *pdev) { - struct rtc_device *rtc = platform_get_drvdata(dev); + struct rtc_device *rtc = platform_get_drvdata(pdev); + struct ep93xx_rtc *ep93xx_rtc = pdev->dev.platform_data; + struct resource *res; - if (rtc) - rtc_device_unregister(rtc); + /* cleanup sysfs */ + device_remove_file(&pdev->dev, &dev_attr_comp_delete); + device_remove_file(&pdev->dev, &dev_attr_comp_preload); - platform_set_drvdata(dev, NULL); + rtc_device_unregister(rtc); + + iounmap(ep93xx_rtc->mmio_base); + pdev->dev.platform_data = NULL; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(res->start, resource_size(res)); + + platform_set_drvdata(pdev, NULL); return 0; } @@ -122,23 +198,22 @@ static int __devexit ep93xx_rtc_remove(struct platform_device *dev) /* work with hotplug and coldplug */ MODULE_ALIAS("platform:ep93xx-rtc"); -static struct platform_driver ep93xx_rtc_platform_driver = { +static struct platform_driver ep93xx_rtc_driver = { .driver = { .name = "ep93xx-rtc", .owner = THIS_MODULE, }, - .probe = ep93xx_rtc_probe, - .remove = __devexit_p(ep93xx_rtc_remove), + .remove = __exit_p(ep93xx_rtc_remove), }; static int __init ep93xx_rtc_init(void) { - return platform_driver_register(&ep93xx_rtc_platform_driver); + return platform_driver_probe(&ep93xx_rtc_driver, ep93xx_rtc_probe); } static void __exit ep93xx_rtc_exit(void) { - platform_driver_unregister(&ep93xx_rtc_platform_driver); + platform_driver_unregister(&ep93xx_rtc_driver); } MODULE_AUTHOR("Alessandro Zummo "); diff --git a/drivers/rtc/rtc-pl030.c b/drivers/rtc/rtc-pl030.c index aaf1f75fa293..457231bb1029 100644 --- a/drivers/rtc/rtc-pl030.c +++ b/drivers/rtc/rtc-pl030.c @@ -117,7 +117,7 @@ static int pl030_probe(struct amba_device *dev, struct amba_id *id) goto err_rtc; } - rtc->base = ioremap(dev->res.start, SZ_4K); + rtc->base = ioremap(dev->res.start, resource_size(&dev->res)); if (!rtc->base) { ret = -ENOMEM; goto err_map; diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c index 451fc13784d1..f41873f98f66 100644 --- a/drivers/rtc/rtc-pl031.c +++ b/drivers/rtc/rtc-pl031.c @@ -142,8 +142,7 @@ static int pl031_probe(struct amba_device *adev, struct amba_id *id) goto out; } - ldata->base = ioremap(adev->res.start, - adev->res.end - adev->res.start + 1); + ldata->base = ioremap(adev->res.start, resource_size(&adev->res)); if (!ldata->base) { ret = -ENOMEM; goto out_no_remap; diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c new file mode 100644 index 000000000000..b1a29bcfdf13 --- /dev/null +++ b/drivers/rtc/rtc-rx8025.c @@ -0,0 +1,688 @@ +/* + * Driver for Epson's RTC module RX-8025 SA/NB + * + * Copyright (C) 2009 Wolfgang Grandegger + * + * Copyright (C) 2005 by Digi International Inc. + * All rights reserved. + * + * Modified by fengjh at rising.com.cn + * + * 2006.11 + * + * Code cleanup by Sergei Poselenov, + * Converted to new style by Wolfgang Grandegger + * Alarm and periodic interrupt added by Dmitry Rakhchev + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include + +/* Register definitions */ +#define RX8025_REG_SEC 0x00 +#define RX8025_REG_MIN 0x01 +#define RX8025_REG_HOUR 0x02 +#define RX8025_REG_WDAY 0x03 +#define RX8025_REG_MDAY 0x04 +#define RX8025_REG_MONTH 0x05 +#define RX8025_REG_YEAR 0x06 +#define RX8025_REG_DIGOFF 0x07 +#define RX8025_REG_ALWMIN 0x08 +#define RX8025_REG_ALWHOUR 0x09 +#define RX8025_REG_ALWWDAY 0x0a +#define RX8025_REG_ALDMIN 0x0b +#define RX8025_REG_ALDHOUR 0x0c +/* 0x0d is reserved */ +#define RX8025_REG_CTRL1 0x0e +#define RX8025_REG_CTRL2 0x0f + +#define RX8025_BIT_CTRL1_CT (7 << 0) +/* 1 Hz periodic level irq */ +#define RX8025_BIT_CTRL1_CT_1HZ 4 +#define RX8025_BIT_CTRL1_TEST (1 << 3) +#define RX8025_BIT_CTRL1_1224 (1 << 5) +#define RX8025_BIT_CTRL1_DALE (1 << 6) +#define RX8025_BIT_CTRL1_WALE (1 << 7) + +#define RX8025_BIT_CTRL2_DAFG (1 << 0) +#define RX8025_BIT_CTRL2_WAFG (1 << 1) +#define RX8025_BIT_CTRL2_CTFG (1 << 2) +#define RX8025_BIT_CTRL2_PON (1 << 4) +#define RX8025_BIT_CTRL2_XST (1 << 5) +#define RX8025_BIT_CTRL2_VDET (1 << 6) + +/* Clock precision adjustment */ +#define RX8025_ADJ_RESOLUTION 3050 /* in ppb */ +#define RX8025_ADJ_DATA_MAX 62 +#define RX8025_ADJ_DATA_MIN -62 + +static const struct i2c_device_id rx8025_id[] = { + { "rx8025", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, rx8025_id); + +struct rx8025_data { + struct i2c_client *client; + struct rtc_device *rtc; + struct work_struct work; + u8 ctrl1; + unsigned exiting:1; +}; + +static int rx8025_read_reg(struct i2c_client *client, int number, u8 *value) +{ + int ret = i2c_smbus_read_byte_data(client, (number << 4) | 0x08); + + if (ret < 0) { + dev_err(&client->dev, "Unable to read register #%d\n", number); + return ret; + } + + *value = ret; + return 0; +} + +static int rx8025_read_regs(struct i2c_client *client, + int number, u8 length, u8 *values) +{ + int ret = i2c_smbus_read_i2c_block_data(client, (number << 4) | 0x08, + length, values); + + if (ret != length) { + dev_err(&client->dev, "Unable to read registers #%d..#%d\n", + number, number + length - 1); + return ret < 0 ? ret : -EIO; + } + + return 0; +} + +static int rx8025_write_reg(struct i2c_client *client, int number, u8 value) +{ + int ret = i2c_smbus_write_byte_data(client, number << 4, value); + + if (ret) + dev_err(&client->dev, "Unable to write register #%d\n", + number); + + return ret; +} + +static int rx8025_write_regs(struct i2c_client *client, + int number, u8 length, u8 *values) +{ + int ret = i2c_smbus_write_i2c_block_data(client, (number << 4) | 0x08, + length, values); + + if (ret) + dev_err(&client->dev, "Unable to write registers #%d..#%d\n", + number, number + length - 1); + + return ret; +} + +static irqreturn_t rx8025_irq(int irq, void *dev_id) +{ + struct i2c_client *client = dev_id; + struct rx8025_data *rx8025 = i2c_get_clientdata(client); + + disable_irq_nosync(irq); + schedule_work(&rx8025->work); + return IRQ_HANDLED; +} + +static void rx8025_work(struct work_struct *work) +{ + struct rx8025_data *rx8025 = container_of(work, struct rx8025_data, + work); + struct i2c_client *client = rx8025->client; + struct mutex *lock = &rx8025->rtc->ops_lock; + u8 status; + + mutex_lock(lock); + + if (rx8025_read_reg(client, RX8025_REG_CTRL2, &status)) + goto out; + + if (!(status & RX8025_BIT_CTRL2_XST)) + dev_warn(&client->dev, "Oscillation stop was detected," + "you may have to readjust the clock\n"); + + if (status & RX8025_BIT_CTRL2_CTFG) { + /* periodic */ + status &= ~RX8025_BIT_CTRL2_CTFG; + local_irq_disable(); + rtc_update_irq(rx8025->rtc, 1, RTC_PF | RTC_IRQF); + local_irq_enable(); + } + + if (status & RX8025_BIT_CTRL2_DAFG) { + /* alarm */ + status &= RX8025_BIT_CTRL2_DAFG; + if (rx8025_write_reg(client, RX8025_REG_CTRL1, + rx8025->ctrl1 & ~RX8025_BIT_CTRL1_DALE)) + goto out; + local_irq_disable(); + rtc_update_irq(rx8025->rtc, 1, RTC_AF | RTC_IRQF); + local_irq_enable(); + } + + /* acknowledge IRQ */ + rx8025_write_reg(client, RX8025_REG_CTRL2, + status | RX8025_BIT_CTRL2_XST); + +out: + if (!rx8025->exiting) + enable_irq(client->irq); + + mutex_unlock(lock); +} + +static int rx8025_get_time(struct device *dev, struct rtc_time *dt) +{ + struct rx8025_data *rx8025 = dev_get_drvdata(dev); + u8 date[7]; + int err; + + err = rx8025_read_regs(rx8025->client, RX8025_REG_SEC, 7, date); + if (err) + return err; + + dev_dbg(dev, "%s: read 0x%02x 0x%02x " + "0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", __func__, + date[0], date[1], date[2], date[3], date[4], + date[5], date[6]); + + dt->tm_sec = bcd2bin(date[RX8025_REG_SEC] & 0x7f); + dt->tm_min = bcd2bin(date[RX8025_REG_MIN] & 0x7f); + if (rx8025->ctrl1 & RX8025_BIT_CTRL1_1224) + dt->tm_hour = bcd2bin(date[RX8025_REG_HOUR] & 0x3f); + else + dt->tm_hour = bcd2bin(date[RX8025_REG_HOUR] & 0x1f) % 12 + + (date[RX8025_REG_HOUR] & 0x20 ? 12 : 0); + + dt->tm_mday = bcd2bin(date[RX8025_REG_MDAY] & 0x3f); + dt->tm_mon = bcd2bin(date[RX8025_REG_MONTH] & 0x1f) - 1; + dt->tm_year = bcd2bin(date[RX8025_REG_YEAR]); + + if (dt->tm_year < 70) + dt->tm_year += 100; + + dev_dbg(dev, "%s: date %ds %dm %dh %dmd %dm %dy\n", __func__, + dt->tm_sec, dt->tm_min, dt->tm_hour, + dt->tm_mday, dt->tm_mon, dt->tm_year); + + return rtc_valid_tm(dt); +} + +static int rx8025_set_time(struct device *dev, struct rtc_time *dt) +{ + struct rx8025_data *rx8025 = dev_get_drvdata(dev); + u8 date[7]; + + /* + * BUG: The HW assumes every year that is a multiple of 4 to be a leap + * year. Next time this is wrong is 2100, which will not be a leap + * year. + */ + + /* + * Here the read-only bits are written as "0". I'm not sure if that + * is sound. + */ + date[RX8025_REG_SEC] = bin2bcd(dt->tm_sec); + date[RX8025_REG_MIN] = bin2bcd(dt->tm_min); + if (rx8025->ctrl1 & RX8025_BIT_CTRL1_1224) + date[RX8025_REG_HOUR] = bin2bcd(dt->tm_hour); + else + date[RX8025_REG_HOUR] = (dt->tm_hour >= 12 ? 0x20 : 0) + | bin2bcd((dt->tm_hour + 11) % 12 + 1); + + date[RX8025_REG_WDAY] = bin2bcd(dt->tm_wday); + date[RX8025_REG_MDAY] = bin2bcd(dt->tm_mday); + date[RX8025_REG_MONTH] = bin2bcd(dt->tm_mon + 1); + date[RX8025_REG_YEAR] = bin2bcd(dt->tm_year % 100); + + dev_dbg(dev, + "%s: write 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", + __func__, + date[0], date[1], date[2], date[3], date[4], date[5], date[6]); + + return rx8025_write_regs(rx8025->client, RX8025_REG_SEC, 7, date); +} + +static int rx8025_init_client(struct i2c_client *client, int *need_reset) +{ + struct rx8025_data *rx8025 = i2c_get_clientdata(client); + u8 ctrl[2], ctrl2; + int need_clear = 0; + int err; + + err = rx8025_read_regs(rx8025->client, RX8025_REG_CTRL1, 2, ctrl); + if (err) + goto out; + + /* Keep test bit zero ! */ + rx8025->ctrl1 = ctrl[0] & ~RX8025_BIT_CTRL1_TEST; + + if (ctrl[1] & RX8025_BIT_CTRL2_PON) { + dev_warn(&client->dev, "power-on reset was detected, " + "you may have to readjust the clock\n"); + *need_reset = 1; + } + + if (ctrl[1] & RX8025_BIT_CTRL2_VDET) { + dev_warn(&client->dev, "a power voltage drop was detected, " + "you may have to readjust the clock\n"); + *need_reset = 1; + } + + if (!(ctrl[1] & RX8025_BIT_CTRL2_XST)) { + dev_warn(&client->dev, "Oscillation stop was detected," + "you may have to readjust the clock\n"); + *need_reset = 1; + } + + if (ctrl[1] & (RX8025_BIT_CTRL2_DAFG | RX8025_BIT_CTRL2_WAFG)) { + dev_warn(&client->dev, "Alarm was detected\n"); + need_clear = 1; + } + + if (!(ctrl[1] & RX8025_BIT_CTRL2_CTFG)) + need_clear = 1; + + if (*need_reset || need_clear) { + ctrl2 = ctrl[0]; + ctrl2 &= ~(RX8025_BIT_CTRL2_PON | RX8025_BIT_CTRL2_VDET | + RX8025_BIT_CTRL2_CTFG | RX8025_BIT_CTRL2_WAFG | + RX8025_BIT_CTRL2_DAFG); + ctrl2 |= RX8025_BIT_CTRL2_XST; + + err = rx8025_write_reg(client, RX8025_REG_CTRL2, ctrl2); + } +out: + return err; +} + +/* Alarm support */ +static int rx8025_read_alarm(struct device *dev, struct rtc_wkalrm *t) +{ + struct rx8025_data *rx8025 = dev_get_drvdata(dev); + struct i2c_client *client = rx8025->client; + u8 ctrl2, ald[2]; + int err; + + if (client->irq <= 0) + return -EINVAL; + + err = rx8025_read_regs(client, RX8025_REG_ALDMIN, 2, ald); + if (err) + return err; + + err = rx8025_read_reg(client, RX8025_REG_CTRL2, &ctrl2); + if (err) + return err; + + dev_dbg(dev, "%s: read alarm 0x%02x 0x%02x ctrl2 %02x\n", + __func__, ald[0], ald[1], ctrl2); + + /* Hardware alarms precision is 1 minute! */ + t->time.tm_sec = 0; + t->time.tm_min = bcd2bin(ald[0] & 0x7f); + if (rx8025->ctrl1 & RX8025_BIT_CTRL1_1224) + t->time.tm_hour = bcd2bin(ald[1] & 0x3f); + else + t->time.tm_hour = bcd2bin(ald[1] & 0x1f) % 12 + + (ald[1] & 0x20 ? 12 : 0); + + t->time.tm_wday = -1; + t->time.tm_mday = -1; + t->time.tm_mon = -1; + t->time.tm_year = -1; + + dev_dbg(dev, "%s: date: %ds %dm %dh %dmd %dm %dy\n", + __func__, + t->time.tm_sec, t->time.tm_min, t->time.tm_hour, + t->time.tm_mday, t->time.tm_mon, t->time.tm_year); + t->enabled = !!(rx8025->ctrl1 & RX8025_BIT_CTRL1_DALE); + t->pending = (ctrl2 & RX8025_BIT_CTRL2_DAFG) && t->enabled; + + return err; +} + +static int rx8025_set_alarm(struct device *dev, struct rtc_wkalrm *t) +{ + struct i2c_client *client = to_i2c_client(dev); + struct rx8025_data *rx8025 = dev_get_drvdata(dev); + u8 ald[2]; + int err; + + if (client->irq <= 0) + return -EINVAL; + + /* Hardware alarm precision is 1 minute! */ + ald[0] = bin2bcd(t->time.tm_min); + if (rx8025->ctrl1 & RX8025_BIT_CTRL1_1224) + ald[1] = bin2bcd(t->time.tm_hour); + else + ald[1] = (t->time.tm_hour >= 12 ? 0x20 : 0) + | bin2bcd((t->time.tm_hour + 11) % 12 + 1); + + dev_dbg(dev, "%s: write 0x%02x 0x%02x\n", __func__, ald[0], ald[1]); + + if (rx8025->ctrl1 & RX8025_BIT_CTRL1_DALE) { + rx8025->ctrl1 &= ~RX8025_BIT_CTRL1_DALE; + err = rx8025_write_reg(rx8025->client, RX8025_REG_CTRL1, + rx8025->ctrl1); + if (err) + return err; + } + err = rx8025_write_regs(rx8025->client, RX8025_REG_ALDMIN, 2, ald); + if (err) + return err; + + if (t->enabled) { + rx8025->ctrl1 |= RX8025_BIT_CTRL1_DALE; + err = rx8025_write_reg(rx8025->client, RX8025_REG_CTRL1, + rx8025->ctrl1); + if (err) + return err; + } + + return 0; +} + +static int rx8025_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ + struct rx8025_data *rx8025 = dev_get_drvdata(dev); + u8 ctrl1; + int err; + + ctrl1 = rx8025->ctrl1; + if (enabled) + ctrl1 |= RX8025_BIT_CTRL1_DALE; + else + ctrl1 &= ~RX8025_BIT_CTRL1_DALE; + + if (ctrl1 != rx8025->ctrl1) { + rx8025->ctrl1 = ctrl1; + err = rx8025_write_reg(rx8025->client, RX8025_REG_CTRL1, + rx8025->ctrl1); + if (err) + return err; + } + return 0; +} + +static int rx8025_irq_set_state(struct device *dev, int enabled) +{ + struct i2c_client *client = to_i2c_client(dev); + struct rx8025_data *rx8025 = i2c_get_clientdata(client); + int ctrl1; + int err; + + if (client->irq <= 0) + return -ENXIO; + + ctrl1 = rx8025->ctrl1 & ~RX8025_BIT_CTRL1_CT; + if (enabled) + ctrl1 |= RX8025_BIT_CTRL1_CT_1HZ; + if (ctrl1 != rx8025->ctrl1) { + rx8025->ctrl1 = ctrl1; + err = rx8025_write_reg(rx8025->client, RX8025_REG_CTRL1, + rx8025->ctrl1); + if (err) + return err; + } + + return 0; +} + +static struct rtc_class_ops rx8025_rtc_ops = { + .read_time = rx8025_get_time, + .set_time = rx8025_set_time, + .read_alarm = rx8025_read_alarm, + .set_alarm = rx8025_set_alarm, + .alarm_irq_enable = rx8025_alarm_irq_enable, + .irq_set_state = rx8025_irq_set_state, +}; + +/* + * Clock precision adjustment support + * + * According to the RX8025 SA/NB application manual the frequency and + * temperature charateristics can be approximated using the following + * equation: + * + * df = a * (ut - t)**2 + * + * df: Frequency deviation in any temperature + * a : Coefficient = (-35 +-5) * 10**-9 + * ut: Ultimate temperature in degree = +25 +-5 degree + * t : Any temperature in degree + * + * Note that the clock adjustment in ppb must be entered (which is + * the negative value of the deviation). + */ +static int rx8025_get_clock_adjust(struct device *dev, int *adj) +{ + struct i2c_client *client = to_i2c_client(dev); + u8 digoff; + int err; + + err = rx8025_read_reg(client, RX8025_REG_DIGOFF, &digoff); + if (err) + return err; + + *adj = digoff >= 64 ? digoff - 128 : digoff; + if (*adj > 0) + (*adj)--; + *adj *= -RX8025_ADJ_RESOLUTION; + + return 0; +} + +static int rx8025_set_clock_adjust(struct device *dev, int adj) +{ + struct i2c_client *client = to_i2c_client(dev); + u8 digoff; + int err; + + adj /= -RX8025_ADJ_RESOLUTION; + if (adj > RX8025_ADJ_DATA_MAX) + adj = RX8025_ADJ_DATA_MAX; + else if (adj < RX8025_ADJ_DATA_MIN) + adj = RX8025_ADJ_DATA_MIN; + else if (adj > 0) + adj++; + else if (adj < 0) + adj += 128; + digoff = adj; + + err = rx8025_write_reg(client, RX8025_REG_DIGOFF, digoff); + if (err) + return err; + + dev_dbg(dev, "%s: write 0x%02x\n", __func__, digoff); + + return 0; +} + +static ssize_t rx8025_sysfs_show_clock_adjust(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int err, adj; + + err = rx8025_get_clock_adjust(dev, &adj); + if (err) + return err; + + return sprintf(buf, "%d\n", adj); +} + +static ssize_t rx8025_sysfs_store_clock_adjust(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int adj, err; + + if (sscanf(buf, "%i", &adj) != 1) + return -EINVAL; + + err = rx8025_set_clock_adjust(dev, adj); + + return err ? err : count; +} + +static DEVICE_ATTR(clock_adjust_ppb, S_IRUGO | S_IWUSR, + rx8025_sysfs_show_clock_adjust, + rx8025_sysfs_store_clock_adjust); + +static int rx8025_sysfs_register(struct device *dev) +{ + return device_create_file(dev, &dev_attr_clock_adjust_ppb); +} + +static void rx8025_sysfs_unregister(struct device *dev) +{ + device_remove_file(dev, &dev_attr_clock_adjust_ppb); +} + +static int __devinit rx8025_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct rx8025_data *rx8025; + int err, need_reset = 0; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA + | I2C_FUNC_SMBUS_I2C_BLOCK)) { + dev_err(&adapter->dev, + "doesn't support required functionality\n"); + err = -EIO; + goto errout; + } + + rx8025 = kzalloc(sizeof(*rx8025), GFP_KERNEL); + if (!rx8025) { + dev_err(&adapter->dev, "failed to alloc memory\n"); + err = -ENOMEM; + goto errout; + } + + rx8025->client = client; + i2c_set_clientdata(client, rx8025); + INIT_WORK(&rx8025->work, rx8025_work); + + err = rx8025_init_client(client, &need_reset); + if (err) + goto errout_free; + + if (need_reset) { + struct rtc_time tm; + dev_info(&client->dev, + "bad conditions detected, resetting date\n"); + rtc_time_to_tm(0, &tm); /* 1970/1/1 */ + rx8025_set_time(&client->dev, &tm); + } + + rx8025->rtc = rtc_device_register(client->name, &client->dev, + &rx8025_rtc_ops, THIS_MODULE); + if (IS_ERR(rx8025->rtc)) { + err = PTR_ERR(rx8025->rtc); + dev_err(&client->dev, "unable to register the class device\n"); + goto errout_free; + } + + if (client->irq > 0) { + dev_info(&client->dev, "IRQ %d supplied\n", client->irq); + err = request_irq(client->irq, rx8025_irq, + 0, "rx8025", client); + if (err) { + dev_err(&client->dev, "unable to request IRQ\n"); + goto errout_reg; + } + } + + rx8025->rtc->irq_freq = 1; + rx8025->rtc->max_user_freq = 1; + + err = rx8025_sysfs_register(&client->dev); + if (err) + goto errout_irq; + + return 0; + +errout_irq: + if (client->irq > 0) + free_irq(client->irq, client); + +errout_reg: + rtc_device_unregister(rx8025->rtc); + +errout_free: + i2c_set_clientdata(client, NULL); + kfree(rx8025); + +errout: + dev_err(&adapter->dev, "probing for rx8025 failed\n"); + return err; +} + +static int __devexit rx8025_remove(struct i2c_client *client) +{ + struct rx8025_data *rx8025 = i2c_get_clientdata(client); + struct mutex *lock = &rx8025->rtc->ops_lock; + + if (client->irq > 0) { + mutex_lock(lock); + rx8025->exiting = 1; + mutex_unlock(lock); + + free_irq(client->irq, client); + flush_scheduled_work(); + } + + rx8025_sysfs_unregister(&client->dev); + rtc_device_unregister(rx8025->rtc); + i2c_set_clientdata(client, NULL); + kfree(rx8025); + return 0; +} + +static struct i2c_driver rx8025_driver = { + .driver = { + .name = "rtc-rx8025", + .owner = THIS_MODULE, + }, + .probe = rx8025_probe, + .remove = __devexit_p(rx8025_remove), + .id_table = rx8025_id, +}; + +static int __init rx8025_init(void) +{ + return i2c_add_driver(&rx8025_driver); +} + +static void __exit rx8025_exit(void) +{ + i2c_del_driver(&rx8025_driver); +} + +MODULE_AUTHOR("Wolfgang Grandegger "); +MODULE_DESCRIPTION("RX-8025 SA/NB RTC driver"); +MODULE_LICENSE("GPL"); + +module_init(rx8025_init); +module_exit(rx8025_exit); diff --git a/drivers/rtc/rtc-test.c b/drivers/rtc/rtc-test.c index e478280ff628..51725f7755b0 100644 --- a/drivers/rtc/rtc-test.c +++ b/drivers/rtc/rtc-test.c @@ -93,7 +93,6 @@ static ssize_t test_irq_store(struct device *dev, struct rtc_device *rtc = platform_get_drvdata(plat_dev); retval = count; - local_irq_disable(); if (strncmp(buf, "tick", 4) == 0) rtc_update_irq(rtc, 1, RTC_PF | RTC_IRQF); else if (strncmp(buf, "alarm", 5) == 0) @@ -102,7 +101,6 @@ static ssize_t test_irq_store(struct device *dev, rtc_update_irq(rtc, 1, RTC_UF | RTC_IRQF); else retval = -EINVAL; - local_irq_enable(); return retval; } diff --git a/drivers/rtc/rtc-tx4939.c b/drivers/rtc/rtc-tx4939.c index 4ee4857ff207..4a6ed1104fbb 100644 --- a/drivers/rtc/rtc-tx4939.c +++ b/drivers/rtc/rtc-tx4939.c @@ -261,10 +261,8 @@ static int __init tx4939_rtc_probe(struct platform_device *pdev) tx4939_rtc_cmd(pdata->rtcreg, TX4939_RTCCTL_COMMAND_NOP); if (devm_request_irq(&pdev->dev, irq, tx4939_rtc_interrupt, - IRQF_DISABLED | IRQF_SHARED, - pdev->name, &pdev->dev) < 0) { + IRQF_DISABLED, pdev->name, &pdev->dev) < 0) return -EBUSY; - } rtc = rtc_device_register(pdev->name, &pdev->dev, &tx4939_rtc_ops, THIS_MODULE); if (IS_ERR(rtc)) diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index d1815272c435..749836668655 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -5,8 +5,7 @@ * Carsten Otte * Martin Schwidefsky * Bugreports.to..: - * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001 - * + * Copyright IBM Corp. 1999, 2009 */ #define KMSG_COMPONENT "dasd" @@ -61,6 +60,7 @@ static int dasd_flush_block_queue(struct dasd_block *); static void dasd_device_tasklet(struct dasd_device *); static void dasd_block_tasklet(struct dasd_block *); static void do_kick_device(struct work_struct *); +static void do_restore_device(struct work_struct *); static void dasd_return_cqr_cb(struct dasd_ccw_req *, void *); static void dasd_device_timeout(unsigned long); static void dasd_block_timeout(unsigned long); @@ -109,6 +109,7 @@ struct dasd_device *dasd_alloc_device(void) device->timer.function = dasd_device_timeout; device->timer.data = (unsigned long) device; INIT_WORK(&device->kick_work, do_kick_device); + INIT_WORK(&device->restore_device, do_restore_device); device->state = DASD_STATE_NEW; device->target = DASD_STATE_NEW; @@ -469,7 +470,7 @@ static int dasd_decrease_state(struct dasd_device *device) */ static void dasd_change_state(struct dasd_device *device) { - int rc; + int rc; if (device->state == device->target) /* Already where we want to go today... */ @@ -478,8 +479,10 @@ static void dasd_change_state(struct dasd_device *device) rc = dasd_increase_state(device); else rc = dasd_decrease_state(device); - if (rc && rc != -EAGAIN) - device->target = device->state; + if (rc == -EAGAIN) + return; + if (rc) + device->target = device->state; if (device->state == device->target) { wake_up(&dasd_init_waitq); @@ -511,6 +514,25 @@ void dasd_kick_device(struct dasd_device *device) schedule_work(&device->kick_work); } +/* + * dasd_restore_device will schedule a call do do_restore_device to the kernel + * event daemon. + */ +static void do_restore_device(struct work_struct *work) +{ + struct dasd_device *device = container_of(work, struct dasd_device, + restore_device); + device->cdev->drv->restore(device->cdev); + dasd_put_device(device); +} + +void dasd_restore_device(struct dasd_device *device) +{ + dasd_get_device(device); + /* queue call to dasd_restore_device to the kernel event daemon. */ + schedule_work(&device->restore_device); +} + /* * Set the target state for a device and starts the state change. */ @@ -603,7 +625,7 @@ static void dasd_profile_end(struct dasd_block *block, if (dasd_profile_level != DASD_PROFILE_ON) return; - sectors = req->nr_sectors; + sectors = blk_rq_sectors(req); if (!cqr->buildclk || !cqr->startclk || !cqr->stopclk || !cqr->endclk || !sectors) @@ -851,8 +873,10 @@ int dasd_start_IO(struct dasd_ccw_req *cqr) /* Check the cqr */ rc = dasd_check_cqr(cqr); - if (rc) + if (rc) { + cqr->intrc = rc; return rc; + } device = (struct dasd_device *) cqr->startdev; if (cqr->retries < 0) { /* internal error 14 - start_IO run out of retries */ @@ -906,6 +930,12 @@ int dasd_start_IO(struct dasd_ccw_req *cqr) DBF_DEV_EVENT(DBF_DEBUG, device, "%s", "start_IO: -EIO device gone, retry"); break; + case -EINVAL: + /* most likely caused in power management context */ + DBF_DEV_EVENT(DBF_DEBUG, device, "%s", + "start_IO: -EINVAL device currently " + "not accessible"); + break; default: /* internal error 11 - unknown rc */ snprintf(errorstring, ERRORLENGTH, "11 %d", rc); @@ -915,6 +945,7 @@ int dasd_start_IO(struct dasd_ccw_req *cqr) BUG(); break; } + cqr->intrc = rc; return rc; } @@ -1454,8 +1485,12 @@ int dasd_sleep_on(struct dasd_ccw_req *cqr) dasd_add_request_tail(cqr); wait_event(generic_waitq, _wait_for_wakeup(cqr)); - /* Request status is either done or failed. */ - rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO; + if (cqr->status == DASD_CQR_DONE) + rc = 0; + else if (cqr->intrc) + rc = cqr->intrc; + else + rc = -EIO; return rc; } @@ -1477,8 +1512,15 @@ int dasd_sleep_on_interruptible(struct dasd_ccw_req *cqr) dasd_cancel_req(cqr); /* wait (non-interruptible) for final status */ wait_event(generic_waitq, _wait_for_wakeup(cqr)); + cqr->intrc = rc; } - rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO; + + if (cqr->status == DASD_CQR_DONE) + rc = 0; + else if (cqr->intrc) + rc = cqr->intrc; + else + rc = -EIO; return rc; } @@ -1523,8 +1565,12 @@ int dasd_sleep_on_immediatly(struct dasd_ccw_req *cqr) wait_event(generic_waitq, _wait_for_wakeup(cqr)); - /* Request status is either done or failed. */ - rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO; + if (cqr->status == DASD_CQR_DONE) + rc = 0; + else if (cqr->intrc) + rc = cqr->intrc; + else + rc = -EIO; return rc; } @@ -1613,15 +1659,6 @@ void dasd_block_clear_timer(struct dasd_block *block) del_timer(&block->timer); } -/* - * posts the buffer_cache about a finalized request - */ -static inline void dasd_end_request(struct request *req, int error) -{ - if (__blk_end_request(req, error, blk_rq_bytes(req))) - BUG(); -} - /* * Process finished error recovery ccw. */ @@ -1665,18 +1702,14 @@ static void __dasd_process_request_queue(struct dasd_block *block) if (basedev->state < DASD_STATE_READY) return; /* Now we try to fetch requests from the request queue */ - while (!blk_queue_plugged(queue) && - elv_next_request(queue)) { - - req = elv_next_request(queue); - + while (!blk_queue_plugged(queue) && (req = blk_peek_request(queue))) { if (basedev->features & DASD_FEATURE_READONLY && rq_data_dir(req) == WRITE) { DBF_DEV_EVENT(DBF_ERR, basedev, "Rejecting write request %p", req); - blkdev_dequeue_request(req); - dasd_end_request(req, -EIO); + blk_start_request(req); + __blk_end_request_all(req, -EIO); continue; } cqr = basedev->discipline->build_cp(basedev, block, req); @@ -1704,8 +1737,8 @@ static void __dasd_process_request_queue(struct dasd_block *block) "CCW creation failed (rc=%ld) " "on request %p", PTR_ERR(cqr), req); - blkdev_dequeue_request(req); - dasd_end_request(req, -EIO); + blk_start_request(req); + __blk_end_request_all(req, -EIO); continue; } /* @@ -1714,7 +1747,7 @@ static void __dasd_process_request_queue(struct dasd_block *block) */ cqr->callback_data = (void *) req; cqr->status = DASD_CQR_FILLED; - blkdev_dequeue_request(req); + blk_start_request(req); list_add_tail(&cqr->blocklist, &block->ccw_queue); dasd_profile_start(block, cqr, req); } @@ -1731,7 +1764,7 @@ static void __dasd_cleanup_cqr(struct dasd_ccw_req *cqr) status = cqr->block->base->discipline->free_cp(cqr, req); if (status <= 0) error = status ? status : -EIO; - dasd_end_request(req, error); + __blk_end_request_all(req, error); } /* @@ -2003,7 +2036,7 @@ static void dasd_setup_queue(struct dasd_block *block) { int max; - blk_queue_hardsect_size(block->request_queue, block->bp_block); + blk_queue_logical_block_size(block->request_queue, block->bp_block); max = block->base->discipline->max_blocks << block->s2b_shift; blk_queue_max_sectors(block->request_queue, max); blk_queue_max_phys_segments(block->request_queue, -1L); @@ -2038,10 +2071,8 @@ static void dasd_flush_request_queue(struct dasd_block *block) return; spin_lock_irq(&block->request_queue_lock); - while ((req = elv_next_request(block->request_queue))) { - blkdev_dequeue_request(req); - dasd_end_request(req, -EIO); - } + while ((req = blk_fetch_request(block->request_queue))) + __blk_end_request_all(req, -EIO); spin_unlock_irq(&block->request_queue_lock); } @@ -2397,6 +2428,12 @@ int dasd_generic_notify(struct ccw_device *cdev, int event) case CIO_OPER: /* FIXME: add a sanity check. */ device->stopped &= ~DASD_STOPPED_DC_WAIT; + if (device->stopped & DASD_UNRESUMED_PM) { + device->stopped &= ~DASD_UNRESUMED_PM; + dasd_restore_device(device); + ret = 1; + break; + } dasd_schedule_device_bh(device); if (device->block) dasd_schedule_block_bh(device->block); @@ -2407,6 +2444,89 @@ int dasd_generic_notify(struct ccw_device *cdev, int event) return ret; } +int dasd_generic_pm_freeze(struct ccw_device *cdev) +{ + struct dasd_ccw_req *cqr, *n; + int rc; + struct list_head freeze_queue; + struct dasd_device *device = dasd_device_from_cdev(cdev); + + if (IS_ERR(device)) + return PTR_ERR(device); + /* disallow new I/O */ + device->stopped |= DASD_STOPPED_PM; + /* clear active requests */ + INIT_LIST_HEAD(&freeze_queue); + spin_lock_irq(get_ccwdev_lock(cdev)); + rc = 0; + list_for_each_entry_safe(cqr, n, &device->ccw_queue, devlist) { + /* Check status and move request to flush_queue */ + if (cqr->status == DASD_CQR_IN_IO) { + rc = device->discipline->term_IO(cqr); + if (rc) { + /* unable to terminate requeust */ + dev_err(&device->cdev->dev, + "Unable to terminate request %p " + "on suspend\n", cqr); + spin_unlock_irq(get_ccwdev_lock(cdev)); + dasd_put_device(device); + return rc; + } + } + list_move_tail(&cqr->devlist, &freeze_queue); + } + + spin_unlock_irq(get_ccwdev_lock(cdev)); + + list_for_each_entry_safe(cqr, n, &freeze_queue, devlist) { + wait_event(dasd_flush_wq, + (cqr->status != DASD_CQR_CLEAR_PENDING)); + if (cqr->status == DASD_CQR_CLEARED) + cqr->status = DASD_CQR_QUEUED; + } + /* move freeze_queue to start of the ccw_queue */ + spin_lock_irq(get_ccwdev_lock(cdev)); + list_splice_tail(&freeze_queue, &device->ccw_queue); + spin_unlock_irq(get_ccwdev_lock(cdev)); + + if (device->discipline->freeze) + rc = device->discipline->freeze(device); + + dasd_put_device(device); + return rc; +} +EXPORT_SYMBOL_GPL(dasd_generic_pm_freeze); + +int dasd_generic_restore_device(struct ccw_device *cdev) +{ + struct dasd_device *device = dasd_device_from_cdev(cdev); + int rc = 0; + + if (IS_ERR(device)) + return PTR_ERR(device); + + /* allow new IO again */ + device->stopped &= ~DASD_STOPPED_PM; + device->stopped &= ~DASD_UNRESUMED_PM; + + dasd_schedule_device_bh(device); + if (device->block) + dasd_schedule_block_bh(device->block); + + if (device->discipline->restore) + rc = device->discipline->restore(device); + if (rc) + /* + * if the resume failed for the DASD we put it in + * an UNRESUMED stop state + */ + device->stopped |= DASD_UNRESUMED_PM; + + dasd_put_device(device); + return 0; +} +EXPORT_SYMBOL_GPL(dasd_generic_restore_device); + static struct dasd_ccw_req *dasd_generic_build_rdc(struct dasd_device *device, void *rdc_buffer, int rdc_buffer_size, @@ -2442,12 +2562,12 @@ static struct dasd_ccw_req *dasd_generic_build_rdc(struct dasd_device *device, int dasd_generic_read_dev_chars(struct dasd_device *device, char *magic, - void **rdc_buffer, int rdc_buffer_size) + void *rdc_buffer, int rdc_buffer_size) { int ret; struct dasd_ccw_req *cqr; - cqr = dasd_generic_build_rdc(device, *rdc_buffer, rdc_buffer_size, + cqr = dasd_generic_build_rdc(device, rdc_buffer, rdc_buffer_size, magic); if (IS_ERR(cqr)) return PTR_ERR(cqr); diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index e77666c8e6c0..4cac5b54f26a 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -1098,6 +1098,7 @@ dasd_get_uid(struct ccw_device *cdev, struct dasd_uid *uid) spin_unlock(&dasd_devmap_lock); return 0; } +EXPORT_SYMBOL_GPL(dasd_get_uid); /* * Register the given device unique identifier into devmap struct. diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index b9a7f7733446..644086ba2ede 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c @@ -202,6 +202,7 @@ dasd_start_diag(struct dasd_ccw_req * cqr) rc = -EIO; break; } + cqr->intrc = rc; return rc; } @@ -505,8 +506,9 @@ static struct dasd_ccw_req *dasd_diag_build_cp(struct dasd_device *memdev, return ERR_PTR(-EINVAL); blksize = block->bp_block; /* Calculate record id of first and last block. */ - first_rec = req->sector >> block->s2b_shift; - last_rec = (req->sector + req->nr_sectors - 1) >> block->s2b_shift; + first_rec = blk_rq_pos(req) >> block->s2b_shift; + last_rec = + (blk_rq_pos(req) + blk_rq_sectors(req) - 1) >> block->s2b_shift; /* Check struct bio and count the number of blocks for the request. */ count = 0; rq_for_each_segment(bv, req, iter) { diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index cb52da033f06..f8b1f04f26b8 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -5,10 +5,9 @@ * Carsten Otte * Martin Schwidefsky * Bugreports.to..: - * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 + * Copyright IBM Corp. 1999, 2009 * EMC Symmetrix ioctl Copyright EMC Corporation, 2008 * Author.........: Nigel Hislop - * */ #define KMSG_COMPONENT "dasd" @@ -104,17 +103,6 @@ dasd_eckd_set_online(struct ccw_device *cdev) return dasd_generic_set_online(cdev, &dasd_eckd_discipline); } -static struct ccw_driver dasd_eckd_driver = { - .name = "dasd-eckd", - .owner = THIS_MODULE, - .ids = dasd_eckd_ids, - .probe = dasd_eckd_probe, - .remove = dasd_generic_remove, - .set_offline = dasd_generic_set_offline, - .set_online = dasd_eckd_set_online, - .notify = dasd_generic_notify, -}; - static const int sizes_trk0[] = { 28, 148, 84 }; #define LABEL_SIZE 140 @@ -1097,20 +1085,20 @@ dasd_eckd_check_characteristics(struct dasd_device *device) { struct dasd_eckd_private *private; struct dasd_block *block; - void *rdc_data; int is_known, rc; private = (struct dasd_eckd_private *) device->private; - if (private == NULL) { - private = kzalloc(sizeof(struct dasd_eckd_private), - GFP_KERNEL | GFP_DMA); - if (private == NULL) { + if (!private) { + private = kzalloc(sizeof(*private), GFP_KERNEL | GFP_DMA); + if (!private) { dev_warn(&device->cdev->dev, "Allocating memory for private DASD data " "failed\n"); return -ENOMEM; } device->private = (void *) private; + } else { + memset(private, 0, sizeof(*private)); } /* Invalidate status of initial analysis. */ private->init_cqr_status = -1; @@ -1161,9 +1149,8 @@ dasd_eckd_check_characteristics(struct dasd_device *device) goto out_err3; /* Read Device Characteristics */ - rdc_data = (void *) &(private->rdc_data); - memset(rdc_data, 0, sizeof(rdc_data)); - rc = dasd_generic_read_dev_chars(device, "ECKD", &rdc_data, 64); + rc = dasd_generic_read_dev_chars(device, "ECKD", &private->rdc_data, + 64); if (rc) { DBF_EVENT(DBF_WARNING, "Read device characteristics failed, rc=%d for " @@ -1183,7 +1170,7 @@ dasd_eckd_check_characteristics(struct dasd_device *device) private->rdc_data.dev_model, private->rdc_data.cu_type, private->rdc_data.cu_model.model, - private->real_cyl, + private->real_cyl, private->rdc_data.trk_per_cyl, private->rdc_data.sec_per_trk); return 0; @@ -2336,9 +2323,10 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev, { int tpm, cmdrtd, cmdwtd; int use_prefix; - - struct dasd_eckd_private *private; +#if defined(CONFIG_64BIT) int fcx_in_css, fcx_in_gneq, fcx_in_features; +#endif + struct dasd_eckd_private *private; struct dasd_device *basedev; sector_t first_rec, last_rec; sector_t first_trk, last_trk; @@ -2354,18 +2342,22 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev, blksize = block->bp_block; blk_per_trk = recs_per_track(&private->rdc_data, 0, blksize); /* Calculate record id of first and last block. */ - first_rec = first_trk = req->sector >> block->s2b_shift; + first_rec = first_trk = blk_rq_pos(req) >> block->s2b_shift; first_offs = sector_div(first_trk, blk_per_trk); last_rec = last_trk = - (req->sector + req->nr_sectors - 1) >> block->s2b_shift; + (blk_rq_pos(req) + blk_rq_sectors(req) - 1) >> block->s2b_shift; last_offs = sector_div(last_trk, blk_per_trk); cdlspecial = (private->uses_cdl && first_rec < 2*blk_per_trk); - /* is transport mode supported ? */ + /* is transport mode supported? */ +#if defined(CONFIG_64BIT) fcx_in_css = css_general_characteristics.fcx; fcx_in_gneq = private->gneq->reserved2[7] & 0x04; fcx_in_features = private->features.feature[40] & 0x80; tpm = fcx_in_css && fcx_in_gneq && fcx_in_features; +#else + tpm = 0; +#endif /* is read track data and write track data in command mode supported? */ cmdrtd = private->features.feature[9] & 0x20; @@ -2420,7 +2412,7 @@ dasd_eckd_free_cp(struct dasd_ccw_req *cqr, struct request *req) private = (struct dasd_eckd_private *) cqr->block->base->private; blksize = cqr->block->bp_block; blk_per_trk = recs_per_track(&private->rdc_data, 0, blksize); - recid = req->sector >> cqr->block->s2b_shift; + recid = blk_rq_pos(req) >> cqr->block->s2b_shift; ccw = cqr->cpaddr; /* Skip over define extent & locate record. */ ccw++; @@ -3013,8 +3005,9 @@ static void dasd_eckd_dump_sense_ccw(struct dasd_device *device, " I/O status report for device %s:\n", dev_name(&device->cdev->dev)); len += sprintf(page + len, KERN_ERR PRINTK_HEADER - " in req: %p CS: 0x%02X DS: 0x%02X\n", req, - scsw_cstat(&irb->scsw), scsw_dstat(&irb->scsw)); + " in req: %p CS: 0x%02X DS: 0x%02X CC: 0x%02X RC: %d\n", + req, scsw_cstat(&irb->scsw), scsw_dstat(&irb->scsw), + scsw_cc(&irb->scsw), req->intrc); len += sprintf(page + len, KERN_ERR PRINTK_HEADER " device %s: Failing CCW: %p\n", dev_name(&device->cdev->dev), @@ -3115,9 +3108,10 @@ static void dasd_eckd_dump_sense_tcw(struct dasd_device *device, " I/O status report for device %s:\n", dev_name(&device->cdev->dev)); len += sprintf(page + len, KERN_ERR PRINTK_HEADER - " in req: %p CS: 0x%02X DS: 0x%02X " + " in req: %p CS: 0x%02X DS: 0x%02X CC: 0x%02X RC: %d " "fcxs: 0x%02X schxs: 0x%02X\n", req, scsw_cstat(&irb->scsw), scsw_dstat(&irb->scsw), + scsw_cc(&irb->scsw), req->intrc, irb->scsw.tm.fcxs, irb->scsw.tm.schxs); len += sprintf(page + len, KERN_ERR PRINTK_HEADER " device %s: Failing TCW: %p\n", @@ -3230,6 +3224,90 @@ static void dasd_eckd_dump_sense(struct dasd_device *device, dasd_eckd_dump_sense_ccw(device, req, irb); } +int dasd_eckd_pm_freeze(struct dasd_device *device) +{ + /* + * the device should be disconnected from our LCU structure + * on restore we will reconnect it and reread LCU specific + * information like PAV support that might have changed + */ + dasd_alias_remove_device(device); + dasd_alias_disconnect_device_from_lcu(device); + + return 0; +} + +int dasd_eckd_restore_device(struct dasd_device *device) +{ + struct dasd_eckd_private *private; + int is_known, rc; + struct dasd_uid temp_uid; + + private = (struct dasd_eckd_private *) device->private; + + /* Read Configuration Data */ + rc = dasd_eckd_read_conf(device); + if (rc) + goto out_err; + + /* Generate device unique id and register in devmap */ + rc = dasd_eckd_generate_uid(device, &private->uid); + dasd_get_uid(device->cdev, &temp_uid); + if (memcmp(&private->uid, &temp_uid, sizeof(struct dasd_uid)) != 0) + dev_err(&device->cdev->dev, "The UID of the DASD has changed\n"); + if (rc) + goto out_err; + dasd_set_uid(device->cdev, &private->uid); + + /* register lcu with alias handling, enable PAV if this is a new lcu */ + is_known = dasd_alias_make_device_known_to_lcu(device); + if (is_known < 0) + return is_known; + if (!is_known) { + /* new lcu found */ + rc = dasd_eckd_validate_server(device); /* will switch pav on */ + if (rc) + goto out_err; + } + + /* Read Feature Codes */ + rc = dasd_eckd_read_features(device); + if (rc) + goto out_err; + + /* Read Device Characteristics */ + memset(&private->rdc_data, 0, sizeof(private->rdc_data)); + rc = dasd_generic_read_dev_chars(device, "ECKD", + &private->rdc_data, 64); + if (rc) { + DBF_EVENT(DBF_WARNING, + "Read device characteristics failed, rc=%d for " + "device: %s", rc, dev_name(&device->cdev->dev)); + goto out_err; + } + + /* add device to alias management */ + dasd_alias_add_device(device); + + return 0; + +out_err: + return -1; +} + +static struct ccw_driver dasd_eckd_driver = { + .name = "dasd-eckd", + .owner = THIS_MODULE, + .ids = dasd_eckd_ids, + .probe = dasd_eckd_probe, + .remove = dasd_generic_remove, + .set_offline = dasd_generic_set_offline, + .set_online = dasd_eckd_set_online, + .notify = dasd_generic_notify, + .freeze = dasd_generic_pm_freeze, + .thaw = dasd_generic_restore_device, + .restore = dasd_generic_restore_device, +}; /* * max_blocks is dependent on the amount of storage that is available @@ -3268,13 +3346,21 @@ static struct dasd_discipline dasd_eckd_discipline = { .dump_sense_dbf = dasd_eckd_dump_sense_dbf, .fill_info = dasd_eckd_fill_info, .ioctl = dasd_eckd_ioctl, + .freeze = dasd_eckd_pm_freeze, + .restore = dasd_eckd_restore_device, }; static int __init dasd_eckd_init(void) { + int ret; + ASCEBC(dasd_eckd_discipline.ebcname, 4); - return ccw_driver_register(&dasd_eckd_driver); + ret = ccw_driver_register(&dasd_eckd_driver); + if (!ret) + wait_for_device_probe(); + + return ret; } static void __exit diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index a3eb6fd14673..e21ee735f926 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c @@ -2,8 +2,7 @@ * File...........: linux/drivers/s390/block/dasd_fba.c * Author(s)......: Holger Smolinski * Bugreports.to..: - * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 - * + * Copyright IBM Corp. 1999, 2009 */ #define KMSG_COMPONENT "dasd" @@ -75,6 +74,9 @@ static struct ccw_driver dasd_fba_driver = { .set_offline = dasd_generic_set_offline, .set_online = dasd_fba_set_online, .notify = dasd_generic_notify, + .freeze = dasd_generic_pm_freeze, + .thaw = dasd_generic_restore_device, + .restore = dasd_generic_restore_device, }; static void @@ -122,20 +124,20 @@ dasd_fba_check_characteristics(struct dasd_device *device) struct dasd_block *block; struct dasd_fba_private *private; struct ccw_device *cdev = device->cdev; - void *rdc_data; int rc; private = (struct dasd_fba_private *) device->private; - if (private == NULL) { - private = kzalloc(sizeof(struct dasd_fba_private), - GFP_KERNEL | GFP_DMA); - if (private == NULL) { + if (!private) { + private = kzalloc(sizeof(*private), GFP_KERNEL | GFP_DMA); + if (!private) { dev_warn(&device->cdev->dev, "Allocating memory for private DASD " "data failed\n"); return -ENOMEM; } device->private = (void *) private; + } else { + memset(private, 0, sizeof(*private)); } block = dasd_alloc_block(); if (IS_ERR(block)) { @@ -150,8 +152,8 @@ dasd_fba_check_characteristics(struct dasd_device *device) block->base = device; /* Read Device Characteristics */ - rdc_data = (void *) &(private->rdc_data); - rc = dasd_generic_read_dev_chars(device, "FBA ", &rdc_data, 32); + rc = dasd_generic_read_dev_chars(device, "FBA ", &private->rdc_data, + 32); if (rc) { DBF_EVENT(DBF_WARNING, "Read device characteristics returned " "error %d for device: %s", @@ -270,8 +272,9 @@ static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device * memdev, return ERR_PTR(-EINVAL); blksize = block->bp_block; /* Calculate record id of first and last block. */ - first_rec = req->sector >> block->s2b_shift; - last_rec = (req->sector + req->nr_sectors - 1) >> block->s2b_shift; + first_rec = blk_rq_pos(req) >> block->s2b_shift; + last_rec = + (blk_rq_pos(req) + blk_rq_sectors(req) - 1) >> block->s2b_shift; /* Check struct bio and count the number of blocks for the request. */ count = 0; cidaw = 0; @@ -309,7 +312,7 @@ static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device * memdev, ccw = cqr->cpaddr; /* First ccw is define extent. */ define_extent(ccw++, cqr->data, rq_data_dir(req), - block->bp_block, req->sector, req->nr_sectors); + block->bp_block, blk_rq_pos(req), blk_rq_sectors(req)); /* Build locate_record + read/write ccws. */ idaws = (unsigned long *) (cqr->data + sizeof(struct DE_fba_data)); LO_data = (struct LO_fba_data *) (idaws + cidaw); @@ -603,8 +606,14 @@ static struct dasd_discipline dasd_fba_discipline = { static int __init dasd_fba_init(void) { + int ret; + ASCEBC(dasd_fba_discipline.ebcname, 4); - return ccw_driver_register(&dasd_fba_driver); + ret = ccw_driver_register(&dasd_fba_driver); + if (!ret) + wait_for_device_probe(); + + return ret; } static void __exit diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index c1e487f774c6..fd63b2f2bda9 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -4,8 +4,7 @@ * Horst Hummel * Martin Schwidefsky * Bugreports.to..: - * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 - * + * Copyright IBM Corp. 1999, 2009 */ #ifndef DASD_INT_H @@ -173,6 +172,7 @@ struct dasd_ccw_req { void *data; /* pointer to data area */ /* these are important for recovering erroneous requests */ + int intrc; /* internal error, e.g. from start_IO */ struct irb irb; /* device status in case of an error */ struct dasd_ccw_req *refers; /* ERP-chain queueing. */ void *function; /* originating ERP action */ @@ -294,6 +294,10 @@ struct dasd_discipline { int (*fill_geometry) (struct dasd_block *, struct hd_geometry *); int (*fill_info) (struct dasd_device *, struct dasd_information2_t *); int (*ioctl) (struct dasd_block *, unsigned int, void __user *); + + /* suspend/resume functions */ + int (*freeze) (struct dasd_device *); + int (*restore) (struct dasd_device *); }; extern struct dasd_discipline *dasd_diag_discipline_pointer; @@ -366,6 +370,7 @@ struct dasd_device { atomic_t tasklet_scheduled; struct tasklet_struct tasklet; struct work_struct kick_work; + struct work_struct restore_device; struct timer_list timer; debug_info_t *debug_area; @@ -409,6 +414,8 @@ struct dasd_block { #define DASD_STOPPED_PENDING 4 /* long busy */ #define DASD_STOPPED_DC_WAIT 8 /* disconnected, wait */ #define DASD_STOPPED_SU 16 /* summary unit check handling */ +#define DASD_STOPPED_PM 32 /* pm state transition */ +#define DASD_UNRESUMED_PM 64 /* pm resume failed state */ /* per device flags */ #define DASD_FLAG_OFFLINE 3 /* device is in offline processing */ @@ -555,6 +562,7 @@ void dasd_free_block(struct dasd_block *); void dasd_enable_device(struct dasd_device *); void dasd_set_target_state(struct dasd_device *, int); void dasd_kick_device(struct dasd_device *); +void dasd_restore_device(struct dasd_device *); void dasd_add_request_head(struct dasd_ccw_req *); void dasd_add_request_tail(struct dasd_ccw_req *); @@ -577,8 +585,10 @@ int dasd_generic_set_online(struct ccw_device *, struct dasd_discipline *); int dasd_generic_set_offline (struct ccw_device *cdev); int dasd_generic_notify(struct ccw_device *, int); void dasd_generic_handle_state_change(struct dasd_device *); +int dasd_generic_pm_freeze(struct ccw_device *); +int dasd_generic_restore_device(struct ccw_device *); -int dasd_generic_read_dev_chars(struct dasd_device *, char *, void **, int); +int dasd_generic_read_dev_chars(struct dasd_device *, char *, void *, int); char *dasd_get_sense(struct irb *); /* externals in dasd_devmap.c */ diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index cfdcf1aed33c..016f9e9d2591 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c @@ -14,10 +14,11 @@ #include #include #include -#include -#include #include #include +#include +#include +#include #define DCSSBLK_NAME "dcssblk" #define DCSSBLK_MINORS_PER_DISK 1 @@ -127,7 +128,7 @@ dcssblk_assign_free_minor(struct dcssblk_dev_info *dev_info) found = 0; // test if minor available list_for_each_entry(entry, &dcssblk_devices, lh) - if (minor == MINOR(disk_devt(entry->gd))) + if (minor == entry->gd->first_minor) found++; if (!found) break; // got unused minor } @@ -602,7 +603,7 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char dev_info->gd->private_data = dev_info; dev_info->gd->driverfs_dev = &dev_info->dev; blk_queue_make_request(dev_info->dcssblk_queue, dcssblk_make_request); - blk_queue_hardsect_size(dev_info->dcssblk_queue, 4096); + blk_queue_logical_block_size(dev_info->dcssblk_queue, 4096); seg_byte_size = (dev_info->end - dev_info->start + 1); set_capacity(dev_info->gd, seg_byte_size >> 9); // size in sectors @@ -625,7 +626,7 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char if (rc) goto release_gd; sprintf(dev_info->gd->disk_name, "dcssblk%d", - MINOR(disk_devt(dev_info->gd))); + dev_info->gd->first_minor); list_add_tail(&dev_info->lh, &dcssblk_devices); if (!try_module_get(THIS_MODULE)) { @@ -939,12 +940,95 @@ dcssblk_check_params(void) } } +/* + * Suspend / Resume + */ +static int dcssblk_freeze(struct device *dev) +{ + struct dcssblk_dev_info *dev_info; + int rc = 0; + + list_for_each_entry(dev_info, &dcssblk_devices, lh) { + switch (dev_info->segment_type) { + case SEG_TYPE_SR: + case SEG_TYPE_ER: + case SEG_TYPE_SC: + if (!dev_info->is_shared) + rc = -EINVAL; + break; + default: + rc = -EINVAL; + break; + } + if (rc) + break; + } + if (rc) + pr_err("Suspend failed because device %s is writeable.\n", + dev_info->segment_name); + return rc; +} + +static int dcssblk_restore(struct device *dev) +{ + struct dcssblk_dev_info *dev_info; + struct segment_info *entry; + unsigned long start, end; + int rc = 0; + + list_for_each_entry(dev_info, &dcssblk_devices, lh) { + list_for_each_entry(entry, &dev_info->seg_list, lh) { + segment_unload(entry->segment_name); + rc = segment_load(entry->segment_name, SEGMENT_SHARED, + &start, &end); + if (rc < 0) { +// TODO in_use check ? + segment_warning(rc, entry->segment_name); + goto out_panic; + } + if (start != entry->start || end != entry->end) { + pr_err("Mismatch of start / end address after " + "resuming device %s\n", + entry->segment_name); + goto out_panic; + } + } + } + return 0; +out_panic: + panic("fatal dcssblk resume error\n"); +} + +static int dcssblk_thaw(struct device *dev) +{ + return 0; +} + +static struct dev_pm_ops dcssblk_pm_ops = { + .freeze = dcssblk_freeze, + .thaw = dcssblk_thaw, + .restore = dcssblk_restore, +}; + +static struct platform_driver dcssblk_pdrv = { + .driver = { + .name = "dcssblk", + .owner = THIS_MODULE, + .pm = &dcssblk_pm_ops, + }, +}; + +static struct platform_device *dcssblk_pdev; + + /* * The init/exit functions. */ static void __exit dcssblk_exit(void) { + platform_device_unregister(dcssblk_pdev); + platform_driver_unregister(&dcssblk_pdrv); root_device_unregister(dcssblk_root_dev); unregister_blkdev(dcssblk_major, DCSSBLK_NAME); } @@ -954,30 +1038,44 @@ dcssblk_init(void) { int rc; + rc = platform_driver_register(&dcssblk_pdrv); + if (rc) + return rc; + + dcssblk_pdev = platform_device_register_simple("dcssblk", -1, NULL, + 0); + if (IS_ERR(dcssblk_pdev)) { + rc = PTR_ERR(dcssblk_pdev); + goto out_pdrv; + } + dcssblk_root_dev = root_device_register("dcssblk"); - if (IS_ERR(dcssblk_root_dev)) - return PTR_ERR(dcssblk_root_dev); + if (IS_ERR(dcssblk_root_dev)) { + rc = PTR_ERR(dcssblk_root_dev); + goto out_pdev; + } rc = device_create_file(dcssblk_root_dev, &dev_attr_add); - if (rc) { - root_device_unregister(dcssblk_root_dev); - return rc; - } + if (rc) + goto out_root; rc = device_create_file(dcssblk_root_dev, &dev_attr_remove); - if (rc) { - root_device_unregister(dcssblk_root_dev); - return rc; - } + if (rc) + goto out_root; rc = register_blkdev(0, DCSSBLK_NAME); - if (rc < 0) { - root_device_unregister(dcssblk_root_dev); - return rc; - } + if (rc < 0) + goto out_root; dcssblk_major = rc; init_rwsem(&dcssblk_devices_sem); dcssblk_check_params(); - return 0; + +out_root: + root_device_unregister(dcssblk_root_dev); +out_pdev: + platform_device_unregister(dcssblk_pdev); +out_pdrv: + platform_driver_unregister(&dcssblk_pdrv); + return rc; } module_init(dcssblk_init); diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c index 76814f3e898a..2e9e1ecd6d82 100644 --- a/drivers/s390/block/xpram.c +++ b/drivers/s390/block/xpram.c @@ -39,7 +39,10 @@ #include /* HDIO_GETGEO */ #include #include +#include +#include #include +#include #define XPRAM_NAME "xpram" #define XPRAM_DEVS 1 /* one partition */ @@ -48,6 +51,7 @@ typedef struct { unsigned int size; /* size of xpram segment in pages */ unsigned int offset; /* start page of xpram segment */ + unsigned int csum; /* partition checksum for suspend */ } xpram_device_t; static xpram_device_t xpram_devices[XPRAM_MAX_DEVS]; @@ -138,7 +142,7 @@ static long xpram_page_out (unsigned long page_addr, unsigned int xpage_index) /* * Check if xpram is available. */ -static int __init xpram_present(void) +static int xpram_present(void) { unsigned long mem_page; int rc; @@ -154,7 +158,7 @@ static int __init xpram_present(void) /* * Return index of the last available xpram page. */ -static unsigned long __init xpram_highest_page_index(void) +static unsigned long xpram_highest_page_index(void) { unsigned int page_index, add_bit; unsigned long mem_page; @@ -343,7 +347,7 @@ static int __init xpram_setup_blkdev(void) goto out; } blk_queue_make_request(xpram_queues[i], xpram_make_request); - blk_queue_hardsect_size(xpram_queues[i], 4096); + blk_queue_logical_block_size(xpram_queues[i], 4096); } /* @@ -382,6 +386,106 @@ out: return rc; } +/* + * Save checksums for all partitions. + */ +static int xpram_save_checksums(void) +{ + unsigned long mem_page; + int rc, i; + + rc = 0; + mem_page = (unsigned long) __get_free_page(GFP_KERNEL); + if (!mem_page) + return -ENOMEM; + for (i = 0; i < xpram_devs; i++) { + rc = xpram_page_in(mem_page, xpram_devices[i].offset); + if (rc) + goto fail; + xpram_devices[i].csum = csum_partial((const void *) mem_page, + PAGE_SIZE, 0); + } +fail: + free_page(mem_page); + return rc ? -ENXIO : 0; +} + +/* + * Verify checksums for all partitions. + */ +static int xpram_validate_checksums(void) +{ + unsigned long mem_page; + unsigned int csum; + int rc, i; + + rc = 0; + mem_page = (unsigned long) __get_free_page(GFP_KERNEL); + if (!mem_page) + return -ENOMEM; + for (i = 0; i < xpram_devs; i++) { + rc = xpram_page_in(mem_page, xpram_devices[i].offset); + if (rc) + goto fail; + csum = csum_partial((const void *) mem_page, PAGE_SIZE, 0); + if (xpram_devices[i].csum != csum) { + rc = -EINVAL; + goto fail; + } + } +fail: + free_page(mem_page); + return rc ? -ENXIO : 0; +} + +/* + * Resume failed: Print error message and call panic. + */ +static void xpram_resume_error(const char *message) +{ + pr_err("Resume error: %s\n", message); + panic("xpram resume error\n"); +} + +/* + * Check if xpram setup changed between suspend and resume. + */ +static int xpram_restore(struct device *dev) +{ + if (!xpram_pages) + return 0; + if (xpram_present() != 0) + xpram_resume_error("xpram disappeared"); + if (xpram_pages != xpram_highest_page_index() + 1) + xpram_resume_error("Size of xpram changed"); + if (xpram_validate_checksums()) + xpram_resume_error("Data of xpram changed"); + return 0; +} + +/* + * Save necessary state in suspend. + */ +static int xpram_freeze(struct device *dev) +{ + return xpram_save_checksums(); +} + +static struct dev_pm_ops xpram_pm_ops = { + .freeze = xpram_freeze, + .restore = xpram_restore, +}; + +static struct platform_driver xpram_pdrv = { + .driver = { + .name = XPRAM_NAME, + .owner = THIS_MODULE, + .pm = &xpram_pm_ops, + }, +}; + +static struct platform_device *xpram_pdev; + /* * Finally, the init/exit functions. */ @@ -394,6 +498,8 @@ static void __exit xpram_exit(void) put_disk(xpram_disks[i]); } unregister_blkdev(XPRAM_MAJOR, XPRAM_NAME); + platform_device_unregister(xpram_pdev); + platform_driver_unregister(&xpram_pdrv); } static int __init xpram_init(void) @@ -411,7 +517,24 @@ static int __init xpram_init(void) rc = xpram_setup_sizes(xpram_pages); if (rc) return rc; - return xpram_setup_blkdev(); + rc = platform_driver_register(&xpram_pdrv); + if (rc) + return rc; + xpram_pdev = platform_device_register_simple(XPRAM_NAME, -1, NULL, 0); + if (IS_ERR(xpram_pdev)) { + rc = PTR_ERR(xpram_pdev); + goto fail_platform_driver_unregister; + } + rc = xpram_setup_blkdev(); + if (rc) + goto fail_platform_device_unregister; + return 0; + +fail_platform_device_unregister: + platform_device_unregister(xpram_pdev); +fail_platform_driver_unregister: + platform_driver_unregister(&xpram_pdrv); + return rc; } module_init(xpram_init); diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index 9ab06e0dad40..21639d6c996f 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c @@ -1,14 +1,12 @@ /* - * drivers/s390/char/con3215.c - * 3215 line mode terminal driver. + * 3215 line mode terminal driver. * - * S390 version - * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), + * Copyright IBM Corp. 1999, 2009 + * Author(s): Martin Schwidefsky * - * Updated: - * Aug-2000: Added tab support - * Dan Morrison, IBM Corporation (dmorriso@cse.buffalo.edu) + * Updated: + * Aug-2000: Added tab support + * Dan Morrison, IBM Corporation */ #include @@ -22,10 +20,7 @@ #include #include #include - #include -#include - #include #include #include @@ -56,6 +51,7 @@ #define RAW3215_CLOSING 32 /* set while in close process */ #define RAW3215_TIMER_RUNS 64 /* set if the output delay timer is on */ #define RAW3215_FLUSHING 128 /* set to flush buffer (no delay) */ +#define RAW3215_FROZEN 256 /* set if 3215 is frozen for suspend */ #define TAB_STOP_SIZE 8 /* tab stop size */ @@ -111,8 +107,8 @@ static struct tty_driver *tty3215_driver; /* * Get a request structure from the free list */ -static inline struct raw3215_req * -raw3215_alloc_req(void) { +static inline struct raw3215_req *raw3215_alloc_req(void) +{ struct raw3215_req *req; unsigned long flags; @@ -126,8 +122,8 @@ raw3215_alloc_req(void) { /* * Put a request structure back to the free list */ -static inline void -raw3215_free_req(struct raw3215_req *req) { +static inline void raw3215_free_req(struct raw3215_req *req) +{ unsigned long flags; if (req->type == RAW3215_FREE) @@ -145,8 +141,7 @@ raw3215_free_req(struct raw3215_req *req) { * because a 3215 terminal won't accept a new read before the old one is * completed. */ -static void -raw3215_mk_read_req(struct raw3215_info *raw) +static void raw3215_mk_read_req(struct raw3215_info *raw) { struct raw3215_req *req; struct ccw1 *ccw; @@ -174,8 +169,7 @@ raw3215_mk_read_req(struct raw3215_info *raw) * buffer to the 3215 device. If a queued write exists it is replaced by * the new, probably lengthened request. */ -static void -raw3215_mk_write_req(struct raw3215_info *raw) +static void raw3215_mk_write_req(struct raw3215_info *raw) { struct raw3215_req *req; struct ccw1 *ccw; @@ -251,8 +245,7 @@ raw3215_mk_write_req(struct raw3215_info *raw) /* * Start a read or a write request */ -static void -raw3215_start_io(struct raw3215_info *raw) +static void raw3215_start_io(struct raw3215_info *raw) { struct raw3215_req *req; int res; @@ -290,8 +283,7 @@ raw3215_start_io(struct raw3215_info *raw) /* * Function to start a delayed output after RAW3215_TIMEOUT seconds */ -static void -raw3215_timeout(unsigned long __data) +static void raw3215_timeout(unsigned long __data) { struct raw3215_info *raw = (struct raw3215_info *) __data; unsigned long flags; @@ -300,8 +292,10 @@ raw3215_timeout(unsigned long __data) if (raw->flags & RAW3215_TIMER_RUNS) { del_timer(&raw->timer); raw->flags &= ~RAW3215_TIMER_RUNS; - raw3215_mk_write_req(raw); - raw3215_start_io(raw); + if (!(raw->flags & RAW3215_FROZEN)) { + raw3215_mk_write_req(raw); + raw3215_start_io(raw); + } } spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); } @@ -312,10 +306,9 @@ raw3215_timeout(unsigned long __data) * amount of data is bigger than RAW3215_MIN_WRITE. If a write is not * done immediately a timer is started with a delay of RAW3215_TIMEOUT. */ -static inline void -raw3215_try_io(struct raw3215_info *raw) +static inline void raw3215_try_io(struct raw3215_info *raw) { - if (!(raw->flags & RAW3215_ACTIVE)) + if (!(raw->flags & RAW3215_ACTIVE) || (raw->flags & RAW3215_FROZEN)) return; if (raw->queued_read != NULL) raw3215_start_io(raw); @@ -359,8 +352,8 @@ static void raw3215_next_io(struct raw3215_info *raw) /* * Interrupt routine, called from common io layer */ -static void -raw3215_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) +static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm, + struct irb *irb) { struct raw3215_info *raw; struct raw3215_req *req; @@ -368,7 +361,7 @@ raw3215_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) int cstat, dstat; int count; - raw = cdev->dev.driver_data; + raw = dev_get_drvdata(&cdev->dev); req = (struct raw3215_req *) intparm; cstat = irb->scsw.cmd.cstat; dstat = irb->scsw.cmd.dstat; @@ -458,15 +451,41 @@ raw3215_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) return; } +/* + * Drop the oldest line from the output buffer. + */ +static void raw3215_drop_line(struct raw3215_info *raw) +{ + int ix; + char ch; + + BUG_ON(raw->written != 0); + ix = (raw->head - raw->count) & (RAW3215_BUFFER_SIZE - 1); + while (raw->count > 0) { + ch = raw->buffer[ix]; + ix = (ix + 1) & (RAW3215_BUFFER_SIZE - 1); + raw->count--; + if (ch == 0x15) + break; + } + raw->head = ix; +} + /* * Wait until length bytes are available int the output buffer. * Has to be called with the s390irq lock held. Can be called * disabled. */ -static void -raw3215_make_room(struct raw3215_info *raw, unsigned int length) +static void raw3215_make_room(struct raw3215_info *raw, unsigned int length) { while (RAW3215_BUFFER_SIZE - raw->count < length) { + /* While console is frozen for suspend we have no other + * choice but to drop message from the buffer to make + * room for even more messages. */ + if (raw->flags & RAW3215_FROZEN) { + raw3215_drop_line(raw); + continue; + } /* there might be a request pending */ raw->flags |= RAW3215_FLUSHING; raw3215_mk_write_req(raw); @@ -488,8 +507,8 @@ raw3215_make_room(struct raw3215_info *raw, unsigned int length) /* * String write routine for 3215 devices */ -static void -raw3215_write(struct raw3215_info *raw, const char *str, unsigned int length) +static void raw3215_write(struct raw3215_info *raw, const char *str, + unsigned int length) { unsigned long flags; int c, count; @@ -529,8 +548,7 @@ raw3215_write(struct raw3215_info *raw, const char *str, unsigned int length) /* * Put character routine for 3215 devices */ -static void -raw3215_putchar(struct raw3215_info *raw, unsigned char ch) +static void raw3215_putchar(struct raw3215_info *raw, unsigned char ch) { unsigned long flags; unsigned int length, i; @@ -566,8 +584,7 @@ raw3215_putchar(struct raw3215_info *raw, unsigned char ch) * Flush routine, it simply sets the flush flag and tries to start * pending IO. */ -static void -raw3215_flush_buffer(struct raw3215_info *raw) +static void raw3215_flush_buffer(struct raw3215_info *raw) { unsigned long flags; @@ -583,8 +600,7 @@ raw3215_flush_buffer(struct raw3215_info *raw) /* * Fire up a 3215 device. */ -static int -raw3215_startup(struct raw3215_info *raw) +static int raw3215_startup(struct raw3215_info *raw) { unsigned long flags; @@ -602,8 +618,7 @@ raw3215_startup(struct raw3215_info *raw) /* * Shutdown a 3215 device. */ -static void -raw3215_shutdown(struct raw3215_info *raw) +static void raw3215_shutdown(struct raw3215_info *raw) { DECLARE_WAITQUEUE(wait, current); unsigned long flags; @@ -628,14 +643,13 @@ raw3215_shutdown(struct raw3215_info *raw) spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); } -static int -raw3215_probe (struct ccw_device *cdev) +static int raw3215_probe (struct ccw_device *cdev) { struct raw3215_info *raw; int line; /* Console is special. */ - if (raw3215[0] && (cdev->dev.driver_data == raw3215[0])) + if (raw3215[0] && (raw3215[0] == dev_get_drvdata(&cdev->dev))) return 0; raw = kmalloc(sizeof(struct raw3215_info) + RAW3215_INBUF_SIZE, GFP_KERNEL|GFP_DMA); @@ -669,44 +683,41 @@ raw3215_probe (struct ccw_device *cdev) } init_waitqueue_head(&raw->empty_wait); - cdev->dev.driver_data = raw; + dev_set_drvdata(&cdev->dev, raw); cdev->handler = raw3215_irq; return 0; } -static void -raw3215_remove (struct ccw_device *cdev) +static void raw3215_remove (struct ccw_device *cdev) { struct raw3215_info *raw; ccw_device_set_offline(cdev); - raw = cdev->dev.driver_data; + raw = dev_get_drvdata(&cdev->dev); if (raw) { - cdev->dev.driver_data = NULL; + dev_set_drvdata(&cdev->dev, NULL); kfree(raw->buffer); kfree(raw); } } -static int -raw3215_set_online (struct ccw_device *cdev) +static int raw3215_set_online (struct ccw_device *cdev) { struct raw3215_info *raw; - raw = cdev->dev.driver_data; + raw = dev_get_drvdata(&cdev->dev); if (!raw) return -ENODEV; return raw3215_startup(raw); } -static int -raw3215_set_offline (struct ccw_device *cdev) +static int raw3215_set_offline (struct ccw_device *cdev) { struct raw3215_info *raw; - raw = cdev->dev.driver_data; + raw = dev_get_drvdata(&cdev->dev); if (!raw) return -ENODEV; @@ -715,6 +726,36 @@ raw3215_set_offline (struct ccw_device *cdev) return 0; } +static int raw3215_pm_stop(struct ccw_device *cdev) +{ + struct raw3215_info *raw; + unsigned long flags; + + /* Empty the output buffer, then prevent new I/O. */ + raw = dev_get_drvdata(&cdev->dev); + spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); + raw3215_make_room(raw, RAW3215_BUFFER_SIZE); + raw->flags |= RAW3215_FROZEN; + spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); + return 0; +} + +static int raw3215_pm_start(struct ccw_device *cdev) +{ + struct raw3215_info *raw; + unsigned long flags; + + /* Allow I/O again and flush output buffer. */ + raw = dev_get_drvdata(&cdev->dev); + spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); + raw->flags &= ~RAW3215_FROZEN; + raw->flags |= RAW3215_FLUSHING; + raw3215_try_io(raw); + raw->flags &= ~RAW3215_FLUSHING; + spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); + return 0; +} + static struct ccw_device_id raw3215_id[] = { { CCW_DEVICE(0x3215, 0) }, { /* end of list */ }, @@ -728,14 +769,17 @@ static struct ccw_driver raw3215_ccw_driver = { .remove = &raw3215_remove, .set_online = &raw3215_set_online, .set_offline = &raw3215_set_offline, + .freeze = &raw3215_pm_stop, + .thaw = &raw3215_pm_start, + .restore = &raw3215_pm_start, }; #ifdef CONFIG_TN3215_CONSOLE /* * Write a string to the 3215 console */ -static void -con3215_write(struct console *co, const char *str, unsigned int count) +static void con3215_write(struct console *co, const char *str, + unsigned int count) { struct raw3215_info *raw; int i; @@ -768,13 +812,17 @@ static struct tty_driver *con3215_device(struct console *c, int *index) * panic() calls con3215_flush through a panic_notifier * before the system enters a disabled, endless loop. */ -static void -con3215_flush(void) +static void con3215_flush(void) { struct raw3215_info *raw; unsigned long flags; raw = raw3215[0]; /* console 3215 is the first one */ + if (raw->flags & RAW3215_FROZEN) + /* The console is still frozen for suspend. */ + if (ccw_device_force_console()) + /* Forcing didn't work, no panic message .. */ + return; spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); raw3215_make_room(raw, RAW3215_BUFFER_SIZE); spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); @@ -811,8 +859,7 @@ static struct console con3215 = { * 3215 console initialization code called from console_init(). * NOTE: This is called before kmalloc is available. */ -static int __init -con3215_init(void) +static int __init con3215_init(void) { struct ccw_device *cdev; struct raw3215_info *raw; @@ -833,7 +880,7 @@ con3215_init(void) raw3215_freelist = NULL; spin_lock_init(&raw3215_freelist_lock); for (i = 0; i < NR_3215_REQ; i++) { - req = (struct raw3215_req *) alloc_bootmem_low(sizeof(struct raw3215_req)); + req = kzalloc(sizeof(struct raw3215_req), GFP_KERNEL | GFP_DMA); req->next = raw3215_freelist; raw3215_freelist = req; } @@ -843,12 +890,11 @@ con3215_init(void) return -ENODEV; raw3215[0] = raw = (struct raw3215_info *) - alloc_bootmem_low(sizeof(struct raw3215_info)); - memset(raw, 0, sizeof(struct raw3215_info)); - raw->buffer = (char *) alloc_bootmem_low(RAW3215_BUFFER_SIZE); - raw->inbuf = (char *) alloc_bootmem_low(RAW3215_INBUF_SIZE); + kzalloc(sizeof(struct raw3215_info), GFP_KERNEL | GFP_DMA); + raw->buffer = kzalloc(RAW3215_BUFFER_SIZE, GFP_KERNEL | GFP_DMA); + raw->inbuf = kzalloc(RAW3215_INBUF_SIZE, GFP_KERNEL | GFP_DMA); raw->cdev = cdev; - cdev->dev.driver_data = raw; + dev_set_drvdata(&cdev->dev, raw); cdev->handler = raw3215_irq; raw->flags |= RAW3215_FIXED; @@ -856,9 +902,9 @@ con3215_init(void) /* Request the console irq */ if (raw3215_startup(raw) != 0) { - free_bootmem((unsigned long) raw->inbuf, RAW3215_INBUF_SIZE); - free_bootmem((unsigned long) raw->buffer, RAW3215_BUFFER_SIZE); - free_bootmem((unsigned long) raw, sizeof(struct raw3215_info)); + kfree(raw->inbuf); + kfree(raw->buffer); + kfree(raw); raw3215[0] = NULL; return -ENODEV; } @@ -875,8 +921,7 @@ console_initcall(con3215_init); * * This routine is called whenever a 3215 tty is opened. */ -static int -tty3215_open(struct tty_struct *tty, struct file * filp) +static int tty3215_open(struct tty_struct *tty, struct file * filp) { struct raw3215_info *raw; int retval, line; @@ -909,8 +954,7 @@ tty3215_open(struct tty_struct *tty, struct file * filp) * This routine is called when the 3215 tty is closed. We wait * for the remaining request to be completed. Then we clean up. */ -static void -tty3215_close(struct tty_struct *tty, struct file * filp) +static void tty3215_close(struct tty_struct *tty, struct file * filp) { struct raw3215_info *raw; @@ -927,8 +971,7 @@ tty3215_close(struct tty_struct *tty, struct file * filp) /* * Returns the amount of free space in the output buffer. */ -static int -tty3215_write_room(struct tty_struct *tty) +static int tty3215_write_room(struct tty_struct *tty) { struct raw3215_info *raw; @@ -944,9 +987,8 @@ tty3215_write_room(struct tty_struct *tty) /* * String write routine for 3215 ttys */ -static int -tty3215_write(struct tty_struct * tty, - const unsigned char *buf, int count) +static int tty3215_write(struct tty_struct * tty, + const unsigned char *buf, int count) { struct raw3215_info *raw; @@ -960,8 +1002,7 @@ tty3215_write(struct tty_struct * tty, /* * Put character routine for 3215 ttys */ -static int -tty3215_put_char(struct tty_struct *tty, unsigned char ch) +static int tty3215_put_char(struct tty_struct *tty, unsigned char ch) { struct raw3215_info *raw; @@ -972,16 +1013,14 @@ tty3215_put_char(struct tty_struct *tty, unsigned char ch) return 1; } -static void -tty3215_flush_chars(struct tty_struct *tty) +static void tty3215_flush_chars(struct tty_struct *tty) { } /* * Returns the number of characters in the output buffer */ -static int -tty3215_chars_in_buffer(struct tty_struct *tty) +static int tty3215_chars_in_buffer(struct tty_struct *tty) { struct raw3215_info *raw; @@ -989,8 +1028,7 @@ tty3215_chars_in_buffer(struct tty_struct *tty) return raw->count; } -static void -tty3215_flush_buffer(struct tty_struct *tty) +static void tty3215_flush_buffer(struct tty_struct *tty) { struct raw3215_info *raw; @@ -1002,9 +1040,8 @@ tty3215_flush_buffer(struct tty_struct *tty) /* * Currently we don't have any io controls for 3215 ttys */ -static int -tty3215_ioctl(struct tty_struct *tty, struct file * file, - unsigned int cmd, unsigned long arg) +static int tty3215_ioctl(struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg) { if (tty->flags & (1 << TTY_IO_ERROR)) return -EIO; @@ -1019,8 +1056,7 @@ tty3215_ioctl(struct tty_struct *tty, struct file * file, /* * Disable reading from a 3215 tty */ -static void -tty3215_throttle(struct tty_struct * tty) +static void tty3215_throttle(struct tty_struct * tty) { struct raw3215_info *raw; @@ -1031,8 +1067,7 @@ tty3215_throttle(struct tty_struct * tty) /* * Enable reading from a 3215 tty */ -static void -tty3215_unthrottle(struct tty_struct * tty) +static void tty3215_unthrottle(struct tty_struct * tty) { struct raw3215_info *raw; unsigned long flags; @@ -1049,8 +1084,7 @@ tty3215_unthrottle(struct tty_struct * tty) /* * Disable writing to a 3215 tty */ -static void -tty3215_stop(struct tty_struct *tty) +static void tty3215_stop(struct tty_struct *tty) { struct raw3215_info *raw; @@ -1061,8 +1095,7 @@ tty3215_stop(struct tty_struct *tty) /* * Enable writing to a 3215 tty */ -static void -tty3215_start(struct tty_struct *tty) +static void tty3215_start(struct tty_struct *tty) { struct raw3215_info *raw; unsigned long flags; @@ -1096,8 +1129,7 @@ static const struct tty_operations tty3215_ops = { * 3215 tty registration code called from tty_init(). * Most kernel services (incl. kmalloc) are available at this poimt. */ -static int __init -tty3215_init(void) +static int __init tty3215_init(void) { struct tty_driver *driver; int ret; @@ -1142,8 +1174,7 @@ tty3215_init(void) return 0; } -static void __exit -tty3215_exit(void) +static void __exit tty3215_exit(void) { tty_unregister_driver(tty3215_driver); put_tty_driver(tty3215_driver); diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c index d028d2ee83dd..bb838bdf829d 100644 --- a/drivers/s390/char/con3270.c +++ b/drivers/s390/char/con3270.c @@ -1,14 +1,12 @@ /* - * drivers/s390/char/con3270.c - * IBM/3270 Driver - console view. + * IBM/3270 Driver - console view. * - * Author(s): - * Original 3270 Code for 2.4 written by Richard Hitt (UTS Global) - * Rewritten for 2.5 by Martin Schwidefsky - * -- Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Author(s): + * Original 3270 Code for 2.4 written by Richard Hitt (UTS Global) + * Rewritten for 2.5 by Martin Schwidefsky + * Copyright IBM Corp. 2003, 2009 */ -#include #include #include #include @@ -64,7 +62,7 @@ static struct con3270 *condev; #define CON_UPDATE_ERASE 1 /* Use EWRITEA instead of WRITE. */ #define CON_UPDATE_LIST 2 /* Update lines in tty3270->update. */ #define CON_UPDATE_STATUS 4 /* Update status line. */ -#define CON_UPDATE_ALL 7 +#define CON_UPDATE_ALL 8 /* Recreate screen. */ static void con3270_update(struct con3270 *); @@ -73,18 +71,10 @@ static void con3270_update(struct con3270 *); */ static void con3270_set_timer(struct con3270 *cp, int expires) { - if (expires == 0) { - if (timer_pending(&cp->timer)) - del_timer(&cp->timer); - return; - } - if (timer_pending(&cp->timer) && - mod_timer(&cp->timer, jiffies + expires)) - return; - cp->timer.function = (void (*)(unsigned long)) con3270_update; - cp->timer.data = (unsigned long) cp; - cp->timer.expires = jiffies + expires; - add_timer(&cp->timer); + if (expires == 0) + del_timer(&cp->timer); + else + mod_timer(&cp->timer, jiffies + expires); } /* @@ -225,6 +215,12 @@ con3270_update(struct con3270 *cp) spin_lock_irqsave(&cp->view.lock, flags); updated = 0; + if (cp->update_flags & CON_UPDATE_ALL) { + con3270_rebuild_update(cp); + con3270_update_status(cp); + cp->update_flags = CON_UPDATE_ERASE | CON_UPDATE_LIST | + CON_UPDATE_STATUS; + } if (cp->update_flags & CON_UPDATE_ERASE) { /* Use erase write alternate to initialize display. */ raw3270_request_set_cmd(wrq, TC_EWRITEA); @@ -302,7 +298,6 @@ con3270_read_tasklet(struct raw3270_request *rrq) deactivate = 1; break; case 0x6d: /* clear: start from scratch. */ - con3270_rebuild_update(cp); cp->update_flags = CON_UPDATE_ALL; con3270_set_timer(cp, 1); break; @@ -382,30 +377,21 @@ con3270_issue_read(struct con3270 *cp) static int con3270_activate(struct raw3270_view *view) { - unsigned long flags; struct con3270 *cp; cp = (struct con3270 *) view; - spin_lock_irqsave(&cp->view.lock, flags); - cp->nr_up = 0; - con3270_rebuild_update(cp); - con3270_update_status(cp); cp->update_flags = CON_UPDATE_ALL; con3270_set_timer(cp, 1); - spin_unlock_irqrestore(&cp->view.lock, flags); return 0; } static void con3270_deactivate(struct raw3270_view *view) { - unsigned long flags; struct con3270 *cp; cp = (struct con3270 *) view; - spin_lock_irqsave(&cp->view.lock, flags); del_timer(&cp->timer); - spin_unlock_irqrestore(&cp->view.lock, flags); } static int @@ -504,6 +490,7 @@ con3270_write(struct console *co, const char *str, unsigned int count) con3270_cline_end(cp); } /* Setup timer to output current console buffer after 1/10 second */ + cp->nr_up = 0; if (cp->view.dev && !timer_pending(&cp->timer)) con3270_set_timer(cp, HZ/10); spin_unlock_irqrestore(&cp->view.lock,flags); @@ -541,6 +528,7 @@ con3270_flush(void) cp = condev; if (!cp->view.dev) return; + raw3270_pm_unfreeze(&cp->view); spin_lock_irqsave(&cp->view.lock, flags); con3270_wait_write(cp); cp->nr_up = 0; @@ -611,20 +599,19 @@ con3270_init(void) if (IS_ERR(rp)) return PTR_ERR(rp); - condev = (struct con3270 *) alloc_bootmem_low(sizeof(struct con3270)); - memset(condev, 0, sizeof(struct con3270)); + condev = kzalloc(sizeof(struct con3270), GFP_KERNEL | GFP_DMA); condev->view.dev = rp; - condev->read = raw3270_request_alloc_bootmem(0); + condev->read = raw3270_request_alloc(0); condev->read->callback = con3270_read_callback; condev->read->callback_data = condev; - condev->write = - raw3270_request_alloc_bootmem(CON3270_OUTPUT_BUFFER_SIZE); - condev->kreset = raw3270_request_alloc_bootmem(1); + condev->write = raw3270_request_alloc(CON3270_OUTPUT_BUFFER_SIZE); + condev->kreset = raw3270_request_alloc(1); INIT_LIST_HEAD(&condev->lines); INIT_LIST_HEAD(&condev->update); - init_timer(&condev->timer); + setup_timer(&condev->timer, (void (*)(unsigned long)) con3270_update, + (unsigned long) condev); tasklet_init(&condev->readlet, (void (*)(unsigned long)) con3270_read_tasklet, (unsigned long) condev->read); @@ -633,7 +620,7 @@ con3270_init(void) INIT_LIST_HEAD(&condev->freemem); for (i = 0; i < CON3270_STRING_PAGES; i++) { - cbuf = (void *) alloc_bootmem_low_pages(PAGE_SIZE); + cbuf = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA); add_string_memory(&condev->freemem, cbuf, PAGE_SIZE); } condev->cline = alloc_string(&condev->freemem, condev->view.cols); diff --git a/drivers/s390/char/fs3270.c b/drivers/s390/char/fs3270.c index 40759c33477d..097d3846a828 100644 --- a/drivers/s390/char/fs3270.c +++ b/drivers/s390/char/fs3270.c @@ -1,11 +1,10 @@ /* - * drivers/s390/char/fs3270.c - * IBM/3270 Driver - fullscreen driver. + * IBM/3270 Driver - fullscreen driver. * - * Author(s): - * Original 3270 Code for 2.4 written by Richard Hitt (UTS Global) - * Rewritten for 2.5/2.6 by Martin Schwidefsky - * -- Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Author(s): + * Original 3270 Code for 2.4 written by Richard Hitt (UTS Global) + * Rewritten for 2.5/2.6 by Martin Schwidefsky + * Copyright IBM Corp. 2003, 2009 */ #include @@ -399,6 +398,11 @@ fs3270_free_view(struct raw3270_view *view) static void fs3270_release(struct raw3270_view *view) { + struct fs3270 *fp; + + fp = (struct fs3270 *) view; + if (fp->fs_pid) + kill_pid(fp->fs_pid, SIGHUP, 1); } /* View to a 3270 device. Can be console, tty or fullscreen. */ diff --git a/drivers/s390/char/monreader.c b/drivers/s390/char/monreader.c index 97e63cf46944..7892550d7932 100644 --- a/drivers/s390/char/monreader.c +++ b/drivers/s390/char/monreader.c @@ -1,10 +1,9 @@ /* - * drivers/s390/char/monreader.c - * * Character device driver for reading z/VM *MONITOR service records. * - * Copyright IBM Corp. 2004, 2008 - * Author: Gerald Schaefer + * Copyright IBM Corp. 2004, 2009 + * + * Author: Gerald Schaefer */ #define KMSG_COMPONENT "monreader" @@ -22,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -78,6 +78,7 @@ static u8 user_data_sever[16] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, }; +static struct device *monreader_device; /****************************************************************************** * helper functions * @@ -319,11 +320,12 @@ static int mon_open(struct inode *inode, struct file *filp) goto out_path; } filp->private_data = monpriv; + dev_set_drvdata(&monreader_device, monpriv); unlock_kernel(); return nonseekable_open(inode, filp); out_path: - kfree(monpriv->path); + iucv_path_free(monpriv->path); out_priv: mon_free_mem(monpriv); out_use: @@ -341,10 +343,13 @@ static int mon_close(struct inode *inode, struct file *filp) /* * Close IUCV connection and unregister */ - rc = iucv_path_sever(monpriv->path, user_data_sever); - if (rc) - pr_warning("Disconnecting the z/VM *MONITOR system service " - "failed with rc=%i\n", rc); + if (monpriv->path) { + rc = iucv_path_sever(monpriv->path, user_data_sever); + if (rc) + pr_warning("Disconnecting the z/VM *MONITOR system " + "service failed with rc=%i\n", rc); + iucv_path_free(monpriv->path); + } atomic_set(&monpriv->iucv_severed, 0); atomic_set(&monpriv->iucv_connected, 0); @@ -452,6 +457,94 @@ static struct miscdevice mon_dev = { .minor = MISC_DYNAMIC_MINOR, }; + +/****************************************************************************** + * suspend / resume * + *****************************************************************************/ +static int monreader_freeze(struct device *dev) +{ + struct mon_private *monpriv = dev_get_drvdata(&dev); + int rc; + + if (!monpriv) + return 0; + if (monpriv->path) { + rc = iucv_path_sever(monpriv->path, user_data_sever); + if (rc) + pr_warning("Disconnecting the z/VM *MONITOR system " + "service failed with rc=%i\n", rc); + iucv_path_free(monpriv->path); + } + atomic_set(&monpriv->iucv_severed, 0); + atomic_set(&monpriv->iucv_connected, 0); + atomic_set(&monpriv->read_ready, 0); + atomic_set(&monpriv->msglim_count, 0); + monpriv->write_index = 0; + monpriv->read_index = 0; + monpriv->path = NULL; + return 0; +} + +static int monreader_thaw(struct device *dev) +{ + struct mon_private *monpriv = dev_get_drvdata(dev); + int rc; + + if (!monpriv) + return 0; + rc = -ENOMEM; + monpriv->path = iucv_path_alloc(MON_MSGLIM, IUCV_IPRMDATA, GFP_KERNEL); + if (!monpriv->path) + goto out; + rc = iucv_path_connect(monpriv->path, &monreader_iucv_handler, + MON_SERVICE, NULL, user_data_connect, monpriv); + if (rc) { + pr_err("Connecting to the z/VM *MONITOR system service " + "failed with rc=%i\n", rc); + goto out_path; + } + wait_event(mon_conn_wait_queue, + atomic_read(&monpriv->iucv_connected) || + atomic_read(&monpriv->iucv_severed)); + if (atomic_read(&monpriv->iucv_severed)) + goto out_path; + return 0; +out_path: + rc = -EIO; + iucv_path_free(monpriv->path); + monpriv->path = NULL; +out: + atomic_set(&monpriv->iucv_severed, 1); + return rc; +} + +static int monreader_restore(struct device *dev) +{ + int rc; + + segment_unload(mon_dcss_name); + rc = segment_load(mon_dcss_name, SEGMENT_SHARED, + &mon_dcss_start, &mon_dcss_end); + if (rc < 0) { + segment_warning(rc, mon_dcss_name); + panic("fatal monreader resume error: no monitor dcss\n"); + } + return monreader_thaw(dev); +} + +static struct dev_pm_ops monreader_pm_ops = { + .freeze = monreader_freeze, + .thaw = monreader_thaw, + .restore = monreader_restore, +}; + +static struct device_driver monreader_driver = { + .name = "monreader", + .bus = &iucv_bus, + .pm = &monreader_pm_ops, +}; + + /****************************************************************************** * module init/exit * *****************************************************************************/ @@ -475,16 +568,33 @@ static int __init mon_init(void) return rc; } + rc = driver_register(&monreader_driver); + if (rc) + goto out_iucv; + monreader_device = kzalloc(sizeof(struct device), GFP_KERNEL); + if (!monreader_device) + goto out_driver; + dev_set_name(monreader_device, "monreader-dev"); + monreader_device->bus = &iucv_bus; + monreader_device->parent = iucv_root; + monreader_device->driver = &monreader_driver; + monreader_device->release = (void (*)(struct device *))kfree; + rc = device_register(monreader_device); + if (rc) { + kfree(monreader_device); + goto out_driver; + } + rc = segment_type(mon_dcss_name); if (rc < 0) { segment_warning(rc, mon_dcss_name); - goto out_iucv; + goto out_device; } if (rc != SEG_TYPE_SC) { pr_err("The specified *MONITOR DCSS %s does not have the " "required type SC\n", mon_dcss_name); rc = -EINVAL; - goto out_iucv; + goto out_device; } rc = segment_load(mon_dcss_name, SEGMENT_SHARED, @@ -492,7 +602,7 @@ static int __init mon_init(void) if (rc < 0) { segment_warning(rc, mon_dcss_name); rc = -EINVAL; - goto out_iucv; + goto out_device; } dcss_mkname(mon_dcss_name, &user_data_connect[8]); @@ -503,6 +613,10 @@ static int __init mon_init(void) out: segment_unload(mon_dcss_name); +out_device: + device_unregister(monreader_device); +out_driver: + driver_unregister(&monreader_driver); out_iucv: iucv_unregister(&monreader_iucv_handler, 1); return rc; @@ -512,6 +626,8 @@ static void __exit mon_exit(void) { segment_unload(mon_dcss_name); WARN_ON(misc_deregister(&mon_dev) != 0); + device_unregister(monreader_device); + driver_unregister(&monreader_driver); iucv_unregister(&monreader_iucv_handler, 1); return; } diff --git a/drivers/s390/char/monwriter.c b/drivers/s390/char/monwriter.c index c7d7483bab9a..66fb8eba93f4 100644 --- a/drivers/s390/char/monwriter.c +++ b/drivers/s390/char/monwriter.c @@ -1,9 +1,7 @@ /* - * drivers/s390/char/monwriter.c - * * Character device driver for writing z/VM *MONITOR service records. * - * Copyright (C) IBM Corp. 2006 + * Copyright IBM Corp. 2006, 2009 * * Author(s): Melissa Howland */ @@ -22,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -40,7 +39,10 @@ struct mon_buf { char *data; }; +static LIST_HEAD(mon_priv_list); + struct mon_private { + struct list_head priv_list; struct list_head list; struct monwrite_hdr hdr; size_t hdr_to_read; @@ -188,6 +190,7 @@ static int monwrite_open(struct inode *inode, struct file *filp) monpriv->hdr_to_read = sizeof(monpriv->hdr); mutex_init(&monpriv->thread_mutex); filp->private_data = monpriv; + list_add_tail(&monpriv->priv_list, &mon_priv_list); unlock_kernel(); return nonseekable_open(inode, filp); } @@ -206,6 +209,7 @@ static int monwrite_close(struct inode *inode, struct file *filp) kfree(entry->data); kfree(entry); } + list_del(&monpriv->priv_list); kfree(monpriv); return 0; } @@ -280,21 +284,103 @@ static struct miscdevice mon_dev = { .minor = MISC_DYNAMIC_MINOR, }; +/* + * suspend/resume + */ + +static int monwriter_freeze(struct device *dev) +{ + struct mon_private *monpriv; + struct mon_buf *monbuf; + + list_for_each_entry(monpriv, &mon_priv_list, priv_list) { + list_for_each_entry(monbuf, &monpriv->list, list) { + if (monbuf->hdr.mon_function != MONWRITE_GEN_EVENT) + monwrite_diag(&monbuf->hdr, monbuf->data, + APPLDATA_STOP_REC); + } + } + return 0; +} + +static int monwriter_restore(struct device *dev) +{ + struct mon_private *monpriv; + struct mon_buf *monbuf; + + list_for_each_entry(monpriv, &mon_priv_list, priv_list) { + list_for_each_entry(monbuf, &monpriv->list, list) { + if (monbuf->hdr.mon_function == MONWRITE_START_INTERVAL) + monwrite_diag(&monbuf->hdr, monbuf->data, + APPLDATA_START_INTERVAL_REC); + if (monbuf->hdr.mon_function == MONWRITE_START_CONFIG) + monwrite_diag(&monbuf->hdr, monbuf->data, + APPLDATA_START_CONFIG_REC); + } + } + return 0; +} + +static int monwriter_thaw(struct device *dev) +{ + return monwriter_restore(dev); +} + +static struct dev_pm_ops monwriter_pm_ops = { + .freeze = monwriter_freeze, + .thaw = monwriter_thaw, + .restore = monwriter_restore, +}; + +static struct platform_driver monwriter_pdrv = { + .driver = { + .name = "monwriter", + .owner = THIS_MODULE, + .pm = &monwriter_pm_ops, + }, +}; + +static struct platform_device *monwriter_pdev; + /* * module init/exit */ static int __init mon_init(void) { - if (MACHINE_IS_VM) - return misc_register(&mon_dev); - else + int rc; + + if (!MACHINE_IS_VM) return -ENODEV; + + rc = platform_driver_register(&monwriter_pdrv); + if (rc) + return rc; + + monwriter_pdev = platform_device_register_simple("monwriter", -1, NULL, + 0); + if (IS_ERR(monwriter_pdev)) { + rc = PTR_ERR(monwriter_pdev); + goto out_driver; + } + + rc = misc_register(&mon_dev); + if (rc) + goto out_device; + return 0; + +out_device: + platform_device_unregister(monwriter_pdev); +out_driver: + platform_driver_unregister(&monwriter_pdrv); + return rc; } static void __exit mon_exit(void) { WARN_ON(misc_deregister(&mon_dev) != 0); + platform_device_unregister(monwriter_pdev); + platform_driver_unregister(&monwriter_pdrv); } module_init(mon_init); diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c index 0b15cf107ec9..d6a022f55e92 100644 --- a/drivers/s390/char/raw3270.c +++ b/drivers/s390/char/raw3270.c @@ -1,14 +1,12 @@ /* - * drivers/s390/char/raw3270.c - * IBM/3270 Driver - core functions. + * IBM/3270 Driver - core functions. * - * Author(s): - * Original 3270 Code for 2.4 written by Richard Hitt (UTS Global) - * Rewritten for 2.5 by Martin Schwidefsky - * -- Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Author(s): + * Original 3270 Code for 2.4 written by Richard Hitt (UTS Global) + * Rewritten for 2.5 by Martin Schwidefsky + * Copyright IBM Corp. 2003, 2009 */ -#include #include #include #include @@ -61,6 +59,7 @@ struct raw3270 { #define RAW3270_FLAGS_ATTN 2 /* Device sent an ATTN interrupt */ #define RAW3270_FLAGS_READY 4 /* Device is useable by views */ #define RAW3270_FLAGS_CONSOLE 8 /* Device is the console. */ +#define RAW3270_FLAGS_FROZEN 16 /* set if 3270 is frozen for suspend */ /* Semaphore to protect global data of raw3270 (devices, views, etc). */ static DEFINE_MUTEX(raw3270_mutex); @@ -143,33 +142,6 @@ raw3270_request_alloc(size_t size) return rq; } -#ifdef CONFIG_TN3270_CONSOLE -/* - * Allocate a new 3270 ccw request from bootmem. Only works very - * early in the boot process. Only con3270.c should be using this. - */ -struct raw3270_request __init *raw3270_request_alloc_bootmem(size_t size) -{ - struct raw3270_request *rq; - - rq = alloc_bootmem_low(sizeof(struct raw3270)); - - /* alloc output buffer. */ - if (size > 0) - rq->buffer = alloc_bootmem_low(size); - rq->size = size; - INIT_LIST_HEAD(&rq->list); - - /* - * Setup ccw. - */ - rq->ccw.cda = __pa(rq->buffer); - rq->ccw.flags = CCW_FLAG_SLI; - - return rq; -} -#endif - /* * Free 3270 ccw request */ @@ -306,7 +278,8 @@ raw3270_start(struct raw3270_view *view, struct raw3270_request *rq) spin_lock_irqsave(get_ccwdev_lock(view->dev->cdev), flags); rp = view->dev; - if (!rp || rp->view != view) + if (!rp || rp->view != view || + test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) rc = -EACCES; else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags)) rc = -ENODEV; @@ -323,7 +296,8 @@ raw3270_start_locked(struct raw3270_view *view, struct raw3270_request *rq) int rc; rp = view->dev; - if (!rp || rp->view != view) + if (!rp || rp->view != view || + test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) rc = -EACCES; else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags)) rc = -ENODEV; @@ -355,7 +329,7 @@ raw3270_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb) struct raw3270_request *rq; int rc; - rp = (struct raw3270 *) cdev->dev.driver_data; + rp = dev_get_drvdata(&cdev->dev); if (!rp) return; rq = (struct raw3270_request *) intparm; @@ -764,7 +738,8 @@ raw3270_reset(struct raw3270_view *view) int rc; rp = view->dev; - if (!rp || rp->view != view) + if (!rp || rp->view != view || + test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) rc = -EACCES; else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags)) rc = -ENODEV; @@ -828,7 +803,7 @@ raw3270_setup_device(struct ccw_device *cdev, struct raw3270 *rp, char *ascebc) if (rp->minor == -1) return -EUSERS; rp->cdev = cdev; - cdev->dev.driver_data = rp; + dev_set_drvdata(&cdev->dev, rp); cdev->handler = raw3270_irq; return 0; } @@ -843,8 +818,8 @@ struct raw3270 __init *raw3270_setup_console(struct ccw_device *cdev) char *ascebc; int rc; - rp = (struct raw3270 *) alloc_bootmem_low(sizeof(struct raw3270)); - ascebc = (char *) alloc_bootmem(256); + rp = kzalloc(sizeof(struct raw3270), GFP_KERNEL | GFP_DMA); + ascebc = kzalloc(256, GFP_KERNEL); rc = raw3270_setup_device(cdev, rp, ascebc); if (rc) return ERR_PTR(rc); @@ -922,6 +897,8 @@ raw3270_activate_view(struct raw3270_view *view) rc = 0; else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags)) rc = -ENODEV; + else if (test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) + rc = -EACCES; else { oldview = NULL; if (rp->view) { @@ -969,7 +946,8 @@ raw3270_deactivate_view(struct raw3270_view *view) list_del_init(&view->list); list_add_tail(&view->list, &rp->view_list); /* Try to activate another view. */ - if (test_bit(RAW3270_FLAGS_READY, &rp->flags)) { + if (test_bit(RAW3270_FLAGS_READY, &rp->flags) && + !test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) { list_for_each_entry(view, &rp->view_list, list) { rp->view = view; if (view->fn->activate(view) == 0) @@ -1068,7 +1046,8 @@ raw3270_del_view(struct raw3270_view *view) rp->view = NULL; } list_del_init(&view->list); - if (!rp->view && test_bit(RAW3270_FLAGS_READY, &rp->flags)) { + if (!rp->view && test_bit(RAW3270_FLAGS_READY, &rp->flags) && + !test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) { /* Try to activate another view. */ list_for_each_entry(nv, &rp->view_list, list) { if (nv->fn->activate(nv) == 0) { @@ -1105,7 +1084,7 @@ raw3270_delete_device(struct raw3270 *rp) /* Disconnect from ccw_device. */ cdev = rp->cdev; rp->cdev = NULL; - cdev->dev.driver_data = NULL; + dev_set_drvdata(&cdev->dev, NULL); cdev->handler = NULL; /* Put ccw_device structure. */ @@ -1129,7 +1108,7 @@ static ssize_t raw3270_model_show(struct device *dev, struct device_attribute *attr, char *buf) { return snprintf(buf, PAGE_SIZE, "%i\n", - ((struct raw3270 *) dev->driver_data)->model); + ((struct raw3270 *) dev_get_drvdata(dev))->model); } static DEVICE_ATTR(model, 0444, raw3270_model_show, NULL); @@ -1137,7 +1116,7 @@ static ssize_t raw3270_rows_show(struct device *dev, struct device_attribute *attr, char *buf) { return snprintf(buf, PAGE_SIZE, "%i\n", - ((struct raw3270 *) dev->driver_data)->rows); + ((struct raw3270 *) dev_get_drvdata(dev))->rows); } static DEVICE_ATTR(rows, 0444, raw3270_rows_show, NULL); @@ -1145,7 +1124,7 @@ static ssize_t raw3270_columns_show(struct device *dev, struct device_attribute *attr, char *buf) { return snprintf(buf, PAGE_SIZE, "%i\n", - ((struct raw3270 *) dev->driver_data)->cols); + ((struct raw3270 *) dev_get_drvdata(dev))->cols); } static DEVICE_ATTR(columns, 0444, raw3270_columns_show, NULL); @@ -1282,7 +1261,7 @@ raw3270_remove (struct ccw_device *cdev) struct raw3270_view *v; struct raw3270_notifier *np; - rp = cdev->dev.driver_data; + rp = dev_get_drvdata(&cdev->dev); /* * _remove is the opposite of _probe; it's probe that * should set up rp. raw3270_remove gets entered for @@ -1330,13 +1309,65 @@ raw3270_set_offline (struct ccw_device *cdev) { struct raw3270 *rp; - rp = cdev->dev.driver_data; + rp = dev_get_drvdata(&cdev->dev); if (test_bit(RAW3270_FLAGS_CONSOLE, &rp->flags)) return -EBUSY; raw3270_remove(cdev); return 0; } +static int raw3270_pm_stop(struct ccw_device *cdev) +{ + struct raw3270 *rp; + struct raw3270_view *view; + unsigned long flags; + + rp = dev_get_drvdata(&cdev->dev); + if (!rp) + return 0; + spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags); + if (rp->view) + rp->view->fn->deactivate(rp->view); + if (!test_bit(RAW3270_FLAGS_CONSOLE, &rp->flags)) { + /* + * Release tty and fullscreen for all non-console + * devices. + */ + list_for_each_entry(view, &rp->view_list, list) { + if (view->fn->release) + view->fn->release(view); + } + } + set_bit(RAW3270_FLAGS_FROZEN, &rp->flags); + spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags); + return 0; +} + +static int raw3270_pm_start(struct ccw_device *cdev) +{ + struct raw3270 *rp; + unsigned long flags; + + rp = dev_get_drvdata(&cdev->dev); + if (!rp) + return 0; + spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags); + clear_bit(RAW3270_FLAGS_FROZEN, &rp->flags); + if (rp->view) + rp->view->fn->activate(rp->view); + spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags); + return 0; +} + +void raw3270_pm_unfreeze(struct raw3270_view *view) +{ + struct raw3270 *rp; + + rp = view->dev; + if (rp && test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) + ccw_device_force_console(); +} + static struct ccw_device_id raw3270_id[] = { { CCW_DEVICE(0x3270, 0) }, { CCW_DEVICE(0x3271, 0) }, @@ -1360,6 +1391,9 @@ static struct ccw_driver raw3270_ccw_driver = { .remove = &raw3270_remove, .set_online = &raw3270_set_online, .set_offline = &raw3270_set_offline, + .freeze = &raw3270_pm_stop, + .thaw = &raw3270_pm_start, + .restore = &raw3270_pm_start, }; static int diff --git a/drivers/s390/char/raw3270.h b/drivers/s390/char/raw3270.h index 90beaa80a782..ed34eb2199cc 100644 --- a/drivers/s390/char/raw3270.h +++ b/drivers/s390/char/raw3270.h @@ -1,11 +1,10 @@ /* - * drivers/s390/char/raw3270.h - * IBM/3270 Driver + * IBM/3270 Driver * - * Author(s): - * Original 3270 Code for 2.4 written by Richard Hitt (UTS Global) - * Rewritten for 2.5 by Martin Schwidefsky - * -- Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Author(s): + * Original 3270 Code for 2.4 written by Richard Hitt (UTS Global) + * Rewritten for 2.5 by Martin Schwidefsky + * Copyright IBM Corp. 2003, 2009 */ #include @@ -195,6 +194,7 @@ void raw3270_wait_cons_dev(struct raw3270 *); /* Notifier for device addition/removal */ int raw3270_register_notifier(void (*notifier)(int, int)); void raw3270_unregister_notifier(void (*notifier)(int, int)); +void raw3270_pm_unfreeze(struct raw3270_view *); /* * Little memory allocator for string objects. diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c index 4377e93a43d7..a983f5086788 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c @@ -1,11 +1,10 @@ /* - * drivers/s390/char/sclp.c - * core function to access sclp interface + * core function to access sclp interface * - * S390 version - * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Martin Peschke - * Martin Schwidefsky + * Copyright IBM Corp. 1999, 2009 + * + * Author(s): Martin Peschke + * Martin Schwidefsky */ #include @@ -16,6 +15,9 @@ #include #include #include +#include +#include +#include #include #include @@ -47,6 +49,16 @@ static struct sclp_req sclp_init_req; static char sclp_read_sccb[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); static char sclp_init_sccb[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); +/* Suspend request */ +static DECLARE_COMPLETION(sclp_request_queue_flushed); + +static void sclp_suspend_req_cb(struct sclp_req *req, void *data) +{ + complete(&sclp_request_queue_flushed); +} + +static struct sclp_req sclp_suspend_req; + /* Timer for request retries. */ static struct timer_list sclp_request_timer; @@ -84,6 +96,12 @@ static volatile enum sclp_mask_state_t { sclp_mask_state_initializing } sclp_mask_state = sclp_mask_state_idle; +/* Internal state: is the driver suspended? */ +static enum sclp_suspend_state_t { + sclp_suspend_state_running, + sclp_suspend_state_suspended, +} sclp_suspend_state = sclp_suspend_state_running; + /* Maximum retry counts */ #define SCLP_INIT_RETRY 3 #define SCLP_MASK_RETRY 3 @@ -211,6 +229,8 @@ sclp_process_queue(void) del_timer(&sclp_request_timer); while (!list_empty(&sclp_req_queue)) { req = list_entry(sclp_req_queue.next, struct sclp_req, list); + if (!req->sccb) + goto do_post; rc = __sclp_start_request(req); if (rc == 0) break; @@ -222,6 +242,7 @@ sclp_process_queue(void) sclp_request_timeout, 0); break; } +do_post: /* Post-processing for aborted request */ list_del(&req->list); if (req->callback) { @@ -233,6 +254,19 @@ sclp_process_queue(void) spin_unlock_irqrestore(&sclp_lock, flags); } +static int __sclp_can_add_request(struct sclp_req *req) +{ + if (req == &sclp_suspend_req || req == &sclp_init_req) + return 1; + if (sclp_suspend_state != sclp_suspend_state_running) + return 0; + if (sclp_init_state != sclp_init_state_initialized) + return 0; + if (sclp_activation_state != sclp_activation_state_active) + return 0; + return 1; +} + /* Queue a new request. Return zero on success, non-zero otherwise. */ int sclp_add_request(struct sclp_req *req) @@ -241,9 +275,7 @@ sclp_add_request(struct sclp_req *req) int rc; spin_lock_irqsave(&sclp_lock, flags); - if ((sclp_init_state != sclp_init_state_initialized || - sclp_activation_state != sclp_activation_state_active) && - req != &sclp_init_req) { + if (!__sclp_can_add_request(req)) { spin_unlock_irqrestore(&sclp_lock, flags); return -EIO; } @@ -254,10 +286,16 @@ sclp_add_request(struct sclp_req *req) /* Start if request is first in list */ if (sclp_running_state == sclp_running_state_idle && req->list.prev == &sclp_req_queue) { + if (!req->sccb) { + list_del(&req->list); + rc = -ENODATA; + goto out; + } rc = __sclp_start_request(req); if (rc) list_del(&req->list); } +out: spin_unlock_irqrestore(&sclp_lock, flags); return rc; } @@ -560,6 +598,7 @@ sclp_register(struct sclp_register *reg) /* Trigger initial state change callback */ reg->sclp_receive_mask = 0; reg->sclp_send_mask = 0; + reg->pm_event_posted = 0; list_add(®->list, &sclp_reg_list); spin_unlock_irqrestore(&sclp_lock, flags); rc = sclp_init_mask(1); @@ -880,20 +919,134 @@ static struct notifier_block sclp_reboot_notifier = { .notifier_call = sclp_reboot_event }; +/* + * Suspend/resume SCLP notifier implementation + */ + +static void sclp_pm_event(enum sclp_pm_event sclp_pm_event, int rollback) +{ + struct sclp_register *reg; + unsigned long flags; + + if (!rollback) { + spin_lock_irqsave(&sclp_lock, flags); + list_for_each_entry(reg, &sclp_reg_list, list) + reg->pm_event_posted = 0; + spin_unlock_irqrestore(&sclp_lock, flags); + } + do { + spin_lock_irqsave(&sclp_lock, flags); + list_for_each_entry(reg, &sclp_reg_list, list) { + if (rollback && reg->pm_event_posted) + goto found; + if (!rollback && !reg->pm_event_posted) + goto found; + } + spin_unlock_irqrestore(&sclp_lock, flags); + return; +found: + spin_unlock_irqrestore(&sclp_lock, flags); + if (reg->pm_event_fn) + reg->pm_event_fn(reg, sclp_pm_event); + reg->pm_event_posted = rollback ? 0 : 1; + } while (1); +} + +/* + * Susend/resume callbacks for platform device + */ + +static int sclp_freeze(struct device *dev) +{ + unsigned long flags; + int rc; + + sclp_pm_event(SCLP_PM_EVENT_FREEZE, 0); + + spin_lock_irqsave(&sclp_lock, flags); + sclp_suspend_state = sclp_suspend_state_suspended; + spin_unlock_irqrestore(&sclp_lock, flags); + + /* Init supend data */ + memset(&sclp_suspend_req, 0, sizeof(sclp_suspend_req)); + sclp_suspend_req.callback = sclp_suspend_req_cb; + sclp_suspend_req.status = SCLP_REQ_FILLED; + init_completion(&sclp_request_queue_flushed); + + rc = sclp_add_request(&sclp_suspend_req); + if (rc == 0) + wait_for_completion(&sclp_request_queue_flushed); + else if (rc != -ENODATA) + goto fail_thaw; + + rc = sclp_deactivate(); + if (rc) + goto fail_thaw; + return 0; + +fail_thaw: + spin_lock_irqsave(&sclp_lock, flags); + sclp_suspend_state = sclp_suspend_state_running; + spin_unlock_irqrestore(&sclp_lock, flags); + sclp_pm_event(SCLP_PM_EVENT_THAW, 1); + return rc; +} + +static int sclp_undo_suspend(enum sclp_pm_event event) +{ + unsigned long flags; + int rc; + + rc = sclp_reactivate(); + if (rc) + return rc; + + spin_lock_irqsave(&sclp_lock, flags); + sclp_suspend_state = sclp_suspend_state_running; + spin_unlock_irqrestore(&sclp_lock, flags); + + sclp_pm_event(event, 0); + return 0; +} + +static int sclp_thaw(struct device *dev) +{ + return sclp_undo_suspend(SCLP_PM_EVENT_THAW); +} + +static int sclp_restore(struct device *dev) +{ + return sclp_undo_suspend(SCLP_PM_EVENT_RESTORE); +} + +static struct dev_pm_ops sclp_pm_ops = { + .freeze = sclp_freeze, + .thaw = sclp_thaw, + .restore = sclp_restore, +}; + +static struct platform_driver sclp_pdrv = { + .driver = { + .name = "sclp", + .owner = THIS_MODULE, + .pm = &sclp_pm_ops, + }, +}; + +static struct platform_device *sclp_pdev; + /* Initialize SCLP driver. Return zero if driver is operational, non-zero * otherwise. */ static int sclp_init(void) { unsigned long flags; - int rc; + int rc = 0; spin_lock_irqsave(&sclp_lock, flags); /* Check for previous or running initialization */ - if (sclp_init_state != sclp_init_state_uninitialized) { - spin_unlock_irqrestore(&sclp_lock, flags); - return 0; - } + if (sclp_init_state != sclp_init_state_uninitialized) + goto fail_unlock; sclp_init_state = sclp_init_state_initializing; /* Set up variables */ INIT_LIST_HEAD(&sclp_req_queue); @@ -904,27 +1057,17 @@ sclp_init(void) spin_unlock_irqrestore(&sclp_lock, flags); rc = sclp_check_interface(); spin_lock_irqsave(&sclp_lock, flags); - if (rc) { - sclp_init_state = sclp_init_state_uninitialized; - spin_unlock_irqrestore(&sclp_lock, flags); - return rc; - } + if (rc) + goto fail_init_state_uninitialized; /* Register reboot handler */ rc = register_reboot_notifier(&sclp_reboot_notifier); - if (rc) { - sclp_init_state = sclp_init_state_uninitialized; - spin_unlock_irqrestore(&sclp_lock, flags); - return rc; - } + if (rc) + goto fail_init_state_uninitialized; /* Register interrupt handler */ rc = register_early_external_interrupt(0x2401, sclp_interrupt_handler, &ext_int_info_hwc); - if (rc) { - unregister_reboot_notifier(&sclp_reboot_notifier); - sclp_init_state = sclp_init_state_uninitialized; - spin_unlock_irqrestore(&sclp_lock, flags); - return rc; - } + if (rc) + goto fail_unregister_reboot_notifier; sclp_init_state = sclp_init_state_initialized; spin_unlock_irqrestore(&sclp_lock, flags); /* Enable service-signal external interruption - needs to happen with @@ -932,11 +1075,56 @@ sclp_init(void) ctl_set_bit(0, 9); sclp_init_mask(1); return 0; + +fail_unregister_reboot_notifier: + unregister_reboot_notifier(&sclp_reboot_notifier); +fail_init_state_uninitialized: + sclp_init_state = sclp_init_state_uninitialized; +fail_unlock: + spin_unlock_irqrestore(&sclp_lock, flags); + return rc; } +/* + * SCLP panic notifier: If we are suspended, we thaw SCLP in order to be able + * to print the panic message. + */ +static int sclp_panic_notify(struct notifier_block *self, + unsigned long event, void *data) +{ + if (sclp_suspend_state == sclp_suspend_state_suspended) + sclp_undo_suspend(SCLP_PM_EVENT_THAW); + return NOTIFY_OK; +} + +static struct notifier_block sclp_on_panic_nb = { + .notifier_call = sclp_panic_notify, + .priority = SCLP_PANIC_PRIO, +}; + static __init int sclp_initcall(void) { + int rc; + + rc = platform_driver_register(&sclp_pdrv); + if (rc) + return rc; + sclp_pdev = platform_device_register_simple("sclp", -1, NULL, 0); + rc = IS_ERR(sclp_pdev) ? PTR_ERR(sclp_pdev) : 0; + if (rc) + goto fail_platform_driver_unregister; + rc = atomic_notifier_chain_register(&panic_notifier_list, + &sclp_on_panic_nb); + if (rc) + goto fail_platform_device_unregister; + return sclp_init(); + +fail_platform_device_unregister: + platform_device_unregister(sclp_pdev); +fail_platform_driver_unregister: + platform_driver_unregister(&sclp_pdrv); + return rc; } arch_initcall(sclp_initcall); diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h index bac80e856f97..60e7cb07095b 100644 --- a/drivers/s390/char/sclp.h +++ b/drivers/s390/char/sclp.h @@ -1,10 +1,8 @@ /* - * drivers/s390/char/sclp.h + * Copyright IBM Corp. 1999, 2009 * - * S390 version - * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Martin Peschke - * Martin Schwidefsky + * Author(s): Martin Peschke + * Martin Schwidefsky */ #ifndef __SCLP_H__ @@ -17,7 +15,7 @@ /* maximum number of pages concerning our own memory management */ #define MAX_KMEM_PAGES (sizeof(unsigned long) << 3) -#define MAX_CONSOLE_PAGES 4 +#define MAX_CONSOLE_PAGES 6 #define EVTYP_OPCMD 0x01 #define EVTYP_MSG 0x02 @@ -68,6 +66,15 @@ typedef unsigned int sclp_cmdw_t; #define GDS_KEY_SELFDEFTEXTMSG 0x31 +enum sclp_pm_event { + SCLP_PM_EVENT_FREEZE, + SCLP_PM_EVENT_THAW, + SCLP_PM_EVENT_RESTORE, +}; + +#define SCLP_PANIC_PRIO 1 +#define SCLP_PANIC_PRIO_CLIENT 0 + typedef u32 sccb_mask_t; /* ATTENTION: assumes 32bit mask !!! */ struct sccb_header { @@ -134,6 +141,10 @@ struct sclp_register { void (*state_change_fn)(struct sclp_register *); /* called for events in cp_receive_mask/sclp_receive_mask */ void (*receiver_fn)(struct evbuf_header *); + /* called for power management events */ + void (*pm_event_fn)(struct sclp_register *, enum sclp_pm_event); + /* pm event posted flag */ + int pm_event_posted; }; /* externals from sclp.c */ diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c index 77ab6e34a100..5cc11c636d38 100644 --- a/drivers/s390/char/sclp_cmd.c +++ b/drivers/s390/char/sclp_cmd.c @@ -1,9 +1,8 @@ /* - * drivers/s390/char/sclp_cmd.c + * Copyright IBM Corp. 2007, 2009 * - * Copyright IBM Corp. 2007 - * Author(s): Heiko Carstens , - * Peter Oberparleiter + * Author(s): Heiko Carstens , + * Peter Oberparleiter */ #define KMSG_COMPONENT "sclp_cmd" @@ -12,11 +11,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -292,6 +293,7 @@ static DEFINE_MUTEX(sclp_mem_mutex); static LIST_HEAD(sclp_mem_list); static u8 sclp_max_storage_id; static unsigned long sclp_storage_ids[256 / BITS_PER_LONG]; +static int sclp_mem_state_changed; struct memory_increment { struct list_head list; @@ -450,6 +452,8 @@ static int sclp_mem_notifier(struct notifier_block *nb, rc = -EINVAL; break; } + if (!rc) + sclp_mem_state_changed = 1; mutex_unlock(&sclp_mem_mutex); return rc ? NOTIFY_BAD : NOTIFY_OK; } @@ -525,6 +529,14 @@ static void __init insert_increment(u16 rn, int standby, int assigned) list_add(&new_incr->list, prev); } +static int sclp_mem_freeze(struct device *dev) +{ + if (!sclp_mem_state_changed) + return 0; + pr_err("Memory hotplug state changed, suspend refused.\n"); + return -EPERM; +} + struct read_storage_sccb { struct sccb_header header; u16 max_id; @@ -534,8 +546,20 @@ struct read_storage_sccb { u32 entries[0]; } __packed; +static struct dev_pm_ops sclp_mem_pm_ops = { + .freeze = sclp_mem_freeze, +}; + +static struct platform_driver sclp_mem_pdrv = { + .driver = { + .name = "sclp_mem", + .pm = &sclp_mem_pm_ops, + }, +}; + static int __init sclp_detect_standby_memory(void) { + struct platform_device *sclp_pdev; struct read_storage_sccb *sccb; int i, id, assigned, rc; @@ -588,7 +612,17 @@ static int __init sclp_detect_standby_memory(void) rc = register_memory_notifier(&sclp_mem_nb); if (rc) goto out; + rc = platform_driver_register(&sclp_mem_pdrv); + if (rc) + goto out; + sclp_pdev = platform_device_register_simple("sclp_mem", -1, NULL, 0); + rc = IS_ERR(sclp_pdev) ? PTR_ERR(sclp_pdev) : 0; + if (rc) + goto out_driver; sclp_add_standby_memory(); + goto out; +out_driver: + platform_driver_unregister(&sclp_mem_pdrv); out: free_page((unsigned long) sccb); return rc; diff --git a/drivers/s390/char/sclp_con.c b/drivers/s390/char/sclp_con.c index 9a25c4bd1421..ad698d30cb3b 100644 --- a/drivers/s390/char/sclp_con.c +++ b/drivers/s390/char/sclp_con.c @@ -1,11 +1,9 @@ /* - * drivers/s390/char/sclp_con.c - * SCLP line mode console driver + * SCLP line mode console driver * - * S390 version - * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Martin Peschke - * Martin Schwidefsky + * Copyright IBM Corp. 1999, 2009 + * Author(s): Martin Peschke + * Martin Schwidefsky */ #include @@ -13,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -32,13 +29,14 @@ static spinlock_t sclp_con_lock; static struct list_head sclp_con_pages; /* List of full struct sclp_buffer structures ready for output */ static struct list_head sclp_con_outqueue; -/* Counter how many buffers are emitted (max 1) and how many */ -/* are on the output queue. */ -static int sclp_con_buffer_count; /* Pointer to current console buffer */ static struct sclp_buffer *sclp_conbuf; /* Timer for delayed output of console messages */ static struct timer_list sclp_con_timer; +/* Suspend mode flag */ +static int sclp_con_suspended; +/* Flag that output queue is currently running */ +static int sclp_con_queue_running; /* Output format for console messages */ static unsigned short sclp_con_columns; @@ -53,42 +51,71 @@ sclp_conbuf_callback(struct sclp_buffer *buffer, int rc) do { page = sclp_unmake_buffer(buffer); spin_lock_irqsave(&sclp_con_lock, flags); + /* Remove buffer from outqueue */ list_del(&buffer->list); - sclp_con_buffer_count--; list_add_tail((struct list_head *) page, &sclp_con_pages); + /* Check if there is a pending buffer on the out queue. */ buffer = NULL; if (!list_empty(&sclp_con_outqueue)) - buffer = list_entry(sclp_con_outqueue.next, - struct sclp_buffer, list); + buffer = list_first_entry(&sclp_con_outqueue, + struct sclp_buffer, list); + if (!buffer || sclp_con_suspended) { + sclp_con_queue_running = 0; + spin_unlock_irqrestore(&sclp_con_lock, flags); + break; + } spin_unlock_irqrestore(&sclp_con_lock, flags); - } while (buffer && sclp_emit_buffer(buffer, sclp_conbuf_callback)); + } while (sclp_emit_buffer(buffer, sclp_conbuf_callback)); } -static void -sclp_conbuf_emit(void) +/* + * Finalize and emit first pending buffer. + */ +static void sclp_conbuf_emit(void) { struct sclp_buffer* buffer; unsigned long flags; - int count; int rc; spin_lock_irqsave(&sclp_con_lock, flags); - buffer = sclp_conbuf; + if (sclp_conbuf) + list_add_tail(&sclp_conbuf->list, &sclp_con_outqueue); sclp_conbuf = NULL; - if (buffer == NULL) { - spin_unlock_irqrestore(&sclp_con_lock, flags); - return; - } - list_add_tail(&buffer->list, &sclp_con_outqueue); - count = sclp_con_buffer_count++; + if (sclp_con_queue_running || sclp_con_suspended) + goto out_unlock; + if (list_empty(&sclp_con_outqueue)) + goto out_unlock; + buffer = list_first_entry(&sclp_con_outqueue, struct sclp_buffer, + list); + sclp_con_queue_running = 1; spin_unlock_irqrestore(&sclp_con_lock, flags); - if (count) - return; + rc = sclp_emit_buffer(buffer, sclp_conbuf_callback); if (rc) sclp_conbuf_callback(buffer, rc); + return; +out_unlock: + spin_unlock_irqrestore(&sclp_con_lock, flags); +} + +/* + * Wait until out queue is empty + */ +static void sclp_console_sync_queue(void) +{ + unsigned long flags; + + spin_lock_irqsave(&sclp_con_lock, flags); + if (timer_pending(&sclp_con_timer)) + del_timer(&sclp_con_timer); + while (sclp_con_queue_running) { + spin_unlock_irqrestore(&sclp_con_lock, flags); + sclp_sync_wait(); + spin_lock_irqsave(&sclp_con_lock, flags); + } + spin_unlock_irqrestore(&sclp_con_lock, flags); } /* @@ -123,6 +150,8 @@ sclp_console_write(struct console *console, const char *message, /* make sure we have a console output buffer */ if (sclp_conbuf == NULL) { while (list_empty(&sclp_con_pages)) { + if (sclp_con_suspended) + goto out; spin_unlock_irqrestore(&sclp_con_lock, flags); sclp_sync_wait(); spin_lock_irqsave(&sclp_con_lock, flags); @@ -157,6 +186,7 @@ sclp_console_write(struct console *console, const char *message, sclp_con_timer.expires = jiffies + HZ/10; add_timer(&sclp_con_timer); } +out: spin_unlock_irqrestore(&sclp_con_lock, flags); } @@ -168,30 +198,43 @@ sclp_console_device(struct console *c, int *index) } /* - * This routine is called from panic when the kernel - * is going to give up. We have to make sure that all buffers - * will be flushed to the SCLP. + * Make sure that all buffers will be flushed to the SCLP. */ static void sclp_console_flush(void) { - unsigned long flags; - sclp_conbuf_emit(); - spin_lock_irqsave(&sclp_con_lock, flags); - if (timer_pending(&sclp_con_timer)) - del_timer(&sclp_con_timer); - while (sclp_con_buffer_count > 0) { - spin_unlock_irqrestore(&sclp_con_lock, flags); - sclp_sync_wait(); - spin_lock_irqsave(&sclp_con_lock, flags); - } - spin_unlock_irqrestore(&sclp_con_lock, flags); + sclp_console_sync_queue(); } -static int -sclp_console_notify(struct notifier_block *self, - unsigned long event, void *data) +/* + * Resume console: If there are cached messages, emit them. + */ +static void sclp_console_resume(void) +{ + unsigned long flags; + + spin_lock_irqsave(&sclp_con_lock, flags); + sclp_con_suspended = 0; + spin_unlock_irqrestore(&sclp_con_lock, flags); + sclp_conbuf_emit(); +} + +/* + * Suspend console: Set suspend flag and flush console + */ +static void sclp_console_suspend(void) +{ + unsigned long flags; + + spin_lock_irqsave(&sclp_con_lock, flags); + sclp_con_suspended = 1; + spin_unlock_irqrestore(&sclp_con_lock, flags); + sclp_console_flush(); +} + +static int sclp_console_notify(struct notifier_block *self, + unsigned long event, void *data) { sclp_console_flush(); return NOTIFY_OK; @@ -199,7 +242,7 @@ sclp_console_notify(struct notifier_block *self, static struct notifier_block on_panic_nb = { .notifier_call = sclp_console_notify, - .priority = 1, + .priority = SCLP_PANIC_PRIO_CLIENT, }; static struct notifier_block on_reboot_nb = { @@ -220,6 +263,22 @@ static struct console sclp_console = .index = 0 /* ttyS0 */ }; +/* + * This function is called for SCLP suspend and resume events. + */ +void sclp_console_pm_event(enum sclp_pm_event sclp_pm_event) +{ + switch (sclp_pm_event) { + case SCLP_PM_EVENT_FREEZE: + sclp_console_suspend(); + break; + case SCLP_PM_EVENT_RESTORE: + case SCLP_PM_EVENT_THAW: + sclp_console_resume(); + break; + } +} + /* * called by console_init() in drivers/char/tty_io.c at boot-time. */ @@ -238,12 +297,11 @@ sclp_console_init(void) /* Allocate pages for output buffering */ INIT_LIST_HEAD(&sclp_con_pages); for (i = 0; i < MAX_CONSOLE_PAGES; i++) { - page = alloc_bootmem_low_pages(PAGE_SIZE); - list_add_tail((struct list_head *) page, &sclp_con_pages); + page = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA); + list_add_tail(page, &sclp_con_pages); } INIT_LIST_HEAD(&sclp_con_outqueue); spin_lock_init(&sclp_con_lock); - sclp_con_buffer_count = 0; sclp_conbuf = NULL; init_timer(&sclp_con_timer); diff --git a/drivers/s390/char/sclp_rw.c b/drivers/s390/char/sclp_rw.c index 710af42603f8..4be63be73445 100644 --- a/drivers/s390/char/sclp_rw.c +++ b/drivers/s390/char/sclp_rw.c @@ -1,11 +1,10 @@ /* - * drivers/s390/char/sclp_rw.c - * driver: reading from and writing to system console on S/390 via SCLP + * driver: reading from and writing to system console on S/390 via SCLP * - * S390 version - * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Martin Peschke - * Martin Schwidefsky + * Copyright IBM Corp. 1999, 2009 + * + * Author(s): Martin Peschke + * Martin Schwidefsky */ #include @@ -26,9 +25,16 @@ */ #define MAX_SCCB_ROOM (PAGE_SIZE - sizeof(struct sclp_buffer)) +static void sclp_rw_pm_event(struct sclp_register *reg, + enum sclp_pm_event sclp_pm_event) +{ + sclp_console_pm_event(sclp_pm_event); +} + /* Event type structure for write message and write priority message */ static struct sclp_register sclp_rw_event = { - .send_mask = EVTYP_MSG_MASK | EVTYP_PMSGCMD_MASK + .send_mask = EVTYP_MSG_MASK | EVTYP_PMSGCMD_MASK, + .pm_event_fn = sclp_rw_pm_event, }; /* diff --git a/drivers/s390/char/sclp_rw.h b/drivers/s390/char/sclp_rw.h index 6aa7a6948bc9..85f491ea929c 100644 --- a/drivers/s390/char/sclp_rw.h +++ b/drivers/s390/char/sclp_rw.h @@ -1,11 +1,10 @@ /* - * drivers/s390/char/sclp_rw.h - * interface to the SCLP-read/write driver + * interface to the SCLP-read/write driver * - * S390 version - * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Martin Peschke - * Martin Schwidefsky + * Copyright IBM Corporation 1999, 2009 + * + * Author(s): Martin Peschke + * Martin Schwidefsky */ #ifndef __SCLP_RW_H__ @@ -93,4 +92,5 @@ void sclp_set_columns(struct sclp_buffer *, unsigned short); void sclp_set_htab(struct sclp_buffer *, unsigned short); int sclp_chars_in_buffer(struct sclp_buffer *); +void sclp_console_pm_event(enum sclp_pm_event sclp_pm_event); #endif /* __SCLP_RW_H__ */ diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c index a839aa531d7c..178724f2a4c3 100644 --- a/drivers/s390/char/sclp_vt220.c +++ b/drivers/s390/char/sclp_vt220.c @@ -1,10 +1,9 @@ /* - * drivers/s390/char/sclp_vt220.c - * SCLP VT220 terminal driver. + * SCLP VT220 terminal driver. * - * S390 version - * Copyright IBM Corp. 2003,2008 - * Author(s): Peter Oberparleiter + * Copyright IBM Corp. 2003, 2009 + * + * Author(s): Peter Oberparleiter */ #include @@ -21,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -69,8 +67,11 @@ static struct list_head sclp_vt220_empty; /* List of pending requests */ static struct list_head sclp_vt220_outqueue; -/* Number of requests in outqueue */ -static int sclp_vt220_outqueue_count; +/* Suspend mode flag */ +static int sclp_vt220_suspended; + +/* Flag that output queue is currently running */ +static int sclp_vt220_queue_running; /* Timer used for delaying write requests to merge subsequent messages into * a single buffer */ @@ -92,6 +93,8 @@ static int __initdata sclp_vt220_init_count; static int sclp_vt220_flush_later; static void sclp_vt220_receiver_fn(struct evbuf_header *evbuf); +static void sclp_vt220_pm_event_fn(struct sclp_register *reg, + enum sclp_pm_event sclp_pm_event); static int __sclp_vt220_emit(struct sclp_vt220_request *request); static void sclp_vt220_emit_current(void); @@ -100,7 +103,8 @@ static struct sclp_register sclp_vt220_register = { .send_mask = EVTYP_VT220MSG_MASK, .receive_mask = EVTYP_VT220MSG_MASK, .state_change_fn = NULL, - .receiver_fn = sclp_vt220_receiver_fn + .receiver_fn = sclp_vt220_receiver_fn, + .pm_event_fn = sclp_vt220_pm_event_fn, }; @@ -120,15 +124,19 @@ sclp_vt220_process_queue(struct sclp_vt220_request *request) spin_lock_irqsave(&sclp_vt220_lock, flags); /* Move request from outqueue to empty queue */ list_del(&request->list); - sclp_vt220_outqueue_count--; list_add_tail((struct list_head *) page, &sclp_vt220_empty); /* Check if there is a pending buffer on the out queue. */ request = NULL; if (!list_empty(&sclp_vt220_outqueue)) request = list_entry(sclp_vt220_outqueue.next, struct sclp_vt220_request, list); + if (!request || sclp_vt220_suspended) { + sclp_vt220_queue_running = 0; + spin_unlock_irqrestore(&sclp_vt220_lock, flags); + break; + } spin_unlock_irqrestore(&sclp_vt220_lock, flags); - } while (request && __sclp_vt220_emit(request)); + } while (__sclp_vt220_emit(request)); if (request == NULL && sclp_vt220_flush_later) sclp_vt220_emit_current(); /* Check if the tty needs a wake up call */ @@ -212,26 +220,7 @@ __sclp_vt220_emit(struct sclp_vt220_request *request) } /* - * Queue and emit given request. - */ -static void -sclp_vt220_emit(struct sclp_vt220_request *request) -{ - unsigned long flags; - int count; - - spin_lock_irqsave(&sclp_vt220_lock, flags); - list_add_tail(&request->list, &sclp_vt220_outqueue); - count = sclp_vt220_outqueue_count++; - spin_unlock_irqrestore(&sclp_vt220_lock, flags); - /* Emit only the first buffer immediately - callback takes care of - * the rest */ - if (count == 0 && __sclp_vt220_emit(request)) - sclp_vt220_process_queue(request); -} - -/* - * Queue and emit current request. Return zero on success, non-zero otherwise. + * Queue and emit current request. */ static void sclp_vt220_emit_current(void) @@ -241,22 +230,33 @@ sclp_vt220_emit_current(void) struct sclp_vt220_sccb *sccb; spin_lock_irqsave(&sclp_vt220_lock, flags); - request = NULL; - if (sclp_vt220_current_request != NULL) { + if (sclp_vt220_current_request) { sccb = (struct sclp_vt220_sccb *) sclp_vt220_current_request->sclp_req.sccb; /* Only emit buffers with content */ if (sccb->header.length != sizeof(struct sclp_vt220_sccb)) { - request = sclp_vt220_current_request; + list_add_tail(&sclp_vt220_current_request->list, + &sclp_vt220_outqueue); sclp_vt220_current_request = NULL; if (timer_pending(&sclp_vt220_timer)) del_timer(&sclp_vt220_timer); } sclp_vt220_flush_later = 0; } + if (sclp_vt220_queue_running || sclp_vt220_suspended) + goto out_unlock; + if (list_empty(&sclp_vt220_outqueue)) + goto out_unlock; + request = list_first_entry(&sclp_vt220_outqueue, + struct sclp_vt220_request, list); + sclp_vt220_queue_running = 1; + spin_unlock_irqrestore(&sclp_vt220_lock, flags); + + if (__sclp_vt220_emit(request)) + sclp_vt220_process_queue(request); + return; +out_unlock: spin_unlock_irqrestore(&sclp_vt220_lock, flags); - if (request != NULL) - sclp_vt220_emit(request); } #define SCLP_NORMAL_WRITE 0x00 @@ -396,7 +396,7 @@ __sclp_vt220_write(const unsigned char *buf, int count, int do_schedule, if (sclp_vt220_current_request == NULL) { while (list_empty(&sclp_vt220_empty)) { spin_unlock_irqrestore(&sclp_vt220_lock, flags); - if (may_fail) + if (may_fail || sclp_vt220_suspended) goto out; else sclp_sync_wait(); @@ -531,7 +531,7 @@ sclp_vt220_put_char(struct tty_struct *tty, unsigned char ch) static void sclp_vt220_flush_chars(struct tty_struct *tty) { - if (sclp_vt220_outqueue_count == 0) + if (!sclp_vt220_queue_running) sclp_vt220_emit_current(); else sclp_vt220_flush_later = 1; @@ -600,10 +600,7 @@ static void __init __sclp_vt220_free_pages(void) list_for_each_safe(page, p, &sclp_vt220_empty) { list_del(page); - if (slab_is_available()) - free_page((unsigned long) page); - else - free_bootmem((unsigned long) page, PAGE_SIZE); + free_page((unsigned long) page); } } @@ -635,21 +632,16 @@ static int __init __sclp_vt220_init(int num_pages) init_timer(&sclp_vt220_timer); sclp_vt220_current_request = NULL; sclp_vt220_buffered_chars = 0; - sclp_vt220_outqueue_count = 0; sclp_vt220_tty = NULL; sclp_vt220_flush_later = 0; /* Allocate pages for output buffering */ + rc = -ENOMEM; for (i = 0; i < num_pages; i++) { - if (slab_is_available()) - page = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA); - else - page = alloc_bootmem_low_pages(PAGE_SIZE); - if (!page) { - rc = -ENOMEM; + page = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA); + if (!page) goto out; - } - list_add_tail((struct list_head *) page, &sclp_vt220_empty); + list_add_tail(page, &sclp_vt220_empty); } rc = sclp_register(&sclp_vt220_register); out: @@ -736,7 +728,7 @@ static void __sclp_vt220_flush_buffer(void) spin_lock_irqsave(&sclp_vt220_lock, flags); if (timer_pending(&sclp_vt220_timer)) del_timer(&sclp_vt220_timer); - while (sclp_vt220_outqueue_count > 0) { + while (sclp_vt220_queue_running) { spin_unlock_irqrestore(&sclp_vt220_lock, flags); sclp_sync_wait(); spin_lock_irqsave(&sclp_vt220_lock, flags); @@ -744,6 +736,46 @@ static void __sclp_vt220_flush_buffer(void) spin_unlock_irqrestore(&sclp_vt220_lock, flags); } +/* + * Resume console: If there are cached messages, emit them. + */ +static void sclp_vt220_resume(void) +{ + unsigned long flags; + + spin_lock_irqsave(&sclp_vt220_lock, flags); + sclp_vt220_suspended = 0; + spin_unlock_irqrestore(&sclp_vt220_lock, flags); + sclp_vt220_emit_current(); +} + +/* + * Suspend console: Set suspend flag and flush console + */ +static void sclp_vt220_suspend(void) +{ + unsigned long flags; + + spin_lock_irqsave(&sclp_vt220_lock, flags); + sclp_vt220_suspended = 1; + spin_unlock_irqrestore(&sclp_vt220_lock, flags); + __sclp_vt220_flush_buffer(); +} + +static void sclp_vt220_pm_event_fn(struct sclp_register *reg, + enum sclp_pm_event sclp_pm_event) +{ + switch (sclp_pm_event) { + case SCLP_PM_EVENT_FREEZE: + sclp_vt220_suspend(); + break; + case SCLP_PM_EVENT_RESTORE: + case SCLP_PM_EVENT_THAW: + sclp_vt220_resume(); + break; + } +} + static int sclp_vt220_notify(struct notifier_block *self, unsigned long event, void *data) diff --git a/drivers/s390/char/tape.h b/drivers/s390/char/tape.h index 5469e099597e..a26333774701 100644 --- a/drivers/s390/char/tape.h +++ b/drivers/s390/char/tape.h @@ -3,7 +3,7 @@ * tape device driver for 3480/3490E/3590 tapes. * * S390 and zSeries version - * Copyright IBM Corp. 2001,2006 + * Copyright IBM Corp. 2001, 2009 * Author(s): Carsten Otte * Tuan Ngo-Anh * Martin Schwidefsky @@ -286,6 +286,7 @@ extern void tape_state_set(struct tape_device *, enum tape_state); extern int tape_generic_online(struct tape_device *, struct tape_discipline *); extern int tape_generic_offline(struct ccw_device *); +extern int tape_generic_pm_suspend(struct ccw_device *); /* Externals from tape_devmap.c */ extern int tape_generic_probe(struct ccw_device *); diff --git a/drivers/s390/char/tape_34xx.c b/drivers/s390/char/tape_34xx.c index 5f8e8ef43dd3..5a519fac37b7 100644 --- a/drivers/s390/char/tape_34xx.c +++ b/drivers/s390/char/tape_34xx.c @@ -2,7 +2,7 @@ * drivers/s390/char/tape_34xx.c * tape device discipline for 3480/3490 tapes. * - * Copyright (C) IBM Corp. 2001,2006 + * Copyright IBM Corp. 2001, 2009 * Author(s): Carsten Otte * Tuan Ngo-Anh * Martin Schwidefsky @@ -1134,7 +1134,7 @@ tape_34xx_bread(struct tape_device *device, struct request *req) /* Setup ccws. */ request->op = TO_BLOCK; start_block = (struct tape_34xx_block_id *) request->cpdata; - start_block->block = req->sector >> TAPEBLOCK_HSEC_S2B; + start_block->block = blk_rq_pos(req) >> TAPEBLOCK_HSEC_S2B; DBF_EVENT(6, "start_block = %i\n", start_block->block); ccw = request->cpaddr; @@ -1289,7 +1289,7 @@ static int tape_34xx_online(struct ccw_device *cdev) { return tape_generic_online( - cdev->dev.driver_data, + dev_get_drvdata(&cdev->dev), &tape_discipline_34xx ); } @@ -1302,6 +1302,7 @@ static struct ccw_driver tape_34xx_driver = { .remove = tape_generic_remove, .set_online = tape_34xx_online, .set_offline = tape_generic_offline, + .freeze = tape_generic_pm_suspend, }; static int diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c index 823b05bd0dd7..418f72dd39b4 100644 --- a/drivers/s390/char/tape_3590.c +++ b/drivers/s390/char/tape_3590.c @@ -2,7 +2,7 @@ * drivers/s390/char/tape_3590.c * tape device discipline for 3590 tapes. * - * Copyright IBM Corp. 2001,2006 + * Copyright IBM Corp. 2001, 2009 * Author(s): Stefan Bader * Michael Holzheu * Martin Schwidefsky @@ -633,7 +633,7 @@ tape_3590_bread(struct tape_device *device, struct request *req) struct req_iterator iter; DBF_EVENT(6, "xBREDid:"); - start_block = req->sector >> TAPEBLOCK_HSEC_S2B; + start_block = blk_rq_pos(req) >> TAPEBLOCK_HSEC_S2B; DBF_EVENT(6, "start_block = %i\n", start_block); rq_for_each_segment(bv, req, iter) @@ -1703,7 +1703,7 @@ static struct ccw_device_id tape_3590_ids[] = { static int tape_3590_online(struct ccw_device *cdev) { - return tape_generic_online(cdev->dev.driver_data, + return tape_generic_online(dev_get_drvdata(&cdev->dev), &tape_discipline_3590); } @@ -1715,6 +1715,7 @@ static struct ccw_driver tape_3590_driver = { .remove = tape_generic_remove, .set_offline = tape_generic_offline, .set_online = tape_3590_online, + .freeze = tape_generic_pm_suspend, }; /* diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c index f32e89e7c4f2..47ff695255ea 100644 --- a/drivers/s390/char/tape_block.c +++ b/drivers/s390/char/tape_block.c @@ -73,13 +73,6 @@ tapeblock_trigger_requeue(struct tape_device *device) /* * Post finished request. */ -static void -tapeblock_end_request(struct request *req, int error) -{ - if (blk_end_request(req, error, blk_rq_bytes(req))) - BUG(); -} - static void __tapeblock_end_request(struct tape_request *ccw_req, void *data) { @@ -90,17 +83,17 @@ __tapeblock_end_request(struct tape_request *ccw_req, void *data) device = ccw_req->device; req = (struct request *) data; - tapeblock_end_request(req, (ccw_req->rc == 0) ? 0 : -EIO); + blk_end_request_all(req, (ccw_req->rc == 0) ? 0 : -EIO); if (ccw_req->rc == 0) /* Update position. */ device->blk_data.block_position = - (req->sector + req->nr_sectors) >> TAPEBLOCK_HSEC_S2B; + (blk_rq_pos(req) + blk_rq_sectors(req)) >> TAPEBLOCK_HSEC_S2B; else /* We lost the position information due to an error. */ device->blk_data.block_position = -1; device->discipline->free_bread(ccw_req); if (!list_empty(&device->req_queue) || - elv_next_request(device->blk_data.request_queue)) + blk_peek_request(device->blk_data.request_queue)) tapeblock_trigger_requeue(device); } @@ -118,7 +111,7 @@ tapeblock_start_request(struct tape_device *device, struct request *req) ccw_req = device->discipline->bread(device, req); if (IS_ERR(ccw_req)) { DBF_EVENT(1, "TBLOCK: bread failed\n"); - tapeblock_end_request(req, -EIO); + blk_end_request_all(req, -EIO); return PTR_ERR(ccw_req); } ccw_req->callback = __tapeblock_end_request; @@ -131,7 +124,7 @@ tapeblock_start_request(struct tape_device *device, struct request *req) * Start/enqueueing failed. No retries in * this case. */ - tapeblock_end_request(req, -EIO); + blk_end_request_all(req, -EIO); device->discipline->free_bread(ccw_req); } @@ -169,19 +162,16 @@ tapeblock_requeue(struct work_struct *work) { spin_lock_irq(&device->blk_data.request_queue_lock); while ( !blk_queue_plugged(queue) && - elv_next_request(queue) && + (req = blk_fetch_request(queue)) && nr_queued < TAPEBLOCK_MIN_REQUEUE ) { - req = elv_next_request(queue); if (rq_data_dir(req) == WRITE) { DBF_EVENT(1, "TBLOCK: Rejecting write request\n"); - blkdev_dequeue_request(req); spin_unlock_irq(&device->blk_data.request_queue_lock); - tapeblock_end_request(req, -EIO); + blk_end_request_all(req, -EIO); spin_lock_irq(&device->blk_data.request_queue_lock); continue; } - blkdev_dequeue_request(req); nr_queued++; spin_unlock_irq(&device->blk_data.request_queue_lock); rc = tapeblock_start_request(device, req); @@ -232,7 +222,7 @@ tapeblock_setup_device(struct tape_device * device) if (rc) goto cleanup_queue; - blk_queue_hardsect_size(blkdat->request_queue, TAPEBLOCK_HSEC_SIZE); + blk_queue_logical_block_size(blkdat->request_queue, TAPEBLOCK_HSEC_SIZE); blk_queue_max_sectors(blkdat->request_queue, TAPEBLOCK_MAX_SEC); blk_queue_max_phys_segments(blkdat->request_queue, -1L); blk_queue_max_hw_segments(blkdat->request_queue, -1L); diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c index 8a109f3b69c6..1d420d947596 100644 --- a/drivers/s390/char/tape_core.c +++ b/drivers/s390/char/tape_core.c @@ -3,7 +3,7 @@ * basic function of the tape device driver * * S390 and zSeries version - * Copyright IBM Corp. 2001,2006 + * Copyright IBM Corp. 2001, 2009 * Author(s): Carsten Otte * Michael Holzheu * Tuan Ngo-Anh @@ -92,7 +92,7 @@ tape_medium_state_show(struct device *dev, struct device_attribute *attr, char * { struct tape_device *tdev; - tdev = (struct tape_device *) dev->driver_data; + tdev = dev_get_drvdata(dev); return scnprintf(buf, PAGE_SIZE, "%i\n", tdev->medium_state); } @@ -104,7 +104,7 @@ tape_first_minor_show(struct device *dev, struct device_attribute *attr, char *b { struct tape_device *tdev; - tdev = (struct tape_device *) dev->driver_data; + tdev = dev_get_drvdata(dev); return scnprintf(buf, PAGE_SIZE, "%i\n", tdev->first_minor); } @@ -116,7 +116,7 @@ tape_state_show(struct device *dev, struct device_attribute *attr, char *buf) { struct tape_device *tdev; - tdev = (struct tape_device *) dev->driver_data; + tdev = dev_get_drvdata(dev); return scnprintf(buf, PAGE_SIZE, "%s\n", (tdev->first_minor < 0) ? "OFFLINE" : tape_state_verbose[tdev->tape_state]); } @@ -130,7 +130,7 @@ tape_operation_show(struct device *dev, struct device_attribute *attr, char *buf struct tape_device *tdev; ssize_t rc; - tdev = (struct tape_device *) dev->driver_data; + tdev = dev_get_drvdata(dev); if (tdev->first_minor < 0) return scnprintf(buf, PAGE_SIZE, "N/A\n"); @@ -156,7 +156,7 @@ tape_blocksize_show(struct device *dev, struct device_attribute *attr, char *buf { struct tape_device *tdev; - tdev = (struct tape_device *) dev->driver_data; + tdev = dev_get_drvdata(dev); return scnprintf(buf, PAGE_SIZE, "%i\n", tdev->char_data.block_size); } @@ -379,6 +379,55 @@ tape_cleanup_device(struct tape_device *device) tape_med_state_set(device, MS_UNKNOWN); } +/* + * Suspend device. + * + * Called by the common I/O layer if the drive should be suspended on user + * request. We refuse to suspend if the device is loaded or in use for the + * following reason: + * While the Linux guest is suspended, it might be logged off which causes + * devices to be detached. Tape devices are automatically rewound and unloaded + * during DETACH processing (unless the tape device was attached with the + * NOASSIGN or MULTIUSER option). After rewind/unload, there is no way to + * resume the original state of the tape device, since we would need to + * manually re-load the cartridge which was active at suspend time. + */ +int tape_generic_pm_suspend(struct ccw_device *cdev) +{ + struct tape_device *device; + + device = dev_get_drvdata(&cdev->dev); + if (!device) { + return -ENODEV; + } + + DBF_LH(3, "(%08x): tape_generic_pm_suspend(%p)\n", + device->cdev_id, device); + + if (device->medium_state != MS_UNLOADED) { + pr_err("A cartridge is loaded in tape device %s, " + "refusing to suspend\n", dev_name(&cdev->dev)); + return -EBUSY; + } + + spin_lock_irq(get_ccwdev_lock(device->cdev)); + switch (device->tape_state) { + case TS_INIT: + case TS_NOT_OPER: + case TS_UNUSED: + spin_unlock_irq(get_ccwdev_lock(device->cdev)); + break; + default: + pr_err("Tape device %s is busy, refusing to " + "suspend\n", dev_name(&cdev->dev)); + spin_unlock_irq(get_ccwdev_lock(device->cdev)); + return -EBUSY; + } + + DBF_LH(3, "(%08x): Drive suspended.\n", device->cdev_id); + return 0; +} + /* * Set device offline. * @@ -391,7 +440,7 @@ tape_generic_offline(struct ccw_device *cdev) { struct tape_device *device; - device = cdev->dev.driver_data; + device = dev_get_drvdata(&cdev->dev); if (!device) { return -ENODEV; } @@ -534,7 +583,7 @@ tape_generic_probe(struct ccw_device *cdev) tape_put_device(device); return ret; } - cdev->dev.driver_data = device; + dev_set_drvdata(&cdev->dev, device); cdev->handler = __tape_do_irq; device->cdev = cdev; ccw_device_get_id(cdev, &dev_id); @@ -573,7 +622,7 @@ tape_generic_remove(struct ccw_device *cdev) { struct tape_device * device; - device = cdev->dev.driver_data; + device = dev_get_drvdata(&cdev->dev); if (!device) { return; } @@ -613,9 +662,9 @@ tape_generic_remove(struct ccw_device *cdev) tape_cleanup_device(device); } - if (cdev->dev.driver_data != NULL) { + if (!dev_get_drvdata(&cdev->dev)) { sysfs_remove_group(&cdev->dev.kobj, &tape_attr_group); - cdev->dev.driver_data = tape_put_device(cdev->dev.driver_data); + dev_set_drvdata(&cdev->dev, tape_put_device(dev_get_drvdata(&cdev->dev))); } } @@ -1011,7 +1060,7 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb) struct tape_request *request; int rc; - device = (struct tape_device *) cdev->dev.driver_data; + device = dev_get_drvdata(&cdev->dev); if (device == NULL) { return; } @@ -1273,6 +1322,7 @@ EXPORT_SYMBOL(tape_generic_remove); EXPORT_SYMBOL(tape_generic_probe); EXPORT_SYMBOL(tape_generic_online); EXPORT_SYMBOL(tape_generic_offline); +EXPORT_SYMBOL(tape_generic_pm_suspend); EXPORT_SYMBOL(tape_put_device); EXPORT_SYMBOL(tape_get_device_reference); EXPORT_SYMBOL(tape_state_verbose); diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c index a7fe6302c982..38385677c653 100644 --- a/drivers/s390/char/tty3270.c +++ b/drivers/s390/char/tty3270.c @@ -112,7 +112,7 @@ struct tty3270 { #define TTY_UPDATE_LIST 2 /* Update lines in tty3270->update. */ #define TTY_UPDATE_INPUT 4 /* Update input line. */ #define TTY_UPDATE_STATUS 8 /* Update status line. */ -#define TTY_UPDATE_ALL 15 +#define TTY_UPDATE_ALL 16 /* Recreate screen. */ static void tty3270_update(struct tty3270 *); @@ -121,19 +121,10 @@ static void tty3270_update(struct tty3270 *); */ static void tty3270_set_timer(struct tty3270 *tp, int expires) { - if (expires == 0) { - if (timer_pending(&tp->timer) && del_timer(&tp->timer)) - raw3270_put_view(&tp->view); - return; - } - if (timer_pending(&tp->timer) && - mod_timer(&tp->timer, jiffies + expires)) - return; - raw3270_get_view(&tp->view); - tp->timer.function = (void (*)(unsigned long)) tty3270_update; - tp->timer.data = (unsigned long) tp; - tp->timer.expires = jiffies + expires; - add_timer(&tp->timer); + if (expires == 0) + del_timer(&tp->timer); + else + mod_timer(&tp->timer, jiffies + expires); } /* @@ -337,7 +328,6 @@ tty3270_write_callback(struct raw3270_request *rq, void *data) tp = (struct tty3270 *) rq->view; if (rq->rc != 0) { /* Write wasn't successfull. Refresh all. */ - tty3270_rebuild_update(tp); tp->update_flags = TTY_UPDATE_ALL; tty3270_set_timer(tp, 1); } @@ -366,6 +356,12 @@ tty3270_update(struct tty3270 *tp) spin_lock(&tp->view.lock); updated = 0; + if (tp->update_flags & TTY_UPDATE_ALL) { + tty3270_rebuild_update(tp); + tty3270_update_status(tp); + tp->update_flags = TTY_UPDATE_ERASE | TTY_UPDATE_LIST | + TTY_UPDATE_INPUT | TTY_UPDATE_STATUS; + } if (tp->update_flags & TTY_UPDATE_ERASE) { /* Use erase write alternate to erase display. */ raw3270_request_set_cmd(wrq, TC_EWRITEA); @@ -425,7 +421,6 @@ tty3270_update(struct tty3270 *tp) xchg(&tp->write, wrq); } spin_unlock(&tp->view.lock); - raw3270_put_view(&tp->view); } /* @@ -570,7 +565,6 @@ tty3270_read_tasklet(struct raw3270_request *rrq) tty3270_set_timer(tp, 1); } else if (tp->input->string[0] == 0x6d) { /* Display has been cleared. Redraw. */ - tty3270_rebuild_update(tp); tp->update_flags = TTY_UPDATE_ALL; tty3270_set_timer(tp, 1); } @@ -641,22 +635,20 @@ static int tty3270_activate(struct raw3270_view *view) { struct tty3270 *tp; - unsigned long flags; tp = (struct tty3270 *) view; - spin_lock_irqsave(&tp->view.lock, flags); - tp->nr_up = 0; - tty3270_rebuild_update(tp); - tty3270_update_status(tp); tp->update_flags = TTY_UPDATE_ALL; tty3270_set_timer(tp, 1); - spin_unlock_irqrestore(&tp->view.lock, flags); return 0; } static void tty3270_deactivate(struct raw3270_view *view) { + struct tty3270 *tp; + + tp = (struct tty3270 *) view; + del_timer(&tp->timer); } static int @@ -743,6 +735,7 @@ tty3270_free_view(struct tty3270 *tp) { int pages; + del_timer_sync(&tp->timer); kbd_free(tp->kbd); raw3270_request_free(tp->kreset); raw3270_request_free(tp->read); @@ -889,7 +882,8 @@ tty3270_open(struct tty_struct *tty, struct file * filp) INIT_LIST_HEAD(&tp->update); INIT_LIST_HEAD(&tp->rcl_lines); tp->rcl_max = 20; - init_timer(&tp->timer); + setup_timer(&tp->timer, (void (*)(unsigned long)) tty3270_update, + (unsigned long) tp); tasklet_init(&tp->readlet, (void (*)(unsigned long)) tty3270_read_tasklet, (unsigned long) tp->read); @@ -1754,14 +1748,6 @@ static const struct tty_operations tty3270_ops = { .set_termios = tty3270_set_termios }; -static void tty3270_notifier(int index, int active) -{ - if (active) - tty_register_device(tty3270_driver, index, NULL); - else - tty_unregister_device(tty3270_driver, index); -} - /* * 3270 tty registration code called from tty_init(). * Most kernel services (incl. kmalloc) are available at this poimt. @@ -1796,12 +1782,6 @@ static int __init tty3270_init(void) return ret; } tty3270_driver = driver; - ret = raw3270_register_notifier(tty3270_notifier); - if (ret) { - put_tty_driver(driver); - return ret; - - } return 0; } @@ -1810,7 +1790,6 @@ tty3270_exit(void) { struct tty_driver *driver; - raw3270_unregister_notifier(tty3270_notifier); driver = tty3270_driver; tty3270_driver = NULL; tty_unregister_driver(driver); diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c index d8a2289fcb69..c20a4fe6da51 100644 --- a/drivers/s390/char/vmlogrdr.c +++ b/drivers/s390/char/vmlogrdr.c @@ -3,7 +3,7 @@ * character device driver for reading z/VM system service records * * - * Copyright 2004 IBM Corporation + * Copyright IBM Corp. 2004, 2009 * character device driver for reading z/VM system service records, * Version 1.0 * Author(s): Xenia Tkatschow @@ -504,7 +504,7 @@ static ssize_t vmlogrdr_autopurge_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t count) { - struct vmlogrdr_priv_t *priv = dev->driver_data; + struct vmlogrdr_priv_t *priv = dev_get_drvdata(dev); ssize_t ret = count; switch (buf[0]) { @@ -525,7 +525,7 @@ static ssize_t vmlogrdr_autopurge_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct vmlogrdr_priv_t *priv = dev->driver_data; + struct vmlogrdr_priv_t *priv = dev_get_drvdata(dev); return sprintf(buf, "%u\n", priv->autopurge); } @@ -541,7 +541,7 @@ static ssize_t vmlogrdr_purge_store(struct device * dev, char cp_command[80]; char cp_response[80]; - struct vmlogrdr_priv_t *priv = dev->driver_data; + struct vmlogrdr_priv_t *priv = dev_get_drvdata(dev); if (buf[0] != '1') return -EINVAL; @@ -578,7 +578,7 @@ static ssize_t vmlogrdr_autorecording_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct vmlogrdr_priv_t *priv = dev->driver_data; + struct vmlogrdr_priv_t *priv = dev_get_drvdata(dev); ssize_t ret = count; switch (buf[0]) { @@ -599,7 +599,7 @@ static ssize_t vmlogrdr_autorecording_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct vmlogrdr_priv_t *priv = dev->driver_data; + struct vmlogrdr_priv_t *priv = dev_get_drvdata(dev); return sprintf(buf, "%u\n", priv->autorecording); } @@ -612,7 +612,7 @@ static ssize_t vmlogrdr_recording_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t count) { - struct vmlogrdr_priv_t *priv = dev->driver_data; + struct vmlogrdr_priv_t *priv = dev_get_drvdata(dev); ssize_t ret; switch (buf[0]) { @@ -660,6 +660,29 @@ static struct attribute *vmlogrdr_attrs[] = { NULL, }; +static int vmlogrdr_pm_prepare(struct device *dev) +{ + int rc; + struct vmlogrdr_priv_t *priv = dev_get_drvdata(dev); + + rc = 0; + if (priv) { + spin_lock_bh(&priv->priv_lock); + if (priv->dev_in_use) + rc = -EBUSY; + spin_unlock_bh(&priv->priv_lock); + } + if (rc) + pr_err("vmlogrdr: device %s is busy. Refuse to suspend.\n", + dev_name(dev)); + return rc; +} + + +static struct dev_pm_ops vmlogrdr_pm_ops = { + .prepare = vmlogrdr_pm_prepare, +}; + static struct attribute_group vmlogrdr_attr_group = { .attrs = vmlogrdr_attrs, }; @@ -668,6 +691,7 @@ static struct class *vmlogrdr_class; static struct device_driver vmlogrdr_driver = { .name = "vmlogrdr", .bus = &iucv_bus, + .pm = &vmlogrdr_pm_ops, }; @@ -729,6 +753,7 @@ static int vmlogrdr_register_device(struct vmlogrdr_priv_t *priv) dev->bus = &iucv_bus; dev->parent = iucv_root; dev->driver = &vmlogrdr_driver; + dev_set_drvdata(dev, priv); /* * The release function could be called after the * module has been unloaded. It's _only_ task is to diff --git a/drivers/s390/char/vmur.c b/drivers/s390/char/vmur.c index 5dcef81fc9d9..31b902e94f7b 100644 --- a/drivers/s390/char/vmur.c +++ b/drivers/s390/char/vmur.c @@ -2,7 +2,7 @@ * Linux driver for System z and s390 unit record devices * (z/VM virtual punch, reader, printer) * - * Copyright IBM Corp. 2001, 2007 + * Copyright IBM Corp. 2001, 2009 * Authors: Malcolm Beattie * Michael Holzheu * Frank Munzert @@ -60,6 +60,7 @@ static int ur_probe(struct ccw_device *cdev); static void ur_remove(struct ccw_device *cdev); static int ur_set_online(struct ccw_device *cdev); static int ur_set_offline(struct ccw_device *cdev); +static int ur_pm_suspend(struct ccw_device *cdev); static struct ccw_driver ur_driver = { .name = "vmur", @@ -69,6 +70,7 @@ static struct ccw_driver ur_driver = { .remove = ur_remove, .set_online = ur_set_online, .set_offline = ur_set_offline, + .freeze = ur_pm_suspend, }; static DEFINE_MUTEX(vmur_mutex); @@ -78,11 +80,11 @@ static DEFINE_MUTEX(vmur_mutex); * * Each ur device (urd) contains a reference to its corresponding ccw device * (cdev) using the urd->cdev pointer. Each ccw device has a reference to the - * ur device using the cdev->dev.driver_data pointer. + * ur device using dev_get_drvdata(&cdev->dev) pointer. * * urd references: * - ur_probe gets a urd reference, ur_remove drops the reference - * (cdev->dev.driver_data) + * dev_get_drvdata(&cdev->dev) * - ur_open gets a urd reference, ur_relase drops the reference * (urf->urd) * @@ -90,7 +92,7 @@ static DEFINE_MUTEX(vmur_mutex); * - urdev_alloc get a cdev reference (urd->cdev) * - urdev_free drops the cdev reference (urd->cdev) * - * Setting and clearing of cdev->dev.driver_data is protected by the ccwdev lock + * Setting and clearing of dev_get_drvdata(&cdev->dev) is protected by the ccwdev lock */ static struct urdev *urdev_alloc(struct ccw_device *cdev) { @@ -129,7 +131,7 @@ static struct urdev *urdev_get_from_cdev(struct ccw_device *cdev) unsigned long flags; spin_lock_irqsave(get_ccwdev_lock(cdev), flags); - urd = cdev->dev.driver_data; + urd = dev_get_drvdata(&cdev->dev); if (urd) urdev_get(urd); spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags); @@ -157,6 +159,28 @@ static void urdev_put(struct urdev *urd) urdev_free(urd); } +/* + * State and contents of ur devices can be changed by class D users issuing + * CP commands such as PURGE or TRANSFER, while the Linux guest is suspended. + * Also the Linux guest might be logged off, which causes all active spool + * files to be closed. + * So we cannot guarantee that spool files are still the same when the Linux + * guest is resumed. In order to avoid unpredictable results at resume time + * we simply refuse to suspend if a ur device node is open. + */ +static int ur_pm_suspend(struct ccw_device *cdev) +{ + struct urdev *urd = dev_get_drvdata(&cdev->dev); + + TRACE("ur_pm_suspend: cdev=%p\n", cdev); + if (urd->open_flag) { + pr_err("Unit record device %s is busy, %s refusing to " + "suspend.\n", dev_name(&cdev->dev), ur_banner); + return -EBUSY; + } + return 0; +} + /* * Low-level functions to do I/O to a ur device. * alloc_chan_prog @@ -286,7 +310,7 @@ static void ur_int_handler(struct ccw_device *cdev, unsigned long intparm, TRACE("ur_int_handler: unsolicited interrupt\n"); return; } - urd = cdev->dev.driver_data; + urd = dev_get_drvdata(&cdev->dev); BUG_ON(!urd); /* On special conditions irb is an error pointer */ if (IS_ERR(irb)) @@ -832,7 +856,7 @@ static int ur_probe(struct ccw_device *cdev) goto fail_remove_attr; } spin_lock_irq(get_ccwdev_lock(cdev)); - cdev->dev.driver_data = urd; + dev_set_drvdata(&cdev->dev, urd); spin_unlock_irq(get_ccwdev_lock(cdev)); mutex_unlock(&vmur_mutex); @@ -972,8 +996,8 @@ static void ur_remove(struct ccw_device *cdev) ur_remove_attributes(&cdev->dev); spin_lock_irqsave(get_ccwdev_lock(cdev), flags); - urdev_put(cdev->dev.driver_data); - cdev->dev.driver_data = NULL; + urdev_put(dev_get_drvdata(&cdev->dev)); + dev_set_drvdata(&cdev->dev, NULL); spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags); mutex_unlock(&vmur_mutex); diff --git a/drivers/s390/char/vmwatchdog.c b/drivers/s390/char/vmwatchdog.c index 21a2a829bf4e..cb7854c10c04 100644 --- a/drivers/s390/char/vmwatchdog.c +++ b/drivers/s390/char/vmwatchdog.c @@ -1,17 +1,23 @@ /* * Watchdog implementation based on z/VM Watchdog Timer API * + * Copyright IBM Corp. 2004,2009 + * * The user space watchdog daemon can use this driver as * /dev/vmwatchdog to have z/VM execute the specified CP * command when the timeout expires. The default command is * "IPL", which which cause an immediate reboot. */ +#define KMSG_COMPONENT "vmwatchdog" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include #include #include #include #include #include +#include #include #include @@ -43,6 +49,9 @@ static unsigned int vmwdt_interval = 60; static unsigned long vmwdt_is_open; static int vmwdt_expect_close; +#define VMWDT_OPEN 0 /* devnode is open or suspend in progress */ +#define VMWDT_RUNNING 1 /* The watchdog is armed */ + enum vmwdt_func { /* function codes */ wdt_init = 0, @@ -92,6 +101,7 @@ static int vmwdt_keepalive(void) EBC_TOUPPER(ebc_cmd, MAX_CMDLEN); func = vmwdt_conceal ? (wdt_init | wdt_conceal) : wdt_init; + set_bit(VMWDT_RUNNING, &vmwdt_is_open); ret = __diag288(func, vmwdt_interval, ebc_cmd, len); WARN_ON(ret != 0); kfree(ebc_cmd); @@ -102,6 +112,7 @@ static int vmwdt_disable(void) { int ret = __diag288(wdt_cancel, 0, "", 0); WARN_ON(ret != 0); + clear_bit(VMWDT_RUNNING, &vmwdt_is_open); return ret; } @@ -123,13 +134,13 @@ static int vmwdt_open(struct inode *i, struct file *f) { int ret; lock_kernel(); - if (test_and_set_bit(0, &vmwdt_is_open)) { + if (test_and_set_bit(VMWDT_OPEN, &vmwdt_is_open)) { unlock_kernel(); return -EBUSY; } ret = vmwdt_keepalive(); if (ret) - clear_bit(0, &vmwdt_is_open); + clear_bit(VMWDT_OPEN, &vmwdt_is_open); unlock_kernel(); return ret ? ret : nonseekable_open(i, f); } @@ -139,7 +150,7 @@ static int vmwdt_close(struct inode *i, struct file *f) if (vmwdt_expect_close == 42) vmwdt_disable(); vmwdt_expect_close = 0; - clear_bit(0, &vmwdt_is_open); + clear_bit(VMWDT_OPEN, &vmwdt_is_open); return 0; } @@ -223,6 +234,57 @@ static ssize_t vmwdt_write(struct file *f, const char __user *buf, return count; } +static int vmwdt_resume(void) +{ + clear_bit(VMWDT_OPEN, &vmwdt_is_open); + return NOTIFY_DONE; +} + +/* + * It makes no sense to go into suspend while the watchdog is running. + * Depending on the memory size, the watchdog might trigger, while we + * are still saving the memory. + * We reuse the open flag to ensure that suspend and watchdog open are + * exclusive operations + */ +static int vmwdt_suspend(void) +{ + if (test_and_set_bit(VMWDT_OPEN, &vmwdt_is_open)) { + pr_err("The watchdog is in use. " + "This prevents hibernation or suspend.\n"); + return NOTIFY_BAD; + } + if (test_bit(VMWDT_RUNNING, &vmwdt_is_open)) { + clear_bit(VMWDT_OPEN, &vmwdt_is_open); + pr_err("The watchdog is running. " + "This prevents hibernation or suspend.\n"); + return NOTIFY_BAD; + } + return NOTIFY_DONE; +} + +/* + * This function is called for suspend and resume. + */ +static int vmwdt_power_event(struct notifier_block *this, unsigned long event, + void *ptr) +{ + switch (event) { + case PM_POST_HIBERNATION: + case PM_POST_SUSPEND: + return vmwdt_resume(); + case PM_HIBERNATION_PREPARE: + case PM_SUSPEND_PREPARE: + return vmwdt_suspend(); + default: + return NOTIFY_DONE; + } +} + +static struct notifier_block vmwdt_power_notifier = { + .notifier_call = vmwdt_power_event, +}; + static const struct file_operations vmwdt_fops = { .open = &vmwdt_open, .release = &vmwdt_close, @@ -244,12 +306,21 @@ static int __init vmwdt_init(void) ret = vmwdt_probe(); if (ret) return ret; - return misc_register(&vmwdt_dev); + ret = register_pm_notifier(&vmwdt_power_notifier); + if (ret) + return ret; + ret = misc_register(&vmwdt_dev); + if (ret) { + unregister_pm_notifier(&vmwdt_power_notifier); + return ret; + } + return 0; } module_init(vmwdt_init); static void __exit vmwdt_exit(void) { - WARN_ON(misc_deregister(&vmwdt_dev) != 0); + unregister_pm_notifier(&vmwdt_power_notifier); + misc_deregister(&vmwdt_dev); } module_exit(vmwdt_exit); diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index 22ce765d537e..a5a62f1f7747 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c @@ -1,11 +1,10 @@ /* - * drivers/s390/cio/ccwgroup.c * bus driver for ccwgroup * - * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, - * IBM Corporation - * Author(s): Arnd Bergmann (arndb@de.ibm.com) - * Cornelia Huck (cornelia.huck@de.ibm.com) + * Copyright IBM Corp. 2002, 2009 + * + * Author(s): Arnd Bergmann (arndb@de.ibm.com) + * Cornelia Huck (cornelia.huck@de.ibm.com) */ #include #include @@ -501,6 +500,74 @@ static void ccwgroup_shutdown(struct device *dev) gdrv->shutdown(gdev); } +static int ccwgroup_pm_prepare(struct device *dev) +{ + struct ccwgroup_device *gdev = to_ccwgroupdev(dev); + struct ccwgroup_driver *gdrv = to_ccwgroupdrv(gdev->dev.driver); + + /* Fail while device is being set online/offline. */ + if (atomic_read(&gdev->onoff)) + return -EAGAIN; + + if (!gdev->dev.driver || gdev->state != CCWGROUP_ONLINE) + return 0; + + return gdrv->prepare ? gdrv->prepare(gdev) : 0; +} + +static void ccwgroup_pm_complete(struct device *dev) +{ + struct ccwgroup_device *gdev = to_ccwgroupdev(dev); + struct ccwgroup_driver *gdrv = to_ccwgroupdrv(dev->driver); + + if (!gdev->dev.driver || gdev->state != CCWGROUP_ONLINE) + return; + + if (gdrv->complete) + gdrv->complete(gdev); +} + +static int ccwgroup_pm_freeze(struct device *dev) +{ + struct ccwgroup_device *gdev = to_ccwgroupdev(dev); + struct ccwgroup_driver *gdrv = to_ccwgroupdrv(gdev->dev.driver); + + if (!gdev->dev.driver || gdev->state != CCWGROUP_ONLINE) + return 0; + + return gdrv->freeze ? gdrv->freeze(gdev) : 0; +} + +static int ccwgroup_pm_thaw(struct device *dev) +{ + struct ccwgroup_device *gdev = to_ccwgroupdev(dev); + struct ccwgroup_driver *gdrv = to_ccwgroupdrv(gdev->dev.driver); + + if (!gdev->dev.driver || gdev->state != CCWGROUP_ONLINE) + return 0; + + return gdrv->thaw ? gdrv->thaw(gdev) : 0; +} + +static int ccwgroup_pm_restore(struct device *dev) +{ + struct ccwgroup_device *gdev = to_ccwgroupdev(dev); + struct ccwgroup_driver *gdrv = to_ccwgroupdrv(gdev->dev.driver); + + if (!gdev->dev.driver || gdev->state != CCWGROUP_ONLINE) + return 0; + + return gdrv->restore ? gdrv->restore(gdev) : 0; +} + +static struct dev_pm_ops ccwgroup_pm_ops = { + .prepare = ccwgroup_pm_prepare, + .complete = ccwgroup_pm_complete, + .freeze = ccwgroup_pm_freeze, + .thaw = ccwgroup_pm_thaw, + .restore = ccwgroup_pm_restore, +}; + static struct bus_type ccwgroup_bus_type = { .name = "ccwgroup", .match = ccwgroup_bus_match, @@ -508,6 +575,7 @@ static struct bus_type ccwgroup_bus_type = { .probe = ccwgroup_probe, .remove = ccwgroup_remove, .shutdown = ccwgroup_shutdown, + .pm = &ccwgroup_pm_ops, }; diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 883f16f96f22..1ecd3e567648 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -549,8 +549,7 @@ cleanup: return ret; } -static int -__chsc_do_secm(struct channel_subsystem *css, int enable, void *page) +int __chsc_do_secm(struct channel_subsystem *css, int enable, void *page) { struct { struct chsc_header request; diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h index ba59bceace98..425e8f89a6c5 100644 --- a/drivers/s390/cio/chsc.h +++ b/drivers/s390/cio/chsc.h @@ -90,6 +90,7 @@ extern void chsc_free_sei_area(void); extern int chsc_enable_facility(int); struct channel_subsystem; extern int chsc_secm(struct channel_subsystem *, int); +int __chsc_do_secm(struct channel_subsystem *css, int enable, void *page); int chsc_chp_vary(struct chp_id chpid, int on); int chsc_determine_channel_path_desc(struct chp_id chpid, int fmt, int rfmt, diff --git a/drivers/s390/cio/chsc_sch.c b/drivers/s390/cio/chsc_sch.c index 93eca1731b81..cc5144b6f9d9 100644 --- a/drivers/s390/cio/chsc_sch.c +++ b/drivers/s390/cio/chsc_sch.c @@ -1,7 +1,8 @@ /* * Driver for s390 chsc subchannels * - * Copyright IBM Corp. 2008 + * Copyright IBM Corp. 2008, 2009 + * * Author(s): Cornelia Huck * */ @@ -112,6 +113,31 @@ static void chsc_subchannel_shutdown(struct subchannel *sch) cio_disable_subchannel(sch); } +static int chsc_subchannel_prepare(struct subchannel *sch) +{ + int cc; + struct schib schib; + /* + * Don't allow suspend while the subchannel is not idle + * since we don't have a way to clear the subchannel and + * cannot disable it with a request running. + */ + cc = stsch(sch->schid, &schib); + if (!cc && scsw_stctl(&schib.scsw)) + return -EAGAIN; + return 0; +} + +static int chsc_subchannel_freeze(struct subchannel *sch) +{ + return cio_disable_subchannel(sch); +} + +static int chsc_subchannel_restore(struct subchannel *sch) +{ + return cio_enable_subchannel(sch, (u32)(unsigned long)sch); +} + static struct css_device_id chsc_subchannel_ids[] = { { .match_flags = 0x1, .type =SUBCHANNEL_TYPE_CHSC, }, { /* end of list */ }, @@ -125,6 +151,10 @@ static struct css_driver chsc_subchannel_driver = { .probe = chsc_subchannel_probe, .remove = chsc_subchannel_remove, .shutdown = chsc_subchannel_shutdown, + .prepare = chsc_subchannel_prepare, + .freeze = chsc_subchannel_freeze, + .thaw = chsc_subchannel_restore, + .restore = chsc_subchannel_restore, .name = "chsc_subchannel", }; diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 2aebb9823044..5ec7789bd9d8 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -12,6 +12,7 @@ #define KMSG_COMPONENT "cio" #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt +#include #include #include #include @@ -28,7 +29,7 @@ #include #include #include -#include +#include #include #include #include @@ -626,8 +627,7 @@ out: * handlers). * */ -void -do_IRQ (struct pt_regs *regs) +void __irq_entry do_IRQ(struct pt_regs *regs) { struct tpi_info *tpi_info; struct subchannel *sch; diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c index dc98b2c63862..30f516111307 100644 --- a/drivers/s390/cio/cmf.c +++ b/drivers/s390/cio/cmf.c @@ -1204,6 +1204,11 @@ static ssize_t cmb_enable_store(struct device *dev, DEVICE_ATTR(cmb_enable, 0644, cmb_enable_show, cmb_enable_store); +int ccw_set_cmf(struct ccw_device *cdev, int enable) +{ + return cmbops->set(cdev, enable ? 2 : 0); +} + /** * enable_cmf() - switch on the channel measurement for a specific device * @cdev: The ccw device to be enabled diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 0085d8901792..85d43c6bcb66 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -1,10 +1,10 @@ /* - * drivers/s390/cio/css.c - * driver for channel subsystem + * driver for channel subsystem * - * Copyright IBM Corp. 2002,2008 - * Author(s): Arnd Bergmann (arndb@de.ibm.com) - * Cornelia Huck (cornelia.huck@de.ibm.com) + * Copyright IBM Corp. 2002, 2009 + * + * Author(s): Arnd Bergmann (arndb@de.ibm.com) + * Cornelia Huck (cornelia.huck@de.ibm.com) */ #define KMSG_COMPONENT "cio" @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -779,6 +780,79 @@ static struct notifier_block css_reboot_notifier = { .notifier_call = css_reboot_event, }; +/* + * Since the css devices are neither on a bus nor have a class + * nor have a special device type, we cannot stop/restart channel + * path measurements via the normal suspend/resume callbacks, but have + * to use notifiers. + */ +static int css_power_event(struct notifier_block *this, unsigned long event, + void *ptr) +{ + void *secm_area; + int ret, i; + + switch (event) { + case PM_HIBERNATION_PREPARE: + case PM_SUSPEND_PREPARE: + ret = NOTIFY_DONE; + for (i = 0; i <= __MAX_CSSID; i++) { + struct channel_subsystem *css; + + css = channel_subsystems[i]; + mutex_lock(&css->mutex); + if (!css->cm_enabled) { + mutex_unlock(&css->mutex); + continue; + } + secm_area = (void *)get_zeroed_page(GFP_KERNEL | + GFP_DMA); + if (secm_area) { + if (__chsc_do_secm(css, 0, secm_area)) + ret = NOTIFY_BAD; + free_page((unsigned long)secm_area); + } else + ret = NOTIFY_BAD; + + mutex_unlock(&css->mutex); + } + break; + case PM_POST_HIBERNATION: + case PM_POST_SUSPEND: + ret = NOTIFY_DONE; + for (i = 0; i <= __MAX_CSSID; i++) { + struct channel_subsystem *css; + + css = channel_subsystems[i]; + mutex_lock(&css->mutex); + if (!css->cm_enabled) { + mutex_unlock(&css->mutex); + continue; + } + secm_area = (void *)get_zeroed_page(GFP_KERNEL | + GFP_DMA); + if (secm_area) { + if (__chsc_do_secm(css, 1, secm_area)) + ret = NOTIFY_BAD; + free_page((unsigned long)secm_area); + } else + ret = NOTIFY_BAD; + + mutex_unlock(&css->mutex); + } + /* search for subchannels, which appeared during hibernation */ + css_schedule_reprobe(); + break; + default: + ret = NOTIFY_DONE; + } + return ret; + +} +static struct notifier_block css_power_notifier = { + .notifier_call = css_power_event, +}; + /* * Now that the driver core is running, we can setup our channel subsystem. * The struct subchannel's are created during probing (except for the @@ -852,6 +926,11 @@ init_channel_subsystem (void) ret = register_reboot_notifier(&css_reboot_notifier); if (ret) goto out_unregister; + ret = register_pm_notifier(&css_power_notifier); + if (ret) { + unregister_reboot_notifier(&css_reboot_notifier); + goto out_unregister; + } css_init_done = 1; /* Enable default isc for I/O subchannels. */ @@ -953,6 +1032,73 @@ static int css_uevent(struct device *dev, struct kobj_uevent_env *env) return ret; } +static int css_pm_prepare(struct device *dev) +{ + struct subchannel *sch = to_subchannel(dev); + struct css_driver *drv; + + if (mutex_is_locked(&sch->reg_mutex)) + return -EAGAIN; + if (!sch->dev.driver) + return 0; + drv = to_cssdriver(sch->dev.driver); + /* Notify drivers that they may not register children. */ + return drv->prepare ? drv->prepare(sch) : 0; +} + +static void css_pm_complete(struct device *dev) +{ + struct subchannel *sch = to_subchannel(dev); + struct css_driver *drv; + + if (!sch->dev.driver) + return; + drv = to_cssdriver(sch->dev.driver); + if (drv->complete) + drv->complete(sch); +} + +static int css_pm_freeze(struct device *dev) +{ + struct subchannel *sch = to_subchannel(dev); + struct css_driver *drv; + + if (!sch->dev.driver) + return 0; + drv = to_cssdriver(sch->dev.driver); + return drv->freeze ? drv->freeze(sch) : 0; +} + +static int css_pm_thaw(struct device *dev) +{ + struct subchannel *sch = to_subchannel(dev); + struct css_driver *drv; + + if (!sch->dev.driver) + return 0; + drv = to_cssdriver(sch->dev.driver); + return drv->thaw ? drv->thaw(sch) : 0; +} + +static int css_pm_restore(struct device *dev) +{ + struct subchannel *sch = to_subchannel(dev); + struct css_driver *drv; + + if (!sch->dev.driver) + return 0; + drv = to_cssdriver(sch->dev.driver); + return drv->restore ? drv->restore(sch) : 0; +} + +static struct dev_pm_ops css_pm_ops = { + .prepare = css_pm_prepare, + .complete = css_pm_complete, + .freeze = css_pm_freeze, + .thaw = css_pm_thaw, + .restore = css_pm_restore, +}; + struct bus_type css_bus_type = { .name = "css", .match = css_bus_match, @@ -960,6 +1106,7 @@ struct bus_type css_bus_type = { .remove = css_remove, .shutdown = css_shutdown, .uevent = css_uevent, + .pm = &css_pm_ops, }; /** diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h index 57ebf120f825..9763eeec7458 100644 --- a/drivers/s390/cio/css.h +++ b/drivers/s390/cio/css.h @@ -70,6 +70,11 @@ struct chp_link; * @probe: function called on probe * @remove: function called on remove * @shutdown: called at device shutdown + * @prepare: prepare for pm state transition + * @complete: undo work done in @prepare + * @freeze: callback for freezing during hibernation snapshotting + * @thaw: undo work done in @freeze + * @restore: callback for restoring after hibernation * @name: name of the device driver */ struct css_driver { @@ -82,6 +87,11 @@ struct css_driver { int (*probe)(struct subchannel *); int (*remove)(struct subchannel *); void (*shutdown)(struct subchannel *); + int (*prepare) (struct subchannel *); + void (*complete) (struct subchannel *); + int (*freeze)(struct subchannel *); + int (*thaw) (struct subchannel *); + int (*restore)(struct subchannel *); const char *name; }; diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 35441fa16be1..3c57c1a18bb8 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -138,6 +138,19 @@ static struct css_device_id io_subchannel_ids[] = { }; MODULE_DEVICE_TABLE(css, io_subchannel_ids); +static int io_subchannel_prepare(struct subchannel *sch) +{ + struct ccw_device *cdev; + /* + * Don't allow suspend while a ccw device registration + * is still outstanding. + */ + cdev = sch_get_cdev(sch); + if (cdev && !device_is_registered(&cdev->dev)) + return -EAGAIN; + return 0; +} + static struct css_driver io_subchannel_driver = { .owner = THIS_MODULE, .subchannel_type = io_subchannel_ids, @@ -148,6 +161,7 @@ static struct css_driver io_subchannel_driver = { .probe = io_subchannel_probe, .remove = io_subchannel_remove, .shutdown = io_subchannel_shutdown, + .prepare = io_subchannel_prepare, }; struct workqueue_struct *ccw_device_work; @@ -1775,6 +1789,15 @@ ccw_device_probe_console(void) return &console_cdev; } +static int ccw_device_pm_restore(struct device *dev); + +int ccw_device_force_console(void) +{ + if (!console_cdev_in_use) + return -ENODEV; + return ccw_device_pm_restore(&console_cdev.dev); +} +EXPORT_SYMBOL_GPL(ccw_device_force_console); const char *cio_get_console_cdev_name(struct subchannel *sch) { @@ -1895,6 +1918,242 @@ static void ccw_device_shutdown(struct device *dev) disable_cmf(cdev); } +static int ccw_device_pm_prepare(struct device *dev) +{ + struct ccw_device *cdev = to_ccwdev(dev); + + if (work_pending(&cdev->private->kick_work)) + return -EAGAIN; + /* Fail while device is being set online/offline. */ + if (atomic_read(&cdev->private->onoff)) + return -EAGAIN; + + if (cdev->online && cdev->drv && cdev->drv->prepare) + return cdev->drv->prepare(cdev); + + return 0; +} + +static void ccw_device_pm_complete(struct device *dev) +{ + struct ccw_device *cdev = to_ccwdev(dev); + + if (cdev->online && cdev->drv && cdev->drv->complete) + cdev->drv->complete(cdev); +} + +static int ccw_device_pm_freeze(struct device *dev) +{ + struct ccw_device *cdev = to_ccwdev(dev); + struct subchannel *sch = to_subchannel(cdev->dev.parent); + int ret, cm_enabled; + + /* Fail suspend while device is in transistional state. */ + if (!dev_fsm_final_state(cdev)) + return -EAGAIN; + if (!cdev->online) + return 0; + if (cdev->drv && cdev->drv->freeze) { + ret = cdev->drv->freeze(cdev); + if (ret) + return ret; + } + + spin_lock_irq(sch->lock); + cm_enabled = cdev->private->cmb != NULL; + spin_unlock_irq(sch->lock); + if (cm_enabled) { + /* Don't have the css write on memory. */ + ret = ccw_set_cmf(cdev, 0); + if (ret) + return ret; + } + /* From here on, disallow device driver I/O. */ + spin_lock_irq(sch->lock); + ret = cio_disable_subchannel(sch); + spin_unlock_irq(sch->lock); + + return ret; +} + +static int ccw_device_pm_thaw(struct device *dev) +{ + struct ccw_device *cdev = to_ccwdev(dev); + struct subchannel *sch = to_subchannel(cdev->dev.parent); + int ret, cm_enabled; + + if (!cdev->online) + return 0; + + spin_lock_irq(sch->lock); + /* Allow device driver I/O again. */ + ret = cio_enable_subchannel(sch, (u32)(addr_t)sch); + cm_enabled = cdev->private->cmb != NULL; + spin_unlock_irq(sch->lock); + if (ret) + return ret; + + if (cm_enabled) { + ret = ccw_set_cmf(cdev, 1); + if (ret) + return ret; + } + + if (cdev->drv && cdev->drv->thaw) + ret = cdev->drv->thaw(cdev); + + return ret; +} + +static void __ccw_device_pm_restore(struct ccw_device *cdev) +{ + struct subchannel *sch = to_subchannel(cdev->dev.parent); + int ret; + + if (cio_is_console(sch->schid)) + goto out; + /* + * While we were sleeping, devices may have gone or become + * available again. Kick re-detection. + */ + spin_lock_irq(sch->lock); + cdev->private->flags.resuming = 1; + ret = ccw_device_recognition(cdev); + spin_unlock_irq(sch->lock); + if (ret) { + CIO_MSG_EVENT(0, "Couldn't start recognition for device " + "%s (ret=%d)\n", dev_name(&cdev->dev), ret); + spin_lock_irq(sch->lock); + cdev->private->state = DEV_STATE_DISCONNECTED; + spin_unlock_irq(sch->lock); + /* notify driver after the resume cb */ + goto out; + } + wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev) || + cdev->private->state == DEV_STATE_DISCONNECTED); + +out: + cdev->private->flags.resuming = 0; +} + +static int resume_handle_boxed(struct ccw_device *cdev) +{ + cdev->private->state = DEV_STATE_BOXED; + if (ccw_device_notify(cdev, CIO_BOXED)) + return 0; + ccw_device_schedule_sch_unregister(cdev); + return -ENODEV; +} + +static int resume_handle_disc(struct ccw_device *cdev) +{ + cdev->private->state = DEV_STATE_DISCONNECTED; + if (ccw_device_notify(cdev, CIO_GONE)) + return 0; + ccw_device_schedule_sch_unregister(cdev); + return -ENODEV; +} + +static int ccw_device_pm_restore(struct device *dev) +{ + struct ccw_device *cdev = to_ccwdev(dev); + struct subchannel *sch = to_subchannel(cdev->dev.parent); + int ret = 0, cm_enabled; + + __ccw_device_pm_restore(cdev); + spin_lock_irq(sch->lock); + if (cio_is_console(sch->schid)) { + cio_enable_subchannel(sch, (u32)(addr_t)sch); + spin_unlock_irq(sch->lock); + goto out_restore; + } + cdev->private->flags.donotify = 0; + /* check recognition results */ + switch (cdev->private->state) { + case DEV_STATE_OFFLINE: + break; + case DEV_STATE_BOXED: + ret = resume_handle_boxed(cdev); + spin_unlock_irq(sch->lock); + if (ret) + goto out; + goto out_restore; + case DEV_STATE_DISCONNECTED: + goto out_disc_unlock; + default: + goto out_unreg_unlock; + } + /* check if the device id has changed */ + if (sch->schib.pmcw.dev != cdev->private->dev_id.devno) { + CIO_MSG_EVENT(0, "resume: sch %s: failed (devno changed from " + "%04x to %04x)\n", dev_name(&sch->dev), + cdev->private->dev_id.devno, + sch->schib.pmcw.dev); + goto out_unreg_unlock; + } + /* check if the device type has changed */ + if (!ccw_device_test_sense_data(cdev)) { + ccw_device_update_sense_data(cdev); + PREPARE_WORK(&cdev->private->kick_work, + ccw_device_do_unbind_bind); + queue_work(ccw_device_work, &cdev->private->kick_work); + ret = -ENODEV; + goto out_unlock; + } + if (!cdev->online) { + ret = 0; + goto out_unlock; + } + ret = ccw_device_online(cdev); + if (ret) + goto out_disc_unlock; + + cm_enabled = cdev->private->cmb != NULL; + spin_unlock_irq(sch->lock); + + wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev)); + if (cdev->private->state != DEV_STATE_ONLINE) { + spin_lock_irq(sch->lock); + goto out_disc_unlock; + } + if (cm_enabled) { + ret = ccw_set_cmf(cdev, 1); + if (ret) { + CIO_MSG_EVENT(2, "resume: cdev %s: cmf failed " + "(rc=%d)\n", dev_name(&cdev->dev), ret); + ret = 0; + } + } + +out_restore: + if (cdev->online && cdev->drv && cdev->drv->restore) + ret = cdev->drv->restore(cdev); +out: + return ret; + +out_disc_unlock: + ret = resume_handle_disc(cdev); + spin_unlock_irq(sch->lock); + if (ret) + return ret; + goto out_restore; + +out_unreg_unlock: + ccw_device_schedule_sch_unregister(cdev); + ret = -ENODEV; +out_unlock: + spin_unlock_irq(sch->lock); + return ret; +} + +static struct dev_pm_ops ccw_pm_ops = { + .prepare = ccw_device_pm_prepare, + .complete = ccw_device_pm_complete, + .freeze = ccw_device_pm_freeze, + .thaw = ccw_device_pm_thaw, + .restore = ccw_device_pm_restore, +}; + struct bus_type ccw_bus_type = { .name = "ccw", .match = ccw_bus_match, @@ -1902,6 +2161,7 @@ struct bus_type ccw_bus_type = { .probe = ccw_device_probe, .remove = ccw_device_remove, .shutdown = ccw_device_shutdown, + .pm = &ccw_pm_ops, }; /** diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h index f1cbbd94ad4e..e3975107a578 100644 --- a/drivers/s390/cio/device.h +++ b/drivers/s390/cio/device.h @@ -87,6 +87,8 @@ int ccw_device_is_orphan(struct ccw_device *); int ccw_device_recognition(struct ccw_device *); int ccw_device_online(struct ccw_device *); int ccw_device_offline(struct ccw_device *); +void ccw_device_update_sense_data(struct ccw_device *); +int ccw_device_test_sense_data(struct ccw_device *); void ccw_device_schedule_sch_unregister(struct ccw_device *); int ccw_purge_blacklisted(void); @@ -133,5 +135,6 @@ extern struct bus_type ccw_bus_type; void retry_set_schib(struct ccw_device *cdev); void cmf_retry_copy_block(struct ccw_device *); int cmf_reenable(struct ccw_device *); +int ccw_set_cmf(struct ccw_device *cdev, int enable); extern struct device_attribute dev_attr_cmb_enable; #endif diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index e46049261561..3db88c52d287 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -177,29 +177,21 @@ ccw_device_cancel_halt_clear(struct ccw_device *cdev) panic("Can't stop i/o on subchannel.\n"); } -static int -ccw_device_handle_oper(struct ccw_device *cdev) +void ccw_device_update_sense_data(struct ccw_device *cdev) { - struct subchannel *sch; + memset(&cdev->id, 0, sizeof(cdev->id)); + cdev->id.cu_type = cdev->private->senseid.cu_type; + cdev->id.cu_model = cdev->private->senseid.cu_model; + cdev->id.dev_type = cdev->private->senseid.dev_type; + cdev->id.dev_model = cdev->private->senseid.dev_model; +} - sch = to_subchannel(cdev->dev.parent); - cdev->private->flags.recog_done = 1; - /* - * Check if cu type and device type still match. If - * not, it is certainly another device and we have to - * de- and re-register. - */ - if (cdev->id.cu_type != cdev->private->senseid.cu_type || - cdev->id.cu_model != cdev->private->senseid.cu_model || - cdev->id.dev_type != cdev->private->senseid.dev_type || - cdev->id.dev_model != cdev->private->senseid.dev_model) { - PREPARE_WORK(&cdev->private->kick_work, - ccw_device_do_unbind_bind); - queue_work(ccw_device_work, &cdev->private->kick_work); - return 0; - } - cdev->private->flags.donotify = 1; - return 1; +int ccw_device_test_sense_data(struct ccw_device *cdev) +{ + return cdev->id.cu_type == cdev->private->senseid.cu_type && + cdev->id.cu_model == cdev->private->senseid.cu_model && + cdev->id.dev_type == cdev->private->senseid.dev_type && + cdev->id.dev_model == cdev->private->senseid.dev_model; } /* @@ -233,7 +225,7 @@ static void ccw_device_recog_done(struct ccw_device *cdev, int state) { struct subchannel *sch; - int notify, old_lpm, same_dev; + int old_lpm; sch = to_subchannel(cdev->dev.parent); @@ -263,8 +255,12 @@ ccw_device_recog_done(struct ccw_device *cdev, int state) wake_up(&cdev->private->wait_q); return; } - notify = 0; - same_dev = 0; /* Keep the compiler quiet... */ + if (cdev->private->flags.resuming) { + cdev->private->state = state; + cdev->private->flags.recog_done = 1; + wake_up(&cdev->private->wait_q); + return; + } switch (state) { case DEV_STATE_NOT_OPER: CIO_MSG_EVENT(2, "SenseID : unknown device %04x on " @@ -273,34 +269,31 @@ ccw_device_recog_done(struct ccw_device *cdev, int state) sch->schid.ssid, sch->schid.sch_no); break; case DEV_STATE_OFFLINE: - if (cdev->online) { - same_dev = ccw_device_handle_oper(cdev); - notify = 1; + if (!cdev->online) { + ccw_device_update_sense_data(cdev); + /* Issue device info message. */ + CIO_MSG_EVENT(4, "SenseID : device 0.%x.%04x reports: " + "CU Type/Mod = %04X/%02X, Dev Type/Mod " + "= %04X/%02X\n", + cdev->private->dev_id.ssid, + cdev->private->dev_id.devno, + cdev->id.cu_type, cdev->id.cu_model, + cdev->id.dev_type, cdev->id.dev_model); + break; } - /* fill out sense information */ - memset(&cdev->id, 0, sizeof(cdev->id)); - cdev->id.cu_type = cdev->private->senseid.cu_type; - cdev->id.cu_model = cdev->private->senseid.cu_model; - cdev->id.dev_type = cdev->private->senseid.dev_type; - cdev->id.dev_model = cdev->private->senseid.dev_model; - if (notify) { - cdev->private->state = DEV_STATE_OFFLINE; - if (same_dev) { - /* Get device online again. */ - ccw_device_online(cdev); - wake_up(&cdev->private->wait_q); - } - return; + cdev->private->state = DEV_STATE_OFFLINE; + cdev->private->flags.recog_done = 1; + if (ccw_device_test_sense_data(cdev)) { + cdev->private->flags.donotify = 1; + ccw_device_online(cdev); + wake_up(&cdev->private->wait_q); + } else { + ccw_device_update_sense_data(cdev); + PREPARE_WORK(&cdev->private->kick_work, + ccw_device_do_unbind_bind); + queue_work(ccw_device_work, &cdev->private->kick_work); } - /* Issue device info message. */ - CIO_MSG_EVENT(4, "SenseID : device 0.%x.%04x reports: " - "CU Type/Mod = %04X/%02X, Dev Type/Mod = " - "%04X/%02X\n", - cdev->private->dev_id.ssid, - cdev->private->dev_id.devno, - cdev->id.cu_type, cdev->id.cu_model, - cdev->id.dev_type, cdev->id.dev_model); - break; + return; case DEV_STATE_BOXED: CIO_MSG_EVENT(0, "SenseID : boxed device %04x on " " subchannel 0.%x.%04x\n", @@ -502,9 +495,6 @@ ccw_device_recognition(struct ccw_device *cdev) struct subchannel *sch; int ret; - if ((cdev->private->state != DEV_STATE_NOT_OPER) && - (cdev->private->state != DEV_STATE_BOXED)) - return -EINVAL; sch = to_subchannel(cdev->dev.parent); ret = cio_enable_subchannel(sch, (u32)(addr_t)sch); if (ret != 0) diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c index 151754d54745..2d0efee8a290 100644 --- a/drivers/s390/cio/device_ops.c +++ b/drivers/s390/cio/device_ops.c @@ -1,10 +1,8 @@ /* - * drivers/s390/cio/device_ops.c + * Copyright IBM Corp. 2002, 2009 * - * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, - * IBM Corporation - * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) - * Cornelia Huck (cornelia.huck@de.ibm.com) + * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) + * Cornelia Huck (cornelia.huck@de.ibm.com) */ #include #include @@ -114,16 +112,17 @@ int ccw_device_clear(struct ccw_device *cdev, unsigned long intparm) struct subchannel *sch; int ret; - if (!cdev) + if (!cdev || !cdev->dev.parent) return -ENODEV; + sch = to_subchannel(cdev->dev.parent); + if (!sch->schib.pmcw.ena) + return -EINVAL; if (cdev->private->state == DEV_STATE_NOT_OPER) return -ENODEV; if (cdev->private->state != DEV_STATE_ONLINE && cdev->private->state != DEV_STATE_W4SENSE) return -EINVAL; - sch = to_subchannel(cdev->dev.parent); - if (!sch) - return -ENODEV; + ret = cio_clear(sch); if (ret == 0) cdev->private->intparm = intparm; @@ -161,11 +160,11 @@ int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa, struct subchannel *sch; int ret; - if (!cdev) + if (!cdev || !cdev->dev.parent) return -ENODEV; sch = to_subchannel(cdev->dev.parent); - if (!sch) - return -ENODEV; + if (!sch->schib.pmcw.ena) + return -EINVAL; if (cdev->private->state == DEV_STATE_NOT_OPER) return -ENODEV; if (cdev->private->state == DEV_STATE_VERIFY || @@ -339,16 +338,17 @@ int ccw_device_halt(struct ccw_device *cdev, unsigned long intparm) struct subchannel *sch; int ret; - if (!cdev) + if (!cdev || !cdev->dev.parent) return -ENODEV; + sch = to_subchannel(cdev->dev.parent); + if (!sch->schib.pmcw.ena) + return -EINVAL; if (cdev->private->state == DEV_STATE_NOT_OPER) return -ENODEV; if (cdev->private->state != DEV_STATE_ONLINE && cdev->private->state != DEV_STATE_W4SENSE) return -EINVAL; - sch = to_subchannel(cdev->dev.parent); - if (!sch) - return -ENODEV; + ret = cio_halt(sch); if (ret == 0) cdev->private->intparm = intparm; @@ -372,11 +372,11 @@ int ccw_device_resume(struct ccw_device *cdev) { struct subchannel *sch; - if (!cdev) + if (!cdev || !cdev->dev.parent) return -ENODEV; sch = to_subchannel(cdev->dev.parent); - if (!sch) - return -ENODEV; + if (!sch->schib.pmcw.ena) + return -EINVAL; if (cdev->private->state == DEV_STATE_NOT_OPER) return -ENODEV; if (cdev->private->state != DEV_STATE_ONLINE || @@ -471,11 +471,11 @@ __u8 ccw_device_get_path_mask(struct ccw_device *cdev) { struct subchannel *sch; - sch = to_subchannel(cdev->dev.parent); - if (!sch) + if (!cdev->dev.parent) return 0; - else - return sch->lpm; + + sch = to_subchannel(cdev->dev.parent); + return sch->lpm; } /* @@ -588,6 +588,8 @@ int ccw_device_tm_start_key(struct ccw_device *cdev, struct tcw *tcw, int rc; sch = to_subchannel(cdev->dev.parent); + if (!sch->schib.pmcw.ena) + return -EINVAL; if (cdev->private->state != DEV_STATE_ONLINE) return -EIO; /* Adjust requested path mask to excluded varied off paths. */ @@ -677,6 +679,8 @@ int ccw_device_tm_intrg(struct ccw_device *cdev) { struct subchannel *sch = to_subchannel(cdev->dev.parent); + if (!sch->schib.pmcw.ena) + return -EINVAL; if (cdev->private->state != DEV_STATE_ONLINE) return -EIO; if (!scsw_is_tm(&sch->schib.scsw) || diff --git a/drivers/s390/cio/io_sch.h b/drivers/s390/cio/io_sch.h index c4f3e7c9a854..0b8f381bd20e 100644 --- a/drivers/s390/cio/io_sch.h +++ b/drivers/s390/cio/io_sch.h @@ -107,6 +107,7 @@ struct ccw_device_private { unsigned int recog_done:1; /* dev. recog. complete */ unsigned int fake_irb:1; /* deliver faked irb */ unsigned int intretry:1; /* retry internal operation */ + unsigned int resuming:1; /* recognition while resume */ } __attribute__((packed)) flags; unsigned long intparm; /* user interruption parameter */ struct qdio_irq *qdio_data; diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index 13bcb8114388..b1241f8fae88 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h @@ -351,15 +351,6 @@ static inline unsigned long long get_usecs(void) ((bufnr - dec) & QDIO_MAX_BUFFERS_MASK) /* prototypes for thin interrupt */ -void qdio_sync_after_thinint(struct qdio_q *q); -int get_buf_state(struct qdio_q *q, unsigned int bufnr, unsigned char *state, - int auto_ack); -void qdio_check_outbound_after_thinint(struct qdio_q *q); -int qdio_inbound_q_moved(struct qdio_q *q); -void qdio_kick_handler(struct qdio_q *q); -void qdio_stop_polling(struct qdio_q *q); -int qdio_siga_sync_q(struct qdio_q *q); - void qdio_setup_thinint(struct qdio_irq *irq_ptr); int qdio_establish_thinint(struct qdio_irq *irq_ptr); void qdio_shutdown_thinint(struct qdio_irq *irq_ptr); @@ -392,4 +383,6 @@ void qdio_setup_destroy_sysfs(struct ccw_device *cdev); int qdio_setup_init(void); void qdio_setup_exit(void); +int debug_get_buf_state(struct qdio_q *q, unsigned int bufnr, + unsigned char *state); #endif /* _CIO_QDIO_H */ diff --git a/drivers/s390/cio/qdio_debug.c b/drivers/s390/cio/qdio_debug.c index e3434b34f86c..b8626d4df116 100644 --- a/drivers/s390/cio/qdio_debug.c +++ b/drivers/s390/cio/qdio_debug.c @@ -70,9 +70,8 @@ static int qstat_show(struct seq_file *m, void *v) seq_printf(m, "slsb buffer states:\n"); seq_printf(m, "|0 |8 |16 |24 |32 |40 |48 |56 63|\n"); - qdio_siga_sync_q(q); for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) { - get_buf_state(q, i, &state, 0); + debug_get_buf_state(q, i, &state); switch (state) { case SLSB_P_INPUT_NOT_INIT: case SLSB_P_OUTPUT_NOT_INIT: diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index accd957454e7..0038750ad945 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -231,8 +231,8 @@ static inline int get_buf_states(struct qdio_q *q, unsigned int bufnr, return i; } -inline int get_buf_state(struct qdio_q *q, unsigned int bufnr, - unsigned char *state, int auto_ack) +static inline int get_buf_state(struct qdio_q *q, unsigned int bufnr, + unsigned char *state, int auto_ack) { return get_buf_states(q, bufnr, state, 1, auto_ack); } @@ -276,7 +276,7 @@ void qdio_init_buf_states(struct qdio_irq *irq_ptr) QDIO_MAX_BUFFERS_PER_Q); } -static int qdio_siga_sync(struct qdio_q *q, unsigned int output, +static inline int qdio_siga_sync(struct qdio_q *q, unsigned int output, unsigned int input) { int cc; @@ -293,7 +293,7 @@ static int qdio_siga_sync(struct qdio_q *q, unsigned int output, return cc; } -inline int qdio_siga_sync_q(struct qdio_q *q) +static inline int qdio_siga_sync_q(struct qdio_q *q) { if (q->is_input_q) return qdio_siga_sync(q, 0, q->mask); @@ -358,8 +358,7 @@ static inline int qdio_siga_input(struct qdio_q *q) return cc; } -/* called from thinint inbound handler */ -void qdio_sync_after_thinint(struct qdio_q *q) +static inline void qdio_sync_after_thinint(struct qdio_q *q) { if (pci_out_supported(q)) { if (need_siga_sync_thinint(q)) @@ -370,7 +369,14 @@ void qdio_sync_after_thinint(struct qdio_q *q) qdio_siga_sync_q(q); } -inline void qdio_stop_polling(struct qdio_q *q) +int debug_get_buf_state(struct qdio_q *q, unsigned int bufnr, + unsigned char *state) +{ + qdio_siga_sync_q(q); + return get_buf_states(q, bufnr, state, 1, 0); +} + +static inline void qdio_stop_polling(struct qdio_q *q) { if (!q->u.in.polling) return; @@ -449,13 +455,6 @@ static inline void inbound_primed(struct qdio_q *q, int count) count--; if (!count) return; - - /* - * Need to change all PRIMED buffers to NOT_INIT, otherwise - * we're loosing initiative in the thinint code. - */ - set_buf_states(q, q->first_to_check, SLSB_P_INPUT_NOT_INIT, - count); } static int get_inbound_buffer_frontier(struct qdio_q *q) @@ -470,19 +469,13 @@ static int get_inbound_buffer_frontier(struct qdio_q *q) count = min(atomic_read(&q->nr_buf_used), QDIO_MAX_BUFFERS_MASK); stop = add_buf(q->first_to_check, count); - /* - * No siga sync here, as a PCI or we after a thin interrupt - * will sync the queues. - */ - - /* need to set count to 1 for non-qebsm */ - if (!is_qebsm(q)) - count = 1; - -check_next: if (q->first_to_check == stop) goto out; + /* + * No siga sync here, as a PCI or we after a thin interrupt + * already sync'ed the queues. + */ count = get_buf_states(q, q->first_to_check, &state, count, 1); if (!count) goto out; @@ -490,14 +483,9 @@ check_next: switch (state) { case SLSB_P_INPUT_PRIMED: inbound_primed(q, count); - /* - * No siga-sync needed for non-qebsm here, as the inbound queue - * will be synced on the next siga-r, resp. - * tiqdio_is_inbound_q_done will do the siga-sync. - */ q->first_to_check = add_buf(q->first_to_check, count); atomic_sub(count, &q->nr_buf_used); - goto check_next; + break; case SLSB_P_INPUT_ERROR: announce_buffer_error(q, count); /* process the buffer, the upper layer will take care of it */ @@ -516,7 +504,7 @@ out: return q->first_to_check; } -int qdio_inbound_q_moved(struct qdio_q *q) +static int qdio_inbound_q_moved(struct qdio_q *q) { int bufnr; @@ -524,35 +512,32 @@ int qdio_inbound_q_moved(struct qdio_q *q) if ((bufnr != q->last_move) || q->qdio_error) { q->last_move = bufnr; - if (!need_siga_sync(q) && !pci_out_supported(q)) + if (!is_thinint_irq(q->irq_ptr) && !MACHINE_IS_VM) q->u.in.timestamp = get_usecs(); - - DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in moved"); return 1; } else return 0; } -static int qdio_inbound_q_done(struct qdio_q *q) +static inline int qdio_inbound_q_done(struct qdio_q *q) { unsigned char state = 0; if (!atomic_read(&q->nr_buf_used)) return 1; - /* - * We need that one for synchronization with the adapter, as it - * does a kind of PCI avoidance. - */ qdio_siga_sync_q(q); - get_buf_state(q, q->first_to_check, &state, 0); + if (state == SLSB_P_INPUT_PRIMED) - /* we got something to do */ + /* more work coming */ return 0; - /* on VM, we don't poll, so the q is always done here */ - if (need_siga_sync(q) || pci_out_supported(q)) + if (is_thinint_irq(q->irq_ptr)) + return 1; + + /* don't poll under z/VM */ + if (MACHINE_IS_VM) return 1; /* @@ -563,14 +548,11 @@ static int qdio_inbound_q_done(struct qdio_q *q) DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in done:%3d", q->first_to_check); return 1; - } else { - DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in notd:%3d", - q->first_to_check); + } else return 0; - } } -void qdio_kick_handler(struct qdio_q *q) +static void qdio_kick_handler(struct qdio_q *q) { int start = q->first_to_kick; int end = q->first_to_check; @@ -619,7 +601,6 @@ again: goto again; } -/* inbound tasklet */ void qdio_inbound_processing(unsigned long data) { struct qdio_q *q = (struct qdio_q *)data; @@ -642,11 +623,6 @@ static int get_outbound_buffer_frontier(struct qdio_q *q) count = min(atomic_read(&q->nr_buf_used), QDIO_MAX_BUFFERS_MASK); stop = add_buf(q->first_to_check, count); - /* need to set count to 1 for non-qebsm */ - if (!is_qebsm(q)) - count = 1; - -check_next: if (q->first_to_check == stop) return q->first_to_check; @@ -661,13 +637,7 @@ check_next: atomic_sub(count, &q->nr_buf_used); q->first_to_check = add_buf(q->first_to_check, count); - /* - * We fetch all buffer states at once. get_buf_states may - * return count < stop. For QEBSM we do not loop. - */ - if (is_qebsm(q)) - break; - goto check_next; + break; case SLSB_P_OUTPUT_ERROR: announce_buffer_error(q, count); /* process the buffer, the upper layer will take care of it */ @@ -797,8 +767,7 @@ void qdio_outbound_timer(unsigned long data) tasklet_schedule(&q->tasklet); } -/* called from thinint inbound tasklet */ -void qdio_check_outbound_after_thinint(struct qdio_q *q) +static inline void qdio_check_outbound_after_thinint(struct qdio_q *q) { struct qdio_q *out; int i; @@ -811,6 +780,46 @@ void qdio_check_outbound_after_thinint(struct qdio_q *q) tasklet_schedule(&out->tasklet); } +static void __tiqdio_inbound_processing(struct qdio_q *q) +{ + qdio_perf_stat_inc(&perf_stats.thinint_inbound); + qdio_sync_after_thinint(q); + + /* + * The interrupt could be caused by a PCI request. Check the + * PCI capable outbound queues. + */ + qdio_check_outbound_after_thinint(q); + + if (!qdio_inbound_q_moved(q)) + return; + + qdio_kick_handler(q); + + if (!qdio_inbound_q_done(q)) { + qdio_perf_stat_inc(&perf_stats.thinint_inbound_loop); + if (likely(q->irq_ptr->state != QDIO_IRQ_STATE_STOPPED)) + tasklet_schedule(&q->tasklet); + } + + qdio_stop_polling(q); + /* + * We need to check again to not lose initiative after + * resetting the ACK state. + */ + if (!qdio_inbound_q_done(q)) { + qdio_perf_stat_inc(&perf_stats.thinint_inbound_loop2); + if (likely(q->irq_ptr->state != QDIO_IRQ_STATE_STOPPED)) + tasklet_schedule(&q->tasklet); + } +} + +void tiqdio_inbound_processing(unsigned long data) +{ + struct qdio_q *q = (struct qdio_q *)data; + __tiqdio_inbound_processing(q); +} + static inline void qdio_set_state(struct qdio_irq *irq_ptr, enum qdio_irq_states state) { @@ -881,42 +890,26 @@ no_handler: qdio_set_state(irq_ptr, QDIO_IRQ_STATE_STOPPED); } -static int qdio_establish_check_errors(struct ccw_device *cdev, int cstat, - int dstat) -{ - struct qdio_irq *irq_ptr = cdev->private->qdio_data; - - if (cstat || (dstat & ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END))) { - DBF_ERROR("EQ:ck con"); - goto error; - } - - if (!(dstat & DEV_STAT_DEV_END)) { - DBF_ERROR("EQ:no dev"); - goto error; - } - - if (dstat & ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) { - DBF_ERROR("EQ: bad io"); - goto error; - } - return 0; -error: - DBF_ERROR("%4x EQ:error", irq_ptr->schid.sch_no); - DBF_ERROR("ds: %2x cs:%2x", dstat, cstat); - - qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ERR); - return 1; -} - static void qdio_establish_handle_irq(struct ccw_device *cdev, int cstat, int dstat) { struct qdio_irq *irq_ptr = cdev->private->qdio_data; DBF_DEV_EVENT(DBF_INFO, irq_ptr, "qest irq"); - if (!qdio_establish_check_errors(cdev, cstat, dstat)) - qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ESTABLISHED); + + if (cstat) + goto error; + if (dstat & ~(DEV_STAT_DEV_END | DEV_STAT_CHN_END)) + goto error; + if (!(dstat & DEV_STAT_DEV_END)) + goto error; + qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ESTABLISHED); + return; + +error: + DBF_ERROR("%4x EQ:error", irq_ptr->schid.sch_no); + DBF_ERROR("ds: %2x cs:%2x", dstat, cstat); + qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ERR); } /* qdio interrupt handler */ @@ -946,7 +939,6 @@ void qdio_int_handler(struct ccw_device *cdev, unsigned long intparm, } } qdio_irq_check_sense(irq_ptr, irb); - cstat = irb->scsw.cmd.cstat; dstat = irb->scsw.cmd.dstat; @@ -954,22 +946,19 @@ void qdio_int_handler(struct ccw_device *cdev, unsigned long intparm, case QDIO_IRQ_STATE_INACTIVE: qdio_establish_handle_irq(cdev, cstat, dstat); break; - case QDIO_IRQ_STATE_CLEANUP: qdio_set_state(irq_ptr, QDIO_IRQ_STATE_INACTIVE); break; - case QDIO_IRQ_STATE_ESTABLISHED: case QDIO_IRQ_STATE_ACTIVE: if (cstat & SCHN_STAT_PCI) { qdio_int_handler_pci(irq_ptr); return; } - if ((cstat & ~SCHN_STAT_PCI) || dstat) { + if (cstat || dstat) qdio_handle_activate_check(cdev, intparm, cstat, dstat); - break; - } + break; default: WARN_ON(1); } @@ -1508,18 +1497,13 @@ out: * @count: how many buffers to process */ int do_QDIO(struct ccw_device *cdev, unsigned int callflags, - int q_nr, int bufnr, int count) + int q_nr, unsigned int bufnr, unsigned int count) { struct qdio_irq *irq_ptr; - if ((bufnr > QDIO_MAX_BUFFERS_PER_Q) || - (count > QDIO_MAX_BUFFERS_PER_Q) || - (q_nr > QDIO_MAX_QUEUES_PER_IRQ)) + if (bufnr >= QDIO_MAX_BUFFERS_PER_Q || count > QDIO_MAX_BUFFERS_PER_Q) return -EINVAL; - if (!count) - return 0; - irq_ptr = cdev->private->qdio_data; if (!irq_ptr) return -ENODEV; diff --git a/drivers/s390/cio/qdio_perf.c b/drivers/s390/cio/qdio_perf.c index 136d0f0b1e93..eff943923c6f 100644 --- a/drivers/s390/cio/qdio_perf.c +++ b/drivers/s390/cio/qdio_perf.c @@ -25,18 +25,6 @@ struct qdio_perf_stats perf_stats; static struct proc_dir_entry *qdio_perf_pde; #endif -inline void qdio_perf_stat_inc(atomic_long_t *count) -{ - if (qdio_performance_stats) - atomic_long_inc(count); -} - -inline void qdio_perf_stat_dec(atomic_long_t *count) -{ - if (qdio_performance_stats) - atomic_long_dec(count); -} - /* * procfs functions */ diff --git a/drivers/s390/cio/qdio_perf.h b/drivers/s390/cio/qdio_perf.h index 7821ac4fa517..ff4504ce1e3c 100644 --- a/drivers/s390/cio/qdio_perf.h +++ b/drivers/s390/cio/qdio_perf.h @@ -9,7 +9,6 @@ #define QDIO_PERF_H #include -#include #include struct qdio_perf_stats { @@ -50,10 +49,13 @@ struct qdio_perf_stats { extern struct qdio_perf_stats perf_stats; extern int qdio_performance_stats; +static inline void qdio_perf_stat_inc(atomic_long_t *count) +{ + if (qdio_performance_stats) + atomic_long_inc(count); +} + int qdio_setup_perf_stats(void); void qdio_remove_perf_stats(void); -extern void qdio_perf_stat_inc(atomic_long_t *count); -extern void qdio_perf_stat_dec(atomic_long_t *count); - #endif diff --git a/drivers/s390/cio/qdio_thinint.c b/drivers/s390/cio/qdio_thinint.c index c655d011a78d..981a77ea7ee2 100644 --- a/drivers/s390/cio/qdio_thinint.c +++ b/drivers/s390/cio/qdio_thinint.c @@ -43,9 +43,6 @@ struct indicator_t { }; static struct indicator_t *q_indicators; -static void tiqdio_tasklet_fn(unsigned long data); -static DECLARE_TASKLET(tiqdio_tasklet, tiqdio_tasklet_fn, 0); - static int css_qdio_omit_svs; static inline unsigned long do_clear_global_summary(void) @@ -103,11 +100,6 @@ void tiqdio_add_input_queues(struct qdio_irq *irq_ptr) xchg(irq_ptr->dsci, 1); } -/* - * we cannot stop the tiqdio tasklet here since it is for all - * thinint qdio devices and it must run as long as there is a - * thinint device left - */ void tiqdio_remove_input_queues(struct qdio_irq *irq_ptr) { struct qdio_q *q; @@ -126,79 +118,39 @@ void tiqdio_remove_input_queues(struct qdio_irq *irq_ptr) } } -static inline int tiqdio_inbound_q_done(struct qdio_q *q) -{ - unsigned char state = 0; - - if (!atomic_read(&q->nr_buf_used)) - return 1; - - qdio_siga_sync_q(q); - get_buf_state(q, q->first_to_check, &state, 0); - - if (state == SLSB_P_INPUT_PRIMED) - /* more work coming */ - return 0; - return 1; -} - static inline int shared_ind(struct qdio_irq *irq_ptr) { return irq_ptr->dsci == &q_indicators[TIQDIO_SHARED_IND].ind; } -static void __tiqdio_inbound_processing(struct qdio_q *q) -{ - qdio_perf_stat_inc(&perf_stats.thinint_inbound); - qdio_sync_after_thinint(q); - - /* - * Maybe we have work on our outbound queues... at least - * we have to check the PCI capable queues. - */ - qdio_check_outbound_after_thinint(q); - - if (!qdio_inbound_q_moved(q)) - return; - - qdio_kick_handler(q); - - if (!tiqdio_inbound_q_done(q)) { - qdio_perf_stat_inc(&perf_stats.thinint_inbound_loop); - if (likely(q->irq_ptr->state != QDIO_IRQ_STATE_STOPPED)) - tasklet_schedule(&q->tasklet); - } - - qdio_stop_polling(q); - /* - * We need to check again to not lose initiative after - * resetting the ACK state. - */ - if (!tiqdio_inbound_q_done(q)) { - qdio_perf_stat_inc(&perf_stats.thinint_inbound_loop2); - if (likely(q->irq_ptr->state != QDIO_IRQ_STATE_STOPPED)) - tasklet_schedule(&q->tasklet); - } -} - -void tiqdio_inbound_processing(unsigned long data) -{ - struct qdio_q *q = (struct qdio_q *)data; - - __tiqdio_inbound_processing(q); -} - -/* check for work on all inbound thinint queues */ -static void tiqdio_tasklet_fn(unsigned long data) +/** + * tiqdio_thinint_handler - thin interrupt handler for qdio + * @ind: pointer to adapter local summary indicator + * @drv_data: NULL + */ +static void tiqdio_thinint_handler(void *ind, void *drv_data) { struct qdio_q *q; - qdio_perf_stat_inc(&perf_stats.tasklet_thinint); -again: + qdio_perf_stat_inc(&perf_stats.thin_int); + + /* + * SVS only when needed: issue SVS to benefit from iqdio interrupt + * avoidance (SVS clears adapter interrupt suppression overwrite) + */ + if (!css_qdio_omit_svs) + do_clear_global_summary(); + + /* + * reset local summary indicator (tiqdio_alsi) to stop adapter + * interrupts for now + */ + xchg((u8 *)ind, 0); /* protect tiq_list entries, only changed in activate or shutdown */ rcu_read_lock(); + /* check for work on all inbound thinint queues */ list_for_each_entry_rcu(q, &tiq_list, entry) /* only process queues from changed sets */ if (*q->irq_ptr->dsci) { @@ -226,37 +178,6 @@ again: if (*tiqdio_alsi) xchg(&q_indicators[TIQDIO_SHARED_IND].ind, 1); } - - /* check for more work */ - if (*tiqdio_alsi) { - xchg(tiqdio_alsi, 0); - qdio_perf_stat_inc(&perf_stats.tasklet_thinint_loop); - goto again; - } -} - -/** - * tiqdio_thinint_handler - thin interrupt handler for qdio - * @ind: pointer to adapter local summary indicator - * @drv_data: NULL - */ -static void tiqdio_thinint_handler(void *ind, void *drv_data) -{ - qdio_perf_stat_inc(&perf_stats.thin_int); - - /* - * SVS only when needed: issue SVS to benefit from iqdio interrupt - * avoidance (SVS clears adapter interrupt suppression overwrite) - */ - if (!css_qdio_omit_svs) - do_clear_global_summary(); - - /* - * reset local summary indicator (tiqdio_alsi) to stop adapter - * interrupts for now, the tasklet will clean all dsci's - */ - xchg((u8 *)ind, 0); - tasklet_hi_schedule(&tiqdio_tasklet); } static int set_subchannel_ind(struct qdio_irq *irq_ptr, int reset) @@ -376,5 +297,4 @@ void __exit tiqdio_unregister_thinints(void) s390_unregister_adapter_interrupt(tiqdio_alsi, QDIO_AIRQ_ISC); isc_unregister(QDIO_AIRQ_ISC); } - tasklet_kill(&tiqdio_tasklet); } diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 9c148406b980..727a809636d8 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -54,6 +54,12 @@ static int ap_poll_thread_start(void); static void ap_poll_thread_stop(void); static void ap_request_timeout(unsigned long); static inline void ap_schedule_poll_timer(void); +static int __ap_poll_device(struct ap_device *ap_dev, unsigned long *flags); +static int ap_device_remove(struct device *dev); +static int ap_device_probe(struct device *dev); +static void ap_interrupt_handler(void *unused1, void *unused2); +static void ap_reset(struct ap_device *ap_dev); +static void ap_config_timeout(unsigned long ptr); /* * Module description. @@ -101,6 +107,10 @@ static struct hrtimer ap_poll_timer; * If z/VM change to 1500000 nanoseconds to adjust to z/VM polling.*/ static unsigned long long poll_timeout = 250000; +/* Suspend flag */ +static int ap_suspend_flag; +static struct bus_type ap_bus_type; + /** * ap_using_interrupts() - Returns non-zero if interrupt support is * available. @@ -617,10 +627,79 @@ static int ap_uevent (struct device *dev, struct kobj_uevent_env *env) return retval; } +static int ap_bus_suspend(struct device *dev, pm_message_t state) +{ + struct ap_device *ap_dev = to_ap_dev(dev); + unsigned long flags; + + if (!ap_suspend_flag) { + ap_suspend_flag = 1; + + /* Disable scanning for devices, thus we do not want to scan + * for them after removing. + */ + del_timer_sync(&ap_config_timer); + if (ap_work_queue != NULL) { + destroy_workqueue(ap_work_queue); + ap_work_queue = NULL; + } + tasklet_disable(&ap_tasklet); + } + /* Poll on the device until all requests are finished. */ + do { + flags = 0; + __ap_poll_device(ap_dev, &flags); + } while ((flags & 1) || (flags & 2)); + + ap_device_remove(dev); + return 0; +} + +static int ap_bus_resume(struct device *dev) +{ + int rc = 0; + struct ap_device *ap_dev = to_ap_dev(dev); + + if (ap_suspend_flag) { + ap_suspend_flag = 0; + if (!ap_interrupts_available()) + ap_interrupt_indicator = NULL; + ap_device_probe(dev); + ap_reset(ap_dev); + setup_timer(&ap_dev->timeout, ap_request_timeout, + (unsigned long) ap_dev); + ap_scan_bus(NULL); + init_timer(&ap_config_timer); + ap_config_timer.function = ap_config_timeout; + ap_config_timer.data = 0; + ap_config_timer.expires = jiffies + ap_config_time * HZ; + add_timer(&ap_config_timer); + ap_work_queue = create_singlethread_workqueue("kapwork"); + if (!ap_work_queue) + return -ENOMEM; + tasklet_enable(&ap_tasklet); + if (!ap_using_interrupts()) + ap_schedule_poll_timer(); + else + tasklet_schedule(&ap_tasklet); + if (ap_thread_flag) + rc = ap_poll_thread_start(); + } else { + ap_device_probe(dev); + ap_reset(ap_dev); + setup_timer(&ap_dev->timeout, ap_request_timeout, + (unsigned long) ap_dev); + } + + return rc; +} + static struct bus_type ap_bus_type = { .name = "ap", .match = &ap_bus_match, .uevent = &ap_uevent, + .suspend = ap_bus_suspend, + .resume = ap_bus_resume }; static int ap_device_probe(struct device *dev) @@ -1066,7 +1145,7 @@ ap_config_timeout(unsigned long ptr) */ static inline void ap_schedule_poll_timer(void) { - if (ap_using_interrupts()) + if (ap_using_interrupts() || ap_suspend_flag) return; if (hrtimer_is_queued(&ap_poll_timer)) return; @@ -1384,6 +1463,8 @@ static int ap_poll_thread(void *data) set_user_nice(current, 19); while (1) { + if (ap_suspend_flag) + return 0; if (need_resched()) { schedule(); continue; @@ -1414,7 +1495,7 @@ static int ap_poll_thread_start(void) { int rc; - if (ap_using_interrupts()) + if (ap_using_interrupts() || ap_suspend_flag) return 0; mutex_lock(&ap_poll_thread_mutex); if (!ap_poll_kthread) { diff --git a/drivers/s390/kvm/kvm_virtio.c b/drivers/s390/kvm/kvm_virtio.c index cbc8566fab70..e38e5d306faf 100644 --- a/drivers/s390/kvm/kvm_virtio.c +++ b/drivers/s390/kvm/kvm_virtio.c @@ -173,8 +173,9 @@ static void kvm_notify(struct virtqueue *vq) * this device and sets it up. */ static struct virtqueue *kvm_find_vq(struct virtio_device *vdev, - unsigned index, - void (*callback)(struct virtqueue *vq)) + unsigned index, + void (*callback)(struct virtqueue *vq), + const char *name) { struct kvm_device *kdev = to_kvmdev(vdev); struct kvm_vqconfig *config; @@ -194,7 +195,7 @@ static struct virtqueue *kvm_find_vq(struct virtio_device *vdev, vq = vring_new_virtqueue(config->num, KVM_S390_VIRTIO_RING_ALIGN, vdev, (void *) config->address, - kvm_notify, callback); + kvm_notify, callback, name); if (!vq) { err = -ENOMEM; goto unmap; @@ -226,6 +227,38 @@ static void kvm_del_vq(struct virtqueue *vq) KVM_S390_VIRTIO_RING_ALIGN)); } +static void kvm_del_vqs(struct virtio_device *vdev) +{ + struct virtqueue *vq, *n; + + list_for_each_entry_safe(vq, n, &vdev->vqs, list) + kvm_del_vq(vq); +} + +static int kvm_find_vqs(struct virtio_device *vdev, unsigned nvqs, + struct virtqueue *vqs[], + vq_callback_t *callbacks[], + const char *names[]) +{ + struct kvm_device *kdev = to_kvmdev(vdev); + int i; + + /* We must have this many virtqueues. */ + if (nvqs > kdev->desc->num_vq) + return -ENOENT; + + for (i = 0; i < nvqs; ++i) { + vqs[i] = kvm_find_vq(vdev, i, callbacks[i], names[i]); + if (IS_ERR(vqs[i])) + goto error; + } + return 0; + +error: + kvm_del_vqs(vdev); + return PTR_ERR(vqs[i]); +} + /* * The config ops structure as defined by virtio config */ @@ -237,8 +270,8 @@ static struct virtio_config_ops kvm_vq_configspace_ops = { .get_status = kvm_get_status, .set_status = kvm_set_status, .reset = kvm_reset, - .find_vq = kvm_find_vq, - .del_vq = kvm_del_vq, + .find_vqs = kvm_find_vqs, + .del_vqs = kvm_del_vqs, }; /* diff --git a/drivers/s390/net/Kconfig b/drivers/s390/net/Kconfig index a7745c82b4ae..cb909a5b5047 100644 --- a/drivers/s390/net/Kconfig +++ b/drivers/s390/net/Kconfig @@ -8,7 +8,7 @@ config LCS Select this option if you want to use LCS networking on IBM System z. This device driver supports Token Ring (IEEE 802.5), FDDI (IEEE 802.7) and Ethernet. - To compile as a module, choose M. The module name is lcs.ko. + To compile as a module, choose M. The module name is lcs. If you do not know what it is, it's safe to choose Y. config CTCM @@ -21,7 +21,7 @@ config CTCM It also supports virtual CTCs when running under VM. This driver also supports channel-to-channel MPC SNA devices. MPC is an SNA protocol device used by Communication Server for Linux. - To compile as a module, choose M. The module name is ctcm.ko. + To compile as a module, choose M. The module name is ctcm. To compile into the kernel, choose Y. If you do not need any channel-to-channel connection, choose N. @@ -34,7 +34,7 @@ config NETIUCV link between VM guests. Using ifconfig a point-to-point connection can be established to the Linux on IBM System z running on the other VM guest. To compile as a module, choose M. - The module name is netiucv.ko. If unsure, choose Y. + The module name is netiucv. If unsure, choose Y. config SMSGIUCV tristate "IUCV special message support (VM only)" @@ -50,7 +50,7 @@ config CLAW This driver supports channel attached CLAW devices. CLAW is Common Link Access for Workstation. Common devices that use CLAW are RS/6000s, Cisco Routers (CIP) and 3172 devices. - To compile as a module, choose M. The module name is claw.ko. + To compile as a module, choose M. The module name is claw. To compile into the kernel, choose Y. config QETH @@ -65,14 +65,14 @@ config QETH To compile this driver as a module, choose M. - The module name is qeth.ko. + The module name is qeth. config QETH_L2 tristate "qeth layer 2 device support" depends on QETH help Select this option to be able to run qeth devices in layer 2 mode. - To compile as a module, choose M. The module name is qeth_l2.ko. + To compile as a module, choose M. The module name is qeth_l2. If unsure, choose y. config QETH_L3 @@ -80,7 +80,7 @@ config QETH_L3 depends on QETH help Select this option to be able to run qeth devices in layer 3 mode. - To compile as a module choose M. The module name is qeth_l3.ko. + To compile as a module choose M. The module name is qeth_l3. If unsure, choose Y. config QETH_IPV6 diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c index 30a43cc79e76..f370f8d460a7 100644 --- a/drivers/s390/net/claw.c +++ b/drivers/s390/net/claw.c @@ -3,12 +3,12 @@ * ESCON CLAW network driver * * Linux for zSeries version - * Copyright (C) 2002,2005 IBM Corporation + * Copyright IBM Corp. 2002, 2009 * Author(s) Original code written by: - * Kazuo Iimura (iimura@jp.ibm.com) + * Kazuo Iimura * Rewritten by - * Andy Richter (richtera@us.ibm.com) - * Marc Price (mwprice@us.ibm.com) + * Andy Richter + * Marc Price * * sysfs parms: * group x.x.rrrr,x.x.wwww @@ -253,6 +253,11 @@ static void claw_free_wrt_buf(struct net_device *dev); /* Functions for unpack reads */ static void unpack_read(struct net_device *dev); +static int claw_pm_prepare(struct ccwgroup_device *gdev) +{ + return -EPERM; +} + /* ccwgroup table */ static struct ccwgroup_driver claw_group_driver = { @@ -264,6 +269,7 @@ static struct ccwgroup_driver claw_group_driver = { .remove = claw_remove_device, .set_online = claw_new_device, .set_offline = claw_shutdown_device, + .prepare = claw_pm_prepare, }; /* @@ -284,7 +290,7 @@ claw_probe(struct ccwgroup_device *cgdev) if (!get_device(&cgdev->dev)) return -ENODEV; privptr = kzalloc(sizeof(struct claw_privbk), GFP_KERNEL); - cgdev->dev.driver_data = privptr; + dev_set_drvdata(&cgdev->dev, privptr); if (privptr == NULL) { probe_error(cgdev); put_device(&cgdev->dev); @@ -338,12 +344,6 @@ claw_tx(struct sk_buff *skb, struct net_device *dev) CLAW_DBF_TEXT(4, trace, "claw_tx"); p_ch=&privptr->channel[WRITE]; - if (skb == NULL) { - privptr->stats.tx_dropped++; - privptr->stats.tx_errors++; - CLAW_DBF_TEXT_(2, trace, "clawtx%d", -EIO); - return -EIO; - } spin_lock_irqsave(get_ccwdev_lock(p_ch->cdev), saveflags); rc=claw_hw_tx( skb, dev, 1 ); spin_unlock_irqrestore(get_ccwdev_lock(p_ch->cdev), saveflags); @@ -597,14 +597,14 @@ claw_irq_handler(struct ccw_device *cdev, CLAW_DBF_TEXT(4, trace, "clawirq"); /* Bypass all 'unsolicited interrupts' */ - if (!cdev->dev.driver_data) { + privptr = dev_get_drvdata(&cdev->dev); + if (!privptr) { dev_warn(&cdev->dev, "An uninitialized CLAW device received an" " IRQ, c-%02x d-%02x\n", irb->scsw.cmd.cstat, irb->scsw.cmd.dstat); CLAW_DBF_TEXT(2, trace, "badirq"); return; } - privptr = (struct claw_privbk *)cdev->dev.driver_data; /* Try to extract channel from driver data. */ if (privptr->channel[READ].cdev == cdev) @@ -1986,9 +1986,9 @@ probe_error( struct ccwgroup_device *cgdev) struct claw_privbk *privptr; CLAW_DBF_TEXT(4, trace, "proberr"); - privptr = (struct claw_privbk *) cgdev->dev.driver_data; + privptr = dev_get_drvdata(&cgdev->dev); if (privptr != NULL) { - cgdev->dev.driver_data = NULL; + dev_set_drvdata(&cgdev->dev, NULL); kfree(privptr->p_env); kfree(privptr->p_mtc_envelope); kfree(privptr); @@ -2917,9 +2917,9 @@ claw_new_device(struct ccwgroup_device *cgdev) dev_info(&cgdev->dev, "add for %s\n", dev_name(&cgdev->cdev[READ]->dev)); CLAW_DBF_TEXT(2, setup, "new_dev"); - privptr = cgdev->dev.driver_data; - cgdev->cdev[READ]->dev.driver_data = privptr; - cgdev->cdev[WRITE]->dev.driver_data = privptr; + privptr = dev_get_drvdata(&cgdev->dev); + dev_set_drvdata(&cgdev->cdev[READ]->dev, privptr); + dev_set_drvdata(&cgdev->cdev[WRITE]->dev, privptr); if (!privptr) return -ENODEV; p_env = privptr->p_env; @@ -2956,9 +2956,9 @@ claw_new_device(struct ccwgroup_device *cgdev) goto out; } dev->ml_priv = privptr; - cgdev->dev.driver_data = privptr; - cgdev->cdev[READ]->dev.driver_data = privptr; - cgdev->cdev[WRITE]->dev.driver_data = privptr; + dev_set_drvdata(&cgdev->dev, privptr); + dev_set_drvdata(&cgdev->cdev[READ]->dev, privptr); + dev_set_drvdata(&cgdev->cdev[WRITE]->dev, privptr); /* sysfs magic */ SET_NETDEV_DEV(dev, &cgdev->dev); if (register_netdev(dev) != 0) { @@ -3024,7 +3024,7 @@ claw_shutdown_device(struct ccwgroup_device *cgdev) int ret; CLAW_DBF_TEXT_(2, setup, "%s", dev_name(&cgdev->dev)); - priv = cgdev->dev.driver_data; + priv = dev_get_drvdata(&cgdev->dev); if (!priv) return -ENODEV; ndev = priv->channel[READ].ndev; @@ -3054,7 +3054,7 @@ claw_remove_device(struct ccwgroup_device *cgdev) BUG_ON(!cgdev); CLAW_DBF_TEXT_(2, setup, "%s", dev_name(&cgdev->dev)); - priv = cgdev->dev.driver_data; + priv = dev_get_drvdata(&cgdev->dev); BUG_ON(!priv); dev_info(&cgdev->dev, " will be removed.\n"); if (cgdev->state == CCWGROUP_ONLINE) @@ -3069,9 +3069,9 @@ claw_remove_device(struct ccwgroup_device *cgdev) kfree(priv->channel[1].irb); priv->channel[1].irb=NULL; kfree(priv); - cgdev->dev.driver_data=NULL; - cgdev->cdev[READ]->dev.driver_data = NULL; - cgdev->cdev[WRITE]->dev.driver_data = NULL; + dev_set_drvdata(&cgdev->dev, NULL); + dev_set_drvdata(&cgdev->cdev[READ]->dev, NULL); + dev_set_drvdata(&cgdev->cdev[WRITE]->dev, NULL); put_device(&cgdev->dev); return; @@ -3087,7 +3087,7 @@ claw_hname_show(struct device *dev, struct device_attribute *attr, char *buf) struct claw_privbk *priv; struct claw_env * p_env; - priv = dev->driver_data; + priv = dev_get_drvdata(dev); if (!priv) return -ENODEV; p_env = priv->p_env; @@ -3101,7 +3101,7 @@ claw_hname_write(struct device *dev, struct device_attribute *attr, struct claw_privbk *priv; struct claw_env * p_env; - priv = dev->driver_data; + priv = dev_get_drvdata(dev); if (!priv) return -ENODEV; p_env = priv->p_env; @@ -3125,7 +3125,7 @@ claw_adname_show(struct device *dev, struct device_attribute *attr, char *buf) struct claw_privbk *priv; struct claw_env * p_env; - priv = dev->driver_data; + priv = dev_get_drvdata(dev); if (!priv) return -ENODEV; p_env = priv->p_env; @@ -3139,7 +3139,7 @@ claw_adname_write(struct device *dev, struct device_attribute *attr, struct claw_privbk *priv; struct claw_env * p_env; - priv = dev->driver_data; + priv = dev_get_drvdata(dev); if (!priv) return -ENODEV; p_env = priv->p_env; @@ -3163,7 +3163,7 @@ claw_apname_show(struct device *dev, struct device_attribute *attr, char *buf) struct claw_privbk *priv; struct claw_env * p_env; - priv = dev->driver_data; + priv = dev_get_drvdata(dev); if (!priv) return -ENODEV; p_env = priv->p_env; @@ -3178,7 +3178,7 @@ claw_apname_write(struct device *dev, struct device_attribute *attr, struct claw_privbk *priv; struct claw_env * p_env; - priv = dev->driver_data; + priv = dev_get_drvdata(dev); if (!priv) return -ENODEV; p_env = priv->p_env; @@ -3212,7 +3212,7 @@ claw_wbuff_show(struct device *dev, struct device_attribute *attr, char *buf) struct claw_privbk *priv; struct claw_env * p_env; - priv = dev->driver_data; + priv = dev_get_drvdata(dev); if (!priv) return -ENODEV; p_env = priv->p_env; @@ -3227,7 +3227,7 @@ claw_wbuff_write(struct device *dev, struct device_attribute *attr, struct claw_env * p_env; int nnn,max; - priv = dev->driver_data; + priv = dev_get_drvdata(dev); if (!priv) return -ENODEV; p_env = priv->p_env; @@ -3254,7 +3254,7 @@ claw_rbuff_show(struct device *dev, struct device_attribute *attr, char *buf) struct claw_privbk *priv; struct claw_env * p_env; - priv = dev->driver_data; + priv = dev_get_drvdata(dev); if (!priv) return -ENODEV; p_env = priv->p_env; @@ -3269,7 +3269,7 @@ claw_rbuff_write(struct device *dev, struct device_attribute *attr, struct claw_env *p_env; int nnn,max; - priv = dev->driver_data; + priv = dev_get_drvdata(dev); if (!priv) return -ENODEV; p_env = priv->p_env; diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c index 77f4033a0f4f..222e47394437 100644 --- a/drivers/s390/net/ctcm_main.c +++ b/drivers/s390/net/ctcm_main.c @@ -1,7 +1,7 @@ /* * drivers/s390/net/ctcm_main.c * - * Copyright IBM Corp. 2001, 2007 + * Copyright IBM Corp. 2001, 2009 * Author(s): * Original CTC driver(s): * Fritz Elfert (felfert@millenux.com) @@ -1677,10 +1677,8 @@ static void ctcm_remove_device(struct ccwgroup_device *cgdev) BUG_ON(priv == NULL); CTCM_DBF_TEXT_(SETUP, CTC_DBF_INFO, - "removing device %s, r/w = %s/%s, proto : %d", - priv->channel[READ]->netdev->name, - priv->channel[READ]->id, priv->channel[WRITE]->id, - priv->protocol); + "removing device %p, proto : %d", + cgdev, priv->protocol); if (cgdev->state == CCWGROUP_ONLINE) ctcm_shutdown_device(cgdev); @@ -1690,6 +1688,38 @@ static void ctcm_remove_device(struct ccwgroup_device *cgdev) put_device(&cgdev->dev); } +static int ctcm_pm_suspend(struct ccwgroup_device *gdev) +{ + struct ctcm_priv *priv = dev_get_drvdata(&gdev->dev); + + if (gdev->state == CCWGROUP_OFFLINE) + return 0; + netif_device_detach(priv->channel[READ]->netdev); + ctcm_close(priv->channel[READ]->netdev); + ccw_device_set_offline(gdev->cdev[1]); + ccw_device_set_offline(gdev->cdev[0]); + return 0; +} + +static int ctcm_pm_resume(struct ccwgroup_device *gdev) +{ + struct ctcm_priv *priv = dev_get_drvdata(&gdev->dev); + int rc; + + if (gdev->state == CCWGROUP_OFFLINE) + return 0; + rc = ccw_device_set_online(gdev->cdev[1]); + if (rc) + goto err_out; + rc = ccw_device_set_online(gdev->cdev[0]); + if (rc) + goto err_out; + ctcm_open(priv->channel[READ]->netdev); +err_out: + netif_device_attach(priv->channel[READ]->netdev); + return rc; +} + static struct ccwgroup_driver ctcm_group_driver = { .owner = THIS_MODULE, .name = CTC_DRIVER_NAME, @@ -1699,6 +1729,9 @@ static struct ccwgroup_driver ctcm_group_driver = { .remove = ctcm_remove_device, .set_online = ctcm_new_device, .set_offline = ctcm_shutdown_device, + .freeze = ctcm_pm_suspend, + .thaw = ctcm_pm_resume, + .restore = ctcm_pm_resume, }; diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index a45bc24eb5f9..8c675905448b 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -1,15 +1,12 @@ /* - * linux/drivers/s390/net/lcs.c - * * Linux for S/390 Lan Channel Station Network Driver * - * Copyright (C) 1999-2001 IBM Deutschland Entwicklung GmbH, - * IBM Corporation - * Author(s): Original Code written by - * DJ Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) - * Rewritten by - * Frank Pavlic (fpavlic@de.ibm.com) and - * Martin Schwidefsky + * Copyright IBM Corp. 1999, 2009 + * Author(s): Original Code written by + * DJ Barrow + * Rewritten by + * Frank Pavlic and + * Martin Schwidefsky * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -1939,7 +1936,7 @@ lcs_portno_show (struct device *dev, struct device_attribute *attr, char *buf) { struct lcs_card *card; - card = (struct lcs_card *)dev->driver_data; + card = dev_get_drvdata(dev); if (!card) return 0; @@ -1956,7 +1953,7 @@ lcs_portno_store (struct device *dev, struct device_attribute *attr, const char struct lcs_card *card; int value; - card = (struct lcs_card *)dev->driver_data; + card = dev_get_drvdata(dev); if (!card) return 0; @@ -1990,7 +1987,7 @@ lcs_timeout_show(struct device *dev, struct device_attribute *attr, char *buf) { struct lcs_card *card; - card = (struct lcs_card *)dev->driver_data; + card = dev_get_drvdata(dev); return card ? sprintf(buf, "%u\n", card->lancmd_timeout) : 0; } @@ -2001,7 +1998,7 @@ lcs_timeout_store (struct device *dev, struct device_attribute *attr, const char struct lcs_card *card; int value; - card = (struct lcs_card *)dev->driver_data; + card = dev_get_drvdata(dev); if (!card) return 0; @@ -2020,7 +2017,7 @@ static ssize_t lcs_dev_recover_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct lcs_card *card = dev->driver_data; + struct lcs_card *card = dev_get_drvdata(dev); char *tmp; int i; @@ -2073,7 +2070,7 @@ lcs_probe_device(struct ccwgroup_device *ccwgdev) put_device(&ccwgdev->dev); return ret; } - ccwgdev->dev.driver_data = card; + dev_set_drvdata(&ccwgdev->dev, card); ccwgdev->cdev[0]->handler = lcs_irq; ccwgdev->cdev[1]->handler = lcs_irq; card->gdev = ccwgdev; @@ -2090,7 +2087,7 @@ lcs_register_netdev(struct ccwgroup_device *ccwgdev) struct lcs_card *card; LCS_DBF_TEXT(2, setup, "regnetdv"); - card = (struct lcs_card *)ccwgdev->dev.driver_data; + card = dev_get_drvdata(&ccwgdev->dev); if (card->dev->reg_state != NETREG_UNINITIALIZED) return 0; SET_NETDEV_DEV(card->dev, &ccwgdev->dev); @@ -2123,7 +2120,7 @@ lcs_new_device(struct ccwgroup_device *ccwgdev) enum lcs_dev_states recover_state; int rc; - card = (struct lcs_card *)ccwgdev->dev.driver_data; + card = dev_get_drvdata(&ccwgdev->dev); if (!card) return -ENODEV; @@ -2229,7 +2226,7 @@ __lcs_shutdown_device(struct ccwgroup_device *ccwgdev, int recovery_mode) int ret; LCS_DBF_TEXT(3, setup, "shtdndev"); - card = (struct lcs_card *)ccwgdev->dev.driver_data; + card = dev_get_drvdata(&ccwgdev->dev); if (!card) return -ENODEV; if (recovery_mode == 0) { @@ -2296,7 +2293,7 @@ lcs_remove_device(struct ccwgroup_device *ccwgdev) { struct lcs_card *card; - card = (struct lcs_card *)ccwgdev->dev.driver_data; + card = dev_get_drvdata(&ccwgdev->dev); if (!card) return; @@ -2313,6 +2310,60 @@ lcs_remove_device(struct ccwgroup_device *ccwgdev) put_device(&ccwgdev->dev); } +static int lcs_pm_suspend(struct lcs_card *card) +{ + if (card->dev) + netif_device_detach(card->dev); + lcs_set_allowed_threads(card, 0); + lcs_wait_for_threads(card, 0xffffffff); + if (card->state != DEV_STATE_DOWN) + __lcs_shutdown_device(card->gdev, 1); + return 0; +} + +static int lcs_pm_resume(struct lcs_card *card) +{ + int rc = 0; + + if (card->state == DEV_STATE_RECOVER) + rc = lcs_new_device(card->gdev); + if (card->dev) + netif_device_attach(card->dev); + if (rc) { + dev_warn(&card->gdev->dev, "The lcs device driver " + "failed to recover the device\n"); + } + return rc; +} + +static int lcs_prepare(struct ccwgroup_device *gdev) +{ + return 0; +} + +static void lcs_complete(struct ccwgroup_device *gdev) +{ + return; +} + +static int lcs_freeze(struct ccwgroup_device *gdev) +{ + struct lcs_card *card = dev_get_drvdata(&gdev->dev); + return lcs_pm_suspend(card); +} + +static int lcs_thaw(struct ccwgroup_device *gdev) +{ + struct lcs_card *card = dev_get_drvdata(&gdev->dev); + return lcs_pm_resume(card); +} + +static int lcs_restore(struct ccwgroup_device *gdev) +{ + struct lcs_card *card = dev_get_drvdata(&gdev->dev); + return lcs_pm_resume(card); +} + /** * LCS ccwgroup driver registration */ @@ -2325,6 +2376,11 @@ static struct ccwgroup_driver lcs_group_driver = { .remove = lcs_remove_device, .set_online = lcs_new_device, .set_offline = lcs_shutdown_device, + .prepare = lcs_prepare, + .complete = lcs_complete, + .freeze = lcs_freeze, + .thaw = lcs_thaw, + .restore = lcs_restore, }; /** diff --git a/drivers/s390/net/lcs.h b/drivers/s390/net/lcs.h index d58fea52557d..6d668642af27 100644 --- a/drivers/s390/net/lcs.h +++ b/drivers/s390/net/lcs.h @@ -34,8 +34,8 @@ static inline int lcs_dbf_passes(debug_info_t *dbf_grp, int level) * sysfs related stuff */ #define CARD_FROM_DEV(cdev) \ - (struct lcs_card *) \ - ((struct ccwgroup_device *)cdev->dev.driver_data)->dev.driver_data; + (struct lcs_card *) dev_get_drvdata( \ + &((struct ccwgroup_device *)dev_get_drvdata(&cdev->dev))->dev); /** * CCW commands used in this driver */ diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index be716e45f7ac..8c36eafcfbfe 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c @@ -1,11 +1,15 @@ /* * IUCV network driver * - * Copyright 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com) + * Copyright IBM Corp. 2001, 2009 * - * Sysfs integration and all bugs therein by Cornelia Huck - * (cornelia.huck@de.ibm.com) + * Author(s): + * Original netiucv driver: + * Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com) + * Sysfs integration and all bugs therein: + * Cornelia Huck (cornelia.huck@de.ibm.com) + * PM functions: + * Ursula Braun (ursula.braun@de.ibm.com) * * Documentation used: * the source of the original IUCV driver by: @@ -149,10 +153,27 @@ PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \ #define PRINTK_HEADER " iucv: " /* for debugging */ +/* dummy device to make sure netiucv_pm functions are called */ +static struct device *netiucv_dev; + +static int netiucv_pm_prepare(struct device *); +static void netiucv_pm_complete(struct device *); +static int netiucv_pm_freeze(struct device *); +static int netiucv_pm_restore_thaw(struct device *); + +static struct dev_pm_ops netiucv_pm_ops = { + .prepare = netiucv_pm_prepare, + .complete = netiucv_pm_complete, + .freeze = netiucv_pm_freeze, + .thaw = netiucv_pm_restore_thaw, + .restore = netiucv_pm_restore_thaw, +}; + static struct device_driver netiucv_driver = { .owner = THIS_MODULE, .name = "netiucv", .bus = &iucv_bus, + .pm = &netiucv_pm_ops, }; static int netiucv_callback_connreq(struct iucv_path *, @@ -233,6 +254,7 @@ struct netiucv_priv { fsm_instance *fsm; struct iucv_connection *conn; struct device *dev; + int pm_state; }; /** @@ -1265,6 +1287,72 @@ static int netiucv_close(struct net_device *dev) return 0; } +static int netiucv_pm_prepare(struct device *dev) +{ + IUCV_DBF_TEXT(trace, 3, __func__); + return 0; +} + +static void netiucv_pm_complete(struct device *dev) +{ + IUCV_DBF_TEXT(trace, 3, __func__); + return; +} + +/** + * netiucv_pm_freeze() - Freeze PM callback + * @dev: netiucv device + * + * close open netiucv interfaces + */ +static int netiucv_pm_freeze(struct device *dev) +{ + struct netiucv_priv *priv = dev_get_drvdata(dev); + struct net_device *ndev = NULL; + int rc = 0; + + IUCV_DBF_TEXT(trace, 3, __func__); + if (priv && priv->conn) + ndev = priv->conn->netdev; + if (!ndev) + goto out; + netif_device_detach(ndev); + priv->pm_state = fsm_getstate(priv->fsm); + rc = netiucv_close(ndev); +out: + return rc; +} + +/** + * netiucv_pm_restore_thaw() - Thaw and restore PM callback + * @dev: netiucv device + * + * re-open netiucv interfaces closed during freeze + */ +static int netiucv_pm_restore_thaw(struct device *dev) +{ + struct netiucv_priv *priv = dev_get_drvdata(dev); + struct net_device *ndev = NULL; + int rc = 0; + + IUCV_DBF_TEXT(trace, 3, __func__); + if (priv && priv->conn) + ndev = priv->conn->netdev; + if (!ndev) + goto out; + switch (priv->pm_state) { + case DEV_STATE_RUNNING: + case DEV_STATE_STARTWAIT: + rc = netiucv_open(ndev); + break; + default: + break; + } + netif_device_attach(ndev); +out: + return rc; +} + /** * Start transmission of a packet. * Called from generic network device layer. @@ -1315,9 +1403,9 @@ static int netiucv_tx(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_BUSY; } dev->trans_start = jiffies; - rc = netiucv_transmit_skb(privptr->conn, skb) != 0; + rc = netiucv_transmit_skb(privptr->conn, skb); netiucv_clear_busy(dev); - return rc; + return rc ? NETDEV_TX_BUSY : NETDEV_TX_OK; } /** @@ -1364,7 +1452,7 @@ static int netiucv_change_mtu(struct net_device * dev, int new_mtu) static ssize_t user_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct netiucv_priv *priv = dev->driver_data; + struct netiucv_priv *priv = dev_get_drvdata(dev); IUCV_DBF_TEXT(trace, 5, __func__); return sprintf(buf, "%s\n", netiucv_printname(priv->conn->userid)); @@ -1373,7 +1461,7 @@ static ssize_t user_show(struct device *dev, struct device_attribute *attr, static ssize_t user_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct netiucv_priv *priv = dev->driver_data; + struct netiucv_priv *priv = dev_get_drvdata(dev); struct net_device *ndev = priv->conn->netdev; char *p; char *tmp; @@ -1430,7 +1518,8 @@ static DEVICE_ATTR(user, 0644, user_show, user_write); static ssize_t buffer_show (struct device *dev, struct device_attribute *attr, char *buf) -{ struct netiucv_priv *priv = dev->driver_data; +{ + struct netiucv_priv *priv = dev_get_drvdata(dev); IUCV_DBF_TEXT(trace, 5, __func__); return sprintf(buf, "%d\n", priv->conn->max_buffsize); @@ -1439,7 +1528,7 @@ static ssize_t buffer_show (struct device *dev, struct device_attribute *attr, static ssize_t buffer_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct netiucv_priv *priv = dev->driver_data; + struct netiucv_priv *priv = dev_get_drvdata(dev); struct net_device *ndev = priv->conn->netdev; char *e; int bs1; @@ -1487,7 +1576,7 @@ static DEVICE_ATTR(buffer, 0644, buffer_show, buffer_write); static ssize_t dev_fsm_show (struct device *dev, struct device_attribute *attr, char *buf) { - struct netiucv_priv *priv = dev->driver_data; + struct netiucv_priv *priv = dev_get_drvdata(dev); IUCV_DBF_TEXT(trace, 5, __func__); return sprintf(buf, "%s\n", fsm_getstate_str(priv->fsm)); @@ -1498,7 +1587,7 @@ static DEVICE_ATTR(device_fsm_state, 0444, dev_fsm_show, NULL); static ssize_t conn_fsm_show (struct device *dev, struct device_attribute *attr, char *buf) { - struct netiucv_priv *priv = dev->driver_data; + struct netiucv_priv *priv = dev_get_drvdata(dev); IUCV_DBF_TEXT(trace, 5, __func__); return sprintf(buf, "%s\n", fsm_getstate_str(priv->conn->fsm)); @@ -1509,7 +1598,7 @@ static DEVICE_ATTR(connection_fsm_state, 0444, conn_fsm_show, NULL); static ssize_t maxmulti_show (struct device *dev, struct device_attribute *attr, char *buf) { - struct netiucv_priv *priv = dev->driver_data; + struct netiucv_priv *priv = dev_get_drvdata(dev); IUCV_DBF_TEXT(trace, 5, __func__); return sprintf(buf, "%ld\n", priv->conn->prof.maxmulti); @@ -1519,7 +1608,7 @@ static ssize_t maxmulti_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct netiucv_priv *priv = dev->driver_data; + struct netiucv_priv *priv = dev_get_drvdata(dev); IUCV_DBF_TEXT(trace, 4, __func__); priv->conn->prof.maxmulti = 0; @@ -1531,7 +1620,7 @@ static DEVICE_ATTR(max_tx_buffer_used, 0644, maxmulti_show, maxmulti_write); static ssize_t maxcq_show (struct device *dev, struct device_attribute *attr, char *buf) { - struct netiucv_priv *priv = dev->driver_data; + struct netiucv_priv *priv = dev_get_drvdata(dev); IUCV_DBF_TEXT(trace, 5, __func__); return sprintf(buf, "%ld\n", priv->conn->prof.maxcqueue); @@ -1540,7 +1629,7 @@ static ssize_t maxcq_show (struct device *dev, struct device_attribute *attr, static ssize_t maxcq_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct netiucv_priv *priv = dev->driver_data; + struct netiucv_priv *priv = dev_get_drvdata(dev); IUCV_DBF_TEXT(trace, 4, __func__); priv->conn->prof.maxcqueue = 0; @@ -1552,7 +1641,7 @@ static DEVICE_ATTR(max_chained_skbs, 0644, maxcq_show, maxcq_write); static ssize_t sdoio_show (struct device *dev, struct device_attribute *attr, char *buf) { - struct netiucv_priv *priv = dev->driver_data; + struct netiucv_priv *priv = dev_get_drvdata(dev); IUCV_DBF_TEXT(trace, 5, __func__); return sprintf(buf, "%ld\n", priv->conn->prof.doios_single); @@ -1561,7 +1650,7 @@ static ssize_t sdoio_show (struct device *dev, struct device_attribute *attr, static ssize_t sdoio_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct netiucv_priv *priv = dev->driver_data; + struct netiucv_priv *priv = dev_get_drvdata(dev); IUCV_DBF_TEXT(trace, 4, __func__); priv->conn->prof.doios_single = 0; @@ -1573,7 +1662,7 @@ static DEVICE_ATTR(tx_single_write_ops, 0644, sdoio_show, sdoio_write); static ssize_t mdoio_show (struct device *dev, struct device_attribute *attr, char *buf) { - struct netiucv_priv *priv = dev->driver_data; + struct netiucv_priv *priv = dev_get_drvdata(dev); IUCV_DBF_TEXT(trace, 5, __func__); return sprintf(buf, "%ld\n", priv->conn->prof.doios_multi); @@ -1582,7 +1671,7 @@ static ssize_t mdoio_show (struct device *dev, struct device_attribute *attr, static ssize_t mdoio_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct netiucv_priv *priv = dev->driver_data; + struct netiucv_priv *priv = dev_get_drvdata(dev); IUCV_DBF_TEXT(trace, 5, __func__); priv->conn->prof.doios_multi = 0; @@ -1594,7 +1683,7 @@ static DEVICE_ATTR(tx_multi_write_ops, 0644, mdoio_show, mdoio_write); static ssize_t txlen_show (struct device *dev, struct device_attribute *attr, char *buf) { - struct netiucv_priv *priv = dev->driver_data; + struct netiucv_priv *priv = dev_get_drvdata(dev); IUCV_DBF_TEXT(trace, 5, __func__); return sprintf(buf, "%ld\n", priv->conn->prof.txlen); @@ -1603,7 +1692,7 @@ static ssize_t txlen_show (struct device *dev, struct device_attribute *attr, static ssize_t txlen_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct netiucv_priv *priv = dev->driver_data; + struct netiucv_priv *priv = dev_get_drvdata(dev); IUCV_DBF_TEXT(trace, 4, __func__); priv->conn->prof.txlen = 0; @@ -1615,7 +1704,7 @@ static DEVICE_ATTR(netto_bytes, 0644, txlen_show, txlen_write); static ssize_t txtime_show (struct device *dev, struct device_attribute *attr, char *buf) { - struct netiucv_priv *priv = dev->driver_data; + struct netiucv_priv *priv = dev_get_drvdata(dev); IUCV_DBF_TEXT(trace, 5, __func__); return sprintf(buf, "%ld\n", priv->conn->prof.tx_time); @@ -1624,7 +1713,7 @@ static ssize_t txtime_show (struct device *dev, struct device_attribute *attr, static ssize_t txtime_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct netiucv_priv *priv = dev->driver_data; + struct netiucv_priv *priv = dev_get_drvdata(dev); IUCV_DBF_TEXT(trace, 4, __func__); priv->conn->prof.tx_time = 0; @@ -1636,7 +1725,7 @@ static DEVICE_ATTR(max_tx_io_time, 0644, txtime_show, txtime_write); static ssize_t txpend_show (struct device *dev, struct device_attribute *attr, char *buf) { - struct netiucv_priv *priv = dev->driver_data; + struct netiucv_priv *priv = dev_get_drvdata(dev); IUCV_DBF_TEXT(trace, 5, __func__); return sprintf(buf, "%ld\n", priv->conn->prof.tx_pending); @@ -1645,7 +1734,7 @@ static ssize_t txpend_show (struct device *dev, struct device_attribute *attr, static ssize_t txpend_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct netiucv_priv *priv = dev->driver_data; + struct netiucv_priv *priv = dev_get_drvdata(dev); IUCV_DBF_TEXT(trace, 4, __func__); priv->conn->prof.tx_pending = 0; @@ -1657,7 +1746,7 @@ static DEVICE_ATTR(tx_pending, 0644, txpend_show, txpend_write); static ssize_t txmpnd_show (struct device *dev, struct device_attribute *attr, char *buf) { - struct netiucv_priv *priv = dev->driver_data; + struct netiucv_priv *priv = dev_get_drvdata(dev); IUCV_DBF_TEXT(trace, 5, __func__); return sprintf(buf, "%ld\n", priv->conn->prof.tx_max_pending); @@ -1666,7 +1755,7 @@ static ssize_t txmpnd_show (struct device *dev, struct device_attribute *attr, static ssize_t txmpnd_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct netiucv_priv *priv = dev->driver_data; + struct netiucv_priv *priv = dev_get_drvdata(dev); IUCV_DBF_TEXT(trace, 4, __func__); priv->conn->prof.tx_max_pending = 0; @@ -1731,7 +1820,6 @@ static int netiucv_register_device(struct net_device *ndev) struct device *dev = kzalloc(sizeof(struct device), GFP_KERNEL); int ret; - IUCV_DBF_TEXT(trace, 3, __func__); if (dev) { @@ -1758,7 +1846,7 @@ static int netiucv_register_device(struct net_device *ndev) if (ret) goto out_unreg; priv->dev = dev; - dev->driver_data = priv; + dev_set_drvdata(dev, priv); return 0; out_unreg: @@ -2100,6 +2188,7 @@ static void __exit netiucv_exit(void) netiucv_unregister_device(dev); } + device_unregister(netiucv_dev); driver_unregister(&netiucv_driver); iucv_unregister(&netiucv_handler, 1); iucv_unregister_dbf_views(); @@ -2125,10 +2214,25 @@ static int __init netiucv_init(void) IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_register\n", rc); goto out_iucv; } - + /* establish dummy device */ + netiucv_dev = kzalloc(sizeof(struct device), GFP_KERNEL); + if (!netiucv_dev) { + rc = -ENOMEM; + goto out_driver; + } + dev_set_name(netiucv_dev, "netiucv"); + netiucv_dev->bus = &iucv_bus; + netiucv_dev->parent = iucv_root; + netiucv_dev->release = (void (*)(struct device *))kfree; + netiucv_dev->driver = &netiucv_driver; + rc = device_register(netiucv_dev); + if (rc) + goto out_driver; netiucv_banner(); return rc; +out_driver: + driver_unregister(&netiucv_driver); out_iucv: iucv_unregister(&netiucv_handler, 1); out_dbf: diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index c827d69b5a91..d53621c4acbb 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -1,7 +1,7 @@ /* * drivers/s390/net/qeth_core_main.c * - * Copyright IBM Corp. 2007 + * Copyright IBM Corp. 2007, 2009 * Author(s): Utz Bacher , * Frank Pavlic , * Thomas Spatzier , @@ -952,6 +952,7 @@ static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue, buf->buffer->element[i].addr = NULL; buf->buffer->element[i].flags = 0; } + buf->buffer->element[15].flags = 0; buf->next_element_to_fill = 0; atomic_set(&buf->state, QETH_QDIO_BUF_EMPTY); } @@ -1140,6 +1141,8 @@ static int qeth_setup_card(struct qeth_card *card) card->ipato.enabled = 0; card->ipato.invert4 = 0; card->ipato.invert6 = 0; + if (card->info.type == QETH_CARD_TYPE_IQD) + card->options.checksum_type = NO_CHECKSUMMING; /* init QDIO stuff */ qeth_init_qdio_info(card); return 0; @@ -2934,8 +2937,8 @@ int qeth_get_cast_type(struct qeth_card *card, struct sk_buff *skb) if (card->info.type == QETH_CARD_TYPE_OSN) return cast_type; - if (skb->dst && skb->dst->neighbour) { - cast_type = skb->dst->neighbour->type; + if (skb_dst(skb) && skb_dst(skb)->neighbour) { + cast_type = skb_dst(skb)->neighbour->type; if ((cast_type == RTN_BROADCAST) || (cast_type == RTN_MULTICAST) || (cast_type == RTN_ANYCAST)) @@ -4192,6 +4195,50 @@ static void qeth_core_shutdown(struct ccwgroup_device *gdev) card->discipline.ccwgdriver->shutdown(gdev); } +static int qeth_core_prepare(struct ccwgroup_device *gdev) +{ + struct qeth_card *card = dev_get_drvdata(&gdev->dev); + if (card->discipline.ccwgdriver && + card->discipline.ccwgdriver->prepare) + return card->discipline.ccwgdriver->prepare(gdev); + return 0; +} + +static void qeth_core_complete(struct ccwgroup_device *gdev) +{ + struct qeth_card *card = dev_get_drvdata(&gdev->dev); + if (card->discipline.ccwgdriver && + card->discipline.ccwgdriver->complete) + card->discipline.ccwgdriver->complete(gdev); +} + +static int qeth_core_freeze(struct ccwgroup_device *gdev) +{ + struct qeth_card *card = dev_get_drvdata(&gdev->dev); + if (card->discipline.ccwgdriver && + card->discipline.ccwgdriver->freeze) + return card->discipline.ccwgdriver->freeze(gdev); + return 0; +} + +static int qeth_core_thaw(struct ccwgroup_device *gdev) +{ + struct qeth_card *card = dev_get_drvdata(&gdev->dev); + if (card->discipline.ccwgdriver && + card->discipline.ccwgdriver->thaw) + return card->discipline.ccwgdriver->thaw(gdev); + return 0; +} + +static int qeth_core_restore(struct ccwgroup_device *gdev) +{ + struct qeth_card *card = dev_get_drvdata(&gdev->dev); + if (card->discipline.ccwgdriver && + card->discipline.ccwgdriver->restore) + return card->discipline.ccwgdriver->restore(gdev); + return 0; +} + static struct ccwgroup_driver qeth_core_ccwgroup_driver = { .owner = THIS_MODULE, .name = "qeth", @@ -4201,6 +4248,11 @@ static struct ccwgroup_driver qeth_core_ccwgroup_driver = { .set_online = qeth_core_set_online, .set_offline = qeth_core_set_offline, .shutdown = qeth_core_shutdown, + .prepare = qeth_core_prepare, + .complete = qeth_core_complete, + .freeze = qeth_core_freeze, + .thaw = qeth_core_thaw, + .restore = qeth_core_restore, }; static ssize_t diff --git a/drivers/s390/net/qeth_core_mpc.c b/drivers/s390/net/qeth_core_mpc.c index 06f4de1f0507..ec24901c802c 100644 --- a/drivers/s390/net/qeth_core_mpc.c +++ b/drivers/s390/net/qeth_core_mpc.c @@ -181,6 +181,8 @@ static struct ipa_rc_msg qeth_ipa_rc_msg[] = { {IPA_RC_L2_ADDR_TABLE_FULL, "Layer2 address table full"}, {IPA_RC_L2_DUP_LAYER3_MAC, "Duplicate with layer 3 MAC"}, {IPA_RC_L2_GMAC_NOT_FOUND, "GMAC not found"}, + {IPA_RC_L2_MAC_NOT_AUTH_BY_HYP, "L2 mac not authorized by hypervisor"}, + {IPA_RC_L2_MAC_NOT_AUTH_BY_ADP, "L2 mac not authorized by adapter"}, {IPA_RC_L2_MAC_NOT_FOUND, "L2 mac address not found"}, {IPA_RC_L2_INVALID_VLAN_ID, "L2 invalid vlan id"}, {IPA_RC_L2_DUP_VLAN_ID, "L2 duplicate vlan id"}, diff --git a/drivers/s390/net/qeth_core_mpc.h b/drivers/s390/net/qeth_core_mpc.h index 18548822e37c..eecb2ee62e85 100644 --- a/drivers/s390/net/qeth_core_mpc.h +++ b/drivers/s390/net/qeth_core_mpc.h @@ -168,6 +168,8 @@ enum qeth_ipa_return_codes { IPA_RC_L2_ADDR_TABLE_FULL = 0x2006, IPA_RC_L2_DUP_LAYER3_MAC = 0x200a, IPA_RC_L2_GMAC_NOT_FOUND = 0x200b, + IPA_RC_L2_MAC_NOT_AUTH_BY_HYP = 0x200c, + IPA_RC_L2_MAC_NOT_AUTH_BY_ADP = 0x200d, IPA_RC_L2_MAC_NOT_FOUND = 0x2010, IPA_RC_L2_INVALID_VLAN_ID = 0x2015, IPA_RC_L2_DUP_VLAN_ID = 0x2016, diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 172031baedc1..691cecd03b83 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -1,7 +1,7 @@ /* * drivers/s390/net/qeth_l2_main.c * - * Copyright IBM Corp. 2007 + * Copyright IBM Corp. 2007, 2009 * Author(s): Utz Bacher , * Frank Pavlic , * Thomas Spatzier , @@ -19,6 +19,7 @@ #include #include #include +#include #include "qeth_core.h" @@ -130,7 +131,7 @@ static int qeth_l2_send_setgroupmac_cb(struct qeth_card *card, cmd = (struct qeth_ipa_cmd *) data; mac = &cmd->data.setdelmac.mac[0]; /* MAC already registered, needed in couple/uncouple case */ - if (cmd->hdr.return_code == 0x2005) { + if (cmd->hdr.return_code == IPA_RC_L2_DUP_MAC) { QETH_DBF_MESSAGE(2, "Group MAC %pM already existing on %s \n", mac, QETH_CARD_IFNAME(card)); cmd->hdr.return_code = 0; @@ -502,6 +503,30 @@ static int qeth_l2_send_setmac_cb(struct qeth_card *card, if (cmd->hdr.return_code) { QETH_DBF_TEXT_(TRACE, 2, "L2er%x", cmd->hdr.return_code); card->info.mac_bits &= ~QETH_LAYER2_MAC_REGISTERED; + switch (cmd->hdr.return_code) { + case IPA_RC_L2_DUP_MAC: + case IPA_RC_L2_DUP_LAYER3_MAC: + dev_warn(&card->gdev->dev, + "MAC address " + "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x " + "already exists\n", + card->dev->dev_addr[0], card->dev->dev_addr[1], + card->dev->dev_addr[2], card->dev->dev_addr[3], + card->dev->dev_addr[4], card->dev->dev_addr[5]); + break; + case IPA_RC_L2_MAC_NOT_AUTH_BY_HYP: + case IPA_RC_L2_MAC_NOT_AUTH_BY_ADP: + dev_warn(&card->gdev->dev, + "MAC address " + "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x " + "is not authorized\n", + card->dev->dev_addr[0], card->dev->dev_addr[1], + card->dev->dev_addr[2], card->dev->dev_addr[3], + card->dev->dev_addr[4], card->dev->dev_addr[5]); + break; + default: + break; + } cmd->hdr.return_code = -EIO; } else { card->info.mac_bits |= QETH_LAYER2_MAC_REGISTERED; @@ -616,6 +641,7 @@ static void qeth_l2_set_multicast_list(struct net_device *dev) { struct qeth_card *card = dev->ml_priv; struct dev_addr_list *dm; + struct netdev_hw_addr *ha; if (card->info.type == QETH_CARD_TYPE_OSN) return ; @@ -629,8 +655,8 @@ static void qeth_l2_set_multicast_list(struct net_device *dev) for (dm = dev->mc_list; dm; dm = dm->next) qeth_l2_add_mc(card, dm->da_addr, 0); - for (dm = dev->uc_list; dm; dm = dm->next) - qeth_l2_add_mc(card, dm->da_addr, 1); + list_for_each_entry(ha, &dev->uc.list, list) + qeth_l2_add_mc(card, ha->addr, 1); spin_unlock_bh(&card->mclock); if (!qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE)) @@ -839,6 +865,7 @@ static void qeth_l2_remove_device(struct ccwgroup_device *cgdev) { struct qeth_card *card = dev_get_drvdata(&cgdev->dev); + qeth_set_allowed_threads(card, 0, 1); wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0); if (cgdev->state == CCWGROUP_ONLINE) { @@ -974,8 +1001,9 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode) dev_warn(&card->gdev->dev, "The LAN is offline\n"); card->lan_online = 0; + return 0; } - return rc; + goto out_remove; } else card->lan_online = 1; @@ -1113,12 +1141,62 @@ static void qeth_l2_shutdown(struct ccwgroup_device *gdev) qeth_clear_qdio_buffers(card); } +static int qeth_l2_pm_suspend(struct ccwgroup_device *gdev) +{ + struct qeth_card *card = dev_get_drvdata(&gdev->dev); + + if (card->dev) + netif_device_detach(card->dev); + qeth_set_allowed_threads(card, 0, 1); + wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0); + if (gdev->state == CCWGROUP_OFFLINE) + return 0; + if (card->state == CARD_STATE_UP) { + card->use_hard_stop = 1; + __qeth_l2_set_offline(card->gdev, 1); + } else + __qeth_l2_set_offline(card->gdev, 0); + return 0; +} + +static int qeth_l2_pm_resume(struct ccwgroup_device *gdev) +{ + struct qeth_card *card = dev_get_drvdata(&gdev->dev); + int rc = 0; + + if (gdev->state == CCWGROUP_OFFLINE) + goto out; + + if (card->state == CARD_STATE_RECOVER) { + rc = __qeth_l2_set_online(card->gdev, 1); + if (rc) { + if (card->dev) { + rtnl_lock(); + dev_close(card->dev); + rtnl_unlock(); + } + } + } else + rc = __qeth_l2_set_online(card->gdev, 0); +out: + qeth_set_allowed_threads(card, 0xffffffff, 0); + if (card->dev) + netif_device_attach(card->dev); + if (rc) + dev_warn(&card->gdev->dev, "The qeth device driver " + "failed to recover an error on the device\n"); + return rc; +} + struct ccwgroup_driver qeth_l2_ccwgroup_driver = { .probe = qeth_l2_probe_device, .remove = qeth_l2_remove_device, .set_online = qeth_l2_set_online, .set_offline = qeth_l2_set_offline, .shutdown = qeth_l2_shutdown, + .freeze = qeth_l2_pm_suspend, + .thaw = qeth_l2_pm_resume, + .restore = qeth_l2_pm_resume, }; EXPORT_SYMBOL_GPL(qeth_l2_ccwgroup_driver); diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 0ba3817cb6a7..54872406864e 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -1,7 +1,7 @@ /* * drivers/s390/net/qeth_l3_main.c * - * Copyright IBM Corp. 2007 + * Copyright IBM Corp. 2007, 2009 * Author(s): Utz Bacher , * Frank Pavlic , * Thomas Spatzier , @@ -1920,16 +1920,22 @@ static inline __u16 qeth_l3_rebuild_skb(struct qeth_card *card, hdr->hdr.l3.vlan_id : *((u16 *)&hdr->hdr.l3.dest_addr[12]); } - skb->ip_summed = card->options.checksum_type; - if (card->options.checksum_type == HW_CHECKSUMMING) { + switch (card->options.checksum_type) { + case SW_CHECKSUMMING: + skb->ip_summed = CHECKSUM_NONE; + break; + case NO_CHECKSUMMING: + skb->ip_summed = CHECKSUM_UNNECESSARY; + break; + case HW_CHECKSUMMING: if ((hdr->hdr.l3.ext_flags & - (QETH_HDR_EXT_CSUM_HDR_REQ | - QETH_HDR_EXT_CSUM_TRANSP_REQ)) == - (QETH_HDR_EXT_CSUM_HDR_REQ | - QETH_HDR_EXT_CSUM_TRANSP_REQ)) + (QETH_HDR_EXT_CSUM_HDR_REQ | + QETH_HDR_EXT_CSUM_TRANSP_REQ)) == + (QETH_HDR_EXT_CSUM_HDR_REQ | + QETH_HDR_EXT_CSUM_TRANSP_REQ)) skb->ip_summed = CHECKSUM_UNNECESSARY; else - skb->ip_summed = SW_CHECKSUMMING; + skb->ip_summed = CHECKSUM_NONE; } return vlan_id; @@ -2543,9 +2549,9 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, /* IPv4 */ hdr->hdr.l3.flags = qeth_l3_get_qeth_hdr_flags4(cast_type); memset(hdr->hdr.l3.dest_addr, 0, 12); - if ((skb->dst) && (skb->dst->neighbour)) { + if ((skb_dst(skb)) && (skb_dst(skb)->neighbour)) { *((u32 *) (&hdr->hdr.l3.dest_addr[12])) = - *((u32 *) skb->dst->neighbour->primary_key); + *((u32 *) skb_dst(skb)->neighbour->primary_key); } else { /* fill in destination address used in ip header */ *((u32 *) (&hdr->hdr.l3.dest_addr[12])) = @@ -2556,9 +2562,9 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, hdr->hdr.l3.flags = qeth_l3_get_qeth_hdr_flags6(cast_type); if (card->info.type == QETH_CARD_TYPE_IQD) hdr->hdr.l3.flags &= ~QETH_HDR_PASSTHRU; - if ((skb->dst) && (skb->dst->neighbour)) { + if ((skb_dst(skb)) && (skb_dst(skb)->neighbour)) { memcpy(hdr->hdr.l3.dest_addr, - skb->dst->neighbour->primary_key, 16); + skb_dst(skb)->neighbour->primary_key, 16); } else { /* fill in destination address used in ip header */ memcpy(hdr->hdr.l3.dest_addr, @@ -3006,6 +3012,7 @@ static int qeth_l3_setup_netdev(struct qeth_card *card) card->dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER; + card->dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; SET_NETDEV_DEV(card->dev, &card->gdev->dev); return register_netdev(card->dev); @@ -3070,6 +3077,7 @@ static void qeth_l3_remove_device(struct ccwgroup_device *cgdev) { struct qeth_card *card = dev_get_drvdata(&cgdev->dev); + qeth_set_allowed_threads(card, 0, 1); wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0); if (cgdev->state == CCWGROUP_ONLINE) { @@ -3141,8 +3149,9 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode) dev_warn(&card->gdev->dev, "The LAN is offline\n"); card->lan_online = 0; + return 0; } - return rc; + goto out_remove; } else card->lan_online = 1; qeth_set_large_send(card, card->options.large_send); @@ -3274,12 +3283,62 @@ static void qeth_l3_shutdown(struct ccwgroup_device *gdev) qeth_clear_qdio_buffers(card); } +static int qeth_l3_pm_suspend(struct ccwgroup_device *gdev) +{ + struct qeth_card *card = dev_get_drvdata(&gdev->dev); + + if (card->dev) + netif_device_detach(card->dev); + qeth_set_allowed_threads(card, 0, 1); + wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0); + if (gdev->state == CCWGROUP_OFFLINE) + return 0; + if (card->state == CARD_STATE_UP) { + card->use_hard_stop = 1; + __qeth_l3_set_offline(card->gdev, 1); + } else + __qeth_l3_set_offline(card->gdev, 0); + return 0; +} + +static int qeth_l3_pm_resume(struct ccwgroup_device *gdev) +{ + struct qeth_card *card = dev_get_drvdata(&gdev->dev); + int rc = 0; + + if (gdev->state == CCWGROUP_OFFLINE) + goto out; + + if (card->state == CARD_STATE_RECOVER) { + rc = __qeth_l3_set_online(card->gdev, 1); + if (rc) { + if (card->dev) { + rtnl_lock(); + dev_close(card->dev); + rtnl_unlock(); + } + } + } else + rc = __qeth_l3_set_online(card->gdev, 0); +out: + qeth_set_allowed_threads(card, 0xffffffff, 0); + if (card->dev) + netif_device_attach(card->dev); + if (rc) + dev_warn(&card->gdev->dev, "The qeth device driver " + "failed to recover an error on the device\n"); + return rc; +} + struct ccwgroup_driver qeth_l3_ccwgroup_driver = { .probe = qeth_l3_probe_device, .remove = qeth_l3_remove_device, .set_online = qeth_l3_set_online, .set_offline = qeth_l3_set_offline, .shutdown = qeth_l3_shutdown, + .freeze = qeth_l3_pm_suspend, + .thaw = qeth_l3_pm_resume, + .restore = qeth_l3_pm_resume, }; EXPORT_SYMBOL_GPL(qeth_l3_ccwgroup_driver); diff --git a/drivers/s390/net/smsgiucv.c b/drivers/s390/net/smsgiucv.c index 164e090c2625..e76a320d373b 100644 --- a/drivers/s390/net/smsgiucv.c +++ b/drivers/s390/net/smsgiucv.c @@ -1,7 +1,8 @@ /* * IUCV special message driver * - * Copyright 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Copyright IBM Corp. 2003, 2009 + * * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) * * This program is free software; you can redistribute it and/or modify @@ -40,6 +41,8 @@ MODULE_AUTHOR MODULE_DESCRIPTION ("Linux for S/390 IUCV special message driver"); static struct iucv_path *smsg_path; +/* dummy device used as trigger for PM functions */ +static struct device *smsg_dev; static DEFINE_SPINLOCK(smsg_list_lock); static LIST_HEAD(smsg_list); @@ -132,14 +135,51 @@ void smsg_unregister_callback(char *prefix, kfree(cb); } +static int smsg_pm_freeze(struct device *dev) +{ +#ifdef CONFIG_PM_DEBUG + printk(KERN_WARNING "smsg_pm_freeze\n"); +#endif + if (smsg_path) + iucv_path_sever(smsg_path, NULL); + return 0; +} + +static int smsg_pm_restore_thaw(struct device *dev) +{ + int rc; + +#ifdef CONFIG_PM_DEBUG + printk(KERN_WARNING "smsg_pm_restore_thaw\n"); +#endif + if (smsg_path) { + memset(smsg_path, 0, sizeof(*smsg_path)); + smsg_path->msglim = 255; + smsg_path->flags = 0; + rc = iucv_path_connect(smsg_path, &smsg_handler, "*MSG ", + NULL, NULL, NULL); + printk(KERN_ERR "iucv_path_connect returned with rc %i\n", rc); + } + return 0; +} + +static struct dev_pm_ops smsg_pm_ops = { + .freeze = smsg_pm_freeze, + .thaw = smsg_pm_restore_thaw, + .restore = smsg_pm_restore_thaw, +}; + static struct device_driver smsg_driver = { + .owner = THIS_MODULE, .name = "SMSGIUCV", .bus = &iucv_bus, + .pm = &smsg_pm_ops, }; static void __exit smsg_exit(void) { cpcmd("SET SMSG IUCV", NULL, 0, NULL); + device_unregister(smsg_dev); iucv_unregister(&smsg_handler, 1); driver_unregister(&smsg_driver); } @@ -166,12 +206,29 @@ static int __init smsg_init(void) rc = iucv_path_connect(smsg_path, &smsg_handler, "*MSG ", NULL, NULL, NULL); if (rc) - goto out_free; + goto out_free_path; + smsg_dev = kzalloc(sizeof(struct device), GFP_KERNEL); + if (!smsg_dev) { + rc = -ENOMEM; + goto out_free_path; + } + dev_set_name(smsg_dev, "smsg_iucv"); + smsg_dev->bus = &iucv_bus; + smsg_dev->parent = iucv_root; + smsg_dev->release = (void (*)(struct device *))kfree; + smsg_dev->driver = &smsg_driver; + rc = device_register(smsg_dev); + if (rc) + goto out_free_dev; + cpcmd("SET SMSG IUCV", NULL, 0, NULL); return 0; -out_free: +out_free_dev: + kfree(smsg_dev); +out_free_path: iucv_path_free(smsg_path); + smsg_path = NULL; out_register: iucv_unregister(&smsg_handler, 1); out_driver: diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 3ac27ee47396..2ccbd185a5fb 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -470,6 +470,12 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device) if (!adapter) return -ENOMEM; + adapter->gs = kzalloc(sizeof(struct zfcp_wka_ports), GFP_KERNEL); + if (!adapter->gs) { + kfree(adapter); + return -ENOMEM; + } + ccw_device->handler = NULL; adapter->ccw_device = ccw_device; atomic_set(&adapter->refcount, 0); @@ -523,8 +529,7 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device) goto sysfs_failed; atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status); - - zfcp_fc_nameserver_init(adapter); + zfcp_fc_wka_ports_init(adapter); if (!zfcp_adapter_scsi_register(adapter)) return 0; @@ -571,6 +576,7 @@ void zfcp_adapter_dequeue(struct zfcp_adapter *adapter) kfree(adapter->req_list); kfree(adapter->fc_stats); kfree(adapter->stats_reset_data); + kfree(adapter->gs); kfree(adapter); } diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c index 733fe3bf6285..d9da5c42ccbe 100644 --- a/drivers/s390/scsi/zfcp_ccw.c +++ b/drivers/s390/scsi/zfcp_ccw.c @@ -11,6 +11,54 @@ #include "zfcp_ext.h" +#define ZFCP_MODEL_PRIV 0x4 + +static int zfcp_ccw_suspend(struct ccw_device *cdev) + +{ + struct zfcp_adapter *adapter = dev_get_drvdata(&cdev->dev); + + down(&zfcp_data.config_sema); + + zfcp_erp_adapter_shutdown(adapter, 0, "ccsusp1", NULL); + zfcp_erp_wait(adapter); + + up(&zfcp_data.config_sema); + + return 0; +} + +static int zfcp_ccw_activate(struct ccw_device *cdev) + +{ + struct zfcp_adapter *adapter = dev_get_drvdata(&cdev->dev); + + zfcp_erp_modify_adapter_status(adapter, "ccresu1", NULL, + ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET); + zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, + "ccresu2", NULL); + zfcp_erp_wait(adapter); + flush_work(&adapter->scan_work); + + return 0; +} + +static struct ccw_device_id zfcp_ccw_device_id[] = { + { CCW_DEVICE_DEVTYPE(0x1731, 0x3, 0x1732, 0x3) }, + { CCW_DEVICE_DEVTYPE(0x1731, 0x3, 0x1732, ZFCP_MODEL_PRIV) }, + {}, +}; +MODULE_DEVICE_TABLE(ccw, zfcp_ccw_device_id); + +/** + * zfcp_ccw_priv_sch - check if subchannel is privileged + * @adapter: Adapter/Subchannel to check + */ +int zfcp_ccw_priv_sch(struct zfcp_adapter *adapter) +{ + return adapter->ccw_device->id.dev_model == ZFCP_MODEL_PRIV; +} + /** * zfcp_ccw_probe - probe function of zfcp driver * @ccw_device: pointer to belonging ccw device @@ -176,8 +224,8 @@ static int zfcp_ccw_notify(struct ccw_device *ccw_device, int event) "ccnoti4", NULL); break; case CIO_BOXED: - dev_warn(&adapter->ccw_device->dev, - "The ccw device did not respond in time.\n"); + dev_warn(&adapter->ccw_device->dev, "The FCP device " + "did not respond within the specified time\n"); zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti5", NULL); break; } @@ -199,14 +247,6 @@ static void zfcp_ccw_shutdown(struct ccw_device *cdev) up(&zfcp_data.config_sema); } -static struct ccw_device_id zfcp_ccw_device_id[] = { - { CCW_DEVICE_DEVTYPE(0x1731, 0x3, 0x1732, 0x3) }, - { CCW_DEVICE_DEVTYPE(0x1731, 0x3, 0x1732, 0x4) }, /* priv. */ - {}, -}; - -MODULE_DEVICE_TABLE(ccw, zfcp_ccw_device_id); - static struct ccw_driver zfcp_ccw_driver = { .owner = THIS_MODULE, .name = "zfcp", @@ -217,6 +257,9 @@ static struct ccw_driver zfcp_ccw_driver = { .set_offline = zfcp_ccw_set_offline, .notify = zfcp_ccw_notify, .shutdown = zfcp_ccw_shutdown, + .freeze = zfcp_ccw_suspend, + .thaw = zfcp_ccw_activate, + .restore = zfcp_ccw_activate, }; /** diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index 0a1a5dd8d018..b99b87ce5a39 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -163,7 +163,7 @@ void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *fsf_req) } response->fsf_command = fsf_req->fsf_command; - response->fsf_reqid = (unsigned long)fsf_req; + response->fsf_reqid = fsf_req->req_id; response->fsf_seqno = fsf_req->seq_no; response->fsf_issued = fsf_req->issued; response->fsf_prot_status = qtcb->prefix.prot_status; @@ -737,7 +737,7 @@ void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *fsf_req) spin_lock_irqsave(&adapter->san_dbf_lock, flags); memset(r, 0, sizeof(*r)); strncpy(r->tag, "octc", ZFCP_DBF_TAG_SIZE); - r->fsf_reqid = (unsigned long)fsf_req; + r->fsf_reqid = fsf_req->req_id; r->fsf_seqno = fsf_req->seq_no; r->s_id = fc_host_port_id(adapter->scsi_host); r->d_id = wka_port->d_id; @@ -773,7 +773,7 @@ void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *fsf_req) spin_lock_irqsave(&adapter->san_dbf_lock, flags); memset(r, 0, sizeof(*r)); strncpy(r->tag, "rctc", ZFCP_DBF_TAG_SIZE); - r->fsf_reqid = (unsigned long)fsf_req; + r->fsf_reqid = fsf_req->req_id; r->fsf_seqno = fsf_req->seq_no; r->s_id = wka_port->d_id; r->d_id = fc_host_port_id(adapter->scsi_host); @@ -803,7 +803,7 @@ static void zfcp_san_dbf_event_els(const char *tag, int level, spin_lock_irqsave(&adapter->san_dbf_lock, flags); memset(rec, 0, sizeof(*rec)); strncpy(rec->tag, tag, ZFCP_DBF_TAG_SIZE); - rec->fsf_reqid = (unsigned long)fsf_req; + rec->fsf_reqid = fsf_req->req_id; rec->fsf_seqno = fsf_req->seq_no; rec->s_id = s_id; rec->d_id = d_id; @@ -965,7 +965,7 @@ static void zfcp_scsi_dbf_event(const char *tag, const char *tag2, int level, ZFCP_DBF_SCSI_FCP_SNS_INFO); } - rec->fsf_reqid = (unsigned long)fsf_req; + rec->fsf_reqid = fsf_req->req_id; rec->fsf_seqno = fsf_req->seq_no; rec->fsf_issued = fsf_req->issued; } diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 4c362a9069f0..49d0532bca1c 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include #include #include @@ -29,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -47,13 +50,6 @@ /********************* CIO/QDIO SPECIFIC DEFINES *****************************/ -/* Adapter Identification Parameters */ -#define ZFCP_CONTROL_UNIT_TYPE 0x1731 -#define ZFCP_CONTROL_UNIT_MODEL 0x03 -#define ZFCP_DEVICE_TYPE 0x1732 -#define ZFCP_DEVICE_MODEL 0x03 -#define ZFCP_DEVICE_MODEL_PRIV 0x04 - /* DMQ bug workaround: don't use last SBALE */ #define ZFCP_MAX_SBALES_PER_SBAL (QDIO_MAX_ELEMENTS_PER_BUFFER - 1) @@ -235,11 +231,6 @@ struct zfcp_ls_adisc { /* FC-PH/FC-GS well-known address identifiers for generic services */ #define ZFCP_DID_WKA 0xFFFFF0 -#define ZFCP_DID_MANAGEMENT_SERVICE 0xFFFFFA -#define ZFCP_DID_TIME_SERVICE 0xFFFFFB -#define ZFCP_DID_DIRECTORY_SERVICE 0xFFFFFC -#define ZFCP_DID_ALIAS_SERVICE 0xFFFFF8 -#define ZFCP_DID_KEY_DISTRIBUTION_SERVICE 0xFFFFF7 /* remote port status */ #define ZFCP_STATUS_PORT_PHYS_OPEN 0x00000001 @@ -383,6 +374,14 @@ struct zfcp_wka_port { struct delayed_work work; }; +struct zfcp_wka_ports { + struct zfcp_wka_port ms; /* management service */ + struct zfcp_wka_port ts; /* time service */ + struct zfcp_wka_port ds; /* directory service */ + struct zfcp_wka_port as; /* alias service */ + struct zfcp_wka_port ks; /* key distribution service */ +}; + struct zfcp_qdio_queue { struct qdio_buffer *sbal[QDIO_MAX_BUFFERS_PER_Q]; u8 first; /* index of next free bfr in queue */ @@ -468,7 +467,7 @@ struct zfcp_adapter { actions */ u32 erp_low_mem_count; /* nr of erp actions waiting for memory */ - struct zfcp_wka_port nsp; /* adapter's nameserver */ + struct zfcp_wka_ports *gs; /* generic services */ debug_info_t *rec_dbf; debug_info_t *hba_dbf; debug_info_t *san_dbf; /* debug feature areas */ diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index fdc9b4352a64..8030e25152fb 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -719,7 +719,7 @@ static void zfcp_erp_adapter_strategy_close(struct zfcp_erp_action *act) zfcp_qdio_close(adapter); zfcp_fsf_req_dismiss_all(adapter); adapter->fsf_req_seq_no = 0; - zfcp_fc_wka_port_force_offline(&adapter->nsp); + zfcp_fc_wka_port_force_offline(&adapter->gs->ds); /* all ports and units are closed */ zfcp_erp_modify_adapter_status(adapter, "erascl1", NULL, ZFCP_STATUS_COMMON_OPEN, ZFCP_CLEAR); @@ -880,6 +880,7 @@ static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act) zfcp_port_put(port); return ZFCP_ERP_CONTINUES; } + /* fall through */ case ZFCP_ERP_STEP_NAMESERVER_LOOKUP: if (!port->d_id) return ZFCP_ERP_FAILED; @@ -894,8 +895,13 @@ static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act) act->step = ZFCP_ERP_STEP_PORT_CLOSING; return ZFCP_ERP_CONTINUES; } - /* fall through otherwise */ } + if (port->d_id && !(p_status & ZFCP_STATUS_COMMON_NOESC)) { + port->d_id = 0; + _zfcp_erp_port_reopen(port, 0, "erpsoc1", NULL); + return ZFCP_ERP_EXIT; + } + /* fall through otherwise */ } return ZFCP_ERP_FAILED; } diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 2e31b536548c..3044c6010306 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -27,6 +27,7 @@ extern int zfcp_sg_setup_table(struct scatterlist *, int); /* zfcp_ccw.c */ extern int zfcp_ccw_register(void); +extern int zfcp_ccw_priv_sch(struct zfcp_adapter *); extern struct zfcp_adapter *zfcp_get_adapter_by_busid(char *); /* zfcp_cfdc.c */ @@ -105,8 +106,12 @@ extern int zfcp_fc_ns_gid_pn(struct zfcp_erp_action *); extern void zfcp_fc_plogi_evaluate(struct zfcp_port *, struct fsf_plogi *); extern void zfcp_test_link(struct zfcp_port *); extern void zfcp_fc_link_test_work(struct work_struct *); -extern void zfcp_fc_nameserver_init(struct zfcp_adapter *); extern void zfcp_fc_wka_port_force_offline(struct zfcp_wka_port *); +extern void zfcp_fc_wka_ports_init(struct zfcp_adapter *); +extern int zfcp_fc_execute_els_fc_job(struct fc_bsg_job *); +extern int zfcp_fc_execute_ct_fc_job(struct fc_bsg_job *); +extern void zfcp_fc_wka_port_force_offline(struct zfcp_wka_port *); + /* zfcp_fsf.c */ extern int zfcp_fsf_open_port(struct zfcp_erp_action *); diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index 19ae0842047c..2f0705d76b72 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c @@ -116,18 +116,17 @@ static void zfcp_wka_port_put(struct zfcp_wka_port *wka_port) { if (atomic_dec_return(&wka_port->refcount) != 0) return; - /* wait 10 miliseconds, other reqs might pop in */ + /* wait 10 milliseconds, other reqs might pop in */ schedule_delayed_work(&wka_port->work, HZ / 100); } -void zfcp_fc_nameserver_init(struct zfcp_adapter *adapter) +static void zfcp_fc_wka_port_init(struct zfcp_wka_port *wka_port, u32 d_id, + struct zfcp_adapter *adapter) { - struct zfcp_wka_port *wka_port = &adapter->nsp; - init_waitqueue_head(&wka_port->completion_wq); wka_port->adapter = adapter; - wka_port->d_id = ZFCP_DID_DIRECTORY_SERVICE; + wka_port->d_id = d_id; wka_port->status = ZFCP_WKA_PORT_OFFLINE; atomic_set(&wka_port->refcount, 0); @@ -143,6 +142,17 @@ void zfcp_fc_wka_port_force_offline(struct zfcp_wka_port *wka) mutex_unlock(&wka->mutex); } +void zfcp_fc_wka_ports_init(struct zfcp_adapter *adapter) +{ + struct zfcp_wka_ports *gs = adapter->gs; + + zfcp_fc_wka_port_init(&gs->ms, FC_FID_MGMT_SERV, adapter); + zfcp_fc_wka_port_init(&gs->ts, FC_FID_TIME_SERV, adapter); + zfcp_fc_wka_port_init(&gs->ds, FC_FID_DIR_SERV, adapter); + zfcp_fc_wka_port_init(&gs->as, FC_FID_ALIASES, adapter); + zfcp_fc_wka_port_init(&gs->ks, FC_FID_SEC_KEY, adapter); +} + static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range, struct fcp_rscn_element *elem) { @@ -150,9 +160,14 @@ static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range, struct zfcp_port *port; read_lock_irqsave(&zfcp_data.config_lock, flags); - list_for_each_entry(port, &fsf_req->adapter->port_list_head, list) + list_for_each_entry(port, &fsf_req->adapter->port_list_head, list) { if ((port->d_id & range) == (elem->nport_did & range)) zfcp_test_link(port); + if (!port->d_id) + zfcp_erp_port_reopen(port, + ZFCP_STATUS_COMMON_ERP_FAILED, + "fcrscn1", NULL); + } read_unlock_irqrestore(&zfcp_data.config_lock, flags); } @@ -277,7 +292,7 @@ int static zfcp_fc_ns_gid_pn_request(struct zfcp_erp_action *erp_action, /* setup parameters for send generic command */ gid_pn->port = erp_action->port; - gid_pn->ct.wka_port = &adapter->nsp; + gid_pn->ct.wka_port = &adapter->gs->ds; gid_pn->ct.handler = zfcp_fc_ns_handler; gid_pn->ct.handler_data = (unsigned long) &compl_rec; gid_pn->ct.timeout = ZFCP_NS_GID_PN_TIMEOUT; @@ -324,13 +339,13 @@ int zfcp_fc_ns_gid_pn(struct zfcp_erp_action *erp_action) memset(gid_pn, 0, sizeof(*gid_pn)); - ret = zfcp_wka_port_get(&adapter->nsp); + ret = zfcp_wka_port_get(&adapter->gs->ds); if (ret) goto out; ret = zfcp_fc_ns_gid_pn_request(erp_action, gid_pn); - zfcp_wka_port_put(&adapter->nsp); + zfcp_wka_port_put(&adapter->gs->ds); out: mempool_free(gid_pn, adapter->pool.data_gid_pn); return ret; @@ -520,7 +535,7 @@ static int zfcp_scan_issue_gpn_ft(struct zfcp_gpn_ft *gpn_ft, req->fc4_type = ZFCP_CT_SCSI_FCP; /* prepare zfcp_send_ct */ - ct->wka_port = &adapter->nsp; + ct->wka_port = &adapter->gs->ds; ct->handler = zfcp_fc_ns_handler; ct->handler_data = (unsigned long)&compl_rec; ct->timeout = 10; @@ -639,7 +654,7 @@ int zfcp_scan_ports(struct zfcp_adapter *adapter) fc_host_port_type(adapter->scsi_host) != FC_PORTTYPE_NPIV) return 0; - ret = zfcp_wka_port_get(&adapter->nsp); + ret = zfcp_wka_port_get(&adapter->gs->ds); if (ret) return ret; @@ -661,7 +676,7 @@ int zfcp_scan_ports(struct zfcp_adapter *adapter) } zfcp_free_sg_env(gpn_ft, buf_num); out: - zfcp_wka_port_put(&adapter->nsp); + zfcp_wka_port_put(&adapter->gs->ds); return ret; } @@ -670,3 +685,158 @@ void _zfcp_scan_ports_later(struct work_struct *work) { zfcp_scan_ports(container_of(work, struct zfcp_adapter, scan_work)); } + +struct zfcp_els_fc_job { + struct zfcp_send_els els; + struct fc_bsg_job *job; +}; + +static void zfcp_fc_generic_els_handler(unsigned long data) +{ + struct zfcp_els_fc_job *els_fc_job = (struct zfcp_els_fc_job *) data; + struct fc_bsg_job *job = els_fc_job->job; + struct fc_bsg_reply *reply = job->reply; + + if (els_fc_job->els.status) { + /* request rejected or timed out */ + reply->reply_data.ctels_reply.status = FC_CTELS_STATUS_REJECT; + goto out; + } + + reply->reply_data.ctels_reply.status = FC_CTELS_STATUS_OK; + reply->reply_payload_rcv_len = job->reply_payload.payload_len; + +out: + job->state_flags = FC_RQST_STATE_DONE; + job->job_done(job); + kfree(els_fc_job); +} + +int zfcp_fc_execute_els_fc_job(struct fc_bsg_job *job) +{ + struct zfcp_els_fc_job *els_fc_job; + struct fc_rport *rport = job->rport; + struct Scsi_Host *shost; + struct zfcp_adapter *adapter; + struct zfcp_port *port; + u8 *port_did; + + shost = rport ? rport_to_shost(rport) : job->shost; + adapter = (struct zfcp_adapter *)shost->hostdata[0]; + + if (!(atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_OPEN)) + return -EINVAL; + + els_fc_job = kzalloc(sizeof(struct zfcp_els_fc_job), GFP_KERNEL); + if (!els_fc_job) + return -ENOMEM; + + els_fc_job->els.adapter = adapter; + if (rport) { + read_lock_irq(&zfcp_data.config_lock); + port = rport->dd_data; + if (port) + els_fc_job->els.d_id = port->d_id; + read_unlock_irq(&zfcp_data.config_lock); + if (!port) { + kfree(els_fc_job); + return -EINVAL; + } + } else { + port_did = job->request->rqst_data.h_els.port_id; + els_fc_job->els.d_id = (port_did[0] << 16) + + (port_did[1] << 8) + port_did[2]; + } + + els_fc_job->els.req = job->request_payload.sg_list; + els_fc_job->els.resp = job->reply_payload.sg_list; + els_fc_job->els.handler = zfcp_fc_generic_els_handler; + els_fc_job->els.handler_data = (unsigned long) els_fc_job; + els_fc_job->job = job; + + return zfcp_fsf_send_els(&els_fc_job->els); +} + +struct zfcp_ct_fc_job { + struct zfcp_send_ct ct; + struct fc_bsg_job *job; +}; + +static void zfcp_fc_generic_ct_handler(unsigned long data) +{ + struct zfcp_ct_fc_job *ct_fc_job = (struct zfcp_ct_fc_job *) data; + struct fc_bsg_job *job = ct_fc_job->job; + + job->reply->reply_data.ctels_reply.status = ct_fc_job->ct.status ? + FC_CTELS_STATUS_REJECT : FC_CTELS_STATUS_OK; + job->reply->reply_payload_rcv_len = job->reply_payload.payload_len; + job->state_flags = FC_RQST_STATE_DONE; + job->job_done(job); + + zfcp_wka_port_put(ct_fc_job->ct.wka_port); + + kfree(ct_fc_job); +} + +int zfcp_fc_execute_ct_fc_job(struct fc_bsg_job *job) +{ + int ret; + u8 gs_type; + struct fc_rport *rport = job->rport; + struct Scsi_Host *shost; + struct zfcp_adapter *adapter; + struct zfcp_ct_fc_job *ct_fc_job; + u32 preamble_word1; + + shost = rport ? rport_to_shost(rport) : job->shost; + + adapter = (struct zfcp_adapter *)shost->hostdata[0]; + if (!(atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_OPEN)) + return -EINVAL; + + ct_fc_job = kzalloc(sizeof(struct zfcp_ct_fc_job), GFP_KERNEL); + if (!ct_fc_job) + return -ENOMEM; + + preamble_word1 = job->request->rqst_data.r_ct.preamble_word1; + gs_type = (preamble_word1 & 0xff000000) >> 24; + + switch (gs_type) { + case FC_FST_ALIAS: + ct_fc_job->ct.wka_port = &adapter->gs->as; + break; + case FC_FST_MGMT: + ct_fc_job->ct.wka_port = &adapter->gs->ms; + break; + case FC_FST_TIME: + ct_fc_job->ct.wka_port = &adapter->gs->ts; + break; + case FC_FST_DIR: + ct_fc_job->ct.wka_port = &adapter->gs->ds; + break; + default: + kfree(ct_fc_job); + return -EINVAL; /* no such service */ + } + + ret = zfcp_wka_port_get(ct_fc_job->ct.wka_port); + if (ret) { + kfree(ct_fc_job); + return ret; + } + + ct_fc_job->ct.req = job->request_payload.sg_list; + ct_fc_job->ct.resp = job->reply_payload.sg_list; + ct_fc_job->ct.timeout = ZFCP_FSF_REQUEST_TIMEOUT; + ct_fc_job->ct.handler = zfcp_fc_generic_ct_handler; + ct_fc_job->ct.handler_data = (unsigned long) ct_fc_job; + ct_fc_job->ct.completion = NULL; + ct_fc_job->job = job; + + ret = zfcp_fsf_send_ct(&ct_fc_job->ct, NULL, NULL); + if (ret) { + kfree(ct_fc_job); + zfcp_wka_port_put(ct_fc_job->ct.wka_port); + } + return ret; +} diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 74dee32afba8..c57658f3d34f 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -526,6 +526,7 @@ static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req) break; case FSF_TOPO_AL: fc_host_port_type(shost) = FC_PORTTYPE_NLPORT; + /* fall through */ default: dev_err(&adapter->ccw_device->dev, "Unknown or unsupported arbitrated loop " @@ -897,6 +898,7 @@ static void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req) switch (fsq->word[0]) { case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: zfcp_test_link(unit->port); + /* fall through */ case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; @@ -993,6 +995,7 @@ static void zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *req) break; case FSF_PORT_HANDLE_NOT_VALID: zfcp_erp_adapter_reopen(adapter, 0, "fsscth1", req); + /* fall through */ case FSF_GENERIC_COMMAND_REJECTED: case FSF_PAYLOAD_SIZE_MISMATCH: case FSF_REQUEST_SIZE_TOO_LARGE: @@ -1143,7 +1146,8 @@ static void zfcp_fsf_send_els_handler(struct zfcp_fsf_req *req) case FSF_RESPONSE_SIZE_TOO_LARGE: break; case FSF_ACCESS_DENIED: - zfcp_fsf_access_denied_port(req, port); + if (port) + zfcp_fsf_access_denied_port(req, port); break; case FSF_SBAL_MISMATCH: /* should never occure, avoided in zfcp_fsf_send_els */ @@ -1399,7 +1403,7 @@ static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req) struct fsf_plogi *plogi; if (req->status & ZFCP_STATUS_FSFREQ_ERROR) - return; + goto out; switch (header->fsf_status) { case FSF_PORT_ALREADY_OPEN: @@ -1461,6 +1465,9 @@ static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req) req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; } + +out: + zfcp_port_put(port); } /** @@ -1473,6 +1480,7 @@ int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action) struct qdio_buffer_element *sbale; struct zfcp_adapter *adapter = erp_action->adapter; struct zfcp_fsf_req *req; + struct zfcp_port *port = erp_action->port; int retval = -EIO; spin_lock_bh(&adapter->req_q_lock); @@ -1493,16 +1501,18 @@ int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action) sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; req->handler = zfcp_fsf_open_port_handler; - req->qtcb->bottom.support.d_id = erp_action->port->d_id; - req->data = erp_action->port; + req->qtcb->bottom.support.d_id = port->d_id; + req->data = port; req->erp_action = erp_action; erp_action->fsf_req = req; + zfcp_port_get(port); zfcp_fsf_start_erp_timer(req); retval = zfcp_fsf_req_send(req); if (retval) { zfcp_fsf_req_free(req); erp_action->fsf_req = NULL; + zfcp_port_put(port); } out: spin_unlock_bh(&adapter->req_q_lock); @@ -1590,8 +1600,10 @@ static void zfcp_fsf_open_wka_port_handler(struct zfcp_fsf_req *req) case FSF_MAXIMUM_NUMBER_OF_PORTS_EXCEEDED: dev_warn(&req->adapter->ccw_device->dev, "Opening WKA port 0x%x failed\n", wka_port->d_id); + /* fall through */ case FSF_ADAPTER_STATUS_AVAILABLE: req->status |= ZFCP_STATUS_FSFREQ_ERROR; + /* fall through */ case FSF_ACCESS_DENIED: wka_port->status = ZFCP_WKA_PORT_OFFLINE; break; @@ -1876,7 +1888,7 @@ static void zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *req) if (!(adapter->connection_features & FSF_FEATURE_NPIV_MODE) && (adapter->adapter_features & FSF_FEATURE_LUN_SHARING) && - (adapter->ccw_device->id.dev_model != ZFCP_DEVICE_MODEL_PRIV)) { + !zfcp_ccw_priv_sch(adapter)) { exclusive = (bottom->lun_access_info & FSF_UNIT_ACCESS_EXCLUSIVE); readwrite = (bottom->lun_access_info & @@ -2314,7 +2326,7 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit, { struct zfcp_fsf_req *req; struct fcp_cmnd_iu *fcp_cmnd_iu; - unsigned int sbtype; + unsigned int sbtype = SBAL_FLAGS0_TYPE_READ; int real_bytes, retval = -EIO; struct zfcp_adapter *adapter = unit->port->adapter; @@ -2356,11 +2368,9 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit, switch (scsi_cmnd->sc_data_direction) { case DMA_NONE: req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND; - sbtype = SBAL_FLAGS0_TYPE_READ; break; case DMA_FROM_DEVICE: req->qtcb->bottom.io.data_direction = FSF_DATADIR_READ; - sbtype = SBAL_FLAGS0_TYPE_READ; fcp_cmnd_iu->rddata = 1; break; case DMA_TO_DEVICE: @@ -2369,8 +2379,6 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit, fcp_cmnd_iu->wddata = 1; break; case DMA_BIDIRECTIONAL: - default: - retval = -EIO; goto failed_scsi_cmnd; } @@ -2394,9 +2402,7 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit, scsi_sglist(scsi_cmnd), FSF_MAX_SBALS_PER_REQ); if (unlikely(real_bytes < 0)) { - if (req->sbal_number < FSF_MAX_SBALS_PER_REQ) - retval = -EIO; - else { + if (req->sbal_number >= FSF_MAX_SBALS_PER_REQ) { dev_err(&adapter->ccw_device->dev, "Oversize data package, unit 0x%016Lx " "on port 0x%016Lx closed\n", diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index e8fbeaeb5fbf..967ede73f4c5 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -12,6 +12,10 @@ #include "zfcp_ext.h" #include +static unsigned int default_depth = 32; +module_param_named(queue_depth, default_depth, uint, 0600); +MODULE_PARM_DESC(queue_depth, "Default queue depth for new SCSI devices"); + /* Find start of Sense Information in FCP response unit*/ char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *fcp_rsp_iu) { @@ -24,6 +28,12 @@ char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *fcp_rsp_iu) return fcp_sns_info_ptr; } +static int zfcp_scsi_change_queue_depth(struct scsi_device *sdev, int depth) +{ + scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth); + return sdev->queue_depth; +} + static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt) { struct zfcp_unit *unit = (struct zfcp_unit *) sdpnt->hostdata; @@ -34,7 +44,7 @@ static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt) static int zfcp_scsi_slave_configure(struct scsi_device *sdp) { if (sdp->tagged_supported) - scsi_adjust_queue_depth(sdp, MSG_SIMPLE_TAG, 32); + scsi_adjust_queue_depth(sdp, MSG_SIMPLE_TAG, default_depth); else scsi_adjust_queue_depth(sdp, 0, 1); return 0; @@ -613,6 +623,20 @@ void zfcp_scsi_scan(struct work_struct *work) zfcp_unit_put(unit); } +static int zfcp_execute_fc_job(struct fc_bsg_job *job) +{ + switch (job->request->msgcode) { + case FC_BSG_RPT_ELS: + case FC_BSG_HST_ELS_NOLOGIN: + return zfcp_fc_execute_els_fc_job(job); + case FC_BSG_RPT_CT: + case FC_BSG_HST_CT: + return zfcp_fc_execute_ct_fc_job(job); + default: + return -EINVAL; + } +} + struct fc_function_template zfcp_transport_functions = { .show_starget_port_id = 1, .show_starget_port_name = 1, @@ -634,6 +658,7 @@ struct fc_function_template zfcp_transport_functions = { .dev_loss_tmo_callbk = zfcp_scsi_dev_loss_tmo_callbk, .terminate_rport_io = zfcp_scsi_terminate_rport_io, .show_host_port_state = 1, + .bsg_request = zfcp_execute_fc_job, /* no functions registered for following dynamic attributes but directly set by LLDD */ .show_host_port_type = 1, @@ -647,6 +672,7 @@ struct zfcp_data zfcp_data = { .name = "zfcp", .module = THIS_MODULE, .proc_name = "zfcp", + .change_queue_depth = zfcp_scsi_change_queue_depth, .slave_alloc = zfcp_scsi_slave_alloc, .slave_configure = zfcp_scsi_slave_configure, .slave_destroy = zfcp_scsi_slave_destroy, diff --git a/drivers/sbus/char/jsflash.c b/drivers/sbus/char/jsflash.c index a85ad05e8548..6d4651684688 100644 --- a/drivers/sbus/char/jsflash.c +++ b/drivers/sbus/char/jsflash.c @@ -186,31 +186,31 @@ static void jsfd_do_request(struct request_queue *q) { struct request *req; - while ((req = elv_next_request(q)) != NULL) { + req = blk_fetch_request(q); + while (req) { struct jsfd_part *jdp = req->rq_disk->private_data; - unsigned long offset = req->sector << 9; - size_t len = req->current_nr_sectors << 9; + unsigned long offset = blk_rq_pos(req) << 9; + size_t len = blk_rq_cur_bytes(req); + int err = -EIO; - if ((offset + len) > jdp->dsize) { - end_request(req, 0); - continue; - } + if ((offset + len) > jdp->dsize) + goto end; if (rq_data_dir(req) != READ) { printk(KERN_ERR "jsfd: write\n"); - end_request(req, 0); - continue; + goto end; } if ((jdp->dbase & 0xff000000) != 0x20000000) { printk(KERN_ERR "jsfd: bad base %x\n", (int)jdp->dbase); - end_request(req, 0); - continue; + goto end; } jsfd_read(req->buffer, jdp->dbase + offset, len); - - end_request(req, 1); + err = 0; + end: + if (!__blk_end_request_cur(req, err)) + req = blk_fetch_request(q); } } diff --git a/drivers/sbus/char/openprom.c b/drivers/sbus/char/openprom.c index 124f660a0383..75ac19b1192f 100644 --- a/drivers/sbus/char/openprom.c +++ b/drivers/sbus/char/openprom.c @@ -303,7 +303,7 @@ static int openprom_sunos_ioctl(struct inode * inode, struct file * file, struct device_node *dp) { DATA *data = file->private_data; - struct openpromio *opp; + struct openpromio *opp = NULL; int bufsize, error = 0; static int cnt; void __user *argp = (void __user *)arg; diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index fb2740789b68..9c23122f755f 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -191,20 +191,19 @@ config SCSI_ENCLOSURE it has an enclosure device. Selecting this option will just allow certain enclosure conditions to be reported and is not required. -comment "Some SCSI devices (e.g. CD jukebox) support multiple LUNs" - depends on SCSI - config SCSI_MULTI_LUN bool "Probe all LUNs on each SCSI device" depends on SCSI help - If you have a SCSI device that supports more than one LUN (Logical - Unit Number), e.g. a CD jukebox, and only one LUN is detected, you - can say Y here to force the SCSI driver to probe for multiple LUNs. - A SCSI device with multiple LUNs acts logically like multiple SCSI - devices. The vast majority of SCSI devices have only one LUN, and - so most people can say N here. The max_luns boot/module parameter - allows to override this setting. + Some devices support more than one LUN (Logical Unit Number) in order + to allow access to several media, e.g. CD jukebox, USB card reader, + mobile phone in mass storage mode. This option forces the kernel to + probe for all LUNs by default. This setting can be overriden by + max_luns boot/module parameter. Note that this option does not affect + devices conforming to SCSI-3 or higher as they can explicitely report + their number of LUNs. It is safe to say Y here unless you have one of + those rare devices which reacts in an unexpected way when probed for + multiple LUNs. config SCSI_CONSTANTS bool "Verbose SCSI error reporting (kernel size +=12K)" @@ -259,10 +258,21 @@ config SCSI_SCAN_ASYNC or async on the kernel's command line. config SCSI_WAIT_SCAN - tristate + tristate # No prompt here, this is an invisible symbol. default m depends on SCSI depends on MODULES +# scsi_wait_scan is a loadable module which waits until all the async scans are +# complete. The idea is to use it in initrd/ initramfs scripts. You modprobe +# it after all the modprobes of the root SCSI drivers and it will wait until +# they have all finished scanning their buses before allowing the boot to +# proceed. (This method is not applicable if targets boot independently in +# parallel with the initiator, or with transports with non-deterministic target +# discovery schemes, or if a transport driver does not support scsi_wait_scan.) +# +# This symbol is not exposed as a prompt because little is to be gained by +# disabling it, whereas people who accidentally switch it off may wonder why +# their mkinitrd gets into trouble. menu "SCSI Transports" depends on SCSI @@ -355,6 +365,7 @@ config ISCSI_TCP http://open-iscsi.org source "drivers/scsi/cxgb3i/Kconfig" +source "drivers/scsi/bnx2i/Kconfig" config SGIWD93_SCSI tristate "SGI WD93C93 SCSI Driver" @@ -508,6 +519,7 @@ config SCSI_AIC7XXX_OLD source "drivers/scsi/aic7xxx/Kconfig.aic79xx" source "drivers/scsi/aic94xx/Kconfig" +source "drivers/scsi/mvsas/Kconfig" config SCSI_DPT_I2O tristate "Adaptec I2O RAID support " @@ -1050,16 +1062,6 @@ config SCSI_IZIP_SLOW_CTR Generally, saying N is fine. -config SCSI_MVSAS - tristate "Marvell 88SE6440 SAS/SATA support" - depends on PCI && SCSI - select SCSI_SAS_LIBSAS - help - This driver supports Marvell SAS/SATA PCI devices. - - To compiler this driver as a module, choose M here: the module - will be called mvsas. - config SCSI_NCR53C406A tristate "NCR53c406a SCSI support" depends on ISA && SCSI diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index a5049cfb40ed..25429ea63d0a 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -126,9 +126,10 @@ obj-$(CONFIG_SCSI_IBMVSCSIS) += ibmvscsi/ obj-$(CONFIG_SCSI_IBMVFC) += ibmvscsi/ obj-$(CONFIG_SCSI_HPTIOP) += hptiop.o obj-$(CONFIG_SCSI_STEX) += stex.o -obj-$(CONFIG_SCSI_MVSAS) += mvsas.o +obj-$(CONFIG_SCSI_MVSAS) += mvsas/ obj-$(CONFIG_PS3_ROM) += ps3rom.o obj-$(CONFIG_SCSI_CXGB3_ISCSI) += libiscsi.o libiscsi_tcp.o cxgb3i/ +obj-$(CONFIG_SCSI_BNX2_ISCSI) += libiscsi.o bnx2i/ obj-$(CONFIG_ARM) += arm/ diff --git a/drivers/scsi/NCR_D700.c b/drivers/scsi/NCR_D700.c index c889d8458684..1cdf09a4779a 100644 --- a/drivers/scsi/NCR_D700.c +++ b/drivers/scsi/NCR_D700.c @@ -224,7 +224,7 @@ NCR_D700_probe_one(struct NCR_D700_private *p, int siop, int irq, return ret; } -static int +static irqreturn_t NCR_D700_intr(int irq, void *data) { struct NCR_D700_private *p = (struct NCR_D700_private *)data; diff --git a/drivers/scsi/aha1740.c b/drivers/scsi/aha1740.c index ed0e3e55652a..538135783aab 100644 --- a/drivers/scsi/aha1740.c +++ b/drivers/scsi/aha1740.c @@ -646,7 +646,7 @@ static int aha1740_probe (struct device *dev) static __devexit int aha1740_remove (struct device *dev) { - struct Scsi_Host *shpnt = dev->driver_data; + struct Scsi_Host *shpnt = dev_get_drvdata(dev); struct aha1740_hostdata *host = HOSTDATA (shpnt); scsi_remove_host(shpnt); diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index 0f829b3b8ab7..75b23317bd26 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -627,19 +627,15 @@ ahd_linux_target_alloc(struct scsi_target *starget) starget->id, &tstate); if ((flags & CFPACKETIZED) == 0) { - /* Do not negotiate packetized transfers */ - spi_rd_strm(starget) = 0; - spi_pcomp_en(starget) = 0; - spi_rti(starget) = 0; - spi_wr_flow(starget) = 0; - spi_hold_mcs(starget) = 0; + /* don't negotiate packetized (IU) transfers */ + spi_max_iu(starget) = 0; } else { if ((ahd->features & AHD_RTI) == 0) spi_rti(starget) = 0; } if ((flags & CFQAS) == 0) - spi_qas(starget) = 0; + spi_max_qas(starget) = 0; /* Transinfo values have been set to BIOS settings */ spi_max_width(starget) = (flags & CFWIDEB) ? 1 : 0; diff --git a/drivers/scsi/bnx2i/57xx_iscsi_constants.h b/drivers/scsi/bnx2i/57xx_iscsi_constants.h new file mode 100644 index 000000000000..2fceb19eb27b --- /dev/null +++ b/drivers/scsi/bnx2i/57xx_iscsi_constants.h @@ -0,0 +1,155 @@ +/* 57xx_iscsi_constants.h: Broadcom NetXtreme II iSCSI HSI + * + * Copyright (c) 2006 - 2009 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation. + * + * Written by: Anil Veerabhadrappa (anilgv@broadcom.com) + */ +#ifndef __57XX_ISCSI_CONSTANTS_H_ +#define __57XX_ISCSI_CONSTANTS_H_ + +/** +* This file defines HSI constants for the iSCSI flows +*/ + +/* iSCSI request op codes */ +#define ISCSI_OPCODE_CLEANUP_REQUEST (7) + +/* iSCSI response/messages op codes */ +#define ISCSI_OPCODE_CLEANUP_RESPONSE (0x27) +#define ISCSI_OPCODE_NOPOUT_LOCAL_COMPLETION (0) + +/* iSCSI task types */ +#define ISCSI_TASK_TYPE_READ (0) +#define ISCSI_TASK_TYPE_WRITE (1) +#define ISCSI_TASK_TYPE_MPATH (2) + +/* initial CQ sequence numbers */ +#define ISCSI_INITIAL_SN (1) + +/* KWQ (kernel work queue) layer codes */ +#define ISCSI_KWQE_LAYER_CODE (6) + +/* KWQ (kernel work queue) request op codes */ +#define ISCSI_KWQE_OPCODE_OFFLOAD_CONN1 (0) +#define ISCSI_KWQE_OPCODE_OFFLOAD_CONN2 (1) +#define ISCSI_KWQE_OPCODE_UPDATE_CONN (2) +#define ISCSI_KWQE_OPCODE_DESTROY_CONN (3) +#define ISCSI_KWQE_OPCODE_INIT1 (4) +#define ISCSI_KWQE_OPCODE_INIT2 (5) + +/* KCQ (kernel completion queue) response op codes */ +#define ISCSI_KCQE_OPCODE_OFFLOAD_CONN (0x10) +#define ISCSI_KCQE_OPCODE_UPDATE_CONN (0x12) +#define ISCSI_KCQE_OPCODE_DESTROY_CONN (0x13) +#define ISCSI_KCQE_OPCODE_INIT (0x14) +#define ISCSI_KCQE_OPCODE_FW_CLEAN_TASK (0x15) +#define ISCSI_KCQE_OPCODE_TCP_RESET (0x16) +#define ISCSI_KCQE_OPCODE_TCP_SYN (0x17) +#define ISCSI_KCQE_OPCODE_TCP_FIN (0X18) +#define ISCSI_KCQE_OPCODE_TCP_ERROR (0x19) +#define ISCSI_KCQE_OPCODE_CQ_EVENT_NOTIFICATION (0x20) +#define ISCSI_KCQE_OPCODE_ISCSI_ERROR (0x21) + +/* KCQ (kernel completion queue) completion status */ +#define ISCSI_KCQE_COMPLETION_STATUS_SUCCESS (0x0) +#define ISCSI_KCQE_COMPLETION_STATUS_INVALID_OPCODE (0x1) +#define ISCSI_KCQE_COMPLETION_STATUS_CTX_ALLOC_FAILURE (0x2) +#define ISCSI_KCQE_COMPLETION_STATUS_CTX_FREE_FAILURE (0x3) +#define ISCSI_KCQE_COMPLETION_STATUS_NIC_ERROR (0x4) + +#define ISCSI_KCQE_COMPLETION_STATUS_HDR_DIG_ERR (0x5) +#define ISCSI_KCQE_COMPLETION_STATUS_DATA_DIG_ERR (0x6) + +#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_UNEXPECTED_OPCODE (0xa) +#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_OPCODE (0xb) +#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_AHS_LEN (0xc) +#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_ITT (0xd) +#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_STATSN (0xe) + +/* Response */ +#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_EXP_DATASN (0xf) +#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_PEND_R2T (0x10) +#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_DATA_SEG_LEN_IS_ZERO (0x2c) +#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_DATA_SEG_LEN_TOO_BIG (0x2d) +#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_0 (0x11) +#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_1 (0x12) +#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_2 (0x13) +#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_3 (0x14) +#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_4 (0x15) +#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_5 (0x16) +#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_6 (0x17) + +/* Data-In */ +#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_REMAIN_RCV_LEN (0x18) +#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_MAX_RCV_PDU_LEN (0x19) +#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_F_BIT_ZERO (0x1a) +#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_TTT_NOT_RSRV (0x1b) +#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_DATASN (0x1c) +#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_REMAIN_BURST_LEN (0x1d) + +/* R2T */ +#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_BUFFER_OFF (0x1f) +#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_LUN (0x20) +#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_R2TSN (0x21) +#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_DESIRED_DATA_TRNS_LEN_0 (0x22) +#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_DESIRED_DATA_TRNS_LEN_1 (0x23) +#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_PEND_R2T_EXCEED (0x24) +#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_TTT_IS_RSRV (0x25) +#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_MAX_BURST_LEN (0x26) +#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_DATA_SEG_LEN_NOT_ZERO (0x27) + +/* TMF */ +#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_REJECT_PDU_LEN (0x28) +#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_ASYNC_PDU_LEN (0x29) +#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_NOPIN_PDU_LEN (0x2a) +#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_PEND_R2T_IN_CLEANUP (0x2b) + +/* IP/TCP processing errors: */ +#define ISCI_KCQE_COMPLETION_STATUS_TCP_ERROR_IP_FRAGMENT (0x40) +#define ISCI_KCQE_COMPLETION_STATUS_TCP_ERROR_IP_OPTIONS (0x41) +#define ISCI_KCQE_COMPLETION_STATUS_TCP_ERROR_URGENT_FLAG (0x42) +#define ISCI_KCQE_COMPLETION_STATUS_TCP_ERROR_MAX_RTRANS (0x43) + +/* iSCSI licensing errors */ +/* general iSCSI license not installed */ +#define ISCSI_KCQE_COMPLETION_STATUS_ISCSI_NOT_SUPPORTED (0x50) +/* additional LOM specific iSCSI license not installed */ +#define ISCSI_KCQE_COMPLETION_STATUS_LOM_ISCSI_NOT_ENABLED (0x51) + +/* SQ/RQ/CQ DB structure sizes */ +#define ISCSI_SQ_DB_SIZE (16) +#define ISCSI_RQ_DB_SIZE (16) +#define ISCSI_CQ_DB_SIZE (80) + +#define ISCSI_SQN_TO_NOTIFY_NOT_VALID 0xFFFF + +/* Page size codes (for flags field in connection offload request) */ +#define ISCSI_PAGE_SIZE_256 (0) +#define ISCSI_PAGE_SIZE_512 (1) +#define ISCSI_PAGE_SIZE_1K (2) +#define ISCSI_PAGE_SIZE_2K (3) +#define ISCSI_PAGE_SIZE_4K (4) +#define ISCSI_PAGE_SIZE_8K (5) +#define ISCSI_PAGE_SIZE_16K (6) +#define ISCSI_PAGE_SIZE_32K (7) +#define ISCSI_PAGE_SIZE_64K (8) +#define ISCSI_PAGE_SIZE_128K (9) +#define ISCSI_PAGE_SIZE_256K (10) +#define ISCSI_PAGE_SIZE_512K (11) +#define ISCSI_PAGE_SIZE_1M (12) +#define ISCSI_PAGE_SIZE_2M (13) +#define ISCSI_PAGE_SIZE_4M (14) +#define ISCSI_PAGE_SIZE_8M (15) + +/* Iscsi PDU related defines */ +#define ISCSI_HEADER_SIZE (48) +#define ISCSI_DIGEST_SHIFT (2) +#define ISCSI_DIGEST_SIZE (4) + +#define B577XX_ISCSI_CONNECTION_TYPE 3 + +#endif /*__57XX_ISCSI_CONSTANTS_H_ */ diff --git a/drivers/scsi/bnx2i/57xx_iscsi_hsi.h b/drivers/scsi/bnx2i/57xx_iscsi_hsi.h new file mode 100644 index 000000000000..36af1afef9b6 --- /dev/null +++ b/drivers/scsi/bnx2i/57xx_iscsi_hsi.h @@ -0,0 +1,1509 @@ +/* 57xx_iscsi_hsi.h: Broadcom NetXtreme II iSCSI HSI. + * + * Copyright (c) 2006 - 2009 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation. + * + * Written by: Anil Veerabhadrappa (anilgv@broadcom.com) + */ +#ifndef __57XX_ISCSI_HSI_LINUX_LE__ +#define __57XX_ISCSI_HSI_LINUX_LE__ + +/* + * iSCSI Async CQE + */ +struct bnx2i_async_msg { +#if defined(__BIG_ENDIAN) + u8 op_code; + u8 reserved1; + u16 reserved0; +#elif defined(__LITTLE_ENDIAN) + u16 reserved0; + u8 reserved1; + u8 op_code; +#endif + u32 reserved2; + u32 exp_cmd_sn; + u32 max_cmd_sn; + u32 reserved3[2]; +#if defined(__BIG_ENDIAN) + u16 reserved5; + u8 err_code; + u8 reserved4; +#elif defined(__LITTLE_ENDIAN) + u8 reserved4; + u8 err_code; + u16 reserved5; +#endif + u32 reserved6; + u32 lun[2]; +#if defined(__BIG_ENDIAN) + u8 async_event; + u8 async_vcode; + u16 param1; +#elif defined(__LITTLE_ENDIAN) + u16 param1; + u8 async_vcode; + u8 async_event; +#endif +#if defined(__BIG_ENDIAN) + u16 param2; + u16 param3; +#elif defined(__LITTLE_ENDIAN) + u16 param3; + u16 param2; +#endif + u32 reserved7[3]; + u32 cq_req_sn; +}; + + +/* + * iSCSI Buffer Descriptor (BD) + */ +struct iscsi_bd { + u32 buffer_addr_hi; + u32 buffer_addr_lo; +#if defined(__BIG_ENDIAN) + u16 reserved0; + u16 buffer_length; +#elif defined(__LITTLE_ENDIAN) + u16 buffer_length; + u16 reserved0; +#endif +#if defined(__BIG_ENDIAN) + u16 reserved3; + u16 flags; +#define ISCSI_BD_RESERVED1 (0x3F<<0) +#define ISCSI_BD_RESERVED1_SHIFT 0 +#define ISCSI_BD_LAST_IN_BD_CHAIN (0x1<<6) +#define ISCSI_BD_LAST_IN_BD_CHAIN_SHIFT 6 +#define ISCSI_BD_FIRST_IN_BD_CHAIN (0x1<<7) +#define ISCSI_BD_FIRST_IN_BD_CHAIN_SHIFT 7 +#define ISCSI_BD_RESERVED2 (0xFF<<8) +#define ISCSI_BD_RESERVED2_SHIFT 8 +#elif defined(__LITTLE_ENDIAN) + u16 flags; +#define ISCSI_BD_RESERVED1 (0x3F<<0) +#define ISCSI_BD_RESERVED1_SHIFT 0 +#define ISCSI_BD_LAST_IN_BD_CHAIN (0x1<<6) +#define ISCSI_BD_LAST_IN_BD_CHAIN_SHIFT 6 +#define ISCSI_BD_FIRST_IN_BD_CHAIN (0x1<<7) +#define ISCSI_BD_FIRST_IN_BD_CHAIN_SHIFT 7 +#define ISCSI_BD_RESERVED2 (0xFF<<8) +#define ISCSI_BD_RESERVED2_SHIFT 8 + u16 reserved3; +#endif +}; + + +/* + * iSCSI Cleanup SQ WQE + */ +struct bnx2i_cleanup_request { +#if defined(__BIG_ENDIAN) + u8 op_code; + u8 reserved1; + u16 reserved0; +#elif defined(__LITTLE_ENDIAN) + u16 reserved0; + u8 reserved1; + u8 op_code; +#endif + u32 reserved2[3]; +#if defined(__BIG_ENDIAN) + u16 reserved3; + u16 itt; +#define ISCSI_CLEANUP_REQUEST_INDEX (0x3FFF<<0) +#define ISCSI_CLEANUP_REQUEST_INDEX_SHIFT 0 +#define ISCSI_CLEANUP_REQUEST_TYPE (0x3<<14) +#define ISCSI_CLEANUP_REQUEST_TYPE_SHIFT 14 +#elif defined(__LITTLE_ENDIAN) + u16 itt; +#define ISCSI_CLEANUP_REQUEST_INDEX (0x3FFF<<0) +#define ISCSI_CLEANUP_REQUEST_INDEX_SHIFT 0 +#define ISCSI_CLEANUP_REQUEST_TYPE (0x3<<14) +#define ISCSI_CLEANUP_REQUEST_TYPE_SHIFT 14 + u16 reserved3; +#endif + u32 reserved4[10]; +#if defined(__BIG_ENDIAN) + u8 cq_index; + u8 reserved6; + u16 reserved5; +#elif defined(__LITTLE_ENDIAN) + u16 reserved5; + u8 reserved6; + u8 cq_index; +#endif +}; + + +/* + * iSCSI Cleanup CQE + */ +struct bnx2i_cleanup_response { +#if defined(__BIG_ENDIAN) + u8 op_code; + u8 status; + u16 reserved0; +#elif defined(__LITTLE_ENDIAN) + u16 reserved0; + u8 status; + u8 op_code; +#endif + u32 reserved1[3]; + u32 reserved2[2]; +#if defined(__BIG_ENDIAN) + u16 reserved4; + u8 err_code; + u8 reserved3; +#elif defined(__LITTLE_ENDIAN) + u8 reserved3; + u8 err_code; + u16 reserved4; +#endif + u32 reserved5[7]; +#if defined(__BIG_ENDIAN) + u16 reserved6; + u16 itt; +#define ISCSI_CLEANUP_RESPONSE_INDEX (0x3FFF<<0) +#define ISCSI_CLEANUP_RESPONSE_INDEX_SHIFT 0 +#define ISCSI_CLEANUP_RESPONSE_TYPE (0x3<<14) +#define ISCSI_CLEANUP_RESPONSE_TYPE_SHIFT 14 +#elif defined(__LITTLE_ENDIAN) + u16 itt; +#define ISCSI_CLEANUP_RESPONSE_INDEX (0x3FFF<<0) +#define ISCSI_CLEANUP_RESPONSE_INDEX_SHIFT 0 +#define ISCSI_CLEANUP_RESPONSE_TYPE (0x3<<14) +#define ISCSI_CLEANUP_RESPONSE_TYPE_SHIFT 14 + u16 reserved6; +#endif + u32 cq_req_sn; +}; + + +/* + * SCSI read/write SQ WQE + */ +struct bnx2i_cmd_request { +#if defined(__BIG_ENDIAN) + u8 op_code; + u8 op_attr; +#define ISCSI_CMD_REQUEST_TASK_ATTR (0x7<<0) +#define ISCSI_CMD_REQUEST_TASK_ATTR_SHIFT 0 +#define ISCSI_CMD_REQUEST_RESERVED1 (0x3<<3) +#define ISCSI_CMD_REQUEST_RESERVED1_SHIFT 3 +#define ISCSI_CMD_REQUEST_WRITE (0x1<<5) +#define ISCSI_CMD_REQUEST_WRITE_SHIFT 5 +#define ISCSI_CMD_REQUEST_READ (0x1<<6) +#define ISCSI_CMD_REQUEST_READ_SHIFT 6 +#define ISCSI_CMD_REQUEST_FINAL (0x1<<7) +#define ISCSI_CMD_REQUEST_FINAL_SHIFT 7 + u16 reserved0; +#elif defined(__LITTLE_ENDIAN) + u16 reserved0; + u8 op_attr; +#define ISCSI_CMD_REQUEST_TASK_ATTR (0x7<<0) +#define ISCSI_CMD_REQUEST_TASK_ATTR_SHIFT 0 +#define ISCSI_CMD_REQUEST_RESERVED1 (0x3<<3) +#define ISCSI_CMD_REQUEST_RESERVED1_SHIFT 3 +#define ISCSI_CMD_REQUEST_WRITE (0x1<<5) +#define ISCSI_CMD_REQUEST_WRITE_SHIFT 5 +#define ISCSI_CMD_REQUEST_READ (0x1<<6) +#define ISCSI_CMD_REQUEST_READ_SHIFT 6 +#define ISCSI_CMD_REQUEST_FINAL (0x1<<7) +#define ISCSI_CMD_REQUEST_FINAL_SHIFT 7 + u8 op_code; +#endif +#if defined(__BIG_ENDIAN) + u16 ud_buffer_offset; + u16 sd_buffer_offset; +#elif defined(__LITTLE_ENDIAN) + u16 sd_buffer_offset; + u16 ud_buffer_offset; +#endif + u32 lun[2]; +#if defined(__BIG_ENDIAN) + u16 reserved2; + u16 itt; +#define ISCSI_CMD_REQUEST_INDEX (0x3FFF<<0) +#define ISCSI_CMD_REQUEST_INDEX_SHIFT 0 +#define ISCSI_CMD_REQUEST_TYPE (0x3<<14) +#define ISCSI_CMD_REQUEST_TYPE_SHIFT 14 +#elif defined(__LITTLE_ENDIAN) + u16 itt; +#define ISCSI_CMD_REQUEST_INDEX (0x3FFF<<0) +#define ISCSI_CMD_REQUEST_INDEX_SHIFT 0 +#define ISCSI_CMD_REQUEST_TYPE (0x3<<14) +#define ISCSI_CMD_REQUEST_TYPE_SHIFT 14 + u16 reserved2; +#endif + u32 total_data_transfer_length; + u32 cmd_sn; + u32 reserved3; + u32 cdb[4]; + u32 zero_fill; + u32 bd_list_addr_lo; + u32 bd_list_addr_hi; +#if defined(__BIG_ENDIAN) + u8 cq_index; + u8 sd_start_bd_index; + u8 ud_start_bd_index; + u8 num_bds; +#elif defined(__LITTLE_ENDIAN) + u8 num_bds; + u8 ud_start_bd_index; + u8 sd_start_bd_index; + u8 cq_index; +#endif +}; + + +/* + * task statistics for write response + */ +struct bnx2i_write_resp_task_stat { + u32 num_data_ins; +}; + +/* + * task statistics for read response + */ +struct bnx2i_read_resp_task_stat { +#if defined(__BIG_ENDIAN) + u16 num_data_outs; + u16 num_r2ts; +#elif defined(__LITTLE_ENDIAN) + u16 num_r2ts; + u16 num_data_outs; +#endif +}; + +/* + * task statistics for iSCSI cmd response + */ +union bnx2i_cmd_resp_task_stat { + struct bnx2i_write_resp_task_stat write_stat; + struct bnx2i_read_resp_task_stat read_stat; +}; + +/* + * SCSI Command CQE + */ +struct bnx2i_cmd_response { +#if defined(__BIG_ENDIAN) + u8 op_code; + u8 response_flags; +#define ISCSI_CMD_RESPONSE_RESERVED0 (0x1<<0) +#define ISCSI_CMD_RESPONSE_RESERVED0_SHIFT 0 +#define ISCSI_CMD_RESPONSE_RESIDUAL_UNDERFLOW (0x1<<1) +#define ISCSI_CMD_RESPONSE_RESIDUAL_UNDERFLOW_SHIFT 1 +#define ISCSI_CMD_RESPONSE_RESIDUAL_OVERFLOW (0x1<<2) +#define ISCSI_CMD_RESPONSE_RESIDUAL_OVERFLOW_SHIFT 2 +#define ISCSI_CMD_RESPONSE_BR_RESIDUAL_UNDERFLOW (0x1<<3) +#define ISCSI_CMD_RESPONSE_BR_RESIDUAL_UNDERFLOW_SHIFT 3 +#define ISCSI_CMD_RESPONSE_BR_RESIDUAL_OVERFLOW (0x1<<4) +#define ISCSI_CMD_RESPONSE_BR_RESIDUAL_OVERFLOW_SHIFT 4 +#define ISCSI_CMD_RESPONSE_RESERVED1 (0x7<<5) +#define ISCSI_CMD_RESPONSE_RESERVED1_SHIFT 5 + u8 response; + u8 status; +#elif defined(__LITTLE_ENDIAN) + u8 status; + u8 response; + u8 response_flags; +#define ISCSI_CMD_RESPONSE_RESERVED0 (0x1<<0) +#define ISCSI_CMD_RESPONSE_RESERVED0_SHIFT 0 +#define ISCSI_CMD_RESPONSE_RESIDUAL_UNDERFLOW (0x1<<1) +#define ISCSI_CMD_RESPONSE_RESIDUAL_UNDERFLOW_SHIFT 1 +#define ISCSI_CMD_RESPONSE_RESIDUAL_OVERFLOW (0x1<<2) +#define ISCSI_CMD_RESPONSE_RESIDUAL_OVERFLOW_SHIFT 2 +#define ISCSI_CMD_RESPONSE_BR_RESIDUAL_UNDERFLOW (0x1<<3) +#define ISCSI_CMD_RESPONSE_BR_RESIDUAL_UNDERFLOW_SHIFT 3 +#define ISCSI_CMD_RESPONSE_BR_RESIDUAL_OVERFLOW (0x1<<4) +#define ISCSI_CMD_RESPONSE_BR_RESIDUAL_OVERFLOW_SHIFT 4 +#define ISCSI_CMD_RESPONSE_RESERVED1 (0x7<<5) +#define ISCSI_CMD_RESPONSE_RESERVED1_SHIFT 5 + u8 op_code; +#endif + u32 data_length; + u32 exp_cmd_sn; + u32 max_cmd_sn; + u32 reserved2; + u32 residual_count; +#if defined(__BIG_ENDIAN) + u16 reserved4; + u8 err_code; + u8 reserved3; +#elif defined(__LITTLE_ENDIAN) + u8 reserved3; + u8 err_code; + u16 reserved4; +#endif + u32 reserved5[5]; + union bnx2i_cmd_resp_task_stat task_stat; + u32 reserved6; +#if defined(__BIG_ENDIAN) + u16 reserved7; + u16 itt; +#define ISCSI_CMD_RESPONSE_INDEX (0x3FFF<<0) +#define ISCSI_CMD_RESPONSE_INDEX_SHIFT 0 +#define ISCSI_CMD_RESPONSE_TYPE (0x3<<14) +#define ISCSI_CMD_RESPONSE_TYPE_SHIFT 14 +#elif defined(__LITTLE_ENDIAN) + u16 itt; +#define ISCSI_CMD_RESPONSE_INDEX (0x3FFF<<0) +#define ISCSI_CMD_RESPONSE_INDEX_SHIFT 0 +#define ISCSI_CMD_RESPONSE_TYPE (0x3<<14) +#define ISCSI_CMD_RESPONSE_TYPE_SHIFT 14 + u16 reserved7; +#endif + u32 cq_req_sn; +}; + + + +/* + * firmware middle-path request SQ WQE + */ +struct bnx2i_fw_mp_request { +#if defined(__BIG_ENDIAN) + u8 op_code; + u8 op_attr; + u16 hdr_opaque1; +#elif defined(__LITTLE_ENDIAN) + u16 hdr_opaque1; + u8 op_attr; + u8 op_code; +#endif + u32 data_length; + u32 hdr_opaque2[2]; +#if defined(__BIG_ENDIAN) + u16 reserved0; + u16 itt; +#define ISCSI_FW_MP_REQUEST_INDEX (0x3FFF<<0) +#define ISCSI_FW_MP_REQUEST_INDEX_SHIFT 0 +#define ISCSI_FW_MP_REQUEST_TYPE (0x3<<14) +#define ISCSI_FW_MP_REQUEST_TYPE_SHIFT 14 +#elif defined(__LITTLE_ENDIAN) + u16 itt; +#define ISCSI_FW_MP_REQUEST_INDEX (0x3FFF<<0) +#define ISCSI_FW_MP_REQUEST_INDEX_SHIFT 0 +#define ISCSI_FW_MP_REQUEST_TYPE (0x3<<14) +#define ISCSI_FW_MP_REQUEST_TYPE_SHIFT 14 + u16 reserved0; +#endif + u32 hdr_opaque3[4]; + u32 resp_bd_list_addr_lo; + u32 resp_bd_list_addr_hi; + u32 resp_buffer; +#define ISCSI_FW_MP_REQUEST_RESP_BUFFER_LENGTH (0xFFFFFF<<0) +#define ISCSI_FW_MP_REQUEST_RESP_BUFFER_LENGTH_SHIFT 0 +#define ISCSI_FW_MP_REQUEST_NUM_RESP_BDS (0xFF<<24) +#define ISCSI_FW_MP_REQUEST_NUM_RESP_BDS_SHIFT 24 +#if defined(__BIG_ENDIAN) + u16 reserved4; + u8 reserved3; + u8 flags; +#define ISCSI_FW_MP_REQUEST_RESERVED1 (0x1<<0) +#define ISCSI_FW_MP_REQUEST_RESERVED1_SHIFT 0 +#define ISCSI_FW_MP_REQUEST_LOCAL_COMPLETION (0x1<<1) +#define ISCSI_FW_MP_REQUEST_LOCAL_COMPLETION_SHIFT 1 +#define ISCSI_FW_MP_REQUEST_UPDATE_EXP_STAT_SN (0x1<<2) +#define ISCSI_FW_MP_REQUEST_UPDATE_EXP_STAT_SN_SHIFT 2 +#define ISCSI_FW_MP_REQUEST_RESERVED2 (0x1F<<3) +#define ISCSI_FW_MP_REQUEST_RESERVED2_SHIFT 3 +#elif defined(__LITTLE_ENDIAN) + u8 flags; +#define ISCSI_FW_MP_REQUEST_RESERVED1 (0x1<<0) +#define ISCSI_FW_MP_REQUEST_RESERVED1_SHIFT 0 +#define ISCSI_FW_MP_REQUEST_LOCAL_COMPLETION (0x1<<1) +#define ISCSI_FW_MP_REQUEST_LOCAL_COMPLETION_SHIFT 1 +#define ISCSI_FW_MP_REQUEST_UPDATE_EXP_STAT_SN (0x1<<2) +#define ISCSI_FW_MP_REQUEST_UPDATE_EXP_STAT_SN_SHIFT 2 +#define ISCSI_FW_MP_REQUEST_RESERVED2 (0x1F<<3) +#define ISCSI_FW_MP_REQUEST_RESERVED2_SHIFT 3 + u8 reserved3; + u16 reserved4; +#endif + u32 bd_list_addr_lo; + u32 bd_list_addr_hi; +#if defined(__BIG_ENDIAN) + u8 cq_index; + u8 reserved6; + u8 reserved5; + u8 num_bds; +#elif defined(__LITTLE_ENDIAN) + u8 num_bds; + u8 reserved5; + u8 reserved6; + u8 cq_index; +#endif +}; + + +/* + * firmware response - CQE: used only by firmware + */ +struct bnx2i_fw_response { + u32 hdr_dword1[2]; + u32 hdr_exp_cmd_sn; + u32 hdr_max_cmd_sn; + u32 hdr_ttt; + u32 hdr_res_cnt; + u32 cqe_flags; +#define ISCSI_FW_RESPONSE_RESERVED2 (0xFF<<0) +#define ISCSI_FW_RESPONSE_RESERVED2_SHIFT 0 +#define ISCSI_FW_RESPONSE_ERR_CODE (0xFF<<8) +#define ISCSI_FW_RESPONSE_ERR_CODE_SHIFT 8 +#define ISCSI_FW_RESPONSE_RESERVED3 (0xFFFF<<16) +#define ISCSI_FW_RESPONSE_RESERVED3_SHIFT 16 + u32 stat_sn; + u32 hdr_dword2[2]; + u32 hdr_dword3[2]; + u32 task_stat; + u32 reserved0; + u32 hdr_itt; + u32 cq_req_sn; +}; + + +/* + * iSCSI KCQ CQE parameters + */ +union iscsi_kcqe_params { + u32 reserved0[4]; +}; + +/* + * iSCSI KCQ CQE + */ +struct iscsi_kcqe { + u32 iscsi_conn_id; + u32 completion_status; + u32 iscsi_conn_context_id; + union iscsi_kcqe_params params; +#if defined(__BIG_ENDIAN) + u8 flags; +#define ISCSI_KCQE_RESERVED0 (0xF<<0) +#define ISCSI_KCQE_RESERVED0_SHIFT 0 +#define ISCSI_KCQE_LAYER_CODE (0x7<<4) +#define ISCSI_KCQE_LAYER_CODE_SHIFT 4 +#define ISCSI_KCQE_RESERVED1 (0x1<<7) +#define ISCSI_KCQE_RESERVED1_SHIFT 7 + u8 op_code; + u16 qe_self_seq; +#elif defined(__LITTLE_ENDIAN) + u16 qe_self_seq; + u8 op_code; + u8 flags; +#define ISCSI_KCQE_RESERVED0 (0xF<<0) +#define ISCSI_KCQE_RESERVED0_SHIFT 0 +#define ISCSI_KCQE_LAYER_CODE (0x7<<4) +#define ISCSI_KCQE_LAYER_CODE_SHIFT 4 +#define ISCSI_KCQE_RESERVED1 (0x1<<7) +#define ISCSI_KCQE_RESERVED1_SHIFT 7 +#endif +}; + + + +/* + * iSCSI KWQE header + */ +struct iscsi_kwqe_header { +#if defined(__BIG_ENDIAN) + u8 flags; +#define ISCSI_KWQE_HEADER_RESERVED0 (0xF<<0) +#define ISCSI_KWQE_HEADER_RESERVED0_SHIFT 0 +#define ISCSI_KWQE_HEADER_LAYER_CODE (0x7<<4) +#define ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT 4 +#define ISCSI_KWQE_HEADER_RESERVED1 (0x1<<7) +#define ISCSI_KWQE_HEADER_RESERVED1_SHIFT 7 + u8 op_code; +#elif defined(__LITTLE_ENDIAN) + u8 op_code; + u8 flags; +#define ISCSI_KWQE_HEADER_RESERVED0 (0xF<<0) +#define ISCSI_KWQE_HEADER_RESERVED0_SHIFT 0 +#define ISCSI_KWQE_HEADER_LAYER_CODE (0x7<<4) +#define ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT 4 +#define ISCSI_KWQE_HEADER_RESERVED1 (0x1<<7) +#define ISCSI_KWQE_HEADER_RESERVED1_SHIFT 7 +#endif +}; + +/* + * iSCSI firmware init request 1 + */ +struct iscsi_kwqe_init1 { +#if defined(__BIG_ENDIAN) + struct iscsi_kwqe_header hdr; + u8 reserved0; + u8 num_cqs; +#elif defined(__LITTLE_ENDIAN) + u8 num_cqs; + u8 reserved0; + struct iscsi_kwqe_header hdr; +#endif + u32 dummy_buffer_addr_lo; + u32 dummy_buffer_addr_hi; +#if defined(__BIG_ENDIAN) + u16 num_ccells_per_conn; + u16 num_tasks_per_conn; +#elif defined(__LITTLE_ENDIAN) + u16 num_tasks_per_conn; + u16 num_ccells_per_conn; +#endif +#if defined(__BIG_ENDIAN) + u16 sq_wqes_per_page; + u16 sq_num_wqes; +#elif defined(__LITTLE_ENDIAN) + u16 sq_num_wqes; + u16 sq_wqes_per_page; +#endif +#if defined(__BIG_ENDIAN) + u8 cq_log_wqes_per_page; + u8 flags; +#define ISCSI_KWQE_INIT1_PAGE_SIZE (0xF<<0) +#define ISCSI_KWQE_INIT1_PAGE_SIZE_SHIFT 0 +#define ISCSI_KWQE_INIT1_DELAYED_ACK_ENABLE (0x1<<4) +#define ISCSI_KWQE_INIT1_DELAYED_ACK_ENABLE_SHIFT 4 +#define ISCSI_KWQE_INIT1_KEEP_ALIVE_ENABLE (0x1<<5) +#define ISCSI_KWQE_INIT1_KEEP_ALIVE_ENABLE_SHIFT 5 +#define ISCSI_KWQE_INIT1_RESERVED1 (0x3<<6) +#define ISCSI_KWQE_INIT1_RESERVED1_SHIFT 6 + u16 cq_num_wqes; +#elif defined(__LITTLE_ENDIAN) + u16 cq_num_wqes; + u8 flags; +#define ISCSI_KWQE_INIT1_PAGE_SIZE (0xF<<0) +#define ISCSI_KWQE_INIT1_PAGE_SIZE_SHIFT 0 +#define ISCSI_KWQE_INIT1_DELAYED_ACK_ENABLE (0x1<<4) +#define ISCSI_KWQE_INIT1_DELAYED_ACK_ENABLE_SHIFT 4 +#define ISCSI_KWQE_INIT1_KEEP_ALIVE_ENABLE (0x1<<5) +#define ISCSI_KWQE_INIT1_KEEP_ALIVE_ENABLE_SHIFT 5 +#define ISCSI_KWQE_INIT1_RESERVED1 (0x3<<6) +#define ISCSI_KWQE_INIT1_RESERVED1_SHIFT 6 + u8 cq_log_wqes_per_page; +#endif +#if defined(__BIG_ENDIAN) + u16 cq_num_pages; + u16 sq_num_pages; +#elif defined(__LITTLE_ENDIAN) + u16 sq_num_pages; + u16 cq_num_pages; +#endif +#if defined(__BIG_ENDIAN) + u16 rq_buffer_size; + u16 rq_num_wqes; +#elif defined(__LITTLE_ENDIAN) + u16 rq_num_wqes; + u16 rq_buffer_size; +#endif +}; + +/* + * iSCSI firmware init request 2 + */ +struct iscsi_kwqe_init2 { +#if defined(__BIG_ENDIAN) + struct iscsi_kwqe_header hdr; + u16 max_cq_sqn; +#elif defined(__LITTLE_ENDIAN) + u16 max_cq_sqn; + struct iscsi_kwqe_header hdr; +#endif + u32 error_bit_map[2]; + u32 reserved1[5]; +}; + +/* + * Initial iSCSI connection offload request 1 + */ +struct iscsi_kwqe_conn_offload1 { +#if defined(__BIG_ENDIAN) + struct iscsi_kwqe_header hdr; + u16 iscsi_conn_id; +#elif defined(__LITTLE_ENDIAN) + u16 iscsi_conn_id; + struct iscsi_kwqe_header hdr; +#endif + u32 sq_page_table_addr_lo; + u32 sq_page_table_addr_hi; + u32 cq_page_table_addr_lo; + u32 cq_page_table_addr_hi; + u32 reserved0[3]; +}; + +/* + * iSCSI Page Table Entry (PTE) + */ +struct iscsi_pte { + u32 hi; + u32 lo; +}; + +/* + * Initial iSCSI connection offload request 2 + */ +struct iscsi_kwqe_conn_offload2 { +#if defined(__BIG_ENDIAN) + struct iscsi_kwqe_header hdr; + u16 reserved0; +#elif defined(__LITTLE_ENDIAN) + u16 reserved0; + struct iscsi_kwqe_header hdr; +#endif + u32 rq_page_table_addr_lo; + u32 rq_page_table_addr_hi; + struct iscsi_pte sq_first_pte; + struct iscsi_pte cq_first_pte; + u32 num_additional_wqes; +}; + + +/* + * Initial iSCSI connection offload request 3 + */ +struct iscsi_kwqe_conn_offload3 { +#if defined(__BIG_ENDIAN) + struct iscsi_kwqe_header hdr; + u16 reserved0; +#elif defined(__LITTLE_ENDIAN) + u16 reserved0; + struct iscsi_kwqe_header hdr; +#endif + u32 reserved1; + struct iscsi_pte qp_first_pte[3]; +}; + + +/* + * iSCSI connection update request + */ +struct iscsi_kwqe_conn_update { +#if defined(__BIG_ENDIAN) + struct iscsi_kwqe_header hdr; + u16 reserved0; +#elif defined(__LITTLE_ENDIAN) + u16 reserved0; + struct iscsi_kwqe_header hdr; +#endif +#if defined(__BIG_ENDIAN) + u8 session_error_recovery_level; + u8 max_outstanding_r2ts; + u8 reserved2; + u8 conn_flags; +#define ISCSI_KWQE_CONN_UPDATE_HEADER_DIGEST (0x1<<0) +#define ISCSI_KWQE_CONN_UPDATE_HEADER_DIGEST_SHIFT 0 +#define ISCSI_KWQE_CONN_UPDATE_DATA_DIGEST (0x1<<1) +#define ISCSI_KWQE_CONN_UPDATE_DATA_DIGEST_SHIFT 1 +#define ISCSI_KWQE_CONN_UPDATE_INITIAL_R2T (0x1<<2) +#define ISCSI_KWQE_CONN_UPDATE_INITIAL_R2T_SHIFT 2 +#define ISCSI_KWQE_CONN_UPDATE_IMMEDIATE_DATA (0x1<<3) +#define ISCSI_KWQE_CONN_UPDATE_IMMEDIATE_DATA_SHIFT 3 +#define ISCSI_KWQE_CONN_UPDATE_RESERVED1 (0xF<<4) +#define ISCSI_KWQE_CONN_UPDATE_RESERVED1_SHIFT 4 +#elif defined(__LITTLE_ENDIAN) + u8 conn_flags; +#define ISCSI_KWQE_CONN_UPDATE_HEADER_DIGEST (0x1<<0) +#define ISCSI_KWQE_CONN_UPDATE_HEADER_DIGEST_SHIFT 0 +#define ISCSI_KWQE_CONN_UPDATE_DATA_DIGEST (0x1<<1) +#define ISCSI_KWQE_CONN_UPDATE_DATA_DIGEST_SHIFT 1 +#define ISCSI_KWQE_CONN_UPDATE_INITIAL_R2T (0x1<<2) +#define ISCSI_KWQE_CONN_UPDATE_INITIAL_R2T_SHIFT 2 +#define ISCSI_KWQE_CONN_UPDATE_IMMEDIATE_DATA (0x1<<3) +#define ISCSI_KWQE_CONN_UPDATE_IMMEDIATE_DATA_SHIFT 3 +#define ISCSI_KWQE_CONN_UPDATE_RESERVED1 (0xF<<4) +#define ISCSI_KWQE_CONN_UPDATE_RESERVED1_SHIFT 4 + u8 reserved2; + u8 max_outstanding_r2ts; + u8 session_error_recovery_level; +#endif + u32 context_id; + u32 max_send_pdu_length; + u32 max_recv_pdu_length; + u32 first_burst_length; + u32 max_burst_length; + u32 exp_stat_sn; +}; + +/* + * iSCSI destroy connection request + */ +struct iscsi_kwqe_conn_destroy { +#if defined(__BIG_ENDIAN) + struct iscsi_kwqe_header hdr; + u16 reserved0; +#elif defined(__LITTLE_ENDIAN) + u16 reserved0; + struct iscsi_kwqe_header hdr; +#endif + u32 context_id; + u32 reserved1[6]; +}; + +/* + * iSCSI KWQ WQE + */ +union iscsi_kwqe { + struct iscsi_kwqe_init1 init1; + struct iscsi_kwqe_init2 init2; + struct iscsi_kwqe_conn_offload1 conn_offload1; + struct iscsi_kwqe_conn_offload2 conn_offload2; + struct iscsi_kwqe_conn_update conn_update; + struct iscsi_kwqe_conn_destroy conn_destroy; +}; + +/* + * iSCSI Login SQ WQE + */ +struct bnx2i_login_request { +#if defined(__BIG_ENDIAN) + u8 op_code; + u8 op_attr; +#define ISCSI_LOGIN_REQUEST_NEXT_STAGE (0x3<<0) +#define ISCSI_LOGIN_REQUEST_NEXT_STAGE_SHIFT 0 +#define ISCSI_LOGIN_REQUEST_CURRENT_STAGE (0x3<<2) +#define ISCSI_LOGIN_REQUEST_CURRENT_STAGE_SHIFT 2 +#define ISCSI_LOGIN_REQUEST_RESERVED0 (0x3<<4) +#define ISCSI_LOGIN_REQUEST_RESERVED0_SHIFT 4 +#define ISCSI_LOGIN_REQUEST_CONT (0x1<<6) +#define ISCSI_LOGIN_REQUEST_CONT_SHIFT 6 +#define ISCSI_LOGIN_REQUEST_TRANSIT (0x1<<7) +#define ISCSI_LOGIN_REQUEST_TRANSIT_SHIFT 7 + u8 version_max; + u8 version_min; +#elif defined(__LITTLE_ENDIAN) + u8 version_min; + u8 version_max; + u8 op_attr; +#define ISCSI_LOGIN_REQUEST_NEXT_STAGE (0x3<<0) +#define ISCSI_LOGIN_REQUEST_NEXT_STAGE_SHIFT 0 +#define ISCSI_LOGIN_REQUEST_CURRENT_STAGE (0x3<<2) +#define ISCSI_LOGIN_REQUEST_CURRENT_STAGE_SHIFT 2 +#define ISCSI_LOGIN_REQUEST_RESERVED0 (0x3<<4) +#define ISCSI_LOGIN_REQUEST_RESERVED0_SHIFT 4 +#define ISCSI_LOGIN_REQUEST_CONT (0x1<<6) +#define ISCSI_LOGIN_REQUEST_CONT_SHIFT 6 +#define ISCSI_LOGIN_REQUEST_TRANSIT (0x1<<7) +#define ISCSI_LOGIN_REQUEST_TRANSIT_SHIFT 7 + u8 op_code; +#endif + u32 data_length; + u32 isid_lo; +#if defined(__BIG_ENDIAN) + u16 isid_hi; + u16 tsih; +#elif defined(__LITTLE_ENDIAN) + u16 tsih; + u16 isid_hi; +#endif +#if defined(__BIG_ENDIAN) + u16 reserved2; + u16 itt; +#define ISCSI_LOGIN_REQUEST_INDEX (0x3FFF<<0) +#define ISCSI_LOGIN_REQUEST_INDEX_SHIFT 0 +#define ISCSI_LOGIN_REQUEST_TYPE (0x3<<14) +#define ISCSI_LOGIN_REQUEST_TYPE_SHIFT 14 +#elif defined(__LITTLE_ENDIAN) + u16 itt; +#define ISCSI_LOGIN_REQUEST_INDEX (0x3FFF<<0) +#define ISCSI_LOGIN_REQUEST_INDEX_SHIFT 0 +#define ISCSI_LOGIN_REQUEST_TYPE (0x3<<14) +#define ISCSI_LOGIN_REQUEST_TYPE_SHIFT 14 + u16 reserved2; +#endif +#if defined(__BIG_ENDIAN) + u16 cid; + u16 reserved3; +#elif defined(__LITTLE_ENDIAN) + u16 reserved3; + u16 cid; +#endif + u32 cmd_sn; + u32 exp_stat_sn; + u32 reserved4; + u32 resp_bd_list_addr_lo; + u32 resp_bd_list_addr_hi; + u32 resp_buffer; +#define ISCSI_LOGIN_REQUEST_RESP_BUFFER_LENGTH (0xFFFFFF<<0) +#define ISCSI_LOGIN_REQUEST_RESP_BUFFER_LENGTH_SHIFT 0 +#define ISCSI_LOGIN_REQUEST_NUM_RESP_BDS (0xFF<<24) +#define ISCSI_LOGIN_REQUEST_NUM_RESP_BDS_SHIFT 24 +#if defined(__BIG_ENDIAN) + u16 reserved8; + u8 reserved7; + u8 flags; +#define ISCSI_LOGIN_REQUEST_RESERVED5 (0x3<<0) +#define ISCSI_LOGIN_REQUEST_RESERVED5_SHIFT 0 +#define ISCSI_LOGIN_REQUEST_UPDATE_EXP_STAT_SN (0x1<<2) +#define ISCSI_LOGIN_REQUEST_UPDATE_EXP_STAT_SN_SHIFT 2 +#define ISCSI_LOGIN_REQUEST_RESERVED6 (0x1F<<3) +#define ISCSI_LOGIN_REQUEST_RESERVED6_SHIFT 3 +#elif defined(__LITTLE_ENDIAN) + u8 flags; +#define ISCSI_LOGIN_REQUEST_RESERVED5 (0x3<<0) +#define ISCSI_LOGIN_REQUEST_RESERVED5_SHIFT 0 +#define ISCSI_LOGIN_REQUEST_UPDATE_EXP_STAT_SN (0x1<<2) +#define ISCSI_LOGIN_REQUEST_UPDATE_EXP_STAT_SN_SHIFT 2 +#define ISCSI_LOGIN_REQUEST_RESERVED6 (0x1F<<3) +#define ISCSI_LOGIN_REQUEST_RESERVED6_SHIFT 3 + u8 reserved7; + u16 reserved8; +#endif + u32 bd_list_addr_lo; + u32 bd_list_addr_hi; +#if defined(__BIG_ENDIAN) + u8 cq_index; + u8 reserved10; + u8 reserved9; + u8 num_bds; +#elif defined(__LITTLE_ENDIAN) + u8 num_bds; + u8 reserved9; + u8 reserved10; + u8 cq_index; +#endif +}; + + +/* + * iSCSI Login CQE + */ +struct bnx2i_login_response { +#if defined(__BIG_ENDIAN) + u8 op_code; + u8 response_flags; +#define ISCSI_LOGIN_RESPONSE_NEXT_STAGE (0x3<<0) +#define ISCSI_LOGIN_RESPONSE_NEXT_STAGE_SHIFT 0 +#define ISCSI_LOGIN_RESPONSE_CURRENT_STAGE (0x3<<2) +#define ISCSI_LOGIN_RESPONSE_CURRENT_STAGE_SHIFT 2 +#define ISCSI_LOGIN_RESPONSE_RESERVED0 (0x3<<4) +#define ISCSI_LOGIN_RESPONSE_RESERVED0_SHIFT 4 +#define ISCSI_LOGIN_RESPONSE_CONT (0x1<<6) +#define ISCSI_LOGIN_RESPONSE_CONT_SHIFT 6 +#define ISCSI_LOGIN_RESPONSE_TRANSIT (0x1<<7) +#define ISCSI_LOGIN_RESPONSE_TRANSIT_SHIFT 7 + u8 version_max; + u8 version_active; +#elif defined(__LITTLE_ENDIAN) + u8 version_active; + u8 version_max; + u8 response_flags; +#define ISCSI_LOGIN_RESPONSE_NEXT_STAGE (0x3<<0) +#define ISCSI_LOGIN_RESPONSE_NEXT_STAGE_SHIFT 0 +#define ISCSI_LOGIN_RESPONSE_CURRENT_STAGE (0x3<<2) +#define ISCSI_LOGIN_RESPONSE_CURRENT_STAGE_SHIFT 2 +#define ISCSI_LOGIN_RESPONSE_RESERVED0 (0x3<<4) +#define ISCSI_LOGIN_RESPONSE_RESERVED0_SHIFT 4 +#define ISCSI_LOGIN_RESPONSE_CONT (0x1<<6) +#define ISCSI_LOGIN_RESPONSE_CONT_SHIFT 6 +#define ISCSI_LOGIN_RESPONSE_TRANSIT (0x1<<7) +#define ISCSI_LOGIN_RESPONSE_TRANSIT_SHIFT 7 + u8 op_code; +#endif + u32 data_length; + u32 exp_cmd_sn; + u32 max_cmd_sn; + u32 reserved1[2]; +#if defined(__BIG_ENDIAN) + u16 reserved3; + u8 err_code; + u8 reserved2; +#elif defined(__LITTLE_ENDIAN) + u8 reserved2; + u8 err_code; + u16 reserved3; +#endif + u32 stat_sn; + u32 isid_lo; +#if defined(__BIG_ENDIAN) + u16 isid_hi; + u16 tsih; +#elif defined(__LITTLE_ENDIAN) + u16 tsih; + u16 isid_hi; +#endif +#if defined(__BIG_ENDIAN) + u8 status_class; + u8 status_detail; + u16 reserved4; +#elif defined(__LITTLE_ENDIAN) + u16 reserved4; + u8 status_detail; + u8 status_class; +#endif + u32 reserved5[3]; +#if defined(__BIG_ENDIAN) + u16 reserved6; + u16 itt; +#define ISCSI_LOGIN_RESPONSE_INDEX (0x3FFF<<0) +#define ISCSI_LOGIN_RESPONSE_INDEX_SHIFT 0 +#define ISCSI_LOGIN_RESPONSE_TYPE (0x3<<14) +#define ISCSI_LOGIN_RESPONSE_TYPE_SHIFT 14 +#elif defined(__LITTLE_ENDIAN) + u16 itt; +#define ISCSI_LOGIN_RESPONSE_INDEX (0x3FFF<<0) +#define ISCSI_LOGIN_RESPONSE_INDEX_SHIFT 0 +#define ISCSI_LOGIN_RESPONSE_TYPE (0x3<<14) +#define ISCSI_LOGIN_RESPONSE_TYPE_SHIFT 14 + u16 reserved6; +#endif + u32 cq_req_sn; +}; + + +/* + * iSCSI Logout SQ WQE + */ +struct bnx2i_logout_request { +#if defined(__BIG_ENDIAN) + u8 op_code; + u8 op_attr; +#define ISCSI_LOGOUT_REQUEST_REASON (0x7F<<0) +#define ISCSI_LOGOUT_REQUEST_REASON_SHIFT 0 +#define ISCSI_LOGOUT_REQUEST_ALWAYS_ONE (0x1<<7) +#define ISCSI_LOGOUT_REQUEST_ALWAYS_ONE_SHIFT 7 + u16 reserved0; +#elif defined(__LITTLE_ENDIAN) + u16 reserved0; + u8 op_attr; +#define ISCSI_LOGOUT_REQUEST_REASON (0x7F<<0) +#define ISCSI_LOGOUT_REQUEST_REASON_SHIFT 0 +#define ISCSI_LOGOUT_REQUEST_ALWAYS_ONE (0x1<<7) +#define ISCSI_LOGOUT_REQUEST_ALWAYS_ONE_SHIFT 7 + u8 op_code; +#endif + u32 data_length; + u32 reserved1[2]; +#if defined(__BIG_ENDIAN) + u16 reserved2; + u16 itt; +#define ISCSI_LOGOUT_REQUEST_INDEX (0x3FFF<<0) +#define ISCSI_LOGOUT_REQUEST_INDEX_SHIFT 0 +#define ISCSI_LOGOUT_REQUEST_TYPE (0x3<<14) +#define ISCSI_LOGOUT_REQUEST_TYPE_SHIFT 14 +#elif defined(__LITTLE_ENDIAN) + u16 itt; +#define ISCSI_LOGOUT_REQUEST_INDEX (0x3FFF<<0) +#define ISCSI_LOGOUT_REQUEST_INDEX_SHIFT 0 +#define ISCSI_LOGOUT_REQUEST_TYPE (0x3<<14) +#define ISCSI_LOGOUT_REQUEST_TYPE_SHIFT 14 + u16 reserved2; +#endif +#if defined(__BIG_ENDIAN) + u16 cid; + u16 reserved3; +#elif defined(__LITTLE_ENDIAN) + u16 reserved3; + u16 cid; +#endif + u32 cmd_sn; + u32 reserved4[5]; + u32 zero_fill; + u32 bd_list_addr_lo; + u32 bd_list_addr_hi; +#if defined(__BIG_ENDIAN) + u8 cq_index; + u8 reserved6; + u8 reserved5; + u8 num_bds; +#elif defined(__LITTLE_ENDIAN) + u8 num_bds; + u8 reserved5; + u8 reserved6; + u8 cq_index; +#endif +}; + + +/* + * iSCSI Logout CQE + */ +struct bnx2i_logout_response { +#if defined(__BIG_ENDIAN) + u8 op_code; + u8 reserved1; + u8 response; + u8 reserved0; +#elif defined(__LITTLE_ENDIAN) + u8 reserved0; + u8 response; + u8 reserved1; + u8 op_code; +#endif + u32 reserved2; + u32 exp_cmd_sn; + u32 max_cmd_sn; + u32 reserved3[2]; +#if defined(__BIG_ENDIAN) + u16 reserved5; + u8 err_code; + u8 reserved4; +#elif defined(__LITTLE_ENDIAN) + u8 reserved4; + u8 err_code; + u16 reserved5; +#endif + u32 reserved6[3]; +#if defined(__BIG_ENDIAN) + u16 time_to_wait; + u16 time_to_retain; +#elif defined(__LITTLE_ENDIAN) + u16 time_to_retain; + u16 time_to_wait; +#endif + u32 reserved7[3]; +#if defined(__BIG_ENDIAN) + u16 reserved8; + u16 itt; +#define ISCSI_LOGOUT_RESPONSE_INDEX (0x3FFF<<0) +#define ISCSI_LOGOUT_RESPONSE_INDEX_SHIFT 0 +#define ISCSI_LOGOUT_RESPONSE_TYPE (0x3<<14) +#define ISCSI_LOGOUT_RESPONSE_TYPE_SHIFT 14 +#elif defined(__LITTLE_ENDIAN) + u16 itt; +#define ISCSI_LOGOUT_RESPONSE_INDEX (0x3FFF<<0) +#define ISCSI_LOGOUT_RESPONSE_INDEX_SHIFT 0 +#define ISCSI_LOGOUT_RESPONSE_TYPE (0x3<<14) +#define ISCSI_LOGOUT_RESPONSE_TYPE_SHIFT 14 + u16 reserved8; +#endif + u32 cq_req_sn; +}; + + +/* + * iSCSI Nop-In CQE + */ +struct bnx2i_nop_in_msg { +#if defined(__BIG_ENDIAN) + u8 op_code; + u8 reserved1; + u16 reserved0; +#elif defined(__LITTLE_ENDIAN) + u16 reserved0; + u8 reserved1; + u8 op_code; +#endif + u32 data_length; + u32 exp_cmd_sn; + u32 max_cmd_sn; + u32 ttt; + u32 reserved2; +#if defined(__BIG_ENDIAN) + u16 reserved4; + u8 err_code; + u8 reserved3; +#elif defined(__LITTLE_ENDIAN) + u8 reserved3; + u8 err_code; + u16 reserved4; +#endif + u32 reserved5; + u32 lun[2]; + u32 reserved6[4]; +#if defined(__BIG_ENDIAN) + u16 reserved7; + u16 itt; +#define ISCSI_NOP_IN_MSG_INDEX (0x3FFF<<0) +#define ISCSI_NOP_IN_MSG_INDEX_SHIFT 0 +#define ISCSI_NOP_IN_MSG_TYPE (0x3<<14) +#define ISCSI_NOP_IN_MSG_TYPE_SHIFT 14 +#elif defined(__LITTLE_ENDIAN) + u16 itt; +#define ISCSI_NOP_IN_MSG_INDEX (0x3FFF<<0) +#define ISCSI_NOP_IN_MSG_INDEX_SHIFT 0 +#define ISCSI_NOP_IN_MSG_TYPE (0x3<<14) +#define ISCSI_NOP_IN_MSG_TYPE_SHIFT 14 + u16 reserved7; +#endif + u32 cq_req_sn; +}; + + +/* + * iSCSI NOP-OUT SQ WQE + */ +struct bnx2i_nop_out_request { +#if defined(__BIG_ENDIAN) + u8 op_code; + u8 op_attr; +#define ISCSI_NOP_OUT_REQUEST_RESERVED1 (0x7F<<0) +#define ISCSI_NOP_OUT_REQUEST_RESERVED1_SHIFT 0 +#define ISCSI_NOP_OUT_REQUEST_ALWAYS_ONE (0x1<<7) +#define ISCSI_NOP_OUT_REQUEST_ALWAYS_ONE_SHIFT 7 + u16 reserved0; +#elif defined(__LITTLE_ENDIAN) + u16 reserved0; + u8 op_attr; +#define ISCSI_NOP_OUT_REQUEST_RESERVED1 (0x7F<<0) +#define ISCSI_NOP_OUT_REQUEST_RESERVED1_SHIFT 0 +#define ISCSI_NOP_OUT_REQUEST_ALWAYS_ONE (0x1<<7) +#define ISCSI_NOP_OUT_REQUEST_ALWAYS_ONE_SHIFT 7 + u8 op_code; +#endif + u32 data_length; + u32 lun[2]; +#if defined(__BIG_ENDIAN) + u16 reserved2; + u16 itt; +#define ISCSI_NOP_OUT_REQUEST_INDEX (0x3FFF<<0) +#define ISCSI_NOP_OUT_REQUEST_INDEX_SHIFT 0 +#define ISCSI_NOP_OUT_REQUEST_TYPE (0x3<<14) +#define ISCSI_NOP_OUT_REQUEST_TYPE_SHIFT 14 +#elif defined(__LITTLE_ENDIAN) + u16 itt; +#define ISCSI_NOP_OUT_REQUEST_INDEX (0x3FFF<<0) +#define ISCSI_NOP_OUT_REQUEST_INDEX_SHIFT 0 +#define ISCSI_NOP_OUT_REQUEST_TYPE (0x3<<14) +#define ISCSI_NOP_OUT_REQUEST_TYPE_SHIFT 14 + u16 reserved2; +#endif + u32 ttt; + u32 cmd_sn; + u32 reserved3[2]; + u32 resp_bd_list_addr_lo; + u32 resp_bd_list_addr_hi; + u32 resp_buffer; +#define ISCSI_NOP_OUT_REQUEST_RESP_BUFFER_LENGTH (0xFFFFFF<<0) +#define ISCSI_NOP_OUT_REQUEST_RESP_BUFFER_LENGTH_SHIFT 0 +#define ISCSI_NOP_OUT_REQUEST_NUM_RESP_BDS (0xFF<<24) +#define ISCSI_NOP_OUT_REQUEST_NUM_RESP_BDS_SHIFT 24 +#if defined(__BIG_ENDIAN) + u16 reserved7; + u8 reserved6; + u8 flags; +#define ISCSI_NOP_OUT_REQUEST_RESERVED4 (0x1<<0) +#define ISCSI_NOP_OUT_REQUEST_RESERVED4_SHIFT 0 +#define ISCSI_NOP_OUT_REQUEST_LOCAL_COMPLETION (0x1<<1) +#define ISCSI_NOP_OUT_REQUEST_LOCAL_COMPLETION_SHIFT 1 +#define ISCSI_NOP_OUT_REQUEST_ZERO_FILL (0x3F<<2) +#define ISCSI_NOP_OUT_REQUEST_ZERO_FILL_SHIFT 2 +#elif defined(__LITTLE_ENDIAN) + u8 flags; +#define ISCSI_NOP_OUT_REQUEST_RESERVED4 (0x1<<0) +#define ISCSI_NOP_OUT_REQUEST_RESERVED4_SHIFT 0 +#define ISCSI_NOP_OUT_REQUEST_LOCAL_COMPLETION (0x1<<1) +#define ISCSI_NOP_OUT_REQUEST_LOCAL_COMPLETION_SHIFT 1 +#define ISCSI_NOP_OUT_REQUEST_ZERO_FILL (0x3F<<2) +#define ISCSI_NOP_OUT_REQUEST_ZERO_FILL_SHIFT 2 + u8 reserved6; + u16 reserved7; +#endif + u32 bd_list_addr_lo; + u32 bd_list_addr_hi; +#if defined(__BIG_ENDIAN) + u8 cq_index; + u8 reserved9; + u8 reserved8; + u8 num_bds; +#elif defined(__LITTLE_ENDIAN) + u8 num_bds; + u8 reserved8; + u8 reserved9; + u8 cq_index; +#endif +}; + +/* + * iSCSI Reject CQE + */ +struct bnx2i_reject_msg { +#if defined(__BIG_ENDIAN) + u8 op_code; + u8 reserved1; + u8 reason; + u8 reserved0; +#elif defined(__LITTLE_ENDIAN) + u8 reserved0; + u8 reason; + u8 reserved1; + u8 op_code; +#endif + u32 data_length; + u32 exp_cmd_sn; + u32 max_cmd_sn; + u32 reserved2[2]; +#if defined(__BIG_ENDIAN) + u16 reserved4; + u8 err_code; + u8 reserved3; +#elif defined(__LITTLE_ENDIAN) + u8 reserved3; + u8 err_code; + u16 reserved4; +#endif + u32 reserved5[8]; + u32 cq_req_sn; +}; + +/* + * bnx2i iSCSI TMF SQ WQE + */ +struct bnx2i_tmf_request { +#if defined(__BIG_ENDIAN) + u8 op_code; + u8 op_attr; +#define ISCSI_TMF_REQUEST_FUNCTION (0x7F<<0) +#define ISCSI_TMF_REQUEST_FUNCTION_SHIFT 0 +#define ISCSI_TMF_REQUEST_ALWAYS_ONE (0x1<<7) +#define ISCSI_TMF_REQUEST_ALWAYS_ONE_SHIFT 7 + u16 reserved0; +#elif defined(__LITTLE_ENDIAN) + u16 reserved0; + u8 op_attr; +#define ISCSI_TMF_REQUEST_FUNCTION (0x7F<<0) +#define ISCSI_TMF_REQUEST_FUNCTION_SHIFT 0 +#define ISCSI_TMF_REQUEST_ALWAYS_ONE (0x1<<7) +#define ISCSI_TMF_REQUEST_ALWAYS_ONE_SHIFT 7 + u8 op_code; +#endif + u32 data_length; + u32 lun[2]; +#if defined(__BIG_ENDIAN) + u16 reserved1; + u16 itt; +#define ISCSI_TMF_REQUEST_INDEX (0x3FFF<<0) +#define ISCSI_TMF_REQUEST_INDEX_SHIFT 0 +#define ISCSI_TMF_REQUEST_TYPE (0x3<<14) +#define ISCSI_TMF_REQUEST_TYPE_SHIFT 14 +#elif defined(__LITTLE_ENDIAN) + u16 itt; +#define ISCSI_TMF_REQUEST_INDEX (0x3FFF<<0) +#define ISCSI_TMF_REQUEST_INDEX_SHIFT 0 +#define ISCSI_TMF_REQUEST_TYPE (0x3<<14) +#define ISCSI_TMF_REQUEST_TYPE_SHIFT 14 + u16 reserved1; +#endif + u32 ref_itt; + u32 cmd_sn; + u32 reserved2; + u32 ref_cmd_sn; + u32 reserved3[3]; + u32 zero_fill; + u32 bd_list_addr_lo; + u32 bd_list_addr_hi; +#if defined(__BIG_ENDIAN) + u8 cq_index; + u8 reserved5; + u8 reserved4; + u8 num_bds; +#elif defined(__LITTLE_ENDIAN) + u8 num_bds; + u8 reserved4; + u8 reserved5; + u8 cq_index; +#endif +}; + +/* + * iSCSI Text SQ WQE + */ +struct bnx2i_text_request { +#if defined(__BIG_ENDIAN) + u8 op_code; + u8 op_attr; +#define ISCSI_TEXT_REQUEST_RESERVED1 (0x3F<<0) +#define ISCSI_TEXT_REQUEST_RESERVED1_SHIFT 0 +#define ISCSI_TEXT_REQUEST_CONT (0x1<<6) +#define ISCSI_TEXT_REQUEST_CONT_SHIFT 6 +#define ISCSI_TEXT_REQUEST_FINAL (0x1<<7) +#define ISCSI_TEXT_REQUEST_FINAL_SHIFT 7 + u16 reserved0; +#elif defined(__LITTLE_ENDIAN) + u16 reserved0; + u8 op_attr; +#define ISCSI_TEXT_REQUEST_RESERVED1 (0x3F<<0) +#define ISCSI_TEXT_REQUEST_RESERVED1_SHIFT 0 +#define ISCSI_TEXT_REQUEST_CONT (0x1<<6) +#define ISCSI_TEXT_REQUEST_CONT_SHIFT 6 +#define ISCSI_TEXT_REQUEST_FINAL (0x1<<7) +#define ISCSI_TEXT_REQUEST_FINAL_SHIFT 7 + u8 op_code; +#endif + u32 data_length; + u32 lun[2]; +#if defined(__BIG_ENDIAN) + u16 reserved3; + u16 itt; +#define ISCSI_TEXT_REQUEST_INDEX (0x3FFF<<0) +#define ISCSI_TEXT_REQUEST_INDEX_SHIFT 0 +#define ISCSI_TEXT_REQUEST_TYPE (0x3<<14) +#define ISCSI_TEXT_REQUEST_TYPE_SHIFT 14 +#elif defined(__LITTLE_ENDIAN) + u16 itt; +#define ISCSI_TEXT_REQUEST_INDEX (0x3FFF<<0) +#define ISCSI_TEXT_REQUEST_INDEX_SHIFT 0 +#define ISCSI_TEXT_REQUEST_TYPE (0x3<<14) +#define ISCSI_TEXT_REQUEST_TYPE_SHIFT 14 + u16 reserved3; +#endif + u32 ttt; + u32 cmd_sn; + u32 reserved4[2]; + u32 resp_bd_list_addr_lo; + u32 resp_bd_list_addr_hi; + u32 resp_buffer; +#define ISCSI_TEXT_REQUEST_RESP_BUFFER_LENGTH (0xFFFFFF<<0) +#define ISCSI_TEXT_REQUEST_RESP_BUFFER_LENGTH_SHIFT 0 +#define ISCSI_TEXT_REQUEST_NUM_RESP_BDS (0xFF<<24) +#define ISCSI_TEXT_REQUEST_NUM_RESP_BDS_SHIFT 24 + u32 zero_fill; + u32 bd_list_addr_lo; + u32 bd_list_addr_hi; +#if defined(__BIG_ENDIAN) + u8 cq_index; + u8 reserved7; + u8 reserved6; + u8 num_bds; +#elif defined(__LITTLE_ENDIAN) + u8 num_bds; + u8 reserved6; + u8 reserved7; + u8 cq_index; +#endif +}; + +/* + * iSCSI SQ WQE + */ +union iscsi_request { + struct bnx2i_cmd_request cmd; + struct bnx2i_tmf_request tmf; + struct bnx2i_nop_out_request nop_out; + struct bnx2i_login_request login_req; + struct bnx2i_text_request text; + struct bnx2i_logout_request logout_req; + struct bnx2i_cleanup_request cleanup; +}; + + +/* + * iSCSI TMF CQE + */ +struct bnx2i_tmf_response { +#if defined(__BIG_ENDIAN) + u8 op_code; + u8 reserved1; + u8 response; + u8 reserved0; +#elif defined(__LITTLE_ENDIAN) + u8 reserved0; + u8 response; + u8 reserved1; + u8 op_code; +#endif + u32 reserved2; + u32 exp_cmd_sn; + u32 max_cmd_sn; + u32 reserved3[2]; +#if defined(__BIG_ENDIAN) + u16 reserved5; + u8 err_code; + u8 reserved4; +#elif defined(__LITTLE_ENDIAN) + u8 reserved4; + u8 err_code; + u16 reserved5; +#endif + u32 reserved6[7]; +#if defined(__BIG_ENDIAN) + u16 reserved7; + u16 itt; +#define ISCSI_TMF_RESPONSE_INDEX (0x3FFF<<0) +#define ISCSI_TMF_RESPONSE_INDEX_SHIFT 0 +#define ISCSI_TMF_RESPONSE_TYPE (0x3<<14) +#define ISCSI_TMF_RESPONSE_TYPE_SHIFT 14 +#elif defined(__LITTLE_ENDIAN) + u16 itt; +#define ISCSI_TMF_RESPONSE_INDEX (0x3FFF<<0) +#define ISCSI_TMF_RESPONSE_INDEX_SHIFT 0 +#define ISCSI_TMF_RESPONSE_TYPE (0x3<<14) +#define ISCSI_TMF_RESPONSE_TYPE_SHIFT 14 + u16 reserved7; +#endif + u32 cq_req_sn; +}; + +/* + * iSCSI Text CQE + */ +struct bnx2i_text_response { +#if defined(__BIG_ENDIAN) + u8 op_code; + u8 response_flags; +#define ISCSI_TEXT_RESPONSE_RESERVED1 (0x3F<<0) +#define ISCSI_TEXT_RESPONSE_RESERVED1_SHIFT 0 +#define ISCSI_TEXT_RESPONSE_CONT (0x1<<6) +#define ISCSI_TEXT_RESPONSE_CONT_SHIFT 6 +#define ISCSI_TEXT_RESPONSE_FINAL (0x1<<7) +#define ISCSI_TEXT_RESPONSE_FINAL_SHIFT 7 + u16 reserved0; +#elif defined(__LITTLE_ENDIAN) + u16 reserved0; + u8 response_flags; +#define ISCSI_TEXT_RESPONSE_RESERVED1 (0x3F<<0) +#define ISCSI_TEXT_RESPONSE_RESERVED1_SHIFT 0 +#define ISCSI_TEXT_RESPONSE_CONT (0x1<<6) +#define ISCSI_TEXT_RESPONSE_CONT_SHIFT 6 +#define ISCSI_TEXT_RESPONSE_FINAL (0x1<<7) +#define ISCSI_TEXT_RESPONSE_FINAL_SHIFT 7 + u8 op_code; +#endif + u32 data_length; + u32 exp_cmd_sn; + u32 max_cmd_sn; + u32 ttt; + u32 reserved2; +#if defined(__BIG_ENDIAN) + u16 reserved4; + u8 err_code; + u8 reserved3; +#elif defined(__LITTLE_ENDIAN) + u8 reserved3; + u8 err_code; + u16 reserved4; +#endif + u32 reserved5; + u32 lun[2]; + u32 reserved6[4]; +#if defined(__BIG_ENDIAN) + u16 reserved7; + u16 itt; +#define ISCSI_TEXT_RESPONSE_INDEX (0x3FFF<<0) +#define ISCSI_TEXT_RESPONSE_INDEX_SHIFT 0 +#define ISCSI_TEXT_RESPONSE_TYPE (0x3<<14) +#define ISCSI_TEXT_RESPONSE_TYPE_SHIFT 14 +#elif defined(__LITTLE_ENDIAN) + u16 itt; +#define ISCSI_TEXT_RESPONSE_INDEX (0x3FFF<<0) +#define ISCSI_TEXT_RESPONSE_INDEX_SHIFT 0 +#define ISCSI_TEXT_RESPONSE_TYPE (0x3<<14) +#define ISCSI_TEXT_RESPONSE_TYPE_SHIFT 14 + u16 reserved7; +#endif + u32 cq_req_sn; +}; + +/* + * iSCSI CQE + */ +union iscsi_response { + struct bnx2i_cmd_response cmd; + struct bnx2i_tmf_response tmf; + struct bnx2i_login_response login_resp; + struct bnx2i_text_response text; + struct bnx2i_logout_response logout_resp; + struct bnx2i_cleanup_response cleanup; + struct bnx2i_reject_msg reject; + struct bnx2i_async_msg async; + struct bnx2i_nop_in_msg nop_in; +}; + +#endif /* __57XX_ISCSI_HSI_LINUX_LE__ */ diff --git a/drivers/scsi/bnx2i/Kconfig b/drivers/scsi/bnx2i/Kconfig new file mode 100644 index 000000000000..1e9f7141102b --- /dev/null +++ b/drivers/scsi/bnx2i/Kconfig @@ -0,0 +1,10 @@ +config SCSI_BNX2_ISCSI + tristate "Broadcom NetXtreme II iSCSI support" + select SCSI_ISCSI_ATTRS + select NETDEVICES + select NETDEV_1000 + select CNIC + depends on PCI + ---help--- + This driver supports iSCSI offload for the Broadcom NetXtreme II + devices. diff --git a/drivers/scsi/bnx2i/Makefile b/drivers/scsi/bnx2i/Makefile new file mode 100644 index 000000000000..b5802bd2e76a --- /dev/null +++ b/drivers/scsi/bnx2i/Makefile @@ -0,0 +1,3 @@ +bnx2i-y := bnx2i_init.o bnx2i_hwi.o bnx2i_iscsi.o bnx2i_sysfs.o + +obj-$(CONFIG_SCSI_BNX2_ISCSI) += bnx2i.o diff --git a/drivers/scsi/bnx2i/bnx2i.h b/drivers/scsi/bnx2i/bnx2i.h new file mode 100644 index 000000000000..d7576f28c6e9 --- /dev/null +++ b/drivers/scsi/bnx2i/bnx2i.h @@ -0,0 +1,771 @@ +/* bnx2i.h: Broadcom NetXtreme II iSCSI driver. + * + * Copyright (c) 2006 - 2009 Broadcom Corporation + * Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved. + * Copyright (c) 2007, 2008 Mike Christie + * + * 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. + * + * Written by: Anil Veerabhadrappa (anilgv@broadcom.com) + */ + +#ifndef _BNX2I_H_ +#define _BNX2I_H_ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../../net/cnic_if.h" +#include "57xx_iscsi_hsi.h" +#include "57xx_iscsi_constants.h" + +#define BNX2_ISCSI_DRIVER_NAME "bnx2i" + +#define BNX2I_MAX_ADAPTERS 8 + +#define ISCSI_MAX_CONNS_PER_HBA 128 +#define ISCSI_MAX_SESS_PER_HBA ISCSI_MAX_CONNS_PER_HBA +#define ISCSI_MAX_CMDS_PER_SESS 128 + +/* Total active commands across all connections supported by devices */ +#define ISCSI_MAX_CMDS_PER_HBA_5708 (28 * (ISCSI_MAX_CMDS_PER_SESS - 1)) +#define ISCSI_MAX_CMDS_PER_HBA_5709 (128 * (ISCSI_MAX_CMDS_PER_SESS - 1)) +#define ISCSI_MAX_CMDS_PER_HBA_57710 (256 * (ISCSI_MAX_CMDS_PER_SESS - 1)) + +#define ISCSI_MAX_BDS_PER_CMD 32 + +#define MAX_PAGES_PER_CTRL_STRUCT_POOL 8 +#define BNX2I_RESERVED_SLOW_PATH_CMD_SLOTS 4 + +/* 5706/08 hardware has limit on maximum buffer size per BD it can handle */ +#define MAX_BD_LENGTH 65535 +#define BD_SPLIT_SIZE 32768 + +/* min, max & default values for SQ/RQ/CQ size, configurable via' modparam */ +#define BNX2I_SQ_WQES_MIN 16 +#define BNX2I_570X_SQ_WQES_MAX 128 +#define BNX2I_5770X_SQ_WQES_MAX 512 +#define BNX2I_570X_SQ_WQES_DEFAULT 128 +#define BNX2I_5770X_SQ_WQES_DEFAULT 256 + +#define BNX2I_570X_CQ_WQES_MAX 128 +#define BNX2I_5770X_CQ_WQES_MAX 512 + +#define BNX2I_RQ_WQES_MIN 16 +#define BNX2I_RQ_WQES_MAX 32 +#define BNX2I_RQ_WQES_DEFAULT 16 + +/* CCELLs per conn */ +#define BNX2I_CCELLS_MIN 16 +#define BNX2I_CCELLS_MAX 96 +#define BNX2I_CCELLS_DEFAULT 64 + +#define ITT_INVALID_SIGNATURE 0xFFFF + +#define ISCSI_CMD_CLEANUP_TIMEOUT 100 + +#define BNX2I_CONN_CTX_BUF_SIZE 16384 + +#define BNX2I_SQ_WQE_SIZE 64 +#define BNX2I_RQ_WQE_SIZE 256 +#define BNX2I_CQE_SIZE 64 + +#define MB_KERNEL_CTX_SHIFT 8 +#define MB_KERNEL_CTX_SIZE (1 << MB_KERNEL_CTX_SHIFT) + +#define CTX_SHIFT 7 +#define GET_CID_NUM(cid_addr) ((cid_addr) >> CTX_SHIFT) + +#define CTX_OFFSET 0x10000 +#define MAX_CID_CNT 0x4000 + +/* 5709 context registers */ +#define BNX2_MQ_CONFIG2 0x00003d00 +#define BNX2_MQ_CONFIG2_CONT_SZ (0x7L<<4) +#define BNX2_MQ_CONFIG2_FIRST_L4L5 (0x1fL<<8) + +/* 57710's BAR2 is mapped to doorbell registers */ +#define BNX2X_DOORBELL_PCI_BAR 2 +#define BNX2X_MAX_CQS 8 + +#define CNIC_ARM_CQE 1 +#define CNIC_DISARM_CQE 0 + +#define REG_RD(__hba, offset) \ + readl(__hba->regview + offset) +#define REG_WR(__hba, offset, val) \ + writel(val, __hba->regview + offset) + + +/** + * struct generic_pdu_resc - login pdu resource structure + * + * @req_buf: driver buffer used to stage payload associated with + * the login request + * @req_dma_addr: dma address for iscsi login request payload buffer + * @req_buf_size: actual login request payload length + * @req_wr_ptr: pointer into login request buffer when next data is + * to be written + * @resp_hdr: iscsi header where iscsi login response header is to + * be recreated + * @resp_buf: buffer to stage login response payload + * @resp_dma_addr: login response payload buffer dma address + * @resp_buf_size: login response paylod length + * @resp_wr_ptr: pointer into login response buffer when next data is + * to be written + * @req_bd_tbl: iscsi login request payload BD table + * @req_bd_dma: login request BD table dma address + * @resp_bd_tbl: iscsi login response payload BD table + * @resp_bd_dma: login request BD table dma address + * + * following structure defines buffer info for generic pdus such as iSCSI Login, + * Logout and NOP + */ +struct generic_pdu_resc { + char *req_buf; + dma_addr_t req_dma_addr; + u32 req_buf_size; + char *req_wr_ptr; + struct iscsi_hdr resp_hdr; + char *resp_buf; + dma_addr_t resp_dma_addr; + u32 resp_buf_size; + char *resp_wr_ptr; + char *req_bd_tbl; + dma_addr_t req_bd_dma; + char *resp_bd_tbl; + dma_addr_t resp_bd_dma; +}; + + +/** + * struct bd_resc_page - tracks DMA'able memory allocated for BD tables + * + * @link: list head to link elements + * @max_ptrs: maximun pointers that can be stored in this page + * @num_valid: number of pointer valid in this page + * @page: base addess for page pointer array + * + * structure to track DMA'able memory allocated for command BD tables + */ +struct bd_resc_page { + struct list_head link; + u32 max_ptrs; + u32 num_valid; + void *page[1]; +}; + + +/** + * struct io_bdt - I/O buffer destricptor table + * + * @bd_tbl: BD table's virtual address + * @bd_tbl_dma: BD table's dma address + * @bd_valid: num valid BD entries + * + * IO BD table + */ +struct io_bdt { + struct iscsi_bd *bd_tbl; + dma_addr_t bd_tbl_dma; + u16 bd_valid; +}; + + +/** + * bnx2i_cmd - iscsi command structure + * + * @scsi_cmd: SCSI-ML task pointer corresponding to this iscsi cmd + * @sg: SG list + * @io_tbl: buffer descriptor (BD) table + * @bd_tbl_dma: buffer descriptor (BD) table's dma address + */ +struct bnx2i_cmd { + struct iscsi_hdr hdr; + struct bnx2i_conn *conn; + struct scsi_cmnd *scsi_cmd; + struct scatterlist *sg; + struct io_bdt io_tbl; + dma_addr_t bd_tbl_dma; + struct bnx2i_cmd_request req; +}; + + +/** + * struct bnx2i_conn - iscsi connection structure + * + * @cls_conn: pointer to iscsi cls conn + * @hba: adapter structure pointer + * @iscsi_conn_cid: iscsi conn id + * @fw_cid: firmware iscsi context id + * @ep: endpoint structure pointer + * @gen_pdu: login/nopout/logout pdu resources + * @violation_notified: bit mask used to track iscsi error/warning messages + * already printed out + * + * iSCSI connection structure + */ +struct bnx2i_conn { + struct iscsi_cls_conn *cls_conn; + struct bnx2i_hba *hba; + struct completion cmd_cleanup_cmpl; + int is_bound; + + u32 iscsi_conn_cid; +#define BNX2I_CID_RESERVED 0x5AFF + u32 fw_cid; + + struct timer_list poll_timer; + /* + * Queue Pair (QP) related structure elements. + */ + struct bnx2i_endpoint *ep; + + /* + * Buffer for login negotiation process + */ + struct generic_pdu_resc gen_pdu; + u64 violation_notified; +}; + + + +/** + * struct iscsi_cid_queue - Per adapter iscsi cid queue + * + * @cid_que_base: queue base memory + * @cid_que: queue memory pointer + * @cid_q_prod_idx: produce index + * @cid_q_cons_idx: consumer index + * @cid_q_max_idx: max index. used to detect wrap around condition + * @cid_free_cnt: queue size + * @conn_cid_tbl: iscsi cid to conn structure mapping table + * + * Per adapter iSCSI CID Queue + */ +struct iscsi_cid_queue { + void *cid_que_base; + u32 *cid_que; + u32 cid_q_prod_idx; + u32 cid_q_cons_idx; + u32 cid_q_max_idx; + u32 cid_free_cnt; + struct bnx2i_conn **conn_cid_tbl; +}; + +/** + * struct bnx2i_hba - bnx2i adapter structure + * + * @link: list head to link elements + * @cnic: pointer to cnic device + * @pcidev: pointer to pci dev + * @netdev: pointer to netdev structure + * @regview: mapped PCI register space + * @age: age, incremented by every recovery + * @cnic_dev_type: cnic device type, 5706/5708/5709/57710 + * @mail_queue_access: mailbox queue access mode, applicable to 5709 only + * @reg_with_cnic: indicates whether the device is register with CNIC + * @adapter_state: adapter state, UP, GOING_DOWN, LINK_DOWN + * @mtu_supported: Ethernet MTU supported + * @shost: scsi host pointer + * @max_sqes: SQ size + * @max_rqes: RQ size + * @max_cqes: CQ size + * @num_ccell: number of command cells per connection + * @ofld_conns_active: active connection list + * @max_active_conns: max offload connections supported by this device + * @cid_que: iscsi cid queue + * @ep_rdwr_lock: read / write lock to synchronize various ep lists + * @ep_ofld_list: connection list for pending offload completion + * @ep_destroy_list: connection list for pending offload completion + * @mp_bd_tbl: BD table to be used with middle path requests + * @mp_bd_dma: DMA address of 'mp_bd_tbl' memory buffer + * @dummy_buffer: Dummy buffer to be used with zero length scsicmd reqs + * @dummy_buf_dma: DMA address of 'dummy_buffer' memory buffer + * @lock: lock to synchonize access to hba structure + * @pci_did: PCI device ID + * @pci_vid: PCI vendor ID + * @pci_sdid: PCI subsystem device ID + * @pci_svid: PCI subsystem vendor ID + * @pci_func: PCI function number in system pci tree + * @pci_devno: PCI device number in system pci tree + * @num_wqe_sent: statistic counter, total wqe's sent + * @num_cqe_rcvd: statistic counter, total cqe's received + * @num_intr_claimed: statistic counter, total interrupts claimed + * @link_changed_count: statistic counter, num of link change notifications + * received + * @ipaddr_changed_count: statistic counter, num times IP address changed while + * at least one connection is offloaded + * @num_sess_opened: statistic counter, total num sessions opened + * @num_conn_opened: statistic counter, total num conns opened on this hba + * @ctx_ccell_tasks: captures number of ccells and tasks supported by + * currently offloaded connection, used to decode + * context memory + * + * Adapter Data Structure + */ +struct bnx2i_hba { + struct list_head link; + struct cnic_dev *cnic; + struct pci_dev *pcidev; + struct net_device *netdev; + void __iomem *regview; + + u32 age; + unsigned long cnic_dev_type; + #define BNX2I_NX2_DEV_5706 0x0 + #define BNX2I_NX2_DEV_5708 0x1 + #define BNX2I_NX2_DEV_5709 0x2 + #define BNX2I_NX2_DEV_57710 0x3 + u32 mail_queue_access; + #define BNX2I_MQ_KERNEL_MODE 0x0 + #define BNX2I_MQ_KERNEL_BYPASS_MODE 0x1 + #define BNX2I_MQ_BIN_MODE 0x2 + unsigned long reg_with_cnic; + #define BNX2I_CNIC_REGISTERED 1 + + unsigned long adapter_state; + #define ADAPTER_STATE_UP 0 + #define ADAPTER_STATE_GOING_DOWN 1 + #define ADAPTER_STATE_LINK_DOWN 2 + #define ADAPTER_STATE_INIT_FAILED 31 + unsigned int mtu_supported; + #define BNX2I_MAX_MTU_SUPPORTED 1500 + + struct Scsi_Host *shost; + + u32 max_sqes; + u32 max_rqes; + u32 max_cqes; + u32 num_ccell; + + int ofld_conns_active; + + int max_active_conns; + struct iscsi_cid_queue cid_que; + + rwlock_t ep_rdwr_lock; + struct list_head ep_ofld_list; + struct list_head ep_destroy_list; + + /* + * BD table to be used with MP (Middle Path requests. + */ + char *mp_bd_tbl; + dma_addr_t mp_bd_dma; + char *dummy_buffer; + dma_addr_t dummy_buf_dma; + + spinlock_t lock; /* protects hba structure access */ + struct mutex net_dev_lock;/* sync net device access */ + + /* + * PCI related info. + */ + u16 pci_did; + u16 pci_vid; + u16 pci_sdid; + u16 pci_svid; + u16 pci_func; + u16 pci_devno; + + /* + * Following are a bunch of statistics useful during development + * and later stage for score boarding. + */ + u32 num_wqe_sent; + u32 num_cqe_rcvd; + u32 num_intr_claimed; + u32 link_changed_count; + u32 ipaddr_changed_count; + u32 num_sess_opened; + u32 num_conn_opened; + unsigned int ctx_ccell_tasks; +}; + + +/******************************************************************************* + * QP [ SQ / RQ / CQ ] info. + ******************************************************************************/ + +/* + * SQ/RQ/CQ generic structure definition + */ +struct sqe { + u8 sqe_byte[BNX2I_SQ_WQE_SIZE]; +}; + +struct rqe { + u8 rqe_byte[BNX2I_RQ_WQE_SIZE]; +}; + +struct cqe { + u8 cqe_byte[BNX2I_CQE_SIZE]; +}; + + +enum { +#if defined(__LITTLE_ENDIAN) + CNIC_EVENT_COAL_INDEX = 0x0, + CNIC_SEND_DOORBELL = 0x4, + CNIC_EVENT_CQ_ARM = 0x7, + CNIC_RECV_DOORBELL = 0x8 +#elif defined(__BIG_ENDIAN) + CNIC_EVENT_COAL_INDEX = 0x2, + CNIC_SEND_DOORBELL = 0x6, + CNIC_EVENT_CQ_ARM = 0x4, + CNIC_RECV_DOORBELL = 0xa +#endif +}; + + +/* + * CQ DB + */ +struct bnx2x_iscsi_cq_pend_cmpl { + /* CQ producer, updated by Ustorm */ + u16 ustrom_prod; + /* CQ pending completion counter */ + u16 pend_cntr; +}; + + +struct bnx2i_5771x_cq_db { + struct bnx2x_iscsi_cq_pend_cmpl qp_pend_cmpl[BNX2X_MAX_CQS]; + /* CQ pending completion ITT array */ + u16 itt[BNX2X_MAX_CQS]; + /* Cstorm CQ sequence to notify array, updated by driver */; + u16 sqn[BNX2X_MAX_CQS]; + u32 reserved[4] /* 16 byte allignment */; +}; + + +struct bnx2i_5771x_sq_rq_db { + u16 prod_idx; + u8 reserved0[14]; /* Pad structure size to 16 bytes */ +}; + + +struct bnx2i_5771x_dbell_hdr { + u8 header; + /* 1 for rx doorbell, 0 for tx doorbell */ +#define B577XX_DOORBELL_HDR_RX (0x1<<0) +#define B577XX_DOORBELL_HDR_RX_SHIFT 0 + /* 0 for normal doorbell, 1 for advertise wnd doorbell */ +#define B577XX_DOORBELL_HDR_DB_TYPE (0x1<<1) +#define B577XX_DOORBELL_HDR_DB_TYPE_SHIFT 1 + /* rdma tx only: DPM transaction size specifier (64/128/256/512B) */ +#define B577XX_DOORBELL_HDR_DPM_SIZE (0x3<<2) +#define B577XX_DOORBELL_HDR_DPM_SIZE_SHIFT 2 + /* connection type */ +#define B577XX_DOORBELL_HDR_CONN_TYPE (0xF<<4) +#define B577XX_DOORBELL_HDR_CONN_TYPE_SHIFT 4 +}; + +struct bnx2i_5771x_dbell { + struct bnx2i_5771x_dbell_hdr dbell; + u8 pad[3]; + +}; + +/** + * struct qp_info - QP (share queue region) atrributes structure + * + * @ctx_base: ioremapped pci register base to access doorbell register + * pertaining to this offloaded connection + * @sq_virt: virtual address of send queue (SQ) region + * @sq_phys: DMA address of SQ memory region + * @sq_mem_size: SQ size + * @sq_prod_qe: SQ producer entry pointer + * @sq_cons_qe: SQ consumer entry pointer + * @sq_first_qe: virtaul address of first entry in SQ + * @sq_last_qe: virtaul address of last entry in SQ + * @sq_prod_idx: SQ producer index + * @sq_cons_idx: SQ consumer index + * @sqe_left: number sq entry left + * @sq_pgtbl_virt: page table describing buffer consituting SQ region + * @sq_pgtbl_phys: dma address of 'sq_pgtbl_virt' + * @sq_pgtbl_size: SQ page table size + * @cq_virt: virtual address of completion queue (CQ) region + * @cq_phys: DMA address of RQ memory region + * @cq_mem_size: CQ size + * @cq_prod_qe: CQ producer entry pointer + * @cq_cons_qe: CQ consumer entry pointer + * @cq_first_qe: virtaul address of first entry in CQ + * @cq_last_qe: virtaul address of last entry in CQ + * @cq_prod_idx: CQ producer index + * @cq_cons_idx: CQ consumer index + * @cqe_left: number cq entry left + * @cqe_size: size of each CQ entry + * @cqe_exp_seq_sn: next expected CQE sequence number + * @cq_pgtbl_virt: page table describing buffer consituting CQ region + * @cq_pgtbl_phys: dma address of 'cq_pgtbl_virt' + * @cq_pgtbl_size: CQ page table size + * @rq_virt: virtual address of receive queue (RQ) region + * @rq_phys: DMA address of RQ memory region + * @rq_mem_size: RQ size + * @rq_prod_qe: RQ producer entry pointer + * @rq_cons_qe: RQ consumer entry pointer + * @rq_first_qe: virtaul address of first entry in RQ + * @rq_last_qe: virtaul address of last entry in RQ + * @rq_prod_idx: RQ producer index + * @rq_cons_idx: RQ consumer index + * @rqe_left: number rq entry left + * @rq_pgtbl_virt: page table describing buffer consituting RQ region + * @rq_pgtbl_phys: dma address of 'rq_pgtbl_virt' + * @rq_pgtbl_size: RQ page table size + * + * queue pair (QP) is a per connection shared data structure which is used + * to send work requests (SQ), receive completion notifications (CQ) + * and receive asynchoronous / scsi sense info (RQ). 'qp_info' structure + * below holds queue memory, consumer/producer indexes and page table + * information + */ +struct qp_info { + void __iomem *ctx_base; +#define DPM_TRIGER_TYPE 0x40 + +#define BNX2I_570x_QUE_DB_SIZE 0 +#define BNX2I_5771x_QUE_DB_SIZE 16 + struct sqe *sq_virt; + dma_addr_t sq_phys; + u32 sq_mem_size; + + struct sqe *sq_prod_qe; + struct sqe *sq_cons_qe; + struct sqe *sq_first_qe; + struct sqe *sq_last_qe; + u16 sq_prod_idx; + u16 sq_cons_idx; + u32 sqe_left; + + void *sq_pgtbl_virt; + dma_addr_t sq_pgtbl_phys; + u32 sq_pgtbl_size; /* set to PAGE_SIZE for 5708 & 5709 */ + + struct cqe *cq_virt; + dma_addr_t cq_phys; + u32 cq_mem_size; + + struct cqe *cq_prod_qe; + struct cqe *cq_cons_qe; + struct cqe *cq_first_qe; + struct cqe *cq_last_qe; + u16 cq_prod_idx; + u16 cq_cons_idx; + u32 cqe_left; + u32 cqe_size; + u32 cqe_exp_seq_sn; + + void *cq_pgtbl_virt; + dma_addr_t cq_pgtbl_phys; + u32 cq_pgtbl_size; /* set to PAGE_SIZE for 5708 & 5709 */ + + struct rqe *rq_virt; + dma_addr_t rq_phys; + u32 rq_mem_size; + + struct rqe *rq_prod_qe; + struct rqe *rq_cons_qe; + struct rqe *rq_first_qe; + struct rqe *rq_last_qe; + u16 rq_prod_idx; + u16 rq_cons_idx; + u32 rqe_left; + + void *rq_pgtbl_virt; + dma_addr_t rq_pgtbl_phys; + u32 rq_pgtbl_size; /* set to PAGE_SIZE for 5708 & 5709 */ +}; + + + +/* + * CID handles + */ +struct ep_handles { + u32 fw_cid; + u32 drv_iscsi_cid; + u16 pg_cid; + u16 rsvd; +}; + + +enum { + EP_STATE_IDLE = 0x0, + EP_STATE_PG_OFLD_START = 0x1, + EP_STATE_PG_OFLD_COMPL = 0x2, + EP_STATE_OFLD_START = 0x4, + EP_STATE_OFLD_COMPL = 0x8, + EP_STATE_CONNECT_START = 0x10, + EP_STATE_CONNECT_COMPL = 0x20, + EP_STATE_ULP_UPDATE_START = 0x40, + EP_STATE_ULP_UPDATE_COMPL = 0x80, + EP_STATE_DISCONN_START = 0x100, + EP_STATE_DISCONN_COMPL = 0x200, + EP_STATE_CLEANUP_START = 0x400, + EP_STATE_CLEANUP_CMPL = 0x800, + EP_STATE_TCP_FIN_RCVD = 0x1000, + EP_STATE_TCP_RST_RCVD = 0x2000, + EP_STATE_PG_OFLD_FAILED = 0x1000000, + EP_STATE_ULP_UPDATE_FAILED = 0x2000000, + EP_STATE_CLEANUP_FAILED = 0x4000000, + EP_STATE_OFLD_FAILED = 0x8000000, + EP_STATE_CONNECT_FAILED = 0x10000000, + EP_STATE_DISCONN_TIMEDOUT = 0x20000000, +}; + +/** + * struct bnx2i_endpoint - representation of tcp connection in NX2 world + * + * @link: list head to link elements + * @hba: adapter to which this connection belongs + * @conn: iscsi connection this EP is linked to + * @sess: iscsi session this EP is linked to + * @cm_sk: cnic sock struct + * @hba_age: age to detect if 'iscsid' issues ep_disconnect() + * after HBA reset is completed by bnx2i/cnic/bnx2 + * modules + * @state: tracks offload connection state machine + * @teardown_mode: indicates if conn teardown is abortive or orderly + * @qp: QP information + * @ids: contains chip allocated *context id* & driver assigned + * *iscsi cid* + * @ofld_timer: offload timer to detect timeout + * @ofld_wait: wait queue + * + * Endpoint Structure - equivalent of tcp socket structure + */ +struct bnx2i_endpoint { + struct list_head link; + struct bnx2i_hba *hba; + struct bnx2i_conn *conn; + struct cnic_sock *cm_sk; + u32 hba_age; + u32 state; + unsigned long timestamp; + int num_active_cmds; + + struct qp_info qp; + struct ep_handles ids; + #define ep_iscsi_cid ids.drv_iscsi_cid + #define ep_cid ids.fw_cid + #define ep_pg_cid ids.pg_cid + struct timer_list ofld_timer; + wait_queue_head_t ofld_wait; +}; + + + +/* Global variables */ +extern unsigned int error_mask1, error_mask2; +extern u64 iscsi_error_mask; +extern unsigned int en_tcp_dack; +extern unsigned int event_coal_div; + +extern struct scsi_transport_template *bnx2i_scsi_xport_template; +extern struct iscsi_transport bnx2i_iscsi_transport; +extern struct cnic_ulp_ops bnx2i_cnic_cb; + +extern unsigned int sq_size; +extern unsigned int rq_size; + +extern struct device_attribute *bnx2i_dev_attributes[]; + + + +/* + * Function Prototypes + */ +extern void bnx2i_identify_device(struct bnx2i_hba *hba); +extern void bnx2i_register_device(struct bnx2i_hba *hba); + +extern void bnx2i_ulp_init(struct cnic_dev *dev); +extern void bnx2i_ulp_exit(struct cnic_dev *dev); +extern void bnx2i_start(void *handle); +extern void bnx2i_stop(void *handle); +extern void bnx2i_reg_dev_all(void); +extern void bnx2i_unreg_dev_all(void); +extern struct bnx2i_hba *get_adapter_list_head(void); + +struct bnx2i_conn *bnx2i_get_conn_from_id(struct bnx2i_hba *hba, + u16 iscsi_cid); + +int bnx2i_alloc_ep_pool(void); +void bnx2i_release_ep_pool(void); +struct bnx2i_endpoint *bnx2i_ep_ofld_list_next(struct bnx2i_hba *hba); +struct bnx2i_endpoint *bnx2i_ep_destroy_list_next(struct bnx2i_hba *hba); + +struct bnx2i_hba *bnx2i_find_hba_for_cnic(struct cnic_dev *cnic); + +struct bnx2i_hba *bnx2i_alloc_hba(struct cnic_dev *cnic); +void bnx2i_free_hba(struct bnx2i_hba *hba); + +void bnx2i_get_rq_buf(struct bnx2i_conn *conn, char *ptr, int len); +void bnx2i_put_rq_buf(struct bnx2i_conn *conn, int count); + +void bnx2i_iscsi_unmap_sg_list(struct bnx2i_cmd *cmd); + +void bnx2i_drop_session(struct iscsi_cls_session *session); + +extern int bnx2i_send_fw_iscsi_init_msg(struct bnx2i_hba *hba); +extern int bnx2i_send_iscsi_login(struct bnx2i_conn *conn, + struct iscsi_task *mtask); +extern int bnx2i_send_iscsi_tmf(struct bnx2i_conn *conn, + struct iscsi_task *mtask); +extern int bnx2i_send_iscsi_scsicmd(struct bnx2i_conn *conn, + struct bnx2i_cmd *cmnd); +extern int bnx2i_send_iscsi_nopout(struct bnx2i_conn *conn, + struct iscsi_task *mtask, u32 ttt, + char *datap, int data_len, int unsol); +extern int bnx2i_send_iscsi_logout(struct bnx2i_conn *conn, + struct iscsi_task *mtask); +extern void bnx2i_send_cmd_cleanup_req(struct bnx2i_hba *hba, + struct bnx2i_cmd *cmd); +extern void bnx2i_send_conn_ofld_req(struct bnx2i_hba *hba, + struct bnx2i_endpoint *ep); +extern void bnx2i_update_iscsi_conn(struct iscsi_conn *conn); +extern void bnx2i_send_conn_destroy(struct bnx2i_hba *hba, + struct bnx2i_endpoint *ep); + +extern int bnx2i_alloc_qp_resc(struct bnx2i_hba *hba, + struct bnx2i_endpoint *ep); +extern void bnx2i_free_qp_resc(struct bnx2i_hba *hba, + struct bnx2i_endpoint *ep); +extern void bnx2i_ep_ofld_timer(unsigned long data); +extern struct bnx2i_endpoint *bnx2i_find_ep_in_ofld_list( + struct bnx2i_hba *hba, u32 iscsi_cid); +extern struct bnx2i_endpoint *bnx2i_find_ep_in_destroy_list( + struct bnx2i_hba *hba, u32 iscsi_cid); + +extern int bnx2i_map_ep_dbell_regs(struct bnx2i_endpoint *ep); +extern void bnx2i_arm_cq_event_coalescing(struct bnx2i_endpoint *ep, u8 action); + +/* Debug related function prototypes */ +extern void bnx2i_print_pend_cmd_queue(struct bnx2i_conn *conn); +extern void bnx2i_print_active_cmd_queue(struct bnx2i_conn *conn); +extern void bnx2i_print_xmit_pdu_queue(struct bnx2i_conn *conn); +extern void bnx2i_print_recv_state(struct bnx2i_conn *conn); + +#endif diff --git a/drivers/scsi/bnx2i/bnx2i_hwi.c b/drivers/scsi/bnx2i/bnx2i_hwi.c new file mode 100644 index 000000000000..906cef5cda86 --- /dev/null +++ b/drivers/scsi/bnx2i/bnx2i_hwi.c @@ -0,0 +1,2405 @@ +/* bnx2i_hwi.c: Broadcom NetXtreme II iSCSI driver. + * + * Copyright (c) 2006 - 2009 Broadcom Corporation + * Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved. + * Copyright (c) 2007, 2008 Mike Christie + * + * 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. + * + * Written by: Anil Veerabhadrappa (anilgv@broadcom.com) + */ + +#include +#include +#include "bnx2i.h" + +/** + * bnx2i_get_cid_num - get cid from ep + * @ep: endpoint pointer + * + * Only applicable to 57710 family of devices + */ +static u32 bnx2i_get_cid_num(struct bnx2i_endpoint *ep) +{ + u32 cid; + + if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type)) + cid = ep->ep_cid; + else + cid = GET_CID_NUM(ep->ep_cid); + return cid; +} + + +/** + * bnx2i_adjust_qp_size - Adjust SQ/RQ/CQ size for 57710 device type + * @hba: Adapter for which adjustments is to be made + * + * Only applicable to 57710 family of devices + */ +static void bnx2i_adjust_qp_size(struct bnx2i_hba *hba) +{ + u32 num_elements_per_pg; + + if (test_bit(BNX2I_NX2_DEV_5706, &hba->cnic_dev_type) || + test_bit(BNX2I_NX2_DEV_5708, &hba->cnic_dev_type) || + test_bit(BNX2I_NX2_DEV_5709, &hba->cnic_dev_type)) { + if (!is_power_of_2(hba->max_sqes)) + hba->max_sqes = rounddown_pow_of_two(hba->max_sqes); + + if (!is_power_of_2(hba->max_rqes)) + hba->max_rqes = rounddown_pow_of_two(hba->max_rqes); + } + + /* Adjust each queue size if the user selection does not + * yield integral num of page buffers + */ + /* adjust SQ */ + num_elements_per_pg = PAGE_SIZE / BNX2I_SQ_WQE_SIZE; + if (hba->max_sqes < num_elements_per_pg) + hba->max_sqes = num_elements_per_pg; + else if (hba->max_sqes % num_elements_per_pg) + hba->max_sqes = (hba->max_sqes + num_elements_per_pg - 1) & + ~(num_elements_per_pg - 1); + + /* adjust CQ */ + num_elements_per_pg = PAGE_SIZE / BNX2I_CQE_SIZE; + if (hba->max_cqes < num_elements_per_pg) + hba->max_cqes = num_elements_per_pg; + else if (hba->max_cqes % num_elements_per_pg) + hba->max_cqes = (hba->max_cqes + num_elements_per_pg - 1) & + ~(num_elements_per_pg - 1); + + /* adjust RQ */ + num_elements_per_pg = PAGE_SIZE / BNX2I_RQ_WQE_SIZE; + if (hba->max_rqes < num_elements_per_pg) + hba->max_rqes = num_elements_per_pg; + else if (hba->max_rqes % num_elements_per_pg) + hba->max_rqes = (hba->max_rqes + num_elements_per_pg - 1) & + ~(num_elements_per_pg - 1); +} + + +/** + * bnx2i_get_link_state - get network interface link state + * @hba: adapter instance pointer + * + * updates adapter structure flag based on netdev state + */ +static void bnx2i_get_link_state(struct bnx2i_hba *hba) +{ + if (test_bit(__LINK_STATE_NOCARRIER, &hba->netdev->state)) + set_bit(ADAPTER_STATE_LINK_DOWN, &hba->adapter_state); + else + clear_bit(ADAPTER_STATE_LINK_DOWN, &hba->adapter_state); +} + + +/** + * bnx2i_iscsi_license_error - displays iscsi license related error message + * @hba: adapter instance pointer + * @error_code: error classification + * + * Puts out an error log when driver is unable to offload iscsi connection + * due to license restrictions + */ +static void bnx2i_iscsi_license_error(struct bnx2i_hba *hba, u32 error_code) +{ + if (error_code == ISCSI_KCQE_COMPLETION_STATUS_ISCSI_NOT_SUPPORTED) + /* iSCSI offload not supported on this device */ + printk(KERN_ERR "bnx2i: iSCSI not supported, dev=%s\n", + hba->netdev->name); + if (error_code == ISCSI_KCQE_COMPLETION_STATUS_LOM_ISCSI_NOT_ENABLED) + /* iSCSI offload not supported on this LOM device */ + printk(KERN_ERR "bnx2i: LOM is not enable to " + "offload iSCSI connections, dev=%s\n", + hba->netdev->name); + set_bit(ADAPTER_STATE_INIT_FAILED, &hba->adapter_state); +} + + +/** + * bnx2i_arm_cq_event_coalescing - arms CQ to enable EQ notification + * @ep: endpoint (transport indentifier) structure + * @action: action, ARM or DISARM. For now only ARM_CQE is used + * + * Arm'ing CQ will enable chip to generate global EQ events inorder to interrupt + * the driver. EQ event is generated CQ index is hit or at least 1 CQ is + * outstanding and on chip timer expires + */ +void bnx2i_arm_cq_event_coalescing(struct bnx2i_endpoint *ep, u8 action) +{ + struct bnx2i_5771x_cq_db *cq_db; + u16 cq_index; + + if (!test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type)) + return; + + if (action == CNIC_ARM_CQE) { + cq_index = ep->qp.cqe_exp_seq_sn + + ep->num_active_cmds / event_coal_div; + cq_index %= (ep->qp.cqe_size * 2 + 1); + if (!cq_index) { + cq_index = 1; + cq_db = (struct bnx2i_5771x_cq_db *) + ep->qp.cq_pgtbl_virt; + cq_db->sqn[0] = cq_index; + } + } +} + + +/** + * bnx2i_get_rq_buf - copy RQ buffer contents to driver buffer + * @conn: iscsi connection on which RQ event occured + * @ptr: driver buffer to which RQ buffer contents is to + * be copied + * @len: length of valid data inside RQ buf + * + * Copies RQ buffer contents from shared (DMA'able) memory region to + * driver buffer. RQ is used to DMA unsolicitated iscsi pdu's and + * scsi sense info + */ +void bnx2i_get_rq_buf(struct bnx2i_conn *bnx2i_conn, char *ptr, int len) +{ + if (!bnx2i_conn->ep->qp.rqe_left) + return; + + bnx2i_conn->ep->qp.rqe_left--; + memcpy(ptr, (u8 *) bnx2i_conn->ep->qp.rq_cons_qe, len); + if (bnx2i_conn->ep->qp.rq_cons_qe == bnx2i_conn->ep->qp.rq_last_qe) { + bnx2i_conn->ep->qp.rq_cons_qe = bnx2i_conn->ep->qp.rq_first_qe; + bnx2i_conn->ep->qp.rq_cons_idx = 0; + } else { + bnx2i_conn->ep->qp.rq_cons_qe++; + bnx2i_conn->ep->qp.rq_cons_idx++; + } +} + + +static void bnx2i_ring_577xx_doorbell(struct bnx2i_conn *conn) +{ + struct bnx2i_5771x_dbell dbell; + u32 msg; + + memset(&dbell, 0, sizeof(dbell)); + dbell.dbell.header = (B577XX_ISCSI_CONNECTION_TYPE << + B577XX_DOORBELL_HDR_CONN_TYPE_SHIFT); + msg = *((u32 *)&dbell); + /* TODO : get doorbell register mapping */ + writel(cpu_to_le32(msg), conn->ep->qp.ctx_base); +} + + +/** + * bnx2i_put_rq_buf - Replenish RQ buffer, if required ring on chip doorbell + * @conn: iscsi connection on which event to post + * @count: number of RQ buffer being posted to chip + * + * No need to ring hardware doorbell for 57710 family of devices + */ +void bnx2i_put_rq_buf(struct bnx2i_conn *bnx2i_conn, int count) +{ + struct bnx2i_5771x_sq_rq_db *rq_db; + u16 hi_bit = (bnx2i_conn->ep->qp.rq_prod_idx & 0x8000); + struct bnx2i_endpoint *ep = bnx2i_conn->ep; + + ep->qp.rqe_left += count; + ep->qp.rq_prod_idx &= 0x7FFF; + ep->qp.rq_prod_idx += count; + + if (ep->qp.rq_prod_idx > bnx2i_conn->hba->max_rqes) { + ep->qp.rq_prod_idx %= bnx2i_conn->hba->max_rqes; + if (!hi_bit) + ep->qp.rq_prod_idx |= 0x8000; + } else + ep->qp.rq_prod_idx |= hi_bit; + + if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type)) { + rq_db = (struct bnx2i_5771x_sq_rq_db *) ep->qp.rq_pgtbl_virt; + rq_db->prod_idx = ep->qp.rq_prod_idx; + /* no need to ring hardware doorbell for 57710 */ + } else { + writew(ep->qp.rq_prod_idx, + ep->qp.ctx_base + CNIC_RECV_DOORBELL); + } + mmiowb(); +} + + +/** + * bnx2i_ring_sq_dbell - Ring SQ doorbell to wake-up the processing engine + * @conn: iscsi connection to which new SQ entries belong + * @count: number of SQ WQEs to post + * + * SQ DB is updated in host memory and TX Doorbell is rung for 57710 family + * of devices. For 5706/5708/5709 new SQ WQE count is written into the + * doorbell register + */ +static void bnx2i_ring_sq_dbell(struct bnx2i_conn *bnx2i_conn, int count) +{ + struct bnx2i_5771x_sq_rq_db *sq_db; + struct bnx2i_endpoint *ep = bnx2i_conn->ep; + + ep->num_active_cmds++; + wmb(); /* flush SQ WQE memory before the doorbell is rung */ + if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type)) { + sq_db = (struct bnx2i_5771x_sq_rq_db *) ep->qp.sq_pgtbl_virt; + sq_db->prod_idx = ep->qp.sq_prod_idx; + bnx2i_ring_577xx_doorbell(bnx2i_conn); + } else + writew(count, ep->qp.ctx_base + CNIC_SEND_DOORBELL); + + mmiowb(); /* flush posted PCI writes */ +} + + +/** + * bnx2i_ring_dbell_update_sq_params - update SQ driver parameters + * @conn: iscsi connection to which new SQ entries belong + * @count: number of SQ WQEs to post + * + * this routine will update SQ driver parameters and ring the doorbell + */ +static void bnx2i_ring_dbell_update_sq_params(struct bnx2i_conn *bnx2i_conn, + int count) +{ + int tmp_cnt; + + if (count == 1) { + if (bnx2i_conn->ep->qp.sq_prod_qe == + bnx2i_conn->ep->qp.sq_last_qe) + bnx2i_conn->ep->qp.sq_prod_qe = + bnx2i_conn->ep->qp.sq_first_qe; + else + bnx2i_conn->ep->qp.sq_prod_qe++; + } else { + if ((bnx2i_conn->ep->qp.sq_prod_qe + count) <= + bnx2i_conn->ep->qp.sq_last_qe) + bnx2i_conn->ep->qp.sq_prod_qe += count; + else { + tmp_cnt = bnx2i_conn->ep->qp.sq_last_qe - + bnx2i_conn->ep->qp.sq_prod_qe; + bnx2i_conn->ep->qp.sq_prod_qe = + &bnx2i_conn->ep->qp.sq_first_qe[count - + (tmp_cnt + 1)]; + } + } + bnx2i_conn->ep->qp.sq_prod_idx += count; + /* Ring the doorbell */ + bnx2i_ring_sq_dbell(bnx2i_conn, bnx2i_conn->ep->qp.sq_prod_idx); +} + + +/** + * bnx2i_send_iscsi_login - post iSCSI login request MP WQE to hardware + * @conn: iscsi connection + * @cmd: driver command structure which is requesting + * a WQE to sent to chip for further processing + * + * prepare and post an iSCSI Login request WQE to CNIC firmware + */ +int bnx2i_send_iscsi_login(struct bnx2i_conn *bnx2i_conn, + struct iscsi_task *task) +{ + struct bnx2i_cmd *bnx2i_cmd; + struct bnx2i_login_request *login_wqe; + struct iscsi_login *login_hdr; + u32 dword; + + bnx2i_cmd = (struct bnx2i_cmd *)task->dd_data; + login_hdr = (struct iscsi_login *)task->hdr; + login_wqe = (struct bnx2i_login_request *) + bnx2i_conn->ep->qp.sq_prod_qe; + + login_wqe->op_code = login_hdr->opcode; + login_wqe->op_attr = login_hdr->flags; + login_wqe->version_max = login_hdr->max_version; + login_wqe->version_min = login_hdr->min_version; + login_wqe->data_length = ntoh24(login_hdr->dlength); + login_wqe->isid_lo = *((u32 *) login_hdr->isid); + login_wqe->isid_hi = *((u16 *) login_hdr->isid + 2); + login_wqe->tsih = login_hdr->tsih; + login_wqe->itt = task->itt | + (ISCSI_TASK_TYPE_MPATH << ISCSI_LOGIN_REQUEST_TYPE_SHIFT); + login_wqe->cid = login_hdr->cid; + + login_wqe->cmd_sn = be32_to_cpu(login_hdr->cmdsn); + login_wqe->exp_stat_sn = be32_to_cpu(login_hdr->exp_statsn); + + login_wqe->resp_bd_list_addr_lo = (u32) bnx2i_conn->gen_pdu.resp_bd_dma; + login_wqe->resp_bd_list_addr_hi = + (u32) ((u64) bnx2i_conn->gen_pdu.resp_bd_dma >> 32); + + dword = ((1 << ISCSI_LOGIN_REQUEST_NUM_RESP_BDS_SHIFT) | + (bnx2i_conn->gen_pdu.resp_buf_size << + ISCSI_LOGIN_REQUEST_RESP_BUFFER_LENGTH_SHIFT)); + login_wqe->resp_buffer = dword; + login_wqe->flags = 0; + login_wqe->bd_list_addr_lo = (u32) bnx2i_conn->gen_pdu.req_bd_dma; + login_wqe->bd_list_addr_hi = + (u32) ((u64) bnx2i_conn->gen_pdu.req_bd_dma >> 32); + login_wqe->num_bds = 1; + login_wqe->cq_index = 0; /* CQ# used for completion, 5771x only */ + + bnx2i_ring_dbell_update_sq_params(bnx2i_conn, 1); + return 0; +} + +/** + * bnx2i_send_iscsi_tmf - post iSCSI task management request MP WQE to hardware + * @conn: iscsi connection + * @mtask: driver command structure which is requesting + * a WQE to sent to chip for further processing + * + * prepare and post an iSCSI Login request WQE to CNIC firmware + */ +int bnx2i_send_iscsi_tmf(struct bnx2i_conn *bnx2i_conn, + struct iscsi_task *mtask) +{ + struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data; + struct iscsi_tm *tmfabort_hdr; + struct scsi_cmnd *ref_sc; + struct iscsi_task *ctask; + struct bnx2i_cmd *bnx2i_cmd; + struct bnx2i_tmf_request *tmfabort_wqe; + u32 dword; + + bnx2i_cmd = (struct bnx2i_cmd *)mtask->dd_data; + tmfabort_hdr = (struct iscsi_tm *)mtask->hdr; + tmfabort_wqe = (struct bnx2i_tmf_request *) + bnx2i_conn->ep->qp.sq_prod_qe; + + tmfabort_wqe->op_code = tmfabort_hdr->opcode; + tmfabort_wqe->op_attr = 0; + tmfabort_wqe->op_attr = + ISCSI_TMF_REQUEST_ALWAYS_ONE | ISCSI_TM_FUNC_ABORT_TASK; + tmfabort_wqe->lun[0] = be32_to_cpu(tmfabort_hdr->lun[0]); + tmfabort_wqe->lun[1] = be32_to_cpu(tmfabort_hdr->lun[1]); + + tmfabort_wqe->itt = (mtask->itt | (ISCSI_TASK_TYPE_MPATH << 14)); + tmfabort_wqe->reserved2 = 0; + tmfabort_wqe->cmd_sn = be32_to_cpu(tmfabort_hdr->cmdsn); + + ctask = iscsi_itt_to_task(conn, tmfabort_hdr->rtt); + if (!ctask || ctask->sc) + /* + * the iscsi layer must have completed the cmd while this + * was starting up. + */ + return 0; + ref_sc = ctask->sc; + + if (ref_sc->sc_data_direction == DMA_TO_DEVICE) + dword = (ISCSI_TASK_TYPE_WRITE << ISCSI_CMD_REQUEST_TYPE_SHIFT); + else + dword = (ISCSI_TASK_TYPE_READ << ISCSI_CMD_REQUEST_TYPE_SHIFT); + tmfabort_wqe->ref_itt = (dword | tmfabort_hdr->rtt); + tmfabort_wqe->ref_cmd_sn = be32_to_cpu(tmfabort_hdr->refcmdsn); + + tmfabort_wqe->bd_list_addr_lo = (u32) bnx2i_conn->hba->mp_bd_dma; + tmfabort_wqe->bd_list_addr_hi = (u32) + ((u64) bnx2i_conn->hba->mp_bd_dma >> 32); + tmfabort_wqe->num_bds = 1; + tmfabort_wqe->cq_index = 0; /* CQ# used for completion, 5771x only */ + + bnx2i_ring_dbell_update_sq_params(bnx2i_conn, 1); + return 0; +} + +/** + * bnx2i_send_iscsi_scsicmd - post iSCSI scsicmd request WQE to hardware + * @conn: iscsi connection + * @cmd: driver command structure which is requesting + * a WQE to sent to chip for further processing + * + * prepare and post an iSCSI SCSI-CMD request WQE to CNIC firmware + */ +int bnx2i_send_iscsi_scsicmd(struct bnx2i_conn *bnx2i_conn, + struct bnx2i_cmd *cmd) +{ + struct bnx2i_cmd_request *scsi_cmd_wqe; + + scsi_cmd_wqe = (struct bnx2i_cmd_request *) + bnx2i_conn->ep->qp.sq_prod_qe; + memcpy(scsi_cmd_wqe, &cmd->req, sizeof(struct bnx2i_cmd_request)); + scsi_cmd_wqe->cq_index = 0; /* CQ# used for completion, 5771x only */ + + bnx2i_ring_dbell_update_sq_params(bnx2i_conn, 1); + return 0; +} + +/** + * bnx2i_send_iscsi_nopout - post iSCSI NOPOUT request WQE to hardware + * @conn: iscsi connection + * @cmd: driver command structure which is requesting + * a WQE to sent to chip for further processing + * @ttt: TTT to be used when building pdu header + * @datap: payload buffer pointer + * @data_len: payload data length + * @unsol: indicated whether nopout pdu is unsolicited pdu or + * in response to target's NOPIN w/ TTT != FFFFFFFF + * + * prepare and post a nopout request WQE to CNIC firmware + */ +int bnx2i_send_iscsi_nopout(struct bnx2i_conn *bnx2i_conn, + struct iscsi_task *task, u32 ttt, + char *datap, int data_len, int unsol) +{ + struct bnx2i_endpoint *ep = bnx2i_conn->ep; + struct bnx2i_cmd *bnx2i_cmd; + struct bnx2i_nop_out_request *nopout_wqe; + struct iscsi_nopout *nopout_hdr; + + bnx2i_cmd = (struct bnx2i_cmd *)task->dd_data; + nopout_hdr = (struct iscsi_nopout *)task->hdr; + nopout_wqe = (struct bnx2i_nop_out_request *)ep->qp.sq_prod_qe; + nopout_wqe->op_code = nopout_hdr->opcode; + nopout_wqe->op_attr = ISCSI_FLAG_CMD_FINAL; + memcpy(nopout_wqe->lun, nopout_hdr->lun, 8); + + if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type)) { + u32 tmp = nopout_hdr->lun[0]; + /* 57710 requires LUN field to be swapped */ + nopout_hdr->lun[0] = nopout_hdr->lun[1]; + nopout_hdr->lun[1] = tmp; + } + + nopout_wqe->itt = ((u16)task->itt | + (ISCSI_TASK_TYPE_MPATH << + ISCSI_TMF_REQUEST_TYPE_SHIFT)); + nopout_wqe->ttt = ttt; + nopout_wqe->flags = 0; + if (!unsol) + nopout_wqe->flags = ISCSI_NOP_OUT_REQUEST_LOCAL_COMPLETION; + else if (nopout_hdr->itt == RESERVED_ITT) + nopout_wqe->flags = ISCSI_NOP_OUT_REQUEST_LOCAL_COMPLETION; + + nopout_wqe->cmd_sn = be32_to_cpu(nopout_hdr->cmdsn); + nopout_wqe->data_length = data_len; + if (data_len) { + /* handle payload data, not required in first release */ + printk(KERN_ALERT "NOPOUT: WARNING!! payload len != 0\n"); + } else { + nopout_wqe->bd_list_addr_lo = (u32) + bnx2i_conn->hba->mp_bd_dma; + nopout_wqe->bd_list_addr_hi = + (u32) ((u64) bnx2i_conn->hba->mp_bd_dma >> 32); + nopout_wqe->num_bds = 1; + } + nopout_wqe->cq_index = 0; /* CQ# used for completion, 5771x only */ + + bnx2i_ring_dbell_update_sq_params(bnx2i_conn, 1); + return 0; +} + + +/** + * bnx2i_send_iscsi_logout - post iSCSI logout request WQE to hardware + * @conn: iscsi connection + * @cmd: driver command structure which is requesting + * a WQE to sent to chip for further processing + * + * prepare and post logout request WQE to CNIC firmware + */ +int bnx2i_send_iscsi_logout(struct bnx2i_conn *bnx2i_conn, + struct iscsi_task *task) +{ + struct bnx2i_cmd *bnx2i_cmd; + struct bnx2i_logout_request *logout_wqe; + struct iscsi_logout *logout_hdr; + + bnx2i_cmd = (struct bnx2i_cmd *)task->dd_data; + logout_hdr = (struct iscsi_logout *)task->hdr; + + logout_wqe = (struct bnx2i_logout_request *) + bnx2i_conn->ep->qp.sq_prod_qe; + memset(logout_wqe, 0x00, sizeof(struct bnx2i_logout_request)); + + logout_wqe->op_code = logout_hdr->opcode; + logout_wqe->cmd_sn = be32_to_cpu(logout_hdr->cmdsn); + logout_wqe->op_attr = + logout_hdr->flags | ISCSI_LOGOUT_REQUEST_ALWAYS_ONE; + logout_wqe->itt = ((u16)task->itt | + (ISCSI_TASK_TYPE_MPATH << + ISCSI_LOGOUT_REQUEST_TYPE_SHIFT)); + logout_wqe->data_length = 0; + logout_wqe->cid = 0; + + logout_wqe->bd_list_addr_lo = (u32) bnx2i_conn->hba->mp_bd_dma; + logout_wqe->bd_list_addr_hi = (u32) + ((u64) bnx2i_conn->hba->mp_bd_dma >> 32); + logout_wqe->num_bds = 1; + logout_wqe->cq_index = 0; /* CQ# used for completion, 5771x only */ + + bnx2i_ring_dbell_update_sq_params(bnx2i_conn, 1); + return 0; +} + + +/** + * bnx2i_update_iscsi_conn - post iSCSI logout request WQE to hardware + * @conn: iscsi connection which requires iscsi parameter update + * + * sends down iSCSI Conn Update request to move iSCSI conn to FFP + */ +void bnx2i_update_iscsi_conn(struct iscsi_conn *conn) +{ + struct bnx2i_conn *bnx2i_conn = conn->dd_data; + struct bnx2i_hba *hba = bnx2i_conn->hba; + struct kwqe *kwqe_arr[2]; + struct iscsi_kwqe_conn_update *update_wqe; + struct iscsi_kwqe_conn_update conn_update_kwqe; + + update_wqe = &conn_update_kwqe; + + update_wqe->hdr.op_code = ISCSI_KWQE_OPCODE_UPDATE_CONN; + update_wqe->hdr.flags = + (ISCSI_KWQE_LAYER_CODE << ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT); + + /* 5771x requires conn context id to be passed as is */ + if (test_bit(BNX2I_NX2_DEV_57710, &bnx2i_conn->ep->hba->cnic_dev_type)) + update_wqe->context_id = bnx2i_conn->ep->ep_cid; + else + update_wqe->context_id = (bnx2i_conn->ep->ep_cid >> 7); + update_wqe->conn_flags = 0; + if (conn->hdrdgst_en) + update_wqe->conn_flags |= ISCSI_KWQE_CONN_UPDATE_HEADER_DIGEST; + if (conn->datadgst_en) + update_wqe->conn_flags |= ISCSI_KWQE_CONN_UPDATE_DATA_DIGEST; + if (conn->session->initial_r2t_en) + update_wqe->conn_flags |= ISCSI_KWQE_CONN_UPDATE_INITIAL_R2T; + if (conn->session->imm_data_en) + update_wqe->conn_flags |= ISCSI_KWQE_CONN_UPDATE_IMMEDIATE_DATA; + + update_wqe->max_send_pdu_length = conn->max_xmit_dlength; + update_wqe->max_recv_pdu_length = conn->max_recv_dlength; + update_wqe->first_burst_length = conn->session->first_burst; + update_wqe->max_burst_length = conn->session->max_burst; + update_wqe->exp_stat_sn = conn->exp_statsn; + update_wqe->max_outstanding_r2ts = conn->session->max_r2t; + update_wqe->session_error_recovery_level = conn->session->erl; + iscsi_conn_printk(KERN_ALERT, conn, + "bnx2i: conn update - MBL 0x%x FBL 0x%x" + "MRDSL_I 0x%x MRDSL_T 0x%x \n", + update_wqe->max_burst_length, + update_wqe->first_burst_length, + update_wqe->max_recv_pdu_length, + update_wqe->max_send_pdu_length); + + kwqe_arr[0] = (struct kwqe *) update_wqe; + if (hba->cnic && hba->cnic->submit_kwqes) + hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, 1); +} + + +/** + * bnx2i_ep_ofld_timer - post iSCSI logout request WQE to hardware + * @data: endpoint (transport handle) structure pointer + * + * routine to handle connection offload/destroy request timeout + */ +void bnx2i_ep_ofld_timer(unsigned long data) +{ + struct bnx2i_endpoint *ep = (struct bnx2i_endpoint *) data; + + if (ep->state == EP_STATE_OFLD_START) { + printk(KERN_ALERT "ofld_timer: CONN_OFLD timeout\n"); + ep->state = EP_STATE_OFLD_FAILED; + } else if (ep->state == EP_STATE_DISCONN_START) { + printk(KERN_ALERT "ofld_timer: CONN_DISCON timeout\n"); + ep->state = EP_STATE_DISCONN_TIMEDOUT; + } else if (ep->state == EP_STATE_CLEANUP_START) { + printk(KERN_ALERT "ofld_timer: CONN_CLEANUP timeout\n"); + ep->state = EP_STATE_CLEANUP_FAILED; + } + + wake_up_interruptible(&ep->ofld_wait); +} + + +static int bnx2i_power_of2(u32 val) +{ + u32 power = 0; + if (val & (val - 1)) + return power; + val--; + while (val) { + val = val >> 1; + power++; + } + return power; +} + + +/** + * bnx2i_send_cmd_cleanup_req - send iscsi cmd context clean-up request + * @hba: adapter structure pointer + * @cmd: driver command structure which is requesting + * a WQE to sent to chip for further processing + * + * prepares and posts CONN_OFLD_REQ1/2 KWQE + */ +void bnx2i_send_cmd_cleanup_req(struct bnx2i_hba *hba, struct bnx2i_cmd *cmd) +{ + struct bnx2i_cleanup_request *cmd_cleanup; + + cmd_cleanup = + (struct bnx2i_cleanup_request *)cmd->conn->ep->qp.sq_prod_qe; + memset(cmd_cleanup, 0x00, sizeof(struct bnx2i_cleanup_request)); + + cmd_cleanup->op_code = ISCSI_OPCODE_CLEANUP_REQUEST; + cmd_cleanup->itt = cmd->req.itt; + cmd_cleanup->cq_index = 0; /* CQ# used for completion, 5771x only */ + + bnx2i_ring_dbell_update_sq_params(cmd->conn, 1); +} + + +/** + * bnx2i_send_conn_destroy - initiates iscsi connection teardown process + * @hba: adapter structure pointer + * @ep: endpoint (transport indentifier) structure + * + * this routine prepares and posts CONN_OFLD_REQ1/2 KWQE to initiate + * iscsi connection context clean-up process + */ +void bnx2i_send_conn_destroy(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep) +{ + struct kwqe *kwqe_arr[2]; + struct iscsi_kwqe_conn_destroy conn_cleanup; + + memset(&conn_cleanup, 0x00, sizeof(struct iscsi_kwqe_conn_destroy)); + + conn_cleanup.hdr.op_code = ISCSI_KWQE_OPCODE_DESTROY_CONN; + conn_cleanup.hdr.flags = + (ISCSI_KWQE_LAYER_CODE << ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT); + /* 5771x requires conn context id to be passed as is */ + if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type)) + conn_cleanup.context_id = ep->ep_cid; + else + conn_cleanup.context_id = (ep->ep_cid >> 7); + + conn_cleanup.reserved0 = (u16)ep->ep_iscsi_cid; + + kwqe_arr[0] = (struct kwqe *) &conn_cleanup; + if (hba->cnic && hba->cnic->submit_kwqes) + hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, 1); +} + + +/** + * bnx2i_570x_send_conn_ofld_req - initiates iscsi conn context setup process + * @hba: adapter structure pointer + * @ep: endpoint (transport indentifier) structure + * + * 5706/5708/5709 specific - prepares and posts CONN_OFLD_REQ1/2 KWQE + */ +static void bnx2i_570x_send_conn_ofld_req(struct bnx2i_hba *hba, + struct bnx2i_endpoint *ep) +{ + struct kwqe *kwqe_arr[2]; + struct iscsi_kwqe_conn_offload1 ofld_req1; + struct iscsi_kwqe_conn_offload2 ofld_req2; + dma_addr_t dma_addr; + int num_kwqes = 2; + u32 *ptbl; + + ofld_req1.hdr.op_code = ISCSI_KWQE_OPCODE_OFFLOAD_CONN1; + ofld_req1.hdr.flags = + (ISCSI_KWQE_LAYER_CODE << ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT); + + ofld_req1.iscsi_conn_id = (u16) ep->ep_iscsi_cid; + + dma_addr = ep->qp.sq_pgtbl_phys; + ofld_req1.sq_page_table_addr_lo = (u32) dma_addr; + ofld_req1.sq_page_table_addr_hi = (u32) ((u64) dma_addr >> 32); + + dma_addr = ep->qp.cq_pgtbl_phys; + ofld_req1.cq_page_table_addr_lo = (u32) dma_addr; + ofld_req1.cq_page_table_addr_hi = (u32) ((u64) dma_addr >> 32); + + ofld_req2.hdr.op_code = ISCSI_KWQE_OPCODE_OFFLOAD_CONN2; + ofld_req2.hdr.flags = + (ISCSI_KWQE_LAYER_CODE << ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT); + + dma_addr = ep->qp.rq_pgtbl_phys; + ofld_req2.rq_page_table_addr_lo = (u32) dma_addr; + ofld_req2.rq_page_table_addr_hi = (u32) ((u64) dma_addr >> 32); + + ptbl = (u32 *) ep->qp.sq_pgtbl_virt; + + ofld_req2.sq_first_pte.hi = *ptbl++; + ofld_req2.sq_first_pte.lo = *ptbl; + + ptbl = (u32 *) ep->qp.cq_pgtbl_virt; + ofld_req2.cq_first_pte.hi = *ptbl++; + ofld_req2.cq_first_pte.lo = *ptbl; + + kwqe_arr[0] = (struct kwqe *) &ofld_req1; + kwqe_arr[1] = (struct kwqe *) &ofld_req2; + ofld_req2.num_additional_wqes = 0; + + if (hba->cnic && hba->cnic->submit_kwqes) + hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes); +} + + +/** + * bnx2i_5771x_send_conn_ofld_req - initiates iscsi connection context creation + * @hba: adapter structure pointer + * @ep: endpoint (transport indentifier) structure + * + * 57710 specific - prepares and posts CONN_OFLD_REQ1/2 KWQE + */ +static void bnx2i_5771x_send_conn_ofld_req(struct bnx2i_hba *hba, + struct bnx2i_endpoint *ep) +{ + struct kwqe *kwqe_arr[5]; + struct iscsi_kwqe_conn_offload1 ofld_req1; + struct iscsi_kwqe_conn_offload2 ofld_req2; + struct iscsi_kwqe_conn_offload3 ofld_req3[1]; + dma_addr_t dma_addr; + int num_kwqes = 2; + u32 *ptbl; + + ofld_req1.hdr.op_code = ISCSI_KWQE_OPCODE_OFFLOAD_CONN1; + ofld_req1.hdr.flags = + (ISCSI_KWQE_LAYER_CODE << ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT); + + ofld_req1.iscsi_conn_id = (u16) ep->ep_iscsi_cid; + + dma_addr = ep->qp.sq_pgtbl_phys + ISCSI_SQ_DB_SIZE; + ofld_req1.sq_page_table_addr_lo = (u32) dma_addr; + ofld_req1.sq_page_table_addr_hi = (u32) ((u64) dma_addr >> 32); + + dma_addr = ep->qp.cq_pgtbl_phys + ISCSI_CQ_DB_SIZE; + ofld_req1.cq_page_table_addr_lo = (u32) dma_addr; + ofld_req1.cq_page_table_addr_hi = (u32) ((u64) dma_addr >> 32); + + ofld_req2.hdr.op_code = ISCSI_KWQE_OPCODE_OFFLOAD_CONN2; + ofld_req2.hdr.flags = + (ISCSI_KWQE_LAYER_CODE << ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT); + + dma_addr = ep->qp.rq_pgtbl_phys + ISCSI_RQ_DB_SIZE; + ofld_req2.rq_page_table_addr_lo = (u32) dma_addr; + ofld_req2.rq_page_table_addr_hi = (u32) ((u64) dma_addr >> 32); + + ptbl = (u32 *)((u8 *)ep->qp.sq_pgtbl_virt + ISCSI_SQ_DB_SIZE); + ofld_req2.sq_first_pte.hi = *ptbl++; + ofld_req2.sq_first_pte.lo = *ptbl; + + ptbl = (u32 *)((u8 *)ep->qp.cq_pgtbl_virt + ISCSI_CQ_DB_SIZE); + ofld_req2.cq_first_pte.hi = *ptbl++; + ofld_req2.cq_first_pte.lo = *ptbl; + + kwqe_arr[0] = (struct kwqe *) &ofld_req1; + kwqe_arr[1] = (struct kwqe *) &ofld_req2; + + ofld_req2.num_additional_wqes = 1; + memset(ofld_req3, 0x00, sizeof(ofld_req3[0])); + ptbl = (u32 *)((u8 *)ep->qp.rq_pgtbl_virt + ISCSI_RQ_DB_SIZE); + ofld_req3[0].qp_first_pte[0].hi = *ptbl++; + ofld_req3[0].qp_first_pte[0].lo = *ptbl; + + kwqe_arr[2] = (struct kwqe *) ofld_req3; + /* need if we decide to go with multiple KCQE's per conn */ + num_kwqes += 1; + + if (hba->cnic && hba->cnic->submit_kwqes) + hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes); +} + +/** + * bnx2i_send_conn_ofld_req - initiates iscsi connection context setup process + * + * @hba: adapter structure pointer + * @ep: endpoint (transport indentifier) structure + * + * this routine prepares and posts CONN_OFLD_REQ1/2 KWQE + */ +void bnx2i_send_conn_ofld_req(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep) +{ + if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type)) + bnx2i_5771x_send_conn_ofld_req(hba, ep); + else + bnx2i_570x_send_conn_ofld_req(hba, ep); +} + + +/** + * setup_qp_page_tables - iscsi QP page table setup function + * @ep: endpoint (transport indentifier) structure + * + * Sets up page tables for SQ/RQ/CQ, 1G/sec (5706/5708/5709) devices requires + * 64-bit address in big endian format. Whereas 10G/sec (57710) requires + * PT in little endian format + */ +static void setup_qp_page_tables(struct bnx2i_endpoint *ep) +{ + int num_pages; + u32 *ptbl; + dma_addr_t page; + int cnic_dev_10g; + + if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type)) + cnic_dev_10g = 1; + else + cnic_dev_10g = 0; + + /* SQ page table */ + memset(ep->qp.sq_pgtbl_virt, 0, ep->qp.sq_pgtbl_size); + num_pages = ep->qp.sq_mem_size / PAGE_SIZE; + page = ep->qp.sq_phys; + + if (cnic_dev_10g) + ptbl = (u32 *)((u8 *)ep->qp.sq_pgtbl_virt + ISCSI_SQ_DB_SIZE); + else + ptbl = (u32 *) ep->qp.sq_pgtbl_virt; + while (num_pages--) { + if (cnic_dev_10g) { + /* PTE is written in little endian format for 57710 */ + *ptbl = (u32) page; + ptbl++; + *ptbl = (u32) ((u64) page >> 32); + ptbl++; + page += PAGE_SIZE; + } else { + /* PTE is written in big endian format for + * 5706/5708/5709 devices */ + *ptbl = (u32) ((u64) page >> 32); + ptbl++; + *ptbl = (u32) page; + ptbl++; + page += PAGE_SIZE; + } + } + + /* RQ page table */ + memset(ep->qp.rq_pgtbl_virt, 0, ep->qp.rq_pgtbl_size); + num_pages = ep->qp.rq_mem_size / PAGE_SIZE; + page = ep->qp.rq_phys; + + if (cnic_dev_10g) + ptbl = (u32 *)((u8 *)ep->qp.rq_pgtbl_virt + ISCSI_RQ_DB_SIZE); + else + ptbl = (u32 *) ep->qp.rq_pgtbl_virt; + while (num_pages--) { + if (cnic_dev_10g) { + /* PTE is written in little endian format for 57710 */ + *ptbl = (u32) page; + ptbl++; + *ptbl = (u32) ((u64) page >> 32); + ptbl++; + page += PAGE_SIZE; + } else { + /* PTE is written in big endian format for + * 5706/5708/5709 devices */ + *ptbl = (u32) ((u64) page >> 32); + ptbl++; + *ptbl = (u32) page; + ptbl++; + page += PAGE_SIZE; + } + } + + /* CQ page table */ + memset(ep->qp.cq_pgtbl_virt, 0, ep->qp.cq_pgtbl_size); + num_pages = ep->qp.cq_mem_size / PAGE_SIZE; + page = ep->qp.cq_phys; + + if (cnic_dev_10g) + ptbl = (u32 *)((u8 *)ep->qp.cq_pgtbl_virt + ISCSI_CQ_DB_SIZE); + else + ptbl = (u32 *) ep->qp.cq_pgtbl_virt; + while (num_pages--) { + if (cnic_dev_10g) { + /* PTE is written in little endian format for 57710 */ + *ptbl = (u32) page; + ptbl++; + *ptbl = (u32) ((u64) page >> 32); + ptbl++; + page += PAGE_SIZE; + } else { + /* PTE is written in big endian format for + * 5706/5708/5709 devices */ + *ptbl = (u32) ((u64) page >> 32); + ptbl++; + *ptbl = (u32) page; + ptbl++; + page += PAGE_SIZE; + } + } +} + + +/** + * bnx2i_alloc_qp_resc - allocates required resources for QP. + * @hba: adapter structure pointer + * @ep: endpoint (transport indentifier) structure + * + * Allocate QP (transport layer for iSCSI connection) resources, DMA'able + * memory for SQ/RQ/CQ and page tables. EP structure elements such + * as producer/consumer indexes/pointers, queue sizes and page table + * contents are setup + */ +int bnx2i_alloc_qp_resc(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep) +{ + struct bnx2i_5771x_cq_db *cq_db; + + ep->hba = hba; + ep->conn = NULL; + ep->ep_cid = ep->ep_iscsi_cid = ep->ep_pg_cid = 0; + + /* Allocate page table memory for SQ which is page aligned */ + ep->qp.sq_mem_size = hba->max_sqes * BNX2I_SQ_WQE_SIZE; + ep->qp.sq_mem_size = + (ep->qp.sq_mem_size + (PAGE_SIZE - 1)) & PAGE_MASK; + ep->qp.sq_pgtbl_size = + (ep->qp.sq_mem_size / PAGE_SIZE) * sizeof(void *); + ep->qp.sq_pgtbl_size = + (ep->qp.sq_pgtbl_size + (PAGE_SIZE - 1)) & PAGE_MASK; + + ep->qp.sq_pgtbl_virt = + dma_alloc_coherent(&hba->pcidev->dev, ep->qp.sq_pgtbl_size, + &ep->qp.sq_pgtbl_phys, GFP_KERNEL); + if (!ep->qp.sq_pgtbl_virt) { + printk(KERN_ALERT "bnx2i: unable to alloc SQ PT mem (%d)\n", + ep->qp.sq_pgtbl_size); + goto mem_alloc_err; + } + + /* Allocate memory area for actual SQ element */ + ep->qp.sq_virt = + dma_alloc_coherent(&hba->pcidev->dev, ep->qp.sq_mem_size, + &ep->qp.sq_phys, GFP_KERNEL); + if (!ep->qp.sq_virt) { + printk(KERN_ALERT "bnx2i: unable to alloc SQ BD memory %d\n", + ep->qp.sq_mem_size); + goto mem_alloc_err; + } + + memset(ep->qp.sq_virt, 0x00, ep->qp.sq_mem_size); + ep->qp.sq_first_qe = ep->qp.sq_virt; + ep->qp.sq_prod_qe = ep->qp.sq_first_qe; + ep->qp.sq_cons_qe = ep->qp.sq_first_qe; + ep->qp.sq_last_qe = &ep->qp.sq_first_qe[hba->max_sqes - 1]; + ep->qp.sq_prod_idx = 0; + ep->qp.sq_cons_idx = 0; + ep->qp.sqe_left = hba->max_sqes; + + /* Allocate page table memory for CQ which is page aligned */ + ep->qp.cq_mem_size = hba->max_cqes * BNX2I_CQE_SIZE; + ep->qp.cq_mem_size = + (ep->qp.cq_mem_size + (PAGE_SIZE - 1)) & PAGE_MASK; + ep->qp.cq_pgtbl_size = + (ep->qp.cq_mem_size / PAGE_SIZE) * sizeof(void *); + ep->qp.cq_pgtbl_size = + (ep->qp.cq_pgtbl_size + (PAGE_SIZE - 1)) & PAGE_MASK; + + ep->qp.cq_pgtbl_virt = + dma_alloc_coherent(&hba->pcidev->dev, ep->qp.cq_pgtbl_size, + &ep->qp.cq_pgtbl_phys, GFP_KERNEL); + if (!ep->qp.cq_pgtbl_virt) { + printk(KERN_ALERT "bnx2i: unable to alloc CQ PT memory %d\n", + ep->qp.cq_pgtbl_size); + goto mem_alloc_err; + } + + /* Allocate memory area for actual CQ element */ + ep->qp.cq_virt = + dma_alloc_coherent(&hba->pcidev->dev, ep->qp.cq_mem_size, + &ep->qp.cq_phys, GFP_KERNEL); + if (!ep->qp.cq_virt) { + printk(KERN_ALERT "bnx2i: unable to alloc CQ BD memory %d\n", + ep->qp.cq_mem_size); + goto mem_alloc_err; + } + memset(ep->qp.cq_virt, 0x00, ep->qp.cq_mem_size); + + ep->qp.cq_first_qe = ep->qp.cq_virt; + ep->qp.cq_prod_qe = ep->qp.cq_first_qe; + ep->qp.cq_cons_qe = ep->qp.cq_first_qe; + ep->qp.cq_last_qe = &ep->qp.cq_first_qe[hba->max_cqes - 1]; + ep->qp.cq_prod_idx = 0; + ep->qp.cq_cons_idx = 0; + ep->qp.cqe_left = hba->max_cqes; + ep->qp.cqe_exp_seq_sn = ISCSI_INITIAL_SN; + ep->qp.cqe_size = hba->max_cqes; + + /* Invalidate all EQ CQE index, req only for 57710 */ + cq_db = (struct bnx2i_5771x_cq_db *) ep->qp.cq_pgtbl_virt; + memset(cq_db->sqn, 0xFF, sizeof(cq_db->sqn[0]) * BNX2X_MAX_CQS); + + /* Allocate page table memory for RQ which is page aligned */ + ep->qp.rq_mem_size = hba->max_rqes * BNX2I_RQ_WQE_SIZE; + ep->qp.rq_mem_size = + (ep->qp.rq_mem_size + (PAGE_SIZE - 1)) & PAGE_MASK; + ep->qp.rq_pgtbl_size = + (ep->qp.rq_mem_size / PAGE_SIZE) * sizeof(void *); + ep->qp.rq_pgtbl_size = + (ep->qp.rq_pgtbl_size + (PAGE_SIZE - 1)) & PAGE_MASK; + + ep->qp.rq_pgtbl_virt = + dma_alloc_coherent(&hba->pcidev->dev, ep->qp.rq_pgtbl_size, + &ep->qp.rq_pgtbl_phys, GFP_KERNEL); + if (!ep->qp.rq_pgtbl_virt) { + printk(KERN_ALERT "bnx2i: unable to alloc RQ PT mem %d\n", + ep->qp.rq_pgtbl_size); + goto mem_alloc_err; + } + + /* Allocate memory area for actual RQ element */ + ep->qp.rq_virt = + dma_alloc_coherent(&hba->pcidev->dev, ep->qp.rq_mem_size, + &ep->qp.rq_phys, GFP_KERNEL); + if (!ep->qp.rq_virt) { + printk(KERN_ALERT "bnx2i: unable to alloc RQ BD memory %d\n", + ep->qp.rq_mem_size); + goto mem_alloc_err; + } + + ep->qp.rq_first_qe = ep->qp.rq_virt; + ep->qp.rq_prod_qe = ep->qp.rq_first_qe; + ep->qp.rq_cons_qe = ep->qp.rq_first_qe; + ep->qp.rq_last_qe = &ep->qp.rq_first_qe[hba->max_rqes - 1]; + ep->qp.rq_prod_idx = 0x8000; + ep->qp.rq_cons_idx = 0; + ep->qp.rqe_left = hba->max_rqes; + + setup_qp_page_tables(ep); + + return 0; + +mem_alloc_err: + bnx2i_free_qp_resc(hba, ep); + return -ENOMEM; +} + + + +/** + * bnx2i_free_qp_resc - free memory resources held by QP + * @hba: adapter structure pointer + * @ep: endpoint (transport indentifier) structure + * + * Free QP resources - SQ/RQ/CQ memory and page tables. + */ +void bnx2i_free_qp_resc(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep) +{ + if (ep->qp.ctx_base) { + iounmap(ep->qp.ctx_base); + ep->qp.ctx_base = NULL; + } + /* Free SQ mem */ + if (ep->qp.sq_pgtbl_virt) { + dma_free_coherent(&hba->pcidev->dev, ep->qp.sq_pgtbl_size, + ep->qp.sq_pgtbl_virt, ep->qp.sq_pgtbl_phys); + ep->qp.sq_pgtbl_virt = NULL; + ep->qp.sq_pgtbl_phys = 0; + } + if (ep->qp.sq_virt) { + dma_free_coherent(&hba->pcidev->dev, ep->qp.sq_mem_size, + ep->qp.sq_virt, ep->qp.sq_phys); + ep->qp.sq_virt = NULL; + ep->qp.sq_phys = 0; + } + + /* Free RQ mem */ + if (ep->qp.rq_pgtbl_virt) { + dma_free_coherent(&hba->pcidev->dev, ep->qp.rq_pgtbl_size, + ep->qp.rq_pgtbl_virt, ep->qp.rq_pgtbl_phys); + ep->qp.rq_pgtbl_virt = NULL; + ep->qp.rq_pgtbl_phys = 0; + } + if (ep->qp.rq_virt) { + dma_free_coherent(&hba->pcidev->dev, ep->qp.rq_mem_size, + ep->qp.rq_virt, ep->qp.rq_phys); + ep->qp.rq_virt = NULL; + ep->qp.rq_phys = 0; + } + + /* Free CQ mem */ + if (ep->qp.cq_pgtbl_virt) { + dma_free_coherent(&hba->pcidev->dev, ep->qp.cq_pgtbl_size, + ep->qp.cq_pgtbl_virt, ep->qp.cq_pgtbl_phys); + ep->qp.cq_pgtbl_virt = NULL; + ep->qp.cq_pgtbl_phys = 0; + } + if (ep->qp.cq_virt) { + dma_free_coherent(&hba->pcidev->dev, ep->qp.cq_mem_size, + ep->qp.cq_virt, ep->qp.cq_phys); + ep->qp.cq_virt = NULL; + ep->qp.cq_phys = 0; + } +} + + +/** + * bnx2i_send_fw_iscsi_init_msg - initiates initial handshake with iscsi f/w + * @hba: adapter structure pointer + * + * Send down iscsi_init KWQEs which initiates the initial handshake with the f/w + * This results in iSCSi support validation and on-chip context manager + * initialization. Firmware completes this handshake with a CQE carrying + * the result of iscsi support validation. Parameter carried by + * iscsi init request determines the number of offloaded connection and + * tolerance level for iscsi protocol violation this hba/chip can support + */ +int bnx2i_send_fw_iscsi_init_msg(struct bnx2i_hba *hba) +{ + struct kwqe *kwqe_arr[3]; + struct iscsi_kwqe_init1 iscsi_init; + struct iscsi_kwqe_init2 iscsi_init2; + int rc = 0; + u64 mask64; + + bnx2i_adjust_qp_size(hba); + + iscsi_init.flags = + ISCSI_PAGE_SIZE_4K << ISCSI_KWQE_INIT1_PAGE_SIZE_SHIFT; + if (en_tcp_dack) + iscsi_init.flags |= ISCSI_KWQE_INIT1_DELAYED_ACK_ENABLE; + iscsi_init.reserved0 = 0; + iscsi_init.num_cqs = 1; + iscsi_init.hdr.op_code = ISCSI_KWQE_OPCODE_INIT1; + iscsi_init.hdr.flags = + (ISCSI_KWQE_LAYER_CODE << ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT); + + iscsi_init.dummy_buffer_addr_lo = (u32) hba->dummy_buf_dma; + iscsi_init.dummy_buffer_addr_hi = + (u32) ((u64) hba->dummy_buf_dma >> 32); + + hba->ctx_ccell_tasks = + ((hba->num_ccell & 0xFFFF) | (hba->max_sqes << 16)); + iscsi_init.num_ccells_per_conn = hba->num_ccell; + iscsi_init.num_tasks_per_conn = hba->max_sqes; + iscsi_init.sq_wqes_per_page = PAGE_SIZE / BNX2I_SQ_WQE_SIZE; + iscsi_init.sq_num_wqes = hba->max_sqes; + iscsi_init.cq_log_wqes_per_page = + (u8) bnx2i_power_of2(PAGE_SIZE / BNX2I_CQE_SIZE); + iscsi_init.cq_num_wqes = hba->max_cqes; + iscsi_init.cq_num_pages = (hba->max_cqes * BNX2I_CQE_SIZE + + (PAGE_SIZE - 1)) / PAGE_SIZE; + iscsi_init.sq_num_pages = (hba->max_sqes * BNX2I_SQ_WQE_SIZE + + (PAGE_SIZE - 1)) / PAGE_SIZE; + iscsi_init.rq_buffer_size = BNX2I_RQ_WQE_SIZE; + iscsi_init.rq_num_wqes = hba->max_rqes; + + + iscsi_init2.hdr.op_code = ISCSI_KWQE_OPCODE_INIT2; + iscsi_init2.hdr.flags = + (ISCSI_KWQE_LAYER_CODE << ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT); + iscsi_init2.max_cq_sqn = hba->max_cqes * 2 + 1; + mask64 = 0x0ULL; + mask64 |= ( + /* CISCO MDS */ + (1UL << + ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_TTT_NOT_RSRV) | + /* HP MSA1510i */ + (1UL << + ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_EXP_DATASN) | + /* EMC */ + (1ULL << ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_LUN)); + if (error_mask1) + iscsi_init2.error_bit_map[0] = error_mask1; + else + iscsi_init2.error_bit_map[0] = (u32) mask64; + + if (error_mask2) + iscsi_init2.error_bit_map[1] = error_mask2; + else + iscsi_init2.error_bit_map[1] = (u32) (mask64 >> 32); + + iscsi_error_mask = mask64; + + kwqe_arr[0] = (struct kwqe *) &iscsi_init; + kwqe_arr[1] = (struct kwqe *) &iscsi_init2; + + if (hba->cnic && hba->cnic->submit_kwqes) + rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, 2); + return rc; +} + + +/** + * bnx2i_process_scsi_cmd_resp - this function handles scsi cmd completion. + * @conn: iscsi connection + * @cqe: pointer to newly DMA'ed CQE entry for processing + * + * process SCSI CMD Response CQE & complete the request to SCSI-ML + */ +static int bnx2i_process_scsi_cmd_resp(struct iscsi_session *session, + struct bnx2i_conn *bnx2i_conn, + struct cqe *cqe) +{ + struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data; + struct bnx2i_cmd_response *resp_cqe; + struct bnx2i_cmd *bnx2i_cmd; + struct iscsi_task *task; + struct iscsi_cmd_rsp *hdr; + u32 datalen = 0; + + resp_cqe = (struct bnx2i_cmd_response *)cqe; + spin_lock(&session->lock); + task = iscsi_itt_to_task(conn, + resp_cqe->itt & ISCSI_CMD_RESPONSE_INDEX); + if (!task) + goto fail; + + bnx2i_cmd = task->dd_data; + + if (bnx2i_cmd->req.op_attr & ISCSI_CMD_REQUEST_READ) { + conn->datain_pdus_cnt += + resp_cqe->task_stat.read_stat.num_data_outs; + conn->rxdata_octets += + bnx2i_cmd->req.total_data_transfer_length; + } else { + conn->dataout_pdus_cnt += + resp_cqe->task_stat.read_stat.num_data_outs; + conn->r2t_pdus_cnt += + resp_cqe->task_stat.read_stat.num_r2ts; + conn->txdata_octets += + bnx2i_cmd->req.total_data_transfer_length; + } + bnx2i_iscsi_unmap_sg_list(bnx2i_cmd); + + hdr = (struct iscsi_cmd_rsp *)task->hdr; + resp_cqe = (struct bnx2i_cmd_response *)cqe; + hdr->opcode = resp_cqe->op_code; + hdr->max_cmdsn = cpu_to_be32(resp_cqe->max_cmd_sn); + hdr->exp_cmdsn = cpu_to_be32(resp_cqe->exp_cmd_sn); + hdr->response = resp_cqe->response; + hdr->cmd_status = resp_cqe->status; + hdr->flags = resp_cqe->response_flags; + hdr->residual_count = cpu_to_be32(resp_cqe->residual_count); + + if (resp_cqe->op_code == ISCSI_OP_SCSI_DATA_IN) + goto done; + + if (resp_cqe->status == SAM_STAT_CHECK_CONDITION) { + datalen = resp_cqe->data_length; + if (datalen < 2) + goto done; + + if (datalen > BNX2I_RQ_WQE_SIZE) { + iscsi_conn_printk(KERN_ERR, conn, + "sense data len %d > RQ sz\n", + datalen); + datalen = BNX2I_RQ_WQE_SIZE; + } else if (datalen > ISCSI_DEF_MAX_RECV_SEG_LEN) { + iscsi_conn_printk(KERN_ERR, conn, + "sense data len %d > conn data\n", + datalen); + datalen = ISCSI_DEF_MAX_RECV_SEG_LEN; + } + + bnx2i_get_rq_buf(bnx2i_cmd->conn, conn->data, datalen); + bnx2i_put_rq_buf(bnx2i_cmd->conn, 1); + } + +done: + __iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, + conn->data, datalen); +fail: + spin_unlock(&session->lock); + return 0; +} + + +/** + * bnx2i_process_login_resp - this function handles iscsi login response + * @session: iscsi session pointer + * @bnx2i_conn: iscsi connection pointer + * @cqe: pointer to newly DMA'ed CQE entry for processing + * + * process Login Response CQE & complete it to open-iscsi user daemon + */ +static int bnx2i_process_login_resp(struct iscsi_session *session, + struct bnx2i_conn *bnx2i_conn, + struct cqe *cqe) +{ + struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data; + struct iscsi_task *task; + struct bnx2i_login_response *login; + struct iscsi_login_rsp *resp_hdr; + int pld_len; + int pad_len; + + login = (struct bnx2i_login_response *) cqe; + spin_lock(&session->lock); + task = iscsi_itt_to_task(conn, + login->itt & ISCSI_LOGIN_RESPONSE_INDEX); + if (!task) + goto done; + + resp_hdr = (struct iscsi_login_rsp *) &bnx2i_conn->gen_pdu.resp_hdr; + memset(resp_hdr, 0, sizeof(struct iscsi_hdr)); + resp_hdr->opcode = login->op_code; + resp_hdr->flags = login->response_flags; + resp_hdr->max_version = login->version_max; + resp_hdr->active_version = login->version_active;; + resp_hdr->hlength = 0; + + hton24(resp_hdr->dlength, login->data_length); + memcpy(resp_hdr->isid, &login->isid_lo, 6); + resp_hdr->tsih = cpu_to_be16(login->tsih); + resp_hdr->itt = task->hdr->itt; + resp_hdr->statsn = cpu_to_be32(login->stat_sn); + resp_hdr->exp_cmdsn = cpu_to_be32(login->exp_cmd_sn); + resp_hdr->max_cmdsn = cpu_to_be32(login->max_cmd_sn); + resp_hdr->status_class = login->status_class; + resp_hdr->status_detail = login->status_detail; + pld_len = login->data_length; + bnx2i_conn->gen_pdu.resp_wr_ptr = + bnx2i_conn->gen_pdu.resp_buf + pld_len; + + pad_len = 0; + if (pld_len & 0x3) + pad_len = 4 - (pld_len % 4); + + if (pad_len) { + int i = 0; + for (i = 0; i < pad_len; i++) { + bnx2i_conn->gen_pdu.resp_wr_ptr[0] = 0; + bnx2i_conn->gen_pdu.resp_wr_ptr++; + } + } + + __iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr, + bnx2i_conn->gen_pdu.resp_buf, + bnx2i_conn->gen_pdu.resp_wr_ptr - bnx2i_conn->gen_pdu.resp_buf); +done: + spin_unlock(&session->lock); + return 0; +} + +/** + * bnx2i_process_tmf_resp - this function handles iscsi TMF response + * @session: iscsi session pointer + * @bnx2i_conn: iscsi connection pointer + * @cqe: pointer to newly DMA'ed CQE entry for processing + * + * process iSCSI TMF Response CQE and wake up the driver eh thread. + */ +static int bnx2i_process_tmf_resp(struct iscsi_session *session, + struct bnx2i_conn *bnx2i_conn, + struct cqe *cqe) +{ + struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data; + struct iscsi_task *task; + struct bnx2i_tmf_response *tmf_cqe; + struct iscsi_tm_rsp *resp_hdr; + + tmf_cqe = (struct bnx2i_tmf_response *)cqe; + spin_lock(&session->lock); + task = iscsi_itt_to_task(conn, + tmf_cqe->itt & ISCSI_TMF_RESPONSE_INDEX); + if (!task) + goto done; + + resp_hdr = (struct iscsi_tm_rsp *) &bnx2i_conn->gen_pdu.resp_hdr; + memset(resp_hdr, 0, sizeof(struct iscsi_hdr)); + resp_hdr->opcode = tmf_cqe->op_code; + resp_hdr->max_cmdsn = cpu_to_be32(tmf_cqe->max_cmd_sn); + resp_hdr->exp_cmdsn = cpu_to_be32(tmf_cqe->exp_cmd_sn); + resp_hdr->itt = task->hdr->itt; + resp_hdr->response = tmf_cqe->response; + + __iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr, NULL, 0); +done: + spin_unlock(&session->lock); + return 0; +} + +/** + * bnx2i_process_logout_resp - this function handles iscsi logout response + * @session: iscsi session pointer + * @bnx2i_conn: iscsi connection pointer + * @cqe: pointer to newly DMA'ed CQE entry for processing + * + * process iSCSI Logout Response CQE & make function call to + * notify the user daemon. + */ +static int bnx2i_process_logout_resp(struct iscsi_session *session, + struct bnx2i_conn *bnx2i_conn, + struct cqe *cqe) +{ + struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data; + struct iscsi_task *task; + struct bnx2i_logout_response *logout; + struct iscsi_logout_rsp *resp_hdr; + + logout = (struct bnx2i_logout_response *) cqe; + spin_lock(&session->lock); + task = iscsi_itt_to_task(conn, + logout->itt & ISCSI_LOGOUT_RESPONSE_INDEX); + if (!task) + goto done; + + resp_hdr = (struct iscsi_logout_rsp *) &bnx2i_conn->gen_pdu.resp_hdr; + memset(resp_hdr, 0, sizeof(struct iscsi_hdr)); + resp_hdr->opcode = logout->op_code; + resp_hdr->flags = logout->response; + resp_hdr->hlength = 0; + + resp_hdr->itt = task->hdr->itt; + resp_hdr->statsn = task->hdr->exp_statsn; + resp_hdr->exp_cmdsn = cpu_to_be32(logout->exp_cmd_sn); + resp_hdr->max_cmdsn = cpu_to_be32(logout->max_cmd_sn); + + resp_hdr->t2wait = cpu_to_be32(logout->time_to_wait); + resp_hdr->t2retain = cpu_to_be32(logout->time_to_retain); + + __iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr, NULL, 0); +done: + spin_unlock(&session->lock); + return 0; +} + +/** + * bnx2i_process_nopin_local_cmpl - this function handles iscsi nopin CQE + * @session: iscsi session pointer + * @bnx2i_conn: iscsi connection pointer + * @cqe: pointer to newly DMA'ed CQE entry for processing + * + * process iSCSI NOPIN local completion CQE, frees IIT and command structures + */ +static void bnx2i_process_nopin_local_cmpl(struct iscsi_session *session, + struct bnx2i_conn *bnx2i_conn, + struct cqe *cqe) +{ + struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data; + struct bnx2i_nop_in_msg *nop_in; + struct iscsi_task *task; + + nop_in = (struct bnx2i_nop_in_msg *)cqe; + spin_lock(&session->lock); + task = iscsi_itt_to_task(conn, + nop_in->itt & ISCSI_NOP_IN_MSG_INDEX); + if (task) + iscsi_put_task(task); + spin_unlock(&session->lock); +} + +/** + * bnx2i_unsol_pdu_adjust_rq - makes adjustments to RQ after unsol pdu is recvd + * @conn: iscsi connection + * + * Firmware advances RQ producer index for every unsolicited PDU even if + * payload data length is '0'. This function makes corresponding + * adjustments on the driver side to match this f/w behavior + */ +static void bnx2i_unsol_pdu_adjust_rq(struct bnx2i_conn *bnx2i_conn) +{ + char dummy_rq_data[2]; + bnx2i_get_rq_buf(bnx2i_conn, dummy_rq_data, 1); + bnx2i_put_rq_buf(bnx2i_conn, 1); +} + + +/** + * bnx2i_process_nopin_mesg - this function handles iscsi nopin CQE + * @session: iscsi session pointer + * @bnx2i_conn: iscsi connection pointer + * @cqe: pointer to newly DMA'ed CQE entry for processing + * + * process iSCSI target's proactive iSCSI NOPIN request + */ +static int bnx2i_process_nopin_mesg(struct iscsi_session *session, + struct bnx2i_conn *bnx2i_conn, + struct cqe *cqe) +{ + struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data; + struct iscsi_task *task; + struct bnx2i_nop_in_msg *nop_in; + struct iscsi_nopin *hdr; + u32 itt; + int tgt_async_nop = 0; + + nop_in = (struct bnx2i_nop_in_msg *)cqe; + itt = nop_in->itt & ISCSI_NOP_IN_MSG_INDEX; + + spin_lock(&session->lock); + hdr = (struct iscsi_nopin *)&bnx2i_conn->gen_pdu.resp_hdr; + memset(hdr, 0, sizeof(struct iscsi_hdr)); + hdr->opcode = nop_in->op_code; + hdr->max_cmdsn = cpu_to_be32(nop_in->max_cmd_sn); + hdr->exp_cmdsn = cpu_to_be32(nop_in->exp_cmd_sn); + hdr->ttt = cpu_to_be32(nop_in->ttt); + + if (itt == (u16) RESERVED_ITT) { + bnx2i_unsol_pdu_adjust_rq(bnx2i_conn); + hdr->itt = RESERVED_ITT; + tgt_async_nop = 1; + goto done; + } + + /* this is a response to one of our nop-outs */ + task = iscsi_itt_to_task(conn, itt); + if (task) { + hdr->flags = ISCSI_FLAG_CMD_FINAL; + hdr->itt = task->hdr->itt; + hdr->ttt = cpu_to_be32(nop_in->ttt); + memcpy(hdr->lun, nop_in->lun, 8); + } +done: + __iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, NULL, 0); + spin_unlock(&session->lock); + + return tgt_async_nop; +} + + +/** + * bnx2i_process_async_mesg - this function handles iscsi async message + * @session: iscsi session pointer + * @bnx2i_conn: iscsi connection pointer + * @cqe: pointer to newly DMA'ed CQE entry for processing + * + * process iSCSI ASYNC Message + */ +static void bnx2i_process_async_mesg(struct iscsi_session *session, + struct bnx2i_conn *bnx2i_conn, + struct cqe *cqe) +{ + struct bnx2i_async_msg *async_cqe; + struct iscsi_async *resp_hdr; + u8 async_event; + + bnx2i_unsol_pdu_adjust_rq(bnx2i_conn); + + async_cqe = (struct bnx2i_async_msg *)cqe; + async_event = async_cqe->async_event; + + if (async_event == ISCSI_ASYNC_MSG_SCSI_EVENT) { + iscsi_conn_printk(KERN_ALERT, bnx2i_conn->cls_conn->dd_data, + "async: scsi events not supported\n"); + return; + } + + spin_lock(&session->lock); + resp_hdr = (struct iscsi_async *) &bnx2i_conn->gen_pdu.resp_hdr; + memset(resp_hdr, 0, sizeof(struct iscsi_hdr)); + resp_hdr->opcode = async_cqe->op_code; + resp_hdr->flags = 0x80; + + memcpy(resp_hdr->lun, async_cqe->lun, 8); + resp_hdr->exp_cmdsn = cpu_to_be32(async_cqe->exp_cmd_sn); + resp_hdr->max_cmdsn = cpu_to_be32(async_cqe->max_cmd_sn); + + resp_hdr->async_event = async_cqe->async_event; + resp_hdr->async_vcode = async_cqe->async_vcode; + + resp_hdr->param1 = cpu_to_be16(async_cqe->param1); + resp_hdr->param2 = cpu_to_be16(async_cqe->param2); + resp_hdr->param3 = cpu_to_be16(async_cqe->param3); + + __iscsi_complete_pdu(bnx2i_conn->cls_conn->dd_data, + (struct iscsi_hdr *)resp_hdr, NULL, 0); + spin_unlock(&session->lock); +} + + +/** + * bnx2i_process_reject_mesg - process iscsi reject pdu + * @session: iscsi session pointer + * @bnx2i_conn: iscsi connection pointer + * @cqe: pointer to newly DMA'ed CQE entry for processing + * + * process iSCSI REJECT message + */ +static void bnx2i_process_reject_mesg(struct iscsi_session *session, + struct bnx2i_conn *bnx2i_conn, + struct cqe *cqe) +{ + struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data; + struct bnx2i_reject_msg *reject; + struct iscsi_reject *hdr; + + reject = (struct bnx2i_reject_msg *) cqe; + if (reject->data_length) { + bnx2i_get_rq_buf(bnx2i_conn, conn->data, reject->data_length); + bnx2i_put_rq_buf(bnx2i_conn, 1); + } else + bnx2i_unsol_pdu_adjust_rq(bnx2i_conn); + + spin_lock(&session->lock); + hdr = (struct iscsi_reject *) &bnx2i_conn->gen_pdu.resp_hdr; + memset(hdr, 0, sizeof(struct iscsi_hdr)); + hdr->opcode = reject->op_code; + hdr->reason = reject->reason; + hton24(hdr->dlength, reject->data_length); + hdr->max_cmdsn = cpu_to_be32(reject->max_cmd_sn); + hdr->exp_cmdsn = cpu_to_be32(reject->exp_cmd_sn); + hdr->ffffffff = cpu_to_be32(RESERVED_ITT); + __iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, conn->data, + reject->data_length); + spin_unlock(&session->lock); +} + +/** + * bnx2i_process_cmd_cleanup_resp - process scsi command clean-up completion + * @session: iscsi session pointer + * @bnx2i_conn: iscsi connection pointer + * @cqe: pointer to newly DMA'ed CQE entry for processing + * + * process command cleanup response CQE during conn shutdown or error recovery + */ +static void bnx2i_process_cmd_cleanup_resp(struct iscsi_session *session, + struct bnx2i_conn *bnx2i_conn, + struct cqe *cqe) +{ + struct bnx2i_cleanup_response *cmd_clean_rsp; + struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data; + struct iscsi_task *task; + + cmd_clean_rsp = (struct bnx2i_cleanup_response *)cqe; + spin_lock(&session->lock); + task = iscsi_itt_to_task(conn, + cmd_clean_rsp->itt & ISCSI_CLEANUP_RESPONSE_INDEX); + if (!task) + printk(KERN_ALERT "bnx2i: cmd clean ITT %x not active\n", + cmd_clean_rsp->itt & ISCSI_CLEANUP_RESPONSE_INDEX); + spin_unlock(&session->lock); + complete(&bnx2i_conn->cmd_cleanup_cmpl); +} + + + +/** + * bnx2i_process_new_cqes - process newly DMA'ed CQE's + * @bnx2i_conn: iscsi connection + * + * this function is called by generic KCQ handler to process all pending CQE's + */ +static void bnx2i_process_new_cqes(struct bnx2i_conn *bnx2i_conn) +{ + struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data; + struct iscsi_session *session = conn->session; + struct qp_info *qp = &bnx2i_conn->ep->qp; + struct bnx2i_nop_in_msg *nopin; + int tgt_async_msg; + + while (1) { + nopin = (struct bnx2i_nop_in_msg *) qp->cq_cons_qe; + if (nopin->cq_req_sn != qp->cqe_exp_seq_sn) + break; + + if (unlikely(test_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx))) + break; + + tgt_async_msg = 0; + + switch (nopin->op_code) { + case ISCSI_OP_SCSI_CMD_RSP: + case ISCSI_OP_SCSI_DATA_IN: + bnx2i_process_scsi_cmd_resp(session, bnx2i_conn, + qp->cq_cons_qe); + break; + case ISCSI_OP_LOGIN_RSP: + bnx2i_process_login_resp(session, bnx2i_conn, + qp->cq_cons_qe); + break; + case ISCSI_OP_SCSI_TMFUNC_RSP: + bnx2i_process_tmf_resp(session, bnx2i_conn, + qp->cq_cons_qe); + break; + case ISCSI_OP_LOGOUT_RSP: + bnx2i_process_logout_resp(session, bnx2i_conn, + qp->cq_cons_qe); + break; + case ISCSI_OP_NOOP_IN: + if (bnx2i_process_nopin_mesg(session, bnx2i_conn, + qp->cq_cons_qe)) + tgt_async_msg = 1; + break; + case ISCSI_OPCODE_NOPOUT_LOCAL_COMPLETION: + bnx2i_process_nopin_local_cmpl(session, bnx2i_conn, + qp->cq_cons_qe); + break; + case ISCSI_OP_ASYNC_EVENT: + bnx2i_process_async_mesg(session, bnx2i_conn, + qp->cq_cons_qe); + tgt_async_msg = 1; + break; + case ISCSI_OP_REJECT: + bnx2i_process_reject_mesg(session, bnx2i_conn, + qp->cq_cons_qe); + break; + case ISCSI_OPCODE_CLEANUP_RESPONSE: + bnx2i_process_cmd_cleanup_resp(session, bnx2i_conn, + qp->cq_cons_qe); + break; + default: + printk(KERN_ALERT "bnx2i: unknown opcode 0x%x\n", + nopin->op_code); + } + + if (!tgt_async_msg) + bnx2i_conn->ep->num_active_cmds--; + + /* clear out in production version only, till beta keep opcode + * field intact, will be helpful in debugging (context dump) + * nopin->op_code = 0; + */ + qp->cqe_exp_seq_sn++; + if (qp->cqe_exp_seq_sn == (qp->cqe_size * 2 + 1)) + qp->cqe_exp_seq_sn = ISCSI_INITIAL_SN; + + if (qp->cq_cons_qe == qp->cq_last_qe) { + qp->cq_cons_qe = qp->cq_first_qe; + qp->cq_cons_idx = 0; + } else { + qp->cq_cons_qe++; + qp->cq_cons_idx++; + } + } + bnx2i_arm_cq_event_coalescing(bnx2i_conn->ep, CNIC_ARM_CQE); +} + +/** + * bnx2i_fastpath_notification - process global event queue (KCQ) + * @hba: adapter structure pointer + * @new_cqe_kcqe: pointer to newly DMA'ed KCQE entry + * + * Fast path event notification handler, KCQ entry carries context id + * of the connection that has 1 or more pending CQ entries + */ +static void bnx2i_fastpath_notification(struct bnx2i_hba *hba, + struct iscsi_kcqe *new_cqe_kcqe) +{ + struct bnx2i_conn *conn; + u32 iscsi_cid; + + iscsi_cid = new_cqe_kcqe->iscsi_conn_id; + conn = bnx2i_get_conn_from_id(hba, iscsi_cid); + + if (!conn) { + printk(KERN_ALERT "cid #%x not valid\n", iscsi_cid); + return; + } + if (!conn->ep) { + printk(KERN_ALERT "cid #%x - ep not bound\n", iscsi_cid); + return; + } + + bnx2i_process_new_cqes(conn); +} + + +/** + * bnx2i_process_update_conn_cmpl - process iscsi conn update completion KCQE + * @hba: adapter structure pointer + * @update_kcqe: kcqe pointer + * + * CONN_UPDATE completion handler, this completes iSCSI connection FFP migration + */ +static void bnx2i_process_update_conn_cmpl(struct bnx2i_hba *hba, + struct iscsi_kcqe *update_kcqe) +{ + struct bnx2i_conn *conn; + u32 iscsi_cid; + + iscsi_cid = update_kcqe->iscsi_conn_id; + conn = bnx2i_get_conn_from_id(hba, iscsi_cid); + + if (!conn) { + printk(KERN_ALERT "conn_update: cid %x not valid\n", iscsi_cid); + return; + } + if (!conn->ep) { + printk(KERN_ALERT "cid %x does not have ep bound\n", iscsi_cid); + return; + } + + if (update_kcqe->completion_status) { + printk(KERN_ALERT "request failed cid %x\n", iscsi_cid); + conn->ep->state = EP_STATE_ULP_UPDATE_FAILED; + } else + conn->ep->state = EP_STATE_ULP_UPDATE_COMPL; + + wake_up_interruptible(&conn->ep->ofld_wait); +} + + +/** + * bnx2i_recovery_que_add_conn - add connection to recovery queue + * @hba: adapter structure pointer + * @bnx2i_conn: iscsi connection + * + * Add connection to recovery queue and schedule adapter eh worker + */ +static void bnx2i_recovery_que_add_conn(struct bnx2i_hba *hba, + struct bnx2i_conn *bnx2i_conn) +{ + iscsi_conn_failure(bnx2i_conn->cls_conn->dd_data, + ISCSI_ERR_CONN_FAILED); +} + + +/** + * bnx2i_process_tcp_error - process error notification on a given connection + * + * @hba: adapter structure pointer + * @tcp_err: tcp error kcqe pointer + * + * handles tcp level error notifications from FW. + */ +static void bnx2i_process_tcp_error(struct bnx2i_hba *hba, + struct iscsi_kcqe *tcp_err) +{ + struct bnx2i_conn *bnx2i_conn; + u32 iscsi_cid; + + iscsi_cid = tcp_err->iscsi_conn_id; + bnx2i_conn = bnx2i_get_conn_from_id(hba, iscsi_cid); + + if (!bnx2i_conn) { + printk(KERN_ALERT "bnx2i - cid 0x%x not valid\n", iscsi_cid); + return; + } + + printk(KERN_ALERT "bnx2i - cid 0x%x had TCP errors, error code 0x%x\n", + iscsi_cid, tcp_err->completion_status); + bnx2i_recovery_que_add_conn(bnx2i_conn->hba, bnx2i_conn); +} + + +/** + * bnx2i_process_iscsi_error - process error notification on a given connection + * @hba: adapter structure pointer + * @iscsi_err: iscsi error kcqe pointer + * + * handles iscsi error notifications from the FW. Firmware based in initial + * handshake classifies iscsi protocol / TCP rfc violation into either + * warning or error indications. If indication is of "Error" type, driver + * will initiate session recovery for that connection/session. For + * "Warning" type indication, driver will put out a system log message + * (there will be only one message for each type for the life of the + * session, this is to avoid un-necessarily overloading the system) + */ +static void bnx2i_process_iscsi_error(struct bnx2i_hba *hba, + struct iscsi_kcqe *iscsi_err) +{ + struct bnx2i_conn *bnx2i_conn; + u32 iscsi_cid; + char warn_notice[] = "iscsi_warning"; + char error_notice[] = "iscsi_error"; + char additional_notice[64]; + char *message; + int need_recovery; + u64 err_mask64; + + iscsi_cid = iscsi_err->iscsi_conn_id; + bnx2i_conn = bnx2i_get_conn_from_id(hba, iscsi_cid); + if (!bnx2i_conn) { + printk(KERN_ALERT "bnx2i - cid 0x%x not valid\n", iscsi_cid); + return; + } + + err_mask64 = (0x1ULL << iscsi_err->completion_status); + + if (err_mask64 & iscsi_error_mask) { + need_recovery = 0; + message = warn_notice; + } else { + need_recovery = 1; + message = error_notice; + } + + switch (iscsi_err->completion_status) { + case ISCSI_KCQE_COMPLETION_STATUS_HDR_DIG_ERR: + strcpy(additional_notice, "hdr digest err"); + break; + case ISCSI_KCQE_COMPLETION_STATUS_DATA_DIG_ERR: + strcpy(additional_notice, "data digest err"); + break; + case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_OPCODE: + strcpy(additional_notice, "wrong opcode rcvd"); + break; + case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_AHS_LEN: + strcpy(additional_notice, "AHS len > 0 rcvd"); + break; + case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_ITT: + strcpy(additional_notice, "invalid ITT rcvd"); + break; + case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_STATSN: + strcpy(additional_notice, "wrong StatSN rcvd"); + break; + case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_EXP_DATASN: + strcpy(additional_notice, "wrong DataSN rcvd"); + break; + case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_PEND_R2T: + strcpy(additional_notice, "pend R2T violation"); + break; + case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_0: + strcpy(additional_notice, "ERL0, UO"); + break; + case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_1: + strcpy(additional_notice, "ERL0, U1"); + break; + case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_2: + strcpy(additional_notice, "ERL0, U2"); + break; + case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_3: + strcpy(additional_notice, "ERL0, U3"); + break; + case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_4: + strcpy(additional_notice, "ERL0, U4"); + break; + case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_5: + strcpy(additional_notice, "ERL0, U5"); + break; + case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_6: + strcpy(additional_notice, "ERL0, U6"); + break; + case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_REMAIN_RCV_LEN: + strcpy(additional_notice, "invalid resi len"); + break; + case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_MAX_RCV_PDU_LEN: + strcpy(additional_notice, "MRDSL violation"); + break; + case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_F_BIT_ZERO: + strcpy(additional_notice, "F-bit not set"); + break; + case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_TTT_NOT_RSRV: + strcpy(additional_notice, "invalid TTT"); + break; + case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_DATASN: + strcpy(additional_notice, "invalid DataSN"); + break; + case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_REMAIN_BURST_LEN: + strcpy(additional_notice, "burst len violation"); + break; + case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_BUFFER_OFF: + strcpy(additional_notice, "buf offset violation"); + break; + case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_LUN: + strcpy(additional_notice, "invalid LUN field"); + break; + case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_R2TSN: + strcpy(additional_notice, "invalid R2TSN field"); + break; +#define BNX2I_ERR_DESIRED_DATA_TRNS_LEN_0 \ + ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_DESIRED_DATA_TRNS_LEN_0 + case BNX2I_ERR_DESIRED_DATA_TRNS_LEN_0: + strcpy(additional_notice, "invalid cmd len1"); + break; +#define BNX2I_ERR_DESIRED_DATA_TRNS_LEN_1 \ + ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_DESIRED_DATA_TRNS_LEN_1 + case BNX2I_ERR_DESIRED_DATA_TRNS_LEN_1: + strcpy(additional_notice, "invalid cmd len2"); + break; + case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_PEND_R2T_EXCEED: + strcpy(additional_notice, + "pend r2t exceeds MaxOutstandingR2T value"); + break; + case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_TTT_IS_RSRV: + strcpy(additional_notice, "TTT is rsvd"); + break; + case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_MAX_BURST_LEN: + strcpy(additional_notice, "MBL violation"); + break; +#define BNX2I_ERR_DATA_SEG_LEN_NOT_ZERO \ + ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_DATA_SEG_LEN_NOT_ZERO + case BNX2I_ERR_DATA_SEG_LEN_NOT_ZERO: + strcpy(additional_notice, "data seg len != 0"); + break; + case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_REJECT_PDU_LEN: + strcpy(additional_notice, "reject pdu len error"); + break; + case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_ASYNC_PDU_LEN: + strcpy(additional_notice, "async pdu len error"); + break; + case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_NOPIN_PDU_LEN: + strcpy(additional_notice, "nopin pdu len error"); + break; +#define BNX2_ERR_PEND_R2T_IN_CLEANUP \ + ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_PEND_R2T_IN_CLEANUP + case BNX2_ERR_PEND_R2T_IN_CLEANUP: + strcpy(additional_notice, "pend r2t in cleanup"); + break; + + case ISCI_KCQE_COMPLETION_STATUS_TCP_ERROR_IP_FRAGMENT: + strcpy(additional_notice, "IP fragments rcvd"); + break; + case ISCI_KCQE_COMPLETION_STATUS_TCP_ERROR_IP_OPTIONS: + strcpy(additional_notice, "IP options error"); + break; + case ISCI_KCQE_COMPLETION_STATUS_TCP_ERROR_URGENT_FLAG: + strcpy(additional_notice, "urgent flag error"); + break; + default: + printk(KERN_ALERT "iscsi_err - unknown err %x\n", + iscsi_err->completion_status); + } + + if (need_recovery) { + iscsi_conn_printk(KERN_ALERT, + bnx2i_conn->cls_conn->dd_data, + "bnx2i: %s - %s\n", + message, additional_notice); + + iscsi_conn_printk(KERN_ALERT, + bnx2i_conn->cls_conn->dd_data, + "conn_err - hostno %d conn %p, " + "iscsi_cid %x cid %x\n", + bnx2i_conn->hba->shost->host_no, + bnx2i_conn, bnx2i_conn->ep->ep_iscsi_cid, + bnx2i_conn->ep->ep_cid); + bnx2i_recovery_que_add_conn(bnx2i_conn->hba, bnx2i_conn); + } else + if (!test_and_set_bit(iscsi_err->completion_status, + (void *) &bnx2i_conn->violation_notified)) + iscsi_conn_printk(KERN_ALERT, + bnx2i_conn->cls_conn->dd_data, + "bnx2i: %s - %s\n", + message, additional_notice); +} + + +/** + * bnx2i_process_conn_destroy_cmpl - process iscsi conn destroy completion + * @hba: adapter structure pointer + * @conn_destroy: conn destroy kcqe pointer + * + * handles connection destroy completion request. + */ +static void bnx2i_process_conn_destroy_cmpl(struct bnx2i_hba *hba, + struct iscsi_kcqe *conn_destroy) +{ + struct bnx2i_endpoint *ep; + + ep = bnx2i_find_ep_in_destroy_list(hba, conn_destroy->iscsi_conn_id); + if (!ep) { + printk(KERN_ALERT "bnx2i_conn_destroy_cmpl: no pending " + "offload request, unexpected complection\n"); + return; + } + + if (hba != ep->hba) { + printk(KERN_ALERT "conn destroy- error hba mis-match\n"); + return; + } + + if (conn_destroy->completion_status) { + printk(KERN_ALERT "conn_destroy_cmpl: op failed\n"); + ep->state = EP_STATE_CLEANUP_FAILED; + } else + ep->state = EP_STATE_CLEANUP_CMPL; + wake_up_interruptible(&ep->ofld_wait); +} + + +/** + * bnx2i_process_ofld_cmpl - process initial iscsi conn offload completion + * @hba: adapter structure pointer + * @ofld_kcqe: conn offload kcqe pointer + * + * handles initial connection offload completion, ep_connect() thread is + * woken-up to continue with LLP connect process + */ +static void bnx2i_process_ofld_cmpl(struct bnx2i_hba *hba, + struct iscsi_kcqe *ofld_kcqe) +{ + u32 cid_addr; + struct bnx2i_endpoint *ep; + u32 cid_num; + + ep = bnx2i_find_ep_in_ofld_list(hba, ofld_kcqe->iscsi_conn_id); + if (!ep) { + printk(KERN_ALERT "ofld_cmpl: no pend offload request\n"); + return; + } + + if (hba != ep->hba) { + printk(KERN_ALERT "ofld_cmpl: error hba mis-match\n"); + return; + } + + if (ofld_kcqe->completion_status) { + if (ofld_kcqe->completion_status == + ISCSI_KCQE_COMPLETION_STATUS_CTX_ALLOC_FAILURE) + printk(KERN_ALERT "bnx2i: unable to allocate" + " iSCSI context resources\n"); + ep->state = EP_STATE_OFLD_FAILED; + } else { + ep->state = EP_STATE_OFLD_COMPL; + cid_addr = ofld_kcqe->iscsi_conn_context_id; + cid_num = bnx2i_get_cid_num(ep); + ep->ep_cid = cid_addr; + ep->qp.ctx_base = NULL; + } + wake_up_interruptible(&ep->ofld_wait); +} + +/** + * bnx2i_indicate_kcqe - process iscsi conn update completion KCQE + * @hba: adapter structure pointer + * @update_kcqe: kcqe pointer + * + * Generic KCQ event handler/dispatcher + */ +static void bnx2i_indicate_kcqe(void *context, struct kcqe *kcqe[], + u32 num_cqe) +{ + struct bnx2i_hba *hba = context; + int i = 0; + struct iscsi_kcqe *ikcqe = NULL; + + while (i < num_cqe) { + ikcqe = (struct iscsi_kcqe *) kcqe[i++]; + + if (ikcqe->op_code == + ISCSI_KCQE_OPCODE_CQ_EVENT_NOTIFICATION) + bnx2i_fastpath_notification(hba, ikcqe); + else if (ikcqe->op_code == ISCSI_KCQE_OPCODE_OFFLOAD_CONN) + bnx2i_process_ofld_cmpl(hba, ikcqe); + else if (ikcqe->op_code == ISCSI_KCQE_OPCODE_UPDATE_CONN) + bnx2i_process_update_conn_cmpl(hba, ikcqe); + else if (ikcqe->op_code == ISCSI_KCQE_OPCODE_INIT) { + if (ikcqe->completion_status != + ISCSI_KCQE_COMPLETION_STATUS_SUCCESS) + bnx2i_iscsi_license_error(hba, ikcqe->\ + completion_status); + else { + set_bit(ADAPTER_STATE_UP, &hba->adapter_state); + bnx2i_get_link_state(hba); + printk(KERN_INFO "bnx2i [%.2x:%.2x.%.2x]: " + "ISCSI_INIT passed\n", + (u8)hba->pcidev->bus->number, + hba->pci_devno, + (u8)hba->pci_func); + + + } + } else if (ikcqe->op_code == ISCSI_KCQE_OPCODE_DESTROY_CONN) + bnx2i_process_conn_destroy_cmpl(hba, ikcqe); + else if (ikcqe->op_code == ISCSI_KCQE_OPCODE_ISCSI_ERROR) + bnx2i_process_iscsi_error(hba, ikcqe); + else if (ikcqe->op_code == ISCSI_KCQE_OPCODE_TCP_ERROR) + bnx2i_process_tcp_error(hba, ikcqe); + else + printk(KERN_ALERT "bnx2i: unknown opcode 0x%x\n", + ikcqe->op_code); + } +} + + +/** + * bnx2i_indicate_netevent - Generic netdev event handler + * @context: adapter structure pointer + * @event: event type + * + * Handles four netdev events, NETDEV_UP, NETDEV_DOWN, + * NETDEV_GOING_DOWN and NETDEV_CHANGE + */ +static void bnx2i_indicate_netevent(void *context, unsigned long event) +{ + struct bnx2i_hba *hba = context; + + switch (event) { + case NETDEV_UP: + if (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state)) + bnx2i_send_fw_iscsi_init_msg(hba); + break; + case NETDEV_DOWN: + clear_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state); + clear_bit(ADAPTER_STATE_UP, &hba->adapter_state); + break; + case NETDEV_GOING_DOWN: + set_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state); + iscsi_host_for_each_session(hba->shost, + bnx2i_drop_session); + break; + case NETDEV_CHANGE: + bnx2i_get_link_state(hba); + break; + default: + ; + } +} + + +/** + * bnx2i_cm_connect_cmpl - process iscsi conn establishment completion + * @cm_sk: cnic sock structure pointer + * + * function callback exported via bnx2i - cnic driver interface to + * indicate completion of option-2 TCP connect request. + */ +static void bnx2i_cm_connect_cmpl(struct cnic_sock *cm_sk) +{ + struct bnx2i_endpoint *ep = (struct bnx2i_endpoint *) cm_sk->context; + + if (test_bit(ADAPTER_STATE_GOING_DOWN, &ep->hba->adapter_state)) + ep->state = EP_STATE_CONNECT_FAILED; + else if (test_bit(SK_F_OFFLD_COMPLETE, &cm_sk->flags)) + ep->state = EP_STATE_CONNECT_COMPL; + else + ep->state = EP_STATE_CONNECT_FAILED; + + wake_up_interruptible(&ep->ofld_wait); +} + + +/** + * bnx2i_cm_close_cmpl - process tcp conn close completion + * @cm_sk: cnic sock structure pointer + * + * function callback exported via bnx2i - cnic driver interface to + * indicate completion of option-2 graceful TCP connect shutdown + */ +static void bnx2i_cm_close_cmpl(struct cnic_sock *cm_sk) +{ + struct bnx2i_endpoint *ep = (struct bnx2i_endpoint *) cm_sk->context; + + ep->state = EP_STATE_DISCONN_COMPL; + wake_up_interruptible(&ep->ofld_wait); +} + + +/** + * bnx2i_cm_abort_cmpl - process abortive tcp conn teardown completion + * @cm_sk: cnic sock structure pointer + * + * function callback exported via bnx2i - cnic driver interface to + * indicate completion of option-2 abortive TCP connect termination + */ +static void bnx2i_cm_abort_cmpl(struct cnic_sock *cm_sk) +{ + struct bnx2i_endpoint *ep = (struct bnx2i_endpoint *) cm_sk->context; + + ep->state = EP_STATE_DISCONN_COMPL; + wake_up_interruptible(&ep->ofld_wait); +} + + +/** + * bnx2i_cm_remote_close - process received TCP FIN + * @hba: adapter structure pointer + * @update_kcqe: kcqe pointer + * + * function callback exported via bnx2i - cnic driver interface to indicate + * async TCP events such as FIN + */ +static void bnx2i_cm_remote_close(struct cnic_sock *cm_sk) +{ + struct bnx2i_endpoint *ep = (struct bnx2i_endpoint *) cm_sk->context; + + ep->state = EP_STATE_TCP_FIN_RCVD; + if (ep->conn) + bnx2i_recovery_que_add_conn(ep->hba, ep->conn); +} + +/** + * bnx2i_cm_remote_abort - process TCP RST and start conn cleanup + * @hba: adapter structure pointer + * @update_kcqe: kcqe pointer + * + * function callback exported via bnx2i - cnic driver interface to + * indicate async TCP events (RST) sent by the peer. + */ +static void bnx2i_cm_remote_abort(struct cnic_sock *cm_sk) +{ + struct bnx2i_endpoint *ep = (struct bnx2i_endpoint *) cm_sk->context; + + ep->state = EP_STATE_TCP_RST_RCVD; + if (ep->conn) + bnx2i_recovery_que_add_conn(ep->hba, ep->conn); +} + + +static void bnx2i_send_nl_mesg(struct cnic_dev *dev, u32 msg_type, + char *buf, u16 buflen) +{ + struct bnx2i_hba *hba; + + hba = bnx2i_find_hba_for_cnic(dev); + if (!hba) + return; + + if (iscsi_offload_mesg(hba->shost, &bnx2i_iscsi_transport, + msg_type, buf, buflen)) + printk(KERN_ALERT "bnx2i: private nl message send error\n"); + +} + + +/** + * bnx2i_cnic_cb - global template of bnx2i - cnic driver interface structure + * carrying callback function pointers + * + */ +struct cnic_ulp_ops bnx2i_cnic_cb = { + .cnic_init = bnx2i_ulp_init, + .cnic_exit = bnx2i_ulp_exit, + .cnic_start = bnx2i_start, + .cnic_stop = bnx2i_stop, + .indicate_kcqes = bnx2i_indicate_kcqe, + .indicate_netevent = bnx2i_indicate_netevent, + .cm_connect_complete = bnx2i_cm_connect_cmpl, + .cm_close_complete = bnx2i_cm_close_cmpl, + .cm_abort_complete = bnx2i_cm_abort_cmpl, + .cm_remote_close = bnx2i_cm_remote_close, + .cm_remote_abort = bnx2i_cm_remote_abort, + .iscsi_nl_send_msg = bnx2i_send_nl_mesg, + .owner = THIS_MODULE +}; + + +/** + * bnx2i_map_ep_dbell_regs - map connection doorbell registers + * @ep: bnx2i endpoint + * + * maps connection's SQ and RQ doorbell registers, 5706/5708/5709 hosts these + * register in BAR #0. Whereas in 57710 these register are accessed by + * mapping BAR #1 + */ +int bnx2i_map_ep_dbell_regs(struct bnx2i_endpoint *ep) +{ + u32 cid_num; + u32 reg_off; + u32 first_l4l5; + u32 ctx_sz; + u32 config2; + resource_size_t reg_base; + + cid_num = bnx2i_get_cid_num(ep); + + if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type)) { + reg_base = pci_resource_start(ep->hba->pcidev, + BNX2X_DOORBELL_PCI_BAR); + reg_off = PAGE_SIZE * (cid_num & 0x1FFFF) + DPM_TRIGER_TYPE; + ep->qp.ctx_base = ioremap_nocache(reg_base + reg_off, 4); + goto arm_cq; + } + + reg_base = ep->hba->netdev->base_addr; + if ((test_bit(BNX2I_NX2_DEV_5709, &ep->hba->cnic_dev_type)) && + (ep->hba->mail_queue_access == BNX2I_MQ_BIN_MODE)) { + config2 = REG_RD(ep->hba, BNX2_MQ_CONFIG2); + first_l4l5 = config2 & BNX2_MQ_CONFIG2_FIRST_L4L5; + ctx_sz = (config2 & BNX2_MQ_CONFIG2_CONT_SZ) >> 3; + if (ctx_sz) + reg_off = CTX_OFFSET + MAX_CID_CNT * MB_KERNEL_CTX_SIZE + + PAGE_SIZE * + (((cid_num - first_l4l5) / ctx_sz) + 256); + else + reg_off = CTX_OFFSET + (MB_KERNEL_CTX_SIZE * cid_num); + } else + /* 5709 device in normal node and 5706/5708 devices */ + reg_off = CTX_OFFSET + (MB_KERNEL_CTX_SIZE * cid_num); + + ep->qp.ctx_base = ioremap_nocache(reg_base + reg_off, + MB_KERNEL_CTX_SIZE); + if (!ep->qp.ctx_base) + return -ENOMEM; + +arm_cq: + bnx2i_arm_cq_event_coalescing(ep, CNIC_ARM_CQE); + return 0; +} diff --git a/drivers/scsi/bnx2i/bnx2i_init.c b/drivers/scsi/bnx2i/bnx2i_init.c new file mode 100644 index 000000000000..ae4b2d588fd3 --- /dev/null +++ b/drivers/scsi/bnx2i/bnx2i_init.c @@ -0,0 +1,438 @@ +/* bnx2i.c: Broadcom NetXtreme II iSCSI driver. + * + * Copyright (c) 2006 - 2009 Broadcom Corporation + * Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved. + * Copyright (c) 2007, 2008 Mike Christie + * + * 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. + * + * Written by: Anil Veerabhadrappa (anilgv@broadcom.com) + */ + +#include "bnx2i.h" + +static struct list_head adapter_list = LIST_HEAD_INIT(adapter_list); +static u32 adapter_count; +static int bnx2i_reg_device; + +#define DRV_MODULE_NAME "bnx2i" +#define DRV_MODULE_VERSION "2.0.1d" +#define DRV_MODULE_RELDATE "Mar 25, 2009" + +static char version[] __devinitdata = + "Broadcom NetXtreme II iSCSI Driver " DRV_MODULE_NAME \ + " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; + + +MODULE_AUTHOR("Anil Veerabhadrappa "); +MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706/5708/5709 iSCSI Driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_MODULE_VERSION); + +static DEFINE_RWLOCK(bnx2i_dev_lock); + +unsigned int event_coal_div = 1; +module_param(event_coal_div, int, 0664); +MODULE_PARM_DESC(event_coal_div, "Event Coalescing Divide Factor"); + +unsigned int en_tcp_dack = 1; +module_param(en_tcp_dack, int, 0664); +MODULE_PARM_DESC(en_tcp_dack, "Enable TCP Delayed ACK"); + +unsigned int error_mask1 = 0x00; +module_param(error_mask1, int, 0664); +MODULE_PARM_DESC(error_mask1, "Config FW iSCSI Error Mask #1"); + +unsigned int error_mask2 = 0x00; +module_param(error_mask2, int, 0664); +MODULE_PARM_DESC(error_mask2, "Config FW iSCSI Error Mask #2"); + +unsigned int sq_size; +module_param(sq_size, int, 0664); +MODULE_PARM_DESC(sq_size, "Configure SQ size"); + +unsigned int rq_size = BNX2I_RQ_WQES_DEFAULT; +module_param(rq_size, int, 0664); +MODULE_PARM_DESC(rq_size, "Configure RQ size"); + +u64 iscsi_error_mask = 0x00; + +static void bnx2i_unreg_one_device(struct bnx2i_hba *hba) ; + + +/** + * bnx2i_identify_device - identifies NetXtreme II device type + * @hba: Adapter structure pointer + * + * This function identifies the NX2 device type and sets appropriate + * queue mailbox register access method, 5709 requires driver to + * access MBOX regs using *bin* mode + */ +void bnx2i_identify_device(struct bnx2i_hba *hba) +{ + hba->cnic_dev_type = 0; + if ((hba->pci_did == PCI_DEVICE_ID_NX2_5706) || + (hba->pci_did == PCI_DEVICE_ID_NX2_5706S)) + set_bit(BNX2I_NX2_DEV_5706, &hba->cnic_dev_type); + else if ((hba->pci_did == PCI_DEVICE_ID_NX2_5708) || + (hba->pci_did == PCI_DEVICE_ID_NX2_5708S)) + set_bit(BNX2I_NX2_DEV_5708, &hba->cnic_dev_type); + else if ((hba->pci_did == PCI_DEVICE_ID_NX2_5709) || + (hba->pci_did == PCI_DEVICE_ID_NX2_5709S)) { + set_bit(BNX2I_NX2_DEV_5709, &hba->cnic_dev_type); + hba->mail_queue_access = BNX2I_MQ_BIN_MODE; + } else if (hba->pci_did == PCI_DEVICE_ID_NX2_57710 || + hba->pci_did == PCI_DEVICE_ID_NX2_57711) + set_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type); +} + + +/** + * get_adapter_list_head - returns head of adapter list + */ +struct bnx2i_hba *get_adapter_list_head(void) +{ + struct bnx2i_hba *hba = NULL; + struct bnx2i_hba *tmp_hba; + + if (!adapter_count) + goto hba_not_found; + + read_lock(&bnx2i_dev_lock); + list_for_each_entry(tmp_hba, &adapter_list, link) { + if (tmp_hba->cnic && tmp_hba->cnic->cm_select_dev) { + hba = tmp_hba; + break; + } + } + read_unlock(&bnx2i_dev_lock); +hba_not_found: + return hba; +} + + +/** + * bnx2i_find_hba_for_cnic - maps cnic device instance to bnx2i adapter instance + * @cnic: pointer to cnic device instance + * + */ +struct bnx2i_hba *bnx2i_find_hba_for_cnic(struct cnic_dev *cnic) +{ + struct bnx2i_hba *hba, *temp; + + read_lock(&bnx2i_dev_lock); + list_for_each_entry_safe(hba, temp, &adapter_list, link) { + if (hba->cnic == cnic) { + read_unlock(&bnx2i_dev_lock); + return hba; + } + } + read_unlock(&bnx2i_dev_lock); + return NULL; +} + + +/** + * bnx2i_start - cnic callback to initialize & start adapter instance + * @handle: transparent handle pointing to adapter structure + * + * This function maps adapter structure to pcidev structure and initiates + * firmware handshake to enable/initialize on chip iscsi components + * This bnx2i - cnic interface api callback is issued after following + * 2 conditions are met - + * a) underlying network interface is up (marked by event 'NETDEV_UP' + * from netdev + * b) bnx2i adapter instance is registered + */ +void bnx2i_start(void *handle) +{ +#define BNX2I_INIT_POLL_TIME (1000 / HZ) + struct bnx2i_hba *hba = handle; + int i = HZ; + + bnx2i_send_fw_iscsi_init_msg(hba); + while (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state) && i--) + msleep(BNX2I_INIT_POLL_TIME); +} + + +/** + * bnx2i_stop - cnic callback to shutdown adapter instance + * @handle: transparent handle pointing to adapter structure + * + * driver checks if adapter is already in shutdown mode, if not start + * the shutdown process + */ +void bnx2i_stop(void *handle) +{ + struct bnx2i_hba *hba = handle; + + /* check if cleanup happened in GOING_DOWN context */ + clear_bit(ADAPTER_STATE_UP, &hba->adapter_state); + if (!test_and_clear_bit(ADAPTER_STATE_GOING_DOWN, + &hba->adapter_state)) + iscsi_host_for_each_session(hba->shost, + bnx2i_drop_session); +} + +/** + * bnx2i_register_device - register bnx2i adapter instance with the cnic driver + * @hba: Adapter instance to register + * + * registers bnx2i adapter instance with the cnic driver while holding the + * adapter structure lock + */ +void bnx2i_register_device(struct bnx2i_hba *hba) +{ + if (test_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state) || + test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) { + return; + } + + hba->cnic->register_device(hba->cnic, CNIC_ULP_ISCSI, hba); + + spin_lock(&hba->lock); + bnx2i_reg_device++; + spin_unlock(&hba->lock); + + set_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic); +} + + +/** + * bnx2i_reg_dev_all - registers all adapter instances with the cnic driver + * + * registers all bnx2i adapter instances with the cnic driver while holding + * the global resource lock + */ +void bnx2i_reg_dev_all(void) +{ + struct bnx2i_hba *hba, *temp; + + read_lock(&bnx2i_dev_lock); + list_for_each_entry_safe(hba, temp, &adapter_list, link) + bnx2i_register_device(hba); + read_unlock(&bnx2i_dev_lock); +} + + +/** + * bnx2i_unreg_one_device - unregister adapter instance with the cnic driver + * @hba: Adapter instance to unregister + * + * registers bnx2i adapter instance with the cnic driver while holding + * the adapter structure lock + */ +static void bnx2i_unreg_one_device(struct bnx2i_hba *hba) +{ + if (hba->ofld_conns_active || + !test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic) || + test_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state)) + return; + + hba->cnic->unregister_device(hba->cnic, CNIC_ULP_ISCSI); + + spin_lock(&hba->lock); + bnx2i_reg_device--; + spin_unlock(&hba->lock); + + /* ep_disconnect could come before NETDEV_DOWN, driver won't + * see NETDEV_DOWN as it already unregistered itself. + */ + hba->adapter_state = 0; + clear_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic); +} + +/** + * bnx2i_unreg_dev_all - unregisters all bnx2i instances with the cnic driver + * + * unregisters all bnx2i adapter instances with the cnic driver while holding + * the global resource lock + */ +void bnx2i_unreg_dev_all(void) +{ + struct bnx2i_hba *hba, *temp; + + read_lock(&bnx2i_dev_lock); + list_for_each_entry_safe(hba, temp, &adapter_list, link) + bnx2i_unreg_one_device(hba); + read_unlock(&bnx2i_dev_lock); +} + + +/** + * bnx2i_init_one - initialize an adapter instance and allocate memory resources + * @hba: bnx2i adapter instance + * @cnic: cnic device handle + * + * Global resource lock and host adapter lock is held during critical sections + * below. This routine is called from cnic_register_driver() context and + * work horse thread which does majority of device specific initialization + */ +static int bnx2i_init_one(struct bnx2i_hba *hba, struct cnic_dev *cnic) +{ + int rc; + + read_lock(&bnx2i_dev_lock); + if (bnx2i_reg_device && + !test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) { + rc = cnic->register_device(cnic, CNIC_ULP_ISCSI, hba); + if (rc) /* duplicate registration */ + printk(KERN_ERR "bnx2i- dev reg failed\n"); + + spin_lock(&hba->lock); + bnx2i_reg_device++; + hba->age++; + spin_unlock(&hba->lock); + + set_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic); + } + read_unlock(&bnx2i_dev_lock); + + write_lock(&bnx2i_dev_lock); + list_add_tail(&hba->link, &adapter_list); + adapter_count++; + write_unlock(&bnx2i_dev_lock); + return 0; +} + + +/** + * bnx2i_ulp_init - initialize an adapter instance + * @dev: cnic device handle + * + * Called from cnic_register_driver() context to initialize all enumerated + * cnic devices. This routine allocate adapter structure and other + * device specific resources. + */ +void bnx2i_ulp_init(struct cnic_dev *dev) +{ + struct bnx2i_hba *hba; + + /* Allocate a HBA structure for this device */ + hba = bnx2i_alloc_hba(dev); + if (!hba) { + printk(KERN_ERR "bnx2i init: hba initialization failed\n"); + return; + } + + /* Get PCI related information and update hba struct members */ + clear_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic); + if (bnx2i_init_one(hba, dev)) { + printk(KERN_ERR "bnx2i - hba %p init failed\n", hba); + bnx2i_free_hba(hba); + } else + hba->cnic = dev; +} + + +/** + * bnx2i_ulp_exit - shuts down adapter instance and frees all resources + * @dev: cnic device handle + * + */ +void bnx2i_ulp_exit(struct cnic_dev *dev) +{ + struct bnx2i_hba *hba; + + hba = bnx2i_find_hba_for_cnic(dev); + if (!hba) { + printk(KERN_INFO "bnx2i_ulp_exit: hba not " + "found, dev 0x%p\n", dev); + return; + } + write_lock(&bnx2i_dev_lock); + list_del_init(&hba->link); + adapter_count--; + + if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) { + hba->cnic->unregister_device(hba->cnic, CNIC_ULP_ISCSI); + clear_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic); + + spin_lock(&hba->lock); + bnx2i_reg_device--; + spin_unlock(&hba->lock); + } + write_unlock(&bnx2i_dev_lock); + + bnx2i_free_hba(hba); +} + + +/** + * bnx2i_mod_init - module init entry point + * + * initialize any driver wide global data structures such as endpoint pool, + * tcp port manager/queue, sysfs. finally driver will register itself + * with the cnic module + */ +static int __init bnx2i_mod_init(void) +{ + int err; + + printk(KERN_INFO "%s", version); + + if (!is_power_of_2(sq_size)) + sq_size = roundup_pow_of_two(sq_size); + + bnx2i_scsi_xport_template = + iscsi_register_transport(&bnx2i_iscsi_transport); + if (!bnx2i_scsi_xport_template) { + printk(KERN_ERR "Could not register bnx2i transport.\n"); + err = -ENOMEM; + goto out; + } + + err = cnic_register_driver(CNIC_ULP_ISCSI, &bnx2i_cnic_cb); + if (err) { + printk(KERN_ERR "Could not register bnx2i cnic driver.\n"); + goto unreg_xport; + } + + return 0; + +unreg_xport: + iscsi_unregister_transport(&bnx2i_iscsi_transport); +out: + return err; +} + + +/** + * bnx2i_mod_exit - module cleanup/exit entry point + * + * Global resource lock and host adapter lock is held during critical sections + * in this function. Driver will browse through the adapter list, cleans-up + * each instance, unregisters iscsi transport name and finally driver will + * unregister itself with the cnic module + */ +static void __exit bnx2i_mod_exit(void) +{ + struct bnx2i_hba *hba; + + write_lock(&bnx2i_dev_lock); + while (!list_empty(&adapter_list)) { + hba = list_entry(adapter_list.next, struct bnx2i_hba, link); + list_del(&hba->link); + adapter_count--; + + if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) { + hba->cnic->unregister_device(hba->cnic, CNIC_ULP_ISCSI); + clear_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic); + bnx2i_reg_device--; + } + + write_unlock(&bnx2i_dev_lock); + bnx2i_free_hba(hba); + write_lock(&bnx2i_dev_lock); + } + write_unlock(&bnx2i_dev_lock); + + iscsi_unregister_transport(&bnx2i_iscsi_transport); + cnic_unregister_driver(CNIC_ULP_ISCSI); +} + +module_init(bnx2i_mod_init); +module_exit(bnx2i_mod_exit); diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c new file mode 100644 index 000000000000..f7412196f2f8 --- /dev/null +++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c @@ -0,0 +1,2064 @@ +/* + * bnx2i_iscsi.c: Broadcom NetXtreme II iSCSI driver. + * + * Copyright (c) 2006 - 2009 Broadcom Corporation + * Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved. + * Copyright (c) 2007, 2008 Mike Christie + * + * 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. + * + * Written by: Anil Veerabhadrappa (anilgv@broadcom.com) + */ + +#include +#include +#include "bnx2i.h" + +struct scsi_transport_template *bnx2i_scsi_xport_template; +struct iscsi_transport bnx2i_iscsi_transport; +static struct scsi_host_template bnx2i_host_template; + +/* + * Global endpoint resource info + */ +static DEFINE_SPINLOCK(bnx2i_resc_lock); /* protects global resources */ + + +static int bnx2i_adapter_ready(struct bnx2i_hba *hba) +{ + int retval = 0; + + if (!hba || !test_bit(ADAPTER_STATE_UP, &hba->adapter_state) || + test_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state) || + test_bit(ADAPTER_STATE_LINK_DOWN, &hba->adapter_state)) + retval = -EPERM; + return retval; +} + +/** + * bnx2i_get_write_cmd_bd_idx - identifies various BD bookmarks + * @cmd: iscsi cmd struct pointer + * @buf_off: absolute buffer offset + * @start_bd_off: u32 pointer to return the offset within the BD + * indicated by 'start_bd_idx' on which 'buf_off' falls + * @start_bd_idx: index of the BD on which 'buf_off' falls + * + * identifies & marks various bd info for scsi command's imm data, + * unsolicited data and the first solicited data seq. + */ +static void bnx2i_get_write_cmd_bd_idx(struct bnx2i_cmd *cmd, u32 buf_off, + u32 *start_bd_off, u32 *start_bd_idx) +{ + struct iscsi_bd *bd_tbl = cmd->io_tbl.bd_tbl; + u32 cur_offset = 0; + u32 cur_bd_idx = 0; + + if (buf_off) { + while (buf_off >= (cur_offset + bd_tbl->buffer_length)) { + cur_offset += bd_tbl->buffer_length; + cur_bd_idx++; + bd_tbl++; + } + } + + *start_bd_off = buf_off - cur_offset; + *start_bd_idx = cur_bd_idx; +} + +/** + * bnx2i_setup_write_cmd_bd_info - sets up BD various information + * @task: transport layer's cmd struct pointer + * + * identifies & marks various bd info for scsi command's immediate data, + * unsolicited data and first solicited data seq which includes BD start + * index & BD buf off. his function takes into account iscsi parameter such + * as immediate data and unsolicited data is support on this connection. + */ +static void bnx2i_setup_write_cmd_bd_info(struct iscsi_task *task) +{ + struct bnx2i_cmd *cmd = task->dd_data; + u32 start_bd_offset; + u32 start_bd_idx; + u32 buffer_offset = 0; + u32 cmd_len = cmd->req.total_data_transfer_length; + + /* if ImmediateData is turned off & IntialR2T is turned on, + * there will be no immediate or unsolicited data, just return. + */ + if (!iscsi_task_has_unsol_data(task) && !task->imm_count) + return; + + /* Immediate data */ + buffer_offset += task->imm_count; + if (task->imm_count == cmd_len) + return; + + if (iscsi_task_has_unsol_data(task)) { + bnx2i_get_write_cmd_bd_idx(cmd, buffer_offset, + &start_bd_offset, &start_bd_idx); + cmd->req.ud_buffer_offset = start_bd_offset; + cmd->req.ud_start_bd_index = start_bd_idx; + buffer_offset += task->unsol_r2t.data_length; + } + + if (buffer_offset != cmd_len) { + bnx2i_get_write_cmd_bd_idx(cmd, buffer_offset, + &start_bd_offset, &start_bd_idx); + if ((start_bd_offset > task->conn->session->first_burst) || + (start_bd_idx > scsi_sg_count(cmd->scsi_cmd))) { + int i = 0; + + iscsi_conn_printk(KERN_ALERT, task->conn, + "bnx2i- error, buf offset 0x%x " + "bd_valid %d use_sg %d\n", + buffer_offset, cmd->io_tbl.bd_valid, + scsi_sg_count(cmd->scsi_cmd)); + for (i = 0; i < cmd->io_tbl.bd_valid; i++) + iscsi_conn_printk(KERN_ALERT, task->conn, + "bnx2i err, bd[%d]: len %x\n", + i, cmd->io_tbl.bd_tbl[i].\ + buffer_length); + } + cmd->req.sd_buffer_offset = start_bd_offset; + cmd->req.sd_start_bd_index = start_bd_idx; + } +} + + + +/** + * bnx2i_map_scsi_sg - maps IO buffer and prepares the BD table + * @hba: adapter instance + * @cmd: iscsi cmd struct pointer + * + * map SG list + */ +static int bnx2i_map_scsi_sg(struct bnx2i_hba *hba, struct bnx2i_cmd *cmd) +{ + struct scsi_cmnd *sc = cmd->scsi_cmd; + struct iscsi_bd *bd = cmd->io_tbl.bd_tbl; + struct scatterlist *sg; + int byte_count = 0; + int bd_count = 0; + int sg_count; + int sg_len; + u64 addr; + int i; + + BUG_ON(scsi_sg_count(sc) > ISCSI_MAX_BDS_PER_CMD); + + sg_count = scsi_dma_map(sc); + + scsi_for_each_sg(sc, sg, sg_count, i) { + sg_len = sg_dma_len(sg); + addr = (u64) sg_dma_address(sg); + bd[bd_count].buffer_addr_lo = addr & 0xffffffff; + bd[bd_count].buffer_addr_hi = addr >> 32; + bd[bd_count].buffer_length = sg_len; + bd[bd_count].flags = 0; + if (bd_count == 0) + bd[bd_count].flags = ISCSI_BD_FIRST_IN_BD_CHAIN; + + byte_count += sg_len; + bd_count++; + } + + if (bd_count) + bd[bd_count - 1].flags |= ISCSI_BD_LAST_IN_BD_CHAIN; + + BUG_ON(byte_count != scsi_bufflen(sc)); + return bd_count; +} + +/** + * bnx2i_iscsi_map_sg_list - maps SG list + * @cmd: iscsi cmd struct pointer + * + * creates BD list table for the command + */ +static void bnx2i_iscsi_map_sg_list(struct bnx2i_cmd *cmd) +{ + int bd_count; + + bd_count = bnx2i_map_scsi_sg(cmd->conn->hba, cmd); + if (!bd_count) { + struct iscsi_bd *bd = cmd->io_tbl.bd_tbl; + + bd[0].buffer_addr_lo = bd[0].buffer_addr_hi = 0; + bd[0].buffer_length = bd[0].flags = 0; + } + cmd->io_tbl.bd_valid = bd_count; +} + + +/** + * bnx2i_iscsi_unmap_sg_list - unmaps SG list + * @cmd: iscsi cmd struct pointer + * + * unmap IO buffers and invalidate the BD table + */ +void bnx2i_iscsi_unmap_sg_list(struct bnx2i_cmd *cmd) +{ + struct scsi_cmnd *sc = cmd->scsi_cmd; + + if (cmd->io_tbl.bd_valid && sc) { + scsi_dma_unmap(sc); + cmd->io_tbl.bd_valid = 0; + } +} + +static void bnx2i_setup_cmd_wqe_template(struct bnx2i_cmd *cmd) +{ + memset(&cmd->req, 0x00, sizeof(cmd->req)); + cmd->req.op_code = 0xFF; + cmd->req.bd_list_addr_lo = (u32) cmd->io_tbl.bd_tbl_dma; + cmd->req.bd_list_addr_hi = + (u32) ((u64) cmd->io_tbl.bd_tbl_dma >> 32); + +} + + +/** + * bnx2i_bind_conn_to_iscsi_cid - bind conn structure to 'iscsi_cid' + * @hba: pointer to adapter instance + * @conn: pointer to iscsi connection + * @iscsi_cid: iscsi context ID, range 0 - (MAX_CONN - 1) + * + * update iscsi cid table entry with connection pointer. This enables + * driver to quickly get hold of connection structure pointer in + * completion/interrupt thread using iscsi context ID + */ +static int bnx2i_bind_conn_to_iscsi_cid(struct bnx2i_hba *hba, + struct bnx2i_conn *bnx2i_conn, + u32 iscsi_cid) +{ + if (hba && hba->cid_que.conn_cid_tbl[iscsi_cid]) { + iscsi_conn_printk(KERN_ALERT, bnx2i_conn->cls_conn->dd_data, + "conn bind - entry #%d not free\n", iscsi_cid); + return -EBUSY; + } + + hba->cid_que.conn_cid_tbl[iscsi_cid] = bnx2i_conn; + return 0; +} + + +/** + * bnx2i_get_conn_from_id - maps an iscsi cid to corresponding conn ptr + * @hba: pointer to adapter instance + * @iscsi_cid: iscsi context ID, range 0 - (MAX_CONN - 1) + */ +struct bnx2i_conn *bnx2i_get_conn_from_id(struct bnx2i_hba *hba, + u16 iscsi_cid) +{ + if (!hba->cid_que.conn_cid_tbl) { + printk(KERN_ERR "bnx2i: ERROR - missing conn<->cid table\n"); + return NULL; + + } else if (iscsi_cid >= hba->max_active_conns) { + printk(KERN_ERR "bnx2i: wrong cid #%d\n", iscsi_cid); + return NULL; + } + return hba->cid_que.conn_cid_tbl[iscsi_cid]; +} + + +/** + * bnx2i_alloc_iscsi_cid - allocates a iscsi_cid from free pool + * @hba: pointer to adapter instance + */ +static u32 bnx2i_alloc_iscsi_cid(struct bnx2i_hba *hba) +{ + int idx; + + if (!hba->cid_que.cid_free_cnt) + return -1; + + idx = hba->cid_que.cid_q_cons_idx; + hba->cid_que.cid_q_cons_idx++; + if (hba->cid_que.cid_q_cons_idx == hba->cid_que.cid_q_max_idx) + hba->cid_que.cid_q_cons_idx = 0; + + hba->cid_que.cid_free_cnt--; + return hba->cid_que.cid_que[idx]; +} + + +/** + * bnx2i_free_iscsi_cid - returns tcp port to free list + * @hba: pointer to adapter instance + * @iscsi_cid: iscsi context ID to free + */ +static void bnx2i_free_iscsi_cid(struct bnx2i_hba *hba, u16 iscsi_cid) +{ + int idx; + + if (iscsi_cid == (u16) -1) + return; + + hba->cid_que.cid_free_cnt++; + + idx = hba->cid_que.cid_q_prod_idx; + hba->cid_que.cid_que[idx] = iscsi_cid; + hba->cid_que.conn_cid_tbl[iscsi_cid] = NULL; + hba->cid_que.cid_q_prod_idx++; + if (hba->cid_que.cid_q_prod_idx == hba->cid_que.cid_q_max_idx) + hba->cid_que.cid_q_prod_idx = 0; +} + + +/** + * bnx2i_setup_free_cid_que - sets up free iscsi cid queue + * @hba: pointer to adapter instance + * + * allocates memory for iscsi cid queue & 'cid - conn ptr' mapping table, + * and initialize table attributes + */ +static int bnx2i_setup_free_cid_que(struct bnx2i_hba *hba) +{ + int mem_size; + int i; + + mem_size = hba->max_active_conns * sizeof(u32); + mem_size = (mem_size + (PAGE_SIZE - 1)) & PAGE_MASK; + + hba->cid_que.cid_que_base = kmalloc(mem_size, GFP_KERNEL); + if (!hba->cid_que.cid_que_base) + return -ENOMEM; + + mem_size = hba->max_active_conns * sizeof(struct bnx2i_conn *); + mem_size = (mem_size + (PAGE_SIZE - 1)) & PAGE_MASK; + hba->cid_que.conn_cid_tbl = kmalloc(mem_size, GFP_KERNEL); + if (!hba->cid_que.conn_cid_tbl) { + kfree(hba->cid_que.cid_que_base); + hba->cid_que.cid_que_base = NULL; + return -ENOMEM; + } + + hba->cid_que.cid_que = (u32 *)hba->cid_que.cid_que_base; + hba->cid_que.cid_q_prod_idx = 0; + hba->cid_que.cid_q_cons_idx = 0; + hba->cid_que.cid_q_max_idx = hba->max_active_conns; + hba->cid_que.cid_free_cnt = hba->max_active_conns; + + for (i = 0; i < hba->max_active_conns; i++) { + hba->cid_que.cid_que[i] = i; + hba->cid_que.conn_cid_tbl[i] = NULL; + } + return 0; +} + + +/** + * bnx2i_release_free_cid_que - releases 'iscsi_cid' queue resources + * @hba: pointer to adapter instance + */ +static void bnx2i_release_free_cid_que(struct bnx2i_hba *hba) +{ + kfree(hba->cid_que.cid_que_base); + hba->cid_que.cid_que_base = NULL; + + kfree(hba->cid_que.conn_cid_tbl); + hba->cid_que.conn_cid_tbl = NULL; +} + + +/** + * bnx2i_alloc_ep - allocates ep structure from global pool + * @hba: pointer to adapter instance + * + * routine allocates a free endpoint structure from global pool and + * a tcp port to be used for this connection. Global resource lock, + * 'bnx2i_resc_lock' is held while accessing shared global data structures + */ +static struct iscsi_endpoint *bnx2i_alloc_ep(struct bnx2i_hba *hba) +{ + struct iscsi_endpoint *ep; + struct bnx2i_endpoint *bnx2i_ep; + + ep = iscsi_create_endpoint(sizeof(*bnx2i_ep)); + if (!ep) { + printk(KERN_ERR "bnx2i: Could not allocate ep\n"); + return NULL; + } + + bnx2i_ep = ep->dd_data; + INIT_LIST_HEAD(&bnx2i_ep->link); + bnx2i_ep->state = EP_STATE_IDLE; + bnx2i_ep->hba = hba; + bnx2i_ep->hba_age = hba->age; + hba->ofld_conns_active++; + init_waitqueue_head(&bnx2i_ep->ofld_wait); + return ep; +} + + +/** + * bnx2i_free_ep - free endpoint + * @ep: pointer to iscsi endpoint structure + */ +static void bnx2i_free_ep(struct iscsi_endpoint *ep) +{ + struct bnx2i_endpoint *bnx2i_ep = ep->dd_data; + unsigned long flags; + + spin_lock_irqsave(&bnx2i_resc_lock, flags); + bnx2i_ep->state = EP_STATE_IDLE; + bnx2i_ep->hba->ofld_conns_active--; + + bnx2i_free_iscsi_cid(bnx2i_ep->hba, bnx2i_ep->ep_iscsi_cid); + if (bnx2i_ep->conn) { + bnx2i_ep->conn->ep = NULL; + bnx2i_ep->conn = NULL; + } + + bnx2i_ep->hba = NULL; + spin_unlock_irqrestore(&bnx2i_resc_lock, flags); + iscsi_destroy_endpoint(ep); +} + + +/** + * bnx2i_alloc_bdt - allocates buffer descriptor (BD) table for the command + * @hba: adapter instance pointer + * @session: iscsi session pointer + * @cmd: iscsi command structure + */ +static int bnx2i_alloc_bdt(struct bnx2i_hba *hba, struct iscsi_session *session, + struct bnx2i_cmd *cmd) +{ + struct io_bdt *io = &cmd->io_tbl; + struct iscsi_bd *bd; + + io->bd_tbl = dma_alloc_coherent(&hba->pcidev->dev, + ISCSI_MAX_BDS_PER_CMD * sizeof(*bd), + &io->bd_tbl_dma, GFP_KERNEL); + if (!io->bd_tbl) { + iscsi_session_printk(KERN_ERR, session, "Could not " + "allocate bdt.\n"); + return -ENOMEM; + } + io->bd_valid = 0; + return 0; +} + +/** + * bnx2i_destroy_cmd_pool - destroys iscsi command pool and release BD table + * @hba: adapter instance pointer + * @session: iscsi session pointer + * @cmd: iscsi command structure + */ +static void bnx2i_destroy_cmd_pool(struct bnx2i_hba *hba, + struct iscsi_session *session) +{ + int i; + + for (i = 0; i < session->cmds_max; i++) { + struct iscsi_task *task = session->cmds[i]; + struct bnx2i_cmd *cmd = task->dd_data; + + if (cmd->io_tbl.bd_tbl) + dma_free_coherent(&hba->pcidev->dev, + ISCSI_MAX_BDS_PER_CMD * + sizeof(struct iscsi_bd), + cmd->io_tbl.bd_tbl, + cmd->io_tbl.bd_tbl_dma); + } + +} + + +/** + * bnx2i_setup_cmd_pool - sets up iscsi command pool for the session + * @hba: adapter instance pointer + * @session: iscsi session pointer + */ +static int bnx2i_setup_cmd_pool(struct bnx2i_hba *hba, + struct iscsi_session *session) +{ + int i; + + for (i = 0; i < session->cmds_max; i++) { + struct iscsi_task *task = session->cmds[i]; + struct bnx2i_cmd *cmd = task->dd_data; + + /* Anil */ + task->hdr = &cmd->hdr; + task->hdr_max = sizeof(struct iscsi_hdr); + + if (bnx2i_alloc_bdt(hba, session, cmd)) + goto free_bdts; + } + + return 0; + +free_bdts: + bnx2i_destroy_cmd_pool(hba, session); + return -ENOMEM; +} + + +/** + * bnx2i_setup_mp_bdt - allocate BD table resources + * @hba: pointer to adapter structure + * + * Allocate memory for dummy buffer and associated BD + * table to be used by middle path (MP) requests + */ +static int bnx2i_setup_mp_bdt(struct bnx2i_hba *hba) +{ + int rc = 0; + struct iscsi_bd *mp_bdt; + u64 addr; + + hba->mp_bd_tbl = dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE, + &hba->mp_bd_dma, GFP_KERNEL); + if (!hba->mp_bd_tbl) { + printk(KERN_ERR "unable to allocate Middle Path BDT\n"); + rc = -1; + goto out; + } + + hba->dummy_buffer = dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE, + &hba->dummy_buf_dma, GFP_KERNEL); + if (!hba->dummy_buffer) { + printk(KERN_ERR "unable to alloc Middle Path Dummy Buffer\n"); + dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE, + hba->mp_bd_tbl, hba->mp_bd_dma); + hba->mp_bd_tbl = NULL; + rc = -1; + goto out; + } + + mp_bdt = (struct iscsi_bd *) hba->mp_bd_tbl; + addr = (unsigned long) hba->dummy_buf_dma; + mp_bdt->buffer_addr_lo = addr & 0xffffffff; + mp_bdt->buffer_addr_hi = addr >> 32; + mp_bdt->buffer_length = PAGE_SIZE; + mp_bdt->flags = ISCSI_BD_LAST_IN_BD_CHAIN | + ISCSI_BD_FIRST_IN_BD_CHAIN; +out: + return rc; +} + + +/** + * bnx2i_free_mp_bdt - releases ITT back to free pool + * @hba: pointer to adapter instance + * + * free MP dummy buffer and associated BD table + */ +static void bnx2i_free_mp_bdt(struct bnx2i_hba *hba) +{ + if (hba->mp_bd_tbl) { + dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE, + hba->mp_bd_tbl, hba->mp_bd_dma); + hba->mp_bd_tbl = NULL; + } + if (hba->dummy_buffer) { + dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE, + hba->dummy_buffer, hba->dummy_buf_dma); + hba->dummy_buffer = NULL; + } + return; +} + +/** + * bnx2i_drop_session - notifies iscsid of connection error. + * @hba: adapter instance pointer + * @session: iscsi session pointer + * + * This notifies iscsid that there is a error, so it can initiate + * recovery. + * + * This relies on caller using the iscsi class iterator so the object + * is refcounted and does not disapper from under us. + */ +void bnx2i_drop_session(struct iscsi_cls_session *cls_session) +{ + iscsi_session_failure(cls_session->dd_data, ISCSI_ERR_CONN_FAILED); +} + +/** + * bnx2i_ep_destroy_list_add - add an entry to EP destroy list + * @hba: pointer to adapter instance + * @ep: pointer to endpoint (transport indentifier) structure + * + * EP destroy queue manager + */ +static int bnx2i_ep_destroy_list_add(struct bnx2i_hba *hba, + struct bnx2i_endpoint *ep) +{ + write_lock_bh(&hba->ep_rdwr_lock); + list_add_tail(&ep->link, &hba->ep_destroy_list); + write_unlock_bh(&hba->ep_rdwr_lock); + return 0; +} + +/** + * bnx2i_ep_destroy_list_del - add an entry to EP destroy list + * + * @hba: pointer to adapter instance + * @ep: pointer to endpoint (transport indentifier) structure + * + * EP destroy queue manager + */ +static int bnx2i_ep_destroy_list_del(struct bnx2i_hba *hba, + struct bnx2i_endpoint *ep) +{ + write_lock_bh(&hba->ep_rdwr_lock); + list_del_init(&ep->link); + write_unlock_bh(&hba->ep_rdwr_lock); + + return 0; +} + +/** + * bnx2i_ep_ofld_list_add - add an entry to ep offload pending list + * @hba: pointer to adapter instance + * @ep: pointer to endpoint (transport indentifier) structure + * + * pending conn offload completion queue manager + */ +static int bnx2i_ep_ofld_list_add(struct bnx2i_hba *hba, + struct bnx2i_endpoint *ep) +{ + write_lock_bh(&hba->ep_rdwr_lock); + list_add_tail(&ep->link, &hba->ep_ofld_list); + write_unlock_bh(&hba->ep_rdwr_lock); + return 0; +} + +/** + * bnx2i_ep_ofld_list_del - add an entry to ep offload pending list + * @hba: pointer to adapter instance + * @ep: pointer to endpoint (transport indentifier) structure + * + * pending conn offload completion queue manager + */ +static int bnx2i_ep_ofld_list_del(struct bnx2i_hba *hba, + struct bnx2i_endpoint *ep) +{ + write_lock_bh(&hba->ep_rdwr_lock); + list_del_init(&ep->link); + write_unlock_bh(&hba->ep_rdwr_lock); + return 0; +} + + +/** + * bnx2i_find_ep_in_ofld_list - find iscsi_cid in pending list of endpoints + * + * @hba: pointer to adapter instance + * @iscsi_cid: iscsi context ID to find + * + */ +struct bnx2i_endpoint * +bnx2i_find_ep_in_ofld_list(struct bnx2i_hba *hba, u32 iscsi_cid) +{ + struct list_head *list; + struct list_head *tmp; + struct bnx2i_endpoint *ep; + + read_lock_bh(&hba->ep_rdwr_lock); + list_for_each_safe(list, tmp, &hba->ep_ofld_list) { + ep = (struct bnx2i_endpoint *)list; + + if (ep->ep_iscsi_cid == iscsi_cid) + break; + ep = NULL; + } + read_unlock_bh(&hba->ep_rdwr_lock); + + if (!ep) + printk(KERN_ERR "l5 cid %d not found\n", iscsi_cid); + return ep; +} + + +/** + * bnx2i_find_ep_in_destroy_list - find iscsi_cid in destroy list + * @hba: pointer to adapter instance + * @iscsi_cid: iscsi context ID to find + * + */ +struct bnx2i_endpoint * +bnx2i_find_ep_in_destroy_list(struct bnx2i_hba *hba, u32 iscsi_cid) +{ + struct list_head *list; + struct list_head *tmp; + struct bnx2i_endpoint *ep; + + read_lock_bh(&hba->ep_rdwr_lock); + list_for_each_safe(list, tmp, &hba->ep_destroy_list) { + ep = (struct bnx2i_endpoint *)list; + + if (ep->ep_iscsi_cid == iscsi_cid) + break; + ep = NULL; + } + read_unlock_bh(&hba->ep_rdwr_lock); + + if (!ep) + printk(KERN_ERR "l5 cid %d not found\n", iscsi_cid); + + return ep; +} + +/** + * bnx2i_setup_host_queue_size - assigns shost->can_queue param + * @hba: pointer to adapter instance + * @shost: scsi host pointer + * + * Initializes 'can_queue' parameter based on how many outstanding commands + * the device can handle. Each device 5708/5709/57710 has different + * capabilities + */ +static void bnx2i_setup_host_queue_size(struct bnx2i_hba *hba, + struct Scsi_Host *shost) +{ + if (test_bit(BNX2I_NX2_DEV_5708, &hba->cnic_dev_type)) + shost->can_queue = ISCSI_MAX_CMDS_PER_HBA_5708; + else if (test_bit(BNX2I_NX2_DEV_5709, &hba->cnic_dev_type)) + shost->can_queue = ISCSI_MAX_CMDS_PER_HBA_5709; + else if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type)) + shost->can_queue = ISCSI_MAX_CMDS_PER_HBA_57710; + else + shost->can_queue = ISCSI_MAX_CMDS_PER_HBA_5708; +} + + +/** + * bnx2i_alloc_hba - allocate and init adapter instance + * @cnic: cnic device pointer + * + * allocate & initialize adapter structure and call other + * support routines to do per adapter initialization + */ +struct bnx2i_hba *bnx2i_alloc_hba(struct cnic_dev *cnic) +{ + struct Scsi_Host *shost; + struct bnx2i_hba *hba; + + shost = iscsi_host_alloc(&bnx2i_host_template, sizeof(*hba), 0); + if (!shost) + return NULL; + shost->dma_boundary = cnic->pcidev->dma_mask; + shost->transportt = bnx2i_scsi_xport_template; + shost->max_id = ISCSI_MAX_CONNS_PER_HBA; + shost->max_channel = 0; + shost->max_lun = 512; + shost->max_cmd_len = 16; + + hba = iscsi_host_priv(shost); + hba->shost = shost; + hba->netdev = cnic->netdev; + /* Get PCI related information and update hba struct members */ + hba->pcidev = cnic->pcidev; + pci_dev_get(hba->pcidev); + hba->pci_did = hba->pcidev->device; + hba->pci_vid = hba->pcidev->vendor; + hba->pci_sdid = hba->pcidev->subsystem_device; + hba->pci_svid = hba->pcidev->subsystem_vendor; + hba->pci_func = PCI_FUNC(hba->pcidev->devfn); + hba->pci_devno = PCI_SLOT(hba->pcidev->devfn); + bnx2i_identify_device(hba); + + bnx2i_identify_device(hba); + bnx2i_setup_host_queue_size(hba, shost); + + if (test_bit(BNX2I_NX2_DEV_5709, &hba->cnic_dev_type)) { + hba->regview = ioremap_nocache(hba->netdev->base_addr, + BNX2_MQ_CONFIG2); + if (!hba->regview) + goto ioreg_map_err; + } else if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type)) { + hba->regview = ioremap_nocache(hba->netdev->base_addr, 4096); + if (!hba->regview) + goto ioreg_map_err; + } + + if (bnx2i_setup_mp_bdt(hba)) + goto mp_bdt_mem_err; + + INIT_LIST_HEAD(&hba->ep_ofld_list); + INIT_LIST_HEAD(&hba->ep_destroy_list); + rwlock_init(&hba->ep_rdwr_lock); + + hba->mtu_supported = BNX2I_MAX_MTU_SUPPORTED; + + /* different values for 5708/5709/57710 */ + hba->max_active_conns = ISCSI_MAX_CONNS_PER_HBA; + + if (bnx2i_setup_free_cid_que(hba)) + goto cid_que_err; + + /* SQ/RQ/CQ size can be changed via sysfx interface */ + if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type)) { + if (sq_size && sq_size <= BNX2I_5770X_SQ_WQES_MAX) + hba->max_sqes = sq_size; + else + hba->max_sqes = BNX2I_5770X_SQ_WQES_DEFAULT; + } else { /* 5706/5708/5709 */ + if (sq_size && sq_size <= BNX2I_570X_SQ_WQES_MAX) + hba->max_sqes = sq_size; + else + hba->max_sqes = BNX2I_570X_SQ_WQES_DEFAULT; + } + + hba->max_rqes = rq_size; + hba->max_cqes = hba->max_sqes + rq_size; + if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type)) { + if (hba->max_cqes > BNX2I_5770X_CQ_WQES_MAX) + hba->max_cqes = BNX2I_5770X_CQ_WQES_MAX; + } else if (hba->max_cqes > BNX2I_570X_CQ_WQES_MAX) + hba->max_cqes = BNX2I_570X_CQ_WQES_MAX; + + hba->num_ccell = hba->max_sqes / 2; + + spin_lock_init(&hba->lock); + mutex_init(&hba->net_dev_lock); + + if (iscsi_host_add(shost, &hba->pcidev->dev)) + goto free_dump_mem; + return hba; + +free_dump_mem: + bnx2i_release_free_cid_que(hba); +cid_que_err: + bnx2i_free_mp_bdt(hba); +mp_bdt_mem_err: + if (hba->regview) { + iounmap(hba->regview); + hba->regview = NULL; + } +ioreg_map_err: + pci_dev_put(hba->pcidev); + scsi_host_put(shost); + return NULL; +} + +/** + * bnx2i_free_hba- releases hba structure and resources held by the adapter + * @hba: pointer to adapter instance + * + * free adapter structure and call various cleanup routines. + */ +void bnx2i_free_hba(struct bnx2i_hba *hba) +{ + struct Scsi_Host *shost = hba->shost; + + iscsi_host_remove(shost); + INIT_LIST_HEAD(&hba->ep_ofld_list); + INIT_LIST_HEAD(&hba->ep_destroy_list); + pci_dev_put(hba->pcidev); + + if (hba->regview) { + iounmap(hba->regview); + hba->regview = NULL; + } + bnx2i_free_mp_bdt(hba); + bnx2i_release_free_cid_que(hba); + iscsi_host_free(shost); +} + +/** + * bnx2i_conn_free_login_resources - free DMA resources used for login process + * @hba: pointer to adapter instance + * @bnx2i_conn: iscsi connection pointer + * + * Login related resources, mostly BDT & payload DMA memory is freed + */ +static void bnx2i_conn_free_login_resources(struct bnx2i_hba *hba, + struct bnx2i_conn *bnx2i_conn) +{ + if (bnx2i_conn->gen_pdu.resp_bd_tbl) { + dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE, + bnx2i_conn->gen_pdu.resp_bd_tbl, + bnx2i_conn->gen_pdu.resp_bd_dma); + bnx2i_conn->gen_pdu.resp_bd_tbl = NULL; + } + + if (bnx2i_conn->gen_pdu.req_bd_tbl) { + dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE, + bnx2i_conn->gen_pdu.req_bd_tbl, + bnx2i_conn->gen_pdu.req_bd_dma); + bnx2i_conn->gen_pdu.req_bd_tbl = NULL; + } + + if (bnx2i_conn->gen_pdu.resp_buf) { + dma_free_coherent(&hba->pcidev->dev, + ISCSI_DEF_MAX_RECV_SEG_LEN, + bnx2i_conn->gen_pdu.resp_buf, + bnx2i_conn->gen_pdu.resp_dma_addr); + bnx2i_conn->gen_pdu.resp_buf = NULL; + } + + if (bnx2i_conn->gen_pdu.req_buf) { + dma_free_coherent(&hba->pcidev->dev, + ISCSI_DEF_MAX_RECV_SEG_LEN, + bnx2i_conn->gen_pdu.req_buf, + bnx2i_conn->gen_pdu.req_dma_addr); + bnx2i_conn->gen_pdu.req_buf = NULL; + } +} + +/** + * bnx2i_conn_alloc_login_resources - alloc DMA resources for login/nop. + * @hba: pointer to adapter instance + * @bnx2i_conn: iscsi connection pointer + * + * Mgmt task DNA resources are allocated in this routine. + */ +static int bnx2i_conn_alloc_login_resources(struct bnx2i_hba *hba, + struct bnx2i_conn *bnx2i_conn) +{ + /* Allocate memory for login request/response buffers */ + bnx2i_conn->gen_pdu.req_buf = + dma_alloc_coherent(&hba->pcidev->dev, + ISCSI_DEF_MAX_RECV_SEG_LEN, + &bnx2i_conn->gen_pdu.req_dma_addr, + GFP_KERNEL); + if (bnx2i_conn->gen_pdu.req_buf == NULL) + goto login_req_buf_failure; + + bnx2i_conn->gen_pdu.req_buf_size = 0; + bnx2i_conn->gen_pdu.req_wr_ptr = bnx2i_conn->gen_pdu.req_buf; + + bnx2i_conn->gen_pdu.resp_buf = + dma_alloc_coherent(&hba->pcidev->dev, + ISCSI_DEF_MAX_RECV_SEG_LEN, + &bnx2i_conn->gen_pdu.resp_dma_addr, + GFP_KERNEL); + if (bnx2i_conn->gen_pdu.resp_buf == NULL) + goto login_resp_buf_failure; + + bnx2i_conn->gen_pdu.resp_buf_size = ISCSI_DEF_MAX_RECV_SEG_LEN; + bnx2i_conn->gen_pdu.resp_wr_ptr = bnx2i_conn->gen_pdu.resp_buf; + + bnx2i_conn->gen_pdu.req_bd_tbl = + dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE, + &bnx2i_conn->gen_pdu.req_bd_dma, GFP_KERNEL); + if (bnx2i_conn->gen_pdu.req_bd_tbl == NULL) + goto login_req_bd_tbl_failure; + + bnx2i_conn->gen_pdu.resp_bd_tbl = + dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE, + &bnx2i_conn->gen_pdu.resp_bd_dma, + GFP_KERNEL); + if (bnx2i_conn->gen_pdu.resp_bd_tbl == NULL) + goto login_resp_bd_tbl_failure; + + return 0; + +login_resp_bd_tbl_failure: + dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE, + bnx2i_conn->gen_pdu.req_bd_tbl, + bnx2i_conn->gen_pdu.req_bd_dma); + bnx2i_conn->gen_pdu.req_bd_tbl = NULL; + +login_req_bd_tbl_failure: + dma_free_coherent(&hba->pcidev->dev, ISCSI_DEF_MAX_RECV_SEG_LEN, + bnx2i_conn->gen_pdu.resp_buf, + bnx2i_conn->gen_pdu.resp_dma_addr); + bnx2i_conn->gen_pdu.resp_buf = NULL; +login_resp_buf_failure: + dma_free_coherent(&hba->pcidev->dev, ISCSI_DEF_MAX_RECV_SEG_LEN, + bnx2i_conn->gen_pdu.req_buf, + bnx2i_conn->gen_pdu.req_dma_addr); + bnx2i_conn->gen_pdu.req_buf = NULL; +login_req_buf_failure: + iscsi_conn_printk(KERN_ERR, bnx2i_conn->cls_conn->dd_data, + "login resource alloc failed!!\n"); + return -ENOMEM; + +} + + +/** + * bnx2i_iscsi_prep_generic_pdu_bd - prepares BD table. + * @bnx2i_conn: iscsi connection pointer + * + * Allocates buffers and BD tables before shipping requests to cnic + * for PDUs prepared by 'iscsid' daemon + */ +static void bnx2i_iscsi_prep_generic_pdu_bd(struct bnx2i_conn *bnx2i_conn) +{ + struct iscsi_bd *bd_tbl; + + bd_tbl = (struct iscsi_bd *) bnx2i_conn->gen_pdu.req_bd_tbl; + + bd_tbl->buffer_addr_hi = + (u32) ((u64) bnx2i_conn->gen_pdu.req_dma_addr >> 32); + bd_tbl->buffer_addr_lo = (u32) bnx2i_conn->gen_pdu.req_dma_addr; + bd_tbl->buffer_length = bnx2i_conn->gen_pdu.req_wr_ptr - + bnx2i_conn->gen_pdu.req_buf; + bd_tbl->reserved0 = 0; + bd_tbl->flags = ISCSI_BD_LAST_IN_BD_CHAIN | + ISCSI_BD_FIRST_IN_BD_CHAIN; + + bd_tbl = (struct iscsi_bd *) bnx2i_conn->gen_pdu.resp_bd_tbl; + bd_tbl->buffer_addr_hi = (u64) bnx2i_conn->gen_pdu.resp_dma_addr >> 32; + bd_tbl->buffer_addr_lo = (u32) bnx2i_conn->gen_pdu.resp_dma_addr; + bd_tbl->buffer_length = ISCSI_DEF_MAX_RECV_SEG_LEN; + bd_tbl->reserved0 = 0; + bd_tbl->flags = ISCSI_BD_LAST_IN_BD_CHAIN | + ISCSI_BD_FIRST_IN_BD_CHAIN; +} + + +/** + * bnx2i_iscsi_send_generic_request - called to send mgmt tasks. + * @task: transport layer task pointer + * + * called to transmit PDUs prepared by the 'iscsid' daemon. iSCSI login, + * Nop-out and Logout requests flow through this path. + */ +static int bnx2i_iscsi_send_generic_request(struct iscsi_task *task) +{ + struct bnx2i_cmd *cmd = task->dd_data; + struct bnx2i_conn *bnx2i_conn = cmd->conn; + int rc = 0; + char *buf; + int data_len; + + bnx2i_iscsi_prep_generic_pdu_bd(bnx2i_conn); + switch (task->hdr->opcode & ISCSI_OPCODE_MASK) { + case ISCSI_OP_LOGIN: + bnx2i_send_iscsi_login(bnx2i_conn, task); + break; + case ISCSI_OP_NOOP_OUT: + data_len = bnx2i_conn->gen_pdu.req_buf_size; + buf = bnx2i_conn->gen_pdu.req_buf; + if (data_len) + rc = bnx2i_send_iscsi_nopout(bnx2i_conn, task, + RESERVED_ITT, + buf, data_len, 1); + else + rc = bnx2i_send_iscsi_nopout(bnx2i_conn, task, + RESERVED_ITT, + NULL, 0, 1); + break; + case ISCSI_OP_LOGOUT: + rc = bnx2i_send_iscsi_logout(bnx2i_conn, task); + break; + case ISCSI_OP_SCSI_TMFUNC: + rc = bnx2i_send_iscsi_tmf(bnx2i_conn, task); + break; + default: + iscsi_conn_printk(KERN_ALERT, bnx2i_conn->cls_conn->dd_data, + "send_gen: unsupported op 0x%x\n", + task->hdr->opcode); + } + return rc; +} + + +/********************************************************************** + * SCSI-ML Interface + **********************************************************************/ + +/** + * bnx2i_cpy_scsi_cdb - copies LUN & CDB fields in required format to sq wqe + * @sc: SCSI-ML command pointer + * @cmd: iscsi cmd pointer + */ +static void bnx2i_cpy_scsi_cdb(struct scsi_cmnd *sc, struct bnx2i_cmd *cmd) +{ + u32 dword; + int lpcnt; + u8 *srcp; + u32 *dstp; + u32 scsi_lun[2]; + + int_to_scsilun(sc->device->lun, (struct scsi_lun *) scsi_lun); + cmd->req.lun[0] = be32_to_cpu(scsi_lun[0]); + cmd->req.lun[1] = be32_to_cpu(scsi_lun[1]); + + lpcnt = cmd->scsi_cmd->cmd_len / sizeof(dword); + srcp = (u8 *) sc->cmnd; + dstp = (u32 *) cmd->req.cdb; + while (lpcnt--) { + memcpy(&dword, (const void *) srcp, 4); + *dstp = cpu_to_be32(dword); + srcp += 4; + dstp++; + } + if (sc->cmd_len & 0x3) { + dword = (u32) srcp[0] | ((u32) srcp[1] << 8); + *dstp = cpu_to_be32(dword); + } +} + +static void bnx2i_cleanup_task(struct iscsi_task *task) +{ + struct iscsi_conn *conn = task->conn; + struct bnx2i_conn *bnx2i_conn = conn->dd_data; + struct bnx2i_hba *hba = bnx2i_conn->hba; + + /* + * mgmt task or cmd was never sent to us to transmit. + */ + if (!task->sc || task->state == ISCSI_TASK_PENDING) + return; + /* + * need to clean-up task context to claim dma buffers + */ + if (task->state == ISCSI_TASK_ABRT_TMF) { + bnx2i_send_cmd_cleanup_req(hba, task->dd_data); + + spin_unlock_bh(&conn->session->lock); + wait_for_completion_timeout(&bnx2i_conn->cmd_cleanup_cmpl, + msecs_to_jiffies(ISCSI_CMD_CLEANUP_TIMEOUT)); + spin_lock_bh(&conn->session->lock); + } + bnx2i_iscsi_unmap_sg_list(task->dd_data); +} + +/** + * bnx2i_mtask_xmit - transmit mtask to chip for further processing + * @conn: transport layer conn structure pointer + * @task: transport layer command structure pointer + */ +static int +bnx2i_mtask_xmit(struct iscsi_conn *conn, struct iscsi_task *task) +{ + struct bnx2i_conn *bnx2i_conn = conn->dd_data; + struct bnx2i_cmd *cmd = task->dd_data; + + memset(bnx2i_conn->gen_pdu.req_buf, 0, ISCSI_DEF_MAX_RECV_SEG_LEN); + + bnx2i_setup_cmd_wqe_template(cmd); + bnx2i_conn->gen_pdu.req_buf_size = task->data_count; + if (task->data_count) { + memcpy(bnx2i_conn->gen_pdu.req_buf, task->data, + task->data_count); + bnx2i_conn->gen_pdu.req_wr_ptr = + bnx2i_conn->gen_pdu.req_buf + task->data_count; + } + cmd->conn = conn->dd_data; + cmd->scsi_cmd = NULL; + return bnx2i_iscsi_send_generic_request(task); +} + +/** + * bnx2i_task_xmit - transmit iscsi command to chip for further processing + * @task: transport layer command structure pointer + * + * maps SG buffers and send request to chip/firmware in the form of SQ WQE + */ +static int bnx2i_task_xmit(struct iscsi_task *task) +{ + struct iscsi_conn *conn = task->conn; + struct iscsi_session *session = conn->session; + struct Scsi_Host *shost = iscsi_session_to_shost(session->cls_session); + struct bnx2i_hba *hba = iscsi_host_priv(shost); + struct bnx2i_conn *bnx2i_conn = conn->dd_data; + struct scsi_cmnd *sc = task->sc; + struct bnx2i_cmd *cmd = task->dd_data; + struct iscsi_cmd *hdr = (struct iscsi_cmd *) task->hdr; + + if (test_bit(ADAPTER_STATE_LINK_DOWN, &hba->adapter_state)) + return -ENOTCONN; + + if (!bnx2i_conn->is_bound) + return -ENOTCONN; + + /* + * If there is no scsi_cmnd this must be a mgmt task + */ + if (!sc) + return bnx2i_mtask_xmit(conn, task); + + bnx2i_setup_cmd_wqe_template(cmd); + cmd->req.op_code = ISCSI_OP_SCSI_CMD; + cmd->conn = bnx2i_conn; + cmd->scsi_cmd = sc; + cmd->req.total_data_transfer_length = scsi_bufflen(sc); + cmd->req.cmd_sn = be32_to_cpu(hdr->cmdsn); + + bnx2i_iscsi_map_sg_list(cmd); + bnx2i_cpy_scsi_cdb(sc, cmd); + + cmd->req.op_attr = ISCSI_ATTR_SIMPLE; + if (sc->sc_data_direction == DMA_TO_DEVICE) { + cmd->req.op_attr |= ISCSI_CMD_REQUEST_WRITE; + cmd->req.itt = task->itt | + (ISCSI_TASK_TYPE_WRITE << ISCSI_CMD_REQUEST_TYPE_SHIFT); + bnx2i_setup_write_cmd_bd_info(task); + } else { + if (scsi_bufflen(sc)) + cmd->req.op_attr |= ISCSI_CMD_REQUEST_READ; + cmd->req.itt = task->itt | + (ISCSI_TASK_TYPE_READ << ISCSI_CMD_REQUEST_TYPE_SHIFT); + } + + cmd->req.num_bds = cmd->io_tbl.bd_valid; + if (!cmd->io_tbl.bd_valid) { + cmd->req.bd_list_addr_lo = (u32) hba->mp_bd_dma; + cmd->req.bd_list_addr_hi = (u32) ((u64) hba->mp_bd_dma >> 32); + cmd->req.num_bds = 1; + } + + bnx2i_send_iscsi_scsicmd(bnx2i_conn, cmd); + return 0; +} + +/** + * bnx2i_session_create - create a new iscsi session + * @cmds_max: max commands supported + * @qdepth: scsi queue depth to support + * @initial_cmdsn: initial iscsi CMDSN to be used for this session + * + * Creates a new iSCSI session instance on given device. + */ +static struct iscsi_cls_session * +bnx2i_session_create(struct iscsi_endpoint *ep, + uint16_t cmds_max, uint16_t qdepth, + uint32_t initial_cmdsn) +{ + struct Scsi_Host *shost; + struct iscsi_cls_session *cls_session; + struct bnx2i_hba *hba; + struct bnx2i_endpoint *bnx2i_ep; + + if (!ep) { + printk(KERN_ERR "bnx2i: missing ep.\n"); + return NULL; + } + + bnx2i_ep = ep->dd_data; + shost = bnx2i_ep->hba->shost; + hba = iscsi_host_priv(shost); + if (bnx2i_adapter_ready(hba)) + return NULL; + + /* + * user can override hw limit as long as it is within + * the min/max. + */ + if (cmds_max > hba->max_sqes) + cmds_max = hba->max_sqes; + else if (cmds_max < BNX2I_SQ_WQES_MIN) + cmds_max = BNX2I_SQ_WQES_MIN; + + cls_session = iscsi_session_setup(&bnx2i_iscsi_transport, shost, + cmds_max, sizeof(struct bnx2i_cmd), + initial_cmdsn, ISCSI_MAX_TARGET); + if (!cls_session) + return NULL; + + if (bnx2i_setup_cmd_pool(hba, cls_session->dd_data)) + goto session_teardown; + return cls_session; + +session_teardown: + iscsi_session_teardown(cls_session); + return NULL; +} + + +/** + * bnx2i_session_destroy - destroys iscsi session + * @cls_session: pointer to iscsi cls session + * + * Destroys previously created iSCSI session instance and releases + * all resources held by it + */ +static void bnx2i_session_destroy(struct iscsi_cls_session *cls_session) +{ + struct iscsi_session *session = cls_session->dd_data; + struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); + struct bnx2i_hba *hba = iscsi_host_priv(shost); + + bnx2i_destroy_cmd_pool(hba, session); + iscsi_session_teardown(cls_session); +} + + +/** + * bnx2i_conn_create - create iscsi connection instance + * @cls_session: pointer to iscsi cls session + * @cid: iscsi cid as per rfc (not NX2's CID terminology) + * + * Creates a new iSCSI connection instance for a given session + */ +static struct iscsi_cls_conn * +bnx2i_conn_create(struct iscsi_cls_session *cls_session, uint32_t cid) +{ + struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); + struct bnx2i_hba *hba = iscsi_host_priv(shost); + struct bnx2i_conn *bnx2i_conn; + struct iscsi_cls_conn *cls_conn; + struct iscsi_conn *conn; + + cls_conn = iscsi_conn_setup(cls_session, sizeof(*bnx2i_conn), + cid); + if (!cls_conn) + return NULL; + conn = cls_conn->dd_data; + + bnx2i_conn = conn->dd_data; + bnx2i_conn->cls_conn = cls_conn; + bnx2i_conn->hba = hba; + /* 'ep' ptr will be assigned in bind() call */ + bnx2i_conn->ep = NULL; + init_completion(&bnx2i_conn->cmd_cleanup_cmpl); + + if (bnx2i_conn_alloc_login_resources(hba, bnx2i_conn)) { + iscsi_conn_printk(KERN_ALERT, conn, + "conn_new: login resc alloc failed!!\n"); + goto free_conn; + } + + return cls_conn; + +free_conn: + iscsi_conn_teardown(cls_conn); + return NULL; +} + +/** + * bnx2i_conn_bind - binds iscsi sess, conn and ep objects together + * @cls_session: pointer to iscsi cls session + * @cls_conn: pointer to iscsi cls conn + * @transport_fd: 64-bit EP handle + * @is_leading: leading connection on this session? + * + * Binds together iSCSI session instance, iSCSI connection instance + * and the TCP connection. This routine returns error code if + * TCP connection does not belong on the device iSCSI sess/conn + * is bound + */ +static int bnx2i_conn_bind(struct iscsi_cls_session *cls_session, + struct iscsi_cls_conn *cls_conn, + uint64_t transport_fd, int is_leading) +{ + struct iscsi_conn *conn = cls_conn->dd_data; + struct bnx2i_conn *bnx2i_conn = conn->dd_data; + struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); + struct bnx2i_hba *hba = iscsi_host_priv(shost); + struct bnx2i_endpoint *bnx2i_ep; + struct iscsi_endpoint *ep; + int ret_code; + + ep = iscsi_lookup_endpoint(transport_fd); + if (!ep) + return -EINVAL; + + bnx2i_ep = ep->dd_data; + if ((bnx2i_ep->state == EP_STATE_TCP_FIN_RCVD) || + (bnx2i_ep->state == EP_STATE_TCP_RST_RCVD)) + /* Peer disconnect via' FIN or RST */ + return -EINVAL; + + if (iscsi_conn_bind(cls_session, cls_conn, is_leading)) + return -EINVAL; + + if (bnx2i_ep->hba != hba) { + /* Error - TCP connection does not belong to this device + */ + iscsi_conn_printk(KERN_ALERT, cls_conn->dd_data, + "conn bind, ep=0x%p (%s) does not", + bnx2i_ep, bnx2i_ep->hba->netdev->name); + iscsi_conn_printk(KERN_ALERT, cls_conn->dd_data, + "belong to hba (%s)\n", + hba->netdev->name); + return -EEXIST; + } + + bnx2i_ep->conn = bnx2i_conn; + bnx2i_conn->ep = bnx2i_ep; + bnx2i_conn->iscsi_conn_cid = bnx2i_ep->ep_iscsi_cid; + bnx2i_conn->fw_cid = bnx2i_ep->ep_cid; + bnx2i_conn->is_bound = 1; + + ret_code = bnx2i_bind_conn_to_iscsi_cid(hba, bnx2i_conn, + bnx2i_ep->ep_iscsi_cid); + + /* 5706/5708/5709 FW takes RQ as full when initiated, but for 57710 + * driver needs to explicitly replenish RQ index during setup. + */ + if (test_bit(BNX2I_NX2_DEV_57710, &bnx2i_ep->hba->cnic_dev_type)) + bnx2i_put_rq_buf(bnx2i_conn, 0); + + bnx2i_arm_cq_event_coalescing(bnx2i_conn->ep, CNIC_ARM_CQE); + return ret_code; +} + + +/** + * bnx2i_conn_destroy - destroy iscsi connection instance & release resources + * @cls_conn: pointer to iscsi cls conn + * + * Destroy an iSCSI connection instance and release memory resources held by + * this connection + */ +static void bnx2i_conn_destroy(struct iscsi_cls_conn *cls_conn) +{ + struct iscsi_conn *conn = cls_conn->dd_data; + struct bnx2i_conn *bnx2i_conn = conn->dd_data; + struct Scsi_Host *shost; + struct bnx2i_hba *hba; + + shost = iscsi_session_to_shost(iscsi_conn_to_session(cls_conn)); + hba = iscsi_host_priv(shost); + + bnx2i_conn_free_login_resources(hba, bnx2i_conn); + iscsi_conn_teardown(cls_conn); +} + + +/** + * bnx2i_conn_get_param - return iscsi connection parameter to caller + * @cls_conn: pointer to iscsi cls conn + * @param: parameter type identifier + * @buf: buffer pointer + * + * returns iSCSI connection parameters + */ +static int bnx2i_conn_get_param(struct iscsi_cls_conn *cls_conn, + enum iscsi_param param, char *buf) +{ + struct iscsi_conn *conn = cls_conn->dd_data; + struct bnx2i_conn *bnx2i_conn = conn->dd_data; + int len = 0; + + switch (param) { + case ISCSI_PARAM_CONN_PORT: + if (bnx2i_conn->ep) + len = sprintf(buf, "%hu\n", + bnx2i_conn->ep->cm_sk->dst_port); + break; + case ISCSI_PARAM_CONN_ADDRESS: + if (bnx2i_conn->ep) + len = sprintf(buf, NIPQUAD_FMT "\n", + NIPQUAD(bnx2i_conn->ep->cm_sk->dst_ip)); + break; + default: + return iscsi_conn_get_param(cls_conn, param, buf); + } + + return len; +} + +/** + * bnx2i_host_get_param - returns host (adapter) related parameters + * @shost: scsi host pointer + * @param: parameter type identifier + * @buf: buffer pointer + */ +static int bnx2i_host_get_param(struct Scsi_Host *shost, + enum iscsi_host_param param, char *buf) +{ + struct bnx2i_hba *hba = iscsi_host_priv(shost); + int len = 0; + + switch (param) { + case ISCSI_HOST_PARAM_HWADDRESS: + len = sysfs_format_mac(buf, hba->cnic->mac_addr, 6); + break; + case ISCSI_HOST_PARAM_NETDEV_NAME: + len = sprintf(buf, "%s\n", hba->netdev->name); + break; + default: + return iscsi_host_get_param(shost, param, buf); + } + return len; +} + +/** + * bnx2i_conn_start - completes iscsi connection migration to FFP + * @cls_conn: pointer to iscsi cls conn + * + * last call in FFP migration to handover iscsi conn to the driver + */ +static int bnx2i_conn_start(struct iscsi_cls_conn *cls_conn) +{ + struct iscsi_conn *conn = cls_conn->dd_data; + struct bnx2i_conn *bnx2i_conn = conn->dd_data; + + bnx2i_conn->ep->state = EP_STATE_ULP_UPDATE_START; + bnx2i_update_iscsi_conn(conn); + + /* + * this should normally not sleep for a long time so it should + * not disrupt the caller. + */ + bnx2i_conn->ep->ofld_timer.expires = 1 * HZ + jiffies; + bnx2i_conn->ep->ofld_timer.function = bnx2i_ep_ofld_timer; + bnx2i_conn->ep->ofld_timer.data = (unsigned long) bnx2i_conn->ep; + add_timer(&bnx2i_conn->ep->ofld_timer); + /* update iSCSI context for this conn, wait for CNIC to complete */ + wait_event_interruptible(bnx2i_conn->ep->ofld_wait, + bnx2i_conn->ep->state != EP_STATE_ULP_UPDATE_START); + + if (signal_pending(current)) + flush_signals(current); + del_timer_sync(&bnx2i_conn->ep->ofld_timer); + + iscsi_conn_start(cls_conn); + return 0; +} + + +/** + * bnx2i_conn_get_stats - returns iSCSI stats + * @cls_conn: pointer to iscsi cls conn + * @stats: pointer to iscsi statistic struct + */ +static void bnx2i_conn_get_stats(struct iscsi_cls_conn *cls_conn, + struct iscsi_stats *stats) +{ + struct iscsi_conn *conn = cls_conn->dd_data; + + stats->txdata_octets = conn->txdata_octets; + stats->rxdata_octets = conn->rxdata_octets; + stats->scsicmd_pdus = conn->scsicmd_pdus_cnt; + stats->dataout_pdus = conn->dataout_pdus_cnt; + stats->scsirsp_pdus = conn->scsirsp_pdus_cnt; + stats->datain_pdus = conn->datain_pdus_cnt; + stats->r2t_pdus = conn->r2t_pdus_cnt; + stats->tmfcmd_pdus = conn->tmfcmd_pdus_cnt; + stats->tmfrsp_pdus = conn->tmfrsp_pdus_cnt; + stats->custom_length = 3; + strcpy(stats->custom[2].desc, "eh_abort_cnt"); + stats->custom[2].value = conn->eh_abort_cnt; + stats->digest_err = 0; + stats->timeout_err = 0; + stats->custom_length = 0; +} + + +/** + * bnx2i_check_route - checks if target IP route belongs to one of NX2 devices + * @dst_addr: target IP address + * + * check if route resolves to BNX2 device + */ +static struct bnx2i_hba *bnx2i_check_route(struct sockaddr *dst_addr) +{ + struct sockaddr_in *desti = (struct sockaddr_in *) dst_addr; + struct bnx2i_hba *hba; + struct cnic_dev *cnic = NULL; + + bnx2i_reg_dev_all(); + + hba = get_adapter_list_head(); + if (hba && hba->cnic) + cnic = hba->cnic->cm_select_dev(desti, CNIC_ULP_ISCSI); + if (!cnic) { + printk(KERN_ALERT "bnx2i: no route," + "can't connect using cnic\n"); + goto no_nx2_route; + } + hba = bnx2i_find_hba_for_cnic(cnic); + if (!hba) + goto no_nx2_route; + + if (bnx2i_adapter_ready(hba)) { + printk(KERN_ALERT "bnx2i: check route, hba not found\n"); + goto no_nx2_route; + } + if (hba->netdev->mtu > hba->mtu_supported) { + printk(KERN_ALERT "bnx2i: %s network i/f mtu is set to %d\n", + hba->netdev->name, hba->netdev->mtu); + printk(KERN_ALERT "bnx2i: iSCSI HBA can support mtu of %d\n", + hba->mtu_supported); + goto no_nx2_route; + } + return hba; +no_nx2_route: + return NULL; +} + + +/** + * bnx2i_tear_down_conn - tear down iscsi/tcp connection and free resources + * @hba: pointer to adapter instance + * @ep: endpoint (transport indentifier) structure + * + * destroys cm_sock structure and on chip iscsi context + */ +static int bnx2i_tear_down_conn(struct bnx2i_hba *hba, + struct bnx2i_endpoint *ep) +{ + if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) + hba->cnic->cm_destroy(ep->cm_sk); + + if (test_bit(ADAPTER_STATE_GOING_DOWN, &ep->hba->adapter_state)) + ep->state = EP_STATE_DISCONN_COMPL; + + if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type) && + ep->state == EP_STATE_DISCONN_TIMEDOUT) { + printk(KERN_ALERT "bnx2i - ERROR - please submit GRC Dump," + " NW/PCIe trace, driver msgs to developers" + " for analysis\n"); + return 1; + } + + ep->state = EP_STATE_CLEANUP_START; + init_timer(&ep->ofld_timer); + ep->ofld_timer.expires = 10*HZ + jiffies; + ep->ofld_timer.function = bnx2i_ep_ofld_timer; + ep->ofld_timer.data = (unsigned long) ep; + add_timer(&ep->ofld_timer); + + bnx2i_ep_destroy_list_add(hba, ep); + + /* destroy iSCSI context, wait for it to complete */ + bnx2i_send_conn_destroy(hba, ep); + wait_event_interruptible(ep->ofld_wait, + (ep->state != EP_STATE_CLEANUP_START)); + + if (signal_pending(current)) + flush_signals(current); + del_timer_sync(&ep->ofld_timer); + + bnx2i_ep_destroy_list_del(hba, ep); + + if (ep->state != EP_STATE_CLEANUP_CMPL) + /* should never happen */ + printk(KERN_ALERT "bnx2i - conn destroy failed\n"); + + return 0; +} + + +/** + * bnx2i_ep_connect - establish TCP connection to target portal + * @shost: scsi host + * @dst_addr: target IP address + * @non_blocking: blocking or non-blocking call + * + * this routine initiates the TCP/IP connection by invoking Option-2 i/f + * with l5_core and the CNIC. This is a multi-step process of resolving + * route to target, create a iscsi connection context, handshaking with + * CNIC module to create/initialize the socket struct and finally + * sending down option-2 request to complete TCP 3-way handshake + */ +static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost, + struct sockaddr *dst_addr, + int non_blocking) +{ + u32 iscsi_cid = BNX2I_CID_RESERVED; + struct sockaddr_in *desti = (struct sockaddr_in *) dst_addr; + struct sockaddr_in6 *desti6; + struct bnx2i_endpoint *bnx2i_ep; + struct bnx2i_hba *hba; + struct cnic_dev *cnic; + struct cnic_sockaddr saddr; + struct iscsi_endpoint *ep; + int rc = 0; + + if (shost) + /* driver is given scsi host to work with */ + hba = iscsi_host_priv(shost); + else + /* + * check if the given destination can be reached through + * a iscsi capable NetXtreme2 device + */ + hba = bnx2i_check_route(dst_addr); + if (!hba) { + rc = -ENOMEM; + goto check_busy; + } + + cnic = hba->cnic; + ep = bnx2i_alloc_ep(hba); + if (!ep) { + rc = -ENOMEM; + goto check_busy; + } + bnx2i_ep = ep->dd_data; + + mutex_lock(&hba->net_dev_lock); + if (bnx2i_adapter_ready(hba)) { + rc = -EPERM; + goto net_if_down; + } + + bnx2i_ep->state = EP_STATE_IDLE; + bnx2i_ep->ep_iscsi_cid = (u16) -1; + bnx2i_ep->num_active_cmds = 0; + iscsi_cid = bnx2i_alloc_iscsi_cid(hba); + if (iscsi_cid == -1) { + printk(KERN_ALERT "alloc_ep: unable to allocate iscsi cid\n"); + rc = -ENOMEM; + goto iscsi_cid_err; + } + bnx2i_ep->hba_age = hba->age; + + rc = bnx2i_alloc_qp_resc(hba, bnx2i_ep); + if (rc != 0) { + printk(KERN_ALERT "bnx2i: ep_conn, alloc QP resc error\n"); + rc = -ENOMEM; + goto qp_resc_err; + } + + bnx2i_ep->ep_iscsi_cid = (u16)iscsi_cid; + bnx2i_ep->state = EP_STATE_OFLD_START; + bnx2i_ep_ofld_list_add(hba, bnx2i_ep); + + init_timer(&bnx2i_ep->ofld_timer); + bnx2i_ep->ofld_timer.expires = 2 * HZ + jiffies; + bnx2i_ep->ofld_timer.function = bnx2i_ep_ofld_timer; + bnx2i_ep->ofld_timer.data = (unsigned long) bnx2i_ep; + add_timer(&bnx2i_ep->ofld_timer); + + bnx2i_send_conn_ofld_req(hba, bnx2i_ep); + + /* Wait for CNIC hardware to setup conn context and return 'cid' */ + wait_event_interruptible(bnx2i_ep->ofld_wait, + bnx2i_ep->state != EP_STATE_OFLD_START); + + if (signal_pending(current)) + flush_signals(current); + del_timer_sync(&bnx2i_ep->ofld_timer); + + bnx2i_ep_ofld_list_del(hba, bnx2i_ep); + + if (bnx2i_ep->state != EP_STATE_OFLD_COMPL) { + rc = -ENOSPC; + goto conn_failed; + } + + rc = cnic->cm_create(cnic, CNIC_ULP_ISCSI, bnx2i_ep->ep_cid, + iscsi_cid, &bnx2i_ep->cm_sk, bnx2i_ep); + if (rc) { + rc = -EINVAL; + goto conn_failed; + } + + bnx2i_ep->cm_sk->rcv_buf = 256 * 1024; + bnx2i_ep->cm_sk->snd_buf = 256 * 1024; + clear_bit(SK_TCP_TIMESTAMP, &bnx2i_ep->cm_sk->tcp_flags); + + memset(&saddr, 0, sizeof(saddr)); + if (dst_addr->sa_family == AF_INET) { + desti = (struct sockaddr_in *) dst_addr; + saddr.remote.v4 = *desti; + saddr.local.v4.sin_family = desti->sin_family; + } else if (dst_addr->sa_family == AF_INET6) { + desti6 = (struct sockaddr_in6 *) dst_addr; + saddr.remote.v6 = *desti6; + saddr.local.v6.sin6_family = desti6->sin6_family; + } + + bnx2i_ep->timestamp = jiffies; + bnx2i_ep->state = EP_STATE_CONNECT_START; + if (!test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) { + rc = -EINVAL; + goto conn_failed; + } else + rc = cnic->cm_connect(bnx2i_ep->cm_sk, &saddr); + + if (rc) + goto release_ep; + + if (bnx2i_map_ep_dbell_regs(bnx2i_ep)) + goto release_ep; + mutex_unlock(&hba->net_dev_lock); + return ep; + +release_ep: + if (bnx2i_tear_down_conn(hba, bnx2i_ep)) { + mutex_unlock(&hba->net_dev_lock); + return ERR_PTR(rc); + } +conn_failed: +net_if_down: +iscsi_cid_err: + bnx2i_free_qp_resc(hba, bnx2i_ep); +qp_resc_err: + bnx2i_free_ep(ep); + mutex_unlock(&hba->net_dev_lock); +check_busy: + bnx2i_unreg_dev_all(); + return ERR_PTR(rc); +} + + +/** + * bnx2i_ep_poll - polls for TCP connection establishement + * @ep: TCP connection (endpoint) handle + * @timeout_ms: timeout value in milli secs + * + * polls for TCP connect request to complete + */ +static int bnx2i_ep_poll(struct iscsi_endpoint *ep, int timeout_ms) +{ + struct bnx2i_endpoint *bnx2i_ep; + int rc = 0; + + bnx2i_ep = ep->dd_data; + if ((bnx2i_ep->state == EP_STATE_IDLE) || + (bnx2i_ep->state == EP_STATE_CONNECT_FAILED) || + (bnx2i_ep->state == EP_STATE_OFLD_FAILED)) + return -1; + if (bnx2i_ep->state == EP_STATE_CONNECT_COMPL) + return 1; + + rc = wait_event_interruptible_timeout(bnx2i_ep->ofld_wait, + ((bnx2i_ep->state == + EP_STATE_OFLD_FAILED) || + (bnx2i_ep->state == + EP_STATE_CONNECT_FAILED) || + (bnx2i_ep->state == + EP_STATE_CONNECT_COMPL)), + msecs_to_jiffies(timeout_ms)); + if (!rc || (bnx2i_ep->state == EP_STATE_OFLD_FAILED)) + rc = -1; + + if (rc > 0) + return 1; + else if (!rc) + return 0; /* timeout */ + else + return rc; +} + + +/** + * bnx2i_ep_tcp_conn_active - check EP state transition + * @ep: endpoint pointer + * + * check if underlying TCP connection is active + */ +static int bnx2i_ep_tcp_conn_active(struct bnx2i_endpoint *bnx2i_ep) +{ + int ret; + int cnic_dev_10g = 0; + + if (test_bit(BNX2I_NX2_DEV_57710, &bnx2i_ep->hba->cnic_dev_type)) + cnic_dev_10g = 1; + + switch (bnx2i_ep->state) { + case EP_STATE_CONNECT_START: + case EP_STATE_CLEANUP_FAILED: + case EP_STATE_OFLD_FAILED: + case EP_STATE_DISCONN_TIMEDOUT: + ret = 0; + break; + case EP_STATE_CONNECT_COMPL: + case EP_STATE_ULP_UPDATE_START: + case EP_STATE_ULP_UPDATE_COMPL: + case EP_STATE_TCP_FIN_RCVD: + case EP_STATE_ULP_UPDATE_FAILED: + ret = 1; + break; + case EP_STATE_TCP_RST_RCVD: + ret = 0; + break; + case EP_STATE_CONNECT_FAILED: + if (cnic_dev_10g) + ret = 1; + else + ret = 0; + break; + default: + ret = 0; + } + + return ret; +} + + +/** + * bnx2i_ep_disconnect - executes TCP connection teardown process + * @ep: TCP connection (endpoint) handle + * + * executes TCP connection teardown process + */ +static void bnx2i_ep_disconnect(struct iscsi_endpoint *ep) +{ + struct bnx2i_endpoint *bnx2i_ep; + struct bnx2i_conn *bnx2i_conn = NULL; + struct iscsi_session *session = NULL; + struct iscsi_conn *conn; + struct cnic_dev *cnic; + struct bnx2i_hba *hba; + + bnx2i_ep = ep->dd_data; + + /* driver should not attempt connection cleanup untill TCP_CONNECT + * completes either successfully or fails. Timeout is 9-secs, so + * wait for it to complete + */ + while ((bnx2i_ep->state == EP_STATE_CONNECT_START) && + !time_after(jiffies, bnx2i_ep->timestamp + (12 * HZ))) + msleep(250); + + if (bnx2i_ep->conn) { + bnx2i_conn = bnx2i_ep->conn; + conn = bnx2i_conn->cls_conn->dd_data; + session = conn->session; + + spin_lock_bh(&session->lock); + bnx2i_conn->is_bound = 0; + spin_unlock_bh(&session->lock); + } + + hba = bnx2i_ep->hba; + if (bnx2i_ep->state == EP_STATE_IDLE) + goto return_bnx2i_ep; + cnic = hba->cnic; + + mutex_lock(&hba->net_dev_lock); + + if (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state)) + goto free_resc; + if (bnx2i_ep->hba_age != hba->age) + goto free_resc; + + if (!bnx2i_ep_tcp_conn_active(bnx2i_ep)) + goto destory_conn; + + bnx2i_ep->state = EP_STATE_DISCONN_START; + + init_timer(&bnx2i_ep->ofld_timer); + bnx2i_ep->ofld_timer.expires = 10*HZ + jiffies; + bnx2i_ep->ofld_timer.function = bnx2i_ep_ofld_timer; + bnx2i_ep->ofld_timer.data = (unsigned long) bnx2i_ep; + add_timer(&bnx2i_ep->ofld_timer); + + if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) { + int close = 0; + + if (session) { + spin_lock_bh(&session->lock); + if (session->state == ISCSI_STATE_LOGGING_OUT) + close = 1; + spin_unlock_bh(&session->lock); + } + if (close) + cnic->cm_close(bnx2i_ep->cm_sk); + else + cnic->cm_abort(bnx2i_ep->cm_sk); + } else + goto free_resc; + + /* wait for option-2 conn teardown */ + wait_event_interruptible(bnx2i_ep->ofld_wait, + bnx2i_ep->state != EP_STATE_DISCONN_START); + + if (signal_pending(current)) + flush_signals(current); + del_timer_sync(&bnx2i_ep->ofld_timer); + +destory_conn: + if (bnx2i_tear_down_conn(hba, bnx2i_ep)) { + mutex_unlock(&hba->net_dev_lock); + return; + } +free_resc: + mutex_unlock(&hba->net_dev_lock); + bnx2i_free_qp_resc(hba, bnx2i_ep); +return_bnx2i_ep: + if (bnx2i_conn) + bnx2i_conn->ep = NULL; + + bnx2i_free_ep(ep); + + if (!hba->ofld_conns_active) + bnx2i_unreg_dev_all(); +} + + +/** + * bnx2i_nl_set_path - ISCSI_UEVENT_PATH_UPDATE user message handler + * @buf: pointer to buffer containing iscsi path message + * + */ +static int bnx2i_nl_set_path(struct Scsi_Host *shost, struct iscsi_path *params) +{ + struct bnx2i_hba *hba = iscsi_host_priv(shost); + char *buf = (char *) params; + u16 len = sizeof(*params); + + /* handled by cnic driver */ + hba->cnic->iscsi_nl_msg_recv(hba->cnic, ISCSI_UEVENT_PATH_UPDATE, buf, + len); + + return 0; +} + + +/* + * 'Scsi_Host_Template' structure and 'iscsi_tranport' structure template + * used while registering with the scsi host and iSCSI transport module. + */ +static struct scsi_host_template bnx2i_host_template = { + .module = THIS_MODULE, + .name = "Broadcom Offload iSCSI Initiator", + .proc_name = "bnx2i", + .queuecommand = iscsi_queuecommand, + .eh_abort_handler = iscsi_eh_abort, + .eh_device_reset_handler = iscsi_eh_device_reset, + .eh_target_reset_handler = iscsi_eh_target_reset, + .can_queue = 1024, + .max_sectors = 127, + .cmd_per_lun = 32, + .this_id = -1, + .use_clustering = ENABLE_CLUSTERING, + .sg_tablesize = ISCSI_MAX_BDS_PER_CMD, + .shost_attrs = bnx2i_dev_attributes, +}; + +struct iscsi_transport bnx2i_iscsi_transport = { + .owner = THIS_MODULE, + .name = "bnx2i", + .caps = CAP_RECOVERY_L0 | CAP_HDRDGST | + CAP_MULTI_R2T | CAP_DATADGST | + CAP_DATA_PATH_OFFLOAD, + .param_mask = ISCSI_MAX_RECV_DLENGTH | + ISCSI_MAX_XMIT_DLENGTH | + ISCSI_HDRDGST_EN | + ISCSI_DATADGST_EN | + ISCSI_INITIAL_R2T_EN | + ISCSI_MAX_R2T | + ISCSI_IMM_DATA_EN | + ISCSI_FIRST_BURST | + ISCSI_MAX_BURST | + ISCSI_PDU_INORDER_EN | + ISCSI_DATASEQ_INORDER_EN | + ISCSI_ERL | + ISCSI_CONN_PORT | + ISCSI_CONN_ADDRESS | + ISCSI_EXP_STATSN | + ISCSI_PERSISTENT_PORT | + ISCSI_PERSISTENT_ADDRESS | + ISCSI_TARGET_NAME | ISCSI_TPGT | + ISCSI_USERNAME | ISCSI_PASSWORD | + ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN | + ISCSI_FAST_ABORT | ISCSI_ABORT_TMO | + ISCSI_LU_RESET_TMO | + ISCSI_PING_TMO | ISCSI_RECV_TMO | + ISCSI_IFACE_NAME | ISCSI_INITIATOR_NAME, + .host_param_mask = ISCSI_HOST_HWADDRESS | ISCSI_HOST_NETDEV_NAME, + .create_session = bnx2i_session_create, + .destroy_session = bnx2i_session_destroy, + .create_conn = bnx2i_conn_create, + .bind_conn = bnx2i_conn_bind, + .destroy_conn = bnx2i_conn_destroy, + .set_param = iscsi_set_param, + .get_conn_param = bnx2i_conn_get_param, + .get_session_param = iscsi_session_get_param, + .get_host_param = bnx2i_host_get_param, + .start_conn = bnx2i_conn_start, + .stop_conn = iscsi_conn_stop, + .send_pdu = iscsi_conn_send_pdu, + .xmit_task = bnx2i_task_xmit, + .get_stats = bnx2i_conn_get_stats, + /* TCP connect - disconnect - option-2 interface calls */ + .ep_connect = bnx2i_ep_connect, + .ep_poll = bnx2i_ep_poll, + .ep_disconnect = bnx2i_ep_disconnect, + .set_path = bnx2i_nl_set_path, + /* Error recovery timeout call */ + .session_recovery_timedout = iscsi_session_recovery_timedout, + .cleanup_task = bnx2i_cleanup_task, +}; diff --git a/drivers/scsi/bnx2i/bnx2i_sysfs.c b/drivers/scsi/bnx2i/bnx2i_sysfs.c new file mode 100644 index 000000000000..96426b751eb2 --- /dev/null +++ b/drivers/scsi/bnx2i/bnx2i_sysfs.c @@ -0,0 +1,142 @@ +/* bnx2i_sysfs.c: Broadcom NetXtreme II iSCSI driver. + * + * Copyright (c) 2004 - 2009 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation. + * + * Written by: Anil Veerabhadrappa (anilgv@broadcom.com) + */ + +#include "bnx2i.h" + +/** + * bnx2i_dev_to_hba - maps dev pointer to adapter struct + * @dev: device pointer + * + * Map device to hba structure + */ +static inline struct bnx2i_hba *bnx2i_dev_to_hba(struct device *dev) +{ + struct Scsi_Host *shost = class_to_shost(dev); + return iscsi_host_priv(shost); +} + + +/** + * bnx2i_show_sq_info - return(s currently configured send queue (SQ) size + * @dev: device pointer + * @buf: buffer to return current SQ size parameter + * + * Returns current SQ size parameter, this paramater determines the number + * outstanding iSCSI commands supported on a connection + */ +static ssize_t bnx2i_show_sq_info(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct bnx2i_hba *hba = bnx2i_dev_to_hba(dev); + + return sprintf(buf, "0x%x\n", hba->max_sqes); +} + + +/** + * bnx2i_set_sq_info - update send queue (SQ) size parameter + * @dev: device pointer + * @buf: buffer to return current SQ size parameter + * @count: parameter buffer size + * + * Interface for user to change shared queue size allocated for each conn + * Must be within SQ limits and a power of 2. For the latter this is needed + * because of how libiscsi preallocates tasks. + */ +static ssize_t bnx2i_set_sq_info(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct bnx2i_hba *hba = bnx2i_dev_to_hba(dev); + u32 val; + int max_sq_size; + + if (hba->ofld_conns_active) + goto skip_config; + + if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type)) + max_sq_size = BNX2I_5770X_SQ_WQES_MAX; + else + max_sq_size = BNX2I_570X_SQ_WQES_MAX; + + if (sscanf(buf, " 0x%x ", &val) > 0) { + if ((val >= BNX2I_SQ_WQES_MIN) && (val <= max_sq_size) && + (is_power_of_2(val))) + hba->max_sqes = val; + } + + return count; + +skip_config: + printk(KERN_ERR "bnx2i: device busy, cannot change SQ size\n"); + return 0; +} + + +/** + * bnx2i_show_ccell_info - returns command cell (HQ) size + * @dev: device pointer + * @buf: buffer to return current SQ size parameter + * + * returns per-connection TCP history queue size parameter + */ +static ssize_t bnx2i_show_ccell_info(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct bnx2i_hba *hba = bnx2i_dev_to_hba(dev); + + return sprintf(buf, "0x%x\n", hba->num_ccell); +} + + +/** + * bnx2i_get_link_state - set command cell (HQ) size + * @dev: device pointer + * @buf: buffer to return current SQ size parameter + * @count: parameter buffer size + * + * updates per-connection TCP history queue size parameter + */ +static ssize_t bnx2i_set_ccell_info(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + u32 val; + struct bnx2i_hba *hba = bnx2i_dev_to_hba(dev); + + if (hba->ofld_conns_active) + goto skip_config; + + if (sscanf(buf, " 0x%x ", &val) > 0) { + if ((val >= BNX2I_CCELLS_MIN) && + (val <= BNX2I_CCELLS_MAX)) { + hba->num_ccell = val; + } + } + + return count; + +skip_config: + printk(KERN_ERR "bnx2i: device busy, cannot change CCELL size\n"); + return 0; +} + + +static DEVICE_ATTR(sq_size, S_IRUGO | S_IWUSR, + bnx2i_show_sq_info, bnx2i_set_sq_info); +static DEVICE_ATTR(num_ccell, S_IRUGO | S_IWUSR, + bnx2i_show_ccell_info, bnx2i_set_ccell_info); + +struct device_attribute *bnx2i_dev_attributes[] = { + &dev_attr_sq_size, + &dev_attr_num_ccell, + NULL +}; diff --git a/drivers/scsi/cxgb3i/cxgb3i.h b/drivers/scsi/cxgb3i/cxgb3i.h index 59b0958d2d11..e3133b58e594 100644 --- a/drivers/scsi/cxgb3i/cxgb3i.h +++ b/drivers/scsi/cxgb3i/cxgb3i.h @@ -144,7 +144,6 @@ struct cxgb3i_adapter *cxgb3i_adapter_find_by_tdev(struct t3cdev *); void cxgb3i_adapter_open(struct t3cdev *); void cxgb3i_adapter_close(struct t3cdev *); -struct cxgb3i_hba *cxgb3i_hba_find_by_netdev(struct net_device *); struct cxgb3i_hba *cxgb3i_hba_host_add(struct cxgb3i_adapter *, struct net_device *); void cxgb3i_hba_host_remove(struct cxgb3i_hba *); diff --git a/drivers/scsi/cxgb3i/cxgb3i_ddp.c b/drivers/scsi/cxgb3i/cxgb3i_ddp.c index 99c912547902..344fd53b9954 100644 --- a/drivers/scsi/cxgb3i/cxgb3i_ddp.c +++ b/drivers/scsi/cxgb3i/cxgb3i_ddp.c @@ -206,6 +206,31 @@ int cxgb3i_ddp_find_page_index(unsigned long pgsz) return DDP_PGIDX_MAX; } +/** + * cxgb3i_ddp_adjust_page_table - adjust page table with PAGE_SIZE + * return the ddp page index, if no match is found return DDP_PGIDX_MAX. + */ +int cxgb3i_ddp_adjust_page_table(void) +{ + int i; + unsigned int base_order, order; + + if (PAGE_SIZE < (1UL << ddp_page_shift[0])) { + ddp_log_info("PAGE_SIZE 0x%lx too small, min. 0x%lx.\n", + PAGE_SIZE, 1UL << ddp_page_shift[0]); + return -EINVAL; + } + + base_order = get_order(1UL << ddp_page_shift[0]); + order = get_order(1 << PAGE_SHIFT); + for (i = 0; i < DDP_PGIDX_MAX; i++) { + /* first is the kernel page size, then just doubling the size */ + ddp_page_order[i] = order - base_order + i; + ddp_page_shift[i] = PAGE_SHIFT + i; + } + return 0; +} + static inline void ddp_gl_unmap(struct pci_dev *pdev, struct cxgb3i_gather_list *gl) { @@ -598,30 +623,40 @@ int cxgb3i_adapter_ddp_info(struct t3cdev *tdev, * release all the resource held by the ddp pagepod manager for a given * adapter if needed */ + +static void ddp_cleanup(struct kref *kref) +{ + struct cxgb3i_ddp_info *ddp = container_of(kref, + struct cxgb3i_ddp_info, + refcnt); + int i = 0; + + ddp_log_info("kref release ddp 0x%p, t3dev 0x%p.\n", ddp, ddp->tdev); + + ddp->tdev->ulp_iscsi = NULL; + while (i < ddp->nppods) { + struct cxgb3i_gather_list *gl = ddp->gl_map[i]; + if (gl) { + int npods = (gl->nelem + PPOD_PAGES_MAX - 1) + >> PPOD_PAGES_SHIFT; + ddp_log_info("t3dev 0x%p, ddp %d + %d.\n", + ddp->tdev, i, npods); + kfree(gl); + ddp_free_gl_skb(ddp, i, npods); + i += npods; + } else + i++; + } + cxgb3i_free_big_mem(ddp); +} + void cxgb3i_ddp_cleanup(struct t3cdev *tdev) { - int i = 0; struct cxgb3i_ddp_info *ddp = (struct cxgb3i_ddp_info *)tdev->ulp_iscsi; ddp_log_info("t3dev 0x%p, release ddp 0x%p.\n", tdev, ddp); - - if (ddp) { - tdev->ulp_iscsi = NULL; - while (i < ddp->nppods) { - struct cxgb3i_gather_list *gl = ddp->gl_map[i]; - if (gl) { - int npods = (gl->nelem + PPOD_PAGES_MAX - 1) - >> PPOD_PAGES_SHIFT; - ddp_log_info("t3dev 0x%p, ddp %d + %d.\n", - tdev, i, npods); - kfree(gl); - ddp_free_gl_skb(ddp, i, npods); - i += npods; - } else - i++; - } - cxgb3i_free_big_mem(ddp); - } + if (ddp) + kref_put(&ddp->refcnt, ddp_cleanup); } /** @@ -631,12 +666,13 @@ void cxgb3i_ddp_cleanup(struct t3cdev *tdev) */ static void ddp_init(struct t3cdev *tdev) { - struct cxgb3i_ddp_info *ddp; + struct cxgb3i_ddp_info *ddp = tdev->ulp_iscsi; struct ulp_iscsi_info uinfo; unsigned int ppmax, bits; int i, err; - if (tdev->ulp_iscsi) { + if (ddp) { + kref_get(&ddp->refcnt); ddp_log_warn("t3dev 0x%p, ddp 0x%p already set up.\n", tdev, tdev->ulp_iscsi); return; @@ -670,6 +706,7 @@ static void ddp_init(struct t3cdev *tdev) ppmax * sizeof(struct cxgb3i_gather_list *)); spin_lock_init(&ddp->map_lock); + kref_init(&ddp->refcnt); ddp->tdev = tdev; ddp->pdev = uinfo.pdev; @@ -715,6 +752,17 @@ void cxgb3i_ddp_init(struct t3cdev *tdev) { if (page_idx == DDP_PGIDX_MAX) { page_idx = cxgb3i_ddp_find_page_index(PAGE_SIZE); + + if (page_idx == DDP_PGIDX_MAX) { + ddp_log_info("system PAGE_SIZE %lu, update hw.\n", + PAGE_SIZE); + if (cxgb3i_ddp_adjust_page_table() < 0) { + ddp_log_info("PAGE_SIZE %lu, ddp disabled.\n", + PAGE_SIZE); + return; + } + page_idx = cxgb3i_ddp_find_page_index(PAGE_SIZE); + } ddp_log_info("system PAGE_SIZE %lu, ddp idx %u.\n", PAGE_SIZE, page_idx); } diff --git a/drivers/scsi/cxgb3i/cxgb3i_ddp.h b/drivers/scsi/cxgb3i/cxgb3i_ddp.h index 0d296de7cf32..87dd56b422bf 100644 --- a/drivers/scsi/cxgb3i/cxgb3i_ddp.h +++ b/drivers/scsi/cxgb3i/cxgb3i_ddp.h @@ -54,6 +54,7 @@ struct cxgb3i_gather_list { * struct cxgb3i_ddp_info - cxgb3i direct data placement for pdu payload * * @list: list head to link elements + * @refcnt: ref. count * @tdev: pointer to t3cdev used by cxgb3 driver * @max_txsz: max tx packet size for ddp * @max_rxsz: max rx packet size for ddp @@ -70,6 +71,7 @@ struct cxgb3i_gather_list { */ struct cxgb3i_ddp_info { struct list_head list; + struct kref refcnt; struct t3cdev *tdev; struct pci_dev *pdev; unsigned int max_txsz; diff --git a/drivers/scsi/cxgb3i/cxgb3i_iscsi.c b/drivers/scsi/cxgb3i/cxgb3i_iscsi.c index 9212400b9b13..74369a3f963b 100644 --- a/drivers/scsi/cxgb3i/cxgb3i_iscsi.c +++ b/drivers/scsi/cxgb3i/cxgb3i_iscsi.c @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -178,7 +179,7 @@ void cxgb3i_adapter_close(struct t3cdev *t3dev) * cxgb3i_hba_find_by_netdev - find the cxgb3i_hba structure via net_device * @t3dev: t3cdev adapter */ -struct cxgb3i_hba *cxgb3i_hba_find_by_netdev(struct net_device *ndev) +static struct cxgb3i_hba *cxgb3i_hba_find_by_netdev(struct net_device *ndev) { struct cxgb3i_adapter *snic; int i; @@ -261,20 +262,27 @@ void cxgb3i_hba_host_remove(struct cxgb3i_hba *hba) /** * cxgb3i_ep_connect - establish TCP connection to target portal + * @shost: scsi host to use * @dst_addr: target IP address * @non_blocking: blocking or non-blocking call * * Initiates a TCP/IP connection to the dst_addr */ -static struct iscsi_endpoint *cxgb3i_ep_connect(struct sockaddr *dst_addr, +static struct iscsi_endpoint *cxgb3i_ep_connect(struct Scsi_Host *shost, + struct sockaddr *dst_addr, int non_blocking) { struct iscsi_endpoint *ep; struct cxgb3i_endpoint *cep; - struct cxgb3i_hba *hba; + struct cxgb3i_hba *hba = NULL; struct s3_conn *c3cn = NULL; int err = 0; + if (shost) + hba = iscsi_host_priv(shost); + + cxgb3i_api_debug("shost 0x%p, hba 0x%p.\n", shost, hba); + c3cn = cxgb3i_c3cn_create(); if (!c3cn) { cxgb3i_log_info("ep connect OOM.\n"); @@ -282,17 +290,27 @@ static struct iscsi_endpoint *cxgb3i_ep_connect(struct sockaddr *dst_addr, goto release_conn; } - err = cxgb3i_c3cn_connect(c3cn, (struct sockaddr_in *)dst_addr); + err = cxgb3i_c3cn_connect(hba ? hba->ndev : NULL, c3cn, + (struct sockaddr_in *)dst_addr); if (err < 0) { cxgb3i_log_info("ep connect failed.\n"); goto release_conn; } + hba = cxgb3i_hba_find_by_netdev(c3cn->dst_cache->dev); if (!hba) { err = -ENOSPC; cxgb3i_log_info("NOT going through cxgbi device.\n"); goto release_conn; } + + if (shost && hba != iscsi_host_priv(shost)) { + err = -ENOSPC; + cxgb3i_log_info("Could not connect through request host%u\n", + shost->host_no); + goto release_conn; + } + if (c3cn_is_closing(c3cn)) { err = -ENOSPC; cxgb3i_log_info("ep connect unable to connect.\n"); diff --git a/drivers/scsi/cxgb3i/cxgb3i_offload.c b/drivers/scsi/cxgb3i/cxgb3i_offload.c index e11c9c180f39..c1d5be4adf9c 100644 --- a/drivers/scsi/cxgb3i/cxgb3i_offload.c +++ b/drivers/scsi/cxgb3i/cxgb3i_offload.c @@ -1479,12 +1479,13 @@ static struct net_device *cxgb3_egress_dev(struct net_device *root_dev, return NULL; } -static struct rtable *find_route(__be32 saddr, __be32 daddr, +static struct rtable *find_route(struct net_device *dev, + __be32 saddr, __be32 daddr, __be16 sport, __be16 dport) { struct rtable *rt; struct flowi fl = { - .oif = 0, + .oif = dev ? dev->ifindex : 0, .nl_u = { .ip4_u = { .daddr = daddr, @@ -1573,36 +1574,40 @@ out_err: * * return 0 if active open request is sent, < 0 otherwise. */ -int cxgb3i_c3cn_connect(struct s3_conn *c3cn, struct sockaddr_in *usin) +int cxgb3i_c3cn_connect(struct net_device *dev, struct s3_conn *c3cn, + struct sockaddr_in *usin) { struct rtable *rt; - struct net_device *dev; struct cxgb3i_sdev_data *cdata; struct t3cdev *cdev; __be32 sipv4; int err; + c3cn_conn_debug("c3cn 0x%p, dev 0x%p.\n", c3cn, dev); + if (usin->sin_family != AF_INET) return -EAFNOSUPPORT; c3cn->daddr.sin_port = usin->sin_port; c3cn->daddr.sin_addr.s_addr = usin->sin_addr.s_addr; - rt = find_route(c3cn->saddr.sin_addr.s_addr, + rt = find_route(dev, c3cn->saddr.sin_addr.s_addr, c3cn->daddr.sin_addr.s_addr, c3cn->saddr.sin_port, c3cn->daddr.sin_port); if (rt == NULL) { - c3cn_conn_debug("NO route to 0x%x, port %u.\n", + c3cn_conn_debug("NO route to 0x%x, port %u, dev %s.\n", c3cn->daddr.sin_addr.s_addr, - ntohs(c3cn->daddr.sin_port)); + ntohs(c3cn->daddr.sin_port), + dev ? dev->name : "any"); return -ENETUNREACH; } if (rt->rt_flags & (RTCF_MULTICAST | RTCF_BROADCAST)) { - c3cn_conn_debug("multi-cast route to 0x%x, port %u.\n", + c3cn_conn_debug("multi-cast route to 0x%x, port %u, dev %s.\n", c3cn->daddr.sin_addr.s_addr, - ntohs(c3cn->daddr.sin_port)); + ntohs(c3cn->daddr.sin_port), + dev ? dev->name : "any"); ip_rt_put(rt); return -ENETUNREACH; } diff --git a/drivers/scsi/cxgb3i/cxgb3i_offload.h b/drivers/scsi/cxgb3i/cxgb3i_offload.h index ebfca960c0a9..6a1d86b1fafe 100644 --- a/drivers/scsi/cxgb3i/cxgb3i_offload.h +++ b/drivers/scsi/cxgb3i/cxgb3i_offload.h @@ -169,7 +169,8 @@ void cxgb3i_sdev_add(struct t3cdev *, struct cxgb3_client *); void cxgb3i_sdev_remove(struct t3cdev *); struct s3_conn *cxgb3i_c3cn_create(void); -int cxgb3i_c3cn_connect(struct s3_conn *, struct sockaddr_in *); +int cxgb3i_c3cn_connect(struct net_device *, struct s3_conn *, + struct sockaddr_in *); void cxgb3i_c3cn_rx_credits(struct s3_conn *, int); int cxgb3i_c3cn_send_pdus(struct s3_conn *, struct sk_buff *); void cxgb3i_c3cn_release(struct s3_conn *); diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c index 43b8c51e98d0..fd0544f7da81 100644 --- a/drivers/scsi/device_handler/scsi_dh_rdac.c +++ b/drivers/scsi/device_handler/scsi_dh_rdac.c @@ -561,6 +561,12 @@ static int rdac_check_sense(struct scsi_device *sdev, struct rdac_dh_data *h = get_rdac_data(sdev); switch (sense_hdr->sense_key) { case NOT_READY: + if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x01) + /* LUN Not Ready - Logical Unit Not Ready and is in + * the process of becoming ready + * Just retry. + */ + return ADD_TO_MLQUEUE; if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x81) /* LUN Not Ready - Storage firmware incompatible * Manual code synchonisation required. diff --git a/drivers/scsi/dpt/osd_util.h b/drivers/scsi/dpt/osd_util.h index 4b56c0436ba2..b2613c2eaac7 100644 --- a/drivers/scsi/dpt/osd_util.h +++ b/drivers/scsi/dpt/osd_util.h @@ -342,7 +342,7 @@ uLONG osdGetThreadID(void); /* wakes up the specifed thread */ void osdWakeThread(uLONG); -/* osd sleep for x miliseconds */ +/* osd sleep for x milliseconds */ void osdSleep(uLONG); #define DPT_THREAD_PRIORITY_LOWEST 0x00 diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c index be5099dd94b5..c7076ce25e21 100644 --- a/drivers/scsi/eata.c +++ b/drivers/scsi/eata.c @@ -1825,7 +1825,7 @@ static int eata2x_queuecommand(struct scsi_cmnd *SCpnt, if (linked_comm && SCpnt->device->queue_depth > 2 && TLDEV(SCpnt->device->type)) { ha->cp_stat[i] = READY; - flush_dev(SCpnt->device, SCpnt->request->sector, ha, 0); + flush_dev(SCpnt->device, blk_rq_pos(SCpnt->request), ha, 0); return 0; } @@ -2144,13 +2144,13 @@ static int reorder(struct hostdata *ha, unsigned long cursec, if (!cpp->din) input_only = 0; - if (SCpnt->request->sector < minsec) - minsec = SCpnt->request->sector; - if (SCpnt->request->sector > maxsec) - maxsec = SCpnt->request->sector; + if (blk_rq_pos(SCpnt->request) < minsec) + minsec = blk_rq_pos(SCpnt->request); + if (blk_rq_pos(SCpnt->request) > maxsec) + maxsec = blk_rq_pos(SCpnt->request); - sl[n] = SCpnt->request->sector; - ioseek += SCpnt->request->nr_sectors; + sl[n] = blk_rq_pos(SCpnt->request); + ioseek += blk_rq_sectors(SCpnt->request); if (!n) continue; @@ -2190,7 +2190,7 @@ static int reorder(struct hostdata *ha, unsigned long cursec, k = il[n]; cpp = &ha->cp[k]; SCpnt = cpp->SCpnt; - ll[n] = SCpnt->request->nr_sectors; + ll[n] = blk_rq_sectors(SCpnt->request); pl[n] = SCpnt->serial_number; if (!n) @@ -2236,12 +2236,12 @@ static int reorder(struct hostdata *ha, unsigned long cursec, cpp = &ha->cp[k]; SCpnt = cpp->SCpnt; scmd_printk(KERN_INFO, SCpnt, - "%s pid %ld mb %d fc %d nr %d sec %ld ns %ld" + "%s pid %ld mb %d fc %d nr %d sec %ld ns %u" " cur %ld s:%c r:%c rev:%c in:%c ov:%c xd %d.\n", (ihdlr ? "ihdlr" : "qcomm"), SCpnt->serial_number, k, flushcount, - n_ready, SCpnt->request->sector, - SCpnt->request->nr_sectors, cursec, YESNO(s), + n_ready, blk_rq_pos(SCpnt->request), + blk_rq_sectors(SCpnt->request), cursec, YESNO(s), YESNO(r), YESNO(rev), YESNO(input_only), YESNO(overlap), cpp->din); } @@ -2408,7 +2408,7 @@ static irqreturn_t ihdlr(struct Scsi_Host *shost) if (linked_comm && SCpnt->device->queue_depth > 2 && TLDEV(SCpnt->device->type)) - flush_dev(SCpnt->device, SCpnt->request->sector, ha, 1); + flush_dev(SCpnt->device, blk_rq_pos(SCpnt->request), ha, 1); tstatus = status_byte(spp->target_status); diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index 03e1926f40b5..0a5609bb5817 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -45,8 +45,6 @@ #include "fcoe.h" -static int debug_fcoe; - MODULE_AUTHOR("Open-FCoE.org"); MODULE_DESCRIPTION("FCoE"); MODULE_LICENSE("GPL v2"); @@ -54,7 +52,6 @@ MODULE_LICENSE("GPL v2"); /* fcoe host list */ LIST_HEAD(fcoe_hostlist); DEFINE_RWLOCK(fcoe_hostlist_lock); -DEFINE_TIMER(fcoe_timer, NULL, 0, 0); DEFINE_PER_CPU(struct fcoe_percpu_s, fcoe_percpu); /* Function Prototypes */ @@ -71,7 +68,7 @@ static struct fc_lport *fcoe_hostlist_lookup(const struct net_device *); static int fcoe_hostlist_add(const struct fc_lport *); static int fcoe_hostlist_remove(const struct fc_lport *); -static int fcoe_check_wait_queue(struct fc_lport *); +static void fcoe_check_wait_queue(struct fc_lport *, struct sk_buff *); static int fcoe_device_notification(struct notifier_block *, ulong, void *); static void fcoe_dev_setup(void); static void fcoe_dev_cleanup(void); @@ -135,6 +132,58 @@ static struct scsi_host_template fcoe_shost_template = { .max_sectors = 0xffff, }; +/** + * fcoe_fip_recv - handle a received FIP frame. + * @skb: the receive skb + * @dev: associated &net_device + * @ptype: the &packet_type structure which was used to register this handler. + * @orig_dev: original receive &net_device, in case @dev is a bond. + * + * Returns: 0 for success + */ +static int fcoe_fip_recv(struct sk_buff *skb, struct net_device *dev, + struct packet_type *ptype, + struct net_device *orig_dev) +{ + struct fcoe_softc *fc; + + fc = container_of(ptype, struct fcoe_softc, fip_packet_type); + fcoe_ctlr_recv(&fc->ctlr, skb); + return 0; +} + +/** + * fcoe_fip_send() - send an Ethernet-encapsulated FIP frame. + * @fip: FCoE controller. + * @skb: FIP Packet. + */ +static void fcoe_fip_send(struct fcoe_ctlr *fip, struct sk_buff *skb) +{ + skb->dev = fcoe_from_ctlr(fip)->real_dev; + dev_queue_xmit(skb); +} + +/** + * fcoe_update_src_mac() - Update Ethernet MAC filters. + * @fip: FCoE controller. + * @old: Unicast MAC address to delete if the MAC is non-zero. + * @new: Unicast MAC address to add. + * + * Remove any previously-set unicast MAC filter. + * Add secondary FCoE MAC address filter for our OUI. + */ +static void fcoe_update_src_mac(struct fcoe_ctlr *fip, u8 *old, u8 *new) +{ + struct fcoe_softc *fc; + + fc = fcoe_from_ctlr(fip); + rtnl_lock(); + if (!is_zero_ether_addr(old)) + dev_unicast_delete(fc->real_dev, old); + dev_unicast_add(fc->real_dev, new); + rtnl_unlock(); +} + /** * fcoe_lport_config() - sets up the fc_lport * @lp: ptr to the fc_lport @@ -146,6 +195,7 @@ static int fcoe_lport_config(struct fc_lport *lp) lp->link_up = 0; lp->qfull = 0; lp->max_retry_count = 3; + lp->max_rport_retry_count = 3; lp->e_d_tov = 2 * 1000; /* FC-FS default */ lp->r_a_tov = 2 * 2 * 1000; lp->service_params = (FCP_SPPF_INIT_FCN | FCP_SPPF_RD_XRDY_DIS | @@ -166,6 +216,42 @@ static int fcoe_lport_config(struct fc_lport *lp) return 0; } +/** + * fcoe_netdev_cleanup() - clean up netdev configurations + * @fc: ptr to the fcoe_softc + */ +void fcoe_netdev_cleanup(struct fcoe_softc *fc) +{ + u8 flogi_maddr[ETH_ALEN]; + + /* Don't listen for Ethernet packets anymore */ + dev_remove_pack(&fc->fcoe_packet_type); + dev_remove_pack(&fc->fip_packet_type); + + /* Delete secondary MAC addresses */ + rtnl_lock(); + memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); + dev_unicast_delete(fc->real_dev, flogi_maddr); + if (!is_zero_ether_addr(fc->ctlr.data_src_addr)) + dev_unicast_delete(fc->real_dev, fc->ctlr.data_src_addr); + if (fc->ctlr.spma) + dev_unicast_delete(fc->real_dev, fc->ctlr.ctl_src_addr); + dev_mc_delete(fc->real_dev, FIP_ALL_ENODE_MACS, ETH_ALEN, 0); + rtnl_unlock(); +} + +/** + * fcoe_queue_timer() - fcoe queue timer + * @lp: the fc_lport pointer + * + * Calls fcoe_check_wait_queue on timeout + * + */ +static void fcoe_queue_timer(ulong lp) +{ + fcoe_check_wait_queue((struct fc_lport *)lp, NULL); +} + /** * fcoe_netdev_config() - Set up netdev for SW FCoE * @lp : ptr to the fc_lport @@ -181,6 +267,7 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev) u64 wwnn, wwpn; struct fcoe_softc *fc; u8 flogi_maddr[ETH_ALEN]; + struct netdev_hw_addr *ha; /* Setup lport private data to point to fcoe softc */ fc = lport_priv(lp); @@ -216,30 +303,44 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev) #ifdef NETIF_F_FCOE_CRC if (netdev->features & NETIF_F_FCOE_CRC) { lp->crc_offload = 1; - printk(KERN_DEBUG "fcoe:%s supports FCCRC offload\n", - netdev->name); + FCOE_NETDEV_DBG(netdev, "Supports FCCRC offload\n"); } #endif #ifdef NETIF_F_FSO if (netdev->features & NETIF_F_FSO) { lp->seq_offload = 1; lp->lso_max = netdev->gso_max_size; - printk(KERN_DEBUG "fcoe:%s supports LSO for max len 0x%x\n", - netdev->name, lp->lso_max); + FCOE_NETDEV_DBG(netdev, "Supports LSO for max len 0x%x\n", + lp->lso_max); } #endif if (netdev->fcoe_ddp_xid) { lp->lro_enabled = 1; lp->lro_xid = netdev->fcoe_ddp_xid; - printk(KERN_DEBUG "fcoe:%s supports LRO for max xid 0x%x\n", - netdev->name, lp->lro_xid); + FCOE_NETDEV_DBG(netdev, "Supports LRO for max xid 0x%x\n", + lp->lro_xid); } skb_queue_head_init(&fc->fcoe_pending_queue); fc->fcoe_pending_queue_active = 0; + setup_timer(&fc->timer, fcoe_queue_timer, (unsigned long)lp); + + /* look for SAN MAC address, if multiple SAN MACs exist, only + * use the first one for SPMA */ + rcu_read_lock(); + for_each_dev_addr(netdev, ha) { + if ((ha->type == NETDEV_HW_ADDR_T_SAN) && + (is_valid_ether_addr(fc->ctlr.ctl_src_addr))) { + memcpy(fc->ctlr.ctl_src_addr, ha->addr, ETH_ALEN); + fc->ctlr.spma = 1; + break; + } + } + rcu_read_unlock(); /* setup Source Mac Address */ - memcpy(fc->ctlr.ctl_src_addr, fc->real_dev->dev_addr, - fc->real_dev->addr_len); + if (!fc->ctlr.spma) + memcpy(fc->ctlr.ctl_src_addr, fc->real_dev->dev_addr, + fc->real_dev->addr_len); wwnn = fcoe_wwn_from_mac(fc->real_dev->dev_addr, 1, 0); fc_set_wwnn(lp, wwnn); @@ -254,7 +355,9 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev) */ rtnl_lock(); memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); - dev_unicast_add(fc->real_dev, flogi_maddr, ETH_ALEN); + dev_unicast_add(fc->real_dev, flogi_maddr); + if (fc->ctlr.spma) + dev_unicast_add(fc->real_dev, fc->ctlr.ctl_src_addr); dev_mc_add(fc->real_dev, FIP_ALL_ENODE_MACS, ETH_ALEN, 0); rtnl_unlock(); @@ -267,6 +370,11 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev) fc->fcoe_packet_type.dev = fc->real_dev; dev_add_pack(&fc->fcoe_packet_type); + fc->fip_packet_type.func = fcoe_fip_recv; + fc->fip_packet_type.type = htons(ETH_P_FIP); + fc->fip_packet_type.dev = fc->real_dev; + dev_add_pack(&fc->fip_packet_type); + return 0; } @@ -296,7 +404,8 @@ static int fcoe_shost_config(struct fc_lport *lp, struct Scsi_Host *shost, /* add the new host to the SCSI-ml */ rc = scsi_add_host(lp->host, dev); if (rc) { - FC_DBG("fcoe_shost_config:error on scsi_add_host\n"); + FCOE_NETDEV_DBG(fcoe_netdev(lp), "fcoe_shost_config: " + "error on scsi_add_host\n"); return rc; } sprintf(fc_host_symbolic_name(lp->host), "%s v%s over %s", @@ -334,12 +443,10 @@ static int fcoe_if_destroy(struct net_device *netdev) { struct fc_lport *lp = NULL; struct fcoe_softc *fc; - u8 flogi_maddr[ETH_ALEN]; BUG_ON(!netdev); - printk(KERN_DEBUG "fcoe_if_destroy:interface on %s\n", - netdev->name); + FCOE_NETDEV_DBG(netdev, "Destroying interface\n"); lp = fcoe_hostlist_lookup(netdev); if (!lp) @@ -353,9 +460,10 @@ static int fcoe_if_destroy(struct net_device *netdev) /* Remove the instance from fcoe's list */ fcoe_hostlist_remove(lp); - /* Don't listen for Ethernet packets anymore */ - dev_remove_pack(&fc->fcoe_packet_type); - dev_remove_pack(&fc->fip_packet_type); + /* clean up netdev configurations */ + fcoe_netdev_cleanup(fc); + + /* tear-down the FCoE controller */ fcoe_ctlr_destroy(&fc->ctlr); /* Cleanup the fc_lport */ @@ -370,22 +478,15 @@ static int fcoe_if_destroy(struct net_device *netdev) if (lp->emp) fc_exch_mgr_free(lp->emp); - /* Delete secondary MAC addresses */ - rtnl_lock(); - memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); - dev_unicast_delete(fc->real_dev, flogi_maddr, ETH_ALEN); - if (!is_zero_ether_addr(fc->ctlr.data_src_addr)) - dev_unicast_delete(fc->real_dev, - fc->ctlr.data_src_addr, ETH_ALEN); - dev_mc_delete(fc->real_dev, FIP_ALL_ENODE_MACS, ETH_ALEN, 0); - rtnl_unlock(); - /* Free the per-CPU receive threads */ fcoe_percpu_clean(lp); /* Free existing skbs */ fcoe_clean_pending_queue(lp); + /* Stop the timer */ + del_timer_sync(&fc->timer); + /* Free memory used by statistical counters */ fc_lport_free_stats(lp); @@ -438,58 +539,6 @@ static struct libfc_function_template fcoe_libfc_fcn_templ = { .ddp_done = fcoe_ddp_done, }; -/** - * fcoe_fip_recv - handle a received FIP frame. - * @skb: the receive skb - * @dev: associated &net_device - * @ptype: the &packet_type structure which was used to register this handler. - * @orig_dev: original receive &net_device, in case @dev is a bond. - * - * Returns: 0 for success - */ -static int fcoe_fip_recv(struct sk_buff *skb, struct net_device *dev, - struct packet_type *ptype, - struct net_device *orig_dev) -{ - struct fcoe_softc *fc; - - fc = container_of(ptype, struct fcoe_softc, fip_packet_type); - fcoe_ctlr_recv(&fc->ctlr, skb); - return 0; -} - -/** - * fcoe_fip_send() - send an Ethernet-encapsulated FIP frame. - * @fip: FCoE controller. - * @skb: FIP Packet. - */ -static void fcoe_fip_send(struct fcoe_ctlr *fip, struct sk_buff *skb) -{ - skb->dev = fcoe_from_ctlr(fip)->real_dev; - dev_queue_xmit(skb); -} - -/** - * fcoe_update_src_mac() - Update Ethernet MAC filters. - * @fip: FCoE controller. - * @old: Unicast MAC address to delete if the MAC is non-zero. - * @new: Unicast MAC address to add. - * - * Remove any previously-set unicast MAC filter. - * Add secondary FCoE MAC address filter for our OUI. - */ -static void fcoe_update_src_mac(struct fcoe_ctlr *fip, u8 *old, u8 *new) -{ - struct fcoe_softc *fc; - - fc = fcoe_from_ctlr(fip); - rtnl_lock(); - if (!is_zero_ether_addr(old)) - dev_unicast_delete(fc->real_dev, old, ETH_ALEN); - dev_unicast_add(fc->real_dev, new, ETH_ALEN); - rtnl_unlock(); -} - /** * fcoe_if_create() - this function creates the fcoe interface * @netdev: pointer the associated netdevice @@ -508,8 +557,7 @@ static int fcoe_if_create(struct net_device *netdev) BUG_ON(!netdev); - printk(KERN_DEBUG "fcoe_if_create:interface on %s\n", - netdev->name); + FCOE_NETDEV_DBG(netdev, "Create Interface\n"); lp = fcoe_hostlist_lookup(netdev); if (lp) @@ -518,7 +566,7 @@ static int fcoe_if_create(struct net_device *netdev) shost = libfc_host_alloc(&fcoe_shost_template, sizeof(struct fcoe_softc)); if (!shost) { - FC_DBG("Could not allocate host structure\n"); + FCOE_NETDEV_DBG(netdev, "Could not allocate host structure\n"); return -ENOMEM; } lp = shost_priv(shost); @@ -527,14 +575,8 @@ static int fcoe_if_create(struct net_device *netdev) /* configure fc_lport, e.g., em */ rc = fcoe_lport_config(lp); if (rc) { - FC_DBG("Could not configure lport\n"); - goto out_host_put; - } - - /* configure lport network properties */ - rc = fcoe_netdev_config(lp, netdev); - if (rc) { - FC_DBG("Could not configure netdev for lport\n"); + FCOE_NETDEV_DBG(netdev, "Could not configure lport for the " + "interface\n"); goto out_host_put; } @@ -545,29 +587,35 @@ static int fcoe_if_create(struct net_device *netdev) fc->ctlr.send = fcoe_fip_send; fc->ctlr.update_mac = fcoe_update_src_mac; - fc->fip_packet_type.func = fcoe_fip_recv; - fc->fip_packet_type.type = htons(ETH_P_FIP); - fc->fip_packet_type.dev = fc->real_dev; - dev_add_pack(&fc->fip_packet_type); + /* configure lport network properties */ + rc = fcoe_netdev_config(lp, netdev); + if (rc) { + FCOE_NETDEV_DBG(netdev, "Could not configure netdev for the " + "interface\n"); + goto out_netdev_cleanup; + } /* configure lport scsi host properties */ rc = fcoe_shost_config(lp, shost, &netdev->dev); if (rc) { - FC_DBG("Could not configure shost for lport\n"); - goto out_host_put; + FCOE_NETDEV_DBG(netdev, "Could not configure shost for the " + "interface\n"); + goto out_netdev_cleanup; } /* lport exch manager allocation */ rc = fcoe_em_config(lp); if (rc) { - FC_DBG("Could not configure em for lport\n"); - goto out_host_put; + FCOE_NETDEV_DBG(netdev, "Could not configure the EM for the " + "interface\n"); + goto out_netdev_cleanup; } /* Initialize the library */ rc = fcoe_libfc_config(lp, &fcoe_libfc_fcn_templ); if (rc) { - FC_DBG("Could not configure libfc for lport!\n"); + FCOE_NETDEV_DBG(netdev, "Could not configure libfc for the " + "interface\n"); goto out_lp_destroy; } @@ -587,6 +635,8 @@ static int fcoe_if_create(struct net_device *netdev) out_lp_destroy: fc_exch_mgr_free(lp->emp); /* Free the EM */ +out_netdev_cleanup: + fcoe_netdev_cleanup(fc); out_host_put: scsi_host_put(lp->host); return rc; @@ -604,7 +654,7 @@ static int __init fcoe_if_init(void) fc_attach_transport(&fcoe_transport_function); if (!scsi_transport_fcoe_sw) { - printk(KERN_ERR "fcoe_init:fc_attach_transport() failed\n"); + printk(KERN_ERR "fcoe: Failed to attach to the FC transport\n"); return -ENODEV; } @@ -665,7 +715,7 @@ static void fcoe_percpu_thread_destroy(unsigned int cpu) unsigned targ_cpu = smp_processor_id(); #endif /* CONFIG_SMP */ - printk(KERN_DEBUG "fcoe: Destroying receive thread for CPU %d\n", cpu); + FCOE_DBG("Destroying receive thread for CPU %d\n", cpu); /* Prevent any new skbs from being queued for this CPU. */ p = &per_cpu(fcoe_percpu, cpu); @@ -687,8 +737,8 @@ static void fcoe_percpu_thread_destroy(unsigned int cpu) p0 = &per_cpu(fcoe_percpu, targ_cpu); spin_lock_bh(&p0->fcoe_rx_list.lock); if (p0->thread) { - FC_DBG("Moving frames from CPU %d to CPU %d\n", - cpu, targ_cpu); + FCOE_DBG("Moving frames from CPU %d to CPU %d\n", + cpu, targ_cpu); while ((skb = __skb_dequeue(&p->fcoe_rx_list)) != NULL) __skb_queue_tail(&p0->fcoe_rx_list, skb); @@ -754,12 +804,12 @@ static int fcoe_cpu_callback(struct notifier_block *nfb, switch (action) { case CPU_ONLINE: case CPU_ONLINE_FROZEN: - FC_DBG("CPU %x online: Create Rx thread\n", cpu); + FCOE_DBG("CPU %x online: Create Rx thread\n", cpu); fcoe_percpu_thread_create(cpu); break; case CPU_DEAD: case CPU_DEAD_FROZEN: - FC_DBG("CPU %x offline: Remove Rx thread\n", cpu); + FCOE_DBG("CPU %x offline: Remove Rx thread\n", cpu); fcoe_percpu_thread_destroy(cpu); break; default: @@ -797,24 +847,21 @@ int fcoe_rcv(struct sk_buff *skb, struct net_device *dev, fc = container_of(ptype, struct fcoe_softc, fcoe_packet_type); lp = fc->ctlr.lp; if (unlikely(lp == NULL)) { - FC_DBG("cannot find hba structure"); + FCOE_NETDEV_DBG(dev, "Cannot find hba structure"); goto err2; } if (!lp->link_up) goto err2; - if (unlikely(debug_fcoe)) { - FC_DBG("skb_info: len:%d data_len:%d head:%p data:%p tail:%p " - "end:%p sum:%d dev:%s", skb->len, skb->data_len, - skb->head, skb->data, skb_tail_pointer(skb), - skb_end_pointer(skb), skb->csum, - skb->dev ? skb->dev->name : ""); - - } + FCOE_NETDEV_DBG(dev, "skb_info: len:%d data_len:%d head:%p " + "data:%p tail:%p end:%p sum:%d dev:%s", + skb->len, skb->data_len, skb->head, skb->data, + skb_tail_pointer(skb), skb_end_pointer(skb), + skb->csum, skb->dev ? skb->dev->name : ""); /* check for FCOE packet type */ if (unlikely(eth_hdr(skb)->h_proto != htons(ETH_P_FCOE))) { - FC_DBG("wrong FC type frame"); + FCOE_NETDEV_DBG(dev, "Wrong FC type frame"); goto err; } @@ -852,8 +899,9 @@ int fcoe_rcv(struct sk_buff *skb, struct net_device *dev, * the first CPU now. For non-SMP systems this * will check the same CPU twice. */ - FC_DBG("CPU is online, but no receive thread ready " - "for incoming skb- using first online CPU.\n"); + FCOE_NETDEV_DBG(dev, "CPU is online, but no receive thread " + "ready for incoming skb- using first online " + "CPU.\n"); spin_unlock_bh(&fps->fcoe_rx_list.lock); cpu = first_cpu(cpu_online_map); @@ -988,7 +1036,7 @@ u32 fcoe_fc_crc(struct fc_frame *fp) */ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp) { - int wlen, rc = 0; + int wlen; u32 crc; struct ethhdr *eh; struct fcoe_crc_eof *cp; @@ -1021,8 +1069,7 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp) sof = fr_sof(fp); eof = fr_eof(fp); - elen = (fc->real_dev->priv_flags & IFF_802_1Q_VLAN) ? - sizeof(struct vlan_ethhdr) : sizeof(struct ethhdr); + elen = sizeof(struct ethhdr); hlen = sizeof(struct fcoe_hdr); tlen = sizeof(struct fcoe_crc_eof); wlen = (skb->len - tlen + sizeof(crc)) / FCOE_WORD_TO_BYTE; @@ -1107,18 +1154,9 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp) /* send down to lld */ fr_dev(fp) = lp; if (fc->fcoe_pending_queue.qlen) - rc = fcoe_check_wait_queue(lp); - - if (rc == 0) - rc = fcoe_start_io(skb); - - if (rc) { - spin_lock_bh(&fc->fcoe_pending_queue.lock); - __skb_queue_tail(&fc->fcoe_pending_queue, skb); - spin_unlock_bh(&fc->fcoe_pending_queue.lock); - if (fc->fcoe_pending_queue.qlen > FCOE_MAX_QUEUE_DEPTH) - lp->qfull = 1; - } + fcoe_check_wait_queue(lp, skb); + else if (fcoe_start_io(skb)) + fcoe_check_wait_queue(lp, skb); return 0; } @@ -1162,19 +1200,17 @@ int fcoe_percpu_receive_thread(void *arg) fr = fcoe_dev_from_skb(skb); lp = fr->fr_dev; if (unlikely(lp == NULL)) { - FC_DBG("invalid HBA Structure"); + FCOE_NETDEV_DBG(skb->dev, "Invalid HBA Structure"); kfree_skb(skb); continue; } - if (unlikely(debug_fcoe)) { - FC_DBG("skb_info: len:%d data_len:%d head:%p data:%p " - "tail:%p end:%p sum:%d dev:%s", - skb->len, skb->data_len, - skb->head, skb->data, skb_tail_pointer(skb), - skb_end_pointer(skb), skb->csum, - skb->dev ? skb->dev->name : ""); - } + FCOE_NETDEV_DBG(skb->dev, "skb_info: len:%d data_len:%d " + "head:%p data:%p tail:%p end:%p sum:%d dev:%s", + skb->len, skb->data_len, + skb->head, skb->data, skb_tail_pointer(skb), + skb_end_pointer(skb), skb->csum, + skb->dev ? skb->dev->name : ""); /* * Save source MAC address before discarding header. @@ -1194,7 +1230,7 @@ int fcoe_percpu_receive_thread(void *arg) stats = fc_lport_get_stats(lp); if (unlikely(FC_FCOE_DECAPS_VER(hp) != FC_FCOE_VER)) { if (stats->ErrorFrames < 5) - printk(KERN_WARNING "FCoE version " + printk(KERN_WARNING "fcoe: FCoE version " "mismatch: The frame has " "version %x, but the " "initiator supports version " @@ -1247,7 +1283,7 @@ int fcoe_percpu_receive_thread(void *arg) if (fr_flags(fp) & FCPHF_CRC_UNCHECKED) { if (le32_to_cpu(fr_crc(fp)) != ~crc32(~0, skb->data, fr_len)) { - if (debug_fcoe || stats->InvalidCRCCount < 5) + if (stats->InvalidCRCCount < 5) printk(KERN_WARNING "fcoe: dropping " "frame with CRC error\n"); stats->InvalidCRCCount++; @@ -1267,32 +1303,6 @@ int fcoe_percpu_receive_thread(void *arg) return 0; } -/** - * fcoe_watchdog() - fcoe timer callback - * @vp: - * - * This checks the pending queue length for fcoe and set lport qfull - * if the FCOE_MAX_QUEUE_DEPTH is reached. This is done for all fc_lport on the - * fcoe_hostlist. - * - * Returns: 0 for success - */ -void fcoe_watchdog(ulong vp) -{ - struct fcoe_softc *fc; - - read_lock(&fcoe_hostlist_lock); - list_for_each_entry(fc, &fcoe_hostlist, list) { - if (fc->ctlr.lp) - fcoe_check_wait_queue(fc->ctlr.lp); - } - read_unlock(&fcoe_hostlist_lock); - - fcoe_timer.expires = jiffies + (1 * HZ); - add_timer(&fcoe_timer); -} - - /** * fcoe_check_wait_queue() - attempt to clear the transmit backlog * @lp: the fc_lport @@ -1305,16 +1315,17 @@ void fcoe_watchdog(ulong vp) * The wait_queue is used when the skb transmit fails. skb will go * in the wait_queue which will be emptied by the timer function or * by the next skb transmit. - * - * Returns: 0 for success */ -static int fcoe_check_wait_queue(struct fc_lport *lp) +static void fcoe_check_wait_queue(struct fc_lport *lp, struct sk_buff *skb) { struct fcoe_softc *fc = lport_priv(lp); - struct sk_buff *skb; - int rc = -1; + int rc; spin_lock_bh(&fc->fcoe_pending_queue.lock); + + if (skb) + __skb_queue_tail(&fc->fcoe_pending_queue, skb); + if (fc->fcoe_pending_queue_active) goto out; fc->fcoe_pending_queue_active = 1; @@ -1340,23 +1351,26 @@ static int fcoe_check_wait_queue(struct fc_lport *lp) if (fc->fcoe_pending_queue.qlen < FCOE_LOW_QUEUE_DEPTH) lp->qfull = 0; + if (fc->fcoe_pending_queue.qlen && !timer_pending(&fc->timer)) + mod_timer(&fc->timer, jiffies + 2); fc->fcoe_pending_queue_active = 0; - rc = fc->fcoe_pending_queue.qlen; out: + if (fc->fcoe_pending_queue.qlen > FCOE_MAX_QUEUE_DEPTH) + lp->qfull = 1; spin_unlock_bh(&fc->fcoe_pending_queue.lock); - return rc; + return; } /** * fcoe_dev_setup() - setup link change notification interface */ -static void fcoe_dev_setup() +static void fcoe_dev_setup(void) { register_netdevice_notifier(&fcoe_notifier); } /** - * fcoe_dev_setup() - cleanup link change notification interface + * fcoe_dev_cleanup() - cleanup link change notification interface */ static void fcoe_dev_cleanup(void) { @@ -1415,7 +1429,8 @@ static int fcoe_device_notification(struct notifier_block *notifier, case NETDEV_REGISTER: break; default: - FC_DBG("Unknown event %ld from netdev netlink\n", event); + FCOE_NETDEV_DBG(real_dev, "Unknown event %ld " + "from netdev netlink\n", event); } if (link_possible && !fcoe_link_ok(lp)) fcoe_ctlr_link_up(&fc->ctlr); @@ -1488,8 +1503,8 @@ static int fcoe_ethdrv_get(const struct net_device *netdev) owner = fcoe_netdev_to_module_owner(netdev); if (owner) { - printk(KERN_DEBUG "fcoe:hold driver module %s for %s\n", - module_name(owner), netdev->name); + FCOE_NETDEV_DBG(netdev, "Hold driver module %s\n", + module_name(owner)); return try_module_get(owner); } return -ENODEV; @@ -1510,8 +1525,8 @@ static int fcoe_ethdrv_put(const struct net_device *netdev) owner = fcoe_netdev_to_module_owner(netdev); if (owner) { - printk(KERN_DEBUG "fcoe:release driver module %s for %s\n", - module_name(owner), netdev->name); + FCOE_NETDEV_DBG(netdev, "Release driver module %s\n", + module_name(owner)); module_put(owner); return 0; } @@ -1542,7 +1557,7 @@ static int fcoe_destroy(const char *buffer, struct kernel_param *kp) } rc = fcoe_if_destroy(netdev); if (rc) { - printk(KERN_ERR "fcoe: fcoe_if_destroy(%s) failed\n", + printk(KERN_ERR "fcoe: Failed to destroy interface (%s)\n", netdev->name); rc = -EIO; goto out_putdev; @@ -1581,7 +1596,7 @@ static int fcoe_create(const char *buffer, struct kernel_param *kp) rc = fcoe_if_create(netdev); if (rc) { - printk(KERN_ERR "fcoe: fcoe_if_create(%s) failed\n", + printk(KERN_ERR "fcoe: Failed to create interface (%s)\n", netdev->name); fcoe_ethdrv_put(netdev); rc = -EIO; @@ -1815,10 +1830,6 @@ static int __init fcoe_init(void) /* Setup link change notification */ fcoe_dev_setup(); - setup_timer(&fcoe_timer, fcoe_watchdog, 0); - - mod_timer(&fcoe_timer, jiffies + (10 * HZ)); - fcoe_if_init(); return 0; @@ -1844,9 +1855,6 @@ static void __exit fcoe_exit(void) fcoe_dev_cleanup(); - /* Stop the timer */ - del_timer_sync(&fcoe_timer); - /* releases the associated fcoe hosts */ list_for_each_entry_safe(fc, tmp, &fcoe_hostlist, list) fcoe_if_destroy(fc->real_dev); diff --git a/drivers/scsi/fcoe/fcoe.h b/drivers/scsi/fcoe/fcoe.h index 917aae886897..0d724fa0898f 100644 --- a/drivers/scsi/fcoe/fcoe.h +++ b/drivers/scsi/fcoe/fcoe.h @@ -40,6 +40,30 @@ #define FCOE_MIN_XID 0x0001 /* the min xid supported by fcoe_sw */ #define FCOE_MAX_XID 0x07ef /* the max xid supported by fcoe_sw */ +unsigned int fcoe_debug_logging; +module_param_named(debug_logging, fcoe_debug_logging, int, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(debug_logging, "a bit mask of logging levels"); + +#define FCOE_LOGGING 0x01 /* General logging, not categorized */ +#define FCOE_NETDEV_LOGGING 0x02 /* Netdevice logging */ + +#define FCOE_CHECK_LOGGING(LEVEL, CMD) \ +do { \ + if (unlikely(fcoe_debug_logging & LEVEL)) \ + do { \ + CMD; \ + } while (0); \ +} while (0); + +#define FCOE_DBG(fmt, args...) \ + FCOE_CHECK_LOGGING(FCOE_LOGGING, \ + printk(KERN_INFO "fcoe: " fmt, ##args);) + +#define FCOE_NETDEV_DBG(netdev, fmt, args...) \ + FCOE_CHECK_LOGGING(FCOE_NETDEV_LOGGING, \ + printk(KERN_INFO "fcoe: %s" fmt, \ + netdev->name, ##args);) + /* * this percpu struct for fcoe */ @@ -61,6 +85,7 @@ struct fcoe_softc { struct packet_type fip_packet_type; struct sk_buff_head fcoe_pending_queue; u8 fcoe_pending_queue_active; + struct timer_list timer; /* queue timer */ struct fcoe_ctlr ctlr; }; diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c index 62ba0f39c6bd..f544340d318b 100644 --- a/drivers/scsi/fcoe/libfcoe.c +++ b/drivers/scsi/fcoe/libfcoe.c @@ -56,15 +56,28 @@ static void fcoe_ctlr_recv_work(struct work_struct *); static u8 fcoe_all_fcfs[ETH_ALEN] = FIP_ALL_FCF_MACS; -static u32 fcoe_ctlr_debug; /* 1 for basic, 2 for noisy debug */ +unsigned int libfcoe_debug_logging; +module_param_named(debug_logging, libfcoe_debug_logging, int, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(debug_logging, "a bit mask of logging levels"); -#define FIP_DBG_LVL(level, fmt, args...) \ +#define LIBFCOE_LOGGING 0x01 /* General logging, not categorized */ +#define LIBFCOE_FIP_LOGGING 0x02 /* FIP logging */ + +#define LIBFCOE_CHECK_LOGGING(LEVEL, CMD) \ +do { \ + if (unlikely(libfcoe_debug_logging & LEVEL)) \ do { \ - if (fcoe_ctlr_debug >= (level)) \ - FC_DBG(fmt, ##args); \ - } while (0) + CMD; \ + } while (0); \ +} while (0); -#define FIP_DBG(fmt, args...) FIP_DBG_LVL(1, fmt, ##args) +#define LIBFCOE_DBG(fmt, args...) \ + LIBFCOE_CHECK_LOGGING(LIBFCOE_LOGGING, \ + printk(KERN_INFO "libfcoe: " fmt, ##args);) + +#define LIBFCOE_FIP_DBG(fmt, args...) \ + LIBFCOE_CHECK_LOGGING(LIBFCOE_FIP_LOGGING, \ + printk(KERN_INFO "fip: " fmt, ##args);) /* * Return non-zero if FCF fcoe_size has been validated. @@ -198,6 +211,8 @@ static void fcoe_ctlr_solicit(struct fcoe_ctlr *fip, struct fcoe_fcf *fcf) sol->fip.fip_subcode = FIP_SC_SOL; sol->fip.fip_dl_len = htons(sizeof(sol->desc) / FIP_BPW); sol->fip.fip_flags = htons(FIP_FL_FPMA); + if (fip->spma) + sol->fip.fip_flags |= htons(FIP_FL_SPMA); sol->desc.mac.fd_desc.fip_dtype = FIP_DT_MAC; sol->desc.mac.fd_desc.fip_dlen = sizeof(sol->desc.mac) / FIP_BPW; @@ -213,7 +228,7 @@ static void fcoe_ctlr_solicit(struct fcoe_ctlr *fip, struct fcoe_fcf *fcf) sol->desc.size.fd_size = htons(fcoe_size); skb_put(skb, sizeof(*sol)); - skb->protocol = htons(ETH_P_802_3); + skb->protocol = htons(ETH_P_FIP); skb_reset_mac_header(skb); skb_reset_network_header(skb); fip->send(fip, skb); @@ -241,7 +256,7 @@ void fcoe_ctlr_link_up(struct fcoe_ctlr *fip) fip->last_link = 1; fip->link = 1; spin_unlock_bh(&fip->lock); - FIP_DBG("%s", "setting AUTO mode.\n"); + LIBFCOE_FIP_DBG("%s", "setting AUTO mode.\n"); fc_linkup(fip->lp); fcoe_ctlr_solicit(fip, NULL); } else @@ -350,6 +365,8 @@ static void fcoe_ctlr_send_keep_alive(struct fcoe_ctlr *fip, int ports, u8 *sa) kal->fip.fip_dl_len = htons((sizeof(kal->mac) + ports * sizeof(*vn)) / FIP_BPW); kal->fip.fip_flags = htons(FIP_FL_FPMA); + if (fip->spma) + kal->fip.fip_flags |= htons(FIP_FL_SPMA); kal->mac.fd_desc.fip_dtype = FIP_DT_MAC; kal->mac.fd_desc.fip_dlen = sizeof(kal->mac) / FIP_BPW; @@ -365,7 +382,7 @@ static void fcoe_ctlr_send_keep_alive(struct fcoe_ctlr *fip, int ports, u8 *sa) } skb_put(skb, len); - skb->protocol = htons(ETH_P_802_3); + skb->protocol = htons(ETH_P_FIP); skb_reset_mac_header(skb); skb_reset_network_header(skb); fip->send(fip, skb); @@ -413,6 +430,8 @@ static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip, cap->fip.fip_subcode = FIP_SC_REQ; cap->fip.fip_dl_len = htons((dlen + sizeof(*mac)) / FIP_BPW); cap->fip.fip_flags = htons(FIP_FL_FPMA); + if (fip->spma) + cap->fip.fip_flags |= htons(FIP_FL_SPMA); cap->encaps.fd_desc.fip_dtype = dtype; cap->encaps.fd_desc.fip_dlen = dlen / FIP_BPW; @@ -421,10 +440,12 @@ static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip, memset(mac, 0, sizeof(mac)); mac->fd_desc.fip_dtype = FIP_DT_MAC; mac->fd_desc.fip_dlen = sizeof(*mac) / FIP_BPW; - if (dtype != ELS_FLOGI) + if (dtype != FIP_DT_FLOGI) memcpy(mac->fd_mac, fip->data_src_addr, ETH_ALEN); + else if (fip->spma) + memcpy(mac->fd_mac, fip->ctl_src_addr, ETH_ALEN); - skb->protocol = htons(ETH_P_802_3); + skb->protocol = htons(ETH_P_FIP); skb_reset_mac_header(skb); skb_reset_network_header(skb); return 0; @@ -447,14 +468,10 @@ int fcoe_ctlr_els_send(struct fcoe_ctlr *fip, struct sk_buff *skb) u16 old_xid; u8 op; - if (fip->state == FIP_ST_NON_FIP) - return 0; - fh = (struct fc_frame_header *)skb->data; op = *(u8 *)(fh + 1); - switch (op) { - case ELS_FLOGI: + if (op == ELS_FLOGI) { old_xid = fip->flogi_oxid; fip->flogi_oxid = ntohs(fh->fh_ox_id); if (fip->state == FIP_ST_AUTO) { @@ -466,6 +483,15 @@ int fcoe_ctlr_els_send(struct fcoe_ctlr *fip, struct sk_buff *skb) fip->map_dest = 1; return 0; } + if (fip->state == FIP_ST_NON_FIP) + fip->map_dest = 1; + } + + if (fip->state == FIP_ST_NON_FIP) + return 0; + + switch (op) { + case ELS_FLOGI: op = FIP_DT_FLOGI; break; case ELS_FDISC: @@ -601,7 +627,8 @@ static int fcoe_ctlr_parse_adv(struct sk_buff *skb, struct fcoe_fcf *fcf) ((struct fip_mac_desc *)desc)->fd_mac, ETH_ALEN); if (!is_valid_ether_addr(fcf->fcf_mac)) { - FIP_DBG("invalid MAC addr in FIP adv\n"); + LIBFCOE_FIP_DBG("Invalid MAC address " + "in FIP adv\n"); return -EINVAL; } break; @@ -634,8 +661,8 @@ static int fcoe_ctlr_parse_adv(struct sk_buff *skb, struct fcoe_fcf *fcf) case FIP_DT_LOGO: case FIP_DT_ELP: default: - FIP_DBG("unexpected descriptor type %x in FIP adv\n", - desc->fip_dtype); + LIBFCOE_FIP_DBG("unexpected descriptor type %x " + "in FIP adv\n", desc->fip_dtype); /* standard says ignore unknown descriptors >= 128 */ if (desc->fip_dtype < FIP_DT_VENDOR_BASE) return -EINVAL; @@ -651,8 +678,8 @@ static int fcoe_ctlr_parse_adv(struct sk_buff *skb, struct fcoe_fcf *fcf) return 0; len_err: - FIP_DBG("FIP length error in descriptor type %x len %zu\n", - desc->fip_dtype, dlen); + LIBFCOE_FIP_DBG("FIP length error in descriptor type %x len %zu\n", + desc->fip_dtype, dlen); return -EINVAL; } @@ -715,9 +742,10 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb) } mtu_valid = fcoe_ctlr_mtu_valid(fcf); fcf->time = jiffies; - FIP_DBG_LVL(found ? 2 : 1, "%s FCF for fab %llx map %x val %d\n", - found ? "old" : "new", - fcf->fabric_name, fcf->fc_map, mtu_valid); + if (!found) { + LIBFCOE_FIP_DBG("New FCF for fab %llx map %x val %d\n", + fcf->fabric_name, fcf->fc_map, mtu_valid); + } /* * If this advertisement is not solicited and our max receive size @@ -794,7 +822,8 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb) ((struct fip_mac_desc *)desc)->fd_mac, ETH_ALEN); if (!is_valid_ether_addr(granted_mac)) { - FIP_DBG("invalid MAC addrs in FIP ELS\n"); + LIBFCOE_FIP_DBG("Invalid MAC address " + "in FIP ELS\n"); goto drop; } break; @@ -812,8 +841,8 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb) els_dtype = desc->fip_dtype; break; default: - FIP_DBG("unexpected descriptor type %x " - "in FIP adv\n", desc->fip_dtype); + LIBFCOE_FIP_DBG("unexpected descriptor type %x " + "in FIP adv\n", desc->fip_dtype); /* standard says ignore unknown descriptors >= 128 */ if (desc->fip_dtype < FIP_DT_VENDOR_BASE) goto drop; @@ -854,8 +883,8 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb) return; len_err: - FIP_DBG("FIP length error in descriptor type %x len %zu\n", - desc->fip_dtype, dlen); + LIBFCOE_FIP_DBG("FIP length error in descriptor type %x len %zu\n", + desc->fip_dtype, dlen); drop: kfree_skb(skb); } @@ -881,7 +910,7 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip, struct fc_lport *lp = fip->lp; u32 desc_mask; - FIP_DBG("Clear Virtual Link received\n"); + LIBFCOE_FIP_DBG("Clear Virtual Link received\n"); if (!fcf) return; if (!fcf || !fc_host_port_id(lp->host)) @@ -939,9 +968,9 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip, * reset only if all required descriptors were present and valid. */ if (desc_mask) { - FIP_DBG("missing descriptors mask %x\n", desc_mask); + LIBFCOE_FIP_DBG("missing descriptors mask %x\n", desc_mask); } else { - FIP_DBG("performing Clear Virtual Link\n"); + LIBFCOE_FIP_DBG("performing Clear Virtual Link\n"); fcoe_ctlr_reset(fip, FIP_ST_ENABLED); } } @@ -989,10 +1018,6 @@ static int fcoe_ctlr_recv_handler(struct fcoe_ctlr *fip, struct sk_buff *skb) op = ntohs(fiph->fip_op); sub = fiph->fip_subcode; - FIP_DBG_LVL(2, "ver %x op %x/%x dl %x fl %x\n", - FIP_VER_DECAPS(fiph->fip_ver), op, sub, - ntohs(fiph->fip_dl_len), ntohs(fiph->fip_flags)); - if (FIP_VER_DECAPS(fiph->fip_ver) != FIP_VER) goto drop; if (ntohs(fiph->fip_dl_len) * FIP_BPW + sizeof(*fiph) > skb->len) @@ -1004,7 +1029,7 @@ static int fcoe_ctlr_recv_handler(struct fcoe_ctlr *fip, struct sk_buff *skb) fip->map_dest = 0; fip->state = FIP_ST_ENABLED; state = FIP_ST_ENABLED; - FIP_DBG("using FIP mode\n"); + LIBFCOE_FIP_DBG("Using FIP mode\n"); } spin_unlock_bh(&fip->lock); if (state != FIP_ST_ENABLED) @@ -1039,14 +1064,15 @@ static void fcoe_ctlr_select(struct fcoe_ctlr *fip) struct fcoe_fcf *best = NULL; list_for_each_entry(fcf, &fip->fcfs, list) { - FIP_DBG("consider FCF for fab %llx VFID %d map %x val %d\n", - fcf->fabric_name, fcf->vfid, - fcf->fc_map, fcoe_ctlr_mtu_valid(fcf)); + LIBFCOE_FIP_DBG("consider FCF for fab %llx VFID %d map %x " + "val %d\n", fcf->fabric_name, fcf->vfid, + fcf->fc_map, fcoe_ctlr_mtu_valid(fcf)); if (!fcoe_ctlr_fcf_usable(fcf)) { - FIP_DBG("FCF for fab %llx map %x %svalid %savailable\n", - fcf->fabric_name, fcf->fc_map, - (fcf->flags & FIP_FL_SOL) ? "" : "in", - (fcf->flags & FIP_FL_AVAIL) ? "" : "un"); + LIBFCOE_FIP_DBG("FCF for fab %llx map %x %svalid " + "%savailable\n", fcf->fabric_name, + fcf->fc_map, (fcf->flags & FIP_FL_SOL) + ? "" : "in", (fcf->flags & FIP_FL_AVAIL) + ? "" : "un"); continue; } if (!best) { @@ -1056,7 +1082,8 @@ static void fcoe_ctlr_select(struct fcoe_ctlr *fip) if (fcf->fabric_name != best->fabric_name || fcf->vfid != best->vfid || fcf->fc_map != best->fc_map) { - FIP_DBG("conflicting fabric, VFID, or FC-MAP\n"); + LIBFCOE_FIP_DBG("Conflicting fabric, VFID, " + "or FC-MAP\n"); return; } if (fcf->pri < best->pri) @@ -1100,7 +1127,7 @@ static void fcoe_ctlr_timeout(unsigned long arg) if (sel != fcf) { fcf = sel; /* the old FCF may have been freed */ if (sel) { - printk(KERN_INFO "host%d: FIP selected " + printk(KERN_INFO "libfcoe: host%d: FIP selected " "Fibre-Channel Forwarder MAC %s\n", fip->lp->host->host_no, print_mac(buf, sel->fcf_mac)); @@ -1110,7 +1137,7 @@ static void fcoe_ctlr_timeout(unsigned long arg) fip->ctlr_ka_time = jiffies + sel->fka_period; fip->link = 1; } else { - printk(KERN_NOTICE "host%d: " + printk(KERN_NOTICE "libfcoe: host%d: " "FIP Fibre-Channel Forwarder timed out. " "Starting FCF discovery.\n", fip->lp->host->host_no); @@ -1234,7 +1261,7 @@ int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *fip, struct fc_frame *fp, u8 *sa) return -EINVAL; } fip->state = FIP_ST_NON_FIP; - FIP_DBG("received FLOGI LS_ACC using non-FIP mode\n"); + LIBFCOE_FIP_DBG("received FLOGI LS_ACC using non-FIP mode\n"); /* * FLOGI accepted. @@ -1263,7 +1290,7 @@ int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *fip, struct fc_frame *fp, u8 *sa) memcpy(fip->dest_addr, sa, ETH_ALEN); fip->map_dest = 0; if (fip->state == FIP_ST_NON_FIP) - FIP_DBG("received FLOGI REQ, " + LIBFCOE_FIP_DBG("received FLOGI REQ, " "using non-FIP mode\n"); fip->state = FIP_ST_NON_FIP; } diff --git a/drivers/scsi/fnic/fnic_main.c b/drivers/scsi/fnic/fnic_main.c index 32ef6b87d895..a84072865fc2 100644 --- a/drivers/scsi/fnic/fnic_main.c +++ b/drivers/scsi/fnic/fnic_main.c @@ -680,6 +680,7 @@ static int __devinit fnic_probe(struct pci_dev *pdev, } lp->max_retry_count = fnic->config.flogi_retries; + lp->max_rport_retry_count = fnic->config.plogi_retries; lp->service_params = (FCP_SPPF_INIT_FCN | FCP_SPPF_RD_XRDY_DIS | FCP_SPPF_CONF_COMPL); if (fnic->config.flags & VFCF_FCP_SEQ_LVL_ERR) diff --git a/drivers/scsi/gdth_proc.c b/drivers/scsi/gdth_proc.c index 59349a316e13..1258da34fbc2 100644 --- a/drivers/scsi/gdth_proc.c +++ b/drivers/scsi/gdth_proc.c @@ -152,6 +152,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length, struct Scsi_Host *host, gdth_ha_str *ha) { int size = 0,len = 0; + int hlen; off_t begin = 0,pos = 0; int id, i, j, k, sec, flag; int no_mdrv = 0, drv_no, is_mirr; @@ -192,11 +193,11 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length, if (reserve_list[0] == 0xff) strcpy(hrec, "--"); else { - sprintf(hrec, "%d", reserve_list[0]); + hlen = sprintf(hrec, "%d", reserve_list[0]); for (i = 1; i < MAX_RES_ARGS; i++) { if (reserve_list[i] == 0xff) break; - sprintf(hrec,"%s,%d", hrec, reserve_list[i]); + hlen += snprintf(hrec + hlen , 161 - hlen, ",%d", reserve_list[i]); } } size = sprintf(buffer+len, diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 89d41a424b33..5fd2da494d08 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -40,7 +40,7 @@ #include "scsi_logging.h" -static int scsi_host_next_hn; /* host_no for next new host */ +static atomic_t scsi_host_next_hn; /* host_no for next new host */ static void scsi_host_cls_release(struct device *dev) @@ -333,7 +333,11 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) mutex_init(&shost->scan_mutex); - shost->host_no = scsi_host_next_hn++; /* XXX(hch): still racy */ + /* + * subtract one because we increment first then return, but we need to + * know what the next host number was before increment + */ + shost->host_no = atomic_inc_return(&scsi_host_next_hn) - 1; shost->dma_channel = 0xff; /* These three are default values which can be overridden */ diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index ea4abee7a2a9..166d96450a0e 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c @@ -110,7 +110,7 @@ static const struct { { IBMVFC_FABRIC_MAPPED, IBMVFC_XPORT_DEAD, DID_ERROR, 0, 1, "transport dead" }, { IBMVFC_FABRIC_MAPPED, IBMVFC_CONFIG_ERROR, DID_ERROR, 1, 1, "configuration error" }, { IBMVFC_FABRIC_MAPPED, IBMVFC_NAME_SERVER_FAIL, DID_ERROR, 1, 1, "name server failure" }, - { IBMVFC_FABRIC_MAPPED, IBMVFC_LINK_HALTED, DID_REQUEUE, 0, 0, "link halted" }, + { IBMVFC_FABRIC_MAPPED, IBMVFC_LINK_HALTED, DID_REQUEUE, 1, 0, "link halted" }, { IBMVFC_FABRIC_MAPPED, IBMVFC_XPORT_GENERAL, DID_OK, 1, 0, "general transport error" }, { IBMVFC_VIOS_FAILURE, IBMVFC_CRQ_FAILURE, DID_REQUEUE, 1, 1, "CRQ failure" }, @@ -143,6 +143,7 @@ static void ibmvfc_npiv_login(struct ibmvfc_host *); static void ibmvfc_tgt_send_prli(struct ibmvfc_target *); static void ibmvfc_tgt_send_plogi(struct ibmvfc_target *); static void ibmvfc_tgt_query_target(struct ibmvfc_target *); +static void ibmvfc_npiv_logout(struct ibmvfc_host *); static const char *unknown_error = "unknown error"; @@ -275,7 +276,7 @@ static int ibmvfc_get_err_result(struct ibmvfc_cmd *vfc_cmd) int fc_rsp_len = rsp->fcp_rsp_len; if ((rsp->flags & FCP_RSP_LEN_VALID) && - ((!fc_rsp_len && fc_rsp_len != 4 && fc_rsp_len != 8) || + ((fc_rsp_len && fc_rsp_len != 4 && fc_rsp_len != 8) || rsp->data.info.rsp_code)) return DID_ERROR << 16; @@ -431,6 +432,8 @@ static void ibmvfc_set_tgt_action(struct ibmvfc_target *tgt, case IBMVFC_TGT_ACTION_DEL_RPORT: break; default: + if (action == IBMVFC_TGT_ACTION_DEL_RPORT) + tgt->add_rport = 0; tgt->action = action; break; } @@ -475,6 +478,10 @@ static void ibmvfc_set_host_action(struct ibmvfc_host *vhost, if (vhost->action == IBMVFC_HOST_ACTION_INIT_WAIT) vhost->action = action; break; + case IBMVFC_HOST_ACTION_LOGO_WAIT: + if (vhost->action == IBMVFC_HOST_ACTION_LOGO) + vhost->action = action; + break; case IBMVFC_HOST_ACTION_INIT_WAIT: if (vhost->action == IBMVFC_HOST_ACTION_INIT) vhost->action = action; @@ -483,7 +490,7 @@ static void ibmvfc_set_host_action(struct ibmvfc_host *vhost, switch (vhost->action) { case IBMVFC_HOST_ACTION_INIT_WAIT: case IBMVFC_HOST_ACTION_NONE: - case IBMVFC_HOST_ACTION_TGT_ADD: + case IBMVFC_HOST_ACTION_TGT_DEL_FAILED: vhost->action = action; break; default: @@ -494,11 +501,11 @@ static void ibmvfc_set_host_action(struct ibmvfc_host *vhost, if (vhost->action == IBMVFC_HOST_ACTION_ALLOC_TGTS) vhost->action = action; break; + case IBMVFC_HOST_ACTION_LOGO: case IBMVFC_HOST_ACTION_INIT: case IBMVFC_HOST_ACTION_TGT_DEL: case IBMVFC_HOST_ACTION_QUERY_TGTS: case IBMVFC_HOST_ACTION_TGT_DEL_FAILED: - case IBMVFC_HOST_ACTION_TGT_ADD: case IBMVFC_HOST_ACTION_NONE: default: vhost->action = action; @@ -576,7 +583,7 @@ static void ibmvfc_init_host(struct ibmvfc_host *vhost, int relogin) } list_for_each_entry(tgt, &vhost->targets, queue) - tgt->need_login = 1; + ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); scsi_block_requests(vhost->host); ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT); vhost->job_step = ibmvfc_npiv_login; @@ -646,6 +653,7 @@ static void ibmvfc_release_crq_queue(struct ibmvfc_host *vhost) } while (rc == H_BUSY || H_IS_LONG_BUSY(rc)); vhost->state = IBMVFC_NO_CRQ; + vhost->logged_in = 0; dma_unmap_single(vhost->dev, crq->msg_token, PAGE_SIZE, DMA_BIDIRECTIONAL); free_page((unsigned long)crq->msgs); } @@ -692,6 +700,7 @@ static int ibmvfc_reset_crq(struct ibmvfc_host *vhost) } while (rc == H_BUSY || H_IS_LONG_BUSY(rc)); vhost->state = IBMVFC_NO_CRQ; + vhost->logged_in = 0; ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE); /* Clean out the queue */ @@ -807,10 +816,10 @@ static void ibmvfc_purge_requests(struct ibmvfc_host *vhost, int error_code) } /** - * __ibmvfc_reset_host - Reset the connection to the server (no locking) + * ibmvfc_hard_reset_host - Reset the connection to the server by breaking the CRQ * @vhost: struct ibmvfc host to reset **/ -static void __ibmvfc_reset_host(struct ibmvfc_host *vhost) +static void ibmvfc_hard_reset_host(struct ibmvfc_host *vhost) { int rc; @@ -826,9 +835,25 @@ static void __ibmvfc_reset_host(struct ibmvfc_host *vhost) } /** - * ibmvfc_reset_host - Reset the connection to the server + * __ibmvfc_reset_host - Reset the connection to the server (no locking) * @vhost: struct ibmvfc host to reset **/ +static void __ibmvfc_reset_host(struct ibmvfc_host *vhost) +{ + if (vhost->logged_in && vhost->action != IBMVFC_HOST_ACTION_LOGO_WAIT && + !ibmvfc_set_host_state(vhost, IBMVFC_INITIALIZING)) { + scsi_block_requests(vhost->host); + ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_LOGO); + vhost->job_step = ibmvfc_npiv_logout; + wake_up(&vhost->work_wait_q); + } else + ibmvfc_hard_reset_host(vhost); +} + +/** + * ibmvfc_reset_host - Reset the connection to the server + * @vhost: ibmvfc host struct + **/ static void ibmvfc_reset_host(struct ibmvfc_host *vhost) { unsigned long flags; @@ -842,9 +867,13 @@ static void ibmvfc_reset_host(struct ibmvfc_host *vhost) * ibmvfc_retry_host_init - Retry host initialization if allowed * @vhost: ibmvfc host struct * + * Returns: 1 if init will be retried / 0 if not + * **/ -static void ibmvfc_retry_host_init(struct ibmvfc_host *vhost) +static int ibmvfc_retry_host_init(struct ibmvfc_host *vhost) { + int retry = 0; + if (vhost->action == IBMVFC_HOST_ACTION_INIT_WAIT) { vhost->delay_init = 1; if (++vhost->init_retries > IBMVFC_MAX_HOST_INIT_RETRIES) { @@ -853,11 +882,14 @@ static void ibmvfc_retry_host_init(struct ibmvfc_host *vhost) ibmvfc_link_down(vhost, IBMVFC_HOST_OFFLINE); } else if (vhost->init_retries == IBMVFC_MAX_HOST_INIT_RETRIES) __ibmvfc_reset_host(vhost); - else + else { ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT); + retry = 1; + } } wake_up(&vhost->work_wait_q); + return retry; } /** @@ -1137,8 +1169,9 @@ static void ibmvfc_set_login_info(struct ibmvfc_host *vhost) login_info->partition_num = vhost->partition_number; login_info->vfc_frame_version = 1; login_info->fcp_version = 3; + login_info->flags = IBMVFC_FLUSH_ON_HALT; if (vhost->client_migrated) - login_info->flags = IBMVFC_CLIENT_MIGRATED; + login_info->flags |= IBMVFC_CLIENT_MIGRATED; login_info->max_cmds = max_requests + IBMVFC_NUM_INTERNAL_REQ; login_info->capabilities = IBMVFC_CAN_MIGRATE; @@ -1451,6 +1484,27 @@ static void ibmvfc_log_error(struct ibmvfc_event *evt) rsp->flags, rsp_code, scsi_get_resid(cmnd), rsp->scsi_status); } +/** + * ibmvfc_relogin - Log back into the specified device + * @sdev: scsi device struct + * + **/ +static void ibmvfc_relogin(struct scsi_device *sdev) +{ + struct ibmvfc_host *vhost = shost_priv(sdev->host); + struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); + struct ibmvfc_target *tgt; + + list_for_each_entry(tgt, &vhost->targets, queue) { + if (rport == tgt->rport) { + ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); + break; + } + } + + ibmvfc_reinit_host(vhost); +} + /** * ibmvfc_scsi_done - Handle responses from commands * @evt: ibmvfc event to be handled @@ -1483,7 +1537,7 @@ static void ibmvfc_scsi_done(struct ibmvfc_event *evt) if ((rsp->flags & FCP_SNS_LEN_VALID) && rsp->fcp_sense_len && rsp_len <= 8) memcpy(cmnd->sense_buffer, rsp->data.sense + rsp_len, sense_len); if ((vfc_cmd->status & IBMVFC_VIOS_FAILURE) && (vfc_cmd->error == IBMVFC_PLOGI_REQUIRED)) - ibmvfc_reinit_host(evt->vhost); + ibmvfc_relogin(cmnd->device); if (!cmnd->result && (!scsi_get_resid(cmnd) || (rsp->flags & FCP_RESID_OVER))) cmnd->result = (DID_ERROR << 16); @@ -2148,13 +2202,31 @@ static void ibmvfc_handle_async(struct ibmvfc_async_crq *crq, struct ibmvfc_host *vhost) { const char *desc = ibmvfc_get_ae_desc(crq->event); + struct ibmvfc_target *tgt; ibmvfc_log(vhost, 3, "%s event received. scsi_id: %llx, wwpn: %llx," " node_name: %llx\n", desc, crq->scsi_id, crq->wwpn, crq->node_name); switch (crq->event) { - case IBMVFC_AE_LINK_UP: case IBMVFC_AE_RESUME: + switch (crq->link_state) { + case IBMVFC_AE_LS_LINK_DOWN: + ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN); + break; + case IBMVFC_AE_LS_LINK_DEAD: + ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); + break; + case IBMVFC_AE_LS_LINK_UP: + case IBMVFC_AE_LS_LINK_BOUNCED: + default: + vhost->events_to_log |= IBMVFC_AE_LINKUP; + vhost->delay_init = 1; + __ibmvfc_reset_host(vhost); + break; + }; + + break; + case IBMVFC_AE_LINK_UP: vhost->events_to_log |= IBMVFC_AE_LINKUP; vhost->delay_init = 1; __ibmvfc_reset_host(vhost); @@ -2168,10 +2240,27 @@ static void ibmvfc_handle_async(struct ibmvfc_async_crq *crq, case IBMVFC_AE_SCN_NPORT: case IBMVFC_AE_SCN_GROUP: vhost->events_to_log |= IBMVFC_AE_RSCN; + ibmvfc_reinit_host(vhost); + break; case IBMVFC_AE_ELS_LOGO: case IBMVFC_AE_ELS_PRLO: case IBMVFC_AE_ELS_PLOGI: - ibmvfc_reinit_host(vhost); + list_for_each_entry(tgt, &vhost->targets, queue) { + if (!crq->scsi_id && !crq->wwpn && !crq->node_name) + break; + if (crq->scsi_id && tgt->scsi_id != crq->scsi_id) + continue; + if (crq->wwpn && tgt->ids.port_name != crq->wwpn) + continue; + if (crq->node_name && tgt->ids.node_name != crq->node_name) + continue; + if (tgt->need_login && crq->event == IBMVFC_AE_ELS_LOGO) + tgt->logo_rcvd = 1; + if (!tgt->need_login || crq->event == IBMVFC_AE_ELS_PLOGI) { + ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); + ibmvfc_reinit_host(vhost); + } + } break; case IBMVFC_AE_LINK_DOWN: case IBMVFC_AE_ADAPTER_FAILED: @@ -2222,6 +2311,7 @@ static void ibmvfc_handle_crq(struct ibmvfc_crq *crq, struct ibmvfc_host *vhost) return; case IBMVFC_CRQ_XPORT_EVENT: vhost->state = IBMVFC_NO_CRQ; + vhost->logged_in = 0; ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE); if (crq->format == IBMVFC_PARTITION_MIGRATED) { /* We need to re-setup the interpartition connection */ @@ -2299,7 +2389,7 @@ static int ibmvfc_scan_finished(struct Scsi_Host *shost, unsigned long time) done = 1; } - if (vhost->state != IBMVFC_NO_CRQ && vhost->action == IBMVFC_HOST_ACTION_NONE) + if (vhost->scan_complete) done = 1; spin_unlock_irqrestore(shost->host_lock, flags); return done; @@ -2434,14 +2524,6 @@ static ssize_t ibmvfc_show_host_partition_name(struct device *dev, vhost->login_buf->resp.partition_name); } -static struct device_attribute ibmvfc_host_partition_name = { - .attr = { - .name = "partition_name", - .mode = S_IRUGO, - }, - .show = ibmvfc_show_host_partition_name, -}; - static ssize_t ibmvfc_show_host_device_name(struct device *dev, struct device_attribute *attr, char *buf) { @@ -2452,14 +2534,6 @@ static ssize_t ibmvfc_show_host_device_name(struct device *dev, vhost->login_buf->resp.device_name); } -static struct device_attribute ibmvfc_host_device_name = { - .attr = { - .name = "device_name", - .mode = S_IRUGO, - }, - .show = ibmvfc_show_host_device_name, -}; - static ssize_t ibmvfc_show_host_loc_code(struct device *dev, struct device_attribute *attr, char *buf) { @@ -2470,14 +2544,6 @@ static ssize_t ibmvfc_show_host_loc_code(struct device *dev, vhost->login_buf->resp.port_loc_code); } -static struct device_attribute ibmvfc_host_loc_code = { - .attr = { - .name = "port_loc_code", - .mode = S_IRUGO, - }, - .show = ibmvfc_show_host_loc_code, -}; - static ssize_t ibmvfc_show_host_drc_name(struct device *dev, struct device_attribute *attr, char *buf) { @@ -2488,14 +2554,6 @@ static ssize_t ibmvfc_show_host_drc_name(struct device *dev, vhost->login_buf->resp.drc_name); } -static struct device_attribute ibmvfc_host_drc_name = { - .attr = { - .name = "drc_name", - .mode = S_IRUGO, - }, - .show = ibmvfc_show_host_drc_name, -}; - static ssize_t ibmvfc_show_host_npiv_version(struct device *dev, struct device_attribute *attr, char *buf) { @@ -2504,13 +2562,13 @@ static ssize_t ibmvfc_show_host_npiv_version(struct device *dev, return snprintf(buf, PAGE_SIZE, "%d\n", vhost->login_buf->resp.version); } -static struct device_attribute ibmvfc_host_npiv_version = { - .attr = { - .name = "npiv_version", - .mode = S_IRUGO, - }, - .show = ibmvfc_show_host_npiv_version, -}; +static ssize_t ibmvfc_show_host_capabilities(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct ibmvfc_host *vhost = shost_priv(shost); + return snprintf(buf, PAGE_SIZE, "%llx\n", vhost->login_buf->resp.capabilities); +} /** * ibmvfc_show_log_level - Show the adapter's error logging level @@ -2556,14 +2614,14 @@ static ssize_t ibmvfc_store_log_level(struct device *dev, return strlen(buf); } -static struct device_attribute ibmvfc_log_level_attr = { - .attr = { - .name = "log_level", - .mode = S_IRUGO | S_IWUSR, - }, - .show = ibmvfc_show_log_level, - .store = ibmvfc_store_log_level -}; +static DEVICE_ATTR(partition_name, S_IRUGO, ibmvfc_show_host_partition_name, NULL); +static DEVICE_ATTR(device_name, S_IRUGO, ibmvfc_show_host_device_name, NULL); +static DEVICE_ATTR(port_loc_code, S_IRUGO, ibmvfc_show_host_loc_code, NULL); +static DEVICE_ATTR(drc_name, S_IRUGO, ibmvfc_show_host_drc_name, NULL); +static DEVICE_ATTR(npiv_version, S_IRUGO, ibmvfc_show_host_npiv_version, NULL); +static DEVICE_ATTR(capabilities, S_IRUGO, ibmvfc_show_host_capabilities, NULL); +static DEVICE_ATTR(log_level, S_IRUGO | S_IWUSR, + ibmvfc_show_log_level, ibmvfc_store_log_level); #ifdef CONFIG_SCSI_IBMVFC_TRACE /** @@ -2612,12 +2670,13 @@ static struct bin_attribute ibmvfc_trace_attr = { #endif static struct device_attribute *ibmvfc_attrs[] = { - &ibmvfc_host_partition_name, - &ibmvfc_host_device_name, - &ibmvfc_host_loc_code, - &ibmvfc_host_drc_name, - &ibmvfc_host_npiv_version, - &ibmvfc_log_level_attr, + &dev_attr_partition_name, + &dev_attr_device_name, + &dev_attr_port_loc_code, + &dev_attr_drc_name, + &dev_attr_npiv_version, + &dev_attr_capabilities, + &dev_attr_log_level, NULL }; @@ -2727,27 +2786,27 @@ static void ibmvfc_tasklet(void *data) spin_lock_irqsave(vhost->host->host_lock, flags); while (!done) { - /* Pull all the valid messages off the CRQ */ - while ((crq = ibmvfc_next_crq(vhost)) != NULL) { - ibmvfc_handle_crq(crq, vhost); - crq->valid = 0; - } - /* Pull all the valid messages off the async CRQ */ while ((async = ibmvfc_next_async_crq(vhost)) != NULL) { ibmvfc_handle_async(async, vhost); async->valid = 0; } - vio_enable_interrupts(vdev); - if ((crq = ibmvfc_next_crq(vhost)) != NULL) { - vio_disable_interrupts(vdev); + /* Pull all the valid messages off the CRQ */ + while ((crq = ibmvfc_next_crq(vhost)) != NULL) { ibmvfc_handle_crq(crq, vhost); crq->valid = 0; - } else if ((async = ibmvfc_next_async_crq(vhost)) != NULL) { + } + + vio_enable_interrupts(vdev); + if ((async = ibmvfc_next_async_crq(vhost)) != NULL) { vio_disable_interrupts(vdev); ibmvfc_handle_async(async, vhost); async->valid = 0; + } else if ((crq = ibmvfc_next_crq(vhost)) != NULL) { + vio_disable_interrupts(vdev); + ibmvfc_handle_crq(crq, vhost); + crq->valid = 0; } else done = 1; } @@ -2774,15 +2833,19 @@ static void ibmvfc_init_tgt(struct ibmvfc_target *tgt, * @tgt: ibmvfc target struct * @job_step: initialization job step * + * Returns: 1 if step will be retried / 0 if not + * **/ -static void ibmvfc_retry_tgt_init(struct ibmvfc_target *tgt, +static int ibmvfc_retry_tgt_init(struct ibmvfc_target *tgt, void (*job_step) (struct ibmvfc_target *)) { if (++tgt->init_retries > IBMVFC_MAX_TGT_INIT_RETRIES) { ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); wake_up(&tgt->vhost->work_wait_q); + return 0; } else ibmvfc_init_tgt(tgt, job_step); + return 1; } /* Defined in FC-LS */ @@ -2831,7 +2894,7 @@ static void ibmvfc_tgt_prli_done(struct ibmvfc_event *evt) struct ibmvfc_process_login *rsp = &evt->xfer_iu->prli; struct ibmvfc_prli_svc_parms *parms = &rsp->parms; u32 status = rsp->common.status; - int index; + int index, level = IBMVFC_DEFAULT_LOG_LEVEL; vhost->discovery_threads--; ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); @@ -2850,7 +2913,7 @@ static void ibmvfc_tgt_prli_done(struct ibmvfc_event *evt) tgt->ids.roles |= FC_PORT_ROLE_FCP_TARGET; if (parms->service_parms & IBMVFC_PRLI_INITIATOR_FUNC) tgt->ids.roles |= FC_PORT_ROLE_FCP_INITIATOR; - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_ADD_RPORT); + tgt->add_rport = 1; } else ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); } else if (prli_rsp[index].retry) @@ -2867,13 +2930,18 @@ static void ibmvfc_tgt_prli_done(struct ibmvfc_event *evt) break; case IBMVFC_MAD_FAILED: default: - tgt_err(tgt, "Process Login failed: %s (%x:%x) rc=0x%02X\n", - ibmvfc_get_cmd_error(rsp->status, rsp->error), - rsp->status, rsp->error, status); - if (ibmvfc_retry_cmd(rsp->status, rsp->error)) - ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_prli); + if ((rsp->status & IBMVFC_VIOS_FAILURE) && rsp->error == IBMVFC_PLOGI_REQUIRED) + level += ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_plogi); + else if (tgt->logo_rcvd) + level += ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_plogi); + else if (ibmvfc_retry_cmd(rsp->status, rsp->error)) + level += ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_prli); else ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); + + tgt_log(tgt, level, "Process Login failed: %s (%x:%x) rc=0x%02X\n", + ibmvfc_get_cmd_error(rsp->status, rsp->error), + rsp->status, rsp->error, status); break; }; @@ -2932,6 +3000,7 @@ static void ibmvfc_tgt_plogi_done(struct ibmvfc_event *evt) struct ibmvfc_host *vhost = evt->vhost; struct ibmvfc_port_login *rsp = &evt->xfer_iu->plogi; u32 status = rsp->common.status; + int level = IBMVFC_DEFAULT_LOG_LEVEL; vhost->discovery_threads--; ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); @@ -2960,15 +3029,15 @@ static void ibmvfc_tgt_plogi_done(struct ibmvfc_event *evt) break; case IBMVFC_MAD_FAILED: default: - tgt_err(tgt, "Port Login failed: %s (%x:%x) %s (%x) %s (%x) rc=0x%02X\n", + if (ibmvfc_retry_cmd(rsp->status, rsp->error)) + level += ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_plogi); + else + ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); + + tgt_log(tgt, level, "Port Login failed: %s (%x:%x) %s (%x) %s (%x) rc=0x%02X\n", ibmvfc_get_cmd_error(rsp->status, rsp->error), rsp->status, rsp->error, ibmvfc_get_fc_type(rsp->fc_type), rsp->fc_type, ibmvfc_get_ls_explain(rsp->fc_explain), rsp->fc_explain, status); - - if (ibmvfc_retry_cmd(rsp->status, rsp->error)) - ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_plogi); - else - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); break; }; @@ -2992,6 +3061,7 @@ static void ibmvfc_tgt_send_plogi(struct ibmvfc_target *tgt) return; kref_get(&tgt->kref); + tgt->logo_rcvd = 0; evt = ibmvfc_get_event(vhost); vhost->discovery_threads++; ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT_WAIT); @@ -3129,13 +3199,13 @@ static void ibmvfc_tgt_adisc_done(struct ibmvfc_event *evt) case IBMVFC_MAD_SUCCESS: tgt_dbg(tgt, "ADISC succeeded\n"); if (ibmvfc_adisc_needs_plogi(mad, tgt)) - tgt->need_login = 1; + ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); break; case IBMVFC_MAD_DRIVER_FAILED: break; case IBMVFC_MAD_FAILED: default: - tgt->need_login = 1; + ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); fc_reason = (mad->fc_iu.response[1] & 0x00ff0000) >> 16; fc_explain = (mad->fc_iu.response[1] & 0x0000ff00) >> 8; tgt_info(tgt, "ADISC failed: %s (%x:%x) %s (%x) %s (%x) rc=0x%02X\n", @@ -3322,6 +3392,7 @@ static void ibmvfc_tgt_query_target_done(struct ibmvfc_event *evt) struct ibmvfc_host *vhost = evt->vhost; struct ibmvfc_query_tgt *rsp = &evt->xfer_iu->query_tgt; u32 status = rsp->common.status; + int level = IBMVFC_DEFAULT_LOG_LEVEL; vhost->discovery_threads--; ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); @@ -3341,19 +3412,19 @@ static void ibmvfc_tgt_query_target_done(struct ibmvfc_event *evt) break; case IBMVFC_MAD_FAILED: default: - tgt_err(tgt, "Query Target failed: %s (%x:%x) %s (%x) %s (%x) rc=0x%02X\n", - ibmvfc_get_cmd_error(rsp->status, rsp->error), rsp->status, rsp->error, - ibmvfc_get_fc_type(rsp->fc_type), rsp->fc_type, - ibmvfc_get_gs_explain(rsp->fc_explain), rsp->fc_explain, status); - if ((rsp->status & IBMVFC_FABRIC_MAPPED) == IBMVFC_FABRIC_MAPPED && rsp->error == IBMVFC_UNABLE_TO_PERFORM_REQ && rsp->fc_explain == IBMVFC_PORT_NAME_NOT_REG) ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); else if (ibmvfc_retry_cmd(rsp->status, rsp->error)) - ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_query_target); + level += ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_query_target); else ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); + + tgt_log(tgt, level, "Query Target failed: %s (%x:%x) %s (%x) %s (%x) rc=0x%02X\n", + ibmvfc_get_cmd_error(rsp->status, rsp->error), rsp->status, rsp->error, + ibmvfc_get_fc_type(rsp->fc_type), rsp->fc_type, + ibmvfc_get_gs_explain(rsp->fc_explain), rsp->fc_explain, status); break; }; @@ -3420,7 +3491,7 @@ static int ibmvfc_alloc_target(struct ibmvfc_host *vhost, u64 scsi_id) } spin_unlock_irqrestore(vhost->host->host_lock, flags); - tgt = mempool_alloc(vhost->tgt_pool, GFP_KERNEL); + tgt = mempool_alloc(vhost->tgt_pool, GFP_NOIO); if (!tgt) { dev_err(vhost->dev, "Target allocation failure for scsi id %08llx\n", scsi_id); @@ -3472,6 +3543,7 @@ static void ibmvfc_discover_targets_done(struct ibmvfc_event *evt) struct ibmvfc_host *vhost = evt->vhost; struct ibmvfc_discover_targets *rsp = &evt->xfer_iu->discover_targets; u32 mad_status = rsp->common.status; + int level = IBMVFC_DEFAULT_LOG_LEVEL; switch (mad_status) { case IBMVFC_MAD_SUCCESS: @@ -3480,9 +3552,9 @@ static void ibmvfc_discover_targets_done(struct ibmvfc_event *evt) ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_ALLOC_TGTS); break; case IBMVFC_MAD_FAILED: - dev_err(vhost->dev, "Discover Targets failed: %s (%x:%x)\n", - ibmvfc_get_cmd_error(rsp->status, rsp->error), rsp->status, rsp->error); - ibmvfc_retry_host_init(vhost); + level += ibmvfc_retry_host_init(vhost); + ibmvfc_log(vhost, level, "Discover Targets failed: %s (%x:%x)\n", + ibmvfc_get_cmd_error(rsp->status, rsp->error), rsp->status, rsp->error); break; case IBMVFC_MAD_DRIVER_FAILED: break; @@ -3534,18 +3606,19 @@ static void ibmvfc_npiv_login_done(struct ibmvfc_event *evt) u32 mad_status = evt->xfer_iu->npiv_login.common.status; struct ibmvfc_npiv_login_resp *rsp = &vhost->login_buf->resp; unsigned int npiv_max_sectors; + int level = IBMVFC_DEFAULT_LOG_LEVEL; switch (mad_status) { case IBMVFC_MAD_SUCCESS: ibmvfc_free_event(evt); break; case IBMVFC_MAD_FAILED: - dev_err(vhost->dev, "NPIV Login failed: %s (%x:%x)\n", - ibmvfc_get_cmd_error(rsp->status, rsp->error), rsp->status, rsp->error); if (ibmvfc_retry_cmd(rsp->status, rsp->error)) - ibmvfc_retry_host_init(vhost); + level += ibmvfc_retry_host_init(vhost); else ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); + ibmvfc_log(vhost, level, "NPIV Login failed: %s (%x:%x)\n", + ibmvfc_get_cmd_error(rsp->status, rsp->error), rsp->status, rsp->error); ibmvfc_free_event(evt); return; case IBMVFC_MAD_CRQ_ERROR: @@ -3578,6 +3651,7 @@ static void ibmvfc_npiv_login_done(struct ibmvfc_event *evt) return; } + vhost->logged_in = 1; npiv_max_sectors = min((uint)(rsp->max_dma_len >> 9), IBMVFC_MAX_SECTORS); dev_info(vhost->dev, "Host partition: %s, device: %s %s %s max sectors %u\n", rsp->partition_name, rsp->device_name, rsp->port_loc_code, @@ -3635,6 +3709,65 @@ static void ibmvfc_npiv_login(struct ibmvfc_host *vhost) ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); }; +/** + * ibmvfc_npiv_logout_done - Completion handler for NPIV Logout + * @vhost: ibmvfc host struct + * + **/ +static void ibmvfc_npiv_logout_done(struct ibmvfc_event *evt) +{ + struct ibmvfc_host *vhost = evt->vhost; + u32 mad_status = evt->xfer_iu->npiv_logout.common.status; + + ibmvfc_free_event(evt); + + switch (mad_status) { + case IBMVFC_MAD_SUCCESS: + if (list_empty(&vhost->sent) && + vhost->action == IBMVFC_HOST_ACTION_LOGO_WAIT) { + ibmvfc_init_host(vhost, 0); + return; + } + break; + case IBMVFC_MAD_FAILED: + case IBMVFC_MAD_NOT_SUPPORTED: + case IBMVFC_MAD_CRQ_ERROR: + case IBMVFC_MAD_DRIVER_FAILED: + default: + ibmvfc_dbg(vhost, "NPIV Logout failed. 0x%X\n", mad_status); + break; + } + + ibmvfc_hard_reset_host(vhost); +} + +/** + * ibmvfc_npiv_logout - Issue an NPIV Logout + * @vhost: ibmvfc host struct + * + **/ +static void ibmvfc_npiv_logout(struct ibmvfc_host *vhost) +{ + struct ibmvfc_npiv_logout_mad *mad; + struct ibmvfc_event *evt; + + evt = ibmvfc_get_event(vhost); + ibmvfc_init_event(evt, ibmvfc_npiv_logout_done, IBMVFC_MAD_FORMAT); + + mad = &evt->iu.npiv_logout; + memset(mad, 0, sizeof(*mad)); + mad->common.version = 1; + mad->common.opcode = IBMVFC_NPIV_LOGOUT; + mad->common.length = sizeof(struct ibmvfc_npiv_logout_mad); + + ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_LOGO_WAIT); + + if (!ibmvfc_send_event(evt, vhost, default_timeout)) + ibmvfc_dbg(vhost, "Sent NPIV logout\n"); + else + ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); +} + /** * ibmvfc_dev_init_to_do - Is there target initialization work to do? * @vhost: ibmvfc host struct @@ -3671,6 +3804,7 @@ static int __ibmvfc_work_to_do(struct ibmvfc_host *vhost) switch (vhost->action) { case IBMVFC_HOST_ACTION_NONE: case IBMVFC_HOST_ACTION_INIT_WAIT: + case IBMVFC_HOST_ACTION_LOGO_WAIT: return 0; case IBMVFC_HOST_ACTION_TGT_INIT: case IBMVFC_HOST_ACTION_QUERY_TGTS: @@ -3683,9 +3817,9 @@ static int __ibmvfc_work_to_do(struct ibmvfc_host *vhost) if (tgt->action == IBMVFC_TGT_ACTION_INIT_WAIT) return 0; return 1; + case IBMVFC_HOST_ACTION_LOGO: case IBMVFC_HOST_ACTION_INIT: case IBMVFC_HOST_ACTION_ALLOC_TGTS: - case IBMVFC_HOST_ACTION_TGT_ADD: case IBMVFC_HOST_ACTION_TGT_DEL: case IBMVFC_HOST_ACTION_TGT_DEL_FAILED: case IBMVFC_HOST_ACTION_QUERY: @@ -3740,25 +3874,26 @@ static void ibmvfc_log_ae(struct ibmvfc_host *vhost, int events) static void ibmvfc_tgt_add_rport(struct ibmvfc_target *tgt) { struct ibmvfc_host *vhost = tgt->vhost; - struct fc_rport *rport = tgt->rport; + struct fc_rport *rport; unsigned long flags; - if (rport) { - tgt_dbg(tgt, "Setting rport roles\n"); - fc_remote_port_rolechg(rport, tgt->ids.roles); - spin_lock_irqsave(vhost->host->host_lock, flags); - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); - spin_unlock_irqrestore(vhost->host->host_lock, flags); - return; - } - tgt_dbg(tgt, "Adding rport\n"); rport = fc_remote_port_add(vhost->host, 0, &tgt->ids); spin_lock_irqsave(vhost->host->host_lock, flags); - tgt->rport = rport; - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); + + if (rport && tgt->action == IBMVFC_TGT_ACTION_DEL_RPORT) { + tgt_dbg(tgt, "Deleting rport\n"); + list_del(&tgt->queue); + spin_unlock_irqrestore(vhost->host->host_lock, flags); + fc_remote_port_delete(rport); + del_timer_sync(&tgt->timer); + kref_put(&tgt->kref, ibmvfc_release_tgt); + return; + } + if (rport) { tgt_dbg(tgt, "rport add succeeded\n"); + tgt->rport = rport; rport->maxframe_size = tgt->service_parms.common.bb_rcv_sz & 0x0fff; rport->supported_classes = 0; tgt->target_id = rport->scsi_target_id; @@ -3789,8 +3924,12 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost) vhost->events_to_log = 0; switch (vhost->action) { case IBMVFC_HOST_ACTION_NONE: + case IBMVFC_HOST_ACTION_LOGO_WAIT: case IBMVFC_HOST_ACTION_INIT_WAIT: break; + case IBMVFC_HOST_ACTION_LOGO: + vhost->job_step(vhost); + break; case IBMVFC_HOST_ACTION_INIT: BUG_ON(vhost->state != IBMVFC_INITIALIZING); if (vhost->delay_init) { @@ -3836,11 +3975,21 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost) if (vhost->state == IBMVFC_INITIALIZING) { if (vhost->action == IBMVFC_HOST_ACTION_TGT_DEL_FAILED) { - ibmvfc_set_host_state(vhost, IBMVFC_ACTIVE); - ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_ADD); - vhost->init_retries = 0; - spin_unlock_irqrestore(vhost->host->host_lock, flags); - scsi_unblock_requests(vhost->host); + if (vhost->reinit) { + vhost->reinit = 0; + scsi_block_requests(vhost->host); + ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY); + spin_unlock_irqrestore(vhost->host->host_lock, flags); + } else { + ibmvfc_set_host_state(vhost, IBMVFC_ACTIVE); + ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE); + wake_up(&vhost->init_wait_q); + schedule_work(&vhost->rport_add_work_q); + vhost->init_retries = 0; + spin_unlock_irqrestore(vhost->host->host_lock, flags); + scsi_unblock_requests(vhost->host); + } + return; } else { ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT); @@ -3871,24 +4020,6 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost) if (!ibmvfc_dev_init_to_do(vhost)) ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_DEL_FAILED); break; - case IBMVFC_HOST_ACTION_TGT_ADD: - list_for_each_entry(tgt, &vhost->targets, queue) { - if (tgt->action == IBMVFC_TGT_ACTION_ADD_RPORT) { - spin_unlock_irqrestore(vhost->host->host_lock, flags); - ibmvfc_tgt_add_rport(tgt); - return; - } - } - - if (vhost->reinit && !ibmvfc_set_host_state(vhost, IBMVFC_INITIALIZING)) { - vhost->reinit = 0; - scsi_block_requests(vhost->host); - ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY); - } else { - ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE); - wake_up(&vhost->init_wait_q); - } - break; default: break; }; @@ -4117,6 +4248,56 @@ nomem: return -ENOMEM; } +/** + * ibmvfc_rport_add_thread - Worker thread for rport adds + * @work: work struct + * + **/ +static void ibmvfc_rport_add_thread(struct work_struct *work) +{ + struct ibmvfc_host *vhost = container_of(work, struct ibmvfc_host, + rport_add_work_q); + struct ibmvfc_target *tgt; + struct fc_rport *rport; + unsigned long flags; + int did_work; + + ENTER; + spin_lock_irqsave(vhost->host->host_lock, flags); + do { + did_work = 0; + if (vhost->state != IBMVFC_ACTIVE) + break; + + list_for_each_entry(tgt, &vhost->targets, queue) { + if (tgt->add_rport) { + did_work = 1; + tgt->add_rport = 0; + kref_get(&tgt->kref); + rport = tgt->rport; + if (!rport) { + spin_unlock_irqrestore(vhost->host->host_lock, flags); + ibmvfc_tgt_add_rport(tgt); + } else if (get_device(&rport->dev)) { + spin_unlock_irqrestore(vhost->host->host_lock, flags); + tgt_dbg(tgt, "Setting rport roles\n"); + fc_remote_port_rolechg(rport, tgt->ids.roles); + put_device(&rport->dev); + } + + kref_put(&tgt->kref, ibmvfc_release_tgt); + spin_lock_irqsave(vhost->host->host_lock, flags); + break; + } + } + } while(did_work); + + if (vhost->state == IBMVFC_ACTIVE) + vhost->scan_complete = 1; + spin_unlock_irqrestore(vhost->host->host_lock, flags); + LEAVE; +} + /** * ibmvfc_probe - Adapter hot plug add entry point * @vdev: vio device struct @@ -4160,6 +4341,7 @@ static int ibmvfc_probe(struct vio_dev *vdev, const struct vio_device_id *id) strcpy(vhost->partition_name, "UNKNOWN"); init_waitqueue_head(&vhost->work_wait_q); init_waitqueue_head(&vhost->init_wait_q); + INIT_WORK(&vhost->rport_add_work_q, ibmvfc_rport_add_thread); if ((rc = ibmvfc_alloc_mem(vhost))) goto free_scsi_host; diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h index ca1dcf7a7568..007fa1c9ef14 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.h +++ b/drivers/scsi/ibmvscsi/ibmvfc.h @@ -29,8 +29,8 @@ #include "viosrp.h" #define IBMVFC_NAME "ibmvfc" -#define IBMVFC_DRIVER_VERSION "1.0.5" -#define IBMVFC_DRIVER_DATE "(March 19, 2009)" +#define IBMVFC_DRIVER_VERSION "1.0.6" +#define IBMVFC_DRIVER_DATE "(May 28, 2009)" #define IBMVFC_DEFAULT_TIMEOUT 60 #define IBMVFC_ADISC_CANCEL_TIMEOUT 45 @@ -57,9 +57,10 @@ * Ensure we have resources for ERP and initialization: * 1 for ERP * 1 for initialization + * 1 for NPIV Logout * 2 for each discovery thread */ -#define IBMVFC_NUM_INTERNAL_REQ (1 + 1 + (disc_threads * 2)) +#define IBMVFC_NUM_INTERNAL_REQ (1 + 1 + 1 + (disc_threads * 2)) #define IBMVFC_MAD_SUCCESS 0x00 #define IBMVFC_MAD_NOT_SUPPORTED 0xF1 @@ -127,6 +128,7 @@ enum ibmvfc_mad_types { IBMVFC_IMPLICIT_LOGOUT = 0x0040, IBMVFC_PASSTHRU = 0x0200, IBMVFC_TMF_MAD = 0x0100, + IBMVFC_NPIV_LOGOUT = 0x0800, }; struct ibmvfc_mad_common { @@ -143,6 +145,10 @@ struct ibmvfc_npiv_login_mad { struct srp_direct_buf buffer; }__attribute__((packed, aligned (8))); +struct ibmvfc_npiv_logout_mad { + struct ibmvfc_mad_common common; +}__attribute__((packed, aligned (8))); + #define IBMVFC_MAX_NAME 256 struct ibmvfc_npiv_login { @@ -201,7 +207,8 @@ struct ibmvfc_npiv_login_resp { #define IBMVFC_NATIVE_FC 0x01 #define IBMVFC_CAN_FLUSH_ON_HALT 0x08 u32 reserved; - u64 capabilites; + u64 capabilities; +#define IBMVFC_CAN_FLUSH_ON_HALT 0x08 u32 max_cmds; u32 scsi_id_sz; u64 max_dma_len; @@ -541,9 +548,17 @@ struct ibmvfc_crq_queue { dma_addr_t msg_token; }; +enum ibmvfc_ae_link_state { + IBMVFC_AE_LS_LINK_UP = 0x01, + IBMVFC_AE_LS_LINK_BOUNCED = 0x02, + IBMVFC_AE_LS_LINK_DOWN = 0x04, + IBMVFC_AE_LS_LINK_DEAD = 0x08, +}; + struct ibmvfc_async_crq { volatile u8 valid; - u8 pad[3]; + u8 link_state; + u8 pad[2]; u32 pad2; volatile u64 event; volatile u64 scsi_id; @@ -561,6 +576,7 @@ struct ibmvfc_async_crq_queue { union ibmvfc_iu { struct ibmvfc_mad_common mad_common; struct ibmvfc_npiv_login_mad npiv_login; + struct ibmvfc_npiv_logout_mad npiv_logout; struct ibmvfc_discover_targets discover_targets; struct ibmvfc_port_login plogi; struct ibmvfc_process_login prli; @@ -575,7 +591,6 @@ enum ibmvfc_target_action { IBMVFC_TGT_ACTION_NONE = 0, IBMVFC_TGT_ACTION_INIT, IBMVFC_TGT_ACTION_INIT_WAIT, - IBMVFC_TGT_ACTION_ADD_RPORT, IBMVFC_TGT_ACTION_DEL_RPORT, }; @@ -588,7 +603,9 @@ struct ibmvfc_target { int target_id; enum ibmvfc_target_action action; int need_login; + int add_rport; int init_retries; + int logo_rcvd; u32 cancel_key; struct ibmvfc_service_parms service_parms; struct ibmvfc_service_parms service_parms_change; @@ -627,6 +644,8 @@ struct ibmvfc_event_pool { enum ibmvfc_host_action { IBMVFC_HOST_ACTION_NONE = 0, + IBMVFC_HOST_ACTION_LOGO, + IBMVFC_HOST_ACTION_LOGO_WAIT, IBMVFC_HOST_ACTION_INIT, IBMVFC_HOST_ACTION_INIT_WAIT, IBMVFC_HOST_ACTION_QUERY, @@ -635,7 +654,6 @@ enum ibmvfc_host_action { IBMVFC_HOST_ACTION_ALLOC_TGTS, IBMVFC_HOST_ACTION_TGT_INIT, IBMVFC_HOST_ACTION_TGT_DEL_FAILED, - IBMVFC_HOST_ACTION_TGT_ADD, }; enum ibmvfc_host_state { @@ -682,6 +700,8 @@ struct ibmvfc_host { int client_migrated; int reinit; int delay_init; + int scan_complete; + int logged_in; int events_to_log; #define IBMVFC_AE_LINKUP 0x0001 #define IBMVFC_AE_LINKDOWN 0x0002 @@ -692,6 +712,7 @@ struct ibmvfc_host { void (*job_step) (struct ibmvfc_host *); struct task_struct *work_thread; struct tasklet_struct tasklet; + struct work_struct rport_add_work_q; wait_queue_head_t init_wait_q; wait_queue_head_t work_wait_q; }; @@ -707,6 +728,12 @@ struct ibmvfc_host { #define tgt_err(t, fmt, ...) \ dev_err((t)->vhost->dev, "%llX: " fmt, (t)->scsi_id, ##__VA_ARGS__) +#define tgt_log(t, level, fmt, ...) \ + do { \ + if ((t)->vhost->log_level >= level) \ + tgt_err(t, fmt, ##__VA_ARGS__); \ + } while (0) + #define ibmvfc_dbg(vhost, ...) \ DBG_CMD(dev_info((vhost)->dev, ##__VA_ARGS__)) diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index c9aa7611e408..869a11bdccbd 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -70,6 +70,7 @@ #include #include #include +#include #include #include #include @@ -87,9 +88,15 @@ */ static int max_id = 64; static int max_channel = 3; -static int init_timeout = 5; +static int init_timeout = 300; +static int login_timeout = 60; +static int info_timeout = 30; +static int abort_timeout = 60; +static int reset_timeout = 60; static int max_requests = IBMVSCSI_MAX_REQUESTS_DEFAULT; static int max_events = IBMVSCSI_MAX_REQUESTS_DEFAULT + 2; +static int fast_fail = 1; +static int client_reserve = 1; static struct scsi_transport_template *ibmvscsi_transport_template; @@ -110,6 +117,10 @@ module_param_named(init_timeout, init_timeout, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(init_timeout, "Initialization timeout in seconds"); module_param_named(max_requests, max_requests, int, S_IRUGO); MODULE_PARM_DESC(max_requests, "Maximum requests for this adapter"); +module_param_named(fast_fail, fast_fail, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(fast_fail, "Enable fast fail. [Default=1]"); +module_param_named(client_reserve, client_reserve, int, S_IRUGO ); +MODULE_PARM_DESC(client_reserve, "Attempt client managed reserve/release"); /* ------------------------------------------------------------ * Routines for the event pool and event structs @@ -781,105 +792,53 @@ static int ibmvscsi_queuecommand(struct scsi_cmnd *cmnd, /* ------------------------------------------------------------ * Routines for driver initialization */ -/** - * adapter_info_rsp: - Handle response to MAD adapter info request - * @evt_struct: srp_event_struct with the response - * - * Used as a "done" callback by when sending adapter_info. Gets called - * by ibmvscsi_handle_crq() -*/ -static void adapter_info_rsp(struct srp_event_struct *evt_struct) -{ - struct ibmvscsi_host_data *hostdata = evt_struct->hostdata; - dma_unmap_single(hostdata->dev, - evt_struct->iu.mad.adapter_info.buffer, - evt_struct->iu.mad.adapter_info.common.length, - DMA_BIDIRECTIONAL); - if (evt_struct->xfer_iu->mad.adapter_info.common.status) { - dev_err(hostdata->dev, "error %d getting adapter info\n", - evt_struct->xfer_iu->mad.adapter_info.common.status); - } else { - dev_info(hostdata->dev, "host srp version: %s, " - "host partition %s (%d), OS %d, max io %u\n", - hostdata->madapter_info.srp_version, - hostdata->madapter_info.partition_name, - hostdata->madapter_info.partition_number, - hostdata->madapter_info.os_type, - hostdata->madapter_info.port_max_txu[0]); - - if (hostdata->madapter_info.port_max_txu[0]) - hostdata->host->max_sectors = - hostdata->madapter_info.port_max_txu[0] >> 9; - - if (hostdata->madapter_info.os_type == 3 && - strcmp(hostdata->madapter_info.srp_version, "1.6a") <= 0) { - dev_err(hostdata->dev, "host (Ver. %s) doesn't support large transfers\n", - hostdata->madapter_info.srp_version); - dev_err(hostdata->dev, "limiting scatterlists to %d\n", - MAX_INDIRECT_BUFS); - hostdata->host->sg_tablesize = MAX_INDIRECT_BUFS; - } +/** + * map_persist_bufs: - Pre-map persistent data for adapter logins + * @hostdata: ibmvscsi_host_data of host + * + * Map the capabilities and adapter info DMA buffers to avoid runtime failures. + * Return 1 on error, 0 on success. + */ +static int map_persist_bufs(struct ibmvscsi_host_data *hostdata) +{ + + hostdata->caps_addr = dma_map_single(hostdata->dev, &hostdata->caps, + sizeof(hostdata->caps), DMA_BIDIRECTIONAL); + + if (dma_mapping_error(hostdata->dev, hostdata->caps_addr)) { + dev_err(hostdata->dev, "Unable to map capabilities buffer!\n"); + return 1; } + + hostdata->adapter_info_addr = dma_map_single(hostdata->dev, + &hostdata->madapter_info, + sizeof(hostdata->madapter_info), + DMA_BIDIRECTIONAL); + if (dma_mapping_error(hostdata->dev, hostdata->adapter_info_addr)) { + dev_err(hostdata->dev, "Unable to map adapter info buffer!\n"); + dma_unmap_single(hostdata->dev, hostdata->caps_addr, + sizeof(hostdata->caps), DMA_BIDIRECTIONAL); + return 1; + } + + return 0; } /** - * send_mad_adapter_info: - Sends the mad adapter info request - * and stores the result so it can be retrieved with - * sysfs. We COULD consider causing a failure if the - * returned SRP version doesn't match ours. - * @hostdata: ibmvscsi_host_data of host - * - * Returns zero if successful. -*/ -static void send_mad_adapter_info(struct ibmvscsi_host_data *hostdata) + * unmap_persist_bufs: - Unmap persistent data needed for adapter logins + * @hostdata: ibmvscsi_host_data of host + * + * Unmap the capabilities and adapter info DMA buffers + */ +static void unmap_persist_bufs(struct ibmvscsi_host_data *hostdata) { - struct viosrp_adapter_info *req; - struct srp_event_struct *evt_struct; - unsigned long flags; - dma_addr_t addr; + dma_unmap_single(hostdata->dev, hostdata->caps_addr, + sizeof(hostdata->caps), DMA_BIDIRECTIONAL); - evt_struct = get_event_struct(&hostdata->pool); - if (!evt_struct) { - dev_err(hostdata->dev, - "couldn't allocate an event for ADAPTER_INFO_REQ!\n"); - return; - } - - init_event_struct(evt_struct, - adapter_info_rsp, - VIOSRP_MAD_FORMAT, - init_timeout); - - req = &evt_struct->iu.mad.adapter_info; - memset(req, 0x00, sizeof(*req)); - - req->common.type = VIOSRP_ADAPTER_INFO_TYPE; - req->common.length = sizeof(hostdata->madapter_info); - req->buffer = addr = dma_map_single(hostdata->dev, - &hostdata->madapter_info, - sizeof(hostdata->madapter_info), - DMA_BIDIRECTIONAL); - - if (dma_mapping_error(hostdata->dev, req->buffer)) { - if (!firmware_has_feature(FW_FEATURE_CMO)) - dev_err(hostdata->dev, - "Unable to map request_buffer for " - "adapter_info!\n"); - free_event_struct(&hostdata->pool, evt_struct); - return; - } - - spin_lock_irqsave(hostdata->host->host_lock, flags); - if (ibmvscsi_send_srp_event(evt_struct, hostdata, init_timeout * 2)) { - dev_err(hostdata->dev, "couldn't send ADAPTER_INFO_REQ!\n"); - dma_unmap_single(hostdata->dev, - addr, - sizeof(hostdata->madapter_info), - DMA_BIDIRECTIONAL); - } - spin_unlock_irqrestore(hostdata->host->host_lock, flags); -}; + dma_unmap_single(hostdata->dev, hostdata->adapter_info_addr, + sizeof(hostdata->madapter_info), DMA_BIDIRECTIONAL); +} /** * login_rsp: - Handle response to SRP login request @@ -909,9 +868,7 @@ static void login_rsp(struct srp_event_struct *evt_struct) } dev_info(hostdata->dev, "SRP_LOGIN succeeded\n"); - - if (evt_struct->xfer_iu->srp.login_rsp.req_lim_delta < 0) - dev_err(hostdata->dev, "Invalid request_limit.\n"); + hostdata->client_migrated = 0; /* Now we know what the real request-limit is. * This value is set rather than added to request_limit because @@ -922,15 +879,12 @@ static void login_rsp(struct srp_event_struct *evt_struct) /* If we had any pending I/Os, kick them */ scsi_unblock_requests(hostdata->host); - - send_mad_adapter_info(hostdata); - return; } /** * send_srp_login: - Sends the srp login * @hostdata: ibmvscsi_host_data of host - * + * * Returns zero if successful. */ static int send_srp_login(struct ibmvscsi_host_data *hostdata) @@ -939,22 +893,17 @@ static int send_srp_login(struct ibmvscsi_host_data *hostdata) unsigned long flags; struct srp_login_req *login; struct srp_event_struct *evt_struct = get_event_struct(&hostdata->pool); - if (!evt_struct) { - dev_err(hostdata->dev, "couldn't allocate an event for login req!\n"); - return FAILED; - } - init_event_struct(evt_struct, - login_rsp, - VIOSRP_SRP_FORMAT, - init_timeout); + BUG_ON(!evt_struct); + init_event_struct(evt_struct, login_rsp, + VIOSRP_SRP_FORMAT, login_timeout); login = &evt_struct->iu.srp.login_req; - memset(login, 0x00, sizeof(struct srp_login_req)); + memset(login, 0, sizeof(*login)); login->opcode = SRP_LOGIN_REQ; login->req_it_iu_len = sizeof(union srp_iu); login->req_buf_fmt = SRP_BUF_FORMAT_DIRECT | SRP_BUF_FORMAT_INDIRECT; - + spin_lock_irqsave(hostdata->host->host_lock, flags); /* Start out with a request limit of 0, since this is negotiated in * the login request we are just sending and login requests always @@ -962,12 +911,240 @@ static int send_srp_login(struct ibmvscsi_host_data *hostdata) */ atomic_set(&hostdata->request_limit, 0); - rc = ibmvscsi_send_srp_event(evt_struct, hostdata, init_timeout * 2); + rc = ibmvscsi_send_srp_event(evt_struct, hostdata, login_timeout * 2); spin_unlock_irqrestore(hostdata->host->host_lock, flags); dev_info(hostdata->dev, "sent SRP login\n"); return rc; }; +/** + * capabilities_rsp: - Handle response to MAD adapter capabilities request + * @evt_struct: srp_event_struct with the response + * + * Used as a "done" callback by when sending adapter_info. + */ +static void capabilities_rsp(struct srp_event_struct *evt_struct) +{ + struct ibmvscsi_host_data *hostdata = evt_struct->hostdata; + + if (evt_struct->xfer_iu->mad.capabilities.common.status) { + dev_err(hostdata->dev, "error 0x%X getting capabilities info\n", + evt_struct->xfer_iu->mad.capabilities.common.status); + } else { + if (hostdata->caps.migration.common.server_support != SERVER_SUPPORTS_CAP) + dev_info(hostdata->dev, "Partition migration not supported\n"); + + if (client_reserve) { + if (hostdata->caps.reserve.common.server_support == + SERVER_SUPPORTS_CAP) + dev_info(hostdata->dev, "Client reserve enabled\n"); + else + dev_info(hostdata->dev, "Client reserve not supported\n"); + } + } + + send_srp_login(hostdata); +} + +/** + * send_mad_capabilities: - Sends the mad capabilities request + * and stores the result so it can be retrieved with + * @hostdata: ibmvscsi_host_data of host + */ +static void send_mad_capabilities(struct ibmvscsi_host_data *hostdata) +{ + struct viosrp_capabilities *req; + struct srp_event_struct *evt_struct; + unsigned long flags; + struct device_node *of_node = hostdata->dev->archdata.of_node; + const char *location; + + evt_struct = get_event_struct(&hostdata->pool); + BUG_ON(!evt_struct); + + init_event_struct(evt_struct, capabilities_rsp, + VIOSRP_MAD_FORMAT, info_timeout); + + req = &evt_struct->iu.mad.capabilities; + memset(req, 0, sizeof(*req)); + + hostdata->caps.flags = CAP_LIST_SUPPORTED; + if (hostdata->client_migrated) + hostdata->caps.flags |= CLIENT_MIGRATED; + + strncpy(hostdata->caps.name, dev_name(&hostdata->host->shost_gendev), + sizeof(hostdata->caps.name)); + hostdata->caps.name[sizeof(hostdata->caps.name) - 1] = '\0'; + + location = of_get_property(of_node, "ibm,loc-code", NULL); + location = location ? location : dev_name(hostdata->dev); + strncpy(hostdata->caps.loc, location, sizeof(hostdata->caps.loc)); + hostdata->caps.loc[sizeof(hostdata->caps.loc) - 1] = '\0'; + + req->common.type = VIOSRP_CAPABILITIES_TYPE; + req->buffer = hostdata->caps_addr; + + hostdata->caps.migration.common.cap_type = MIGRATION_CAPABILITIES; + hostdata->caps.migration.common.length = sizeof(hostdata->caps.migration); + hostdata->caps.migration.common.server_support = SERVER_SUPPORTS_CAP; + hostdata->caps.migration.ecl = 1; + + if (client_reserve) { + hostdata->caps.reserve.common.cap_type = RESERVATION_CAPABILITIES; + hostdata->caps.reserve.common.length = sizeof(hostdata->caps.reserve); + hostdata->caps.reserve.common.server_support = SERVER_SUPPORTS_CAP; + hostdata->caps.reserve.type = CLIENT_RESERVE_SCSI_2; + req->common.length = sizeof(hostdata->caps); + } else + req->common.length = sizeof(hostdata->caps) - sizeof(hostdata->caps.reserve); + + spin_lock_irqsave(hostdata->host->host_lock, flags); + if (ibmvscsi_send_srp_event(evt_struct, hostdata, info_timeout * 2)) + dev_err(hostdata->dev, "couldn't send CAPABILITIES_REQ!\n"); + spin_unlock_irqrestore(hostdata->host->host_lock, flags); +}; + +/** + * fast_fail_rsp: - Handle response to MAD enable fast fail + * @evt_struct: srp_event_struct with the response + * + * Used as a "done" callback by when sending enable fast fail. Gets called + * by ibmvscsi_handle_crq() + */ +static void fast_fail_rsp(struct srp_event_struct *evt_struct) +{ + struct ibmvscsi_host_data *hostdata = evt_struct->hostdata; + u8 status = evt_struct->xfer_iu->mad.fast_fail.common.status; + + if (status == VIOSRP_MAD_NOT_SUPPORTED) + dev_err(hostdata->dev, "fast_fail not supported in server\n"); + else if (status == VIOSRP_MAD_FAILED) + dev_err(hostdata->dev, "fast_fail request failed\n"); + else if (status != VIOSRP_MAD_SUCCESS) + dev_err(hostdata->dev, "error 0x%X enabling fast_fail\n", status); + + send_mad_capabilities(hostdata); +} + +/** + * init_host - Start host initialization + * @hostdata: ibmvscsi_host_data of host + * + * Returns zero if successful. + */ +static int enable_fast_fail(struct ibmvscsi_host_data *hostdata) +{ + int rc; + unsigned long flags; + struct viosrp_fast_fail *fast_fail_mad; + struct srp_event_struct *evt_struct; + + if (!fast_fail) { + send_mad_capabilities(hostdata); + return 0; + } + + evt_struct = get_event_struct(&hostdata->pool); + BUG_ON(!evt_struct); + + init_event_struct(evt_struct, fast_fail_rsp, VIOSRP_MAD_FORMAT, info_timeout); + + fast_fail_mad = &evt_struct->iu.mad.fast_fail; + memset(fast_fail_mad, 0, sizeof(*fast_fail_mad)); + fast_fail_mad->common.type = VIOSRP_ENABLE_FAST_FAIL; + fast_fail_mad->common.length = sizeof(*fast_fail_mad); + + spin_lock_irqsave(hostdata->host->host_lock, flags); + rc = ibmvscsi_send_srp_event(evt_struct, hostdata, info_timeout * 2); + spin_unlock_irqrestore(hostdata->host->host_lock, flags); + return rc; +} + +/** + * adapter_info_rsp: - Handle response to MAD adapter info request + * @evt_struct: srp_event_struct with the response + * + * Used as a "done" callback by when sending adapter_info. Gets called + * by ibmvscsi_handle_crq() +*/ +static void adapter_info_rsp(struct srp_event_struct *evt_struct) +{ + struct ibmvscsi_host_data *hostdata = evt_struct->hostdata; + + if (evt_struct->xfer_iu->mad.adapter_info.common.status) { + dev_err(hostdata->dev, "error %d getting adapter info\n", + evt_struct->xfer_iu->mad.adapter_info.common.status); + } else { + dev_info(hostdata->dev, "host srp version: %s, " + "host partition %s (%d), OS %d, max io %u\n", + hostdata->madapter_info.srp_version, + hostdata->madapter_info.partition_name, + hostdata->madapter_info.partition_number, + hostdata->madapter_info.os_type, + hostdata->madapter_info.port_max_txu[0]); + + if (hostdata->madapter_info.port_max_txu[0]) + hostdata->host->max_sectors = + hostdata->madapter_info.port_max_txu[0] >> 9; + + if (hostdata->madapter_info.os_type == 3 && + strcmp(hostdata->madapter_info.srp_version, "1.6a") <= 0) { + dev_err(hostdata->dev, "host (Ver. %s) doesn't support large transfers\n", + hostdata->madapter_info.srp_version); + dev_err(hostdata->dev, "limiting scatterlists to %d\n", + MAX_INDIRECT_BUFS); + hostdata->host->sg_tablesize = MAX_INDIRECT_BUFS; + } + } + + enable_fast_fail(hostdata); +} + +/** + * send_mad_adapter_info: - Sends the mad adapter info request + * and stores the result so it can be retrieved with + * sysfs. We COULD consider causing a failure if the + * returned SRP version doesn't match ours. + * @hostdata: ibmvscsi_host_data of host + * + * Returns zero if successful. +*/ +static void send_mad_adapter_info(struct ibmvscsi_host_data *hostdata) +{ + struct viosrp_adapter_info *req; + struct srp_event_struct *evt_struct; + unsigned long flags; + + evt_struct = get_event_struct(&hostdata->pool); + BUG_ON(!evt_struct); + + init_event_struct(evt_struct, + adapter_info_rsp, + VIOSRP_MAD_FORMAT, + info_timeout); + + req = &evt_struct->iu.mad.adapter_info; + memset(req, 0x00, sizeof(*req)); + + req->common.type = VIOSRP_ADAPTER_INFO_TYPE; + req->common.length = sizeof(hostdata->madapter_info); + req->buffer = hostdata->adapter_info_addr; + + spin_lock_irqsave(hostdata->host->host_lock, flags); + if (ibmvscsi_send_srp_event(evt_struct, hostdata, info_timeout * 2)) + dev_err(hostdata->dev, "couldn't send ADAPTER_INFO_REQ!\n"); + spin_unlock_irqrestore(hostdata->host->host_lock, flags); +}; + +/** + * init_adapter: Start virtual adapter initialization sequence + * + */ +static void init_adapter(struct ibmvscsi_host_data *hostdata) +{ + send_mad_adapter_info(hostdata); +} + /** * sync_completion: Signal that a synchronous command has completed * Note that after returning from this call, the evt_struct is freed. @@ -1029,7 +1206,7 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd) init_event_struct(evt, sync_completion, VIOSRP_SRP_FORMAT, - init_timeout); + abort_timeout); tsk_mgmt = &evt->iu.srp.tsk_mgmt; @@ -1043,7 +1220,7 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd) evt->sync_srp = &srp_rsp; init_completion(&evt->comp); - rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, init_timeout * 2); + rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, abort_timeout * 2); if (rsp_rc != SCSI_MLQUEUE_HOST_BUSY) break; @@ -1152,7 +1329,7 @@ static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd) init_event_struct(evt, sync_completion, VIOSRP_SRP_FORMAT, - init_timeout); + reset_timeout); tsk_mgmt = &evt->iu.srp.tsk_mgmt; @@ -1165,7 +1342,7 @@ static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd) evt->sync_srp = &srp_rsp; init_completion(&evt->comp); - rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, init_timeout * 2); + rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, reset_timeout * 2); if (rsp_rc != SCSI_MLQUEUE_HOST_BUSY) break; @@ -1281,7 +1458,7 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq, if ((rc = ibmvscsi_ops->send_crq(hostdata, 0xC002000000000000LL, 0)) == 0) { /* Now login */ - send_srp_login(hostdata); + init_adapter(hostdata); } else { dev_err(hostdata->dev, "Unable to send init rsp. rc=%ld\n", rc); } @@ -1291,7 +1468,7 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq, dev_info(hostdata->dev, "partner initialization complete\n"); /* Now login */ - send_srp_login(hostdata); + init_adapter(hostdata); break; default: dev_err(hostdata->dev, "unknown crq message type: %d\n", crq->format); @@ -1303,6 +1480,7 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq, if (crq->format == 0x06) { /* We need to re-setup the interpartition connection */ dev_info(hostdata->dev, "Re-enabling adapter!\n"); + hostdata->client_migrated = 1; purge_requests(hostdata, DID_REQUEUE); if ((ibmvscsi_ops->reenable_crq_queue(&hostdata->queue, hostdata)) || @@ -1397,7 +1575,7 @@ static int ibmvscsi_do_host_config(struct ibmvscsi_host_data *hostdata, init_event_struct(evt_struct, sync_completion, VIOSRP_MAD_FORMAT, - init_timeout); + info_timeout); host_config = &evt_struct->iu.mad.host_config; @@ -1419,7 +1597,7 @@ static int ibmvscsi_do_host_config(struct ibmvscsi_host_data *hostdata, init_completion(&evt_struct->comp); spin_lock_irqsave(hostdata->host->host_lock, flags); - rc = ibmvscsi_send_srp_event(evt_struct, hostdata, init_timeout * 2); + rc = ibmvscsi_send_srp_event(evt_struct, hostdata, info_timeout * 2); spin_unlock_irqrestore(hostdata->host->host_lock, flags); if (rc == 0) wait_for_completion(&evt_struct->comp); @@ -1444,7 +1622,7 @@ static int ibmvscsi_slave_configure(struct scsi_device *sdev) spin_lock_irqsave(shost->host_lock, lock_flags); if (sdev->type == TYPE_DISK) { sdev->allow_restart = 1; - blk_queue_rq_timeout(sdev->request_queue, 60 * HZ); + blk_queue_rq_timeout(sdev->request_queue, 120 * HZ); } scsi_adjust_queue_depth(sdev, 0, shost->cmd_per_lun); spin_unlock_irqrestore(shost->host_lock, lock_flags); @@ -1471,6 +1649,46 @@ static int ibmvscsi_change_queue_depth(struct scsi_device *sdev, int qdepth) /* ------------------------------------------------------------ * sysfs attributes */ +static ssize_t show_host_vhost_loc(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct ibmvscsi_host_data *hostdata = shost_priv(shost); + int len; + + len = snprintf(buf, sizeof(hostdata->caps.loc), "%s\n", + hostdata->caps.loc); + return len; +} + +static struct device_attribute ibmvscsi_host_vhost_loc = { + .attr = { + .name = "vhost_loc", + .mode = S_IRUGO, + }, + .show = show_host_vhost_loc, +}; + +static ssize_t show_host_vhost_name(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct ibmvscsi_host_data *hostdata = shost_priv(shost); + int len; + + len = snprintf(buf, sizeof(hostdata->caps.name), "%s\n", + hostdata->caps.name); + return len; +} + +static struct device_attribute ibmvscsi_host_vhost_name = { + .attr = { + .name = "vhost_name", + .mode = S_IRUGO, + }, + .show = show_host_vhost_name, +}; + static ssize_t show_host_srp_version(struct device *dev, struct device_attribute *attr, char *buf) { @@ -1594,6 +1812,8 @@ static struct device_attribute ibmvscsi_host_config = { }; static struct device_attribute *ibmvscsi_attrs[] = { + &ibmvscsi_host_vhost_loc, + &ibmvscsi_host_vhost_name, &ibmvscsi_host_srp_version, &ibmvscsi_host_partition_name, &ibmvscsi_host_partition_number, @@ -1657,7 +1877,7 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id) unsigned long wait_switch = 0; int rc; - vdev->dev.driver_data = NULL; + dev_set_drvdata(&vdev->dev, NULL); host = scsi_host_alloc(&driver_template, sizeof(*hostdata)); if (!host) { @@ -1674,6 +1894,11 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id) atomic_set(&hostdata->request_limit, -1); hostdata->host->max_sectors = IBMVSCSI_MAX_SECTORS_DEFAULT; + if (map_persist_bufs(hostdata)) { + dev_err(&vdev->dev, "couldn't map persistent buffers\n"); + goto persist_bufs_failed; + } + rc = ibmvscsi_ops->init_crq_queue(&hostdata->queue, hostdata, max_events); if (rc != 0 && rc != H_RESOURCE) { dev_err(&vdev->dev, "couldn't initialize crq. rc=%d\n", rc); @@ -1687,6 +1912,7 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id) host->max_lun = 8; host->max_id = max_id; host->max_channel = max_channel; + host->max_cmd_len = 16; if (scsi_add_host(hostdata->host, hostdata->dev)) goto add_host_failed; @@ -1723,7 +1949,7 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id) scsi_scan_host(host); } - vdev->dev.driver_data = hostdata; + dev_set_drvdata(&vdev->dev, hostdata); return 0; add_srp_port_failed: @@ -1733,6 +1959,8 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id) init_pool_failed: ibmvscsi_ops->release_crq_queue(&hostdata->queue, hostdata, max_events); init_crq_failed: + unmap_persist_bufs(hostdata); + persist_bufs_failed: scsi_host_put(host); scsi_host_alloc_failed: return -1; @@ -1740,7 +1968,8 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id) static int ibmvscsi_remove(struct vio_dev *vdev) { - struct ibmvscsi_host_data *hostdata = vdev->dev.driver_data; + struct ibmvscsi_host_data *hostdata = dev_get_drvdata(&vdev->dev); + unmap_persist_bufs(hostdata); release_event_pool(&hostdata->pool, hostdata); ibmvscsi_ops->release_crq_queue(&hostdata->queue, hostdata, max_events); diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.h b/drivers/scsi/ibmvscsi/ibmvscsi.h index 2d4339d5e16e..76425303def0 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.h +++ b/drivers/scsi/ibmvscsi/ibmvscsi.h @@ -90,6 +90,7 @@ struct event_pool { /* all driver data associated with a host adapter */ struct ibmvscsi_host_data { atomic_t request_limit; + int client_migrated; struct device *dev; struct event_pool pool; struct crq_queue queue; @@ -97,6 +98,9 @@ struct ibmvscsi_host_data { struct list_head sent; struct Scsi_Host *host; struct mad_adapter_info_data madapter_info; + struct capabilities caps; + dma_addr_t caps_addr; + dma_addr_t adapter_info_addr; }; /* routines for managing a command/response queue */ diff --git a/drivers/scsi/ibmvscsi/ibmvstgt.c b/drivers/scsi/ibmvscsi/ibmvstgt.c index e2dd6a45924a..d5eaf9727109 100644 --- a/drivers/scsi/ibmvscsi/ibmvstgt.c +++ b/drivers/scsi/ibmvscsi/ibmvstgt.c @@ -892,7 +892,7 @@ free_vport: static int ibmvstgt_remove(struct vio_dev *dev) { - struct srp_target *target = (struct srp_target *) dev->dev.driver_data; + struct srp_target *target = dev_get_drvdata(&dev->dev); struct Scsi_Host *shost = target->shost; struct vio_port *vport = target->ldata; diff --git a/drivers/scsi/ibmvscsi/viosrp.h b/drivers/scsi/ibmvscsi/viosrp.h index 204604501ad8..2cd735d1d196 100644 --- a/drivers/scsi/ibmvscsi/viosrp.h +++ b/drivers/scsi/ibmvscsi/viosrp.h @@ -37,6 +37,7 @@ #define SRP_VERSION "16.a" #define SRP_MAX_IU_LEN 256 +#define SRP_MAX_LOC_LEN 32 union srp_iu { struct srp_login_req login_req; @@ -86,7 +87,37 @@ enum viosrp_mad_types { VIOSRP_EMPTY_IU_TYPE = 0x01, VIOSRP_ERROR_LOG_TYPE = 0x02, VIOSRP_ADAPTER_INFO_TYPE = 0x03, - VIOSRP_HOST_CONFIG_TYPE = 0x04 + VIOSRP_HOST_CONFIG_TYPE = 0x04, + VIOSRP_CAPABILITIES_TYPE = 0x05, + VIOSRP_ENABLE_FAST_FAIL = 0x08, +}; + +enum viosrp_mad_status { + VIOSRP_MAD_SUCCESS = 0x00, + VIOSRP_MAD_NOT_SUPPORTED = 0xF1, + VIOSRP_MAD_FAILED = 0xF7, +}; + +enum viosrp_capability_type { + MIGRATION_CAPABILITIES = 0x01, + RESERVATION_CAPABILITIES = 0x02, +}; + +enum viosrp_capability_support { + SERVER_DOES_NOT_SUPPORTS_CAP = 0x0, + SERVER_SUPPORTS_CAP = 0x01, + SERVER_CAP_DATA = 0x02, +}; + +enum viosrp_reserve_type { + CLIENT_RESERVE_SCSI_2 = 0x01, +}; + +enum viosrp_capability_flag { + CLIENT_MIGRATED = 0x01, + CLIENT_RECONNECT = 0x02, + CAP_LIST_SUPPORTED = 0x04, + CAP_LIST_DATA = 0x08, }; /* @@ -127,11 +158,46 @@ struct viosrp_host_config { u64 buffer; }; +struct viosrp_fast_fail { + struct mad_common common; +}; + +struct viosrp_capabilities { + struct mad_common common; + u64 buffer; +}; + +struct mad_capability_common { + u32 cap_type; + u16 length; + u16 server_support; +}; + +struct mad_reserve_cap { + struct mad_capability_common common; + u32 type; +}; + +struct mad_migration_cap { + struct mad_capability_common common; + u32 ecl; +}; + +struct capabilities{ + u32 flags; + char name[SRP_MAX_LOC_LEN]; + char loc[SRP_MAX_LOC_LEN]; + struct mad_migration_cap migration; + struct mad_reserve_cap reserve; +}; + union mad_iu { struct viosrp_empty_iu empty_iu; struct viosrp_error_log error_log; struct viosrp_adapter_info adapter_info; struct viosrp_host_config host_config; + struct viosrp_fast_fail fast_fail; + struct viosrp_capabilities capabilities; }; union viosrp_iu { diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index dd689ded8609..5f045505a1f4 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -131,13 +131,13 @@ static const struct ipr_chip_cfg_t ipr_chip_cfg[] = { }; static const struct ipr_chip_t ipr_chip[] = { - { PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE, &ipr_chip_cfg[0] }, - { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE, &ipr_chip_cfg[0] }, - { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN, &ipr_chip_cfg[0] }, - { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN, &ipr_chip_cfg[0] }, - { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E, &ipr_chip_cfg[0] }, - { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE, &ipr_chip_cfg[1] }, - { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP, &ipr_chip_cfg[1] } + { PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE, IPR_USE_LSI, &ipr_chip_cfg[0] }, + { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE, IPR_USE_LSI, &ipr_chip_cfg[0] }, + { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN, IPR_USE_LSI, &ipr_chip_cfg[0] }, + { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN, IPR_USE_LSI, &ipr_chip_cfg[0] }, + { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E, IPR_USE_MSI, &ipr_chip_cfg[0] }, + { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE, IPR_USE_LSI, &ipr_chip_cfg[1] }, + { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP, IPR_USE_LSI, &ipr_chip_cfg[1] } }; static int ipr_max_bus_speeds [] = { @@ -7003,6 +7003,7 @@ static void ipr_pci_perm_failure(struct pci_dev *pdev) ioa_cfg->sdt_state = ABORT_DUMP; ioa_cfg->reset_retries = IPR_NUM_RESET_RELOAD_RETRIES; ioa_cfg->in_ioa_bringdown = 1; + ioa_cfg->allow_cmds = 0; ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE); spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags); } @@ -7366,6 +7367,7 @@ static void __devinit ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg, INIT_LIST_HEAD(&ioa_cfg->used_res_q); INIT_WORK(&ioa_cfg->work_q, ipr_worker_thread); init_waitqueue_head(&ioa_cfg->reset_wait_q); + init_waitqueue_head(&ioa_cfg->msi_wait_q); ioa_cfg->sdt_state = INACTIVE; if (ipr_enable_cache) ioa_cfg->cache_state = CACHE_ENABLED; @@ -7397,24 +7399,107 @@ static void __devinit ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg, } /** - * ipr_get_chip_cfg - Find adapter chip configuration + * ipr_get_chip_info - Find adapter chip information * @dev_id: PCI device id struct * * Return value: - * ptr to chip config on success / NULL on failure + * ptr to chip information on success / NULL on failure **/ -static const struct ipr_chip_cfg_t * __devinit -ipr_get_chip_cfg(const struct pci_device_id *dev_id) +static const struct ipr_chip_t * __devinit +ipr_get_chip_info(const struct pci_device_id *dev_id) { int i; for (i = 0; i < ARRAY_SIZE(ipr_chip); i++) if (ipr_chip[i].vendor == dev_id->vendor && ipr_chip[i].device == dev_id->device) - return ipr_chip[i].cfg; + return &ipr_chip[i]; return NULL; } +/** + * ipr_test_intr - Handle the interrupt generated in ipr_test_msi(). + * @pdev: PCI device struct + * + * Description: Simply set the msi_received flag to 1 indicating that + * Message Signaled Interrupts are supported. + * + * Return value: + * 0 on success / non-zero on failure + **/ +static irqreturn_t __devinit ipr_test_intr(int irq, void *devp) +{ + struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)devp; + unsigned long lock_flags = 0; + irqreturn_t rc = IRQ_HANDLED; + + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + + ioa_cfg->msi_received = 1; + wake_up(&ioa_cfg->msi_wait_q); + + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + return rc; +} + +/** + * ipr_test_msi - Test for Message Signaled Interrupt (MSI) support. + * @pdev: PCI device struct + * + * Description: The return value from pci_enable_msi() can not always be + * trusted. This routine sets up and initiates a test interrupt to determine + * if the interrupt is received via the ipr_test_intr() service routine. + * If the tests fails, the driver will fall back to LSI. + * + * Return value: + * 0 on success / non-zero on failure + **/ +static int __devinit ipr_test_msi(struct ipr_ioa_cfg *ioa_cfg, + struct pci_dev *pdev) +{ + int rc; + volatile u32 int_reg; + unsigned long lock_flags = 0; + + ENTER; + + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + init_waitqueue_head(&ioa_cfg->msi_wait_q); + ioa_cfg->msi_received = 0; + ipr_mask_and_clear_interrupts(ioa_cfg, ~IPR_PCII_IOA_TRANS_TO_OPER); + writel(IPR_PCII_IO_DEBUG_ACKNOWLEDGE, ioa_cfg->regs.clr_interrupt_mask_reg); + int_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg); + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + + rc = request_irq(pdev->irq, ipr_test_intr, 0, IPR_NAME, ioa_cfg); + if (rc) { + dev_err(&pdev->dev, "Can not assign irq %d\n", pdev->irq); + return rc; + } else if (ipr_debug) + dev_info(&pdev->dev, "IRQ assigned: %d\n", pdev->irq); + + writel(IPR_PCII_IO_DEBUG_ACKNOWLEDGE, ioa_cfg->regs.sense_interrupt_reg); + int_reg = readl(ioa_cfg->regs.sense_interrupt_reg); + wait_event_timeout(ioa_cfg->msi_wait_q, ioa_cfg->msi_received, HZ); + ipr_mask_and_clear_interrupts(ioa_cfg, ~IPR_PCII_IOA_TRANS_TO_OPER); + + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + if (!ioa_cfg->msi_received) { + /* MSI test failed */ + dev_info(&pdev->dev, "MSI test failed. Falling back to LSI.\n"); + rc = -EOPNOTSUPP; + } else if (ipr_debug) + dev_info(&pdev->dev, "MSI test succeeded.\n"); + + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + + free_irq(pdev->irq, ioa_cfg); + + LEAVE; + + return rc; +} + /** * ipr_probe_ioa - Allocates memory and does first stage of initialization * @pdev: PCI device struct @@ -7440,11 +7525,6 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev, goto out; } - if (!(rc = pci_enable_msi(pdev))) - dev_info(&pdev->dev, "MSI enabled\n"); - else if (ipr_debug) - dev_info(&pdev->dev, "Cannot enable MSI\n"); - dev_info(&pdev->dev, "Found IOA with IRQ: %d\n", pdev->irq); host = scsi_host_alloc(&driver_template, sizeof(*ioa_cfg)); @@ -7460,14 +7540,16 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev, ata_host_init(&ioa_cfg->ata_host, &pdev->dev, sata_port_info.flags, &ipr_sata_ops); - ioa_cfg->chip_cfg = ipr_get_chip_cfg(dev_id); + ioa_cfg->ipr_chip = ipr_get_chip_info(dev_id); - if (!ioa_cfg->chip_cfg) { + if (!ioa_cfg->ipr_chip) { dev_err(&pdev->dev, "Unknown adapter chipset 0x%04X 0x%04X\n", dev_id->vendor, dev_id->device); goto out_scsi_host_put; } + ioa_cfg->chip_cfg = ioa_cfg->ipr_chip->cfg; + if (ipr_transop_timeout) ioa_cfg->transop_timeout = ipr_transop_timeout; else if (dev_id->driver_data & IPR_USE_LONG_TRANSOP_TIMEOUT) @@ -7518,6 +7600,18 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev, goto cleanup_nomem; } + /* Enable MSI style interrupts if they are supported. */ + if (ioa_cfg->ipr_chip->intr_type == IPR_USE_MSI && !pci_enable_msi(pdev)) { + rc = ipr_test_msi(ioa_cfg, pdev); + if (rc == -EOPNOTSUPP) + pci_disable_msi(pdev); + else if (rc) + goto out_msi_disable; + else + dev_info(&pdev->dev, "MSI enabled with IRQ: %d\n", pdev->irq); + } else if (ipr_debug) + dev_info(&pdev->dev, "Cannot enable MSI.\n"); + /* Save away PCI config space for use following IOA reset */ rc = pci_save_state(pdev); @@ -7555,7 +7649,9 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev, ioa_cfg->ioa_unit_checked = 1; ipr_mask_and_clear_interrupts(ioa_cfg, ~IPR_PCII_IOA_TRANS_TO_OPER); - rc = request_irq(pdev->irq, ipr_isr, IRQF_SHARED, IPR_NAME, ioa_cfg); + rc = request_irq(pdev->irq, ipr_isr, + ioa_cfg->msi_received ? 0 : IRQF_SHARED, + IPR_NAME, ioa_cfg); if (rc) { dev_err(&pdev->dev, "Couldn't register IRQ %d! rc=%d\n", @@ -7582,12 +7678,13 @@ cleanup_nolog: ipr_free_mem(ioa_cfg); cleanup_nomem: iounmap(ipr_regs); +out_msi_disable: + pci_disable_msi(pdev); out_release_regions: pci_release_regions(pdev); out_scsi_host_put: scsi_host_put(host); out_disable: - pci_disable_msi(pdev); pci_disable_device(pdev); goto out; } @@ -7688,7 +7785,7 @@ static void __ipr_remove(struct pci_dev *pdev) * Return value: * none **/ -static void ipr_remove(struct pci_dev *pdev) +static void __devexit ipr_remove(struct pci_dev *pdev) { struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev); @@ -7864,7 +7961,7 @@ static struct pci_driver ipr_driver = { .name = IPR_NAME, .id_table = ipr_pci_table, .probe = ipr_probe, - .remove = ipr_remove, + .remove = __devexit_p(ipr_remove), .shutdown = ipr_shutdown, .err_handler = &ipr_err_handler, }; diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h index 79a3ae4fb2c7..4b63dd6b1c81 100644 --- a/drivers/scsi/ipr.h +++ b/drivers/scsi/ipr.h @@ -37,8 +37,8 @@ /* * Literals */ -#define IPR_DRIVER_VERSION "2.4.2" -#define IPR_DRIVER_DATE "(January 21, 2009)" +#define IPR_DRIVER_VERSION "2.4.3" +#define IPR_DRIVER_DATE "(June 10, 2009)" /* * IPR_MAX_CMD_PER_LUN: This defines the maximum number of outstanding @@ -1025,6 +1025,9 @@ struct ipr_chip_cfg_t { struct ipr_chip_t { u16 vendor; u16 device; + u16 intr_type; +#define IPR_USE_LSI 0x00 +#define IPR_USE_MSI 0x01 const struct ipr_chip_cfg_t *cfg; }; @@ -1094,6 +1097,7 @@ struct ipr_ioa_cfg { u8 needs_hard_reset:1; u8 dual_raid:1; u8 needs_warm_reset:1; + u8 msi_received:1; u8 revid; @@ -1159,6 +1163,7 @@ struct ipr_ioa_cfg { unsigned int transop_timeout; const struct ipr_chip_cfg_t *chip_cfg; + const struct ipr_chip_t *ipr_chip; void __iomem *hdw_dma_regs; /* iomapped PCI memory space */ unsigned long hdw_dma_regs_pci; /* raw PCI memory space */ @@ -1179,6 +1184,7 @@ struct ipr_ioa_cfg { struct work_struct work_q; wait_queue_head_t reset_wait_q; + wait_queue_head_t msi_wait_q; struct ipr_dump *dump; enum ipr_sdt_state sdt_state; diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index b7c092d63bbe..518dbd91df85 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -253,8 +253,6 @@ static int iscsi_sw_tcp_xmit_segment(struct iscsi_tcp_conn *tcp_conn, if (r < 0) { iscsi_tcp_segment_unmap(segment); - if (copied || r == -EAGAIN) - break; return r; } copied += r; @@ -275,11 +273,17 @@ static int iscsi_sw_tcp_xmit(struct iscsi_conn *conn) while (1) { rc = iscsi_sw_tcp_xmit_segment(tcp_conn, segment); - if (rc < 0) { + /* + * We may not have been able to send data because the conn + * is getting stopped. libiscsi will know so propogate err + * for it to do the right thing. + */ + if (rc == -EAGAIN) + return rc; + else if (rc < 0) { rc = ISCSI_ERR_XMIT_FAILED; goto error; - } - if (rc == 0) + } else if (rc == 0) break; consumed += rc; diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index 4c880656990b..6fabf66972b9 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -45,14 +45,6 @@ #define FC_DISC_DELAY 3 -static int fc_disc_debug; - -#define FC_DEBUG_DISC(fmt...) \ - do { \ - if (fc_disc_debug) \ - FC_DBG(fmt); \ - } while (0) - static void fc_disc_gpn_ft_req(struct fc_disc *); static void fc_disc_gpn_ft_resp(struct fc_seq *, struct fc_frame *, void *); static int fc_disc_new_target(struct fc_disc *, struct fc_rport *, @@ -137,8 +129,8 @@ static void fc_disc_rport_callback(struct fc_lport *lport, struct fc_rport_libfc_priv *rdata = rport->dd_data; struct fc_disc *disc = &lport->disc; - FC_DEBUG_DISC("Received a %d event for port (%6x)\n", event, - rport->port_id); + FC_DISC_DBG(disc, "Received a %d event for port (%6x)\n", event, + rport->port_id); switch (event) { case RPORT_EV_CREATED: @@ -191,8 +183,7 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp, lport = disc->lport; - FC_DEBUG_DISC("Received an RSCN event on port (%6x)\n", - fc_host_port_id(lport->host)); + FC_DISC_DBG(disc, "Received an RSCN event\n"); /* make sure the frame contains an RSCN message */ rp = fc_frame_payload_get(fp, sizeof(*rp)); @@ -225,8 +216,8 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp, */ switch (fmt) { case ELS_ADDR_FMT_PORT: - FC_DEBUG_DISC("Port address format for port (%6x)\n", - ntoh24(pp->rscn_fid)); + FC_DISC_DBG(disc, "Port address format for port " + "(%6x)\n", ntoh24(pp->rscn_fid)); dp = kzalloc(sizeof(*dp), GFP_KERNEL); if (!dp) { redisc = 1; @@ -243,19 +234,19 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp, case ELS_ADDR_FMT_DOM: case ELS_ADDR_FMT_FAB: default: - FC_DEBUG_DISC("Address format is (%d)\n", fmt); + FC_DISC_DBG(disc, "Address format is (%d)\n", fmt); redisc = 1; break; } } lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL); if (redisc) { - FC_DEBUG_DISC("RSCN received: rediscovering\n"); + FC_DISC_DBG(disc, "RSCN received: rediscovering\n"); fc_disc_restart(disc); } else { - FC_DEBUG_DISC("RSCN received: not rediscovering. " - "redisc %d state %d in_prog %d\n", - redisc, lport->state, disc->pending); + FC_DISC_DBG(disc, "RSCN received: not rediscovering. " + "redisc %d state %d in_prog %d\n", + redisc, lport->state, disc->pending); list_for_each_entry_safe(dp, next, &disc_ports, peers) { list_del(&dp->peers); rport = lport->tt.rport_lookup(lport, dp->ids.port_id); @@ -270,7 +261,7 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp, fc_frame_free(fp); return; reject: - FC_DEBUG_DISC("Received a bad RSCN frame\n"); + FC_DISC_DBG(disc, "Received a bad RSCN frame\n"); rjt_data.fp = NULL; rjt_data.reason = ELS_RJT_LOGIC; rjt_data.explan = ELS_EXPL_NONE; @@ -302,7 +293,8 @@ static void fc_disc_recv_req(struct fc_seq *sp, struct fc_frame *fp, mutex_unlock(&disc->disc_mutex); break; default: - FC_DBG("Received an unsupported request. opcode (%x)\n", op); + FC_DISC_DBG(disc, "Received an unsupported request, " + "the opcode is (%x)\n", op); break; } } @@ -320,12 +312,10 @@ static void fc_disc_restart(struct fc_disc *disc) struct fc_rport_libfc_priv *rdata, *next; struct fc_lport *lport = disc->lport; - FC_DEBUG_DISC("Restarting discovery for port (%6x)\n", - fc_host_port_id(lport->host)); + FC_DISC_DBG(disc, "Restarting discovery\n"); list_for_each_entry_safe(rdata, next, &disc->rports, peers) { rport = PRIV_TO_RPORT(rdata); - FC_DEBUG_DISC("list_del(%6x)\n", rport->port_id); list_del(&rdata->peers); lport->tt.rport_logoff(rport); } @@ -485,8 +475,7 @@ static void fc_disc_done(struct fc_disc *disc) struct fc_lport *lport = disc->lport; enum fc_disc_event event; - FC_DEBUG_DISC("Discovery complete for port (%6x)\n", - fc_host_port_id(lport->host)); + FC_DISC_DBG(disc, "Discovery complete\n"); event = disc->event; disc->event = DISC_EV_NONE; @@ -510,10 +499,10 @@ static void fc_disc_error(struct fc_disc *disc, struct fc_frame *fp) { struct fc_lport *lport = disc->lport; unsigned long delay = 0; - if (fc_disc_debug) - FC_DBG("Error %ld, retries %d/%d\n", - PTR_ERR(fp), disc->retry_count, - FC_DISC_RETRY_LIMIT); + + FC_DISC_DBG(disc, "Error %ld, retries %d/%d\n", + PTR_ERR(fp), disc->retry_count, + FC_DISC_RETRY_LIMIT); if (!fp || PTR_ERR(fp) == -FC_EX_TIMEOUT) { /* @@ -649,9 +638,9 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len) &disc->rogue_rports); lport->tt.rport_login(rport); } else - FC_DBG("Failed to allocate memory for " - "the newly discovered port (%6x)\n", - dp.ids.port_id); + printk(KERN_WARNING "libfc: Failed to allocate " + "memory for the newly discovered port " + "(%6x)\n", dp.ids.port_id); } if (np->fp_flags & FC_NS_FID_LAST) { @@ -671,9 +660,8 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len) */ if (error == 0 && len > 0 && len < sizeof(*np)) { if (np != &disc->partial_buf) { - FC_DEBUG_DISC("Partial buffer remains " - "for discovery by (%6x)\n", - fc_host_port_id(lport->host)); + FC_DISC_DBG(disc, "Partial buffer remains " + "for discovery\n"); memcpy(&disc->partial_buf, np, len); } disc->buf_len = (unsigned char) len; @@ -721,8 +709,7 @@ static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp, int error; mutex_lock(&disc->disc_mutex); - FC_DEBUG_DISC("Received a GPN_FT response on port (%6x)\n", - fc_host_port_id(disc->lport->host)); + FC_DISC_DBG(disc, "Received a GPN_FT response\n"); if (IS_ERR(fp)) { fc_disc_error(disc, fp); @@ -738,30 +725,30 @@ static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp, disc->seq_count == 0) { cp = fc_frame_payload_get(fp, sizeof(*cp)); if (!cp) { - FC_DBG("GPN_FT response too short, len %d\n", - fr_len(fp)); + FC_DISC_DBG(disc, "GPN_FT response too short, len %d\n", + fr_len(fp)); } else if (ntohs(cp->ct_cmd) == FC_FS_ACC) { /* Accepted, parse the response. */ buf = cp + 1; len -= sizeof(*cp); } else if (ntohs(cp->ct_cmd) == FC_FS_RJT) { - FC_DBG("GPN_FT rejected reason %x exp %x " - "(check zoning)\n", cp->ct_reason, - cp->ct_explan); + FC_DISC_DBG(disc, "GPN_FT rejected reason %x exp %x " + "(check zoning)\n", cp->ct_reason, + cp->ct_explan); disc->event = DISC_EV_FAILED; fc_disc_done(disc); } else { - FC_DBG("GPN_FT unexpected response code %x\n", - ntohs(cp->ct_cmd)); + FC_DISC_DBG(disc, "GPN_FT unexpected response code " + "%x\n", ntohs(cp->ct_cmd)); } } else if (fr_sof(fp) == FC_SOF_N3 && seq_cnt == disc->seq_count) { buf = fh + 1; } else { - FC_DBG("GPN_FT unexpected frame - out of sequence? " - "seq_cnt %x expected %x sof %x eof %x\n", - seq_cnt, disc->seq_count, fr_sof(fp), fr_eof(fp)); + FC_DISC_DBG(disc, "GPN_FT unexpected frame - out of sequence? " + "seq_cnt %x expected %x sof %x eof %x\n", + seq_cnt, disc->seq_count, fr_sof(fp), fr_eof(fp)); } if (buf) { error = fc_disc_gpn_ft_parse(disc, buf, len); diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index 992af05aacf1..2bc22be5f849 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c @@ -32,18 +32,7 @@ #include #include -/* - * fc_exch_debug can be set in debugger or at compile time to get more logs. - */ -static int fc_exch_debug; - -#define FC_DEBUG_EXCH(fmt...) \ - do { \ - if (fc_exch_debug) \ - FC_DBG(fmt); \ - } while (0) - -static struct kmem_cache *fc_em_cachep; /* cache for exchanges */ +static struct kmem_cache *fc_em_cachep; /* cache for exchanges */ /* * Structure and function definitions for managing Fibre Channel Exchanges @@ -333,8 +322,8 @@ static inline void fc_exch_timer_set_locked(struct fc_exch *ep, if (ep->state & (FC_EX_RST_CLEANUP | FC_EX_DONE)) return; - FC_DEBUG_EXCH("Exchange (%4x) timed out, notifying the upper layer\n", - ep->xid); + FC_EXCH_DBG(ep, "Exchange timed out, notifying the upper layer\n"); + if (schedule_delayed_work(&ep->timeout_work, msecs_to_jiffies(timer_msec))) fc_exch_hold(ep); /* hold for timer */ @@ -545,7 +534,7 @@ struct fc_exch *fc_exch_alloc(struct fc_exch_mgr *mp, /* alloc a new xid */ xid = fc_em_alloc_xid(mp, fp); if (!xid) { - printk(KERN_ERR "fc_em_alloc_xid() failed\n"); + printk(KERN_WARNING "libfc: Failed to allocate an exhange\n"); goto err; } } @@ -820,8 +809,8 @@ static struct fc_seq *fc_seq_start_next_locked(struct fc_seq *sp) struct fc_exch *ep = fc_seq_exch(sp); sp = fc_seq_alloc(ep, ep->seq_id++); - FC_DEBUG_EXCH("exch %4x f_ctl %6x seq %2x\n", - ep->xid, ep->f_ctl, sp->id); + FC_EXCH_DBG(ep, "f_ctl %6x seq %2x\n", + ep->f_ctl, sp->id); return sp; } /* @@ -901,7 +890,7 @@ void fc_seq_els_rsp_send(struct fc_seq *sp, enum fc_els_cmd els_cmd, fc_exch_els_rec(sp, els_data->fp); break; default: - FC_DBG("Invalid ELS CMD:%x\n", els_cmd); + FC_EXCH_DBG(fc_seq_exch(sp), "Invalid ELS CMD:%x\n", els_cmd); } } EXPORT_SYMBOL(fc_seq_els_rsp_send); @@ -1134,7 +1123,7 @@ static void fc_exch_recv_req(struct fc_lport *lp, struct fc_exch_mgr *mp, lp->tt.lport_recv(lp, sp, fp); fc_exch_release(ep); /* release from lookup */ } else { - FC_DEBUG_EXCH("exch/seq lookup failed: reject %x\n", reject); + FC_EM_DBG(mp, "exch/seq lookup failed: reject %x\n", reject); fc_frame_free(fp); } } @@ -1159,6 +1148,10 @@ static void fc_exch_recv_seq_resp(struct fc_exch_mgr *mp, struct fc_frame *fp) atomic_inc(&mp->stats.xid_not_found); goto out; } + if (ep->esb_stat & ESB_ST_COMPLETE) { + atomic_inc(&mp->stats.xid_not_found); + goto out; + } if (ep->rxid == FC_XID_UNKNOWN) ep->rxid = ntohs(fh->fh_rx_id); if (ep->sid != 0 && ep->sid != ntoh24(fh->fh_d_id)) { @@ -1238,10 +1231,10 @@ static void fc_exch_recv_resp(struct fc_exch_mgr *mp, struct fc_frame *fp) sp = fc_seq_lookup_orig(mp, fp); /* doesn't hold sequence */ if (!sp) { atomic_inc(&mp->stats.xid_not_found); - FC_DEBUG_EXCH("seq lookup failed\n"); + FC_EM_DBG(mp, "seq lookup failed\n"); } else { atomic_inc(&mp->stats.non_bls_resp); - FC_DEBUG_EXCH("non-BLS response to sequence"); + FC_EM_DBG(mp, "non-BLS response to sequence"); } fc_frame_free(fp); } @@ -1262,8 +1255,8 @@ static void fc_exch_abts_resp(struct fc_exch *ep, struct fc_frame *fp) int rc = 1, has_rec = 0; fh = fc_frame_header_get(fp); - FC_DEBUG_EXCH("exch: BLS rctl %x - %s\n", - fh->fh_r_ctl, fc_exch_rctl_name(fh->fh_r_ctl)); + FC_EXCH_DBG(ep, "exch: BLS rctl %x - %s\n", fh->fh_r_ctl, + fc_exch_rctl_name(fh->fh_r_ctl)); if (cancel_delayed_work_sync(&ep->timeout_work)) fc_exch_release(ep); /* release from pending timer hold */ @@ -1355,9 +1348,9 @@ static void fc_exch_recv_bls(struct fc_exch_mgr *mp, struct fc_frame *fp) case FC_RCTL_ACK_0: break; default: - FC_DEBUG_EXCH("BLS rctl %x - %s received", - fh->fh_r_ctl, - fc_exch_rctl_name(fh->fh_r_ctl)); + FC_EXCH_DBG(ep, "BLS rctl %x - %s received", + fh->fh_r_ctl, + fc_exch_rctl_name(fh->fh_r_ctl)); break; } fc_frame_free(fp); @@ -1595,7 +1588,8 @@ static void fc_exch_rrq_resp(struct fc_seq *sp, struct fc_frame *fp, void *arg) if (err == -FC_EX_CLOSED || err == -FC_EX_TIMEOUT) goto cleanup; - FC_DBG("Cannot process RRQ, because of frame error %d\n", err); + FC_EXCH_DBG(aborted_ep, "Cannot process RRQ, " + "frame error %d\n", err); return; } @@ -1604,12 +1598,13 @@ static void fc_exch_rrq_resp(struct fc_seq *sp, struct fc_frame *fp, void *arg) switch (op) { case ELS_LS_RJT: - FC_DBG("LS_RJT for RRQ"); + FC_EXCH_DBG(aborted_ep, "LS_RJT for RRQ"); /* fall through */ case ELS_LS_ACC: goto cleanup; default: - FC_DBG("unexpected response op %x for RRQ", op); + FC_EXCH_DBG(aborted_ep, "unexpected response op %x " + "for RRQ", op); return; } @@ -1736,8 +1731,8 @@ struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp, size_t len; if (max_xid <= min_xid || min_xid == 0 || max_xid == FC_XID_UNKNOWN) { - FC_DBG("Invalid min_xid 0x:%x and max_xid 0x:%x\n", - min_xid, max_xid); + FC_LPORT_DBG(lp, "Invalid min_xid 0x:%x and max_xid 0x:%x\n", + min_xid, max_xid); return NULL; } @@ -1874,7 +1869,8 @@ void fc_exch_recv(struct fc_lport *lp, struct fc_exch_mgr *mp, /* lport lock ? */ if (!lp || !mp || (lp->state == LPORT_ST_NONE)) { - FC_DBG("fc_lport or EM is not allocated and configured"); + FC_LPORT_DBG(lp, "Receiving frames for an lport that " + "has not been initialized correctly\n"); fc_frame_free(fp); return; } @@ -1900,7 +1896,7 @@ void fc_exch_recv(struct fc_lport *lp, struct fc_exch_mgr *mp, fc_exch_recv_req(lp, mp, fp); break; default: - FC_DBG("dropping invalid frame (eof %x)", fr_eof(fp)); + FC_EM_DBG(mp, "dropping invalid frame (eof %x)", fr_eof(fp)); fc_frame_free(fp); break; } diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c index 521f996f9b13..e303e0d12c4b 100644 --- a/drivers/scsi/libfc/fc_fcp.c +++ b/drivers/scsi/libfc/fc_fcp.c @@ -43,13 +43,9 @@ MODULE_AUTHOR("Open-FCoE.org"); MODULE_DESCRIPTION("libfc"); MODULE_LICENSE("GPL v2"); -static int fc_fcp_debug; - -#define FC_DEBUG_FCP(fmt...) \ - do { \ - if (fc_fcp_debug) \ - FC_DBG(fmt); \ - } while (0) +unsigned int fc_debug_logging; +module_param_named(debug_logging, fc_debug_logging, int, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(debug_logging, "a bit mask of logging levels"); static struct kmem_cache *scsi_pkt_cachep; @@ -347,8 +343,8 @@ static void fc_fcp_recv_data(struct fc_fcp_pkt *fsp, struct fc_frame *fp) if ((fr_flags(fp) & FCPHF_CRC_UNCHECKED) && fc_frame_crc_check(fp)) goto crc_err; - FC_DEBUG_FCP("data received past end. len %zx offset %zx " - "data_len %x\n", len, offset, fsp->data_len); + FC_FCP_DBG(fsp, "data received past end. len %zx offset %zx " + "data_len %x\n", len, offset, fsp->data_len); fc_fcp_retry_cmd(fsp); return; } @@ -411,7 +407,8 @@ crc_err: stats->ErrorFrames++; /* FIXME - per cpu count, not total count! */ if (stats->InvalidCRCCount++ < 5) - printk(KERN_WARNING "CRC error on data frame for port (%6x)\n", + printk(KERN_WARNING "libfc: CRC error on data " + "frame for port (%6x)\n", fc_host_port_id(lp->host)); /* * Assume the frame is total garbage. @@ -475,14 +472,14 @@ static int fc_fcp_send_data(struct fc_fcp_pkt *fsp, struct fc_seq *seq, WARN_ON(seq_blen <= 0); if (unlikely(offset + seq_blen > fsp->data_len)) { /* this should never happen */ - FC_DEBUG_FCP("xfer-ready past end. seq_blen %zx offset %zx\n", - seq_blen, offset); + FC_FCP_DBG(fsp, "xfer-ready past end. seq_blen %zx " + "offset %zx\n", seq_blen, offset); fc_fcp_send_abort(fsp); return 0; } else if (offset != fsp->xfer_len) { /* Out of Order Data Request - no problem, but unexpected. */ - FC_DEBUG_FCP("xfer-ready non-contiguous. " - "seq_blen %zx offset %zx\n", seq_blen, offset); + FC_FCP_DBG(fsp, "xfer-ready non-contiguous. " + "seq_blen %zx offset %zx\n", seq_blen, offset); } /* @@ -493,7 +490,7 @@ static int fc_fcp_send_data(struct fc_fcp_pkt *fsp, struct fc_seq *seq, t_blen = fsp->max_payload; if (lp->seq_offload) { t_blen = min(seq_blen, (size_t)lp->lso_max); - FC_DEBUG_FCP("fsp=%p:lso:blen=%zx lso_max=0x%x t_blen=%zx\n", + FC_FCP_DBG(fsp, "fsp=%p:lso:blen=%zx lso_max=0x%x t_blen=%zx\n", fsp, seq_blen, lp->lso_max, t_blen); } @@ -694,7 +691,7 @@ static void fc_fcp_reduce_can_queue(struct fc_lport *lp) if (!can_queue) can_queue = 1; lp->host->can_queue = can_queue; - shost_printk(KERN_ERR, lp->host, "Could not allocate frame.\n" + shost_printk(KERN_ERR, lp->host, "libfc: Could not allocate frame.\n" "Reducing can_queue to %d.\n", can_queue); done: spin_unlock_irqrestore(lp->host->host_lock, flags); @@ -768,7 +765,7 @@ static void fc_fcp_recv(struct fc_seq *seq, struct fc_frame *fp, void *arg) fc_fcp_resp(fsp, fp); } else { - FC_DBG("unexpected frame. r_ctl %x\n", r_ctl); + FC_FCP_DBG(fsp, "unexpected frame. r_ctl %x\n", r_ctl); } unlock: fc_fcp_unlock_pkt(fsp); @@ -877,17 +874,17 @@ static void fc_fcp_resp(struct fc_fcp_pkt *fsp, struct fc_frame *fp) return; } fsp->status_code = FC_DATA_OVRRUN; - FC_DBG("tgt %6x xfer len %zx greater than expected len %x. " - "data len %x\n", - fsp->rport->port_id, - fsp->xfer_len, expected_len, fsp->data_len); + FC_FCP_DBG(fsp, "tgt %6x xfer len %zx greater than expected, " + "len %x, data len %x\n", + fsp->rport->port_id, + fsp->xfer_len, expected_len, fsp->data_len); } fc_fcp_complete_locked(fsp); return; len_err: - FC_DBG("short FCP response. flags 0x%x len %u respl %u snsl %u\n", - flags, fr_len(fp), respl, snsl); + FC_FCP_DBG(fsp, "short FCP response. flags 0x%x len %u respl %u " + "snsl %u\n", flags, fr_len(fp), respl, snsl); err: fsp->status_code = FC_ERROR; fc_fcp_complete_locked(fsp); @@ -1107,13 +1104,11 @@ static void fc_fcp_error(struct fc_fcp_pkt *fsp, struct fc_frame *fp) if (fc_fcp_lock_pkt(fsp)) return; - switch (error) { - case -FC_EX_CLOSED: + if (error == -FC_EX_CLOSED) { fc_fcp_retry_cmd(fsp); goto unlock; - default: - FC_DBG("unknown error %ld\n", PTR_ERR(fp)); } + /* * clear abort pending, because the lower layer * decided to force completion. @@ -1145,10 +1140,10 @@ static int fc_fcp_pkt_abort(struct fc_lport *lp, struct fc_fcp_pkt *fsp) fsp->wait_for_comp = 0; if (!rc) { - FC_DBG("target abort cmd failed\n"); + FC_FCP_DBG(fsp, "target abort cmd failed\n"); rc = FAILED; } else if (fsp->state & FC_SRB_ABORTED) { - FC_DBG("target abort cmd passed\n"); + FC_FCP_DBG(fsp, "target abort cmd passed\n"); rc = SUCCESS; fc_fcp_complete_locked(fsp); } @@ -1213,7 +1208,7 @@ static int fc_lun_reset(struct fc_lport *lp, struct fc_fcp_pkt *fsp, spin_unlock_bh(&fsp->scsi_pkt_lock); if (!rc) { - FC_DBG("lun reset failed\n"); + FC_SCSI_DBG(lp, "lun reset failed\n"); return FAILED; } @@ -1221,7 +1216,7 @@ static int fc_lun_reset(struct fc_lport *lp, struct fc_fcp_pkt *fsp, if (fsp->cdb_status != FCP_TMF_CMPL) return FAILED; - FC_DBG("lun reset to lun %u completed\n", lun); + FC_SCSI_DBG(lp, "lun reset to lun %u completed\n", lun); fc_fcp_cleanup_each_cmd(lp, id, lun, FC_CMD_ABORTED); return SUCCESS; } @@ -1388,13 +1383,13 @@ static void fc_fcp_rec_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg) rjt = fc_frame_payload_get(fp, sizeof(*rjt)); switch (rjt->er_reason) { default: - FC_DEBUG_FCP("device %x unexpected REC reject " - "reason %d expl %d\n", - fsp->rport->port_id, rjt->er_reason, - rjt->er_explan); + FC_FCP_DBG(fsp, "device %x unexpected REC reject " + "reason %d expl %d\n", + fsp->rport->port_id, rjt->er_reason, + rjt->er_explan); /* fall through */ case ELS_RJT_UNSUP: - FC_DEBUG_FCP("device does not support REC\n"); + FC_FCP_DBG(fsp, "device does not support REC\n"); rp = fsp->rport->dd_data; /* * if we do not spport RECs or got some bogus @@ -1514,8 +1509,8 @@ static void fc_fcp_rec_error(struct fc_fcp_pkt *fsp, struct fc_frame *fp) break; default: - FC_DBG("REC %p fid %x error unexpected error %d\n", - fsp, fsp->rport->port_id, error); + FC_FCP_DBG(fsp, "REC %p fid %x error unexpected error %d\n", + fsp, fsp->rport->port_id, error); fsp->status_code = FC_CMD_PLOGO; /* fall through */ @@ -1524,9 +1519,9 @@ static void fc_fcp_rec_error(struct fc_fcp_pkt *fsp, struct fc_frame *fp) * Assume REC or LS_ACC was lost. * The exchange manager will have aborted REC, so retry. */ - FC_DBG("REC fid %x error error %d retry %d/%d\n", - fsp->rport->port_id, error, fsp->recov_retry, - FC_MAX_RECOV_RETRY); + FC_FCP_DBG(fsp, "REC fid %x error error %d retry %d/%d\n", + fsp->rport->port_id, error, fsp->recov_retry, + FC_MAX_RECOV_RETRY); if (fsp->recov_retry++ < FC_MAX_RECOV_RETRY) fc_fcp_rec(fsp); else @@ -1896,7 +1891,7 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp) sc_cmd->result = (DID_ERROR << 16) | fsp->cdb_status; break; case FC_CMD_ABORTED: - sc_cmd->result = (DID_ABORT << 16) | fsp->io_status; + sc_cmd->result = (DID_ERROR << 16) | fsp->io_status; break; case FC_CMD_TIME_OUT: sc_cmd->result = (DID_BUS_BUSY << 16) | fsp->io_status; @@ -2011,9 +2006,11 @@ int fc_eh_device_reset(struct scsi_cmnd *sc_cmd) if (lp->state != LPORT_ST_READY) return rc; + FC_SCSI_DBG(lp, "Resetting rport (%6x)\n", rport->port_id); + fsp = fc_fcp_pkt_alloc(lp, GFP_NOIO); if (fsp == NULL) { - FC_DBG("could not allocate scsi_pkt\n"); + printk(KERN_WARNING "libfc: could not allocate scsi_pkt\n"); sc_cmd->result = DID_NO_CONNECT << 16; goto out; } @@ -2048,17 +2045,21 @@ int fc_eh_host_reset(struct scsi_cmnd *sc_cmd) struct fc_lport *lp = shost_priv(shost); unsigned long wait_tmo; + FC_SCSI_DBG(lp, "Resetting host\n"); + lp->tt.lport_reset(lp); wait_tmo = jiffies + FC_HOST_RESET_TIMEOUT; while (!fc_fcp_lport_queue_ready(lp) && time_before(jiffies, wait_tmo)) msleep(1000); if (fc_fcp_lport_queue_ready(lp)) { - shost_printk(KERN_INFO, shost, "Host reset succeeded.\n"); + shost_printk(KERN_INFO, shost, "libfc: Host reset succeeded " + "on port (%6x)\n", fc_host_port_id(lp->host)); return SUCCESS; } else { - shost_printk(KERN_INFO, shost, "Host reset failed. " - "lport not ready.\n"); + shost_printk(KERN_INFO, shost, "libfc: Host reset failed, " + "port (%6x) is not ready.\n", + fc_host_port_id(lp->host)); return FAILED; } } @@ -2117,7 +2118,8 @@ void fc_fcp_destroy(struct fc_lport *lp) struct fc_fcp_internal *si = fc_get_scsi_internal(lp); if (!list_empty(&si->scsi_pkt_queue)) - printk(KERN_ERR "Leaked scsi packets.\n"); + printk(KERN_ERR "libfc: Leaked SCSI packets when destroying " + "port (%6x)\n", fc_host_port_id(lp->host)); mempool_destroy(si->scsi_pkt_pool); kfree(si); @@ -2166,7 +2168,8 @@ static int __init libfc_init(void) sizeof(struct fc_fcp_pkt), 0, SLAB_HWCACHE_ALIGN, NULL); if (scsi_pkt_cachep == NULL) { - FC_DBG("Unable to allocate SRB cache...module load failed!"); + printk(KERN_ERR "libfc: Unable to allocate SRB cache, " + "module load failed!"); return -ENOMEM; } diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index e0c247724d2b..745fa5555d6a 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -101,14 +101,6 @@ #define DNS_DELAY 3 /* Discovery delay after RSCN (in seconds)*/ -static int fc_lport_debug; - -#define FC_DEBUG_LPORT(fmt...) \ - do { \ - if (fc_lport_debug) \ - FC_DBG(fmt); \ - } while (0) - static void fc_lport_error(struct fc_lport *, struct fc_frame *); static void fc_lport_enter_reset(struct fc_lport *); @@ -151,8 +143,8 @@ static void fc_lport_rport_callback(struct fc_lport *lport, struct fc_rport *rport, enum fc_rport_event event) { - FC_DEBUG_LPORT("Received a %d event for port (%6x)\n", event, - rport->port_id); + FC_LPORT_DBG(lport, "Received a %d event for port (%6x)\n", event, + rport->port_id); switch (event) { case RPORT_EV_CREATED: @@ -162,19 +154,19 @@ static void fc_lport_rport_callback(struct fc_lport *lport, lport->dns_rp = rport; fc_lport_enter_rpn_id(lport); } else { - FC_DEBUG_LPORT("Received an CREATED event on " - "port (%6x) for the directory " - "server, but the lport is not " - "in the DNS state, it's in the " - "%d state", rport->port_id, - lport->state); + FC_LPORT_DBG(lport, "Received an CREATED event " + "on port (%6x) for the directory " + "server, but the lport is not " + "in the DNS state, it's in the " + "%d state", rport->port_id, + lport->state); lport->tt.rport_logoff(rport); } mutex_unlock(&lport->lp_mutex); } else - FC_DEBUG_LPORT("Received an event for port (%6x) " - "which is not the directory server\n", - rport->port_id); + FC_LPORT_DBG(lport, "Received an event for port (%6x) " + "which is not the directory server\n", + rport->port_id); break; case RPORT_EV_LOGO: case RPORT_EV_FAILED: @@ -185,9 +177,9 @@ static void fc_lport_rport_callback(struct fc_lport *lport, mutex_unlock(&lport->lp_mutex); } else - FC_DEBUG_LPORT("Received an event for port (%6x) " - "which is not the directory server\n", - rport->port_id); + FC_LPORT_DBG(lport, "Received an event for port (%6x) " + "which is not the directory server\n", + rport->port_id); break; case RPORT_EV_NONE: break; @@ -363,8 +355,8 @@ static void fc_lport_add_fc4_type(struct fc_lport *lport, enum fc_fh_type type) static void fc_lport_recv_rlir_req(struct fc_seq *sp, struct fc_frame *fp, struct fc_lport *lport) { - FC_DEBUG_LPORT("Received RLIR request while in state %s\n", - fc_lport_state(lport)); + FC_LPORT_DBG(lport, "Received RLIR request while in state %s\n", + fc_lport_state(lport)); lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL); fc_frame_free(fp); @@ -389,8 +381,8 @@ static void fc_lport_recv_echo_req(struct fc_seq *sp, struct fc_frame *in_fp, void *dp; u32 f_ctl; - FC_DEBUG_LPORT("Received RLIR request while in state %s\n", - fc_lport_state(lport)); + FC_LPORT_DBG(lport, "Received RLIR request while in state %s\n", + fc_lport_state(lport)); len = fr_len(in_fp) - sizeof(struct fc_frame_header); pp = fc_frame_payload_get(in_fp, len); @@ -437,8 +429,8 @@ static void fc_lport_recv_rnid_req(struct fc_seq *sp, struct fc_frame *in_fp, size_t len; u32 f_ctl; - FC_DEBUG_LPORT("Received RNID request while in state %s\n", - fc_lport_state(lport)); + FC_LPORT_DBG(lport, "Received RNID request while in state %s\n", + fc_lport_state(lport)); req = fc_frame_payload_get(in_fp, sizeof(*req)); if (!req) { @@ -498,8 +490,8 @@ static void fc_lport_recv_adisc_req(struct fc_seq *sp, struct fc_frame *in_fp, size_t len; u32 f_ctl; - FC_DEBUG_LPORT("Received ADISC request while in state %s\n", - fc_lport_state(lport)); + FC_LPORT_DBG(lport, "Received ADISC request while in state %s\n", + fc_lport_state(lport)); req = fc_frame_payload_get(in_fp, sizeof(*req)); if (!req) { @@ -574,8 +566,8 @@ EXPORT_SYMBOL(fc_fabric_login); */ void fc_linkup(struct fc_lport *lport) { - FC_DEBUG_LPORT("Link is up for port (%6x)\n", - fc_host_port_id(lport->host)); + printk(KERN_INFO "libfc: Link up on port (%6x)\n", + fc_host_port_id(lport->host)); mutex_lock(&lport->lp_mutex); if (!lport->link_up) { @@ -595,8 +587,8 @@ EXPORT_SYMBOL(fc_linkup); void fc_linkdown(struct fc_lport *lport) { mutex_lock(&lport->lp_mutex); - FC_DEBUG_LPORT("Link is down for port (%6x)\n", - fc_host_port_id(lport->host)); + printk(KERN_INFO "libfc: Link down on port (%6x)\n", + fc_host_port_id(lport->host)); if (lport->link_up) { lport->link_up = 0; @@ -701,12 +693,11 @@ void fc_lport_disc_callback(struct fc_lport *lport, enum fc_disc_event event) { switch (event) { case DISC_EV_SUCCESS: - FC_DEBUG_LPORT("Got a SUCCESS event for port (%6x)\n", - fc_host_port_id(lport->host)); + FC_LPORT_DBG(lport, "Discovery succeeded\n"); break; case DISC_EV_FAILED: - FC_DEBUG_LPORT("Got a FAILED event for port (%6x)\n", - fc_host_port_id(lport->host)); + printk(KERN_ERR "libfc: Discovery failed for port (%6x)\n", + fc_host_port_id(lport->host)); mutex_lock(&lport->lp_mutex); fc_lport_enter_reset(lport); mutex_unlock(&lport->lp_mutex); @@ -726,8 +717,8 @@ void fc_lport_disc_callback(struct fc_lport *lport, enum fc_disc_event event) */ static void fc_lport_enter_ready(struct fc_lport *lport) { - FC_DEBUG_LPORT("Port (%6x) entered Ready from state %s\n", - fc_host_port_id(lport->host), fc_lport_state(lport)); + FC_LPORT_DBG(lport, "Entered READY from state %s\n", + fc_lport_state(lport)); fc_lport_state_enter(lport, LPORT_ST_READY); @@ -762,8 +753,8 @@ static void fc_lport_recv_flogi_req(struct fc_seq *sp_in, u32 local_fid; u32 f_ctl; - FC_DEBUG_LPORT("Received FLOGI request while in state %s\n", - fc_lport_state(lport)); + FC_LPORT_DBG(lport, "Received FLOGI request while in state %s\n", + fc_lport_state(lport)); fh = fc_frame_header_get(rx_fp); remote_fid = ntoh24(fh->fh_s_id); @@ -772,12 +763,11 @@ static void fc_lport_recv_flogi_req(struct fc_seq *sp_in, goto out; remote_wwpn = get_unaligned_be64(&flp->fl_wwpn); if (remote_wwpn == lport->wwpn) { - FC_DBG("FLOGI from port with same WWPN %llx " - "possible configuration error\n", - (unsigned long long)remote_wwpn); + printk(KERN_WARNING "libfc: Received FLOGI from port " + "with same WWPN %llx\n", remote_wwpn); goto out; } - FC_DBG("FLOGI from port WWPN %llx\n", (unsigned long long)remote_wwpn); + FC_LPORT_DBG(lport, "FLOGI from port WWPN %llx\n", remote_wwpn); /* * XXX what is the right thing to do for FIDs? @@ -909,7 +899,8 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp, } } } else { - FC_DBG("dropping invalid frame (eof %x)\n", fr_eof(fp)); + FC_LPORT_DBG(lport, "dropping invalid frame (eof %x)\n", + fr_eof(fp)); fc_frame_free(fp); } mutex_unlock(&lport->lp_mutex); @@ -947,8 +938,8 @@ EXPORT_SYMBOL(fc_lport_reset); */ static void fc_lport_enter_reset(struct fc_lport *lport) { - FC_DEBUG_LPORT("Port (%6x) entered RESET state from %s state\n", - fc_host_port_id(lport->host), fc_lport_state(lport)); + FC_LPORT_DBG(lport, "Entered RESET state from %s state\n", + fc_lport_state(lport)); fc_lport_state_enter(lport, LPORT_ST_RESET); @@ -982,9 +973,9 @@ static void fc_lport_enter_reset(struct fc_lport *lport) static void fc_lport_error(struct fc_lport *lport, struct fc_frame *fp) { unsigned long delay = 0; - FC_DEBUG_LPORT("Error %ld in state %s, retries %d\n", - PTR_ERR(fp), fc_lport_state(lport), - lport->retry_count); + FC_LPORT_DBG(lport, "Error %ld in state %s, retries %d\n", + PTR_ERR(fp), fc_lport_state(lport), + lport->retry_count); if (!fp || PTR_ERR(fp) == -FC_EX_TIMEOUT) { /* @@ -1040,11 +1031,11 @@ static void fc_lport_rft_id_resp(struct fc_seq *sp, struct fc_frame *fp, mutex_lock(&lport->lp_mutex); - FC_DEBUG_LPORT("Received a RFT_ID response\n"); + FC_LPORT_DBG(lport, "Received a RFT_ID response\n"); if (lport->state != LPORT_ST_RFT_ID) { - FC_DBG("Received a RFT_ID response, but in state %s\n", - fc_lport_state(lport)); + FC_LPORT_DBG(lport, "Received a RFT_ID response, but in state " + "%s\n", fc_lport_state(lport)); if (IS_ERR(fp)) goto err; goto out; @@ -1094,11 +1085,11 @@ static void fc_lport_rpn_id_resp(struct fc_seq *sp, struct fc_frame *fp, mutex_lock(&lport->lp_mutex); - FC_DEBUG_LPORT("Received a RPN_ID response\n"); + FC_LPORT_DBG(lport, "Received a RPN_ID response\n"); if (lport->state != LPORT_ST_RPN_ID) { - FC_DBG("Received a RPN_ID response, but in state %s\n", - fc_lport_state(lport)); + FC_LPORT_DBG(lport, "Received a RPN_ID response, but in state " + "%s\n", fc_lport_state(lport)); if (IS_ERR(fp)) goto err; goto out; @@ -1146,11 +1137,11 @@ static void fc_lport_scr_resp(struct fc_seq *sp, struct fc_frame *fp, mutex_lock(&lport->lp_mutex); - FC_DEBUG_LPORT("Received a SCR response\n"); + FC_LPORT_DBG(lport, "Received a SCR response\n"); if (lport->state != LPORT_ST_SCR) { - FC_DBG("Received a SCR response, but in state %s\n", - fc_lport_state(lport)); + FC_LPORT_DBG(lport, "Received a SCR response, but in state " + "%s\n", fc_lport_state(lport)); if (IS_ERR(fp)) goto err; goto out; @@ -1184,8 +1175,8 @@ static void fc_lport_enter_scr(struct fc_lport *lport) { struct fc_frame *fp; - FC_DEBUG_LPORT("Port (%6x) entered SCR state from %s state\n", - fc_host_port_id(lport->host), fc_lport_state(lport)); + FC_LPORT_DBG(lport, "Entered SCR state from %s state\n", + fc_lport_state(lport)); fc_lport_state_enter(lport, LPORT_ST_SCR); @@ -1213,8 +1204,8 @@ static void fc_lport_enter_rft_id(struct fc_lport *lport) struct fc_ns_fts *lps; int i; - FC_DEBUG_LPORT("Port (%6x) entered RFT_ID state from %s state\n", - fc_host_port_id(lport->host), fc_lport_state(lport)); + FC_LPORT_DBG(lport, "Entered RFT_ID state from %s state\n", + fc_lport_state(lport)); fc_lport_state_enter(lport, LPORT_ST_RFT_ID); @@ -1253,8 +1244,8 @@ static void fc_lport_enter_rpn_id(struct fc_lport *lport) { struct fc_frame *fp; - FC_DEBUG_LPORT("Port (%6x) entered RPN_ID state from %s state\n", - fc_host_port_id(lport->host), fc_lport_state(lport)); + FC_LPORT_DBG(lport, "Entered RPN_ID state from %s state\n", + fc_lport_state(lport)); fc_lport_state_enter(lport, LPORT_ST_RPN_ID); @@ -1294,8 +1285,8 @@ static void fc_lport_enter_dns(struct fc_lport *lport) dp.ids.roles = FC_RPORT_ROLE_UNKNOWN; dp.lp = lport; - FC_DEBUG_LPORT("Port (%6x) entered DNS state from %s state\n", - fc_host_port_id(lport->host), fc_lport_state(lport)); + FC_LPORT_DBG(lport, "Entered DNS state from %s state\n", + fc_lport_state(lport)); fc_lport_state_enter(lport, LPORT_ST_DNS); @@ -1374,11 +1365,11 @@ static void fc_lport_logo_resp(struct fc_seq *sp, struct fc_frame *fp, mutex_lock(&lport->lp_mutex); - FC_DEBUG_LPORT("Received a LOGO response\n"); + FC_LPORT_DBG(lport, "Received a LOGO response\n"); if (lport->state != LPORT_ST_LOGO) { - FC_DBG("Received a LOGO response, but in state %s\n", - fc_lport_state(lport)); + FC_LPORT_DBG(lport, "Received a LOGO response, but in state " + "%s\n", fc_lport_state(lport)); if (IS_ERR(fp)) goto err; goto out; @@ -1413,8 +1404,8 @@ static void fc_lport_enter_logo(struct fc_lport *lport) struct fc_frame *fp; struct fc_els_logo *logo; - FC_DEBUG_LPORT("Port (%6x) entered LOGO state from %s state\n", - fc_host_port_id(lport->host), fc_lport_state(lport)); + FC_LPORT_DBG(lport, "Entered LOGO state from %s state\n", + fc_lport_state(lport)); fc_lport_state_enter(lport, LPORT_ST_LOGO); @@ -1456,11 +1447,11 @@ static void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp, mutex_lock(&lport->lp_mutex); - FC_DEBUG_LPORT("Received a FLOGI response\n"); + FC_LPORT_DBG(lport, "Received a FLOGI response\n"); if (lport->state != LPORT_ST_FLOGI) { - FC_DBG("Received a FLOGI response, but in state %s\n", - fc_lport_state(lport)); + FC_LPORT_DBG(lport, "Received a FLOGI response, but in state " + "%s\n", fc_lport_state(lport)); if (IS_ERR(fp)) goto err; goto out; @@ -1475,7 +1466,8 @@ static void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp, did = ntoh24(fh->fh_d_id); if (fc_frame_payload_op(fp) == ELS_LS_ACC && did != 0) { - FC_DEBUG_LPORT("Assigned fid %x\n", did); + printk(KERN_INFO "libfc: Assigned FID (%6x) in FLOGI response\n", + did); fc_host_port_id(lport->host) = did; flp = fc_frame_payload_get(fp, sizeof(*flp)); @@ -1494,7 +1486,8 @@ static void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp, if (e_d_tov > lport->e_d_tov) lport->e_d_tov = e_d_tov; lport->r_a_tov = 2 * e_d_tov; - FC_DBG("Point-to-Point mode\n"); + printk(KERN_INFO "libfc: Port (%6x) entered " + "point to point mode\n", did); fc_lport_ptp_setup(lport, ntoh24(fh->fh_s_id), get_unaligned_be64( &flp->fl_wwpn), @@ -1517,7 +1510,7 @@ static void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp, } } } else { - FC_DBG("bad FLOGI response\n"); + FC_LPORT_DBG(lport, "Bad FLOGI response\n"); } out: @@ -1537,7 +1530,8 @@ void fc_lport_enter_flogi(struct fc_lport *lport) { struct fc_frame *fp; - FC_DEBUG_LPORT("Processing FLOGI state\n"); + FC_LPORT_DBG(lport, "Entered FLOGI state from %s state\n", + fc_lport_state(lport)); fc_lport_state_enter(lport, LPORT_ST_FLOGI); diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index 747d73c5c8af..7162385f52eb 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -55,14 +55,6 @@ #include #include -static int fc_rport_debug; - -#define FC_DEBUG_RPORT(fmt...) \ - do { \ - if (fc_rport_debug) \ - FC_DBG(fmt); \ - } while (0) - struct workqueue_struct *rport_event_queue; static void fc_rport_enter_plogi(struct fc_rport *); @@ -97,7 +89,7 @@ static const char *fc_rport_state_names[] = { static void fc_rport_rogue_destroy(struct device *dev) { struct fc_rport *rport = dev_to_rport(dev); - FC_DEBUG_RPORT("Destroying rogue rport (%6x)\n", rport->port_id); + FC_RPORT_DBG(rport, "Destroying rogue rport\n"); kfree(rport); } @@ -263,8 +255,8 @@ static void fc_rport_work(struct work_struct *work) fc_rport_state_enter(new_rport, RPORT_ST_READY); } else { - FC_DBG("Failed to create the rport for port " - "(%6x).\n", ids.port_id); + printk(KERN_WARNING "libfc: Failed to allocate " + " memory for rport (%6x)\n", ids.port_id); event = RPORT_EV_FAILED; } if (rport->port_id != FC_FID_DIR_SERV) @@ -309,7 +301,7 @@ int fc_rport_login(struct fc_rport *rport) mutex_lock(&rdata->rp_mutex); - FC_DEBUG_RPORT("Login to port (%6x)\n", rport->port_id); + FC_RPORT_DBG(rport, "Login to port\n"); fc_rport_enter_plogi(rport); @@ -329,16 +321,13 @@ int fc_rport_login(struct fc_rport *rport) int fc_rport_logoff(struct fc_rport *rport) { struct fc_rport_libfc_priv *rdata = rport->dd_data; - struct fc_lport *lport = rdata->local_port; mutex_lock(&rdata->rp_mutex); - FC_DEBUG_RPORT("Remove port (%6x)\n", rport->port_id); + FC_RPORT_DBG(rport, "Remove port\n"); if (rdata->rp_state == RPORT_ST_NONE) { - FC_DEBUG_RPORT("(%6x): Port (%6x) in NONE state," - " not removing", fc_host_port_id(lport->host), - rport->port_id); + FC_RPORT_DBG(rport, "Port in NONE state, not removing\n"); mutex_unlock(&rdata->rp_mutex); goto out; } @@ -379,7 +368,7 @@ static void fc_rport_enter_ready(struct fc_rport *rport) fc_rport_state_enter(rport, RPORT_ST_READY); - FC_DEBUG_RPORT("Port (%6x) is Ready\n", rport->port_id); + FC_RPORT_DBG(rport, "Port is Ready\n"); rdata->event = RPORT_EV_CREATED; queue_work(rport_event_queue, &rdata->event_work); @@ -436,8 +425,8 @@ static void fc_rport_error(struct fc_rport *rport, struct fc_frame *fp) { struct fc_rport_libfc_priv *rdata = rport->dd_data; - FC_DEBUG_RPORT("Error %ld in state %s, retries %d\n", - PTR_ERR(fp), fc_rport_state(rport), rdata->retries); + FC_RPORT_DBG(rport, "Error %ld in state %s, retries %d\n", + PTR_ERR(fp), fc_rport_state(rport), rdata->retries); switch (rdata->rp_state) { case RPORT_ST_PLOGI: @@ -478,9 +467,9 @@ static void fc_rport_error_retry(struct fc_rport *rport, struct fc_frame *fp) if (PTR_ERR(fp) == -FC_EX_CLOSED) return fc_rport_error(rport, fp); - if (rdata->retries < rdata->local_port->max_retry_count) { - FC_DEBUG_RPORT("Error %ld in state %s, retrying\n", - PTR_ERR(fp), fc_rport_state(rport)); + if (rdata->retries < rdata->local_port->max_rport_retry_count) { + FC_RPORT_DBG(rport, "Error %ld in state %s, retrying\n", + PTR_ERR(fp), fc_rport_state(rport)); rdata->retries++; /* no additional delay on exchange timeouts */ if (PTR_ERR(fp) == -FC_EX_TIMEOUT) @@ -517,12 +506,11 @@ static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp, mutex_lock(&rdata->rp_mutex); - FC_DEBUG_RPORT("Received a PLOGI response from port (%6x)\n", - rport->port_id); + FC_RPORT_DBG(rport, "Received a PLOGI response\n"); if (rdata->rp_state != RPORT_ST_PLOGI) { - FC_DBG("Received a PLOGI response, but in state %s\n", - fc_rport_state(rport)); + FC_RPORT_DBG(rport, "Received a PLOGI response, but in state " + "%s\n", fc_rport_state(rport)); if (IS_ERR(fp)) goto err; goto out; @@ -583,8 +571,8 @@ static void fc_rport_enter_plogi(struct fc_rport *rport) struct fc_lport *lport = rdata->local_port; struct fc_frame *fp; - FC_DEBUG_RPORT("Port (%6x) entered PLOGI state from %s state\n", - rport->port_id, fc_rport_state(rport)); + FC_RPORT_DBG(rport, "Port entered PLOGI state from %s state\n", + fc_rport_state(rport)); fc_rport_state_enter(rport, RPORT_ST_PLOGI); @@ -628,12 +616,11 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp, mutex_lock(&rdata->rp_mutex); - FC_DEBUG_RPORT("Received a PRLI response from port (%6x)\n", - rport->port_id); + FC_RPORT_DBG(rport, "Received a PRLI response\n"); if (rdata->rp_state != RPORT_ST_PRLI) { - FC_DBG("Received a PRLI response, but in state %s\n", - fc_rport_state(rport)); + FC_RPORT_DBG(rport, "Received a PRLI response, but in state " + "%s\n", fc_rport_state(rport)); if (IS_ERR(fp)) goto err; goto out; @@ -663,7 +650,7 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp, fc_rport_enter_rtv(rport); } else { - FC_DBG("Bad ELS response\n"); + FC_RPORT_DBG(rport, "Bad ELS response for PRLI command\n"); rdata->event = RPORT_EV_FAILED; fc_rport_state_enter(rport, RPORT_ST_NONE); queue_work(rport_event_queue, &rdata->event_work); @@ -695,12 +682,11 @@ static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp, mutex_lock(&rdata->rp_mutex); - FC_DEBUG_RPORT("Received a LOGO response from port (%6x)\n", - rport->port_id); + FC_RPORT_DBG(rport, "Received a LOGO response\n"); if (rdata->rp_state != RPORT_ST_LOGO) { - FC_DEBUG_RPORT("Received a LOGO response, but in state %s\n", - fc_rport_state(rport)); + FC_RPORT_DBG(rport, "Received a LOGO response, but in state " + "%s\n", fc_rport_state(rport)); if (IS_ERR(fp)) goto err; goto out; @@ -715,7 +701,7 @@ static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp, if (op == ELS_LS_ACC) { fc_rport_enter_rtv(rport); } else { - FC_DBG("Bad ELS response\n"); + FC_RPORT_DBG(rport, "Bad ELS response for LOGO command\n"); rdata->event = RPORT_EV_LOGO; fc_rport_state_enter(rport, RPORT_ST_NONE); queue_work(rport_event_queue, &rdata->event_work); @@ -745,8 +731,8 @@ static void fc_rport_enter_prli(struct fc_rport *rport) } *pp; struct fc_frame *fp; - FC_DEBUG_RPORT("Port (%6x) entered PRLI state from %s state\n", - rport->port_id, fc_rport_state(rport)); + FC_RPORT_DBG(rport, "Port entered PRLI state from %s state\n", + fc_rport_state(rport)); fc_rport_state_enter(rport, RPORT_ST_PRLI); @@ -784,12 +770,11 @@ static void fc_rport_rtv_resp(struct fc_seq *sp, struct fc_frame *fp, mutex_lock(&rdata->rp_mutex); - FC_DEBUG_RPORT("Received a RTV response from port (%6x)\n", - rport->port_id); + FC_RPORT_DBG(rport, "Received a RTV response\n"); if (rdata->rp_state != RPORT_ST_RTV) { - FC_DBG("Received a RTV response, but in state %s\n", - fc_rport_state(rport)); + FC_RPORT_DBG(rport, "Received a RTV response, but in state " + "%s\n", fc_rport_state(rport)); if (IS_ERR(fp)) goto err; goto out; @@ -844,8 +829,8 @@ static void fc_rport_enter_rtv(struct fc_rport *rport) struct fc_rport_libfc_priv *rdata = rport->dd_data; struct fc_lport *lport = rdata->local_port; - FC_DEBUG_RPORT("Port (%6x) entered RTV state from %s state\n", - rport->port_id, fc_rport_state(rport)); + FC_RPORT_DBG(rport, "Port entered RTV state from %s state\n", + fc_rport_state(rport)); fc_rport_state_enter(rport, RPORT_ST_RTV); @@ -875,8 +860,8 @@ static void fc_rport_enter_logo(struct fc_rport *rport) struct fc_lport *lport = rdata->local_port; struct fc_frame *fp; - FC_DEBUG_RPORT("Port (%6x) entered LOGO state from %s state\n", - rport->port_id, fc_rport_state(rport)); + FC_RPORT_DBG(rport, "Port entered LOGO state from %s state\n", + fc_rport_state(rport)); fc_rport_state_enter(rport, RPORT_ST_LOGO); @@ -983,14 +968,13 @@ static void fc_rport_recv_plogi_req(struct fc_rport *rport, fh = fc_frame_header_get(fp); - FC_DEBUG_RPORT("Received PLOGI request from port (%6x) " - "while in state %s\n", ntoh24(fh->fh_s_id), - fc_rport_state(rport)); + FC_RPORT_DBG(rport, "Received PLOGI request while in state %s\n", + fc_rport_state(rport)); sid = ntoh24(fh->fh_s_id); pl = fc_frame_payload_get(fp, sizeof(*pl)); if (!pl) { - FC_DBG("incoming PLOGI from %x too short\n", sid); + FC_RPORT_DBG(rport, "Received PLOGI too short\n"); WARN_ON(1); /* XXX TBD: send reject? */ fc_frame_free(fp); @@ -1012,26 +996,26 @@ static void fc_rport_recv_plogi_req(struct fc_rport *rport, */ switch (rdata->rp_state) { case RPORT_ST_INIT: - FC_DEBUG_RPORT("incoming PLOGI from %6x wwpn %llx state INIT " - "- reject\n", sid, (unsigned long long)wwpn); + FC_RPORT_DBG(rport, "Received PLOGI, wwpn %llx state INIT " + "- reject\n", (unsigned long long)wwpn); reject = ELS_RJT_UNSUP; break; case RPORT_ST_PLOGI: - FC_DEBUG_RPORT("incoming PLOGI from %x in PLOGI state %d\n", - sid, rdata->rp_state); + FC_RPORT_DBG(rport, "Received PLOGI in PLOGI state %d\n", + rdata->rp_state); if (wwpn < lport->wwpn) reject = ELS_RJT_INPROG; break; case RPORT_ST_PRLI: case RPORT_ST_READY: - FC_DEBUG_RPORT("incoming PLOGI from %x in logged-in state %d " - "- ignored for now\n", sid, rdata->rp_state); + FC_RPORT_DBG(rport, "Received PLOGI in logged-in state %d " + "- ignored for now\n", rdata->rp_state); /* XXX TBD - should reset */ break; case RPORT_ST_NONE: default: - FC_DEBUG_RPORT("incoming PLOGI from %x in unexpected " - "state %d\n", sid, rdata->rp_state); + FC_RPORT_DBG(rport, "Received PLOGI in unexpected " + "state %d\n", rdata->rp_state); fc_frame_free(fp); return; break; @@ -1115,9 +1099,8 @@ static void fc_rport_recv_prli_req(struct fc_rport *rport, fh = fc_frame_header_get(rx_fp); - FC_DEBUG_RPORT("Received PRLI request from port (%6x) " - "while in state %s\n", ntoh24(fh->fh_s_id), - fc_rport_state(rport)); + FC_RPORT_DBG(rport, "Received PRLI request while in state %s\n", + fc_rport_state(rport)); switch (rdata->rp_state) { case RPORT_ST_PRLI: @@ -1252,9 +1235,8 @@ static void fc_rport_recv_prlo_req(struct fc_rport *rport, struct fc_seq *sp, fh = fc_frame_header_get(fp); - FC_DEBUG_RPORT("Received PRLO request from port (%6x) " - "while in state %s\n", ntoh24(fh->fh_s_id), - fc_rport_state(rport)); + FC_RPORT_DBG(rport, "Received PRLO request while in state %s\n", + fc_rport_state(rport)); if (rdata->rp_state == RPORT_ST_NONE) { fc_frame_free(fp); @@ -1286,9 +1268,8 @@ static void fc_rport_recv_logo_req(struct fc_rport *rport, struct fc_seq *sp, fh = fc_frame_header_get(fp); - FC_DEBUG_RPORT("Received LOGO request from port (%6x) " - "while in state %s\n", ntoh24(fh->fh_s_id), - fc_rport_state(rport)); + FC_RPORT_DBG(rport, "Received LOGO request while in state %s\n", + fc_rport_state(rport)); if (rdata->rp_state == RPORT_ST_NONE) { fc_frame_free(fp); @@ -1308,7 +1289,6 @@ static void fc_rport_flush_queue(void) flush_workqueue(rport_event_queue); } - int fc_rport_init(struct fc_lport *lport) { if (!lport->tt.rport_create) @@ -1330,7 +1310,7 @@ int fc_rport_init(struct fc_lport *lport) } EXPORT_SYMBOL(fc_rport_init); -int fc_setup_rport() +int fc_setup_rport(void) { rport_event_queue = create_singlethread_workqueue("fc_rport_eq"); if (!rport_event_queue) @@ -1339,7 +1319,7 @@ int fc_setup_rport() } EXPORT_SYMBOL(fc_setup_rport); -void fc_destroy_rport() +void fc_destroy_rport(void) { destroy_workqueue(rport_event_queue); } diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index e72b4ad47d35..716cc344c5df 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -38,15 +38,30 @@ #include #include -static int iscsi_dbg_lib; -module_param_named(debug_libiscsi, iscsi_dbg_lib, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug_libiscsi, "Turn on debugging for libiscsi module. " - "Set to 1 to turn on, and zero to turn off. Default " - "is off."); +static int iscsi_dbg_lib_conn; +module_param_named(debug_libiscsi_conn, iscsi_dbg_lib_conn, int, + S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug_libiscsi_conn, + "Turn on debugging for connections in libiscsi module. " + "Set to 1 to turn on, and zero to turn off. Default is off."); + +static int iscsi_dbg_lib_session; +module_param_named(debug_libiscsi_session, iscsi_dbg_lib_session, int, + S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug_libiscsi_session, + "Turn on debugging for sessions in libiscsi module. " + "Set to 1 to turn on, and zero to turn off. Default is off."); + +static int iscsi_dbg_lib_eh; +module_param_named(debug_libiscsi_eh, iscsi_dbg_lib_eh, int, + S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug_libiscsi_eh, + "Turn on debugging for error handling in libiscsi module. " + "Set to 1 to turn on, and zero to turn off. Default is off."); #define ISCSI_DBG_CONN(_conn, dbg_fmt, arg...) \ do { \ - if (iscsi_dbg_lib) \ + if (iscsi_dbg_lib_conn) \ iscsi_conn_printk(KERN_INFO, _conn, \ "%s " dbg_fmt, \ __func__, ##arg); \ @@ -54,7 +69,15 @@ MODULE_PARM_DESC(debug_libiscsi, "Turn on debugging for libiscsi module. " #define ISCSI_DBG_SESSION(_session, dbg_fmt, arg...) \ do { \ - if (iscsi_dbg_lib) \ + if (iscsi_dbg_lib_session) \ + iscsi_session_printk(KERN_INFO, _session, \ + "%s " dbg_fmt, \ + __func__, ##arg); \ + } while (0); + +#define ISCSI_DBG_EH(_session, dbg_fmt, arg...) \ + do { \ + if (iscsi_dbg_lib_eh) \ iscsi_session_printk(KERN_INFO, _session, \ "%s " dbg_fmt, \ __func__, ##arg); \ @@ -81,7 +104,8 @@ inline void iscsi_conn_queue_work(struct iscsi_conn *conn) struct Scsi_Host *shost = conn->session->host; struct iscsi_host *ihost = shost_priv(shost); - queue_work(ihost->workq, &conn->xmitwork); + if (ihost->workq) + queue_work(ihost->workq, &conn->xmitwork); } EXPORT_SYMBOL_GPL(iscsi_conn_queue_work); @@ -109,11 +133,9 @@ iscsi_update_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr) * if the window closed with IO queued, then kick the * xmit thread */ - if (!list_empty(&session->leadconn->xmitqueue) || - !list_empty(&session->leadconn->mgmtqueue)) { - if (!(session->tt->caps & CAP_DATA_PATH_OFFLOAD)) - iscsi_conn_queue_work(session->leadconn); - } + if (!list_empty(&session->leadconn->cmdqueue) || + !list_empty(&session->leadconn->mgmtqueue)) + iscsi_conn_queue_work(session->leadconn); } } EXPORT_SYMBOL_GPL(iscsi_update_cmdsn); @@ -257,9 +279,11 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task) itt_t itt; int rc; - rc = conn->session->tt->alloc_pdu(task, ISCSI_OP_SCSI_CMD); - if (rc) - return rc; + if (conn->session->tt->alloc_pdu) { + rc = conn->session->tt->alloc_pdu(task, ISCSI_OP_SCSI_CMD); + if (rc) + return rc; + } hdr = (struct iscsi_cmd *) task->hdr; itt = hdr->itt; memset(hdr, 0, sizeof(*hdr)); @@ -364,7 +388,6 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task) return -EIO; task->state = ISCSI_TASK_RUNNING; - list_move_tail(&task->running, &conn->run_list); conn->scsicmd_pdus_cnt++; ISCSI_DBG_SESSION(session, "iscsi prep [%s cid %d sc %p cdb 0x%x " @@ -380,26 +403,25 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task) } /** - * iscsi_complete_command - finish a task + * iscsi_free_task - free a task * @task: iscsi cmd task * * Must be called with session lock. * This function returns the scsi command to scsi-ml or cleans * up mgmt tasks then returns the task to the pool. */ -static void iscsi_complete_command(struct iscsi_task *task) +static void iscsi_free_task(struct iscsi_task *task) { struct iscsi_conn *conn = task->conn; struct iscsi_session *session = conn->session; struct scsi_cmnd *sc = task->sc; - session->tt->cleanup_task(task); - list_del_init(&task->running); - task->state = ISCSI_TASK_COMPLETED; - task->sc = NULL; + ISCSI_DBG_SESSION(session, "freeing task itt 0x%x state %d sc %p\n", + task->itt, task->state, task->sc); - if (conn->task == task) - conn->task = NULL; + session->tt->cleanup_task(task); + task->state = ISCSI_TASK_FREE; + task->sc = NULL; /* * login task is preallocated so do not free */ @@ -408,9 +430,6 @@ static void iscsi_complete_command(struct iscsi_task *task) __kfifo_put(session->cmdpool.queue, (void*)&task, sizeof(void*)); - if (conn->ping_task == task) - conn->ping_task = NULL; - if (sc) { task->sc = NULL; /* SCSI eh reuses commands to verify us */ @@ -433,7 +452,7 @@ EXPORT_SYMBOL_GPL(__iscsi_get_task); static void __iscsi_put_task(struct iscsi_task *task) { if (atomic_dec_and_test(&task->refcount)) - iscsi_complete_command(task); + iscsi_free_task(task); } void iscsi_put_task(struct iscsi_task *task) @@ -446,26 +465,74 @@ void iscsi_put_task(struct iscsi_task *task) } EXPORT_SYMBOL_GPL(iscsi_put_task); -/* - * session lock must be held +/** + * iscsi_complete_task - finish a task + * @task: iscsi cmd task + * @state: state to complete task with + * + * Must be called with session lock. */ -static void fail_command(struct iscsi_conn *conn, struct iscsi_task *task, - int err) +static void iscsi_complete_task(struct iscsi_task *task, int state) { - struct scsi_cmnd *sc; + struct iscsi_conn *conn = task->conn; + ISCSI_DBG_SESSION(conn->session, + "complete task itt 0x%x state %d sc %p\n", + task->itt, task->state, task->sc); + if (task->state == ISCSI_TASK_COMPLETED || + task->state == ISCSI_TASK_ABRT_TMF || + task->state == ISCSI_TASK_ABRT_SESS_RECOV) + return; + WARN_ON_ONCE(task->state == ISCSI_TASK_FREE); + task->state = state; + + if (!list_empty(&task->running)) + list_del_init(&task->running); + + if (conn->task == task) + conn->task = NULL; + + if (conn->ping_task == task) + conn->ping_task = NULL; + + /* release get from queueing */ + __iscsi_put_task(task); +} + +/* + * session lock must be held and if not called for a task that is + * still pending or from the xmit thread, then xmit thread must + * be suspended. + */ +static void fail_scsi_task(struct iscsi_task *task, int err) +{ + struct iscsi_conn *conn = task->conn; + struct scsi_cmnd *sc; + int state; + + /* + * if a command completes and we get a successful tmf response + * we will hit this because the scsi eh abort code does not take + * a ref to the task. + */ sc = task->sc; if (!sc) return; - if (task->state == ISCSI_TASK_PENDING) + if (task->state == ISCSI_TASK_PENDING) { /* * cmd never made it to the xmit thread, so we should not count * the cmd in the sequencing */ conn->session->queued_cmdsn--; + /* it was never sent so just complete like normal */ + state = ISCSI_TASK_COMPLETED; + } else if (err == DID_TRANSPORT_DISRUPTED) + state = ISCSI_TASK_ABRT_SESS_RECOV; + else + state = ISCSI_TASK_ABRT_TMF; - sc->result = err; + sc->result = err << 16; if (!scsi_bidi_cmnd(sc)) scsi_set_resid(sc, scsi_bufflen(sc)); else { @@ -473,10 +540,7 @@ static void fail_command(struct iscsi_conn *conn, struct iscsi_task *task, scsi_in(sc)->resid = scsi_in(sc)->length; } - if (conn->task == task) - conn->task = NULL; - /* release ref from queuecommand */ - __iscsi_put_task(task); + iscsi_complete_task(task, state); } static int iscsi_prep_mgmt_task(struct iscsi_conn *conn, @@ -516,7 +580,6 @@ static int iscsi_prep_mgmt_task(struct iscsi_conn *conn, session->state = ISCSI_STATE_LOGGING_OUT; task->state = ISCSI_TASK_RUNNING; - list_move_tail(&task->running, &conn->mgmt_run_list); ISCSI_DBG_SESSION(session, "mgmtpdu [op 0x%x hdr->itt 0x%x " "datalen %d]\n", hdr->opcode & ISCSI_OPCODE_MASK, hdr->itt, task->data_count); @@ -528,6 +591,7 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, char *data, uint32_t data_size) { struct iscsi_session *session = conn->session; + struct iscsi_host *ihost = shost_priv(session->host); struct iscsi_task *task; itt_t itt; @@ -544,6 +608,9 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, */ task = conn->login_task; else { + if (session->state != ISCSI_STATE_LOGGED_IN) + return NULL; + BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE); BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED); @@ -559,6 +626,8 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, atomic_set(&task->refcount, 1); task->conn = conn; task->sc = NULL; + INIT_LIST_HEAD(&task->running); + task->state = ISCSI_TASK_PENDING; if (data_size) { memcpy(task->data, data, data_size); @@ -566,11 +635,14 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, } else task->data_count = 0; - if (conn->session->tt->alloc_pdu(task, hdr->opcode)) { - iscsi_conn_printk(KERN_ERR, conn, "Could not allocate " - "pdu for mgmt task.\n"); - goto requeue_task; + if (conn->session->tt->alloc_pdu) { + if (conn->session->tt->alloc_pdu(task, hdr->opcode)) { + iscsi_conn_printk(KERN_ERR, conn, "Could not allocate " + "pdu for mgmt task.\n"); + goto free_task; + } } + itt = task->hdr->itt; task->hdr_len = sizeof(struct iscsi_hdr); memcpy(task->hdr, hdr, sizeof(struct iscsi_hdr)); @@ -583,30 +655,22 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, task->conn->session->age); } - INIT_LIST_HEAD(&task->running); - list_add_tail(&task->running, &conn->mgmtqueue); - - if (session->tt->caps & CAP_DATA_PATH_OFFLOAD) { + if (!ihost->workq) { if (iscsi_prep_mgmt_task(conn, task)) goto free_task; if (session->tt->xmit_task(task)) goto free_task; - - } else + } else { + list_add_tail(&task->running, &conn->mgmtqueue); iscsi_conn_queue_work(conn); + } return task; free_task: __iscsi_put_task(task); return NULL; - -requeue_task: - if (task != conn->login_task) - __kfifo_put(session->cmdpool.queue, (void*)&task, - sizeof(void*)); - return NULL; } int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr, @@ -701,11 +765,10 @@ invalid_datalen: sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status; } out: - ISCSI_DBG_SESSION(session, "done [sc %p res %d itt 0x%x]\n", + ISCSI_DBG_SESSION(session, "cmd rsp done [sc %p res %d itt 0x%x]\n", sc, sc->result, task->itt); conn->scsirsp_pdus_cnt++; - - __iscsi_put_task(task); + iscsi_complete_task(task, ISCSI_TASK_COMPLETED); } /** @@ -724,6 +787,7 @@ iscsi_data_in_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr, if (!(rhdr->flags & ISCSI_FLAG_DATA_STATUS)) return; + iscsi_update_cmdsn(conn->session, (struct iscsi_nopin *)hdr); sc->result = (DID_OK << 16) | rhdr->cmd_status; conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1; if (rhdr->flags & (ISCSI_FLAG_DATA_UNDERFLOW | @@ -738,8 +802,11 @@ iscsi_data_in_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr, sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status; } + ISCSI_DBG_SESSION(conn->session, "data in with status done " + "[sc %p res %d itt 0x%x]\n", + sc, sc->result, task->itt); conn->scsirsp_pdus_cnt++; - __iscsi_put_task(task); + iscsi_complete_task(task, ISCSI_TASK_COMPLETED); } static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr) @@ -823,7 +890,7 @@ static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr, * * The session lock must be held. */ -static struct iscsi_task *iscsi_itt_to_task(struct iscsi_conn *conn, itt_t itt) +struct iscsi_task *iscsi_itt_to_task(struct iscsi_conn *conn, itt_t itt) { struct iscsi_session *session = conn->session; int i; @@ -840,6 +907,7 @@ static struct iscsi_task *iscsi_itt_to_task(struct iscsi_conn *conn, itt_t itt) return session->cmds[i]; } +EXPORT_SYMBOL_GPL(iscsi_itt_to_task); /** * __iscsi_complete_pdu - complete pdu @@ -909,6 +977,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, task = iscsi_itt_to_ctask(conn, hdr->itt); if (!task) return ISCSI_ERR_BAD_ITT; + task->last_xfer = jiffies; break; case ISCSI_OP_R2T: /* @@ -959,7 +1028,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, } iscsi_tmf_rsp(conn, hdr); - __iscsi_put_task(task); + iscsi_complete_task(task, ISCSI_TASK_COMPLETED); break; case ISCSI_OP_NOOP_IN: iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr); @@ -977,7 +1046,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, goto recv_pdu; mod_timer(&conn->transport_timer, jiffies + conn->recv_timeout); - __iscsi_put_task(task); + iscsi_complete_task(task, ISCSI_TASK_COMPLETED); break; default: rc = ISCSI_ERR_BAD_OPCODE; @@ -989,7 +1058,7 @@ out: recv_pdu: if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen)) rc = ISCSI_ERR_CONN_FAILED; - __iscsi_put_task(task); + iscsi_complete_task(task, ISCSI_TASK_COMPLETED); return rc; } EXPORT_SYMBOL_GPL(__iscsi_complete_pdu); @@ -1147,10 +1216,12 @@ static int iscsi_xmit_task(struct iscsi_conn *conn) spin_unlock_bh(&conn->session->lock); rc = conn->session->tt->xmit_task(task); spin_lock_bh(&conn->session->lock); - __iscsi_put_task(task); - if (!rc) + if (!rc) { /* done with this task */ + task->last_xfer = jiffies; conn->task = NULL; + } + __iscsi_put_task(task); return rc; } @@ -1166,7 +1237,12 @@ void iscsi_requeue_task(struct iscsi_task *task) { struct iscsi_conn *conn = task->conn; - list_move_tail(&task->running, &conn->requeue); + /* + * this may be on the requeue list already if the xmit_task callout + * is handling the r2ts while we are adding new ones + */ + if (list_empty(&task->running)) + list_add_tail(&task->running, &conn->requeue); iscsi_conn_queue_work(conn); } EXPORT_SYMBOL_GPL(iscsi_requeue_task); @@ -1206,6 +1282,7 @@ check_mgmt: while (!list_empty(&conn->mgmtqueue)) { conn->task = list_entry(conn->mgmtqueue.next, struct iscsi_task, running); + list_del_init(&conn->task->running); if (iscsi_prep_mgmt_task(conn, conn->task)) { __iscsi_put_task(conn->task); conn->task = NULL; @@ -1217,23 +1294,26 @@ check_mgmt: } /* process pending command queue */ - while (!list_empty(&conn->xmitqueue)) { + while (!list_empty(&conn->cmdqueue)) { if (conn->tmf_state == TMF_QUEUED) break; - conn->task = list_entry(conn->xmitqueue.next, + conn->task = list_entry(conn->cmdqueue.next, struct iscsi_task, running); + list_del_init(&conn->task->running); if (conn->session->state == ISCSI_STATE_LOGGING_OUT) { - fail_command(conn, conn->task, DID_IMM_RETRY << 16); + fail_scsi_task(conn->task, DID_IMM_RETRY); continue; } rc = iscsi_prep_scsi_cmd_pdu(conn->task); if (rc) { if (rc == -ENOMEM) { + list_add_tail(&conn->task->running, + &conn->cmdqueue); conn->task = NULL; goto again; } else - fail_command(conn, conn->task, DID_ABORT << 16); + fail_scsi_task(conn->task, DID_ABORT); continue; } rc = iscsi_xmit_task(conn); @@ -1260,8 +1340,8 @@ check_mgmt: conn->task = list_entry(conn->requeue.next, struct iscsi_task, running); + list_del_init(&conn->task->running); conn->task->state = ISCSI_TASK_RUNNING; - list_move_tail(conn->requeue.next, &conn->run_list); rc = iscsi_xmit_task(conn); if (rc) goto again; @@ -1307,6 +1387,9 @@ static inline struct iscsi_task *iscsi_alloc_task(struct iscsi_conn *conn, task->state = ISCSI_TASK_PENDING; task->conn = conn; task->sc = sc; + task->have_checked_conn = false; + task->last_timeout = jiffies; + task->last_xfer = jiffies; INIT_LIST_HEAD(&task->running); return task; } @@ -1328,6 +1411,7 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) { struct iscsi_cls_session *cls_session; struct Scsi_Host *host; + struct iscsi_host *ihost; int reason = 0; struct iscsi_session *session; struct iscsi_conn *conn; @@ -1338,6 +1422,7 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) sc->SCp.ptr = NULL; host = sc->device->host; + ihost = shost_priv(host); spin_unlock(host->host_lock); cls_session = starget_to_session(scsi_target(sc->device)); @@ -1350,13 +1435,7 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) goto fault; } - /* - * ISCSI_STATE_FAILED is a temp. state. The recovery - * code will decide what is best to do with command queued - * during this time - */ - if (session->state != ISCSI_STATE_LOGGED_IN && - session->state != ISCSI_STATE_FAILED) { + if (session->state != ISCSI_STATE_LOGGED_IN) { /* * to handle the race between when we set the recovery state * and block the session we requeue here (commands could @@ -1364,12 +1443,15 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) * up because the block code is not locked) */ switch (session->state) { + case ISCSI_STATE_FAILED: case ISCSI_STATE_IN_RECOVERY: reason = FAILURE_SESSION_IN_RECOVERY; - goto reject; + sc->result = DID_IMM_RETRY << 16; + break; case ISCSI_STATE_LOGGING_OUT: reason = FAILURE_SESSION_LOGGING_OUT; - goto reject; + sc->result = DID_IMM_RETRY << 16; + break; case ISCSI_STATE_RECOVERY_FAILED: reason = FAILURE_SESSION_RECOVERY_TIMEOUT; sc->result = DID_TRANSPORT_FAILFAST << 16; @@ -1402,9 +1484,8 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) reason = FAILURE_OOM; goto reject; } - list_add_tail(&task->running, &conn->xmitqueue); - if (session->tt->caps & CAP_DATA_PATH_OFFLOAD) { + if (!ihost->workq) { reason = iscsi_prep_scsi_cmd_pdu(task); if (reason) { if (reason == -ENOMEM) { @@ -1419,8 +1500,10 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) reason = FAILURE_SESSION_NOT_READY; goto prepd_reject; } - } else + } else { + list_add_tail(&task->running, &conn->cmdqueue); iscsi_conn_queue_work(conn); + } session->queued_cmdsn++; spin_unlock(&session->lock); @@ -1429,7 +1512,7 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) prepd_reject: sc->scsi_done = NULL; - iscsi_complete_command(task); + iscsi_complete_task(task, ISCSI_TASK_COMPLETED); reject: spin_unlock(&session->lock); ISCSI_DBG_SESSION(session, "cmd 0x%x rejected (%d)\n", @@ -1439,7 +1522,7 @@ reject: prepd_fault: sc->scsi_done = NULL; - iscsi_complete_command(task); + iscsi_complete_task(task, ISCSI_TASK_COMPLETED); fault: spin_unlock(&session->lock); ISCSI_DBG_SESSION(session, "iscsi: cmd 0x%x is not queued (%d)\n", @@ -1501,10 +1584,10 @@ int iscsi_eh_target_reset(struct scsi_cmnd *sc) spin_lock_bh(&session->lock); if (session->state == ISCSI_STATE_TERMINATE) { failed: - iscsi_session_printk(KERN_INFO, session, - "failing target reset: Could not log " - "back into target [age %d]\n", - session->age); + ISCSI_DBG_EH(session, + "failing target reset: Could not log back into " + "target [age %d]\n", + session->age); spin_unlock_bh(&session->lock); mutex_unlock(&session->eh_mutex); return FAILED; @@ -1518,7 +1601,7 @@ failed: */ iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); - ISCSI_DBG_SESSION(session, "wait for relogin\n"); + ISCSI_DBG_EH(session, "wait for relogin\n"); wait_event_interruptible(conn->ehwait, session->state == ISCSI_STATE_TERMINATE || session->state == ISCSI_STATE_LOGGED_IN || @@ -1528,10 +1611,10 @@ failed: mutex_lock(&session->eh_mutex); spin_lock_bh(&session->lock); - if (session->state == ISCSI_STATE_LOGGED_IN) - iscsi_session_printk(KERN_INFO, session, - "target reset succeeded\n"); - else + if (session->state == ISCSI_STATE_LOGGED_IN) { + ISCSI_DBG_EH(session, + "target reset succeeded\n"); + } else goto failed; spin_unlock_bh(&session->lock); mutex_unlock(&session->eh_mutex); @@ -1547,7 +1630,7 @@ static void iscsi_tmf_timedout(unsigned long data) spin_lock(&session->lock); if (conn->tmf_state == TMF_QUEUED) { conn->tmf_state = TMF_TIMEDOUT; - ISCSI_DBG_SESSION(session, "tmf timedout\n"); + ISCSI_DBG_EH(session, "tmf timedout\n"); /* unblock eh_abort() */ wake_up(&conn->ehwait); } @@ -1567,7 +1650,7 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn, spin_unlock_bh(&session->lock); iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); spin_lock_bh(&session->lock); - ISCSI_DBG_SESSION(session, "tmf exec failure\n"); + ISCSI_DBG_EH(session, "tmf exec failure\n"); return -EPERM; } conn->tmfcmd_pdus_cnt++; @@ -1575,7 +1658,7 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn, conn->tmf_timer.function = iscsi_tmf_timedout; conn->tmf_timer.data = (unsigned long)conn; add_timer(&conn->tmf_timer); - ISCSI_DBG_SESSION(session, "tmf set timeout\n"); + ISCSI_DBG_EH(session, "tmf set timeout\n"); spin_unlock_bh(&session->lock); mutex_unlock(&session->eh_mutex); @@ -1608,44 +1691,24 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn, * Fail commands. session lock held and recv side suspended and xmit * thread flushed */ -static void fail_all_commands(struct iscsi_conn *conn, unsigned lun, - int error) +static void fail_scsi_tasks(struct iscsi_conn *conn, unsigned lun, + int error) { - struct iscsi_task *task, *tmp; + struct iscsi_task *task; + int i; - if (conn->task) { - if (lun == -1 || - (conn->task->sc && conn->task->sc->device->lun == lun)) - conn->task = NULL; - } + for (i = 0; i < conn->session->cmds_max; i++) { + task = conn->session->cmds[i]; + if (!task->sc || task->state == ISCSI_TASK_FREE) + continue; - /* flush pending */ - list_for_each_entry_safe(task, tmp, &conn->xmitqueue, running) { - if (lun == task->sc->device->lun || lun == -1) { - ISCSI_DBG_SESSION(conn->session, - "failing pending sc %p itt 0x%x\n", - task->sc, task->itt); - fail_command(conn, task, error << 16); - } - } + if (lun != -1 && lun != task->sc->device->lun) + continue; - list_for_each_entry_safe(task, tmp, &conn->requeue, running) { - if (lun == task->sc->device->lun || lun == -1) { - ISCSI_DBG_SESSION(conn->session, - "failing requeued sc %p itt 0x%x\n", - task->sc, task->itt); - fail_command(conn, task, error << 16); - } - } - - /* fail all other running */ - list_for_each_entry_safe(task, tmp, &conn->run_list, running) { - if (lun == task->sc->device->lun || lun == -1) { - ISCSI_DBG_SESSION(conn->session, - "failing in progress sc %p itt 0x%x\n", - task->sc, task->itt); - fail_command(conn, task, error << 16); - } + ISCSI_DBG_SESSION(conn->session, + "failing sc %p itt 0x%x state %d\n", + task->sc, task->itt, task->state); + fail_scsi_task(task, error); } } @@ -1655,7 +1718,7 @@ void iscsi_suspend_tx(struct iscsi_conn *conn) struct iscsi_host *ihost = shost_priv(shost); set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); - if (!(conn->session->tt->caps & CAP_DATA_PATH_OFFLOAD)) + if (ihost->workq) flush_workqueue(ihost->workq); } EXPORT_SYMBOL_GPL(iscsi_suspend_tx); @@ -1663,21 +1726,37 @@ EXPORT_SYMBOL_GPL(iscsi_suspend_tx); static void iscsi_start_tx(struct iscsi_conn *conn) { clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); - if (!(conn->session->tt->caps & CAP_DATA_PATH_OFFLOAD)) - iscsi_conn_queue_work(conn); + iscsi_conn_queue_work(conn); } -static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *scmd) +/* + * We want to make sure a ping is in flight. It has timed out. + * And we are not busy processing a pdu that is making + * progress but got started before the ping and is taking a while + * to complete so the ping is just stuck behind it in a queue. + */ +static int iscsi_has_ping_timed_out(struct iscsi_conn *conn) { + if (conn->ping_task && + time_before_eq(conn->last_recv + (conn->recv_timeout * HZ) + + (conn->ping_timeout * HZ), jiffies)) + return 1; + else + return 0; +} + +static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc) +{ + enum blk_eh_timer_return rc = BLK_EH_NOT_HANDLED; + struct iscsi_task *task = NULL; struct iscsi_cls_session *cls_session; struct iscsi_session *session; struct iscsi_conn *conn; - enum blk_eh_timer_return rc = BLK_EH_NOT_HANDLED; - cls_session = starget_to_session(scsi_target(scmd->device)); + cls_session = starget_to_session(scsi_target(sc->device)); session = cls_session->dd_data; - ISCSI_DBG_SESSION(session, "scsi cmd %p timedout\n", scmd); + ISCSI_DBG_EH(session, "scsi cmd %p timedout\n", sc); spin_lock(&session->lock); if (session->state != ISCSI_STATE_LOGGED_IN) { @@ -1696,29 +1775,62 @@ static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *scmd) goto done; } + task = (struct iscsi_task *)sc->SCp.ptr; + if (!task) + goto done; + /* + * If we have sent (at least queued to the network layer) a pdu or + * recvd one for the task since the last timeout ask for + * more time. If on the next timeout we have not made progress + * we can check if it is the task or connection when we send the + * nop as a ping. + */ + if (time_after_eq(task->last_xfer, task->last_timeout)) { + ISCSI_DBG_EH(session, "Command making progress. Asking " + "scsi-ml for more time to complete. " + "Last data recv at %lu. Last timeout was at " + "%lu\n.", task->last_xfer, task->last_timeout); + task->have_checked_conn = false; + rc = BLK_EH_RESET_TIMER; + goto done; + } + if (!conn->recv_timeout && !conn->ping_timeout) goto done; /* * if the ping timedout then we are in the middle of cleaning up * and can let the iscsi eh handle it */ - if (time_before_eq(conn->last_recv + (conn->recv_timeout * HZ) + - (conn->ping_timeout * HZ), jiffies)) + if (iscsi_has_ping_timed_out(conn)) { rc = BLK_EH_RESET_TIMER; + goto done; + } + + /* Assumes nop timeout is shorter than scsi cmd timeout */ + if (task->have_checked_conn) + goto done; + /* - * if we are about to check the transport then give the command - * more time + * Checking the transport already or nop from a cmd timeout still + * running */ - if (time_before_eq(conn->last_recv + (conn->recv_timeout * HZ), - jiffies)) - rc = BLK_EH_RESET_TIMER; - /* if in the middle of checking the transport then give us more time */ - if (conn->ping_task) + if (conn->ping_task) { + task->have_checked_conn = true; rc = BLK_EH_RESET_TIMER; + goto done; + } + + /* Make sure there is a transport check done */ + iscsi_send_nopout(conn, NULL); + task->have_checked_conn = true; + rc = BLK_EH_RESET_TIMER; + done: + if (task) + task->last_timeout = jiffies; spin_unlock(&session->lock); - ISCSI_DBG_SESSION(session, "return %s\n", rc == BLK_EH_RESET_TIMER ? - "timer reset" : "nh"); + ISCSI_DBG_EH(session, "return %s\n", rc == BLK_EH_RESET_TIMER ? + "timer reset" : "nh"); return rc; } @@ -1738,13 +1850,13 @@ static void iscsi_check_transport_timeouts(unsigned long data) recv_timeout *= HZ; last_recv = conn->last_recv; - if (conn->ping_task && - time_before_eq(conn->last_ping + (conn->ping_timeout * HZ), - jiffies)) { + + if (iscsi_has_ping_timed_out(conn)) { iscsi_conn_printk(KERN_ERR, conn, "ping timeout of %d secs " - "expired, last rx %lu, last ping %lu, " - "now %lu\n", conn->ping_timeout, last_recv, - conn->last_ping, jiffies); + "expired, recv timeout %d, last rx %lu, " + "last ping %lu, now %lu\n", + conn->ping_timeout, conn->recv_timeout, + last_recv, conn->last_ping, jiffies); spin_unlock(&session->lock); iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); return; @@ -1788,6 +1900,8 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) cls_session = starget_to_session(scsi_target(sc->device)); session = cls_session->dd_data; + ISCSI_DBG_EH(session, "aborting sc %p\n", sc); + mutex_lock(&session->eh_mutex); spin_lock_bh(&session->lock); /* @@ -1795,8 +1909,8 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) * got the command. */ if (!sc->SCp.ptr) { - ISCSI_DBG_SESSION(session, "sc never reached iscsi layer or " - "it completed.\n"); + ISCSI_DBG_EH(session, "sc never reached iscsi layer or " + "it completed.\n"); spin_unlock_bh(&session->lock); mutex_unlock(&session->eh_mutex); return SUCCESS; @@ -1810,6 +1924,8 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) sc->SCp.phase != session->age) { spin_unlock_bh(&session->lock); mutex_unlock(&session->eh_mutex); + ISCSI_DBG_EH(session, "failing abort due to dropped " + "session.\n"); return FAILED; } @@ -1818,18 +1934,17 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) age = session->age; task = (struct iscsi_task *)sc->SCp.ptr; - ISCSI_DBG_SESSION(session, "aborting [sc %p itt 0x%x]\n", - sc, task->itt); + ISCSI_DBG_EH(session, "aborting [sc %p itt 0x%x]\n", + sc, task->itt); /* task completed before time out */ if (!task->sc) { - ISCSI_DBG_SESSION(session, "sc completed while abort in " - "progress\n"); + ISCSI_DBG_EH(session, "sc completed while abort in progress\n"); goto success; } if (task->state == ISCSI_TASK_PENDING) { - fail_command(conn, task, DID_ABORT << 16); + fail_scsi_task(task, DID_ABORT); goto success; } @@ -1860,7 +1975,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) * then sent more data for the cmd. */ spin_lock(&session->lock); - fail_command(conn, task, DID_ABORT << 16); + fail_scsi_task(task, DID_ABORT); conn->tmf_state = TMF_INITIAL; spin_unlock(&session->lock); iscsi_start_tx(conn); @@ -1873,8 +1988,8 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) if (!sc->SCp.ptr) { conn->tmf_state = TMF_INITIAL; /* task completed before tmf abort response */ - ISCSI_DBG_SESSION(session, "sc completed while abort " - "in progress\n"); + ISCSI_DBG_EH(session, "sc completed while abort in " + "progress\n"); goto success; } /* fall through */ @@ -1886,16 +2001,16 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) success: spin_unlock_bh(&session->lock); success_unlocked: - ISCSI_DBG_SESSION(session, "abort success [sc %p itt 0x%x]\n", - sc, task->itt); + ISCSI_DBG_EH(session, "abort success [sc %p itt 0x%x]\n", + sc, task->itt); mutex_unlock(&session->eh_mutex); return SUCCESS; failed: spin_unlock_bh(&session->lock); failed_unlocked: - ISCSI_DBG_SESSION(session, "abort failed [sc %p itt 0x%x]\n", sc, - task ? task->itt : 0); + ISCSI_DBG_EH(session, "abort failed [sc %p itt 0x%x]\n", sc, + task ? task->itt : 0); mutex_unlock(&session->eh_mutex); return FAILED; } @@ -1922,8 +2037,7 @@ int iscsi_eh_device_reset(struct scsi_cmnd *sc) cls_session = starget_to_session(scsi_target(sc->device)); session = cls_session->dd_data; - ISCSI_DBG_SESSION(session, "LU Reset [sc %p lun %u]\n", - sc, sc->device->lun); + ISCSI_DBG_EH(session, "LU Reset [sc %p lun %u]\n", sc, sc->device->lun); mutex_lock(&session->eh_mutex); spin_lock_bh(&session->lock); @@ -1967,7 +2081,7 @@ int iscsi_eh_device_reset(struct scsi_cmnd *sc) iscsi_suspend_tx(conn); spin_lock_bh(&session->lock); - fail_all_commands(conn, sc->device->lun, DID_ERROR); + fail_scsi_tasks(conn, sc->device->lun, DID_ERROR); conn->tmf_state = TMF_INITIAL; spin_unlock_bh(&session->lock); @@ -1977,8 +2091,8 @@ int iscsi_eh_device_reset(struct scsi_cmnd *sc) unlock: spin_unlock_bh(&session->lock); done: - ISCSI_DBG_SESSION(session, "dev reset result = %s\n", - rc == SUCCESS ? "SUCCESS" : "FAILED"); + ISCSI_DBG_EH(session, "dev reset result = %s\n", + rc == SUCCESS ? "SUCCESS" : "FAILED"); mutex_unlock(&session->eh_mutex); return rc; } @@ -2274,6 +2388,7 @@ iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost, if (cmd_task_size) task->dd_data = &task[1]; task->itt = cmd_i; + task->state = ISCSI_TASK_FREE; INIT_LIST_HEAD(&task->running); } @@ -2360,10 +2475,8 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size, conn->transport_timer.data = (unsigned long)conn; conn->transport_timer.function = iscsi_check_transport_timeouts; - INIT_LIST_HEAD(&conn->run_list); - INIT_LIST_HEAD(&conn->mgmt_run_list); INIT_LIST_HEAD(&conn->mgmtqueue); - INIT_LIST_HEAD(&conn->xmitqueue); + INIT_LIST_HEAD(&conn->cmdqueue); INIT_LIST_HEAD(&conn->requeue); INIT_WORK(&conn->xmitwork, iscsi_xmitworker); @@ -2531,27 +2644,28 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn) EXPORT_SYMBOL_GPL(iscsi_conn_start); static void -flush_control_queues(struct iscsi_session *session, struct iscsi_conn *conn) +fail_mgmt_tasks(struct iscsi_session *session, struct iscsi_conn *conn) { - struct iscsi_task *task, *tmp; + struct iscsi_task *task; + int i, state; + + for (i = 0; i < conn->session->cmds_max; i++) { + task = conn->session->cmds[i]; + if (task->sc) + continue; + + if (task->state == ISCSI_TASK_FREE) + continue; + + ISCSI_DBG_SESSION(conn->session, + "failing mgmt itt 0x%x state %d\n", + task->itt, task->state); + state = ISCSI_TASK_ABRT_SESS_RECOV; + if (task->state == ISCSI_TASK_PENDING) + state = ISCSI_TASK_COMPLETED; + iscsi_complete_task(task, state); - /* handle pending */ - list_for_each_entry_safe(task, tmp, &conn->mgmtqueue, running) { - ISCSI_DBG_SESSION(session, "flushing pending mgmt task " - "itt 0x%x\n", task->itt); - /* release ref from prep task */ - __iscsi_put_task(task); } - - /* handle running */ - list_for_each_entry_safe(task, tmp, &conn->mgmt_run_list, running) { - ISCSI_DBG_SESSION(session, "flushing running mgmt task " - "itt 0x%x\n", task->itt); - /* release ref from prep task */ - __iscsi_put_task(task); - } - - conn->task = NULL; } static void iscsi_start_session_recovery(struct iscsi_session *session, @@ -2559,8 +2673,6 @@ static void iscsi_start_session_recovery(struct iscsi_session *session, { int old_stop_stage; - del_timer_sync(&conn->transport_timer); - mutex_lock(&session->eh_mutex); spin_lock_bh(&session->lock); if (conn->stop_stage == STOP_CONN_TERM) { @@ -2578,13 +2690,17 @@ static void iscsi_start_session_recovery(struct iscsi_session *session, session->state = ISCSI_STATE_TERMINATE; else if (conn->stop_stage != STOP_CONN_RECOVER) session->state = ISCSI_STATE_IN_RECOVERY; + spin_unlock_bh(&session->lock); + del_timer_sync(&conn->transport_timer); + iscsi_suspend_tx(conn); + + spin_lock_bh(&session->lock); old_stop_stage = conn->stop_stage; conn->stop_stage = flag; conn->c_stage = ISCSI_CONN_STOPPED; spin_unlock_bh(&session->lock); - iscsi_suspend_tx(conn); /* * for connection level recovery we should not calculate * header digest. conn->hdr_size used for optimization @@ -2605,11 +2721,8 @@ static void iscsi_start_session_recovery(struct iscsi_session *session, * flush queues. */ spin_lock_bh(&session->lock); - if (flag == STOP_CONN_RECOVER) - fail_all_commands(conn, -1, DID_TRANSPORT_DISRUPTED); - else - fail_all_commands(conn, -1, DID_ERROR); - flush_control_queues(session, conn); + fail_scsi_tasks(conn, -1, DID_TRANSPORT_DISRUPTED); + fail_mgmt_tasks(session, conn); spin_unlock_bh(&session->lock); mutex_unlock(&session->eh_mutex); } @@ -2651,6 +2764,23 @@ int iscsi_conn_bind(struct iscsi_cls_session *cls_session, } EXPORT_SYMBOL_GPL(iscsi_conn_bind); +static int iscsi_switch_str_param(char **param, char *new_val_buf) +{ + char *new_val; + + if (*param) { + if (!strcmp(*param, new_val_buf)) + return 0; + } + + new_val = kstrdup(new_val_buf, GFP_NOIO); + if (!new_val) + return -ENOMEM; + + kfree(*param); + *param = new_val; + return 0; +} int iscsi_set_param(struct iscsi_cls_conn *cls_conn, enum iscsi_param param, char *buf, int buflen) @@ -2723,38 +2853,15 @@ int iscsi_set_param(struct iscsi_cls_conn *cls_conn, sscanf(buf, "%u", &conn->exp_statsn); break; case ISCSI_PARAM_USERNAME: - kfree(session->username); - session->username = kstrdup(buf, GFP_KERNEL); - if (!session->username) - return -ENOMEM; - break; + return iscsi_switch_str_param(&session->username, buf); case ISCSI_PARAM_USERNAME_IN: - kfree(session->username_in); - session->username_in = kstrdup(buf, GFP_KERNEL); - if (!session->username_in) - return -ENOMEM; - break; + return iscsi_switch_str_param(&session->username_in, buf); case ISCSI_PARAM_PASSWORD: - kfree(session->password); - session->password = kstrdup(buf, GFP_KERNEL); - if (!session->password) - return -ENOMEM; - break; + return iscsi_switch_str_param(&session->password, buf); case ISCSI_PARAM_PASSWORD_IN: - kfree(session->password_in); - session->password_in = kstrdup(buf, GFP_KERNEL); - if (!session->password_in) - return -ENOMEM; - break; + return iscsi_switch_str_param(&session->password_in, buf); case ISCSI_PARAM_TARGET_NAME: - /* this should not change between logins */ - if (session->targetname) - break; - - session->targetname = kstrdup(buf, GFP_KERNEL); - if (!session->targetname) - return -ENOMEM; - break; + return iscsi_switch_str_param(&session->targetname, buf); case ISCSI_PARAM_TPGT: sscanf(buf, "%d", &session->tpgt); break; @@ -2762,25 +2869,11 @@ int iscsi_set_param(struct iscsi_cls_conn *cls_conn, sscanf(buf, "%d", &conn->persistent_port); break; case ISCSI_PARAM_PERSISTENT_ADDRESS: - /* - * this is the address returned in discovery so it should - * not change between logins. - */ - if (conn->persistent_address) - break; - - conn->persistent_address = kstrdup(buf, GFP_KERNEL); - if (!conn->persistent_address) - return -ENOMEM; - break; + return iscsi_switch_str_param(&conn->persistent_address, buf); case ISCSI_PARAM_IFACE_NAME: - if (!session->ifacename) - session->ifacename = kstrdup(buf, GFP_KERNEL); - break; + return iscsi_switch_str_param(&session->ifacename, buf); case ISCSI_PARAM_INITIATOR_NAME: - if (!session->initiatorname) - session->initiatorname = kstrdup(buf, GFP_KERNEL); - break; + return iscsi_switch_str_param(&session->initiatorname, buf); default: return -ENOSYS; } @@ -2851,10 +2944,7 @@ int iscsi_session_get_param(struct iscsi_cls_session *cls_session, len = sprintf(buf, "%s\n", session->ifacename); break; case ISCSI_PARAM_INITIATOR_NAME: - if (!session->initiatorname) - len = sprintf(buf, "%s\n", "unknown"); - else - len = sprintf(buf, "%s\n", session->initiatorname); + len = sprintf(buf, "%s\n", session->initiatorname); break; default: return -ENOSYS; @@ -2920,29 +3010,16 @@ int iscsi_host_get_param(struct Scsi_Host *shost, enum iscsi_host_param param, switch (param) { case ISCSI_HOST_PARAM_NETDEV_NAME: - if (!ihost->netdev) - len = sprintf(buf, "%s\n", "default"); - else - len = sprintf(buf, "%s\n", ihost->netdev); + len = sprintf(buf, "%s\n", ihost->netdev); break; case ISCSI_HOST_PARAM_HWADDRESS: - if (!ihost->hwaddress) - len = sprintf(buf, "%s\n", "default"); - else - len = sprintf(buf, "%s\n", ihost->hwaddress); + len = sprintf(buf, "%s\n", ihost->hwaddress); break; case ISCSI_HOST_PARAM_INITIATOR_NAME: - if (!ihost->initiatorname) - len = sprintf(buf, "%s\n", "unknown"); - else - len = sprintf(buf, "%s\n", ihost->initiatorname); + len = sprintf(buf, "%s\n", ihost->initiatorname); break; case ISCSI_HOST_PARAM_IPADDRESS: - if (!strlen(ihost->local_address)) - len = sprintf(buf, "%s\n", "unknown"); - else - len = sprintf(buf, "%s\n", - ihost->local_address); + len = sprintf(buf, "%s\n", ihost->local_address); break; default: return -ENOSYS; @@ -2959,17 +3036,11 @@ int iscsi_host_set_param(struct Scsi_Host *shost, enum iscsi_host_param param, switch (param) { case ISCSI_HOST_PARAM_NETDEV_NAME: - if (!ihost->netdev) - ihost->netdev = kstrdup(buf, GFP_KERNEL); - break; + return iscsi_switch_str_param(&ihost->netdev, buf); case ISCSI_HOST_PARAM_HWADDRESS: - if (!ihost->hwaddress) - ihost->hwaddress = kstrdup(buf, GFP_KERNEL); - break; + return iscsi_switch_str_param(&ihost->hwaddress, buf); case ISCSI_HOST_PARAM_INITIATOR_NAME: - if (!ihost->initiatorname) - ihost->initiatorname = kstrdup(buf, GFP_KERNEL); - break; + return iscsi_switch_str_param(&ihost->initiatorname, buf); default: return -ENOSYS; } diff --git a/drivers/scsi/libiscsi_tcp.c b/drivers/scsi/libiscsi_tcp.c index b579ca9f4836..2e0746d70303 100644 --- a/drivers/scsi/libiscsi_tcp.c +++ b/drivers/scsi/libiscsi_tcp.c @@ -440,8 +440,8 @@ void iscsi_tcp_cleanup_task(struct iscsi_task *task) struct iscsi_tcp_task *tcp_task = task->dd_data; struct iscsi_r2t_info *r2t; - /* nothing to do for mgmt or pending tasks */ - if (!task->sc || task->state == ISCSI_TASK_PENDING) + /* nothing to do for mgmt */ + if (!task->sc) return; /* flush task's r2t queues */ @@ -473,7 +473,13 @@ static int iscsi_tcp_data_in(struct iscsi_conn *conn, struct iscsi_task *task) int datasn = be32_to_cpu(rhdr->datasn); unsigned total_in_length = scsi_in(task->sc)->length; - iscsi_update_cmdsn(conn->session, (struct iscsi_nopin*)rhdr); + /* + * lib iscsi will update this in the completion handling if there + * is status. + */ + if (!(rhdr->flags & ISCSI_FLAG_DATA_STATUS)) + iscsi_update_cmdsn(conn->session, (struct iscsi_nopin*)rhdr); + if (tcp_conn->in.datalen == 0) return 0; @@ -680,6 +686,7 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr) "offset=%d, datalen=%d)\n", tcp_task->data_offset, tcp_conn->in.datalen); + task->last_xfer = jiffies; rc = iscsi_segment_seek_sg(&tcp_conn->in.segment, sdb->table.sgl, sdb->table.nents, @@ -707,9 +714,10 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr) rc = ISCSI_ERR_BAD_ITT; else if (ahslen) rc = ISCSI_ERR_AHSLEN; - else if (task->sc->sc_data_direction == DMA_TO_DEVICE) + else if (task->sc->sc_data_direction == DMA_TO_DEVICE) { + task->last_xfer = jiffies; rc = iscsi_tcp_r2t_rsp(conn, task); - else + } else rc = ISCSI_ERR_PROTO; spin_unlock(&conn->session->lock); break; @@ -857,6 +865,12 @@ int iscsi_tcp_recv_skb(struct iscsi_conn *conn, struct sk_buff *skb, int rc = 0; ISCSI_DBG_TCP(conn, "in %d bytes\n", skb->len - offset); + /* + * Update for each skb instead of pdu, because over slow networks a + * data_in's data could take a while to read in. We also want to + * account for r2ts. + */ + conn->last_recv = jiffies; if (unlikely(conn->suspend_rx)) { ISCSI_DBG_TCP(conn, "Rx suspended!\n"); diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index 3da02e436788..54fa1e42dc4d 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -1927,21 +1927,21 @@ int sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, /* do we need to support multiple segments? */ if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) { printk("%s: multiple segments req %u %u, rsp %u %u\n", - __func__, req->bio->bi_vcnt, req->data_len, - rsp->bio->bi_vcnt, rsp->data_len); + __func__, req->bio->bi_vcnt, blk_rq_bytes(req), + rsp->bio->bi_vcnt, blk_rq_bytes(rsp)); return -EINVAL; } - ret = smp_execute_task(dev, bio_data(req->bio), req->data_len, - bio_data(rsp->bio), rsp->data_len); + ret = smp_execute_task(dev, bio_data(req->bio), blk_rq_bytes(req), + bio_data(rsp->bio), blk_rq_bytes(rsp)); if (ret > 0) { /* positive number is the untransferred residual */ - rsp->data_len = ret; - req->data_len = 0; + rsp->resid_len = ret; + req->resid_len = 0; ret = 0; } else if (ret == 0) { - rsp->data_len = 0; - req->data_len = 0; + rsp->resid_len = 0; + req->resid_len = 0; } return ret; diff --git a/drivers/scsi/libsas/sas_host_smp.c b/drivers/scsi/libsas/sas_host_smp.c index d110a366c48a..1bc3b7567994 100644 --- a/drivers/scsi/libsas/sas_host_smp.c +++ b/drivers/scsi/libsas/sas_host_smp.c @@ -134,24 +134,24 @@ int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req, { u8 *req_data = NULL, *resp_data = NULL, *buf; struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost); - int error = -EINVAL, resp_data_len = rsp->data_len; + int error = -EINVAL; /* eight is the minimum size for request and response frames */ - if (req->data_len < 8 || rsp->data_len < 8) + if (blk_rq_bytes(req) < 8 || blk_rq_bytes(rsp) < 8) goto out; - if (bio_offset(req->bio) + req->data_len > PAGE_SIZE || - bio_offset(rsp->bio) + rsp->data_len > PAGE_SIZE) { + if (bio_offset(req->bio) + blk_rq_bytes(req) > PAGE_SIZE || + bio_offset(rsp->bio) + blk_rq_bytes(rsp) > PAGE_SIZE) { shost_printk(KERN_ERR, shost, "SMP request/response frame crosses page boundary"); goto out; } - req_data = kzalloc(req->data_len, GFP_KERNEL); + req_data = kzalloc(blk_rq_bytes(req), GFP_KERNEL); /* make sure frame can always be built ... we copy * back only the requested length */ - resp_data = kzalloc(max(rsp->data_len, 128U), GFP_KERNEL); + resp_data = kzalloc(max(blk_rq_bytes(rsp), 128U), GFP_KERNEL); if (!req_data || !resp_data) { error = -ENOMEM; @@ -160,7 +160,7 @@ int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req, local_irq_disable(); buf = kmap_atomic(bio_page(req->bio), KM_USER0) + bio_offset(req->bio); - memcpy(req_data, buf, req->data_len); + memcpy(req_data, buf, blk_rq_bytes(req)); kunmap_atomic(buf - bio_offset(req->bio), KM_USER0); local_irq_enable(); @@ -178,15 +178,15 @@ int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req, switch (req_data[1]) { case SMP_REPORT_GENERAL: - req->data_len -= 8; - resp_data_len -= 32; + req->resid_len -= 8; + rsp->resid_len -= 32; resp_data[2] = SMP_RESP_FUNC_ACC; resp_data[9] = sas_ha->num_phys; break; case SMP_REPORT_MANUF_INFO: - req->data_len -= 8; - resp_data_len -= 64; + req->resid_len -= 8; + rsp->resid_len -= 64; resp_data[2] = SMP_RESP_FUNC_ACC; memcpy(resp_data + 12, shost->hostt->name, SAS_EXPANDER_VENDOR_ID_LEN); @@ -199,13 +199,13 @@ int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req, break; case SMP_DISCOVER: - req->data_len -= 16; - if ((int)req->data_len < 0) { - req->data_len = 0; + req->resid_len -= 16; + if ((int)req->resid_len < 0) { + req->resid_len = 0; error = -EINVAL; goto out; } - resp_data_len -= 56; + rsp->resid_len -= 56; sas_host_smp_discover(sas_ha, resp_data, req_data[9]); break; @@ -215,13 +215,13 @@ int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req, break; case SMP_REPORT_PHY_SATA: - req->data_len -= 16; - if ((int)req->data_len < 0) { - req->data_len = 0; + req->resid_len -= 16; + if ((int)req->resid_len < 0) { + req->resid_len = 0; error = -EINVAL; goto out; } - resp_data_len -= 60; + rsp->resid_len -= 60; sas_report_phy_sata(sas_ha, resp_data, req_data[9]); break; @@ -238,13 +238,13 @@ int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req, break; case SMP_PHY_CONTROL: - req->data_len -= 44; - if ((int)req->data_len < 0) { - req->data_len = 0; + req->resid_len -= 44; + if ((int)req->resid_len < 0) { + req->resid_len = 0; error = -EINVAL; goto out; } - resp_data_len -= 8; + rsp->resid_len -= 8; sas_phy_control(sas_ha, req_data[9], req_data[10], req_data[32] >> 4, req_data[33] >> 4, resp_data); @@ -261,11 +261,10 @@ int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req, local_irq_disable(); buf = kmap_atomic(bio_page(rsp->bio), KM_USER0) + bio_offset(rsp->bio); - memcpy(buf, resp_data, rsp->data_len); + memcpy(buf, resp_data, blk_rq_bytes(rsp)); flush_kernel_dcache_page(bio_page(rsp->bio)); kunmap_atomic(buf - bio_offset(rsp->bio), KM_USER0); local_irq_enable(); - rsp->data_len = resp_data_len; out: kfree(req_data); diff --git a/drivers/scsi/libsrp.c b/drivers/scsi/libsrp.c index 15e2d132e8b9..2742ae8a3d09 100644 --- a/drivers/scsi/libsrp.c +++ b/drivers/scsi/libsrp.c @@ -135,7 +135,7 @@ int srp_target_alloc(struct srp_target *target, struct device *dev, INIT_LIST_HEAD(&target->cmd_queue); target->dev = dev; - target->dev->driver_data = target; + dev_set_drvdata(target->dev, target); target->srp_iu_size = iu_size; target->rx_ring_size = nr; diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 1105f9a111ba..1877d9811831 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2008 Emulex. All rights reserved. * + * Copyright (C) 2004-2009 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -23,6 +23,13 @@ struct lpfc_sli2_slim; +#define LPFC_PCI_DEV_LP 0x1 +#define LPFC_PCI_DEV_OC 0x2 + +#define LPFC_SLI_REV2 2 +#define LPFC_SLI_REV3 3 +#define LPFC_SLI_REV4 4 + #define LPFC_MAX_TARGET 4096 /* max number of targets supported */ #define LPFC_MAX_DISC_THREADS 64 /* max outstanding discovery els requests */ @@ -98,9 +105,11 @@ struct lpfc_dma_pool { }; struct hbq_dmabuf { + struct lpfc_dmabuf hbuf; struct lpfc_dmabuf dbuf; uint32_t size; uint32_t tag; + struct lpfc_rcqe rcqe; }; /* Priority bit. Set value to exceed low water mark in lpfc_mem. */ @@ -134,7 +143,10 @@ typedef struct lpfc_vpd { } rev; struct { #ifdef __BIG_ENDIAN_BITFIELD - uint32_t rsvd2 :24; /* Reserved */ + uint32_t rsvd3 :19; /* Reserved */ + uint32_t cdss : 1; /* Configure Data Security SLI */ + uint32_t rsvd2 : 3; /* Reserved */ + uint32_t cbg : 1; /* Configure BlockGuard */ uint32_t cmv : 1; /* Configure Max VPIs */ uint32_t ccrp : 1; /* Config Command Ring Polling */ uint32_t csah : 1; /* Configure Synchronous Abort Handling */ @@ -152,7 +164,10 @@ typedef struct lpfc_vpd { uint32_t csah : 1; /* Configure Synchronous Abort Handling */ uint32_t ccrp : 1; /* Config Command Ring Polling */ uint32_t cmv : 1; /* Configure Max VPIs */ - uint32_t rsvd2 :24; /* Reserved */ + uint32_t cbg : 1; /* Configure BlockGuard */ + uint32_t rsvd2 : 3; /* Reserved */ + uint32_t cdss : 1; /* Configure Data Security SLI */ + uint32_t rsvd3 :19; /* Reserved */ #endif } sli3Feat; } lpfc_vpd_t; @@ -264,8 +279,8 @@ enum hba_state { }; struct lpfc_vport { - struct list_head listentry; struct lpfc_hba *phba; + struct list_head listentry; uint8_t port_type; #define LPFC_PHYSICAL_PORT 1 #define LPFC_NPIV_PORT 2 @@ -273,6 +288,9 @@ struct lpfc_vport { enum discovery_state port_state; uint16_t vpi; + uint16_t vfi; + uint8_t vfi_state; +#define LPFC_VFI_REGISTERED 0x1 uint32_t fc_flag; /* FC flags */ /* Several of these flags are HBA centric and should be moved to @@ -385,6 +403,9 @@ struct lpfc_vport { #endif uint8_t stat_data_enabled; uint8_t stat_data_blocked; + struct list_head rcv_buffer_list; + uint32_t vport_flag; +#define STATIC_VPORT 1 }; struct hbq_s { @@ -420,8 +441,62 @@ enum intr_type_t { }; struct lpfc_hba { + /* SCSI interface function jump table entries */ + int (*lpfc_new_scsi_buf) + (struct lpfc_vport *, int); + struct lpfc_scsi_buf * (*lpfc_get_scsi_buf) + (struct lpfc_hba *); + int (*lpfc_scsi_prep_dma_buf) + (struct lpfc_hba *, struct lpfc_scsi_buf *); + void (*lpfc_scsi_unprep_dma_buf) + (struct lpfc_hba *, struct lpfc_scsi_buf *); + void (*lpfc_release_scsi_buf) + (struct lpfc_hba *, struct lpfc_scsi_buf *); + void (*lpfc_rampdown_queue_depth) + (struct lpfc_hba *); + void (*lpfc_scsi_prep_cmnd) + (struct lpfc_vport *, struct lpfc_scsi_buf *, + struct lpfc_nodelist *); + /* IOCB interface function jump table entries */ + int (*__lpfc_sli_issue_iocb) + (struct lpfc_hba *, uint32_t, + struct lpfc_iocbq *, uint32_t); + void (*__lpfc_sli_release_iocbq)(struct lpfc_hba *, + struct lpfc_iocbq *); + int (*lpfc_hba_down_post)(struct lpfc_hba *phba); + + + IOCB_t * (*lpfc_get_iocb_from_iocbq) + (struct lpfc_iocbq *); + void (*lpfc_scsi_cmd_iocb_cmpl) + (struct lpfc_hba *, struct lpfc_iocbq *, struct lpfc_iocbq *); + + /* MBOX interface function jump table entries */ + int (*lpfc_sli_issue_mbox) + (struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t); + /* Slow-path IOCB process function jump table entries */ + void (*lpfc_sli_handle_slow_ring_event) + (struct lpfc_hba *phba, struct lpfc_sli_ring *pring, + uint32_t mask); + /* INIT device interface function jump table entries */ + int (*lpfc_sli_hbq_to_firmware) + (struct lpfc_hba *, uint32_t, struct hbq_dmabuf *); + int (*lpfc_sli_brdrestart) + (struct lpfc_hba *); + int (*lpfc_sli_brdready) + (struct lpfc_hba *, uint32_t); + void (*lpfc_handle_eratt) + (struct lpfc_hba *); + void (*lpfc_stop_port) + (struct lpfc_hba *); + + + /* SLI4 specific HBA data structure */ + struct lpfc_sli4_hba sli4_hba; + struct lpfc_sli sli; - uint32_t sli_rev; /* SLI2 or SLI3 */ + uint8_t pci_dev_grp; /* lpfc PCI dev group: 0x0, 0x1, 0x2,... */ + uint32_t sli_rev; /* SLI2, SLI3, or SLI4 */ uint32_t sli3_options; /* Mask of enabled SLI3 options */ #define LPFC_SLI3_HBQ_ENABLED 0x01 #define LPFC_SLI3_NPIV_ENABLED 0x02 @@ -429,6 +504,7 @@ struct lpfc_hba { #define LPFC_SLI3_CRP_ENABLED 0x08 #define LPFC_SLI3_INB_ENABLED 0x10 #define LPFC_SLI3_BG_ENABLED 0x20 +#define LPFC_SLI3_DSS_ENABLED 0x40 uint32_t iocb_cmd_size; uint32_t iocb_rsp_size; @@ -442,8 +518,13 @@ struct lpfc_hba { uint32_t hba_flag; /* hba generic flags */ #define HBA_ERATT_HANDLED 0x1 /* This flag is set when eratt handled */ - -#define DEFER_ERATT 0x4 /* Deferred error attention in progress */ +#define DEFER_ERATT 0x2 /* Deferred error attention in progress */ +#define HBA_FCOE_SUPPORT 0x4 /* HBA function supports FCOE */ +#define HBA_RECEIVE_BUFFER 0x8 /* Rcv buffer posted to worker thread */ +#define HBA_POST_RECEIVE_BUFFER 0x10 /* Rcv buffers need to be posted */ +#define FCP_XRI_ABORT_EVENT 0x20 +#define ELS_XRI_ABORT_EVENT 0x40 +#define ASYNC_EVENT 0x80 struct lpfc_dmabuf slim2p; MAILBOX_t *mbox; @@ -502,6 +583,9 @@ struct lpfc_hba { uint32_t cfg_poll; uint32_t cfg_poll_tmo; uint32_t cfg_use_msi; + uint32_t cfg_fcp_imax; + uint32_t cfg_fcp_wq_count; + uint32_t cfg_fcp_eq_count; uint32_t cfg_sg_seg_cnt; uint32_t cfg_prot_sg_seg_cnt; uint32_t cfg_sg_dma_buf_size; @@ -511,6 +595,8 @@ struct lpfc_hba { uint32_t cfg_enable_hba_reset; uint32_t cfg_enable_hba_heartbeat; uint32_t cfg_enable_bg; + uint32_t cfg_enable_fip; + uint32_t cfg_log_verbose; lpfc_vpd_t vpd; /* vital product data */ @@ -526,11 +612,12 @@ struct lpfc_hba { unsigned long data_flags; uint32_t hbq_in_use; /* HBQs in use flag */ - struct list_head hbqbuf_in_list; /* in-fly hbq buffer list */ + struct list_head rb_pend_list; /* Received buffers to be processed */ uint32_t hbq_count; /* Count of configured HBQs */ struct hbq_s hbqs[LPFC_MAX_HBQS]; /* local copy of hbq indicies */ unsigned long pci_bar0_map; /* Physical address for PCI BAR0 */ + unsigned long pci_bar1_map; /* Physical address for PCI BAR1 */ unsigned long pci_bar2_map; /* Physical address for PCI BAR2 */ void __iomem *slim_memmap_p; /* Kernel memory mapped address for PCI BAR0 */ @@ -593,7 +680,8 @@ struct lpfc_hba { /* pci_mem_pools */ struct pci_pool *lpfc_scsi_dma_buf_pool; struct pci_pool *lpfc_mbuf_pool; - struct pci_pool *lpfc_hbq_pool; + struct pci_pool *lpfc_hrb_pool; /* header receive buffer pool */ + struct pci_pool *lpfc_drb_pool; /* data receive buffer pool */ struct lpfc_dma_pool lpfc_mbuf_safety_pool; mempool_t *mbox_mem_pool; @@ -609,6 +697,14 @@ struct lpfc_hba { struct lpfc_vport *pport; /* physical lpfc_vport pointer */ uint16_t max_vpi; /* Maximum virtual nports */ #define LPFC_MAX_VPI 0xFFFF /* Max number of VPI supported */ + uint16_t max_vports; /* + * For IOV HBAs max_vpi can change + * after a reset. max_vports is max + * number of vports present. This can + * be greater than max_vpi. + */ + uint16_t vpi_base; + uint16_t vfi_base; unsigned long *vpi_bmask; /* vpi allocation table */ /* Data structure used by fabric iocb scheduler */ @@ -667,6 +763,11 @@ struct lpfc_hba { /* Maximum number of events that can be outstanding at any time*/ #define LPFC_MAX_EVT_COUNT 512 atomic_t fast_event_count; + struct lpfc_fcf fcf; + uint8_t fc_map[3]; + uint8_t valid_vlan; + uint16_t vlan_id; + struct list_head fcf_conn_rec_list; }; static inline struct Scsi_Host * diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index c14f0cbdb125..fc07be5fbce9 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2008 Emulex. All rights reserved. * + * Copyright (C) 2004-2009 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -30,8 +30,10 @@ #include #include +#include "lpfc_hw4.h" #include "lpfc_hw.h" #include "lpfc_sli.h" +#include "lpfc_sli4.h" #include "lpfc_nl.h" #include "lpfc_disc.h" #include "lpfc_scsi.h" @@ -505,12 +507,14 @@ lpfc_issue_lip(struct Scsi_Host *shost) return -ENOMEM; memset((void *)pmboxq, 0, sizeof (LPFC_MBOXQ_t)); - pmboxq->mb.mbxCommand = MBX_DOWN_LINK; - pmboxq->mb.mbxOwner = OWN_HOST; + pmboxq->u.mb.mbxCommand = MBX_DOWN_LINK; + pmboxq->u.mb.mbxOwner = OWN_HOST; mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, LPFC_MBOX_TMO * 2); - if ((mbxstatus == MBX_SUCCESS) && (pmboxq->mb.mbxStatus == 0)) { + if ((mbxstatus == MBX_SUCCESS) && + (pmboxq->u.mb.mbxStatus == 0 || + pmboxq->u.mb.mbxStatus == MBXERR_LINK_DOWN)) { memset((void *)pmboxq, 0, sizeof (LPFC_MBOXQ_t)); lpfc_init_link(phba, pmboxq, phba->cfg_topology, phba->cfg_link_speed); @@ -789,7 +793,8 @@ lpfc_get_hba_info(struct lpfc_hba *phba, uint32_t *mrpi, uint32_t *arpi, uint32_t *mvpi, uint32_t *avpi) { - struct lpfc_sli *psli = &phba->sli; + struct lpfc_sli *psli = &phba->sli; + struct lpfc_mbx_read_config *rd_config; LPFC_MBOXQ_t *pmboxq; MAILBOX_t *pmb; int rc = 0; @@ -800,7 +805,7 @@ lpfc_get_hba_info(struct lpfc_hba *phba, */ if (phba->link_state < LPFC_LINK_DOWN || !phba->mbox_mem_pool || - (phba->sli.sli_flag & LPFC_SLI2_ACTIVE) == 0) + (phba->sli.sli_flag & LPFC_SLI_ACTIVE) == 0) return 0; if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) @@ -811,13 +816,13 @@ lpfc_get_hba_info(struct lpfc_hba *phba, return 0; memset(pmboxq, 0, sizeof (LPFC_MBOXQ_t)); - pmb = &pmboxq->mb; + pmb = &pmboxq->u.mb; pmb->mbxCommand = MBX_READ_CONFIG; pmb->mbxOwner = OWN_HOST; pmboxq->context1 = NULL; if ((phba->pport->fc_flag & FC_OFFLINE_MODE) || - (!(psli->sli_flag & LPFC_SLI2_ACTIVE))) + (!(psli->sli_flag & LPFC_SLI_ACTIVE))) rc = MBX_NOT_FINISHED; else rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2); @@ -828,18 +833,37 @@ lpfc_get_hba_info(struct lpfc_hba *phba, return 0; } - if (mrpi) - *mrpi = pmb->un.varRdConfig.max_rpi; - if (arpi) - *arpi = pmb->un.varRdConfig.avail_rpi; - if (mxri) - *mxri = pmb->un.varRdConfig.max_xri; - if (axri) - *axri = pmb->un.varRdConfig.avail_xri; - if (mvpi) - *mvpi = pmb->un.varRdConfig.max_vpi; - if (avpi) - *avpi = pmb->un.varRdConfig.avail_vpi; + if (phba->sli_rev == LPFC_SLI_REV4) { + rd_config = &pmboxq->u.mqe.un.rd_config; + if (mrpi) + *mrpi = bf_get(lpfc_mbx_rd_conf_rpi_count, rd_config); + if (arpi) + *arpi = bf_get(lpfc_mbx_rd_conf_rpi_count, rd_config) - + phba->sli4_hba.max_cfg_param.rpi_used; + if (mxri) + *mxri = bf_get(lpfc_mbx_rd_conf_xri_count, rd_config); + if (axri) + *axri = bf_get(lpfc_mbx_rd_conf_xri_count, rd_config) - + phba->sli4_hba.max_cfg_param.xri_used; + if (mvpi) + *mvpi = bf_get(lpfc_mbx_rd_conf_vpi_count, rd_config); + if (avpi) + *avpi = bf_get(lpfc_mbx_rd_conf_vpi_count, rd_config) - + phba->sli4_hba.max_cfg_param.vpi_used; + } else { + if (mrpi) + *mrpi = pmb->un.varRdConfig.max_rpi; + if (arpi) + *arpi = pmb->un.varRdConfig.avail_rpi; + if (mxri) + *mxri = pmb->un.varRdConfig.max_xri; + if (axri) + *axri = pmb->un.varRdConfig.avail_xri; + if (mvpi) + *mvpi = pmb->un.varRdConfig.max_vpi; + if (avpi) + *avpi = pmb->un.varRdConfig.avail_vpi; + } mempool_free(pmboxq, phba->mbox_mem_pool); return 1; @@ -2021,22 +2045,9 @@ static DEVICE_ATTR(lpfc_devloss_tmo, S_IRUGO | S_IWUSR, # lpfc_log_verbose: Only turn this flag on if you are willing to risk being # deluged with LOTS of information. # You can set a bit mask to record specific types of verbose messages: -# -# LOG_ELS 0x1 ELS events -# LOG_DISCOVERY 0x2 Link discovery events -# LOG_MBOX 0x4 Mailbox events -# LOG_INIT 0x8 Initialization events -# LOG_LINK_EVENT 0x10 Link events -# LOG_FCP 0x40 FCP traffic history -# LOG_NODE 0x80 Node table events -# LOG_BG 0x200 BlockBuard events -# LOG_MISC 0x400 Miscellaneous events -# LOG_SLI 0x800 SLI events -# LOG_FCP_ERROR 0x1000 Only log FCP errors -# LOG_LIBDFC 0x2000 LIBDFC events -# LOG_ALL_MSG 0xffff LOG all messages +# See lpfc_logmsh.h for definitions. */ -LPFC_VPORT_ATTR_HEX_RW(log_verbose, 0x0, 0x0, 0xffff, +LPFC_VPORT_ATTR_HEX_RW(log_verbose, 0x0, 0x0, 0xffffffff, "Verbose logging bit-mask"); /* @@ -2266,6 +2277,36 @@ lpfc_param_init(topology, 0, 0, 6) static DEVICE_ATTR(lpfc_topology, S_IRUGO | S_IWUSR, lpfc_topology_show, lpfc_topology_store); +/** + * lpfc_static_vport_show: Read callback function for + * lpfc_static_vport sysfs file. + * @dev: Pointer to class device object. + * @attr: device attribute structure. + * @buf: Data buffer. + * + * This function is the read call back function for + * lpfc_static_vport sysfs file. The lpfc_static_vport + * sysfs file report the mageability of the vport. + **/ +static ssize_t +lpfc_static_vport_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; + if (vport->vport_flag & STATIC_VPORT) + sprintf(buf, "1\n"); + else + sprintf(buf, "0\n"); + + return strlen(buf); +} + +/* + * Sysfs attribute to control the statistical data collection. + */ +static DEVICE_ATTR(lpfc_static_vport, S_IRUGO, + lpfc_static_vport_show, NULL); /** * lpfc_stat_data_ctrl_store - write call back for lpfc_stat_data_ctrl sysfs file @@ -2341,7 +2382,7 @@ lpfc_stat_data_ctrl_store(struct device *dev, struct device_attribute *attr, if (vports == NULL) return -ENOMEM; - for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { + for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { v_shost = lpfc_shost_from_vport(vports[i]); spin_lock_irq(v_shost->host_lock); /* Block and reset data collection */ @@ -2356,7 +2397,7 @@ lpfc_stat_data_ctrl_store(struct device *dev, struct device_attribute *attr, phba->bucket_base = base; phba->bucket_step = step; - for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { + for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { v_shost = lpfc_shost_from_vport(vports[i]); /* Unblock data collection */ @@ -2373,7 +2414,7 @@ lpfc_stat_data_ctrl_store(struct device *dev, struct device_attribute *attr, if (vports == NULL) return -ENOMEM; - for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { + for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { v_shost = lpfc_shost_from_vport(vports[i]); spin_lock_irq(shost->host_lock); vports[i]->stat_data_blocked = 1; @@ -2844,14 +2885,38 @@ LPFC_ATTR_RW(poll_tmo, 10, 1, 255, /* # lpfc_use_msi: Use MSI (Message Signaled Interrupts) in systems that # support this feature -# 0 = MSI disabled +# 0 = MSI disabled (default) # 1 = MSI enabled -# 2 = MSI-X enabled (default) -# Value range is [0,2]. Default value is 2. +# 2 = MSI-X enabled +# Value range is [0,2]. Default value is 0. */ -LPFC_ATTR_R(use_msi, 2, 0, 2, "Use Message Signaled Interrupts (1) or " +LPFC_ATTR_R(use_msi, 0, 0, 2, "Use Message Signaled Interrupts (1) or " "MSI-X (2), if possible"); +/* +# lpfc_fcp_imax: Set the maximum number of fast-path FCP interrupts per second +# +# Value range is [636,651042]. Default value is 10000. +*/ +LPFC_ATTR_R(fcp_imax, LPFC_FP_DEF_IMAX, LPFC_MIM_IMAX, LPFC_DMULT_CONST, + "Set the maximum number of fast-path FCP interrupts per second"); + +/* +# lpfc_fcp_wq_count: Set the number of fast-path FCP work queues +# +# Value range is [1,31]. Default value is 4. +*/ +LPFC_ATTR_R(fcp_wq_count, LPFC_FP_WQN_DEF, LPFC_FP_WQN_MIN, LPFC_FP_WQN_MAX, + "Set the number of fast-path FCP work queues, if possible"); + +/* +# lpfc_fcp_eq_count: Set the number of fast-path FCP event queues +# +# Value range is [1,7]. Default value is 1. +*/ +LPFC_ATTR_R(fcp_eq_count, LPFC_FP_EQN_DEF, LPFC_FP_EQN_MIN, LPFC_FP_EQN_MAX, + "Set the number of fast-path FCP event queues, if possible"); + /* # lpfc_enable_hba_reset: Allow or prevent HBA resets to the hardware. # 0 = HBA resets disabled @@ -2876,6 +2941,14 @@ LPFC_ATTR_R(enable_hba_heartbeat, 1, 0, 1, "Enable HBA Heartbeat."); */ LPFC_ATTR_R(enable_bg, 0, 0, 1, "Enable BlockGuard Support"); +/* +# lpfc_enable_fip: When set, FIP is required to start discovery. If not +# set, the driver will add an FCF record manually if the port has no +# FCF records available and start discovery. +# Value range is [0,1]. Default value is 1 (enabled) +*/ +LPFC_ATTR_RW(enable_fip, 0, 0, 1, "Enable FIP Discovery"); + /* # lpfc_prot_mask: i @@ -2942,6 +3015,7 @@ struct device_attribute *lpfc_hba_attrs[] = { &dev_attr_lpfc_peer_port_login, &dev_attr_lpfc_nodev_tmo, &dev_attr_lpfc_devloss_tmo, + &dev_attr_lpfc_enable_fip, &dev_attr_lpfc_fcp_class, &dev_attr_lpfc_use_adisc, &dev_attr_lpfc_ack0, @@ -2969,6 +3043,9 @@ struct device_attribute *lpfc_hba_attrs[] = { &dev_attr_lpfc_poll, &dev_attr_lpfc_poll_tmo, &dev_attr_lpfc_use_msi, + &dev_attr_lpfc_fcp_imax, + &dev_attr_lpfc_fcp_wq_count, + &dev_attr_lpfc_fcp_eq_count, &dev_attr_lpfc_enable_bg, &dev_attr_lpfc_soft_wwnn, &dev_attr_lpfc_soft_wwpn, @@ -2991,6 +3068,7 @@ struct device_attribute *lpfc_vport_attrs[] = { &dev_attr_lpfc_lun_queue_depth, &dev_attr_lpfc_nodev_tmo, &dev_attr_lpfc_devloss_tmo, + &dev_attr_lpfc_enable_fip, &dev_attr_lpfc_hba_queue_depth, &dev_attr_lpfc_peer_port_login, &dev_attr_lpfc_restrict_login, @@ -3003,6 +3081,7 @@ struct device_attribute *lpfc_vport_attrs[] = { &dev_attr_lpfc_enable_da_id, &dev_attr_lpfc_max_scsicmpl_time, &dev_attr_lpfc_stat_data_ctrl, + &dev_attr_lpfc_static_vport, NULL, }; @@ -3034,6 +3113,9 @@ sysfs_ctlreg_write(struct kobject *kobj, struct bin_attribute *bin_attr, struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; + if (phba->sli_rev >= LPFC_SLI_REV4) + return -EPERM; + if ((off + count) > FF_REG_AREA_SIZE) return -ERANGE; @@ -3084,6 +3166,9 @@ sysfs_ctlreg_read(struct kobject *kobj, struct bin_attribute *bin_attr, struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; + if (phba->sli_rev >= LPFC_SLI_REV4) + return -EPERM; + if (off > FF_REG_AREA_SIZE) return -ERANGE; @@ -3199,7 +3284,7 @@ sysfs_mbox_write(struct kobject *kobj, struct bin_attribute *bin_attr, } } - memcpy((uint8_t *) & phba->sysfs_mbox.mbox->mb + off, + memcpy((uint8_t *) &phba->sysfs_mbox.mbox->u.mb + off, buf, count); phba->sysfs_mbox.offset = off + count; @@ -3241,6 +3326,7 @@ sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr, struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; int rc; + MAILBOX_t *pmb; if (off > MAILBOX_CMD_SIZE) return -ERANGE; @@ -3265,8 +3351,8 @@ sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr, if (off == 0 && phba->sysfs_mbox.state == SMBOX_WRITING && phba->sysfs_mbox.offset >= 2 * sizeof(uint32_t)) { - - switch (phba->sysfs_mbox.mbox->mb.mbxCommand) { + pmb = &phba->sysfs_mbox.mbox->u.mb; + switch (pmb->mbxCommand) { /* Offline only */ case MBX_INIT_LINK: case MBX_DOWN_LINK: @@ -3283,7 +3369,7 @@ sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr, if (!(vport->fc_flag & FC_OFFLINE_MODE)) { printk(KERN_WARNING "mbox_read:Command 0x%x " "is illegal in on-line state\n", - phba->sysfs_mbox.mbox->mb.mbxCommand); + pmb->mbxCommand); sysfs_mbox_idle(phba); spin_unlock_irq(&phba->hbalock); return -EPERM; @@ -3319,13 +3405,13 @@ sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr, case MBX_CONFIG_PORT: case MBX_RUN_BIU_DIAG: printk(KERN_WARNING "mbox_read: Illegal Command 0x%x\n", - phba->sysfs_mbox.mbox->mb.mbxCommand); + pmb->mbxCommand); sysfs_mbox_idle(phba); spin_unlock_irq(&phba->hbalock); return -EPERM; default: printk(KERN_WARNING "mbox_read: Unknown Command 0x%x\n", - phba->sysfs_mbox.mbox->mb.mbxCommand); + pmb->mbxCommand); sysfs_mbox_idle(phba); spin_unlock_irq(&phba->hbalock); return -EPERM; @@ -3335,14 +3421,14 @@ sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr, * or RESTART mailbox commands until the HBA is restarted. */ if (phba->pport->stopped && - phba->sysfs_mbox.mbox->mb.mbxCommand != MBX_DUMP_MEMORY && - phba->sysfs_mbox.mbox->mb.mbxCommand != MBX_RESTART && - phba->sysfs_mbox.mbox->mb.mbxCommand != MBX_WRITE_VPARMS && - phba->sysfs_mbox.mbox->mb.mbxCommand != MBX_WRITE_WWN) + pmb->mbxCommand != MBX_DUMP_MEMORY && + pmb->mbxCommand != MBX_RESTART && + pmb->mbxCommand != MBX_WRITE_VPARMS && + pmb->mbxCommand != MBX_WRITE_WWN) lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX, "1259 mbox: Issued mailbox cmd " "0x%x while in stopped state.\n", - phba->sysfs_mbox.mbox->mb.mbxCommand); + pmb->mbxCommand); phba->sysfs_mbox.mbox->vport = vport; @@ -3356,7 +3442,7 @@ sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr, } if ((vport->fc_flag & FC_OFFLINE_MODE) || - (!(phba->sli.sli_flag & LPFC_SLI2_ACTIVE))){ + (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE))) { spin_unlock_irq(&phba->hbalock); rc = lpfc_sli_issue_mbox (phba, @@ -3368,8 +3454,7 @@ sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr, spin_unlock_irq(&phba->hbalock); rc = lpfc_sli_issue_mbox_wait (phba, phba->sysfs_mbox.mbox, - lpfc_mbox_tmo_val(phba, - phba->sysfs_mbox.mbox->mb.mbxCommand) * HZ); + lpfc_mbox_tmo_val(phba, pmb->mbxCommand) * HZ); spin_lock_irq(&phba->hbalock); } @@ -3391,7 +3476,7 @@ sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr, return -EAGAIN; } - memcpy(buf, (uint8_t *) & phba->sysfs_mbox.mbox->mb + off, count); + memcpy(buf, (uint8_t *) &pmb + off, count); phba->sysfs_mbox.offset = off + count; @@ -3585,6 +3670,9 @@ lpfc_get_host_speed(struct Scsi_Host *shost) case LA_8GHZ_LINK: fc_host_speed(shost) = FC_PORTSPEED_8GBIT; break; + case LA_10GHZ_LINK: + fc_host_speed(shost) = FC_PORTSPEED_10GBIT; + break; default: fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN; break; @@ -3652,7 +3740,7 @@ lpfc_get_stats(struct Scsi_Host *shost) */ if (phba->link_state < LPFC_LINK_DOWN || !phba->mbox_mem_pool || - (phba->sli.sli_flag & LPFC_SLI2_ACTIVE) == 0) + (phba->sli.sli_flag & LPFC_SLI_ACTIVE) == 0) return NULL; if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) @@ -3663,14 +3751,14 @@ lpfc_get_stats(struct Scsi_Host *shost) return NULL; memset(pmboxq, 0, sizeof (LPFC_MBOXQ_t)); - pmb = &pmboxq->mb; + pmb = &pmboxq->u.mb; pmb->mbxCommand = MBX_READ_STATUS; pmb->mbxOwner = OWN_HOST; pmboxq->context1 = NULL; pmboxq->vport = vport; if ((vport->fc_flag & FC_OFFLINE_MODE) || - (!(psli->sli_flag & LPFC_SLI2_ACTIVE))) + (!(psli->sli_flag & LPFC_SLI_ACTIVE))) rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); else rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2); @@ -3695,7 +3783,7 @@ lpfc_get_stats(struct Scsi_Host *shost) pmboxq->vport = vport; if ((vport->fc_flag & FC_OFFLINE_MODE) || - (!(psli->sli_flag & LPFC_SLI2_ACTIVE))) + (!(psli->sli_flag & LPFC_SLI_ACTIVE))) rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); else rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2); @@ -3769,7 +3857,7 @@ lpfc_reset_stats(struct Scsi_Host *shost) return; memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t)); - pmb = &pmboxq->mb; + pmb = &pmboxq->u.mb; pmb->mbxCommand = MBX_READ_STATUS; pmb->mbxOwner = OWN_HOST; pmb->un.varWords[0] = 0x1; /* reset request */ @@ -3777,7 +3865,7 @@ lpfc_reset_stats(struct Scsi_Host *shost) pmboxq->vport = vport; if ((vport->fc_flag & FC_OFFLINE_MODE) || - (!(psli->sli_flag & LPFC_SLI2_ACTIVE))) + (!(psli->sli_flag & LPFC_SLI_ACTIVE))) rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); else rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2); @@ -3795,7 +3883,7 @@ lpfc_reset_stats(struct Scsi_Host *shost) pmboxq->vport = vport; if ((vport->fc_flag & FC_OFFLINE_MODE) || - (!(psli->sli_flag & LPFC_SLI2_ACTIVE))) + (!(psli->sli_flag & LPFC_SLI_ACTIVE))) rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); else rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2); @@ -3962,6 +4050,21 @@ lpfc_set_vport_symbolic_name(struct fc_vport *fc_vport) lpfc_ns_cmd(vport, SLI_CTNS_RSPN_ID, 0, 0); } +/** + * lpfc_hba_log_verbose_init - Set hba's log verbose level + * @phba: Pointer to lpfc_hba struct. + * + * This function is called by the lpfc_get_cfgparam() routine to set the + * module lpfc_log_verbose into the @phba cfg_log_verbose for use with + * log messsage according to the module's lpfc_log_verbose parameter setting + * before hba port or vport created. + **/ +static void +lpfc_hba_log_verbose_init(struct lpfc_hba *phba, uint32_t verbose) +{ + phba->cfg_log_verbose = verbose; +} + struct fc_function_template lpfc_transport_functions = { /* fixed attributes the driver supports */ .show_host_node_name = 1, @@ -4105,6 +4208,9 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) lpfc_poll_tmo_init(phba, lpfc_poll_tmo); lpfc_enable_npiv_init(phba, lpfc_enable_npiv); lpfc_use_msi_init(phba, lpfc_use_msi); + lpfc_fcp_imax_init(phba, lpfc_fcp_imax); + lpfc_fcp_wq_count_init(phba, lpfc_fcp_wq_count); + lpfc_fcp_eq_count_init(phba, lpfc_fcp_eq_count); lpfc_enable_hba_reset_init(phba, lpfc_enable_hba_reset); lpfc_enable_hba_heartbeat_init(phba, lpfc_enable_hba_heartbeat); lpfc_enable_bg_init(phba, lpfc_enable_bg); @@ -4113,26 +4219,10 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) phba->cfg_soft_wwpn = 0L; lpfc_sg_seg_cnt_init(phba, lpfc_sg_seg_cnt); lpfc_prot_sg_seg_cnt_init(phba, lpfc_prot_sg_seg_cnt); - /* - * Since the sg_tablesize is module parameter, the sg_dma_buf_size - * used to create the sg_dma_buf_pool must be dynamically calculated. - * 2 segments are added since the IOCB needs a command and response bde. - */ - phba->cfg_sg_dma_buf_size = sizeof(struct fcp_cmnd) + - sizeof(struct fcp_rsp) + - ((phba->cfg_sg_seg_cnt + 2) * sizeof(struct ulp_bde64)); - - if (phba->cfg_enable_bg) { - phba->cfg_sg_seg_cnt = LPFC_MAX_SG_SEG_CNT; - phba->cfg_sg_dma_buf_size += - phba->cfg_prot_sg_seg_cnt * sizeof(struct ulp_bde64); - } - - /* Also reinitialize the host templates with new values. */ - lpfc_vport_template.sg_tablesize = phba->cfg_sg_seg_cnt; - lpfc_template.sg_tablesize = phba->cfg_sg_seg_cnt; - lpfc_hba_queue_depth_init(phba, lpfc_hba_queue_depth); + lpfc_enable_fip_init(phba, lpfc_enable_fip); + lpfc_hba_log_verbose_init(phba, lpfc_log_verbose); + return; } diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index f88ce3f26190..d2a922997c0f 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -23,6 +23,8 @@ typedef int (*node_filter)(struct lpfc_nodelist *, void *); struct fc_rport; void lpfc_dump_mem(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t); void lpfc_dump_wakeup_param(struct lpfc_hba *, LPFC_MBOXQ_t *); +void lpfc_dump_static_vport(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t); +int lpfc_dump_fcoe_param(struct lpfc_hba *, struct lpfcMboxq *); void lpfc_read_nv(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_config_async(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t); @@ -35,17 +37,19 @@ int lpfc_config_msi(struct lpfc_hba *, LPFC_MBOXQ_t *); int lpfc_read_sparam(struct lpfc_hba *, LPFC_MBOXQ_t *, int); void lpfc_read_config(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_read_lnk_stat(struct lpfc_hba *, LPFC_MBOXQ_t *); -int lpfc_reg_login(struct lpfc_hba *, uint16_t, uint32_t, uint8_t *, - LPFC_MBOXQ_t *, uint32_t); +int lpfc_reg_rpi(struct lpfc_hba *, uint16_t, uint32_t, uint8_t *, + LPFC_MBOXQ_t *, uint32_t); void lpfc_unreg_login(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *); void lpfc_unreg_did(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *); -void lpfc_reg_vpi(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *); +void lpfc_reg_vpi(struct lpfc_vport *, LPFC_MBOXQ_t *); void lpfc_unreg_vpi(struct lpfc_hba *, uint16_t, LPFC_MBOXQ_t *); void lpfc_init_link(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t); +void lpfc_request_features(struct lpfc_hba *, struct lpfcMboxq *); struct lpfc_vport *lpfc_find_vport_by_did(struct lpfc_hba *, uint32_t); void lpfc_cleanup_rpis(struct lpfc_vport *, int); int lpfc_linkdown(struct lpfc_hba *); +void lpfc_linkdown_port(struct lpfc_vport *); void lpfc_port_link_failure(struct lpfc_vport *); void lpfc_mbx_cmpl_read_la(struct lpfc_hba *, LPFC_MBOXQ_t *); @@ -54,6 +58,7 @@ void lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *); +void lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_enqueue_node(struct lpfc_vport *, struct lpfc_nodelist *); void lpfc_dequeue_node(struct lpfc_vport *, struct lpfc_nodelist *); struct lpfc_nodelist *lpfc_enable_node(struct lpfc_vport *, @@ -105,6 +110,7 @@ int lpfc_issue_els_adisc(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t); int lpfc_issue_els_logo(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t); int lpfc_issue_els_npiv_logo(struct lpfc_vport *, struct lpfc_nodelist *); int lpfc_issue_els_scr(struct lpfc_vport *, uint32_t, uint8_t); +int lpfc_issue_fabric_reglogin(struct lpfc_vport *); int lpfc_els_free_iocb(struct lpfc_hba *, struct lpfc_iocbq *); int lpfc_ct_free_iocb(struct lpfc_hba *, struct lpfc_iocbq *); int lpfc_els_rsp_acc(struct lpfc_vport *, uint32_t, struct lpfc_iocbq *, @@ -149,15 +155,19 @@ int lpfc_online(struct lpfc_hba *); void lpfc_unblock_mgmt_io(struct lpfc_hba *); void lpfc_offline_prep(struct lpfc_hba *); void lpfc_offline(struct lpfc_hba *); +void lpfc_reset_hba(struct lpfc_hba *); int lpfc_sli_setup(struct lpfc_hba *); int lpfc_sli_queue_setup(struct lpfc_hba *); void lpfc_handle_eratt(struct lpfc_hba *); void lpfc_handle_latt(struct lpfc_hba *); -irqreturn_t lpfc_intr_handler(int, void *); -irqreturn_t lpfc_sp_intr_handler(int, void *); -irqreturn_t lpfc_fp_intr_handler(int, void *); +irqreturn_t lpfc_sli_intr_handler(int, void *); +irqreturn_t lpfc_sli_sp_intr_handler(int, void *); +irqreturn_t lpfc_sli_fp_intr_handler(int, void *); +irqreturn_t lpfc_sli4_intr_handler(int, void *); +irqreturn_t lpfc_sli4_sp_intr_handler(int, void *); +irqreturn_t lpfc_sli4_fp_intr_handler(int, void *); void lpfc_read_rev(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_config_ring(struct lpfc_hba *, int, LPFC_MBOXQ_t *); @@ -165,16 +175,32 @@ void lpfc_config_port(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_kill_board(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_mbox_put(struct lpfc_hba *, LPFC_MBOXQ_t *); LPFC_MBOXQ_t *lpfc_mbox_get(struct lpfc_hba *); +void __lpfc_mbox_cmpl_put(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_mbox_cmpl_put(struct lpfc_hba *, LPFC_MBOXQ_t *); +int lpfc_mbox_cmd_check(struct lpfc_hba *, LPFC_MBOXQ_t *); +int lpfc_mbox_dev_check(struct lpfc_hba *); int lpfc_mbox_tmo_val(struct lpfc_hba *, int); +void lpfc_init_vfi(struct lpfcMboxq *, struct lpfc_vport *); +void lpfc_reg_vfi(struct lpfcMboxq *, struct lpfc_vport *, dma_addr_t); +void lpfc_init_vpi(struct lpfcMboxq *, uint16_t); +void lpfc_unreg_vfi(struct lpfcMboxq *, uint16_t); +void lpfc_reg_fcfi(struct lpfc_hba *, struct lpfcMboxq *); +void lpfc_unreg_fcfi(struct lpfcMboxq *, uint16_t); +void lpfc_resume_rpi(struct lpfcMboxq *, struct lpfc_nodelist *); void lpfc_config_hbq(struct lpfc_hba *, uint32_t, struct lpfc_hbq_init *, uint32_t , LPFC_MBOXQ_t *); struct hbq_dmabuf *lpfc_els_hbq_alloc(struct lpfc_hba *); void lpfc_els_hbq_free(struct lpfc_hba *, struct hbq_dmabuf *); +struct hbq_dmabuf *lpfc_sli4_rb_alloc(struct lpfc_hba *); +void lpfc_sli4_rb_free(struct lpfc_hba *, struct hbq_dmabuf *); +void lpfc_sli4_build_dflt_fcf_record(struct lpfc_hba *, struct fcf_record *, + uint16_t); +void lpfc_unregister_unused_fcf(struct lpfc_hba *); -int lpfc_mem_alloc(struct lpfc_hba *); +int lpfc_mem_alloc(struct lpfc_hba *, int align); void lpfc_mem_free(struct lpfc_hba *); +void lpfc_mem_free_all(struct lpfc_hba *); void lpfc_stop_vport_timers(struct lpfc_vport *); void lpfc_poll_timeout(unsigned long ptr); @@ -186,6 +212,7 @@ void lpfc_sli_release_iocbq(struct lpfc_hba *, struct lpfc_iocbq *); uint16_t lpfc_sli_next_iotag(struct lpfc_hba *, struct lpfc_iocbq *); void lpfc_sli_cancel_iocbs(struct lpfc_hba *, struct list_head *, uint32_t, uint32_t); +void lpfc_sli_wake_mbox_wait(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_reset_barrier(struct lpfc_hba * phba); int lpfc_sli_brdready(struct lpfc_hba *, uint32_t); @@ -198,12 +225,13 @@ int lpfc_sli_host_down(struct lpfc_vport *); int lpfc_sli_hba_down(struct lpfc_hba *); int lpfc_sli_issue_mbox(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t); int lpfc_sli_handle_mb_event(struct lpfc_hba *); -int lpfc_sli_flush_mbox_queue(struct lpfc_hba *); +void lpfc_sli_mbox_sys_shutdown(struct lpfc_hba *); int lpfc_sli_check_eratt(struct lpfc_hba *); -int lpfc_sli_handle_slow_ring_event(struct lpfc_hba *, +void lpfc_sli_handle_slow_ring_event(struct lpfc_hba *, struct lpfc_sli_ring *, uint32_t); +int lpfc_sli4_handle_received_buffer(struct lpfc_hba *); void lpfc_sli_def_mbox_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *); -int lpfc_sli_issue_iocb(struct lpfc_hba *, struct lpfc_sli_ring *, +int lpfc_sli_issue_iocb(struct lpfc_hba *, uint32_t, struct lpfc_iocbq *, uint32_t); void lpfc_sli_pcimem_bcopy(void *, void *, uint32_t); void lpfc_sli_abort_iocb_ring(struct lpfc_hba *, struct lpfc_sli_ring *); @@ -237,7 +265,7 @@ struct lpfc_nodelist *lpfc_findnode_wwpn(struct lpfc_vport *, int lpfc_sli_issue_mbox_wait(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t); -int lpfc_sli_issue_iocb_wait(struct lpfc_hba *, struct lpfc_sli_ring *, +int lpfc_sli_issue_iocb_wait(struct lpfc_hba *, uint32_t, struct lpfc_iocbq *, struct lpfc_iocbq *, uint32_t); void lpfc_sli_abort_fcp_cmpl(struct lpfc_hba *, struct lpfc_iocbq *, @@ -254,6 +282,12 @@ void lpfc_in_buf_free(struct lpfc_hba *, struct lpfc_dmabuf *); const char* lpfc_info(struct Scsi_Host *); int lpfc_scan_finished(struct Scsi_Host *, unsigned long); +int lpfc_init_api_table_setup(struct lpfc_hba *, uint8_t); +int lpfc_sli_api_table_setup(struct lpfc_hba *, uint8_t); +int lpfc_scsi_api_table_setup(struct lpfc_hba *, uint8_t); +int lpfc_mbox_api_table_setup(struct lpfc_hba *, uint8_t); +int lpfc_api_table_setup(struct lpfc_hba *, uint8_t); + void lpfc_get_cfgparam(struct lpfc_hba *); void lpfc_get_vport_cfgparam(struct lpfc_vport *); int lpfc_alloc_sysfs_attr(struct lpfc_vport *); @@ -314,8 +348,15 @@ lpfc_send_els_failure_event(struct lpfc_hba *, struct lpfc_iocbq *, struct lpfc_iocbq *); struct lpfc_fast_path_event *lpfc_alloc_fast_evt(struct lpfc_hba *); void lpfc_free_fast_evt(struct lpfc_hba *, struct lpfc_fast_path_event *); +void lpfc_create_static_vport(struct lpfc_hba *); +void lpfc_stop_hba_timers(struct lpfc_hba *); +void lpfc_stop_port(struct lpfc_hba *); +void lpfc_parse_fcoe_conf(struct lpfc_hba *, uint8_t *, uint32_t); +int lpfc_parse_vpd(struct lpfc_hba *, uint8_t *, int); +void lpfc_start_fdiscs(struct lpfc_hba *phba); #define ScsiResult(host_code, scsi_code) (((host_code) << 16) | scsi_code) #define HBA_EVENT_RSCN 5 #define HBA_EVENT_LINK_UP 2 #define HBA_EVENT_LINK_DOWN 3 + diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index 896c7b0351e5..0e532f072eb3 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2008 Emulex. All rights reserved. * + * Copyright (C) 2004-2009 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * @@ -32,8 +32,10 @@ #include #include +#include "lpfc_hw4.h" #include "lpfc_hw.h" #include "lpfc_sli.h" +#include "lpfc_sli4.h" #include "lpfc_nl.h" #include "lpfc_disc.h" #include "lpfc_scsi.h" @@ -267,8 +269,6 @@ lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp, uint32_t tmo, uint8_t retry) { struct lpfc_hba *phba = vport->phba; - struct lpfc_sli *psli = &phba->sli; - struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING]; IOCB_t *icmd; struct lpfc_iocbq *geniocb; int rc; @@ -331,7 +331,7 @@ lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp, geniocb->drvrTimeout = icmd->ulpTimeout + LPFC_DRVR_TIMEOUT; geniocb->vport = vport; geniocb->retry = retry; - rc = lpfc_sli_issue_iocb(phba, pring, geniocb, 0); + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, geniocb, 0); if (rc == IOCB_ERROR) { lpfc_sli_release_iocbq(phba, geniocb); @@ -1578,6 +1578,9 @@ lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int cmdcode) case LA_8GHZ_LINK: ae->un.PortSpeed = HBA_PORTSPEED_8GBIT; break; + case LA_10GHZ_LINK: + ae->un.PortSpeed = HBA_PORTSPEED_10GBIT; + break; default: ae->un.PortSpeed = HBA_PORTSPEED_UNKNOWN; @@ -1729,8 +1732,10 @@ lpfc_decode_firmware_rev(struct lpfc_hba *phba, char *fwrevision, int flag) uint32_t *ptr, str[4]; uint8_t *fwname; - if (vp->rev.rBit) { - if (psli->sli_flag & LPFC_SLI2_ACTIVE) + if (phba->sli_rev == LPFC_SLI_REV4) + sprintf(fwrevision, "%s", vp->rev.opFwName); + else if (vp->rev.rBit) { + if (psli->sli_flag & LPFC_SLI_ACTIVE) rev = vp->rev.sli2FwRev; else rev = vp->rev.sli1FwRev; @@ -1756,7 +1761,7 @@ lpfc_decode_firmware_rev(struct lpfc_hba *phba, char *fwrevision, int flag) } b4 = (rev & 0x0000000f); - if (psli->sli_flag & LPFC_SLI2_ACTIVE) + if (psli->sli_flag & LPFC_SLI_ACTIVE) fwname = vp->rev.sli2FwName; else fwname = vp->rev.sli1FwName; diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c index 52be5644e07a..8d0f0de76b63 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/drivers/scsi/lpfc/lpfc_debugfs.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2007-2008 Emulex. All rights reserved. * + * Copyright (C) 2007-2009 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * @@ -33,8 +33,10 @@ #include #include +#include "lpfc_hw4.h" #include "lpfc_hw.h" #include "lpfc_sli.h" +#include "lpfc_sli4.h" #include "lpfc_nl.h" #include "lpfc_disc.h" #include "lpfc_scsi.h" @@ -51,8 +53,7 @@ * debugfs interface * * To access this interface the user should: - * # mkdir /debug - * # mount -t debugfs none /debug + * # mount -t debugfs none /sys/kernel/debug * * The lpfc debugfs directory hierarchy is: * lpfc/lpfcX/vportY @@ -280,6 +281,8 @@ lpfc_debugfs_hbqinfo_data(struct lpfc_hba *phba, char *buf, int size) struct lpfc_dmabuf *d_buf; struct hbq_dmabuf *hbq_buf; + if (phba->sli_rev != 3) + return 0; cnt = LPFC_HBQINFO_SIZE; spin_lock_irq(&phba->hbalock); @@ -489,12 +492,15 @@ lpfc_debugfs_dumpHostSlim_data(struct lpfc_hba *phba, char *buf, int size) pring->next_cmdidx, pring->local_getidx, pring->flag, pgpp->rspPutInx, pring->numRiocb); } - word0 = readl(phba->HAregaddr); - word1 = readl(phba->CAregaddr); - word2 = readl(phba->HSregaddr); - word3 = readl(phba->HCregaddr); - len += snprintf(buf+len, size-len, "HA:%08x CA:%08x HS:%08x HC:%08x\n", - word0, word1, word2, word3); + + if (phba->sli_rev <= LPFC_SLI_REV3) { + word0 = readl(phba->HAregaddr); + word1 = readl(phba->CAregaddr); + word2 = readl(phba->HSregaddr); + word3 = readl(phba->HCregaddr); + len += snprintf(buf+len, size-len, "HA:%08x CA:%08x HS:%08x " + "HC:%08x\n", word0, word1, word2, word3); + } spin_unlock_irq(&phba->hbalock); return len; } diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h index ffd108972072..1142070e9484 100644 --- a/drivers/scsi/lpfc/lpfc_disc.h +++ b/drivers/scsi/lpfc/lpfc_disc.h @@ -135,6 +135,7 @@ struct lpfc_nodelist { #define NLP_NODEV_REMOVE 0x08000000 /* Defer removal till discovery ends */ #define NLP_TARGET_REMOVE 0x10000000 /* Target remove in process */ #define NLP_SC_REQ 0x20000000 /* Target requires authentication */ +#define NLP_RPI_VALID 0x80000000 /* nlp_rpi is valid */ /* ndlp usage management macros */ #define NLP_CHK_NODE_ACT(ndlp) (((ndlp)->nlp_usg_map \ diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index b8b34cf5c3d2..f72fdf23bf1b 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2008 Emulex. All rights reserved. * + * Copyright (C) 2004-2009 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -28,8 +28,10 @@ #include #include +#include "lpfc_hw4.h" #include "lpfc_hw.h" #include "lpfc_sli.h" +#include "lpfc_sli4.h" #include "lpfc_nl.h" #include "lpfc_disc.h" #include "lpfc_scsi.h" @@ -84,7 +86,8 @@ lpfc_els_chk_latt(struct lpfc_vport *vport) uint32_t ha_copy; if (vport->port_state >= LPFC_VPORT_READY || - phba->link_state == LPFC_LINK_DOWN) + phba->link_state == LPFC_LINK_DOWN || + phba->sli_rev > LPFC_SLI_REV3) return 0; /* Read the HBA Host Attention Register */ @@ -165,6 +168,19 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp, if (elsiocb == NULL) return NULL; + /* + * If this command is for fabric controller and HBA running + * in FIP mode send FLOGI, FDISC and LOGO as FIP frames. + */ + if ((did == Fabric_DID) && + bf_get(lpfc_fip_flag, &phba->sli4_hba.sli4_flags) && + ((elscmd == ELS_CMD_FLOGI) || + (elscmd == ELS_CMD_FDISC) || + (elscmd == ELS_CMD_LOGO))) + elsiocb->iocb_flag |= LPFC_FIP_ELS; + else + elsiocb->iocb_flag &= ~LPFC_FIP_ELS; + icmd = &elsiocb->iocb; /* fill in BDEs for command */ @@ -219,7 +235,7 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp, icmd->un.elsreq64.myID = vport->fc_myDID; /* For ELS_REQUEST64_CR, use the VPI by default */ - icmd->ulpContext = vport->vpi; + icmd->ulpContext = vport->vpi + phba->vpi_base; icmd->ulpCt_h = 0; /* The CT field must be 0=INVALID_RPI for the ECHO cmd */ if (elscmd == ELS_CMD_ECHO) @@ -305,7 +321,7 @@ els_iocb_free_pcmb_exit: * 0 - successfully issued fabric registration login for @vport * -ENXIO -- failed to issue fabric registration login for @vport **/ -static int +int lpfc_issue_fabric_reglogin(struct lpfc_vport *vport) { struct lpfc_hba *phba = vport->phba; @@ -345,8 +361,7 @@ lpfc_issue_fabric_reglogin(struct lpfc_vport *vport) err = 4; goto fail; } - rc = lpfc_reg_login(phba, vport->vpi, Fabric_DID, (uint8_t *)sp, mbox, - 0); + rc = lpfc_reg_rpi(phba, vport->vpi, Fabric_DID, (uint8_t *)sp, mbox, 0); if (rc) { err = 5; goto fail_free_mbox; @@ -385,6 +400,75 @@ fail: return -ENXIO; } +/** + * lpfc_issue_reg_vfi - Register VFI for this vport's fabric login + * @vport: pointer to a host virtual N_Port data structure. + * + * This routine issues a REG_VFI mailbox for the vfi, vpi, fcfi triplet for + * the @vport. This mailbox command is necessary for FCoE only. + * + * Return code + * 0 - successfully issued REG_VFI for @vport + * A failure code otherwise. + **/ +static int +lpfc_issue_reg_vfi(struct lpfc_vport *vport) +{ + struct lpfc_hba *phba = vport->phba; + LPFC_MBOXQ_t *mboxq; + struct lpfc_nodelist *ndlp; + struct serv_parm *sp; + struct lpfc_dmabuf *dmabuf; + int rc = 0; + + sp = &phba->fc_fabparam; + ndlp = lpfc_findnode_did(vport, Fabric_DID); + if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { + rc = -ENODEV; + goto fail; + } + + dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); + if (!dmabuf) { + rc = -ENOMEM; + goto fail; + } + dmabuf->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &dmabuf->phys); + if (!dmabuf->virt) { + rc = -ENOMEM; + goto fail_free_dmabuf; + } + mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mboxq) { + rc = -ENOMEM; + goto fail_free_coherent; + } + vport->port_state = LPFC_FABRIC_CFG_LINK; + memcpy(dmabuf->virt, &phba->fc_fabparam, sizeof(vport->fc_sparam)); + lpfc_reg_vfi(mboxq, vport, dmabuf->phys); + mboxq->mbox_cmpl = lpfc_mbx_cmpl_reg_vfi; + mboxq->vport = vport; + mboxq->context1 = dmabuf; + rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT); + if (rc == MBX_NOT_FINISHED) { + rc = -ENXIO; + goto fail_free_mbox; + } + return 0; + +fail_free_mbox: + mempool_free(mboxq, phba->mbox_mem_pool); +fail_free_coherent: + lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys); +fail_free_dmabuf: + kfree(dmabuf); +fail: + lpfc_vport_set_state(vport, FC_VPORT_FAILED); + lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + "0289 Issue Register VFI failed: Err %d\n", rc); + return rc; +} + /** * lpfc_cmpl_els_flogi_fabric - Completion function for flogi to a fabric port * @vport: pointer to a host virtual N_Port data structure. @@ -497,17 +581,24 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, } } - lpfc_nlp_set_state(vport, ndlp, NLP_STE_REG_LOGIN_ISSUE); - - if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED && - vport->fc_flag & FC_VPORT_NEEDS_REG_VPI) { - lpfc_register_new_vport(phba, vport, ndlp); - return 0; + if (phba->sli_rev < LPFC_SLI_REV4) { + lpfc_nlp_set_state(vport, ndlp, NLP_STE_REG_LOGIN_ISSUE); + if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED && + vport->fc_flag & FC_VPORT_NEEDS_REG_VPI) + lpfc_register_new_vport(phba, vport, ndlp); + else + lpfc_issue_fabric_reglogin(vport); + } else { + ndlp->nlp_type |= NLP_FABRIC; + lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); + if (vport->vfi_state & LPFC_VFI_REGISTERED) { + lpfc_start_fdiscs(phba); + lpfc_do_scr_ns_plogi(phba, vport); + } else + lpfc_issue_reg_vfi(vport); } - lpfc_issue_fabric_reglogin(vport); return 0; } - /** * lpfc_cmpl_els_flogi_nport - Completion function for flogi to an N_Port * @vport: pointer to a host virtual N_Port data structure. @@ -815,9 +906,14 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (sp->cmn.fcphHigh < FC_PH3) sp->cmn.fcphHigh = FC_PH3; - if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) { + if (phba->sli_rev == LPFC_SLI_REV4) { + elsiocb->iocb.ulpCt_h = ((SLI4_CT_FCFI >> 1) & 1); + elsiocb->iocb.ulpCt_l = (SLI4_CT_FCFI & 1); + /* FLOGI needs to be 3 for WQE FCFI */ + /* Set the fcfi to the fcfi we registered with */ + elsiocb->iocb.ulpContext = phba->fcf.fcfi; + } else if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) { sp->cmn.request_multiple_Nport = 1; - /* For FLOGI, Let FLOGI rsp set the NPortID for VPI 0 */ icmd->ulpCt_h = 1; icmd->ulpCt_l = 0; @@ -930,6 +1026,8 @@ lpfc_initial_flogi(struct lpfc_vport *vport) if (!ndlp) return 0; lpfc_nlp_init(vport, ndlp, Fabric_DID); + /* Set the node type */ + ndlp->nlp_type |= NLP_FABRIC; /* Put ndlp onto node list */ lpfc_enqueue_node(vport, ndlp); } else if (!NLP_CHK_NODE_ACT(ndlp)) { @@ -1350,14 +1448,12 @@ lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry) IOCB_t *icmd; struct lpfc_nodelist *ndlp; struct lpfc_iocbq *elsiocb; - struct lpfc_sli_ring *pring; struct lpfc_sli *psli; uint8_t *pcmd; uint16_t cmdsize; int ret; psli = &phba->sli; - pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */ ndlp = lpfc_findnode_did(vport, did); if (ndlp && !NLP_CHK_NODE_ACT(ndlp)) @@ -1391,7 +1487,7 @@ lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry) phba->fc_stat.elsXmitPLOGI++; elsiocb->iocb_cmpl = lpfc_cmpl_els_plogi; - ret = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0); + ret = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); if (ret == IOCB_ERROR) { lpfc_els_free_iocb(phba, elsiocb); @@ -1501,14 +1597,9 @@ lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, PRLI *npr; IOCB_t *icmd; struct lpfc_iocbq *elsiocb; - struct lpfc_sli_ring *pring; - struct lpfc_sli *psli; uint8_t *pcmd; uint16_t cmdsize; - psli = &phba->sli; - pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */ - cmdsize = (sizeof(uint32_t) + sizeof(PRLI)); elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, ndlp->nlp_DID, ELS_CMD_PRLI); @@ -1550,7 +1641,8 @@ lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, spin_lock_irq(shost->host_lock); ndlp->nlp_flag |= NLP_PRLI_SND; spin_unlock_irq(shost->host_lock); - if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) { + if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == + IOCB_ERROR) { spin_lock_irq(shost->host_lock); ndlp->nlp_flag &= ~NLP_PRLI_SND; spin_unlock_irq(shost->host_lock); @@ -1608,7 +1700,8 @@ lpfc_adisc_done(struct lpfc_vport *vport) * and continue discovery. */ if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) && - !(vport->fc_flag & FC_RSCN_MODE)) { + !(vport->fc_flag & FC_RSCN_MODE) && + (phba->sli_rev < LPFC_SLI_REV4)) { lpfc_issue_reg_vpi(phba, vport); return; } @@ -1788,8 +1881,6 @@ lpfc_issue_els_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ADISC *ap; IOCB_t *icmd; struct lpfc_iocbq *elsiocb; - struct lpfc_sli *psli = &phba->sli; - struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING]; uint8_t *pcmd; uint16_t cmdsize; @@ -1822,7 +1913,8 @@ lpfc_issue_els_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, spin_lock_irq(shost->host_lock); ndlp->nlp_flag |= NLP_ADISC_SND; spin_unlock_irq(shost->host_lock); - if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) { + if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == + IOCB_ERROR) { spin_lock_irq(shost->host_lock); ndlp->nlp_flag &= ~NLP_ADISC_SND; spin_unlock_irq(shost->host_lock); @@ -1937,15 +2029,10 @@ lpfc_issue_els_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, struct lpfc_hba *phba = vport->phba; IOCB_t *icmd; struct lpfc_iocbq *elsiocb; - struct lpfc_sli_ring *pring; - struct lpfc_sli *psli; uint8_t *pcmd; uint16_t cmdsize; int rc; - psli = &phba->sli; - pring = &psli->ring[LPFC_ELS_RING]; - spin_lock_irq(shost->host_lock); if (ndlp->nlp_flag & NLP_LOGO_SND) { spin_unlock_irq(shost->host_lock); @@ -1978,7 +2065,7 @@ lpfc_issue_els_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, spin_lock_irq(shost->host_lock); ndlp->nlp_flag |= NLP_LOGO_SND; spin_unlock_irq(shost->host_lock); - rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0); + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); if (rc == IOCB_ERROR) { spin_lock_irq(shost->host_lock); @@ -2058,14 +2145,12 @@ lpfc_issue_els_scr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) struct lpfc_hba *phba = vport->phba; IOCB_t *icmd; struct lpfc_iocbq *elsiocb; - struct lpfc_sli_ring *pring; struct lpfc_sli *psli; uint8_t *pcmd; uint16_t cmdsize; struct lpfc_nodelist *ndlp; psli = &phba->sli; - pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */ cmdsize = (sizeof(uint32_t) + sizeof(SCR)); ndlp = lpfc_findnode_did(vport, nportid); @@ -2108,7 +2193,8 @@ lpfc_issue_els_scr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) phba->fc_stat.elsXmitSCR++; elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd; - if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) { + if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == + IOCB_ERROR) { /* The additional lpfc_nlp_put will cause the following * lpfc_els_free_iocb routine to trigger the rlease of * the node. @@ -2152,7 +2238,6 @@ lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) struct lpfc_hba *phba = vport->phba; IOCB_t *icmd; struct lpfc_iocbq *elsiocb; - struct lpfc_sli_ring *pring; struct lpfc_sli *psli; FARP *fp; uint8_t *pcmd; @@ -2162,7 +2247,6 @@ lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) struct lpfc_nodelist *ndlp; psli = &phba->sli; - pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */ cmdsize = (sizeof(uint32_t) + sizeof(FARP)); ndlp = lpfc_findnode_did(vport, nportid); @@ -2219,7 +2303,8 @@ lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) phba->fc_stat.elsXmitFARPR++; elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd; - if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) { + if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == + IOCB_ERROR) { /* The additional lpfc_nlp_put will cause the following * lpfc_els_free_iocb routine to trigger the release of * the node. @@ -2949,6 +3034,14 @@ lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1); struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2; + /* + * This routine is used to register and unregister in previous SLI + * modes. + */ + if ((pmb->u.mb.mbxCommand == MBX_UNREG_LOGIN) && + (phba->sli_rev == LPFC_SLI_REV4)) + lpfc_sli4_free_rpi(phba, pmb->u.mb.un.varUnregLogin.rpi); + pmb->context1 = NULL; lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); @@ -2961,6 +3054,7 @@ lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) */ lpfc_nlp_not_used(ndlp); } + return; } @@ -3170,7 +3264,6 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag, IOCB_t *icmd; IOCB_t *oldcmd; struct lpfc_iocbq *elsiocb; - struct lpfc_sli_ring *pring; struct lpfc_sli *psli; uint8_t *pcmd; uint16_t cmdsize; @@ -3178,7 +3271,6 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag, ELS_PKT *els_pkt_ptr; psli = &phba->sli; - pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */ oldcmd = &oldiocb->iocb; switch (flag) { @@ -3266,7 +3358,7 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag, } phba->fc_stat.elsXmitACC++; - rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0); + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); if (rc == IOCB_ERROR) { lpfc_els_free_iocb(phba, elsiocb); return 1; @@ -3305,15 +3397,12 @@ lpfc_els_rsp_reject(struct lpfc_vport *vport, uint32_t rejectError, IOCB_t *icmd; IOCB_t *oldcmd; struct lpfc_iocbq *elsiocb; - struct lpfc_sli_ring *pring; struct lpfc_sli *psli; uint8_t *pcmd; uint16_t cmdsize; int rc; psli = &phba->sli; - pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */ - cmdsize = 2 * sizeof(uint32_t); elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp, ndlp->nlp_DID, ELS_CMD_LS_RJT); @@ -3346,7 +3435,7 @@ lpfc_els_rsp_reject(struct lpfc_vport *vport, uint32_t rejectError, phba->fc_stat.elsXmitLSRJT++; elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; - rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0); + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); if (rc == IOCB_ERROR) { lpfc_els_free_iocb(phba, elsiocb); @@ -3379,8 +3468,6 @@ lpfc_els_rsp_adisc_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp) { struct lpfc_hba *phba = vport->phba; - struct lpfc_sli *psli = &phba->sli; - struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING]; ADISC *ap; IOCB_t *icmd, *oldcmd; struct lpfc_iocbq *elsiocb; @@ -3422,7 +3509,7 @@ lpfc_els_rsp_adisc_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb, phba->fc_stat.elsXmitACC++; elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; - rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0); + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); if (rc == IOCB_ERROR) { lpfc_els_free_iocb(phba, elsiocb); return 1; @@ -3459,14 +3546,12 @@ lpfc_els_rsp_prli_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb, IOCB_t *icmd; IOCB_t *oldcmd; struct lpfc_iocbq *elsiocb; - struct lpfc_sli_ring *pring; struct lpfc_sli *psli; uint8_t *pcmd; uint16_t cmdsize; int rc; psli = &phba->sli; - pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */ cmdsize = sizeof(uint32_t) + sizeof(PRLI); elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp, @@ -3520,7 +3605,7 @@ lpfc_els_rsp_prli_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb, phba->fc_stat.elsXmitACC++; elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; - rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0); + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); if (rc == IOCB_ERROR) { lpfc_els_free_iocb(phba, elsiocb); return 1; @@ -3562,15 +3647,12 @@ lpfc_els_rsp_rnid_acc(struct lpfc_vport *vport, uint8_t format, RNID *rn; IOCB_t *icmd, *oldcmd; struct lpfc_iocbq *elsiocb; - struct lpfc_sli_ring *pring; struct lpfc_sli *psli; uint8_t *pcmd; uint16_t cmdsize; int rc; psli = &phba->sli; - pring = &psli->ring[LPFC_ELS_RING]; - cmdsize = sizeof(uint32_t) + sizeof(uint32_t) + (2 * sizeof(struct lpfc_name)); if (format) @@ -3626,7 +3708,7 @@ lpfc_els_rsp_rnid_acc(struct lpfc_vport *vport, uint8_t format, elsiocb->context1 = NULL; /* Don't need ndlp for cmpl, * it could be freed */ - rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0); + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); if (rc == IOCB_ERROR) { lpfc_els_free_iocb(phba, elsiocb); return 1; @@ -3839,7 +3921,9 @@ lpfc_rscn_payload_check(struct lpfc_vport *vport, uint32_t did) payload_len -= sizeof(uint32_t); switch (rscn_did.un.b.resv & RSCN_ADDRESS_FORMAT_MASK) { case RSCN_ADDRESS_FORMAT_PORT: - if (ns_did.un.word == rscn_did.un.word) + if ((ns_did.un.b.domain == rscn_did.un.b.domain) + && (ns_did.un.b.area == rscn_did.un.b.area) + && (ns_did.un.b.id == rscn_did.un.b.id)) goto return_did_out; break; case RSCN_ADDRESS_FORMAT_AREA: @@ -4300,7 +4384,7 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, lpfc_init_link(phba, mbox, phba->cfg_topology, phba->cfg_link_speed); - mbox->mb.un.varInitLnk.lipsr_AL_PA = 0; + mbox->u.mb.un.varInitLnk.lipsr_AL_PA = 0; mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; mbox->vport = vport; rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); @@ -4440,8 +4524,6 @@ lpfc_els_rcv_lirr(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, static void lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { - struct lpfc_sli *psli = &phba->sli; - struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING]; MAILBOX_t *mb; IOCB_t *icmd; RPS_RSP *rps_rsp; @@ -4451,7 +4533,7 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) uint16_t xri, status; uint32_t cmdsize; - mb = &pmb->mb; + mb = &pmb->u.mb; ndlp = (struct lpfc_nodelist *) pmb->context2; xri = (uint16_t) ((unsigned long)(pmb->context1)); @@ -4507,7 +4589,7 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) ndlp->nlp_rpi); elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; phba->fc_stat.elsXmitACC++; - if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) + if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == IOCB_ERROR) lpfc_els_free_iocb(phba, elsiocb); return; } @@ -4616,8 +4698,6 @@ lpfc_els_rsp_rpl_acc(struct lpfc_vport *vport, uint16_t cmdsize, IOCB_t *icmd, *oldcmd; RPL_RSP rpl_rsp; struct lpfc_iocbq *elsiocb; - struct lpfc_sli *psli = &phba->sli; - struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING]; uint8_t *pcmd; elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp, @@ -4654,7 +4734,8 @@ lpfc_els_rsp_rpl_acc(struct lpfc_vport *vport, uint16_t cmdsize, ndlp->nlp_rpi); elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; phba->fc_stat.elsXmitACC++; - if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) { + if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == + IOCB_ERROR) { lpfc_els_free_iocb(phba, elsiocb); return 1; } @@ -4883,7 +4964,10 @@ lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, } else { /* FAN verified - skip FLOGI */ vport->fc_myDID = vport->fc_prevDID; - lpfc_issue_fabric_reglogin(vport); + if (phba->sli_rev < LPFC_SLI_REV4) + lpfc_issue_fabric_reglogin(vport); + else + lpfc_issue_reg_vfi(vport); } } return 0; @@ -5566,11 +5650,10 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, dropit: if (vport && !(vport->load_flag & FC_UNLOADING)) - lpfc_printf_log(phba, KERN_ERR, LOG_ELS, - "(%d):0111 Dropping received ELS cmd " + lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + "0111 Dropping received ELS cmd " "Data: x%x x%x x%x\n", - vport->vpi, icmd->ulpStatus, - icmd->un.ulpWord[4], icmd->ulpTimeout); + icmd->ulpStatus, icmd->un.ulpWord[4], icmd->ulpTimeout); phba->fc_stat.elsRcvDrop++; } @@ -5646,10 +5729,9 @@ lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, icmd->ulpCommand == CMD_IOCB_RCV_SEQ64_CX)) { if (icmd->unsli3.rcvsli3.vpi == 0xffff) vport = phba->pport; - else { - uint16_t vpi = icmd->unsli3.rcvsli3.vpi; - vport = lpfc_find_vport_by_vpid(phba, vpi); - } + else + vport = lpfc_find_vport_by_vpid(phba, + icmd->unsli3.rcvsli3.vpi - phba->vpi_base); } /* If there are no BDEs associated * with this IOCB, there is nothing to do. @@ -5781,7 +5863,7 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) struct lpfc_vport *vport = pmb->vport; struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2; - MAILBOX_t *mb = &pmb->mb; + MAILBOX_t *mb = &pmb->u.mb; spin_lock_irq(shost->host_lock); vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI; @@ -5818,7 +5900,10 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) } else { if (vport == phba->pport) - lpfc_issue_fabric_reglogin(vport); + if (phba->sli_rev < LPFC_SLI_REV4) + lpfc_issue_fabric_reglogin(vport); + else + lpfc_issue_reg_vfi(vport); else lpfc_do_scr_ns_plogi(phba, vport); } @@ -5850,7 +5935,7 @@ lpfc_register_new_vport(struct lpfc_hba *phba, struct lpfc_vport *vport, mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (mbox) { - lpfc_reg_vpi(phba, vport->vpi, vport->fc_myDID, mbox); + lpfc_reg_vpi(vport, mbox); mbox->vport = vport; mbox->context2 = lpfc_nlp_get(ndlp); mbox->mbox_cmpl = lpfc_cmpl_reg_new_vport; @@ -6036,9 +6121,17 @@ lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, icmd->un.elsreq64.myID = 0; icmd->un.elsreq64.fl = 1; - /* For FDISC, Let FDISC rsp set the NPortID for this VPI */ - icmd->ulpCt_h = 1; - icmd->ulpCt_l = 0; + if (phba->sli_rev == LPFC_SLI_REV4) { + /* FDISC needs to be 1 for WQE VPI */ + elsiocb->iocb.ulpCt_h = (SLI4_CT_VPI >> 1) & 1; + elsiocb->iocb.ulpCt_l = SLI4_CT_VPI & 1 ; + /* Set the ulpContext to the vpi */ + elsiocb->iocb.ulpContext = vport->vpi + phba->vpi_base; + } else { + /* For FDISC, Let FDISC rsp set the NPortID for this VPI */ + icmd->ulpCt_h = 1; + icmd->ulpCt_l = 0; + } pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); *((uint32_t *) (pcmd)) = ELS_CMD_FDISC; @@ -6139,7 +6232,6 @@ lpfc_issue_els_npiv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) { struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; - struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING]; IOCB_t *icmd; struct lpfc_iocbq *elsiocb; uint8_t *pcmd; @@ -6169,7 +6261,8 @@ lpfc_issue_els_npiv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) spin_lock_irq(shost->host_lock); ndlp->nlp_flag |= NLP_LOGO_SND; spin_unlock_irq(shost->host_lock); - if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) { + if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == + IOCB_ERROR) { spin_lock_irq(shost->host_lock); ndlp->nlp_flag &= ~NLP_LOGO_SND; spin_unlock_irq(shost->host_lock); @@ -6224,7 +6317,6 @@ lpfc_resume_fabric_iocbs(struct lpfc_hba *phba) struct lpfc_iocbq *iocb; unsigned long iflags; int ret; - struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING]; IOCB_t *cmd; repeat: @@ -6248,7 +6340,7 @@ repeat: "Fabric sched1: ste:x%x", iocb->vport->port_state, 0, 0); - ret = lpfc_sli_issue_iocb(phba, pring, iocb, 0); + ret = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, iocb, 0); if (ret == IOCB_ERROR) { iocb->iocb_cmpl = iocb->fabric_iocb_cmpl; @@ -6394,7 +6486,6 @@ static int lpfc_issue_fabric_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *iocb) { unsigned long iflags; - struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING]; int ready; int ret; @@ -6418,7 +6509,7 @@ lpfc_issue_fabric_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *iocb) "Fabric sched2: ste:x%x", iocb->vport->port_state, 0, 0); - ret = lpfc_sli_issue_iocb(phba, pring, iocb, 0); + ret = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, iocb, 0); if (ret == IOCB_ERROR) { iocb->iocb_cmpl = iocb->fabric_iocb_cmpl; @@ -6524,3 +6615,38 @@ void lpfc_fabric_abort_hba(struct lpfc_hba *phba) lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT, IOERR_SLI_ABORTED); } + +/** + * lpfc_sli4_els_xri_aborted - Slow-path process of els xri abort + * @phba: pointer to lpfc hba data structure. + * @axri: pointer to the els xri abort wcqe structure. + * + * This routine is invoked by the worker thread to process a SLI4 slow-path + * ELS aborted xri. + **/ +void +lpfc_sli4_els_xri_aborted(struct lpfc_hba *phba, + struct sli4_wcqe_xri_aborted *axri) +{ + uint16_t xri = bf_get(lpfc_wcqe_xa_xri, axri); + struct lpfc_sglq *sglq_entry = NULL, *sglq_next = NULL; + unsigned long iflag = 0; + + spin_lock_irqsave(&phba->sli4_hba.abts_sgl_list_lock, iflag); + list_for_each_entry_safe(sglq_entry, sglq_next, + &phba->sli4_hba.lpfc_abts_els_sgl_list, list) { + if (sglq_entry->sli4_xritag == xri) { + list_del(&sglq_entry->list); + spin_unlock_irqrestore( + &phba->sli4_hba.abts_sgl_list_lock, + iflag); + spin_lock_irqsave(&phba->hbalock, iflag); + + list_add_tail(&sglq_entry->list, + &phba->sli4_hba.lpfc_sgl_list); + spin_unlock_irqrestore(&phba->hbalock, iflag); + return; + } + } + spin_unlock_irqrestore(&phba->sli4_hba.abts_sgl_list_lock, iflag); +} diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index e764ce0bf704..ed46b24a3380 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2008 Emulex. All rights reserved. * + * Copyright (C) 2004-2009 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -29,10 +29,12 @@ #include #include +#include "lpfc_hw4.h" #include "lpfc_hw.h" #include "lpfc_nl.h" #include "lpfc_disc.h" #include "lpfc_sli.h" +#include "lpfc_sli4.h" #include "lpfc_scsi.h" #include "lpfc.h" #include "lpfc_logmsg.h" @@ -273,6 +275,8 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) !(ndlp->nlp_flag & NLP_NPR_2B_DISC) && (ndlp->nlp_state != NLP_STE_UNMAPPED_NODE)) lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM); + + lpfc_unregister_unused_fcf(phba); } /** @@ -295,10 +299,11 @@ lpfc_alloc_fast_evt(struct lpfc_hba *phba) { ret = kzalloc(sizeof(struct lpfc_fast_path_event), GFP_ATOMIC); - if (ret) + if (ret) { atomic_inc(&phba->fast_event_count); - INIT_LIST_HEAD(&ret->work_evt.evt_listp); - ret->work_evt.evt = LPFC_EVT_FASTPATH_MGMT_EVT; + INIT_LIST_HEAD(&ret->work_evt.evt_listp); + ret->work_evt.evt = LPFC_EVT_FASTPATH_MGMT_EVT; + } return ret; } @@ -491,6 +496,10 @@ lpfc_work_done(struct lpfc_hba *phba) phba->work_ha = 0; spin_unlock_irq(&phba->hbalock); + /* First, try to post the next mailbox command to SLI4 device */ + if (phba->pci_dev_grp == LPFC_PCI_DEV_OC) + lpfc_sli4_post_async_mbox(phba); + if (ha_copy & HA_ERATT) /* Handle the error attention event */ lpfc_handle_eratt(phba); @@ -501,9 +510,27 @@ lpfc_work_done(struct lpfc_hba *phba) if (ha_copy & HA_LATT) lpfc_handle_latt(phba); + /* Process SLI4 events */ + if (phba->pci_dev_grp == LPFC_PCI_DEV_OC) { + if (phba->hba_flag & FCP_XRI_ABORT_EVENT) + lpfc_sli4_fcp_xri_abort_event_proc(phba); + if (phba->hba_flag & ELS_XRI_ABORT_EVENT) + lpfc_sli4_els_xri_abort_event_proc(phba); + if (phba->hba_flag & ASYNC_EVENT) + lpfc_sli4_async_event_proc(phba); + if (phba->hba_flag & HBA_POST_RECEIVE_BUFFER) { + spin_lock_irq(&phba->hbalock); + phba->hba_flag &= ~HBA_POST_RECEIVE_BUFFER; + spin_unlock_irq(&phba->hbalock); + lpfc_sli_hbqbuf_add_hbqs(phba, LPFC_ELS_HBQ); + } + if (phba->hba_flag & HBA_RECEIVE_BUFFER) + lpfc_sli4_handle_received_buffer(phba); + } + vports = lpfc_create_vport_work_array(phba); if (vports != NULL) - for(i = 0; i <= phba->max_vpi; i++) { + for (i = 0; i <= phba->max_vports; i++) { /* * We could have no vports in array if unloading, so if * this happens then just use the pport @@ -555,23 +582,24 @@ lpfc_work_done(struct lpfc_hba *phba) /* * Turn on Ring interrupts */ - spin_lock_irq(&phba->hbalock); - control = readl(phba->HCregaddr); - if (!(control & (HC_R0INT_ENA << LPFC_ELS_RING))) { - lpfc_debugfs_slow_ring_trc(phba, - "WRK Enable ring: cntl:x%x hacopy:x%x", - control, ha_copy, 0); + if (phba->sli_rev <= LPFC_SLI_REV3) { + spin_lock_irq(&phba->hbalock); + control = readl(phba->HCregaddr); + if (!(control & (HC_R0INT_ENA << LPFC_ELS_RING))) { + lpfc_debugfs_slow_ring_trc(phba, + "WRK Enable ring: cntl:x%x hacopy:x%x", + control, ha_copy, 0); - control |= (HC_R0INT_ENA << LPFC_ELS_RING); - writel(control, phba->HCregaddr); - readl(phba->HCregaddr); /* flush */ + control |= (HC_R0INT_ENA << LPFC_ELS_RING); + writel(control, phba->HCregaddr); + readl(phba->HCregaddr); /* flush */ + } else { + lpfc_debugfs_slow_ring_trc(phba, + "WRK Ring ok: cntl:x%x hacopy:x%x", + control, ha_copy, 0); + } + spin_unlock_irq(&phba->hbalock); } - else { - lpfc_debugfs_slow_ring_trc(phba, - "WRK Ring ok: cntl:x%x hacopy:x%x", - control, ha_copy, 0); - } - spin_unlock_irq(&phba->hbalock); } lpfc_work_list_done(phba); } @@ -689,7 +717,7 @@ lpfc_port_link_failure(struct lpfc_vport *vport) lpfc_can_disctmo(vport); } -static void +void lpfc_linkdown_port(struct lpfc_vport *vport) { struct Scsi_Host *shost = lpfc_shost_from_vport(vport); @@ -716,6 +744,7 @@ lpfc_linkdown(struct lpfc_hba *phba) if (phba->link_state == LPFC_LINK_DOWN) return 0; spin_lock_irq(&phba->hbalock); + phba->fcf.fcf_flag &= ~(FCF_AVAILABLE | FCF_DISCOVERED); if (phba->link_state > LPFC_LINK_DOWN) { phba->link_state = LPFC_LINK_DOWN; phba->pport->fc_flag &= ~FC_LBIT; @@ -723,7 +752,7 @@ lpfc_linkdown(struct lpfc_hba *phba) spin_unlock_irq(&phba->hbalock); vports = lpfc_create_vport_work_array(phba); if (vports != NULL) - for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { + for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { /* Issue a LINK DOWN event to all nodes */ lpfc_linkdown_port(vports[i]); } @@ -833,10 +862,11 @@ lpfc_linkup(struct lpfc_hba *phba) vports = lpfc_create_vport_work_array(phba); if (vports != NULL) - for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) + for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) lpfc_linkup_port(vports[i]); lpfc_destroy_vport_work_array(phba, vports); - if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) + if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) && + (phba->sli_rev < LPFC_SLI_REV4)) lpfc_issue_clear_la(phba, phba->pport); return 0; @@ -854,7 +884,7 @@ lpfc_mbx_cmpl_clear_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) struct lpfc_vport *vport = pmb->vport; struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_sli *psli = &phba->sli; - MAILBOX_t *mb = &pmb->mb; + MAILBOX_t *mb = &pmb->u.mb; uint32_t control; /* Since we don't do discovery right now, turn these off here */ @@ -917,7 +947,7 @@ lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { struct lpfc_vport *vport = pmb->vport; - if (pmb->mb.mbxStatus) + if (pmb->u.mb.mbxStatus) goto out; mempool_free(pmb, phba->mbox_mem_pool); @@ -945,7 +975,7 @@ out: lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, "0306 CONFIG_LINK mbxStatus error x%x " "HBA state x%x\n", - pmb->mb.mbxStatus, vport->port_state); + pmb->u.mb.mbxStatus, vport->port_state); mempool_free(pmb, phba->mbox_mem_pool); lpfc_linkdown(phba); @@ -958,10 +988,613 @@ out: return; } +static void +lpfc_mbx_cmpl_reg_fcfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) +{ + struct lpfc_vport *vport = mboxq->vport; + unsigned long flags; + + if (mboxq->u.mb.mbxStatus) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, + "2017 REG_FCFI mbxStatus error x%x " + "HBA state x%x\n", + mboxq->u.mb.mbxStatus, vport->port_state); + mempool_free(mboxq, phba->mbox_mem_pool); + return; + } + + /* Start FCoE discovery by sending a FLOGI. */ + phba->fcf.fcfi = bf_get(lpfc_reg_fcfi_fcfi, &mboxq->u.mqe.un.reg_fcfi); + /* Set the FCFI registered flag */ + spin_lock_irqsave(&phba->hbalock, flags); + phba->fcf.fcf_flag |= FCF_REGISTERED; + spin_unlock_irqrestore(&phba->hbalock, flags); + if (vport->port_state != LPFC_FLOGI) { + spin_lock_irqsave(&phba->hbalock, flags); + phba->fcf.fcf_flag |= (FCF_DISCOVERED | FCF_IN_USE); + spin_unlock_irqrestore(&phba->hbalock, flags); + lpfc_initial_flogi(vport); + } + + mempool_free(mboxq, phba->mbox_mem_pool); + return; +} + +/** + * lpfc_fab_name_match - Check if the fcf fabric name match. + * @fab_name: pointer to fabric name. + * @new_fcf_record: pointer to fcf record. + * + * This routine compare the fcf record's fabric name with provided + * fabric name. If the fabric name are identical this function + * returns 1 else return 0. + **/ +static uint32_t +lpfc_fab_name_match(uint8_t *fab_name, struct fcf_record *new_fcf_record) +{ + if ((fab_name[0] == + bf_get(lpfc_fcf_record_fab_name_0, new_fcf_record)) && + (fab_name[1] == + bf_get(lpfc_fcf_record_fab_name_1, new_fcf_record)) && + (fab_name[2] == + bf_get(lpfc_fcf_record_fab_name_2, new_fcf_record)) && + (fab_name[3] == + bf_get(lpfc_fcf_record_fab_name_3, new_fcf_record)) && + (fab_name[4] == + bf_get(lpfc_fcf_record_fab_name_4, new_fcf_record)) && + (fab_name[5] == + bf_get(lpfc_fcf_record_fab_name_5, new_fcf_record)) && + (fab_name[6] == + bf_get(lpfc_fcf_record_fab_name_6, new_fcf_record)) && + (fab_name[7] == + bf_get(lpfc_fcf_record_fab_name_7, new_fcf_record))) + return 1; + else + return 0; +} + +/** + * lpfc_mac_addr_match - Check if the fcf mac address match. + * @phba: pointer to lpfc hba data structure. + * @new_fcf_record: pointer to fcf record. + * + * This routine compare the fcf record's mac address with HBA's + * FCF mac address. If the mac addresses are identical this function + * returns 1 else return 0. + **/ +static uint32_t +lpfc_mac_addr_match(struct lpfc_hba *phba, struct fcf_record *new_fcf_record) +{ + if ((phba->fcf.mac_addr[0] == + bf_get(lpfc_fcf_record_mac_0, new_fcf_record)) && + (phba->fcf.mac_addr[1] == + bf_get(lpfc_fcf_record_mac_1, new_fcf_record)) && + (phba->fcf.mac_addr[2] == + bf_get(lpfc_fcf_record_mac_2, new_fcf_record)) && + (phba->fcf.mac_addr[3] == + bf_get(lpfc_fcf_record_mac_3, new_fcf_record)) && + (phba->fcf.mac_addr[4] == + bf_get(lpfc_fcf_record_mac_4, new_fcf_record)) && + (phba->fcf.mac_addr[5] == + bf_get(lpfc_fcf_record_mac_5, new_fcf_record))) + return 1; + else + return 0; +} + +/** + * lpfc_copy_fcf_record - Copy fcf information to lpfc_hba. + * @phba: pointer to lpfc hba data structure. + * @new_fcf_record: pointer to fcf record. + * + * This routine copies the FCF information from the FCF + * record to lpfc_hba data structure. + **/ +static void +lpfc_copy_fcf_record(struct lpfc_hba *phba, struct fcf_record *new_fcf_record) +{ + phba->fcf.fabric_name[0] = + bf_get(lpfc_fcf_record_fab_name_0, new_fcf_record); + phba->fcf.fabric_name[1] = + bf_get(lpfc_fcf_record_fab_name_1, new_fcf_record); + phba->fcf.fabric_name[2] = + bf_get(lpfc_fcf_record_fab_name_2, new_fcf_record); + phba->fcf.fabric_name[3] = + bf_get(lpfc_fcf_record_fab_name_3, new_fcf_record); + phba->fcf.fabric_name[4] = + bf_get(lpfc_fcf_record_fab_name_4, new_fcf_record); + phba->fcf.fabric_name[5] = + bf_get(lpfc_fcf_record_fab_name_5, new_fcf_record); + phba->fcf.fabric_name[6] = + bf_get(lpfc_fcf_record_fab_name_6, new_fcf_record); + phba->fcf.fabric_name[7] = + bf_get(lpfc_fcf_record_fab_name_7, new_fcf_record); + phba->fcf.mac_addr[0] = + bf_get(lpfc_fcf_record_mac_0, new_fcf_record); + phba->fcf.mac_addr[1] = + bf_get(lpfc_fcf_record_mac_1, new_fcf_record); + phba->fcf.mac_addr[2] = + bf_get(lpfc_fcf_record_mac_2, new_fcf_record); + phba->fcf.mac_addr[3] = + bf_get(lpfc_fcf_record_mac_3, new_fcf_record); + phba->fcf.mac_addr[4] = + bf_get(lpfc_fcf_record_mac_4, new_fcf_record); + phba->fcf.mac_addr[5] = + bf_get(lpfc_fcf_record_mac_5, new_fcf_record); + phba->fcf.fcf_indx = bf_get(lpfc_fcf_record_fcf_index, new_fcf_record); + phba->fcf.priority = new_fcf_record->fip_priority; +} + +/** + * lpfc_register_fcf - Register the FCF with hba. + * @phba: pointer to lpfc hba data structure. + * + * This routine issues a register fcfi mailbox command to register + * the fcf with HBA. + **/ +static void +lpfc_register_fcf(struct lpfc_hba *phba) +{ + LPFC_MBOXQ_t *fcf_mbxq; + int rc; + unsigned long flags; + + spin_lock_irqsave(&phba->hbalock, flags); + + /* If the FCF is not availabe do nothing. */ + if (!(phba->fcf.fcf_flag & FCF_AVAILABLE)) { + spin_unlock_irqrestore(&phba->hbalock, flags); + return; + } + + /* The FCF is already registered, start discovery */ + if (phba->fcf.fcf_flag & FCF_REGISTERED) { + phba->fcf.fcf_flag |= (FCF_DISCOVERED | FCF_IN_USE); + spin_unlock_irqrestore(&phba->hbalock, flags); + if (phba->pport->port_state != LPFC_FLOGI) + lpfc_initial_flogi(phba->pport); + return; + } + spin_unlock_irqrestore(&phba->hbalock, flags); + + fcf_mbxq = mempool_alloc(phba->mbox_mem_pool, + GFP_KERNEL); + if (!fcf_mbxq) + return; + + lpfc_reg_fcfi(phba, fcf_mbxq); + fcf_mbxq->vport = phba->pport; + fcf_mbxq->mbox_cmpl = lpfc_mbx_cmpl_reg_fcfi; + rc = lpfc_sli_issue_mbox(phba, fcf_mbxq, MBX_NOWAIT); + if (rc == MBX_NOT_FINISHED) + mempool_free(fcf_mbxq, phba->mbox_mem_pool); + + return; +} + +/** + * lpfc_match_fcf_conn_list - Check if the FCF record can be used for discovery. + * @phba: pointer to lpfc hba data structure. + * @new_fcf_record: pointer to fcf record. + * @boot_flag: Indicates if this record used by boot bios. + * @addr_mode: The address mode to be used by this FCF + * + * This routine compare the fcf record with connect list obtained from the + * config region to decide if this FCF can be used for SAN discovery. It returns + * 1 if this record can be used for SAN discovery else return zero. If this FCF + * record can be used for SAN discovery, the boot_flag will indicate if this FCF + * is used by boot bios and addr_mode will indicate the addressing mode to be + * used for this FCF when the function returns. + * If the FCF record need to be used with a particular vlan id, the vlan is + * set in the vlan_id on return of the function. If not VLAN tagging need to + * be used with the FCF vlan_id will be set to 0xFFFF; + **/ +static int +lpfc_match_fcf_conn_list(struct lpfc_hba *phba, + struct fcf_record *new_fcf_record, + uint32_t *boot_flag, uint32_t *addr_mode, + uint16_t *vlan_id) +{ + struct lpfc_fcf_conn_entry *conn_entry; + + /* If FCF not available return 0 */ + if (!bf_get(lpfc_fcf_record_fcf_avail, new_fcf_record) || + !bf_get(lpfc_fcf_record_fcf_valid, new_fcf_record)) + return 0; + + if (!phba->cfg_enable_fip) { + *boot_flag = 0; + *addr_mode = bf_get(lpfc_fcf_record_mac_addr_prov, + new_fcf_record); + if (phba->valid_vlan) + *vlan_id = phba->vlan_id; + else + *vlan_id = 0xFFFF; + return 1; + } + + /* + * If there are no FCF connection table entry, driver connect to all + * FCFs. + */ + if (list_empty(&phba->fcf_conn_rec_list)) { + *boot_flag = 0; + *addr_mode = bf_get(lpfc_fcf_record_mac_addr_prov, + new_fcf_record); + + /* + * When there are no FCF connect entries, use driver's default + * addressing mode - FPMA. + */ + if (*addr_mode & LPFC_FCF_FPMA) + *addr_mode = LPFC_FCF_FPMA; + + *vlan_id = 0xFFFF; + return 1; + } + + list_for_each_entry(conn_entry, &phba->fcf_conn_rec_list, list) { + if (!(conn_entry->conn_rec.flags & FCFCNCT_VALID)) + continue; + + if ((conn_entry->conn_rec.flags & FCFCNCT_FBNM_VALID) && + !lpfc_fab_name_match(conn_entry->conn_rec.fabric_name, + new_fcf_record)) + continue; + + if (conn_entry->conn_rec.flags & FCFCNCT_VLAN_VALID) { + /* + * If the vlan bit map does not have the bit set for the + * vlan id to be used, then it is not a match. + */ + if (!(new_fcf_record->vlan_bitmap + [conn_entry->conn_rec.vlan_tag / 8] & + (1 << (conn_entry->conn_rec.vlan_tag % 8)))) + continue; + } + + /* + * If connection record does not support any addressing mode, + * skip the FCF record. + */ + if (!(bf_get(lpfc_fcf_record_mac_addr_prov, new_fcf_record) + & (LPFC_FCF_FPMA | LPFC_FCF_SPMA))) + continue; + + /* + * Check if the connection record specifies a required + * addressing mode. + */ + if ((conn_entry->conn_rec.flags & FCFCNCT_AM_VALID) && + !(conn_entry->conn_rec.flags & FCFCNCT_AM_PREFERRED)) { + + /* + * If SPMA required but FCF not support this continue. + */ + if ((conn_entry->conn_rec.flags & FCFCNCT_AM_SPMA) && + !(bf_get(lpfc_fcf_record_mac_addr_prov, + new_fcf_record) & LPFC_FCF_SPMA)) + continue; + + /* + * If FPMA required but FCF not support this continue. + */ + if (!(conn_entry->conn_rec.flags & FCFCNCT_AM_SPMA) && + !(bf_get(lpfc_fcf_record_mac_addr_prov, + new_fcf_record) & LPFC_FCF_FPMA)) + continue; + } + + /* + * This fcf record matches filtering criteria. + */ + if (conn_entry->conn_rec.flags & FCFCNCT_BOOT) + *boot_flag = 1; + else + *boot_flag = 0; + + /* + * If user did not specify any addressing mode, or if the + * prefered addressing mode specified by user is not supported + * by FCF, allow fabric to pick the addressing mode. + */ + *addr_mode = bf_get(lpfc_fcf_record_mac_addr_prov, + new_fcf_record); + /* + * If the user specified a required address mode, assign that + * address mode + */ + if ((conn_entry->conn_rec.flags & FCFCNCT_AM_VALID) && + (!(conn_entry->conn_rec.flags & FCFCNCT_AM_PREFERRED))) + *addr_mode = (conn_entry->conn_rec.flags & + FCFCNCT_AM_SPMA) ? + LPFC_FCF_SPMA : LPFC_FCF_FPMA; + /* + * If the user specified a prefered address mode, use the + * addr mode only if FCF support the addr_mode. + */ + else if ((conn_entry->conn_rec.flags & FCFCNCT_AM_VALID) && + (conn_entry->conn_rec.flags & FCFCNCT_AM_PREFERRED) && + (conn_entry->conn_rec.flags & FCFCNCT_AM_SPMA) && + (*addr_mode & LPFC_FCF_SPMA)) + *addr_mode = LPFC_FCF_SPMA; + else if ((conn_entry->conn_rec.flags & FCFCNCT_AM_VALID) && + (conn_entry->conn_rec.flags & FCFCNCT_AM_PREFERRED) && + !(conn_entry->conn_rec.flags & FCFCNCT_AM_SPMA) && + (*addr_mode & LPFC_FCF_FPMA)) + *addr_mode = LPFC_FCF_FPMA; + + if (conn_entry->conn_rec.flags & FCFCNCT_VLAN_VALID) + *vlan_id = conn_entry->conn_rec.vlan_tag; + else + *vlan_id = 0xFFFF; + + return 1; + } + + return 0; +} + +/** + * lpfc_mbx_cmpl_read_fcf_record - Completion handler for read_fcf mbox. + * @phba: pointer to lpfc hba data structure. + * @mboxq: pointer to mailbox object. + * + * This function iterate through all the fcf records available in + * HBA and choose the optimal FCF record for discovery. After finding + * the FCF for discovery it register the FCF record and kick start + * discovery. + * If FCF_IN_USE flag is set in currently used FCF, the routine try to + * use a FCF record which match fabric name and mac address of the + * currently used FCF record. + * If the driver support only one FCF, it will try to use the FCF record + * used by BOOT_BIOS. + */ +void +lpfc_mbx_cmpl_read_fcf_record(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) +{ + void *virt_addr; + dma_addr_t phys_addr; + uint8_t *bytep; + struct lpfc_mbx_sge sge; + struct lpfc_mbx_read_fcf_tbl *read_fcf; + uint32_t shdr_status, shdr_add_status; + union lpfc_sli4_cfg_shdr *shdr; + struct fcf_record *new_fcf_record; + int rc; + uint32_t boot_flag, addr_mode; + uint32_t next_fcf_index; + unsigned long flags; + uint16_t vlan_id; + + /* Get the first SGE entry from the non-embedded DMA memory. This + * routine only uses a single SGE. + */ + lpfc_sli4_mbx_sge_get(mboxq, 0, &sge); + phys_addr = getPaddr(sge.pa_hi, sge.pa_lo); + if (unlikely(!mboxq->sge_array)) { + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, + "2524 Failed to get the non-embedded SGE " + "virtual address\n"); + goto out; + } + virt_addr = mboxq->sge_array->addr[0]; + + shdr = (union lpfc_sli4_cfg_shdr *)virt_addr; + shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); + shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, + &shdr->response); + /* + * The FCF Record was read and there is no reason for the driver + * to maintain the FCF record data or memory. Instead, just need + * to book keeping the FCFIs can be used. + */ + if (shdr_status || shdr_add_status) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2521 READ_FCF_RECORD mailbox failed " + "with status x%x add_status x%x, mbx\n", + shdr_status, shdr_add_status); + goto out; + } + /* Interpreting the returned information of FCF records */ + read_fcf = (struct lpfc_mbx_read_fcf_tbl *)virt_addr; + lpfc_sli_pcimem_bcopy(read_fcf, read_fcf, + sizeof(struct lpfc_mbx_read_fcf_tbl)); + next_fcf_index = bf_get(lpfc_mbx_read_fcf_tbl_nxt_vindx, read_fcf); + + new_fcf_record = (struct fcf_record *)(virt_addr + + sizeof(struct lpfc_mbx_read_fcf_tbl)); + lpfc_sli_pcimem_bcopy(new_fcf_record, new_fcf_record, + sizeof(struct fcf_record)); + bytep = virt_addr + sizeof(union lpfc_sli4_cfg_shdr); + + rc = lpfc_match_fcf_conn_list(phba, new_fcf_record, + &boot_flag, &addr_mode, + &vlan_id); + /* + * If the fcf record does not match with connect list entries + * read the next entry. + */ + if (!rc) + goto read_next_fcf; + /* + * If this is not the first FCF discovery of the HBA, use last + * FCF record for the discovery. + */ + spin_lock_irqsave(&phba->hbalock, flags); + if (phba->fcf.fcf_flag & FCF_IN_USE) { + if (lpfc_fab_name_match(phba->fcf.fabric_name, + new_fcf_record) && + lpfc_mac_addr_match(phba, new_fcf_record)) { + phba->fcf.fcf_flag |= FCF_AVAILABLE; + spin_unlock_irqrestore(&phba->hbalock, flags); + goto out; + } + spin_unlock_irqrestore(&phba->hbalock, flags); + goto read_next_fcf; + } + if (phba->fcf.fcf_flag & FCF_AVAILABLE) { + /* + * If the current FCF record does not have boot flag + * set and new fcf record has boot flag set, use the + * new fcf record. + */ + if (boot_flag && !(phba->fcf.fcf_flag & FCF_BOOT_ENABLE)) { + /* Use this FCF record */ + lpfc_copy_fcf_record(phba, new_fcf_record); + phba->fcf.addr_mode = addr_mode; + phba->fcf.fcf_flag |= FCF_BOOT_ENABLE; + if (vlan_id != 0xFFFF) { + phba->fcf.fcf_flag |= FCF_VALID_VLAN; + phba->fcf.vlan_id = vlan_id; + } + spin_unlock_irqrestore(&phba->hbalock, flags); + goto read_next_fcf; + } + /* + * If the current FCF record has boot flag set and the + * new FCF record does not have boot flag, read the next + * FCF record. + */ + if (!boot_flag && (phba->fcf.fcf_flag & FCF_BOOT_ENABLE)) { + spin_unlock_irqrestore(&phba->hbalock, flags); + goto read_next_fcf; + } + /* + * If there is a record with lower priority value for + * the current FCF, use that record. + */ + if (lpfc_fab_name_match(phba->fcf.fabric_name, new_fcf_record) + && (new_fcf_record->fip_priority < + phba->fcf.priority)) { + /* Use this FCF record */ + lpfc_copy_fcf_record(phba, new_fcf_record); + phba->fcf.addr_mode = addr_mode; + if (vlan_id != 0xFFFF) { + phba->fcf.fcf_flag |= FCF_VALID_VLAN; + phba->fcf.vlan_id = vlan_id; + } + spin_unlock_irqrestore(&phba->hbalock, flags); + goto read_next_fcf; + } + spin_unlock_irqrestore(&phba->hbalock, flags); + goto read_next_fcf; + } + /* + * This is the first available FCF record, use this + * record. + */ + lpfc_copy_fcf_record(phba, new_fcf_record); + phba->fcf.addr_mode = addr_mode; + if (boot_flag) + phba->fcf.fcf_flag |= FCF_BOOT_ENABLE; + phba->fcf.fcf_flag |= FCF_AVAILABLE; + if (vlan_id != 0xFFFF) { + phba->fcf.fcf_flag |= FCF_VALID_VLAN; + phba->fcf.vlan_id = vlan_id; + } + spin_unlock_irqrestore(&phba->hbalock, flags); + goto read_next_fcf; + +read_next_fcf: + lpfc_sli4_mbox_cmd_free(phba, mboxq); + if (next_fcf_index == LPFC_FCOE_FCF_NEXT_NONE || next_fcf_index == 0) + lpfc_register_fcf(phba); + else + lpfc_sli4_read_fcf_record(phba, next_fcf_index); + return; + +out: + lpfc_sli4_mbox_cmd_free(phba, mboxq); + lpfc_register_fcf(phba); + + return; +} + +/** + * lpfc_start_fdiscs - send fdiscs for each vports on this port. + * @phba: pointer to lpfc hba data structure. + * + * This function loops through the list of vports on the @phba and issues an + * FDISC if possible. + */ +void +lpfc_start_fdiscs(struct lpfc_hba *phba) +{ + struct lpfc_vport **vports; + int i; + + vports = lpfc_create_vport_work_array(phba); + if (vports != NULL) { + for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { + if (vports[i]->port_type == LPFC_PHYSICAL_PORT) + continue; + /* There are no vpi for this vport */ + if (vports[i]->vpi > phba->max_vpi) { + lpfc_vport_set_state(vports[i], + FC_VPORT_FAILED); + continue; + } + if (phba->fc_topology == TOPOLOGY_LOOP) { + lpfc_vport_set_state(vports[i], + FC_VPORT_LINKDOWN); + continue; + } + if (phba->link_flag & LS_NPIV_FAB_SUPPORTED) + lpfc_initial_fdisc(vports[i]); + else { + lpfc_vport_set_state(vports[i], + FC_VPORT_NO_FABRIC_SUPP); + lpfc_printf_vlog(vports[i], KERN_ERR, + LOG_ELS, + "0259 No NPIV " + "Fabric support\n"); + } + } + } + lpfc_destroy_vport_work_array(phba, vports); +} + +void +lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) +{ + struct lpfc_dmabuf *dmabuf = mboxq->context1; + struct lpfc_vport *vport = mboxq->vport; + + if (mboxq->u.mb.mbxStatus) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, + "2018 REG_VFI mbxStatus error x%x " + "HBA state x%x\n", + mboxq->u.mb.mbxStatus, vport->port_state); + if (phba->fc_topology == TOPOLOGY_LOOP) { + /* FLOGI failed, use loop map to make discovery list */ + lpfc_disc_list_loopmap(vport); + /* Start discovery */ + lpfc_disc_start(vport); + goto fail_free_mem; + } + lpfc_vport_set_state(vport, FC_VPORT_FAILED); + goto fail_free_mem; + } + /* Mark the vport has registered with its VFI */ + vport->vfi_state |= LPFC_VFI_REGISTERED; + + if (vport->port_state == LPFC_FABRIC_CFG_LINK) { + lpfc_start_fdiscs(phba); + lpfc_do_scr_ns_plogi(phba, vport); + } + +fail_free_mem: + mempool_free(mboxq, phba->mbox_mem_pool); + lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys); + kfree(dmabuf); + return; +} + static void lpfc_mbx_cmpl_read_sparam(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { - MAILBOX_t *mb = &pmb->mb; + MAILBOX_t *mb = &pmb->u.mb; struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) pmb->context1; struct lpfc_vport *vport = pmb->vport; @@ -1012,13 +1645,13 @@ static void lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la) { struct lpfc_vport *vport = phba->pport; - LPFC_MBOXQ_t *sparam_mbox, *cfglink_mbox; + LPFC_MBOXQ_t *sparam_mbox, *cfglink_mbox = NULL; int i; struct lpfc_dmabuf *mp; int rc; + struct fcf_record *fcf_record; sparam_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - cfglink_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); spin_lock_irq(&phba->hbalock); switch (la->UlnkSpeed) { @@ -1034,6 +1667,9 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la) case LA_8GHZ_LINK: phba->fc_linkspeed = LA_8GHZ_LINK; break; + case LA_10GHZ_LINK: + phba->fc_linkspeed = LA_10GHZ_LINK; + break; default: phba->fc_linkspeed = LA_UNKNW_LINK; break; @@ -1115,22 +1751,66 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la) lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); mempool_free(sparam_mbox, phba->mbox_mem_pool); - if (cfglink_mbox) - mempool_free(cfglink_mbox, phba->mbox_mem_pool); goto out; } } - if (cfglink_mbox) { + if (!(phba->hba_flag & HBA_FCOE_SUPPORT)) { + cfglink_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!cfglink_mbox) + goto out; vport->port_state = LPFC_LOCAL_CFG_LINK; lpfc_config_link(phba, cfglink_mbox); cfglink_mbox->vport = vport; cfglink_mbox->mbox_cmpl = lpfc_mbx_cmpl_local_config_link; rc = lpfc_sli_issue_mbox(phba, cfglink_mbox, MBX_NOWAIT); - if (rc != MBX_NOT_FINISHED) - return; - mempool_free(cfglink_mbox, phba->mbox_mem_pool); + if (rc == MBX_NOT_FINISHED) { + mempool_free(cfglink_mbox, phba->mbox_mem_pool); + goto out; + } + } else { + /* + * Add the driver's default FCF record at FCF index 0 now. This + * is phase 1 implementation that support FCF index 0 and driver + * defaults. + */ + if (phba->cfg_enable_fip == 0) { + fcf_record = kzalloc(sizeof(struct fcf_record), + GFP_KERNEL); + if (unlikely(!fcf_record)) { + lpfc_printf_log(phba, KERN_ERR, + LOG_MBOX | LOG_SLI, + "2554 Could not allocate memmory for " + "fcf record\n"); + rc = -ENODEV; + goto out; + } + + lpfc_sli4_build_dflt_fcf_record(phba, fcf_record, + LPFC_FCOE_FCF_DEF_INDEX); + rc = lpfc_sli4_add_fcf_record(phba, fcf_record); + if (unlikely(rc)) { + lpfc_printf_log(phba, KERN_ERR, + LOG_MBOX | LOG_SLI, + "2013 Could not manually add FCF " + "record 0, status %d\n", rc); + rc = -ENODEV; + kfree(fcf_record); + goto out; + } + kfree(fcf_record); + } + /* + * The driver is expected to do FIP/FCF. Call the port + * and get the FCF Table. + */ + rc = lpfc_sli4_read_fcf_record(phba, + LPFC_FCOE_FCF_GET_FIRST); + if (rc) + goto out; } + + return; out: lpfc_vport_set_state(vport, FC_VPORT_FAILED); lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, @@ -1147,10 +1827,12 @@ lpfc_enable_la(struct lpfc_hba *phba) struct lpfc_sli *psli = &phba->sli; spin_lock_irq(&phba->hbalock); psli->sli_flag |= LPFC_PROCESS_LA; - control = readl(phba->HCregaddr); - control |= HC_LAINT_ENA; - writel(control, phba->HCregaddr); - readl(phba->HCregaddr); /* flush */ + if (phba->sli_rev <= LPFC_SLI_REV3) { + control = readl(phba->HCregaddr); + control |= HC_LAINT_ENA; + writel(control, phba->HCregaddr); + readl(phba->HCregaddr); /* flush */ + } spin_unlock_irq(&phba->hbalock); } @@ -1159,6 +1841,7 @@ lpfc_mbx_issue_link_down(struct lpfc_hba *phba) { lpfc_linkdown(phba); lpfc_enable_la(phba); + lpfc_unregister_unused_fcf(phba); /* turn on Link Attention interrupts - no CLEAR_LA needed */ } @@ -1175,7 +1858,7 @@ lpfc_mbx_cmpl_read_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) struct lpfc_vport *vport = pmb->vport; struct Scsi_Host *shost = lpfc_shost_from_vport(vport); READ_LA_VAR *la; - MAILBOX_t *mb = &pmb->mb; + MAILBOX_t *mb = &pmb->u.mb; struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1); /* Unblock ELS traffic */ @@ -1190,7 +1873,7 @@ lpfc_mbx_cmpl_read_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) goto lpfc_mbx_cmpl_read_la_free_mbuf; } - la = (READ_LA_VAR *) & pmb->mb.un.varReadLA; + la = (READ_LA_VAR *) &pmb->u.mb.un.varReadLA; memcpy(&phba->alpa_map[0], mp->virt, 128); @@ -1201,7 +1884,7 @@ lpfc_mbx_cmpl_read_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) vport->fc_flag &= ~FC_BYPASSED_MODE; spin_unlock_irq(shost->host_lock); - if (((phba->fc_eventTag + 1) < la->eventTag) || + if ((phba->fc_eventTag < la->eventTag) || (phba->fc_eventTag == la->eventTag)) { phba->fc_stat.LinkMultiEvent++; if (la->attType == AT_LINK_UP) @@ -1328,7 +2011,7 @@ lpfc_mbx_cmpl_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) static void lpfc_mbx_cmpl_unreg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { - MAILBOX_t *mb = &pmb->mb; + MAILBOX_t *mb = &pmb->u.mb; struct lpfc_vport *vport = pmb->vport; struct Scsi_Host *shost = lpfc_shost_from_vport(vport); @@ -1381,7 +2064,7 @@ lpfc_mbx_cmpl_reg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { struct lpfc_vport *vport = pmb->vport; struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - MAILBOX_t *mb = &pmb->mb; + MAILBOX_t *mb = &pmb->u.mb; switch (mb->mbxStatus) { case 0x0011: @@ -1416,6 +2099,128 @@ out: return; } +/** + * lpfc_create_static_vport - Read HBA config region to create static vports. + * @phba: pointer to lpfc hba data structure. + * + * This routine issue a DUMP mailbox command for config region 22 to get + * the list of static vports to be created. The function create vports + * based on the information returned from the HBA. + **/ +void +lpfc_create_static_vport(struct lpfc_hba *phba) +{ + LPFC_MBOXQ_t *pmb = NULL; + MAILBOX_t *mb; + struct static_vport_info *vport_info; + int rc, i; + struct fc_vport_identifiers vport_id; + struct fc_vport *new_fc_vport; + struct Scsi_Host *shost; + struct lpfc_vport *vport; + uint16_t offset = 0; + uint8_t *vport_buff; + + pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!pmb) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0542 lpfc_create_static_vport failed to" + " allocate mailbox memory\n"); + return; + } + + mb = &pmb->u.mb; + + vport_info = kzalloc(sizeof(struct static_vport_info), GFP_KERNEL); + if (!vport_info) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0543 lpfc_create_static_vport failed to" + " allocate vport_info\n"); + mempool_free(pmb, phba->mbox_mem_pool); + return; + } + + vport_buff = (uint8_t *) vport_info; + do { + lpfc_dump_static_vport(phba, pmb, offset); + pmb->vport = phba->pport; + rc = lpfc_sli_issue_mbox_wait(phba, pmb, LPFC_MBOX_TMO); + + if ((rc != MBX_SUCCESS) || mb->mbxStatus) { + lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, + "0544 lpfc_create_static_vport failed to" + " issue dump mailbox command ret 0x%x " + "status 0x%x\n", + rc, mb->mbxStatus); + goto out; + } + + if (mb->un.varDmp.word_cnt > + sizeof(struct static_vport_info) - offset) + mb->un.varDmp.word_cnt = + sizeof(struct static_vport_info) - offset; + + lpfc_sli_pcimem_bcopy(((uint8_t *)mb) + DMP_RSP_OFFSET, + vport_buff + offset, + mb->un.varDmp.word_cnt); + offset += mb->un.varDmp.word_cnt; + + } while (mb->un.varDmp.word_cnt && + offset < sizeof(struct static_vport_info)); + + + if ((le32_to_cpu(vport_info->signature) != VPORT_INFO_SIG) || + ((le32_to_cpu(vport_info->rev) & VPORT_INFO_REV_MASK) + != VPORT_INFO_REV)) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0545 lpfc_create_static_vport bad" + " information header 0x%x 0x%x\n", + le32_to_cpu(vport_info->signature), + le32_to_cpu(vport_info->rev) & VPORT_INFO_REV_MASK); + + goto out; + } + + shost = lpfc_shost_from_vport(phba->pport); + + for (i = 0; i < MAX_STATIC_VPORT_COUNT; i++) { + memset(&vport_id, 0, sizeof(vport_id)); + vport_id.port_name = wwn_to_u64(vport_info->vport_list[i].wwpn); + vport_id.node_name = wwn_to_u64(vport_info->vport_list[i].wwnn); + if (!vport_id.port_name || !vport_id.node_name) + continue; + + vport_id.roles = FC_PORT_ROLE_FCP_INITIATOR; + vport_id.vport_type = FC_PORTTYPE_NPIV; + vport_id.disable = false; + new_fc_vport = fc_vport_create(shost, 0, &vport_id); + + if (!new_fc_vport) { + lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, + "0546 lpfc_create_static_vport failed to" + " create vport \n"); + continue; + } + + vport = *(struct lpfc_vport **)new_fc_vport->dd_data; + vport->vport_flag |= STATIC_VPORT; + } + +out: + /* + * If this is timed out command, setting NULL to context2 tell SLI + * layer not to use this buffer. + */ + spin_lock_irq(&phba->hbalock); + pmb->context2 = NULL; + spin_unlock_irq(&phba->hbalock); + kfree(vport_info); + if (rc != MBX_TIMEOUT) + mempool_free(pmb, phba->mbox_mem_pool); + + return; +} + /* * This routine handles processing a Fabric REG_LOGIN mailbox * command upon completion. It is setup in the LPFC_MBOXQ @@ -1426,16 +2231,17 @@ void lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { struct lpfc_vport *vport = pmb->vport; - MAILBOX_t *mb = &pmb->mb; + MAILBOX_t *mb = &pmb->u.mb; struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1); struct lpfc_nodelist *ndlp; - struct lpfc_vport **vports; - int i; ndlp = (struct lpfc_nodelist *) pmb->context2; pmb->context1 = NULL; pmb->context2 = NULL; if (mb->mbxStatus) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, + "0258 Register Fabric login error: 0x%x\n", + mb->mbxStatus); lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); mempool_free(pmb, phba->mbox_mem_pool); @@ -1454,9 +2260,6 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) } lpfc_vport_set_state(vport, FC_VPORT_FAILED); - lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, - "0258 Register Fabric login error: 0x%x\n", - mb->mbxStatus); /* Decrement the reference count to ndlp after the reference * to the ndlp are done. */ @@ -1465,34 +2268,12 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) } ndlp->nlp_rpi = mb->un.varWords[0]; + ndlp->nlp_flag |= NLP_RPI_VALID; ndlp->nlp_type |= NLP_FABRIC; lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); if (vport->port_state == LPFC_FABRIC_CFG_LINK) { - vports = lpfc_create_vport_work_array(phba); - if (vports != NULL) - for(i = 0; - i <= phba->max_vpi && vports[i] != NULL; - i++) { - if (vports[i]->port_type == LPFC_PHYSICAL_PORT) - continue; - if (phba->fc_topology == TOPOLOGY_LOOP) { - lpfc_vport_set_state(vports[i], - FC_VPORT_LINKDOWN); - continue; - } - if (phba->link_flag & LS_NPIV_FAB_SUPPORTED) - lpfc_initial_fdisc(vports[i]); - else { - lpfc_vport_set_state(vports[i], - FC_VPORT_NO_FABRIC_SUPP); - lpfc_printf_vlog(vport, KERN_ERR, - LOG_ELS, - "0259 No NPIV " - "Fabric support\n"); - } - } - lpfc_destroy_vport_work_array(phba, vports); + lpfc_start_fdiscs(phba); lpfc_do_scr_ns_plogi(phba, vport); } @@ -1516,13 +2297,16 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) void lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { - MAILBOX_t *mb = &pmb->mb; + MAILBOX_t *mb = &pmb->u.mb; struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1); struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2; struct lpfc_vport *vport = pmb->vport; if (mb->mbxStatus) { out: + lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + "0260 Register NameServer error: 0x%x\n", + mb->mbxStatus); /* decrement the node reference count held for this * callback function. */ @@ -1546,15 +2330,13 @@ out: return; } lpfc_vport_set_state(vport, FC_VPORT_FAILED); - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "0260 Register NameServer error: 0x%x\n", - mb->mbxStatus); return; } pmb->context1 = NULL; ndlp->nlp_rpi = mb->un.varWords[0]; + ndlp->nlp_flag |= NLP_RPI_VALID; ndlp->nlp_type |= NLP_FABRIC; lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); @@ -2055,7 +2837,7 @@ lpfc_check_sli_ndlp(struct lpfc_hba *phba, if (pring->ringno == LPFC_ELS_RING) { switch (icmd->ulpCommand) { case CMD_GEN_REQUEST64_CR: - if (icmd->ulpContext == (volatile ushort)ndlp->nlp_rpi) + if (iocb->context_un.ndlp == ndlp) return 1; case CMD_ELS_REQUEST64_CR: if (icmd->un.elsreq64.remoteID == ndlp->nlp_DID) @@ -2102,7 +2884,7 @@ lpfc_no_rpi(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) */ psli = &phba->sli; rpi = ndlp->nlp_rpi; - if (rpi) { + if (ndlp->nlp_flag & NLP_RPI_VALID) { /* Now process each ring */ for (i = 0; i < psli->num_rings; i++) { pring = &psli->ring[i]; @@ -2150,7 +2932,7 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) LPFC_MBOXQ_t *mbox; int rc; - if (ndlp->nlp_rpi) { + if (ndlp->nlp_flag & NLP_RPI_VALID) { mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (mbox) { lpfc_unreg_login(phba, vport->vpi, ndlp->nlp_rpi, mbox); @@ -2162,6 +2944,8 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) } lpfc_no_rpi(phba, ndlp); ndlp->nlp_rpi = 0; + ndlp->nlp_flag &= ~NLP_RPI_VALID; + ndlp->nlp_flag &= ~NLP_NPR_ADISC; return 1; } return 0; @@ -2252,7 +3036,7 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) /* cleanup any ndlp on mbox q waiting for reglogin cmpl */ if ((mb = phba->sli.mbox_active)) { - if ((mb->mb.mbxCommand == MBX_REG_LOGIN64) && + if ((mb->u.mb.mbxCommand == MBX_REG_LOGIN64) && (ndlp == (struct lpfc_nodelist *) mb->context2)) { mb->context2 = NULL; mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; @@ -2261,7 +3045,7 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) spin_lock_irq(&phba->hbalock); list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) { - if ((mb->mb.mbxCommand == MBX_REG_LOGIN64) && + if ((mb->u.mb.mbxCommand == MBX_REG_LOGIN64) && (ndlp == (struct lpfc_nodelist *) mb->context2)) { mp = (struct lpfc_dmabuf *) (mb->context1); if (mp) { @@ -2309,13 +3093,14 @@ lpfc_nlp_remove(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) int rc; lpfc_cancel_retry_delay_tmo(vport, ndlp); - if (ndlp->nlp_flag & NLP_DEFER_RM && !ndlp->nlp_rpi) { + if ((ndlp->nlp_flag & NLP_DEFER_RM) && + !(ndlp->nlp_flag & NLP_RPI_VALID)) { /* For this case we need to cleanup the default rpi * allocated by the firmware. */ if ((mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL)) != NULL) { - rc = lpfc_reg_login(phba, vport->vpi, ndlp->nlp_DID, + rc = lpfc_reg_rpi(phba, vport->vpi, ndlp->nlp_DID, (uint8_t *) &vport->fc_sparam, mbox, 0); if (rc) { mempool_free(mbox, phba->mbox_mem_pool); @@ -2553,7 +3338,8 @@ lpfc_issue_clear_la(struct lpfc_hba *phba, struct lpfc_vport *vport) * clear_la then don't send it. */ if ((phba->link_state >= LPFC_CLEAR_LA) || - (vport->port_type != LPFC_PHYSICAL_PORT)) + (vport->port_type != LPFC_PHYSICAL_PORT) || + (phba->sli_rev == LPFC_SLI_REV4)) return; /* Link up discovery */ @@ -2582,7 +3368,7 @@ lpfc_issue_reg_vpi(struct lpfc_hba *phba, struct lpfc_vport *vport) regvpimbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (regvpimbox) { - lpfc_reg_vpi(phba, vport->vpi, vport->fc_myDID, regvpimbox); + lpfc_reg_vpi(vport, regvpimbox); regvpimbox->mbox_cmpl = lpfc_mbx_cmpl_reg_vpi; regvpimbox->vport = vport; if (lpfc_sli_issue_mbox(phba, regvpimbox, MBX_NOWAIT) @@ -2642,7 +3428,8 @@ lpfc_disc_start(struct lpfc_vport *vport) */ if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) && !(vport->fc_flag & FC_PT2PT) && - !(vport->fc_flag & FC_RSCN_MODE)) { + !(vport->fc_flag & FC_RSCN_MODE) && + (phba->sli_rev < LPFC_SLI_REV4)) { lpfc_issue_reg_vpi(phba, vport); return; } @@ -2919,11 +3706,13 @@ restart_disc: * set port_state to PORT_READY if SLI2. * cmpl_reg_vpi will set port_state to READY for SLI3. */ - if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) - lpfc_issue_reg_vpi(phba, vport); - else { /* NPIV Not enabled */ - lpfc_issue_clear_la(phba, vport); - vport->port_state = LPFC_VPORT_READY; + if (phba->sli_rev < LPFC_SLI_REV4) { + if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) + lpfc_issue_reg_vpi(phba, vport); + else { /* NPIV Not enabled */ + lpfc_issue_clear_la(phba, vport); + vport->port_state = LPFC_VPORT_READY; + } } /* Setup and issue mailbox INITIALIZE LINK command */ @@ -2939,7 +3728,7 @@ restart_disc: lpfc_linkdown(phba); lpfc_init_link(phba, initlinkmbox, phba->cfg_topology, phba->cfg_link_speed); - initlinkmbox->mb.un.varInitLnk.lipsr_AL_PA = 0; + initlinkmbox->u.mb.un.varInitLnk.lipsr_AL_PA = 0; initlinkmbox->vport = vport; initlinkmbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; rc = lpfc_sli_issue_mbox(phba, initlinkmbox, MBX_NOWAIT); @@ -2959,11 +3748,13 @@ restart_disc: * set port_state to PORT_READY if SLI2. * cmpl_reg_vpi will set port_state to READY for SLI3. */ - if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) - lpfc_issue_reg_vpi(phba, vport); - else { /* NPIV Not enabled */ - lpfc_issue_clear_la(phba, vport); - vport->port_state = LPFC_VPORT_READY; + if (phba->sli_rev < LPFC_SLI_REV4) { + if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) + lpfc_issue_reg_vpi(phba, vport); + else { /* NPIV Not enabled */ + lpfc_issue_clear_la(phba, vport); + vport->port_state = LPFC_VPORT_READY; + } } break; @@ -3036,7 +3827,7 @@ restart_disc: void lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { - MAILBOX_t *mb = &pmb->mb; + MAILBOX_t *mb = &pmb->u.mb; struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1); struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2; struct lpfc_vport *vport = pmb->vport; @@ -3044,6 +3835,7 @@ lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) pmb->context1 = NULL; ndlp->nlp_rpi = mb->un.varWords[0]; + ndlp->nlp_flag |= NLP_RPI_VALID; ndlp->nlp_type |= NLP_FABRIC; lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); @@ -3297,3 +4089,395 @@ lpfc_nlp_not_used(struct lpfc_nodelist *ndlp) return 1; return 0; } + +/** + * lpfc_fcf_inuse - Check if FCF can be unregistered. + * @phba: Pointer to hba context object. + * + * This function iterate through all FC nodes associated + * will all vports to check if there is any node with + * fc_rports associated with it. If there is an fc_rport + * associated with the node, then the node is either in + * discovered state or its devloss_timer is pending. + */ +static int +lpfc_fcf_inuse(struct lpfc_hba *phba) +{ + struct lpfc_vport **vports; + int i, ret = 0; + struct lpfc_nodelist *ndlp; + struct Scsi_Host *shost; + + vports = lpfc_create_vport_work_array(phba); + + for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { + shost = lpfc_shost_from_vport(vports[i]); + spin_lock_irq(shost->host_lock); + list_for_each_entry(ndlp, &vports[i]->fc_nodes, nlp_listp) { + if (NLP_CHK_NODE_ACT(ndlp) && ndlp->rport && + (ndlp->rport->roles & FC_RPORT_ROLE_FCP_TARGET)) { + ret = 1; + spin_unlock_irq(shost->host_lock); + goto out; + } + } + spin_unlock_irq(shost->host_lock); + } +out: + lpfc_destroy_vport_work_array(phba, vports); + return ret; +} + +/** + * lpfc_unregister_vfi_cmpl - Completion handler for unreg vfi. + * @phba: Pointer to hba context object. + * @mboxq: Pointer to mailbox object. + * + * This function frees memory associated with the mailbox command. + */ +static void +lpfc_unregister_vfi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) +{ + struct lpfc_vport *vport = mboxq->vport; + + if (mboxq->u.mb.mbxStatus) { + lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX, + "2555 UNREG_VFI mbxStatus error x%x " + "HBA state x%x\n", + mboxq->u.mb.mbxStatus, vport->port_state); + } + mempool_free(mboxq, phba->mbox_mem_pool); + return; +} + +/** + * lpfc_unregister_fcfi_cmpl - Completion handler for unreg fcfi. + * @phba: Pointer to hba context object. + * @mboxq: Pointer to mailbox object. + * + * This function frees memory associated with the mailbox command. + */ +static void +lpfc_unregister_fcfi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) +{ + struct lpfc_vport *vport = mboxq->vport; + + if (mboxq->u.mb.mbxStatus) { + lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX, + "2550 UNREG_FCFI mbxStatus error x%x " + "HBA state x%x\n", + mboxq->u.mb.mbxStatus, vport->port_state); + } + mempool_free(mboxq, phba->mbox_mem_pool); + return; +} + +/** + * lpfc_unregister_unused_fcf - Unregister FCF if all devices are disconnected. + * @phba: Pointer to hba context object. + * + * This function check if there are any connected remote port for the FCF and + * if all the devices are disconnected, this function unregister FCFI. + * This function also tries to use another FCF for discovery. + */ +void +lpfc_unregister_unused_fcf(struct lpfc_hba *phba) +{ + LPFC_MBOXQ_t *mbox; + int rc; + struct lpfc_vport **vports; + int i; + + spin_lock_irq(&phba->hbalock); + /* + * If HBA is not running in FIP mode or + * If HBA does not support FCoE or + * If FCF is not registered. + * do nothing. + */ + if (!(phba->hba_flag & HBA_FCOE_SUPPORT) || + !(phba->fcf.fcf_flag & FCF_REGISTERED) || + (phba->cfg_enable_fip == 0)) { + spin_unlock_irq(&phba->hbalock); + return; + } + spin_unlock_irq(&phba->hbalock); + + if (lpfc_fcf_inuse(phba)) + return; + + + /* Unregister VPIs */ + vports = lpfc_create_vport_work_array(phba); + if (vports && + (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)) + for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { + lpfc_mbx_unreg_vpi(vports[i]); + vports[i]->fc_flag |= FC_VPORT_NEEDS_REG_VPI; + vports[i]->vfi_state &= ~LPFC_VFI_REGISTERED; + } + lpfc_destroy_vport_work_array(phba, vports); + + /* Unregister VFI */ + mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mbox) { + lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX, + "2556 UNREG_VFI mbox allocation failed" + "HBA state x%x\n", + phba->pport->port_state); + return; + } + + lpfc_unreg_vfi(mbox, phba->pport->vfi); + mbox->vport = phba->pport; + mbox->mbox_cmpl = lpfc_unregister_vfi_cmpl; + + rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); + if (rc == MBX_NOT_FINISHED) { + lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX, + "2557 UNREG_VFI issue mbox failed rc x%x " + "HBA state x%x\n", + rc, phba->pport->port_state); + mempool_free(mbox, phba->mbox_mem_pool); + return; + } + + /* Unregister FCF */ + mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mbox) { + lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX, + "2551 UNREG_FCFI mbox allocation failed" + "HBA state x%x\n", + phba->pport->port_state); + return; + } + + lpfc_unreg_fcfi(mbox, phba->fcf.fcfi); + mbox->vport = phba->pport; + mbox->mbox_cmpl = lpfc_unregister_fcfi_cmpl; + rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); + + if (rc == MBX_NOT_FINISHED) { + lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX, + "2552 UNREG_FCFI issue mbox failed rc x%x " + "HBA state x%x\n", + rc, phba->pport->port_state); + mempool_free(mbox, phba->mbox_mem_pool); + return; + } + + spin_lock_irq(&phba->hbalock); + phba->fcf.fcf_flag &= ~(FCF_AVAILABLE | FCF_REGISTERED | + FCF_DISCOVERED | FCF_BOOT_ENABLE | FCF_IN_USE | + FCF_VALID_VLAN); + spin_unlock_irq(&phba->hbalock); + + /* + * If driver is not unloading, check if there is any other + * FCF record that can be used for discovery. + */ + if ((phba->pport->load_flag & FC_UNLOADING) || + (phba->link_state < LPFC_LINK_UP)) + return; + + rc = lpfc_sli4_read_fcf_record(phba, LPFC_FCOE_FCF_GET_FIRST); + + if (rc) + lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX, + "2553 lpfc_unregister_unused_fcf failed to read FCF" + " record HBA state x%x\n", + phba->pport->port_state); +} + +/** + * lpfc_read_fcf_conn_tbl - Create driver FCF connection table. + * @phba: Pointer to hba context object. + * @buff: Buffer containing the FCF connection table as in the config + * region. + * This function create driver data structure for the FCF connection + * record table read from config region 23. + */ +static void +lpfc_read_fcf_conn_tbl(struct lpfc_hba *phba, + uint8_t *buff) +{ + struct lpfc_fcf_conn_entry *conn_entry, *next_conn_entry; + struct lpfc_fcf_conn_hdr *conn_hdr; + struct lpfc_fcf_conn_rec *conn_rec; + uint32_t record_count; + int i; + + /* Free the current connect table */ + list_for_each_entry_safe(conn_entry, next_conn_entry, + &phba->fcf_conn_rec_list, list) + kfree(conn_entry); + + conn_hdr = (struct lpfc_fcf_conn_hdr *) buff; + record_count = conn_hdr->length * sizeof(uint32_t)/ + sizeof(struct lpfc_fcf_conn_rec); + + conn_rec = (struct lpfc_fcf_conn_rec *) + (buff + sizeof(struct lpfc_fcf_conn_hdr)); + + for (i = 0; i < record_count; i++) { + if (!(conn_rec[i].flags & FCFCNCT_VALID)) + continue; + conn_entry = kzalloc(sizeof(struct lpfc_fcf_conn_entry), + GFP_KERNEL); + if (!conn_entry) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2566 Failed to allocate connection" + " table entry\n"); + return; + } + + memcpy(&conn_entry->conn_rec, &conn_rec[i], + sizeof(struct lpfc_fcf_conn_rec)); + conn_entry->conn_rec.vlan_tag = + le16_to_cpu(conn_entry->conn_rec.vlan_tag) & 0xFFF; + conn_entry->conn_rec.flags = + le16_to_cpu(conn_entry->conn_rec.flags); + list_add_tail(&conn_entry->list, + &phba->fcf_conn_rec_list); + } +} + +/** + * lpfc_read_fcoe_param - Read FCoe parameters from conf region.. + * @phba: Pointer to hba context object. + * @buff: Buffer containing the FCoE parameter data structure. + * + * This function update driver data structure with config + * parameters read from config region 23. + */ +static void +lpfc_read_fcoe_param(struct lpfc_hba *phba, + uint8_t *buff) +{ + struct lpfc_fip_param_hdr *fcoe_param_hdr; + struct lpfc_fcoe_params *fcoe_param; + + fcoe_param_hdr = (struct lpfc_fip_param_hdr *) + buff; + fcoe_param = (struct lpfc_fcoe_params *) + buff + sizeof(struct lpfc_fip_param_hdr); + + if ((fcoe_param_hdr->parm_version != FIPP_VERSION) || + (fcoe_param_hdr->length != FCOE_PARAM_LENGTH)) + return; + + if (bf_get(lpfc_fip_param_hdr_fipp_mode, fcoe_param_hdr) == + FIPP_MODE_ON) + phba->cfg_enable_fip = 1; + + if (bf_get(lpfc_fip_param_hdr_fipp_mode, fcoe_param_hdr) == + FIPP_MODE_OFF) + phba->cfg_enable_fip = 0; + + if (fcoe_param_hdr->parm_flags & FIPP_VLAN_VALID) { + phba->valid_vlan = 1; + phba->vlan_id = le16_to_cpu(fcoe_param->vlan_tag) & + 0xFFF; + } + + phba->fc_map[0] = fcoe_param->fc_map[0]; + phba->fc_map[1] = fcoe_param->fc_map[1]; + phba->fc_map[2] = fcoe_param->fc_map[2]; + return; +} + +/** + * lpfc_get_rec_conf23 - Get a record type in config region data. + * @buff: Buffer containing config region 23 data. + * @size: Size of the data buffer. + * @rec_type: Record type to be searched. + * + * This function searches config region data to find the begining + * of the record specified by record_type. If record found, this + * function return pointer to the record else return NULL. + */ +static uint8_t * +lpfc_get_rec_conf23(uint8_t *buff, uint32_t size, uint8_t rec_type) +{ + uint32_t offset = 0, rec_length; + + if ((buff[0] == LPFC_REGION23_LAST_REC) || + (size < sizeof(uint32_t))) + return NULL; + + rec_length = buff[offset + 1]; + + /* + * One TLV record has one word header and number of data words + * specified in the rec_length field of the record header. + */ + while ((offset + rec_length * sizeof(uint32_t) + sizeof(uint32_t)) + <= size) { + if (buff[offset] == rec_type) + return &buff[offset]; + + if (buff[offset] == LPFC_REGION23_LAST_REC) + return NULL; + + offset += rec_length * sizeof(uint32_t) + sizeof(uint32_t); + rec_length = buff[offset + 1]; + } + return NULL; +} + +/** + * lpfc_parse_fcoe_conf - Parse FCoE config data read from config region 23. + * @phba: Pointer to lpfc_hba data structure. + * @buff: Buffer containing config region 23 data. + * @size: Size of the data buffer. + * + * This fuction parse the FCoE config parameters in config region 23 and + * populate driver data structure with the parameters. + */ +void +lpfc_parse_fcoe_conf(struct lpfc_hba *phba, + uint8_t *buff, + uint32_t size) +{ + uint32_t offset = 0, rec_length; + uint8_t *rec_ptr; + + /* + * If data size is less than 2 words signature and version cannot be + * verified. + */ + if (size < 2*sizeof(uint32_t)) + return; + + /* Check the region signature first */ + if (memcmp(buff, LPFC_REGION23_SIGNATURE, 4)) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2567 Config region 23 has bad signature\n"); + return; + } + + offset += 4; + + /* Check the data structure version */ + if (buff[offset] != LPFC_REGION23_VERSION) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2568 Config region 23 has bad version\n"); + return; + } + offset += 4; + + rec_length = buff[offset + 1]; + + /* Read FCoE param record */ + rec_ptr = lpfc_get_rec_conf23(&buff[offset], + size - offset, FCOE_PARAM_TYPE); + if (rec_ptr) + lpfc_read_fcoe_param(phba, rec_ptr); + + /* Read FCF connection table */ + rec_ptr = lpfc_get_rec_conf23(&buff[offset], + size - offset, FCOE_CONN_TBL_TYPE); + if (rec_ptr) + lpfc_read_fcf_conn_tbl(phba, rec_ptr); + +} diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index 4168c7b498b8..8a3a026667e4 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2008 Emulex. All rights reserved. * + * Copyright (C) 2004-2009 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * @@ -470,6 +470,35 @@ struct serv_parm { /* Structure is in Big Endian format */ uint8_t vendorVersion[16]; }; +/* + * Virtual Fabric Tagging Header + */ +struct fc_vft_header { + uint32_t word0; +#define fc_vft_hdr_r_ctl_SHIFT 24 +#define fc_vft_hdr_r_ctl_MASK 0xFF +#define fc_vft_hdr_r_ctl_WORD word0 +#define fc_vft_hdr_ver_SHIFT 22 +#define fc_vft_hdr_ver_MASK 0x3 +#define fc_vft_hdr_ver_WORD word0 +#define fc_vft_hdr_type_SHIFT 18 +#define fc_vft_hdr_type_MASK 0xF +#define fc_vft_hdr_type_WORD word0 +#define fc_vft_hdr_e_SHIFT 16 +#define fc_vft_hdr_e_MASK 0x1 +#define fc_vft_hdr_e_WORD word0 +#define fc_vft_hdr_priority_SHIFT 13 +#define fc_vft_hdr_priority_MASK 0x7 +#define fc_vft_hdr_priority_WORD word0 +#define fc_vft_hdr_vf_id_SHIFT 1 +#define fc_vft_hdr_vf_id_MASK 0xFFF +#define fc_vft_hdr_vf_id_WORD word0 + uint32_t word1; +#define fc_vft_hdr_hopct_SHIFT 24 +#define fc_vft_hdr_hopct_MASK 0xFF +#define fc_vft_hdr_hopct_WORD word1 +}; + /* * Extended Link Service LS_COMMAND codes (Payload Word 0) */ @@ -1152,6 +1181,8 @@ typedef struct { #define PCI_DEVICE_ID_HORNET 0xfe05 #define PCI_DEVICE_ID_ZEPHYR_SCSP 0xfe11 #define PCI_DEVICE_ID_ZEPHYR_DCSP 0xfe12 +#define PCI_VENDOR_ID_SERVERENGINE 0x19a2 +#define PCI_DEVICE_ID_TIGERSHARK 0x0704 #define JEDEC_ID_ADDRESS 0x0080001c #define FIREFLY_JEDEC_ID 0x1ACC @@ -1342,15 +1373,21 @@ typedef struct { /* FireFly BIU registers */ #define MBX_READ_LA64 0x95 #define MBX_REG_VPI 0x96 #define MBX_UNREG_VPI 0x97 -#define MBX_REG_VNPID 0x96 -#define MBX_UNREG_VNPID 0x97 #define MBX_WRITE_WWN 0x98 #define MBX_SET_DEBUG 0x99 #define MBX_LOAD_EXP_ROM 0x9C - -#define MBX_MAX_CMDS 0x9D +#define MBX_SLI4_CONFIG 0x9B +#define MBX_SLI4_REQ_FTRS 0x9D +#define MBX_MAX_CMDS 0x9E +#define MBX_RESUME_RPI 0x9E #define MBX_SLI2_CMD_MASK 0x80 +#define MBX_REG_VFI 0x9F +#define MBX_REG_FCFI 0xA0 +#define MBX_UNREG_VFI 0xA1 +#define MBX_UNREG_FCFI 0xA2 +#define MBX_INIT_VFI 0xA3 +#define MBX_INIT_VPI 0xA4 /* IOCB Commands */ @@ -1440,6 +1477,16 @@ typedef struct { /* FireFly BIU registers */ #define CMD_IOCB_LOGENTRY_CN 0x94 #define CMD_IOCB_LOGENTRY_ASYNC_CN 0x96 +/* Unhandled Data Security SLI Commands */ +#define DSSCMD_IWRITE64_CR 0xD8 +#define DSSCMD_IWRITE64_CX 0xD9 +#define DSSCMD_IREAD64_CR 0xDA +#define DSSCMD_IREAD64_CX 0xDB +#define DSSCMD_INVALIDATE_DEK 0xDC +#define DSSCMD_SET_KEK 0xDD +#define DSSCMD_GET_KEK_ID 0xDE +#define DSSCMD_GEN_XFER 0xDF + #define CMD_MAX_IOCB_CMD 0xE6 #define CMD_IOCB_MASK 0xff @@ -1466,6 +1513,7 @@ typedef struct { /* FireFly BIU registers */ #define MBXERR_BAD_RCV_LENGTH 14 #define MBXERR_DMA_ERROR 15 #define MBXERR_ERROR 16 +#define MBXERR_LINK_DOWN 0x33 #define MBX_NOT_FINISHED 255 #define MBX_BUSY 0xffffff /* Attempted cmd to busy Mailbox */ @@ -1504,32 +1552,6 @@ struct ulp_bde { #endif }; -struct ulp_bde64 { /* SLI-2 */ - union ULP_BDE_TUS { - uint32_t w; - struct { -#ifdef __BIG_ENDIAN_BITFIELD - uint32_t bdeFlags:8; /* BDE Flags 0 IS A SUPPORTED - VALUE !! */ - uint32_t bdeSize:24; /* Size of buffer (in bytes) */ -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint32_t bdeSize:24; /* Size of buffer (in bytes) */ - uint32_t bdeFlags:8; /* BDE Flags 0 IS A SUPPORTED - VALUE !! */ -#endif -#define BUFF_TYPE_BDE_64 0x00 /* BDE (Host_resident) */ -#define BUFF_TYPE_BDE_IMMED 0x01 /* Immediate Data BDE */ -#define BUFF_TYPE_BDE_64P 0x02 /* BDE (Port-resident) */ -#define BUFF_TYPE_BDE_64I 0x08 /* Input BDE (Host-resident) */ -#define BUFF_TYPE_BDE_64IP 0x0A /* Input BDE (Port-resident) */ -#define BUFF_TYPE_BLP_64 0x40 /* BLP (Host-resident) */ -#define BUFF_TYPE_BLP_64P 0x42 /* BLP (Port-resident) */ - } f; - } tus; - uint32_t addrLow; - uint32_t addrHigh; -}; - typedef struct ULP_BDL { /* SLI-2 */ #ifdef __BIG_ENDIAN_BITFIELD uint32_t bdeFlags:8; /* BDL Flags */ @@ -2287,7 +2309,7 @@ typedef struct { uint32_t rsvd3; uint32_t rsvd4; uint32_t rsvd5; - uint16_t rsvd6; + uint16_t vfi; uint16_t vpi; #else /* __LITTLE_ENDIAN */ uint32_t rsvd1; @@ -2297,7 +2319,7 @@ typedef struct { uint32_t rsvd4; uint32_t rsvd5; uint16_t vpi; - uint16_t rsvd6; + uint16_t vfi; #endif } REG_VPI_VAR; @@ -2457,7 +2479,7 @@ typedef struct { uint32_t entry_index:16; #endif - uint32_t rsvd1; + uint32_t sli4_length; uint32_t word_cnt; uint32_t resp_offset; } DUMP_VAR; @@ -2470,9 +2492,32 @@ typedef struct { #define DMP_RSP_OFFSET 0x14 /* word 5 contains first word of rsp */ #define DMP_RSP_SIZE 0x6C /* maximum of 27 words of rsp data */ +#define DMP_REGION_VPORT 0x16 /* VPort info region */ +#define DMP_VPORT_REGION_SIZE 0x200 +#define DMP_MBOX_OFFSET_WORD 0x5 + +#define DMP_REGION_FCOEPARAM 0x17 /* fcoe param region */ +#define DMP_FCOEPARAM_RGN_SIZE 0x400 + #define WAKE_UP_PARMS_REGION_ID 4 #define WAKE_UP_PARMS_WORD_SIZE 15 +struct vport_rec { + uint8_t wwpn[8]; + uint8_t wwnn[8]; +}; + +#define VPORT_INFO_SIG 0x32324752 +#define VPORT_INFO_REV_MASK 0xff +#define VPORT_INFO_REV 0x1 +#define MAX_STATIC_VPORT_COUNT 16 +struct static_vport_info { + uint32_t signature; + uint32_t rev; + struct vport_rec vport_list[MAX_STATIC_VPORT_COUNT]; + uint32_t resvd[66]; +}; + /* Option rom version structure */ struct prog_id { #ifdef __BIG_ENDIAN_BITFIELD @@ -2697,7 +2742,9 @@ typedef struct { #endif #ifdef __BIG_ENDIAN_BITFIELD - uint32_t rsvd1 : 23; /* Reserved */ + uint32_t rsvd1 : 19; /* Reserved */ + uint32_t cdss : 1; /* Configure Data Security SLI */ + uint32_t rsvd2 : 3; /* Reserved */ uint32_t cbg : 1; /* Configure BlockGuard */ uint32_t cmv : 1; /* Configure Max VPIs */ uint32_t ccrp : 1; /* Config Command Ring Polling */ @@ -2717,10 +2764,14 @@ typedef struct { uint32_t ccrp : 1; /* Config Command Ring Polling */ uint32_t cmv : 1; /* Configure Max VPIs */ uint32_t cbg : 1; /* Configure BlockGuard */ - uint32_t rsvd1 : 23; /* Reserved */ + uint32_t rsvd2 : 3; /* Reserved */ + uint32_t cdss : 1; /* Configure Data Security SLI */ + uint32_t rsvd1 : 19; /* Reserved */ #endif #ifdef __BIG_ENDIAN_BITFIELD - uint32_t rsvd2 : 23; /* Reserved */ + uint32_t rsvd3 : 19; /* Reserved */ + uint32_t gdss : 1; /* Configure Data Security SLI */ + uint32_t rsvd4 : 3; /* Reserved */ uint32_t gbg : 1; /* Grant BlockGuard */ uint32_t gmv : 1; /* Grant Max VPIs */ uint32_t gcrp : 1; /* Grant Command Ring Polling */ @@ -2740,7 +2791,9 @@ typedef struct { uint32_t gcrp : 1; /* Grant Command Ring Polling */ uint32_t gmv : 1; /* Grant Max VPIs */ uint32_t gbg : 1; /* Grant BlockGuard */ - uint32_t rsvd2 : 23; /* Reserved */ + uint32_t rsvd4 : 3; /* Reserved */ + uint32_t gdss : 1; /* Configure Data Security SLI */ + uint32_t rsvd3 : 19; /* Reserved */ #endif #ifdef __BIG_ENDIAN_BITFIELD @@ -2753,20 +2806,20 @@ typedef struct { #ifdef __BIG_ENDIAN_BITFIELD uint32_t max_hbq : 16; /* Max HBQs Host expect to configure */ - uint32_t rsvd3 : 16; /* Max HBQs Host expect to configure */ + uint32_t rsvd5 : 16; /* Max HBQs Host expect to configure */ #else /* __LITTLE_ENDIAN */ - uint32_t rsvd3 : 16; /* Max HBQs Host expect to configure */ + uint32_t rsvd5 : 16; /* Max HBQs Host expect to configure */ uint32_t max_hbq : 16; /* Max HBQs Host expect to configure */ #endif - uint32_t rsvd4; /* Reserved */ + uint32_t rsvd6; /* Reserved */ #ifdef __BIG_ENDIAN_BITFIELD - uint32_t rsvd5 : 16; /* Reserved */ + uint32_t rsvd7 : 16; /* Reserved */ uint32_t max_vpi : 16; /* Max number of virt N-Ports */ #else /* __LITTLE_ENDIAN */ uint32_t max_vpi : 16; /* Max number of virt N-Ports */ - uint32_t rsvd5 : 16; /* Reserved */ + uint32_t rsvd7 : 16; /* Reserved */ #endif } CONFIG_PORT_VAR; @@ -3666,3 +3719,5 @@ lpfc_error_lost_link(IOCB_t *iocbp) #define MENLO_TIMEOUT 30 #define SETVAR_MLOMNT 0x103107 #define SETVAR_MLORST 0x103007 + +#define BPL_ALIGN_SZ 8 /* 8 byte alignment for bpl and mbufs */ diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h new file mode 100644 index 000000000000..2995d128f07f --- /dev/null +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -0,0 +1,2141 @@ +/******************************************************************* + * This file is part of the Emulex Linux Device Driver for * + * Fibre Channel Host Bus Adapters. * + * Copyright (C) 2009 Emulex. All rights reserved. * + * EMULEX and SLI are trademarks of Emulex. * + * www.emulex.com * + * * + * 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. * + * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * + * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * + * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * + * TO BE LEGALLY INVALID. See the GNU General Public License for * + * more details, a copy of which can be found in the file COPYING * + * included with this package. * + *******************************************************************/ + +/* Macros to deal with bit fields. Each bit field must have 3 #defines + * associated with it (_SHIFT, _MASK, and _WORD). + * EG. For a bit field that is in the 7th bit of the "field4" field of a + * structure and is 2 bits in size the following #defines must exist: + * struct temp { + * uint32_t field1; + * uint32_t field2; + * uint32_t field3; + * uint32_t field4; + * #define example_bit_field_SHIFT 7 + * #define example_bit_field_MASK 0x03 + * #define example_bit_field_WORD field4 + * uint32_t field5; + * }; + * Then the macros below may be used to get or set the value of that field. + * EG. To get the value of the bit field from the above example: + * struct temp t1; + * value = bf_get(example_bit_field, &t1); + * And then to set that bit field: + * bf_set(example_bit_field, &t1, 2); + * Or clear that bit field: + * bf_set(example_bit_field, &t1, 0); + */ +#define bf_get(name, ptr) \ + (((ptr)->name##_WORD >> name##_SHIFT) & name##_MASK) +#define bf_set(name, ptr, value) \ + ((ptr)->name##_WORD = ((((value) & name##_MASK) << name##_SHIFT) | \ + ((ptr)->name##_WORD & ~(name##_MASK << name##_SHIFT)))) + +struct dma_address { + uint32_t addr_lo; + uint32_t addr_hi; +}; + +#define LPFC_SLI4_BAR0 1 +#define LPFC_SLI4_BAR1 2 +#define LPFC_SLI4_BAR2 4 + +#define LPFC_SLI4_MBX_EMBED true +#define LPFC_SLI4_MBX_NEMBED false + +#define LPFC_SLI4_MB_WORD_COUNT 64 +#define LPFC_MAX_MQ_PAGE 8 +#define LPFC_MAX_WQ_PAGE 8 +#define LPFC_MAX_CQ_PAGE 4 +#define LPFC_MAX_EQ_PAGE 8 + +#define LPFC_VIR_FUNC_MAX 32 /* Maximum number of virtual functions */ +#define LPFC_PCI_FUNC_MAX 5 /* Maximum number of PCI functions */ +#define LPFC_VFR_PAGE_SIZE 0x1000 /* 4KB BAR2 per-VF register page size */ + +/* Define SLI4 Alignment requirements. */ +#define LPFC_ALIGN_16_BYTE 16 +#define LPFC_ALIGN_64_BYTE 64 + +/* Define SLI4 specific definitions. */ +#define LPFC_MQ_CQE_BYTE_OFFSET 256 +#define LPFC_MBX_CMD_HDR_LENGTH 16 +#define LPFC_MBX_ERROR_RANGE 0x4000 +#define LPFC_BMBX_BIT1_ADDR_HI 0x2 +#define LPFC_BMBX_BIT1_ADDR_LO 0 +#define LPFC_RPI_HDR_COUNT 64 +#define LPFC_HDR_TEMPLATE_SIZE 4096 +#define LPFC_RPI_ALLOC_ERROR 0xFFFF +#define LPFC_FCF_RECORD_WD_CNT 132 +#define LPFC_ENTIRE_FCF_DATABASE 0 +#define LPFC_DFLT_FCF_INDEX 0 + +/* Virtual function numbers */ +#define LPFC_VF0 0 +#define LPFC_VF1 1 +#define LPFC_VF2 2 +#define LPFC_VF3 3 +#define LPFC_VF4 4 +#define LPFC_VF5 5 +#define LPFC_VF6 6 +#define LPFC_VF7 7 +#define LPFC_VF8 8 +#define LPFC_VF9 9 +#define LPFC_VF10 10 +#define LPFC_VF11 11 +#define LPFC_VF12 12 +#define LPFC_VF13 13 +#define LPFC_VF14 14 +#define LPFC_VF15 15 +#define LPFC_VF16 16 +#define LPFC_VF17 17 +#define LPFC_VF18 18 +#define LPFC_VF19 19 +#define LPFC_VF20 20 +#define LPFC_VF21 21 +#define LPFC_VF22 22 +#define LPFC_VF23 23 +#define LPFC_VF24 24 +#define LPFC_VF25 25 +#define LPFC_VF26 26 +#define LPFC_VF27 27 +#define LPFC_VF28 28 +#define LPFC_VF29 29 +#define LPFC_VF30 30 +#define LPFC_VF31 31 + +/* PCI function numbers */ +#define LPFC_PCI_FUNC0 0 +#define LPFC_PCI_FUNC1 1 +#define LPFC_PCI_FUNC2 2 +#define LPFC_PCI_FUNC3 3 +#define LPFC_PCI_FUNC4 4 + +/* Active interrupt test count */ +#define LPFC_ACT_INTR_CNT 4 + +/* Delay Multiplier constant */ +#define LPFC_DMULT_CONST 651042 +#define LPFC_MIM_IMAX 636 +#define LPFC_FP_DEF_IMAX 10000 +#define LPFC_SP_DEF_IMAX 10000 + +struct ulp_bde64 { + union ULP_BDE_TUS { + uint32_t w; + struct { +#ifdef __BIG_ENDIAN_BITFIELD + uint32_t bdeFlags:8; /* BDE Flags 0 IS A SUPPORTED + VALUE !! */ + uint32_t bdeSize:24; /* Size of buffer (in bytes) */ +#else /* __LITTLE_ENDIAN_BITFIELD */ + uint32_t bdeSize:24; /* Size of buffer (in bytes) */ + uint32_t bdeFlags:8; /* BDE Flags 0 IS A SUPPORTED + VALUE !! */ +#endif +#define BUFF_TYPE_BDE_64 0x00 /* BDE (Host_resident) */ +#define BUFF_TYPE_BDE_IMMED 0x01 /* Immediate Data BDE */ +#define BUFF_TYPE_BDE_64P 0x02 /* BDE (Port-resident) */ +#define BUFF_TYPE_BDE_64I 0x08 /* Input BDE (Host-resident) */ +#define BUFF_TYPE_BDE_64IP 0x0A /* Input BDE (Port-resident) */ +#define BUFF_TYPE_BLP_64 0x40 /* BLP (Host-resident) */ +#define BUFF_TYPE_BLP_64P 0x42 /* BLP (Port-resident) */ + } f; + } tus; + uint32_t addrLow; + uint32_t addrHigh; +}; + +struct lpfc_sli4_flags { + uint32_t word0; +#define lpfc_fip_flag_SHIFT 0 +#define lpfc_fip_flag_MASK 0x00000001 +#define lpfc_fip_flag_WORD word0 +}; + +/* event queue entry structure */ +struct lpfc_eqe { + uint32_t word0; +#define lpfc_eqe_resource_id_SHIFT 16 +#define lpfc_eqe_resource_id_MASK 0x000000FF +#define lpfc_eqe_resource_id_WORD word0 +#define lpfc_eqe_minor_code_SHIFT 4 +#define lpfc_eqe_minor_code_MASK 0x00000FFF +#define lpfc_eqe_minor_code_WORD word0 +#define lpfc_eqe_major_code_SHIFT 1 +#define lpfc_eqe_major_code_MASK 0x00000007 +#define lpfc_eqe_major_code_WORD word0 +#define lpfc_eqe_valid_SHIFT 0 +#define lpfc_eqe_valid_MASK 0x00000001 +#define lpfc_eqe_valid_WORD word0 +}; + +/* completion queue entry structure (common fields for all cqe types) */ +struct lpfc_cqe { + uint32_t reserved0; + uint32_t reserved1; + uint32_t reserved2; + uint32_t word3; +#define lpfc_cqe_valid_SHIFT 31 +#define lpfc_cqe_valid_MASK 0x00000001 +#define lpfc_cqe_valid_WORD word3 +#define lpfc_cqe_code_SHIFT 16 +#define lpfc_cqe_code_MASK 0x000000FF +#define lpfc_cqe_code_WORD word3 +}; + +/* Completion Queue Entry Status Codes */ +#define CQE_STATUS_SUCCESS 0x0 +#define CQE_STATUS_FCP_RSP_FAILURE 0x1 +#define CQE_STATUS_REMOTE_STOP 0x2 +#define CQE_STATUS_LOCAL_REJECT 0x3 +#define CQE_STATUS_NPORT_RJT 0x4 +#define CQE_STATUS_FABRIC_RJT 0x5 +#define CQE_STATUS_NPORT_BSY 0x6 +#define CQE_STATUS_FABRIC_BSY 0x7 +#define CQE_STATUS_INTERMED_RSP 0x8 +#define CQE_STATUS_LS_RJT 0x9 +#define CQE_STATUS_CMD_REJECT 0xb +#define CQE_STATUS_FCP_TGT_LENCHECK 0xc +#define CQE_STATUS_NEED_BUFF_ENTRY 0xf + +/* Status returned by hardware (valid only if status = CQE_STATUS_SUCCESS). */ +#define CQE_HW_STATUS_NO_ERR 0x0 +#define CQE_HW_STATUS_UNDERRUN 0x1 +#define CQE_HW_STATUS_OVERRUN 0x2 + +/* Completion Queue Entry Codes */ +#define CQE_CODE_COMPL_WQE 0x1 +#define CQE_CODE_RELEASE_WQE 0x2 +#define CQE_CODE_RECEIVE 0x4 +#define CQE_CODE_XRI_ABORTED 0x5 + +/* completion queue entry for wqe completions */ +struct lpfc_wcqe_complete { + uint32_t word0; +#define lpfc_wcqe_c_request_tag_SHIFT 16 +#define lpfc_wcqe_c_request_tag_MASK 0x0000FFFF +#define lpfc_wcqe_c_request_tag_WORD word0 +#define lpfc_wcqe_c_status_SHIFT 8 +#define lpfc_wcqe_c_status_MASK 0x000000FF +#define lpfc_wcqe_c_status_WORD word0 +#define lpfc_wcqe_c_hw_status_SHIFT 0 +#define lpfc_wcqe_c_hw_status_MASK 0x000000FF +#define lpfc_wcqe_c_hw_status_WORD word0 + uint32_t total_data_placed; + uint32_t parameter; + uint32_t word3; +#define lpfc_wcqe_c_valid_SHIFT lpfc_cqe_valid_SHIFT +#define lpfc_wcqe_c_valid_MASK lpfc_cqe_valid_MASK +#define lpfc_wcqe_c_valid_WORD lpfc_cqe_valid_WORD +#define lpfc_wcqe_c_xb_SHIFT 28 +#define lpfc_wcqe_c_xb_MASK 0x00000001 +#define lpfc_wcqe_c_xb_WORD word3 +#define lpfc_wcqe_c_pv_SHIFT 27 +#define lpfc_wcqe_c_pv_MASK 0x00000001 +#define lpfc_wcqe_c_pv_WORD word3 +#define lpfc_wcqe_c_priority_SHIFT 24 +#define lpfc_wcqe_c_priority_MASK 0x00000007 +#define lpfc_wcqe_c_priority_WORD word3 +#define lpfc_wcqe_c_code_SHIFT lpfc_cqe_code_SHIFT +#define lpfc_wcqe_c_code_MASK lpfc_cqe_code_MASK +#define lpfc_wcqe_c_code_WORD lpfc_cqe_code_WORD +}; + +/* completion queue entry for wqe release */ +struct lpfc_wcqe_release { + uint32_t reserved0; + uint32_t reserved1; + uint32_t word2; +#define lpfc_wcqe_r_wq_id_SHIFT 16 +#define lpfc_wcqe_r_wq_id_MASK 0x0000FFFF +#define lpfc_wcqe_r_wq_id_WORD word2 +#define lpfc_wcqe_r_wqe_index_SHIFT 0 +#define lpfc_wcqe_r_wqe_index_MASK 0x0000FFFF +#define lpfc_wcqe_r_wqe_index_WORD word2 + uint32_t word3; +#define lpfc_wcqe_r_valid_SHIFT lpfc_cqe_valid_SHIFT +#define lpfc_wcqe_r_valid_MASK lpfc_cqe_valid_MASK +#define lpfc_wcqe_r_valid_WORD lpfc_cqe_valid_WORD +#define lpfc_wcqe_r_code_SHIFT lpfc_cqe_code_SHIFT +#define lpfc_wcqe_r_code_MASK lpfc_cqe_code_MASK +#define lpfc_wcqe_r_code_WORD lpfc_cqe_code_WORD +}; + +struct sli4_wcqe_xri_aborted { + uint32_t word0; +#define lpfc_wcqe_xa_status_SHIFT 8 +#define lpfc_wcqe_xa_status_MASK 0x000000FF +#define lpfc_wcqe_xa_status_WORD word0 + uint32_t parameter; + uint32_t word2; +#define lpfc_wcqe_xa_remote_xid_SHIFT 16 +#define lpfc_wcqe_xa_remote_xid_MASK 0x0000FFFF +#define lpfc_wcqe_xa_remote_xid_WORD word2 +#define lpfc_wcqe_xa_xri_SHIFT 0 +#define lpfc_wcqe_xa_xri_MASK 0x0000FFFF +#define lpfc_wcqe_xa_xri_WORD word2 + uint32_t word3; +#define lpfc_wcqe_xa_valid_SHIFT lpfc_cqe_valid_SHIFT +#define lpfc_wcqe_xa_valid_MASK lpfc_cqe_valid_MASK +#define lpfc_wcqe_xa_valid_WORD lpfc_cqe_valid_WORD +#define lpfc_wcqe_xa_ia_SHIFT 30 +#define lpfc_wcqe_xa_ia_MASK 0x00000001 +#define lpfc_wcqe_xa_ia_WORD word3 +#define CQE_XRI_ABORTED_IA_REMOTE 0 +#define CQE_XRI_ABORTED_IA_LOCAL 1 +#define lpfc_wcqe_xa_br_SHIFT 29 +#define lpfc_wcqe_xa_br_MASK 0x00000001 +#define lpfc_wcqe_xa_br_WORD word3 +#define CQE_XRI_ABORTED_BR_BA_ACC 0 +#define CQE_XRI_ABORTED_BR_BA_RJT 1 +#define lpfc_wcqe_xa_eo_SHIFT 28 +#define lpfc_wcqe_xa_eo_MASK 0x00000001 +#define lpfc_wcqe_xa_eo_WORD word3 +#define CQE_XRI_ABORTED_EO_REMOTE 0 +#define CQE_XRI_ABORTED_EO_LOCAL 1 +#define lpfc_wcqe_xa_code_SHIFT lpfc_cqe_code_SHIFT +#define lpfc_wcqe_xa_code_MASK lpfc_cqe_code_MASK +#define lpfc_wcqe_xa_code_WORD lpfc_cqe_code_WORD +}; + +/* completion queue entry structure for rqe completion */ +struct lpfc_rcqe { + uint32_t word0; +#define lpfc_rcqe_bindex_SHIFT 16 +#define lpfc_rcqe_bindex_MASK 0x0000FFF +#define lpfc_rcqe_bindex_WORD word0 +#define lpfc_rcqe_status_SHIFT 8 +#define lpfc_rcqe_status_MASK 0x000000FF +#define lpfc_rcqe_status_WORD word0 +#define FC_STATUS_RQ_SUCCESS 0x10 /* Async receive successful */ +#define FC_STATUS_RQ_BUF_LEN_EXCEEDED 0x11 /* payload truncated */ +#define FC_STATUS_INSUFF_BUF_NEED_BUF 0x12 /* Insufficient buffers */ +#define FC_STATUS_INSUFF_BUF_FRM_DISC 0x13 /* Frame Discard */ + uint32_t reserved1; + uint32_t word2; +#define lpfc_rcqe_length_SHIFT 16 +#define lpfc_rcqe_length_MASK 0x0000FFFF +#define lpfc_rcqe_length_WORD word2 +#define lpfc_rcqe_rq_id_SHIFT 6 +#define lpfc_rcqe_rq_id_MASK 0x000003FF +#define lpfc_rcqe_rq_id_WORD word2 +#define lpfc_rcqe_fcf_id_SHIFT 0 +#define lpfc_rcqe_fcf_id_MASK 0x0000003F +#define lpfc_rcqe_fcf_id_WORD word2 + uint32_t word3; +#define lpfc_rcqe_valid_SHIFT lpfc_cqe_valid_SHIFT +#define lpfc_rcqe_valid_MASK lpfc_cqe_valid_MASK +#define lpfc_rcqe_valid_WORD lpfc_cqe_valid_WORD +#define lpfc_rcqe_port_SHIFT 30 +#define lpfc_rcqe_port_MASK 0x00000001 +#define lpfc_rcqe_port_WORD word3 +#define lpfc_rcqe_hdr_length_SHIFT 24 +#define lpfc_rcqe_hdr_length_MASK 0x0000001F +#define lpfc_rcqe_hdr_length_WORD word3 +#define lpfc_rcqe_code_SHIFT lpfc_cqe_code_SHIFT +#define lpfc_rcqe_code_MASK lpfc_cqe_code_MASK +#define lpfc_rcqe_code_WORD lpfc_cqe_code_WORD +#define lpfc_rcqe_eof_SHIFT 8 +#define lpfc_rcqe_eof_MASK 0x000000FF +#define lpfc_rcqe_eof_WORD word3 +#define FCOE_EOFn 0x41 +#define FCOE_EOFt 0x42 +#define FCOE_EOFni 0x49 +#define FCOE_EOFa 0x50 +#define lpfc_rcqe_sof_SHIFT 0 +#define lpfc_rcqe_sof_MASK 0x000000FF +#define lpfc_rcqe_sof_WORD word3 +#define FCOE_SOFi2 0x2d +#define FCOE_SOFi3 0x2e +#define FCOE_SOFn2 0x35 +#define FCOE_SOFn3 0x36 +}; + +struct lpfc_wqe_generic{ + struct ulp_bde64 bde; + uint32_t word3; + uint32_t word4; + uint32_t word5; + uint32_t word6; +#define lpfc_wqe_gen_context_SHIFT 16 +#define lpfc_wqe_gen_context_MASK 0x0000FFFF +#define lpfc_wqe_gen_context_WORD word6 +#define lpfc_wqe_gen_xri_SHIFT 0 +#define lpfc_wqe_gen_xri_MASK 0x0000FFFF +#define lpfc_wqe_gen_xri_WORD word6 + uint32_t word7; +#define lpfc_wqe_gen_lnk_SHIFT 23 +#define lpfc_wqe_gen_lnk_MASK 0x00000001 +#define lpfc_wqe_gen_lnk_WORD word7 +#define lpfc_wqe_gen_erp_SHIFT 22 +#define lpfc_wqe_gen_erp_MASK 0x00000001 +#define lpfc_wqe_gen_erp_WORD word7 +#define lpfc_wqe_gen_pu_SHIFT 20 +#define lpfc_wqe_gen_pu_MASK 0x00000003 +#define lpfc_wqe_gen_pu_WORD word7 +#define lpfc_wqe_gen_class_SHIFT 16 +#define lpfc_wqe_gen_class_MASK 0x00000007 +#define lpfc_wqe_gen_class_WORD word7 +#define lpfc_wqe_gen_command_SHIFT 8 +#define lpfc_wqe_gen_command_MASK 0x000000FF +#define lpfc_wqe_gen_command_WORD word7 +#define lpfc_wqe_gen_status_SHIFT 4 +#define lpfc_wqe_gen_status_MASK 0x0000000F +#define lpfc_wqe_gen_status_WORD word7 +#define lpfc_wqe_gen_ct_SHIFT 2 +#define lpfc_wqe_gen_ct_MASK 0x00000007 +#define lpfc_wqe_gen_ct_WORD word7 + uint32_t abort_tag; + uint32_t word9; +#define lpfc_wqe_gen_request_tag_SHIFT 0 +#define lpfc_wqe_gen_request_tag_MASK 0x0000FFFF +#define lpfc_wqe_gen_request_tag_WORD word9 + uint32_t word10; +#define lpfc_wqe_gen_ccp_SHIFT 24 +#define lpfc_wqe_gen_ccp_MASK 0x000000FF +#define lpfc_wqe_gen_ccp_WORD word10 +#define lpfc_wqe_gen_ccpe_SHIFT 23 +#define lpfc_wqe_gen_ccpe_MASK 0x00000001 +#define lpfc_wqe_gen_ccpe_WORD word10 +#define lpfc_wqe_gen_pv_SHIFT 19 +#define lpfc_wqe_gen_pv_MASK 0x00000001 +#define lpfc_wqe_gen_pv_WORD word10 +#define lpfc_wqe_gen_pri_SHIFT 16 +#define lpfc_wqe_gen_pri_MASK 0x00000007 +#define lpfc_wqe_gen_pri_WORD word10 + uint32_t word11; +#define lpfc_wqe_gen_cq_id_SHIFT 16 +#define lpfc_wqe_gen_cq_id_MASK 0x0000FFFF +#define lpfc_wqe_gen_cq_id_WORD word11 +#define LPFC_WQE_CQ_ID_DEFAULT 0xffff +#define lpfc_wqe_gen_wqec_SHIFT 7 +#define lpfc_wqe_gen_wqec_MASK 0x00000001 +#define lpfc_wqe_gen_wqec_WORD word11 +#define lpfc_wqe_gen_cmd_type_SHIFT 0 +#define lpfc_wqe_gen_cmd_type_MASK 0x0000000F +#define lpfc_wqe_gen_cmd_type_WORD word11 + uint32_t payload[4]; +}; + +struct lpfc_rqe { + uint32_t address_hi; + uint32_t address_lo; +}; + +/* buffer descriptors */ +struct lpfc_bde4 { + uint32_t addr_hi; + uint32_t addr_lo; + uint32_t word2; +#define lpfc_bde4_last_SHIFT 31 +#define lpfc_bde4_last_MASK 0x00000001 +#define lpfc_bde4_last_WORD word2 +#define lpfc_bde4_sge_offset_SHIFT 0 +#define lpfc_bde4_sge_offset_MASK 0x000003FF +#define lpfc_bde4_sge_offset_WORD word2 + uint32_t word3; +#define lpfc_bde4_length_SHIFT 0 +#define lpfc_bde4_length_MASK 0x000000FF +#define lpfc_bde4_length_WORD word3 +}; + +struct lpfc_register { + uint32_t word0; +}; + +#define LPFC_UERR_STATUS_HI 0x00A4 +#define LPFC_UERR_STATUS_LO 0x00A0 +#define LPFC_ONLINE0 0x00B0 +#define LPFC_ONLINE1 0x00B4 +#define LPFC_SCRATCHPAD 0x0058 + +/* BAR0 Registers */ +#define LPFC_HST_STATE 0x00AC +#define lpfc_hst_state_perr_SHIFT 31 +#define lpfc_hst_state_perr_MASK 0x1 +#define lpfc_hst_state_perr_WORD word0 +#define lpfc_hst_state_sfi_SHIFT 30 +#define lpfc_hst_state_sfi_MASK 0x1 +#define lpfc_hst_state_sfi_WORD word0 +#define lpfc_hst_state_nip_SHIFT 29 +#define lpfc_hst_state_nip_MASK 0x1 +#define lpfc_hst_state_nip_WORD word0 +#define lpfc_hst_state_ipc_SHIFT 28 +#define lpfc_hst_state_ipc_MASK 0x1 +#define lpfc_hst_state_ipc_WORD word0 +#define lpfc_hst_state_xrom_SHIFT 27 +#define lpfc_hst_state_xrom_MASK 0x1 +#define lpfc_hst_state_xrom_WORD word0 +#define lpfc_hst_state_dl_SHIFT 26 +#define lpfc_hst_state_dl_MASK 0x1 +#define lpfc_hst_state_dl_WORD word0 +#define lpfc_hst_state_port_status_SHIFT 0 +#define lpfc_hst_state_port_status_MASK 0xFFFF +#define lpfc_hst_state_port_status_WORD word0 + +#define LPFC_POST_STAGE_POWER_ON_RESET 0x0000 +#define LPFC_POST_STAGE_AWAITING_HOST_RDY 0x0001 +#define LPFC_POST_STAGE_HOST_RDY 0x0002 +#define LPFC_POST_STAGE_BE_RESET 0x0003 +#define LPFC_POST_STAGE_SEEPROM_CS_START 0x0100 +#define LPFC_POST_STAGE_SEEPROM_CS_DONE 0x0101 +#define LPFC_POST_STAGE_DDR_CONFIG_START 0x0200 +#define LPFC_POST_STAGE_DDR_CONFIG_DONE 0x0201 +#define LPFC_POST_STAGE_DDR_CALIBRATE_START 0x0300 +#define LPFC_POST_STAGE_DDR_CALIBRATE_DONE 0x0301 +#define LPFC_POST_STAGE_DDR_TEST_START 0x0400 +#define LPFC_POST_STAGE_DDR_TEST_DONE 0x0401 +#define LPFC_POST_STAGE_REDBOOT_INIT_START 0x0600 +#define LPFC_POST_STAGE_REDBOOT_INIT_DONE 0x0601 +#define LPFC_POST_STAGE_FW_IMAGE_LOAD_START 0x0700 +#define LPFC_POST_STAGE_FW_IMAGE_LOAD_DONE 0x0701 +#define LPFC_POST_STAGE_ARMFW_START 0x0800 +#define LPFC_POST_STAGE_DHCP_QUERY_START 0x0900 +#define LPFC_POST_STAGE_DHCP_QUERY_DONE 0x0901 +#define LPFC_POST_STAGE_BOOT_TARGET_DISCOVERY_START 0x0A00 +#define LPFC_POST_STAGE_BOOT_TARGET_DISCOVERY_DONE 0x0A01 +#define LPFC_POST_STAGE_RC_OPTION_SET 0x0B00 +#define LPFC_POST_STAGE_SWITCH_LINK 0x0B01 +#define LPFC_POST_STAGE_SEND_ICDS_MESSAGE 0x0B02 +#define LPFC_POST_STAGE_PERFROM_TFTP 0x0B03 +#define LPFC_POST_STAGE_PARSE_XML 0x0B04 +#define LPFC_POST_STAGE_DOWNLOAD_IMAGE 0x0B05 +#define LPFC_POST_STAGE_FLASH_IMAGE 0x0B06 +#define LPFC_POST_STAGE_RC_DONE 0x0B07 +#define LPFC_POST_STAGE_REBOOT_SYSTEM 0x0B08 +#define LPFC_POST_STAGE_MAC_ADDRESS 0x0C00 +#define LPFC_POST_STAGE_ARMFW_READY 0xC000 +#define LPFC_POST_STAGE_ARMFW_UE 0xF000 + +#define lpfc_scratchpad_slirev_SHIFT 4 +#define lpfc_scratchpad_slirev_MASK 0xF +#define lpfc_scratchpad_slirev_WORD word0 +#define lpfc_scratchpad_chiptype_SHIFT 8 +#define lpfc_scratchpad_chiptype_MASK 0xFF +#define lpfc_scratchpad_chiptype_WORD word0 +#define lpfc_scratchpad_featurelevel1_SHIFT 16 +#define lpfc_scratchpad_featurelevel1_MASK 0xFF +#define lpfc_scratchpad_featurelevel1_WORD word0 +#define lpfc_scratchpad_featurelevel2_SHIFT 24 +#define lpfc_scratchpad_featurelevel2_MASK 0xFF +#define lpfc_scratchpad_featurelevel2_WORD word0 + +/* BAR1 Registers */ +#define LPFC_IMR_MASK_ALL 0xFFFFFFFF +#define LPFC_ISCR_CLEAR_ALL 0xFFFFFFFF + +#define LPFC_HST_ISR0 0x0C18 +#define LPFC_HST_ISR1 0x0C1C +#define LPFC_HST_ISR2 0x0C20 +#define LPFC_HST_ISR3 0x0C24 +#define LPFC_HST_ISR4 0x0C28 + +#define LPFC_HST_IMR0 0x0C48 +#define LPFC_HST_IMR1 0x0C4C +#define LPFC_HST_IMR2 0x0C50 +#define LPFC_HST_IMR3 0x0C54 +#define LPFC_HST_IMR4 0x0C58 + +#define LPFC_HST_ISCR0 0x0C78 +#define LPFC_HST_ISCR1 0x0C7C +#define LPFC_HST_ISCR2 0x0C80 +#define LPFC_HST_ISCR3 0x0C84 +#define LPFC_HST_ISCR4 0x0C88 + +#define LPFC_SLI4_INTR0 BIT0 +#define LPFC_SLI4_INTR1 BIT1 +#define LPFC_SLI4_INTR2 BIT2 +#define LPFC_SLI4_INTR3 BIT3 +#define LPFC_SLI4_INTR4 BIT4 +#define LPFC_SLI4_INTR5 BIT5 +#define LPFC_SLI4_INTR6 BIT6 +#define LPFC_SLI4_INTR7 BIT7 +#define LPFC_SLI4_INTR8 BIT8 +#define LPFC_SLI4_INTR9 BIT9 +#define LPFC_SLI4_INTR10 BIT10 +#define LPFC_SLI4_INTR11 BIT11 +#define LPFC_SLI4_INTR12 BIT12 +#define LPFC_SLI4_INTR13 BIT13 +#define LPFC_SLI4_INTR14 BIT14 +#define LPFC_SLI4_INTR15 BIT15 +#define LPFC_SLI4_INTR16 BIT16 +#define LPFC_SLI4_INTR17 BIT17 +#define LPFC_SLI4_INTR18 BIT18 +#define LPFC_SLI4_INTR19 BIT19 +#define LPFC_SLI4_INTR20 BIT20 +#define LPFC_SLI4_INTR21 BIT21 +#define LPFC_SLI4_INTR22 BIT22 +#define LPFC_SLI4_INTR23 BIT23 +#define LPFC_SLI4_INTR24 BIT24 +#define LPFC_SLI4_INTR25 BIT25 +#define LPFC_SLI4_INTR26 BIT26 +#define LPFC_SLI4_INTR27 BIT27 +#define LPFC_SLI4_INTR28 BIT28 +#define LPFC_SLI4_INTR29 BIT29 +#define LPFC_SLI4_INTR30 BIT30 +#define LPFC_SLI4_INTR31 BIT31 + +/* BAR2 Registers */ +#define LPFC_RQ_DOORBELL 0x00A0 +#define lpfc_rq_doorbell_num_posted_SHIFT 16 +#define lpfc_rq_doorbell_num_posted_MASK 0x3FFF +#define lpfc_rq_doorbell_num_posted_WORD word0 +#define LPFC_RQ_POST_BATCH 8 /* RQEs to post at one time */ +#define lpfc_rq_doorbell_id_SHIFT 0 +#define lpfc_rq_doorbell_id_MASK 0x03FF +#define lpfc_rq_doorbell_id_WORD word0 + +#define LPFC_WQ_DOORBELL 0x0040 +#define lpfc_wq_doorbell_num_posted_SHIFT 24 +#define lpfc_wq_doorbell_num_posted_MASK 0x00FF +#define lpfc_wq_doorbell_num_posted_WORD word0 +#define lpfc_wq_doorbell_index_SHIFT 16 +#define lpfc_wq_doorbell_index_MASK 0x00FF +#define lpfc_wq_doorbell_index_WORD word0 +#define lpfc_wq_doorbell_id_SHIFT 0 +#define lpfc_wq_doorbell_id_MASK 0xFFFF +#define lpfc_wq_doorbell_id_WORD word0 + +#define LPFC_EQCQ_DOORBELL 0x0120 +#define lpfc_eqcq_doorbell_arm_SHIFT 29 +#define lpfc_eqcq_doorbell_arm_MASK 0x0001 +#define lpfc_eqcq_doorbell_arm_WORD word0 +#define lpfc_eqcq_doorbell_num_released_SHIFT 16 +#define lpfc_eqcq_doorbell_num_released_MASK 0x1FFF +#define lpfc_eqcq_doorbell_num_released_WORD word0 +#define lpfc_eqcq_doorbell_qt_SHIFT 10 +#define lpfc_eqcq_doorbell_qt_MASK 0x0001 +#define lpfc_eqcq_doorbell_qt_WORD word0 +#define LPFC_QUEUE_TYPE_COMPLETION 0 +#define LPFC_QUEUE_TYPE_EVENT 1 +#define lpfc_eqcq_doorbell_eqci_SHIFT 9 +#define lpfc_eqcq_doorbell_eqci_MASK 0x0001 +#define lpfc_eqcq_doorbell_eqci_WORD word0 +#define lpfc_eqcq_doorbell_cqid_SHIFT 0 +#define lpfc_eqcq_doorbell_cqid_MASK 0x03FF +#define lpfc_eqcq_doorbell_cqid_WORD word0 +#define lpfc_eqcq_doorbell_eqid_SHIFT 0 +#define lpfc_eqcq_doorbell_eqid_MASK 0x01FF +#define lpfc_eqcq_doorbell_eqid_WORD word0 + +#define LPFC_BMBX 0x0160 +#define lpfc_bmbx_addr_SHIFT 2 +#define lpfc_bmbx_addr_MASK 0x3FFFFFFF +#define lpfc_bmbx_addr_WORD word0 +#define lpfc_bmbx_hi_SHIFT 1 +#define lpfc_bmbx_hi_MASK 0x0001 +#define lpfc_bmbx_hi_WORD word0 +#define lpfc_bmbx_rdy_SHIFT 0 +#define lpfc_bmbx_rdy_MASK 0x0001 +#define lpfc_bmbx_rdy_WORD word0 + +#define LPFC_MQ_DOORBELL 0x0140 +#define lpfc_mq_doorbell_num_posted_SHIFT 16 +#define lpfc_mq_doorbell_num_posted_MASK 0x3FFF +#define lpfc_mq_doorbell_num_posted_WORD word0 +#define lpfc_mq_doorbell_id_SHIFT 0 +#define lpfc_mq_doorbell_id_MASK 0x03FF +#define lpfc_mq_doorbell_id_WORD word0 + +struct lpfc_sli4_cfg_mhdr { + uint32_t word1; +#define lpfc_mbox_hdr_emb_SHIFT 0 +#define lpfc_mbox_hdr_emb_MASK 0x00000001 +#define lpfc_mbox_hdr_emb_WORD word1 +#define lpfc_mbox_hdr_sge_cnt_SHIFT 3 +#define lpfc_mbox_hdr_sge_cnt_MASK 0x0000001F +#define lpfc_mbox_hdr_sge_cnt_WORD word1 + uint32_t payload_length; + uint32_t tag_lo; + uint32_t tag_hi; + uint32_t reserved5; +}; + +union lpfc_sli4_cfg_shdr { + struct { + uint32_t word6; +#define lpfc_mbox_hdr_opcode_SHIFT 0 +#define lpfc_mbox_hdr_opcode_MASK 0x000000FF +#define lpfc_mbox_hdr_opcode_WORD word6 +#define lpfc_mbox_hdr_subsystem_SHIFT 8 +#define lpfc_mbox_hdr_subsystem_MASK 0x000000FF +#define lpfc_mbox_hdr_subsystem_WORD word6 +#define lpfc_mbox_hdr_port_number_SHIFT 16 +#define lpfc_mbox_hdr_port_number_MASK 0x000000FF +#define lpfc_mbox_hdr_port_number_WORD word6 +#define lpfc_mbox_hdr_domain_SHIFT 24 +#define lpfc_mbox_hdr_domain_MASK 0x000000FF +#define lpfc_mbox_hdr_domain_WORD word6 + uint32_t timeout; + uint32_t request_length; + uint32_t reserved9; + } request; + struct { + uint32_t word6; +#define lpfc_mbox_hdr_opcode_SHIFT 0 +#define lpfc_mbox_hdr_opcode_MASK 0x000000FF +#define lpfc_mbox_hdr_opcode_WORD word6 +#define lpfc_mbox_hdr_subsystem_SHIFT 8 +#define lpfc_mbox_hdr_subsystem_MASK 0x000000FF +#define lpfc_mbox_hdr_subsystem_WORD word6 +#define lpfc_mbox_hdr_domain_SHIFT 24 +#define lpfc_mbox_hdr_domain_MASK 0x000000FF +#define lpfc_mbox_hdr_domain_WORD word6 + uint32_t word7; +#define lpfc_mbox_hdr_status_SHIFT 0 +#define lpfc_mbox_hdr_status_MASK 0x000000FF +#define lpfc_mbox_hdr_status_WORD word7 +#define lpfc_mbox_hdr_add_status_SHIFT 8 +#define lpfc_mbox_hdr_add_status_MASK 0x000000FF +#define lpfc_mbox_hdr_add_status_WORD word7 + uint32_t response_length; + uint32_t actual_response_length; + } response; +}; + +/* Mailbox structures */ +struct mbox_header { + struct lpfc_sli4_cfg_mhdr cfg_mhdr; + union lpfc_sli4_cfg_shdr cfg_shdr; +}; + +/* Subsystem Definitions */ +#define LPFC_MBOX_SUBSYSTEM_COMMON 0x1 +#define LPFC_MBOX_SUBSYSTEM_FCOE 0xC + +/* Device Specific Definitions */ + +/* The HOST ENDIAN defines are in Big Endian format. */ +#define HOST_ENDIAN_LOW_WORD0 0xFF3412FF +#define HOST_ENDIAN_HIGH_WORD1 0xFF7856FF + +/* Common Opcodes */ +#define LPFC_MBOX_OPCODE_CQ_CREATE 0x0C +#define LPFC_MBOX_OPCODE_EQ_CREATE 0x0D +#define LPFC_MBOX_OPCODE_MQ_CREATE 0x15 +#define LPFC_MBOX_OPCODE_GET_CNTL_ATTRIBUTES 0x20 +#define LPFC_MBOX_OPCODE_NOP 0x21 +#define LPFC_MBOX_OPCODE_MQ_DESTROY 0x35 +#define LPFC_MBOX_OPCODE_CQ_DESTROY 0x36 +#define LPFC_MBOX_OPCODE_EQ_DESTROY 0x37 +#define LPFC_MBOX_OPCODE_FUNCTION_RESET 0x3D + +/* FCoE Opcodes */ +#define LPFC_MBOX_OPCODE_FCOE_WQ_CREATE 0x01 +#define LPFC_MBOX_OPCODE_FCOE_WQ_DESTROY 0x02 +#define LPFC_MBOX_OPCODE_FCOE_POST_SGL_PAGES 0x03 +#define LPFC_MBOX_OPCODE_FCOE_REMOVE_SGL_PAGES 0x04 +#define LPFC_MBOX_OPCODE_FCOE_RQ_CREATE 0x05 +#define LPFC_MBOX_OPCODE_FCOE_RQ_DESTROY 0x06 +#define LPFC_MBOX_OPCODE_FCOE_READ_FCF_TABLE 0x08 +#define LPFC_MBOX_OPCODE_FCOE_ADD_FCF 0x09 +#define LPFC_MBOX_OPCODE_FCOE_DELETE_FCF 0x0A +#define LPFC_MBOX_OPCODE_FCOE_POST_HDR_TEMPLATE 0x0B + +/* Mailbox command structures */ +struct eq_context { + uint32_t word0; +#define lpfc_eq_context_size_SHIFT 31 +#define lpfc_eq_context_size_MASK 0x00000001 +#define lpfc_eq_context_size_WORD word0 +#define LPFC_EQE_SIZE_4 0x0 +#define LPFC_EQE_SIZE_16 0x1 +#define lpfc_eq_context_valid_SHIFT 29 +#define lpfc_eq_context_valid_MASK 0x00000001 +#define lpfc_eq_context_valid_WORD word0 + uint32_t word1; +#define lpfc_eq_context_count_SHIFT 26 +#define lpfc_eq_context_count_MASK 0x00000003 +#define lpfc_eq_context_count_WORD word1 +#define LPFC_EQ_CNT_256 0x0 +#define LPFC_EQ_CNT_512 0x1 +#define LPFC_EQ_CNT_1024 0x2 +#define LPFC_EQ_CNT_2048 0x3 +#define LPFC_EQ_CNT_4096 0x4 + uint32_t word2; +#define lpfc_eq_context_delay_multi_SHIFT 13 +#define lpfc_eq_context_delay_multi_MASK 0x000003FF +#define lpfc_eq_context_delay_multi_WORD word2 + uint32_t reserved3; +}; + +struct sgl_page_pairs { + uint32_t sgl_pg0_addr_lo; + uint32_t sgl_pg0_addr_hi; + uint32_t sgl_pg1_addr_lo; + uint32_t sgl_pg1_addr_hi; +}; + +struct lpfc_mbx_post_sgl_pages { + struct mbox_header header; + uint32_t word0; +#define lpfc_post_sgl_pages_xri_SHIFT 0 +#define lpfc_post_sgl_pages_xri_MASK 0x0000FFFF +#define lpfc_post_sgl_pages_xri_WORD word0 +#define lpfc_post_sgl_pages_xricnt_SHIFT 16 +#define lpfc_post_sgl_pages_xricnt_MASK 0x0000FFFF +#define lpfc_post_sgl_pages_xricnt_WORD word0 + struct sgl_page_pairs sgl_pg_pairs[1]; +}; + +/* word0 of page-1 struct shares the same SHIFT/MASK/WORD defines as above */ +struct lpfc_mbx_post_uembed_sgl_page1 { + union lpfc_sli4_cfg_shdr cfg_shdr; + uint32_t word0; + struct sgl_page_pairs sgl_pg_pairs; +}; + +struct lpfc_mbx_sge { + uint32_t pa_lo; + uint32_t pa_hi; + uint32_t length; +}; + +struct lpfc_mbx_nembed_cmd { + struct lpfc_sli4_cfg_mhdr cfg_mhdr; +#define LPFC_SLI4_MBX_SGE_MAX_PAGES 19 + struct lpfc_mbx_sge sge[LPFC_SLI4_MBX_SGE_MAX_PAGES]; +}; + +struct lpfc_mbx_nembed_sge_virt { + void *addr[LPFC_SLI4_MBX_SGE_MAX_PAGES]; +}; + +struct lpfc_mbx_eq_create { + struct mbox_header header; + union { + struct { + uint32_t word0; +#define lpfc_mbx_eq_create_num_pages_SHIFT 0 +#define lpfc_mbx_eq_create_num_pages_MASK 0x0000FFFF +#define lpfc_mbx_eq_create_num_pages_WORD word0 + struct eq_context context; + struct dma_address page[LPFC_MAX_EQ_PAGE]; + } request; + struct { + uint32_t word0; +#define lpfc_mbx_eq_create_q_id_SHIFT 0 +#define lpfc_mbx_eq_create_q_id_MASK 0x0000FFFF +#define lpfc_mbx_eq_create_q_id_WORD word0 + } response; + } u; +}; + +struct lpfc_mbx_eq_destroy { + struct mbox_header header; + union { + struct { + uint32_t word0; +#define lpfc_mbx_eq_destroy_q_id_SHIFT 0 +#define lpfc_mbx_eq_destroy_q_id_MASK 0x0000FFFF +#define lpfc_mbx_eq_destroy_q_id_WORD word0 + } request; + struct { + uint32_t word0; + } response; + } u; +}; + +struct lpfc_mbx_nop { + struct mbox_header header; + uint32_t context[2]; +}; + +struct cq_context { + uint32_t word0; +#define lpfc_cq_context_event_SHIFT 31 +#define lpfc_cq_context_event_MASK 0x00000001 +#define lpfc_cq_context_event_WORD word0 +#define lpfc_cq_context_valid_SHIFT 29 +#define lpfc_cq_context_valid_MASK 0x00000001 +#define lpfc_cq_context_valid_WORD word0 +#define lpfc_cq_context_count_SHIFT 27 +#define lpfc_cq_context_count_MASK 0x00000003 +#define lpfc_cq_context_count_WORD word0 +#define LPFC_CQ_CNT_256 0x0 +#define LPFC_CQ_CNT_512 0x1 +#define LPFC_CQ_CNT_1024 0x2 + uint32_t word1; +#define lpfc_cq_eq_id_SHIFT 22 +#define lpfc_cq_eq_id_MASK 0x000000FF +#define lpfc_cq_eq_id_WORD word1 + uint32_t reserved0; + uint32_t reserved1; +}; + +struct lpfc_mbx_cq_create { + struct mbox_header header; + union { + struct { + uint32_t word0; +#define lpfc_mbx_cq_create_num_pages_SHIFT 0 +#define lpfc_mbx_cq_create_num_pages_MASK 0x0000FFFF +#define lpfc_mbx_cq_create_num_pages_WORD word0 + struct cq_context context; + struct dma_address page[LPFC_MAX_CQ_PAGE]; + } request; + struct { + uint32_t word0; +#define lpfc_mbx_cq_create_q_id_SHIFT 0 +#define lpfc_mbx_cq_create_q_id_MASK 0x0000FFFF +#define lpfc_mbx_cq_create_q_id_WORD word0 + } response; + } u; +}; + +struct lpfc_mbx_cq_destroy { + struct mbox_header header; + union { + struct { + uint32_t word0; +#define lpfc_mbx_cq_destroy_q_id_SHIFT 0 +#define lpfc_mbx_cq_destroy_q_id_MASK 0x0000FFFF +#define lpfc_mbx_cq_destroy_q_id_WORD word0 + } request; + struct { + uint32_t word0; + } response; + } u; +}; + +struct wq_context { + uint32_t reserved0; + uint32_t reserved1; + uint32_t reserved2; + uint32_t reserved3; +}; + +struct lpfc_mbx_wq_create { + struct mbox_header header; + union { + struct { + uint32_t word0; +#define lpfc_mbx_wq_create_num_pages_SHIFT 0 +#define lpfc_mbx_wq_create_num_pages_MASK 0x0000FFFF +#define lpfc_mbx_wq_create_num_pages_WORD word0 +#define lpfc_mbx_wq_create_cq_id_SHIFT 16 +#define lpfc_mbx_wq_create_cq_id_MASK 0x0000FFFF +#define lpfc_mbx_wq_create_cq_id_WORD word0 + struct dma_address page[LPFC_MAX_WQ_PAGE]; + } request; + struct { + uint32_t word0; +#define lpfc_mbx_wq_create_q_id_SHIFT 0 +#define lpfc_mbx_wq_create_q_id_MASK 0x0000FFFF +#define lpfc_mbx_wq_create_q_id_WORD word0 + } response; + } u; +}; + +struct lpfc_mbx_wq_destroy { + struct mbox_header header; + union { + struct { + uint32_t word0; +#define lpfc_mbx_wq_destroy_q_id_SHIFT 0 +#define lpfc_mbx_wq_destroy_q_id_MASK 0x0000FFFF +#define lpfc_mbx_wq_destroy_q_id_WORD word0 + } request; + struct { + uint32_t word0; + } response; + } u; +}; + +#define LPFC_HDR_BUF_SIZE 128 +#define LPFC_DATA_BUF_SIZE 4096 +struct rq_context { + uint32_t word0; +#define lpfc_rq_context_rq_size_SHIFT 16 +#define lpfc_rq_context_rq_size_MASK 0x0000000F +#define lpfc_rq_context_rq_size_WORD word0 +#define LPFC_RQ_RING_SIZE_512 9 /* 512 entries */ +#define LPFC_RQ_RING_SIZE_1024 10 /* 1024 entries */ +#define LPFC_RQ_RING_SIZE_2048 11 /* 2048 entries */ +#define LPFC_RQ_RING_SIZE_4096 12 /* 4096 entries */ + uint32_t reserved1; + uint32_t word2; +#define lpfc_rq_context_cq_id_SHIFT 16 +#define lpfc_rq_context_cq_id_MASK 0x000003FF +#define lpfc_rq_context_cq_id_WORD word2 +#define lpfc_rq_context_buf_size_SHIFT 0 +#define lpfc_rq_context_buf_size_MASK 0x0000FFFF +#define lpfc_rq_context_buf_size_WORD word2 + uint32_t reserved3; +}; + +struct lpfc_mbx_rq_create { + struct mbox_header header; + union { + struct { + uint32_t word0; +#define lpfc_mbx_rq_create_num_pages_SHIFT 0 +#define lpfc_mbx_rq_create_num_pages_MASK 0x0000FFFF +#define lpfc_mbx_rq_create_num_pages_WORD word0 + struct rq_context context; + struct dma_address page[LPFC_MAX_WQ_PAGE]; + } request; + struct { + uint32_t word0; +#define lpfc_mbx_rq_create_q_id_SHIFT 0 +#define lpfc_mbx_rq_create_q_id_MASK 0x0000FFFF +#define lpfc_mbx_rq_create_q_id_WORD word0 + } response; + } u; +}; + +struct lpfc_mbx_rq_destroy { + struct mbox_header header; + union { + struct { + uint32_t word0; +#define lpfc_mbx_rq_destroy_q_id_SHIFT 0 +#define lpfc_mbx_rq_destroy_q_id_MASK 0x0000FFFF +#define lpfc_mbx_rq_destroy_q_id_WORD word0 + } request; + struct { + uint32_t word0; + } response; + } u; +}; + +struct mq_context { + uint32_t word0; +#define lpfc_mq_context_cq_id_SHIFT 22 +#define lpfc_mq_context_cq_id_MASK 0x000003FF +#define lpfc_mq_context_cq_id_WORD word0 +#define lpfc_mq_context_count_SHIFT 16 +#define lpfc_mq_context_count_MASK 0x0000000F +#define lpfc_mq_context_count_WORD word0 +#define LPFC_MQ_CNT_16 0x5 +#define LPFC_MQ_CNT_32 0x6 +#define LPFC_MQ_CNT_64 0x7 +#define LPFC_MQ_CNT_128 0x8 + uint32_t word1; +#define lpfc_mq_context_valid_SHIFT 31 +#define lpfc_mq_context_valid_MASK 0x00000001 +#define lpfc_mq_context_valid_WORD word1 + uint32_t reserved2; + uint32_t reserved3; +}; + +struct lpfc_mbx_mq_create { + struct mbox_header header; + union { + struct { + uint32_t word0; +#define lpfc_mbx_mq_create_num_pages_SHIFT 0 +#define lpfc_mbx_mq_create_num_pages_MASK 0x0000FFFF +#define lpfc_mbx_mq_create_num_pages_WORD word0 + struct mq_context context; + struct dma_address page[LPFC_MAX_MQ_PAGE]; + } request; + struct { + uint32_t word0; +#define lpfc_mbx_mq_create_q_id_SHIFT 0 +#define lpfc_mbx_mq_create_q_id_MASK 0x0000FFFF +#define lpfc_mbx_mq_create_q_id_WORD word0 + } response; + } u; +}; + +struct lpfc_mbx_mq_destroy { + struct mbox_header header; + union { + struct { + uint32_t word0; +#define lpfc_mbx_mq_destroy_q_id_SHIFT 0 +#define lpfc_mbx_mq_destroy_q_id_MASK 0x0000FFFF +#define lpfc_mbx_mq_destroy_q_id_WORD word0 + } request; + struct { + uint32_t word0; + } response; + } u; +}; + +struct lpfc_mbx_post_hdr_tmpl { + struct mbox_header header; + uint32_t word10; +#define lpfc_mbx_post_hdr_tmpl_rpi_offset_SHIFT 0 +#define lpfc_mbx_post_hdr_tmpl_rpi_offset_MASK 0x0000FFFF +#define lpfc_mbx_post_hdr_tmpl_rpi_offset_WORD word10 +#define lpfc_mbx_post_hdr_tmpl_page_cnt_SHIFT 16 +#define lpfc_mbx_post_hdr_tmpl_page_cnt_MASK 0x0000FFFF +#define lpfc_mbx_post_hdr_tmpl_page_cnt_WORD word10 + uint32_t rpi_paddr_lo; + uint32_t rpi_paddr_hi; +}; + +struct sli4_sge { /* SLI-4 */ + uint32_t addr_hi; + uint32_t addr_lo; + + uint32_t word2; +#define lpfc_sli4_sge_offset_SHIFT 0 /* Offset of buffer - Not used*/ +#define lpfc_sli4_sge_offset_MASK 0x00FFFFFF +#define lpfc_sli4_sge_offset_WORD word2 +#define lpfc_sli4_sge_last_SHIFT 31 /* Last SEG in the SGL sets + this flag !! */ +#define lpfc_sli4_sge_last_MASK 0x00000001 +#define lpfc_sli4_sge_last_WORD word2 + uint32_t word3; +#define lpfc_sli4_sge_len_SHIFT 0 +#define lpfc_sli4_sge_len_MASK 0x0001FFFF +#define lpfc_sli4_sge_len_WORD word3 +}; + +struct fcf_record { + uint32_t max_rcv_size; + uint32_t fka_adv_period; + uint32_t fip_priority; + uint32_t word3; +#define lpfc_fcf_record_mac_0_SHIFT 0 +#define lpfc_fcf_record_mac_0_MASK 0x000000FF +#define lpfc_fcf_record_mac_0_WORD word3 +#define lpfc_fcf_record_mac_1_SHIFT 8 +#define lpfc_fcf_record_mac_1_MASK 0x000000FF +#define lpfc_fcf_record_mac_1_WORD word3 +#define lpfc_fcf_record_mac_2_SHIFT 16 +#define lpfc_fcf_record_mac_2_MASK 0x000000FF +#define lpfc_fcf_record_mac_2_WORD word3 +#define lpfc_fcf_record_mac_3_SHIFT 24 +#define lpfc_fcf_record_mac_3_MASK 0x000000FF +#define lpfc_fcf_record_mac_3_WORD word3 + uint32_t word4; +#define lpfc_fcf_record_mac_4_SHIFT 0 +#define lpfc_fcf_record_mac_4_MASK 0x000000FF +#define lpfc_fcf_record_mac_4_WORD word4 +#define lpfc_fcf_record_mac_5_SHIFT 8 +#define lpfc_fcf_record_mac_5_MASK 0x000000FF +#define lpfc_fcf_record_mac_5_WORD word4 +#define lpfc_fcf_record_fcf_avail_SHIFT 16 +#define lpfc_fcf_record_fcf_avail_MASK 0x000000FF +#define lpfc_fcf_record_fcf_avail_WORD word4 +#define lpfc_fcf_record_mac_addr_prov_SHIFT 24 +#define lpfc_fcf_record_mac_addr_prov_MASK 0x000000FF +#define lpfc_fcf_record_mac_addr_prov_WORD word4 +#define LPFC_FCF_FPMA 1 /* Fabric Provided MAC Address */ +#define LPFC_FCF_SPMA 2 /* Server Provided MAC Address */ + uint32_t word5; +#define lpfc_fcf_record_fab_name_0_SHIFT 0 +#define lpfc_fcf_record_fab_name_0_MASK 0x000000FF +#define lpfc_fcf_record_fab_name_0_WORD word5 +#define lpfc_fcf_record_fab_name_1_SHIFT 8 +#define lpfc_fcf_record_fab_name_1_MASK 0x000000FF +#define lpfc_fcf_record_fab_name_1_WORD word5 +#define lpfc_fcf_record_fab_name_2_SHIFT 16 +#define lpfc_fcf_record_fab_name_2_MASK 0x000000FF +#define lpfc_fcf_record_fab_name_2_WORD word5 +#define lpfc_fcf_record_fab_name_3_SHIFT 24 +#define lpfc_fcf_record_fab_name_3_MASK 0x000000FF +#define lpfc_fcf_record_fab_name_3_WORD word5 + uint32_t word6; +#define lpfc_fcf_record_fab_name_4_SHIFT 0 +#define lpfc_fcf_record_fab_name_4_MASK 0x000000FF +#define lpfc_fcf_record_fab_name_4_WORD word6 +#define lpfc_fcf_record_fab_name_5_SHIFT 8 +#define lpfc_fcf_record_fab_name_5_MASK 0x000000FF +#define lpfc_fcf_record_fab_name_5_WORD word6 +#define lpfc_fcf_record_fab_name_6_SHIFT 16 +#define lpfc_fcf_record_fab_name_6_MASK 0x000000FF +#define lpfc_fcf_record_fab_name_6_WORD word6 +#define lpfc_fcf_record_fab_name_7_SHIFT 24 +#define lpfc_fcf_record_fab_name_7_MASK 0x000000FF +#define lpfc_fcf_record_fab_name_7_WORD word6 + uint32_t word7; +#define lpfc_fcf_record_fc_map_0_SHIFT 0 +#define lpfc_fcf_record_fc_map_0_MASK 0x000000FF +#define lpfc_fcf_record_fc_map_0_WORD word7 +#define lpfc_fcf_record_fc_map_1_SHIFT 8 +#define lpfc_fcf_record_fc_map_1_MASK 0x000000FF +#define lpfc_fcf_record_fc_map_1_WORD word7 +#define lpfc_fcf_record_fc_map_2_SHIFT 16 +#define lpfc_fcf_record_fc_map_2_MASK 0x000000FF +#define lpfc_fcf_record_fc_map_2_WORD word7 +#define lpfc_fcf_record_fcf_valid_SHIFT 24 +#define lpfc_fcf_record_fcf_valid_MASK 0x000000FF +#define lpfc_fcf_record_fcf_valid_WORD word7 + uint32_t word8; +#define lpfc_fcf_record_fcf_index_SHIFT 0 +#define lpfc_fcf_record_fcf_index_MASK 0x0000FFFF +#define lpfc_fcf_record_fcf_index_WORD word8 +#define lpfc_fcf_record_fcf_state_SHIFT 16 +#define lpfc_fcf_record_fcf_state_MASK 0x0000FFFF +#define lpfc_fcf_record_fcf_state_WORD word8 + uint8_t vlan_bitmap[512]; +}; + +struct lpfc_mbx_read_fcf_tbl { + union lpfc_sli4_cfg_shdr cfg_shdr; + union { + struct { + uint32_t word10; +#define lpfc_mbx_read_fcf_tbl_indx_SHIFT 0 +#define lpfc_mbx_read_fcf_tbl_indx_MASK 0x0000FFFF +#define lpfc_mbx_read_fcf_tbl_indx_WORD word10 + } request; + struct { + uint32_t eventag; + } response; + } u; + uint32_t word11; +#define lpfc_mbx_read_fcf_tbl_nxt_vindx_SHIFT 0 +#define lpfc_mbx_read_fcf_tbl_nxt_vindx_MASK 0x0000FFFF +#define lpfc_mbx_read_fcf_tbl_nxt_vindx_WORD word11 +}; + +struct lpfc_mbx_add_fcf_tbl_entry { + union lpfc_sli4_cfg_shdr cfg_shdr; + uint32_t word10; +#define lpfc_mbx_add_fcf_tbl_fcfi_SHIFT 0 +#define lpfc_mbx_add_fcf_tbl_fcfi_MASK 0x0000FFFF +#define lpfc_mbx_add_fcf_tbl_fcfi_WORD word10 + struct lpfc_mbx_sge fcf_sge; +}; + +struct lpfc_mbx_del_fcf_tbl_entry { + struct mbox_header header; + uint32_t word10; +#define lpfc_mbx_del_fcf_tbl_count_SHIFT 0 +#define lpfc_mbx_del_fcf_tbl_count_MASK 0x0000FFFF +#define lpfc_mbx_del_fcf_tbl_count_WORD word10 +#define lpfc_mbx_del_fcf_tbl_index_SHIFT 16 +#define lpfc_mbx_del_fcf_tbl_index_MASK 0x0000FFFF +#define lpfc_mbx_del_fcf_tbl_index_WORD word10 +}; + +/* Status field for embedded SLI_CONFIG mailbox command */ +#define STATUS_SUCCESS 0x0 +#define STATUS_FAILED 0x1 +#define STATUS_ILLEGAL_REQUEST 0x2 +#define STATUS_ILLEGAL_FIELD 0x3 +#define STATUS_INSUFFICIENT_BUFFER 0x4 +#define STATUS_UNAUTHORIZED_REQUEST 0x5 +#define STATUS_FLASHROM_SAVE_FAILED 0x17 +#define STATUS_FLASHROM_RESTORE_FAILED 0x18 +#define STATUS_ICCBINDEX_ALLOC_FAILED 0x1a +#define STATUS_IOCTLHANDLE_ALLOC_FAILED 0x1b +#define STATUS_INVALID_PHY_ADDR_FROM_OSM 0x1c +#define STATUS_INVALID_PHY_ADDR_LEN_FROM_OSM 0x1d +#define STATUS_ASSERT_FAILED 0x1e +#define STATUS_INVALID_SESSION 0x1f +#define STATUS_INVALID_CONNECTION 0x20 +#define STATUS_BTL_PATH_EXCEEDS_OSM_LIMIT 0x21 +#define STATUS_BTL_NO_FREE_SLOT_PATH 0x24 +#define STATUS_BTL_NO_FREE_SLOT_TGTID 0x25 +#define STATUS_OSM_DEVSLOT_NOT_FOUND 0x26 +#define STATUS_FLASHROM_READ_FAILED 0x27 +#define STATUS_POLL_IOCTL_TIMEOUT 0x28 +#define STATUS_ERROR_ACITMAIN 0x2a +#define STATUS_REBOOT_REQUIRED 0x2c +#define STATUS_FCF_IN_USE 0x3a + +struct lpfc_mbx_sli4_config { + struct mbox_header header; +}; + +struct lpfc_mbx_init_vfi { + uint32_t word1; +#define lpfc_init_vfi_vr_SHIFT 31 +#define lpfc_init_vfi_vr_MASK 0x00000001 +#define lpfc_init_vfi_vr_WORD word1 +#define lpfc_init_vfi_vt_SHIFT 30 +#define lpfc_init_vfi_vt_MASK 0x00000001 +#define lpfc_init_vfi_vt_WORD word1 +#define lpfc_init_vfi_vf_SHIFT 29 +#define lpfc_init_vfi_vf_MASK 0x00000001 +#define lpfc_init_vfi_vf_WORD word1 +#define lpfc_init_vfi_vfi_SHIFT 0 +#define lpfc_init_vfi_vfi_MASK 0x0000FFFF +#define lpfc_init_vfi_vfi_WORD word1 + uint32_t word2; +#define lpfc_init_vfi_fcfi_SHIFT 0 +#define lpfc_init_vfi_fcfi_MASK 0x0000FFFF +#define lpfc_init_vfi_fcfi_WORD word2 + uint32_t word3; +#define lpfc_init_vfi_pri_SHIFT 13 +#define lpfc_init_vfi_pri_MASK 0x00000007 +#define lpfc_init_vfi_pri_WORD word3 +#define lpfc_init_vfi_vf_id_SHIFT 1 +#define lpfc_init_vfi_vf_id_MASK 0x00000FFF +#define lpfc_init_vfi_vf_id_WORD word3 + uint32_t word4; +#define lpfc_init_vfi_hop_count_SHIFT 24 +#define lpfc_init_vfi_hop_count_MASK 0x000000FF +#define lpfc_init_vfi_hop_count_WORD word4 +}; + +struct lpfc_mbx_reg_vfi { + uint32_t word1; +#define lpfc_reg_vfi_vp_SHIFT 28 +#define lpfc_reg_vfi_vp_MASK 0x00000001 +#define lpfc_reg_vfi_vp_WORD word1 +#define lpfc_reg_vfi_vfi_SHIFT 0 +#define lpfc_reg_vfi_vfi_MASK 0x0000FFFF +#define lpfc_reg_vfi_vfi_WORD word1 + uint32_t word2; +#define lpfc_reg_vfi_vpi_SHIFT 16 +#define lpfc_reg_vfi_vpi_MASK 0x0000FFFF +#define lpfc_reg_vfi_vpi_WORD word2 +#define lpfc_reg_vfi_fcfi_SHIFT 0 +#define lpfc_reg_vfi_fcfi_MASK 0x0000FFFF +#define lpfc_reg_vfi_fcfi_WORD word2 + uint32_t word3_rsvd; + uint32_t word4_rsvd; + struct ulp_bde64 bde; + uint32_t word8_rsvd; + uint32_t word9_rsvd; + uint32_t word10; +#define lpfc_reg_vfi_nport_id_SHIFT 0 +#define lpfc_reg_vfi_nport_id_MASK 0x00FFFFFF +#define lpfc_reg_vfi_nport_id_WORD word10 +}; + +struct lpfc_mbx_init_vpi { + uint32_t word1; +#define lpfc_init_vpi_vfi_SHIFT 16 +#define lpfc_init_vpi_vfi_MASK 0x0000FFFF +#define lpfc_init_vpi_vfi_WORD word1 +#define lpfc_init_vpi_vpi_SHIFT 0 +#define lpfc_init_vpi_vpi_MASK 0x0000FFFF +#define lpfc_init_vpi_vpi_WORD word1 +}; + +struct lpfc_mbx_read_vpi { + uint32_t word1_rsvd; + uint32_t word2; +#define lpfc_mbx_read_vpi_vnportid_SHIFT 0 +#define lpfc_mbx_read_vpi_vnportid_MASK 0x00FFFFFF +#define lpfc_mbx_read_vpi_vnportid_WORD word2 + uint32_t word3_rsvd; + uint32_t word4; +#define lpfc_mbx_read_vpi_acq_alpa_SHIFT 0 +#define lpfc_mbx_read_vpi_acq_alpa_MASK 0x000000FF +#define lpfc_mbx_read_vpi_acq_alpa_WORD word4 +#define lpfc_mbx_read_vpi_pb_SHIFT 15 +#define lpfc_mbx_read_vpi_pb_MASK 0x00000001 +#define lpfc_mbx_read_vpi_pb_WORD word4 +#define lpfc_mbx_read_vpi_spec_alpa_SHIFT 16 +#define lpfc_mbx_read_vpi_spec_alpa_MASK 0x000000FF +#define lpfc_mbx_read_vpi_spec_alpa_WORD word4 +#define lpfc_mbx_read_vpi_ns_SHIFT 30 +#define lpfc_mbx_read_vpi_ns_MASK 0x00000001 +#define lpfc_mbx_read_vpi_ns_WORD word4 +#define lpfc_mbx_read_vpi_hl_SHIFT 31 +#define lpfc_mbx_read_vpi_hl_MASK 0x00000001 +#define lpfc_mbx_read_vpi_hl_WORD word4 + uint32_t word5_rsvd; + uint32_t word6; +#define lpfc_mbx_read_vpi_vpi_SHIFT 0 +#define lpfc_mbx_read_vpi_vpi_MASK 0x0000FFFF +#define lpfc_mbx_read_vpi_vpi_WORD word6 + uint32_t word7; +#define lpfc_mbx_read_vpi_mac_0_SHIFT 0 +#define lpfc_mbx_read_vpi_mac_0_MASK 0x000000FF +#define lpfc_mbx_read_vpi_mac_0_WORD word7 +#define lpfc_mbx_read_vpi_mac_1_SHIFT 8 +#define lpfc_mbx_read_vpi_mac_1_MASK 0x000000FF +#define lpfc_mbx_read_vpi_mac_1_WORD word7 +#define lpfc_mbx_read_vpi_mac_2_SHIFT 16 +#define lpfc_mbx_read_vpi_mac_2_MASK 0x000000FF +#define lpfc_mbx_read_vpi_mac_2_WORD word7 +#define lpfc_mbx_read_vpi_mac_3_SHIFT 24 +#define lpfc_mbx_read_vpi_mac_3_MASK 0x000000FF +#define lpfc_mbx_read_vpi_mac_3_WORD word7 + uint32_t word8; +#define lpfc_mbx_read_vpi_mac_4_SHIFT 0 +#define lpfc_mbx_read_vpi_mac_4_MASK 0x000000FF +#define lpfc_mbx_read_vpi_mac_4_WORD word8 +#define lpfc_mbx_read_vpi_mac_5_SHIFT 8 +#define lpfc_mbx_read_vpi_mac_5_MASK 0x000000FF +#define lpfc_mbx_read_vpi_mac_5_WORD word8 +#define lpfc_mbx_read_vpi_vlan_tag_SHIFT 16 +#define lpfc_mbx_read_vpi_vlan_tag_MASK 0x00000FFF +#define lpfc_mbx_read_vpi_vlan_tag_WORD word8 +#define lpfc_mbx_read_vpi_vv_SHIFT 28 +#define lpfc_mbx_read_vpi_vv_MASK 0x0000001 +#define lpfc_mbx_read_vpi_vv_WORD word8 +}; + +struct lpfc_mbx_unreg_vfi { + uint32_t word1_rsvd; + uint32_t word2; +#define lpfc_unreg_vfi_vfi_SHIFT 0 +#define lpfc_unreg_vfi_vfi_MASK 0x0000FFFF +#define lpfc_unreg_vfi_vfi_WORD word2 +}; + +struct lpfc_mbx_resume_rpi { + uint32_t word1; +#define lpfc_resume_rpi_rpi_SHIFT 0 +#define lpfc_resume_rpi_rpi_MASK 0x0000FFFF +#define lpfc_resume_rpi_rpi_WORD word1 + uint32_t event_tag; + uint32_t word3_rsvd; + uint32_t word4_rsvd; + uint32_t word5_rsvd; + uint32_t word6; +#define lpfc_resume_rpi_vpi_SHIFT 0 +#define lpfc_resume_rpi_vpi_MASK 0x0000FFFF +#define lpfc_resume_rpi_vpi_WORD word6 +#define lpfc_resume_rpi_vfi_SHIFT 16 +#define lpfc_resume_rpi_vfi_MASK 0x0000FFFF +#define lpfc_resume_rpi_vfi_WORD word6 +}; + +#define REG_FCF_INVALID_QID 0xFFFF +struct lpfc_mbx_reg_fcfi { + uint32_t word1; +#define lpfc_reg_fcfi_info_index_SHIFT 0 +#define lpfc_reg_fcfi_info_index_MASK 0x0000FFFF +#define lpfc_reg_fcfi_info_index_WORD word1 +#define lpfc_reg_fcfi_fcfi_SHIFT 16 +#define lpfc_reg_fcfi_fcfi_MASK 0x0000FFFF +#define lpfc_reg_fcfi_fcfi_WORD word1 + uint32_t word2; +#define lpfc_reg_fcfi_rq_id1_SHIFT 0 +#define lpfc_reg_fcfi_rq_id1_MASK 0x0000FFFF +#define lpfc_reg_fcfi_rq_id1_WORD word2 +#define lpfc_reg_fcfi_rq_id0_SHIFT 16 +#define lpfc_reg_fcfi_rq_id0_MASK 0x0000FFFF +#define lpfc_reg_fcfi_rq_id0_WORD word2 + uint32_t word3; +#define lpfc_reg_fcfi_rq_id3_SHIFT 0 +#define lpfc_reg_fcfi_rq_id3_MASK 0x0000FFFF +#define lpfc_reg_fcfi_rq_id3_WORD word3 +#define lpfc_reg_fcfi_rq_id2_SHIFT 16 +#define lpfc_reg_fcfi_rq_id2_MASK 0x0000FFFF +#define lpfc_reg_fcfi_rq_id2_WORD word3 + uint32_t word4; +#define lpfc_reg_fcfi_type_match0_SHIFT 24 +#define lpfc_reg_fcfi_type_match0_MASK 0x000000FF +#define lpfc_reg_fcfi_type_match0_WORD word4 +#define lpfc_reg_fcfi_type_mask0_SHIFT 16 +#define lpfc_reg_fcfi_type_mask0_MASK 0x000000FF +#define lpfc_reg_fcfi_type_mask0_WORD word4 +#define lpfc_reg_fcfi_rctl_match0_SHIFT 8 +#define lpfc_reg_fcfi_rctl_match0_MASK 0x000000FF +#define lpfc_reg_fcfi_rctl_match0_WORD word4 +#define lpfc_reg_fcfi_rctl_mask0_SHIFT 0 +#define lpfc_reg_fcfi_rctl_mask0_MASK 0x000000FF +#define lpfc_reg_fcfi_rctl_mask0_WORD word4 + uint32_t word5; +#define lpfc_reg_fcfi_type_match1_SHIFT 24 +#define lpfc_reg_fcfi_type_match1_MASK 0x000000FF +#define lpfc_reg_fcfi_type_match1_WORD word5 +#define lpfc_reg_fcfi_type_mask1_SHIFT 16 +#define lpfc_reg_fcfi_type_mask1_MASK 0x000000FF +#define lpfc_reg_fcfi_type_mask1_WORD word5 +#define lpfc_reg_fcfi_rctl_match1_SHIFT 8 +#define lpfc_reg_fcfi_rctl_match1_MASK 0x000000FF +#define lpfc_reg_fcfi_rctl_match1_WORD word5 +#define lpfc_reg_fcfi_rctl_mask1_SHIFT 0 +#define lpfc_reg_fcfi_rctl_mask1_MASK 0x000000FF +#define lpfc_reg_fcfi_rctl_mask1_WORD word5 + uint32_t word6; +#define lpfc_reg_fcfi_type_match2_SHIFT 24 +#define lpfc_reg_fcfi_type_match2_MASK 0x000000FF +#define lpfc_reg_fcfi_type_match2_WORD word6 +#define lpfc_reg_fcfi_type_mask2_SHIFT 16 +#define lpfc_reg_fcfi_type_mask2_MASK 0x000000FF +#define lpfc_reg_fcfi_type_mask2_WORD word6 +#define lpfc_reg_fcfi_rctl_match2_SHIFT 8 +#define lpfc_reg_fcfi_rctl_match2_MASK 0x000000FF +#define lpfc_reg_fcfi_rctl_match2_WORD word6 +#define lpfc_reg_fcfi_rctl_mask2_SHIFT 0 +#define lpfc_reg_fcfi_rctl_mask2_MASK 0x000000FF +#define lpfc_reg_fcfi_rctl_mask2_WORD word6 + uint32_t word7; +#define lpfc_reg_fcfi_type_match3_SHIFT 24 +#define lpfc_reg_fcfi_type_match3_MASK 0x000000FF +#define lpfc_reg_fcfi_type_match3_WORD word7 +#define lpfc_reg_fcfi_type_mask3_SHIFT 16 +#define lpfc_reg_fcfi_type_mask3_MASK 0x000000FF +#define lpfc_reg_fcfi_type_mask3_WORD word7 +#define lpfc_reg_fcfi_rctl_match3_SHIFT 8 +#define lpfc_reg_fcfi_rctl_match3_MASK 0x000000FF +#define lpfc_reg_fcfi_rctl_match3_WORD word7 +#define lpfc_reg_fcfi_rctl_mask3_SHIFT 0 +#define lpfc_reg_fcfi_rctl_mask3_MASK 0x000000FF +#define lpfc_reg_fcfi_rctl_mask3_WORD word7 + uint32_t word8; +#define lpfc_reg_fcfi_mam_SHIFT 13 +#define lpfc_reg_fcfi_mam_MASK 0x00000003 +#define lpfc_reg_fcfi_mam_WORD word8 +#define LPFC_MAM_BOTH 0 /* Both SPMA and FPMA */ +#define LPFC_MAM_SPMA 1 /* Server Provided MAC Address */ +#define LPFC_MAM_FPMA 2 /* Fabric Provided MAC Address */ +#define lpfc_reg_fcfi_vv_SHIFT 12 +#define lpfc_reg_fcfi_vv_MASK 0x00000001 +#define lpfc_reg_fcfi_vv_WORD word8 +#define lpfc_reg_fcfi_vlan_tag_SHIFT 0 +#define lpfc_reg_fcfi_vlan_tag_MASK 0x00000FFF +#define lpfc_reg_fcfi_vlan_tag_WORD word8 +}; + +struct lpfc_mbx_unreg_fcfi { + uint32_t word1_rsv; + uint32_t word2; +#define lpfc_unreg_fcfi_SHIFT 0 +#define lpfc_unreg_fcfi_MASK 0x0000FFFF +#define lpfc_unreg_fcfi_WORD word2 +}; + +struct lpfc_mbx_read_rev { + uint32_t word1; +#define lpfc_mbx_rd_rev_sli_lvl_SHIFT 16 +#define lpfc_mbx_rd_rev_sli_lvl_MASK 0x0000000F +#define lpfc_mbx_rd_rev_sli_lvl_WORD word1 +#define lpfc_mbx_rd_rev_fcoe_SHIFT 20 +#define lpfc_mbx_rd_rev_fcoe_MASK 0x00000001 +#define lpfc_mbx_rd_rev_fcoe_WORD word1 +#define lpfc_mbx_rd_rev_vpd_SHIFT 29 +#define lpfc_mbx_rd_rev_vpd_MASK 0x00000001 +#define lpfc_mbx_rd_rev_vpd_WORD word1 + uint32_t first_hw_rev; + uint32_t second_hw_rev; + uint32_t word4_rsvd; + uint32_t third_hw_rev; + uint32_t word6; +#define lpfc_mbx_rd_rev_fcph_low_SHIFT 0 +#define lpfc_mbx_rd_rev_fcph_low_MASK 0x000000FF +#define lpfc_mbx_rd_rev_fcph_low_WORD word6 +#define lpfc_mbx_rd_rev_fcph_high_SHIFT 8 +#define lpfc_mbx_rd_rev_fcph_high_MASK 0x000000FF +#define lpfc_mbx_rd_rev_fcph_high_WORD word6 +#define lpfc_mbx_rd_rev_ftr_lvl_low_SHIFT 16 +#define lpfc_mbx_rd_rev_ftr_lvl_low_MASK 0x000000FF +#define lpfc_mbx_rd_rev_ftr_lvl_low_WORD word6 +#define lpfc_mbx_rd_rev_ftr_lvl_high_SHIFT 24 +#define lpfc_mbx_rd_rev_ftr_lvl_high_MASK 0x000000FF +#define lpfc_mbx_rd_rev_ftr_lvl_high_WORD word6 + uint32_t word7_rsvd; + uint32_t fw_id_rev; + uint8_t fw_name[16]; + uint32_t ulp_fw_id_rev; + uint8_t ulp_fw_name[16]; + uint32_t word18_47_rsvd[30]; + uint32_t word48; +#define lpfc_mbx_rd_rev_avail_len_SHIFT 0 +#define lpfc_mbx_rd_rev_avail_len_MASK 0x00FFFFFF +#define lpfc_mbx_rd_rev_avail_len_WORD word48 + uint32_t vpd_paddr_low; + uint32_t vpd_paddr_high; + uint32_t avail_vpd_len; + uint32_t rsvd_52_63[12]; +}; + +struct lpfc_mbx_read_config { + uint32_t word1; +#define lpfc_mbx_rd_conf_max_bbc_SHIFT 0 +#define lpfc_mbx_rd_conf_max_bbc_MASK 0x000000FF +#define lpfc_mbx_rd_conf_max_bbc_WORD word1 +#define lpfc_mbx_rd_conf_init_bbc_SHIFT 8 +#define lpfc_mbx_rd_conf_init_bbc_MASK 0x000000FF +#define lpfc_mbx_rd_conf_init_bbc_WORD word1 + uint32_t word2; +#define lpfc_mbx_rd_conf_nport_did_SHIFT 0 +#define lpfc_mbx_rd_conf_nport_did_MASK 0x00FFFFFF +#define lpfc_mbx_rd_conf_nport_did_WORD word2 +#define lpfc_mbx_rd_conf_topology_SHIFT 24 +#define lpfc_mbx_rd_conf_topology_MASK 0x000000FF +#define lpfc_mbx_rd_conf_topology_WORD word2 + uint32_t word3; +#define lpfc_mbx_rd_conf_ao_SHIFT 0 +#define lpfc_mbx_rd_conf_ao_MASK 0x00000001 +#define lpfc_mbx_rd_conf_ao_WORD word3 +#define lpfc_mbx_rd_conf_bb_scn_SHIFT 8 +#define lpfc_mbx_rd_conf_bb_scn_MASK 0x0000000F +#define lpfc_mbx_rd_conf_bb_scn_WORD word3 +#define lpfc_mbx_rd_conf_cbb_scn_SHIFT 12 +#define lpfc_mbx_rd_conf_cbb_scn_MASK 0x0000000F +#define lpfc_mbx_rd_conf_cbb_scn_WORD word3 +#define lpfc_mbx_rd_conf_mc_SHIFT 29 +#define lpfc_mbx_rd_conf_mc_MASK 0x00000001 +#define lpfc_mbx_rd_conf_mc_WORD word3 + uint32_t word4; +#define lpfc_mbx_rd_conf_e_d_tov_SHIFT 0 +#define lpfc_mbx_rd_conf_e_d_tov_MASK 0x0000FFFF +#define lpfc_mbx_rd_conf_e_d_tov_WORD word4 + uint32_t word5; +#define lpfc_mbx_rd_conf_lp_tov_SHIFT 0 +#define lpfc_mbx_rd_conf_lp_tov_MASK 0x0000FFFF +#define lpfc_mbx_rd_conf_lp_tov_WORD word5 + uint32_t word6; +#define lpfc_mbx_rd_conf_r_a_tov_SHIFT 0 +#define lpfc_mbx_rd_conf_r_a_tov_MASK 0x0000FFFF +#define lpfc_mbx_rd_conf_r_a_tov_WORD word6 + uint32_t word7; +#define lpfc_mbx_rd_conf_r_t_tov_SHIFT 0 +#define lpfc_mbx_rd_conf_r_t_tov_MASK 0x000000FF +#define lpfc_mbx_rd_conf_r_t_tov_WORD word7 + uint32_t word8; +#define lpfc_mbx_rd_conf_al_tov_SHIFT 0 +#define lpfc_mbx_rd_conf_al_tov_MASK 0x0000000F +#define lpfc_mbx_rd_conf_al_tov_WORD word8 + uint32_t word9; +#define lpfc_mbx_rd_conf_lmt_SHIFT 0 +#define lpfc_mbx_rd_conf_lmt_MASK 0x0000FFFF +#define lpfc_mbx_rd_conf_lmt_WORD word9 + uint32_t word10; +#define lpfc_mbx_rd_conf_max_alpa_SHIFT 0 +#define lpfc_mbx_rd_conf_max_alpa_MASK 0x000000FF +#define lpfc_mbx_rd_conf_max_alpa_WORD word10 + uint32_t word11_rsvd; + uint32_t word12; +#define lpfc_mbx_rd_conf_xri_base_SHIFT 0 +#define lpfc_mbx_rd_conf_xri_base_MASK 0x0000FFFF +#define lpfc_mbx_rd_conf_xri_base_WORD word12 +#define lpfc_mbx_rd_conf_xri_count_SHIFT 16 +#define lpfc_mbx_rd_conf_xri_count_MASK 0x0000FFFF +#define lpfc_mbx_rd_conf_xri_count_WORD word12 + uint32_t word13; +#define lpfc_mbx_rd_conf_rpi_base_SHIFT 0 +#define lpfc_mbx_rd_conf_rpi_base_MASK 0x0000FFFF +#define lpfc_mbx_rd_conf_rpi_base_WORD word13 +#define lpfc_mbx_rd_conf_rpi_count_SHIFT 16 +#define lpfc_mbx_rd_conf_rpi_count_MASK 0x0000FFFF +#define lpfc_mbx_rd_conf_rpi_count_WORD word13 + uint32_t word14; +#define lpfc_mbx_rd_conf_vpi_base_SHIFT 0 +#define lpfc_mbx_rd_conf_vpi_base_MASK 0x0000FFFF +#define lpfc_mbx_rd_conf_vpi_base_WORD word14 +#define lpfc_mbx_rd_conf_vpi_count_SHIFT 16 +#define lpfc_mbx_rd_conf_vpi_count_MASK 0x0000FFFF +#define lpfc_mbx_rd_conf_vpi_count_WORD word14 + uint32_t word15; +#define lpfc_mbx_rd_conf_vfi_base_SHIFT 0 +#define lpfc_mbx_rd_conf_vfi_base_MASK 0x0000FFFF +#define lpfc_mbx_rd_conf_vfi_base_WORD word15 +#define lpfc_mbx_rd_conf_vfi_count_SHIFT 16 +#define lpfc_mbx_rd_conf_vfi_count_MASK 0x0000FFFF +#define lpfc_mbx_rd_conf_vfi_count_WORD word15 + uint32_t word16; +#define lpfc_mbx_rd_conf_fcfi_base_SHIFT 0 +#define lpfc_mbx_rd_conf_fcfi_base_MASK 0x0000FFFF +#define lpfc_mbx_rd_conf_fcfi_base_WORD word16 +#define lpfc_mbx_rd_conf_fcfi_count_SHIFT 16 +#define lpfc_mbx_rd_conf_fcfi_count_MASK 0x0000FFFF +#define lpfc_mbx_rd_conf_fcfi_count_WORD word16 + uint32_t word17; +#define lpfc_mbx_rd_conf_rq_count_SHIFT 0 +#define lpfc_mbx_rd_conf_rq_count_MASK 0x0000FFFF +#define lpfc_mbx_rd_conf_rq_count_WORD word17 +#define lpfc_mbx_rd_conf_eq_count_SHIFT 16 +#define lpfc_mbx_rd_conf_eq_count_MASK 0x0000FFFF +#define lpfc_mbx_rd_conf_eq_count_WORD word17 + uint32_t word18; +#define lpfc_mbx_rd_conf_wq_count_SHIFT 0 +#define lpfc_mbx_rd_conf_wq_count_MASK 0x0000FFFF +#define lpfc_mbx_rd_conf_wq_count_WORD word18 +#define lpfc_mbx_rd_conf_cq_count_SHIFT 16 +#define lpfc_mbx_rd_conf_cq_count_MASK 0x0000FFFF +#define lpfc_mbx_rd_conf_cq_count_WORD word18 +}; + +struct lpfc_mbx_request_features { + uint32_t word1; +#define lpfc_mbx_rq_ftr_qry_SHIFT 0 +#define lpfc_mbx_rq_ftr_qry_MASK 0x00000001 +#define lpfc_mbx_rq_ftr_qry_WORD word1 + uint32_t word2; +#define lpfc_mbx_rq_ftr_rq_iaab_SHIFT 0 +#define lpfc_mbx_rq_ftr_rq_iaab_MASK 0x00000001 +#define lpfc_mbx_rq_ftr_rq_iaab_WORD word2 +#define lpfc_mbx_rq_ftr_rq_npiv_SHIFT 1 +#define lpfc_mbx_rq_ftr_rq_npiv_MASK 0x00000001 +#define lpfc_mbx_rq_ftr_rq_npiv_WORD word2 +#define lpfc_mbx_rq_ftr_rq_dif_SHIFT 2 +#define lpfc_mbx_rq_ftr_rq_dif_MASK 0x00000001 +#define lpfc_mbx_rq_ftr_rq_dif_WORD word2 +#define lpfc_mbx_rq_ftr_rq_vf_SHIFT 3 +#define lpfc_mbx_rq_ftr_rq_vf_MASK 0x00000001 +#define lpfc_mbx_rq_ftr_rq_vf_WORD word2 +#define lpfc_mbx_rq_ftr_rq_fcpi_SHIFT 4 +#define lpfc_mbx_rq_ftr_rq_fcpi_MASK 0x00000001 +#define lpfc_mbx_rq_ftr_rq_fcpi_WORD word2 +#define lpfc_mbx_rq_ftr_rq_fcpt_SHIFT 5 +#define lpfc_mbx_rq_ftr_rq_fcpt_MASK 0x00000001 +#define lpfc_mbx_rq_ftr_rq_fcpt_WORD word2 +#define lpfc_mbx_rq_ftr_rq_fcpc_SHIFT 6 +#define lpfc_mbx_rq_ftr_rq_fcpc_MASK 0x00000001 +#define lpfc_mbx_rq_ftr_rq_fcpc_WORD word2 +#define lpfc_mbx_rq_ftr_rq_ifip_SHIFT 7 +#define lpfc_mbx_rq_ftr_rq_ifip_MASK 0x00000001 +#define lpfc_mbx_rq_ftr_rq_ifip_WORD word2 + uint32_t word3; +#define lpfc_mbx_rq_ftr_rsp_iaab_SHIFT 0 +#define lpfc_mbx_rq_ftr_rsp_iaab_MASK 0x00000001 +#define lpfc_mbx_rq_ftr_rsp_iaab_WORD word3 +#define lpfc_mbx_rq_ftr_rsp_npiv_SHIFT 1 +#define lpfc_mbx_rq_ftr_rsp_npiv_MASK 0x00000001 +#define lpfc_mbx_rq_ftr_rsp_npiv_WORD word3 +#define lpfc_mbx_rq_ftr_rsp_dif_SHIFT 2 +#define lpfc_mbx_rq_ftr_rsp_dif_MASK 0x00000001 +#define lpfc_mbx_rq_ftr_rsp_dif_WORD word3 +#define lpfc_mbx_rq_ftr_rsp_vf_SHIFT 3 +#define lpfc_mbx_rq_ftr_rsp_vf__MASK 0x00000001 +#define lpfc_mbx_rq_ftr_rsp_vf_WORD word3 +#define lpfc_mbx_rq_ftr_rsp_fcpi_SHIFT 4 +#define lpfc_mbx_rq_ftr_rsp_fcpi_MASK 0x00000001 +#define lpfc_mbx_rq_ftr_rsp_fcpi_WORD word3 +#define lpfc_mbx_rq_ftr_rsp_fcpt_SHIFT 5 +#define lpfc_mbx_rq_ftr_rsp_fcpt_MASK 0x00000001 +#define lpfc_mbx_rq_ftr_rsp_fcpt_WORD word3 +#define lpfc_mbx_rq_ftr_rsp_fcpc_SHIFT 6 +#define lpfc_mbx_rq_ftr_rsp_fcpc_MASK 0x00000001 +#define lpfc_mbx_rq_ftr_rsp_fcpc_WORD word3 +#define lpfc_mbx_rq_ftr_rsp_ifip_SHIFT 7 +#define lpfc_mbx_rq_ftr_rsp_ifip_MASK 0x00000001 +#define lpfc_mbx_rq_ftr_rsp_ifip_WORD word3 +}; + +/* Mailbox Completion Queue Error Messages */ +#define MB_CQE_STATUS_SUCCESS 0x0 +#define MB_CQE_STATUS_INSUFFICIENT_PRIVILEGES 0x1 +#define MB_CQE_STATUS_INVALID_PARAMETER 0x2 +#define MB_CQE_STATUS_INSUFFICIENT_RESOURCES 0x3 +#define MB_CEQ_STATUS_QUEUE_FLUSHING 0x4 +#define MB_CQE_STATUS_DMA_FAILED 0x5 + +/* mailbox queue entry structure */ +struct lpfc_mqe { + uint32_t word0; +#define lpfc_mqe_status_SHIFT 16 +#define lpfc_mqe_status_MASK 0x0000FFFF +#define lpfc_mqe_status_WORD word0 +#define lpfc_mqe_command_SHIFT 8 +#define lpfc_mqe_command_MASK 0x000000FF +#define lpfc_mqe_command_WORD word0 + union { + uint32_t mb_words[LPFC_SLI4_MB_WORD_COUNT - 1]; + /* sli4 mailbox commands */ + struct lpfc_mbx_sli4_config sli4_config; + struct lpfc_mbx_init_vfi init_vfi; + struct lpfc_mbx_reg_vfi reg_vfi; + struct lpfc_mbx_reg_vfi unreg_vfi; + struct lpfc_mbx_init_vpi init_vpi; + struct lpfc_mbx_resume_rpi resume_rpi; + struct lpfc_mbx_read_fcf_tbl read_fcf_tbl; + struct lpfc_mbx_add_fcf_tbl_entry add_fcf_entry; + struct lpfc_mbx_del_fcf_tbl_entry del_fcf_entry; + struct lpfc_mbx_reg_fcfi reg_fcfi; + struct lpfc_mbx_unreg_fcfi unreg_fcfi; + struct lpfc_mbx_mq_create mq_create; + struct lpfc_mbx_eq_create eq_create; + struct lpfc_mbx_cq_create cq_create; + struct lpfc_mbx_wq_create wq_create; + struct lpfc_mbx_rq_create rq_create; + struct lpfc_mbx_mq_destroy mq_destroy; + struct lpfc_mbx_eq_destroy eq_destroy; + struct lpfc_mbx_cq_destroy cq_destroy; + struct lpfc_mbx_wq_destroy wq_destroy; + struct lpfc_mbx_rq_destroy rq_destroy; + struct lpfc_mbx_post_sgl_pages post_sgl_pages; + struct lpfc_mbx_nembed_cmd nembed_cmd; + struct lpfc_mbx_read_rev read_rev; + struct lpfc_mbx_read_vpi read_vpi; + struct lpfc_mbx_read_config rd_config; + struct lpfc_mbx_request_features req_ftrs; + struct lpfc_mbx_post_hdr_tmpl hdr_tmpl; + struct lpfc_mbx_nop nop; + } un; +}; + +struct lpfc_mcqe { + uint32_t word0; +#define lpfc_mcqe_status_SHIFT 0 +#define lpfc_mcqe_status_MASK 0x0000FFFF +#define lpfc_mcqe_status_WORD word0 +#define lpfc_mcqe_ext_status_SHIFT 16 +#define lpfc_mcqe_ext_status_MASK 0x0000FFFF +#define lpfc_mcqe_ext_status_WORD word0 + uint32_t mcqe_tag0; + uint32_t mcqe_tag1; + uint32_t trailer; +#define lpfc_trailer_valid_SHIFT 31 +#define lpfc_trailer_valid_MASK 0x00000001 +#define lpfc_trailer_valid_WORD trailer +#define lpfc_trailer_async_SHIFT 30 +#define lpfc_trailer_async_MASK 0x00000001 +#define lpfc_trailer_async_WORD trailer +#define lpfc_trailer_hpi_SHIFT 29 +#define lpfc_trailer_hpi_MASK 0x00000001 +#define lpfc_trailer_hpi_WORD trailer +#define lpfc_trailer_completed_SHIFT 28 +#define lpfc_trailer_completed_MASK 0x00000001 +#define lpfc_trailer_completed_WORD trailer +#define lpfc_trailer_consumed_SHIFT 27 +#define lpfc_trailer_consumed_MASK 0x00000001 +#define lpfc_trailer_consumed_WORD trailer +#define lpfc_trailer_type_SHIFT 16 +#define lpfc_trailer_type_MASK 0x000000FF +#define lpfc_trailer_type_WORD trailer +#define lpfc_trailer_code_SHIFT 8 +#define lpfc_trailer_code_MASK 0x000000FF +#define lpfc_trailer_code_WORD trailer +#define LPFC_TRAILER_CODE_LINK 0x1 +#define LPFC_TRAILER_CODE_FCOE 0x2 +#define LPFC_TRAILER_CODE_DCBX 0x3 +}; + +struct lpfc_acqe_link { + uint32_t word0; +#define lpfc_acqe_link_speed_SHIFT 24 +#define lpfc_acqe_link_speed_MASK 0x000000FF +#define lpfc_acqe_link_speed_WORD word0 +#define LPFC_ASYNC_LINK_SPEED_ZERO 0x0 +#define LPFC_ASYNC_LINK_SPEED_10MBPS 0x1 +#define LPFC_ASYNC_LINK_SPEED_100MBPS 0x2 +#define LPFC_ASYNC_LINK_SPEED_1GBPS 0x3 +#define LPFC_ASYNC_LINK_SPEED_10GBPS 0x4 +#define lpfc_acqe_link_duplex_SHIFT 16 +#define lpfc_acqe_link_duplex_MASK 0x000000FF +#define lpfc_acqe_link_duplex_WORD word0 +#define LPFC_ASYNC_LINK_DUPLEX_NONE 0x0 +#define LPFC_ASYNC_LINK_DUPLEX_HALF 0x1 +#define LPFC_ASYNC_LINK_DUPLEX_FULL 0x2 +#define lpfc_acqe_link_status_SHIFT 8 +#define lpfc_acqe_link_status_MASK 0x000000FF +#define lpfc_acqe_link_status_WORD word0 +#define LPFC_ASYNC_LINK_STATUS_DOWN 0x0 +#define LPFC_ASYNC_LINK_STATUS_UP 0x1 +#define LPFC_ASYNC_LINK_STATUS_LOGICAL_DOWN 0x2 +#define LPFC_ASYNC_LINK_STATUS_LOGICAL_UP 0x3 +#define lpfc_acqe_link_physical_SHIFT 0 +#define lpfc_acqe_link_physical_MASK 0x000000FF +#define lpfc_acqe_link_physical_WORD word0 +#define LPFC_ASYNC_LINK_PORT_A 0x0 +#define LPFC_ASYNC_LINK_PORT_B 0x1 + uint32_t word1; +#define lpfc_acqe_link_fault_SHIFT 0 +#define lpfc_acqe_link_fault_MASK 0x000000FF +#define lpfc_acqe_link_fault_WORD word1 +#define LPFC_ASYNC_LINK_FAULT_NONE 0x0 +#define LPFC_ASYNC_LINK_FAULT_LOCAL 0x1 +#define LPFC_ASYNC_LINK_FAULT_REMOTE 0x2 + uint32_t event_tag; + uint32_t trailer; +}; + +struct lpfc_acqe_fcoe { + uint32_t fcf_index; + uint32_t word1; +#define lpfc_acqe_fcoe_fcf_count_SHIFT 0 +#define lpfc_acqe_fcoe_fcf_count_MASK 0x0000FFFF +#define lpfc_acqe_fcoe_fcf_count_WORD word1 +#define lpfc_acqe_fcoe_event_type_SHIFT 16 +#define lpfc_acqe_fcoe_event_type_MASK 0x0000FFFF +#define lpfc_acqe_fcoe_event_type_WORD word1 +#define LPFC_FCOE_EVENT_TYPE_NEW_FCF 0x1 +#define LPFC_FCOE_EVENT_TYPE_FCF_TABLE_FULL 0x2 +#define LPFC_FCOE_EVENT_TYPE_FCF_DEAD 0x3 + uint32_t event_tag; + uint32_t trailer; +}; + +struct lpfc_acqe_dcbx { + uint32_t tlv_ttl; + uint32_t reserved; + uint32_t event_tag; + uint32_t trailer; +}; + +/* + * Define the bootstrap mailbox (bmbx) region used to communicate + * mailbox command between the host and port. The mailbox consists + * of a payload area of 256 bytes and a completion queue of length + * 16 bytes. + */ +struct lpfc_bmbx_create { + struct lpfc_mqe mqe; + struct lpfc_mcqe mcqe; +}; + +#define SGL_ALIGN_SZ 64 +#define SGL_PAGE_SIZE 4096 +/* align SGL addr on a size boundary - adjust address up */ +#define NO_XRI ((uint16_t)-1) +struct wqe_common { + uint32_t word6; +#define wqe_xri_SHIFT 0 +#define wqe_xri_MASK 0x0000FFFF +#define wqe_xri_WORD word6 +#define wqe_ctxt_tag_SHIFT 16 +#define wqe_ctxt_tag_MASK 0x0000FFFF +#define wqe_ctxt_tag_WORD word6 + uint32_t word7; +#define wqe_ct_SHIFT 2 +#define wqe_ct_MASK 0x00000003 +#define wqe_ct_WORD word7 +#define wqe_status_SHIFT 4 +#define wqe_status_MASK 0x0000000f +#define wqe_status_WORD word7 +#define wqe_cmnd_SHIFT 8 +#define wqe_cmnd_MASK 0x000000ff +#define wqe_cmnd_WORD word7 +#define wqe_class_SHIFT 16 +#define wqe_class_MASK 0x00000007 +#define wqe_class_WORD word7 +#define wqe_pu_SHIFT 20 +#define wqe_pu_MASK 0x00000003 +#define wqe_pu_WORD word7 +#define wqe_erp_SHIFT 22 +#define wqe_erp_MASK 0x00000001 +#define wqe_erp_WORD word7 +#define wqe_lnk_SHIFT 23 +#define wqe_lnk_MASK 0x00000001 +#define wqe_lnk_WORD word7 +#define wqe_tmo_SHIFT 24 +#define wqe_tmo_MASK 0x000000ff +#define wqe_tmo_WORD word7 + uint32_t abort_tag; /* word 8 in WQE */ + uint32_t word9; +#define wqe_reqtag_SHIFT 0 +#define wqe_reqtag_MASK 0x0000FFFF +#define wqe_reqtag_WORD word9 +#define wqe_rcvoxid_SHIFT 16 +#define wqe_rcvoxid_MASK 0x0000FFFF +#define wqe_rcvoxid_WORD word9 + uint32_t word10; +#define wqe_pri_SHIFT 16 +#define wqe_pri_MASK 0x00000007 +#define wqe_pri_WORD word10 +#define wqe_pv_SHIFT 19 +#define wqe_pv_MASK 0x00000001 +#define wqe_pv_WORD word10 +#define wqe_xc_SHIFT 21 +#define wqe_xc_MASK 0x00000001 +#define wqe_xc_WORD word10 +#define wqe_ccpe_SHIFT 23 +#define wqe_ccpe_MASK 0x00000001 +#define wqe_ccpe_WORD word10 +#define wqe_ccp_SHIFT 24 +#define wqe_ccp_MASK 0x000000ff +#define wqe_ccp_WORD word10 + uint32_t word11; +#define wqe_cmd_type_SHIFT 0 +#define wqe_cmd_type_MASK 0x0000000f +#define wqe_cmd_type_WORD word11 +#define wqe_wqec_SHIFT 7 +#define wqe_wqec_MASK 0x00000001 +#define wqe_wqec_WORD word11 +#define wqe_cqid_SHIFT 16 +#define wqe_cqid_MASK 0x000003ff +#define wqe_cqid_WORD word11 +}; + +struct wqe_did { + uint32_t word5; +#define wqe_els_did_SHIFT 0 +#define wqe_els_did_MASK 0x00FFFFFF +#define wqe_els_did_WORD word5 +#define wqe_xmit_bls_ar_SHIFT 30 +#define wqe_xmit_bls_ar_MASK 0x00000001 +#define wqe_xmit_bls_ar_WORD word5 +#define wqe_xmit_bls_xo_SHIFT 31 +#define wqe_xmit_bls_xo_MASK 0x00000001 +#define wqe_xmit_bls_xo_WORD word5 +}; + +struct els_request64_wqe { + struct ulp_bde64 bde; + uint32_t payload_len; + uint32_t word4; +#define els_req64_sid_SHIFT 0 +#define els_req64_sid_MASK 0x00FFFFFF +#define els_req64_sid_WORD word4 +#define els_req64_sp_SHIFT 24 +#define els_req64_sp_MASK 0x00000001 +#define els_req64_sp_WORD word4 +#define els_req64_vf_SHIFT 25 +#define els_req64_vf_MASK 0x00000001 +#define els_req64_vf_WORD word4 + struct wqe_did wqe_dest; + struct wqe_common wqe_com; /* words 6-11 */ + uint32_t word12; +#define els_req64_vfid_SHIFT 1 +#define els_req64_vfid_MASK 0x00000FFF +#define els_req64_vfid_WORD word12 +#define els_req64_pri_SHIFT 13 +#define els_req64_pri_MASK 0x00000007 +#define els_req64_pri_WORD word12 + uint32_t word13; +#define els_req64_hopcnt_SHIFT 24 +#define els_req64_hopcnt_MASK 0x000000ff +#define els_req64_hopcnt_WORD word13 + uint32_t reserved[2]; +}; + +struct xmit_els_rsp64_wqe { + struct ulp_bde64 bde; + uint32_t rsvd3; + uint32_t rsvd4; + struct wqe_did wqe_dest; + struct wqe_common wqe_com; /* words 6-11 */ + uint32_t rsvd_12_15[4]; +}; + +struct xmit_bls_rsp64_wqe { + uint32_t payload0; + uint32_t word1; +#define xmit_bls_rsp64_rxid_SHIFT 0 +#define xmit_bls_rsp64_rxid_MASK 0x0000ffff +#define xmit_bls_rsp64_rxid_WORD word1 +#define xmit_bls_rsp64_oxid_SHIFT 16 +#define xmit_bls_rsp64_oxid_MASK 0x0000ffff +#define xmit_bls_rsp64_oxid_WORD word1 + uint32_t word2; +#define xmit_bls_rsp64_seqcntlo_SHIFT 0 +#define xmit_bls_rsp64_seqcntlo_MASK 0x0000ffff +#define xmit_bls_rsp64_seqcntlo_WORD word2 +#define xmit_bls_rsp64_seqcnthi_SHIFT 16 +#define xmit_bls_rsp64_seqcnthi_MASK 0x0000ffff +#define xmit_bls_rsp64_seqcnthi_WORD word2 + uint32_t rsrvd3; + uint32_t rsrvd4; + struct wqe_did wqe_dest; + struct wqe_common wqe_com; /* words 6-11 */ + uint32_t rsvd_12_15[4]; +}; +struct wqe_rctl_dfctl { + uint32_t word5; +#define wqe_si_SHIFT 2 +#define wqe_si_MASK 0x000000001 +#define wqe_si_WORD word5 +#define wqe_la_SHIFT 3 +#define wqe_la_MASK 0x000000001 +#define wqe_la_WORD word5 +#define wqe_ls_SHIFT 7 +#define wqe_ls_MASK 0x000000001 +#define wqe_ls_WORD word5 +#define wqe_dfctl_SHIFT 8 +#define wqe_dfctl_MASK 0x0000000ff +#define wqe_dfctl_WORD word5 +#define wqe_type_SHIFT 16 +#define wqe_type_MASK 0x0000000ff +#define wqe_type_WORD word5 +#define wqe_rctl_SHIFT 24 +#define wqe_rctl_MASK 0x0000000ff +#define wqe_rctl_WORD word5 +}; + +struct xmit_seq64_wqe { + struct ulp_bde64 bde; + uint32_t paylaod_offset; + uint32_t relative_offset; + struct wqe_rctl_dfctl wge_ctl; + struct wqe_common wqe_com; /* words 6-11 */ + /* Note: word10 different REVISIT */ + uint32_t xmit_len; + uint32_t rsvd_12_15[3]; +}; +struct xmit_bcast64_wqe { + struct ulp_bde64 bde; + uint32_t paylaod_len; + uint32_t rsvd4; + struct wqe_rctl_dfctl wge_ctl; /* word 5 */ + struct wqe_common wqe_com; /* words 6-11 */ + uint32_t rsvd_12_15[4]; +}; + +struct gen_req64_wqe { + struct ulp_bde64 bde; + uint32_t command_len; + uint32_t payload_len; + struct wqe_rctl_dfctl wge_ctl; /* word 5 */ + struct wqe_common wqe_com; /* words 6-11 */ + uint32_t rsvd_12_15[4]; +}; + +struct create_xri_wqe { + uint32_t rsrvd[5]; /* words 0-4 */ + struct wqe_did wqe_dest; /* word 5 */ + struct wqe_common wqe_com; /* words 6-11 */ + uint32_t rsvd_12_15[4]; /* word 12-15 */ +}; + +#define T_REQUEST_TAG 3 +#define T_XRI_TAG 1 + +struct abort_cmd_wqe { + uint32_t rsrvd[3]; + uint32_t word3; +#define abort_cmd_ia_SHIFT 0 +#define abort_cmd_ia_MASK 0x000000001 +#define abort_cmd_ia_WORD word3 +#define abort_cmd_criteria_SHIFT 8 +#define abort_cmd_criteria_MASK 0x0000000ff +#define abort_cmd_criteria_WORD word3 + uint32_t rsrvd4; + uint32_t rsrvd5; + struct wqe_common wqe_com; /* words 6-11 */ + uint32_t rsvd_12_15[4]; /* word 12-15 */ +}; + +struct fcp_iwrite64_wqe { + struct ulp_bde64 bde; + uint32_t payload_len; + uint32_t total_xfer_len; + uint32_t initial_xfer_len; + struct wqe_common wqe_com; /* words 6-11 */ + uint32_t rsvd_12_15[4]; /* word 12-15 */ +}; + +struct fcp_iread64_wqe { + struct ulp_bde64 bde; + uint32_t payload_len; /* word 3 */ + uint32_t total_xfer_len; /* word 4 */ + uint32_t rsrvd5; /* word 5 */ + struct wqe_common wqe_com; /* words 6-11 */ + uint32_t rsvd_12_15[4]; /* word 12-15 */ +}; + +struct fcp_icmnd64_wqe { + struct ulp_bde64 bde; /* words 0-2 */ + uint32_t rsrvd[3]; /* words 3-5 */ + struct wqe_common wqe_com; /* words 6-11 */ + uint32_t rsvd_12_15[4]; /* word 12-15 */ +}; + + +union lpfc_wqe { + uint32_t words[16]; + struct lpfc_wqe_generic generic; + struct fcp_icmnd64_wqe fcp_icmd; + struct fcp_iread64_wqe fcp_iread; + struct fcp_iwrite64_wqe fcp_iwrite; + struct abort_cmd_wqe abort_cmd; + struct create_xri_wqe create_xri; + struct xmit_bcast64_wqe xmit_bcast64; + struct xmit_seq64_wqe xmit_sequence; + struct xmit_bls_rsp64_wqe xmit_bls_rsp; + struct xmit_els_rsp64_wqe xmit_els_rsp; + struct els_request64_wqe els_req; + struct gen_req64_wqe gen_req; +}; + +#define FCP_COMMAND 0x0 +#define FCP_COMMAND_DATA_OUT 0x1 +#define ELS_COMMAND_NON_FIP 0xC +#define ELS_COMMAND_FIP 0xD +#define OTHER_COMMAND 0x8 + diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 86d1bdcbf2d8..fc67cc65c63b 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2008 Emulex. All rights reserved. * + * Copyright (C) 2004-2009 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -34,8 +34,10 @@ #include #include +#include "lpfc_hw4.h" #include "lpfc_hw.h" #include "lpfc_sli.h" +#include "lpfc_sli4.h" #include "lpfc_nl.h" #include "lpfc_disc.h" #include "lpfc_scsi.h" @@ -51,9 +53,23 @@ char *_dump_buf_dif; unsigned long _dump_buf_dif_order; spinlock_t _dump_buf_lock; -static int lpfc_parse_vpd(struct lpfc_hba *, uint8_t *, int); static void lpfc_get_hba_model_desc(struct lpfc_hba *, uint8_t *, uint8_t *); static int lpfc_post_rcv_buf(struct lpfc_hba *); +static int lpfc_sli4_queue_create(struct lpfc_hba *); +static void lpfc_sli4_queue_destroy(struct lpfc_hba *); +static int lpfc_create_bootstrap_mbox(struct lpfc_hba *); +static int lpfc_setup_endian_order(struct lpfc_hba *); +static int lpfc_sli4_read_config(struct lpfc_hba *); +static void lpfc_destroy_bootstrap_mbox(struct lpfc_hba *); +static void lpfc_free_sgl_list(struct lpfc_hba *); +static int lpfc_init_sgl_list(struct lpfc_hba *); +static int lpfc_init_active_sgl_array(struct lpfc_hba *); +static void lpfc_free_active_sgl(struct lpfc_hba *); +static int lpfc_hba_down_post_s3(struct lpfc_hba *phba); +static int lpfc_hba_down_post_s4(struct lpfc_hba *phba); +static int lpfc_sli4_cq_event_pool_create(struct lpfc_hba *); +static void lpfc_sli4_cq_event_pool_destroy(struct lpfc_hba *); +static void lpfc_sli4_cq_event_release_all(struct lpfc_hba *); static struct scsi_transport_template *lpfc_transport_template = NULL; static struct scsi_transport_template *lpfc_vport_transport_template = NULL; @@ -92,7 +108,7 @@ lpfc_config_port_prep(struct lpfc_hba *phba) return -ENOMEM; } - mb = &pmb->mb; + mb = &pmb->u.mb; phba->link_state = LPFC_INIT_MBX_CMDS; if (lpfc_is_LC_HBA(phba->pcidev->device)) { @@ -205,6 +221,11 @@ lpfc_config_port_prep(struct lpfc_hba *phba) mb->mbxCommand, mb->mbxStatus); mb->un.varDmp.word_cnt = 0; } + /* dump mem may return a zero when finished or we got a + * mailbox error, either way we are done. + */ + if (mb->un.varDmp.word_cnt == 0) + break; if (mb->un.varDmp.word_cnt > DMP_VPD_SIZE - offset) mb->un.varDmp.word_cnt = DMP_VPD_SIZE - offset; lpfc_sli_pcimem_bcopy(((uint8_t *)mb) + DMP_RSP_OFFSET, @@ -233,7 +254,7 @@ out_free_mbox: static void lpfc_config_async_cmpl(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq) { - if (pmboxq->mb.mbxStatus == MBX_SUCCESS) + if (pmboxq->u.mb.mbxStatus == MBX_SUCCESS) phba->temp_sensor_support = 1; else phba->temp_sensor_support = 0; @@ -260,7 +281,7 @@ lpfc_dump_wakeup_param_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) /* character array used for decoding dist type. */ char dist_char[] = "nabx"; - if (pmboxq->mb.mbxStatus != MBX_SUCCESS) { + if (pmboxq->u.mb.mbxStatus != MBX_SUCCESS) { mempool_free(pmboxq, phba->mbox_mem_pool); return; } @@ -268,7 +289,7 @@ lpfc_dump_wakeup_param_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) prg = (struct prog_id *) &prog_id_word; /* word 7 contain option rom version */ - prog_id_word = pmboxq->mb.un.varWords[7]; + prog_id_word = pmboxq->u.mb.un.varWords[7]; /* Decode the Option rom version word to a readable string */ if (prg->dist < 4) @@ -325,7 +346,7 @@ lpfc_config_port_post(struct lpfc_hba *phba) phba->link_state = LPFC_HBA_ERROR; return -ENOMEM; } - mb = &pmb->mb; + mb = &pmb->u.mb; /* Get login parameters for NID. */ lpfc_read_sparam(phba, pmb, 0); @@ -364,6 +385,7 @@ lpfc_config_port_post(struct lpfc_hba *phba) /* Update the fc_host data structures with new wwn. */ fc_host_node_name(shost) = wwn_to_u64(vport->fc_nodename.u.wwn); fc_host_port_name(shost) = wwn_to_u64(vport->fc_portname.u.wwn); + fc_host_max_npiv_vports(shost) = phba->max_vpi; /* If no serial number in VPD data, use low 6 bytes of WWNN */ /* This should be consolidated into parse_vpd ? - mr */ @@ -406,7 +428,8 @@ lpfc_config_port_post(struct lpfc_hba *phba) /* Reset the DFT_HBA_Q_DEPTH to the max xri */ if (phba->cfg_hba_queue_depth > (mb->un.varRdConfig.max_xri+1)) phba->cfg_hba_queue_depth = - mb->un.varRdConfig.max_xri + 1; + (mb->un.varRdConfig.max_xri + 1) - + lpfc_sli4_get_els_iocb_cnt(phba); phba->lmt = mb->un.varRdConfig.lmt; @@ -460,17 +483,18 @@ lpfc_config_port_post(struct lpfc_hba *phba) lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, "0352 Config MSI mailbox command " "failed, mbxCmd x%x, mbxStatus x%x\n", - pmb->mb.mbxCommand, pmb->mb.mbxStatus); + pmb->u.mb.mbxCommand, + pmb->u.mb.mbxStatus); mempool_free(pmb, phba->mbox_mem_pool); return -EIO; } } + spin_lock_irq(&phba->hbalock); /* Initialize ERATT handling flag */ phba->hba_flag &= ~HBA_ERATT_HANDLED; /* Enable appropriate host interrupts */ - spin_lock_irq(&phba->hbalock); status = readl(phba->HCregaddr); status |= HC_MBINT_ENA | HC_ERINT_ENA | HC_LAINT_ENA; if (psli->num_rings > 0) @@ -571,16 +595,20 @@ lpfc_hba_down_prep(struct lpfc_hba *phba) { struct lpfc_vport **vports; int i; - /* Disable interrupts */ - writel(0, phba->HCregaddr); - readl(phba->HCregaddr); /* flush */ + + if (phba->sli_rev <= LPFC_SLI_REV3) { + /* Disable interrupts */ + writel(0, phba->HCregaddr); + readl(phba->HCregaddr); /* flush */ + } if (phba->pport->load_flag & FC_UNLOADING) lpfc_cleanup_discovery_resources(phba->pport); else { vports = lpfc_create_vport_work_array(phba); if (vports != NULL) - for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) + for (i = 0; i <= phba->max_vports && + vports[i] != NULL; i++) lpfc_cleanup_discovery_resources(vports[i]); lpfc_destroy_vport_work_array(phba, vports); } @@ -588,7 +616,7 @@ lpfc_hba_down_prep(struct lpfc_hba *phba) } /** - * lpfc_hba_down_post - Perform lpfc uninitialization after HBA reset + * lpfc_hba_down_post_s3 - Perform lpfc uninitialization after HBA reset * @phba: pointer to lpfc HBA data structure. * * This routine will do uninitialization after the HBA is reset when bring @@ -598,8 +626,8 @@ lpfc_hba_down_prep(struct lpfc_hba *phba) * 0 - sucess. * Any other value - error. **/ -int -lpfc_hba_down_post(struct lpfc_hba *phba) +static int +lpfc_hba_down_post_s3(struct lpfc_hba *phba) { struct lpfc_sli *psli = &phba->sli; struct lpfc_sli_ring *pring; @@ -642,6 +670,77 @@ lpfc_hba_down_post(struct lpfc_hba *phba) return 0; } +/** + * lpfc_hba_down_post_s4 - Perform lpfc uninitialization after HBA reset + * @phba: pointer to lpfc HBA data structure. + * + * This routine will do uninitialization after the HBA is reset when bring + * down the SLI Layer. + * + * Return codes + * 0 - sucess. + * Any other value - error. + **/ +static int +lpfc_hba_down_post_s4(struct lpfc_hba *phba) +{ + struct lpfc_scsi_buf *psb, *psb_next; + LIST_HEAD(aborts); + int ret; + unsigned long iflag = 0; + ret = lpfc_hba_down_post_s3(phba); + if (ret) + return ret; + /* At this point in time the HBA is either reset or DOA. Either + * way, nothing should be on lpfc_abts_els_sgl_list, it needs to be + * on the lpfc_sgl_list so that it can either be freed if the + * driver is unloading or reposted if the driver is restarting + * the port. + */ + spin_lock_irq(&phba->hbalock); /* required for lpfc_sgl_list and */ + /* scsl_buf_list */ + /* abts_sgl_list_lock required because worker thread uses this + * list. + */ + spin_lock(&phba->sli4_hba.abts_sgl_list_lock); + list_splice_init(&phba->sli4_hba.lpfc_abts_els_sgl_list, + &phba->sli4_hba.lpfc_sgl_list); + spin_unlock(&phba->sli4_hba.abts_sgl_list_lock); + /* abts_scsi_buf_list_lock required because worker thread uses this + * list. + */ + spin_lock(&phba->sli4_hba.abts_scsi_buf_list_lock); + list_splice_init(&phba->sli4_hba.lpfc_abts_scsi_buf_list, + &aborts); + spin_unlock(&phba->sli4_hba.abts_scsi_buf_list_lock); + spin_unlock_irq(&phba->hbalock); + + list_for_each_entry_safe(psb, psb_next, &aborts, list) { + psb->pCmd = NULL; + psb->status = IOSTAT_SUCCESS; + } + spin_lock_irqsave(&phba->scsi_buf_list_lock, iflag); + list_splice(&aborts, &phba->lpfc_scsi_buf_list); + spin_unlock_irqrestore(&phba->scsi_buf_list_lock, iflag); + return 0; +} + +/** + * lpfc_hba_down_post - Wrapper func for hba down post routine + * @phba: pointer to lpfc HBA data structure. + * + * This routine wraps the actual SLI3 or SLI4 routine for performing + * uninitialization after the HBA is reset when bring down the SLI Layer. + * + * Return codes + * 0 - sucess. + * Any other value - error. + **/ +int +lpfc_hba_down_post(struct lpfc_hba *phba) +{ + return (*phba->lpfc_hba_down_post)(phba); +} /** * lpfc_hb_timeout - The HBA-timer timeout handler @@ -809,7 +908,7 @@ lpfc_hb_timeout_handler(struct lpfc_hba *phba) "taking this port offline.\n"); spin_lock_irq(&phba->hbalock); - psli->sli_flag &= ~LPFC_SLI2_ACTIVE; + psli->sli_flag &= ~LPFC_SLI_ACTIVE; spin_unlock_irq(&phba->hbalock); lpfc_offline_prep(phba); @@ -834,13 +933,15 @@ lpfc_offline_eratt(struct lpfc_hba *phba) struct lpfc_sli *psli = &phba->sli; spin_lock_irq(&phba->hbalock); - psli->sli_flag &= ~LPFC_SLI2_ACTIVE; + psli->sli_flag &= ~LPFC_SLI_ACTIVE; spin_unlock_irq(&phba->hbalock); lpfc_offline_prep(phba); lpfc_offline(phba); lpfc_reset_barrier(phba); + spin_lock_irq(&phba->hbalock); lpfc_sli_brdreset(phba); + spin_unlock_irq(&phba->hbalock); lpfc_hba_down_post(phba); lpfc_sli_brdready(phba, HS_MBRDY); lpfc_unblock_mgmt_io(phba); @@ -848,6 +949,25 @@ lpfc_offline_eratt(struct lpfc_hba *phba) return; } +/** + * lpfc_sli4_offline_eratt - Bring lpfc offline on SLI4 hardware error attention + * @phba: pointer to lpfc hba data structure. + * + * This routine is called to bring a SLI4 HBA offline when HBA hardware error + * other than Port Error 6 has been detected. + **/ +static void +lpfc_sli4_offline_eratt(struct lpfc_hba *phba) +{ + lpfc_offline_prep(phba); + lpfc_offline(phba); + lpfc_sli4_brdreset(phba); + lpfc_hba_down_post(phba); + lpfc_sli4_post_status_check(phba); + lpfc_unblock_mgmt_io(phba); + phba->link_state = LPFC_HBA_ERROR; +} + /** * lpfc_handle_deferred_eratt - The HBA hardware deferred error handler * @phba: pointer to lpfc hba data structure. @@ -864,6 +984,16 @@ lpfc_handle_deferred_eratt(struct lpfc_hba *phba) struct lpfc_sli_ring *pring; struct lpfc_sli *psli = &phba->sli; + /* If the pci channel is offline, ignore possible errors, + * since we cannot communicate with the pci card anyway. + */ + if (pci_channel_offline(phba->pcidev)) { + spin_lock_irq(&phba->hbalock); + phba->hba_flag &= ~DEFER_ERATT; + spin_unlock_irq(&phba->hbalock); + return; + } + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0479 Deferred Adapter Hardware Error " "Data: x%x x%x x%x\n", @@ -871,7 +1001,7 @@ lpfc_handle_deferred_eratt(struct lpfc_hba *phba) phba->work_status[0], phba->work_status[1]); spin_lock_irq(&phba->hbalock); - psli->sli_flag &= ~LPFC_SLI2_ACTIVE; + psli->sli_flag &= ~LPFC_SLI_ACTIVE; spin_unlock_irq(&phba->hbalock); @@ -909,13 +1039,30 @@ lpfc_handle_deferred_eratt(struct lpfc_hba *phba) if ((!phba->work_hs) && (!(phba->pport->load_flag & FC_UNLOADING))) phba->work_hs = old_host_status & ~HS_FFER1; + spin_lock_irq(&phba->hbalock); phba->hba_flag &= ~DEFER_ERATT; + spin_unlock_irq(&phba->hbalock); phba->work_status[0] = readl(phba->MBslimaddr + 0xa8); phba->work_status[1] = readl(phba->MBslimaddr + 0xac); } +static void +lpfc_board_errevt_to_mgmt(struct lpfc_hba *phba) +{ + struct lpfc_board_event_header board_event; + struct Scsi_Host *shost; + + board_event.event_type = FC_REG_BOARD_EVENT; + board_event.subcategory = LPFC_EVENT_PORTINTERR; + shost = lpfc_shost_from_vport(phba->pport); + fc_host_post_vendor_event(shost, fc_get_event_number(), + sizeof(board_event), + (char *) &board_event, + LPFC_NL_VENDOR_ID); +} + /** - * lpfc_handle_eratt - The HBA hardware error handler + * lpfc_handle_eratt_s3 - The SLI3 HBA hardware error handler * @phba: pointer to lpfc hba data structure. * * This routine is invoked to handle the following HBA hardware error @@ -924,8 +1071,8 @@ lpfc_handle_deferred_eratt(struct lpfc_hba *phba) * 2 - DMA ring index out of range * 3 - Mailbox command came back as unknown **/ -void -lpfc_handle_eratt(struct lpfc_hba *phba) +static void +lpfc_handle_eratt_s3(struct lpfc_hba *phba) { struct lpfc_vport *vport = phba->pport; struct lpfc_sli *psli = &phba->sli; @@ -934,24 +1081,23 @@ lpfc_handle_eratt(struct lpfc_hba *phba) unsigned long temperature; struct temp_event temp_event_data; struct Scsi_Host *shost; - struct lpfc_board_event_header board_event; /* If the pci channel is offline, ignore possible errors, - * since we cannot communicate with the pci card anyway. */ - if (pci_channel_offline(phba->pcidev)) + * since we cannot communicate with the pci card anyway. + */ + if (pci_channel_offline(phba->pcidev)) { + spin_lock_irq(&phba->hbalock); + phba->hba_flag &= ~DEFER_ERATT; + spin_unlock_irq(&phba->hbalock); return; + } + /* If resets are disabled then leave the HBA alone and return */ if (!phba->cfg_enable_hba_reset) return; /* Send an internal error event to mgmt application */ - board_event.event_type = FC_REG_BOARD_EVENT; - board_event.subcategory = LPFC_EVENT_PORTINTERR; - shost = lpfc_shost_from_vport(phba->pport); - fc_host_post_vendor_event(shost, fc_get_event_number(), - sizeof(board_event), - (char *) &board_event, - LPFC_NL_VENDOR_ID); + lpfc_board_errevt_to_mgmt(phba); if (phba->hba_flag & DEFER_ERATT) lpfc_handle_deferred_eratt(phba); @@ -965,7 +1111,7 @@ lpfc_handle_eratt(struct lpfc_hba *phba) phba->work_status[0], phba->work_status[1]); spin_lock_irq(&phba->hbalock); - psli->sli_flag &= ~LPFC_SLI2_ACTIVE; + psli->sli_flag &= ~LPFC_SLI_ACTIVE; spin_unlock_irq(&phba->hbalock); /* @@ -1036,6 +1182,65 @@ lpfc_handle_eratt(struct lpfc_hba *phba) return; } +/** + * lpfc_handle_eratt_s4 - The SLI4 HBA hardware error handler + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to handle the SLI4 HBA hardware error attention + * conditions. + **/ +static void +lpfc_handle_eratt_s4(struct lpfc_hba *phba) +{ + struct lpfc_vport *vport = phba->pport; + uint32_t event_data; + struct Scsi_Host *shost; + + /* If the pci channel is offline, ignore possible errors, since + * we cannot communicate with the pci card anyway. + */ + if (pci_channel_offline(phba->pcidev)) + return; + /* If resets are disabled then leave the HBA alone and return */ + if (!phba->cfg_enable_hba_reset) + return; + + /* Send an internal error event to mgmt application */ + lpfc_board_errevt_to_mgmt(phba); + + /* For now, the actual action for SLI4 device handling is not + * specified yet, just treated it as adaptor hardware failure + */ + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0143 SLI4 Adapter Hardware Error Data: x%x x%x\n", + phba->work_status[0], phba->work_status[1]); + + event_data = FC_REG_DUMP_EVENT; + shost = lpfc_shost_from_vport(vport); + fc_host_post_vendor_event(shost, fc_get_event_number(), + sizeof(event_data), (char *) &event_data, + SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX); + + lpfc_sli4_offline_eratt(phba); +} + +/** + * lpfc_handle_eratt - Wrapper func for handling hba error attention + * @phba: pointer to lpfc HBA data structure. + * + * This routine wraps the actual SLI3 or SLI4 hba error attention handling + * routine from the API jump table function pointer from the lpfc_hba struct. + * + * Return codes + * 0 - sucess. + * Any other value - error. + **/ +void +lpfc_handle_eratt(struct lpfc_hba *phba) +{ + (*phba->lpfc_handle_eratt)(phba); +} + /** * lpfc_handle_latt - The HBA link event handler * @phba: pointer to lpfc hba data structure. @@ -1137,7 +1342,7 @@ lpfc_handle_latt_err_exit: * 0 - pointer to the VPD passed in is NULL * 1 - success **/ -static int +int lpfc_parse_vpd(struct lpfc_hba *phba, uint8_t *vpd, int len) { uint8_t lenlo, lenhi; @@ -1292,6 +1497,7 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp) uint16_t dev_id = phba->pcidev->device; int max_speed; int GE = 0; + int oneConnect = 0; /* default is not a oneConnect */ struct { char * name; int max_speed; @@ -1437,6 +1643,10 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp) case PCI_DEVICE_ID_PROTEUS_S: m = (typeof(m)) {"LPemv12002-S", max_speed, "PCIe IOV"}; break; + case PCI_DEVICE_ID_TIGERSHARK: + oneConnect = 1; + m = (typeof(m)) {"OCe10100-F", max_speed, "PCIe"}; + break; default: m = (typeof(m)){ NULL }; break; @@ -1444,13 +1654,24 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp) if (mdp && mdp[0] == '\0') snprintf(mdp, 79,"%s", m.name); - if (descp && descp[0] == '\0') - snprintf(descp, 255, - "Emulex %s %d%s %s %s", - m.name, m.max_speed, - (GE) ? "GE" : "Gb", - m.bus, - (GE) ? "FCoE Adapter" : "Fibre Channel Adapter"); + /* oneConnect hba requires special processing, they are all initiators + * and we put the port number on the end + */ + if (descp && descp[0] == '\0') { + if (oneConnect) + snprintf(descp, 255, + "Emulex OneConnect %s, FCoE Initiator, Port %s", + m.name, + phba->Port); + else + snprintf(descp, 255, + "Emulex %s %d%s %s %s", + m.name, m.max_speed, + (GE) ? "GE" : "Gb", + m.bus, + (GE) ? "FCoE Adapter" : + "Fibre Channel Adapter"); + } } /** @@ -1533,7 +1754,8 @@ lpfc_post_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, int cnt) icmd->ulpCommand = CMD_QUE_RING_BUF64_CN; icmd->ulpLe = 1; - if (lpfc_sli_issue_iocb(phba, pring, iocb, 0) == IOCB_ERROR) { + if (lpfc_sli_issue_iocb(phba, pring->ringno, iocb, 0) == + IOCB_ERROR) { lpfc_mbuf_free(phba, mp1->virt, mp1->phys); kfree(mp1); cnt++; @@ -1761,7 +1983,6 @@ lpfc_cleanup(struct lpfc_vport *vport) * Lets wait for this to happen, if needed. */ while (!list_empty(&vport->fc_nodes)) { - if (i++ > 3000) { lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, "0233 Nodelist not empty\n"); @@ -1782,7 +2003,6 @@ lpfc_cleanup(struct lpfc_vport *vport) /* Wait for any activity on ndlps to settle */ msleep(10); } - return; } /** @@ -1803,22 +2023,36 @@ lpfc_stop_vport_timers(struct lpfc_vport *vport) } /** - * lpfc_stop_phba_timers - Stop all the timers associated with an HBA + * lpfc_stop_hba_timers - Stop all the timers associated with an HBA * @phba: pointer to lpfc hba data structure. * * This routine stops all the timers associated with a HBA. This function is * invoked before either putting a HBA offline or unloading the driver. **/ -static void -lpfc_stop_phba_timers(struct lpfc_hba *phba) +void +lpfc_stop_hba_timers(struct lpfc_hba *phba) { - del_timer_sync(&phba->fcp_poll_timer); lpfc_stop_vport_timers(phba->pport); del_timer_sync(&phba->sli.mbox_tmo); del_timer_sync(&phba->fabric_block_timer); - phba->hb_outstanding = 0; - del_timer_sync(&phba->hb_tmofunc); del_timer_sync(&phba->eratt_poll); + del_timer_sync(&phba->hb_tmofunc); + phba->hb_outstanding = 0; + + switch (phba->pci_dev_grp) { + case LPFC_PCI_DEV_LP: + /* Stop any LightPulse device specific driver timers */ + del_timer_sync(&phba->fcp_poll_timer); + break; + case LPFC_PCI_DEV_OC: + /* Stop any OneConnect device sepcific driver timers */ + break; + default: + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0297 Invalid device group (x%x)\n", + phba->pci_dev_grp); + break; + } return; } @@ -1878,14 +2112,21 @@ lpfc_online(struct lpfc_hba *phba) return 1; } - if (lpfc_sli_hba_setup(phba)) { /* Initialize the HBA */ - lpfc_unblock_mgmt_io(phba); - return 1; + if (phba->sli_rev == LPFC_SLI_REV4) { + if (lpfc_sli4_hba_setup(phba)) { /* Initialize SLI4 HBA */ + lpfc_unblock_mgmt_io(phba); + return 1; + } + } else { + if (lpfc_sli_hba_setup(phba)) { /* Initialize SLI2/SLI3 HBA */ + lpfc_unblock_mgmt_io(phba); + return 1; + } } vports = lpfc_create_vport_work_array(phba); if (vports != NULL) - for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { + for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { struct Scsi_Host *shost; shost = lpfc_shost_from_vport(vports[i]); spin_lock_irq(shost->host_lock); @@ -1947,11 +2188,12 @@ lpfc_offline_prep(struct lpfc_hba * phba) /* Issue an unreg_login to all nodes on all vports */ vports = lpfc_create_vport_work_array(phba); if (vports != NULL) { - for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { + for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { struct Scsi_Host *shost; if (vports[i]->load_flag & FC_UNLOADING) continue; + vports[i]->vfi_state &= ~LPFC_VFI_REGISTERED; shost = lpfc_shost_from_vport(vports[i]); list_for_each_entry_safe(ndlp, next_ndlp, &vports[i]->fc_nodes, @@ -1975,7 +2217,7 @@ lpfc_offline_prep(struct lpfc_hba * phba) } lpfc_destroy_vport_work_array(phba, vports); - lpfc_sli_flush_mbox_queue(phba); + lpfc_sli_mbox_sys_shutdown(phba); } /** @@ -1996,11 +2238,11 @@ lpfc_offline(struct lpfc_hba *phba) if (phba->pport->fc_flag & FC_OFFLINE_MODE) return; - /* stop all timers associated with this hba */ - lpfc_stop_phba_timers(phba); + /* stop port and all timers associated with this hba */ + lpfc_stop_port(phba); vports = lpfc_create_vport_work_array(phba); if (vports != NULL) - for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) + for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) lpfc_stop_vport_timers(vports[i]); lpfc_destroy_vport_work_array(phba, vports); lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, @@ -2013,7 +2255,7 @@ lpfc_offline(struct lpfc_hba *phba) spin_unlock_irq(&phba->hbalock); vports = lpfc_create_vport_work_array(phba); if (vports != NULL) - for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { + for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { shost = lpfc_shost_from_vport(vports[i]); spin_lock_irq(shost->host_lock); vports[i]->work_port_events = 0; @@ -2106,6 +2348,10 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev) shost->max_lun = vport->cfg_max_luns; shost->this_id = -1; shost->max_cmd_len = 16; + if (phba->sli_rev == LPFC_SLI_REV4) { + shost->dma_boundary = LPFC_SLI4_MAX_SEGMENT_SIZE; + shost->sg_tablesize = phba->cfg_sg_seg_cnt; + } /* * Set initial can_queue value since 0 is no longer supported and @@ -2123,6 +2369,7 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev) /* Initialize all internally managed lists. */ INIT_LIST_HEAD(&vport->fc_nodes); + INIT_LIST_HEAD(&vport->rcv_buffer_list); spin_lock_init(&vport->work_port_lock); init_timer(&vport->fc_disctmo); @@ -2314,15 +2561,3462 @@ void lpfc_host_attrib_init(struct Scsi_Host *shost) } /** - * lpfc_enable_msix - Enable MSI-X interrupt mode + * lpfc_stop_port_s3 - Stop SLI3 device port * @phba: pointer to lpfc hba data structure. * - * This routine is invoked to enable the MSI-X interrupt vectors. The kernel - * function pci_enable_msix() is called to enable the MSI-X vectors. Note that - * pci_enable_msix(), once invoked, enables either all or nothing, depending - * on the current availability of PCI vector resources. The device driver is - * responsible for calling the individual request_irq() to register each MSI-X - * vector with a interrupt handler, which is done in this function. Note that + * This routine is invoked to stop an SLI3 device port, it stops the device + * from generating interrupts and stops the device driver's timers for the + * device. + **/ +static void +lpfc_stop_port_s3(struct lpfc_hba *phba) +{ + /* Clear all interrupt enable conditions */ + writel(0, phba->HCregaddr); + readl(phba->HCregaddr); /* flush */ + /* Clear all pending interrupts */ + writel(0xffffffff, phba->HAregaddr); + readl(phba->HAregaddr); /* flush */ + + /* Reset some HBA SLI setup states */ + lpfc_stop_hba_timers(phba); + phba->pport->work_port_events = 0; +} + +/** + * lpfc_stop_port_s4 - Stop SLI4 device port + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to stop an SLI4 device port, it stops the device + * from generating interrupts and stops the device driver's timers for the + * device. + **/ +static void +lpfc_stop_port_s4(struct lpfc_hba *phba) +{ + /* Reset some HBA SLI4 setup states */ + lpfc_stop_hba_timers(phba); + phba->pport->work_port_events = 0; + phba->sli4_hba.intr_enable = 0; + /* Hard clear it for now, shall have more graceful way to wait later */ + phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; +} + +/** + * lpfc_stop_port - Wrapper function for stopping hba port + * @phba: Pointer to HBA context object. + * + * This routine wraps the actual SLI3 or SLI4 hba stop port routine from + * the API jump table function pointer from the lpfc_hba struct. + **/ +void +lpfc_stop_port(struct lpfc_hba *phba) +{ + phba->lpfc_stop_port(phba); +} + +/** + * lpfc_sli4_remove_dflt_fcf - Remove the driver default fcf record from the port. + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to remove the driver default fcf record from + * the port. This routine currently acts on FCF Index 0. + * + **/ +void +lpfc_sli_remove_dflt_fcf(struct lpfc_hba *phba) +{ + int rc = 0; + LPFC_MBOXQ_t *mboxq; + struct lpfc_mbx_del_fcf_tbl_entry *del_fcf_record; + uint32_t mbox_tmo, req_len; + uint32_t shdr_status, shdr_add_status; + + mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mboxq) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2020 Failed to allocate mbox for ADD_FCF cmd\n"); + return; + } + + req_len = sizeof(struct lpfc_mbx_del_fcf_tbl_entry) - + sizeof(struct lpfc_sli4_cfg_mhdr); + rc = lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_FCOE, + LPFC_MBOX_OPCODE_FCOE_DELETE_FCF, + req_len, LPFC_SLI4_MBX_EMBED); + /* + * In phase 1, there is a single FCF index, 0. In phase2, the driver + * supports multiple FCF indices. + */ + del_fcf_record = &mboxq->u.mqe.un.del_fcf_entry; + bf_set(lpfc_mbx_del_fcf_tbl_count, del_fcf_record, 1); + bf_set(lpfc_mbx_del_fcf_tbl_index, del_fcf_record, + phba->fcf.fcf_indx); + + if (!phba->sli4_hba.intr_enable) + rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); + else { + mbox_tmo = lpfc_mbox_tmo_val(phba, MBX_SLI4_CONFIG); + rc = lpfc_sli_issue_mbox_wait(phba, mboxq, mbox_tmo); + } + /* The IOCTL status is embedded in the mailbox subheader. */ + shdr_status = bf_get(lpfc_mbox_hdr_status, + &del_fcf_record->header.cfg_shdr.response); + shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, + &del_fcf_record->header.cfg_shdr.response); + if (shdr_status || shdr_add_status || rc != MBX_SUCCESS) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "2516 DEL FCF of default FCF Index failed " + "mbx status x%x, status x%x add_status x%x\n", + rc, shdr_status, shdr_add_status); + } + if (rc != MBX_TIMEOUT) + mempool_free(mboxq, phba->mbox_mem_pool); +} + +/** + * lpfc_sli4_parse_latt_fault - Parse sli4 link-attention link fault code + * @phba: pointer to lpfc hba data structure. + * @acqe_link: pointer to the async link completion queue entry. + * + * This routine is to parse the SLI4 link-attention link fault code and + * translate it into the base driver's read link attention mailbox command + * status. + * + * Return: Link-attention status in terms of base driver's coding. + **/ +static uint16_t +lpfc_sli4_parse_latt_fault(struct lpfc_hba *phba, + struct lpfc_acqe_link *acqe_link) +{ + uint16_t latt_fault; + + switch (bf_get(lpfc_acqe_link_fault, acqe_link)) { + case LPFC_ASYNC_LINK_FAULT_NONE: + case LPFC_ASYNC_LINK_FAULT_LOCAL: + case LPFC_ASYNC_LINK_FAULT_REMOTE: + latt_fault = 0; + break; + default: + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0398 Invalid link fault code: x%x\n", + bf_get(lpfc_acqe_link_fault, acqe_link)); + latt_fault = MBXERR_ERROR; + break; + } + return latt_fault; +} + +/** + * lpfc_sli4_parse_latt_type - Parse sli4 link attention type + * @phba: pointer to lpfc hba data structure. + * @acqe_link: pointer to the async link completion queue entry. + * + * This routine is to parse the SLI4 link attention type and translate it + * into the base driver's link attention type coding. + * + * Return: Link attention type in terms of base driver's coding. + **/ +static uint8_t +lpfc_sli4_parse_latt_type(struct lpfc_hba *phba, + struct lpfc_acqe_link *acqe_link) +{ + uint8_t att_type; + + switch (bf_get(lpfc_acqe_link_status, acqe_link)) { + case LPFC_ASYNC_LINK_STATUS_DOWN: + case LPFC_ASYNC_LINK_STATUS_LOGICAL_DOWN: + att_type = AT_LINK_DOWN; + break; + case LPFC_ASYNC_LINK_STATUS_UP: + /* Ignore physical link up events - wait for logical link up */ + att_type = AT_RESERVED; + break; + case LPFC_ASYNC_LINK_STATUS_LOGICAL_UP: + att_type = AT_LINK_UP; + break; + default: + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0399 Invalid link attention type: x%x\n", + bf_get(lpfc_acqe_link_status, acqe_link)); + att_type = AT_RESERVED; + break; + } + return att_type; +} + +/** + * lpfc_sli4_parse_latt_link_speed - Parse sli4 link-attention link speed + * @phba: pointer to lpfc hba data structure. + * @acqe_link: pointer to the async link completion queue entry. + * + * This routine is to parse the SLI4 link-attention link speed and translate + * it into the base driver's link-attention link speed coding. + * + * Return: Link-attention link speed in terms of base driver's coding. + **/ +static uint8_t +lpfc_sli4_parse_latt_link_speed(struct lpfc_hba *phba, + struct lpfc_acqe_link *acqe_link) +{ + uint8_t link_speed; + + switch (bf_get(lpfc_acqe_link_speed, acqe_link)) { + case LPFC_ASYNC_LINK_SPEED_ZERO: + link_speed = LA_UNKNW_LINK; + break; + case LPFC_ASYNC_LINK_SPEED_10MBPS: + link_speed = LA_UNKNW_LINK; + break; + case LPFC_ASYNC_LINK_SPEED_100MBPS: + link_speed = LA_UNKNW_LINK; + break; + case LPFC_ASYNC_LINK_SPEED_1GBPS: + link_speed = LA_1GHZ_LINK; + break; + case LPFC_ASYNC_LINK_SPEED_10GBPS: + link_speed = LA_10GHZ_LINK; + break; + default: + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0483 Invalid link-attention link speed: x%x\n", + bf_get(lpfc_acqe_link_speed, acqe_link)); + link_speed = LA_UNKNW_LINK; + break; + } + return link_speed; +} + +/** + * lpfc_sli4_async_link_evt - Process the asynchronous link event + * @phba: pointer to lpfc hba data structure. + * @acqe_link: pointer to the async link completion queue entry. + * + * This routine is to handle the SLI4 asynchronous link event. + **/ +static void +lpfc_sli4_async_link_evt(struct lpfc_hba *phba, + struct lpfc_acqe_link *acqe_link) +{ + struct lpfc_dmabuf *mp; + LPFC_MBOXQ_t *pmb; + MAILBOX_t *mb; + READ_LA_VAR *la; + uint8_t att_type; + + att_type = lpfc_sli4_parse_latt_type(phba, acqe_link); + if (att_type != AT_LINK_DOWN && att_type != AT_LINK_UP) + return; + pmb = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!pmb) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "0395 The mboxq allocation failed\n"); + return; + } + mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); + if (!mp) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "0396 The lpfc_dmabuf allocation failed\n"); + goto out_free_pmb; + } + mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys); + if (!mp->virt) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "0397 The mbuf allocation failed\n"); + goto out_free_dmabuf; + } + + /* Cleanup any outstanding ELS commands */ + lpfc_els_flush_all_cmd(phba); + + /* Block ELS IOCBs until we have done process link event */ + phba->sli.ring[LPFC_ELS_RING].flag |= LPFC_STOP_IOCB_EVENT; + + /* Update link event statistics */ + phba->sli.slistat.link_event++; + + /* Create pseudo lpfc_handle_latt mailbox command from link ACQE */ + lpfc_read_la(phba, pmb, mp); + pmb->vport = phba->pport; + + /* Parse and translate status field */ + mb = &pmb->u.mb; + mb->mbxStatus = lpfc_sli4_parse_latt_fault(phba, acqe_link); + + /* Parse and translate link attention fields */ + la = (READ_LA_VAR *) &pmb->u.mb.un.varReadLA; + la->eventTag = acqe_link->event_tag; + la->attType = att_type; + la->UlnkSpeed = lpfc_sli4_parse_latt_link_speed(phba, acqe_link); + + /* Fake the the following irrelvant fields */ + la->topology = TOPOLOGY_PT_PT; + la->granted_AL_PA = 0; + la->il = 0; + la->pb = 0; + la->fa = 0; + la->mm = 0; + + /* Keep the link status for extra SLI4 state machine reference */ + phba->sli4_hba.link_state.speed = + bf_get(lpfc_acqe_link_speed, acqe_link); + phba->sli4_hba.link_state.duplex = + bf_get(lpfc_acqe_link_duplex, acqe_link); + phba->sli4_hba.link_state.status = + bf_get(lpfc_acqe_link_status, acqe_link); + phba->sli4_hba.link_state.physical = + bf_get(lpfc_acqe_link_physical, acqe_link); + phba->sli4_hba.link_state.fault = + bf_get(lpfc_acqe_link_fault, acqe_link); + + /* Invoke the lpfc_handle_latt mailbox command callback function */ + lpfc_mbx_cmpl_read_la(phba, pmb); + + return; + +out_free_dmabuf: + kfree(mp); +out_free_pmb: + mempool_free(pmb, phba->mbox_mem_pool); +} + +/** + * lpfc_sli4_async_fcoe_evt - Process the asynchronous fcoe event + * @phba: pointer to lpfc hba data structure. + * @acqe_link: pointer to the async fcoe completion queue entry. + * + * This routine is to handle the SLI4 asynchronous fcoe event. + **/ +static void +lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba, + struct lpfc_acqe_fcoe *acqe_fcoe) +{ + uint8_t event_type = bf_get(lpfc_acqe_fcoe_event_type, acqe_fcoe); + int rc; + + switch (event_type) { + case LPFC_FCOE_EVENT_TYPE_NEW_FCF: + lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, + "2546 New FCF found index 0x%x tag 0x%x \n", + acqe_fcoe->fcf_index, + acqe_fcoe->event_tag); + /* + * If the current FCF is in discovered state, + * do nothing. + */ + spin_lock_irq(&phba->hbalock); + if (phba->fcf.fcf_flag & FCF_DISCOVERED) { + spin_unlock_irq(&phba->hbalock); + break; + } + spin_unlock_irq(&phba->hbalock); + + /* Read the FCF table and re-discover SAN. */ + rc = lpfc_sli4_read_fcf_record(phba, + LPFC_FCOE_FCF_GET_FIRST); + if (rc) + lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, + "2547 Read FCF record failed 0x%x\n", + rc); + break; + + case LPFC_FCOE_EVENT_TYPE_FCF_TABLE_FULL: + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "2548 FCF Table full count 0x%x tag 0x%x \n", + bf_get(lpfc_acqe_fcoe_fcf_count, acqe_fcoe), + acqe_fcoe->event_tag); + break; + + case LPFC_FCOE_EVENT_TYPE_FCF_DEAD: + lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, + "2549 FCF disconnected fron network index 0x%x" + " tag 0x%x \n", acqe_fcoe->fcf_index, + acqe_fcoe->event_tag); + /* If the event is not for currently used fcf do nothing */ + if (phba->fcf.fcf_indx != acqe_fcoe->fcf_index) + break; + /* + * Currently, driver support only one FCF - so treat this as + * a link down. + */ + lpfc_linkdown(phba); + /* Unregister FCF if no devices connected to it */ + lpfc_unregister_unused_fcf(phba); + break; + + default: + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "0288 Unknown FCoE event type 0x%x event tag " + "0x%x\n", event_type, acqe_fcoe->event_tag); + break; + } +} + +/** + * lpfc_sli4_async_dcbx_evt - Process the asynchronous dcbx event + * @phba: pointer to lpfc hba data structure. + * @acqe_link: pointer to the async dcbx completion queue entry. + * + * This routine is to handle the SLI4 asynchronous dcbx event. + **/ +static void +lpfc_sli4_async_dcbx_evt(struct lpfc_hba *phba, + struct lpfc_acqe_dcbx *acqe_dcbx) +{ + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "0290 The SLI4 DCBX asynchronous event is not " + "handled yet\n"); +} + +/** + * lpfc_sli4_async_event_proc - Process all the pending asynchronous event + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked by the worker thread to process all the pending + * SLI4 asynchronous events. + **/ +void lpfc_sli4_async_event_proc(struct lpfc_hba *phba) +{ + struct lpfc_cq_event *cq_event; + + /* First, declare the async event has been handled */ + spin_lock_irq(&phba->hbalock); + phba->hba_flag &= ~ASYNC_EVENT; + spin_unlock_irq(&phba->hbalock); + /* Now, handle all the async events */ + while (!list_empty(&phba->sli4_hba.sp_asynce_work_queue)) { + /* Get the first event from the head of the event queue */ + spin_lock_irq(&phba->hbalock); + list_remove_head(&phba->sli4_hba.sp_asynce_work_queue, + cq_event, struct lpfc_cq_event, list); + spin_unlock_irq(&phba->hbalock); + /* Process the asynchronous event */ + switch (bf_get(lpfc_trailer_code, &cq_event->cqe.mcqe_cmpl)) { + case LPFC_TRAILER_CODE_LINK: + lpfc_sli4_async_link_evt(phba, + &cq_event->cqe.acqe_link); + break; + case LPFC_TRAILER_CODE_FCOE: + lpfc_sli4_async_fcoe_evt(phba, + &cq_event->cqe.acqe_fcoe); + break; + case LPFC_TRAILER_CODE_DCBX: + lpfc_sli4_async_dcbx_evt(phba, + &cq_event->cqe.acqe_dcbx); + break; + default: + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "1804 Invalid asynchrous event code: " + "x%x\n", bf_get(lpfc_trailer_code, + &cq_event->cqe.mcqe_cmpl)); + break; + } + /* Free the completion event processed to the free pool */ + lpfc_sli4_cq_event_release(phba, cq_event); + } +} + +/** + * lpfc_api_table_setup - Set up per hba pci-device group func api jump table + * @phba: pointer to lpfc hba data structure. + * @dev_grp: The HBA PCI-Device group number. + * + * This routine is invoked to set up the per HBA PCI-Device group function + * API jump table entries. + * + * Return: 0 if success, otherwise -ENODEV + **/ +int +lpfc_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp) +{ + int rc; + + /* Set up lpfc PCI-device group */ + phba->pci_dev_grp = dev_grp; + + /* The LPFC_PCI_DEV_OC uses SLI4 */ + if (dev_grp == LPFC_PCI_DEV_OC) + phba->sli_rev = LPFC_SLI_REV4; + + /* Set up device INIT API function jump table */ + rc = lpfc_init_api_table_setup(phba, dev_grp); + if (rc) + return -ENODEV; + /* Set up SCSI API function jump table */ + rc = lpfc_scsi_api_table_setup(phba, dev_grp); + if (rc) + return -ENODEV; + /* Set up SLI API function jump table */ + rc = lpfc_sli_api_table_setup(phba, dev_grp); + if (rc) + return -ENODEV; + /* Set up MBOX API function jump table */ + rc = lpfc_mbox_api_table_setup(phba, dev_grp); + if (rc) + return -ENODEV; + + return 0; +} + +/** + * lpfc_log_intr_mode - Log the active interrupt mode + * @phba: pointer to lpfc hba data structure. + * @intr_mode: active interrupt mode adopted. + * + * This routine it invoked to log the currently used active interrupt mode + * to the device. + **/ +static void lpfc_log_intr_mode(struct lpfc_hba *phba, uint32_t intr_mode) +{ + switch (intr_mode) { + case 0: + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "0470 Enable INTx interrupt mode.\n"); + break; + case 1: + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "0481 Enabled MSI interrupt mode.\n"); + break; + case 2: + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "0480 Enabled MSI-X interrupt mode.\n"); + break; + default: + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0482 Illegal interrupt mode.\n"); + break; + } + return; +} + +/** + * lpfc_enable_pci_dev - Enable a generic PCI device. + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to enable the PCI device that is common to all + * PCI devices. + * + * Return codes + * 0 - sucessful + * other values - error + **/ +static int +lpfc_enable_pci_dev(struct lpfc_hba *phba) +{ + struct pci_dev *pdev; + int bars; + + /* Obtain PCI device reference */ + if (!phba->pcidev) + goto out_error; + else + pdev = phba->pcidev; + /* Select PCI BARs */ + bars = pci_select_bars(pdev, IORESOURCE_MEM); + /* Enable PCI device */ + if (pci_enable_device_mem(pdev)) + goto out_error; + /* Request PCI resource for the device */ + if (pci_request_selected_regions(pdev, bars, LPFC_DRIVER_NAME)) + goto out_disable_device; + /* Set up device as PCI master and save state for EEH */ + pci_set_master(pdev); + pci_try_set_mwi(pdev); + pci_save_state(pdev); + + return 0; + +out_disable_device: + pci_disable_device(pdev); +out_error: + return -ENODEV; +} + +/** + * lpfc_disable_pci_dev - Disable a generic PCI device. + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to disable the PCI device that is common to all + * PCI devices. + **/ +static void +lpfc_disable_pci_dev(struct lpfc_hba *phba) +{ + struct pci_dev *pdev; + int bars; + + /* Obtain PCI device reference */ + if (!phba->pcidev) + return; + else + pdev = phba->pcidev; + /* Select PCI BARs */ + bars = pci_select_bars(pdev, IORESOURCE_MEM); + /* Release PCI resource and disable PCI device */ + pci_release_selected_regions(pdev, bars); + pci_disable_device(pdev); + /* Null out PCI private reference to driver */ + pci_set_drvdata(pdev, NULL); + + return; +} + +/** + * lpfc_reset_hba - Reset a hba + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to reset a hba device. It brings the HBA + * offline, performs a board restart, and then brings the board back + * online. The lpfc_offline calls lpfc_sli_hba_down which will clean up + * on outstanding mailbox commands. + **/ +void +lpfc_reset_hba(struct lpfc_hba *phba) +{ + /* If resets are disabled then set error state and return. */ + if (!phba->cfg_enable_hba_reset) { + phba->link_state = LPFC_HBA_ERROR; + return; + } + lpfc_offline_prep(phba); + lpfc_offline(phba); + lpfc_sli_brdrestart(phba); + lpfc_online(phba); + lpfc_unblock_mgmt_io(phba); +} + +/** + * lpfc_sli_driver_resource_setup - Setup driver internal resources for SLI3 dev. + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to set up the driver internal resources specific to + * support the SLI-3 HBA device it attached to. + * + * Return codes + * 0 - sucessful + * other values - error + **/ +static int +lpfc_sli_driver_resource_setup(struct lpfc_hba *phba) +{ + struct lpfc_sli *psli; + + /* + * Initialize timers used by driver + */ + + /* Heartbeat timer */ + init_timer(&phba->hb_tmofunc); + phba->hb_tmofunc.function = lpfc_hb_timeout; + phba->hb_tmofunc.data = (unsigned long)phba; + + psli = &phba->sli; + /* MBOX heartbeat timer */ + init_timer(&psli->mbox_tmo); + psli->mbox_tmo.function = lpfc_mbox_timeout; + psli->mbox_tmo.data = (unsigned long) phba; + /* FCP polling mode timer */ + init_timer(&phba->fcp_poll_timer); + phba->fcp_poll_timer.function = lpfc_poll_timeout; + phba->fcp_poll_timer.data = (unsigned long) phba; + /* Fabric block timer */ + init_timer(&phba->fabric_block_timer); + phba->fabric_block_timer.function = lpfc_fabric_block_timeout; + phba->fabric_block_timer.data = (unsigned long) phba; + /* EA polling mode timer */ + init_timer(&phba->eratt_poll); + phba->eratt_poll.function = lpfc_poll_eratt; + phba->eratt_poll.data = (unsigned long) phba; + + /* Host attention work mask setup */ + phba->work_ha_mask = (HA_ERATT | HA_MBATT | HA_LATT); + phba->work_ha_mask |= (HA_RXMASK << (LPFC_ELS_RING * 4)); + + /* Get all the module params for configuring this host */ + lpfc_get_cfgparam(phba); + /* + * Since the sg_tablesize is module parameter, the sg_dma_buf_size + * used to create the sg_dma_buf_pool must be dynamically calculated. + * 2 segments are added since the IOCB needs a command and response bde. + */ + phba->cfg_sg_dma_buf_size = sizeof(struct fcp_cmnd) + + sizeof(struct fcp_rsp) + + ((phba->cfg_sg_seg_cnt + 2) * sizeof(struct ulp_bde64)); + + if (phba->cfg_enable_bg) { + phba->cfg_sg_seg_cnt = LPFC_MAX_SG_SEG_CNT; + phba->cfg_sg_dma_buf_size += + phba->cfg_prot_sg_seg_cnt * sizeof(struct ulp_bde64); + } + + /* Also reinitialize the host templates with new values. */ + lpfc_vport_template.sg_tablesize = phba->cfg_sg_seg_cnt; + lpfc_template.sg_tablesize = phba->cfg_sg_seg_cnt; + + phba->max_vpi = LPFC_MAX_VPI; + /* This will be set to correct value after config_port mbox */ + phba->max_vports = 0; + + /* + * Initialize the SLI Layer to run with lpfc HBAs. + */ + lpfc_sli_setup(phba); + lpfc_sli_queue_setup(phba); + + /* Allocate device driver memory */ + if (lpfc_mem_alloc(phba, BPL_ALIGN_SZ)) + return -ENOMEM; + + return 0; +} + +/** + * lpfc_sli_driver_resource_unset - Unset drvr internal resources for SLI3 dev + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to unset the driver internal resources set up + * specific for supporting the SLI-3 HBA device it attached to. + **/ +static void +lpfc_sli_driver_resource_unset(struct lpfc_hba *phba) +{ + /* Free device driver memory allocated */ + lpfc_mem_free_all(phba); + + return; +} + +/** + * lpfc_sli4_driver_resource_setup - Setup drvr internal resources for SLI4 dev + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to set up the driver internal resources specific to + * support the SLI-4 HBA device it attached to. + * + * Return codes + * 0 - sucessful + * other values - error + **/ +static int +lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) +{ + struct lpfc_sli *psli; + int rc; + int i, hbq_count; + + /* Before proceed, wait for POST done and device ready */ + rc = lpfc_sli4_post_status_check(phba); + if (rc) + return -ENODEV; + + /* + * Initialize timers used by driver + */ + + /* Heartbeat timer */ + init_timer(&phba->hb_tmofunc); + phba->hb_tmofunc.function = lpfc_hb_timeout; + phba->hb_tmofunc.data = (unsigned long)phba; + + psli = &phba->sli; + /* MBOX heartbeat timer */ + init_timer(&psli->mbox_tmo); + psli->mbox_tmo.function = lpfc_mbox_timeout; + psli->mbox_tmo.data = (unsigned long) phba; + /* Fabric block timer */ + init_timer(&phba->fabric_block_timer); + phba->fabric_block_timer.function = lpfc_fabric_block_timeout; + phba->fabric_block_timer.data = (unsigned long) phba; + /* EA polling mode timer */ + init_timer(&phba->eratt_poll); + phba->eratt_poll.function = lpfc_poll_eratt; + phba->eratt_poll.data = (unsigned long) phba; + /* + * We need to do a READ_CONFIG mailbox command here before + * calling lpfc_get_cfgparam. For VFs this will report the + * MAX_XRI, MAX_VPI, MAX_RPI, MAX_IOCB, and MAX_VFI settings. + * All of the resources allocated + * for this Port are tied to these values. + */ + /* Get all the module params for configuring this host */ + lpfc_get_cfgparam(phba); + phba->max_vpi = LPFC_MAX_VPI; + /* This will be set to correct value after the read_config mbox */ + phba->max_vports = 0; + + /* Program the default value of vlan_id and fc_map */ + phba->valid_vlan = 0; + phba->fc_map[0] = LPFC_FCOE_FCF_MAP0; + phba->fc_map[1] = LPFC_FCOE_FCF_MAP1; + phba->fc_map[2] = LPFC_FCOE_FCF_MAP2; + + /* + * Since the sg_tablesize is module parameter, the sg_dma_buf_size + * used to create the sg_dma_buf_pool must be dynamically calculated. + * 2 segments are added since the IOCB needs a command and response bde. + * To insure that the scsi sgl does not cross a 4k page boundary only + * sgl sizes of 1k, 2k, 4k, and 8k are supported. + * Table of sgl sizes and seg_cnt: + * sgl size, sg_seg_cnt total seg + * 1k 50 52 + * 2k 114 116 + * 4k 242 244 + * 8k 498 500 + * cmd(32) + rsp(160) + (52 * sizeof(sli4_sge)) = 1024 + * cmd(32) + rsp(160) + (116 * sizeof(sli4_sge)) = 2048 + * cmd(32) + rsp(160) + (244 * sizeof(sli4_sge)) = 4096 + * cmd(32) + rsp(160) + (500 * sizeof(sli4_sge)) = 8192 + */ + if (phba->cfg_sg_seg_cnt <= LPFC_DEFAULT_SG_SEG_CNT) + phba->cfg_sg_seg_cnt = 50; + else if (phba->cfg_sg_seg_cnt <= 114) + phba->cfg_sg_seg_cnt = 114; + else if (phba->cfg_sg_seg_cnt <= 242) + phba->cfg_sg_seg_cnt = 242; + else + phba->cfg_sg_seg_cnt = 498; + + phba->cfg_sg_dma_buf_size = sizeof(struct fcp_cmnd) + + sizeof(struct fcp_rsp); + phba->cfg_sg_dma_buf_size += + ((phba->cfg_sg_seg_cnt + 2) * sizeof(struct sli4_sge)); + + /* Initialize buffer queue management fields */ + hbq_count = lpfc_sli_hbq_count(); + for (i = 0; i < hbq_count; ++i) + INIT_LIST_HEAD(&phba->hbqs[i].hbq_buffer_list); + INIT_LIST_HEAD(&phba->rb_pend_list); + phba->hbqs[LPFC_ELS_HBQ].hbq_alloc_buffer = lpfc_sli4_rb_alloc; + phba->hbqs[LPFC_ELS_HBQ].hbq_free_buffer = lpfc_sli4_rb_free; + + /* + * Initialize the SLI Layer to run with lpfc SLI4 HBAs. + */ + /* Initialize the Abort scsi buffer list used by driver */ + spin_lock_init(&phba->sli4_hba.abts_scsi_buf_list_lock); + INIT_LIST_HEAD(&phba->sli4_hba.lpfc_abts_scsi_buf_list); + /* This abort list used by worker thread */ + spin_lock_init(&phba->sli4_hba.abts_sgl_list_lock); + + /* + * Initialize dirver internal slow-path work queues + */ + + /* Driver internel slow-path CQ Event pool */ + INIT_LIST_HEAD(&phba->sli4_hba.sp_cqe_event_pool); + /* Response IOCB work queue list */ + INIT_LIST_HEAD(&phba->sli4_hba.sp_rspiocb_work_queue); + /* Asynchronous event CQ Event work queue list */ + INIT_LIST_HEAD(&phba->sli4_hba.sp_asynce_work_queue); + /* Fast-path XRI aborted CQ Event work queue list */ + INIT_LIST_HEAD(&phba->sli4_hba.sp_fcp_xri_aborted_work_queue); + /* Slow-path XRI aborted CQ Event work queue list */ + INIT_LIST_HEAD(&phba->sli4_hba.sp_els_xri_aborted_work_queue); + /* Receive queue CQ Event work queue list */ + INIT_LIST_HEAD(&phba->sli4_hba.sp_unsol_work_queue); + + /* Initialize the driver internal SLI layer lists. */ + lpfc_sli_setup(phba); + lpfc_sli_queue_setup(phba); + + /* Allocate device driver memory */ + rc = lpfc_mem_alloc(phba, SGL_ALIGN_SZ); + if (rc) + return -ENOMEM; + + /* Create the bootstrap mailbox command */ + rc = lpfc_create_bootstrap_mbox(phba); + if (unlikely(rc)) + goto out_free_mem; + + /* Set up the host's endian order with the device. */ + rc = lpfc_setup_endian_order(phba); + if (unlikely(rc)) + goto out_free_bsmbx; + + /* Set up the hba's configuration parameters. */ + rc = lpfc_sli4_read_config(phba); + if (unlikely(rc)) + goto out_free_bsmbx; + + /* Perform a function reset */ + rc = lpfc_pci_function_reset(phba); + if (unlikely(rc)) + goto out_free_bsmbx; + + /* Create all the SLI4 queues */ + rc = lpfc_sli4_queue_create(phba); + if (rc) + goto out_free_bsmbx; + + /* Create driver internal CQE event pool */ + rc = lpfc_sli4_cq_event_pool_create(phba); + if (rc) + goto out_destroy_queue; + + /* Initialize and populate the iocb list per host */ + rc = lpfc_init_sgl_list(phba); + if (rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "1400 Failed to initialize sgl list.\n"); + goto out_destroy_cq_event_pool; + } + rc = lpfc_init_active_sgl_array(phba); + if (rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "1430 Failed to initialize sgl list.\n"); + goto out_free_sgl_list; + } + + rc = lpfc_sli4_init_rpi_hdrs(phba); + if (rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "1432 Failed to initialize rpi headers.\n"); + goto out_free_active_sgl; + } + + phba->sli4_hba.fcp_eq_hdl = kzalloc((sizeof(struct lpfc_fcp_eq_hdl) * + phba->cfg_fcp_eq_count), GFP_KERNEL); + if (!phba->sli4_hba.fcp_eq_hdl) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2572 Failed allocate memory for fast-path " + "per-EQ handle array\n"); + goto out_remove_rpi_hdrs; + } + + phba->sli4_hba.msix_entries = kzalloc((sizeof(struct msix_entry) * + phba->sli4_hba.cfg_eqn), GFP_KERNEL); + if (!phba->sli4_hba.msix_entries) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2573 Failed allocate memory for msi-x " + "interrupt vector entries\n"); + goto out_free_fcp_eq_hdl; + } + + return rc; + +out_free_fcp_eq_hdl: + kfree(phba->sli4_hba.fcp_eq_hdl); +out_remove_rpi_hdrs: + lpfc_sli4_remove_rpi_hdrs(phba); +out_free_active_sgl: + lpfc_free_active_sgl(phba); +out_free_sgl_list: + lpfc_free_sgl_list(phba); +out_destroy_cq_event_pool: + lpfc_sli4_cq_event_pool_destroy(phba); +out_destroy_queue: + lpfc_sli4_queue_destroy(phba); +out_free_bsmbx: + lpfc_destroy_bootstrap_mbox(phba); +out_free_mem: + lpfc_mem_free(phba); + return rc; +} + +/** + * lpfc_sli4_driver_resource_unset - Unset drvr internal resources for SLI4 dev + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to unset the driver internal resources set up + * specific for supporting the SLI-4 HBA device it attached to. + **/ +static void +lpfc_sli4_driver_resource_unset(struct lpfc_hba *phba) +{ + struct lpfc_fcf_conn_entry *conn_entry, *next_conn_entry; + + /* unregister default FCFI from the HBA */ + lpfc_sli4_fcfi_unreg(phba, phba->fcf.fcfi); + + /* Free the default FCR table */ + lpfc_sli_remove_dflt_fcf(phba); + + /* Free memory allocated for msi-x interrupt vector entries */ + kfree(phba->sli4_hba.msix_entries); + + /* Free memory allocated for fast-path work queue handles */ + kfree(phba->sli4_hba.fcp_eq_hdl); + + /* Free the allocated rpi headers. */ + lpfc_sli4_remove_rpi_hdrs(phba); + lpfc_sli4_remove_rpis(phba); + + /* Free the ELS sgl list */ + lpfc_free_active_sgl(phba); + lpfc_free_sgl_list(phba); + + /* Free the SCSI sgl management array */ + kfree(phba->sli4_hba.lpfc_scsi_psb_array); + + /* Free the SLI4 queues */ + lpfc_sli4_queue_destroy(phba); + + /* Free the completion queue EQ event pool */ + lpfc_sli4_cq_event_release_all(phba); + lpfc_sli4_cq_event_pool_destroy(phba); + + /* Reset SLI4 HBA FCoE function */ + lpfc_pci_function_reset(phba); + + /* Free the bsmbx region. */ + lpfc_destroy_bootstrap_mbox(phba); + + /* Free the SLI Layer memory with SLI4 HBAs */ + lpfc_mem_free_all(phba); + + /* Free the current connect table */ + list_for_each_entry_safe(conn_entry, next_conn_entry, + &phba->fcf_conn_rec_list, list) + kfree(conn_entry); + + return; +} + +/** + * lpfc_init_api_table_setup - Set up init api fucntion jump table + * @phba: The hba struct for which this call is being executed. + * @dev_grp: The HBA PCI-Device group number. + * + * This routine sets up the device INIT interface API function jump table + * in @phba struct. + * + * Returns: 0 - success, -ENODEV - failure. + **/ +int +lpfc_init_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp) +{ + switch (dev_grp) { + case LPFC_PCI_DEV_LP: + phba->lpfc_hba_down_post = lpfc_hba_down_post_s3; + phba->lpfc_handle_eratt = lpfc_handle_eratt_s3; + phba->lpfc_stop_port = lpfc_stop_port_s3; + break; + case LPFC_PCI_DEV_OC: + phba->lpfc_hba_down_post = lpfc_hba_down_post_s4; + phba->lpfc_handle_eratt = lpfc_handle_eratt_s4; + phba->lpfc_stop_port = lpfc_stop_port_s4; + break; + default: + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "1431 Invalid HBA PCI-device group: 0x%x\n", + dev_grp); + return -ENODEV; + break; + } + return 0; +} + +/** + * lpfc_setup_driver_resource_phase1 - Phase1 etup driver internal resources. + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to set up the driver internal resources before the + * device specific resource setup to support the HBA device it attached to. + * + * Return codes + * 0 - sucessful + * other values - error + **/ +static int +lpfc_setup_driver_resource_phase1(struct lpfc_hba *phba) +{ + /* + * Driver resources common to all SLI revisions + */ + atomic_set(&phba->fast_event_count, 0); + spin_lock_init(&phba->hbalock); + + /* Initialize ndlp management spinlock */ + spin_lock_init(&phba->ndlp_lock); + + INIT_LIST_HEAD(&phba->port_list); + INIT_LIST_HEAD(&phba->work_list); + init_waitqueue_head(&phba->wait_4_mlo_m_q); + + /* Initialize the wait queue head for the kernel thread */ + init_waitqueue_head(&phba->work_waitq); + + /* Initialize the scsi buffer list used by driver for scsi IO */ + spin_lock_init(&phba->scsi_buf_list_lock); + INIT_LIST_HEAD(&phba->lpfc_scsi_buf_list); + + /* Initialize the fabric iocb list */ + INIT_LIST_HEAD(&phba->fabric_iocb_list); + + /* Initialize list to save ELS buffers */ + INIT_LIST_HEAD(&phba->elsbuf); + + /* Initialize FCF connection rec list */ + INIT_LIST_HEAD(&phba->fcf_conn_rec_list); + + return 0; +} + +/** + * lpfc_setup_driver_resource_phase2 - Phase2 setup driver internal resources. + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to set up the driver internal resources after the + * device specific resource setup to support the HBA device it attached to. + * + * Return codes + * 0 - sucessful + * other values - error + **/ +static int +lpfc_setup_driver_resource_phase2(struct lpfc_hba *phba) +{ + int error; + + /* Startup the kernel thread for this host adapter. */ + phba->worker_thread = kthread_run(lpfc_do_work, phba, + "lpfc_worker_%d", phba->brd_no); + if (IS_ERR(phba->worker_thread)) { + error = PTR_ERR(phba->worker_thread); + return error; + } + + return 0; +} + +/** + * lpfc_unset_driver_resource_phase2 - Phase2 unset driver internal resources. + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to unset the driver internal resources set up after + * the device specific resource setup for supporting the HBA device it + * attached to. + **/ +static void +lpfc_unset_driver_resource_phase2(struct lpfc_hba *phba) +{ + /* Stop kernel worker thread */ + kthread_stop(phba->worker_thread); +} + +/** + * lpfc_free_iocb_list - Free iocb list. + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to free the driver's IOCB list and memory. + **/ +static void +lpfc_free_iocb_list(struct lpfc_hba *phba) +{ + struct lpfc_iocbq *iocbq_entry = NULL, *iocbq_next = NULL; + + spin_lock_irq(&phba->hbalock); + list_for_each_entry_safe(iocbq_entry, iocbq_next, + &phba->lpfc_iocb_list, list) { + list_del(&iocbq_entry->list); + kfree(iocbq_entry); + phba->total_iocbq_bufs--; + } + spin_unlock_irq(&phba->hbalock); + + return; +} + +/** + * lpfc_init_iocb_list - Allocate and initialize iocb list. + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to allocate and initizlize the driver's IOCB + * list and set up the IOCB tag array accordingly. + * + * Return codes + * 0 - sucessful + * other values - error + **/ +static int +lpfc_init_iocb_list(struct lpfc_hba *phba, int iocb_count) +{ + struct lpfc_iocbq *iocbq_entry = NULL; + uint16_t iotag; + int i; + + /* Initialize and populate the iocb list per host. */ + INIT_LIST_HEAD(&phba->lpfc_iocb_list); + for (i = 0; i < iocb_count; i++) { + iocbq_entry = kzalloc(sizeof(struct lpfc_iocbq), GFP_KERNEL); + if (iocbq_entry == NULL) { + printk(KERN_ERR "%s: only allocated %d iocbs of " + "expected %d count. Unloading driver.\n", + __func__, i, LPFC_IOCB_LIST_CNT); + goto out_free_iocbq; + } + + iotag = lpfc_sli_next_iotag(phba, iocbq_entry); + if (iotag == 0) { + kfree(iocbq_entry); + printk(KERN_ERR "%s: failed to allocate IOTAG. " + "Unloading driver.\n", __func__); + goto out_free_iocbq; + } + iocbq_entry->sli4_xritag = NO_XRI; + + spin_lock_irq(&phba->hbalock); + list_add(&iocbq_entry->list, &phba->lpfc_iocb_list); + phba->total_iocbq_bufs++; + spin_unlock_irq(&phba->hbalock); + } + + return 0; + +out_free_iocbq: + lpfc_free_iocb_list(phba); + + return -ENOMEM; +} + +/** + * lpfc_free_sgl_list - Free sgl list. + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to free the driver's sgl list and memory. + **/ +static void +lpfc_free_sgl_list(struct lpfc_hba *phba) +{ + struct lpfc_sglq *sglq_entry = NULL, *sglq_next = NULL; + LIST_HEAD(sglq_list); + int rc = 0; + + spin_lock_irq(&phba->hbalock); + list_splice_init(&phba->sli4_hba.lpfc_sgl_list, &sglq_list); + spin_unlock_irq(&phba->hbalock); + + list_for_each_entry_safe(sglq_entry, sglq_next, + &sglq_list, list) { + list_del(&sglq_entry->list); + lpfc_mbuf_free(phba, sglq_entry->virt, sglq_entry->phys); + kfree(sglq_entry); + phba->sli4_hba.total_sglq_bufs--; + } + rc = lpfc_sli4_remove_all_sgl_pages(phba); + if (rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "2005 Unable to deregister pages from HBA: %x", rc); + } + kfree(phba->sli4_hba.lpfc_els_sgl_array); +} + +/** + * lpfc_init_active_sgl_array - Allocate the buf to track active ELS XRIs. + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to allocate the driver's active sgl memory. + * This array will hold the sglq_entry's for active IOs. + **/ +static int +lpfc_init_active_sgl_array(struct lpfc_hba *phba) +{ + int size; + size = sizeof(struct lpfc_sglq *); + size *= phba->sli4_hba.max_cfg_param.max_xri; + + phba->sli4_hba.lpfc_sglq_active_list = + kzalloc(size, GFP_KERNEL); + if (!phba->sli4_hba.lpfc_sglq_active_list) + return -ENOMEM; + return 0; +} + +/** + * lpfc_free_active_sgl - Free the buf that tracks active ELS XRIs. + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to walk through the array of active sglq entries + * and free all of the resources. + * This is just a place holder for now. + **/ +static void +lpfc_free_active_sgl(struct lpfc_hba *phba) +{ + kfree(phba->sli4_hba.lpfc_sglq_active_list); +} + +/** + * lpfc_init_sgl_list - Allocate and initialize sgl list. + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to allocate and initizlize the driver's sgl + * list and set up the sgl xritag tag array accordingly. + * + * Return codes + * 0 - sucessful + * other values - error + **/ +static int +lpfc_init_sgl_list(struct lpfc_hba *phba) +{ + struct lpfc_sglq *sglq_entry = NULL; + int i; + int els_xri_cnt; + + els_xri_cnt = lpfc_sli4_get_els_iocb_cnt(phba); + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "2400 lpfc_init_sgl_list els %d.\n", + els_xri_cnt); + /* Initialize and populate the sglq list per host/VF. */ + INIT_LIST_HEAD(&phba->sli4_hba.lpfc_sgl_list); + INIT_LIST_HEAD(&phba->sli4_hba.lpfc_abts_els_sgl_list); + + /* Sanity check on XRI management */ + if (phba->sli4_hba.max_cfg_param.max_xri <= els_xri_cnt) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "2562 No room left for SCSI XRI allocation: " + "max_xri=%d, els_xri=%d\n", + phba->sli4_hba.max_cfg_param.max_xri, + els_xri_cnt); + return -ENOMEM; + } + + /* Allocate memory for the ELS XRI management array */ + phba->sli4_hba.lpfc_els_sgl_array = + kzalloc((sizeof(struct lpfc_sglq *) * els_xri_cnt), + GFP_KERNEL); + + if (!phba->sli4_hba.lpfc_els_sgl_array) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "2401 Failed to allocate memory for ELS " + "XRI management array of size %d.\n", + els_xri_cnt); + return -ENOMEM; + } + + /* Keep the SCSI XRI into the XRI management array */ + phba->sli4_hba.scsi_xri_max = + phba->sli4_hba.max_cfg_param.max_xri - els_xri_cnt; + phba->sli4_hba.scsi_xri_cnt = 0; + + phba->sli4_hba.lpfc_scsi_psb_array = + kzalloc((sizeof(struct lpfc_scsi_buf *) * + phba->sli4_hba.scsi_xri_max), GFP_KERNEL); + + if (!phba->sli4_hba.lpfc_scsi_psb_array) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "2563 Failed to allocate memory for SCSI " + "XRI management array of size %d.\n", + phba->sli4_hba.scsi_xri_max); + kfree(phba->sli4_hba.lpfc_els_sgl_array); + return -ENOMEM; + } + + for (i = 0; i < els_xri_cnt; i++) { + sglq_entry = kzalloc(sizeof(struct lpfc_sglq), GFP_KERNEL); + if (sglq_entry == NULL) { + printk(KERN_ERR "%s: only allocated %d sgls of " + "expected %d count. Unloading driver.\n", + __func__, i, els_xri_cnt); + goto out_free_mem; + } + + sglq_entry->sli4_xritag = lpfc_sli4_next_xritag(phba); + if (sglq_entry->sli4_xritag == NO_XRI) { + kfree(sglq_entry); + printk(KERN_ERR "%s: failed to allocate XRI.\n" + "Unloading driver.\n", __func__); + goto out_free_mem; + } + sglq_entry->buff_type = GEN_BUFF_TYPE; + sglq_entry->virt = lpfc_mbuf_alloc(phba, 0, &sglq_entry->phys); + if (sglq_entry->virt == NULL) { + kfree(sglq_entry); + printk(KERN_ERR "%s: failed to allocate mbuf.\n" + "Unloading driver.\n", __func__); + goto out_free_mem; + } + sglq_entry->sgl = sglq_entry->virt; + memset(sglq_entry->sgl, 0, LPFC_BPL_SIZE); + + /* The list order is used by later block SGL registraton */ + spin_lock_irq(&phba->hbalock); + list_add_tail(&sglq_entry->list, &phba->sli4_hba.lpfc_sgl_list); + phba->sli4_hba.lpfc_els_sgl_array[i] = sglq_entry; + phba->sli4_hba.total_sglq_bufs++; + spin_unlock_irq(&phba->hbalock); + } + return 0; + +out_free_mem: + kfree(phba->sli4_hba.lpfc_scsi_psb_array); + lpfc_free_sgl_list(phba); + return -ENOMEM; +} + +/** + * lpfc_sli4_init_rpi_hdrs - Post the rpi header memory region to the port + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to post rpi header templates to the + * HBA consistent with the SLI-4 interface spec. This routine + * posts a PAGE_SIZE memory region to the port to hold up to + * PAGE_SIZE modulo 64 rpi context headers. + * No locks are held here because this is an initialization routine + * called only from probe or lpfc_online when interrupts are not + * enabled and the driver is reinitializing the device. + * + * Return codes + * 0 - sucessful + * ENOMEM - No availble memory + * EIO - The mailbox failed to complete successfully. + **/ +int +lpfc_sli4_init_rpi_hdrs(struct lpfc_hba *phba) +{ + int rc = 0; + int longs; + uint16_t rpi_count; + struct lpfc_rpi_hdr *rpi_hdr; + + INIT_LIST_HEAD(&phba->sli4_hba.lpfc_rpi_hdr_list); + + /* + * Provision an rpi bitmask range for discovery. The total count + * is the difference between max and base + 1. + */ + rpi_count = phba->sli4_hba.max_cfg_param.rpi_base + + phba->sli4_hba.max_cfg_param.max_rpi - 1; + + longs = ((rpi_count) + BITS_PER_LONG - 1) / BITS_PER_LONG; + phba->sli4_hba.rpi_bmask = kzalloc(longs * sizeof(unsigned long), + GFP_KERNEL); + if (!phba->sli4_hba.rpi_bmask) + return -ENOMEM; + + rpi_hdr = lpfc_sli4_create_rpi_hdr(phba); + if (!rpi_hdr) { + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + "0391 Error during rpi post operation\n"); + lpfc_sli4_remove_rpis(phba); + rc = -ENODEV; + } + + return rc; +} + +/** + * lpfc_sli4_create_rpi_hdr - Allocate an rpi header memory region + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to allocate a single 4KB memory region to + * support rpis and stores them in the phba. This single region + * provides support for up to 64 rpis. The region is used globally + * by the device. + * + * Returns: + * A valid rpi hdr on success. + * A NULL pointer on any failure. + **/ +struct lpfc_rpi_hdr * +lpfc_sli4_create_rpi_hdr(struct lpfc_hba *phba) +{ + uint16_t rpi_limit, curr_rpi_range; + struct lpfc_dmabuf *dmabuf; + struct lpfc_rpi_hdr *rpi_hdr; + + rpi_limit = phba->sli4_hba.max_cfg_param.rpi_base + + phba->sli4_hba.max_cfg_param.max_rpi - 1; + + spin_lock_irq(&phba->hbalock); + curr_rpi_range = phba->sli4_hba.next_rpi; + spin_unlock_irq(&phba->hbalock); + + /* + * The port has a limited number of rpis. The increment here + * is LPFC_RPI_HDR_COUNT - 1 to account for the starting value + * and to allow the full max_rpi range per port. + */ + if ((curr_rpi_range + (LPFC_RPI_HDR_COUNT - 1)) > rpi_limit) + return NULL; + + /* + * First allocate the protocol header region for the port. The + * port expects a 4KB DMA-mapped memory region that is 4K aligned. + */ + dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); + if (!dmabuf) + return NULL; + + dmabuf->virt = dma_alloc_coherent(&phba->pcidev->dev, + LPFC_HDR_TEMPLATE_SIZE, + &dmabuf->phys, + GFP_KERNEL); + if (!dmabuf->virt) { + rpi_hdr = NULL; + goto err_free_dmabuf; + } + + memset(dmabuf->virt, 0, LPFC_HDR_TEMPLATE_SIZE); + if (!IS_ALIGNED(dmabuf->phys, LPFC_HDR_TEMPLATE_SIZE)) { + rpi_hdr = NULL; + goto err_free_coherent; + } + + /* Save the rpi header data for cleanup later. */ + rpi_hdr = kzalloc(sizeof(struct lpfc_rpi_hdr), GFP_KERNEL); + if (!rpi_hdr) + goto err_free_coherent; + + rpi_hdr->dmabuf = dmabuf; + rpi_hdr->len = LPFC_HDR_TEMPLATE_SIZE; + rpi_hdr->page_count = 1; + spin_lock_irq(&phba->hbalock); + rpi_hdr->start_rpi = phba->sli4_hba.next_rpi; + list_add_tail(&rpi_hdr->list, &phba->sli4_hba.lpfc_rpi_hdr_list); + + /* + * The next_rpi stores the next module-64 rpi value to post + * in any subsequent rpi memory region postings. + */ + phba->sli4_hba.next_rpi += LPFC_RPI_HDR_COUNT; + spin_unlock_irq(&phba->hbalock); + return rpi_hdr; + + err_free_coherent: + dma_free_coherent(&phba->pcidev->dev, LPFC_HDR_TEMPLATE_SIZE, + dmabuf->virt, dmabuf->phys); + err_free_dmabuf: + kfree(dmabuf); + return NULL; +} + +/** + * lpfc_sli4_remove_rpi_hdrs - Remove all rpi header memory regions + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to remove all memory resources allocated + * to support rpis. This routine presumes the caller has released all + * rpis consumed by fabric or port logins and is prepared to have + * the header pages removed. + **/ +void +lpfc_sli4_remove_rpi_hdrs(struct lpfc_hba *phba) +{ + struct lpfc_rpi_hdr *rpi_hdr, *next_rpi_hdr; + + list_for_each_entry_safe(rpi_hdr, next_rpi_hdr, + &phba->sli4_hba.lpfc_rpi_hdr_list, list) { + list_del(&rpi_hdr->list); + dma_free_coherent(&phba->pcidev->dev, rpi_hdr->len, + rpi_hdr->dmabuf->virt, rpi_hdr->dmabuf->phys); + kfree(rpi_hdr->dmabuf); + kfree(rpi_hdr); + } + + phba->sli4_hba.next_rpi = phba->sli4_hba.max_cfg_param.rpi_base; + memset(phba->sli4_hba.rpi_bmask, 0, sizeof(*phba->sli4_hba.rpi_bmask)); +} + +/** + * lpfc_hba_alloc - Allocate driver hba data structure for a device. + * @pdev: pointer to pci device data structure. + * + * This routine is invoked to allocate the driver hba data structure for an + * HBA device. If the allocation is successful, the phba reference to the + * PCI device data structure is set. + * + * Return codes + * pointer to @phba - sucessful + * NULL - error + **/ +static struct lpfc_hba * +lpfc_hba_alloc(struct pci_dev *pdev) +{ + struct lpfc_hba *phba; + + /* Allocate memory for HBA structure */ + phba = kzalloc(sizeof(struct lpfc_hba), GFP_KERNEL); + if (!phba) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "1417 Failed to allocate hba struct.\n"); + return NULL; + } + + /* Set reference to PCI device in HBA structure */ + phba->pcidev = pdev; + + /* Assign an unused board number */ + phba->brd_no = lpfc_get_instance(); + if (phba->brd_no < 0) { + kfree(phba); + return NULL; + } + + return phba; +} + +/** + * lpfc_hba_free - Free driver hba data structure with a device. + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to free the driver hba data structure with an + * HBA device. + **/ +static void +lpfc_hba_free(struct lpfc_hba *phba) +{ + /* Release the driver assigned board number */ + idr_remove(&lpfc_hba_index, phba->brd_no); + + kfree(phba); + return; +} + +/** + * lpfc_create_shost - Create hba physical port with associated scsi host. + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to create HBA physical port and associate a SCSI + * host with it. + * + * Return codes + * 0 - sucessful + * other values - error + **/ +static int +lpfc_create_shost(struct lpfc_hba *phba) +{ + struct lpfc_vport *vport; + struct Scsi_Host *shost; + + /* Initialize HBA FC structure */ + phba->fc_edtov = FF_DEF_EDTOV; + phba->fc_ratov = FF_DEF_RATOV; + phba->fc_altov = FF_DEF_ALTOV; + phba->fc_arbtov = FF_DEF_ARBTOV; + + vport = lpfc_create_port(phba, phba->brd_no, &phba->pcidev->dev); + if (!vport) + return -ENODEV; + + shost = lpfc_shost_from_vport(vport); + phba->pport = vport; + lpfc_debugfs_initialize(vport); + /* Put reference to SCSI host to driver's device private data */ + pci_set_drvdata(phba->pcidev, shost); + + return 0; +} + +/** + * lpfc_destroy_shost - Destroy hba physical port with associated scsi host. + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to destroy HBA physical port and the associated + * SCSI host. + **/ +static void +lpfc_destroy_shost(struct lpfc_hba *phba) +{ + struct lpfc_vport *vport = phba->pport; + + /* Destroy physical port that associated with the SCSI host */ + destroy_port(vport); + + return; +} + +/** + * lpfc_setup_bg - Setup Block guard structures and debug areas. + * @phba: pointer to lpfc hba data structure. + * @shost: the shost to be used to detect Block guard settings. + * + * This routine sets up the local Block guard protocol settings for @shost. + * This routine also allocates memory for debugging bg buffers. + **/ +static void +lpfc_setup_bg(struct lpfc_hba *phba, struct Scsi_Host *shost) +{ + int pagecnt = 10; + if (lpfc_prot_mask && lpfc_prot_guard) { + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "1478 Registering BlockGuard with the " + "SCSI layer\n"); + scsi_host_set_prot(shost, lpfc_prot_mask); + scsi_host_set_guard(shost, lpfc_prot_guard); + } + if (!_dump_buf_data) { + while (pagecnt) { + spin_lock_init(&_dump_buf_lock); + _dump_buf_data = + (char *) __get_free_pages(GFP_KERNEL, pagecnt); + if (_dump_buf_data) { + printk(KERN_ERR "BLKGRD allocated %d pages for " + "_dump_buf_data at 0x%p\n", + (1 << pagecnt), _dump_buf_data); + _dump_buf_data_order = pagecnt; + memset(_dump_buf_data, 0, + ((1 << PAGE_SHIFT) << pagecnt)); + break; + } else + --pagecnt; + } + if (!_dump_buf_data_order) + printk(KERN_ERR "BLKGRD ERROR unable to allocate " + "memory for hexdump\n"); + } else + printk(KERN_ERR "BLKGRD already allocated _dump_buf_data=0x%p" + "\n", _dump_buf_data); + if (!_dump_buf_dif) { + while (pagecnt) { + _dump_buf_dif = + (char *) __get_free_pages(GFP_KERNEL, pagecnt); + if (_dump_buf_dif) { + printk(KERN_ERR "BLKGRD allocated %d pages for " + "_dump_buf_dif at 0x%p\n", + (1 << pagecnt), _dump_buf_dif); + _dump_buf_dif_order = pagecnt; + memset(_dump_buf_dif, 0, + ((1 << PAGE_SHIFT) << pagecnt)); + break; + } else + --pagecnt; + } + if (!_dump_buf_dif_order) + printk(KERN_ERR "BLKGRD ERROR unable to allocate " + "memory for hexdump\n"); + } else + printk(KERN_ERR "BLKGRD already allocated _dump_buf_dif=0x%p\n", + _dump_buf_dif); +} + +/** + * lpfc_post_init_setup - Perform necessary device post initialization setup. + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to perform all the necessary post initialization + * setup for the device. + **/ +static void +lpfc_post_init_setup(struct lpfc_hba *phba) +{ + struct Scsi_Host *shost; + struct lpfc_adapter_event_header adapter_event; + + /* Get the default values for Model Name and Description */ + lpfc_get_hba_model_desc(phba, phba->ModelName, phba->ModelDesc); + + /* + * hba setup may have changed the hba_queue_depth so we need to + * adjust the value of can_queue. + */ + shost = pci_get_drvdata(phba->pcidev); + shost->can_queue = phba->cfg_hba_queue_depth - 10; + if (phba->sli3_options & LPFC_SLI3_BG_ENABLED) + lpfc_setup_bg(phba, shost); + + lpfc_host_attrib_init(shost); + + if (phba->cfg_poll & DISABLE_FCP_RING_INT) { + spin_lock_irq(shost->host_lock); + lpfc_poll_start_timer(phba); + spin_unlock_irq(shost->host_lock); + } + + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "0428 Perform SCSI scan\n"); + /* Send board arrival event to upper layer */ + adapter_event.event_type = FC_REG_ADAPTER_EVENT; + adapter_event.subcategory = LPFC_EVENT_ARRIVAL; + fc_host_post_vendor_event(shost, fc_get_event_number(), + sizeof(adapter_event), + (char *) &adapter_event, + LPFC_NL_VENDOR_ID); + return; +} + +/** + * lpfc_sli_pci_mem_setup - Setup SLI3 HBA PCI memory space. + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to set up the PCI device memory space for device + * with SLI-3 interface spec. + * + * Return codes + * 0 - sucessful + * other values - error + **/ +static int +lpfc_sli_pci_mem_setup(struct lpfc_hba *phba) +{ + struct pci_dev *pdev; + unsigned long bar0map_len, bar2map_len; + int i, hbq_count; + void *ptr; + int error = -ENODEV; + + /* Obtain PCI device reference */ + if (!phba->pcidev) + return error; + else + pdev = phba->pcidev; + + /* Set the device DMA mask size */ + if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) != 0) + if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0) + return error; + + /* Get the bus address of Bar0 and Bar2 and the number of bytes + * required by each mapping. + */ + phba->pci_bar0_map = pci_resource_start(pdev, 0); + bar0map_len = pci_resource_len(pdev, 0); + + phba->pci_bar2_map = pci_resource_start(pdev, 2); + bar2map_len = pci_resource_len(pdev, 2); + + /* Map HBA SLIM to a kernel virtual address. */ + phba->slim_memmap_p = ioremap(phba->pci_bar0_map, bar0map_len); + if (!phba->slim_memmap_p) { + dev_printk(KERN_ERR, &pdev->dev, + "ioremap failed for SLIM memory.\n"); + goto out; + } + + /* Map HBA Control Registers to a kernel virtual address. */ + phba->ctrl_regs_memmap_p = ioremap(phba->pci_bar2_map, bar2map_len); + if (!phba->ctrl_regs_memmap_p) { + dev_printk(KERN_ERR, &pdev->dev, + "ioremap failed for HBA control registers.\n"); + goto out_iounmap_slim; + } + + /* Allocate memory for SLI-2 structures */ + phba->slim2p.virt = dma_alloc_coherent(&pdev->dev, + SLI2_SLIM_SIZE, + &phba->slim2p.phys, + GFP_KERNEL); + if (!phba->slim2p.virt) + goto out_iounmap; + + memset(phba->slim2p.virt, 0, SLI2_SLIM_SIZE); + phba->mbox = phba->slim2p.virt + offsetof(struct lpfc_sli2_slim, mbx); + phba->pcb = (phba->slim2p.virt + offsetof(struct lpfc_sli2_slim, pcb)); + phba->IOCBs = (phba->slim2p.virt + + offsetof(struct lpfc_sli2_slim, IOCBs)); + + phba->hbqslimp.virt = dma_alloc_coherent(&pdev->dev, + lpfc_sli_hbq_size(), + &phba->hbqslimp.phys, + GFP_KERNEL); + if (!phba->hbqslimp.virt) + goto out_free_slim; + + hbq_count = lpfc_sli_hbq_count(); + ptr = phba->hbqslimp.virt; + for (i = 0; i < hbq_count; ++i) { + phba->hbqs[i].hbq_virt = ptr; + INIT_LIST_HEAD(&phba->hbqs[i].hbq_buffer_list); + ptr += (lpfc_hbq_defs[i]->entry_count * + sizeof(struct lpfc_hbq_entry)); + } + phba->hbqs[LPFC_ELS_HBQ].hbq_alloc_buffer = lpfc_els_hbq_alloc; + phba->hbqs[LPFC_ELS_HBQ].hbq_free_buffer = lpfc_els_hbq_free; + + memset(phba->hbqslimp.virt, 0, lpfc_sli_hbq_size()); + + INIT_LIST_HEAD(&phba->rb_pend_list); + + phba->MBslimaddr = phba->slim_memmap_p; + phba->HAregaddr = phba->ctrl_regs_memmap_p + HA_REG_OFFSET; + phba->CAregaddr = phba->ctrl_regs_memmap_p + CA_REG_OFFSET; + phba->HSregaddr = phba->ctrl_regs_memmap_p + HS_REG_OFFSET; + phba->HCregaddr = phba->ctrl_regs_memmap_p + HC_REG_OFFSET; + + return 0; + +out_free_slim: + dma_free_coherent(&pdev->dev, SLI2_SLIM_SIZE, + phba->slim2p.virt, phba->slim2p.phys); +out_iounmap: + iounmap(phba->ctrl_regs_memmap_p); +out_iounmap_slim: + iounmap(phba->slim_memmap_p); +out: + return error; +} + +/** + * lpfc_sli_pci_mem_unset - Unset SLI3 HBA PCI memory space. + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to unset the PCI device memory space for device + * with SLI-3 interface spec. + **/ +static void +lpfc_sli_pci_mem_unset(struct lpfc_hba *phba) +{ + struct pci_dev *pdev; + + /* Obtain PCI device reference */ + if (!phba->pcidev) + return; + else + pdev = phba->pcidev; + + /* Free coherent DMA memory allocated */ + dma_free_coherent(&pdev->dev, lpfc_sli_hbq_size(), + phba->hbqslimp.virt, phba->hbqslimp.phys); + dma_free_coherent(&pdev->dev, SLI2_SLIM_SIZE, + phba->slim2p.virt, phba->slim2p.phys); + + /* I/O memory unmap */ + iounmap(phba->ctrl_regs_memmap_p); + iounmap(phba->slim_memmap_p); + + return; +} + +/** + * lpfc_sli4_post_status_check - Wait for SLI4 POST done and check status + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to wait for SLI4 device Power On Self Test (POST) + * done and check status. + * + * Return 0 if successful, otherwise -ENODEV. + **/ +int +lpfc_sli4_post_status_check(struct lpfc_hba *phba) +{ + struct lpfc_register sta_reg, uerrlo_reg, uerrhi_reg, scratchpad; + uint32_t onlnreg0, onlnreg1; + int i, port_error = -ENODEV; + + if (!phba->sli4_hba.STAregaddr) + return -ENODEV; + + /* With uncoverable error, log the error message and return error */ + onlnreg0 = readl(phba->sli4_hba.ONLINE0regaddr); + onlnreg1 = readl(phba->sli4_hba.ONLINE1regaddr); + if ((onlnreg0 != LPFC_ONLINE_NERR) || (onlnreg1 != LPFC_ONLINE_NERR)) { + uerrlo_reg.word0 = readl(phba->sli4_hba.UERRLOregaddr); + uerrhi_reg.word0 = readl(phba->sli4_hba.UERRHIregaddr); + if (uerrlo_reg.word0 || uerrhi_reg.word0) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "1422 HBA Unrecoverable error: " + "uerr_lo_reg=0x%x, uerr_hi_reg=0x%x, " + "online0_reg=0x%x, online1_reg=0x%x\n", + uerrlo_reg.word0, uerrhi_reg.word0, + onlnreg0, onlnreg1); + } + return -ENODEV; + } + + /* Wait up to 30 seconds for the SLI Port POST done and ready */ + for (i = 0; i < 3000; i++) { + sta_reg.word0 = readl(phba->sli4_hba.STAregaddr); + /* Encounter fatal POST error, break out */ + if (bf_get(lpfc_hst_state_perr, &sta_reg)) { + port_error = -ENODEV; + break; + } + if (LPFC_POST_STAGE_ARMFW_READY == + bf_get(lpfc_hst_state_port_status, &sta_reg)) { + port_error = 0; + break; + } + msleep(10); + } + + if (port_error) + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "1408 Failure HBA POST Status: sta_reg=0x%x, " + "perr=x%x, sfi=x%x, nip=x%x, ipc=x%x, xrom=x%x, " + "dl=x%x, pstatus=x%x\n", sta_reg.word0, + bf_get(lpfc_hst_state_perr, &sta_reg), + bf_get(lpfc_hst_state_sfi, &sta_reg), + bf_get(lpfc_hst_state_nip, &sta_reg), + bf_get(lpfc_hst_state_ipc, &sta_reg), + bf_get(lpfc_hst_state_xrom, &sta_reg), + bf_get(lpfc_hst_state_dl, &sta_reg), + bf_get(lpfc_hst_state_port_status, &sta_reg)); + + /* Log device information */ + scratchpad.word0 = readl(phba->sli4_hba.SCRATCHPADregaddr); + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "2534 Device Info: ChipType=0x%x, SliRev=0x%x, " + "FeatureL1=0x%x, FeatureL2=0x%x\n", + bf_get(lpfc_scratchpad_chiptype, &scratchpad), + bf_get(lpfc_scratchpad_slirev, &scratchpad), + bf_get(lpfc_scratchpad_featurelevel1, &scratchpad), + bf_get(lpfc_scratchpad_featurelevel2, &scratchpad)); + + return port_error; +} + +/** + * lpfc_sli4_bar0_register_memmap - Set up SLI4 BAR0 register memory map. + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to set up SLI4 BAR0 PCI config space register + * memory map. + **/ +static void +lpfc_sli4_bar0_register_memmap(struct lpfc_hba *phba) +{ + phba->sli4_hba.UERRLOregaddr = phba->sli4_hba.conf_regs_memmap_p + + LPFC_UERR_STATUS_LO; + phba->sli4_hba.UERRHIregaddr = phba->sli4_hba.conf_regs_memmap_p + + LPFC_UERR_STATUS_HI; + phba->sli4_hba.ONLINE0regaddr = phba->sli4_hba.conf_regs_memmap_p + + LPFC_ONLINE0; + phba->sli4_hba.ONLINE1regaddr = phba->sli4_hba.conf_regs_memmap_p + + LPFC_ONLINE1; + phba->sli4_hba.SCRATCHPADregaddr = phba->sli4_hba.conf_regs_memmap_p + + LPFC_SCRATCHPAD; +} + +/** + * lpfc_sli4_bar1_register_memmap - Set up SLI4 BAR1 register memory map. + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to set up SLI4 BAR1 control status register (CSR) + * memory map. + **/ +static void +lpfc_sli4_bar1_register_memmap(struct lpfc_hba *phba) +{ + + phba->sli4_hba.STAregaddr = phba->sli4_hba.ctrl_regs_memmap_p + + LPFC_HST_STATE; + phba->sli4_hba.ISRregaddr = phba->sli4_hba.ctrl_regs_memmap_p + + LPFC_HST_ISR0; + phba->sli4_hba.IMRregaddr = phba->sli4_hba.ctrl_regs_memmap_p + + LPFC_HST_IMR0; + phba->sli4_hba.ISCRregaddr = phba->sli4_hba.ctrl_regs_memmap_p + + LPFC_HST_ISCR0; + return; +} + +/** + * lpfc_sli4_bar2_register_memmap - Set up SLI4 BAR2 register memory map. + * @phba: pointer to lpfc hba data structure. + * @vf: virtual function number + * + * This routine is invoked to set up SLI4 BAR2 doorbell register memory map + * based on the given viftual function number, @vf. + * + * Return 0 if successful, otherwise -ENODEV. + **/ +static int +lpfc_sli4_bar2_register_memmap(struct lpfc_hba *phba, uint32_t vf) +{ + if (vf > LPFC_VIR_FUNC_MAX) + return -ENODEV; + + phba->sli4_hba.RQDBregaddr = (phba->sli4_hba.drbl_regs_memmap_p + + vf * LPFC_VFR_PAGE_SIZE + LPFC_RQ_DOORBELL); + phba->sli4_hba.WQDBregaddr = (phba->sli4_hba.drbl_regs_memmap_p + + vf * LPFC_VFR_PAGE_SIZE + LPFC_WQ_DOORBELL); + phba->sli4_hba.EQCQDBregaddr = (phba->sli4_hba.drbl_regs_memmap_p + + vf * LPFC_VFR_PAGE_SIZE + LPFC_EQCQ_DOORBELL); + phba->sli4_hba.MQDBregaddr = (phba->sli4_hba.drbl_regs_memmap_p + + vf * LPFC_VFR_PAGE_SIZE + LPFC_MQ_DOORBELL); + phba->sli4_hba.BMBXregaddr = (phba->sli4_hba.drbl_regs_memmap_p + + vf * LPFC_VFR_PAGE_SIZE + LPFC_BMBX); + return 0; +} + +/** + * lpfc_create_bootstrap_mbox - Create the bootstrap mailbox + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to create the bootstrap mailbox + * region consistent with the SLI-4 interface spec. This + * routine allocates all memory necessary to communicate + * mailbox commands to the port and sets up all alignment + * needs. No locks are expected to be held when calling + * this routine. + * + * Return codes + * 0 - sucessful + * ENOMEM - could not allocated memory. + **/ +static int +lpfc_create_bootstrap_mbox(struct lpfc_hba *phba) +{ + uint32_t bmbx_size; + struct lpfc_dmabuf *dmabuf; + struct dma_address *dma_address; + uint32_t pa_addr; + uint64_t phys_addr; + + dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); + if (!dmabuf) + return -ENOMEM; + + /* + * The bootstrap mailbox region is comprised of 2 parts + * plus an alignment restriction of 16 bytes. + */ + bmbx_size = sizeof(struct lpfc_bmbx_create) + (LPFC_ALIGN_16_BYTE - 1); + dmabuf->virt = dma_alloc_coherent(&phba->pcidev->dev, + bmbx_size, + &dmabuf->phys, + GFP_KERNEL); + if (!dmabuf->virt) { + kfree(dmabuf); + return -ENOMEM; + } + memset(dmabuf->virt, 0, bmbx_size); + + /* + * Initialize the bootstrap mailbox pointers now so that the register + * operations are simple later. The mailbox dma address is required + * to be 16-byte aligned. Also align the virtual memory as each + * maibox is copied into the bmbx mailbox region before issuing the + * command to the port. + */ + phba->sli4_hba.bmbx.dmabuf = dmabuf; + phba->sli4_hba.bmbx.bmbx_size = bmbx_size; + + phba->sli4_hba.bmbx.avirt = PTR_ALIGN(dmabuf->virt, + LPFC_ALIGN_16_BYTE); + phba->sli4_hba.bmbx.aphys = ALIGN(dmabuf->phys, + LPFC_ALIGN_16_BYTE); + + /* + * Set the high and low physical addresses now. The SLI4 alignment + * requirement is 16 bytes and the mailbox is posted to the port + * as two 30-bit addresses. The other data is a bit marking whether + * the 30-bit address is the high or low address. + * Upcast bmbx aphys to 64bits so shift instruction compiles + * clean on 32 bit machines. + */ + dma_address = &phba->sli4_hba.bmbx.dma_address; + phys_addr = (uint64_t)phba->sli4_hba.bmbx.aphys; + pa_addr = (uint32_t) ((phys_addr >> 34) & 0x3fffffff); + dma_address->addr_hi = (uint32_t) ((pa_addr << 2) | + LPFC_BMBX_BIT1_ADDR_HI); + + pa_addr = (uint32_t) ((phba->sli4_hba.bmbx.aphys >> 4) & 0x3fffffff); + dma_address->addr_lo = (uint32_t) ((pa_addr << 2) | + LPFC_BMBX_BIT1_ADDR_LO); + return 0; +} + +/** + * lpfc_destroy_bootstrap_mbox - Destroy all bootstrap mailbox resources + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to teardown the bootstrap mailbox + * region and release all host resources. This routine requires + * the caller to ensure all mailbox commands recovered, no + * additional mailbox comands are sent, and interrupts are disabled + * before calling this routine. + * + **/ +static void +lpfc_destroy_bootstrap_mbox(struct lpfc_hba *phba) +{ + dma_free_coherent(&phba->pcidev->dev, + phba->sli4_hba.bmbx.bmbx_size, + phba->sli4_hba.bmbx.dmabuf->virt, + phba->sli4_hba.bmbx.dmabuf->phys); + + kfree(phba->sli4_hba.bmbx.dmabuf); + memset(&phba->sli4_hba.bmbx, 0, sizeof(struct lpfc_bmbx)); +} + +/** + * lpfc_sli4_read_config - Get the config parameters. + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to read the configuration parameters from the HBA. + * The configuration parameters are used to set the base and maximum values + * for RPI's XRI's VPI's VFI's and FCFIs. These values also affect the resource + * allocation for the port. + * + * Return codes + * 0 - sucessful + * ENOMEM - No availble memory + * EIO - The mailbox failed to complete successfully. + **/ +static int +lpfc_sli4_read_config(struct lpfc_hba *phba) +{ + LPFC_MBOXQ_t *pmb; + struct lpfc_mbx_read_config *rd_config; + uint32_t rc = 0; + + pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!pmb) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "2011 Unable to allocate memory for issuing " + "SLI_CONFIG_SPECIAL mailbox command\n"); + return -ENOMEM; + } + + lpfc_read_config(phba, pmb); + + rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL); + if (rc != MBX_SUCCESS) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "2012 Mailbox failed , mbxCmd x%x " + "READ_CONFIG, mbxStatus x%x\n", + bf_get(lpfc_mqe_command, &pmb->u.mqe), + bf_get(lpfc_mqe_status, &pmb->u.mqe)); + rc = -EIO; + } else { + rd_config = &pmb->u.mqe.un.rd_config; + phba->sli4_hba.max_cfg_param.max_xri = + bf_get(lpfc_mbx_rd_conf_xri_count, rd_config); + phba->sli4_hba.max_cfg_param.xri_base = + bf_get(lpfc_mbx_rd_conf_xri_base, rd_config); + phba->sli4_hba.max_cfg_param.max_vpi = + bf_get(lpfc_mbx_rd_conf_vpi_count, rd_config); + phba->sli4_hba.max_cfg_param.vpi_base = + bf_get(lpfc_mbx_rd_conf_vpi_base, rd_config); + phba->sli4_hba.max_cfg_param.max_rpi = + bf_get(lpfc_mbx_rd_conf_rpi_count, rd_config); + phba->sli4_hba.max_cfg_param.rpi_base = + bf_get(lpfc_mbx_rd_conf_rpi_base, rd_config); + phba->sli4_hba.max_cfg_param.max_vfi = + bf_get(lpfc_mbx_rd_conf_vfi_count, rd_config); + phba->sli4_hba.max_cfg_param.vfi_base = + bf_get(lpfc_mbx_rd_conf_vfi_base, rd_config); + phba->sli4_hba.max_cfg_param.max_fcfi = + bf_get(lpfc_mbx_rd_conf_fcfi_count, rd_config); + phba->sli4_hba.max_cfg_param.fcfi_base = + bf_get(lpfc_mbx_rd_conf_fcfi_base, rd_config); + phba->sli4_hba.max_cfg_param.max_eq = + bf_get(lpfc_mbx_rd_conf_eq_count, rd_config); + phba->sli4_hba.max_cfg_param.max_rq = + bf_get(lpfc_mbx_rd_conf_rq_count, rd_config); + phba->sli4_hba.max_cfg_param.max_wq = + bf_get(lpfc_mbx_rd_conf_wq_count, rd_config); + phba->sli4_hba.max_cfg_param.max_cq = + bf_get(lpfc_mbx_rd_conf_cq_count, rd_config); + phba->lmt = bf_get(lpfc_mbx_rd_conf_lmt, rd_config); + phba->sli4_hba.next_xri = phba->sli4_hba.max_cfg_param.xri_base; + phba->vpi_base = phba->sli4_hba.max_cfg_param.vpi_base; + phba->vfi_base = phba->sli4_hba.max_cfg_param.vfi_base; + phba->sli4_hba.next_rpi = phba->sli4_hba.max_cfg_param.rpi_base; + phba->max_vpi = phba->sli4_hba.max_cfg_param.max_vpi; + phba->max_vports = phba->max_vpi; + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "2003 cfg params XRI(B:%d M:%d), " + "VPI(B:%d M:%d) " + "VFI(B:%d M:%d) " + "RPI(B:%d M:%d) " + "FCFI(B:%d M:%d)\n", + phba->sli4_hba.max_cfg_param.xri_base, + phba->sli4_hba.max_cfg_param.max_xri, + phba->sli4_hba.max_cfg_param.vpi_base, + phba->sli4_hba.max_cfg_param.max_vpi, + phba->sli4_hba.max_cfg_param.vfi_base, + phba->sli4_hba.max_cfg_param.max_vfi, + phba->sli4_hba.max_cfg_param.rpi_base, + phba->sli4_hba.max_cfg_param.max_rpi, + phba->sli4_hba.max_cfg_param.fcfi_base, + phba->sli4_hba.max_cfg_param.max_fcfi); + } + mempool_free(pmb, phba->mbox_mem_pool); + + /* Reset the DFT_HBA_Q_DEPTH to the max xri */ + if (phba->cfg_hba_queue_depth > (phba->sli4_hba.max_cfg_param.max_xri)) + phba->cfg_hba_queue_depth = + phba->sli4_hba.max_cfg_param.max_xri; + return rc; +} + +/** + * lpfc_dev_endian_order_setup - Notify the port of the host's endian order. + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to setup the host-side endian order to the + * HBA consistent with the SLI-4 interface spec. + * + * Return codes + * 0 - sucessful + * ENOMEM - No availble memory + * EIO - The mailbox failed to complete successfully. + **/ +static int +lpfc_setup_endian_order(struct lpfc_hba *phba) +{ + LPFC_MBOXQ_t *mboxq; + uint32_t rc = 0; + uint32_t endian_mb_data[2] = {HOST_ENDIAN_LOW_WORD0, + HOST_ENDIAN_HIGH_WORD1}; + + mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mboxq) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0492 Unable to allocate memory for issuing " + "SLI_CONFIG_SPECIAL mailbox command\n"); + return -ENOMEM; + } + + /* + * The SLI4_CONFIG_SPECIAL mailbox command requires the first two + * words to contain special data values and no other data. + */ + memset(mboxq, 0, sizeof(LPFC_MBOXQ_t)); + memcpy(&mboxq->u.mqe, &endian_mb_data, sizeof(endian_mb_data)); + rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); + if (rc != MBX_SUCCESS) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0493 SLI_CONFIG_SPECIAL mailbox failed with " + "status x%x\n", + rc); + rc = -EIO; + } + + mempool_free(mboxq, phba->mbox_mem_pool); + return rc; +} + +/** + * lpfc_sli4_queue_create - Create all the SLI4 queues + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to allocate all the SLI4 queues for the FCoE HBA + * operation. For each SLI4 queue type, the parameters such as queue entry + * count (queue depth) shall be taken from the module parameter. For now, + * we just use some constant number as place holder. + * + * Return codes + * 0 - sucessful + * ENOMEM - No availble memory + * EIO - The mailbox failed to complete successfully. + **/ +static int +lpfc_sli4_queue_create(struct lpfc_hba *phba) +{ + struct lpfc_queue *qdesc; + int fcp_eqidx, fcp_cqidx, fcp_wqidx; + int cfg_fcp_wq_count; + int cfg_fcp_eq_count; + + /* + * Sanity check for confiugred queue parameters against the run-time + * device parameters + */ + + /* Sanity check on FCP fast-path WQ parameters */ + cfg_fcp_wq_count = phba->cfg_fcp_wq_count; + if (cfg_fcp_wq_count > + (phba->sli4_hba.max_cfg_param.max_wq - LPFC_SP_WQN_DEF)) { + cfg_fcp_wq_count = phba->sli4_hba.max_cfg_param.max_wq - + LPFC_SP_WQN_DEF; + if (cfg_fcp_wq_count < LPFC_FP_WQN_MIN) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2581 Not enough WQs (%d) from " + "the pci function for supporting " + "FCP WQs (%d)\n", + phba->sli4_hba.max_cfg_param.max_wq, + phba->cfg_fcp_wq_count); + goto out_error; + } + lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, + "2582 Not enough WQs (%d) from the pci " + "function for supporting the requested " + "FCP WQs (%d), the actual FCP WQs can " + "be supported: %d\n", + phba->sli4_hba.max_cfg_param.max_wq, + phba->cfg_fcp_wq_count, cfg_fcp_wq_count); + } + /* The actual number of FCP work queues adopted */ + phba->cfg_fcp_wq_count = cfg_fcp_wq_count; + + /* Sanity check on FCP fast-path EQ parameters */ + cfg_fcp_eq_count = phba->cfg_fcp_eq_count; + if (cfg_fcp_eq_count > + (phba->sli4_hba.max_cfg_param.max_eq - LPFC_SP_EQN_DEF)) { + cfg_fcp_eq_count = phba->sli4_hba.max_cfg_param.max_eq - + LPFC_SP_EQN_DEF; + if (cfg_fcp_eq_count < LPFC_FP_EQN_MIN) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2574 Not enough EQs (%d) from the " + "pci function for supporting FCP " + "EQs (%d)\n", + phba->sli4_hba.max_cfg_param.max_eq, + phba->cfg_fcp_eq_count); + goto out_error; + } + lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, + "2575 Not enough EQs (%d) from the pci " + "function for supporting the requested " + "FCP EQs (%d), the actual FCP EQs can " + "be supported: %d\n", + phba->sli4_hba.max_cfg_param.max_eq, + phba->cfg_fcp_eq_count, cfg_fcp_eq_count); + } + /* It does not make sense to have more EQs than WQs */ + if (cfg_fcp_eq_count > phba->cfg_fcp_wq_count) { + lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, + "2593 The number of FCP EQs (%d) is more " + "than the number of FCP WQs (%d), take " + "the number of FCP EQs same as than of " + "WQs (%d)\n", cfg_fcp_eq_count, + phba->cfg_fcp_wq_count, + phba->cfg_fcp_wq_count); + cfg_fcp_eq_count = phba->cfg_fcp_wq_count; + } + /* The actual number of FCP event queues adopted */ + phba->cfg_fcp_eq_count = cfg_fcp_eq_count; + /* The overall number of event queues used */ + phba->sli4_hba.cfg_eqn = phba->cfg_fcp_eq_count + LPFC_SP_EQN_DEF; + + /* + * Create Event Queues (EQs) + */ + + /* Get EQ depth from module parameter, fake the default for now */ + phba->sli4_hba.eq_esize = LPFC_EQE_SIZE_4B; + phba->sli4_hba.eq_ecount = LPFC_EQE_DEF_COUNT; + + /* Create slow path event queue */ + qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.eq_esize, + phba->sli4_hba.eq_ecount); + if (!qdesc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0496 Failed allocate slow-path EQ\n"); + goto out_error; + } + phba->sli4_hba.sp_eq = qdesc; + + /* Create fast-path FCP Event Queue(s) */ + phba->sli4_hba.fp_eq = kzalloc((sizeof(struct lpfc_queue *) * + phba->cfg_fcp_eq_count), GFP_KERNEL); + if (!phba->sli4_hba.fp_eq) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2576 Failed allocate memory for fast-path " + "EQ record array\n"); + goto out_free_sp_eq; + } + for (fcp_eqidx = 0; fcp_eqidx < phba->cfg_fcp_eq_count; fcp_eqidx++) { + qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.eq_esize, + phba->sli4_hba.eq_ecount); + if (!qdesc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0497 Failed allocate fast-path EQ\n"); + goto out_free_fp_eq; + } + phba->sli4_hba.fp_eq[fcp_eqidx] = qdesc; + } + + /* + * Create Complete Queues (CQs) + */ + + /* Get CQ depth from module parameter, fake the default for now */ + phba->sli4_hba.cq_esize = LPFC_CQE_SIZE; + phba->sli4_hba.cq_ecount = LPFC_CQE_DEF_COUNT; + + /* Create slow-path Mailbox Command Complete Queue */ + qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.cq_esize, + phba->sli4_hba.cq_ecount); + if (!qdesc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0500 Failed allocate slow-path mailbox CQ\n"); + goto out_free_fp_eq; + } + phba->sli4_hba.mbx_cq = qdesc; + + /* Create slow-path ELS Complete Queue */ + qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.cq_esize, + phba->sli4_hba.cq_ecount); + if (!qdesc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0501 Failed allocate slow-path ELS CQ\n"); + goto out_free_mbx_cq; + } + phba->sli4_hba.els_cq = qdesc; + + /* Create slow-path Unsolicited Receive Complete Queue */ + qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.cq_esize, + phba->sli4_hba.cq_ecount); + if (!qdesc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0502 Failed allocate slow-path USOL RX CQ\n"); + goto out_free_els_cq; + } + phba->sli4_hba.rxq_cq = qdesc; + + /* Create fast-path FCP Completion Queue(s), one-to-one with EQs */ + phba->sli4_hba.fcp_cq = kzalloc((sizeof(struct lpfc_queue *) * + phba->cfg_fcp_eq_count), GFP_KERNEL); + if (!phba->sli4_hba.fcp_cq) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2577 Failed allocate memory for fast-path " + "CQ record array\n"); + goto out_free_rxq_cq; + } + for (fcp_cqidx = 0; fcp_cqidx < phba->cfg_fcp_eq_count; fcp_cqidx++) { + qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.cq_esize, + phba->sli4_hba.cq_ecount); + if (!qdesc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0499 Failed allocate fast-path FCP " + "CQ (%d)\n", fcp_cqidx); + goto out_free_fcp_cq; + } + phba->sli4_hba.fcp_cq[fcp_cqidx] = qdesc; + } + + /* Create Mailbox Command Queue */ + phba->sli4_hba.mq_esize = LPFC_MQE_SIZE; + phba->sli4_hba.mq_ecount = LPFC_MQE_DEF_COUNT; + + qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.mq_esize, + phba->sli4_hba.mq_ecount); + if (!qdesc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0505 Failed allocate slow-path MQ\n"); + goto out_free_fcp_cq; + } + phba->sli4_hba.mbx_wq = qdesc; + + /* + * Create all the Work Queues (WQs) + */ + phba->sli4_hba.wq_esize = LPFC_WQE_SIZE; + phba->sli4_hba.wq_ecount = LPFC_WQE_DEF_COUNT; + + /* Create slow-path ELS Work Queue */ + qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.wq_esize, + phba->sli4_hba.wq_ecount); + if (!qdesc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0504 Failed allocate slow-path ELS WQ\n"); + goto out_free_mbx_wq; + } + phba->sli4_hba.els_wq = qdesc; + + /* Create fast-path FCP Work Queue(s) */ + phba->sli4_hba.fcp_wq = kzalloc((sizeof(struct lpfc_queue *) * + phba->cfg_fcp_wq_count), GFP_KERNEL); + if (!phba->sli4_hba.fcp_wq) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2578 Failed allocate memory for fast-path " + "WQ record array\n"); + goto out_free_els_wq; + } + for (fcp_wqidx = 0; fcp_wqidx < phba->cfg_fcp_wq_count; fcp_wqidx++) { + qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.wq_esize, + phba->sli4_hba.wq_ecount); + if (!qdesc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0503 Failed allocate fast-path FCP " + "WQ (%d)\n", fcp_wqidx); + goto out_free_fcp_wq; + } + phba->sli4_hba.fcp_wq[fcp_wqidx] = qdesc; + } + + /* + * Create Receive Queue (RQ) + */ + phba->sli4_hba.rq_esize = LPFC_RQE_SIZE; + phba->sli4_hba.rq_ecount = LPFC_RQE_DEF_COUNT; + + /* Create Receive Queue for header */ + qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.rq_esize, + phba->sli4_hba.rq_ecount); + if (!qdesc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0506 Failed allocate receive HRQ\n"); + goto out_free_fcp_wq; + } + phba->sli4_hba.hdr_rq = qdesc; + + /* Create Receive Queue for data */ + qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.rq_esize, + phba->sli4_hba.rq_ecount); + if (!qdesc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0507 Failed allocate receive DRQ\n"); + goto out_free_hdr_rq; + } + phba->sli4_hba.dat_rq = qdesc; + + return 0; + +out_free_hdr_rq: + lpfc_sli4_queue_free(phba->sli4_hba.hdr_rq); + phba->sli4_hba.hdr_rq = NULL; +out_free_fcp_wq: + for (--fcp_wqidx; fcp_wqidx >= 0; fcp_wqidx--) { + lpfc_sli4_queue_free(phba->sli4_hba.fcp_wq[fcp_wqidx]); + phba->sli4_hba.fcp_wq[fcp_wqidx] = NULL; + } + kfree(phba->sli4_hba.fcp_wq); +out_free_els_wq: + lpfc_sli4_queue_free(phba->sli4_hba.els_wq); + phba->sli4_hba.els_wq = NULL; +out_free_mbx_wq: + lpfc_sli4_queue_free(phba->sli4_hba.mbx_wq); + phba->sli4_hba.mbx_wq = NULL; +out_free_fcp_cq: + for (--fcp_cqidx; fcp_cqidx >= 0; fcp_cqidx--) { + lpfc_sli4_queue_free(phba->sli4_hba.fcp_cq[fcp_cqidx]); + phba->sli4_hba.fcp_cq[fcp_cqidx] = NULL; + } + kfree(phba->sli4_hba.fcp_cq); +out_free_rxq_cq: + lpfc_sli4_queue_free(phba->sli4_hba.rxq_cq); + phba->sli4_hba.rxq_cq = NULL; +out_free_els_cq: + lpfc_sli4_queue_free(phba->sli4_hba.els_cq); + phba->sli4_hba.els_cq = NULL; +out_free_mbx_cq: + lpfc_sli4_queue_free(phba->sli4_hba.mbx_cq); + phba->sli4_hba.mbx_cq = NULL; +out_free_fp_eq: + for (--fcp_eqidx; fcp_eqidx >= 0; fcp_eqidx--) { + lpfc_sli4_queue_free(phba->sli4_hba.fp_eq[fcp_eqidx]); + phba->sli4_hba.fp_eq[fcp_eqidx] = NULL; + } + kfree(phba->sli4_hba.fp_eq); +out_free_sp_eq: + lpfc_sli4_queue_free(phba->sli4_hba.sp_eq); + phba->sli4_hba.sp_eq = NULL; +out_error: + return -ENOMEM; +} + +/** + * lpfc_sli4_queue_destroy - Destroy all the SLI4 queues + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to release all the SLI4 queues with the FCoE HBA + * operation. + * + * Return codes + * 0 - sucessful + * ENOMEM - No availble memory + * EIO - The mailbox failed to complete successfully. + **/ +static void +lpfc_sli4_queue_destroy(struct lpfc_hba *phba) +{ + int fcp_qidx; + + /* Release mailbox command work queue */ + lpfc_sli4_queue_free(phba->sli4_hba.mbx_wq); + phba->sli4_hba.mbx_wq = NULL; + + /* Release ELS work queue */ + lpfc_sli4_queue_free(phba->sli4_hba.els_wq); + phba->sli4_hba.els_wq = NULL; + + /* Release FCP work queue */ + for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_wq_count; fcp_qidx++) + lpfc_sli4_queue_free(phba->sli4_hba.fcp_wq[fcp_qidx]); + kfree(phba->sli4_hba.fcp_wq); + phba->sli4_hba.fcp_wq = NULL; + + /* Release unsolicited receive queue */ + lpfc_sli4_queue_free(phba->sli4_hba.hdr_rq); + phba->sli4_hba.hdr_rq = NULL; + lpfc_sli4_queue_free(phba->sli4_hba.dat_rq); + phba->sli4_hba.dat_rq = NULL; + + /* Release unsolicited receive complete queue */ + lpfc_sli4_queue_free(phba->sli4_hba.rxq_cq); + phba->sli4_hba.rxq_cq = NULL; + + /* Release ELS complete queue */ + lpfc_sli4_queue_free(phba->sli4_hba.els_cq); + phba->sli4_hba.els_cq = NULL; + + /* Release mailbox command complete queue */ + lpfc_sli4_queue_free(phba->sli4_hba.mbx_cq); + phba->sli4_hba.mbx_cq = NULL; + + /* Release FCP response complete queue */ + for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_eq_count; fcp_qidx++) + lpfc_sli4_queue_free(phba->sli4_hba.fcp_cq[fcp_qidx]); + kfree(phba->sli4_hba.fcp_cq); + phba->sli4_hba.fcp_cq = NULL; + + /* Release fast-path event queue */ + for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_eq_count; fcp_qidx++) + lpfc_sli4_queue_free(phba->sli4_hba.fp_eq[fcp_qidx]); + kfree(phba->sli4_hba.fp_eq); + phba->sli4_hba.fp_eq = NULL; + + /* Release slow-path event queue */ + lpfc_sli4_queue_free(phba->sli4_hba.sp_eq); + phba->sli4_hba.sp_eq = NULL; + + return; +} + +/** + * lpfc_sli4_queue_setup - Set up all the SLI4 queues + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to set up all the SLI4 queues for the FCoE HBA + * operation. + * + * Return codes + * 0 - sucessful + * ENOMEM - No availble memory + * EIO - The mailbox failed to complete successfully. + **/ +int +lpfc_sli4_queue_setup(struct lpfc_hba *phba) +{ + int rc = -ENOMEM; + int fcp_eqidx, fcp_cqidx, fcp_wqidx; + int fcp_cq_index = 0; + + /* + * Set up Event Queues (EQs) + */ + + /* Set up slow-path event queue */ + if (!phba->sli4_hba.sp_eq) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0520 Slow-path EQ not allocated\n"); + goto out_error; + } + rc = lpfc_eq_create(phba, phba->sli4_hba.sp_eq, + LPFC_SP_DEF_IMAX); + if (rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0521 Failed setup of slow-path EQ: " + "rc = 0x%x\n", rc); + goto out_error; + } + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "2583 Slow-path EQ setup: queue-id=%d\n", + phba->sli4_hba.sp_eq->queue_id); + + /* Set up fast-path event queue */ + for (fcp_eqidx = 0; fcp_eqidx < phba->cfg_fcp_eq_count; fcp_eqidx++) { + if (!phba->sli4_hba.fp_eq[fcp_eqidx]) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0522 Fast-path EQ (%d) not " + "allocated\n", fcp_eqidx); + goto out_destroy_fp_eq; + } + rc = lpfc_eq_create(phba, phba->sli4_hba.fp_eq[fcp_eqidx], + phba->cfg_fcp_imax); + if (rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0523 Failed setup of fast-path EQ " + "(%d), rc = 0x%x\n", fcp_eqidx, rc); + goto out_destroy_fp_eq; + } + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "2584 Fast-path EQ setup: " + "queue[%d]-id=%d\n", fcp_eqidx, + phba->sli4_hba.fp_eq[fcp_eqidx]->queue_id); + } + + /* + * Set up Complete Queues (CQs) + */ + + /* Set up slow-path MBOX Complete Queue as the first CQ */ + if (!phba->sli4_hba.mbx_cq) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0528 Mailbox CQ not allocated\n"); + goto out_destroy_fp_eq; + } + rc = lpfc_cq_create(phba, phba->sli4_hba.mbx_cq, phba->sli4_hba.sp_eq, + LPFC_MCQ, LPFC_MBOX); + if (rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0529 Failed setup of slow-path mailbox CQ: " + "rc = 0x%x\n", rc); + goto out_destroy_fp_eq; + } + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "2585 MBX CQ setup: cq-id=%d, parent eq-id=%d\n", + phba->sli4_hba.mbx_cq->queue_id, + phba->sli4_hba.sp_eq->queue_id); + + /* Set up slow-path ELS Complete Queue */ + if (!phba->sli4_hba.els_cq) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0530 ELS CQ not allocated\n"); + goto out_destroy_mbx_cq; + } + rc = lpfc_cq_create(phba, phba->sli4_hba.els_cq, phba->sli4_hba.sp_eq, + LPFC_WCQ, LPFC_ELS); + if (rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0531 Failed setup of slow-path ELS CQ: " + "rc = 0x%x\n", rc); + goto out_destroy_mbx_cq; + } + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "2586 ELS CQ setup: cq-id=%d, parent eq-id=%d\n", + phba->sli4_hba.els_cq->queue_id, + phba->sli4_hba.sp_eq->queue_id); + + /* Set up slow-path Unsolicited Receive Complete Queue */ + if (!phba->sli4_hba.rxq_cq) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0532 USOL RX CQ not allocated\n"); + goto out_destroy_els_cq; + } + rc = lpfc_cq_create(phba, phba->sli4_hba.rxq_cq, phba->sli4_hba.sp_eq, + LPFC_RCQ, LPFC_USOL); + if (rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0533 Failed setup of slow-path USOL RX CQ: " + "rc = 0x%x\n", rc); + goto out_destroy_els_cq; + } + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "2587 USL CQ setup: cq-id=%d, parent eq-id=%d\n", + phba->sli4_hba.rxq_cq->queue_id, + phba->sli4_hba.sp_eq->queue_id); + + /* Set up fast-path FCP Response Complete Queue */ + for (fcp_cqidx = 0; fcp_cqidx < phba->cfg_fcp_eq_count; fcp_cqidx++) { + if (!phba->sli4_hba.fcp_cq[fcp_cqidx]) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0526 Fast-path FCP CQ (%d) not " + "allocated\n", fcp_cqidx); + goto out_destroy_fcp_cq; + } + rc = lpfc_cq_create(phba, phba->sli4_hba.fcp_cq[fcp_cqidx], + phba->sli4_hba.fp_eq[fcp_cqidx], + LPFC_WCQ, LPFC_FCP); + if (rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0527 Failed setup of fast-path FCP " + "CQ (%d), rc = 0x%x\n", fcp_cqidx, rc); + goto out_destroy_fcp_cq; + } + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "2588 FCP CQ setup: cq[%d]-id=%d, " + "parent eq[%d]-id=%d\n", + fcp_cqidx, + phba->sli4_hba.fcp_cq[fcp_cqidx]->queue_id, + fcp_cqidx, + phba->sli4_hba.fp_eq[fcp_cqidx]->queue_id); + } + + /* + * Set up all the Work Queues (WQs) + */ + + /* Set up Mailbox Command Queue */ + if (!phba->sli4_hba.mbx_wq) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0538 Slow-path MQ not allocated\n"); + goto out_destroy_fcp_cq; + } + rc = lpfc_mq_create(phba, phba->sli4_hba.mbx_wq, + phba->sli4_hba.mbx_cq, LPFC_MBOX); + if (rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0539 Failed setup of slow-path MQ: " + "rc = 0x%x\n", rc); + goto out_destroy_fcp_cq; + } + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "2589 MBX MQ setup: wq-id=%d, parent cq-id=%d\n", + phba->sli4_hba.mbx_wq->queue_id, + phba->sli4_hba.mbx_cq->queue_id); + + /* Set up slow-path ELS Work Queue */ + if (!phba->sli4_hba.els_wq) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0536 Slow-path ELS WQ not allocated\n"); + goto out_destroy_mbx_wq; + } + rc = lpfc_wq_create(phba, phba->sli4_hba.els_wq, + phba->sli4_hba.els_cq, LPFC_ELS); + if (rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0537 Failed setup of slow-path ELS WQ: " + "rc = 0x%x\n", rc); + goto out_destroy_mbx_wq; + } + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "2590 ELS WQ setup: wq-id=%d, parent cq-id=%d\n", + phba->sli4_hba.els_wq->queue_id, + phba->sli4_hba.els_cq->queue_id); + + /* Set up fast-path FCP Work Queue */ + for (fcp_wqidx = 0; fcp_wqidx < phba->cfg_fcp_wq_count; fcp_wqidx++) { + if (!phba->sli4_hba.fcp_wq[fcp_wqidx]) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0534 Fast-path FCP WQ (%d) not " + "allocated\n", fcp_wqidx); + goto out_destroy_fcp_wq; + } + rc = lpfc_wq_create(phba, phba->sli4_hba.fcp_wq[fcp_wqidx], + phba->sli4_hba.fcp_cq[fcp_cq_index], + LPFC_FCP); + if (rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0535 Failed setup of fast-path FCP " + "WQ (%d), rc = 0x%x\n", fcp_wqidx, rc); + goto out_destroy_fcp_wq; + } + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "2591 FCP WQ setup: wq[%d]-id=%d, " + "parent cq[%d]-id=%d\n", + fcp_wqidx, + phba->sli4_hba.fcp_wq[fcp_wqidx]->queue_id, + fcp_cq_index, + phba->sli4_hba.fcp_cq[fcp_cq_index]->queue_id); + /* Round robin FCP Work Queue's Completion Queue assignment */ + fcp_cq_index = ((fcp_cq_index + 1) % phba->cfg_fcp_eq_count); + } + + /* + * Create Receive Queue (RQ) + */ + if (!phba->sli4_hba.hdr_rq || !phba->sli4_hba.dat_rq) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0540 Receive Queue not allocated\n"); + goto out_destroy_fcp_wq; + } + rc = lpfc_rq_create(phba, phba->sli4_hba.hdr_rq, phba->sli4_hba.dat_rq, + phba->sli4_hba.rxq_cq, LPFC_USOL); + if (rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0541 Failed setup of Receive Queue: " + "rc = 0x%x\n", rc); + goto out_destroy_fcp_wq; + } + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "2592 USL RQ setup: hdr-rq-id=%d, dat-rq-id=%d " + "parent cq-id=%d\n", + phba->sli4_hba.hdr_rq->queue_id, + phba->sli4_hba.dat_rq->queue_id, + phba->sli4_hba.rxq_cq->queue_id); + return 0; + +out_destroy_fcp_wq: + for (--fcp_wqidx; fcp_wqidx >= 0; fcp_wqidx--) + lpfc_wq_destroy(phba, phba->sli4_hba.fcp_wq[fcp_wqidx]); + lpfc_wq_destroy(phba, phba->sli4_hba.els_wq); +out_destroy_mbx_wq: + lpfc_mq_destroy(phba, phba->sli4_hba.mbx_wq); +out_destroy_fcp_cq: + for (--fcp_cqidx; fcp_cqidx >= 0; fcp_cqidx--) + lpfc_cq_destroy(phba, phba->sli4_hba.fcp_cq[fcp_cqidx]); + lpfc_cq_destroy(phba, phba->sli4_hba.rxq_cq); +out_destroy_els_cq: + lpfc_cq_destroy(phba, phba->sli4_hba.els_cq); +out_destroy_mbx_cq: + lpfc_cq_destroy(phba, phba->sli4_hba.mbx_cq); +out_destroy_fp_eq: + for (--fcp_eqidx; fcp_eqidx >= 0; fcp_eqidx--) + lpfc_eq_destroy(phba, phba->sli4_hba.fp_eq[fcp_eqidx]); + lpfc_eq_destroy(phba, phba->sli4_hba.sp_eq); +out_error: + return rc; +} + +/** + * lpfc_sli4_queue_unset - Unset all the SLI4 queues + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to unset all the SLI4 queues with the FCoE HBA + * operation. + * + * Return codes + * 0 - sucessful + * ENOMEM - No availble memory + * EIO - The mailbox failed to complete successfully. + **/ +void +lpfc_sli4_queue_unset(struct lpfc_hba *phba) +{ + int fcp_qidx; + + /* Unset mailbox command work queue */ + lpfc_mq_destroy(phba, phba->sli4_hba.mbx_wq); + /* Unset ELS work queue */ + lpfc_wq_destroy(phba, phba->sli4_hba.els_wq); + /* Unset unsolicited receive queue */ + lpfc_rq_destroy(phba, phba->sli4_hba.hdr_rq, phba->sli4_hba.dat_rq); + /* Unset FCP work queue */ + for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_wq_count; fcp_qidx++) + lpfc_wq_destroy(phba, phba->sli4_hba.fcp_wq[fcp_qidx]); + /* Unset mailbox command complete queue */ + lpfc_cq_destroy(phba, phba->sli4_hba.mbx_cq); + /* Unset ELS complete queue */ + lpfc_cq_destroy(phba, phba->sli4_hba.els_cq); + /* Unset unsolicited receive complete queue */ + lpfc_cq_destroy(phba, phba->sli4_hba.rxq_cq); + /* Unset FCP response complete queue */ + for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_eq_count; fcp_qidx++) + lpfc_cq_destroy(phba, phba->sli4_hba.fcp_cq[fcp_qidx]); + /* Unset fast-path event queue */ + for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_eq_count; fcp_qidx++) + lpfc_eq_destroy(phba, phba->sli4_hba.fp_eq[fcp_qidx]); + /* Unset slow-path event queue */ + lpfc_eq_destroy(phba, phba->sli4_hba.sp_eq); +} + +/** + * lpfc_sli4_cq_event_pool_create - Create completion-queue event free pool + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to allocate and set up a pool of completion queue + * events. The body of the completion queue event is a completion queue entry + * CQE. For now, this pool is used for the interrupt service routine to queue + * the following HBA completion queue events for the worker thread to process: + * - Mailbox asynchronous events + * - Receive queue completion unsolicited events + * Later, this can be used for all the slow-path events. + * + * Return codes + * 0 - sucessful + * -ENOMEM - No availble memory + **/ +static int +lpfc_sli4_cq_event_pool_create(struct lpfc_hba *phba) +{ + struct lpfc_cq_event *cq_event; + int i; + + for (i = 0; i < (4 * phba->sli4_hba.cq_ecount); i++) { + cq_event = kmalloc(sizeof(struct lpfc_cq_event), GFP_KERNEL); + if (!cq_event) + goto out_pool_create_fail; + list_add_tail(&cq_event->list, + &phba->sli4_hba.sp_cqe_event_pool); + } + return 0; + +out_pool_create_fail: + lpfc_sli4_cq_event_pool_destroy(phba); + return -ENOMEM; +} + +/** + * lpfc_sli4_cq_event_pool_destroy - Free completion-queue event free pool + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to free the pool of completion queue events at + * driver unload time. Note that, it is the responsibility of the driver + * cleanup routine to free all the outstanding completion-queue events + * allocated from this pool back into the pool before invoking this routine + * to destroy the pool. + **/ +static void +lpfc_sli4_cq_event_pool_destroy(struct lpfc_hba *phba) +{ + struct lpfc_cq_event *cq_event, *next_cq_event; + + list_for_each_entry_safe(cq_event, next_cq_event, + &phba->sli4_hba.sp_cqe_event_pool, list) { + list_del(&cq_event->list); + kfree(cq_event); + } +} + +/** + * __lpfc_sli4_cq_event_alloc - Allocate a completion-queue event from free pool + * @phba: pointer to lpfc hba data structure. + * + * This routine is the lock free version of the API invoked to allocate a + * completion-queue event from the free pool. + * + * Return: Pointer to the newly allocated completion-queue event if successful + * NULL otherwise. + **/ +struct lpfc_cq_event * +__lpfc_sli4_cq_event_alloc(struct lpfc_hba *phba) +{ + struct lpfc_cq_event *cq_event = NULL; + + list_remove_head(&phba->sli4_hba.sp_cqe_event_pool, cq_event, + struct lpfc_cq_event, list); + return cq_event; +} + +/** + * lpfc_sli4_cq_event_alloc - Allocate a completion-queue event from free pool + * @phba: pointer to lpfc hba data structure. + * + * This routine is the lock version of the API invoked to allocate a + * completion-queue event from the free pool. + * + * Return: Pointer to the newly allocated completion-queue event if successful + * NULL otherwise. + **/ +struct lpfc_cq_event * +lpfc_sli4_cq_event_alloc(struct lpfc_hba *phba) +{ + struct lpfc_cq_event *cq_event; + unsigned long iflags; + + spin_lock_irqsave(&phba->hbalock, iflags); + cq_event = __lpfc_sli4_cq_event_alloc(phba); + spin_unlock_irqrestore(&phba->hbalock, iflags); + return cq_event; +} + +/** + * __lpfc_sli4_cq_event_release - Release a completion-queue event to free pool + * @phba: pointer to lpfc hba data structure. + * @cq_event: pointer to the completion queue event to be freed. + * + * This routine is the lock free version of the API invoked to release a + * completion-queue event back into the free pool. + **/ +void +__lpfc_sli4_cq_event_release(struct lpfc_hba *phba, + struct lpfc_cq_event *cq_event) +{ + list_add_tail(&cq_event->list, &phba->sli4_hba.sp_cqe_event_pool); +} + +/** + * lpfc_sli4_cq_event_release - Release a completion-queue event to free pool + * @phba: pointer to lpfc hba data structure. + * @cq_event: pointer to the completion queue event to be freed. + * + * This routine is the lock version of the API invoked to release a + * completion-queue event back into the free pool. + **/ +void +lpfc_sli4_cq_event_release(struct lpfc_hba *phba, + struct lpfc_cq_event *cq_event) +{ + unsigned long iflags; + spin_lock_irqsave(&phba->hbalock, iflags); + __lpfc_sli4_cq_event_release(phba, cq_event); + spin_unlock_irqrestore(&phba->hbalock, iflags); +} + +/** + * lpfc_sli4_cq_event_release_all - Release all cq events to the free pool + * @phba: pointer to lpfc hba data structure. + * + * This routine is to free all the pending completion-queue events to the + * back into the free pool for device reset. + **/ +static void +lpfc_sli4_cq_event_release_all(struct lpfc_hba *phba) +{ + LIST_HEAD(cqelist); + struct lpfc_cq_event *cqe; + unsigned long iflags; + + /* Retrieve all the pending WCQEs from pending WCQE lists */ + spin_lock_irqsave(&phba->hbalock, iflags); + /* Pending FCP XRI abort events */ + list_splice_init(&phba->sli4_hba.sp_fcp_xri_aborted_work_queue, + &cqelist); + /* Pending ELS XRI abort events */ + list_splice_init(&phba->sli4_hba.sp_els_xri_aborted_work_queue, + &cqelist); + /* Pending asynnc events */ + list_splice_init(&phba->sli4_hba.sp_asynce_work_queue, + &cqelist); + spin_unlock_irqrestore(&phba->hbalock, iflags); + + while (!list_empty(&cqelist)) { + list_remove_head(&cqelist, cqe, struct lpfc_cq_event, list); + lpfc_sli4_cq_event_release(phba, cqe); + } +} + +/** + * lpfc_pci_function_reset - Reset pci function. + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to request a PCI function reset. It will destroys + * all resources assigned to the PCI function which originates this request. + * + * Return codes + * 0 - sucessful + * ENOMEM - No availble memory + * EIO - The mailbox failed to complete successfully. + **/ +int +lpfc_pci_function_reset(struct lpfc_hba *phba) +{ + LPFC_MBOXQ_t *mboxq; + uint32_t rc = 0; + uint32_t shdr_status, shdr_add_status; + union lpfc_sli4_cfg_shdr *shdr; + + mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mboxq) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0494 Unable to allocate memory for issuing " + "SLI_FUNCTION_RESET mailbox command\n"); + return -ENOMEM; + } + + /* Set up PCI function reset SLI4_CONFIG mailbox-ioctl command */ + lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_COMMON, + LPFC_MBOX_OPCODE_FUNCTION_RESET, 0, + LPFC_SLI4_MBX_EMBED); + rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); + shdr = (union lpfc_sli4_cfg_shdr *) + &mboxq->u.mqe.un.sli4_config.header.cfg_shdr; + shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); + shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); + if (rc != MBX_TIMEOUT) + mempool_free(mboxq, phba->mbox_mem_pool); + if (shdr_status || shdr_add_status || rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0495 SLI_FUNCTION_RESET mailbox failed with " + "status x%x add_status x%x, mbx status x%x\n", + shdr_status, shdr_add_status, rc); + rc = -ENXIO; + } + return rc; +} + +/** + * lpfc_sli4_send_nop_mbox_cmds - Send sli-4 nop mailbox commands + * @phba: pointer to lpfc hba data structure. + * @cnt: number of nop mailbox commands to send. + * + * This routine is invoked to send a number @cnt of NOP mailbox command and + * wait for each command to complete. + * + * Return: the number of NOP mailbox command completed. + **/ +static int +lpfc_sli4_send_nop_mbox_cmds(struct lpfc_hba *phba, uint32_t cnt) +{ + LPFC_MBOXQ_t *mboxq; + int length, cmdsent; + uint32_t mbox_tmo; + uint32_t rc = 0; + uint32_t shdr_status, shdr_add_status; + union lpfc_sli4_cfg_shdr *shdr; + + if (cnt == 0) { + lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, + "2518 Requested to send 0 NOP mailbox cmd\n"); + return cnt; + } + + mboxq = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mboxq) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2519 Unable to allocate memory for issuing " + "NOP mailbox command\n"); + return 0; + } + + /* Set up NOP SLI4_CONFIG mailbox-ioctl command */ + length = (sizeof(struct lpfc_mbx_nop) - + sizeof(struct lpfc_sli4_cfg_mhdr)); + lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_COMMON, + LPFC_MBOX_OPCODE_NOP, length, LPFC_SLI4_MBX_EMBED); + + mbox_tmo = lpfc_mbox_tmo_val(phba, MBX_SLI4_CONFIG); + for (cmdsent = 0; cmdsent < cnt; cmdsent++) { + if (!phba->sli4_hba.intr_enable) + rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); + else + rc = lpfc_sli_issue_mbox_wait(phba, mboxq, mbox_tmo); + if (rc == MBX_TIMEOUT) + break; + /* Check return status */ + shdr = (union lpfc_sli4_cfg_shdr *) + &mboxq->u.mqe.un.sli4_config.header.cfg_shdr; + shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); + shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, + &shdr->response); + if (shdr_status || shdr_add_status || rc) { + lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, + "2520 NOP mailbox command failed " + "status x%x add_status x%x mbx " + "status x%x\n", shdr_status, + shdr_add_status, rc); + break; + } + } + + if (rc != MBX_TIMEOUT) + mempool_free(mboxq, phba->mbox_mem_pool); + + return cmdsent; +} + +/** + * lpfc_sli4_fcfi_unreg - Unregister fcfi to device + * @phba: pointer to lpfc hba data structure. + * @fcfi: fcf index. + * + * This routine is invoked to unregister a FCFI from device. + **/ +void +lpfc_sli4_fcfi_unreg(struct lpfc_hba *phba, uint16_t fcfi) +{ + LPFC_MBOXQ_t *mbox; + uint32_t mbox_tmo; + int rc; + unsigned long flags; + + mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + + if (!mbox) + return; + + lpfc_unreg_fcfi(mbox, fcfi); + + if (!phba->sli4_hba.intr_enable) + rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); + else { + mbox_tmo = lpfc_mbox_tmo_val(phba, MBX_SLI4_CONFIG); + rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo); + } + if (rc != MBX_TIMEOUT) + mempool_free(mbox, phba->mbox_mem_pool); + if (rc != MBX_SUCCESS) + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "2517 Unregister FCFI command failed " + "status %d, mbxStatus x%x\n", rc, + bf_get(lpfc_mqe_status, &mbox->u.mqe)); + else { + spin_lock_irqsave(&phba->hbalock, flags); + /* Mark the FCFI is no longer registered */ + phba->fcf.fcf_flag &= + ~(FCF_AVAILABLE | FCF_REGISTERED | FCF_DISCOVERED); + spin_unlock_irqrestore(&phba->hbalock, flags); + } +} + +/** + * lpfc_sli4_pci_mem_setup - Setup SLI4 HBA PCI memory space. + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to set up the PCI device memory space for device + * with SLI-4 interface spec. + * + * Return codes + * 0 - sucessful + * other values - error + **/ +static int +lpfc_sli4_pci_mem_setup(struct lpfc_hba *phba) +{ + struct pci_dev *pdev; + unsigned long bar0map_len, bar1map_len, bar2map_len; + int error = -ENODEV; + + /* Obtain PCI device reference */ + if (!phba->pcidev) + return error; + else + pdev = phba->pcidev; + + /* Set the device DMA mask size */ + if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) != 0) + if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0) + return error; + + /* Get the bus address of SLI4 device Bar0, Bar1, and Bar2 and the + * number of bytes required by each mapping. They are actually + * mapping to the PCI BAR regions 1, 2, and 4 by the SLI4 device. + */ + phba->pci_bar0_map = pci_resource_start(pdev, LPFC_SLI4_BAR0); + bar0map_len = pci_resource_len(pdev, LPFC_SLI4_BAR0); + + phba->pci_bar1_map = pci_resource_start(pdev, LPFC_SLI4_BAR1); + bar1map_len = pci_resource_len(pdev, LPFC_SLI4_BAR1); + + phba->pci_bar2_map = pci_resource_start(pdev, LPFC_SLI4_BAR2); + bar2map_len = pci_resource_len(pdev, LPFC_SLI4_BAR2); + + /* Map SLI4 PCI Config Space Register base to a kernel virtual addr */ + phba->sli4_hba.conf_regs_memmap_p = + ioremap(phba->pci_bar0_map, bar0map_len); + if (!phba->sli4_hba.conf_regs_memmap_p) { + dev_printk(KERN_ERR, &pdev->dev, + "ioremap failed for SLI4 PCI config registers.\n"); + goto out; + } + + /* Map SLI4 HBA Control Register base to a kernel virtual address. */ + phba->sli4_hba.ctrl_regs_memmap_p = + ioremap(phba->pci_bar1_map, bar1map_len); + if (!phba->sli4_hba.ctrl_regs_memmap_p) { + dev_printk(KERN_ERR, &pdev->dev, + "ioremap failed for SLI4 HBA control registers.\n"); + goto out_iounmap_conf; + } + + /* Map SLI4 HBA Doorbell Register base to a kernel virtual address. */ + phba->sli4_hba.drbl_regs_memmap_p = + ioremap(phba->pci_bar2_map, bar2map_len); + if (!phba->sli4_hba.drbl_regs_memmap_p) { + dev_printk(KERN_ERR, &pdev->dev, + "ioremap failed for SLI4 HBA doorbell registers.\n"); + goto out_iounmap_ctrl; + } + + /* Set up BAR0 PCI config space register memory map */ + lpfc_sli4_bar0_register_memmap(phba); + + /* Set up BAR1 register memory map */ + lpfc_sli4_bar1_register_memmap(phba); + + /* Set up BAR2 register memory map */ + error = lpfc_sli4_bar2_register_memmap(phba, LPFC_VF0); + if (error) + goto out_iounmap_all; + + return 0; + +out_iounmap_all: + iounmap(phba->sli4_hba.drbl_regs_memmap_p); +out_iounmap_ctrl: + iounmap(phba->sli4_hba.ctrl_regs_memmap_p); +out_iounmap_conf: + iounmap(phba->sli4_hba.conf_regs_memmap_p); +out: + return error; +} + +/** + * lpfc_sli4_pci_mem_unset - Unset SLI4 HBA PCI memory space. + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to unset the PCI device memory space for device + * with SLI-4 interface spec. + **/ +static void +lpfc_sli4_pci_mem_unset(struct lpfc_hba *phba) +{ + struct pci_dev *pdev; + + /* Obtain PCI device reference */ + if (!phba->pcidev) + return; + else + pdev = phba->pcidev; + + /* Free coherent DMA memory allocated */ + + /* Unmap I/O memory space */ + iounmap(phba->sli4_hba.drbl_regs_memmap_p); + iounmap(phba->sli4_hba.ctrl_regs_memmap_p); + iounmap(phba->sli4_hba.conf_regs_memmap_p); + + return; +} + +/** + * lpfc_sli_enable_msix - Enable MSI-X interrupt mode on SLI-3 device + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to enable the MSI-X interrupt vectors to device + * with SLI-3 interface specs. The kernel function pci_enable_msix() is + * called to enable the MSI-X vectors. Note that pci_enable_msix(), once + * invoked, enables either all or nothing, depending on the current + * availability of PCI vector resources. The device driver is responsible + * for calling the individual request_irq() to register each MSI-X vector + * with a interrupt handler, which is done in this function. Note that * later when device is unloading, the driver should always call free_irq() * on all MSI-X vectors it has done request_irq() on before calling * pci_disable_msix(). Failure to do so results in a BUG_ON() and a device @@ -2333,7 +6027,7 @@ void lpfc_host_attrib_init(struct Scsi_Host *shost) * other values - error **/ static int -lpfc_enable_msix(struct lpfc_hba *phba) +lpfc_sli_enable_msix(struct lpfc_hba *phba) { int rc, i; LPFC_MBOXQ_t *pmb; @@ -2349,20 +6043,21 @@ lpfc_enable_msix(struct lpfc_hba *phba) lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "0420 PCI enable MSI-X failed (%d)\n", rc); goto msi_fail_out; - } else - for (i = 0; i < LPFC_MSIX_VECTORS; i++) - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "0477 MSI-X entry[%d]: vector=x%x " - "message=%d\n", i, - phba->msix_entries[i].vector, - phba->msix_entries[i].entry); + } + for (i = 0; i < LPFC_MSIX_VECTORS; i++) + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "0477 MSI-X entry[%d]: vector=x%x " + "message=%d\n", i, + phba->msix_entries[i].vector, + phba->msix_entries[i].entry); /* * Assign MSI-X vectors to interrupt handlers */ /* vector-0 is associated to slow-path handler */ - rc = request_irq(phba->msix_entries[0].vector, &lpfc_sp_intr_handler, - IRQF_SHARED, LPFC_SP_DRIVER_HANDLER_NAME, phba); + rc = request_irq(phba->msix_entries[0].vector, + &lpfc_sli_sp_intr_handler, IRQF_SHARED, + LPFC_SP_DRIVER_HANDLER_NAME, phba); if (rc) { lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, "0421 MSI-X slow-path request_irq failed " @@ -2371,8 +6066,9 @@ lpfc_enable_msix(struct lpfc_hba *phba) } /* vector-1 is associated to fast-path handler */ - rc = request_irq(phba->msix_entries[1].vector, &lpfc_fp_intr_handler, - IRQF_SHARED, LPFC_FP_DRIVER_HANDLER_NAME, phba); + rc = request_irq(phba->msix_entries[1].vector, + &lpfc_sli_fp_intr_handler, IRQF_SHARED, + LPFC_FP_DRIVER_HANDLER_NAME, phba); if (rc) { lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, @@ -2401,7 +6097,7 @@ lpfc_enable_msix(struct lpfc_hba *phba) lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX, "0351 Config MSI mailbox command failed, " "mbxCmd x%x, mbxStatus x%x\n", - pmb->mb.mbxCommand, pmb->mb.mbxStatus); + pmb->u.mb.mbxCommand, pmb->u.mb.mbxStatus); goto mbx_fail_out; } @@ -2428,14 +6124,14 @@ msi_fail_out: } /** - * lpfc_disable_msix - Disable MSI-X interrupt mode + * lpfc_sli_disable_msix - Disable MSI-X interrupt mode on SLI-3 device. * @phba: pointer to lpfc hba data structure. * * This routine is invoked to release the MSI-X vectors and then disable the - * MSI-X interrupt mode. + * MSI-X interrupt mode to device with SLI-3 interface spec. **/ static void -lpfc_disable_msix(struct lpfc_hba *phba) +lpfc_sli_disable_msix(struct lpfc_hba *phba) { int i; @@ -2444,23 +6140,26 @@ lpfc_disable_msix(struct lpfc_hba *phba) free_irq(phba->msix_entries[i].vector, phba); /* Disable MSI-X */ pci_disable_msix(phba->pcidev); + + return; } /** - * lpfc_enable_msi - Enable MSI interrupt mode + * lpfc_sli_enable_msi - Enable MSI interrupt mode on SLI-3 device. * @phba: pointer to lpfc hba data structure. * - * This routine is invoked to enable the MSI interrupt mode. The kernel - * function pci_enable_msi() is called to enable the MSI vector. The - * device driver is responsible for calling the request_irq() to register - * MSI vector with a interrupt the handler, which is done in this function. + * This routine is invoked to enable the MSI interrupt mode to device with + * SLI-3 interface spec. The kernel function pci_enable_msi() is called to + * enable the MSI vector. The device driver is responsible for calling the + * request_irq() to register MSI vector with a interrupt the handler, which + * is done in this function. * * Return codes * 0 - sucessful * other values - error */ static int -lpfc_enable_msi(struct lpfc_hba *phba) +lpfc_sli_enable_msi(struct lpfc_hba *phba) { int rc; @@ -2474,7 +6173,7 @@ lpfc_enable_msi(struct lpfc_hba *phba) return rc; } - rc = request_irq(phba->pcidev->irq, lpfc_intr_handler, + rc = request_irq(phba->pcidev->irq, lpfc_sli_intr_handler, IRQF_SHARED, LPFC_DRIVER_NAME, phba); if (rc) { pci_disable_msi(phba->pcidev); @@ -2485,17 +6184,17 @@ lpfc_enable_msi(struct lpfc_hba *phba) } /** - * lpfc_disable_msi - Disable MSI interrupt mode + * lpfc_sli_disable_msi - Disable MSI interrupt mode to SLI-3 device. * @phba: pointer to lpfc hba data structure. * - * This routine is invoked to disable the MSI interrupt mode. The driver - * calls free_irq() on MSI vector it has done request_irq() on before - * calling pci_disable_msi(). Failure to do so results in a BUG_ON() and - * a device will be left with MSI enabled and leaks its vector. + * This routine is invoked to disable the MSI interrupt mode to device with + * SLI-3 interface spec. The driver calls free_irq() on MSI vector it has + * done request_irq() on before calling pci_disable_msi(). Failure to do so + * results in a BUG_ON() and a device will be left with MSI enabled and leaks + * its vector. */ - static void -lpfc_disable_msi(struct lpfc_hba *phba) +lpfc_sli_disable_msi(struct lpfc_hba *phba) { free_irq(phba->pcidev->irq, phba); pci_disable_msi(phba->pcidev); @@ -2503,80 +6202,33 @@ lpfc_disable_msi(struct lpfc_hba *phba) } /** - * lpfc_log_intr_mode - Log the active interrupt mode - * @phba: pointer to lpfc hba data structure. - * @intr_mode: active interrupt mode adopted. - * - * This routine it invoked to log the currently used active interrupt mode - * to the device. - */ -static void -lpfc_log_intr_mode(struct lpfc_hba *phba, uint32_t intr_mode) -{ - switch (intr_mode) { - case 0: - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "0470 Enable INTx interrupt mode.\n"); - break; - case 1: - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "0481 Enabled MSI interrupt mode.\n"); - break; - case 2: - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "0480 Enabled MSI-X interrupt mode.\n"); - break; - default: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0482 Illegal interrupt mode.\n"); - break; - } - return; -} - -static void -lpfc_stop_port(struct lpfc_hba *phba) -{ - /* Clear all interrupt enable conditions */ - writel(0, phba->HCregaddr); - readl(phba->HCregaddr); /* flush */ - /* Clear all pending interrupts */ - writel(0xffffffff, phba->HAregaddr); - readl(phba->HAregaddr); /* flush */ - - /* Reset some HBA SLI setup states */ - lpfc_stop_phba_timers(phba); - phba->pport->work_port_events = 0; - - return; -} - -/** - * lpfc_enable_intr - Enable device interrupt + * lpfc_sli_enable_intr - Enable device interrupt to SLI-3 device. * @phba: pointer to lpfc hba data structure. * * This routine is invoked to enable device interrupt and associate driver's - * interrupt handler(s) to interrupt vector(s). Depends on the interrupt - * mode configured to the driver, the driver will try to fallback from the - * configured interrupt mode to an interrupt mode which is supported by the - * platform, kernel, and device in the order of: MSI-X -> MSI -> IRQ. + * interrupt handler(s) to interrupt vector(s) to device with SLI-3 interface + * spec. Depends on the interrupt mode configured to the driver, the driver + * will try to fallback from the configured interrupt mode to an interrupt + * mode which is supported by the platform, kernel, and device in the order + * of: + * MSI-X -> MSI -> IRQ. * * Return codes * 0 - sucessful * other values - error **/ static uint32_t -lpfc_enable_intr(struct lpfc_hba *phba, uint32_t cfg_mode) +lpfc_sli_enable_intr(struct lpfc_hba *phba, uint32_t cfg_mode) { uint32_t intr_mode = LPFC_INTR_ERROR; int retval; if (cfg_mode == 2) { /* Need to issue conf_port mbox cmd before conf_msi mbox cmd */ - retval = lpfc_sli_config_port(phba, 3); + retval = lpfc_sli_config_port(phba, LPFC_SLI_REV3); if (!retval) { /* Now, try to enable MSI-X interrupt mode */ - retval = lpfc_enable_msix(phba); + retval = lpfc_sli_enable_msix(phba); if (!retval) { /* Indicate initialization to MSI-X mode */ phba->intr_type = MSIX; @@ -2587,7 +6239,7 @@ lpfc_enable_intr(struct lpfc_hba *phba, uint32_t cfg_mode) /* Fallback to MSI if MSI-X initialization failed */ if (cfg_mode >= 1 && phba->intr_type == NONE) { - retval = lpfc_enable_msi(phba); + retval = lpfc_sli_enable_msi(phba); if (!retval) { /* Indicate initialization to MSI mode */ phba->intr_type = MSI; @@ -2597,7 +6249,7 @@ lpfc_enable_intr(struct lpfc_hba *phba, uint32_t cfg_mode) /* Fallback to INTx if both MSI-X/MSI initalization failed */ if (phba->intr_type == NONE) { - retval = request_irq(phba->pcidev->irq, lpfc_intr_handler, + retval = request_irq(phba->pcidev->irq, lpfc_sli_intr_handler, IRQF_SHARED, LPFC_DRIVER_NAME, phba); if (!retval) { /* Indicate initialization to INTx mode */ @@ -2609,22 +6261,22 @@ lpfc_enable_intr(struct lpfc_hba *phba, uint32_t cfg_mode) } /** - * lpfc_disable_intr - Disable device interrupt + * lpfc_sli_disable_intr - Disable device interrupt to SLI-3 device. * @phba: pointer to lpfc hba data structure. * * This routine is invoked to disable device interrupt and disassociate the - * driver's interrupt handler(s) from interrupt vector(s). Depending on the - * interrupt mode, the driver will release the interrupt vector(s) for the - * message signaled interrupt. + * driver's interrupt handler(s) from interrupt vector(s) to device with + * SLI-3 interface spec. Depending on the interrupt mode, the driver will + * release the interrupt vector(s) for the message signaled interrupt. **/ static void -lpfc_disable_intr(struct lpfc_hba *phba) +lpfc_sli_disable_intr(struct lpfc_hba *phba) { /* Disable the currently initialized interrupt mode */ if (phba->intr_type == MSIX) - lpfc_disable_msix(phba); + lpfc_sli_disable_msix(phba); else if (phba->intr_type == MSI) - lpfc_disable_msi(phba); + lpfc_sli_disable_msi(phba); else if (phba->intr_type == INTx) free_irq(phba->pcidev->irq, phba); @@ -2636,263 +6288,503 @@ lpfc_disable_intr(struct lpfc_hba *phba) } /** - * lpfc_pci_probe_one - lpfc PCI probe func to register device to PCI subsystem - * @pdev: pointer to PCI device - * @pid: pointer to PCI device identifier + * lpfc_sli4_enable_msix - Enable MSI-X interrupt mode to SLI-4 device + * @phba: pointer to lpfc hba data structure. * - * This routine is to be registered to the kernel's PCI subsystem. When an - * Emulex HBA is presented in PCI bus, the kernel PCI subsystem looks at - * PCI device-specific information of the device and driver to see if the - * driver state that it can support this kind of device. If the match is - * successful, the driver core invokes this routine. If this routine - * determines it can claim the HBA, it does all the initialization that it - * needs to do to handle the HBA properly. + * This routine is invoked to enable the MSI-X interrupt vectors to device + * with SLI-4 interface spec. The kernel function pci_enable_msix() is called + * to enable the MSI-X vectors. Note that pci_enable_msix(), once invoked, + * enables either all or nothing, depending on the current availability of + * PCI vector resources. The device driver is responsible for calling the + * individual request_irq() to register each MSI-X vector with a interrupt + * handler, which is done in this function. Note that later when device is + * unloading, the driver should always call free_irq() on all MSI-X vectors + * it has done request_irq() on before calling pci_disable_msix(). Failure + * to do so results in a BUG_ON() and a device will be left with MSI-X + * enabled and leaks its vectors. * - * Return code - * 0 - driver can claim the device - * negative value - driver can not claim the device + * Return codes + * 0 - sucessful + * other values - error **/ -static int __devinit -lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) +static int +lpfc_sli4_enable_msix(struct lpfc_hba *phba) { - struct lpfc_vport *vport = NULL; - struct lpfc_hba *phba; - struct lpfc_sli *psli; - struct lpfc_iocbq *iocbq_entry = NULL, *iocbq_next = NULL; - struct Scsi_Host *shost = NULL; - void *ptr; - unsigned long bar0map_len, bar2map_len; - int error = -ENODEV, retval; - int i, hbq_count; - uint16_t iotag; - uint32_t cfg_mode, intr_mode; - int bars = pci_select_bars(pdev, IORESOURCE_MEM); - struct lpfc_adapter_event_header adapter_event; + int rc, index; - if (pci_enable_device_mem(pdev)) - goto out; - if (pci_request_selected_regions(pdev, bars, LPFC_DRIVER_NAME)) - goto out_disable_device; + /* Set up MSI-X multi-message vectors */ + for (index = 0; index < phba->sli4_hba.cfg_eqn; index++) + phba->sli4_hba.msix_entries[index].entry = index; - phba = kzalloc(sizeof (struct lpfc_hba), GFP_KERNEL); - if (!phba) - goto out_release_regions; - - atomic_set(&phba->fast_event_count, 0); - spin_lock_init(&phba->hbalock); - - /* Initialize ndlp management spinlock */ - spin_lock_init(&phba->ndlp_lock); - - phba->pcidev = pdev; - - /* Assign an unused board number */ - if ((phba->brd_no = lpfc_get_instance()) < 0) - goto out_free_phba; - - INIT_LIST_HEAD(&phba->port_list); - init_waitqueue_head(&phba->wait_4_mlo_m_q); + /* Configure MSI-X capability structure */ + rc = pci_enable_msix(phba->pcidev, phba->sli4_hba.msix_entries, + phba->sli4_hba.cfg_eqn); + if (rc) { + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "0484 PCI enable MSI-X failed (%d)\n", rc); + goto msi_fail_out; + } + /* Log MSI-X vector assignment */ + for (index = 0; index < phba->sli4_hba.cfg_eqn; index++) + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "0489 MSI-X entry[%d]: vector=x%x " + "message=%d\n", index, + phba->sli4_hba.msix_entries[index].vector, + phba->sli4_hba.msix_entries[index].entry); /* - * Get all the module params for configuring this host and then - * establish the host. + * Assign MSI-X vectors to interrupt handlers */ - lpfc_get_cfgparam(phba); - phba->max_vpi = LPFC_MAX_VPI; - /* Initialize timers used by driver */ - init_timer(&phba->hb_tmofunc); - phba->hb_tmofunc.function = lpfc_hb_timeout; - phba->hb_tmofunc.data = (unsigned long)phba; + /* The first vector must associated to slow-path handler for MQ */ + rc = request_irq(phba->sli4_hba.msix_entries[0].vector, + &lpfc_sli4_sp_intr_handler, IRQF_SHARED, + LPFC_SP_DRIVER_HANDLER_NAME, phba); + if (rc) { + lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, + "0485 MSI-X slow-path request_irq failed " + "(%d)\n", rc); + goto msi_fail_out; + } - psli = &phba->sli; - init_timer(&psli->mbox_tmo); - psli->mbox_tmo.function = lpfc_mbox_timeout; - psli->mbox_tmo.data = (unsigned long) phba; - init_timer(&phba->fcp_poll_timer); - phba->fcp_poll_timer.function = lpfc_poll_timeout; - phba->fcp_poll_timer.data = (unsigned long) phba; - init_timer(&phba->fabric_block_timer); - phba->fabric_block_timer.function = lpfc_fabric_block_timeout; - phba->fabric_block_timer.data = (unsigned long) phba; - init_timer(&phba->eratt_poll); - phba->eratt_poll.function = lpfc_poll_eratt; - phba->eratt_poll.data = (unsigned long) phba; + /* The rest of the vector(s) are associated to fast-path handler(s) */ + for (index = 1; index < phba->sli4_hba.cfg_eqn; index++) { + phba->sli4_hba.fcp_eq_hdl[index - 1].idx = index - 1; + phba->sli4_hba.fcp_eq_hdl[index - 1].phba = phba; + rc = request_irq(phba->sli4_hba.msix_entries[index].vector, + &lpfc_sli4_fp_intr_handler, IRQF_SHARED, + LPFC_FP_DRIVER_HANDLER_NAME, + &phba->sli4_hba.fcp_eq_hdl[index - 1]); + if (rc) { + lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, + "0486 MSI-X fast-path (%d) " + "request_irq failed (%d)\n", index, rc); + goto cfg_fail_out; + } + } - pci_set_master(pdev); - pci_save_state(pdev); - pci_try_set_mwi(pdev); + return rc; - if (pci_set_dma_mask(phba->pcidev, DMA_BIT_MASK(64)) != 0) - if (pci_set_dma_mask(phba->pcidev, DMA_BIT_MASK(32)) != 0) - goto out_idr_remove; +cfg_fail_out: + /* free the irq already requested */ + for (--index; index >= 1; index--) + free_irq(phba->sli4_hba.msix_entries[index - 1].vector, + &phba->sli4_hba.fcp_eq_hdl[index - 1]); + + /* free the irq already requested */ + free_irq(phba->sli4_hba.msix_entries[0].vector, phba); + +msi_fail_out: + /* Unconfigure MSI-X capability structure */ + pci_disable_msix(phba->pcidev); + return rc; +} + +/** + * lpfc_sli4_disable_msix - Disable MSI-X interrupt mode to SLI-4 device + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to release the MSI-X vectors and then disable the + * MSI-X interrupt mode to device with SLI-4 interface spec. + **/ +static void +lpfc_sli4_disable_msix(struct lpfc_hba *phba) +{ + int index; + + /* Free up MSI-X multi-message vectors */ + free_irq(phba->sli4_hba.msix_entries[0].vector, phba); + + for (index = 1; index < phba->sli4_hba.cfg_eqn; index++) + free_irq(phba->sli4_hba.msix_entries[index].vector, + &phba->sli4_hba.fcp_eq_hdl[index - 1]); + /* Disable MSI-X */ + pci_disable_msix(phba->pcidev); + + return; +} + +/** + * lpfc_sli4_enable_msi - Enable MSI interrupt mode to SLI-4 device + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to enable the MSI interrupt mode to device with + * SLI-4 interface spec. The kernel function pci_enable_msi() is called + * to enable the MSI vector. The device driver is responsible for calling + * the request_irq() to register MSI vector with a interrupt the handler, + * which is done in this function. + * + * Return codes + * 0 - sucessful + * other values - error + **/ +static int +lpfc_sli4_enable_msi(struct lpfc_hba *phba) +{ + int rc, index; + + rc = pci_enable_msi(phba->pcidev); + if (!rc) + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "0487 PCI enable MSI mode success.\n"); + else { + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "0488 PCI enable MSI mode failed (%d)\n", rc); + return rc; + } + + rc = request_irq(phba->pcidev->irq, lpfc_sli4_intr_handler, + IRQF_SHARED, LPFC_DRIVER_NAME, phba); + if (rc) { + pci_disable_msi(phba->pcidev); + lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, + "0490 MSI request_irq failed (%d)\n", rc); + } + + for (index = 0; index < phba->cfg_fcp_eq_count; index++) { + phba->sli4_hba.fcp_eq_hdl[index].idx = index; + phba->sli4_hba.fcp_eq_hdl[index].phba = phba; + } + + return rc; +} + +/** + * lpfc_sli4_disable_msi - Disable MSI interrupt mode to SLI-4 device + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to disable the MSI interrupt mode to device with + * SLI-4 interface spec. The driver calls free_irq() on MSI vector it has + * done request_irq() on before calling pci_disable_msi(). Failure to do so + * results in a BUG_ON() and a device will be left with MSI enabled and leaks + * its vector. + **/ +static void +lpfc_sli4_disable_msi(struct lpfc_hba *phba) +{ + free_irq(phba->pcidev->irq, phba); + pci_disable_msi(phba->pcidev); + return; +} + +/** + * lpfc_sli4_enable_intr - Enable device interrupt to SLI-4 device + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to enable device interrupt and associate driver's + * interrupt handler(s) to interrupt vector(s) to device with SLI-4 + * interface spec. Depends on the interrupt mode configured to the driver, + * the driver will try to fallback from the configured interrupt mode to an + * interrupt mode which is supported by the platform, kernel, and device in + * the order of: + * MSI-X -> MSI -> IRQ. + * + * Return codes + * 0 - sucessful + * other values - error + **/ +static uint32_t +lpfc_sli4_enable_intr(struct lpfc_hba *phba, uint32_t cfg_mode) +{ + uint32_t intr_mode = LPFC_INTR_ERROR; + int retval, index; + + if (cfg_mode == 2) { + /* Preparation before conf_msi mbox cmd */ + retval = 0; + if (!retval) { + /* Now, try to enable MSI-X interrupt mode */ + retval = lpfc_sli4_enable_msix(phba); + if (!retval) { + /* Indicate initialization to MSI-X mode */ + phba->intr_type = MSIX; + intr_mode = 2; + } + } + } + + /* Fallback to MSI if MSI-X initialization failed */ + if (cfg_mode >= 1 && phba->intr_type == NONE) { + retval = lpfc_sli4_enable_msi(phba); + if (!retval) { + /* Indicate initialization to MSI mode */ + phba->intr_type = MSI; + intr_mode = 1; + } + } + + /* Fallback to INTx if both MSI-X/MSI initalization failed */ + if (phba->intr_type == NONE) { + retval = request_irq(phba->pcidev->irq, lpfc_sli4_intr_handler, + IRQF_SHARED, LPFC_DRIVER_NAME, phba); + if (!retval) { + /* Indicate initialization to INTx mode */ + phba->intr_type = INTx; + intr_mode = 0; + for (index = 0; index < phba->cfg_fcp_eq_count; + index++) { + phba->sli4_hba.fcp_eq_hdl[index].idx = index; + phba->sli4_hba.fcp_eq_hdl[index].phba = phba; + } + } + } + return intr_mode; +} + +/** + * lpfc_sli4_disable_intr - Disable device interrupt to SLI-4 device + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to disable device interrupt and disassociate + * the driver's interrupt handler(s) from interrupt vector(s) to device + * with SLI-4 interface spec. Depending on the interrupt mode, the driver + * will release the interrupt vector(s) for the message signaled interrupt. + **/ +static void +lpfc_sli4_disable_intr(struct lpfc_hba *phba) +{ + /* Disable the currently initialized interrupt mode */ + if (phba->intr_type == MSIX) + lpfc_sli4_disable_msix(phba); + else if (phba->intr_type == MSI) + lpfc_sli4_disable_msi(phba); + else if (phba->intr_type == INTx) + free_irq(phba->pcidev->irq, phba); + + /* Reset interrupt management states */ + phba->intr_type = NONE; + phba->sli.slistat.sli_intr = 0; + + return; +} + +/** + * lpfc_unset_hba - Unset SLI3 hba device initialization + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to unset the HBA device initialization steps to + * a device with SLI-3 interface spec. + **/ +static void +lpfc_unset_hba(struct lpfc_hba *phba) +{ + struct lpfc_vport *vport = phba->pport; + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + + spin_lock_irq(shost->host_lock); + vport->load_flag |= FC_UNLOADING; + spin_unlock_irq(shost->host_lock); + + lpfc_stop_hba_timers(phba); + + phba->pport->work_port_events = 0; + + lpfc_sli_hba_down(phba); + + lpfc_sli_brdrestart(phba); + + lpfc_sli_disable_intr(phba); + + return; +} + +/** + * lpfc_sli4_unset_hba - Unset SLI4 hba device initialization. + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to unset the HBA device initialization steps to + * a device with SLI-4 interface spec. + **/ +static void +lpfc_sli4_unset_hba(struct lpfc_hba *phba) +{ + struct lpfc_vport *vport = phba->pport; + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + + spin_lock_irq(shost->host_lock); + vport->load_flag |= FC_UNLOADING; + spin_unlock_irq(shost->host_lock); + + phba->pport->work_port_events = 0; + + lpfc_sli4_hba_down(phba); + + lpfc_sli4_disable_intr(phba); + + return; +} + +/** + * lpfc_sli4_hba_unset - Unset the fcoe hba + * @phba: Pointer to HBA context object. + * + * This function is called in the SLI4 code path to reset the HBA's FCoE + * function. The caller is not required to hold any lock. This routine + * issues PCI function reset mailbox command to reset the FCoE function. + * At the end of the function, it calls lpfc_hba_down_post function to + * free any pending commands. + **/ +static void +lpfc_sli4_hba_unset(struct lpfc_hba *phba) +{ + int wait_cnt = 0; + LPFC_MBOXQ_t *mboxq; + + lpfc_stop_hba_timers(phba); + phba->sli4_hba.intr_enable = 0; /* - * Get the bus address of Bar0 and Bar2 and the number of bytes - * required by each mapping. + * Gracefully wait out the potential current outstanding asynchronous + * mailbox command. */ - phba->pci_bar0_map = pci_resource_start(phba->pcidev, 0); - bar0map_len = pci_resource_len(phba->pcidev, 0); - phba->pci_bar2_map = pci_resource_start(phba->pcidev, 2); - bar2map_len = pci_resource_len(phba->pcidev, 2); - - /* Map HBA SLIM to a kernel virtual address. */ - phba->slim_memmap_p = ioremap(phba->pci_bar0_map, bar0map_len); - if (!phba->slim_memmap_p) { - error = -ENODEV; - dev_printk(KERN_ERR, &pdev->dev, - "ioremap failed for SLIM memory.\n"); - goto out_idr_remove; + /* First, block any pending async mailbox command from posted */ + spin_lock_irq(&phba->hbalock); + phba->sli.sli_flag |= LPFC_SLI_ASYNC_MBX_BLK; + spin_unlock_irq(&phba->hbalock); + /* Now, trying to wait it out if we can */ + while (phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE) { + msleep(10); + if (++wait_cnt > LPFC_ACTIVE_MBOX_WAIT_CNT) + break; } - - /* Map HBA Control Registers to a kernel virtual address. */ - phba->ctrl_regs_memmap_p = ioremap(phba->pci_bar2_map, bar2map_len); - if (!phba->ctrl_regs_memmap_p) { - error = -ENODEV; - dev_printk(KERN_ERR, &pdev->dev, - "ioremap failed for HBA control registers.\n"); - goto out_iounmap_slim; - } - - /* Allocate memory for SLI-2 structures */ - phba->slim2p.virt = dma_alloc_coherent(&phba->pcidev->dev, - SLI2_SLIM_SIZE, - &phba->slim2p.phys, - GFP_KERNEL); - if (!phba->slim2p.virt) - goto out_iounmap; - - memset(phba->slim2p.virt, 0, SLI2_SLIM_SIZE); - phba->mbox = phba->slim2p.virt + offsetof(struct lpfc_sli2_slim, mbx); - phba->pcb = (phba->slim2p.virt + offsetof(struct lpfc_sli2_slim, pcb)); - phba->IOCBs = (phba->slim2p.virt + - offsetof(struct lpfc_sli2_slim, IOCBs)); - - phba->hbqslimp.virt = dma_alloc_coherent(&phba->pcidev->dev, - lpfc_sli_hbq_size(), - &phba->hbqslimp.phys, - GFP_KERNEL); - if (!phba->hbqslimp.virt) - goto out_free_slim; - - hbq_count = lpfc_sli_hbq_count(); - ptr = phba->hbqslimp.virt; - for (i = 0; i < hbq_count; ++i) { - phba->hbqs[i].hbq_virt = ptr; - INIT_LIST_HEAD(&phba->hbqs[i].hbq_buffer_list); - ptr += (lpfc_hbq_defs[i]->entry_count * - sizeof(struct lpfc_hbq_entry)); - } - phba->hbqs[LPFC_ELS_HBQ].hbq_alloc_buffer = lpfc_els_hbq_alloc; - phba->hbqs[LPFC_ELS_HBQ].hbq_free_buffer = lpfc_els_hbq_free; - - memset(phba->hbqslimp.virt, 0, lpfc_sli_hbq_size()); - - INIT_LIST_HEAD(&phba->hbqbuf_in_list); - - /* Initialize the SLI Layer to run with lpfc HBAs. */ - lpfc_sli_setup(phba); - lpfc_sli_queue_setup(phba); - - retval = lpfc_mem_alloc(phba); - if (retval) { - error = retval; - goto out_free_hbqslimp; - } - - /* Initialize and populate the iocb list per host. */ - INIT_LIST_HEAD(&phba->lpfc_iocb_list); - for (i = 0; i < LPFC_IOCB_LIST_CNT; i++) { - iocbq_entry = kzalloc(sizeof(struct lpfc_iocbq), GFP_KERNEL); - if (iocbq_entry == NULL) { - printk(KERN_ERR "%s: only allocated %d iocbs of " - "expected %d count. Unloading driver.\n", - __func__, i, LPFC_IOCB_LIST_CNT); - error = -ENOMEM; - goto out_free_iocbq; - } - - iotag = lpfc_sli_next_iotag(phba, iocbq_entry); - if (iotag == 0) { - kfree (iocbq_entry); - printk(KERN_ERR "%s: failed to allocate IOTAG. " - "Unloading driver.\n", - __func__); - error = -ENOMEM; - goto out_free_iocbq; - } - + /* Forcefully release the outstanding mailbox command if timed out */ + if (phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE) { spin_lock_irq(&phba->hbalock); - list_add(&iocbq_entry->list, &phba->lpfc_iocb_list); - phba->total_iocbq_bufs++; + mboxq = phba->sli.mbox_active; + mboxq->u.mb.mbxStatus = MBX_NOT_FINISHED; + __lpfc_mbox_cmpl_put(phba, mboxq); + phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; + phba->sli.mbox_active = NULL; spin_unlock_irq(&phba->hbalock); } - /* Initialize HBA structure */ - phba->fc_edtov = FF_DEF_EDTOV; - phba->fc_ratov = FF_DEF_RATOV; - phba->fc_altov = FF_DEF_ALTOV; - phba->fc_arbtov = FF_DEF_ARBTOV; + /* Tear down the queues in the HBA */ + lpfc_sli4_queue_unset(phba); - INIT_LIST_HEAD(&phba->work_list); - phba->work_ha_mask = (HA_ERATT | HA_MBATT | HA_LATT); - phba->work_ha_mask |= (HA_RXMASK << (LPFC_ELS_RING * 4)); + /* Disable PCI subsystem interrupt */ + lpfc_sli4_disable_intr(phba); - /* Initialize the wait queue head for the kernel thread */ - init_waitqueue_head(&phba->work_waitq); + /* Stop kthread signal shall trigger work_done one more time */ + kthread_stop(phba->worker_thread); - /* Startup the kernel thread for this host adapter. */ - phba->worker_thread = kthread_run(lpfc_do_work, phba, - "lpfc_worker_%d", phba->brd_no); - if (IS_ERR(phba->worker_thread)) { - error = PTR_ERR(phba->worker_thread); - goto out_free_iocbq; + /* Stop the SLI4 device port */ + phba->pport->work_port_events = 0; +} + +/** + * lpfc_pci_probe_one_s3 - PCI probe func to reg SLI-3 device to PCI subsystem. + * @pdev: pointer to PCI device + * @pid: pointer to PCI device identifier + * + * This routine is to be called to attach a device with SLI-3 interface spec + * to the PCI subsystem. When an Emulex HBA with SLI-3 interface spec is + * presented on PCI bus, the kernel PCI subsystem looks at PCI device-specific + * information of the device and driver to see if the driver state that it can + * support this kind of device. If the match is successful, the driver core + * invokes this routine. If this routine determines it can claim the HBA, it + * does all the initialization that it needs to do to handle the HBA properly. + * + * Return code + * 0 - driver can claim the device + * negative value - driver can not claim the device + **/ +static int __devinit +lpfc_pci_probe_one_s3(struct pci_dev *pdev, const struct pci_device_id *pid) +{ + struct lpfc_hba *phba; + struct lpfc_vport *vport = NULL; + int error; + uint32_t cfg_mode, intr_mode; + + /* Allocate memory for HBA structure */ + phba = lpfc_hba_alloc(pdev); + if (!phba) + return -ENOMEM; + + /* Perform generic PCI device enabling operation */ + error = lpfc_enable_pci_dev(phba); + if (error) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "1401 Failed to enable pci device.\n"); + goto out_free_phba; } - /* Initialize the list of scsi buffers used by driver for scsi IO. */ - spin_lock_init(&phba->scsi_buf_list_lock); - INIT_LIST_HEAD(&phba->lpfc_scsi_buf_list); + /* Set up SLI API function jump table for PCI-device group-0 HBAs */ + error = lpfc_api_table_setup(phba, LPFC_PCI_DEV_LP); + if (error) + goto out_disable_pci_dev; - /* Initialize list of fabric iocbs */ - INIT_LIST_HEAD(&phba->fabric_iocb_list); + /* Set up SLI-3 specific device PCI memory space */ + error = lpfc_sli_pci_mem_setup(phba); + if (error) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "1402 Failed to set up pci memory space.\n"); + goto out_disable_pci_dev; + } - /* Initialize list to save ELS buffers */ - INIT_LIST_HEAD(&phba->elsbuf); + /* Set up phase-1 common device driver resources */ + error = lpfc_setup_driver_resource_phase1(phba); + if (error) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "1403 Failed to set up driver resource.\n"); + goto out_unset_pci_mem_s3; + } - vport = lpfc_create_port(phba, phba->brd_no, &phba->pcidev->dev); - if (!vport) - goto out_kthread_stop; + /* Set up SLI-3 specific device driver resources */ + error = lpfc_sli_driver_resource_setup(phba); + if (error) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "1404 Failed to set up driver resource.\n"); + goto out_unset_pci_mem_s3; + } - shost = lpfc_shost_from_vport(vport); - phba->pport = vport; - lpfc_debugfs_initialize(vport); + /* Initialize and populate the iocb list per host */ + error = lpfc_init_iocb_list(phba, LPFC_IOCB_LIST_CNT); + if (error) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "1405 Failed to initialize iocb list.\n"); + goto out_unset_driver_resource_s3; + } - pci_set_drvdata(pdev, shost); + /* Set up common device driver resources */ + error = lpfc_setup_driver_resource_phase2(phba); + if (error) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "1406 Failed to set up driver resource.\n"); + goto out_free_iocb_list; + } - phba->MBslimaddr = phba->slim_memmap_p; - phba->HAregaddr = phba->ctrl_regs_memmap_p + HA_REG_OFFSET; - phba->CAregaddr = phba->ctrl_regs_memmap_p + CA_REG_OFFSET; - phba->HSregaddr = phba->ctrl_regs_memmap_p + HS_REG_OFFSET; - phba->HCregaddr = phba->ctrl_regs_memmap_p + HC_REG_OFFSET; + /* Create SCSI host to the physical port */ + error = lpfc_create_shost(phba); + if (error) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "1407 Failed to create scsi host.\n"); + goto out_unset_driver_resource; + } /* Configure sysfs attributes */ - if (lpfc_alloc_sysfs_attr(vport)) { + vport = phba->pport; + error = lpfc_alloc_sysfs_attr(vport); + if (error) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "1476 Failed to allocate sysfs attr\n"); - error = -ENOMEM; - goto out_destroy_port; + goto out_destroy_shost; } + /* Now, trying to enable interrupt and bring up the device */ cfg_mode = phba->cfg_use_msi; while (true) { + /* Put device to a known state before enabling interrupt */ + lpfc_stop_port(phba); /* Configure and enable interrupt */ - intr_mode = lpfc_enable_intr(phba, cfg_mode); + intr_mode = lpfc_sli_enable_intr(phba, cfg_mode); if (intr_mode == LPFC_INTR_ERROR) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0426 Failed to enable interrupt.\n"); + "0431 Failed to enable interrupt.\n"); + error = -ENODEV; goto out_free_sysfs_attr; } - /* HBA SLI setup */ + /* SLI-3 HBA setup */ if (lpfc_sli_hba_setup(phba)) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "1477 Failed to set up hba\n"); @@ -2902,185 +6794,65 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) /* Wait 50ms for the interrupts of previous mailbox commands */ msleep(50); - /* Check active interrupts received */ - if (phba->sli.slistat.sli_intr > LPFC_MSIX_VECTORS) { + /* Check active interrupts on message signaled interrupts */ + if (intr_mode == 0 || + phba->sli.slistat.sli_intr > LPFC_MSIX_VECTORS) { /* Log the current active interrupt mode */ phba->intr_mode = intr_mode; lpfc_log_intr_mode(phba, intr_mode); break; } else { lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "0451 Configure interrupt mode (%d) " + "0447 Configure interrupt mode (%d) " "failed active interrupt test.\n", intr_mode); - if (intr_mode == 0) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0479 Failed to enable " - "interrupt.\n"); - error = -ENODEV; - goto out_remove_device; - } - /* Stop HBA SLI setups */ - lpfc_stop_port(phba); /* Disable the current interrupt mode */ - lpfc_disable_intr(phba); + lpfc_sli_disable_intr(phba); /* Try next level of interrupt mode */ cfg_mode = --intr_mode; } } - /* - * hba setup may have changed the hba_queue_depth so we need to adjust - * the value of can_queue. - */ - shost->can_queue = phba->cfg_hba_queue_depth - 10; - if (phba->sli3_options & LPFC_SLI3_BG_ENABLED) { + /* Perform post initialization setup */ + lpfc_post_init_setup(phba); - if (lpfc_prot_mask && lpfc_prot_guard) { - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "1478 Registering BlockGuard with the " - "SCSI layer\n"); - - scsi_host_set_prot(shost, lpfc_prot_mask); - scsi_host_set_guard(shost, lpfc_prot_guard); - } - } - - if (!_dump_buf_data) { - int pagecnt = 10; - while (pagecnt) { - spin_lock_init(&_dump_buf_lock); - _dump_buf_data = - (char *) __get_free_pages(GFP_KERNEL, pagecnt); - if (_dump_buf_data) { - printk(KERN_ERR "BLKGRD allocated %d pages for " - "_dump_buf_data at 0x%p\n", - (1 << pagecnt), _dump_buf_data); - _dump_buf_data_order = pagecnt; - memset(_dump_buf_data, 0, ((1 << PAGE_SHIFT) - << pagecnt)); - break; - } else { - --pagecnt; - } - - } - - if (!_dump_buf_data_order) - printk(KERN_ERR "BLKGRD ERROR unable to allocate " - "memory for hexdump\n"); - - } else { - printk(KERN_ERR "BLKGRD already allocated _dump_buf_data=0x%p" - "\n", _dump_buf_data); - } - - - if (!_dump_buf_dif) { - int pagecnt = 10; - while (pagecnt) { - _dump_buf_dif = - (char *) __get_free_pages(GFP_KERNEL, pagecnt); - if (_dump_buf_dif) { - printk(KERN_ERR "BLKGRD allocated %d pages for " - "_dump_buf_dif at 0x%p\n", - (1 << pagecnt), _dump_buf_dif); - _dump_buf_dif_order = pagecnt; - memset(_dump_buf_dif, 0, ((1 << PAGE_SHIFT) - << pagecnt)); - break; - } else { - --pagecnt; - } - - } - - if (!_dump_buf_dif_order) - printk(KERN_ERR "BLKGRD ERROR unable to allocate " - "memory for hexdump\n"); - - } else { - printk(KERN_ERR "BLKGRD already allocated _dump_buf_dif=0x%p\n", - _dump_buf_dif); - } - - lpfc_host_attrib_init(shost); - - if (phba->cfg_poll & DISABLE_FCP_RING_INT) { - spin_lock_irq(shost->host_lock); - lpfc_poll_start_timer(phba); - spin_unlock_irq(shost->host_lock); - } - - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "0428 Perform SCSI scan\n"); - /* Send board arrival event to upper layer */ - adapter_event.event_type = FC_REG_ADAPTER_EVENT; - adapter_event.subcategory = LPFC_EVENT_ARRIVAL; - fc_host_post_vendor_event(shost, fc_get_event_number(), - sizeof(adapter_event), - (char *) &adapter_event, - LPFC_NL_VENDOR_ID); + /* Check if there are static vports to be created. */ + lpfc_create_static_vport(phba); return 0; out_remove_device: - spin_lock_irq(shost->host_lock); - vport->load_flag |= FC_UNLOADING; - spin_unlock_irq(shost->host_lock); - lpfc_stop_phba_timers(phba); - phba->pport->work_port_events = 0; - lpfc_disable_intr(phba); - lpfc_sli_hba_down(phba); - lpfc_sli_brdrestart(phba); + lpfc_unset_hba(phba); out_free_sysfs_attr: lpfc_free_sysfs_attr(vport); -out_destroy_port: - destroy_port(vport); -out_kthread_stop: - kthread_stop(phba->worker_thread); -out_free_iocbq: - list_for_each_entry_safe(iocbq_entry, iocbq_next, - &phba->lpfc_iocb_list, list) { - kfree(iocbq_entry); - phba->total_iocbq_bufs--; - } - lpfc_mem_free(phba); -out_free_hbqslimp: - dma_free_coherent(&pdev->dev, lpfc_sli_hbq_size(), - phba->hbqslimp.virt, phba->hbqslimp.phys); -out_free_slim: - dma_free_coherent(&pdev->dev, SLI2_SLIM_SIZE, - phba->slim2p.virt, phba->slim2p.phys); -out_iounmap: - iounmap(phba->ctrl_regs_memmap_p); -out_iounmap_slim: - iounmap(phba->slim_memmap_p); -out_idr_remove: - idr_remove(&lpfc_hba_index, phba->brd_no); +out_destroy_shost: + lpfc_destroy_shost(phba); +out_unset_driver_resource: + lpfc_unset_driver_resource_phase2(phba); +out_free_iocb_list: + lpfc_free_iocb_list(phba); +out_unset_driver_resource_s3: + lpfc_sli_driver_resource_unset(phba); +out_unset_pci_mem_s3: + lpfc_sli_pci_mem_unset(phba); +out_disable_pci_dev: + lpfc_disable_pci_dev(phba); out_free_phba: - kfree(phba); -out_release_regions: - pci_release_selected_regions(pdev, bars); -out_disable_device: - pci_disable_device(pdev); -out: - pci_set_drvdata(pdev, NULL); - if (shost) - scsi_host_put(shost); + lpfc_hba_free(phba); return error; } /** - * lpfc_pci_remove_one - lpfc PCI func to unregister device from PCI subsystem + * lpfc_pci_remove_one_s3 - PCI func to unreg SLI-3 device from PCI subsystem. * @pdev: pointer to PCI device * - * This routine is to be registered to the kernel's PCI subsystem. When an - * Emulex HBA is removed from PCI bus, it performs all the necessary cleanup - * for the HBA device to be removed from the PCI subsystem properly. + * This routine is to be called to disattach a device with SLI-3 interface + * spec from PCI subsystem. When an Emulex HBA with SLI-3 interface spec is + * removed from PCI bus, it performs all the necessary cleanup for the HBA + * device to be removed from the PCI subsystem properly. **/ static void __devexit -lpfc_pci_remove_one(struct pci_dev *pdev) +lpfc_pci_remove_one_s3(struct pci_dev *pdev) { struct Scsi_Host *shost = pci_get_drvdata(pdev); struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; @@ -3098,7 +6870,7 @@ lpfc_pci_remove_one(struct pci_dev *pdev) /* Release all the vports against this physical port */ vports = lpfc_create_vport_work_array(phba); if (vports != NULL) - for (i = 1; i <= phba->max_vpi && vports[i] != NULL; i++) + for (i = 1; i <= phba->max_vports && vports[i] != NULL; i++) fc_vport_terminate(vports[i]->fc_vport); lpfc_destroy_vport_work_array(phba, vports); @@ -3120,7 +6892,7 @@ lpfc_pci_remove_one(struct pci_dev *pdev) /* Final cleanup of txcmplq and reset the HBA */ lpfc_sli_brdrestart(phba); - lpfc_stop_phba_timers(phba); + lpfc_stop_hba_timers(phba); spin_lock_irq(&phba->hbalock); list_del_init(&vport->listentry); spin_unlock_irq(&phba->hbalock); @@ -3128,7 +6900,7 @@ lpfc_pci_remove_one(struct pci_dev *pdev) lpfc_debugfs_terminate(vport); /* Disable interrupt */ - lpfc_disable_intr(phba); + lpfc_sli_disable_intr(phba); pci_set_drvdata(pdev, NULL); scsi_host_put(shost); @@ -3138,7 +6910,7 @@ lpfc_pci_remove_one(struct pci_dev *pdev) * corresponding pools here. */ lpfc_scsi_free(phba); - lpfc_mem_free(phba); + lpfc_mem_free_all(phba); dma_free_coherent(&pdev->dev, lpfc_sli_hbq_size(), phba->hbqslimp.virt, phba->hbqslimp.phys); @@ -3151,36 +6923,35 @@ lpfc_pci_remove_one(struct pci_dev *pdev) iounmap(phba->ctrl_regs_memmap_p); iounmap(phba->slim_memmap_p); - idr_remove(&lpfc_hba_index, phba->brd_no); - - kfree(phba); + lpfc_hba_free(phba); pci_release_selected_regions(pdev, bars); pci_disable_device(pdev); } /** - * lpfc_pci_suspend_one - lpfc PCI func to suspend device for power management + * lpfc_pci_suspend_one_s3 - PCI func to suspend SLI-3 device for power mgmnt * @pdev: pointer to PCI device * @msg: power management message * - * This routine is to be registered to the kernel's PCI subsystem to support - * system Power Management (PM). When PM invokes this method, it quiesces the - * device by stopping the driver's worker thread for the device, turning off - * device's interrupt and DMA, and bring the device offline. Note that as the - * driver implements the minimum PM requirements to a power-aware driver's PM - * support for suspend/resume -- all the possible PM messages (SUSPEND, - * HIBERNATE, FREEZE) to the suspend() method call will be treated as SUSPEND - * and the driver will fully reinitialize its device during resume() method - * call, the driver will set device to PCI_D3hot state in PCI config space - * instead of setting it according to the @msg provided by the PM. + * This routine is to be called from the kernel's PCI subsystem to support + * system Power Management (PM) to device with SLI-3 interface spec. When + * PM invokes this method, it quiesces the device by stopping the driver's + * worker thread for the device, turning off device's interrupt and DMA, + * and bring the device offline. Note that as the driver implements the + * minimum PM requirements to a power-aware driver's PM support for the + * suspend/resume -- all the possible PM messages (SUSPEND, HIBERNATE, FREEZE) + * to the suspend() method call will be treated as SUSPEND and the driver will + * fully reinitialize its device during resume() method call, the driver will + * set device to PCI_D3hot state in PCI config space instead of setting it + * according to the @msg provided by the PM. * * Return code - * 0 - driver suspended the device - * Error otherwise + * 0 - driver suspended the device + * Error otherwise **/ static int -lpfc_pci_suspend_one(struct pci_dev *pdev, pm_message_t msg) +lpfc_pci_suspend_one_s3(struct pci_dev *pdev, pm_message_t msg) { struct Scsi_Host *shost = pci_get_drvdata(pdev); struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; @@ -3194,7 +6965,7 @@ lpfc_pci_suspend_one(struct pci_dev *pdev, pm_message_t msg) kthread_stop(phba->worker_thread); /* Disable interrupt from device */ - lpfc_disable_intr(phba); + lpfc_sli_disable_intr(phba); /* Save device state to PCI config space */ pci_save_state(pdev); @@ -3204,25 +6975,26 @@ lpfc_pci_suspend_one(struct pci_dev *pdev, pm_message_t msg) } /** - * lpfc_pci_resume_one - lpfc PCI func to resume device for power management + * lpfc_pci_resume_one_s3 - PCI func to resume SLI-3 device for power mgmnt * @pdev: pointer to PCI device * - * This routine is to be registered to the kernel's PCI subsystem to support - * system Power Management (PM). When PM invokes this method, it restores - * the device's PCI config space state and fully reinitializes the device - * and brings it online. Note that as the driver implements the minimum PM - * requirements to a power-aware driver's PM for suspend/resume -- all - * the possible PM messages (SUSPEND, HIBERNATE, FREEZE) to the suspend() - * method call will be treated as SUSPEND and the driver will fully - * reinitialize its device during resume() method call, the device will be - * set to PCI_D0 directly in PCI config space before restoring the state. + * This routine is to be called from the kernel's PCI subsystem to support + * system Power Management (PM) to device with SLI-3 interface spec. When PM + * invokes this method, it restores the device's PCI config space state and + * fully reinitializes the device and brings it online. Note that as the + * driver implements the minimum PM requirements to a power-aware driver's + * PM for suspend/resume -- all the possible PM messages (SUSPEND, HIBERNATE, + * FREEZE) to the suspend() method call will be treated as SUSPEND and the + * driver will fully reinitialize its device during resume() method call, + * the device will be set to PCI_D0 directly in PCI config space before + * restoring the state. * * Return code - * 0 - driver suspended the device - * Error otherwise + * 0 - driver suspended the device + * Error otherwise **/ static int -lpfc_pci_resume_one(struct pci_dev *pdev) +lpfc_pci_resume_one_s3(struct pci_dev *pdev) { struct Scsi_Host *shost = pci_get_drvdata(pdev); struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; @@ -3250,7 +7022,7 @@ lpfc_pci_resume_one(struct pci_dev *pdev) } /* Configure and enable interrupt */ - intr_mode = lpfc_enable_intr(phba, phba->intr_mode); + intr_mode = lpfc_sli_enable_intr(phba, phba->intr_mode); if (intr_mode == LPFC_INTR_ERROR) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0430 PM resume Failed to enable interrupt\n"); @@ -3269,23 +7041,24 @@ lpfc_pci_resume_one(struct pci_dev *pdev) } /** - * lpfc_io_error_detected - Driver method for handling PCI I/O error detected + * lpfc_io_error_detected_s3 - Method for handling SLI-3 device PCI I/O error * @pdev: pointer to PCI device. * @state: the current PCI connection state. * - * This routine is registered to the PCI subsystem for error handling. This - * function is called by the PCI subsystem after a PCI bus error affecting - * this device has been detected. When this function is invoked, it will - * need to stop all the I/Os and interrupt(s) to the device. Once that is - * done, it will return PCI_ERS_RESULT_NEED_RESET for the PCI subsystem to - * perform proper recovery as desired. + * This routine is called from the PCI subsystem for I/O error handling to + * device with SLI-3 interface spec. This function is called by the PCI + * subsystem after a PCI bus error affecting this device has been detected. + * When this function is invoked, it will need to stop all the I/Os and + * interrupt(s) to the device. Once that is done, it will return + * PCI_ERS_RESULT_NEED_RESET for the PCI subsystem to perform proper recovery + * as desired. * * Return codes - * PCI_ERS_RESULT_NEED_RESET - need to reset before recovery - * PCI_ERS_RESULT_DISCONNECT - device could not be recovered + * PCI_ERS_RESULT_NEED_RESET - need to reset before recovery + * PCI_ERS_RESULT_DISCONNECT - device could not be recovered **/ -static pci_ers_result_t lpfc_io_error_detected(struct pci_dev *pdev, - pci_channel_state_t state) +static pci_ers_result_t +lpfc_io_error_detected_s3(struct pci_dev *pdev, pci_channel_state_t state) { struct Scsi_Host *shost = pci_get_drvdata(pdev); struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; @@ -3312,30 +7085,32 @@ static pci_ers_result_t lpfc_io_error_detected(struct pci_dev *pdev, lpfc_sli_abort_iocb_ring(phba, pring); /* Disable interrupt */ - lpfc_disable_intr(phba); + lpfc_sli_disable_intr(phba); /* Request a slot reset. */ return PCI_ERS_RESULT_NEED_RESET; } /** - * lpfc_io_slot_reset - Restart a PCI device from scratch + * lpfc_io_slot_reset_s3 - Method for restarting PCI SLI-3 device from scratch. * @pdev: pointer to PCI device. * - * This routine is registered to the PCI subsystem for error handling. This is - * called after PCI bus has been reset to restart the PCI card from scratch, - * as if from a cold-boot. During the PCI subsystem error recovery, after the - * driver returns PCI_ERS_RESULT_NEED_RESET, the PCI subsystem will perform - * proper error recovery and then call this routine before calling the .resume - * method to recover the device. This function will initialize the HBA device, - * enable the interrupt, but it will just put the HBA to offline state without - * passing any I/O traffic. + * This routine is called from the PCI subsystem for error handling to + * device with SLI-3 interface spec. This is called after PCI bus has been + * reset to restart the PCI card from scratch, as if from a cold-boot. + * During the PCI subsystem error recovery, after driver returns + * PCI_ERS_RESULT_NEED_RESET, the PCI subsystem will perform proper error + * recovery and then call this routine before calling the .resume method + * to recover the device. This function will initialize the HBA device, + * enable the interrupt, but it will just put the HBA to offline state + * without passing any I/O traffic. * * Return codes - * PCI_ERS_RESULT_RECOVERED - the device has been recovered - * PCI_ERS_RESULT_DISCONNECT - device could not be recovered + * PCI_ERS_RESULT_RECOVERED - the device has been recovered + * PCI_ERS_RESULT_DISCONNECT - device could not be recovered */ -static pci_ers_result_t lpfc_io_slot_reset(struct pci_dev *pdev) +static pci_ers_result_t +lpfc_io_slot_reset_s3(struct pci_dev *pdev) { struct Scsi_Host *shost = pci_get_drvdata(pdev); struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; @@ -3354,11 +7129,11 @@ static pci_ers_result_t lpfc_io_slot_reset(struct pci_dev *pdev) pci_set_master(pdev); spin_lock_irq(&phba->hbalock); - psli->sli_flag &= ~LPFC_SLI2_ACTIVE; + psli->sli_flag &= ~LPFC_SLI_ACTIVE; spin_unlock_irq(&phba->hbalock); /* Configure and enable interrupt */ - intr_mode = lpfc_enable_intr(phba, phba->intr_mode); + intr_mode = lpfc_sli_enable_intr(phba, phba->intr_mode); if (intr_mode == LPFC_INTR_ERROR) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0427 Cannot re-enable interrupt after " @@ -3378,15 +7153,17 @@ static pci_ers_result_t lpfc_io_slot_reset(struct pci_dev *pdev) } /** - * lpfc_io_resume - Resume PCI I/O operation + * lpfc_io_resume_s3 - Method for resuming PCI I/O operation on SLI-3 device. * @pdev: pointer to PCI device * - * This routine is registered to the PCI subsystem for error handling. It is - * called when kernel error recovery tells the lpfc driver that it is ok to - * resume normal PCI operation after PCI bus error recovery. After this call, - * traffic can start to flow from this device again. + * This routine is called from the PCI subsystem for error handling to device + * with SLI-3 interface spec. It is called when kernel error recovery tells + * the lpfc driver that it is ok to resume normal PCI operation after PCI bus + * error recovery. After this call, traffic can start to flow from this device + * again. */ -static void lpfc_io_resume(struct pci_dev *pdev) +static void +lpfc_io_resume_s3(struct pci_dev *pdev) { struct Scsi_Host *shost = pci_get_drvdata(pdev); struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; @@ -3394,6 +7171,699 @@ static void lpfc_io_resume(struct pci_dev *pdev) lpfc_online(phba); } +/** + * lpfc_sli4_get_els_iocb_cnt - Calculate the # of ELS IOCBs to reserve + * @phba: pointer to lpfc hba data structure. + * + * returns the number of ELS/CT IOCBs to reserve + **/ +int +lpfc_sli4_get_els_iocb_cnt(struct lpfc_hba *phba) +{ + int max_xri = phba->sli4_hba.max_cfg_param.max_xri; + + if (phba->sli_rev == LPFC_SLI_REV4) { + if (max_xri <= 100) + return 4; + else if (max_xri <= 256) + return 8; + else if (max_xri <= 512) + return 16; + else if (max_xri <= 1024) + return 32; + else + return 48; + } else + return 0; +} + +/** + * lpfc_pci_probe_one_s4 - PCI probe func to reg SLI-4 device to PCI subsys + * @pdev: pointer to PCI device + * @pid: pointer to PCI device identifier + * + * This routine is called from the kernel's PCI subsystem to device with + * SLI-4 interface spec. When an Emulex HBA with SLI-4 interface spec is + * presented on PCI bus, the kernel PCI subsystem looks at PCI device-specific + * information of the device and driver to see if the driver state that it + * can support this kind of device. If the match is successful, the driver + * core invokes this routine. If this routine determines it can claim the HBA, + * it does all the initialization that it needs to do to handle the HBA + * properly. + * + * Return code + * 0 - driver can claim the device + * negative value - driver can not claim the device + **/ +static int __devinit +lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid) +{ + struct lpfc_hba *phba; + struct lpfc_vport *vport = NULL; + int error; + uint32_t cfg_mode, intr_mode; + int mcnt; + + /* Allocate memory for HBA structure */ + phba = lpfc_hba_alloc(pdev); + if (!phba) + return -ENOMEM; + + /* Perform generic PCI device enabling operation */ + error = lpfc_enable_pci_dev(phba); + if (error) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "1409 Failed to enable pci device.\n"); + goto out_free_phba; + } + + /* Set up SLI API function jump table for PCI-device group-1 HBAs */ + error = lpfc_api_table_setup(phba, LPFC_PCI_DEV_OC); + if (error) + goto out_disable_pci_dev; + + /* Set up SLI-4 specific device PCI memory space */ + error = lpfc_sli4_pci_mem_setup(phba); + if (error) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "1410 Failed to set up pci memory space.\n"); + goto out_disable_pci_dev; + } + + /* Set up phase-1 common device driver resources */ + error = lpfc_setup_driver_resource_phase1(phba); + if (error) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "1411 Failed to set up driver resource.\n"); + goto out_unset_pci_mem_s4; + } + + /* Set up SLI-4 Specific device driver resources */ + error = lpfc_sli4_driver_resource_setup(phba); + if (error) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "1412 Failed to set up driver resource.\n"); + goto out_unset_pci_mem_s4; + } + + /* Initialize and populate the iocb list per host */ + error = lpfc_init_iocb_list(phba, + phba->sli4_hba.max_cfg_param.max_xri); + if (error) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "1413 Failed to initialize iocb list.\n"); + goto out_unset_driver_resource_s4; + } + + /* Set up common device driver resources */ + error = lpfc_setup_driver_resource_phase2(phba); + if (error) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "1414 Failed to set up driver resource.\n"); + goto out_free_iocb_list; + } + + /* Create SCSI host to the physical port */ + error = lpfc_create_shost(phba); + if (error) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "1415 Failed to create scsi host.\n"); + goto out_unset_driver_resource; + } + + /* Configure sysfs attributes */ + vport = phba->pport; + error = lpfc_alloc_sysfs_attr(vport); + if (error) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "1416 Failed to allocate sysfs attr\n"); + goto out_destroy_shost; + } + + /* Now, trying to enable interrupt and bring up the device */ + cfg_mode = phba->cfg_use_msi; + while (true) { + /* Put device to a known state before enabling interrupt */ + lpfc_stop_port(phba); + /* Configure and enable interrupt */ + intr_mode = lpfc_sli4_enable_intr(phba, cfg_mode); + if (intr_mode == LPFC_INTR_ERROR) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0426 Failed to enable interrupt.\n"); + error = -ENODEV; + goto out_free_sysfs_attr; + } + /* Set up SLI-4 HBA */ + if (lpfc_sli4_hba_setup(phba)) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "1421 Failed to set up hba\n"); + error = -ENODEV; + goto out_disable_intr; + } + + /* Send NOP mbx cmds for non-INTx mode active interrupt test */ + if (intr_mode != 0) + mcnt = lpfc_sli4_send_nop_mbox_cmds(phba, + LPFC_ACT_INTR_CNT); + + /* Check active interrupts received only for MSI/MSI-X */ + if (intr_mode == 0 || + phba->sli.slistat.sli_intr >= LPFC_ACT_INTR_CNT) { + /* Log the current active interrupt mode */ + phba->intr_mode = intr_mode; + lpfc_log_intr_mode(phba, intr_mode); + break; + } + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "0451 Configure interrupt mode (%d) " + "failed active interrupt test.\n", + intr_mode); + /* Unset the preivous SLI-4 HBA setup */ + lpfc_sli4_unset_hba(phba); + /* Try next level of interrupt mode */ + cfg_mode = --intr_mode; + } + + /* Perform post initialization setup */ + lpfc_post_init_setup(phba); + + return 0; + +out_disable_intr: + lpfc_sli4_disable_intr(phba); +out_free_sysfs_attr: + lpfc_free_sysfs_attr(vport); +out_destroy_shost: + lpfc_destroy_shost(phba); +out_unset_driver_resource: + lpfc_unset_driver_resource_phase2(phba); +out_free_iocb_list: + lpfc_free_iocb_list(phba); +out_unset_driver_resource_s4: + lpfc_sli4_driver_resource_unset(phba); +out_unset_pci_mem_s4: + lpfc_sli4_pci_mem_unset(phba); +out_disable_pci_dev: + lpfc_disable_pci_dev(phba); +out_free_phba: + lpfc_hba_free(phba); + return error; +} + +/** + * lpfc_pci_remove_one_s4 - PCI func to unreg SLI-4 device from PCI subsystem + * @pdev: pointer to PCI device + * + * This routine is called from the kernel's PCI subsystem to device with + * SLI-4 interface spec. When an Emulex HBA with SLI-4 interface spec is + * removed from PCI bus, it performs all the necessary cleanup for the HBA + * device to be removed from the PCI subsystem properly. + **/ +static void __devexit +lpfc_pci_remove_one_s4(struct pci_dev *pdev) +{ + struct Scsi_Host *shost = pci_get_drvdata(pdev); + struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; + struct lpfc_vport **vports; + struct lpfc_hba *phba = vport->phba; + int i; + + /* Mark the device unloading flag */ + spin_lock_irq(&phba->hbalock); + vport->load_flag |= FC_UNLOADING; + spin_unlock_irq(&phba->hbalock); + + /* Free the HBA sysfs attributes */ + lpfc_free_sysfs_attr(vport); + + /* Release all the vports against this physical port */ + vports = lpfc_create_vport_work_array(phba); + if (vports != NULL) + for (i = 1; i <= phba->max_vports && vports[i] != NULL; i++) + fc_vport_terminate(vports[i]->fc_vport); + lpfc_destroy_vport_work_array(phba, vports); + + /* Remove FC host and then SCSI host with the physical port */ + fc_remove_host(shost); + scsi_remove_host(shost); + + /* Perform cleanup on the physical port */ + lpfc_cleanup(vport); + + /* + * Bring down the SLI Layer. This step disables all interrupts, + * clears the rings, discards all mailbox commands, and resets + * the HBA FCoE function. + */ + lpfc_debugfs_terminate(vport); + lpfc_sli4_hba_unset(phba); + + spin_lock_irq(&phba->hbalock); + list_del_init(&vport->listentry); + spin_unlock_irq(&phba->hbalock); + + /* Call scsi_free before lpfc_sli4_driver_resource_unset since scsi + * buffers are released to their corresponding pools here. + */ + lpfc_scsi_free(phba); + lpfc_sli4_driver_resource_unset(phba); + + /* Unmap adapter Control and Doorbell registers */ + lpfc_sli4_pci_mem_unset(phba); + + /* Release PCI resources and disable device's PCI function */ + scsi_host_put(shost); + lpfc_disable_pci_dev(phba); + + /* Finally, free the driver's device data structure */ + lpfc_hba_free(phba); + + return; +} + +/** + * lpfc_pci_suspend_one_s4 - PCI func to suspend SLI-4 device for power mgmnt + * @pdev: pointer to PCI device + * @msg: power management message + * + * This routine is called from the kernel's PCI subsystem to support system + * Power Management (PM) to device with SLI-4 interface spec. When PM invokes + * this method, it quiesces the device by stopping the driver's worker + * thread for the device, turning off device's interrupt and DMA, and bring + * the device offline. Note that as the driver implements the minimum PM + * requirements to a power-aware driver's PM support for suspend/resume -- all + * the possible PM messages (SUSPEND, HIBERNATE, FREEZE) to the suspend() + * method call will be treated as SUSPEND and the driver will fully + * reinitialize its device during resume() method call, the driver will set + * device to PCI_D3hot state in PCI config space instead of setting it + * according to the @msg provided by the PM. + * + * Return code + * 0 - driver suspended the device + * Error otherwise + **/ +static int +lpfc_pci_suspend_one_s4(struct pci_dev *pdev, pm_message_t msg) +{ + struct Scsi_Host *shost = pci_get_drvdata(pdev); + struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; + + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "0298 PCI device Power Management suspend.\n"); + + /* Bring down the device */ + lpfc_offline_prep(phba); + lpfc_offline(phba); + kthread_stop(phba->worker_thread); + + /* Disable interrupt from device */ + lpfc_sli4_disable_intr(phba); + + /* Save device state to PCI config space */ + pci_save_state(pdev); + pci_set_power_state(pdev, PCI_D3hot); + + return 0; +} + +/** + * lpfc_pci_resume_one_s4 - PCI func to resume SLI-4 device for power mgmnt + * @pdev: pointer to PCI device + * + * This routine is called from the kernel's PCI subsystem to support system + * Power Management (PM) to device with SLI-4 interface spac. When PM invokes + * this method, it restores the device's PCI config space state and fully + * reinitializes the device and brings it online. Note that as the driver + * implements the minimum PM requirements to a power-aware driver's PM for + * suspend/resume -- all the possible PM messages (SUSPEND, HIBERNATE, FREEZE) + * to the suspend() method call will be treated as SUSPEND and the driver + * will fully reinitialize its device during resume() method call, the device + * will be set to PCI_D0 directly in PCI config space before restoring the + * state. + * + * Return code + * 0 - driver suspended the device + * Error otherwise + **/ +static int +lpfc_pci_resume_one_s4(struct pci_dev *pdev) +{ + struct Scsi_Host *shost = pci_get_drvdata(pdev); + struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; + uint32_t intr_mode; + int error; + + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "0292 PCI device Power Management resume.\n"); + + /* Restore device state from PCI config space */ + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + if (pdev->is_busmaster) + pci_set_master(pdev); + + /* Startup the kernel thread for this host adapter. */ + phba->worker_thread = kthread_run(lpfc_do_work, phba, + "lpfc_worker_%d", phba->brd_no); + if (IS_ERR(phba->worker_thread)) { + error = PTR_ERR(phba->worker_thread); + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0293 PM resume failed to start worker " + "thread: error=x%x.\n", error); + return error; + } + + /* Configure and enable interrupt */ + intr_mode = lpfc_sli4_enable_intr(phba, phba->intr_mode); + if (intr_mode == LPFC_INTR_ERROR) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0294 PM resume Failed to enable interrupt\n"); + return -EIO; + } else + phba->intr_mode = intr_mode; + + /* Restart HBA and bring it online */ + lpfc_sli_brdrestart(phba); + lpfc_online(phba); + + /* Log the current active interrupt mode */ + lpfc_log_intr_mode(phba, phba->intr_mode); + + return 0; +} + +/** + * lpfc_io_error_detected_s4 - Method for handling PCI I/O error to SLI-4 device + * @pdev: pointer to PCI device. + * @state: the current PCI connection state. + * + * This routine is called from the PCI subsystem for error handling to device + * with SLI-4 interface spec. This function is called by the PCI subsystem + * after a PCI bus error affecting this device has been detected. When this + * function is invoked, it will need to stop all the I/Os and interrupt(s) + * to the device. Once that is done, it will return PCI_ERS_RESULT_NEED_RESET + * for the PCI subsystem to perform proper recovery as desired. + * + * Return codes + * PCI_ERS_RESULT_NEED_RESET - need to reset before recovery + * PCI_ERS_RESULT_DISCONNECT - device could not be recovered + **/ +static pci_ers_result_t +lpfc_io_error_detected_s4(struct pci_dev *pdev, pci_channel_state_t state) +{ + return PCI_ERS_RESULT_NEED_RESET; +} + +/** + * lpfc_io_slot_reset_s4 - Method for restart PCI SLI-4 device from scratch + * @pdev: pointer to PCI device. + * + * This routine is called from the PCI subsystem for error handling to device + * with SLI-4 interface spec. It is called after PCI bus has been reset to + * restart the PCI card from scratch, as if from a cold-boot. During the + * PCI subsystem error recovery, after the driver returns + * PCI_ERS_RESULT_NEED_RESET, the PCI subsystem will perform proper error + * recovery and then call this routine before calling the .resume method to + * recover the device. This function will initialize the HBA device, enable + * the interrupt, but it will just put the HBA to offline state without + * passing any I/O traffic. + * + * Return codes + * PCI_ERS_RESULT_RECOVERED - the device has been recovered + * PCI_ERS_RESULT_DISCONNECT - device could not be recovered + */ +static pci_ers_result_t +lpfc_io_slot_reset_s4(struct pci_dev *pdev) +{ + return PCI_ERS_RESULT_RECOVERED; +} + +/** + * lpfc_io_resume_s4 - Method for resuming PCI I/O operation to SLI-4 device + * @pdev: pointer to PCI device + * + * This routine is called from the PCI subsystem for error handling to device + * with SLI-4 interface spec. It is called when kernel error recovery tells + * the lpfc driver that it is ok to resume normal PCI operation after PCI bus + * error recovery. After this call, traffic can start to flow from this device + * again. + **/ +static void +lpfc_io_resume_s4(struct pci_dev *pdev) +{ + return; +} + +/** + * lpfc_pci_probe_one - lpfc PCI probe func to reg dev to PCI subsystem + * @pdev: pointer to PCI device + * @pid: pointer to PCI device identifier + * + * This routine is to be registered to the kernel's PCI subsystem. When an + * Emulex HBA device is presented on PCI bus, the kernel PCI subsystem looks + * at PCI device-specific information of the device and driver to see if the + * driver state that it can support this kind of device. If the match is + * successful, the driver core invokes this routine. This routine dispatches + * the action to the proper SLI-3 or SLI-4 device probing routine, which will + * do all the initialization that it needs to do to handle the HBA device + * properly. + * + * Return code + * 0 - driver can claim the device + * negative value - driver can not claim the device + **/ +static int __devinit +lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) +{ + int rc; + uint16_t dev_id; + + if (pci_read_config_word(pdev, PCI_DEVICE_ID, &dev_id)) + return -ENODEV; + + switch (dev_id) { + case PCI_DEVICE_ID_TIGERSHARK: + rc = lpfc_pci_probe_one_s4(pdev, pid); + break; + default: + rc = lpfc_pci_probe_one_s3(pdev, pid); + break; + } + return rc; +} + +/** + * lpfc_pci_remove_one - lpfc PCI func to unreg dev from PCI subsystem + * @pdev: pointer to PCI device + * + * This routine is to be registered to the kernel's PCI subsystem. When an + * Emulex HBA is removed from PCI bus, the driver core invokes this routine. + * This routine dispatches the action to the proper SLI-3 or SLI-4 device + * remove routine, which will perform all the necessary cleanup for the + * device to be removed from the PCI subsystem properly. + **/ +static void __devexit +lpfc_pci_remove_one(struct pci_dev *pdev) +{ + struct Scsi_Host *shost = pci_get_drvdata(pdev); + struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; + + switch (phba->pci_dev_grp) { + case LPFC_PCI_DEV_LP: + lpfc_pci_remove_one_s3(pdev); + break; + case LPFC_PCI_DEV_OC: + lpfc_pci_remove_one_s4(pdev); + break; + default: + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "1424 Invalid PCI device group: 0x%x\n", + phba->pci_dev_grp); + break; + } + return; +} + +/** + * lpfc_pci_suspend_one - lpfc PCI func to suspend dev for power management + * @pdev: pointer to PCI device + * @msg: power management message + * + * This routine is to be registered to the kernel's PCI subsystem to support + * system Power Management (PM). When PM invokes this method, it dispatches + * the action to the proper SLI-3 or SLI-4 device suspend routine, which will + * suspend the device. + * + * Return code + * 0 - driver suspended the device + * Error otherwise + **/ +static int +lpfc_pci_suspend_one(struct pci_dev *pdev, pm_message_t msg) +{ + struct Scsi_Host *shost = pci_get_drvdata(pdev); + struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; + int rc = -ENODEV; + + switch (phba->pci_dev_grp) { + case LPFC_PCI_DEV_LP: + rc = lpfc_pci_suspend_one_s3(pdev, msg); + break; + case LPFC_PCI_DEV_OC: + rc = lpfc_pci_suspend_one_s4(pdev, msg); + break; + default: + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "1425 Invalid PCI device group: 0x%x\n", + phba->pci_dev_grp); + break; + } + return rc; +} + +/** + * lpfc_pci_resume_one - lpfc PCI func to resume dev for power management + * @pdev: pointer to PCI device + * + * This routine is to be registered to the kernel's PCI subsystem to support + * system Power Management (PM). When PM invokes this method, it dispatches + * the action to the proper SLI-3 or SLI-4 device resume routine, which will + * resume the device. + * + * Return code + * 0 - driver suspended the device + * Error otherwise + **/ +static int +lpfc_pci_resume_one(struct pci_dev *pdev) +{ + struct Scsi_Host *shost = pci_get_drvdata(pdev); + struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; + int rc = -ENODEV; + + switch (phba->pci_dev_grp) { + case LPFC_PCI_DEV_LP: + rc = lpfc_pci_resume_one_s3(pdev); + break; + case LPFC_PCI_DEV_OC: + rc = lpfc_pci_resume_one_s4(pdev); + break; + default: + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "1426 Invalid PCI device group: 0x%x\n", + phba->pci_dev_grp); + break; + } + return rc; +} + +/** + * lpfc_io_error_detected - lpfc method for handling PCI I/O error + * @pdev: pointer to PCI device. + * @state: the current PCI connection state. + * + * This routine is registered to the PCI subsystem for error handling. This + * function is called by the PCI subsystem after a PCI bus error affecting + * this device has been detected. When this routine is invoked, it dispatches + * the action to the proper SLI-3 or SLI-4 device error detected handling + * routine, which will perform the proper error detected operation. + * + * Return codes + * PCI_ERS_RESULT_NEED_RESET - need to reset before recovery + * PCI_ERS_RESULT_DISCONNECT - device could not be recovered + **/ +static pci_ers_result_t +lpfc_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state) +{ + struct Scsi_Host *shost = pci_get_drvdata(pdev); + struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; + pci_ers_result_t rc = PCI_ERS_RESULT_DISCONNECT; + + switch (phba->pci_dev_grp) { + case LPFC_PCI_DEV_LP: + rc = lpfc_io_error_detected_s3(pdev, state); + break; + case LPFC_PCI_DEV_OC: + rc = lpfc_io_error_detected_s4(pdev, state); + break; + default: + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "1427 Invalid PCI device group: 0x%x\n", + phba->pci_dev_grp); + break; + } + return rc; +} + +/** + * lpfc_io_slot_reset - lpfc method for restart PCI dev from scratch + * @pdev: pointer to PCI device. + * + * This routine is registered to the PCI subsystem for error handling. This + * function is called after PCI bus has been reset to restart the PCI card + * from scratch, as if from a cold-boot. When this routine is invoked, it + * dispatches the action to the proper SLI-3 or SLI-4 device reset handling + * routine, which will perform the proper device reset. + * + * Return codes + * PCI_ERS_RESULT_RECOVERED - the device has been recovered + * PCI_ERS_RESULT_DISCONNECT - device could not be recovered + **/ +static pci_ers_result_t +lpfc_io_slot_reset(struct pci_dev *pdev) +{ + struct Scsi_Host *shost = pci_get_drvdata(pdev); + struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; + pci_ers_result_t rc = PCI_ERS_RESULT_DISCONNECT; + + switch (phba->pci_dev_grp) { + case LPFC_PCI_DEV_LP: + rc = lpfc_io_slot_reset_s3(pdev); + break; + case LPFC_PCI_DEV_OC: + rc = lpfc_io_slot_reset_s4(pdev); + break; + default: + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "1428 Invalid PCI device group: 0x%x\n", + phba->pci_dev_grp); + break; + } + return rc; +} + +/** + * lpfc_io_resume - lpfc method for resuming PCI I/O operation + * @pdev: pointer to PCI device + * + * This routine is registered to the PCI subsystem for error handling. It + * is called when kernel error recovery tells the lpfc driver that it is + * OK to resume normal PCI operation after PCI bus error recovery. When + * this routine is invoked, it dispatches the action to the proper SLI-3 + * or SLI-4 device io_resume routine, which will resume the device operation. + **/ +static void +lpfc_io_resume(struct pci_dev *pdev) +{ + struct Scsi_Host *shost = pci_get_drvdata(pdev); + struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; + + switch (phba->pci_dev_grp) { + case LPFC_PCI_DEV_LP: + lpfc_io_resume_s3(pdev); + break; + case LPFC_PCI_DEV_OC: + lpfc_io_resume_s4(pdev); + break; + default: + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "1429 Invalid PCI device group: 0x%x\n", + phba->pci_dev_grp); + break; + } + return; +} + static struct pci_device_id lpfc_id_table[] = { {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_VIPER, PCI_ANY_ID, PCI_ANY_ID, }, @@ -3469,6 +7939,8 @@ static struct pci_device_id lpfc_id_table[] = { PCI_ANY_ID, PCI_ANY_ID, }, {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_PROTEUS_S, PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_SERVERENGINE, PCI_DEVICE_ID_TIGERSHARK, + PCI_ANY_ID, PCI_ANY_ID, }, { 0 } }; @@ -3486,7 +7958,7 @@ static struct pci_driver lpfc_driver = { .probe = lpfc_pci_probe_one, .remove = __devexit_p(lpfc_pci_remove_one), .suspend = lpfc_pci_suspend_one, - .resume = lpfc_pci_resume_one, + .resume = lpfc_pci_resume_one, .err_handler = &lpfc_err_handler, }; diff --git a/drivers/scsi/lpfc/lpfc_logmsg.h b/drivers/scsi/lpfc/lpfc_logmsg.h index 1aa85709b012..954ba57970a3 100644 --- a/drivers/scsi/lpfc/lpfc_logmsg.h +++ b/drivers/scsi/lpfc/lpfc_logmsg.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2008 Emulex. All rights reserved. * + * Copyright (C) 2004-2009 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * @@ -18,33 +18,39 @@ * included with this package. * *******************************************************************/ -#define LOG_ELS 0x1 /* ELS events */ -#define LOG_DISCOVERY 0x2 /* Link discovery events */ -#define LOG_MBOX 0x4 /* Mailbox events */ -#define LOG_INIT 0x8 /* Initialization events */ -#define LOG_LINK_EVENT 0x10 /* Link events */ -#define LOG_IP 0x20 /* IP traffic history */ -#define LOG_FCP 0x40 /* FCP traffic history */ -#define LOG_NODE 0x80 /* Node table events */ -#define LOG_TEMP 0x100 /* Temperature sensor events */ -#define LOG_BG 0x200 /* BlockGuard events */ -#define LOG_MISC 0x400 /* Miscellaneous events */ -#define LOG_SLI 0x800 /* SLI events */ -#define LOG_FCP_ERROR 0x1000 /* log errors, not underruns */ -#define LOG_LIBDFC 0x2000 /* Libdfc events */ -#define LOG_VPORT 0x4000 /* NPIV events */ -#define LOG_ALL_MSG 0xffff /* LOG all messages */ +#define LOG_ELS 0x00000001 /* ELS events */ +#define LOG_DISCOVERY 0x00000002 /* Link discovery events */ +#define LOG_MBOX 0x00000004 /* Mailbox events */ +#define LOG_INIT 0x00000008 /* Initialization events */ +#define LOG_LINK_EVENT 0x00000010 /* Link events */ +#define LOG_IP 0x00000020 /* IP traffic history */ +#define LOG_FCP 0x00000040 /* FCP traffic history */ +#define LOG_NODE 0x00000080 /* Node table events */ +#define LOG_TEMP 0x00000100 /* Temperature sensor events */ +#define LOG_BG 0x00000200 /* BlockGuard events */ +#define LOG_MISC 0x00000400 /* Miscellaneous events */ +#define LOG_SLI 0x00000800 /* SLI events */ +#define LOG_FCP_ERROR 0x00001000 /* log errors, not underruns */ +#define LOG_LIBDFC 0x00002000 /* Libdfc events */ +#define LOG_VPORT 0x00004000 /* NPIV events */ +#define LOF_SECURITY 0x00008000 /* Security events */ +#define LOG_EVENT 0x00010000 /* CT,TEMP,DUMP, logging */ +#define LOG_ALL_MSG 0xffffffff /* LOG all messages */ #define lpfc_printf_vlog(vport, level, mask, fmt, arg...) \ - do { \ - { if (((mask) &(vport)->cfg_log_verbose) || (level[1] <= '3')) \ +do { \ + { if (((mask) & (vport)->cfg_log_verbose) || (level[1] <= '3')) \ dev_printk(level, &((vport)->phba->pcidev)->dev, "%d:(%d):" \ fmt, (vport)->phba->brd_no, vport->vpi, ##arg); } \ - } while (0) +} while (0) #define lpfc_printf_log(phba, level, mask, fmt, arg...) \ - do { \ - { if (((mask) &(phba)->pport->cfg_log_verbose) || (level[1] <= '3')) \ +do { \ + { uint32_t log_verbose = (phba)->pport ? \ + (phba)->pport->cfg_log_verbose : \ + (phba)->cfg_log_verbose; \ + if (((mask) & log_verbose) || (level[1] <= '3')) \ dev_printk(level, &((phba)->pcidev)->dev, "%d:" \ - fmt, phba->brd_no, ##arg); } \ - } while (0) + fmt, phba->brd_no, ##arg); \ + } \ +} while (0) diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index 134fc7fc2127..3423571dd1b3 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2008 Emulex. All rights reserved. * + * Copyright (C) 2004-2009 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -28,8 +28,10 @@ #include +#include "lpfc_hw4.h" #include "lpfc_hw.h" #include "lpfc_sli.h" +#include "lpfc_sli4.h" #include "lpfc_nl.h" #include "lpfc_disc.h" #include "lpfc_scsi.h" @@ -38,6 +40,44 @@ #include "lpfc_crtn.h" #include "lpfc_compat.h" +/** + * lpfc_dump_static_vport - Dump HBA's static vport information. + * @phba: pointer to lpfc hba data structure. + * @pmb: pointer to the driver internal queue element for mailbox command. + * @offset: offset for dumping vport info. + * + * The dump mailbox command provides a method for the device driver to obtain + * various types of information from the HBA device. + * + * This routine prepares the mailbox command for dumping list of static + * vports to be created. + **/ +void +lpfc_dump_static_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb, + uint16_t offset) +{ + MAILBOX_t *mb; + void *ctx; + + mb = &pmb->u.mb; + ctx = pmb->context2; + + /* Setup to dump vport info region */ + memset(pmb, 0, sizeof(LPFC_MBOXQ_t)); + mb->mbxCommand = MBX_DUMP_MEMORY; + mb->un.varDmp.cv = 1; + mb->un.varDmp.type = DMP_NV_PARAMS; + mb->un.varDmp.entry_index = offset; + mb->un.varDmp.region_id = DMP_REGION_VPORT; + mb->un.varDmp.word_cnt = DMP_RSP_SIZE/sizeof(uint32_t); + mb->un.varDmp.co = 0; + mb->un.varDmp.resp_offset = 0; + pmb->context2 = ctx; + mb->mbxOwner = OWN_HOST; + + return; +} + /** * lpfc_dump_mem - Prepare a mailbox command for retrieving HBA's VPD memory * @phba: pointer to lpfc hba data structure. @@ -58,7 +98,7 @@ lpfc_dump_mem(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb, uint16_t offset) MAILBOX_t *mb; void *ctx; - mb = &pmb->mb; + mb = &pmb->u.mb; ctx = pmb->context2; /* Setup to dump VPD region */ @@ -90,7 +130,7 @@ lpfc_dump_wakeup_param(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) MAILBOX_t *mb; void *ctx; - mb = &pmb->mb; + mb = &pmb->u.mb; /* Save context so that we can restore after memset */ ctx = pmb->context2; @@ -125,7 +165,7 @@ lpfc_read_nv(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) { MAILBOX_t *mb; - mb = &pmb->mb; + mb = &pmb->u.mb; memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); mb->mbxCommand = MBX_READ_NV; mb->mbxOwner = OWN_HOST; @@ -151,7 +191,7 @@ lpfc_config_async(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb, { MAILBOX_t *mb; - mb = &pmb->mb; + mb = &pmb->u.mb; memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); mb->mbxCommand = MBX_ASYNCEVT_ENABLE; mb->un.varCfgAsyncEvent.ring = ring; @@ -177,7 +217,7 @@ lpfc_heart_beat(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) { MAILBOX_t *mb; - mb = &pmb->mb; + mb = &pmb->u.mb; memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); mb->mbxCommand = MBX_HEARTBEAT; mb->mbxOwner = OWN_HOST; @@ -211,7 +251,7 @@ lpfc_read_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb, struct lpfc_dmabuf *mp) struct lpfc_sli *psli; psli = &phba->sli; - mb = &pmb->mb; + mb = &pmb->u.mb; memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); INIT_LIST_HEAD(&mp->list); @@ -248,7 +288,7 @@ lpfc_clear_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) { MAILBOX_t *mb; - mb = &pmb->mb; + mb = &pmb->u.mb; memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); mb->un.varClearLA.eventTag = phba->fc_eventTag; @@ -275,7 +315,7 @@ void lpfc_config_link(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) { struct lpfc_vport *vport = phba->pport; - MAILBOX_t *mb = &pmb->mb; + MAILBOX_t *mb = &pmb->u.mb; memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); /* NEW_FEATURE @@ -321,7 +361,7 @@ lpfc_config_link(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) int lpfc_config_msi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { - MAILBOX_t *mb = &pmb->mb; + MAILBOX_t *mb = &pmb->u.mb; uint32_t attentionConditions[2]; /* Sanity check */ @@ -405,7 +445,7 @@ lpfc_init_link(struct lpfc_hba * phba, struct lpfc_sli *psli; MAILBOX_t *mb; - mb = &pmb->mb; + mb = &pmb->u.mb; memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); psli = &phba->sli; @@ -492,7 +532,7 @@ lpfc_read_sparam(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb, int vpi) struct lpfc_sli *psli; psli = &phba->sli; - mb = &pmb->mb; + mb = &pmb->u.mb; memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); mb->mbxOwner = OWN_HOST; @@ -515,7 +555,7 @@ lpfc_read_sparam(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb, int vpi) mb->un.varRdSparm.un.sp64.tus.f.bdeSize = sizeof (struct serv_parm); mb->un.varRdSparm.un.sp64.addrHigh = putPaddrHigh(mp->phys); mb->un.varRdSparm.un.sp64.addrLow = putPaddrLow(mp->phys); - mb->un.varRdSparm.vpi = vpi; + mb->un.varRdSparm.vpi = vpi + phba->vpi_base; /* save address for completion */ pmb->context1 = mp; @@ -544,10 +584,12 @@ lpfc_unreg_did(struct lpfc_hba * phba, uint16_t vpi, uint32_t did, { MAILBOX_t *mb; - mb = &pmb->mb; + mb = &pmb->u.mb; memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); mb->un.varUnregDID.did = did; + if (vpi != 0xffff) + vpi += phba->vpi_base; mb->un.varUnregDID.vpi = vpi; mb->mbxCommand = MBX_UNREG_D_ID; @@ -573,7 +615,7 @@ lpfc_read_config(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) { MAILBOX_t *mb; - mb = &pmb->mb; + mb = &pmb->u.mb; memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); mb->mbxCommand = MBX_READ_CONFIG; @@ -598,7 +640,7 @@ lpfc_read_lnk_stat(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) { MAILBOX_t *mb; - mb = &pmb->mb; + mb = &pmb->u.mb; memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); mb->mbxCommand = MBX_READ_LNK_STAT; @@ -607,7 +649,7 @@ lpfc_read_lnk_stat(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) } /** - * lpfc_reg_login - Prepare a mailbox command for registering remote login + * lpfc_reg_rpi - Prepare a mailbox command for registering remote login * @phba: pointer to lpfc hba data structure. * @vpi: virtual N_Port identifier. * @did: remote port identifier. @@ -631,17 +673,23 @@ lpfc_read_lnk_stat(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) * 1 - DMA memory allocation failed **/ int -lpfc_reg_login(struct lpfc_hba *phba, uint16_t vpi, uint32_t did, +lpfc_reg_rpi(struct lpfc_hba *phba, uint16_t vpi, uint32_t did, uint8_t *param, LPFC_MBOXQ_t *pmb, uint32_t flag) { - MAILBOX_t *mb = &pmb->mb; + MAILBOX_t *mb = &pmb->u.mb; uint8_t *sparam; struct lpfc_dmabuf *mp; memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); mb->un.varRegLogin.rpi = 0; - mb->un.varRegLogin.vpi = vpi; + if (phba->sli_rev == LPFC_SLI_REV4) { + mb->un.varRegLogin.rpi = lpfc_sli4_alloc_rpi(phba); + if (mb->un.varRegLogin.rpi == LPFC_RPI_ALLOC_ERROR) + return 1; + } + + mb->un.varRegLogin.vpi = vpi + phba->vpi_base; mb->un.varRegLogin.did = did; mb->un.varWords[30] = flag; /* Set flag to issue action on cmpl */ @@ -697,15 +745,16 @@ lpfc_unreg_login(struct lpfc_hba *phba, uint16_t vpi, uint32_t rpi, { MAILBOX_t *mb; - mb = &pmb->mb; + mb = &pmb->u.mb; memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); mb->un.varUnregLogin.rpi = (uint16_t) rpi; mb->un.varUnregLogin.rsvd1 = 0; - mb->un.varUnregLogin.vpi = vpi; + mb->un.varUnregLogin.vpi = vpi + phba->vpi_base; mb->mbxCommand = MBX_UNREG_LOGIN; mb->mbxOwner = OWN_HOST; + return; } @@ -725,15 +774,15 @@ lpfc_unreg_login(struct lpfc_hba *phba, uint16_t vpi, uint32_t rpi, * This routine prepares the mailbox command for registering a virtual N_Port. **/ void -lpfc_reg_vpi(struct lpfc_hba *phba, uint16_t vpi, uint32_t sid, - LPFC_MBOXQ_t *pmb) +lpfc_reg_vpi(struct lpfc_vport *vport, LPFC_MBOXQ_t *pmb) { - MAILBOX_t *mb = &pmb->mb; + MAILBOX_t *mb = &pmb->u.mb; memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); - mb->un.varRegVpi.vpi = vpi; - mb->un.varRegVpi.sid = sid; + mb->un.varRegVpi.vpi = vport->vpi + vport->phba->vpi_base; + mb->un.varRegVpi.sid = vport->fc_myDID; + mb->un.varRegVpi.vfi = vport->vfi + vport->phba->vfi_base; mb->mbxCommand = MBX_REG_VPI; mb->mbxOwner = OWN_HOST; @@ -760,10 +809,10 @@ lpfc_reg_vpi(struct lpfc_hba *phba, uint16_t vpi, uint32_t sid, void lpfc_unreg_vpi(struct lpfc_hba *phba, uint16_t vpi, LPFC_MBOXQ_t *pmb) { - MAILBOX_t *mb = &pmb->mb; + MAILBOX_t *mb = &pmb->u.mb; memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); - mb->un.varUnregVpi.vpi = vpi; + mb->un.varUnregVpi.vpi = vpi + phba->vpi_base; mb->mbxCommand = MBX_UNREG_VPI; mb->mbxOwner = OWN_HOST; @@ -852,7 +901,7 @@ lpfc_config_pcb_setup(struct lpfc_hba * phba) void lpfc_read_rev(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) { - MAILBOX_t *mb = &pmb->mb; + MAILBOX_t *mb = &pmb->u.mb; memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); mb->un.varRdRev.cv = 1; mb->un.varRdRev.v3req = 1; /* Request SLI3 info */ @@ -945,7 +994,7 @@ lpfc_config_hbq(struct lpfc_hba *phba, uint32_t id, uint32_t hbq_entry_index, LPFC_MBOXQ_t *pmb) { int i; - MAILBOX_t *mb = &pmb->mb; + MAILBOX_t *mb = &pmb->u.mb; struct config_hbq_var *hbqmb = &mb->un.varCfgHbq; memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); @@ -1020,7 +1069,7 @@ void lpfc_config_ring(struct lpfc_hba * phba, int ring, LPFC_MBOXQ_t * pmb) { int i; - MAILBOX_t *mb = &pmb->mb; + MAILBOX_t *mb = &pmb->u.mb; struct lpfc_sli *psli; struct lpfc_sli_ring *pring; @@ -1075,7 +1124,7 @@ void lpfc_config_port(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { MAILBOX_t __iomem *mb_slim = (MAILBOX_t __iomem *) phba->MBslimaddr; - MAILBOX_t *mb = &pmb->mb; + MAILBOX_t *mb = &pmb->u.mb; dma_addr_t pdma_addr; uint32_t bar_low, bar_high; size_t offset; @@ -1099,21 +1148,22 @@ lpfc_config_port(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) /* If HBA supports SLI=3 ask for it */ - if (phba->sli_rev == 3 && phba->vpd.sli3Feat.cerbm) { + if (phba->sli_rev == LPFC_SLI_REV3 && phba->vpd.sli3Feat.cerbm) { if (phba->cfg_enable_bg) mb->un.varCfgPort.cbg = 1; /* configure BlockGuard */ + mb->un.varCfgPort.cdss = 1; /* Configure Security */ mb->un.varCfgPort.cerbm = 1; /* Request HBQs */ mb->un.varCfgPort.ccrp = 1; /* Command Ring Polling */ mb->un.varCfgPort.cinb = 1; /* Interrupt Notification Block */ mb->un.varCfgPort.max_hbq = lpfc_sli_hbq_count(); if (phba->max_vpi && phba->cfg_enable_npiv && phba->vpd.sli3Feat.cmv) { - mb->un.varCfgPort.max_vpi = phba->max_vpi; + mb->un.varCfgPort.max_vpi = LPFC_MAX_VPI; mb->un.varCfgPort.cmv = 1; } else mb->un.varCfgPort.max_vpi = phba->max_vpi = 0; } else - phba->sli_rev = 2; + phba->sli_rev = LPFC_SLI_REV2; mb->un.varCfgPort.sli_mode = phba->sli_rev; /* Now setup pcb */ @@ -1245,7 +1295,7 @@ lpfc_config_port(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) void lpfc_kill_board(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) { - MAILBOX_t *mb = &pmb->mb; + MAILBOX_t *mb = &pmb->u.mb; memset(pmb, 0, sizeof(LPFC_MBOXQ_t)); mb->mbxCommand = MBX_KILL_BOARD; @@ -1304,29 +1354,98 @@ lpfc_mbox_get(struct lpfc_hba * phba) return mbq; } +/** + * __lpfc_mbox_cmpl_put - Put mailbox cmd into mailbox cmd complete list + * @phba: pointer to lpfc hba data structure. + * @mbq: pointer to the driver internal queue element for mailbox command. + * + * This routine put the completed mailbox command into the mailbox command + * complete list. This is the unlocked version of the routine. The mailbox + * complete list is used by the driver worker thread to process mailbox + * complete callback functions outside the driver interrupt handler. + **/ +void +__lpfc_mbox_cmpl_put(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbq) +{ + list_add_tail(&mbq->list, &phba->sli.mboxq_cmpl); +} + /** * lpfc_mbox_cmpl_put - Put mailbox command into mailbox command complete list * @phba: pointer to lpfc hba data structure. * @mbq: pointer to the driver internal queue element for mailbox command. * * This routine put the completed mailbox command into the mailbox command - * complete list. This routine is called from driver interrupt handler - * context.The mailbox complete list is used by the driver worker thread - * to process mailbox complete callback functions outside the driver interrupt - * handler. + * complete list. This is the locked version of the routine. The mailbox + * complete list is used by the driver worker thread to process mailbox + * complete callback functions outside the driver interrupt handler. **/ void -lpfc_mbox_cmpl_put(struct lpfc_hba * phba, LPFC_MBOXQ_t * mbq) +lpfc_mbox_cmpl_put(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbq) { unsigned long iflag; /* This function expects to be called from interrupt context */ spin_lock_irqsave(&phba->hbalock, iflag); - list_add_tail(&mbq->list, &phba->sli.mboxq_cmpl); + __lpfc_mbox_cmpl_put(phba, mbq); spin_unlock_irqrestore(&phba->hbalock, iflag); return; } +/** + * lpfc_mbox_cmd_check - Check the validality of a mailbox command + * @phba: pointer to lpfc hba data structure. + * @mboxq: pointer to the driver internal queue element for mailbox command. + * + * This routine is to check whether a mailbox command is valid to be issued. + * This check will be performed by both the mailbox issue API when a client + * is to issue a mailbox command to the mailbox transport. + * + * Return 0 - pass the check, -ENODEV - fail the check + **/ +int +lpfc_mbox_cmd_check(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) +{ + /* Mailbox command that have a completion handler must also have a + * vport specified. + */ + if (mboxq->mbox_cmpl && mboxq->mbox_cmpl != lpfc_sli_def_mbox_cmpl && + mboxq->mbox_cmpl != lpfc_sli_wake_mbox_wait) { + if (!mboxq->vport) { + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_VPORT, + "1814 Mbox x%x failed, no vport\n", + mboxq->u.mb.mbxCommand); + dump_stack(); + return -ENODEV; + } + } + return 0; +} + +/** + * lpfc_mbox_dev_check - Check the device state for issuing a mailbox command + * @phba: pointer to lpfc hba data structure. + * + * This routine is to check whether the HBA device is ready for posting a + * mailbox command. It is used by the mailbox transport API at the time the + * to post a mailbox command to the device. + * + * Return 0 - pass the check, -ENODEV - fail the check + **/ +int +lpfc_mbox_dev_check(struct lpfc_hba *phba) +{ + /* If the PCI channel is in offline state, do not issue mbox */ + if (unlikely(pci_channel_offline(phba->pcidev))) + return -ENODEV; + + /* If the HBA is in error state, do not issue mbox */ + if (phba->link_state == LPFC_HBA_ERROR) + return -ENODEV; + + return 0; +} + /** * lpfc_mbox_tmo_val - Retrieve mailbox command timeout value * @phba: pointer to lpfc hba data structure. @@ -1350,6 +1469,478 @@ lpfc_mbox_tmo_val(struct lpfc_hba *phba, int cmd) case MBX_WRITE_WWN: /* 0x98 */ case MBX_LOAD_EXP_ROM: /* 0x9C */ return LPFC_MBOX_TMO_FLASH_CMD; + case MBX_SLI4_CONFIG: /* 0x9b */ + return LPFC_MBOX_SLI4_CONFIG_TMO; } return LPFC_MBOX_TMO; } + +/** + * lpfc_sli4_mbx_sge_set - Set a sge entry in non-embedded mailbox command + * @mbox: pointer to lpfc mbox command. + * @sgentry: sge entry index. + * @phyaddr: physical address for the sge + * @length: Length of the sge. + * + * This routine sets up an entry in the non-embedded mailbox command at the sge + * index location. + **/ +void +lpfc_sli4_mbx_sge_set(struct lpfcMboxq *mbox, uint32_t sgentry, + dma_addr_t phyaddr, uint32_t length) +{ + struct lpfc_mbx_nembed_cmd *nembed_sge; + + nembed_sge = (struct lpfc_mbx_nembed_cmd *) + &mbox->u.mqe.un.nembed_cmd; + nembed_sge->sge[sgentry].pa_lo = putPaddrLow(phyaddr); + nembed_sge->sge[sgentry].pa_hi = putPaddrHigh(phyaddr); + nembed_sge->sge[sgentry].length = length; +} + +/** + * lpfc_sli4_mbx_sge_get - Get a sge entry from non-embedded mailbox command + * @mbox: pointer to lpfc mbox command. + * @sgentry: sge entry index. + * + * This routine gets an entry from the non-embedded mailbox command at the sge + * index location. + **/ +void +lpfc_sli4_mbx_sge_get(struct lpfcMboxq *mbox, uint32_t sgentry, + struct lpfc_mbx_sge *sge) +{ + struct lpfc_mbx_nembed_cmd *nembed_sge; + + nembed_sge = (struct lpfc_mbx_nembed_cmd *) + &mbox->u.mqe.un.nembed_cmd; + sge->pa_lo = nembed_sge->sge[sgentry].pa_lo; + sge->pa_hi = nembed_sge->sge[sgentry].pa_hi; + sge->length = nembed_sge->sge[sgentry].length; +} + +/** + * lpfc_sli4_mbox_cmd_free - Free a sli4 mailbox command + * @phba: pointer to lpfc hba data structure. + * @mbox: pointer to lpfc mbox command. + * + * This routine frees SLI4 specific mailbox command for sending IOCTL command. + **/ +void +lpfc_sli4_mbox_cmd_free(struct lpfc_hba *phba, struct lpfcMboxq *mbox) +{ + struct lpfc_mbx_sli4_config *sli4_cfg; + struct lpfc_mbx_sge sge; + dma_addr_t phyaddr; + uint32_t sgecount, sgentry; + + sli4_cfg = &mbox->u.mqe.un.sli4_config; + + /* For embedded mbox command, just free the mbox command */ + if (bf_get(lpfc_mbox_hdr_emb, &sli4_cfg->header.cfg_mhdr)) { + mempool_free(mbox, phba->mbox_mem_pool); + return; + } + + /* For non-embedded mbox command, we need to free the pages first */ + sgecount = bf_get(lpfc_mbox_hdr_sge_cnt, &sli4_cfg->header.cfg_mhdr); + /* There is nothing we can do if there is no sge address array */ + if (unlikely(!mbox->sge_array)) { + mempool_free(mbox, phba->mbox_mem_pool); + return; + } + /* Each non-embedded DMA memory was allocated in the length of a page */ + for (sgentry = 0; sgentry < sgecount; sgentry++) { + lpfc_sli4_mbx_sge_get(mbox, sgentry, &sge); + phyaddr = getPaddr(sge.pa_hi, sge.pa_lo); + dma_free_coherent(&phba->pcidev->dev, PAGE_SIZE, + mbox->sge_array->addr[sgentry], phyaddr); + } + /* Free the sge address array memory */ + kfree(mbox->sge_array); + /* Finally, free the mailbox command itself */ + mempool_free(mbox, phba->mbox_mem_pool); +} + +/** + * lpfc_sli4_config - Initialize the SLI4 Config Mailbox command + * @phba: pointer to lpfc hba data structure. + * @mbox: pointer to lpfc mbox command. + * @subsystem: The sli4 config sub mailbox subsystem. + * @opcode: The sli4 config sub mailbox command opcode. + * @length: Length of the sli4 config mailbox command. + * + * This routine sets up the header fields of SLI4 specific mailbox command + * for sending IOCTL command. + * + * Return: the actual length of the mbox command allocated (mostly useful + * for none embedded mailbox command). + **/ +int +lpfc_sli4_config(struct lpfc_hba *phba, struct lpfcMboxq *mbox, + uint8_t subsystem, uint8_t opcode, uint32_t length, bool emb) +{ + struct lpfc_mbx_sli4_config *sli4_config; + union lpfc_sli4_cfg_shdr *cfg_shdr = NULL; + uint32_t alloc_len; + uint32_t resid_len; + uint32_t pagen, pcount; + void *viraddr; + dma_addr_t phyaddr; + + /* Set up SLI4 mailbox command header fields */ + memset(mbox, 0, sizeof(*mbox)); + bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_SLI4_CONFIG); + + /* Set up SLI4 ioctl command header fields */ + sli4_config = &mbox->u.mqe.un.sli4_config; + + /* Setup for the embedded mbox command */ + if (emb) { + /* Set up main header fields */ + bf_set(lpfc_mbox_hdr_emb, &sli4_config->header.cfg_mhdr, 1); + sli4_config->header.cfg_mhdr.payload_length = + LPFC_MBX_CMD_HDR_LENGTH + length; + /* Set up sub-header fields following main header */ + bf_set(lpfc_mbox_hdr_opcode, + &sli4_config->header.cfg_shdr.request, opcode); + bf_set(lpfc_mbox_hdr_subsystem, + &sli4_config->header.cfg_shdr.request, subsystem); + sli4_config->header.cfg_shdr.request.request_length = length; + return length; + } + + /* Setup for the none-embedded mbox command */ + pcount = (PAGE_ALIGN(length))/PAGE_SIZE; + pcount = (pcount > LPFC_SLI4_MBX_SGE_MAX_PAGES) ? + LPFC_SLI4_MBX_SGE_MAX_PAGES : pcount; + /* Allocate record for keeping SGE virtual addresses */ + mbox->sge_array = kmalloc(sizeof(struct lpfc_mbx_nembed_sge_virt), + GFP_KERNEL); + if (!mbox->sge_array) + return 0; + + for (pagen = 0, alloc_len = 0; pagen < pcount; pagen++) { + /* The DMA memory is always allocated in the length of a + * page even though the last SGE might not fill up to a + * page, this is used as a priori size of PAGE_SIZE for + * the later DMA memory free. + */ + viraddr = dma_alloc_coherent(&phba->pcidev->dev, PAGE_SIZE, + &phyaddr, GFP_KERNEL); + /* In case of malloc fails, proceed with whatever we have */ + if (!viraddr) + break; + memset(viraddr, 0, PAGE_SIZE); + mbox->sge_array->addr[pagen] = viraddr; + /* Keep the first page for later sub-header construction */ + if (pagen == 0) + cfg_shdr = (union lpfc_sli4_cfg_shdr *)viraddr; + resid_len = length - alloc_len; + if (resid_len > PAGE_SIZE) { + lpfc_sli4_mbx_sge_set(mbox, pagen, phyaddr, + PAGE_SIZE); + alloc_len += PAGE_SIZE; + } else { + lpfc_sli4_mbx_sge_set(mbox, pagen, phyaddr, + resid_len); + alloc_len = length; + } + } + + /* Set up main header fields in mailbox command */ + sli4_config->header.cfg_mhdr.payload_length = alloc_len; + bf_set(lpfc_mbox_hdr_sge_cnt, &sli4_config->header.cfg_mhdr, pagen); + + /* Set up sub-header fields into the first page */ + if (pagen > 0) { + bf_set(lpfc_mbox_hdr_opcode, &cfg_shdr->request, opcode); + bf_set(lpfc_mbox_hdr_subsystem, &cfg_shdr->request, subsystem); + cfg_shdr->request.request_length = + alloc_len - sizeof(union lpfc_sli4_cfg_shdr); + } + /* The sub-header is in DMA memory, which needs endian converstion */ + lpfc_sli_pcimem_bcopy(cfg_shdr, cfg_shdr, + sizeof(union lpfc_sli4_cfg_shdr)); + + return alloc_len; +} + +/** + * lpfc_sli4_mbox_opcode_get - Get the opcode from a sli4 mailbox command + * @phba: pointer to lpfc hba data structure. + * @mbox: pointer to lpfc mbox command. + * + * This routine gets the opcode from a SLI4 specific mailbox command for + * sending IOCTL command. If the mailbox command is not MBX_SLI4_CONFIG + * (0x9B) or if the IOCTL sub-header is not present, opcode 0x0 shall be + * returned. + **/ +uint8_t +lpfc_sli4_mbox_opcode_get(struct lpfc_hba *phba, struct lpfcMboxq *mbox) +{ + struct lpfc_mbx_sli4_config *sli4_cfg; + union lpfc_sli4_cfg_shdr *cfg_shdr; + + if (mbox->u.mb.mbxCommand != MBX_SLI4_CONFIG) + return 0; + sli4_cfg = &mbox->u.mqe.un.sli4_config; + + /* For embedded mbox command, get opcode from embedded sub-header*/ + if (bf_get(lpfc_mbox_hdr_emb, &sli4_cfg->header.cfg_mhdr)) { + cfg_shdr = &mbox->u.mqe.un.sli4_config.header.cfg_shdr; + return bf_get(lpfc_mbox_hdr_opcode, &cfg_shdr->request); + } + + /* For non-embedded mbox command, get opcode from first dma page */ + if (unlikely(!mbox->sge_array)) + return 0; + cfg_shdr = (union lpfc_sli4_cfg_shdr *)mbox->sge_array->addr[0]; + return bf_get(lpfc_mbox_hdr_opcode, &cfg_shdr->request); +} + +/** + * lpfc_request_features: Configure SLI4 REQUEST_FEATURES mailbox + * @mboxq: pointer to lpfc mbox command. + * + * This routine sets up the mailbox for an SLI4 REQUEST_FEATURES + * mailbox command. + **/ +void +lpfc_request_features(struct lpfc_hba *phba, struct lpfcMboxq *mboxq) +{ + /* Set up SLI4 mailbox command header fields */ + memset(mboxq, 0, sizeof(LPFC_MBOXQ_t)); + bf_set(lpfc_mqe_command, &mboxq->u.mqe, MBX_SLI4_REQ_FTRS); + + /* Set up host requested features. */ + bf_set(lpfc_mbx_rq_ftr_rq_fcpi, &mboxq->u.mqe.un.req_ftrs, 1); + + if (phba->cfg_enable_fip) + bf_set(lpfc_mbx_rq_ftr_rq_ifip, &mboxq->u.mqe.un.req_ftrs, 0); + else + bf_set(lpfc_mbx_rq_ftr_rq_ifip, &mboxq->u.mqe.un.req_ftrs, 1); + + /* Enable DIF (block guard) only if configured to do so. */ + if (phba->cfg_enable_bg) + bf_set(lpfc_mbx_rq_ftr_rq_dif, &mboxq->u.mqe.un.req_ftrs, 1); + + /* Enable NPIV only if configured to do so. */ + if (phba->max_vpi && phba->cfg_enable_npiv) + bf_set(lpfc_mbx_rq_ftr_rq_npiv, &mboxq->u.mqe.un.req_ftrs, 1); + + return; +} + +/** + * lpfc_init_vfi - Initialize the INIT_VFI mailbox command + * @mbox: pointer to lpfc mbox command to initialize. + * @vport: Vport associated with the VF. + * + * This routine initializes @mbox to all zeros and then fills in the mailbox + * fields from @vport. INIT_VFI configures virtual fabrics identified by VFI + * in the context of an FCF. The driver issues this command to setup a VFI + * before issuing a FLOGI to login to the VSAN. The driver should also issue a + * REG_VFI after a successful VSAN login. + **/ +void +lpfc_init_vfi(struct lpfcMboxq *mbox, struct lpfc_vport *vport) +{ + struct lpfc_mbx_init_vfi *init_vfi; + + memset(mbox, 0, sizeof(*mbox)); + init_vfi = &mbox->u.mqe.un.init_vfi; + bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_INIT_VFI); + bf_set(lpfc_init_vfi_vr, init_vfi, 1); + bf_set(lpfc_init_vfi_vt, init_vfi, 1); + bf_set(lpfc_init_vfi_vfi, init_vfi, vport->vfi + vport->phba->vfi_base); + bf_set(lpfc_init_vfi_fcfi, init_vfi, vport->phba->fcf.fcfi); +} + +/** + * lpfc_reg_vfi - Initialize the REG_VFI mailbox command + * @mbox: pointer to lpfc mbox command to initialize. + * @vport: vport associated with the VF. + * @phys: BDE DMA bus address used to send the service parameters to the HBA. + * + * This routine initializes @mbox to all zeros and then fills in the mailbox + * fields from @vport, and uses @buf as a DMAable buffer to send the vport's + * fc service parameters to the HBA for this VFI. REG_VFI configures virtual + * fabrics identified by VFI in the context of an FCF. + **/ +void +lpfc_reg_vfi(struct lpfcMboxq *mbox, struct lpfc_vport *vport, dma_addr_t phys) +{ + struct lpfc_mbx_reg_vfi *reg_vfi; + + memset(mbox, 0, sizeof(*mbox)); + reg_vfi = &mbox->u.mqe.un.reg_vfi; + bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_REG_VFI); + bf_set(lpfc_reg_vfi_vp, reg_vfi, 1); + bf_set(lpfc_reg_vfi_vfi, reg_vfi, vport->vfi + vport->phba->vfi_base); + bf_set(lpfc_reg_vfi_fcfi, reg_vfi, vport->phba->fcf.fcfi); + bf_set(lpfc_reg_vfi_vpi, reg_vfi, vport->vpi + vport->phba->vpi_base); + reg_vfi->bde.addrHigh = putPaddrHigh(phys); + reg_vfi->bde.addrLow = putPaddrLow(phys); + reg_vfi->bde.tus.f.bdeSize = sizeof(vport->fc_sparam); + reg_vfi->bde.tus.f.bdeFlags = BUFF_TYPE_BDE_64; + bf_set(lpfc_reg_vfi_nport_id, reg_vfi, vport->fc_myDID); +} + +/** + * lpfc_init_vpi - Initialize the INIT_VPI mailbox command + * @mbox: pointer to lpfc mbox command to initialize. + * @vpi: VPI to be initialized. + * + * The INIT_VPI mailbox command supports virtual N_Ports. The driver uses the + * command to activate a virtual N_Port. The HBA assigns a MAC address to use + * with the virtual N Port. The SLI Host issues this command before issuing a + * FDISC to connect to the Fabric. The SLI Host should issue a REG_VPI after a + * successful virtual NPort login. + **/ +void +lpfc_init_vpi(struct lpfcMboxq *mbox, uint16_t vpi) +{ + memset(mbox, 0, sizeof(*mbox)); + bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_INIT_VPI); + bf_set(lpfc_init_vpi_vpi, &mbox->u.mqe.un.init_vpi, vpi); +} + +/** + * lpfc_unreg_vfi - Initialize the UNREG_VFI mailbox command + * @mbox: pointer to lpfc mbox command to initialize. + * @vfi: VFI to be unregistered. + * + * The UNREG_VFI mailbox command causes the SLI Host to put a virtual fabric + * (logical NPort) into the inactive state. The SLI Host must have logged out + * and unregistered all remote N_Ports to abort any activity on the virtual + * fabric. The SLI Port posts the mailbox response after marking the virtual + * fabric inactive. + **/ +void +lpfc_unreg_vfi(struct lpfcMboxq *mbox, uint16_t vfi) +{ + memset(mbox, 0, sizeof(*mbox)); + bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_UNREG_VFI); + bf_set(lpfc_unreg_vfi_vfi, &mbox->u.mqe.un.unreg_vfi, vfi); +} + +/** + * lpfc_dump_fcoe_param - Dump config region 23 to get FCoe parameters. + * @phba: pointer to the hba structure containing. + * @mbox: pointer to lpfc mbox command to initialize. + * + * This function create a SLI4 dump mailbox command to dump FCoE + * parameters stored in region 23. + **/ +int +lpfc_dump_fcoe_param(struct lpfc_hba *phba, + struct lpfcMboxq *mbox) +{ + struct lpfc_dmabuf *mp = NULL; + MAILBOX_t *mb; + + memset(mbox, 0, sizeof(*mbox)); + mb = &mbox->u.mb; + + mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); + if (mp) + mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys); + + if (!mp || !mp->virt) { + kfree(mp); + /* dump_fcoe_param failed to allocate memory */ + lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX, + "2569 lpfc_dump_fcoe_param: memory" + " allocation failed \n"); + return 1; + } + + memset(mp->virt, 0, LPFC_BPL_SIZE); + INIT_LIST_HEAD(&mp->list); + + /* save address for completion */ + mbox->context1 = (uint8_t *) mp; + + mb->mbxCommand = MBX_DUMP_MEMORY; + mb->un.varDmp.type = DMP_NV_PARAMS; + mb->un.varDmp.region_id = DMP_REGION_FCOEPARAM; + mb->un.varDmp.sli4_length = DMP_FCOEPARAM_RGN_SIZE; + mb->un.varWords[3] = putPaddrLow(mp->phys); + mb->un.varWords[4] = putPaddrHigh(mp->phys); + return 0; +} + +/** + * lpfc_reg_fcfi - Initialize the REG_FCFI mailbox command + * @phba: pointer to the hba structure containing the FCF index and RQ ID. + * @mbox: pointer to lpfc mbox command to initialize. + * + * The REG_FCFI mailbox command supports Fibre Channel Forwarders (FCFs). The + * SLI Host uses the command to activate an FCF after it has acquired FCF + * information via a READ_FCF mailbox command. This mailbox command also is used + * to indicate where received unsolicited frames from this FCF will be sent. By + * default this routine will set up the FCF to forward all unsolicited frames + * the the RQ ID passed in the @phba. This can be overridden by the caller for + * more complicated setups. + **/ +void +lpfc_reg_fcfi(struct lpfc_hba *phba, struct lpfcMboxq *mbox) +{ + struct lpfc_mbx_reg_fcfi *reg_fcfi; + + memset(mbox, 0, sizeof(*mbox)); + reg_fcfi = &mbox->u.mqe.un.reg_fcfi; + bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_REG_FCFI); + bf_set(lpfc_reg_fcfi_rq_id0, reg_fcfi, phba->sli4_hba.hdr_rq->queue_id); + bf_set(lpfc_reg_fcfi_rq_id1, reg_fcfi, REG_FCF_INVALID_QID); + bf_set(lpfc_reg_fcfi_rq_id2, reg_fcfi, REG_FCF_INVALID_QID); + bf_set(lpfc_reg_fcfi_rq_id3, reg_fcfi, REG_FCF_INVALID_QID); + bf_set(lpfc_reg_fcfi_info_index, reg_fcfi, phba->fcf.fcf_indx); + /* reg_fcf addr mode is bit wise inverted value of fcf addr_mode */ + bf_set(lpfc_reg_fcfi_mam, reg_fcfi, + (~phba->fcf.addr_mode) & 0x3); + if (phba->fcf.fcf_flag & FCF_VALID_VLAN) { + bf_set(lpfc_reg_fcfi_vv, reg_fcfi, 1); + bf_set(lpfc_reg_fcfi_vlan_tag, reg_fcfi, phba->fcf.vlan_id); + } +} + +/** + * lpfc_unreg_fcfi - Initialize the UNREG_FCFI mailbox command + * @mbox: pointer to lpfc mbox command to initialize. + * @fcfi: FCFI to be unregistered. + * + * The UNREG_FCFI mailbox command supports Fibre Channel Forwarders (FCFs). + * The SLI Host uses the command to inactivate an FCFI. + **/ +void +lpfc_unreg_fcfi(struct lpfcMboxq *mbox, uint16_t fcfi) +{ + memset(mbox, 0, sizeof(*mbox)); + bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_UNREG_FCFI); + bf_set(lpfc_unreg_fcfi, &mbox->u.mqe.un.unreg_fcfi, fcfi); +} + +/** + * lpfc_resume_rpi - Initialize the RESUME_RPI mailbox command + * @mbox: pointer to lpfc mbox command to initialize. + * @ndlp: The nodelist structure that describes the RPI to resume. + * + * The RESUME_RPI mailbox command is used to restart I/O to an RPI after a + * link event. + **/ +void +lpfc_resume_rpi(struct lpfcMboxq *mbox, struct lpfc_nodelist *ndlp) +{ + struct lpfc_mbx_resume_rpi *resume_rpi; + + memset(mbox, 0, sizeof(*mbox)); + resume_rpi = &mbox->u.mqe.un.resume_rpi; + bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_RESUME_RPI); + bf_set(lpfc_resume_rpi_rpi, resume_rpi, ndlp->nlp_rpi); + bf_set(lpfc_resume_rpi_vpi, resume_rpi, + ndlp->vport->vpi + ndlp->vport->phba->vpi_base); + bf_set(lpfc_resume_rpi_vfi, resume_rpi, + ndlp->vport->vfi + ndlp->vport->phba->vfi_base); +} diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c index 35a976733398..e198c917c13e 100644 --- a/drivers/scsi/lpfc/lpfc_mem.c +++ b/drivers/scsi/lpfc/lpfc_mem.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2008 Emulex. All rights reserved. * + * Copyright (C) 2004-2009 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -28,8 +28,10 @@ #include +#include "lpfc_hw4.h" #include "lpfc_hw.h" #include "lpfc_sli.h" +#include "lpfc_sli4.h" #include "lpfc_nl.h" #include "lpfc_disc.h" #include "lpfc_scsi.h" @@ -45,7 +47,7 @@ * @phba: HBA to allocate pools for * * Description: Creates and allocates PCI pools lpfc_scsi_dma_buf_pool, - * lpfc_mbuf_pool, lpfc_hbq_pool. Creates and allocates kmalloc-backed mempools + * lpfc_mbuf_pool, lpfc_hrb_pool. Creates and allocates kmalloc-backed mempools * for LPFC_MBOXQ_t and lpfc_nodelist. Also allocates the VPI bitmask. * * Notes: Not interrupt-safe. Must be called with no locks held. If any @@ -56,19 +58,30 @@ * -ENOMEM on failure (if any memory allocations fail) **/ int -lpfc_mem_alloc(struct lpfc_hba * phba) +lpfc_mem_alloc(struct lpfc_hba *phba, int align) { struct lpfc_dma_pool *pool = &phba->lpfc_mbuf_safety_pool; int longs; int i; - phba->lpfc_scsi_dma_buf_pool = pci_pool_create("lpfc_scsi_dma_buf_pool", - phba->pcidev, phba->cfg_sg_dma_buf_size, 8, 0); + if (phba->sli_rev == LPFC_SLI_REV4) + phba->lpfc_scsi_dma_buf_pool = + pci_pool_create("lpfc_scsi_dma_buf_pool", + phba->pcidev, + phba->cfg_sg_dma_buf_size, + phba->cfg_sg_dma_buf_size, + 0); + else + phba->lpfc_scsi_dma_buf_pool = + pci_pool_create("lpfc_scsi_dma_buf_pool", + phba->pcidev, phba->cfg_sg_dma_buf_size, + align, 0); if (!phba->lpfc_scsi_dma_buf_pool) goto fail; phba->lpfc_mbuf_pool = pci_pool_create("lpfc_mbuf_pool", phba->pcidev, - LPFC_BPL_SIZE, 8,0); + LPFC_BPL_SIZE, + align, 0); if (!phba->lpfc_mbuf_pool) goto fail_free_dma_buf_pool; @@ -97,23 +110,31 @@ lpfc_mem_alloc(struct lpfc_hba * phba) sizeof(struct lpfc_nodelist)); if (!phba->nlp_mem_pool) goto fail_free_mbox_pool; - - phba->lpfc_hbq_pool = pci_pool_create("lpfc_hbq_pool",phba->pcidev, - LPFC_BPL_SIZE, 8, 0); - if (!phba->lpfc_hbq_pool) + phba->lpfc_hrb_pool = pci_pool_create("lpfc_hrb_pool", + phba->pcidev, + LPFC_HDR_BUF_SIZE, align, 0); + if (!phba->lpfc_hrb_pool) goto fail_free_nlp_mem_pool; + phba->lpfc_drb_pool = pci_pool_create("lpfc_drb_pool", + phba->pcidev, + LPFC_DATA_BUF_SIZE, align, 0); + if (!phba->lpfc_drb_pool) + goto fail_free_hbq_pool; /* vpi zero is reserved for the physical port so add 1 to max */ longs = ((phba->max_vpi + 1) + BITS_PER_LONG - 1) / BITS_PER_LONG; phba->vpi_bmask = kzalloc(longs * sizeof(unsigned long), GFP_KERNEL); if (!phba->vpi_bmask) - goto fail_free_hbq_pool; + goto fail_free_dbq_pool; return 0; + fail_free_dbq_pool: + pci_pool_destroy(phba->lpfc_drb_pool); + phba->lpfc_drb_pool = NULL; fail_free_hbq_pool: - lpfc_sli_hbqbuf_free_all(phba); - pci_pool_destroy(phba->lpfc_hbq_pool); + pci_pool_destroy(phba->lpfc_hrb_pool); + phba->lpfc_hrb_pool = NULL; fail_free_nlp_mem_pool: mempool_destroy(phba->nlp_mem_pool); phba->nlp_mem_pool = NULL; @@ -136,27 +157,73 @@ lpfc_mem_alloc(struct lpfc_hba * phba) } /** - * lpfc_mem_free - Frees all PCI and memory allocated by lpfc_mem_alloc + * lpfc_mem_free - Frees memory allocated by lpfc_mem_alloc * @phba: HBA to free memory for * - * Description: Frees PCI pools lpfc_scsi_dma_buf_pool, lpfc_mbuf_pool, - * lpfc_hbq_pool. Frees kmalloc-backed mempools for LPFC_MBOXQ_t and - * lpfc_nodelist. Also frees the VPI bitmask + * Description: Free the memory allocated by lpfc_mem_alloc routine. This + * routine is a the counterpart of lpfc_mem_alloc. * * Returns: None **/ void -lpfc_mem_free(struct lpfc_hba * phba) +lpfc_mem_free(struct lpfc_hba *phba) +{ + int i; + struct lpfc_dma_pool *pool = &phba->lpfc_mbuf_safety_pool; + + /* Free VPI bitmask memory */ + kfree(phba->vpi_bmask); + + /* Free HBQ pools */ + lpfc_sli_hbqbuf_free_all(phba); + pci_pool_destroy(phba->lpfc_drb_pool); + phba->lpfc_drb_pool = NULL; + pci_pool_destroy(phba->lpfc_hrb_pool); + phba->lpfc_hrb_pool = NULL; + + /* Free NLP memory pool */ + mempool_destroy(phba->nlp_mem_pool); + phba->nlp_mem_pool = NULL; + + /* Free mbox memory pool */ + mempool_destroy(phba->mbox_mem_pool); + phba->mbox_mem_pool = NULL; + + /* Free MBUF memory pool */ + for (i = 0; i < pool->current_count; i++) + pci_pool_free(phba->lpfc_mbuf_pool, pool->elements[i].virt, + pool->elements[i].phys); + kfree(pool->elements); + + pci_pool_destroy(phba->lpfc_mbuf_pool); + phba->lpfc_mbuf_pool = NULL; + + /* Free DMA buffer memory pool */ + pci_pool_destroy(phba->lpfc_scsi_dma_buf_pool); + phba->lpfc_scsi_dma_buf_pool = NULL; + + return; +} + +/** + * lpfc_mem_free_all - Frees all PCI and driver memory + * @phba: HBA to free memory for + * + * Description: Free memory from PCI and driver memory pools and also those + * used : lpfc_scsi_dma_buf_pool, lpfc_mbuf_pool, lpfc_hrb_pool. Frees + * kmalloc-backed mempools for LPFC_MBOXQ_t and lpfc_nodelist. Also frees + * the VPI bitmask. + * + * Returns: None + **/ +void +lpfc_mem_free_all(struct lpfc_hba *phba) { struct lpfc_sli *psli = &phba->sli; - struct lpfc_dma_pool *pool = &phba->lpfc_mbuf_safety_pool; LPFC_MBOXQ_t *mbox, *next_mbox; struct lpfc_dmabuf *mp; - int i; - - kfree(phba->vpi_bmask); - lpfc_sli_hbqbuf_free_all(phba); + /* Free memory used in mailbox queue back to mailbox memory pool */ list_for_each_entry_safe(mbox, next_mbox, &psli->mboxq, list) { mp = (struct lpfc_dmabuf *) (mbox->context1); if (mp) { @@ -166,6 +233,7 @@ lpfc_mem_free(struct lpfc_hba * phba) list_del(&mbox->list); mempool_free(mbox, phba->mbox_mem_pool); } + /* Free memory used in mailbox cmpl list back to mailbox memory pool */ list_for_each_entry_safe(mbox, next_mbox, &psli->mboxq_cmpl, list) { mp = (struct lpfc_dmabuf *) (mbox->context1); if (mp) { @@ -175,8 +243,10 @@ lpfc_mem_free(struct lpfc_hba * phba) list_del(&mbox->list); mempool_free(mbox, phba->mbox_mem_pool); } - + /* Free the active mailbox command back to the mailbox memory pool */ + spin_lock_irq(&phba->hbalock); psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; + spin_unlock_irq(&phba->hbalock); if (psli->mbox_active) { mbox = psli->mbox_active; mp = (struct lpfc_dmabuf *) (mbox->context1); @@ -188,27 +258,14 @@ lpfc_mem_free(struct lpfc_hba * phba) psli->mbox_active = NULL; } - for (i = 0; i < pool->current_count; i++) - pci_pool_free(phba->lpfc_mbuf_pool, pool->elements[i].virt, - pool->elements[i].phys); - kfree(pool->elements); - - pci_pool_destroy(phba->lpfc_hbq_pool); - mempool_destroy(phba->nlp_mem_pool); - mempool_destroy(phba->mbox_mem_pool); - - pci_pool_destroy(phba->lpfc_scsi_dma_buf_pool); - pci_pool_destroy(phba->lpfc_mbuf_pool); - - phba->lpfc_hbq_pool = NULL; - phba->nlp_mem_pool = NULL; - phba->mbox_mem_pool = NULL; - phba->lpfc_scsi_dma_buf_pool = NULL; - phba->lpfc_mbuf_pool = NULL; + /* Free and destroy all the allocated memory pools */ + lpfc_mem_free(phba); /* Free the iocb lookup array */ kfree(psli->iocbq_lookup); psli->iocbq_lookup = NULL; + + return; } /** @@ -305,7 +362,7 @@ lpfc_mbuf_free(struct lpfc_hba * phba, void *virt, dma_addr_t dma) * lpfc_els_hbq_alloc - Allocate an HBQ buffer * @phba: HBA to allocate HBQ buffer for * - * Description: Allocates a DMA-mapped HBQ buffer from the lpfc_hbq_pool PCI + * Description: Allocates a DMA-mapped HBQ buffer from the lpfc_hrb_pool PCI * pool along a non-DMA-mapped container for it. * * Notes: Not interrupt-safe. Must be called with no locks held. @@ -323,7 +380,7 @@ lpfc_els_hbq_alloc(struct lpfc_hba *phba) if (!hbqbp) return NULL; - hbqbp->dbuf.virt = pci_pool_alloc(phba->lpfc_hbq_pool, GFP_KERNEL, + hbqbp->dbuf.virt = pci_pool_alloc(phba->lpfc_hrb_pool, GFP_KERNEL, &hbqbp->dbuf.phys); if (!hbqbp->dbuf.virt) { kfree(hbqbp); @@ -334,7 +391,7 @@ lpfc_els_hbq_alloc(struct lpfc_hba *phba) } /** - * lpfc_mem_hbq_free - Frees an HBQ buffer allocated with lpfc_els_hbq_alloc + * lpfc_els_hbq_free - Frees an HBQ buffer allocated with lpfc_els_hbq_alloc * @phba: HBA buffer was allocated for * @hbqbp: HBQ container returned by lpfc_els_hbq_alloc * @@ -348,11 +405,72 @@ lpfc_els_hbq_alloc(struct lpfc_hba *phba) void lpfc_els_hbq_free(struct lpfc_hba *phba, struct hbq_dmabuf *hbqbp) { - pci_pool_free(phba->lpfc_hbq_pool, hbqbp->dbuf.virt, hbqbp->dbuf.phys); + pci_pool_free(phba->lpfc_hrb_pool, hbqbp->dbuf.virt, hbqbp->dbuf.phys); kfree(hbqbp); return; } +/** + * lpfc_sli4_rb_alloc - Allocate an SLI4 Receive buffer + * @phba: HBA to allocate a receive buffer for + * + * Description: Allocates a DMA-mapped receive buffer from the lpfc_hrb_pool PCI + * pool along a non-DMA-mapped container for it. + * + * Notes: Not interrupt-safe. Must be called with no locks held. + * + * Returns: + * pointer to HBQ on success + * NULL on failure + **/ +struct hbq_dmabuf * +lpfc_sli4_rb_alloc(struct lpfc_hba *phba) +{ + struct hbq_dmabuf *dma_buf; + + dma_buf = kmalloc(sizeof(struct hbq_dmabuf), GFP_KERNEL); + if (!dma_buf) + return NULL; + + dma_buf->hbuf.virt = pci_pool_alloc(phba->lpfc_hrb_pool, GFP_KERNEL, + &dma_buf->hbuf.phys); + if (!dma_buf->hbuf.virt) { + kfree(dma_buf); + return NULL; + } + dma_buf->dbuf.virt = pci_pool_alloc(phba->lpfc_drb_pool, GFP_KERNEL, + &dma_buf->dbuf.phys); + if (!dma_buf->dbuf.virt) { + pci_pool_free(phba->lpfc_hrb_pool, dma_buf->hbuf.virt, + dma_buf->hbuf.phys); + kfree(dma_buf); + return NULL; + } + dma_buf->size = LPFC_BPL_SIZE; + return dma_buf; +} + +/** + * lpfc_sli4_rb_free - Frees a receive buffer + * @phba: HBA buffer was allocated for + * @dmab: DMA Buffer container returned by lpfc_sli4_hbq_alloc + * + * Description: Frees both the container and the DMA-mapped buffers returned by + * lpfc_sli4_rb_alloc. + * + * Notes: Can be called with or without locks held. + * + * Returns: None + **/ +void +lpfc_sli4_rb_free(struct lpfc_hba *phba, struct hbq_dmabuf *dmab) +{ + pci_pool_free(phba->lpfc_hrb_pool, dmab->hbuf.virt, dmab->hbuf.phys); + pci_pool_free(phba->lpfc_drb_pool, dmab->dbuf.virt, dmab->dbuf.phys); + kfree(dmab); + return; +} + /** * lpfc_in_buf_free - Free a DMA buffer * @phba: HBA buffer is associated with diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index 08cdc77af41c..3e74136f1ede 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2008 Emulex. All rights reserved. * + * Copyright (C) 2004-2009 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -28,8 +28,10 @@ #include #include +#include "lpfc_hw4.h" #include "lpfc_hw.h" #include "lpfc_sli.h" +#include "lpfc_sli4.h" #include "lpfc_nl.h" #include "lpfc_disc.h" #include "lpfc_scsi.h" @@ -361,7 +363,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (!mbox) goto out; - rc = lpfc_reg_login(phba, vport->vpi, icmd->un.rcvels.remoteID, + rc = lpfc_reg_rpi(phba, vport->vpi, icmd->un.rcvels.remoteID, (uint8_t *) sp, mbox, 0); if (rc) { mempool_free(mbox, phba->mbox_mem_pool); @@ -495,11 +497,19 @@ lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL); else lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); + if ((ndlp->nlp_DID == Fabric_DID) && + vport->port_type == LPFC_NPIV_PORT) { + lpfc_linkdown_port(vport); + mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1); + spin_lock_irq(shost->host_lock); + ndlp->nlp_flag |= NLP_DELAY_TMO; + spin_unlock_irq(shost->host_lock); - if ((!(ndlp->nlp_type & NLP_FABRIC) && - ((ndlp->nlp_type & NLP_FCP_TARGET) || - !(ndlp->nlp_type & NLP_FCP_INITIATOR))) || - (ndlp->nlp_state == NLP_STE_ADISC_ISSUE)) { + ndlp->nlp_last_elscmd = ELS_CMD_FDISC; + } else if ((!(ndlp->nlp_type & NLP_FABRIC) && + ((ndlp->nlp_type & NLP_FCP_TARGET) || + !(ndlp->nlp_type & NLP_FCP_INITIATOR))) || + (ndlp->nlp_state == NLP_STE_ADISC_ISSUE)) { /* Only try to re-login if this is NOT a Fabric Node */ mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1); spin_lock_irq(shost->host_lock); @@ -567,7 +577,7 @@ lpfc_disc_set_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) { struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - if (!ndlp->nlp_rpi) { + if (!(ndlp->nlp_flag & NLP_RPI_VALID)) { ndlp->nlp_flag &= ~NLP_NPR_ADISC; return 0; } @@ -857,7 +867,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport, lpfc_unreg_rpi(vport, ndlp); - if (lpfc_reg_login(phba, vport->vpi, irsp->un.elsreq64.remoteID, + if (lpfc_reg_rpi(phba, vport->vpi, irsp->un.elsreq64.remoteID, (uint8_t *) sp, mbox, 0) == 0) { switch (ndlp->nlp_DID) { case NameServer_DID: @@ -1068,6 +1078,7 @@ lpfc_cmpl_adisc_adisc_issue(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, *rspiocb; IOCB_t *irsp; ADISC *ap; + int rc; cmdiocb = (struct lpfc_iocbq *) arg; rspiocb = cmdiocb->context_un.rsp_iocb; @@ -1093,6 +1104,15 @@ lpfc_cmpl_adisc_adisc_issue(struct lpfc_vport *vport, return ndlp->nlp_state; } + if (phba->sli_rev == LPFC_SLI_REV4) { + rc = lpfc_sli4_resume_rpi(ndlp); + if (rc) { + /* Stay in state and retry. */ + ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE; + return ndlp->nlp_state; + } + } + if (ndlp->nlp_type & NLP_FCP_TARGET) { ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE; lpfc_nlp_set_state(vport, ndlp, NLP_STE_MAPPED_NODE); @@ -1100,6 +1120,7 @@ lpfc_cmpl_adisc_adisc_issue(struct lpfc_vport *vport, ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE; lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); } + return ndlp->nlp_state; } @@ -1190,7 +1211,7 @@ lpfc_rcv_logo_reglogin_issue(struct lpfc_vport *vport, /* cleanup any ndlp on mbox q waiting for reglogin cmpl */ if ((mb = phba->sli.mbox_active)) { - if ((mb->mb.mbxCommand == MBX_REG_LOGIN64) && + if ((mb->u.mb.mbxCommand == MBX_REG_LOGIN64) && (ndlp == (struct lpfc_nodelist *) mb->context2)) { lpfc_nlp_put(ndlp); mb->context2 = NULL; @@ -1200,7 +1221,7 @@ lpfc_rcv_logo_reglogin_issue(struct lpfc_vport *vport, spin_lock_irq(&phba->hbalock); list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) { - if ((mb->mb.mbxCommand == MBX_REG_LOGIN64) && + if ((mb->u.mb.mbxCommand == MBX_REG_LOGIN64) && (ndlp == (struct lpfc_nodelist *) mb->context2)) { mp = (struct lpfc_dmabuf *) (mb->context1); if (mp) { @@ -1251,7 +1272,7 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_vport *vport, { struct Scsi_Host *shost = lpfc_shost_from_vport(vport); LPFC_MBOXQ_t *pmb = (LPFC_MBOXQ_t *) arg; - MAILBOX_t *mb = &pmb->mb; + MAILBOX_t *mb = &pmb->u.mb; uint32_t did = mb->un.varWords[1]; if (mb->mbxStatus) { @@ -1283,6 +1304,7 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_vport *vport, } ndlp->nlp_rpi = mb->un.varWords[0]; + ndlp->nlp_flag |= NLP_RPI_VALID; /* Only if we are not a fabric nport do we issue PRLI */ if (!(ndlp->nlp_type & NLP_FABRIC)) { @@ -1878,11 +1900,12 @@ lpfc_cmpl_reglogin_npr_node(struct lpfc_vport *vport, void *arg, uint32_t evt) { LPFC_MBOXQ_t *pmb = (LPFC_MBOXQ_t *) arg; - MAILBOX_t *mb = &pmb->mb; + MAILBOX_t *mb = &pmb->u.mb; - if (!mb->mbxStatus) + if (!mb->mbxStatus) { ndlp->nlp_rpi = mb->un.varWords[0]; - else { + ndlp->nlp_flag |= NLP_RPI_VALID; + } else { if (ndlp->nlp_flag & NLP_NODEV_REMOVE) { lpfc_drop_node(vport, ndlp); return NLP_STE_FREED_NODE; diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 167b66dd34c7..da59c4f0168f 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2008 Emulex. All rights reserved. * + * Copyright (C) 2004-2009 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -31,8 +31,10 @@ #include #include "lpfc_version.h" +#include "lpfc_hw4.h" #include "lpfc_hw.h" #include "lpfc_sli.h" +#include "lpfc_sli4.h" #include "lpfc_nl.h" #include "lpfc_disc.h" #include "lpfc_scsi.h" @@ -57,6 +59,8 @@ static char *dif_op_str[] = { "SCSI_PROT_READ_CONVERT", "SCSI_PROT_WRITE_CONVERT" }; +static void +lpfc_release_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb); static void lpfc_debug_save_data(struct scsi_cmnd *cmnd) @@ -111,6 +115,27 @@ lpfc_debug_save_dif(struct scsi_cmnd *cmnd) } } +/** + * lpfc_sli4_set_rsp_sgl_last - Set the last bit in the response sge. + * @phba: Pointer to HBA object. + * @lpfc_cmd: lpfc scsi command object pointer. + * + * This function is called from the lpfc_prep_task_mgmt_cmd function to + * set the last bit in the response sge entry. + **/ +static void +lpfc_sli4_set_rsp_sgl_last(struct lpfc_hba *phba, + struct lpfc_scsi_buf *lpfc_cmd) +{ + struct sli4_sge *sgl = (struct sli4_sge *)lpfc_cmd->fcp_bpl; + if (sgl) { + sgl += 1; + sgl->word2 = le32_to_cpu(sgl->word2); + bf_set(lpfc_sli4_sge_last, sgl, 1); + sgl->word2 = cpu_to_le32(sgl->word2); + } +} + /** * lpfc_update_stats - Update statistical data for the command completion * @phba: Pointer to HBA object. @@ -325,7 +350,7 @@ lpfc_ramp_down_queue_handler(struct lpfc_hba *phba) vports = lpfc_create_vport_work_array(phba); if (vports != NULL) - for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { + for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { shost = lpfc_shost_from_vport(vports[i]); shost_for_each_device(sdev, shost) { new_queue_depth = @@ -379,7 +404,7 @@ lpfc_ramp_up_queue_handler(struct lpfc_hba *phba) vports = lpfc_create_vport_work_array(phba); if (vports != NULL) - for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { + for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { shost = lpfc_shost_from_vport(vports[i]); shost_for_each_device(sdev, shost) { if (vports[i]->cfg_lun_queue_depth <= @@ -427,7 +452,7 @@ lpfc_scsi_dev_block(struct lpfc_hba *phba) vports = lpfc_create_vport_work_array(phba); if (vports != NULL) - for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { + for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { shost = lpfc_shost_from_vport(vports[i]); shost_for_each_device(sdev, shost) { rport = starget_to_rport(scsi_target(sdev)); @@ -438,22 +463,23 @@ lpfc_scsi_dev_block(struct lpfc_hba *phba) } /** - * lpfc_new_scsi_buf - Scsi buffer allocator + * lpfc_new_scsi_buf_s3 - Scsi buffer allocator for HBA with SLI3 IF spec * @vport: The virtual port for which this call being executed. + * @num_to_allocate: The requested number of buffers to allocate. * - * This routine allocates a scsi buffer, which contains all the necessary - * information needed to initiate a SCSI I/O. The non-DMAable buffer region - * contains information to build the IOCB. The DMAable region contains - * memory for the FCP CMND, FCP RSP, and the initial BPL. In addition to - * allocating memory, the FCP CMND and FCP RSP BDEs are setup in the BPL - * and the BPL BDE is setup in the IOCB. + * This routine allocates a scsi buffer for device with SLI-3 interface spec, + * the scsi buffer contains all the necessary information needed to initiate + * a SCSI I/O. The non-DMAable buffer region contains information to build + * the IOCB. The DMAable region contains memory for the FCP CMND, FCP RSP, + * and the initial BPL. In addition to allocating memory, the FCP CMND and + * FCP RSP BDEs are setup in the BPL and the BPL BDE is setup in the IOCB. * * Return codes: - * NULL - Error - * Pointer to lpfc_scsi_buf data structure - Success + * int - number of scsi buffers that were allocated. + * 0 = failure, less than num_to_alloc is a partial failure. **/ -static struct lpfc_scsi_buf * -lpfc_new_scsi_buf(struct lpfc_vport *vport) +static int +lpfc_new_scsi_buf_s3(struct lpfc_vport *vport, int num_to_alloc) { struct lpfc_hba *phba = vport->phba; struct lpfc_scsi_buf *psb; @@ -463,107 +489,401 @@ lpfc_new_scsi_buf(struct lpfc_vport *vport) dma_addr_t pdma_phys_fcp_rsp; dma_addr_t pdma_phys_bpl; uint16_t iotag; + int bcnt; - psb = kzalloc(sizeof(struct lpfc_scsi_buf), GFP_KERNEL); - if (!psb) - return NULL; + for (bcnt = 0; bcnt < num_to_alloc; bcnt++) { + psb = kzalloc(sizeof(struct lpfc_scsi_buf), GFP_KERNEL); + if (!psb) + break; - /* - * Get memory from the pci pool to map the virt space to pci bus space - * for an I/O. The DMA buffer includes space for the struct fcp_cmnd, - * struct fcp_rsp and the number of bde's necessary to support the - * sg_tablesize. - */ - psb->data = pci_pool_alloc(phba->lpfc_scsi_dma_buf_pool, GFP_KERNEL, - &psb->dma_handle); - if (!psb->data) { - kfree(psb); - return NULL; - } + /* + * Get memory from the pci pool to map the virt space to pci + * bus space for an I/O. The DMA buffer includes space for the + * struct fcp_cmnd, struct fcp_rsp and the number of bde's + * necessary to support the sg_tablesize. + */ + psb->data = pci_pool_alloc(phba->lpfc_scsi_dma_buf_pool, + GFP_KERNEL, &psb->dma_handle); + if (!psb->data) { + kfree(psb); + break; + } - /* Initialize virtual ptrs to dma_buf region. */ - memset(psb->data, 0, phba->cfg_sg_dma_buf_size); + /* Initialize virtual ptrs to dma_buf region. */ + memset(psb->data, 0, phba->cfg_sg_dma_buf_size); - /* Allocate iotag for psb->cur_iocbq. */ - iotag = lpfc_sli_next_iotag(phba, &psb->cur_iocbq); - if (iotag == 0) { - pci_pool_free(phba->lpfc_scsi_dma_buf_pool, - psb->data, psb->dma_handle); - kfree (psb); - return NULL; - } - psb->cur_iocbq.iocb_flag |= LPFC_IO_FCP; + /* Allocate iotag for psb->cur_iocbq. */ + iotag = lpfc_sli_next_iotag(phba, &psb->cur_iocbq); + if (iotag == 0) { + pci_pool_free(phba->lpfc_scsi_dma_buf_pool, + psb->data, psb->dma_handle); + kfree(psb); + break; + } + psb->cur_iocbq.iocb_flag |= LPFC_IO_FCP; - psb->fcp_cmnd = psb->data; - psb->fcp_rsp = psb->data + sizeof(struct fcp_cmnd); - psb->fcp_bpl = psb->data + sizeof(struct fcp_cmnd) + - sizeof(struct fcp_rsp); - - /* Initialize local short-hand pointers. */ - bpl = psb->fcp_bpl; - pdma_phys_fcp_cmd = psb->dma_handle; - pdma_phys_fcp_rsp = psb->dma_handle + sizeof(struct fcp_cmnd); - pdma_phys_bpl = psb->dma_handle + sizeof(struct fcp_cmnd) + + psb->fcp_cmnd = psb->data; + psb->fcp_rsp = psb->data + sizeof(struct fcp_cmnd); + psb->fcp_bpl = psb->data + sizeof(struct fcp_cmnd) + sizeof(struct fcp_rsp); - /* - * The first two bdes are the FCP_CMD and FCP_RSP. The balance are sg - * list bdes. Initialize the first two and leave the rest for - * queuecommand. - */ - bpl[0].addrHigh = le32_to_cpu(putPaddrHigh(pdma_phys_fcp_cmd)); - bpl[0].addrLow = le32_to_cpu(putPaddrLow(pdma_phys_fcp_cmd)); - bpl[0].tus.f.bdeSize = sizeof(struct fcp_cmnd); - bpl[0].tus.f.bdeFlags = BUFF_TYPE_BDE_64; - bpl[0].tus.w = le32_to_cpu(bpl[0].tus.w); + /* Initialize local short-hand pointers. */ + bpl = psb->fcp_bpl; + pdma_phys_fcp_cmd = psb->dma_handle; + pdma_phys_fcp_rsp = psb->dma_handle + sizeof(struct fcp_cmnd); + pdma_phys_bpl = psb->dma_handle + sizeof(struct fcp_cmnd) + + sizeof(struct fcp_rsp); - /* Setup the physical region for the FCP RSP */ - bpl[1].addrHigh = le32_to_cpu(putPaddrHigh(pdma_phys_fcp_rsp)); - bpl[1].addrLow = le32_to_cpu(putPaddrLow(pdma_phys_fcp_rsp)); - bpl[1].tus.f.bdeSize = sizeof(struct fcp_rsp); - bpl[1].tus.f.bdeFlags = BUFF_TYPE_BDE_64; - bpl[1].tus.w = le32_to_cpu(bpl[1].tus.w); + /* + * The first two bdes are the FCP_CMD and FCP_RSP. The balance + * are sg list bdes. Initialize the first two and leave the + * rest for queuecommand. + */ + bpl[0].addrHigh = le32_to_cpu(putPaddrHigh(pdma_phys_fcp_cmd)); + bpl[0].addrLow = le32_to_cpu(putPaddrLow(pdma_phys_fcp_cmd)); + bpl[0].tus.f.bdeSize = sizeof(struct fcp_cmnd); + bpl[0].tus.f.bdeFlags = BUFF_TYPE_BDE_64; + bpl[0].tus.w = le32_to_cpu(bpl[0].tus.w); + + /* Setup the physical region for the FCP RSP */ + bpl[1].addrHigh = le32_to_cpu(putPaddrHigh(pdma_phys_fcp_rsp)); + bpl[1].addrLow = le32_to_cpu(putPaddrLow(pdma_phys_fcp_rsp)); + bpl[1].tus.f.bdeSize = sizeof(struct fcp_rsp); + bpl[1].tus.f.bdeFlags = BUFF_TYPE_BDE_64; + bpl[1].tus.w = le32_to_cpu(bpl[1].tus.w); + + /* + * Since the IOCB for the FCP I/O is built into this + * lpfc_scsi_buf, initialize it with all known data now. + */ + iocb = &psb->cur_iocbq.iocb; + iocb->un.fcpi64.bdl.ulpIoTag32 = 0; + if ((phba->sli_rev == 3) && + !(phba->sli3_options & LPFC_SLI3_BG_ENABLED)) { + /* fill in immediate fcp command BDE */ + iocb->un.fcpi64.bdl.bdeFlags = BUFF_TYPE_BDE_IMMED; + iocb->un.fcpi64.bdl.bdeSize = sizeof(struct fcp_cmnd); + iocb->un.fcpi64.bdl.addrLow = offsetof(IOCB_t, + unsli3.fcp_ext.icd); + iocb->un.fcpi64.bdl.addrHigh = 0; + iocb->ulpBdeCount = 0; + iocb->ulpLe = 0; + /* fill in responce BDE */ + iocb->unsli3.fcp_ext.rbde.tus.f.bdeFlags = + BUFF_TYPE_BDE_64; + iocb->unsli3.fcp_ext.rbde.tus.f.bdeSize = + sizeof(struct fcp_rsp); + iocb->unsli3.fcp_ext.rbde.addrLow = + putPaddrLow(pdma_phys_fcp_rsp); + iocb->unsli3.fcp_ext.rbde.addrHigh = + putPaddrHigh(pdma_phys_fcp_rsp); + } else { + iocb->un.fcpi64.bdl.bdeFlags = BUFF_TYPE_BLP_64; + iocb->un.fcpi64.bdl.bdeSize = + (2 * sizeof(struct ulp_bde64)); + iocb->un.fcpi64.bdl.addrLow = + putPaddrLow(pdma_phys_bpl); + iocb->un.fcpi64.bdl.addrHigh = + putPaddrHigh(pdma_phys_bpl); + iocb->ulpBdeCount = 1; + iocb->ulpLe = 1; + } + iocb->ulpClass = CLASS3; + psb->status = IOSTAT_SUCCESS; + /* Put it back into the SCSI buffer list */ + lpfc_release_scsi_buf_s4(phba, psb); - /* - * Since the IOCB for the FCP I/O is built into this lpfc_scsi_buf, - * initialize it with all known data now. - */ - iocb = &psb->cur_iocbq.iocb; - iocb->un.fcpi64.bdl.ulpIoTag32 = 0; - if ((phba->sli_rev == 3) && - !(phba->sli3_options & LPFC_SLI3_BG_ENABLED)) { - /* fill in immediate fcp command BDE */ - iocb->un.fcpi64.bdl.bdeFlags = BUFF_TYPE_BDE_IMMED; - iocb->un.fcpi64.bdl.bdeSize = sizeof(struct fcp_cmnd); - iocb->un.fcpi64.bdl.addrLow = offsetof(IOCB_t, - unsli3.fcp_ext.icd); - iocb->un.fcpi64.bdl.addrHigh = 0; - iocb->ulpBdeCount = 0; - iocb->ulpLe = 0; - /* fill in responce BDE */ - iocb->unsli3.fcp_ext.rbde.tus.f.bdeFlags = BUFF_TYPE_BDE_64; - iocb->unsli3.fcp_ext.rbde.tus.f.bdeSize = - sizeof(struct fcp_rsp); - iocb->unsli3.fcp_ext.rbde.addrLow = - putPaddrLow(pdma_phys_fcp_rsp); - iocb->unsli3.fcp_ext.rbde.addrHigh = - putPaddrHigh(pdma_phys_fcp_rsp); - } else { - iocb->un.fcpi64.bdl.bdeFlags = BUFF_TYPE_BLP_64; - iocb->un.fcpi64.bdl.bdeSize = (2 * sizeof(struct ulp_bde64)); - iocb->un.fcpi64.bdl.addrLow = putPaddrLow(pdma_phys_bpl); - iocb->un.fcpi64.bdl.addrHigh = putPaddrHigh(pdma_phys_bpl); - iocb->ulpBdeCount = 1; - iocb->ulpLe = 1; } - iocb->ulpClass = CLASS3; - return psb; + return bcnt; } /** - * lpfc_get_scsi_buf - Get a scsi buffer from lpfc_scsi_buf_list list of Hba - * @phba: The Hba for which this call is being executed. + * lpfc_sli4_fcp_xri_aborted - Fast-path process of fcp xri abort + * @phba: pointer to lpfc hba data structure. + * @axri: pointer to the fcp xri abort wcqe structure. + * + * This routine is invoked by the worker thread to process a SLI4 fast-path + * FCP aborted xri. + **/ +void +lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *phba, + struct sli4_wcqe_xri_aborted *axri) +{ + uint16_t xri = bf_get(lpfc_wcqe_xa_xri, axri); + struct lpfc_scsi_buf *psb, *next_psb; + unsigned long iflag = 0; + + spin_lock_irqsave(&phba->sli4_hba.abts_scsi_buf_list_lock, iflag); + list_for_each_entry_safe(psb, next_psb, + &phba->sli4_hba.lpfc_abts_scsi_buf_list, list) { + if (psb->cur_iocbq.sli4_xritag == xri) { + list_del(&psb->list); + psb->status = IOSTAT_SUCCESS; + spin_unlock_irqrestore( + &phba->sli4_hba.abts_scsi_buf_list_lock, + iflag); + lpfc_release_scsi_buf_s4(phba, psb); + return; + } + } + spin_unlock_irqrestore(&phba->sli4_hba.abts_scsi_buf_list_lock, + iflag); +} + +/** + * lpfc_sli4_repost_scsi_sgl_list - Repsot the Scsi buffers sgl pages as block + * @phba: pointer to lpfc hba data structure. + * + * This routine walks the list of scsi buffers that have been allocated and + * repost them to the HBA by using SGL block post. This is needed after a + * pci_function_reset/warm_start or start. The lpfc_hba_down_post_s4 routine + * is responsible for moving all scsi buffers on the lpfc_abts_scsi_sgl_list + * to the lpfc_scsi_buf_list. If the repost fails, reject all scsi buffers. + * + * Returns: 0 = success, non-zero failure. + **/ +int +lpfc_sli4_repost_scsi_sgl_list(struct lpfc_hba *phba) +{ + struct lpfc_scsi_buf *psb; + int index, status, bcnt = 0, rcnt = 0, rc = 0; + LIST_HEAD(sblist); + + for (index = 0; index < phba->sli4_hba.scsi_xri_cnt; index++) { + psb = phba->sli4_hba.lpfc_scsi_psb_array[index]; + if (psb) { + /* Remove from SCSI buffer list */ + list_del(&psb->list); + /* Add it to a local SCSI buffer list */ + list_add_tail(&psb->list, &sblist); + if (++rcnt == LPFC_NEMBED_MBOX_SGL_CNT) { + bcnt = rcnt; + rcnt = 0; + } + } else + /* A hole present in the XRI array, need to skip */ + bcnt = rcnt; + + if (index == phba->sli4_hba.scsi_xri_cnt - 1) + /* End of XRI array for SCSI buffer, complete */ + bcnt = rcnt; + + /* Continue until collect up to a nembed page worth of sgls */ + if (bcnt == 0) + continue; + /* Now, post the SCSI buffer list sgls as a block */ + status = lpfc_sli4_post_scsi_sgl_block(phba, &sblist, bcnt); + /* Reset SCSI buffer count for next round of posting */ + bcnt = 0; + while (!list_empty(&sblist)) { + list_remove_head(&sblist, psb, struct lpfc_scsi_buf, + list); + if (status) { + /* Put this back on the abort scsi list */ + psb->status = IOSTAT_LOCAL_REJECT; + psb->result = IOERR_ABORT_REQUESTED; + rc++; + } else + psb->status = IOSTAT_SUCCESS; + /* Put it back into the SCSI buffer list */ + lpfc_release_scsi_buf_s4(phba, psb); + } + } + return rc; +} + +/** + * lpfc_new_scsi_buf_s4 - Scsi buffer allocator for HBA with SLI4 IF spec + * @vport: The virtual port for which this call being executed. + * @num_to_allocate: The requested number of buffers to allocate. + * + * This routine allocates a scsi buffer for device with SLI-4 interface spec, + * the scsi buffer contains all the necessary information needed to initiate + * a SCSI I/O. + * + * Return codes: + * int - number of scsi buffers that were allocated. + * 0 = failure, less than num_to_alloc is a partial failure. + **/ +static int +lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc) +{ + struct lpfc_hba *phba = vport->phba; + struct lpfc_scsi_buf *psb; + struct sli4_sge *sgl; + IOCB_t *iocb; + dma_addr_t pdma_phys_fcp_cmd; + dma_addr_t pdma_phys_fcp_rsp; + dma_addr_t pdma_phys_bpl, pdma_phys_bpl1; + uint16_t iotag, last_xritag = NO_XRI; + int status = 0, index; + int bcnt; + int non_sequential_xri = 0; + int rc = 0; + LIST_HEAD(sblist); + + for (bcnt = 0; bcnt < num_to_alloc; bcnt++) { + psb = kzalloc(sizeof(struct lpfc_scsi_buf), GFP_KERNEL); + if (!psb) + break; + + /* + * Get memory from the pci pool to map the virt space to pci bus + * space for an I/O. The DMA buffer includes space for the + * struct fcp_cmnd, struct fcp_rsp and the number of bde's + * necessary to support the sg_tablesize. + */ + psb->data = pci_pool_alloc(phba->lpfc_scsi_dma_buf_pool, + GFP_KERNEL, &psb->dma_handle); + if (!psb->data) { + kfree(psb); + break; + } + + /* Initialize virtual ptrs to dma_buf region. */ + memset(psb->data, 0, phba->cfg_sg_dma_buf_size); + + /* Allocate iotag for psb->cur_iocbq. */ + iotag = lpfc_sli_next_iotag(phba, &psb->cur_iocbq); + if (iotag == 0) { + kfree(psb); + break; + } + + psb->cur_iocbq.sli4_xritag = lpfc_sli4_next_xritag(phba); + if (psb->cur_iocbq.sli4_xritag == NO_XRI) { + pci_pool_free(phba->lpfc_scsi_dma_buf_pool, + psb->data, psb->dma_handle); + kfree(psb); + break; + } + if (last_xritag != NO_XRI + && psb->cur_iocbq.sli4_xritag != (last_xritag+1)) { + non_sequential_xri = 1; + } else + list_add_tail(&psb->list, &sblist); + last_xritag = psb->cur_iocbq.sli4_xritag; + + index = phba->sli4_hba.scsi_xri_cnt++; + psb->cur_iocbq.iocb_flag |= LPFC_IO_FCP; + + psb->fcp_bpl = psb->data; + psb->fcp_cmnd = (psb->data + phba->cfg_sg_dma_buf_size) + - (sizeof(struct fcp_cmnd) + sizeof(struct fcp_rsp)); + psb->fcp_rsp = (struct fcp_rsp *)((uint8_t *)psb->fcp_cmnd + + sizeof(struct fcp_cmnd)); + + /* Initialize local short-hand pointers. */ + sgl = (struct sli4_sge *)psb->fcp_bpl; + pdma_phys_bpl = psb->dma_handle; + pdma_phys_fcp_cmd = + (psb->dma_handle + phba->cfg_sg_dma_buf_size) + - (sizeof(struct fcp_cmnd) + sizeof(struct fcp_rsp)); + pdma_phys_fcp_rsp = pdma_phys_fcp_cmd + sizeof(struct fcp_cmnd); + + /* + * The first two bdes are the FCP_CMD and FCP_RSP. The balance + * are sg list bdes. Initialize the first two and leave the + * rest for queuecommand. + */ + sgl->addr_hi = cpu_to_le32(putPaddrHigh(pdma_phys_fcp_cmd)); + sgl->addr_lo = cpu_to_le32(putPaddrLow(pdma_phys_fcp_cmd)); + bf_set(lpfc_sli4_sge_len, sgl, sizeof(struct fcp_cmnd)); + bf_set(lpfc_sli4_sge_last, sgl, 0); + sgl->word2 = cpu_to_le32(sgl->word2); + sgl->word3 = cpu_to_le32(sgl->word3); + sgl++; + + /* Setup the physical region for the FCP RSP */ + sgl->addr_hi = cpu_to_le32(putPaddrHigh(pdma_phys_fcp_rsp)); + sgl->addr_lo = cpu_to_le32(putPaddrLow(pdma_phys_fcp_rsp)); + bf_set(lpfc_sli4_sge_len, sgl, sizeof(struct fcp_rsp)); + bf_set(lpfc_sli4_sge_last, sgl, 1); + sgl->word2 = cpu_to_le32(sgl->word2); + sgl->word3 = cpu_to_le32(sgl->word3); + + /* + * Since the IOCB for the FCP I/O is built into this + * lpfc_scsi_buf, initialize it with all known data now. + */ + iocb = &psb->cur_iocbq.iocb; + iocb->un.fcpi64.bdl.ulpIoTag32 = 0; + iocb->un.fcpi64.bdl.bdeFlags = BUFF_TYPE_BDE_64; + /* setting the BLP size to 2 * sizeof BDE may not be correct. + * We are setting the bpl to point to out sgl. An sgl's + * entries are 16 bytes, a bpl entries are 12 bytes. + */ + iocb->un.fcpi64.bdl.bdeSize = sizeof(struct fcp_cmnd); + iocb->un.fcpi64.bdl.addrLow = putPaddrLow(pdma_phys_fcp_cmd); + iocb->un.fcpi64.bdl.addrHigh = putPaddrHigh(pdma_phys_fcp_cmd); + iocb->ulpBdeCount = 1; + iocb->ulpLe = 1; + iocb->ulpClass = CLASS3; + if (phba->cfg_sg_dma_buf_size > SGL_PAGE_SIZE) + pdma_phys_bpl1 = pdma_phys_bpl + SGL_PAGE_SIZE; + else + pdma_phys_bpl1 = 0; + psb->dma_phys_bpl = pdma_phys_bpl; + phba->sli4_hba.lpfc_scsi_psb_array[index] = psb; + if (non_sequential_xri) { + status = lpfc_sli4_post_sgl(phba, pdma_phys_bpl, + pdma_phys_bpl1, + psb->cur_iocbq.sli4_xritag); + if (status) { + /* Put this back on the abort scsi list */ + psb->status = IOSTAT_LOCAL_REJECT; + psb->result = IOERR_ABORT_REQUESTED; + rc++; + } else + psb->status = IOSTAT_SUCCESS; + /* Put it back into the SCSI buffer list */ + lpfc_release_scsi_buf_s4(phba, psb); + break; + } + } + if (bcnt) { + status = lpfc_sli4_post_scsi_sgl_block(phba, &sblist, bcnt); + /* Reset SCSI buffer count for next round of posting */ + while (!list_empty(&sblist)) { + list_remove_head(&sblist, psb, struct lpfc_scsi_buf, + list); + if (status) { + /* Put this back on the abort scsi list */ + psb->status = IOSTAT_LOCAL_REJECT; + psb->result = IOERR_ABORT_REQUESTED; + rc++; + } else + psb->status = IOSTAT_SUCCESS; + /* Put it back into the SCSI buffer list */ + lpfc_release_scsi_buf_s4(phba, psb); + } + } + + return bcnt + non_sequential_xri - rc; +} + +/** + * lpfc_new_scsi_buf - Wrapper funciton for scsi buffer allocator + * @vport: The virtual port for which this call being executed. + * @num_to_allocate: The requested number of buffers to allocate. + * + * This routine wraps the actual SCSI buffer allocator function pointer from + * the lpfc_hba struct. + * + * Return codes: + * int - number of scsi buffers that were allocated. + * 0 = failure, less than num_to_alloc is a partial failure. + **/ +static inline int +lpfc_new_scsi_buf(struct lpfc_vport *vport, int num_to_alloc) +{ + return vport->phba->lpfc_new_scsi_buf(vport, num_to_alloc); +} + +/** + * lpfc_get_scsi_buf - Get a scsi buffer from lpfc_scsi_buf_list of the HBA + * @phba: The HBA for which this call is being executed. * * This routine removes a scsi buffer from head of @phba lpfc_scsi_buf_list list * and returns to caller. @@ -591,7 +911,7 @@ lpfc_get_scsi_buf(struct lpfc_hba * phba) } /** - * lpfc_release_scsi_buf - Return a scsi buffer back to hba's lpfc_scsi_buf_list + * lpfc_release_scsi_buf - Return a scsi buffer back to hba scsi buf list * @phba: The Hba for which this call is being executed. * @psb: The scsi buffer which is being released. * @@ -599,7 +919,7 @@ lpfc_get_scsi_buf(struct lpfc_hba * phba) * lpfc_scsi_buf_list list. **/ static void -lpfc_release_scsi_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb) +lpfc_release_scsi_buf_s3(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb) { unsigned long iflag = 0; @@ -610,21 +930,69 @@ lpfc_release_scsi_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb) } /** - * lpfc_scsi_prep_dma_buf - Routine to do DMA mapping for scsi buffer + * lpfc_release_scsi_buf_s4: Return a scsi buffer back to hba scsi buf list. + * @phba: The Hba for which this call is being executed. + * @psb: The scsi buffer which is being released. + * + * This routine releases @psb scsi buffer by adding it to tail of @phba + * lpfc_scsi_buf_list list. For SLI4 XRI's are tied to the scsi buffer + * and cannot be reused for at least RA_TOV amount of time if it was + * aborted. + **/ +static void +lpfc_release_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb) +{ + unsigned long iflag = 0; + + if (psb->status == IOSTAT_LOCAL_REJECT + && psb->result == IOERR_ABORT_REQUESTED) { + spin_lock_irqsave(&phba->sli4_hba.abts_scsi_buf_list_lock, + iflag); + psb->pCmd = NULL; + list_add_tail(&psb->list, + &phba->sli4_hba.lpfc_abts_scsi_buf_list); + spin_unlock_irqrestore(&phba->sli4_hba.abts_scsi_buf_list_lock, + iflag); + } else { + + spin_lock_irqsave(&phba->scsi_buf_list_lock, iflag); + psb->pCmd = NULL; + list_add_tail(&psb->list, &phba->lpfc_scsi_buf_list); + spin_unlock_irqrestore(&phba->scsi_buf_list_lock, iflag); + } +} + +/** + * lpfc_release_scsi_buf: Return a scsi buffer back to hba scsi buf list. + * @phba: The Hba for which this call is being executed. + * @psb: The scsi buffer which is being released. + * + * This routine releases @psb scsi buffer by adding it to tail of @phba + * lpfc_scsi_buf_list list. + **/ +static void +lpfc_release_scsi_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb) +{ + + phba->lpfc_release_scsi_buf(phba, psb); +} + +/** + * lpfc_scsi_prep_dma_buf_s3 - DMA mapping for scsi buffer to SLI3 IF spec * @phba: The Hba for which this call is being executed. * @lpfc_cmd: The scsi buffer which is going to be mapped. * * This routine does the pci dma mapping for scatter-gather list of scsi cmnd - * field of @lpfc_cmd. This routine scans through sg elements and format the - * bdea. This routine also initializes all IOCB fields which are dependent on - * scsi command request buffer. + * field of @lpfc_cmd for device with SLI-3 interface spec. This routine scans + * through sg elements and format the bdea. This routine also initializes all + * IOCB fields which are dependent on scsi command request buffer. * * Return codes: * 1 - Error * 0 - Success **/ static int -lpfc_scsi_prep_dma_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd) +lpfc_scsi_prep_dma_buf_s3(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd) { struct scsi_cmnd *scsi_cmnd = lpfc_cmd->pCmd; struct scatterlist *sgel = NULL; @@ -827,8 +1195,8 @@ lpfc_cmd_blksize(struct scsi_cmnd *sc) * @reftag: out: ref tag (reference tag) * * Description: - * Extract DIF paramters from the command if possible. Otherwise, - * use default paratmers. + * Extract DIF parameters from the command if possible. Otherwise, + * use default parameters. * **/ static inline void @@ -1312,10 +1680,10 @@ lpfc_parse_bg_err(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd, uint32_t bgstat = bgf->bgstat; uint64_t failing_sector = 0; - printk(KERN_ERR "BG ERROR in cmd 0x%x lba 0x%llx blk cnt 0x%lx " + printk(KERN_ERR "BG ERROR in cmd 0x%x lba 0x%llx blk cnt 0x%x " "bgstat=0x%x bghm=0x%x\n", cmd->cmnd[0], (unsigned long long)scsi_get_lba(cmd), - cmd->request->nr_sectors, bgstat, bghm); + blk_rq_sectors(cmd->request), bgstat, bghm); spin_lock(&_dump_buf_lock); if (!_dump_buf_done) { @@ -1411,6 +1779,133 @@ out: return ret; } +/** + * lpfc_scsi_prep_dma_buf_s4 - DMA mapping for scsi buffer to SLI4 IF spec + * @phba: The Hba for which this call is being executed. + * @lpfc_cmd: The scsi buffer which is going to be mapped. + * + * This routine does the pci dma mapping for scatter-gather list of scsi cmnd + * field of @lpfc_cmd for device with SLI-4 interface spec. + * + * Return codes: + * 1 - Error + * 0 - Success + **/ +static int +lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd) +{ + struct scsi_cmnd *scsi_cmnd = lpfc_cmd->pCmd; + struct scatterlist *sgel = NULL; + struct fcp_cmnd *fcp_cmnd = lpfc_cmd->fcp_cmnd; + struct sli4_sge *sgl = (struct sli4_sge *)lpfc_cmd->fcp_bpl; + IOCB_t *iocb_cmd = &lpfc_cmd->cur_iocbq.iocb; + dma_addr_t physaddr; + uint32_t num_bde = 0; + uint32_t dma_len; + uint32_t dma_offset = 0; + int nseg; + + /* + * There are three possibilities here - use scatter-gather segment, use + * the single mapping, or neither. Start the lpfc command prep by + * bumping the bpl beyond the fcp_cmnd and fcp_rsp regions to the first + * data bde entry. + */ + if (scsi_sg_count(scsi_cmnd)) { + /* + * The driver stores the segment count returned from pci_map_sg + * because this a count of dma-mappings used to map the use_sg + * pages. They are not guaranteed to be the same for those + * architectures that implement an IOMMU. + */ + + nseg = scsi_dma_map(scsi_cmnd); + if (unlikely(!nseg)) + return 1; + sgl += 1; + /* clear the last flag in the fcp_rsp map entry */ + sgl->word2 = le32_to_cpu(sgl->word2); + bf_set(lpfc_sli4_sge_last, sgl, 0); + sgl->word2 = cpu_to_le32(sgl->word2); + sgl += 1; + + lpfc_cmd->seg_cnt = nseg; + if (lpfc_cmd->seg_cnt > phba->cfg_sg_seg_cnt) { + printk(KERN_ERR "%s: Too many sg segments from " + "dma_map_sg. Config %d, seg_cnt %d\n", + __func__, phba->cfg_sg_seg_cnt, + lpfc_cmd->seg_cnt); + scsi_dma_unmap(scsi_cmnd); + return 1; + } + + /* + * The driver established a maximum scatter-gather segment count + * during probe that limits the number of sg elements in any + * single scsi command. Just run through the seg_cnt and format + * the sge's. + * When using SLI-3 the driver will try to fit all the BDEs into + * the IOCB. If it can't then the BDEs get added to a BPL as it + * does for SLI-2 mode. + */ + scsi_for_each_sg(scsi_cmnd, sgel, nseg, num_bde) { + physaddr = sg_dma_address(sgel); + dma_len = sg_dma_len(sgel); + bf_set(lpfc_sli4_sge_len, sgl, sg_dma_len(sgel)); + sgl->addr_lo = cpu_to_le32(putPaddrLow(physaddr)); + sgl->addr_hi = cpu_to_le32(putPaddrHigh(physaddr)); + if ((num_bde + 1) == nseg) + bf_set(lpfc_sli4_sge_last, sgl, 1); + else + bf_set(lpfc_sli4_sge_last, sgl, 0); + bf_set(lpfc_sli4_sge_offset, sgl, dma_offset); + sgl->word2 = cpu_to_le32(sgl->word2); + sgl->word3 = cpu_to_le32(sgl->word3); + dma_offset += dma_len; + sgl++; + } + } else { + sgl += 1; + /* clear the last flag in the fcp_rsp map entry */ + sgl->word2 = le32_to_cpu(sgl->word2); + bf_set(lpfc_sli4_sge_last, sgl, 1); + sgl->word2 = cpu_to_le32(sgl->word2); + } + + /* + * Finish initializing those IOCB fields that are dependent on the + * scsi_cmnd request_buffer. Note that for SLI-2 the bdeSize is + * explicitly reinitialized. + * all iocb memory resources are reused. + */ + fcp_cmnd->fcpDl = cpu_to_be32(scsi_bufflen(scsi_cmnd)); + + /* + * Due to difference in data length between DIF/non-DIF paths, + * we need to set word 4 of IOCB here + */ + iocb_cmd->un.fcpi.fcpi_parm = scsi_bufflen(scsi_cmnd); + return 0; +} + +/** + * lpfc_scsi_prep_dma_buf - Wrapper function for DMA mapping of scsi buffer + * @phba: The Hba for which this call is being executed. + * @lpfc_cmd: The scsi buffer which is going to be mapped. + * + * This routine wraps the actual DMA mapping function pointer from the + * lpfc_hba struct. + * + * Return codes: + * 1 - Error + * 0 - Success + **/ +static inline int +lpfc_scsi_prep_dma_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd) +{ + return phba->lpfc_scsi_prep_dma_buf(phba, lpfc_cmd); +} + /** * lpfc_send_scsi_error_event - Posts an event when there is SCSI error * @phba: Pointer to hba context object. @@ -1504,15 +1999,15 @@ lpfc_send_scsi_error_event(struct lpfc_hba *phba, struct lpfc_vport *vport, } /** - * lpfc_scsi_unprep_dma_buf - Routine to un-map DMA mapping of scatter gather - * @phba: The Hba for which this call is being executed. + * lpfc_scsi_unprep_dma_buf - Un-map DMA mapping of SG-list for dev + * @phba: The HBA for which this call is being executed. * @psb: The scsi buffer which is going to be un-mapped. * * This routine does DMA un-mapping of scatter gather list of scsi command - * field of @lpfc_cmd. + * field of @lpfc_cmd for device with SLI-3 interface spec. **/ static void -lpfc_scsi_unprep_dma_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * psb) +lpfc_scsi_unprep_dma_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb) { /* * There are only two special cases to consider. (1) the scsi command @@ -1676,7 +2171,7 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, * lpfc_scsi_cmd_iocb_cmpl - Scsi cmnd IOCB completion routine * @phba: The Hba for which this call is being executed. * @pIocbIn: The command IOCBQ for the scsi cmnd. - * @pIocbOut: The response IOCBQ for the scsi cmnd . + * @pIocbOut: The response IOCBQ for the scsi cmnd. * * This routine assigns scsi command result by looking into response IOCB * status field appropriately. This routine handles QUEUE FULL condition as @@ -1957,13 +2452,13 @@ lpfc_fcpcmd_to_iocb(uint8_t *data, struct fcp_cmnd *fcp_cmnd) } /** - * lpfc_scsi_prep_cmnd - Routine to convert scsi cmnd to FCP information unit + * lpfc_scsi_prep_cmnd - Wrapper func for convert scsi cmnd to FCP info unit * @vport: The virtual port for which this call is being executed. * @lpfc_cmd: The scsi command which needs to send. * @pnode: Pointer to lpfc_nodelist. * * This routine initializes fcp_cmnd and iocb data structure from scsi command - * to transfer. + * to transfer for device with SLI3 interface spec. **/ static void lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, @@ -2013,8 +2508,11 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, if (scsi_sg_count(scsi_cmnd)) { if (datadir == DMA_TO_DEVICE) { iocb_cmd->ulpCommand = CMD_FCP_IWRITE64_CR; - iocb_cmd->un.fcpi.fcpi_parm = 0; - iocb_cmd->ulpPU = 0; + if (phba->sli_rev < LPFC_SLI_REV4) { + iocb_cmd->un.fcpi.fcpi_parm = 0; + iocb_cmd->ulpPU = 0; + } else + iocb_cmd->ulpPU = PARM_READ_CHECK; fcp_cmnd->fcpCntl3 = WRITE_DATA; phba->fc4OutputRequests++; } else { @@ -2051,13 +2549,14 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, } /** - * lpfc_scsi_prep_task_mgmt_cmnd - Convert scsi TM cmnd to FCP information unit + * lpfc_scsi_prep_task_mgmt_cmnd - Convert SLI3 scsi TM cmd to FCP info unit * @vport: The virtual port for which this call is being executed. * @lpfc_cmd: Pointer to lpfc_scsi_buf data structure. * @lun: Logical unit number. * @task_mgmt_cmd: SCSI task management command. * - * This routine creates FCP information unit corresponding to @task_mgmt_cmd. + * This routine creates FCP information unit corresponding to @task_mgmt_cmd + * for device with SLI-3 interface spec. * * Return codes: * 0 - Error @@ -2106,13 +2605,55 @@ lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_vport *vport, * The driver will provide the timeout mechanism. */ piocb->ulpTimeout = 0; - } else { + } else piocb->ulpTimeout = lpfc_cmd->timeout; - } + + if (vport->phba->sli_rev == LPFC_SLI_REV4) + lpfc_sli4_set_rsp_sgl_last(vport->phba, lpfc_cmd); return 1; } +/** + * lpfc_scsi_api_table_setup - Set up scsi api fucntion jump table + * @phba: The hba struct for which this call is being executed. + * @dev_grp: The HBA PCI-Device group number. + * + * This routine sets up the SCSI interface API function jump table in @phba + * struct. + * Returns: 0 - success, -ENODEV - failure. + **/ +int +lpfc_scsi_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp) +{ + + phba->lpfc_scsi_unprep_dma_buf = lpfc_scsi_unprep_dma_buf; + phba->lpfc_scsi_prep_cmnd = lpfc_scsi_prep_cmnd; + phba->lpfc_get_scsi_buf = lpfc_get_scsi_buf; + + switch (dev_grp) { + case LPFC_PCI_DEV_LP: + phba->lpfc_new_scsi_buf = lpfc_new_scsi_buf_s3; + phba->lpfc_scsi_prep_dma_buf = lpfc_scsi_prep_dma_buf_s3; + phba->lpfc_release_scsi_buf = lpfc_release_scsi_buf_s3; + break; + case LPFC_PCI_DEV_OC: + phba->lpfc_new_scsi_buf = lpfc_new_scsi_buf_s4; + phba->lpfc_scsi_prep_dma_buf = lpfc_scsi_prep_dma_buf_s4; + phba->lpfc_release_scsi_buf = lpfc_release_scsi_buf_s4; + break; + default: + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "1418 Invalid HBA PCI-device group: 0x%x\n", + dev_grp); + return -ENODEV; + break; + } + phba->lpfc_get_scsi_buf = lpfc_get_scsi_buf; + phba->lpfc_rampdown_queue_depth = lpfc_rampdown_queue_depth; + return 0; +} + /** * lpfc_taskmgmt_def_cmpl - IOCB completion routine for task management command * @phba: The Hba for which this call is being executed. @@ -2134,73 +2675,6 @@ lpfc_tskmgmt_def_cmpl(struct lpfc_hba *phba, return; } -/** - * lpfc_scsi_tgt_reset - Target reset handler - * @lpfc_cmd: Pointer to lpfc_scsi_buf data structure - * @vport: The virtual port for which this call is being executed. - * @tgt_id: Target ID. - * @lun: Lun number. - * @rdata: Pointer to lpfc_rport_data. - * - * This routine issues a TARGET RESET iocb to reset a target with @tgt_id ID. - * - * Return Code: - * 0x2003 - Error - * 0x2002 - Success. - **/ -static int -lpfc_scsi_tgt_reset(struct lpfc_scsi_buf *lpfc_cmd, struct lpfc_vport *vport, - unsigned tgt_id, unsigned int lun, - struct lpfc_rport_data *rdata) -{ - struct lpfc_hba *phba = vport->phba; - struct lpfc_iocbq *iocbq; - struct lpfc_iocbq *iocbqrsp; - int ret; - int status; - - if (!rdata->pnode || !NLP_CHK_NODE_ACT(rdata->pnode)) - return FAILED; - - lpfc_cmd->rdata = rdata; - status = lpfc_scsi_prep_task_mgmt_cmd(vport, lpfc_cmd, lun, - FCP_TARGET_RESET); - if (!status) - return FAILED; - - iocbq = &lpfc_cmd->cur_iocbq; - iocbqrsp = lpfc_sli_get_iocbq(phba); - - if (!iocbqrsp) - return FAILED; - - /* Issue Target Reset to TGT */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP, - "0702 Issue Target Reset to TGT %d Data: x%x x%x\n", - tgt_id, rdata->pnode->nlp_rpi, rdata->pnode->nlp_flag); - status = lpfc_sli_issue_iocb_wait(phba, - &phba->sli.ring[phba->sli.fcp_ring], - iocbq, iocbqrsp, lpfc_cmd->timeout); - if (status != IOCB_SUCCESS) { - if (status == IOCB_TIMEDOUT) { - iocbq->iocb_cmpl = lpfc_tskmgmt_def_cmpl; - ret = TIMEOUT_ERROR; - } else - ret = FAILED; - lpfc_cmd->status = IOSTAT_DRIVER_REJECT; - } else { - ret = SUCCESS; - lpfc_cmd->result = iocbqrsp->iocb.un.ulpWord[4]; - lpfc_cmd->status = iocbqrsp->iocb.ulpStatus; - if (lpfc_cmd->status == IOSTAT_LOCAL_REJECT && - (lpfc_cmd->result & IOERR_DRVR_MASK)) - lpfc_cmd->status = IOSTAT_DRIVER_REJECT; - } - - lpfc_sli_release_iocbq(phba, iocbqrsp); - return ret; -} - /** * lpfc_info - Info entry point of scsi_host_template data structure * @host: The scsi host for which this call is being executed. @@ -2305,7 +2779,6 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) struct Scsi_Host *shost = cmnd->device->host; struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; - struct lpfc_sli *psli = &phba->sli; struct lpfc_rport_data *rdata = cmnd->device->hostdata; struct lpfc_nodelist *ndlp = rdata->pnode; struct lpfc_scsi_buf *lpfc_cmd; @@ -2378,15 +2851,15 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) if (cmnd->cmnd[0] == READ_10) lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG, "9035 BLKGRD: READ @ sector %llu, " - "count %lu\n", - (unsigned long long)scsi_get_lba(cmnd), - cmnd->request->nr_sectors); + "count %u\n", + (unsigned long long)scsi_get_lba(cmnd), + blk_rq_sectors(cmnd->request)); else if (cmnd->cmnd[0] == WRITE_10) lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG, "9036 BLKGRD: WRITE @ sector %llu, " - "count %lu cmd=%p\n", + "count %u cmd=%p\n", (unsigned long long)scsi_get_lba(cmnd), - cmnd->request->nr_sectors, + blk_rq_sectors(cmnd->request), cmnd); err = lpfc_bg_scsi_prep_dma_buf(phba, lpfc_cmd); @@ -2406,15 +2879,15 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) if (cmnd->cmnd[0] == READ_10) lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG, "9040 dbg: READ @ sector %llu, " - "count %lu\n", + "count %u\n", (unsigned long long)scsi_get_lba(cmnd), - cmnd->request->nr_sectors); + blk_rq_sectors(cmnd->request)); else if (cmnd->cmnd[0] == WRITE_10) lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG, "9041 dbg: WRITE @ sector %llu, " - "count %lu cmd=%p\n", + "count %u cmd=%p\n", (unsigned long long)scsi_get_lba(cmnd), - cmnd->request->nr_sectors, cmnd); + blk_rq_sectors(cmnd->request), cmnd); else lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG, "9042 dbg: parser not implemented\n"); @@ -2427,7 +2900,7 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) lpfc_scsi_prep_cmnd(vport, lpfc_cmd, ndlp); atomic_inc(&ndlp->cmd_pending); - err = lpfc_sli_issue_iocb(phba, &phba->sli.ring[psli->fcp_ring], + err = lpfc_sli_issue_iocb(phba, LPFC_FCP_RING, &lpfc_cmd->cur_iocbq, SLI_IOCB_RET_IOCB); if (err) { atomic_dec(&ndlp->cmd_pending); @@ -2490,7 +2963,6 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) struct Scsi_Host *shost = cmnd->device->host; struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; - struct lpfc_sli_ring *pring = &phba->sli.ring[phba->sli.fcp_ring]; struct lpfc_iocbq *iocb; struct lpfc_iocbq *abtsiocb; struct lpfc_scsi_buf *lpfc_cmd; @@ -2531,7 +3003,10 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) icmd = &abtsiocb->iocb; icmd->un.acxri.abortType = ABORT_TYPE_ABTS; icmd->un.acxri.abortContextTag = cmd->ulpContext; - icmd->un.acxri.abortIoTag = cmd->ulpIoTag; + if (phba->sli_rev == LPFC_SLI_REV4) + icmd->un.acxri.abortIoTag = iocb->sli4_xritag; + else + icmd->un.acxri.abortIoTag = cmd->ulpIoTag; icmd->ulpLe = 1; icmd->ulpClass = cmd->ulpClass; @@ -2542,7 +3017,8 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) abtsiocb->iocb_cmpl = lpfc_sli_abort_fcp_cmpl; abtsiocb->vport = vport; - if (lpfc_sli_issue_iocb(phba, pring, abtsiocb, 0) == IOCB_ERROR) { + if (lpfc_sli_issue_iocb(phba, LPFC_FCP_RING, abtsiocb, 0) == + IOCB_ERROR) { lpfc_sli_release_iocbq(phba, abtsiocb); ret = FAILED; goto out; @@ -2579,11 +3055,201 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) return ret; } +static char * +lpfc_taskmgmt_name(uint8_t task_mgmt_cmd) +{ + switch (task_mgmt_cmd) { + case FCP_ABORT_TASK_SET: + return "ABORT_TASK_SET"; + case FCP_CLEAR_TASK_SET: + return "FCP_CLEAR_TASK_SET"; + case FCP_BUS_RESET: + return "FCP_BUS_RESET"; + case FCP_LUN_RESET: + return "FCP_LUN_RESET"; + case FCP_TARGET_RESET: + return "FCP_TARGET_RESET"; + case FCP_CLEAR_ACA: + return "FCP_CLEAR_ACA"; + case FCP_TERMINATE_TASK: + return "FCP_TERMINATE_TASK"; + default: + return "unknown"; + } +} + +/** + * lpfc_send_taskmgmt - Generic SCSI Task Mgmt Handler + * @vport: The virtual port for which this call is being executed. + * @rdata: Pointer to remote port local data + * @tgt_id: Target ID of remote device. + * @lun_id: Lun number for the TMF + * @task_mgmt_cmd: type of TMF to send + * + * This routine builds and sends a TMF (SCSI Task Mgmt Function) to + * a remote port. + * + * Return Code: + * 0x2003 - Error + * 0x2002 - Success. + **/ +static int +lpfc_send_taskmgmt(struct lpfc_vport *vport, struct lpfc_rport_data *rdata, + unsigned tgt_id, unsigned int lun_id, + uint8_t task_mgmt_cmd) +{ + struct lpfc_hba *phba = vport->phba; + struct lpfc_scsi_buf *lpfc_cmd; + struct lpfc_iocbq *iocbq; + struct lpfc_iocbq *iocbqrsp; + int ret; + int status; + + if (!rdata->pnode || !NLP_CHK_NODE_ACT(rdata->pnode)) + return FAILED; + + lpfc_cmd = lpfc_get_scsi_buf(phba); + if (lpfc_cmd == NULL) + return FAILED; + lpfc_cmd->timeout = 60; + lpfc_cmd->rdata = rdata; + + status = lpfc_scsi_prep_task_mgmt_cmd(vport, lpfc_cmd, lun_id, + task_mgmt_cmd); + if (!status) { + lpfc_release_scsi_buf(phba, lpfc_cmd); + return FAILED; + } + + iocbq = &lpfc_cmd->cur_iocbq; + iocbqrsp = lpfc_sli_get_iocbq(phba); + if (iocbqrsp == NULL) { + lpfc_release_scsi_buf(phba, lpfc_cmd); + return FAILED; + } + + lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP, + "0702 Issue %s to TGT %d LUN %d " + "rpi x%x nlp_flag x%x\n", + lpfc_taskmgmt_name(task_mgmt_cmd), tgt_id, lun_id, + rdata->pnode->nlp_rpi, rdata->pnode->nlp_flag); + + status = lpfc_sli_issue_iocb_wait(phba, LPFC_FCP_RING, + iocbq, iocbqrsp, lpfc_cmd->timeout); + if (status != IOCB_SUCCESS) { + if (status == IOCB_TIMEDOUT) { + iocbq->iocb_cmpl = lpfc_tskmgmt_def_cmpl; + ret = TIMEOUT_ERROR; + } else + ret = FAILED; + lpfc_cmd->status = IOSTAT_DRIVER_REJECT; + lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, + "0727 TMF %s to TGT %d LUN %d failed (%d, %d)\n", + lpfc_taskmgmt_name(task_mgmt_cmd), + tgt_id, lun_id, iocbqrsp->iocb.ulpStatus, + iocbqrsp->iocb.un.ulpWord[4]); + } else + ret = SUCCESS; + + lpfc_sli_release_iocbq(phba, iocbqrsp); + + if (ret != TIMEOUT_ERROR) + lpfc_release_scsi_buf(phba, lpfc_cmd); + + return ret; +} + +/** + * lpfc_chk_tgt_mapped - + * @vport: The virtual port to check on + * @cmnd: Pointer to scsi_cmnd data structure. + * + * This routine delays until the scsi target (aka rport) for the + * command exists (is present and logged in) or we declare it non-existent. + * + * Return code : + * 0x2003 - Error + * 0x2002 - Success + **/ +static int +lpfc_chk_tgt_mapped(struct lpfc_vport *vport, struct scsi_cmnd *cmnd) +{ + struct lpfc_rport_data *rdata = cmnd->device->hostdata; + struct lpfc_nodelist *pnode = rdata->pnode; + unsigned long later; + + /* + * If target is not in a MAPPED state, delay until + * target is rediscovered or devloss timeout expires. + */ + later = msecs_to_jiffies(2 * vport->cfg_devloss_tmo * 1000) + jiffies; + while (time_after(later, jiffies)) { + if (!pnode || !NLP_CHK_NODE_ACT(pnode)) + return FAILED; + if (pnode->nlp_state == NLP_STE_MAPPED_NODE) + return SUCCESS; + schedule_timeout_uninterruptible(msecs_to_jiffies(500)); + rdata = cmnd->device->hostdata; + if (!rdata) + return FAILED; + pnode = rdata->pnode; + } + if (!pnode || !NLP_CHK_NODE_ACT(pnode) || + (pnode->nlp_state != NLP_STE_MAPPED_NODE)) + return FAILED; + return SUCCESS; +} + +/** + * lpfc_reset_flush_io_context - + * @vport: The virtual port (scsi_host) for the flush context + * @tgt_id: If aborting by Target contect - specifies the target id + * @lun_id: If aborting by Lun context - specifies the lun id + * @context: specifies the context level to flush at. + * + * After a reset condition via TMF, we need to flush orphaned i/o + * contexts from the adapter. This routine aborts any contexts + * outstanding, then waits for their completions. The wait is + * bounded by devloss_tmo though. + * + * Return code : + * 0x2003 - Error + * 0x2002 - Success + **/ +static int +lpfc_reset_flush_io_context(struct lpfc_vport *vport, uint16_t tgt_id, + uint64_t lun_id, lpfc_ctx_cmd context) +{ + struct lpfc_hba *phba = vport->phba; + unsigned long later; + int cnt; + + cnt = lpfc_sli_sum_iocb(vport, tgt_id, lun_id, context); + if (cnt) + lpfc_sli_abort_iocb(vport, &phba->sli.ring[phba->sli.fcp_ring], + tgt_id, lun_id, context); + later = msecs_to_jiffies(2 * vport->cfg_devloss_tmo * 1000) + jiffies; + while (time_after(later, jiffies) && cnt) { + schedule_timeout_uninterruptible(msecs_to_jiffies(20)); + cnt = lpfc_sli_sum_iocb(vport, tgt_id, lun_id, context); + } + if (cnt) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, + "0724 I/O flush failure for context %s : cnt x%x\n", + ((context == LPFC_CTX_LUN) ? "LUN" : + ((context == LPFC_CTX_TGT) ? "TGT" : + ((context == LPFC_CTX_HOST) ? "HOST" : "Unknown"))), + cnt); + return FAILED; + } + return SUCCESS; +} + /** * lpfc_device_reset_handler - scsi_host_template eh_device_reset entry point * @cmnd: Pointer to scsi_cmnd data structure. * - * This routine does a device reset by sending a TARGET_RESET task management + * This routine does a device reset by sending a LUN_RESET task management * command. * * Return code : @@ -2595,33 +3261,79 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd) { struct Scsi_Host *shost = cmnd->device->host; struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - struct lpfc_scsi_buf *lpfc_cmd; - struct lpfc_iocbq *iocbq, *iocbqrsp; struct lpfc_rport_data *rdata = cmnd->device->hostdata; struct lpfc_nodelist *pnode = rdata->pnode; - unsigned long later; - int ret = SUCCESS; - int status; - int cnt; + unsigned tgt_id = cmnd->device->id; + unsigned int lun_id = cmnd->device->lun; struct lpfc_scsi_event_header scsi_event; + int status; lpfc_block_error_handler(cmnd); + + status = lpfc_chk_tgt_mapped(vport, cmnd); + if (status == FAILED) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, + "0721 Device Reset rport failure: rdata x%p\n", rdata); + return FAILED; + } + + scsi_event.event_type = FC_REG_SCSI_EVENT; + scsi_event.subcategory = LPFC_EVENT_LUNRESET; + scsi_event.lun = lun_id; + memcpy(scsi_event.wwpn, &pnode->nlp_portname, sizeof(struct lpfc_name)); + memcpy(scsi_event.wwnn, &pnode->nlp_nodename, sizeof(struct lpfc_name)); + + fc_host_post_vendor_event(shost, fc_get_event_number(), + sizeof(scsi_event), (char *)&scsi_event, LPFC_NL_VENDOR_ID); + + status = lpfc_send_taskmgmt(vport, rdata, tgt_id, lun_id, + FCP_LUN_RESET); + + lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, + "0713 SCSI layer issued Device Reset (%d, %d) " + "return x%x\n", tgt_id, lun_id, status); + /* - * If target is not in a MAPPED state, delay the reset until - * target is rediscovered or devloss timeout expires. + * We have to clean up i/o as : they may be orphaned by the TMF; + * or if the TMF failed, they may be in an indeterminate state. + * So, continue on. + * We will report success if all the i/o aborts successfully. */ - later = msecs_to_jiffies(2 * vport->cfg_devloss_tmo * 1000) + jiffies; - while (time_after(later, jiffies)) { - if (!pnode || !NLP_CHK_NODE_ACT(pnode)) - return FAILED; - if (pnode->nlp_state == NLP_STE_MAPPED_NODE) - break; - schedule_timeout_uninterruptible(msecs_to_jiffies(500)); - rdata = cmnd->device->hostdata; - if (!rdata) - break; - pnode = rdata->pnode; + status = lpfc_reset_flush_io_context(vport, tgt_id, lun_id, + LPFC_CTX_LUN); + return status; +} + +/** + * lpfc_target_reset_handler - scsi_host_template eh_target_reset entry point + * @cmnd: Pointer to scsi_cmnd data structure. + * + * This routine does a target reset by sending a TARGET_RESET task management + * command. + * + * Return code : + * 0x2003 - Error + * 0x2002 - Success + **/ +static int +lpfc_target_reset_handler(struct scsi_cmnd *cmnd) +{ + struct Scsi_Host *shost = cmnd->device->host; + struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; + struct lpfc_rport_data *rdata = cmnd->device->hostdata; + struct lpfc_nodelist *pnode = rdata->pnode; + unsigned tgt_id = cmnd->device->id; + unsigned int lun_id = cmnd->device->lun; + struct lpfc_scsi_event_header scsi_event; + int status; + + lpfc_block_error_handler(cmnd); + + status = lpfc_chk_tgt_mapped(vport, cmnd); + if (status == FAILED) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, + "0722 Target Reset rport failure: rdata x%p\n", rdata); + return FAILED; } scsi_event.event_type = FC_REG_SCSI_EVENT; @@ -2630,106 +3342,47 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd) memcpy(scsi_event.wwpn, &pnode->nlp_portname, sizeof(struct lpfc_name)); memcpy(scsi_event.wwnn, &pnode->nlp_nodename, sizeof(struct lpfc_name)); - fc_host_post_vendor_event(shost, - fc_get_event_number(), - sizeof(scsi_event), - (char *)&scsi_event, - LPFC_NL_VENDOR_ID); + fc_host_post_vendor_event(shost, fc_get_event_number(), + sizeof(scsi_event), (char *)&scsi_event, LPFC_NL_VENDOR_ID); - if (!rdata || pnode->nlp_state != NLP_STE_MAPPED_NODE) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, - "0721 LUN Reset rport " - "failure: msec x%x rdata x%p\n", - jiffies_to_msecs(jiffies - later), rdata); - return FAILED; - } - lpfc_cmd = lpfc_get_scsi_buf(phba); - if (lpfc_cmd == NULL) - return FAILED; - lpfc_cmd->timeout = 60; - lpfc_cmd->rdata = rdata; + status = lpfc_send_taskmgmt(vport, rdata, tgt_id, lun_id, + FCP_TARGET_RESET); - status = lpfc_scsi_prep_task_mgmt_cmd(vport, lpfc_cmd, - cmnd->device->lun, - FCP_TARGET_RESET); - if (!status) { - lpfc_release_scsi_buf(phba, lpfc_cmd); - return FAILED; - } - iocbq = &lpfc_cmd->cur_iocbq; - - /* get a buffer for this IOCB command response */ - iocbqrsp = lpfc_sli_get_iocbq(phba); - if (iocbqrsp == NULL) { - lpfc_release_scsi_buf(phba, lpfc_cmd); - return FAILED; - } - lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP, - "0703 Issue target reset to TGT %d LUN %d " - "rpi x%x nlp_flag x%x\n", cmnd->device->id, - cmnd->device->lun, pnode->nlp_rpi, pnode->nlp_flag); - status = lpfc_sli_issue_iocb_wait(phba, - &phba->sli.ring[phba->sli.fcp_ring], - iocbq, iocbqrsp, lpfc_cmd->timeout); - if (status == IOCB_TIMEDOUT) { - iocbq->iocb_cmpl = lpfc_tskmgmt_def_cmpl; - ret = TIMEOUT_ERROR; - } else { - if (status != IOCB_SUCCESS) - ret = FAILED; - lpfc_release_scsi_buf(phba, lpfc_cmd); - } lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, - "0713 SCSI layer issued device reset (%d, %d) " - "return x%x status x%x result x%x\n", - cmnd->device->id, cmnd->device->lun, ret, - iocbqrsp->iocb.ulpStatus, - iocbqrsp->iocb.un.ulpWord[4]); - lpfc_sli_release_iocbq(phba, iocbqrsp); - cnt = lpfc_sli_sum_iocb(vport, cmnd->device->id, cmnd->device->lun, - LPFC_CTX_TGT); - if (cnt) - lpfc_sli_abort_iocb(vport, &phba->sli.ring[phba->sli.fcp_ring], - cmnd->device->id, cmnd->device->lun, - LPFC_CTX_TGT); - later = msecs_to_jiffies(2 * vport->cfg_devloss_tmo * 1000) + jiffies; - while (time_after(later, jiffies) && cnt) { - schedule_timeout_uninterruptible(msecs_to_jiffies(20)); - cnt = lpfc_sli_sum_iocb(vport, cmnd->device->id, - cmnd->device->lun, LPFC_CTX_TGT); - } - if (cnt) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, - "0719 device reset I/O flush failure: " - "cnt x%x\n", cnt); - ret = FAILED; - } - return ret; + "0723 SCSI layer issued Target Reset (%d, %d) " + "return x%x\n", tgt_id, lun_id, status); + + /* + * We have to clean up i/o as : they may be orphaned by the TMF; + * or if the TMF failed, they may be in an indeterminate state. + * So, continue on. + * We will report success if all the i/o aborts successfully. + */ + status = lpfc_reset_flush_io_context(vport, tgt_id, lun_id, + LPFC_CTX_TGT); + return status; } /** * lpfc_bus_reset_handler - scsi_host_template eh_bus_reset_handler entry point * @cmnd: Pointer to scsi_cmnd data structure. * - * This routine does target reset to all target on @cmnd->device->host. + * This routine does target reset to all targets on @cmnd->device->host. + * This emulates Parallel SCSI Bus Reset Semantics. * - * Return Code: - * 0x2003 - Error - * 0x2002 - Success + * Return code : + * 0x2003 - Error + * 0x2002 - Success **/ static int lpfc_bus_reset_handler(struct scsi_cmnd *cmnd) { struct Scsi_Host *shost = cmnd->device->host; struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; struct lpfc_nodelist *ndlp = NULL; - int match; - int ret = SUCCESS, status = SUCCESS, i; - int cnt; - struct lpfc_scsi_buf * lpfc_cmd; - unsigned long later; struct lpfc_scsi_event_header scsi_event; + int match; + int ret = SUCCESS, status, i; scsi_event.event_type = FC_REG_SCSI_EVENT; scsi_event.subcategory = LPFC_EVENT_BUSRESET; @@ -2737,13 +3390,11 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd) memcpy(scsi_event.wwpn, &vport->fc_portname, sizeof(struct lpfc_name)); memcpy(scsi_event.wwnn, &vport->fc_nodename, sizeof(struct lpfc_name)); - fc_host_post_vendor_event(shost, - fc_get_event_number(), - sizeof(scsi_event), - (char *)&scsi_event, - LPFC_NL_VENDOR_ID); + fc_host_post_vendor_event(shost, fc_get_event_number(), + sizeof(scsi_event), (char *)&scsi_event, LPFC_NL_VENDOR_ID); lpfc_block_error_handler(cmnd); + /* * Since the driver manages a single bus device, reset all * targets known to the driver. Should any target reset @@ -2766,16 +3417,11 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd) spin_unlock_irq(shost->host_lock); if (!match) continue; - lpfc_cmd = lpfc_get_scsi_buf(phba); - if (lpfc_cmd) { - lpfc_cmd->timeout = 60; - status = lpfc_scsi_tgt_reset(lpfc_cmd, vport, i, - cmnd->device->lun, - ndlp->rport->dd_data); - if (status != TIMEOUT_ERROR) - lpfc_release_scsi_buf(phba, lpfc_cmd); - } - if (!lpfc_cmd || status != SUCCESS) { + + status = lpfc_send_taskmgmt(vport, ndlp->rport->dd_data, + i, 0, FCP_TARGET_RESET); + + if (status != SUCCESS) { lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, "0700 Bus Reset on target %d failed\n", i); @@ -2783,25 +3429,16 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd) } } /* - * All outstanding txcmplq I/Os should have been aborted by - * the targets. Unfortunately, some targets do not abide by - * this forcing the driver to double check. + * We have to clean up i/o as : they may be orphaned by the TMFs + * above; or if any of the TMFs failed, they may be in an + * indeterminate state. + * We will report success if all the i/o aborts successfully. */ - cnt = lpfc_sli_sum_iocb(vport, 0, 0, LPFC_CTX_HOST); - if (cnt) - lpfc_sli_abort_iocb(vport, &phba->sli.ring[phba->sli.fcp_ring], - 0, 0, LPFC_CTX_HOST); - later = msecs_to_jiffies(2 * vport->cfg_devloss_tmo * 1000) + jiffies; - while (time_after(later, jiffies) && cnt) { - schedule_timeout_uninterruptible(msecs_to_jiffies(20)); - cnt = lpfc_sli_sum_iocb(vport, 0, 0, LPFC_CTX_HOST); - } - if (cnt) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, - "0715 Bus Reset I/O flush failure: " - "cnt x%x left x%x\n", cnt, i); + + status = lpfc_reset_flush_io_context(vport, 0, 0, LPFC_CTX_HOST); + if (status != SUCCESS) ret = FAILED; - } + lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, "0714 SCSI layer issued Bus Reset Data: x%x\n", ret); return ret; @@ -2825,11 +3462,10 @@ lpfc_slave_alloc(struct scsi_device *sdev) { struct lpfc_vport *vport = (struct lpfc_vport *) sdev->host->hostdata; struct lpfc_hba *phba = vport->phba; - struct lpfc_scsi_buf *scsi_buf = NULL; struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); - uint32_t total = 0, i; + uint32_t total = 0; uint32_t num_to_alloc = 0; - unsigned long flags; + int num_allocated = 0; if (!rport || fc_remote_port_chkready(rport)) return -ENXIO; @@ -2863,20 +3499,13 @@ lpfc_slave_alloc(struct scsi_device *sdev) (phba->cfg_hba_queue_depth - total)); num_to_alloc = phba->cfg_hba_queue_depth - total; } - - for (i = 0; i < num_to_alloc; i++) { - scsi_buf = lpfc_new_scsi_buf(vport); - if (!scsi_buf) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, - "0706 Failed to allocate " - "command buffer\n"); - break; - } - - spin_lock_irqsave(&phba->scsi_buf_list_lock, flags); - phba->total_scsi_bufs++; - list_add_tail(&scsi_buf->list, &phba->lpfc_scsi_buf_list); - spin_unlock_irqrestore(&phba->scsi_buf_list_lock, flags); + num_allocated = lpfc_new_scsi_buf(vport, num_to_alloc); + if (num_to_alloc != num_allocated) { + lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, + "0708 Allocation request of %d " + "command buffers did not succeed. " + "Allocated %d buffers.\n", + num_to_alloc, num_allocated); } return 0; } @@ -2942,7 +3571,8 @@ struct scsi_host_template lpfc_template = { .info = lpfc_info, .queuecommand = lpfc_queuecommand, .eh_abort_handler = lpfc_abort_handler, - .eh_device_reset_handler= lpfc_device_reset_handler, + .eh_device_reset_handler = lpfc_device_reset_handler, + .eh_target_reset_handler = lpfc_target_reset_handler, .eh_bus_reset_handler = lpfc_bus_reset_handler, .slave_alloc = lpfc_slave_alloc, .slave_configure = lpfc_slave_configure, @@ -2962,7 +3592,8 @@ struct scsi_host_template lpfc_vport_template = { .info = lpfc_info, .queuecommand = lpfc_queuecommand, .eh_abort_handler = lpfc_abort_handler, - .eh_device_reset_handler= lpfc_device_reset_handler, + .eh_device_reset_handler = lpfc_device_reset_handler, + .eh_target_reset_handler = lpfc_target_reset_handler, .eh_bus_reset_handler = lpfc_bus_reset_handler, .slave_alloc = lpfc_slave_alloc, .slave_configure = lpfc_slave_configure, diff --git a/drivers/scsi/lpfc/lpfc_scsi.h b/drivers/scsi/lpfc/lpfc_scsi.h index c7c440d5fa29..65dfc8bd5b49 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.h +++ b/drivers/scsi/lpfc/lpfc_scsi.h @@ -140,6 +140,8 @@ struct lpfc_scsi_buf { struct fcp_rsp *fcp_rsp; struct ulp_bde64 *fcp_bpl; + dma_addr_t dma_phys_bpl; + /* cur_iocbq has phys of the dma-able buffer. * Iotag is in here */ diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index eb5c75c45ba4..acc43b061ba1 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2008 Emulex. All rights reserved. * + * Copyright (C) 2004-2009 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -29,9 +29,12 @@ #include #include #include +#include +#include "lpfc_hw4.h" #include "lpfc_hw.h" #include "lpfc_sli.h" +#include "lpfc_sli4.h" #include "lpfc_nl.h" #include "lpfc_disc.h" #include "lpfc_scsi.h" @@ -40,24 +43,7 @@ #include "lpfc_logmsg.h" #include "lpfc_compat.h" #include "lpfc_debugfs.h" - -/* - * Define macro to log: Mailbox command x%x cannot issue Data - * This allows multiple uses of lpfc_msgBlk0311 - * w/o perturbing log msg utility. - */ -#define LOG_MBOX_CANNOT_ISSUE_DATA(phba, pmbox, psli, flag) \ - lpfc_printf_log(phba, \ - KERN_INFO, \ - LOG_MBOX | LOG_SLI, \ - "(%d):0311 Mailbox command x%x cannot " \ - "issue Data: x%x x%x x%x\n", \ - pmbox->vport ? pmbox->vport->vpi : 0, \ - pmbox->mb.mbxCommand, \ - phba->pport->port_state, \ - psli->sli_flag, \ - flag) - +#include "lpfc_vport.h" /* There are only four IOCB completion types. */ typedef enum _lpfc_iocb_type { @@ -67,6 +53,350 @@ typedef enum _lpfc_iocb_type { LPFC_ABORT_IOCB } lpfc_iocb_type; + +/* Provide function prototypes local to this module. */ +static int lpfc_sli_issue_mbox_s4(struct lpfc_hba *, LPFC_MBOXQ_t *, + uint32_t); +static int lpfc_sli4_read_rev(struct lpfc_hba *, LPFC_MBOXQ_t *, + uint8_t *, uint32_t *); + +static IOCB_t * +lpfc_get_iocb_from_iocbq(struct lpfc_iocbq *iocbq) +{ + return &iocbq->iocb; +} + +/** + * lpfc_sli4_wq_put - Put a Work Queue Entry on an Work Queue + * @q: The Work Queue to operate on. + * @wqe: The work Queue Entry to put on the Work queue. + * + * This routine will copy the contents of @wqe to the next available entry on + * the @q. This function will then ring the Work Queue Doorbell to signal the + * HBA to start processing the Work Queue Entry. This function returns 0 if + * successful. If no entries are available on @q then this function will return + * -ENOMEM. + * The caller is expected to hold the hbalock when calling this routine. + **/ +static uint32_t +lpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe *wqe) +{ + union lpfc_wqe *temp_wqe = q->qe[q->host_index].wqe; + struct lpfc_register doorbell; + uint32_t host_index; + + /* If the host has not yet processed the next entry then we are done */ + if (((q->host_index + 1) % q->entry_count) == q->hba_index) + return -ENOMEM; + /* set consumption flag every once in a while */ + if (!((q->host_index + 1) % LPFC_RELEASE_NOTIFICATION_INTERVAL)) + bf_set(lpfc_wqe_gen_wqec, &wqe->generic, 1); + + lpfc_sli_pcimem_bcopy(wqe, temp_wqe, q->entry_size); + + /* Update the host index before invoking device */ + host_index = q->host_index; + q->host_index = ((q->host_index + 1) % q->entry_count); + + /* Ring Doorbell */ + doorbell.word0 = 0; + bf_set(lpfc_wq_doorbell_num_posted, &doorbell, 1); + bf_set(lpfc_wq_doorbell_index, &doorbell, host_index); + bf_set(lpfc_wq_doorbell_id, &doorbell, q->queue_id); + writel(doorbell.word0, q->phba->sli4_hba.WQDBregaddr); + readl(q->phba->sli4_hba.WQDBregaddr); /* Flush */ + + return 0; +} + +/** + * lpfc_sli4_wq_release - Updates internal hba index for WQ + * @q: The Work Queue to operate on. + * @index: The index to advance the hba index to. + * + * This routine will update the HBA index of a queue to reflect consumption of + * Work Queue Entries by the HBA. When the HBA indicates that it has consumed + * an entry the host calls this function to update the queue's internal + * pointers. This routine returns the number of entries that were consumed by + * the HBA. + **/ +static uint32_t +lpfc_sli4_wq_release(struct lpfc_queue *q, uint32_t index) +{ + uint32_t released = 0; + + if (q->hba_index == index) + return 0; + do { + q->hba_index = ((q->hba_index + 1) % q->entry_count); + released++; + } while (q->hba_index != index); + return released; +} + +/** + * lpfc_sli4_mq_put - Put a Mailbox Queue Entry on an Mailbox Queue + * @q: The Mailbox Queue to operate on. + * @wqe: The Mailbox Queue Entry to put on the Work queue. + * + * This routine will copy the contents of @mqe to the next available entry on + * the @q. This function will then ring the Work Queue Doorbell to signal the + * HBA to start processing the Work Queue Entry. This function returns 0 if + * successful. If no entries are available on @q then this function will return + * -ENOMEM. + * The caller is expected to hold the hbalock when calling this routine. + **/ +static uint32_t +lpfc_sli4_mq_put(struct lpfc_queue *q, struct lpfc_mqe *mqe) +{ + struct lpfc_mqe *temp_mqe = q->qe[q->host_index].mqe; + struct lpfc_register doorbell; + uint32_t host_index; + + /* If the host has not yet processed the next entry then we are done */ + if (((q->host_index + 1) % q->entry_count) == q->hba_index) + return -ENOMEM; + lpfc_sli_pcimem_bcopy(mqe, temp_mqe, q->entry_size); + /* Save off the mailbox pointer for completion */ + q->phba->mbox = (MAILBOX_t *)temp_mqe; + + /* Update the host index before invoking device */ + host_index = q->host_index; + q->host_index = ((q->host_index + 1) % q->entry_count); + + /* Ring Doorbell */ + doorbell.word0 = 0; + bf_set(lpfc_mq_doorbell_num_posted, &doorbell, 1); + bf_set(lpfc_mq_doorbell_id, &doorbell, q->queue_id); + writel(doorbell.word0, q->phba->sli4_hba.MQDBregaddr); + readl(q->phba->sli4_hba.MQDBregaddr); /* Flush */ + return 0; +} + +/** + * lpfc_sli4_mq_release - Updates internal hba index for MQ + * @q: The Mailbox Queue to operate on. + * + * This routine will update the HBA index of a queue to reflect consumption of + * a Mailbox Queue Entry by the HBA. When the HBA indicates that it has consumed + * an entry the host calls this function to update the queue's internal + * pointers. This routine returns the number of entries that were consumed by + * the HBA. + **/ +static uint32_t +lpfc_sli4_mq_release(struct lpfc_queue *q) +{ + /* Clear the mailbox pointer for completion */ + q->phba->mbox = NULL; + q->hba_index = ((q->hba_index + 1) % q->entry_count); + return 1; +} + +/** + * lpfc_sli4_eq_get - Gets the next valid EQE from a EQ + * @q: The Event Queue to get the first valid EQE from + * + * This routine will get the first valid Event Queue Entry from @q, update + * the queue's internal hba index, and return the EQE. If no valid EQEs are in + * the Queue (no more work to do), or the Queue is full of EQEs that have been + * processed, but not popped back to the HBA then this routine will return NULL. + **/ +static struct lpfc_eqe * +lpfc_sli4_eq_get(struct lpfc_queue *q) +{ + struct lpfc_eqe *eqe = q->qe[q->hba_index].eqe; + + /* If the next EQE is not valid then we are done */ + if (!bf_get(lpfc_eqe_valid, eqe)) + return NULL; + /* If the host has not yet processed the next entry then we are done */ + if (((q->hba_index + 1) % q->entry_count) == q->host_index) + return NULL; + + q->hba_index = ((q->hba_index + 1) % q->entry_count); + return eqe; +} + +/** + * lpfc_sli4_eq_release - Indicates the host has finished processing an EQ + * @q: The Event Queue that the host has completed processing for. + * @arm: Indicates whether the host wants to arms this CQ. + * + * This routine will mark all Event Queue Entries on @q, from the last + * known completed entry to the last entry that was processed, as completed + * by clearing the valid bit for each completion queue entry. Then it will + * notify the HBA, by ringing the doorbell, that the EQEs have been processed. + * The internal host index in the @q will be updated by this routine to indicate + * that the host has finished processing the entries. The @arm parameter + * indicates that the queue should be rearmed when ringing the doorbell. + * + * This function will return the number of EQEs that were popped. + **/ +uint32_t +lpfc_sli4_eq_release(struct lpfc_queue *q, bool arm) +{ + uint32_t released = 0; + struct lpfc_eqe *temp_eqe; + struct lpfc_register doorbell; + + /* while there are valid entries */ + while (q->hba_index != q->host_index) { + temp_eqe = q->qe[q->host_index].eqe; + bf_set(lpfc_eqe_valid, temp_eqe, 0); + released++; + q->host_index = ((q->host_index + 1) % q->entry_count); + } + if (unlikely(released == 0 && !arm)) + return 0; + + /* ring doorbell for number popped */ + doorbell.word0 = 0; + if (arm) { + bf_set(lpfc_eqcq_doorbell_arm, &doorbell, 1); + bf_set(lpfc_eqcq_doorbell_eqci, &doorbell, 1); + } + bf_set(lpfc_eqcq_doorbell_num_released, &doorbell, released); + bf_set(lpfc_eqcq_doorbell_qt, &doorbell, LPFC_QUEUE_TYPE_EVENT); + bf_set(lpfc_eqcq_doorbell_eqid, &doorbell, q->queue_id); + writel(doorbell.word0, q->phba->sli4_hba.EQCQDBregaddr); + return released; +} + +/** + * lpfc_sli4_cq_get - Gets the next valid CQE from a CQ + * @q: The Completion Queue to get the first valid CQE from + * + * This routine will get the first valid Completion Queue Entry from @q, update + * the queue's internal hba index, and return the CQE. If no valid CQEs are in + * the Queue (no more work to do), or the Queue is full of CQEs that have been + * processed, but not popped back to the HBA then this routine will return NULL. + **/ +static struct lpfc_cqe * +lpfc_sli4_cq_get(struct lpfc_queue *q) +{ + struct lpfc_cqe *cqe; + + /* If the next CQE is not valid then we are done */ + if (!bf_get(lpfc_cqe_valid, q->qe[q->hba_index].cqe)) + return NULL; + /* If the host has not yet processed the next entry then we are done */ + if (((q->hba_index + 1) % q->entry_count) == q->host_index) + return NULL; + + cqe = q->qe[q->hba_index].cqe; + q->hba_index = ((q->hba_index + 1) % q->entry_count); + return cqe; +} + +/** + * lpfc_sli4_cq_release - Indicates the host has finished processing a CQ + * @q: The Completion Queue that the host has completed processing for. + * @arm: Indicates whether the host wants to arms this CQ. + * + * This routine will mark all Completion queue entries on @q, from the last + * known completed entry to the last entry that was processed, as completed + * by clearing the valid bit for each completion queue entry. Then it will + * notify the HBA, by ringing the doorbell, that the CQEs have been processed. + * The internal host index in the @q will be updated by this routine to indicate + * that the host has finished processing the entries. The @arm parameter + * indicates that the queue should be rearmed when ringing the doorbell. + * + * This function will return the number of CQEs that were released. + **/ +uint32_t +lpfc_sli4_cq_release(struct lpfc_queue *q, bool arm) +{ + uint32_t released = 0; + struct lpfc_cqe *temp_qe; + struct lpfc_register doorbell; + + /* while there are valid entries */ + while (q->hba_index != q->host_index) { + temp_qe = q->qe[q->host_index].cqe; + bf_set(lpfc_cqe_valid, temp_qe, 0); + released++; + q->host_index = ((q->host_index + 1) % q->entry_count); + } + if (unlikely(released == 0 && !arm)) + return 0; + + /* ring doorbell for number popped */ + doorbell.word0 = 0; + if (arm) + bf_set(lpfc_eqcq_doorbell_arm, &doorbell, 1); + bf_set(lpfc_eqcq_doorbell_num_released, &doorbell, released); + bf_set(lpfc_eqcq_doorbell_qt, &doorbell, LPFC_QUEUE_TYPE_COMPLETION); + bf_set(lpfc_eqcq_doorbell_cqid, &doorbell, q->queue_id); + writel(doorbell.word0, q->phba->sli4_hba.EQCQDBregaddr); + return released; +} + +/** + * lpfc_sli4_rq_put - Put a Receive Buffer Queue Entry on a Receive Queue + * @q: The Header Receive Queue to operate on. + * @wqe: The Receive Queue Entry to put on the Receive queue. + * + * This routine will copy the contents of @wqe to the next available entry on + * the @q. This function will then ring the Receive Queue Doorbell to signal the + * HBA to start processing the Receive Queue Entry. This function returns the + * index that the rqe was copied to if successful. If no entries are available + * on @q then this function will return -ENOMEM. + * The caller is expected to hold the hbalock when calling this routine. + **/ +static int +lpfc_sli4_rq_put(struct lpfc_queue *hq, struct lpfc_queue *dq, + struct lpfc_rqe *hrqe, struct lpfc_rqe *drqe) +{ + struct lpfc_rqe *temp_hrqe = hq->qe[hq->host_index].rqe; + struct lpfc_rqe *temp_drqe = dq->qe[dq->host_index].rqe; + struct lpfc_register doorbell; + int put_index = hq->host_index; + + if (hq->type != LPFC_HRQ || dq->type != LPFC_DRQ) + return -EINVAL; + if (hq->host_index != dq->host_index) + return -EINVAL; + /* If the host has not yet processed the next entry then we are done */ + if (((hq->host_index + 1) % hq->entry_count) == hq->hba_index) + return -EBUSY; + lpfc_sli_pcimem_bcopy(hrqe, temp_hrqe, hq->entry_size); + lpfc_sli_pcimem_bcopy(drqe, temp_drqe, dq->entry_size); + + /* Update the host index to point to the next slot */ + hq->host_index = ((hq->host_index + 1) % hq->entry_count); + dq->host_index = ((dq->host_index + 1) % dq->entry_count); + + /* Ring The Header Receive Queue Doorbell */ + if (!(hq->host_index % LPFC_RQ_POST_BATCH)) { + doorbell.word0 = 0; + bf_set(lpfc_rq_doorbell_num_posted, &doorbell, + LPFC_RQ_POST_BATCH); + bf_set(lpfc_rq_doorbell_id, &doorbell, hq->queue_id); + writel(doorbell.word0, hq->phba->sli4_hba.RQDBregaddr); + } + return put_index; +} + +/** + * lpfc_sli4_rq_release - Updates internal hba index for RQ + * @q: The Header Receive Queue to operate on. + * + * This routine will update the HBA index of a queue to reflect consumption of + * one Receive Queue Entry by the HBA. When the HBA indicates that it has + * consumed an entry the host calls this function to update the queue's + * internal pointers. This routine returns the number of entries that were + * consumed by the HBA. + **/ +static uint32_t +lpfc_sli4_rq_release(struct lpfc_queue *hq, struct lpfc_queue *dq) +{ + if ((hq->type != LPFC_HRQ) || (dq->type != LPFC_DRQ)) + return 0; + hq->hba_index = ((hq->hba_index + 1) % hq->entry_count); + dq->hba_index = ((dq->hba_index + 1) % dq->entry_count); + return 1; +} + /** * lpfc_cmd_iocb - Get next command iocb entry in the ring * @phba: Pointer to HBA context object. @@ -120,6 +450,76 @@ __lpfc_sli_get_iocbq(struct lpfc_hba *phba) return iocbq; } +/** + * __lpfc_clear_active_sglq - Remove the active sglq for this XRI. + * @phba: Pointer to HBA context object. + * @xritag: XRI value. + * + * This function clears the sglq pointer from the array of acive + * sglq's. The xritag that is passed in is used to index into the + * array. Before the xritag can be used it needs to be adjusted + * by subtracting the xribase. + * + * Returns sglq ponter = success, NULL = Failure. + **/ +static struct lpfc_sglq * +__lpfc_clear_active_sglq(struct lpfc_hba *phba, uint16_t xritag) +{ + uint16_t adj_xri; + struct lpfc_sglq *sglq; + adj_xri = xritag - phba->sli4_hba.max_cfg_param.xri_base; + if (adj_xri > phba->sli4_hba.max_cfg_param.max_xri) + return NULL; + sglq = phba->sli4_hba.lpfc_sglq_active_list[adj_xri]; + phba->sli4_hba.lpfc_sglq_active_list[adj_xri] = NULL; + return sglq; +} + +/** + * __lpfc_get_active_sglq - Get the active sglq for this XRI. + * @phba: Pointer to HBA context object. + * @xritag: XRI value. + * + * This function returns the sglq pointer from the array of acive + * sglq's. The xritag that is passed in is used to index into the + * array. Before the xritag can be used it needs to be adjusted + * by subtracting the xribase. + * + * Returns sglq ponter = success, NULL = Failure. + **/ +static struct lpfc_sglq * +__lpfc_get_active_sglq(struct lpfc_hba *phba, uint16_t xritag) +{ + uint16_t adj_xri; + struct lpfc_sglq *sglq; + adj_xri = xritag - phba->sli4_hba.max_cfg_param.xri_base; + if (adj_xri > phba->sli4_hba.max_cfg_param.max_xri) + return NULL; + sglq = phba->sli4_hba.lpfc_sglq_active_list[adj_xri]; + return sglq; +} + +/** + * __lpfc_sli_get_sglq - Allocates an iocb object from sgl pool + * @phba: Pointer to HBA context object. + * + * This function is called with hbalock held. This function + * Gets a new driver sglq object from the sglq list. If the + * list is not empty then it is successful, it returns pointer to the newly + * allocated sglq object else it returns NULL. + **/ +static struct lpfc_sglq * +__lpfc_sli_get_sglq(struct lpfc_hba *phba) +{ + struct list_head *lpfc_sgl_list = &phba->sli4_hba.lpfc_sgl_list; + struct lpfc_sglq *sglq = NULL; + uint16_t adj_xri; + list_remove_head(lpfc_sgl_list, sglq, struct lpfc_sglq, list); + adj_xri = sglq->sli4_xritag - phba->sli4_hba.max_cfg_param.xri_base; + phba->sli4_hba.lpfc_sglq_active_list[adj_xri] = sglq; + return sglq; +} + /** * lpfc_sli_get_iocbq - Allocates an iocb object from iocb pool * @phba: Pointer to HBA context object. @@ -141,6 +541,82 @@ lpfc_sli_get_iocbq(struct lpfc_hba *phba) return iocbq; } +/** + * __lpfc_sli_release_iocbq_s4 - Release iocb to the iocb pool + * @phba: Pointer to HBA context object. + * @iocbq: Pointer to driver iocb object. + * + * This function is called with hbalock held to release driver + * iocb object to the iocb pool. The iotag in the iocb object + * does not change for each use of the iocb object. This function + * clears all other fields of the iocb object when it is freed. + * The sqlq structure that holds the xritag and phys and virtual + * mappings for the scatter gather list is retrieved from the + * active array of sglq. The get of the sglq pointer also clears + * the entry in the array. If the status of the IO indiactes that + * this IO was aborted then the sglq entry it put on the + * lpfc_abts_els_sgl_list until the CQ_ABORTED_XRI is received. If the + * IO has good status or fails for any other reason then the sglq + * entry is added to the free list (lpfc_sgl_list). + **/ +static void +__lpfc_sli_release_iocbq_s4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) +{ + struct lpfc_sglq *sglq; + size_t start_clean = offsetof(struct lpfc_iocbq, iocb); + unsigned long iflag; + + if (iocbq->sli4_xritag == NO_XRI) + sglq = NULL; + else + sglq = __lpfc_clear_active_sglq(phba, iocbq->sli4_xritag); + if (sglq) { + if (iocbq->iocb_flag & LPFC_DRIVER_ABORTED + || ((iocbq->iocb.ulpStatus == IOSTAT_LOCAL_REJECT) + && (iocbq->iocb.un.ulpWord[4] + == IOERR_SLI_ABORTED))) { + spin_lock_irqsave(&phba->sli4_hba.abts_sgl_list_lock, + iflag); + list_add(&sglq->list, + &phba->sli4_hba.lpfc_abts_els_sgl_list); + spin_unlock_irqrestore( + &phba->sli4_hba.abts_sgl_list_lock, iflag); + } else + list_add(&sglq->list, &phba->sli4_hba.lpfc_sgl_list); + } + + + /* + * Clean all volatile data fields, preserve iotag and node struct. + */ + memset((char *)iocbq + start_clean, 0, sizeof(*iocbq) - start_clean); + iocbq->sli4_xritag = NO_XRI; + list_add_tail(&iocbq->list, &phba->lpfc_iocb_list); +} + +/** + * __lpfc_sli_release_iocbq_s3 - Release iocb to the iocb pool + * @phba: Pointer to HBA context object. + * @iocbq: Pointer to driver iocb object. + * + * This function is called with hbalock held to release driver + * iocb object to the iocb pool. The iotag in the iocb object + * does not change for each use of the iocb object. This function + * clears all other fields of the iocb object when it is freed. + **/ +static void +__lpfc_sli_release_iocbq_s3(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) +{ + size_t start_clean = offsetof(struct lpfc_iocbq, iocb); + + /* + * Clean all volatile data fields, preserve iotag and node struct. + */ + memset((char*)iocbq + start_clean, 0, sizeof(*iocbq) - start_clean); + iocbq->sli4_xritag = NO_XRI; + list_add_tail(&iocbq->list, &phba->lpfc_iocb_list); +} + /** * __lpfc_sli_release_iocbq - Release iocb to the iocb pool * @phba: Pointer to HBA context object. @@ -154,13 +630,7 @@ lpfc_sli_get_iocbq(struct lpfc_hba *phba) static void __lpfc_sli_release_iocbq(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) { - size_t start_clean = offsetof(struct lpfc_iocbq, iocb); - - /* - * Clean all volatile data fields, preserve iotag and node struct. - */ - memset((char*)iocbq + start_clean, 0, sizeof(*iocbq) - start_clean); - list_add_tail(&iocbq->list, &phba->lpfc_iocb_list); + phba->__lpfc_sli_release_iocbq(phba, iocbq); } /** @@ -281,6 +751,14 @@ lpfc_sli_iocb_cmd_type(uint8_t iocb_cmnd) case CMD_GEN_REQUEST64_CR: case CMD_GEN_REQUEST64_CX: case CMD_XMIT_ELS_RSP64_CX: + case DSSCMD_IWRITE64_CR: + case DSSCMD_IWRITE64_CX: + case DSSCMD_IREAD64_CR: + case DSSCMD_IREAD64_CX: + case DSSCMD_INVALIDATE_DEK: + case DSSCMD_SET_KEK: + case DSSCMD_GET_KEK_ID: + case DSSCMD_GEN_XFER: type = LPFC_SOL_IOCB; break; case CMD_ABORT_XRI_CN: @@ -348,7 +826,7 @@ lpfc_sli_ring_map(struct lpfc_hba *phba) pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!pmb) return -ENOMEM; - pmbox = &pmb->mb; + pmbox = &pmb->u.mb; phba->link_state = LPFC_INIT_MBX_CMDS; for (i = 0; i < psli->num_rings; i++) { lpfc_config_ring(phba, i, pmb); @@ -779,8 +1257,8 @@ lpfc_sli_hbqbuf_free_all(struct lpfc_hba *phba) phba->hbqs[i].buffer_count = 0; } /* Return all HBQ buffer that are in-fly */ - list_for_each_entry_safe(dmabuf, next_dmabuf, - &phba->hbqbuf_in_list, list) { + list_for_each_entry_safe(dmabuf, next_dmabuf, &phba->rb_pend_list, + list) { hbq_buf = container_of(dmabuf, struct hbq_dmabuf, dbuf); list_del(&hbq_buf->dbuf.list); if (hbq_buf->tag == -1) { @@ -814,9 +1292,27 @@ lpfc_sli_hbqbuf_free_all(struct lpfc_hba *phba) * pointer to the hbq entry if it successfully post the buffer * else it will return NULL. **/ -static struct lpfc_hbq_entry * +static int lpfc_sli_hbq_to_firmware(struct lpfc_hba *phba, uint32_t hbqno, struct hbq_dmabuf *hbq_buf) +{ + return phba->lpfc_sli_hbq_to_firmware(phba, hbqno, hbq_buf); +} + +/** + * lpfc_sli_hbq_to_firmware_s3 - Post the hbq buffer to SLI3 firmware + * @phba: Pointer to HBA context object. + * @hbqno: HBQ number. + * @hbq_buf: Pointer to HBQ buffer. + * + * This function is called with the hbalock held to post a hbq buffer to the + * firmware. If the function finds an empty slot in the HBQ, it will post the + * buffer and place it on the hbq_buffer_list. The function will return zero if + * it successfully post the buffer else it will return an error. + **/ +static int +lpfc_sli_hbq_to_firmware_s3(struct lpfc_hba *phba, uint32_t hbqno, + struct hbq_dmabuf *hbq_buf) { struct lpfc_hbq_entry *hbqe; dma_addr_t physaddr = hbq_buf->dbuf.phys; @@ -838,8 +1334,40 @@ lpfc_sli_hbq_to_firmware(struct lpfc_hba *phba, uint32_t hbqno, /* flush */ readl(phba->hbq_put + hbqno); list_add_tail(&hbq_buf->dbuf.list, &hbqp->hbq_buffer_list); - } - return hbqe; + return 0; + } else + return -ENOMEM; +} + +/** + * lpfc_sli_hbq_to_firmware_s4 - Post the hbq buffer to SLI4 firmware + * @phba: Pointer to HBA context object. + * @hbqno: HBQ number. + * @hbq_buf: Pointer to HBQ buffer. + * + * This function is called with the hbalock held to post an RQE to the SLI4 + * firmware. If able to post the RQE to the RQ it will queue the hbq entry to + * the hbq_buffer_list and return zero, otherwise it will return an error. + **/ +static int +lpfc_sli_hbq_to_firmware_s4(struct lpfc_hba *phba, uint32_t hbqno, + struct hbq_dmabuf *hbq_buf) +{ + int rc; + struct lpfc_rqe hrqe; + struct lpfc_rqe drqe; + + hrqe.address_lo = putPaddrLow(hbq_buf->hbuf.phys); + hrqe.address_hi = putPaddrHigh(hbq_buf->hbuf.phys); + drqe.address_lo = putPaddrLow(hbq_buf->dbuf.phys); + drqe.address_hi = putPaddrHigh(hbq_buf->dbuf.phys); + rc = lpfc_sli4_rq_put(phba->sli4_hba.hdr_rq, phba->sli4_hba.dat_rq, + &hrqe, &drqe); + if (rc < 0) + return rc; + hbq_buf->tag = rc; + list_add_tail(&hbq_buf->dbuf.list, &phba->hbqs[hbqno].hbq_buffer_list); + return 0; } /* HBQ for ELS and CT traffic. */ @@ -914,7 +1442,7 @@ lpfc_sli_hbqbuf_fill_hbqs(struct lpfc_hba *phba, uint32_t hbqno, uint32_t count) dbuf.list); hbq_buffer->tag = (phba->hbqs[hbqno].buffer_count | (hbqno << 16)); - if (lpfc_sli_hbq_to_firmware(phba, hbqno, hbq_buffer)) { + if (!lpfc_sli_hbq_to_firmware(phba, hbqno, hbq_buffer)) { phba->hbqs[hbqno].buffer_count++; posted++; } else @@ -964,6 +1492,25 @@ lpfc_sli_hbqbuf_init_hbqs(struct lpfc_hba *phba, uint32_t qno) lpfc_hbq_defs[qno]->init_count)); } +/** + * lpfc_sli_hbqbuf_get - Remove the first hbq off of an hbq list + * @phba: Pointer to HBA context object. + * @hbqno: HBQ number. + * + * This function removes the first hbq buffer on an hbq list and returns a + * pointer to that buffer. If it finds no buffers on the list it returns NULL. + **/ +static struct hbq_dmabuf * +lpfc_sli_hbqbuf_get(struct list_head *rb_list) +{ + struct lpfc_dmabuf *d_buf; + + list_remove_head(rb_list, d_buf, struct lpfc_dmabuf, list); + if (!d_buf) + return NULL; + return container_of(d_buf, struct hbq_dmabuf, dbuf); +} + /** * lpfc_sli_hbqbuf_find - Find the hbq buffer associated with a tag * @phba: Pointer to HBA context object. @@ -985,12 +1532,15 @@ lpfc_sli_hbqbuf_find(struct lpfc_hba *phba, uint32_t tag) if (hbqno >= LPFC_MAX_HBQS) return NULL; + spin_lock_irq(&phba->hbalock); list_for_each_entry(d_buf, &phba->hbqs[hbqno].hbq_buffer_list, list) { hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf); if (hbq_buf->tag == tag) { + spin_unlock_irq(&phba->hbalock); return hbq_buf; } } + spin_unlock_irq(&phba->hbalock); lpfc_printf_log(phba, KERN_ERR, LOG_SLI | LOG_VPORT, "1803 Bad hbq tag. Data: x%x x%x\n", tag, phba->hbqs[tag >> 16].buffer_count); @@ -1013,9 +1563,8 @@ lpfc_sli_free_hbq(struct lpfc_hba *phba, struct hbq_dmabuf *hbq_buffer) if (hbq_buffer) { hbqno = hbq_buffer->tag >> 16; - if (!lpfc_sli_hbq_to_firmware(phba, hbqno, hbq_buffer)) { + if (lpfc_sli_hbq_to_firmware(phba, hbqno, hbq_buffer)) (phba->hbqs[hbqno].hbq_free_buffer)(phba, hbq_buffer); - } } } @@ -1086,6 +1635,15 @@ lpfc_sli_chk_mbx_command(uint8_t mbxCommand) case MBX_HEARTBEAT: case MBX_PORT_CAPABILITIES: case MBX_PORT_IOV_CONTROL: + case MBX_SLI4_CONFIG: + case MBX_SLI4_REQ_FTRS: + case MBX_REG_FCFI: + case MBX_UNREG_FCFI: + case MBX_REG_VFI: + case MBX_UNREG_VFI: + case MBX_INIT_VPI: + case MBX_INIT_VFI: + case MBX_RESUME_RPI: ret = mbxCommand; break; default: @@ -1106,7 +1664,7 @@ lpfc_sli_chk_mbx_command(uint8_t mbxCommand) * will wake up thread waiting on the wait queue pointed by context1 * of the mailbox. **/ -static void +void lpfc_sli_wake_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) { wait_queue_head_t *pdone_q; @@ -1140,7 +1698,7 @@ void lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { struct lpfc_dmabuf *mp; - uint16_t rpi; + uint16_t rpi, vpi; int rc; mp = (struct lpfc_dmabuf *) (pmb->context1); @@ -1150,24 +1708,30 @@ lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) kfree(mp); } + if ((pmb->u.mb.mbxCommand == MBX_UNREG_LOGIN) && + (phba->sli_rev == LPFC_SLI_REV4)) + lpfc_sli4_free_rpi(phba, pmb->u.mb.un.varUnregLogin.rpi); + /* * If a REG_LOGIN succeeded after node is destroyed or node * is in re-discovery driver need to cleanup the RPI. */ if (!(phba->pport->load_flag & FC_UNLOADING) && - pmb->mb.mbxCommand == MBX_REG_LOGIN64 && - !pmb->mb.mbxStatus) { - - rpi = pmb->mb.un.varWords[0]; - lpfc_unreg_login(phba, pmb->mb.un.varRegLogin.vpi, rpi, pmb); + pmb->u.mb.mbxCommand == MBX_REG_LOGIN64 && + !pmb->u.mb.mbxStatus) { + rpi = pmb->u.mb.un.varWords[0]; + vpi = pmb->u.mb.un.varRegLogin.vpi - phba->vpi_base; + lpfc_unreg_login(phba, vpi, rpi, pmb); pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); if (rc != MBX_NOT_FINISHED) return; } - mempool_free(pmb, phba->mbox_mem_pool); - return; + if (bf_get(lpfc_mqe_command, &pmb->u.mqe) == MBX_SLI4_CONFIG) + lpfc_sli4_mbox_cmd_free(phba, pmb); + else + mempool_free(pmb, phba->mbox_mem_pool); } /** @@ -1204,7 +1768,7 @@ lpfc_sli_handle_mb_event(struct lpfc_hba *phba) if (pmb == NULL) break; - pmbox = &pmb->mb; + pmbox = &pmb->u.mb; if (pmbox->mbxCommand != MBX_HEARTBEAT) { if (pmb->vport) { @@ -1233,9 +1797,10 @@ lpfc_sli_handle_mb_event(struct lpfc_hba *phba) /* Unknow mailbox command compl */ lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, "(%d):0323 Unknown Mailbox command " - "%x Cmpl\n", + "x%x (x%x) Cmpl\n", pmb->vport ? pmb->vport->vpi : 0, - pmbox->mbxCommand); + pmbox->mbxCommand, + lpfc_sli4_mbox_opcode_get(phba, pmb)); phba->link_state = LPFC_HBA_ERROR; phba->work_hs = HS_FFER3; lpfc_handle_eratt(phba); @@ -1250,29 +1815,29 @@ lpfc_sli_handle_mb_event(struct lpfc_hba *phba) LOG_MBOX | LOG_SLI, "(%d):0305 Mbox cmd cmpl " "error - RETRYing Data: x%x " - "x%x x%x x%x\n", + "(x%x) x%x x%x x%x\n", pmb->vport ? pmb->vport->vpi :0, pmbox->mbxCommand, + lpfc_sli4_mbox_opcode_get(phba, + pmb), pmbox->mbxStatus, pmbox->un.varWords[0], pmb->vport->port_state); pmbox->mbxStatus = 0; pmbox->mbxOwner = OWN_HOST; - spin_lock_irq(&phba->hbalock); - phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; - spin_unlock_irq(&phba->hbalock); rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); - if (rc == MBX_SUCCESS) + if (rc != MBX_NOT_FINISHED) continue; } } /* Mailbox cmd Cmpl */ lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI, - "(%d):0307 Mailbox cmd x%x Cmpl x%p " + "(%d):0307 Mailbox cmd x%x (x%x) Cmpl x%p " "Data: x%x x%x x%x x%x x%x x%x x%x x%x x%x\n", pmb->vport ? pmb->vport->vpi : 0, pmbox->mbxCommand, + lpfc_sli4_mbox_opcode_get(phba, pmb), pmb->mbox_cmpl, *((uint32_t *) pmbox), pmbox->un.varWords[0], @@ -1317,6 +1882,45 @@ lpfc_sli_get_buff(struct lpfc_hba *phba, return &hbq_entry->dbuf; } +/** + * lpfc_complete_unsol_iocb - Complete an unsolicited sequence + * @phba: Pointer to HBA context object. + * @pring: Pointer to driver SLI ring object. + * @saveq: Pointer to the iocbq struct representing the sequence starting frame. + * @fch_r_ctl: the r_ctl for the first frame of the sequence. + * @fch_type: the type for the first frame of the sequence. + * + * This function is called with no lock held. This function uses the r_ctl and + * type of the received sequence to find the correct callback function to call + * to process the sequence. + **/ +static int +lpfc_complete_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, + struct lpfc_iocbq *saveq, uint32_t fch_r_ctl, + uint32_t fch_type) +{ + int i; + + /* unSolicited Responses */ + if (pring->prt[0].profile) { + if (pring->prt[0].lpfc_sli_rcv_unsol_event) + (pring->prt[0].lpfc_sli_rcv_unsol_event) (phba, pring, + saveq); + return 1; + } + /* We must search, based on rctl / type + for the right routine */ + for (i = 0; i < pring->num_mask; i++) { + if ((pring->prt[i].rctl == fch_r_ctl) && + (pring->prt[i].type == fch_type)) { + if (pring->prt[i].lpfc_sli_rcv_unsol_event) + (pring->prt[i].lpfc_sli_rcv_unsol_event) + (phba, pring, saveq); + return 1; + } + } + return 0; +} /** * lpfc_sli_process_unsol_iocb - Unsolicited iocb handler @@ -1339,7 +1943,7 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, IOCB_t * irsp; WORD5 * w5p; uint32_t Rctl, Type; - uint32_t match, i; + uint32_t match; struct lpfc_iocbq *iocbq; struct lpfc_dmabuf *dmzbuf; @@ -1482,35 +2086,12 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, } } - /* unSolicited Responses */ - if (pring->prt[0].profile) { - if (pring->prt[0].lpfc_sli_rcv_unsol_event) - (pring->prt[0].lpfc_sli_rcv_unsol_event) (phba, pring, - saveq); - match = 1; - } else { - /* We must search, based on rctl / type - for the right routine */ - for (i = 0; i < pring->num_mask; i++) { - if ((pring->prt[i].rctl == Rctl) - && (pring->prt[i].type == Type)) { - if (pring->prt[i].lpfc_sli_rcv_unsol_event) - (pring->prt[i].lpfc_sli_rcv_unsol_event) - (phba, pring, saveq); - match = 1; - break; - } - } - } - if (match == 0) { - /* Unexpected Rctl / Type received */ - /* Ring handler: unexpected - Rctl Type received */ + if (!lpfc_complete_unsol_iocb(phba, pring, saveq, Rctl, Type)) lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, "0313 Ring %d handler: unexpected Rctl x%x " "Type x%x received\n", pring->ringno, Rctl, Type); - } + return 1; } @@ -1551,6 +2132,37 @@ lpfc_sli_iocbq_lookup(struct lpfc_hba *phba, return NULL; } +/** + * lpfc_sli_iocbq_lookup_by_tag - Find command iocb for the iotag + * @phba: Pointer to HBA context object. + * @pring: Pointer to driver SLI ring object. + * @iotag: IOCB tag. + * + * This function looks up the iocb_lookup table to get the command iocb + * corresponding to the given iotag. This function is called with the + * hbalock held. + * This function returns the command iocb object if it finds the command + * iocb else returns NULL. + **/ +static struct lpfc_iocbq * +lpfc_sli_iocbq_lookup_by_tag(struct lpfc_hba *phba, + struct lpfc_sli_ring *pring, uint16_t iotag) +{ + struct lpfc_iocbq *cmd_iocb; + + if (iotag != 0 && iotag <= phba->sli.last_iotag) { + cmd_iocb = phba->sli.iocbq_lookup[iotag]; + list_del_init(&cmd_iocb->list); + pring->txcmplq_cnt--; + return cmd_iocb; + } + + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "0372 iotag x%x is out off range: max iotag (x%x)\n", + iotag, phba->sli.last_iotag); + return NULL; +} + /** * lpfc_sli_process_sol_iocb - process solicited iocb completion * @phba: Pointer to HBA context object. @@ -1954,7 +2566,7 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba, if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) && (irsp->un.ulpWord[4] == IOERR_NO_RESOURCES)) { spin_unlock_irqrestore(&phba->hbalock, iflag); - lpfc_rampdown_queue_depth(phba); + phba->lpfc_rampdown_queue_depth(phba); spin_lock_irqsave(&phba->hbalock, iflag); } @@ -2068,39 +2680,215 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba, } /** - * lpfc_sli_handle_slow_ring_event - Handle ring events for non-FCP rings + * lpfc_sli_sp_handle_rspiocb - Handle slow-path response iocb + * @phba: Pointer to HBA context object. + * @pring: Pointer to driver SLI ring object. + * @rspiocbp: Pointer to driver response IOCB object. + * + * This function is called from the worker thread when there is a slow-path + * response IOCB to process. This function chains all the response iocbs until + * seeing the iocb with the LE bit set. The function will call + * lpfc_sli_process_sol_iocb function if the response iocb indicates a + * completion of a command iocb. The function will call the + * lpfc_sli_process_unsol_iocb function if this is an unsolicited iocb. + * The function frees the resources or calls the completion handler if this + * iocb is an abort completion. The function returns NULL when the response + * iocb has the LE bit set and all the chained iocbs are processed, otherwise + * this function shall chain the iocb on to the iocb_continueq and return the + * response iocb passed in. + **/ +static struct lpfc_iocbq * +lpfc_sli_sp_handle_rspiocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, + struct lpfc_iocbq *rspiocbp) +{ + struct lpfc_iocbq *saveq; + struct lpfc_iocbq *cmdiocbp; + struct lpfc_iocbq *next_iocb; + IOCB_t *irsp = NULL; + uint32_t free_saveq; + uint8_t iocb_cmd_type; + lpfc_iocb_type type; + unsigned long iflag; + int rc; + + spin_lock_irqsave(&phba->hbalock, iflag); + /* First add the response iocb to the countinueq list */ + list_add_tail(&rspiocbp->list, &(pring->iocb_continueq)); + pring->iocb_continueq_cnt++; + + /* Now, determine whetehr the list is completed for processing */ + irsp = &rspiocbp->iocb; + if (irsp->ulpLe) { + /* + * By default, the driver expects to free all resources + * associated with this iocb completion. + */ + free_saveq = 1; + saveq = list_get_first(&pring->iocb_continueq, + struct lpfc_iocbq, list); + irsp = &(saveq->iocb); + list_del_init(&pring->iocb_continueq); + pring->iocb_continueq_cnt = 0; + + pring->stats.iocb_rsp++; + + /* + * If resource errors reported from HBA, reduce + * queuedepths of the SCSI device. + */ + if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) && + (irsp->un.ulpWord[4] == IOERR_NO_RESOURCES)) { + spin_unlock_irqrestore(&phba->hbalock, iflag); + phba->lpfc_rampdown_queue_depth(phba); + spin_lock_irqsave(&phba->hbalock, iflag); + } + + if (irsp->ulpStatus) { + /* Rsp ring error: IOCB */ + lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, + "0328 Rsp Ring %d error: " + "IOCB Data: " + "x%x x%x x%x x%x " + "x%x x%x x%x x%x " + "x%x x%x x%x x%x " + "x%x x%x x%x x%x\n", + pring->ringno, + irsp->un.ulpWord[0], + irsp->un.ulpWord[1], + irsp->un.ulpWord[2], + irsp->un.ulpWord[3], + irsp->un.ulpWord[4], + irsp->un.ulpWord[5], + *(((uint32_t *) irsp) + 6), + *(((uint32_t *) irsp) + 7), + *(((uint32_t *) irsp) + 8), + *(((uint32_t *) irsp) + 9), + *(((uint32_t *) irsp) + 10), + *(((uint32_t *) irsp) + 11), + *(((uint32_t *) irsp) + 12), + *(((uint32_t *) irsp) + 13), + *(((uint32_t *) irsp) + 14), + *(((uint32_t *) irsp) + 15)); + } + + /* + * Fetch the IOCB command type and call the correct completion + * routine. Solicited and Unsolicited IOCBs on the ELS ring + * get freed back to the lpfc_iocb_list by the discovery + * kernel thread. + */ + iocb_cmd_type = irsp->ulpCommand & CMD_IOCB_MASK; + type = lpfc_sli_iocb_cmd_type(iocb_cmd_type); + switch (type) { + case LPFC_SOL_IOCB: + spin_unlock_irqrestore(&phba->hbalock, iflag); + rc = lpfc_sli_process_sol_iocb(phba, pring, saveq); + spin_lock_irqsave(&phba->hbalock, iflag); + break; + + case LPFC_UNSOL_IOCB: + spin_unlock_irqrestore(&phba->hbalock, iflag); + rc = lpfc_sli_process_unsol_iocb(phba, pring, saveq); + spin_lock_irqsave(&phba->hbalock, iflag); + if (!rc) + free_saveq = 0; + break; + + case LPFC_ABORT_IOCB: + cmdiocbp = NULL; + if (irsp->ulpCommand != CMD_XRI_ABORTED_CX) + cmdiocbp = lpfc_sli_iocbq_lookup(phba, pring, + saveq); + if (cmdiocbp) { + /* Call the specified completion routine */ + if (cmdiocbp->iocb_cmpl) { + spin_unlock_irqrestore(&phba->hbalock, + iflag); + (cmdiocbp->iocb_cmpl)(phba, cmdiocbp, + saveq); + spin_lock_irqsave(&phba->hbalock, + iflag); + } else + __lpfc_sli_release_iocbq(phba, + cmdiocbp); + } + break; + + case LPFC_UNKNOWN_IOCB: + if (irsp->ulpCommand == CMD_ADAPTER_MSG) { + char adaptermsg[LPFC_MAX_ADPTMSG]; + memset(adaptermsg, 0, LPFC_MAX_ADPTMSG); + memcpy(&adaptermsg[0], (uint8_t *)irsp, + MAX_MSG_DATA); + dev_warn(&((phba->pcidev)->dev), + "lpfc%d: %s\n", + phba->brd_no, adaptermsg); + } else { + /* Unknown IOCB command */ + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "0335 Unknown IOCB " + "command Data: x%x " + "x%x x%x x%x\n", + irsp->ulpCommand, + irsp->ulpStatus, + irsp->ulpIoTag, + irsp->ulpContext); + } + break; + } + + if (free_saveq) { + list_for_each_entry_safe(rspiocbp, next_iocb, + &saveq->list, list) { + list_del(&rspiocbp->list); + __lpfc_sli_release_iocbq(phba, rspiocbp); + } + __lpfc_sli_release_iocbq(phba, saveq); + } + rspiocbp = NULL; + } + spin_unlock_irqrestore(&phba->hbalock, iflag); + return rspiocbp; +} + +/** + * lpfc_sli_handle_slow_ring_event - Wrapper func for handling slow-path iocbs * @phba: Pointer to HBA context object. * @pring: Pointer to driver SLI ring object. * @mask: Host attention register mask for this ring. * - * This function is called from the worker thread when there is a ring - * event for non-fcp rings. The caller does not hold any lock . - * The function processes each response iocb in the response ring until it - * finds an iocb with LE bit set and chains all the iocbs upto the iocb with - * LE bit set. The function will call lpfc_sli_process_sol_iocb function if the - * response iocb indicates a completion of a command iocb. The function - * will call lpfc_sli_process_unsol_iocb function if this is an unsolicited - * iocb. The function frees the resources or calls the completion handler if - * this iocb is an abort completion. The function returns 0 when the allocated - * iocbs are not freed, otherwise returns 1. + * This routine wraps the actual slow_ring event process routine from the + * API jump table function pointer from the lpfc_hba struct. **/ -int +void lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, uint32_t mask) +{ + phba->lpfc_sli_handle_slow_ring_event(phba, pring, mask); +} + +/** + * lpfc_sli_handle_slow_ring_event_s3 - Handle SLI3 ring event for non-FCP rings + * @phba: Pointer to HBA context object. + * @pring: Pointer to driver SLI ring object. + * @mask: Host attention register mask for this ring. + * + * This function is called from the worker thread when there is a ring event + * for non-fcp rings. The caller does not hold any lock. The function will + * remove each response iocb in the response ring and calls the handle + * response iocb routine (lpfc_sli_sp_handle_rspiocb) to process it. + **/ +static void +lpfc_sli_handle_slow_ring_event_s3(struct lpfc_hba *phba, + struct lpfc_sli_ring *pring, uint32_t mask) { struct lpfc_pgp *pgp; IOCB_t *entry; IOCB_t *irsp = NULL; struct lpfc_iocbq *rspiocbp = NULL; - struct lpfc_iocbq *next_iocb; - struct lpfc_iocbq *cmdiocbp; - struct lpfc_iocbq *saveq; - uint8_t iocb_cmd_type; - lpfc_iocb_type type; - uint32_t status, free_saveq; uint32_t portRspPut, portRspMax; - int rc = 1; unsigned long iflag; + uint32_t status; pgp = &phba->port_gp[pring->ringno]; spin_lock_irqsave(&phba->hbalock, iflag); @@ -2128,7 +2916,7 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba, phba->work_hs = HS_FFER3; lpfc_handle_eratt(phba); - return 1; + return; } rmb(); @@ -2173,138 +2961,10 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba, writel(pring->rspidx, &phba->host_gp[pring->ringno].rspGetInx); - list_add_tail(&rspiocbp->list, &(pring->iocb_continueq)); - - pring->iocb_continueq_cnt++; - if (irsp->ulpLe) { - /* - * By default, the driver expects to free all resources - * associated with this iocb completion. - */ - free_saveq = 1; - saveq = list_get_first(&pring->iocb_continueq, - struct lpfc_iocbq, list); - irsp = &(saveq->iocb); - list_del_init(&pring->iocb_continueq); - pring->iocb_continueq_cnt = 0; - - pring->stats.iocb_rsp++; - - /* - * If resource errors reported from HBA, reduce - * queuedepths of the SCSI device. - */ - if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) && - (irsp->un.ulpWord[4] == IOERR_NO_RESOURCES)) { - spin_unlock_irqrestore(&phba->hbalock, iflag); - lpfc_rampdown_queue_depth(phba); - spin_lock_irqsave(&phba->hbalock, iflag); - } - - if (irsp->ulpStatus) { - /* Rsp ring error: IOCB */ - lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, - "0328 Rsp Ring %d error: " - "IOCB Data: " - "x%x x%x x%x x%x " - "x%x x%x x%x x%x " - "x%x x%x x%x x%x " - "x%x x%x x%x x%x\n", - pring->ringno, - irsp->un.ulpWord[0], - irsp->un.ulpWord[1], - irsp->un.ulpWord[2], - irsp->un.ulpWord[3], - irsp->un.ulpWord[4], - irsp->un.ulpWord[5], - *(((uint32_t *) irsp) + 6), - *(((uint32_t *) irsp) + 7), - *(((uint32_t *) irsp) + 8), - *(((uint32_t *) irsp) + 9), - *(((uint32_t *) irsp) + 10), - *(((uint32_t *) irsp) + 11), - *(((uint32_t *) irsp) + 12), - *(((uint32_t *) irsp) + 13), - *(((uint32_t *) irsp) + 14), - *(((uint32_t *) irsp) + 15)); - } - - /* - * Fetch the IOCB command type and call the correct - * completion routine. Solicited and Unsolicited - * IOCBs on the ELS ring get freed back to the - * lpfc_iocb_list by the discovery kernel thread. - */ - iocb_cmd_type = irsp->ulpCommand & CMD_IOCB_MASK; - type = lpfc_sli_iocb_cmd_type(iocb_cmd_type); - if (type == LPFC_SOL_IOCB) { - spin_unlock_irqrestore(&phba->hbalock, iflag); - rc = lpfc_sli_process_sol_iocb(phba, pring, - saveq); - spin_lock_irqsave(&phba->hbalock, iflag); - } else if (type == LPFC_UNSOL_IOCB) { - spin_unlock_irqrestore(&phba->hbalock, iflag); - rc = lpfc_sli_process_unsol_iocb(phba, pring, - saveq); - spin_lock_irqsave(&phba->hbalock, iflag); - if (!rc) - free_saveq = 0; - } else if (type == LPFC_ABORT_IOCB) { - if ((irsp->ulpCommand != CMD_XRI_ABORTED_CX) && - ((cmdiocbp = - lpfc_sli_iocbq_lookup(phba, pring, - saveq)))) { - /* Call the specified completion - routine */ - if (cmdiocbp->iocb_cmpl) { - spin_unlock_irqrestore( - &phba->hbalock, - iflag); - (cmdiocbp->iocb_cmpl) (phba, - cmdiocbp, saveq); - spin_lock_irqsave( - &phba->hbalock, - iflag); - } else - __lpfc_sli_release_iocbq(phba, - cmdiocbp); - } - } else if (type == LPFC_UNKNOWN_IOCB) { - if (irsp->ulpCommand == CMD_ADAPTER_MSG) { - - char adaptermsg[LPFC_MAX_ADPTMSG]; - - memset(adaptermsg, 0, - LPFC_MAX_ADPTMSG); - memcpy(&adaptermsg[0], (uint8_t *) irsp, - MAX_MSG_DATA); - dev_warn(&((phba->pcidev)->dev), - "lpfc%d: %s\n", - phba->brd_no, adaptermsg); - } else { - /* Unknown IOCB command */ - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0335 Unknown IOCB " - "command Data: x%x " - "x%x x%x x%x\n", - irsp->ulpCommand, - irsp->ulpStatus, - irsp->ulpIoTag, - irsp->ulpContext); - } - } - - if (free_saveq) { - list_for_each_entry_safe(rspiocbp, next_iocb, - &saveq->list, list) { - list_del(&rspiocbp->list); - __lpfc_sli_release_iocbq(phba, - rspiocbp); - } - __lpfc_sli_release_iocbq(phba, saveq); - } - rspiocbp = NULL; - } + spin_unlock_irqrestore(&phba->hbalock, iflag); + /* Handle the response IOCB */ + rspiocbp = lpfc_sli_sp_handle_rspiocb(phba, pring, rspiocbp); + spin_lock_irqsave(&phba->hbalock, iflag); /* * If the port response put pointer has not been updated, sync @@ -2338,7 +2998,37 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba, } spin_unlock_irqrestore(&phba->hbalock, iflag); - return rc; + return; +} + +/** + * lpfc_sli_handle_slow_ring_event_s4 - Handle SLI4 slow-path els events + * @phba: Pointer to HBA context object. + * @pring: Pointer to driver SLI ring object. + * @mask: Host attention register mask for this ring. + * + * This function is called from the worker thread when there is a pending + * ELS response iocb on the driver internal slow-path response iocb worker + * queue. The caller does not hold any lock. The function will remove each + * response iocb from the response worker queue and calls the handle + * response iocb routine (lpfc_sli_sp_handle_rspiocb) to process it. + **/ +static void +lpfc_sli_handle_slow_ring_event_s4(struct lpfc_hba *phba, + struct lpfc_sli_ring *pring, uint32_t mask) +{ + struct lpfc_iocbq *irspiocbq; + unsigned long iflag; + + while (!list_empty(&phba->sli4_hba.sp_rspiocb_work_queue)) { + /* Get the response iocb from the head of work queue */ + spin_lock_irqsave(&phba->hbalock, iflag); + list_remove_head(&phba->sli4_hba.sp_rspiocb_work_queue, + irspiocbq, struct lpfc_iocbq, list); + spin_unlock_irqrestore(&phba->hbalock, iflag); + /* Process the response iocb */ + lpfc_sli_sp_handle_rspiocb(phba, pring, irspiocbq); + } } /** @@ -2420,7 +3110,7 @@ lpfc_sli_flush_fcp_rings(struct lpfc_hba *phba) } /** - * lpfc_sli_brdready - Check for host status bits + * lpfc_sli_brdready_s3 - Check for sli3 host ready status * @phba: Pointer to HBA context object. * @mask: Bit mask to be checked. * @@ -2432,8 +3122,8 @@ lpfc_sli_flush_fcp_rings(struct lpfc_hba *phba) * function returns 1 when HBA fail to restart otherwise returns * zero. **/ -int -lpfc_sli_brdready(struct lpfc_hba *phba, uint32_t mask) +static int +lpfc_sli_brdready_s3(struct lpfc_hba *phba, uint32_t mask) { uint32_t status; int i = 0; @@ -2477,6 +3167,56 @@ lpfc_sli_brdready(struct lpfc_hba *phba, uint32_t mask) return retval; } +/** + * lpfc_sli_brdready_s4 - Check for sli4 host ready status + * @phba: Pointer to HBA context object. + * @mask: Bit mask to be checked. + * + * This function checks the host status register to check if HBA is + * ready. This function will wait in a loop for the HBA to be ready + * If the HBA is not ready , the function will will reset the HBA PCI + * function again. The function returns 1 when HBA fail to be ready + * otherwise returns zero. + **/ +static int +lpfc_sli_brdready_s4(struct lpfc_hba *phba, uint32_t mask) +{ + uint32_t status; + int retval = 0; + + /* Read the HBA Host Status Register */ + status = lpfc_sli4_post_status_check(phba); + + if (status) { + phba->pport->port_state = LPFC_VPORT_UNKNOWN; + lpfc_sli_brdrestart(phba); + status = lpfc_sli4_post_status_check(phba); + } + + /* Check to see if any errors occurred during init */ + if (status) { + phba->link_state = LPFC_HBA_ERROR; + retval = 1; + } else + phba->sli4_hba.intr_enable = 0; + + return retval; +} + +/** + * lpfc_sli_brdready - Wrapper func for checking the hba readyness + * @phba: Pointer to HBA context object. + * @mask: Bit mask to be checked. + * + * This routine wraps the actual SLI3 or SLI4 hba readyness check routine + * from the API jump table function pointer from the lpfc_hba struct. + **/ +int +lpfc_sli_brdready(struct lpfc_hba *phba, uint32_t mask) +{ + return phba->lpfc_sli_brdready(phba, mask); +} + #define BARRIER_TEST_PATTERN (0xdeadbeef) /** @@ -2532,7 +3272,7 @@ void lpfc_reset_barrier(struct lpfc_hba *phba) mdelay(1); if (readl(resp_buf + 1) != ~(BARRIER_TEST_PATTERN)) { - if (phba->sli.sli_flag & LPFC_SLI2_ACTIVE || + if (phba->sli.sli_flag & LPFC_SLI_ACTIVE || phba->pport->stopped) goto restore_hc; else @@ -2613,7 +3353,9 @@ lpfc_sli_brdkill(struct lpfc_hba *phba) return 1; } - psli->sli_flag &= ~LPFC_SLI2_ACTIVE; + spin_lock_irq(&phba->hbalock); + psli->sli_flag &= ~LPFC_SLI_ACTIVE; + spin_unlock_irq(&phba->hbalock); mempool_free(pmb, phba->mbox_mem_pool); @@ -2636,10 +3378,10 @@ lpfc_sli_brdkill(struct lpfc_hba *phba) } spin_lock_irq(&phba->hbalock); psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; + psli->mbox_active = NULL; phba->link_flag &= ~LS_IGNORE_ERATT; spin_unlock_irq(&phba->hbalock); - psli->mbox_active = NULL; lpfc_hba_down_post(phba); phba->link_state = LPFC_HBA_ERROR; @@ -2647,7 +3389,7 @@ lpfc_sli_brdkill(struct lpfc_hba *phba) } /** - * lpfc_sli_brdreset - Reset the HBA + * lpfc_sli_brdreset - Reset a sli-2 or sli-3 HBA * @phba: Pointer to HBA context object. * * This function resets the HBA by writing HC_INITFF to the control @@ -2683,7 +3425,8 @@ lpfc_sli_brdreset(struct lpfc_hba *phba) (cfg_value & ~(PCI_COMMAND_PARITY | PCI_COMMAND_SERR))); - psli->sli_flag &= ~(LPFC_SLI2_ACTIVE | LPFC_PROCESS_LA); + psli->sli_flag &= ~(LPFC_SLI_ACTIVE | LPFC_PROCESS_LA); + /* Now toggle INITFF bit in the Host Control Register */ writel(HC_INITFF, phba->HCregaddr); mdelay(1); @@ -2710,7 +3453,66 @@ lpfc_sli_brdreset(struct lpfc_hba *phba) } /** - * lpfc_sli_brdrestart - Restart the HBA + * lpfc_sli4_brdreset - Reset a sli-4 HBA + * @phba: Pointer to HBA context object. + * + * This function resets a SLI4 HBA. This function disables PCI layer parity + * checking during resets the device. The caller is not required to hold + * any locks. + * + * This function returns 0 always. + **/ +int +lpfc_sli4_brdreset(struct lpfc_hba *phba) +{ + struct lpfc_sli *psli = &phba->sli; + uint16_t cfg_value; + uint8_t qindx; + + /* Reset HBA */ + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "0295 Reset HBA Data: x%x x%x\n", + phba->pport->port_state, psli->sli_flag); + + /* perform board reset */ + phba->fc_eventTag = 0; + phba->pport->fc_myDID = 0; + phba->pport->fc_prevDID = 0; + + /* Turn off parity checking and serr during the physical reset */ + pci_read_config_word(phba->pcidev, PCI_COMMAND, &cfg_value); + pci_write_config_word(phba->pcidev, PCI_COMMAND, + (cfg_value & + ~(PCI_COMMAND_PARITY | PCI_COMMAND_SERR))); + + spin_lock_irq(&phba->hbalock); + psli->sli_flag &= ~(LPFC_PROCESS_LA); + phba->fcf.fcf_flag = 0; + /* Clean up the child queue list for the CQs */ + list_del_init(&phba->sli4_hba.mbx_wq->list); + list_del_init(&phba->sli4_hba.els_wq->list); + list_del_init(&phba->sli4_hba.hdr_rq->list); + list_del_init(&phba->sli4_hba.dat_rq->list); + list_del_init(&phba->sli4_hba.mbx_cq->list); + list_del_init(&phba->sli4_hba.els_cq->list); + list_del_init(&phba->sli4_hba.rxq_cq->list); + for (qindx = 0; qindx < phba->cfg_fcp_wq_count; qindx++) + list_del_init(&phba->sli4_hba.fcp_wq[qindx]->list); + for (qindx = 0; qindx < phba->cfg_fcp_eq_count; qindx++) + list_del_init(&phba->sli4_hba.fcp_cq[qindx]->list); + spin_unlock_irq(&phba->hbalock); + + /* Now physically reset the device */ + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "0389 Performing PCI function reset!\n"); + /* Perform FCoE PCI function reset */ + lpfc_pci_function_reset(phba); + + return 0; +} + +/** + * lpfc_sli_brdrestart_s3 - Restart a sli-3 hba * @phba: Pointer to HBA context object. * * This function is called in the SLI initialization code path to @@ -2722,8 +3524,8 @@ lpfc_sli_brdreset(struct lpfc_hba *phba) * The function does not guarantee completion of MBX_RESTART mailbox * command before the return of this function. **/ -int -lpfc_sli_brdrestart(struct lpfc_hba *phba) +static int +lpfc_sli_brdrestart_s3(struct lpfc_hba *phba) { MAILBOX_t *mb; struct lpfc_sli *psli; @@ -2762,7 +3564,7 @@ lpfc_sli_brdrestart(struct lpfc_hba *phba) lpfc_sli_brdreset(phba); phba->pport->stopped = 0; phba->link_state = LPFC_INIT_START; - + phba->hba_flag = 0; spin_unlock_irq(&phba->hbalock); memset(&psli->lnk_stat_offsets, 0, sizeof(psli->lnk_stat_offsets)); @@ -2776,6 +3578,55 @@ lpfc_sli_brdrestart(struct lpfc_hba *phba) return 0; } +/** + * lpfc_sli_brdrestart_s4 - Restart the sli-4 hba + * @phba: Pointer to HBA context object. + * + * This function is called in the SLI initialization code path to restart + * a SLI4 HBA. The caller is not required to hold any lock. + * At the end of the function, it calls lpfc_hba_down_post function to + * free any pending commands. + **/ +static int +lpfc_sli_brdrestart_s4(struct lpfc_hba *phba) +{ + struct lpfc_sli *psli = &phba->sli; + + + /* Restart HBA */ + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "0296 Restart HBA Data: x%x x%x\n", + phba->pport->port_state, psli->sli_flag); + + lpfc_sli4_brdreset(phba); + + spin_lock_irq(&phba->hbalock); + phba->pport->stopped = 0; + phba->link_state = LPFC_INIT_START; + phba->hba_flag = 0; + spin_unlock_irq(&phba->hbalock); + + memset(&psli->lnk_stat_offsets, 0, sizeof(psli->lnk_stat_offsets)); + psli->stats_start = get_seconds(); + + lpfc_hba_down_post(phba); + + return 0; +} + +/** + * lpfc_sli_brdrestart - Wrapper func for restarting hba + * @phba: Pointer to HBA context object. + * + * This routine wraps the actual SLI3 or SLI4 hba restart routine from the + * API jump table function pointer from the lpfc_hba struct. +**/ +int +lpfc_sli_brdrestart(struct lpfc_hba *phba) +{ + return phba->lpfc_sli_brdrestart(phba); +} + /** * lpfc_sli_chipset_init - Wait for the restart of the HBA after a restart * @phba: Pointer to HBA context object. @@ -2940,7 +3791,7 @@ lpfc_sli_hbq_setup(struct lpfc_hba *phba) if (!pmb) return -ENOMEM; - pmbox = &pmb->mb; + pmbox = &pmb->u.mb; /* Initialize the struct lpfc_sli_hbq structure for each hbq */ phba->link_state = LPFC_INIT_MBX_CMDS; @@ -2983,6 +3834,26 @@ lpfc_sli_hbq_setup(struct lpfc_hba *phba) return 0; } +/** + * lpfc_sli4_rb_setup - Initialize and post RBs to HBA + * @phba: Pointer to HBA context object. + * + * This function is called during the SLI initialization to configure + * all the HBQs and post buffers to the HBQ. The caller is not + * required to hold any locks. This function will return zero if successful + * else it will return negative error code. + **/ +static int +lpfc_sli4_rb_setup(struct lpfc_hba *phba) +{ + phba->hbq_in_use = 1; + phba->hbqs[0].entry_count = lpfc_hbq_defs[0]->entry_count; + phba->hbq_count = 1; + /* Initially populate or replenish the HBQs */ + lpfc_sli_hbqbuf_init_hbqs(phba, 0); + return 0; +} + /** * lpfc_sli_config_port - Issue config port mailbox command * @phba: Pointer to HBA context object. @@ -3047,33 +3918,43 @@ lpfc_sli_config_port(struct lpfc_hba *phba, int sli_mode) lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0442 Adapter failed to init, mbxCmd x%x " "CONFIG_PORT, mbxStatus x%x Data: x%x\n", - pmb->mb.mbxCommand, pmb->mb.mbxStatus, 0); + pmb->u.mb.mbxCommand, pmb->u.mb.mbxStatus, 0); spin_lock_irq(&phba->hbalock); - phba->sli.sli_flag &= ~LPFC_SLI2_ACTIVE; + phba->sli.sli_flag &= ~LPFC_SLI_ACTIVE; spin_unlock_irq(&phba->hbalock); rc = -ENXIO; - } else + } else { + /* Allow asynchronous mailbox command to go through */ + spin_lock_irq(&phba->hbalock); + phba->sli.sli_flag &= ~LPFC_SLI_ASYNC_MBX_BLK; + spin_unlock_irq(&phba->hbalock); done = 1; + } } if (!done) { rc = -EINVAL; goto do_prep_failed; } - if (pmb->mb.un.varCfgPort.sli_mode == 3) { - if (!pmb->mb.un.varCfgPort.cMA) { + if (pmb->u.mb.un.varCfgPort.sli_mode == 3) { + if (!pmb->u.mb.un.varCfgPort.cMA) { rc = -ENXIO; goto do_prep_failed; } - if (phba->max_vpi && pmb->mb.un.varCfgPort.gmv) { + if (phba->max_vpi && pmb->u.mb.un.varCfgPort.gmv) { phba->sli3_options |= LPFC_SLI3_NPIV_ENABLED; - phba->max_vpi = pmb->mb.un.varCfgPort.max_vpi; + phba->max_vpi = pmb->u.mb.un.varCfgPort.max_vpi; + phba->max_vports = (phba->max_vpi > phba->max_vports) ? + phba->max_vpi : phba->max_vports; + } else phba->max_vpi = 0; - if (pmb->mb.un.varCfgPort.gerbm) + if (pmb->u.mb.un.varCfgPort.gdss) + phba->sli3_options |= LPFC_SLI3_DSS_ENABLED; + if (pmb->u.mb.un.varCfgPort.gerbm) phba->sli3_options |= LPFC_SLI3_HBQ_ENABLED; - if (pmb->mb.un.varCfgPort.gcrp) + if (pmb->u.mb.un.varCfgPort.gcrp) phba->sli3_options |= LPFC_SLI3_CRP_ENABLED; - if (pmb->mb.un.varCfgPort.ginb) { + if (pmb->u.mb.un.varCfgPort.ginb) { phba->sli3_options |= LPFC_SLI3_INB_ENABLED; phba->hbq_get = phba->mbox->us.s3_inb_pgp.hbq_get; phba->port_gp = phba->mbox->us.s3_inb_pgp.port; @@ -3089,7 +3970,7 @@ lpfc_sli_config_port(struct lpfc_hba *phba, int sli_mode) } if (phba->cfg_enable_bg) { - if (pmb->mb.un.varCfgPort.gbg) + if (pmb->u.mb.un.varCfgPort.gbg) phba->sli3_options |= LPFC_SLI3_BG_ENABLED; else lpfc_printf_log(phba, KERN_ERR, LOG_INIT, @@ -3184,8 +4065,9 @@ lpfc_sli_hba_setup(struct lpfc_hba *phba) if (rc) goto lpfc_sli_hba_setup_error; } - + spin_lock_irq(&phba->hbalock); phba->sli.sli_flag |= LPFC_PROCESS_LA; + spin_unlock_irq(&phba->hbalock); rc = lpfc_config_port_post(phba); if (rc) @@ -3200,6 +4082,493 @@ lpfc_sli_hba_setup_error: return rc; } +/** + * lpfc_sli4_read_fcoe_params - Read fcoe params from conf region + * @phba: Pointer to HBA context object. + * @mboxq: mailbox pointer. + * This function issue a dump mailbox command to read config region + * 23 and parse the records in the region and populate driver + * data structure. + **/ +static int +lpfc_sli4_read_fcoe_params(struct lpfc_hba *phba, + LPFC_MBOXQ_t *mboxq) +{ + struct lpfc_dmabuf *mp; + struct lpfc_mqe *mqe; + uint32_t data_length; + int rc; + + /* Program the default value of vlan_id and fc_map */ + phba->valid_vlan = 0; + phba->fc_map[0] = LPFC_FCOE_FCF_MAP0; + phba->fc_map[1] = LPFC_FCOE_FCF_MAP1; + phba->fc_map[2] = LPFC_FCOE_FCF_MAP2; + + mqe = &mboxq->u.mqe; + if (lpfc_dump_fcoe_param(phba, mboxq)) + return -ENOMEM; + + mp = (struct lpfc_dmabuf *) mboxq->context1; + rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); + + lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI, + "(%d):2571 Mailbox cmd x%x Status x%x " + "Data: x%x x%x x%x x%x x%x x%x x%x x%x x%x " + "x%x x%x x%x x%x x%x x%x x%x x%x x%x " + "CQ: x%x x%x x%x x%x\n", + mboxq->vport ? mboxq->vport->vpi : 0, + bf_get(lpfc_mqe_command, mqe), + bf_get(lpfc_mqe_status, mqe), + mqe->un.mb_words[0], mqe->un.mb_words[1], + mqe->un.mb_words[2], mqe->un.mb_words[3], + mqe->un.mb_words[4], mqe->un.mb_words[5], + mqe->un.mb_words[6], mqe->un.mb_words[7], + mqe->un.mb_words[8], mqe->un.mb_words[9], + mqe->un.mb_words[10], mqe->un.mb_words[11], + mqe->un.mb_words[12], mqe->un.mb_words[13], + mqe->un.mb_words[14], mqe->un.mb_words[15], + mqe->un.mb_words[16], mqe->un.mb_words[50], + mboxq->mcqe.word0, + mboxq->mcqe.mcqe_tag0, mboxq->mcqe.mcqe_tag1, + mboxq->mcqe.trailer); + + if (rc) { + lpfc_mbuf_free(phba, mp->virt, mp->phys); + kfree(mp); + return -EIO; + } + data_length = mqe->un.mb_words[5]; + if (data_length > DMP_FCOEPARAM_RGN_SIZE) { + lpfc_mbuf_free(phba, mp->virt, mp->phys); + kfree(mp); + return -EIO; + } + + lpfc_parse_fcoe_conf(phba, mp->virt, data_length); + lpfc_mbuf_free(phba, mp->virt, mp->phys); + kfree(mp); + return 0; +} + +/** + * lpfc_sli4_read_rev - Issue READ_REV and collect vpd data + * @phba: pointer to lpfc hba data structure. + * @mboxq: pointer to the LPFC_MBOXQ_t structure. + * @vpd: pointer to the memory to hold resulting port vpd data. + * @vpd_size: On input, the number of bytes allocated to @vpd. + * On output, the number of data bytes in @vpd. + * + * This routine executes a READ_REV SLI4 mailbox command. In + * addition, this routine gets the port vpd data. + * + * Return codes + * 0 - sucessful + * ENOMEM - could not allocated memory. + **/ +static int +lpfc_sli4_read_rev(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq, + uint8_t *vpd, uint32_t *vpd_size) +{ + int rc = 0; + uint32_t dma_size; + struct lpfc_dmabuf *dmabuf; + struct lpfc_mqe *mqe; + + dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); + if (!dmabuf) + return -ENOMEM; + + /* + * Get a DMA buffer for the vpd data resulting from the READ_REV + * mailbox command. + */ + dma_size = *vpd_size; + dmabuf->virt = dma_alloc_coherent(&phba->pcidev->dev, + dma_size, + &dmabuf->phys, + GFP_KERNEL); + if (!dmabuf->virt) { + kfree(dmabuf); + return -ENOMEM; + } + memset(dmabuf->virt, 0, dma_size); + + /* + * The SLI4 implementation of READ_REV conflicts at word1, + * bits 31:16 and SLI4 adds vpd functionality not present + * in SLI3. This code corrects the conflicts. + */ + lpfc_read_rev(phba, mboxq); + mqe = &mboxq->u.mqe; + mqe->un.read_rev.vpd_paddr_high = putPaddrHigh(dmabuf->phys); + mqe->un.read_rev.vpd_paddr_low = putPaddrLow(dmabuf->phys); + mqe->un.read_rev.word1 &= 0x0000FFFF; + bf_set(lpfc_mbx_rd_rev_vpd, &mqe->un.read_rev, 1); + bf_set(lpfc_mbx_rd_rev_avail_len, &mqe->un.read_rev, dma_size); + + rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); + if (rc) { + dma_free_coherent(&phba->pcidev->dev, dma_size, + dmabuf->virt, dmabuf->phys); + return -EIO; + } + + /* + * The available vpd length cannot be bigger than the + * DMA buffer passed to the port. Catch the less than + * case and update the caller's size. + */ + if (mqe->un.read_rev.avail_vpd_len < *vpd_size) + *vpd_size = mqe->un.read_rev.avail_vpd_len; + + lpfc_sli_pcimem_bcopy(dmabuf->virt, vpd, *vpd_size); + dma_free_coherent(&phba->pcidev->dev, dma_size, + dmabuf->virt, dmabuf->phys); + kfree(dmabuf); + return 0; +} + +/** + * lpfc_sli4_arm_cqeq_intr - Arm sli-4 device completion and event queues + * @phba: pointer to lpfc hba data structure. + * + * This routine is called to explicitly arm the SLI4 device's completion and + * event queues + **/ +static void +lpfc_sli4_arm_cqeq_intr(struct lpfc_hba *phba) +{ + uint8_t fcp_eqidx; + + lpfc_sli4_cq_release(phba->sli4_hba.mbx_cq, LPFC_QUEUE_REARM); + lpfc_sli4_cq_release(phba->sli4_hba.els_cq, LPFC_QUEUE_REARM); + lpfc_sli4_cq_release(phba->sli4_hba.rxq_cq, LPFC_QUEUE_REARM); + for (fcp_eqidx = 0; fcp_eqidx < phba->cfg_fcp_eq_count; fcp_eqidx++) + lpfc_sli4_cq_release(phba->sli4_hba.fcp_cq[fcp_eqidx], + LPFC_QUEUE_REARM); + lpfc_sli4_eq_release(phba->sli4_hba.sp_eq, LPFC_QUEUE_REARM); + for (fcp_eqidx = 0; fcp_eqidx < phba->cfg_fcp_eq_count; fcp_eqidx++) + lpfc_sli4_eq_release(phba->sli4_hba.fp_eq[fcp_eqidx], + LPFC_QUEUE_REARM); +} + +/** + * lpfc_sli4_hba_setup - SLI4 device intialization PCI function + * @phba: Pointer to HBA context object. + * + * This function is the main SLI4 device intialization PCI function. This + * function is called by the HBA intialization code, HBA reset code and + * HBA error attention handler code. Caller is not required to hold any + * locks. + **/ +int +lpfc_sli4_hba_setup(struct lpfc_hba *phba) +{ + int rc; + LPFC_MBOXQ_t *mboxq; + struct lpfc_mqe *mqe; + uint8_t *vpd; + uint32_t vpd_size; + uint32_t ftr_rsp = 0; + struct Scsi_Host *shost = lpfc_shost_from_vport(phba->pport); + struct lpfc_vport *vport = phba->pport; + struct lpfc_dmabuf *mp; + + /* Perform a PCI function reset to start from clean */ + rc = lpfc_pci_function_reset(phba); + if (unlikely(rc)) + return -ENODEV; + + /* Check the HBA Host Status Register for readyness */ + rc = lpfc_sli4_post_status_check(phba); + if (unlikely(rc)) + return -ENODEV; + else { + spin_lock_irq(&phba->hbalock); + phba->sli.sli_flag |= LPFC_SLI_ACTIVE; + spin_unlock_irq(&phba->hbalock); + } + + /* + * Allocate a single mailbox container for initializing the + * port. + */ + mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mboxq) + return -ENOMEM; + + /* + * Continue initialization with default values even if driver failed + * to read FCoE param config regions + */ + if (lpfc_sli4_read_fcoe_params(phba, mboxq)) + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_INIT, + "2570 Failed to read FCoE parameters \n"); + + /* Issue READ_REV to collect vpd and FW information. */ + vpd_size = PAGE_SIZE; + vpd = kzalloc(vpd_size, GFP_KERNEL); + if (!vpd) { + rc = -ENOMEM; + goto out_free_mbox; + } + + rc = lpfc_sli4_read_rev(phba, mboxq, vpd, &vpd_size); + if (unlikely(rc)) + goto out_free_vpd; + + mqe = &mboxq->u.mqe; + phba->sli_rev = bf_get(lpfc_mbx_rd_rev_sli_lvl, &mqe->un.read_rev); + if (bf_get(lpfc_mbx_rd_rev_fcoe, &mqe->un.read_rev)) + phba->hba_flag |= HBA_FCOE_SUPPORT; + if (phba->sli_rev != LPFC_SLI_REV4 || + !(phba->hba_flag & HBA_FCOE_SUPPORT)) { + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + "0376 READ_REV Error. SLI Level %d " + "FCoE enabled %d\n", + phba->sli_rev, phba->hba_flag & HBA_FCOE_SUPPORT); + rc = -EIO; + goto out_free_vpd; + } + /* + * Evaluate the read rev and vpd data. Populate the driver + * state with the results. If this routine fails, the failure + * is not fatal as the driver will use generic values. + */ + rc = lpfc_parse_vpd(phba, vpd, vpd_size); + if (unlikely(!rc)) { + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + "0377 Error %d parsing vpd. " + "Using defaults.\n", rc); + rc = 0; + } + + /* Save information as VPD data */ + phba->vpd.rev.biuRev = mqe->un.read_rev.first_hw_rev; + phba->vpd.rev.smRev = mqe->un.read_rev.second_hw_rev; + phba->vpd.rev.endecRev = mqe->un.read_rev.third_hw_rev; + phba->vpd.rev.fcphHigh = bf_get(lpfc_mbx_rd_rev_fcph_high, + &mqe->un.read_rev); + phba->vpd.rev.fcphLow = bf_get(lpfc_mbx_rd_rev_fcph_low, + &mqe->un.read_rev); + phba->vpd.rev.feaLevelHigh = bf_get(lpfc_mbx_rd_rev_ftr_lvl_high, + &mqe->un.read_rev); + phba->vpd.rev.feaLevelLow = bf_get(lpfc_mbx_rd_rev_ftr_lvl_low, + &mqe->un.read_rev); + phba->vpd.rev.sli1FwRev = mqe->un.read_rev.fw_id_rev; + memcpy(phba->vpd.rev.sli1FwName, mqe->un.read_rev.fw_name, 16); + phba->vpd.rev.sli2FwRev = mqe->un.read_rev.ulp_fw_id_rev; + memcpy(phba->vpd.rev.sli2FwName, mqe->un.read_rev.ulp_fw_name, 16); + phba->vpd.rev.opFwRev = mqe->un.read_rev.fw_id_rev; + memcpy(phba->vpd.rev.opFwName, mqe->un.read_rev.fw_name, 16); + lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI, + "(%d):0380 READ_REV Status x%x " + "fw_rev:%s fcphHi:%x fcphLo:%x flHi:%x flLo:%x\n", + mboxq->vport ? mboxq->vport->vpi : 0, + bf_get(lpfc_mqe_status, mqe), + phba->vpd.rev.opFwName, + phba->vpd.rev.fcphHigh, phba->vpd.rev.fcphLow, + phba->vpd.rev.feaLevelHigh, phba->vpd.rev.feaLevelLow); + + /* + * Discover the port's supported feature set and match it against the + * hosts requests. + */ + lpfc_request_features(phba, mboxq); + rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); + if (unlikely(rc)) { + rc = -EIO; + goto out_free_vpd; + } + + /* + * The port must support FCP initiator mode as this is the + * only mode running in the host. + */ + if (!(bf_get(lpfc_mbx_rq_ftr_rsp_fcpi, &mqe->un.req_ftrs))) { + lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_SLI, + "0378 No support for fcpi mode.\n"); + ftr_rsp++; + } + + /* + * If the port cannot support the host's requested features + * then turn off the global config parameters to disable the + * feature in the driver. This is not a fatal error. + */ + if ((phba->cfg_enable_bg) && + !(bf_get(lpfc_mbx_rq_ftr_rsp_dif, &mqe->un.req_ftrs))) + ftr_rsp++; + + if (phba->max_vpi && phba->cfg_enable_npiv && + !(bf_get(lpfc_mbx_rq_ftr_rsp_npiv, &mqe->un.req_ftrs))) + ftr_rsp++; + + if (ftr_rsp) { + lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_SLI, + "0379 Feature Mismatch Data: x%08x %08x " + "x%x x%x x%x\n", mqe->un.req_ftrs.word2, + mqe->un.req_ftrs.word3, phba->cfg_enable_bg, + phba->cfg_enable_npiv, phba->max_vpi); + if (!(bf_get(lpfc_mbx_rq_ftr_rsp_dif, &mqe->un.req_ftrs))) + phba->cfg_enable_bg = 0; + if (!(bf_get(lpfc_mbx_rq_ftr_rsp_npiv, &mqe->un.req_ftrs))) + phba->cfg_enable_npiv = 0; + } + + /* These SLI3 features are assumed in SLI4 */ + spin_lock_irq(&phba->hbalock); + phba->sli3_options |= (LPFC_SLI3_NPIV_ENABLED | LPFC_SLI3_HBQ_ENABLED); + spin_unlock_irq(&phba->hbalock); + + /* Read the port's service parameters. */ + lpfc_read_sparam(phba, mboxq, vport->vpi); + mboxq->vport = vport; + rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); + mp = (struct lpfc_dmabuf *) mboxq->context1; + if (rc == MBX_SUCCESS) { + memcpy(&vport->fc_sparam, mp->virt, sizeof(struct serv_parm)); + rc = 0; + } + + /* + * This memory was allocated by the lpfc_read_sparam routine. Release + * it to the mbuf pool. + */ + lpfc_mbuf_free(phba, mp->virt, mp->phys); + kfree(mp); + mboxq->context1 = NULL; + if (unlikely(rc)) { + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + "0382 READ_SPARAM command failed " + "status %d, mbxStatus x%x\n", + rc, bf_get(lpfc_mqe_status, mqe)); + phba->link_state = LPFC_HBA_ERROR; + rc = -EIO; + goto out_free_vpd; + } + + if (phba->cfg_soft_wwnn) + u64_to_wwn(phba->cfg_soft_wwnn, + vport->fc_sparam.nodeName.u.wwn); + if (phba->cfg_soft_wwpn) + u64_to_wwn(phba->cfg_soft_wwpn, + vport->fc_sparam.portName.u.wwn); + memcpy(&vport->fc_nodename, &vport->fc_sparam.nodeName, + sizeof(struct lpfc_name)); + memcpy(&vport->fc_portname, &vport->fc_sparam.portName, + sizeof(struct lpfc_name)); + + /* Update the fc_host data structures with new wwn. */ + fc_host_node_name(shost) = wwn_to_u64(vport->fc_nodename.u.wwn); + fc_host_port_name(shost) = wwn_to_u64(vport->fc_portname.u.wwn); + + /* Register SGL pool to the device using non-embedded mailbox command */ + rc = lpfc_sli4_post_sgl_list(phba); + if (unlikely(rc)) { + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + "0582 Error %d during sgl post operation", rc); + rc = -ENODEV; + goto out_free_vpd; + } + + /* Register SCSI SGL pool to the device */ + rc = lpfc_sli4_repost_scsi_sgl_list(phba); + if (unlikely(rc)) { + lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_SLI, + "0383 Error %d during scsi sgl post opeation", + rc); + /* Some Scsi buffers were moved to the abort scsi list */ + /* A pci function reset will repost them */ + rc = -ENODEV; + goto out_free_vpd; + } + + /* Post the rpi header region to the device. */ + rc = lpfc_sli4_post_all_rpi_hdrs(phba); + if (unlikely(rc)) { + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + "0393 Error %d during rpi post operation\n", + rc); + rc = -ENODEV; + goto out_free_vpd; + } + if (phba->cfg_enable_fip) + bf_set(lpfc_fip_flag, &phba->sli4_hba.sli4_flags, 1); + else + bf_set(lpfc_fip_flag, &phba->sli4_hba.sli4_flags, 0); + + /* Set up all the queues to the device */ + rc = lpfc_sli4_queue_setup(phba); + if (unlikely(rc)) { + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + "0381 Error %d during queue setup.\n ", rc); + goto out_stop_timers; + } + + /* Arm the CQs and then EQs on device */ + lpfc_sli4_arm_cqeq_intr(phba); + + /* Indicate device interrupt mode */ + phba->sli4_hba.intr_enable = 1; + + /* Allow asynchronous mailbox command to go through */ + spin_lock_irq(&phba->hbalock); + phba->sli.sli_flag &= ~LPFC_SLI_ASYNC_MBX_BLK; + spin_unlock_irq(&phba->hbalock); + + /* Post receive buffers to the device */ + lpfc_sli4_rb_setup(phba); + + /* Start the ELS watchdog timer */ + /* + * The driver for SLI4 is not yet ready to process timeouts + * or interrupts. Once it is, the comment bars can be removed. + */ + /* mod_timer(&vport->els_tmofunc, + * jiffies + HZ * (phba->fc_ratov*2)); */ + + /* Start heart beat timer */ + mod_timer(&phba->hb_tmofunc, + jiffies + HZ * LPFC_HB_MBOX_INTERVAL); + phba->hb_outstanding = 0; + phba->last_completion_time = jiffies; + + /* Start error attention (ERATT) polling timer */ + mod_timer(&phba->eratt_poll, jiffies + HZ * LPFC_ERATT_POLL_INTERVAL); + + /* + * The port is ready, set the host's link state to LINK_DOWN + * in preparation for link interrupts. + */ + lpfc_init_link(phba, mboxq, phba->cfg_topology, phba->cfg_link_speed); + mboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl; + lpfc_set_loopback_flag(phba); + /* Change driver state to LPFC_LINK_DOWN right before init link */ + spin_lock_irq(&phba->hbalock); + phba->link_state = LPFC_LINK_DOWN; + spin_unlock_irq(&phba->hbalock); + rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT); + if (unlikely(rc != MBX_NOT_FINISHED)) { + kfree(vpd); + return 0; + } else + rc = -EIO; + + /* Unset all the queues set up in this routine when error out */ + if (rc) + lpfc_sli4_queue_unset(phba); + +out_stop_timers: + if (rc) + lpfc_stop_hba_timers(phba); +out_free_vpd: + kfree(vpd); +out_free_mbox: + mempool_free(mboxq, phba->mbox_mem_pool); + return rc; +} /** * lpfc_mbox_timeout - Timeout call back function for mbox timer @@ -3244,7 +4613,7 @@ void lpfc_mbox_timeout_handler(struct lpfc_hba *phba) { LPFC_MBOXQ_t *pmbox = phba->sli.mbox_active; - MAILBOX_t *mb = &pmbox->mb; + MAILBOX_t *mb = &pmbox->u.mb; struct lpfc_sli *psli = &phba->sli; struct lpfc_sli_ring *pring; @@ -3281,7 +4650,7 @@ lpfc_mbox_timeout_handler(struct lpfc_hba *phba) spin_unlock_irq(&phba->pport->work_port_lock); spin_lock_irq(&phba->hbalock); phba->link_state = LPFC_LINK_UNKNOWN; - psli->sli_flag &= ~LPFC_SLI2_ACTIVE; + psli->sli_flag &= ~LPFC_SLI_ACTIVE; spin_unlock_irq(&phba->hbalock); pring = &psli->ring[psli->fcp_ring]; @@ -3289,32 +4658,20 @@ lpfc_mbox_timeout_handler(struct lpfc_hba *phba) lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, "0345 Resetting board due to mailbox timeout\n"); - /* - * lpfc_offline calls lpfc_sli_hba_down which will clean up - * on oustanding mailbox commands. - */ - /* If resets are disabled then set error state and return. */ - if (!phba->cfg_enable_hba_reset) { - phba->link_state = LPFC_HBA_ERROR; - return; - } - lpfc_offline_prep(phba); - lpfc_offline(phba); - lpfc_sli_brdrestart(phba); - lpfc_online(phba); - lpfc_unblock_mgmt_io(phba); - return; + + /* Reset the HBA device */ + lpfc_reset_hba(phba); } /** - * lpfc_sli_issue_mbox - Issue a mailbox command to firmware + * lpfc_sli_issue_mbox_s3 - Issue an SLI3 mailbox command to firmware * @phba: Pointer to HBA context object. * @pmbox: Pointer to mailbox object. * @flag: Flag indicating how the mailbox need to be processed. * * This function is called by discovery code and HBA management code - * to submit a mailbox command to firmware. This function gets the - * hbalock to protect the data structures. + * to submit a mailbox command to firmware with SLI-3 interface spec. This + * function gets the hbalock to protect the data structures. * The mailbox command can be submitted in polling mode, in which case * this function will wait in a polling loop for the completion of the * mailbox. @@ -3332,8 +4689,9 @@ lpfc_mbox_timeout_handler(struct lpfc_hba *phba) * return codes the caller owns the mailbox command after the return of * the function. **/ -int -lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag) +static int +lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, + uint32_t flag) { MAILBOX_t *mb; struct lpfc_sli *psli = &phba->sli; @@ -3349,6 +4707,10 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag) spin_lock_irqsave(&phba->hbalock, drvr_flag); if (!pmbox) { /* processing mbox queue from intr_handler */ + if (unlikely(psli->sli_flag & LPFC_SLI_ASYNC_MBX_BLK)) { + spin_unlock_irqrestore(&phba->hbalock, drvr_flag); + return MBX_SUCCESS; + } processing_queue = 1; phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; pmbox = lpfc_mbox_get(phba); @@ -3365,7 +4727,7 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag) lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_VPORT, "1806 Mbox x%x failed. No vport\n", - pmbox->mb.mbxCommand); + pmbox->u.mb.mbxCommand); dump_stack(); goto out_not_finished; } @@ -3385,21 +4747,29 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag) psli = &phba->sli; - mb = &pmbox->mb; + mb = &pmbox->u.mb; status = MBX_SUCCESS; if (phba->link_state == LPFC_HBA_ERROR) { spin_unlock_irqrestore(&phba->hbalock, drvr_flag); /* Mbox command cannot issue */ - LOG_MBOX_CANNOT_ISSUE_DATA(phba, pmbox, psli, flag); + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + "(%d):0311 Mailbox command x%x cannot " + "issue Data: x%x x%x\n", + pmbox->vport ? pmbox->vport->vpi : 0, + pmbox->u.mb.mbxCommand, psli->sli_flag, flag); goto out_not_finished; } if (mb->mbxCommand != MBX_KILL_BOARD && flag & MBX_NOWAIT && !(readl(phba->HCregaddr) & HC_MBINT_ENA)) { spin_unlock_irqrestore(&phba->hbalock, drvr_flag); - LOG_MBOX_CANNOT_ISSUE_DATA(phba, pmbox, psli, flag); + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + "(%d):2528 Mailbox command x%x cannot " + "issue Data: x%x x%x\n", + pmbox->vport ? pmbox->vport->vpi : 0, + pmbox->u.mb.mbxCommand, psli->sli_flag, flag); goto out_not_finished; } @@ -3413,14 +4783,24 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag) spin_unlock_irqrestore(&phba->hbalock, drvr_flag); /* Mbox command cannot issue */ - LOG_MBOX_CANNOT_ISSUE_DATA(phba, pmbox, psli, flag); + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + "(%d):2529 Mailbox command x%x " + "cannot issue Data: x%x x%x\n", + pmbox->vport ? pmbox->vport->vpi : 0, + pmbox->u.mb.mbxCommand, + psli->sli_flag, flag); goto out_not_finished; } - if (!(psli->sli_flag & LPFC_SLI2_ACTIVE)) { + if (!(psli->sli_flag & LPFC_SLI_ACTIVE)) { spin_unlock_irqrestore(&phba->hbalock, drvr_flag); /* Mbox command cannot issue */ - LOG_MBOX_CANNOT_ISSUE_DATA(phba, pmbox, psli, flag); + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + "(%d):2530 Mailbox command x%x " + "cannot issue Data: x%x x%x\n", + pmbox->vport ? pmbox->vport->vpi : 0, + pmbox->u.mb.mbxCommand, + psli->sli_flag, flag); goto out_not_finished; } @@ -3462,12 +4842,17 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag) /* If we are not polling, we MUST be in SLI2 mode */ if (flag != MBX_POLL) { - if (!(psli->sli_flag & LPFC_SLI2_ACTIVE) && + if (!(psli->sli_flag & LPFC_SLI_ACTIVE) && (mb->mbxCommand != MBX_KILL_BOARD)) { psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; spin_unlock_irqrestore(&phba->hbalock, drvr_flag); /* Mbox command cannot issue */ - LOG_MBOX_CANNOT_ISSUE_DATA(phba, pmbox, psli, flag); + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + "(%d):2531 Mailbox command x%x " + "cannot issue Data: x%x x%x\n", + pmbox->vport ? pmbox->vport->vpi : 0, + pmbox->u.mb.mbxCommand, + psli->sli_flag, flag); goto out_not_finished; } /* timeout active mbox command */ @@ -3506,7 +4891,7 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag) /* next set own bit for the adapter and copy over command word */ mb->mbxOwner = OWN_CHIP; - if (psli->sli_flag & LPFC_SLI2_ACTIVE) { + if (psli->sli_flag & LPFC_SLI_ACTIVE) { /* First copy command data to host SLIM area */ lpfc_sli_pcimem_bcopy(mb, phba->mbox, MAILBOX_CMD_SIZE); } else { @@ -3529,7 +4914,7 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag) if (mb->mbxCommand == MBX_CONFIG_PORT) { /* switch over to host mailbox */ - psli->sli_flag |= LPFC_SLI2_ACTIVE; + psli->sli_flag |= LPFC_SLI_ACTIVE; } } @@ -3552,7 +4937,7 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag) writel(CA_MBATT, phba->CAregaddr); readl(phba->CAregaddr); /* flush */ - if (psli->sli_flag & LPFC_SLI2_ACTIVE) { + if (psli->sli_flag & LPFC_SLI_ACTIVE) { /* First read mbox status word */ word0 = *((uint32_t *)phba->mbox); word0 = le32_to_cpu(word0); @@ -3591,7 +4976,7 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag) spin_lock_irqsave(&phba->hbalock, drvr_flag); } - if (psli->sli_flag & LPFC_SLI2_ACTIVE) { + if (psli->sli_flag & LPFC_SLI_ACTIVE) { /* First copy command data */ word0 = *((uint32_t *)phba->mbox); word0 = le32_to_cpu(word0); @@ -3604,7 +4989,7 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag) if (((slimword0 & OWN_CHIP) != OWN_CHIP) && slimmb->mbxStatus) { psli->sli_flag &= - ~LPFC_SLI2_ACTIVE; + ~LPFC_SLI_ACTIVE; word0 = slimword0; } } @@ -3616,7 +5001,7 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag) ha_copy = readl(phba->HAregaddr); } - if (psli->sli_flag & LPFC_SLI2_ACTIVE) { + if (psli->sli_flag & LPFC_SLI_ACTIVE) { /* copy results back to user */ lpfc_sli_pcimem_bcopy(phba->mbox, mb, MAILBOX_CMD_SIZE); } else { @@ -3643,12 +5028,526 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag) out_not_finished: if (processing_queue) { - pmbox->mb.mbxStatus = MBX_NOT_FINISHED; + pmbox->u.mb.mbxStatus = MBX_NOT_FINISHED; lpfc_mbox_cmpl_put(phba, pmbox); } return MBX_NOT_FINISHED; } +/** + * lpfc_sli4_async_mbox_block - Block posting SLI4 asynchronous mailbox command + * @phba: Pointer to HBA context object. + * + * The function blocks the posting of SLI4 asynchronous mailbox commands from + * the driver internal pending mailbox queue. It will then try to wait out the + * possible outstanding mailbox command before return. + * + * Returns: + * 0 - the outstanding mailbox command completed; otherwise, the wait for + * the outstanding mailbox command timed out. + **/ +static int +lpfc_sli4_async_mbox_block(struct lpfc_hba *phba) +{ + struct lpfc_sli *psli = &phba->sli; + uint8_t actcmd = MBX_HEARTBEAT; + int rc = 0; + unsigned long timeout; + + /* Mark the asynchronous mailbox command posting as blocked */ + spin_lock_irq(&phba->hbalock); + psli->sli_flag |= LPFC_SLI_ASYNC_MBX_BLK; + if (phba->sli.mbox_active) + actcmd = phba->sli.mbox_active->u.mb.mbxCommand; + spin_unlock_irq(&phba->hbalock); + /* Determine how long we might wait for the active mailbox + * command to be gracefully completed by firmware. + */ + timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba, actcmd) * 1000) + + jiffies; + /* Wait for the outstnading mailbox command to complete */ + while (phba->sli.mbox_active) { + /* Check active mailbox complete status every 2ms */ + msleep(2); + if (time_after(jiffies, timeout)) { + /* Timeout, marked the outstanding cmd not complete */ + rc = 1; + break; + } + } + + /* Can not cleanly block async mailbox command, fails it */ + if (rc) { + spin_lock_irq(&phba->hbalock); + psli->sli_flag &= ~LPFC_SLI_ASYNC_MBX_BLK; + spin_unlock_irq(&phba->hbalock); + } + return rc; +} + +/** + * lpfc_sli4_async_mbox_unblock - Block posting SLI4 async mailbox command + * @phba: Pointer to HBA context object. + * + * The function unblocks and resume posting of SLI4 asynchronous mailbox + * commands from the driver internal pending mailbox queue. It makes sure + * that there is no outstanding mailbox command before resuming posting + * asynchronous mailbox commands. If, for any reason, there is outstanding + * mailbox command, it will try to wait it out before resuming asynchronous + * mailbox command posting. + **/ +static void +lpfc_sli4_async_mbox_unblock(struct lpfc_hba *phba) +{ + struct lpfc_sli *psli = &phba->sli; + + spin_lock_irq(&phba->hbalock); + if (!(psli->sli_flag & LPFC_SLI_ASYNC_MBX_BLK)) { + /* Asynchronous mailbox posting is not blocked, do nothing */ + spin_unlock_irq(&phba->hbalock); + return; + } + + /* Outstanding synchronous mailbox command is guaranteed to be done, + * successful or timeout, after timing-out the outstanding mailbox + * command shall always be removed, so just unblock posting async + * mailbox command and resume + */ + psli->sli_flag &= ~LPFC_SLI_ASYNC_MBX_BLK; + spin_unlock_irq(&phba->hbalock); + + /* wake up worker thread to post asynchronlous mailbox command */ + lpfc_worker_wake_up(phba); +} + +/** + * lpfc_sli4_post_sync_mbox - Post an SLI4 mailbox to the bootstrap mailbox + * @phba: Pointer to HBA context object. + * @mboxq: Pointer to mailbox object. + * + * The function posts a mailbox to the port. The mailbox is expected + * to be comletely filled in and ready for the port to operate on it. + * This routine executes a synchronous completion operation on the + * mailbox by polling for its completion. + * + * The caller must not be holding any locks when calling this routine. + * + * Returns: + * MBX_SUCCESS - mailbox posted successfully + * Any of the MBX error values. + **/ +static int +lpfc_sli4_post_sync_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) +{ + int rc = MBX_SUCCESS; + unsigned long iflag; + uint32_t db_ready; + uint32_t mcqe_status; + uint32_t mbx_cmnd; + unsigned long timeout; + struct lpfc_sli *psli = &phba->sli; + struct lpfc_mqe *mb = &mboxq->u.mqe; + struct lpfc_bmbx_create *mbox_rgn; + struct dma_address *dma_address; + struct lpfc_register bmbx_reg; + + /* + * Only one mailbox can be active to the bootstrap mailbox region + * at a time and there is no queueing provided. + */ + spin_lock_irqsave(&phba->hbalock, iflag); + if (psli->sli_flag & LPFC_SLI_MBOX_ACTIVE) { + spin_unlock_irqrestore(&phba->hbalock, iflag); + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + "(%d):2532 Mailbox command x%x (x%x) " + "cannot issue Data: x%x x%x\n", + mboxq->vport ? mboxq->vport->vpi : 0, + mboxq->u.mb.mbxCommand, + lpfc_sli4_mbox_opcode_get(phba, mboxq), + psli->sli_flag, MBX_POLL); + return MBXERR_ERROR; + } + /* The server grabs the token and owns it until release */ + psli->sli_flag |= LPFC_SLI_MBOX_ACTIVE; + phba->sli.mbox_active = mboxq; + spin_unlock_irqrestore(&phba->hbalock, iflag); + + /* + * Initialize the bootstrap memory region to avoid stale data areas + * in the mailbox post. Then copy the caller's mailbox contents to + * the bmbx mailbox region. + */ + mbx_cmnd = bf_get(lpfc_mqe_command, mb); + memset(phba->sli4_hba.bmbx.avirt, 0, sizeof(struct lpfc_bmbx_create)); + lpfc_sli_pcimem_bcopy(mb, phba->sli4_hba.bmbx.avirt, + sizeof(struct lpfc_mqe)); + + /* Post the high mailbox dma address to the port and wait for ready. */ + dma_address = &phba->sli4_hba.bmbx.dma_address; + writel(dma_address->addr_hi, phba->sli4_hba.BMBXregaddr); + + timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba, mbx_cmnd) + * 1000) + jiffies; + do { + bmbx_reg.word0 = readl(phba->sli4_hba.BMBXregaddr); + db_ready = bf_get(lpfc_bmbx_rdy, &bmbx_reg); + if (!db_ready) + msleep(2); + + if (time_after(jiffies, timeout)) { + rc = MBXERR_ERROR; + goto exit; + } + } while (!db_ready); + + /* Post the low mailbox dma address to the port. */ + writel(dma_address->addr_lo, phba->sli4_hba.BMBXregaddr); + timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba, mbx_cmnd) + * 1000) + jiffies; + do { + bmbx_reg.word0 = readl(phba->sli4_hba.BMBXregaddr); + db_ready = bf_get(lpfc_bmbx_rdy, &bmbx_reg); + if (!db_ready) + msleep(2); + + if (time_after(jiffies, timeout)) { + rc = MBXERR_ERROR; + goto exit; + } + } while (!db_ready); + + /* + * Read the CQ to ensure the mailbox has completed. + * If so, update the mailbox status so that the upper layers + * can complete the request normally. + */ + lpfc_sli_pcimem_bcopy(phba->sli4_hba.bmbx.avirt, mb, + sizeof(struct lpfc_mqe)); + mbox_rgn = (struct lpfc_bmbx_create *) phba->sli4_hba.bmbx.avirt; + lpfc_sli_pcimem_bcopy(&mbox_rgn->mcqe, &mboxq->mcqe, + sizeof(struct lpfc_mcqe)); + mcqe_status = bf_get(lpfc_mcqe_status, &mbox_rgn->mcqe); + + /* Prefix the mailbox status with range x4000 to note SLI4 status. */ + if (mcqe_status != MB_CQE_STATUS_SUCCESS) { + bf_set(lpfc_mqe_status, mb, LPFC_MBX_ERROR_RANGE | mcqe_status); + rc = MBXERR_ERROR; + } + + lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI, + "(%d):0356 Mailbox cmd x%x (x%x) Status x%x " + "Data: x%x x%x x%x x%x x%x x%x x%x x%x x%x x%x x%x" + " x%x x%x CQ: x%x x%x x%x x%x\n", + mboxq->vport ? mboxq->vport->vpi : 0, + mbx_cmnd, lpfc_sli4_mbox_opcode_get(phba, mboxq), + bf_get(lpfc_mqe_status, mb), + mb->un.mb_words[0], mb->un.mb_words[1], + mb->un.mb_words[2], mb->un.mb_words[3], + mb->un.mb_words[4], mb->un.mb_words[5], + mb->un.mb_words[6], mb->un.mb_words[7], + mb->un.mb_words[8], mb->un.mb_words[9], + mb->un.mb_words[10], mb->un.mb_words[11], + mb->un.mb_words[12], mboxq->mcqe.word0, + mboxq->mcqe.mcqe_tag0, mboxq->mcqe.mcqe_tag1, + mboxq->mcqe.trailer); +exit: + /* We are holding the token, no needed for lock when release */ + spin_lock_irqsave(&phba->hbalock, iflag); + psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; + phba->sli.mbox_active = NULL; + spin_unlock_irqrestore(&phba->hbalock, iflag); + return rc; +} + +/** + * lpfc_sli_issue_mbox_s4 - Issue an SLI4 mailbox command to firmware + * @phba: Pointer to HBA context object. + * @pmbox: Pointer to mailbox object. + * @flag: Flag indicating how the mailbox need to be processed. + * + * This function is called by discovery code and HBA management code to submit + * a mailbox command to firmware with SLI-4 interface spec. + * + * Return codes the caller owns the mailbox command after the return of the + * function. + **/ +static int +lpfc_sli_issue_mbox_s4(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq, + uint32_t flag) +{ + struct lpfc_sli *psli = &phba->sli; + unsigned long iflags; + int rc; + + /* Detect polling mode and jump to a handler */ + if (!phba->sli4_hba.intr_enable) { + if (flag == MBX_POLL) + rc = lpfc_sli4_post_sync_mbox(phba, mboxq); + else + rc = -EIO; + if (rc != MBX_SUCCESS) + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + "(%d):2541 Mailbox command x%x " + "(x%x) cannot issue Data: x%x x%x\n", + mboxq->vport ? mboxq->vport->vpi : 0, + mboxq->u.mb.mbxCommand, + lpfc_sli4_mbox_opcode_get(phba, mboxq), + psli->sli_flag, flag); + return rc; + } else if (flag == MBX_POLL) { + lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_SLI, + "(%d):2542 Try to issue mailbox command " + "x%x (x%x) synchronously ahead of async" + "mailbox command queue: x%x x%x\n", + mboxq->vport ? mboxq->vport->vpi : 0, + mboxq->u.mb.mbxCommand, + lpfc_sli4_mbox_opcode_get(phba, mboxq), + psli->sli_flag, flag); + /* Try to block the asynchronous mailbox posting */ + rc = lpfc_sli4_async_mbox_block(phba); + if (!rc) { + /* Successfully blocked, now issue sync mbox cmd */ + rc = lpfc_sli4_post_sync_mbox(phba, mboxq); + if (rc != MBX_SUCCESS) + lpfc_printf_log(phba, KERN_ERR, + LOG_MBOX | LOG_SLI, + "(%d):2597 Mailbox command " + "x%x (x%x) cannot issue " + "Data: x%x x%x\n", + mboxq->vport ? + mboxq->vport->vpi : 0, + mboxq->u.mb.mbxCommand, + lpfc_sli4_mbox_opcode_get(phba, + mboxq), + psli->sli_flag, flag); + /* Unblock the async mailbox posting afterward */ + lpfc_sli4_async_mbox_unblock(phba); + } + return rc; + } + + /* Now, interrupt mode asynchrous mailbox command */ + rc = lpfc_mbox_cmd_check(phba, mboxq); + if (rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + "(%d):2543 Mailbox command x%x (x%x) " + "cannot issue Data: x%x x%x\n", + mboxq->vport ? mboxq->vport->vpi : 0, + mboxq->u.mb.mbxCommand, + lpfc_sli4_mbox_opcode_get(phba, mboxq), + psli->sli_flag, flag); + goto out_not_finished; + } + rc = lpfc_mbox_dev_check(phba); + if (unlikely(rc)) { + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + "(%d):2544 Mailbox command x%x (x%x) " + "cannot issue Data: x%x x%x\n", + mboxq->vport ? mboxq->vport->vpi : 0, + mboxq->u.mb.mbxCommand, + lpfc_sli4_mbox_opcode_get(phba, mboxq), + psli->sli_flag, flag); + goto out_not_finished; + } + + /* Put the mailbox command to the driver internal FIFO */ + psli->slistat.mbox_busy++; + spin_lock_irqsave(&phba->hbalock, iflags); + lpfc_mbox_put(phba, mboxq); + spin_unlock_irqrestore(&phba->hbalock, iflags); + lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI, + "(%d):0354 Mbox cmd issue - Enqueue Data: " + "x%x (x%x) x%x x%x x%x\n", + mboxq->vport ? mboxq->vport->vpi : 0xffffff, + bf_get(lpfc_mqe_command, &mboxq->u.mqe), + lpfc_sli4_mbox_opcode_get(phba, mboxq), + phba->pport->port_state, + psli->sli_flag, MBX_NOWAIT); + /* Wake up worker thread to transport mailbox command from head */ + lpfc_worker_wake_up(phba); + + return MBX_BUSY; + +out_not_finished: + return MBX_NOT_FINISHED; +} + +/** + * lpfc_sli4_post_async_mbox - Post an SLI4 mailbox command to device + * @phba: Pointer to HBA context object. + * + * This function is called by worker thread to send a mailbox command to + * SLI4 HBA firmware. + * + **/ +int +lpfc_sli4_post_async_mbox(struct lpfc_hba *phba) +{ + struct lpfc_sli *psli = &phba->sli; + LPFC_MBOXQ_t *mboxq; + int rc = MBX_SUCCESS; + unsigned long iflags; + struct lpfc_mqe *mqe; + uint32_t mbx_cmnd; + + /* Check interrupt mode before post async mailbox command */ + if (unlikely(!phba->sli4_hba.intr_enable)) + return MBX_NOT_FINISHED; + + /* Check for mailbox command service token */ + spin_lock_irqsave(&phba->hbalock, iflags); + if (unlikely(psli->sli_flag & LPFC_SLI_ASYNC_MBX_BLK)) { + spin_unlock_irqrestore(&phba->hbalock, iflags); + return MBX_NOT_FINISHED; + } + if (psli->sli_flag & LPFC_SLI_MBOX_ACTIVE) { + spin_unlock_irqrestore(&phba->hbalock, iflags); + return MBX_NOT_FINISHED; + } + if (unlikely(phba->sli.mbox_active)) { + spin_unlock_irqrestore(&phba->hbalock, iflags); + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + "0384 There is pending active mailbox cmd\n"); + return MBX_NOT_FINISHED; + } + /* Take the mailbox command service token */ + psli->sli_flag |= LPFC_SLI_MBOX_ACTIVE; + + /* Get the next mailbox command from head of queue */ + mboxq = lpfc_mbox_get(phba); + + /* If no more mailbox command waiting for post, we're done */ + if (!mboxq) { + psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; + spin_unlock_irqrestore(&phba->hbalock, iflags); + return MBX_SUCCESS; + } + phba->sli.mbox_active = mboxq; + spin_unlock_irqrestore(&phba->hbalock, iflags); + + /* Check device readiness for posting mailbox command */ + rc = lpfc_mbox_dev_check(phba); + if (unlikely(rc)) + /* Driver clean routine will clean up pending mailbox */ + goto out_not_finished; + + /* Prepare the mbox command to be posted */ + mqe = &mboxq->u.mqe; + mbx_cmnd = bf_get(lpfc_mqe_command, mqe); + + /* Start timer for the mbox_tmo and log some mailbox post messages */ + mod_timer(&psli->mbox_tmo, (jiffies + + (HZ * lpfc_mbox_tmo_val(phba, mbx_cmnd)))); + + lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI, + "(%d):0355 Mailbox cmd x%x (x%x) issue Data: " + "x%x x%x\n", + mboxq->vport ? mboxq->vport->vpi : 0, mbx_cmnd, + lpfc_sli4_mbox_opcode_get(phba, mboxq), + phba->pport->port_state, psli->sli_flag); + + if (mbx_cmnd != MBX_HEARTBEAT) { + if (mboxq->vport) { + lpfc_debugfs_disc_trc(mboxq->vport, + LPFC_DISC_TRC_MBOX_VPORT, + "MBOX Send vport: cmd:x%x mb:x%x x%x", + mbx_cmnd, mqe->un.mb_words[0], + mqe->un.mb_words[1]); + } else { + lpfc_debugfs_disc_trc(phba->pport, + LPFC_DISC_TRC_MBOX, + "MBOX Send: cmd:x%x mb:x%x x%x", + mbx_cmnd, mqe->un.mb_words[0], + mqe->un.mb_words[1]); + } + } + psli->slistat.mbox_cmd++; + + /* Post the mailbox command to the port */ + rc = lpfc_sli4_mq_put(phba->sli4_hba.mbx_wq, mqe); + if (rc != MBX_SUCCESS) { + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + "(%d):2533 Mailbox command x%x (x%x) " + "cannot issue Data: x%x x%x\n", + mboxq->vport ? mboxq->vport->vpi : 0, + mboxq->u.mb.mbxCommand, + lpfc_sli4_mbox_opcode_get(phba, mboxq), + psli->sli_flag, MBX_NOWAIT); + goto out_not_finished; + } + + return rc; + +out_not_finished: + spin_lock_irqsave(&phba->hbalock, iflags); + mboxq->u.mb.mbxStatus = MBX_NOT_FINISHED; + __lpfc_mbox_cmpl_put(phba, mboxq); + /* Release the token */ + psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; + phba->sli.mbox_active = NULL; + spin_unlock_irqrestore(&phba->hbalock, iflags); + + return MBX_NOT_FINISHED; +} + +/** + * lpfc_sli_issue_mbox - Wrapper func for issuing mailbox command + * @phba: Pointer to HBA context object. + * @pmbox: Pointer to mailbox object. + * @flag: Flag indicating how the mailbox need to be processed. + * + * This routine wraps the actual SLI3 or SLI4 mailbox issuing routine from + * the API jump table function pointer from the lpfc_hba struct. + * + * Return codes the caller owns the mailbox command after the return of the + * function. + **/ +int +lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag) +{ + return phba->lpfc_sli_issue_mbox(phba, pmbox, flag); +} + +/** + * lpfc_mbox_api_table_setup - Set up mbox api fucntion jump table + * @phba: The hba struct for which this call is being executed. + * @dev_grp: The HBA PCI-Device group number. + * + * This routine sets up the mbox interface API function jump table in @phba + * struct. + * Returns: 0 - success, -ENODEV - failure. + **/ +int +lpfc_mbox_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp) +{ + + switch (dev_grp) { + case LPFC_PCI_DEV_LP: + phba->lpfc_sli_issue_mbox = lpfc_sli_issue_mbox_s3; + phba->lpfc_sli_handle_slow_ring_event = + lpfc_sli_handle_slow_ring_event_s3; + phba->lpfc_sli_hbq_to_firmware = lpfc_sli_hbq_to_firmware_s3; + phba->lpfc_sli_brdrestart = lpfc_sli_brdrestart_s3; + phba->lpfc_sli_brdready = lpfc_sli_brdready_s3; + break; + case LPFC_PCI_DEV_OC: + phba->lpfc_sli_issue_mbox = lpfc_sli_issue_mbox_s4; + phba->lpfc_sli_handle_slow_ring_event = + lpfc_sli_handle_slow_ring_event_s4; + phba->lpfc_sli_hbq_to_firmware = lpfc_sli_hbq_to_firmware_s4; + phba->lpfc_sli_brdrestart = lpfc_sli_brdrestart_s4; + phba->lpfc_sli_brdready = lpfc_sli_brdready_s4; + break; + default: + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "1420 Invalid HBA PCI-device group: 0x%x\n", + dev_grp); + return -ENODEV; + break; + } + return 0; +} + /** * __lpfc_sli_ringtx_put - Add an iocb to the txq * @phba: Pointer to HBA context object. @@ -3701,35 +5600,34 @@ lpfc_sli_next_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, } /** - * __lpfc_sli_issue_iocb - Lockless version of lpfc_sli_issue_iocb + * __lpfc_sli_issue_iocb_s3 - SLI3 device lockless ver of lpfc_sli_issue_iocb * @phba: Pointer to HBA context object. - * @pring: Pointer to driver SLI ring object. + * @ring_number: SLI ring number to issue iocb on. * @piocb: Pointer to command iocb. * @flag: Flag indicating if this command can be put into txq. * - * __lpfc_sli_issue_iocb is used by other functions in the driver - * to issue an iocb command to the HBA. If the PCI slot is recovering - * from error state or if HBA is resetting or if LPFC_STOP_IOCB_EVENT - * flag is turned on, the function returns IOCB_ERROR. - * When the link is down, this function allows only iocbs for - * posting buffers. - * This function finds next available slot in the command ring and - * posts the command to the available slot and writes the port - * attention register to request HBA start processing new iocb. - * If there is no slot available in the ring and - * flag & SLI_IOCB_RET_IOCB is set, the new iocb is added to the - * txq, otherwise the function returns IOCB_BUSY. + * __lpfc_sli_issue_iocb_s3 is used by other functions in the driver to issue + * an iocb command to an HBA with SLI-3 interface spec. If the PCI slot is + * recovering from error state, if HBA is resetting or if LPFC_STOP_IOCB_EVENT + * flag is turned on, the function returns IOCB_ERROR. When the link is down, + * this function allows only iocbs for posting buffers. This function finds + * next available slot in the command ring and posts the command to the + * available slot and writes the port attention register to request HBA start + * processing new iocb. If there is no slot available in the ring and + * flag & SLI_IOCB_RET_IOCB is set, the new iocb is added to the txq, otherwise + * the function returns IOCB_BUSY. * - * This function is called with hbalock held. - * The function will return success after it successfully submit the - * iocb to firmware or after adding to the txq. + * This function is called with hbalock held. The function will return success + * after it successfully submit the iocb to firmware or after adding to the + * txq. **/ static int -__lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, +__lpfc_sli_issue_iocb_s3(struct lpfc_hba *phba, uint32_t ring_number, struct lpfc_iocbq *piocb, uint32_t flag) { struct lpfc_iocbq *nextiocb; IOCB_t *iocb; + struct lpfc_sli_ring *pring = &phba->sli.ring[ring_number]; if (piocb->iocb_cmpl && (!piocb->vport) && (piocb->iocb.ulpCommand != CMD_ABORT_XRI_CN) && @@ -3833,6 +5731,493 @@ __lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, return IOCB_BUSY; } +/** + * lpfc_sli4_bpl2sgl - Convert the bpl/bde to a sgl. + * @phba: Pointer to HBA context object. + * @piocb: Pointer to command iocb. + * @sglq: Pointer to the scatter gather queue object. + * + * This routine converts the bpl or bde that is in the IOCB + * to a sgl list for the sli4 hardware. The physical address + * of the bpl/bde is converted back to a virtual address. + * If the IOCB contains a BPL then the list of BDE's is + * converted to sli4_sge's. If the IOCB contains a single + * BDE then it is converted to a single sli_sge. + * The IOCB is still in cpu endianess so the contents of + * the bpl can be used without byte swapping. + * + * Returns valid XRI = Success, NO_XRI = Failure. +**/ +static uint16_t +lpfc_sli4_bpl2sgl(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq, + struct lpfc_sglq *sglq) +{ + uint16_t xritag = NO_XRI; + struct ulp_bde64 *bpl = NULL; + struct ulp_bde64 bde; + struct sli4_sge *sgl = NULL; + IOCB_t *icmd; + int numBdes = 0; + int i = 0; + + if (!piocbq || !sglq) + return xritag; + + sgl = (struct sli4_sge *)sglq->sgl; + icmd = &piocbq->iocb; + if (icmd->un.genreq64.bdl.bdeFlags == BUFF_TYPE_BLP_64) { + numBdes = icmd->un.genreq64.bdl.bdeSize / + sizeof(struct ulp_bde64); + /* The addrHigh and addrLow fields within the IOCB + * have not been byteswapped yet so there is no + * need to swap them back. + */ + bpl = (struct ulp_bde64 *) + ((struct lpfc_dmabuf *)piocbq->context3)->virt; + + if (!bpl) + return xritag; + + for (i = 0; i < numBdes; i++) { + /* Should already be byte swapped. */ + sgl->addr_hi = bpl->addrHigh; + sgl->addr_lo = bpl->addrLow; + /* swap the size field back to the cpu so we + * can assign it to the sgl. + */ + bde.tus.w = le32_to_cpu(bpl->tus.w); + bf_set(lpfc_sli4_sge_len, sgl, bde.tus.f.bdeSize); + if ((i+1) == numBdes) + bf_set(lpfc_sli4_sge_last, sgl, 1); + else + bf_set(lpfc_sli4_sge_last, sgl, 0); + sgl->word2 = cpu_to_le32(sgl->word2); + sgl->word3 = cpu_to_le32(sgl->word3); + bpl++; + sgl++; + } + } else if (icmd->un.genreq64.bdl.bdeFlags == BUFF_TYPE_BDE_64) { + /* The addrHigh and addrLow fields of the BDE have not + * been byteswapped yet so they need to be swapped + * before putting them in the sgl. + */ + sgl->addr_hi = + cpu_to_le32(icmd->un.genreq64.bdl.addrHigh); + sgl->addr_lo = + cpu_to_le32(icmd->un.genreq64.bdl.addrLow); + bf_set(lpfc_sli4_sge_len, sgl, + icmd->un.genreq64.bdl.bdeSize); + bf_set(lpfc_sli4_sge_last, sgl, 1); + sgl->word2 = cpu_to_le32(sgl->word2); + sgl->word3 = cpu_to_le32(sgl->word3); + } + return sglq->sli4_xritag; +} + +/** + * lpfc_sli4_scmd_to_wqidx_distr - scsi command to SLI4 WQ index distribution + * @phba: Pointer to HBA context object. + * @piocb: Pointer to command iocb. + * + * This routine performs a round robin SCSI command to SLI4 FCP WQ index + * distribution. + * + * Return: index into SLI4 fast-path FCP queue index. + **/ +static uint32_t +lpfc_sli4_scmd_to_wqidx_distr(struct lpfc_hba *phba, struct lpfc_iocbq *piocb) +{ + static uint32_t fcp_qidx; + + return fcp_qidx++ % phba->cfg_fcp_wq_count; +} + +/** + * lpfc_sli_iocb2wqe - Convert the IOCB to a work queue entry. + * @phba: Pointer to HBA context object. + * @piocb: Pointer to command iocb. + * @wqe: Pointer to the work queue entry. + * + * This routine converts the iocb command to its Work Queue Entry + * equivalent. The wqe pointer should not have any fields set when + * this routine is called because it will memcpy over them. + * This routine does not set the CQ_ID or the WQEC bits in the + * wqe. + * + * Returns: 0 = Success, IOCB_ERROR = Failure. + **/ +static int +lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, + union lpfc_wqe *wqe) +{ + uint32_t payload_len = 0; + uint8_t ct = 0; + uint32_t fip; + uint32_t abort_tag; + uint8_t command_type = ELS_COMMAND_NON_FIP; + uint8_t cmnd; + uint16_t xritag; + struct ulp_bde64 *bpl = NULL; + + fip = bf_get(lpfc_fip_flag, &phba->sli4_hba.sli4_flags); + /* The fcp commands will set command type */ + if (iocbq->iocb_flag & LPFC_IO_FCP) + command_type = FCP_COMMAND; + else if (fip && (iocbq->iocb_flag & LPFC_FIP_ELS)) + command_type = ELS_COMMAND_FIP; + else + command_type = ELS_COMMAND_NON_FIP; + + /* Some of the fields are in the right position already */ + memcpy(wqe, &iocbq->iocb, sizeof(union lpfc_wqe)); + abort_tag = (uint32_t) iocbq->iotag; + xritag = iocbq->sli4_xritag; + wqe->words[7] = 0; /* The ct field has moved so reset */ + /* words0-2 bpl convert bde */ + if (iocbq->iocb.un.genreq64.bdl.bdeFlags == BUFF_TYPE_BLP_64) { + bpl = (struct ulp_bde64 *) + ((struct lpfc_dmabuf *)iocbq->context3)->virt; + if (!bpl) + return IOCB_ERROR; + + /* Should already be byte swapped. */ + wqe->generic.bde.addrHigh = le32_to_cpu(bpl->addrHigh); + wqe->generic.bde.addrLow = le32_to_cpu(bpl->addrLow); + /* swap the size field back to the cpu so we + * can assign it to the sgl. + */ + wqe->generic.bde.tus.w = le32_to_cpu(bpl->tus.w); + payload_len = wqe->generic.bde.tus.f.bdeSize; + } else + payload_len = iocbq->iocb.un.fcpi64.bdl.bdeSize; + + iocbq->iocb.ulpIoTag = iocbq->iotag; + cmnd = iocbq->iocb.ulpCommand; + + switch (iocbq->iocb.ulpCommand) { + case CMD_ELS_REQUEST64_CR: + if (!iocbq->iocb.ulpLe) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "2007 Only Limited Edition cmd Format" + " supported 0x%x\n", + iocbq->iocb.ulpCommand); + return IOCB_ERROR; + } + wqe->els_req.payload_len = payload_len; + /* Els_reguest64 has a TMO */ + bf_set(wqe_tmo, &wqe->els_req.wqe_com, + iocbq->iocb.ulpTimeout); + /* Need a VF for word 4 set the vf bit*/ + bf_set(els_req64_vf, &wqe->els_req, 0); + /* And a VFID for word 12 */ + bf_set(els_req64_vfid, &wqe->els_req, 0); + /* + * Set ct field to 3, indicates that the context_tag field + * contains the FCFI and remote N_Port_ID is + * in word 5. + */ + + ct = ((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l); + bf_set(lpfc_wqe_gen_context, &wqe->generic, + iocbq->iocb.ulpContext); + + bf_set(lpfc_wqe_gen_ct, &wqe->generic, ct); + bf_set(lpfc_wqe_gen_pu, &wqe->generic, 0); + /* CCP CCPE PV PRI in word10 were set in the memcpy */ + break; + case CMD_XMIT_SEQUENCE64_CR: + /* word3 iocb=io_tag32 wqe=payload_offset */ + /* payload offset used for multilpe outstanding + * sequences on the same exchange + */ + wqe->words[3] = 0; + /* word4 relative_offset memcpy */ + /* word5 r_ctl/df_ctl memcpy */ + bf_set(lpfc_wqe_gen_pu, &wqe->generic, 0); + wqe->xmit_sequence.xmit_len = payload_len; + break; + case CMD_XMIT_BCAST64_CN: + /* word3 iocb=iotag32 wqe=payload_len */ + wqe->words[3] = 0; /* no definition for this in wqe */ + /* word4 iocb=rsvd wqe=rsvd */ + /* word5 iocb=rctl/type/df_ctl wqe=rctl/type/df_ctl memcpy */ + /* word6 iocb=ctxt_tag/io_tag wqe=ctxt_tag/xri */ + bf_set(lpfc_wqe_gen_ct, &wqe->generic, + ((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l)); + break; + case CMD_FCP_IWRITE64_CR: + command_type = FCP_COMMAND_DATA_OUT; + /* The struct for wqe fcp_iwrite has 3 fields that are somewhat + * confusing. + * word3 is payload_len: byte offset to the sgl entry for the + * fcp_command. + * word4 is total xfer len, same as the IOCB->ulpParameter. + * word5 is initial xfer len 0 = wait for xfer-ready + */ + + /* Always wait for xfer-ready before sending data */ + wqe->fcp_iwrite.initial_xfer_len = 0; + /* word 4 (xfer length) should have been set on the memcpy */ + + /* allow write to fall through to read */ + case CMD_FCP_IREAD64_CR: + /* FCP_CMD is always the 1st sgl entry */ + wqe->fcp_iread.payload_len = + payload_len + sizeof(struct fcp_rsp); + + /* word 4 (xfer length) should have been set on the memcpy */ + + bf_set(lpfc_wqe_gen_erp, &wqe->generic, + iocbq->iocb.ulpFCP2Rcvy); + bf_set(lpfc_wqe_gen_lnk, &wqe->generic, iocbq->iocb.ulpXS); + /* The XC bit and the XS bit are similar. The driver never + * tracked whether or not the exchange was previouslly open. + * XC = Exchange create, 0 is create. 1 is already open. + * XS = link cmd: 1 do not close the exchange after command. + * XS = 0 close exchange when command completes. + * The only time we would not set the XC bit is when the XS bit + * is set and we are sending our 2nd or greater command on + * this exchange. + */ + /* Always open the exchange */ + bf_set(wqe_xc, &wqe->fcp_iread.wqe_com, 0); + + wqe->words[10] &= 0xffff0000; /* zero out ebde count */ + bf_set(lpfc_wqe_gen_pu, &wqe->generic, iocbq->iocb.ulpPU); + break; + case CMD_FCP_ICMND64_CR: + /* Always open the exchange */ + bf_set(wqe_xc, &wqe->fcp_iread.wqe_com, 0); + + wqe->words[4] = 0; + wqe->words[10] &= 0xffff0000; /* zero out ebde count */ + bf_set(lpfc_wqe_gen_pu, &wqe->generic, 0); + break; + case CMD_GEN_REQUEST64_CR: + /* word3 command length is described as byte offset to the + * rsp_data. Would always be 16, sizeof(struct sli4_sge) + * sgl[0] = cmnd + * sgl[1] = rsp. + * + */ + wqe->gen_req.command_len = payload_len; + /* Word4 parameter copied in the memcpy */ + /* Word5 [rctl, type, df_ctl, la] copied in memcpy */ + /* word6 context tag copied in memcpy */ + if (iocbq->iocb.ulpCt_h || iocbq->iocb.ulpCt_l) { + ct = ((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l); + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "2015 Invalid CT %x command 0x%x\n", + ct, iocbq->iocb.ulpCommand); + return IOCB_ERROR; + } + bf_set(lpfc_wqe_gen_ct, &wqe->generic, 0); + bf_set(wqe_tmo, &wqe->gen_req.wqe_com, + iocbq->iocb.ulpTimeout); + + bf_set(lpfc_wqe_gen_pu, &wqe->generic, iocbq->iocb.ulpPU); + command_type = OTHER_COMMAND; + break; + case CMD_XMIT_ELS_RSP64_CX: + /* words0-2 BDE memcpy */ + /* word3 iocb=iotag32 wqe=rsvd */ + wqe->words[3] = 0; + /* word4 iocb=did wge=rsvd. */ + wqe->words[4] = 0; + /* word5 iocb=rsvd wge=did */ + bf_set(wqe_els_did, &wqe->xmit_els_rsp.wqe_dest, + iocbq->iocb.un.elsreq64.remoteID); + + bf_set(lpfc_wqe_gen_ct, &wqe->generic, + ((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l)); + + bf_set(lpfc_wqe_gen_pu, &wqe->generic, iocbq->iocb.ulpPU); + bf_set(wqe_rcvoxid, &wqe->generic, iocbq->iocb.ulpContext); + if (!iocbq->iocb.ulpCt_h && iocbq->iocb.ulpCt_l) + bf_set(lpfc_wqe_gen_context, &wqe->generic, + iocbq->vport->vpi + phba->vpi_base); + command_type = OTHER_COMMAND; + break; + case CMD_CLOSE_XRI_CN: + case CMD_ABORT_XRI_CN: + case CMD_ABORT_XRI_CX: + /* words 0-2 memcpy should be 0 rserved */ + /* port will send abts */ + if (iocbq->iocb.ulpCommand == CMD_CLOSE_XRI_CN) + /* + * The link is down so the fw does not need to send abts + * on the wire. + */ + bf_set(abort_cmd_ia, &wqe->abort_cmd, 1); + else + bf_set(abort_cmd_ia, &wqe->abort_cmd, 0); + bf_set(abort_cmd_criteria, &wqe->abort_cmd, T_XRI_TAG); + abort_tag = iocbq->iocb.un.acxri.abortIoTag; + wqe->words[5] = 0; + bf_set(lpfc_wqe_gen_ct, &wqe->generic, + ((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l)); + abort_tag = iocbq->iocb.un.acxri.abortIoTag; + wqe->generic.abort_tag = abort_tag; + /* + * The abort handler will send us CMD_ABORT_XRI_CN or + * CMD_CLOSE_XRI_CN and the fw only accepts CMD_ABORT_XRI_CX + */ + bf_set(lpfc_wqe_gen_command, &wqe->generic, CMD_ABORT_XRI_CX); + cmnd = CMD_ABORT_XRI_CX; + command_type = OTHER_COMMAND; + xritag = 0; + break; + case CMD_XRI_ABORTED_CX: + case CMD_CREATE_XRI_CR: /* Do we expect to use this? */ + /* words0-2 are all 0's no bde */ + /* word3 and word4 are rsvrd */ + wqe->words[3] = 0; + wqe->words[4] = 0; + /* word5 iocb=rsvd wge=did */ + /* There is no remote port id in the IOCB? */ + /* Let this fall through and fail */ + case CMD_IOCB_FCP_IBIDIR64_CR: /* bidirectional xfer */ + case CMD_FCP_TSEND64_CX: /* Target mode send xfer-ready */ + case CMD_FCP_TRSP64_CX: /* Target mode rcv */ + case CMD_FCP_AUTO_TRSP_CX: /* Auto target rsp */ + default: + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "2014 Invalid command 0x%x\n", + iocbq->iocb.ulpCommand); + return IOCB_ERROR; + break; + + } + bf_set(lpfc_wqe_gen_xri, &wqe->generic, xritag); + bf_set(lpfc_wqe_gen_request_tag, &wqe->generic, iocbq->iotag); + wqe->generic.abort_tag = abort_tag; + bf_set(lpfc_wqe_gen_cmd_type, &wqe->generic, command_type); + bf_set(lpfc_wqe_gen_command, &wqe->generic, cmnd); + bf_set(lpfc_wqe_gen_class, &wqe->generic, iocbq->iocb.ulpClass); + bf_set(lpfc_wqe_gen_cq_id, &wqe->generic, LPFC_WQE_CQ_ID_DEFAULT); + + return 0; +} + +/** + * __lpfc_sli_issue_iocb_s4 - SLI4 device lockless ver of lpfc_sli_issue_iocb + * @phba: Pointer to HBA context object. + * @ring_number: SLI ring number to issue iocb on. + * @piocb: Pointer to command iocb. + * @flag: Flag indicating if this command can be put into txq. + * + * __lpfc_sli_issue_iocb_s4 is used by other functions in the driver to issue + * an iocb command to an HBA with SLI-4 interface spec. + * + * This function is called with hbalock held. The function will return success + * after it successfully submit the iocb to firmware or after adding to the + * txq. + **/ +static int +__lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number, + struct lpfc_iocbq *piocb, uint32_t flag) +{ + struct lpfc_sglq *sglq; + uint16_t xritag; + union lpfc_wqe wqe; + struct lpfc_sli_ring *pring = &phba->sli.ring[ring_number]; + uint32_t fcp_wqidx; + + if (piocb->sli4_xritag == NO_XRI) { + if (piocb->iocb.ulpCommand == CMD_ABORT_XRI_CN || + piocb->iocb.ulpCommand == CMD_CLOSE_XRI_CN) + sglq = NULL; + else { + sglq = __lpfc_sli_get_sglq(phba); + if (!sglq) + return IOCB_ERROR; + piocb->sli4_xritag = sglq->sli4_xritag; + } + } else if (piocb->iocb_flag & LPFC_IO_FCP) { + sglq = NULL; /* These IO's already have an XRI and + * a mapped sgl. + */ + } else { + /* This is a continuation of a commandi,(CX) so this + * sglq is on the active list + */ + sglq = __lpfc_get_active_sglq(phba, piocb->sli4_xritag); + if (!sglq) + return IOCB_ERROR; + } + + if (sglq) { + xritag = lpfc_sli4_bpl2sgl(phba, piocb, sglq); + if (xritag != sglq->sli4_xritag) + return IOCB_ERROR; + } + + if (lpfc_sli4_iocb2wqe(phba, piocb, &wqe)) + return IOCB_ERROR; + + if (piocb->iocb_flag & LPFC_IO_FCP) { + fcp_wqidx = lpfc_sli4_scmd_to_wqidx_distr(phba, piocb); + if (lpfc_sli4_wq_put(phba->sli4_hba.fcp_wq[fcp_wqidx], &wqe)) + return IOCB_ERROR; + } else { + if (lpfc_sli4_wq_put(phba->sli4_hba.els_wq, &wqe)) + return IOCB_ERROR; + } + lpfc_sli_ringtxcmpl_put(phba, pring, piocb); + + return 0; +} + +/** + * __lpfc_sli_issue_iocb - Wrapper func of lockless version for issuing iocb + * + * This routine wraps the actual lockless version for issusing IOCB function + * pointer from the lpfc_hba struct. + * + * Return codes: + * IOCB_ERROR - Error + * IOCB_SUCCESS - Success + * IOCB_BUSY - Busy + **/ +static inline int +__lpfc_sli_issue_iocb(struct lpfc_hba *phba, uint32_t ring_number, + struct lpfc_iocbq *piocb, uint32_t flag) +{ + return phba->__lpfc_sli_issue_iocb(phba, ring_number, piocb, flag); +} + +/** + * lpfc_sli_api_table_setup - Set up sli api fucntion jump table + * @phba: The hba struct for which this call is being executed. + * @dev_grp: The HBA PCI-Device group number. + * + * This routine sets up the SLI interface API function jump table in @phba + * struct. + * Returns: 0 - success, -ENODEV - failure. + **/ +int +lpfc_sli_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp) +{ + + switch (dev_grp) { + case LPFC_PCI_DEV_LP: + phba->__lpfc_sli_issue_iocb = __lpfc_sli_issue_iocb_s3; + phba->__lpfc_sli_release_iocbq = __lpfc_sli_release_iocbq_s3; + break; + case LPFC_PCI_DEV_OC: + phba->__lpfc_sli_issue_iocb = __lpfc_sli_issue_iocb_s4; + phba->__lpfc_sli_release_iocbq = __lpfc_sli_release_iocbq_s4; + break; + default: + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "1419 Invalid HBA PCI-device group: 0x%x\n", + dev_grp); + return -ENODEV; + break; + } + phba->lpfc_get_iocb_from_iocbq = lpfc_get_iocb_from_iocbq; + return 0; +} /** * lpfc_sli_issue_iocb - Wrapper function for __lpfc_sli_issue_iocb @@ -3848,14 +6233,14 @@ __lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, * functions which do not hold hbalock. **/ int -lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, +lpfc_sli_issue_iocb(struct lpfc_hba *phba, uint32_t ring_number, struct lpfc_iocbq *piocb, uint32_t flag) { unsigned long iflags; int rc; spin_lock_irqsave(&phba->hbalock, iflags); - rc = __lpfc_sli_issue_iocb(phba, pring, piocb, flag); + rc = __lpfc_sli_issue_iocb(phba, ring_number, piocb, flag); spin_unlock_irqrestore(&phba->hbalock, iflags); return rc; @@ -4147,6 +6532,52 @@ lpfc_sli_queue_setup(struct lpfc_hba *phba) return 1; } +/** + * lpfc_sli_mbox_sys_flush - Flush mailbox command sub-system + * @phba: Pointer to HBA context object. + * + * This routine flushes the mailbox command subsystem. It will unconditionally + * flush all the mailbox commands in the three possible stages in the mailbox + * command sub-system: pending mailbox command queue; the outstanding mailbox + * command; and completed mailbox command queue. It is caller's responsibility + * to make sure that the driver is in the proper state to flush the mailbox + * command sub-system. Namely, the posting of mailbox commands into the + * pending mailbox command queue from the various clients must be stopped; + * either the HBA is in a state that it will never works on the outstanding + * mailbox command (such as in EEH or ERATT conditions) or the outstanding + * mailbox command has been completed. + **/ +static void +lpfc_sli_mbox_sys_flush(struct lpfc_hba *phba) +{ + LIST_HEAD(completions); + struct lpfc_sli *psli = &phba->sli; + LPFC_MBOXQ_t *pmb; + unsigned long iflag; + + /* Flush all the mailbox commands in the mbox system */ + spin_lock_irqsave(&phba->hbalock, iflag); + /* The pending mailbox command queue */ + list_splice_init(&phba->sli.mboxq, &completions); + /* The outstanding active mailbox command */ + if (psli->mbox_active) { + list_add_tail(&psli->mbox_active->list, &completions); + psli->mbox_active = NULL; + psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; + } + /* The completed mailbox command queue */ + list_splice_init(&phba->sli.mboxq_cmpl, &completions); + spin_unlock_irqrestore(&phba->hbalock, iflag); + + /* Return all flushed mailbox commands with MBX_NOT_FINISHED status */ + while (!list_empty(&completions)) { + list_remove_head(&completions, pmb, LPFC_MBOXQ_t, list); + pmb->u.mb.mbxStatus = MBX_NOT_FINISHED; + if (pmb->mbox_cmpl) + pmb->mbox_cmpl(phba, pmb); + } +} + /** * lpfc_sli_host_down - Vport cleanup function * @vport: Pointer to virtual port object. @@ -4240,9 +6671,11 @@ lpfc_sli_hba_down(struct lpfc_hba *phba) struct lpfc_sli *psli = &phba->sli; struct lpfc_sli_ring *pring; struct lpfc_dmabuf *buf_ptr; - LPFC_MBOXQ_t *pmb; - int i; unsigned long flags = 0; + int i; + + /* Shutdown the mailbox command sub-system */ + lpfc_sli_mbox_sys_shutdown(phba); lpfc_hba_down_prep(phba); @@ -4287,28 +6720,42 @@ lpfc_sli_hba_down(struct lpfc_hba *phba) /* Return any active mbox cmds */ del_timer_sync(&psli->mbox_tmo); - spin_lock_irqsave(&phba->hbalock, flags); - spin_lock(&phba->pport->work_port_lock); + spin_lock_irqsave(&phba->pport->work_port_lock, flags); phba->pport->work_port_events &= ~WORKER_MBOX_TMO; - spin_unlock(&phba->pport->work_port_lock); + spin_unlock_irqrestore(&phba->pport->work_port_lock, flags); - /* Return any pending or completed mbox cmds */ - list_splice_init(&phba->sli.mboxq, &completions); - if (psli->mbox_active) { - list_add_tail(&psli->mbox_active->list, &completions); - psli->mbox_active = NULL; - psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; - } - list_splice_init(&phba->sli.mboxq_cmpl, &completions); - spin_unlock_irqrestore(&phba->hbalock, flags); + return 1; +} + +/** + * lpfc_sli4_hba_down - PCI function resource cleanup for the SLI4 HBA + * @phba: Pointer to HBA context object. + * + * This function cleans up all queues, iocb, buffers, mailbox commands while + * shutting down the SLI4 HBA FCoE function. This function is called with no + * lock held and always returns 1. + * + * This function does the following to cleanup driver FCoE function resources: + * - Free discovery resources for each virtual port + * - Cleanup any pending fabric iocbs + * - Iterate through the iocb txq and free each entry in the list. + * - Free up any buffer posted to the HBA. + * - Clean up all the queue entries: WQ, RQ, MQ, EQ, CQ, etc. + * - Free mailbox commands in the mailbox queue. + **/ +int +lpfc_sli4_hba_down(struct lpfc_hba *phba) +{ + /* Stop the SLI4 device port */ + lpfc_stop_port(phba); + + /* Tear down the queues in the HBA */ + lpfc_sli4_queue_unset(phba); + + /* unregister default FCFI from the HBA */ + lpfc_sli4_fcfi_unreg(phba, phba->fcf.fcfi); - while (!list_empty(&completions)) { - list_remove_head(&completions, pmb, LPFC_MBOXQ_t, list); - pmb->mb.mbxStatus = MBX_NOT_FINISHED; - if (pmb->mbox_cmpl) - pmb->mbox_cmpl(phba,pmb); - } return 1; } @@ -4639,7 +7086,10 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, iabt = &abtsiocbp->iocb; iabt->un.acxri.abortType = ABORT_TYPE_ABTS; iabt->un.acxri.abortContextTag = icmd->ulpContext; - iabt->un.acxri.abortIoTag = icmd->ulpIoTag; + if (phba->sli_rev == LPFC_SLI_REV4) + iabt->un.acxri.abortIoTag = cmdiocb->sli4_xritag; + else + iabt->un.acxri.abortIoTag = icmd->ulpIoTag; iabt->ulpLe = 1; iabt->ulpClass = icmd->ulpClass; @@ -4655,7 +7105,7 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, "abort cmd iotag x%x\n", iabt->un.acxri.abortContextTag, iabt->un.acxri.abortIoTag, abtsiocbp->iotag); - retval = __lpfc_sli_issue_iocb(phba, pring, abtsiocbp, 0); + retval = __lpfc_sli_issue_iocb(phba, pring->ringno, abtsiocbp, 0); if (retval) __lpfc_sli_release_iocbq(phba, abtsiocbp); @@ -4838,7 +7288,10 @@ lpfc_sli_abort_iocb(struct lpfc_vport *vport, struct lpfc_sli_ring *pring, cmd = &iocbq->iocb; abtsiocb->iocb.un.acxri.abortType = ABORT_TYPE_ABTS; abtsiocb->iocb.un.acxri.abortContextTag = cmd->ulpContext; - abtsiocb->iocb.un.acxri.abortIoTag = cmd->ulpIoTag; + if (phba->sli_rev == LPFC_SLI_REV4) + abtsiocb->iocb.un.acxri.abortIoTag = iocbq->sli4_xritag; + else + abtsiocb->iocb.un.acxri.abortIoTag = cmd->ulpIoTag; abtsiocb->iocb.ulpLe = 1; abtsiocb->iocb.ulpClass = cmd->ulpClass; abtsiocb->vport = phba->pport; @@ -4850,7 +7303,8 @@ lpfc_sli_abort_iocb(struct lpfc_vport *vport, struct lpfc_sli_ring *pring, /* Setup callback routine and issue the command. */ abtsiocb->iocb_cmpl = lpfc_sli_abort_fcp_cmpl; - ret_val = lpfc_sli_issue_iocb(phba, pring, abtsiocb, 0); + ret_val = lpfc_sli_issue_iocb(phba, pring->ringno, + abtsiocb, 0); if (ret_val == IOCB_ERROR) { lpfc_sli_release_iocbq(phba, abtsiocb); errcnt++; @@ -4899,6 +7353,32 @@ lpfc_sli_wake_iocb_wait(struct lpfc_hba *phba, return; } +/** + * lpfc_chk_iocb_flg - Test IOCB flag with lock held. + * @phba: Pointer to HBA context object.. + * @piocbq: Pointer to command iocb. + * @flag: Flag to test. + * + * This routine grabs the hbalock and then test the iocb_flag to + * see if the passed in flag is set. + * Returns: + * 1 if flag is set. + * 0 if flag is not set. + **/ +static int +lpfc_chk_iocb_flg(struct lpfc_hba *phba, + struct lpfc_iocbq *piocbq, uint32_t flag) +{ + unsigned long iflags; + int ret; + + spin_lock_irqsave(&phba->hbalock, iflags); + ret = piocbq->iocb_flag & flag; + spin_unlock_irqrestore(&phba->hbalock, iflags); + return ret; + +} + /** * lpfc_sli_issue_iocb_wait - Synchronous function to issue iocb commands * @phba: Pointer to HBA context object.. @@ -4931,7 +7411,7 @@ lpfc_sli_wake_iocb_wait(struct lpfc_hba *phba, **/ int lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba, - struct lpfc_sli_ring *pring, + uint32_t ring_number, struct lpfc_iocbq *piocb, struct lpfc_iocbq *prspiocbq, uint32_t timeout) @@ -4962,11 +7442,11 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba, readl(phba->HCregaddr); /* flush */ } - retval = lpfc_sli_issue_iocb(phba, pring, piocb, 0); + retval = lpfc_sli_issue_iocb(phba, ring_number, piocb, 0); if (retval == IOCB_SUCCESS) { timeout_req = timeout * HZ; timeleft = wait_event_timeout(done_q, - piocb->iocb_flag & LPFC_IO_WAKE, + lpfc_chk_iocb_flg(phba, piocb, LPFC_IO_WAKE), timeout_req); if (piocb->iocb_flag & LPFC_IO_WAKE) { @@ -5077,53 +7557,150 @@ lpfc_sli_issue_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq, } /** - * lpfc_sli_flush_mbox_queue - mailbox queue cleanup function + * lpfc_sli_mbox_sys_shutdown - shutdown mailbox command sub-system * @phba: Pointer to HBA context. * - * This function is called to cleanup any pending mailbox - * objects in the driver queue before bringing the HBA offline. - * This function is called while resetting the HBA. - * The function is called without any lock held. The function - * takes hbalock to update SLI data structure. - * This function returns 1 when there is an active mailbox - * command pending else returns 0. + * This function is called to shutdown the driver's mailbox sub-system. + * It first marks the mailbox sub-system is in a block state to prevent + * the asynchronous mailbox command from issued off the pending mailbox + * command queue. If the mailbox command sub-system shutdown is due to + * HBA error conditions such as EEH or ERATT, this routine shall invoke + * the mailbox sub-system flush routine to forcefully bring down the + * mailbox sub-system. Otherwise, if it is due to normal condition (such + * as with offline or HBA function reset), this routine will wait for the + * outstanding mailbox command to complete before invoking the mailbox + * sub-system flush routine to gracefully bring down mailbox sub-system. **/ -int -lpfc_sli_flush_mbox_queue(struct lpfc_hba * phba) +void +lpfc_sli_mbox_sys_shutdown(struct lpfc_hba *phba) +{ + struct lpfc_sli *psli = &phba->sli; + uint8_t actcmd = MBX_HEARTBEAT; + unsigned long timeout; + + spin_lock_irq(&phba->hbalock); + psli->sli_flag |= LPFC_SLI_ASYNC_MBX_BLK; + spin_unlock_irq(&phba->hbalock); + + if (psli->sli_flag & LPFC_SLI_ACTIVE) { + spin_lock_irq(&phba->hbalock); + if (phba->sli.mbox_active) + actcmd = phba->sli.mbox_active->u.mb.mbxCommand; + spin_unlock_irq(&phba->hbalock); + /* Determine how long we might wait for the active mailbox + * command to be gracefully completed by firmware. + */ + timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba, actcmd) * + 1000) + jiffies; + while (phba->sli.mbox_active) { + /* Check active mailbox complete status every 2ms */ + msleep(2); + if (time_after(jiffies, timeout)) + /* Timeout, let the mailbox flush routine to + * forcefully release active mailbox command + */ + break; + } + } + lpfc_sli_mbox_sys_flush(phba); +} + +/** + * lpfc_sli_eratt_read - read sli-3 error attention events + * @phba: Pointer to HBA context. + * + * This function is called to read the SLI3 device error attention registers + * for possible error attention events. The caller must hold the hostlock + * with spin_lock_irq(). + * + * This fucntion returns 1 when there is Error Attention in the Host Attention + * Register and returns 0 otherwise. + **/ +static int +lpfc_sli_eratt_read(struct lpfc_hba *phba) { - struct lpfc_vport *vport = phba->pport; - int i = 0; uint32_t ha_copy; - while (phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE && !vport->stopped) { - if (i++ > LPFC_MBOX_TMO * 1000) - return 1; + /* Read chip Host Attention (HA) register */ + ha_copy = readl(phba->HAregaddr); + if (ha_copy & HA_ERATT) { + /* Read host status register to retrieve error event */ + lpfc_sli_read_hs(phba); - /* - * Call lpfc_sli_handle_mb_event only if a mailbox cmd - * did finish. This way we won't get the misleading - * "Stray Mailbox Interrupt" message. - */ - spin_lock_irq(&phba->hbalock); - ha_copy = phba->work_ha; - phba->work_ha &= ~HA_MBATT; - spin_unlock_irq(&phba->hbalock); + /* Check if there is a deferred error condition is active */ + if ((HS_FFER1 & phba->work_hs) && + ((HS_FFER2 | HS_FFER3 | HS_FFER4 | HS_FFER5 | + HS_FFER6 | HS_FFER7) & phba->work_hs)) { + phba->hba_flag |= DEFER_ERATT; + /* Clear all interrupt enable conditions */ + writel(0, phba->HCregaddr); + readl(phba->HCregaddr); + } - if (ha_copy & HA_MBATT) - if (lpfc_sli_handle_mb_event(phba) == 0) - i = 0; - - msleep(1); + /* Set the driver HA work bitmap */ + phba->work_ha |= HA_ERATT; + /* Indicate polling handles this ERATT */ + phba->hba_flag |= HBA_ERATT_HANDLED; + return 1; } + return 0; +} - return (phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE) ? 1 : 0; +/** + * lpfc_sli4_eratt_read - read sli-4 error attention events + * @phba: Pointer to HBA context. + * + * This function is called to read the SLI4 device error attention registers + * for possible error attention events. The caller must hold the hostlock + * with spin_lock_irq(). + * + * This fucntion returns 1 when there is Error Attention in the Host Attention + * Register and returns 0 otherwise. + **/ +static int +lpfc_sli4_eratt_read(struct lpfc_hba *phba) +{ + uint32_t uerr_sta_hi, uerr_sta_lo; + uint32_t onlnreg0, onlnreg1; + + /* For now, use the SLI4 device internal unrecoverable error + * registers for error attention. This can be changed later. + */ + onlnreg0 = readl(phba->sli4_hba.ONLINE0regaddr); + onlnreg1 = readl(phba->sli4_hba.ONLINE1regaddr); + if ((onlnreg0 != LPFC_ONLINE_NERR) || (onlnreg1 != LPFC_ONLINE_NERR)) { + uerr_sta_lo = readl(phba->sli4_hba.UERRLOregaddr); + uerr_sta_hi = readl(phba->sli4_hba.UERRHIregaddr); + if (uerr_sta_lo || uerr_sta_hi) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "1423 HBA Unrecoverable error: " + "uerr_lo_reg=0x%x, uerr_hi_reg=0x%x, " + "online0_reg=0x%x, online1_reg=0x%x\n", + uerr_sta_lo, uerr_sta_hi, + onlnreg0, onlnreg1); + /* TEMP: as the driver error recover logic is not + * fully developed, we just log the error message + * and the device error attention action is now + * temporarily disabled. + */ + return 0; + phba->work_status[0] = uerr_sta_lo; + phba->work_status[1] = uerr_sta_hi; + /* Set the driver HA work bitmap */ + phba->work_ha |= HA_ERATT; + /* Indicate polling handles this ERATT */ + phba->hba_flag |= HBA_ERATT_HANDLED; + return 1; + } + } + return 0; } /** * lpfc_sli_check_eratt - check error attention events * @phba: Pointer to HBA context. * - * This function is called form timer soft interrupt context to check HBA's + * This function is called from timer soft interrupt context to check HBA's * error attention register bit for error attention events. * * This fucntion returns 1 when there is Error Attention in the Host Attention @@ -5134,10 +7711,6 @@ lpfc_sli_check_eratt(struct lpfc_hba *phba) { uint32_t ha_copy; - /* If PCI channel is offline, don't process it */ - if (unlikely(pci_channel_offline(phba->pcidev))) - return 0; - /* If somebody is waiting to handle an eratt, don't process it * here. The brdkill function will do this. */ @@ -5161,56 +7734,84 @@ lpfc_sli_check_eratt(struct lpfc_hba *phba) return 0; } - /* Read chip Host Attention (HA) register */ - ha_copy = readl(phba->HAregaddr); - if (ha_copy & HA_ERATT) { - /* Read host status register to retrieve error event */ - lpfc_sli_read_hs(phba); - - /* Check if there is a deferred error condition is active */ - if ((HS_FFER1 & phba->work_hs) && - ((HS_FFER2 | HS_FFER3 | HS_FFER4 | HS_FFER5 | - HS_FFER6 | HS_FFER7) & phba->work_hs)) { - phba->hba_flag |= DEFER_ERATT; - /* Clear all interrupt enable conditions */ - writel(0, phba->HCregaddr); - readl(phba->HCregaddr); - } - - /* Set the driver HA work bitmap */ - phba->work_ha |= HA_ERATT; - /* Indicate polling handles this ERATT */ - phba->hba_flag |= HBA_ERATT_HANDLED; + /* If PCI channel is offline, don't process it */ + if (unlikely(pci_channel_offline(phba->pcidev))) { spin_unlock_irq(&phba->hbalock); - return 1; + return 0; + } + + switch (phba->sli_rev) { + case LPFC_SLI_REV2: + case LPFC_SLI_REV3: + /* Read chip Host Attention (HA) register */ + ha_copy = lpfc_sli_eratt_read(phba); + break; + case LPFC_SLI_REV4: + /* Read devcie Uncoverable Error (UERR) registers */ + ha_copy = lpfc_sli4_eratt_read(phba); + break; + default: + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0299 Invalid SLI revision (%d)\n", + phba->sli_rev); + ha_copy = 0; + break; } spin_unlock_irq(&phba->hbalock); + + return ha_copy; +} + +/** + * lpfc_intr_state_check - Check device state for interrupt handling + * @phba: Pointer to HBA context. + * + * This inline routine checks whether a device or its PCI slot is in a state + * that the interrupt should be handled. + * + * This function returns 0 if the device or the PCI slot is in a state that + * interrupt should be handled, otherwise -EIO. + */ +static inline int +lpfc_intr_state_check(struct lpfc_hba *phba) +{ + /* If the pci channel is offline, ignore all the interrupts */ + if (unlikely(pci_channel_offline(phba->pcidev))) + return -EIO; + + /* Update device level interrupt statistics */ + phba->sli.slistat.sli_intr++; + + /* Ignore all interrupts during initialization. */ + if (unlikely(phba->link_state < LPFC_LINK_DOWN)) + return -EIO; + return 0; } /** - * lpfc_sp_intr_handler - The slow-path interrupt handler of lpfc driver + * lpfc_sli_sp_intr_handler - Slow-path interrupt handler to SLI-3 device * @irq: Interrupt number. * @dev_id: The device context pointer. * * This function is directly called from the PCI layer as an interrupt - * service routine when the device is enabled with MSI-X multi-message - * interrupt mode and there are slow-path events in the HBA. However, - * when the device is enabled with either MSI or Pin-IRQ interrupt mode, - * this function is called as part of the device-level interrupt handler. - * When the PCI slot is in error recovery or the HBA is undergoing - * initialization, the interrupt handler will not process the interrupt. - * The link attention and ELS ring attention events are handled by the - * worker thread. The interrupt handler signals the worker thread and - * and returns for these events. This function is called without any - * lock held. It gets the hbalock to access and update SLI data + * service routine when device with SLI-3 interface spec is enabled with + * MSI-X multi-message interrupt mode and there are slow-path events in + * the HBA. However, when the device is enabled with either MSI or Pin-IRQ + * interrupt mode, this function is called as part of the device-level + * interrupt handler. When the PCI slot is in error recovery or the HBA + * is undergoing initialization, the interrupt handler will not process + * the interrupt. The link attention and ELS ring attention events are + * handled by the worker thread. The interrupt handler signals the worker + * thread and returns for these events. This function is called without + * any lock held. It gets the hbalock to access and update SLI data * structures. * * This function returns IRQ_HANDLED when interrupt is handled else it * returns IRQ_NONE. **/ irqreturn_t -lpfc_sp_intr_handler(int irq, void *dev_id) +lpfc_sli_sp_intr_handler(int irq, void *dev_id) { struct lpfc_hba *phba; uint32_t ha_copy; @@ -5240,13 +7841,8 @@ lpfc_sp_intr_handler(int irq, void *dev_id) * individual interrupt handler in MSI-X multi-message interrupt mode */ if (phba->intr_type == MSIX) { - /* If the pci channel is offline, ignore all the interrupts */ - if (unlikely(pci_channel_offline(phba->pcidev))) - return IRQ_NONE; - /* Update device-level interrupt statistics */ - phba->sli.slistat.sli_intr++; - /* Ignore all interrupts during initialization. */ - if (unlikely(phba->link_state < LPFC_LINK_DOWN)) + /* Check device state for handling interrupt */ + if (lpfc_intr_state_check(phba)) return IRQ_NONE; /* Need to read HA REG for slow-path events */ spin_lock_irqsave(&phba->hbalock, iflag); @@ -5271,7 +7867,7 @@ lpfc_sp_intr_handler(int irq, void *dev_id) * interrupt. */ if (unlikely(phba->hba_flag & DEFER_ERATT)) { - spin_unlock_irq(&phba->hbalock); + spin_unlock_irqrestore(&phba->hbalock, iflag); return IRQ_NONE; } @@ -5364,7 +7960,7 @@ lpfc_sp_intr_handler(int irq, void *dev_id) if ((work_ha_copy & HA_MBATT) && (phba->sli.mbox_active)) { pmb = phba->sli.mbox_active; - pmbox = &pmb->mb; + pmbox = &pmb->u.mb; mbox = phba->mbox; vport = pmb->vport; @@ -5434,7 +8030,8 @@ lpfc_sp_intr_handler(int irq, void *dev_id) LOG_MBOX | LOG_SLI, "0350 rc should have" "been MBX_BUSY"); - goto send_current_mbox; + if (rc != MBX_NOT_FINISHED) + goto send_current_mbox; } } spin_lock_irqsave( @@ -5471,29 +8068,29 @@ send_current_mbox: } return IRQ_HANDLED; -} /* lpfc_sp_intr_handler */ +} /* lpfc_sli_sp_intr_handler */ /** - * lpfc_fp_intr_handler - The fast-path interrupt handler of lpfc driver + * lpfc_sli_fp_intr_handler - Fast-path interrupt handler to SLI-3 device. * @irq: Interrupt number. * @dev_id: The device context pointer. * * This function is directly called from the PCI layer as an interrupt - * service routine when the device is enabled with MSI-X multi-message - * interrupt mode and there is a fast-path FCP IOCB ring event in the - * HBA. However, when the device is enabled with either MSI or Pin-IRQ - * interrupt mode, this function is called as part of the device-level - * interrupt handler. When the PCI slot is in error recovery or the HBA - * is undergoing initialization, the interrupt handler will not process - * the interrupt. The SCSI FCP fast-path ring event are handled in the - * intrrupt context. This function is called without any lock held. It - * gets the hbalock to access and update SLI data structures. + * service routine when device with SLI-3 interface spec is enabled with + * MSI-X multi-message interrupt mode and there is a fast-path FCP IOCB + * ring event in the HBA. However, when the device is enabled with either + * MSI or Pin-IRQ interrupt mode, this function is called as part of the + * device-level interrupt handler. When the PCI slot is in error recovery + * or the HBA is undergoing initialization, the interrupt handler will not + * process the interrupt. The SCSI FCP fast-path ring event are handled in + * the intrrupt context. This function is called without any lock held. + * It gets the hbalock to access and update SLI data structures. * * This function returns IRQ_HANDLED when interrupt is handled else it * returns IRQ_NONE. **/ irqreturn_t -lpfc_fp_intr_handler(int irq, void *dev_id) +lpfc_sli_fp_intr_handler(int irq, void *dev_id) { struct lpfc_hba *phba; uint32_t ha_copy; @@ -5513,13 +8110,8 @@ lpfc_fp_intr_handler(int irq, void *dev_id) * individual interrupt handler in MSI-X multi-message interrupt mode */ if (phba->intr_type == MSIX) { - /* If pci channel is offline, ignore all the interrupts */ - if (unlikely(pci_channel_offline(phba->pcidev))) - return IRQ_NONE; - /* Update device-level interrupt statistics */ - phba->sli.slistat.sli_intr++; - /* Ignore all interrupts during initialization. */ - if (unlikely(phba->link_state < LPFC_LINK_DOWN)) + /* Check device state for handling interrupt */ + if (lpfc_intr_state_check(phba)) return IRQ_NONE; /* Need to read HA REG for FCP ring and other ring events */ ha_copy = readl(phba->HAregaddr); @@ -5530,7 +8122,7 @@ lpfc_fp_intr_handler(int irq, void *dev_id) * any interrupt. */ if (unlikely(phba->hba_flag & DEFER_ERATT)) { - spin_unlock_irq(&phba->hbalock); + spin_unlock_irqrestore(&phba->hbalock, iflag); return IRQ_NONE; } writel((ha_copy & (HA_R0_CLR_MSK | HA_R1_CLR_MSK)), @@ -5566,26 +8158,27 @@ lpfc_fp_intr_handler(int irq, void *dev_id) } } return IRQ_HANDLED; -} /* lpfc_fp_intr_handler */ +} /* lpfc_sli_fp_intr_handler */ /** - * lpfc_intr_handler - The device-level interrupt handler of lpfc driver + * lpfc_sli_intr_handler - Device-level interrupt handler to SLI-3 device * @irq: Interrupt number. * @dev_id: The device context pointer. * - * This function is the device-level interrupt handler called from the PCI - * layer when either MSI or Pin-IRQ interrupt mode is enabled and there is - * an event in the HBA which requires driver attention. This function - * invokes the slow-path interrupt attention handling function and fast-path - * interrupt attention handling function in turn to process the relevant - * HBA attention events. This function is called without any lock held. It - * gets the hbalock to access and update SLI data structures. + * This function is the HBA device-level interrupt handler to device with + * SLI-3 interface spec, called from the PCI layer when either MSI or + * Pin-IRQ interrupt mode is enabled and there is an event in the HBA which + * requires driver attention. This function invokes the slow-path interrupt + * attention handling function and fast-path interrupt attention handling + * function in turn to process the relevant HBA attention events. This + * function is called without any lock held. It gets the hbalock to access + * and update SLI data structures. * * This function returns IRQ_HANDLED when interrupt is handled, else it * returns IRQ_NONE. **/ irqreturn_t -lpfc_intr_handler(int irq, void *dev_id) +lpfc_sli_intr_handler(int irq, void *dev_id) { struct lpfc_hba *phba; irqreturn_t sp_irq_rc, fp_irq_rc; @@ -5600,15 +8193,8 @@ lpfc_intr_handler(int irq, void *dev_id) if (unlikely(!phba)) return IRQ_NONE; - /* If the pci channel is offline, ignore all the interrupts. */ - if (unlikely(pci_channel_offline(phba->pcidev))) - return IRQ_NONE; - - /* Update device level interrupt statistics */ - phba->sli.slistat.sli_intr++; - - /* Ignore all interrupts during initialization. */ - if (unlikely(phba->link_state < LPFC_LINK_DOWN)) + /* Check device state for handling interrupt */ + if (lpfc_intr_state_check(phba)) return IRQ_NONE; spin_lock(&phba->hbalock); @@ -5650,7 +8236,7 @@ lpfc_intr_handler(int irq, void *dev_id) status2 >>= (4*LPFC_ELS_RING); if (status1 || (status2 & HA_RXMASK)) - sp_irq_rc = lpfc_sp_intr_handler(irq, dev_id); + sp_irq_rc = lpfc_sli_sp_intr_handler(irq, dev_id); else sp_irq_rc = IRQ_NONE; @@ -5670,10 +8256,3321 @@ lpfc_intr_handler(int irq, void *dev_id) status2 = 0; if ((status1 & HA_RXMASK) || (status2 & HA_RXMASK)) - fp_irq_rc = lpfc_fp_intr_handler(irq, dev_id); + fp_irq_rc = lpfc_sli_fp_intr_handler(irq, dev_id); else fp_irq_rc = IRQ_NONE; /* Return device-level interrupt handling status */ return (sp_irq_rc == IRQ_HANDLED) ? sp_irq_rc : fp_irq_rc; -} /* lpfc_intr_handler */ +} /* lpfc_sli_intr_handler */ + +/** + * lpfc_sli4_fcp_xri_abort_event_proc - Process fcp xri abort event + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked by the worker thread to process all the pending + * SLI4 FCP abort XRI events. + **/ +void lpfc_sli4_fcp_xri_abort_event_proc(struct lpfc_hba *phba) +{ + struct lpfc_cq_event *cq_event; + + /* First, declare the fcp xri abort event has been handled */ + spin_lock_irq(&phba->hbalock); + phba->hba_flag &= ~FCP_XRI_ABORT_EVENT; + spin_unlock_irq(&phba->hbalock); + /* Now, handle all the fcp xri abort events */ + while (!list_empty(&phba->sli4_hba.sp_fcp_xri_aborted_work_queue)) { + /* Get the first event from the head of the event queue */ + spin_lock_irq(&phba->hbalock); + list_remove_head(&phba->sli4_hba.sp_fcp_xri_aborted_work_queue, + cq_event, struct lpfc_cq_event, list); + spin_unlock_irq(&phba->hbalock); + /* Notify aborted XRI for FCP work queue */ + lpfc_sli4_fcp_xri_aborted(phba, &cq_event->cqe.wcqe_axri); + /* Free the event processed back to the free pool */ + lpfc_sli4_cq_event_release(phba, cq_event); + } +} + +/** + * lpfc_sli4_els_xri_abort_event_proc - Process els xri abort event + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked by the worker thread to process all the pending + * SLI4 els abort xri events. + **/ +void lpfc_sli4_els_xri_abort_event_proc(struct lpfc_hba *phba) +{ + struct lpfc_cq_event *cq_event; + + /* First, declare the els xri abort event has been handled */ + spin_lock_irq(&phba->hbalock); + phba->hba_flag &= ~ELS_XRI_ABORT_EVENT; + spin_unlock_irq(&phba->hbalock); + /* Now, handle all the els xri abort events */ + while (!list_empty(&phba->sli4_hba.sp_els_xri_aborted_work_queue)) { + /* Get the first event from the head of the event queue */ + spin_lock_irq(&phba->hbalock); + list_remove_head(&phba->sli4_hba.sp_els_xri_aborted_work_queue, + cq_event, struct lpfc_cq_event, list); + spin_unlock_irq(&phba->hbalock); + /* Notify aborted XRI for ELS work queue */ + lpfc_sli4_els_xri_aborted(phba, &cq_event->cqe.wcqe_axri); + /* Free the event processed back to the free pool */ + lpfc_sli4_cq_event_release(phba, cq_event); + } +} + +static void +lpfc_sli4_iocb_param_transfer(struct lpfc_iocbq *pIocbIn, + struct lpfc_iocbq *pIocbOut, + struct lpfc_wcqe_complete *wcqe) +{ + size_t offset = offsetof(struct lpfc_iocbq, iocb); + + memcpy((char *)pIocbIn + offset, (char *)pIocbOut + offset, + sizeof(struct lpfc_iocbq) - offset); + memset(&pIocbIn->sli4_info, 0, + sizeof(struct lpfc_sli4_rspiocb_info)); + /* Map WCQE parameters into irspiocb parameters */ + pIocbIn->iocb.ulpStatus = bf_get(lpfc_wcqe_c_status, wcqe); + if (pIocbOut->iocb_flag & LPFC_IO_FCP) + if (pIocbIn->iocb.ulpStatus == IOSTAT_FCP_RSP_ERROR) + pIocbIn->iocb.un.fcpi.fcpi_parm = + pIocbOut->iocb.un.fcpi.fcpi_parm - + wcqe->total_data_placed; + else + pIocbIn->iocb.un.ulpWord[4] = wcqe->parameter; + else + pIocbIn->iocb.un.ulpWord[4] = wcqe->parameter; + /* Load in additional WCQE parameters */ + pIocbIn->sli4_info.hw_status = bf_get(lpfc_wcqe_c_hw_status, wcqe); + pIocbIn->sli4_info.bfield = 0; + if (bf_get(lpfc_wcqe_c_xb, wcqe)) + pIocbIn->sli4_info.bfield |= LPFC_XB; + if (bf_get(lpfc_wcqe_c_pv, wcqe)) { + pIocbIn->sli4_info.bfield |= LPFC_PV; + pIocbIn->sli4_info.priority = + bf_get(lpfc_wcqe_c_priority, wcqe); + } +} + +/** + * lpfc_sli4_sp_handle_async_event - Handle an asynchroous event + * @phba: Pointer to HBA context object. + * @cqe: Pointer to mailbox completion queue entry. + * + * This routine process a mailbox completion queue entry with asynchrous + * event. + * + * Return: true if work posted to worker thread, otherwise false. + **/ +static bool +lpfc_sli4_sp_handle_async_event(struct lpfc_hba *phba, struct lpfc_mcqe *mcqe) +{ + struct lpfc_cq_event *cq_event; + unsigned long iflags; + + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "0392 Async Event: word0:x%x, word1:x%x, " + "word2:x%x, word3:x%x\n", mcqe->word0, + mcqe->mcqe_tag0, mcqe->mcqe_tag1, mcqe->trailer); + + /* Allocate a new internal CQ_EVENT entry */ + cq_event = lpfc_sli4_cq_event_alloc(phba); + if (!cq_event) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "0394 Failed to allocate CQ_EVENT entry\n"); + return false; + } + + /* Move the CQE into an asynchronous event entry */ + memcpy(&cq_event->cqe, mcqe, sizeof(struct lpfc_mcqe)); + spin_lock_irqsave(&phba->hbalock, iflags); + list_add_tail(&cq_event->list, &phba->sli4_hba.sp_asynce_work_queue); + /* Set the async event flag */ + phba->hba_flag |= ASYNC_EVENT; + spin_unlock_irqrestore(&phba->hbalock, iflags); + + return true; +} + +/** + * lpfc_sli4_sp_handle_mbox_event - Handle a mailbox completion event + * @phba: Pointer to HBA context object. + * @cqe: Pointer to mailbox completion queue entry. + * + * This routine process a mailbox completion queue entry with mailbox + * completion event. + * + * Return: true if work posted to worker thread, otherwise false. + **/ +static bool +lpfc_sli4_sp_handle_mbox_event(struct lpfc_hba *phba, struct lpfc_mcqe *mcqe) +{ + uint32_t mcqe_status; + MAILBOX_t *mbox, *pmbox; + struct lpfc_mqe *mqe; + struct lpfc_vport *vport; + struct lpfc_nodelist *ndlp; + struct lpfc_dmabuf *mp; + unsigned long iflags; + LPFC_MBOXQ_t *pmb; + bool workposted = false; + int rc; + + /* If not a mailbox complete MCQE, out by checking mailbox consume */ + if (!bf_get(lpfc_trailer_completed, mcqe)) + goto out_no_mqe_complete; + + /* Get the reference to the active mbox command */ + spin_lock_irqsave(&phba->hbalock, iflags); + pmb = phba->sli.mbox_active; + if (unlikely(!pmb)) { + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, + "1832 No pending MBOX command to handle\n"); + spin_unlock_irqrestore(&phba->hbalock, iflags); + goto out_no_mqe_complete; + } + spin_unlock_irqrestore(&phba->hbalock, iflags); + mqe = &pmb->u.mqe; + pmbox = (MAILBOX_t *)&pmb->u.mqe; + mbox = phba->mbox; + vport = pmb->vport; + + /* Reset heartbeat timer */ + phba->last_completion_time = jiffies; + del_timer(&phba->sli.mbox_tmo); + + /* Move mbox data to caller's mailbox region, do endian swapping */ + if (pmb->mbox_cmpl && mbox) + lpfc_sli_pcimem_bcopy(mbox, mqe, sizeof(struct lpfc_mqe)); + /* Set the mailbox status with SLI4 range 0x4000 */ + mcqe_status = bf_get(lpfc_mcqe_status, mcqe); + if (mcqe_status != MB_CQE_STATUS_SUCCESS) + bf_set(lpfc_mqe_status, mqe, + (LPFC_MBX_ERROR_RANGE | mcqe_status)); + + if (pmb->mbox_flag & LPFC_MBX_IMED_UNREG) { + pmb->mbox_flag &= ~LPFC_MBX_IMED_UNREG; + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_MBOX_VPORT, + "MBOX dflt rpi: status:x%x rpi:x%x", + mcqe_status, + pmbox->un.varWords[0], 0); + if (mcqe_status == MB_CQE_STATUS_SUCCESS) { + mp = (struct lpfc_dmabuf *)(pmb->context1); + ndlp = (struct lpfc_nodelist *)pmb->context2; + /* Reg_LOGIN of dflt RPI was successful. Now lets get + * RID of the PPI using the same mbox buffer. + */ + lpfc_unreg_login(phba, vport->vpi, + pmbox->un.varWords[0], pmb); + pmb->mbox_cmpl = lpfc_mbx_cmpl_dflt_rpi; + pmb->context1 = mp; + pmb->context2 = ndlp; + pmb->vport = vport; + rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); + if (rc != MBX_BUSY) + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | + LOG_SLI, "0385 rc should " + "have been MBX_BUSY\n"); + if (rc != MBX_NOT_FINISHED) + goto send_current_mbox; + } + } + spin_lock_irqsave(&phba->pport->work_port_lock, iflags); + phba->pport->work_port_events &= ~WORKER_MBOX_TMO; + spin_unlock_irqrestore(&phba->pport->work_port_lock, iflags); + + /* There is mailbox completion work to do */ + spin_lock_irqsave(&phba->hbalock, iflags); + __lpfc_mbox_cmpl_put(phba, pmb); + phba->work_ha |= HA_MBATT; + spin_unlock_irqrestore(&phba->hbalock, iflags); + workposted = true; + +send_current_mbox: + spin_lock_irqsave(&phba->hbalock, iflags); + /* Release the mailbox command posting token */ + phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; + /* Setting active mailbox pointer need to be in sync to flag clear */ + phba->sli.mbox_active = NULL; + spin_unlock_irqrestore(&phba->hbalock, iflags); + /* Wake up worker thread to post the next pending mailbox command */ + lpfc_worker_wake_up(phba); +out_no_mqe_complete: + if (bf_get(lpfc_trailer_consumed, mcqe)) + lpfc_sli4_mq_release(phba->sli4_hba.mbx_wq); + return workposted; +} + +/** + * lpfc_sli4_sp_handle_mcqe - Process a mailbox completion queue entry + * @phba: Pointer to HBA context object. + * @cqe: Pointer to mailbox completion queue entry. + * + * This routine process a mailbox completion queue entry, it invokes the + * proper mailbox complete handling or asynchrous event handling routine + * according to the MCQE's async bit. + * + * Return: true if work posted to worker thread, otherwise false. + **/ +static bool +lpfc_sli4_sp_handle_mcqe(struct lpfc_hba *phba, struct lpfc_cqe *cqe) +{ + struct lpfc_mcqe mcqe; + bool workposted; + + /* Copy the mailbox MCQE and convert endian order as needed */ + lpfc_sli_pcimem_bcopy(cqe, &mcqe, sizeof(struct lpfc_mcqe)); + + /* Invoke the proper event handling routine */ + if (!bf_get(lpfc_trailer_async, &mcqe)) + workposted = lpfc_sli4_sp_handle_mbox_event(phba, &mcqe); + else + workposted = lpfc_sli4_sp_handle_async_event(phba, &mcqe); + return workposted; +} + +/** + * lpfc_sli4_sp_handle_els_wcqe - Handle els work-queue completion event + * @phba: Pointer to HBA context object. + * @wcqe: Pointer to work-queue completion queue entry. + * + * This routine handles an ELS work-queue completion event. + * + * Return: true if work posted to worker thread, otherwise false. + **/ +static bool +lpfc_sli4_sp_handle_els_wcqe(struct lpfc_hba *phba, + struct lpfc_wcqe_complete *wcqe) +{ + struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING]; + struct lpfc_iocbq *cmdiocbq; + struct lpfc_iocbq *irspiocbq; + unsigned long iflags; + bool workposted = false; + + spin_lock_irqsave(&phba->hbalock, iflags); + pring->stats.iocb_event++; + /* Look up the ELS command IOCB and create pseudo response IOCB */ + cmdiocbq = lpfc_sli_iocbq_lookup_by_tag(phba, pring, + bf_get(lpfc_wcqe_c_request_tag, wcqe)); + spin_unlock_irqrestore(&phba->hbalock, iflags); + + if (unlikely(!cmdiocbq)) { + lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, + "0386 ELS complete with no corresponding " + "cmdiocb: iotag (%d)\n", + bf_get(lpfc_wcqe_c_request_tag, wcqe)); + return workposted; + } + + /* Fake the irspiocbq and copy necessary response information */ + irspiocbq = lpfc_sli_get_iocbq(phba); + if (!irspiocbq) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "0387 Failed to allocate an iocbq\n"); + return workposted; + } + lpfc_sli4_iocb_param_transfer(irspiocbq, cmdiocbq, wcqe); + + /* Add the irspiocb to the response IOCB work list */ + spin_lock_irqsave(&phba->hbalock, iflags); + list_add_tail(&irspiocbq->list, &phba->sli4_hba.sp_rspiocb_work_queue); + /* Indicate ELS ring attention */ + phba->work_ha |= (HA_R0ATT << (4*LPFC_ELS_RING)); + spin_unlock_irqrestore(&phba->hbalock, iflags); + workposted = true; + + return workposted; +} + +/** + * lpfc_sli4_sp_handle_rel_wcqe - Handle slow-path WQ entry consumed event + * @phba: Pointer to HBA context object. + * @wcqe: Pointer to work-queue completion queue entry. + * + * This routine handles slow-path WQ entry comsumed event by invoking the + * proper WQ release routine to the slow-path WQ. + **/ +static void +lpfc_sli4_sp_handle_rel_wcqe(struct lpfc_hba *phba, + struct lpfc_wcqe_release *wcqe) +{ + /* Check for the slow-path ELS work queue */ + if (bf_get(lpfc_wcqe_r_wq_id, wcqe) == phba->sli4_hba.els_wq->queue_id) + lpfc_sli4_wq_release(phba->sli4_hba.els_wq, + bf_get(lpfc_wcqe_r_wqe_index, wcqe)); + else + lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, + "2579 Slow-path wqe consume event carries " + "miss-matched qid: wcqe-qid=x%x, sp-qid=x%x\n", + bf_get(lpfc_wcqe_r_wqe_index, wcqe), + phba->sli4_hba.els_wq->queue_id); +} + +/** + * lpfc_sli4_sp_handle_abort_xri_wcqe - Handle a xri abort event + * @phba: Pointer to HBA context object. + * @cq: Pointer to a WQ completion queue. + * @wcqe: Pointer to work-queue completion queue entry. + * + * This routine handles an XRI abort event. + * + * Return: true if work posted to worker thread, otherwise false. + **/ +static bool +lpfc_sli4_sp_handle_abort_xri_wcqe(struct lpfc_hba *phba, + struct lpfc_queue *cq, + struct sli4_wcqe_xri_aborted *wcqe) +{ + bool workposted = false; + struct lpfc_cq_event *cq_event; + unsigned long iflags; + + /* Allocate a new internal CQ_EVENT entry */ + cq_event = lpfc_sli4_cq_event_alloc(phba); + if (!cq_event) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "0602 Failed to allocate CQ_EVENT entry\n"); + return false; + } + + /* Move the CQE into the proper xri abort event list */ + memcpy(&cq_event->cqe, wcqe, sizeof(struct sli4_wcqe_xri_aborted)); + switch (cq->subtype) { + case LPFC_FCP: + spin_lock_irqsave(&phba->hbalock, iflags); + list_add_tail(&cq_event->list, + &phba->sli4_hba.sp_fcp_xri_aborted_work_queue); + /* Set the fcp xri abort event flag */ + phba->hba_flag |= FCP_XRI_ABORT_EVENT; + spin_unlock_irqrestore(&phba->hbalock, iflags); + workposted = true; + break; + case LPFC_ELS: + spin_lock_irqsave(&phba->hbalock, iflags); + list_add_tail(&cq_event->list, + &phba->sli4_hba.sp_els_xri_aborted_work_queue); + /* Set the els xri abort event flag */ + phba->hba_flag |= ELS_XRI_ABORT_EVENT; + spin_unlock_irqrestore(&phba->hbalock, iflags); + workposted = true; + break; + default: + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "0603 Invalid work queue CQE subtype (x%x)\n", + cq->subtype); + workposted = false; + break; + } + return workposted; +} + +/** + * lpfc_sli4_sp_handle_wcqe - Process a work-queue completion queue entry + * @phba: Pointer to HBA context object. + * @cq: Pointer to the completion queue. + * @wcqe: Pointer to a completion queue entry. + * + * This routine process a slow-path work-queue completion queue entry. + * + * Return: true if work posted to worker thread, otherwise false. + **/ +static bool +lpfc_sli4_sp_handle_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq, + struct lpfc_cqe *cqe) +{ + struct lpfc_wcqe_complete wcqe; + bool workposted = false; + + /* Copy the work queue CQE and convert endian order if needed */ + lpfc_sli_pcimem_bcopy(cqe, &wcqe, sizeof(struct lpfc_cqe)); + + /* Check and process for different type of WCQE and dispatch */ + switch (bf_get(lpfc_wcqe_c_code, &wcqe)) { + case CQE_CODE_COMPL_WQE: + /* Process the WQ complete event */ + workposted = lpfc_sli4_sp_handle_els_wcqe(phba, + (struct lpfc_wcqe_complete *)&wcqe); + break; + case CQE_CODE_RELEASE_WQE: + /* Process the WQ release event */ + lpfc_sli4_sp_handle_rel_wcqe(phba, + (struct lpfc_wcqe_release *)&wcqe); + break; + case CQE_CODE_XRI_ABORTED: + /* Process the WQ XRI abort event */ + workposted = lpfc_sli4_sp_handle_abort_xri_wcqe(phba, cq, + (struct sli4_wcqe_xri_aborted *)&wcqe); + break; + default: + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "0388 Not a valid WCQE code: x%x\n", + bf_get(lpfc_wcqe_c_code, &wcqe)); + break; + } + return workposted; +} + +/** + * lpfc_sli4_sp_handle_rcqe - Process a receive-queue completion queue entry + * @phba: Pointer to HBA context object. + * @rcqe: Pointer to receive-queue completion queue entry. + * + * This routine process a receive-queue completion queue entry. + * + * Return: true if work posted to worker thread, otherwise false. + **/ +static bool +lpfc_sli4_sp_handle_rcqe(struct lpfc_hba *phba, struct lpfc_cqe *cqe) +{ + struct lpfc_rcqe rcqe; + bool workposted = false; + struct lpfc_queue *hrq = phba->sli4_hba.hdr_rq; + struct lpfc_queue *drq = phba->sli4_hba.dat_rq; + struct hbq_dmabuf *dma_buf; + uint32_t status; + unsigned long iflags; + + /* Copy the receive queue CQE and convert endian order if needed */ + lpfc_sli_pcimem_bcopy(cqe, &rcqe, sizeof(struct lpfc_rcqe)); + lpfc_sli4_rq_release(hrq, drq); + if (bf_get(lpfc_rcqe_code, &rcqe) != CQE_CODE_RECEIVE) + goto out; + if (bf_get(lpfc_rcqe_rq_id, &rcqe) != hrq->queue_id) + goto out; + + status = bf_get(lpfc_rcqe_status, &rcqe); + switch (status) { + case FC_STATUS_RQ_BUF_LEN_EXCEEDED: + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "2537 Receive Frame Truncated!!\n"); + case FC_STATUS_RQ_SUCCESS: + spin_lock_irqsave(&phba->hbalock, iflags); + dma_buf = lpfc_sli_hbqbuf_get(&phba->hbqs[0].hbq_buffer_list); + if (!dma_buf) { + spin_unlock_irqrestore(&phba->hbalock, iflags); + goto out; + } + memcpy(&dma_buf->rcqe, &rcqe, sizeof(rcqe)); + /* save off the frame for the word thread to process */ + list_add_tail(&dma_buf->dbuf.list, &phba->rb_pend_list); + /* Frame received */ + phba->hba_flag |= HBA_RECEIVE_BUFFER; + spin_unlock_irqrestore(&phba->hbalock, iflags); + workposted = true; + break; + case FC_STATUS_INSUFF_BUF_NEED_BUF: + case FC_STATUS_INSUFF_BUF_FRM_DISC: + /* Post more buffers if possible */ + spin_lock_irqsave(&phba->hbalock, iflags); + phba->hba_flag |= HBA_POST_RECEIVE_BUFFER; + spin_unlock_irqrestore(&phba->hbalock, iflags); + workposted = true; + break; + } +out: + return workposted; + +} + +/** + * lpfc_sli4_sp_handle_eqe - Process a slow-path event queue entry + * @phba: Pointer to HBA context object. + * @eqe: Pointer to fast-path event queue entry. + * + * This routine process a event queue entry from the slow-path event queue. + * It will check the MajorCode and MinorCode to determine this is for a + * completion event on a completion queue, if not, an error shall be logged + * and just return. Otherwise, it will get to the corresponding completion + * queue and process all the entries on that completion queue, rearm the + * completion queue, and then return. + * + **/ +static void +lpfc_sli4_sp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe) +{ + struct lpfc_queue *cq = NULL, *childq, *speq; + struct lpfc_cqe *cqe; + bool workposted = false; + int ecount = 0; + uint16_t cqid; + + if (bf_get(lpfc_eqe_major_code, eqe) != 0 || + bf_get(lpfc_eqe_minor_code, eqe) != 0) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "0359 Not a valid slow-path completion " + "event: majorcode=x%x, minorcode=x%x\n", + bf_get(lpfc_eqe_major_code, eqe), + bf_get(lpfc_eqe_minor_code, eqe)); + return; + } + + /* Get the reference to the corresponding CQ */ + cqid = bf_get(lpfc_eqe_resource_id, eqe); + + /* Search for completion queue pointer matching this cqid */ + speq = phba->sli4_hba.sp_eq; + list_for_each_entry(childq, &speq->child_list, list) { + if (childq->queue_id == cqid) { + cq = childq; + break; + } + } + if (unlikely(!cq)) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "0365 Slow-path CQ identifier (%d) does " + "not exist\n", cqid); + return; + } + + /* Process all the entries to the CQ */ + switch (cq->type) { + case LPFC_MCQ: + while ((cqe = lpfc_sli4_cq_get(cq))) { + workposted |= lpfc_sli4_sp_handle_mcqe(phba, cqe); + if (!(++ecount % LPFC_GET_QE_REL_INT)) + lpfc_sli4_cq_release(cq, LPFC_QUEUE_NOARM); + } + break; + case LPFC_WCQ: + while ((cqe = lpfc_sli4_cq_get(cq))) { + workposted |= lpfc_sli4_sp_handle_wcqe(phba, cq, cqe); + if (!(++ecount % LPFC_GET_QE_REL_INT)) + lpfc_sli4_cq_release(cq, LPFC_QUEUE_NOARM); + } + break; + case LPFC_RCQ: + while ((cqe = lpfc_sli4_cq_get(cq))) { + workposted |= lpfc_sli4_sp_handle_rcqe(phba, cqe); + if (!(++ecount % LPFC_GET_QE_REL_INT)) + lpfc_sli4_cq_release(cq, LPFC_QUEUE_NOARM); + } + break; + default: + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "0370 Invalid completion queue type (%d)\n", + cq->type); + return; + } + + /* Catch the no cq entry condition, log an error */ + if (unlikely(ecount == 0)) + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "0371 No entry from the CQ: identifier " + "(x%x), type (%d)\n", cq->queue_id, cq->type); + + /* In any case, flash and re-arm the RCQ */ + lpfc_sli4_cq_release(cq, LPFC_QUEUE_REARM); + + /* wake up worker thread if there are works to be done */ + if (workposted) + lpfc_worker_wake_up(phba); +} + +/** + * lpfc_sli4_fp_handle_fcp_wcqe - Process fast-path work queue completion entry + * @eqe: Pointer to fast-path completion queue entry. + * + * This routine process a fast-path work queue completion entry from fast-path + * event queue for FCP command response completion. + **/ +static void +lpfc_sli4_fp_handle_fcp_wcqe(struct lpfc_hba *phba, + struct lpfc_wcqe_complete *wcqe) +{ + struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_FCP_RING]; + struct lpfc_iocbq *cmdiocbq; + struct lpfc_iocbq irspiocbq; + unsigned long iflags; + + spin_lock_irqsave(&phba->hbalock, iflags); + pring->stats.iocb_event++; + spin_unlock_irqrestore(&phba->hbalock, iflags); + + /* Check for response status */ + if (unlikely(bf_get(lpfc_wcqe_c_status, wcqe))) { + /* If resource errors reported from HBA, reduce queue + * depth of the SCSI device. + */ + if ((bf_get(lpfc_wcqe_c_status, wcqe) == + IOSTAT_LOCAL_REJECT) && + (wcqe->parameter == IOERR_NO_RESOURCES)) { + phba->lpfc_rampdown_queue_depth(phba); + } + /* Log the error status */ + lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, + "0373 FCP complete error: status=x%x, " + "hw_status=x%x, total_data_specified=%d, " + "parameter=x%x, word3=x%x\n", + bf_get(lpfc_wcqe_c_status, wcqe), + bf_get(lpfc_wcqe_c_hw_status, wcqe), + wcqe->total_data_placed, wcqe->parameter, + wcqe->word3); + } + + /* Look up the FCP command IOCB and create pseudo response IOCB */ + spin_lock_irqsave(&phba->hbalock, iflags); + cmdiocbq = lpfc_sli_iocbq_lookup_by_tag(phba, pring, + bf_get(lpfc_wcqe_c_request_tag, wcqe)); + spin_unlock_irqrestore(&phba->hbalock, iflags); + if (unlikely(!cmdiocbq)) { + lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, + "0374 FCP complete with no corresponding " + "cmdiocb: iotag (%d)\n", + bf_get(lpfc_wcqe_c_request_tag, wcqe)); + return; + } + if (unlikely(!cmdiocbq->iocb_cmpl)) { + lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, + "0375 FCP cmdiocb not callback function " + "iotag: (%d)\n", + bf_get(lpfc_wcqe_c_request_tag, wcqe)); + return; + } + + /* Fake the irspiocb and copy necessary response information */ + lpfc_sli4_iocb_param_transfer(&irspiocbq, cmdiocbq, wcqe); + + /* Pass the cmd_iocb and the rsp state to the upper layer */ + (cmdiocbq->iocb_cmpl)(phba, cmdiocbq, &irspiocbq); +} + +/** + * lpfc_sli4_fp_handle_rel_wcqe - Handle fast-path WQ entry consumed event + * @phba: Pointer to HBA context object. + * @cq: Pointer to completion queue. + * @wcqe: Pointer to work-queue completion queue entry. + * + * This routine handles an fast-path WQ entry comsumed event by invoking the + * proper WQ release routine to the slow-path WQ. + **/ +static void +lpfc_sli4_fp_handle_rel_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq, + struct lpfc_wcqe_release *wcqe) +{ + struct lpfc_queue *childwq; + bool wqid_matched = false; + uint16_t fcp_wqid; + + /* Check for fast-path FCP work queue release */ + fcp_wqid = bf_get(lpfc_wcqe_r_wq_id, wcqe); + list_for_each_entry(childwq, &cq->child_list, list) { + if (childwq->queue_id == fcp_wqid) { + lpfc_sli4_wq_release(childwq, + bf_get(lpfc_wcqe_r_wqe_index, wcqe)); + wqid_matched = true; + break; + } + } + /* Report warning log message if no match found */ + if (wqid_matched != true) + lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, + "2580 Fast-path wqe consume event carries " + "miss-matched qid: wcqe-qid=x%x\n", fcp_wqid); +} + +/** + * lpfc_sli4_fp_handle_wcqe - Process fast-path work queue completion entry + * @cq: Pointer to the completion queue. + * @eqe: Pointer to fast-path completion queue entry. + * + * This routine process a fast-path work queue completion entry from fast-path + * event queue for FCP command response completion. + **/ +static int +lpfc_sli4_fp_handle_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq, + struct lpfc_cqe *cqe) +{ + struct lpfc_wcqe_release wcqe; + bool workposted = false; + + /* Copy the work queue CQE and convert endian order if needed */ + lpfc_sli_pcimem_bcopy(cqe, &wcqe, sizeof(struct lpfc_cqe)); + + /* Check and process for different type of WCQE and dispatch */ + switch (bf_get(lpfc_wcqe_c_code, &wcqe)) { + case CQE_CODE_COMPL_WQE: + /* Process the WQ complete event */ + lpfc_sli4_fp_handle_fcp_wcqe(phba, + (struct lpfc_wcqe_complete *)&wcqe); + break; + case CQE_CODE_RELEASE_WQE: + /* Process the WQ release event */ + lpfc_sli4_fp_handle_rel_wcqe(phba, cq, + (struct lpfc_wcqe_release *)&wcqe); + break; + case CQE_CODE_XRI_ABORTED: + /* Process the WQ XRI abort event */ + workposted = lpfc_sli4_sp_handle_abort_xri_wcqe(phba, cq, + (struct sli4_wcqe_xri_aborted *)&wcqe); + break; + default: + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "0144 Not a valid WCQE code: x%x\n", + bf_get(lpfc_wcqe_c_code, &wcqe)); + break; + } + return workposted; +} + +/** + * lpfc_sli4_fp_handle_eqe - Process a fast-path event queue entry + * @phba: Pointer to HBA context object. + * @eqe: Pointer to fast-path event queue entry. + * + * This routine process a event queue entry from the fast-path event queue. + * It will check the MajorCode and MinorCode to determine this is for a + * completion event on a completion queue, if not, an error shall be logged + * and just return. Otherwise, it will get to the corresponding completion + * queue and process all the entries on the completion queue, rearm the + * completion queue, and then return. + **/ +static void +lpfc_sli4_fp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe, + uint32_t fcp_cqidx) +{ + struct lpfc_queue *cq; + struct lpfc_cqe *cqe; + bool workposted = false; + uint16_t cqid; + int ecount = 0; + + if (unlikely(bf_get(lpfc_eqe_major_code, eqe) != 0) || + unlikely(bf_get(lpfc_eqe_minor_code, eqe) != 0)) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "0366 Not a valid fast-path completion " + "event: majorcode=x%x, minorcode=x%x\n", + bf_get(lpfc_eqe_major_code, eqe), + bf_get(lpfc_eqe_minor_code, eqe)); + return; + } + + cq = phba->sli4_hba.fcp_cq[fcp_cqidx]; + if (unlikely(!cq)) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "0367 Fast-path completion queue does not " + "exist\n"); + return; + } + + /* Get the reference to the corresponding CQ */ + cqid = bf_get(lpfc_eqe_resource_id, eqe); + if (unlikely(cqid != cq->queue_id)) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "0368 Miss-matched fast-path completion " + "queue identifier: eqcqid=%d, fcpcqid=%d\n", + cqid, cq->queue_id); + return; + } + + /* Process all the entries to the CQ */ + while ((cqe = lpfc_sli4_cq_get(cq))) { + workposted |= lpfc_sli4_fp_handle_wcqe(phba, cq, cqe); + if (!(++ecount % LPFC_GET_QE_REL_INT)) + lpfc_sli4_cq_release(cq, LPFC_QUEUE_NOARM); + } + + /* Catch the no cq entry condition */ + if (unlikely(ecount == 0)) + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "0369 No entry from fast-path completion " + "queue fcpcqid=%d\n", cq->queue_id); + + /* In any case, flash and re-arm the CQ */ + lpfc_sli4_cq_release(cq, LPFC_QUEUE_REARM); + + /* wake up worker thread if there are works to be done */ + if (workposted) + lpfc_worker_wake_up(phba); +} + +static void +lpfc_sli4_eq_flush(struct lpfc_hba *phba, struct lpfc_queue *eq) +{ + struct lpfc_eqe *eqe; + + /* walk all the EQ entries and drop on the floor */ + while ((eqe = lpfc_sli4_eq_get(eq))) + ; + + /* Clear and re-arm the EQ */ + lpfc_sli4_eq_release(eq, LPFC_QUEUE_REARM); +} + +/** + * lpfc_sli4_sp_intr_handler - Slow-path interrupt handler to SLI-4 device + * @irq: Interrupt number. + * @dev_id: The device context pointer. + * + * This function is directly called from the PCI layer as an interrupt + * service routine when device with SLI-4 interface spec is enabled with + * MSI-X multi-message interrupt mode and there are slow-path events in + * the HBA. However, when the device is enabled with either MSI or Pin-IRQ + * interrupt mode, this function is called as part of the device-level + * interrupt handler. When the PCI slot is in error recovery or the HBA is + * undergoing initialization, the interrupt handler will not process the + * interrupt. The link attention and ELS ring attention events are handled + * by the worker thread. The interrupt handler signals the worker thread + * and returns for these events. This function is called without any lock + * held. It gets the hbalock to access and update SLI data structures. + * + * This function returns IRQ_HANDLED when interrupt is handled else it + * returns IRQ_NONE. + **/ +irqreturn_t +lpfc_sli4_sp_intr_handler(int irq, void *dev_id) +{ + struct lpfc_hba *phba; + struct lpfc_queue *speq; + struct lpfc_eqe *eqe; + unsigned long iflag; + int ecount = 0; + + /* + * Get the driver's phba structure from the dev_id + */ + phba = (struct lpfc_hba *)dev_id; + + if (unlikely(!phba)) + return IRQ_NONE; + + /* Get to the EQ struct associated with this vector */ + speq = phba->sli4_hba.sp_eq; + + /* Check device state for handling interrupt */ + if (unlikely(lpfc_intr_state_check(phba))) { + /* Check again for link_state with lock held */ + spin_lock_irqsave(&phba->hbalock, iflag); + if (phba->link_state < LPFC_LINK_DOWN) + /* Flush, clear interrupt, and rearm the EQ */ + lpfc_sli4_eq_flush(phba, speq); + spin_unlock_irqrestore(&phba->hbalock, iflag); + return IRQ_NONE; + } + + /* + * Process all the event on FCP slow-path EQ + */ + while ((eqe = lpfc_sli4_eq_get(speq))) { + lpfc_sli4_sp_handle_eqe(phba, eqe); + if (!(++ecount % LPFC_GET_QE_REL_INT)) + lpfc_sli4_eq_release(speq, LPFC_QUEUE_NOARM); + } + + /* Always clear and re-arm the slow-path EQ */ + lpfc_sli4_eq_release(speq, LPFC_QUEUE_REARM); + + /* Catch the no cq entry condition */ + if (unlikely(ecount == 0)) { + if (phba->intr_type == MSIX) + /* MSI-X treated interrupt served as no EQ share INT */ + lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, + "0357 MSI-X interrupt with no EQE\n"); + else + /* Non MSI-X treated on interrupt as EQ share INT */ + return IRQ_NONE; + } + + return IRQ_HANDLED; +} /* lpfc_sli4_sp_intr_handler */ + +/** + * lpfc_sli4_fp_intr_handler - Fast-path interrupt handler to SLI-4 device + * @irq: Interrupt number. + * @dev_id: The device context pointer. + * + * This function is directly called from the PCI layer as an interrupt + * service routine when device with SLI-4 interface spec is enabled with + * MSI-X multi-message interrupt mode and there is a fast-path FCP IOCB + * ring event in the HBA. However, when the device is enabled with either + * MSI or Pin-IRQ interrupt mode, this function is called as part of the + * device-level interrupt handler. When the PCI slot is in error recovery + * or the HBA is undergoing initialization, the interrupt handler will not + * process the interrupt. The SCSI FCP fast-path ring event are handled in + * the intrrupt context. This function is called without any lock held. + * It gets the hbalock to access and update SLI data structures. Note that, + * the FCP EQ to FCP CQ are one-to-one map such that the FCP EQ index is + * equal to that of FCP CQ index. + * + * This function returns IRQ_HANDLED when interrupt is handled else it + * returns IRQ_NONE. + **/ +irqreturn_t +lpfc_sli4_fp_intr_handler(int irq, void *dev_id) +{ + struct lpfc_hba *phba; + struct lpfc_fcp_eq_hdl *fcp_eq_hdl; + struct lpfc_queue *fpeq; + struct lpfc_eqe *eqe; + unsigned long iflag; + int ecount = 0; + uint32_t fcp_eqidx; + + /* Get the driver's phba structure from the dev_id */ + fcp_eq_hdl = (struct lpfc_fcp_eq_hdl *)dev_id; + phba = fcp_eq_hdl->phba; + fcp_eqidx = fcp_eq_hdl->idx; + + if (unlikely(!phba)) + return IRQ_NONE; + + /* Get to the EQ struct associated with this vector */ + fpeq = phba->sli4_hba.fp_eq[fcp_eqidx]; + + /* Check device state for handling interrupt */ + if (unlikely(lpfc_intr_state_check(phba))) { + /* Check again for link_state with lock held */ + spin_lock_irqsave(&phba->hbalock, iflag); + if (phba->link_state < LPFC_LINK_DOWN) + /* Flush, clear interrupt, and rearm the EQ */ + lpfc_sli4_eq_flush(phba, fpeq); + spin_unlock_irqrestore(&phba->hbalock, iflag); + return IRQ_NONE; + } + + /* + * Process all the event on FCP fast-path EQ + */ + while ((eqe = lpfc_sli4_eq_get(fpeq))) { + lpfc_sli4_fp_handle_eqe(phba, eqe, fcp_eqidx); + if (!(++ecount % LPFC_GET_QE_REL_INT)) + lpfc_sli4_eq_release(fpeq, LPFC_QUEUE_NOARM); + } + + /* Always clear and re-arm the fast-path EQ */ + lpfc_sli4_eq_release(fpeq, LPFC_QUEUE_REARM); + + if (unlikely(ecount == 0)) { + if (phba->intr_type == MSIX) + /* MSI-X treated interrupt served as no EQ share INT */ + lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, + "0358 MSI-X interrupt with no EQE\n"); + else + /* Non MSI-X treated on interrupt as EQ share INT */ + return IRQ_NONE; + } + + return IRQ_HANDLED; +} /* lpfc_sli4_fp_intr_handler */ + +/** + * lpfc_sli4_intr_handler - Device-level interrupt handler for SLI-4 device + * @irq: Interrupt number. + * @dev_id: The device context pointer. + * + * This function is the device-level interrupt handler to device with SLI-4 + * interface spec, called from the PCI layer when either MSI or Pin-IRQ + * interrupt mode is enabled and there is an event in the HBA which requires + * driver attention. This function invokes the slow-path interrupt attention + * handling function and fast-path interrupt attention handling function in + * turn to process the relevant HBA attention events. This function is called + * without any lock held. It gets the hbalock to access and update SLI data + * structures. + * + * This function returns IRQ_HANDLED when interrupt is handled, else it + * returns IRQ_NONE. + **/ +irqreturn_t +lpfc_sli4_intr_handler(int irq, void *dev_id) +{ + struct lpfc_hba *phba; + irqreturn_t sp_irq_rc, fp_irq_rc; + bool fp_handled = false; + uint32_t fcp_eqidx; + + /* Get the driver's phba structure from the dev_id */ + phba = (struct lpfc_hba *)dev_id; + + if (unlikely(!phba)) + return IRQ_NONE; + + /* + * Invokes slow-path host attention interrupt handling as appropriate. + */ + sp_irq_rc = lpfc_sli4_sp_intr_handler(irq, dev_id); + + /* + * Invoke fast-path host attention interrupt handling as appropriate. + */ + for (fcp_eqidx = 0; fcp_eqidx < phba->cfg_fcp_eq_count; fcp_eqidx++) { + fp_irq_rc = lpfc_sli4_fp_intr_handler(irq, + &phba->sli4_hba.fcp_eq_hdl[fcp_eqidx]); + if (fp_irq_rc == IRQ_HANDLED) + fp_handled |= true; + } + + return (fp_handled == true) ? IRQ_HANDLED : sp_irq_rc; +} /* lpfc_sli4_intr_handler */ + +/** + * lpfc_sli4_queue_free - free a queue structure and associated memory + * @queue: The queue structure to free. + * + * This function frees a queue structure and the DMAable memeory used for + * the host resident queue. This function must be called after destroying the + * queue on the HBA. + **/ +void +lpfc_sli4_queue_free(struct lpfc_queue *queue) +{ + struct lpfc_dmabuf *dmabuf; + + if (!queue) + return; + + while (!list_empty(&queue->page_list)) { + list_remove_head(&queue->page_list, dmabuf, struct lpfc_dmabuf, + list); + dma_free_coherent(&queue->phba->pcidev->dev, PAGE_SIZE, + dmabuf->virt, dmabuf->phys); + kfree(dmabuf); + } + kfree(queue); + return; +} + +/** + * lpfc_sli4_queue_alloc - Allocate and initialize a queue structure + * @phba: The HBA that this queue is being created on. + * @entry_size: The size of each queue entry for this queue. + * @entry count: The number of entries that this queue will handle. + * + * This function allocates a queue structure and the DMAable memory used for + * the host resident queue. This function must be called before creating the + * queue on the HBA. + **/ +struct lpfc_queue * +lpfc_sli4_queue_alloc(struct lpfc_hba *phba, uint32_t entry_size, + uint32_t entry_count) +{ + struct lpfc_queue *queue; + struct lpfc_dmabuf *dmabuf; + int x, total_qe_count; + void *dma_pointer; + + + queue = kzalloc(sizeof(struct lpfc_queue) + + (sizeof(union sli4_qe) * entry_count), GFP_KERNEL); + if (!queue) + return NULL; + queue->page_count = (PAGE_ALIGN(entry_size * entry_count))/PAGE_SIZE; + INIT_LIST_HEAD(&queue->list); + INIT_LIST_HEAD(&queue->page_list); + INIT_LIST_HEAD(&queue->child_list); + for (x = 0, total_qe_count = 0; x < queue->page_count; x++) { + dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); + if (!dmabuf) + goto out_fail; + dmabuf->virt = dma_alloc_coherent(&phba->pcidev->dev, + PAGE_SIZE, &dmabuf->phys, + GFP_KERNEL); + if (!dmabuf->virt) { + kfree(dmabuf); + goto out_fail; + } + memset(dmabuf->virt, 0, PAGE_SIZE); + dmabuf->buffer_tag = x; + list_add_tail(&dmabuf->list, &queue->page_list); + /* initialize queue's entry array */ + dma_pointer = dmabuf->virt; + for (; total_qe_count < entry_count && + dma_pointer < (PAGE_SIZE + dmabuf->virt); + total_qe_count++, dma_pointer += entry_size) { + queue->qe[total_qe_count].address = dma_pointer; + } + } + queue->entry_size = entry_size; + queue->entry_count = entry_count; + queue->phba = phba; + + return queue; +out_fail: + lpfc_sli4_queue_free(queue); + return NULL; +} + +/** + * lpfc_eq_create - Create an Event Queue on the HBA + * @phba: HBA structure that indicates port to create a queue on. + * @eq: The queue structure to use to create the event queue. + * @imax: The maximum interrupt per second limit. + * + * This function creates an event queue, as detailed in @eq, on a port, + * described by @phba by sending an EQ_CREATE mailbox command to the HBA. + * + * The @phba struct is used to send mailbox command to HBA. The @eq struct + * is used to get the entry count and entry size that are necessary to + * determine the number of pages to allocate and use for this queue. This + * function will send the EQ_CREATE mailbox command to the HBA to setup the + * event queue. This function is asynchronous and will wait for the mailbox + * command to finish before continuing. + * + * On success this function will return a zero. If unable to allocate enough + * memory this function will return ENOMEM. If the queue create mailbox command + * fails this function will return ENXIO. + **/ +uint32_t +lpfc_eq_create(struct lpfc_hba *phba, struct lpfc_queue *eq, uint16_t imax) +{ + struct lpfc_mbx_eq_create *eq_create; + LPFC_MBOXQ_t *mbox; + int rc, length, status = 0; + struct lpfc_dmabuf *dmabuf; + uint32_t shdr_status, shdr_add_status; + union lpfc_sli4_cfg_shdr *shdr; + uint16_t dmult; + + mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mbox) + return -ENOMEM; + length = (sizeof(struct lpfc_mbx_eq_create) - + sizeof(struct lpfc_sli4_cfg_mhdr)); + lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON, + LPFC_MBOX_OPCODE_EQ_CREATE, + length, LPFC_SLI4_MBX_EMBED); + eq_create = &mbox->u.mqe.un.eq_create; + bf_set(lpfc_mbx_eq_create_num_pages, &eq_create->u.request, + eq->page_count); + bf_set(lpfc_eq_context_size, &eq_create->u.request.context, + LPFC_EQE_SIZE); + bf_set(lpfc_eq_context_valid, &eq_create->u.request.context, 1); + /* Calculate delay multiper from maximum interrupt per second */ + dmult = LPFC_DMULT_CONST/imax - 1; + bf_set(lpfc_eq_context_delay_multi, &eq_create->u.request.context, + dmult); + switch (eq->entry_count) { + default: + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "0360 Unsupported EQ count. (%d)\n", + eq->entry_count); + if (eq->entry_count < 256) + return -EINVAL; + /* otherwise default to smallest count (drop through) */ + case 256: + bf_set(lpfc_eq_context_count, &eq_create->u.request.context, + LPFC_EQ_CNT_256); + break; + case 512: + bf_set(lpfc_eq_context_count, &eq_create->u.request.context, + LPFC_EQ_CNT_512); + break; + case 1024: + bf_set(lpfc_eq_context_count, &eq_create->u.request.context, + LPFC_EQ_CNT_1024); + break; + case 2048: + bf_set(lpfc_eq_context_count, &eq_create->u.request.context, + LPFC_EQ_CNT_2048); + break; + case 4096: + bf_set(lpfc_eq_context_count, &eq_create->u.request.context, + LPFC_EQ_CNT_4096); + break; + } + list_for_each_entry(dmabuf, &eq->page_list, list) { + eq_create->u.request.page[dmabuf->buffer_tag].addr_lo = + putPaddrLow(dmabuf->phys); + eq_create->u.request.page[dmabuf->buffer_tag].addr_hi = + putPaddrHigh(dmabuf->phys); + } + mbox->vport = phba->pport; + mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; + mbox->context1 = NULL; + rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); + shdr = (union lpfc_sli4_cfg_shdr *) &eq_create->header.cfg_shdr; + shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); + shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); + if (shdr_status || shdr_add_status || rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2500 EQ_CREATE mailbox failed with " + "status x%x add_status x%x, mbx status x%x\n", + shdr_status, shdr_add_status, rc); + status = -ENXIO; + } + eq->type = LPFC_EQ; + eq->subtype = LPFC_NONE; + eq->queue_id = bf_get(lpfc_mbx_eq_create_q_id, &eq_create->u.response); + if (eq->queue_id == 0xFFFF) + status = -ENXIO; + eq->host_index = 0; + eq->hba_index = 0; + + if (rc != MBX_TIMEOUT) + mempool_free(mbox, phba->mbox_mem_pool); + return status; +} + +/** + * lpfc_cq_create - Create a Completion Queue on the HBA + * @phba: HBA structure that indicates port to create a queue on. + * @cq: The queue structure to use to create the completion queue. + * @eq: The event queue to bind this completion queue to. + * + * This function creates a completion queue, as detailed in @wq, on a port, + * described by @phba by sending a CQ_CREATE mailbox command to the HBA. + * + * The @phba struct is used to send mailbox command to HBA. The @cq struct + * is used to get the entry count and entry size that are necessary to + * determine the number of pages to allocate and use for this queue. The @eq + * is used to indicate which event queue to bind this completion queue to. This + * function will send the CQ_CREATE mailbox command to the HBA to setup the + * completion queue. This function is asynchronous and will wait for the mailbox + * command to finish before continuing. + * + * On success this function will return a zero. If unable to allocate enough + * memory this function will return ENOMEM. If the queue create mailbox command + * fails this function will return ENXIO. + **/ +uint32_t +lpfc_cq_create(struct lpfc_hba *phba, struct lpfc_queue *cq, + struct lpfc_queue *eq, uint32_t type, uint32_t subtype) +{ + struct lpfc_mbx_cq_create *cq_create; + struct lpfc_dmabuf *dmabuf; + LPFC_MBOXQ_t *mbox; + int rc, length, status = 0; + uint32_t shdr_status, shdr_add_status; + union lpfc_sli4_cfg_shdr *shdr; + + mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mbox) + return -ENOMEM; + length = (sizeof(struct lpfc_mbx_cq_create) - + sizeof(struct lpfc_sli4_cfg_mhdr)); + lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON, + LPFC_MBOX_OPCODE_CQ_CREATE, + length, LPFC_SLI4_MBX_EMBED); + cq_create = &mbox->u.mqe.un.cq_create; + bf_set(lpfc_mbx_cq_create_num_pages, &cq_create->u.request, + cq->page_count); + bf_set(lpfc_cq_context_event, &cq_create->u.request.context, 1); + bf_set(lpfc_cq_context_valid, &cq_create->u.request.context, 1); + bf_set(lpfc_cq_eq_id, &cq_create->u.request.context, eq->queue_id); + switch (cq->entry_count) { + default: + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "0361 Unsupported CQ count. (%d)\n", + cq->entry_count); + if (cq->entry_count < 256) + return -EINVAL; + /* otherwise default to smallest count (drop through) */ + case 256: + bf_set(lpfc_cq_context_count, &cq_create->u.request.context, + LPFC_CQ_CNT_256); + break; + case 512: + bf_set(lpfc_cq_context_count, &cq_create->u.request.context, + LPFC_CQ_CNT_512); + break; + case 1024: + bf_set(lpfc_cq_context_count, &cq_create->u.request.context, + LPFC_CQ_CNT_1024); + break; + } + list_for_each_entry(dmabuf, &cq->page_list, list) { + cq_create->u.request.page[dmabuf->buffer_tag].addr_lo = + putPaddrLow(dmabuf->phys); + cq_create->u.request.page[dmabuf->buffer_tag].addr_hi = + putPaddrHigh(dmabuf->phys); + } + rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); + + /* The IOCTL status is embedded in the mailbox subheader. */ + shdr = (union lpfc_sli4_cfg_shdr *) &cq_create->header.cfg_shdr; + shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); + shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); + if (shdr_status || shdr_add_status || rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2501 CQ_CREATE mailbox failed with " + "status x%x add_status x%x, mbx status x%x\n", + shdr_status, shdr_add_status, rc); + status = -ENXIO; + goto out; + } + cq->queue_id = bf_get(lpfc_mbx_cq_create_q_id, &cq_create->u.response); + if (cq->queue_id == 0xFFFF) { + status = -ENXIO; + goto out; + } + /* link the cq onto the parent eq child list */ + list_add_tail(&cq->list, &eq->child_list); + /* Set up completion queue's type and subtype */ + cq->type = type; + cq->subtype = subtype; + cq->queue_id = bf_get(lpfc_mbx_cq_create_q_id, &cq_create->u.response); + cq->host_index = 0; + cq->hba_index = 0; +out: + + if (rc != MBX_TIMEOUT) + mempool_free(mbox, phba->mbox_mem_pool); + return status; +} + +/** + * lpfc_mq_create - Create a mailbox Queue on the HBA + * @phba: HBA structure that indicates port to create a queue on. + * @mq: The queue structure to use to create the mailbox queue. + * + * This function creates a mailbox queue, as detailed in @mq, on a port, + * described by @phba by sending a MQ_CREATE mailbox command to the HBA. + * + * The @phba struct is used to send mailbox command to HBA. The @cq struct + * is used to get the entry count and entry size that are necessary to + * determine the number of pages to allocate and use for this queue. This + * function will send the MQ_CREATE mailbox command to the HBA to setup the + * mailbox queue. This function is asynchronous and will wait for the mailbox + * command to finish before continuing. + * + * On success this function will return a zero. If unable to allocate enough + * memory this function will return ENOMEM. If the queue create mailbox command + * fails this function will return ENXIO. + **/ +uint32_t +lpfc_mq_create(struct lpfc_hba *phba, struct lpfc_queue *mq, + struct lpfc_queue *cq, uint32_t subtype) +{ + struct lpfc_mbx_mq_create *mq_create; + struct lpfc_dmabuf *dmabuf; + LPFC_MBOXQ_t *mbox; + int rc, length, status = 0; + uint32_t shdr_status, shdr_add_status; + union lpfc_sli4_cfg_shdr *shdr; + + mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mbox) + return -ENOMEM; + length = (sizeof(struct lpfc_mbx_mq_create) - + sizeof(struct lpfc_sli4_cfg_mhdr)); + lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON, + LPFC_MBOX_OPCODE_MQ_CREATE, + length, LPFC_SLI4_MBX_EMBED); + mq_create = &mbox->u.mqe.un.mq_create; + bf_set(lpfc_mbx_mq_create_num_pages, &mq_create->u.request, + mq->page_count); + bf_set(lpfc_mq_context_cq_id, &mq_create->u.request.context, + cq->queue_id); + bf_set(lpfc_mq_context_valid, &mq_create->u.request.context, 1); + switch (mq->entry_count) { + default: + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "0362 Unsupported MQ count. (%d)\n", + mq->entry_count); + if (mq->entry_count < 16) + return -EINVAL; + /* otherwise default to smallest count (drop through) */ + case 16: + bf_set(lpfc_mq_context_count, &mq_create->u.request.context, + LPFC_MQ_CNT_16); + break; + case 32: + bf_set(lpfc_mq_context_count, &mq_create->u.request.context, + LPFC_MQ_CNT_32); + break; + case 64: + bf_set(lpfc_mq_context_count, &mq_create->u.request.context, + LPFC_MQ_CNT_64); + break; + case 128: + bf_set(lpfc_mq_context_count, &mq_create->u.request.context, + LPFC_MQ_CNT_128); + break; + } + list_for_each_entry(dmabuf, &mq->page_list, list) { + mq_create->u.request.page[dmabuf->buffer_tag].addr_lo = + putPaddrLow(dmabuf->phys); + mq_create->u.request.page[dmabuf->buffer_tag].addr_hi = + putPaddrHigh(dmabuf->phys); + } + rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); + /* The IOCTL status is embedded in the mailbox subheader. */ + shdr = (union lpfc_sli4_cfg_shdr *) &mq_create->header.cfg_shdr; + shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); + shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); + if (shdr_status || shdr_add_status || rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2502 MQ_CREATE mailbox failed with " + "status x%x add_status x%x, mbx status x%x\n", + shdr_status, shdr_add_status, rc); + status = -ENXIO; + goto out; + } + mq->queue_id = bf_get(lpfc_mbx_mq_create_q_id, &mq_create->u.response); + if (mq->queue_id == 0xFFFF) { + status = -ENXIO; + goto out; + } + mq->type = LPFC_MQ; + mq->subtype = subtype; + mq->host_index = 0; + mq->hba_index = 0; + + /* link the mq onto the parent cq child list */ + list_add_tail(&mq->list, &cq->child_list); +out: + if (rc != MBX_TIMEOUT) + mempool_free(mbox, phba->mbox_mem_pool); + return status; +} + +/** + * lpfc_wq_create - Create a Work Queue on the HBA + * @phba: HBA structure that indicates port to create a queue on. + * @wq: The queue structure to use to create the work queue. + * @cq: The completion queue to bind this work queue to. + * @subtype: The subtype of the work queue indicating its functionality. + * + * This function creates a work queue, as detailed in @wq, on a port, described + * by @phba by sending a WQ_CREATE mailbox command to the HBA. + * + * The @phba struct is used to send mailbox command to HBA. The @wq struct + * is used to get the entry count and entry size that are necessary to + * determine the number of pages to allocate and use for this queue. The @cq + * is used to indicate which completion queue to bind this work queue to. This + * function will send the WQ_CREATE mailbox command to the HBA to setup the + * work queue. This function is asynchronous and will wait for the mailbox + * command to finish before continuing. + * + * On success this function will return a zero. If unable to allocate enough + * memory this function will return ENOMEM. If the queue create mailbox command + * fails this function will return ENXIO. + **/ +uint32_t +lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq, + struct lpfc_queue *cq, uint32_t subtype) +{ + struct lpfc_mbx_wq_create *wq_create; + struct lpfc_dmabuf *dmabuf; + LPFC_MBOXQ_t *mbox; + int rc, length, status = 0; + uint32_t shdr_status, shdr_add_status; + union lpfc_sli4_cfg_shdr *shdr; + + mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mbox) + return -ENOMEM; + length = (sizeof(struct lpfc_mbx_wq_create) - + sizeof(struct lpfc_sli4_cfg_mhdr)); + lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE, + LPFC_MBOX_OPCODE_FCOE_WQ_CREATE, + length, LPFC_SLI4_MBX_EMBED); + wq_create = &mbox->u.mqe.un.wq_create; + bf_set(lpfc_mbx_wq_create_num_pages, &wq_create->u.request, + wq->page_count); + bf_set(lpfc_mbx_wq_create_cq_id, &wq_create->u.request, + cq->queue_id); + list_for_each_entry(dmabuf, &wq->page_list, list) { + wq_create->u.request.page[dmabuf->buffer_tag].addr_lo = + putPaddrLow(dmabuf->phys); + wq_create->u.request.page[dmabuf->buffer_tag].addr_hi = + putPaddrHigh(dmabuf->phys); + } + rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); + /* The IOCTL status is embedded in the mailbox subheader. */ + shdr = (union lpfc_sli4_cfg_shdr *) &wq_create->header.cfg_shdr; + shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); + shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); + if (shdr_status || shdr_add_status || rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2503 WQ_CREATE mailbox failed with " + "status x%x add_status x%x, mbx status x%x\n", + shdr_status, shdr_add_status, rc); + status = -ENXIO; + goto out; + } + wq->queue_id = bf_get(lpfc_mbx_wq_create_q_id, &wq_create->u.response); + if (wq->queue_id == 0xFFFF) { + status = -ENXIO; + goto out; + } + wq->type = LPFC_WQ; + wq->subtype = subtype; + wq->host_index = 0; + wq->hba_index = 0; + + /* link the wq onto the parent cq child list */ + list_add_tail(&wq->list, &cq->child_list); +out: + if (rc != MBX_TIMEOUT) + mempool_free(mbox, phba->mbox_mem_pool); + return status; +} + +/** + * lpfc_rq_create - Create a Receive Queue on the HBA + * @phba: HBA structure that indicates port to create a queue on. + * @hrq: The queue structure to use to create the header receive queue. + * @drq: The queue structure to use to create the data receive queue. + * @cq: The completion queue to bind this work queue to. + * + * This function creates a receive buffer queue pair , as detailed in @hrq and + * @drq, on a port, described by @phba by sending a RQ_CREATE mailbox command + * to the HBA. + * + * The @phba struct is used to send mailbox command to HBA. The @drq and @hrq + * struct is used to get the entry count that is necessary to determine the + * number of pages to use for this queue. The @cq is used to indicate which + * completion queue to bind received buffers that are posted to these queues to. + * This function will send the RQ_CREATE mailbox command to the HBA to setup the + * receive queue pair. This function is asynchronous and will wait for the + * mailbox command to finish before continuing. + * + * On success this function will return a zero. If unable to allocate enough + * memory this function will return ENOMEM. If the queue create mailbox command + * fails this function will return ENXIO. + **/ +uint32_t +lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq, + struct lpfc_queue *drq, struct lpfc_queue *cq, uint32_t subtype) +{ + struct lpfc_mbx_rq_create *rq_create; + struct lpfc_dmabuf *dmabuf; + LPFC_MBOXQ_t *mbox; + int rc, length, status = 0; + uint32_t shdr_status, shdr_add_status; + union lpfc_sli4_cfg_shdr *shdr; + + if (hrq->entry_count != drq->entry_count) + return -EINVAL; + mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mbox) + return -ENOMEM; + length = (sizeof(struct lpfc_mbx_rq_create) - + sizeof(struct lpfc_sli4_cfg_mhdr)); + lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE, + LPFC_MBOX_OPCODE_FCOE_RQ_CREATE, + length, LPFC_SLI4_MBX_EMBED); + rq_create = &mbox->u.mqe.un.rq_create; + switch (hrq->entry_count) { + default: + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "2535 Unsupported RQ count. (%d)\n", + hrq->entry_count); + if (hrq->entry_count < 512) + return -EINVAL; + /* otherwise default to smallest count (drop through) */ + case 512: + bf_set(lpfc_rq_context_rq_size, &rq_create->u.request.context, + LPFC_RQ_RING_SIZE_512); + break; + case 1024: + bf_set(lpfc_rq_context_rq_size, &rq_create->u.request.context, + LPFC_RQ_RING_SIZE_1024); + break; + case 2048: + bf_set(lpfc_rq_context_rq_size, &rq_create->u.request.context, + LPFC_RQ_RING_SIZE_2048); + break; + case 4096: + bf_set(lpfc_rq_context_rq_size, &rq_create->u.request.context, + LPFC_RQ_RING_SIZE_4096); + break; + } + bf_set(lpfc_rq_context_cq_id, &rq_create->u.request.context, + cq->queue_id); + bf_set(lpfc_mbx_rq_create_num_pages, &rq_create->u.request, + hrq->page_count); + bf_set(lpfc_rq_context_buf_size, &rq_create->u.request.context, + LPFC_HDR_BUF_SIZE); + list_for_each_entry(dmabuf, &hrq->page_list, list) { + rq_create->u.request.page[dmabuf->buffer_tag].addr_lo = + putPaddrLow(dmabuf->phys); + rq_create->u.request.page[dmabuf->buffer_tag].addr_hi = + putPaddrHigh(dmabuf->phys); + } + rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); + /* The IOCTL status is embedded in the mailbox subheader. */ + shdr = (union lpfc_sli4_cfg_shdr *) &rq_create->header.cfg_shdr; + shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); + shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); + if (shdr_status || shdr_add_status || rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2504 RQ_CREATE mailbox failed with " + "status x%x add_status x%x, mbx status x%x\n", + shdr_status, shdr_add_status, rc); + status = -ENXIO; + goto out; + } + hrq->queue_id = bf_get(lpfc_mbx_rq_create_q_id, &rq_create->u.response); + if (hrq->queue_id == 0xFFFF) { + status = -ENXIO; + goto out; + } + hrq->type = LPFC_HRQ; + hrq->subtype = subtype; + hrq->host_index = 0; + hrq->hba_index = 0; + + /* now create the data queue */ + lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE, + LPFC_MBOX_OPCODE_FCOE_RQ_CREATE, + length, LPFC_SLI4_MBX_EMBED); + switch (drq->entry_count) { + default: + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "2536 Unsupported RQ count. (%d)\n", + drq->entry_count); + if (drq->entry_count < 512) + return -EINVAL; + /* otherwise default to smallest count (drop through) */ + case 512: + bf_set(lpfc_rq_context_rq_size, &rq_create->u.request.context, + LPFC_RQ_RING_SIZE_512); + break; + case 1024: + bf_set(lpfc_rq_context_rq_size, &rq_create->u.request.context, + LPFC_RQ_RING_SIZE_1024); + break; + case 2048: + bf_set(lpfc_rq_context_rq_size, &rq_create->u.request.context, + LPFC_RQ_RING_SIZE_2048); + break; + case 4096: + bf_set(lpfc_rq_context_rq_size, &rq_create->u.request.context, + LPFC_RQ_RING_SIZE_4096); + break; + } + bf_set(lpfc_rq_context_cq_id, &rq_create->u.request.context, + cq->queue_id); + bf_set(lpfc_mbx_rq_create_num_pages, &rq_create->u.request, + drq->page_count); + bf_set(lpfc_rq_context_buf_size, &rq_create->u.request.context, + LPFC_DATA_BUF_SIZE); + list_for_each_entry(dmabuf, &drq->page_list, list) { + rq_create->u.request.page[dmabuf->buffer_tag].addr_lo = + putPaddrLow(dmabuf->phys); + rq_create->u.request.page[dmabuf->buffer_tag].addr_hi = + putPaddrHigh(dmabuf->phys); + } + rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); + /* The IOCTL status is embedded in the mailbox subheader. */ + shdr = (union lpfc_sli4_cfg_shdr *) &rq_create->header.cfg_shdr; + shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); + shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); + if (shdr_status || shdr_add_status || rc) { + status = -ENXIO; + goto out; + } + drq->queue_id = bf_get(lpfc_mbx_rq_create_q_id, &rq_create->u.response); + if (drq->queue_id == 0xFFFF) { + status = -ENXIO; + goto out; + } + drq->type = LPFC_DRQ; + drq->subtype = subtype; + drq->host_index = 0; + drq->hba_index = 0; + + /* link the header and data RQs onto the parent cq child list */ + list_add_tail(&hrq->list, &cq->child_list); + list_add_tail(&drq->list, &cq->child_list); + +out: + if (rc != MBX_TIMEOUT) + mempool_free(mbox, phba->mbox_mem_pool); + return status; +} + +/** + * lpfc_eq_destroy - Destroy an event Queue on the HBA + * @eq: The queue structure associated with the queue to destroy. + * + * This function destroys a queue, as detailed in @eq by sending an mailbox + * command, specific to the type of queue, to the HBA. + * + * The @eq struct is used to get the queue ID of the queue to destroy. + * + * On success this function will return a zero. If the queue destroy mailbox + * command fails this function will return ENXIO. + **/ +uint32_t +lpfc_eq_destroy(struct lpfc_hba *phba, struct lpfc_queue *eq) +{ + LPFC_MBOXQ_t *mbox; + int rc, length, status = 0; + uint32_t shdr_status, shdr_add_status; + union lpfc_sli4_cfg_shdr *shdr; + + if (!eq) + return -ENODEV; + mbox = mempool_alloc(eq->phba->mbox_mem_pool, GFP_KERNEL); + if (!mbox) + return -ENOMEM; + length = (sizeof(struct lpfc_mbx_eq_destroy) - + sizeof(struct lpfc_sli4_cfg_mhdr)); + lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON, + LPFC_MBOX_OPCODE_EQ_DESTROY, + length, LPFC_SLI4_MBX_EMBED); + bf_set(lpfc_mbx_eq_destroy_q_id, &mbox->u.mqe.un.eq_destroy.u.request, + eq->queue_id); + mbox->vport = eq->phba->pport; + mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; + + rc = lpfc_sli_issue_mbox(eq->phba, mbox, MBX_POLL); + /* The IOCTL status is embedded in the mailbox subheader. */ + shdr = (union lpfc_sli4_cfg_shdr *) + &mbox->u.mqe.un.eq_destroy.header.cfg_shdr; + shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); + shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); + if (shdr_status || shdr_add_status || rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2505 EQ_DESTROY mailbox failed with " + "status x%x add_status x%x, mbx status x%x\n", + shdr_status, shdr_add_status, rc); + status = -ENXIO; + } + + /* Remove eq from any list */ + list_del_init(&eq->list); + if (rc != MBX_TIMEOUT) + mempool_free(mbox, eq->phba->mbox_mem_pool); + return status; +} + +/** + * lpfc_cq_destroy - Destroy a Completion Queue on the HBA + * @cq: The queue structure associated with the queue to destroy. + * + * This function destroys a queue, as detailed in @cq by sending an mailbox + * command, specific to the type of queue, to the HBA. + * + * The @cq struct is used to get the queue ID of the queue to destroy. + * + * On success this function will return a zero. If the queue destroy mailbox + * command fails this function will return ENXIO. + **/ +uint32_t +lpfc_cq_destroy(struct lpfc_hba *phba, struct lpfc_queue *cq) +{ + LPFC_MBOXQ_t *mbox; + int rc, length, status = 0; + uint32_t shdr_status, shdr_add_status; + union lpfc_sli4_cfg_shdr *shdr; + + if (!cq) + return -ENODEV; + mbox = mempool_alloc(cq->phba->mbox_mem_pool, GFP_KERNEL); + if (!mbox) + return -ENOMEM; + length = (sizeof(struct lpfc_mbx_cq_destroy) - + sizeof(struct lpfc_sli4_cfg_mhdr)); + lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON, + LPFC_MBOX_OPCODE_CQ_DESTROY, + length, LPFC_SLI4_MBX_EMBED); + bf_set(lpfc_mbx_cq_destroy_q_id, &mbox->u.mqe.un.cq_destroy.u.request, + cq->queue_id); + mbox->vport = cq->phba->pport; + mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; + rc = lpfc_sli_issue_mbox(cq->phba, mbox, MBX_POLL); + /* The IOCTL status is embedded in the mailbox subheader. */ + shdr = (union lpfc_sli4_cfg_shdr *) + &mbox->u.mqe.un.wq_create.header.cfg_shdr; + shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); + shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); + if (shdr_status || shdr_add_status || rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2506 CQ_DESTROY mailbox failed with " + "status x%x add_status x%x, mbx status x%x\n", + shdr_status, shdr_add_status, rc); + status = -ENXIO; + } + /* Remove cq from any list */ + list_del_init(&cq->list); + if (rc != MBX_TIMEOUT) + mempool_free(mbox, cq->phba->mbox_mem_pool); + return status; +} + +/** + * lpfc_mq_destroy - Destroy a Mailbox Queue on the HBA + * @qm: The queue structure associated with the queue to destroy. + * + * This function destroys a queue, as detailed in @mq by sending an mailbox + * command, specific to the type of queue, to the HBA. + * + * The @mq struct is used to get the queue ID of the queue to destroy. + * + * On success this function will return a zero. If the queue destroy mailbox + * command fails this function will return ENXIO. + **/ +uint32_t +lpfc_mq_destroy(struct lpfc_hba *phba, struct lpfc_queue *mq) +{ + LPFC_MBOXQ_t *mbox; + int rc, length, status = 0; + uint32_t shdr_status, shdr_add_status; + union lpfc_sli4_cfg_shdr *shdr; + + if (!mq) + return -ENODEV; + mbox = mempool_alloc(mq->phba->mbox_mem_pool, GFP_KERNEL); + if (!mbox) + return -ENOMEM; + length = (sizeof(struct lpfc_mbx_mq_destroy) - + sizeof(struct lpfc_sli4_cfg_mhdr)); + lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON, + LPFC_MBOX_OPCODE_MQ_DESTROY, + length, LPFC_SLI4_MBX_EMBED); + bf_set(lpfc_mbx_mq_destroy_q_id, &mbox->u.mqe.un.mq_destroy.u.request, + mq->queue_id); + mbox->vport = mq->phba->pport; + mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; + rc = lpfc_sli_issue_mbox(mq->phba, mbox, MBX_POLL); + /* The IOCTL status is embedded in the mailbox subheader. */ + shdr = (union lpfc_sli4_cfg_shdr *) + &mbox->u.mqe.un.mq_destroy.header.cfg_shdr; + shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); + shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); + if (shdr_status || shdr_add_status || rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2507 MQ_DESTROY mailbox failed with " + "status x%x add_status x%x, mbx status x%x\n", + shdr_status, shdr_add_status, rc); + status = -ENXIO; + } + /* Remove mq from any list */ + list_del_init(&mq->list); + if (rc != MBX_TIMEOUT) + mempool_free(mbox, mq->phba->mbox_mem_pool); + return status; +} + +/** + * lpfc_wq_destroy - Destroy a Work Queue on the HBA + * @wq: The queue structure associated with the queue to destroy. + * + * This function destroys a queue, as detailed in @wq by sending an mailbox + * command, specific to the type of queue, to the HBA. + * + * The @wq struct is used to get the queue ID of the queue to destroy. + * + * On success this function will return a zero. If the queue destroy mailbox + * command fails this function will return ENXIO. + **/ +uint32_t +lpfc_wq_destroy(struct lpfc_hba *phba, struct lpfc_queue *wq) +{ + LPFC_MBOXQ_t *mbox; + int rc, length, status = 0; + uint32_t shdr_status, shdr_add_status; + union lpfc_sli4_cfg_shdr *shdr; + + if (!wq) + return -ENODEV; + mbox = mempool_alloc(wq->phba->mbox_mem_pool, GFP_KERNEL); + if (!mbox) + return -ENOMEM; + length = (sizeof(struct lpfc_mbx_wq_destroy) - + sizeof(struct lpfc_sli4_cfg_mhdr)); + lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE, + LPFC_MBOX_OPCODE_FCOE_WQ_DESTROY, + length, LPFC_SLI4_MBX_EMBED); + bf_set(lpfc_mbx_wq_destroy_q_id, &mbox->u.mqe.un.wq_destroy.u.request, + wq->queue_id); + mbox->vport = wq->phba->pport; + mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; + rc = lpfc_sli_issue_mbox(wq->phba, mbox, MBX_POLL); + shdr = (union lpfc_sli4_cfg_shdr *) + &mbox->u.mqe.un.wq_destroy.header.cfg_shdr; + shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); + shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); + if (shdr_status || shdr_add_status || rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2508 WQ_DESTROY mailbox failed with " + "status x%x add_status x%x, mbx status x%x\n", + shdr_status, shdr_add_status, rc); + status = -ENXIO; + } + /* Remove wq from any list */ + list_del_init(&wq->list); + if (rc != MBX_TIMEOUT) + mempool_free(mbox, wq->phba->mbox_mem_pool); + return status; +} + +/** + * lpfc_rq_destroy - Destroy a Receive Queue on the HBA + * @rq: The queue structure associated with the queue to destroy. + * + * This function destroys a queue, as detailed in @rq by sending an mailbox + * command, specific to the type of queue, to the HBA. + * + * The @rq struct is used to get the queue ID of the queue to destroy. + * + * On success this function will return a zero. If the queue destroy mailbox + * command fails this function will return ENXIO. + **/ +uint32_t +lpfc_rq_destroy(struct lpfc_hba *phba, struct lpfc_queue *hrq, + struct lpfc_queue *drq) +{ + LPFC_MBOXQ_t *mbox; + int rc, length, status = 0; + uint32_t shdr_status, shdr_add_status; + union lpfc_sli4_cfg_shdr *shdr; + + if (!hrq || !drq) + return -ENODEV; + mbox = mempool_alloc(hrq->phba->mbox_mem_pool, GFP_KERNEL); + if (!mbox) + return -ENOMEM; + length = (sizeof(struct lpfc_mbx_rq_destroy) - + sizeof(struct mbox_header)); + lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE, + LPFC_MBOX_OPCODE_FCOE_RQ_DESTROY, + length, LPFC_SLI4_MBX_EMBED); + bf_set(lpfc_mbx_rq_destroy_q_id, &mbox->u.mqe.un.rq_destroy.u.request, + hrq->queue_id); + mbox->vport = hrq->phba->pport; + mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; + rc = lpfc_sli_issue_mbox(hrq->phba, mbox, MBX_POLL); + /* The IOCTL status is embedded in the mailbox subheader. */ + shdr = (union lpfc_sli4_cfg_shdr *) + &mbox->u.mqe.un.rq_destroy.header.cfg_shdr; + shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); + shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); + if (shdr_status || shdr_add_status || rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2509 RQ_DESTROY mailbox failed with " + "status x%x add_status x%x, mbx status x%x\n", + shdr_status, shdr_add_status, rc); + if (rc != MBX_TIMEOUT) + mempool_free(mbox, hrq->phba->mbox_mem_pool); + return -ENXIO; + } + bf_set(lpfc_mbx_rq_destroy_q_id, &mbox->u.mqe.un.rq_destroy.u.request, + drq->queue_id); + rc = lpfc_sli_issue_mbox(drq->phba, mbox, MBX_POLL); + shdr = (union lpfc_sli4_cfg_shdr *) + &mbox->u.mqe.un.rq_destroy.header.cfg_shdr; + shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); + shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); + if (shdr_status || shdr_add_status || rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2510 RQ_DESTROY mailbox failed with " + "status x%x add_status x%x, mbx status x%x\n", + shdr_status, shdr_add_status, rc); + status = -ENXIO; + } + list_del_init(&hrq->list); + list_del_init(&drq->list); + if (rc != MBX_TIMEOUT) + mempool_free(mbox, hrq->phba->mbox_mem_pool); + return status; +} + +/** + * lpfc_sli4_post_sgl - Post scatter gather list for an XRI to HBA + * @phba: The virtual port for which this call being executed. + * @pdma_phys_addr0: Physical address of the 1st SGL page. + * @pdma_phys_addr1: Physical address of the 2nd SGL page. + * @xritag: the xritag that ties this io to the SGL pages. + * + * This routine will post the sgl pages for the IO that has the xritag + * that is in the iocbq structure. The xritag is assigned during iocbq + * creation and persists for as long as the driver is loaded. + * if the caller has fewer than 256 scatter gather segments to map then + * pdma_phys_addr1 should be 0. + * If the caller needs to map more than 256 scatter gather segment then + * pdma_phys_addr1 should be a valid physical address. + * physical address for SGLs must be 64 byte aligned. + * If you are going to map 2 SGL's then the first one must have 256 entries + * the second sgl can have between 1 and 256 entries. + * + * Return codes: + * 0 - Success + * -ENXIO, -ENOMEM - Failure + **/ +int +lpfc_sli4_post_sgl(struct lpfc_hba *phba, + dma_addr_t pdma_phys_addr0, + dma_addr_t pdma_phys_addr1, + uint16_t xritag) +{ + struct lpfc_mbx_post_sgl_pages *post_sgl_pages; + LPFC_MBOXQ_t *mbox; + int rc; + uint32_t shdr_status, shdr_add_status; + union lpfc_sli4_cfg_shdr *shdr; + + if (xritag == NO_XRI) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "0364 Invalid param:\n"); + return -EINVAL; + } + + mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mbox) + return -ENOMEM; + + lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE, + LPFC_MBOX_OPCODE_FCOE_POST_SGL_PAGES, + sizeof(struct lpfc_mbx_post_sgl_pages) - + sizeof(struct mbox_header), LPFC_SLI4_MBX_EMBED); + + post_sgl_pages = (struct lpfc_mbx_post_sgl_pages *) + &mbox->u.mqe.un.post_sgl_pages; + bf_set(lpfc_post_sgl_pages_xri, post_sgl_pages, xritag); + bf_set(lpfc_post_sgl_pages_xricnt, post_sgl_pages, 1); + + post_sgl_pages->sgl_pg_pairs[0].sgl_pg0_addr_lo = + cpu_to_le32(putPaddrLow(pdma_phys_addr0)); + post_sgl_pages->sgl_pg_pairs[0].sgl_pg0_addr_hi = + cpu_to_le32(putPaddrHigh(pdma_phys_addr0)); + + post_sgl_pages->sgl_pg_pairs[0].sgl_pg1_addr_lo = + cpu_to_le32(putPaddrLow(pdma_phys_addr1)); + post_sgl_pages->sgl_pg_pairs[0].sgl_pg1_addr_hi = + cpu_to_le32(putPaddrHigh(pdma_phys_addr1)); + if (!phba->sli4_hba.intr_enable) + rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); + else + rc = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO); + /* The IOCTL status is embedded in the mailbox subheader. */ + shdr = (union lpfc_sli4_cfg_shdr *) &post_sgl_pages->header.cfg_shdr; + shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); + shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); + if (rc != MBX_TIMEOUT) + mempool_free(mbox, phba->mbox_mem_pool); + if (shdr_status || shdr_add_status || rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2511 POST_SGL mailbox failed with " + "status x%x add_status x%x, mbx status x%x\n", + shdr_status, shdr_add_status, rc); + rc = -ENXIO; + } + return 0; +} +/** + * lpfc_sli4_remove_all_sgl_pages - Post scatter gather list for an XRI to HBA + * @phba: The virtual port for which this call being executed. + * + * This routine will remove all of the sgl pages registered with the hba. + * + * Return codes: + * 0 - Success + * -ENXIO, -ENOMEM - Failure + **/ +int +lpfc_sli4_remove_all_sgl_pages(struct lpfc_hba *phba) +{ + LPFC_MBOXQ_t *mbox; + int rc; + uint32_t shdr_status, shdr_add_status; + union lpfc_sli4_cfg_shdr *shdr; + + mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mbox) + return -ENOMEM; + + lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE, + LPFC_MBOX_OPCODE_FCOE_REMOVE_SGL_PAGES, 0, + LPFC_SLI4_MBX_EMBED); + if (!phba->sli4_hba.intr_enable) + rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); + else + rc = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO); + /* The IOCTL status is embedded in the mailbox subheader. */ + shdr = (union lpfc_sli4_cfg_shdr *) + &mbox->u.mqe.un.sli4_config.header.cfg_shdr; + shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); + shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); + if (rc != MBX_TIMEOUT) + mempool_free(mbox, phba->mbox_mem_pool); + if (shdr_status || shdr_add_status || rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2512 REMOVE_ALL_SGL_PAGES mailbox failed with " + "status x%x add_status x%x, mbx status x%x\n", + shdr_status, shdr_add_status, rc); + rc = -ENXIO; + } + return rc; +} + +/** + * lpfc_sli4_next_xritag - Get an xritag for the io + * @phba: Pointer to HBA context object. + * + * This function gets an xritag for the iocb. If there is no unused xritag + * it will return 0xffff. + * The function returns the allocated xritag if successful, else returns zero. + * Zero is not a valid xritag. + * The caller is not required to hold any lock. + **/ +uint16_t +lpfc_sli4_next_xritag(struct lpfc_hba *phba) +{ + uint16_t xritag; + + spin_lock_irq(&phba->hbalock); + xritag = phba->sli4_hba.next_xri; + if ((xritag != (uint16_t) -1) && xritag < + (phba->sli4_hba.max_cfg_param.max_xri + + phba->sli4_hba.max_cfg_param.xri_base)) { + phba->sli4_hba.next_xri++; + phba->sli4_hba.max_cfg_param.xri_used++; + spin_unlock_irq(&phba->hbalock); + return xritag; + } + spin_unlock_irq(&phba->hbalock); + + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "2004 Failed to allocate XRI.last XRITAG is %d" + " Max XRI is %d, Used XRI is %d\n", + phba->sli4_hba.next_xri, + phba->sli4_hba.max_cfg_param.max_xri, + phba->sli4_hba.max_cfg_param.xri_used); + return -1; +} + +/** + * lpfc_sli4_post_sgl_list - post a block of sgl list to the firmware. + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to post a block of driver's sgl pages to the + * HBA using non-embedded mailbox command. No Lock is held. This routine + * is only called when the driver is loading and after all IO has been + * stopped. + **/ +int +lpfc_sli4_post_sgl_list(struct lpfc_hba *phba) +{ + struct lpfc_sglq *sglq_entry; + struct lpfc_mbx_post_uembed_sgl_page1 *sgl; + struct sgl_page_pairs *sgl_pg_pairs; + void *viraddr; + LPFC_MBOXQ_t *mbox; + uint32_t reqlen, alloclen, pg_pairs; + uint32_t mbox_tmo; + uint16_t xritag_start = 0; + int els_xri_cnt, rc = 0; + uint32_t shdr_status, shdr_add_status; + union lpfc_sli4_cfg_shdr *shdr; + + /* The number of sgls to be posted */ + els_xri_cnt = lpfc_sli4_get_els_iocb_cnt(phba); + + reqlen = els_xri_cnt * sizeof(struct sgl_page_pairs) + + sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t); + if (reqlen > PAGE_SIZE) { + lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, + "2559 Block sgl registration required DMA " + "size (%d) great than a page\n", reqlen); + return -ENOMEM; + } + mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mbox) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2560 Failed to allocate mbox cmd memory\n"); + return -ENOMEM; + } + + /* Allocate DMA memory and set up the non-embedded mailbox command */ + alloclen = lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE, + LPFC_MBOX_OPCODE_FCOE_POST_SGL_PAGES, reqlen, + LPFC_SLI4_MBX_NEMBED); + + if (alloclen < reqlen) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0285 Allocated DMA memory size (%d) is " + "less than the requested DMA memory " + "size (%d)\n", alloclen, reqlen); + lpfc_sli4_mbox_cmd_free(phba, mbox); + return -ENOMEM; + } + + /* Get the first SGE entry from the non-embedded DMA memory */ + if (unlikely(!mbox->sge_array)) { + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, + "2525 Failed to get the non-embedded SGE " + "virtual address\n"); + lpfc_sli4_mbox_cmd_free(phba, mbox); + return -ENOMEM; + } + viraddr = mbox->sge_array->addr[0]; + + /* Set up the SGL pages in the non-embedded DMA pages */ + sgl = (struct lpfc_mbx_post_uembed_sgl_page1 *)viraddr; + sgl_pg_pairs = &sgl->sgl_pg_pairs; + + for (pg_pairs = 0; pg_pairs < els_xri_cnt; pg_pairs++) { + sglq_entry = phba->sli4_hba.lpfc_els_sgl_array[pg_pairs]; + /* Set up the sge entry */ + sgl_pg_pairs->sgl_pg0_addr_lo = + cpu_to_le32(putPaddrLow(sglq_entry->phys)); + sgl_pg_pairs->sgl_pg0_addr_hi = + cpu_to_le32(putPaddrHigh(sglq_entry->phys)); + sgl_pg_pairs->sgl_pg1_addr_lo = + cpu_to_le32(putPaddrLow(0)); + sgl_pg_pairs->sgl_pg1_addr_hi = + cpu_to_le32(putPaddrHigh(0)); + /* Keep the first xritag on the list */ + if (pg_pairs == 0) + xritag_start = sglq_entry->sli4_xritag; + sgl_pg_pairs++; + } + bf_set(lpfc_post_sgl_pages_xri, sgl, xritag_start); + pg_pairs = (pg_pairs > 0) ? (pg_pairs - 1) : pg_pairs; + bf_set(lpfc_post_sgl_pages_xricnt, sgl, pg_pairs); + /* Perform endian conversion if necessary */ + sgl->word0 = cpu_to_le32(sgl->word0); + + if (!phba->sli4_hba.intr_enable) + rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); + else { + mbox_tmo = lpfc_mbox_tmo_val(phba, MBX_SLI4_CONFIG); + rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo); + } + shdr = (union lpfc_sli4_cfg_shdr *) &sgl->cfg_shdr; + shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); + shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); + if (rc != MBX_TIMEOUT) + lpfc_sli4_mbox_cmd_free(phba, mbox); + if (shdr_status || shdr_add_status || rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "2513 POST_SGL_BLOCK mailbox command failed " + "status x%x add_status x%x mbx status x%x\n", + shdr_status, shdr_add_status, rc); + rc = -ENXIO; + } + return rc; +} + +/** + * lpfc_sli4_post_scsi_sgl_block - post a block of scsi sgl list to firmware + * @phba: pointer to lpfc hba data structure. + * @sblist: pointer to scsi buffer list. + * @count: number of scsi buffers on the list. + * + * This routine is invoked to post a block of @count scsi sgl pages from a + * SCSI buffer list @sblist to the HBA using non-embedded mailbox command. + * No Lock is held. + * + **/ +int +lpfc_sli4_post_scsi_sgl_block(struct lpfc_hba *phba, struct list_head *sblist, + int cnt) +{ + struct lpfc_scsi_buf *psb; + struct lpfc_mbx_post_uembed_sgl_page1 *sgl; + struct sgl_page_pairs *sgl_pg_pairs; + void *viraddr; + LPFC_MBOXQ_t *mbox; + uint32_t reqlen, alloclen, pg_pairs; + uint32_t mbox_tmo; + uint16_t xritag_start = 0; + int rc = 0; + uint32_t shdr_status, shdr_add_status; + dma_addr_t pdma_phys_bpl1; + union lpfc_sli4_cfg_shdr *shdr; + + /* Calculate the requested length of the dma memory */ + reqlen = cnt * sizeof(struct sgl_page_pairs) + + sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t); + if (reqlen > PAGE_SIZE) { + lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, + "0217 Block sgl registration required DMA " + "size (%d) great than a page\n", reqlen); + return -ENOMEM; + } + mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mbox) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0283 Failed to allocate mbox cmd memory\n"); + return -ENOMEM; + } + + /* Allocate DMA memory and set up the non-embedded mailbox command */ + alloclen = lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE, + LPFC_MBOX_OPCODE_FCOE_POST_SGL_PAGES, reqlen, + LPFC_SLI4_MBX_NEMBED); + + if (alloclen < reqlen) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2561 Allocated DMA memory size (%d) is " + "less than the requested DMA memory " + "size (%d)\n", alloclen, reqlen); + lpfc_sli4_mbox_cmd_free(phba, mbox); + return -ENOMEM; + } + + /* Get the first SGE entry from the non-embedded DMA memory */ + if (unlikely(!mbox->sge_array)) { + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, + "2565 Failed to get the non-embedded SGE " + "virtual address\n"); + lpfc_sli4_mbox_cmd_free(phba, mbox); + return -ENOMEM; + } + viraddr = mbox->sge_array->addr[0]; + + /* Set up the SGL pages in the non-embedded DMA pages */ + sgl = (struct lpfc_mbx_post_uembed_sgl_page1 *)viraddr; + sgl_pg_pairs = &sgl->sgl_pg_pairs; + + pg_pairs = 0; + list_for_each_entry(psb, sblist, list) { + /* Set up the sge entry */ + sgl_pg_pairs->sgl_pg0_addr_lo = + cpu_to_le32(putPaddrLow(psb->dma_phys_bpl)); + sgl_pg_pairs->sgl_pg0_addr_hi = + cpu_to_le32(putPaddrHigh(psb->dma_phys_bpl)); + if (phba->cfg_sg_dma_buf_size > SGL_PAGE_SIZE) + pdma_phys_bpl1 = psb->dma_phys_bpl + SGL_PAGE_SIZE; + else + pdma_phys_bpl1 = 0; + sgl_pg_pairs->sgl_pg1_addr_lo = + cpu_to_le32(putPaddrLow(pdma_phys_bpl1)); + sgl_pg_pairs->sgl_pg1_addr_hi = + cpu_to_le32(putPaddrHigh(pdma_phys_bpl1)); + /* Keep the first xritag on the list */ + if (pg_pairs == 0) + xritag_start = psb->cur_iocbq.sli4_xritag; + sgl_pg_pairs++; + pg_pairs++; + } + bf_set(lpfc_post_sgl_pages_xri, sgl, xritag_start); + bf_set(lpfc_post_sgl_pages_xricnt, sgl, pg_pairs); + /* Perform endian conversion if necessary */ + sgl->word0 = cpu_to_le32(sgl->word0); + + if (!phba->sli4_hba.intr_enable) + rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); + else { + mbox_tmo = lpfc_mbox_tmo_val(phba, MBX_SLI4_CONFIG); + rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo); + } + shdr = (union lpfc_sli4_cfg_shdr *) &sgl->cfg_shdr; + shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); + shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); + if (rc != MBX_TIMEOUT) + lpfc_sli4_mbox_cmd_free(phba, mbox); + if (shdr_status || shdr_add_status || rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "2564 POST_SGL_BLOCK mailbox command failed " + "status x%x add_status x%x mbx status x%x\n", + shdr_status, shdr_add_status, rc); + rc = -ENXIO; + } + return rc; +} + +/** + * lpfc_fc_frame_check - Check that this frame is a valid frame to handle + * @phba: pointer to lpfc_hba struct that the frame was received on + * @fc_hdr: A pointer to the FC Header data (In Big Endian Format) + * + * This function checks the fields in the @fc_hdr to see if the FC frame is a + * valid type of frame that the LPFC driver will handle. This function will + * return a zero if the frame is a valid frame or a non zero value when the + * frame does not pass the check. + **/ +static int +lpfc_fc_frame_check(struct lpfc_hba *phba, struct fc_frame_header *fc_hdr) +{ + char *rctl_names[] = FC_RCTL_NAMES_INIT; + char *type_names[] = FC_TYPE_NAMES_INIT; + struct fc_vft_header *fc_vft_hdr; + + switch (fc_hdr->fh_r_ctl) { + case FC_RCTL_DD_UNCAT: /* uncategorized information */ + case FC_RCTL_DD_SOL_DATA: /* solicited data */ + case FC_RCTL_DD_UNSOL_CTL: /* unsolicited control */ + case FC_RCTL_DD_SOL_CTL: /* solicited control or reply */ + case FC_RCTL_DD_UNSOL_DATA: /* unsolicited data */ + case FC_RCTL_DD_DATA_DESC: /* data descriptor */ + case FC_RCTL_DD_UNSOL_CMD: /* unsolicited command */ + case FC_RCTL_DD_CMD_STATUS: /* command status */ + case FC_RCTL_ELS_REQ: /* extended link services request */ + case FC_RCTL_ELS_REP: /* extended link services reply */ + case FC_RCTL_ELS4_REQ: /* FC-4 ELS request */ + case FC_RCTL_ELS4_REP: /* FC-4 ELS reply */ + case FC_RCTL_BA_NOP: /* basic link service NOP */ + case FC_RCTL_BA_ABTS: /* basic link service abort */ + case FC_RCTL_BA_RMC: /* remove connection */ + case FC_RCTL_BA_ACC: /* basic accept */ + case FC_RCTL_BA_RJT: /* basic reject */ + case FC_RCTL_BA_PRMT: + case FC_RCTL_ACK_1: /* acknowledge_1 */ + case FC_RCTL_ACK_0: /* acknowledge_0 */ + case FC_RCTL_P_RJT: /* port reject */ + case FC_RCTL_F_RJT: /* fabric reject */ + case FC_RCTL_P_BSY: /* port busy */ + case FC_RCTL_F_BSY: /* fabric busy to data frame */ + case FC_RCTL_F_BSYL: /* fabric busy to link control frame */ + case FC_RCTL_LCR: /* link credit reset */ + case FC_RCTL_END: /* end */ + break; + case FC_RCTL_VFTH: /* Virtual Fabric tagging Header */ + fc_vft_hdr = (struct fc_vft_header *)fc_hdr; + fc_hdr = &((struct fc_frame_header *)fc_vft_hdr)[1]; + return lpfc_fc_frame_check(phba, fc_hdr); + default: + goto drop; + } + switch (fc_hdr->fh_type) { + case FC_TYPE_BLS: + case FC_TYPE_ELS: + case FC_TYPE_FCP: + case FC_TYPE_CT: + break; + case FC_TYPE_IP: + case FC_TYPE_ILS: + default: + goto drop; + } + lpfc_printf_log(phba, KERN_INFO, LOG_ELS, + "2538 Received frame rctl:%s type:%s\n", + rctl_names[fc_hdr->fh_r_ctl], + type_names[fc_hdr->fh_type]); + return 0; +drop: + lpfc_printf_log(phba, KERN_WARNING, LOG_ELS, + "2539 Dropped frame rctl:%s type:%s\n", + rctl_names[fc_hdr->fh_r_ctl], + type_names[fc_hdr->fh_type]); + return 1; +} + +/** + * lpfc_fc_hdr_get_vfi - Get the VFI from an FC frame + * @fc_hdr: A pointer to the FC Header data (In Big Endian Format) + * + * This function processes the FC header to retrieve the VFI from the VF + * header, if one exists. This function will return the VFI if one exists + * or 0 if no VSAN Header exists. + **/ +static uint32_t +lpfc_fc_hdr_get_vfi(struct fc_frame_header *fc_hdr) +{ + struct fc_vft_header *fc_vft_hdr = (struct fc_vft_header *)fc_hdr; + + if (fc_hdr->fh_r_ctl != FC_RCTL_VFTH) + return 0; + return bf_get(fc_vft_hdr_vf_id, fc_vft_hdr); +} + +/** + * lpfc_fc_frame_to_vport - Finds the vport that a frame is destined to + * @phba: Pointer to the HBA structure to search for the vport on + * @fc_hdr: A pointer to the FC Header data (In Big Endian Format) + * @fcfi: The FC Fabric ID that the frame came from + * + * This function searches the @phba for a vport that matches the content of the + * @fc_hdr passed in and the @fcfi. This function uses the @fc_hdr to fetch the + * VFI, if the Virtual Fabric Tagging Header exists, and the DID. This function + * returns the matching vport pointer or NULL if unable to match frame to a + * vport. + **/ +static struct lpfc_vport * +lpfc_fc_frame_to_vport(struct lpfc_hba *phba, struct fc_frame_header *fc_hdr, + uint16_t fcfi) +{ + struct lpfc_vport **vports; + struct lpfc_vport *vport = NULL; + int i; + uint32_t did = (fc_hdr->fh_d_id[0] << 16 | + fc_hdr->fh_d_id[1] << 8 | + fc_hdr->fh_d_id[2]); + + vports = lpfc_create_vport_work_array(phba); + if (vports != NULL) + for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { + if (phba->fcf.fcfi == fcfi && + vports[i]->vfi == lpfc_fc_hdr_get_vfi(fc_hdr) && + vports[i]->fc_myDID == did) { + vport = vports[i]; + break; + } + } + lpfc_destroy_vport_work_array(phba, vports); + return vport; +} + +/** + * lpfc_fc_frame_add - Adds a frame to the vport's list of received sequences + * @dmabuf: pointer to a dmabuf that describes the hdr and data of the FC frame + * + * This function searches through the existing incomplete sequences that have + * been sent to this @vport. If the frame matches one of the incomplete + * sequences then the dbuf in the @dmabuf is added to the list of frames that + * make up that sequence. If no sequence is found that matches this frame then + * the function will add the hbuf in the @dmabuf to the @vport's rcv_buffer_list + * This function returns a pointer to the first dmabuf in the sequence list that + * the frame was linked to. + **/ +static struct hbq_dmabuf * +lpfc_fc_frame_add(struct lpfc_vport *vport, struct hbq_dmabuf *dmabuf) +{ + struct fc_frame_header *new_hdr; + struct fc_frame_header *temp_hdr; + struct lpfc_dmabuf *d_buf; + struct lpfc_dmabuf *h_buf; + struct hbq_dmabuf *seq_dmabuf = NULL; + struct hbq_dmabuf *temp_dmabuf = NULL; + + new_hdr = (struct fc_frame_header *)dmabuf->hbuf.virt; + /* Use the hdr_buf to find the sequence that this frame belongs to */ + list_for_each_entry(h_buf, &vport->rcv_buffer_list, list) { + temp_hdr = (struct fc_frame_header *)h_buf->virt; + if ((temp_hdr->fh_seq_id != new_hdr->fh_seq_id) || + (temp_hdr->fh_ox_id != new_hdr->fh_ox_id) || + (memcmp(&temp_hdr->fh_s_id, &new_hdr->fh_s_id, 3))) + continue; + /* found a pending sequence that matches this frame */ + seq_dmabuf = container_of(h_buf, struct hbq_dmabuf, hbuf); + break; + } + if (!seq_dmabuf) { + /* + * This indicates first frame received for this sequence. + * Queue the buffer on the vport's rcv_buffer_list. + */ + list_add_tail(&dmabuf->hbuf.list, &vport->rcv_buffer_list); + return dmabuf; + } + temp_hdr = seq_dmabuf->hbuf.virt; + if (new_hdr->fh_seq_cnt < temp_hdr->fh_seq_cnt) { + list_add(&seq_dmabuf->dbuf.list, &dmabuf->dbuf.list); + return dmabuf; + } + /* find the correct place in the sequence to insert this frame */ + list_for_each_entry_reverse(d_buf, &seq_dmabuf->dbuf.list, list) { + temp_dmabuf = container_of(d_buf, struct hbq_dmabuf, dbuf); + temp_hdr = (struct fc_frame_header *)temp_dmabuf->hbuf.virt; + /* + * If the frame's sequence count is greater than the frame on + * the list then insert the frame right after this frame + */ + if (new_hdr->fh_seq_cnt > temp_hdr->fh_seq_cnt) { + list_add(&dmabuf->dbuf.list, &temp_dmabuf->dbuf.list); + return seq_dmabuf; + } + } + return NULL; +} + +/** + * lpfc_seq_complete - Indicates if a sequence is complete + * @dmabuf: pointer to a dmabuf that describes the FC sequence + * + * This function checks the sequence, starting with the frame described by + * @dmabuf, to see if all the frames associated with this sequence are present. + * the frames associated with this sequence are linked to the @dmabuf using the + * dbuf list. This function looks for two major things. 1) That the first frame + * has a sequence count of zero. 2) There is a frame with last frame of sequence + * set. 3) That there are no holes in the sequence count. The function will + * return 1 when the sequence is complete, otherwise it will return 0. + **/ +static int +lpfc_seq_complete(struct hbq_dmabuf *dmabuf) +{ + struct fc_frame_header *hdr; + struct lpfc_dmabuf *d_buf; + struct hbq_dmabuf *seq_dmabuf; + uint32_t fctl; + int seq_count = 0; + + hdr = (struct fc_frame_header *)dmabuf->hbuf.virt; + /* make sure first fame of sequence has a sequence count of zero */ + if (hdr->fh_seq_cnt != seq_count) + return 0; + fctl = (hdr->fh_f_ctl[0] << 16 | + hdr->fh_f_ctl[1] << 8 | + hdr->fh_f_ctl[2]); + /* If last frame of sequence we can return success. */ + if (fctl & FC_FC_END_SEQ) + return 1; + list_for_each_entry(d_buf, &dmabuf->dbuf.list, list) { + seq_dmabuf = container_of(d_buf, struct hbq_dmabuf, dbuf); + hdr = (struct fc_frame_header *)seq_dmabuf->hbuf.virt; + /* If there is a hole in the sequence count then fail. */ + if (++seq_count != hdr->fh_seq_cnt) + return 0; + fctl = (hdr->fh_f_ctl[0] << 16 | + hdr->fh_f_ctl[1] << 8 | + hdr->fh_f_ctl[2]); + /* If last frame of sequence we can return success. */ + if (fctl & FC_FC_END_SEQ) + return 1; + } + return 0; +} + +/** + * lpfc_prep_seq - Prep sequence for ULP processing + * @vport: Pointer to the vport on which this sequence was received + * @dmabuf: pointer to a dmabuf that describes the FC sequence + * + * This function takes a sequence, described by a list of frames, and creates + * a list of iocbq structures to describe the sequence. This iocbq list will be + * used to issue to the generic unsolicited sequence handler. This routine + * returns a pointer to the first iocbq in the list. If the function is unable + * to allocate an iocbq then it throw out the received frames that were not + * able to be described and return a pointer to the first iocbq. If unable to + * allocate any iocbqs (including the first) this function will return NULL. + **/ +static struct lpfc_iocbq * +lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf) +{ + struct lpfc_dmabuf *d_buf, *n_buf; + struct lpfc_iocbq *first_iocbq, *iocbq; + struct fc_frame_header *fc_hdr; + uint32_t sid; + + fc_hdr = (struct fc_frame_header *)seq_dmabuf->hbuf.virt; + /* remove from receive buffer list */ + list_del_init(&seq_dmabuf->hbuf.list); + /* get the Remote Port's SID */ + sid = (fc_hdr->fh_s_id[0] << 16 | + fc_hdr->fh_s_id[1] << 8 | + fc_hdr->fh_s_id[2]); + /* Get an iocbq struct to fill in. */ + first_iocbq = lpfc_sli_get_iocbq(vport->phba); + if (first_iocbq) { + /* Initialize the first IOCB. */ + first_iocbq->iocb.ulpStatus = IOSTAT_SUCCESS; + first_iocbq->iocb.ulpCommand = CMD_IOCB_RCV_SEQ64_CX; + first_iocbq->iocb.ulpContext = be16_to_cpu(fc_hdr->fh_ox_id); + first_iocbq->iocb.unsli3.rcvsli3.vpi = + vport->vpi + vport->phba->vpi_base; + /* put the first buffer into the first IOCBq */ + first_iocbq->context2 = &seq_dmabuf->dbuf; + first_iocbq->context3 = NULL; + first_iocbq->iocb.ulpBdeCount = 1; + first_iocbq->iocb.un.cont64[0].tus.f.bdeSize = + LPFC_DATA_BUF_SIZE; + first_iocbq->iocb.un.rcvels.remoteID = sid; + } + iocbq = first_iocbq; + /* + * Each IOCBq can have two Buffers assigned, so go through the list + * of buffers for this sequence and save two buffers in each IOCBq + */ + list_for_each_entry_safe(d_buf, n_buf, &seq_dmabuf->dbuf.list, list) { + if (!iocbq) { + lpfc_in_buf_free(vport->phba, d_buf); + continue; + } + if (!iocbq->context3) { + iocbq->context3 = d_buf; + iocbq->iocb.ulpBdeCount++; + iocbq->iocb.unsli3.rcvsli3.bde2.tus.f.bdeSize = + LPFC_DATA_BUF_SIZE; + } else { + iocbq = lpfc_sli_get_iocbq(vport->phba); + if (!iocbq) { + if (first_iocbq) { + first_iocbq->iocb.ulpStatus = + IOSTAT_FCP_RSP_ERROR; + first_iocbq->iocb.un.ulpWord[4] = + IOERR_NO_RESOURCES; + } + lpfc_in_buf_free(vport->phba, d_buf); + continue; + } + iocbq->context2 = d_buf; + iocbq->context3 = NULL; + iocbq->iocb.ulpBdeCount = 1; + iocbq->iocb.un.cont64[0].tus.f.bdeSize = + LPFC_DATA_BUF_SIZE; + iocbq->iocb.un.rcvels.remoteID = sid; + list_add_tail(&iocbq->list, &first_iocbq->list); + } + } + return first_iocbq; +} + +/** + * lpfc_sli4_handle_received_buffer - Handle received buffers from firmware + * @phba: Pointer to HBA context object. + * + * This function is called with no lock held. This function processes all + * the received buffers and gives it to upper layers when a received buffer + * indicates that it is the final frame in the sequence. The interrupt + * service routine processes received buffers at interrupt contexts and adds + * received dma buffers to the rb_pend_list queue and signals the worker thread. + * Worker thread calls lpfc_sli4_handle_received_buffer, which will call the + * appropriate receive function when the final frame in a sequence is received. + **/ +int +lpfc_sli4_handle_received_buffer(struct lpfc_hba *phba) +{ + LIST_HEAD(cmplq); + struct hbq_dmabuf *dmabuf, *seq_dmabuf; + struct fc_frame_header *fc_hdr; + struct lpfc_vport *vport; + uint32_t fcfi; + struct lpfc_iocbq *iocbq; + + /* Clear hba flag and get all received buffers into the cmplq */ + spin_lock_irq(&phba->hbalock); + phba->hba_flag &= ~HBA_RECEIVE_BUFFER; + list_splice_init(&phba->rb_pend_list, &cmplq); + spin_unlock_irq(&phba->hbalock); + + /* Process each received buffer */ + while ((dmabuf = lpfc_sli_hbqbuf_get(&cmplq)) != NULL) { + fc_hdr = (struct fc_frame_header *)dmabuf->hbuf.virt; + /* check to see if this a valid type of frame */ + if (lpfc_fc_frame_check(phba, fc_hdr)) { + lpfc_in_buf_free(phba, &dmabuf->dbuf); + continue; + } + fcfi = bf_get(lpfc_rcqe_fcf_id, &dmabuf->rcqe); + vport = lpfc_fc_frame_to_vport(phba, fc_hdr, fcfi); + if (!vport) { + /* throw out the frame */ + lpfc_in_buf_free(phba, &dmabuf->dbuf); + continue; + } + /* Link this frame */ + seq_dmabuf = lpfc_fc_frame_add(vport, dmabuf); + if (!seq_dmabuf) { + /* unable to add frame to vport - throw it out */ + lpfc_in_buf_free(phba, &dmabuf->dbuf); + continue; + } + /* If not last frame in sequence continue processing frames. */ + if (!lpfc_seq_complete(seq_dmabuf)) { + /* + * When saving off frames post a new one and mark this + * frame to be freed when it is finished. + **/ + lpfc_sli_hbqbuf_fill_hbqs(phba, LPFC_ELS_HBQ, 1); + dmabuf->tag = -1; + continue; + } + fc_hdr = (struct fc_frame_header *)seq_dmabuf->hbuf.virt; + iocbq = lpfc_prep_seq(vport, seq_dmabuf); + if (!lpfc_complete_unsol_iocb(phba, + &phba->sli.ring[LPFC_ELS_RING], + iocbq, fc_hdr->fh_r_ctl, + fc_hdr->fh_type)) + lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, + "2540 Ring %d handler: unexpected Rctl " + "x%x Type x%x received\n", + LPFC_ELS_RING, + fc_hdr->fh_r_ctl, fc_hdr->fh_type); + }; + return 0; +} + +/** + * lpfc_sli4_post_all_rpi_hdrs - Post the rpi header memory region to the port + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to post rpi header templates to the + * HBA consistent with the SLI-4 interface spec. This routine + * posts a PAGE_SIZE memory region to the port to hold up to + * PAGE_SIZE modulo 64 rpi context headers. + * + * This routine does not require any locks. It's usage is expected + * to be driver load or reset recovery when the driver is + * sequential. + * + * Return codes + * 0 - sucessful + * EIO - The mailbox failed to complete successfully. + * When this error occurs, the driver is not guaranteed + * to have any rpi regions posted to the device and + * must either attempt to repost the regions or take a + * fatal error. + **/ +int +lpfc_sli4_post_all_rpi_hdrs(struct lpfc_hba *phba) +{ + struct lpfc_rpi_hdr *rpi_page; + uint32_t rc = 0; + + /* Post all rpi memory regions to the port. */ + list_for_each_entry(rpi_page, &phba->sli4_hba.lpfc_rpi_hdr_list, list) { + rc = lpfc_sli4_post_rpi_hdr(phba, rpi_page); + if (rc != MBX_SUCCESS) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "2008 Error %d posting all rpi " + "headers\n", rc); + rc = -EIO; + break; + } + } + + return rc; +} + +/** + * lpfc_sli4_post_rpi_hdr - Post an rpi header memory region to the port + * @phba: pointer to lpfc hba data structure. + * @rpi_page: pointer to the rpi memory region. + * + * This routine is invoked to post a single rpi header to the + * HBA consistent with the SLI-4 interface spec. This memory region + * maps up to 64 rpi context regions. + * + * Return codes + * 0 - sucessful + * ENOMEM - No available memory + * EIO - The mailbox failed to complete successfully. + **/ +int +lpfc_sli4_post_rpi_hdr(struct lpfc_hba *phba, struct lpfc_rpi_hdr *rpi_page) +{ + LPFC_MBOXQ_t *mboxq; + struct lpfc_mbx_post_hdr_tmpl *hdr_tmpl; + uint32_t rc = 0; + uint32_t mbox_tmo; + uint32_t shdr_status, shdr_add_status; + union lpfc_sli4_cfg_shdr *shdr; + + /* The port is notified of the header region via a mailbox command. */ + mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mboxq) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "2001 Unable to allocate memory for issuing " + "SLI_CONFIG_SPECIAL mailbox command\n"); + return -ENOMEM; + } + + /* Post all rpi memory regions to the port. */ + hdr_tmpl = &mboxq->u.mqe.un.hdr_tmpl; + mbox_tmo = lpfc_mbox_tmo_val(phba, MBX_SLI4_CONFIG); + lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_FCOE, + LPFC_MBOX_OPCODE_FCOE_POST_HDR_TEMPLATE, + sizeof(struct lpfc_mbx_post_hdr_tmpl) - + sizeof(struct mbox_header), LPFC_SLI4_MBX_EMBED); + bf_set(lpfc_mbx_post_hdr_tmpl_page_cnt, + hdr_tmpl, rpi_page->page_count); + bf_set(lpfc_mbx_post_hdr_tmpl_rpi_offset, hdr_tmpl, + rpi_page->start_rpi); + hdr_tmpl->rpi_paddr_lo = putPaddrLow(rpi_page->dmabuf->phys); + hdr_tmpl->rpi_paddr_hi = putPaddrHigh(rpi_page->dmabuf->phys); + rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); + shdr = (union lpfc_sli4_cfg_shdr *) &hdr_tmpl->header.cfg_shdr; + shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); + shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); + if (rc != MBX_TIMEOUT) + mempool_free(mboxq, phba->mbox_mem_pool); + if (shdr_status || shdr_add_status || rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2514 POST_RPI_HDR mailbox failed with " + "status x%x add_status x%x, mbx status x%x\n", + shdr_status, shdr_add_status, rc); + rc = -ENXIO; + } + return rc; +} + +/** + * lpfc_sli4_alloc_rpi - Get an available rpi in the device's range + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to post rpi header templates to the + * HBA consistent with the SLI-4 interface spec. This routine + * posts a PAGE_SIZE memory region to the port to hold up to + * PAGE_SIZE modulo 64 rpi context headers. + * + * Returns + * A nonzero rpi defined as rpi_base <= rpi < max_rpi if sucessful + * LPFC_RPI_ALLOC_ERROR if no rpis are available. + **/ +int +lpfc_sli4_alloc_rpi(struct lpfc_hba *phba) +{ + int rpi; + uint16_t max_rpi, rpi_base, rpi_limit; + uint16_t rpi_remaining; + struct lpfc_rpi_hdr *rpi_hdr; + + max_rpi = phba->sli4_hba.max_cfg_param.max_rpi; + rpi_base = phba->sli4_hba.max_cfg_param.rpi_base; + rpi_limit = phba->sli4_hba.next_rpi; + + /* + * The valid rpi range is not guaranteed to be zero-based. Start + * the search at the rpi_base as reported by the port. + */ + spin_lock_irq(&phba->hbalock); + rpi = find_next_zero_bit(phba->sli4_hba.rpi_bmask, rpi_limit, rpi_base); + if (rpi >= rpi_limit || rpi < rpi_base) + rpi = LPFC_RPI_ALLOC_ERROR; + else { + set_bit(rpi, phba->sli4_hba.rpi_bmask); + phba->sli4_hba.max_cfg_param.rpi_used++; + phba->sli4_hba.rpi_count++; + } + + /* + * Don't try to allocate more rpi header regions if the device limit + * on available rpis max has been exhausted. + */ + if ((rpi == LPFC_RPI_ALLOC_ERROR) && + (phba->sli4_hba.rpi_count >= max_rpi)) { + spin_unlock_irq(&phba->hbalock); + return rpi; + } + + /* + * If the driver is running low on rpi resources, allocate another + * page now. Note that the next_rpi value is used because + * it represents how many are actually in use whereas max_rpi notes + * how many are supported max by the device. + */ + rpi_remaining = phba->sli4_hba.next_rpi - rpi_base - + phba->sli4_hba.rpi_count; + spin_unlock_irq(&phba->hbalock); + if (rpi_remaining < LPFC_RPI_LOW_WATER_MARK) { + rpi_hdr = lpfc_sli4_create_rpi_hdr(phba); + if (!rpi_hdr) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "2002 Error Could not grow rpi " + "count\n"); + } else { + lpfc_sli4_post_rpi_hdr(phba, rpi_hdr); + } + } + + return rpi; +} + +/** + * lpfc_sli4_free_rpi - Release an rpi for reuse. + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to release an rpi to the pool of + * available rpis maintained by the driver. + **/ +void +lpfc_sli4_free_rpi(struct lpfc_hba *phba, int rpi) +{ + spin_lock_irq(&phba->hbalock); + clear_bit(rpi, phba->sli4_hba.rpi_bmask); + phba->sli4_hba.rpi_count--; + phba->sli4_hba.max_cfg_param.rpi_used--; + spin_unlock_irq(&phba->hbalock); +} + +/** + * lpfc_sli4_remove_rpis - Remove the rpi bitmask region + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to remove the memory region that + * provided rpi via a bitmask. + **/ +void +lpfc_sli4_remove_rpis(struct lpfc_hba *phba) +{ + kfree(phba->sli4_hba.rpi_bmask); +} + +/** + * lpfc_sli4_resume_rpi - Remove the rpi bitmask region + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to remove the memory region that + * provided rpi via a bitmask. + **/ +int +lpfc_sli4_resume_rpi(struct lpfc_nodelist *ndlp) +{ + LPFC_MBOXQ_t *mboxq; + struct lpfc_hba *phba = ndlp->phba; + int rc; + + /* The port is notified of the header region via a mailbox command. */ + mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mboxq) + return -ENOMEM; + + /* Post all rpi memory regions to the port. */ + lpfc_resume_rpi(mboxq, ndlp); + rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT); + if (rc == MBX_NOT_FINISHED) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "2010 Resume RPI Mailbox failed " + "status %d, mbxStatus x%x\n", rc, + bf_get(lpfc_mqe_status, &mboxq->u.mqe)); + mempool_free(mboxq, phba->mbox_mem_pool); + return -EIO; + } + return 0; +} + +/** + * lpfc_sli4_init_vpi - Initialize a vpi with the port + * @phba: pointer to lpfc hba data structure. + * @vpi: vpi value to activate with the port. + * + * This routine is invoked to activate a vpi with the + * port when the host intends to use vports with a + * nonzero vpi. + * + * Returns: + * 0 success + * -Evalue otherwise + **/ +int +lpfc_sli4_init_vpi(struct lpfc_hba *phba, uint16_t vpi) +{ + LPFC_MBOXQ_t *mboxq; + int rc = 0; + uint32_t mbox_tmo; + + if (vpi == 0) + return -EINVAL; + mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mboxq) + return -ENOMEM; + lpfc_init_vpi(mboxq, vpi); + mbox_tmo = lpfc_mbox_tmo_val(phba, MBX_INIT_VPI); + rc = lpfc_sli_issue_mbox_wait(phba, mboxq, mbox_tmo); + if (rc != MBX_TIMEOUT) + mempool_free(mboxq, phba->mbox_mem_pool); + if (rc != MBX_SUCCESS) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "2022 INIT VPI Mailbox failed " + "status %d, mbxStatus x%x\n", rc, + bf_get(lpfc_mqe_status, &mboxq->u.mqe)); + rc = -EIO; + } + return rc; +} + +/** + * lpfc_mbx_cmpl_add_fcf_record - add fcf mbox completion handler. + * @phba: pointer to lpfc hba data structure. + * @mboxq: Pointer to mailbox object. + * + * This routine is invoked to manually add a single FCF record. The caller + * must pass a completely initialized FCF_Record. This routine takes + * care of the nonembedded mailbox operations. + **/ +static void +lpfc_mbx_cmpl_add_fcf_record(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) +{ + void *virt_addr; + union lpfc_sli4_cfg_shdr *shdr; + uint32_t shdr_status, shdr_add_status; + + virt_addr = mboxq->sge_array->addr[0]; + /* The IOCTL status is embedded in the mailbox subheader. */ + shdr = (union lpfc_sli4_cfg_shdr *) virt_addr; + shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); + shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); + + if ((shdr_status || shdr_add_status) && + (shdr_status != STATUS_FCF_IN_USE)) + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2558 ADD_FCF_RECORD mailbox failed with " + "status x%x add_status x%x\n", + shdr_status, shdr_add_status); + + lpfc_sli4_mbox_cmd_free(phba, mboxq); +} + +/** + * lpfc_sli4_add_fcf_record - Manually add an FCF Record. + * @phba: pointer to lpfc hba data structure. + * @fcf_record: pointer to the initialized fcf record to add. + * + * This routine is invoked to manually add a single FCF record. The caller + * must pass a completely initialized FCF_Record. This routine takes + * care of the nonembedded mailbox operations. + **/ +int +lpfc_sli4_add_fcf_record(struct lpfc_hba *phba, struct fcf_record *fcf_record) +{ + int rc = 0; + LPFC_MBOXQ_t *mboxq; + uint8_t *bytep; + void *virt_addr; + dma_addr_t phys_addr; + struct lpfc_mbx_sge sge; + uint32_t alloc_len, req_len; + uint32_t fcfindex; + + mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mboxq) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2009 Failed to allocate mbox for ADD_FCF cmd\n"); + return -ENOMEM; + } + + req_len = sizeof(struct fcf_record) + sizeof(union lpfc_sli4_cfg_shdr) + + sizeof(uint32_t); + + /* Allocate DMA memory and set up the non-embedded mailbox command */ + alloc_len = lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_FCOE, + LPFC_MBOX_OPCODE_FCOE_ADD_FCF, + req_len, LPFC_SLI4_MBX_NEMBED); + if (alloc_len < req_len) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2523 Allocated DMA memory size (x%x) is " + "less than the requested DMA memory " + "size (x%x)\n", alloc_len, req_len); + lpfc_sli4_mbox_cmd_free(phba, mboxq); + return -ENOMEM; + } + + /* + * Get the first SGE entry from the non-embedded DMA memory. This + * routine only uses a single SGE. + */ + lpfc_sli4_mbx_sge_get(mboxq, 0, &sge); + phys_addr = getPaddr(sge.pa_hi, sge.pa_lo); + if (unlikely(!mboxq->sge_array)) { + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, + "2526 Failed to get the non-embedded SGE " + "virtual address\n"); + lpfc_sli4_mbox_cmd_free(phba, mboxq); + return -ENOMEM; + } + virt_addr = mboxq->sge_array->addr[0]; + /* + * Configure the FCF record for FCFI 0. This is the driver's + * hardcoded default and gets used in nonFIP mode. + */ + fcfindex = bf_get(lpfc_fcf_record_fcf_index, fcf_record); + bytep = virt_addr + sizeof(union lpfc_sli4_cfg_shdr); + lpfc_sli_pcimem_bcopy(&fcfindex, bytep, sizeof(uint32_t)); + + /* + * Copy the fcf_index and the FCF Record Data. The data starts after + * the FCoE header plus word10. The data copy needs to be endian + * correct. + */ + bytep += sizeof(uint32_t); + lpfc_sli_pcimem_bcopy(fcf_record, bytep, sizeof(struct fcf_record)); + mboxq->vport = phba->pport; + mboxq->mbox_cmpl = lpfc_mbx_cmpl_add_fcf_record; + rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT); + if (rc == MBX_NOT_FINISHED) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2515 ADD_FCF_RECORD mailbox failed with " + "status 0x%x\n", rc); + lpfc_sli4_mbox_cmd_free(phba, mboxq); + rc = -EIO; + } else + rc = 0; + + return rc; +} + +/** + * lpfc_sli4_build_dflt_fcf_record - Build the driver's default FCF Record. + * @phba: pointer to lpfc hba data structure. + * @fcf_record: pointer to the fcf record to write the default data. + * @fcf_index: FCF table entry index. + * + * This routine is invoked to build the driver's default FCF record. The + * values used are hardcoded. This routine handles memory initialization. + * + **/ +void +lpfc_sli4_build_dflt_fcf_record(struct lpfc_hba *phba, + struct fcf_record *fcf_record, + uint16_t fcf_index) +{ + memset(fcf_record, 0, sizeof(struct fcf_record)); + fcf_record->max_rcv_size = LPFC_FCOE_MAX_RCV_SIZE; + fcf_record->fka_adv_period = LPFC_FCOE_FKA_ADV_PER; + fcf_record->fip_priority = LPFC_FCOE_FIP_PRIORITY; + bf_set(lpfc_fcf_record_mac_0, fcf_record, phba->fc_map[0]); + bf_set(lpfc_fcf_record_mac_1, fcf_record, phba->fc_map[1]); + bf_set(lpfc_fcf_record_mac_2, fcf_record, phba->fc_map[2]); + bf_set(lpfc_fcf_record_mac_3, fcf_record, LPFC_FCOE_FCF_MAC3); + bf_set(lpfc_fcf_record_mac_4, fcf_record, LPFC_FCOE_FCF_MAC4); + bf_set(lpfc_fcf_record_mac_5, fcf_record, LPFC_FCOE_FCF_MAC5); + bf_set(lpfc_fcf_record_fc_map_0, fcf_record, phba->fc_map[0]); + bf_set(lpfc_fcf_record_fc_map_1, fcf_record, phba->fc_map[1]); + bf_set(lpfc_fcf_record_fc_map_2, fcf_record, phba->fc_map[2]); + bf_set(lpfc_fcf_record_fcf_valid, fcf_record, 1); + bf_set(lpfc_fcf_record_fcf_avail, fcf_record, 1); + bf_set(lpfc_fcf_record_fcf_index, fcf_record, fcf_index); + bf_set(lpfc_fcf_record_mac_addr_prov, fcf_record, + LPFC_FCF_FPMA | LPFC_FCF_SPMA); + /* Set the VLAN bit map */ + if (phba->valid_vlan) { + fcf_record->vlan_bitmap[phba->vlan_id / 8] + = 1 << (phba->vlan_id % 8); + } +} + +/** + * lpfc_sli4_read_fcf_record - Read the driver's default FCF Record. + * @phba: pointer to lpfc hba data structure. + * @fcf_index: FCF table entry offset. + * + * This routine is invoked to read up to @fcf_num of FCF record from the + * device starting with the given @fcf_index. + **/ +int +lpfc_sli4_read_fcf_record(struct lpfc_hba *phba, uint16_t fcf_index) +{ + int rc = 0, error; + LPFC_MBOXQ_t *mboxq; + void *virt_addr; + dma_addr_t phys_addr; + uint8_t *bytep; + struct lpfc_mbx_sge sge; + uint32_t alloc_len, req_len; + struct lpfc_mbx_read_fcf_tbl *read_fcf; + + mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mboxq) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2000 Failed to allocate mbox for " + "READ_FCF cmd\n"); + return -ENOMEM; + } + + req_len = sizeof(struct fcf_record) + + sizeof(union lpfc_sli4_cfg_shdr) + 2 * sizeof(uint32_t); + + /* Set up READ_FCF SLI4_CONFIG mailbox-ioctl command */ + alloc_len = lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_FCOE, + LPFC_MBOX_OPCODE_FCOE_READ_FCF_TABLE, req_len, + LPFC_SLI4_MBX_NEMBED); + + if (alloc_len < req_len) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0291 Allocated DMA memory size (x%x) is " + "less than the requested DMA memory " + "size (x%x)\n", alloc_len, req_len); + lpfc_sli4_mbox_cmd_free(phba, mboxq); + return -ENOMEM; + } + + /* Get the first SGE entry from the non-embedded DMA memory. This + * routine only uses a single SGE. + */ + lpfc_sli4_mbx_sge_get(mboxq, 0, &sge); + phys_addr = getPaddr(sge.pa_hi, sge.pa_lo); + if (unlikely(!mboxq->sge_array)) { + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, + "2527 Failed to get the non-embedded SGE " + "virtual address\n"); + lpfc_sli4_mbox_cmd_free(phba, mboxq); + return -ENOMEM; + } + virt_addr = mboxq->sge_array->addr[0]; + read_fcf = (struct lpfc_mbx_read_fcf_tbl *)virt_addr; + + /* Set up command fields */ + bf_set(lpfc_mbx_read_fcf_tbl_indx, &read_fcf->u.request, fcf_index); + /* Perform necessary endian conversion */ + bytep = virt_addr + sizeof(union lpfc_sli4_cfg_shdr); + lpfc_sli_pcimem_bcopy(bytep, bytep, sizeof(uint32_t)); + mboxq->vport = phba->pport; + mboxq->mbox_cmpl = lpfc_mbx_cmpl_read_fcf_record; + rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT); + if (rc == MBX_NOT_FINISHED) { + lpfc_sli4_mbox_cmd_free(phba, mboxq); + error = -EIO; + } else + error = 0; + return error; +} diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h index 883938652a6a..3c53316cf6d0 100644 --- a/drivers/scsi/lpfc/lpfc_sli.h +++ b/drivers/scsi/lpfc/lpfc_sli.h @@ -29,13 +29,23 @@ typedef enum _lpfc_ctx_cmd { LPFC_CTX_HOST } lpfc_ctx_cmd; +/* This structure is used to carry the needed response IOCB states */ +struct lpfc_sli4_rspiocb_info { + uint8_t hw_status; + uint8_t bfield; +#define LPFC_XB 0x1 +#define LPFC_PV 0x2 + uint8_t priority; + uint8_t reserved; +}; + /* This structure is used to handle IOCB requests / responses */ struct lpfc_iocbq { /* lpfc_iocbqs are used in double linked lists */ struct list_head list; struct list_head clist; uint16_t iotag; /* pre-assigned IO tag */ - uint16_t rsvd1; + uint16_t sli4_xritag; /* pre-assigned XRI, (OXID) tag. */ IOCB_t iocb; /* IOCB cmd */ uint8_t retry; /* retry counter for IOCB cmd - if needed */ @@ -46,6 +56,7 @@ struct lpfc_iocbq { #define LPFC_DRIVER_ABORTED 8 /* driver aborted this request */ #define LPFC_IO_FABRIC 0x10 /* Iocb send using fabric scheduler */ #define LPFC_DELAY_MEM_FREE 0x20 /* Defer free'ing of FC data */ +#define LPFC_FIP_ELS 0x40 uint8_t abort_count; uint8_t rsvd2; @@ -65,7 +76,7 @@ struct lpfc_iocbq { struct lpfc_iocbq *); void (*iocb_cmpl) (struct lpfc_hba *, struct lpfc_iocbq *, struct lpfc_iocbq *); - + struct lpfc_sli4_rspiocb_info sli4_info; }; #define SLI_IOCB_RET_IOCB 1 /* Return IOCB if cmd ring full */ @@ -81,14 +92,18 @@ struct lpfc_iocbq { typedef struct lpfcMboxq { /* MBOXQs are used in single linked lists */ struct list_head list; /* ptr to next mailbox command */ - MAILBOX_t mb; /* Mailbox cmd */ - struct lpfc_vport *vport;/* virutal port pointer */ + union { + MAILBOX_t mb; /* Mailbox cmd */ + struct lpfc_mqe mqe; + } u; + struct lpfc_vport *vport;/* virtual port pointer */ void *context1; /* caller context information */ void *context2; /* caller context information */ void (*mbox_cmpl) (struct lpfc_hba *, struct lpfcMboxq *); uint8_t mbox_flag; - + struct lpfc_mcqe mcqe; + struct lpfc_mbx_nembed_sge_virt *sge_array; } LPFC_MBOXQ_t; #define MBX_POLL 1 /* poll mailbox till command done, then @@ -230,10 +245,11 @@ struct lpfc_sli { /* Additional sli_flags */ #define LPFC_SLI_MBOX_ACTIVE 0x100 /* HBA mailbox is currently active */ -#define LPFC_SLI2_ACTIVE 0x200 /* SLI2 overlay in firmware is active */ +#define LPFC_SLI_ACTIVE 0x200 /* SLI in firmware is active */ #define LPFC_PROCESS_LA 0x400 /* Able to process link attention */ #define LPFC_BLOCK_MGMT_IO 0x800 /* Don't allow mgmt mbx or iocb cmds */ #define LPFC_MENLO_MAINT 0x1000 /* need for menl fw download */ +#define LPFC_SLI_ASYNC_MBX_BLK 0x2000 /* Async mailbox is blocked */ struct lpfc_sli_ring ring[LPFC_MAX_RING]; int fcp_ring; /* ring used for FCP initiator commands */ @@ -261,6 +277,8 @@ struct lpfc_sli { #define LPFC_MBOX_TMO 30 /* Sec tmo for outstanding mbox command */ +#define LPFC_MBOX_SLI4_CONFIG_TMO 60 /* Sec tmo for outstanding mbox + command */ #define LPFC_MBOX_TMO_FLASH_CMD 300 /* Sec tmo for outstanding FLASH write * or erase cmds. This is especially * long because of the potential of diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h new file mode 100644 index 000000000000..3b276b47d18f --- /dev/null +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -0,0 +1,467 @@ +/******************************************************************* + * This file is part of the Emulex Linux Device Driver for * + * Fibre Channel Host Bus Adapters. * + * Copyright (C) 2009 Emulex. All rights reserved. * + * EMULEX and SLI are trademarks of Emulex. * + * www.emulex.com * + * * + * 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. * + * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * + * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * + * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * + * TO BE LEGALLY INVALID. See the GNU General Public License for * + * more details, a copy of which can be found in the file COPYING * + * included with this package. * + *******************************************************************/ + +#define LPFC_ACTIVE_MBOX_WAIT_CNT 100 +#define LPFC_RELEASE_NOTIFICATION_INTERVAL 32 +#define LPFC_GET_QE_REL_INT 32 +#define LPFC_RPI_LOW_WATER_MARK 10 +/* Number of SGL entries can be posted in a 4KB nonembedded mbox command */ +#define LPFC_NEMBED_MBOX_SGL_CNT 254 + +/* Multi-queue arrangement for fast-path FCP work queues */ +#define LPFC_FN_EQN_MAX 8 +#define LPFC_SP_EQN_DEF 1 +#define LPFC_FP_EQN_DEF 1 +#define LPFC_FP_EQN_MIN 1 +#define LPFC_FP_EQN_MAX (LPFC_FN_EQN_MAX - LPFC_SP_EQN_DEF) + +#define LPFC_FN_WQN_MAX 32 +#define LPFC_SP_WQN_DEF 1 +#define LPFC_FP_WQN_DEF 4 +#define LPFC_FP_WQN_MIN 1 +#define LPFC_FP_WQN_MAX (LPFC_FN_WQN_MAX - LPFC_SP_WQN_DEF) + +/* + * Provide the default FCF Record attributes used by the driver + * when nonFIP mode is configured and there is no other default + * FCF Record attributes. + */ +#define LPFC_FCOE_FCF_DEF_INDEX 0 +#define LPFC_FCOE_FCF_GET_FIRST 0xFFFF +#define LPFC_FCOE_FCF_NEXT_NONE 0xFFFF + +/* First 3 bytes of default FCF MAC is specified by FC_MAP */ +#define LPFC_FCOE_FCF_MAC3 0xFF +#define LPFC_FCOE_FCF_MAC4 0xFF +#define LPFC_FCOE_FCF_MAC5 0xFE +#define LPFC_FCOE_FCF_MAP0 0x0E +#define LPFC_FCOE_FCF_MAP1 0xFC +#define LPFC_FCOE_FCF_MAP2 0x00 +#define LPFC_FCOE_MAX_RCV_SIZE 0x5AC +#define LPFC_FCOE_FKA_ADV_PER 0 +#define LPFC_FCOE_FIP_PRIORITY 0x80 + +enum lpfc_sli4_queue_type { + LPFC_EQ, + LPFC_GCQ, + LPFC_MCQ, + LPFC_WCQ, + LPFC_RCQ, + LPFC_MQ, + LPFC_WQ, + LPFC_HRQ, + LPFC_DRQ +}; + +/* The queue sub-type defines the functional purpose of the queue */ +enum lpfc_sli4_queue_subtype { + LPFC_NONE, + LPFC_MBOX, + LPFC_FCP, + LPFC_ELS, + LPFC_USOL +}; + +union sli4_qe { + void *address; + struct lpfc_eqe *eqe; + struct lpfc_cqe *cqe; + struct lpfc_mcqe *mcqe; + struct lpfc_wcqe_complete *wcqe_complete; + struct lpfc_wcqe_release *wcqe_release; + struct sli4_wcqe_xri_aborted *wcqe_xri_aborted; + struct lpfc_rcqe_complete *rcqe_complete; + struct lpfc_mqe *mqe; + union lpfc_wqe *wqe; + struct lpfc_rqe *rqe; +}; + +struct lpfc_queue { + struct list_head list; + enum lpfc_sli4_queue_type type; + enum lpfc_sli4_queue_subtype subtype; + struct lpfc_hba *phba; + struct list_head child_list; + uint32_t entry_count; /* Number of entries to support on the queue */ + uint32_t entry_size; /* Size of each queue entry. */ + uint32_t queue_id; /* Queue ID assigned by the hardware */ + struct list_head page_list; + uint32_t page_count; /* Number of pages allocated for this queue */ + + uint32_t host_index; /* The host's index for putting or getting */ + uint32_t hba_index; /* The last known hba index for get or put */ + union sli4_qe qe[1]; /* array to index entries (must be last) */ +}; + +struct lpfc_cq_event { + struct list_head list; + union { + struct lpfc_mcqe mcqe_cmpl; + struct lpfc_acqe_link acqe_link; + struct lpfc_acqe_fcoe acqe_fcoe; + struct lpfc_acqe_dcbx acqe_dcbx; + struct lpfc_rcqe rcqe_cmpl; + struct sli4_wcqe_xri_aborted wcqe_axri; + } cqe; +}; + +struct lpfc_sli4_link { + uint8_t speed; + uint8_t duplex; + uint8_t status; + uint8_t physical; + uint8_t fault; +}; + +struct lpfc_fcf { + uint8_t fabric_name[8]; + uint8_t mac_addr[6]; + uint16_t fcf_indx; + uint16_t fcfi; + uint32_t fcf_flag; +#define FCF_AVAILABLE 0x01 /* FCF available for discovery */ +#define FCF_REGISTERED 0x02 /* FCF registered with FW */ +#define FCF_DISCOVERED 0x04 /* FCF discovery started */ +#define FCF_BOOT_ENABLE 0x08 /* Boot bios use this FCF */ +#define FCF_IN_USE 0x10 /* Atleast one discovery completed */ +#define FCF_VALID_VLAN 0x20 /* Use the vlan id specified */ + uint32_t priority; + uint32_t addr_mode; + uint16_t vlan_id; +}; + +#define LPFC_REGION23_SIGNATURE "RG23" +#define LPFC_REGION23_VERSION 1 +#define LPFC_REGION23_LAST_REC 0xff +struct lpfc_fip_param_hdr { + uint8_t type; +#define FCOE_PARAM_TYPE 0xA0 + uint8_t length; +#define FCOE_PARAM_LENGTH 2 + uint8_t parm_version; +#define FIPP_VERSION 0x01 + uint8_t parm_flags; +#define lpfc_fip_param_hdr_fipp_mode_SHIFT 6 +#define lpfc_fip_param_hdr_fipp_mode_MASK 0x3 +#define lpfc_fip_param_hdr_fipp_mode_WORD parm_flags +#define FIPP_MODE_ON 0x2 +#define FIPP_MODE_OFF 0x0 +#define FIPP_VLAN_VALID 0x1 +}; + +struct lpfc_fcoe_params { + uint8_t fc_map[3]; + uint8_t reserved1; + uint16_t vlan_tag; + uint8_t reserved[2]; +}; + +struct lpfc_fcf_conn_hdr { + uint8_t type; +#define FCOE_CONN_TBL_TYPE 0xA1 + uint8_t length; /* words */ + uint8_t reserved[2]; +}; + +struct lpfc_fcf_conn_rec { + uint16_t flags; +#define FCFCNCT_VALID 0x0001 +#define FCFCNCT_BOOT 0x0002 +#define FCFCNCT_PRIMARY 0x0004 /* if not set, Secondary */ +#define FCFCNCT_FBNM_VALID 0x0008 +#define FCFCNCT_SWNM_VALID 0x0010 +#define FCFCNCT_VLAN_VALID 0x0020 +#define FCFCNCT_AM_VALID 0x0040 +#define FCFCNCT_AM_PREFERRED 0x0080 /* if not set, AM Required */ +#define FCFCNCT_AM_SPMA 0x0100 /* if not set, FPMA */ + + uint16_t vlan_tag; + uint8_t fabric_name[8]; + uint8_t switch_name[8]; +}; + +struct lpfc_fcf_conn_entry { + struct list_head list; + struct lpfc_fcf_conn_rec conn_rec; +}; + +/* + * Define the host's bootstrap mailbox. This structure contains + * the member attributes needed to create, use, and destroy the + * bootstrap mailbox region. + * + * The macro definitions for the bmbx data structure are defined + * in lpfc_hw4.h with the register definition. + */ +struct lpfc_bmbx { + struct lpfc_dmabuf *dmabuf; + struct dma_address dma_address; + void *avirt; + dma_addr_t aphys; + uint32_t bmbx_size; +}; + +#define LPFC_EQE_SIZE LPFC_EQE_SIZE_4 + +#define LPFC_EQE_SIZE_4B 4 +#define LPFC_EQE_SIZE_16B 16 +#define LPFC_CQE_SIZE 16 +#define LPFC_WQE_SIZE 64 +#define LPFC_MQE_SIZE 256 +#define LPFC_RQE_SIZE 8 + +#define LPFC_EQE_DEF_COUNT 1024 +#define LPFC_CQE_DEF_COUNT 256 +#define LPFC_WQE_DEF_COUNT 256 +#define LPFC_MQE_DEF_COUNT 16 +#define LPFC_RQE_DEF_COUNT 512 + +#define LPFC_QUEUE_NOARM false +#define LPFC_QUEUE_REARM true + + +/* + * SLI4 CT field defines + */ +#define SLI4_CT_RPI 0 +#define SLI4_CT_VPI 1 +#define SLI4_CT_VFI 2 +#define SLI4_CT_FCFI 3 + +#define LPFC_SLI4_MAX_SEGMENT_SIZE 0x10000 + +/* + * SLI4 specific data structures + */ +struct lpfc_max_cfg_param { + uint16_t max_xri; + uint16_t xri_base; + uint16_t xri_used; + uint16_t max_rpi; + uint16_t rpi_base; + uint16_t rpi_used; + uint16_t max_vpi; + uint16_t vpi_base; + uint16_t vpi_used; + uint16_t max_vfi; + uint16_t vfi_base; + uint16_t vfi_used; + uint16_t max_fcfi; + uint16_t fcfi_base; + uint16_t fcfi_used; + uint16_t max_eq; + uint16_t max_rq; + uint16_t max_cq; + uint16_t max_wq; +}; + +struct lpfc_hba; +/* SLI4 HBA multi-fcp queue handler struct */ +struct lpfc_fcp_eq_hdl { + uint32_t idx; + struct lpfc_hba *phba; +}; + +/* SLI4 HBA data structure entries */ +struct lpfc_sli4_hba { + void __iomem *conf_regs_memmap_p; /* Kernel memory mapped address for + PCI BAR0, config space registers */ + void __iomem *ctrl_regs_memmap_p; /* Kernel memory mapped address for + PCI BAR1, control registers */ + void __iomem *drbl_regs_memmap_p; /* Kernel memory mapped address for + PCI BAR2, doorbell registers */ + /* BAR0 PCI config space register memory map */ + void __iomem *UERRLOregaddr; /* Address to UERR_STATUS_LO register */ + void __iomem *UERRHIregaddr; /* Address to UERR_STATUS_HI register */ + void __iomem *ONLINE0regaddr; /* Address to components of internal UE */ + void __iomem *ONLINE1regaddr; /* Address to components of internal UE */ +#define LPFC_ONLINE_NERR 0xFFFFFFFF + void __iomem *SCRATCHPADregaddr; /* Address to scratchpad register */ + /* BAR1 FCoE function CSR register memory map */ + void __iomem *STAregaddr; /* Address to HST_STATE register */ + void __iomem *ISRregaddr; /* Address to HST_ISR register */ + void __iomem *IMRregaddr; /* Address to HST_IMR register */ + void __iomem *ISCRregaddr; /* Address to HST_ISCR register */ + /* BAR2 VF-0 doorbell register memory map */ + void __iomem *RQDBregaddr; /* Address to RQ_DOORBELL register */ + void __iomem *WQDBregaddr; /* Address to WQ_DOORBELL register */ + void __iomem *EQCQDBregaddr; /* Address to EQCQ_DOORBELL register */ + void __iomem *MQDBregaddr; /* Address to MQ_DOORBELL register */ + void __iomem *BMBXregaddr; /* Address to BootStrap MBX register */ + + struct msix_entry *msix_entries; + uint32_t cfg_eqn; + struct lpfc_fcp_eq_hdl *fcp_eq_hdl; /* FCP per-WQ handle */ + /* Pointers to the constructed SLI4 queues */ + struct lpfc_queue **fp_eq; /* Fast-path event queue */ + struct lpfc_queue *sp_eq; /* Slow-path event queue */ + struct lpfc_queue **fcp_wq;/* Fast-path FCP work queue */ + struct lpfc_queue *mbx_wq; /* Slow-path MBOX work queue */ + struct lpfc_queue *els_wq; /* Slow-path ELS work queue */ + struct lpfc_queue *hdr_rq; /* Slow-path Header Receive queue */ + struct lpfc_queue *dat_rq; /* Slow-path Data Receive queue */ + struct lpfc_queue **fcp_cq;/* Fast-path FCP compl queue */ + struct lpfc_queue *mbx_cq; /* Slow-path mailbox complete queue */ + struct lpfc_queue *els_cq; /* Slow-path ELS response complete queue */ + struct lpfc_queue *rxq_cq; /* Slow-path unsolicited complete queue */ + + /* Setup information for various queue parameters */ + int eq_esize; + int eq_ecount; + int cq_esize; + int cq_ecount; + int wq_esize; + int wq_ecount; + int mq_esize; + int mq_ecount; + int rq_esize; + int rq_ecount; +#define LPFC_SP_EQ_MAX_INTR_SEC 10000 +#define LPFC_FP_EQ_MAX_INTR_SEC 10000 + + uint32_t intr_enable; + struct lpfc_bmbx bmbx; + struct lpfc_max_cfg_param max_cfg_param; + uint16_t next_xri; /* last_xri - max_cfg_param.xri_base = used */ + uint16_t next_rpi; + uint16_t scsi_xri_max; + uint16_t scsi_xri_cnt; + struct list_head lpfc_free_sgl_list; + struct list_head lpfc_sgl_list; + struct lpfc_sglq **lpfc_els_sgl_array; + struct list_head lpfc_abts_els_sgl_list; + struct lpfc_scsi_buf **lpfc_scsi_psb_array; + struct list_head lpfc_abts_scsi_buf_list; + uint32_t total_sglq_bufs; + struct lpfc_sglq **lpfc_sglq_active_list; + struct list_head lpfc_rpi_hdr_list; + unsigned long *rpi_bmask; + uint16_t rpi_count; + struct lpfc_sli4_flags sli4_flags; + struct list_head sp_rspiocb_work_queue; + struct list_head sp_cqe_event_pool; + struct list_head sp_asynce_work_queue; + struct list_head sp_fcp_xri_aborted_work_queue; + struct list_head sp_els_xri_aborted_work_queue; + struct list_head sp_unsol_work_queue; + struct lpfc_sli4_link link_state; + spinlock_t abts_scsi_buf_list_lock; /* list of aborted SCSI IOs */ + spinlock_t abts_sgl_list_lock; /* list of aborted els IOs */ +}; + +enum lpfc_sge_type { + GEN_BUFF_TYPE, + SCSI_BUFF_TYPE +}; + +struct lpfc_sglq { + /* lpfc_sglqs are used in double linked lists */ + struct list_head list; + struct list_head clist; + enum lpfc_sge_type buff_type; /* is this a scsi sgl */ + uint16_t iotag; /* pre-assigned IO tag */ + uint16_t sli4_xritag; /* pre-assigned XRI, (OXID) tag. */ + struct sli4_sge *sgl; /* pre-assigned SGL */ + void *virt; /* virtual address. */ + dma_addr_t phys; /* physical address */ +}; + +struct lpfc_rpi_hdr { + struct list_head list; + uint32_t len; + struct lpfc_dmabuf *dmabuf; + uint32_t page_count; + uint32_t start_rpi; +}; + +/* + * SLI4 specific function prototypes + */ +int lpfc_pci_function_reset(struct lpfc_hba *); +int lpfc_sli4_hba_setup(struct lpfc_hba *); +int lpfc_sli4_hba_down(struct lpfc_hba *); +int lpfc_sli4_config(struct lpfc_hba *, struct lpfcMboxq *, uint8_t, + uint8_t, uint32_t, bool); +void lpfc_sli4_mbox_cmd_free(struct lpfc_hba *, struct lpfcMboxq *); +void lpfc_sli4_mbx_sge_set(struct lpfcMboxq *, uint32_t, dma_addr_t, uint32_t); +void lpfc_sli4_mbx_sge_get(struct lpfcMboxq *, uint32_t, + struct lpfc_mbx_sge *); + +void lpfc_sli4_hba_reset(struct lpfc_hba *); +struct lpfc_queue *lpfc_sli4_queue_alloc(struct lpfc_hba *, uint32_t, + uint32_t); +void lpfc_sli4_queue_free(struct lpfc_queue *); +uint32_t lpfc_eq_create(struct lpfc_hba *, struct lpfc_queue *, uint16_t); +uint32_t lpfc_cq_create(struct lpfc_hba *, struct lpfc_queue *, + struct lpfc_queue *, uint32_t, uint32_t); +uint32_t lpfc_mq_create(struct lpfc_hba *, struct lpfc_queue *, + struct lpfc_queue *, uint32_t); +uint32_t lpfc_wq_create(struct lpfc_hba *, struct lpfc_queue *, + struct lpfc_queue *, uint32_t); +uint32_t lpfc_rq_create(struct lpfc_hba *, struct lpfc_queue *, + struct lpfc_queue *, struct lpfc_queue *, uint32_t); +uint32_t lpfc_eq_destroy(struct lpfc_hba *, struct lpfc_queue *); +uint32_t lpfc_cq_destroy(struct lpfc_hba *, struct lpfc_queue *); +uint32_t lpfc_mq_destroy(struct lpfc_hba *, struct lpfc_queue *); +uint32_t lpfc_wq_destroy(struct lpfc_hba *, struct lpfc_queue *); +uint32_t lpfc_rq_destroy(struct lpfc_hba *, struct lpfc_queue *, + struct lpfc_queue *); +int lpfc_sli4_queue_setup(struct lpfc_hba *); +void lpfc_sli4_queue_unset(struct lpfc_hba *); +int lpfc_sli4_post_sgl(struct lpfc_hba *, dma_addr_t, dma_addr_t, uint16_t); +int lpfc_sli4_repost_scsi_sgl_list(struct lpfc_hba *); +int lpfc_sli4_remove_all_sgl_pages(struct lpfc_hba *); +uint16_t lpfc_sli4_next_xritag(struct lpfc_hba *); +int lpfc_sli4_post_async_mbox(struct lpfc_hba *); +int lpfc_sli4_post_sgl_list(struct lpfc_hba *phba); +int lpfc_sli4_post_scsi_sgl_block(struct lpfc_hba *, struct list_head *, int); +struct lpfc_cq_event *__lpfc_sli4_cq_event_alloc(struct lpfc_hba *); +struct lpfc_cq_event *lpfc_sli4_cq_event_alloc(struct lpfc_hba *); +void __lpfc_sli4_cq_event_release(struct lpfc_hba *, struct lpfc_cq_event *); +void lpfc_sli4_cq_event_release(struct lpfc_hba *, struct lpfc_cq_event *); +int lpfc_sli4_init_rpi_hdrs(struct lpfc_hba *); +int lpfc_sli4_post_rpi_hdr(struct lpfc_hba *, struct lpfc_rpi_hdr *); +int lpfc_sli4_post_all_rpi_hdrs(struct lpfc_hba *); +struct lpfc_rpi_hdr *lpfc_sli4_create_rpi_hdr(struct lpfc_hba *); +void lpfc_sli4_remove_rpi_hdrs(struct lpfc_hba *); +int lpfc_sli4_alloc_rpi(struct lpfc_hba *); +void lpfc_sli4_free_rpi(struct lpfc_hba *, int); +void lpfc_sli4_remove_rpis(struct lpfc_hba *); +void lpfc_sli4_async_event_proc(struct lpfc_hba *); +int lpfc_sli4_resume_rpi(struct lpfc_nodelist *); +void lpfc_sli4_fcp_xri_abort_event_proc(struct lpfc_hba *); +void lpfc_sli4_els_xri_abort_event_proc(struct lpfc_hba *); +void lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *, + struct sli4_wcqe_xri_aborted *); +void lpfc_sli4_els_xri_aborted(struct lpfc_hba *, + struct sli4_wcqe_xri_aborted *); +int lpfc_sli4_brdreset(struct lpfc_hba *); +int lpfc_sli4_add_fcf_record(struct lpfc_hba *, struct fcf_record *); +void lpfc_sli_remove_dflt_fcf(struct lpfc_hba *); +int lpfc_sli4_get_els_iocb_cnt(struct lpfc_hba *); +int lpfc_sli4_init_vpi(struct lpfc_hba *, uint16_t); +uint32_t lpfc_sli4_cq_release(struct lpfc_queue *, bool); +uint32_t lpfc_sli4_eq_release(struct lpfc_queue *, bool); +void lpfc_sli4_fcfi_unreg(struct lpfc_hba *, uint16_t); +int lpfc_sli4_read_fcf_record(struct lpfc_hba *, uint16_t); +void lpfc_mbx_cmpl_read_fcf_record(struct lpfc_hba *, LPFC_MBOXQ_t *); +int lpfc_sli4_post_status_check(struct lpfc_hba *); +uint8_t lpfc_sli4_mbox_opcode_get(struct lpfc_hba *, struct lpfcMboxq *); + diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index e599519e3078..41094e02304b 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -18,7 +18,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "8.3.1" +#define LPFC_DRIVER_VERSION "8.3.3" #define LPFC_DRIVER_NAME "lpfc" #define LPFC_SP_DRIVER_HANDLER_NAME "lpfc:sp" diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c index 917ad56b0aff..e0b49922193e 100644 --- a/drivers/scsi/lpfc/lpfc_vport.c +++ b/drivers/scsi/lpfc/lpfc_vport.c @@ -32,8 +32,10 @@ #include #include #include +#include "lpfc_hw4.h" #include "lpfc_hw.h" #include "lpfc_sli.h" +#include "lpfc_sli4.h" #include "lpfc_nl.h" #include "lpfc_disc.h" #include "lpfc_scsi.h" @@ -89,6 +91,8 @@ lpfc_alloc_vpi(struct lpfc_hba *phba) vpi = 0; else set_bit(vpi, phba->vpi_bmask); + if (phba->sli_rev == LPFC_SLI_REV4) + phba->sli4_hba.max_cfg_param.vpi_used++; spin_unlock_irq(&phba->hbalock); return vpi; } @@ -96,8 +100,12 @@ lpfc_alloc_vpi(struct lpfc_hba *phba) static void lpfc_free_vpi(struct lpfc_hba *phba, int vpi) { + if (vpi == 0) + return; spin_lock_irq(&phba->hbalock); clear_bit(vpi, phba->vpi_bmask); + if (phba->sli_rev == LPFC_SLI_REV4) + phba->sli4_hba.max_cfg_param.vpi_used--; spin_unlock_irq(&phba->hbalock); } @@ -113,7 +121,7 @@ lpfc_vport_sparm(struct lpfc_hba *phba, struct lpfc_vport *vport) if (!pmb) { return -ENOMEM; } - mb = &pmb->mb; + mb = &pmb->u.mb; lpfc_read_sparam(phba, pmb, vport->vpi); /* @@ -243,23 +251,22 @@ static void lpfc_discovery_wait(struct lpfc_vport *vport) (vport->fc_flag & wait_flags) || ((vport->port_state > LPFC_VPORT_FAILED) && (vport->port_state < LPFC_VPORT_READY))) { - lpfc_printf_log(phba, KERN_INFO, LOG_VPORT, + lpfc_printf_vlog(vport, KERN_INFO, LOG_VPORT, "1833 Vport discovery quiesce Wait:" - " vpi x%x state x%x fc_flags x%x" + " state x%x fc_flags x%x" " num_nodes x%x, waiting 1000 msecs" " total wait msecs x%x\n", - vport->vpi, vport->port_state, - vport->fc_flag, vport->num_disc_nodes, + vport->port_state, vport->fc_flag, + vport->num_disc_nodes, jiffies_to_msecs(jiffies - start_time)); msleep(1000); } else { /* Base case. Wait variants satisfied. Break out */ - lpfc_printf_log(phba, KERN_INFO, LOG_VPORT, + lpfc_printf_vlog(vport, KERN_INFO, LOG_VPORT, "1834 Vport discovery quiesced:" - " vpi x%x state x%x fc_flags x%x" + " state x%x fc_flags x%x" " wait msecs x%x\n", - vport->vpi, vport->port_state, - vport->fc_flag, + vport->port_state, vport->fc_flag, jiffies_to_msecs(jiffies - start_time)); break; @@ -267,12 +274,10 @@ static void lpfc_discovery_wait(struct lpfc_vport *vport) } if (time_after(jiffies, wait_time_max)) - lpfc_printf_log(phba, KERN_ERR, LOG_VPORT, + lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT, "1835 Vport discovery quiesce failed:" - " vpi x%x state x%x fc_flags x%x" - " wait msecs x%x\n", - vport->vpi, vport->port_state, - vport->fc_flag, + " state x%x fc_flags x%x wait msecs x%x\n", + vport->port_state, vport->fc_flag, jiffies_to_msecs(jiffies - start_time)); } @@ -308,6 +313,21 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable) goto error_out; } + /* + * In SLI4, the vpi must be activated before it can be used + * by the port. + */ + if (phba->sli_rev == LPFC_SLI_REV4) { + rc = lpfc_sli4_init_vpi(phba, vpi); + if (rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_VPORT, + "1838 Failed to INIT_VPI on vpi %d " + "status %d\n", vpi, rc); + rc = VPORT_NORESOURCES; + lpfc_free_vpi(phba, vpi); + goto error_out; + } + } /* Assign an unused board number */ if ((instance = lpfc_get_instance()) < 0) { @@ -535,6 +555,16 @@ lpfc_vport_delete(struct fc_vport *fc_vport) "physical host\n"); return VPORT_ERROR; } + + /* If the vport is a static vport fail the deletion. */ + if ((vport->vport_flag & STATIC_VPORT) && + !(phba->pport->load_flag & FC_UNLOADING)) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT, + "1837 vport_delete failed: Cannot delete " + "static vport.\n"); + return VPORT_ERROR; + } + /* * If we are not unloading the driver then prevent the vport_delete * from happening until after this vport's discovery is finished. @@ -665,8 +695,6 @@ lpfc_vport_delete(struct fc_vport *fc_vport) } vport->unreg_vpi_cmpl = VPORT_INVAL; timeout = msecs_to_jiffies(phba->fc_ratov * 2000); - if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) - goto skip_logo; if (!lpfc_issue_els_npiv_logo(vport, ndlp)) while (vport->unreg_vpi_cmpl == VPORT_INVAL && timeout) timeout = schedule_timeout(timeout); @@ -710,7 +738,7 @@ lpfc_create_vport_work_array(struct lpfc_hba *phba) struct lpfc_vport *port_iterator; struct lpfc_vport **vports; int index = 0; - vports = kzalloc((phba->max_vpi + 1) * sizeof(struct lpfc_vport *), + vports = kzalloc((phba->max_vports + 1) * sizeof(struct lpfc_vport *), GFP_KERNEL); if (vports == NULL) return NULL; @@ -734,7 +762,7 @@ lpfc_destroy_vport_work_array(struct lpfc_hba *phba, struct lpfc_vport **vports) int i; if (vports == NULL) return; - for (i=0; vports[i] != NULL && i <= phba->max_vpi; i++) + for (i = 0; vports[i] != NULL && i <= phba->max_vports; i++) scsi_host_put(lpfc_shost_from_vport(vports[i])); kfree(vports); } diff --git a/drivers/scsi/megaraid.h b/drivers/scsi/megaraid.h index 795201fa0b48..512c2cc1a33f 100644 --- a/drivers/scsi/megaraid.h +++ b/drivers/scsi/megaraid.h @@ -469,7 +469,7 @@ typedef struct { u8 type; /* Type of the device */ u8 cur_status; /* current status of the device */ u8 tag_depth; /* Level of tagging */ - u8 sync_neg; /* sync negotiation - ENABLE or DISBALE */ + u8 sync_neg; /* sync negotiation - ENABLE or DISABLE */ u32 size; /* configurable size in terms of 512 byte blocks */ }__attribute__ ((packed)) phys_drv; diff --git a/drivers/scsi/megaraid/mbox_defs.h b/drivers/scsi/megaraid/mbox_defs.h index 170399ef06f4..b25b74764ec3 100644 --- a/drivers/scsi/megaraid/mbox_defs.h +++ b/drivers/scsi/megaraid/mbox_defs.h @@ -686,7 +686,7 @@ typedef struct { * @type : Type of the device * @cur_status : current status of the device * @tag_depth : Level of tagging - * @sync_neg : sync negotiation - ENABLE or DISBALE + * @sync_neg : sync negotiation - ENABLE or DISABLE * @size : configurable size in terms of 512 byte */ typedef struct { diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h index 36b1d1052ba1..286c185fa9e4 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.h +++ b/drivers/scsi/mpt2sas/mpt2sas_base.h @@ -61,6 +61,7 @@ #include #include #include +#include #include "mpt2sas_debug.h" @@ -68,10 +69,10 @@ #define MPT2SAS_DRIVER_NAME "mpt2sas" #define MPT2SAS_AUTHOR "LSI Corporation " #define MPT2SAS_DESCRIPTION "LSI MPT Fusion SAS 2.0 Device Driver" -#define MPT2SAS_DRIVER_VERSION "01.100.02.00" +#define MPT2SAS_DRIVER_VERSION "01.100.03.00" #define MPT2SAS_MAJOR_VERSION 01 #define MPT2SAS_MINOR_VERSION 100 -#define MPT2SAS_BUILD_VERSION 02 +#define MPT2SAS_BUILD_VERSION 03 #define MPT2SAS_RELEASE_VERSION 00 /* diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c index ba6ab170bdf0..14e473d1fa7b 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c +++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c @@ -473,7 +473,7 @@ _ctl_poll(struct file *filep, poll_table *wait) } /** - * _ctl_do_task_abort - assign an active smid to the abort_task + * _ctl_set_task_mid - assign an active smid to tm request * @ioc: per adapter object * @karg - (struct mpt2_ioctl_command) * @tm_request - pointer to mf from user space @@ -482,7 +482,7 @@ _ctl_poll(struct file *filep, poll_table *wait) * during failure, the reply frame is filled. */ static int -_ctl_do_task_abort(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command *karg, +_ctl_set_task_mid(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command *karg, Mpi2SCSITaskManagementRequest_t *tm_request) { u8 found = 0; @@ -494,6 +494,14 @@ _ctl_do_task_abort(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command *karg, Mpi2SCSITaskManagementReply_t *tm_reply; u32 sz; u32 lun; + char *desc = NULL; + + if (tm_request->TaskType == MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK) + desc = "abort_task"; + else if (tm_request->TaskType == MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK) + desc = "query_task"; + else + return 0; lun = scsilun_to_int((struct scsi_lun *)tm_request->LUN); @@ -517,13 +525,13 @@ _ctl_do_task_abort(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command *karg, spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); if (!found) { - dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "ABORT_TASK: " - "DevHandle(0x%04x), lun(%d), no active mid!!\n", ioc->name, - tm_request->DevHandle, lun)); + dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " + "handle(0x%04x), lun(%d), no active mid!!\n", ioc->name, + desc, tm_request->DevHandle, lun)); tm_reply = ioc->ctl_cmds.reply; tm_reply->DevHandle = tm_request->DevHandle; tm_reply->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; - tm_reply->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK; + tm_reply->TaskType = tm_request->TaskType; tm_reply->MsgLength = sizeof(Mpi2SCSITaskManagementReply_t)/4; tm_reply->VP_ID = tm_request->VP_ID; tm_reply->VF_ID = tm_request->VF_ID; @@ -535,9 +543,9 @@ _ctl_do_task_abort(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command *karg, return 1; } - dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "ABORT_TASK: " - "DevHandle(0x%04x), lun(%d), smid(%d)\n", ioc->name, - tm_request->DevHandle, lun, tm_request->TaskMID)); + dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " + "handle(0x%04x), lun(%d), task_mid(%d)\n", ioc->name, + desc, tm_request->DevHandle, lun, tm_request->TaskMID)); return 0; } @@ -739,8 +747,10 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, (Mpi2SCSITaskManagementRequest_t *)mpi_request; if (tm_request->TaskType == - MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK) { - if (_ctl_do_task_abort(ioc, &karg, tm_request)) { + MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK || + tm_request->TaskType == + MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK) { + if (_ctl_set_task_mid(ioc, &karg, tm_request)) { mpt2sas_base_free_smid(ioc, smid); goto out; } diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index e3a7967259e7..2a01a5f2a84d 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -197,12 +197,12 @@ static struct pci_device_id scsih_pci_table[] = { MODULE_DEVICE_TABLE(pci, scsih_pci_table); /** - * scsih_set_debug_level - global setting of ioc->logging_level. + * _scsih_set_debug_level - global setting of ioc->logging_level. * * Note: The logging levels are defined in mpt2sas_debug.h. */ static int -scsih_set_debug_level(const char *val, struct kernel_param *kp) +_scsih_set_debug_level(const char *val, struct kernel_param *kp) { int ret = param_set_int(val, kp); struct MPT2SAS_ADAPTER *ioc; @@ -215,7 +215,7 @@ scsih_set_debug_level(const char *val, struct kernel_param *kp) ioc->logging_level = logging_level; return 0; } -module_param_call(logging_level, scsih_set_debug_level, param_get_int, +module_param_call(logging_level, _scsih_set_debug_level, param_get_int, &logging_level, 0644); /** @@ -883,6 +883,41 @@ _scsih_scsi_lookup_find_by_target(struct MPT2SAS_ADAPTER *ioc, int id, return found; } +/** + * _scsih_scsi_lookup_find_by_lun - search for matching channel:id:lun + * @ioc: per adapter object + * @id: target id + * @lun: lun number + * @channel: channel + * Context: This function will acquire ioc->scsi_lookup_lock. + * + * This will search for a matching channel:id:lun in the scsi_lookup array, + * returning 1 if found. + */ +static u8 +_scsih_scsi_lookup_find_by_lun(struct MPT2SAS_ADAPTER *ioc, int id, + unsigned int lun, int channel) +{ + u8 found; + unsigned long flags; + int i; + + spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); + found = 0; + for (i = 0 ; i < ioc->request_depth; i++) { + if (ioc->scsi_lookup[i].scmd && + (ioc->scsi_lookup[i].scmd->device->id == id && + ioc->scsi_lookup[i].scmd->device->channel == channel && + ioc->scsi_lookup[i].scmd->device->lun == lun)) { + found = 1; + goto out; + } + } + out: + spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); + return found; +} + /** * _scsih_get_chain_buffer_dma - obtain block of chains (dma address) * @ioc: per adapter object @@ -1047,14 +1082,14 @@ _scsih_build_scatter_gather(struct MPT2SAS_ADAPTER *ioc, } /** - * scsih_change_queue_depth - setting device queue depth + * _scsih_change_queue_depth - setting device queue depth * @sdev: scsi device struct * @qdepth: requested queue depth * * Returns queue depth. */ static int -scsih_change_queue_depth(struct scsi_device *sdev, int qdepth) +_scsih_change_queue_depth(struct scsi_device *sdev, int qdepth) { struct Scsi_Host *shost = sdev->host; int max_depth; @@ -1079,14 +1114,14 @@ scsih_change_queue_depth(struct scsi_device *sdev, int qdepth) } /** - * scsih_change_queue_depth - changing device queue tag type + * _scsih_change_queue_depth - changing device queue tag type * @sdev: scsi device struct * @tag_type: requested tag type * * Returns queue tag type. */ static int -scsih_change_queue_type(struct scsi_device *sdev, int tag_type) +_scsih_change_queue_type(struct scsi_device *sdev, int tag_type) { if (sdev->tagged_supported) { scsi_set_tag_type(sdev, tag_type); @@ -1101,14 +1136,14 @@ scsih_change_queue_type(struct scsi_device *sdev, int tag_type) } /** - * scsih_target_alloc - target add routine + * _scsih_target_alloc - target add routine * @starget: scsi target struct * * Returns 0 if ok. Any other return is assumed to be an error and * the device is ignored. */ static int -scsih_target_alloc(struct scsi_target *starget) +_scsih_target_alloc(struct scsi_target *starget) { struct Scsi_Host *shost = dev_to_shost(&starget->dev); struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); @@ -1163,13 +1198,13 @@ scsih_target_alloc(struct scsi_target *starget) } /** - * scsih_target_destroy - target destroy routine + * _scsih_target_destroy - target destroy routine * @starget: scsi target struct * * Returns nothing. */ static void -scsih_target_destroy(struct scsi_target *starget) +_scsih_target_destroy(struct scsi_target *starget) { struct Scsi_Host *shost = dev_to_shost(&starget->dev); struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); @@ -1212,14 +1247,14 @@ scsih_target_destroy(struct scsi_target *starget) } /** - * scsih_slave_alloc - device add routine + * _scsih_slave_alloc - device add routine * @sdev: scsi device struct * * Returns 0 if ok. Any other return is assumed to be an error and * the device is ignored. */ static int -scsih_slave_alloc(struct scsi_device *sdev) +_scsih_slave_alloc(struct scsi_device *sdev) { struct Scsi_Host *shost; struct MPT2SAS_ADAPTER *ioc; @@ -1273,13 +1308,13 @@ scsih_slave_alloc(struct scsi_device *sdev) } /** - * scsih_slave_destroy - device destroy routine + * _scsih_slave_destroy - device destroy routine * @sdev: scsi device struct * * Returns nothing. */ static void -scsih_slave_destroy(struct scsi_device *sdev) +_scsih_slave_destroy(struct scsi_device *sdev) { struct MPT2SAS_TARGET *sas_target_priv_data; struct scsi_target *starget; @@ -1295,13 +1330,13 @@ scsih_slave_destroy(struct scsi_device *sdev) } /** - * scsih_display_sata_capabilities - sata capabilities + * _scsih_display_sata_capabilities - sata capabilities * @ioc: per adapter object * @sas_device: the sas_device object * @sdev: scsi device struct */ static void -scsih_display_sata_capabilities(struct MPT2SAS_ADAPTER *ioc, +_scsih_display_sata_capabilities(struct MPT2SAS_ADAPTER *ioc, struct _sas_device *sas_device, struct scsi_device *sdev) { Mpi2ConfigReply_t mpi_reply; @@ -1401,14 +1436,14 @@ _scsih_get_volume_capabilities(struct MPT2SAS_ADAPTER *ioc, } /** - * scsih_slave_configure - device configure routine. + * _scsih_slave_configure - device configure routine. * @sdev: scsi device struct * * Returns 0 if ok. Any other return is assumed to be an error and * the device is ignored. */ static int -scsih_slave_configure(struct scsi_device *sdev) +_scsih_slave_configure(struct scsi_device *sdev) { struct Scsi_Host *shost = sdev->host; struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); @@ -1489,7 +1524,7 @@ scsih_slave_configure(struct scsi_device *sdev) r_level, raid_device->handle, (unsigned long long)raid_device->wwid, raid_device->num_pds, ds); - scsih_change_queue_depth(sdev, qdepth); + _scsih_change_queue_depth(sdev, qdepth); return 0; } @@ -1532,10 +1567,10 @@ scsih_slave_configure(struct scsi_device *sdev) sas_device->slot); if (!ssp_target) - scsih_display_sata_capabilities(ioc, sas_device, sdev); + _scsih_display_sata_capabilities(ioc, sas_device, sdev); } - scsih_change_queue_depth(sdev, qdepth); + _scsih_change_queue_depth(sdev, qdepth); if (ssp_target) sas_read_port_mode_page(sdev); @@ -1543,7 +1578,7 @@ scsih_slave_configure(struct scsi_device *sdev) } /** - * scsih_bios_param - fetch head, sector, cylinder info for a disk + * _scsih_bios_param - fetch head, sector, cylinder info for a disk * @sdev: scsi device struct * @bdev: pointer to block device context * @capacity: device size (in 512 byte sectors) @@ -1555,7 +1590,7 @@ scsih_slave_configure(struct scsi_device *sdev) * Return nothing. */ static int -scsih_bios_param(struct scsi_device *sdev, struct block_device *bdev, +_scsih_bios_param(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int params[]) { int heads; @@ -1636,7 +1671,7 @@ _scsih_response_code(struct MPT2SAS_ADAPTER *ioc, u8 response_code) } /** - * scsih_tm_done - tm completion routine + * _scsih_tm_done - tm completion routine * @ioc: per adapter object * @smid: system request message index * @VF_ID: virtual function id @@ -1648,7 +1683,7 @@ _scsih_response_code(struct MPT2SAS_ADAPTER *ioc, u8 response_code) * Return nothing. */ static void -scsih_tm_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply) +_scsih_tm_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply) { MPI2DefaultReply_t *mpi_reply; @@ -1823,13 +1858,13 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun, } /** - * scsih_abort - eh threads main abort routine + * _scsih_abort - eh threads main abort routine * @sdev: scsi device struct * * Returns SUCCESS if command aborted else FAILED */ static int -scsih_abort(struct scsi_cmnd *scmd) +_scsih_abort(struct scsi_cmnd *scmd) { struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host); struct MPT2SAS_DEVICE *sas_device_priv_data; @@ -1889,15 +1924,86 @@ scsih_abort(struct scsi_cmnd *scmd) return r; } - /** - * scsih_dev_reset - eh threads main device reset routine + * _scsih_dev_reset - eh threads main device reset routine * @sdev: scsi device struct * * Returns SUCCESS if command aborted else FAILED */ static int -scsih_dev_reset(struct scsi_cmnd *scmd) +_scsih_dev_reset(struct scsi_cmnd *scmd) +{ + struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host); + struct MPT2SAS_DEVICE *sas_device_priv_data; + struct _sas_device *sas_device; + unsigned long flags; + u16 handle; + int r; + + printk(MPT2SAS_INFO_FMT "attempting device reset! scmd(%p)\n", + ioc->name, scmd); + scsi_print_command(scmd); + + sas_device_priv_data = scmd->device->hostdata; + if (!sas_device_priv_data || !sas_device_priv_data->sas_target) { + printk(MPT2SAS_INFO_FMT "device been deleted! scmd(%p)\n", + ioc->name, scmd); + scmd->result = DID_NO_CONNECT << 16; + scmd->scsi_done(scmd); + r = SUCCESS; + goto out; + } + + /* for hidden raid components obtain the volume_handle */ + handle = 0; + if (sas_device_priv_data->sas_target->flags & + MPT_TARGET_FLAGS_RAID_COMPONENT) { + spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_device = _scsih_sas_device_find_by_handle(ioc, + sas_device_priv_data->sas_target->handle); + if (sas_device) + handle = sas_device->volume_handle; + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + } else + handle = sas_device_priv_data->sas_target->handle; + + if (!handle) { + scmd->result = DID_RESET << 16; + r = FAILED; + goto out; + } + + mutex_lock(&ioc->tm_cmds.mutex); + mpt2sas_scsih_issue_tm(ioc, handle, 0, + MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET, scmd->device->lun, + 30); + + /* + * sanity check see whether all commands to this device been + * completed + */ + if (_scsih_scsi_lookup_find_by_lun(ioc, scmd->device->id, + scmd->device->lun, scmd->device->channel)) + r = FAILED; + else + r = SUCCESS; + ioc->tm_cmds.status = MPT2_CMD_NOT_USED; + mutex_unlock(&ioc->tm_cmds.mutex); + + out: + printk(MPT2SAS_INFO_FMT "device reset: %s scmd(%p)\n", + ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); + return r; +} + +/** + * _scsih_target_reset - eh threads main target reset routine + * @sdev: scsi device struct + * + * Returns SUCCESS if command aborted else FAILED + */ +static int +_scsih_target_reset(struct scsi_cmnd *scmd) { struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host); struct MPT2SAS_DEVICE *sas_device_priv_data; @@ -1912,7 +2018,7 @@ scsih_dev_reset(struct scsi_cmnd *scmd) sas_device_priv_data = scmd->device->hostdata; if (!sas_device_priv_data || !sas_device_priv_data->sas_target) { - printk(MPT2SAS_INFO_FMT "device been deleted! scmd(%p)\n", + printk(MPT2SAS_INFO_FMT "target been deleted! scmd(%p)\n", ioc->name, scmd); scmd->result = DID_NO_CONNECT << 16; scmd->scsi_done(scmd); @@ -1962,13 +2068,13 @@ scsih_dev_reset(struct scsi_cmnd *scmd) } /** - * scsih_abort - eh threads main host reset routine + * _scsih_abort - eh threads main host reset routine * @sdev: scsi device struct * * Returns SUCCESS if command aborted else FAILED */ static int -scsih_host_reset(struct scsi_cmnd *scmd) +_scsih_host_reset(struct scsi_cmnd *scmd) { struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host); int r, retval; @@ -2390,7 +2496,107 @@ mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase) } /** - * scsih_qcmd - main scsi request entry point + * _scsih_setup_eedp - setup MPI request for EEDP transfer + * @scmd: pointer to scsi command object + * @mpi_request: pointer to the SCSI_IO reqest message frame + * + * Supporting protection 1 and 3. + * + * Returns nothing + */ +static void +_scsih_setup_eedp(struct scsi_cmnd *scmd, Mpi2SCSIIORequest_t *mpi_request) +{ + u16 eedp_flags; + unsigned char prot_op = scsi_get_prot_op(scmd); + unsigned char prot_type = scsi_get_prot_type(scmd); + + if (prot_type == SCSI_PROT_DIF_TYPE0 || + prot_type == SCSI_PROT_DIF_TYPE2 || + prot_op == SCSI_PROT_NORMAL) + return; + + if (prot_op == SCSI_PROT_READ_STRIP) + eedp_flags = MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP; + else if (prot_op == SCSI_PROT_WRITE_INSERT) + eedp_flags = MPI2_SCSIIO_EEDPFLAGS_INSERT_OP; + else + return; + + mpi_request->EEDPBlockSize = scmd->device->sector_size; + + switch (prot_type) { + case SCSI_PROT_DIF_TYPE1: + + /* + * enable ref/guard checking + * auto increment ref tag + */ + mpi_request->EEDPFlags = eedp_flags | + MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG | + MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG | + MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD; + mpi_request->CDB.EEDP32.PrimaryReferenceTag = + cpu_to_be32(scsi_get_lba(scmd)); + + break; + + case SCSI_PROT_DIF_TYPE3: + + /* + * enable guard checking + */ + mpi_request->EEDPFlags = eedp_flags | + MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD; + + break; + } +} + +/** + * _scsih_eedp_error_handling - return sense code for EEDP errors + * @scmd: pointer to scsi command object + * @ioc_status: ioc status + * + * Returns nothing + */ +static void +_scsih_eedp_error_handling(struct scsi_cmnd *scmd, u16 ioc_status) +{ + u8 ascq; + u8 sk; + u8 host_byte; + + switch (ioc_status) { + case MPI2_IOCSTATUS_EEDP_GUARD_ERROR: + ascq = 0x01; + break; + case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR: + ascq = 0x02; + break; + case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR: + ascq = 0x03; + break; + default: + ascq = 0x00; + break; + } + + if (scmd->sc_data_direction == DMA_TO_DEVICE) { + sk = ILLEGAL_REQUEST; + host_byte = DID_ABORT; + } else { + sk = ABORTED_COMMAND; + host_byte = DID_OK; + } + + scsi_build_sense_buffer(0, scmd->sense_buffer, sk, 0x10, ascq); + scmd->result = DRIVER_SENSE << 24 | (host_byte << 16) | + SAM_STAT_CHECK_CONDITION; +} + +/** + * _scsih_qcmd - main scsi request entry point * @scmd: pointer to scsi command object * @done: function pointer to be invoked on completion * @@ -2401,7 +2607,7 @@ mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase) * SCSI_MLQUEUE_HOST_BUSY if the entire host queue is full */ static int -scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *)) +_scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *)) { struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host); struct MPT2SAS_DEVICE *sas_device_priv_data; @@ -2470,6 +2676,7 @@ scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *)) } mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); memset(mpi_request, 0, sizeof(Mpi2SCSIIORequest_t)); + _scsih_setup_eedp(scmd, mpi_request); mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST; if (sas_device_priv_data->sas_target->flags & MPT_TARGET_FLAGS_RAID_COMPONENT) @@ -2604,6 +2811,15 @@ _scsih_scsi_ioc_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED: desc_ioc_state = "scsi ext terminated"; break; + case MPI2_IOCSTATUS_EEDP_GUARD_ERROR: + desc_ioc_state = "eedp guard error"; + break; + case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR: + desc_ioc_state = "eedp ref tag error"; + break; + case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR: + desc_ioc_state = "eedp app tag error"; + break; default: desc_ioc_state = "unknown"; break; @@ -2783,7 +2999,7 @@ _scsih_smart_predicted_fault(struct MPT2SAS_ADAPTER *ioc, u16 handle) } /** - * scsih_io_done - scsi request callback + * _scsih_io_done - scsi request callback * @ioc: per adapter object * @smid: system request message index * @VF_ID: virtual function id @@ -2794,7 +3010,7 @@ _scsih_smart_predicted_fault(struct MPT2SAS_ADAPTER *ioc, u16 handle) * Return nothing. */ static void -scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply) +_scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply) { Mpi2SCSIIORequest_t *mpi_request; Mpi2SCSIIOReply_t *mpi_reply; @@ -2939,6 +3155,11 @@ scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply) scmd->result = DID_RESET << 16; break; + case MPI2_IOCSTATUS_EEDP_GUARD_ERROR: + case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR: + case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR: + _scsih_eedp_error_handling(scmd, ioc_status); + break; case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR: case MPI2_IOCSTATUS_INVALID_FUNCTION: case MPI2_IOCSTATUS_INVALID_SGL: @@ -5130,18 +5351,19 @@ static struct scsi_host_template scsih_driver_template = { .module = THIS_MODULE, .name = "Fusion MPT SAS Host", .proc_name = MPT2SAS_DRIVER_NAME, - .queuecommand = scsih_qcmd, - .target_alloc = scsih_target_alloc, - .slave_alloc = scsih_slave_alloc, - .slave_configure = scsih_slave_configure, - .target_destroy = scsih_target_destroy, - .slave_destroy = scsih_slave_destroy, - .change_queue_depth = scsih_change_queue_depth, - .change_queue_type = scsih_change_queue_type, - .eh_abort_handler = scsih_abort, - .eh_device_reset_handler = scsih_dev_reset, - .eh_host_reset_handler = scsih_host_reset, - .bios_param = scsih_bios_param, + .queuecommand = _scsih_qcmd, + .target_alloc = _scsih_target_alloc, + .slave_alloc = _scsih_slave_alloc, + .slave_configure = _scsih_slave_configure, + .target_destroy = _scsih_target_destroy, + .slave_destroy = _scsih_slave_destroy, + .change_queue_depth = _scsih_change_queue_depth, + .change_queue_type = _scsih_change_queue_type, + .eh_abort_handler = _scsih_abort, + .eh_device_reset_handler = _scsih_dev_reset, + .eh_target_reset_handler = _scsih_target_reset, + .eh_host_reset_handler = _scsih_host_reset, + .bios_param = _scsih_bios_param, .can_queue = 1, .this_id = -1, .sg_tablesize = MPT2SAS_SG_DEPTH, @@ -5228,13 +5450,13 @@ _scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc, } /** - * scsih_remove - detach and remove add host + * _scsih_remove - detach and remove add host * @pdev: PCI device struct * * Return nothing. */ static void __devexit -scsih_remove(struct pci_dev *pdev) +_scsih_remove(struct pci_dev *pdev) { struct Scsi_Host *shost = pci_get_drvdata(pdev); struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); @@ -5442,14 +5664,14 @@ _scsih_probe_devices(struct MPT2SAS_ADAPTER *ioc) } /** - * scsih_probe - attach and add scsi host + * _scsih_probe - attach and add scsi host * @pdev: PCI device struct * @id: pci device id * * Returns 0 success, anything else error. */ static int -scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) +_scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct MPT2SAS_ADAPTER *ioc; struct Scsi_Host *shost; @@ -5503,6 +5725,9 @@ scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto out_add_shost_fail; } + scsi_host_set_prot(shost, SHOST_DIF_TYPE1_PROTECTION + | SHOST_DIF_TYPE3_PROTECTION); + /* event thread */ snprintf(ioc->firmware_event_name, sizeof(ioc->firmware_event_name), "fw_event%d", ioc->id); @@ -5536,14 +5761,14 @@ scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) #ifdef CONFIG_PM /** - * scsih_suspend - power management suspend main entry point + * _scsih_suspend - power management suspend main entry point * @pdev: PCI device struct * @state: PM state change to (usually PCI_D3) * * Returns 0 success, anything else error. */ static int -scsih_suspend(struct pci_dev *pdev, pm_message_t state) +_scsih_suspend(struct pci_dev *pdev, pm_message_t state) { struct Scsi_Host *shost = pci_get_drvdata(pdev); struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); @@ -5564,13 +5789,13 @@ scsih_suspend(struct pci_dev *pdev, pm_message_t state) } /** - * scsih_resume - power management resume main entry point + * _scsih_resume - power management resume main entry point * @pdev: PCI device struct * * Returns 0 success, anything else error. */ static int -scsih_resume(struct pci_dev *pdev) +_scsih_resume(struct pci_dev *pdev) { struct Scsi_Host *shost = pci_get_drvdata(pdev); struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); @@ -5599,22 +5824,22 @@ scsih_resume(struct pci_dev *pdev) static struct pci_driver scsih_driver = { .name = MPT2SAS_DRIVER_NAME, .id_table = scsih_pci_table, - .probe = scsih_probe, - .remove = __devexit_p(scsih_remove), + .probe = _scsih_probe, + .remove = __devexit_p(_scsih_remove), #ifdef CONFIG_PM - .suspend = scsih_suspend, - .resume = scsih_resume, + .suspend = _scsih_suspend, + .resume = _scsih_resume, #endif }; /** - * scsih_init - main entry point for this driver. + * _scsih_init - main entry point for this driver. * * Returns 0 success, anything else error. */ static int __init -scsih_init(void) +_scsih_init(void) { int error; @@ -5630,10 +5855,10 @@ scsih_init(void) mpt2sas_base_initialize_callback_handler(); /* queuecommand callback hander */ - scsi_io_cb_idx = mpt2sas_base_register_callback_handler(scsih_io_done); + scsi_io_cb_idx = mpt2sas_base_register_callback_handler(_scsih_io_done); /* task managment callback handler */ - tm_cb_idx = mpt2sas_base_register_callback_handler(scsih_tm_done); + tm_cb_idx = mpt2sas_base_register_callback_handler(_scsih_tm_done); /* base internal commands callback handler */ base_cb_idx = mpt2sas_base_register_callback_handler(mpt2sas_base_done); @@ -5659,12 +5884,12 @@ scsih_init(void) } /** - * scsih_exit - exit point for this driver (when it is a module). + * _scsih_exit - exit point for this driver (when it is a module). * * Returns 0 success, anything else error. */ static void __exit -scsih_exit(void) +_scsih_exit(void) { printk(KERN_INFO "mpt2sas version %s unloading\n", MPT2SAS_DRIVER_VERSION); @@ -5682,5 +5907,5 @@ scsih_exit(void) mpt2sas_ctl_exit(); } -module_init(scsih_init); -module_exit(scsih_exit); +module_init(_scsih_init); +module_exit(_scsih_exit); diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c index e03dc0b1e1a0..686695b155c7 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_transport.c +++ b/drivers/scsi/mpt2sas/mpt2sas_transport.c @@ -264,7 +264,7 @@ struct rep_manu_reply{ }; /** - * transport_expander_report_manufacture - obtain SMP report_manufacture + * _transport_expander_report_manufacture - obtain SMP report_manufacture * @ioc: per adapter object * @sas_address: expander sas address * @edev: the sas_expander_device object @@ -274,7 +274,7 @@ struct rep_manu_reply{ * Returns 0 for success, non-zero for failure. */ static int -transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc, +_transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc, u64 sas_address, struct sas_expander_device *edev) { Mpi2SmpPassthroughRequest_t *mpi_request; @@ -578,7 +578,7 @@ mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle, MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER || mpt2sas_port->remote_identify.device_type == MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER) - transport_expander_report_manufacture(ioc, + _transport_expander_report_manufacture(ioc, mpt2sas_port->remote_identify.sas_address, rphy_to_expander_device(rphy)); @@ -852,7 +852,7 @@ rphy_to_ioc(struct sas_rphy *rphy) } /** - * transport_get_linkerrors - + * _transport_get_linkerrors - * @phy: The sas phy object * * Only support sas_host direct attached phys. @@ -860,7 +860,7 @@ rphy_to_ioc(struct sas_rphy *rphy) * */ static int -transport_get_linkerrors(struct sas_phy *phy) +_transport_get_linkerrors(struct sas_phy *phy) { struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy); struct _sas_phy *mpt2sas_phy; @@ -903,14 +903,14 @@ transport_get_linkerrors(struct sas_phy *phy) } /** - * transport_get_enclosure_identifier - + * _transport_get_enclosure_identifier - * @phy: The sas phy object * * Obtain the enclosure logical id for an expander. * Returns 0 for success, non-zero for failure. */ static int -transport_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier) +_transport_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier) { struct MPT2SAS_ADAPTER *ioc = rphy_to_ioc(rphy); struct _sas_node *sas_expander; @@ -929,13 +929,13 @@ transport_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier) } /** - * transport_get_bay_identifier - + * _transport_get_bay_identifier - * @phy: The sas phy object * * Returns the slot id for a device that resides inside an enclosure. */ static int -transport_get_bay_identifier(struct sas_rphy *rphy) +_transport_get_bay_identifier(struct sas_rphy *rphy) { struct MPT2SAS_ADAPTER *ioc = rphy_to_ioc(rphy); struct _sas_device *sas_device; @@ -953,7 +953,7 @@ transport_get_bay_identifier(struct sas_rphy *rphy) } /** - * transport_phy_reset - + * _transport_phy_reset - * @phy: The sas phy object * @hard_reset: * @@ -961,7 +961,7 @@ transport_get_bay_identifier(struct sas_rphy *rphy) * Returns 0 for success, non-zero for failure. */ static int -transport_phy_reset(struct sas_phy *phy, int hard_reset) +_transport_phy_reset(struct sas_phy *phy, int hard_reset) { struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy); struct _sas_phy *mpt2sas_phy; @@ -1002,7 +1002,7 @@ transport_phy_reset(struct sas_phy *phy, int hard_reset) } /** - * transport_smp_handler - transport portal for smp passthru + * _transport_smp_handler - transport portal for smp passthru * @shost: shost object * @rphy: sas transport rphy object * @req: @@ -1012,7 +1012,7 @@ transport_phy_reset(struct sas_phy *phy, int hard_reset) * smp_rep_general /sys/class/bsg/expander-5:0 */ static int -transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, +_transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, struct request *req) { struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); @@ -1041,7 +1041,7 @@ transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) { printk(MPT2SAS_ERR_FMT "%s: multiple segments req %u %u, " "rsp %u %u\n", ioc->name, __func__, req->bio->bi_vcnt, - req->data_len, rsp->bio->bi_vcnt, rsp->data_len); + blk_rq_bytes(req), rsp->bio->bi_vcnt, blk_rq_bytes(rsp)); return -EINVAL; } @@ -1104,7 +1104,7 @@ transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, *((u64 *)&mpi_request->SASAddress) = (rphy) ? cpu_to_le64(rphy->identify.sas_address) : cpu_to_le64(ioc->sas_hba.sas_address); - mpi_request->RequestDataLength = cpu_to_le16(req->data_len - 4); + mpi_request->RequestDataLength = cpu_to_le16(blk_rq_bytes(req) - 4); psge = &mpi_request->SGL; /* WRITE sgel first */ @@ -1112,13 +1112,13 @@ transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC); sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; dma_addr_out = pci_map_single(ioc->pdev, bio_data(req->bio), - req->data_len, PCI_DMA_BIDIRECTIONAL); + blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL); if (!dma_addr_out) { mpt2sas_base_free_smid(ioc, le16_to_cpu(smid)); goto unmap; } - ioc->base_add_sg_single(psge, sgl_flags | (req->data_len - 4), + ioc->base_add_sg_single(psge, sgl_flags | (blk_rq_bytes(req) - 4), dma_addr_out); /* incr sgel */ @@ -1129,14 +1129,14 @@ transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_END_OF_LIST); sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; - dma_addr_in = pci_map_single(ioc->pdev, bio_data(rsp->bio), - rsp->data_len, PCI_DMA_BIDIRECTIONAL); + dma_addr_in = pci_map_single(ioc->pdev, bio_data(rsp->bio), + blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL); if (!dma_addr_in) { mpt2sas_base_free_smid(ioc, le16_to_cpu(smid)); goto unmap; } - ioc->base_add_sg_single(psge, sgl_flags | (rsp->data_len + 4), + ioc->base_add_sg_single(psge, sgl_flags | (blk_rq_bytes(rsp) + 4), dma_addr_in); dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s - " @@ -1170,9 +1170,8 @@ transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, memcpy(req->sense, mpi_reply, sizeof(*mpi_reply)); req->sense_len = sizeof(*mpi_reply); - req->data_len = 0; - rsp->data_len -= mpi_reply->ResponseDataLength; - + req->resid_len = 0; + rsp->resid_len -= mpi_reply->ResponseDataLength; } else { dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s - no reply\n", ioc->name, __func__)); @@ -1188,10 +1187,10 @@ transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, unmap: if (dma_addr_out) - pci_unmap_single(ioc->pdev, dma_addr_out, req->data_len, + pci_unmap_single(ioc->pdev, dma_addr_out, blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL); if (dma_addr_in) - pci_unmap_single(ioc->pdev, dma_addr_in, rsp->data_len, + pci_unmap_single(ioc->pdev, dma_addr_in, blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL); out: @@ -1201,11 +1200,11 @@ transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, } struct sas_function_template mpt2sas_transport_functions = { - .get_linkerrors = transport_get_linkerrors, - .get_enclosure_identifier = transport_get_enclosure_identifier, - .get_bay_identifier = transport_get_bay_identifier, - .phy_reset = transport_phy_reset, - .smp_handler = transport_smp_handler, + .get_linkerrors = _transport_get_linkerrors, + .get_enclosure_identifier = _transport_get_enclosure_identifier, + .get_bay_identifier = _transport_get_bay_identifier, + .phy_reset = _transport_phy_reset, + .smp_handler = _transport_smp_handler, }; struct scsi_transport_template *mpt2sas_transport_template; diff --git a/drivers/scsi/mvsas.c b/drivers/scsi/mvsas.c deleted file mode 100644 index e4acebd10d1b..000000000000 --- a/drivers/scsi/mvsas.c +++ /dev/null @@ -1,3222 +0,0 @@ -/* - mvsas.c - Marvell 88SE6440 SAS/SATA support - - Copyright 2007 Red Hat, Inc. - Copyright 2008 Marvell. - - 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, - or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty - of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public - License along with this program; see the file COPYING. If not, - write to the Free Software Foundation, 675 Mass Ave, Cambridge, - MA 02139, USA. - - --------------------------------------------------------------- - - Random notes: - * hardware supports controlling the endian-ness of data - structures. this permits elimination of all the le32_to_cpu() - and cpu_to_le32() conversions. - - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DRV_NAME "mvsas" -#define DRV_VERSION "0.5.2" -#define _MV_DUMP 0 -#define MVS_DISABLE_NVRAM -#define MVS_DISABLE_MSI - -#define mr32(reg) readl(regs + MVS_##reg) -#define mw32(reg,val) writel((val), regs + MVS_##reg) -#define mw32_f(reg,val) do { \ - writel((val), regs + MVS_##reg); \ - readl(regs + MVS_##reg); \ - } while (0) - -#define MVS_ID_NOT_MAPPED 0x7f -#define MVS_CHIP_SLOT_SZ (1U << mvi->chip->slot_width) - -/* offset for D2H FIS in the Received FIS List Structure */ -#define SATA_RECEIVED_D2H_FIS(reg_set) \ - ((void *) mvi->rx_fis + 0x400 + 0x100 * reg_set + 0x40) -#define SATA_RECEIVED_PIO_FIS(reg_set) \ - ((void *) mvi->rx_fis + 0x400 + 0x100 * reg_set + 0x20) -#define UNASSOC_D2H_FIS(id) \ - ((void *) mvi->rx_fis + 0x100 * id) - -#define for_each_phy(__lseq_mask, __mc, __lseq, __rest) \ - for ((__mc) = (__lseq_mask), (__lseq) = 0; \ - (__mc) != 0 && __rest; \ - (++__lseq), (__mc) >>= 1) - -/* driver compile-time configuration */ -enum driver_configuration { - MVS_TX_RING_SZ = 1024, /* TX ring size (12-bit) */ - MVS_RX_RING_SZ = 1024, /* RX ring size (12-bit) */ - /* software requires power-of-2 - ring size */ - - MVS_SLOTS = 512, /* command slots */ - MVS_SLOT_BUF_SZ = 8192, /* cmd tbl + IU + status + PRD */ - MVS_SSP_CMD_SZ = 64, /* SSP command table buffer size */ - MVS_ATA_CMD_SZ = 96, /* SATA command table buffer size */ - MVS_OAF_SZ = 64, /* Open address frame buffer size */ - - MVS_RX_FIS_COUNT = 17, /* Optional rx'd FISs (max 17) */ - - MVS_QUEUE_SIZE = 30, /* Support Queue depth */ - MVS_CAN_QUEUE = MVS_SLOTS - 1, /* SCSI Queue depth */ -}; - -/* unchangeable hardware details */ -enum hardware_details { - MVS_MAX_PHYS = 8, /* max. possible phys */ - MVS_MAX_PORTS = 8, /* max. possible ports */ - MVS_RX_FISL_SZ = 0x400 + (MVS_RX_FIS_COUNT * 0x100), -}; - -/* peripheral registers (BAR2) */ -enum peripheral_registers { - SPI_CTL = 0x10, /* EEPROM control */ - SPI_CMD = 0x14, /* EEPROM command */ - SPI_DATA = 0x18, /* EEPROM data */ -}; - -enum peripheral_register_bits { - TWSI_RDY = (1U << 7), /* EEPROM interface ready */ - TWSI_RD = (1U << 4), /* EEPROM read access */ - - SPI_ADDR_MASK = 0x3ffff, /* bits 17:0 */ -}; - -/* enhanced mode registers (BAR4) */ -enum hw_registers { - MVS_GBL_CTL = 0x04, /* global control */ - MVS_GBL_INT_STAT = 0x08, /* global irq status */ - MVS_GBL_PI = 0x0C, /* ports implemented bitmask */ - MVS_GBL_PORT_TYPE = 0xa0, /* port type */ - - MVS_CTL = 0x100, /* SAS/SATA port configuration */ - MVS_PCS = 0x104, /* SAS/SATA port control/status */ - MVS_CMD_LIST_LO = 0x108, /* cmd list addr */ - MVS_CMD_LIST_HI = 0x10C, - MVS_RX_FIS_LO = 0x110, /* RX FIS list addr */ - MVS_RX_FIS_HI = 0x114, - - MVS_TX_CFG = 0x120, /* TX configuration */ - MVS_TX_LO = 0x124, /* TX (delivery) ring addr */ - MVS_TX_HI = 0x128, - - MVS_TX_PROD_IDX = 0x12C, /* TX producer pointer */ - MVS_TX_CONS_IDX = 0x130, /* TX consumer pointer (RO) */ - MVS_RX_CFG = 0x134, /* RX configuration */ - MVS_RX_LO = 0x138, /* RX (completion) ring addr */ - MVS_RX_HI = 0x13C, - MVS_RX_CONS_IDX = 0x140, /* RX consumer pointer (RO) */ - - MVS_INT_COAL = 0x148, /* Int coalescing config */ - MVS_INT_COAL_TMOUT = 0x14C, /* Int coalescing timeout */ - MVS_INT_STAT = 0x150, /* Central int status */ - MVS_INT_MASK = 0x154, /* Central int enable */ - MVS_INT_STAT_SRS = 0x158, /* SATA register set status */ - MVS_INT_MASK_SRS = 0x15C, - - /* ports 1-3 follow after this */ - MVS_P0_INT_STAT = 0x160, /* port0 interrupt status */ - MVS_P0_INT_MASK = 0x164, /* port0 interrupt mask */ - MVS_P4_INT_STAT = 0x200, /* Port 4 interrupt status */ - MVS_P4_INT_MASK = 0x204, /* Port 4 interrupt enable mask */ - - /* ports 1-3 follow after this */ - MVS_P0_SER_CTLSTAT = 0x180, /* port0 serial control/status */ - MVS_P4_SER_CTLSTAT = 0x220, /* port4 serial control/status */ - - MVS_CMD_ADDR = 0x1B8, /* Command register port (addr) */ - MVS_CMD_DATA = 0x1BC, /* Command register port (data) */ - - /* ports 1-3 follow after this */ - MVS_P0_CFG_ADDR = 0x1C0, /* port0 phy register address */ - MVS_P0_CFG_DATA = 0x1C4, /* port0 phy register data */ - MVS_P4_CFG_ADDR = 0x230, /* Port 4 config address */ - MVS_P4_CFG_DATA = 0x234, /* Port 4 config data */ - - /* ports 1-3 follow after this */ - MVS_P0_VSR_ADDR = 0x1E0, /* port0 VSR address */ - MVS_P0_VSR_DATA = 0x1E4, /* port0 VSR data */ - MVS_P4_VSR_ADDR = 0x250, /* port 4 VSR addr */ - MVS_P4_VSR_DATA = 0x254, /* port 4 VSR data */ -}; - -enum hw_register_bits { - /* MVS_GBL_CTL */ - INT_EN = (1U << 1), /* Global int enable */ - HBA_RST = (1U << 0), /* HBA reset */ - - /* MVS_GBL_INT_STAT */ - INT_XOR = (1U << 4), /* XOR engine event */ - INT_SAS_SATA = (1U << 0), /* SAS/SATA event */ - - /* MVS_GBL_PORT_TYPE */ /* shl for ports 1-3 */ - SATA_TARGET = (1U << 16), /* port0 SATA target enable */ - MODE_AUTO_DET_PORT7 = (1U << 15), /* port0 SAS/SATA autodetect */ - MODE_AUTO_DET_PORT6 = (1U << 14), - MODE_AUTO_DET_PORT5 = (1U << 13), - MODE_AUTO_DET_PORT4 = (1U << 12), - MODE_AUTO_DET_PORT3 = (1U << 11), - MODE_AUTO_DET_PORT2 = (1U << 10), - MODE_AUTO_DET_PORT1 = (1U << 9), - MODE_AUTO_DET_PORT0 = (1U << 8), - MODE_AUTO_DET_EN = MODE_AUTO_DET_PORT0 | MODE_AUTO_DET_PORT1 | - MODE_AUTO_DET_PORT2 | MODE_AUTO_DET_PORT3 | - MODE_AUTO_DET_PORT4 | MODE_AUTO_DET_PORT5 | - MODE_AUTO_DET_PORT6 | MODE_AUTO_DET_PORT7, - MODE_SAS_PORT7_MASK = (1U << 7), /* port0 SAS(1), SATA(0) mode */ - MODE_SAS_PORT6_MASK = (1U << 6), - MODE_SAS_PORT5_MASK = (1U << 5), - MODE_SAS_PORT4_MASK = (1U << 4), - MODE_SAS_PORT3_MASK = (1U << 3), - MODE_SAS_PORT2_MASK = (1U << 2), - MODE_SAS_PORT1_MASK = (1U << 1), - MODE_SAS_PORT0_MASK = (1U << 0), - MODE_SAS_SATA = MODE_SAS_PORT0_MASK | MODE_SAS_PORT1_MASK | - MODE_SAS_PORT2_MASK | MODE_SAS_PORT3_MASK | - MODE_SAS_PORT4_MASK | MODE_SAS_PORT5_MASK | - MODE_SAS_PORT6_MASK | MODE_SAS_PORT7_MASK, - - /* SAS_MODE value may be - * dictated (in hw) by values - * of SATA_TARGET & AUTO_DET - */ - - /* MVS_TX_CFG */ - TX_EN = (1U << 16), /* Enable TX */ - TX_RING_SZ_MASK = 0xfff, /* TX ring size, bits 11:0 */ - - /* MVS_RX_CFG */ - RX_EN = (1U << 16), /* Enable RX */ - RX_RING_SZ_MASK = 0xfff, /* RX ring size, bits 11:0 */ - - /* MVS_INT_COAL */ - COAL_EN = (1U << 16), /* Enable int coalescing */ - - /* MVS_INT_STAT, MVS_INT_MASK */ - CINT_I2C = (1U << 31), /* I2C event */ - CINT_SW0 = (1U << 30), /* software event 0 */ - CINT_SW1 = (1U << 29), /* software event 1 */ - CINT_PRD_BC = (1U << 28), /* PRD BC err for read cmd */ - CINT_DMA_PCIE = (1U << 27), /* DMA to PCIE timeout */ - CINT_MEM = (1U << 26), /* int mem parity err */ - CINT_I2C_SLAVE = (1U << 25), /* slave I2C event */ - CINT_SRS = (1U << 3), /* SRS event */ - CINT_CI_STOP = (1U << 1), /* cmd issue stopped */ - CINT_DONE = (1U << 0), /* cmd completion */ - - /* shl for ports 1-3 */ - CINT_PORT_STOPPED = (1U << 16), /* port0 stopped */ - CINT_PORT = (1U << 8), /* port0 event */ - CINT_PORT_MASK_OFFSET = 8, - CINT_PORT_MASK = (0xFF << CINT_PORT_MASK_OFFSET), - - /* TX (delivery) ring bits */ - TXQ_CMD_SHIFT = 29, - TXQ_CMD_SSP = 1, /* SSP protocol */ - TXQ_CMD_SMP = 2, /* SMP protocol */ - TXQ_CMD_STP = 3, /* STP/SATA protocol */ - TXQ_CMD_SSP_FREE_LIST = 4, /* add to SSP targ free list */ - TXQ_CMD_SLOT_RESET = 7, /* reset command slot */ - TXQ_MODE_I = (1U << 28), /* mode: 0=target,1=initiator */ - TXQ_PRIO_HI = (1U << 27), /* priority: 0=normal, 1=high */ - TXQ_SRS_SHIFT = 20, /* SATA register set */ - TXQ_SRS_MASK = 0x7f, - TXQ_PHY_SHIFT = 12, /* PHY bitmap */ - TXQ_PHY_MASK = 0xff, - TXQ_SLOT_MASK = 0xfff, /* slot number */ - - /* RX (completion) ring bits */ - RXQ_GOOD = (1U << 23), /* Response good */ - RXQ_SLOT_RESET = (1U << 21), /* Slot reset complete */ - RXQ_CMD_RX = (1U << 20), /* target cmd received */ - RXQ_ATTN = (1U << 19), /* attention */ - RXQ_RSP = (1U << 18), /* response frame xfer'd */ - RXQ_ERR = (1U << 17), /* err info rec xfer'd */ - RXQ_DONE = (1U << 16), /* cmd complete */ - RXQ_SLOT_MASK = 0xfff, /* slot number */ - - /* mvs_cmd_hdr bits */ - MCH_PRD_LEN_SHIFT = 16, /* 16-bit PRD table len */ - MCH_SSP_FR_TYPE_SHIFT = 13, /* SSP frame type */ - - /* SSP initiator only */ - MCH_SSP_FR_CMD = 0x0, /* COMMAND frame */ - - /* SSP initiator or target */ - MCH_SSP_FR_TASK = 0x1, /* TASK frame */ - - /* SSP target only */ - MCH_SSP_FR_XFER_RDY = 0x4, /* XFER_RDY frame */ - MCH_SSP_FR_RESP = 0x5, /* RESPONSE frame */ - MCH_SSP_FR_READ = 0x6, /* Read DATA frame(s) */ - MCH_SSP_FR_READ_RESP = 0x7, /* ditto, plus RESPONSE */ - - MCH_PASSTHRU = (1U << 12), /* pass-through (SSP) */ - MCH_FBURST = (1U << 11), /* first burst (SSP) */ - MCH_CHK_LEN = (1U << 10), /* chk xfer len (SSP) */ - MCH_RETRY = (1U << 9), /* tport layer retry (SSP) */ - MCH_PROTECTION = (1U << 8), /* protection info rec (SSP) */ - MCH_RESET = (1U << 7), /* Reset (STP/SATA) */ - MCH_FPDMA = (1U << 6), /* First party DMA (STP/SATA) */ - MCH_ATAPI = (1U << 5), /* ATAPI (STP/SATA) */ - MCH_BIST = (1U << 4), /* BIST activate (STP/SATA) */ - MCH_PMP_MASK = 0xf, /* PMP from cmd FIS (STP/SATA)*/ - - CCTL_RST = (1U << 5), /* port logic reset */ - - /* 0(LSB first), 1(MSB first) */ - CCTL_ENDIAN_DATA = (1U << 3), /* PRD data */ - CCTL_ENDIAN_RSP = (1U << 2), /* response frame */ - CCTL_ENDIAN_OPEN = (1U << 1), /* open address frame */ - CCTL_ENDIAN_CMD = (1U << 0), /* command table */ - - /* MVS_Px_SER_CTLSTAT (per-phy control) */ - PHY_SSP_RST = (1U << 3), /* reset SSP link layer */ - PHY_BCAST_CHG = (1U << 2), /* broadcast(change) notif */ - PHY_RST_HARD = (1U << 1), /* hard reset + phy reset */ - PHY_RST = (1U << 0), /* phy reset */ - PHY_MIN_SPP_PHYS_LINK_RATE_MASK = (0xF << 8), - PHY_MAX_SPP_PHYS_LINK_RATE_MASK = (0xF << 12), - PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET = (16), - PHY_NEG_SPP_PHYS_LINK_RATE_MASK = - (0xF << PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET), - PHY_READY_MASK = (1U << 20), - - /* MVS_Px_INT_STAT, MVS_Px_INT_MASK (per-phy events) */ - PHYEV_DEC_ERR = (1U << 24), /* Phy Decoding Error */ - PHYEV_UNASSOC_FIS = (1U << 19), /* unassociated FIS rx'd */ - PHYEV_AN = (1U << 18), /* SATA async notification */ - PHYEV_BIST_ACT = (1U << 17), /* BIST activate FIS */ - PHYEV_SIG_FIS = (1U << 16), /* signature FIS */ - PHYEV_POOF = (1U << 12), /* phy ready from 1 -> 0 */ - PHYEV_IU_BIG = (1U << 11), /* IU too long err */ - PHYEV_IU_SMALL = (1U << 10), /* IU too short err */ - PHYEV_UNK_TAG = (1U << 9), /* unknown tag */ - PHYEV_BROAD_CH = (1U << 8), /* broadcast(CHANGE) */ - PHYEV_COMWAKE = (1U << 7), /* COMWAKE rx'd */ - PHYEV_PORT_SEL = (1U << 6), /* port selector present */ - PHYEV_HARD_RST = (1U << 5), /* hard reset rx'd */ - PHYEV_ID_TMOUT = (1U << 4), /* identify timeout */ - PHYEV_ID_FAIL = (1U << 3), /* identify failed */ - PHYEV_ID_DONE = (1U << 2), /* identify done */ - PHYEV_HARD_RST_DONE = (1U << 1), /* hard reset done */ - PHYEV_RDY_CH = (1U << 0), /* phy ready changed state */ - - /* MVS_PCS */ - PCS_EN_SATA_REG_SHIFT = (16), /* Enable SATA Register Set */ - PCS_EN_PORT_XMT_SHIFT = (12), /* Enable Port Transmit */ - PCS_EN_PORT_XMT_SHIFT2 = (8), /* For 6480 */ - PCS_SATA_RETRY = (1U << 8), /* retry ctl FIS on R_ERR */ - PCS_RSP_RX_EN = (1U << 7), /* raw response rx */ - PCS_SELF_CLEAR = (1U << 5), /* self-clearing int mode */ - PCS_FIS_RX_EN = (1U << 4), /* FIS rx enable */ - PCS_CMD_STOP_ERR = (1U << 3), /* cmd stop-on-err enable */ - PCS_CMD_RST = (1U << 1), /* reset cmd issue */ - PCS_CMD_EN = (1U << 0), /* enable cmd issue */ - - /* Port n Attached Device Info */ - PORT_DEV_SSP_TRGT = (1U << 19), - PORT_DEV_SMP_TRGT = (1U << 18), - PORT_DEV_STP_TRGT = (1U << 17), - PORT_DEV_SSP_INIT = (1U << 11), - PORT_DEV_SMP_INIT = (1U << 10), - PORT_DEV_STP_INIT = (1U << 9), - PORT_PHY_ID_MASK = (0xFFU << 24), - PORT_DEV_TRGT_MASK = (0x7U << 17), - PORT_DEV_INIT_MASK = (0x7U << 9), - PORT_DEV_TYPE_MASK = (0x7U << 0), - - /* Port n PHY Status */ - PHY_RDY = (1U << 2), - PHY_DW_SYNC = (1U << 1), - PHY_OOB_DTCTD = (1U << 0), - - /* VSR */ - /* PHYMODE 6 (CDB) */ - PHY_MODE6_LATECLK = (1U << 29), /* Lock Clock */ - PHY_MODE6_DTL_SPEED = (1U << 27), /* Digital Loop Speed */ - PHY_MODE6_FC_ORDER = (1U << 26), /* Fibre Channel Mode Order*/ - PHY_MODE6_MUCNT_EN = (1U << 24), /* u Count Enable */ - PHY_MODE6_SEL_MUCNT_LEN = (1U << 22), /* Training Length Select */ - PHY_MODE6_SELMUPI = (1U << 20), /* Phase Multi Select (init) */ - PHY_MODE6_SELMUPF = (1U << 18), /* Phase Multi Select (final) */ - PHY_MODE6_SELMUFF = (1U << 16), /* Freq Loop Multi Sel(final) */ - PHY_MODE6_SELMUFI = (1U << 14), /* Freq Loop Multi Sel(init) */ - PHY_MODE6_FREEZE_LOOP = (1U << 12), /* Freeze Rx CDR Loop */ - PHY_MODE6_INT_RXFOFFS = (1U << 3), /* Rx CDR Freq Loop Enable */ - PHY_MODE6_FRC_RXFOFFS = (1U << 2), /* Initial Rx CDR Offset */ - PHY_MODE6_STAU_0D8 = (1U << 1), /* Rx CDR Freq Loop Saturate */ - PHY_MODE6_RXSAT_DIS = (1U << 0), /* Saturate Ctl */ -}; - -enum mvs_info_flags { - MVF_MSI = (1U << 0), /* MSI is enabled */ - MVF_PHY_PWR_FIX = (1U << 1), /* bug workaround */ -}; - -enum sas_cmd_port_registers { - CMD_CMRST_OOB_DET = 0x100, /* COMRESET OOB detect register */ - CMD_CMWK_OOB_DET = 0x104, /* COMWAKE OOB detect register */ - CMD_CMSAS_OOB_DET = 0x108, /* COMSAS OOB detect register */ - CMD_BRST_OOB_DET = 0x10c, /* burst OOB detect register */ - CMD_OOB_SPACE = 0x110, /* OOB space control register */ - CMD_OOB_BURST = 0x114, /* OOB burst control register */ - CMD_PHY_TIMER = 0x118, /* PHY timer control register */ - CMD_PHY_CONFIG0 = 0x11c, /* PHY config register 0 */ - CMD_PHY_CONFIG1 = 0x120, /* PHY config register 1 */ - CMD_SAS_CTL0 = 0x124, /* SAS control register 0 */ - CMD_SAS_CTL1 = 0x128, /* SAS control register 1 */ - CMD_SAS_CTL2 = 0x12c, /* SAS control register 2 */ - CMD_SAS_CTL3 = 0x130, /* SAS control register 3 */ - CMD_ID_TEST = 0x134, /* ID test register */ - CMD_PL_TIMER = 0x138, /* PL timer register */ - CMD_WD_TIMER = 0x13c, /* WD timer register */ - CMD_PORT_SEL_COUNT = 0x140, /* port selector count register */ - CMD_APP_MEM_CTL = 0x144, /* Application Memory Control */ - CMD_XOR_MEM_CTL = 0x148, /* XOR Block Memory Control */ - CMD_DMA_MEM_CTL = 0x14c, /* DMA Block Memory Control */ - CMD_PORT_MEM_CTL0 = 0x150, /* Port Memory Control 0 */ - CMD_PORT_MEM_CTL1 = 0x154, /* Port Memory Control 1 */ - CMD_SATA_PORT_MEM_CTL0 = 0x158, /* SATA Port Memory Control 0 */ - CMD_SATA_PORT_MEM_CTL1 = 0x15c, /* SATA Port Memory Control 1 */ - CMD_XOR_MEM_BIST_CTL = 0x160, /* XOR Memory BIST Control */ - CMD_XOR_MEM_BIST_STAT = 0x164, /* XOR Memroy BIST Status */ - CMD_DMA_MEM_BIST_CTL = 0x168, /* DMA Memory BIST Control */ - CMD_DMA_MEM_BIST_STAT = 0x16c, /* DMA Memory BIST Status */ - CMD_PORT_MEM_BIST_CTL = 0x170, /* Port Memory BIST Control */ - CMD_PORT_MEM_BIST_STAT0 = 0x174, /* Port Memory BIST Status 0 */ - CMD_PORT_MEM_BIST_STAT1 = 0x178, /* Port Memory BIST Status 1 */ - CMD_STP_MEM_BIST_CTL = 0x17c, /* STP Memory BIST Control */ - CMD_STP_MEM_BIST_STAT0 = 0x180, /* STP Memory BIST Status 0 */ - CMD_STP_MEM_BIST_STAT1 = 0x184, /* STP Memory BIST Status 1 */ - CMD_RESET_COUNT = 0x188, /* Reset Count */ - CMD_MONTR_DATA_SEL = 0x18C, /* Monitor Data/Select */ - CMD_PLL_PHY_CONFIG = 0x190, /* PLL/PHY Configuration */ - CMD_PHY_CTL = 0x194, /* PHY Control and Status */ - CMD_PHY_TEST_COUNT0 = 0x198, /* Phy Test Count 0 */ - CMD_PHY_TEST_COUNT1 = 0x19C, /* Phy Test Count 1 */ - CMD_PHY_TEST_COUNT2 = 0x1A0, /* Phy Test Count 2 */ - CMD_APP_ERR_CONFIG = 0x1A4, /* Application Error Configuration */ - CMD_PND_FIFO_CTL0 = 0x1A8, /* Pending FIFO Control 0 */ - CMD_HOST_CTL = 0x1AC, /* Host Control Status */ - CMD_HOST_WR_DATA = 0x1B0, /* Host Write Data */ - CMD_HOST_RD_DATA = 0x1B4, /* Host Read Data */ - CMD_PHY_MODE_21 = 0x1B8, /* Phy Mode 21 */ - CMD_SL_MODE0 = 0x1BC, /* SL Mode 0 */ - CMD_SL_MODE1 = 0x1C0, /* SL Mode 1 */ - CMD_PND_FIFO_CTL1 = 0x1C4, /* Pending FIFO Control 1 */ -}; - -/* SAS/SATA configuration port registers, aka phy registers */ -enum sas_sata_config_port_regs { - PHYR_IDENTIFY = 0x00, /* info for IDENTIFY frame */ - PHYR_ADDR_LO = 0x04, /* my SAS address (low) */ - PHYR_ADDR_HI = 0x08, /* my SAS address (high) */ - PHYR_ATT_DEV_INFO = 0x0C, /* attached device info */ - PHYR_ATT_ADDR_LO = 0x10, /* attached dev SAS addr (low) */ - PHYR_ATT_ADDR_HI = 0x14, /* attached dev SAS addr (high) */ - PHYR_SATA_CTL = 0x18, /* SATA control */ - PHYR_PHY_STAT = 0x1C, /* PHY status */ - PHYR_SATA_SIG0 = 0x20, /*port SATA signature FIS(Byte 0-3) */ - PHYR_SATA_SIG1 = 0x24, /*port SATA signature FIS(Byte 4-7) */ - PHYR_SATA_SIG2 = 0x28, /*port SATA signature FIS(Byte 8-11) */ - PHYR_SATA_SIG3 = 0x2c, /*port SATA signature FIS(Byte 12-15) */ - PHYR_R_ERR_COUNT = 0x30, /* port R_ERR count register */ - PHYR_CRC_ERR_COUNT = 0x34, /* port CRC error count register */ - PHYR_WIDE_PORT = 0x38, /* wide port participating */ - PHYR_CURRENT0 = 0x80, /* current connection info 0 */ - PHYR_CURRENT1 = 0x84, /* current connection info 1 */ - PHYR_CURRENT2 = 0x88, /* current connection info 2 */ -}; - -/* SAS/SATA Vendor Specific Port Registers */ -enum sas_sata_vsp_regs { - VSR_PHY_STAT = 0x00, /* Phy Status */ - VSR_PHY_MODE1 = 0x01, /* phy tx */ - VSR_PHY_MODE2 = 0x02, /* tx scc */ - VSR_PHY_MODE3 = 0x03, /* pll */ - VSR_PHY_MODE4 = 0x04, /* VCO */ - VSR_PHY_MODE5 = 0x05, /* Rx */ - VSR_PHY_MODE6 = 0x06, /* CDR */ - VSR_PHY_MODE7 = 0x07, /* Impedance */ - VSR_PHY_MODE8 = 0x08, /* Voltage */ - VSR_PHY_MODE9 = 0x09, /* Test */ - VSR_PHY_MODE10 = 0x0A, /* Power */ - VSR_PHY_MODE11 = 0x0B, /* Phy Mode */ - VSR_PHY_VS0 = 0x0C, /* Vednor Specific 0 */ - VSR_PHY_VS1 = 0x0D, /* Vednor Specific 1 */ -}; - -enum pci_cfg_registers { - PCR_PHY_CTL = 0x40, - PCR_PHY_CTL2 = 0x90, - PCR_DEV_CTRL = 0xE8, -}; - -enum pci_cfg_register_bits { - PCTL_PWR_ON = (0xFU << 24), - PCTL_OFF = (0xFU << 12), - PRD_REQ_SIZE = (0x4000), - PRD_REQ_MASK = (0x00007000), -}; - -enum nvram_layout_offsets { - NVR_SIG = 0x00, /* 0xAA, 0x55 */ - NVR_SAS_ADDR = 0x02, /* 8-byte SAS address */ -}; - -enum chip_flavors { - chip_6320, - chip_6440, - chip_6480, -}; - -enum port_type { - PORT_TYPE_SAS = (1L << 1), - PORT_TYPE_SATA = (1L << 0), -}; - -/* Command Table Format */ -enum ct_format { - /* SSP */ - SSP_F_H = 0x00, - SSP_F_IU = 0x18, - SSP_F_MAX = 0x4D, - /* STP */ - STP_CMD_FIS = 0x00, - STP_ATAPI_CMD = 0x40, - STP_F_MAX = 0x10, - /* SMP */ - SMP_F_T = 0x00, - SMP_F_DEP = 0x01, - SMP_F_MAX = 0x101, -}; - -enum status_buffer { - SB_EIR_OFF = 0x00, /* Error Information Record */ - SB_RFB_OFF = 0x08, /* Response Frame Buffer */ - SB_RFB_MAX = 0x400, /* RFB size*/ -}; - -enum error_info_rec { - CMD_ISS_STPD = (1U << 31), /* Cmd Issue Stopped */ - CMD_PI_ERR = (1U << 30), /* Protection info error. see flags2 */ - RSP_OVER = (1U << 29), /* rsp buffer overflow */ - RETRY_LIM = (1U << 28), /* FIS/frame retry limit exceeded */ - UNK_FIS = (1U << 27), /* unknown FIS */ - DMA_TERM = (1U << 26), /* DMA terminate primitive rx'd */ - SYNC_ERR = (1U << 25), /* SYNC rx'd during frame xmit */ - TFILE_ERR = (1U << 24), /* SATA taskfile Error bit set */ - R_ERR = (1U << 23), /* SATA returned R_ERR prim */ - RD_OFS = (1U << 20), /* Read DATA frame invalid offset */ - XFER_RDY_OFS = (1U << 19), /* XFER_RDY offset error */ - UNEXP_XFER_RDY = (1U << 18), /* unexpected XFER_RDY error */ - DATA_OVER_UNDER = (1U << 16), /* data overflow/underflow */ - INTERLOCK = (1U << 15), /* interlock error */ - NAK = (1U << 14), /* NAK rx'd */ - ACK_NAK_TO = (1U << 13), /* ACK/NAK timeout */ - CXN_CLOSED = (1U << 12), /* cxn closed w/out ack/nak */ - OPEN_TO = (1U << 11), /* I_T nexus lost, open cxn timeout */ - PATH_BLOCKED = (1U << 10), /* I_T nexus lost, pathway blocked */ - NO_DEST = (1U << 9), /* I_T nexus lost, no destination */ - STP_RES_BSY = (1U << 8), /* STP resources busy */ - BREAK = (1U << 7), /* break received */ - BAD_DEST = (1U << 6), /* bad destination */ - BAD_PROTO = (1U << 5), /* protocol not supported */ - BAD_RATE = (1U << 4), /* cxn rate not supported */ - WRONG_DEST = (1U << 3), /* wrong destination error */ - CREDIT_TO = (1U << 2), /* credit timeout */ - WDOG_TO = (1U << 1), /* watchdog timeout */ - BUF_PAR = (1U << 0), /* buffer parity error */ -}; - -enum error_info_rec_2 { - SLOT_BSY_ERR = (1U << 31), /* Slot Busy Error */ - GRD_CHK_ERR = (1U << 14), /* Guard Check Error */ - APP_CHK_ERR = (1U << 13), /* Application Check error */ - REF_CHK_ERR = (1U << 12), /* Reference Check Error */ - USR_BLK_NM = (1U << 0), /* User Block Number */ -}; - -struct mvs_chip_info { - u32 n_phy; - u32 srs_sz; - u32 slot_width; -}; - -struct mvs_err_info { - __le32 flags; - __le32 flags2; -}; - -struct mvs_prd { - __le64 addr; /* 64-bit buffer address */ - __le32 reserved; - __le32 len; /* 16-bit length */ -}; - -struct mvs_cmd_hdr { - __le32 flags; /* PRD tbl len; SAS, SATA ctl */ - __le32 lens; /* cmd, max resp frame len */ - __le32 tags; /* targ port xfer tag; tag */ - __le32 data_len; /* data xfer len */ - __le64 cmd_tbl; /* command table address */ - __le64 open_frame; /* open addr frame address */ - __le64 status_buf; /* status buffer address */ - __le64 prd_tbl; /* PRD tbl address */ - __le32 reserved[4]; -}; - -struct mvs_port { - struct asd_sas_port sas_port; - u8 port_attached; - u8 taskfileset; - u8 wide_port_phymap; - struct list_head list; -}; - -struct mvs_phy { - struct mvs_port *port; - struct asd_sas_phy sas_phy; - struct sas_identify identify; - struct scsi_device *sdev; - u64 dev_sas_addr; - u64 att_dev_sas_addr; - u32 att_dev_info; - u32 dev_info; - u32 phy_type; - u32 phy_status; - u32 irq_status; - u32 frame_rcvd_size; - u8 frame_rcvd[32]; - u8 phy_attached; - enum sas_linkrate minimum_linkrate; - enum sas_linkrate maximum_linkrate; -}; - -struct mvs_slot_info { - struct list_head list; - struct sas_task *task; - u32 n_elem; - u32 tx; - - /* DMA buffer for storing cmd tbl, open addr frame, status buffer, - * and PRD table - */ - void *buf; - dma_addr_t buf_dma; -#if _MV_DUMP - u32 cmd_size; -#endif - - void *response; - struct mvs_port *port; -}; - -struct mvs_info { - unsigned long flags; - - spinlock_t lock; /* host-wide lock */ - struct pci_dev *pdev; /* our device */ - void __iomem *regs; /* enhanced mode registers */ - void __iomem *peri_regs; /* peripheral registers */ - - u8 sas_addr[SAS_ADDR_SIZE]; - struct sas_ha_struct sas; /* SCSI/SAS glue */ - struct Scsi_Host *shost; - - __le32 *tx; /* TX (delivery) DMA ring */ - dma_addr_t tx_dma; - u32 tx_prod; /* cached next-producer idx */ - - __le32 *rx; /* RX (completion) DMA ring */ - dma_addr_t rx_dma; - u32 rx_cons; /* RX consumer idx */ - - __le32 *rx_fis; /* RX'd FIS area */ - dma_addr_t rx_fis_dma; - - struct mvs_cmd_hdr *slot; /* DMA command header slots */ - dma_addr_t slot_dma; - - const struct mvs_chip_info *chip; - - u8 tags[MVS_SLOTS]; - struct mvs_slot_info slot_info[MVS_SLOTS]; - /* further per-slot information */ - struct mvs_phy phy[MVS_MAX_PHYS]; - struct mvs_port port[MVS_MAX_PHYS]; -#ifdef MVS_USE_TASKLET - struct tasklet_struct tasklet; -#endif -}; - -static int mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func, - void *funcdata); -static u32 mvs_read_phy_ctl(struct mvs_info *mvi, u32 port); -static void mvs_write_phy_ctl(struct mvs_info *mvi, u32 port, u32 val); -static u32 mvs_read_port_irq_stat(struct mvs_info *mvi, u32 port); -static void mvs_write_port_irq_stat(struct mvs_info *mvi, u32 port, u32 val); -static void mvs_write_port_irq_mask(struct mvs_info *mvi, u32 port, u32 val); -static u32 mvs_read_port_irq_mask(struct mvs_info *mvi, u32 port); - -static u32 mvs_is_phy_ready(struct mvs_info *mvi, int i); -static void mvs_detect_porttype(struct mvs_info *mvi, int i); -static void mvs_update_phyinfo(struct mvs_info *mvi, int i, int get_st); -static void mvs_release_task(struct mvs_info *mvi, int phy_no); - -static int mvs_scan_finished(struct Scsi_Host *, unsigned long); -static void mvs_scan_start(struct Scsi_Host *); -static int mvs_slave_configure(struct scsi_device *sdev); - -static struct scsi_transport_template *mvs_stt; - -static const struct mvs_chip_info mvs_chips[] = { - [chip_6320] = { 2, 16, 9 }, - [chip_6440] = { 4, 16, 9 }, - [chip_6480] = { 8, 32, 10 }, -}; - -static struct scsi_host_template mvs_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .queuecommand = sas_queuecommand, - .target_alloc = sas_target_alloc, - .slave_configure = mvs_slave_configure, - .slave_destroy = sas_slave_destroy, - .scan_finished = mvs_scan_finished, - .scan_start = mvs_scan_start, - .change_queue_depth = sas_change_queue_depth, - .change_queue_type = sas_change_queue_type, - .bios_param = sas_bios_param, - .can_queue = 1, - .cmd_per_lun = 1, - .this_id = -1, - .sg_tablesize = SG_ALL, - .max_sectors = SCSI_DEFAULT_MAX_SECTORS, - .use_clustering = ENABLE_CLUSTERING, - .eh_device_reset_handler = sas_eh_device_reset_handler, - .eh_bus_reset_handler = sas_eh_bus_reset_handler, - .slave_alloc = sas_slave_alloc, - .target_destroy = sas_target_destroy, - .ioctl = sas_ioctl, -}; - -static void mvs_hexdump(u32 size, u8 *data, u32 baseaddr) -{ - u32 i; - u32 run; - u32 offset; - - offset = 0; - while (size) { - printk("%08X : ", baseaddr + offset); - if (size >= 16) - run = 16; - else - run = size; - size -= run; - for (i = 0; i < 16; i++) { - if (i < run) - printk("%02X ", (u32)data[i]); - else - printk(" "); - } - printk(": "); - for (i = 0; i < run; i++) - printk("%c", isalnum(data[i]) ? data[i] : '.'); - printk("\n"); - data = &data[16]; - offset += run; - } - printk("\n"); -} - -#if _MV_DUMP -static void mvs_hba_sb_dump(struct mvs_info *mvi, u32 tag, - enum sas_protocol proto) -{ - u32 offset; - struct pci_dev *pdev = mvi->pdev; - struct mvs_slot_info *slot = &mvi->slot_info[tag]; - - offset = slot->cmd_size + MVS_OAF_SZ + - sizeof(struct mvs_prd) * slot->n_elem; - dev_printk(KERN_DEBUG, &pdev->dev, "+---->Status buffer[%d] :\n", - tag); - mvs_hexdump(32, (u8 *) slot->response, - (u32) slot->buf_dma + offset); -} -#endif - -static void mvs_hba_memory_dump(struct mvs_info *mvi, u32 tag, - enum sas_protocol proto) -{ -#if _MV_DUMP - u32 sz, w_ptr; - u64 addr; - void __iomem *regs = mvi->regs; - struct pci_dev *pdev = mvi->pdev; - struct mvs_slot_info *slot = &mvi->slot_info[tag]; - - /*Delivery Queue */ - sz = mr32(TX_CFG) & TX_RING_SZ_MASK; - w_ptr = slot->tx; - addr = mr32(TX_HI) << 16 << 16 | mr32(TX_LO); - dev_printk(KERN_DEBUG, &pdev->dev, - "Delivery Queue Size=%04d , WRT_PTR=%04X\n", sz, w_ptr); - dev_printk(KERN_DEBUG, &pdev->dev, - "Delivery Queue Base Address=0x%llX (PA)" - "(tx_dma=0x%llX), Entry=%04d\n", - addr, mvi->tx_dma, w_ptr); - mvs_hexdump(sizeof(u32), (u8 *)(&mvi->tx[mvi->tx_prod]), - (u32) mvi->tx_dma + sizeof(u32) * w_ptr); - /*Command List */ - addr = mvi->slot_dma; - dev_printk(KERN_DEBUG, &pdev->dev, - "Command List Base Address=0x%llX (PA)" - "(slot_dma=0x%llX), Header=%03d\n", - addr, slot->buf_dma, tag); - dev_printk(KERN_DEBUG, &pdev->dev, "Command Header[%03d]:\n", tag); - /*mvs_cmd_hdr */ - mvs_hexdump(sizeof(struct mvs_cmd_hdr), (u8 *)(&mvi->slot[tag]), - (u32) mvi->slot_dma + tag * sizeof(struct mvs_cmd_hdr)); - /*1.command table area */ - dev_printk(KERN_DEBUG, &pdev->dev, "+---->Command Table :\n"); - mvs_hexdump(slot->cmd_size, (u8 *) slot->buf, (u32) slot->buf_dma); - /*2.open address frame area */ - dev_printk(KERN_DEBUG, &pdev->dev, "+---->Open Address Frame :\n"); - mvs_hexdump(MVS_OAF_SZ, (u8 *) slot->buf + slot->cmd_size, - (u32) slot->buf_dma + slot->cmd_size); - /*3.status buffer */ - mvs_hba_sb_dump(mvi, tag, proto); - /*4.PRD table */ - dev_printk(KERN_DEBUG, &pdev->dev, "+---->PRD table :\n"); - mvs_hexdump(sizeof(struct mvs_prd) * slot->n_elem, - (u8 *) slot->buf + slot->cmd_size + MVS_OAF_SZ, - (u32) slot->buf_dma + slot->cmd_size + MVS_OAF_SZ); -#endif -} - -static void mvs_hba_cq_dump(struct mvs_info *mvi) -{ -#if (_MV_DUMP > 2) - u64 addr; - void __iomem *regs = mvi->regs; - struct pci_dev *pdev = mvi->pdev; - u32 entry = mvi->rx_cons + 1; - u32 rx_desc = le32_to_cpu(mvi->rx[entry]); - - /*Completion Queue */ - addr = mr32(RX_HI) << 16 << 16 | mr32(RX_LO); - dev_printk(KERN_DEBUG, &pdev->dev, "Completion Task = 0x%p\n", - mvi->slot_info[rx_desc & RXQ_SLOT_MASK].task); - dev_printk(KERN_DEBUG, &pdev->dev, - "Completion List Base Address=0x%llX (PA), " - "CQ_Entry=%04d, CQ_WP=0x%08X\n", - addr, entry - 1, mvi->rx[0]); - mvs_hexdump(sizeof(u32), (u8 *)(&rx_desc), - mvi->rx_dma + sizeof(u32) * entry); -#endif -} - -static void mvs_hba_interrupt_enable(struct mvs_info *mvi) -{ - void __iomem *regs = mvi->regs; - u32 tmp; - - tmp = mr32(GBL_CTL); - - mw32(GBL_CTL, tmp | INT_EN); -} - -static void mvs_hba_interrupt_disable(struct mvs_info *mvi) -{ - void __iomem *regs = mvi->regs; - u32 tmp; - - tmp = mr32(GBL_CTL); - - mw32(GBL_CTL, tmp & ~INT_EN); -} - -static int mvs_int_rx(struct mvs_info *mvi, bool self_clear); - -/* move to PCI layer or libata core? */ -static int pci_go_64(struct pci_dev *pdev) -{ - int rc; - - if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { - rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); - if (rc) { - rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); - if (rc) { - dev_printk(KERN_ERR, &pdev->dev, - "64-bit DMA enable failed\n"); - return rc; - } - } - } else { - rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (rc) { - dev_printk(KERN_ERR, &pdev->dev, - "32-bit DMA enable failed\n"); - return rc; - } - rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); - if (rc) { - dev_printk(KERN_ERR, &pdev->dev, - "32-bit consistent DMA enable failed\n"); - return rc; - } - } - - return rc; -} - -static int mvs_find_tag(struct mvs_info *mvi, struct sas_task *task, u32 *tag) -{ - if (task->lldd_task) { - struct mvs_slot_info *slot; - slot = (struct mvs_slot_info *) task->lldd_task; - *tag = slot - mvi->slot_info; - return 1; - } - return 0; -} - -static void mvs_tag_clear(struct mvs_info *mvi, u32 tag) -{ - void *bitmap = (void *) &mvi->tags; - clear_bit(tag, bitmap); -} - -static void mvs_tag_free(struct mvs_info *mvi, u32 tag) -{ - mvs_tag_clear(mvi, tag); -} - -static void mvs_tag_set(struct mvs_info *mvi, unsigned int tag) -{ - void *bitmap = (void *) &mvi->tags; - set_bit(tag, bitmap); -} - -static int mvs_tag_alloc(struct mvs_info *mvi, u32 *tag_out) -{ - unsigned int index, tag; - void *bitmap = (void *) &mvi->tags; - - index = find_first_zero_bit(bitmap, MVS_SLOTS); - tag = index; - if (tag >= MVS_SLOTS) - return -SAS_QUEUE_FULL; - mvs_tag_set(mvi, tag); - *tag_out = tag; - return 0; -} - -static void mvs_tag_init(struct mvs_info *mvi) -{ - int i; - for (i = 0; i < MVS_SLOTS; ++i) - mvs_tag_clear(mvi, i); -} - -#ifndef MVS_DISABLE_NVRAM -static int mvs_eep_read(void __iomem *regs, u32 addr, u32 *data) -{ - int timeout = 1000; - - if (addr & ~SPI_ADDR_MASK) - return -EINVAL; - - writel(addr, regs + SPI_CMD); - writel(TWSI_RD, regs + SPI_CTL); - - while (timeout-- > 0) { - if (readl(regs + SPI_CTL) & TWSI_RDY) { - *data = readl(regs + SPI_DATA); - return 0; - } - - udelay(10); - } - - return -EBUSY; -} - -static int mvs_eep_read_buf(void __iomem *regs, u32 addr, - void *buf, u32 buflen) -{ - u32 addr_end, tmp_addr, i, j; - u32 tmp = 0; - int rc; - u8 *tmp8, *buf8 = buf; - - addr_end = addr + buflen; - tmp_addr = ALIGN(addr, 4); - if (addr > 0xff) - return -EINVAL; - - j = addr & 0x3; - if (j) { - rc = mvs_eep_read(regs, tmp_addr, &tmp); - if (rc) - return rc; - - tmp8 = (u8 *)&tmp; - for (i = j; i < 4; i++) - *buf8++ = tmp8[i]; - - tmp_addr += 4; - } - - for (j = ALIGN(addr_end, 4); tmp_addr < j; tmp_addr += 4) { - rc = mvs_eep_read(regs, tmp_addr, &tmp); - if (rc) - return rc; - - memcpy(buf8, &tmp, 4); - buf8 += 4; - } - - if (tmp_addr < addr_end) { - rc = mvs_eep_read(regs, tmp_addr, &tmp); - if (rc) - return rc; - - tmp8 = (u8 *)&tmp; - j = addr_end - tmp_addr; - for (i = 0; i < j; i++) - *buf8++ = tmp8[i]; - - tmp_addr += 4; - } - - return 0; -} -#endif - -static int mvs_nvram_read(struct mvs_info *mvi, u32 addr, - void *buf, u32 buflen) -{ -#ifndef MVS_DISABLE_NVRAM - void __iomem *regs = mvi->regs; - int rc, i; - u32 sum; - u8 hdr[2], *tmp; - const char *msg; - - rc = mvs_eep_read_buf(regs, addr, &hdr, 2); - if (rc) { - msg = "nvram hdr read failed"; - goto err_out; - } - rc = mvs_eep_read_buf(regs, addr + 2, buf, buflen); - if (rc) { - msg = "nvram read failed"; - goto err_out; - } - - if (hdr[0] != 0x5A) { - /* entry id */ - msg = "invalid nvram entry id"; - rc = -ENOENT; - goto err_out; - } - - tmp = buf; - sum = ((u32)hdr[0]) + ((u32)hdr[1]); - for (i = 0; i < buflen; i++) - sum += ((u32)tmp[i]); - - if (sum) { - msg = "nvram checksum failure"; - rc = -EILSEQ; - goto err_out; - } - - return 0; - -err_out: - dev_printk(KERN_ERR, &mvi->pdev->dev, "%s", msg); - return rc; -#else - /* FIXME , For SAS target mode */ - memcpy(buf, "\x50\x05\x04\x30\x11\xab\x00\x00", 8); - return 0; -#endif -} - -static void mvs_bytes_dmaed(struct mvs_info *mvi, int i) -{ - struct mvs_phy *phy = &mvi->phy[i]; - struct asd_sas_phy *sas_phy = mvi->sas.sas_phy[i]; - - if (!phy->phy_attached) - return; - - if (sas_phy->phy) { - struct sas_phy *sphy = sas_phy->phy; - - sphy->negotiated_linkrate = sas_phy->linkrate; - sphy->minimum_linkrate = phy->minimum_linkrate; - sphy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS; - sphy->maximum_linkrate = phy->maximum_linkrate; - sphy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS; - } - - if (phy->phy_type & PORT_TYPE_SAS) { - struct sas_identify_frame *id; - - id = (struct sas_identify_frame *)phy->frame_rcvd; - id->dev_type = phy->identify.device_type; - id->initiator_bits = SAS_PROTOCOL_ALL; - id->target_bits = phy->identify.target_port_protocols; - } else if (phy->phy_type & PORT_TYPE_SATA) { - /* TODO */ - } - mvi->sas.sas_phy[i]->frame_rcvd_size = phy->frame_rcvd_size; - mvi->sas.notify_port_event(mvi->sas.sas_phy[i], - PORTE_BYTES_DMAED); -} - -static int mvs_scan_finished(struct Scsi_Host *shost, unsigned long time) -{ - /* give the phy enabling interrupt event time to come in (1s - * is empirically about all it takes) */ - if (time < HZ) - return 0; - /* Wait for discovery to finish */ - scsi_flush_work(shost); - return 1; -} - -static void mvs_scan_start(struct Scsi_Host *shost) -{ - int i; - struct mvs_info *mvi = SHOST_TO_SAS_HA(shost)->lldd_ha; - - for (i = 0; i < mvi->chip->n_phy; ++i) { - mvs_bytes_dmaed(mvi, i); - } -} - -static int mvs_slave_configure(struct scsi_device *sdev) -{ - struct domain_device *dev = sdev_to_domain_dev(sdev); - int ret = sas_slave_configure(sdev); - - if (ret) - return ret; - - if (dev_is_sata(dev)) { - /* struct ata_port *ap = dev->sata_dev.ap; */ - /* struct ata_device *adev = ap->link.device; */ - - /* clamp at no NCQ for the time being */ - /* adev->flags |= ATA_DFLAG_NCQ_OFF; */ - scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, 1); - } - return 0; -} - -static void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events) -{ - struct pci_dev *pdev = mvi->pdev; - struct sas_ha_struct *sas_ha = &mvi->sas; - struct mvs_phy *phy = &mvi->phy[phy_no]; - struct asd_sas_phy *sas_phy = &phy->sas_phy; - - phy->irq_status = mvs_read_port_irq_stat(mvi, phy_no); - /* - * events is port event now , - * we need check the interrupt status which belongs to per port. - */ - dev_printk(KERN_DEBUG, &pdev->dev, - "Port %d Event = %X\n", - phy_no, phy->irq_status); - - if (phy->irq_status & (PHYEV_POOF | PHYEV_DEC_ERR)) { - mvs_release_task(mvi, phy_no); - if (!mvs_is_phy_ready(mvi, phy_no)) { - sas_phy_disconnected(sas_phy); - sas_ha->notify_phy_event(sas_phy, PHYE_LOSS_OF_SIGNAL); - dev_printk(KERN_INFO, &pdev->dev, - "Port %d Unplug Notice\n", phy_no); - - } else - mvs_phy_control(sas_phy, PHY_FUNC_LINK_RESET, NULL); - } - if (!(phy->irq_status & PHYEV_DEC_ERR)) { - if (phy->irq_status & PHYEV_COMWAKE) { - u32 tmp = mvs_read_port_irq_mask(mvi, phy_no); - mvs_write_port_irq_mask(mvi, phy_no, - tmp | PHYEV_SIG_FIS); - } - if (phy->irq_status & (PHYEV_SIG_FIS | PHYEV_ID_DONE)) { - phy->phy_status = mvs_is_phy_ready(mvi, phy_no); - if (phy->phy_status) { - mvs_detect_porttype(mvi, phy_no); - - if (phy->phy_type & PORT_TYPE_SATA) { - u32 tmp = mvs_read_port_irq_mask(mvi, - phy_no); - tmp &= ~PHYEV_SIG_FIS; - mvs_write_port_irq_mask(mvi, - phy_no, tmp); - } - - mvs_update_phyinfo(mvi, phy_no, 0); - sas_ha->notify_phy_event(sas_phy, - PHYE_OOB_DONE); - mvs_bytes_dmaed(mvi, phy_no); - } else { - dev_printk(KERN_DEBUG, &pdev->dev, - "plugin interrupt but phy is gone\n"); - mvs_phy_control(sas_phy, PHY_FUNC_LINK_RESET, - NULL); - } - } else if (phy->irq_status & PHYEV_BROAD_CH) { - mvs_release_task(mvi, phy_no); - sas_ha->notify_port_event(sas_phy, - PORTE_BROADCAST_RCVD); - } - } - mvs_write_port_irq_stat(mvi, phy_no, phy->irq_status); -} - -static void mvs_int_sata(struct mvs_info *mvi) -{ - u32 tmp; - void __iomem *regs = mvi->regs; - tmp = mr32(INT_STAT_SRS); - mw32(INT_STAT_SRS, tmp & 0xFFFF); -} - -static void mvs_slot_reset(struct mvs_info *mvi, struct sas_task *task, - u32 slot_idx) -{ - void __iomem *regs = mvi->regs; - struct domain_device *dev = task->dev; - struct asd_sas_port *sas_port = dev->port; - struct mvs_port *port = mvi->slot_info[slot_idx].port; - u32 reg_set, phy_mask; - - if (!sas_protocol_ata(task->task_proto)) { - reg_set = 0; - phy_mask = (port->wide_port_phymap) ? port->wide_port_phymap : - sas_port->phy_mask; - } else { - reg_set = port->taskfileset; - phy_mask = sas_port->phy_mask; - } - mvi->tx[mvi->tx_prod] = cpu_to_le32(TXQ_MODE_I | slot_idx | - (TXQ_CMD_SLOT_RESET << TXQ_CMD_SHIFT) | - (phy_mask << TXQ_PHY_SHIFT) | - (reg_set << TXQ_SRS_SHIFT)); - - mw32(TX_PROD_IDX, mvi->tx_prod); - mvi->tx_prod = (mvi->tx_prod + 1) & (MVS_CHIP_SLOT_SZ - 1); -} - -static int mvs_sata_done(struct mvs_info *mvi, struct sas_task *task, - u32 slot_idx, int err) -{ - struct mvs_port *port = mvi->slot_info[slot_idx].port; - struct task_status_struct *tstat = &task->task_status; - struct ata_task_resp *resp = (struct ata_task_resp *)tstat->buf; - int stat = SAM_GOOD; - - resp->frame_len = sizeof(struct dev_to_host_fis); - memcpy(&resp->ending_fis[0], - SATA_RECEIVED_D2H_FIS(port->taskfileset), - sizeof(struct dev_to_host_fis)); - tstat->buf_valid_size = sizeof(*resp); - if (unlikely(err)) - stat = SAS_PROTO_RESPONSE; - return stat; -} - -static void mvs_slot_free(struct mvs_info *mvi, u32 rx_desc) -{ - u32 slot_idx = rx_desc & RXQ_SLOT_MASK; - mvs_tag_clear(mvi, slot_idx); -} - -static void mvs_slot_task_free(struct mvs_info *mvi, struct sas_task *task, - struct mvs_slot_info *slot, u32 slot_idx) -{ - if (!sas_protocol_ata(task->task_proto)) - if (slot->n_elem) - pci_unmap_sg(mvi->pdev, task->scatter, - slot->n_elem, task->data_dir); - - switch (task->task_proto) { - case SAS_PROTOCOL_SMP: - pci_unmap_sg(mvi->pdev, &task->smp_task.smp_resp, 1, - PCI_DMA_FROMDEVICE); - pci_unmap_sg(mvi->pdev, &task->smp_task.smp_req, 1, - PCI_DMA_TODEVICE); - break; - - case SAS_PROTOCOL_SATA: - case SAS_PROTOCOL_STP: - case SAS_PROTOCOL_SSP: - default: - /* do nothing */ - break; - } - list_del(&slot->list); - task->lldd_task = NULL; - slot->task = NULL; - slot->port = NULL; -} - -static int mvs_slot_err(struct mvs_info *mvi, struct sas_task *task, - u32 slot_idx) -{ - struct mvs_slot_info *slot = &mvi->slot_info[slot_idx]; - u32 err_dw0 = le32_to_cpu(*(u32 *) (slot->response)); - u32 err_dw1 = le32_to_cpu(*(u32 *) (slot->response + 4)); - int stat = SAM_CHECK_COND; - - if (err_dw1 & SLOT_BSY_ERR) { - stat = SAS_QUEUE_FULL; - mvs_slot_reset(mvi, task, slot_idx); - } - switch (task->task_proto) { - case SAS_PROTOCOL_SSP: - break; - case SAS_PROTOCOL_SMP: - break; - case SAS_PROTOCOL_SATA: - case SAS_PROTOCOL_STP: - case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: - if (err_dw0 & TFILE_ERR) - stat = mvs_sata_done(mvi, task, slot_idx, 1); - break; - default: - break; - } - - mvs_hexdump(16, (u8 *) slot->response, 0); - return stat; -} - -static int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags) -{ - u32 slot_idx = rx_desc & RXQ_SLOT_MASK; - struct mvs_slot_info *slot = &mvi->slot_info[slot_idx]; - struct sas_task *task = slot->task; - struct task_status_struct *tstat; - struct mvs_port *port; - bool aborted; - void *to; - - if (unlikely(!task || !task->lldd_task)) - return -1; - - mvs_hba_cq_dump(mvi); - - spin_lock(&task->task_state_lock); - aborted = task->task_state_flags & SAS_TASK_STATE_ABORTED; - if (!aborted) { - task->task_state_flags &= - ~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR); - task->task_state_flags |= SAS_TASK_STATE_DONE; - } - spin_unlock(&task->task_state_lock); - - if (aborted) { - mvs_slot_task_free(mvi, task, slot, slot_idx); - mvs_slot_free(mvi, rx_desc); - return -1; - } - - port = slot->port; - tstat = &task->task_status; - memset(tstat, 0, sizeof(*tstat)); - tstat->resp = SAS_TASK_COMPLETE; - - if (unlikely(!port->port_attached || flags)) { - mvs_slot_err(mvi, task, slot_idx); - if (!sas_protocol_ata(task->task_proto)) - tstat->stat = SAS_PHY_DOWN; - goto out; - } - - /* error info record present */ - if (unlikely((rx_desc & RXQ_ERR) && (*(u64 *) slot->response))) { - tstat->stat = mvs_slot_err(mvi, task, slot_idx); - goto out; - } - - switch (task->task_proto) { - case SAS_PROTOCOL_SSP: - /* hw says status == 0, datapres == 0 */ - if (rx_desc & RXQ_GOOD) { - tstat->stat = SAM_GOOD; - tstat->resp = SAS_TASK_COMPLETE; - } - /* response frame present */ - else if (rx_desc & RXQ_RSP) { - struct ssp_response_iu *iu = - slot->response + sizeof(struct mvs_err_info); - sas_ssp_task_response(&mvi->pdev->dev, task, iu); - } - - /* should never happen? */ - else - tstat->stat = SAM_CHECK_COND; - break; - - case SAS_PROTOCOL_SMP: { - struct scatterlist *sg_resp = &task->smp_task.smp_resp; - tstat->stat = SAM_GOOD; - to = kmap_atomic(sg_page(sg_resp), KM_IRQ0); - memcpy(to + sg_resp->offset, - slot->response + sizeof(struct mvs_err_info), - sg_dma_len(sg_resp)); - kunmap_atomic(to, KM_IRQ0); - break; - } - - case SAS_PROTOCOL_SATA: - case SAS_PROTOCOL_STP: - case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: { - tstat->stat = mvs_sata_done(mvi, task, slot_idx, 0); - break; - } - - default: - tstat->stat = SAM_CHECK_COND; - break; - } - -out: - mvs_slot_task_free(mvi, task, slot, slot_idx); - if (unlikely(tstat->stat != SAS_QUEUE_FULL)) - mvs_slot_free(mvi, rx_desc); - - spin_unlock(&mvi->lock); - task->task_done(task); - spin_lock(&mvi->lock); - return tstat->stat; -} - -static void mvs_release_task(struct mvs_info *mvi, int phy_no) -{ - struct list_head *pos, *n; - struct mvs_slot_info *slot; - struct mvs_phy *phy = &mvi->phy[phy_no]; - struct mvs_port *port = phy->port; - u32 rx_desc; - - if (!port) - return; - - list_for_each_safe(pos, n, &port->list) { - slot = container_of(pos, struct mvs_slot_info, list); - rx_desc = (u32) (slot - mvi->slot_info); - mvs_slot_complete(mvi, rx_desc, 1); - } -} - -static void mvs_int_full(struct mvs_info *mvi) -{ - void __iomem *regs = mvi->regs; - u32 tmp, stat; - int i; - - stat = mr32(INT_STAT); - - mvs_int_rx(mvi, false); - - for (i = 0; i < MVS_MAX_PORTS; i++) { - tmp = (stat >> i) & (CINT_PORT | CINT_PORT_STOPPED); - if (tmp) - mvs_int_port(mvi, i, tmp); - } - - if (stat & CINT_SRS) - mvs_int_sata(mvi); - - mw32(INT_STAT, stat); -} - -static int mvs_int_rx(struct mvs_info *mvi, bool self_clear) -{ - void __iomem *regs = mvi->regs; - u32 rx_prod_idx, rx_desc; - bool attn = false; - struct pci_dev *pdev = mvi->pdev; - - /* the first dword in the RX ring is special: it contains - * a mirror of the hardware's RX producer index, so that - * we don't have to stall the CPU reading that register. - * The actual RX ring is offset by one dword, due to this. - */ - rx_prod_idx = mvi->rx_cons; - mvi->rx_cons = le32_to_cpu(mvi->rx[0]); - if (mvi->rx_cons == 0xfff) /* h/w hasn't touched RX ring yet */ - return 0; - - /* The CMPL_Q may come late, read from register and try again - * note: if coalescing is enabled, - * it will need to read from register every time for sure - */ - if (mvi->rx_cons == rx_prod_idx) - mvi->rx_cons = mr32(RX_CONS_IDX) & RX_RING_SZ_MASK; - - if (mvi->rx_cons == rx_prod_idx) - return 0; - - while (mvi->rx_cons != rx_prod_idx) { - - /* increment our internal RX consumer pointer */ - rx_prod_idx = (rx_prod_idx + 1) & (MVS_RX_RING_SZ - 1); - - rx_desc = le32_to_cpu(mvi->rx[rx_prod_idx + 1]); - - if (likely(rx_desc & RXQ_DONE)) - mvs_slot_complete(mvi, rx_desc, 0); - if (rx_desc & RXQ_ATTN) { - attn = true; - dev_printk(KERN_DEBUG, &pdev->dev, "ATTN %X\n", - rx_desc); - } else if (rx_desc & RXQ_ERR) { - if (!(rx_desc & RXQ_DONE)) - mvs_slot_complete(mvi, rx_desc, 0); - dev_printk(KERN_DEBUG, &pdev->dev, "RXQ_ERR %X\n", - rx_desc); - } else if (rx_desc & RXQ_SLOT_RESET) { - dev_printk(KERN_DEBUG, &pdev->dev, "Slot reset[%X]\n", - rx_desc); - mvs_slot_free(mvi, rx_desc); - } - } - - if (attn && self_clear) - mvs_int_full(mvi); - - return 0; -} - -#ifdef MVS_USE_TASKLET -static void mvs_tasklet(unsigned long data) -{ - struct mvs_info *mvi = (struct mvs_info *) data; - unsigned long flags; - - spin_lock_irqsave(&mvi->lock, flags); - -#ifdef MVS_DISABLE_MSI - mvs_int_full(mvi); -#else - mvs_int_rx(mvi, true); -#endif - spin_unlock_irqrestore(&mvi->lock, flags); -} -#endif - -static irqreturn_t mvs_interrupt(int irq, void *opaque) -{ - struct mvs_info *mvi = opaque; - void __iomem *regs = mvi->regs; - u32 stat; - - stat = mr32(GBL_INT_STAT); - - if (stat == 0 || stat == 0xffffffff) - return IRQ_NONE; - - /* clear CMD_CMPLT ASAP */ - mw32_f(INT_STAT, CINT_DONE); - -#ifndef MVS_USE_TASKLET - spin_lock(&mvi->lock); - - mvs_int_full(mvi); - - spin_unlock(&mvi->lock); -#else - tasklet_schedule(&mvi->tasklet); -#endif - return IRQ_HANDLED; -} - -#ifndef MVS_DISABLE_MSI -static irqreturn_t mvs_msi_interrupt(int irq, void *opaque) -{ - struct mvs_info *mvi = opaque; - -#ifndef MVS_USE_TASKLET - spin_lock(&mvi->lock); - - mvs_int_rx(mvi, true); - - spin_unlock(&mvi->lock); -#else - tasklet_schedule(&mvi->tasklet); -#endif - return IRQ_HANDLED; -} -#endif - -struct mvs_task_exec_info { - struct sas_task *task; - struct mvs_cmd_hdr *hdr; - struct mvs_port *port; - u32 tag; - int n_elem; -}; - -static int mvs_task_prep_smp(struct mvs_info *mvi, - struct mvs_task_exec_info *tei) -{ - int elem, rc, i; - struct sas_task *task = tei->task; - struct mvs_cmd_hdr *hdr = tei->hdr; - struct scatterlist *sg_req, *sg_resp; - u32 req_len, resp_len, tag = tei->tag; - void *buf_tmp; - u8 *buf_oaf; - dma_addr_t buf_tmp_dma; - struct mvs_prd *buf_prd; - struct scatterlist *sg; - struct mvs_slot_info *slot = &mvi->slot_info[tag]; - struct asd_sas_port *sas_port = task->dev->port; - u32 flags = (tei->n_elem << MCH_PRD_LEN_SHIFT); -#if _MV_DUMP - u8 *buf_cmd; - void *from; -#endif - /* - * DMA-map SMP request, response buffers - */ - sg_req = &task->smp_task.smp_req; - elem = pci_map_sg(mvi->pdev, sg_req, 1, PCI_DMA_TODEVICE); - if (!elem) - return -ENOMEM; - req_len = sg_dma_len(sg_req); - - sg_resp = &task->smp_task.smp_resp; - elem = pci_map_sg(mvi->pdev, sg_resp, 1, PCI_DMA_FROMDEVICE); - if (!elem) { - rc = -ENOMEM; - goto err_out; - } - resp_len = sg_dma_len(sg_resp); - - /* must be in dwords */ - if ((req_len & 0x3) || (resp_len & 0x3)) { - rc = -EINVAL; - goto err_out_2; - } - - /* - * arrange MVS_SLOT_BUF_SZ-sized DMA buffer according to our needs - */ - - /* region 1: command table area (MVS_SSP_CMD_SZ bytes) ************** */ - buf_tmp = slot->buf; - buf_tmp_dma = slot->buf_dma; - -#if _MV_DUMP - buf_cmd = buf_tmp; - hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma); - buf_tmp += req_len; - buf_tmp_dma += req_len; - slot->cmd_size = req_len; -#else - hdr->cmd_tbl = cpu_to_le64(sg_dma_address(sg_req)); -#endif - - /* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */ - buf_oaf = buf_tmp; - hdr->open_frame = cpu_to_le64(buf_tmp_dma); - - buf_tmp += MVS_OAF_SZ; - buf_tmp_dma += MVS_OAF_SZ; - - /* region 3: PRD table ********************************************* */ - buf_prd = buf_tmp; - if (tei->n_elem) - hdr->prd_tbl = cpu_to_le64(buf_tmp_dma); - else - hdr->prd_tbl = 0; - - i = sizeof(struct mvs_prd) * tei->n_elem; - buf_tmp += i; - buf_tmp_dma += i; - - /* region 4: status buffer (larger the PRD, smaller this buf) ****** */ - slot->response = buf_tmp; - hdr->status_buf = cpu_to_le64(buf_tmp_dma); - - /* - * Fill in TX ring and command slot header - */ - slot->tx = mvi->tx_prod; - mvi->tx[mvi->tx_prod] = cpu_to_le32((TXQ_CMD_SMP << TXQ_CMD_SHIFT) | - TXQ_MODE_I | tag | - (sas_port->phy_mask << TXQ_PHY_SHIFT)); - - hdr->flags |= flags; - hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | ((req_len - 4) / 4)); - hdr->tags = cpu_to_le32(tag); - hdr->data_len = 0; - - /* generate open address frame hdr (first 12 bytes) */ - buf_oaf[0] = (1 << 7) | (0 << 4) | 0x01; /* initiator, SMP, ftype 1h */ - buf_oaf[1] = task->dev->linkrate & 0xf; - *(u16 *)(buf_oaf + 2) = 0xFFFF; /* SAS SPEC */ - memcpy(buf_oaf + 4, task->dev->sas_addr, SAS_ADDR_SIZE); - - /* fill in PRD (scatter/gather) table, if any */ - for_each_sg(task->scatter, sg, tei->n_elem, i) { - buf_prd->addr = cpu_to_le64(sg_dma_address(sg)); - buf_prd->len = cpu_to_le32(sg_dma_len(sg)); - buf_prd++; - } - -#if _MV_DUMP - /* copy cmd table */ - from = kmap_atomic(sg_page(sg_req), KM_IRQ0); - memcpy(buf_cmd, from + sg_req->offset, req_len); - kunmap_atomic(from, KM_IRQ0); -#endif - return 0; - -err_out_2: - pci_unmap_sg(mvi->pdev, &tei->task->smp_task.smp_resp, 1, - PCI_DMA_FROMDEVICE); -err_out: - pci_unmap_sg(mvi->pdev, &tei->task->smp_task.smp_req, 1, - PCI_DMA_TODEVICE); - return rc; -} - -static void mvs_free_reg_set(struct mvs_info *mvi, struct mvs_port *port) -{ - void __iomem *regs = mvi->regs; - u32 tmp, offs; - u8 *tfs = &port->taskfileset; - - if (*tfs == MVS_ID_NOT_MAPPED) - return; - - offs = 1U << ((*tfs & 0x0f) + PCS_EN_SATA_REG_SHIFT); - if (*tfs < 16) { - tmp = mr32(PCS); - mw32(PCS, tmp & ~offs); - } else { - tmp = mr32(CTL); - mw32(CTL, tmp & ~offs); - } - - tmp = mr32(INT_STAT_SRS) & (1U << *tfs); - if (tmp) - mw32(INT_STAT_SRS, tmp); - - *tfs = MVS_ID_NOT_MAPPED; -} - -static u8 mvs_assign_reg_set(struct mvs_info *mvi, struct mvs_port *port) -{ - int i; - u32 tmp, offs; - void __iomem *regs = mvi->regs; - - if (port->taskfileset != MVS_ID_NOT_MAPPED) - return 0; - - tmp = mr32(PCS); - - for (i = 0; i < mvi->chip->srs_sz; i++) { - if (i == 16) - tmp = mr32(CTL); - offs = 1U << ((i & 0x0f) + PCS_EN_SATA_REG_SHIFT); - if (!(tmp & offs)) { - port->taskfileset = i; - - if (i < 16) - mw32(PCS, tmp | offs); - else - mw32(CTL, tmp | offs); - tmp = mr32(INT_STAT_SRS) & (1U << i); - if (tmp) - mw32(INT_STAT_SRS, tmp); - return 0; - } - } - return MVS_ID_NOT_MAPPED; -} - -static u32 mvs_get_ncq_tag(struct sas_task *task, u32 *tag) -{ - struct ata_queued_cmd *qc = task->uldd_task; - - if (qc) { - if (qc->tf.command == ATA_CMD_FPDMA_WRITE || - qc->tf.command == ATA_CMD_FPDMA_READ) { - *tag = qc->tag; - return 1; - } - } - - return 0; -} - -static int mvs_task_prep_ata(struct mvs_info *mvi, - struct mvs_task_exec_info *tei) -{ - struct sas_task *task = tei->task; - struct domain_device *dev = task->dev; - struct mvs_cmd_hdr *hdr = tei->hdr; - struct asd_sas_port *sas_port = dev->port; - struct mvs_slot_info *slot; - struct scatterlist *sg; - struct mvs_prd *buf_prd; - struct mvs_port *port = tei->port; - u32 tag = tei->tag; - u32 flags = (tei->n_elem << MCH_PRD_LEN_SHIFT); - void *buf_tmp; - u8 *buf_cmd, *buf_oaf; - dma_addr_t buf_tmp_dma; - u32 i, req_len, resp_len; - const u32 max_resp_len = SB_RFB_MAX; - - if (mvs_assign_reg_set(mvi, port) == MVS_ID_NOT_MAPPED) - return -EBUSY; - - slot = &mvi->slot_info[tag]; - slot->tx = mvi->tx_prod; - mvi->tx[mvi->tx_prod] = cpu_to_le32(TXQ_MODE_I | tag | - (TXQ_CMD_STP << TXQ_CMD_SHIFT) | - (sas_port->phy_mask << TXQ_PHY_SHIFT) | - (port->taskfileset << TXQ_SRS_SHIFT)); - - if (task->ata_task.use_ncq) - flags |= MCH_FPDMA; - if (dev->sata_dev.command_set == ATAPI_COMMAND_SET) { - if (task->ata_task.fis.command != ATA_CMD_ID_ATAPI) - flags |= MCH_ATAPI; - } - - /* FIXME: fill in port multiplier number */ - - hdr->flags = cpu_to_le32(flags); - - /* FIXME: the low order order 5 bits for the TAG if enable NCQ */ - if (task->ata_task.use_ncq && mvs_get_ncq_tag(task, &hdr->tags)) - task->ata_task.fis.sector_count |= hdr->tags << 3; - else - hdr->tags = cpu_to_le32(tag); - hdr->data_len = cpu_to_le32(task->total_xfer_len); - - /* - * arrange MVS_SLOT_BUF_SZ-sized DMA buffer according to our needs - */ - - /* region 1: command table area (MVS_ATA_CMD_SZ bytes) ************** */ - buf_cmd = buf_tmp = slot->buf; - buf_tmp_dma = slot->buf_dma; - - hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma); - - buf_tmp += MVS_ATA_CMD_SZ; - buf_tmp_dma += MVS_ATA_CMD_SZ; -#if _MV_DUMP - slot->cmd_size = MVS_ATA_CMD_SZ; -#endif - - /* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */ - /* used for STP. unused for SATA? */ - buf_oaf = buf_tmp; - hdr->open_frame = cpu_to_le64(buf_tmp_dma); - - buf_tmp += MVS_OAF_SZ; - buf_tmp_dma += MVS_OAF_SZ; - - /* region 3: PRD table ********************************************* */ - buf_prd = buf_tmp; - if (tei->n_elem) - hdr->prd_tbl = cpu_to_le64(buf_tmp_dma); - else - hdr->prd_tbl = 0; - - i = sizeof(struct mvs_prd) * tei->n_elem; - buf_tmp += i; - buf_tmp_dma += i; - - /* region 4: status buffer (larger the PRD, smaller this buf) ****** */ - /* FIXME: probably unused, for SATA. kept here just in case - * we get a STP/SATA error information record - */ - slot->response = buf_tmp; - hdr->status_buf = cpu_to_le64(buf_tmp_dma); - - req_len = sizeof(struct host_to_dev_fis); - resp_len = MVS_SLOT_BUF_SZ - MVS_ATA_CMD_SZ - - sizeof(struct mvs_err_info) - i; - - /* request, response lengths */ - resp_len = min(resp_len, max_resp_len); - hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | (req_len / 4)); - - task->ata_task.fis.flags |= 0x80; /* C=1: update ATA cmd reg */ - /* fill in command FIS and ATAPI CDB */ - memcpy(buf_cmd, &task->ata_task.fis, sizeof(struct host_to_dev_fis)); - if (dev->sata_dev.command_set == ATAPI_COMMAND_SET) - memcpy(buf_cmd + STP_ATAPI_CMD, - task->ata_task.atapi_packet, 16); - - /* generate open address frame hdr (first 12 bytes) */ - buf_oaf[0] = (1 << 7) | (2 << 4) | 0x1; /* initiator, STP, ftype 1h */ - buf_oaf[1] = task->dev->linkrate & 0xf; - *(u16 *)(buf_oaf + 2) = cpu_to_be16(tag); - memcpy(buf_oaf + 4, task->dev->sas_addr, SAS_ADDR_SIZE); - - /* fill in PRD (scatter/gather) table, if any */ - for_each_sg(task->scatter, sg, tei->n_elem, i) { - buf_prd->addr = cpu_to_le64(sg_dma_address(sg)); - buf_prd->len = cpu_to_le32(sg_dma_len(sg)); - buf_prd++; - } - - return 0; -} - -static int mvs_task_prep_ssp(struct mvs_info *mvi, - struct mvs_task_exec_info *tei) -{ - struct sas_task *task = tei->task; - struct mvs_cmd_hdr *hdr = tei->hdr; - struct mvs_port *port = tei->port; - struct mvs_slot_info *slot; - struct scatterlist *sg; - struct mvs_prd *buf_prd; - struct ssp_frame_hdr *ssp_hdr; - void *buf_tmp; - u8 *buf_cmd, *buf_oaf, fburst = 0; - dma_addr_t buf_tmp_dma; - u32 flags; - u32 resp_len, req_len, i, tag = tei->tag; - const u32 max_resp_len = SB_RFB_MAX; - u8 phy_mask; - - slot = &mvi->slot_info[tag]; - - phy_mask = (port->wide_port_phymap) ? port->wide_port_phymap : - task->dev->port->phy_mask; - slot->tx = mvi->tx_prod; - mvi->tx[mvi->tx_prod] = cpu_to_le32(TXQ_MODE_I | tag | - (TXQ_CMD_SSP << TXQ_CMD_SHIFT) | - (phy_mask << TXQ_PHY_SHIFT)); - - flags = MCH_RETRY; - if (task->ssp_task.enable_first_burst) { - flags |= MCH_FBURST; - fburst = (1 << 7); - } - hdr->flags = cpu_to_le32(flags | - (tei->n_elem << MCH_PRD_LEN_SHIFT) | - (MCH_SSP_FR_CMD << MCH_SSP_FR_TYPE_SHIFT)); - - hdr->tags = cpu_to_le32(tag); - hdr->data_len = cpu_to_le32(task->total_xfer_len); - - /* - * arrange MVS_SLOT_BUF_SZ-sized DMA buffer according to our needs - */ - - /* region 1: command table area (MVS_SSP_CMD_SZ bytes) ************** */ - buf_cmd = buf_tmp = slot->buf; - buf_tmp_dma = slot->buf_dma; - - hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma); - - buf_tmp += MVS_SSP_CMD_SZ; - buf_tmp_dma += MVS_SSP_CMD_SZ; -#if _MV_DUMP - slot->cmd_size = MVS_SSP_CMD_SZ; -#endif - - /* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */ - buf_oaf = buf_tmp; - hdr->open_frame = cpu_to_le64(buf_tmp_dma); - - buf_tmp += MVS_OAF_SZ; - buf_tmp_dma += MVS_OAF_SZ; - - /* region 3: PRD table ********************************************* */ - buf_prd = buf_tmp; - if (tei->n_elem) - hdr->prd_tbl = cpu_to_le64(buf_tmp_dma); - else - hdr->prd_tbl = 0; - - i = sizeof(struct mvs_prd) * tei->n_elem; - buf_tmp += i; - buf_tmp_dma += i; - - /* region 4: status buffer (larger the PRD, smaller this buf) ****** */ - slot->response = buf_tmp; - hdr->status_buf = cpu_to_le64(buf_tmp_dma); - - resp_len = MVS_SLOT_BUF_SZ - MVS_SSP_CMD_SZ - MVS_OAF_SZ - - sizeof(struct mvs_err_info) - i; - resp_len = min(resp_len, max_resp_len); - - req_len = sizeof(struct ssp_frame_hdr) + 28; - - /* request, response lengths */ - hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | (req_len / 4)); - - /* generate open address frame hdr (first 12 bytes) */ - buf_oaf[0] = (1 << 7) | (1 << 4) | 0x1; /* initiator, SSP, ftype 1h */ - buf_oaf[1] = task->dev->linkrate & 0xf; - *(u16 *)(buf_oaf + 2) = cpu_to_be16(tag); - memcpy(buf_oaf + 4, task->dev->sas_addr, SAS_ADDR_SIZE); - - /* fill in SSP frame header (Command Table.SSP frame header) */ - ssp_hdr = (struct ssp_frame_hdr *)buf_cmd; - ssp_hdr->frame_type = SSP_COMMAND; - memcpy(ssp_hdr->hashed_dest_addr, task->dev->hashed_sas_addr, - HASHED_SAS_ADDR_SIZE); - memcpy(ssp_hdr->hashed_src_addr, - task->dev->port->ha->hashed_sas_addr, HASHED_SAS_ADDR_SIZE); - ssp_hdr->tag = cpu_to_be16(tag); - - /* fill in command frame IU */ - buf_cmd += sizeof(*ssp_hdr); - memcpy(buf_cmd, &task->ssp_task.LUN, 8); - buf_cmd[9] = fburst | task->ssp_task.task_attr | - (task->ssp_task.task_prio << 3); - memcpy(buf_cmd + 12, &task->ssp_task.cdb, 16); - - /* fill in PRD (scatter/gather) table, if any */ - for_each_sg(task->scatter, sg, tei->n_elem, i) { - buf_prd->addr = cpu_to_le64(sg_dma_address(sg)); - buf_prd->len = cpu_to_le32(sg_dma_len(sg)); - buf_prd++; - } - - return 0; -} - -static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags) -{ - struct domain_device *dev = task->dev; - struct mvs_info *mvi = dev->port->ha->lldd_ha; - struct pci_dev *pdev = mvi->pdev; - void __iomem *regs = mvi->regs; - struct mvs_task_exec_info tei; - struct sas_task *t = task; - struct mvs_slot_info *slot; - u32 tag = 0xdeadbeef, rc, n_elem = 0; - unsigned long flags; - u32 n = num, pass = 0; - - spin_lock_irqsave(&mvi->lock, flags); - do { - dev = t->dev; - tei.port = &mvi->port[dev->port->id]; - - if (!tei.port->port_attached) { - if (sas_protocol_ata(t->task_proto)) { - rc = SAS_PHY_DOWN; - goto out_done; - } else { - struct task_status_struct *ts = &t->task_status; - ts->resp = SAS_TASK_UNDELIVERED; - ts->stat = SAS_PHY_DOWN; - t->task_done(t); - if (n > 1) - t = list_entry(t->list.next, - struct sas_task, list); - continue; - } - } - - if (!sas_protocol_ata(t->task_proto)) { - if (t->num_scatter) { - n_elem = pci_map_sg(mvi->pdev, t->scatter, - t->num_scatter, - t->data_dir); - if (!n_elem) { - rc = -ENOMEM; - goto err_out; - } - } - } else { - n_elem = t->num_scatter; - } - - rc = mvs_tag_alloc(mvi, &tag); - if (rc) - goto err_out; - - slot = &mvi->slot_info[tag]; - t->lldd_task = NULL; - slot->n_elem = n_elem; - memset(slot->buf, 0, MVS_SLOT_BUF_SZ); - tei.task = t; - tei.hdr = &mvi->slot[tag]; - tei.tag = tag; - tei.n_elem = n_elem; - - switch (t->task_proto) { - case SAS_PROTOCOL_SMP: - rc = mvs_task_prep_smp(mvi, &tei); - break; - case SAS_PROTOCOL_SSP: - rc = mvs_task_prep_ssp(mvi, &tei); - break; - case SAS_PROTOCOL_SATA: - case SAS_PROTOCOL_STP: - case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: - rc = mvs_task_prep_ata(mvi, &tei); - break; - default: - dev_printk(KERN_ERR, &pdev->dev, - "unknown sas_task proto: 0x%x\n", - t->task_proto); - rc = -EINVAL; - break; - } - - if (rc) - goto err_out_tag; - - slot->task = t; - slot->port = tei.port; - t->lldd_task = (void *) slot; - list_add_tail(&slot->list, &slot->port->list); - /* TODO: select normal or high priority */ - - spin_lock(&t->task_state_lock); - t->task_state_flags |= SAS_TASK_AT_INITIATOR; - spin_unlock(&t->task_state_lock); - - mvs_hba_memory_dump(mvi, tag, t->task_proto); - - ++pass; - mvi->tx_prod = (mvi->tx_prod + 1) & (MVS_CHIP_SLOT_SZ - 1); - if (n > 1) - t = list_entry(t->list.next, struct sas_task, list); - } while (--n); - - rc = 0; - goto out_done; - -err_out_tag: - mvs_tag_free(mvi, tag); -err_out: - dev_printk(KERN_ERR, &pdev->dev, "mvsas exec failed[%d]!\n", rc); - if (!sas_protocol_ata(t->task_proto)) - if (n_elem) - pci_unmap_sg(mvi->pdev, t->scatter, n_elem, - t->data_dir); -out_done: - if (pass) - mw32(TX_PROD_IDX, (mvi->tx_prod - 1) & (MVS_CHIP_SLOT_SZ - 1)); - spin_unlock_irqrestore(&mvi->lock, flags); - return rc; -} - -static int mvs_task_abort(struct sas_task *task) -{ - int rc; - unsigned long flags; - struct mvs_info *mvi = task->dev->port->ha->lldd_ha; - struct pci_dev *pdev = mvi->pdev; - int tag; - - spin_lock_irqsave(&task->task_state_lock, flags); - if (task->task_state_flags & SAS_TASK_STATE_DONE) { - rc = TMF_RESP_FUNC_COMPLETE; - spin_unlock_irqrestore(&task->task_state_lock, flags); - goto out_done; - } - spin_unlock_irqrestore(&task->task_state_lock, flags); - - switch (task->task_proto) { - case SAS_PROTOCOL_SMP: - dev_printk(KERN_DEBUG, &pdev->dev, "SMP Abort! \n"); - break; - case SAS_PROTOCOL_SSP: - dev_printk(KERN_DEBUG, &pdev->dev, "SSP Abort! \n"); - break; - case SAS_PROTOCOL_SATA: - case SAS_PROTOCOL_STP: - case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:{ - dev_printk(KERN_DEBUG, &pdev->dev, "STP Abort! \n"); -#if _MV_DUMP - dev_printk(KERN_DEBUG, &pdev->dev, "Dump D2H FIS: \n"); - mvs_hexdump(sizeof(struct host_to_dev_fis), - (void *)&task->ata_task.fis, 0); - dev_printk(KERN_DEBUG, &pdev->dev, "Dump ATAPI Cmd : \n"); - mvs_hexdump(16, task->ata_task.atapi_packet, 0); -#endif - spin_lock_irqsave(&task->task_state_lock, flags); - if (task->task_state_flags & SAS_TASK_NEED_DEV_RESET) { - /* TODO */ - ; - } - spin_unlock_irqrestore(&task->task_state_lock, flags); - break; - } - default: - break; - } - - if (mvs_find_tag(mvi, task, &tag)) { - spin_lock_irqsave(&mvi->lock, flags); - mvs_slot_task_free(mvi, task, &mvi->slot_info[tag], tag); - spin_unlock_irqrestore(&mvi->lock, flags); - } - if (!mvs_task_exec(task, 1, GFP_ATOMIC)) - rc = TMF_RESP_FUNC_COMPLETE; - else - rc = TMF_RESP_FUNC_FAILED; -out_done: - return rc; -} - -static void mvs_free(struct mvs_info *mvi) -{ - int i; - - if (!mvi) - return; - - for (i = 0; i < MVS_SLOTS; i++) { - struct mvs_slot_info *slot = &mvi->slot_info[i]; - - if (slot->buf) - dma_free_coherent(&mvi->pdev->dev, MVS_SLOT_BUF_SZ, - slot->buf, slot->buf_dma); - } - - if (mvi->tx) - dma_free_coherent(&mvi->pdev->dev, - sizeof(*mvi->tx) * MVS_CHIP_SLOT_SZ, - mvi->tx, mvi->tx_dma); - if (mvi->rx_fis) - dma_free_coherent(&mvi->pdev->dev, MVS_RX_FISL_SZ, - mvi->rx_fis, mvi->rx_fis_dma); - if (mvi->rx) - dma_free_coherent(&mvi->pdev->dev, - sizeof(*mvi->rx) * (MVS_RX_RING_SZ + 1), - mvi->rx, mvi->rx_dma); - if (mvi->slot) - dma_free_coherent(&mvi->pdev->dev, - sizeof(*mvi->slot) * MVS_SLOTS, - mvi->slot, mvi->slot_dma); -#ifdef MVS_ENABLE_PERI - if (mvi->peri_regs) - iounmap(mvi->peri_regs); -#endif - if (mvi->regs) - iounmap(mvi->regs); - if (mvi->shost) - scsi_host_put(mvi->shost); - kfree(mvi->sas.sas_port); - kfree(mvi->sas.sas_phy); - kfree(mvi); -} - -/* FIXME: locking? */ -static int mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func, - void *funcdata) -{ - struct mvs_info *mvi = sas_phy->ha->lldd_ha; - int rc = 0, phy_id = sas_phy->id; - u32 tmp; - - tmp = mvs_read_phy_ctl(mvi, phy_id); - - switch (func) { - case PHY_FUNC_SET_LINK_RATE:{ - struct sas_phy_linkrates *rates = funcdata; - u32 lrmin = 0, lrmax = 0; - - lrmin = (rates->minimum_linkrate << 8); - lrmax = (rates->maximum_linkrate << 12); - - if (lrmin) { - tmp &= ~(0xf << 8); - tmp |= lrmin; - } - if (lrmax) { - tmp &= ~(0xf << 12); - tmp |= lrmax; - } - mvs_write_phy_ctl(mvi, phy_id, tmp); - break; - } - - case PHY_FUNC_HARD_RESET: - if (tmp & PHY_RST_HARD) - break; - mvs_write_phy_ctl(mvi, phy_id, tmp | PHY_RST_HARD); - break; - - case PHY_FUNC_LINK_RESET: - mvs_write_phy_ctl(mvi, phy_id, tmp | PHY_RST); - break; - - case PHY_FUNC_DISABLE: - case PHY_FUNC_RELEASE_SPINUP_HOLD: - default: - rc = -EOPNOTSUPP; - } - - return rc; -} - -static void __devinit mvs_phy_init(struct mvs_info *mvi, int phy_id) -{ - struct mvs_phy *phy = &mvi->phy[phy_id]; - struct asd_sas_phy *sas_phy = &phy->sas_phy; - - sas_phy->enabled = (phy_id < mvi->chip->n_phy) ? 1 : 0; - sas_phy->class = SAS; - sas_phy->iproto = SAS_PROTOCOL_ALL; - sas_phy->tproto = 0; - sas_phy->type = PHY_TYPE_PHYSICAL; - sas_phy->role = PHY_ROLE_INITIATOR; - sas_phy->oob_mode = OOB_NOT_CONNECTED; - sas_phy->linkrate = SAS_LINK_RATE_UNKNOWN; - - sas_phy->id = phy_id; - sas_phy->sas_addr = &mvi->sas_addr[0]; - sas_phy->frame_rcvd = &phy->frame_rcvd[0]; - sas_phy->ha = &mvi->sas; - sas_phy->lldd_phy = phy; -} - -static struct mvs_info *__devinit mvs_alloc(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - struct mvs_info *mvi; - unsigned long res_start, res_len, res_flag; - struct asd_sas_phy **arr_phy; - struct asd_sas_port **arr_port; - const struct mvs_chip_info *chip = &mvs_chips[ent->driver_data]; - int i; - - /* - * alloc and init our per-HBA mvs_info struct - */ - - mvi = kzalloc(sizeof(*mvi), GFP_KERNEL); - if (!mvi) - return NULL; - - spin_lock_init(&mvi->lock); -#ifdef MVS_USE_TASKLET - tasklet_init(&mvi->tasklet, mvs_tasklet, (unsigned long)mvi); -#endif - mvi->pdev = pdev; - mvi->chip = chip; - - if (pdev->device == 0x6440 && pdev->revision == 0) - mvi->flags |= MVF_PHY_PWR_FIX; - - /* - * alloc and init SCSI, SAS glue - */ - - mvi->shost = scsi_host_alloc(&mvs_sht, sizeof(void *)); - if (!mvi->shost) - goto err_out; - - arr_phy = kcalloc(MVS_MAX_PHYS, sizeof(void *), GFP_KERNEL); - arr_port = kcalloc(MVS_MAX_PHYS, sizeof(void *), GFP_KERNEL); - if (!arr_phy || !arr_port) - goto err_out; - - for (i = 0; i < MVS_MAX_PHYS; i++) { - mvs_phy_init(mvi, i); - arr_phy[i] = &mvi->phy[i].sas_phy; - arr_port[i] = &mvi->port[i].sas_port; - mvi->port[i].taskfileset = MVS_ID_NOT_MAPPED; - mvi->port[i].wide_port_phymap = 0; - mvi->port[i].port_attached = 0; - INIT_LIST_HEAD(&mvi->port[i].list); - } - - SHOST_TO_SAS_HA(mvi->shost) = &mvi->sas; - mvi->shost->transportt = mvs_stt; - mvi->shost->max_id = 21; - mvi->shost->max_lun = ~0; - mvi->shost->max_channel = 0; - mvi->shost->max_cmd_len = 16; - - mvi->sas.sas_ha_name = DRV_NAME; - mvi->sas.dev = &pdev->dev; - mvi->sas.lldd_module = THIS_MODULE; - mvi->sas.sas_addr = &mvi->sas_addr[0]; - mvi->sas.sas_phy = arr_phy; - mvi->sas.sas_port = arr_port; - mvi->sas.num_phys = chip->n_phy; - mvi->sas.lldd_max_execute_num = 1; - mvi->sas.lldd_queue_size = MVS_QUEUE_SIZE; - mvi->shost->can_queue = MVS_CAN_QUEUE; - mvi->shost->cmd_per_lun = MVS_SLOTS / mvi->sas.num_phys; - mvi->sas.lldd_ha = mvi; - mvi->sas.core.shost = mvi->shost; - - mvs_tag_init(mvi); - - /* - * ioremap main and peripheral registers - */ - -#ifdef MVS_ENABLE_PERI - res_start = pci_resource_start(pdev, 2); - res_len = pci_resource_len(pdev, 2); - if (!res_start || !res_len) - goto err_out; - - mvi->peri_regs = ioremap_nocache(res_start, res_len); - if (!mvi->peri_regs) - goto err_out; -#endif - - res_start = pci_resource_start(pdev, 4); - res_len = pci_resource_len(pdev, 4); - if (!res_start || !res_len) - goto err_out; - - res_flag = pci_resource_flags(pdev, 4); - if (res_flag & IORESOURCE_CACHEABLE) - mvi->regs = ioremap(res_start, res_len); - else - mvi->regs = ioremap_nocache(res_start, res_len); - - if (!mvi->regs) - goto err_out; - - /* - * alloc and init our DMA areas - */ - - mvi->tx = dma_alloc_coherent(&pdev->dev, - sizeof(*mvi->tx) * MVS_CHIP_SLOT_SZ, - &mvi->tx_dma, GFP_KERNEL); - if (!mvi->tx) - goto err_out; - memset(mvi->tx, 0, sizeof(*mvi->tx) * MVS_CHIP_SLOT_SZ); - - mvi->rx_fis = dma_alloc_coherent(&pdev->dev, MVS_RX_FISL_SZ, - &mvi->rx_fis_dma, GFP_KERNEL); - if (!mvi->rx_fis) - goto err_out; - memset(mvi->rx_fis, 0, MVS_RX_FISL_SZ); - - mvi->rx = dma_alloc_coherent(&pdev->dev, - sizeof(*mvi->rx) * (MVS_RX_RING_SZ + 1), - &mvi->rx_dma, GFP_KERNEL); - if (!mvi->rx) - goto err_out; - memset(mvi->rx, 0, sizeof(*mvi->rx) * (MVS_RX_RING_SZ + 1)); - - mvi->rx[0] = cpu_to_le32(0xfff); - mvi->rx_cons = 0xfff; - - mvi->slot = dma_alloc_coherent(&pdev->dev, - sizeof(*mvi->slot) * MVS_SLOTS, - &mvi->slot_dma, GFP_KERNEL); - if (!mvi->slot) - goto err_out; - memset(mvi->slot, 0, sizeof(*mvi->slot) * MVS_SLOTS); - - for (i = 0; i < MVS_SLOTS; i++) { - struct mvs_slot_info *slot = &mvi->slot_info[i]; - - slot->buf = dma_alloc_coherent(&pdev->dev, MVS_SLOT_BUF_SZ, - &slot->buf_dma, GFP_KERNEL); - if (!slot->buf) - goto err_out; - memset(slot->buf, 0, MVS_SLOT_BUF_SZ); - } - - /* finally, read NVRAM to get our SAS address */ - if (mvs_nvram_read(mvi, NVR_SAS_ADDR, &mvi->sas_addr, 8)) - goto err_out; - return mvi; - -err_out: - mvs_free(mvi); - return NULL; -} - -static u32 mvs_cr32(void __iomem *regs, u32 addr) -{ - mw32(CMD_ADDR, addr); - return mr32(CMD_DATA); -} - -static void mvs_cw32(void __iomem *regs, u32 addr, u32 val) -{ - mw32(CMD_ADDR, addr); - mw32(CMD_DATA, val); -} - -static u32 mvs_read_phy_ctl(struct mvs_info *mvi, u32 port) -{ - void __iomem *regs = mvi->regs; - return (port < 4)?mr32(P0_SER_CTLSTAT + port * 4): - mr32(P4_SER_CTLSTAT + (port - 4) * 4); -} - -static void mvs_write_phy_ctl(struct mvs_info *mvi, u32 port, u32 val) -{ - void __iomem *regs = mvi->regs; - if (port < 4) - mw32(P0_SER_CTLSTAT + port * 4, val); - else - mw32(P4_SER_CTLSTAT + (port - 4) * 4, val); -} - -static u32 mvs_read_port(struct mvs_info *mvi, u32 off, u32 off2, u32 port) -{ - void __iomem *regs = mvi->regs + off; - void __iomem *regs2 = mvi->regs + off2; - return (port < 4)?readl(regs + port * 8): - readl(regs2 + (port - 4) * 8); -} - -static void mvs_write_port(struct mvs_info *mvi, u32 off, u32 off2, - u32 port, u32 val) -{ - void __iomem *regs = mvi->regs + off; - void __iomem *regs2 = mvi->regs + off2; - if (port < 4) - writel(val, regs + port * 8); - else - writel(val, regs2 + (port - 4) * 8); -} - -static u32 mvs_read_port_cfg_data(struct mvs_info *mvi, u32 port) -{ - return mvs_read_port(mvi, MVS_P0_CFG_DATA, MVS_P4_CFG_DATA, port); -} - -static void mvs_write_port_cfg_data(struct mvs_info *mvi, u32 port, u32 val) -{ - mvs_write_port(mvi, MVS_P0_CFG_DATA, MVS_P4_CFG_DATA, port, val); -} - -static void mvs_write_port_cfg_addr(struct mvs_info *mvi, u32 port, u32 addr) -{ - mvs_write_port(mvi, MVS_P0_CFG_ADDR, MVS_P4_CFG_ADDR, port, addr); -} - -static u32 mvs_read_port_vsr_data(struct mvs_info *mvi, u32 port) -{ - return mvs_read_port(mvi, MVS_P0_VSR_DATA, MVS_P4_VSR_DATA, port); -} - -static void mvs_write_port_vsr_data(struct mvs_info *mvi, u32 port, u32 val) -{ - mvs_write_port(mvi, MVS_P0_VSR_DATA, MVS_P4_VSR_DATA, port, val); -} - -static void mvs_write_port_vsr_addr(struct mvs_info *mvi, u32 port, u32 addr) -{ - mvs_write_port(mvi, MVS_P0_VSR_ADDR, MVS_P4_VSR_ADDR, port, addr); -} - -static u32 mvs_read_port_irq_stat(struct mvs_info *mvi, u32 port) -{ - return mvs_read_port(mvi, MVS_P0_INT_STAT, MVS_P4_INT_STAT, port); -} - -static void mvs_write_port_irq_stat(struct mvs_info *mvi, u32 port, u32 val) -{ - mvs_write_port(mvi, MVS_P0_INT_STAT, MVS_P4_INT_STAT, port, val); -} - -static u32 mvs_read_port_irq_mask(struct mvs_info *mvi, u32 port) -{ - return mvs_read_port(mvi, MVS_P0_INT_MASK, MVS_P4_INT_MASK, port); -} - -static void mvs_write_port_irq_mask(struct mvs_info *mvi, u32 port, u32 val) -{ - mvs_write_port(mvi, MVS_P0_INT_MASK, MVS_P4_INT_MASK, port, val); -} - -static void __devinit mvs_phy_hacks(struct mvs_info *mvi) -{ - void __iomem *regs = mvi->regs; - u32 tmp; - - /* workaround for SATA R-ERR, to ignore phy glitch */ - tmp = mvs_cr32(regs, CMD_PHY_TIMER); - tmp &= ~(1 << 9); - tmp |= (1 << 10); - mvs_cw32(regs, CMD_PHY_TIMER, tmp); - - /* enable retry 127 times */ - mvs_cw32(regs, CMD_SAS_CTL1, 0x7f7f); - - /* extend open frame timeout to max */ - tmp = mvs_cr32(regs, CMD_SAS_CTL0); - tmp &= ~0xffff; - tmp |= 0x3fff; - mvs_cw32(regs, CMD_SAS_CTL0, tmp); - - /* workaround for WDTIMEOUT , set to 550 ms */ - mvs_cw32(regs, CMD_WD_TIMER, 0x86470); - - /* not to halt for different port op during wideport link change */ - mvs_cw32(regs, CMD_APP_ERR_CONFIG, 0xffefbf7d); - - /* workaround for Seagate disk not-found OOB sequence, recv - * COMINIT before sending out COMWAKE */ - tmp = mvs_cr32(regs, CMD_PHY_MODE_21); - tmp &= 0x0000ffff; - tmp |= 0x00fa0000; - mvs_cw32(regs, CMD_PHY_MODE_21, tmp); - - tmp = mvs_cr32(regs, CMD_PHY_TIMER); - tmp &= 0x1fffffff; - tmp |= (2U << 29); /* 8 ms retry */ - mvs_cw32(regs, CMD_PHY_TIMER, tmp); - - /* TEST - for phy decoding error, adjust voltage levels */ - mw32(P0_VSR_ADDR + 0, 0x8); - mw32(P0_VSR_DATA + 0, 0x2F0); - - mw32(P0_VSR_ADDR + 8, 0x8); - mw32(P0_VSR_DATA + 8, 0x2F0); - - mw32(P0_VSR_ADDR + 16, 0x8); - mw32(P0_VSR_DATA + 16, 0x2F0); - - mw32(P0_VSR_ADDR + 24, 0x8); - mw32(P0_VSR_DATA + 24, 0x2F0); - -} - -static void mvs_enable_xmt(struct mvs_info *mvi, int PhyId) -{ - void __iomem *regs = mvi->regs; - u32 tmp; - - tmp = mr32(PCS); - if (mvi->chip->n_phy <= 4) - tmp |= 1 << (PhyId + PCS_EN_PORT_XMT_SHIFT); - else - tmp |= 1 << (PhyId + PCS_EN_PORT_XMT_SHIFT2); - mw32(PCS, tmp); -} - -static void mvs_detect_porttype(struct mvs_info *mvi, int i) -{ - void __iomem *regs = mvi->regs; - u32 reg; - struct mvs_phy *phy = &mvi->phy[i]; - - /* TODO check & save device type */ - reg = mr32(GBL_PORT_TYPE); - - if (reg & MODE_SAS_SATA & (1 << i)) - phy->phy_type |= PORT_TYPE_SAS; - else - phy->phy_type |= PORT_TYPE_SATA; -} - -static void *mvs_get_d2h_reg(struct mvs_info *mvi, int i, void *buf) -{ - u32 *s = (u32 *) buf; - - if (!s) - return NULL; - - mvs_write_port_cfg_addr(mvi, i, PHYR_SATA_SIG3); - s[3] = mvs_read_port_cfg_data(mvi, i); - - mvs_write_port_cfg_addr(mvi, i, PHYR_SATA_SIG2); - s[2] = mvs_read_port_cfg_data(mvi, i); - - mvs_write_port_cfg_addr(mvi, i, PHYR_SATA_SIG1); - s[1] = mvs_read_port_cfg_data(mvi, i); - - mvs_write_port_cfg_addr(mvi, i, PHYR_SATA_SIG0); - s[0] = mvs_read_port_cfg_data(mvi, i); - - return (void *)s; -} - -static u32 mvs_is_sig_fis_received(u32 irq_status) -{ - return irq_status & PHYEV_SIG_FIS; -} - -static void mvs_update_wideport(struct mvs_info *mvi, int i) -{ - struct mvs_phy *phy = &mvi->phy[i]; - struct mvs_port *port = phy->port; - int j, no; - - for_each_phy(port->wide_port_phymap, no, j, mvi->chip->n_phy) - if (no & 1) { - mvs_write_port_cfg_addr(mvi, no, PHYR_WIDE_PORT); - mvs_write_port_cfg_data(mvi, no, - port->wide_port_phymap); - } else { - mvs_write_port_cfg_addr(mvi, no, PHYR_WIDE_PORT); - mvs_write_port_cfg_data(mvi, no, 0); - } -} - -static u32 mvs_is_phy_ready(struct mvs_info *mvi, int i) -{ - u32 tmp; - struct mvs_phy *phy = &mvi->phy[i]; - struct mvs_port *port = phy->port;; - - tmp = mvs_read_phy_ctl(mvi, i); - - if ((tmp & PHY_READY_MASK) && !(phy->irq_status & PHYEV_POOF)) { - if (!port) - phy->phy_attached = 1; - return tmp; - } - - if (port) { - if (phy->phy_type & PORT_TYPE_SAS) { - port->wide_port_phymap &= ~(1U << i); - if (!port->wide_port_phymap) - port->port_attached = 0; - mvs_update_wideport(mvi, i); - } else if (phy->phy_type & PORT_TYPE_SATA) - port->port_attached = 0; - mvs_free_reg_set(mvi, phy->port); - phy->port = NULL; - phy->phy_attached = 0; - phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA); - } - return 0; -} - -static void mvs_update_phyinfo(struct mvs_info *mvi, int i, - int get_st) -{ - struct mvs_phy *phy = &mvi->phy[i]; - struct pci_dev *pdev = mvi->pdev; - u32 tmp; - u64 tmp64; - - mvs_write_port_cfg_addr(mvi, i, PHYR_IDENTIFY); - phy->dev_info = mvs_read_port_cfg_data(mvi, i); - - mvs_write_port_cfg_addr(mvi, i, PHYR_ADDR_HI); - phy->dev_sas_addr = (u64) mvs_read_port_cfg_data(mvi, i) << 32; - - mvs_write_port_cfg_addr(mvi, i, PHYR_ADDR_LO); - phy->dev_sas_addr |= mvs_read_port_cfg_data(mvi, i); - - if (get_st) { - phy->irq_status = mvs_read_port_irq_stat(mvi, i); - phy->phy_status = mvs_is_phy_ready(mvi, i); - } - - if (phy->phy_status) { - u32 phy_st; - struct asd_sas_phy *sas_phy = mvi->sas.sas_phy[i]; - - mvs_write_port_cfg_addr(mvi, i, PHYR_PHY_STAT); - phy_st = mvs_read_port_cfg_data(mvi, i); - - sas_phy->linkrate = - (phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >> - PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET; - phy->minimum_linkrate = - (phy->phy_status & - PHY_MIN_SPP_PHYS_LINK_RATE_MASK) >> 8; - phy->maximum_linkrate = - (phy->phy_status & - PHY_MAX_SPP_PHYS_LINK_RATE_MASK) >> 12; - - if (phy->phy_type & PORT_TYPE_SAS) { - /* Updated attached_sas_addr */ - mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_ADDR_HI); - phy->att_dev_sas_addr = - (u64) mvs_read_port_cfg_data(mvi, i) << 32; - mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_ADDR_LO); - phy->att_dev_sas_addr |= mvs_read_port_cfg_data(mvi, i); - mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_DEV_INFO); - phy->att_dev_info = mvs_read_port_cfg_data(mvi, i); - phy->identify.device_type = - phy->att_dev_info & PORT_DEV_TYPE_MASK; - - if (phy->identify.device_type == SAS_END_DEV) - phy->identify.target_port_protocols = - SAS_PROTOCOL_SSP; - else if (phy->identify.device_type != NO_DEVICE) - phy->identify.target_port_protocols = - SAS_PROTOCOL_SMP; - if (phy_st & PHY_OOB_DTCTD) - sas_phy->oob_mode = SAS_OOB_MODE; - phy->frame_rcvd_size = - sizeof(struct sas_identify_frame); - } else if (phy->phy_type & PORT_TYPE_SATA) { - phy->identify.target_port_protocols = SAS_PROTOCOL_STP; - if (mvs_is_sig_fis_received(phy->irq_status)) { - phy->att_dev_sas_addr = i; /* temp */ - if (phy_st & PHY_OOB_DTCTD) - sas_phy->oob_mode = SATA_OOB_MODE; - phy->frame_rcvd_size = - sizeof(struct dev_to_host_fis); - mvs_get_d2h_reg(mvi, i, - (void *)sas_phy->frame_rcvd); - } else { - dev_printk(KERN_DEBUG, &pdev->dev, - "No sig fis\n"); - phy->phy_type &= ~(PORT_TYPE_SATA); - goto out_done; - } - } - tmp64 = cpu_to_be64(phy->att_dev_sas_addr); - memcpy(sas_phy->attached_sas_addr, &tmp64, SAS_ADDR_SIZE); - - dev_printk(KERN_DEBUG, &pdev->dev, - "phy[%d] Get Attached Address 0x%llX ," - " SAS Address 0x%llX\n", - i, - (unsigned long long)phy->att_dev_sas_addr, - (unsigned long long)phy->dev_sas_addr); - dev_printk(KERN_DEBUG, &pdev->dev, - "Rate = %x , type = %d\n", - sas_phy->linkrate, phy->phy_type); - - /* workaround for HW phy decoding error on 1.5g disk drive */ - mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE6); - tmp = mvs_read_port_vsr_data(mvi, i); - if (((phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >> - PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET) == - SAS_LINK_RATE_1_5_GBPS) - tmp &= ~PHY_MODE6_LATECLK; - else - tmp |= PHY_MODE6_LATECLK; - mvs_write_port_vsr_data(mvi, i, tmp); - - } -out_done: - if (get_st) - mvs_write_port_irq_stat(mvi, i, phy->irq_status); -} - -static void mvs_port_formed(struct asd_sas_phy *sas_phy) -{ - struct sas_ha_struct *sas_ha = sas_phy->ha; - struct mvs_info *mvi = sas_ha->lldd_ha; - struct asd_sas_port *sas_port = sas_phy->port; - struct mvs_phy *phy = sas_phy->lldd_phy; - struct mvs_port *port = &mvi->port[sas_port->id]; - unsigned long flags; - - spin_lock_irqsave(&mvi->lock, flags); - port->port_attached = 1; - phy->port = port; - port->taskfileset = MVS_ID_NOT_MAPPED; - if (phy->phy_type & PORT_TYPE_SAS) { - port->wide_port_phymap = sas_port->phy_mask; - mvs_update_wideport(mvi, sas_phy->id); - } - spin_unlock_irqrestore(&mvi->lock, flags); -} - -static int mvs_I_T_nexus_reset(struct domain_device *dev) -{ - return TMF_RESP_FUNC_FAILED; -} - -static int __devinit mvs_hw_init(struct mvs_info *mvi) -{ - void __iomem *regs = mvi->regs; - int i; - u32 tmp, cctl; - - /* make sure interrupts are masked immediately (paranoia) */ - mw32(GBL_CTL, 0); - tmp = mr32(GBL_CTL); - - /* Reset Controller */ - if (!(tmp & HBA_RST)) { - if (mvi->flags & MVF_PHY_PWR_FIX) { - pci_read_config_dword(mvi->pdev, PCR_PHY_CTL, &tmp); - tmp &= ~PCTL_PWR_ON; - tmp |= PCTL_OFF; - pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, tmp); - - pci_read_config_dword(mvi->pdev, PCR_PHY_CTL2, &tmp); - tmp &= ~PCTL_PWR_ON; - tmp |= PCTL_OFF; - pci_write_config_dword(mvi->pdev, PCR_PHY_CTL2, tmp); - } - - /* global reset, incl. COMRESET/H_RESET_N (self-clearing) */ - mw32_f(GBL_CTL, HBA_RST); - } - - /* wait for reset to finish; timeout is just a guess */ - i = 1000; - while (i-- > 0) { - msleep(10); - - if (!(mr32(GBL_CTL) & HBA_RST)) - break; - } - if (mr32(GBL_CTL) & HBA_RST) { - dev_printk(KERN_ERR, &mvi->pdev->dev, "HBA reset failed\n"); - return -EBUSY; - } - - /* Init Chip */ - /* make sure RST is set; HBA_RST /should/ have done that for us */ - cctl = mr32(CTL); - if (cctl & CCTL_RST) - cctl &= ~CCTL_RST; - else - mw32_f(CTL, cctl | CCTL_RST); - - /* write to device control _AND_ device status register? - A.C. */ - pci_read_config_dword(mvi->pdev, PCR_DEV_CTRL, &tmp); - tmp &= ~PRD_REQ_MASK; - tmp |= PRD_REQ_SIZE; - pci_write_config_dword(mvi->pdev, PCR_DEV_CTRL, tmp); - - pci_read_config_dword(mvi->pdev, PCR_PHY_CTL, &tmp); - tmp |= PCTL_PWR_ON; - tmp &= ~PCTL_OFF; - pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, tmp); - - pci_read_config_dword(mvi->pdev, PCR_PHY_CTL2, &tmp); - tmp |= PCTL_PWR_ON; - tmp &= ~PCTL_OFF; - pci_write_config_dword(mvi->pdev, PCR_PHY_CTL2, tmp); - - mw32_f(CTL, cctl); - - /* reset control */ - mw32(PCS, 0); /*MVS_PCS */ - - mvs_phy_hacks(mvi); - - mw32(CMD_LIST_LO, mvi->slot_dma); - mw32(CMD_LIST_HI, (mvi->slot_dma >> 16) >> 16); - - mw32(RX_FIS_LO, mvi->rx_fis_dma); - mw32(RX_FIS_HI, (mvi->rx_fis_dma >> 16) >> 16); - - mw32(TX_CFG, MVS_CHIP_SLOT_SZ); - mw32(TX_LO, mvi->tx_dma); - mw32(TX_HI, (mvi->tx_dma >> 16) >> 16); - - mw32(RX_CFG, MVS_RX_RING_SZ); - mw32(RX_LO, mvi->rx_dma); - mw32(RX_HI, (mvi->rx_dma >> 16) >> 16); - - /* enable auto port detection */ - mw32(GBL_PORT_TYPE, MODE_AUTO_DET_EN); - msleep(1100); - /* init and reset phys */ - for (i = 0; i < mvi->chip->n_phy; i++) { - u32 lo = be32_to_cpu(*(u32 *)&mvi->sas_addr[4]); - u32 hi = be32_to_cpu(*(u32 *)&mvi->sas_addr[0]); - - mvs_detect_porttype(mvi, i); - - /* set phy local SAS address */ - mvs_write_port_cfg_addr(mvi, i, PHYR_ADDR_LO); - mvs_write_port_cfg_data(mvi, i, lo); - mvs_write_port_cfg_addr(mvi, i, PHYR_ADDR_HI); - mvs_write_port_cfg_data(mvi, i, hi); - - /* reset phy */ - tmp = mvs_read_phy_ctl(mvi, i); - tmp |= PHY_RST; - mvs_write_phy_ctl(mvi, i, tmp); - } - - msleep(100); - - for (i = 0; i < mvi->chip->n_phy; i++) { - /* clear phy int status */ - tmp = mvs_read_port_irq_stat(mvi, i); - tmp &= ~PHYEV_SIG_FIS; - mvs_write_port_irq_stat(mvi, i, tmp); - - /* set phy int mask */ - tmp = PHYEV_RDY_CH | PHYEV_BROAD_CH | PHYEV_UNASSOC_FIS | - PHYEV_ID_DONE | PHYEV_DEC_ERR; - mvs_write_port_irq_mask(mvi, i, tmp); - - msleep(100); - mvs_update_phyinfo(mvi, i, 1); - mvs_enable_xmt(mvi, i); - } - - /* FIXME: update wide port bitmaps */ - - /* little endian for open address and command table, etc. */ - /* A.C. - * it seems that ( from the spec ) turning on big-endian won't - * do us any good on big-endian machines, need further confirmation - */ - cctl = mr32(CTL); - cctl |= CCTL_ENDIAN_CMD; - cctl |= CCTL_ENDIAN_DATA; - cctl &= ~CCTL_ENDIAN_OPEN; - cctl |= CCTL_ENDIAN_RSP; - mw32_f(CTL, cctl); - - /* reset CMD queue */ - tmp = mr32(PCS); - tmp |= PCS_CMD_RST; - mw32(PCS, tmp); - /* interrupt coalescing may cause missing HW interrput in some case, - * and the max count is 0x1ff, while our max slot is 0x200, - * it will make count 0. - */ - tmp = 0; - mw32(INT_COAL, tmp); - - tmp = 0x100; - mw32(INT_COAL_TMOUT, tmp); - - /* ladies and gentlemen, start your engines */ - mw32(TX_CFG, 0); - mw32(TX_CFG, MVS_CHIP_SLOT_SZ | TX_EN); - mw32(RX_CFG, MVS_RX_RING_SZ | RX_EN); - /* enable CMD/CMPL_Q/RESP mode */ - mw32(PCS, PCS_SATA_RETRY | PCS_FIS_RX_EN | PCS_CMD_EN); - - /* enable completion queue interrupt */ - tmp = (CINT_PORT_MASK | CINT_DONE | CINT_MEM | CINT_SRS); - mw32(INT_MASK, tmp); - - /* Enable SRS interrupt */ - mw32(INT_MASK_SRS, 0xFF); - return 0; -} - -static void __devinit mvs_print_info(struct mvs_info *mvi) -{ - struct pci_dev *pdev = mvi->pdev; - static int printed_version; - - if (!printed_version++) - dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n"); - - dev_printk(KERN_INFO, &pdev->dev, "%u phys, addr %llx\n", - mvi->chip->n_phy, SAS_ADDR(mvi->sas_addr)); -} - -static int __devinit mvs_pci_init(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - int rc; - struct mvs_info *mvi; - irq_handler_t irq_handler = mvs_interrupt; - - rc = pci_enable_device(pdev); - if (rc) - return rc; - - pci_set_master(pdev); - - rc = pci_request_regions(pdev, DRV_NAME); - if (rc) - goto err_out_disable; - - rc = pci_go_64(pdev); - if (rc) - goto err_out_regions; - - mvi = mvs_alloc(pdev, ent); - if (!mvi) { - rc = -ENOMEM; - goto err_out_regions; - } - - rc = mvs_hw_init(mvi); - if (rc) - goto err_out_mvi; - -#ifndef MVS_DISABLE_MSI - if (!pci_enable_msi(pdev)) { - u32 tmp; - void __iomem *regs = mvi->regs; - mvi->flags |= MVF_MSI; - irq_handler = mvs_msi_interrupt; - tmp = mr32(PCS); - mw32(PCS, tmp | PCS_SELF_CLEAR); - } -#endif - - rc = request_irq(pdev->irq, irq_handler, IRQF_SHARED, DRV_NAME, mvi); - if (rc) - goto err_out_msi; - - rc = scsi_add_host(mvi->shost, &pdev->dev); - if (rc) - goto err_out_irq; - - rc = sas_register_ha(&mvi->sas); - if (rc) - goto err_out_shost; - - pci_set_drvdata(pdev, mvi); - - mvs_print_info(mvi); - - mvs_hba_interrupt_enable(mvi); - - scsi_scan_host(mvi->shost); - - return 0; - -err_out_shost: - scsi_remove_host(mvi->shost); -err_out_irq: - free_irq(pdev->irq, mvi); -err_out_msi: - if (mvi->flags |= MVF_MSI) - pci_disable_msi(pdev); -err_out_mvi: - mvs_free(mvi); -err_out_regions: - pci_release_regions(pdev); -err_out_disable: - pci_disable_device(pdev); - return rc; -} - -static void __devexit mvs_pci_remove(struct pci_dev *pdev) -{ - struct mvs_info *mvi = pci_get_drvdata(pdev); - - pci_set_drvdata(pdev, NULL); - - if (mvi) { - sas_unregister_ha(&mvi->sas); - mvs_hba_interrupt_disable(mvi); - sas_remove_host(mvi->shost); - scsi_remove_host(mvi->shost); - - free_irq(pdev->irq, mvi); - if (mvi->flags & MVF_MSI) - pci_disable_msi(pdev); - mvs_free(mvi); - pci_release_regions(pdev); - } - pci_disable_device(pdev); -} - -static struct sas_domain_function_template mvs_transport_ops = { - .lldd_execute_task = mvs_task_exec, - .lldd_control_phy = mvs_phy_control, - .lldd_abort_task = mvs_task_abort, - .lldd_port_formed = mvs_port_formed, - .lldd_I_T_nexus_reset = mvs_I_T_nexus_reset, -}; - -static struct pci_device_id __devinitdata mvs_pci_table[] = { - { PCI_VDEVICE(MARVELL, 0x6320), chip_6320 }, - { PCI_VDEVICE(MARVELL, 0x6340), chip_6440 }, - { - .vendor = PCI_VENDOR_ID_MARVELL, - .device = 0x6440, - .subvendor = PCI_ANY_ID, - .subdevice = 0x6480, - .class = 0, - .class_mask = 0, - .driver_data = chip_6480, - }, - { PCI_VDEVICE(MARVELL, 0x6440), chip_6440 }, - { PCI_VDEVICE(MARVELL, 0x6480), chip_6480 }, - - { } /* terminate list */ -}; - -static struct pci_driver mvs_pci_driver = { - .name = DRV_NAME, - .id_table = mvs_pci_table, - .probe = mvs_pci_init, - .remove = __devexit_p(mvs_pci_remove), -}; - -static int __init mvs_init(void) -{ - int rc; - - mvs_stt = sas_domain_attach_transport(&mvs_transport_ops); - if (!mvs_stt) - return -ENOMEM; - - rc = pci_register_driver(&mvs_pci_driver); - if (rc) - goto err_out; - - return 0; - -err_out: - sas_release_transport(mvs_stt); - return rc; -} - -static void __exit mvs_exit(void) -{ - pci_unregister_driver(&mvs_pci_driver); - sas_release_transport(mvs_stt); -} - -module_init(mvs_init); -module_exit(mvs_exit); - -MODULE_AUTHOR("Jeff Garzik "); -MODULE_DESCRIPTION("Marvell 88SE6440 SAS/SATA controller driver"); -MODULE_VERSION(DRV_VERSION); -MODULE_LICENSE("GPL"); -MODULE_DEVICE_TABLE(pci, mvs_pci_table); diff --git a/drivers/scsi/mvsas/Kconfig b/drivers/scsi/mvsas/Kconfig new file mode 100644 index 000000000000..6de7af27e507 --- /dev/null +++ b/drivers/scsi/mvsas/Kconfig @@ -0,0 +1,42 @@ +# +# Kernel configuration file for 88SE64XX/88SE94XX SAS/SATA driver. +# +# Copyright 2007 Red Hat, Inc. +# Copyright 2008 Marvell. +# +# This file is licensed under GPLv2. +# +# This file is part of the 88SE64XX/88SE94XX driver. +# +# The 88SE64XX/88SE94XX driver is free software; you can redistribute +# it and/or modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; version 2 of the +# License. +# +# The 88SE64XX/88SE94XX driver 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 88SE64XX/88SE94XX Driver; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# +# + +config SCSI_MVSAS + tristate "Marvell 88SE64XX/88SE94XX SAS/SATA support" + depends on PCI + select SCSI_SAS_LIBSAS + select FW_LOADER + help + This driver supports Marvell's SAS/SATA 3Gb/s PCI-E 88SE64XX and 6Gb/s + PCI-E 88SE94XX chip based host adapters. + +config SCSI_MVSAS_DEBUG + bool "Compile in debug mode" + default y + depends on SCSI_MVSAS + help + Compiles the 88SE64XX/88SE94XX driver in debug mode. In debug mode, + the driver prints some messages to the console. diff --git a/drivers/scsi/mvsas/Makefile b/drivers/scsi/mvsas/Makefile new file mode 100644 index 000000000000..52ac4264677d --- /dev/null +++ b/drivers/scsi/mvsas/Makefile @@ -0,0 +1,32 @@ +# +# Makefile for Marvell 88SE64xx/88SE84xx SAS/SATA driver. +# +# Copyright 2007 Red Hat, Inc. +# Copyright 2008 Marvell. +# +# This file is licensed under GPLv2. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; version 2 of the +# License. +# +# 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 + +ifeq ($(CONFIG_SCSI_MVSAS_DEBUG),y) + EXTRA_CFLAGS += -DMV_DEBUG +endif + +obj-$(CONFIG_SCSI_MVSAS) += mvsas.o +mvsas-y += mv_init.o \ + mv_sas.o \ + mv_64xx.o \ + mv_94xx.o diff --git a/drivers/scsi/mvsas/mv_64xx.c b/drivers/scsi/mvsas/mv_64xx.c new file mode 100644 index 000000000000..10a5077b6aed --- /dev/null +++ b/drivers/scsi/mvsas/mv_64xx.c @@ -0,0 +1,793 @@ +/* + * Marvell 88SE64xx hardware specific + * + * Copyright 2007 Red Hat, Inc. + * Copyright 2008 Marvell. + * + * This file is licensed under GPLv2. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2 of the + * License. + * + * 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 "mv_sas.h" +#include "mv_64xx.h" +#include "mv_chips.h" + +static void mvs_64xx_detect_porttype(struct mvs_info *mvi, int i) +{ + void __iomem *regs = mvi->regs; + u32 reg; + struct mvs_phy *phy = &mvi->phy[i]; + + /* TODO check & save device type */ + reg = mr32(MVS_GBL_PORT_TYPE); + phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA); + if (reg & MODE_SAS_SATA & (1 << i)) + phy->phy_type |= PORT_TYPE_SAS; + else + phy->phy_type |= PORT_TYPE_SATA; +} + +static void __devinit mvs_64xx_enable_xmt(struct mvs_info *mvi, int phy_id) +{ + void __iomem *regs = mvi->regs; + u32 tmp; + + tmp = mr32(MVS_PCS); + if (mvi->chip->n_phy <= 4) + tmp |= 1 << (phy_id + PCS_EN_PORT_XMT_SHIFT); + else + tmp |= 1 << (phy_id + PCS_EN_PORT_XMT_SHIFT2); + mw32(MVS_PCS, tmp); +} + +static void __devinit mvs_64xx_phy_hacks(struct mvs_info *mvi) +{ + void __iomem *regs = mvi->regs; + + mvs_phy_hacks(mvi); + + if (!(mvi->flags & MVF_FLAG_SOC)) { + /* TEST - for phy decoding error, adjust voltage levels */ + mw32(MVS_P0_VSR_ADDR + 0, 0x8); + mw32(MVS_P0_VSR_DATA + 0, 0x2F0); + + mw32(MVS_P0_VSR_ADDR + 8, 0x8); + mw32(MVS_P0_VSR_DATA + 8, 0x2F0); + + mw32(MVS_P0_VSR_ADDR + 16, 0x8); + mw32(MVS_P0_VSR_DATA + 16, 0x2F0); + + mw32(MVS_P0_VSR_ADDR + 24, 0x8); + mw32(MVS_P0_VSR_DATA + 24, 0x2F0); + } else { + int i; + /* disable auto port detection */ + mw32(MVS_GBL_PORT_TYPE, 0); + for (i = 0; i < mvi->chip->n_phy; i++) { + mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE7); + mvs_write_port_vsr_data(mvi, i, 0x90000000); + mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE9); + mvs_write_port_vsr_data(mvi, i, 0x50f2); + mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE11); + mvs_write_port_vsr_data(mvi, i, 0x0e); + } + } +} + +static void mvs_64xx_stp_reset(struct mvs_info *mvi, u32 phy_id) +{ + void __iomem *regs = mvi->regs; + u32 reg, tmp; + + if (!(mvi->flags & MVF_FLAG_SOC)) { + if (phy_id < 4) + pci_read_config_dword(mvi->pdev, PCR_PHY_CTL, ®); + else + pci_read_config_dword(mvi->pdev, PCR_PHY_CTL2, ®); + + } else + reg = mr32(MVS_PHY_CTL); + + tmp = reg; + if (phy_id < 4) + tmp |= (1U << phy_id) << PCTL_LINK_OFFS; + else + tmp |= (1U << (phy_id - 4)) << PCTL_LINK_OFFS; + + if (!(mvi->flags & MVF_FLAG_SOC)) { + if (phy_id < 4) { + pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, tmp); + mdelay(10); + pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, reg); + } else { + pci_write_config_dword(mvi->pdev, PCR_PHY_CTL2, tmp); + mdelay(10); + pci_write_config_dword(mvi->pdev, PCR_PHY_CTL2, reg); + } + } else { + mw32(MVS_PHY_CTL, tmp); + mdelay(10); + mw32(MVS_PHY_CTL, reg); + } +} + +static void mvs_64xx_phy_reset(struct mvs_info *mvi, u32 phy_id, int hard) +{ + u32 tmp; + tmp = mvs_read_port_irq_stat(mvi, phy_id); + tmp &= ~PHYEV_RDY_CH; + mvs_write_port_irq_stat(mvi, phy_id, tmp); + tmp = mvs_read_phy_ctl(mvi, phy_id); + if (hard) + tmp |= PHY_RST_HARD; + else + tmp |= PHY_RST; + mvs_write_phy_ctl(mvi, phy_id, tmp); + if (hard) { + do { + tmp = mvs_read_phy_ctl(mvi, phy_id); + } while (tmp & PHY_RST_HARD); + } +} + +static int __devinit mvs_64xx_chip_reset(struct mvs_info *mvi) +{ + void __iomem *regs = mvi->regs; + u32 tmp; + int i; + + /* make sure interrupts are masked immediately (paranoia) */ + mw32(MVS_GBL_CTL, 0); + tmp = mr32(MVS_GBL_CTL); + + /* Reset Controller */ + if (!(tmp & HBA_RST)) { + if (mvi->flags & MVF_PHY_PWR_FIX) { + pci_read_config_dword(mvi->pdev, PCR_PHY_CTL, &tmp); + tmp &= ~PCTL_PWR_OFF; + tmp |= PCTL_PHY_DSBL; + pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, tmp); + + pci_read_config_dword(mvi->pdev, PCR_PHY_CTL2, &tmp); + tmp &= ~PCTL_PWR_OFF; + tmp |= PCTL_PHY_DSBL; + pci_write_config_dword(mvi->pdev, PCR_PHY_CTL2, tmp); + } + } + + /* make sure interrupts are masked immediately (paranoia) */ + mw32(MVS_GBL_CTL, 0); + tmp = mr32(MVS_GBL_CTL); + + /* Reset Controller */ + if (!(tmp & HBA_RST)) { + /* global reset, incl. COMRESET/H_RESET_N (self-clearing) */ + mw32_f(MVS_GBL_CTL, HBA_RST); + } + + /* wait for reset to finish; timeout is just a guess */ + i = 1000; + while (i-- > 0) { + msleep(10); + + if (!(mr32(MVS_GBL_CTL) & HBA_RST)) + break; + } + if (mr32(MVS_GBL_CTL) & HBA_RST) { + dev_printk(KERN_ERR, mvi->dev, "HBA reset failed\n"); + return -EBUSY; + } + return 0; +} + +static void mvs_64xx_phy_disable(struct mvs_info *mvi, u32 phy_id) +{ + void __iomem *regs = mvi->regs; + u32 tmp; + if (!(mvi->flags & MVF_FLAG_SOC)) { + u32 offs; + if (phy_id < 4) + offs = PCR_PHY_CTL; + else { + offs = PCR_PHY_CTL2; + phy_id -= 4; + } + pci_read_config_dword(mvi->pdev, offs, &tmp); + tmp |= 1U << (PCTL_PHY_DSBL_OFFS + phy_id); + pci_write_config_dword(mvi->pdev, offs, tmp); + } else { + tmp = mr32(MVS_PHY_CTL); + tmp |= 1U << (PCTL_PHY_DSBL_OFFS + phy_id); + mw32(MVS_PHY_CTL, tmp); + } +} + +static void mvs_64xx_phy_enable(struct mvs_info *mvi, u32 phy_id) +{ + void __iomem *regs = mvi->regs; + u32 tmp; + if (!(mvi->flags & MVF_FLAG_SOC)) { + u32 offs; + if (phy_id < 4) + offs = PCR_PHY_CTL; + else { + offs = PCR_PHY_CTL2; + phy_id -= 4; + } + pci_read_config_dword(mvi->pdev, offs, &tmp); + tmp &= ~(1U << (PCTL_PHY_DSBL_OFFS + phy_id)); + pci_write_config_dword(mvi->pdev, offs, tmp); + } else { + tmp = mr32(MVS_PHY_CTL); + tmp &= ~(1U << (PCTL_PHY_DSBL_OFFS + phy_id)); + mw32(MVS_PHY_CTL, tmp); + } +} + +static int __devinit mvs_64xx_init(struct mvs_info *mvi) +{ + void __iomem *regs = mvi->regs; + int i; + u32 tmp, cctl; + + if (mvi->pdev && mvi->pdev->revision == 0) + mvi->flags |= MVF_PHY_PWR_FIX; + if (!(mvi->flags & MVF_FLAG_SOC)) { + mvs_show_pcie_usage(mvi); + tmp = mvs_64xx_chip_reset(mvi); + if (tmp) + return tmp; + } else { + tmp = mr32(MVS_PHY_CTL); + tmp &= ~PCTL_PWR_OFF; + tmp |= PCTL_PHY_DSBL; + mw32(MVS_PHY_CTL, tmp); + } + + /* Init Chip */ + /* make sure RST is set; HBA_RST /should/ have done that for us */ + cctl = mr32(MVS_CTL) & 0xFFFF; + if (cctl & CCTL_RST) + cctl &= ~CCTL_RST; + else + mw32_f(MVS_CTL, cctl | CCTL_RST); + + if (!(mvi->flags & MVF_FLAG_SOC)) { + /* write to device control _AND_ device status register */ + pci_read_config_dword(mvi->pdev, PCR_DEV_CTRL, &tmp); + tmp &= ~PRD_REQ_MASK; + tmp |= PRD_REQ_SIZE; + pci_write_config_dword(mvi->pdev, PCR_DEV_CTRL, tmp); + + pci_read_config_dword(mvi->pdev, PCR_PHY_CTL, &tmp); + tmp &= ~PCTL_PWR_OFF; + tmp &= ~PCTL_PHY_DSBL; + pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, tmp); + + pci_read_config_dword(mvi->pdev, PCR_PHY_CTL2, &tmp); + tmp &= PCTL_PWR_OFF; + tmp &= ~PCTL_PHY_DSBL; + pci_write_config_dword(mvi->pdev, PCR_PHY_CTL2, tmp); + } else { + tmp = mr32(MVS_PHY_CTL); + tmp &= ~PCTL_PWR_OFF; + tmp |= PCTL_COM_ON; + tmp &= ~PCTL_PHY_DSBL; + tmp |= PCTL_LINK_RST; + mw32(MVS_PHY_CTL, tmp); + msleep(100); + tmp &= ~PCTL_LINK_RST; + mw32(MVS_PHY_CTL, tmp); + msleep(100); + } + + /* reset control */ + mw32(MVS_PCS, 0); /* MVS_PCS */ + /* init phys */ + mvs_64xx_phy_hacks(mvi); + + /* enable auto port detection */ + mw32(MVS_GBL_PORT_TYPE, MODE_AUTO_DET_EN); + + mw32(MVS_CMD_LIST_LO, mvi->slot_dma); + mw32(MVS_CMD_LIST_HI, (mvi->slot_dma >> 16) >> 16); + + mw32(MVS_RX_FIS_LO, mvi->rx_fis_dma); + mw32(MVS_RX_FIS_HI, (mvi->rx_fis_dma >> 16) >> 16); + + mw32(MVS_TX_CFG, MVS_CHIP_SLOT_SZ); + mw32(MVS_TX_LO, mvi->tx_dma); + mw32(MVS_TX_HI, (mvi->tx_dma >> 16) >> 16); + + mw32(MVS_RX_CFG, MVS_RX_RING_SZ); + mw32(MVS_RX_LO, mvi->rx_dma); + mw32(MVS_RX_HI, (mvi->rx_dma >> 16) >> 16); + + for (i = 0; i < mvi->chip->n_phy; i++) { + /* set phy local SAS address */ + /* should set little endian SAS address to 64xx chip */ + mvs_set_sas_addr(mvi, i, PHYR_ADDR_LO, PHYR_ADDR_HI, + cpu_to_be64(mvi->phy[i].dev_sas_addr)); + + mvs_64xx_enable_xmt(mvi, i); + + mvs_64xx_phy_reset(mvi, i, 1); + msleep(500); + mvs_64xx_detect_porttype(mvi, i); + } + if (mvi->flags & MVF_FLAG_SOC) { + /* set select registers */ + writel(0x0E008000, regs + 0x000); + writel(0x59000008, regs + 0x004); + writel(0x20, regs + 0x008); + writel(0x20, regs + 0x00c); + writel(0x20, regs + 0x010); + writel(0x20, regs + 0x014); + writel(0x20, regs + 0x018); + writel(0x20, regs + 0x01c); + } + for (i = 0; i < mvi->chip->n_phy; i++) { + /* clear phy int status */ + tmp = mvs_read_port_irq_stat(mvi, i); + tmp &= ~PHYEV_SIG_FIS; + mvs_write_port_irq_stat(mvi, i, tmp); + + /* set phy int mask */ + tmp = PHYEV_RDY_CH | PHYEV_BROAD_CH | PHYEV_UNASSOC_FIS | + PHYEV_ID_DONE | PHYEV_DCDR_ERR | PHYEV_CRC_ERR | + PHYEV_DEC_ERR; + mvs_write_port_irq_mask(mvi, i, tmp); + + msleep(100); + mvs_update_phyinfo(mvi, i, 1); + } + + /* FIXME: update wide port bitmaps */ + + /* little endian for open address and command table, etc. */ + /* + * it seems that ( from the spec ) turning on big-endian won't + * do us any good on big-endian machines, need further confirmation + */ + cctl = mr32(MVS_CTL); + cctl |= CCTL_ENDIAN_CMD; + cctl |= CCTL_ENDIAN_DATA; + cctl &= ~CCTL_ENDIAN_OPEN; + cctl |= CCTL_ENDIAN_RSP; + mw32_f(MVS_CTL, cctl); + + /* reset CMD queue */ + tmp = mr32(MVS_PCS); + tmp |= PCS_CMD_RST; + mw32(MVS_PCS, tmp); + /* interrupt coalescing may cause missing HW interrput in some case, + * and the max count is 0x1ff, while our max slot is 0x200, + * it will make count 0. + */ + tmp = 0; + mw32(MVS_INT_COAL, tmp); + + tmp = 0x100; + mw32(MVS_INT_COAL_TMOUT, tmp); + + /* ladies and gentlemen, start your engines */ + mw32(MVS_TX_CFG, 0); + mw32(MVS_TX_CFG, MVS_CHIP_SLOT_SZ | TX_EN); + mw32(MVS_RX_CFG, MVS_RX_RING_SZ | RX_EN); + /* enable CMD/CMPL_Q/RESP mode */ + mw32(MVS_PCS, PCS_SATA_RETRY | PCS_FIS_RX_EN | + PCS_CMD_EN | PCS_CMD_STOP_ERR); + + /* enable completion queue interrupt */ + tmp = (CINT_PORT_MASK | CINT_DONE | CINT_MEM | CINT_SRS | CINT_CI_STOP | + CINT_DMA_PCIE); + + mw32(MVS_INT_MASK, tmp); + + /* Enable SRS interrupt */ + mw32(MVS_INT_MASK_SRS_0, 0xFFFF); + + return 0; +} + +static int mvs_64xx_ioremap(struct mvs_info *mvi) +{ + if (!mvs_ioremap(mvi, 4, 2)) + return 0; + return -1; +} + +static void mvs_64xx_iounmap(struct mvs_info *mvi) +{ + mvs_iounmap(mvi->regs); + mvs_iounmap(mvi->regs_ex); +} + +static void mvs_64xx_interrupt_enable(struct mvs_info *mvi) +{ + void __iomem *regs = mvi->regs; + u32 tmp; + + tmp = mr32(MVS_GBL_CTL); + mw32(MVS_GBL_CTL, tmp | INT_EN); +} + +static void mvs_64xx_interrupt_disable(struct mvs_info *mvi) +{ + void __iomem *regs = mvi->regs; + u32 tmp; + + tmp = mr32(MVS_GBL_CTL); + mw32(MVS_GBL_CTL, tmp & ~INT_EN); +} + +static u32 mvs_64xx_isr_status(struct mvs_info *mvi, int irq) +{ + void __iomem *regs = mvi->regs; + u32 stat; + + if (!(mvi->flags & MVF_FLAG_SOC)) { + stat = mr32(MVS_GBL_INT_STAT); + + if (stat == 0 || stat == 0xffffffff) + return 0; + } else + stat = 1; + return stat; +} + +static irqreturn_t mvs_64xx_isr(struct mvs_info *mvi, int irq, u32 stat) +{ + void __iomem *regs = mvi->regs; + + /* clear CMD_CMPLT ASAP */ + mw32_f(MVS_INT_STAT, CINT_DONE); +#ifndef MVS_USE_TASKLET + spin_lock(&mvi->lock); +#endif + mvs_int_full(mvi); +#ifndef MVS_USE_TASKLET + spin_unlock(&mvi->lock); +#endif + return IRQ_HANDLED; +} + +static void mvs_64xx_command_active(struct mvs_info *mvi, u32 slot_idx) +{ + u32 tmp; + mvs_cw32(mvi, 0x40 + (slot_idx >> 3), 1 << (slot_idx % 32)); + mvs_cw32(mvi, 0x00 + (slot_idx >> 3), 1 << (slot_idx % 32)); + do { + tmp = mvs_cr32(mvi, 0x00 + (slot_idx >> 3)); + } while (tmp & 1 << (slot_idx % 32)); + do { + tmp = mvs_cr32(mvi, 0x40 + (slot_idx >> 3)); + } while (tmp & 1 << (slot_idx % 32)); +} + +static void mvs_64xx_issue_stop(struct mvs_info *mvi, enum mvs_port_type type, + u32 tfs) +{ + void __iomem *regs = mvi->regs; + u32 tmp; + + if (type == PORT_TYPE_SATA) { + tmp = mr32(MVS_INT_STAT_SRS_0) | (1U << tfs); + mw32(MVS_INT_STAT_SRS_0, tmp); + } + mw32(MVS_INT_STAT, CINT_CI_STOP); + tmp = mr32(MVS_PCS) | 0xFF00; + mw32(MVS_PCS, tmp); +} + +static void mvs_64xx_free_reg_set(struct mvs_info *mvi, u8 *tfs) +{ + void __iomem *regs = mvi->regs; + u32 tmp, offs; + + if (*tfs == MVS_ID_NOT_MAPPED) + return; + + offs = 1U << ((*tfs & 0x0f) + PCS_EN_SATA_REG_SHIFT); + if (*tfs < 16) { + tmp = mr32(MVS_PCS); + mw32(MVS_PCS, tmp & ~offs); + } else { + tmp = mr32(MVS_CTL); + mw32(MVS_CTL, tmp & ~offs); + } + + tmp = mr32(MVS_INT_STAT_SRS_0) & (1U << *tfs); + if (tmp) + mw32(MVS_INT_STAT_SRS_0, tmp); + + *tfs = MVS_ID_NOT_MAPPED; + return; +} + +static u8 mvs_64xx_assign_reg_set(struct mvs_info *mvi, u8 *tfs) +{ + int i; + u32 tmp, offs; + void __iomem *regs = mvi->regs; + + if (*tfs != MVS_ID_NOT_MAPPED) + return 0; + + tmp = mr32(MVS_PCS); + + for (i = 0; i < mvi->chip->srs_sz; i++) { + if (i == 16) + tmp = mr32(MVS_CTL); + offs = 1U << ((i & 0x0f) + PCS_EN_SATA_REG_SHIFT); + if (!(tmp & offs)) { + *tfs = i; + + if (i < 16) + mw32(MVS_PCS, tmp | offs); + else + mw32(MVS_CTL, tmp | offs); + tmp = mr32(MVS_INT_STAT_SRS_0) & (1U << i); + if (tmp) + mw32(MVS_INT_STAT_SRS_0, tmp); + return 0; + } + } + return MVS_ID_NOT_MAPPED; +} + +void mvs_64xx_make_prd(struct scatterlist *scatter, int nr, void *prd) +{ + int i; + struct scatterlist *sg; + struct mvs_prd *buf_prd = prd; + for_each_sg(scatter, sg, nr, i) { + buf_prd->addr = cpu_to_le64(sg_dma_address(sg)); + buf_prd->len = cpu_to_le32(sg_dma_len(sg)); + buf_prd++; + } +} + +static int mvs_64xx_oob_done(struct mvs_info *mvi, int i) +{ + u32 phy_st; + mvs_write_port_cfg_addr(mvi, i, + PHYR_PHY_STAT); + phy_st = mvs_read_port_cfg_data(mvi, i); + if (phy_st & PHY_OOB_DTCTD) + return 1; + return 0; +} + +static void mvs_64xx_fix_phy_info(struct mvs_info *mvi, int i, + struct sas_identify_frame *id) + +{ + struct mvs_phy *phy = &mvi->phy[i]; + struct asd_sas_phy *sas_phy = &phy->sas_phy; + + sas_phy->linkrate = + (phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >> + PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET; + + phy->minimum_linkrate = + (phy->phy_status & + PHY_MIN_SPP_PHYS_LINK_RATE_MASK) >> 8; + phy->maximum_linkrate = + (phy->phy_status & + PHY_MAX_SPP_PHYS_LINK_RATE_MASK) >> 12; + + mvs_write_port_cfg_addr(mvi, i, PHYR_IDENTIFY); + phy->dev_info = mvs_read_port_cfg_data(mvi, i); + + mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_DEV_INFO); + phy->att_dev_info = mvs_read_port_cfg_data(mvi, i); + + mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_ADDR_HI); + phy->att_dev_sas_addr = + (u64) mvs_read_port_cfg_data(mvi, i) << 32; + mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_ADDR_LO); + phy->att_dev_sas_addr |= mvs_read_port_cfg_data(mvi, i); + phy->att_dev_sas_addr = SAS_ADDR(&phy->att_dev_sas_addr); +} + +static void mvs_64xx_phy_work_around(struct mvs_info *mvi, int i) +{ + u32 tmp; + struct mvs_phy *phy = &mvi->phy[i]; + /* workaround for HW phy decoding error on 1.5g disk drive */ + mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE6); + tmp = mvs_read_port_vsr_data(mvi, i); + if (((phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >> + PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET) == + SAS_LINK_RATE_1_5_GBPS) + tmp &= ~PHY_MODE6_LATECLK; + else + tmp |= PHY_MODE6_LATECLK; + mvs_write_port_vsr_data(mvi, i, tmp); +} + +void mvs_64xx_phy_set_link_rate(struct mvs_info *mvi, u32 phy_id, + struct sas_phy_linkrates *rates) +{ + u32 lrmin = 0, lrmax = 0; + u32 tmp; + + tmp = mvs_read_phy_ctl(mvi, phy_id); + lrmin = (rates->minimum_linkrate << 8); + lrmax = (rates->maximum_linkrate << 12); + + if (lrmin) { + tmp &= ~(0xf << 8); + tmp |= lrmin; + } + if (lrmax) { + tmp &= ~(0xf << 12); + tmp |= lrmax; + } + mvs_write_phy_ctl(mvi, phy_id, tmp); + mvs_64xx_phy_reset(mvi, phy_id, 1); +} + +static void mvs_64xx_clear_active_cmds(struct mvs_info *mvi) +{ + u32 tmp; + void __iomem *regs = mvi->regs; + tmp = mr32(MVS_PCS); + mw32(MVS_PCS, tmp & 0xFFFF); + mw32(MVS_PCS, tmp); + tmp = mr32(MVS_CTL); + mw32(MVS_CTL, tmp & 0xFFFF); + mw32(MVS_CTL, tmp); +} + + +u32 mvs_64xx_spi_read_data(struct mvs_info *mvi) +{ + void __iomem *regs = mvi->regs_ex; + return ior32(SPI_DATA_REG_64XX); +} + +void mvs_64xx_spi_write_data(struct mvs_info *mvi, u32 data) +{ + void __iomem *regs = mvi->regs_ex; + iow32(SPI_DATA_REG_64XX, data); +} + + +int mvs_64xx_spi_buildcmd(struct mvs_info *mvi, + u32 *dwCmd, + u8 cmd, + u8 read, + u8 length, + u32 addr + ) +{ + u32 dwTmp; + + dwTmp = ((u32)cmd << 24) | ((u32)length << 19); + if (read) + dwTmp |= 1U<<23; + + if (addr != MV_MAX_U32) { + dwTmp |= 1U<<22; + dwTmp |= (addr & 0x0003FFFF); + } + + *dwCmd = dwTmp; + return 0; +} + + +int mvs_64xx_spi_issuecmd(struct mvs_info *mvi, u32 cmd) +{ + void __iomem *regs = mvi->regs_ex; + int retry; + + for (retry = 0; retry < 1; retry++) { + iow32(SPI_CTRL_REG_64XX, SPI_CTRL_VENDOR_ENABLE); + iow32(SPI_CMD_REG_64XX, cmd); + iow32(SPI_CTRL_REG_64XX, + SPI_CTRL_VENDOR_ENABLE | SPI_CTRL_SPISTART); + } + + return 0; +} + +int mvs_64xx_spi_waitdataready(struct mvs_info *mvi, u32 timeout) +{ + void __iomem *regs = mvi->regs_ex; + u32 i, dwTmp; + + for (i = 0; i < timeout; i++) { + dwTmp = ior32(SPI_CTRL_REG_64XX); + if (!(dwTmp & SPI_CTRL_SPISTART)) + return 0; + msleep(10); + } + + return -1; +} + +#ifndef DISABLE_HOTPLUG_DMA_FIX +void mvs_64xx_fix_dma(dma_addr_t buf_dma, int buf_len, int from, void *prd) +{ + int i; + struct mvs_prd *buf_prd = prd; + buf_prd += from; + for (i = 0; i < MAX_SG_ENTRY - from; i++) { + buf_prd->addr = cpu_to_le64(buf_dma); + buf_prd->len = cpu_to_le32(buf_len); + ++buf_prd; + } +} +#endif + +const struct mvs_dispatch mvs_64xx_dispatch = { + "mv64xx", + mvs_64xx_init, + NULL, + mvs_64xx_ioremap, + mvs_64xx_iounmap, + mvs_64xx_isr, + mvs_64xx_isr_status, + mvs_64xx_interrupt_enable, + mvs_64xx_interrupt_disable, + mvs_read_phy_ctl, + mvs_write_phy_ctl, + mvs_read_port_cfg_data, + mvs_write_port_cfg_data, + mvs_write_port_cfg_addr, + mvs_read_port_vsr_data, + mvs_write_port_vsr_data, + mvs_write_port_vsr_addr, + mvs_read_port_irq_stat, + mvs_write_port_irq_stat, + mvs_read_port_irq_mask, + mvs_write_port_irq_mask, + mvs_get_sas_addr, + mvs_64xx_command_active, + mvs_64xx_issue_stop, + mvs_start_delivery, + mvs_rx_update, + mvs_int_full, + mvs_64xx_assign_reg_set, + mvs_64xx_free_reg_set, + mvs_get_prd_size, + mvs_get_prd_count, + mvs_64xx_make_prd, + mvs_64xx_detect_porttype, + mvs_64xx_oob_done, + mvs_64xx_fix_phy_info, + mvs_64xx_phy_work_around, + mvs_64xx_phy_set_link_rate, + mvs_hw_max_link_rate, + mvs_64xx_phy_disable, + mvs_64xx_phy_enable, + mvs_64xx_phy_reset, + mvs_64xx_stp_reset, + mvs_64xx_clear_active_cmds, + mvs_64xx_spi_read_data, + mvs_64xx_spi_write_data, + mvs_64xx_spi_buildcmd, + mvs_64xx_spi_issuecmd, + mvs_64xx_spi_waitdataready, +#ifndef DISABLE_HOTPLUG_DMA_FIX + mvs_64xx_fix_dma, +#endif +}; + diff --git a/drivers/scsi/mvsas/mv_64xx.h b/drivers/scsi/mvsas/mv_64xx.h new file mode 100644 index 000000000000..42e947d9795e --- /dev/null +++ b/drivers/scsi/mvsas/mv_64xx.h @@ -0,0 +1,151 @@ +/* + * Marvell 88SE64xx hardware specific head file + * + * Copyright 2007 Red Hat, Inc. + * Copyright 2008 Marvell. + * + * This file is licensed under GPLv2. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2 of the + * License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA +*/ + +#ifndef _MVS64XX_REG_H_ +#define _MVS64XX_REG_H_ + +#include + +#define MAX_LINK_RATE SAS_LINK_RATE_3_0_GBPS + +/* enhanced mode registers (BAR4) */ +enum hw_registers { + MVS_GBL_CTL = 0x04, /* global control */ + MVS_GBL_INT_STAT = 0x08, /* global irq status */ + MVS_GBL_PI = 0x0C, /* ports implemented bitmask */ + + MVS_PHY_CTL = 0x40, /* SOC PHY Control */ + MVS_PORTS_IMP = 0x9C, /* SOC Port Implemented */ + + MVS_GBL_PORT_TYPE = 0xa0, /* port type */ + + MVS_CTL = 0x100, /* SAS/SATA port configuration */ + MVS_PCS = 0x104, /* SAS/SATA port control/status */ + MVS_CMD_LIST_LO = 0x108, /* cmd list addr */ + MVS_CMD_LIST_HI = 0x10C, + MVS_RX_FIS_LO = 0x110, /* RX FIS list addr */ + MVS_RX_FIS_HI = 0x114, + + MVS_TX_CFG = 0x120, /* TX configuration */ + MVS_TX_LO = 0x124, /* TX (delivery) ring addr */ + MVS_TX_HI = 0x128, + + MVS_TX_PROD_IDX = 0x12C, /* TX producer pointer */ + MVS_TX_CONS_IDX = 0x130, /* TX consumer pointer (RO) */ + MVS_RX_CFG = 0x134, /* RX configuration */ + MVS_RX_LO = 0x138, /* RX (completion) ring addr */ + MVS_RX_HI = 0x13C, + MVS_RX_CONS_IDX = 0x140, /* RX consumer pointer (RO) */ + + MVS_INT_COAL = 0x148, /* Int coalescing config */ + MVS_INT_COAL_TMOUT = 0x14C, /* Int coalescing timeout */ + MVS_INT_STAT = 0x150, /* Central int status */ + MVS_INT_MASK = 0x154, /* Central int enable */ + MVS_INT_STAT_SRS_0 = 0x158, /* SATA register set status */ + MVS_INT_MASK_SRS_0 = 0x15C, + + /* ports 1-3 follow after this */ + MVS_P0_INT_STAT = 0x160, /* port0 interrupt status */ + MVS_P0_INT_MASK = 0x164, /* port0 interrupt mask */ + /* ports 5-7 follow after this */ + MVS_P4_INT_STAT = 0x200, /* Port4 interrupt status */ + MVS_P4_INT_MASK = 0x204, /* Port4 interrupt enable mask */ + + /* ports 1-3 follow after this */ + MVS_P0_SER_CTLSTAT = 0x180, /* port0 serial control/status */ + /* ports 5-7 follow after this */ + MVS_P4_SER_CTLSTAT = 0x220, /* port4 serial control/status */ + + MVS_CMD_ADDR = 0x1B8, /* Command register port (addr) */ + MVS_CMD_DATA = 0x1BC, /* Command register port (data) */ + + /* ports 1-3 follow after this */ + MVS_P0_CFG_ADDR = 0x1C0, /* port0 phy register address */ + MVS_P0_CFG_DATA = 0x1C4, /* port0 phy register data */ + /* ports 5-7 follow after this */ + MVS_P4_CFG_ADDR = 0x230, /* Port4 config address */ + MVS_P4_CFG_DATA = 0x234, /* Port4 config data */ + + /* ports 1-3 follow after this */ + MVS_P0_VSR_ADDR = 0x1E0, /* port0 VSR address */ + MVS_P0_VSR_DATA = 0x1E4, /* port0 VSR data */ + /* ports 5-7 follow after this */ + MVS_P4_VSR_ADDR = 0x250, /* port4 VSR addr */ + MVS_P4_VSR_DATA = 0x254, /* port4 VSR data */ +}; + +enum pci_cfg_registers { + PCR_PHY_CTL = 0x40, + PCR_PHY_CTL2 = 0x90, + PCR_DEV_CTRL = 0xE8, + PCR_LINK_STAT = 0xF2, +}; + +/* SAS/SATA Vendor Specific Port Registers */ +enum sas_sata_vsp_regs { + VSR_PHY_STAT = 0x00, /* Phy Status */ + VSR_PHY_MODE1 = 0x01, /* phy tx */ + VSR_PHY_MODE2 = 0x02, /* tx scc */ + VSR_PHY_MODE3 = 0x03, /* pll */ + VSR_PHY_MODE4 = 0x04, /* VCO */ + VSR_PHY_MODE5 = 0x05, /* Rx */ + VSR_PHY_MODE6 = 0x06, /* CDR */ + VSR_PHY_MODE7 = 0x07, /* Impedance */ + VSR_PHY_MODE8 = 0x08, /* Voltage */ + VSR_PHY_MODE9 = 0x09, /* Test */ + VSR_PHY_MODE10 = 0x0A, /* Power */ + VSR_PHY_MODE11 = 0x0B, /* Phy Mode */ + VSR_PHY_VS0 = 0x0C, /* Vednor Specific 0 */ + VSR_PHY_VS1 = 0x0D, /* Vednor Specific 1 */ +}; + +enum chip_register_bits { + PHY_MIN_SPP_PHYS_LINK_RATE_MASK = (0xF << 8), + PHY_MAX_SPP_PHYS_LINK_RATE_MASK = (0xF << 12), + PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET = (16), + PHY_NEG_SPP_PHYS_LINK_RATE_MASK = + (0xF << PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET), +}; + +#define MAX_SG_ENTRY 64 + +struct mvs_prd { + __le64 addr; /* 64-bit buffer address */ + __le32 reserved; + __le32 len; /* 16-bit length */ +}; + +#define SPI_CTRL_REG 0xc0 +#define SPI_CTRL_VENDOR_ENABLE (1U<<29) +#define SPI_CTRL_SPIRDY (1U<<22) +#define SPI_CTRL_SPISTART (1U<<20) + +#define SPI_CMD_REG 0xc4 +#define SPI_DATA_REG 0xc8 + +#define SPI_CTRL_REG_64XX 0x10 +#define SPI_CMD_REG_64XX 0x14 +#define SPI_DATA_REG_64XX 0x18 + +#endif diff --git a/drivers/scsi/mvsas/mv_94xx.c b/drivers/scsi/mvsas/mv_94xx.c new file mode 100644 index 000000000000..0940fae19d20 --- /dev/null +++ b/drivers/scsi/mvsas/mv_94xx.c @@ -0,0 +1,672 @@ +/* + * Marvell 88SE94xx hardware specific + * + * Copyright 2007 Red Hat, Inc. + * Copyright 2008 Marvell. + * + * This file is licensed under GPLv2. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2 of the + * License. + * + * 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 "mv_sas.h" +#include "mv_94xx.h" +#include "mv_chips.h" + +static void mvs_94xx_detect_porttype(struct mvs_info *mvi, int i) +{ + u32 reg; + struct mvs_phy *phy = &mvi->phy[i]; + u32 phy_status; + + mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE3); + reg = mvs_read_port_vsr_data(mvi, i); + phy_status = ((reg & 0x3f0000) >> 16) & 0xff; + phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA); + switch (phy_status) { + case 0x10: + phy->phy_type |= PORT_TYPE_SAS; + break; + case 0x1d: + default: + phy->phy_type |= PORT_TYPE_SATA; + break; + } +} + +static void __devinit mvs_94xx_enable_xmt(struct mvs_info *mvi, int phy_id) +{ + void __iomem *regs = mvi->regs; + u32 tmp; + + tmp = mr32(MVS_PCS); + tmp |= 1 << (phy_id + PCS_EN_PORT_XMT_SHIFT2); + mw32(MVS_PCS, tmp); +} + +static void mvs_94xx_phy_reset(struct mvs_info *mvi, u32 phy_id, int hard) +{ + u32 tmp; + + tmp = mvs_read_port_irq_stat(mvi, phy_id); + tmp &= ~PHYEV_RDY_CH; + mvs_write_port_irq_stat(mvi, phy_id, tmp); + if (hard) { + tmp = mvs_read_phy_ctl(mvi, phy_id); + tmp |= PHY_RST_HARD; + mvs_write_phy_ctl(mvi, phy_id, tmp); + do { + tmp = mvs_read_phy_ctl(mvi, phy_id); + } while (tmp & PHY_RST_HARD); + } else { + mvs_write_port_vsr_addr(mvi, phy_id, VSR_PHY_STAT); + tmp = mvs_read_port_vsr_data(mvi, phy_id); + tmp |= PHY_RST; + mvs_write_port_vsr_data(mvi, phy_id, tmp); + } +} + +static void mvs_94xx_phy_disable(struct mvs_info *mvi, u32 phy_id) +{ + u32 tmp; + mvs_write_port_vsr_addr(mvi, phy_id, VSR_PHY_MODE2); + tmp = mvs_read_port_vsr_data(mvi, phy_id); + mvs_write_port_vsr_data(mvi, phy_id, tmp | 0x00800000); +} + +static void mvs_94xx_phy_enable(struct mvs_info *mvi, u32 phy_id) +{ + mvs_write_port_vsr_addr(mvi, phy_id, 0x1B4); + mvs_write_port_vsr_data(mvi, phy_id, 0x8300ffc1); + mvs_write_port_vsr_addr(mvi, phy_id, 0x104); + mvs_write_port_vsr_data(mvi, phy_id, 0x00018080); + mvs_write_port_vsr_addr(mvi, phy_id, VSR_PHY_MODE2); + mvs_write_port_vsr_data(mvi, phy_id, 0x00207fff); +} + +static int __devinit mvs_94xx_init(struct mvs_info *mvi) +{ + void __iomem *regs = mvi->regs; + int i; + u32 tmp, cctl; + + mvs_show_pcie_usage(mvi); + if (mvi->flags & MVF_FLAG_SOC) { + tmp = mr32(MVS_PHY_CTL); + tmp &= ~PCTL_PWR_OFF; + tmp |= PCTL_PHY_DSBL; + mw32(MVS_PHY_CTL, tmp); + } + + /* Init Chip */ + /* make sure RST is set; HBA_RST /should/ have done that for us */ + cctl = mr32(MVS_CTL) & 0xFFFF; + if (cctl & CCTL_RST) + cctl &= ~CCTL_RST; + else + mw32_f(MVS_CTL, cctl | CCTL_RST); + + if (mvi->flags & MVF_FLAG_SOC) { + tmp = mr32(MVS_PHY_CTL); + tmp &= ~PCTL_PWR_OFF; + tmp |= PCTL_COM_ON; + tmp &= ~PCTL_PHY_DSBL; + tmp |= PCTL_LINK_RST; + mw32(MVS_PHY_CTL, tmp); + msleep(100); + tmp &= ~PCTL_LINK_RST; + mw32(MVS_PHY_CTL, tmp); + msleep(100); + } + + /* reset control */ + mw32(MVS_PCS, 0); /* MVS_PCS */ + mw32(MVS_STP_REG_SET_0, 0); + mw32(MVS_STP_REG_SET_1, 0); + + /* init phys */ + mvs_phy_hacks(mvi); + + /* disable Multiplexing, enable phy implemented */ + mw32(MVS_PORTS_IMP, 0xFF); + + + mw32(MVS_PA_VSR_ADDR, 0x00000104); + mw32(MVS_PA_VSR_PORT, 0x00018080); + mw32(MVS_PA_VSR_ADDR, VSR_PHY_MODE8); + mw32(MVS_PA_VSR_PORT, 0x0084ffff); + + /* set LED blink when IO*/ + mw32(MVS_PA_VSR_ADDR, 0x00000030); + tmp = mr32(MVS_PA_VSR_PORT); + tmp &= 0xFFFF00FF; + tmp |= 0x00003300; + mw32(MVS_PA_VSR_PORT, tmp); + + mw32(MVS_CMD_LIST_LO, mvi->slot_dma); + mw32(MVS_CMD_LIST_HI, (mvi->slot_dma >> 16) >> 16); + + mw32(MVS_RX_FIS_LO, mvi->rx_fis_dma); + mw32(MVS_RX_FIS_HI, (mvi->rx_fis_dma >> 16) >> 16); + + mw32(MVS_TX_CFG, MVS_CHIP_SLOT_SZ); + mw32(MVS_TX_LO, mvi->tx_dma); + mw32(MVS_TX_HI, (mvi->tx_dma >> 16) >> 16); + + mw32(MVS_RX_CFG, MVS_RX_RING_SZ); + mw32(MVS_RX_LO, mvi->rx_dma); + mw32(MVS_RX_HI, (mvi->rx_dma >> 16) >> 16); + + for (i = 0; i < mvi->chip->n_phy; i++) { + mvs_94xx_phy_disable(mvi, i); + /* set phy local SAS address */ + mvs_set_sas_addr(mvi, i, CONFIG_ID_FRAME3, CONFIG_ID_FRAME4, + (mvi->phy[i].dev_sas_addr)); + + mvs_94xx_enable_xmt(mvi, i); + mvs_94xx_phy_enable(mvi, i); + + mvs_94xx_phy_reset(mvi, i, 1); + msleep(500); + mvs_94xx_detect_porttype(mvi, i); + } + + if (mvi->flags & MVF_FLAG_SOC) { + /* set select registers */ + writel(0x0E008000, regs + 0x000); + writel(0x59000008, regs + 0x004); + writel(0x20, regs + 0x008); + writel(0x20, regs + 0x00c); + writel(0x20, regs + 0x010); + writel(0x20, regs + 0x014); + writel(0x20, regs + 0x018); + writel(0x20, regs + 0x01c); + } + for (i = 0; i < mvi->chip->n_phy; i++) { + /* clear phy int status */ + tmp = mvs_read_port_irq_stat(mvi, i); + tmp &= ~PHYEV_SIG_FIS; + mvs_write_port_irq_stat(mvi, i, tmp); + + /* set phy int mask */ + tmp = PHYEV_RDY_CH | PHYEV_BROAD_CH | + PHYEV_ID_DONE | PHYEV_DCDR_ERR | PHYEV_CRC_ERR ; + mvs_write_port_irq_mask(mvi, i, tmp); + + msleep(100); + mvs_update_phyinfo(mvi, i, 1); + } + + /* FIXME: update wide port bitmaps */ + + /* little endian for open address and command table, etc. */ + /* + * it seems that ( from the spec ) turning on big-endian won't + * do us any good on big-endian machines, need further confirmation + */ + cctl = mr32(MVS_CTL); + cctl |= CCTL_ENDIAN_CMD; + cctl |= CCTL_ENDIAN_DATA; + cctl &= ~CCTL_ENDIAN_OPEN; + cctl |= CCTL_ENDIAN_RSP; + mw32_f(MVS_CTL, cctl); + + /* reset CMD queue */ + tmp = mr32(MVS_PCS); + tmp |= PCS_CMD_RST; + mw32(MVS_PCS, tmp); + /* interrupt coalescing may cause missing HW interrput in some case, + * and the max count is 0x1ff, while our max slot is 0x200, + * it will make count 0. + */ + tmp = 0; + mw32(MVS_INT_COAL, tmp); + + tmp = 0x100; + mw32(MVS_INT_COAL_TMOUT, tmp); + + /* ladies and gentlemen, start your engines */ + mw32(MVS_TX_CFG, 0); + mw32(MVS_TX_CFG, MVS_CHIP_SLOT_SZ | TX_EN); + mw32(MVS_RX_CFG, MVS_RX_RING_SZ | RX_EN); + /* enable CMD/CMPL_Q/RESP mode */ + mw32(MVS_PCS, PCS_SATA_RETRY_2 | PCS_FIS_RX_EN | + PCS_CMD_EN | PCS_CMD_STOP_ERR); + + /* enable completion queue interrupt */ + tmp = (CINT_PORT_MASK | CINT_DONE | CINT_MEM | CINT_SRS | CINT_CI_STOP | + CINT_DMA_PCIE); + tmp |= CINT_PHY_MASK; + mw32(MVS_INT_MASK, tmp); + + /* Enable SRS interrupt */ + mw32(MVS_INT_MASK_SRS_0, 0xFFFF); + + return 0; +} + +static int mvs_94xx_ioremap(struct mvs_info *mvi) +{ + if (!mvs_ioremap(mvi, 2, -1)) { + mvi->regs_ex = mvi->regs + 0x10200; + mvi->regs += 0x20000; + if (mvi->id == 1) + mvi->regs += 0x4000; + return 0; + } + return -1; +} + +static void mvs_94xx_iounmap(struct mvs_info *mvi) +{ + if (mvi->regs) { + mvi->regs -= 0x20000; + if (mvi->id == 1) + mvi->regs -= 0x4000; + mvs_iounmap(mvi->regs); + } +} + +static void mvs_94xx_interrupt_enable(struct mvs_info *mvi) +{ + void __iomem *regs = mvi->regs_ex; + u32 tmp; + + tmp = mr32(MVS_GBL_CTL); + tmp |= (IRQ_SAS_A | IRQ_SAS_B); + mw32(MVS_GBL_INT_STAT, tmp); + writel(tmp, regs + 0x0C); + writel(tmp, regs + 0x10); + writel(tmp, regs + 0x14); + writel(tmp, regs + 0x18); + mw32(MVS_GBL_CTL, tmp); +} + +static void mvs_94xx_interrupt_disable(struct mvs_info *mvi) +{ + void __iomem *regs = mvi->regs_ex; + u32 tmp; + + tmp = mr32(MVS_GBL_CTL); + + tmp &= ~(IRQ_SAS_A | IRQ_SAS_B); + mw32(MVS_GBL_INT_STAT, tmp); + writel(tmp, regs + 0x0C); + writel(tmp, regs + 0x10); + writel(tmp, regs + 0x14); + writel(tmp, regs + 0x18); + mw32(MVS_GBL_CTL, tmp); +} + +static u32 mvs_94xx_isr_status(struct mvs_info *mvi, int irq) +{ + void __iomem *regs = mvi->regs_ex; + u32 stat = 0; + if (!(mvi->flags & MVF_FLAG_SOC)) { + stat = mr32(MVS_GBL_INT_STAT); + + if (!(stat & (IRQ_SAS_A | IRQ_SAS_B))) + return 0; + } + return stat; +} + +static irqreturn_t mvs_94xx_isr(struct mvs_info *mvi, int irq, u32 stat) +{ + void __iomem *regs = mvi->regs; + + if (((stat & IRQ_SAS_A) && mvi->id == 0) || + ((stat & IRQ_SAS_B) && mvi->id == 1)) { + mw32_f(MVS_INT_STAT, CINT_DONE); + #ifndef MVS_USE_TASKLET + spin_lock(&mvi->lock); + #endif + mvs_int_full(mvi); + #ifndef MVS_USE_TASKLET + spin_unlock(&mvi->lock); + #endif + } + return IRQ_HANDLED; +} + +static void mvs_94xx_command_active(struct mvs_info *mvi, u32 slot_idx) +{ + u32 tmp; + mvs_cw32(mvi, 0x300 + (slot_idx >> 3), 1 << (slot_idx % 32)); + do { + tmp = mvs_cr32(mvi, 0x300 + (slot_idx >> 3)); + } while (tmp & 1 << (slot_idx % 32)); +} + +static void mvs_94xx_issue_stop(struct mvs_info *mvi, enum mvs_port_type type, + u32 tfs) +{ + void __iomem *regs = mvi->regs; + u32 tmp; + + if (type == PORT_TYPE_SATA) { + tmp = mr32(MVS_INT_STAT_SRS_0) | (1U << tfs); + mw32(MVS_INT_STAT_SRS_0, tmp); + } + mw32(MVS_INT_STAT, CINT_CI_STOP); + tmp = mr32(MVS_PCS) | 0xFF00; + mw32(MVS_PCS, tmp); +} + +static void mvs_94xx_free_reg_set(struct mvs_info *mvi, u8 *tfs) +{ + void __iomem *regs = mvi->regs; + u32 tmp; + u8 reg_set = *tfs; + + if (*tfs == MVS_ID_NOT_MAPPED) + return; + + mvi->sata_reg_set &= ~bit(reg_set); + if (reg_set < 32) { + w_reg_set_enable(reg_set, (u32)mvi->sata_reg_set); + tmp = mr32(MVS_INT_STAT_SRS_0) & (u32)mvi->sata_reg_set; + if (tmp) + mw32(MVS_INT_STAT_SRS_0, tmp); + } else { + w_reg_set_enable(reg_set, mvi->sata_reg_set); + tmp = mr32(MVS_INT_STAT_SRS_1) & mvi->sata_reg_set; + if (tmp) + mw32(MVS_INT_STAT_SRS_1, tmp); + } + + *tfs = MVS_ID_NOT_MAPPED; + + return; +} + +static u8 mvs_94xx_assign_reg_set(struct mvs_info *mvi, u8 *tfs) +{ + int i; + void __iomem *regs = mvi->regs; + + if (*tfs != MVS_ID_NOT_MAPPED) + return 0; + + i = mv_ffc64(mvi->sata_reg_set); + if (i > 32) { + mvi->sata_reg_set |= bit(i); + w_reg_set_enable(i, (u32)(mvi->sata_reg_set >> 32)); + *tfs = i; + return 0; + } else if (i >= 0) { + mvi->sata_reg_set |= bit(i); + w_reg_set_enable(i, (u32)mvi->sata_reg_set); + *tfs = i; + return 0; + } + return MVS_ID_NOT_MAPPED; +} + +static void mvs_94xx_make_prd(struct scatterlist *scatter, int nr, void *prd) +{ + int i; + struct scatterlist *sg; + struct mvs_prd *buf_prd = prd; + for_each_sg(scatter, sg, nr, i) { + buf_prd->addr = cpu_to_le64(sg_dma_address(sg)); + buf_prd->im_len.len = cpu_to_le32(sg_dma_len(sg)); + buf_prd++; + } +} + +static int mvs_94xx_oob_done(struct mvs_info *mvi, int i) +{ + u32 phy_st; + phy_st = mvs_read_phy_ctl(mvi, i); + if (phy_st & PHY_READY_MASK) /* phy ready */ + return 1; + return 0; +} + +static void mvs_94xx_get_dev_identify_frame(struct mvs_info *mvi, int port_id, + struct sas_identify_frame *id) +{ + int i; + u32 id_frame[7]; + + for (i = 0; i < 7; i++) { + mvs_write_port_cfg_addr(mvi, port_id, + CONFIG_ID_FRAME0 + i * 4); + id_frame[i] = mvs_read_port_cfg_data(mvi, port_id); + } + memcpy(id, id_frame, 28); +} + +static void mvs_94xx_get_att_identify_frame(struct mvs_info *mvi, int port_id, + struct sas_identify_frame *id) +{ + int i; + u32 id_frame[7]; + + /* mvs_hexdump(28, (u8 *)id_frame, 0); */ + for (i = 0; i < 7; i++) { + mvs_write_port_cfg_addr(mvi, port_id, + CONFIG_ATT_ID_FRAME0 + i * 4); + id_frame[i] = mvs_read_port_cfg_data(mvi, port_id); + mv_dprintk("94xx phy %d atta frame %d %x.\n", + port_id + mvi->id * mvi->chip->n_phy, i, id_frame[i]); + } + /* mvs_hexdump(28, (u8 *)id_frame, 0); */ + memcpy(id, id_frame, 28); +} + +static u32 mvs_94xx_make_dev_info(struct sas_identify_frame *id) +{ + u32 att_dev_info = 0; + + att_dev_info |= id->dev_type; + if (id->stp_iport) + att_dev_info |= PORT_DEV_STP_INIT; + if (id->smp_iport) + att_dev_info |= PORT_DEV_SMP_INIT; + if (id->ssp_iport) + att_dev_info |= PORT_DEV_SSP_INIT; + if (id->stp_tport) + att_dev_info |= PORT_DEV_STP_TRGT; + if (id->smp_tport) + att_dev_info |= PORT_DEV_SMP_TRGT; + if (id->ssp_tport) + att_dev_info |= PORT_DEV_SSP_TRGT; + + att_dev_info |= (u32)id->phy_id<<24; + return att_dev_info; +} + +static u32 mvs_94xx_make_att_info(struct sas_identify_frame *id) +{ + return mvs_94xx_make_dev_info(id); +} + +static void mvs_94xx_fix_phy_info(struct mvs_info *mvi, int i, + struct sas_identify_frame *id) +{ + struct mvs_phy *phy = &mvi->phy[i]; + struct asd_sas_phy *sas_phy = &phy->sas_phy; + mv_dprintk("get all reg link rate is 0x%x\n", phy->phy_status); + sas_phy->linkrate = + (phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >> + PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET; + sas_phy->linkrate += 0x8; + mv_dprintk("get link rate is %d\n", sas_phy->linkrate); + phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS; + phy->maximum_linkrate = SAS_LINK_RATE_6_0_GBPS; + mvs_94xx_get_dev_identify_frame(mvi, i, id); + phy->dev_info = mvs_94xx_make_dev_info(id); + + if (phy->phy_type & PORT_TYPE_SAS) { + mvs_94xx_get_att_identify_frame(mvi, i, id); + phy->att_dev_info = mvs_94xx_make_att_info(id); + phy->att_dev_sas_addr = *(u64 *)id->sas_addr; + } else { + phy->att_dev_info = PORT_DEV_STP_TRGT | 1; + } + +} + +void mvs_94xx_phy_set_link_rate(struct mvs_info *mvi, u32 phy_id, + struct sas_phy_linkrates *rates) +{ + /* TODO */ +} + +static void mvs_94xx_clear_active_cmds(struct mvs_info *mvi) +{ + u32 tmp; + void __iomem *regs = mvi->regs; + tmp = mr32(MVS_STP_REG_SET_0); + mw32(MVS_STP_REG_SET_0, 0); + mw32(MVS_STP_REG_SET_0, tmp); + tmp = mr32(MVS_STP_REG_SET_1); + mw32(MVS_STP_REG_SET_1, 0); + mw32(MVS_STP_REG_SET_1, tmp); +} + + +u32 mvs_94xx_spi_read_data(struct mvs_info *mvi) +{ + void __iomem *regs = mvi->regs_ex - 0x10200; + return mr32(SPI_RD_DATA_REG_94XX); +} + +void mvs_94xx_spi_write_data(struct mvs_info *mvi, u32 data) +{ + void __iomem *regs = mvi->regs_ex - 0x10200; + mw32(SPI_RD_DATA_REG_94XX, data); +} + + +int mvs_94xx_spi_buildcmd(struct mvs_info *mvi, + u32 *dwCmd, + u8 cmd, + u8 read, + u8 length, + u32 addr + ) +{ + void __iomem *regs = mvi->regs_ex - 0x10200; + u32 dwTmp; + + dwTmp = ((u32)cmd << 8) | ((u32)length << 4); + if (read) + dwTmp |= SPI_CTRL_READ_94XX; + + if (addr != MV_MAX_U32) { + mw32(SPI_ADDR_REG_94XX, (addr & 0x0003FFFFL)); + dwTmp |= SPI_ADDR_VLD_94XX; + } + + *dwCmd = dwTmp; + return 0; +} + + +int mvs_94xx_spi_issuecmd(struct mvs_info *mvi, u32 cmd) +{ + void __iomem *regs = mvi->regs_ex - 0x10200; + mw32(SPI_CTRL_REG_94XX, cmd | SPI_CTRL_SpiStart_94XX); + + return 0; +} + +int mvs_94xx_spi_waitdataready(struct mvs_info *mvi, u32 timeout) +{ + void __iomem *regs = mvi->regs_ex - 0x10200; + u32 i, dwTmp; + + for (i = 0; i < timeout; i++) { + dwTmp = mr32(SPI_CTRL_REG_94XX); + if (!(dwTmp & SPI_CTRL_SpiStart_94XX)) + return 0; + msleep(10); + } + + return -1; +} + +#ifndef DISABLE_HOTPLUG_DMA_FIX +void mvs_94xx_fix_dma(dma_addr_t buf_dma, int buf_len, int from, void *prd) +{ + int i; + struct mvs_prd *buf_prd = prd; + buf_prd += from; + for (i = 0; i < MAX_SG_ENTRY - from; i++) { + buf_prd->addr = cpu_to_le64(buf_dma); + buf_prd->im_len.len = cpu_to_le32(buf_len); + ++buf_prd; + } +} +#endif + +const struct mvs_dispatch mvs_94xx_dispatch = { + "mv94xx", + mvs_94xx_init, + NULL, + mvs_94xx_ioremap, + mvs_94xx_iounmap, + mvs_94xx_isr, + mvs_94xx_isr_status, + mvs_94xx_interrupt_enable, + mvs_94xx_interrupt_disable, + mvs_read_phy_ctl, + mvs_write_phy_ctl, + mvs_read_port_cfg_data, + mvs_write_port_cfg_data, + mvs_write_port_cfg_addr, + mvs_read_port_vsr_data, + mvs_write_port_vsr_data, + mvs_write_port_vsr_addr, + mvs_read_port_irq_stat, + mvs_write_port_irq_stat, + mvs_read_port_irq_mask, + mvs_write_port_irq_mask, + mvs_get_sas_addr, + mvs_94xx_command_active, + mvs_94xx_issue_stop, + mvs_start_delivery, + mvs_rx_update, + mvs_int_full, + mvs_94xx_assign_reg_set, + mvs_94xx_free_reg_set, + mvs_get_prd_size, + mvs_get_prd_count, + mvs_94xx_make_prd, + mvs_94xx_detect_porttype, + mvs_94xx_oob_done, + mvs_94xx_fix_phy_info, + NULL, + mvs_94xx_phy_set_link_rate, + mvs_hw_max_link_rate, + mvs_94xx_phy_disable, + mvs_94xx_phy_enable, + mvs_94xx_phy_reset, + NULL, + mvs_94xx_clear_active_cmds, + mvs_94xx_spi_read_data, + mvs_94xx_spi_write_data, + mvs_94xx_spi_buildcmd, + mvs_94xx_spi_issuecmd, + mvs_94xx_spi_waitdataready, +#ifndef DISABLE_HOTPLUG_DMA_FIX + mvs_94xx_fix_dma, +#endif +}; + diff --git a/drivers/scsi/mvsas/mv_94xx.h b/drivers/scsi/mvsas/mv_94xx.h new file mode 100644 index 000000000000..23ed9b164669 --- /dev/null +++ b/drivers/scsi/mvsas/mv_94xx.h @@ -0,0 +1,222 @@ +/* + * Marvell 88SE94xx hardware specific head file + * + * Copyright 2007 Red Hat, Inc. + * Copyright 2008 Marvell. + * + * This file is licensed under GPLv2. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2 of the + * License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA +*/ + +#ifndef _MVS94XX_REG_H_ +#define _MVS94XX_REG_H_ + +#include + +#define MAX_LINK_RATE SAS_LINK_RATE_6_0_GBPS + +enum hw_registers { + MVS_GBL_CTL = 0x04, /* global control */ + MVS_GBL_INT_STAT = 0x00, /* global irq status */ + MVS_GBL_PI = 0x0C, /* ports implemented bitmask */ + + MVS_PHY_CTL = 0x40, /* SOC PHY Control */ + MVS_PORTS_IMP = 0x9C, /* SOC Port Implemented */ + + MVS_GBL_PORT_TYPE = 0xa0, /* port type */ + + MVS_CTL = 0x100, /* SAS/SATA port configuration */ + MVS_PCS = 0x104, /* SAS/SATA port control/status */ + MVS_CMD_LIST_LO = 0x108, /* cmd list addr */ + MVS_CMD_LIST_HI = 0x10C, + MVS_RX_FIS_LO = 0x110, /* RX FIS list addr */ + MVS_RX_FIS_HI = 0x114, + MVS_STP_REG_SET_0 = 0x118, /* STP/SATA Register Set Enable */ + MVS_STP_REG_SET_1 = 0x11C, + MVS_TX_CFG = 0x120, /* TX configuration */ + MVS_TX_LO = 0x124, /* TX (delivery) ring addr */ + MVS_TX_HI = 0x128, + + MVS_TX_PROD_IDX = 0x12C, /* TX producer pointer */ + MVS_TX_CONS_IDX = 0x130, /* TX consumer pointer (RO) */ + MVS_RX_CFG = 0x134, /* RX configuration */ + MVS_RX_LO = 0x138, /* RX (completion) ring addr */ + MVS_RX_HI = 0x13C, + MVS_RX_CONS_IDX = 0x140, /* RX consumer pointer (RO) */ + + MVS_INT_COAL = 0x148, /* Int coalescing config */ + MVS_INT_COAL_TMOUT = 0x14C, /* Int coalescing timeout */ + MVS_INT_STAT = 0x150, /* Central int status */ + MVS_INT_MASK = 0x154, /* Central int enable */ + MVS_INT_STAT_SRS_0 = 0x158, /* SATA register set status */ + MVS_INT_MASK_SRS_0 = 0x15C, + MVS_INT_STAT_SRS_1 = 0x160, + MVS_INT_MASK_SRS_1 = 0x164, + MVS_NON_NCQ_ERR_0 = 0x168, /* SRS Non-specific NCQ Error */ + MVS_NON_NCQ_ERR_1 = 0x16C, + MVS_CMD_ADDR = 0x170, /* Command register port (addr) */ + MVS_CMD_DATA = 0x174, /* Command register port (data) */ + MVS_MEM_PARITY_ERR = 0x178, /* Memory parity error */ + + /* ports 1-3 follow after this */ + MVS_P0_INT_STAT = 0x180, /* port0 interrupt status */ + MVS_P0_INT_MASK = 0x184, /* port0 interrupt mask */ + /* ports 5-7 follow after this */ + MVS_P4_INT_STAT = 0x1A0, /* Port4 interrupt status */ + MVS_P4_INT_MASK = 0x1A4, /* Port4 interrupt enable mask */ + + /* ports 1-3 follow after this */ + MVS_P0_SER_CTLSTAT = 0x1D0, /* port0 serial control/status */ + /* ports 5-7 follow after this */ + MVS_P4_SER_CTLSTAT = 0x1E0, /* port4 serial control/status */ + + /* ports 1-3 follow after this */ + MVS_P0_CFG_ADDR = 0x200, /* port0 phy register address */ + MVS_P0_CFG_DATA = 0x204, /* port0 phy register data */ + /* ports 5-7 follow after this */ + MVS_P4_CFG_ADDR = 0x220, /* Port4 config address */ + MVS_P4_CFG_DATA = 0x224, /* Port4 config data */ + + /* phys 1-3 follow after this */ + MVS_P0_VSR_ADDR = 0x250, /* phy0 VSR address */ + MVS_P0_VSR_DATA = 0x254, /* phy0 VSR data */ + /* phys 1-3 follow after this */ + /* multiplexing */ + MVS_P4_VSR_ADDR = 0x250, /* phy4 VSR address */ + MVS_P4_VSR_DATA = 0x254, /* phy4 VSR data */ + MVS_PA_VSR_ADDR = 0x290, /* All port VSR addr */ + MVS_PA_VSR_PORT = 0x294, /* All port VSR data */ +}; + +enum pci_cfg_registers { + PCR_PHY_CTL = 0x40, + PCR_PHY_CTL2 = 0x90, + PCR_DEV_CTRL = 0x78, + PCR_LINK_STAT = 0x82, +}; + +/* SAS/SATA Vendor Specific Port Registers */ +enum sas_sata_vsp_regs { + VSR_PHY_STAT = 0x00 * 4, /* Phy Status */ + VSR_PHY_MODE1 = 0x01 * 4, /* phy tx */ + VSR_PHY_MODE2 = 0x02 * 4, /* tx scc */ + VSR_PHY_MODE3 = 0x03 * 4, /* pll */ + VSR_PHY_MODE4 = 0x04 * 4, /* VCO */ + VSR_PHY_MODE5 = 0x05 * 4, /* Rx */ + VSR_PHY_MODE6 = 0x06 * 4, /* CDR */ + VSR_PHY_MODE7 = 0x07 * 4, /* Impedance */ + VSR_PHY_MODE8 = 0x08 * 4, /* Voltage */ + VSR_PHY_MODE9 = 0x09 * 4, /* Test */ + VSR_PHY_MODE10 = 0x0A * 4, /* Power */ + VSR_PHY_MODE11 = 0x0B * 4, /* Phy Mode */ + VSR_PHY_VS0 = 0x0C * 4, /* Vednor Specific 0 */ + VSR_PHY_VS1 = 0x0D * 4, /* Vednor Specific 1 */ +}; + +enum chip_register_bits { + PHY_MIN_SPP_PHYS_LINK_RATE_MASK = (0x7 << 8), + PHY_MAX_SPP_PHYS_LINK_RATE_MASK = (0x7 << 8), + PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET = (12), + PHY_NEG_SPP_PHYS_LINK_RATE_MASK = + (0x3 << PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET), +}; + +enum pci_interrupt_cause { + /* MAIN_IRQ_CAUSE (R10200) Bits*/ + IRQ_COM_IN_I2O_IOP0 = (1 << 0), + IRQ_COM_IN_I2O_IOP1 = (1 << 1), + IRQ_COM_IN_I2O_IOP2 = (1 << 2), + IRQ_COM_IN_I2O_IOP3 = (1 << 3), + IRQ_COM_OUT_I2O_HOS0 = (1 << 4), + IRQ_COM_OUT_I2O_HOS1 = (1 << 5), + IRQ_COM_OUT_I2O_HOS2 = (1 << 6), + IRQ_COM_OUT_I2O_HOS3 = (1 << 7), + IRQ_PCIF_TO_CPU_DRBL0 = (1 << 8), + IRQ_PCIF_TO_CPU_DRBL1 = (1 << 9), + IRQ_PCIF_TO_CPU_DRBL2 = (1 << 10), + IRQ_PCIF_TO_CPU_DRBL3 = (1 << 11), + IRQ_PCIF_DRBL0 = (1 << 12), + IRQ_PCIF_DRBL1 = (1 << 13), + IRQ_PCIF_DRBL2 = (1 << 14), + IRQ_PCIF_DRBL3 = (1 << 15), + IRQ_XOR_A = (1 << 16), + IRQ_XOR_B = (1 << 17), + IRQ_SAS_A = (1 << 18), + IRQ_SAS_B = (1 << 19), + IRQ_CPU_CNTRL = (1 << 20), + IRQ_GPIO = (1 << 21), + IRQ_UART = (1 << 22), + IRQ_SPI = (1 << 23), + IRQ_I2C = (1 << 24), + IRQ_SGPIO = (1 << 25), + IRQ_COM_ERR = (1 << 29), + IRQ_I2O_ERR = (1 << 30), + IRQ_PCIE_ERR = (1 << 31), +}; + +#define MAX_SG_ENTRY 255 + +struct mvs_prd_imt { + __le32 len:22; + u8 _r_a:2; + u8 misc_ctl:4; + u8 inter_sel:4; +}; + +struct mvs_prd { + /* 64-bit buffer address */ + __le64 addr; + /* 22-bit length */ + struct mvs_prd_imt im_len; +} __attribute__ ((packed)); + +#define SPI_CTRL_REG_94XX 0xc800 +#define SPI_ADDR_REG_94XX 0xc804 +#define SPI_WR_DATA_REG_94XX 0xc808 +#define SPI_RD_DATA_REG_94XX 0xc80c +#define SPI_CTRL_READ_94XX (1U << 2) +#define SPI_ADDR_VLD_94XX (1U << 1) +#define SPI_CTRL_SpiStart_94XX (1U << 0) + +#define mv_ffc(x) ffz(x) + +static inline int +mv_ffc64(u64 v) +{ + int i; + i = mv_ffc((u32)v); + if (i >= 0) + return i; + i = mv_ffc((u32)(v>>32)); + + if (i != 0) + return 32 + i; + + return -1; +} + +#define r_reg_set_enable(i) \ + (((i) > 31) ? mr32(MVS_STP_REG_SET_1) : \ + mr32(MVS_STP_REG_SET_0)) + +#define w_reg_set_enable(i, tmp) \ + (((i) > 31) ? mw32(MVS_STP_REG_SET_1, tmp) : \ + mw32(MVS_STP_REG_SET_0, tmp)) + +extern const struct mvs_dispatch mvs_94xx_dispatch; +#endif + diff --git a/drivers/scsi/mvsas/mv_chips.h b/drivers/scsi/mvsas/mv_chips.h new file mode 100644 index 000000000000..a67e1c4172f9 --- /dev/null +++ b/drivers/scsi/mvsas/mv_chips.h @@ -0,0 +1,280 @@ +/* + * Marvell 88SE64xx/88SE94xx register IO interface + * + * Copyright 2007 Red Hat, Inc. + * Copyright 2008 Marvell. + * + * This file is licensed under GPLv2. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2 of the + * License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA +*/ + + +#ifndef _MV_CHIPS_H_ +#define _MV_CHIPS_H_ + +#define mr32(reg) readl(regs + reg) +#define mw32(reg, val) writel((val), regs + reg) +#define mw32_f(reg, val) do { \ + mw32(reg, val); \ + mr32(reg); \ + } while (0) + +#define iow32(reg, val) outl(val, (unsigned long)(regs + reg)) +#define ior32(reg) inl((unsigned long)(regs + reg)) +#define iow16(reg, val) outw((unsigned long)(val, regs + reg)) +#define ior16(reg) inw((unsigned long)(regs + reg)) +#define iow8(reg, val) outb((unsigned long)(val, regs + reg)) +#define ior8(reg) inb((unsigned long)(regs + reg)) + +static inline u32 mvs_cr32(struct mvs_info *mvi, u32 addr) +{ + void __iomem *regs = mvi->regs; + mw32(MVS_CMD_ADDR, addr); + return mr32(MVS_CMD_DATA); +} + +static inline void mvs_cw32(struct mvs_info *mvi, u32 addr, u32 val) +{ + void __iomem *regs = mvi->regs; + mw32(MVS_CMD_ADDR, addr); + mw32(MVS_CMD_DATA, val); +} + +static inline u32 mvs_read_phy_ctl(struct mvs_info *mvi, u32 port) +{ + void __iomem *regs = mvi->regs; + return (port < 4) ? mr32(MVS_P0_SER_CTLSTAT + port * 4) : + mr32(MVS_P4_SER_CTLSTAT + (port - 4) * 4); +} + +static inline void mvs_write_phy_ctl(struct mvs_info *mvi, u32 port, u32 val) +{ + void __iomem *regs = mvi->regs; + if (port < 4) + mw32(MVS_P0_SER_CTLSTAT + port * 4, val); + else + mw32(MVS_P4_SER_CTLSTAT + (port - 4) * 4, val); +} + +static inline u32 mvs_read_port(struct mvs_info *mvi, u32 off, + u32 off2, u32 port) +{ + void __iomem *regs = mvi->regs + off; + void __iomem *regs2 = mvi->regs + off2; + return (port < 4) ? readl(regs + port * 8) : + readl(regs2 + (port - 4) * 8); +} + +static inline void mvs_write_port(struct mvs_info *mvi, u32 off, u32 off2, + u32 port, u32 val) +{ + void __iomem *regs = mvi->regs + off; + void __iomem *regs2 = mvi->regs + off2; + if (port < 4) + writel(val, regs + port * 8); + else + writel(val, regs2 + (port - 4) * 8); +} + +static inline u32 mvs_read_port_cfg_data(struct mvs_info *mvi, u32 port) +{ + return mvs_read_port(mvi, MVS_P0_CFG_DATA, + MVS_P4_CFG_DATA, port); +} + +static inline void mvs_write_port_cfg_data(struct mvs_info *mvi, + u32 port, u32 val) +{ + mvs_write_port(mvi, MVS_P0_CFG_DATA, + MVS_P4_CFG_DATA, port, val); +} + +static inline void mvs_write_port_cfg_addr(struct mvs_info *mvi, + u32 port, u32 addr) +{ + mvs_write_port(mvi, MVS_P0_CFG_ADDR, + MVS_P4_CFG_ADDR, port, addr); + mdelay(10); +} + +static inline u32 mvs_read_port_vsr_data(struct mvs_info *mvi, u32 port) +{ + return mvs_read_port(mvi, MVS_P0_VSR_DATA, + MVS_P4_VSR_DATA, port); +} + +static inline void mvs_write_port_vsr_data(struct mvs_info *mvi, + u32 port, u32 val) +{ + mvs_write_port(mvi, MVS_P0_VSR_DATA, + MVS_P4_VSR_DATA, port, val); +} + +static inline void mvs_write_port_vsr_addr(struct mvs_info *mvi, + u32 port, u32 addr) +{ + mvs_write_port(mvi, MVS_P0_VSR_ADDR, + MVS_P4_VSR_ADDR, port, addr); + mdelay(10); +} + +static inline u32 mvs_read_port_irq_stat(struct mvs_info *mvi, u32 port) +{ + return mvs_read_port(mvi, MVS_P0_INT_STAT, + MVS_P4_INT_STAT, port); +} + +static inline void mvs_write_port_irq_stat(struct mvs_info *mvi, + u32 port, u32 val) +{ + mvs_write_port(mvi, MVS_P0_INT_STAT, + MVS_P4_INT_STAT, port, val); +} + +static inline u32 mvs_read_port_irq_mask(struct mvs_info *mvi, u32 port) +{ + return mvs_read_port(mvi, MVS_P0_INT_MASK, + MVS_P4_INT_MASK, port); + +} + +static inline void mvs_write_port_irq_mask(struct mvs_info *mvi, + u32 port, u32 val) +{ + mvs_write_port(mvi, MVS_P0_INT_MASK, + MVS_P4_INT_MASK, port, val); +} + +static inline void __devinit mvs_phy_hacks(struct mvs_info *mvi) +{ + u32 tmp; + + /* workaround for SATA R-ERR, to ignore phy glitch */ + tmp = mvs_cr32(mvi, CMD_PHY_TIMER); + tmp &= ~(1 << 9); + tmp |= (1 << 10); + mvs_cw32(mvi, CMD_PHY_TIMER, tmp); + + /* enable retry 127 times */ + mvs_cw32(mvi, CMD_SAS_CTL1, 0x7f7f); + + /* extend open frame timeout to max */ + tmp = mvs_cr32(mvi, CMD_SAS_CTL0); + tmp &= ~0xffff; + tmp |= 0x3fff; + mvs_cw32(mvi, CMD_SAS_CTL0, tmp); + + /* workaround for WDTIMEOUT , set to 550 ms */ + mvs_cw32(mvi, CMD_WD_TIMER, 0x7a0000); + + /* not to halt for different port op during wideport link change */ + mvs_cw32(mvi, CMD_APP_ERR_CONFIG, 0xffefbf7d); + + /* workaround for Seagate disk not-found OOB sequence, recv + * COMINIT before sending out COMWAKE */ + tmp = mvs_cr32(mvi, CMD_PHY_MODE_21); + tmp &= 0x0000ffff; + tmp |= 0x00fa0000; + mvs_cw32(mvi, CMD_PHY_MODE_21, tmp); + + tmp = mvs_cr32(mvi, CMD_PHY_TIMER); + tmp &= 0x1fffffff; + tmp |= (2U << 29); /* 8 ms retry */ + mvs_cw32(mvi, CMD_PHY_TIMER, tmp); +} + +static inline void mvs_int_sata(struct mvs_info *mvi) +{ + u32 tmp; + void __iomem *regs = mvi->regs; + tmp = mr32(MVS_INT_STAT_SRS_0); + if (tmp) + mw32(MVS_INT_STAT_SRS_0, tmp); + MVS_CHIP_DISP->clear_active_cmds(mvi); +} + +static inline void mvs_int_full(struct mvs_info *mvi) +{ + void __iomem *regs = mvi->regs; + u32 tmp, stat; + int i; + + stat = mr32(MVS_INT_STAT); + mvs_int_rx(mvi, false); + + for (i = 0; i < mvi->chip->n_phy; i++) { + tmp = (stat >> i) & (CINT_PORT | CINT_PORT_STOPPED); + if (tmp) + mvs_int_port(mvi, i, tmp); + } + + if (stat & CINT_SRS) + mvs_int_sata(mvi); + + mw32(MVS_INT_STAT, stat); +} + +static inline void mvs_start_delivery(struct mvs_info *mvi, u32 tx) +{ + void __iomem *regs = mvi->regs; + mw32(MVS_TX_PROD_IDX, tx); +} + +static inline u32 mvs_rx_update(struct mvs_info *mvi) +{ + void __iomem *regs = mvi->regs; + return mr32(MVS_RX_CONS_IDX); +} + +static inline u32 mvs_get_prd_size(void) +{ + return sizeof(struct mvs_prd); +} + +static inline u32 mvs_get_prd_count(void) +{ + return MAX_SG_ENTRY; +} + +static inline void mvs_show_pcie_usage(struct mvs_info *mvi) +{ + u16 link_stat, link_spd; + const char *spd[] = { + "UnKnown", + "2.5", + "5.0", + }; + if (mvi->flags & MVF_FLAG_SOC || mvi->id > 0) + return; + + pci_read_config_word(mvi->pdev, PCR_LINK_STAT, &link_stat); + link_spd = (link_stat & PLS_LINK_SPD) >> PLS_LINK_SPD_OFFS; + if (link_spd >= 3) + link_spd = 0; + dev_printk(KERN_INFO, mvi->dev, + "mvsas: PCI-E x%u, Bandwidth Usage: %s Gbps\n", + (link_stat & PLS_NEG_LINK_WD) >> PLS_NEG_LINK_WD_OFFS, + spd[link_spd]); +} + +static inline u32 mvs_hw_max_link_rate(void) +{ + return MAX_LINK_RATE; +} + +#endif /* _MV_CHIPS_H_ */ + diff --git a/drivers/scsi/mvsas/mv_defs.h b/drivers/scsi/mvsas/mv_defs.h new file mode 100644 index 000000000000..f8cb9defb961 --- /dev/null +++ b/drivers/scsi/mvsas/mv_defs.h @@ -0,0 +1,502 @@ +/* + * Marvell 88SE64xx/88SE94xx const head file + * + * Copyright 2007 Red Hat, Inc. + * Copyright 2008 Marvell. + * + * This file is licensed under GPLv2. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2 of the + * License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA +*/ + +#ifndef _MV_DEFS_H_ +#define _MV_DEFS_H_ + + +enum chip_flavors { + chip_6320, + chip_6440, + chip_6485, + chip_9480, + chip_9180, +}; + +/* driver compile-time configuration */ +enum driver_configuration { + MVS_SLOTS = 512, /* command slots */ + MVS_TX_RING_SZ = 1024, /* TX ring size (12-bit) */ + MVS_RX_RING_SZ = 1024, /* RX ring size (12-bit) */ + /* software requires power-of-2 + ring size */ + MVS_SOC_SLOTS = 64, + MVS_SOC_TX_RING_SZ = MVS_SOC_SLOTS * 2, + MVS_SOC_RX_RING_SZ = MVS_SOC_SLOTS * 2, + + MVS_SLOT_BUF_SZ = 8192, /* cmd tbl + IU + status + PRD */ + MVS_SSP_CMD_SZ = 64, /* SSP command table buffer size */ + MVS_ATA_CMD_SZ = 96, /* SATA command table buffer size */ + MVS_OAF_SZ = 64, /* Open address frame buffer size */ + MVS_QUEUE_SIZE = 32, /* Support Queue depth */ + MVS_CAN_QUEUE = MVS_SLOTS - 2, /* SCSI Queue depth */ + MVS_SOC_CAN_QUEUE = MVS_SOC_SLOTS - 2, +}; + +/* unchangeable hardware details */ +enum hardware_details { + MVS_MAX_PHYS = 8, /* max. possible phys */ + MVS_MAX_PORTS = 8, /* max. possible ports */ + MVS_SOC_PHYS = 4, /* soc phys */ + MVS_SOC_PORTS = 4, /* soc phys */ + MVS_MAX_DEVICES = 1024, /* max supported device */ +}; + +/* peripheral registers (BAR2) */ +enum peripheral_registers { + SPI_CTL = 0x10, /* EEPROM control */ + SPI_CMD = 0x14, /* EEPROM command */ + SPI_DATA = 0x18, /* EEPROM data */ +}; + +enum peripheral_register_bits { + TWSI_RDY = (1U << 7), /* EEPROM interface ready */ + TWSI_RD = (1U << 4), /* EEPROM read access */ + + SPI_ADDR_MASK = 0x3ffff, /* bits 17:0 */ +}; + +enum hw_register_bits { + /* MVS_GBL_CTL */ + INT_EN = (1U << 1), /* Global int enable */ + HBA_RST = (1U << 0), /* HBA reset */ + + /* MVS_GBL_INT_STAT */ + INT_XOR = (1U << 4), /* XOR engine event */ + INT_SAS_SATA = (1U << 0), /* SAS/SATA event */ + + /* MVS_GBL_PORT_TYPE */ /* shl for ports 1-3 */ + SATA_TARGET = (1U << 16), /* port0 SATA target enable */ + MODE_AUTO_DET_PORT7 = (1U << 15), /* port0 SAS/SATA autodetect */ + MODE_AUTO_DET_PORT6 = (1U << 14), + MODE_AUTO_DET_PORT5 = (1U << 13), + MODE_AUTO_DET_PORT4 = (1U << 12), + MODE_AUTO_DET_PORT3 = (1U << 11), + MODE_AUTO_DET_PORT2 = (1U << 10), + MODE_AUTO_DET_PORT1 = (1U << 9), + MODE_AUTO_DET_PORT0 = (1U << 8), + MODE_AUTO_DET_EN = MODE_AUTO_DET_PORT0 | MODE_AUTO_DET_PORT1 | + MODE_AUTO_DET_PORT2 | MODE_AUTO_DET_PORT3 | + MODE_AUTO_DET_PORT4 | MODE_AUTO_DET_PORT5 | + MODE_AUTO_DET_PORT6 | MODE_AUTO_DET_PORT7, + MODE_SAS_PORT7_MASK = (1U << 7), /* port0 SAS(1), SATA(0) mode */ + MODE_SAS_PORT6_MASK = (1U << 6), + MODE_SAS_PORT5_MASK = (1U << 5), + MODE_SAS_PORT4_MASK = (1U << 4), + MODE_SAS_PORT3_MASK = (1U << 3), + MODE_SAS_PORT2_MASK = (1U << 2), + MODE_SAS_PORT1_MASK = (1U << 1), + MODE_SAS_PORT0_MASK = (1U << 0), + MODE_SAS_SATA = MODE_SAS_PORT0_MASK | MODE_SAS_PORT1_MASK | + MODE_SAS_PORT2_MASK | MODE_SAS_PORT3_MASK | + MODE_SAS_PORT4_MASK | MODE_SAS_PORT5_MASK | + MODE_SAS_PORT6_MASK | MODE_SAS_PORT7_MASK, + + /* SAS_MODE value may be + * dictated (in hw) by values + * of SATA_TARGET & AUTO_DET + */ + + /* MVS_TX_CFG */ + TX_EN = (1U << 16), /* Enable TX */ + TX_RING_SZ_MASK = 0xfff, /* TX ring size, bits 11:0 */ + + /* MVS_RX_CFG */ + RX_EN = (1U << 16), /* Enable RX */ + RX_RING_SZ_MASK = 0xfff, /* RX ring size, bits 11:0 */ + + /* MVS_INT_COAL */ + COAL_EN = (1U << 16), /* Enable int coalescing */ + + /* MVS_INT_STAT, MVS_INT_MASK */ + CINT_I2C = (1U << 31), /* I2C event */ + CINT_SW0 = (1U << 30), /* software event 0 */ + CINT_SW1 = (1U << 29), /* software event 1 */ + CINT_PRD_BC = (1U << 28), /* PRD BC err for read cmd */ + CINT_DMA_PCIE = (1U << 27), /* DMA to PCIE timeout */ + CINT_MEM = (1U << 26), /* int mem parity err */ + CINT_I2C_SLAVE = (1U << 25), /* slave I2C event */ + CINT_SRS = (1U << 3), /* SRS event */ + CINT_CI_STOP = (1U << 1), /* cmd issue stopped */ + CINT_DONE = (1U << 0), /* cmd completion */ + + /* shl for ports 1-3 */ + CINT_PORT_STOPPED = (1U << 16), /* port0 stopped */ + CINT_PORT = (1U << 8), /* port0 event */ + CINT_PORT_MASK_OFFSET = 8, + CINT_PORT_MASK = (0xFF << CINT_PORT_MASK_OFFSET), + CINT_PHY_MASK_OFFSET = 4, + CINT_PHY_MASK = (0x0F << CINT_PHY_MASK_OFFSET), + + /* TX (delivery) ring bits */ + TXQ_CMD_SHIFT = 29, + TXQ_CMD_SSP = 1, /* SSP protocol */ + TXQ_CMD_SMP = 2, /* SMP protocol */ + TXQ_CMD_STP = 3, /* STP/SATA protocol */ + TXQ_CMD_SSP_FREE_LIST = 4, /* add to SSP targ free list */ + TXQ_CMD_SLOT_RESET = 7, /* reset command slot */ + TXQ_MODE_I = (1U << 28), /* mode: 0=target,1=initiator */ + TXQ_MODE_TARGET = 0, + TXQ_MODE_INITIATOR = 1, + TXQ_PRIO_HI = (1U << 27), /* priority: 0=normal, 1=high */ + TXQ_PRI_NORMAL = 0, + TXQ_PRI_HIGH = 1, + TXQ_SRS_SHIFT = 20, /* SATA register set */ + TXQ_SRS_MASK = 0x7f, + TXQ_PHY_SHIFT = 12, /* PHY bitmap */ + TXQ_PHY_MASK = 0xff, + TXQ_SLOT_MASK = 0xfff, /* slot number */ + + /* RX (completion) ring bits */ + RXQ_GOOD = (1U << 23), /* Response good */ + RXQ_SLOT_RESET = (1U << 21), /* Slot reset complete */ + RXQ_CMD_RX = (1U << 20), /* target cmd received */ + RXQ_ATTN = (1U << 19), /* attention */ + RXQ_RSP = (1U << 18), /* response frame xfer'd */ + RXQ_ERR = (1U << 17), /* err info rec xfer'd */ + RXQ_DONE = (1U << 16), /* cmd complete */ + RXQ_SLOT_MASK = 0xfff, /* slot number */ + + /* mvs_cmd_hdr bits */ + MCH_PRD_LEN_SHIFT = 16, /* 16-bit PRD table len */ + MCH_SSP_FR_TYPE_SHIFT = 13, /* SSP frame type */ + + /* SSP initiator only */ + MCH_SSP_FR_CMD = 0x0, /* COMMAND frame */ + + /* SSP initiator or target */ + MCH_SSP_FR_TASK = 0x1, /* TASK frame */ + + /* SSP target only */ + MCH_SSP_FR_XFER_RDY = 0x4, /* XFER_RDY frame */ + MCH_SSP_FR_RESP = 0x5, /* RESPONSE frame */ + MCH_SSP_FR_READ = 0x6, /* Read DATA frame(s) */ + MCH_SSP_FR_READ_RESP = 0x7, /* ditto, plus RESPONSE */ + + MCH_SSP_MODE_PASSTHRU = 1, + MCH_SSP_MODE_NORMAL = 0, + MCH_PASSTHRU = (1U << 12), /* pass-through (SSP) */ + MCH_FBURST = (1U << 11), /* first burst (SSP) */ + MCH_CHK_LEN = (1U << 10), /* chk xfer len (SSP) */ + MCH_RETRY = (1U << 9), /* tport layer retry (SSP) */ + MCH_PROTECTION = (1U << 8), /* protection info rec (SSP) */ + MCH_RESET = (1U << 7), /* Reset (STP/SATA) */ + MCH_FPDMA = (1U << 6), /* First party DMA (STP/SATA) */ + MCH_ATAPI = (1U << 5), /* ATAPI (STP/SATA) */ + MCH_BIST = (1U << 4), /* BIST activate (STP/SATA) */ + MCH_PMP_MASK = 0xf, /* PMP from cmd FIS (STP/SATA)*/ + + CCTL_RST = (1U << 5), /* port logic reset */ + + /* 0(LSB first), 1(MSB first) */ + CCTL_ENDIAN_DATA = (1U << 3), /* PRD data */ + CCTL_ENDIAN_RSP = (1U << 2), /* response frame */ + CCTL_ENDIAN_OPEN = (1U << 1), /* open address frame */ + CCTL_ENDIAN_CMD = (1U << 0), /* command table */ + + /* MVS_Px_SER_CTLSTAT (per-phy control) */ + PHY_SSP_RST = (1U << 3), /* reset SSP link layer */ + PHY_BCAST_CHG = (1U << 2), /* broadcast(change) notif */ + PHY_RST_HARD = (1U << 1), /* hard reset + phy reset */ + PHY_RST = (1U << 0), /* phy reset */ + PHY_READY_MASK = (1U << 20), + + /* MVS_Px_INT_STAT, MVS_Px_INT_MASK (per-phy events) */ + PHYEV_DEC_ERR = (1U << 24), /* Phy Decoding Error */ + PHYEV_DCDR_ERR = (1U << 23), /* STP Deocder Error */ + PHYEV_CRC_ERR = (1U << 22), /* STP CRC Error */ + PHYEV_UNASSOC_FIS = (1U << 19), /* unassociated FIS rx'd */ + PHYEV_AN = (1U << 18), /* SATA async notification */ + PHYEV_BIST_ACT = (1U << 17), /* BIST activate FIS */ + PHYEV_SIG_FIS = (1U << 16), /* signature FIS */ + PHYEV_POOF = (1U << 12), /* phy ready from 1 -> 0 */ + PHYEV_IU_BIG = (1U << 11), /* IU too long err */ + PHYEV_IU_SMALL = (1U << 10), /* IU too short err */ + PHYEV_UNK_TAG = (1U << 9), /* unknown tag */ + PHYEV_BROAD_CH = (1U << 8), /* broadcast(CHANGE) */ + PHYEV_COMWAKE = (1U << 7), /* COMWAKE rx'd */ + PHYEV_PORT_SEL = (1U << 6), /* port selector present */ + PHYEV_HARD_RST = (1U << 5), /* hard reset rx'd */ + PHYEV_ID_TMOUT = (1U << 4), /* identify timeout */ + PHYEV_ID_FAIL = (1U << 3), /* identify failed */ + PHYEV_ID_DONE = (1U << 2), /* identify done */ + PHYEV_HARD_RST_DONE = (1U << 1), /* hard reset done */ + PHYEV_RDY_CH = (1U << 0), /* phy ready changed state */ + + /* MVS_PCS */ + PCS_EN_SATA_REG_SHIFT = (16), /* Enable SATA Register Set */ + PCS_EN_PORT_XMT_SHIFT = (12), /* Enable Port Transmit */ + PCS_EN_PORT_XMT_SHIFT2 = (8), /* For 6485 */ + PCS_SATA_RETRY = (1U << 8), /* retry ctl FIS on R_ERR */ + PCS_RSP_RX_EN = (1U << 7), /* raw response rx */ + PCS_SATA_RETRY_2 = (1U << 6), /* For 9180 */ + PCS_SELF_CLEAR = (1U << 5), /* self-clearing int mode */ + PCS_FIS_RX_EN = (1U << 4), /* FIS rx enable */ + PCS_CMD_STOP_ERR = (1U << 3), /* cmd stop-on-err enable */ + PCS_CMD_RST = (1U << 1), /* reset cmd issue */ + PCS_CMD_EN = (1U << 0), /* enable cmd issue */ + + /* Port n Attached Device Info */ + PORT_DEV_SSP_TRGT = (1U << 19), + PORT_DEV_SMP_TRGT = (1U << 18), + PORT_DEV_STP_TRGT = (1U << 17), + PORT_DEV_SSP_INIT = (1U << 11), + PORT_DEV_SMP_INIT = (1U << 10), + PORT_DEV_STP_INIT = (1U << 9), + PORT_PHY_ID_MASK = (0xFFU << 24), + PORT_SSP_TRGT_MASK = (0x1U << 19), + PORT_SSP_INIT_MASK = (0x1U << 11), + PORT_DEV_TRGT_MASK = (0x7U << 17), + PORT_DEV_INIT_MASK = (0x7U << 9), + PORT_DEV_TYPE_MASK = (0x7U << 0), + + /* Port n PHY Status */ + PHY_RDY = (1U << 2), + PHY_DW_SYNC = (1U << 1), + PHY_OOB_DTCTD = (1U << 0), + + /* VSR */ + /* PHYMODE 6 (CDB) */ + PHY_MODE6_LATECLK = (1U << 29), /* Lock Clock */ + PHY_MODE6_DTL_SPEED = (1U << 27), /* Digital Loop Speed */ + PHY_MODE6_FC_ORDER = (1U << 26), /* Fibre Channel Mode Order*/ + PHY_MODE6_MUCNT_EN = (1U << 24), /* u Count Enable */ + PHY_MODE6_SEL_MUCNT_LEN = (1U << 22), /* Training Length Select */ + PHY_MODE6_SELMUPI = (1U << 20), /* Phase Multi Select (init) */ + PHY_MODE6_SELMUPF = (1U << 18), /* Phase Multi Select (final) */ + PHY_MODE6_SELMUFF = (1U << 16), /* Freq Loop Multi Sel(final) */ + PHY_MODE6_SELMUFI = (1U << 14), /* Freq Loop Multi Sel(init) */ + PHY_MODE6_FREEZE_LOOP = (1U << 12), /* Freeze Rx CDR Loop */ + PHY_MODE6_INT_RXFOFFS = (1U << 3), /* Rx CDR Freq Loop Enable */ + PHY_MODE6_FRC_RXFOFFS = (1U << 2), /* Initial Rx CDR Offset */ + PHY_MODE6_STAU_0D8 = (1U << 1), /* Rx CDR Freq Loop Saturate */ + PHY_MODE6_RXSAT_DIS = (1U << 0), /* Saturate Ctl */ +}; + +/* SAS/SATA configuration port registers, aka phy registers */ +enum sas_sata_config_port_regs { + PHYR_IDENTIFY = 0x00, /* info for IDENTIFY frame */ + PHYR_ADDR_LO = 0x04, /* my SAS address (low) */ + PHYR_ADDR_HI = 0x08, /* my SAS address (high) */ + PHYR_ATT_DEV_INFO = 0x0C, /* attached device info */ + PHYR_ATT_ADDR_LO = 0x10, /* attached dev SAS addr (low) */ + PHYR_ATT_ADDR_HI = 0x14, /* attached dev SAS addr (high) */ + PHYR_SATA_CTL = 0x18, /* SATA control */ + PHYR_PHY_STAT = 0x1C, /* PHY status */ + PHYR_SATA_SIG0 = 0x20, /*port SATA signature FIS(Byte 0-3) */ + PHYR_SATA_SIG1 = 0x24, /*port SATA signature FIS(Byte 4-7) */ + PHYR_SATA_SIG2 = 0x28, /*port SATA signature FIS(Byte 8-11) */ + PHYR_SATA_SIG3 = 0x2c, /*port SATA signature FIS(Byte 12-15) */ + PHYR_R_ERR_COUNT = 0x30, /* port R_ERR count register */ + PHYR_CRC_ERR_COUNT = 0x34, /* port CRC error count register */ + PHYR_WIDE_PORT = 0x38, /* wide port participating */ + PHYR_CURRENT0 = 0x80, /* current connection info 0 */ + PHYR_CURRENT1 = 0x84, /* current connection info 1 */ + PHYR_CURRENT2 = 0x88, /* current connection info 2 */ + CONFIG_ID_FRAME0 = 0x100, /* Port device ID frame register 0 */ + CONFIG_ID_FRAME1 = 0x104, /* Port device ID frame register 1 */ + CONFIG_ID_FRAME2 = 0x108, /* Port device ID frame register 2 */ + CONFIG_ID_FRAME3 = 0x10c, /* Port device ID frame register 3 */ + CONFIG_ID_FRAME4 = 0x110, /* Port device ID frame register 4 */ + CONFIG_ID_FRAME5 = 0x114, /* Port device ID frame register 5 */ + CONFIG_ID_FRAME6 = 0x118, /* Port device ID frame register 6 */ + CONFIG_ATT_ID_FRAME0 = 0x11c, /* attached ID frame register 0 */ + CONFIG_ATT_ID_FRAME1 = 0x120, /* attached ID frame register 1 */ + CONFIG_ATT_ID_FRAME2 = 0x124, /* attached ID frame register 2 */ + CONFIG_ATT_ID_FRAME3 = 0x128, /* attached ID frame register 3 */ + CONFIG_ATT_ID_FRAME4 = 0x12c, /* attached ID frame register 4 */ + CONFIG_ATT_ID_FRAME5 = 0x130, /* attached ID frame register 5 */ + CONFIG_ATT_ID_FRAME6 = 0x134, /* attached ID frame register 6 */ +}; + +enum sas_cmd_port_registers { + CMD_CMRST_OOB_DET = 0x100, /* COMRESET OOB detect register */ + CMD_CMWK_OOB_DET = 0x104, /* COMWAKE OOB detect register */ + CMD_CMSAS_OOB_DET = 0x108, /* COMSAS OOB detect register */ + CMD_BRST_OOB_DET = 0x10c, /* burst OOB detect register */ + CMD_OOB_SPACE = 0x110, /* OOB space control register */ + CMD_OOB_BURST = 0x114, /* OOB burst control register */ + CMD_PHY_TIMER = 0x118, /* PHY timer control register */ + CMD_PHY_CONFIG0 = 0x11c, /* PHY config register 0 */ + CMD_PHY_CONFIG1 = 0x120, /* PHY config register 1 */ + CMD_SAS_CTL0 = 0x124, /* SAS control register 0 */ + CMD_SAS_CTL1 = 0x128, /* SAS control register 1 */ + CMD_SAS_CTL2 = 0x12c, /* SAS control register 2 */ + CMD_SAS_CTL3 = 0x130, /* SAS control register 3 */ + CMD_ID_TEST = 0x134, /* ID test register */ + CMD_PL_TIMER = 0x138, /* PL timer register */ + CMD_WD_TIMER = 0x13c, /* WD timer register */ + CMD_PORT_SEL_COUNT = 0x140, /* port selector count register */ + CMD_APP_MEM_CTL = 0x144, /* Application Memory Control */ + CMD_XOR_MEM_CTL = 0x148, /* XOR Block Memory Control */ + CMD_DMA_MEM_CTL = 0x14c, /* DMA Block Memory Control */ + CMD_PORT_MEM_CTL0 = 0x150, /* Port Memory Control 0 */ + CMD_PORT_MEM_CTL1 = 0x154, /* Port Memory Control 1 */ + CMD_SATA_PORT_MEM_CTL0 = 0x158, /* SATA Port Memory Control 0 */ + CMD_SATA_PORT_MEM_CTL1 = 0x15c, /* SATA Port Memory Control 1 */ + CMD_XOR_MEM_BIST_CTL = 0x160, /* XOR Memory BIST Control */ + CMD_XOR_MEM_BIST_STAT = 0x164, /* XOR Memroy BIST Status */ + CMD_DMA_MEM_BIST_CTL = 0x168, /* DMA Memory BIST Control */ + CMD_DMA_MEM_BIST_STAT = 0x16c, /* DMA Memory BIST Status */ + CMD_PORT_MEM_BIST_CTL = 0x170, /* Port Memory BIST Control */ + CMD_PORT_MEM_BIST_STAT0 = 0x174, /* Port Memory BIST Status 0 */ + CMD_PORT_MEM_BIST_STAT1 = 0x178, /* Port Memory BIST Status 1 */ + CMD_STP_MEM_BIST_CTL = 0x17c, /* STP Memory BIST Control */ + CMD_STP_MEM_BIST_STAT0 = 0x180, /* STP Memory BIST Status 0 */ + CMD_STP_MEM_BIST_STAT1 = 0x184, /* STP Memory BIST Status 1 */ + CMD_RESET_COUNT = 0x188, /* Reset Count */ + CMD_MONTR_DATA_SEL = 0x18C, /* Monitor Data/Select */ + CMD_PLL_PHY_CONFIG = 0x190, /* PLL/PHY Configuration */ + CMD_PHY_CTL = 0x194, /* PHY Control and Status */ + CMD_PHY_TEST_COUNT0 = 0x198, /* Phy Test Count 0 */ + CMD_PHY_TEST_COUNT1 = 0x19C, /* Phy Test Count 1 */ + CMD_PHY_TEST_COUNT2 = 0x1A0, /* Phy Test Count 2 */ + CMD_APP_ERR_CONFIG = 0x1A4, /* Application Error Configuration */ + CMD_PND_FIFO_CTL0 = 0x1A8, /* Pending FIFO Control 0 */ + CMD_HOST_CTL = 0x1AC, /* Host Control Status */ + CMD_HOST_WR_DATA = 0x1B0, /* Host Write Data */ + CMD_HOST_RD_DATA = 0x1B4, /* Host Read Data */ + CMD_PHY_MODE_21 = 0x1B8, /* Phy Mode 21 */ + CMD_SL_MODE0 = 0x1BC, /* SL Mode 0 */ + CMD_SL_MODE1 = 0x1C0, /* SL Mode 1 */ + CMD_PND_FIFO_CTL1 = 0x1C4, /* Pending FIFO Control 1 */ +}; + +enum mvs_info_flags { + MVF_MSI = (1U << 0), /* MSI is enabled */ + MVF_PHY_PWR_FIX = (1U << 1), /* bug workaround */ + MVF_FLAG_SOC = (1U << 2), /* SoC integrated controllers */ +}; + +enum mvs_event_flags { + PHY_PLUG_EVENT = (3U), + PHY_PLUG_IN = (1U << 0), /* phy plug in */ + PHY_PLUG_OUT = (1U << 1), /* phy plug out */ +}; + +enum mvs_port_type { + PORT_TGT_MASK = (1U << 5), + PORT_INIT_PORT = (1U << 4), + PORT_TGT_PORT = (1U << 3), + PORT_INIT_TGT_PORT = (PORT_INIT_PORT | PORT_TGT_PORT), + PORT_TYPE_SAS = (1U << 1), + PORT_TYPE_SATA = (1U << 0), +}; + +/* Command Table Format */ +enum ct_format { + /* SSP */ + SSP_F_H = 0x00, + SSP_F_IU = 0x18, + SSP_F_MAX = 0x4D, + /* STP */ + STP_CMD_FIS = 0x00, + STP_ATAPI_CMD = 0x40, + STP_F_MAX = 0x10, + /* SMP */ + SMP_F_T = 0x00, + SMP_F_DEP = 0x01, + SMP_F_MAX = 0x101, +}; + +enum status_buffer { + SB_EIR_OFF = 0x00, /* Error Information Record */ + SB_RFB_OFF = 0x08, /* Response Frame Buffer */ + SB_RFB_MAX = 0x400, /* RFB size*/ +}; + +enum error_info_rec { + CMD_ISS_STPD = (1U << 31), /* Cmd Issue Stopped */ + CMD_PI_ERR = (1U << 30), /* Protection info error. see flags2 */ + RSP_OVER = (1U << 29), /* rsp buffer overflow */ + RETRY_LIM = (1U << 28), /* FIS/frame retry limit exceeded */ + UNK_FIS = (1U << 27), /* unknown FIS */ + DMA_TERM = (1U << 26), /* DMA terminate primitive rx'd */ + SYNC_ERR = (1U << 25), /* SYNC rx'd during frame xmit */ + TFILE_ERR = (1U << 24), /* SATA taskfile Error bit set */ + R_ERR = (1U << 23), /* SATA returned R_ERR prim */ + RD_OFS = (1U << 20), /* Read DATA frame invalid offset */ + XFER_RDY_OFS = (1U << 19), /* XFER_RDY offset error */ + UNEXP_XFER_RDY = (1U << 18), /* unexpected XFER_RDY error */ + DATA_OVER_UNDER = (1U << 16), /* data overflow/underflow */ + INTERLOCK = (1U << 15), /* interlock error */ + NAK = (1U << 14), /* NAK rx'd */ + ACK_NAK_TO = (1U << 13), /* ACK/NAK timeout */ + CXN_CLOSED = (1U << 12), /* cxn closed w/out ack/nak */ + OPEN_TO = (1U << 11), /* I_T nexus lost, open cxn timeout */ + PATH_BLOCKED = (1U << 10), /* I_T nexus lost, pathway blocked */ + NO_DEST = (1U << 9), /* I_T nexus lost, no destination */ + STP_RES_BSY = (1U << 8), /* STP resources busy */ + BREAK = (1U << 7), /* break received */ + BAD_DEST = (1U << 6), /* bad destination */ + BAD_PROTO = (1U << 5), /* protocol not supported */ + BAD_RATE = (1U << 4), /* cxn rate not supported */ + WRONG_DEST = (1U << 3), /* wrong destination error */ + CREDIT_TO = (1U << 2), /* credit timeout */ + WDOG_TO = (1U << 1), /* watchdog timeout */ + BUF_PAR = (1U << 0), /* buffer parity error */ +}; + +enum error_info_rec_2 { + SLOT_BSY_ERR = (1U << 31), /* Slot Busy Error */ + GRD_CHK_ERR = (1U << 14), /* Guard Check Error */ + APP_CHK_ERR = (1U << 13), /* Application Check error */ + REF_CHK_ERR = (1U << 12), /* Reference Check Error */ + USR_BLK_NM = (1U << 0), /* User Block Number */ +}; + +enum pci_cfg_register_bits { + PCTL_PWR_OFF = (0xFU << 24), + PCTL_COM_ON = (0xFU << 20), + PCTL_LINK_RST = (0xFU << 16), + PCTL_LINK_OFFS = (16), + PCTL_PHY_DSBL = (0xFU << 12), + PCTL_PHY_DSBL_OFFS = (12), + PRD_REQ_SIZE = (0x4000), + PRD_REQ_MASK = (0x00007000), + PLS_NEG_LINK_WD = (0x3FU << 4), + PLS_NEG_LINK_WD_OFFS = 4, + PLS_LINK_SPD = (0x0FU << 0), + PLS_LINK_SPD_OFFS = 0, +}; + +enum open_frame_protocol { + PROTOCOL_SMP = 0x0, + PROTOCOL_SSP = 0x1, + PROTOCOL_STP = 0x2, +}; + +/* define for response frame datapres field */ +enum datapres_field { + NO_DATA = 0, + RESPONSE_DATA = 1, + SENSE_DATA = 2, +}; + +/* define task management IU */ +struct mvs_tmf_task{ + u8 tmf; + u16 tag_of_task_to_be_managed; +}; +#endif diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c new file mode 100644 index 000000000000..8646a19f999d --- /dev/null +++ b/drivers/scsi/mvsas/mv_init.c @@ -0,0 +1,703 @@ +/* + * Marvell 88SE64xx/88SE94xx pci init + * + * Copyright 2007 Red Hat, Inc. + * Copyright 2008 Marvell. + * + * This file is licensed under GPLv2. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2 of the + * License. + * + * 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 "mv_sas.h" + +static struct scsi_transport_template *mvs_stt; +static const struct mvs_chip_info mvs_chips[] = { + [chip_6320] = { 1, 2, 0x400, 17, 16, 9, &mvs_64xx_dispatch, }, + [chip_6440] = { 1, 4, 0x400, 17, 16, 9, &mvs_64xx_dispatch, }, + [chip_6485] = { 1, 8, 0x800, 33, 32, 10, &mvs_64xx_dispatch, }, + [chip_9180] = { 2, 4, 0x800, 17, 64, 9, &mvs_94xx_dispatch, }, + [chip_9480] = { 2, 4, 0x800, 17, 64, 9, &mvs_94xx_dispatch, }, +}; + +#define SOC_SAS_NUM 2 + +static struct scsi_host_template mvs_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .queuecommand = sas_queuecommand, + .target_alloc = sas_target_alloc, + .slave_configure = mvs_slave_configure, + .slave_destroy = sas_slave_destroy, + .scan_finished = mvs_scan_finished, + .scan_start = mvs_scan_start, + .change_queue_depth = sas_change_queue_depth, + .change_queue_type = sas_change_queue_type, + .bios_param = sas_bios_param, + .can_queue = 1, + .cmd_per_lun = 1, + .this_id = -1, + .sg_tablesize = SG_ALL, + .max_sectors = SCSI_DEFAULT_MAX_SECTORS, + .use_clustering = ENABLE_CLUSTERING, + .eh_device_reset_handler = sas_eh_device_reset_handler, + .eh_bus_reset_handler = sas_eh_bus_reset_handler, + .slave_alloc = mvs_slave_alloc, + .target_destroy = sas_target_destroy, + .ioctl = sas_ioctl, +}; + +static struct sas_domain_function_template mvs_transport_ops = { + .lldd_dev_found = mvs_dev_found, + .lldd_dev_gone = mvs_dev_gone, + + .lldd_execute_task = mvs_queue_command, + .lldd_control_phy = mvs_phy_control, + + .lldd_abort_task = mvs_abort_task, + .lldd_abort_task_set = mvs_abort_task_set, + .lldd_clear_aca = mvs_clear_aca, + .lldd_clear_task_set = mvs_clear_task_set, + .lldd_I_T_nexus_reset = mvs_I_T_nexus_reset, + .lldd_lu_reset = mvs_lu_reset, + .lldd_query_task = mvs_query_task, + + .lldd_port_formed = mvs_port_formed, + .lldd_port_deformed = mvs_port_deformed, + +}; + +static void __devinit mvs_phy_init(struct mvs_info *mvi, int phy_id) +{ + struct mvs_phy *phy = &mvi->phy[phy_id]; + struct asd_sas_phy *sas_phy = &phy->sas_phy; + + phy->mvi = mvi; + init_timer(&phy->timer); + sas_phy->enabled = (phy_id < mvi->chip->n_phy) ? 1 : 0; + sas_phy->class = SAS; + sas_phy->iproto = SAS_PROTOCOL_ALL; + sas_phy->tproto = 0; + sas_phy->type = PHY_TYPE_PHYSICAL; + sas_phy->role = PHY_ROLE_INITIATOR; + sas_phy->oob_mode = OOB_NOT_CONNECTED; + sas_phy->linkrate = SAS_LINK_RATE_UNKNOWN; + + sas_phy->id = phy_id; + sas_phy->sas_addr = &mvi->sas_addr[0]; + sas_phy->frame_rcvd = &phy->frame_rcvd[0]; + sas_phy->ha = (struct sas_ha_struct *)mvi->shost->hostdata; + sas_phy->lldd_phy = phy; +} + +static void mvs_free(struct mvs_info *mvi) +{ + int i; + struct mvs_wq *mwq; + int slot_nr; + + if (!mvi) + return; + + if (mvi->flags & MVF_FLAG_SOC) + slot_nr = MVS_SOC_SLOTS; + else + slot_nr = MVS_SLOTS; + + for (i = 0; i < mvi->tags_num; i++) { + struct mvs_slot_info *slot = &mvi->slot_info[i]; + if (slot->buf) + dma_free_coherent(mvi->dev, MVS_SLOT_BUF_SZ, + slot->buf, slot->buf_dma); + } + + if (mvi->tx) + dma_free_coherent(mvi->dev, + sizeof(*mvi->tx) * MVS_CHIP_SLOT_SZ, + mvi->tx, mvi->tx_dma); + if (mvi->rx_fis) + dma_free_coherent(mvi->dev, MVS_RX_FISL_SZ, + mvi->rx_fis, mvi->rx_fis_dma); + if (mvi->rx) + dma_free_coherent(mvi->dev, + sizeof(*mvi->rx) * (MVS_RX_RING_SZ + 1), + mvi->rx, mvi->rx_dma); + if (mvi->slot) + dma_free_coherent(mvi->dev, + sizeof(*mvi->slot) * slot_nr, + mvi->slot, mvi->slot_dma); +#ifndef DISABLE_HOTPLUG_DMA_FIX + if (mvi->bulk_buffer) + dma_free_coherent(mvi->dev, TRASH_BUCKET_SIZE, + mvi->bulk_buffer, mvi->bulk_buffer_dma); +#endif + + MVS_CHIP_DISP->chip_iounmap(mvi); + if (mvi->shost) + scsi_host_put(mvi->shost); + list_for_each_entry(mwq, &mvi->wq_list, entry) + cancel_delayed_work(&mwq->work_q); + kfree(mvi); +} + +#ifdef MVS_USE_TASKLET +struct tasklet_struct mv_tasklet; +static void mvs_tasklet(unsigned long opaque) +{ + unsigned long flags; + u32 stat; + u16 core_nr, i = 0; + + struct mvs_info *mvi; + struct sas_ha_struct *sha = (struct sas_ha_struct *)opaque; + + core_nr = ((struct mvs_prv_info *)sha->lldd_ha)->n_host; + mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[0]; + + if (unlikely(!mvi)) + BUG_ON(1); + + for (i = 0; i < core_nr; i++) { + mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[i]; + stat = MVS_CHIP_DISP->isr_status(mvi, mvi->irq); + if (stat) + MVS_CHIP_DISP->isr(mvi, mvi->irq, stat); + } + +} +#endif + +static irqreturn_t mvs_interrupt(int irq, void *opaque) +{ + u32 core_nr, i = 0; + u32 stat; + struct mvs_info *mvi; + struct sas_ha_struct *sha = opaque; + + core_nr = ((struct mvs_prv_info *)sha->lldd_ha)->n_host; + mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[0]; + + if (unlikely(!mvi)) + return IRQ_NONE; + + stat = MVS_CHIP_DISP->isr_status(mvi, irq); + if (!stat) + return IRQ_NONE; + +#ifdef MVS_USE_TASKLET + tasklet_schedule(&mv_tasklet); +#else + for (i = 0; i < core_nr; i++) { + mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[i]; + MVS_CHIP_DISP->isr(mvi, irq, stat); + } +#endif + return IRQ_HANDLED; +} + +static int __devinit mvs_alloc(struct mvs_info *mvi, struct Scsi_Host *shost) +{ + int i, slot_nr; + + if (mvi->flags & MVF_FLAG_SOC) + slot_nr = MVS_SOC_SLOTS; + else + slot_nr = MVS_SLOTS; + + spin_lock_init(&mvi->lock); + for (i = 0; i < mvi->chip->n_phy; i++) { + mvs_phy_init(mvi, i); + mvi->port[i].wide_port_phymap = 0; + mvi->port[i].port_attached = 0; + INIT_LIST_HEAD(&mvi->port[i].list); + } + for (i = 0; i < MVS_MAX_DEVICES; i++) { + mvi->devices[i].taskfileset = MVS_ID_NOT_MAPPED; + mvi->devices[i].dev_type = NO_DEVICE; + mvi->devices[i].device_id = i; + mvi->devices[i].dev_status = MVS_DEV_NORMAL; + } + + /* + * alloc and init our DMA areas + */ + mvi->tx = dma_alloc_coherent(mvi->dev, + sizeof(*mvi->tx) * MVS_CHIP_SLOT_SZ, + &mvi->tx_dma, GFP_KERNEL); + if (!mvi->tx) + goto err_out; + memset(mvi->tx, 0, sizeof(*mvi->tx) * MVS_CHIP_SLOT_SZ); + mvi->rx_fis = dma_alloc_coherent(mvi->dev, MVS_RX_FISL_SZ, + &mvi->rx_fis_dma, GFP_KERNEL); + if (!mvi->rx_fis) + goto err_out; + memset(mvi->rx_fis, 0, MVS_RX_FISL_SZ); + + mvi->rx = dma_alloc_coherent(mvi->dev, + sizeof(*mvi->rx) * (MVS_RX_RING_SZ + 1), + &mvi->rx_dma, GFP_KERNEL); + if (!mvi->rx) + goto err_out; + memset(mvi->rx, 0, sizeof(*mvi->rx) * (MVS_RX_RING_SZ + 1)); + mvi->rx[0] = cpu_to_le32(0xfff); + mvi->rx_cons = 0xfff; + + mvi->slot = dma_alloc_coherent(mvi->dev, + sizeof(*mvi->slot) * slot_nr, + &mvi->slot_dma, GFP_KERNEL); + if (!mvi->slot) + goto err_out; + memset(mvi->slot, 0, sizeof(*mvi->slot) * slot_nr); + +#ifndef DISABLE_HOTPLUG_DMA_FIX + mvi->bulk_buffer = dma_alloc_coherent(mvi->dev, + TRASH_BUCKET_SIZE, + &mvi->bulk_buffer_dma, GFP_KERNEL); + if (!mvi->bulk_buffer) + goto err_out; +#endif + for (i = 0; i < slot_nr; i++) { + struct mvs_slot_info *slot = &mvi->slot_info[i]; + + slot->buf = dma_alloc_coherent(mvi->dev, MVS_SLOT_BUF_SZ, + &slot->buf_dma, GFP_KERNEL); + if (!slot->buf) { + printk(KERN_DEBUG"failed to allocate slot->buf.\n"); + goto err_out; + } + memset(slot->buf, 0, MVS_SLOT_BUF_SZ); + ++mvi->tags_num; + } + /* Initialize tags */ + mvs_tag_init(mvi); + return 0; +err_out: + return 1; +} + + +int mvs_ioremap(struct mvs_info *mvi, int bar, int bar_ex) +{ + unsigned long res_start, res_len, res_flag, res_flag_ex = 0; + struct pci_dev *pdev = mvi->pdev; + if (bar_ex != -1) { + /* + * ioremap main and peripheral registers + */ + res_start = pci_resource_start(pdev, bar_ex); + res_len = pci_resource_len(pdev, bar_ex); + if (!res_start || !res_len) + goto err_out; + + res_flag_ex = pci_resource_flags(pdev, bar_ex); + if (res_flag_ex & IORESOURCE_MEM) { + if (res_flag_ex & IORESOURCE_CACHEABLE) + mvi->regs_ex = ioremap(res_start, res_len); + else + mvi->regs_ex = ioremap_nocache(res_start, + res_len); + } else + mvi->regs_ex = (void *)res_start; + if (!mvi->regs_ex) + goto err_out; + } + + res_start = pci_resource_start(pdev, bar); + res_len = pci_resource_len(pdev, bar); + if (!res_start || !res_len) + goto err_out; + + res_flag = pci_resource_flags(pdev, bar); + if (res_flag & IORESOURCE_CACHEABLE) + mvi->regs = ioremap(res_start, res_len); + else + mvi->regs = ioremap_nocache(res_start, res_len); + + if (!mvi->regs) { + if (mvi->regs_ex && (res_flag_ex & IORESOURCE_MEM)) + iounmap(mvi->regs_ex); + mvi->regs_ex = NULL; + goto err_out; + } + + return 0; +err_out: + return -1; +} + +void mvs_iounmap(void __iomem *regs) +{ + iounmap(regs); +} + +static struct mvs_info *__devinit mvs_pci_alloc(struct pci_dev *pdev, + const struct pci_device_id *ent, + struct Scsi_Host *shost, unsigned int id) +{ + struct mvs_info *mvi; + struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); + + mvi = kzalloc(sizeof(*mvi) + MVS_SLOTS * sizeof(struct mvs_slot_info), + GFP_KERNEL); + if (!mvi) + return NULL; + + mvi->pdev = pdev; + mvi->dev = &pdev->dev; + mvi->chip_id = ent->driver_data; + mvi->chip = &mvs_chips[mvi->chip_id]; + INIT_LIST_HEAD(&mvi->wq_list); + mvi->irq = pdev->irq; + + ((struct mvs_prv_info *)sha->lldd_ha)->mvi[id] = mvi; + ((struct mvs_prv_info *)sha->lldd_ha)->n_phy = mvi->chip->n_phy; + + mvi->id = id; + mvi->sas = sha; + mvi->shost = shost; +#ifdef MVS_USE_TASKLET + tasklet_init(&mv_tasklet, mvs_tasklet, (unsigned long)sha); +#endif + + if (MVS_CHIP_DISP->chip_ioremap(mvi)) + goto err_out; + if (!mvs_alloc(mvi, shost)) + return mvi; +err_out: + mvs_free(mvi); + return NULL; +} + +/* move to PCI layer or libata core? */ +static int pci_go_64(struct pci_dev *pdev) +{ + int rc; + + if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { + rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); + if (rc) { + rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); + if (rc) { + dev_printk(KERN_ERR, &pdev->dev, + "64-bit DMA enable failed\n"); + return rc; + } + } + } else { + rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (rc) { + dev_printk(KERN_ERR, &pdev->dev, + "32-bit DMA enable failed\n"); + return rc; + } + rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); + if (rc) { + dev_printk(KERN_ERR, &pdev->dev, + "32-bit consistent DMA enable failed\n"); + return rc; + } + } + + return rc; +} + +static int __devinit mvs_prep_sas_ha_init(struct Scsi_Host *shost, + const struct mvs_chip_info *chip_info) +{ + int phy_nr, port_nr; unsigned short core_nr; + struct asd_sas_phy **arr_phy; + struct asd_sas_port **arr_port; + struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); + + core_nr = chip_info->n_host; + phy_nr = core_nr * chip_info->n_phy; + port_nr = phy_nr; + + memset(sha, 0x00, sizeof(struct sas_ha_struct)); + arr_phy = kcalloc(phy_nr, sizeof(void *), GFP_KERNEL); + arr_port = kcalloc(port_nr, sizeof(void *), GFP_KERNEL); + if (!arr_phy || !arr_port) + goto exit_free; + + sha->sas_phy = arr_phy; + sha->sas_port = arr_port; + + sha->lldd_ha = kzalloc(sizeof(struct mvs_prv_info), GFP_KERNEL); + if (!sha->lldd_ha) + goto exit_free; + + ((struct mvs_prv_info *)sha->lldd_ha)->n_host = core_nr; + + shost->transportt = mvs_stt; + shost->max_id = 128; + shost->max_lun = ~0; + shost->max_channel = 1; + shost->max_cmd_len = 16; + + return 0; +exit_free: + kfree(arr_phy); + kfree(arr_port); + return -1; + +} + +static void __devinit mvs_post_sas_ha_init(struct Scsi_Host *shost, + const struct mvs_chip_info *chip_info) +{ + int can_queue, i = 0, j = 0; + struct mvs_info *mvi = NULL; + struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); + unsigned short nr_core = ((struct mvs_prv_info *)sha->lldd_ha)->n_host; + + for (j = 0; j < nr_core; j++) { + mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[j]; + for (i = 0; i < chip_info->n_phy; i++) { + sha->sas_phy[j * chip_info->n_phy + i] = + &mvi->phy[i].sas_phy; + sha->sas_port[j * chip_info->n_phy + i] = + &mvi->port[i].sas_port; + } + } + + sha->sas_ha_name = DRV_NAME; + sha->dev = mvi->dev; + sha->lldd_module = THIS_MODULE; + sha->sas_addr = &mvi->sas_addr[0]; + + sha->num_phys = nr_core * chip_info->n_phy; + + sha->lldd_max_execute_num = 1; + + if (mvi->flags & MVF_FLAG_SOC) + can_queue = MVS_SOC_CAN_QUEUE; + else + can_queue = MVS_CAN_QUEUE; + + sha->lldd_queue_size = can_queue; + shost->can_queue = can_queue; + mvi->shost->cmd_per_lun = MVS_SLOTS/sha->num_phys; + sha->core.shost = mvi->shost; +} + +static void mvs_init_sas_add(struct mvs_info *mvi) +{ + u8 i; + for (i = 0; i < mvi->chip->n_phy; i++) { + mvi->phy[i].dev_sas_addr = 0x5005043011ab0000ULL; + mvi->phy[i].dev_sas_addr = + cpu_to_be64((u64)(*(u64 *)&mvi->phy[i].dev_sas_addr)); + } + + memcpy(mvi->sas_addr, &mvi->phy[0].dev_sas_addr, SAS_ADDR_SIZE); +} + +static int __devinit mvs_pci_init(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + unsigned int rc, nhost = 0; + struct mvs_info *mvi; + irq_handler_t irq_handler = mvs_interrupt; + struct Scsi_Host *shost = NULL; + const struct mvs_chip_info *chip; + + dev_printk(KERN_INFO, &pdev->dev, + "mvsas: driver version %s\n", DRV_VERSION); + rc = pci_enable_device(pdev); + if (rc) + goto err_out_enable; + + pci_set_master(pdev); + + rc = pci_request_regions(pdev, DRV_NAME); + if (rc) + goto err_out_disable; + + rc = pci_go_64(pdev); + if (rc) + goto err_out_regions; + + shost = scsi_host_alloc(&mvs_sht, sizeof(void *)); + if (!shost) { + rc = -ENOMEM; + goto err_out_regions; + } + + chip = &mvs_chips[ent->driver_data]; + SHOST_TO_SAS_HA(shost) = + kcalloc(1, sizeof(struct sas_ha_struct), GFP_KERNEL); + if (!SHOST_TO_SAS_HA(shost)) { + kfree(shost); + rc = -ENOMEM; + goto err_out_regions; + } + + rc = mvs_prep_sas_ha_init(shost, chip); + if (rc) { + kfree(shost); + rc = -ENOMEM; + goto err_out_regions; + } + + pci_set_drvdata(pdev, SHOST_TO_SAS_HA(shost)); + + do { + mvi = mvs_pci_alloc(pdev, ent, shost, nhost); + if (!mvi) { + rc = -ENOMEM; + goto err_out_regions; + } + + mvs_init_sas_add(mvi); + + mvi->instance = nhost; + rc = MVS_CHIP_DISP->chip_init(mvi); + if (rc) { + mvs_free(mvi); + goto err_out_regions; + } + nhost++; + } while (nhost < chip->n_host); + + mvs_post_sas_ha_init(shost, chip); + + rc = scsi_add_host(shost, &pdev->dev); + if (rc) + goto err_out_shost; + + rc = sas_register_ha(SHOST_TO_SAS_HA(shost)); + if (rc) + goto err_out_shost; + rc = request_irq(pdev->irq, irq_handler, IRQF_SHARED, + DRV_NAME, SHOST_TO_SAS_HA(shost)); + if (rc) + goto err_not_sas; + + MVS_CHIP_DISP->interrupt_enable(mvi); + + scsi_scan_host(mvi->shost); + + return 0; + +err_not_sas: + sas_unregister_ha(SHOST_TO_SAS_HA(shost)); +err_out_shost: + scsi_remove_host(mvi->shost); +err_out_regions: + pci_release_regions(pdev); +err_out_disable: + pci_disable_device(pdev); +err_out_enable: + return rc; +} + +static void __devexit mvs_pci_remove(struct pci_dev *pdev) +{ + unsigned short core_nr, i = 0; + struct sas_ha_struct *sha = pci_get_drvdata(pdev); + struct mvs_info *mvi = NULL; + + core_nr = ((struct mvs_prv_info *)sha->lldd_ha)->n_host; + mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[0]; + +#ifdef MVS_USE_TASKLET + tasklet_kill(&mv_tasklet); +#endif + + pci_set_drvdata(pdev, NULL); + sas_unregister_ha(sha); + sas_remove_host(mvi->shost); + scsi_remove_host(mvi->shost); + + MVS_CHIP_DISP->interrupt_disable(mvi); + free_irq(mvi->irq, sha); + for (i = 0; i < core_nr; i++) { + mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[i]; + mvs_free(mvi); + } + kfree(sha->sas_phy); + kfree(sha->sas_port); + kfree(sha); + pci_release_regions(pdev); + pci_disable_device(pdev); + return; +} + +static struct pci_device_id __devinitdata mvs_pci_table[] = { + { PCI_VDEVICE(MARVELL, 0x6320), chip_6320 }, + { PCI_VDEVICE(MARVELL, 0x6340), chip_6440 }, + { + .vendor = PCI_VENDOR_ID_MARVELL, + .device = 0x6440, + .subvendor = PCI_ANY_ID, + .subdevice = 0x6480, + .class = 0, + .class_mask = 0, + .driver_data = chip_6485, + }, + { PCI_VDEVICE(MARVELL, 0x6440), chip_6440 }, + { PCI_VDEVICE(MARVELL, 0x6485), chip_6485 }, + { PCI_VDEVICE(MARVELL, 0x9480), chip_9480 }, + { PCI_VDEVICE(MARVELL, 0x9180), chip_9180 }, + + { } /* terminate list */ +}; + +static struct pci_driver mvs_pci_driver = { + .name = DRV_NAME, + .id_table = mvs_pci_table, + .probe = mvs_pci_init, + .remove = __devexit_p(mvs_pci_remove), +}; + +/* task handler */ +struct task_struct *mvs_th; +static int __init mvs_init(void) +{ + int rc; + mvs_stt = sas_domain_attach_transport(&mvs_transport_ops); + if (!mvs_stt) + return -ENOMEM; + + rc = pci_register_driver(&mvs_pci_driver); + + if (rc) + goto err_out; + + return 0; + +err_out: + sas_release_transport(mvs_stt); + return rc; +} + +static void __exit mvs_exit(void) +{ + pci_unregister_driver(&mvs_pci_driver); + sas_release_transport(mvs_stt); +} + +module_init(mvs_init); +module_exit(mvs_exit); + +MODULE_AUTHOR("Jeff Garzik "); +MODULE_DESCRIPTION("Marvell 88SE6440 SAS/SATA controller driver"); +MODULE_VERSION(DRV_VERSION); +MODULE_LICENSE("GPL"); +#ifdef CONFIG_PCI +MODULE_DEVICE_TABLE(pci, mvs_pci_table); +#endif diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c new file mode 100644 index 000000000000..0d2138641214 --- /dev/null +++ b/drivers/scsi/mvsas/mv_sas.c @@ -0,0 +1,2154 @@ +/* + * Marvell 88SE64xx/88SE94xx main function + * + * Copyright 2007 Red Hat, Inc. + * Copyright 2008 Marvell. + * + * This file is licensed under GPLv2. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2 of the + * License. + * + * 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 "mv_sas.h" + +static int mvs_find_tag(struct mvs_info *mvi, struct sas_task *task, u32 *tag) +{ + if (task->lldd_task) { + struct mvs_slot_info *slot; + slot = task->lldd_task; + *tag = slot->slot_tag; + return 1; + } + return 0; +} + +void mvs_tag_clear(struct mvs_info *mvi, u32 tag) +{ + void *bitmap = &mvi->tags; + clear_bit(tag, bitmap); +} + +void mvs_tag_free(struct mvs_info *mvi, u32 tag) +{ + mvs_tag_clear(mvi, tag); +} + +void mvs_tag_set(struct mvs_info *mvi, unsigned int tag) +{ + void *bitmap = &mvi->tags; + set_bit(tag, bitmap); +} + +inline int mvs_tag_alloc(struct mvs_info *mvi, u32 *tag_out) +{ + unsigned int index, tag; + void *bitmap = &mvi->tags; + + index = find_first_zero_bit(bitmap, mvi->tags_num); + tag = index; + if (tag >= mvi->tags_num) + return -SAS_QUEUE_FULL; + mvs_tag_set(mvi, tag); + *tag_out = tag; + return 0; +} + +void mvs_tag_init(struct mvs_info *mvi) +{ + int i; + for (i = 0; i < mvi->tags_num; ++i) + mvs_tag_clear(mvi, i); +} + +void mvs_hexdump(u32 size, u8 *data, u32 baseaddr) +{ + u32 i; + u32 run; + u32 offset; + + offset = 0; + while (size) { + printk(KERN_DEBUG"%08X : ", baseaddr + offset); + if (size >= 16) + run = 16; + else + run = size; + size -= run; + for (i = 0; i < 16; i++) { + if (i < run) + printk(KERN_DEBUG"%02X ", (u32)data[i]); + else + printk(KERN_DEBUG" "); + } + printk(KERN_DEBUG": "); + for (i = 0; i < run; i++) + printk(KERN_DEBUG"%c", + isalnum(data[i]) ? data[i] : '.'); + printk(KERN_DEBUG"\n"); + data = &data[16]; + offset += run; + } + printk(KERN_DEBUG"\n"); +} + +#if (_MV_DUMP > 1) +static void mvs_hba_sb_dump(struct mvs_info *mvi, u32 tag, + enum sas_protocol proto) +{ + u32 offset; + struct mvs_slot_info *slot = &mvi->slot_info[tag]; + + offset = slot->cmd_size + MVS_OAF_SZ + + MVS_CHIP_DISP->prd_size() * slot->n_elem; + dev_printk(KERN_DEBUG, mvi->dev, "+---->Status buffer[%d] :\n", + tag); + mvs_hexdump(32, (u8 *) slot->response, + (u32) slot->buf_dma + offset); +} +#endif + +static void mvs_hba_memory_dump(struct mvs_info *mvi, u32 tag, + enum sas_protocol proto) +{ +#if (_MV_DUMP > 1) + u32 sz, w_ptr; + u64 addr; + struct mvs_slot_info *slot = &mvi->slot_info[tag]; + + /*Delivery Queue */ + sz = MVS_CHIP_SLOT_SZ; + w_ptr = slot->tx; + addr = mvi->tx_dma; + dev_printk(KERN_DEBUG, mvi->dev, + "Delivery Queue Size=%04d , WRT_PTR=%04X\n", sz, w_ptr); + dev_printk(KERN_DEBUG, mvi->dev, + "Delivery Queue Base Address=0x%llX (PA)" + "(tx_dma=0x%llX), Entry=%04d\n", + addr, (unsigned long long)mvi->tx_dma, w_ptr); + mvs_hexdump(sizeof(u32), (u8 *)(&mvi->tx[mvi->tx_prod]), + (u32) mvi->tx_dma + sizeof(u32) * w_ptr); + /*Command List */ + addr = mvi->slot_dma; + dev_printk(KERN_DEBUG, mvi->dev, + "Command List Base Address=0x%llX (PA)" + "(slot_dma=0x%llX), Header=%03d\n", + addr, (unsigned long long)slot->buf_dma, tag); + dev_printk(KERN_DEBUG, mvi->dev, "Command Header[%03d]:\n", tag); + /*mvs_cmd_hdr */ + mvs_hexdump(sizeof(struct mvs_cmd_hdr), (u8 *)(&mvi->slot[tag]), + (u32) mvi->slot_dma + tag * sizeof(struct mvs_cmd_hdr)); + /*1.command table area */ + dev_printk(KERN_DEBUG, mvi->dev, "+---->Command Table :\n"); + mvs_hexdump(slot->cmd_size, (u8 *) slot->buf, (u32) slot->buf_dma); + /*2.open address frame area */ + dev_printk(KERN_DEBUG, mvi->dev, "+---->Open Address Frame :\n"); + mvs_hexdump(MVS_OAF_SZ, (u8 *) slot->buf + slot->cmd_size, + (u32) slot->buf_dma + slot->cmd_size); + /*3.status buffer */ + mvs_hba_sb_dump(mvi, tag, proto); + /*4.PRD table */ + dev_printk(KERN_DEBUG, mvi->dev, "+---->PRD table :\n"); + mvs_hexdump(MVS_CHIP_DISP->prd_size() * slot->n_elem, + (u8 *) slot->buf + slot->cmd_size + MVS_OAF_SZ, + (u32) slot->buf_dma + slot->cmd_size + MVS_OAF_SZ); +#endif +} + +static void mvs_hba_cq_dump(struct mvs_info *mvi) +{ +#if (_MV_DUMP > 2) + u64 addr; + void __iomem *regs = mvi->regs; + u32 entry = mvi->rx_cons + 1; + u32 rx_desc = le32_to_cpu(mvi->rx[entry]); + + /*Completion Queue */ + addr = mr32(RX_HI) << 16 << 16 | mr32(RX_LO); + dev_printk(KERN_DEBUG, mvi->dev, "Completion Task = 0x%p\n", + mvi->slot_info[rx_desc & RXQ_SLOT_MASK].task); + dev_printk(KERN_DEBUG, mvi->dev, + "Completion List Base Address=0x%llX (PA), " + "CQ_Entry=%04d, CQ_WP=0x%08X\n", + addr, entry - 1, mvi->rx[0]); + mvs_hexdump(sizeof(u32), (u8 *)(&rx_desc), + mvi->rx_dma + sizeof(u32) * entry); +#endif +} + +void mvs_get_sas_addr(void *buf, u32 buflen) +{ + /*memcpy(buf, "\x50\x05\x04\x30\x11\xab\x64\x40", 8);*/ +} + +struct mvs_info *mvs_find_dev_mvi(struct domain_device *dev) +{ + unsigned long i = 0, j = 0, hi = 0; + struct sas_ha_struct *sha = dev->port->ha; + struct mvs_info *mvi = NULL; + struct asd_sas_phy *phy; + + while (sha->sas_port[i]) { + if (sha->sas_port[i] == dev->port) { + phy = container_of(sha->sas_port[i]->phy_list.next, + struct asd_sas_phy, port_phy_el); + j = 0; + while (sha->sas_phy[j]) { + if (sha->sas_phy[j] == phy) + break; + j++; + } + break; + } + i++; + } + hi = j/((struct mvs_prv_info *)sha->lldd_ha)->n_phy; + mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[hi]; + + return mvi; + +} + +/* FIXME */ +int mvs_find_dev_phyno(struct domain_device *dev, int *phyno) +{ + unsigned long i = 0, j = 0, n = 0, num = 0; + struct mvs_device *mvi_dev = (struct mvs_device *)dev->lldd_dev; + struct mvs_info *mvi = mvi_dev->mvi_info; + struct sas_ha_struct *sha = dev->port->ha; + + while (sha->sas_port[i]) { + if (sha->sas_port[i] == dev->port) { + struct asd_sas_phy *phy; + list_for_each_entry(phy, + &sha->sas_port[i]->phy_list, port_phy_el) { + j = 0; + while (sha->sas_phy[j]) { + if (sha->sas_phy[j] == phy) + break; + j++; + } + phyno[n] = (j >= mvi->chip->n_phy) ? + (j - mvi->chip->n_phy) : j; + num++; + n++; + } + break; + } + i++; + } + return num; +} + +static inline void mvs_free_reg_set(struct mvs_info *mvi, + struct mvs_device *dev) +{ + if (!dev) { + mv_printk("device has been free.\n"); + return; + } + if (dev->runing_req != 0) + return; + if (dev->taskfileset == MVS_ID_NOT_MAPPED) + return; + MVS_CHIP_DISP->free_reg_set(mvi, &dev->taskfileset); +} + +static inline u8 mvs_assign_reg_set(struct mvs_info *mvi, + struct mvs_device *dev) +{ + if (dev->taskfileset != MVS_ID_NOT_MAPPED) + return 0; + return MVS_CHIP_DISP->assign_reg_set(mvi, &dev->taskfileset); +} + +void mvs_phys_reset(struct mvs_info *mvi, u32 phy_mask, int hard) +{ + u32 no; + for_each_phy(phy_mask, phy_mask, no) { + if (!(phy_mask & 1)) + continue; + MVS_CHIP_DISP->phy_reset(mvi, no, hard); + } +} + +/* FIXME: locking? */ +int mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func, + void *funcdata) +{ + int rc = 0, phy_id = sas_phy->id; + u32 tmp, i = 0, hi; + struct sas_ha_struct *sha = sas_phy->ha; + struct mvs_info *mvi = NULL; + + while (sha->sas_phy[i]) { + if (sha->sas_phy[i] == sas_phy) + break; + i++; + } + hi = i/((struct mvs_prv_info *)sha->lldd_ha)->n_phy; + mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[hi]; + + switch (func) { + case PHY_FUNC_SET_LINK_RATE: + MVS_CHIP_DISP->phy_set_link_rate(mvi, phy_id, funcdata); + break; + + case PHY_FUNC_HARD_RESET: + tmp = MVS_CHIP_DISP->read_phy_ctl(mvi, phy_id); + if (tmp & PHY_RST_HARD) + break; + MVS_CHIP_DISP->phy_reset(mvi, phy_id, 1); + break; + + case PHY_FUNC_LINK_RESET: + MVS_CHIP_DISP->phy_enable(mvi, phy_id); + MVS_CHIP_DISP->phy_reset(mvi, phy_id, 0); + break; + + case PHY_FUNC_DISABLE: + MVS_CHIP_DISP->phy_disable(mvi, phy_id); + break; + case PHY_FUNC_RELEASE_SPINUP_HOLD: + default: + rc = -EOPNOTSUPP; + } + msleep(200); + return rc; +} + +void __devinit mvs_set_sas_addr(struct mvs_info *mvi, int port_id, + u32 off_lo, u32 off_hi, u64 sas_addr) +{ + u32 lo = (u32)sas_addr; + u32 hi = (u32)(sas_addr>>32); + + MVS_CHIP_DISP->write_port_cfg_addr(mvi, port_id, off_lo); + MVS_CHIP_DISP->write_port_cfg_data(mvi, port_id, lo); + MVS_CHIP_DISP->write_port_cfg_addr(mvi, port_id, off_hi); + MVS_CHIP_DISP->write_port_cfg_data(mvi, port_id, hi); +} + +static void mvs_bytes_dmaed(struct mvs_info *mvi, int i) +{ + struct mvs_phy *phy = &mvi->phy[i]; + struct asd_sas_phy *sas_phy = &phy->sas_phy; + struct sas_ha_struct *sas_ha; + if (!phy->phy_attached) + return; + + if (!(phy->att_dev_info & PORT_DEV_TRGT_MASK) + && phy->phy_type & PORT_TYPE_SAS) { + return; + } + + sas_ha = mvi->sas; + sas_ha->notify_phy_event(sas_phy, PHYE_OOB_DONE); + + if (sas_phy->phy) { + struct sas_phy *sphy = sas_phy->phy; + + sphy->negotiated_linkrate = sas_phy->linkrate; + sphy->minimum_linkrate = phy->minimum_linkrate; + sphy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS; + sphy->maximum_linkrate = phy->maximum_linkrate; + sphy->maximum_linkrate_hw = MVS_CHIP_DISP->phy_max_link_rate(); + } + + if (phy->phy_type & PORT_TYPE_SAS) { + struct sas_identify_frame *id; + + id = (struct sas_identify_frame *)phy->frame_rcvd; + id->dev_type = phy->identify.device_type; + id->initiator_bits = SAS_PROTOCOL_ALL; + id->target_bits = phy->identify.target_port_protocols; + } else if (phy->phy_type & PORT_TYPE_SATA) { + /*Nothing*/ + } + mv_dprintk("phy %d byte dmaded.\n", i + mvi->id * mvi->chip->n_phy); + + sas_phy->frame_rcvd_size = phy->frame_rcvd_size; + + mvi->sas->notify_port_event(sas_phy, + PORTE_BYTES_DMAED); +} + +int mvs_slave_alloc(struct scsi_device *scsi_dev) +{ + struct domain_device *dev = sdev_to_domain_dev(scsi_dev); + if (dev_is_sata(dev)) { + /* We don't need to rescan targets + * if REPORT_LUNS request is failed + */ + if (scsi_dev->lun > 0) + return -ENXIO; + scsi_dev->tagged_supported = 1; + } + + return sas_slave_alloc(scsi_dev); +} + +int mvs_slave_configure(struct scsi_device *sdev) +{ + struct domain_device *dev = sdev_to_domain_dev(sdev); + int ret = sas_slave_configure(sdev); + + if (ret) + return ret; + if (dev_is_sata(dev)) { + /* may set PIO mode */ + #if MV_DISABLE_NCQ + struct ata_port *ap = dev->sata_dev.ap; + struct ata_device *adev = ap->link.device; + adev->flags |= ATA_DFLAG_NCQ_OFF; + scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, 1); + #endif + } + return 0; +} + +void mvs_scan_start(struct Scsi_Host *shost) +{ + int i, j; + unsigned short core_nr; + struct mvs_info *mvi; + struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); + + core_nr = ((struct mvs_prv_info *)sha->lldd_ha)->n_host; + + for (j = 0; j < core_nr; j++) { + mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[j]; + for (i = 0; i < mvi->chip->n_phy; ++i) + mvs_bytes_dmaed(mvi, i); + } +} + +int mvs_scan_finished(struct Scsi_Host *shost, unsigned long time) +{ + /* give the phy enabling interrupt event time to come in (1s + * is empirically about all it takes) */ + if (time < HZ) + return 0; + /* Wait for discovery to finish */ + scsi_flush_work(shost); + return 1; +} + +static int mvs_task_prep_smp(struct mvs_info *mvi, + struct mvs_task_exec_info *tei) +{ + int elem, rc, i; + struct sas_task *task = tei->task; + struct mvs_cmd_hdr *hdr = tei->hdr; + struct domain_device *dev = task->dev; + struct asd_sas_port *sas_port = dev->port; + struct scatterlist *sg_req, *sg_resp; + u32 req_len, resp_len, tag = tei->tag; + void *buf_tmp; + u8 *buf_oaf; + dma_addr_t buf_tmp_dma; + void *buf_prd; + struct mvs_slot_info *slot = &mvi->slot_info[tag]; + u32 flags = (tei->n_elem << MCH_PRD_LEN_SHIFT); +#if _MV_DUMP + u8 *buf_cmd; + void *from; +#endif + /* + * DMA-map SMP request, response buffers + */ + sg_req = &task->smp_task.smp_req; + elem = dma_map_sg(mvi->dev, sg_req, 1, PCI_DMA_TODEVICE); + if (!elem) + return -ENOMEM; + req_len = sg_dma_len(sg_req); + + sg_resp = &task->smp_task.smp_resp; + elem = dma_map_sg(mvi->dev, sg_resp, 1, PCI_DMA_FROMDEVICE); + if (!elem) { + rc = -ENOMEM; + goto err_out; + } + resp_len = SB_RFB_MAX; + + /* must be in dwords */ + if ((req_len & 0x3) || (resp_len & 0x3)) { + rc = -EINVAL; + goto err_out_2; + } + + /* + * arrange MVS_SLOT_BUF_SZ-sized DMA buffer according to our needs + */ + + /* region 1: command table area (MVS_SSP_CMD_SZ bytes) ***** */ + buf_tmp = slot->buf; + buf_tmp_dma = slot->buf_dma; + +#if _MV_DUMP + buf_cmd = buf_tmp; + hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma); + buf_tmp += req_len; + buf_tmp_dma += req_len; + slot->cmd_size = req_len; +#else + hdr->cmd_tbl = cpu_to_le64(sg_dma_address(sg_req)); +#endif + + /* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */ + buf_oaf = buf_tmp; + hdr->open_frame = cpu_to_le64(buf_tmp_dma); + + buf_tmp += MVS_OAF_SZ; + buf_tmp_dma += MVS_OAF_SZ; + + /* region 3: PRD table *********************************** */ + buf_prd = buf_tmp; + if (tei->n_elem) + hdr->prd_tbl = cpu_to_le64(buf_tmp_dma); + else + hdr->prd_tbl = 0; + + i = MVS_CHIP_DISP->prd_size() * tei->n_elem; + buf_tmp += i; + buf_tmp_dma += i; + + /* region 4: status buffer (larger the PRD, smaller this buf) ****** */ + slot->response = buf_tmp; + hdr->status_buf = cpu_to_le64(buf_tmp_dma); + if (mvi->flags & MVF_FLAG_SOC) + hdr->reserved[0] = 0; + + /* + * Fill in TX ring and command slot header + */ + slot->tx = mvi->tx_prod; + mvi->tx[mvi->tx_prod] = cpu_to_le32((TXQ_CMD_SMP << TXQ_CMD_SHIFT) | + TXQ_MODE_I | tag | + (sas_port->phy_mask << TXQ_PHY_SHIFT)); + + hdr->flags |= flags; + hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | ((req_len - 4) / 4)); + hdr->tags = cpu_to_le32(tag); + hdr->data_len = 0; + + /* generate open address frame hdr (first 12 bytes) */ + /* initiator, SMP, ftype 1h */ + buf_oaf[0] = (1 << 7) | (PROTOCOL_SMP << 4) | 0x01; + buf_oaf[1] = dev->linkrate & 0xf; + *(u16 *)(buf_oaf + 2) = 0xFFFF; /* SAS SPEC */ + memcpy(buf_oaf + 4, dev->sas_addr, SAS_ADDR_SIZE); + + /* fill in PRD (scatter/gather) table, if any */ + MVS_CHIP_DISP->make_prd(task->scatter, tei->n_elem, buf_prd); + +#if _MV_DUMP + /* copy cmd table */ + from = kmap_atomic(sg_page(sg_req), KM_IRQ0); + memcpy(buf_cmd, from + sg_req->offset, req_len); + kunmap_atomic(from, KM_IRQ0); +#endif + return 0; + +err_out_2: + dma_unmap_sg(mvi->dev, &tei->task->smp_task.smp_resp, 1, + PCI_DMA_FROMDEVICE); +err_out: + dma_unmap_sg(mvi->dev, &tei->task->smp_task.smp_req, 1, + PCI_DMA_TODEVICE); + return rc; +} + +static u32 mvs_get_ncq_tag(struct sas_task *task, u32 *tag) +{ + struct ata_queued_cmd *qc = task->uldd_task; + + if (qc) { + if (qc->tf.command == ATA_CMD_FPDMA_WRITE || + qc->tf.command == ATA_CMD_FPDMA_READ) { + *tag = qc->tag; + return 1; + } + } + + return 0; +} + +static int mvs_task_prep_ata(struct mvs_info *mvi, + struct mvs_task_exec_info *tei) +{ + struct sas_task *task = tei->task; + struct domain_device *dev = task->dev; + struct mvs_device *mvi_dev = dev->lldd_dev; + struct mvs_cmd_hdr *hdr = tei->hdr; + struct asd_sas_port *sas_port = dev->port; + struct mvs_slot_info *slot; + void *buf_prd; + u32 tag = tei->tag, hdr_tag; + u32 flags, del_q; + void *buf_tmp; + u8 *buf_cmd, *buf_oaf; + dma_addr_t buf_tmp_dma; + u32 i, req_len, resp_len; + const u32 max_resp_len = SB_RFB_MAX; + + if (mvs_assign_reg_set(mvi, mvi_dev) == MVS_ID_NOT_MAPPED) { + mv_dprintk("Have not enough regiset for dev %d.\n", + mvi_dev->device_id); + return -EBUSY; + } + slot = &mvi->slot_info[tag]; + slot->tx = mvi->tx_prod; + del_q = TXQ_MODE_I | tag | + (TXQ_CMD_STP << TXQ_CMD_SHIFT) | + (sas_port->phy_mask << TXQ_PHY_SHIFT) | + (mvi_dev->taskfileset << TXQ_SRS_SHIFT); + mvi->tx[mvi->tx_prod] = cpu_to_le32(del_q); + +#ifndef DISABLE_HOTPLUG_DMA_FIX + if (task->data_dir == DMA_FROM_DEVICE) + flags = (MVS_CHIP_DISP->prd_count() << MCH_PRD_LEN_SHIFT); + else + flags = (tei->n_elem << MCH_PRD_LEN_SHIFT); +#else + flags = (tei->n_elem << MCH_PRD_LEN_SHIFT); +#endif + if (task->ata_task.use_ncq) + flags |= MCH_FPDMA; + if (dev->sata_dev.command_set == ATAPI_COMMAND_SET) { + if (task->ata_task.fis.command != ATA_CMD_ID_ATAPI) + flags |= MCH_ATAPI; + } + + /* FIXME: fill in port multiplier number */ + + hdr->flags = cpu_to_le32(flags); + + /* FIXME: the low order order 5 bits for the TAG if enable NCQ */ + if (task->ata_task.use_ncq && mvs_get_ncq_tag(task, &hdr_tag)) + task->ata_task.fis.sector_count |= (u8) (hdr_tag << 3); + else + hdr_tag = tag; + + hdr->tags = cpu_to_le32(hdr_tag); + + hdr->data_len = cpu_to_le32(task->total_xfer_len); + + /* + * arrange MVS_SLOT_BUF_SZ-sized DMA buffer according to our needs + */ + + /* region 1: command table area (MVS_ATA_CMD_SZ bytes) ************** */ + buf_cmd = buf_tmp = slot->buf; + buf_tmp_dma = slot->buf_dma; + + hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma); + + buf_tmp += MVS_ATA_CMD_SZ; + buf_tmp_dma += MVS_ATA_CMD_SZ; +#if _MV_DUMP + slot->cmd_size = MVS_ATA_CMD_SZ; +#endif + + /* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */ + /* used for STP. unused for SATA? */ + buf_oaf = buf_tmp; + hdr->open_frame = cpu_to_le64(buf_tmp_dma); + + buf_tmp += MVS_OAF_SZ; + buf_tmp_dma += MVS_OAF_SZ; + + /* region 3: PRD table ********************************************* */ + buf_prd = buf_tmp; + + if (tei->n_elem) + hdr->prd_tbl = cpu_to_le64(buf_tmp_dma); + else + hdr->prd_tbl = 0; + i = MVS_CHIP_DISP->prd_size() * MVS_CHIP_DISP->prd_count(); + + buf_tmp += i; + buf_tmp_dma += i; + + /* region 4: status buffer (larger the PRD, smaller this buf) ****** */ + /* FIXME: probably unused, for SATA. kept here just in case + * we get a STP/SATA error information record + */ + slot->response = buf_tmp; + hdr->status_buf = cpu_to_le64(buf_tmp_dma); + if (mvi->flags & MVF_FLAG_SOC) + hdr->reserved[0] = 0; + + req_len = sizeof(struct host_to_dev_fis); + resp_len = MVS_SLOT_BUF_SZ - MVS_ATA_CMD_SZ - + sizeof(struct mvs_err_info) - i; + + /* request, response lengths */ + resp_len = min(resp_len, max_resp_len); + hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | (req_len / 4)); + + if (likely(!task->ata_task.device_control_reg_update)) + task->ata_task.fis.flags |= 0x80; /* C=1: update ATA cmd reg */ + /* fill in command FIS and ATAPI CDB */ + memcpy(buf_cmd, &task->ata_task.fis, sizeof(struct host_to_dev_fis)); + if (dev->sata_dev.command_set == ATAPI_COMMAND_SET) + memcpy(buf_cmd + STP_ATAPI_CMD, + task->ata_task.atapi_packet, 16); + + /* generate open address frame hdr (first 12 bytes) */ + /* initiator, STP, ftype 1h */ + buf_oaf[0] = (1 << 7) | (PROTOCOL_STP << 4) | 0x1; + buf_oaf[1] = dev->linkrate & 0xf; + *(u16 *)(buf_oaf + 2) = cpu_to_be16(mvi_dev->device_id + 1); + memcpy(buf_oaf + 4, dev->sas_addr, SAS_ADDR_SIZE); + + /* fill in PRD (scatter/gather) table, if any */ + MVS_CHIP_DISP->make_prd(task->scatter, tei->n_elem, buf_prd); +#ifndef DISABLE_HOTPLUG_DMA_FIX + if (task->data_dir == DMA_FROM_DEVICE) + MVS_CHIP_DISP->dma_fix(mvi->bulk_buffer_dma, + TRASH_BUCKET_SIZE, tei->n_elem, buf_prd); +#endif + return 0; +} + +static int mvs_task_prep_ssp(struct mvs_info *mvi, + struct mvs_task_exec_info *tei, int is_tmf, + struct mvs_tmf_task *tmf) +{ + struct sas_task *task = tei->task; + struct mvs_cmd_hdr *hdr = tei->hdr; + struct mvs_port *port = tei->port; + struct domain_device *dev = task->dev; + struct mvs_device *mvi_dev = dev->lldd_dev; + struct asd_sas_port *sas_port = dev->port; + struct mvs_slot_info *slot; + void *buf_prd; + struct ssp_frame_hdr *ssp_hdr; + void *buf_tmp; + u8 *buf_cmd, *buf_oaf, fburst = 0; + dma_addr_t buf_tmp_dma; + u32 flags; + u32 resp_len, req_len, i, tag = tei->tag; + const u32 max_resp_len = SB_RFB_MAX; + u32 phy_mask; + + slot = &mvi->slot_info[tag]; + + phy_mask = ((port->wide_port_phymap) ? port->wide_port_phymap : + sas_port->phy_mask) & TXQ_PHY_MASK; + + slot->tx = mvi->tx_prod; + mvi->tx[mvi->tx_prod] = cpu_to_le32(TXQ_MODE_I | tag | + (TXQ_CMD_SSP << TXQ_CMD_SHIFT) | + (phy_mask << TXQ_PHY_SHIFT)); + + flags = MCH_RETRY; + if (task->ssp_task.enable_first_burst) { + flags |= MCH_FBURST; + fburst = (1 << 7); + } + if (is_tmf) + flags |= (MCH_SSP_FR_TASK << MCH_SSP_FR_TYPE_SHIFT); + else + flags |= (MCH_SSP_FR_CMD << MCH_SSP_FR_TYPE_SHIFT); + hdr->flags = cpu_to_le32(flags | (tei->n_elem << MCH_PRD_LEN_SHIFT)); + hdr->tags = cpu_to_le32(tag); + hdr->data_len = cpu_to_le32(task->total_xfer_len); + + /* + * arrange MVS_SLOT_BUF_SZ-sized DMA buffer according to our needs + */ + + /* region 1: command table area (MVS_SSP_CMD_SZ bytes) ************** */ + buf_cmd = buf_tmp = slot->buf; + buf_tmp_dma = slot->buf_dma; + + hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma); + + buf_tmp += MVS_SSP_CMD_SZ; + buf_tmp_dma += MVS_SSP_CMD_SZ; +#if _MV_DUMP + slot->cmd_size = MVS_SSP_CMD_SZ; +#endif + + /* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */ + buf_oaf = buf_tmp; + hdr->open_frame = cpu_to_le64(buf_tmp_dma); + + buf_tmp += MVS_OAF_SZ; + buf_tmp_dma += MVS_OAF_SZ; + + /* region 3: PRD table ********************************************* */ + buf_prd = buf_tmp; + if (tei->n_elem) + hdr->prd_tbl = cpu_to_le64(buf_tmp_dma); + else + hdr->prd_tbl = 0; + + i = MVS_CHIP_DISP->prd_size() * tei->n_elem; + buf_tmp += i; + buf_tmp_dma += i; + + /* region 4: status buffer (larger the PRD, smaller this buf) ****** */ + slot->response = buf_tmp; + hdr->status_buf = cpu_to_le64(buf_tmp_dma); + if (mvi->flags & MVF_FLAG_SOC) + hdr->reserved[0] = 0; + + resp_len = MVS_SLOT_BUF_SZ - MVS_SSP_CMD_SZ - MVS_OAF_SZ - + sizeof(struct mvs_err_info) - i; + resp_len = min(resp_len, max_resp_len); + + req_len = sizeof(struct ssp_frame_hdr) + 28; + + /* request, response lengths */ + hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | (req_len / 4)); + + /* generate open address frame hdr (first 12 bytes) */ + /* initiator, SSP, ftype 1h */ + buf_oaf[0] = (1 << 7) | (PROTOCOL_SSP << 4) | 0x1; + buf_oaf[1] = dev->linkrate & 0xf; + *(u16 *)(buf_oaf + 2) = cpu_to_be16(mvi_dev->device_id + 1); + memcpy(buf_oaf + 4, dev->sas_addr, SAS_ADDR_SIZE); + + /* fill in SSP frame header (Command Table.SSP frame header) */ + ssp_hdr = (struct ssp_frame_hdr *)buf_cmd; + + if (is_tmf) + ssp_hdr->frame_type = SSP_TASK; + else + ssp_hdr->frame_type = SSP_COMMAND; + + memcpy(ssp_hdr->hashed_dest_addr, dev->hashed_sas_addr, + HASHED_SAS_ADDR_SIZE); + memcpy(ssp_hdr->hashed_src_addr, + dev->hashed_sas_addr, HASHED_SAS_ADDR_SIZE); + ssp_hdr->tag = cpu_to_be16(tag); + + /* fill in IU for TASK and Command Frame */ + buf_cmd += sizeof(*ssp_hdr); + memcpy(buf_cmd, &task->ssp_task.LUN, 8); + + if (ssp_hdr->frame_type != SSP_TASK) { + buf_cmd[9] = fburst | task->ssp_task.task_attr | + (task->ssp_task.task_prio << 3); + memcpy(buf_cmd + 12, &task->ssp_task.cdb, 16); + } else{ + buf_cmd[10] = tmf->tmf; + switch (tmf->tmf) { + case TMF_ABORT_TASK: + case TMF_QUERY_TASK: + buf_cmd[12] = + (tmf->tag_of_task_to_be_managed >> 8) & 0xff; + buf_cmd[13] = + tmf->tag_of_task_to_be_managed & 0xff; + break; + default: + break; + } + } + /* fill in PRD (scatter/gather) table, if any */ + MVS_CHIP_DISP->make_prd(task->scatter, tei->n_elem, buf_prd); + return 0; +} + +#define DEV_IS_GONE(mvi_dev) ((!mvi_dev || (mvi_dev->dev_type == NO_DEVICE))) +static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags, + struct completion *completion,int is_tmf, + struct mvs_tmf_task *tmf) +{ + struct domain_device *dev = task->dev; + struct mvs_device *mvi_dev = (struct mvs_device *)dev->lldd_dev; + struct mvs_info *mvi = mvi_dev->mvi_info; + struct mvs_task_exec_info tei; + struct sas_task *t = task; + struct mvs_slot_info *slot; + u32 tag = 0xdeadbeef, rc, n_elem = 0; + u32 n = num, pass = 0; + unsigned long flags = 0; + + if (!dev->port) { + struct task_status_struct *tsm = &t->task_status; + + tsm->resp = SAS_TASK_UNDELIVERED; + tsm->stat = SAS_PHY_DOWN; + t->task_done(t); + return 0; + } + + spin_lock_irqsave(&mvi->lock, flags); + do { + dev = t->dev; + mvi_dev = dev->lldd_dev; + if (DEV_IS_GONE(mvi_dev)) { + if (mvi_dev) + mv_dprintk("device %d not ready.\n", + mvi_dev->device_id); + else + mv_dprintk("device %016llx not ready.\n", + SAS_ADDR(dev->sas_addr)); + + rc = SAS_PHY_DOWN; + goto out_done; + } + + if (dev->port->id >= mvi->chip->n_phy) + tei.port = &mvi->port[dev->port->id - mvi->chip->n_phy]; + else + tei.port = &mvi->port[dev->port->id]; + + if (!tei.port->port_attached) { + if (sas_protocol_ata(t->task_proto)) { + mv_dprintk("port %d does not" + "attached device.\n", dev->port->id); + rc = SAS_PHY_DOWN; + goto out_done; + } else { + struct task_status_struct *ts = &t->task_status; + ts->resp = SAS_TASK_UNDELIVERED; + ts->stat = SAS_PHY_DOWN; + t->task_done(t); + if (n > 1) + t = list_entry(t->list.next, + struct sas_task, list); + continue; + } + } + + if (!sas_protocol_ata(t->task_proto)) { + if (t->num_scatter) { + n_elem = dma_map_sg(mvi->dev, + t->scatter, + t->num_scatter, + t->data_dir); + if (!n_elem) { + rc = -ENOMEM; + goto err_out; + } + } + } else { + n_elem = t->num_scatter; + } + + rc = mvs_tag_alloc(mvi, &tag); + if (rc) + goto err_out; + + slot = &mvi->slot_info[tag]; + + + t->lldd_task = NULL; + slot->n_elem = n_elem; + slot->slot_tag = tag; + memset(slot->buf, 0, MVS_SLOT_BUF_SZ); + + tei.task = t; + tei.hdr = &mvi->slot[tag]; + tei.tag = tag; + tei.n_elem = n_elem; + switch (t->task_proto) { + case SAS_PROTOCOL_SMP: + rc = mvs_task_prep_smp(mvi, &tei); + break; + case SAS_PROTOCOL_SSP: + rc = mvs_task_prep_ssp(mvi, &tei, is_tmf, tmf); + break; + case SAS_PROTOCOL_SATA: + case SAS_PROTOCOL_STP: + case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: + rc = mvs_task_prep_ata(mvi, &tei); + break; + default: + dev_printk(KERN_ERR, mvi->dev, + "unknown sas_task proto: 0x%x\n", + t->task_proto); + rc = -EINVAL; + break; + } + + if (rc) { + mv_dprintk("rc is %x\n", rc); + goto err_out_tag; + } + slot->task = t; + slot->port = tei.port; + t->lldd_task = slot; + list_add_tail(&slot->entry, &tei.port->list); + /* TODO: select normal or high priority */ + spin_lock(&t->task_state_lock); + t->task_state_flags |= SAS_TASK_AT_INITIATOR; + spin_unlock(&t->task_state_lock); + + mvs_hba_memory_dump(mvi, tag, t->task_proto); + mvi_dev->runing_req++; + ++pass; + mvi->tx_prod = (mvi->tx_prod + 1) & (MVS_CHIP_SLOT_SZ - 1); + if (n > 1) + t = list_entry(t->list.next, struct sas_task, list); + } while (--n); + rc = 0; + goto out_done; + +err_out_tag: + mvs_tag_free(mvi, tag); +err_out: + + dev_printk(KERN_ERR, mvi->dev, "mvsas exec failed[%d]!\n", rc); + if (!sas_protocol_ata(t->task_proto)) + if (n_elem) + dma_unmap_sg(mvi->dev, t->scatter, n_elem, + t->data_dir); +out_done: + if (likely(pass)) { + MVS_CHIP_DISP->start_delivery(mvi, + (mvi->tx_prod - 1) & (MVS_CHIP_SLOT_SZ - 1)); + } + spin_unlock_irqrestore(&mvi->lock, flags); + return rc; +} + +int mvs_queue_command(struct sas_task *task, const int num, + gfp_t gfp_flags) +{ + return mvs_task_exec(task, num, gfp_flags, NULL, 0, NULL); +} + +static void mvs_slot_free(struct mvs_info *mvi, u32 rx_desc) +{ + u32 slot_idx = rx_desc & RXQ_SLOT_MASK; + mvs_tag_clear(mvi, slot_idx); +} + +static void mvs_slot_task_free(struct mvs_info *mvi, struct sas_task *task, + struct mvs_slot_info *slot, u32 slot_idx) +{ + if (!slot->task) + return; + if (!sas_protocol_ata(task->task_proto)) + if (slot->n_elem) + dma_unmap_sg(mvi->dev, task->scatter, + slot->n_elem, task->data_dir); + + switch (task->task_proto) { + case SAS_PROTOCOL_SMP: + dma_unmap_sg(mvi->dev, &task->smp_task.smp_resp, 1, + PCI_DMA_FROMDEVICE); + dma_unmap_sg(mvi->dev, &task->smp_task.smp_req, 1, + PCI_DMA_TODEVICE); + break; + + case SAS_PROTOCOL_SATA: + case SAS_PROTOCOL_STP: + case SAS_PROTOCOL_SSP: + default: + /* do nothing */ + break; + } + list_del_init(&slot->entry); + task->lldd_task = NULL; + slot->task = NULL; + slot->port = NULL; + slot->slot_tag = 0xFFFFFFFF; + mvs_slot_free(mvi, slot_idx); +} + +static void mvs_update_wideport(struct mvs_info *mvi, int i) +{ + struct mvs_phy *phy = &mvi->phy[i]; + struct mvs_port *port = phy->port; + int j, no; + + for_each_phy(port->wide_port_phymap, j, no) { + if (j & 1) { + MVS_CHIP_DISP->write_port_cfg_addr(mvi, no, + PHYR_WIDE_PORT); + MVS_CHIP_DISP->write_port_cfg_data(mvi, no, + port->wide_port_phymap); + } else { + MVS_CHIP_DISP->write_port_cfg_addr(mvi, no, + PHYR_WIDE_PORT); + MVS_CHIP_DISP->write_port_cfg_data(mvi, no, + 0); + } + } +} + +static u32 mvs_is_phy_ready(struct mvs_info *mvi, int i) +{ + u32 tmp; + struct mvs_phy *phy = &mvi->phy[i]; + struct mvs_port *port = phy->port; + + tmp = MVS_CHIP_DISP->read_phy_ctl(mvi, i); + if ((tmp & PHY_READY_MASK) && !(phy->irq_status & PHYEV_POOF)) { + if (!port) + phy->phy_attached = 1; + return tmp; + } + + if (port) { + if (phy->phy_type & PORT_TYPE_SAS) { + port->wide_port_phymap &= ~(1U << i); + if (!port->wide_port_phymap) + port->port_attached = 0; + mvs_update_wideport(mvi, i); + } else if (phy->phy_type & PORT_TYPE_SATA) + port->port_attached = 0; + phy->port = NULL; + phy->phy_attached = 0; + phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA); + } + return 0; +} + +static void *mvs_get_d2h_reg(struct mvs_info *mvi, int i, void *buf) +{ + u32 *s = (u32 *) buf; + + if (!s) + return NULL; + + MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_SATA_SIG3); + s[3] = MVS_CHIP_DISP->read_port_cfg_data(mvi, i); + + MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_SATA_SIG2); + s[2] = MVS_CHIP_DISP->read_port_cfg_data(mvi, i); + + MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_SATA_SIG1); + s[1] = MVS_CHIP_DISP->read_port_cfg_data(mvi, i); + + MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_SATA_SIG0); + s[0] = MVS_CHIP_DISP->read_port_cfg_data(mvi, i); + + /* Workaround: take some ATAPI devices for ATA */ + if (((s[1] & 0x00FFFFFF) == 0x00EB1401) && (*(u8 *)&s[3] == 0x01)) + s[1] = 0x00EB1401 | (*((u8 *)&s[1] + 3) & 0x10); + + return s; +} + +static u32 mvs_is_sig_fis_received(u32 irq_status) +{ + return irq_status & PHYEV_SIG_FIS; +} + +void mvs_update_phyinfo(struct mvs_info *mvi, int i, int get_st) +{ + struct mvs_phy *phy = &mvi->phy[i]; + struct sas_identify_frame *id; + + id = (struct sas_identify_frame *)phy->frame_rcvd; + + if (get_st) { + phy->irq_status = MVS_CHIP_DISP->read_port_irq_stat(mvi, i); + phy->phy_status = mvs_is_phy_ready(mvi, i); + } + + if (phy->phy_status) { + int oob_done = 0; + struct asd_sas_phy *sas_phy = &mvi->phy[i].sas_phy; + + oob_done = MVS_CHIP_DISP->oob_done(mvi, i); + + MVS_CHIP_DISP->fix_phy_info(mvi, i, id); + if (phy->phy_type & PORT_TYPE_SATA) { + phy->identify.target_port_protocols = SAS_PROTOCOL_STP; + if (mvs_is_sig_fis_received(phy->irq_status)) { + phy->phy_attached = 1; + phy->att_dev_sas_addr = + i + mvi->id * mvi->chip->n_phy; + if (oob_done) + sas_phy->oob_mode = SATA_OOB_MODE; + phy->frame_rcvd_size = + sizeof(struct dev_to_host_fis); + mvs_get_d2h_reg(mvi, i, id); + } else { + u32 tmp; + dev_printk(KERN_DEBUG, mvi->dev, + "Phy%d : No sig fis\n", i); + tmp = MVS_CHIP_DISP->read_port_irq_mask(mvi, i); + MVS_CHIP_DISP->write_port_irq_mask(mvi, i, + tmp | PHYEV_SIG_FIS); + phy->phy_attached = 0; + phy->phy_type &= ~PORT_TYPE_SATA; + MVS_CHIP_DISP->phy_reset(mvi, i, 0); + goto out_done; + } + } else if (phy->phy_type & PORT_TYPE_SAS + || phy->att_dev_info & PORT_SSP_INIT_MASK) { + phy->phy_attached = 1; + phy->identify.device_type = + phy->att_dev_info & PORT_DEV_TYPE_MASK; + + if (phy->identify.device_type == SAS_END_DEV) + phy->identify.target_port_protocols = + SAS_PROTOCOL_SSP; + else if (phy->identify.device_type != NO_DEVICE) + phy->identify.target_port_protocols = + SAS_PROTOCOL_SMP; + if (oob_done) + sas_phy->oob_mode = SAS_OOB_MODE; + phy->frame_rcvd_size = + sizeof(struct sas_identify_frame); + } + memcpy(sas_phy->attached_sas_addr, + &phy->att_dev_sas_addr, SAS_ADDR_SIZE); + + if (MVS_CHIP_DISP->phy_work_around) + MVS_CHIP_DISP->phy_work_around(mvi, i); + } + mv_dprintk("port %d attach dev info is %x\n", + i + mvi->id * mvi->chip->n_phy, phy->att_dev_info); + mv_dprintk("port %d attach sas addr is %llx\n", + i + mvi->id * mvi->chip->n_phy, phy->att_dev_sas_addr); +out_done: + if (get_st) + MVS_CHIP_DISP->write_port_irq_stat(mvi, i, phy->irq_status); +} + +static void mvs_port_notify_formed(struct asd_sas_phy *sas_phy, int lock) +{ + struct sas_ha_struct *sas_ha = sas_phy->ha; + struct mvs_info *mvi = NULL; int i = 0, hi; + struct mvs_phy *phy = sas_phy->lldd_phy; + struct asd_sas_port *sas_port = sas_phy->port; + struct mvs_port *port; + unsigned long flags = 0; + if (!sas_port) + return; + + while (sas_ha->sas_phy[i]) { + if (sas_ha->sas_phy[i] == sas_phy) + break; + i++; + } + hi = i/((struct mvs_prv_info *)sas_ha->lldd_ha)->n_phy; + mvi = ((struct mvs_prv_info *)sas_ha->lldd_ha)->mvi[hi]; + if (sas_port->id >= mvi->chip->n_phy) + port = &mvi->port[sas_port->id - mvi->chip->n_phy]; + else + port = &mvi->port[sas_port->id]; + if (lock) + spin_lock_irqsave(&mvi->lock, flags); + port->port_attached = 1; + phy->port = port; + if (phy->phy_type & PORT_TYPE_SAS) { + port->wide_port_phymap = sas_port->phy_mask; + mv_printk("set wide port phy map %x\n", sas_port->phy_mask); + mvs_update_wideport(mvi, sas_phy->id); + } + if (lock) + spin_unlock_irqrestore(&mvi->lock, flags); +} + +static void mvs_port_notify_deformed(struct asd_sas_phy *sas_phy, int lock) +{ + /*Nothing*/ +} + + +void mvs_port_formed(struct asd_sas_phy *sas_phy) +{ + mvs_port_notify_formed(sas_phy, 1); +} + +void mvs_port_deformed(struct asd_sas_phy *sas_phy) +{ + mvs_port_notify_deformed(sas_phy, 1); +} + +struct mvs_device *mvs_alloc_dev(struct mvs_info *mvi) +{ + u32 dev; + for (dev = 0; dev < MVS_MAX_DEVICES; dev++) { + if (mvi->devices[dev].dev_type == NO_DEVICE) { + mvi->devices[dev].device_id = dev; + return &mvi->devices[dev]; + } + } + + if (dev == MVS_MAX_DEVICES) + mv_printk("max support %d devices, ignore ..\n", + MVS_MAX_DEVICES); + + return NULL; +} + +void mvs_free_dev(struct mvs_device *mvi_dev) +{ + u32 id = mvi_dev->device_id; + memset(mvi_dev, 0, sizeof(*mvi_dev)); + mvi_dev->device_id = id; + mvi_dev->dev_type = NO_DEVICE; + mvi_dev->dev_status = MVS_DEV_NORMAL; + mvi_dev->taskfileset = MVS_ID_NOT_MAPPED; +} + +int mvs_dev_found_notify(struct domain_device *dev, int lock) +{ + unsigned long flags = 0; + int res = 0; + struct mvs_info *mvi = NULL; + struct domain_device *parent_dev = dev->parent; + struct mvs_device *mvi_device; + + mvi = mvs_find_dev_mvi(dev); + + if (lock) + spin_lock_irqsave(&mvi->lock, flags); + + mvi_device = mvs_alloc_dev(mvi); + if (!mvi_device) { + res = -1; + goto found_out; + } + dev->lldd_dev = mvi_device; + mvi_device->dev_type = dev->dev_type; + mvi_device->mvi_info = mvi; + if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type)) { + int phy_id; + u8 phy_num = parent_dev->ex_dev.num_phys; + struct ex_phy *phy; + for (phy_id = 0; phy_id < phy_num; phy_id++) { + phy = &parent_dev->ex_dev.ex_phy[phy_id]; + if (SAS_ADDR(phy->attached_sas_addr) == + SAS_ADDR(dev->sas_addr)) { + mvi_device->attached_phy = phy_id; + break; + } + } + + if (phy_id == phy_num) { + mv_printk("Error: no attached dev:%016llx" + "at ex:%016llx.\n", + SAS_ADDR(dev->sas_addr), + SAS_ADDR(parent_dev->sas_addr)); + res = -1; + } + } + +found_out: + if (lock) + spin_unlock_irqrestore(&mvi->lock, flags); + return res; +} + +int mvs_dev_found(struct domain_device *dev) +{ + return mvs_dev_found_notify(dev, 1); +} + +void mvs_dev_gone_notify(struct domain_device *dev, int lock) +{ + unsigned long flags = 0; + struct mvs_device *mvi_dev = dev->lldd_dev; + struct mvs_info *mvi = mvi_dev->mvi_info; + + if (lock) + spin_lock_irqsave(&mvi->lock, flags); + + if (mvi_dev) { + mv_dprintk("found dev[%d:%x] is gone.\n", + mvi_dev->device_id, mvi_dev->dev_type); + mvs_free_reg_set(mvi, mvi_dev); + mvs_free_dev(mvi_dev); + } else { + mv_dprintk("found dev has gone.\n"); + } + dev->lldd_dev = NULL; + + if (lock) + spin_unlock_irqrestore(&mvi->lock, flags); +} + + +void mvs_dev_gone(struct domain_device *dev) +{ + mvs_dev_gone_notify(dev, 1); +} + +static struct sas_task *mvs_alloc_task(void) +{ + struct sas_task *task = kzalloc(sizeof(struct sas_task), GFP_KERNEL); + + if (task) { + INIT_LIST_HEAD(&task->list); + spin_lock_init(&task->task_state_lock); + task->task_state_flags = SAS_TASK_STATE_PENDING; + init_timer(&task->timer); + init_completion(&task->completion); + } + return task; +} + +static void mvs_free_task(struct sas_task *task) +{ + if (task) { + BUG_ON(!list_empty(&task->list)); + kfree(task); + } +} + +static void mvs_task_done(struct sas_task *task) +{ + if (!del_timer(&task->timer)) + return; + complete(&task->completion); +} + +static void mvs_tmf_timedout(unsigned long data) +{ + struct sas_task *task = (struct sas_task *)data; + + task->task_state_flags |= SAS_TASK_STATE_ABORTED; + complete(&task->completion); +} + +/* XXX */ +#define MVS_TASK_TIMEOUT 20 +static int mvs_exec_internal_tmf_task(struct domain_device *dev, + void *parameter, u32 para_len, struct mvs_tmf_task *tmf) +{ + int res, retry; + struct sas_task *task = NULL; + + for (retry = 0; retry < 3; retry++) { + task = mvs_alloc_task(); + if (!task) + return -ENOMEM; + + task->dev = dev; + task->task_proto = dev->tproto; + + memcpy(&task->ssp_task, parameter, para_len); + task->task_done = mvs_task_done; + + task->timer.data = (unsigned long) task; + task->timer.function = mvs_tmf_timedout; + task->timer.expires = jiffies + MVS_TASK_TIMEOUT*HZ; + add_timer(&task->timer); + + res = mvs_task_exec(task, 1, GFP_KERNEL, NULL, 1, tmf); + + if (res) { + del_timer(&task->timer); + mv_printk("executing internel task failed:%d\n", res); + goto ex_err; + } + + wait_for_completion(&task->completion); + res = -TMF_RESP_FUNC_FAILED; + /* Even TMF timed out, return direct. */ + if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) { + if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) { + mv_printk("TMF task[%x] timeout.\n", tmf->tmf); + goto ex_err; + } + } + + if (task->task_status.resp == SAS_TASK_COMPLETE && + task->task_status.stat == SAM_GOOD) { + res = TMF_RESP_FUNC_COMPLETE; + break; + } + + if (task->task_status.resp == SAS_TASK_COMPLETE && + task->task_status.stat == SAS_DATA_UNDERRUN) { + /* no error, but return the number of bytes of + * underrun */ + res = task->task_status.residual; + break; + } + + if (task->task_status.resp == SAS_TASK_COMPLETE && + task->task_status.stat == SAS_DATA_OVERRUN) { + mv_dprintk("blocked task error.\n"); + res = -EMSGSIZE; + break; + } else { + mv_dprintk(" task to dev %016llx response: 0x%x " + "status 0x%x\n", + SAS_ADDR(dev->sas_addr), + task->task_status.resp, + task->task_status.stat); + mvs_free_task(task); + task = NULL; + + } + } +ex_err: + BUG_ON(retry == 3 && task != NULL); + if (task != NULL) + mvs_free_task(task); + return res; +} + +static int mvs_debug_issue_ssp_tmf(struct domain_device *dev, + u8 *lun, struct mvs_tmf_task *tmf) +{ + struct sas_ssp_task ssp_task; + DECLARE_COMPLETION_ONSTACK(completion); + if (!(dev->tproto & SAS_PROTOCOL_SSP)) + return TMF_RESP_FUNC_ESUPP; + + strncpy((u8 *)&ssp_task.LUN, lun, 8); + + return mvs_exec_internal_tmf_task(dev, &ssp_task, + sizeof(ssp_task), tmf); +} + + +/* Standard mandates link reset for ATA (type 0) + and hard reset for SSP (type 1) , only for RECOVERY */ +static int mvs_debug_I_T_nexus_reset(struct domain_device *dev) +{ + int rc; + struct sas_phy *phy = sas_find_local_phy(dev); + int reset_type = (dev->dev_type == SATA_DEV || + (dev->tproto & SAS_PROTOCOL_STP)) ? 0 : 1; + rc = sas_phy_reset(phy, reset_type); + msleep(2000); + return rc; +} + +/* mandatory SAM-3 */ +int mvs_lu_reset(struct domain_device *dev, u8 *lun) +{ + unsigned long flags; + int i, phyno[WIDE_PORT_MAX_PHY], num , rc = TMF_RESP_FUNC_FAILED; + struct mvs_tmf_task tmf_task; + struct mvs_device * mvi_dev = dev->lldd_dev; + struct mvs_info *mvi = mvi_dev->mvi_info; + + tmf_task.tmf = TMF_LU_RESET; + mvi_dev->dev_status = MVS_DEV_EH; + rc = mvs_debug_issue_ssp_tmf(dev, lun, &tmf_task); + if (rc == TMF_RESP_FUNC_COMPLETE) { + num = mvs_find_dev_phyno(dev, phyno); + spin_lock_irqsave(&mvi->lock, flags); + for (i = 0; i < num; i++) + mvs_release_task(mvi, phyno[i], dev); + spin_unlock_irqrestore(&mvi->lock, flags); + } + /* If failed, fall-through I_T_Nexus reset */ + mv_printk("%s for device[%x]:rc= %d\n", __func__, + mvi_dev->device_id, rc); + return rc; +} + +int mvs_I_T_nexus_reset(struct domain_device *dev) +{ + unsigned long flags; + int i, phyno[WIDE_PORT_MAX_PHY], num , rc = TMF_RESP_FUNC_FAILED; + struct mvs_device * mvi_dev = (struct mvs_device *)dev->lldd_dev; + struct mvs_info *mvi = mvi_dev->mvi_info; + + if (mvi_dev->dev_status != MVS_DEV_EH) + return TMF_RESP_FUNC_COMPLETE; + rc = mvs_debug_I_T_nexus_reset(dev); + mv_printk("%s for device[%x]:rc= %d\n", + __func__, mvi_dev->device_id, rc); + + /* housekeeper */ + num = mvs_find_dev_phyno(dev, phyno); + spin_lock_irqsave(&mvi->lock, flags); + for (i = 0; i < num; i++) + mvs_release_task(mvi, phyno[i], dev); + spin_unlock_irqrestore(&mvi->lock, flags); + + return rc; +} +/* optional SAM-3 */ +int mvs_query_task(struct sas_task *task) +{ + u32 tag; + struct scsi_lun lun; + struct mvs_tmf_task tmf_task; + int rc = TMF_RESP_FUNC_FAILED; + + if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SSP) { + struct scsi_cmnd * cmnd = (struct scsi_cmnd *)task->uldd_task; + struct domain_device *dev = task->dev; + struct mvs_device *mvi_dev = (struct mvs_device *)dev->lldd_dev; + struct mvs_info *mvi = mvi_dev->mvi_info; + + int_to_scsilun(cmnd->device->lun, &lun); + rc = mvs_find_tag(mvi, task, &tag); + if (rc == 0) { + rc = TMF_RESP_FUNC_FAILED; + return rc; + } + + tmf_task.tmf = TMF_QUERY_TASK; + tmf_task.tag_of_task_to_be_managed = cpu_to_le16(tag); + + rc = mvs_debug_issue_ssp_tmf(dev, lun.scsi_lun, &tmf_task); + switch (rc) { + /* The task is still in Lun, release it then */ + case TMF_RESP_FUNC_SUCC: + /* The task is not in Lun or failed, reset the phy */ + case TMF_RESP_FUNC_FAILED: + case TMF_RESP_FUNC_COMPLETE: + break; + } + } + mv_printk("%s:rc= %d\n", __func__, rc); + return rc; +} + +/* mandatory SAM-3, still need free task/slot info */ +int mvs_abort_task(struct sas_task *task) +{ + struct scsi_lun lun; + struct mvs_tmf_task tmf_task; + struct domain_device *dev = task->dev; + struct mvs_device *mvi_dev = (struct mvs_device *)dev->lldd_dev; + struct mvs_info *mvi = mvi_dev->mvi_info; + int rc = TMF_RESP_FUNC_FAILED; + unsigned long flags; + u32 tag; + + if (mvi->exp_req) + mvi->exp_req--; + spin_lock_irqsave(&task->task_state_lock, flags); + if (task->task_state_flags & SAS_TASK_STATE_DONE) { + spin_unlock_irqrestore(&task->task_state_lock, flags); + rc = TMF_RESP_FUNC_COMPLETE; + goto out; + } + spin_unlock_irqrestore(&task->task_state_lock, flags); + if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SSP) { + struct scsi_cmnd * cmnd = (struct scsi_cmnd *)task->uldd_task; + + int_to_scsilun(cmnd->device->lun, &lun); + rc = mvs_find_tag(mvi, task, &tag); + if (rc == 0) { + mv_printk("No such tag in %s\n", __func__); + rc = TMF_RESP_FUNC_FAILED; + return rc; + } + + tmf_task.tmf = TMF_ABORT_TASK; + tmf_task.tag_of_task_to_be_managed = cpu_to_le16(tag); + + rc = mvs_debug_issue_ssp_tmf(dev, lun.scsi_lun, &tmf_task); + + /* if successful, clear the task and callback forwards.*/ + if (rc == TMF_RESP_FUNC_COMPLETE) { + u32 slot_no; + struct mvs_slot_info *slot; + + if (task->lldd_task) { + slot = task->lldd_task; + slot_no = (u32) (slot - mvi->slot_info); + mvs_slot_complete(mvi, slot_no, 1); + } + } + } else if (task->task_proto & SAS_PROTOCOL_SATA || + task->task_proto & SAS_PROTOCOL_STP) { + /* to do free register_set */ + } else { + /* SMP */ + + } +out: + if (rc != TMF_RESP_FUNC_COMPLETE) + mv_printk("%s:rc= %d\n", __func__, rc); + return rc; +} + +int mvs_abort_task_set(struct domain_device *dev, u8 *lun) +{ + int rc = TMF_RESP_FUNC_FAILED; + struct mvs_tmf_task tmf_task; + + tmf_task.tmf = TMF_ABORT_TASK_SET; + rc = mvs_debug_issue_ssp_tmf(dev, lun, &tmf_task); + + return rc; +} + +int mvs_clear_aca(struct domain_device *dev, u8 *lun) +{ + int rc = TMF_RESP_FUNC_FAILED; + struct mvs_tmf_task tmf_task; + + tmf_task.tmf = TMF_CLEAR_ACA; + rc = mvs_debug_issue_ssp_tmf(dev, lun, &tmf_task); + + return rc; +} + +int mvs_clear_task_set(struct domain_device *dev, u8 *lun) +{ + int rc = TMF_RESP_FUNC_FAILED; + struct mvs_tmf_task tmf_task; + + tmf_task.tmf = TMF_CLEAR_TASK_SET; + rc = mvs_debug_issue_ssp_tmf(dev, lun, &tmf_task); + + return rc; +} + +static int mvs_sata_done(struct mvs_info *mvi, struct sas_task *task, + u32 slot_idx, int err) +{ + struct mvs_device *mvi_dev = task->dev->lldd_dev; + struct task_status_struct *tstat = &task->task_status; + struct ata_task_resp *resp = (struct ata_task_resp *)tstat->buf; + int stat = SAM_GOOD; + + + resp->frame_len = sizeof(struct dev_to_host_fis); + memcpy(&resp->ending_fis[0], + SATA_RECEIVED_D2H_FIS(mvi_dev->taskfileset), + sizeof(struct dev_to_host_fis)); + tstat->buf_valid_size = sizeof(*resp); + if (unlikely(err)) + stat = SAS_PROTO_RESPONSE; + return stat; +} + +static int mvs_slot_err(struct mvs_info *mvi, struct sas_task *task, + u32 slot_idx) +{ + struct mvs_slot_info *slot = &mvi->slot_info[slot_idx]; + int stat; + u32 err_dw0 = le32_to_cpu(*(u32 *) (slot->response)); + u32 tfs = 0; + enum mvs_port_type type = PORT_TYPE_SAS; + + if (err_dw0 & CMD_ISS_STPD) + MVS_CHIP_DISP->issue_stop(mvi, type, tfs); + + MVS_CHIP_DISP->command_active(mvi, slot_idx); + + stat = SAM_CHECK_COND; + switch (task->task_proto) { + case SAS_PROTOCOL_SSP: + stat = SAS_ABORTED_TASK; + break; + case SAS_PROTOCOL_SMP: + stat = SAM_CHECK_COND; + break; + + case SAS_PROTOCOL_SATA: + case SAS_PROTOCOL_STP: + case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: + { + if (err_dw0 == 0x80400002) + mv_printk("find reserved error, why?\n"); + + task->ata_task.use_ncq = 0; + stat = SAS_PROTO_RESPONSE; + mvs_sata_done(mvi, task, slot_idx, 1); + + } + break; + default: + break; + } + + return stat; +} + +int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags) +{ + u32 slot_idx = rx_desc & RXQ_SLOT_MASK; + struct mvs_slot_info *slot = &mvi->slot_info[slot_idx]; + struct sas_task *task = slot->task; + struct mvs_device *mvi_dev = NULL; + struct task_status_struct *tstat; + + bool aborted; + void *to; + enum exec_status sts; + + if (mvi->exp_req) + mvi->exp_req--; + if (unlikely(!task || !task->lldd_task)) + return -1; + + tstat = &task->task_status; + mvi_dev = task->dev->lldd_dev; + + mvs_hba_cq_dump(mvi); + + spin_lock(&task->task_state_lock); + task->task_state_flags &= + ~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR); + task->task_state_flags |= SAS_TASK_STATE_DONE; + /* race condition*/ + aborted = task->task_state_flags & SAS_TASK_STATE_ABORTED; + spin_unlock(&task->task_state_lock); + + memset(tstat, 0, sizeof(*tstat)); + tstat->resp = SAS_TASK_COMPLETE; + + if (unlikely(aborted)) { + tstat->stat = SAS_ABORTED_TASK; + if (mvi_dev) + mvi_dev->runing_req--; + if (sas_protocol_ata(task->task_proto)) + mvs_free_reg_set(mvi, mvi_dev); + + mvs_slot_task_free(mvi, task, slot, slot_idx); + return -1; + } + + if (unlikely(!mvi_dev || !slot->port->port_attached || flags)) { + mv_dprintk("port has not device.\n"); + tstat->stat = SAS_PHY_DOWN; + goto out; + } + + /* + if (unlikely((rx_desc & RXQ_ERR) || (*(u64 *) slot->response))) { + mv_dprintk("Find device[%016llx] RXQ_ERR %X, + err info:%016llx\n", + SAS_ADDR(task->dev->sas_addr), + rx_desc, (u64)(*(u64 *) slot->response)); + } + */ + + /* error info record present */ + if (unlikely((rx_desc & RXQ_ERR) && (*(u64 *) slot->response))) { + tstat->stat = mvs_slot_err(mvi, task, slot_idx); + goto out; + } + + switch (task->task_proto) { + case SAS_PROTOCOL_SSP: + /* hw says status == 0, datapres == 0 */ + if (rx_desc & RXQ_GOOD) { + tstat->stat = SAM_GOOD; + tstat->resp = SAS_TASK_COMPLETE; + } + /* response frame present */ + else if (rx_desc & RXQ_RSP) { + struct ssp_response_iu *iu = slot->response + + sizeof(struct mvs_err_info); + sas_ssp_task_response(mvi->dev, task, iu); + } else + tstat->stat = SAM_CHECK_COND; + break; + + case SAS_PROTOCOL_SMP: { + struct scatterlist *sg_resp = &task->smp_task.smp_resp; + tstat->stat = SAM_GOOD; + to = kmap_atomic(sg_page(sg_resp), KM_IRQ0); + memcpy(to + sg_resp->offset, + slot->response + sizeof(struct mvs_err_info), + sg_dma_len(sg_resp)); + kunmap_atomic(to, KM_IRQ0); + break; + } + + case SAS_PROTOCOL_SATA: + case SAS_PROTOCOL_STP: + case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: { + tstat->stat = mvs_sata_done(mvi, task, slot_idx, 0); + break; + } + + default: + tstat->stat = SAM_CHECK_COND; + break; + } + +out: + if (mvi_dev) { + mvi_dev->runing_req--; + if (sas_protocol_ata(task->task_proto)) + mvs_free_reg_set(mvi, mvi_dev); + } + mvs_slot_task_free(mvi, task, slot, slot_idx); + sts = tstat->stat; + + spin_unlock(&mvi->lock); + if (task->task_done) + task->task_done(task); + else + mv_dprintk("why has not task_done.\n"); + spin_lock(&mvi->lock); + + return sts; +} + +void mvs_release_task(struct mvs_info *mvi, + int phy_no, struct domain_device *dev) +{ + int i = 0; u32 slot_idx; + struct mvs_phy *phy; + struct mvs_port *port; + struct mvs_slot_info *slot, *slot2; + + phy = &mvi->phy[phy_no]; + port = phy->port; + if (!port) + return; + + list_for_each_entry_safe(slot, slot2, &port->list, entry) { + struct sas_task *task; + slot_idx = (u32) (slot - mvi->slot_info); + task = slot->task; + + if (dev && task->dev != dev) + continue; + + mv_printk("Release slot [%x] tag[%x], task [%p]:\n", + slot_idx, slot->slot_tag, task); + + if (task->task_proto & SAS_PROTOCOL_SSP) { + mv_printk("attached with SSP task CDB["); + for (i = 0; i < 16; i++) + mv_printk(" %02x", task->ssp_task.cdb[i]); + mv_printk(" ]\n"); + } + + mvs_slot_complete(mvi, slot_idx, 1); + } +} + +static void mvs_phy_disconnected(struct mvs_phy *phy) +{ + phy->phy_attached = 0; + phy->att_dev_info = 0; + phy->att_dev_sas_addr = 0; +} + +static void mvs_work_queue(struct work_struct *work) +{ + struct delayed_work *dw = container_of(work, struct delayed_work, work); + struct mvs_wq *mwq = container_of(dw, struct mvs_wq, work_q); + struct mvs_info *mvi = mwq->mvi; + unsigned long flags; + + spin_lock_irqsave(&mvi->lock, flags); + if (mwq->handler & PHY_PLUG_EVENT) { + u32 phy_no = (unsigned long) mwq->data; + struct sas_ha_struct *sas_ha = mvi->sas; + struct mvs_phy *phy = &mvi->phy[phy_no]; + struct asd_sas_phy *sas_phy = &phy->sas_phy; + + if (phy->phy_event & PHY_PLUG_OUT) { + u32 tmp; + struct sas_identify_frame *id; + id = (struct sas_identify_frame *)phy->frame_rcvd; + tmp = MVS_CHIP_DISP->read_phy_ctl(mvi, phy_no); + phy->phy_event &= ~PHY_PLUG_OUT; + if (!(tmp & PHY_READY_MASK)) { + sas_phy_disconnected(sas_phy); + mvs_phy_disconnected(phy); + sas_ha->notify_phy_event(sas_phy, + PHYE_LOSS_OF_SIGNAL); + mv_dprintk("phy%d Removed Device\n", phy_no); + } else { + MVS_CHIP_DISP->detect_porttype(mvi, phy_no); + mvs_update_phyinfo(mvi, phy_no, 1); + mvs_bytes_dmaed(mvi, phy_no); + mvs_port_notify_formed(sas_phy, 0); + mv_dprintk("phy%d Attached Device\n", phy_no); + } + } + } + list_del(&mwq->entry); + spin_unlock_irqrestore(&mvi->lock, flags); + kfree(mwq); +} + +static int mvs_handle_event(struct mvs_info *mvi, void *data, int handler) +{ + struct mvs_wq *mwq; + int ret = 0; + + mwq = kmalloc(sizeof(struct mvs_wq), GFP_ATOMIC); + if (mwq) { + mwq->mvi = mvi; + mwq->data = data; + mwq->handler = handler; + MV_INIT_DELAYED_WORK(&mwq->work_q, mvs_work_queue, mwq); + list_add_tail(&mwq->entry, &mvi->wq_list); + schedule_delayed_work(&mwq->work_q, HZ * 2); + } else + ret = -ENOMEM; + + return ret; +} + +static void mvs_sig_time_out(unsigned long tphy) +{ + struct mvs_phy *phy = (struct mvs_phy *)tphy; + struct mvs_info *mvi = phy->mvi; + u8 phy_no; + + for (phy_no = 0; phy_no < mvi->chip->n_phy; phy_no++) { + if (&mvi->phy[phy_no] == phy) { + mv_dprintk("Get signature time out, reset phy %d\n", + phy_no+mvi->id*mvi->chip->n_phy); + MVS_CHIP_DISP->phy_reset(mvi, phy_no, 1); + } + } +} + +static void mvs_sig_remove_timer(struct mvs_phy *phy) +{ + if (phy->timer.function) + del_timer(&phy->timer); + phy->timer.function = NULL; +} + +void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events) +{ + u32 tmp; + struct sas_ha_struct *sas_ha = mvi->sas; + struct mvs_phy *phy = &mvi->phy[phy_no]; + struct asd_sas_phy *sas_phy = &phy->sas_phy; + + phy->irq_status = MVS_CHIP_DISP->read_port_irq_stat(mvi, phy_no); + mv_dprintk("port %d ctrl sts=0x%X.\n", phy_no+mvi->id*mvi->chip->n_phy, + MVS_CHIP_DISP->read_phy_ctl(mvi, phy_no)); + mv_dprintk("Port %d irq sts = 0x%X\n", phy_no+mvi->id*mvi->chip->n_phy, + phy->irq_status); + + /* + * events is port event now , + * we need check the interrupt status which belongs to per port. + */ + + if (phy->irq_status & PHYEV_DCDR_ERR) + mv_dprintk("port %d STP decoding error.\n", + phy_no+mvi->id*mvi->chip->n_phy); + + if (phy->irq_status & PHYEV_POOF) { + if (!(phy->phy_event & PHY_PLUG_OUT)) { + int dev_sata = phy->phy_type & PORT_TYPE_SATA; + int ready; + mvs_release_task(mvi, phy_no, NULL); + phy->phy_event |= PHY_PLUG_OUT; + mvs_handle_event(mvi, + (void *)(unsigned long)phy_no, + PHY_PLUG_EVENT); + ready = mvs_is_phy_ready(mvi, phy_no); + if (!ready) + mv_dprintk("phy%d Unplug Notice\n", + phy_no + + mvi->id * mvi->chip->n_phy); + if (ready || dev_sata) { + if (MVS_CHIP_DISP->stp_reset) + MVS_CHIP_DISP->stp_reset(mvi, + phy_no); + else + MVS_CHIP_DISP->phy_reset(mvi, + phy_no, 0); + return; + } + } + } + + if (phy->irq_status & PHYEV_COMWAKE) { + tmp = MVS_CHIP_DISP->read_port_irq_mask(mvi, phy_no); + MVS_CHIP_DISP->write_port_irq_mask(mvi, phy_no, + tmp | PHYEV_SIG_FIS); + if (phy->timer.function == NULL) { + phy->timer.data = (unsigned long)phy; + phy->timer.function = mvs_sig_time_out; + phy->timer.expires = jiffies + 10*HZ; + add_timer(&phy->timer); + } + } + if (phy->irq_status & (PHYEV_SIG_FIS | PHYEV_ID_DONE)) { + phy->phy_status = mvs_is_phy_ready(mvi, phy_no); + mvs_sig_remove_timer(phy); + mv_dprintk("notify plug in on phy[%d]\n", phy_no); + if (phy->phy_status) { + mdelay(10); + MVS_CHIP_DISP->detect_porttype(mvi, phy_no); + if (phy->phy_type & PORT_TYPE_SATA) { + tmp = MVS_CHIP_DISP->read_port_irq_mask( + mvi, phy_no); + tmp &= ~PHYEV_SIG_FIS; + MVS_CHIP_DISP->write_port_irq_mask(mvi, + phy_no, tmp); + } + mvs_update_phyinfo(mvi, phy_no, 0); + mvs_bytes_dmaed(mvi, phy_no); + /* whether driver is going to handle hot plug */ + if (phy->phy_event & PHY_PLUG_OUT) { + mvs_port_notify_formed(sas_phy, 0); + phy->phy_event &= ~PHY_PLUG_OUT; + } + } else { + mv_dprintk("plugin interrupt but phy%d is gone\n", + phy_no + mvi->id*mvi->chip->n_phy); + } + } else if (phy->irq_status & PHYEV_BROAD_CH) { + mv_dprintk("port %d broadcast change.\n", + phy_no + mvi->id*mvi->chip->n_phy); + /* exception for Samsung disk drive*/ + mdelay(1000); + sas_ha->notify_port_event(sas_phy, PORTE_BROADCAST_RCVD); + } + MVS_CHIP_DISP->write_port_irq_stat(mvi, phy_no, phy->irq_status); +} + +int mvs_int_rx(struct mvs_info *mvi, bool self_clear) +{ + u32 rx_prod_idx, rx_desc; + bool attn = false; + + /* the first dword in the RX ring is special: it contains + * a mirror of the hardware's RX producer index, so that + * we don't have to stall the CPU reading that register. + * The actual RX ring is offset by one dword, due to this. + */ + rx_prod_idx = mvi->rx_cons; + mvi->rx_cons = le32_to_cpu(mvi->rx[0]); + if (mvi->rx_cons == 0xfff) /* h/w hasn't touched RX ring yet */ + return 0; + + /* The CMPL_Q may come late, read from register and try again + * note: if coalescing is enabled, + * it will need to read from register every time for sure + */ + if (unlikely(mvi->rx_cons == rx_prod_idx)) + mvi->rx_cons = MVS_CHIP_DISP->rx_update(mvi) & RX_RING_SZ_MASK; + + if (mvi->rx_cons == rx_prod_idx) + return 0; + + while (mvi->rx_cons != rx_prod_idx) { + /* increment our internal RX consumer pointer */ + rx_prod_idx = (rx_prod_idx + 1) & (MVS_RX_RING_SZ - 1); + rx_desc = le32_to_cpu(mvi->rx[rx_prod_idx + 1]); + + if (likely(rx_desc & RXQ_DONE)) + mvs_slot_complete(mvi, rx_desc, 0); + if (rx_desc & RXQ_ATTN) { + attn = true; + } else if (rx_desc & RXQ_ERR) { + if (!(rx_desc & RXQ_DONE)) + mvs_slot_complete(mvi, rx_desc, 0); + } else if (rx_desc & RXQ_SLOT_RESET) { + mvs_slot_free(mvi, rx_desc); + } + } + + if (attn && self_clear) + MVS_CHIP_DISP->int_full(mvi); + return 0; +} + diff --git a/drivers/scsi/mvsas/mv_sas.h b/drivers/scsi/mvsas/mv_sas.h new file mode 100644 index 000000000000..aa2270af1bac --- /dev/null +++ b/drivers/scsi/mvsas/mv_sas.h @@ -0,0 +1,406 @@ +/* + * Marvell 88SE64xx/88SE94xx main function head file + * + * Copyright 2007 Red Hat, Inc. + * Copyright 2008 Marvell. + * + * This file is licensed under GPLv2. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2 of the + * License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA +*/ + +#ifndef _MV_SAS_H_ +#define _MV_SAS_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mv_defs.h" + +#define DRV_NAME "mvsas" +#define DRV_VERSION "0.8.2" +#define _MV_DUMP 0 +#define MVS_ID_NOT_MAPPED 0x7f +/* #define DISABLE_HOTPLUG_DMA_FIX */ +#define MAX_EXP_RUNNING_REQ 2 +#define WIDE_PORT_MAX_PHY 4 +#define MV_DISABLE_NCQ 0 +#define mv_printk(fmt, arg ...) \ + printk(KERN_DEBUG"%s %d:" fmt, __FILE__, __LINE__, ## arg) +#ifdef MV_DEBUG +#define mv_dprintk(format, arg...) \ + printk(KERN_DEBUG"%s %d:" format, __FILE__, __LINE__, ## arg) +#else +#define mv_dprintk(format, arg...) +#endif +#define MV_MAX_U32 0xffffffff + +extern struct mvs_tgt_initiator mvs_tgt; +extern struct mvs_info *tgt_mvi; +extern const struct mvs_dispatch mvs_64xx_dispatch; +extern const struct mvs_dispatch mvs_94xx_dispatch; + +#define DEV_IS_EXPANDER(type) \ + ((type == EDGE_DEV) || (type == FANOUT_DEV)) + +#define bit(n) ((u32)1 << n) + +#define for_each_phy(__lseq_mask, __mc, __lseq) \ + for ((__mc) = (__lseq_mask), (__lseq) = 0; \ + (__mc) != 0 ; \ + (++__lseq), (__mc) >>= 1) + +#define MV_INIT_DELAYED_WORK(w, f, d) INIT_DELAYED_WORK(w, f) +#define UNASSOC_D2H_FIS(id) \ + ((void *) mvi->rx_fis + 0x100 * id) +#define SATA_RECEIVED_FIS_LIST(reg_set) \ + ((void *) mvi->rx_fis + mvi->chip->fis_offs + 0x100 * reg_set) +#define SATA_RECEIVED_SDB_FIS(reg_set) \ + (SATA_RECEIVED_FIS_LIST(reg_set) + 0x58) +#define SATA_RECEIVED_D2H_FIS(reg_set) \ + (SATA_RECEIVED_FIS_LIST(reg_set) + 0x40) +#define SATA_RECEIVED_PIO_FIS(reg_set) \ + (SATA_RECEIVED_FIS_LIST(reg_set) + 0x20) +#define SATA_RECEIVED_DMA_FIS(reg_set) \ + (SATA_RECEIVED_FIS_LIST(reg_set) + 0x00) + +enum dev_status { + MVS_DEV_NORMAL = 0x0, + MVS_DEV_EH = 0x1, +}; + + +struct mvs_info; + +struct mvs_dispatch { + char *name; + int (*chip_init)(struct mvs_info *mvi); + int (*spi_init)(struct mvs_info *mvi); + int (*chip_ioremap)(struct mvs_info *mvi); + void (*chip_iounmap)(struct mvs_info *mvi); + irqreturn_t (*isr)(struct mvs_info *mvi, int irq, u32 stat); + u32 (*isr_status)(struct mvs_info *mvi, int irq); + void (*interrupt_enable)(struct mvs_info *mvi); + void (*interrupt_disable)(struct mvs_info *mvi); + + u32 (*read_phy_ctl)(struct mvs_info *mvi, u32 port); + void (*write_phy_ctl)(struct mvs_info *mvi, u32 port, u32 val); + + u32 (*read_port_cfg_data)(struct mvs_info *mvi, u32 port); + void (*write_port_cfg_data)(struct mvs_info *mvi, u32 port, u32 val); + void (*write_port_cfg_addr)(struct mvs_info *mvi, u32 port, u32 addr); + + u32 (*read_port_vsr_data)(struct mvs_info *mvi, u32 port); + void (*write_port_vsr_data)(struct mvs_info *mvi, u32 port, u32 val); + void (*write_port_vsr_addr)(struct mvs_info *mvi, u32 port, u32 addr); + + u32 (*read_port_irq_stat)(struct mvs_info *mvi, u32 port); + void (*write_port_irq_stat)(struct mvs_info *mvi, u32 port, u32 val); + + u32 (*read_port_irq_mask)(struct mvs_info *mvi, u32 port); + void (*write_port_irq_mask)(struct mvs_info *mvi, u32 port, u32 val); + + void (*get_sas_addr)(void *buf, u32 buflen); + void (*command_active)(struct mvs_info *mvi, u32 slot_idx); + void (*issue_stop)(struct mvs_info *mvi, enum mvs_port_type type, + u32 tfs); + void (*start_delivery)(struct mvs_info *mvi, u32 tx); + u32 (*rx_update)(struct mvs_info *mvi); + void (*int_full)(struct mvs_info *mvi); + u8 (*assign_reg_set)(struct mvs_info *mvi, u8 *tfs); + void (*free_reg_set)(struct mvs_info *mvi, u8 *tfs); + u32 (*prd_size)(void); + u32 (*prd_count)(void); + void (*make_prd)(struct scatterlist *scatter, int nr, void *prd); + void (*detect_porttype)(struct mvs_info *mvi, int i); + int (*oob_done)(struct mvs_info *mvi, int i); + void (*fix_phy_info)(struct mvs_info *mvi, int i, + struct sas_identify_frame *id); + void (*phy_work_around)(struct mvs_info *mvi, int i); + void (*phy_set_link_rate)(struct mvs_info *mvi, u32 phy_id, + struct sas_phy_linkrates *rates); + u32 (*phy_max_link_rate)(void); + void (*phy_disable)(struct mvs_info *mvi, u32 phy_id); + void (*phy_enable)(struct mvs_info *mvi, u32 phy_id); + void (*phy_reset)(struct mvs_info *mvi, u32 phy_id, int hard); + void (*stp_reset)(struct mvs_info *mvi, u32 phy_id); + void (*clear_active_cmds)(struct mvs_info *mvi); + u32 (*spi_read_data)(struct mvs_info *mvi); + void (*spi_write_data)(struct mvs_info *mvi, u32 data); + int (*spi_buildcmd)(struct mvs_info *mvi, + u32 *dwCmd, + u8 cmd, + u8 read, + u8 length, + u32 addr + ); + int (*spi_issuecmd)(struct mvs_info *mvi, u32 cmd); + int (*spi_waitdataready)(struct mvs_info *mvi, u32 timeout); +#ifndef DISABLE_HOTPLUG_DMA_FIX + void (*dma_fix)(dma_addr_t buf_dma, int buf_len, int from, void *prd); +#endif + +}; + +struct mvs_chip_info { + u32 n_host; + u32 n_phy; + u32 fis_offs; + u32 fis_count; + u32 srs_sz; + u32 slot_width; + const struct mvs_dispatch *dispatch; +}; +#define MVS_CHIP_SLOT_SZ (1U << mvi->chip->slot_width) +#define MVS_RX_FISL_SZ \ + (mvi->chip->fis_offs + (mvi->chip->fis_count * 0x100)) +#define MVS_CHIP_DISP (mvi->chip->dispatch) + +struct mvs_err_info { + __le32 flags; + __le32 flags2; +}; + +struct mvs_cmd_hdr { + __le32 flags; /* PRD tbl len; SAS, SATA ctl */ + __le32 lens; /* cmd, max resp frame len */ + __le32 tags; /* targ port xfer tag; tag */ + __le32 data_len; /* data xfer len */ + __le64 cmd_tbl; /* command table address */ + __le64 open_frame; /* open addr frame address */ + __le64 status_buf; /* status buffer address */ + __le64 prd_tbl; /* PRD tbl address */ + __le32 reserved[4]; +}; + +struct mvs_port { + struct asd_sas_port sas_port; + u8 port_attached; + u8 wide_port_phymap; + struct list_head list; +}; + +struct mvs_phy { + struct mvs_info *mvi; + struct mvs_port *port; + struct asd_sas_phy sas_phy; + struct sas_identify identify; + struct scsi_device *sdev; + struct timer_list timer; + u64 dev_sas_addr; + u64 att_dev_sas_addr; + u32 att_dev_info; + u32 dev_info; + u32 phy_type; + u32 phy_status; + u32 irq_status; + u32 frame_rcvd_size; + u8 frame_rcvd[32]; + u8 phy_attached; + u8 phy_mode; + u8 reserved[2]; + u32 phy_event; + enum sas_linkrate minimum_linkrate; + enum sas_linkrate maximum_linkrate; +}; + +struct mvs_device { + struct list_head dev_entry; + enum sas_dev_type dev_type; + struct mvs_info *mvi_info; + struct domain_device *sas_device; + u32 attached_phy; + u32 device_id; + u32 runing_req; + u8 taskfileset; + u8 dev_status; + u16 reserved; +}; + +struct mvs_slot_info { + struct list_head entry; + union { + struct sas_task *task; + void *tdata; + }; + u32 n_elem; + u32 tx; + u32 slot_tag; + + /* DMA buffer for storing cmd tbl, open addr frame, status buffer, + * and PRD table + */ + void *buf; + dma_addr_t buf_dma; +#if _MV_DUMP + u32 cmd_size; +#endif + void *response; + struct mvs_port *port; + struct mvs_device *device; + void *open_frame; +}; + +struct mvs_info { + unsigned long flags; + + /* host-wide lock */ + spinlock_t lock; + + /* our device */ + struct pci_dev *pdev; + struct device *dev; + + /* enhanced mode registers */ + void __iomem *regs; + + /* peripheral or soc registers */ + void __iomem *regs_ex; + u8 sas_addr[SAS_ADDR_SIZE]; + + /* SCSI/SAS glue */ + struct sas_ha_struct *sas; + struct Scsi_Host *shost; + + /* TX (delivery) DMA ring */ + __le32 *tx; + dma_addr_t tx_dma; + + /* cached next-producer idx */ + u32 tx_prod; + + /* RX (completion) DMA ring */ + __le32 *rx; + dma_addr_t rx_dma; + + /* RX consumer idx */ + u32 rx_cons; + + /* RX'd FIS area */ + __le32 *rx_fis; + dma_addr_t rx_fis_dma; + + /* DMA command header slots */ + struct mvs_cmd_hdr *slot; + dma_addr_t slot_dma; + + u32 chip_id; + const struct mvs_chip_info *chip; + + int tags_num; + DECLARE_BITMAP(tags, MVS_SLOTS); + /* further per-slot information */ + struct mvs_phy phy[MVS_MAX_PHYS]; + struct mvs_port port[MVS_MAX_PHYS]; + u32 irq; + u32 exp_req; + u32 id; + u64 sata_reg_set; + struct list_head *hba_list; + struct list_head soc_entry; + struct list_head wq_list; + unsigned long instance; + u16 flashid; + u32 flashsize; + u32 flashsectSize; + + void *addon; + struct mvs_device devices[MVS_MAX_DEVICES]; +#ifndef DISABLE_HOTPLUG_DMA_FIX + void *bulk_buffer; + dma_addr_t bulk_buffer_dma; +#define TRASH_BUCKET_SIZE 0x20000 +#endif + struct mvs_slot_info slot_info[0]; +}; + +struct mvs_prv_info{ + u8 n_host; + u8 n_phy; + u16 reserve; + struct mvs_info *mvi[2]; +}; + +struct mvs_wq { + struct delayed_work work_q; + struct mvs_info *mvi; + void *data; + int handler; + struct list_head entry; +}; + +struct mvs_task_exec_info { + struct sas_task *task; + struct mvs_cmd_hdr *hdr; + struct mvs_port *port; + u32 tag; + int n_elem; +}; + + +/******************** function prototype *********************/ +void mvs_get_sas_addr(void *buf, u32 buflen); +void mvs_tag_clear(struct mvs_info *mvi, u32 tag); +void mvs_tag_free(struct mvs_info *mvi, u32 tag); +void mvs_tag_set(struct mvs_info *mvi, unsigned int tag); +int mvs_tag_alloc(struct mvs_info *mvi, u32 *tag_out); +void mvs_tag_init(struct mvs_info *mvi); +void mvs_iounmap(void __iomem *regs); +int mvs_ioremap(struct mvs_info *mvi, int bar, int bar_ex); +void mvs_phys_reset(struct mvs_info *mvi, u32 phy_mask, int hard); +int mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func, + void *funcdata); +void __devinit mvs_set_sas_addr(struct mvs_info *mvi, int port_id, + u32 off_lo, u32 off_hi, u64 sas_addr); +int mvs_slave_alloc(struct scsi_device *scsi_dev); +int mvs_slave_configure(struct scsi_device *sdev); +void mvs_scan_start(struct Scsi_Host *shost); +int mvs_scan_finished(struct Scsi_Host *shost, unsigned long time); +int mvs_queue_command(struct sas_task *task, const int num, + gfp_t gfp_flags); +int mvs_abort_task(struct sas_task *task); +int mvs_abort_task_set(struct domain_device *dev, u8 *lun); +int mvs_clear_aca(struct domain_device *dev, u8 *lun); +int mvs_clear_task_set(struct domain_device *dev, u8 * lun); +void mvs_port_formed(struct asd_sas_phy *sas_phy); +void mvs_port_deformed(struct asd_sas_phy *sas_phy); +int mvs_dev_found(struct domain_device *dev); +void mvs_dev_gone(struct domain_device *dev); +int mvs_lu_reset(struct domain_device *dev, u8 *lun); +int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags); +int mvs_I_T_nexus_reset(struct domain_device *dev); +int mvs_query_task(struct sas_task *task); +void mvs_release_task(struct mvs_info *mvi, int phy_no, + struct domain_device *dev); +void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events); +void mvs_update_phyinfo(struct mvs_info *mvi, int i, int get_st); +int mvs_int_rx(struct mvs_info *mvi, bool self_clear); +void mvs_hexdump(u32 size, u8 *data, u32 baseaddr); +#endif + diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c index 3b7240e40819..e3c482aa87b5 100644 --- a/drivers/scsi/ncr53c8xx.c +++ b/drivers/scsi/ncr53c8xx.c @@ -5444,7 +5444,7 @@ static void ncr_getsync(struct ncb *np, u_char sfac, u_char *fakp, u_char *scntl ** input speed faster than the period. */ kpc = per * clk; - while (--div >= 0) + while (--div > 0) if (kpc >= (div_10M[div] << 2)) break; /* diff --git a/drivers/scsi/osd/Kbuild b/drivers/scsi/osd/Kbuild index 0e207aa67d16..5fd73d77c3af 100644 --- a/drivers/scsi/osd/Kbuild +++ b/drivers/scsi/osd/Kbuild @@ -11,31 +11,6 @@ # it under the terms of the GNU General Public License version 2 # -ifneq ($(OSD_INC),) -# we are built out-of-tree Kconfigure everything as on - -CONFIG_SCSI_OSD_INITIATOR=m -ccflags-y += -DCONFIG_SCSI_OSD_INITIATOR -DCONFIG_SCSI_OSD_INITIATOR_MODULE - -CONFIG_SCSI_OSD_ULD=m -ccflags-y += -DCONFIG_SCSI_OSD_ULD -DCONFIG_SCSI_OSD_ULD_MODULE - -# CONFIG_SCSI_OSD_DPRINT_SENSE = -# 0 - no print of errors -# 1 - print errors -# 2 - errors + warrnings -ccflags-y += -DCONFIG_SCSI_OSD_DPRINT_SENSE=1 - -# Uncomment to turn debug on -# ccflags-y += -DCONFIG_SCSI_OSD_DEBUG - -# if we are built out-of-tree and the hosting kernel has OSD headers -# then "ccflags-y +=" will not pick the out-off-tree headers. Only by doing -# this it will work. This might break in future kernels -LINUXINCLUDE := -I$(OSD_INC) $(LINUXINCLUDE) - -endif - # libosd.ko - osd-initiator library libosd-y := osd_initiator.o obj-$(CONFIG_SCSI_OSD_INITIATOR) += libosd.o diff --git a/drivers/scsi/osd/Makefile b/drivers/scsi/osd/Makefile deleted file mode 100755 index d905344f83ba..000000000000 --- a/drivers/scsi/osd/Makefile +++ /dev/null @@ -1,37 +0,0 @@ -# -# Makefile for the OSD modules (out of tree) -# -# Copyright (C) 2008 Panasas Inc. All rights reserved. -# -# Authors: -# Boaz Harrosh -# Benny Halevy -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2 -# -# This Makefile is used to call the kernel Makefile in case of an out-of-tree -# build. -# $KSRC should point to a Kernel source tree otherwise host's default is -# used. (eg. /lib/modules/`uname -r`/build) - -# include path for out-of-tree Headers -OSD_INC ?= `pwd`/../../../include - -# allow users to override these -# e.g. to compile for a kernel that you aren't currently running -KSRC ?= /lib/modules/$(shell uname -r)/build -KBUILD_OUTPUT ?= -ARCH ?= -V ?= 0 - -# this is the basic Kbuild out-of-tree invocation, with the M= option -KBUILD_BASE = +$(MAKE) -C $(KSRC) M=`pwd` KBUILD_OUTPUT=$(KBUILD_OUTPUT) ARCH=$(ARCH) V=$(V) - -all: libosd - -libosd: ; - $(KBUILD_BASE) OSD_INC=$(OSD_INC) modules - -clean: - $(KBUILD_BASE) clean diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c index 1ce6b24abab2..7a117c18114c 100644 --- a/drivers/scsi/osd/osd_initiator.c +++ b/drivers/scsi/osd/osd_initiator.c @@ -118,39 +118,39 @@ static int _osd_print_system_info(struct osd_dev *od, void *caps) _osd_ver_desc(or)); pFirst = get_attrs[a++].val_ptr; - OSD_INFO("OSD_ATTR_RI_VENDOR_IDENTIFICATION [%s]\n", + OSD_INFO("VENDOR_IDENTIFICATION [%s]\n", (char *)pFirst); pFirst = get_attrs[a++].val_ptr; - OSD_INFO("OSD_ATTR_RI_PRODUCT_IDENTIFICATION [%s]\n", + OSD_INFO("PRODUCT_IDENTIFICATION [%s]\n", (char *)pFirst); pFirst = get_attrs[a++].val_ptr; - OSD_INFO("OSD_ATTR_RI_PRODUCT_MODEL [%s]\n", + OSD_INFO("PRODUCT_MODEL [%s]\n", (char *)pFirst); pFirst = get_attrs[a++].val_ptr; - OSD_INFO("OSD_ATTR_RI_PRODUCT_REVISION_LEVEL [%u]\n", + OSD_INFO("PRODUCT_REVISION_LEVEL [%u]\n", pFirst ? get_unaligned_be32(pFirst) : ~0U); pFirst = get_attrs[a++].val_ptr; - OSD_INFO("OSD_ATTR_RI_PRODUCT_SERIAL_NUMBER [%s]\n", + OSD_INFO("PRODUCT_SERIAL_NUMBER [%s]\n", (char *)pFirst); pFirst = get_attrs[a].val_ptr; - OSD_INFO("OSD_ATTR_RI_OSD_NAME [%s]\n", (char *)pFirst); + OSD_INFO("OSD_NAME [%s]\n", (char *)pFirst); a++; pFirst = get_attrs[a++].val_ptr; - OSD_INFO("OSD_ATTR_RI_TOTAL_CAPACITY [0x%llx]\n", + OSD_INFO("TOTAL_CAPACITY [0x%llx]\n", pFirst ? _LLU(get_unaligned_be64(pFirst)) : ~0ULL); pFirst = get_attrs[a++].val_ptr; - OSD_INFO("OSD_ATTR_RI_USED_CAPACITY [0x%llx]\n", + OSD_INFO("USED_CAPACITY [0x%llx]\n", pFirst ? _LLU(get_unaligned_be64(pFirst)) : ~0ULL); pFirst = get_attrs[a++].val_ptr; - OSD_INFO("OSD_ATTR_RI_NUMBER_OF_PARTITIONS [%llu]\n", + OSD_INFO("NUMBER_OF_PARTITIONS [%llu]\n", pFirst ? _LLU(get_unaligned_be64(pFirst)) : ~0ULL); if (a >= nelem) @@ -158,7 +158,7 @@ static int _osd_print_system_info(struct osd_dev *od, void *caps) /* FIXME: Where are the time utilities */ pFirst = get_attrs[a++].val_ptr; - OSD_INFO("OSD_ATTR_RI_CLOCK [0x%02x%02x%02x%02x%02x%02x]\n", + OSD_INFO("CLOCK [0x%02x%02x%02x%02x%02x%02x]\n", ((char *)pFirst)[0], ((char *)pFirst)[1], ((char *)pFirst)[2], ((char *)pFirst)[3], ((char *)pFirst)[4], ((char *)pFirst)[5]); @@ -169,7 +169,8 @@ static int _osd_print_system_info(struct osd_dev *od, void *caps) hex_dump_to_buffer(get_attrs[a].val_ptr, len, 32, 1, sid_dump, sizeof(sid_dump), true); - OSD_INFO("OSD_ATTR_RI_OSD_SYSTEM_ID(%d) [%s]\n", len, sid_dump); + OSD_INFO("OSD_SYSTEM_ID(%d)\n" + " [%s]\n", len, sid_dump); a++; } out: @@ -669,7 +670,7 @@ static int _osd_req_list_objects(struct osd_request *or, __be16 action, const struct osd_obj_id *obj, osd_id initial_id, struct osd_obj_id_list *list, unsigned nelem) { - struct request_queue *q = or->osd_dev->scsi_device->request_queue; + struct request_queue *q = osd_request_queue(or->osd_dev); u64 len = nelem * sizeof(osd_id) + sizeof(*list); struct bio *bio; @@ -778,16 +779,32 @@ EXPORT_SYMBOL(osd_req_remove_object); */ void osd_req_write(struct osd_request *or, - const struct osd_obj_id *obj, struct bio *bio, u64 offset) + const struct osd_obj_id *obj, u64 offset, + struct bio *bio, u64 len) { - _osd_req_encode_common(or, OSD_ACT_WRITE, obj, offset, bio->bi_size); + _osd_req_encode_common(or, OSD_ACT_WRITE, obj, offset, len); WARN_ON(or->out.bio || or->out.total_bytes); - bio->bi_rw |= (1 << BIO_RW); + WARN_ON(0 == bio_rw_flagged(bio, BIO_RW)); or->out.bio = bio; - or->out.total_bytes = bio->bi_size; + or->out.total_bytes = len; } EXPORT_SYMBOL(osd_req_write); +int osd_req_write_kern(struct osd_request *or, + const struct osd_obj_id *obj, u64 offset, void* buff, u64 len) +{ + struct request_queue *req_q = osd_request_queue(or->osd_dev); + struct bio *bio = bio_map_kern(req_q, buff, len, GFP_KERNEL); + + if (IS_ERR(bio)) + return PTR_ERR(bio); + + bio->bi_rw |= (1 << BIO_RW); /* FIXME: bio_set_dir() */ + osd_req_write(or, obj, offset, bio, len); + return 0; +} +EXPORT_SYMBOL(osd_req_write_kern); + /*TODO: void osd_req_append(struct osd_request *, const struct osd_obj_id *, struct bio *data_out); */ /*TODO: void osd_req_create_write(struct osd_request *, @@ -813,16 +830,31 @@ void osd_req_flush_object(struct osd_request *or, EXPORT_SYMBOL(osd_req_flush_object); void osd_req_read(struct osd_request *or, - const struct osd_obj_id *obj, struct bio *bio, u64 offset) + const struct osd_obj_id *obj, u64 offset, + struct bio *bio, u64 len) { - _osd_req_encode_common(or, OSD_ACT_READ, obj, offset, bio->bi_size); + _osd_req_encode_common(or, OSD_ACT_READ, obj, offset, len); WARN_ON(or->in.bio || or->in.total_bytes); - bio->bi_rw &= ~(1 << BIO_RW); + WARN_ON(1 == bio_rw_flagged(bio, BIO_RW)); or->in.bio = bio; - or->in.total_bytes = bio->bi_size; + or->in.total_bytes = len; } EXPORT_SYMBOL(osd_req_read); +int osd_req_read_kern(struct osd_request *or, + const struct osd_obj_id *obj, u64 offset, void* buff, u64 len) +{ + struct request_queue *req_q = osd_request_queue(or->osd_dev); + struct bio *bio = bio_map_kern(req_q, buff, len, GFP_KERNEL); + + if (IS_ERR(bio)) + return PTR_ERR(bio); + + osd_req_read(or, obj, offset, bio, len); + return 0; +} +EXPORT_SYMBOL(osd_req_read_kern); + void osd_req_get_attributes(struct osd_request *or, const struct osd_obj_id *obj) { @@ -889,26 +921,6 @@ int osd_req_add_set_attr_list(struct osd_request *or, } EXPORT_SYMBOL(osd_req_add_set_attr_list); -static int _append_map_kern(struct request *req, - void *buff, unsigned len, gfp_t flags) -{ - struct bio *bio; - int ret; - - bio = bio_map_kern(req->q, buff, len, flags); - if (IS_ERR(bio)) { - OSD_ERR("Failed bio_map_kern(%p, %d) => %ld\n", buff, len, - PTR_ERR(bio)); - return PTR_ERR(bio); - } - ret = blk_rq_append_bio(req->q, req, bio); - if (ret) { - OSD_ERR("Failed blk_rq_append_bio(%p) => %d\n", bio, ret); - bio_put(bio); - } - return ret; -} - static int _req_append_segment(struct osd_request *or, unsigned padding, struct _osd_req_data_segment *seg, struct _osd_req_data_segment *last_seg, struct _osd_io_info *io) @@ -924,14 +936,14 @@ static int _req_append_segment(struct osd_request *or, else pad_buff = io->pad_buff; - ret = _append_map_kern(io->req, pad_buff, padding, + ret = blk_rq_map_kern(io->req->q, io->req, pad_buff, padding, or->alloc_flags); if (ret) return ret; io->total_bytes += padding; } - ret = _append_map_kern(io->req, seg->buff, seg->total_bytes, + ret = blk_rq_map_kern(io->req->q, io->req, seg->buff, seg->total_bytes, or->alloc_flags); if (ret) return ret; @@ -1233,7 +1245,7 @@ static inline void osd_sec_parms_set_in_offset(bool is_v1, } static int _osd_req_finalize_data_integrity(struct osd_request *or, - bool has_in, bool has_out, const u8 *cap_key) + bool has_in, bool has_out, u64 out_data_bytes, const u8 *cap_key) { struct osd_security_parameters *sec_parms = _osd_req_sec_params(or); int ret; @@ -1248,8 +1260,7 @@ static int _osd_req_finalize_data_integrity(struct osd_request *or, }; unsigned pad; - or->out_data_integ.data_bytes = cpu_to_be64( - or->out.bio ? or->out.bio->bi_size : 0); + or->out_data_integ.data_bytes = cpu_to_be64(out_data_bytes); or->out_data_integ.set_attributes_bytes = cpu_to_be64( or->set_attr.total_bytes); or->out_data_integ.get_attributes_bytes = cpu_to_be64( @@ -1293,6 +1304,21 @@ static int _osd_req_finalize_data_integrity(struct osd_request *or, /* * osd_finalize_request and helpers */ +static struct request *_make_request(struct request_queue *q, bool has_write, + struct _osd_io_info *oii, gfp_t flags) +{ + if (oii->bio) + return blk_make_request(q, oii->bio, flags); + else { + struct request *req; + + req = blk_get_request(q, has_write ? WRITE : READ, flags); + if (unlikely(!req)) + return ERR_PTR(-ENOMEM); + + return req; + } +} static int _init_blk_request(struct osd_request *or, bool has_in, bool has_out) @@ -1301,14 +1327,18 @@ static int _init_blk_request(struct osd_request *or, struct scsi_device *scsi_device = or->osd_dev->scsi_device; struct request_queue *q = scsi_device->request_queue; struct request *req; - int ret = -ENOMEM; + int ret; - req = blk_get_request(q, has_out, flags); - if (!req) + req = _make_request(q, has_out, has_out ? &or->out : &or->in, flags); + if (IS_ERR(req)) { + ret = PTR_ERR(req); goto out; + } or->request = req; req->cmd_type = REQ_TYPE_BLOCK_PC; + req->cmd_flags |= REQ_QUIET; + req->timeout = or->timeout; req->retries = or->retries; req->sense = or->sense; @@ -1318,9 +1348,10 @@ static int _init_blk_request(struct osd_request *or, or->out.req = req; if (has_in) { /* allocate bidi request */ - req = blk_get_request(q, READ, flags); - if (!req) { + req = _make_request(q, false, &or->in, flags); + if (IS_ERR(req)) { OSD_DEBUG("blk_get_request for bidi failed\n"); + ret = PTR_ERR(req); goto out; } req->cmd_type = REQ_TYPE_BLOCK_PC; @@ -1341,6 +1372,7 @@ int osd_finalize_request(struct osd_request *or, { struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb); bool has_in, has_out; + u64 out_data_bytes = or->out.total_bytes; int ret; if (options & OSD_REQ_FUA) @@ -1364,26 +1396,6 @@ int osd_finalize_request(struct osd_request *or, return ret; } - if (or->out.bio) { - ret = blk_rq_append_bio(or->request->q, or->out.req, - or->out.bio); - if (ret) { - OSD_DEBUG("blk_rq_append_bio out failed\n"); - return ret; - } - OSD_DEBUG("out bytes=%llu (bytes_req=%u)\n", - _LLU(or->out.total_bytes), or->out.req->data_len); - } - if (or->in.bio) { - ret = blk_rq_append_bio(or->request->q, or->in.req, or->in.bio); - if (ret) { - OSD_DEBUG("blk_rq_append_bio in failed\n"); - return ret; - } - OSD_DEBUG("in bytes=%llu (bytes_req=%u)\n", - _LLU(or->in.total_bytes), or->in.req->data_len); - } - or->out.pad_buff = sg_out_pad_buffer; or->in.pad_buff = sg_in_pad_buffer; @@ -1410,7 +1422,8 @@ int osd_finalize_request(struct osd_request *or, } } - ret = _osd_req_finalize_data_integrity(or, has_in, has_out, cap_key); + ret = _osd_req_finalize_data_integrity(or, has_in, has_out, + out_data_bytes, cap_key); if (ret) return ret; diff --git a/drivers/scsi/osd/osd_uld.c b/drivers/scsi/osd/osd_uld.c index 22b59e13ba83..0bdef3390902 100644 --- a/drivers/scsi/osd/osd_uld.c +++ b/drivers/scsi/osd/osd_uld.c @@ -49,6 +49,7 @@ #include #include #include +#include #include #include @@ -175,10 +176,9 @@ static const struct file_operations osd_fops = { struct osd_dev *osduld_path_lookup(const char *name) { - struct path path; - struct inode *inode; - struct cdev *cdev; - struct osd_uld_device *uninitialized_var(oud); + struct osd_uld_device *oud; + struct osd_dev *od; + struct file *file; int error; if (!name || !*name) { @@ -186,52 +186,46 @@ struct osd_dev *osduld_path_lookup(const char *name) return ERR_PTR(-EINVAL); } - error = kern_path(name, LOOKUP_FOLLOW, &path); - if (error) { - OSD_ERR("path_lookup of %s failed=>%d\n", name, error); - return ERR_PTR(error); + od = kzalloc(sizeof(*od), GFP_KERNEL); + if (!od) + return ERR_PTR(-ENOMEM); + + file = filp_open(name, O_RDWR, 0); + if (IS_ERR(file)) { + error = PTR_ERR(file); + goto free_od; } - inode = path.dentry->d_inode; - error = -EINVAL; /* Not the right device e.g osd_uld_device */ - if (!S_ISCHR(inode->i_mode)) { - OSD_DEBUG("!S_ISCHR()\n"); - goto out; + if (file->f_op != &osd_fops){ + error = -EINVAL; + goto close_file; } - cdev = inode->i_cdev; - if (!cdev) { - OSD_ERR("Before mounting an OSD Based filesystem\n"); - OSD_ERR(" user-mode must open+close the %s device\n", name); - OSD_ERR(" Example: bash: echo < %s\n", name); - goto out; - } + oud = file->private_data; - /* The Magic wand. Is it our char-dev */ - /* TODO: Support sg devices */ - if (cdev->owner != THIS_MODULE) { - OSD_ERR("Error mounting %s - is not an OSD device\n", name); - goto out; - } + *od = oud->od; + od->file = file; - oud = container_of(cdev, struct osd_uld_device, cdev); + return od; - __uld_get(oud); - error = 0; - -out: - path_put(&path); - return error ? ERR_PTR(error) : &oud->od; +close_file: + fput(file); +free_od: + kfree(od); + return ERR_PTR(error); } EXPORT_SYMBOL(osduld_path_lookup); void osduld_put_device(struct osd_dev *od) { - if (od) { - struct osd_uld_device *oud = container_of(od, - struct osd_uld_device, od); - __uld_put(oud); + if (od && !IS_ERR(od)) { + struct osd_uld_device *oud = od->file->private_data; + + BUG_ON(od->scsi_device != oud->od.scsi_device); + + fput(od->file); + kfree(od); } } EXPORT_SYMBOL(osduld_put_device); diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c index 11a61ea8d5d9..70b60ade049e 100644 --- a/drivers/scsi/pcmcia/nsp_cs.c +++ b/drivers/scsi/pcmcia/nsp_cs.c @@ -530,7 +530,7 @@ static int nsp_negate_signal(struct scsi_cmnd *SCpnt, unsigned char mask, if (reg == 0xff) { break; } - } while ((time_out-- != 0) && (reg & mask) != 0); + } while ((--time_out != 0) && (reg & mask) != 0); if (time_out == 0) { nsp_msg(KERN_DEBUG, " %s signal off timeut", str); @@ -801,7 +801,7 @@ static void nsp_pio_read(struct scsi_cmnd *SCpnt) data->FifoCount = ocount; - if (time_out == 0) { + if (time_out < 0) { nsp_msg(KERN_DEBUG, "pio read timeout resid=%d this_residual=%d buffers_residual=%d", scsi_get_resid(SCpnt), SCpnt->SCp.this_residual, SCpnt->SCp.buffers_residual); @@ -897,7 +897,7 @@ static void nsp_pio_write(struct scsi_cmnd *SCpnt) data->FifoCount = ocount; - if (time_out == 0) { + if (time_out < 0) { nsp_msg(KERN_DEBUG, "pio write timeout resid=0x%x", scsi_get_resid(SCpnt)); } diff --git a/drivers/scsi/ps3rom.c b/drivers/scsi/ps3rom.c index ca0dd33497ec..db90caf43f42 100644 --- a/drivers/scsi/ps3rom.c +++ b/drivers/scsi/ps3rom.c @@ -299,7 +299,7 @@ static irqreturn_t ps3rom_interrupt(int irq, void *data) return IRQ_HANDLED; } - host = dev->sbd.core.driver_data; + host = ps3_system_bus_get_drvdata(&dev->sbd); priv = shost_priv(host); cmd = priv->curr_cmd; @@ -387,7 +387,7 @@ static int __devinit ps3rom_probe(struct ps3_system_bus_device *_dev) } priv = shost_priv(host); - dev->sbd.core.driver_data = host; + ps3_system_bus_set_drvdata(&dev->sbd, host); priv->dev = dev; /* One device/LUN per SCSI bus */ @@ -407,7 +407,7 @@ static int __devinit ps3rom_probe(struct ps3_system_bus_device *_dev) fail_host_put: scsi_host_put(host); - dev->sbd.core.driver_data = NULL; + ps3_system_bus_set_drvdata(&dev->sbd, NULL); fail_teardown: ps3stor_teardown(dev); fail_free_bounce: @@ -418,12 +418,12 @@ fail_free_bounce: static int ps3rom_remove(struct ps3_system_bus_device *_dev) { struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core); - struct Scsi_Host *host = dev->sbd.core.driver_data; + struct Scsi_Host *host = ps3_system_bus_get_drvdata(&dev->sbd); scsi_remove_host(host); ps3stor_teardown(dev); scsi_host_put(host); - dev->sbd.core.driver_data = NULL; + ps3_system_bus_set_drvdata(&dev->sbd, NULL); kfree(dev->bounce_buf); return 0; } diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index 5defe5ea5eda..8371d917a9a2 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -17,9 +17,12 @@ * General Public License for more details. * ******************************************************************************/ -#define QLA1280_VERSION "3.26" +#define QLA1280_VERSION "3.27" /***************************************************************************** Revision History: + Rev 3.27, February 10, 2009, Michael Reed + - General code cleanup. + - Improve error recovery. Rev 3.26, January 16, 2006 Jes Sorensen - Ditch all < 2.6 support Rev 3.25.1, February 10, 2005 Christoph Hellwig @@ -435,7 +438,6 @@ static int qla1280_mailbox_command(struct scsi_qla_host *, uint8_t, uint16_t *); static int qla1280_bus_reset(struct scsi_qla_host *, int); static int qla1280_device_reset(struct scsi_qla_host *, int, int); -static int qla1280_abort_device(struct scsi_qla_host *, int, int, int); static int qla1280_abort_command(struct scsi_qla_host *, struct srb *, int); static int qla1280_abort_isp(struct scsi_qla_host *); #ifdef QLA_64BIT_PTR @@ -698,7 +700,7 @@ qla1280_info(struct Scsi_Host *host) } /************************************************************************** - * qla1200_queuecommand + * qla1280_queuecommand * Queue a command to the controller. * * Note: @@ -713,12 +715,14 @@ qla1280_queuecommand(struct scsi_cmnd *cmd, void (*fn)(struct scsi_cmnd *)) { struct Scsi_Host *host = cmd->device->host; struct scsi_qla_host *ha = (struct scsi_qla_host *)host->hostdata; - struct srb *sp = (struct srb *)&cmd->SCp; + struct srb *sp = (struct srb *)CMD_SP(cmd); int status; cmd->scsi_done = fn; sp->cmd = cmd; sp->flags = 0; + sp->wait = NULL; + CMD_HANDLE(cmd) = (unsigned char *)NULL; qla1280_print_scsi_cmd(5, cmd); @@ -738,21 +742,11 @@ qla1280_queuecommand(struct scsi_cmnd *cmd, void (*fn)(struct scsi_cmnd *)) enum action { ABORT_COMMAND, - ABORT_DEVICE, DEVICE_RESET, BUS_RESET, ADAPTER_RESET, - FAIL }; -/* timer action for error action processor */ -static void qla1280_error_wait_timeout(unsigned long __data) -{ - struct scsi_cmnd *cmd = (struct scsi_cmnd *)__data; - struct srb *sp = (struct srb *)CMD_SP(cmd); - - complete(sp->wait); -} static void qla1280_mailbox_timeout(unsigned long __data) { @@ -767,8 +761,67 @@ static void qla1280_mailbox_timeout(unsigned long __data) complete(ha->mailbox_wait); } +static int +_qla1280_wait_for_single_command(struct scsi_qla_host *ha, struct srb *sp, + struct completion *wait) +{ + int status = FAILED; + struct scsi_cmnd *cmd = sp->cmd; + + spin_unlock_irq(ha->host->host_lock); + wait_for_completion_timeout(wait, 4*HZ); + spin_lock_irq(ha->host->host_lock); + sp->wait = NULL; + if(CMD_HANDLE(cmd) == COMPLETED_HANDLE) { + status = SUCCESS; + (*cmd->scsi_done)(cmd); + } + return status; +} + +static int +qla1280_wait_for_single_command(struct scsi_qla_host *ha, struct srb *sp) +{ + DECLARE_COMPLETION_ONSTACK(wait); + + sp->wait = &wait; + return _qla1280_wait_for_single_command(ha, sp, &wait); +} + +static int +qla1280_wait_for_pending_commands(struct scsi_qla_host *ha, int bus, int target) +{ + int cnt; + int status; + struct srb *sp; + struct scsi_cmnd *cmd; + + status = SUCCESS; + + /* + * Wait for all commands with the designated bus/target + * to be completed by the firmware + */ + for (cnt = 0; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { + sp = ha->outstanding_cmds[cnt]; + if (sp) { + cmd = sp->cmd; + + if (bus >= 0 && SCSI_BUS_32(cmd) != bus) + continue; + if (target >= 0 && SCSI_TCN_32(cmd) != target) + continue; + + status = qla1280_wait_for_single_command(ha, sp); + if (status == FAILED) + break; + } + } + return status; +} + /************************************************************************** - * qla1200_error_action + * qla1280_error_action * The function will attempt to perform a specified error action and * wait for the results (or time out). * @@ -780,11 +833,6 @@ static void qla1280_mailbox_timeout(unsigned long __data) * Returns: * SUCCESS or FAILED * - * Note: - * Resetting the bus always succeeds - is has to, otherwise the - * kernel will panic! Try a surgical technique - sending a BUS - * DEVICE RESET message - on the offending target before pulling - * the SCSI bus reset line. **************************************************************************/ static int qla1280_error_action(struct scsi_cmnd *cmd, enum action action) @@ -792,13 +840,19 @@ qla1280_error_action(struct scsi_cmnd *cmd, enum action action) struct scsi_qla_host *ha; int bus, target, lun; struct srb *sp; - uint16_t data; - unsigned char *handle; - int result, i; + int i, found; + int result=FAILED; + int wait_for_bus=-1; + int wait_for_target = -1; DECLARE_COMPLETION_ONSTACK(wait); - struct timer_list timer; + + ENTER("qla1280_error_action"); ha = (struct scsi_qla_host *)(CMD_HOST(cmd)->hostdata); + sp = (struct srb *)CMD_SP(cmd); + bus = SCSI_BUS_32(cmd); + target = SCSI_TCN_32(cmd); + lun = SCSI_LUN_32(cmd); dprintk(4, "error_action %i, istatus 0x%04x\n", action, RD_REG_WORD(&ha->iobase->istatus)); @@ -807,99 +861,47 @@ qla1280_error_action(struct scsi_cmnd *cmd, enum action action) RD_REG_WORD(&ha->iobase->host_cmd), RD_REG_WORD(&ha->iobase->ictrl), jiffies); - ENTER("qla1280_error_action"); if (qla1280_verbose) printk(KERN_INFO "scsi(%li): Resetting Cmnd=0x%p, " "Handle=0x%p, action=0x%x\n", ha->host_no, cmd, CMD_HANDLE(cmd), action); - if (cmd == NULL) { - printk(KERN_WARNING "(scsi?:?:?:?) Reset called with NULL " - "si_Cmnd pointer, failing.\n"); - LEAVE("qla1280_error_action"); - return FAILED; - } - - ha = (struct scsi_qla_host *)cmd->device->host->hostdata; - sp = (struct srb *)CMD_SP(cmd); - handle = CMD_HANDLE(cmd); - - /* Check for pending interrupts. */ - data = qla1280_debounce_register(&ha->iobase->istatus); /* - * The io_request_lock is held when the reset handler is called, hence - * the interrupt handler cannot be running in parallel as it also - * grabs the lock. /Jes + * Check to see if we have the command in the outstanding_cmds[] + * array. If not then it must have completed before this error + * action was initiated. If the error_action isn't ABORT_COMMAND + * then the driver must proceed with the requested action. */ - if (data & RISC_INT) - qla1280_isr(ha, &ha->done_q); - - /* - * Determine the suggested action that the mid-level driver wants - * us to perform. - */ - if (handle == (unsigned char *)INVALID_HANDLE || handle == NULL) { - if(action == ABORT_COMMAND) { - /* we never got this command */ - printk(KERN_INFO "qla1280: Aborting a NULL handle\n"); - return SUCCESS; /* no action - we don't have command */ - } - } else { - sp->wait = &wait; - } - - bus = SCSI_BUS_32(cmd); - target = SCSI_TCN_32(cmd); - lun = SCSI_LUN_32(cmd); - - /* Overloading result. Here it means the success or fail of the - * *issue* of the action. When we return from the routine, it must - * mean the actual success or fail of the action */ - result = FAILED; - switch (action) { - case FAIL: - break; - - case ABORT_COMMAND: - if ((sp->flags & SRB_ABORT_PENDING)) { - printk(KERN_WARNING - "scsi(): Command has a pending abort " - "message - ABORT_PENDING.\n"); - /* This should technically be impossible since we - * now wait for abort completion */ + found = -1; + for (i = 0; i < MAX_OUTSTANDING_COMMANDS; i++) { + if (sp == ha->outstanding_cmds[i]) { + found = i; + sp->wait = &wait; /* we'll wait for it to complete */ break; } + } - for (i = 0; i < MAX_OUTSTANDING_COMMANDS; i++) { - if (sp == ha->outstanding_cmds[i]) { - dprintk(1, "qla1280: RISC aborting command\n"); - if (qla1280_abort_command(ha, sp, i) == 0) - result = SUCCESS; - else { - /* - * Since we don't know what might - * have happend to the command, it - * is unsafe to remove it from the - * device's queue at this point. - * Wait and let the escalation - * process take care of it. - */ - printk(KERN_WARNING - "scsi(%li:%i:%i:%i): Unable" - " to abort command!\n", - ha->host_no, bus, target, lun); - } - } - } - break; - - case ABORT_DEVICE: - if (qla1280_verbose) + if (found < 0) { /* driver doesn't have command */ + result = SUCCESS; + if (qla1280_verbose) { printk(KERN_INFO - "scsi(%ld:%d:%d:%d): Queueing abort device " - "command.\n", ha->host_no, bus, target, lun); - if (qla1280_abort_device(ha, bus, target, lun) == 0) - result = SUCCESS; + "scsi(%ld:%d:%d:%d): specified command has " + "already completed.\n", ha->host_no, bus, + target, lun); + } + } + + switch (action) { + + case ABORT_COMMAND: + dprintk(1, "qla1280: RISC aborting command\n"); + /* + * The abort might fail due to race when the host_lock + * is released to issue the abort. As such, we + * don't bother to check the return status. + */ + if (found >= 0) + qla1280_abort_command(ha, sp, found); break; case DEVICE_RESET: @@ -907,16 +909,21 @@ qla1280_error_action(struct scsi_cmnd *cmd, enum action action) printk(KERN_INFO "scsi(%ld:%d:%d:%d): Queueing device reset " "command.\n", ha->host_no, bus, target, lun); - if (qla1280_device_reset(ha, bus, target) == 0) - result = SUCCESS; + if (qla1280_device_reset(ha, bus, target) == 0) { + /* issued device reset, set wait conditions */ + wait_for_bus = bus; + wait_for_target = target; + } break; case BUS_RESET: if (qla1280_verbose) printk(KERN_INFO "qla1280(%ld:%d): Issued bus " "reset.\n", ha->host_no, bus); - if (qla1280_bus_reset(ha, bus) == 0) - result = SUCCESS; + if (qla1280_bus_reset(ha, bus) == 0) { + /* issued bus reset, set wait conditions */ + wait_for_bus = bus; + } break; case ADAPTER_RESET: @@ -929,55 +936,48 @@ qla1280_error_action(struct scsi_cmnd *cmd, enum action action) "continue automatically\n", ha->host_no); } ha->flags.reset_active = 1; - /* - * We restarted all of the commands automatically, so the - * mid-level code can expect completions momentitarily. - */ - if (qla1280_abort_isp(ha) == 0) - result = SUCCESS; + + if (qla1280_abort_isp(ha) != 0) { /* it's dead */ + result = FAILED; + } ha->flags.reset_active = 0; } - if (!list_empty(&ha->done_q)) - qla1280_done(ha); + /* + * At this point, the host_lock has been released and retaken + * by the issuance of the mailbox command. + * Wait for the command passed in by the mid-layer if it + * was found by the driver. It might have been returned + * between eh recovery steps, hence the check of the "found" + * variable. + */ - /* If we didn't manage to issue the action, or we have no - * command to wait for, exit here */ - if (result == FAILED || handle == NULL || - handle == (unsigned char *)INVALID_HANDLE) { - /* - * Clear completion queue to avoid qla1280_done() trying - * to complete the command at a later stage after we - * have exited the current context - */ - sp->wait = NULL; - goto leave; + if (found >= 0) + result = _qla1280_wait_for_single_command(ha, sp, &wait); + + if (action == ABORT_COMMAND && result != SUCCESS) { + printk(KERN_WARNING + "scsi(%li:%i:%i:%i): " + "Unable to abort command!\n", + ha->host_no, bus, target, lun); } - /* set up a timer just in case we're really jammed */ - init_timer(&timer); - timer.expires = jiffies + 4*HZ; - timer.data = (unsigned long)cmd; - timer.function = qla1280_error_wait_timeout; - add_timer(&timer); - - /* wait for the action to complete (or the timer to expire) */ - spin_unlock_irq(ha->host->host_lock); - wait_for_completion(&wait); - del_timer_sync(&timer); - spin_lock_irq(ha->host->host_lock); - sp->wait = NULL; - - /* the only action we might get a fail for is abort */ - if (action == ABORT_COMMAND) { - if(sp->flags & SRB_ABORTED) - result = SUCCESS; - else - result = FAILED; + /* + * If the command passed in by the mid-layer has been + * returned by the board, then wait for any additional + * commands which are supposed to complete based upon + * the error action. + * + * All commands are unconditionally returned during a + * call to qla1280_abort_isp(), ADAPTER_RESET. No need + * to wait for them. + */ + if (result == SUCCESS && wait_for_bus >= 0) { + result = qla1280_wait_for_pending_commands(ha, + wait_for_bus, wait_for_target); } - leave: dprintk(1, "RESET returning %d\n", result); LEAVE("qla1280_error_action"); @@ -1280,13 +1280,12 @@ qla1280_done(struct scsi_qla_host *ha) switch ((CMD_RESULT(cmd) >> 16)) { case DID_RESET: /* Issue marker command. */ - qla1280_marker(ha, bus, target, 0, MK_SYNC_ID); + if (!ha->flags.abort_isp_active) + qla1280_marker(ha, bus, target, 0, MK_SYNC_ID); break; case DID_ABORT: sp->flags &= ~SRB_ABORT_PENDING; sp->flags |= SRB_ABORTED; - if (sp->flags & SRB_TIMEOUT) - CMD_RESULT(sp->cmd) = DID_TIME_OUT << 16; break; default: break; @@ -1296,12 +1295,11 @@ qla1280_done(struct scsi_qla_host *ha) scsi_dma_unmap(cmd); /* Call the mid-level driver interrupt handler */ - CMD_HANDLE(sp->cmd) = (unsigned char *)INVALID_HANDLE; ha->actthreads--; - (*(cmd)->scsi_done)(cmd); - - if(sp->wait != NULL) + if (sp->wait == NULL) + (*(cmd)->scsi_done)(cmd); + else complete(sp->wait); } LEAVE("qla1280_done"); @@ -2417,9 +2415,6 @@ static int qla1280_mailbox_command(struct scsi_qla_host *ha, uint8_t mr, uint16_t *mb) { struct device_reg __iomem *reg = ha->iobase; -#if 0 - LIST_HEAD(done_q); -#endif int status = 0; int cnt; uint16_t *optr, *iptr; @@ -2493,19 +2488,9 @@ qla1280_mailbox_command(struct scsi_qla_host *ha, uint8_t mr, uint16_t *mb) mr = MAILBOX_REGISTER_COUNT; memcpy(optr, iptr, MAILBOX_REGISTER_COUNT * sizeof(uint16_t)); -#if 0 - /* Go check for any response interrupts pending. */ - qla1280_isr(ha, &done_q); -#endif - if (ha->flags.reset_marker) qla1280_rst_aen(ha); -#if 0 - if (!list_empty(&done_q)) - qla1280_done(ha, &done_q); -#endif - if (status) dprintk(2, "qla1280_mailbox_command: **** FAILED, mailbox0 = " "0x%x ****\n", mb[0]); @@ -2640,41 +2625,6 @@ qla1280_device_reset(struct scsi_qla_host *ha, int bus, int target) return status; } -/* - * qla1280_abort_device - * Issue an abort message to the device - * - * Input: - * ha = adapter block pointer. - * bus = SCSI BUS. - * target = SCSI ID. - * lun = SCSI LUN. - * - * Returns: - * 0 = success - */ -static int -qla1280_abort_device(struct scsi_qla_host *ha, int bus, int target, int lun) -{ - uint16_t mb[MAILBOX_REGISTER_COUNT]; - int status; - - ENTER("qla1280_abort_device"); - - mb[0] = MBC_ABORT_DEVICE; - mb[1] = (bus ? target | BIT_7 : target) << 8 | lun; - status = qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]); - - /* Issue marker command. */ - qla1280_marker(ha, bus, target, lun, MK_SYNC_ID_LUN); - - if (status) - dprintk(2, "qla1280_abort_device: **** FAILED ****\n"); - - LEAVE("qla1280_abort_device"); - return status; -} - /* * qla1280_abort_command * Abort command aborts a specified IOCB. @@ -2833,7 +2783,7 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp) /* If room for request in request ring. */ if ((req_cnt + 2) >= ha->req_q_cnt) { - status = 1; + status = SCSI_MLQUEUE_HOST_BUSY; dprintk(2, "qla1280_start_scsi: in-ptr=0x%x req_q_cnt=" "0x%xreq_cnt=0x%x", ha->req_ring_index, ha->req_q_cnt, req_cnt); @@ -2845,7 +2795,7 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp) ha->outstanding_cmds[cnt] != NULL; cnt++); if (cnt >= MAX_OUTSTANDING_COMMANDS) { - status = 1; + status = SCSI_MLQUEUE_HOST_BUSY; dprintk(2, "qla1280_start_scsi: NO ROOM IN " "OUTSTANDING ARRAY, req_q_cnt=0x%x", ha->req_q_cnt); goto out; @@ -3108,7 +3058,7 @@ qla1280_32bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp) ha->req_q_cnt, seg_cnt); /* If room for request in request ring. */ if ((req_cnt + 2) >= ha->req_q_cnt) { - status = 1; + status = SCSI_MLQUEUE_HOST_BUSY; dprintk(2, "qla1280_32bit_start_scsi: in-ptr=0x%x, " "req_q_cnt=0x%x, req_cnt=0x%x", ha->req_ring_index, ha->req_q_cnt, req_cnt); @@ -3120,7 +3070,7 @@ qla1280_32bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp) (ha->outstanding_cmds[cnt] != 0); cnt++) ; if (cnt >= MAX_OUTSTANDING_COMMANDS) { - status = 1; + status = SCSI_MLQUEUE_HOST_BUSY; dprintk(2, "qla1280_32bit_start_scsi: NO ROOM IN OUTSTANDING " "ARRAY, req_q_cnt=0x%x\n", ha->req_q_cnt); goto out; @@ -3487,6 +3437,7 @@ qla1280_isr(struct scsi_qla_host *ha, struct list_head *done_q) /* Save ISP completion status */ CMD_RESULT(sp->cmd) = 0; + CMD_HANDLE(sp->cmd) = COMPLETED_HANDLE; /* Place block on done queue */ list_add_tail(&sp->list, done_q); @@ -3495,7 +3446,7 @@ qla1280_isr(struct scsi_qla_host *ha, struct list_head *done_q) * If we get here we have a real problem! */ printk(KERN_WARNING - "qla1280: ISP invalid handle"); + "qla1280: ISP invalid handle\n"); } } break; @@ -3753,6 +3704,8 @@ qla1280_status_entry(struct scsi_qla_host *ha, struct response *pkt, } } + CMD_HANDLE(sp->cmd) = COMPLETED_HANDLE; + /* Place command on done queue. */ list_add_tail(&sp->list, done_q); out: @@ -3808,6 +3761,8 @@ qla1280_error_entry(struct scsi_qla_host *ha, struct response *pkt, CMD_RESULT(sp->cmd) = DID_ERROR << 16; } + CMD_HANDLE(sp->cmd) = COMPLETED_HANDLE; + /* Place command on done queue. */ list_add_tail(&sp->list, done_q); } @@ -3858,19 +3813,16 @@ qla1280_abort_isp(struct scsi_qla_host *ha) struct scsi_cmnd *cmd; sp = ha->outstanding_cmds[cnt]; if (sp) { - cmd = sp->cmd; CMD_RESULT(cmd) = DID_RESET << 16; - - sp->cmd = NULL; + CMD_HANDLE(cmd) = COMPLETED_HANDLE; ha->outstanding_cmds[cnt] = NULL; - - (*cmd->scsi_done)(cmd); - - sp->flags = 0; + list_add_tail(&sp->list, &ha->done_q); } } + qla1280_done(ha); + status = qla1280_load_firmware(ha); if (status) goto out; @@ -3955,13 +3907,6 @@ qla1280_check_for_dead_scsi_bus(struct scsi_qla_host *ha, unsigned int bus) if (scsi_control == SCSI_PHASE_INVALID) { ha->bus_settings[bus].scsi_bus_dead = 1; -#if 0 - CMD_RESULT(cp) = DID_NO_CONNECT << 16; - CMD_HANDLE(cp) = INVALID_HANDLE; - /* ha->actthreads--; */ - - (*(cp)->scsi_done)(cp); -#endif return 1; /* bus is dead */ } else { ha->bus_settings[bus].scsi_bus_dead = 0; diff --git a/drivers/scsi/qla1280.h b/drivers/scsi/qla1280.h index d7c44b8d2b4f..834884b9eed5 100644 --- a/drivers/scsi/qla1280.h +++ b/drivers/scsi/qla1280.h @@ -88,7 +88,8 @@ /* Maximum outstanding commands in ISP queues */ #define MAX_OUTSTANDING_COMMANDS 512 -#define INVALID_HANDLE (MAX_OUTSTANDING_COMMANDS + 2) +#define COMPLETED_HANDLE ((unsigned char *) \ + (MAX_OUTSTANDING_COMMANDS + 2)) /* ISP request and response entry counts (37-65535) */ #define REQUEST_ENTRY_CNT 255 /* Number of request entries. */ diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index b09993a06576..0f8796201504 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -97,7 +97,7 @@ qla2x00_sysfs_read_nvram(struct kobject *kobj, return 0; if (IS_NOCACHE_VPD_TYPE(ha)) - ha->isp_ops->read_optrom(vha, ha->vpd, ha->flt_region_nvram << 2, + ha->isp_ops->read_optrom(vha, ha->nvram, ha->flt_region_nvram << 2, ha->nvram_size); return memory_read_from_buffer(buf, count, &off, ha->nvram, ha->nvram_size); @@ -692,6 +692,109 @@ static struct bin_attribute sysfs_edc_status_attr = { .read = qla2x00_sysfs_read_edc_status, }; +static ssize_t +qla2x00_sysfs_read_xgmac_stats(struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t off, size_t count) +{ + struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj, + struct device, kobj))); + struct qla_hw_data *ha = vha->hw; + int rval; + uint16_t actual_size; + + if (!capable(CAP_SYS_ADMIN) || off != 0 || count > XGMAC_DATA_SIZE) + return 0; + + if (ha->xgmac_data) + goto do_read; + + ha->xgmac_data = dma_alloc_coherent(&ha->pdev->dev, XGMAC_DATA_SIZE, + &ha->xgmac_data_dma, GFP_KERNEL); + if (!ha->xgmac_data) { + qla_printk(KERN_WARNING, ha, + "Unable to allocate memory for XGMAC read-data.\n"); + return 0; + } + +do_read: + actual_size = 0; + memset(ha->xgmac_data, 0, XGMAC_DATA_SIZE); + + rval = qla2x00_get_xgmac_stats(vha, ha->xgmac_data_dma, + XGMAC_DATA_SIZE, &actual_size); + if (rval != QLA_SUCCESS) { + qla_printk(KERN_WARNING, ha, + "Unable to read XGMAC data (%x).\n", rval); + count = 0; + } + + count = actual_size > count ? count: actual_size; + memcpy(buf, ha->xgmac_data, count); + + return count; +} + +static struct bin_attribute sysfs_xgmac_stats_attr = { + .attr = { + .name = "xgmac_stats", + .mode = S_IRUSR, + }, + .size = 0, + .read = qla2x00_sysfs_read_xgmac_stats, +}; + +static ssize_t +qla2x00_sysfs_read_dcbx_tlv(struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t off, size_t count) +{ + struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj, + struct device, kobj))); + struct qla_hw_data *ha = vha->hw; + int rval; + uint16_t actual_size; + + if (!capable(CAP_SYS_ADMIN) || off != 0 || count > DCBX_TLV_DATA_SIZE) + return 0; + + if (ha->dcbx_tlv) + goto do_read; + + ha->dcbx_tlv = dma_alloc_coherent(&ha->pdev->dev, DCBX_TLV_DATA_SIZE, + &ha->dcbx_tlv_dma, GFP_KERNEL); + if (!ha->dcbx_tlv) { + qla_printk(KERN_WARNING, ha, + "Unable to allocate memory for DCBX TLV read-data.\n"); + return 0; + } + +do_read: + actual_size = 0; + memset(ha->dcbx_tlv, 0, DCBX_TLV_DATA_SIZE); + + rval = qla2x00_get_dcbx_params(vha, ha->dcbx_tlv_dma, + DCBX_TLV_DATA_SIZE); + if (rval != QLA_SUCCESS) { + qla_printk(KERN_WARNING, ha, + "Unable to read DCBX TLV data (%x).\n", rval); + count = 0; + } + + memcpy(buf, ha->dcbx_tlv, count); + + return count; +} + +static struct bin_attribute sysfs_dcbx_tlv_attr = { + .attr = { + .name = "dcbx_tlv", + .mode = S_IRUSR, + }, + .size = 0, + .read = qla2x00_sysfs_read_dcbx_tlv, +}; + static struct sysfs_entry { char *name; struct bin_attribute *attr; @@ -706,6 +809,8 @@ static struct sysfs_entry { { "reset", &sysfs_reset_attr, }, { "edc", &sysfs_edc_attr, 2 }, { "edc_status", &sysfs_edc_status_attr, 2 }, + { "xgmac_stats", &sysfs_xgmac_stats_attr, 3 }, + { "dcbx_tlv", &sysfs_dcbx_tlv_attr, 3 }, { NULL }, }; @@ -721,6 +826,8 @@ qla2x00_alloc_sysfs_attr(scsi_qla_host_t *vha) continue; if (iter->is4GBp_only == 2 && !IS_QLA25XX(vha->hw)) continue; + if (iter->is4GBp_only == 3 && !IS_QLA81XX(vha->hw)) + continue; ret = sysfs_create_bin_file(&host->shost_gendev.kobj, iter->attr); @@ -743,6 +850,8 @@ qla2x00_free_sysfs_attr(scsi_qla_host_t *vha) continue; if (iter->is4GBp_only == 2 && !IS_QLA25XX(ha)) continue; + if (iter->is4GBp_only == 3 && !IS_QLA81XX(ha)) + continue; sysfs_remove_bin_file(&host->shost_gendev.kobj, iter->attr); @@ -1088,6 +1197,58 @@ qla2x00_flash_block_size_show(struct device *dev, return snprintf(buf, PAGE_SIZE, "0x%x\n", ha->fdt_block_size); } +static ssize_t +qla2x00_vlan_id_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); + + if (!IS_QLA81XX(vha->hw)) + return snprintf(buf, PAGE_SIZE, "\n"); + + return snprintf(buf, PAGE_SIZE, "%d\n", vha->fcoe_vlan_id); +} + +static ssize_t +qla2x00_vn_port_mac_address_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); + + if (!IS_QLA81XX(vha->hw)) + return snprintf(buf, PAGE_SIZE, "\n"); + + return snprintf(buf, PAGE_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x\n", + vha->fcoe_vn_port_mac[5], vha->fcoe_vn_port_mac[4], + vha->fcoe_vn_port_mac[3], vha->fcoe_vn_port_mac[2], + vha->fcoe_vn_port_mac[1], vha->fcoe_vn_port_mac[0]); +} + +static ssize_t +qla2x00_fabric_param_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); + + return snprintf(buf, PAGE_SIZE, "%d\n", vha->hw->switch_cap); +} + +static ssize_t +qla2x00_fw_state_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); + int rval; + uint16_t state[5]; + + rval = qla2x00_get_firmware_state(vha, state); + if (rval != QLA_SUCCESS) + memset(state, -1, sizeof(state)); + + return snprintf(buf, PAGE_SIZE, "0x%x 0x%x 0x%x 0x%x 0x%x\n", state[0], + state[1], state[2], state[3], state[4]); +} + static DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_drvr_version_show, NULL); static DEVICE_ATTR(fw_version, S_IRUGO, qla2x00_fw_version_show, NULL); static DEVICE_ATTR(serial_num, S_IRUGO, qla2x00_serial_num_show, NULL); @@ -1116,6 +1277,11 @@ static DEVICE_ATTR(mpi_version, S_IRUGO, qla2x00_mpi_version_show, NULL); static DEVICE_ATTR(phy_version, S_IRUGO, qla2x00_phy_version_show, NULL); static DEVICE_ATTR(flash_block_size, S_IRUGO, qla2x00_flash_block_size_show, NULL); +static DEVICE_ATTR(vlan_id, S_IRUGO, qla2x00_vlan_id_show, NULL); +static DEVICE_ATTR(vn_port_mac_address, S_IRUGO, + qla2x00_vn_port_mac_address_show, NULL); +static DEVICE_ATTR(fabric_param, S_IRUGO, qla2x00_fabric_param_show, NULL); +static DEVICE_ATTR(fw_state, S_IRUGO, qla2x00_fw_state_show, NULL); struct device_attribute *qla2x00_host_attrs[] = { &dev_attr_driver_version, @@ -1138,6 +1304,10 @@ struct device_attribute *qla2x00_host_attrs[] = { &dev_attr_mpi_version, &dev_attr_phy_version, &dev_attr_flash_block_size, + &dev_attr_vlan_id, + &dev_attr_vn_port_mac_address, + &dev_attr_fabric_param, + &dev_attr_fw_state, NULL, }; @@ -1313,7 +1483,8 @@ qla2x00_terminate_rport_io(struct fc_rport *rport) * At this point all fcport's software-states are cleared. Perform any * final cleanup of firmware resources (PCBs and XCBs). */ - if (fcport->loop_id != FC_NO_LOOP_ID) + if (fcport->loop_id != FC_NO_LOOP_ID && + !test_bit(UNLOADING, &fcport->vha->dpc_flags)) fcport->vha->hw->isp_ops->fabric_logout(fcport->vha, fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa); @@ -1437,11 +1608,13 @@ static int qla24xx_vport_create(struct fc_vport *fc_vport, bool disable) { int ret = 0; - int cnt = 0; - uint8_t qos = QLA_DEFAULT_QUE_QOS; + uint8_t qos = 0; scsi_qla_host_t *base_vha = shost_priv(fc_vport->shost); scsi_qla_host_t *vha = NULL; struct qla_hw_data *ha = base_vha->hw; + uint16_t options = 0; + int cnt; + struct req_que *req = ha->req_q_map[0]; ret = qla24xx_vport_create_req_sanity_check(fc_vport); if (ret) { @@ -1497,23 +1670,39 @@ qla24xx_vport_create(struct fc_vport *fc_vport, bool disable) qla24xx_vport_disable(fc_vport, disable); - /* Create a queue pair for the vport */ - if (ha->mqenable) { - if (ha->npiv_info) { - for (; cnt < ha->nvram_npiv_size; cnt++) { - if (ha->npiv_info[cnt].port_name == - vha->port_name && - ha->npiv_info[cnt].node_name == - vha->node_name) { - qos = ha->npiv_info[cnt].q_qos; - break; - } - } + if (ql2xmultique_tag) { + req = ha->req_q_map[1]; + goto vport_queue; + } else if (ql2xmaxqueues == 1 || !ha->npiv_info) + goto vport_queue; + /* Create a request queue in QoS mode for the vport */ + for (cnt = 0; cnt < ha->nvram_npiv_size; cnt++) { + if (memcmp(ha->npiv_info[cnt].port_name, vha->port_name, 8) == 0 + && memcmp(ha->npiv_info[cnt].node_name, vha->node_name, + 8) == 0) { + qos = ha->npiv_info[cnt].q_qos; + break; + } + } + if (qos) { + ret = qla25xx_create_req_que(ha, options, vha->vp_idx, 0, 0, + qos); + if (!ret) + qla_printk(KERN_WARNING, ha, + "Can't create request queue for vp_idx:%d\n", + vha->vp_idx); + else { + DEBUG2(qla_printk(KERN_INFO, ha, + "Request Que:%d (QoS: %d) created for vp_idx:%d\n", + ret, qos, vha->vp_idx)); + req = ha->req_q_map[ret]; } - qla25xx_create_queues(vha, qos); } +vport_queue: + vha->req = req; return 0; + vport_create_failed_2: qla24xx_disable_vp(vha); qla24xx_deallocate_vp_id(vha); @@ -1554,8 +1743,8 @@ qla24xx_vport_delete(struct fc_vport *fc_vport) vha->host_no, vha->vp_idx, vha)); } - if (ha->mqenable) { - if (qla25xx_delete_queues(vha, 0) != QLA_SUCCESS) + if (vha->req->id && !ql2xmultique_tag) { + if (qla25xx_delete_req_que(vha, vha->req) != QLA_SUCCESS) qla_printk(KERN_WARNING, ha, "Queue delete failed.\n"); } diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index 34760f8d4f17..cca8e4ab0372 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/qla_dbg.c @@ -149,11 +149,9 @@ qla24xx_pause_risc(struct device_reg_24xx __iomem *reg) int rval = QLA_SUCCESS; uint32_t cnt; - if (RD_REG_DWORD(®->hccr) & HCCRX_RISC_PAUSE) - return rval; - WRT_REG_DWORD(®->hccr, HCCRX_SET_RISC_PAUSE); - for (cnt = 30000; (RD_REG_DWORD(®->hccr) & HCCRX_RISC_PAUSE) == 0 && + for (cnt = 30000; + ((RD_REG_DWORD(®->host_status) & HSRX_RISC_PAUSED) == 0) && rval == QLA_SUCCESS; cnt--) { if (cnt) udelay(100); @@ -218,7 +216,7 @@ qla24xx_soft_reset(struct qla_hw_data *ha) static int qla2xxx_dump_ram(struct qla_hw_data *ha, uint32_t addr, uint16_t *ram, - uint16_t ram_words, void **nxt) + uint32_t ram_words, void **nxt) { int rval; uint32_t cnt, stat, timer, words, idx; @@ -351,7 +349,7 @@ static inline void * qla25xx_copy_mq(struct qla_hw_data *ha, void *ptr, uint32_t **last_chain) { uint32_t cnt, que_idx; - uint8_t req_cnt, rsp_cnt, que_cnt; + uint8_t que_cnt; struct qla2xxx_mq_chain *mq = ptr; struct device_reg_25xxmq __iomem *reg; @@ -363,9 +361,8 @@ qla25xx_copy_mq(struct qla_hw_data *ha, void *ptr, uint32_t **last_chain) mq->type = __constant_htonl(DUMP_CHAIN_MQ); mq->chain_size = __constant_htonl(sizeof(struct qla2xxx_mq_chain)); - req_cnt = find_first_zero_bit(ha->req_qid_map, ha->max_queues); - rsp_cnt = find_first_zero_bit(ha->rsp_qid_map, ha->max_queues); - que_cnt = req_cnt > rsp_cnt ? req_cnt : rsp_cnt; + que_cnt = ha->max_req_queues > ha->max_rsp_queues ? + ha->max_req_queues : ha->max_rsp_queues; mq->count = htonl(que_cnt); for (cnt = 0; cnt < que_cnt; cnt++) { reg = (struct device_reg_25xxmq *) ((void *) diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 714ee67567e1..00aa48d975a6 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -93,6 +93,7 @@ #define LSD(x) ((uint32_t)((uint64_t)(x))) #define MSD(x) ((uint32_t)((((uint64_t)(x)) >> 16) >> 16)) +#define MAKE_HANDLE(x, y) ((uint32_t)((((uint32_t)(x)) << 16) | (uint32_t)(y))) /* * I/O register @@ -179,6 +180,7 @@ #define REQUEST_ENTRY_CNT_24XX 2048 /* Number of request entries. */ #define RESPONSE_ENTRY_CNT_2100 64 /* Number of response entries.*/ #define RESPONSE_ENTRY_CNT_2300 512 /* Number of response entries.*/ +#define RESPONSE_ENTRY_CNT_MQ 128 /* Number of response entries.*/ struct req_que; @@ -186,7 +188,6 @@ struct req_que; * SCSI Request Block */ typedef struct srb { - struct req_que *que; struct fc_port *fcport; struct scsi_cmnd *cmd; /* Linux SCSI command pkt */ @@ -2008,7 +2009,7 @@ typedef struct vport_params { #define VP_RET_CODE_NOT_FOUND 6 struct qla_hw_data; - +struct rsp_que; /* * ISP operations */ @@ -2030,10 +2031,9 @@ struct isp_operations { void (*enable_intrs) (struct qla_hw_data *); void (*disable_intrs) (struct qla_hw_data *); - int (*abort_command) (struct scsi_qla_host *, srb_t *, - struct req_que *); - int (*target_reset) (struct fc_port *, unsigned int); - int (*lun_reset) (struct fc_port *, unsigned int); + int (*abort_command) (srb_t *); + int (*target_reset) (struct fc_port *, unsigned int, int); + int (*lun_reset) (struct fc_port *, unsigned int, int); int (*fabric_login) (struct scsi_qla_host *, uint16_t, uint8_t, uint8_t, uint8_t, uint16_t *, uint8_t); int (*fabric_logout) (struct scsi_qla_host *, uint16_t, uint8_t, @@ -2079,7 +2079,6 @@ struct isp_operations { #define QLA_PCI_MSIX_CONTROL 0xa2 struct scsi_qla_host; -struct rsp_que; struct qla_msix_entry { int have_irq; @@ -2140,7 +2139,6 @@ struct qla_statistics { #define MBC_INITIALIZE_MULTIQ 0x1f #define QLA_QUE_PAGE 0X1000 #define QLA_MQ_SIZE 32 -#define QLA_MAX_HOST_QUES 16 #define QLA_MAX_QUEUES 256 #define ISP_QUE_REG(ha, id) \ ((ha->mqenable) ? \ @@ -2170,6 +2168,8 @@ struct rsp_que { struct qla_hw_data *hw; struct qla_msix_entry *msix; struct req_que *req; + srb_t *status_srb; /* status continuation entry */ + struct work_struct q_work; }; /* Request queue data structure */ @@ -2222,6 +2222,8 @@ struct qla_hw_data { uint32_t fce_enabled :1; uint32_t fac_supported :1; uint32_t chip_reset_done :1; + uint32_t port0 :1; + uint32_t running_gold_fw :1; } flags; /* This spinlock is used to protect "io transactions", you must @@ -2246,7 +2248,8 @@ struct qla_hw_data { struct rsp_que **rsp_q_map; unsigned long req_qid_map[(QLA_MAX_QUEUES / 8) / sizeof(unsigned long)]; unsigned long rsp_qid_map[(QLA_MAX_QUEUES / 8) / sizeof(unsigned long)]; - uint16_t max_queues; + uint8_t max_req_queues; + uint8_t max_rsp_queues; struct qla_npiv_entry *npiv_info; uint16_t nvram_npiv_size; @@ -2255,6 +2258,9 @@ struct qla_hw_data { #define FLOGI_MID_SUPPORT BIT_10 #define FLOGI_VSAN_SUPPORT BIT_12 #define FLOGI_SP_SUPPORT BIT_13 + + uint8_t port_no; /* Physical port of adapter */ + /* Timeout timers. */ uint8_t loop_down_abort_time; /* port down timer */ atomic_t loop_down_timer; /* loop down timer */ @@ -2392,6 +2398,14 @@ struct qla_hw_data { dma_addr_t edc_data_dma; uint16_t edc_data_len; +#define XGMAC_DATA_SIZE PAGE_SIZE + void *xgmac_data; + dma_addr_t xgmac_data_dma; + +#define DCBX_TLV_DATA_SIZE PAGE_SIZE + void *dcbx_tlv; + dma_addr_t dcbx_tlv_dma; + struct task_struct *dpc_thread; uint8_t dpc_active; /* DPC routine is active */ @@ -2510,6 +2524,7 @@ struct qla_hw_data { uint32_t flt_region_vpd; uint32_t flt_region_nvram; uint32_t flt_region_npiv_conf; + uint32_t flt_region_gold_fw; /* Needed for BEACON */ uint16_t beacon_blink_led; @@ -2536,6 +2551,7 @@ struct qla_hw_data { struct qla_chip_state_84xx *cs84xx; struct qla_statistics qla_stats; struct isp_operations *isp_ops; + struct workqueue_struct *wq; }; /* @@ -2545,6 +2561,8 @@ typedef struct scsi_qla_host { struct list_head list; struct list_head vp_fcports; /* list of fcports */ struct list_head work_list; + spinlock_t work_lock; + /* Commonly used flags and state information. */ struct Scsi_Host *host; unsigned long host_no; @@ -2591,8 +2609,6 @@ typedef struct scsi_qla_host { #define SWITCH_FOUND BIT_0 #define DFLG_NO_CABLE BIT_1 - srb_t *status_srb; /* Status continuation entry. */ - /* ISP configuration data. */ uint16_t loop_id; /* Host adapter loop id */ @@ -2618,6 +2634,11 @@ typedef struct scsi_qla_host { uint8_t node_name[WWN_SIZE]; uint8_t port_name[WWN_SIZE]; uint8_t fabric_node_name[WWN_SIZE]; + + uint16_t fcoe_vlan_id; + uint16_t fcoe_fcf_idx; + uint8_t fcoe_vn_port_mac[6]; + uint32_t vp_abort_cnt; struct fc_vport *fc_vport; /* holds fc_vport * for each vport */ @@ -2643,7 +2664,7 @@ typedef struct scsi_qla_host { #define VP_ERR_FAB_LOGOUT 4 #define VP_ERR_ADAP_NORESOURCES 5 struct qla_hw_data *hw; - int req_ques[QLA_MAX_HOST_QUES]; + struct req_que *req; } scsi_qla_host_t; /* diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h index 96ccb9642ba0..dfde2dd865cb 100644 --- a/drivers/scsi/qla2xxx/qla_fw.h +++ b/drivers/scsi/qla2xxx/qla_fw.h @@ -878,7 +878,6 @@ struct device_reg_24xx { /* HCCR statuses. */ #define HCCRX_HOST_INT BIT_6 /* Host to RISC interrupt bit. */ #define HCCRX_RISC_RESET BIT_5 /* RISC Reset mode bit. */ -#define HCCRX_RISC_PAUSE BIT_4 /* RISC Pause mode bit. */ /* HCCR commands. */ /* NOOP. */ #define HCCRX_NOOP 0x00000000 @@ -1241,6 +1240,7 @@ struct qla_flt_header { #define FLT_REG_HW_EVENT_1 0x1f #define FLT_REG_NPIV_CONF_0 0x29 #define FLT_REG_NPIV_CONF_1 0x2a +#define FLT_REG_GOLD_FW 0x2f struct qla_flt_region { uint32_t code; @@ -1405,6 +1405,8 @@ struct access_chip_rsp_84xx { #define MBC_IDC_ACK 0x101 #define MBC_RESTART_MPI_FW 0x3d #define MBC_FLASH_ACCESS_CTRL 0x3e /* Control flash access. */ +#define MBC_GET_XGMAC_STATS 0x7a +#define MBC_GET_DCBX_PARAMS 0x51 /* Flash access control option field bit definitions */ #define FAC_OPT_FORCE_SEMAPHORE BIT_15 @@ -1711,7 +1713,7 @@ struct ex_init_cb_81xx { #define FA_VPD0_ADDR_81 0xD0000 #define FA_VPD1_ADDR_81 0xD0400 #define FA_NVRAM0_ADDR_81 0xD0080 -#define FA_NVRAM1_ADDR_81 0xD0480 +#define FA_NVRAM1_ADDR_81 0xD0180 #define FA_FEATURE_ADDR_81 0xD4000 #define FA_FLASH_DESCR_ADDR_81 0xD8000 #define FA_FLASH_LAYOUT_ADDR_81 0xD8400 diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 528913f6bed9..65b12d82867c 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -65,8 +65,11 @@ extern int ql2xfdmienable; extern int ql2xallocfwdump; extern int ql2xextended_error_logging; extern int ql2xqfullrampup; +extern int ql2xqfulltracking; extern int ql2xiidmaenable; extern int ql2xmaxqueues; +extern int ql2xmultique_tag; +extern int ql2xfwloadbin; extern int qla2x00_loop_reset(scsi_qla_host_t *); extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int); @@ -145,7 +148,7 @@ qla2x00_dump_ram(scsi_qla_host_t *, dma_addr_t, uint32_t, uint32_t); extern int qla2x00_execute_fw(scsi_qla_host_t *, uint32_t); -extern void +extern int qla2x00_get_fw_version(scsi_qla_host_t *, uint16_t *, uint16_t *, uint16_t *, uint16_t *, uint32_t *, uint8_t *, uint32_t *, uint8_t *); @@ -165,13 +168,13 @@ extern int qla2x00_issue_iocb(scsi_qla_host_t *, void *, dma_addr_t, size_t); extern int -qla2x00_abort_command(scsi_qla_host_t *, srb_t *, struct req_que *); +qla2x00_abort_command(srb_t *); extern int -qla2x00_abort_target(struct fc_port *, unsigned int); +qla2x00_abort_target(struct fc_port *, unsigned int, int); extern int -qla2x00_lun_reset(struct fc_port *, unsigned int); +qla2x00_lun_reset(struct fc_port *, unsigned int, int); extern int qla2x00_get_adapter_id(scsi_qla_host_t *, uint16_t *, uint8_t *, uint8_t *, @@ -236,9 +239,11 @@ extern int qla24xx_get_isp_stats(scsi_qla_host_t *, struct link_statistics *, dma_addr_t); -extern int qla24xx_abort_command(scsi_qla_host_t *, srb_t *, struct req_que *); -extern int qla24xx_abort_target(struct fc_port *, unsigned int); -extern int qla24xx_lun_reset(struct fc_port *, unsigned int); +extern int qla24xx_abort_command(srb_t *); +extern int +qla24xx_abort_target(struct fc_port *, unsigned int, int); +extern int +qla24xx_lun_reset(struct fc_port *, unsigned int, int); extern int qla2x00_system_error(scsi_qla_host_t *); @@ -288,6 +293,18 @@ qla81xx_fac_do_write_enable(scsi_qla_host_t *, int); extern int qla81xx_fac_erase_sector(scsi_qla_host_t *, uint32_t, uint32_t); +extern int +qla2x00_get_xgmac_stats(scsi_qla_host_t *, dma_addr_t, uint16_t, uint16_t *); + +extern int +qla2x00_get_dcbx_params(scsi_qla_host_t *, dma_addr_t, uint16_t); + +extern int +qla2x00_read_ram_word(scsi_qla_host_t *, uint32_t, uint32_t *); + +extern int +qla2x00_write_ram_word(scsi_qla_host_t *, uint32_t, uint32_t); + /* * Global Function Prototypes in qla_isr.c source file. */ @@ -295,8 +312,8 @@ extern irqreturn_t qla2100_intr_handler(int, void *); extern irqreturn_t qla2300_intr_handler(int, void *); extern irqreturn_t qla24xx_intr_handler(int, void *); extern void qla2x00_process_response_queue(struct rsp_que *); -extern void qla24xx_process_response_queue(struct rsp_que *); - +extern void +qla24xx_process_response_queue(struct scsi_qla_host *, struct rsp_que *); extern int qla2x00_request_irqs(struct qla_hw_data *, struct rsp_que *); extern void qla2x00_free_irqs(scsi_qla_host_t *); @@ -401,19 +418,21 @@ extern int qla25xx_request_irq(struct rsp_que *); extern int qla25xx_init_req_que(struct scsi_qla_host *, struct req_que *); extern int qla25xx_init_rsp_que(struct scsi_qla_host *, struct rsp_que *); extern int qla25xx_create_req_que(struct qla_hw_data *, uint16_t, uint8_t, - uint16_t, uint8_t, uint8_t); + uint16_t, int, uint8_t); extern int qla25xx_create_rsp_que(struct qla_hw_data *, uint16_t, uint8_t, - uint16_t); + uint16_t, int); extern int qla25xx_update_req_que(struct scsi_qla_host *, uint8_t, uint8_t); extern void qla2x00_init_response_q_entries(struct rsp_que *); extern int qla25xx_delete_req_que(struct scsi_qla_host *, struct req_que *); extern int qla25xx_delete_rsp_que(struct scsi_qla_host *, struct rsp_que *); extern int qla25xx_create_queues(struct scsi_qla_host *, uint8_t); -extern int qla25xx_delete_queues(struct scsi_qla_host *, uint8_t); +extern int qla25xx_delete_queues(struct scsi_qla_host *); extern uint16_t qla24xx_rd_req_reg(struct qla_hw_data *, uint16_t); extern uint16_t qla25xx_rd_req_reg(struct qla_hw_data *, uint16_t); extern void qla24xx_wrt_req_reg(struct qla_hw_data *, uint16_t, uint16_t); extern void qla25xx_wrt_req_reg(struct qla_hw_data *, uint16_t, uint16_t); extern void qla25xx_wrt_rsp_reg(struct qla_hw_data *, uint16_t, uint16_t); extern void qla24xx_wrt_rsp_reg(struct qla_hw_data *, uint16_t, uint16_t); +extern struct scsi_qla_host * qla25xx_get_host(struct rsp_que *); + #endif /* _QLA_GBL_H */ diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index 557f58d5bf88..917534b9f221 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -1107,7 +1107,7 @@ qla2x00_mgmt_svr_login(scsi_qla_host_t *vha) return ret; ha->isp_ops->fabric_login(vha, vha->mgmt_svr_loop_id, 0xff, 0xff, 0xfa, - mb, BIT_1); + mb, BIT_1|BIT_0); if (mb[0] != MBS_COMMAND_COMPLETE) { DEBUG2_13(printk("%s(%ld): Failed MANAGEMENT_SERVER login: " "loop_id=%x mb[0]=%x mb[1]=%x mb[2]=%x mb[6]=%x mb[7]=%x\n", @@ -1879,6 +1879,9 @@ qla2x00_gpsc(scsi_qla_host_t *vha, sw_info_t *list) case BIT_13: list[i].fp_speed = PORT_SPEED_4GB; break; + case BIT_12: + list[i].fp_speed = PORT_SPEED_10GB; + break; case BIT_11: list[i].fp_speed = PORT_SPEED_8GB; break; diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index bd7dd84c0648..f2ce8e3cc91b 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -634,7 +634,7 @@ qla2x00_chip_diag(scsi_qla_host_t *vha) goto chip_diag_failed; DEBUG3(printk("scsi(%ld): Reset register cleared by chip reset\n", - ha->host_no)); + vha->host_no)); /* Reset RISC processor. */ WRT_REG_WORD(®->hccr, HCCR_RESET_RISC); @@ -655,7 +655,7 @@ qla2x00_chip_diag(scsi_qla_host_t *vha) goto chip_diag_failed; /* Check product ID of chip */ - DEBUG3(printk("scsi(%ld): Checking product ID of chip\n", ha->host_no)); + DEBUG3(printk("scsi(%ld): Checking product ID of chip\n", vha->host_no)); mb[1] = RD_MAILBOX_REG(ha, reg, 1); mb[2] = RD_MAILBOX_REG(ha, reg, 2); @@ -730,9 +730,6 @@ qla24xx_chip_diag(scsi_qla_host_t *vha) struct qla_hw_data *ha = vha->hw; struct req_que *req = ha->req_q_map[0]; - /* Perform RISC reset. */ - qla24xx_reset_risc(vha); - ha->fw_transfer_size = REQUEST_ENTRY_SIZE * req->length; rval = qla2x00_mbx_reg_test(vha); @@ -786,7 +783,6 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha) sizeof(uint32_t); if (ha->mqenable) mq_size = sizeof(struct qla2xxx_mq_chain); - /* Allocate memory for Fibre Channel Event Buffer. */ if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha)) goto try_eft; @@ -850,8 +846,7 @@ cont_alloc: rsp_q_size = rsp->length * sizeof(response_t); dump_size = offsetof(struct qla2xxx_fw_dump, isp); - dump_size += fixed_size + mem_size + req_q_size + rsp_q_size + - eft_size; + dump_size += fixed_size + mem_size + req_q_size + rsp_q_size + eft_size; ha->chain_offset = dump_size; dump_size += mq_size + fce_size; @@ -891,6 +886,56 @@ cont_alloc: htonl(offsetof(struct qla2xxx_fw_dump, isp)); } +static int +qla81xx_mpi_sync(scsi_qla_host_t *vha) +{ +#define MPS_MASK 0xe0 + int rval; + uint16_t dc; + uint32_t dw; + struct qla_hw_data *ha = vha->hw; + + if (!IS_QLA81XX(vha->hw)) + return QLA_SUCCESS; + + rval = qla2x00_write_ram_word(vha, 0x7c00, 1); + if (rval != QLA_SUCCESS) { + DEBUG2(qla_printk(KERN_WARNING, ha, + "Sync-MPI: Unable to acquire semaphore.\n")); + goto done; + } + + pci_read_config_word(vha->hw->pdev, 0x54, &dc); + rval = qla2x00_read_ram_word(vha, 0x7a15, &dw); + if (rval != QLA_SUCCESS) { + DEBUG2(qla_printk(KERN_WARNING, ha, + "Sync-MPI: Unable to read sync.\n")); + goto done_release; + } + + dc &= MPS_MASK; + if (dc == (dw & MPS_MASK)) + goto done_release; + + dw &= ~MPS_MASK; + dw |= dc; + rval = qla2x00_write_ram_word(vha, 0x7a15, dw); + if (rval != QLA_SUCCESS) { + DEBUG2(qla_printk(KERN_WARNING, ha, + "Sync-MPI: Unable to gain sync.\n")); + } + +done_release: + rval = qla2x00_write_ram_word(vha, 0x7c00, 0); + if (rval != QLA_SUCCESS) { + DEBUG2(qla_printk(KERN_WARNING, ha, + "Sync-MPI: Unable to release semaphore.\n")); + } + +done: + return rval; +} + /** * qla2x00_setup_chip() - Load and start RISC firmware. * @ha: HA context @@ -915,6 +960,8 @@ qla2x00_setup_chip(scsi_qla_host_t *vha) spin_unlock_irqrestore(&ha->hardware_lock, flags); } + qla81xx_mpi_sync(vha); + /* Load firmware sequences */ rval = ha->isp_ops->load_risc(vha, &srisc_address); if (rval == QLA_SUCCESS) { @@ -931,13 +978,16 @@ qla2x00_setup_chip(scsi_qla_host_t *vha) /* Retrieve firmware information. */ if (rval == QLA_SUCCESS) { fw_major_version = ha->fw_major_version; - qla2x00_get_fw_version(vha, + rval = qla2x00_get_fw_version(vha, &ha->fw_major_version, &ha->fw_minor_version, &ha->fw_subminor_version, &ha->fw_attributes, &ha->fw_memory_size, ha->mpi_version, &ha->mpi_capabilities, ha->phy_version); + if (rval != QLA_SUCCESS) + goto failed; + ha->flags.npiv_supported = 0; if (IS_QLA2XXX_MIDTYPE(ha) && (ha->fw_attributes & BIT_2)) { @@ -989,7 +1039,7 @@ qla2x00_setup_chip(scsi_qla_host_t *vha) ha->fw_subminor_version); } } - +failed: if (rval) { DEBUG2_3(printk("scsi(%ld): Setup chip **** FAILED ****.\n", vha->host_no)); @@ -1013,12 +1063,14 @@ qla2x00_init_response_q_entries(struct rsp_que *rsp) uint16_t cnt; response_t *pkt; + rsp->ring_ptr = rsp->ring; + rsp->ring_index = 0; + rsp->status_srb = NULL; pkt = rsp->ring_ptr; for (cnt = 0; cnt < rsp->length; cnt++) { pkt->signature = RESPONSE_PROCESSED; pkt++; } - } /** @@ -1176,7 +1228,7 @@ qla24xx_config_rings(struct scsi_qla_host *vha) if (ha->flags.msix_enabled) { msix = &ha->msix_entries[1]; DEBUG2_17(printk(KERN_INFO - "Reistering vector 0x%x for base que\n", msix->entry)); + "Registering vector 0x%x for base que\n", msix->entry)); icb->msix = cpu_to_le16(msix->entry); } /* Use alternate PCI bus number */ @@ -1230,14 +1282,14 @@ qla2x00_init_rings(scsi_qla_host_t *vha) spin_lock_irqsave(&ha->hardware_lock, flags); /* Clear outstanding commands array. */ - for (que = 0; que < ha->max_queues; que++) { + for (que = 0; que < ha->max_req_queues; que++) { req = ha->req_q_map[que]; if (!req) continue; - for (cnt = 0; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) + for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) req->outstanding_cmds[cnt] = NULL; - req->current_outstanding_cmd = 0; + req->current_outstanding_cmd = 1; /* Initialize firmware. */ req->ring_ptr = req->ring; @@ -1245,13 +1297,10 @@ qla2x00_init_rings(scsi_qla_host_t *vha) req->cnt = req->length; } - for (que = 0; que < ha->max_queues; que++) { + for (que = 0; que < ha->max_rsp_queues; que++) { rsp = ha->rsp_q_map[que]; if (!rsp) continue; - rsp->ring_ptr = rsp->ring; - rsp->ring_index = 0; - /* Initialize response queue entries */ qla2x00_init_response_q_entries(rsp); } @@ -1307,7 +1356,7 @@ qla2x00_fw_ready(scsi_qla_host_t *vha) unsigned long wtime, mtime, cs84xx_time; uint16_t min_wait; /* Minimum wait time if loop is down */ uint16_t wait_time; /* Wait time if loop is coming ready */ - uint16_t state[3]; + uint16_t state[5]; struct qla_hw_data *ha = vha->hw; rval = QLA_SUCCESS; @@ -1406,8 +1455,9 @@ qla2x00_fw_ready(scsi_qla_host_t *vha) vha->host_no, state[0], jiffies)); } while (1); - DEBUG(printk("scsi(%ld): fw_state=%x curr time=%lx.\n", - vha->host_no, state[0], jiffies)); + DEBUG(printk("scsi(%ld): fw_state=%x (%x, %x, %x, %x) curr time=%lx.\n", + vha->host_no, state[0], state[1], state[2], state[3], state[4], + jiffies)); if (rval) { DEBUG2_3(printk("scsi(%ld): Firmware ready **** FAILED ****.\n", @@ -1541,6 +1591,7 @@ qla2x00_set_model_info(scsi_qla_host_t *vha, uint8_t *model, size_t len, char *st, *en; uint16_t index; struct qla_hw_data *ha = vha->hw; + int use_tbl = !IS_QLA25XX(ha) && !IS_QLA81XX(ha); if (memcmp(model, BINZERO, len) != 0) { strncpy(ha->model_number, model, len); @@ -1553,14 +1604,16 @@ qla2x00_set_model_info(scsi_qla_host_t *vha, uint8_t *model, size_t len, } index = (ha->pdev->subsystem_device & 0xff); - if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC && + if (use_tbl && + ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC && index < QLA_MODEL_NAMES) strncpy(ha->model_desc, qla2x00_model_name[index * 2 + 1], sizeof(ha->model_desc) - 1); } else { index = (ha->pdev->subsystem_device & 0xff); - if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC && + if (use_tbl && + ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC && index < QLA_MODEL_NAMES) { strcpy(ha->model_number, qla2x00_model_name[index * 2]); @@ -2061,8 +2114,10 @@ qla2x00_configure_loop(scsi_qla_host_t *vha) if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) { if (test_bit(LOCAL_LOOP_UPDATE, &save_flags)) set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); - if (test_bit(RSCN_UPDATE, &save_flags)) + if (test_bit(RSCN_UPDATE, &save_flags)) { set_bit(RSCN_UPDATE, &vha->dpc_flags); + vha->flags.rscn_queue_overflow = 1; + } } return (rval); @@ -2110,7 +2165,7 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha) goto cleanup_allocation; DEBUG3(printk("scsi(%ld): Entries in ID list (%d)\n", - ha->host_no, entries)); + vha->host_no, entries)); DEBUG3(qla2x00_dump_buffer((uint8_t *)ha->gid_list, entries * sizeof(struct gid_list_info))); @@ -2243,9 +2298,10 @@ static void qla2x00_iidma_fcport(scsi_qla_host_t *vha, fc_port_t *fcport) { #define LS_UNKNOWN 2 - static char *link_speeds[5] = { "1", "2", "?", "4", "8" }; + static char *link_speeds[] = { "1", "2", "?", "4", "8", "10" }; + char *link_speed; int rval; - uint16_t mb[6]; + uint16_t mb[4]; struct qla_hw_data *ha = vha->hw; if (!IS_IIDMA_CAPABLE(ha)) @@ -2266,10 +2322,15 @@ qla2x00_iidma_fcport(scsi_qla_host_t *vha, fc_port_t *fcport) fcport->port_name[6], fcport->port_name[7], rval, fcport->fp_speed, mb[0], mb[1])); } else { + link_speed = link_speeds[LS_UNKNOWN]; + if (fcport->fp_speed < 5) + link_speed = link_speeds[fcport->fp_speed]; + else if (fcport->fp_speed == 0x13) + link_speed = link_speeds[5]; DEBUG2(qla_printk(KERN_INFO, ha, "iIDMA adjusted to %s GB/s on " "%02x%02x%02x%02x%02x%02x%02x%02x.\n", - link_speeds[fcport->fp_speed], fcport->port_name[0], + link_speed, fcport->port_name[0], fcport->port_name[1], fcport->port_name[2], fcport->port_name[3], fcport->port_name[4], fcport->port_name[5], fcport->port_name[6], @@ -3180,9 +3241,14 @@ qla2x00_loop_resync(scsi_qla_host_t *vha) { int rval = QLA_SUCCESS; uint32_t wait_time; - struct qla_hw_data *ha = vha->hw; - struct req_que *req = ha->req_q_map[vha->req_ques[0]]; - struct rsp_que *rsp = req->rsp; + struct req_que *req; + struct rsp_que *rsp; + + if (ql2xmultique_tag) + req = vha->hw->req_q_map[0]; + else + req = vha->req; + rsp = req->rsp; atomic_set(&vha->loop_state, LOOP_UPDATE); clear_bit(ISP_ABORT_RETRY, &vha->dpc_flags); @@ -3448,7 +3514,7 @@ qla25xx_init_queues(struct qla_hw_data *ha) int ret = -1; int i; - for (i = 1; i < ha->max_queues; i++) { + for (i = 1; i < ha->max_rsp_queues; i++) { rsp = ha->rsp_q_map[i]; if (rsp) { rsp->options &= ~BIT_0; @@ -3462,6 +3528,8 @@ qla25xx_init_queues(struct qla_hw_data *ha) "%s Rsp que:%d inited\n", __func__, rsp->id)); } + } + for (i = 1; i < ha->max_req_queues; i++) { req = ha->req_q_map[i]; if (req) { /* Clear outstanding commands array. */ @@ -3566,14 +3634,15 @@ qla24xx_nvram_config(scsi_qla_host_t *vha) nv = ha->nvram; /* Determine NVRAM starting address. */ - ha->nvram_size = sizeof(struct nvram_24xx); - ha->nvram_base = FA_NVRAM_FUNC0_ADDR; - ha->vpd_size = FA_NVRAM_VPD_SIZE; - ha->vpd_base = FA_NVRAM_VPD0_ADDR; - if (PCI_FUNC(ha->pdev->devfn)) { + if (ha->flags.port0) { + ha->nvram_base = FA_NVRAM_FUNC0_ADDR; + ha->vpd_base = FA_NVRAM_VPD0_ADDR; + } else { ha->nvram_base = FA_NVRAM_FUNC1_ADDR; ha->vpd_base = FA_NVRAM_VPD1_ADDR; } + ha->nvram_size = sizeof(struct nvram_24xx); + ha->vpd_size = FA_NVRAM_VPD_SIZE; /* Get VPD data into cache */ ha->vpd = ha->nvram + VPD_OFFSET; @@ -3587,7 +3656,7 @@ qla24xx_nvram_config(scsi_qla_host_t *vha) for (cnt = 0, chksum = 0; cnt < ha->nvram_size >> 2; cnt++) chksum += le32_to_cpu(*dptr++); - DEBUG5(printk("scsi(%ld): Contents of NVRAM\n", ha->host_no)); + DEBUG5(printk("scsi(%ld): Contents of NVRAM\n", vha->host_no)); DEBUG5(qla2x00_dump_buffer((uint8_t *)nv, ha->nvram_size)); /* Bad NVRAM data, set defaults parameters. */ @@ -3612,7 +3681,7 @@ qla24xx_nvram_config(scsi_qla_host_t *vha) nv->exchange_count = __constant_cpu_to_le16(0); nv->hard_address = __constant_cpu_to_le16(124); nv->port_name[0] = 0x21; - nv->port_name[1] = 0x00 + PCI_FUNC(ha->pdev->devfn); + nv->port_name[1] = 0x00 + ha->port_no; nv->port_name[2] = 0x00; nv->port_name[3] = 0xe0; nv->port_name[4] = 0x8b; @@ -3798,11 +3867,11 @@ qla24xx_nvram_config(scsi_qla_host_t *vha) } static int -qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr) +qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr, + uint32_t faddr) { int rval = QLA_SUCCESS; int segments, fragment; - uint32_t faddr; uint32_t *dcode, dlen; uint32_t risc_addr; uint32_t risc_size; @@ -3811,12 +3880,11 @@ qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr) struct req_que *req = ha->req_q_map[0]; qla_printk(KERN_INFO, ha, - "FW: Loading from flash (%x)...\n", ha->flt_region_fw); + "FW: Loading from flash (%x)...\n", faddr); rval = QLA_SUCCESS; segments = FA_RISC_CODE_SEGMENTS; - faddr = ha->flt_region_fw; dcode = (uint32_t *)req->ring; *srisc_addr = 0; @@ -4104,6 +4172,9 @@ qla24xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr) { int rval; + if (ql2xfwloadbin == 1) + return qla81xx_load_risc(vha, srisc_addr); + /* * FW Load priority: * 1) Firmware via request-firmware interface (.bin file). @@ -4113,24 +4184,45 @@ qla24xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr) if (rval == QLA_SUCCESS) return rval; - return qla24xx_load_risc_flash(vha, srisc_addr); + return qla24xx_load_risc_flash(vha, srisc_addr, + vha->hw->flt_region_fw); } int qla81xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr) { int rval; + struct qla_hw_data *ha = vha->hw; + + if (ql2xfwloadbin == 2) + goto try_blob_fw; /* * FW Load priority: * 1) Firmware residing in flash. * 2) Firmware via request-firmware interface (.bin file). + * 3) Golden-Firmware residing in flash -- limited operation. */ - rval = qla24xx_load_risc_flash(vha, srisc_addr); + rval = qla24xx_load_risc_flash(vha, srisc_addr, ha->flt_region_fw); if (rval == QLA_SUCCESS) return rval; - return qla24xx_load_risc_blob(vha, srisc_addr); +try_blob_fw: + rval = qla24xx_load_risc_blob(vha, srisc_addr); + if (rval == QLA_SUCCESS || !ha->flt_region_gold_fw) + return rval; + + qla_printk(KERN_ERR, ha, + "FW: Attempting to fallback to golden firmware...\n"); + rval = qla24xx_load_risc_flash(vha, srisc_addr, ha->flt_region_gold_fw); + if (rval != QLA_SUCCESS) + return rval; + + qla_printk(KERN_ERR, ha, + "FW: Please update operational firmware...\n"); + ha->flags.running_gold_fw = 1; + + return rval; } void @@ -4146,7 +4238,7 @@ qla2x00_try_to_stop_firmware(scsi_qla_host_t *vha) ret = qla2x00_stop_firmware(vha); for (retries = 5; ret != QLA_SUCCESS && ret != QLA_FUNCTION_TIMEOUT && - retries ; retries--) { + ret != QLA_INVALID_COMMAND && retries ; retries--) { ha->isp_ops->reset_chip(vha); if (ha->isp_ops->chip_diag(vha) != QLA_SUCCESS) continue; @@ -4165,13 +4257,19 @@ qla24xx_configure_vhba(scsi_qla_host_t *vha) uint16_t mb[MAILBOX_REGISTER_COUNT]; struct qla_hw_data *ha = vha->hw; struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); - struct req_que *req = ha->req_q_map[vha->req_ques[0]]; - struct rsp_que *rsp = req->rsp; + struct req_que *req; + struct rsp_que *rsp; if (!vha->vp_idx) return -EINVAL; rval = qla2x00_fw_ready(base_vha); + if (ql2xmultique_tag) + req = ha->req_q_map[0]; + else + req = vha->req; + rsp = req->rsp; + if (rval == QLA_SUCCESS) { clear_bit(RESET_MARKER_NEEDED, &vha->dpc_flags); qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL); @@ -4305,7 +4403,7 @@ qla81xx_nvram_config(scsi_qla_host_t *vha) for (cnt = 0, chksum = 0; cnt < ha->nvram_size >> 2; cnt++) chksum += le32_to_cpu(*dptr++); - DEBUG5(printk("scsi(%ld): Contents of NVRAM\n", ha->host_no)); + DEBUG5(printk("scsi(%ld): Contents of NVRAM\n", vha->host_no)); DEBUG5(qla2x00_dump_buffer((uint8_t *)nv, ha->nvram_size)); /* Bad NVRAM data, set defaults parameters. */ @@ -4329,7 +4427,7 @@ qla81xx_nvram_config(scsi_qla_host_t *vha) nv->execution_throttle = __constant_cpu_to_le16(0xFFFF); nv->exchange_count = __constant_cpu_to_le16(0); nv->port_name[0] = 0x21; - nv->port_name[1] = 0x00 + PCI_FUNC(ha->pdev->devfn); + nv->port_name[1] = 0x00 + ha->port_no; nv->port_name[2] = 0x00; nv->port_name[3] = 0xe0; nv->port_name[4] = 0x8b; @@ -4358,12 +4456,12 @@ qla81xx_nvram_config(scsi_qla_host_t *vha) nv->max_luns_per_target = __constant_cpu_to_le16(128); nv->port_down_retry_count = __constant_cpu_to_le16(30); nv->link_down_timeout = __constant_cpu_to_le16(30); - nv->enode_mac[0] = 0x01; + nv->enode_mac[0] = 0x00; nv->enode_mac[1] = 0x02; nv->enode_mac[2] = 0x03; nv->enode_mac[3] = 0x04; nv->enode_mac[4] = 0x05; - nv->enode_mac[5] = 0x06 + PCI_FUNC(ha->pdev->devfn); + nv->enode_mac[5] = 0x06 + ha->port_no; rval = 1; } @@ -4396,7 +4494,7 @@ qla81xx_nvram_config(scsi_qla_host_t *vha) icb->enode_mac[2] = 0x03; icb->enode_mac[3] = 0x04; icb->enode_mac[4] = 0x05; - icb->enode_mac[5] = 0x06 + PCI_FUNC(ha->pdev->devfn); + icb->enode_mac[5] = 0x06 + ha->port_no; } /* Use extended-initialization control block. */ diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index a8abbb95730d..13396beae2ce 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -15,6 +15,7 @@ static request_t *qla2x00_req_pkt(struct scsi_qla_host *, struct req_que *, struct rsp_que *rsp); static void qla2x00_isp_cmd(struct scsi_qla_host *, struct req_que *); +static void qla25xx_set_que(srb_t *, struct rsp_que **); /** * qla2x00_get_cmd_direction() - Determine control_flag data direction. * @cmd: SCSI command @@ -92,9 +93,10 @@ qla2x00_calc_iocbs_64(uint16_t dsds) * Returns a pointer to the Continuation Type 0 IOCB packet. */ static inline cont_entry_t * -qla2x00_prep_cont_type0_iocb(struct req_que *req, struct scsi_qla_host *vha) +qla2x00_prep_cont_type0_iocb(struct scsi_qla_host *vha) { cont_entry_t *cont_pkt; + struct req_que *req = vha->req; /* Adjust ring index. */ req->ring_index++; if (req->ring_index == req->length) { @@ -120,10 +122,11 @@ qla2x00_prep_cont_type0_iocb(struct req_que *req, struct scsi_qla_host *vha) * Returns a pointer to the continuation type 1 IOCB packet. */ static inline cont_a64_entry_t * -qla2x00_prep_cont_type1_iocb(struct req_que *req, scsi_qla_host_t *vha) +qla2x00_prep_cont_type1_iocb(scsi_qla_host_t *vha) { cont_a64_entry_t *cont_pkt; + struct req_que *req = vha->req; /* Adjust ring index. */ req->ring_index++; if (req->ring_index == req->length) { @@ -159,7 +162,6 @@ void qla2x00_build_scsi_iocbs_32(srb_t *sp, cmd_entry_t *cmd_pkt, struct scsi_cmnd *cmd; struct scatterlist *sg; int i; - struct req_que *req; cmd = sp->cmd; @@ -174,8 +176,6 @@ void qla2x00_build_scsi_iocbs_32(srb_t *sp, cmd_entry_t *cmd_pkt, } vha = sp->fcport->vha; - req = sp->que; - cmd_pkt->control_flags |= cpu_to_le16(qla2x00_get_cmd_direction(sp)); /* Three DSDs are available in the Command Type 2 IOCB */ @@ -192,7 +192,7 @@ void qla2x00_build_scsi_iocbs_32(srb_t *sp, cmd_entry_t *cmd_pkt, * Seven DSDs are available in the Continuation * Type 0 IOCB. */ - cont_pkt = qla2x00_prep_cont_type0_iocb(req, vha); + cont_pkt = qla2x00_prep_cont_type0_iocb(vha); cur_dsd = (uint32_t *)&cont_pkt->dseg_0_address; avail_dsds = 7; } @@ -220,7 +220,6 @@ void qla2x00_build_scsi_iocbs_64(srb_t *sp, cmd_entry_t *cmd_pkt, struct scsi_cmnd *cmd; struct scatterlist *sg; int i; - struct req_que *req; cmd = sp->cmd; @@ -235,8 +234,6 @@ void qla2x00_build_scsi_iocbs_64(srb_t *sp, cmd_entry_t *cmd_pkt, } vha = sp->fcport->vha; - req = sp->que; - cmd_pkt->control_flags |= cpu_to_le16(qla2x00_get_cmd_direction(sp)); /* Two DSDs are available in the Command Type 3 IOCB */ @@ -254,7 +251,7 @@ void qla2x00_build_scsi_iocbs_64(srb_t *sp, cmd_entry_t *cmd_pkt, * Five DSDs are available in the Continuation * Type 1 IOCB. */ - cont_pkt = qla2x00_prep_cont_type1_iocb(req, vha); + cont_pkt = qla2x00_prep_cont_type1_iocb(vha); cur_dsd = (uint32_t *)cont_pkt->dseg_0_address; avail_dsds = 5; } @@ -353,7 +350,6 @@ qla2x00_start_scsi(srb_t *sp) /* Build command packet */ req->current_outstanding_cmd = handle; req->outstanding_cmds[handle] = sp; - sp->que = req; sp->cmd->host_scribble = (unsigned char *)(unsigned long)handle; req->cnt -= req_cnt; @@ -453,6 +449,7 @@ __qla2x00_marker(struct scsi_qla_host *vha, struct req_que *req, mrk24->lun[2] = MSB(lun); host_to_fcp_swap(mrk24->lun, sizeof(mrk24->lun)); mrk24->vp_index = vha->vp_idx; + mrk24->handle = MAKE_HANDLE(req->id, mrk24->handle); } else { SET_TARGET_ID(ha, mrk->target, loop_id); mrk->lun = cpu_to_le16(lun); @@ -531,9 +528,6 @@ qla2x00_req_pkt(struct scsi_qla_host *vha, struct req_que *req, for (cnt = 0; cnt < REQUEST_ENTRY_SIZE / 4; cnt++) *dword_ptr++ = 0; - /* Set system defined field. */ - pkt->sys_define = (uint8_t)req->ring_index; - /* Set entry count. */ pkt->entry_count = 1; @@ -656,7 +650,7 @@ qla24xx_build_scsi_iocbs(srb_t *sp, struct cmd_type_7 *cmd_pkt, } vha = sp->fcport->vha; - req = sp->que; + req = vha->req; /* Set transfer direction */ if (cmd->sc_data_direction == DMA_TO_DEVICE) { @@ -687,7 +681,7 @@ qla24xx_build_scsi_iocbs(srb_t *sp, struct cmd_type_7 *cmd_pkt, * Five DSDs are available in the Continuation * Type 1 IOCB. */ - cont_pkt = qla2x00_prep_cont_type1_iocb(req, vha); + cont_pkt = qla2x00_prep_cont_type1_iocb(vha); cur_dsd = (uint32_t *)cont_pkt->dseg_0_address; avail_dsds = 5; } @@ -724,19 +718,13 @@ qla24xx_start_scsi(srb_t *sp) struct scsi_cmnd *cmd = sp->cmd; struct scsi_qla_host *vha = sp->fcport->vha; struct qla_hw_data *ha = vha->hw; - uint16_t que_id; /* Setup device pointers. */ ret = 0; - que_id = vha->req_ques[0]; - req = ha->req_q_map[que_id]; - sp->que = req; + qla25xx_set_que(sp, &rsp); + req = vha->req; - if (req->rsp) - rsp = req->rsp; - else - rsp = ha->rsp_q_map[que_id]; /* So we know we haven't pci_map'ed anything yet */ tot_dsds = 0; @@ -794,7 +782,7 @@ qla24xx_start_scsi(srb_t *sp) req->cnt -= req_cnt; cmd_pkt = (struct cmd_type_7 *)req->ring_ptr; - cmd_pkt->handle = handle; + cmd_pkt->handle = MAKE_HANDLE(req->id, handle); /* Zero out remaining portion of packet. */ /* tagged queuing modifier -- default is TSK_SIMPLE (0). */ @@ -823,6 +811,8 @@ qla24xx_start_scsi(srb_t *sp) /* Set total data segment count. */ cmd_pkt->entry_count = (uint8_t)req_cnt; + /* Specify response queue number where completion should happen */ + cmd_pkt->entry_status = (uint8_t) rsp->id; wmb(); /* Adjust ring index. */ @@ -842,7 +832,7 @@ qla24xx_start_scsi(srb_t *sp) /* Manage unprocessed RIO/ZIO commands in response queue. */ if (vha->flags.process_response_queue && rsp->ring_ptr->signature != RESPONSE_PROCESSED) - qla24xx_process_response_queue(rsp); + qla24xx_process_response_queue(vha, rsp); spin_unlock_irqrestore(&ha->hardware_lock, flags); return QLA_SUCCESS; @@ -855,3 +845,16 @@ queuing_error: return QLA_FUNCTION_FAILED; } + +static void qla25xx_set_que(srb_t *sp, struct rsp_que **rsp) +{ + struct scsi_cmnd *cmd = sp->cmd; + struct qla_hw_data *ha = sp->fcport->vha->hw; + int affinity = cmd->request->cpu; + + if (ql2xmultique_tag && affinity >= 0 && + affinity < ha->max_rsp_queues - 1) + *rsp = ha->rsp_q_map[affinity + 1]; + else + *rsp = ha->rsp_q_map[0]; +} diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index d04981848e56..245e7afb4c4d 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -13,10 +13,9 @@ static void qla2x00_mbx_completion(scsi_qla_host_t *, uint16_t); static void qla2x00_process_completed_request(struct scsi_qla_host *, struct req_que *, uint32_t); static void qla2x00_status_entry(scsi_qla_host_t *, struct rsp_que *, void *); -static void qla2x00_status_cont_entry(scsi_qla_host_t *, sts_cont_entry_t *); +static void qla2x00_status_cont_entry(struct rsp_que *, sts_cont_entry_t *); static void qla2x00_error_entry(scsi_qla_host_t *, struct rsp_que *, sts_entry_t *); -static struct scsi_qla_host *qla2x00_get_rsp_host(struct rsp_que *); /** * qla2100_intr_handler() - Process interrupts for the ISP2100 and ISP2200. @@ -38,6 +37,7 @@ qla2100_intr_handler(int irq, void *dev_id) uint16_t hccr; uint16_t mb[4]; struct rsp_que *rsp; + unsigned long flags; rsp = (struct rsp_que *) dev_id; if (!rsp) { @@ -50,8 +50,8 @@ qla2100_intr_handler(int irq, void *dev_id) reg = &ha->iobase->isp; status = 0; - spin_lock(&ha->hardware_lock); - vha = qla2x00_get_rsp_host(rsp); + spin_lock_irqsave(&ha->hardware_lock, flags); + vha = pci_get_drvdata(ha->pdev); for (iter = 50; iter--; ) { hccr = RD_REG_WORD(®->hccr); if (hccr & HCCR_RISC_PAUSE) { @@ -102,7 +102,7 @@ qla2100_intr_handler(int irq, void *dev_id) RD_REG_WORD(®->hccr); } } - spin_unlock(&ha->hardware_lock); + spin_unlock_irqrestore(&ha->hardware_lock, flags); if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) && (status & MBX_INTERRUPT) && ha->flags.mbox_int) { @@ -134,6 +134,7 @@ qla2300_intr_handler(int irq, void *dev_id) uint16_t mb[4]; struct rsp_que *rsp; struct qla_hw_data *ha; + unsigned long flags; rsp = (struct rsp_que *) dev_id; if (!rsp) { @@ -146,8 +147,8 @@ qla2300_intr_handler(int irq, void *dev_id) reg = &ha->iobase->isp; status = 0; - spin_lock(&ha->hardware_lock); - vha = qla2x00_get_rsp_host(rsp); + spin_lock_irqsave(&ha->hardware_lock, flags); + vha = pci_get_drvdata(ha->pdev); for (iter = 50; iter--; ) { stat = RD_REG_DWORD(®->u.isp2300.host_status); if (stat & HSR_RISC_PAUSED) { @@ -217,7 +218,7 @@ qla2300_intr_handler(int irq, void *dev_id) WRT_REG_WORD(®->hccr, HCCR_CLR_RISC_INT); RD_REG_WORD_RELAXED(®->hccr); } - spin_unlock(&ha->hardware_lock); + spin_unlock_irqrestore(&ha->hardware_lock, flags); if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) && (status & MBX_INTERRUPT) && ha->flags.mbox_int) { @@ -685,7 +686,7 @@ skip_rio: vha->host_no)); if (IS_FWI2_CAPABLE(ha)) - qla24xx_process_response_queue(rsp); + qla24xx_process_response_queue(vha, rsp); else qla2x00_process_response_queue(rsp); break; @@ -766,7 +767,10 @@ qla2x00_adjust_sdev_qdepth_up(struct scsi_device *sdev, void *data) struct qla_hw_data *ha = vha->hw; struct req_que *req = NULL; - req = ha->req_q_map[vha->req_ques[0]]; + if (!ql2xqfulltracking) + return; + + req = vha->req; if (!req) return; if (req->max_q_depth <= sdev->queue_depth) @@ -808,6 +812,9 @@ qla2x00_ramp_up_queue_depth(scsi_qla_host_t *vha, struct req_que *req, fc_port_t *fcport; struct scsi_device *sdev; + if (!ql2xqfulltracking) + return; + sdev = sp->cmd->device; if (sdev->queue_depth >= req->max_q_depth) return; @@ -858,8 +865,8 @@ qla2x00_process_completed_request(struct scsi_qla_host *vha, qla2x00_ramp_up_queue_depth(vha, req, sp); qla2x00_sp_compl(ha, sp); } else { - DEBUG2(printk("scsi(%ld): Invalid ISP SCSI completion handle\n", - vha->host_no)); + DEBUG2(printk("scsi(%ld) Req:%d: Invalid ISP SCSI completion" + " handle(%d)\n", vha->host_no, req->id, index)); qla_printk(KERN_WARNING, ha, "Invalid ISP SCSI completion handle\n"); @@ -881,7 +888,7 @@ qla2x00_process_response_queue(struct rsp_que *rsp) uint16_t handle_cnt; uint16_t cnt; - vha = qla2x00_get_rsp_host(rsp); + vha = pci_get_drvdata(ha->pdev); if (!vha->flags.online) return; @@ -926,7 +933,7 @@ qla2x00_process_response_queue(struct rsp_que *rsp) } break; case STATUS_CONT_TYPE: - qla2x00_status_cont_entry(vha, (sts_cont_entry_t *)pkt); + qla2x00_status_cont_entry(rsp, (sts_cont_entry_t *)pkt); break; default: /* Type Not Supported. */ @@ -945,7 +952,8 @@ qla2x00_process_response_queue(struct rsp_que *rsp) } static inline void -qla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t sense_len) +qla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t sense_len, + struct rsp_que *rsp) { struct scsi_cmnd *cp = sp->cmd; @@ -962,7 +970,7 @@ qla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t sense_len) sp->request_sense_ptr += sense_len; sp->request_sense_length -= sense_len; if (sp->request_sense_length != 0) - sp->fcport->vha->status_srb = sp; + rsp->status_srb = sp; DEBUG5(printk("%s(): Check condition Sense data, scsi(%ld:%d:%d:%d) " "cmd=%p pid=%ld\n", __func__, sp->fcport->vha->host_no, @@ -992,7 +1000,9 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) uint32_t sense_len, rsp_info_len, resid_len, fw_resid_len; uint8_t *rsp_info, *sense_data; struct qla_hw_data *ha = vha->hw; - struct req_que *req = rsp->req; + uint32_t handle; + uint16_t que; + struct req_que *req; sts = (sts_entry_t *) pkt; sts24 = (struct sts_entry_24xx *) pkt; @@ -1003,18 +1013,20 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) comp_status = le16_to_cpu(sts->comp_status); scsi_status = le16_to_cpu(sts->scsi_status) & SS_MASK; } - + handle = (uint32_t) LSW(sts->handle); + que = MSW(sts->handle); + req = ha->req_q_map[que]; /* Fast path completion. */ if (comp_status == CS_COMPLETE && scsi_status == 0) { - qla2x00_process_completed_request(vha, req, sts->handle); + qla2x00_process_completed_request(vha, req, handle); return; } /* Validate handle. */ - if (sts->handle < MAX_OUTSTANDING_COMMANDS) { - sp = req->outstanding_cmds[sts->handle]; - req->outstanding_cmds[sts->handle] = NULL; + if (handle < MAX_OUTSTANDING_COMMANDS) { + sp = req->outstanding_cmds[handle]; + req->outstanding_cmds[handle] = NULL; } else sp = NULL; @@ -1030,7 +1042,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) cp = sp->cmd; if (cp == NULL) { DEBUG2(printk("scsi(%ld): Command already returned back to OS " - "pkt->handle=%d sp=%p.\n", vha->host_no, sts->handle, sp)); + "pkt->handle=%d sp=%p.\n", vha->host_no, handle, sp)); qla_printk(KERN_WARNING, ha, "Command is NULL: already returned to OS (sp=%p)\n", sp); @@ -1121,6 +1133,8 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) scsi_status)); /* Adjust queue depth for all luns on the port. */ + if (!ql2xqfulltracking) + break; fcport->last_queue_full = jiffies; starget_for_each_device(cp->device->sdev_target, fcport, qla2x00_adjust_sdev_qdepth_down); @@ -1133,7 +1147,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) if (!(scsi_status & SS_SENSE_LEN_VALID)) break; - qla2x00_handle_sense(sp, sense_data, sense_len); + qla2x00_handle_sense(sp, sense_data, sense_len, rsp); break; case CS_DATA_UNDERRUN: @@ -1179,6 +1193,8 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) * Adjust queue depth for all luns on the * port. */ + if (!ql2xqfulltracking) + break; fcport->last_queue_full = jiffies; starget_for_each_device( cp->device->sdev_target, fcport, @@ -1192,12 +1208,12 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) if (!(scsi_status & SS_SENSE_LEN_VALID)) break; - qla2x00_handle_sense(sp, sense_data, sense_len); + qla2x00_handle_sense(sp, sense_data, sense_len, rsp); } else { /* * If RISC reports underrun and target does not report * it then we must have a lost frame, so tell upper - * layer to retry it by reporting a bus busy. + * layer to retry it by reporting an error. */ if (!(scsi_status & SS_RESIDUAL_UNDER)) { DEBUG2(printk("scsi(%ld:%d:%d:%d) Dropped " @@ -1207,7 +1223,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) cp->device->id, cp->device->lun, resid, scsi_bufflen(cp))); - cp->result = DID_BUS_BUSY << 16; + cp->result = DID_ERROR << 16; break; } @@ -1334,7 +1350,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) } /* Place command on done queue. */ - if (vha->status_srb == NULL) + if (rsp->status_srb == NULL) qla2x00_sp_compl(ha, sp); } @@ -1346,11 +1362,11 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) * Extended sense data. */ static void -qla2x00_status_cont_entry(scsi_qla_host_t *vha, sts_cont_entry_t *pkt) +qla2x00_status_cont_entry(struct rsp_que *rsp, sts_cont_entry_t *pkt) { uint8_t sense_sz = 0; - struct qla_hw_data *ha = vha->hw; - srb_t *sp = vha->status_srb; + struct qla_hw_data *ha = rsp->hw; + srb_t *sp = rsp->status_srb; struct scsi_cmnd *cp; if (sp != NULL && sp->request_sense_length != 0) { @@ -1362,7 +1378,7 @@ qla2x00_status_cont_entry(scsi_qla_host_t *vha, sts_cont_entry_t *pkt) "cmd is NULL: already returned to OS (sp=%p)\n", sp); - vha->status_srb = NULL; + rsp->status_srb = NULL; return; } @@ -1383,7 +1399,7 @@ qla2x00_status_cont_entry(scsi_qla_host_t *vha, sts_cont_entry_t *pkt) /* Place command on done queue. */ if (sp->request_sense_length == 0) { - vha->status_srb = NULL; + rsp->status_srb = NULL; qla2x00_sp_compl(ha, sp); } } @@ -1399,7 +1415,9 @@ qla2x00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, sts_entry_t *pkt) { srb_t *sp; struct qla_hw_data *ha = vha->hw; - struct req_que *req = rsp->req; + uint32_t handle = LSW(pkt->handle); + uint16_t que = MSW(pkt->handle); + struct req_que *req = ha->req_q_map[que]; #if defined(QL_DEBUG_LEVEL_2) if (pkt->entry_status & RF_INV_E_ORDER) qla_printk(KERN_ERR, ha, "%s: Invalid Entry Order\n", __func__); @@ -1417,14 +1435,14 @@ qla2x00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, sts_entry_t *pkt) #endif /* Validate handle. */ - if (pkt->handle < MAX_OUTSTANDING_COMMANDS) - sp = req->outstanding_cmds[pkt->handle]; + if (handle < MAX_OUTSTANDING_COMMANDS) + sp = req->outstanding_cmds[handle]; else sp = NULL; if (sp) { /* Free outstanding command slot. */ - req->outstanding_cmds[pkt->handle] = NULL; + req->outstanding_cmds[handle] = NULL; /* Bad payload or header */ if (pkt->entry_status & @@ -1486,13 +1504,10 @@ qla24xx_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0) * qla24xx_process_response_queue() - Process response queue entries. * @ha: SCSI driver HA context */ -void -qla24xx_process_response_queue(struct rsp_que *rsp) +void qla24xx_process_response_queue(struct scsi_qla_host *vha, + struct rsp_que *rsp) { struct sts_entry_24xx *pkt; - struct scsi_qla_host *vha; - - vha = qla2x00_get_rsp_host(rsp); if (!vha->flags.online) return; @@ -1523,7 +1538,7 @@ qla24xx_process_response_queue(struct rsp_que *rsp) qla2x00_status_entry(vha, rsp, pkt); break; case STATUS_CONT_TYPE: - qla2x00_status_cont_entry(vha, (sts_cont_entry_t *)pkt); + qla2x00_status_cont_entry(rsp, (sts_cont_entry_t *)pkt); break; case VP_RPT_ID_IOCB_TYPE: qla24xx_report_id_acquisition(vha, @@ -1613,6 +1628,7 @@ qla24xx_intr_handler(int irq, void *dev_id) uint32_t hccr; uint16_t mb[4]; struct rsp_que *rsp; + unsigned long flags; rsp = (struct rsp_que *) dev_id; if (!rsp) { @@ -1625,8 +1641,8 @@ qla24xx_intr_handler(int irq, void *dev_id) reg = &ha->iobase->isp24; status = 0; - spin_lock(&ha->hardware_lock); - vha = qla2x00_get_rsp_host(rsp); + spin_lock_irqsave(&ha->hardware_lock, flags); + vha = pci_get_drvdata(ha->pdev); for (iter = 50; iter--; ) { stat = RD_REG_DWORD(®->host_status); if (stat & HSRX_RISC_PAUSED) { @@ -1664,7 +1680,7 @@ qla24xx_intr_handler(int irq, void *dev_id) break; case 0x13: case 0x14: - qla24xx_process_response_queue(rsp); + qla24xx_process_response_queue(vha, rsp); break; default: DEBUG2(printk("scsi(%ld): Unrecognized interrupt type " @@ -1675,7 +1691,7 @@ qla24xx_intr_handler(int irq, void *dev_id) WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT); RD_REG_DWORD_RELAXED(®->hccr); } - spin_unlock(&ha->hardware_lock); + spin_unlock_irqrestore(&ha->hardware_lock, flags); if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) && (status & MBX_INTERRUPT) && ha->flags.mbox_int) { @@ -1692,6 +1708,7 @@ qla24xx_msix_rsp_q(int irq, void *dev_id) struct qla_hw_data *ha; struct rsp_que *rsp; struct device_reg_24xx __iomem *reg; + struct scsi_qla_host *vha; rsp = (struct rsp_que *) dev_id; if (!rsp) { @@ -1704,7 +1721,8 @@ qla24xx_msix_rsp_q(int irq, void *dev_id) spin_lock_irq(&ha->hardware_lock); - qla24xx_process_response_queue(rsp); + vha = qla25xx_get_host(rsp); + qla24xx_process_response_queue(vha, rsp); WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT); spin_unlock_irq(&ha->hardware_lock); @@ -1717,7 +1735,6 @@ qla25xx_msix_rsp_q(int irq, void *dev_id) { struct qla_hw_data *ha; struct rsp_que *rsp; - struct device_reg_24xx __iomem *reg; rsp = (struct rsp_que *) dev_id; if (!rsp) { @@ -1726,13 +1743,8 @@ qla25xx_msix_rsp_q(int irq, void *dev_id) return IRQ_NONE; } ha = rsp->hw; - reg = &ha->iobase->isp24; - spin_lock_irq(&ha->hardware_lock); - - qla24xx_process_response_queue(rsp); - - spin_unlock_irq(&ha->hardware_lock); + queue_work_on((int) (rsp->id - 1), ha->wq, &rsp->q_work); return IRQ_HANDLED; } @@ -1760,7 +1772,7 @@ qla24xx_msix_default(int irq, void *dev_id) status = 0; spin_lock_irq(&ha->hardware_lock); - vha = qla2x00_get_rsp_host(rsp); + vha = pci_get_drvdata(ha->pdev); do { stat = RD_REG_DWORD(®->host_status); if (stat & HSRX_RISC_PAUSED) { @@ -1798,7 +1810,7 @@ qla24xx_msix_default(int irq, void *dev_id) break; case 0x13: case 0x14: - qla24xx_process_response_queue(rsp); + qla24xx_process_response_queue(vha, rsp); break; default: DEBUG2(printk("scsi(%ld): Unrecognized interrupt type " @@ -1822,31 +1834,14 @@ qla24xx_msix_default(int irq, void *dev_id) /* Interrupt handling helpers. */ struct qla_init_msix_entry { - uint16_t entry; - uint16_t index; const char *name; irq_handler_t handler; }; -static struct qla_init_msix_entry base_queue = { - .entry = 0, - .index = 0, - .name = "qla2xxx (default)", - .handler = qla24xx_msix_default, -}; - -static struct qla_init_msix_entry base_rsp_queue = { - .entry = 1, - .index = 1, - .name = "qla2xxx (rsp_q)", - .handler = qla24xx_msix_rsp_q, -}; - -static struct qla_init_msix_entry multi_rsp_queue = { - .entry = 1, - .index = 1, - .name = "qla2xxx (multi_q)", - .handler = qla25xx_msix_rsp_q, +static struct qla_init_msix_entry msix_entries[3] = { + { "qla2xxx (default)", qla24xx_msix_default }, + { "qla2xxx (rsp_q)", qla24xx_msix_rsp_q }, + { "qla2xxx (multiq)", qla25xx_msix_rsp_q }, }; static void @@ -1873,7 +1868,6 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp) int i, ret; struct msix_entry *entries; struct qla_msix_entry *qentry; - struct qla_init_msix_entry *msix_queue; entries = kzalloc(sizeof(struct msix_entry) * ha->msix_count, GFP_KERNEL); @@ -1900,7 +1894,7 @@ msix_failed: ha->msix_count, ret); goto msix_out; } - ha->max_queues = ha->msix_count - 1; + ha->max_rsp_queues = ha->msix_count - 1; } ha->msix_entries = kzalloc(sizeof(struct qla_msix_entry) * ha->msix_count, GFP_KERNEL); @@ -1918,45 +1912,27 @@ msix_failed: qentry->rsp = NULL; } - /* Enable MSI-X for AENs for queue 0 */ - qentry = &ha->msix_entries[0]; - ret = request_irq(qentry->vector, base_queue.handler, 0, - base_queue.name, rsp); - if (ret) { - qla_printk(KERN_WARNING, ha, + /* Enable MSI-X vectors for the base queue */ + for (i = 0; i < 2; i++) { + qentry = &ha->msix_entries[i]; + ret = request_irq(qentry->vector, msix_entries[i].handler, + 0, msix_entries[i].name, rsp); + if (ret) { + qla_printk(KERN_WARNING, ha, "MSI-X: Unable to register handler -- %x/%d.\n", qentry->vector, ret); - qla24xx_disable_msix(ha); - goto msix_out; + qla24xx_disable_msix(ha); + ha->mqenable = 0; + goto msix_out; + } + qentry->have_irq = 1; + qentry->rsp = rsp; + rsp->msix = qentry; } - qentry->have_irq = 1; - qentry->rsp = rsp; /* Enable MSI-X vector for response queue update for queue 0 */ - if (ha->max_queues > 1 && ha->mqiobase) { + if (ha->mqiobase && (ha->max_rsp_queues > 1 || ha->max_req_queues > 1)) ha->mqenable = 1; - msix_queue = &multi_rsp_queue; - qla_printk(KERN_INFO, ha, - "MQ enabled, Number of Queue Resources: %d \n", - ha->max_queues); - } else { - ha->mqenable = 0; - msix_queue = &base_rsp_queue; - } - - qentry = &ha->msix_entries[1]; - ret = request_irq(qentry->vector, msix_queue->handler, 0, - msix_queue->name, rsp); - if (ret) { - qla_printk(KERN_WARNING, ha, - "MSI-X: Unable to register handler -- %x/%d.\n", - qentry->vector, ret); - qla24xx_disable_msix(ha); - ha->mqenable = 0; - goto msix_out; - } - qentry->have_irq = 1; - qentry->rsp = rsp; msix_out: kfree(entries); @@ -2063,35 +2039,11 @@ qla2x00_free_irqs(scsi_qla_host_t *vha) } } -static struct scsi_qla_host * -qla2x00_get_rsp_host(struct rsp_que *rsp) -{ - srb_t *sp; - struct qla_hw_data *ha = rsp->hw; - struct scsi_qla_host *vha = NULL; - struct sts_entry_24xx *pkt; - struct req_que *req; - - if (rsp->id) { - pkt = (struct sts_entry_24xx *) rsp->ring_ptr; - req = rsp->req; - if (pkt && pkt->handle < MAX_OUTSTANDING_COMMANDS) { - sp = req->outstanding_cmds[pkt->handle]; - if (sp) - vha = sp->fcport->vha; - } - } - if (!vha) - /* handle it in base queue */ - vha = pci_get_drvdata(ha->pdev); - - return vha; -} int qla25xx_request_irq(struct rsp_que *rsp) { struct qla_hw_data *ha = rsp->hw; - struct qla_init_msix_entry *intr = &multi_rsp_queue; + struct qla_init_msix_entry *intr = &msix_entries[2]; struct qla_msix_entry *msix = rsp->msix; int ret; @@ -2106,3 +2058,30 @@ int qla25xx_request_irq(struct rsp_que *rsp) msix->rsp = rsp; return ret; } + +struct scsi_qla_host * +qla25xx_get_host(struct rsp_que *rsp) +{ + srb_t *sp; + struct qla_hw_data *ha = rsp->hw; + struct scsi_qla_host *vha = NULL; + struct sts_entry_24xx *pkt; + struct req_que *req; + uint16_t que; + uint32_t handle; + + pkt = (struct sts_entry_24xx *) rsp->ring_ptr; + que = MSW(pkt->handle); + handle = (uint32_t) LSW(pkt->handle); + req = ha->req_q_map[que]; + if (handle < MAX_OUTSTANDING_COMMANDS) { + sp = req->outstanding_cmds[handle]; + if (sp) + return sp->fcport->vha; + else + goto base_que; + } +base_que: + vha = pci_get_drvdata(ha->pdev); + return vha; +} diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index e67c1660bf46..fe69f3057671 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -408,7 +408,7 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr) * Context: * Kernel context. */ -void +int qla2x00_get_fw_version(scsi_qla_host_t *vha, uint16_t *major, uint16_t *minor, uint16_t *subminor, uint16_t *attributes, uint32_t *memory, uint8_t *mpi, uint32_t *mpi_caps, uint8_t *phy) @@ -427,6 +427,8 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha, uint16_t *major, uint16_t *minor, mcp->flags = 0; mcp->tov = MBX_TOV_SECONDS; rval = qla2x00_mailbox_command(vha, mcp); + if (rval != QLA_SUCCESS) + goto failed; /* Return mailbox data. */ *major = mcp->mb[1]; @@ -446,7 +448,7 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha, uint16_t *major, uint16_t *minor, phy[1] = mcp->mb[9] >> 8; phy[2] = mcp->mb[9] & 0xff; } - +failed: if (rval != QLA_SUCCESS) { /*EMPTY*/ DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__, @@ -455,6 +457,7 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha, uint16_t *major, uint16_t *minor, /*EMPTY*/ DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no)); } + return rval; } /* @@ -748,20 +751,20 @@ qla2x00_issue_iocb(scsi_qla_host_t *vha, void *buffer, dma_addr_t phys_addr, * Kernel context. */ int -qla2x00_abort_command(scsi_qla_host_t *vha, srb_t *sp, struct req_que *req) +qla2x00_abort_command(srb_t *sp) { unsigned long flags = 0; - fc_port_t *fcport; int rval; uint32_t handle = 0; mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; + fc_port_t *fcport = sp->fcport; + scsi_qla_host_t *vha = fcport->vha; struct qla_hw_data *ha = vha->hw; + struct req_que *req = vha->req; DEBUG11(printk("qla2x00_abort_command(%ld): entered.\n", vha->host_no)); - fcport = sp->fcport; - spin_lock_irqsave(&ha->hardware_lock, flags); for (handle = 1; handle < MAX_OUTSTANDING_COMMANDS; handle++) { if (req->outstanding_cmds[handle] == sp) @@ -800,7 +803,7 @@ qla2x00_abort_command(scsi_qla_host_t *vha, srb_t *sp, struct req_que *req) } int -qla2x00_abort_target(struct fc_port *fcport, unsigned int l) +qla2x00_abort_target(struct fc_port *fcport, unsigned int l, int tag) { int rval, rval2; mbx_cmd_t mc; @@ -813,8 +816,8 @@ qla2x00_abort_target(struct fc_port *fcport, unsigned int l) l = l; vha = fcport->vha; - req = vha->hw->req_q_map[0]; - rsp = vha->hw->rsp_q_map[0]; + req = vha->hw->req_q_map[tag]; + rsp = vha->hw->rsp_q_map[tag]; mcp->mb[0] = MBC_ABORT_TARGET; mcp->out_mb = MBX_9|MBX_2|MBX_1|MBX_0; if (HAS_EXTENDED_IDS(vha->hw)) { @@ -850,7 +853,7 @@ qla2x00_abort_target(struct fc_port *fcport, unsigned int l) } int -qla2x00_lun_reset(struct fc_port *fcport, unsigned int l) +qla2x00_lun_reset(struct fc_port *fcport, unsigned int l, int tag) { int rval, rval2; mbx_cmd_t mc; @@ -862,8 +865,8 @@ qla2x00_lun_reset(struct fc_port *fcport, unsigned int l) DEBUG11(printk("%s(%ld): entered.\n", __func__, fcport->vha->host_no)); vha = fcport->vha; - req = vha->hw->req_q_map[0]; - rsp = vha->hw->rsp_q_map[0]; + req = vha->hw->req_q_map[tag]; + rsp = vha->hw->rsp_q_map[tag]; mcp->mb[0] = MBC_LUN_RESET; mcp->out_mb = MBX_9|MBX_3|MBX_2|MBX_1|MBX_0; if (HAS_EXTENDED_IDS(vha->hw)) @@ -931,6 +934,8 @@ qla2x00_get_adapter_id(scsi_qla_host_t *vha, uint16_t *id, uint8_t *al_pa, mcp->mb[9] = vha->vp_idx; mcp->out_mb = MBX_9|MBX_0; mcp->in_mb = MBX_9|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; + if (IS_QLA81XX(vha->hw)) + mcp->in_mb |= MBX_13|MBX_12|MBX_11|MBX_10; mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(vha, mcp); @@ -952,9 +957,19 @@ qla2x00_get_adapter_id(scsi_qla_host_t *vha, uint16_t *id, uint8_t *al_pa, DEBUG2_3_11(printk("qla2x00_get_adapter_id(%ld): failed=%x.\n", vha->host_no, rval)); } else { - /*EMPTY*/ DEBUG11(printk("qla2x00_get_adapter_id(%ld): done.\n", vha->host_no)); + + if (IS_QLA81XX(vha->hw)) { + vha->fcoe_vlan_id = mcp->mb[9] & 0xfff; + vha->fcoe_fcf_idx = mcp->mb[10]; + vha->fcoe_vn_port_mac[5] = mcp->mb[11] >> 8; + vha->fcoe_vn_port_mac[4] = mcp->mb[11] & 0xff; + vha->fcoe_vn_port_mac[3] = mcp->mb[12] >> 8; + vha->fcoe_vn_port_mac[2] = mcp->mb[12] & 0xff; + vha->fcoe_vn_port_mac[1] = mcp->mb[13] >> 8; + vha->fcoe_vn_port_mac[0] = mcp->mb[13] & 0xff; + } } return rval; @@ -1252,15 +1267,22 @@ qla2x00_get_firmware_state(scsi_qla_host_t *vha, uint16_t *states) mcp->mb[0] = MBC_GET_FIRMWARE_STATE; mcp->out_mb = MBX_0; - mcp->in_mb = MBX_3|MBX_2|MBX_1|MBX_0; + if (IS_FWI2_CAPABLE(vha->hw)) + mcp->in_mb = MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; + else + mcp->in_mb = MBX_1|MBX_0; mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(vha, mcp); /* Return firmware states. */ states[0] = mcp->mb[1]; - states[1] = mcp->mb[2]; - states[2] = mcp->mb[3]; + if (IS_FWI2_CAPABLE(vha->hw)) { + states[1] = mcp->mb[2]; + states[2] = mcp->mb[3]; + states[3] = mcp->mb[4]; + states[4] = mcp->mb[5]; + } if (rval != QLA_SUCCESS) { /*EMPTY*/ @@ -1480,9 +1502,17 @@ qla24xx_login_fabric(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain, dma_addr_t lg_dma; uint32_t iop[2]; struct qla_hw_data *ha = vha->hw; + struct req_que *req; + struct rsp_que *rsp; DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no)); + if (ql2xmultique_tag) + req = ha->req_q_map[0]; + else + req = vha->req; + rsp = req->rsp; + lg = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &lg_dma); if (lg == NULL) { DEBUG2_3(printk("%s(%ld): failed to allocate Login IOCB.\n", @@ -1493,6 +1523,7 @@ qla24xx_login_fabric(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain, lg->entry_type = LOGINOUT_PORT_IOCB_TYPE; lg->entry_count = 1; + lg->handle = MAKE_HANDLE(req->id, lg->handle); lg->nport_handle = cpu_to_le16(loop_id); lg->control_flags = __constant_cpu_to_le16(LCF_COMMAND_PLOGI); if (opt & BIT_0) @@ -1741,6 +1772,8 @@ qla24xx_fabric_logout(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain, struct logio_entry_24xx *lg; dma_addr_t lg_dma; struct qla_hw_data *ha = vha->hw; + struct req_que *req; + struct rsp_que *rsp; DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no)); @@ -1752,8 +1785,14 @@ qla24xx_fabric_logout(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain, } memset(lg, 0, sizeof(struct logio_entry_24xx)); + if (ql2xmaxqueues > 1) + req = ha->req_q_map[0]; + else + req = vha->req; + rsp = req->rsp; lg->entry_type = LOGINOUT_PORT_IOCB_TYPE; lg->entry_count = 1; + lg->handle = MAKE_HANDLE(req->id, lg->handle); lg->nport_handle = cpu_to_le16(loop_id); lg->control_flags = __constant_cpu_to_le16(LCF_COMMAND_LOGO|LCF_IMPL_LOGO); @@ -1864,9 +1903,6 @@ qla2x00_full_login_lip(scsi_qla_host_t *vha) mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - if (IS_QLA81XX(vha->hw)) - return QLA_SUCCESS; - DEBUG11(printk("qla2x00_full_login_lip(%ld): entered.\n", vha->host_no)); @@ -2195,21 +2231,21 @@ qla24xx_get_isp_stats(scsi_qla_host_t *vha, struct link_statistics *stats, } int -qla24xx_abort_command(scsi_qla_host_t *vha, srb_t *sp, struct req_que *req) +qla24xx_abort_command(srb_t *sp) { int rval; - fc_port_t *fcport; unsigned long flags = 0; struct abort_entry_24xx *abt; dma_addr_t abt_dma; uint32_t handle; + fc_port_t *fcport = sp->fcport; + struct scsi_qla_host *vha = fcport->vha; struct qla_hw_data *ha = vha->hw; + struct req_que *req = vha->req; DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no)); - fcport = sp->fcport; - spin_lock_irqsave(&ha->hardware_lock, flags); for (handle = 1; handle < MAX_OUTSTANDING_COMMANDS; handle++) { if (req->outstanding_cmds[handle] == sp) @@ -2231,6 +2267,7 @@ qla24xx_abort_command(scsi_qla_host_t *vha, srb_t *sp, struct req_que *req) abt->entry_type = ABORT_IOCB_TYPE; abt->entry_count = 1; + abt->handle = MAKE_HANDLE(req->id, abt->handle); abt->nport_handle = cpu_to_le16(fcport->loop_id); abt->handle_to_abort = handle; abt->port_id[0] = fcport->d_id.b.al_pa; @@ -2272,7 +2309,7 @@ struct tsk_mgmt_cmd { static int __qla24xx_issue_tmf(char *name, uint32_t type, struct fc_port *fcport, - unsigned int l) + unsigned int l, int tag) { int rval, rval2; struct tsk_mgmt_cmd *tsk; @@ -2286,8 +2323,11 @@ __qla24xx_issue_tmf(char *name, uint32_t type, struct fc_port *fcport, vha = fcport->vha; ha = vha->hw; - req = ha->req_q_map[0]; - rsp = ha->rsp_q_map[0]; + req = vha->req; + if (ql2xmultique_tag) + rsp = ha->rsp_q_map[tag + 1]; + else + rsp = req->rsp; tsk = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &tsk_dma); if (tsk == NULL) { DEBUG2_3(printk("%s(%ld): failed to allocate Task Management " @@ -2298,6 +2338,7 @@ __qla24xx_issue_tmf(char *name, uint32_t type, struct fc_port *fcport, tsk->p.tsk.entry_type = TSK_MGMT_IOCB_TYPE; tsk->p.tsk.entry_count = 1; + tsk->p.tsk.handle = MAKE_HANDLE(req->id, tsk->p.tsk.handle); tsk->p.tsk.nport_handle = cpu_to_le16(fcport->loop_id); tsk->p.tsk.timeout = cpu_to_le16(ha->r_a_tov / 10 * 2); tsk->p.tsk.control_flags = cpu_to_le32(type); @@ -2344,15 +2385,15 @@ __qla24xx_issue_tmf(char *name, uint32_t type, struct fc_port *fcport, } int -qla24xx_abort_target(struct fc_port *fcport, unsigned int l) +qla24xx_abort_target(struct fc_port *fcport, unsigned int l, int tag) { - return __qla24xx_issue_tmf("Target", TCF_TARGET_RESET, fcport, l); + return __qla24xx_issue_tmf("Target", TCF_TARGET_RESET, fcport, l, tag); } int -qla24xx_lun_reset(struct fc_port *fcport, unsigned int l) +qla24xx_lun_reset(struct fc_port *fcport, unsigned int l, int tag) { - return __qla24xx_issue_tmf("Lun", TCF_LUN_RESET, fcport, l); + return __qla24xx_issue_tmf("Lun", TCF_LUN_RESET, fcport, l, tag); } int @@ -2446,6 +2487,8 @@ qla2x00_stop_firmware(scsi_qla_host_t *vha) if (rval != QLA_SUCCESS) { DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__, vha->host_no, rval)); + if (mcp->mb[0] == MBS_INVALID_COMMAND) + rval = QLA_INVALID_COMMAND; } else { DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no)); } @@ -2659,10 +2702,13 @@ qla2x00_set_idma_speed(scsi_qla_host_t *vha, uint16_t loop_id, mcp->mb[0] = MBC_PORT_PARAMS; mcp->mb[1] = loop_id; mcp->mb[2] = BIT_0; - mcp->mb[3] = port_speed & (BIT_2|BIT_1|BIT_0); - mcp->mb[4] = mcp->mb[5] = 0; - mcp->out_mb = MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; - mcp->in_mb = MBX_5|MBX_4|MBX_3|MBX_1|MBX_0; + if (IS_QLA81XX(vha->hw)) + mcp->mb[3] = port_speed & (BIT_5|BIT_4|BIT_3|BIT_2|BIT_1|BIT_0); + else + mcp->mb[3] = port_speed & (BIT_2|BIT_1|BIT_0); + mcp->mb[9] = vha->vp_idx; + mcp->out_mb = MBX_9|MBX_3|MBX_2|MBX_1|MBX_0; + mcp->in_mb = MBX_3|MBX_1|MBX_0; mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(vha, mcp); @@ -2672,8 +2718,6 @@ qla2x00_set_idma_speed(scsi_qla_host_t *vha, uint16_t loop_id, mb[0] = mcp->mb[0]; mb[1] = mcp->mb[1]; mb[3] = mcp->mb[3]; - mb[4] = mcp->mb[4]; - mb[5] = mcp->mb[5]; } if (rval != QLA_SUCCESS) { @@ -2717,8 +2761,11 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha, if (vp_idx == 0) return; - if (MSB(stat) == 1) + if (MSB(stat) == 1) { + DEBUG2(printk("scsi(%ld): Could not acquire ID for " + "VP[%d].\n", vha->host_no, vp_idx)); return; + } list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) if (vp_idx == vp->vp_idx) @@ -3141,6 +3188,8 @@ qla25xx_init_req_que(struct scsi_qla_host *vha, struct req_que *req) WRT_REG_DWORD(®->req_q_in, 0); WRT_REG_DWORD(®->req_q_out, 0); } + req->req_q_in = ®->req_q_in; + req->req_q_out = ®->req_q_out; spin_unlock_irqrestore(&ha->hardware_lock, flags); rval = qla2x00_mailbox_command(vha, mcp); @@ -3167,7 +3216,6 @@ qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp) mcp->mb[6] = MSW(MSD(rsp->dma)); mcp->mb[7] = LSW(MSD(rsp->dma)); mcp->mb[5] = rsp->length; - mcp->mb[11] = rsp->vp_idx; mcp->mb[14] = rsp->msix->entry; mcp->mb[13] = rsp->rid; @@ -3179,7 +3227,7 @@ qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp) mcp->mb[8] = 0; /* que out ptr index */ mcp->mb[9] = 0; - mcp->out_mb = MBX_14|MBX_13|MBX_12|MBX_11|MBX_10|MBX_9|MBX_8|MBX_7 + mcp->out_mb = MBX_14|MBX_13|MBX_9|MBX_8|MBX_7 |MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; mcp->in_mb = MBX_0; mcp->flags = MBX_DMA_OUT; @@ -3384,7 +3432,7 @@ qla2x00_read_edc(scsi_qla_host_t *vha, uint16_t dev, uint16_t adr, DEBUG2_3_11(printk("%s(%ld): failed=%x (%x).\n", __func__, vha->host_no, rval, mcp->mb[0])); } else { - DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); + DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no)); } return rval; @@ -3428,3 +3476,141 @@ qla2x00_write_edc(scsi_qla_host_t *vha, uint16_t dev, uint16_t adr, return rval; } + +int +qla2x00_get_xgmac_stats(scsi_qla_host_t *vha, dma_addr_t stats_dma, + uint16_t size_in_bytes, uint16_t *actual_size) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + if (!IS_QLA81XX(vha->hw)) + return QLA_FUNCTION_FAILED; + + DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no)); + + mcp->mb[0] = MBC_GET_XGMAC_STATS; + mcp->mb[2] = MSW(stats_dma); + mcp->mb[3] = LSW(stats_dma); + mcp->mb[6] = MSW(MSD(stats_dma)); + mcp->mb[7] = LSW(MSD(stats_dma)); + mcp->mb[8] = size_in_bytes >> 2; + mcp->out_mb = MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_0; + mcp->in_mb = MBX_2|MBX_1|MBX_0; + mcp->tov = MBX_TOV_SECONDS; + mcp->flags = 0; + rval = qla2x00_mailbox_command(vha, mcp); + + if (rval != QLA_SUCCESS) { + DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=0x%x " + "mb[1]=0x%x mb[2]=0x%x.\n", __func__, vha->host_no, rval, + mcp->mb[0], mcp->mb[1], mcp->mb[2])); + } else { + DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no)); + + *actual_size = mcp->mb[2] << 2; + } + + return rval; +} + +int +qla2x00_get_dcbx_params(scsi_qla_host_t *vha, dma_addr_t tlv_dma, + uint16_t size) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + if (!IS_QLA81XX(vha->hw)) + return QLA_FUNCTION_FAILED; + + DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no)); + + mcp->mb[0] = MBC_GET_DCBX_PARAMS; + mcp->mb[1] = 0; + mcp->mb[2] = MSW(tlv_dma); + mcp->mb[3] = LSW(tlv_dma); + mcp->mb[6] = MSW(MSD(tlv_dma)); + mcp->mb[7] = LSW(MSD(tlv_dma)); + mcp->mb[8] = size; + mcp->out_mb = MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; + mcp->in_mb = MBX_2|MBX_1|MBX_0; + mcp->tov = MBX_TOV_SECONDS; + mcp->flags = 0; + rval = qla2x00_mailbox_command(vha, mcp); + + if (rval != QLA_SUCCESS) { + DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=0x%x " + "mb[1]=0x%x mb[2]=0x%x.\n", __func__, vha->host_no, rval, + mcp->mb[0], mcp->mb[1], mcp->mb[2])); + } else { + DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no)); + } + + return rval; +} + +int +qla2x00_read_ram_word(scsi_qla_host_t *vha, uint32_t risc_addr, uint32_t *data) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + if (!IS_FWI2_CAPABLE(vha->hw)) + return QLA_FUNCTION_FAILED; + + DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no)); + + mcp->mb[0] = MBC_READ_RAM_EXTENDED; + mcp->mb[1] = LSW(risc_addr); + mcp->mb[8] = MSW(risc_addr); + mcp->out_mb = MBX_8|MBX_1|MBX_0; + mcp->in_mb = MBX_3|MBX_2|MBX_0; + mcp->tov = 30; + mcp->flags = 0; + rval = qla2x00_mailbox_command(vha, mcp); + if (rval != QLA_SUCCESS) { + DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x.\n", __func__, + vha->host_no, rval, mcp->mb[0])); + } else { + DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no)); + *data = mcp->mb[3] << 16 | mcp->mb[2]; + } + + return rval; +} + +int +qla2x00_write_ram_word(scsi_qla_host_t *vha, uint32_t risc_addr, uint32_t data) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + if (!IS_FWI2_CAPABLE(vha->hw)) + return QLA_FUNCTION_FAILED; + + DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no)); + + mcp->mb[0] = MBC_WRITE_RAM_WORD_EXTENDED; + mcp->mb[1] = LSW(risc_addr); + mcp->mb[2] = LSW(data); + mcp->mb[3] = MSW(data); + mcp->mb[8] = MSW(risc_addr); + mcp->out_mb = MBX_8|MBX_3|MBX_2|MBX_1|MBX_0; + mcp->in_mb = MBX_0; + mcp->tov = 30; + mcp->flags = 0; + rval = qla2x00_mailbox_command(vha, mcp); + if (rval != QLA_SUCCESS) { + DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x.\n", __func__, + vha->host_no, rval, mcp->mb[0])); + } else { + DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no)); + } + + return rval; +} diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c index 51716c7e3008..650bcef08f2a 100644 --- a/drivers/scsi/qla2xxx/qla_mid.c +++ b/drivers/scsi/qla2xxx/qla_mid.c @@ -398,9 +398,8 @@ qla24xx_create_vhost(struct fc_vport *fc_vport) qla2x00_start_timer(vha, qla2x00_timer, WATCH_INTERVAL); - memset(vha->req_ques, 0, sizeof(vha->req_ques)); - vha->req_ques[0] = ha->req_q_map[0]->id; - host->can_queue = ha->req_q_map[0]->length + 128; + vha->req = base_vha->req; + host->can_queue = base_vha->req->length + 128; host->this_id = 255; host->cmd_per_lun = 3; host->max_cmd_len = MAX_CMDSZ; @@ -515,76 +514,53 @@ int qla25xx_update_req_que(struct scsi_qla_host *vha, uint8_t que, uint8_t qos) /* Delete all queues for a given vhost */ int -qla25xx_delete_queues(struct scsi_qla_host *vha, uint8_t que_no) +qla25xx_delete_queues(struct scsi_qla_host *vha) { int cnt, ret = 0; struct req_que *req = NULL; struct rsp_que *rsp = NULL; struct qla_hw_data *ha = vha->hw; - if (que_no) { - /* Delete request queue */ - req = ha->req_q_map[que_no]; + /* Delete request queues */ + for (cnt = 1; cnt < ha->max_req_queues; cnt++) { + req = ha->req_q_map[cnt]; if (req) { - rsp = req->rsp; ret = qla25xx_delete_req_que(vha, req); if (ret != QLA_SUCCESS) { qla_printk(KERN_WARNING, ha, - "Couldn't delete req que %d\n", req->id); + "Couldn't delete req que %d\n", + req->id); + return ret; + } + } + } + + /* Delete response queues */ + for (cnt = 1; cnt < ha->max_rsp_queues; cnt++) { + rsp = ha->rsp_q_map[cnt]; + if (rsp) { + ret = qla25xx_delete_rsp_que(vha, rsp); + if (ret != QLA_SUCCESS) { + qla_printk(KERN_WARNING, ha, + "Couldn't delete rsp que %d\n", + rsp->id); return ret; } - /* Delete associated response queue */ - if (rsp) { - ret = qla25xx_delete_rsp_que(vha, rsp); - if (ret != QLA_SUCCESS) { - qla_printk(KERN_WARNING, ha, - "Couldn't delete rsp que %d\n", - rsp->id); - return ret; - } - } - } - } else { /* delete all queues of this host */ - for (cnt = 0; cnt < QLA_MAX_HOST_QUES; cnt++) { - /* Delete request queues */ - req = ha->req_q_map[vha->req_ques[cnt]]; - if (req && req->id) { - rsp = req->rsp; - ret = qla25xx_delete_req_que(vha, req); - if (ret != QLA_SUCCESS) { - qla_printk(KERN_WARNING, ha, - "Couldn't delete req que %d\n", - vha->req_ques[cnt]); - return ret; - } - vha->req_ques[cnt] = ha->req_q_map[0]->id; - /* Delete associated response queue */ - if (rsp && rsp->id) { - ret = qla25xx_delete_rsp_que(vha, rsp); - if (ret != QLA_SUCCESS) { - qla_printk(KERN_WARNING, ha, - "Couldn't delete rsp que %d\n", - rsp->id); - return ret; - } - } - } } } - qla_printk(KERN_INFO, ha, "Queues deleted for vport:%d\n", - vha->vp_idx); return ret; } int qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options, - uint8_t vp_idx, uint16_t rid, uint8_t rsp_que, uint8_t qos) + uint8_t vp_idx, uint16_t rid, int rsp_que, uint8_t qos) { int ret = 0; struct req_que *req = NULL; struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); uint16_t que_id = 0; device_reg_t __iomem *reg; + uint32_t cnt; req = kzalloc(sizeof(struct req_que), GFP_KERNEL); if (req == NULL) { @@ -604,8 +580,8 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options, } mutex_lock(&ha->vport_lock); - que_id = find_first_zero_bit(ha->req_qid_map, ha->max_queues); - if (que_id >= ha->max_queues) { + que_id = find_first_zero_bit(ha->req_qid_map, ha->max_req_queues); + if (que_id >= ha->max_req_queues) { mutex_unlock(&ha->vport_lock); qla_printk(KERN_INFO, ha, "No resources to create " "additional request queue\n"); @@ -617,10 +593,10 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options, req->vp_idx = vp_idx; req->qos = qos; - if (ha->rsp_q_map[rsp_que]) { + if (rsp_que < 0) + req->rsp = NULL; + else req->rsp = ha->rsp_q_map[rsp_que]; - req->rsp->req = req; - } /* Use alternate PCI bus number */ if (MSB(req->rid)) options |= BIT_4; @@ -628,13 +604,16 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options, if (LSB(req->rid)) options |= BIT_5; req->options = options; + + for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) + req->outstanding_cmds[cnt] = NULL; + req->current_outstanding_cmd = 1; + req->ring_ptr = req->ring; req->ring_index = 0; req->cnt = req->length; req->id = que_id; reg = ISP_QUE_REG(ha, que_id); - req->req_q_in = ®->isp25mq.req_q_in; - req->req_q_out = ®->isp25mq.req_q_out; req->max_q_depth = ha->req_q_map[0]->max_q_depth; mutex_unlock(&ha->vport_lock); @@ -654,10 +633,19 @@ que_failed: return 0; } +static void qla_do_work(struct work_struct *work) +{ + struct rsp_que *rsp = container_of(work, struct rsp_que, q_work); + struct scsi_qla_host *vha; + + vha = qla25xx_get_host(rsp); + qla24xx_process_response_queue(vha, rsp); +} + /* create response queue */ int qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options, - uint8_t vp_idx, uint16_t rid) + uint8_t vp_idx, uint16_t rid, int req) { int ret = 0; struct rsp_que *rsp = NULL; @@ -672,7 +660,7 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options, goto que_failed; } - rsp->length = RESPONSE_ENTRY_CNT_2300; + rsp->length = RESPONSE_ENTRY_CNT_MQ; rsp->ring = dma_alloc_coherent(&ha->pdev->dev, (rsp->length + 1) * sizeof(response_t), &rsp->dma, GFP_KERNEL); @@ -683,8 +671,8 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options, } mutex_lock(&ha->vport_lock); - que_id = find_first_zero_bit(ha->rsp_qid_map, ha->max_queues); - if (que_id >= ha->max_queues) { + que_id = find_first_zero_bit(ha->rsp_qid_map, ha->max_rsp_queues); + if (que_id >= ha->max_rsp_queues) { mutex_unlock(&ha->vport_lock); qla_printk(KERN_INFO, ha, "No resources to create " "additional response queue\n"); @@ -708,8 +696,6 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options, if (LSB(rsp->rid)) options |= BIT_5; rsp->options = options; - rsp->ring_ptr = rsp->ring; - rsp->ring_index = 0; rsp->id = que_id; reg = ISP_QUE_REG(ha, que_id); rsp->rsp_q_in = ®->isp25mq.rsp_q_in; @@ -728,9 +714,14 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options, mutex_unlock(&ha->vport_lock); goto que_failed; } + if (req >= 0) + rsp->req = ha->req_q_map[req]; + else + rsp->req = NULL; qla2x00_init_response_q_entries(rsp); - + if (rsp->hw->wq) + INIT_WORK(&rsp->q_work, qla_do_work); return rsp->id; que_failed: @@ -744,14 +735,16 @@ qla25xx_create_queues(struct scsi_qla_host *vha, uint8_t qos) uint16_t options = 0; uint8_t ret = 0; struct qla_hw_data *ha = vha->hw; + struct rsp_que *rsp; options |= BIT_1; - ret = qla25xx_create_rsp_que(ha, options, vha->vp_idx, 0); + ret = qla25xx_create_rsp_que(ha, options, vha->vp_idx, 0, -1); if (!ret) { qla_printk(KERN_WARNING, ha, "Response Que create failed\n"); return ret; } else qla_printk(KERN_INFO, ha, "Response Que:%d created.\n", ret); + rsp = ha->rsp_q_map[ret]; options = 0; if (qos & BIT_7) @@ -759,10 +752,11 @@ qla25xx_create_queues(struct scsi_qla_host *vha, uint8_t qos) ret = qla25xx_create_req_que(ha, options, vha->vp_idx, 0, ret, qos & ~BIT_7); if (ret) { - vha->req_ques[0] = ret; + vha->req = ha->req_q_map[ret]; qla_printk(KERN_INFO, ha, "Request Que:%d created.\n", ret); } else qla_printk(KERN_WARNING, ha, "Request Que create failed\n"); + rsp->req = ha->req_q_map[ret]; return ret; } diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index e4fdcdad80d0..f0396e79b6fa 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -77,6 +77,14 @@ module_param(ql2xmaxqdepth, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(ql2xmaxqdepth, "Maximum queue depth to report for target devices."); +int ql2xqfulltracking = 1; +module_param(ql2xqfulltracking, int, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(ql2xqfulltracking, + "Controls whether the driver tracks queue full status " + "returns and dynamically adjusts a scsi device's queue " + "depth. Default is 1, perform tracking. Set to 0 to " + "disable dynamic tracking and adjustment of queue depth."); + int ql2xqfullrampup = 120; module_param(ql2xqfullrampup, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(ql2xqfullrampup, @@ -96,6 +104,23 @@ MODULE_PARM_DESC(ql2xmaxqueues, "Enables MQ settings " "Default is 1 for single queue. Set it to number \ of queues in MQ mode."); + +int ql2xmultique_tag; +module_param(ql2xmultique_tag, int, S_IRUGO|S_IRUSR); +MODULE_PARM_DESC(ql2xmultique_tag, + "Enables CPU affinity settings for the driver " + "Default is 0 for no affinity of request and response IO. " + "Set it to 1 to turn on the cpu affinity."); + +int ql2xfwloadbin; +module_param(ql2xfwloadbin, int, S_IRUGO|S_IRUSR); +MODULE_PARM_DESC(ql2xfwloadbin, + "Option to specify location from which to load ISP firmware:\n" + " 2 -- load firmware via the request_firmware() (hotplug)\n" + " interface.\n" + " 1 -- load firmware from flash.\n" + " 0 -- use default semantics.\n"); + /* * SCSI host template entry points */ @@ -187,7 +212,7 @@ static void qla2x00_sp_free_dma(srb_t *); /* -------------------------------------------------------------------------- */ static int qla2x00_alloc_queues(struct qla_hw_data *ha) { - ha->req_q_map = kzalloc(sizeof(struct req_que *) * ha->max_queues, + ha->req_q_map = kzalloc(sizeof(struct req_que *) * ha->max_req_queues, GFP_KERNEL); if (!ha->req_q_map) { qla_printk(KERN_WARNING, ha, @@ -195,7 +220,7 @@ static int qla2x00_alloc_queues(struct qla_hw_data *ha) goto fail_req_map; } - ha->rsp_q_map = kzalloc(sizeof(struct rsp_que *) * ha->max_queues, + ha->rsp_q_map = kzalloc(sizeof(struct rsp_que *) * ha->max_rsp_queues, GFP_KERNEL); if (!ha->rsp_q_map) { qla_printk(KERN_WARNING, ha, @@ -213,16 +238,8 @@ fail_req_map: return -ENOMEM; } -static void qla2x00_free_que(struct qla_hw_data *ha, struct req_que *req, - struct rsp_que *rsp) +static void qla2x00_free_req_que(struct qla_hw_data *ha, struct req_que *req) { - if (rsp && rsp->ring) - dma_free_coherent(&ha->pdev->dev, - (rsp->length + 1) * sizeof(response_t), - rsp->ring, rsp->dma); - - kfree(rsp); - rsp = NULL; if (req && req->ring) dma_free_coherent(&ha->pdev->dev, (req->length + 1) * sizeof(request_t), @@ -232,22 +249,77 @@ static void qla2x00_free_que(struct qla_hw_data *ha, struct req_que *req, req = NULL; } +static void qla2x00_free_rsp_que(struct qla_hw_data *ha, struct rsp_que *rsp) +{ + if (rsp && rsp->ring) + dma_free_coherent(&ha->pdev->dev, + (rsp->length + 1) * sizeof(response_t), + rsp->ring, rsp->dma); + + kfree(rsp); + rsp = NULL; +} + static void qla2x00_free_queues(struct qla_hw_data *ha) { struct req_que *req; struct rsp_que *rsp; int cnt; - for (cnt = 0; cnt < ha->max_queues; cnt++) { - rsp = ha->rsp_q_map[cnt]; + for (cnt = 0; cnt < ha->max_req_queues; cnt++) { req = ha->req_q_map[cnt]; - qla2x00_free_que(ha, req, rsp); + qla2x00_free_req_que(ha, req); + } + kfree(ha->req_q_map); + ha->req_q_map = NULL; + + for (cnt = 0; cnt < ha->max_rsp_queues; cnt++) { + rsp = ha->rsp_q_map[cnt]; + qla2x00_free_rsp_que(ha, rsp); } kfree(ha->rsp_q_map); ha->rsp_q_map = NULL; +} - kfree(ha->req_q_map); - ha->req_q_map = NULL; +static int qla25xx_setup_mode(struct scsi_qla_host *vha) +{ + uint16_t options = 0; + int ques, req, ret; + struct qla_hw_data *ha = vha->hw; + + if (ql2xmultique_tag) { + /* CPU affinity mode */ + ha->wq = create_workqueue("qla2xxx_wq"); + /* create a request queue for IO */ + options |= BIT_7; + req = qla25xx_create_req_que(ha, options, 0, 0, -1, + QLA_DEFAULT_QUE_QOS); + if (!req) { + qla_printk(KERN_WARNING, ha, + "Can't create request queue\n"); + goto fail; + } + vha->req = ha->req_q_map[req]; + options |= BIT_1; + for (ques = 1; ques < ha->max_rsp_queues; ques++) { + ret = qla25xx_create_rsp_que(ha, options, 0, 0, req); + if (!ret) { + qla_printk(KERN_WARNING, ha, + "Response Queue create failed\n"); + goto fail2; + } + } + DEBUG2(qla_printk(KERN_INFO, ha, + "CPU affinity mode enabled, no. of response" + " queues:%d, no. of request queues:%d\n", + ha->max_rsp_queues, ha->max_req_queues)); + } + return 0; +fail2: + qla25xx_delete_queues(vha); +fail: + ha->mqenable = 0; + return 1; } static char * @@ -387,7 +459,6 @@ qla2x00_get_new_sp(scsi_qla_host_t *vha, fc_port_t *fcport, sp->fcport = fcport; sp->cmd = cmd; - sp->que = ha->req_q_map[0]; sp->flags = 0; CMD_SP(cmd) = (void *)sp; cmd->scsi_done = done; @@ -612,7 +683,7 @@ qla2x00_wait_for_loop_ready(scsi_qla_host_t *vha) void qla2x00_abort_fcport_cmds(fc_port_t *fcport) { - int cnt, que, id; + int cnt; unsigned long flags; srb_t *sp; scsi_qla_host_t *vha = fcport->vha; @@ -620,32 +691,27 @@ qla2x00_abort_fcport_cmds(fc_port_t *fcport) struct req_que *req; spin_lock_irqsave(&ha->hardware_lock, flags); - for (que = 0; que < QLA_MAX_HOST_QUES; que++) { - id = vha->req_ques[que]; - req = ha->req_q_map[id]; - if (!req) + req = vha->req; + for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { + sp = req->outstanding_cmds[cnt]; + if (!sp) + continue; + if (sp->fcport != fcport) continue; - for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { - sp = req->outstanding_cmds[cnt]; - if (!sp) - continue; - if (sp->fcport != fcport) - continue; - spin_unlock_irqrestore(&ha->hardware_lock, flags); - if (ha->isp_ops->abort_command(vha, sp, req)) { + spin_unlock_irqrestore(&ha->hardware_lock, flags); + if (ha->isp_ops->abort_command(sp)) { + DEBUG2(qla_printk(KERN_WARNING, ha, + "Abort failed -- %lx\n", + sp->cmd->serial_number)); + } else { + if (qla2x00_eh_wait_on_command(sp->cmd) != + QLA_SUCCESS) DEBUG2(qla_printk(KERN_WARNING, ha, - "Abort failed -- %lx\n", + "Abort failed while waiting -- %lx\n", sp->cmd->serial_number)); - } else { - if (qla2x00_eh_wait_on_command(sp->cmd) != - QLA_SUCCESS) - DEBUG2(qla_printk(KERN_WARNING, ha, - "Abort failed while waiting -- %lx\n", - sp->cmd->serial_number)); - } - spin_lock_irqsave(&ha->hardware_lock, flags); } + spin_lock_irqsave(&ha->hardware_lock, flags); } spin_unlock_irqrestore(&ha->hardware_lock, flags); } @@ -693,7 +759,7 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) unsigned long flags; int wait = 0; struct qla_hw_data *ha = vha->hw; - struct req_que *req; + struct req_que *req = vha->req; srb_t *spt; qla2x00_block_error_handler(cmd); @@ -709,7 +775,6 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) spt = (srb_t *) CMD_SP(cmd); if (!spt) return SUCCESS; - req = spt->que; /* Check active list for command command. */ spin_lock_irqsave(&ha->hardware_lock, flags); @@ -726,7 +791,7 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) " pid=%ld.\n", __func__, vha->host_no, sp, serial)); spin_unlock_irqrestore(&ha->hardware_lock, flags); - if (ha->isp_ops->abort_command(vha, sp, req)) { + if (ha->isp_ops->abort_command(sp)) { DEBUG2(printk("%s(%ld): abort_command " "mbx failed.\n", __func__, vha->host_no)); ret = FAILED; @@ -777,7 +842,7 @@ qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *vha, unsigned int t, return status; spin_lock_irqsave(&ha->hardware_lock, flags); - req = sp->que; + req = vha->req; for (cnt = 1; status == QLA_SUCCESS && cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { sp = req->outstanding_cmds[cnt]; @@ -820,7 +885,7 @@ static char *reset_errors[] = { static int __qla2xxx_eh_generic_reset(char *name, enum nexus_wait_type type, - struct scsi_cmnd *cmd, int (*do_reset)(struct fc_port *, unsigned int)) + struct scsi_cmnd *cmd, int (*do_reset)(struct fc_port *, unsigned int, int)) { scsi_qla_host_t *vha = shost_priv(cmd->device->host); fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata; @@ -841,7 +906,8 @@ __qla2xxx_eh_generic_reset(char *name, enum nexus_wait_type type, if (qla2x00_wait_for_loop_ready(vha) != QLA_SUCCESS) goto eh_reset_failed; err = 2; - if (do_reset(fcport, cmd->device->lun) != QLA_SUCCESS) + if (do_reset(fcport, cmd->device->lun, cmd->request->cpu + 1) + != QLA_SUCCESS) goto eh_reset_failed; err = 3; if (qla2x00_eh_wait_for_pending_commands(vha, cmd->device->id, @@ -996,6 +1062,9 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd) if (qla2x00_vp_abort_isp(vha)) goto eh_host_reset_lock; } else { + if (ha->wq) + flush_workqueue(ha->wq); + set_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); if (qla2x00_abort_isp(base_vha)) { clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); @@ -1037,7 +1106,8 @@ qla2x00_loop_reset(scsi_qla_host_t *vha) struct fc_port *fcport; struct qla_hw_data *ha = vha->hw; - if (ha->flags.enable_lip_full_login && !vha->vp_idx) { + if (ha->flags.enable_lip_full_login && !vha->vp_idx && + !IS_QLA81XX(ha)) { ret = qla2x00_full_login_lip(vha); if (ret != QLA_SUCCESS) { DEBUG2_3(printk("%s(%ld): failed: " @@ -1064,7 +1134,7 @@ qla2x00_loop_reset(scsi_qla_host_t *vha) if (fcport->port_type != FCT_TARGET) continue; - ret = ha->isp_ops->target_reset(fcport, 0); + ret = ha->isp_ops->target_reset(fcport, 0, 0); if (ret != QLA_SUCCESS) { DEBUG2_3(printk("%s(%ld): bus_reset failed: " "target_reset=%d d_id=%x.\n", __func__, @@ -1088,7 +1158,7 @@ qla2x00_abort_all_cmds(scsi_qla_host_t *vha, int res) struct req_que *req; spin_lock_irqsave(&ha->hardware_lock, flags); - for (que = 0; que < ha->max_queues; que++) { + for (que = 0; que < ha->max_req_queues; que++) { req = ha->req_q_map[que]; if (!req) continue; @@ -1123,7 +1193,7 @@ qla2xxx_slave_configure(struct scsi_device *sdev) scsi_qla_host_t *vha = shost_priv(sdev->host); struct qla_hw_data *ha = vha->hw; struct fc_rport *rport = starget_to_rport(sdev->sdev_target); - struct req_que *req = ha->req_q_map[vha->req_ques[0]]; + struct req_que *req = vha->req; if (sdev->tagged_supported) scsi_activate_tcq(sdev, req->max_q_depth); @@ -1511,6 +1581,13 @@ qla2x00_set_isp_flags(struct qla_hw_data *ha) ha->fw_srisc_address = RISC_START_ADDRESS_2400; break; } + + /* Get adapter physical port no from interrupt pin register. */ + pci_read_config_byte(ha->pdev, PCI_INTERRUPT_PIN, &ha->port_no); + if (ha->port_no & 1) + ha->flags.port0 = 1; + else + ha->flags.port0 = 0; } static int @@ -1518,6 +1595,7 @@ qla2x00_iospace_config(struct qla_hw_data *ha) { resource_size_t pio; uint16_t msix; + int cpus; if (pci_request_selected_regions(ha->pdev, ha->bars, QLA2XXX_DRIVER_NAME)) { @@ -1571,8 +1649,9 @@ skip_pio: } /* Determine queue resources */ - ha->max_queues = 1; - if (ql2xmaxqueues <= 1 || (!IS_QLA25XX(ha) && !IS_QLA81XX(ha))) + ha->max_req_queues = ha->max_rsp_queues = 1; + if ((ql2xmaxqueues <= 1 || ql2xmultique_tag < 1) && + (!IS_QLA25XX(ha) && !IS_QLA81XX(ha))) goto mqiobase_exit; ha->mqiobase = ioremap(pci_resource_start(ha->pdev, 3), pci_resource_len(ha->pdev, 3)); @@ -1582,18 +1661,24 @@ skip_pio: ha->msix_count = msix; /* Max queues are bounded by available msix vectors */ /* queue 0 uses two msix vectors */ - if (ha->msix_count - 1 < ql2xmaxqueues) - ha->max_queues = ha->msix_count - 1; - else if (ql2xmaxqueues > QLA_MQ_SIZE) - ha->max_queues = QLA_MQ_SIZE; - else - ha->max_queues = ql2xmaxqueues; + if (ql2xmultique_tag) { + cpus = num_online_cpus(); + ha->max_rsp_queues = (ha->msix_count - 1 > cpus) ? + (cpus + 1) : (ha->msix_count - 1); + ha->max_req_queues = 2; + } else if (ql2xmaxqueues > 1) { + ha->max_req_queues = ql2xmaxqueues > QLA_MQ_SIZE ? + QLA_MQ_SIZE : ql2xmaxqueues; + DEBUG2(qla_printk(KERN_INFO, ha, "QoS mode set, max no" + " of request queues:%d\n", ha->max_req_queues)); + } qla_printk(KERN_INFO, ha, "MSI-X vector count: %d\n", msix); - } + } else + qla_printk(KERN_INFO, ha, "BAR 3 not enabled\n"); mqiobase_exit: - ha->msix_count = ha->max_queues + 1; + ha->msix_count = ha->max_rsp_queues + 1; return (0); iospace_error_exit: @@ -1605,6 +1690,9 @@ qla2xxx_scan_start(struct Scsi_Host *shost) { scsi_qla_host_t *vha = shost_priv(shost); + if (vha->hw->flags.running_gold_fw) + return; + set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); set_bit(RSCN_UPDATE, &vha->dpc_flags); @@ -1768,6 +1856,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) ha->init_cb_size = sizeof(struct mid_init_cb_81xx); ha->gid_list_info_size = 8; ha->optrom_size = OPTROM_SIZE_81XX; + ha->nvram_npiv_size = QLA_MAX_VPORTS_QLA25XX; ha->isp_ops = &qla81xx_isp_ops; ha->flash_conf_off = FARX_ACCESS_FLASH_CONF_81XX; ha->flash_data_off = FARX_ACCESS_FLASH_DATA_81XX; @@ -1803,14 +1892,15 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) ret = -ENOMEM; qla2x00_mem_free(ha); - qla2x00_free_que(ha, req, rsp); + qla2x00_free_req_que(ha, req); + qla2x00_free_rsp_que(ha, rsp); goto probe_hw_failed; } pci_set_drvdata(pdev, base_vha); host = base_vha->host; - base_vha->req_ques[0] = req->id; + base_vha->req = req; host->can_queue = req->length + 128; if (IS_QLA2XXX_MIDTYPE(ha)) base_vha->mgmt_svr_loop_id = 10 + base_vha->vp_idx; @@ -1841,7 +1931,10 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) } ha->rsp_q_map[0] = rsp; ha->req_q_map[0] = req; - + rsp->req = req; + req->rsp = rsp; + set_bit(0, ha->req_qid_map); + set_bit(0, ha->rsp_qid_map); /* FWI2-capable only. */ req->req_q_in = &ha->iobase->isp24.req_q_in; req->req_q_out = &ha->iobase->isp24.req_q_out; @@ -1866,6 +1959,15 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) goto probe_failed; } + if (ha->mqenable) + if (qla25xx_setup_mode(base_vha)) + qla_printk(KERN_WARNING, ha, + "Can't create queues, falling back to single" + " queue mode\n"); + + if (ha->flags.running_gold_fw) + goto skip_dpc; + /* * Startup the kernel thread for this host adapter */ @@ -1878,6 +1980,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) goto probe_failed; } +skip_dpc: list_add_tail(&base_vha->list, &ha->vp_list); base_vha->host->irq = ha->pdev->irq; @@ -1917,8 +2020,9 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) return 0; probe_init_failed: - qla2x00_free_que(ha, req, rsp); - ha->max_queues = 0; + qla2x00_free_req_que(ha, req); + qla2x00_free_rsp_que(ha, rsp); + ha->max_req_queues = ha->max_rsp_queues = 0; probe_failed: if (base_vha->timer_active) @@ -1976,6 +2080,13 @@ qla2x00_remove_one(struct pci_dev *pdev) base_vha->flags.online = 0; + /* Flush the work queue and remove it */ + if (ha->wq) { + flush_workqueue(ha->wq); + destroy_workqueue(ha->wq); + ha->wq = NULL; + } + /* Kill the kernel thread for this host */ if (ha->dpc_thread) { struct task_struct *t = ha->dpc_thread; @@ -2017,6 +2128,8 @@ qla2x00_free_device(scsi_qla_host_t *vha) { struct qla_hw_data *ha = vha->hw; + qla25xx_delete_queues(vha); + if (ha->flags.fce_enabled) qla2x00_disable_fce_trace(vha, NULL, NULL); @@ -2329,6 +2442,14 @@ qla2x00_mem_free(struct qla_hw_data *ha) vfree(ha->fw_dump); } + if (ha->dcbx_tlv) + dma_free_coherent(&ha->pdev->dev, DCBX_TLV_DATA_SIZE, + ha->dcbx_tlv, ha->dcbx_tlv_dma); + + if (ha->xgmac_data) + dma_free_coherent(&ha->pdev->dev, XGMAC_DATA_SIZE, + ha->xgmac_data, ha->xgmac_data_dma); + if (ha->sns_cmd) dma_free_coherent(&ha->pdev->dev, sizeof(struct sns_cmd_pkt), ha->sns_cmd, ha->sns_cmd_dma); @@ -2412,6 +2533,8 @@ struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht, INIT_LIST_HEAD(&vha->work_list); INIT_LIST_HEAD(&vha->list); + spin_lock_init(&vha->work_lock); + sprintf(vha->host_str, "%s_%ld", QLA2XXX_DRIVER_NAME, vha->host_no); return vha; @@ -2420,13 +2543,11 @@ fail: } static struct qla_work_evt * -qla2x00_alloc_work(struct scsi_qla_host *vha, enum qla_work_type type, - int locked) +qla2x00_alloc_work(struct scsi_qla_host *vha, enum qla_work_type type) { struct qla_work_evt *e; - e = kzalloc(sizeof(struct qla_work_evt), locked ? GFP_ATOMIC: - GFP_KERNEL); + e = kzalloc(sizeof(struct qla_work_evt), GFP_ATOMIC); if (!e) return NULL; @@ -2437,17 +2558,15 @@ qla2x00_alloc_work(struct scsi_qla_host *vha, enum qla_work_type type, } static int -qla2x00_post_work(struct scsi_qla_host *vha, struct qla_work_evt *e, int locked) +qla2x00_post_work(struct scsi_qla_host *vha, struct qla_work_evt *e) { - unsigned long uninitialized_var(flags); - struct qla_hw_data *ha = vha->hw; + unsigned long flags; - if (!locked) - spin_lock_irqsave(&ha->hardware_lock, flags); + spin_lock_irqsave(&vha->work_lock, flags); list_add_tail(&e->list, &vha->work_list); + spin_unlock_irqrestore(&vha->work_lock, flags); qla2xxx_wake_dpc(vha); - if (!locked) - spin_unlock_irqrestore(&ha->hardware_lock, flags); + return QLA_SUCCESS; } @@ -2457,13 +2576,13 @@ qla2x00_post_aen_work(struct scsi_qla_host *vha, enum fc_host_event_code code, { struct qla_work_evt *e; - e = qla2x00_alloc_work(vha, QLA_EVT_AEN, 1); + e = qla2x00_alloc_work(vha, QLA_EVT_AEN); if (!e) return QLA_FUNCTION_FAILED; e->u.aen.code = code; e->u.aen.data = data; - return qla2x00_post_work(vha, e, 1); + return qla2x00_post_work(vha, e); } int @@ -2471,25 +2590,27 @@ qla2x00_post_idc_ack_work(struct scsi_qla_host *vha, uint16_t *mb) { struct qla_work_evt *e; - e = qla2x00_alloc_work(vha, QLA_EVT_IDC_ACK, 1); + e = qla2x00_alloc_work(vha, QLA_EVT_IDC_ACK); if (!e) return QLA_FUNCTION_FAILED; memcpy(e->u.idc_ack.mb, mb, QLA_IDC_ACK_REGS * sizeof(uint16_t)); - return qla2x00_post_work(vha, e, 1); + return qla2x00_post_work(vha, e); } static void qla2x00_do_work(struct scsi_qla_host *vha) { - struct qla_work_evt *e; - struct qla_hw_data *ha = vha->hw; + struct qla_work_evt *e, *tmp; + unsigned long flags; + LIST_HEAD(work); - spin_lock_irq(&ha->hardware_lock); - while (!list_empty(&vha->work_list)) { - e = list_entry(vha->work_list.next, struct qla_work_evt, list); + spin_lock_irqsave(&vha->work_lock, flags); + list_splice_init(&vha->work_list, &work); + spin_unlock_irqrestore(&vha->work_lock, flags); + + list_for_each_entry_safe(e, tmp, &work, list) { list_del_init(&e->list); - spin_unlock_irq(&ha->hardware_lock); switch (e->type) { case QLA_EVT_AEN: @@ -2502,10 +2623,9 @@ qla2x00_do_work(struct scsi_qla_host *vha) } if (e->flags & QLA_EVT_FLAG_FREE) kfree(e); - spin_lock_irq(&ha->hardware_lock); } - spin_unlock_irq(&ha->hardware_lock); } + /* Relogins all the fcports of a vport * Context: dpc thread */ diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c index 152ecfc26cd2..010e69b29afe 100644 --- a/drivers/scsi/qla2xxx/qla_sup.c +++ b/drivers/scsi/qla2xxx/qla_sup.c @@ -219,8 +219,8 @@ qla2x00_write_nvram_word(struct qla_hw_data *ha, uint32_t addr, uint16_t data) wait_cnt = NVR_WAIT_CNT; do { if (!--wait_cnt) { - DEBUG9_10(printk("%s(%ld): NVRAM didn't go ready...\n", - __func__, vha->host_no)); + DEBUG9_10(qla_printk(KERN_WARNING, ha, + "NVRAM didn't go ready...\n")); break; } NVRAM_DELAY(); @@ -349,7 +349,7 @@ qla2x00_clear_nvram_protection(struct qla_hw_data *ha) wait_cnt = NVR_WAIT_CNT; do { if (!--wait_cnt) { - DEBUG9_10(qla_printk( + DEBUG9_10(qla_printk(KERN_WARNING, ha, "NVRAM didn't go ready...\n")); break; } @@ -408,7 +408,8 @@ qla2x00_set_nvram_protection(struct qla_hw_data *ha, int stat) wait_cnt = NVR_WAIT_CNT; do { if (!--wait_cnt) { - DEBUG9_10(qla_printk("NVRAM didn't go ready...\n")); + DEBUG9_10(qla_printk(KERN_WARNING, ha, + "NVRAM didn't go ready...\n")); break; } NVRAM_DELAY(); @@ -701,32 +702,35 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr) break; case FLT_REG_VPD_0: ha->flt_region_vpd_nvram = start; - if (!(PCI_FUNC(ha->pdev->devfn) & 1)) + if (ha->flags.port0) ha->flt_region_vpd = start; break; case FLT_REG_VPD_1: - if (PCI_FUNC(ha->pdev->devfn) & 1) + if (!ha->flags.port0) ha->flt_region_vpd = start; break; case FLT_REG_NVRAM_0: - if (!(PCI_FUNC(ha->pdev->devfn) & 1)) + if (ha->flags.port0) ha->flt_region_nvram = start; break; case FLT_REG_NVRAM_1: - if (PCI_FUNC(ha->pdev->devfn) & 1) + if (!ha->flags.port0) ha->flt_region_nvram = start; break; case FLT_REG_FDT: ha->flt_region_fdt = start; break; case FLT_REG_NPIV_CONF_0: - if (!(PCI_FUNC(ha->pdev->devfn) & 1)) + if (ha->flags.port0) ha->flt_region_npiv_conf = start; break; case FLT_REG_NPIV_CONF_1: - if (PCI_FUNC(ha->pdev->devfn) & 1) + if (!ha->flags.port0) ha->flt_region_npiv_conf = start; break; + case FLT_REG_GOLD_FW: + ha->flt_region_gold_fw = start; + break; } } goto done; @@ -744,12 +748,12 @@ no_flash_data: ha->flt_region_fw = def_fw[def]; ha->flt_region_boot = def_boot[def]; ha->flt_region_vpd_nvram = def_vpd_nvram[def]; - ha->flt_region_vpd = !(PCI_FUNC(ha->pdev->devfn) & 1) ? + ha->flt_region_vpd = ha->flags.port0 ? def_vpd0[def]: def_vpd1[def]; - ha->flt_region_nvram = !(PCI_FUNC(ha->pdev->devfn) & 1) ? + ha->flt_region_nvram = ha->flags.port0 ? def_nvram0[def]: def_nvram1[def]; ha->flt_region_fdt = def_fdt[def]; - ha->flt_region_npiv_conf = !(PCI_FUNC(ha->pdev->devfn) & 1) ? + ha->flt_region_npiv_conf = ha->flags.port0 ? def_npiv_conf0[def]: def_npiv_conf1[def]; done: DEBUG2(qla_printk(KERN_DEBUG, ha, "FLT[%s]: boot=0x%x fw=0x%x " @@ -924,6 +928,8 @@ qla2xxx_flash_npiv_conf(scsi_qla_host_t *vha) struct fc_vport_identifiers vid; struct fc_vport *vport; + memcpy(&ha->npiv_info[i], entry, sizeof(struct qla_npiv_entry)); + flags = le16_to_cpu(entry->flags); if (flags == 0xffff) continue; @@ -937,11 +943,11 @@ qla2xxx_flash_npiv_conf(scsi_qla_host_t *vha) vid.port_name = wwn_to_u64(entry->port_name); vid.node_name = wwn_to_u64(entry->node_name); - memcpy(&ha->npiv_info[i], entry, sizeof(struct qla_npiv_entry)); - - DEBUG2(qla_printk(KERN_DEBUG, ha, "NPIV[%02x]: wwpn=%llx " + DEBUG2(qla_printk(KERN_INFO, ha, "NPIV[%02x]: wwpn=%llx " "wwnn=%llx vf_id=0x%x Q_qos=0x%x F_qos=0x%x.\n", cnt, - vid.port_name, vid.node_name, le16_to_cpu(entry->vf_id), + (unsigned long long)vid.port_name, + (unsigned long long)vid.node_name, + le16_to_cpu(entry->vf_id), entry->q_qos, entry->f_qos)); if (i < QLA_PRECONFIG_VPORTS) { @@ -950,12 +956,12 @@ qla2xxx_flash_npiv_conf(scsi_qla_host_t *vha) qla_printk(KERN_INFO, ha, "NPIV-Config: Failed to create vport [%02x]: " "wwpn=%llx wwnn=%llx.\n", cnt, - vid.port_name, vid.node_name); + (unsigned long long)vid.port_name, + (unsigned long long)vid.node_name); } } done: kfree(data); - ha->npiv_info = NULL; } static int @@ -1079,8 +1085,9 @@ qla24xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr, 0xff0000) | ((fdata >> 16) & 0xff)); ret = qla24xx_erase_sector(vha, fdata); if (ret != QLA_SUCCESS) { - DEBUG9(qla_printk("Unable to erase sector: " - "address=%x.\n", faddr)); + DEBUG9(qla_printk(KERN_WARNING, ha, + "Unable to erase sector: address=%x.\n", + faddr)); break; } } @@ -1240,8 +1247,9 @@ qla24xx_write_nvram_data(scsi_qla_host_t *vha, uint8_t *buf, uint32_t naddr, ret = qla24xx_write_flash_dword(ha, nvram_data_addr(ha, naddr), cpu_to_le32(*dwptr)); if (ret != QLA_SUCCESS) { - DEBUG9(qla_printk("Unable to program nvram address=%x " - "data=%x.\n", naddr, *dwptr)); + DEBUG9(qla_printk(KERN_WARNING, ha, + "Unable to program nvram address=%x data=%x.\n", + naddr, *dwptr)); break; } } diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index 19d1afc3a343..84369705a9ad 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -7,7 +7,7 @@ /* * Driver version */ -#define QLA2XXX_VERSION "8.03.01-k1" +#define QLA2XXX_VERSION "8.03.01-k4" #define QLA_DRIVER_MAJOR_VER 8 #define QLA_DRIVER_MINOR_VER 3 diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 166417a6afba..2de5f3ad640b 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -1225,8 +1225,8 @@ EXPORT_SYMBOL(__scsi_device_lookup_by_target); * @starget: SCSI target pointer * @lun: SCSI Logical Unit Number * - * Description: Looks up the scsi_device with the specified @channel, @id, @lun - * for a given host. The returned scsi_device has an additional reference that + * Description: Looks up the scsi_device with the specified @lun for a given + * @starget. The returned scsi_device has an additional reference that * needs to be released with scsi_device_put once you're done with it. **/ struct scsi_device *scsi_device_lookup_by_target(struct scsi_target *starget, diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 213123b0486b..fb9af207d61d 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -101,6 +101,8 @@ static const char * scsi_debug_version_date = "20070104"; #define DEF_DIF 0 #define DEF_GUARD 0 #define DEF_ATO 1 +#define DEF_PHYSBLK_EXP 0 +#define DEF_LOWEST_ALIGNED 0 /* bit mask values for scsi_debug_opts */ #define SCSI_DEBUG_OPT_NOISE 1 @@ -156,6 +158,8 @@ static int scsi_debug_dix = DEF_DIX; static int scsi_debug_dif = DEF_DIF; static int scsi_debug_guard = DEF_GUARD; static int scsi_debug_ato = DEF_ATO; +static int scsi_debug_physblk_exp = DEF_PHYSBLK_EXP; +static int scsi_debug_lowest_aligned = DEF_LOWEST_ALIGNED; static int scsi_debug_cmnd_count = 0; @@ -657,7 +661,12 @@ static unsigned char vpdb0_data[] = { static int inquiry_evpd_b0(unsigned char * arr) { + unsigned int gran; + memcpy(arr, vpdb0_data, sizeof(vpdb0_data)); + gran = 1 << scsi_debug_physblk_exp; + arr[2] = (gran >> 8) & 0xff; + arr[3] = gran & 0xff; if (sdebug_store_sectors > 0x400) { arr[4] = (sdebug_store_sectors >> 24) & 0xff; arr[5] = (sdebug_store_sectors >> 16) & 0xff; @@ -887,7 +896,7 @@ static int resp_start_stop(struct scsi_cmnd * scp, static sector_t get_sdebug_capacity(void) { if (scsi_debug_virtual_gb > 0) - return 2048 * 1024 * scsi_debug_virtual_gb; + return 2048 * 1024 * (sector_t)scsi_debug_virtual_gb; else return sdebug_store_sectors; } @@ -945,6 +954,9 @@ static int resp_readcap16(struct scsi_cmnd * scp, arr[9] = (scsi_debug_sector_size >> 16) & 0xff; arr[10] = (scsi_debug_sector_size >> 8) & 0xff; arr[11] = scsi_debug_sector_size & 0xff; + arr[13] = scsi_debug_physblk_exp & 0xf; + arr[14] = (scsi_debug_lowest_aligned >> 8) & 0x3f; + arr[15] = scsi_debug_lowest_aligned & 0xff; if (scsi_debug_dif) { arr[12] = (scsi_debug_dif - 1) << 1; /* P_TYPE */ @@ -2380,6 +2392,8 @@ module_param_named(dix, scsi_debug_dix, int, S_IRUGO); module_param_named(dif, scsi_debug_dif, int, S_IRUGO); module_param_named(guard, scsi_debug_guard, int, S_IRUGO); module_param_named(ato, scsi_debug_ato, int, S_IRUGO); +module_param_named(physblk_exp, scsi_debug_physblk_exp, int, S_IRUGO); +module_param_named(lowest_aligned, scsi_debug_lowest_aligned, int, S_IRUGO); MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert"); MODULE_DESCRIPTION("SCSI debug adapter driver"); @@ -2401,7 +2415,9 @@ MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])"); MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])"); MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)"); MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)"); -MODULE_PARM_DESC(sector_size, "hardware sector size in bytes (def=512)"); +MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)"); +MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)"); +MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)"); MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)"); MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)"); MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)"); @@ -2874,6 +2890,18 @@ static int __init scsi_debug_init(void) return -EINVAL; } + if (scsi_debug_physblk_exp > 15) { + printk(KERN_ERR "scsi_debug_init: invalid physblk_exp %u\n", + scsi_debug_physblk_exp); + return -EINVAL; + } + + if (scsi_debug_lowest_aligned > 0x3fff) { + printk(KERN_ERR "scsi_debug_init: lowest_aligned too big: %u\n", + scsi_debug_lowest_aligned); + return -EINVAL; + } + if (scsi_debug_dev_size_mb < 1) scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */ sz = (unsigned long)scsi_debug_dev_size_mb * 1048576; diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index b13481369642..93c2622cb969 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c @@ -24,6 +24,13 @@ struct scsi_dev_info_list { unsigned compatible; /* for use with scsi_static_device_list entries */ }; +struct scsi_dev_info_list_table { + struct list_head node; /* our node for being on the master list */ + struct list_head scsi_dev_info_list; /* head of dev info list */ + const char *name; /* name of list for /proc (NULL for global) */ + int key; /* unique numeric identifier */ +}; + static const char spaces[] = " "; /* 16 of them */ static unsigned scsi_default_dev_flags; @@ -225,6 +232,7 @@ static struct { {"SGI", "Universal Xport", "*", BLIST_NO_ULD_ATTACH}, {"IBM", "Universal Xport", "*", BLIST_NO_ULD_ATTACH}, {"SUN", "Universal Xport", "*", BLIST_NO_ULD_ATTACH}, + {"DELL", "Universal Xport", "*", BLIST_NO_ULD_ATTACH}, {"SMSC", "USB 2 HS-CF", NULL, BLIST_SPARSELUN | BLIST_INQUIRY_36}, {"SONY", "CD-ROM CDU-8001", NULL, BLIST_BORKEN}, {"SONY", "TSL", NULL, BLIST_FORCELUN}, /* DDS3 & DDS4 autoloaders */ @@ -246,6 +254,22 @@ static struct { { NULL, NULL, NULL, 0 }, }; +static struct scsi_dev_info_list_table *scsi_devinfo_lookup_by_key(int key) +{ + struct scsi_dev_info_list_table *devinfo_table; + int found = 0; + + list_for_each_entry(devinfo_table, &scsi_dev_info_list, node) + if (devinfo_table->key == key) { + found = 1; + break; + } + if (!found) + return ERR_PTR(-EINVAL); + + return devinfo_table; +} + /* * scsi_strcpy_devinfo: called from scsi_dev_info_list_add to copy into * devinfo vendor and model strings. @@ -294,8 +318,39 @@ static void scsi_strcpy_devinfo(char *name, char *to, size_t to_length, **/ static int scsi_dev_info_list_add(int compatible, char *vendor, char *model, char *strflags, int flags) +{ + return scsi_dev_info_list_add_keyed(compatible, vendor, model, + strflags, flags, + SCSI_DEVINFO_GLOBAL); +} + +/** + * scsi_dev_info_list_add_keyed - add one dev_info list entry. + * @compatible: if true, null terminate short strings. Otherwise space pad. + * @vendor: vendor string + * @model: model (product) string + * @strflags: integer string + * @flags: if strflags NULL, use this flag value + * @key: specify list to use + * + * Description: + * Create and add one dev_info entry for @vendor, @model, + * @strflags or @flag in list specified by @key. If @compatible, + * add to the tail of the list, do not space pad, and set + * devinfo->compatible. The scsi_static_device_list entries are + * added with @compatible 1 and @clfags NULL. + * + * Returns: 0 OK, -error on failure. + **/ +int scsi_dev_info_list_add_keyed(int compatible, char *vendor, char *model, + char *strflags, int flags, int key) { struct scsi_dev_info_list *devinfo; + struct scsi_dev_info_list_table *devinfo_table = + scsi_devinfo_lookup_by_key(key); + + if (IS_ERR(devinfo_table)) + return PTR_ERR(devinfo_table); devinfo = kmalloc(sizeof(*devinfo), GFP_KERNEL); if (!devinfo) { @@ -316,12 +371,15 @@ static int scsi_dev_info_list_add(int compatible, char *vendor, char *model, devinfo->compatible = compatible; if (compatible) - list_add_tail(&devinfo->dev_info_list, &scsi_dev_info_list); + list_add_tail(&devinfo->dev_info_list, + &devinfo_table->scsi_dev_info_list); else - list_add(&devinfo->dev_info_list, &scsi_dev_info_list); + list_add(&devinfo->dev_info_list, + &devinfo_table->scsi_dev_info_list); return 0; } +EXPORT_SYMBOL(scsi_dev_info_list_add_keyed); /** * scsi_dev_info_list_add_str - parse dev_list and add to the scsi_dev_info_list. @@ -381,22 +439,48 @@ static int scsi_dev_info_list_add_str(char *dev_list) * @model: model name * * Description: - * Search the scsi_dev_info_list for an entry matching @vendor and - * @model, if found, return the matching flags value, else return - * the host or global default settings. Called during scan time. + * Search the global scsi_dev_info_list (specified by list zero) + * for an entry matching @vendor and @model, if found, return the + * matching flags value, else return the host or global default + * settings. Called during scan time. **/ int scsi_get_device_flags(struct scsi_device *sdev, const unsigned char *vendor, const unsigned char *model) +{ + return scsi_get_device_flags_keyed(sdev, vendor, model, + SCSI_DEVINFO_GLOBAL); +} + + +/** + * get_device_flags_keyed - get device specific flags from the dynamic device list. + * @sdev: &scsi_device to get flags for + * @vendor: vendor name + * @model: model name + * @key: list to look up + * + * Description: + * Search the scsi_dev_info_list specified by @key for an entry + * matching @vendor and @model, if found, return the matching + * flags value, else return the host or global default settings. + * Called during scan time. + **/ +int scsi_get_device_flags_keyed(struct scsi_device *sdev, + const unsigned char *vendor, + const unsigned char *model, + int key) { struct scsi_dev_info_list *devinfo; - unsigned int bflags; + struct scsi_dev_info_list_table *devinfo_table; - bflags = sdev->sdev_bflags; - if (!bflags) - bflags = scsi_default_dev_flags; + devinfo_table = scsi_devinfo_lookup_by_key(key); - list_for_each_entry(devinfo, &scsi_dev_info_list, dev_info_list) { + if (IS_ERR(devinfo_table)) + return PTR_ERR(devinfo_table); + + list_for_each_entry(devinfo, &devinfo_table->scsi_dev_info_list, + dev_info_list) { if (devinfo->compatible) { /* * Behave like the older version of get_device_flags. @@ -446,32 +530,89 @@ int scsi_get_device_flags(struct scsi_device *sdev, return devinfo->flags; } } - return bflags; + /* nothing found, return nothing */ + if (key != SCSI_DEVINFO_GLOBAL) + return 0; + + /* except for the global list, where we have an exception */ + if (sdev->sdev_bflags) + return sdev->sdev_bflags; + + return scsi_default_dev_flags; } +EXPORT_SYMBOL(scsi_get_device_flags_keyed); #ifdef CONFIG_SCSI_PROC_FS +struct double_list { + struct list_head *top; + struct list_head *bottom; +}; + static int devinfo_seq_show(struct seq_file *m, void *v) { + struct double_list *dl = v; + struct scsi_dev_info_list_table *devinfo_table = + list_entry(dl->top, struct scsi_dev_info_list_table, node); struct scsi_dev_info_list *devinfo = - list_entry(v, struct scsi_dev_info_list, dev_info_list); + list_entry(dl->bottom, struct scsi_dev_info_list, + dev_info_list); + + if (devinfo_table->scsi_dev_info_list.next == dl->bottom && + devinfo_table->name) + seq_printf(m, "[%s]:\n", devinfo_table->name); seq_printf(m, "'%.8s' '%.16s' 0x%x\n", - devinfo->vendor, devinfo->model, devinfo->flags); + devinfo->vendor, devinfo->model, devinfo->flags); return 0; } -static void * devinfo_seq_start(struct seq_file *m, loff_t *pos) +static void *devinfo_seq_start(struct seq_file *m, loff_t *ppos) { - return seq_list_start(&scsi_dev_info_list, *pos); + struct double_list *dl = kmalloc(sizeof(*dl), GFP_KERNEL); + loff_t pos = *ppos; + + if (!dl) + return NULL; + + list_for_each(dl->top, &scsi_dev_info_list) { + struct scsi_dev_info_list_table *devinfo_table = + list_entry(dl->top, struct scsi_dev_info_list_table, + node); + list_for_each(dl->bottom, &devinfo_table->scsi_dev_info_list) + if (pos-- == 0) + return dl; + } + + kfree(dl); + return NULL; } -static void * devinfo_seq_next(struct seq_file *m, void *v, loff_t *pos) +static void *devinfo_seq_next(struct seq_file *m, void *v, loff_t *ppos) { - return seq_list_next(v, &scsi_dev_info_list, pos); + struct double_list *dl = v; + struct scsi_dev_info_list_table *devinfo_table = + list_entry(dl->top, struct scsi_dev_info_list_table, node); + + ++*ppos; + dl->bottom = dl->bottom->next; + while (&devinfo_table->scsi_dev_info_list == dl->bottom) { + dl->top = dl->top->next; + if (dl->top == &scsi_dev_info_list) { + kfree(dl); + return NULL; + } + devinfo_table = list_entry(dl->top, + struct scsi_dev_info_list_table, + node); + dl->bottom = devinfo_table->scsi_dev_info_list.next; + } + + return dl; } static void devinfo_seq_stop(struct seq_file *m, void *v) { + kfree(v); } static const struct seq_operations scsi_devinfo_seq_ops = { @@ -548,19 +689,78 @@ MODULE_PARM_DESC(default_dev_flags, **/ void scsi_exit_devinfo(void) { - struct list_head *lh, *lh_next; - struct scsi_dev_info_list *devinfo; - #ifdef CONFIG_SCSI_PROC_FS remove_proc_entry("scsi/device_info", NULL); #endif - list_for_each_safe(lh, lh_next, &scsi_dev_info_list) { + scsi_dev_info_remove_list(SCSI_DEVINFO_GLOBAL); +} + +/** + * scsi_dev_info_add_list - add a new devinfo list + * @key: key of the list to add + * @name: Name of the list to add (for /proc/scsi/device_info) + * + * Adds the requested list, returns zero on success, -EEXIST if the + * key is already registered to a list, or other error on failure. + */ +int scsi_dev_info_add_list(int key, const char *name) +{ + struct scsi_dev_info_list_table *devinfo_table = + scsi_devinfo_lookup_by_key(key); + + if (!IS_ERR(devinfo_table)) + /* list already exists */ + return -EEXIST; + + devinfo_table = kmalloc(sizeof(*devinfo_table), GFP_KERNEL); + + if (!devinfo_table) + return -ENOMEM; + + INIT_LIST_HEAD(&devinfo_table->node); + INIT_LIST_HEAD(&devinfo_table->scsi_dev_info_list); + devinfo_table->name = name; + devinfo_table->key = key; + list_add_tail(&devinfo_table->node, &scsi_dev_info_list); + + return 0; +} +EXPORT_SYMBOL(scsi_dev_info_add_list); + +/** + * scsi_dev_info_remove_list - destroy an added devinfo list + * @key: key of the list to destroy + * + * Iterates over the entire list first, freeing all the values, then + * frees the list itself. Returns 0 on success or -EINVAL if the key + * can't be found. + */ +int scsi_dev_info_remove_list(int key) +{ + struct list_head *lh, *lh_next; + struct scsi_dev_info_list_table *devinfo_table = + scsi_devinfo_lookup_by_key(key); + + if (IS_ERR(devinfo_table)) + /* no such list */ + return -EINVAL; + + /* remove from the master list */ + list_del(&devinfo_table->node); + + list_for_each_safe(lh, lh_next, &devinfo_table->scsi_dev_info_list) { + struct scsi_dev_info_list *devinfo; + devinfo = list_entry(lh, struct scsi_dev_info_list, dev_info_list); kfree(devinfo); } + kfree(devinfo_table); + + return 0; } +EXPORT_SYMBOL(scsi_dev_info_remove_list); /** * scsi_init_devinfo - set up the dynamic device list. @@ -576,10 +776,14 @@ int __init scsi_init_devinfo(void) #endif int error, i; - error = scsi_dev_info_list_add_str(scsi_dev_flags); + error = scsi_dev_info_add_list(SCSI_DEVINFO_GLOBAL, NULL); if (error) return error; + error = scsi_dev_info_list_add_str(scsi_dev_flags); + if (error) + goto out; + for (i = 0; scsi_static_device_list[i].vendor; i++) { error = scsi_dev_info_list_add(1 /* compatibile */, scsi_static_device_list[i].vendor, diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 0c2c73be1974..a1689353d7fd 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -641,9 +641,9 @@ EXPORT_SYMBOL(scsi_eh_prep_cmnd); /** * scsi_eh_restore_cmnd - Restore a scsi command info as part of error recory * @scmd: SCSI command structure to restore - * @ses: saved information from a coresponding call to scsi_prep_eh_cmnd + * @ses: saved information from a coresponding call to scsi_eh_prep_cmnd * - * Undo any damage done by above scsi_prep_eh_cmnd(). + * Undo any damage done by above scsi_eh_prep_cmnd(). */ void scsi_eh_restore_cmnd(struct scsi_cmnd* scmd, struct scsi_eh_save *ses) { @@ -1451,28 +1451,21 @@ static void eh_lock_door_done(struct request *req, int uptodate) * @sdev: SCSI device to prevent medium removal * * Locking: - * We must be called from process context; scsi_allocate_request() - * may sleep. + * We must be called from process context. * * Notes: * We queue up an asynchronous "ALLOW MEDIUM REMOVAL" request on the * head of the devices request queue, and continue. - * - * Bugs: - * scsi_allocate_request() may sleep waiting for existing requests to - * be processed. However, since we haven't kicked off any request - * processing for this host, this may deadlock. - * - * If scsi_allocate_request() fails for what ever reason, we - * completely forget to lock the door. */ static void scsi_eh_lock_door(struct scsi_device *sdev) { struct request *req; + /* + * blk_get_request with GFP_KERNEL (__GFP_WAIT) sleeps until a + * request becomes available + */ req = blk_get_request(sdev->request_queue, READ, GFP_KERNEL); - if (!req) - return; req->cmd[0] = ALLOW_MEDIUM_REMOVAL; req->cmd[1] = 0; diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index bb218c8b6e98..f3c40898fc7d 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -240,11 +240,11 @@ int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd, * is invalid. Prevent the garbage from being misinterpreted * and prevent security leaks by zeroing out the excess data. */ - if (unlikely(req->data_len > 0 && req->data_len <= bufflen)) - memset(buffer + (bufflen - req->data_len), 0, req->data_len); + if (unlikely(req->resid_len > 0 && req->resid_len <= bufflen)) + memset(buffer + (bufflen - req->resid_len), 0, req->resid_len); if (resid) - *resid = req->data_len; + *resid = req->resid_len; ret = req->errors; out: blk_put_request(req); @@ -546,14 +546,9 @@ static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int error, * to queue the remainder of them. */ if (blk_end_request(req, error, bytes)) { - int leftover = (req->hard_nr_sectors << 9); - - if (blk_pc_request(req)) - leftover = req->data_len; - /* kill remainder if no retrys */ if (error && scsi_noretry_cmd(cmd)) - blk_end_request(req, error, leftover); + blk_end_request_all(req, error); else { if (requeue) { /* @@ -672,34 +667,6 @@ void scsi_release_buffers(struct scsi_cmnd *cmd) } EXPORT_SYMBOL(scsi_release_buffers); -/* - * Bidi commands Must be complete as a whole, both sides at once. - * If part of the bytes were written and lld returned - * scsi_in()->resid and/or scsi_out()->resid this information will be left - * in req->data_len and req->next_rq->data_len. The upper-layer driver can - * decide what to do with this information. - */ -static void scsi_end_bidi_request(struct scsi_cmnd *cmd) -{ - struct request *req = cmd->request; - unsigned int dlen = req->data_len; - unsigned int next_dlen = req->next_rq->data_len; - - req->data_len = scsi_out(cmd)->resid; - req->next_rq->data_len = scsi_in(cmd)->resid; - - /* The req and req->next_rq have not been completed */ - BUG_ON(blk_end_bidi_request(req, 0, dlen, next_dlen)); - - scsi_release_buffers(cmd); - - /* - * This will goose the queue request function at the end, so we don't - * need to worry about launching another command. - */ - scsi_next_command(cmd); -} - /* * Function: scsi_io_completion() * @@ -739,7 +706,6 @@ static void scsi_end_bidi_request(struct scsi_cmnd *cmd) void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) { int result = cmd->result; - int this_count; struct request_queue *q = cmd->device->request_queue; struct request *req = cmd->request; int error = 0; @@ -773,12 +739,22 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) if (!sense_deferred) error = -EIO; } + + req->resid_len = scsi_get_resid(cmd); + if (scsi_bidi_cmnd(cmd)) { - /* will also release_buffers */ - scsi_end_bidi_request(cmd); + /* + * Bidi commands Must be complete as a whole, + * both sides at once. + */ + req->next_rq->resid_len = scsi_in(cmd)->resid; + + blk_end_request_all(req, 0); + + scsi_release_buffers(cmd); + scsi_next_command(cmd); return; } - req->data_len = scsi_get_resid(cmd); } BUG_ON(blk_bidi_rq(req)); /* bidi not support for !blk_pc_request yet */ @@ -787,9 +763,9 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) * Next deal with any sectors which we were able to correctly * handle. */ - SCSI_LOG_HLCOMPLETE(1, printk("%ld sectors total, " + SCSI_LOG_HLCOMPLETE(1, printk("%u sectors total, " "%d bytes done.\n", - req->nr_sectors, good_bytes)); + blk_rq_sectors(req), good_bytes)); /* * Recovered errors need reporting, but they're always treated @@ -812,7 +788,6 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) */ if (scsi_end_request(cmd, error, good_bytes, result == 0) == NULL) return; - this_count = blk_rq_bytes(req); error = -EIO; @@ -922,7 +897,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) if (driver_byte(result) & DRIVER_SENSE) scsi_print_sense("", cmd); } - blk_end_request(req, -EIO, blk_rq_bytes(req)); + blk_end_request_all(req, -EIO); scsi_next_command(cmd); break; case ACTION_REPREP: @@ -965,10 +940,7 @@ static int scsi_init_sgtable(struct request *req, struct scsi_data_buffer *sdb, count = blk_rq_map_sg(req->q, req, sdb->table.sgl); BUG_ON(count > sdb->table.nents); sdb->table.nents = count; - if (blk_pc_request(req)) - sdb->length = req->data_len; - else - sdb->length = req->nr_sectors << 9; + sdb->length = blk_rq_bytes(req); return BLKPREP_OK; } @@ -1087,22 +1059,21 @@ int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req) if (unlikely(ret)) return ret; } else { - BUG_ON(req->data_len); - BUG_ON(req->data); + BUG_ON(blk_rq_bytes(req)); memset(&cmd->sdb, 0, sizeof(cmd->sdb)); req->buffer = NULL; } cmd->cmd_len = req->cmd_len; - if (!req->data_len) + if (!blk_rq_bytes(req)) cmd->sc_data_direction = DMA_NONE; else if (rq_data_dir(req) == WRITE) cmd->sc_data_direction = DMA_TO_DEVICE; else cmd->sc_data_direction = DMA_FROM_DEVICE; - cmd->transfersize = req->data_len; + cmd->transfersize = blk_rq_bytes(req); cmd->allowed = req->retries; return BLKPREP_OK; } @@ -1212,7 +1183,7 @@ int scsi_prep_return(struct request_queue *q, struct request *req, int ret) break; case BLKPREP_DEFER: /* - * If we defer, the elv_next_request() returns NULL, but the + * If we defer, the blk_peek_request() returns NULL, but the * queue must be restarted, so we plug here if no returning * command will automatically do that. */ @@ -1236,6 +1207,7 @@ int scsi_prep_fn(struct request_queue *q, struct request *req) ret = scsi_setup_blk_pc_cmnd(sdev, req); return scsi_prep_return(q, req, ret); } +EXPORT_SYMBOL(scsi_prep_fn); /* * scsi_dev_queue_ready: if we can send requests to sdev, return 1 else @@ -1388,7 +1360,7 @@ static void scsi_kill_request(struct request *req, struct request_queue *q) struct scsi_target *starget = scsi_target(sdev); struct Scsi_Host *shost = sdev->host; - blkdev_dequeue_request(req); + blk_start_request(req); if (unlikely(cmd == NULL)) { printk(KERN_CRIT "impossible request in %s.\n", @@ -1480,7 +1452,7 @@ static void scsi_request_fn(struct request_queue *q) if (!sdev) { printk("scsi: killing requests for dead queue\n"); - while ((req = elv_next_request(q)) != NULL) + while ((req = blk_peek_request(q)) != NULL) scsi_kill_request(req, q); return; } @@ -1501,7 +1473,7 @@ static void scsi_request_fn(struct request_queue *q) * that the request is fully prepared even if we cannot * accept it. */ - req = elv_next_request(q); + req = blk_peek_request(q); if (!req || !scsi_dev_queue_ready(q, sdev)) break; @@ -1517,7 +1489,7 @@ static void scsi_request_fn(struct request_queue *q) * Remove the request from the request list. */ if (!(blk_queue_tagged(q) && !blk_queue_start_tag(q, req))) - blkdev_dequeue_request(req); + blk_start_request(req); sdev->device_busy++; spin_unlock(q->queue_lock); @@ -2441,20 +2413,18 @@ int scsi_internal_device_unblock(struct scsi_device *sdev) { struct request_queue *q = sdev->request_queue; - int err; unsigned long flags; /* * Try to transition the scsi device to SDEV_RUNNING * and goose the device queue if successful. */ - err = scsi_device_set_state(sdev, SDEV_RUNNING); - if (err) { - err = scsi_device_set_state(sdev, SDEV_CREATED); - - if (err) - return err; - } + if (sdev->sdev_state == SDEV_BLOCK) + sdev->sdev_state = SDEV_RUNNING; + else if (sdev->sdev_state == SDEV_CREATED_BLOCK) + sdev->sdev_state = SDEV_CREATED; + else + return -EINVAL; spin_lock_irqsave(q->queue_lock, flags); blk_start_queue(q); diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index fbc83bebdd8e..021e503c8c44 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h @@ -39,9 +39,25 @@ static inline void scsi_log_completion(struct scsi_cmnd *cmd, int disposition) #endif /* scsi_devinfo.c */ + +/* list of keys for the lists */ +enum { + SCSI_DEVINFO_GLOBAL = 0, + SCSI_DEVINFO_SPI, +}; + extern int scsi_get_device_flags(struct scsi_device *sdev, const unsigned char *vendor, const unsigned char *model); +extern int scsi_get_device_flags_keyed(struct scsi_device *sdev, + const unsigned char *vendor, + const unsigned char *model, int key); +extern int scsi_dev_info_list_add_keyed(int compatible, char *vendor, + char *model, char *strflags, + int flags, int key); +extern int scsi_dev_info_add_list(int key, const char *name); +extern int scsi_dev_info_remove_list(int key); + extern int __init scsi_init_devinfo(void); extern void scsi_exit_devinfo(void); @@ -71,7 +87,6 @@ extern int scsi_init_queue(void); extern void scsi_exit_queue(void); struct request_queue; struct request; -extern int scsi_prep_fn(struct request_queue *, struct request *); extern struct kmem_cache *scsi_sdb_cache; /* scsi_proc.c */ diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index e2b50d8f57a8..c44783801402 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -115,12 +115,12 @@ MODULE_PARM_DESC(max_report_luns, "REPORT LUNS maximum number of LUNS received (should be" " between 1 and 16384)"); -static unsigned int scsi_inq_timeout = SCSI_TIMEOUT/HZ+3; +static unsigned int scsi_inq_timeout = SCSI_TIMEOUT/HZ + 18; module_param_named(inq_timeout, scsi_inq_timeout, uint, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(inq_timeout, "Timeout (in seconds) waiting for devices to answer INQUIRY." - " Default is 5. Some non-compliant devices need more."); + " Default is 20. Some devices may need more; most need less."); /* This lock protects only this list */ static DEFINE_SPINLOCK(async_scan_lock); diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index fa4711d12744..91482f2dcc50 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -420,29 +420,12 @@ static int scsi_bus_resume(struct device * dev) return err; } -static int scsi_bus_remove(struct device *dev) -{ - struct device_driver *drv = dev->driver; - struct scsi_device *sdev = to_scsi_device(dev); - int err = 0; - - /* reset the prep_fn back to the default since the - * driver may have altered it and it's being removed */ - blk_queue_prep_rq(sdev->request_queue, scsi_prep_fn); - - if (drv && drv->remove) - err = drv->remove(dev); - - return 0; -} - struct bus_type scsi_bus_type = { .name = "scsi", .match = scsi_bus_match, .uevent = scsi_bus_uevent, .suspend = scsi_bus_suspend, .resume = scsi_bus_resume, - .remove = scsi_bus_remove, }; EXPORT_SYMBOL_GPL(scsi_bus_type); diff --git a/drivers/scsi/scsi_tgt_lib.c b/drivers/scsi/scsi_tgt_lib.c index 48ba413f7f6a..10303272ba45 100644 --- a/drivers/scsi/scsi_tgt_lib.c +++ b/drivers/scsi/scsi_tgt_lib.c @@ -387,7 +387,7 @@ static int scsi_map_user_pages(struct scsi_tgt_cmd *tcmd, struct scsi_cmnd *cmd, * we use REQ_TYPE_BLOCK_PC so scsi_init_io doesn't set the * length for us. */ - cmd->sdb.length = rq->data_len; + cmd->sdb.length = blk_rq_bytes(rq); return 0; diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index a152f89ae51c..2eee9e6e4fe8 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -35,6 +35,7 @@ #include #include #include +#include #include "scsi_priv.h" #include "scsi_transport_fc_internal.h" @@ -43,6 +44,10 @@ static void fc_vport_sched_delete(struct work_struct *work); static int fc_vport_setup(struct Scsi_Host *shost, int channel, struct device *pdev, struct fc_vport_identifiers *ids, struct fc_vport **vport); +static int fc_bsg_hostadd(struct Scsi_Host *, struct fc_host_attrs *); +static int fc_bsg_rportadd(struct Scsi_Host *, struct fc_rport *); +static void fc_bsg_remove(struct request_queue *); +static void fc_bsg_goose_queue(struct fc_rport *); /* * Redefine so that we can have same named attributes in the @@ -411,13 +416,26 @@ static int fc_host_setup(struct transport_container *tc, struct device *dev, return -ENOMEM; } + fc_bsg_hostadd(shost, fc_host); + /* ignore any bsg add error - we just can't do sgio */ + + return 0; +} + +static int fc_host_remove(struct transport_container *tc, struct device *dev, + struct device *cdev) +{ + struct Scsi_Host *shost = dev_to_shost(dev); + struct fc_host_attrs *fc_host = shost_to_fc_host(shost); + + fc_bsg_remove(fc_host->rqst_q); return 0; } static DECLARE_TRANSPORT_CLASS(fc_host_class, "fc_host", fc_host_setup, - NULL, + fc_host_remove, NULL); /* @@ -2375,6 +2393,7 @@ fc_rport_final_delete(struct work_struct *work) scsi_flush_work(shost); fc_terminate_rport_io(rport); + /* * Cancel any outstanding timers. These should really exist * only when rmmod'ing the LLDD and we're asking for @@ -2407,6 +2426,8 @@ fc_rport_final_delete(struct work_struct *work) (i->f->dev_loss_tmo_callbk)) i->f->dev_loss_tmo_callbk(rport); + fc_bsg_remove(rport->rqst_q); + transport_remove_device(dev); device_del(dev); transport_destroy_device(dev); @@ -2494,6 +2515,9 @@ fc_rport_create(struct Scsi_Host *shost, int channel, transport_add_device(dev); transport_configure_device(dev); + fc_bsg_rportadd(shost, rport); + /* ignore any bsg add error - we just can't do sgio */ + if (rport->roles & FC_PORT_ROLE_FCP_TARGET) { /* initiate a scan of the target */ rport->flags |= FC_RPORT_SCAN_PENDING; @@ -2658,6 +2682,8 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel, spin_unlock_irqrestore(shost->host_lock, flags); + fc_bsg_goose_queue(rport); + return rport; } } @@ -3343,6 +3369,596 @@ fc_vport_sched_delete(struct work_struct *work) } +/* + * BSG support + */ + + +/** + * fc_destroy_bsgjob - routine to teardown/delete a fc bsg job + * @job: fc_bsg_job that is to be torn down + */ +static void +fc_destroy_bsgjob(struct fc_bsg_job *job) +{ + unsigned long flags; + + spin_lock_irqsave(&job->job_lock, flags); + if (job->ref_cnt) { + spin_unlock_irqrestore(&job->job_lock, flags); + return; + } + spin_unlock_irqrestore(&job->job_lock, flags); + + put_device(job->dev); /* release reference for the request */ + + kfree(job->request_payload.sg_list); + kfree(job->reply_payload.sg_list); + kfree(job); +} + +/** + * fc_bsg_jobdone - completion routine for bsg requests that the LLD has + * completed + * @job: fc_bsg_job that is complete + */ +static void +fc_bsg_jobdone(struct fc_bsg_job *job) +{ + struct request *req = job->req; + struct request *rsp = req->next_rq; + int err; + + err = job->req->errors = job->reply->result; + + if (err < 0) + /* we're only returning the result field in the reply */ + job->req->sense_len = sizeof(uint32_t); + else + job->req->sense_len = job->reply_len; + + /* we assume all request payload was transferred, residual == 0 */ + req->resid_len = 0; + + if (rsp) { + WARN_ON(job->reply->reply_payload_rcv_len > rsp->resid_len); + + /* set reply (bidi) residual */ + rsp->resid_len -= min(job->reply->reply_payload_rcv_len, + rsp->resid_len); + } + blk_complete_request(req); +} + +/** + * fc_bsg_softirq_done - softirq done routine for destroying the bsg requests + * @req: BSG request that holds the job to be destroyed + */ +static void fc_bsg_softirq_done(struct request *rq) +{ + struct fc_bsg_job *job = rq->special; + unsigned long flags; + + spin_lock_irqsave(&job->job_lock, flags); + job->state_flags |= FC_RQST_STATE_DONE; + job->ref_cnt--; + spin_unlock_irqrestore(&job->job_lock, flags); + + blk_end_request_all(rq, rq->errors); + fc_destroy_bsgjob(job); +} + +/** + * fc_bsg_job_timeout - handler for when a bsg request timesout + * @req: request that timed out + */ +static enum blk_eh_timer_return +fc_bsg_job_timeout(struct request *req) +{ + struct fc_bsg_job *job = (void *) req->special; + struct Scsi_Host *shost = job->shost; + struct fc_internal *i = to_fc_internal(shost->transportt); + unsigned long flags; + int err = 0, done = 0; + + if (job->rport && job->rport->port_state == FC_PORTSTATE_BLOCKED) + return BLK_EH_RESET_TIMER; + + spin_lock_irqsave(&job->job_lock, flags); + if (job->state_flags & FC_RQST_STATE_DONE) + done = 1; + else + job->ref_cnt++; + spin_unlock_irqrestore(&job->job_lock, flags); + + if (!done && i->f->bsg_timeout) { + /* call LLDD to abort the i/o as it has timed out */ + err = i->f->bsg_timeout(job); + if (err) + printk(KERN_ERR "ERROR: FC BSG request timeout - LLD " + "abort failed with status %d\n", err); + } + + /* the blk_end_sync_io() doesn't check the error */ + if (done) + return BLK_EH_NOT_HANDLED; + else + return BLK_EH_HANDLED; +} + +static int +fc_bsg_map_buffer(struct fc_bsg_buffer *buf, struct request *req) +{ + size_t sz = (sizeof(struct scatterlist) * req->nr_phys_segments); + + BUG_ON(!req->nr_phys_segments); + + buf->sg_list = kzalloc(sz, GFP_KERNEL); + if (!buf->sg_list) + return -ENOMEM; + sg_init_table(buf->sg_list, req->nr_phys_segments); + buf->sg_cnt = blk_rq_map_sg(req->q, req, buf->sg_list); + buf->payload_len = blk_rq_bytes(req); + return 0; +} + + +/** + * fc_req_to_bsgjob - Allocate/create the fc_bsg_job structure for the + * bsg request + * @shost: SCSI Host corresponding to the bsg object + * @rport: (optional) FC Remote Port corresponding to the bsg object + * @req: BSG request that needs a job structure + */ +static int +fc_req_to_bsgjob(struct Scsi_Host *shost, struct fc_rport *rport, + struct request *req) +{ + struct fc_internal *i = to_fc_internal(shost->transportt); + struct request *rsp = req->next_rq; + struct fc_bsg_job *job; + int ret; + + BUG_ON(req->special); + + job = kzalloc(sizeof(struct fc_bsg_job) + i->f->dd_bsg_size, + GFP_KERNEL); + if (!job) + return -ENOMEM; + + /* + * Note: this is a bit silly. + * The request gets formatted as a SGIO v4 ioctl request, which + * then gets reformatted as a blk request, which then gets + * reformatted as a fc bsg request. And on completion, we have + * to wrap return results such that SGIO v4 thinks it was a scsi + * status. I hope this was all worth it. + */ + + req->special = job; + job->shost = shost; + job->rport = rport; + job->req = req; + if (i->f->dd_bsg_size) + job->dd_data = (void *)&job[1]; + spin_lock_init(&job->job_lock); + job->request = (struct fc_bsg_request *)req->cmd; + job->request_len = req->cmd_len; + job->reply = req->sense; + job->reply_len = SCSI_SENSE_BUFFERSIZE; /* Size of sense buffer + * allocated */ + if (req->bio) { + ret = fc_bsg_map_buffer(&job->request_payload, req); + if (ret) + goto failjob_rls_job; + } + if (rsp && rsp->bio) { + ret = fc_bsg_map_buffer(&job->reply_payload, rsp); + if (ret) + goto failjob_rls_rqst_payload; + } + job->job_done = fc_bsg_jobdone; + if (rport) + job->dev = &rport->dev; + else + job->dev = &shost->shost_gendev; + get_device(job->dev); /* take a reference for the request */ + + job->ref_cnt = 1; + + return 0; + + +failjob_rls_rqst_payload: + kfree(job->request_payload.sg_list); +failjob_rls_job: + kfree(job); + return -ENOMEM; +} + + +enum fc_dispatch_result { + FC_DISPATCH_BREAK, /* on return, q is locked, break from q loop */ + FC_DISPATCH_LOCKED, /* on return, q is locked, continue on */ + FC_DISPATCH_UNLOCKED, /* on return, q is unlocked, continue on */ +}; + + +/** + * fc_bsg_host_dispatch - process fc host bsg requests and dispatch to LLDD + * @shost: scsi host rport attached to + * @job: bsg job to be processed + */ +static enum fc_dispatch_result +fc_bsg_host_dispatch(struct request_queue *q, struct Scsi_Host *shost, + struct fc_bsg_job *job) +{ + struct fc_internal *i = to_fc_internal(shost->transportt); + int cmdlen = sizeof(uint32_t); /* start with length of msgcode */ + int ret; + + /* Validate the host command */ + switch (job->request->msgcode) { + case FC_BSG_HST_ADD_RPORT: + cmdlen += sizeof(struct fc_bsg_host_add_rport); + break; + + case FC_BSG_HST_DEL_RPORT: + cmdlen += sizeof(struct fc_bsg_host_del_rport); + break; + + case FC_BSG_HST_ELS_NOLOGIN: + cmdlen += sizeof(struct fc_bsg_host_els); + /* there better be a xmt and rcv payloads */ + if ((!job->request_payload.payload_len) || + (!job->reply_payload.payload_len)) { + ret = -EINVAL; + goto fail_host_msg; + } + break; + + case FC_BSG_HST_CT: + cmdlen += sizeof(struct fc_bsg_host_ct); + /* there better be xmt and rcv payloads */ + if ((!job->request_payload.payload_len) || + (!job->reply_payload.payload_len)) { + ret = -EINVAL; + goto fail_host_msg; + } + break; + + case FC_BSG_HST_VENDOR: + cmdlen += sizeof(struct fc_bsg_host_vendor); + if ((shost->hostt->vendor_id == 0L) || + (job->request->rqst_data.h_vendor.vendor_id != + shost->hostt->vendor_id)) { + ret = -ESRCH; + goto fail_host_msg; + } + break; + + default: + ret = -EBADR; + goto fail_host_msg; + } + + /* check if we really have all the request data needed */ + if (job->request_len < cmdlen) { + ret = -ENOMSG; + goto fail_host_msg; + } + + ret = i->f->bsg_request(job); + if (!ret) + return FC_DISPATCH_UNLOCKED; + +fail_host_msg: + /* return the errno failure code as the only status */ + BUG_ON(job->reply_len < sizeof(uint32_t)); + job->reply->result = ret; + job->reply_len = sizeof(uint32_t); + fc_bsg_jobdone(job); + return FC_DISPATCH_UNLOCKED; +} + + +/* + * fc_bsg_goose_queue - restart rport queue in case it was stopped + * @rport: rport to be restarted + */ +static void +fc_bsg_goose_queue(struct fc_rport *rport) +{ + int flagset; + + if (!rport->rqst_q) + return; + + get_device(&rport->dev); + + spin_lock(rport->rqst_q->queue_lock); + flagset = test_bit(QUEUE_FLAG_REENTER, &rport->rqst_q->queue_flags) && + !test_bit(QUEUE_FLAG_REENTER, &rport->rqst_q->queue_flags); + if (flagset) + queue_flag_set(QUEUE_FLAG_REENTER, rport->rqst_q); + __blk_run_queue(rport->rqst_q); + if (flagset) + queue_flag_clear(QUEUE_FLAG_REENTER, rport->rqst_q); + spin_unlock(rport->rqst_q->queue_lock); + + put_device(&rport->dev); +} + + +/** + * fc_bsg_rport_dispatch - process rport bsg requests and dispatch to LLDD + * @shost: scsi host rport attached to + * @rport: rport request destined to + * @job: bsg job to be processed + */ +static enum fc_dispatch_result +fc_bsg_rport_dispatch(struct request_queue *q, struct Scsi_Host *shost, + struct fc_rport *rport, struct fc_bsg_job *job) +{ + struct fc_internal *i = to_fc_internal(shost->transportt); + int cmdlen = sizeof(uint32_t); /* start with length of msgcode */ + int ret; + + /* Validate the rport command */ + switch (job->request->msgcode) { + case FC_BSG_RPT_ELS: + cmdlen += sizeof(struct fc_bsg_rport_els); + goto check_bidi; + + case FC_BSG_RPT_CT: + cmdlen += sizeof(struct fc_bsg_rport_ct); +check_bidi: + /* there better be xmt and rcv payloads */ + if ((!job->request_payload.payload_len) || + (!job->reply_payload.payload_len)) { + ret = -EINVAL; + goto fail_rport_msg; + } + break; + default: + ret = -EBADR; + goto fail_rport_msg; + } + + /* check if we really have all the request data needed */ + if (job->request_len < cmdlen) { + ret = -ENOMSG; + goto fail_rport_msg; + } + + ret = i->f->bsg_request(job); + if (!ret) + return FC_DISPATCH_UNLOCKED; + +fail_rport_msg: + /* return the errno failure code as the only status */ + BUG_ON(job->reply_len < sizeof(uint32_t)); + job->reply->result = ret; + job->reply_len = sizeof(uint32_t); + fc_bsg_jobdone(job); + return FC_DISPATCH_UNLOCKED; +} + + +/** + * fc_bsg_request_handler - generic handler for bsg requests + * @q: request queue to manage + * @shost: Scsi_Host related to the bsg object + * @rport: FC remote port related to the bsg object (optional) + * @dev: device structure for bsg object + */ +static void +fc_bsg_request_handler(struct request_queue *q, struct Scsi_Host *shost, + struct fc_rport *rport, struct device *dev) +{ + struct request *req; + struct fc_bsg_job *job; + enum fc_dispatch_result ret; + + if (!get_device(dev)) + return; + + while (!blk_queue_plugged(q)) { + if (rport && (rport->port_state == FC_PORTSTATE_BLOCKED)) + break; + + req = blk_fetch_request(q); + if (!req) + break; + + if (rport && (rport->port_state != FC_PORTSTATE_ONLINE)) { + req->errors = -ENXIO; + spin_unlock_irq(q->queue_lock); + blk_end_request(req, -ENXIO, blk_rq_bytes(req)); + spin_lock_irq(q->queue_lock); + continue; + } + + spin_unlock_irq(q->queue_lock); + + ret = fc_req_to_bsgjob(shost, rport, req); + if (ret) { + req->errors = ret; + blk_end_request(req, ret, blk_rq_bytes(req)); + spin_lock_irq(q->queue_lock); + continue; + } + + job = req->special; + + /* check if we have the msgcode value at least */ + if (job->request_len < sizeof(uint32_t)) { + BUG_ON(job->reply_len < sizeof(uint32_t)); + job->reply->result = -ENOMSG; + job->reply_len = sizeof(uint32_t); + fc_bsg_jobdone(job); + spin_lock_irq(q->queue_lock); + continue; + } + + /* the dispatch routines will unlock the queue_lock */ + if (rport) + ret = fc_bsg_rport_dispatch(q, shost, rport, job); + else + ret = fc_bsg_host_dispatch(q, shost, job); + + /* did dispatcher hit state that can't process any more */ + if (ret == FC_DISPATCH_BREAK) + break; + + /* did dispatcher had released the lock */ + if (ret == FC_DISPATCH_UNLOCKED) + spin_lock_irq(q->queue_lock); + } + + spin_unlock_irq(q->queue_lock); + put_device(dev); + spin_lock_irq(q->queue_lock); +} + + +/** + * fc_bsg_host_handler - handler for bsg requests for a fc host + * @q: fc host request queue + */ +static void +fc_bsg_host_handler(struct request_queue *q) +{ + struct Scsi_Host *shost = q->queuedata; + + fc_bsg_request_handler(q, shost, NULL, &shost->shost_gendev); +} + + +/** + * fc_bsg_rport_handler - handler for bsg requests for a fc rport + * @q: rport request queue + */ +static void +fc_bsg_rport_handler(struct request_queue *q) +{ + struct fc_rport *rport = q->queuedata; + struct Scsi_Host *shost = rport_to_shost(rport); + + fc_bsg_request_handler(q, shost, rport, &rport->dev); +} + + +/** + * fc_bsg_hostadd - Create and add the bsg hooks so we can receive requests + * @shost: shost for fc_host + * @fc_host: fc_host adding the structures to + */ +static int +fc_bsg_hostadd(struct Scsi_Host *shost, struct fc_host_attrs *fc_host) +{ + struct device *dev = &shost->shost_gendev; + struct fc_internal *i = to_fc_internal(shost->transportt); + struct request_queue *q; + int err; + char bsg_name[20]; + + fc_host->rqst_q = NULL; + + if (!i->f->bsg_request) + return -ENOTSUPP; + + snprintf(bsg_name, sizeof(bsg_name), + "fc_host%d", shost->host_no); + + q = __scsi_alloc_queue(shost, fc_bsg_host_handler); + if (!q) { + printk(KERN_ERR "fc_host%d: bsg interface failed to " + "initialize - no request queue\n", + shost->host_no); + return -ENOMEM; + } + + q->queuedata = shost; + queue_flag_set_unlocked(QUEUE_FLAG_BIDI, q); + blk_queue_softirq_done(q, fc_bsg_softirq_done); + blk_queue_rq_timed_out(q, fc_bsg_job_timeout); + blk_queue_rq_timeout(q, FC_DEFAULT_BSG_TIMEOUT); + + err = bsg_register_queue(q, dev, bsg_name, NULL); + if (err) { + printk(KERN_ERR "fc_host%d: bsg interface failed to " + "initialize - register queue\n", + shost->host_no); + blk_cleanup_queue(q); + return err; + } + + fc_host->rqst_q = q; + return 0; +} + + +/** + * fc_bsg_rportadd - Create and add the bsg hooks so we can receive requests + * @shost: shost that rport is attached to + * @rport: rport that the bsg hooks are being attached to + */ +static int +fc_bsg_rportadd(struct Scsi_Host *shost, struct fc_rport *rport) +{ + struct device *dev = &rport->dev; + struct fc_internal *i = to_fc_internal(shost->transportt); + struct request_queue *q; + int err; + + rport->rqst_q = NULL; + + if (!i->f->bsg_request) + return -ENOTSUPP; + + q = __scsi_alloc_queue(shost, fc_bsg_rport_handler); + if (!q) { + printk(KERN_ERR "%s: bsg interface failed to " + "initialize - no request queue\n", + dev->kobj.name); + return -ENOMEM; + } + + q->queuedata = rport; + queue_flag_set_unlocked(QUEUE_FLAG_BIDI, q); + blk_queue_softirq_done(q, fc_bsg_softirq_done); + blk_queue_rq_timed_out(q, fc_bsg_job_timeout); + blk_queue_rq_timeout(q, BLK_DEFAULT_SG_TIMEOUT); + + err = bsg_register_queue(q, dev, NULL, NULL); + if (err) { + printk(KERN_ERR "%s: bsg interface failed to " + "initialize - register queue\n", + dev->kobj.name); + blk_cleanup_queue(q); + return err; + } + + rport->rqst_q = q; + return 0; +} + + +/** + * fc_bsg_remove - Deletes the bsg hooks on fchosts/rports + * @q: the request_queue that is to be torn down. + */ +static void +fc_bsg_remove(struct request_queue *q) +{ + if (q) { + bsg_unregister_queue(q); + blk_cleanup_queue(q); + } +} + + /* Original Author: Martin Hicks */ MODULE_AUTHOR("James Smart"); MODULE_DESCRIPTION("FC Transport Attributes"); diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 0a2ce7b6325c..783e33c65eb7 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -37,7 +37,6 @@ #define ISCSI_TRANSPORT_VERSION "2.0-870" struct iscsi_internal { - int daemon_pid; struct scsi_transport_template t; struct iscsi_transport *iscsi_transport; struct list_head list; @@ -693,6 +692,7 @@ int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id) "Too many iscsi targets. Max " "number of targets is %d.\n", ISCSI_MAX_TARGET - 1); + err = -EOVERFLOW; goto release_host; } } @@ -938,23 +938,9 @@ iscsi_if_transport_lookup(struct iscsi_transport *tt) } static int -iscsi_broadcast_skb(struct sk_buff *skb, gfp_t gfp) +iscsi_multicast_skb(struct sk_buff *skb, uint32_t group, gfp_t gfp) { - return netlink_broadcast(nls, skb, 0, 1, gfp); -} - -static int -iscsi_unicast_skb(struct sk_buff *skb, int pid) -{ - int rc; - - rc = netlink_unicast(nls, skb, pid, MSG_DONTWAIT); - if (rc < 0) { - printk(KERN_ERR "iscsi: can not unicast skb (%d)\n", rc); - return rc; - } - - return 0; + return nlmsg_multicast(nls, skb, 0, group, gfp); } int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr, @@ -980,7 +966,7 @@ int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr, return -ENOMEM; } - nlh = __nlmsg_put(skb, priv->daemon_pid, 0, 0, (len - sizeof(*nlh)), 0); + nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0); ev = NLMSG_DATA(nlh); memset(ev, 0, sizeof(*ev)); ev->transport_handle = iscsi_handle(conn->transport); @@ -991,10 +977,45 @@ int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr, memcpy(pdu, hdr, sizeof(struct iscsi_hdr)); memcpy(pdu + sizeof(struct iscsi_hdr), data, data_size); - return iscsi_unicast_skb(skb, priv->daemon_pid); + return iscsi_multicast_skb(skb, ISCSI_NL_GRP_ISCSID, GFP_ATOMIC); } EXPORT_SYMBOL_GPL(iscsi_recv_pdu); +int iscsi_offload_mesg(struct Scsi_Host *shost, + struct iscsi_transport *transport, uint32_t type, + char *data, uint16_t data_size) +{ + struct nlmsghdr *nlh; + struct sk_buff *skb; + struct iscsi_uevent *ev; + int len = NLMSG_SPACE(sizeof(*ev) + data_size); + + skb = alloc_skb(len, GFP_NOIO); + if (!skb) { + printk(KERN_ERR "can not deliver iscsi offload message:OOM\n"); + return -ENOMEM; + } + + nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0); + ev = NLMSG_DATA(nlh); + memset(ev, 0, sizeof(*ev)); + ev->type = type; + ev->transport_handle = iscsi_handle(transport); + switch (type) { + case ISCSI_KEVENT_PATH_REQ: + ev->r.req_path.host_no = shost->host_no; + break; + case ISCSI_KEVENT_IF_DOWN: + ev->r.notify_if_down.host_no = shost->host_no; + break; + } + + memcpy((char *)ev + sizeof(*ev), data, data_size); + + return iscsi_multicast_skb(skb, ISCSI_NL_GRP_UIP, GFP_NOIO); +} +EXPORT_SYMBOL_GPL(iscsi_offload_mesg); + void iscsi_conn_error_event(struct iscsi_cls_conn *conn, enum iscsi_err error) { struct nlmsghdr *nlh; @@ -1014,7 +1035,7 @@ void iscsi_conn_error_event(struct iscsi_cls_conn *conn, enum iscsi_err error) return; } - nlh = __nlmsg_put(skb, priv->daemon_pid, 0, 0, (len - sizeof(*nlh)), 0); + nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0); ev = NLMSG_DATA(nlh); ev->transport_handle = iscsi_handle(conn->transport); ev->type = ISCSI_KEVENT_CONN_ERROR; @@ -1022,7 +1043,7 @@ void iscsi_conn_error_event(struct iscsi_cls_conn *conn, enum iscsi_err error) ev->r.connerror.cid = conn->cid; ev->r.connerror.sid = iscsi_conn_get_sid(conn); - iscsi_broadcast_skb(skb, GFP_ATOMIC); + iscsi_multicast_skb(skb, ISCSI_NL_GRP_ISCSID, GFP_ATOMIC); iscsi_cls_conn_printk(KERN_INFO, conn, "detected conn error (%d)\n", error); @@ -1030,8 +1051,8 @@ void iscsi_conn_error_event(struct iscsi_cls_conn *conn, enum iscsi_err error) EXPORT_SYMBOL_GPL(iscsi_conn_error_event); static int -iscsi_if_send_reply(int pid, int seq, int type, int done, int multi, - void *payload, int size) +iscsi_if_send_reply(uint32_t group, int seq, int type, int done, int multi, + void *payload, int size) { struct sk_buff *skb; struct nlmsghdr *nlh; @@ -1045,10 +1066,10 @@ iscsi_if_send_reply(int pid, int seq, int type, int done, int multi, return -ENOMEM; } - nlh = __nlmsg_put(skb, pid, seq, t, (len - sizeof(*nlh)), 0); + nlh = __nlmsg_put(skb, 0, 0, t, (len - sizeof(*nlh)), 0); nlh->nlmsg_flags = flags; memcpy(NLMSG_DATA(nlh), payload, size); - return iscsi_unicast_skb(skb, pid); + return iscsi_multicast_skb(skb, group, GFP_ATOMIC); } static int @@ -1085,7 +1106,7 @@ iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh) return -ENOMEM; } - nlhstat = __nlmsg_put(skbstat, priv->daemon_pid, 0, 0, + nlhstat = __nlmsg_put(skbstat, 0, 0, 0, (len - sizeof(*nlhstat)), 0); evstat = NLMSG_DATA(nlhstat); memset(evstat, 0, sizeof(*evstat)); @@ -1109,7 +1130,8 @@ iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh) skb_trim(skbstat, NLMSG_ALIGN(actual_size)); nlhstat->nlmsg_len = actual_size; - err = iscsi_unicast_skb(skbstat, priv->daemon_pid); + err = iscsi_multicast_skb(skbstat, ISCSI_NL_GRP_ISCSID, + GFP_ATOMIC); } while (err < 0 && err != -ECONNREFUSED); return err; @@ -1143,7 +1165,7 @@ int iscsi_session_event(struct iscsi_cls_session *session, return -ENOMEM; } - nlh = __nlmsg_put(skb, priv->daemon_pid, 0, 0, (len - sizeof(*nlh)), 0); + nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0); ev = NLMSG_DATA(nlh); ev->transport_handle = iscsi_handle(session->transport); @@ -1172,7 +1194,7 @@ int iscsi_session_event(struct iscsi_cls_session *session, * this will occur if the daemon is not up, so we just warn * the user and when the daemon is restarted it will handle it */ - rc = iscsi_broadcast_skb(skb, GFP_KERNEL); + rc = iscsi_multicast_skb(skb, ISCSI_NL_GRP_ISCSID, GFP_KERNEL); if (rc == -ESRCH) iscsi_cls_session_printk(KERN_ERR, session, "Cannot notify userspace of session " @@ -1268,26 +1290,54 @@ iscsi_set_param(struct iscsi_transport *transport, struct iscsi_uevent *ev) return err; } +static int iscsi_if_ep_connect(struct iscsi_transport *transport, + struct iscsi_uevent *ev, int msg_type) +{ + struct iscsi_endpoint *ep; + struct sockaddr *dst_addr; + struct Scsi_Host *shost = NULL; + int non_blocking, err = 0; + + if (!transport->ep_connect) + return -EINVAL; + + if (msg_type == ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST) { + shost = scsi_host_lookup(ev->u.ep_connect_through_host.host_no); + if (!shost) { + printk(KERN_ERR "ep connect failed. Could not find " + "host no %u\n", + ev->u.ep_connect_through_host.host_no); + return -ENODEV; + } + non_blocking = ev->u.ep_connect_through_host.non_blocking; + } else + non_blocking = ev->u.ep_connect.non_blocking; + + dst_addr = (struct sockaddr *)((char*)ev + sizeof(*ev)); + ep = transport->ep_connect(shost, dst_addr, non_blocking); + if (IS_ERR(ep)) { + err = PTR_ERR(ep); + goto release_host; + } + + ev->r.ep_connect_ret.handle = ep->id; +release_host: + if (shost) + scsi_host_put(shost); + return err; +} + static int iscsi_if_transport_ep(struct iscsi_transport *transport, struct iscsi_uevent *ev, int msg_type) { struct iscsi_endpoint *ep; - struct sockaddr *dst_addr; int rc = 0; switch (msg_type) { + case ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST: case ISCSI_UEVENT_TRANSPORT_EP_CONNECT: - if (!transport->ep_connect) - return -EINVAL; - - dst_addr = (struct sockaddr *)((char*)ev + sizeof(*ev)); - ep = transport->ep_connect(dst_addr, - ev->u.ep_connect.non_blocking); - if (IS_ERR(ep)) - return PTR_ERR(ep); - - ev->r.ep_connect_ret.handle = ep->id; + rc = iscsi_if_ep_connect(transport, ev, msg_type); break; case ISCSI_UEVENT_TRANSPORT_EP_POLL: if (!transport->ep_poll) @@ -1365,7 +1415,31 @@ iscsi_set_host_param(struct iscsi_transport *transport, } static int -iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) +iscsi_set_path(struct iscsi_transport *transport, struct iscsi_uevent *ev) +{ + struct Scsi_Host *shost; + struct iscsi_path *params; + int err; + + if (!transport->set_path) + return -ENOSYS; + + shost = scsi_host_lookup(ev->u.set_path.host_no); + if (!shost) { + printk(KERN_ERR "set path could not find host no %u\n", + ev->u.set_path.host_no); + return -ENODEV; + } + + params = (struct iscsi_path *)((char *)ev + sizeof(*ev)); + err = transport->set_path(shost, params); + + scsi_host_put(shost); + return err; +} + +static int +iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group) { int err = 0; struct iscsi_uevent *ev = NLMSG_DATA(nlh); @@ -1375,6 +1449,11 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) struct iscsi_cls_conn *conn; struct iscsi_endpoint *ep = NULL; + if (nlh->nlmsg_type == ISCSI_UEVENT_PATH_UPDATE) + *group = ISCSI_NL_GRP_UIP; + else + *group = ISCSI_NL_GRP_ISCSID; + priv = iscsi_if_transport_lookup(iscsi_ptr(ev->transport_handle)); if (!priv) return -EINVAL; @@ -1383,8 +1462,6 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) if (!try_module_get(transport->owner)) return -EINVAL; - priv->daemon_pid = NETLINK_CREDS(skb)->pid; - switch (nlh->nlmsg_type) { case ISCSI_UEVENT_CREATE_SESSION: err = iscsi_if_create_session(priv, ep, ev, @@ -1469,6 +1546,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) case ISCSI_UEVENT_TRANSPORT_EP_CONNECT: case ISCSI_UEVENT_TRANSPORT_EP_POLL: case ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT: + case ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST: err = iscsi_if_transport_ep(transport, ev, nlh->nlmsg_type); break; case ISCSI_UEVENT_TGT_DSCVR: @@ -1477,6 +1555,9 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) case ISCSI_UEVENT_SET_HOST_PARAM: err = iscsi_set_host_param(transport, ev); break; + case ISCSI_UEVENT_PATH_UPDATE: + err = iscsi_set_path(transport, ev); + break; default: err = -ENOSYS; break; @@ -1499,6 +1580,7 @@ iscsi_if_rx(struct sk_buff *skb) uint32_t rlen; struct nlmsghdr *nlh; struct iscsi_uevent *ev; + uint32_t group; nlh = nlmsg_hdr(skb); if (nlh->nlmsg_len < sizeof(*nlh) || @@ -1511,7 +1593,7 @@ iscsi_if_rx(struct sk_buff *skb) if (rlen > skb->len) rlen = skb->len; - err = iscsi_if_recv_msg(skb, nlh); + err = iscsi_if_recv_msg(skb, nlh, &group); if (err) { ev->type = ISCSI_KEVENT_IF_ERROR; ev->iferror = err; @@ -1525,8 +1607,7 @@ iscsi_if_rx(struct sk_buff *skb) */ if (ev->type == ISCSI_UEVENT_GET_STATS && !err) break; - err = iscsi_if_send_reply( - NETLINK_CREDS(skb)->pid, nlh->nlmsg_seq, + err = iscsi_if_send_reply(group, nlh->nlmsg_seq, nlh->nlmsg_type, 0, 0, ev, sizeof(*ev)); } while (err < 0 && err != -ECONNREFUSED); skb_pull(skb, rlen); @@ -1774,7 +1855,6 @@ iscsi_register_transport(struct iscsi_transport *tt) if (!priv) return NULL; INIT_LIST_HEAD(&priv->list); - priv->daemon_pid = -1; priv->iscsi_transport = tt; priv->t.user_scan = iscsi_user_scan; priv->t.create_work_queue = 1; diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c index 50988cbf7b2d..0895d3c71b03 100644 --- a/drivers/scsi/scsi_transport_sas.c +++ b/drivers/scsi/scsi_transport_sas.c @@ -163,21 +163,19 @@ static void sas_smp_request(struct request_queue *q, struct Scsi_Host *shost, int (*handler)(struct Scsi_Host *, struct sas_rphy *, struct request *); while (!blk_queue_plugged(q)) { - req = elv_next_request(q); + req = blk_fetch_request(q); if (!req) break; - blkdev_dequeue_request(req); - spin_unlock_irq(q->queue_lock); handler = to_sas_internal(shost->transportt)->f->smp_handler; ret = handler(shost, rphy, req); req->errors = ret; - spin_lock_irq(q->queue_lock); + blk_end_request_all(req, ret); - req->end_io(req, ret); + spin_lock_irq(q->queue_lock); } } diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c index f49f55c6bfc8..c25bd9a34e02 100644 --- a/drivers/scsi/scsi_transport_spi.c +++ b/drivers/scsi/scsi_transport_spi.c @@ -46,6 +46,22 @@ #define DV_RETRIES 3 /* should only need at most * two cc/ua clears */ +/* Our blacklist flags */ +enum { + SPI_BLIST_NOIUS = 0x1, +}; + +/* blacklist table, modelled on scsi_devinfo.c */ +static struct { + char *vendor; + char *model; + unsigned flags; +} spi_static_device_list[] __initdata = { + {"HP", "Ultrium 3-SCSI", SPI_BLIST_NOIUS }, + {"IBM", "ULTRIUM-TD3", SPI_BLIST_NOIUS }, + {NULL, NULL, 0} +}; + /* Private data accessors (keep these out of the header file) */ #define spi_dv_in_progress(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_in_progress) #define spi_dv_mutex(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_mutex) @@ -207,6 +223,9 @@ static int spi_device_configure(struct transport_container *tc, { struct scsi_device *sdev = to_scsi_device(dev); struct scsi_target *starget = sdev->sdev_target; + unsigned bflags = scsi_get_device_flags_keyed(sdev, &sdev->inquiry[8], + &sdev->inquiry[16], + SCSI_DEVINFO_SPI); /* Populate the target capability fields with the values * gleaned from the device inquiry */ @@ -216,6 +235,10 @@ static int spi_device_configure(struct transport_container *tc, spi_support_dt(starget) = scsi_device_dt(sdev); spi_support_dt_only(starget) = scsi_device_dt_only(sdev); spi_support_ius(starget) = scsi_device_ius(sdev); + if (bflags & SPI_BLIST_NOIUS) { + dev_info(dev, "Information Units disabled by blacklist\n"); + spi_support_ius(starget) = 0; + } spi_support_qas(starget) = scsi_device_qas(sdev); return 0; @@ -234,8 +257,10 @@ static int spi_setup_transport_attrs(struct transport_container *tc, spi_width(starget) = 0; /* narrow */ spi_max_width(starget) = 1; spi_iu(starget) = 0; /* no IU */ + spi_max_iu(starget) = 1; spi_dt(starget) = 0; /* ST */ spi_qas(starget) = 0; + spi_max_qas(starget) = 1; spi_wr_flow(starget) = 0; spi_rd_strm(starget) = 0; spi_rti(starget) = 0; @@ -360,9 +385,9 @@ static DEVICE_ATTR(field, S_IRUGO, \ /* The Parallel SCSI Tranport Attributes: */ spi_transport_max_attr(offset, "%d\n"); spi_transport_max_attr(width, "%d\n"); -spi_transport_rd_attr(iu, "%d\n"); +spi_transport_max_attr(iu, "%d\n"); spi_transport_rd_attr(dt, "%d\n"); -spi_transport_rd_attr(qas, "%d\n"); +spi_transport_max_attr(qas, "%d\n"); spi_transport_rd_attr(wr_flow, "%d\n"); spi_transport_rd_attr(rd_strm, "%d\n"); spi_transport_rd_attr(rti, "%d\n"); @@ -831,7 +856,7 @@ spi_dv_device_internal(struct scsi_device *sdev, u8 *buffer) return; } - if (!scsi_device_wide(sdev)) { + if (!spi_support_wide(starget)) { spi_max_width(starget) = 0; max_width = 0; } @@ -858,7 +883,7 @@ spi_dv_device_internal(struct scsi_device *sdev, u8 *buffer) return; /* device can't handle synchronous */ - if (!scsi_device_sync(sdev) && !scsi_device_dt(sdev)) + if (!spi_support_sync(starget) && !spi_support_dt(starget)) return; /* len == -1 is the signal that we need to ascertain the @@ -874,13 +899,14 @@ spi_dv_device_internal(struct scsi_device *sdev, u8 *buffer) /* try QAS requests; this should be harmless to set if the * target supports it */ - if (scsi_device_qas(sdev)) { + if (spi_support_qas(starget) && spi_max_qas(starget)) { DV_SET(qas, 1); } else { DV_SET(qas, 0); } - if (scsi_device_ius(sdev) && min_period < 9) { + if (spi_support_ius(starget) && spi_max_iu(starget) && + min_period < 9) { /* This u320 (or u640). Set IU transfers */ DV_SET(iu, 1); /* Then set the optional parameters */ @@ -900,7 +926,7 @@ spi_dv_device_internal(struct scsi_device *sdev, u8 *buffer) i->f->get_signalling(shost); if (spi_signalling(shost) == SPI_SIGNAL_SE || spi_signalling(shost) == SPI_SIGNAL_HVD || - !scsi_device_dt(sdev)) { + !spi_support_dt(starget)) { DV_SET(dt, 0); } else { DV_SET(dt, 1); @@ -1412,12 +1438,18 @@ static mode_t target_attribute_is_visible(struct kobject *kobj, else if (attr == &dev_attr_iu.attr && spi_support_ius(starget)) return TARGET_ATTRIBUTE_HELPER(iu); + else if (attr == &dev_attr_max_iu.attr && + spi_support_ius(starget)) + return TARGET_ATTRIBUTE_HELPER(iu); else if (attr == &dev_attr_dt.attr && spi_support_dt(starget)) return TARGET_ATTRIBUTE_HELPER(dt); else if (attr == &dev_attr_qas.attr && spi_support_qas(starget)) return TARGET_ATTRIBUTE_HELPER(qas); + else if (attr == &dev_attr_max_qas.attr && + spi_support_qas(starget)) + return TARGET_ATTRIBUTE_HELPER(qas); else if (attr == &dev_attr_wr_flow.attr && spi_support_ius(starget)) return TARGET_ATTRIBUTE_HELPER(wr_flow); @@ -1447,8 +1479,10 @@ static struct attribute *target_attributes[] = { &dev_attr_width.attr, &dev_attr_max_width.attr, &dev_attr_iu.attr, + &dev_attr_max_iu.attr, &dev_attr_dt.attr, &dev_attr_qas.attr, + &dev_attr_max_qas.attr, &dev_attr_wr_flow.attr, &dev_attr_rd_strm.attr, &dev_attr_rti.attr, @@ -1513,7 +1547,21 @@ EXPORT_SYMBOL(spi_release_transport); static __init int spi_transport_init(void) { - int error = transport_class_register(&spi_transport_class); + int error = scsi_dev_info_add_list(SCSI_DEVINFO_SPI, + "SCSI Parallel Transport Class"); + if (!error) { + int i; + + for (i = 0; spi_static_device_list[i].vendor; i++) + scsi_dev_info_list_add_keyed(1, /* compatible */ + spi_static_device_list[i].vendor, + spi_static_device_list[i].model, + NULL, + spi_static_device_list[i].flags, + SCSI_DEVINFO_SPI); + } + + error = transport_class_register(&spi_transport_class); if (error) return error; error = anon_transport_class_register(&spi_device_class); @@ -1525,6 +1573,7 @@ static void __exit spi_transport_exit(void) transport_class_unregister(&spi_transport_class); anon_transport_class_unregister(&spi_device_class); transport_class_unregister(&spi_host_class); + scsi_dev_info_remove_list(SCSI_DEVINFO_SPI); } MODULE_AUTHOR("Martin Hicks"); diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 84044233b637..5616cd780ff3 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -384,9 +384,9 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq) struct scsi_device *sdp = q->queuedata; struct gendisk *disk = rq->rq_disk; struct scsi_disk *sdkp; - sector_t block = rq->sector; + sector_t block = blk_rq_pos(rq); sector_t threshold; - unsigned int this_count = rq->nr_sectors; + unsigned int this_count = blk_rq_sectors(rq); int ret, host_dif; if (rq->cmd_type == REQ_TYPE_BLOCK_PC) { @@ -413,10 +413,10 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq) this_count)); if (!sdp || !scsi_device_online(sdp) || - block + rq->nr_sectors > get_capacity(disk)) { + block + blk_rq_sectors(rq) > get_capacity(disk)) { SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt, - "Finishing %ld sectors\n", - rq->nr_sectors)); + "Finishing %u sectors\n", + blk_rq_sectors(rq))); SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt, "Retry with 0x%p\n", SCpnt)); goto out; @@ -463,7 +463,7 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq) * for this. */ if (sdp->sector_size == 1024) { - if ((block & 1) || (rq->nr_sectors & 1)) { + if ((block & 1) || (blk_rq_sectors(rq) & 1)) { scmd_printk(KERN_ERR, SCpnt, "Bad block number requested\n"); goto out; @@ -473,7 +473,7 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq) } } if (sdp->sector_size == 2048) { - if ((block & 3) || (rq->nr_sectors & 3)) { + if ((block & 3) || (blk_rq_sectors(rq) & 3)) { scmd_printk(KERN_ERR, SCpnt, "Bad block number requested\n"); goto out; @@ -483,7 +483,7 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq) } } if (sdp->sector_size == 4096) { - if ((block & 7) || (rq->nr_sectors & 7)) { + if ((block & 7) || (blk_rq_sectors(rq) & 7)) { scmd_printk(KERN_ERR, SCpnt, "Bad block number requested\n"); goto out; @@ -512,10 +512,10 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq) } SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt, - "%s %d/%ld 512 byte blocks.\n", + "%s %d/%u 512 byte blocks.\n", (rq_data_dir(rq) == WRITE) ? "writing" : "reading", this_count, - rq->nr_sectors)); + blk_rq_sectors(rq))); /* Set RDPROTECT/WRPROTECT if disk is formatted with DIF */ host_dif = scsi_host_dif_capable(sdp->host, sdkp->protection_type); @@ -971,8 +971,8 @@ static struct block_device_operations sd_fops = { static unsigned int sd_completed_bytes(struct scsi_cmnd *scmd) { - u64 start_lba = scmd->request->sector; - u64 end_lba = scmd->request->sector + (scsi_bufflen(scmd) / 512); + u64 start_lba = blk_rq_pos(scmd->request); + u64 end_lba = blk_rq_pos(scmd->request) + (scsi_bufflen(scmd) / 512); u64 bad_lba; int info_valid; @@ -1307,6 +1307,7 @@ static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp, int sense_valid = 0; int the_result; int retries = 3; + unsigned int alignment; unsigned long long lba; unsigned sector_size; @@ -1358,6 +1359,16 @@ static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp, return -EOVERFLOW; } + /* Logical blocks per physical block exponent */ + sdkp->hw_sector_size = (1 << (buffer[13] & 0xf)) * sector_size; + + /* Lowest aligned logical block */ + alignment = ((buffer[14] & 0x3f) << 8 | buffer[15]) * sector_size; + blk_queue_alignment_offset(sdp->request_queue, alignment); + if (alignment && sdkp->first_scan) + sd_printk(KERN_NOTICE, sdkp, + "physical block alignment offset: %u\n", alignment); + sdkp->capacity = lba + 1; return sector_size; } @@ -1409,6 +1420,7 @@ static int read_capacity_10(struct scsi_disk *sdkp, struct scsi_device *sdp, } sdkp->capacity = lba + 1; + sdkp->hw_sector_size = sector_size; return sector_size; } @@ -1510,7 +1522,7 @@ got_data: */ sector_size = 512; } - blk_queue_hardsect_size(sdp->request_queue, sector_size); + blk_queue_logical_block_size(sdp->request_queue, sector_size); { char cap_str_2[10], cap_str_10[10]; @@ -1521,11 +1533,17 @@ got_data: string_get_size(sz, STRING_UNITS_10, cap_str_10, sizeof(cap_str_10)); - if (sdkp->first_scan || old_capacity != sdkp->capacity) + if (sdkp->first_scan || old_capacity != sdkp->capacity) { sd_printk(KERN_NOTICE, sdkp, - "%llu %d-byte hardware sectors: (%s/%s)\n", + "%llu %d-byte logical blocks: (%s/%s)\n", (unsigned long long)sdkp->capacity, sector_size, cap_str_10, cap_str_2); + + if (sdkp->hw_sector_size != sector_size) + sd_printk(KERN_NOTICE, sdkp, + "%u-byte physical blocks\n", + sdkp->hw_sector_size); + } } /* Rescale capacity to 512-byte units */ @@ -1538,6 +1556,7 @@ got_data: else if (sector_size == 256) sdkp->capacity >>= 1; + blk_queue_physical_block_size(sdp->request_queue, sdkp->hw_sector_size); sdkp->device->sector_size = sector_size; } @@ -1775,6 +1794,52 @@ void sd_read_app_tag_own(struct scsi_disk *sdkp, unsigned char *buffer) return; } +/** + * sd_read_block_limits - Query disk device for preferred I/O sizes. + * @disk: disk to query + */ +static void sd_read_block_limits(struct scsi_disk *sdkp) +{ + unsigned int sector_sz = sdkp->device->sector_size; + char *buffer; + + /* Block Limits VPD */ + buffer = scsi_get_vpd_page(sdkp->device, 0xb0); + + if (buffer == NULL) + return; + + blk_queue_io_min(sdkp->disk->queue, + get_unaligned_be16(&buffer[6]) * sector_sz); + blk_queue_io_opt(sdkp->disk->queue, + get_unaligned_be32(&buffer[12]) * sector_sz); + + kfree(buffer); +} + +/** + * sd_read_block_characteristics - Query block dev. characteristics + * @disk: disk to query + */ +static void sd_read_block_characteristics(struct scsi_disk *sdkp) +{ + char *buffer; + u16 rot; + + /* Block Device Characteristics VPD */ + buffer = scsi_get_vpd_page(sdkp->device, 0xb1); + + if (buffer == NULL) + return; + + rot = get_unaligned_be16(&buffer[4]); + + if (rot == 1) + queue_flag_set_unlocked(QUEUE_FLAG_NONROT, sdkp->disk->queue); + + kfree(buffer); +} + /** * sd_revalidate_disk - called the first time a new disk is seen, * performs disk spin up, read_capacity, etc. @@ -1812,6 +1877,8 @@ static int sd_revalidate_disk(struct gendisk *disk) */ if (sdkp->media_present) { sd_read_capacity(sdkp, buffer); + sd_read_block_limits(sdkp); + sd_read_block_characteristics(sdkp); sd_read_write_protect_flag(sdkp, buffer); sd_read_cache_type(sdkp, buffer); sd_read_app_tag_own(sdkp, buffer); @@ -1902,24 +1969,6 @@ static void sd_probe_async(void *data, async_cookie_t cookie) index = sdkp->index; dev = &sdp->sdev_gendev; - if (!sdp->request_queue->rq_timeout) { - if (sdp->type != TYPE_MOD) - blk_queue_rq_timeout(sdp->request_queue, SD_TIMEOUT); - else - blk_queue_rq_timeout(sdp->request_queue, - SD_MOD_TIMEOUT); - } - - device_initialize(&sdkp->dev); - sdkp->dev.parent = &sdp->sdev_gendev; - sdkp->dev.class = &sd_disk_class; - dev_set_name(&sdkp->dev, dev_name(&sdp->sdev_gendev)); - - if (device_add(&sdkp->dev)) - goto out_free_index; - - get_device(&sdp->sdev_gendev); - if (index < SD_MAX_DISKS) { gd->major = sd_major((index & 0xf0) >> 4); gd->first_minor = ((index & 0xf) << 4) | (index & 0xfff00); @@ -1952,13 +2001,10 @@ static void sd_probe_async(void *data, async_cookie_t cookie) add_disk(gd); sd_dif_config_host(sdkp); + sd_revalidate_disk(gd); + sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n", sdp->removable ? "removable " : ""); - - return; - - out_free_index: - ida_remove(&sd_index_ida, index); } /** @@ -2026,6 +2072,24 @@ static int sd_probe(struct device *dev) sdkp->openers = 0; sdkp->previous_state = 1; + if (!sdp->request_queue->rq_timeout) { + if (sdp->type != TYPE_MOD) + blk_queue_rq_timeout(sdp->request_queue, SD_TIMEOUT); + else + blk_queue_rq_timeout(sdp->request_queue, + SD_MOD_TIMEOUT); + } + + device_initialize(&sdkp->dev); + sdkp->dev.parent = &sdp->sdev_gendev; + sdkp->dev.class = &sd_disk_class; + dev_set_name(&sdkp->dev, dev_name(&sdp->sdev_gendev)); + + if (device_add(&sdkp->dev)) + goto out_free_index; + + get_device(&sdp->sdev_gendev); + async_schedule(sd_probe_async, sdkp); return 0; @@ -2055,8 +2119,11 @@ static int sd_probe(struct device *dev) **/ static int sd_remove(struct device *dev) { - struct scsi_disk *sdkp = dev_get_drvdata(dev); + struct scsi_disk *sdkp; + async_synchronize_full(); + sdkp = dev_get_drvdata(dev); + blk_queue_prep_rq(sdkp->device->request_queue, scsi_prep_fn); device_del(&sdkp->dev); del_gendisk(sdkp->disk); sd_shutdown(dev); diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h index 708778cf5f06..8474b5bad3fe 100644 --- a/drivers/scsi/sd.h +++ b/drivers/scsi/sd.h @@ -45,6 +45,7 @@ struct scsi_disk { unsigned int openers; /* protected by BKL for now, yuck */ sector_t capacity; /* size in 512-byte sectors */ u32 index; + unsigned short hw_sector_size; u8 media_present; u8 write_prot; u8 protection_type;/* Data Integrity Field */ diff --git a/drivers/scsi/sd_dif.c b/drivers/scsi/sd_dif.c index 184dff492797..82f14a9482d0 100644 --- a/drivers/scsi/sd_dif.c +++ b/drivers/scsi/sd_dif.c @@ -507,7 +507,7 @@ void sd_dif_complete(struct scsi_cmnd *scmd, unsigned int good_bytes) sector_sz = scmd->device->sector_size; sectors = good_bytes / sector_sz; - phys = scmd->request->sector & 0xffffffff; + phys = blk_rq_pos(scmd->request) & 0xffffffff; if (sector_sz == 4096) phys >>= 3; diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index e1716f14cd47..8201387b4daa 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -289,8 +289,8 @@ sg_open(struct inode *inode, struct file *filp) if (list_empty(&sdp->sfds)) { /* no existing opens on this device */ sdp->sgdebug = 0; q = sdp->device->request_queue; - sdp->sg_tablesize = min(q->max_hw_segments, - q->max_phys_segments); + sdp->sg_tablesize = min(queue_max_hw_segments(q), + queue_max_phys_segments(q)); } if ((sfp = sg_add_sfp(sdp, dev))) filp->private_data = sfp; @@ -909,7 +909,7 @@ sg_ioctl(struct inode *inode, struct file *filp, if (val < 0) return -EINVAL; val = min_t(int, val, - sdp->device->request_queue->max_sectors * 512); + queue_max_sectors(sdp->device->request_queue) * 512); if (val != sfp->reserve.bufflen) { if (sg_res_in_use(sfp) || sfp->mmap_called) return -EBUSY; @@ -919,7 +919,7 @@ sg_ioctl(struct inode *inode, struct file *filp, return 0; case SG_GET_RESERVED_SIZE: val = min_t(int, sfp->reserve.bufflen, - sdp->device->request_queue->max_sectors * 512); + queue_max_sectors(sdp->device->request_queue) * 512); return put_user(val, ip); case SG_SET_COMMAND_Q: result = get_user(val, ip); @@ -1059,12 +1059,13 @@ sg_ioctl(struct inode *inode, struct file *filp, return -ENODEV; return scsi_ioctl(sdp->device, cmd_in, p); case BLKSECTGET: - return put_user(sdp->device->request_queue->max_sectors * 512, + return put_user(queue_max_sectors(sdp->device->request_queue) * 512, ip); case BLKTRACESETUP: return blk_trace_setup(sdp->device->request_queue, sdp->disk->disk_name, MKDEV(SCSI_GENERIC_MAJOR, sdp->index), + NULL, (char *)arg); case BLKTRACESTART: return blk_trace_startstop(sdp->device->request_queue, 1); @@ -1260,7 +1261,7 @@ static void sg_rq_end_io(struct request *rq, int uptodate) sense = rq->sense; result = rq->errors; - resid = rq->data_len; + resid = rq->resid_len; SCSI_LOG_TIMEOUT(4, printk("sg_cmd_done: %s, pack_id=%d, res=0x%x\n", sdp->disk->disk_name, srp->header.pack_id, result)); @@ -1377,7 +1378,8 @@ static Sg_device *sg_alloc(struct gendisk *disk, struct scsi_device *scsidp) sdp->device = scsidp; INIT_LIST_HEAD(&sdp->sfds); init_waitqueue_head(&sdp->o_excl_wait); - sdp->sg_tablesize = min(q->max_hw_segments, q->max_phys_segments); + sdp->sg_tablesize = min(queue_max_hw_segments(q), + queue_max_phys_segments(q)); sdp->index = k; kref_init(&sdp->d_ref); @@ -2055,7 +2057,7 @@ sg_add_sfp(Sg_device * sdp, int dev) sg_big_buff = def_reserved_size; bufflen = min_t(int, sg_big_buff, - sdp->device->request_queue->max_sectors * 512); + queue_max_sectors(sdp->device->request_queue) * 512); sg_build_reserve(sfp, bufflen); SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: bufflen=%d, k_use_sg=%d\n", sfp->reserve.bufflen, sfp->reserve.k_use_sg)); diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index 0e1a0f2d2ad5..cce0fe4c8a3b 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -292,7 +292,8 @@ static int sr_done(struct scsi_cmnd *SCpnt) if (cd->device->sector_size == 2048) error_sector <<= 2; error_sector &= ~(block_sectors - 1); - good_bytes = (error_sector - SCpnt->request->sector) << 9; + good_bytes = (error_sector - + blk_rq_pos(SCpnt->request)) << 9; if (good_bytes < 0 || good_bytes >= this_count) good_bytes = 0; /* @@ -349,8 +350,8 @@ static int sr_prep_fn(struct request_queue *q, struct request *rq) cd->disk->disk_name, block)); if (!cd->device || !scsi_device_online(cd->device)) { - SCSI_LOG_HLQUEUE(2, printk("Finishing %ld sectors\n", - rq->nr_sectors)); + SCSI_LOG_HLQUEUE(2, printk("Finishing %u sectors\n", + blk_rq_sectors(rq))); SCSI_LOG_HLQUEUE(2, printk("Retry with 0x%p\n", SCpnt)); goto out; } @@ -413,7 +414,7 @@ static int sr_prep_fn(struct request_queue *q, struct request *rq) /* * request doesn't start on hw block boundary, add scatter pads */ - if (((unsigned int)rq->sector % (s_size >> 9)) || + if (((unsigned int)blk_rq_pos(rq) % (s_size >> 9)) || (scsi_bufflen(SCpnt) % s_size)) { scmd_printk(KERN_NOTICE, SCpnt, "unaligned transfer\n"); goto out; @@ -422,14 +423,14 @@ static int sr_prep_fn(struct request_queue *q, struct request *rq) this_count = (scsi_bufflen(SCpnt) >> 9) / (s_size >> 9); - SCSI_LOG_HLQUEUE(2, printk("%s : %s %d/%ld 512 byte blocks.\n", + SCSI_LOG_HLQUEUE(2, printk("%s : %s %d/%u 512 byte blocks.\n", cd->cdi.name, (rq_data_dir(rq) == WRITE) ? "writing" : "reading", - this_count, rq->nr_sectors)); + this_count, blk_rq_sectors(rq))); SCpnt->cmnd[1] = 0; - block = (unsigned int)rq->sector / (s_size >> 9); + block = (unsigned int)blk_rq_pos(rq) / (s_size >> 9); if (this_count > 0xffff) { this_count = 0xffff; @@ -726,7 +727,7 @@ static void get_sectorsize(struct scsi_cd *cd) } queue = cd->device->request_queue; - blk_queue_hardsect_size(queue, sector_size); + blk_queue_logical_block_size(queue, sector_size); return; } @@ -880,6 +881,7 @@ static int sr_remove(struct device *dev) { struct scsi_cd *cd = dev_get_drvdata(dev); + blk_queue_prep_rq(cd->device->request_queue, scsi_prep_fn); del_gendisk(cd->disk); mutex_lock(&sr_ref_mutex); diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index eb24efea8f14..b33d04250bbc 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -463,7 +463,7 @@ static void st_scsi_execute_end(struct request *req, int uptodate) struct scsi_tape *STp = SRpnt->stp; STp->buffer->cmdstat.midlevel_result = SRpnt->result = req->errors; - STp->buffer->cmdstat.residual = req->data_len; + STp->buffer->cmdstat.residual = req->resid_len; if (SRpnt->waiting) complete(SRpnt->waiting); @@ -2964,7 +2964,7 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon !(STp->use_pf & PF_TESTED)) { /* Try the other possible state of Page Format if not already tried */ - STp->use_pf = !STp->use_pf | PF_TESTED; + STp->use_pf = (STp->use_pf ^ USE_PF) | PF_TESTED; st_release_request(SRpnt); SRpnt = NULL; return st_int_ioctl(STp, cmd_in, arg); @@ -3983,8 +3983,8 @@ static int st_probe(struct device *dev) return -ENODEV; } - i = min(SDp->request_queue->max_hw_segments, - SDp->request_queue->max_phys_segments); + i = min(queue_max_hw_segments(SDp->request_queue), + queue_max_phys_segments(SDp->request_queue)); if (st_max_sg_segs < i) i = st_max_sg_segs; buffer = new_tape_buffer((SDp->host)->unchecked_isa_dma, i); diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c index 583966ec8266..45374d66d26a 100644 --- a/drivers/scsi/sym53c8xx_2/sym_glue.c +++ b/drivers/scsi/sym53c8xx_2/sym_glue.c @@ -737,11 +737,14 @@ static int sym53c8xx_slave_alloc(struct scsi_device *sdev) struct sym_hcb *np = sym_get_hcb(sdev->host); struct sym_tcb *tp = &np->target[sdev->id]; struct sym_lcb *lp; + unsigned long flags; + int error; if (sdev->id >= SYM_CONF_MAX_TARGET || sdev->lun >= SYM_CONF_MAX_LUN) return -ENXIO; - tp->starget = sdev->sdev_target; + spin_lock_irqsave(np->s.host->host_lock, flags); + /* * Fail the device init if the device is flagged NOSCAN at BOOT in * the NVRAM. This may speed up boot and maintain coherency with @@ -753,26 +756,37 @@ static int sym53c8xx_slave_alloc(struct scsi_device *sdev) if (tp->usrflags & SYM_SCAN_BOOT_DISABLED) { tp->usrflags &= ~SYM_SCAN_BOOT_DISABLED; - starget_printk(KERN_INFO, tp->starget, + starget_printk(KERN_INFO, sdev->sdev_target, "Scan at boot disabled in NVRAM\n"); - return -ENXIO; + error = -ENXIO; + goto out; } if (tp->usrflags & SYM_SCAN_LUNS_DISABLED) { - if (sdev->lun != 0) - return -ENXIO; - starget_printk(KERN_INFO, tp->starget, + if (sdev->lun != 0) { + error = -ENXIO; + goto out; + } + starget_printk(KERN_INFO, sdev->sdev_target, "Multiple LUNs disabled in NVRAM\n"); } lp = sym_alloc_lcb(np, sdev->id, sdev->lun); - if (!lp) - return -ENOMEM; + if (!lp) { + error = -ENOMEM; + goto out; + } + if (tp->nlcb == 1) + tp->starget = sdev->sdev_target; spi_min_period(tp->starget) = tp->usr_period; spi_max_width(tp->starget) = tp->usr_width; - return 0; + error = 0; +out: + spin_unlock_irqrestore(np->s.host->host_lock, flags); + + return error; } /* @@ -819,12 +833,34 @@ static int sym53c8xx_slave_configure(struct scsi_device *sdev) static void sym53c8xx_slave_destroy(struct scsi_device *sdev) { struct sym_hcb *np = sym_get_hcb(sdev->host); - struct sym_lcb *lp = sym_lp(&np->target[sdev->id], sdev->lun); + struct sym_tcb *tp = &np->target[sdev->id]; + struct sym_lcb *lp = sym_lp(tp, sdev->lun); + unsigned long flags; - if (lp->itlq_tbl) - sym_mfree_dma(lp->itlq_tbl, SYM_CONF_MAX_TASK * 4, "ITLQ_TBL"); - kfree(lp->cb_tags); - sym_mfree_dma(lp, sizeof(*lp), "LCB"); + spin_lock_irqsave(np->s.host->host_lock, flags); + + if (lp->busy_itlq || lp->busy_itl) { + /* + * This really shouldn't happen, but we can't return an error + * so let's try to stop all on-going I/O. + */ + starget_printk(KERN_WARNING, tp->starget, + "Removing busy LCB (%d)\n", sdev->lun); + sym_reset_scsi_bus(np, 1); + } + + if (sym_free_lcb(np, sdev->id, sdev->lun) == 0) { + /* + * It was the last unit for this target. + */ + tp->head.sval = 0; + tp->head.wval = np->rv_scntl3; + tp->head.uval = 0; + tp->tgoal.check_nego = 1; + tp->starget = NULL; + } + + spin_unlock_irqrestore(np->s.host->host_lock, flags); } /* @@ -890,6 +926,8 @@ static void sym_exec_user_command (struct sym_hcb *np, struct sym_usrcmd *uc) if (!((uc->target >> t) & 1)) continue; tp = &np->target[t]; + if (!tp->nlcb) + continue; switch (uc->cmd) { diff --git a/drivers/scsi/sym53c8xx_2/sym_hipd.c b/drivers/scsi/sym53c8xx_2/sym_hipd.c index ffa70d1ed182..297deb817a5d 100644 --- a/drivers/scsi/sym53c8xx_2/sym_hipd.c +++ b/drivers/scsi/sym53c8xx_2/sym_hipd.c @@ -1896,6 +1896,15 @@ void sym_start_up(struct Scsi_Host *shost, int reason) tp->head.sval = 0; tp->head.wval = np->rv_scntl3; tp->head.uval = 0; + if (tp->lun0p) + tp->lun0p->to_clear = 0; + if (tp->lunmp) { + int ln; + + for (ln = 1; ln < SYM_CONF_MAX_LUN; ln++) + if (tp->lunmp[ln]) + tp->lunmp[ln]->to_clear = 0; + } } /* @@ -2312,8 +2321,9 @@ static void sym_int_par (struct sym_hcb *np, u_short sist) int phase = cmd & 7; struct sym_ccb *cp = sym_ccb_from_dsa(np, dsa); - printf("%s: SCSI parity error detected: SCR1=%d DBC=%x SBCL=%x\n", - sym_name(np), hsts, dbc, sbcl); + if (printk_ratelimit()) + printf("%s: SCSI parity error detected: SCR1=%d DBC=%x SBCL=%x\n", + sym_name(np), hsts, dbc, sbcl); /* * Check that the chip is connected to the SCSI BUS. @@ -4988,7 +4998,7 @@ struct sym_lcb *sym_alloc_lcb (struct sym_hcb *np, u_char tn, u_char ln) */ if (ln && !tp->lunmp) { tp->lunmp = kcalloc(SYM_CONF_MAX_LUN, sizeof(struct sym_lcb *), - GFP_KERNEL); + GFP_ATOMIC); if (!tp->lunmp) goto fail; } @@ -5008,6 +5018,7 @@ struct sym_lcb *sym_alloc_lcb (struct sym_hcb *np, u_char tn, u_char ln) tp->lun0p = lp; tp->head.lun0_sa = cpu_to_scr(vtobus(lp)); } + tp->nlcb++; /* * Let the itl task point to error handling. @@ -5084,6 +5095,43 @@ fail: return; } +/* + * Lun control block deallocation. Returns the number of valid remaing LCBs + * for the target. + */ +int sym_free_lcb(struct sym_hcb *np, u_char tn, u_char ln) +{ + struct sym_tcb *tp = &np->target[tn]; + struct sym_lcb *lp = sym_lp(tp, ln); + + tp->nlcb--; + + if (ln) { + if (!tp->nlcb) { + kfree(tp->lunmp); + sym_mfree_dma(tp->luntbl, 256, "LUNTBL"); + tp->lunmp = NULL; + tp->luntbl = NULL; + tp->head.luntbl_sa = cpu_to_scr(vtobus(np->badluntbl)); + } else { + tp->luntbl[ln] = cpu_to_scr(vtobus(&np->badlun_sa)); + tp->lunmp[ln] = NULL; + } + } else { + tp->lun0p = NULL; + tp->head.lun0_sa = cpu_to_scr(vtobus(&np->badlun_sa)); + } + + if (lp->itlq_tbl) { + sym_mfree_dma(lp->itlq_tbl, SYM_CONF_MAX_TASK*4, "ITLQ_TBL"); + kfree(lp->cb_tags); + } + + sym_mfree_dma(lp, sizeof(*lp), "LCB"); + + return tp->nlcb; +} + /* * Queue a SCSI IO to the controller. */ diff --git a/drivers/scsi/sym53c8xx_2/sym_hipd.h b/drivers/scsi/sym53c8xx_2/sym_hipd.h index 9ebc8706b6bf..053e63c86822 100644 --- a/drivers/scsi/sym53c8xx_2/sym_hipd.h +++ b/drivers/scsi/sym53c8xx_2/sym_hipd.h @@ -401,6 +401,7 @@ struct sym_tcb { * An array of bus addresses is used on reselection. */ u32 *luntbl; /* LCBs bus address table */ + int nlcb; /* Number of valid LCBs (including LUN #0) */ /* * LUN table used by the C code. @@ -1065,6 +1066,7 @@ int sym_clear_tasks(struct sym_hcb *np, int cam_status, int target, int lun, int struct sym_ccb *sym_get_ccb(struct sym_hcb *np, struct scsi_cmnd *cmd, u_char tag_order); void sym_free_ccb(struct sym_hcb *np, struct sym_ccb *cp); struct sym_lcb *sym_alloc_lcb(struct sym_hcb *np, u_char tn, u_char ln); +int sym_free_lcb(struct sym_hcb *np, u_char tn, u_char ln); int sym_queue_scsiio(struct sym_hcb *np, struct scsi_cmnd *csio, struct sym_ccb *cp); int sym_abort_scsiio(struct sym_hcb *np, struct scsi_cmnd *ccb, int timed_out); int sym_reset_scsi_target(struct sym_hcb *np, int target); diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c index 601e95141cbe..54023d41fd15 100644 --- a/drivers/scsi/u14-34f.c +++ b/drivers/scsi/u14-34f.c @@ -1306,7 +1306,7 @@ static int u14_34f_queuecommand(struct scsi_cmnd *SCpnt, void (*done)(struct scs if (linked_comm && SCpnt->device->queue_depth > 2 && TLDEV(SCpnt->device->type)) { HD(j)->cp_stat[i] = READY; - flush_dev(SCpnt->device, SCpnt->request->sector, j, FALSE); + flush_dev(SCpnt->device, blk_rq_pos(SCpnt->request), j, FALSE); return 0; } @@ -1610,11 +1610,13 @@ static int reorder(unsigned int j, unsigned long cursec, if (!(cpp->xdir == DTD_IN)) input_only = FALSE; - if (SCpnt->request->sector < minsec) minsec = SCpnt->request->sector; - if (SCpnt->request->sector > maxsec) maxsec = SCpnt->request->sector; + if (blk_rq_pos(SCpnt->request) < minsec) + minsec = blk_rq_pos(SCpnt->request); + if (blk_rq_pos(SCpnt->request) > maxsec) + maxsec = blk_rq_pos(SCpnt->request); - sl[n] = SCpnt->request->sector; - ioseek += SCpnt->request->nr_sectors; + sl[n] = blk_rq_pos(SCpnt->request); + ioseek += blk_rq_sectors(SCpnt->request); if (!n) continue; @@ -1642,7 +1644,7 @@ static int reorder(unsigned int j, unsigned long cursec, if (!input_only) for (n = 0; n < n_ready; n++) { k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt; - ll[n] = SCpnt->request->nr_sectors; pl[n] = SCpnt->serial_number; + ll[n] = blk_rq_sectors(SCpnt->request); pl[n] = SCpnt->serial_number; if (!n) continue; @@ -1666,12 +1668,12 @@ static int reorder(unsigned int j, unsigned long cursec, if (link_statistics && (overlap || !(flushcount % link_statistics))) for (n = 0; n < n_ready; n++) { k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt; - printk("%s %d.%d:%d pid %ld mb %d fc %d nr %d sec %ld ns %ld"\ + printk("%s %d.%d:%d pid %ld mb %d fc %d nr %d sec %ld ns %u"\ " cur %ld s:%c r:%c rev:%c in:%c ov:%c xd %d.\n", (ihdlr ? "ihdlr" : "qcomm"), SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->serial_number, k, flushcount, n_ready, - SCpnt->request->sector, SCpnt->request->nr_sectors, cursec, - YESNO(s), YESNO(r), YESNO(rev), YESNO(input_only), + blk_rq_pos(SCpnt->request), blk_rq_sectors(SCpnt->request), + cursec, YESNO(s), YESNO(r), YESNO(rev), YESNO(input_only), YESNO(overlap), cpp->xdir); } #endif @@ -1799,7 +1801,7 @@ static irqreturn_t ihdlr(unsigned int j) if (linked_comm && SCpnt->device->queue_depth > 2 && TLDEV(SCpnt->device->type)) - flush_dev(SCpnt->device, SCpnt->request->sector, j, TRUE); + flush_dev(SCpnt->device, blk_rq_pos(SCpnt->request), j, TRUE); tstatus = status_byte(spp->target_status); diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index a0127e93ade0..fb867a9f55e9 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -287,6 +287,13 @@ static const struct serial8250_config uart_config[] = { .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, .flags = UART_CAP_FIFO, }, + [PORT_AR7] = { + .name = "AR7", + .fifo_size = 16, + .tx_loadsz = 16, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_00, + .flags = UART_CAP_FIFO | UART_CAP_AFE, + }, }; #if defined (CONFIG_SERIAL_8250_AU1X00) diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c index 938bc1b6c3fa..a07015d646dd 100644 --- a/drivers/serial/8250_pci.c +++ b/drivers/serial/8250_pci.c @@ -398,8 +398,7 @@ static int sbs_init(struct pci_dev *dev) { u8 __iomem *p; - p = ioremap_nocache(pci_resource_start(dev, 0), - pci_resource_len(dev, 0)); + p = pci_ioremap_bar(dev, 0); if (p == NULL) return -ENOMEM; @@ -423,8 +422,7 @@ static void __devexit sbs_exit(struct pci_dev *dev) { u8 __iomem *p; - p = ioremap_nocache(pci_resource_start(dev, 0), - pci_resource_len(dev, 0)); + p = pci_ioremap_bar(dev, 0); /* FIXME: What if resource_len < OCT_REG_CR_OFF */ if (p != NULL) writeb(0, p + OCT_REG_CR_OFF); @@ -2776,6 +2774,9 @@ static struct pci_device_id serial_pci_tbl[] = { { PCI_VENDOR_ID_OXSEMI, 0x950a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b0_2_1130000 }, + { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_C950, + PCI_VENDOR_ID_OXSEMI, PCI_SUBDEVICE_ID_OXSEMI_C950, 0, 0, + pbn_b0_1_921600 }, { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b0_4_115200 }, diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 343e3a35b6a3..037c1e0b7c4c 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -833,6 +833,7 @@ config SERIAL_IMX bool "IMX serial port support" depends on ARM && (ARCH_IMX || ARCH_MXC) select SERIAL_CORE + select RATIONAL help If you have a machine based on a Motorola IMX CPU you can enable its onboard serial port by enabling this option. @@ -860,7 +861,7 @@ config SERIAL_UARTLITE Say Y here if you want to use the Xilinx uartlite serial controller. To compile this driver as a module, choose M here: the - module will be called uartlite.ko. + module will be called uartlite. config SERIAL_UARTLITE_CONSOLE bool "Support for console on Xilinx uartlite serial port" @@ -1319,6 +1320,16 @@ config SERIAL_SGI_IOC3 If you have an SGI Altix with an IOC3 serial card, say Y or M. Otherwise, say N. +config SERIAL_MSM + bool "MSM on-chip serial port support" + depends on ARM && ARCH_MSM + select SERIAL_CORE + +config SERIAL_MSM_CONSOLE + bool "MSM serial console support" + depends on SERIAL_MSM=y + select SERIAL_CORE_CONSOLE + config SERIAL_NETX tristate "NetX serial port support" depends on ARM && ARCH_NETX @@ -1433,4 +1444,11 @@ config SPORT_BAUD_RATE default 19200 if (SERIAL_SPORT_BAUD_RATE_19200) default 9600 if (SERIAL_SPORT_BAUD_RATE_9600) +config SERIAL_TIMBERDALE + tristate "Support for timberdale UART" + depends on MFD_TIMBERDALE + select SERIAL_CORE + ---help--- + Add support for UART controller on timberdale. + endmenu diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index d438eb2a73de..d5a29981c6c4 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -71,9 +71,11 @@ obj-$(CONFIG_SERIAL_SGI_IOC4) += ioc4_serial.o obj-$(CONFIG_SERIAL_SGI_IOC3) += ioc3_serial.o obj-$(CONFIG_SERIAL_ATMEL) += atmel_serial.o obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o +obj-$(CONFIG_SERIAL_MSM) += msm_serial.o obj-$(CONFIG_SERIAL_NETX) += netx-serial.o obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o obj-$(CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL) += nwpserial.o obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o obj-$(CONFIG_SERIAL_QE) += ucc_uart.o +obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o diff --git a/drivers/serial/amba-pl010.c b/drivers/serial/amba-pl010.c index cdc049d4350f..58a4879c7e48 100644 --- a/drivers/serial/amba-pl010.c +++ b/drivers/serial/amba-pl010.c @@ -686,7 +686,7 @@ static int pl010_probe(struct amba_device *dev, struct amba_id *id) goto out; } - base = ioremap(dev->res.start, PAGE_SIZE); + base = ioremap(dev->res.start, resource_size(&dev->res)); if (!base) { ret = -ENOMEM; goto free; diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c index 88fdac51b6c5..bf82e28770a9 100644 --- a/drivers/serial/amba-pl011.c +++ b/drivers/serial/amba-pl011.c @@ -70,6 +70,23 @@ struct uart_amba_port { struct clk *clk; unsigned int im; /* interrupt mask */ unsigned int old_status; + unsigned int ifls; /* vendor-specific */ +}; + +/* There is by now at least one vendor with differing details, so handle it */ +struct vendor_data { + unsigned int ifls; + unsigned int fifosize; +}; + +static struct vendor_data vendor_arm = { + .ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8, + .fifosize = 16, +}; + +static struct vendor_data vendor_st = { + .ifls = UART011_IFLS_RX_HALF|UART011_IFLS_TX_HALF, + .fifosize = 64, }; static void pl011_stop_tx(struct uart_port *port) @@ -360,8 +377,7 @@ static int pl011_startup(struct uart_port *port) if (retval) goto clk_dis; - writew(UART011_IFLS_RX4_8|UART011_IFLS_TX4_8, - uap->port.membase + UART011_IFLS); + writew(uap->ifls, uap->port.membase + UART011_IFLS); /* * Provoke TX FIFO interrupt into asserting. @@ -732,6 +748,7 @@ static struct uart_driver amba_reg = { static int pl011_probe(struct amba_device *dev, struct amba_id *id) { struct uart_amba_port *uap; + struct vendor_data *vendor = id->data; void __iomem *base; int i, ret; @@ -750,7 +767,7 @@ static int pl011_probe(struct amba_device *dev, struct amba_id *id) goto out; } - base = ioremap(dev->res.start, PAGE_SIZE); + base = ioremap(dev->res.start, resource_size(&dev->res)); if (!base) { ret = -ENOMEM; goto free; @@ -762,12 +779,13 @@ static int pl011_probe(struct amba_device *dev, struct amba_id *id) goto unmap; } + uap->ifls = vendor->ifls; uap->port.dev = &dev->dev; uap->port.mapbase = dev->res.start; uap->port.membase = base; uap->port.iotype = UPIO_MEM; uap->port.irq = dev->irq[0]; - uap->port.fifosize = 16; + uap->port.fifosize = vendor->fifosize; uap->port.ops = &amba_pl011_pops; uap->port.flags = UPF_BOOT_AUTOCONF; uap->port.line = i; @@ -812,6 +830,12 @@ static struct amba_id pl011_ids[] __initdata = { { .id = 0x00041011, .mask = 0x000fffff, + .data = &vendor_arm, + }, + { + .id = 0x00380802, + .mask = 0x00ffffff, + .data = &vendor_st, }, { 0, 0 }, }; @@ -845,7 +869,11 @@ static void __exit pl011_exit(void) uart_unregister_driver(&amba_reg); } -module_init(pl011_init); +/* + * While this can be a module, if builtin it's most likely the console + * So let's leave module_exit but move module_init to an earlier place + */ +arch_initcall(pl011_init); module_exit(pl011_exit); MODULE_AUTHOR("ARM Ltd/Deep Blue Solutions Ltd"); diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c index b3497d7e5354..338b15c0a548 100644 --- a/drivers/serial/atmel_serial.c +++ b/drivers/serial/atmel_serial.c @@ -1104,11 +1104,13 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, /* update the per-port timeout */ uart_update_timeout(port, termios->c_cflag, baud); - /* save/disable interrupts and drain transmitter */ + /* + * save/disable interrupts. The tty layer will ensure that the + * transmitter is empty if requested by the caller, so there's + * no need to wait for it here. + */ imr = UART_GET_IMR(port); UART_PUT_IDR(port, -1); - while (!(UART_GET_CSR(port) & ATMEL_US_TXEMPTY)) - cpu_relax(); /* disable receiver and transmitter */ UART_PUT_CR(port, ATMEL_US_TXDIS | ATMEL_US_RXDIS); diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c index d86123e03391..b4a7650af696 100644 --- a/drivers/serial/bfin_5xx.c +++ b/drivers/serial/bfin_5xx.c @@ -38,6 +38,10 @@ #include #endif +#ifdef CONFIG_SERIAL_BFIN_MODULE +# undef CONFIG_EARLY_PRINTK +#endif + /* UART name and device definitions */ #define BFIN_SERIAL_NAME "ttyBF" #define BFIN_SERIAL_MAJOR 204 @@ -330,6 +334,11 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart) /* Clear TFI bit */ UART_PUT_LSR(uart, TFI); #endif + /* Anomaly notes: + * 05000215 - we always clear ETBEI within last UART TX + * interrupt to end a string. It is always set + * when start a new tx. + */ UART_CLEAR_IER(uart, ETBEI); return; } @@ -415,6 +424,7 @@ static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart) set_dma_start_addr(uart->tx_dma_channel, (unsigned long)(xmit->buf+xmit->tail)); set_dma_x_count(uart->tx_dma_channel, uart->tx_count); set_dma_x_modify(uart->tx_dma_channel, 1); + SSYNC(); enable_dma(uart->tx_dma_channel); UART_SET_IER(uart, ETBEI); @@ -473,27 +483,41 @@ static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart) void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart) { int x_pos, pos; - unsigned long flags; - spin_lock_irqsave(&uart->port.lock, flags); + dma_disable_irq(uart->rx_dma_channel); + spin_lock_bh(&uart->port.lock); + /* 2D DMA RX buffer ring is used. Because curr_y_count and + * curr_x_count can't be read as an atomic operation, + * curr_y_count should be read before curr_x_count. When + * curr_x_count is read, curr_y_count may already indicate + * next buffer line. But, the position calculated here is + * still indicate the old line. The wrong position data may + * be smaller than current buffer tail, which cause garbages + * are received if it is not prohibit. + */ uart->rx_dma_nrows = get_dma_curr_ycount(uart->rx_dma_channel); x_pos = get_dma_curr_xcount(uart->rx_dma_channel); uart->rx_dma_nrows = DMA_RX_YCOUNT - uart->rx_dma_nrows; - if (uart->rx_dma_nrows == DMA_RX_YCOUNT) + if (uart->rx_dma_nrows == DMA_RX_YCOUNT || x_pos == 0) uart->rx_dma_nrows = 0; x_pos = DMA_RX_XCOUNT - x_pos; if (x_pos == DMA_RX_XCOUNT) x_pos = 0; pos = uart->rx_dma_nrows * DMA_RX_XCOUNT + x_pos; - if (pos != uart->rx_dma_buf.tail) { + /* Ignore receiving data if new position is in the same line of + * current buffer tail and small. + */ + if (pos > uart->rx_dma_buf.tail || + uart->rx_dma_nrows < (uart->rx_dma_buf.tail/DMA_RX_XCOUNT)) { uart->rx_dma_buf.head = pos; bfin_serial_dma_rx_chars(uart); uart->rx_dma_buf.tail = uart->rx_dma_buf.head; } - spin_unlock_irqrestore(&uart->port.lock, flags); + spin_unlock_bh(&uart->port.lock); + dma_enable_irq(uart->rx_dma_channel); mod_timer(&(uart->rx_dma_timer), jiffies + DMA_RX_FLUSH_JIFFIES); } @@ -514,6 +538,11 @@ static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id) if (!(get_dma_curr_irqstat(uart->tx_dma_channel)&DMA_RUN)) { disable_dma(uart->tx_dma_channel); clear_dma_irqstat(uart->tx_dma_channel); + /* Anomaly notes: + * 05000215 - we always clear ETBEI within last UART TX + * interrupt to end a string. It is always set + * when start a new tx. + */ UART_CLEAR_IER(uart, ETBEI); xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1); uart->port.icount.tx += uart->tx_count; @@ -532,11 +561,26 @@ static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id) { struct bfin_serial_port *uart = dev_id; unsigned short irqstat; + int x_pos, pos; spin_lock(&uart->port.lock); irqstat = get_dma_curr_irqstat(uart->rx_dma_channel); clear_dma_irqstat(uart->rx_dma_channel); - bfin_serial_dma_rx_chars(uart); + + uart->rx_dma_nrows = get_dma_curr_ycount(uart->rx_dma_channel); + x_pos = get_dma_curr_xcount(uart->rx_dma_channel); + uart->rx_dma_nrows = DMA_RX_YCOUNT - uart->rx_dma_nrows; + if (uart->rx_dma_nrows == DMA_RX_YCOUNT || x_pos == 0) + uart->rx_dma_nrows = 0; + + pos = uart->rx_dma_nrows * DMA_RX_XCOUNT; + if (pos > uart->rx_dma_buf.tail || + uart->rx_dma_nrows < (uart->rx_dma_buf.tail/DMA_RX_XCOUNT)) { + uart->rx_dma_buf.head = pos; + bfin_serial_dma_rx_chars(uart); + uart->rx_dma_buf.tail = uart->rx_dma_buf.head; + } + spin_unlock(&uart->port.lock); return IRQ_HANDLED; @@ -789,8 +833,16 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios, __func__); } - if (termios->c_cflag & CSTOPB) - lcr |= STB; + /* Anomaly notes: + * 05000231 - STOP bit is always set to 1 whatever the user is set. + */ + if (termios->c_cflag & CSTOPB) { + if (ANOMALY_05000231) + printk(KERN_WARNING "STOP bits other than 1 is not " + "supported in case of anomaly 05000231.\n"); + else + lcr |= STB; + } if (termios->c_cflag & PARENB) lcr |= PEN; if (!(termios->c_cflag & PARODD)) @@ -940,6 +992,10 @@ static void bfin_serial_reset_irda(struct uart_port *port) } #ifdef CONFIG_CONSOLE_POLL +/* Anomaly notes: + * 05000099 - Because we only use THRE in poll_put and DR in poll_get, + * losing other bits of UART_LSR is not a problem here. + */ static void bfin_serial_poll_put_char(struct uart_port *port, unsigned char chr) { struct bfin_serial_port *uart = (struct bfin_serial_port *)port; @@ -1058,6 +1114,7 @@ static void __init bfin_serial_init_ports(void) bfin_serial_hw_init(); for (i = 0; i < nr_active_ports; i++) { + spin_lock_init(&bfin_serial_ports[i].port.lock); bfin_serial_ports[i].port.uartclk = get_sclk(); bfin_serial_ports[i].port.fifosize = BFIN_UART_TX_FIFO_SIZE; bfin_serial_ports[i].port.ops = &bfin_serial_pops; @@ -1245,12 +1302,17 @@ static __init void early_serial_write(struct console *con, const char *s, } } +/* + * This should have a .setup or .early_setup in it, but then things get called + * without the command line options, and the baud rate gets messed up - so + * don't let the common infrastructure play with things. (see calls to setup + * & earlysetup in ./kernel/printk.c:register_console() + */ static struct __initdata console bfin_early_serial_console = { .name = "early_BFuart", .write = early_serial_write, .device = uart_console_device, .flags = CON_PRINTBUFFER, - .setup = bfin_serial_console_setup, .index = -1, .data = &bfin_serial_reg, }; diff --git a/drivers/serial/bfin_sport_uart.c b/drivers/serial/bfin_sport_uart.c index 529c0ff7952c..34b4ae0fe760 100644 --- a/drivers/serial/bfin_sport_uart.c +++ b/drivers/serial/bfin_sport_uart.c @@ -101,15 +101,16 @@ static inline void tx_one_byte(struct sport_uart_port *up, unsigned int value) { pr_debug("%s value:%x\n", __func__, value); /* Place a Start and Stop bit */ - __asm__ volatile ( - "R2 = b#01111111100;\n\t" - "R3 = b#10000000001;\n\t" - "%0 <<= 2;\n\t" - "%0 = %0 & R2;\n\t" - "%0 = %0 | R3;\n\t" - :"=r"(value) - :"0"(value) - :"R2", "R3"); + __asm__ __volatile__ ( + "R2 = b#01111111100;" + "R3 = b#10000000001;" + "%0 <<= 2;" + "%0 = %0 & R2;" + "%0 = %0 | R3;" + : "=d"(value) + : "d"(value) + : "ASTAT", "R2", "R3" + ); pr_debug("%s value:%x\n", __func__, value); SPORT_PUT_TX(up, value); @@ -118,27 +119,30 @@ static inline void tx_one_byte(struct sport_uart_port *up, unsigned int value) static inline unsigned int rx_one_byte(struct sport_uart_port *up) { unsigned int value, extract; + u32 tmp_mask1, tmp_mask2, tmp_shift, tmp; value = SPORT_GET_RX32(up); pr_debug("%s value:%x\n", __func__, value); /* Extract 8 bits data */ - __asm__ volatile ( - "R5 = 0;\n\t" - "P0 = 8;\n\t" - "R1 = 0x1801(Z);\n\t" - "R3 = 0x0300(Z);\n\t" - "R4 = 0;\n\t" - "LSETUP(loop_s, loop_e) LC0 = P0;\nloop_s:\t" - "R2 = extract(%1, R1.L)(Z);\n\t" - "R2 <<= R4;\n\t" - "R5 = R5 | R2;\n\t" - "R1 = R1 - R3;\nloop_e:\t" - "R4 += 1;\n\t" - "%0 = R5;\n\t" - :"=r"(extract) - :"r"(value) - :"P0", "R1", "R2","R3","R4", "R5"); + __asm__ __volatile__ ( + "%[extr] = 0;" + "%[mask1] = 0x1801(Z);" + "%[mask2] = 0x0300(Z);" + "%[shift] = 0;" + "LSETUP(.Lloop_s, .Lloop_e) LC0 = %[lc];" + ".Lloop_s:" + "%[tmp] = extract(%[val], %[mask1].L)(Z);" + "%[tmp] <<= %[shift];" + "%[extr] = %[extr] | %[tmp];" + "%[mask1] = %[mask1] - %[mask2];" + ".Lloop_e:" + "%[shift] += 1;" + : [val]"=d"(value), [extr]"=d"(extract), [shift]"=d"(tmp_shift), [tmp]"=d"(tmp), + [mask1]"=d"(tmp_mask1), [mask2]"=d"(tmp_mask2) + : "d"(value), [lc]"a"(8) + : "ASTAT", "LB0", "LC0", "LT0" + ); pr_debug(" extract:%x\n", extract); return extract; @@ -149,7 +153,7 @@ static int sport_uart_setup(struct sport_uart_port *up, int sclk, int baud_rate) int tclkdiv, tfsdiv, rclkdiv; /* Set TCR1 and TCR2 */ - SPORT_PUT_TCR1(up, (LTFS | ITFS | TFSR | TLSBIT | ITCLK)); + SPORT_PUT_TCR1(up, (LATFS | ITFS | TFSR | TLSBIT | ITCLK)); SPORT_PUT_TCR2(up, 10); pr_debug("%s TCR1:%x, TCR2:%x\n", __func__, SPORT_GET_TCR1(up), SPORT_GET_TCR2(up)); @@ -419,7 +423,7 @@ static void sport_shutdown(struct uart_port *port) } static void sport_set_termios(struct uart_port *port, - struct termios *termios, struct termios *old) + struct ktermios *termios, struct ktermios *old) { pr_debug("%s enter, c_cflag:%08x\n", __func__, termios->c_cflag); uart_update_timeout(port, CS8 ,port->uartclk); diff --git a/drivers/serial/icom.c b/drivers/serial/icom.c index a461b3b2c72d..cd1b6a45bb82 100644 --- a/drivers/serial/icom.c +++ b/drivers/serial/icom.c @@ -137,7 +137,12 @@ static LIST_HEAD(icom_adapter_head); static spinlock_t icom_lock; #ifdef ICOM_TRACE -static inline void trace(struct icom_port *, char *, unsigned long) {}; +static inline void trace(struct icom_port *icom_port, char *trace_pt, + unsigned long trace_data) +{ + dev_info(&icom_port->adapter->pci_dev->dev, ":%d:%s - %lx\n", + icom_port->port, trace_pt, trace_data); +} #else static inline void trace(struct icom_port *icom_port, char *trace_pt, unsigned long trace_data) {}; #endif @@ -408,7 +413,7 @@ static void load_code(struct icom_port *icom_port) release_firmware(fw); /* Set Hardware level */ - if ((icom_port->adapter->version | ADAPTER_V2) == ADAPTER_V2) + if (icom_port->adapter->version == ADAPTER_V2) writeb(V2_HARDWARE, &(icom_port->dram->misc_flags)); /* Start the processor in Adapter */ @@ -861,7 +866,7 @@ static irqreturn_t icom_interrupt(int irq, void *dev_id) /* find icom_port for this interrupt */ icom_adapter = (struct icom_adapter *) dev_id; - if ((icom_adapter->version | ADAPTER_V2) == ADAPTER_V2) { + if (icom_adapter->version == ADAPTER_V2) { int_reg = icom_adapter->base_addr + 0x8024; adapter_interrupts = readl(int_reg); @@ -1543,8 +1548,7 @@ static int __devinit icom_probe(struct pci_dev *dev, goto probe_exit1; } - icom_adapter->base_addr = ioremap(icom_adapter->base_addr_pci, - pci_resource_len(dev, 0)); + icom_adapter->base_addr = pci_ioremap_bar(dev, 0); if (!icom_adapter->base_addr) goto probe_exit1; @@ -1647,15 +1651,6 @@ static void __exit icom_exit(void) module_init(icom_init); module_exit(icom_exit); -#ifdef ICOM_TRACE -static inline void trace(struct icom_port *icom_port, char *trace_pt, - unsigned long trace_data) -{ - dev_info(&icom_port->adapter->pci_dev->dev, ":%d:%s - %lx\n", - icom_port->port, trace_pt, trace_data); -} -#endif - MODULE_AUTHOR("Michael Anderson "); MODULE_DESCRIPTION("IBM iSeries Serial IOA driver"); MODULE_SUPPORTED_DEVICE diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index 5f0be40dfdab..5d7b58f1fe42 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c @@ -8,6 +8,9 @@ * Author: Sascha Hauer * Copyright (C) 2004 Pengutronix * + * Copyright (C) 2009 emlix GmbH + * Author: Fabian Godehardt (added IrDA support for iMX) + * * 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 @@ -41,6 +44,8 @@ #include #include #include +#include +#include #include #include @@ -66,7 +71,7 @@ #define ONEMS 0xb0 /* One Millisecond register */ #define UTS 0xb4 /* UART Test Register */ #endif -#if defined(CONFIG_ARCH_IMX) || defined(CONFIG_ARCH_MX1) +#ifdef CONFIG_ARCH_MX1 #define BIPR1 0xb0 /* Incremental Preset Register 1 */ #define BIPR2 0xb4 /* Incremental Preset Register 2 */ #define BIPR3 0xb8 /* Incremental Preset Register 3 */ @@ -96,7 +101,7 @@ #define UCR1_RTSDEN (1<<5) /* RTS delta interrupt enable */ #define UCR1_SNDBRK (1<<4) /* Send break */ #define UCR1_TDMAEN (1<<3) /* Transmitter ready DMA enable */ -#if defined(CONFIG_ARCH_IMX) || defined(CONFIG_ARCH_MX1) +#ifdef CONFIG_ARCH_MX1 #define UCR1_UARTCLKEN (1<<2) /* UART clock enabled */ #endif #if defined CONFIG_ARCH_MX3 || defined CONFIG_ARCH_MX2 @@ -127,7 +132,7 @@ #define UCR3_RXDSEN (1<<6) /* Receive status interrupt enable */ #define UCR3_AIRINTEN (1<<5) /* Async IR wake interrupt enable */ #define UCR3_AWAKEN (1<<4) /* Async wake interrupt enable */ -#ifdef CONFIG_ARCH_IMX +#ifdef CONFIG_ARCH_MX1 #define UCR3_REF25 (1<<3) /* Ref freq 25 MHz, only on mx1 */ #define UCR3_REF30 (1<<2) /* Ref Freq 30 MHz, only on mx1 */ #endif @@ -148,6 +153,7 @@ #define UCR4_DREN (1<<0) /* Recv data ready interrupt enable */ #define UFCR_RXTL_SHF 0 /* Receiver trigger level shift */ #define UFCR_RFDIV (7<<7) /* Reference freq divider mask */ +#define UFCR_RFDIV_REG(x) (((x) < 7 ? 6 - (x) : 6) << 7) #define UFCR_TXTL_SHF 10 /* Transmitter trigger level shift */ #define USR1_PARITYERR (1<<15) /* Parity error interrupt flag */ #define USR1_RTSS (1<<14) /* RTS pin status */ @@ -180,13 +186,6 @@ #define UTS_SOFTRST (1<<0) /* Software reset */ /* We've been assigned a range on the "Low-density serial ports" major */ -#ifdef CONFIG_ARCH_IMX -#define SERIAL_IMX_MAJOR 204 -#define MINOR_START 41 -#define DEV_NAME "ttySMX" -#define MAX_INTERNAL_IRQ IMX_IRQS -#endif - #ifdef CONFIG_ARCH_MXC #define SERIAL_IMX_MAJOR 207 #define MINOR_START 16 @@ -211,10 +210,20 @@ struct imx_port { struct timer_list timer; unsigned int old_status; int txirq,rxirq,rtsirq; - int have_rtscts:1; + unsigned int have_rtscts:1; + unsigned int use_irda:1; + unsigned int irda_inv_rx:1; + unsigned int irda_inv_tx:1; + unsigned short trcv_delay; /* transceiver delay */ struct clk *clk; }; +#ifdef CONFIG_IRDA +#define USE_IRDA(sport) ((sport)->use_irda) +#else +#define USE_IRDA(sport) (0) +#endif + /* * Handle any change of modem status signal since we were last called. */ @@ -268,6 +277,48 @@ static void imx_stop_tx(struct uart_port *port) struct imx_port *sport = (struct imx_port *)port; unsigned long temp; + if (USE_IRDA(sport)) { + /* half duplex - wait for end of transmission */ + int n = 256; + while ((--n > 0) && + !(readl(sport->port.membase + USR2) & USR2_TXDC)) { + udelay(5); + barrier(); + } + /* + * irda transceiver - wait a bit more to avoid + * cutoff, hardware dependent + */ + udelay(sport->trcv_delay); + + /* + * half duplex - reactivate receive mode, + * flush receive pipe echo crap + */ + if (readl(sport->port.membase + USR2) & USR2_TXDC) { + temp = readl(sport->port.membase + UCR1); + temp &= ~(UCR1_TXMPTYEN | UCR1_TRDYEN); + writel(temp, sport->port.membase + UCR1); + + temp = readl(sport->port.membase + UCR4); + temp &= ~(UCR4_TCEN); + writel(temp, sport->port.membase + UCR4); + + while (readl(sport->port.membase + URXD0) & + URXD_CHARRDY) + barrier(); + + temp = readl(sport->port.membase + UCR1); + temp |= UCR1_RRDYEN; + writel(temp, sport->port.membase + UCR1); + + temp = readl(sport->port.membase + UCR4); + temp |= UCR4_DREN; + writel(temp, sport->port.membase + UCR4); + } + return; + } + temp = readl(sport->port.membase + UCR1); writel(temp & ~UCR1_TXMPTYEN, sport->port.membase + UCR1); } @@ -302,13 +353,15 @@ static inline void imx_transmit_buffer(struct imx_port *sport) /* send xmit->buf[xmit->tail] * out the port here */ writel(xmit->buf[xmit->tail], sport->port.membase + URTX0); - xmit->tail = (xmit->tail + 1) & - (UART_XMIT_SIZE - 1); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); sport->port.icount.tx++; if (uart_circ_empty(xmit)) break; } + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&sport->port); + if (uart_circ_empty(xmit)) imx_stop_tx(&sport->port); } @@ -321,9 +374,30 @@ static void imx_start_tx(struct uart_port *port) struct imx_port *sport = (struct imx_port *)port; unsigned long temp; + if (USE_IRDA(sport)) { + /* half duplex in IrDA mode; have to disable receive mode */ + temp = readl(sport->port.membase + UCR4); + temp &= ~(UCR4_DREN); + writel(temp, sport->port.membase + UCR4); + + temp = readl(sport->port.membase + UCR1); + temp &= ~(UCR1_RRDYEN); + writel(temp, sport->port.membase + UCR1); + } + temp = readl(sport->port.membase + UCR1); writel(temp | UCR1_TXMPTYEN, sport->port.membase + UCR1); + if (USE_IRDA(sport)) { + temp = readl(sport->port.membase + UCR1); + temp |= UCR1_TRDYEN; + writel(temp, sport->port.membase + UCR1); + + temp = readl(sport->port.membase + UCR4); + temp |= UCR4_TCEN; + writel(temp, sport->port.membase + UCR4); + } + if (readl(sport->port.membase + UTS) & UTS_TXEMPTY) imx_transmit_buffer(sport); } @@ -395,8 +469,7 @@ static irqreturn_t imx_rxint(int irq, void *dev_id) continue; } - if (uart_handle_sysrq_char - (&sport->port, (unsigned char)rx)) + if (uart_handle_sysrq_char(&sport->port, (unsigned char)rx)) continue; if (rx & (URXD_PRERR | URXD_OVRRUN | URXD_FRMERR) ) { @@ -471,26 +544,26 @@ static unsigned int imx_tx_empty(struct uart_port *port) */ static unsigned int imx_get_mctrl(struct uart_port *port) { - struct imx_port *sport = (struct imx_port *)port; - unsigned int tmp = TIOCM_DSR | TIOCM_CAR; + struct imx_port *sport = (struct imx_port *)port; + unsigned int tmp = TIOCM_DSR | TIOCM_CAR; - if (readl(sport->port.membase + USR1) & USR1_RTSS) - tmp |= TIOCM_CTS; + if (readl(sport->port.membase + USR1) & USR1_RTSS) + tmp |= TIOCM_CTS; - if (readl(sport->port.membase + UCR2) & UCR2_CTS) - tmp |= TIOCM_RTS; + if (readl(sport->port.membase + UCR2) & UCR2_CTS) + tmp |= TIOCM_RTS; - return tmp; + return tmp; } static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl) { - struct imx_port *sport = (struct imx_port *)port; + struct imx_port *sport = (struct imx_port *)port; unsigned long temp; temp = readl(sport->port.membase + UCR2) & ~UCR2_CTS; - if (mctrl & TIOCM_RTS) + if (mctrl & TIOCM_RTS) temp |= UCR2_CTS; writel(temp, sport->port.membase + UCR2); @@ -534,12 +607,7 @@ static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode) if(!ufcr_rfdiv) ufcr_rfdiv = 1; - if(ufcr_rfdiv >= 7) - ufcr_rfdiv = 6; - else - ufcr_rfdiv = 6 - ufcr_rfdiv; - - val |= UFCR_RFDIV & (ufcr_rfdiv << 7); + val |= UFCR_RFDIV_REG(ufcr_rfdiv); writel(val, sport->port.membase + UFCR); @@ -558,8 +626,24 @@ static int imx_startup(struct uart_port *port) * requesting IRQs */ temp = readl(sport->port.membase + UCR4); + + if (USE_IRDA(sport)) + temp |= UCR4_IRSC; + writel(temp & ~UCR4_DREN, sport->port.membase + UCR4); + if (USE_IRDA(sport)) { + /* reset fifo's and state machines */ + int i = 100; + temp = readl(sport->port.membase + UCR2); + temp &= ~UCR2_SRST; + writel(temp, sport->port.membase + UCR2); + while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) && + (--i > 0)) { + udelay(1); + } + } + /* * Allocate the IRQ(s) i.MX1 has three interrupts whereas later * chips only have one interrupt. @@ -575,12 +659,16 @@ static int imx_startup(struct uart_port *port) if (retval) goto error_out2; - retval = request_irq(sport->rtsirq, imx_rtsint, - (sport->rtsirq < MAX_INTERNAL_IRQ) ? 0 : - IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, - DRIVER_NAME, sport); - if (retval) - goto error_out3; + /* do not use RTS IRQ on IrDA */ + if (!USE_IRDA(sport)) { + retval = request_irq(sport->rtsirq, imx_rtsint, + (sport->rtsirq < MAX_INTERNAL_IRQ) ? 0 : + IRQF_TRIGGER_FALLING | + IRQF_TRIGGER_RISING, + DRIVER_NAME, sport); + if (retval) + goto error_out3; + } } else { retval = request_irq(sport->port.irq, imx_int, 0, DRIVER_NAME, sport); @@ -597,18 +685,49 @@ static int imx_startup(struct uart_port *port) temp = readl(sport->port.membase + UCR1); temp |= UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN; + + if (USE_IRDA(sport)) { + temp |= UCR1_IREN; + temp &= ~(UCR1_RTSDEN); + } + writel(temp, sport->port.membase + UCR1); temp = readl(sport->port.membase + UCR2); temp |= (UCR2_RXEN | UCR2_TXEN); writel(temp, sport->port.membase + UCR2); + if (USE_IRDA(sport)) { + /* clear RX-FIFO */ + int i = 64; + while ((--i > 0) && + (readl(sport->port.membase + URXD0) & URXD_CHARRDY)) { + barrier(); + } + } + #if defined CONFIG_ARCH_MX2 || defined CONFIG_ARCH_MX3 temp = readl(sport->port.membase + UCR3); temp |= UCR3_RXDMUXSEL; writel(temp, sport->port.membase + UCR3); #endif + if (USE_IRDA(sport)) { + temp = readl(sport->port.membase + UCR4); + if (sport->irda_inv_rx) + temp |= UCR4_INVR; + else + temp &= ~(UCR4_INVR); + writel(temp | UCR4_DREN, sport->port.membase + UCR4); + + temp = readl(sport->port.membase + UCR3); + if (sport->irda_inv_tx) + temp |= UCR3_INVT; + else + temp &= ~(UCR3_INVT); + writel(temp, sport->port.membase + UCR3); + } + /* * Enable modem status interrupts */ @@ -616,6 +735,16 @@ static int imx_startup(struct uart_port *port) imx_enable_ms(&sport->port); spin_unlock_irqrestore(&sport->port.lock,flags); + if (USE_IRDA(sport)) { + struct imxuart_platform_data *pdata; + pdata = sport->port.dev->platform_data; + sport->irda_inv_rx = pdata->irda_inv_rx; + sport->irda_inv_tx = pdata->irda_inv_tx; + sport->trcv_delay = pdata->transceiver_delay; + if (pdata->irda_enable) + pdata->irda_enable(1); + } + return 0; error_out3: @@ -633,6 +762,17 @@ static void imx_shutdown(struct uart_port *port) struct imx_port *sport = (struct imx_port *)port; unsigned long temp; + temp = readl(sport->port.membase + UCR2); + temp &= ~(UCR2_TXEN); + writel(temp, sport->port.membase + UCR2); + + if (USE_IRDA(sport)) { + struct imxuart_platform_data *pdata; + pdata = sport->port.dev->platform_data; + if (pdata->irda_enable) + pdata->irda_enable(0); + } + /* * Stop our timer. */ @@ -642,7 +782,8 @@ static void imx_shutdown(struct uart_port *port) * Free the interrupts */ if (sport->txirq > 0) { - free_irq(sport->rtsirq, sport); + if (!USE_IRDA(sport)) + free_irq(sport->rtsirq, sport); free_irq(sport->txirq, sport); free_irq(sport->rxirq, sport); } else @@ -654,6 +795,9 @@ static void imx_shutdown(struct uart_port *port) temp = readl(sport->port.membase + UCR1); temp &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN); + if (USE_IRDA(sport)) + temp &= ~(UCR1_IREN); + writel(temp, sport->port.membase + UCR1); } @@ -665,7 +809,9 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, unsigned long flags; unsigned int ucr2, old_ucr1, old_txrxen, baud, quot; unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8; - unsigned int div, num, denom, ufcr; + unsigned int div, ufcr; + unsigned long num, denom; + uint64_t tdiv64; /* * If we don't support modem control lines, don't allow @@ -761,38 +907,41 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, sport->port.membase + UCR2); old_txrxen &= (UCR2_TXEN | UCR2_RXEN); - div = sport->port.uartclk / (baud * 16); - if (div > 7) - div = 7; - if (!div) + if (USE_IRDA(sport)) { + /* + * use maximum available submodule frequency to + * avoid missing short pulses due to low sampling rate + */ div = 1; - - num = baud; - denom = port->uartclk / div / 16; - - /* shift num and denom right until they fit into 16 bits */ - while (num > 0x10000 || denom > 0x10000) { - num >>= 1; - denom >>= 1; + } else { + div = sport->port.uartclk / (baud * 16); + if (div > 7) + div = 7; + if (!div) + div = 1; } - if (num > 0) - num -= 1; - if (denom > 0) - denom -= 1; + + rational_best_approximation(16 * div * baud, sport->port.uartclk, + 1 << 16, 1 << 16, &num, &denom); + + if (port->info && port->info->port.tty) { + tdiv64 = sport->port.uartclk; + tdiv64 *= num; + do_div(tdiv64, denom * 16 * div); + tty_encode_baud_rate(sport->port.info->port.tty, + (speed_t)tdiv64, (speed_t)tdiv64); + } + + num -= 1; + denom -= 1; + + ufcr = readl(sport->port.membase + UFCR); + ufcr = (ufcr & (~UFCR_RFDIV)) | UFCR_RFDIV_REG(div); + writel(ufcr, sport->port.membase + UFCR); writel(num, sport->port.membase + UBIR); writel(denom, sport->port.membase + UBMR); - if (div == 7) - div = 6; /* 6 in RFDIV means divide by 7 */ - else - div = 6 - div; - - ufcr = readl(sport->port.membase + UFCR); - ufcr = (ufcr & (~UFCR_RFDIV)) | - (div << 7); - writel(ufcr, sport->port.membase + UFCR); - #ifdef ONEMS writel(sport->port.uartclk / div / 1000, sport->port.membase + ONEMS); #endif @@ -1072,22 +1221,22 @@ static struct uart_driver imx_reg = { static int serial_imx_suspend(struct platform_device *dev, pm_message_t state) { - struct imx_port *sport = platform_get_drvdata(dev); + struct imx_port *sport = platform_get_drvdata(dev); - if (sport) - uart_suspend_port(&imx_reg, &sport->port); + if (sport) + uart_suspend_port(&imx_reg, &sport->port); - return 0; + return 0; } static int serial_imx_resume(struct platform_device *dev) { - struct imx_port *sport = platform_get_drvdata(dev); + struct imx_port *sport = platform_get_drvdata(dev); - if (sport) - uart_resume_port(&imx_reg, &sport->port); + if (sport) + uart_resume_port(&imx_reg, &sport->port); - return 0; + return 0; } static int serial_imx_probe(struct platform_device *pdev) @@ -1143,19 +1292,29 @@ static int serial_imx_probe(struct platform_device *pdev) imx_ports[pdev->id] = sport; pdata = pdev->dev.platform_data; - if(pdata && (pdata->flags & IMXUART_HAVE_RTSCTS)) + if (pdata && (pdata->flags & IMXUART_HAVE_RTSCTS)) sport->have_rtscts = 1; +#ifdef CONFIG_IRDA + if (pdata && (pdata->flags & IMXUART_IRDA)) + sport->use_irda = 1; +#endif + if (pdata->init) { ret = pdata->init(pdev); if (ret) goto clkput; } - uart_add_one_port(&imx_reg, &sport->port); + ret = uart_add_one_port(&imx_reg, &sport->port); + if (ret) + goto deinit; platform_set_drvdata(pdev, &sport->port); return 0; +deinit: + if (pdata->exit) + pdata->exit(pdev); clkput: clk_put(sport->clk); clk_disable(sport->clk); @@ -1193,13 +1352,13 @@ static int serial_imx_remove(struct platform_device *pdev) } static struct platform_driver serial_imx_driver = { - .probe = serial_imx_probe, - .remove = serial_imx_remove, + .probe = serial_imx_probe, + .remove = serial_imx_remove, .suspend = serial_imx_suspend, .resume = serial_imx_resume, .driver = { - .name = "imx-uart", + .name = "imx-uart", .owner = THIS_MODULE, }, }; diff --git a/drivers/serial/jsm/jsm.h b/drivers/serial/jsm/jsm.h index c0a3e2734e24..4e5f3bde0461 100644 --- a/drivers/serial/jsm/jsm.h +++ b/drivers/serial/jsm/jsm.h @@ -61,6 +61,7 @@ enum { if ((DBG_##nlevel & jsm_debug)) \ dev_printk(KERN_##klevel, pdev->dev, fmt, ## args) +#define MAXLINES 256 #define MAXPORTS 8 #define MAX_STOPS_SENT 5 diff --git a/drivers/serial/jsm/jsm_tty.c b/drivers/serial/jsm/jsm_tty.c index 31496dc0a0d1..00f4577d2f7f 100644 --- a/drivers/serial/jsm/jsm_tty.c +++ b/drivers/serial/jsm/jsm_tty.c @@ -33,6 +33,8 @@ #include "jsm.h" +static DECLARE_BITMAP(linemap, MAXLINES); + static void jsm_carrier(struct jsm_channel *ch); static inline int jsm_get_mstat(struct jsm_channel *ch) @@ -433,6 +435,7 @@ int __devinit jsm_tty_init(struct jsm_board *brd) int __devinit jsm_uart_port_init(struct jsm_board *brd) { int i; + unsigned int line; struct jsm_channel *ch; if (!brd) @@ -459,9 +462,15 @@ int __devinit jsm_uart_port_init(struct jsm_board *brd) brd->channels[i]->uart_port.membase = brd->re_map_membase; brd->channels[i]->uart_port.fifosize = 16; brd->channels[i]->uart_port.ops = &jsm_ops; - brd->channels[i]->uart_port.line = brd->channels[i]->ch_portnum + brd->boardnum * 2; + line = find_first_zero_bit(linemap, MAXLINES); + if (line >= MAXLINES) { + printk(KERN_INFO "jsm: linemap is full, added device failed\n"); + continue; + } else + set_bit(line, linemap); + brd->channels[i]->uart_port.line = line; if (uart_add_one_port (&jsm_uart_driver, &brd->channels[i]->uart_port)) - printk(KERN_INFO "Added device failed\n"); + printk(KERN_INFO "jsm: add device failed\n"); else printk(KERN_INFO "Added device \n"); } @@ -494,6 +503,7 @@ int jsm_remove_uart_port(struct jsm_board *brd) ch = brd->channels[i]; + clear_bit(ch->uart_port.line, linemap); uart_remove_one_port(&jsm_uart_driver, &brd->channels[i]->uart_port); } diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c index b3feb6198d57..abbd146c50d9 100644 --- a/drivers/serial/mpc52xx_uart.c +++ b/drivers/serial/mpc52xx_uart.c @@ -76,7 +76,6 @@ #include #include -#include #include #if defined(CONFIG_SERIAL_MPC52xx_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) @@ -254,7 +253,7 @@ static unsigned long mpc52xx_getuartclk(void *p) * but the generic serial code assumes 16 * so return ipb freq / 2 */ - return mpc52xx_find_ipb_freq(p) / 2; + return mpc5xxx_get_bus_frequency(p) / 2; } static struct psc_ops mpc52xx_psc_ops = { @@ -391,7 +390,7 @@ static void mpc512x_psc_cw_restore_ints(struct uart_port *port) static unsigned long mpc512x_getuartclk(void *p) { - return mpc512x_find_ips_freq(p); + return mpc5xxx_get_bus_frequency(p); } static struct psc_ops mpc512x_psc_ops = { diff --git a/drivers/serial/msm_serial.c b/drivers/serial/msm_serial.c new file mode 100644 index 000000000000..698048f64f5e --- /dev/null +++ b/drivers/serial/msm_serial.c @@ -0,0 +1,772 @@ +/* + * drivers/serial/msm_serial.c - driver for msm7k serial device and console + * + * Copyright (C) 2007 Google, Inc. + * Author: Robert Love + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#if defined(CONFIG_SERIAL_MSM_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +# define SUPPORT_SYSRQ +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "msm_serial.h" + +struct msm_port { + struct uart_port uart; + char name[16]; + struct clk *clk; + unsigned int imr; +}; + +#define UART_TO_MSM(uart_port) ((struct msm_port *) uart_port) + +static inline void msm_write(struct uart_port *port, unsigned int val, + unsigned int off) +{ + __raw_writel(val, port->membase + off); +} + +static inline unsigned int msm_read(struct uart_port *port, unsigned int off) +{ + return __raw_readl(port->membase + off); +} + +static void msm_stop_tx(struct uart_port *port) +{ + struct msm_port *msm_port = UART_TO_MSM(port); + + msm_port->imr &= ~UART_IMR_TXLEV; + msm_write(port, msm_port->imr, UART_IMR); +} + +static void msm_start_tx(struct uart_port *port) +{ + struct msm_port *msm_port = UART_TO_MSM(port); + + msm_port->imr |= UART_IMR_TXLEV; + msm_write(port, msm_port->imr, UART_IMR); +} + +static void msm_stop_rx(struct uart_port *port) +{ + struct msm_port *msm_port = UART_TO_MSM(port); + + msm_port->imr &= ~(UART_IMR_RXLEV | UART_IMR_RXSTALE); + msm_write(port, msm_port->imr, UART_IMR); +} + +static void msm_enable_ms(struct uart_port *port) +{ + struct msm_port *msm_port = UART_TO_MSM(port); + + msm_port->imr |= UART_IMR_DELTA_CTS; + msm_write(port, msm_port->imr, UART_IMR); +} + +static void handle_rx(struct uart_port *port) +{ + struct tty_struct *tty = port->info->port.tty; + unsigned int sr; + + /* + * Handle overrun. My understanding of the hardware is that overrun + * is not tied to the RX buffer, so we handle the case out of band. + */ + if ((msm_read(port, UART_SR) & UART_SR_OVERRUN)) { + port->icount.overrun++; + tty_insert_flip_char(tty, 0, TTY_OVERRUN); + msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR); + } + + /* and now the main RX loop */ + while ((sr = msm_read(port, UART_SR)) & UART_SR_RX_READY) { + unsigned int c; + char flag = TTY_NORMAL; + + c = msm_read(port, UART_RF); + + if (sr & UART_SR_RX_BREAK) { + port->icount.brk++; + if (uart_handle_break(port)) + continue; + } else if (sr & UART_SR_PAR_FRAME_ERR) { + port->icount.frame++; + } else { + port->icount.rx++; + } + + /* Mask conditions we're ignorning. */ + sr &= port->read_status_mask; + + if (sr & UART_SR_RX_BREAK) { + flag = TTY_BREAK; + } else if (sr & UART_SR_PAR_FRAME_ERR) { + flag = TTY_FRAME; + } + + if (!uart_handle_sysrq_char(port, c)) + tty_insert_flip_char(tty, c, flag); + } + + tty_flip_buffer_push(tty); +} + +static void handle_tx(struct uart_port *port) +{ + struct circ_buf *xmit = &port->info->xmit; + struct msm_port *msm_port = UART_TO_MSM(port); + int sent_tx; + + if (port->x_char) { + msm_write(port, port->x_char, UART_TF); + port->icount.tx++; + port->x_char = 0; + } + + while (msm_read(port, UART_SR) & UART_SR_TX_READY) { + if (uart_circ_empty(xmit)) { + /* disable tx interrupts */ + msm_port->imr &= ~UART_IMR_TXLEV; + msm_write(port, msm_port->imr, UART_IMR); + break; + } + + msm_write(port, xmit->buf[xmit->tail], UART_TF); + + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + sent_tx = 1; + } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); +} + +static void handle_delta_cts(struct uart_port *port) +{ + msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR); + port->icount.cts++; + wake_up_interruptible(&port->info->delta_msr_wait); +} + +static irqreturn_t msm_irq(int irq, void *dev_id) +{ + struct uart_port *port = dev_id; + struct msm_port *msm_port = UART_TO_MSM(port); + unsigned int misr; + + spin_lock(&port->lock); + misr = msm_read(port, UART_MISR); + msm_write(port, 0, UART_IMR); /* disable interrupt */ + + if (misr & (UART_IMR_RXLEV | UART_IMR_RXSTALE)) + handle_rx(port); + if (misr & UART_IMR_TXLEV) + handle_tx(port); + if (misr & UART_IMR_DELTA_CTS) + handle_delta_cts(port); + + msm_write(port, msm_port->imr, UART_IMR); /* restore interrupt */ + spin_unlock(&port->lock); + + return IRQ_HANDLED; +} + +static unsigned int msm_tx_empty(struct uart_port *port) +{ + return (msm_read(port, UART_SR) & UART_SR_TX_EMPTY) ? TIOCSER_TEMT : 0; +} + +static unsigned int msm_get_mctrl(struct uart_port *port) +{ + return TIOCM_CAR | TIOCM_CTS | TIOCM_DSR | TIOCM_RTS; +} + +static void msm_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + unsigned int mr; + + mr = msm_read(port, UART_MR1); + + if (!(mctrl & TIOCM_RTS)) { + mr &= ~UART_MR1_RX_RDY_CTL; + msm_write(port, mr, UART_MR1); + msm_write(port, UART_CR_CMD_RESET_RFR, UART_CR); + } else { + mr |= UART_MR1_RX_RDY_CTL; + msm_write(port, mr, UART_MR1); + } +} + +static void msm_break_ctl(struct uart_port *port, int break_ctl) +{ + if (break_ctl) + msm_write(port, UART_CR_CMD_START_BREAK, UART_CR); + else + msm_write(port, UART_CR_CMD_STOP_BREAK, UART_CR); +} + +static int msm_set_baud_rate(struct uart_port *port, unsigned int baud) +{ + unsigned int baud_code, rxstale, watermark; + + switch (baud) { + case 300: + baud_code = UART_CSR_300; + rxstale = 1; + break; + case 600: + baud_code = UART_CSR_600; + rxstale = 1; + break; + case 1200: + baud_code = UART_CSR_1200; + rxstale = 1; + break; + case 2400: + baud_code = UART_CSR_2400; + rxstale = 1; + break; + case 4800: + baud_code = UART_CSR_4800; + rxstale = 1; + break; + case 9600: + baud_code = UART_CSR_9600; + rxstale = 2; + break; + case 14400: + baud_code = UART_CSR_14400; + rxstale = 3; + break; + case 19200: + baud_code = UART_CSR_19200; + rxstale = 4; + break; + case 28800: + baud_code = UART_CSR_28800; + rxstale = 6; + break; + case 38400: + baud_code = UART_CSR_38400; + rxstale = 8; + break; + case 57600: + baud_code = UART_CSR_57600; + rxstale = 16; + break; + case 115200: + default: + baud_code = UART_CSR_115200; + baud = 115200; + rxstale = 31; + break; + } + + msm_write(port, baud_code, UART_CSR); + + /* RX stale watermark */ + watermark = UART_IPR_STALE_LSB & rxstale; + watermark |= UART_IPR_RXSTALE_LAST; + watermark |= UART_IPR_STALE_TIMEOUT_MSB & (rxstale << 2); + msm_write(port, watermark, UART_IPR); + + /* set RX watermark */ + watermark = (port->fifosize * 3) / 4; + msm_write(port, watermark, UART_RFWR); + + /* set TX watermark */ + msm_write(port, 10, UART_TFWR); + + return baud; +} + +static void msm_reset(struct uart_port *port) +{ + /* reset everything */ + msm_write(port, UART_CR_CMD_RESET_RX, UART_CR); + msm_write(port, UART_CR_CMD_RESET_TX, UART_CR); + msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR); + msm_write(port, UART_CR_CMD_RESET_BREAK_INT, UART_CR); + msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR); + msm_write(port, UART_CR_CMD_SET_RFR, UART_CR); +} + +static void msm_init_clock(struct uart_port *port) +{ + struct msm_port *msm_port = UART_TO_MSM(port); + + clk_enable(msm_port->clk); + + msm_write(port, 0xC0, UART_MREG); + msm_write(port, 0xB2, UART_NREG); + msm_write(port, 0x7D, UART_DREG); + msm_write(port, 0x1C, UART_MNDREG); +} + +static int msm_startup(struct uart_port *port) +{ + struct msm_port *msm_port = UART_TO_MSM(port); + unsigned int data, rfr_level; + int ret; + + snprintf(msm_port->name, sizeof(msm_port->name), + "msm_serial%d", port->line); + + ret = request_irq(port->irq, msm_irq, IRQF_TRIGGER_HIGH, + msm_port->name, port); + if (unlikely(ret)) + return ret; + + msm_init_clock(port); + + if (likely(port->fifosize > 12)) + rfr_level = port->fifosize - 12; + else + rfr_level = port->fifosize; + + /* set automatic RFR level */ + data = msm_read(port, UART_MR1); + data &= ~UART_MR1_AUTO_RFR_LEVEL1; + data &= ~UART_MR1_AUTO_RFR_LEVEL0; + data |= UART_MR1_AUTO_RFR_LEVEL1 & (rfr_level << 2); + data |= UART_MR1_AUTO_RFR_LEVEL0 & rfr_level; + msm_write(port, data, UART_MR1); + + /* make sure that RXSTALE count is non-zero */ + data = msm_read(port, UART_IPR); + if (unlikely(!data)) { + data |= UART_IPR_RXSTALE_LAST; + data |= UART_IPR_STALE_LSB; + msm_write(port, data, UART_IPR); + } + + msm_reset(port); + + msm_write(port, 0x05, UART_CR); /* enable TX & RX */ + + /* turn on RX and CTS interrupts */ + msm_port->imr = UART_IMR_RXLEV | UART_IMR_RXSTALE | + UART_IMR_CURRENT_CTS; + msm_write(port, msm_port->imr, UART_IMR); + + return 0; +} + +static void msm_shutdown(struct uart_port *port) +{ + struct msm_port *msm_port = UART_TO_MSM(port); + + msm_port->imr = 0; + msm_write(port, 0, UART_IMR); /* disable interrupts */ + + clk_disable(msm_port->clk); + + free_irq(port->irq, port); +} + +static void msm_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + unsigned long flags; + unsigned int baud, mr; + + spin_lock_irqsave(&port->lock, flags); + + /* calculate and set baud rate */ + baud = uart_get_baud_rate(port, termios, old, 300, 115200); + baud = msm_set_baud_rate(port, baud); + if (tty_termios_baud_rate(termios)) + tty_termios_encode_baud_rate(termios, baud, baud); + + /* calculate parity */ + mr = msm_read(port, UART_MR2); + mr &= ~UART_MR2_PARITY_MODE; + if (termios->c_cflag & PARENB) { + if (termios->c_cflag & PARODD) + mr |= UART_MR2_PARITY_MODE_ODD; + else if (termios->c_cflag & CMSPAR) + mr |= UART_MR2_PARITY_MODE_SPACE; + else + mr |= UART_MR2_PARITY_MODE_EVEN; + } + + /* calculate bits per char */ + mr &= ~UART_MR2_BITS_PER_CHAR; + switch (termios->c_cflag & CSIZE) { + case CS5: + mr |= UART_MR2_BITS_PER_CHAR_5; + break; + case CS6: + mr |= UART_MR2_BITS_PER_CHAR_6; + break; + case CS7: + mr |= UART_MR2_BITS_PER_CHAR_7; + break; + case CS8: + default: + mr |= UART_MR2_BITS_PER_CHAR_8; + break; + } + + /* calculate stop bits */ + mr &= ~(UART_MR2_STOP_BIT_LEN_ONE | UART_MR2_STOP_BIT_LEN_TWO); + if (termios->c_cflag & CSTOPB) + mr |= UART_MR2_STOP_BIT_LEN_TWO; + else + mr |= UART_MR2_STOP_BIT_LEN_ONE; + + /* set parity, bits per char, and stop bit */ + msm_write(port, mr, UART_MR2); + + /* calculate and set hardware flow control */ + mr = msm_read(port, UART_MR1); + mr &= ~(UART_MR1_CTS_CTL | UART_MR1_RX_RDY_CTL); + if (termios->c_cflag & CRTSCTS) { + mr |= UART_MR1_CTS_CTL; + mr |= UART_MR1_RX_RDY_CTL; + } + msm_write(port, mr, UART_MR1); + + /* Configure status bits to ignore based on termio flags. */ + port->read_status_mask = 0; + if (termios->c_iflag & INPCK) + port->read_status_mask |= UART_SR_PAR_FRAME_ERR; + if (termios->c_iflag & (BRKINT | PARMRK)) + port->read_status_mask |= UART_SR_RX_BREAK; + + uart_update_timeout(port, termios->c_cflag, baud); + + spin_unlock_irqrestore(&port->lock, flags); +} + +static const char *msm_type(struct uart_port *port) +{ + return "MSM"; +} + +static void msm_release_port(struct uart_port *port) +{ + struct platform_device *pdev = to_platform_device(port->dev); + struct resource *resource; + resource_size_t size; + + resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (unlikely(!resource)) + return; + size = resource->end - resource->start + 1; + + release_mem_region(port->mapbase, size); + iounmap(port->membase); + port->membase = NULL; +} + +static int msm_request_port(struct uart_port *port) +{ + struct platform_device *pdev = to_platform_device(port->dev); + struct resource *resource; + resource_size_t size; + + resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (unlikely(!resource)) + return -ENXIO; + size = resource->end - resource->start + 1; + + if (unlikely(!request_mem_region(port->mapbase, size, "msm_serial"))) + return -EBUSY; + + port->membase = ioremap(port->mapbase, size); + if (!port->membase) { + release_mem_region(port->mapbase, size); + return -EBUSY; + } + + return 0; +} + +static void msm_config_port(struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE) { + port->type = PORT_MSM; + msm_request_port(port); + } +} + +static int msm_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + if (unlikely(ser->type != PORT_UNKNOWN && ser->type != PORT_MSM)) + return -EINVAL; + if (unlikely(port->irq != ser->irq)) + return -EINVAL; + return 0; +} + +static void msm_power(struct uart_port *port, unsigned int state, + unsigned int oldstate) +{ + struct msm_port *msm_port = UART_TO_MSM(port); + + switch (state) { + case 0: + clk_enable(msm_port->clk); + break; + case 3: + clk_disable(msm_port->clk); + break; + default: + printk(KERN_ERR "msm_serial: Unknown PM state %d\n", state); + } +} + +static struct uart_ops msm_uart_pops = { + .tx_empty = msm_tx_empty, + .set_mctrl = msm_set_mctrl, + .get_mctrl = msm_get_mctrl, + .stop_tx = msm_stop_tx, + .start_tx = msm_start_tx, + .stop_rx = msm_stop_rx, + .enable_ms = msm_enable_ms, + .break_ctl = msm_break_ctl, + .startup = msm_startup, + .shutdown = msm_shutdown, + .set_termios = msm_set_termios, + .type = msm_type, + .release_port = msm_release_port, + .request_port = msm_request_port, + .config_port = msm_config_port, + .verify_port = msm_verify_port, + .pm = msm_power, +}; + +static struct msm_port msm_uart_ports[] = { + { + .uart = { + .iotype = UPIO_MEM, + .ops = &msm_uart_pops, + .flags = UPF_BOOT_AUTOCONF, + .fifosize = 512, + .line = 0, + }, + }, + { + .uart = { + .iotype = UPIO_MEM, + .ops = &msm_uart_pops, + .flags = UPF_BOOT_AUTOCONF, + .fifosize = 512, + .line = 1, + }, + }, + { + .uart = { + .iotype = UPIO_MEM, + .ops = &msm_uart_pops, + .flags = UPF_BOOT_AUTOCONF, + .fifosize = 64, + .line = 2, + }, + }, +}; + +#define UART_NR ARRAY_SIZE(msm_uart_ports) + +static inline struct uart_port *get_port_from_line(unsigned int line) +{ + return &msm_uart_ports[line].uart; +} + +#ifdef CONFIG_SERIAL_MSM_CONSOLE + +static void msm_console_putchar(struct uart_port *port, int c) +{ + while (!(msm_read(port, UART_SR) & UART_SR_TX_READY)) + ; + msm_write(port, c, UART_TF); +} + +static void msm_console_write(struct console *co, const char *s, + unsigned int count) +{ + struct uart_port *port; + struct msm_port *msm_port; + + BUG_ON(co->index < 0 || co->index >= UART_NR); + + port = get_port_from_line(co->index); + msm_port = UART_TO_MSM(port); + + spin_lock(&port->lock); + uart_console_write(port, s, count, msm_console_putchar); + spin_unlock(&port->lock); +} + +static int __init msm_console_setup(struct console *co, char *options) +{ + struct uart_port *port; + int baud, flow, bits, parity; + + if (unlikely(co->index >= UART_NR || co->index < 0)) + return -ENXIO; + + port = get_port_from_line(co->index); + + if (unlikely(!port->membase)) + return -ENXIO; + + port->cons = co; + + msm_init_clock(port); + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + bits = 8; + parity = 'n'; + flow = 'n'; + msm_write(port, UART_MR2_BITS_PER_CHAR_8 | UART_MR2_STOP_BIT_LEN_ONE, + UART_MR2); /* 8N1 */ + + if (baud < 300 || baud > 115200) + baud = 115200; + msm_set_baud_rate(port, baud); + + msm_reset(port); + + printk(KERN_INFO "msm_serial: console setup on port #%d\n", port->line); + + return uart_set_options(port, co, baud, parity, bits, flow); +} + +static struct uart_driver msm_uart_driver; + +static struct console msm_console = { + .name = "ttyMSM", + .write = msm_console_write, + .device = uart_console_device, + .setup = msm_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &msm_uart_driver, +}; + +#define MSM_CONSOLE (&msm_console) + +#else +#define MSM_CONSOLE NULL +#endif + +static struct uart_driver msm_uart_driver = { + .owner = THIS_MODULE, + .driver_name = "msm_serial", + .dev_name = "ttyMSM", + .nr = UART_NR, + .cons = MSM_CONSOLE, +}; + +static int __init msm_serial_probe(struct platform_device *pdev) +{ + struct msm_port *msm_port; + struct resource *resource; + struct uart_port *port; + + if (unlikely(pdev->id < 0 || pdev->id >= UART_NR)) + return -ENXIO; + + printk(KERN_INFO "msm_serial: detected port #%d\n", pdev->id); + + port = get_port_from_line(pdev->id); + port->dev = &pdev->dev; + msm_port = UART_TO_MSM(port); + + msm_port->clk = clk_get(&pdev->dev, "uart_clk"); + if (unlikely(IS_ERR(msm_port->clk))) + return PTR_ERR(msm_port->clk); + port->uartclk = clk_get_rate(msm_port->clk); + + resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (unlikely(!resource)) + return -ENXIO; + port->mapbase = resource->start; + + port->irq = platform_get_irq(pdev, 0); + if (unlikely(port->irq < 0)) + return -ENXIO; + + platform_set_drvdata(pdev, port); + + return uart_add_one_port(&msm_uart_driver, port); +} + +static int __devexit msm_serial_remove(struct platform_device *pdev) +{ + struct msm_port *msm_port = platform_get_drvdata(pdev); + + clk_put(msm_port->clk); + + return 0; +} + +static struct platform_driver msm_platform_driver = { + .probe = msm_serial_probe, + .remove = msm_serial_remove, + .driver = { + .name = "msm_serial", + .owner = THIS_MODULE, + }, +}; + +static int __init msm_serial_init(void) +{ + int ret; + + ret = uart_register_driver(&msm_uart_driver); + if (unlikely(ret)) + return ret; + + ret = platform_driver_probe(&msm_platform_driver, msm_serial_probe); + if (unlikely(ret)) + uart_unregister_driver(&msm_uart_driver); + + printk(KERN_INFO "msm_serial: driver initialized\n"); + + return ret; +} + +static void __exit msm_serial_exit(void) +{ +#ifdef CONFIG_SERIAL_MSM_CONSOLE + unregister_console(&msm_console); +#endif + platform_driver_unregister(&msm_platform_driver); + uart_unregister_driver(&msm_uart_driver); +} + +module_init(msm_serial_init); +module_exit(msm_serial_exit); + +MODULE_AUTHOR("Robert Love "); +MODULE_DESCRIPTION("Driver for msm7x serial device"); +MODULE_LICENSE("GPL"); diff --git a/drivers/serial/msm_serial.h b/drivers/serial/msm_serial.h new file mode 100644 index 000000000000..689f1fa0e84e --- /dev/null +++ b/drivers/serial/msm_serial.h @@ -0,0 +1,117 @@ +/* + * drivers/serial/msm_serial.h + * + * Copyright (C) 2007 Google, Inc. + * Author: Robert Love + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#ifndef __DRIVERS_SERIAL_MSM_SERIAL_H +#define __DRIVERS_SERIAL_MSM_SERIAL_H + +#define UART_MR1 0x0000 + +#define UART_MR1_AUTO_RFR_LEVEL0 0x3F +#define UART_MR1_AUTO_RFR_LEVEL1 0x3FF00 +#define UART_MR1_RX_RDY_CTL (1 << 7) +#define UART_MR1_CTS_CTL (1 << 6) + +#define UART_MR2 0x0004 +#define UART_MR2_ERROR_MODE (1 << 6) +#define UART_MR2_BITS_PER_CHAR 0x30 +#define UART_MR2_BITS_PER_CHAR_5 (0x0 << 4) +#define UART_MR2_BITS_PER_CHAR_6 (0x1 << 4) +#define UART_MR2_BITS_PER_CHAR_7 (0x2 << 4) +#define UART_MR2_BITS_PER_CHAR_8 (0x3 << 4) +#define UART_MR2_STOP_BIT_LEN_ONE (0x1 << 2) +#define UART_MR2_STOP_BIT_LEN_TWO (0x3 << 2) +#define UART_MR2_PARITY_MODE_NONE 0x0 +#define UART_MR2_PARITY_MODE_ODD 0x1 +#define UART_MR2_PARITY_MODE_EVEN 0x2 +#define UART_MR2_PARITY_MODE_SPACE 0x3 +#define UART_MR2_PARITY_MODE 0x3 + +#define UART_CSR 0x0008 +#define UART_CSR_115200 0xFF +#define UART_CSR_57600 0xEE +#define UART_CSR_38400 0xDD +#define UART_CSR_28800 0xCC +#define UART_CSR_19200 0xBB +#define UART_CSR_14400 0xAA +#define UART_CSR_9600 0x99 +#define UART_CSR_4800 0x77 +#define UART_CSR_2400 0x55 +#define UART_CSR_1200 0x44 +#define UART_CSR_600 0x33 +#define UART_CSR_300 0x22 + +#define UART_TF 0x000C + +#define UART_CR 0x0010 +#define UART_CR_CMD_NULL (0 << 4) +#define UART_CR_CMD_RESET_RX (1 << 4) +#define UART_CR_CMD_RESET_TX (2 << 4) +#define UART_CR_CMD_RESET_ERR (3 << 4) +#define UART_CR_CMD_RESET_BREAK_INT (4 << 4) +#define UART_CR_CMD_START_BREAK (5 << 4) +#define UART_CR_CMD_STOP_BREAK (6 << 4) +#define UART_CR_CMD_RESET_CTS (7 << 4) +#define UART_CR_CMD_PACKET_MODE (9 << 4) +#define UART_CR_CMD_MODE_RESET (12 << 4) +#define UART_CR_CMD_SET_RFR (13 << 4) +#define UART_CR_CMD_RESET_RFR (14 << 4) +#define UART_CR_TX_DISABLE (1 << 3) +#define UART_CR_TX_ENABLE (1 << 3) +#define UART_CR_RX_DISABLE (1 << 3) +#define UART_CR_RX_ENABLE (1 << 3) + +#define UART_IMR 0x0014 +#define UART_IMR_TXLEV (1 << 0) +#define UART_IMR_RXSTALE (1 << 3) +#define UART_IMR_RXLEV (1 << 4) +#define UART_IMR_DELTA_CTS (1 << 5) +#define UART_IMR_CURRENT_CTS (1 << 6) + +#define UART_IPR_RXSTALE_LAST 0x20 +#define UART_IPR_STALE_LSB 0x1F +#define UART_IPR_STALE_TIMEOUT_MSB 0x3FF80 + +#define UART_IPR 0x0018 +#define UART_TFWR 0x001C +#define UART_RFWR 0x0020 +#define UART_HCR 0x0024 + +#define UART_MREG 0x0028 +#define UART_NREG 0x002C +#define UART_DREG 0x0030 +#define UART_MNDREG 0x0034 +#define UART_IRDA 0x0038 +#define UART_MISR_MODE 0x0040 +#define UART_MISR_RESET 0x0044 +#define UART_MISR_EXPORT 0x0048 +#define UART_MISR_VAL 0x004C +#define UART_TEST_CTRL 0x0050 + +#define UART_SR 0x0008 +#define UART_SR_HUNT_CHAR (1 << 7) +#define UART_SR_RX_BREAK (1 << 6) +#define UART_SR_PAR_FRAME_ERR (1 << 5) +#define UART_SR_OVERRUN (1 << 4) +#define UART_SR_TX_EMPTY (1 << 3) +#define UART_SR_TX_READY (1 << 2) +#define UART_SR_RX_FULL (1 << 1) +#define UART_SR_RX_READY (1 << 0) + +#define UART_RF 0x000C +#define UART_MISR 0x0010 +#define UART_ISR 0x0014 + +#endif /* __DRIVERS_SERIAL_MSM_SERIAL_H */ diff --git a/drivers/serial/of_serial.c b/drivers/serial/of_serial.c index 14f8fa9135be..02406ba6da1c 100644 --- a/drivers/serial/of_serial.c +++ b/drivers/serial/of_serial.c @@ -67,7 +67,7 @@ static int __devinit of_platform_serial_setup(struct of_device *ofdev, port->type = type; port->uartclk = *clk; port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP - | UPF_FIXED_PORT; + | UPF_FIXED_PORT | UPF_FIXED_TYPE; port->dev = &ofdev->dev; /* If current-speed was set, then try not to change it. */ if (spd) @@ -122,7 +122,7 @@ static int __devinit of_platform_serial_probe(struct of_device *ofdev, info->type = port_type; info->line = ret; - ofdev->dev.driver_data = info; + dev_set_drvdata(&ofdev->dev, info); return 0; out: kfree(info); @@ -135,7 +135,7 @@ out: */ static int of_platform_serial_remove(struct of_device *ofdev) { - struct of_serial_info *info = ofdev->dev.driver_data; + struct of_serial_info *info = dev_get_drvdata(&ofdev->dev); switch (info->type) { #ifdef CONFIG_SERIAL_8250 case PORT_8250 ... PORT_MAX_8250: diff --git a/drivers/serial/s3c2400.c b/drivers/serial/s3c2400.c index 4873f2978bd2..fb00ed5296e6 100644 --- a/drivers/serial/s3c2400.c +++ b/drivers/serial/s3c2400.c @@ -78,7 +78,7 @@ static int s3c2400_serial_probe(struct platform_device *dev) static struct platform_driver s3c2400_serial_drv = { .probe = s3c2400_serial_probe, - .remove = s3c24xx_serial_remove, + .remove = __devexit_p(s3c24xx_serial_remove), .driver = { .name = "s3c2400-uart", .owner = THIS_MODULE, diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c index 87c182ef71b8..b5d7cbcba2ae 100644 --- a/drivers/serial/s3c2410.c +++ b/drivers/serial/s3c2410.c @@ -90,7 +90,7 @@ static int s3c2410_serial_probe(struct platform_device *dev) static struct platform_driver s3c2410_serial_drv = { .probe = s3c2410_serial_probe, - .remove = s3c24xx_serial_remove, + .remove = __devexit_p(s3c24xx_serial_remove), .driver = { .name = "s3c2410-uart", .owner = THIS_MODULE, diff --git a/drivers/serial/s3c2412.c b/drivers/serial/s3c2412.c index fd017b375568..11dcb90bdfef 100644 --- a/drivers/serial/s3c2412.c +++ b/drivers/serial/s3c2412.c @@ -123,7 +123,7 @@ static int s3c2412_serial_probe(struct platform_device *dev) static struct platform_driver s3c2412_serial_drv = { .probe = s3c2412_serial_probe, - .remove = s3c24xx_serial_remove, + .remove = __devexit_p(s3c24xx_serial_remove), .driver = { .name = "s3c2412-uart", .owner = THIS_MODULE, diff --git a/drivers/serial/s3c2440.c b/drivers/serial/s3c2440.c index 29cbb0afef8e..06c5b0cc47a3 100644 --- a/drivers/serial/s3c2440.c +++ b/drivers/serial/s3c2440.c @@ -153,7 +153,7 @@ static int s3c2440_serial_probe(struct platform_device *dev) static struct platform_driver s3c2440_serial_drv = { .probe = s3c2440_serial_probe, - .remove = s3c24xx_serial_remove, + .remove = __devexit_p(s3c24xx_serial_remove), .driver = { .name = "s3c2440-uart", .owner = THIS_MODULE, diff --git a/drivers/serial/s3c24a0.c b/drivers/serial/s3c24a0.c index ebf2fd3c8f7d..786a067d62ac 100644 --- a/drivers/serial/s3c24a0.c +++ b/drivers/serial/s3c24a0.c @@ -94,7 +94,7 @@ static int s3c24a0_serial_probe(struct platform_device *dev) static struct platform_driver s3c24a0_serial_drv = { .probe = s3c24a0_serial_probe, - .remove = s3c24xx_serial_remove, + .remove = __devexit_p(s3c24xx_serial_remove), .driver = { .name = "s3c24a0-uart", .owner = THIS_MODULE, diff --git a/drivers/serial/s3c6400.c b/drivers/serial/s3c6400.c index 3e3785233682..48f1a3781f0d 100644 --- a/drivers/serial/s3c6400.c +++ b/drivers/serial/s3c6400.c @@ -124,7 +124,7 @@ static int s3c6400_serial_probe(struct platform_device *dev) static struct platform_driver s3c6400_serial_drv = { .probe = s3c6400_serial_probe, - .remove = s3c24xx_serial_remove, + .remove = __devexit_p(s3c24xx_serial_remove), .driver = { .name = "s3c6400-uart", .owner = THIS_MODULE, diff --git a/drivers/serial/samsung.c b/drivers/serial/samsung.c index 93b5d75db126..c8851a0db63a 100644 --- a/drivers/serial/samsung.c +++ b/drivers/serial/samsung.c @@ -1174,7 +1174,7 @@ int s3c24xx_serial_probe(struct platform_device *dev, EXPORT_SYMBOL_GPL(s3c24xx_serial_probe); -int s3c24xx_serial_remove(struct platform_device *dev) +int __devexit s3c24xx_serial_remove(struct platform_device *dev) { struct uart_port *port = s3c24xx_dev_to_port(&dev->dev); diff --git a/drivers/serial/samsung.h b/drivers/serial/samsung.h index 7afb94843a08..d3fe315969f6 100644 --- a/drivers/serial/samsung.h +++ b/drivers/serial/samsung.h @@ -72,7 +72,7 @@ struct s3c24xx_uart_port { extern int s3c24xx_serial_probe(struct platform_device *dev, struct s3c24xx_uart_info *uart); -extern int s3c24xx_serial_remove(struct platform_device *dev); +extern int __devexit s3c24xx_serial_remove(struct platform_device *dev); extern int s3c24xx_serial_initconsole(struct platform_driver *drv, struct s3c24xx_uart_info *uart); diff --git a/drivers/serial/sb1250-duart.c b/drivers/serial/sb1250-duart.c index a4fb343a08da..319e8b83f6be 100644 --- a/drivers/serial/sb1250-duart.c +++ b/drivers/serial/sb1250-duart.c @@ -204,7 +204,7 @@ static int sbd_receive_drain(struct sbd_port *sport) { int loops = 10000; - while (sbd_receive_ready(sport) && loops--) + while (sbd_receive_ready(sport) && --loops) read_sbdchn(sport, R_DUART_RX_HOLD); return loops; } @@ -218,7 +218,7 @@ static int __maybe_unused sbd_transmit_drain(struct sbd_port *sport) { int loops = 10000; - while (!sbd_transmit_ready(sport) && loops--) + while (!sbd_transmit_ready(sport) && --loops) udelay(2); return loops; } @@ -232,7 +232,7 @@ static int sbd_line_drain(struct sbd_port *sport) { int loops = 10000; - while (!sbd_transmit_empty(sport) && loops--) + while (!sbd_transmit_empty(sport) && --loops) udelay(2); return loops; } diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c index 7546aa887fa7..79c9c5f5cdba 100644 --- a/drivers/serial/serial_cs.c +++ b/drivers/serial/serial_cs.c @@ -681,7 +681,7 @@ static int serial_config(struct pcmcia_device * link) u_char *buf; cisparse_t *parse; cistpl_cftable_entry_t *cf; - int i; + int i, last_ret, last_fn; DEBUG(0, "serial_config(0x%p)\n", link); @@ -699,6 +699,16 @@ static int serial_config(struct pcmcia_device * link) tuple->TupleDataMax = 255; tuple->Attributes = 0; + /* Get configuration register information */ + tuple->DesiredTuple = CISTPL_CONFIG; + last_ret = first_tuple(link, tuple, parse); + if (last_ret != 0) { + last_fn = ParseTuple; + goto cs_failed; + } + link->conf.ConfigBase = parse->config.base; + link->conf.Present = parse->config.rmask[0]; + /* Is this a compliant multifunction card? */ tuple->DesiredTuple = CISTPL_LONGLINK_MFC; tuple->Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK; @@ -761,7 +771,9 @@ static int serial_config(struct pcmcia_device * link) kfree(cfg_mem); return 0; - failed: +cs_failed: + cs_error(link, last_fn, last_ret); +failed: serial_remove(link); kfree(cfg_mem); return -ENODEV; @@ -863,10 +875,10 @@ static struct pcmcia_device_id serial_ids[] = { PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "LINKSYS", "PCMLM28", 0xf7cb0b07, 0x66881874, "PCMLM28.cis"), PCMCIA_MFC_DEVICE_CIS_PROD_ID12(1, "DAYNA COMMUNICATIONS", "LAN AND MODEM MULTIFUNCTION", 0x8fdf8f89, 0xdd5ed9e8, "DP83903.cis"), PCMCIA_MFC_DEVICE_CIS_PROD_ID4(1, "NSC MF LAN/Modem", 0x58fc6056, "DP83903.cis"), - PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x0556, "3CCFEM556.cis"), + PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x0556, "cis/3CCFEM556.cis"), PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0175, 0x0000, "DP83903.cis"), - PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x0035, "3CXEM556.cis"), - PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x003d, "3CXEM556.cis"), + PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x0035, "cis/3CXEM556.cis"), + PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x003d, "cis/3CXEM556.cis"), PCMCIA_DEVICE_CIS_PROD_ID12("Sierra Wireless", "AC850", 0xd85f6206, 0x42a2c018, "SW_8xx_SER.cis"), /* Sierra Wireless AC850 3G Network Adapter R1 */ PCMCIA_DEVICE_CIS_MANF_CARD(0x0192, 0x0710, "SW_7xx_SER.cis"), /* Sierra Wireless AC710/AC750 GPRS Network Adapter R1 */ PCMCIA_DEVICE_CIS_MANF_CARD(0x0192, 0xa555, "SW_555_SER.cis"), /* Sierra Aircard 555 CDMA 1xrtt Modem -- pre update */ diff --git a/drivers/serial/serial_txx9.c b/drivers/serial/serial_txx9.c index 7313c2edcb83..54dd16d66a4b 100644 --- a/drivers/serial/serial_txx9.c +++ b/drivers/serial/serial_txx9.c @@ -461,6 +461,94 @@ static void serial_txx9_break_ctl(struct uart_port *port, int break_state) spin_unlock_irqrestore(&up->port.lock, flags); } +#if defined(CONFIG_SERIAL_TXX9_CONSOLE) || (CONFIG_CONSOLE_POLL) +/* + * Wait for transmitter & holding register to empty + */ +static void wait_for_xmitr(struct uart_txx9_port *up) +{ + unsigned int tmout = 10000; + + /* Wait up to 10ms for the character(s) to be sent. */ + while (--tmout && + !(sio_in(up, TXX9_SICISR) & TXX9_SICISR_TXALS)) + udelay(1); + + /* Wait up to 1s for flow control if necessary */ + if (up->port.flags & UPF_CONS_FLOW) { + tmout = 1000000; + while (--tmout && + (sio_in(up, TXX9_SICISR) & TXX9_SICISR_CTSS)) + udelay(1); + } +} +#endif + +#ifdef CONFIG_CONSOLE_POLL +/* + * Console polling routines for writing and reading from the uart while + * in an interrupt or debug context. + */ + +static int serial_txx9_get_poll_char(struct uart_port *port) +{ + unsigned int ier; + unsigned char c; + struct uart_txx9_port *up = (struct uart_txx9_port *)port; + + /* + * First save the IER then disable the interrupts + */ + ier = sio_in(up, TXX9_SIDICR); + sio_out(up, TXX9_SIDICR, 0); + + while (sio_in(up, TXX9_SIDISR) & TXX9_SIDISR_UVALID) + ; + + c = sio_in(up, TXX9_SIRFIFO); + + /* + * Finally, clear RX interrupt status + * and restore the IER + */ + sio_mask(up, TXX9_SIDISR, TXX9_SIDISR_RDIS); + sio_out(up, TXX9_SIDICR, ier); + return c; +} + + +static void serial_txx9_put_poll_char(struct uart_port *port, unsigned char c) +{ + unsigned int ier; + struct uart_txx9_port *up = (struct uart_txx9_port *)port; + + /* + * First save the IER then disable the interrupts + */ + ier = sio_in(up, TXX9_SIDICR); + sio_out(up, TXX9_SIDICR, 0); + + wait_for_xmitr(up); + /* + * Send the character out. + * If a LF, also do CR... + */ + sio_out(up, TXX9_SITFIFO, c); + if (c == 10) { + wait_for_xmitr(up); + sio_out(up, TXX9_SITFIFO, 13); + } + + /* + * Finally, wait for transmitter to become empty + * and restore the IER + */ + wait_for_xmitr(up); + sio_out(up, TXX9_SIDICR, ier); +} + +#endif /* CONFIG_CONSOLE_POLL */ + static int serial_txx9_startup(struct uart_port *port) { struct uart_txx9_port *up = (struct uart_txx9_port *)port; @@ -781,6 +869,10 @@ static struct uart_ops serial_txx9_pops = { .release_port = serial_txx9_release_port, .request_port = serial_txx9_request_port, .config_port = serial_txx9_config_port, +#ifdef CONFIG_CONSOLE_POLL + .poll_get_char = serial_txx9_get_poll_char, + .poll_put_char = serial_txx9_put_poll_char, +#endif }; static struct uart_txx9_port serial_txx9_ports[UART_NR]; @@ -803,27 +895,6 @@ static void __init serial_txx9_register_ports(struct uart_driver *drv, #ifdef CONFIG_SERIAL_TXX9_CONSOLE -/* - * Wait for transmitter & holding register to empty - */ -static inline void wait_for_xmitr(struct uart_txx9_port *up) -{ - unsigned int tmout = 10000; - - /* Wait up to 10ms for the character(s) to be sent. */ - while (--tmout && - !(sio_in(up, TXX9_SICISR) & TXX9_SICISR_TXALS)) - udelay(1); - - /* Wait up to 1s for flow control if necessary */ - if (up->port.flags & UPF_CONS_FLOW) { - tmout = 1000000; - while (--tmout && - (sio_in(up, TXX9_SICISR) & TXX9_SICISR_CTSS)) - udelay(1); - } -} - static void serial_txx9_console_putchar(struct uart_port *port, int ch) { struct uart_txx9_port *up = (struct uart_txx9_port *)port; diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index dbf5357a77b3..66f52674ca0c 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c @@ -47,12 +47,17 @@ #include #include #include +#include #ifdef CONFIG_SUPERH #include #include #endif +#ifdef CONFIG_H8300 +#include +#endif + #include "sh-sci.h" struct sci_port { @@ -75,14 +80,22 @@ struct sci_port { int break_flag; #ifdef CONFIG_HAVE_CLK - /* Port clock */ - struct clk *clk; + /* Interface clock */ + struct clk *iclk; + /* Data clock */ + struct clk *dclk; #endif + struct list_head node; }; -#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE -static struct sci_port *serial_console_port; +struct sh_sci_priv { + spinlock_t lock; + struct list_head ports; + +#ifdef CONFIG_HAVE_CLK + struct notifier_block clk_nb; #endif +}; /* Function prototypes */ static void sci_stop_tx(struct uart_port *port); @@ -138,9 +151,8 @@ static void sci_poll_put_char(struct uart_port *port, unsigned char c) status = sci_in(port, SCxSR); } while (!(status & SCxSR_TDxE(port))); - sci_in(port, SCxSR); /* Dummy read */ - sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port)); sci_out(port, SCxTDR, c); + sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port)); } #endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE */ @@ -159,12 +171,12 @@ static void h8300_sci_config(struct uart_port *port, unsigned int ctrl) *mstpcrl &= ~mask; } -static inline void h8300_sci_enable(struct uart_port *port) +static void h8300_sci_enable(struct uart_port *port) { h8300_sci_config(port, sci_enable); } -static inline void h8300_sci_disable(struct uart_port *port) +static void h8300_sci_disable(struct uart_port *port) { h8300_sci_config(port, sci_disable); } @@ -611,7 +623,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->port.tty; - struct sci_port *s = &sci_ports[port->line]; + struct sci_port *s = to_sci_port(port); if (uart_handle_break(port)) return 0; @@ -726,19 +738,43 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr) static int sci_notifier(struct notifier_block *self, unsigned long phase, void *p) { - int i; + struct sh_sci_priv *priv = container_of(self, + struct sh_sci_priv, clk_nb); + struct sci_port *sci_port; + unsigned long flags; if ((phase == CPUFREQ_POSTCHANGE) || - (phase == CPUFREQ_RESUMECHANGE)) - for (i = 0; i < SCI_NPORTS; i++) { - struct sci_port *s = &sci_ports[i]; - s->port.uartclk = clk_get_rate(s->clk); - } + (phase == CPUFREQ_RESUMECHANGE)) { + spin_lock_irqsave(&priv->lock, flags); + list_for_each_entry(sci_port, &priv->ports, node) + sci_port->port.uartclk = clk_get_rate(sci_port->dclk); + + spin_unlock_irqrestore(&priv->lock, flags); + } return NOTIFY_OK; } -static struct notifier_block sci_nb = { &sci_notifier, NULL, 0 }; +static void sci_clk_enable(struct uart_port *port) +{ + struct sci_port *sci_port = to_sci_port(port); + + clk_enable(sci_port->dclk); + sci_port->port.uartclk = clk_get_rate(sci_port->dclk); + + if (sci_port->iclk) + clk_enable(sci_port->iclk); +} + +static void sci_clk_disable(struct uart_port *port) +{ + struct sci_port *sci_port = to_sci_port(port); + + if (sci_port->iclk) + clk_disable(sci_port->iclk); + + clk_disable(sci_port->dclk); +} #endif static int sci_request_irq(struct sci_port *port) @@ -865,15 +901,11 @@ static void sci_break_ctl(struct uart_port *port, int break_state) static int sci_startup(struct uart_port *port) { - struct sci_port *s = &sci_ports[port->line]; + struct sci_port *s = to_sci_port(port); if (s->enable) s->enable(port); -#ifdef CONFIG_HAVE_CLK - s->clk = clk_get(NULL, "module_clk"); -#endif - sci_request_irq(s); sci_start_tx(port); sci_start_rx(port, 1); @@ -883,7 +915,7 @@ static int sci_startup(struct uart_port *port) static void sci_shutdown(struct uart_port *port) { - struct sci_port *s = &sci_ports[port->line]; + struct sci_port *s = to_sci_port(port); sci_stop_rx(port); sci_stop_tx(port); @@ -891,11 +923,6 @@ static void sci_shutdown(struct uart_port *port) if (s->disable) s->disable(port); - -#ifdef CONFIG_HAVE_CLK - clk_put(s->clk); - s->clk = NULL; -#endif } static void sci_set_termios(struct uart_port *port, struct ktermios *termios, @@ -980,25 +1007,31 @@ static int sci_request_port(struct uart_port *port) static void sci_config_port(struct uart_port *port, int flags) { - struct sci_port *s = &sci_ports[port->line]; + struct sci_port *s = to_sci_port(port); port->type = s->type; - if (port->flags & UPF_IOREMAP && !port->membase) { -#if defined(CONFIG_SUPERH64) - port->mapbase = onchip_remap(SCIF_ADDR_SH5, 1024, "SCIF"); - port->membase = (void __iomem *)port->mapbase; -#else - port->membase = ioremap_nocache(port->mapbase, 0x40); -#endif + if (port->membase) + return; - dev_err(port->dev, "can't remap port#%d\n", port->line); + if (port->flags & UPF_IOREMAP) { + port->membase = ioremap_nocache(port->mapbase, 0x40); + + if (IS_ERR(port->membase)) + dev_err(port->dev, "can't remap port#%d\n", port->line); + } else { + /* + * For the simple (and majority of) cases where we don't + * need to do any remapping, just cast the cookie + * directly. + */ + port->membase = (void __iomem *)port->mapbase; } } static int sci_verify_port(struct uart_port *port, struct serial_struct *ser) { - struct sci_port *s = &sci_ports[port->line]; + struct sci_port *s = to_sci_port(port); if (ser->irq != s->irqs[SCIx_TXI_IRQ] || ser->irq > nr_irqs) return -EINVAL; @@ -1032,63 +1065,60 @@ static struct uart_ops sci_uart_ops = { #endif }; -static void __init sci_init_ports(void) +static void __devinit sci_init_single(struct platform_device *dev, + struct sci_port *sci_port, + unsigned int index, + struct plat_sci_port *p) { - static int first = 1; - int i; - - if (!first) - return; - - first = 0; - - for (i = 0; i < SCI_NPORTS; i++) { - sci_ports[i].port.ops = &sci_uart_ops; - sci_ports[i].port.iotype = UPIO_MEM; - sci_ports[i].port.line = i; - sci_ports[i].port.fifosize = 1; + sci_port->port.ops = &sci_uart_ops; + sci_port->port.iotype = UPIO_MEM; + sci_port->port.line = index; + sci_port->port.fifosize = 1; #if defined(__H8300H__) || defined(__H8300S__) #ifdef __H8300S__ - sci_ports[i].enable = h8300_sci_enable; - sci_ports[i].disable = h8300_sci_disable; + sci_port->enable = h8300_sci_enable; + sci_port->disable = h8300_sci_disable; #endif - sci_ports[i].port.uartclk = CONFIG_CPU_CLOCK; + sci_port->port.uartclk = CONFIG_CPU_CLOCK; #elif defined(CONFIG_HAVE_CLK) - /* - * XXX: We should use a proper SCI/SCIF clock - */ - { - struct clk *clk = clk_get(NULL, "module_clk"); - sci_ports[i].port.uartclk = clk_get_rate(clk); - clk_put(clk); - } + sci_port->iclk = p->clk ? clk_get(&dev->dev, p->clk) : NULL; + sci_port->dclk = clk_get(&dev->dev, "peripheral_clk"); + sci_port->enable = sci_clk_enable; + sci_port->disable = sci_clk_disable; #else #error "Need a valid uartclk" #endif - sci_ports[i].break_timer.data = (unsigned long)&sci_ports[i]; - sci_ports[i].break_timer.function = sci_break_timer; + sci_port->break_timer.data = (unsigned long)sci_port; + sci_port->break_timer.function = sci_break_timer; + init_timer(&sci_port->break_timer); - init_timer(&sci_ports[i].break_timer); - } -} + sci_port->port.mapbase = p->mapbase; + sci_port->port.membase = p->membase; -int __init early_sci_setup(struct uart_port *port) -{ - if (unlikely(port->line > SCI_NPORTS)) - return -ENODEV; + sci_port->port.irq = p->irqs[SCIx_TXI_IRQ]; + sci_port->port.flags = p->flags; + sci_port->port.dev = &dev->dev; + sci_port->type = sci_port->port.type = p->type; - sci_init_ports(); + memcpy(&sci_port->irqs, &p->irqs, sizeof(p->irqs)); - sci_ports[port->line].port.membase = port->membase; - sci_ports[port->line].port.mapbase = port->mapbase; - sci_ports[port->line].port.type = port->type; - - return 0; } #ifdef CONFIG_SERIAL_SH_SCI_CONSOLE +static struct tty_driver *serial_console_device(struct console *co, int *index) +{ + struct uart_driver *p = &sci_uart_driver; + *index = co->index; + return p->tty_driver; +} + +static void serial_console_putchar(struct uart_port *port, int ch) +{ + sci_poll_put_char(port, ch); +} + /* * Print a string to the serial port trying not to disturb * any possible real use of the port... @@ -1096,25 +1126,27 @@ int __init early_sci_setup(struct uart_port *port) static void serial_console_write(struct console *co, const char *s, unsigned count) { - struct uart_port *port = &serial_console_port->port; + struct uart_port *port = co->data; + struct sci_port *sci_port = to_sci_port(port); unsigned short bits; - int i; - for (i = 0; i < count; i++) { - if (*s == 10) - sci_poll_put_char(port, '\r'); + if (sci_port->enable) + sci_port->enable(port); - sci_poll_put_char(port, *s++); - } + uart_console_write(port, s, count, serial_console_putchar); /* wait until fifo is empty and last bit has been transmitted */ bits = SCxSR_TDxE(port) | SCxSR_TEND(port); while ((sci_in(port, SCxSR) & bits) != bits) cpu_relax(); + + if (sci_port->disable); + sci_port->disable(port); } static int __init serial_console_setup(struct console *co, char *options) { + struct sci_port *sci_port; struct uart_port *port; int baud = 115200; int bits = 8; @@ -1130,8 +1162,9 @@ static int __init serial_console_setup(struct console *co, char *options) if (co->index >= SCI_NPORTS) co->index = 0; - serial_console_port = &sci_ports[co->index]; - port = &serial_console_port->port; + sci_port = &sci_ports[co->index]; + port = &sci_port->port; + co->data = port; /* * Also need to check port->type, we don't actually have any @@ -1141,21 +1174,11 @@ static int __init serial_console_setup(struct console *co, char *options) */ if (!port->type) return -ENODEV; - if (!port->membase || !port->mapbase) - return -ENODEV; - port->type = serial_console_port->type; + sci_config_port(port, 0); -#ifdef CONFIG_HAVE_CLK - if (!serial_console_port->clk) - serial_console_port->clk = clk_get(NULL, "module_clk"); -#endif - - if (port->flags & UPF_IOREMAP) - sci_config_port(port, 0); - - if (serial_console_port->enable) - serial_console_port->enable(port); + if (sci_port->enable) + sci_port->enable(port); if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); @@ -1166,22 +1189,21 @@ static int __init serial_console_setup(struct console *co, char *options) if (ret == 0) sci_stop_rx(port); #endif + /* TODO: disable clock */ return ret; } static struct console serial_console = { .name = "ttySC", - .device = uart_console_device, + .device = serial_console_device, .write = serial_console_write, .setup = serial_console_setup, .flags = CON_PRINTBUFFER, .index = -1, - .data = &sci_uart_driver, }; static int __init sci_console_init(void) { - sci_init_ports(); register_console(&serial_console); return 0; } @@ -1207,6 +1229,61 @@ static struct uart_driver sci_uart_driver = { .cons = SCI_CONSOLE, }; + +static int sci_remove(struct platform_device *dev) +{ + struct sh_sci_priv *priv = platform_get_drvdata(dev); + struct sci_port *p; + unsigned long flags; + +#ifdef CONFIG_HAVE_CLK + cpufreq_unregister_notifier(&priv->clk_nb, CPUFREQ_TRANSITION_NOTIFIER); +#endif + + spin_lock_irqsave(&priv->lock, flags); + list_for_each_entry(p, &priv->ports, node) + uart_remove_one_port(&sci_uart_driver, &p->port); + + spin_unlock_irqrestore(&priv->lock, flags); + + kfree(priv); + return 0; +} + +static int __devinit sci_probe_single(struct platform_device *dev, + unsigned int index, + struct plat_sci_port *p, + struct sci_port *sciport) +{ + struct sh_sci_priv *priv = platform_get_drvdata(dev); + unsigned long flags; + int ret; + + /* Sanity check */ + if (unlikely(index >= SCI_NPORTS)) { + dev_notice(&dev->dev, "Attempting to register port " + "%d when only %d are available.\n", + index+1, SCI_NPORTS); + dev_notice(&dev->dev, "Consider bumping " + "CONFIG_SERIAL_SH_SCI_NR_UARTS!\n"); + return 0; + } + + sci_init_single(dev, sciport, index, p); + + ret = uart_add_one_port(&sci_uart_driver, &sciport->port); + if (ret) + return ret; + + INIT_LIST_HEAD(&sciport->node); + + spin_lock_irqsave(&priv->lock, flags); + list_add(&sciport->node, &priv->ports); + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + /* * Register a set of serial devices attached to a platform device. The * list is terminated with a zero flags entry, which means we expect @@ -1216,57 +1293,34 @@ static struct uart_driver sci_uart_driver = { static int __devinit sci_probe(struct platform_device *dev) { struct plat_sci_port *p = dev->dev.platform_data; + struct sh_sci_priv *priv; int i, ret = -EINVAL; - for (i = 0; p && p->flags != 0; p++, i++) { - struct sci_port *sciport = &sci_ports[i]; + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; - /* Sanity check */ - if (unlikely(i == SCI_NPORTS)) { - dev_notice(&dev->dev, "Attempting to register port " - "%d when only %d are available.\n", - i+1, SCI_NPORTS); - dev_notice(&dev->dev, "Consider bumping " - "CONFIG_SERIAL_SH_SCI_NR_UARTS!\n"); - break; - } - - sciport->port.mapbase = p->mapbase; - - if (p->mapbase && !p->membase) { - if (p->flags & UPF_IOREMAP) { - p->membase = ioremap_nocache(p->mapbase, 0x40); - if (IS_ERR(p->membase)) { - ret = PTR_ERR(p->membase); - goto err_unreg; - } - } else { - /* - * For the simple (and majority of) cases - * where we don't need to do any remapping, - * just cast the cookie directly. - */ - p->membase = (void __iomem *)p->mapbase; - } - } - - sciport->port.membase = p->membase; - - sciport->port.irq = p->irqs[SCIx_TXI_IRQ]; - sciport->port.flags = p->flags; - sciport->port.dev = &dev->dev; - - sciport->type = sciport->port.type = p->type; - - memcpy(&sciport->irqs, &p->irqs, sizeof(p->irqs)); - - uart_add_one_port(&sci_uart_driver, &sciport->port); - } + INIT_LIST_HEAD(&priv->ports); + spin_lock_init(&priv->lock); + platform_set_drvdata(dev, priv); #ifdef CONFIG_HAVE_CLK - cpufreq_register_notifier(&sci_nb, CPUFREQ_TRANSITION_NOTIFIER); + priv->clk_nb.notifier_call = sci_notifier; + cpufreq_register_notifier(&priv->clk_nb, CPUFREQ_TRANSITION_NOTIFIER); #endif + if (dev->id != -1) { + ret = sci_probe_single(dev, dev->id, p, &sci_ports[dev->id]); + if (ret) + goto err_unreg; + } else { + for (i = 0; p && p->flags != 0; p++, i++) { + ret = sci_probe_single(dev, i, p, &sci_ports[i]); + if (ret) + goto err_unreg; + } + } + #ifdef CONFIG_SH_STANDARD_BIOS sh_bios_gdb_detach(); #endif @@ -1274,62 +1328,50 @@ static int __devinit sci_probe(struct platform_device *dev) return 0; err_unreg: - for (i = i - 1; i >= 0; i--) - uart_remove_one_port(&sci_uart_driver, &sci_ports[i].port); - + sci_remove(dev); return ret; } -static int __devexit sci_remove(struct platform_device *dev) +static int sci_suspend(struct device *dev) { - int i; + struct sh_sci_priv *priv = dev_get_drvdata(dev); + struct sci_port *p; + unsigned long flags; -#ifdef CONFIG_HAVE_CLK - cpufreq_unregister_notifier(&sci_nb, CPUFREQ_TRANSITION_NOTIFIER); -#endif - - for (i = 0; i < SCI_NPORTS; i++) - uart_remove_one_port(&sci_uart_driver, &sci_ports[i].port); + spin_lock_irqsave(&priv->lock, flags); + list_for_each_entry(p, &priv->ports, node) + uart_suspend_port(&sci_uart_driver, &p->port); + spin_unlock_irqrestore(&priv->lock, flags); return 0; } -static int sci_suspend(struct platform_device *dev, pm_message_t state) +static int sci_resume(struct device *dev) { - int i; + struct sh_sci_priv *priv = dev_get_drvdata(dev); + struct sci_port *p; + unsigned long flags; - for (i = 0; i < SCI_NPORTS; i++) { - struct sci_port *p = &sci_ports[i]; - - if (p->type != PORT_UNKNOWN && p->port.dev == &dev->dev) - uart_suspend_port(&sci_uart_driver, &p->port); - } + spin_lock_irqsave(&priv->lock, flags); + list_for_each_entry(p, &priv->ports, node) + uart_resume_port(&sci_uart_driver, &p->port); + spin_unlock_irqrestore(&priv->lock, flags); return 0; } -static int sci_resume(struct platform_device *dev) -{ - int i; - - for (i = 0; i < SCI_NPORTS; i++) { - struct sci_port *p = &sci_ports[i]; - - if (p->type != PORT_UNKNOWN && p->port.dev == &dev->dev) - uart_resume_port(&sci_uart_driver, &p->port); - } - - return 0; -} +static struct dev_pm_ops sci_dev_pm_ops = { + .suspend = sci_suspend, + .resume = sci_resume, +}; static struct platform_driver sci_driver = { .probe = sci_probe, .remove = __devexit_p(sci_remove), - .suspend = sci_suspend, - .resume = sci_resume, .driver = { .name = "sh-sci", .owner = THIS_MODULE, + .pm = &sci_dev_pm_ops, }, }; @@ -1339,8 +1381,6 @@ static int __init sci_init(void) printk(banner); - sci_init_ports(); - ret = uart_register_driver(&sci_uart_driver); if (likely(ret == 0)) { ret = platform_driver_register(&sci_driver); diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h index d0aa82d7fce0..38072c15b845 100644 --- a/drivers/serial/sh-sci.h +++ b/drivers/serial/sh-sci.h @@ -91,6 +91,9 @@ # define SCSPTR5 0xa4050128 # define SCIF_ORER 0x0001 /* overrun error bit */ # define SCSCR_INIT(port) 0x0038 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ +#elif defined(CONFIG_CPU_SUBTYPE_SH7724) +# define SCIF_ORER 0x0001 /* overrun error bit */ +# define SCSCR_INIT(port) 0x0038 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ #elif defined(CONFIG_CPU_SUBTYPE_SH4_202) # define SCSPTR2 0xffe80020 /* 16 bit SCIF */ # define SCIF_ORER 0x0001 /* overrun error bit */ @@ -314,7 +317,18 @@ } \ } -#define CPU_SCIF_FNS(name, scif_offset, scif_size) \ +#ifdef CONFIG_H8300 +/* h8300 don't have SCIF */ +#define CPU_SCIF_FNS(name) \ + static inline unsigned int sci_##name##_in(struct uart_port *port) \ + { \ + return 0; \ + } \ + static inline void sci_##name##_out(struct uart_port *port, unsigned int value) \ + { \ + } +#else +#define CPU_SCIF_FNS(name, scif_offset, scif_size) \ static inline unsigned int sci_##name##_in(struct uart_port *port) \ { \ SCI_IN(scif_size, scif_offset); \ @@ -323,6 +337,7 @@ { \ SCI_OUT(scif_size, scif_offset, value); \ } +#endif #define CPU_SCI_FNS(name, sci_offset, sci_size) \ static inline unsigned int sci_##name##_in(struct uart_port* port) \ @@ -360,8 +375,10 @@ sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \ h8_sci_offset, h8_sci_size) \ CPU_SCI_FNS(name, h8_sci_offset, h8_sci_size) -#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) -#elif defined(CONFIG_CPU_SUBTYPE_SH7723) +#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \ + CPU_SCIF_FNS(name) +#elif defined(CONFIG_CPU_SUBTYPE_SH7723) ||\ + defined(CONFIG_CPU_SUBTYPE_SH7724) #define SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scif_offset, sh4_scif_size) \ CPU_SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scif_offset, sh4_scif_size) #define SCIF_FNS(name, sh4_scif_offset, sh4_scif_size) \ @@ -390,7 +407,8 @@ SCIF_FNS(SCFDR, 0x1c, 16) SCIF_FNS(SCxTDR, 0x20, 8) SCIF_FNS(SCxRDR, 0x24, 8) SCIF_FNS(SCLSR, 0x24, 16) -#elif defined(CONFIG_CPU_SUBTYPE_SH7723) +#elif defined(CONFIG_CPU_SUBTYPE_SH7723) ||\ + defined(CONFIG_CPU_SUBTYPE_SH7724) SCIx_FNS(SCSMR, 0x00, 16, 0x00, 16) SCIx_FNS(SCBRR, 0x04, 8, 0x04, 8) SCIx_FNS(SCSCR, 0x08, 16, 0x08, 16) @@ -604,10 +622,21 @@ static inline int sci_rxd_in(struct uart_port *port) return ctrl_inb(SCSPTR5) & 0x0008 ? 1 : 0; /* SCIF5 */ return 1; } +#elif defined(CONFIG_CPU_SUBTYPE_SH7724) +# define SCFSR 0x0010 +# define SCASSR 0x0014 +static inline int sci_rxd_in(struct uart_port *port) +{ + if (port->type == PORT_SCIF) + return ctrl_inw((port->mapbase + SCFSR)) & SCIF_BRK ? 1 : 0; + if (port->type == PORT_SCIFA) + return ctrl_inw((port->mapbase + SCASSR)) & SCIF_BRK ? 1 : 0; + return 1; +} #elif defined(CONFIG_CPU_SUBTYPE_SH5_101) || defined(CONFIG_CPU_SUBTYPE_SH5_103) static inline int sci_rxd_in(struct uart_port *port) { - return sci_in(port, SCSPTR2)&0x0001 ? 1 : 0; /* SCIF */ + return sci_in(port, SCSPTR)&0x0001 ? 1 : 0; /* SCIF */ } #elif defined(__H8300H__) || defined(__H8300S__) static inline int sci_rxd_in(struct uart_port *port) @@ -757,7 +786,8 @@ static inline int sci_rxd_in(struct uart_port *port) defined(CONFIG_CPU_SUBTYPE_SH7720) || \ defined(CONFIG_CPU_SUBTYPE_SH7721) #define SCBRR_VALUE(bps, clk) (((clk*2)+16*bps)/(32*bps)-1) -#elif defined(CONFIG_CPU_SUBTYPE_SH7723) +#elif defined(CONFIG_CPU_SUBTYPE_SH7723) ||\ + defined(CONFIG_CPU_SUBTYPE_SH7724) static inline int scbrr_calc(struct uart_port *port, int bps, int clk) { if (port->type == PORT_SCIF) diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c index a94a2ab4b571..1df5325faab2 100644 --- a/drivers/serial/sunhv.c +++ b/drivers/serial/sunhv.c @@ -461,7 +461,7 @@ static void sunhv_console_write_paged(struct console *con, const char *s, unsign break; udelay(1); } - if (limit <= 0) + if (limit < 0) break; page_bytes -= written; ra += written; diff --git a/drivers/serial/timbuart.c b/drivers/serial/timbuart.c new file mode 100644 index 000000000000..063a313b755c --- /dev/null +++ b/drivers/serial/timbuart.c @@ -0,0 +1,526 @@ +/* + * timbuart.c timberdale FPGA UART driver + * Copyright (c) 2009 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* Supports: + * Timberdale FPGA UART + */ + +#include +#include +#include +#include +#include +#include + +#include "timbuart.h" + +struct timbuart_port { + struct uart_port port; + struct tasklet_struct tasklet; + int usedma; + u32 last_ier; + struct platform_device *dev; +}; + +static int baudrates[] = {9600, 19200, 38400, 57600, 115200, 230400, 460800, + 921600, 1843200, 3250000}; + +static void timbuart_mctrl_check(struct uart_port *port, u32 isr, u32 *ier); + +static irqreturn_t timbuart_handleinterrupt(int irq, void *devid); + +static void timbuart_stop_rx(struct uart_port *port) +{ + /* spin lock held by upper layer, disable all RX interrupts */ + u32 ier = ioread32(port->membase + TIMBUART_IER) & ~RXFLAGS; + iowrite32(ier, port->membase + TIMBUART_IER); +} + +static void timbuart_stop_tx(struct uart_port *port) +{ + /* spinlock held by upper layer, disable TX interrupt */ + u32 ier = ioread32(port->membase + TIMBUART_IER) & ~TXBAE; + iowrite32(ier, port->membase + TIMBUART_IER); +} + +static void timbuart_start_tx(struct uart_port *port) +{ + struct timbuart_port *uart = + container_of(port, struct timbuart_port, port); + + /* do not transfer anything here -> fire off the tasklet */ + tasklet_schedule(&uart->tasklet); +} + +static void timbuart_flush_buffer(struct uart_port *port) +{ + u8 ctl = ioread8(port->membase + TIMBUART_CTRL) | TIMBUART_CTRL_FLSHTX; + + iowrite8(ctl, port->membase + TIMBUART_CTRL); + iowrite32(TXBF, port->membase + TIMBUART_ISR); +} + +static void timbuart_rx_chars(struct uart_port *port) +{ + struct tty_struct *tty = port->info->port.tty; + + while (ioread32(port->membase + TIMBUART_ISR) & RXDP) { + u8 ch = ioread8(port->membase + TIMBUART_RXFIFO); + port->icount.rx++; + tty_insert_flip_char(tty, ch, TTY_NORMAL); + } + + spin_unlock(&port->lock); + tty_flip_buffer_push(port->info->port.tty); + spin_lock(&port->lock); + + dev_dbg(port->dev, "%s - total read %d bytes\n", + __func__, port->icount.rx); +} + +static void timbuart_tx_chars(struct uart_port *port) +{ + struct circ_buf *xmit = &port->info->xmit; + + while (!(ioread32(port->membase + TIMBUART_ISR) & TXBF) && + !uart_circ_empty(xmit)) { + iowrite8(xmit->buf[xmit->tail], + port->membase + TIMBUART_TXFIFO); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + } + + dev_dbg(port->dev, + "%s - total written %d bytes, CTL: %x, RTS: %x, baud: %x\n", + __func__, + port->icount.tx, + ioread8(port->membase + TIMBUART_CTRL), + port->mctrl & TIOCM_RTS, + ioread8(port->membase + TIMBUART_BAUDRATE)); +} + +static void timbuart_handle_tx_port(struct uart_port *port, u32 isr, u32 *ier) +{ + struct timbuart_port *uart = + container_of(port, struct timbuart_port, port); + struct circ_buf *xmit = &port->info->xmit; + + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) + return; + + if (port->x_char) + return; + + if (isr & TXFLAGS) { + timbuart_tx_chars(port); + /* clear all TX interrupts */ + iowrite32(TXFLAGS, port->membase + TIMBUART_ISR); + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + } else + /* Re-enable any tx interrupt */ + *ier |= uart->last_ier & TXFLAGS; + + /* enable interrupts if there are chars in the transmit buffer, + * Or if we delivered some bytes and want the almost empty interrupt + * we wake up the upper layer later when we got the interrupt + * to give it some time to go out... + */ + if (!uart_circ_empty(xmit)) + *ier |= TXBAE; + + dev_dbg(port->dev, "%s - leaving\n", __func__); +} + +void timbuart_handle_rx_port(struct uart_port *port, u32 isr, u32 *ier) +{ + if (isr & RXFLAGS) { + /* Some RX status is set */ + if (isr & RXBF) { + u8 ctl = ioread8(port->membase + TIMBUART_CTRL) | + TIMBUART_CTRL_FLSHRX; + iowrite8(ctl, port->membase + TIMBUART_CTRL); + port->icount.overrun++; + } else if (isr & (RXDP)) + timbuart_rx_chars(port); + + /* ack all RX interrupts */ + iowrite32(RXFLAGS, port->membase + TIMBUART_ISR); + } + + /* always have the RX interrupts enabled */ + *ier |= RXBAF | RXBF | RXTT; + + dev_dbg(port->dev, "%s - leaving\n", __func__); +} + +void timbuart_tasklet(unsigned long arg) +{ + struct timbuart_port *uart = (struct timbuart_port *)arg; + u32 isr, ier = 0; + + spin_lock(&uart->port.lock); + + isr = ioread32(uart->port.membase + TIMBUART_ISR); + dev_dbg(uart->port.dev, "%s ISR: %x\n", __func__, isr); + + if (!uart->usedma) + timbuart_handle_tx_port(&uart->port, isr, &ier); + + timbuart_mctrl_check(&uart->port, isr, &ier); + + if (!uart->usedma) + timbuart_handle_rx_port(&uart->port, isr, &ier); + + iowrite32(ier, uart->port.membase + TIMBUART_IER); + + spin_unlock(&uart->port.lock); + dev_dbg(uart->port.dev, "%s leaving\n", __func__); +} + +static unsigned int timbuart_tx_empty(struct uart_port *port) +{ + u32 isr = ioread32(port->membase + TIMBUART_ISR); + + return (isr & TXBE) ? TIOCSER_TEMT : 0; +} + +static unsigned int timbuart_get_mctrl(struct uart_port *port) +{ + u8 cts = ioread8(port->membase + TIMBUART_CTRL); + dev_dbg(port->dev, "%s - cts %x\n", __func__, cts); + + if (cts & TIMBUART_CTRL_CTS) + return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; + else + return TIOCM_DSR | TIOCM_CAR; +} + +static void timbuart_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + dev_dbg(port->dev, "%s - %x\n", __func__, mctrl); + + if (mctrl & TIOCM_RTS) + iowrite8(TIMBUART_CTRL_RTS, port->membase + TIMBUART_CTRL); + else + iowrite8(TIMBUART_CTRL_RTS, port->membase + TIMBUART_CTRL); +} + +static void timbuart_mctrl_check(struct uart_port *port, u32 isr, u32 *ier) +{ + unsigned int cts; + + if (isr & CTS_DELTA) { + /* ack */ + iowrite32(CTS_DELTA, port->membase + TIMBUART_ISR); + cts = timbuart_get_mctrl(port); + uart_handle_cts_change(port, cts & TIOCM_CTS); + wake_up_interruptible(&port->info->delta_msr_wait); + } + + *ier |= CTS_DELTA; +} + +static void timbuart_enable_ms(struct uart_port *port) +{ + /* N/A */ +} + +static void timbuart_break_ctl(struct uart_port *port, int ctl) +{ + /* N/A */ +} + +static int timbuart_startup(struct uart_port *port) +{ + struct timbuart_port *uart = + container_of(port, struct timbuart_port, port); + + dev_dbg(port->dev, "%s\n", __func__); + + iowrite8(TIMBUART_CTRL_FLSHRX, port->membase + TIMBUART_CTRL); + iowrite32(0x1ff, port->membase + TIMBUART_ISR); + /* Enable all but TX interrupts */ + iowrite32(RXBAF | RXBF | RXTT | CTS_DELTA, + port->membase + TIMBUART_IER); + + return request_irq(port->irq, timbuart_handleinterrupt, IRQF_SHARED, + "timb-uart", uart); +} + +static void timbuart_shutdown(struct uart_port *port) +{ + struct timbuart_port *uart = + container_of(port, struct timbuart_port, port); + dev_dbg(port->dev, "%s\n", __func__); + free_irq(port->irq, uart); + iowrite32(0, port->membase + TIMBUART_IER); +} + +static int get_bindex(int baud) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(baudrates); i++) + if (baud <= baudrates[i]) + return i; + + return -1; +} + +static void timbuart_set_termios(struct uart_port *port, + struct ktermios *termios, + struct ktermios *old) +{ + unsigned int baud; + short bindex; + unsigned long flags; + + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); + bindex = get_bindex(baud); + dev_dbg(port->dev, "%s - bindex %d\n", __func__, bindex); + + if (bindex < 0) + bindex = 0; + baud = baudrates[bindex]; + + /* The serial layer calls into this once with old = NULL when setting + up initially */ + if (old) + tty_termios_copy_hw(termios, old); + tty_termios_encode_baud_rate(termios, baud, baud); + + spin_lock_irqsave(&port->lock, flags); + iowrite8((u8)bindex, port->membase + TIMBUART_BAUDRATE); + uart_update_timeout(port, termios->c_cflag, baud); + spin_unlock_irqrestore(&port->lock, flags); +} + +static const char *timbuart_type(struct uart_port *port) +{ + return port->type == PORT_UNKNOWN ? "timbuart" : NULL; +} + +/* We do not request/release mappings of the registers here, + * currently it's done in the proble function. + */ +static void timbuart_release_port(struct uart_port *port) +{ + struct platform_device *pdev = to_platform_device(port->dev); + int size = + resource_size(platform_get_resource(pdev, IORESOURCE_MEM, 0)); + + if (port->flags & UPF_IOREMAP) { + iounmap(port->membase); + port->membase = NULL; + } + + release_mem_region(port->mapbase, size); +} + +static int timbuart_request_port(struct uart_port *port) +{ + struct platform_device *pdev = to_platform_device(port->dev); + int size = + resource_size(platform_get_resource(pdev, IORESOURCE_MEM, 0)); + + if (!request_mem_region(port->mapbase, size, "timb-uart")) + return -EBUSY; + + if (port->flags & UPF_IOREMAP) { + port->membase = ioremap(port->mapbase, size); + if (port->membase == NULL) { + release_mem_region(port->mapbase, size); + return -ENOMEM; + } + } + + return 0; +} + +static irqreturn_t timbuart_handleinterrupt(int irq, void *devid) +{ + struct timbuart_port *uart = (struct timbuart_port *)devid; + + if (ioread8(uart->port.membase + TIMBUART_IPR)) { + uart->last_ier = ioread32(uart->port.membase + TIMBUART_IER); + + /* disable interrupts, the tasklet enables them again */ + iowrite32(0, uart->port.membase + TIMBUART_IER); + + /* fire off bottom half */ + tasklet_schedule(&uart->tasklet); + + return IRQ_HANDLED; + } else + return IRQ_NONE; +} + +/* + * Configure/autoconfigure the port. + */ +static void timbuart_config_port(struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE) { + port->type = PORT_TIMBUART; + timbuart_request_port(port); + } +} + +static int timbuart_verify_port(struct uart_port *port, + struct serial_struct *ser) +{ + /* we don't want the core code to modify any port params */ + return -EINVAL; +} + +static struct uart_ops timbuart_ops = { + .tx_empty = timbuart_tx_empty, + .set_mctrl = timbuart_set_mctrl, + .get_mctrl = timbuart_get_mctrl, + .stop_tx = timbuart_stop_tx, + .start_tx = timbuart_start_tx, + .flush_buffer = timbuart_flush_buffer, + .stop_rx = timbuart_stop_rx, + .enable_ms = timbuart_enable_ms, + .break_ctl = timbuart_break_ctl, + .startup = timbuart_startup, + .shutdown = timbuart_shutdown, + .set_termios = timbuart_set_termios, + .type = timbuart_type, + .release_port = timbuart_release_port, + .request_port = timbuart_request_port, + .config_port = timbuart_config_port, + .verify_port = timbuart_verify_port +}; + +static struct uart_driver timbuart_driver = { + .owner = THIS_MODULE, + .driver_name = "timberdale_uart", + .dev_name = "ttyTU", + .major = TIMBUART_MAJOR, + .minor = TIMBUART_MINOR, + .nr = 1 +}; + +static int timbuart_probe(struct platform_device *dev) +{ + int err; + struct timbuart_port *uart; + struct resource *iomem; + + dev_dbg(&dev->dev, "%s\n", __func__); + + uart = kzalloc(sizeof(*uart), GFP_KERNEL); + if (!uart) { + err = -EINVAL; + goto err_mem; + } + + uart->usedma = 0; + + uart->port.uartclk = 3250000 * 16; + uart->port.fifosize = TIMBUART_FIFO_SIZE; + uart->port.regshift = 2; + uart->port.iotype = UPIO_MEM; + uart->port.ops = &timbuart_ops; + uart->port.irq = 0; + uart->port.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP; + uart->port.line = 0; + uart->port.dev = &dev->dev; + + iomem = platform_get_resource(dev, IORESOURCE_MEM, 0); + if (!iomem) { + err = -ENOMEM; + goto err_register; + } + uart->port.mapbase = iomem->start; + uart->port.membase = NULL; + + uart->port.irq = platform_get_irq(dev, 0); + if (uart->port.irq < 0) { + err = -EINVAL; + goto err_register; + } + + tasklet_init(&uart->tasklet, timbuart_tasklet, (unsigned long)uart); + + err = uart_register_driver(&timbuart_driver); + if (err) + goto err_register; + + err = uart_add_one_port(&timbuart_driver, &uart->port); + if (err) + goto err_add_port; + + platform_set_drvdata(dev, uart); + + return 0; + +err_add_port: + uart_unregister_driver(&timbuart_driver); +err_register: + kfree(uart); +err_mem: + printk(KERN_ERR "timberdale: Failed to register Timberdale UART: %d\n", + err); + + return err; +} + +static int timbuart_remove(struct platform_device *dev) +{ + struct timbuart_port *uart = platform_get_drvdata(dev); + + tasklet_kill(&uart->tasklet); + uart_remove_one_port(&timbuart_driver, &uart->port); + uart_unregister_driver(&timbuart_driver); + kfree(uart); + + return 0; +} + +static struct platform_driver timbuart_platform_driver = { + .driver = { + .name = "timb-uart", + .owner = THIS_MODULE, + }, + .probe = timbuart_probe, + .remove = timbuart_remove, +}; + +/*--------------------------------------------------------------------------*/ + +static int __init timbuart_init(void) +{ + return platform_driver_register(&timbuart_platform_driver); +} + +static void __exit timbuart_exit(void) +{ + platform_driver_unregister(&timbuart_platform_driver); +} + +module_init(timbuart_init); +module_exit(timbuart_exit); + +MODULE_DESCRIPTION("Timberdale UART driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:timb-uart"); + diff --git a/drivers/serial/timbuart.h b/drivers/serial/timbuart.h new file mode 100644 index 000000000000..7e566766bc43 --- /dev/null +++ b/drivers/serial/timbuart.h @@ -0,0 +1,58 @@ +/* + * timbuart.c timberdale FPGA GPIO driver + * Copyright (c) 2009 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* Supports: + * Timberdale FPGA UART + */ + +#ifndef _TIMBUART_H +#define _TIMBUART_H + +#define TIMBUART_FIFO_SIZE 2048 + +#define TIMBUART_RXFIFO 0x08 +#define TIMBUART_TXFIFO 0x0c +#define TIMBUART_IER 0x10 +#define TIMBUART_IPR 0x14 +#define TIMBUART_ISR 0x18 +#define TIMBUART_CTRL 0x1c +#define TIMBUART_BAUDRATE 0x20 + +#define TIMBUART_CTRL_RTS 0x01 +#define TIMBUART_CTRL_CTS 0x02 +#define TIMBUART_CTRL_FLSHTX 0x40 +#define TIMBUART_CTRL_FLSHRX 0x80 + +#define TXBF 0x01 +#define TXBAE 0x02 +#define CTS_DELTA 0x04 +#define RXDP 0x08 +#define RXBAF 0x10 +#define RXBF 0x20 +#define RXTT 0x40 +#define RXBNAE 0x80 +#define TXBE 0x100 + +#define RXFLAGS (RXDP | RXBAF | RXBF | RXTT | RXBNAE) +#define TXFLAGS (TXBF | TXBAE) + +#define TIMBUART_MAJOR 204 +#define TIMBUART_MINOR 192 + +#endif /* _TIMBUART_H */ + diff --git a/drivers/serial/ucc_uart.c b/drivers/serial/ucc_uart.c index 7de66c06b05d..e945e780b5c9 100644 --- a/drivers/serial/ucc_uart.c +++ b/drivers/serial/ucc_uart.c @@ -681,22 +681,27 @@ static void qe_uart_init_ucc(struct uart_qe_port *qe_port) out_be16(&uccup->rccm, 0xc0ff); /* Configure the GUMR registers for UART */ - if (soft_uart) + if (soft_uart) { /* Soft-UART requires a 1X multiplier for TX */ clrsetbits_be32(&uccp->gumr_l, UCC_SLOW_GUMR_L_MODE_MASK | UCC_SLOW_GUMR_L_TDCR_MASK | UCC_SLOW_GUMR_L_RDCR_MASK, UCC_SLOW_GUMR_L_MODE_UART | UCC_SLOW_GUMR_L_TDCR_1 | UCC_SLOW_GUMR_L_RDCR_16); - else + + clrsetbits_be32(&uccp->gumr_h, UCC_SLOW_GUMR_H_RFW, + UCC_SLOW_GUMR_H_TRX | UCC_SLOW_GUMR_H_TTX); + } else { clrsetbits_be32(&uccp->gumr_l, UCC_SLOW_GUMR_L_MODE_MASK | UCC_SLOW_GUMR_L_TDCR_MASK | UCC_SLOW_GUMR_L_RDCR_MASK, UCC_SLOW_GUMR_L_MODE_UART | UCC_SLOW_GUMR_L_TDCR_16 | UCC_SLOW_GUMR_L_RDCR_16); - clrsetbits_be32(&uccp->gumr_h, UCC_SLOW_GUMR_H_RFW, - UCC_SLOW_GUMR_H_TRX | UCC_SLOW_GUMR_H_TTX); + clrsetbits_be32(&uccp->gumr_h, + UCC_SLOW_GUMR_H_TRX | UCC_SLOW_GUMR_H_TTX, + UCC_SLOW_GUMR_H_RFW); + } #ifdef LOOPBACK clrsetbits_be32(&uccp->gumr_l, UCC_SLOW_GUMR_L_DIAG_MASK, @@ -706,7 +711,7 @@ static void qe_uart_init_ucc(struct uart_qe_port *qe_port) UCC_SLOW_GUMR_H_CDS); #endif - /* Enable rx interrupts and clear all pending events. */ + /* Disable rx interrupts and clear all pending events. */ out_be16(&uccp->uccm, 0); out_be16(&uccp->ucce, 0xffff); out_be16(&uccp->udsr, 0x7e7e); @@ -765,6 +770,10 @@ static void qe_uart_init_ucc(struct uart_qe_port *qe_port) cecr_subblock = ucc_slow_get_qe_cr_subblock(qe_port->ucc_num); qe_issue_cmd(QE_INIT_TX_RX, cecr_subblock, QE_CR_PROTOCOL_UNSPECIFIED, 0); + } else { + cecr_subblock = ucc_slow_get_qe_cr_subblock(qe_port->ucc_num); + qe_issue_cmd(QE_INIT_TX_RX, cecr_subblock, + QE_CR_PROTOCOL_UART, 0); } } diff --git a/drivers/serial/zs.c b/drivers/serial/zs.c index 9e6a873f8203..d8c2809b1ab6 100644 --- a/drivers/serial/zs.c +++ b/drivers/serial/zs.c @@ -231,7 +231,7 @@ static int zs_receive_drain(struct zs_port *zport) { int loops = 10000; - while ((read_zsreg(zport, R0) & Rx_CH_AV) && loops--) + while ((read_zsreg(zport, R0) & Rx_CH_AV) && --loops) read_zsdata(zport); return loops; } @@ -241,7 +241,7 @@ static int zs_transmit_drain(struct zs_port *zport, int irq) struct zs_scc *scc = zport->scc; int loops = 10000; - while (!(read_zsreg(zport, R0) & Tx_BUF_EMP) && loops--) { + while (!(read_zsreg(zport, R0) & Tx_BUF_EMP) && --loops) { zs_spin_unlock_cond_irq(&scc->zlock, irq); udelay(2); zs_spin_lock_cond_irq(&scc->zlock, irq); @@ -254,7 +254,7 @@ static int zs_line_drain(struct zs_port *zport, int irq) struct zs_scc *scc = zport->scc; int loops = 10000; - while (!(read_zsreg(zport, R1) & ALL_SNT) && loops--) { + while (!(read_zsreg(zport, R1) & ALL_SNT) && --loops) { zs_spin_unlock_cond_irq(&scc->zlock, irq); udelay(2); zs_spin_lock_cond_irq(&scc->zlock, irq); diff --git a/drivers/sh/intc.c b/drivers/sh/intc.c index 12d13d99b6f0..3dd231a643b5 100644 --- a/drivers/sh/intc.c +++ b/drivers/sh/intc.c @@ -20,10 +20,10 @@ #include #include #include -#include #include #include #include +#include #define _INTC_MK(fn, mode, addr_e, addr_d, width, shift) \ ((shift) | ((width) << 5) | ((fn) << 9) | ((mode) << 13) | \ @@ -674,7 +674,7 @@ void __init register_intc_controller(struct intc_desc *desc) unsigned int i, k, smp; struct intc_desc_int *d; - d = alloc_bootmem(sizeof(*d)); + d = kzalloc(sizeof(*d), GFP_NOWAIT); INIT_LIST_HEAD(&d->list); list_add(&d->list, &intc_list); @@ -686,9 +686,9 @@ void __init register_intc_controller(struct intc_desc *desc) #if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A) d->nr_reg += desc->ack_regs ? desc->nr_ack_regs : 0; #endif - d->reg = alloc_bootmem(d->nr_reg * sizeof(*d->reg)); + d->reg = kzalloc(d->nr_reg * sizeof(*d->reg), GFP_NOWAIT); #ifdef CONFIG_SMP - d->smp = alloc_bootmem(d->nr_reg * sizeof(*d->smp)); + d->smp = kzalloc(d->nr_reg * sizeof(*d->smp), GFP_NOWAIT); #endif k = 0; @@ -701,7 +701,7 @@ void __init register_intc_controller(struct intc_desc *desc) } if (desc->prio_regs) { - d->prio = alloc_bootmem(desc->nr_vectors * sizeof(*d->prio)); + d->prio = kzalloc(desc->nr_vectors * sizeof(*d->prio), GFP_NOWAIT); for (i = 0; i < desc->nr_prio_regs; i++) { smp = IS_SMP(desc->prio_regs[i]); @@ -711,7 +711,7 @@ void __init register_intc_controller(struct intc_desc *desc) } if (desc->sense_regs) { - d->sense = alloc_bootmem(desc->nr_vectors * sizeof(*d->sense)); + d->sense = kzalloc(desc->nr_vectors * sizeof(*d->sense), GFP_NOWAIT); for (i = 0; i < desc->nr_sense_regs; i++) { k += save_reg(d, k, desc->sense_regs[i].reg, 0); @@ -756,7 +756,7 @@ void __init register_intc_controller(struct intc_desc *desc) vect2->enum_id = 0; if (!intc_evt2irq_table) - intc_evt2irq_table = alloc_bootmem(NR_IRQS); + intc_evt2irq_table = kzalloc(NR_IRQS, GFP_NOWAIT); if (!intc_evt2irq_table) { pr_warning("intc: cannot allocate evt2irq!\n"); @@ -770,11 +770,19 @@ void __init register_intc_controller(struct intc_desc *desc) /* register the vectors one by one */ for (i = 0; i < desc->nr_vectors; i++) { struct intc_vect *vect = desc->vectors + i; + unsigned int irq = evt2irq(vect->vect); + struct irq_desc *irq_desc; if (!vect->enum_id) continue; - intc_register_irq(desc, d, vect->enum_id, evt2irq(vect->vect)); + irq_desc = irq_to_desc_alloc_node(irq, numa_node_id()); + if (unlikely(!irq_desc)) { + printk(KERN_INFO "can not get irq_desc for %d\n", irq); + continue; + } + + intc_register_irq(desc, d, vect->enum_id, irq); } } diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 83a185d52961..2c733c27db2f 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -118,7 +118,7 @@ config SPI_GPIO config SPI_IMX tristate "Freescale iMX SPI controller" - depends on ARCH_IMX && EXPERIMENTAL + depends on ARCH_MX1 && EXPERIMENTAL help This enables using the Freescale iMX SPI controller in master mode. @@ -139,17 +139,15 @@ config SPI_MPC52xx_PSC This enables using the Freescale MPC52xx Programmable Serial Controller in master SPI mode. -config SPI_MPC83xx - tristate "Freescale MPC83xx/QUICC Engine SPI controller" - depends on (PPC_83xx || QUICC_ENGINE) && EXPERIMENTAL +config SPI_MPC8xxx + tristate "Freescale MPC8xxx SPI controller" + depends on FSL_SOC help - This enables using the Freescale MPC83xx and QUICC Engine SPI - controllers in master mode. + This enables using the Freescale MPC8xxx SPI controllers in master + mode. - Note, this driver uniquely supports the SPI controller on the MPC83xx - family of PowerPC processors, plus processors with QUICC Engine - technology. This driver uses a simple set of shift registers for data - (opposed to the CPM based descriptor model). + This driver uses a simple set of shift registers for data (opposed + to the CPM based descriptor model). config SPI_OMAP_UWIRE tristate "OMAP1 MicroWire" @@ -171,6 +169,15 @@ config SPI_ORION help This enables using the SPI master controller on the Orion chips. +config SPI_PL022 + tristate "ARM AMBA PL022 SSP controller (EXPERIMENTAL)" + depends on ARM_AMBA && EXPERIMENTAL + default y if MACH_U300 + help + This selects the ARM(R) AMBA(R) PrimeCell PL022 SSP + controller. If you have an embedded system with an AMBA(R) + bus and a PL022 controller, say Y or M here. + config SPI_PXA2XX tristate "PXA2xx SSP SPI master" depends on ARCH_PXA && EXPERIMENTAL @@ -212,7 +219,7 @@ config SPI_TXX9 config SPI_XILINX tristate "Xilinx SPI controller" - depends on XILINX_VIRTEX && EXPERIMENTAL + depends on (XILINX_VIRTEX || MICROBLAZE) && EXPERIMENTAL select SPI_BITBANG help This exposes the SPI controller IP from the Xilinx EDK. diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 5d0451936d86..3de408d294ba 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -23,8 +23,9 @@ obj-$(CONFIG_SPI_PXA2XX) += pxa2xx_spi.o obj-$(CONFIG_SPI_OMAP_UWIRE) += omap_uwire.o obj-$(CONFIG_SPI_OMAP24XX) += omap2_mcspi.o obj-$(CONFIG_SPI_ORION) += orion_spi.o +obj-$(CONFIG_SPI_PL022) += amba-pl022.o obj-$(CONFIG_SPI_MPC52xx_PSC) += mpc52xx_psc_spi.o -obj-$(CONFIG_SPI_MPC83xx) += spi_mpc83xx.o +obj-$(CONFIG_SPI_MPC8xxx) += spi_mpc8xxx.o obj-$(CONFIG_SPI_S3C24XX_GPIO) += spi_s3c24xx_gpio.o obj-$(CONFIG_SPI_S3C24XX) += spi_s3c24xx.o obj-$(CONFIG_SPI_TXX9) += spi_txx9.o diff --git a/drivers/spi/amba-pl022.c b/drivers/spi/amba-pl022.c new file mode 100644 index 000000000000..da76797ce8b9 --- /dev/null +++ b/drivers/spi/amba-pl022.c @@ -0,0 +1,1866 @@ +/* + * drivers/spi/amba-pl022.c + * + * A driver for the ARM PL022 PrimeCell SSP/SPI bus master. + * + * Copyright (C) 2008-2009 ST-Ericsson AB + * Copyright (C) 2006 STMicroelectronics Pvt. Ltd. + * + * Author: Linus Walleij + * + * Initial version inspired by: + * linux-2.6.17-rc3-mm1/drivers/spi/pxa2xx_spi.c + * Initial adoption to PL022 by: + * Sachin Verma + * + * 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. + */ + +/* + * TODO: + * - add timeout on polled transfers + * - add generic DMA framework support + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * This macro is used to define some register default values. + * reg is masked with mask, the OR:ed with an (again masked) + * val shifted sb steps to the left. + */ +#define SSP_WRITE_BITS(reg, val, mask, sb) \ + ((reg) = (((reg) & ~(mask)) | (((val)<<(sb)) & (mask)))) + +/* + * This macro is also used to define some default values. + * It will just shift val by sb steps to the left and mask + * the result with mask. + */ +#define GEN_MASK_BITS(val, mask, sb) \ + (((val)<<(sb)) & (mask)) + +#define DRIVE_TX 0 +#define DO_NOT_DRIVE_TX 1 + +#define DO_NOT_QUEUE_DMA 0 +#define QUEUE_DMA 1 + +#define RX_TRANSFER 1 +#define TX_TRANSFER 2 + +/* + * Macros to access SSP Registers with their offsets + */ +#define SSP_CR0(r) (r + 0x000) +#define SSP_CR1(r) (r + 0x004) +#define SSP_DR(r) (r + 0x008) +#define SSP_SR(r) (r + 0x00C) +#define SSP_CPSR(r) (r + 0x010) +#define SSP_IMSC(r) (r + 0x014) +#define SSP_RIS(r) (r + 0x018) +#define SSP_MIS(r) (r + 0x01C) +#define SSP_ICR(r) (r + 0x020) +#define SSP_DMACR(r) (r + 0x024) +#define SSP_ITCR(r) (r + 0x080) +#define SSP_ITIP(r) (r + 0x084) +#define SSP_ITOP(r) (r + 0x088) +#define SSP_TDR(r) (r + 0x08C) + +#define SSP_PID0(r) (r + 0xFE0) +#define SSP_PID1(r) (r + 0xFE4) +#define SSP_PID2(r) (r + 0xFE8) +#define SSP_PID3(r) (r + 0xFEC) + +#define SSP_CID0(r) (r + 0xFF0) +#define SSP_CID1(r) (r + 0xFF4) +#define SSP_CID2(r) (r + 0xFF8) +#define SSP_CID3(r) (r + 0xFFC) + +/* + * SSP Control Register 0 - SSP_CR0 + */ +#define SSP_CR0_MASK_DSS (0x1FUL << 0) +#define SSP_CR0_MASK_HALFDUP (0x1UL << 5) +#define SSP_CR0_MASK_SPO (0x1UL << 6) +#define SSP_CR0_MASK_SPH (0x1UL << 7) +#define SSP_CR0_MASK_SCR (0xFFUL << 8) +#define SSP_CR0_MASK_CSS (0x1FUL << 16) +#define SSP_CR0_MASK_FRF (0x3UL << 21) + +/* + * SSP Control Register 0 - SSP_CR1 + */ +#define SSP_CR1_MASK_LBM (0x1UL << 0) +#define SSP_CR1_MASK_SSE (0x1UL << 1) +#define SSP_CR1_MASK_MS (0x1UL << 2) +#define SSP_CR1_MASK_SOD (0x1UL << 3) +#define SSP_CR1_MASK_RENDN (0x1UL << 4) +#define SSP_CR1_MASK_TENDN (0x1UL << 5) +#define SSP_CR1_MASK_MWAIT (0x1UL << 6) +#define SSP_CR1_MASK_RXIFLSEL (0x7UL << 7) +#define SSP_CR1_MASK_TXIFLSEL (0x7UL << 10) + +/* + * SSP Data Register - SSP_DR + */ +#define SSP_DR_MASK_DATA 0xFFFFFFFF + +/* + * SSP Status Register - SSP_SR + */ +#define SSP_SR_MASK_TFE (0x1UL << 0) /* Transmit FIFO empty */ +#define SSP_SR_MASK_TNF (0x1UL << 1) /* Transmit FIFO not full */ +#define SSP_SR_MASK_RNE (0x1UL << 2) /* Receive FIFO not empty */ +#define SSP_SR_MASK_RFF (0x1UL << 3) /* Receive FIFO full */ +#define SSP_SR_MASK_BSY (0x1UL << 4) /* Busy Flag */ + +/* + * SSP Clock Prescale Register - SSP_CPSR + */ +#define SSP_CPSR_MASK_CPSDVSR (0xFFUL << 0) + +/* + * SSP Interrupt Mask Set/Clear Register - SSP_IMSC + */ +#define SSP_IMSC_MASK_RORIM (0x1UL << 0) /* Receive Overrun Interrupt mask */ +#define SSP_IMSC_MASK_RTIM (0x1UL << 1) /* Receive timeout Interrupt mask */ +#define SSP_IMSC_MASK_RXIM (0x1UL << 2) /* Receive FIFO Interrupt mask */ +#define SSP_IMSC_MASK_TXIM (0x1UL << 3) /* Transmit FIFO Interrupt mask */ + +/* + * SSP Raw Interrupt Status Register - SSP_RIS + */ +/* Receive Overrun Raw Interrupt status */ +#define SSP_RIS_MASK_RORRIS (0x1UL << 0) +/* Receive Timeout Raw Interrupt status */ +#define SSP_RIS_MASK_RTRIS (0x1UL << 1) +/* Receive FIFO Raw Interrupt status */ +#define SSP_RIS_MASK_RXRIS (0x1UL << 2) +/* Transmit FIFO Raw Interrupt status */ +#define SSP_RIS_MASK_TXRIS (0x1UL << 3) + +/* + * SSP Masked Interrupt Status Register - SSP_MIS + */ +/* Receive Overrun Masked Interrupt status */ +#define SSP_MIS_MASK_RORMIS (0x1UL << 0) +/* Receive Timeout Masked Interrupt status */ +#define SSP_MIS_MASK_RTMIS (0x1UL << 1) +/* Receive FIFO Masked Interrupt status */ +#define SSP_MIS_MASK_RXMIS (0x1UL << 2) +/* Transmit FIFO Masked Interrupt status */ +#define SSP_MIS_MASK_TXMIS (0x1UL << 3) + +/* + * SSP Interrupt Clear Register - SSP_ICR + */ +/* Receive Overrun Raw Clear Interrupt bit */ +#define SSP_ICR_MASK_RORIC (0x1UL << 0) +/* Receive Timeout Clear Interrupt bit */ +#define SSP_ICR_MASK_RTIC (0x1UL << 1) + +/* + * SSP DMA Control Register - SSP_DMACR + */ +/* Receive DMA Enable bit */ +#define SSP_DMACR_MASK_RXDMAE (0x1UL << 0) +/* Transmit DMA Enable bit */ +#define SSP_DMACR_MASK_TXDMAE (0x1UL << 1) + +/* + * SSP Integration Test control Register - SSP_ITCR + */ +#define SSP_ITCR_MASK_ITEN (0x1UL << 0) +#define SSP_ITCR_MASK_TESTFIFO (0x1UL << 1) + +/* + * SSP Integration Test Input Register - SSP_ITIP + */ +#define ITIP_MASK_SSPRXD (0x1UL << 0) +#define ITIP_MASK_SSPFSSIN (0x1UL << 1) +#define ITIP_MASK_SSPCLKIN (0x1UL << 2) +#define ITIP_MASK_RXDMAC (0x1UL << 3) +#define ITIP_MASK_TXDMAC (0x1UL << 4) +#define ITIP_MASK_SSPTXDIN (0x1UL << 5) + +/* + * SSP Integration Test output Register - SSP_ITOP + */ +#define ITOP_MASK_SSPTXD (0x1UL << 0) +#define ITOP_MASK_SSPFSSOUT (0x1UL << 1) +#define ITOP_MASK_SSPCLKOUT (0x1UL << 2) +#define ITOP_MASK_SSPOEn (0x1UL << 3) +#define ITOP_MASK_SSPCTLOEn (0x1UL << 4) +#define ITOP_MASK_RORINTR (0x1UL << 5) +#define ITOP_MASK_RTINTR (0x1UL << 6) +#define ITOP_MASK_RXINTR (0x1UL << 7) +#define ITOP_MASK_TXINTR (0x1UL << 8) +#define ITOP_MASK_INTR (0x1UL << 9) +#define ITOP_MASK_RXDMABREQ (0x1UL << 10) +#define ITOP_MASK_RXDMASREQ (0x1UL << 11) +#define ITOP_MASK_TXDMABREQ (0x1UL << 12) +#define ITOP_MASK_TXDMASREQ (0x1UL << 13) + +/* + * SSP Test Data Register - SSP_TDR + */ +#define TDR_MASK_TESTDATA (0xFFFFFFFF) + +/* + * Message State + * we use the spi_message.state (void *) pointer to + * hold a single state value, that's why all this + * (void *) casting is done here. + */ +#define STATE_START ((void *) 0) +#define STATE_RUNNING ((void *) 1) +#define STATE_DONE ((void *) 2) +#define STATE_ERROR ((void *) -1) + +/* + * Queue State + */ +#define QUEUE_RUNNING (0) +#define QUEUE_STOPPED (1) +/* + * SSP State - Whether Enabled or Disabled + */ +#define SSP_DISABLED (0) +#define SSP_ENABLED (1) + +/* + * SSP DMA State - Whether DMA Enabled or Disabled + */ +#define SSP_DMA_DISABLED (0) +#define SSP_DMA_ENABLED (1) + +/* + * SSP Clock Defaults + */ +#define NMDK_SSP_DEFAULT_CLKRATE 0x2 +#define NMDK_SSP_DEFAULT_PRESCALE 0x40 + +/* + * SSP Clock Parameter ranges + */ +#define CPSDVR_MIN 0x02 +#define CPSDVR_MAX 0xFE +#define SCR_MIN 0x00 +#define SCR_MAX 0xFF + +/* + * SSP Interrupt related Macros + */ +#define DEFAULT_SSP_REG_IMSC 0x0UL +#define DISABLE_ALL_INTERRUPTS DEFAULT_SSP_REG_IMSC +#define ENABLE_ALL_INTERRUPTS (~DEFAULT_SSP_REG_IMSC) + +#define CLEAR_ALL_INTERRUPTS 0x3 + + +/* + * The type of reading going on on this chip + */ +enum ssp_reading { + READING_NULL, + READING_U8, + READING_U16, + READING_U32 +}; + +/** + * The type of writing going on on this chip + */ +enum ssp_writing { + WRITING_NULL, + WRITING_U8, + WRITING_U16, + WRITING_U32 +}; + +/** + * struct vendor_data - vendor-specific config parameters + * for PL022 derivates + * @fifodepth: depth of FIFOs (both) + * @max_bpw: maximum number of bits per word + * @unidir: supports unidirection transfers + */ +struct vendor_data { + int fifodepth; + int max_bpw; + bool unidir; +}; + +/** + * struct pl022 - This is the private SSP driver data structure + * @adev: AMBA device model hookup + * @phybase: The physical memory where the SSP device resides + * @virtbase: The virtual memory where the SSP is mapped + * @master: SPI framework hookup + * @master_info: controller-specific data from machine setup + * @regs: SSP controller register's virtual address + * @pump_messages: Work struct for scheduling work to the workqueue + * @lock: spinlock to syncronise access to driver data + * @workqueue: a workqueue on which any spi_message request is queued + * @busy: workqueue is busy + * @run: workqueue is running + * @pump_transfers: Tasklet used in Interrupt Transfer mode + * @cur_msg: Pointer to current spi_message being processed + * @cur_transfer: Pointer to current spi_transfer + * @cur_chip: pointer to current clients chip(assigned from controller_state) + * @tx: current position in TX buffer to be read + * @tx_end: end position in TX buffer to be read + * @rx: current position in RX buffer to be written + * @rx_end: end position in RX buffer to be written + * @readingtype: the type of read currently going on + * @writingtype: the type or write currently going on + */ +struct pl022 { + struct amba_device *adev; + struct vendor_data *vendor; + resource_size_t phybase; + void __iomem *virtbase; + struct clk *clk; + struct spi_master *master; + struct pl022_ssp_controller *master_info; + /* Driver message queue */ + struct workqueue_struct *workqueue; + struct work_struct pump_messages; + spinlock_t queue_lock; + struct list_head queue; + int busy; + int run; + /* Message transfer pump */ + struct tasklet_struct pump_transfers; + struct spi_message *cur_msg; + struct spi_transfer *cur_transfer; + struct chip_data *cur_chip; + void *tx; + void *tx_end; + void *rx; + void *rx_end; + enum ssp_reading read; + enum ssp_writing write; +}; + +/** + * struct chip_data - To maintain runtime state of SSP for each client chip + * @cr0: Value of control register CR0 of SSP + * @cr1: Value of control register CR1 of SSP + * @dmacr: Value of DMA control Register of SSP + * @cpsr: Value of Clock prescale register + * @n_bytes: how many bytes(power of 2) reqd for a given data width of client + * @enable_dma: Whether to enable DMA or not + * @write: function ptr to be used to write when doing xfer for this chip + * @read: function ptr to be used to read when doing xfer for this chip + * @cs_control: chip select callback provided by chip + * @xfer_type: polling/interrupt/DMA + * + * Runtime state of the SSP controller, maintained per chip, + * This would be set according to the current message that would be served + */ +struct chip_data { + u16 cr0; + u16 cr1; + u16 dmacr; + u16 cpsr; + u8 n_bytes; + u8 enable_dma:1; + enum ssp_reading read; + enum ssp_writing write; + void (*cs_control) (u32 command); + int xfer_type; +}; + +/** + * null_cs_control - Dummy chip select function + * @command: select/delect the chip + * + * If no chip select function is provided by client this is used as dummy + * chip select + */ +static void null_cs_control(u32 command) +{ + pr_debug("pl022: dummy chip select control, CS=0x%x\n", command); +} + +/** + * giveback - current spi_message is over, schedule next message and call + * callback of this message. Assumes that caller already + * set message->status; dma and pio irqs are blocked + * @pl022: SSP driver private data structure + */ +static void giveback(struct pl022 *pl022) +{ + struct spi_transfer *last_transfer; + unsigned long flags; + struct spi_message *msg; + void (*curr_cs_control) (u32 command); + + /* + * This local reference to the chip select function + * is needed because we set curr_chip to NULL + * as a step toward termininating the message. + */ + curr_cs_control = pl022->cur_chip->cs_control; + spin_lock_irqsave(&pl022->queue_lock, flags); + msg = pl022->cur_msg; + pl022->cur_msg = NULL; + pl022->cur_transfer = NULL; + pl022->cur_chip = NULL; + queue_work(pl022->workqueue, &pl022->pump_messages); + spin_unlock_irqrestore(&pl022->queue_lock, flags); + + last_transfer = list_entry(msg->transfers.prev, + struct spi_transfer, + transfer_list); + + /* Delay if requested before any change in chip select */ + if (last_transfer->delay_usecs) + /* + * FIXME: This runs in interrupt context. + * Is this really smart? + */ + udelay(last_transfer->delay_usecs); + + /* + * Drop chip select UNLESS cs_change is true or we are returning + * a message with an error, or next message is for another chip + */ + if (!last_transfer->cs_change) + curr_cs_control(SSP_CHIP_DESELECT); + else { + struct spi_message *next_msg; + + /* Holding of cs was hinted, but we need to make sure + * the next message is for the same chip. Don't waste + * time with the following tests unless this was hinted. + * + * We cannot postpone this until pump_messages, because + * after calling msg->complete (below) the driver that + * sent the current message could be unloaded, which + * could invalidate the cs_control() callback... + */ + + /* get a pointer to the next message, if any */ + spin_lock_irqsave(&pl022->queue_lock, flags); + if (list_empty(&pl022->queue)) + next_msg = NULL; + else + next_msg = list_entry(pl022->queue.next, + struct spi_message, queue); + spin_unlock_irqrestore(&pl022->queue_lock, flags); + + /* see if the next and current messages point + * to the same chip + */ + if (next_msg && next_msg->spi != msg->spi) + next_msg = NULL; + if (!next_msg || msg->state == STATE_ERROR) + curr_cs_control(SSP_CHIP_DESELECT); + } + msg->state = NULL; + if (msg->complete) + msg->complete(msg->context); + /* This message is completed, so let's turn off the clock! */ + clk_disable(pl022->clk); +} + +/** + * flush - flush the FIFO to reach a clean state + * @pl022: SSP driver private data structure + */ +static int flush(struct pl022 *pl022) +{ + unsigned long limit = loops_per_jiffy << 1; + + dev_dbg(&pl022->adev->dev, "flush\n"); + do { + while (readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_RNE) + readw(SSP_DR(pl022->virtbase)); + } while ((readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_BSY) && limit--); + return limit; +} + +/** + * restore_state - Load configuration of current chip + * @pl022: SSP driver private data structure + */ +static void restore_state(struct pl022 *pl022) +{ + struct chip_data *chip = pl022->cur_chip; + + writew(chip->cr0, SSP_CR0(pl022->virtbase)); + writew(chip->cr1, SSP_CR1(pl022->virtbase)); + writew(chip->dmacr, SSP_DMACR(pl022->virtbase)); + writew(chip->cpsr, SSP_CPSR(pl022->virtbase)); + writew(DISABLE_ALL_INTERRUPTS, SSP_IMSC(pl022->virtbase)); + writew(CLEAR_ALL_INTERRUPTS, SSP_ICR(pl022->virtbase)); +} + +/** + * load_ssp_default_config - Load default configuration for SSP + * @pl022: SSP driver private data structure + */ + +/* + * Default SSP Register Values + */ +#define DEFAULT_SSP_REG_CR0 ( \ + GEN_MASK_BITS(SSP_DATA_BITS_12, SSP_CR0_MASK_DSS, 0) | \ + GEN_MASK_BITS(SSP_MICROWIRE_CHANNEL_FULL_DUPLEX, SSP_CR0_MASK_HALFDUP, 5) | \ + GEN_MASK_BITS(SSP_CLK_POL_IDLE_LOW, SSP_CR0_MASK_SPO, 6) | \ + GEN_MASK_BITS(SSP_CLK_FALLING_EDGE, SSP_CR0_MASK_SPH, 7) | \ + GEN_MASK_BITS(NMDK_SSP_DEFAULT_CLKRATE, SSP_CR0_MASK_SCR, 8) | \ + GEN_MASK_BITS(SSP_BITS_8, SSP_CR0_MASK_CSS, 16) | \ + GEN_MASK_BITS(SSP_INTERFACE_MOTOROLA_SPI, SSP_CR0_MASK_FRF, 21) \ +) + +#define DEFAULT_SSP_REG_CR1 ( \ + GEN_MASK_BITS(LOOPBACK_DISABLED, SSP_CR1_MASK_LBM, 0) | \ + GEN_MASK_BITS(SSP_DISABLED, SSP_CR1_MASK_SSE, 1) | \ + GEN_MASK_BITS(SSP_MASTER, SSP_CR1_MASK_MS, 2) | \ + GEN_MASK_BITS(DO_NOT_DRIVE_TX, SSP_CR1_MASK_SOD, 3) | \ + GEN_MASK_BITS(SSP_RX_MSB, SSP_CR1_MASK_RENDN, 4) | \ + GEN_MASK_BITS(SSP_TX_MSB, SSP_CR1_MASK_TENDN, 5) | \ + GEN_MASK_BITS(SSP_MWIRE_WAIT_ZERO, SSP_CR1_MASK_MWAIT, 6) |\ + GEN_MASK_BITS(SSP_RX_1_OR_MORE_ELEM, SSP_CR1_MASK_RXIFLSEL, 7) | \ + GEN_MASK_BITS(SSP_TX_1_OR_MORE_EMPTY_LOC, SSP_CR1_MASK_TXIFLSEL, 10) \ +) + +#define DEFAULT_SSP_REG_CPSR ( \ + GEN_MASK_BITS(NMDK_SSP_DEFAULT_PRESCALE, SSP_CPSR_MASK_CPSDVSR, 0) \ +) + +#define DEFAULT_SSP_REG_DMACR (\ + GEN_MASK_BITS(SSP_DMA_DISABLED, SSP_DMACR_MASK_RXDMAE, 0) | \ + GEN_MASK_BITS(SSP_DMA_DISABLED, SSP_DMACR_MASK_TXDMAE, 1) \ +) + + +static void load_ssp_default_config(struct pl022 *pl022) +{ + writew(DEFAULT_SSP_REG_CR0, SSP_CR0(pl022->virtbase)); + writew(DEFAULT_SSP_REG_CR1, SSP_CR1(pl022->virtbase)); + writew(DEFAULT_SSP_REG_DMACR, SSP_DMACR(pl022->virtbase)); + writew(DEFAULT_SSP_REG_CPSR, SSP_CPSR(pl022->virtbase)); + writew(DISABLE_ALL_INTERRUPTS, SSP_IMSC(pl022->virtbase)); + writew(CLEAR_ALL_INTERRUPTS, SSP_ICR(pl022->virtbase)); +} + +/** + * This will write to TX and read from RX according to the parameters + * set in pl022. + */ +static void readwriter(struct pl022 *pl022) +{ + + /* + * The FIFO depth is different inbetween primecell variants. + * I believe filling in too much in the FIFO might cause + * errons in 8bit wide transfers on ARM variants (just 8 words + * FIFO, means only 8x8 = 64 bits in FIFO) at least. + * + * FIXME: currently we have no logic to account for this. + * perhaps there is even something broken in HW regarding + * 8bit transfers (it doesn't fail on 16bit) so this needs + * more investigation... + */ + dev_dbg(&pl022->adev->dev, + "%s, rx: %p, rxend: %p, tx: %p, txend: %p\n", + __func__, pl022->rx, pl022->rx_end, pl022->tx, pl022->tx_end); + + /* Read as much as you can */ + while ((readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_RNE) + && (pl022->rx < pl022->rx_end)) { + switch (pl022->read) { + case READING_NULL: + readw(SSP_DR(pl022->virtbase)); + break; + case READING_U8: + *(u8 *) (pl022->rx) = + readw(SSP_DR(pl022->virtbase)) & 0xFFU; + break; + case READING_U16: + *(u16 *) (pl022->rx) = + (u16) readw(SSP_DR(pl022->virtbase)); + break; + case READING_U32: + *(u32 *) (pl022->rx) = + readl(SSP_DR(pl022->virtbase)); + break; + } + pl022->rx += (pl022->cur_chip->n_bytes); + } + /* + * Write as much as you can, while keeping an eye on the RX FIFO! + */ + while ((readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_TNF) + && (pl022->tx < pl022->tx_end)) { + switch (pl022->write) { + case WRITING_NULL: + writew(0x0, SSP_DR(pl022->virtbase)); + break; + case WRITING_U8: + writew(*(u8 *) (pl022->tx), SSP_DR(pl022->virtbase)); + break; + case WRITING_U16: + writew((*(u16 *) (pl022->tx)), SSP_DR(pl022->virtbase)); + break; + case WRITING_U32: + writel(*(u32 *) (pl022->tx), SSP_DR(pl022->virtbase)); + break; + } + pl022->tx += (pl022->cur_chip->n_bytes); + /* + * This inner reader takes care of things appearing in the RX + * FIFO as we're transmitting. This will happen a lot since the + * clock starts running when you put things into the TX FIFO, + * and then things are continously clocked into the RX FIFO. + */ + while ((readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_RNE) + && (pl022->rx < pl022->rx_end)) { + switch (pl022->read) { + case READING_NULL: + readw(SSP_DR(pl022->virtbase)); + break; + case READING_U8: + *(u8 *) (pl022->rx) = + readw(SSP_DR(pl022->virtbase)) & 0xFFU; + break; + case READING_U16: + *(u16 *) (pl022->rx) = + (u16) readw(SSP_DR(pl022->virtbase)); + break; + case READING_U32: + *(u32 *) (pl022->rx) = + readl(SSP_DR(pl022->virtbase)); + break; + } + pl022->rx += (pl022->cur_chip->n_bytes); + } + } + /* + * When we exit here the TX FIFO should be full and the RX FIFO + * should be empty + */ +} + + +/** + * next_transfer - Move to the Next transfer in the current spi message + * @pl022: SSP driver private data structure + * + * This function moves though the linked list of spi transfers in the + * current spi message and returns with the state of current spi + * message i.e whether its last transfer is done(STATE_DONE) or + * Next transfer is ready(STATE_RUNNING) + */ +static void *next_transfer(struct pl022 *pl022) +{ + struct spi_message *msg = pl022->cur_msg; + struct spi_transfer *trans = pl022->cur_transfer; + + /* Move to next transfer */ + if (trans->transfer_list.next != &msg->transfers) { + pl022->cur_transfer = + list_entry(trans->transfer_list.next, + struct spi_transfer, transfer_list); + return STATE_RUNNING; + } + return STATE_DONE; +} +/** + * pl022_interrupt_handler - Interrupt handler for SSP controller + * + * This function handles interrupts generated for an interrupt based transfer. + * If a receive overrun (ROR) interrupt is there then we disable SSP, flag the + * current message's state as STATE_ERROR and schedule the tasklet + * pump_transfers which will do the postprocessing of the current message by + * calling giveback(). Otherwise it reads data from RX FIFO till there is no + * more data, and writes data in TX FIFO till it is not full. If we complete + * the transfer we move to the next transfer and schedule the tasklet. + */ +static irqreturn_t pl022_interrupt_handler(int irq, void *dev_id) +{ + struct pl022 *pl022 = dev_id; + struct spi_message *msg = pl022->cur_msg; + u16 irq_status = 0; + u16 flag = 0; + + if (unlikely(!msg)) { + dev_err(&pl022->adev->dev, + "bad message state in interrupt handler"); + /* Never fail */ + return IRQ_HANDLED; + } + + /* Read the Interrupt Status Register */ + irq_status = readw(SSP_MIS(pl022->virtbase)); + + if (unlikely(!irq_status)) + return IRQ_NONE; + + /* This handles the error code interrupts */ + if (unlikely(irq_status & SSP_MIS_MASK_RORMIS)) { + /* + * Overrun interrupt - bail out since our Data has been + * corrupted + */ + dev_err(&pl022->adev->dev, + "FIFO overrun\n"); + if (readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_RFF) + dev_err(&pl022->adev->dev, + "RXFIFO is full\n"); + if (readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_TNF) + dev_err(&pl022->adev->dev, + "TXFIFO is full\n"); + + /* + * Disable and clear interrupts, disable SSP, + * mark message with bad status so it can be + * retried. + */ + writew(DISABLE_ALL_INTERRUPTS, + SSP_IMSC(pl022->virtbase)); + writew(CLEAR_ALL_INTERRUPTS, SSP_ICR(pl022->virtbase)); + writew((readw(SSP_CR1(pl022->virtbase)) & + (~SSP_CR1_MASK_SSE)), SSP_CR1(pl022->virtbase)); + msg->state = STATE_ERROR; + + /* Schedule message queue handler */ + tasklet_schedule(&pl022->pump_transfers); + return IRQ_HANDLED; + } + + readwriter(pl022); + + if ((pl022->tx == pl022->tx_end) && (flag == 0)) { + flag = 1; + /* Disable Transmit interrupt */ + writew(readw(SSP_IMSC(pl022->virtbase)) & + (~SSP_IMSC_MASK_TXIM), + SSP_IMSC(pl022->virtbase)); + } + + /* + * Since all transactions must write as much as shall be read, + * we can conclude the entire transaction once RX is complete. + * At this point, all TX will always be finished. + */ + if (pl022->rx >= pl022->rx_end) { + writew(DISABLE_ALL_INTERRUPTS, + SSP_IMSC(pl022->virtbase)); + writew(CLEAR_ALL_INTERRUPTS, SSP_ICR(pl022->virtbase)); + if (unlikely(pl022->rx > pl022->rx_end)) { + dev_warn(&pl022->adev->dev, "read %u surplus " + "bytes (did you request an odd " + "number of bytes on a 16bit bus?)\n", + (u32) (pl022->rx - pl022->rx_end)); + } + /* Update total bytes transfered */ + msg->actual_length += pl022->cur_transfer->len; + if (pl022->cur_transfer->cs_change) + pl022->cur_chip-> + cs_control(SSP_CHIP_DESELECT); + /* Move to next transfer */ + msg->state = next_transfer(pl022); + tasklet_schedule(&pl022->pump_transfers); + return IRQ_HANDLED; + } + + return IRQ_HANDLED; +} + +/** + * This sets up the pointers to memory for the next message to + * send out on the SPI bus. + */ +static int set_up_next_transfer(struct pl022 *pl022, + struct spi_transfer *transfer) +{ + int residue; + + /* Sanity check the message for this bus width */ + residue = pl022->cur_transfer->len % pl022->cur_chip->n_bytes; + if (unlikely(residue != 0)) { + dev_err(&pl022->adev->dev, + "message of %u bytes to transmit but the current " + "chip bus has a data width of %u bytes!\n", + pl022->cur_transfer->len, + pl022->cur_chip->n_bytes); + dev_err(&pl022->adev->dev, "skipping this message\n"); + return -EIO; + } + pl022->tx = (void *)transfer->tx_buf; + pl022->tx_end = pl022->tx + pl022->cur_transfer->len; + pl022->rx = (void *)transfer->rx_buf; + pl022->rx_end = pl022->rx + pl022->cur_transfer->len; + pl022->write = + pl022->tx ? pl022->cur_chip->write : WRITING_NULL; + pl022->read = pl022->rx ? pl022->cur_chip->read : READING_NULL; + return 0; +} + +/** + * pump_transfers - Tasklet function which schedules next interrupt transfer + * when running in interrupt transfer mode. + * @data: SSP driver private data structure + * + */ +static void pump_transfers(unsigned long data) +{ + struct pl022 *pl022 = (struct pl022 *) data; + struct spi_message *message = NULL; + struct spi_transfer *transfer = NULL; + struct spi_transfer *previous = NULL; + + /* Get current state information */ + message = pl022->cur_msg; + transfer = pl022->cur_transfer; + + /* Handle for abort */ + if (message->state == STATE_ERROR) { + message->status = -EIO; + giveback(pl022); + return; + } + + /* Handle end of message */ + if (message->state == STATE_DONE) { + message->status = 0; + giveback(pl022); + return; + } + + /* Delay if requested at end of transfer before CS change */ + if (message->state == STATE_RUNNING) { + previous = list_entry(transfer->transfer_list.prev, + struct spi_transfer, + transfer_list); + if (previous->delay_usecs) + /* + * FIXME: This runs in interrupt context. + * Is this really smart? + */ + udelay(previous->delay_usecs); + + /* Drop chip select only if cs_change is requested */ + if (previous->cs_change) + pl022->cur_chip->cs_control(SSP_CHIP_SELECT); + } else { + /* STATE_START */ + message->state = STATE_RUNNING; + } + + if (set_up_next_transfer(pl022, transfer)) { + message->state = STATE_ERROR; + message->status = -EIO; + giveback(pl022); + return; + } + /* Flush the FIFOs and let's go! */ + flush(pl022); + writew(ENABLE_ALL_INTERRUPTS, SSP_IMSC(pl022->virtbase)); +} + +/** + * NOT IMPLEMENTED + * configure_dma - It configures the DMA pipes for DMA transfers + * @data: SSP driver's private data structure + * + */ +static int configure_dma(void *data) +{ + struct pl022 *pl022 = data; + dev_dbg(&pl022->adev->dev, "configure DMA\n"); + return -ENOTSUPP; +} + +/** + * do_dma_transfer - It handles transfers of the current message + * if it is DMA xfer. + * NOT FULLY IMPLEMENTED + * @data: SSP driver's private data structure + */ +static void do_dma_transfer(void *data) +{ + struct pl022 *pl022 = data; + + if (configure_dma(data)) { + dev_dbg(&pl022->adev->dev, "configuration of DMA Failed!\n"); + goto err_config_dma; + } + + /* TODO: Implememt DMA setup of pipes here */ + + /* Enable target chip, set up transfer */ + pl022->cur_chip->cs_control(SSP_CHIP_SELECT); + if (set_up_next_transfer(pl022, pl022->cur_transfer)) { + /* Error path */ + pl022->cur_msg->state = STATE_ERROR; + pl022->cur_msg->status = -EIO; + giveback(pl022); + return; + } + /* Enable SSP */ + writew((readw(SSP_CR1(pl022->virtbase)) | SSP_CR1_MASK_SSE), + SSP_CR1(pl022->virtbase)); + + /* TODO: Enable the DMA transfer here */ + return; + + err_config_dma: + pl022->cur_msg->state = STATE_ERROR; + pl022->cur_msg->status = -EIO; + giveback(pl022); + return; +} + +static void do_interrupt_transfer(void *data) +{ + struct pl022 *pl022 = data; + + /* Enable target chip */ + pl022->cur_chip->cs_control(SSP_CHIP_SELECT); + if (set_up_next_transfer(pl022, pl022->cur_transfer)) { + /* Error path */ + pl022->cur_msg->state = STATE_ERROR; + pl022->cur_msg->status = -EIO; + giveback(pl022); + return; + } + /* Enable SSP, turn on interrupts */ + writew((readw(SSP_CR1(pl022->virtbase)) | SSP_CR1_MASK_SSE), + SSP_CR1(pl022->virtbase)); + writew(ENABLE_ALL_INTERRUPTS, SSP_IMSC(pl022->virtbase)); +} + +static void do_polling_transfer(void *data) +{ + struct pl022 *pl022 = data; + struct spi_message *message = NULL; + struct spi_transfer *transfer = NULL; + struct spi_transfer *previous = NULL; + struct chip_data *chip; + + chip = pl022->cur_chip; + message = pl022->cur_msg; + + while (message->state != STATE_DONE) { + /* Handle for abort */ + if (message->state == STATE_ERROR) + break; + transfer = pl022->cur_transfer; + + /* Delay if requested at end of transfer */ + if (message->state == STATE_RUNNING) { + previous = + list_entry(transfer->transfer_list.prev, + struct spi_transfer, transfer_list); + if (previous->delay_usecs) + udelay(previous->delay_usecs); + if (previous->cs_change) + pl022->cur_chip->cs_control(SSP_CHIP_SELECT); + } else { + /* STATE_START */ + message->state = STATE_RUNNING; + pl022->cur_chip->cs_control(SSP_CHIP_SELECT); + } + + /* Configuration Changing Per Transfer */ + if (set_up_next_transfer(pl022, transfer)) { + /* Error path */ + message->state = STATE_ERROR; + break; + } + /* Flush FIFOs and enable SSP */ + flush(pl022); + writew((readw(SSP_CR1(pl022->virtbase)) | SSP_CR1_MASK_SSE), + SSP_CR1(pl022->virtbase)); + + dev_dbg(&pl022->adev->dev, "POLLING TRANSFER ONGOING ... \n"); + /* FIXME: insert a timeout so we don't hang here indefinately */ + while (pl022->tx < pl022->tx_end || pl022->rx < pl022->rx_end) + readwriter(pl022); + + /* Update total byte transfered */ + message->actual_length += pl022->cur_transfer->len; + if (pl022->cur_transfer->cs_change) + pl022->cur_chip->cs_control(SSP_CHIP_DESELECT); + /* Move to next transfer */ + message->state = next_transfer(pl022); + } + + /* Handle end of message */ + if (message->state == STATE_DONE) + message->status = 0; + else + message->status = -EIO; + + giveback(pl022); + return; +} + +/** + * pump_messages - Workqueue function which processes spi message queue + * @data: pointer to private data of SSP driver + * + * This function checks if there is any spi message in the queue that + * needs processing and delegate control to appropriate function + * do_polling_transfer()/do_interrupt_transfer()/do_dma_transfer() + * based on the kind of the transfer + * + */ +static void pump_messages(struct work_struct *work) +{ + struct pl022 *pl022 = + container_of(work, struct pl022, pump_messages); + unsigned long flags; + + /* Lock queue and check for queue work */ + spin_lock_irqsave(&pl022->queue_lock, flags); + if (list_empty(&pl022->queue) || pl022->run == QUEUE_STOPPED) { + pl022->busy = 0; + spin_unlock_irqrestore(&pl022->queue_lock, flags); + return; + } + /* Make sure we are not already running a message */ + if (pl022->cur_msg) { + spin_unlock_irqrestore(&pl022->queue_lock, flags); + return; + } + /* Extract head of queue */ + pl022->cur_msg = + list_entry(pl022->queue.next, struct spi_message, queue); + + list_del_init(&pl022->cur_msg->queue); + pl022->busy = 1; + spin_unlock_irqrestore(&pl022->queue_lock, flags); + + /* Initial message state */ + pl022->cur_msg->state = STATE_START; + pl022->cur_transfer = list_entry(pl022->cur_msg->transfers.next, + struct spi_transfer, + transfer_list); + + /* Setup the SPI using the per chip configuration */ + pl022->cur_chip = spi_get_ctldata(pl022->cur_msg->spi); + /* + * We enable the clock here, then the clock will be disabled when + * giveback() is called in each method (poll/interrupt/DMA) + */ + clk_enable(pl022->clk); + restore_state(pl022); + flush(pl022); + + if (pl022->cur_chip->xfer_type == POLLING_TRANSFER) + do_polling_transfer(pl022); + else if (pl022->cur_chip->xfer_type == INTERRUPT_TRANSFER) + do_interrupt_transfer(pl022); + else + do_dma_transfer(pl022); +} + + +static int __init init_queue(struct pl022 *pl022) +{ + INIT_LIST_HEAD(&pl022->queue); + spin_lock_init(&pl022->queue_lock); + + pl022->run = QUEUE_STOPPED; + pl022->busy = 0; + + tasklet_init(&pl022->pump_transfers, + pump_transfers, (unsigned long)pl022); + + INIT_WORK(&pl022->pump_messages, pump_messages); + pl022->workqueue = create_singlethread_workqueue( + dev_name(pl022->master->dev.parent)); + if (pl022->workqueue == NULL) + return -EBUSY; + + return 0; +} + + +static int start_queue(struct pl022 *pl022) +{ + unsigned long flags; + + spin_lock_irqsave(&pl022->queue_lock, flags); + + if (pl022->run == QUEUE_RUNNING || pl022->busy) { + spin_unlock_irqrestore(&pl022->queue_lock, flags); + return -EBUSY; + } + + pl022->run = QUEUE_RUNNING; + pl022->cur_msg = NULL; + pl022->cur_transfer = NULL; + pl022->cur_chip = NULL; + spin_unlock_irqrestore(&pl022->queue_lock, flags); + + queue_work(pl022->workqueue, &pl022->pump_messages); + + return 0; +} + + +static int stop_queue(struct pl022 *pl022) +{ + unsigned long flags; + unsigned limit = 500; + int status = 0; + + spin_lock_irqsave(&pl022->queue_lock, flags); + + /* This is a bit lame, but is optimized for the common execution path. + * A wait_queue on the pl022->busy could be used, but then the common + * execution path (pump_messages) would be required to call wake_up or + * friends on every SPI message. Do this instead */ + pl022->run = QUEUE_STOPPED; + while (!list_empty(&pl022->queue) && pl022->busy && limit--) { + spin_unlock_irqrestore(&pl022->queue_lock, flags); + msleep(10); + spin_lock_irqsave(&pl022->queue_lock, flags); + } + + if (!list_empty(&pl022->queue) || pl022->busy) + status = -EBUSY; + + spin_unlock_irqrestore(&pl022->queue_lock, flags); + + return status; +} + +static int destroy_queue(struct pl022 *pl022) +{ + int status; + + status = stop_queue(pl022); + /* we are unloading the module or failing to load (only two calls + * to this routine), and neither call can handle a return value. + * However, destroy_workqueue calls flush_workqueue, and that will + * block until all work is done. If the reason that stop_queue + * timed out is that the work will never finish, then it does no + * good to call destroy_workqueue, so return anyway. */ + if (status != 0) + return status; + + destroy_workqueue(pl022->workqueue); + + return 0; +} + +static int verify_controller_parameters(struct pl022 *pl022, + struct pl022_config_chip *chip_info) +{ + if ((chip_info->lbm != LOOPBACK_ENABLED) + && (chip_info->lbm != LOOPBACK_DISABLED)) { + dev_err(chip_info->dev, + "loopback Mode is configured incorrectly\n"); + return -EINVAL; + } + if ((chip_info->iface < SSP_INTERFACE_MOTOROLA_SPI) + || (chip_info->iface > SSP_INTERFACE_UNIDIRECTIONAL)) { + dev_err(chip_info->dev, + "interface is configured incorrectly\n"); + return -EINVAL; + } + if ((chip_info->iface == SSP_INTERFACE_UNIDIRECTIONAL) && + (!pl022->vendor->unidir)) { + dev_err(chip_info->dev, + "unidirectional mode not supported in this " + "hardware version\n"); + return -EINVAL; + } + if ((chip_info->hierarchy != SSP_MASTER) + && (chip_info->hierarchy != SSP_SLAVE)) { + dev_err(chip_info->dev, + "hierarchy is configured incorrectly\n"); + return -EINVAL; + } + if (((chip_info->clk_freq).cpsdvsr < CPSDVR_MIN) + || ((chip_info->clk_freq).cpsdvsr > CPSDVR_MAX)) { + dev_err(chip_info->dev, + "cpsdvsr is configured incorrectly\n"); + return -EINVAL; + } + if ((chip_info->endian_rx != SSP_RX_MSB) + && (chip_info->endian_rx != SSP_RX_LSB)) { + dev_err(chip_info->dev, + "RX FIFO endianess is configured incorrectly\n"); + return -EINVAL; + } + if ((chip_info->endian_tx != SSP_TX_MSB) + && (chip_info->endian_tx != SSP_TX_LSB)) { + dev_err(chip_info->dev, + "TX FIFO endianess is configured incorrectly\n"); + return -EINVAL; + } + if ((chip_info->data_size < SSP_DATA_BITS_4) + || (chip_info->data_size > SSP_DATA_BITS_32)) { + dev_err(chip_info->dev, + "DATA Size is configured incorrectly\n"); + return -EINVAL; + } + if ((chip_info->com_mode != INTERRUPT_TRANSFER) + && (chip_info->com_mode != DMA_TRANSFER) + && (chip_info->com_mode != POLLING_TRANSFER)) { + dev_err(chip_info->dev, + "Communication mode is configured incorrectly\n"); + return -EINVAL; + } + if ((chip_info->rx_lev_trig < SSP_RX_1_OR_MORE_ELEM) + || (chip_info->rx_lev_trig > SSP_RX_32_OR_MORE_ELEM)) { + dev_err(chip_info->dev, + "RX FIFO Trigger Level is configured incorrectly\n"); + return -EINVAL; + } + if ((chip_info->tx_lev_trig < SSP_TX_1_OR_MORE_EMPTY_LOC) + || (chip_info->tx_lev_trig > SSP_TX_32_OR_MORE_EMPTY_LOC)) { + dev_err(chip_info->dev, + "TX FIFO Trigger Level is configured incorrectly\n"); + return -EINVAL; + } + if (chip_info->iface == SSP_INTERFACE_MOTOROLA_SPI) { + if ((chip_info->clk_phase != SSP_CLK_RISING_EDGE) + && (chip_info->clk_phase != SSP_CLK_FALLING_EDGE)) { + dev_err(chip_info->dev, + "Clock Phase is configured incorrectly\n"); + return -EINVAL; + } + if ((chip_info->clk_pol != SSP_CLK_POL_IDLE_LOW) + && (chip_info->clk_pol != SSP_CLK_POL_IDLE_HIGH)) { + dev_err(chip_info->dev, + "Clock Polarity is configured incorrectly\n"); + return -EINVAL; + } + } + if (chip_info->iface == SSP_INTERFACE_NATIONAL_MICROWIRE) { + if ((chip_info->ctrl_len < SSP_BITS_4) + || (chip_info->ctrl_len > SSP_BITS_32)) { + dev_err(chip_info->dev, + "CTRL LEN is configured incorrectly\n"); + return -EINVAL; + } + if ((chip_info->wait_state != SSP_MWIRE_WAIT_ZERO) + && (chip_info->wait_state != SSP_MWIRE_WAIT_ONE)) { + dev_err(chip_info->dev, + "Wait State is configured incorrectly\n"); + return -EINVAL; + } + if ((chip_info->duplex != SSP_MICROWIRE_CHANNEL_FULL_DUPLEX) + && (chip_info->duplex != + SSP_MICROWIRE_CHANNEL_HALF_DUPLEX)) { + dev_err(chip_info->dev, + "DUPLEX is configured incorrectly\n"); + return -EINVAL; + } + } + if (chip_info->cs_control == NULL) { + dev_warn(chip_info->dev, + "Chip Select Function is NULL for this chip\n"); + chip_info->cs_control = null_cs_control; + } + return 0; +} + +/** + * pl022_transfer - transfer function registered to SPI master framework + * @spi: spi device which is requesting transfer + * @msg: spi message which is to handled is queued to driver queue + * + * This function is registered to the SPI framework for this SPI master + * controller. It will queue the spi_message in the queue of driver if + * the queue is not stopped and return. + */ +static int pl022_transfer(struct spi_device *spi, struct spi_message *msg) +{ + struct pl022 *pl022 = spi_master_get_devdata(spi->master); + unsigned long flags; + + spin_lock_irqsave(&pl022->queue_lock, flags); + + if (pl022->run == QUEUE_STOPPED) { + spin_unlock_irqrestore(&pl022->queue_lock, flags); + return -ESHUTDOWN; + } + msg->actual_length = 0; + msg->status = -EINPROGRESS; + msg->state = STATE_START; + + list_add_tail(&msg->queue, &pl022->queue); + if (pl022->run == QUEUE_RUNNING && !pl022->busy) + queue_work(pl022->workqueue, &pl022->pump_messages); + + spin_unlock_irqrestore(&pl022->queue_lock, flags); + return 0; +} + +static int calculate_effective_freq(struct pl022 *pl022, + int freq, + struct ssp_clock_params *clk_freq) +{ + /* Lets calculate the frequency parameters */ + u16 cpsdvsr = 2; + u16 scr = 0; + bool freq_found = false; + u32 rate; + u32 max_tclk; + u32 min_tclk; + + rate = clk_get_rate(pl022->clk); + /* cpsdvscr = 2 & scr 0 */ + max_tclk = (rate / (CPSDVR_MIN * (1 + SCR_MIN))); + /* cpsdvsr = 254 & scr = 255 */ + min_tclk = (rate / (CPSDVR_MAX * (1 + SCR_MAX))); + + if ((freq <= max_tclk) && (freq >= min_tclk)) { + while (cpsdvsr <= CPSDVR_MAX && !freq_found) { + while (scr <= SCR_MAX && !freq_found) { + if ((rate / + (cpsdvsr * (1 + scr))) > freq) + scr += 1; + else { + /* + * This bool is made true when + * effective frequency >= + * target frequency is found + */ + freq_found = true; + if ((rate / + (cpsdvsr * (1 + scr))) != freq) { + if (scr == SCR_MIN) { + cpsdvsr -= 2; + scr = SCR_MAX; + } else + scr -= 1; + } + } + } + if (!freq_found) { + cpsdvsr += 2; + scr = SCR_MIN; + } + } + if (cpsdvsr != 0) { + dev_dbg(&pl022->adev->dev, + "SSP Effective Frequency is %u\n", + (rate / (cpsdvsr * (1 + scr)))); + clk_freq->cpsdvsr = (u8) (cpsdvsr & 0xFF); + clk_freq->scr = (u8) (scr & 0xFF); + dev_dbg(&pl022->adev->dev, + "SSP cpsdvsr = %d, scr = %d\n", + clk_freq->cpsdvsr, clk_freq->scr); + } + } else { + dev_err(&pl022->adev->dev, + "controller data is incorrect: out of range frequency"); + return -EINVAL; + } + return 0; +} + +/** + * NOT IMPLEMENTED + * process_dma_info - Processes the DMA info provided by client drivers + * @chip_info: chip info provided by client device + * @chip: Runtime state maintained by the SSP controller for each spi device + * + * This function processes and stores DMA config provided by client driver + * into the runtime state maintained by the SSP controller driver + */ +static int process_dma_info(struct pl022_config_chip *chip_info, + struct chip_data *chip) +{ + dev_err(chip_info->dev, + "cannot process DMA info, DMA not implemented!\n"); + return -ENOTSUPP; +} + +/** + * pl022_setup - setup function registered to SPI master framework + * @spi: spi device which is requesting setup + * + * This function is registered to the SPI framework for this SPI master + * controller. If it is the first time when setup is called by this device, + * this function will initialize the runtime state for this chip and save + * the same in the device structure. Else it will update the runtime info + * with the updated chip info. Nothing is really being written to the + * controller hardware here, that is not done until the actual transfer + * commence. + */ + +/* FIXME: JUST GUESSING the spi->mode bits understood by this driver */ +#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH \ + | SPI_LSB_FIRST | SPI_LOOP) + +static int pl022_setup(struct spi_device *spi) +{ + struct pl022_config_chip *chip_info; + struct chip_data *chip; + int status = 0; + struct pl022 *pl022 = spi_master_get_devdata(spi->master); + + if (spi->mode & ~MODEBITS) { + dev_dbg(&spi->dev, "unsupported mode bits %x\n", + spi->mode & ~MODEBITS); + return -EINVAL; + } + + if (!spi->max_speed_hz) + return -EINVAL; + + /* Get controller_state if one is supplied */ + chip = spi_get_ctldata(spi); + + if (chip == NULL) { + chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL); + if (!chip) { + dev_err(&spi->dev, + "cannot allocate controller state\n"); + return -ENOMEM; + } + dev_dbg(&spi->dev, + "allocated memory for controller's runtime state\n"); + } + + /* Get controller data if one is supplied */ + chip_info = spi->controller_data; + + if (chip_info == NULL) { + /* spi_board_info.controller_data not is supplied */ + dev_dbg(&spi->dev, + "using default controller_data settings\n"); + + chip_info = + kzalloc(sizeof(struct pl022_config_chip), GFP_KERNEL); + + if (!chip_info) { + dev_err(&spi->dev, + "cannot allocate controller data\n"); + status = -ENOMEM; + goto err_first_setup; + } + + dev_dbg(&spi->dev, "allocated memory for controller data\n"); + + /* Pointer back to the SPI device */ + chip_info->dev = &spi->dev; + /* + * Set controller data default values: + * Polling is supported by default + */ + chip_info->lbm = LOOPBACK_DISABLED; + chip_info->com_mode = POLLING_TRANSFER; + chip_info->iface = SSP_INTERFACE_MOTOROLA_SPI; + chip_info->hierarchy = SSP_SLAVE; + chip_info->slave_tx_disable = DO_NOT_DRIVE_TX; + chip_info->endian_tx = SSP_TX_LSB; + chip_info->endian_rx = SSP_RX_LSB; + chip_info->data_size = SSP_DATA_BITS_12; + chip_info->rx_lev_trig = SSP_RX_1_OR_MORE_ELEM; + chip_info->tx_lev_trig = SSP_TX_1_OR_MORE_EMPTY_LOC; + chip_info->clk_phase = SSP_CLK_FALLING_EDGE; + chip_info->clk_pol = SSP_CLK_POL_IDLE_LOW; + chip_info->ctrl_len = SSP_BITS_8; + chip_info->wait_state = SSP_MWIRE_WAIT_ZERO; + chip_info->duplex = SSP_MICROWIRE_CHANNEL_FULL_DUPLEX; + chip_info->cs_control = null_cs_control; + } else { + dev_dbg(&spi->dev, + "using user supplied controller_data settings\n"); + } + + /* + * We can override with custom divisors, else we use the board + * frequency setting + */ + if ((0 == chip_info->clk_freq.cpsdvsr) + && (0 == chip_info->clk_freq.scr)) { + status = calculate_effective_freq(pl022, + spi->max_speed_hz, + &chip_info->clk_freq); + if (status < 0) + goto err_config_params; + } else { + if ((chip_info->clk_freq.cpsdvsr % 2) != 0) + chip_info->clk_freq.cpsdvsr = + chip_info->clk_freq.cpsdvsr - 1; + } + status = verify_controller_parameters(pl022, chip_info); + if (status) { + dev_err(&spi->dev, "controller data is incorrect"); + goto err_config_params; + } + /* Now set controller state based on controller data */ + chip->xfer_type = chip_info->com_mode; + chip->cs_control = chip_info->cs_control; + + if (chip_info->data_size <= 8) { + dev_dbg(&spi->dev, "1 <= n <=8 bits per word\n"); + chip->n_bytes = 1; + chip->read = READING_U8; + chip->write = WRITING_U8; + } else if (chip_info->data_size <= 16) { + dev_dbg(&spi->dev, "9 <= n <= 16 bits per word\n"); + chip->n_bytes = 2; + chip->read = READING_U16; + chip->write = WRITING_U16; + } else { + if (pl022->vendor->max_bpw >= 32) { + dev_dbg(&spi->dev, "17 <= n <= 32 bits per word\n"); + chip->n_bytes = 4; + chip->read = READING_U32; + chip->write = WRITING_U32; + } else { + dev_err(&spi->dev, + "illegal data size for this controller!\n"); + dev_err(&spi->dev, + "a standard pl022 can only handle " + "1 <= n <= 16 bit words\n"); + goto err_config_params; + } + } + + /* Now Initialize all register settings required for this chip */ + chip->cr0 = 0; + chip->cr1 = 0; + chip->dmacr = 0; + chip->cpsr = 0; + if ((chip_info->com_mode == DMA_TRANSFER) + && ((pl022->master_info)->enable_dma)) { + chip->enable_dma = 1; + dev_dbg(&spi->dev, "DMA mode set in controller state\n"); + status = process_dma_info(chip_info, chip); + if (status < 0) + goto err_config_params; + SSP_WRITE_BITS(chip->dmacr, SSP_DMA_ENABLED, + SSP_DMACR_MASK_RXDMAE, 0); + SSP_WRITE_BITS(chip->dmacr, SSP_DMA_ENABLED, + SSP_DMACR_MASK_TXDMAE, 1); + } else { + chip->enable_dma = 0; + dev_dbg(&spi->dev, "DMA mode NOT set in controller state\n"); + SSP_WRITE_BITS(chip->dmacr, SSP_DMA_DISABLED, + SSP_DMACR_MASK_RXDMAE, 0); + SSP_WRITE_BITS(chip->dmacr, SSP_DMA_DISABLED, + SSP_DMACR_MASK_TXDMAE, 1); + } + + chip->cpsr = chip_info->clk_freq.cpsdvsr; + + SSP_WRITE_BITS(chip->cr0, chip_info->data_size, SSP_CR0_MASK_DSS, 0); + SSP_WRITE_BITS(chip->cr0, chip_info->duplex, SSP_CR0_MASK_HALFDUP, 5); + SSP_WRITE_BITS(chip->cr0, chip_info->clk_pol, SSP_CR0_MASK_SPO, 6); + SSP_WRITE_BITS(chip->cr0, chip_info->clk_phase, SSP_CR0_MASK_SPH, 7); + SSP_WRITE_BITS(chip->cr0, chip_info->clk_freq.scr, SSP_CR0_MASK_SCR, 8); + SSP_WRITE_BITS(chip->cr0, chip_info->ctrl_len, SSP_CR0_MASK_CSS, 16); + SSP_WRITE_BITS(chip->cr0, chip_info->iface, SSP_CR0_MASK_FRF, 21); + SSP_WRITE_BITS(chip->cr1, chip_info->lbm, SSP_CR1_MASK_LBM, 0); + SSP_WRITE_BITS(chip->cr1, SSP_DISABLED, SSP_CR1_MASK_SSE, 1); + SSP_WRITE_BITS(chip->cr1, chip_info->hierarchy, SSP_CR1_MASK_MS, 2); + SSP_WRITE_BITS(chip->cr1, chip_info->slave_tx_disable, SSP_CR1_MASK_SOD, 3); + SSP_WRITE_BITS(chip->cr1, chip_info->endian_rx, SSP_CR1_MASK_RENDN, 4); + SSP_WRITE_BITS(chip->cr1, chip_info->endian_tx, SSP_CR1_MASK_TENDN, 5); + SSP_WRITE_BITS(chip->cr1, chip_info->wait_state, SSP_CR1_MASK_MWAIT, 6); + SSP_WRITE_BITS(chip->cr1, chip_info->rx_lev_trig, SSP_CR1_MASK_RXIFLSEL, 7); + SSP_WRITE_BITS(chip->cr1, chip_info->tx_lev_trig, SSP_CR1_MASK_TXIFLSEL, 10); + + /* Save controller_state */ + spi_set_ctldata(spi, chip); + return status; + err_config_params: + err_first_setup: + kfree(chip); + return status; +} + +/** + * pl022_cleanup - cleanup function registered to SPI master framework + * @spi: spi device which is requesting cleanup + * + * This function is registered to the SPI framework for this SPI master + * controller. It will free the runtime state of chip. + */ +static void pl022_cleanup(struct spi_device *spi) +{ + struct chip_data *chip = spi_get_ctldata(spi); + + spi_set_ctldata(spi, NULL); + kfree(chip); +} + + +static int __init +pl022_probe(struct amba_device *adev, struct amba_id *id) +{ + struct device *dev = &adev->dev; + struct pl022_ssp_controller *platform_info = adev->dev.platform_data; + struct spi_master *master; + struct pl022 *pl022 = NULL; /*Data for this driver */ + int status = 0; + + dev_info(&adev->dev, + "ARM PL022 driver, device ID: 0x%08x\n", adev->periphid); + if (platform_info == NULL) { + dev_err(&adev->dev, "probe - no platform data supplied\n"); + status = -ENODEV; + goto err_no_pdata; + } + + /* Allocate master with space for data */ + master = spi_alloc_master(dev, sizeof(struct pl022)); + if (master == NULL) { + dev_err(&adev->dev, "probe - cannot alloc SPI master\n"); + status = -ENOMEM; + goto err_no_master; + } + + pl022 = spi_master_get_devdata(master); + pl022->master = master; + pl022->master_info = platform_info; + pl022->adev = adev; + pl022->vendor = id->data; + + /* + * Bus Number Which has been Assigned to this SSP controller + * on this board + */ + master->bus_num = platform_info->bus_id; + master->num_chipselect = platform_info->num_chipselect; + master->cleanup = pl022_cleanup; + master->setup = pl022_setup; + master->transfer = pl022_transfer; + + dev_dbg(&adev->dev, "BUSNO: %d\n", master->bus_num); + + status = amba_request_regions(adev, NULL); + if (status) + goto err_no_ioregion; + + pl022->virtbase = ioremap(adev->res.start, resource_size(&adev->res)); + if (pl022->virtbase == NULL) { + status = -ENOMEM; + goto err_no_ioremap; + } + printk(KERN_INFO "pl022: mapped registers from 0x%08x to %p\n", + adev->res.start, pl022->virtbase); + + pl022->clk = clk_get(&adev->dev, NULL); + if (IS_ERR(pl022->clk)) { + status = PTR_ERR(pl022->clk); + dev_err(&adev->dev, "could not retrieve SSP/SPI bus clock\n"); + goto err_no_clk; + } + + /* Disable SSP */ + clk_enable(pl022->clk); + writew((readw(SSP_CR1(pl022->virtbase)) & (~SSP_CR1_MASK_SSE)), + SSP_CR1(pl022->virtbase)); + load_ssp_default_config(pl022); + clk_disable(pl022->clk); + + status = request_irq(adev->irq[0], pl022_interrupt_handler, 0, "pl022", + pl022); + if (status < 0) { + dev_err(&adev->dev, "probe - cannot get IRQ (%d)\n", status); + goto err_no_irq; + } + /* Initialize and start queue */ + status = init_queue(pl022); + if (status != 0) { + dev_err(&adev->dev, "probe - problem initializing queue\n"); + goto err_init_queue; + } + status = start_queue(pl022); + if (status != 0) { + dev_err(&adev->dev, "probe - problem starting queue\n"); + goto err_start_queue; + } + /* Register with the SPI framework */ + amba_set_drvdata(adev, pl022); + status = spi_register_master(master); + if (status != 0) { + dev_err(&adev->dev, + "probe - problem registering spi master\n"); + goto err_spi_register; + } + dev_dbg(dev, "probe succeded\n"); + return 0; + + err_spi_register: + err_start_queue: + err_init_queue: + destroy_queue(pl022); + free_irq(adev->irq[0], pl022); + err_no_irq: + clk_put(pl022->clk); + err_no_clk: + iounmap(pl022->virtbase); + err_no_ioremap: + amba_release_regions(adev); + err_no_ioregion: + spi_master_put(master); + err_no_master: + err_no_pdata: + return status; +} + +static int __exit +pl022_remove(struct amba_device *adev) +{ + struct pl022 *pl022 = amba_get_drvdata(adev); + int status = 0; + if (!pl022) + return 0; + + /* Remove the queue */ + status = destroy_queue(pl022); + if (status != 0) { + dev_err(&adev->dev, + "queue remove failed (%d)\n", status); + return status; + } + load_ssp_default_config(pl022); + free_irq(adev->irq[0], pl022); + clk_disable(pl022->clk); + clk_put(pl022->clk); + iounmap(pl022->virtbase); + amba_release_regions(adev); + tasklet_disable(&pl022->pump_transfers); + spi_unregister_master(pl022->master); + spi_master_put(pl022->master); + amba_set_drvdata(adev, NULL); + dev_dbg(&adev->dev, "remove succeded\n"); + return 0; +} + +#ifdef CONFIG_PM +static int pl022_suspend(struct amba_device *adev, pm_message_t state) +{ + struct pl022 *pl022 = amba_get_drvdata(adev); + int status = 0; + + status = stop_queue(pl022); + if (status) { + dev_warn(&adev->dev, "suspend cannot stop queue\n"); + return status; + } + + clk_enable(pl022->clk); + load_ssp_default_config(pl022); + clk_disable(pl022->clk); + dev_dbg(&adev->dev, "suspended\n"); + return 0; +} + +static int pl022_resume(struct amba_device *adev) +{ + struct pl022 *pl022 = amba_get_drvdata(adev); + int status = 0; + + /* Start the queue running */ + status = start_queue(pl022); + if (status) + dev_err(&adev->dev, "problem starting queue (%d)\n", status); + else + dev_dbg(&adev->dev, "resumed\n"); + + return status; +} +#else +#define pl022_suspend NULL +#define pl022_resume NULL +#endif /* CONFIG_PM */ + +static struct vendor_data vendor_arm = { + .fifodepth = 8, + .max_bpw = 16, + .unidir = false, +}; + + +static struct vendor_data vendor_st = { + .fifodepth = 32, + .max_bpw = 32, + .unidir = false, +}; + +static struct amba_id pl022_ids[] = { + { + /* + * ARM PL022 variant, this has a 16bit wide + * and 8 locations deep TX/RX FIFO + */ + .id = 0x00041022, + .mask = 0x000fffff, + .data = &vendor_arm, + }, + { + /* + * ST Micro derivative, this has 32bit wide + * and 32 locations deep TX/RX FIFO + */ + .id = 0x00108022, + .mask = 0xffffffff, + .data = &vendor_st, + }, + { 0, 0 }, +}; + +static struct amba_driver pl022_driver = { + .drv = { + .name = "ssp-pl022", + }, + .id_table = pl022_ids, + .probe = pl022_probe, + .remove = __exit_p(pl022_remove), + .suspend = pl022_suspend, + .resume = pl022_resume, +}; + + +static int __init pl022_init(void) +{ + return amba_driver_register(&pl022_driver); +} + +module_init(pl022_init); + +static void __exit pl022_exit(void) +{ + amba_driver_unregister(&pl022_driver); +} + +module_exit(pl022_exit); + +MODULE_AUTHOR("Linus Walleij "); +MODULE_DESCRIPTION("PL022 SSP Controller Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c index 12e443cc4ac9..f5b3fdbb1e27 100644 --- a/drivers/spi/atmel_spi.c +++ b/drivers/spi/atmel_spi.c @@ -530,9 +530,6 @@ atmel_spi_interrupt(int irq, void *dev_id) return ret; } -/* the spi->mode bits understood by this driver: */ -#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH) - static int atmel_spi_setup(struct spi_device *spi) { struct atmel_spi *as; @@ -555,8 +552,6 @@ static int atmel_spi_setup(struct spi_device *spi) return -EINVAL; } - if (bits == 0) - bits = 8; if (bits < 8 || bits > 16) { dev_dbg(&spi->dev, "setup: invalid bits_per_word %u (8 to 16)\n", @@ -564,12 +559,6 @@ static int atmel_spi_setup(struct spi_device *spi) return -EINVAL; } - if (spi->mode & ~MODEBITS) { - dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n", - spi->mode & ~MODEBITS); - return -EINVAL; - } - /* see notes above re chipselect */ if (!atmel_spi_is_v2() && spi->chip_select == 0 @@ -775,6 +764,9 @@ static int __init atmel_spi_probe(struct platform_device *pdev) if (!master) goto out_free; + /* the spi->mode bits understood by this driver: */ + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; + master->bus_num = pdev->id; master->num_chipselect = 4; master->setup = atmel_spi_setup; diff --git a/drivers/spi/au1550_spi.c b/drivers/spi/au1550_spi.c index b02f25c702fd..76cbc1a66598 100644 --- a/drivers/spi/au1550_spi.c +++ b/drivers/spi/au1550_spi.c @@ -284,27 +284,16 @@ static int au1550_spi_setupxfer(struct spi_device *spi, struct spi_transfer *t) return 0; } -/* the spi->mode bits understood by this driver: */ -#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST) - static int au1550_spi_setup(struct spi_device *spi) { struct au1550_spi *hw = spi_master_get_devdata(spi->master); - if (spi->bits_per_word == 0) - spi->bits_per_word = 8; if (spi->bits_per_word < 4 || spi->bits_per_word > 24) { dev_err(&spi->dev, "setup: invalid bits_per_word=%d\n", spi->bits_per_word); return -EINVAL; } - if (spi->mode & ~MODEBITS) { - dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n", - spi->mode & ~MODEBITS); - return -EINVAL; - } - if (spi->max_speed_hz == 0) spi->max_speed_hz = hw->freq_max; if (spi->max_speed_hz > hw->freq_max @@ -781,6 +770,9 @@ static int __init au1550_spi_probe(struct platform_device *pdev) goto err_nomem; } + /* the spi->mode bits understood by this driver: */ + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST; + hw = spi_master_get_devdata(master); hw->master = spi_master_get(master); diff --git a/drivers/spi/mpc52xx_psc_spi.c b/drivers/spi/mpc52xx_psc_spi.c index 68c77a911595..1b74d5ca03f3 100644 --- a/drivers/spi/mpc52xx_psc_spi.c +++ b/drivers/spi/mpc52xx_psc_spi.c @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -30,8 +31,7 @@ struct mpc52xx_psc_spi { /* fsl_spi_platform data */ - void (*activate_cs)(u8, u8); - void (*deactivate_cs)(u8, u8); + void (*cs_control)(struct spi_device *spi, bool on); u32 sysclk; /* driver internal data */ @@ -111,18 +111,16 @@ static void mpc52xx_psc_spi_activate_cs(struct spi_device *spi) out_be16((u16 __iomem *)&psc->ccr, ccr); mps->bits_per_word = cs->bits_per_word; - if (mps->activate_cs) - mps->activate_cs(spi->chip_select, - (spi->mode & SPI_CS_HIGH) ? 1 : 0); + if (mps->cs_control) + mps->cs_control(spi, (spi->mode & SPI_CS_HIGH) ? 1 : 0); } static void mpc52xx_psc_spi_deactivate_cs(struct spi_device *spi) { struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master); - if (mps->deactivate_cs) - mps->deactivate_cs(spi->chip_select, - (spi->mode & SPI_CS_HIGH) ? 1 : 0); + if (mps->cs_control) + mps->cs_control(spi, (spi->mode & SPI_CS_HIGH) ? 0 : 1); } #define MPC52xx_PSC_BUFSIZE (MPC52xx_PSC_RFNUM_MASK + 1) @@ -261,9 +259,6 @@ static void mpc52xx_psc_spi_work(struct work_struct *work) spin_unlock_irq(&mps->lock); } -/* the spi->mode bits understood by this driver: */ -#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST) - static int mpc52xx_psc_spi_setup(struct spi_device *spi) { struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master); @@ -273,12 +268,6 @@ static int mpc52xx_psc_spi_setup(struct spi_device *spi) if (spi->bits_per_word%8) return -EINVAL; - if (spi->mode & ~MODEBITS) { - dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n", - spi->mode & ~MODEBITS); - return -EINVAL; - } - if (!cs) { cs = kzalloc(sizeof *cs, GFP_KERNEL); if (!cs) @@ -385,18 +374,19 @@ static int __init mpc52xx_psc_spi_do_probe(struct device *dev, u32 regaddr, dev_set_drvdata(dev, master); mps = spi_master_get_devdata(master); + /* the spi->mode bits understood by this driver: */ + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST; + mps->irq = irq; if (pdata == NULL) { dev_warn(dev, "probe called without platform data, no " - "(de)activate_cs function will be called\n"); - mps->activate_cs = NULL; - mps->deactivate_cs = NULL; + "cs_control function will be called\n"); + mps->cs_control = NULL; mps->sysclk = 0; master->bus_num = bus_num; master->num_chipselect = 255; } else { - mps->activate_cs = pdata->activate_cs; - mps->deactivate_cs = pdata->deactivate_cs; + mps->cs_control = pdata->cs_control; mps->sysclk = pdata->sysclk; master->bus_num = pdata->bus_num; master->num_chipselect = pdata->max_chipselect; diff --git a/drivers/spi/omap2_mcspi.c b/drivers/spi/omap2_mcspi.c index d6d0c5d241ce..eee4b6e0af2c 100644 --- a/drivers/spi/omap2_mcspi.c +++ b/drivers/spi/omap2_mcspi.c @@ -603,9 +603,6 @@ static int omap2_mcspi_request_dma(struct spi_device *spi) return 0; } -/* the spi->mode bits understood by this driver: */ -#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH) - static int omap2_mcspi_setup(struct spi_device *spi) { int ret; @@ -613,15 +610,7 @@ static int omap2_mcspi_setup(struct spi_device *spi) struct omap2_mcspi_dma *mcspi_dma; struct omap2_mcspi_cs *cs = spi->controller_state; - if (spi->mode & ~MODEBITS) { - dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n", - spi->mode & ~MODEBITS); - return -EINVAL; - } - - if (spi->bits_per_word == 0) - spi->bits_per_word = 8; - else if (spi->bits_per_word < 4 || spi->bits_per_word > 32) { + if (spi->bits_per_word < 4 || spi->bits_per_word > 32) { dev_dbg(&spi->dev, "setup: unsupported %d bit words\n", spi->bits_per_word); return -EINVAL; @@ -984,6 +973,9 @@ static int __init omap2_mcspi_probe(struct platform_device *pdev) return -ENOMEM; } + /* the spi->mode bits understood by this driver: */ + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; + if (pdev->id != -1) master->bus_num = pdev->id; diff --git a/drivers/spi/omap_uwire.c b/drivers/spi/omap_uwire.c index fe8b9ac0ccef..aa90ddb37066 100644 --- a/drivers/spi/omap_uwire.c +++ b/drivers/spi/omap_uwire.c @@ -339,8 +339,6 @@ static int uwire_setup_transfer(struct spi_device *spi, struct spi_transfer *t) bits = spi->bits_per_word; if (t != NULL && t->bits_per_word) bits = t->bits_per_word; - if (!bits) - bits = 8; if (bits > 16) { pr_debug("%s: wordsize %d?\n", dev_name(&spi->dev), bits); @@ -449,19 +447,10 @@ done: return status; } -/* the spi->mode bits understood by this driver: */ -#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH) - static int uwire_setup(struct spi_device *spi) { struct uwire_state *ust = spi->controller_state; - if (spi->mode & ~MODEBITS) { - dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n", - spi->mode & ~MODEBITS); - return -EINVAL; - } - if (ust == NULL) { ust = kzalloc(sizeof(*ust), GFP_KERNEL); if (ust == NULL) @@ -522,6 +511,9 @@ static int __init uwire_probe(struct platform_device *pdev) uwire_write_reg(UWIRE_SR3, 1); + /* the spi->mode bits understood by this driver: */ + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; + master->bus_num = 2; /* "official" */ master->num_chipselect = 4; master->setup = uwire_setup; diff --git a/drivers/spi/orion_spi.c b/drivers/spi/orion_spi.c index c8b0babdc2a6..3aea50da7b29 100644 --- a/drivers/spi/orion_spi.c +++ b/drivers/spi/orion_spi.c @@ -358,20 +358,11 @@ static int orion_spi_setup(struct spi_device *spi) orion_spi = spi_master_get_devdata(spi->master); - if (spi->mode) { - dev_err(&spi->dev, "setup: unsupported mode bits %x\n", - spi->mode); - return -EINVAL; - } - /* Fix ac timing if required. */ if (orion_spi->spi_info->enable_clock_fix) orion_spi_setbits(orion_spi, ORION_SPI_IF_CONFIG_REG, (1 << 14)); - if (spi->bits_per_word == 0) - spi->bits_per_word = 8; - if ((spi->max_speed_hz == 0) || (spi->max_speed_hz > orion_spi->max_speed)) spi->max_speed_hz = orion_spi->max_speed; @@ -476,6 +467,9 @@ static int __init orion_spi_probe(struct platform_device *pdev) if (pdev->id != -1) master->bus_num = pdev->id; + /* we support only mode 0, and no options */ + master->mode_bits = 0; + master->setup = orion_spi_setup; master->transfer = orion_spi_transfer; master->num_chipselect = ORION_NUM_CHIPSELECTS; diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c index 3f3c08c6ba4e..d949dbf1141f 100644 --- a/drivers/spi/pxa2xx_spi.c +++ b/drivers/spi/pxa2xx_spi.c @@ -1185,9 +1185,6 @@ static int transfer(struct spi_device *spi, struct spi_message *msg) return 0; } -/* the spi->mode bits understood by this driver: */ -#define MODEBITS (SPI_CPOL | SPI_CPHA) - static int setup_cs(struct spi_device *spi, struct chip_data *chip, struct pxa2xx_spi_chip *chip_info) { @@ -1236,9 +1233,6 @@ static int setup(struct spi_device *spi) uint tx_thres = TX_THRESH_DFLT; uint rx_thres = RX_THRESH_DFLT; - if (!spi->bits_per_word) - spi->bits_per_word = 8; - if (drv_data->ssp_type != PXA25x_SSP && (spi->bits_per_word < 4 || spi->bits_per_word > 32)) { dev_err(&spi->dev, "failed setup: ssp_type=%d, bits/wrd=%d " @@ -1255,12 +1249,6 @@ static int setup(struct spi_device *spi) return -EINVAL; } - if (spi->mode & ~MODEBITS) { - dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n", - spi->mode & ~MODEBITS); - return -EINVAL; - } - /* Only alloc on first setup */ chip = spi_get_ctldata(spi); if (!chip) { @@ -1328,18 +1316,14 @@ static int setup(struct spi_device *spi) /* NOTE: PXA25x_SSP _could_ use external clocking ... */ if (drv_data->ssp_type != PXA25x_SSP) - dev_dbg(&spi->dev, "%d bits/word, %ld Hz, mode %d, %s\n", - spi->bits_per_word, + dev_dbg(&spi->dev, "%ld Hz actual, %s\n", clk_get_rate(ssp->clk) / (1 + ((chip->cr0 & SSCR0_SCR) >> 8)), - spi->mode & 0x3, chip->enable_dma ? "DMA" : "PIO"); else - dev_dbg(&spi->dev, "%d bits/word, %ld Hz, mode %d, %s\n", - spi->bits_per_word, + dev_dbg(&spi->dev, "%ld Hz actual, %s\n", clk_get_rate(ssp->clk) / 2 / (1 + ((chip->cr0 & SSCR0_SCR) >> 8)), - spi->mode & 0x3, chip->enable_dma ? "DMA" : "PIO"); if (spi->bits_per_word <= 8) { @@ -1500,6 +1484,9 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev) drv_data->pdev = pdev; drv_data->ssp = ssp; + /* the spi->mode bits understood by this driver: */ + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; + master->bus_num = pdev->id; master->num_chipselect = platform_info->num_chipselect; master->dma_alignment = DMA_ALIGNMENT; diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 8eba98c8ed1e..70845ccd85c3 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -265,7 +265,7 @@ int spi_add_device(struct spi_device *spi) * normally rely on the device being setup. Devices * using SPI_CS_HIGH can't coexist well otherwise... */ - status = spi->master->setup(spi); + status = spi_setup(spi); if (status < 0) { dev_err(dev, "can't %s %s, status %d\n", "setup", dev_name(&spi->dev), status); @@ -583,6 +583,70 @@ EXPORT_SYMBOL_GPL(spi_busnum_to_master); /*-------------------------------------------------------------------------*/ +/* Core methods for SPI master protocol drivers. Some of the + * other core methods are currently defined as inline functions. + */ + +/** + * spi_setup - setup SPI mode and clock rate + * @spi: the device whose settings are being modified + * Context: can sleep, and no requests are queued to the device + * + * SPI protocol drivers may need to update the transfer mode if the + * device doesn't work with its default. They may likewise need + * to update clock rates or word sizes from initial values. This function + * changes those settings, and must be called from a context that can sleep. + * Except for SPI_CS_HIGH, which takes effect immediately, the changes take + * effect the next time the device is selected and data is transferred to + * or from it. When this function returns, the spi device is deselected. + * + * Note that this call will fail if the protocol driver specifies an option + * that the underlying controller or its driver does not support. For + * example, not all hardware supports wire transfers using nine bit words, + * LSB-first wire encoding, or active-high chipselects. + */ +int spi_setup(struct spi_device *spi) +{ + unsigned bad_bits; + int status; + + /* help drivers fail *cleanly* when they need options + * that aren't supported with their current master + */ + bad_bits = spi->mode & ~spi->master->mode_bits; + if (bad_bits) { + dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n", + bad_bits); + return -EINVAL; + } + + if (!spi->bits_per_word) + spi->bits_per_word = 8; + + status = spi->master->setup(spi); + + dev_dbg(&spi->dev, "setup mode %d, %s%s%s%s" + "%u bits/w, %u Hz max --> %d\n", + (int) (spi->mode & (SPI_CPOL | SPI_CPHA)), + (spi->mode & SPI_CS_HIGH) ? "cs_high, " : "", + (spi->mode & SPI_LSB_FIRST) ? "lsb, " : "", + (spi->mode & SPI_3WIRE) ? "3wire, " : "", + (spi->mode & SPI_LOOP) ? "loopback, " : "", + spi->bits_per_word, spi->max_speed_hz, + status); + + return status; +} +EXPORT_SYMBOL_GPL(spi_setup); + + +/*-------------------------------------------------------------------------*/ + +/* Utility methods for SPI master protocol drivers, layered on + * top of the core. Some other utility methods are defined as + * inline functions. + */ + static void spi_complete(void *arg) { complete(arg); @@ -636,8 +700,8 @@ static u8 *buf; * @spi: device with which data will be exchanged * @txbuf: data to be written (need not be dma-safe) * @n_tx: size of txbuf, in bytes - * @rxbuf: buffer into which data will be read - * @n_rx: size of rxbuf, in bytes (need not be dma-safe) + * @rxbuf: buffer into which data will be read (need not be dma-safe) + * @n_rx: size of rxbuf, in bytes * Context: can sleep * * This performs a half duplex MicroWire style transaction with the diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c index f014cc21e813..73e24ef5a2f9 100644 --- a/drivers/spi/spi_bfin5xx.c +++ b/drivers/spi/spi_bfin5xx.c @@ -169,7 +169,7 @@ static int bfin_spi_flush(struct driver_data *drv_data) unsigned long limit = loops_per_jiffy << 1; /* wait for stop and clear stat */ - while (!(read_STAT(drv_data) & BIT_STAT_SPIF) && limit--) + while (!(read_STAT(drv_data) & BIT_STAT_SPIF) && --limit) cpu_relax(); write_STAT(drv_data, BIT_STAT_CLR); @@ -803,7 +803,7 @@ static void bfin_spi_pump_transfers(unsigned long data) drv_data->rx, drv_data->len_in_bytes); /* invalidate caches, if needed */ - if (bfin_addr_dcachable((unsigned long) drv_data->rx)) + if (bfin_addr_dcacheable((unsigned long) drv_data->rx)) invalidate_dcache_range((unsigned long) drv_data->rx, (unsigned long) (drv_data->rx + drv_data->len_in_bytes)); @@ -816,7 +816,7 @@ static void bfin_spi_pump_transfers(unsigned long data) dev_dbg(&drv_data->pdev->dev, "doing DMA out.\n"); /* flush caches, if needed */ - if (bfin_addr_dcachable((unsigned long) drv_data->tx)) + if (bfin_addr_dcacheable((unsigned long) drv_data->tx)) flush_dcache_range((unsigned long) drv_data->tx, (unsigned long) (drv_data->tx + drv_data->len_in_bytes)); @@ -1010,16 +1010,6 @@ static int bfin_spi_setup(struct spi_device *spi) struct driver_data *drv_data = spi_master_get_devdata(spi->master); int ret; - /* Abort device setup if requested features are not supported */ - if (spi->mode & ~(SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST)) { - dev_err(&spi->dev, "requested mode not fully supported\n"); - return -EINVAL; - } - - /* Zero (the default) here means 8 bits */ - if (!spi->bits_per_word) - spi->bits_per_word = 8; - if (spi->bits_per_word != 8 && spi->bits_per_word != 16) return -EINVAL; @@ -1287,6 +1277,9 @@ static int __init bfin_spi_probe(struct platform_device *pdev) drv_data->pdev = pdev; drv_data->pin_req = platform_info->pin_req; + /* the spi->mode bits supported by this driver: */ + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST; + master->bus_num = pdev->id; master->num_chipselect = platform_info->num_chipselect; master->cleanup = bfin_spi_cleanup; diff --git a/drivers/spi/spi_bitbang.c b/drivers/spi/spi_bitbang.c index 85e61f451218..2a5abc08e857 100644 --- a/drivers/spi/spi_bitbang.c +++ b/drivers/spi/spi_bitbang.c @@ -188,12 +188,6 @@ int spi_bitbang_setup(struct spi_device *spi) bitbang = spi_master_get_devdata(spi->master); - /* Bitbangers can support SPI_CS_HIGH, SPI_3WIRE, and so on; - * add those to master->flags, and provide the other support. - */ - if ((spi->mode & ~(SPI_CPOL|SPI_CPHA|bitbang->flags)) != 0) - return -EINVAL; - if (!cs) { cs = kzalloc(sizeof *cs, GFP_KERNEL); if (!cs) @@ -201,9 +195,6 @@ int spi_bitbang_setup(struct spi_device *spi) spi->controller_state = cs; } - if (!spi->bits_per_word) - spi->bits_per_word = 8; - /* per-word shift register access, in hardware or bitbanging */ cs->txrx_word = bitbang->txrx_word[spi->mode & (SPI_CPOL|SPI_CPHA)]; if (!cs->txrx_word) @@ -213,9 +204,7 @@ int spi_bitbang_setup(struct spi_device *spi) if (retval < 0) return retval; - dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u nsec/bit\n", - __func__, spi->mode & (SPI_CPOL | SPI_CPHA), - spi->bits_per_word, 2 * cs->nsecs); + dev_dbg(&spi->dev, "%s, %u nsec/bit\n", __func__, 2 * cs->nsecs); /* NOTE we _need_ to call chipselect() early, ideally with adapter * setup, unless the hardware defaults cooperate to avoid confusion @@ -457,6 +446,9 @@ int spi_bitbang_start(struct spi_bitbang *bitbang) spin_lock_init(&bitbang->lock); INIT_LIST_HEAD(&bitbang->queue); + if (!bitbang->master->mode_bits) + bitbang->master->mode_bits = SPI_CPOL | SPI_CPHA | bitbang->flags; + if (!bitbang->master->transfer) bitbang->master->transfer = spi_bitbang_transfer; if (!bitbang->txrx_bufs) { diff --git a/drivers/spi/spi_imx.c b/drivers/spi/spi_imx.c index 0671aeef5792..c195e45f7f35 100644 --- a/drivers/spi/spi_imx.c +++ b/drivers/spi/spi_imx.c @@ -1171,9 +1171,6 @@ msg_rejected: return -EINVAL; } -/* the spi->mode bits understood by this driver: */ -#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH) - /* On first setup bad values must free chip_data memory since will cause spi_new_device to fail. Bad value setup from protocol driver are simply not applied and notified to the calling driver. */ @@ -1186,12 +1183,6 @@ static int setup(struct spi_device *spi) u32 tmp; int status = 0; - if (spi->mode & ~MODEBITS) { - dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n", - spi->mode & ~MODEBITS); - return -EINVAL; - } - /* Get controller data */ chip_info = spi->controller_data; @@ -1286,10 +1277,7 @@ static int setup(struct spi_device *spi) /* SPI word width */ tmp = spi->bits_per_word; - if (tmp == 0) { - tmp = 8; - spi->bits_per_word = 8; - } else if (tmp > 16) { + if (tmp > 16) { status = -EINVAL; dev_err(&spi->dev, "setup - " @@ -1481,6 +1469,9 @@ static int __init spi_imx_probe(struct platform_device *pdev) drv_data->master_info = platform_info; drv_data->pdev = pdev; + /* the spi->mode bits understood by this driver: */ + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; + master->bus_num = pdev->id; master->num_chipselect = platform_info->num_chipselect; master->dma_alignment = DMA_ALIGNMENT; diff --git a/drivers/spi/spi_mpc83xx.c b/drivers/spi/spi_mpc8xxx.c similarity index 52% rename from drivers/spi/spi_mpc83xx.c rename to drivers/spi/spi_mpc8xxx.c index f4573a96af24..0fd0ec4d3a7d 100644 --- a/drivers/spi/spi_mpc83xx.c +++ b/drivers/spi/spi_mpc8xxx.c @@ -1,5 +1,5 @@ /* - * MPC83xx SPI controller driver. + * MPC8xxx SPI controller driver. * * Maintainer: Kumar Gala * @@ -14,8 +14,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -33,10 +35,9 @@ #include #include -#include /* SPI Controller registers */ -struct mpc83xx_spi_reg { +struct mpc8xxx_spi_reg { u8 res1[0x20]; __be32 mode; __be32 event; @@ -75,16 +76,16 @@ struct mpc83xx_spi_reg { #define SPIM_NF 0x00000100 /* Not full */ /* SPI Controller driver's private data. */ -struct mpc83xx_spi { - struct mpc83xx_spi_reg __iomem *base; +struct mpc8xxx_spi { + struct mpc8xxx_spi_reg __iomem *base; /* rx & tx bufs from the spi_transfer */ const void *tx; void *rx; /* functions to deal with different sized buffers */ - void (*get_rx) (u32 rx_data, struct mpc83xx_spi *); - u32(*get_tx) (struct mpc83xx_spi *); + void (*get_rx) (u32 rx_data, struct mpc8xxx_spi *); + u32(*get_tx) (struct mpc8xxx_spi *); unsigned int count; unsigned int irq; @@ -97,8 +98,6 @@ struct mpc83xx_spi { bool qe_mode; - u8 busy; - struct workqueue_struct *workqueue; struct work_struct work; @@ -108,44 +107,44 @@ struct mpc83xx_spi { struct completion done; }; -struct spi_mpc83xx_cs { +struct spi_mpc8xxx_cs { /* functions to deal with different sized buffers */ - void (*get_rx) (u32 rx_data, struct mpc83xx_spi *); - u32 (*get_tx) (struct mpc83xx_spi *); + void (*get_rx) (u32 rx_data, struct mpc8xxx_spi *); + u32 (*get_tx) (struct mpc8xxx_spi *); u32 rx_shift; /* RX data reg shift when in qe mode */ u32 tx_shift; /* TX data reg shift when in qe mode */ u32 hw_mode; /* Holds HW mode register settings */ }; -static inline void mpc83xx_spi_write_reg(__be32 __iomem * reg, u32 val) +static inline void mpc8xxx_spi_write_reg(__be32 __iomem *reg, u32 val) { out_be32(reg, val); } -static inline u32 mpc83xx_spi_read_reg(__be32 __iomem * reg) +static inline u32 mpc8xxx_spi_read_reg(__be32 __iomem *reg) { return in_be32(reg); } #define MPC83XX_SPI_RX_BUF(type) \ static \ -void mpc83xx_spi_rx_buf_##type(u32 data, struct mpc83xx_spi *mpc83xx_spi) \ +void mpc8xxx_spi_rx_buf_##type(u32 data, struct mpc8xxx_spi *mpc8xxx_spi) \ { \ - type * rx = mpc83xx_spi->rx; \ - *rx++ = (type)(data >> mpc83xx_spi->rx_shift); \ - mpc83xx_spi->rx = rx; \ + type *rx = mpc8xxx_spi->rx; \ + *rx++ = (type)(data >> mpc8xxx_spi->rx_shift); \ + mpc8xxx_spi->rx = rx; \ } #define MPC83XX_SPI_TX_BUF(type) \ static \ -u32 mpc83xx_spi_tx_buf_##type(struct mpc83xx_spi *mpc83xx_spi) \ +u32 mpc8xxx_spi_tx_buf_##type(struct mpc8xxx_spi *mpc8xxx_spi) \ { \ u32 data; \ - const type * tx = mpc83xx_spi->tx; \ + const type *tx = mpc8xxx_spi->tx; \ if (!tx) \ return 0; \ - data = *tx++ << mpc83xx_spi->tx_shift; \ - mpc83xx_spi->tx = tx; \ + data = *tx++ << mpc8xxx_spi->tx_shift; \ + mpc8xxx_spi->tx = tx; \ return data; \ } @@ -156,12 +155,12 @@ MPC83XX_SPI_TX_BUF(u8) MPC83XX_SPI_TX_BUF(u16) MPC83XX_SPI_TX_BUF(u32) -static void mpc83xx_spi_chipselect(struct spi_device *spi, int value) +static void mpc8xxx_spi_chipselect(struct spi_device *spi, int value) { - struct mpc83xx_spi *mpc83xx_spi = spi_master_get_devdata(spi->master); + struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master); struct fsl_spi_platform_data *pdata = spi->dev.parent->platform_data; bool pol = spi->mode & SPI_CS_HIGH; - struct spi_mpc83xx_cs *cs = spi->controller_state; + struct spi_mpc8xxx_cs *cs = spi->controller_state; if (value == BITBANG_CS_INACTIVE) { if (pdata->cs_control) @@ -169,16 +168,16 @@ static void mpc83xx_spi_chipselect(struct spi_device *spi, int value) } if (value == BITBANG_CS_ACTIVE) { - u32 regval = mpc83xx_spi_read_reg(&mpc83xx_spi->base->mode); + u32 regval = mpc8xxx_spi_read_reg(&mpc8xxx_spi->base->mode); - mpc83xx_spi->rx_shift = cs->rx_shift; - mpc83xx_spi->tx_shift = cs->tx_shift; - mpc83xx_spi->get_rx = cs->get_rx; - mpc83xx_spi->get_tx = cs->get_tx; + mpc8xxx_spi->rx_shift = cs->rx_shift; + mpc8xxx_spi->tx_shift = cs->tx_shift; + mpc8xxx_spi->get_rx = cs->get_rx; + mpc8xxx_spi->get_tx = cs->get_tx; if (cs->hw_mode != regval) { unsigned long flags; - __be32 __iomem *mode = &mpc83xx_spi->base->mode; + __be32 __iomem *mode = &mpc8xxx_spi->base->mode; regval = cs->hw_mode; /* Turn off IRQs locally to minimize time that @@ -186,8 +185,8 @@ static void mpc83xx_spi_chipselect(struct spi_device *spi, int value) */ local_irq_save(flags); /* Turn off SPI unit prior changing mode */ - mpc83xx_spi_write_reg(mode, regval & ~SPMODE_ENABLE); - mpc83xx_spi_write_reg(mode, regval); + mpc8xxx_spi_write_reg(mode, regval & ~SPMODE_ENABLE); + mpc8xxx_spi_write_reg(mode, regval); local_irq_restore(flags); } if (pdata->cs_control) @@ -196,15 +195,15 @@ static void mpc83xx_spi_chipselect(struct spi_device *spi, int value) } static -int mpc83xx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) +int mpc8xxx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) { - struct mpc83xx_spi *mpc83xx_spi; + struct mpc8xxx_spi *mpc8xxx_spi; u32 regval; u8 bits_per_word, pm; u32 hz; - struct spi_mpc83xx_cs *cs = spi->controller_state; + struct spi_mpc8xxx_cs *cs = spi->controller_state; - mpc83xx_spi = spi_master_get_devdata(spi->master); + mpc8xxx_spi = spi_master_get_devdata(spi->master); if (t) { bits_per_word = t->bits_per_word; @@ -229,26 +228,26 @@ int mpc83xx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) cs->rx_shift = 0; cs->tx_shift = 0; if (bits_per_word <= 8) { - cs->get_rx = mpc83xx_spi_rx_buf_u8; - cs->get_tx = mpc83xx_spi_tx_buf_u8; - if (mpc83xx_spi->qe_mode) { + cs->get_rx = mpc8xxx_spi_rx_buf_u8; + cs->get_tx = mpc8xxx_spi_tx_buf_u8; + if (mpc8xxx_spi->qe_mode) { cs->rx_shift = 16; cs->tx_shift = 24; } } else if (bits_per_word <= 16) { - cs->get_rx = mpc83xx_spi_rx_buf_u16; - cs->get_tx = mpc83xx_spi_tx_buf_u16; - if (mpc83xx_spi->qe_mode) { + cs->get_rx = mpc8xxx_spi_rx_buf_u16; + cs->get_tx = mpc8xxx_spi_tx_buf_u16; + if (mpc8xxx_spi->qe_mode) { cs->rx_shift = 16; cs->tx_shift = 16; } } else if (bits_per_word <= 32) { - cs->get_rx = mpc83xx_spi_rx_buf_u32; - cs->get_tx = mpc83xx_spi_tx_buf_u32; + cs->get_rx = mpc8xxx_spi_rx_buf_u32; + cs->get_tx = mpc8xxx_spi_tx_buf_u32; } else return -EINVAL; - if (mpc83xx_spi->qe_mode && spi->mode & SPI_LSB_FIRST) { + if (mpc8xxx_spi->qe_mode && spi->mode & SPI_LSB_FIRST) { cs->tx_shift = 0; if (bits_per_word <= 8) cs->rx_shift = 8; @@ -256,10 +255,10 @@ int mpc83xx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) cs->rx_shift = 0; } - mpc83xx_spi->rx_shift = cs->rx_shift; - mpc83xx_spi->tx_shift = cs->tx_shift; - mpc83xx_spi->get_rx = cs->get_rx; - mpc83xx_spi->get_tx = cs->get_tx; + mpc8xxx_spi->rx_shift = cs->rx_shift; + mpc8xxx_spi->tx_shift = cs->tx_shift; + mpc8xxx_spi->get_rx = cs->get_rx; + mpc8xxx_spi->get_tx = cs->get_tx; if (bits_per_word == 32) bits_per_word = 0; @@ -272,25 +271,25 @@ int mpc83xx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) cs->hw_mode |= SPMODE_LEN(bits_per_word); - if ((mpc83xx_spi->spibrg / hz) > 64) { + if ((mpc8xxx_spi->spibrg / hz) > 64) { cs->hw_mode |= SPMODE_DIV16; - pm = mpc83xx_spi->spibrg / (hz * 64); - if (pm > 16) { - dev_err(&spi->dev, "Requested speed is too " - "low: %d Hz. Will use %d Hz instead.\n", - hz, mpc83xx_spi->spibrg / 1024); + pm = mpc8xxx_spi->spibrg / (hz * 64); + + WARN_ONCE(pm > 16, "%s: Requested speed is too low: %d Hz. " + "Will use %d Hz instead.\n", dev_name(&spi->dev), + hz, mpc8xxx_spi->spibrg / 1024); + if (pm > 16) pm = 16; - } } else - pm = mpc83xx_spi->spibrg / (hz * 4); + pm = mpc8xxx_spi->spibrg / (hz * 4); if (pm) pm--; cs->hw_mode |= SPMODE_PM(pm); - regval = mpc83xx_spi_read_reg(&mpc83xx_spi->base->mode); + regval = mpc8xxx_spi_read_reg(&mpc8xxx_spi->base->mode); if (cs->hw_mode != regval) { unsigned long flags; - __be32 __iomem *mode = &mpc83xx_spi->base->mode; + __be32 __iomem *mode = &mpc8xxx_spi->base->mode; regval = cs->hw_mode; /* Turn off IRQs locally to minimize time @@ -298,22 +297,22 @@ int mpc83xx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) */ local_irq_save(flags); /* Turn off SPI unit prior changing mode */ - mpc83xx_spi_write_reg(mode, regval & ~SPMODE_ENABLE); - mpc83xx_spi_write_reg(mode, regval); + mpc8xxx_spi_write_reg(mode, regval & ~SPMODE_ENABLE); + mpc8xxx_spi_write_reg(mode, regval); local_irq_restore(flags); } return 0; } -static int mpc83xx_spi_bufs(struct spi_device *spi, struct spi_transfer *t) +static int mpc8xxx_spi_bufs(struct spi_device *spi, struct spi_transfer *t) { - struct mpc83xx_spi *mpc83xx_spi; + struct mpc8xxx_spi *mpc8xxx_spi; u32 word, len, bits_per_word; - mpc83xx_spi = spi_master_get_devdata(spi->master); + mpc8xxx_spi = spi_master_get_devdata(spi->master); - mpc83xx_spi->tx = t->tx_buf; - mpc83xx_spi->rx = t->rx_buf; + mpc8xxx_spi->tx = t->tx_buf; + mpc8xxx_spi->rx = t->rx_buf; bits_per_word = spi->bits_per_word; if (t->bits_per_word) bits_per_word = t->bits_per_word; @@ -330,111 +329,106 @@ static int mpc83xx_spi_bufs(struct spi_device *spi, struct spi_transfer *t) return -EINVAL; len /= 2; } - mpc83xx_spi->count = len; + mpc8xxx_spi->count = len; - INIT_COMPLETION(mpc83xx_spi->done); + INIT_COMPLETION(mpc8xxx_spi->done); /* enable rx ints */ - mpc83xx_spi_write_reg(&mpc83xx_spi->base->mask, SPIM_NE); + mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mask, SPIM_NE); /* transmit word */ - word = mpc83xx_spi->get_tx(mpc83xx_spi); - mpc83xx_spi_write_reg(&mpc83xx_spi->base->transmit, word); + word = mpc8xxx_spi->get_tx(mpc8xxx_spi); + mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->transmit, word); - wait_for_completion(&mpc83xx_spi->done); + wait_for_completion(&mpc8xxx_spi->done); /* disable rx ints */ - mpc83xx_spi_write_reg(&mpc83xx_spi->base->mask, 0); + mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mask, 0); - return mpc83xx_spi->count; + return mpc8xxx_spi->count; } -static void mpc83xx_spi_work(struct work_struct *work) +static void mpc8xxx_spi_do_one_msg(struct spi_message *m) { - struct mpc83xx_spi *mpc83xx_spi = - container_of(work, struct mpc83xx_spi, work); + struct spi_device *spi = m->spi; + struct spi_transfer *t; + unsigned int cs_change; + const int nsecs = 50; + int status; - spin_lock_irq(&mpc83xx_spi->lock); - mpc83xx_spi->busy = 1; - while (!list_empty(&mpc83xx_spi->queue)) { - struct spi_message *m; - struct spi_device *spi; - struct spi_transfer *t = NULL; - unsigned cs_change; - int status, nsecs = 50; - - m = container_of(mpc83xx_spi->queue.next, - struct spi_message, queue); - list_del_init(&m->queue); - spin_unlock_irq(&mpc83xx_spi->lock); - - spi = m->spi; - cs_change = 1; - status = 0; - list_for_each_entry(t, &m->transfers, transfer_list) { - if (t->bits_per_word || t->speed_hz) { - /* Don't allow changes if CS is active */ - status = -EINVAL; - - if (cs_change) - status = mpc83xx_spi_setup_transfer(spi, t); - if (status < 0) - break; - } + cs_change = 1; + status = 0; + list_for_each_entry(t, &m->transfers, transfer_list) { + if (t->bits_per_word || t->speed_hz) { + /* Don't allow changes if CS is active */ + status = -EINVAL; if (cs_change) - mpc83xx_spi_chipselect(spi, BITBANG_CS_ACTIVE); - cs_change = t->cs_change; - if (t->len) - status = mpc83xx_spi_bufs(spi, t); - if (status) { - status = -EMSGSIZE; + status = mpc8xxx_spi_setup_transfer(spi, t); + if (status < 0) break; - } - m->actual_length += t->len; - - if (t->delay_usecs) - udelay(t->delay_usecs); - - if (cs_change) { - ndelay(nsecs); - mpc83xx_spi_chipselect(spi, BITBANG_CS_INACTIVE); - ndelay(nsecs); - } } - m->status = status; - m->complete(m->context); - - if (status || !cs_change) { + if (cs_change) { + mpc8xxx_spi_chipselect(spi, BITBANG_CS_ACTIVE); ndelay(nsecs); - mpc83xx_spi_chipselect(spi, BITBANG_CS_INACTIVE); } + cs_change = t->cs_change; + if (t->len) + status = mpc8xxx_spi_bufs(spi, t); + if (status) { + status = -EMSGSIZE; + break; + } + m->actual_length += t->len; - mpc83xx_spi_setup_transfer(spi, NULL); + if (t->delay_usecs) + udelay(t->delay_usecs); - spin_lock_irq(&mpc83xx_spi->lock); + if (cs_change) { + ndelay(nsecs); + mpc8xxx_spi_chipselect(spi, BITBANG_CS_INACTIVE); + ndelay(nsecs); + } } - mpc83xx_spi->busy = 0; - spin_unlock_irq(&mpc83xx_spi->lock); + + m->status = status; + m->complete(m->context); + + if (status || !cs_change) { + ndelay(nsecs); + mpc8xxx_spi_chipselect(spi, BITBANG_CS_INACTIVE); + } + + mpc8xxx_spi_setup_transfer(spi, NULL); } -/* the spi->mode bits understood by this driver: */ -#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH \ - | SPI_LSB_FIRST | SPI_LOOP) - -static int mpc83xx_spi_setup(struct spi_device *spi) +static void mpc8xxx_spi_work(struct work_struct *work) { - struct mpc83xx_spi *mpc83xx_spi; + struct mpc8xxx_spi *mpc8xxx_spi = container_of(work, struct mpc8xxx_spi, + work); + + spin_lock_irq(&mpc8xxx_spi->lock); + while (!list_empty(&mpc8xxx_spi->queue)) { + struct spi_message *m = container_of(mpc8xxx_spi->queue.next, + struct spi_message, queue); + + list_del_init(&m->queue); + spin_unlock_irq(&mpc8xxx_spi->lock); + + mpc8xxx_spi_do_one_msg(m); + + spin_lock_irq(&mpc8xxx_spi->lock); + } + spin_unlock_irq(&mpc8xxx_spi->lock); +} + +static int mpc8xxx_spi_setup(struct spi_device *spi) +{ + struct mpc8xxx_spi *mpc8xxx_spi; int retval; u32 hw_mode; - struct spi_mpc83xx_cs *cs = spi->controller_state; - - if (spi->mode & ~MODEBITS) { - dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n", - spi->mode & ~MODEBITS); - return -EINVAL; - } + struct spi_mpc8xxx_cs *cs = spi->controller_state; if (!spi->max_speed_hz) return -EINVAL; @@ -445,13 +439,10 @@ static int mpc83xx_spi_setup(struct spi_device *spi) return -ENOMEM; spi->controller_state = cs; } - mpc83xx_spi = spi_master_get_devdata(spi->master); - - if (!spi->bits_per_word) - spi->bits_per_word = 8; + mpc8xxx_spi = spi_master_get_devdata(spi->master); hw_mode = cs->hw_mode; /* Save orginal settings */ - cs->hw_mode = mpc83xx_spi_read_reg(&mpc83xx_spi->base->mode); + cs->hw_mode = mpc8xxx_spi_read_reg(&mpc8xxx_spi->base->mode); /* mask out bits we are going to set */ cs->hw_mode &= ~(SPMODE_CP_BEGIN_EDGECLK | SPMODE_CI_INACTIVEHIGH | SPMODE_REV | SPMODE_LOOP); @@ -465,45 +456,29 @@ static int mpc83xx_spi_setup(struct spi_device *spi) if (spi->mode & SPI_LOOP) cs->hw_mode |= SPMODE_LOOP; - retval = mpc83xx_spi_setup_transfer(spi, NULL); + retval = mpc8xxx_spi_setup_transfer(spi, NULL); if (retval < 0) { cs->hw_mode = hw_mode; /* Restore settings */ return retval; } - - dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u Hz\n", - __func__, spi->mode & (SPI_CPOL | SPI_CPHA), - spi->bits_per_word, spi->max_speed_hz); -#if 0 /* Don't think this is needed */ - /* NOTE we _need_ to call chipselect() early, ideally with adapter - * setup, unless the hardware defaults cooperate to avoid confusion - * between normal (active low) and inverted chipselects. - */ - - /* deselect chip (low or high) */ - spin_lock(&mpc83xx_spi->lock); - if (!mpc83xx_spi->busy) - mpc83xx_spi_chipselect(spi, BITBANG_CS_INACTIVE); - spin_unlock(&mpc83xx_spi->lock); -#endif return 0; } -static irqreturn_t mpc83xx_spi_irq(s32 irq, void *context_data) +static irqreturn_t mpc8xxx_spi_irq(s32 irq, void *context_data) { - struct mpc83xx_spi *mpc83xx_spi = context_data; + struct mpc8xxx_spi *mpc8xxx_spi = context_data; u32 event; irqreturn_t ret = IRQ_NONE; /* Get interrupt events(tx/rx) */ - event = mpc83xx_spi_read_reg(&mpc83xx_spi->base->event); + event = mpc8xxx_spi_read_reg(&mpc8xxx_spi->base->event); /* We need handle RX first */ if (event & SPIE_NE) { - u32 rx_data = mpc83xx_spi_read_reg(&mpc83xx_spi->base->receive); + u32 rx_data = mpc8xxx_spi_read_reg(&mpc8xxx_spi->base->receive); - if (mpc83xx_spi->rx) - mpc83xx_spi->get_rx(rx_data, mpc83xx_spi); + if (mpc8xxx_spi->rx) + mpc8xxx_spi->get_rx(rx_data, mpc8xxx_spi); ret = IRQ_HANDLED; } @@ -511,56 +486,56 @@ static irqreturn_t mpc83xx_spi_irq(s32 irq, void *context_data) if ((event & SPIE_NF) == 0) /* spin until TX is done */ while (((event = - mpc83xx_spi_read_reg(&mpc83xx_spi->base->event)) & + mpc8xxx_spi_read_reg(&mpc8xxx_spi->base->event)) & SPIE_NF) == 0) - cpu_relax(); + cpu_relax(); - mpc83xx_spi->count -= 1; - if (mpc83xx_spi->count) { - u32 word = mpc83xx_spi->get_tx(mpc83xx_spi); - mpc83xx_spi_write_reg(&mpc83xx_spi->base->transmit, word); + mpc8xxx_spi->count -= 1; + if (mpc8xxx_spi->count) { + u32 word = mpc8xxx_spi->get_tx(mpc8xxx_spi); + mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->transmit, word); } else { - complete(&mpc83xx_spi->done); + complete(&mpc8xxx_spi->done); } /* Clear the events */ - mpc83xx_spi_write_reg(&mpc83xx_spi->base->event, event); + mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->event, event); return ret; } -static int mpc83xx_spi_transfer(struct spi_device *spi, +static int mpc8xxx_spi_transfer(struct spi_device *spi, struct spi_message *m) { - struct mpc83xx_spi *mpc83xx_spi = spi_master_get_devdata(spi->master); + struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master); unsigned long flags; m->actual_length = 0; m->status = -EINPROGRESS; - spin_lock_irqsave(&mpc83xx_spi->lock, flags); - list_add_tail(&m->queue, &mpc83xx_spi->queue); - queue_work(mpc83xx_spi->workqueue, &mpc83xx_spi->work); - spin_unlock_irqrestore(&mpc83xx_spi->lock, flags); + spin_lock_irqsave(&mpc8xxx_spi->lock, flags); + list_add_tail(&m->queue, &mpc8xxx_spi->queue); + queue_work(mpc8xxx_spi->workqueue, &mpc8xxx_spi->work); + spin_unlock_irqrestore(&mpc8xxx_spi->lock, flags); return 0; } -static void mpc83xx_spi_cleanup(struct spi_device *spi) +static void mpc8xxx_spi_cleanup(struct spi_device *spi) { kfree(spi->controller_state); } static struct spi_master * __devinit -mpc83xx_spi_probe(struct device *dev, struct resource *mem, unsigned int irq) +mpc8xxx_spi_probe(struct device *dev, struct resource *mem, unsigned int irq) { struct fsl_spi_platform_data *pdata = dev->platform_data; struct spi_master *master; - struct mpc83xx_spi *mpc83xx_spi; + struct mpc8xxx_spi *mpc8xxx_spi; u32 regval; int ret = 0; - master = spi_alloc_master(dev, sizeof(struct mpc83xx_spi)); + master = spi_alloc_master(dev, sizeof(struct mpc8xxx_spi)); if (master == NULL) { ret = -ENOMEM; goto err; @@ -568,36 +543,40 @@ mpc83xx_spi_probe(struct device *dev, struct resource *mem, unsigned int irq) dev_set_drvdata(dev, master); - master->setup = mpc83xx_spi_setup; - master->transfer = mpc83xx_spi_transfer; - master->cleanup = mpc83xx_spi_cleanup; + /* the spi->mode bits understood by this driver: */ + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH + | SPI_LSB_FIRST | SPI_LOOP; - mpc83xx_spi = spi_master_get_devdata(master); - mpc83xx_spi->qe_mode = pdata->qe_mode; - mpc83xx_spi->get_rx = mpc83xx_spi_rx_buf_u8; - mpc83xx_spi->get_tx = mpc83xx_spi_tx_buf_u8; - mpc83xx_spi->spibrg = pdata->sysclk; + master->setup = mpc8xxx_spi_setup; + master->transfer = mpc8xxx_spi_transfer; + master->cleanup = mpc8xxx_spi_cleanup; - mpc83xx_spi->rx_shift = 0; - mpc83xx_spi->tx_shift = 0; - if (mpc83xx_spi->qe_mode) { - mpc83xx_spi->rx_shift = 16; - mpc83xx_spi->tx_shift = 24; + mpc8xxx_spi = spi_master_get_devdata(master); + mpc8xxx_spi->qe_mode = pdata->qe_mode; + mpc8xxx_spi->get_rx = mpc8xxx_spi_rx_buf_u8; + mpc8xxx_spi->get_tx = mpc8xxx_spi_tx_buf_u8; + mpc8xxx_spi->spibrg = pdata->sysclk; + + mpc8xxx_spi->rx_shift = 0; + mpc8xxx_spi->tx_shift = 0; + if (mpc8xxx_spi->qe_mode) { + mpc8xxx_spi->rx_shift = 16; + mpc8xxx_spi->tx_shift = 24; } - init_completion(&mpc83xx_spi->done); + init_completion(&mpc8xxx_spi->done); - mpc83xx_spi->base = ioremap(mem->start, mem->end - mem->start + 1); - if (mpc83xx_spi->base == NULL) { + mpc8xxx_spi->base = ioremap(mem->start, mem->end - mem->start + 1); + if (mpc8xxx_spi->base == NULL) { ret = -ENOMEM; goto put_master; } - mpc83xx_spi->irq = irq; + mpc8xxx_spi->irq = irq; /* Register for SPI Interrupt */ - ret = request_irq(mpc83xx_spi->irq, mpc83xx_spi_irq, - 0, "mpc83xx_spi", mpc83xx_spi); + ret = request_irq(mpc8xxx_spi->irq, mpc8xxx_spi_irq, + 0, "mpc8xxx_spi", mpc8xxx_spi); if (ret != 0) goto unmap_io; @@ -606,25 +585,25 @@ mpc83xx_spi_probe(struct device *dev, struct resource *mem, unsigned int irq) master->num_chipselect = pdata->max_chipselect; /* SPI controller initializations */ - mpc83xx_spi_write_reg(&mpc83xx_spi->base->mode, 0); - mpc83xx_spi_write_reg(&mpc83xx_spi->base->mask, 0); - mpc83xx_spi_write_reg(&mpc83xx_spi->base->command, 0); - mpc83xx_spi_write_reg(&mpc83xx_spi->base->event, 0xffffffff); + mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mode, 0); + mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mask, 0); + mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->command, 0); + mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->event, 0xffffffff); /* Enable SPI interface */ regval = pdata->initial_spmode | SPMODE_INIT_VAL | SPMODE_ENABLE; if (pdata->qe_mode) regval |= SPMODE_OP; - mpc83xx_spi_write_reg(&mpc83xx_spi->base->mode, regval); - spin_lock_init(&mpc83xx_spi->lock); - init_completion(&mpc83xx_spi->done); - INIT_WORK(&mpc83xx_spi->work, mpc83xx_spi_work); - INIT_LIST_HEAD(&mpc83xx_spi->queue); + mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mode, regval); + spin_lock_init(&mpc8xxx_spi->lock); + init_completion(&mpc8xxx_spi->done); + INIT_WORK(&mpc8xxx_spi->work, mpc8xxx_spi_work); + INIT_LIST_HEAD(&mpc8xxx_spi->queue); - mpc83xx_spi->workqueue = create_singlethread_workqueue( + mpc8xxx_spi->workqueue = create_singlethread_workqueue( dev_name(master->dev.parent)); - if (mpc83xx_spi->workqueue == NULL) { + if (mpc8xxx_spi->workqueue == NULL) { ret = -EBUSY; goto free_irq; } @@ -634,57 +613,57 @@ mpc83xx_spi_probe(struct device *dev, struct resource *mem, unsigned int irq) goto unreg_master; printk(KERN_INFO - "%s: MPC83xx SPI Controller driver at 0x%p (irq = %d)\n", - dev_name(dev), mpc83xx_spi->base, mpc83xx_spi->irq); + "%s: MPC8xxx SPI Controller driver at 0x%p (irq = %d)\n", + dev_name(dev), mpc8xxx_spi->base, mpc8xxx_spi->irq); return master; unreg_master: - destroy_workqueue(mpc83xx_spi->workqueue); + destroy_workqueue(mpc8xxx_spi->workqueue); free_irq: - free_irq(mpc83xx_spi->irq, mpc83xx_spi); + free_irq(mpc8xxx_spi->irq, mpc8xxx_spi); unmap_io: - iounmap(mpc83xx_spi->base); + iounmap(mpc8xxx_spi->base); put_master: spi_master_put(master); err: return ERR_PTR(ret); } -static int __devexit mpc83xx_spi_remove(struct device *dev) +static int __devexit mpc8xxx_spi_remove(struct device *dev) { - struct mpc83xx_spi *mpc83xx_spi; + struct mpc8xxx_spi *mpc8xxx_spi; struct spi_master *master; master = dev_get_drvdata(dev); - mpc83xx_spi = spi_master_get_devdata(master); + mpc8xxx_spi = spi_master_get_devdata(master); - flush_workqueue(mpc83xx_spi->workqueue); - destroy_workqueue(mpc83xx_spi->workqueue); + flush_workqueue(mpc8xxx_spi->workqueue); + destroy_workqueue(mpc8xxx_spi->workqueue); spi_unregister_master(master); - free_irq(mpc83xx_spi->irq, mpc83xx_spi); - iounmap(mpc83xx_spi->base); + free_irq(mpc8xxx_spi->irq, mpc8xxx_spi); + iounmap(mpc8xxx_spi->base); return 0; } -struct mpc83xx_spi_probe_info { +struct mpc8xxx_spi_probe_info { struct fsl_spi_platform_data pdata; int *gpios; bool *alow_flags; }; -static struct mpc83xx_spi_probe_info * +static struct mpc8xxx_spi_probe_info * to_of_pinfo(struct fsl_spi_platform_data *pdata) { - return container_of(pdata, struct mpc83xx_spi_probe_info, pdata); + return container_of(pdata, struct mpc8xxx_spi_probe_info, pdata); } -static void mpc83xx_spi_cs_control(struct spi_device *spi, bool on) +static void mpc8xxx_spi_cs_control(struct spi_device *spi, bool on) { struct device *dev = spi->dev.parent; - struct mpc83xx_spi_probe_info *pinfo = to_of_pinfo(dev->platform_data); + struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(dev->platform_data); u16 cs = spi->chip_select; int gpio = pinfo->gpios[cs]; bool alow = pinfo->alow_flags[cs]; @@ -692,11 +671,11 @@ static void mpc83xx_spi_cs_control(struct spi_device *spi, bool on) gpio_set_value(gpio, on ^ alow); } -static int of_mpc83xx_spi_get_chipselects(struct device *dev) +static int of_mpc8xxx_spi_get_chipselects(struct device *dev) { struct device_node *np = dev_archdata_get_node(&dev->archdata); struct fsl_spi_platform_data *pdata = dev->platform_data; - struct mpc83xx_spi_probe_info *pinfo = to_of_pinfo(pdata); + struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata); unsigned int ngpios; int i = 0; int ret; @@ -711,12 +690,12 @@ static int of_mpc83xx_spi_get_chipselects(struct device *dev) return 0; } - pinfo->gpios = kmalloc(ngpios * sizeof(pinfo->gpios), GFP_KERNEL); + pinfo->gpios = kmalloc(ngpios * sizeof(*pinfo->gpios), GFP_KERNEL); if (!pinfo->gpios) return -ENOMEM; - memset(pinfo->gpios, -1, ngpios * sizeof(pinfo->gpios)); + memset(pinfo->gpios, -1, ngpios * sizeof(*pinfo->gpios)); - pinfo->alow_flags = kzalloc(ngpios * sizeof(pinfo->alow_flags), + pinfo->alow_flags = kzalloc(ngpios * sizeof(*pinfo->alow_flags), GFP_KERNEL); if (!pinfo->alow_flags) { ret = -ENOMEM; @@ -752,7 +731,7 @@ static int of_mpc83xx_spi_get_chipselects(struct device *dev) } pdata->max_chipselect = ngpios; - pdata->cs_control = mpc83xx_spi_cs_control; + pdata->cs_control = mpc8xxx_spi_cs_control; return 0; @@ -771,10 +750,10 @@ err_alloc_flags: return ret; } -static int of_mpc83xx_spi_free_chipselects(struct device *dev) +static int of_mpc8xxx_spi_free_chipselects(struct device *dev) { struct fsl_spi_platform_data *pdata = dev->platform_data; - struct mpc83xx_spi_probe_info *pinfo = to_of_pinfo(pdata); + struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata); int i; if (!pinfo->gpios) @@ -790,12 +769,12 @@ static int of_mpc83xx_spi_free_chipselects(struct device *dev) return 0; } -static int __devinit of_mpc83xx_spi_probe(struct of_device *ofdev, +static int __devinit of_mpc8xxx_spi_probe(struct of_device *ofdev, const struct of_device_id *ofid) { struct device *dev = &ofdev->dev; struct device_node *np = ofdev->node; - struct mpc83xx_spi_probe_info *pinfo; + struct mpc8xxx_spi_probe_info *pinfo; struct fsl_spi_platform_data *pdata; struct spi_master *master; struct resource mem; @@ -827,7 +806,7 @@ static int __devinit of_mpc83xx_spi_probe(struct of_device *ofdev, if (prop && !strcmp(prop, "cpu-qe")) pdata->qe_mode = 1; - ret = of_mpc83xx_spi_get_chipselects(dev); + ret = of_mpc8xxx_spi_get_chipselects(dev); if (ret) goto err; @@ -841,7 +820,7 @@ static int __devinit of_mpc83xx_spi_probe(struct of_device *ofdev, goto err; } - master = mpc83xx_spi_probe(dev, &mem, irq.start); + master = mpc8xxx_spi_probe(dev, &mem, irq.start); if (IS_ERR(master)) { ret = PTR_ERR(master); goto err; @@ -852,34 +831,34 @@ static int __devinit of_mpc83xx_spi_probe(struct of_device *ofdev, return 0; err: - of_mpc83xx_spi_free_chipselects(dev); + of_mpc8xxx_spi_free_chipselects(dev); err_clk: kfree(pinfo); return ret; } -static int __devexit of_mpc83xx_spi_remove(struct of_device *ofdev) +static int __devexit of_mpc8xxx_spi_remove(struct of_device *ofdev) { int ret; - ret = mpc83xx_spi_remove(&ofdev->dev); + ret = mpc8xxx_spi_remove(&ofdev->dev); if (ret) return ret; - of_mpc83xx_spi_free_chipselects(&ofdev->dev); + of_mpc8xxx_spi_free_chipselects(&ofdev->dev); return 0; } -static const struct of_device_id of_mpc83xx_spi_match[] = { +static const struct of_device_id of_mpc8xxx_spi_match[] = { { .compatible = "fsl,spi" }, {}, }; -MODULE_DEVICE_TABLE(of, of_mpc83xx_spi_match); +MODULE_DEVICE_TABLE(of, of_mpc8xxx_spi_match); -static struct of_platform_driver of_mpc83xx_spi_driver = { - .name = "mpc83xx_spi", - .match_table = of_mpc83xx_spi_match, - .probe = of_mpc83xx_spi_probe, - .remove = __devexit_p(of_mpc83xx_spi_remove), +static struct of_platform_driver of_mpc8xxx_spi_driver = { + .name = "mpc8xxx_spi", + .match_table = of_mpc8xxx_spi_match, + .probe = of_mpc8xxx_spi_probe, + .remove = __devexit_p(of_mpc8xxx_spi_remove), }; #ifdef CONFIG_MPC832x_RDB @@ -890,7 +869,7 @@ static struct of_platform_driver of_mpc83xx_spi_driver = { * tree can work with OpenFirmware driver. But for now we support old trees * as well. */ -static int __devinit plat_mpc83xx_spi_probe(struct platform_device *pdev) +static int __devinit plat_mpc8xxx_spi_probe(struct platform_device *pdev) { struct resource *mem; unsigned int irq; @@ -907,23 +886,23 @@ static int __devinit plat_mpc83xx_spi_probe(struct platform_device *pdev) if (!irq) return -EINVAL; - master = mpc83xx_spi_probe(&pdev->dev, mem, irq); + master = mpc8xxx_spi_probe(&pdev->dev, mem, irq); if (IS_ERR(master)) return PTR_ERR(master); return 0; } -static int __devexit plat_mpc83xx_spi_remove(struct platform_device *pdev) +static int __devexit plat_mpc8xxx_spi_remove(struct platform_device *pdev) { - return mpc83xx_spi_remove(&pdev->dev); + return mpc8xxx_spi_remove(&pdev->dev); } -MODULE_ALIAS("platform:mpc83xx_spi"); -static struct platform_driver mpc83xx_spi_driver = { - .probe = plat_mpc83xx_spi_probe, - .remove = __exit_p(plat_mpc83xx_spi_remove), +MODULE_ALIAS("platform:mpc8xxx_spi"); +static struct platform_driver mpc8xxx_spi_driver = { + .probe = plat_mpc8xxx_spi_probe, + .remove = __exit_p(plat_mpc8xxx_spi_remove), .driver = { - .name = "mpc83xx_spi", + .name = "mpc8xxx_spi", .owner = THIS_MODULE, }, }; @@ -932,35 +911,35 @@ static bool legacy_driver_failed; static void __init legacy_driver_register(void) { - legacy_driver_failed = platform_driver_register(&mpc83xx_spi_driver); + legacy_driver_failed = platform_driver_register(&mpc8xxx_spi_driver); } static void __exit legacy_driver_unregister(void) { if (legacy_driver_failed) return; - platform_driver_unregister(&mpc83xx_spi_driver); + platform_driver_unregister(&mpc8xxx_spi_driver); } #else static void __init legacy_driver_register(void) {} static void __exit legacy_driver_unregister(void) {} #endif /* CONFIG_MPC832x_RDB */ -static int __init mpc83xx_spi_init(void) +static int __init mpc8xxx_spi_init(void) { legacy_driver_register(); - return of_register_platform_driver(&of_mpc83xx_spi_driver); + return of_register_platform_driver(&of_mpc8xxx_spi_driver); } -static void __exit mpc83xx_spi_exit(void) +static void __exit mpc8xxx_spi_exit(void) { - of_unregister_platform_driver(&of_mpc83xx_spi_driver); + of_unregister_platform_driver(&of_mpc8xxx_spi_driver); legacy_driver_unregister(); } -module_init(mpc83xx_spi_init); -module_exit(mpc83xx_spi_exit); +module_init(mpc8xxx_spi_init); +module_exit(mpc8xxx_spi_exit); MODULE_AUTHOR("Kumar Gala"); -MODULE_DESCRIPTION("Simple MPC83xx SPI Driver"); +MODULE_DESCRIPTION("Simple MPC8xxx SPI Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/spi/spi_s3c24xx.c b/drivers/spi/spi_s3c24xx.c index b3ebc1d0f85f..e0d44af4745a 100644 --- a/drivers/spi/spi_s3c24xx.c +++ b/drivers/spi/spi_s3c24xx.c @@ -146,32 +146,16 @@ static int s3c24xx_spi_setupxfer(struct spi_device *spi, return 0; } -/* the spi->mode bits understood by this driver: */ -#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH) - static int s3c24xx_spi_setup(struct spi_device *spi) { int ret; - if (!spi->bits_per_word) - spi->bits_per_word = 8; - - if (spi->mode & ~MODEBITS) { - dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n", - spi->mode & ~MODEBITS); - return -EINVAL; - } - ret = s3c24xx_spi_setupxfer(spi, NULL); if (ret < 0) { dev_err(&spi->dev, "setupxfer returned %d\n", ret); return ret; } - dev_dbg(&spi->dev, "%s: mode %d, %u bpw, %d hz\n", - __func__, spi->mode, spi->bits_per_word, - spi->max_speed_hz); - return 0; } @@ -290,6 +274,9 @@ static int __init s3c24xx_spi_probe(struct platform_device *pdev) /* setup the master state. */ + /* the spi->mode bits understood by this driver: */ + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; + master->num_chipselect = hw->pdata->num_cs; master->bus_num = pdata->bus_num; diff --git a/drivers/spi/spi_s3c24xx_gpio.c b/drivers/spi/spi_s3c24xx_gpio.c index f2447a5476bb..bbf9371cd284 100644 --- a/drivers/spi/spi_s3c24xx_gpio.c +++ b/drivers/spi/spi_s3c24xx_gpio.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include diff --git a/drivers/spi/spi_txx9.c b/drivers/spi/spi_txx9.c index 29cbb065618a..96057de133ad 100644 --- a/drivers/spi/spi_txx9.c +++ b/drivers/spi/spi_txx9.c @@ -110,23 +110,17 @@ static void txx9spi_cs_func(struct spi_device *spi, struct txx9spi *c, ndelay(cs_delay); /* CS Setup Time / CS Recovery Time */ } -/* the spi->mode bits understood by this driver: */ -#define MODEBITS (SPI_CS_HIGH|SPI_CPOL|SPI_CPHA) - static int txx9spi_setup(struct spi_device *spi) { struct txx9spi *c = spi_master_get_devdata(spi->master); u8 bits_per_word; - if (spi->mode & ~MODEBITS) - return -EINVAL; - if (!spi->max_speed_hz || spi->max_speed_hz > c->max_speed_hz || spi->max_speed_hz < c->min_speed_hz) return -EINVAL; - bits_per_word = spi->bits_per_word ? : 8; + bits_per_word = spi->bits_per_word; if (bits_per_word != 8 && bits_per_word != 16) return -EINVAL; @@ -414,6 +408,9 @@ static int __init txx9spi_probe(struct platform_device *dev) (unsigned long long)res->start, irq, (c->baseclk + 500000) / 1000000); + /* the spi->mode bits understood by this driver: */ + master->mode_bits = SPI_CS_HIGH | SPI_CPOL | SPI_CPHA; + master->bus_num = dev->id; master->setup = txx9spi_setup; master->transfer = txx9spi_transfer; diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c index 494d3f756e29..46b8c5c2f45e 100644 --- a/drivers/spi/xilinx_spi.c +++ b/drivers/spi/xilinx_spi.c @@ -158,9 +158,6 @@ static int xilinx_spi_setup_transfer(struct spi_device *spi, return 0; } -/* the spi->mode bits understood by this driver: */ -#define MODEBITS (SPI_CPOL | SPI_CPHA) - static int xilinx_spi_setup(struct spi_device *spi) { struct spi_bitbang *bitbang; @@ -170,22 +167,10 @@ static int xilinx_spi_setup(struct spi_device *spi) xspi = spi_master_get_devdata(spi->master); bitbang = &xspi->bitbang; - if (!spi->bits_per_word) - spi->bits_per_word = 8; - - if (spi->mode & ~MODEBITS) { - dev_err(&spi->dev, "%s, unsupported mode bits %x\n", - __func__, spi->mode & ~MODEBITS); - return -EINVAL; - } - retval = xilinx_spi_setup_transfer(spi, NULL); if (retval < 0) return retval; - dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u nsec/bit\n", - __func__, spi->mode & MODEBITS, spi->bits_per_word, 0); - return 0; } @@ -333,6 +318,9 @@ static int __init xilinx_spi_of_probe(struct of_device *ofdev, goto put_master; } + /* the spi->mode bits understood by this driver: */ + master->mode_bits = SPI_CPOL | SPI_CPHA; + xspi = spi_master_get_devdata(master); xspi->bitbang.master = spi_master_get(master); xspi->bitbang.chipselect = xilinx_spi_chipselect; diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 0dcf9ca0b0ac..348bf61a8fec 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -85,6 +85,8 @@ source "drivers/staging/altpciechdma/Kconfig" source "drivers/staging/rtl8187se/Kconfig" +source "drivers/staging/rtl8192su/Kconfig" + source "drivers/staging/rspiusb/Kconfig" source "drivers/staging/mimio/Kconfig" @@ -113,7 +115,19 @@ source "drivers/staging/heci/Kconfig" source "drivers/staging/line6/Kconfig" -source "drivers/staging/serqt_usb/Kconfig" +source "drivers/gpu/drm/radeon/Kconfig" + +source "drivers/staging/octeon/Kconfig" + +source "drivers/staging/serqt_usb2/Kconfig" + +source "drivers/staging/vt6655/Kconfig" + +source "drivers/staging/cpc-usb/Kconfig" + +source "drivers/staging/pata_rdc/Kconfig" + +source "drivers/staging/udlfb/Kconfig" endif # !STAGING_EXCLUDE_BUILD endif # STAGING diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 47dfd5b4288b..8d61d7b4debf 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -25,6 +25,7 @@ obj-$(CONFIG_ASUS_OLED) += asus_oled/ obj-$(CONFIG_PANEL) += panel/ obj-$(CONFIG_ALTERA_PCIE_CHDMA) += altpciechdma/ obj-$(CONFIG_RTL8187SE) += rtl8187se/ +obj-$(CONFIG_RTL8192SU) += rtl8192su/ obj-$(CONFIG_USB_RSPI) += rspiusb/ obj-$(CONFIG_INPUT_MIMIO) += mimio/ obj-$(CONFIG_TRANZPORT) += frontier/ @@ -39,4 +40,9 @@ obj-$(CONFIG_IDE_PHISON) += phison/ obj-$(CONFIG_PLAN9AUTH) += p9auth/ obj-$(CONFIG_HECI) += heci/ obj-$(CONFIG_LINE6_USB) += line6/ -obj-$(CONFIG_USB_SERIAL_QUATECH_ESU100) += serqt_usb/ +obj-$(CONFIG_USB_SERIAL_QUATECH2) += serqt_usb2/ +obj-$(CONFIG_OCTEON_ETHERNET) += octeon/ +obj-$(CONFIG_VT6655) += vt6655/ +obj-$(CONFIG_USB_CPC) += cpc-usb/ +obj-$(CONFIG_RDC_17F3101X) += pata_rdc/ +obj-$(CONFIG_FB_UDL) += udlfb/ diff --git a/drivers/staging/agnx/debug.h b/drivers/staging/agnx/debug.h index 761d99c2d3f0..7947f327a214 100644 --- a/drivers/staging/agnx/debug.h +++ b/drivers/staging/agnx/debug.h @@ -312,7 +312,6 @@ static inline void dump_ieee80211_hdr(struct ieee80211_hdr *hdr, char *tag) { u16 fctl; int hdrlen; - DECLARE_MAC_BUF(mac); fctl = le16_to_cpu(hdr->frame_control); switch (fctl & IEEE80211_FCTL_FTYPE) { @@ -375,13 +374,13 @@ static inline void dump_ieee80211_hdr(struct ieee80211_hdr *hdr, char *tag) printk("FC=0x%04x DUR=0x%04x", fctl, le16_to_cpu(hdr->duration_id)); if (hdrlen >= 10) - printk(" A1=%s", print_mac(mac, hdr->addr1)); + printk(" A1=%pM", hdr->addr1); if (hdrlen >= 16) - printk(" A2=%s", print_mac(mac, hdr->addr2)); + printk(" A2=%pM", hdr->addr2); if (hdrlen >= 24) - printk(" A3=%s", print_mac(mac, hdr->addr3)); + printk(" A3=%pM", hdr->addr3); if (hdrlen >= 30) - printk(" A4=%s", print_mac(mac, hdr->addr4)); + printk(" A4=%pM", hdr->addr4); printk("\n"); } diff --git a/drivers/staging/agnx/pci.c b/drivers/staging/agnx/pci.c index 25c0ffd2faa0..1fe987065257 100644 --- a/drivers/staging/agnx/pci.c +++ b/drivers/staging/agnx/pci.c @@ -58,15 +58,17 @@ static inline void agnx_interrupt_ack(struct agnx_priv *priv, u32 *reason) *reason |= AGNX_STAT_TXM; } } -/* if (*reason & AGNX_STAT_X) { +#if 0 + if (*reason & AGNX_STAT_X) { reg = ioread32(ctl + AGNX_INT_STAT); iowrite32(reg, ctl + AGNX_INT_STAT); - /* FIXME reinit interrupt mask *\/ + /* FIXME reinit interrupt mask */ reg = 0xc390bf9 & ~IRQ_TX_BEACON; reg &= ~IRQ_TX_DISABLE; iowrite32(reg, ctl + AGNX_INT_MASK); iowrite32(0x800, ctl + AGNX_CIR_BLKCTL); - } */ + } +#endif } /* agnx_interrupt_ack */ static irqreturn_t agnx_interrupt_handler(int irq, void *dev_id) @@ -150,8 +152,7 @@ static int agnx_get_mac_address(struct agnx_priv *priv) *((u32 *)(priv->mac_addr + 2)) = cpu_to_le32(reg); if (!is_valid_ether_addr(priv->mac_addr)) { - DECLARE_MAC_BUF(mbuf); - printk(KERN_WARNING PFX "read mac %s\n", print_mac(mbuf, priv->mac_addr)); + printk(KERN_WARNING PFX "read mac %pM\n", priv->mac_addr); printk(KERN_WARNING PFX "Invalid hwaddr! Using random hwaddr\n"); random_ether_addr(priv->mac_addr); } @@ -220,7 +221,7 @@ static void agnx_periodic_work_handler(struct work_struct *work) /* TODO Recalibrate*/ /* calibrate_oscillator(priv); */ /* antenna_calibrate(priv); */ -/* agnx_send_packet(priv, 997); / +/* agnx_send_packet(priv, 997); */ /* FIXME */ /* if (debug == 3) */ /* delay = msecs_to_jiffies(AGNX_PERIODIC_DELAY); */ @@ -303,14 +304,18 @@ static int agnx_config(struct ieee80211_hw *dev, u32 changed) return 0; } -static int agnx_config_interface(struct ieee80211_hw *dev, - struct ieee80211_vif *vif, - struct ieee80211_if_conf *conf) +static void agnx_bss_info_changed(struct ieee80211_hw *dev, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *conf, + u32 changed) { struct agnx_priv *priv = dev->priv; void __iomem *ctl = priv->ctl; AGNX_TRACE; + if (!(changed & BSS_CHANGED_BSSID)) + return; + spin_lock(&priv->lock); if (memcmp(conf->bssid, priv->bssid, ETH_ALEN)) { @@ -323,8 +328,7 @@ static int agnx_config_interface(struct ieee80211_hw *dev, agnx_write32(ctl, AGNX_BM_MTSM, 0xff & ~0x1); } spin_unlock(&priv->lock); - return 0; -} /* agnx_config_interface */ +} /* agnx_bss_info_changed */ static void agnx_configure_filter(struct ieee80211_hw *dev, @@ -422,7 +426,7 @@ static struct ieee80211_ops agnx_ops = { .add_interface = agnx_add_interface, .remove_interface = agnx_remove_interface, .config = agnx_config, - .config_interface = agnx_config_interface, + .bss_info_changed = agnx_bss_info_changed, .configure_filter = agnx_configure_filter, .get_stats = agnx_get_stats, .get_tx_stats = agnx_get_tx_stats, @@ -452,47 +456,35 @@ static int __devinit agnx_pci_probe(struct pci_dev *pdev, { struct ieee80211_hw *dev; struct agnx_priv *priv; - u32 mem_addr0, mem_len0; - u32 mem_addr1, mem_len1; int err; - DECLARE_MAC_BUF(mac); err = pci_enable_device(pdev); if (err) { - printk(KERN_ERR PFX "Can't enable new PCI device\n"); + dev_err(&pdev->dev, "can't enable pci device\n"); return err; } - /* get pci resource */ - mem_addr0 = pci_resource_start(pdev, 0); - mem_len0 = pci_resource_len(pdev, 0); - mem_addr1 = pci_resource_start(pdev, 1); - mem_len1 = pci_resource_len(pdev, 1); - printk(KERN_DEBUG PFX "Memaddr0 is %x, length is %x\n", mem_addr0, mem_len0); - printk(KERN_DEBUG PFX "Memaddr1 is %x, length is %x\n", mem_addr1, mem_len1); - err = pci_request_regions(pdev, "agnx-pci"); if (err) { - printk(KERN_ERR PFX "Can't obtain PCI resource\n"); + dev_err(&pdev->dev, "can't reserve PCI resources\n"); return err; } if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) { - printk(KERN_ERR PFX "No suitable DMA available\n"); + dev_err(&pdev->dev, "no suitable DMA available\n"); + err = -EIO; goto err_free_reg; } pci_set_master(pdev); - printk(KERN_DEBUG PFX "pdev->irq is %d\n", pdev->irq); dev = ieee80211_alloc_hw(sizeof(*priv), &agnx_ops); if (!dev) { - printk(KERN_ERR PFX "ieee80211 alloc failed\n"); + dev_err(&pdev->dev, "ieee80211 alloc failed\n"); err = -ENOMEM; goto err_free_reg; } - /* init priv */ priv = dev->priv; memset(priv, 0, sizeof(*priv)); priv->mode = NL80211_IFTYPE_MONITOR; @@ -501,17 +493,17 @@ static int __devinit agnx_pci_probe(struct pci_dev *pdev, spin_lock_init(&priv->lock); priv->init_status = AGNX_UNINIT; - /* Map mem #1 and #2 */ - priv->ctl = pci_iomap(pdev, 0, mem_len0); -/* printk(KERN_DEBUG PFX"MEM1 mapped address is 0x%p\n", priv->ctl); */ + priv->ctl = pci_iomap(pdev, 0, 0); +/* dev_dbg(&pdev->dev, "MEM1 mapped address is 0x%p\n", priv->ctl); */ if (!priv->ctl) { - printk(KERN_ERR PFX "Can't map device memory\n"); + dev_err(&pdev->dev, "can't map device memory\n"); + err = -ENOMEM; goto err_free_dev; } - priv->data = pci_iomap(pdev, 1, mem_len1); - printk(KERN_DEBUG PFX "MEM2 mapped address is 0x%p\n", priv->data); + priv->data = pci_iomap(pdev, 1, 0); if (!priv->data) { - printk(KERN_ERR PFX "Can't map device memory\n"); + dev_err(&pdev->dev, "can't map device memory\n"); + err = -ENOMEM; goto err_iounmap2; } @@ -552,15 +544,15 @@ static int __devinit agnx_pci_probe(struct pci_dev *pdev, err = ieee80211_register_hw(dev); if (err) { - printk(KERN_ERR PFX "Can't register hardware\n"); + dev_err(&pdev->dev, "can't register hardware\n"); goto err_iounmap; } agnx_hw_reset(priv); - - printk(PFX "%s: hwaddr %s, Rev 0x%02x\n", wiphy_name(dev->wiphy), - print_mac(mac, dev->wiphy->perm_addr), priv->revid); + dev_info(&pdev->dev, "%s: hwaddr %pM, Rev 0x%02x\n", + wiphy_name(dev->wiphy), + dev->wiphy->perm_addr, priv->revid); return 0; err_iounmap: diff --git a/drivers/staging/agnx/phy.c b/drivers/staging/agnx/phy.c index 2be63312b727..ec1ca86fa0c4 100644 --- a/drivers/staging/agnx/phy.c +++ b/drivers/staging/agnx/phy.c @@ -118,7 +118,7 @@ static void mac_address_set(struct agnx_priv *priv) iowrite32(reg, ctl + AGNX_RXM_MACLO); } -static void receiver_bssid_set(struct agnx_priv *priv, u8 *bssid) +static void receiver_bssid_set(struct agnx_priv *priv, const u8 *bssid) { void __iomem *ctl = priv->ctl; u32 reg; @@ -954,7 +954,7 @@ int agnx_set_ssid(struct agnx_priv *priv, u8 *ssid, size_t ssid_len) return 0; } -void agnx_set_bssid(struct agnx_priv *priv, u8 *bssid) +void agnx_set_bssid(struct agnx_priv *priv, const u8 *bssid) { receiver_bssid_set(priv, bssid); } diff --git a/drivers/staging/agnx/phy.h b/drivers/staging/agnx/phy.h index 55e1e222179e..a955f05361e7 100644 --- a/drivers/staging/agnx/phy.h +++ b/drivers/staging/agnx/phy.h @@ -401,7 +401,7 @@ u8 read_from_eeprom(struct agnx_priv *priv, u16 address); void agnx_hw_init(struct agnx_priv *priv); int agnx_hw_reset(struct agnx_priv *priv); int agnx_set_ssid(struct agnx_priv *priv, u8 *ssid, size_t ssid_len); -void agnx_set_bssid(struct agnx_priv *priv, u8 *bssid); +void agnx_set_bssid(struct agnx_priv *priv, const u8 *bssid); void enable_power_saving(struct agnx_priv *priv); void disable_power_saving(struct agnx_priv *priv); void calibrate_antenna_period(unsigned long data); diff --git a/drivers/staging/agnx/sta.c b/drivers/staging/agnx/sta.c index 5b2d54a587c8..3e7db5e2811a 100644 --- a/drivers/staging/agnx/sta.c +++ b/drivers/staging/agnx/sta.c @@ -22,7 +22,7 @@ void hash_read(struct agnx_priv *priv, u32 reghi, u32 reglo, u8 sta_id) printk(PFX "RX hash cmd are : %.8x%.8x\n", reghi, reglo); } -void hash_write(struct agnx_priv *priv, u8 *mac_addr, u8 sta_id) +void hash_write(struct agnx_priv *priv, const u8 *mac_addr, u8 sta_id) { void __iomem *ctl = priv->ctl; u32 reghi, reglo; diff --git a/drivers/staging/agnx/sta.h b/drivers/staging/agnx/sta.h index 94e2cf1f973f..fd504e3f3870 100644 --- a/drivers/staging/agnx/sta.h +++ b/drivers/staging/agnx/sta.h @@ -201,7 +201,7 @@ struct agnx_beacon_hdr { /* 802.11(abg) beacon */ } __attribute__((__packed__)); -void hash_write(struct agnx_priv *priv, u8 *mac_addr, u8 sta_id); +void hash_write(struct agnx_priv *priv, const u8 *mac_addr, u8 sta_id); void hash_dump(struct agnx_priv *priv, u8 sta_id); void hash_read(struct agnx_priv *priv, u32 reghi, u32 reglo, u8 sta_id); void hash_delete(struct agnx_priv *priv, u32 reghi, u32 reglo, u8 sta_id); diff --git a/drivers/staging/altpciechdma/altpciechdma.c b/drivers/staging/altpciechdma/altpciechdma.c index 5869e1484a95..3724b8ad4879 100644 --- a/drivers/staging/altpciechdma/altpciechdma.c +++ b/drivers/staging/altpciechdma/altpciechdma.c @@ -399,6 +399,7 @@ static inline void ape_chdma_desc_set(struct ape_chdma_desc *desc, dma_addr_t ad desc->rc_addr_l = cpu_to_le32(pci_dma_l(addr)); } +#if ALTPCIECHDMA_CDEV /* * ape_sg_to_chdma_table() - Create a device descriptor table from a scatterlist. * @@ -456,6 +457,7 @@ static int ape_sg_to_chdma_table(struct scatterlist *sgl, int nents, int first, j++; return j; } +#endif /* compare buffers */ static inline int compare(u32 *p, u32 *q, int len) @@ -540,8 +542,8 @@ static int __devinit dma_test(struct ape_dev *ape, struct pci_dev *dev) printk(KERN_DEBUG "Could not allocate coherent DMA buffer.\n"); goto fail; } - printk(KERN_DEBUG "Allocated cache-coherent DMA buffer (virtual address = 0x%016llx, bus address = 0x%016llx).\n", - (u64)buffer_virt, (u64)buffer_bus); + printk(KERN_DEBUG "Allocated cache-coherent DMA buffer (virtual address = %p, bus address = 0x%016llx).\n", + buffer_virt, (u64)buffer_bus); /* fill first half of buffer with its virtual address as data */ for (i = 0; i < 4 * PAGE_SIZE; i += 4) @@ -783,7 +785,7 @@ static int __devinit probe(struct pci_dev *dev, const struct pci_device_id *id) goto err_ape; } ape->pci_dev = dev; - dev->dev.driver_data = (void *)ape; + dev_set_drvdata(&dev->dev, ape); printk(KERN_DEBUG "probe() ape = 0x%p\n", ape); printk(KERN_DEBUG "sizeof(struct ape_chdma_table) = %d.\n", @@ -801,8 +803,8 @@ static int __devinit probe(struct pci_dev *dev, const struct pci_device_id *id) goto err_table; } - printk(KERN_DEBUG "table_virt = 0x%16llx, table_bus = 0x%16llx.\n", - (u64)ape->table_virt, (u64)ape->table_bus); + printk(KERN_DEBUG "table_virt = %p, table_bus = 0x%16llx.\n", + ape->table_virt, (u64)ape->table_bus); /* enable device */ rc = pci_enable_device(dev); @@ -913,9 +915,11 @@ static int __devinit probe(struct pci_dev *dev, const struct pci_device_id *id) rc = 0; printk(KERN_DEBUG "probe() successful.\n"); goto end; +#if ALTPCIECHDMA_CDEV err_cdev: /* unmap the BARs */ unmap_bars(ape, dev); +#endif err_map: /* free allocated irq */ if (ape->irq_line >= 0) @@ -930,7 +934,7 @@ err_irq: pci_release_regions(dev); err_mask: err_regions: -err_rev: +/*err_rev:*/ /* clean up everything before device enable() */ err_enable: if (ape->table_virt) @@ -946,19 +950,11 @@ end: static void __devexit remove(struct pci_dev *dev) { - struct ape_dev *ape; + struct ape_dev *ape = dev_get_drvdata(&dev->dev); + printk(KERN_DEBUG "remove(0x%p)\n", dev); - if ((dev == 0) || (dev->dev.driver_data == 0)) { - printk(KERN_DEBUG "remove(dev = 0x%p) dev->dev.driver_data = 0x%p\n", - dev, (dev? dev->dev.driver_data: NULL)); - return; - } - ape = (struct ape_dev *)dev->dev.driver_data; - printk(KERN_DEBUG "remove(dev = 0x%p) where dev->dev.driver_data = 0x%p\n", dev, ape); - if (ape->pci_dev != dev) { - printk(KERN_DEBUG "dev->dev.driver_data->pci_dev (0x%08lx) != dev (0x%08lx)\n", - (unsigned long)ape->pci_dev, (unsigned long)dev); - } + printk(KERN_DEBUG "remove(dev = 0x%p) where ape = 0x%p\n", dev, ape); + /* remove character device */ #if ALTPCIECHDMA_CDEV sg_exit(ape); @@ -1151,7 +1147,7 @@ static struct pci_driver pci_driver = { .name = DRV_NAME, .id_table = ids, .probe = probe, - .remove = remove, + .remove = __devexit_p(remove), /* resume, suspend are optional */ }; diff --git a/drivers/staging/android/Kconfig b/drivers/staging/android/Kconfig index 604bd1e0d546..247194992374 100644 --- a/drivers/staging/android/Kconfig +++ b/drivers/staging/android/Kconfig @@ -6,6 +6,8 @@ config ANDROID ---help--- Enable support for various drivers needed on the Android platform +if ANDROID + config ANDROID_BINDER_IPC bool "Android Binder IPC Driver" default n @@ -73,9 +75,13 @@ config ANDROID_RAM_CONSOLE_EARLY_SIZE default 0 depends on ANDROID_RAM_CONSOLE_EARLY_INIT +config ANDROID_TIMED_OUTPUT + bool "Timed output class driver" + default y + config ANDROID_TIMED_GPIO tristate "Android timed gpio driver" - depends on GENERIC_GPIO + depends on GENERIC_GPIO && ANDROID_TIMED_OUTPUT default n config ANDROID_LOW_MEMORY_KILLER @@ -84,4 +90,6 @@ config ANDROID_LOW_MEMORY_KILLER ---help--- Register processes to be killed when memory is low +endif # if ANDROID + endmenu diff --git a/drivers/staging/android/Makefile b/drivers/staging/android/Makefile index 95209d6273a1..8e057e626d11 100644 --- a/drivers/staging/android/Makefile +++ b/drivers/staging/android/Makefile @@ -1,5 +1,6 @@ obj-$(CONFIG_ANDROID_BINDER_IPC) += binder.o obj-$(CONFIG_ANDROID_LOGGER) += logger.o obj-$(CONFIG_ANDROID_RAM_CONSOLE) += ram_console.o +obj-$(CONFIG_ANDROID_TIMED_OUTPUT) += timed_output.o obj-$(CONFIG_ANDROID_TIMED_GPIO) += timed_gpio.o obj-$(CONFIG_ANDROID_LOW_MEMORY_KILLER) += lowmemorykiller.o diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c index 299d29d1dadb..17d89a8124ad 100644 --- a/drivers/staging/android/binder.c +++ b/drivers/staging/android/binder.c @@ -44,8 +44,8 @@ static struct hlist_head binder_dead_nodes; static HLIST_HEAD(binder_deferred_list); static DEFINE_MUTEX(binder_deferred_lock); -static int binder_read_proc_proc( - char *page, char **start, off_t off, int count, int *eof, void *data); +static int binder_read_proc_proc(char *page, char **start, off_t off, + int count, int *eof, void *data); /* This is only defined in include/asm-arm/sizes.h */ #ifndef SZ_1K @@ -81,12 +81,15 @@ enum { static uint32_t binder_debug_mask = BINDER_DEBUG_USER_ERROR | BINDER_DEBUG_FAILED_TRANSACTION | BINDER_DEBUG_DEAD_TRANSACTION; module_param_named(debug_mask, binder_debug_mask, uint, S_IWUSR | S_IRUGO); + static int binder_debug_no_lock; module_param_named(proc_no_lock, binder_debug_no_lock, bool, S_IWUSR | S_IRUGO); + static DECLARE_WAIT_QUEUE_HEAD(binder_user_error_wait); static int binder_stop_on_user_error; -static int binder_set_stop_on_user_error( - const char *val, struct kernel_param *kp) + +static int binder_set_stop_on_user_error(const char *val, + struct kernel_param *kp) { int ret; ret = param_set_int(val, kp); @@ -185,13 +188,13 @@ struct binder_node { int local_strong_refs; void __user *ptr; void __user *cookie; - unsigned has_strong_ref : 1; - unsigned pending_strong_ref : 1; - unsigned has_weak_ref : 1; - unsigned pending_weak_ref : 1; - unsigned has_async_transaction : 1; - unsigned accept_fds : 1; - int min_priority : 8; + unsigned has_strong_ref:1; + unsigned pending_strong_ref:1; + unsigned has_weak_ref:1; + unsigned pending_weak_ref:1; + unsigned has_async_transaction:1; + unsigned accept_fds:1; + unsigned min_priority:8; struct list_head async_todo; }; @@ -221,10 +224,10 @@ struct binder_buffer { struct list_head entry; /* free and allocated entries by addesss */ struct rb_node rb_node; /* free entry by size or allocated entry */ /* by address */ - unsigned free : 1; - unsigned allow_user_free : 1; - unsigned async_transaction : 1; - unsigned debug_id : 29; + unsigned free:1; + unsigned allow_user_free:1; + unsigned async_transaction:1; + unsigned debug_id:29; struct binder_transaction *transaction; @@ -306,8 +309,8 @@ struct binder_transaction { struct binder_proc *to_proc; struct binder_thread *to_thread; struct binder_transaction *to_parent; - unsigned need_reply : 1; - /*unsigned is_dead : 1;*/ /* not used at the moment */ + unsigned need_reply:1; + /* unsigned is_dead:1; */ /* not used at the moment */ struct binder_buffer *buffer; unsigned int code; @@ -474,8 +477,8 @@ static void binder_set_nice(long nice) binder_user_error("binder: %d RLIMIT_NICE not set\n", current->pid); } -static size_t binder_buffer_size( - struct binder_proc *proc, struct binder_buffer *buffer) +static size_t binder_buffer_size(struct binder_proc *proc, + struct binder_buffer *buffer) { if (list_is_last(&buffer->entry, &proc->buffers)) return proc->buffer + proc->buffer_size - (void *)buffer->data; @@ -484,8 +487,8 @@ static size_t binder_buffer_size( struct binder_buffer, entry) - (size_t)buffer->data; } -static void binder_insert_free_buffer( - struct binder_proc *proc, struct binder_buffer *new_buffer) +static void binder_insert_free_buffer(struct binder_proc *proc, + struct binder_buffer *new_buffer) { struct rb_node **p = &proc->free_buffers.rb_node; struct rb_node *parent = NULL; @@ -517,8 +520,8 @@ static void binder_insert_free_buffer( rb_insert_color(&new_buffer->rb_node, &proc->free_buffers); } -static void binder_insert_allocated_buffer( - struct binder_proc *proc, struct binder_buffer *new_buffer) +static void binder_insert_allocated_buffer(struct binder_proc *proc, + struct binder_buffer *new_buffer) { struct rb_node **p = &proc->allocated_buffers.rb_node; struct rb_node *parent = NULL; @@ -542,8 +545,8 @@ static void binder_insert_allocated_buffer( rb_insert_color(&new_buffer->rb_node, &proc->allocated_buffers); } -static struct binder_buffer *binder_buffer_lookup( - struct binder_proc *proc, void __user *user_ptr) +static struct binder_buffer *binder_buffer_lookup(struct binder_proc *proc, + void __user *user_ptr) { struct rb_node *n = proc->allocated_buffers.rb_node; struct binder_buffer *buffer; @@ -567,7 +570,8 @@ static struct binder_buffer *binder_buffer_lookup( } static int binder_update_page_range(struct binder_proc *proc, int allocate, - void *start, void *end, struct vm_area_struct *vma) + void *start, void *end, + struct vm_area_struct *vma) { void *page_addr; unsigned long user_page_addr; @@ -664,7 +668,8 @@ err_no_vma: } static struct binder_buffer *binder_alloc_buf(struct binder_proc *proc, - size_t data_size, size_t offsets_size, int is_async) + size_t data_size, + size_t offsets_size, int is_async) { struct rb_node *n = proc->free_buffers.rb_node; struct binder_buffer *buffer; @@ -692,8 +697,9 @@ static struct binder_buffer *binder_alloc_buf(struct binder_proc *proc, if (is_async && proc->free_async_space < size + sizeof(struct binder_buffer)) { if (binder_debug_mask & BINDER_DEBUG_BUFFER_ALLOC) - printk(KERN_ERR "binder: %d: binder_alloc_buf size %zd f" - "ailed, no async space left\n", proc->pid, size); + printk(KERN_ERR + "binder: %d: binder_alloc_buf size %zd failed, " + "no async space left\n", proc->pid, size); return NULL; } @@ -777,8 +783,8 @@ static void *buffer_end_page(struct binder_buffer *buffer) return (void *)(((uintptr_t)(buffer + 1) - 1) & PAGE_MASK); } -static void binder_delete_free_buffer( - struct binder_proc *proc, struct binder_buffer *buffer) +static void binder_delete_free_buffer(struct binder_proc *proc, + struct binder_buffer *buffer) { struct binder_buffer *prev, *next = NULL; int free_page_end = 1; @@ -824,8 +830,8 @@ static void binder_delete_free_buffer( } } -static void binder_free_buf( - struct binder_proc *proc, struct binder_buffer *buffer) +static void binder_free_buf(struct binder_proc *proc, + struct binder_buffer *buffer) { size_t size, buffer_size; @@ -877,8 +883,8 @@ static void binder_free_buf( binder_insert_free_buffer(proc, buffer); } -static struct binder_node * -binder_get_node(struct binder_proc *proc, void __user *ptr) +static struct binder_node *binder_get_node(struct binder_proc *proc, + void __user *ptr) { struct rb_node *n = proc->nodes.rb_node; struct binder_node *node; @@ -896,8 +902,9 @@ binder_get_node(struct binder_proc *proc, void __user *ptr) return NULL; } -static struct binder_node * -binder_new_node(struct binder_proc *proc, void __user *ptr, void __user *cookie) +static struct binder_node *binder_new_node(struct binder_proc *proc, + void __user *ptr, + void __user *cookie) { struct rb_node **p = &proc->nodes.rb_node; struct rb_node *parent = NULL; @@ -935,9 +942,8 @@ binder_new_node(struct binder_proc *proc, void __user *ptr, void __user *cookie) return node; } -static int -binder_inc_node(struct binder_node *node, int strong, int internal, - struct list_head *target_list) +static int binder_inc_node(struct binder_node *node, int strong, int internal, + struct list_head *target_list) { if (strong) { if (internal) { @@ -971,8 +977,7 @@ binder_inc_node(struct binder_node *node, int strong, int internal, return 0; } -static int -binder_dec_node(struct binder_node *node, int strong, int internal) +static int binder_dec_node(struct binder_node *node, int strong, int internal) { if (strong) { if (internal) @@ -1014,8 +1019,8 @@ binder_dec_node(struct binder_node *node, int strong, int internal) } -static struct binder_ref * -binder_get_ref(struct binder_proc *proc, uint32_t desc) +static struct binder_ref *binder_get_ref(struct binder_proc *proc, + uint32_t desc) { struct rb_node *n = proc->refs_by_desc.rb_node; struct binder_ref *ref; @@ -1033,8 +1038,8 @@ binder_get_ref(struct binder_proc *proc, uint32_t desc) return NULL; } -static struct binder_ref * -binder_get_ref_for_node(struct binder_proc *proc, struct binder_node *node) +static struct binder_ref *binder_get_ref_for_node(struct binder_proc *proc, + struct binder_node *node) { struct rb_node *n; struct rb_node **p = &proc->refs_by_node.rb_node; @@ -1099,8 +1104,7 @@ binder_get_ref_for_node(struct binder_proc *proc, struct binder_node *node) return new_ref; } -static void -binder_delete_ref(struct binder_ref *ref) +static void binder_delete_ref(struct binder_ref *ref) { if (binder_debug_mask & BINDER_DEBUG_INTERNAL_REFS) printk(KERN_INFO "binder: %d delete ref %d desc %d for " @@ -1125,9 +1129,8 @@ binder_delete_ref(struct binder_ref *ref) binder_stats.obj_deleted[BINDER_STAT_REF]++; } -static int -binder_inc_ref( - struct binder_ref *ref, int strong, struct list_head *target_list) +static int binder_inc_ref(struct binder_ref *ref, int strong, + struct list_head *target_list) { int ret; if (strong) { @@ -1149,8 +1152,7 @@ binder_inc_ref( } -static int -binder_dec_ref(struct binder_ref *ref, int strong) +static int binder_dec_ref(struct binder_ref *ref, int strong) { if (strong) { if (ref->strong == 0) { @@ -1182,9 +1184,8 @@ binder_dec_ref(struct binder_ref *ref, int strong) return 0; } -static void -binder_pop_transaction( - struct binder_thread *target_thread, struct binder_transaction *t) +static void binder_pop_transaction(struct binder_thread *target_thread, + struct binder_transaction *t) { if (target_thread) { BUG_ON(target_thread->transaction_stack != t); @@ -1200,8 +1201,8 @@ binder_pop_transaction( binder_stats.obj_deleted[BINDER_STAT_TRANSACTION]++; } -static void -binder_send_failed_reply(struct binder_transaction *t, uint32_t error_code) +static void binder_send_failed_reply(struct binder_transaction *t, + uint32_t error_code) { struct binder_thread *target_thread; BUG_ON(t->flags & TF_ONE_WAY); @@ -1253,13 +1254,13 @@ binder_send_failed_reply(struct binder_transaction *t, uint32_t error_code) } } -static void -binder_transaction_buffer_release(struct binder_proc *proc, - struct binder_buffer *buffer, size_t *failed_at); +static void binder_transaction_buffer_release(struct binder_proc *proc, + struct binder_buffer *buffer, + size_t *failed_at); -static void -binder_transaction(struct binder_proc *proc, struct binder_thread *thread, - struct binder_transaction_data *tr, int reply) +static void binder_transaction(struct binder_proc *proc, + struct binder_thread *thread, + struct binder_transaction_data *tr, int reply) { struct binder_transaction *t; struct binder_work *tcomplete; @@ -1661,8 +1662,9 @@ err_no_context_mgr_node: thread->return_error = return_error; } -static void -binder_transaction_buffer_release(struct binder_proc *proc, struct binder_buffer *buffer, size_t *failed_at) +static void binder_transaction_buffer_release(struct binder_proc *proc, + struct binder_buffer *buffer, + size_t *failed_at) { size_t *offp, *off_end; int debug_id = buffer->debug_id; @@ -1730,9 +1732,8 @@ binder_transaction_buffer_release(struct binder_proc *proc, struct binder_buffer } } -int -binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, - void __user *buffer, int size, signed long *consumed) +int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, + void __user *buffer, int size, signed long *consumed) { uint32_t cmd; void __user *ptr = buffer + *consumed; @@ -2104,7 +2105,8 @@ binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, } break; default: - printk(KERN_ERR "binder: %d:%d unknown command %d\n", proc->pid, thread->pid, cmd); + printk(KERN_ERR "binder: %d:%d unknown command %d\n", + proc->pid, thread->pid, cmd); return -EINVAL; } *consumed = ptr - buffer; @@ -2112,8 +2114,8 @@ binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, return 0; } -void -binder_stat_br(struct binder_proc *proc, struct binder_thread *thread, uint32_t cmd) +void binder_stat_br(struct binder_proc *proc, struct binder_thread *thread, + uint32_t cmd) { if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.br)) { binder_stats.br[_IOC_NR(cmd)]++; @@ -2122,22 +2124,23 @@ binder_stat_br(struct binder_proc *proc, struct binder_thread *thread, uint32_t } } -static int -binder_has_proc_work(struct binder_proc *proc, struct binder_thread *thread) +static int binder_has_proc_work(struct binder_proc *proc, + struct binder_thread *thread) { - return !list_empty(&proc->todo) || (thread->looper & BINDER_LOOPER_STATE_NEED_RETURN); + return !list_empty(&proc->todo) || + (thread->looper & BINDER_LOOPER_STATE_NEED_RETURN); } -static int -binder_has_thread_work(struct binder_thread *thread) +static int binder_has_thread_work(struct binder_thread *thread) { return !list_empty(&thread->todo) || thread->return_error != BR_OK || (thread->looper & BINDER_LOOPER_STATE_NEED_RETURN); } -static int -binder_thread_read(struct binder_proc *proc, struct binder_thread *thread, - void __user *buffer, int size, signed long *consumed, int non_block) +static int binder_thread_read(struct binder_proc *proc, + struct binder_thread *thread, + void __user *buffer, int size, + signed long *consumed, int non_block) { void __user *ptr = buffer + *consumed; void __user *end = buffer + size; @@ -2152,7 +2155,8 @@ binder_thread_read(struct binder_proc *proc, struct binder_thread *thread, } retry: - wait_for_proc_work = thread->transaction_stack == NULL && list_empty(&thread->todo); + wait_for_proc_work = thread->transaction_stack == NULL && + list_empty(&thread->todo); if (thread->return_error != BR_OK && ptr < end) { if (thread->return_error2 != BR_OK) { @@ -2182,7 +2186,8 @@ retry: "for process work before calling BC_REGISTER_" "LOOPER or BC_ENTER_LOOPER (state %x)\n", proc->pid, thread->pid, thread->looper); - wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2); + wait_event_interruptible(binder_user_error_wait, + binder_stop_on_user_error < 2); } binder_set_nice(proc->default_priority); if (non_block) { @@ -2304,8 +2309,10 @@ retry: case BINDER_WORK_DEAD_BINDER: case BINDER_WORK_DEAD_BINDER_AND_CLEAR: case BINDER_WORK_CLEAR_DEATH_NOTIFICATION: { - struct binder_ref_death *death = container_of(w, struct binder_ref_death, work); + struct binder_ref_death *death; uint32_t cmd; + + death = container_of(w, struct binder_ref_death, work); if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION) cmd = BR_CLEAR_DEATH_NOTIFICATION_DONE; else @@ -2362,15 +2369,19 @@ retry: if (t->from) { struct task_struct *sender = t->from->proc->tsk; - tr.sender_pid = task_tgid_nr_ns(sender, current->nsproxy->pid_ns); + tr.sender_pid = task_tgid_nr_ns(sender, + current->nsproxy->pid_ns); } else { tr.sender_pid = 0; } tr.data_size = t->buffer->data_size; tr.offsets_size = t->buffer->offsets_size; - tr.data.ptr.buffer = (void *)t->buffer->data + proc->user_buffer_offset; - tr.data.ptr.offsets = tr.data.ptr.buffer + ALIGN(t->buffer->data_size, sizeof(void *)); + tr.data.ptr.buffer = (void *)t->buffer->data + + proc->user_buffer_offset; + tr.data.ptr.offsets = tr.data.ptr.buffer + + ALIGN(t->buffer->data_size, + sizeof(void *)); if (put_user(cmd, (uint32_t __user *)ptr)) return -EFAULT; @@ -2384,7 +2395,8 @@ retry: printk(KERN_INFO "binder: %d:%d %s %d %d:%d, cmd %d" "size %zd-%zd ptr %p-%p\n", proc->pid, thread->pid, - (cmd == BR_TRANSACTION) ? "BR_TRANSACTION" : "BR_REPLY", + (cmd == BR_TRANSACTION) ? "BR_TRANSACTION" : + "BR_REPLY", t->debug_id, t->from ? t->from->proc->pid : 0, t->from ? t->from->pid : 0, cmd, t->buffer->data_size, t->buffer->offsets_size, @@ -2430,7 +2442,9 @@ static void binder_release_work(struct list_head *list) list_del_init(&w->entry); switch (w->type) { case BINDER_WORK_TRANSACTION: { - struct binder_transaction *t = container_of(w, struct binder_transaction, work); + struct binder_transaction *t; + + t = container_of(w, struct binder_transaction, work); if (t->buffer->target_node && !(t->flags & TF_ONE_WAY)) binder_send_failed_reply(t, BR_DEAD_REPLY); } break; @@ -2480,7 +2494,8 @@ static struct binder_thread *binder_get_thread(struct binder_proc *proc) return thread; } -static int binder_free_thread(struct binder_proc *proc, struct binder_thread *thread) +static int binder_free_thread(struct binder_proc *proc, + struct binder_thread *thread) { struct binder_transaction *t; struct binder_transaction *send_reply = NULL; @@ -2493,8 +2508,10 @@ static int binder_free_thread(struct binder_proc *proc, struct binder_thread *th while (t) { active_transactions++; if (binder_debug_mask & BINDER_DEBUG_DEAD_TRANSACTION) - printk(KERN_INFO "binder: release %d:%d transaction %d %s, still active\n", - proc->pid, thread->pid, t->debug_id, (t->to_thread == thread) ? "in" : "out"); + printk(KERN_INFO "binder: release %d:%d transaction %d " + "%s, still active\n", proc->pid, thread->pid, + t->debug_id, + (t->to_thread == thread) ? "in" : "out"); if (t->to_thread == thread) { t->to_proc = NULL; t->to_thread = NULL; @@ -2517,7 +2534,8 @@ static int binder_free_thread(struct binder_proc *proc, struct binder_thread *th return active_transactions; } -static unsigned int binder_poll(struct file *filp, struct poll_table_struct *wait) +static unsigned int binder_poll(struct file *filp, + struct poll_table_struct *wait) { struct binder_proc *proc = filp->private_data; struct binder_thread *thread = NULL; @@ -2778,7 +2796,8 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma) proc->files = get_files_struct(current); proc->vma = vma; - /*printk(KERN_INFO "binder_mmap: %d %lx-%lx maps %p\n", proc->pid, vma->vm_start, vma->vm_end, proc->buffer);*/ + /*printk(KERN_INFO "binder_mmap: %d %lx-%lx maps %p\n", + proc->pid, vma->vm_start, vma->vm_end, proc->buffer);*/ return 0; err_alloc_small_buf_failed: @@ -2790,7 +2809,8 @@ err_alloc_pages_failed: err_get_vm_area_failed: err_already_mapped: err_bad_arg: - printk(KERN_ERR "binder_mmap: %d %lx-%lx %s failed %d\n", proc->pid, vma->vm_start, vma->vm_end, failure_string, ret); + printk(KERN_ERR "binder_mmap: %d %lx-%lx %s failed %d\n", + proc->pid, vma->vm_start, vma->vm_end, failure_string, ret); return ret; } @@ -2799,7 +2819,8 @@ static int binder_open(struct inode *nodp, struct file *filp) struct binder_proc *proc; if (binder_debug_mask & BINDER_DEBUG_OPEN_CLOSE) - printk(KERN_INFO "binder_open: %d:%d\n", current->group_leader->pid, current->pid); + printk(KERN_INFO "binder_open: %d:%d\n", + current->group_leader->pid, current->pid); proc = kzalloc(sizeof(*proc), GFP_KERNEL); if (proc == NULL) @@ -2821,7 +2842,9 @@ static int binder_open(struct inode *nodp, struct file *filp) char strbuf[11]; snprintf(strbuf, sizeof(strbuf), "%u", proc->pid); remove_proc_entry(strbuf, binder_proc_dir_entry_proc); - create_proc_read_entry(strbuf, S_IRUGO, binder_proc_dir_entry_proc, binder_read_proc_proc, proc); + create_proc_read_entry(strbuf, S_IRUGO, + binder_proc_dir_entry_proc, + binder_read_proc_proc, proc); } return 0; @@ -2925,12 +2948,15 @@ static void binder_deferred_release(struct binder_proc *proc) } } if (binder_debug_mask & BINDER_DEBUG_DEAD_BINDER) - printk(KERN_INFO "binder: node %d now dead, refs %d, death %d\n", node->debug_id, incoming_refs, death); + printk(KERN_INFO "binder: node %d now dead, " + "refs %d, death %d\n", node->debug_id, + incoming_refs, death); } } outgoing_refs = 0; while ((n = rb_first(&proc->refs_by_desc))) { - struct binder_ref *ref = rb_entry(n, struct binder_ref, rb_node_desc); + struct binder_ref *ref = rb_entry(n, struct binder_ref, + rb_node_desc); outgoing_refs++; binder_delete_ref(ref); } @@ -2938,12 +2964,15 @@ static void binder_deferred_release(struct binder_proc *proc) buffers = 0; while ((n = rb_first(&proc->allocated_buffers))) { - struct binder_buffer *buffer = rb_entry(n, struct binder_buffer, rb_node); + struct binder_buffer *buffer = rb_entry(n, struct binder_buffer, + rb_node); t = buffer->transaction; if (t) { t->buffer = NULL; buffer->transaction = NULL; - printk(KERN_ERR "binder: release proc %d, transaction %d, not freed\n", proc->pid, t->debug_id); + printk(KERN_ERR "binder: release proc %d, " + "transaction %d, not freed\n", + proc->pid, t->debug_id); /*BUG();*/ } binder_free_buf(proc, buffer); @@ -2957,8 +2986,13 @@ static void binder_deferred_release(struct binder_proc *proc) int i; for (i = 0; i < proc->buffer_size / PAGE_SIZE; i++) { if (proc->pages[i]) { - if (binder_debug_mask & BINDER_DEBUG_BUFFER_ALLOC) - printk(KERN_INFO "binder_release: %d: page %d at %p not freed\n", proc->pid, i, proc->buffer + i * PAGE_SIZE); + if (binder_debug_mask & + BINDER_DEBUG_BUFFER_ALLOC) + printk(KERN_INFO + "binder_release: %d: " + "page %d at %p not freed\n", + proc->pid, i, + proc->buffer + i * PAGE_SIZE); __free_page(proc->pages[i]); page_count++; } @@ -2970,8 +3004,12 @@ static void binder_deferred_release(struct binder_proc *proc) put_task_struct(proc->tsk); if (binder_debug_mask & BINDER_DEBUG_OPEN_CLOSE) - printk(KERN_INFO "binder_release: %d threads %d, nodes %d (ref %d), refs %d, active transactions %d, buffers %d, pages %d\n", - proc->pid, threads, nodes, incoming_refs, outgoing_refs, active_transactions, buffers, page_count); + printk(KERN_INFO + "binder_release: %d threads %d, nodes %d (ref %d), " + "refs %d, active transactions %d, buffers %d, " + "pages %d\n", + proc->pid, threads, nodes, incoming_refs, outgoing_refs, + active_transactions, buffers, page_count); kfree(proc); } @@ -2998,9 +3036,11 @@ static void binder_deferred_func(struct work_struct *work) mutex_unlock(&binder_deferred_lock); files = NULL; - if (defer & BINDER_DEFERRED_PUT_FILES) - if ((files = proc->files)) + if (defer & BINDER_DEFERRED_PUT_FILES) { + files = proc->files; + if (files) proc->files = NULL; + } if (defer & BINDER_DEFERRED_FLUSH) binder_deferred_flush(proc); @@ -3027,10 +3067,14 @@ static void binder_defer_work(struct binder_proc *proc, int defer) mutex_unlock(&binder_deferred_lock); } -static char *print_binder_transaction(char *buf, char *end, const char *prefix, struct binder_transaction *t) +static char *print_binder_transaction(char *buf, char *end, const char *prefix, + struct binder_transaction *t) { - buf += snprintf(buf, end - buf, "%s %d: %p from %d:%d to %d:%d code %x flags %x pri %ld r%d", - prefix, t->debug_id, t, t->from ? t->from->proc->pid : 0, + buf += snprintf(buf, end - buf, + "%s %d: %p from %d:%d to %d:%d code %x " + "flags %x pri %ld r%d", + prefix, t->debug_id, t, + t->from ? t->from->proc->pid : 0, t->from ? t->from->pid : 0, t->to_proc ? t->to_proc->pid : 0, t->to_thread ? t->to_thread->pid : 0, @@ -3053,7 +3097,8 @@ static char *print_binder_transaction(char *buf, char *end, const char *prefix, return buf; } -static char *print_binder_buffer(char *buf, char *end, const char *prefix, struct binder_buffer *buffer) +static char *print_binder_buffer(char *buf, char *end, const char *prefix, + struct binder_buffer *buffer) { buf += snprintf(buf, end - buf, "%s %d: %p size %zd:%zd %s\n", prefix, buffer->debug_id, buffer->data, @@ -3063,7 +3108,8 @@ static char *print_binder_buffer(char *buf, char *end, const char *prefix, struc } static char *print_binder_work(char *buf, char *end, const char *prefix, - const char *transaction_prefix, struct binder_work *w) + const char *transaction_prefix, + struct binder_work *w) { struct binder_node *node; struct binder_transaction *t; @@ -3080,7 +3126,8 @@ static char *print_binder_work(char *buf, char *end, const char *prefix, case BINDER_WORK_NODE: node = container_of(w, struct binder_node, work); buf += snprintf(buf, end - buf, "%snode work %d: u%p c%p\n", - prefix, node->debug_id, node->ptr, node->cookie); + prefix, node->debug_id, node->ptr, + node->cookie); break; case BINDER_WORK_DEAD_BINDER: buf += snprintf(buf, end - buf, "%shas dead binder\n", prefix); @@ -3101,27 +3148,33 @@ static char *print_binder_work(char *buf, char *end, const char *prefix, return buf; } -static char *print_binder_thread(char *buf, char *end, struct binder_thread *thread, int print_always) +static char *print_binder_thread(char *buf, char *end, + struct binder_thread *thread, + int print_always) { struct binder_transaction *t; struct binder_work *w; char *start_buf = buf; char *header_buf; - buf += snprintf(buf, end - buf, " thread %d: l %02x\n", thread->pid, thread->looper); + buf += snprintf(buf, end - buf, " thread %d: l %02x\n", + thread->pid, thread->looper); header_buf = buf; t = thread->transaction_stack; while (t) { if (buf >= end) break; if (t->from == thread) { - buf = print_binder_transaction(buf, end, " outgoing transaction", t); + buf = print_binder_transaction(buf, end, + " outgoing transaction", t); t = t->from_parent; } else if (t->to_thread == thread) { - buf = print_binder_transaction(buf, end, " incoming transaction", t); + buf = print_binder_transaction(buf, end, + " incoming transaction", t); t = t->to_parent; } else { - buf = print_binder_transaction(buf, end, " bad transaction", t); + buf = print_binder_transaction(buf, end, + " bad transaction", t); t = NULL; } } @@ -3142,11 +3195,14 @@ static char *print_binder_node(char *buf, char *end, struct binder_node *node) struct hlist_node *pos; struct binder_work *w; int count; + count = 0; hlist_for_each_entry(ref, pos, &node->refs, node_entry) count++; - buf += snprintf(buf, end - buf, " node %d: u%p c%p hs %d hw %d ls %d lw %d is %d iw %d", + buf += snprintf(buf, end - buf, + " node %d: u%p c%p hs %d hw %d ls %d lw %d " + "is %d iw %d", node->debug_id, node->ptr, node->cookie, node->has_strong_ref, node->has_weak_ref, node->local_strong_refs, node->local_weak_refs, @@ -3175,13 +3231,16 @@ static char *print_binder_node(char *buf, char *end, struct binder_node *node) static char *print_binder_ref(char *buf, char *end, struct binder_ref *ref) { - buf += snprintf(buf, end - buf, " ref %d: desc %d %snode %d s %d w %d d %p\n", - ref->debug_id, ref->desc, ref->node->proc ? "" : "dead ", - ref->node->debug_id, ref->strong, ref->weak, ref->death); + buf += snprintf(buf, end - buf, + " ref %d: desc %d %snode %d s %d w %d d %p\n", + ref->debug_id, ref->desc, + ref->node->proc ? "" : "dead ", ref->node->debug_id, + ref->strong, ref->weak, ref->death); return buf; } -static char *print_binder_proc(char *buf, char *end, struct binder_proc *proc, int print_all) +static char *print_binder_proc(char *buf, char *end, + struct binder_proc *proc, int print_all) { struct binder_work *w; struct rb_node *n; @@ -3191,19 +3250,34 @@ static char *print_binder_proc(char *buf, char *end, struct binder_proc *proc, i buf += snprintf(buf, end - buf, "proc %d\n", proc->pid); header_buf = buf; - for (n = rb_first(&proc->threads); n != NULL && buf < end; n = rb_next(n)) - buf = print_binder_thread(buf, end, rb_entry(n, struct binder_thread, rb_node), print_all); - for (n = rb_first(&proc->nodes); n != NULL && buf < end; n = rb_next(n)) { - struct binder_node *node = rb_entry(n, struct binder_node, rb_node); + for (n = rb_first(&proc->threads); + n != NULL && buf < end; + n = rb_next(n)) + buf = print_binder_thread(buf, end, + rb_entry(n, struct binder_thread, + rb_node), print_all); + for (n = rb_first(&proc->nodes); + n != NULL && buf < end; + n = rb_next(n)) { + struct binder_node *node = rb_entry(n, struct binder_node, + rb_node); if (print_all || node->has_async_transaction) buf = print_binder_node(buf, end, node); } if (print_all) { - for (n = rb_first(&proc->refs_by_desc); n != NULL && buf < end; n = rb_next(n)) - buf = print_binder_ref(buf, end, rb_entry(n, struct binder_ref, rb_node_desc)); + for (n = rb_first(&proc->refs_by_desc); + n != NULL && buf < end; + n = rb_next(n)) + buf = print_binder_ref(buf, end, + rb_entry(n, struct binder_ref, + rb_node_desc)); } - for (n = rb_first(&proc->allocated_buffers); n != NULL && buf < end; n = rb_next(n)) - buf = print_binder_buffer(buf, end, " buffer", rb_entry(n, struct binder_buffer, rb_node)); + for (n = rb_first(&proc->allocated_buffers); + n != NULL && buf < end; + n = rb_next(n)) + buf = print_binder_buffer(buf, end, " buffer", + rb_entry(n, struct binder_buffer, + rb_node)); list_for_each_entry(w, &proc->todo, entry) { if (buf >= end) break; @@ -3213,7 +3287,8 @@ static char *print_binder_proc(char *buf, char *end, struct binder_proc *proc, i list_for_each_entry(w, &proc->delivered_death, entry) { if (buf >= end) break; - buf += snprintf(buf, end - buf, " has delivered dead binder\n"); + buf += snprintf(buf, end - buf, + " has delivered dead binder\n"); break; } if (!print_all && buf == header_buf) @@ -3272,20 +3347,24 @@ static const char *binder_objstat_strings[] = { "transaction_complete" }; -static char *print_binder_stats(char *buf, char *end, const char *prefix, struct binder_stats *stats) +static char *print_binder_stats(char *buf, char *end, const char *prefix, + struct binder_stats *stats) { int i; - BUILD_BUG_ON(ARRAY_SIZE(stats->bc) != ARRAY_SIZE(binder_command_strings)); + BUILD_BUG_ON(ARRAY_SIZE(stats->bc) != + ARRAY_SIZE(binder_command_strings)); for (i = 0; i < ARRAY_SIZE(stats->bc); i++) { if (stats->bc[i]) buf += snprintf(buf, end - buf, "%s%s: %d\n", prefix, - binder_command_strings[i], stats->bc[i]); + binder_command_strings[i], + stats->bc[i]); if (buf >= end) return buf; } - BUILD_BUG_ON(ARRAY_SIZE(stats->br) != ARRAY_SIZE(binder_return_strings)); + BUILD_BUG_ON(ARRAY_SIZE(stats->br) != + ARRAY_SIZE(binder_return_strings)); for (i = 0; i < ARRAY_SIZE(stats->br); i++) { if (stats->br[i]) buf += snprintf(buf, end - buf, "%s%s: %d\n", prefix, @@ -3294,13 +3373,17 @@ static char *print_binder_stats(char *buf, char *end, const char *prefix, struct return buf; } - BUILD_BUG_ON(ARRAY_SIZE(stats->obj_created) != ARRAY_SIZE(binder_objstat_strings)); - BUILD_BUG_ON(ARRAY_SIZE(stats->obj_created) != ARRAY_SIZE(stats->obj_deleted)); + BUILD_BUG_ON(ARRAY_SIZE(stats->obj_created) != + ARRAY_SIZE(binder_objstat_strings)); + BUILD_BUG_ON(ARRAY_SIZE(stats->obj_created) != + ARRAY_SIZE(stats->obj_deleted)); for (i = 0; i < ARRAY_SIZE(stats->obj_created); i++) { if (stats->obj_created[i] || stats->obj_deleted[i]) - buf += snprintf(buf, end - buf, "%s%s: active %d total %d\n", prefix, + buf += snprintf(buf, end - buf, + "%s%s: active %d total %d\n", prefix, binder_objstat_strings[i], - stats->obj_created[i] - stats->obj_deleted[i], + stats->obj_created[i] - + stats->obj_deleted[i], stats->obj_created[i]); if (buf >= end) return buf; @@ -3308,7 +3391,8 @@ static char *print_binder_stats(char *buf, char *end, const char *prefix, struct return buf; } -static char *print_binder_proc_stats(char *buf, char *end, struct binder_proc *proc) +static char *print_binder_proc_stats(char *buf, char *end, + struct binder_proc *proc) { struct binder_work *w; struct rb_node *n; @@ -3340,12 +3424,14 @@ static char *print_binder_proc_stats(char *buf, char *end, struct binder_proc *p strong = 0; weak = 0; for (n = rb_first(&proc->refs_by_desc); n != NULL; n = rb_next(n)) { - struct binder_ref *ref = rb_entry(n, struct binder_ref, rb_node_desc); + struct binder_ref *ref = rb_entry(n, struct binder_ref, + rb_node_desc); count++; strong += ref->strong; weak += ref->weak; } - buf += snprintf(buf, end - buf, " refs: %d s %d w %d\n", count, strong, weak); + buf += snprintf(buf, end - buf, " refs: %d s %d w %d\n", + count, strong, weak); if (buf >= end) return buf; @@ -3376,8 +3462,8 @@ static char *print_binder_proc_stats(char *buf, char *end, struct binder_proc *p } -static int binder_read_proc_state( - char *page, char **start, off_t off, int count, int *eof, void *data) +static int binder_read_proc_state(char *page, char **start, off_t off, + int count, int *eof, void *data) { struct binder_proc *proc; struct hlist_node *pos; @@ -3424,8 +3510,8 @@ static int binder_read_proc_state( return len < count ? len : count; } -static int binder_read_proc_stats( - char *page, char **start, off_t off, int count, int *eof, void *data) +static int binder_read_proc_stats(char *page, char **start, off_t off, + int count, int *eof, void *data) { struct binder_proc *proc; struct hlist_node *pos; @@ -3464,8 +3550,8 @@ static int binder_read_proc_stats( return len < count ? len : count; } -static int binder_read_proc_transactions( - char *page, char **start, off_t off, int count, int *eof, void *data) +static int binder_read_proc_transactions(char *page, char **start, off_t off, + int count, int *eof, void *data) { struct binder_proc *proc; struct hlist_node *pos; @@ -3502,8 +3588,8 @@ static int binder_read_proc_transactions( return len < count ? len : count; } -static int binder_read_proc_proc( - char *page, char **start, off_t off, int count, int *eof, void *data) +static int binder_read_proc_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) { struct binder_proc *proc = data; int len = 0; @@ -3533,9 +3619,12 @@ static int binder_read_proc_proc( return len < count ? len : count; } -static char *print_binder_transaction_log_entry(char *buf, char *end, struct binder_transaction_log_entry *e) +static char *print_binder_transaction_log_entry(char *buf, char *end, + struct binder_transaction_log_entry *e) { - buf += snprintf(buf, end - buf, "%d: %s from %d:%d to %d:%d node %d handle %d size %d:%d\n", + buf += snprintf(buf, end - buf, + "%d: %s from %d:%d to %d:%d node %d handle %d " + "size %d:%d\n", e->debug_id, (e->call_type == 2) ? "reply" : ((e->call_type == 1) ? "async" : "call "), e->from_proc, e->from_thread, e->to_proc, e->to_thread, e->to_node, @@ -3559,13 +3648,15 @@ static int binder_read_proc_transaction_log( for (i = log->next; i < ARRAY_SIZE(log->entry); i++) { if (buf >= end) break; - buf = print_binder_transaction_log_entry(buf, end, &log->entry[i]); + buf = print_binder_transaction_log_entry(buf, end, + &log->entry[i]); } } for (i = 0; i < log->next; i++) { if (buf >= end) break; - buf = print_binder_transaction_log_entry(buf, end, &log->entry[i]); + buf = print_binder_transaction_log_entry(buf, end, + &log->entry[i]); } *start = page + off; @@ -3579,7 +3670,7 @@ static int binder_read_proc_transaction_log( return len < count ? len : count; } -static struct file_operations binder_fops = { +static const struct file_operations binder_fops = { .owner = THIS_MODULE, .poll = binder_poll, .unlocked_ioctl = binder_ioctl, @@ -3601,14 +3692,35 @@ static int __init binder_init(void) binder_proc_dir_entry_root = proc_mkdir("binder", NULL); if (binder_proc_dir_entry_root) - binder_proc_dir_entry_proc = proc_mkdir("proc", binder_proc_dir_entry_root); + binder_proc_dir_entry_proc = proc_mkdir("proc", + binder_proc_dir_entry_root); ret = misc_register(&binder_miscdev); if (binder_proc_dir_entry_root) { - create_proc_read_entry("state", S_IRUGO, binder_proc_dir_entry_root, binder_read_proc_state, NULL); - create_proc_read_entry("stats", S_IRUGO, binder_proc_dir_entry_root, binder_read_proc_stats, NULL); - create_proc_read_entry("transactions", S_IRUGO, binder_proc_dir_entry_root, binder_read_proc_transactions, NULL); - create_proc_read_entry("transaction_log", S_IRUGO, binder_proc_dir_entry_root, binder_read_proc_transaction_log, &binder_transaction_log); - create_proc_read_entry("failed_transaction_log", S_IRUGO, binder_proc_dir_entry_root, binder_read_proc_transaction_log, &binder_transaction_log_failed); + create_proc_read_entry("state", + S_IRUGO, + binder_proc_dir_entry_root, + binder_read_proc_state, + NULL); + create_proc_read_entry("stats", + S_IRUGO, + binder_proc_dir_entry_root, + binder_read_proc_stats, + NULL); + create_proc_read_entry("transactions", + S_IRUGO, + binder_proc_dir_entry_root, + binder_read_proc_transactions, + NULL); + create_proc_read_entry("transaction_log", + S_IRUGO, + binder_proc_dir_entry_root, + binder_read_proc_transaction_log, + &binder_transaction_log); + create_proc_read_entry("failed_transaction_log", + S_IRUGO, + binder_proc_dir_entry_root, + binder_read_proc_transaction_log, + &binder_transaction_log_failed); } return ret; } diff --git a/drivers/staging/android/logger.c b/drivers/staging/android/logger.c index ab32003ecd0b..6c10b456c6cc 100644 --- a/drivers/staging/android/logger.c +++ b/drivers/staging/android/logger.c @@ -35,7 +35,7 @@ * mutex 'mutex'. */ struct logger_log { - unsigned char * buffer; /* the ring buffer itself */ + unsigned char *buffer;/* the ring buffer itself */ struct miscdevice misc; /* misc device representing the log */ wait_queue_head_t wq; /* wait queue for readers */ struct list_head readers; /* this log's readers */ @@ -52,7 +52,7 @@ struct logger_log { * reference counting. The structure is protected by log->mutex. */ struct logger_reader { - struct logger_log * log; /* associated log */ + struct logger_log *log; /* associated log */ struct list_head list; /* entry in logger_log's list */ size_t r_off; /* current read head offset */ }; @@ -74,7 +74,7 @@ struct logger_reader { * file->logger_log. Thus what file->private_data points at depends on whether * or not the file was opened for reading. This function hides that dirtiness. */ -static inline struct logger_log * file_get_log(struct file *file) +static inline struct logger_log *file_get_log(struct file *file) { if (file->f_mode & FMODE_READ) { struct logger_reader *reader = file->private_data; @@ -379,7 +379,7 @@ ssize_t logger_aio_write(struct kiocb *iocb, const struct iovec *iov, return ret; } -static struct logger_log * get_log_from_minor(int); +static struct logger_log *get_log_from_minor(int); /* * logger_open - the log's open() file operation @@ -519,7 +519,7 @@ static long logger_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return ret; } -static struct file_operations logger_fops = { +static const struct file_operations logger_fops = { .owner = THIS_MODULE, .read = logger_read, .aio_write = logger_aio_write, @@ -557,7 +557,7 @@ DEFINE_LOGGER_DEVICE(log_main, LOGGER_LOG_MAIN, 64*1024) DEFINE_LOGGER_DEVICE(log_events, LOGGER_LOG_EVENTS, 256*1024) DEFINE_LOGGER_DEVICE(log_radio, LOGGER_LOG_RADIO, 64*1024) -static struct logger_log * get_log_from_minor(int minor) +static struct logger_log *get_log_from_minor(int minor) { if (log_main.misc.minor == minor) return &log_main; diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c index 3715d56ca96b..fe72240f5a9e 100644 --- a/drivers/staging/android/lowmemorykiller.c +++ b/drivers/staging/android/lowmemorykiller.c @@ -34,18 +34,24 @@ static int lowmem_adj[6] = { }; static int lowmem_adj_size = 4; static size_t lowmem_minfree[6] = { - 3*512, // 6MB - 2*1024, // 8MB - 4*1024, // 16MB - 16*1024, // 64MB + 3 * 512, /* 6MB */ + 2 * 1024, /* 8MB */ + 4 * 1024, /* 16MB */ + 16 * 1024, /* 64MB */ }; static int lowmem_minfree_size = 4; -#define lowmem_print(level, x...) do { if(lowmem_debug_level >= (level)) printk(x); } while(0) +#define lowmem_print(level, x...) \ + do { \ + if (lowmem_debug_level >= (level)) \ + printk(x); \ + } while (0) module_param_named(cost, lowmem_shrinker.seeks, int, S_IRUGO | S_IWUSR); -module_param_array_named(adj, lowmem_adj, int, &lowmem_adj_size, S_IRUGO | S_IWUSR); -module_param_array_named(minfree, lowmem_minfree, uint, &lowmem_minfree_size, S_IRUGO | S_IWUSR); +module_param_array_named(adj, lowmem_adj, int, &lowmem_adj_size, + S_IRUGO | S_IWUSR); +module_param_array_named(minfree, lowmem_minfree, uint, &lowmem_minfree_size, + S_IRUGO | S_IWUSR); module_param_named(debug_level, lowmem_debug_level, uint, S_IRUGO | S_IWUSR); static int lowmem_shrink(int nr_to_scan, gfp_t gfp_mask) @@ -57,46 +63,77 @@ static int lowmem_shrink(int nr_to_scan, gfp_t gfp_mask) int i; int min_adj = OOM_ADJUST_MAX + 1; int selected_tasksize = 0; + int selected_oom_adj; int array_size = ARRAY_SIZE(lowmem_adj); - int other_free = global_page_state(NR_FREE_PAGES) + global_page_state(NR_FILE_PAGES); - if(lowmem_adj_size < array_size) + int other_free = global_page_state(NR_FREE_PAGES); + int other_file = global_page_state(NR_FILE_PAGES); + + if (lowmem_adj_size < array_size) array_size = lowmem_adj_size; - if(lowmem_minfree_size < array_size) + if (lowmem_minfree_size < array_size) array_size = lowmem_minfree_size; - for(i = 0; i < array_size; i++) { - if(other_free < lowmem_minfree[i]) { + for (i = 0; i < array_size; i++) { + if (other_free < lowmem_minfree[i] && + other_file < lowmem_minfree[i]) { min_adj = lowmem_adj[i]; break; } } - if(nr_to_scan > 0) - lowmem_print(3, "lowmem_shrink %d, %x, ofree %d, ma %d\n", nr_to_scan, gfp_mask, other_free, min_adj); + if (nr_to_scan > 0) + lowmem_print(3, "lowmem_shrink %d, %x, ofree %d %d, ma %d\n", + nr_to_scan, gfp_mask, other_free, other_file, + min_adj); + rem = global_page_state(NR_ACTIVE_ANON) + + global_page_state(NR_ACTIVE_FILE) + + global_page_state(NR_INACTIVE_ANON) + + global_page_state(NR_INACTIVE_FILE); + if (nr_to_scan <= 0 || min_adj == OOM_ADJUST_MAX + 1) { + lowmem_print(5, "lowmem_shrink %d, %x, return %d\n", + nr_to_scan, gfp_mask, rem); + return rem; + } + selected_oom_adj = min_adj; + read_lock(&tasklist_lock); for_each_process(p) { - if(p->oomkilladj >= 0 && p->mm) { - tasksize = get_mm_rss(p->mm); - if(nr_to_scan > 0 && tasksize > 0 && p->oomkilladj >= min_adj) { - if(selected == NULL || - p->oomkilladj > selected->oomkilladj || - (p->oomkilladj == selected->oomkilladj && - tasksize > selected_tasksize)) { - selected = p; - selected_tasksize = tasksize; - lowmem_print(2, "select %d (%s), adj %d, size %d, to kill\n", - p->pid, p->comm, p->oomkilladj, tasksize); - } - } - rem += tasksize; + int oom_adj; + + task_lock(p); + if (!p->mm) { + task_unlock(p); + continue; } + oom_adj = p->oomkilladj; + if (oom_adj < min_adj) { + task_unlock(p); + continue; + } + tasksize = get_mm_rss(p->mm); + task_unlock(p); + if (tasksize <= 0) + continue; + if (selected) { + if (oom_adj < selected_oom_adj) + continue; + if (oom_adj == selected_oom_adj && + tasksize <= selected_tasksize) + continue; + } + selected = p; + selected_tasksize = tasksize; + selected_oom_adj = oom_adj; + lowmem_print(2, "select %d (%s), adj %d, size %d, to kill\n", + p->pid, p->comm, oom_adj, tasksize); } - if(selected != NULL) { + if (selected) { lowmem_print(1, "send sigkill to %d (%s), adj %d, size %d\n", - selected->pid, selected->comm, - selected->oomkilladj, selected_tasksize); + selected->pid, selected->comm, + selected_oom_adj, selected_tasksize); force_sig(SIGKILL, selected); rem -= selected_tasksize; } - lowmem_print(4, "lowmem_shrink %d, %x, return %d\n", nr_to_scan, gfp_mask, rem); + lowmem_print(4, "lowmem_shrink %d, %x, return %d\n", + nr_to_scan, gfp_mask, rem); read_unlock(&tasklist_lock); return rem; } diff --git a/drivers/staging/android/ram_console.c b/drivers/staging/android/ram_console.c index 3375c1cce2b3..8f18a59744cd 100644 --- a/drivers/staging/android/ram_console.c +++ b/drivers/staging/android/ram_console.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION #include @@ -225,8 +225,9 @@ static int __init ram_console_init(struct ram_console_buffer *buffer, buffer_size - sizeof(struct ram_console_buffer); if (ram_console_buffer_size > buffer_size) { - pr_err("ram_console: buffer %p, invalid size %zu, datasize %zu\n", - buffer, buffer_size, ram_console_buffer_size); + pr_err("ram_console: buffer %p, invalid size %zu, " + "datasize %zu\n", buffer, buffer_size, + ram_console_buffer_size); return 0; } @@ -365,7 +366,7 @@ static ssize_t ram_console_read_old(struct file *file, char __user *buf, return count; } -static struct file_operations ram_console_file_ops = { +static const struct file_operations ram_console_file_ops = { .owner = THIS_MODULE, .read = ram_console_read_old, }; diff --git a/drivers/staging/android/timed_gpio.c b/drivers/staging/android/timed_gpio.c index 33daff0481d2..be7cdaa783ae 100644 --- a/drivers/staging/android/timed_gpio.c +++ b/drivers/staging/android/timed_gpio.c @@ -20,13 +20,12 @@ #include #include +#include "timed_output.h" #include "timed_gpio.h" -static struct class *timed_gpio_class; - struct timed_gpio_data { - struct device *dev; + struct timed_output_dev dev; struct hrtimer timer; spinlock_t lock; unsigned gpio; @@ -36,70 +35,62 @@ struct timed_gpio_data { static enum hrtimer_restart gpio_timer_func(struct hrtimer *timer) { - struct timed_gpio_data *gpio_data = container_of(timer, struct timed_gpio_data, timer); + struct timed_gpio_data *data = + container_of(timer, struct timed_gpio_data, timer); - gpio_direction_output(gpio_data->gpio, gpio_data->active_low ? 1 : 0); + gpio_direction_output(data->gpio, data->active_low ? 1 : 0); return HRTIMER_NORESTART; } -static ssize_t gpio_enable_show(struct device *dev, struct device_attribute *attr, char *buf) +static int gpio_get_time(struct timed_output_dev *dev) { - struct timed_gpio_data *gpio_data = dev_get_drvdata(dev); - int remaining; + struct timed_gpio_data *data = + container_of(dev, struct timed_gpio_data, dev); - if (hrtimer_active(&gpio_data->timer)) { - ktime_t r = hrtimer_get_remaining(&gpio_data->timer); + if (hrtimer_active(&data->timer)) { + ktime_t r = hrtimer_get_remaining(&data->timer); struct timeval t = ktime_to_timeval(r); - remaining = t.tv_sec * 1000 + t.tv_usec / 1000; + return t.tv_sec * 1000 + t.tv_usec / 1000; } else - remaining = 0; - - return sprintf(buf, "%d\n", remaining); + return 0; } -static ssize_t gpio_enable_store( - struct device *dev, struct device_attribute *attr, - const char *buf, size_t size) +static void gpio_enable(struct timed_output_dev *dev, int value) { - struct timed_gpio_data *gpio_data = dev_get_drvdata(dev); - int value; + struct timed_gpio_data *data = + container_of(dev, struct timed_gpio_data, dev); unsigned long flags; - sscanf(buf, "%d", &value); - - spin_lock_irqsave(&gpio_data->lock, flags); + spin_lock_irqsave(&data->lock, flags); /* cancel previous timer and set GPIO according to value */ - hrtimer_cancel(&gpio_data->timer); - gpio_direction_output(gpio_data->gpio, gpio_data->active_low ? !value : !!value); + hrtimer_cancel(&data->timer); + gpio_direction_output(data->gpio, data->active_low ? !value : !!value); if (value > 0) { - if (value > gpio_data->max_timeout) - value = gpio_data->max_timeout; + if (value > data->max_timeout) + value = data->max_timeout; - hrtimer_start(&gpio_data->timer, - ktime_set(value / 1000, (value % 1000) * 1000000), - HRTIMER_MODE_REL); + hrtimer_start(&data->timer, + ktime_set(value / 1000, (value % 1000) * 1000000), + HRTIMER_MODE_REL); } - spin_unlock_irqrestore(&gpio_data->lock, flags); - - return size; + spin_unlock_irqrestore(&data->lock, flags); } -static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, gpio_enable_show, gpio_enable_store); - static int timed_gpio_probe(struct platform_device *pdev) { struct timed_gpio_platform_data *pdata = pdev->dev.platform_data; struct timed_gpio *cur_gpio; struct timed_gpio_data *gpio_data, *gpio_dat; - int i, ret = 0; + int i, j, ret = 0; if (!pdata) return -EBUSY; - gpio_data = kzalloc(sizeof(struct timed_gpio_data) * pdata->num_gpios, GFP_KERNEL); + gpio_data = kzalloc(sizeof(struct timed_gpio_data) * pdata->num_gpios, + GFP_KERNEL); if (!gpio_data) return -ENOMEM; @@ -107,23 +98,26 @@ static int timed_gpio_probe(struct platform_device *pdev) cur_gpio = &pdata->gpios[i]; gpio_dat = &gpio_data[i]; - hrtimer_init(&gpio_dat->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + hrtimer_init(&gpio_dat->timer, CLOCK_MONOTONIC, + HRTIMER_MODE_REL); gpio_dat->timer.function = gpio_timer_func; spin_lock_init(&gpio_dat->lock); + gpio_dat->dev.name = cur_gpio->name; + gpio_dat->dev.get_time = gpio_get_time; + gpio_dat->dev.enable = gpio_enable; + ret = timed_output_dev_register(&gpio_dat->dev); + if (ret < 0) { + for (j = 0; j < i; j++) + timed_output_dev_unregister(&gpio_data[i].dev); + kfree(gpio_data); + return ret; + } + gpio_dat->gpio = cur_gpio->gpio; gpio_dat->max_timeout = cur_gpio->max_timeout; gpio_dat->active_low = cur_gpio->active_low; gpio_direction_output(gpio_dat->gpio, gpio_dat->active_low); - - gpio_dat->dev = device_create(timed_gpio_class, &pdev->dev, 0, "%s", cur_gpio->name); - if (unlikely(IS_ERR(gpio_dat->dev))) - return PTR_ERR(gpio_dat->dev); - - dev_set_drvdata(gpio_dat->dev, gpio_dat); - ret = device_create_file(gpio_dat->dev, &dev_attr_enable); - if (ret) - return ret; } platform_set_drvdata(pdev, gpio_data); @@ -137,10 +131,8 @@ static int timed_gpio_remove(struct platform_device *pdev) struct timed_gpio_data *gpio_data = platform_get_drvdata(pdev); int i; - for (i = 0; i < pdata->num_gpios; i++) { - device_remove_file(gpio_data[i].dev, &dev_attr_enable); - device_unregister(gpio_data[i].dev); - } + for (i = 0; i < pdata->num_gpios; i++) + timed_output_dev_unregister(&gpio_data[i].dev); kfree(gpio_data); @@ -151,22 +143,18 @@ static struct platform_driver timed_gpio_driver = { .probe = timed_gpio_probe, .remove = timed_gpio_remove, .driver = { - .name = "timed-gpio", + .name = TIMED_GPIO_NAME, .owner = THIS_MODULE, }, }; static int __init timed_gpio_init(void) { - timed_gpio_class = class_create(THIS_MODULE, "timed_output"); - if (IS_ERR(timed_gpio_class)) - return PTR_ERR(timed_gpio_class); return platform_driver_register(&timed_gpio_driver); } static void __exit timed_gpio_exit(void) { - class_destroy(timed_gpio_class); platform_driver_unregister(&timed_gpio_driver); } diff --git a/drivers/staging/android/timed_gpio.h b/drivers/staging/android/timed_gpio.h index 78449b2161cf..a0e15f8be3f7 100644 --- a/drivers/staging/android/timed_gpio.h +++ b/drivers/staging/android/timed_gpio.h @@ -16,10 +16,12 @@ #ifndef _LINUX_TIMED_GPIO_H #define _LINUX_TIMED_GPIO_H +#define TIMED_GPIO_NAME "timed-gpio" + struct timed_gpio { const char *name; unsigned gpio; - int max_timeout; + int max_timeout; u8 active_low; }; diff --git a/drivers/staging/android/timed_output.c b/drivers/staging/android/timed_output.c new file mode 100644 index 000000000000..62e79180421b --- /dev/null +++ b/drivers/staging/android/timed_output.c @@ -0,0 +1,121 @@ +/* drivers/misc/timed_output.c + * + * Copyright (C) 2009 Google, Inc. + * Author: Mike Lockwood + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 +#include +#include +#include +#include + +#include "timed_output.h" + +static struct class *timed_output_class; +static atomic_t device_count; + +static ssize_t enable_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct timed_output_dev *tdev = dev_get_drvdata(dev); + int remaining = tdev->get_time(tdev); + + return sprintf(buf, "%d\n", remaining); +} + +static ssize_t enable_store( + struct device *dev, struct device_attribute *attr, + const char *buf, size_t size) +{ + struct timed_output_dev *tdev = dev_get_drvdata(dev); + int value; + + sscanf(buf, "%d", &value); + tdev->enable(tdev, value); + + return size; +} + +static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, enable_show, enable_store); + +static int create_timed_output_class(void) +{ + if (!timed_output_class) { + timed_output_class = class_create(THIS_MODULE, "timed_output"); + if (IS_ERR(timed_output_class)) + return PTR_ERR(timed_output_class); + atomic_set(&device_count, 0); + } + + return 0; +} + +int timed_output_dev_register(struct timed_output_dev *tdev) +{ + int ret; + + if (!tdev || !tdev->name || !tdev->enable || !tdev->get_time) + return -EINVAL; + + ret = create_timed_output_class(); + if (ret < 0) + return ret; + + tdev->index = atomic_inc_return(&device_count); + tdev->dev = device_create(timed_output_class, NULL, + MKDEV(0, tdev->index), NULL, tdev->name); + if (IS_ERR(tdev->dev)) + return PTR_ERR(tdev->dev); + + ret = device_create_file(tdev->dev, &dev_attr_enable); + if (ret < 0) + goto err_create_file; + + dev_set_drvdata(tdev->dev, tdev); + tdev->state = 0; + return 0; + +err_create_file: + device_destroy(timed_output_class, MKDEV(0, tdev->index)); + printk(KERN_ERR "timed_output: Failed to register driver %s\n", + tdev->name); + + return ret; +} +EXPORT_SYMBOL_GPL(timed_output_dev_register); + +void timed_output_dev_unregister(struct timed_output_dev *tdev) +{ + device_remove_file(tdev->dev, &dev_attr_enable); + device_destroy(timed_output_class, MKDEV(0, tdev->index)); + dev_set_drvdata(tdev->dev, NULL); +} +EXPORT_SYMBOL_GPL(timed_output_dev_unregister); + +static int __init timed_output_init(void) +{ + return create_timed_output_class(); +} + +static void __exit timed_output_exit(void) +{ + class_destroy(timed_output_class); +} + +module_init(timed_output_init); +module_exit(timed_output_exit); + +MODULE_AUTHOR("Mike Lockwood "); +MODULE_DESCRIPTION("timed output class driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/android/timed_output.h b/drivers/staging/android/timed_output.h new file mode 100644 index 000000000000..ec907ab2ff54 --- /dev/null +++ b/drivers/staging/android/timed_output.h @@ -0,0 +1,37 @@ +/* include/linux/timed_output.h + * + * Copyright (C) 2008 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * +*/ + +#ifndef _LINUX_TIMED_OUTPUT_H +#define _LINUX_TIMED_OUTPUT_H + +struct timed_output_dev { + const char *name; + + /* enable the output and set the timer */ + void (*enable)(struct timed_output_dev *sdev, int timeout); + + /* returns the current number of milliseconds remaining on the timer */ + int (*get_time)(struct timed_output_dev *sdev); + + /* private data */ + struct device *dev; + int index; + int state; +}; + +extern int timed_output_dev_register(struct timed_output_dev *dev); +extern void timed_output_dev_unregister(struct timed_output_dev *dev); + +#endif diff --git a/drivers/staging/asus_oled/asus_oled.c b/drivers/staging/asus_oled/asus_oled.c index 04dde4b82817..9270f5df0204 100644 --- a/drivers/staging/asus_oled/asus_oled.c +++ b/drivers/staging/asus_oled/asus_oled.c @@ -516,7 +516,7 @@ static ssize_t odev_set_picture(struct asus_oled_dev *odev, const char *buf, siz max_offs = odev->width * odev->height; while (offs < count && odev->buf_offs < max_offs) { - int ret; + int ret = 0; if (buf[offs] == '1' || buf[offs] == '#') { ret = append_values(odev, 1, 1); diff --git a/drivers/staging/at76_usb/at76_usb.c b/drivers/staging/at76_usb/at76_usb.c index c8af9a868d62..3f303ae97b43 100644 --- a/drivers/staging/at76_usb/at76_usb.c +++ b/drivers/staging/at76_usb/at76_usb.c @@ -3242,12 +3242,11 @@ static int at76_tx(struct sk_buff *skb, struct net_device *netdev) "%s: -EINVAL: tx urb %p hcpriv %p complete %p\n", priv->netdev->name, priv->tx_urb, priv->tx_urb->hcpriv, priv->tx_urb->complete); - } else { + } else stats->tx_bytes += skb->len; - dev_kfree_skb(skb); - } - return ret; + dev_kfree_skb(skb); + return NETDEV_TX_OK; } static void at76_tx_timeout(struct net_device *netdev) diff --git a/drivers/staging/b3dfg/b3dfg.c b/drivers/staging/b3dfg/b3dfg.c index 75ebe338c6f2..eec9c99ffaa0 100644 --- a/drivers/staging/b3dfg/b3dfg.c +++ b/drivers/staging/b3dfg/b3dfg.c @@ -35,14 +35,13 @@ #include #include #include -#include #include static unsigned int b3dfg_nbuf = 2; module_param_named(buffer_count, b3dfg_nbuf, uint, 0444); -MODULE_PARM_DESC(buffer_count, "Number of buffers (min 2, default 2)\n"); +MODULE_PARM_DESC(buffer_count, "Number of buffers (min 2, default 2)"); MODULE_AUTHOR("Daniel Drake "); MODULE_DESCRIPTION("Brontes frame grabber driver"); diff --git a/drivers/staging/comedi/Kconfig b/drivers/staging/comedi/Kconfig index 2d819d278b0e..af723cb9d08f 100644 --- a/drivers/staging/comedi/Kconfig +++ b/drivers/staging/comedi/Kconfig @@ -13,13 +13,6 @@ config COMEDI_DEBUG This is an option for use by developers; most people should say N here. This enables comedi core and driver debugging. -config COMEDI_RT - tristate "Comedi Real-time support" - depends on COMEDI && RT - default N - ---help--- - Enable Real time support for the Comedi core. - config COMEDI_PCI_DRIVERS tristate "Comedi PCI drivers" depends on COMEDI && PCI @@ -29,10 +22,10 @@ config COMEDI_PCI_DRIVERS config COMEDI_PCMCIA_DRIVERS tristate "Comedi PCMCIA drivers" - depends on COMEDI && PCMCIAI + depends on COMEDI && PCMCIA && PCCARD default N ---help--- - Enable lots of comedi PCMCIA drivers to be built + Enable lots of comedi PCMCIA and PCCARD drivers to be built config COMEDI_USB_DRIVERS tristate "Comedi USB drivers" diff --git a/drivers/staging/comedi/Makefile b/drivers/staging/comedi/Makefile index afd1a19c1b87..05811f79d85b 100644 --- a/drivers/staging/comedi/Makefile +++ b/drivers/staging/comedi/Makefile @@ -1,5 +1,4 @@ obj-$(CONFIG_COMEDI) += comedi.o -obj-$(CONFIG_COMEDI_RT) += comedi_rt.o obj-$(CONFIG_COMEDI) += kcomedilib/ obj-$(CONFIG_COMEDI) += drivers/ @@ -11,7 +10,3 @@ comedi-objs := \ drivers.o \ comedi_compat32.o \ comedi_ksyms.o \ - -comedi_rt-objs := \ - rt_pend_tq.o \ - rt.o diff --git a/drivers/staging/comedi/comedi.h b/drivers/staging/comedi/comedi.h index e6b5f16edb02..8101cea84528 100644 --- a/drivers/staging/comedi/comedi.h +++ b/drivers/staging/comedi/comedi.h @@ -188,7 +188,6 @@ extern "C" { #define SDF_WRITABLE 0x00020000 /* subdevice can be written (e.g. analog output) */ #define SDF_WRITEABLE SDF_WRITABLE /* spelling error in API */ #define SDF_INTERNAL 0x00040000 /* subdevice does not have externally visible lines */ -#define SDF_RT 0x00080000 /* DEPRECATED: subdevice is RT capable */ #define SDF_GROUND 0x00100000 /* can do aref=ground */ #define SDF_COMMON 0x00200000 /* can do aref=common */ #define SDF_DIFF 0x00400000 /* can do aref=diff */ diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index 19dce2ebfc19..9d7c99394ec6 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -44,6 +44,7 @@ #include #include "comedidev.h" #include +#include #include #include @@ -92,6 +93,15 @@ static int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s); static int comedi_fasync(int fd, struct file *file, int on); static int is_device_busy(struct comedi_device *dev); +static int resize_async_buffer(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_async *async, unsigned new_size); + +/* declarations for sysfs attribute files */ +static struct device_attribute dev_attr_max_read_buffer_kb; +static struct device_attribute dev_attr_read_buffer_kb; +static struct device_attribute dev_attr_max_write_buffer_kb; +static struct device_attribute dev_attr_write_buffer_kb; #ifdef HAVE_UNLOCKED_IOCTL static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd, @@ -277,7 +287,7 @@ static int do_bufconfig_ioctl(struct comedi_device *dev, void *arg) struct comedi_bufconfig bc; struct comedi_async *async; struct comedi_subdevice *s; - int ret = 0; + int retval = 0; if (copy_from_user(&bc, arg, sizeof(struct comedi_bufconfig))) return -EFAULT; @@ -303,37 +313,9 @@ static int do_bufconfig_ioctl(struct comedi_device *dev, void *arg) } if (bc.size) { - if (bc.size > async->max_bufsize) - return -EPERM; - - if (s->busy) { - DPRINTK("subdevice is busy, cannot resize buffer\n"); - return -EBUSY; - } - if (async->mmap_count) { - DPRINTK("subdevice is mmapped, cannot resize buffer\n"); - return -EBUSY; - } - - if (!async->prealloc_buf) - return -EINVAL; - - /* make sure buffer is an integral number of pages - * (we round up) */ - bc.size = (bc.size + PAGE_SIZE - 1) & PAGE_MASK; - - ret = comedi_buf_alloc(dev, s, bc.size); - if (ret < 0) - return ret; - - if (s->buf_change) { - ret = s->buf_change(dev, s, bc.size); - if (ret < 0) - return ret; - } - - DPRINTK("comedi%i subd %d buffer resized to %i bytes\n", - dev->minor, bc.subdevice, async->prealloc_bufsz); + retval = resize_async_buffer(dev, s, async, bc.size); + if (retval < 0) + return retval; } bc.size = async->prealloc_bufsz; @@ -746,7 +728,7 @@ static int check_insn_config_length(struct comedi_insn *insn, unsigned int *data /* by default we allow the insn since we don't have checks for * all possible cases yet */ default: - rt_printk("comedi: no check for data length of config insn id " + printk("comedi: no check for data length of config insn id " "%i is implemented.\n" " Add a check to %s in %s.\n" " Assuming n=%i is correct.\n", data[0], __func__, @@ -1097,13 +1079,6 @@ static int do_cmd_ioctl(struct comedi_device *dev, void *arg, void *file) comedi_set_subdevice_runflags(s, ~0, SRF_USER | SRF_RUNNING); -#ifdef CONFIG_COMEDI_RT - if (async->cmd.flags & TRIG_RT) { - if (comedi_switch_to_rt(dev) == 0) - comedi_set_subdevice_runflags(s, SRF_RT, SRF_RT); - } -#endif - ret = s->do_cmd(dev, s); if (ret == 0) return 0; @@ -1237,12 +1212,12 @@ static int do_lock_ioctl(struct comedi_device *dev, unsigned int arg, void *file return -EINVAL; s = dev->subdevices + arg; - comedi_spin_lock_irqsave(&s->spin_lock, flags); + spin_lock_irqsave(&s->spin_lock, flags); if (s->busy || s->lock) ret = -EBUSY; else s->lock = file; - comedi_spin_unlock_irqrestore(&s->spin_lock, flags); + spin_unlock_irqrestore(&s->spin_lock, flags); if (ret < 0) return ret; @@ -1738,12 +1713,6 @@ void do_become_nonbusy(struct comedi_device *dev, struct comedi_subdevice *s) struct comedi_async *async = s->async; comedi_set_subdevice_runflags(s, SRF_RUNNING, 0); -#ifdef CONFIG_COMEDI_RT - if (comedi_get_subdevice_runflags(s) & SRF_RT) { - comedi_switch_to_non_rt(dev); - comedi_set_subdevice_runflags(s, SRF_RT, 0); - } -#endif if (async) { comedi_reset_async_buf(async); async->inttrig = NULL; @@ -1970,8 +1939,6 @@ static int __init comedi_init(void) } } - comedi_rt_init(); - comedi_register_ioctl32(); return 0; @@ -1992,8 +1959,6 @@ static void __exit comedi_cleanup(void) comedi_proc_cleanup(); - comedi_rt_cleanup(); - comedi_unregister_ioctl32(); } @@ -2002,8 +1967,7 @@ module_exit(comedi_cleanup); void comedi_error(const struct comedi_device *dev, const char *s) { - rt_printk("comedi%d: %s: %s\n", dev->minor, dev->driver->driver_name, - s); + printk("comedi%d: %s: %s\n", dev->minor, dev->driver->driver_name, s); } void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s) @@ -2034,34 +1998,18 @@ void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s) if (async->cb_mask & s->async->events) { if (comedi_get_subdevice_runflags(s) & SRF_USER) { - - if (dev->rt) { -#ifdef CONFIG_COMEDI_RT - /* pend wake up */ - comedi_rt_pend_wakeup(&async->wait_head); -#else - printk - ("BUG: comedi_event() code unreachable\n"); -#endif - } else { - wake_up_interruptible(&async->wait_head); - if (s->subdev_flags & SDF_CMD_READ) { - kill_fasync(&dev->async_queue, SIGIO, - POLL_IN); - } - if (s->subdev_flags & SDF_CMD_WRITE) { - kill_fasync(&dev->async_queue, SIGIO, - POLL_OUT); - } + wake_up_interruptible(&async->wait_head); + if (s->subdev_flags & SDF_CMD_READ) { + kill_fasync(&dev->async_queue, SIGIO, + POLL_IN); + } + if (s->subdev_flags & SDF_CMD_WRITE) { + kill_fasync(&dev->async_queue, SIGIO, + POLL_OUT); } } else { if (async->cb_func) async->cb_func(s->async->events, async->cb_arg); - /* XXX bug here. If subdevice A is rt, and - * subdevice B tries to callback to a normal - * linux kernel function, it will be at the - * wrong priority. Since this isn't very - * common, I'm not going to worry about it. */ } } s->async->events = 0; @@ -2072,10 +2020,10 @@ void comedi_set_subdevice_runflags(struct comedi_subdevice *s, unsigned mask, { unsigned long flags; - comedi_spin_lock_irqsave(&s->spin_lock, flags); + spin_lock_irqsave(&s->spin_lock, flags); s->runflags &= ~mask; s->runflags |= (bits & mask); - comedi_spin_unlock_irqrestore(&s->spin_lock, flags); + spin_unlock_irqrestore(&s->spin_lock, flags); } unsigned comedi_get_subdevice_runflags(struct comedi_subdevice *s) @@ -2083,9 +2031,9 @@ unsigned comedi_get_subdevice_runflags(struct comedi_subdevice *s) unsigned long flags; unsigned runflags; - comedi_spin_lock_irqsave(&s->spin_lock, flags); + spin_lock_irqsave(&s->spin_lock, flags); runflags = s->runflags; - comedi_spin_unlock_irqrestore(&s->spin_lock, flags); + spin_unlock_irqrestore(&s->spin_lock, flags); return runflags; } @@ -2132,6 +2080,7 @@ int comedi_alloc_board_minor(struct device *hardware_device) struct comedi_device_file_info *info; struct device *csdev; unsigned i; + int retval; info = kzalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL); if (info == NULL) @@ -2142,20 +2091,19 @@ int comedi_alloc_board_minor(struct device *hardware_device) return -ENOMEM; } comedi_device_init(info->device); - comedi_spin_lock_irqsave(&comedi_file_info_table_lock, flags); + spin_lock_irqsave(&comedi_file_info_table_lock, flags); for (i = 0; i < COMEDI_NUM_BOARD_MINORS; ++i) { if (comedi_file_info_table[i] == NULL) { comedi_file_info_table[i] = info; break; } } - comedi_spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); + spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); if (i == COMEDI_NUM_BOARD_MINORS) { comedi_device_cleanup(info->device); kfree(info->device); kfree(info); - rt_printk - ("comedi: error: ran out of minor numbers for board device files.\n"); + printk(KERN_ERR "comedi: error: ran out of minor numbers for board device files.\n"); return -EBUSY; } info->device->minor = i; @@ -2164,7 +2112,35 @@ int comedi_alloc_board_minor(struct device *hardware_device) hardware_device, "comedi%i", i); if (!IS_ERR(csdev)) info->device->class_dev = csdev; - + dev_set_drvdata(csdev, info); + retval = device_create_file(csdev, &dev_attr_max_read_buffer_kb); + if (retval) { + printk(KERN_ERR "comedi: failed to create sysfs attribute file \"%s\".\n", + dev_attr_max_read_buffer_kb.attr.name); + comedi_free_board_minor(i); + return retval; + } + retval = device_create_file(csdev, &dev_attr_read_buffer_kb); + if (retval) { + printk(KERN_ERR "comedi: failed to create sysfs attribute file \"%s\".\n", + dev_attr_read_buffer_kb.attr.name); + comedi_free_board_minor(i); + return retval; + } + retval = device_create_file(csdev, &dev_attr_max_write_buffer_kb); + if (retval) { + printk(KERN_ERR "comedi: failed to create sysfs attribute file \"%s\".\n", + dev_attr_max_write_buffer_kb.attr.name); + comedi_free_board_minor(i); + return retval; + } + retval = device_create_file(csdev, &dev_attr_write_buffer_kb); + if (retval) { + printk(KERN_ERR "comedi: failed to create sysfs attribute file \"%s\".\n", + dev_attr_write_buffer_kb.attr.name); + comedi_free_board_minor(i); + return retval; + } return i; } @@ -2174,10 +2150,10 @@ void comedi_free_board_minor(unsigned minor) struct comedi_device_file_info *info; BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS); - comedi_spin_lock_irqsave(&comedi_file_info_table_lock, flags); + spin_lock_irqsave(&comedi_file_info_table_lock, flags); info = comedi_file_info_table[minor]; comedi_file_info_table[minor] = NULL; - comedi_spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); + spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); if (info) { struct comedi_device *dev = info->device; @@ -2193,12 +2169,14 @@ void comedi_free_board_minor(unsigned minor) } } -int comedi_alloc_subdevice_minor(struct comedi_device *dev, struct comedi_subdevice *s) +int comedi_alloc_subdevice_minor(struct comedi_device *dev, + struct comedi_subdevice *s) { unsigned long flags; struct comedi_device_file_info *info; struct device *csdev; unsigned i; + int retval; info = kmalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL); if (info == NULL) @@ -2206,18 +2184,17 @@ int comedi_alloc_subdevice_minor(struct comedi_device *dev, struct comedi_subdev info->device = dev; info->read_subdevice = s; info->write_subdevice = s; - comedi_spin_lock_irqsave(&comedi_file_info_table_lock, flags); + spin_lock_irqsave(&comedi_file_info_table_lock, flags); for (i = COMEDI_FIRST_SUBDEVICE_MINOR; i < COMEDI_NUM_MINORS; ++i) { if (comedi_file_info_table[i] == NULL) { comedi_file_info_table[i] = info; break; } } - comedi_spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); + spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); if (i == COMEDI_NUM_MINORS) { kfree(info); - rt_printk - ("comedi: error: ran out of minor numbers for board device files.\n"); + printk(KERN_ERR "comedi: error: ran out of minor numbers for board device files.\n"); return -EBUSY; } s->minor = i; @@ -2227,7 +2204,35 @@ int comedi_alloc_subdevice_minor(struct comedi_device *dev, struct comedi_subdev (int)(s - dev->subdevices)); if (!IS_ERR(csdev)) s->class_dev = csdev; - + dev_set_drvdata(csdev, info); + retval = device_create_file(csdev, &dev_attr_max_read_buffer_kb); + if (retval) { + printk(KERN_ERR "comedi: failed to create sysfs attribute file \"%s\".\n", + dev_attr_max_read_buffer_kb.attr.name); + comedi_free_subdevice_minor(s); + return retval; + } + retval = device_create_file(csdev, &dev_attr_read_buffer_kb); + if (retval) { + printk(KERN_ERR "comedi: failed to create sysfs attribute file \"%s\".\n", + dev_attr_read_buffer_kb.attr.name); + comedi_free_subdevice_minor(s); + return retval; + } + retval = device_create_file(csdev, &dev_attr_max_write_buffer_kb); + if (retval) { + printk(KERN_ERR "comedi: failed to create sysfs attribute file \"%s\".\n", + dev_attr_max_write_buffer_kb.attr.name); + comedi_free_subdevice_minor(s); + return retval; + } + retval = device_create_file(csdev, &dev_attr_write_buffer_kb); + if (retval) { + printk(KERN_ERR "comedi: failed to create sysfs attribute file \"%s\".\n", + dev_attr_write_buffer_kb.attr.name); + comedi_free_subdevice_minor(s); + return retval; + } return i; } @@ -2244,10 +2249,10 @@ void comedi_free_subdevice_minor(struct comedi_subdevice *s) BUG_ON(s->minor >= COMEDI_NUM_MINORS); BUG_ON(s->minor < COMEDI_FIRST_SUBDEVICE_MINOR); - comedi_spin_lock_irqsave(&comedi_file_info_table_lock, flags); + spin_lock_irqsave(&comedi_file_info_table_lock, flags); info = comedi_file_info_table[s->minor]; comedi_file_info_table[s->minor] = NULL; - comedi_spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); + spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); if (s->class_dev) { device_destroy(comedi_class, MKDEV(COMEDI_MAJOR, s->minor)); @@ -2262,8 +2267,309 @@ struct comedi_device_file_info *comedi_get_device_file_info(unsigned minor) struct comedi_device_file_info *info; BUG_ON(minor >= COMEDI_NUM_MINORS); - comedi_spin_lock_irqsave(&comedi_file_info_table_lock, flags); + spin_lock_irqsave(&comedi_file_info_table_lock, flags); info = comedi_file_info_table[minor]; - comedi_spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); + spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); return info; } + +static int resize_async_buffer(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_async *async, unsigned new_size) +{ + int retval; + + if (new_size > async->max_bufsize) + return -EPERM; + + if (s->busy) { + DPRINTK("subdevice is busy, cannot resize buffer\n"); + return -EBUSY; + } + if (async->mmap_count) { + DPRINTK("subdevice is mmapped, cannot resize buffer\n"); + return -EBUSY; + } + + if (!async->prealloc_buf) + return -EINVAL; + + /* make sure buffer is an integral number of pages + * (we round up) */ + new_size = (new_size + PAGE_SIZE - 1) & PAGE_MASK; + + retval = comedi_buf_alloc(dev, s, new_size); + if (retval < 0) + return retval; + + if (s->buf_change) { + retval = s->buf_change(dev, s, new_size); + if (retval < 0) + return retval; + } + + DPRINTK("comedi%i subd %d buffer resized to %i bytes\n", + dev->minor, s - dev->subdevices, async->prealloc_bufsz); + return 0; +} + +/* sysfs attribute files */ + +static const unsigned bytes_per_kibi = 1024; + +static ssize_t show_max_read_buffer_kb(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t retval; + struct comedi_device_file_info *info = dev_get_drvdata(dev); + unsigned max_buffer_size_kb = 0; + struct comedi_subdevice *const read_subdevice = + comedi_get_read_subdevice(info); + + mutex_lock(&info->device->mutex); + if (read_subdevice && + (read_subdevice->subdev_flags & SDF_CMD_READ) && + read_subdevice->async) { + max_buffer_size_kb = read_subdevice->async->max_bufsize / + bytes_per_kibi; + } + retval = snprintf(buf, PAGE_SIZE, "%i\n", max_buffer_size_kb); + mutex_unlock(&info->device->mutex); + + return retval; +} + +static ssize_t store_max_read_buffer_kb(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct comedi_device_file_info *info = dev_get_drvdata(dev); + unsigned long new_max_size_kb; + uint64_t new_max_size; + struct comedi_subdevice *const read_subdevice = + comedi_get_read_subdevice(info); + + if (strict_strtoul(buf, 10, &new_max_size_kb)) + return -EINVAL; + if (new_max_size_kb != (uint32_t)new_max_size_kb) + return -EINVAL; + new_max_size = ((uint64_t)new_max_size_kb) * bytes_per_kibi; + if (new_max_size != (uint32_t)new_max_size) + return -EINVAL; + + mutex_lock(&info->device->mutex); + if (read_subdevice == NULL || + (read_subdevice->subdev_flags & SDF_CMD_READ) == 0 || + read_subdevice->async == NULL) { + mutex_unlock(&info->device->mutex); + return -EINVAL; + } + read_subdevice->async->max_bufsize = new_max_size; + mutex_unlock(&info->device->mutex); + + return count; +} + +static struct device_attribute dev_attr_max_read_buffer_kb = { + .attr = { + .name = "max_read_buffer_kb", + .mode = S_IRUGO | S_IWUSR + }, + .show = &show_max_read_buffer_kb, + .store = &store_max_read_buffer_kb +}; + +static ssize_t show_read_buffer_kb(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t retval; + struct comedi_device_file_info *info = dev_get_drvdata(dev); + unsigned buffer_size_kb = 0; + struct comedi_subdevice *const read_subdevice = + comedi_get_read_subdevice(info); + + mutex_lock(&info->device->mutex); + if (read_subdevice && + (read_subdevice->subdev_flags & SDF_CMD_READ) && + read_subdevice->async) { + buffer_size_kb = read_subdevice->async->prealloc_bufsz / + bytes_per_kibi; + } + retval = snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb); + mutex_unlock(&info->device->mutex); + + return retval; +} + +static ssize_t store_read_buffer_kb(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct comedi_device_file_info *info = dev_get_drvdata(dev); + unsigned long new_size_kb; + uint64_t new_size; + int retval; + struct comedi_subdevice *const read_subdevice = + comedi_get_read_subdevice(info); + + if (strict_strtoul(buf, 10, &new_size_kb)) + return -EINVAL; + if (new_size_kb != (uint32_t)new_size_kb) + return -EINVAL; + new_size = ((uint64_t)new_size_kb) * bytes_per_kibi; + if (new_size != (uint32_t)new_size) + return -EINVAL; + + mutex_lock(&info->device->mutex); + if (read_subdevice == NULL || + (read_subdevice->subdev_flags & SDF_CMD_READ) == 0 || + read_subdevice->async == NULL) { + mutex_unlock(&info->device->mutex); + return -EINVAL; + } + retval = resize_async_buffer(info->device, read_subdevice, + read_subdevice->async, new_size); + mutex_unlock(&info->device->mutex); + + if (retval < 0) + return retval; + return count; +} + +static struct device_attribute dev_attr_read_buffer_kb = { + .attr = { + .name = "read_buffer_kb", + .mode = S_IRUGO | S_IWUSR | S_IWGRP + }, + .show = &show_read_buffer_kb, + .store = &store_read_buffer_kb +}; + +static ssize_t show_max_write_buffer_kb(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + ssize_t retval; + struct comedi_device_file_info *info = dev_get_drvdata(dev); + unsigned max_buffer_size_kb = 0; + struct comedi_subdevice *const write_subdevice = + comedi_get_write_subdevice(info); + + mutex_lock(&info->device->mutex); + if (write_subdevice && + (write_subdevice->subdev_flags & SDF_CMD_WRITE) && + write_subdevice->async) { + max_buffer_size_kb = write_subdevice->async->max_bufsize / + bytes_per_kibi; + } + retval = snprintf(buf, PAGE_SIZE, "%i\n", max_buffer_size_kb); + mutex_unlock(&info->device->mutex); + + return retval; +} + +static ssize_t store_max_write_buffer_kb(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct comedi_device_file_info *info = dev_get_drvdata(dev); + unsigned long new_max_size_kb; + uint64_t new_max_size; + struct comedi_subdevice *const write_subdevice = + comedi_get_write_subdevice(info); + + if (strict_strtoul(buf, 10, &new_max_size_kb)) + return -EINVAL; + if (new_max_size_kb != (uint32_t)new_max_size_kb) + return -EINVAL; + new_max_size = ((uint64_t)new_max_size_kb) * bytes_per_kibi; + if (new_max_size != (uint32_t)new_max_size) + return -EINVAL; + + mutex_lock(&info->device->mutex); + if (write_subdevice == NULL || + (write_subdevice->subdev_flags & SDF_CMD_WRITE) == 0 || + write_subdevice->async == NULL) { + mutex_unlock(&info->device->mutex); + return -EINVAL; + } + write_subdevice->async->max_bufsize = new_max_size; + mutex_unlock(&info->device->mutex); + + return count; +} + +static struct device_attribute dev_attr_max_write_buffer_kb = { + .attr = { + .name = "max_write_buffer_kb", + .mode = S_IRUGO | S_IWUSR + }, + .show = &show_max_write_buffer_kb, + .store = &store_max_write_buffer_kb +}; + +static ssize_t show_write_buffer_kb(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t retval; + struct comedi_device_file_info *info = dev_get_drvdata(dev); + unsigned buffer_size_kb = 0; + struct comedi_subdevice *const write_subdevice = + comedi_get_write_subdevice(info); + + mutex_lock(&info->device->mutex); + if (write_subdevice && + (write_subdevice->subdev_flags & SDF_CMD_WRITE) && + write_subdevice->async) { + buffer_size_kb = write_subdevice->async->prealloc_bufsz / + bytes_per_kibi; + } + retval = snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb); + mutex_unlock(&info->device->mutex); + + return retval; +} + +static ssize_t store_write_buffer_kb(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct comedi_device_file_info *info = dev_get_drvdata(dev); + unsigned long new_size_kb; + uint64_t new_size; + int retval; + struct comedi_subdevice *const write_subdevice = + comedi_get_write_subdevice(info); + + if (strict_strtoul(buf, 10, &new_size_kb)) + return -EINVAL; + if (new_size_kb != (uint32_t)new_size_kb) + return -EINVAL; + new_size = ((uint64_t)new_size_kb) * bytes_per_kibi; + if (new_size != (uint32_t)new_size) + return -EINVAL; + + mutex_lock(&info->device->mutex); + if (write_subdevice == NULL || + (write_subdevice->subdev_flags & SDF_CMD_WRITE) == 0 || + write_subdevice->async == NULL) { + mutex_unlock(&info->device->mutex); + return -EINVAL; + } + retval = resize_async_buffer(info->device, write_subdevice, + write_subdevice->async, new_size); + mutex_unlock(&info->device->mutex); + + if (retval < 0) + return retval; + return count; +} + +static struct device_attribute dev_attr_write_buffer_kb = { + .attr = { + .name = "write_buffer_kb", + .mode = S_IRUGO | S_IWUSR | S_IWGRP + }, + .show = &show_write_buffer_kb, + .store = &store_write_buffer_kb +}; diff --git a/drivers/staging/comedi/comedi_ksyms.c b/drivers/staging/comedi/comedi_ksyms.c index 6e6fb979ef54..a732e342dcd2 100644 --- a/drivers/staging/comedi/comedi_ksyms.c +++ b/drivers/staging/comedi/comedi_ksyms.c @@ -46,13 +46,6 @@ EXPORT_SYMBOL(range_bipolar2_5); EXPORT_SYMBOL(range_unipolar10); EXPORT_SYMBOL(range_unipolar5); EXPORT_SYMBOL(range_unknown); -#ifdef CONFIG_COMEDI_RT -EXPORT_SYMBOL(comedi_free_irq); -EXPORT_SYMBOL(comedi_request_irq); -EXPORT_SYMBOL(comedi_switch_to_rt); -EXPORT_SYMBOL(comedi_switch_to_non_rt); -EXPORT_SYMBOL(rt_pend_call); -#endif #ifdef CONFIG_COMEDI_DEBUG EXPORT_SYMBOL(comedi_debug); #endif diff --git a/drivers/staging/comedi/comedi_rt.h b/drivers/staging/comedi/comedi_rt.h deleted file mode 100644 index 169ca963312a..000000000000 --- a/drivers/staging/comedi/comedi_rt.h +++ /dev/null @@ -1,149 +0,0 @@ -/* - module/comedi_rt.h - header file for real-time structures, variables, and constants - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 1997-2000 David A. Schleef - - 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 _COMEDI_RT_H -#define _COMEDI_RT_H - -#ifndef _COMEDIDEV_H -#error comedi_rt.h should only be included by comedidev.h -#endif - -#include -#include -#include -#include -#include - -#ifdef CONFIG_COMEDI_RT - -#ifdef CONFIG_COMEDI_RTAI -#include -#include -#include -#endif -#ifdef CONFIG_COMEDI_RTL -#include -#include -/* #ifdef RTLINUX_VERSION_CODE */ -#include -/* #endif */ -#define rt_printk rtl_printf -#endif -#ifdef CONFIG_COMEDI_FUSION -#define rt_printk(format, args...) printk(format , ## args) -#endif /* CONFIG_COMEDI_FUSION */ -#ifdef CONFIG_PRIORITY_IRQ -#define rt_printk printk -#endif - -int comedi_request_irq(unsigned int irq, irqreturn_t(*handler) (int, - void *PT_REGS_ARG), unsigned long flags, const char *device, - struct comedi_device *dev_id); -void comedi_free_irq(unsigned int irq, struct comedi_device *dev_id); -void comedi_rt_init(void); -void comedi_rt_cleanup(void); -int comedi_switch_to_rt(struct comedi_device *dev); -void comedi_switch_to_non_rt(struct comedi_device *dev); -void comedi_rt_pend_wakeup(wait_queue_head_t *q); -extern int rt_pend_call(void (*func) (int arg1, void *arg2), int arg1, - void *arg2); - -#else - -#define comedi_request_irq(a, b, c, d, e) request_irq(a, b, c, d, e) -#define comedi_free_irq(a, b) free_irq(a, b) -#define comedi_rt_init() do {} while (0) -#define comedi_rt_cleanup() do {} while (0) -#define comedi_switch_to_rt(a) (-1) -#define comedi_switch_to_non_rt(a) do {} while (0) -#define comedi_rt_pend_wakeup(a) do {} while (0) - -#define rt_printk(format, args...) printk(format, ##args) - -#endif - -/* Define a spin_lock_irqsave function that will work with rt or without. - * Use inline functions instead of just macros to enforce some type checking. - */ -#define comedi_spin_lock_irqsave(lock_ptr, flags) \ - (flags = __comedi_spin_lock_irqsave(lock_ptr)) - -static inline unsigned long __comedi_spin_lock_irqsave(spinlock_t *lock_ptr) -{ - unsigned long flags; - -#if defined(CONFIG_COMEDI_RTAI) - flags = rt_spin_lock_irqsave(lock_ptr); - -#elif defined(CONFIG_COMEDI_RTL) - rtl_spin_lock_irqsave(lock_ptr, flags); - -#elif defined(CONFIG_COMEDI_RTL_V1) - rtl_spin_lock_irqsave(lock_ptr, flags); - -#elif defined(CONFIG_COMEDI_FUSION) - rthal_spin_lock_irqsave(lock_ptr, flags); -#else - spin_lock_irqsave(lock_ptr, flags); - -#endif - - return flags; -} - -static inline void comedi_spin_unlock_irqrestore(spinlock_t *lock_ptr, - unsigned long flags) -{ - -#if defined(CONFIG_COMEDI_RTAI) - rt_spin_unlock_irqrestore(flags, lock_ptr); - -#elif defined(CONFIG_COMEDI_RTL) - rtl_spin_unlock_irqrestore(lock_ptr, flags); - -#elif defined(CONFIG_COMEDI_RTL_V1) - rtl_spin_unlock_irqrestore(lock_ptr, flags); -#elif defined(CONFIG_COMEDI_FUSION) - rthal_spin_unlock_irqrestore(lock_ptr, flags); -#else - spin_unlock_irqrestore(lock_ptr, flags); - -#endif - -} - -/* define a RT safe udelay */ -static inline void comedi_udelay(unsigned int usec) -{ -#if defined(CONFIG_COMEDI_RTAI) - static const int nanosec_per_usec = 1000; - rt_busy_sleep(usec * nanosec_per_usec); -#elif defined(CONFIG_COMEDI_RTL) - static const int nanosec_per_usec = 1000; - rtl_delay(usec * nanosec_per_usec); -#else - udelay(usec); -#endif -} - -#endif diff --git a/drivers/staging/comedi/comedidev.h b/drivers/staging/comedi/comedidev.h index ea319360ae68..89af44a788df 100644 --- a/drivers/staging/comedi/comedidev.h +++ b/drivers/staging/comedi/comedidev.h @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -35,10 +36,10 @@ #include #include #include -#include "interrupt.h" #include #include #include +#include #include "comedi.h" @@ -264,7 +265,6 @@ struct comedi_device { const char *board_name; const void *board_ptr; int attached; - int rt; spinlock_t spinlock; struct mutex mutex; int in_request_module; @@ -524,6 +524,17 @@ struct usb_device; /* forward declaration */ int comedi_usb_auto_config(struct usb_device *usbdev, const char *board_name); void comedi_usb_auto_unconfig(struct usb_device *usbdev); -#include "comedi_rt.h" +#ifdef CONFIG_COMEDI_PCI_DRIVERS + #define CONFIG_COMEDI_PCI +#endif +#ifdef CONFIG_COMEDI_PCI_DRIVERS_MODULE + #define CONFIG_COMEDI_PCI +#endif +#ifdef CONFIG_COMEDI_PCMCIA_DRIVERS + #define CONFIG_COMEDI_PCMCIA +#endif +#ifdef CONFIG_COMEDI_PCMCIA_DRIVERS_MODULE + #define CONFIG_COMEDI_PCMCIA +#endif #endif /* _COMEDIDEV_H */ diff --git a/drivers/staging/comedi/drivers.c b/drivers/staging/comedi/drivers.c index 6e13e450dc73..42a02571ff1b 100644 --- a/drivers/staging/comedi/drivers.c +++ b/drivers/staging/comedi/drivers.c @@ -198,7 +198,7 @@ int comedi_driver_unregister(struct comedi_driver *driver) struct comedi_device_file_info *dev_file_info = comedi_get_device_file_info(i); struct comedi_device *dev; - if(dev_file_info == NULL) continue; + if (dev_file_info == NULL) continue; dev = dev_file_info->device; mutex_lock(&dev->mutex); @@ -554,7 +554,7 @@ unsigned int comedi_buf_munge(struct comedi_async *async, unsigned int num_bytes block_size = num_bytes - count; if (block_size < 0) { - rt_printk("%s: %s: bug! block_size is negative\n", + printk("%s: %s: bug! block_size is negative\n", __FILE__, __func__); break; } @@ -633,8 +633,7 @@ unsigned comedi_buf_write_free(struct comedi_async *async, unsigned int nbytes) { if ((int)(async->buf_write_count + nbytes - async->buf_write_alloc_count) > 0) { - rt_printk - ("comedi: attempted to write-free more bytes than have been write-allocated.\n"); + printk("comedi: attempted to write-free more bytes than have been write-allocated.\n"); nbytes = async->buf_write_alloc_count - async->buf_write_count; } async->buf_write_count += nbytes; @@ -667,8 +666,7 @@ unsigned comedi_buf_read_free(struct comedi_async *async, unsigned int nbytes) smp_mb(); if ((int)(async->buf_read_count + nbytes - async->buf_read_alloc_count) > 0) { - rt_printk - ("comedi: attempted to read-free more bytes than have been read-allocated.\n"); + printk("comedi: attempted to read-free more bytes than have been read-allocated.\n"); nbytes = async->buf_read_alloc_count - async->buf_read_count; } async->buf_read_count += nbytes; @@ -801,7 +799,7 @@ int comedi_auto_config(struct device *hardware_device, const char *board_name, c } minor = comedi_alloc_board_minor(hardware_device); - if(minor < 0) return minor; + if (minor < 0) return minor; private_data = kmalloc(sizeof(unsigned), GFP_KERNEL); if (private_data == NULL) { @@ -824,7 +822,7 @@ int comedi_auto_config(struct device *hardware_device, const char *board_name, c mutex_unlock(&dev_file_info->device->mutex); cleanup: - if(retval < 0) + if (retval < 0) { kfree(private_data); comedi_free_board_minor(minor); @@ -835,7 +833,7 @@ cleanup: void comedi_auto_unconfig(struct device *hardware_device) { unsigned *minor = (unsigned *)dev_get_drvdata(hardware_device); - if(minor == NULL) return; + if (minor == NULL) return; BUG_ON(*minor >= COMEDI_NUM_BOARD_MINORS); @@ -853,7 +851,8 @@ int comedi_pci_auto_config(struct pci_dev *pcidev, const char *board_name) /* pci slot */ options[1] = PCI_SLOT(pcidev->devfn); - return comedi_auto_config(&pcidev->dev, board_name, options, sizeof(options) / sizeof(options[0])); + return comedi_auto_config(&pcidev->dev, board_name, + options, ARRAY_SIZE(options)); } void comedi_pci_auto_unconfig(struct pci_dev *pcidev) diff --git a/drivers/staging/comedi/drivers/8253.h b/drivers/staging/comedi/drivers/8253.h index 08a11a5a16e6..ad467ac290a3 100644 --- a/drivers/staging/comedi/drivers/8253.h +++ b/drivers/staging/comedi/drivers/8253.h @@ -24,11 +24,7 @@ #ifndef _8253_H #define _8253_H -#ifndef CMDTEST #include "../comedi.h" -#else -#include "../comedi.h" -#endif #define i8253_cascade_ns_to_timer i8253_cascade_ns_to_timer_2div @@ -205,7 +201,7 @@ static inline void i8253_cascade_ns_to_timer_2div(int i8253_osc_base, } *nanosec = div1 * div2 * i8253_osc_base; - *d1 = div1 & 0xffff; // masking is done since counter maps zero to 0x10000 + *d1 = div1 & 0xffff; /* masking is done since counter maps zero to 0x10000 */ *d2 = div2 & 0xffff; return; } @@ -247,12 +243,12 @@ static inline int i8254_load(unsigned long base_address, unsigned int regshift, return -1; byte = counter_number << 6; - byte |= 0x30; // load low then high byte - byte |= (mode << 1); // set counter mode + byte |= 0x30; /* load low then high byte */ + byte |= (mode << 1); /* set counter mode */ outb(byte, base_address + (i8254_control_reg << regshift)); - byte = count & 0xff; // lsb of counter value + byte = count & 0xff; /* lsb of counter value */ outb(byte, base_address + (counter_number << regshift)); - byte = (count >> 8) & 0xff; // msb of counter value + byte = (count >> 8) & 0xff; /* msb of counter value */ outb(byte, base_address + (counter_number << regshift)); return 0; @@ -273,12 +269,12 @@ static inline int i8254_mm_load(void *base_address, unsigned int regshift, return -1; byte = counter_number << 6; - byte |= 0x30; // load low then high byte - byte |= (mode << 1); // set counter mode + byte |= 0x30; /* load low then high byte */ + byte |= (mode << 1); /* set counter mode */ writeb(byte, base_address + (i8254_control_reg << regshift)); - byte = count & 0xff; // lsb of counter value + byte = count & 0xff; /* lsb of counter value */ writeb(byte, base_address + (counter_number << regshift)); - byte = (count >> 8) & 0xff; // msb of counter value + byte = (count >> 8) & 0xff; /* msb of counter value */ writeb(byte, base_address + (counter_number << regshift)); return 0; @@ -294,13 +290,13 @@ static inline int i8254_read(unsigned long base_address, unsigned int regshift, if (counter_number > 2) return -1; - // latch counter + /* latch counter */ byte = counter_number << 6; outb(byte, base_address + (i8254_control_reg << regshift)); - // read lsb + /* read lsb */ ret = inb(base_address + (counter_number << regshift)); - // read msb + /* read msb */ ret += inb(base_address + (counter_number << regshift)) << 8; return ret; @@ -315,13 +311,13 @@ static inline int i8254_mm_read(void *base_address, unsigned int regshift, if (counter_number > 2) return -1; - // latch counter + /* latch counter */ byte = counter_number << 6; writeb(byte, base_address + (i8254_control_reg << regshift)); - // read lsb + /* read lsb */ ret = readb(base_address + (counter_number << regshift)); - // read msb + /* read msb */ ret += readb(base_address + (counter_number << regshift)) << 8; return ret; @@ -336,9 +332,9 @@ static inline void i8254_write(unsigned long base_address, if (counter_number > 2) return; - byte = count & 0xff; // lsb of counter value + byte = count & 0xff; /* lsb of counter value */ outb(byte, base_address + (counter_number << regshift)); - byte = (count >> 8) & 0xff; // msb of counter value + byte = (count >> 8) & 0xff; /* msb of counter value */ outb(byte, base_address + (counter_number << regshift)); } @@ -350,9 +346,9 @@ static inline void i8254_mm_write(void *base_address, if (counter_number > 2) return; - byte = count & 0xff; // lsb of counter value + byte = count & 0xff; /* lsb of counter value */ writeb(byte, base_address + (counter_number << regshift)); - byte = (count >> 8) & 0xff; // msb of counter value + byte = (count >> 8) & 0xff; /* msb of counter value */ writeb(byte, base_address + (counter_number << regshift)); } @@ -374,8 +370,8 @@ static inline int i8254_set_mode(unsigned long base_address, return -1; byte = counter_number << 6; - byte |= 0x30; // load low then high byte - byte |= mode; // set counter mode and BCD|binary + byte |= 0x30; /* load low then high byte */ + byte |= mode; /* set counter mode and BCD|binary */ outb(byte, base_address + (i8254_control_reg << regshift)); return 0; @@ -392,8 +388,8 @@ static inline int i8254_mm_set_mode(void *base_address, return -1; byte = counter_number << 6; - byte |= 0x30; // load low then high byte - byte |= mode; // set counter mode and BCD|binary + byte |= 0x30; /* load low then high byte */ + byte |= mode; /* set counter mode and BCD|binary */ writeb(byte, base_address + (i8254_control_reg << regshift)); return 0; diff --git a/drivers/staging/comedi/drivers/8255.c b/drivers/staging/comedi/drivers/8255.c index 0369c7c84ac5..bdc3957bceb8 100644 --- a/drivers/staging/comedi/drivers/8255.c +++ b/drivers/staging/comedi/drivers/8255.c @@ -108,10 +108,10 @@ struct subdev_8255_struct { static int dev_8255_attach(struct comedi_device *dev, struct comedi_devconfig * it); static int dev_8255_detach(struct comedi_device *dev); static struct comedi_driver driver_8255 = { - driver_name:"8255", - module:THIS_MODULE, - attach:dev_8255_attach, - detach:dev_8255_detach, + .driver_name = "8255", + .module = THIS_MODULE, + .attach = dev_8255_attach, + .detach = dev_8255_detach, }; COMEDI_INITCLEANUP(driver_8255); @@ -144,7 +144,7 @@ static int subdev_8255_cb(int dir, int port, int data, unsigned long arg) } static int subdev_8255_insn(struct comedi_device *dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) + struct comedi_insn *insn, unsigned int *data) { if (data[0]) { s->state &= ~data[0]; @@ -169,7 +169,7 @@ static int subdev_8255_insn(struct comedi_device *dev, struct comedi_subdevice * } static int subdev_8255_insn_config(struct comedi_device *dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) + struct comedi_insn *insn, unsigned int *data) { unsigned int mask; unsigned int bits; @@ -223,7 +223,7 @@ static void do_config(struct comedi_device *dev, struct comedi_subdevice * s) } static int subdev_8255_cmdtest(struct comedi_device *dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd) + struct comedi_cmd *cmd) { int err = 0; unsigned int tmp; @@ -361,8 +361,10 @@ int subdev_8255_init_irq(struct comedi_device *dev, struct comedi_subdevice * s, void subdev_8255_cleanup(struct comedi_device *dev, struct comedi_subdevice * s) { if (s->private) { - if (subdevpriv->have_irq) { - } + /* this test does nothing, so comment it out + * if (subdevpriv->have_irq) { + * } + */ kfree(s->private); } @@ -394,7 +396,8 @@ static int dev_8255_attach(struct comedi_device *dev, struct comedi_devconfig * return -EINVAL; } - if ((ret = alloc_subdevices(dev, i)) < 0) + ret = alloc_subdevices(dev, i); + if (ret < 0) return ret; for (i = 0; i < dev->n_subdevices; i++) { diff --git a/drivers/staging/comedi/drivers/8255.h b/drivers/staging/comedi/drivers/8255.h index 979311b99275..5457c6b2d22e 100644 --- a/drivers/staging/comedi/drivers/8255.h +++ b/drivers/staging/comedi/drivers/8255.h @@ -28,16 +28,16 @@ #if defined(CONFIG_COMEDI_8255) || defined(CONFIG_COMEDI_8255_MODULE) -int subdev_8255_init(struct comedi_device * dev, struct comedi_subdevice * s, +int subdev_8255_init(struct comedi_device *dev, struct comedi_subdevice *s, int (*cb) (int, int, int, unsigned long), unsigned long arg); -int subdev_8255_init_irq(struct comedi_device * dev, struct comedi_subdevice * s, +int subdev_8255_init_irq(struct comedi_device *dev, struct comedi_subdevice *s, int (*cb) (int, int, int, unsigned long), unsigned long arg); -void subdev_8255_cleanup(struct comedi_device * dev, struct comedi_subdevice * s); -void subdev_8255_interrupt(struct comedi_device * dev, struct comedi_subdevice * s); +void subdev_8255_cleanup(struct comedi_device *dev, struct comedi_subdevice *s); +void subdev_8255_interrupt(struct comedi_device *dev, struct comedi_subdevice *s); #else -static inline int subdev_8255_init(struct comedi_device * dev, struct comedi_subdevice * s, +static inline int subdev_8255_init(struct comedi_device *dev, struct comedi_subdevice *s, void *x, unsigned long y) { printk("8255 support not configured -- disabling subdevice\n"); @@ -47,8 +47,8 @@ static inline int subdev_8255_init(struct comedi_device * dev, struct comedi_sub return 0; } -static inline void subdev_8255_cleanup(struct comedi_device * dev, - struct comedi_subdevice * s) +static inline void subdev_8255_cleanup(struct comedi_device *dev, + struct comedi_subdevice *s) { } diff --git a/drivers/staging/comedi/drivers/Makefile b/drivers/staging/comedi/drivers/Makefile index 12d6e4312f3a..df2854d543cc 100644 --- a/drivers/staging/comedi/drivers/Makefile +++ b/drivers/staging/comedi/drivers/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_COMEDI) += comedi_fc.o obj-$(CONFIG_COMEDI) += comedi_bond.o obj-$(CONFIG_COMEDI) += comedi_test.o obj-$(CONFIG_COMEDI) += comedi_parport.o +obj-$(CONFIG_COMEDI) += pcm_common.o # Comedi PCI drivers obj-$(CONFIG_COMEDI_PCI_DRIVERS) += 8255.o @@ -125,6 +126,8 @@ obj-$(CONFIG_COMEDI_PCMCIA_DRIVERS) += ni_mio_cs.o obj-$(CONFIG_COMEDI_PCMCIA_DRIVERS) += quatech_daqp_cs.o # Comedi USB drivers +obj-$(CONFIG_COMEDI_USB_DRIVERS) += dt9812.o obj-$(CONFIG_COMEDI_USB_DRIVERS) += usbdux.o obj-$(CONFIG_COMEDI_USB_DRIVERS) += usbduxfast.o -obj-$(CONFIG_COMEDI_USB_DRIVERS) += dt9812.o +obj-$(CONFIG_COMEDI_USB_DRIVERS) += vmk80xx.o + diff --git a/drivers/staging/comedi/drivers/acl7225b.c b/drivers/staging/comedi/drivers/acl7225b.c index b21320f0959f..5b986aa7398b 100644 --- a/drivers/staging/comedi/drivers/acl7225b.c +++ b/drivers/staging/comedi/drivers/acl7225b.c @@ -26,8 +26,8 @@ static int acl7225b_attach(struct comedi_device *dev, struct comedi_devconfig * static int acl7225b_detach(struct comedi_device *dev); struct boardtype { - const char *name; // driver name - int io_range; // len of I/O space + const char *name; /* driver name */ + int io_range; /* len of I/O space */ }; static const struct boardtype boardtypes[] = { @@ -39,19 +39,19 @@ static const struct boardtype boardtypes[] = { #define this_board ((const struct boardtype *)dev->board_ptr) static struct comedi_driver driver_acl7225b = { - driver_name:"acl7225b", - module:THIS_MODULE, - attach:acl7225b_attach, - detach:acl7225b_detach, - board_name:&boardtypes[0].name, - num_names:n_boardtypes, - offset:sizeof(struct boardtype), + .driver_name = "acl7225b", + .module = THIS_MODULE, + .attach = acl7225b_attach, + .detach = acl7225b_detach, + .board_name = &boardtypes[0].name, + .num_names = n_boardtypes, + .offset = sizeof(struct boardtype), }; COMEDI_INITCLEANUP(driver_acl7225b); static int acl7225b_do_insn(struct comedi_device *dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) + struct comedi_insn *insn, unsigned int *data) { if (insn->n != 2) return -EINVAL; @@ -72,7 +72,7 @@ static int acl7225b_do_insn(struct comedi_device *dev, struct comedi_subdevice * } static int acl7225b_di_insn(struct comedi_device *dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) + struct comedi_insn *insn, unsigned int *data) { if (insn->n != 2) return -EINVAL; diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_82x54.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_82x54.c index c96aee09e1b6..60213d292a5f 100644 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_82x54.c +++ b/drivers/staging/comedi/drivers/addi-data/APCI1710_82x54.c @@ -23,16 +23,16 @@ /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_InitTimer | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr, | -| BYTE_ b_TimerNbr, | -| BYTE_ b_TimerMode, | +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr, | +| unsigned char_ b_TimerNbr, | +| unsigned char_ b_TimerMode, | | ULONG_ ul_ReloadValue, | -| BYTE_ b_InputClockSelection, | -| BYTE_ b_InputClockLevel, | -| BYTE_ b_OutputLevel, | -| BYTE_ b_HardwareGateLevel) -INT i_InsnConfig_InitTimer(struct comedi_device *dev,struct comedi_subdevice *s, +| unsigned char_ b_InputClockSelection, | +| unsigned char_ b_InputClockLevel, | +| unsigned char_ b_OutputLevel, | +| unsigned char_ b_HardwareGateLevel) +int i_InsnConfig_InitTimer(struct comedi_device *dev,struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data) | +----------------------------------------------------------------------------+ @@ -148,13 +148,13 @@ INT i_InsnConfig_InitTimer(struct comedi_device *dev,struct comedi_subdevice *s, | +--------------------------------+------------------------------------+ | | | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board | | APCI-1710 | -| BYTE_ b_ModulNbr : Module number to | +| unsigned char_ b_ModulNbr : Module number to | | configure (0 to 3) | -| BYTE_ b_TimerNbr : Timer number to | +| unsigned char_ b_TimerNbr : Timer number to | | configure (0 to 2) | -| BYTE_ b_TimerMode : Timer mode selection | +| unsigned char_ b_TimerMode : Timer mode selection | | (0 to 5) | | 0: Interrupt on terminal| | count | @@ -173,21 +173,21 @@ INT i_InsnConfig_InitTimer(struct comedi_device *dev,struct comedi_subdevice *s, | or division factor | | See timer mode | | description table. | -| BYTE_ b_InputClockSelection : Selection from input | +| unsigned char_ b_InputClockSelection : Selection from input | | timer clock. | | See input clock | | selection table. | -| BYTE_ b_InputClockLevel : Selection from input | +| unsigned char_ b_InputClockLevel : Selection from input | | clock level. | | 0 : Low active | | (Input inverted) | | 1 : High active | -| BYTE_ b_OutputLevel, : Selection from output | +| unsigned char_ b_OutputLevel, : Selection from output | | clock level. | | 0 : Low active | | 1 : High active | | (Output inverted) | -| BYTE_ b_HardwareGateLevel : Selection from | +| unsigned char_ b_HardwareGateLevel : Selection from | | hardware gate level. | | 0 : Low active | | (Input inverted) | @@ -195,14 +195,14 @@ INT i_InsnConfig_InitTimer(struct comedi_device *dev,struct comedi_subdevice *s, | If you will not used | | the hardware gate set | | this value to 0. -|b_ModulNbr = (BYTE) CR_AREF(insn->chanspec); - b_TimerNbr = (BYTE) CR_CHAN(insn->chanspec); - b_TimerMode = (BYTE) data[0]; - ul_ReloadValue = (ULONG) data[1]; - b_InputClockSelection =(BYTE) data[2]; - b_InputClockLevel =(BYTE) data[3]; - b_OutputLevel =(BYTE) data[4]; - b_HardwareGateLevel =(BYTE) data[5]; +|b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); + b_TimerNbr = (unsigned char) CR_CHAN(insn->chanspec); + b_TimerMode = (unsigned char) data[0]; + ul_ReloadValue = (unsigned int) data[1]; + b_InputClockSelection =(unsigned char) data[2]; + b_InputClockLevel =(unsigned char) data[3]; + b_OutputLevel =(unsigned char) data[4]; + b_HardwareGateLevel =(unsigned char) data[5]; +----------------------------------------------------------------------------+ | Output Parameters : - | +----------------------------------------------------------------------------+ @@ -219,33 +219,33 @@ INT i_InsnConfig_InitTimer(struct comedi_device *dev,struct comedi_subdevice *s, +----------------------------------------------------------------------------+ */ -INT i_APCI1710_InsnConfigInitTimer(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI1710_InsnConfigInitTimer(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - INT i_ReturnValue = 0; - BYTE b_ModulNbr; - BYTE b_TimerNbr; - BYTE b_TimerMode; - ULONG ul_ReloadValue; - BYTE b_InputClockSelection; - BYTE b_InputClockLevel; - BYTE b_OutputLevel; - BYTE b_HardwareGateLevel; + int i_ReturnValue = 0; + unsigned char b_ModulNbr; + unsigned char b_TimerNbr; + unsigned char b_TimerMode; + unsigned int ul_ReloadValue; + unsigned char b_InputClockSelection; + unsigned char b_InputClockLevel; + unsigned char b_OutputLevel; + unsigned char b_HardwareGateLevel; - //BEGIN JK 27.10.2003 : Add the possibility to use a 40 Mhz quartz - DWORD dw_Test = 0; - //END JK 27.10.2003 : Add the possibility to use a 40 Mhz quartz + /* BEGIN JK 27.10.2003 : Add the possibility to use a 40 Mhz quartz */ + unsigned int dw_Test = 0; + /* END JK 27.10.2003 : Add the possibility to use a 40 Mhz quartz */ i_ReturnValue = insn->n; - b_ModulNbr = (BYTE) CR_AREF(insn->chanspec); - b_TimerNbr = (BYTE) CR_CHAN(insn->chanspec); - b_TimerMode = (BYTE) data[0]; - ul_ReloadValue = (ULONG) data[1]; - b_InputClockSelection = (BYTE) data[2]; - b_InputClockLevel = (BYTE) data[3]; - b_OutputLevel = (BYTE) data[4]; - b_HardwareGateLevel = (BYTE) data[5]; + b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); + b_TimerNbr = (unsigned char) CR_CHAN(insn->chanspec); + b_TimerMode = (unsigned char) data[0]; + ul_ReloadValue = (unsigned int) data[1]; + b_InputClockSelection = (unsigned char) data[2]; + b_InputClockLevel = (unsigned char) data[3]; + b_OutputLevel = (unsigned char) data[4]; + b_HardwareGateLevel = (unsigned char) data[5]; /* Test the module number */ if (b_ModulNbr < 4) { @@ -256,7 +256,7 @@ INT i_APCI1710_InsnConfigInitTimer(struct comedi_device * dev, struct comedi_sub if (b_TimerNbr <= 2) { /* Test the timer mode */ if (b_TimerMode <= 5) { - //BEGIN JK 27.10.2003 : Add the possibility to use a 40 Mhz quartz + /* BEGIN JK 27.10.2003 : Add the possibility to use a 40 Mhz quartz */ /* Test te imput clock selection */ /* if (((b_TimerNbr == 0) && (b_InputClockSelection == 0)) || @@ -271,11 +271,11 @@ INT i_APCI1710_InsnConfigInitTimer(struct comedi_device * dev, struct comedi_sub ((b_InputClockSelection == APCI1710_PCI_BUS_CLOCK) || (b_InputClockSelection == APCI1710_FRONT_CONNECTOR_INPUT) || (b_InputClockSelection == APCI1710_10MHZ)))) { - //BEGIN JK 27.10.2003 : Add the possibility to use a 40 Mhz quartz + /* BEGIN JK 27.10.2003 : Add the possibility to use a 40 Mhz quartz */ if (((b_InputClockSelection == APCI1710_10MHZ) && ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0x0000FFFFUL) >= 0x3131)) || (b_InputClockSelection != APCI1710_10MHZ)) { - //END JK 27.10.2003 : Add the possibility to use a 40 Mhz quartz + /* END JK 27.10.2003 : Add the possibility to use a 40 Mhz quartz */ /* Test the input clock level selection */ if ((b_InputClockLevel == 0) || @@ -284,7 +284,7 @@ INT i_APCI1710_InsnConfigInitTimer(struct comedi_device * dev, struct comedi_sub if ((b_OutputLevel == 0) || (b_OutputLevel == 1)) { /* Test the hardware gate level selection */ if ((b_HardwareGateLevel == 0) || (b_HardwareGateLevel == 1)) { - //BEGIN JK 27.10.03 : Add the possibility to use a 40 Mhz quartz + /* BEGIN JK 27.10.03 : Add the possibility to use a 40 Mhz quartz */ /* Test if version > 1.1 and clock selection = 10MHz */ if ((b_InputClockSelection == APCI1710_10MHZ) && ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0x0000FFFFUL) > 0x3131)) { /* Test if 40MHz quartz on board */ @@ -297,7 +297,7 @@ INT i_APCI1710_InsnConfigInitTimer(struct comedi_device * dev, struct comedi_sub /* Test if detection OK */ if (dw_Test == 1) { - //END JK 27.10.03 : Add the possibility to use a 40 Mhz quartz + /* END JK 27.10.03 : Add the possibility to use a 40 Mhz quartz */ /* Initialisation OK */ devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_82X54Init = 1; @@ -314,12 +314,12 @@ INT i_APCI1710_InsnConfigInitTimer(struct comedi_device * dev, struct comedi_sub devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_HardwareGateLevel = b_HardwareGateLevel; /* Set the configuration word and disable the timer */ - //BEGIN JK 27.10.03 : Add the possibility to use a 40 Mhz quartz + /* BEGIN JK 27.10.03 : Add the possibility to use a 40 Mhz quartz */ /* devpriv->s_ModuleInfo [b_ModulNbr]. s_82X54ModuleInfo. s_82X54TimerInfo [b_TimerNbr]. - dw_ConfigurationWord = (DWORD) (((b_HardwareGateLevel << 0) & 0x1) | + dw_ConfigurationWord = (unsigned int) (((b_HardwareGateLevel << 0) & 0x1) | ((b_InputClockLevel << 1) & 0x2) | (((~b_OutputLevel & 1) << 2) & 0x4) | ((b_InputClockSelection << 4) & 0x10)); @@ -329,40 +329,40 @@ INT i_APCI1710_InsnConfigInitTimer(struct comedi_device * dev, struct comedi_sub b_InputClockSelection = 2; } - devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord = (DWORD)(((b_HardwareGateLevel << 0) & 0x1) | ((b_InputClockLevel << 1) & 0x2) | (((~b_OutputLevel & 1) << 2) & 0x4) | ((b_InputClockSelection << 4) & 0x30)); - //END JK 27.10.03 : Add the possibility to use a 40 Mhz quartz + devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord = (unsigned int)(((b_HardwareGateLevel << 0) & 0x1) | ((b_InputClockLevel << 1) & 0x2) | (((~b_OutputLevel & 1) << 2) & 0x4) | ((b_InputClockSelection << 4) & 0x30)); + /* END JK 27.10.03 : Add the possibility to use a 40 Mhz quartz */ outl(devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord, devpriv->s_BoardInfos.ui_Address + 32 + (b_TimerNbr * 4) + (64 * b_ModulNbr)); /* Initialise the 82X54 Timer */ - outl((DWORD) b_TimerMode, devpriv->s_BoardInfos.ui_Address + 16 + (b_TimerNbr * 4) + (64 * b_ModulNbr)); + outl((unsigned int) b_TimerMode, devpriv->s_BoardInfos.ui_Address + 16 + (b_TimerNbr * 4) + (64 * b_ModulNbr)); /* Write the reload value */ outl(ul_ReloadValue, devpriv->s_BoardInfos.ui_Address + 0 + (b_TimerNbr * 4) + (64 * b_ModulNbr)); - //BEGIN JK 27.10.03 : Add the possibility to use a 40 Mhz quartz - } // if (dw_Test == 1) + /* BEGIN JK 27.10.03 : Add the possibility to use a 40 Mhz quartz */ + } /* if (dw_Test == 1) */ else { /* Input timer clock selection is wrong */ i_ReturnValue = -6; - } // if (dw_Test == 1) - //END JK 27.10.03 : Add the possibility to use a 40 Mhz quartz - } // if ((b_HardwareGateLevel == 0) || (b_HardwareGateLevel == 1)) + } /* if (dw_Test == 1) */ + /* END JK 27.10.03 : Add the possibility to use a 40 Mhz quartz */ + } /* if ((b_HardwareGateLevel == 0) || (b_HardwareGateLevel == 1)) */ else { /* Selection from hardware gate level is wrong */ DPRINTK("Selection from hardware gate level is wrong\n"); i_ReturnValue = -9; - } // if ((b_HardwareGateLevel == 0) || (b_HardwareGateLevel == 1)) - } // if ((b_OutputLevel == 0) || (b_OutputLevel == 1)) + } /* if ((b_HardwareGateLevel == 0) || (b_HardwareGateLevel == 1)) */ + } /* if ((b_OutputLevel == 0) || (b_OutputLevel == 1)) */ else { /* Selection from output clock level is wrong */ DPRINTK("Selection from output clock level is wrong\n"); i_ReturnValue = -8; - } // if ((b_OutputLevel == 0) || (b_OutputLevel == 1)) - } // if ((b_InputClockLevel == 0) || (b_InputClockLevel == 1)) + } /* if ((b_OutputLevel == 0) || (b_OutputLevel == 1)) */ + } /* if ((b_InputClockLevel == 0) || (b_InputClockLevel == 1)) */ else { /* Selection from input clock level is wrong */ DPRINTK("Selection from input clock level is wrong\n"); i_ReturnValue = -7; - } // if ((b_InputClockLevel == 0) || (b_InputClockLevel == 1)) + } /* if ((b_InputClockLevel == 0) || (b_InputClockLevel == 1)) */ } else { /* Input timer clock selection is wrong */ DPRINTK("Input timer clock selection is wrong\n"); @@ -373,18 +373,18 @@ INT i_APCI1710_InsnConfigInitTimer(struct comedi_device * dev, struct comedi_sub DPRINTK("Input timer clock selection is wrong\n"); i_ReturnValue = -6; } - } // if ((b_TimerMode >= 0) && (b_TimerMode <= 5)) + } /* if ((b_TimerMode >= 0) && (b_TimerMode <= 5)) */ else { /* Timer mode selection is wrong */ DPRINTK("Timer mode selection is wrong\n"); i_ReturnValue = -5; - } // if ((b_TimerMode >= 0) && (b_TimerMode <= 5)) - } // if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2)) + } /* if ((b_TimerMode >= 0) && (b_TimerMode <= 5)) */ + } /* if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2)) */ else { /* Timer selection wrong */ DPRINTK("Timer selection wrong\n"); i_ReturnValue = -3; - } // if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2)) + } /* if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2)) */ } else { /* The module is not a TIMER module */ DPRINTK("The module is not a TIMER module\n"); @@ -396,17 +396,17 @@ INT i_APCI1710_InsnConfigInitTimer(struct comedi_device * dev, struct comedi_sub i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_EnableTimer | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr, | -| BYTE_ b_TimerNbr, | -| BYTE_ b_InterruptEnable) -INT i_APCI1710_InsnWriteEnableDisableTimer(struct comedi_device *dev,struct comedi_subdevice *s, +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr, | +| unsigned char_ b_TimerNbr, | +| unsigned char_ b_InterruptEnable) +int i_APCI1710_InsnWriteEnableDisableTimer(struct comedi_device *dev,struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data) | +----------------------------------------------------------------------------+ | Task : Enable OR Disable the Timer (b_TimerNbr) from selected module | @@ -416,22 +416,22 @@ INT i_APCI1710_InsnWriteEnableDisableTimer(struct comedi_device *dev,struct come | generate a interrupt after the timer value reach | | the zero. See function "i_APCI1710_SetBoardIntRoutineX"| +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board | | APCI-1710 | -| BYTE_ b_ModulNbr : Selected module number | +| unsigned char_ b_ModulNbr : Selected module number | | (0 to 3) | -| BYTE_ b_TimerNbr : Timer number to enable | +| unsigned char_ b_TimerNbr : Timer number to enable | | (0 to 2) | -| BYTE_ b_InterruptEnable : Enable or disable the | +| unsigned char_ b_InterruptEnable : Enable or disable the | | timer interrupt. | | APCI1710_ENABLE : | | Enable the timer interrupt | | APCI1710_DISABLE : | | Disable the timer interrupt| i_ReturnValue=insn->n; - b_ModulNbr = (BYTE) CR_AREF(insn->chanspec); - b_TimerNbr = (BYTE) CR_CHAN(insn->chanspec); - b_ActionType = (BYTE) data[0]; // enable disable + b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); + b_TimerNbr = (unsigned char) CR_CHAN(insn->chanspec); + b_ActionType = (unsigned char) data[0]; /* enable disable */ +----------------------------------------------------------------------------+ | Output Parameters : - | +----------------------------------------------------------------------------+ @@ -448,21 +448,21 @@ i_ReturnValue=insn->n; +----------------------------------------------------------------------------+ */ -INT i_APCI1710_InsnWriteEnableDisableTimer(struct comedi_device * dev, - struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI1710_InsnWriteEnableDisableTimer(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - INT i_ReturnValue = 0; - DWORD dw_DummyRead; - BYTE b_ModulNbr; - BYTE b_TimerNbr; - BYTE b_ActionType; - BYTE b_InterruptEnable; + int i_ReturnValue = 0; + unsigned int dw_DummyRead; + unsigned char b_ModulNbr; + unsigned char b_TimerNbr; + unsigned char b_ActionType; + unsigned char b_InterruptEnable; i_ReturnValue = insn->n; - b_ModulNbr = (BYTE) CR_AREF(insn->chanspec); - b_TimerNbr = (BYTE) CR_CHAN(insn->chanspec); - b_ActionType = (BYTE) data[0]; // enable disable + b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); + b_TimerNbr = (unsigned char) CR_CHAN(insn->chanspec); + b_ActionType = (unsigned char) data[0]; /* enable disable */ /* Test the module number */ if (b_ModulNbr < 4) { @@ -475,7 +475,7 @@ INT i_APCI1710_InsnWriteEnableDisableTimer(struct comedi_device * dev, switch (b_ActionType) { case APCI1710_ENABLE: - b_InterruptEnable = (BYTE) data[1]; + b_InterruptEnable = (unsigned char) data[1]; /* Test the interrupt selection */ if ((b_InterruptEnable == APCI1710_ENABLE) || (b_InterruptEnable == APCI1710_DISABLE)) { @@ -487,9 +487,9 @@ INT i_APCI1710_InsnWriteEnableDisableTimer(struct comedi_device * dev, devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord = devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord | 0x8; outl(devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord, devpriv->s_BoardInfos.ui_Address + 32 + (b_TimerNbr * 4) + (64 * b_ModulNbr)); - devpriv->tsk_Current = current; // Save the current process task structure + devpriv->tsk_Current = current; /* Save the current process task structure */ - } // if (b_InterruptEnable == APCI1710_ENABLE) + } /* if (b_InterruptEnable == APCI1710_ENABLE) */ else { /* Disable the interrupt */ devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord = devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord & 0xF7; @@ -498,7 +498,7 @@ INT i_APCI1710_InsnWriteEnableDisableTimer(struct comedi_device * dev, /* Save the interrupt flag */ devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.b_InterruptMask = devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.b_InterruptMask & (0xFF - (1 << b_TimerNbr)); - } // if (b_InterruptEnable == APCI1710_ENABLE) + } /* if (b_InterruptEnable == APCI1710_ENABLE) */ /* Test if error occur */ if (i_ReturnValue >= 0) { @@ -530,7 +530,7 @@ INT i_APCI1710_InsnWriteEnableDisableTimer(struct comedi_device * dev, /* Disable the timer */ outl(0, devpriv->s_BoardInfos.ui_Address + 44 + (b_TimerNbr * 4) + (64 * b_ModulNbr)); break; - } // Switch end + } /* Switch end */ } else { /* Timer not initialised see function */ DPRINTK ("Timer not initialised see function\n"); @@ -540,7 +540,7 @@ INT i_APCI1710_InsnWriteEnableDisableTimer(struct comedi_device * dev, /* Timer selection wrong */ DPRINTK("Timer selection wrong\n"); i_ReturnValue = -3; - } // if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2)) + } /* if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2)) */ } else { /* The module is not a TIMER module */ DPRINTK("The module is not a TIMER module\n"); @@ -552,24 +552,24 @@ INT i_APCI1710_InsnWriteEnableDisableTimer(struct comedi_device * dev, i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_ReadAllTimerValue | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr, | +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr, | | PULONG_ pul_TimerValueArray) -INT i_APCI1710_InsnReadAllTimerValue(struct comedi_device *dev,struct comedi_subdevice *s, +int i_APCI1710_InsnReadAllTimerValue(struct comedi_device *dev,struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data) | +----------------------------------------------------------------------------+ | Task : Return the all timer values from selected timer | | module (b_ModulNbr). | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board | | APCI-1710 | -| BYTE_ b_ModulNbr : Selected module number | +| unsigned char_ b_ModulNbr : Selected module number | | (0 to 3) | +----------------------------------------------------------------------------+ | Output Parameters : PULONG_ pul_TimerValueArray : Timer value array. | @@ -590,16 +590,16 @@ INT i_APCI1710_InsnReadAllTimerValue(struct comedi_device *dev,struct comedi_sub +----------------------------------------------------------------------------+ */ -INT i_APCI1710_InsnReadAllTimerValue(struct comedi_device *dev, struct comedi_subdevice *s, +int i_APCI1710_InsnReadAllTimerValue(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - INT i_ReturnValue = 0; - BYTE b_ModulNbr, b_ReadType; - PULONG pul_TimerValueArray; + int i_ReturnValue = 0; + unsigned char b_ModulNbr, b_ReadType; + unsigned int *pul_TimerValueArray; b_ModulNbr = CR_AREF(insn->chanspec); b_ReadType = CR_CHAN(insn->chanspec); - pul_TimerValueArray = (PULONG) data; + pul_TimerValueArray = (unsigned int *) data; i_ReturnValue = insn->n; switch (b_ReadType) { @@ -662,8 +662,8 @@ INT i_APCI1710_InsnReadAllTimerValue(struct comedi_device *dev, struct comedi_su i_ReturnValue = -2; } - } // End of Switch - return (i_ReturnValue); + } /* End of Switch */ + return i_ReturnValue; } /* @@ -681,11 +681,11 @@ struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) +----------------------------------------------------------------------------+ */ -INT i_APCI1710_InsnBitsTimer(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI1710_InsnBitsTimer(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - BYTE b_BitsType; - INT i_ReturnValue = 0; + unsigned char b_BitsType; + int i_ReturnValue = 0; b_BitsType = data[0]; printk("\n82X54"); @@ -693,30 +693,30 @@ INT i_APCI1710_InsnBitsTimer(struct comedi_device * dev, struct comedi_subdevice switch (b_BitsType) { case APCI1710_TIMER_READVALUE: i_ReturnValue = i_APCI1710_ReadTimerValue(dev, - (BYTE)CR_AREF(insn->chanspec), - (BYTE)CR_CHAN(insn->chanspec), - (PULONG) & data[0]); + (unsigned char)CR_AREF(insn->chanspec), + (unsigned char)CR_CHAN(insn->chanspec), + (unsigned int *) &data[0]); break; case APCI1710_TIMER_GETOUTPUTLEVEL: i_ReturnValue = i_APCI1710_GetTimerOutputLevel(dev, - (BYTE)CR_AREF(insn->chanspec), - (BYTE)CR_CHAN(insn->chanspec), - (PBYTE) &data[0]); + (unsigned char)CR_AREF(insn->chanspec), + (unsigned char)CR_CHAN(insn->chanspec), + (unsigned char *) &data[0]); break; case APCI1710_TIMER_GETPROGRESSSTATUS: i_ReturnValue = i_APCI1710_GetTimerProgressStatus(dev, - (BYTE)CR_AREF(insn->chanspec), - (BYTE)CR_CHAN(insn->chanspec), - (PBYTE)&data[0]); + (unsigned char)CR_AREF(insn->chanspec), + (unsigned char)CR_CHAN(insn->chanspec), + (unsigned char *)&data[0]); break; case APCI1710_TIMER_WRITEVALUE: i_ReturnValue = i_APCI1710_WriteTimerValue(dev, - (BYTE)CR_AREF(insn->chanspec), - (BYTE)CR_CHAN(insn->chanspec), - (ULONG)data[1]); + (unsigned char)CR_AREF(insn->chanspec), + (unsigned char)CR_CHAN(insn->chanspec), + (unsigned int)data[1]); break; @@ -727,25 +727,25 @@ INT i_APCI1710_InsnBitsTimer(struct comedi_device * dev, struct comedi_subdevice if (i_ReturnValue >= 0) i_ReturnValue = insn->n; - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_ReadTimerValue | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr, | -| BYTE_ b_TimerNbr, | +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr, | +| unsigned char_ b_TimerNbr, | | PULONG_ pul_TimerValue) | +----------------------------------------------------------------------------+ | Task : Return the timer value from selected digital timer | | (b_TimerNbr) from selected timer module (b_ModulNbr). | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board | | APCI-1710 | -| BYTE_ b_ModulNbr : Selected module number | +| unsigned char_ b_ModulNbr : Selected module number | | (0 to 3) | -| BYTE_ b_TimerNbr : Timer number to read | +| unsigned char_ b_TimerNbr : Timer number to read | | (0 to 2) | +----------------------------------------------------------------------------+ | Output Parameters : PULONG_ pul_TimerValue : Timer value | @@ -760,11 +760,11 @@ INT i_APCI1710_InsnBitsTimer(struct comedi_device * dev, struct comedi_subdevice +----------------------------------------------------------------------------+ */ -INT i_APCI1710_ReadTimerValue(struct comedi_device * dev, - BYTE b_ModulNbr, BYTE b_TimerNbr, - PULONG pul_TimerValue) +int i_APCI1710_ReadTimerValue(struct comedi_device *dev, + unsigned char b_ModulNbr, unsigned char b_TimerNbr, + unsigned int *pul_TimerValue) { - INT i_ReturnValue = 0; + int i_ReturnValue = 0; /* Test the module number */ if (b_ModulNbr < 4) { @@ -800,7 +800,7 @@ INT i_APCI1710_ReadTimerValue(struct comedi_device * dev, /* Timer selection wrong */ DPRINTK("Timer selection wrong\n"); i_ReturnValue = -3; - } // if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2)) + } /* if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2)) */ } else { /* The module is not a TIMER module */ DPRINTK("The module is not a TIMER module\n"); @@ -812,29 +812,29 @@ INT i_APCI1710_ReadTimerValue(struct comedi_device * dev, i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_GetTimerOutputLevel | - | (BYTE_ b_BoardHandle, | - | BYTE_ b_ModulNbr, | - | BYTE_ b_TimerNbr, | - | PBYTE_ pb_OutputLevel) | + | (unsigned char_ b_BoardHandle, | + | unsigned char_ b_ModulNbr, | + | unsigned char_ b_TimerNbr, | + | unsigned char *_ pb_OutputLevel) | +----------------------------------------------------------------------------+ | Task : Return the output signal level (pb_OutputLevel) from | | selected digital timer (b_TimerNbr) from selected timer| | module (b_ModulNbr). | +----------------------------------------------------------------------------+ - | Input Parameters : BYTE_ b_BoardHandle : Handle of board | + | Input Parameters : unsigned char_ b_BoardHandle : Handle of board | | APCI-1710 | - | BYTE_ b_ModulNbr : Selected module number | + | unsigned char_ b_ModulNbr : Selected module number | | (0 to 3) | - | BYTE_ b_TimerNbr : Timer number to test | + | unsigned char_ b_TimerNbr : Timer number to test | | (0 to 2) | +----------------------------------------------------------------------------+ - | Output Parameters : PBYTE_ pb_OutputLevel : Output signal level | + | Output Parameters : unsigned char *_ pb_OutputLevel : Output signal level | | 0 : The output is low | | 1 : The output is high | +----------------------------------------------------------------------------+ @@ -848,12 +848,12 @@ INT i_APCI1710_ReadTimerValue(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -INT i_APCI1710_GetTimerOutputLevel(struct comedi_device * dev, - BYTE b_ModulNbr, BYTE b_TimerNbr, - PBYTE pb_OutputLevel) +int i_APCI1710_GetTimerOutputLevel(struct comedi_device *dev, + unsigned char b_ModulNbr, unsigned char b_TimerNbr, + unsigned char *pb_OutputLevel) { - INT i_ReturnValue = 0; - DWORD dw_TimerStatus; + int i_ReturnValue = 0; + unsigned int dw_TimerStatus; /* Test the module number */ if (b_ModulNbr < 4) { @@ -869,7 +869,7 @@ INT i_APCI1710_GetTimerOutputLevel(struct comedi_device * dev, /* Read the timer status */ dw_TimerStatus = inl(devpriv->s_BoardInfos.ui_Address + 16 + (b_TimerNbr * 4) + (64 * b_ModulNbr)); - *pb_OutputLevel = (BYTE) (((dw_TimerStatus >> 7) & 1) ^ devpriv-> s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_OutputLevel); + *pb_OutputLevel = (unsigned char) (((dw_TimerStatus >> 7) & 1) ^ devpriv-> s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_OutputLevel); } else { /* Timer not initialised see function */ DPRINTK("Timer not initialised see function\n"); @@ -879,7 +879,7 @@ INT i_APCI1710_GetTimerOutputLevel(struct comedi_device * dev, /* Timer selection wrong */ DPRINTK("Timer selection wrong\n"); i_ReturnValue = -3; - } // if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2)) + } /* if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2)) */ } else { /* The module is not a TIMER module */ DPRINTK("The module is not a TIMER module\n"); @@ -891,29 +891,29 @@ INT i_APCI1710_GetTimerOutputLevel(struct comedi_device * dev, i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_GetTimerProgressStatus | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr, | -| BYTE_ b_TimerNbr, | -| PBYTE_ pb_TimerStatus) | +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr, | +| unsigned char_ b_TimerNbr, | +| unsigned char *_ pb_TimerStatus) | +----------------------------------------------------------------------------+ | Task : Return the progress status (pb_TimerStatus) from | | selected digital timer (b_TimerNbr) from selected timer| | module (b_ModulNbr). | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board | | APCI-1710 | -| BYTE_ b_ModulNbr : Selected module number | +| unsigned char_ b_ModulNbr : Selected module number | | (0 to 3) | -| BYTE_ b_TimerNbr : Timer number to test | +| unsigned char_ b_TimerNbr : Timer number to test | | (0 to 2) | +----------------------------------------------------------------------------+ -| Output Parameters : PBYTE_ pb_TimerStatus : Output signal level | +| Output Parameters : unsigned char *_ pb_TimerStatus : Output signal level | | 0 : Timer not in progress | | 1 : Timer in progress | +----------------------------------------------------------------------------+ @@ -927,12 +927,12 @@ INT i_APCI1710_GetTimerOutputLevel(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -INT i_APCI1710_GetTimerProgressStatus(struct comedi_device *dev, - BYTE b_ModulNbr, BYTE b_TimerNbr, - PBYTE pb_TimerStatus) +int i_APCI1710_GetTimerProgressStatus(struct comedi_device *dev, + unsigned char b_ModulNbr, unsigned char b_TimerNbr, + unsigned char *pb_TimerStatus) { - INT i_ReturnValue = 0; - DWORD dw_TimerStatus; + int i_ReturnValue = 0; + unsigned int dw_TimerStatus; /* Test the module number */ if (b_ModulNbr < 4) { @@ -949,7 +949,7 @@ INT i_APCI1710_GetTimerProgressStatus(struct comedi_device *dev, /* Read the timer status */ dw_TimerStatus = inl(devpriv->s_BoardInfos.ui_Address + 16 + (b_TimerNbr * 4) + (64 * b_ModulNbr)); - *pb_TimerStatus = (BYTE) ((dw_TimerStatus) >> 8) & 1; + *pb_TimerStatus = (unsigned char) ((dw_TimerStatus) >> 8) & 1; printk("ProgressStatus : %d", *pb_TimerStatus); } else { /* Timer not initialised see function */ @@ -958,7 +958,7 @@ INT i_APCI1710_GetTimerProgressStatus(struct comedi_device *dev, } else { /* Timer selection wrong */ i_ReturnValue = -3; - } // if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2)) + } /* if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2)) */ } else { /* The module is not a TIMER module */ @@ -976,9 +976,9 @@ INT i_APCI1710_GetTimerProgressStatus(struct comedi_device *dev, /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_WriteTimerValue | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr, | -| BYTE_ b_TimerNbr, | +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr, | +| unsigned char_ b_TimerNbr, | | ULONG_ ul_WriteValue) | +----------------------------------------------------------------------------+ | Task : Write the value (ul_WriteValue) into the selected timer| @@ -986,11 +986,11 @@ INT i_APCI1710_GetTimerProgressStatus(struct comedi_device *dev, | The action in depend of the time mode selection. | | See timer mode description table. | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board | | APCI-1710 | -| BYTE_ b_ModulNbr : Selected module number | +| unsigned char_ b_ModulNbr : Selected module number | | (0 to 3) | -| BYTE_ b_TimerNbr : Timer number to write | +| unsigned char_ b_TimerNbr : Timer number to write | | (0 to 2) | | ULONG_ ul_WriteValue : Value to write | +----------------------------------------------------------------------------+ @@ -1006,11 +1006,11 @@ INT i_APCI1710_GetTimerProgressStatus(struct comedi_device *dev, +----------------------------------------------------------------------------+ */ -INT i_APCI1710_WriteTimerValue(struct comedi_device * dev, - BYTE b_ModulNbr, BYTE b_TimerNbr, - ULONG ul_WriteValue) +int i_APCI1710_WriteTimerValue(struct comedi_device *dev, + unsigned char b_ModulNbr, unsigned char b_TimerNbr, + unsigned int ul_WriteValue) { - INT i_ReturnValue = 0; + int i_ReturnValue = 0; /* Test the module number */ if (b_ModulNbr < 4) { @@ -1031,7 +1031,7 @@ INT i_APCI1710_WriteTimerValue(struct comedi_device * dev, /* Timer selection wrong */ DPRINTK("Timer selection wrong\n"); i_ReturnValue = -3; - } // if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2)) + } /* if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2)) */ } else { /* The module is not a TIMER module */ DPRINTK("The module is not a TIMER module\n"); diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_82x54.h b/drivers/staging/comedi/drivers/addi-data/APCI1710_82x54.h index 4797c0b77a43..9698ae13509d 100644 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_82x54.h +++ b/drivers/staging/comedi/drivers/addi-data/APCI1710_82x54.h @@ -34,40 +34,40 @@ /* * 82X54 TIMER INISIALISATION FUNCTION */ -INT i_APCI1710_InsnConfigInitTimer(struct comedi_device *dev, struct comedi_subdevice *s, +int i_APCI1710_InsnConfigInitTimer(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -INT i_APCI1710_InsnWriteEnableDisableTimer(struct comedi_device *dev, +int i_APCI1710_InsnWriteEnableDisableTimer(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); /* * 82X54 READ FUNCTION */ -INT i_APCI1710_InsnReadAllTimerValue(struct comedi_device *dev, struct comedi_subdevice *s, +int i_APCI1710_InsnReadAllTimerValue(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -INT i_APCI1710_InsnBitsTimer(struct comedi_device *dev, struct comedi_subdevice *s, +int i_APCI1710_InsnBitsTimer(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); /* * 82X54 READ & WRITE FUNCTION */ -INT i_APCI1710_ReadTimerValue(struct comedi_device *dev, - BYTE b_ModulNbr, BYTE b_TimerNbr, - PULONG pul_TimerValue); +int i_APCI1710_ReadTimerValue(struct comedi_device *dev, + unsigned char b_ModulNbr, unsigned char b_TimerNbr, + unsigned int *pul_TimerValue); -INT i_APCI1710_GetTimerOutputLevel(struct comedi_device *dev, - BYTE b_ModulNbr, BYTE b_TimerNbr, - PBYTE pb_OutputLevel); +int i_APCI1710_GetTimerOutputLevel(struct comedi_device *dev, + unsigned char b_ModulNbr, unsigned char b_TimerNbr, + unsigned char *pb_OutputLevel); -INT i_APCI1710_GetTimerProgressStatus(struct comedi_device *dev, - BYTE b_ModulNbr, BYTE b_TimerNbr, - PBYTE pb_TimerStatus); +int i_APCI1710_GetTimerProgressStatus(struct comedi_device *dev, + unsigned char b_ModulNbr, unsigned char b_TimerNbr, + unsigned char *pb_TimerStatus); /* * 82X54 WRITE FUNCTION */ -INT i_APCI1710_WriteTimerValue(struct comedi_device *dev, - BYTE b_ModulNbr, BYTE b_TimerNbr, - ULONG ul_WriteValue); +int i_APCI1710_WriteTimerValue(struct comedi_device *dev, + unsigned char b_ModulNbr, unsigned char b_TimerNbr, + unsigned int ul_WriteValue); diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Chrono.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_Chrono.c index 1a54d3b2c694..ccb109a851f2 100644 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Chrono.c +++ b/drivers/staging/comedi/drivers/addi-data/APCI1710_Chrono.c @@ -3,13 +3,13 @@ Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data-com - info@addi-data.com + ADDI-DATA GmbH + Dieselstrasse 3 + D-77833 Ottersweier + Tel: +19(0)7223/9493-0 + Fax: +49(0)7223/9493-92 + http://www.addi-data-com + info@addi-data.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. @@ -62,11 +62,11 @@ You shoud also find the complete GPL in the COPYING file accompanying this sourc /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_InitChrono | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr, | -| BYTE_ b_ChronoMode, | -| BYTE_ b_PCIInputClock, | -| BYTE_ b_TimingUnit, | +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr, | +| unsigned char_ b_ChronoMode, | +| unsigned char_ b_PCIInputClock, | +| unsigned char_ b_TimingUnit, | | ULONG_ ul_TimingInterval, | | PULONG_ pul_RealTimingInterval) @@ -88,12 +88,12 @@ You shoud also find the complete GPL in the COPYING file accompanying this sourc | The mode 4 to 7 is appropriate for measuring the timing| | between two event. | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | -| BYTE_ b_ModulNbr CR_AREF(insn->chanspec) : Module number to configure | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | +| unsigned char_ b_ModulNbr CR_AREF(insn->chanspec) : Module number to configure | | (0 to 3) | -| BYTE_ b_ChronoMode data[0] : Chronometer action mode | +| unsigned char_ b_ChronoMode data[0] : Chronometer action mode | | (0 to 7). | -| BYTE_ b_PCIInputClock data[1] : Selection from PCI bus clock| +| unsigned char_ b_PCIInputClock data[1] : Selection from PCI bus clock| | - APCI1710_30MHZ : | | The PC have a PCI bus | | clock from 30 MHz | @@ -104,7 +104,7 @@ You shoud also find the complete GPL in the COPYING file accompanying this sourc | The APCI-1710 have a | | integrated 40Mhz | | quartz. | -| BYTE_ b_TimingUnit data[2] : Base timing unity (0 to 4) | +| unsigned char_ b_TimingUnit data[2] : Base timing unity (0 to 4) | | 0 : ns | | 1 : µs | | 2 : ms | @@ -131,23 +131,23 @@ You shoud also find the complete GPL in the COPYING file accompanying this sourc +----------------------------------------------------------------------------+ */ -INT i_APCI1710_InsnConfigInitChrono(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI1710_InsnConfigInitChrono(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - INT i_ReturnValue = 0; - ULONG ul_TimerValue = 0; - ULONG ul_TimingInterval = 0; - ULONG ul_RealTimingInterval = 0; + int i_ReturnValue = 0; + unsigned int ul_TimerValue = 0; + unsigned int ul_TimingInterval = 0; + unsigned int ul_RealTimingInterval = 0; double d_RealTimingInterval = 0; - DWORD dw_ModeArray[8] = + unsigned int dw_ModeArray[8] = { 0x01, 0x05, 0x00, 0x04, 0x02, 0x0E, 0x0A, 0x06 }; - BYTE b_ModulNbr, b_ChronoMode, b_PCIInputClock, b_TimingUnit; + unsigned char b_ModulNbr, b_ChronoMode, b_PCIInputClock, b_TimingUnit; b_ModulNbr = CR_AREF(insn->chanspec); - b_ChronoMode = (BYTE) data[0]; - b_PCIInputClock = (BYTE) data[1]; - b_TimingUnit = (BYTE) data[2]; - ul_TimingInterval = (ULONG) data[3]; + b_ChronoMode = (unsigned char) data[0]; + b_PCIInputClock = (unsigned char) data[1]; + b_TimingUnit = (unsigned char) data[2]; + ul_TimingInterval = (unsigned int) data[3]; i_ReturnValue = insn->n; /**************************/ @@ -214,7 +214,7 @@ INT i_APCI1710_InsnConfigInitChrono(struct comedi_device * dev, struct comedi_su ul_TimerValue = - (ULONG) + (unsigned int) (ul_TimingInterval * (0.001 * b_PCIInputClock)); @@ -237,7 +237,7 @@ INT i_APCI1710_InsnConfigInitChrono(struct comedi_device * dev, struct comedi_su ul_RealTimingInterval = - (ULONG) + (unsigned int) (ul_TimerValue / (0.001 * (double)b_PCIInputClock)); @@ -272,7 +272,7 @@ INT i_APCI1710_InsnConfigInitChrono(struct comedi_device * dev, struct comedi_su if (b_PCIInputClock != APCI1710_40MHZ) { ul_TimerValue = - (ULONG) + (unsigned int) ( (double) (ul_TimerValue) @@ -294,7 +294,7 @@ INT i_APCI1710_InsnConfigInitChrono(struct comedi_device * dev, struct comedi_su ul_TimerValue = - (ULONG) + (unsigned int) (ul_TimingInterval * (1.0 * b_PCIInputClock)); @@ -317,7 +317,7 @@ INT i_APCI1710_InsnConfigInitChrono(struct comedi_device * dev, struct comedi_su ul_RealTimingInterval = - (ULONG) + (unsigned int) (ul_TimerValue / (1.0 * (double)b_PCIInputClock)); @@ -354,7 +354,7 @@ INT i_APCI1710_InsnConfigInitChrono(struct comedi_device * dev, struct comedi_su if (b_PCIInputClock != APCI1710_40MHZ) { ul_TimerValue = - (ULONG) + (unsigned int) ( (double) (ul_TimerValue) @@ -400,7 +400,7 @@ INT i_APCI1710_InsnConfigInitChrono(struct comedi_device * dev, struct comedi_su ul_RealTimingInterval = - (ULONG) + (unsigned int) (ul_TimerValue / (1000.0 * (double)b_PCIInputClock)); @@ -435,7 +435,7 @@ INT i_APCI1710_InsnConfigInitChrono(struct comedi_device * dev, struct comedi_su if (b_PCIInputClock != APCI1710_40MHZ) { ul_TimerValue = - (ULONG) + (unsigned int) ( (double) (ul_TimerValue) @@ -457,7 +457,7 @@ INT i_APCI1710_InsnConfigInitChrono(struct comedi_device * dev, struct comedi_su ul_TimerValue = - (ULONG) + (unsigned int) (ul_TimingInterval * (1000000.0 @@ -482,7 +482,7 @@ INT i_APCI1710_InsnConfigInitChrono(struct comedi_device * dev, struct comedi_su ul_RealTimingInterval = - (ULONG) + (unsigned int) (ul_TimerValue / (1000000.0 @@ -520,7 +520,7 @@ INT i_APCI1710_InsnConfigInitChrono(struct comedi_device * dev, struct comedi_su if (b_PCIInputClock != APCI1710_40MHZ) { ul_TimerValue = - (ULONG) + (unsigned int) ( (double) (ul_TimerValue) @@ -542,7 +542,7 @@ INT i_APCI1710_InsnConfigInitChrono(struct comedi_device * dev, struct comedi_su ul_TimerValue = - (ULONG) + (unsigned int) ( (ul_TimingInterval * @@ -570,7 +570,7 @@ INT i_APCI1710_InsnConfigInitChrono(struct comedi_device * dev, struct comedi_su ul_RealTimingInterval = - (ULONG) + (unsigned int) (ul_TimerValue / (1000000.0 @@ -608,7 +608,7 @@ INT i_APCI1710_InsnConfigInitChrono(struct comedi_device * dev, struct comedi_su if (b_PCIInputClock != APCI1710_40MHZ) { ul_TimerValue = - (ULONG) + (unsigned int) ( (double) (ul_TimerValue) @@ -736,7 +736,7 @@ INT i_APCI1710_InsnConfigInitChrono(struct comedi_device * dev, struct comedi_su DPRINTK("Base timing selection is wrong\n"); i_ReturnValue = -7; } - } // if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4)) + } /* if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4)) */ else { /***********************************/ /* Timing unity selection is wrong */ @@ -744,8 +744,8 @@ INT i_APCI1710_InsnConfigInitChrono(struct comedi_device * dev, struct comedi_su DPRINTK("Timing unity selection is wrong\n"); i_ReturnValue = -6; - } // if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4)) - } // if ((b_PCIInputClock == APCI1710_30MHZ) || (b_PCIInputClock == APCI1710_33MHZ)) + } /* if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4)) */ + } /* if ((b_PCIInputClock == APCI1710_30MHZ) || (b_PCIInputClock == APCI1710_33MHZ)) */ else { /*****************************************/ /* The selected PCI input clock is wrong */ @@ -753,8 +753,8 @@ INT i_APCI1710_InsnConfigInitChrono(struct comedi_device * dev, struct comedi_su DPRINTK("The selected PCI input clock is wrong\n"); i_ReturnValue = -5; - } // if ((b_PCIInputClock == APCI1710_30MHZ) || (b_PCIInputClock == APCI1710_33MHZ)) - } // if (b_ChronoMode >= 0 && b_ChronoMode <= 7) + } /* if ((b_PCIInputClock == APCI1710_30MHZ) || (b_PCIInputClock == APCI1710_33MHZ)) */ + } /* if (b_ChronoMode >= 0 && b_ChronoMode <= 7) */ else { /***************************************/ /* Chronometer mode selection is wrong */ @@ -762,7 +762,7 @@ INT i_APCI1710_InsnConfigInitChrono(struct comedi_device * dev, struct comedi_su DPRINTK("Chronometer mode selection is wrong\n"); i_ReturnValue = -4; - } // if (b_ChronoMode >= 0 && b_ChronoMode <= 7) + } /* if (b_ChronoMode >= 0 && b_ChronoMode <= 7) */ } else { /******************************************/ /* The module is not a Chronometer module */ @@ -780,17 +780,17 @@ INT i_APCI1710_InsnConfigInitChrono(struct comedi_device * dev, struct comedi_su i_ReturnValue = -2; } data[0] = ul_RealTimingInterval; - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_EnableChrono | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr, | -| BYTE_ b_CycleMode, | -| BYTE_ b_InterruptEnable) -INT i_APCI1710_InsnWriteEnableDisableChrono(struct comedi_device *dev, +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr, | +| unsigned char_ b_CycleMode, | +| unsigned char_ b_InterruptEnable) +int i_APCI1710_InsnWriteEnableDisableChrono(struct comedi_device *dev, struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) | +----------------------------------------------------------------------------+ | Task : Enable the chronometer from selected module | @@ -810,12 +810,12 @@ struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) | | witch the " i_APCI1710_EnableChrono" function, if no | | stop signal occur this start signal is ignored. +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | -| BYTE_ b_ModulNbr CR_AREF(chanspec) : Selected module number (0 to 3) | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | +| unsigned char_ b_ModulNbr CR_AREF(chanspec) : Selected module number (0 to 3) | data[0] ENABle/Disable chrono -| BYTE_ b_CycleMode : Selected the chronometer | +| unsigned char_ b_CycleMode : Selected the chronometer | | data[1] acquisition mode | -| BYTE_ b_InterruptEnable : Enable or disable the | +| unsigned char_ b_InterruptEnable : Enable or disable the | | data[2] chronometer interrupt. | | APCI1710_ENABLE: | | Enable the chronometer | @@ -840,15 +840,15 @@ struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) | +----------------------------------------------------------------------------+ */ -INT i_APCI1710_InsnWriteEnableDisableChrono(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +int i_APCI1710_InsnWriteEnableDisableChrono(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - INT i_ReturnValue = 0; - BYTE b_ModulNbr, b_CycleMode, b_InterruptEnable, b_Action; + int i_ReturnValue = 0; + unsigned char b_ModulNbr, b_CycleMode, b_InterruptEnable, b_Action; b_ModulNbr = CR_AREF(insn->chanspec); - b_Action = (BYTE) data[0]; - b_CycleMode = (BYTE) data[1]; - b_InterruptEnable = (BYTE) data[2]; + b_Action = (unsigned char) data[0]; + b_CycleMode = (unsigned char) data[1]; + b_InterruptEnable = (unsigned char) data[2]; i_ReturnValue = insn->n; /**************************/ @@ -951,7 +951,7 @@ INT i_APCI1710_InsnWriteEnableDisableChrono(struct comedi_device * dev, ui_Address + 32 + (64 * b_ModulNbr)); - devpriv->tsk_Current = current; // Save the current process task structure + devpriv->tsk_Current = current; /* Save the current process task structure */ } /***********************************/ @@ -980,7 +980,7 @@ INT i_APCI1710_InsnWriteEnableDisableChrono(struct comedi_device * dev, 36 + (64 * b_ModulNbr)); - } // if ((b_InterruptEnable == APCI1710_ENABLE) || (b_InterruptEnable == APCI1710_DISABLE)) + } /* if ((b_InterruptEnable == APCI1710_ENABLE) || (b_InterruptEnable == APCI1710_DISABLE)) */ else { /********************************/ /* Interrupt parameter is wrong */ @@ -988,8 +988,8 @@ INT i_APCI1710_InsnWriteEnableDisableChrono(struct comedi_device * dev, DPRINTK("Interrupt parameter is wrong\n"); i_ReturnValue = -6; - } // if ((b_InterruptEnable == APCI1710_ENABLE) || (b_InterruptEnable == APCI1710_DISABLE)) - } // if ((b_CycleMode == APCI1710_SINGLE) || (b_CycleMode == APCI1710_CONTINUOUS)) + } /* if ((b_InterruptEnable == APCI1710_ENABLE) || (b_InterruptEnable == APCI1710_DISABLE)) */ + } /* if ((b_CycleMode == APCI1710_SINGLE) || (b_CycleMode == APCI1710_CONTINUOUS)) */ else { /***********************************************/ /* Chronometer acquisition mode cycle is wrong */ @@ -997,7 +997,7 @@ INT i_APCI1710_InsnWriteEnableDisableChrono(struct comedi_device * dev, DPRINTK("Chronometer acquisition mode cycle is wrong\n"); i_ReturnValue = -5; - } // if ((b_CycleMode == APCI1710_SINGLE) || (b_CycleMode == APCI1710_CONTINUOUS)) + } /* if ((b_CycleMode == APCI1710_SINGLE) || (b_CycleMode == APCI1710_CONTINUOUS)) */ break; case APCI1710_DISABLE: @@ -1046,7 +1046,7 @@ INT i_APCI1710_InsnWriteEnableDisableChrono(struct comedi_device * dev, default: DPRINTK("Inputs wrong! Enable or Disable chrono\n"); i_ReturnValue = -8; - } // switch ENABLE/DISABLE + } /* switch ENABLE/DISABLE */ } else { /*******************************/ /* Chronometer not initialised */ @@ -1072,7 +1072,7 @@ INT i_APCI1710_InsnWriteEnableDisableChrono(struct comedi_device * dev, i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* @@ -1090,36 +1090,36 @@ struct comedi_insn *insn,unsigned int *data) | +----------------------------------------------------------------------------+ */ -INT i_APCI1710_InsnReadChrono(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI1710_InsnReadChrono(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - BYTE b_ReadType; - INT i_ReturnValue = insn->n; + unsigned char b_ReadType; + int i_ReturnValue = insn->n; b_ReadType = CR_CHAN(insn->chanspec); switch (b_ReadType) { case APCI1710_CHRONO_PROGRESS_STATUS: i_ReturnValue = i_APCI1710_GetChronoProgressStatus(dev, - (BYTE) CR_AREF(insn->chanspec), (PBYTE) & data[0]); + (unsigned char) CR_AREF(insn->chanspec), (unsigned char *) &data[0]); break; case APCI1710_CHRONO_READVALUE: i_ReturnValue = i_APCI1710_ReadChronoValue(dev, - (BYTE) CR_AREF(insn->chanspec), - (UINT) insn->unused[0], - (PBYTE) & data[0], (PULONG) & data[1]); + (unsigned char) CR_AREF(insn->chanspec), + (unsigned int) insn->unused[0], + (unsigned char *) &data[0], (unsigned int *) &data[1]); break; case APCI1710_CHRONO_CONVERTVALUE: i_ReturnValue = i_APCI1710_ConvertChronoValue(dev, - (BYTE) CR_AREF(insn->chanspec), - (ULONG) insn->unused[0], - (PULONG) & data[0], - (PBYTE) & data[1], - (PBYTE) & data[2], - (PUINT) & data[3], - (PUINT) & data[4], (PUINT) & data[5]); + (unsigned char) CR_AREF(insn->chanspec), + (unsigned int) insn->unused[0], + (unsigned int *) &data[0], + (unsigned char *) &data[1], + (unsigned char *) &data[2], + (unsigned int *) &data[3], + (unsigned int *) &data[4], (unsigned int *) &data[5]); break; case APCI1710_CHRONO_READINTERRUPT: @@ -1152,22 +1152,22 @@ INT i_APCI1710_InsnReadChrono(struct comedi_device * dev, struct comedi_subdevic if (i_ReturnValue >= 0) i_ReturnValue = insn->n; - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_GetChronoProgressStatus | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr, | -| PBYTE_ pb_ChronoStatus) | +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr, | +| unsigned char *_ pb_ChronoStatus) | +----------------------------------------------------------------------------+ | Task : Return the chronometer status (pb_ChronoStatus) from | | selected chronometer module (b_ModulNbr). | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | -| BYTE_ b_ModulNbr : Selected module number (0 to 3) | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | +| unsigned char_ b_ModulNbr : Selected module number (0 to 3) | +----------------------------------------------------------------------------+ | Output Parameters : PULONG_ pb_ChronoStatus : Return the chronometer | | status. | @@ -1194,11 +1194,11 @@ INT i_APCI1710_InsnReadChrono(struct comedi_device * dev, struct comedi_subdevic +----------------------------------------------------------------------------+ */ -INT i_APCI1710_GetChronoProgressStatus(struct comedi_device * dev, - BYTE b_ModulNbr, PBYTE pb_ChronoStatus) +int i_APCI1710_GetChronoProgressStatus(struct comedi_device *dev, + unsigned char b_ModulNbr, unsigned char *pb_ChronoStatus) { - INT i_ReturnValue = 0; - DWORD dw_Status; + int i_ReturnValue = 0; + unsigned int dw_Status; /**************************/ /* Test the module number */ @@ -1233,7 +1233,7 @@ INT i_APCI1710_GetChronoProgressStatus(struct comedi_device * dev, /******************/ *pb_ChronoStatus = 3; - } // if ((dw_Status & 8) == 8) + } /* if ((dw_Status & 8) == 8) */ else { /*******************************/ /* Test if measurement stopped */ @@ -1245,7 +1245,7 @@ INT i_APCI1710_GetChronoProgressStatus(struct comedi_device * dev, /***********************/ *pb_ChronoStatus = 2; - } // if ((dw_Status & 2) == 2) + } /* if ((dw_Status & 2) == 2) */ else { /*******************************/ /* Test if measurement started */ @@ -1257,16 +1257,16 @@ INT i_APCI1710_GetChronoProgressStatus(struct comedi_device * dev, /************************/ *pb_ChronoStatus = 1; - } // if ((dw_Status & 1) == 1) + } /* if ((dw_Status & 1) == 1) */ else { /***************************/ /* Measurement not started */ /***************************/ *pb_ChronoStatus = 0; - } // if ((dw_Status & 1) == 1) - } // if ((dw_Status & 2) == 2) - } // if ((dw_Status & 8) == 8) + } /* if ((dw_Status & 1) == 1) */ + } /* if ((dw_Status & 2) == 2) */ + } /* if ((dw_Status & 8) == 8) */ } else { /*******************************/ /* Chronometer not initialised */ @@ -1289,16 +1289,16 @@ INT i_APCI1710_GetChronoProgressStatus(struct comedi_device * dev, i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_ReadChronoValue | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr, | -| UINT_ ui_TimeOut, | -| PBYTE_ pb_ChronoStatus, | +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr, | +| unsigned int_ ui_TimeOut, | +| unsigned char *_ pb_ChronoStatus, | | PULONG_ pul_ChronoValue) | +----------------------------------------------------------------------------+ | Task : Return the chronometer status (pb_ChronoStatus) and the| @@ -1323,8 +1323,8 @@ INT i_APCI1710_GetChronoProgressStatus(struct comedi_device * dev, | "i_APCI1710_InitChrono" function and the time unity is | | the b_TimingUnit from "i_APCI1710_InitChrono" function| +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | -| BYTE_ b_ModulNbr : Selected module number (0 to 3) | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | +| unsigned char_ b_ModulNbr : Selected module number (0 to 3) | +----------------------------------------------------------------------------+ | Output Parameters : PULONG_ pb_ChronoStatus : Return the chronometer | | status. | @@ -1341,7 +1341,7 @@ INT i_APCI1710_GetChronoProgressStatus(struct comedi_device * dev, | timing witch the | | function | | "i_APCI1710_InitChrono" | -| PULONG pul_ChronoValue : Chronometer timing value. | +| unsigned int * pul_ChronoValue : Chronometer timing value. | +----------------------------------------------------------------------------+ | Return Value : 0: No error | | -1: The handle parameter of the board is wrong | @@ -1355,13 +1355,13 @@ INT i_APCI1710_GetChronoProgressStatus(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -INT i_APCI1710_ReadChronoValue(struct comedi_device * dev, - BYTE b_ModulNbr, - UINT ui_TimeOut, PBYTE pb_ChronoStatus, PULONG pul_ChronoValue) +int i_APCI1710_ReadChronoValue(struct comedi_device *dev, + unsigned char b_ModulNbr, + unsigned int ui_TimeOut, unsigned char *pb_ChronoStatus, unsigned int *pul_ChronoValue) { - INT i_ReturnValue = 0; - DWORD dw_Status; - DWORD dw_TimeOut = 0; + int i_ReturnValue = 0; + unsigned int dw_Status; + unsigned int dw_TimeOut = 0; /**************************/ /* Test the module number */ @@ -1430,7 +1430,7 @@ INT i_APCI1710_ReadChronoValue(struct comedi_device * dev, } break; - } // if ((dw_Status & 8) == 8) + } /* if ((dw_Status & 8) == 8) */ else { /*******************************/ /* Test if measurement stopped */ @@ -1464,7 +1464,7 @@ INT i_APCI1710_ReadChronoValue(struct comedi_device * dev, outl(0, devpriv->s_BoardInfos.ui_Address + 36 + (64 * b_ModulNbr)); } break; - } // if ((dw_Status & 2) == 2) + } /* if ((dw_Status & 2) == 2) */ else { /*******************************/ /* Test if measurement started */ @@ -1478,7 +1478,7 @@ INT i_APCI1710_ReadChronoValue(struct comedi_device * dev, *pb_ChronoStatus = 1; - } // if ((dw_Status & 1) == 1) + } /* if ((dw_Status & 1) == 1) */ else { /***************************/ /* Measurement not started */ @@ -1487,9 +1487,9 @@ INT i_APCI1710_ReadChronoValue(struct comedi_device * dev, *pb_ChronoStatus = 0; - } // if ((dw_Status & 1) == 1) - } // if ((dw_Status & 2) == 2) - } // if ((dw_Status & 8) == 8) + } /* if ((dw_Status & 1) == 1) */ + } /* if ((dw_Status & 2) == 2) */ + } /* if ((dw_Status & 8) == 8) */ if (dw_TimeOut == ui_TimeOut) { /*****************/ @@ -1507,7 +1507,7 @@ INT i_APCI1710_ReadChronoValue(struct comedi_device * dev, mdelay(1000); } - } // for (;;) + } /* for (;;) */ /*****************************/ /* Test if stop signal occur */ @@ -1575,39 +1575,39 @@ INT i_APCI1710_ReadChronoValue(struct comedi_device * dev, i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_ConvertChronoValue | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr, | +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr, | | ULONG_ ul_ChronoValue, | | PULONG_ pul_Hour, | -| PBYTE_ pb_Minute, | -| PBYTE_ pb_Second, | -| PUINT_ pui_MilliSecond, | -| PUINT_ pui_MicroSecond, | -| PUINT_ pui_NanoSecond) | +| unsigned char *_ pb_Minute, | +| unsigned char *_ pb_Second, | +| unsigned int *_ pui_MilliSecond, | +| unsigned int *_ pui_MicroSecond, | +| unsigned int *_ pui_NanoSecond) | +----------------------------------------------------------------------------+ | Task : Convert the chronometer measured timing | | (ul_ChronoValue) in to h, mn, s, ms, µs, ns. | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | -| BYTE_ b_ModulNbr : Selected module number (0 to 3)| +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | +| unsigned char_ b_ModulNbr : Selected module number (0 to 3)| | ULONG_ ul_ChronoValue : Measured chronometer timing | | value. | | See"i_APCI1710_ReadChronoValue"| +----------------------------------------------------------------------------+ | Output Parameters : PULONG_ pul_Hour : Chronometer timing hour | -| PBYTE_ pb_Minute : Chronometer timing minute | -| PBYTE_ pb_Second : Chronometer timing second | -| PUINT_ pui_MilliSecond : Chronometer timing mini | +| unsigned char *_ pb_Minute : Chronometer timing minute | +| unsigned char *_ pb_Second : Chronometer timing second | +| unsigned int *_ pui_MilliSecond : Chronometer timing mini | | second | -| PUINT_ pui_MicroSecond : Chronometer timing micro | +| unsigned int *_ pui_MicroSecond : Chronometer timing micro | | second | -| PUINT_ pui_NanoSecond : Chronometer timing nano | +| unsigned int *_ pui_NanoSecond : Chronometer timing nano | | second | +----------------------------------------------------------------------------+ | Return Value : 0: No error | @@ -1619,15 +1619,15 @@ INT i_APCI1710_ReadChronoValue(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -INT i_APCI1710_ConvertChronoValue(struct comedi_device * dev, - BYTE b_ModulNbr, - ULONG ul_ChronoValue, - PULONG pul_Hour, - PBYTE pb_Minute, - PBYTE pb_Second, - PUINT pui_MilliSecond, PUINT pui_MicroSecond, PUINT pui_NanoSecond) +int i_APCI1710_ConvertChronoValue(struct comedi_device *dev, + unsigned char b_ModulNbr, + unsigned int ul_ChronoValue, + unsigned int *pul_Hour, + unsigned char *pb_Minute, + unsigned char *pb_Second, + unsigned int *pui_MilliSecond, unsigned int *pui_MicroSecond, unsigned int *pui_NanoSecond) { - INT i_ReturnValue = 0; + int i_ReturnValue = 0; double d_Hour; double d_Minute; double d_Second; @@ -1681,7 +1681,7 @@ INT i_APCI1710_ConvertChronoValue(struct comedi_device * dev, /**********************/ d_Hour = d_Hour / (double)60.0; - *pul_Hour = (ULONG) d_Hour; + *pul_Hour = (unsigned int) d_Hour; /************************/ /* Calculate the minute */ @@ -1689,7 +1689,7 @@ INT i_APCI1710_ConvertChronoValue(struct comedi_device * dev, d_Minute = d_Hour - *pul_Hour; d_Minute = d_Minute * 60; - *pb_Minute = (BYTE) d_Minute; + *pb_Minute = (unsigned char) d_Minute; /************************/ /* Calculate the second */ @@ -1697,7 +1697,7 @@ INT i_APCI1710_ConvertChronoValue(struct comedi_device * dev, d_Second = d_Minute - *pb_Minute; d_Second = d_Second * 60; - *pb_Second = (BYTE) d_Second; + *pb_Second = (unsigned char) d_Second; /*****************************/ /* Calculate the mini second */ @@ -1705,7 +1705,7 @@ INT i_APCI1710_ConvertChronoValue(struct comedi_device * dev, d_MilliSecond = d_Second - *pb_Second; d_MilliSecond = d_MilliSecond * 1000; - *pui_MilliSecond = (UINT) d_MilliSecond; + *pui_MilliSecond = (unsigned int) d_MilliSecond; /******************************/ /* Calculate the micro second */ @@ -1715,7 +1715,7 @@ INT i_APCI1710_ConvertChronoValue(struct comedi_device * dev, d_MilliSecond - *pui_MilliSecond; d_MicroSecond = d_MicroSecond * 1000; - *pui_MicroSecond = (UINT) d_MicroSecond; + *pui_MicroSecond = (unsigned int) d_MicroSecond; /******************************/ /* Calculate the micro second */ @@ -1725,7 +1725,7 @@ INT i_APCI1710_ConvertChronoValue(struct comedi_device * dev, d_MicroSecond - *pui_MicroSecond; d_NanoSecond = d_NanoSecond * 1000; - *pui_NanoSecond = (UINT) d_NanoSecond; + *pui_NanoSecond = (unsigned int) d_NanoSecond; break; } @@ -1752,21 +1752,21 @@ INT i_APCI1710_ConvertChronoValue(struct comedi_device * dev, i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ -| Function Name : INT i_APCI1710_InsnBitsChronoDigitalIO(struct comedi_device *dev,struct comedi_subdevice *s, +| Function Name : int i_APCI1710_InsnBitsChronoDigitalIO(struct comedi_device *dev,struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data) | +----------------------------------------------------------------------------+ | Task : Sets the output witch has been passed with the | | parameter b_Channel. Setting an output means setting an| | output high. | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | -| BYTE_ b_ModulNbr : Selected module number (0 to 3)| -| BYTE_ b_OutputChannel : Selection from digital output | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | +| unsigned char_ b_ModulNbr : Selected module number (0 to 3)| +| unsigned char_ b_OutputChannel : Selection from digital output | | CR_CHAN() channel (0 to 2) | | 0 : Channel H | | 1 : Channel A | @@ -1787,19 +1787,19 @@ INT i_APCI1710_ConvertChronoValue(struct comedi_device * dev, /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_SetChronoChlOff | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr, | -| BYTE_ b_OutputChannel) | +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr, | +| unsigned char_ b_OutputChannel) | +----------------------------------------------------------------------------+ | Task : Resets the output witch has been passed with the | | parameter b_Channel. Resetting an output means setting | | an output low. | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 data[0] : Chl ON, Chl OFF , Chl Read , Port Read -| BYTE_ b_ModulNbr CR_AREF : Selected module number (0 to 3)| -| BYTE_ b_OutputChannel CR_CHAN : Selection from digital output | +| unsigned char_ b_ModulNbr CR_AREF : Selected module number (0 to 3)| +| unsigned char_ b_OutputChannel CR_CHAN : Selection from digital output | | channel (0 to 2) | | 0 : Channel H | | 1 : Channel A | @@ -1820,24 +1820,24 @@ INT i_APCI1710_ConvertChronoValue(struct comedi_device * dev, /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_ReadChronoChlValue | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr, | -| BYTE_ b_InputChannel, | -| PBYTE_ pb_ChannelStatus) | +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr, | +| unsigned char_ b_InputChannel, | +| unsigned char *_ pb_ChannelStatus) | +----------------------------------------------------------------------------+ | Task : Return the status from selected digital input | | (b_InputChannel) from selected chronometer | | module (b_ModulNbr). | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | -| BYTE_ b_ModulNbr : Selected module number (0 to 3)| -| BYTE_ b_InputChannel : Selection from digital input | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | +| unsigned char_ b_ModulNbr : Selected module number (0 to 3)| +| unsigned char_ b_InputChannel : Selection from digital input | | channel (0 to 2) | | CR_CHAN() 0 : Channel E | | 1 : Channel F | | 2 : Channel G | +----------------------------------------------------------------------------+ -| Output Parameters : PBYTE_ pb_ChannelStatus : Digital input channel status.| +| Output Parameters : unsigned char *_ pb_ChannelStatus : Digital input channel status.| | data[0] 0 : Channel is not active | | 1 : Channel is active | +----------------------------------------------------------------------------+ @@ -1854,17 +1854,17 @@ INT i_APCI1710_ConvertChronoValue(struct comedi_device * dev, /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_ReadChronoPortValue | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr, | -| PBYTE_ pb_PortValue) | +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr, | +| unsigned char *_ pb_PortValue) | +----------------------------------------------------------------------------+ | Task : Return the status from digital inputs port from | | selected (b_ModulNbr) chronometer module. | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | -| BYTE_ b_ModulNbr : Selected module number (0 to 3)| +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | +| unsigned char_ b_ModulNbr : Selected module number (0 to 3)| +----------------------------------------------------------------------------+ -| Output Parameters : PBYTE_ pb_PortValue : Digital inputs port status. +| Output Parameters : unsigned char *_ pb_PortValue : Digital inputs port status. | data[0] +----------------------------------------------------------------------------+ | Return Value : 0: No error | @@ -1876,18 +1876,18 @@ INT i_APCI1710_ConvertChronoValue(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -INT i_APCI1710_InsnBitsChronoDigitalIO(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +int i_APCI1710_InsnBitsChronoDigitalIO(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - INT i_ReturnValue = 0; - BYTE b_ModulNbr, b_OutputChannel, b_InputChannel, b_IOType; - DWORD dw_Status; - PBYTE pb_ChannelStatus; - PBYTE pb_PortValue; + int i_ReturnValue = 0; + unsigned char b_ModulNbr, b_OutputChannel, b_InputChannel, b_IOType; + unsigned int dw_Status; + unsigned char *pb_ChannelStatus; + unsigned char *pb_PortValue; b_ModulNbr = CR_AREF(insn->chanspec); i_ReturnValue = insn->n; - b_IOType = (BYTE) data[0]; + b_IOType = (unsigned char) data[0]; /**************************/ /* Test the module number */ @@ -1915,14 +1915,14 @@ INT i_APCI1710_InsnBitsChronoDigitalIO(struct comedi_device * dev, case APCI1710_CHRONO_SET_CHANNELOFF: b_OutputChannel = - (BYTE) CR_CHAN(insn->chanspec); + (unsigned char) CR_CHAN(insn->chanspec); if (b_OutputChannel <= 2) { outl(0, devpriv->s_BoardInfos. ui_Address + 20 + (b_OutputChannel * 4) + (64 * b_ModulNbr)); - } // if ((b_OutputChannel >= 0) && (b_OutputChannel <= 2)) + } /* if ((b_OutputChannel >= 0) && (b_OutputChannel <= 2)) */ else { /****************************************/ /* The selected digital output is wrong */ @@ -1931,21 +1931,21 @@ INT i_APCI1710_InsnBitsChronoDigitalIO(struct comedi_device * dev, DPRINTK("The selected digital output is wrong\n"); i_ReturnValue = -4; - } // if ((b_OutputChannel >= 0) && (b_OutputChannel <= 2)) + } /* if ((b_OutputChannel >= 0) && (b_OutputChannel <= 2)) */ break; case APCI1710_CHRONO_SET_CHANNELON: b_OutputChannel = - (BYTE) CR_CHAN(insn->chanspec); + (unsigned char) CR_CHAN(insn->chanspec); if (b_OutputChannel <= 2) { outl(1, devpriv->s_BoardInfos. ui_Address + 20 + (b_OutputChannel * 4) + (64 * b_ModulNbr)); - } // if ((b_OutputChannel >= 0) && (b_OutputChannel <= 2)) + } /* if ((b_OutputChannel >= 0) && (b_OutputChannel <= 2)) */ else { /****************************************/ /* The selected digital output is wrong */ @@ -1954,7 +1954,7 @@ INT i_APCI1710_InsnBitsChronoDigitalIO(struct comedi_device * dev, DPRINTK("The selected digital output is wrong\n"); i_ReturnValue = -4; - } // if ((b_OutputChannel >= 0) && (b_OutputChannel <= 2)) + } /* if ((b_OutputChannel >= 0) && (b_OutputChannel <= 2)) */ break; @@ -1962,9 +1962,9 @@ INT i_APCI1710_InsnBitsChronoDigitalIO(struct comedi_device * dev, /**********************************/ /* Test the digital input channel */ /**********************************/ - pb_ChannelStatus = (PBYTE) & data[0]; + pb_ChannelStatus = (unsigned char *) &data[0]; b_InputChannel = - (BYTE) CR_CHAN(insn->chanspec); + (unsigned char) CR_CHAN(insn->chanspec); if (b_InputChannel <= 2) { @@ -1975,10 +1975,10 @@ INT i_APCI1710_InsnBitsChronoDigitalIO(struct comedi_device * dev, (64 * b_ModulNbr)); *pb_ChannelStatus = - (BYTE) (((dw_Status >> + (unsigned char) (((dw_Status >> b_InputChannel) & 1) ^ 1); - } // if ((b_InputChannel >= 0) && (b_InputChannel <= 2)) + } /* if ((b_InputChannel >= 0) && (b_InputChannel <= 2)) */ else { /***************************************/ /* The selected digital input is wrong */ @@ -1986,13 +1986,13 @@ INT i_APCI1710_InsnBitsChronoDigitalIO(struct comedi_device * dev, DPRINTK("The selected digital input is wrong\n"); i_ReturnValue = -4; - } // if ((b_InputChannel >= 0) && (b_InputChannel <= 2)) + } /* if ((b_InputChannel >= 0) && (b_InputChannel <= 2)) */ break; case APCI1710_CHRONO_READ_PORT: - pb_PortValue = (PBYTE) & data[0]; + pb_PortValue = (unsigned char *) &data[0]; dw_Status = inl(devpriv->s_BoardInfos. @@ -2000,7 +2000,7 @@ INT i_APCI1710_InsnBitsChronoDigitalIO(struct comedi_device * dev, (64 * b_ModulNbr)); *pb_PortValue = - (BYTE) ((dw_Status & 0x7) ^ 7); + (unsigned char) ((dw_Status & 0x7) ^ 7); break; } } else { @@ -2028,5 +2028,5 @@ INT i_APCI1710_InsnBitsChronoDigitalIO(struct comedi_device * dev, i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Chrono.h b/drivers/staging/comedi/drivers/addi-data/APCI1710_Chrono.h index 26b50cefee5a..29bad1d144a1 100644 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Chrono.h +++ b/drivers/staging/comedi/drivers/addi-data/APCI1710_Chrono.h @@ -35,10 +35,10 @@ /* * CHRONOMETER INISIALISATION FUNCTION */ -INT i_APCI1710_InsnConfigInitChrono(struct comedi_device *dev, struct comedi_subdevice *s, +int i_APCI1710_InsnConfigInitChrono(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -INT i_APCI1710_InsnWriteEnableDisableChrono(struct comedi_device *dev, +int i_APCI1710_InsnWriteEnableDisableChrono(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); @@ -46,29 +46,29 @@ INT i_APCI1710_InsnWriteEnableDisableChrono(struct comedi_device *dev, /* * CHRONOMETER READ FUNCTION */ -INT i_APCI1710_InsnReadChrono(struct comedi_device *dev, struct comedi_subdevice *s, +int i_APCI1710_InsnReadChrono(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -INT i_APCI1710_GetChronoProgressStatus(struct comedi_device *dev, - BYTE b_ModulNbr, PBYTE pb_ChronoStatus); +int i_APCI1710_GetChronoProgressStatus(struct comedi_device *dev, + unsigned char b_ModulNbr, unsigned char *pb_ChronoStatus); -INT i_APCI1710_ReadChronoValue(struct comedi_device *dev, - BYTE b_ModulNbr, - UINT ui_TimeOut, PBYTE pb_ChronoStatus, - PULONG pul_ChronoValue); +int i_APCI1710_ReadChronoValue(struct comedi_device *dev, + unsigned char b_ModulNbr, + unsigned int ui_TimeOut, unsigned char *pb_ChronoStatus, + unsigned int *pul_ChronoValue); -INT i_APCI1710_ConvertChronoValue(struct comedi_device *dev, - BYTE b_ModulNbr, - ULONG ul_ChronoValue, - PULONG pul_Hour, - PBYTE pb_Minute, - PBYTE pb_Second, - PUINT pui_MilliSecond, PUINT pui_MicroSecond, - PUINT pui_NanoSecond); +int i_APCI1710_ConvertChronoValue(struct comedi_device *dev, + unsigned char b_ModulNbr, + unsigned int ul_ChronoValue, + unsigned int *pul_Hour, + unsigned char *pb_Minute, + unsigned char *pb_Second, + unsigned int *pui_MilliSecond, unsigned int *pui_MicroSecond, + unsigned int *pui_NanoSecond); /* * CHRONOMETER DIGITAL INPUT OUTPUT FUNCTION */ -INT i_APCI1710_InsnBitsChronoDigitalIO(struct comedi_device *dev, +int i_APCI1710_InsnBitsChronoDigitalIO(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Dig_io.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_Dig_io.c index 8be27aedaaf5..f3e47e5791db 100644 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Dig_io.c +++ b/drivers/staging/comedi/drivers/addi-data/APCI1710_Dig_io.c @@ -3,13 +3,13 @@ Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data-com - info@addi-data.com + ADDI-DATA GmbH + Dieselstrasse 3 + D-77833 Ottersweier + Tel: +19(0)7223/9493-0 + Fax: +49(0)7223/9493-92 + http://www.addi-data-com + info@addi-data.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. @@ -61,7 +61,7 @@ You shoud also find the complete GPL in the COPYING file accompanying this sourc /* +----------------------------------------------------------------------------+ -| Function Name : INT i_APCI1710_InsnConfigDigitalIO(struct comedi_device *dev, | +| Function Name : int i_APCI1710_InsnConfigDigitalIO(struct comedi_device *dev, | | struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data)| +----------------------------------------------------------------------------+ | Task : Configure the digital I/O operating mode from selected | @@ -70,14 +70,14 @@ You shoud also find the complete GPL in the COPYING file accompanying this sourc | I/O. | +----------------------------------------------------------------------------+ | Input Parameters : | -| BYTE_ b_ModulNbr data[0]: Module number to | +| unsigned char_ b_ModulNbr data[0]: Module number to | | configure (0 to 3) | -| BYTE_ b_ChannelAMode data[1] : Channel A mode selection | +| unsigned char_ b_ChannelAMode data[1] : Channel A mode selection | | 0 : Channel used for digital | | input | | 1 : Channel used for digital | | output | -| BYTE_ b_ChannelBMode data[2] : Channel B mode selection | +| unsigned char_ b_ChannelBMode data[2] : Channel B mode selection | | 0 : Channel used for digital | | input | | 1 : Channel used for digital | @@ -99,19 +99,19 @@ Activates and deactivates the digital output memory. +----------------------------------------------------------------------------+ */ -INT i_APCI1710_InsnConfigDigitalIO(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI1710_InsnConfigDigitalIO(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - BYTE b_ModulNbr, b_ChannelAMode, b_ChannelBMode; - BYTE b_MemoryOnOff, b_ConfigType; - INT i_ReturnValue = 0; - DWORD dw_WriteConfig = 0; + unsigned char b_ModulNbr, b_ChannelAMode, b_ChannelBMode; + unsigned char b_MemoryOnOff, b_ConfigType; + int i_ReturnValue = 0; + unsigned int dw_WriteConfig = 0; - b_ModulNbr = (BYTE) CR_AREF(insn->chanspec); - b_ConfigType = (BYTE) data[0]; // Memory or Init - b_ChannelAMode = (BYTE) data[1]; - b_ChannelBMode = (BYTE) data[2]; - b_MemoryOnOff = (BYTE) data[1]; // if memory operation + b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); + b_ConfigType = (unsigned char) data[0]; /* Memory or Init */ + b_ChannelAMode = (unsigned char) data[1]; + b_ChannelBMode = (unsigned char) data[2]; + b_MemoryOnOff = (unsigned char) data[1]; /* if memory operation */ i_ReturnValue = insn->n; /**************************/ @@ -126,7 +126,7 @@ INT i_APCI1710_InsnConfigDigitalIO(struct comedi_device * dev, struct comedi_sub switch (b_ConfigType) { case APCI1710_DIGIO_MEMORYONOFF: - if (b_MemoryOnOff) // If Memory ON + if (b_MemoryOnOff) /* If Memory ON */ { /****************************/ /* Set the output memory on */ @@ -140,7 +140,7 @@ INT i_APCI1710_InsnConfigDigitalIO(struct comedi_device * dev, struct comedi_sub /***************************/ devpriv->s_ModuleInfo[b_ModulNbr]. s_DigitalIOInfo.dw_OutputMemory = 0; - } else // If memory off + } else /* If memory off */ { /*****************************/ /* Set the output memory off */ @@ -197,7 +197,7 @@ INT i_APCI1710_InsnConfigDigitalIO(struct comedi_device * dev, struct comedi_sub /*****************************************/ dw_WriteConfig = - (DWORD) (b_ChannelAMode | + (unsigned int) (b_ChannelAMode | (b_ChannelBMode * 2)); /***************************/ @@ -233,7 +233,7 @@ INT i_APCI1710_InsnConfigDigitalIO(struct comedi_device * dev, struct comedi_sub DPRINTK("The module is not a digital I/O module\n"); i_ReturnValue = -3; } - } // end of Switch + } /* end of Switch */ printk("Return Value %d\n", i_ReturnValue); return i_ReturnValue; } @@ -257,9 +257,9 @@ INT i_APCI1710_InsnConfigDigitalIO(struct comedi_device * dev, struct comedi_sub | -| BYTE_ b_ModulNbr CR_AREF(chanspec) : Selected module number | +| unsigned char_ b_ModulNbr CR_AREF(chanspec) : Selected module number | | (0 to 3) | -| BYTE_ b_InputChannel CR_CHAN(chanspec) : Selection from digital | +| unsigned char_ b_InputChannel CR_CHAN(chanspec) : Selection from digital | | input ( 0 to 6) | | 0 : Channel C | | 1 : Channel D | @@ -288,22 +288,22 @@ INT i_APCI1710_InsnConfigDigitalIO(struct comedi_device * dev, struct comedi_sub +----------------------------------------------------------------------------+ */ -//_INT_ i_APCI1710_ReadDigitalIOChlValue (BYTE_ b_BoardHandle, -// BYTE_ b_ModulNbr, -// BYTE_ b_InputChannel, -// -// PBYTE_ pb_ChannelStatus) -INT i_APCI1710_InsnReadDigitalIOChlValue(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +/* _INT_ i_APCI1710_ReadDigitalIOChlValue (unsigned char_ b_BoardHandle, */ +/* +* unsigned char_ b_ModulNbr, unsigned char_ b_InputChannel, +* unsigned char *_ pb_ChannelStatus) +*/ +int i_APCI1710_InsnReadDigitalIOChlValue(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - INT i_ReturnValue = 0; - DWORD dw_StatusReg; - BYTE b_ModulNbr, b_InputChannel; - PBYTE pb_ChannelStatus; - b_ModulNbr = (BYTE) CR_AREF(insn->chanspec); - b_InputChannel = (BYTE) CR_CHAN(insn->chanspec); + int i_ReturnValue = 0; + unsigned int dw_StatusReg; + unsigned char b_ModulNbr, b_InputChannel; + unsigned char *pb_ChannelStatus; + b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); + b_InputChannel = (unsigned char) CR_CHAN(insn->chanspec); data[0] = 0; - pb_ChannelStatus = (PBYTE) & data[0]; + pb_ChannelStatus = (unsigned char *) &data[0]; i_ReturnValue = insn->n; /**************************/ @@ -356,7 +356,7 @@ INT i_APCI1710_InsnReadDigitalIOChlValue(struct comedi_device * dev, i_ReturnValue = -6; } - } // if (b_InputChannel == 5) + } /* if (b_InputChannel == 5) */ else { /***************************/ /* Test the channel B mode */ @@ -375,8 +375,8 @@ INT i_APCI1710_InsnReadDigitalIOChlValue(struct comedi_device * dev, i_ReturnValue = -7; } - } // if (b_InputChannel == 5) - } // if (b_InputChannel > 4) + } /* if (b_InputChannel == 5) */ + } /* if (b_InputChannel > 4) */ /***********************/ /* Test if error occur */ @@ -387,11 +387,10 @@ INT i_APCI1710_InsnReadDigitalIOChlValue(struct comedi_device * dev, /* Read all digital input */ /**************************/ - //INPDW (ps_APCI1710Variable-> - // s_Board [b_BoardHandle]. - // s_BoardInfos. - // ui_Address + (64 * b_ModulNbr), - // &dw_StatusReg); +/* +* INPDW (ps_APCI1710Variable-> s_Board [b_BoardHandle]. +* s_BoardInfos. ui_Address + (64 * b_ModulNbr), &dw_StatusReg); +*/ dw_StatusReg = inl(devpriv-> @@ -400,11 +399,11 @@ INT i_APCI1710_InsnReadDigitalIOChlValue(struct comedi_device * dev, (64 * b_ModulNbr)); *pb_ChannelStatus = - (BYTE) ((dw_StatusReg ^ + (unsigned char) ((dw_StatusReg ^ 0x1C) >> b_InputChannel) & 1; - } // if (i_ReturnValue == 0) + } /* if (i_ReturnValue == 0) */ } else { /*******************************/ /* Digital I/O not initialised */ @@ -434,7 +433,7 @@ INT i_APCI1710_InsnReadDigitalIOChlValue(struct comedi_device * dev, i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* @@ -445,7 +444,7 @@ INT i_APCI1710_InsnReadDigitalIOChlValue(struct comedi_device * dev, /* +----------------------------------------------------------------------------+ -| Function Name : INT i_APCI1710_InsnWriteDigitalIOChlOnOff(comedi_device +| Function Name : int i_APCI1710_InsnWriteDigitalIOChlOnOff(comedi_device |*dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) +----------------------------------------------------------------------------+ @@ -453,9 +452,9 @@ INT i_APCI1710_InsnReadDigitalIOChlValue(struct comedi_device * dev, | parameter b_Channel. Setting an output means setting | | an ouput high. | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | -| BYTE_ b_ModulNbr (aref ) : Selected module number (0 to 3)| -| BYTE_ b_OutputChannel (CR_CHAN) : Selection from digital output | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | +| unsigned char_ b_ModulNbr (aref ) : Selected module number (0 to 3)| +| unsigned char_ b_OutputChannel (CR_CHAN) : Selection from digital output | | channel (0 to 2) | | 0 : Channel H | | 1 : Channel A | @@ -478,15 +477,16 @@ INT i_APCI1710_InsnReadDigitalIOChlValue(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -//_INT_ i_APCI1710_SetDigitalIOChlOn (BYTE_ b_BoardHandle, -// BYTE_ b_ModulNbr, -// BYTE_ b_OutputChannel) -INT i_APCI1710_InsnWriteDigitalIOChlOnOff(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +/* +* _INT_ i_APCI1710_SetDigitalIOChlOn (unsigned char_ b_BoardHandle, +* unsigned char_ b_ModulNbr, unsigned char_ b_OutputChannel) +*/ +int i_APCI1710_InsnWriteDigitalIOChlOnOff(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - INT i_ReturnValue = 0; - DWORD dw_WriteValue = 0; - BYTE b_ModulNbr, b_OutputChannel; + int i_ReturnValue = 0; + unsigned int dw_WriteValue = 0; + unsigned char b_ModulNbr, b_OutputChannel; i_ReturnValue = insn->n; b_ModulNbr = CR_AREF(insn->chanspec); b_OutputChannel = CR_CHAN(insn->chanspec); @@ -602,7 +602,7 @@ INT i_APCI1710_InsnWriteDigitalIOChlOnOff(struct comedi_device * dev, 1 << b_OutputChannel; } - } // set channel off + } /* set channel off */ else { if (devpriv-> s_ModuleInfo @@ -627,23 +627,24 @@ INT i_APCI1710_InsnWriteDigitalIOChlOnOff(struct comedi_device * dev, dw_OutputMemory = dw_WriteValue; } else { - /*****************************/ + /*****************************/ /* Digital Output Memory OFF */ - /*****************************/ - // +Use previously the function "i_APCI1710_SetDigitalIOMemoryOn" + /*****************************/ + /* +Use previously the function "i_APCI1710_SetDigitalIOMemoryOn" */ i_ReturnValue = -8; } } - /*******************/ + /*******************/ /* Write the value */ - /*******************/ + /*******************/ - //OUTPDW (ps_APCI1710Variable-> - // s_Board [b_BoardHandle]. - // s_BoardInfos. - // ui_Address + (64 * b_ModulNbr), - // dw_WriteValue); + /* OUTPDW (ps_APCI1710Variable-> + * s_Board [b_BoardHandle]. + * s_BoardInfos. ui_Address + (64 * b_ModulNbr), + * dw_WriteValue); + */ +*/ outl(dw_WriteValue, devpriv->s_BoardInfos. ui_Address + (64 * b_ModulNbr)); @@ -670,7 +671,7 @@ INT i_APCI1710_InsnWriteDigitalIOChlOnOff(struct comedi_device * dev, i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* @@ -690,19 +691,19 @@ INT i_APCI1710_InsnWriteDigitalIOChlOnOff(struct comedi_device * dev, | from selected digital I/O module (b_ModulNbr) +----------------------------------------------------------------------------+ | Input Parameters : - BYTE_ b_BoardHandle : Handle of board APCI-1710 | -| BYTE_ b_ModulNbr CR_AREF(aref) : Selected module number (0 to 3)| -| BYTE_ b_PortValue CR_CHAN(chanspec) : Output Value ( 0 To 7 ) + unsigned char_ b_BoardHandle : Handle of board APCI-1710 | +| unsigned char_ b_ModulNbr CR_AREF(aref) : Selected module number (0 to 3)| +| unsigned char_ b_PortValue CR_CHAN(chanspec) : Output Value ( 0 To 7 ) | data[0] read or write port - data[1] if write then indicate ON or OFF +| data[1] if write then indicate ON or OFF - if read : data[1] will return port status. +| if read : data[1] will return port status. +----------------------------------------------------------------------------+ | Output Parameters : - | +----------------------------------------------------------------------------+ | Return Value : - INPUT : +| INPUT : 0: No error | | -1: The handle parameter of the board is wrong | @@ -725,75 +726,78 @@ INT i_APCI1710_InsnWriteDigitalIOChlOnOff(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -//_INT_ i_APCI1710_SetDigitalIOPortOn (BYTE_ b_BoardHandle, -// BYTE_ b_ModulNbr, -// BYTE_ b_PortValue) -INT i_APCI1710_InsnBitsDigitalIOPortOnOff(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +/* + * _INT_ i_APCI1710_SetDigitalIOPortOn (unsigned char_ + * b_BoardHandle, unsigned char_ b_ModulNbr, unsigned char_ + * b_PortValue) +*/ +int i_APCI1710_InsnBitsDigitalIOPortOnOff(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - INT i_ReturnValue = 0; - DWORD dw_WriteValue = 0; - DWORD dw_StatusReg; - BYTE b_ModulNbr, b_PortValue; - BYTE b_PortOperation, b_PortOnOFF; + int i_ReturnValue = 0; + unsigned int dw_WriteValue = 0; + unsigned int dw_StatusReg; + unsigned char b_ModulNbr, b_PortValue; + unsigned char b_PortOperation, b_PortOnOFF; - PBYTE pb_PortValue; + unsigned char *pb_PortValue; - b_ModulNbr = (BYTE) CR_AREF(insn->chanspec); - b_PortOperation = (BYTE) data[0]; // Input or output - b_PortOnOFF = (BYTE) data[1]; // if output then On or Off - b_PortValue = (BYTE) data[2]; // if out put then Value + b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); + b_PortOperation = (unsigned char) data[0]; /* Input or output */ + b_PortOnOFF = (unsigned char) data[1]; /* if output then On or Off */ + b_PortValue = (unsigned char) data[2]; /* if out put then Value */ i_ReturnValue = insn->n; - pb_PortValue = (PBYTE) & data[0]; -// if input then read value + pb_PortValue = (unsigned char *) &data[0]; +/* if input then read value */ switch (b_PortOperation) { case APCI1710_INPUT: - /**************************/ + /**************************/ /* Test the module number */ - /**************************/ + /**************************/ if (b_ModulNbr < 4) { - /*******************************/ + /*******************************/ /* Test if digital I/O counter */ - /*******************************/ + /*******************************/ if ((devpriv->s_BoardInfos. dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF0000UL) == APCI1710_DIGITAL_IO) { - /**********************************************/ + /**********************************************/ /* Test if the digital I/O module initialised */ - /**********************************************/ + /**********************************************/ if (devpriv->s_ModuleInfo[b_ModulNbr]. s_DigitalIOInfo.b_DigitalInit == 1) { - /**************************/ + /**************************/ /* Read all digital input */ - /**************************/ + /**************************/ - //INPDW (ps_APCI1710Variable-> - // s_Board [b_BoardHandle]. - // s_BoardInfos. - // ui_Address + (64 * b_ModulNbr), - // &dw_StatusReg); + /* INPDW (ps_APCI1710Variable-> + * s_Board [b_BoardHandle]. + * s_BoardInfos. + * ui_Address + (64 * b_ModulNbr), + * &dw_StatusReg); + */ dw_StatusReg = inl(devpriv->s_BoardInfos. ui_Address + (64 * b_ModulNbr)); *pb_PortValue = - (BYTE) (dw_StatusReg ^ 0x1C); + (unsigned char) (dw_StatusReg ^ 0x1C); } else { - /*******************************/ + /*******************************/ /* Digital I/O not initialised */ - /*******************************/ + /*******************************/ i_ReturnValue = -4; } } else { - /******************************************/ + /******************************************/ /* The module is not a digital I/O module */ - /******************************************/ + /******************************************/ i_ReturnValue = -3; } @@ -853,11 +857,11 @@ INT i_APCI1710_InsnBitsDigitalIOPortOnOff(struct comedi_device * dev, i_ReturnValue = -6; } - } // if ((b_PortValue & 2) == 2) + } /* if ((b_PortValue & 2) == 2) */ - /**************************/ + /**************************/ /* Test if channel B used */ - /**************************/ + /**************************/ if ((b_PortValue & 4) == 4) { if (devpriv-> @@ -866,33 +870,33 @@ INT i_APCI1710_InsnBitsDigitalIOPortOnOff(struct comedi_device * dev, s_DigitalIOInfo. b_ChannelBMode != 1) { - /*******************************************/ + /*******************************************/ /* The digital channel B is used for input */ - /*******************************************/ + /*******************************************/ i_ReturnValue = -7; } - } // if ((b_PortValue & 4) == 4) + } /* if ((b_PortValue & 4) == 4) */ - /***********************/ + /***********************/ /* Test if error occur */ - /***********************/ + /***********************/ if (i_ReturnValue >= 0) { - //if(data[1]) - //{ + /* if(data[1]) { */ + switch (b_PortOnOFF) { - /*********************************/ + /*********************************/ /* Test if set Port ON */ - /*********************************/ + /*********************************/ case APCI1710_ON: - /*********************************/ + /*********************************/ /* Test if output memory enabled */ - /*********************************/ + /*********************************/ if (devpriv-> s_ModuleInfo @@ -924,7 +928,7 @@ INT i_APCI1710_InsnBitsDigitalIOPortOnOff(struct comedi_device * dev, } break; - // If Set PORT OFF + /* If Set PORT OFF */ case APCI1710_OFF: /*********************************/ @@ -957,25 +961,26 @@ INT i_APCI1710_InsnBitsDigitalIOPortOnOff(struct comedi_device * dev, = dw_WriteValue; } else { - /*****************************/ + /*****************************/ /* Digital Output Memory OFF */ - /*****************************/ + /*****************************/ i_ReturnValue = -8; } - } // switch + } /* switch */ - /*******************/ + /*******************/ /* Write the value */ - /*******************/ + /*******************/ + + /* OUTPDW (ps_APCI1710Variable-> + * s_Board [b_BoardHandle]. + * s_BoardInfos. + * ui_Address + (64 * b_ModulNbr), + * dw_WriteValue); */ - // OUTPDW (ps_APCI1710Variable-> - // s_Board [b_BoardHandle]. - // s_BoardInfos. - // ui_Address + (64 * b_ModulNbr), - // dw_WriteValue); outl(dw_WriteValue, devpriv-> s_BoardInfos. @@ -983,16 +988,16 @@ INT i_APCI1710_InsnBitsDigitalIOPortOnOff(struct comedi_device * dev, (64 * b_ModulNbr)); } } else { - /**********************/ + /**********************/ /* Output value wrong */ - /**********************/ + /**********************/ i_ReturnValue = -4; } } else { - /*******************************/ + /*******************************/ /* Digital I/O not initialised */ - /*******************************/ + /*******************************/ i_ReturnValue = -5; } @@ -1015,6 +1020,6 @@ INT i_APCI1710_InsnBitsDigitalIOPortOnOff(struct comedi_device * dev, default: i_ReturnValue = -9; DPRINTK("NO INPUT/OUTPUT specified\n"); - } //switch INPUT / OUTPUT - return (i_ReturnValue); + } /* switch INPUT / OUTPUT */ + return i_ReturnValue; } diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Dig_io.h b/drivers/staging/comedi/drivers/addi-data/APCI1710_Dig_io.h index 5ef157a55ca1..af1b9cdecfb3 100644 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Dig_io.h +++ b/drivers/staging/comedi/drivers/addi-data/APCI1710_Dig_io.h @@ -27,20 +27,20 @@ /* * DIGITAL I/O INISIALISATION FUNCTION */ -INT i_APCI1710_InsnConfigDigitalIO(struct comedi_device *dev, struct comedi_subdevice *s, +int i_APCI1710_InsnConfigDigitalIO(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); /* * INPUT OUTPUT FUNCTIONS */ -INT i_APCI1710_InsnReadDigitalIOChlValue(struct comedi_device *dev, +int i_APCI1710_InsnReadDigitalIOChlValue(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -INT i_APCI1710_InsnWriteDigitalIOChlOnOff(struct comedi_device *dev, +int i_APCI1710_InsnWriteDigitalIOChlOnOff(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -INT i_APCI1710_InsnBitsDigitalIOPortOnOff(struct comedi_device *dev, +int i_APCI1710_InsnBitsDigitalIOPortOnOff(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_INCCPT.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_INCCPT.c index 1062f2fdec30..6c092efee7bd 100644 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_INCCPT.c +++ b/drivers/staging/comedi/drivers/addi-data/APCI1710_INCCPT.c @@ -3,13 +3,13 @@ Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data-com - info@addi-data.com + ADDI-DATA GmbH + Dieselstrasse 3 + D-77833 Ottersweier + Tel: +19(0)7223/9493-0 + Fax: +49(0)7223/9493-92 + http://www.addi-data-com + info@addi-data.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. @@ -61,7 +61,7 @@ You shoud also find the complete GPL in the COPYING file accompanying this sourc /* +----------------------------------------------------------------------------+ -| INT i_APCI1710_InsnConfigINCCPT(struct comedi_device *dev,struct comedi_subdevice *s, +| int i_APCI1710_InsnConfigINCCPT(struct comedi_device *dev,struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data) +----------------------------------------------------------------------------+ @@ -75,58 +75,58 @@ struct comedi_insn *insn,unsigned int *data) +----------------------------------------------------------------------------+ */ -INT i_APCI1710_InsnConfigINCCPT(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI1710_InsnConfigINCCPT(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - UINT ui_ConfigType; - INT i_ReturnValue = 0; + unsigned int ui_ConfigType; + int i_ReturnValue = 0; ui_ConfigType = CR_CHAN(insn->chanspec); printk("\nINC_CPT"); - devpriv->tsk_Current = current; // Save the current process task structure + devpriv->tsk_Current = current; /* Save the current process task structure */ switch (ui_ConfigType) { case APCI1710_INCCPT_INITCOUNTER: i_ReturnValue = i_APCI1710_InitCounter(dev, CR_AREF(insn->chanspec), - (BYTE) data[0], - (BYTE) data[1], - (BYTE) data[2], (BYTE) data[3], (BYTE) data[4]); + (unsigned char) data[0], + (unsigned char) data[1], + (unsigned char) data[2], (unsigned char) data[3], (unsigned char) data[4]); break; case APCI1710_INCCPT_COUNTERAUTOTEST: i_ReturnValue = i_APCI1710_CounterAutoTest(dev, - (PBYTE) & data[0]); + (unsigned char *) &data[0]); break; case APCI1710_INCCPT_INITINDEX: i_ReturnValue = i_APCI1710_InitIndex(dev, CR_AREF(insn->chanspec), - (BYTE) data[0], - (BYTE) data[1], (BYTE) data[2], (BYTE) data[3]); + (unsigned char) data[0], + (unsigned char) data[1], (unsigned char) data[2], (unsigned char) data[3]); break; case APCI1710_INCCPT_INITREFERENCE: i_ReturnValue = i_APCI1710_InitReference(dev, - CR_AREF(insn->chanspec), (BYTE) data[0]); + CR_AREF(insn->chanspec), (unsigned char) data[0]); break; case APCI1710_INCCPT_INITEXTERNALSTROBE: i_ReturnValue = i_APCI1710_InitExternalStrobe(dev, CR_AREF(insn->chanspec), - (BYTE) data[0], (BYTE) data[1]); + (unsigned char) data[0], (unsigned char) data[1]); break; case APCI1710_INCCPT_INITCOMPARELOGIC: i_ReturnValue = i_APCI1710_InitCompareLogic(dev, - CR_AREF(insn->chanspec), (UINT) data[0]); + CR_AREF(insn->chanspec), (unsigned int) data[0]); break; case APCI1710_INCCPT_INITFREQUENCYMEASUREMENT: i_ReturnValue = i_APCI1710_InitFrequencyMeasurement(dev, CR_AREF(insn->chanspec), - (BYTE) data[0], - (BYTE) data[1], (ULONG) data[2], (PULONG) & data[0]); + (unsigned char) data[0], + (unsigned char) data[1], (unsigned int) data[2], (unsigned int *) &data[0]); break; default: @@ -136,19 +136,19 @@ INT i_APCI1710_InsnConfigINCCPT(struct comedi_device * dev, struct comedi_subdev if (i_ReturnValue >= 0) i_ReturnValue = insn->n; - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_InitCounter | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr, | -| BYTE_ b_CounterRange, | -| BYTE_ b_FirstCounterModus, | -| BYTE_ b_FirstCounterOption, | -| BYTE_ b_SecondCounterModus, | -| BYTE_ b_SecondCounterOption) | +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr, | +| unsigned char_ b_CounterRange, | +| unsigned char_ b_FirstCounterModus, | +| unsigned char_ b_FirstCounterOption, | +| unsigned char_ b_SecondCounterModus, | +| unsigned char_ b_SecondCounterOption) | +----------------------------------------------------------------------------+ | Task : Configure the counter operating mode from selected | | module (b_ModulNbr). You must calling this function be | @@ -273,17 +273,17 @@ INT i_APCI1710_InsnConfigINCCPT(struct comedi_device * dev, struct comedi_subdev | +----------------------+--------------------+----------------------------+ | | | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710| -| BYTE_ b_ModulNbr : Module number to | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710| +| unsigned char_ b_ModulNbr : Module number to | | configure (0 to 3) | -| BYTE_ b_CounterRange : Selection form counter | +| unsigned char_ b_CounterRange : Selection form counter | | range. | -| BYTE_ b_FirstCounterModus : First counter operating | +| unsigned char_ b_FirstCounterModus : First counter operating | | mode. | -| BYTE_ b_FirstCounterOption : First counter option. | -| BYTE_ b_SecondCounterModus : Second counter operating | +| unsigned char_ b_FirstCounterOption : First counter option. | +| unsigned char_ b_SecondCounterModus : Second counter operating | | mode. | -| BYTE_ b_SecondCounterOption : Second counter option. | +| unsigned char_ b_SecondCounterOption : Second counter option. | +----------------------------------------------------------------------------+ | Output Parameters : - | +----------------------------------------------------------------------------+ @@ -299,14 +299,14 @@ INT i_APCI1710_InsnConfigINCCPT(struct comedi_device * dev, struct comedi_subdev +----------------------------------------------------------------------------+ */ -INT i_APCI1710_InitCounter(struct comedi_device * dev, - BYTE b_ModulNbr, - BYTE b_CounterRange, - BYTE b_FirstCounterModus, - BYTE b_FirstCounterOption, - BYTE b_SecondCounterModus, BYTE b_SecondCounterOption) +int i_APCI1710_InitCounter(struct comedi_device *dev, + unsigned char b_ModulNbr, + unsigned char b_CounterRange, + unsigned char b_FirstCounterModus, + unsigned char b_FirstCounterOption, + unsigned char b_SecondCounterModus, unsigned char b_SecondCounterOption) { - INT i_ReturnValue = 0; + int i_ReturnValue = 0; /*******************************/ /* Test if incremental counter */ @@ -502,14 +502,14 @@ INT i_APCI1710_InitCounter(struct comedi_device * dev, i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_CounterAutoTest | -| (BYTE_ b_BoardHandle, | -| PBYTE_ pb_TestStatus) | +| (unsigned char_ b_BoardHandle, | +| unsigned char *_ pb_TestStatus) | +----------------------------------------------------------------------------+ | Task : A test mode is intended for testing the component and | | the connected periphery. All the 8-bit counter chains | @@ -535,9 +535,9 @@ INT i_APCI1710_InitCounter(struct comedi_device * dev, | | 1000 | Error detected of counter 3 | | | +-----------------+-----------------------------+ | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | | +----------------------------------------------------------------------------+ -| Output Parameters : PBYTE_ pb_TestStatus : Auto test conclusion. See table| +| Output Parameters : unsigned char *_ pb_TestStatus : Auto test conclusion. See table| +----------------------------------------------------------------------------+ | Return Value : 0: No error | | -1: The handle parameter of the board is wrong | @@ -545,11 +545,11 @@ INT i_APCI1710_InitCounter(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -INT i_APCI1710_CounterAutoTest(struct comedi_device * dev, PBYTE pb_TestStatus) +int i_APCI1710_CounterAutoTest(struct comedi_device *dev, unsigned char *pb_TestStatus) { - BYTE b_ModulCpt = 0; - INT i_ReturnValue = 0; - DWORD dw_LathchValue; + unsigned char b_ModulCpt = 0; + int i_ReturnValue = 0; + unsigned int dw_LathchValue; *pb_TestStatus = 0; @@ -627,17 +627,17 @@ INT i_APCI1710_CounterAutoTest(struct comedi_device * dev, PBYTE pb_TestStatus) i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_InitIndex (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr, | -| BYTE_ b_ReferenceAction, | -| BYTE_ b_IndexOperation, | -| BYTE_ b_AutoMode, | -| BYTE_ b_InterruptEnable) | +| Function Name : _INT_ i_APCI1710_InitIndex (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr, | +| unsigned char_ b_ReferenceAction, | +| unsigned char_ b_IndexOperation, | +| unsigned char_ b_AutoMode, | +| unsigned char_ b_InterruptEnable) | +----------------------------------------------------------------------------+ | Task : Initialise the index corresponding to the selected | | module (b_ModulNbr). If a INDEX flag occur, you have | @@ -665,10 +665,10 @@ INT i_APCI1710_CounterAutoTest(struct comedi_device * dev, PBYTE pb_TestStatus) | | | value is cleared (32-Bit) | | | +------------------------+------------------------------------+ | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | -| BYTE_ b_ModulNbr : Module number to configure | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | +| unsigned char_ b_ModulNbr : Module number to configure | | (0 to 3) | -| BYTE_ b_ReferenceAction : Determine if the reference | +| unsigned char_ b_ReferenceAction : Determine if the reference | | must set or no for the | | acceptance from index | | APCI1710_ENABLE : | @@ -677,15 +677,15 @@ INT i_APCI1710_CounterAutoTest(struct comedi_device * dev, PBYTE pb_TestStatus) | APCI1710_DISABLE : | | Reference have not | | importance | -| BYTE_ b_IndexOperation : Index operating mode. | +| unsigned char_ b_IndexOperation : Index operating mode. | | See table. | -| BYTE_ b_AutoMode : Enable or disable the | +| unsigned char_ b_AutoMode : Enable or disable the | | automatic index reset. | | APCI1710_ENABLE : | | Enable the automatic mode | | APCI1710_DISABLE : | | Disable the automatic mode | -| BYTE_ b_InterruptEnable : Enable or disable the | +| unsigned char_ b_InterruptEnable : Enable or disable the | | interrupt. | | APCI1710_ENABLE : | | Enable the interrupt | @@ -708,12 +708,12 @@ INT i_APCI1710_CounterAutoTest(struct comedi_device * dev, PBYTE pb_TestStatus) +----------------------------------------------------------------------------+ */ -INT i_APCI1710_InitIndex(struct comedi_device * dev, - BYTE b_ModulNbr, - BYTE b_ReferenceAction, - BYTE b_IndexOperation, BYTE b_AutoMode, BYTE b_InterruptEnable) +int i_APCI1710_InitIndex(struct comedi_device *dev, + unsigned char b_ModulNbr, + unsigned char b_ReferenceAction, + unsigned char b_IndexOperation, unsigned char b_AutoMode, unsigned char b_InterruptEnable) { - INT i_ReturnValue = 0; + int i_ReturnValue = 0; /**************************/ /* Test the module number */ @@ -902,7 +902,7 @@ INT i_APCI1710_InitIndex(struct comedi_device * dev, b_ModeRegister4 | APCI1710_ENABLE_LATCH_AND_CLEAR; - } // if (b_IndexOperation == APCI1710_HIGH_EDGE_LATCH_AND_CLEAR_COUNTER || b_IndexOperation == APCI1710_LOW_EDGE_LATCH_AND_CLEAR_COUNTER) + } /* if (b_IndexOperation == APCI1710_HIGH_EDGE_LATCH_AND_CLEAR_COUNTER || b_IndexOperation == APCI1710_LOW_EDGE_LATCH_AND_CLEAR_COUNTER) */ else { /*****************************************/ /* Clear the latch and clear flag (DQ27) */ @@ -975,7 +975,7 @@ INT i_APCI1710_InitIndex(struct comedi_device * dev, & (~APCI1710_INDEX_LATCH_COUNTER); } - } // // if (b_IndexOperation == APCI1710_HIGH_EDGE_LATCH_AND_CLEAR_COUNTER || b_IndexOperation == APCI1710_LOW_EDGE_LATCH_AND_CLEAR_COUNTER) + } /* // if (b_IndexOperation == APCI1710_HIGH_EDGE_LATCH_AND_CLEAR_COUNTER || b_IndexOperation == APCI1710_LOW_EDGE_LATCH_AND_CLEAR_COUNTER) */ if (b_AutoMode == APCI1710_DISABLE) @@ -1113,15 +1113,15 @@ INT i_APCI1710_InitIndex(struct comedi_device * dev, i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_InitReference | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr, | -| BYTE_ b_ReferenceLevel) | +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr, | +| unsigned char_ b_ReferenceLevel) | +----------------------------------------------------------------------------+ | Task : Initialise the reference corresponding to the selected | | module (b_ModulNbr). | @@ -1136,10 +1136,10 @@ INT i_APCI1710_InitIndex(struct comedi_device * dev, | | APCI1710_HIGH | Reference occur if "1" | | | +--------------------+-------------------------+ | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | -| BYTE_ b_ModulNbr : Module number to configure | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | +| unsigned char_ b_ModulNbr : Module number to configure | | (0 to 3) | -| BYTE_ b_ReferenceLevel : Reference level. | +| unsigned char_ b_ReferenceLevel : Reference level. | +----------------------------------------------------------------------------+ | Output Parameters : - | +----------------------------------------------------------------------------+ @@ -1152,10 +1152,10 @@ INT i_APCI1710_InitIndex(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -INT i_APCI1710_InitReference(struct comedi_device * dev, - BYTE b_ModulNbr, BYTE b_ReferenceLevel) +int i_APCI1710_InitReference(struct comedi_device *dev, + unsigned char b_ModulNbr, unsigned char b_ReferenceLevel) { - INT i_ReturnValue = 0; + int i_ReturnValue = 0; /**************************/ /* Test the module number */ @@ -1239,27 +1239,27 @@ INT i_APCI1710_InitReference(struct comedi_device * dev, i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_InitExternalStrobe | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr, | -| BYTE_ b_ExternalStrobe, | -| BYTE_ b_ExternalStrobeLevel) | +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr, | +| unsigned char_ b_ExternalStrobe, | +| unsigned char_ b_ExternalStrobeLevel) | +----------------------------------------------------------------------------+ | Task : Initialises the external strobe level corresponding to | | the selected module (b_ModulNbr). | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | -| BYTE_ b_ModulNbr : Module number to configure | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | +| unsigned char_ b_ModulNbr : Module number to configure | | (0 to 3) | -| BYTE_ b_ExternalStrobe : External strobe selection | +| unsigned char_ b_ExternalStrobe : External strobe selection | | 0 : External strobe A | | 1 : External strobe B | -| BYTE_ b_ExternalStrobeLevel : External strobe level | +| unsigned char_ b_ExternalStrobeLevel : External strobe level | | APCI1710_LOW : | | External latch occurs if "0" | | APCI1710_HIGH : | @@ -1277,10 +1277,10 @@ INT i_APCI1710_InitReference(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -INT i_APCI1710_InitExternalStrobe(struct comedi_device * dev, - BYTE b_ModulNbr, BYTE b_ExternalStrobe, BYTE b_ExternalStrobeLevel) +int i_APCI1710_InitExternalStrobe(struct comedi_device *dev, + unsigned char b_ModulNbr, unsigned char b_ExternalStrobe, unsigned char b_ExternalStrobeLevel) { - INT i_ReturnValue = 0; + int i_ReturnValue = 0; /**************************/ /* Test the module number */ @@ -1335,7 +1335,7 @@ INT i_APCI1710_InitExternalStrobe(struct comedi_device * dev, DPRINTK("External strobe level parameter is wrong\n"); i_ReturnValue = -5; } - } // if (b_ExternalStrobe == 0 || b_ExternalStrobe == 1) + } /* if (b_ExternalStrobe == 0 || b_ExternalStrobe == 1) */ else { /**************************************/ /* External strobe selection is wrong */ @@ -1343,7 +1343,7 @@ INT i_APCI1710_InitExternalStrobe(struct comedi_device * dev, DPRINTK("External strobe selection is wrong\n"); i_ReturnValue = -4; - } // if (b_ExternalStrobe == 0 || b_ExternalStrobe == 1) + } /* if (b_ExternalStrobe == 0 || b_ExternalStrobe == 1) */ } else { /****************************************/ /* Counter not initialised see function */ @@ -1362,24 +1362,24 @@ INT i_APCI1710_InitExternalStrobe(struct comedi_device * dev, i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_InitCompareLogic | - | (BYTE_ b_BoardHandle, | - | BYTE_ b_ModulNbr, | - | UINT_ ui_CompareValue) | + | (unsigned char_ b_BoardHandle, | + | unsigned char_ b_ModulNbr, | + | unsigned int_ ui_CompareValue) | +----------------------------------------------------------------------------+ | Task : Set the 32-Bit compare value. At that moment that the | | incremental counter arrive to the compare value | | (ui_CompareValue) a interrupt is generated. | +----------------------------------------------------------------------------+ - | Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | - | BYTE_ b_ModulNbr : Module number to configure | + | Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | + | unsigned char_ b_ModulNbr : Module number to configure | | (0 to 3) | - | UINT_ ui_CompareValue : 32-Bit compare value | + | unsigned int_ ui_CompareValue : 32-Bit compare value | +----------------------------------------------------------------------------+ | Output Parameters : - +----------------------------------------------------------------------------+ @@ -1391,10 +1391,10 @@ INT i_APCI1710_InitExternalStrobe(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -INT i_APCI1710_InitCompareLogic(struct comedi_device * dev, - BYTE b_ModulNbr, UINT ui_CompareValue) +int i_APCI1710_InitCompareLogic(struct comedi_device *dev, + unsigned char b_ModulNbr, unsigned int ui_CompareValue) { - INT i_ReturnValue = 0; + int i_ReturnValue = 0; /**************************/ /* Test the module number */ @@ -1434,16 +1434,16 @@ INT i_APCI1710_InitCompareLogic(struct comedi_device * dev, i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_InitFrequencyMeasurement | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr, | -| BYTE_ b_PCIInputClock, | -| BYTE_ b_TimingUnity, | +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr, | +| unsigned char_ b_PCIInputClock, | +| unsigned char_ b_TimingUnity, | | ULONG_ ul_TimingInterval, | | PULONG_ pul_RealTimingInterval) | +----------------------------------------------------------------------------+ @@ -1456,10 +1456,10 @@ INT i_APCI1710_InitCompareLogic(struct comedi_device * dev, | you call up any other function which gives access to | | the frequency measurement. | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | -| BYTE_ b_ModulNbr : Number of the module to be | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | +| unsigned char_ b_ModulNbr : Number of the module to be | | configured (0 to 3) | -| BYTE_ b_PCIInputClock : Selection of the PCI bus | +| unsigned char_ b_PCIInputClock : Selection of the PCI bus | | clock | | - APCI1710_30MHZ : | | The PC has a PCI bus clock | @@ -1467,7 +1467,7 @@ INT i_APCI1710_InitCompareLogic(struct comedi_device * dev, | - APCI1710_33MHZ : | | The PC has a PCI bus clock | | of 33 MHz | -| BYTE_ b_TimingUnity : Base time unit (0 to 2) | +| unsigned char_ b_TimingUnity : Base time unit (0 to 2) | | 0 : ns | | 1 : æs | | 2 : ms | @@ -1487,16 +1487,16 @@ INT i_APCI1710_InitCompareLogic(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -INT i_APCI1710_InitFrequencyMeasurement(struct comedi_device * dev, - BYTE b_ModulNbr, - BYTE b_PCIInputClock, - BYTE b_TimingUnity, - ULONG ul_TimingInterval, PULONG pul_RealTimingInterval) +int i_APCI1710_InitFrequencyMeasurement(struct comedi_device *dev, + unsigned char b_ModulNbr, + unsigned char b_PCIInputClock, + unsigned char b_TimingUnity, + unsigned int ul_TimingInterval, unsigned int *pul_RealTimingInterval) { - INT i_ReturnValue = 0; - ULONG ul_TimerValue = 0; + int i_ReturnValue = 0; + unsigned int ul_TimerValue = 0; double d_RealTimingInterval; - DWORD dw_Status = 0; + unsigned int dw_Status = 0; /**************************/ /* Test the module number */ @@ -1637,7 +1637,7 @@ INT i_APCI1710_InitFrequencyMeasurement(struct comedi_device * dev, i_ReturnValue = -7; } - } // if (b_PCIInputClock == APCI1710_40MHZ) + } /* if (b_PCIInputClock == APCI1710_40MHZ) */ /***************************/ /* Test if not error occur */ @@ -1676,7 +1676,7 @@ INT i_APCI1710_InitFrequencyMeasurement(struct comedi_device * dev, b_ModeRegister4 | APCI1710_ENABLE_40MHZ_FREQUENCY; - } // if (b_PCIInputClock == APCI1710_40MHZ) + } /* if (b_PCIInputClock == APCI1710_40MHZ) */ else { /**********************************/ /* Disable the 40MHz quarz (DQ30) */ @@ -1700,7 +1700,7 @@ INT i_APCI1710_InitFrequencyMeasurement(struct comedi_device * dev, & APCI1710_DISABLE_40MHZ_FREQUENCY; - } // if (b_PCIInputClock == APCI1710_40MHZ) + } /* if (b_PCIInputClock == APCI1710_40MHZ) */ /********************************/ /* Calculate the division fator */ @@ -1720,7 +1720,7 @@ INT i_APCI1710_InitFrequencyMeasurement(struct comedi_device * dev, ul_TimerValue = - (ULONG) + (unsigned int) (ul_TimingInterval * (0.00025 * b_PCIInputClock)); @@ -1743,7 +1743,7 @@ INT i_APCI1710_InitFrequencyMeasurement(struct comedi_device * dev, *pul_RealTimingInterval = - (ULONG) + (unsigned int) (ul_TimerValue / (0.00025 * (double)b_PCIInputClock)); @@ -1790,7 +1790,7 @@ INT i_APCI1710_InitFrequencyMeasurement(struct comedi_device * dev, ul_TimerValue = - (ULONG) + (unsigned int) (ul_TimingInterval * (0.25 * b_PCIInputClock)); @@ -1813,7 +1813,7 @@ INT i_APCI1710_InitFrequencyMeasurement(struct comedi_device * dev, *pul_RealTimingInterval = - (ULONG) + (unsigned int) (ul_TimerValue / (0.25 * (double)b_PCIInputClock)); @@ -1886,7 +1886,7 @@ INT i_APCI1710_InitFrequencyMeasurement(struct comedi_device * dev, *pul_RealTimingInterval = - (ULONG) + (unsigned int) (ul_TimerValue / (250.0 * (double)b_PCIInputClock)); @@ -1949,7 +1949,7 @@ INT i_APCI1710_InitFrequencyMeasurement(struct comedi_device * dev, i_ReturnValue = -3; } - } // if (i_ReturnValue == 0) + } /* if (i_ReturnValue == 0) */ } else { /**********************************/ /* Base timing selection is wrong */ @@ -1992,12 +1992,12 @@ INT i_APCI1710_InitFrequencyMeasurement(struct comedi_device * dev, i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /*########################################################################### */ - //INSN BITS + /* INSN BITS */ /*########################################################################### */ /* @@ -2015,18 +2015,18 @@ struct comedi_insn *insn,unsigned int *data) | +----------------------------------------------------------------------------+ */ -INT i_APCI1710_InsnBitsINCCPT(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI1710_InsnBitsINCCPT(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - UINT ui_BitsType; - INT i_ReturnValue = 0; + unsigned int ui_BitsType; + int i_ReturnValue = 0; ui_BitsType = CR_CHAN(insn->chanspec); - devpriv->tsk_Current = current; // Save the current process task structure + devpriv->tsk_Current = current; /* Save the current process task structure */ switch (ui_BitsType) { case APCI1710_INCCPT_CLEARCOUNTERVALUE: i_ReturnValue = i_APCI1710_ClearCounterValue(dev, - (BYTE) CR_AREF(insn->chanspec)); + (unsigned char) CR_AREF(insn->chanspec)); break; case APCI1710_INCCPT_CLEARALLCOUNTERVALUE: @@ -2035,28 +2035,28 @@ INT i_APCI1710_InsnBitsINCCPT(struct comedi_device * dev, struct comedi_subdevic case APCI1710_INCCPT_SETINPUTFILTER: i_ReturnValue = i_APCI1710_SetInputFilter(dev, - (BYTE) CR_AREF(insn->chanspec), - (BYTE) data[0], (BYTE) data[1]); + (unsigned char) CR_AREF(insn->chanspec), + (unsigned char) data[0], (unsigned char) data[1]); break; case APCI1710_INCCPT_LATCHCOUNTER: i_ReturnValue = i_APCI1710_LatchCounter(dev, - (BYTE) CR_AREF(insn->chanspec), (BYTE) data[0]); + (unsigned char) CR_AREF(insn->chanspec), (unsigned char) data[0]); break; case APCI1710_INCCPT_SETINDEXANDREFERENCESOURCE: i_ReturnValue = i_APCI1710_SetIndexAndReferenceSource(dev, - (BYTE) CR_AREF(insn->chanspec), (BYTE) data[0]); + (unsigned char) CR_AREF(insn->chanspec), (unsigned char) data[0]); break; case APCI1710_INCCPT_SETDIGITALCHLON: i_ReturnValue = i_APCI1710_SetDigitalChlOn(dev, - (BYTE) CR_AREF(insn->chanspec)); + (unsigned char) CR_AREF(insn->chanspec)); break; case APCI1710_INCCPT_SETDIGITALCHLOFF: i_ReturnValue = i_APCI1710_SetDigitalChlOff(dev, - (BYTE) CR_AREF(insn->chanspec)); + (unsigned char) CR_AREF(insn->chanspec)); break; default: @@ -2065,20 +2065,20 @@ INT i_APCI1710_InsnBitsINCCPT(struct comedi_device * dev, struct comedi_subdevic if (i_ReturnValue >= 0) i_ReturnValue = insn->n; - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_ClearCounterValue | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr) | +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr) | +----------------------------------------------------------------------------+ | Task : Clear the counter value from selected module | | (b_ModulNbr). | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | -| BYTE_ b_ModulNbr : Module number to configure | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | +| unsigned char_ b_ModulNbr : Module number to configure | | (0 to 3) | +----------------------------------------------------------------------------+ | Output Parameters : - | @@ -2091,9 +2091,9 @@ INT i_APCI1710_InsnBitsINCCPT(struct comedi_device * dev, struct comedi_subdevic +----------------------------------------------------------------------------+ */ -INT i_APCI1710_ClearCounterValue(struct comedi_device * dev, BYTE b_ModulNbr) +int i_APCI1710_ClearCounterValue(struct comedi_device *dev, unsigned char b_ModulNbr) { - INT i_ReturnValue = 0; + int i_ReturnValue = 0; /**************************/ /* Test the module number */ @@ -2131,17 +2131,17 @@ INT i_APCI1710_ClearCounterValue(struct comedi_device * dev, BYTE b_ModulNbr) i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_ClearAllCounterValue | -| (BYTE_ b_BoardHandle) | +| (unsigned char_ b_BoardHandle) | +----------------------------------------------------------------------------+ | Task : Clear all counter value. | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | +----------------------------------------------------------------------------+ | Output Parameters : - | +----------------------------------------------------------------------------+ @@ -2151,10 +2151,10 @@ INT i_APCI1710_ClearCounterValue(struct comedi_device * dev, BYTE b_ModulNbr) +----------------------------------------------------------------------------+ */ -INT i_APCI1710_ClearAllCounterValue(struct comedi_device * dev) +int i_APCI1710_ClearAllCounterValue(struct comedi_device *dev) { - BYTE b_ModulCpt = 0; - INT i_ReturnValue = 0; + unsigned char b_ModulCpt = 0; + int i_ReturnValue = 0; /********************************/ /* Test if counter module found */ @@ -2198,24 +2198,24 @@ INT i_APCI1710_ClearAllCounterValue(struct comedi_device * dev) i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_SetInputFilter | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_Module, | -| BYTE_ b_PCIInputClock, | -| BYTE_ b_Filter) | +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_Module, | +| unsigned char_ b_PCIInputClock, | +| unsigned char_ b_Filter) | +----------------------------------------------------------------------------+ | Task : Disable or enable the software filter from selected | | module (b_ModulNbr). b_Filter determine the filter time| +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | -| BYTE_ b_ModulNbr : Number of the module to be | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | +| unsigned char_ b_ModulNbr : Number of the module to be | | configured (0 to 3) | -| BYTE_ b_PCIInputClock : Selection of the PCI bus | +| unsigned char_ b_PCIInputClock : Selection of the PCI bus | | clock | | - APCI1710_30MHZ : | | The PC has a PCI bus clock | @@ -2226,7 +2226,7 @@ INT i_APCI1710_ClearAllCounterValue(struct comedi_device * dev) | - APCI1710_40MHZ : | | The APCI1710 has a 40MHz | | quartz | -| BYTE_ b_Filter : Filter selection | +| unsigned char_ b_Filter : Filter selection | | | | 30 MHz | | ------ | @@ -2297,11 +2297,11 @@ INT i_APCI1710_ClearAllCounterValue(struct comedi_device * dev) +----------------------------------------------------------------------------+ */ -INT i_APCI1710_SetInputFilter(struct comedi_device * dev, - BYTE b_ModulNbr, BYTE b_PCIInputClock, BYTE b_Filter) +int i_APCI1710_SetInputFilter(struct comedi_device *dev, + unsigned char b_ModulNbr, unsigned char b_PCIInputClock, unsigned char b_Filter) { - INT i_ReturnValue = 0; - DWORD dw_Status = 0; + int i_ReturnValue = 0; + unsigned int dw_Status = 0; /**************************/ /* Test the module number */ @@ -2365,7 +2365,7 @@ INT i_APCI1710_SetInputFilter(struct comedi_device * dev, i_ReturnValue = -6; } - } // if (b_PCIInputClock == APCI1710_40MHZ) + } /* if (b_PCIInputClock == APCI1710_40MHZ) */ /***************************/ /* Test if error not occur */ @@ -2401,7 +2401,7 @@ INT i_APCI1710_SetInputFilter(struct comedi_device * dev, | APCI1710_ENABLE_40MHZ_FILTER; - } // if (b_PCIInputClock == APCI1710_40MHZ) + } /* if (b_PCIInputClock == APCI1710_40MHZ) */ else { /**********************************/ /* Disable the 40MHz quarz (DQ31) */ @@ -2425,7 +2425,7 @@ INT i_APCI1710_SetInputFilter(struct comedi_device * dev, & APCI1710_DISABLE_40MHZ_FILTER; - } // if (b_PCIInputClock == APCI1710_40MHZ) + } /* if (b_PCIInputClock == APCI1710_40MHZ) */ /************************/ /* Set the filter value */ @@ -2486,8 +2486,8 @@ INT i_APCI1710_SetInputFilter(struct comedi_device * dev, ui_Address + 20 + (64 * b_ModulNbr)); - } // if (i_ReturnValue == 0) - } // if (b_Filter < 16) + } /* if (i_ReturnValue == 0) */ + } /* if (b_Filter < 16) */ else { /**************************************/ /* The selected filter value is wrong */ @@ -2495,8 +2495,8 @@ INT i_APCI1710_SetInputFilter(struct comedi_device * dev, DPRINTK("The selected filter value is wrong\n"); i_ReturnValue = -5; - } // if (b_Filter < 16) - } // if ((b_PCIInputClock == APCI1710_30MHZ) || (b_PCIInputClock == APCI1710_33MHZ) || (b_PCIInputClock == APCI1710_40MHZ)) + } /* if (b_Filter < 16) */ + } /* if ((b_PCIInputClock == APCI1710_30MHZ) || (b_PCIInputClock == APCI1710_33MHZ) || (b_PCIInputClock == APCI1710_40MHZ)) */ else { /*****************************************/ /* The selected PCI input clock is wrong */ @@ -2504,7 +2504,7 @@ INT i_APCI1710_SetInputFilter(struct comedi_device * dev, DPRINTK("The selected PCI input clock is wrong\n"); i_ReturnValue = 4; - } // if ((b_PCIInputClock == APCI1710_30MHZ) || (b_PCIInputClock == APCI1710_33MHZ) || (b_PCIInputClock == APCI1710_40MHZ)) + } /* if ((b_PCIInputClock == APCI1710_30MHZ) || (b_PCIInputClock == APCI1710_33MHZ) || (b_PCIInputClock == APCI1710_40MHZ)) */ } else { /**************************************/ /* The module is not a counter module */ @@ -2530,23 +2530,23 @@ INT i_APCI1710_SetInputFilter(struct comedi_device * dev, i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_LatchCounter (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr, | -| BYTE_ b_LatchReg) | +| Function Name : _INT_ i_APCI1710_LatchCounter (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr, | +| unsigned char_ b_LatchReg) | +----------------------------------------------------------------------------+ | Task : Latch the courant value from selected module | | (b_ModulNbr) in to the selected latch register | | (b_LatchReg). | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | -| BYTE_ b_ModulNbr : Module number to configure | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | +| unsigned char_ b_ModulNbr : Module number to configure | | (0 to 3) | -| BYTE_ b_LatchReg : Selected latch register | +| unsigned char_ b_LatchReg : Selected latch register | | 0 : for the first latch register | | 1 : for the second latch register | +----------------------------------------------------------------------------+ @@ -2561,10 +2561,10 @@ INT i_APCI1710_SetInputFilter(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -INT i_APCI1710_LatchCounter(struct comedi_device * dev, - BYTE b_ModulNbr, BYTE b_LatchReg) +int i_APCI1710_LatchCounter(struct comedi_device *dev, + unsigned char b_ModulNbr, unsigned char b_LatchReg) { - INT i_ReturnValue = 0; + int i_ReturnValue = 0; /**************************/ /* Test the module number */ @@ -2616,25 +2616,25 @@ INT i_APCI1710_LatchCounter(struct comedi_device * dev, i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_SetIndexAndReferenceSource | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr, | -| BYTE_ b_SourceSelection) | +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr, | +| unsigned char_ b_SourceSelection) | +----------------------------------------------------------------------------+ | Task : Determine the hardware source for the index and the | | reference logic. Per default the index logic is | | connected to the difference input C and the reference | | logic is connected to the 24V input E | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | -| BYTE_ b_ModulNbr : Module number to configure | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | +| unsigned char_ b_ModulNbr : Module number to configure | | (0 to 3) | -| BYTE_ b_SourceSelection : APCI1710_SOURCE_0 : | +| unsigned char_ b_SourceSelection : APCI1710_SOURCE_0 : | | The index logic is connected | | to the difference input C and| | the reference logic is | @@ -2658,10 +2658,10 @@ INT i_APCI1710_LatchCounter(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -INT i_APCI1710_SetIndexAndReferenceSource(struct comedi_device * dev, - BYTE b_ModulNbr, BYTE b_SourceSelection) +int i_APCI1710_SetIndexAndReferenceSource(struct comedi_device *dev, + unsigned char b_ModulNbr, unsigned char b_SourceSelection) { - INT i_ReturnValue = 0; + int i_ReturnValue = 0; /**************************/ /* Test the module number */ @@ -2735,7 +2735,7 @@ INT i_APCI1710_SetIndexAndReferenceSource(struct comedi_device * dev, b_ModeRegister4 & APCI1710_DEFAULT_INDEX_RFERENCE; } - } // if (b_SourceSelection == APCI1710_SOURCE_0 ||b_SourceSelection == APCI1710_SOURCE_1) + } /* if (b_SourceSelection == APCI1710_SOURCE_0 ||b_SourceSelection == APCI1710_SOURCE_1) */ else { /*********************************/ /* The source selection is wrong */ @@ -2743,7 +2743,7 @@ INT i_APCI1710_SetIndexAndReferenceSource(struct comedi_device * dev, DPRINTK("The source selection is wrong\n"); i_ReturnValue = -4; - } // if (b_SourceSelection == APCI1710_SOURCE_0 ||b_SourceSelection == APCI1710_SOURCE_1) + } /* if (b_SourceSelection == APCI1710_SOURCE_0 ||b_SourceSelection == APCI1710_SOURCE_1) */ } else { /**************************************/ /* The module is not a counter module */ @@ -2769,20 +2769,20 @@ INT i_APCI1710_SetIndexAndReferenceSource(struct comedi_device * dev, i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_SetDigitalChlOn | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr) | +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr) | +----------------------------------------------------------------------------+ | Task : Sets the digital output H Setting an output means | | setting an ouput high. | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | -| BYTE_ b_ModulNbr : Number of the module to be | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | +| unsigned char_ b_ModulNbr : Number of the module to be | | configured (0 to 3) | +----------------------------------------------------------------------------+ | Output Parameters : - | @@ -2795,9 +2795,9 @@ INT i_APCI1710_SetIndexAndReferenceSource(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -INT i_APCI1710_SetDigitalChlOn(struct comedi_device * dev, BYTE b_ModulNbr) +int i_APCI1710_SetDigitalChlOn(struct comedi_device *dev, unsigned char b_ModulNbr) { - INT i_ReturnValue = 0; + int i_ReturnValue = 0; /**************************/ /* Test the module number */ @@ -2849,20 +2849,20 @@ INT i_APCI1710_SetDigitalChlOn(struct comedi_device * dev, BYTE b_ModulNbr) i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_SetDigitalChlOff | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr) | +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr) | +----------------------------------------------------------------------------+ | Task : Resets the digital output H. Resetting an output means | | setting an ouput low. | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | -| BYTE_ b_ModulNbr : Number of the module to be | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | +| unsigned char_ b_ModulNbr : Number of the module to be | | configured (0 to 3) | +----------------------------------------------------------------------------+ | Output Parameters : - | @@ -2875,9 +2875,9 @@ INT i_APCI1710_SetDigitalChlOn(struct comedi_device * dev, BYTE b_ModulNbr) +----------------------------------------------------------------------------+ */ -INT i_APCI1710_SetDigitalChlOff(struct comedi_device * dev, BYTE b_ModulNbr) +int i_APCI1710_SetDigitalChlOff(struct comedi_device *dev, unsigned char b_ModulNbr) { - INT i_ReturnValue = 0; + int i_ReturnValue = 0; /**************************/ /* Test the module number */ @@ -2929,12 +2929,12 @@ INT i_APCI1710_SetDigitalChlOff(struct comedi_device * dev, BYTE b_ModulNbr) i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /*########################################################################### */ - // INSN WRITE + /* INSN WRITE */ /*########################################################################### */ /* @@ -2951,65 +2951,65 @@ struct comedi_insn *insn,unsigned int *data) | | Return Value : +----------------------------------------------------------------------------+ */ -INT i_APCI1710_InsnWriteINCCPT(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI1710_InsnWriteINCCPT(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - UINT ui_WriteType; - INT i_ReturnValue = 0; + unsigned int ui_WriteType; + int i_ReturnValue = 0; ui_WriteType = CR_CHAN(insn->chanspec); - devpriv->tsk_Current = current; // Save the current process task structure + devpriv->tsk_Current = current; /* Save the current process task structure */ switch (ui_WriteType) { case APCI1710_INCCPT_ENABLELATCHINTERRUPT: i_ReturnValue = i_APCI1710_EnableLatchInterrupt(dev, - (BYTE) CR_AREF(insn->chanspec)); + (unsigned char) CR_AREF(insn->chanspec)); break; case APCI1710_INCCPT_DISABLELATCHINTERRUPT: i_ReturnValue = i_APCI1710_DisableLatchInterrupt(dev, - (BYTE) CR_AREF(insn->chanspec)); + (unsigned char) CR_AREF(insn->chanspec)); break; case APCI1710_INCCPT_WRITE16BITCOUNTERVALUE: i_ReturnValue = i_APCI1710_Write16BitCounterValue(dev, - (BYTE) CR_AREF(insn->chanspec), - (BYTE) data[0], (UINT) data[1]); + (unsigned char) CR_AREF(insn->chanspec), + (unsigned char) data[0], (unsigned int) data[1]); break; case APCI1710_INCCPT_WRITE32BITCOUNTERVALUE: i_ReturnValue = i_APCI1710_Write32BitCounterValue(dev, - (BYTE) CR_AREF(insn->chanspec), (ULONG) data[0]); + (unsigned char) CR_AREF(insn->chanspec), (unsigned int) data[0]); break; case APCI1710_INCCPT_ENABLEINDEX: - i_APCI1710_EnableIndex(dev, (BYTE) CR_AREF(insn->chanspec)); + i_APCI1710_EnableIndex(dev, (unsigned char) CR_AREF(insn->chanspec)); break; case APCI1710_INCCPT_DISABLEINDEX: i_ReturnValue = i_APCI1710_DisableIndex(dev, - (BYTE) CR_AREF(insn->chanspec)); + (unsigned char) CR_AREF(insn->chanspec)); break; case APCI1710_INCCPT_ENABLECOMPARELOGIC: i_ReturnValue = i_APCI1710_EnableCompareLogic(dev, - (BYTE) CR_AREF(insn->chanspec)); + (unsigned char) CR_AREF(insn->chanspec)); break; case APCI1710_INCCPT_DISABLECOMPARELOGIC: i_ReturnValue = i_APCI1710_DisableCompareLogic(dev, - (BYTE) CR_AREF(insn->chanspec)); + (unsigned char) CR_AREF(insn->chanspec)); break; case APCI1710_INCCPT_ENABLEFREQUENCYMEASUREMENT: i_ReturnValue = i_APCI1710_EnableFrequencyMeasurement(dev, - (BYTE) CR_AREF(insn->chanspec), (BYTE) data[0]); + (unsigned char) CR_AREF(insn->chanspec), (unsigned char) data[0]); break; case APCI1710_INCCPT_DISABLEFREQUENCYMEASUREMENT: i_ReturnValue = i_APCI1710_DisableFrequencyMeasurement(dev, - (BYTE) CR_AREF(insn->chanspec)); + (unsigned char) CR_AREF(insn->chanspec)); break; default: @@ -3018,21 +3018,21 @@ INT i_APCI1710_InsnWriteINCCPT(struct comedi_device * dev, struct comedi_subdevi if (i_ReturnValue >= 0) i_ReturnValue = insn->n; - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_EnableLatchInterrupt | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr) | +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr) | +----------------------------------------------------------------------------+ | Task : Enable the latch interrupt from selected module | | (b_ModulNbr). Each software or hardware latch occur a | | interrupt. | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | -| BYTE_ b_ModulNbr : Module number to configure | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | +| unsigned char_ b_ModulNbr : Module number to configure | | (0 to 3) | +----------------------------------------------------------------------------+ | Output Parameters : - | @@ -3047,9 +3047,9 @@ INT i_APCI1710_InsnWriteINCCPT(struct comedi_device * dev, struct comedi_subdevi +----------------------------------------------------------------------------+ */ -INT i_APCI1710_EnableLatchInterrupt(struct comedi_device * dev, BYTE b_ModulNbr) +int i_APCI1710_EnableLatchInterrupt(struct comedi_device *dev, unsigned char b_ModulNbr) { - INT i_ReturnValue = 0; + int i_ReturnValue = 0; /**************************/ /* Test the module number */ @@ -3105,20 +3105,20 @@ INT i_APCI1710_EnableLatchInterrupt(struct comedi_device * dev, BYTE b_ModulNbr) i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_DisableLatchInterrupt | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr) | +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr) | +----------------------------------------------------------------------------+ | Task : Disable the latch interrupt from selected module | | (b_ModulNbr). | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | -| BYTE_ b_ModulNbr : Module number to configure | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | +| unsigned char_ b_ModulNbr : Module number to configure | | (0 to 3) | +----------------------------------------------------------------------------+ | Output Parameters : - | @@ -3133,9 +3133,9 @@ INT i_APCI1710_EnableLatchInterrupt(struct comedi_device * dev, BYTE b_ModulNbr) +----------------------------------------------------------------------------+ */ -INT i_APCI1710_DisableLatchInterrupt(struct comedi_device * dev, BYTE b_ModulNbr) +int i_APCI1710_DisableLatchInterrupt(struct comedi_device *dev, unsigned char b_ModulNbr) { - INT i_ReturnValue = 0; + int i_ReturnValue = 0; /**************************/ /* Test the module number */ @@ -3198,27 +3198,27 @@ INT i_APCI1710_DisableLatchInterrupt(struct comedi_device * dev, BYTE b_ModulNbr i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_Write16BitCounterValue | -| (BYTE_ b_BoardHandle | -| BYTE_ b_ModulNbr, | -| BYTE_ b_SelectedCounter, | -| UINT_ ui_WriteValue) | +| (unsigned char_ b_BoardHandle | +| unsigned char_ b_ModulNbr, | +| unsigned char_ b_SelectedCounter, | +| unsigned int_ ui_WriteValue) | +----------------------------------------------------------------------------+ | Task : Write a 16-Bit value (ui_WriteValue) in to the selected| | 16-Bit counter (b_SelectedCounter) from selected module| | (b_ModulNbr). | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | -| BYTE_ b_ModulNbr : Module number to configure | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | +| unsigned char_ b_ModulNbr : Module number to configure | | (0 to 3) | -| BYTE_ b_SelectedCounter : Selected 16-Bit counter | +| unsigned char_ b_SelectedCounter : Selected 16-Bit counter | | (0 or 1) | -| UINT_ ui_WriteValue : 16-Bit write value | +| unsigned int_ ui_WriteValue : 16-Bit write value | +----------------------------------------------------------------------------+ | Output Parameters : - | +----------------------------------------------------------------------------+ @@ -3231,10 +3231,10 @@ INT i_APCI1710_DisableLatchInterrupt(struct comedi_device * dev, BYTE b_ModulNbr +----------------------------------------------------------------------------+ */ -INT i_APCI1710_Write16BitCounterValue(struct comedi_device * dev, - BYTE b_ModulNbr, BYTE b_SelectedCounter, UINT ui_WriteValue) +int i_APCI1710_Write16BitCounterValue(struct comedi_device *dev, + unsigned char b_ModulNbr, unsigned char b_SelectedCounter, unsigned int ui_WriteValue) { - INT i_ReturnValue = 0; + int i_ReturnValue = 0; /**************************/ /* Test the module number */ @@ -3257,7 +3257,7 @@ INT i_APCI1710_Write16BitCounterValue(struct comedi_device * dev, /* Write the value */ /*******************/ - outl((ULONG) ((ULONG) (ui_WriteValue) << (16 * + outl((unsigned int) ((unsigned int) (ui_WriteValue) << (16 * b_SelectedCounter)), devpriv->s_BoardInfos.ui_Address + 8 + (b_SelectedCounter * 4) + @@ -3288,21 +3288,21 @@ INT i_APCI1710_Write16BitCounterValue(struct comedi_device * dev, i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_Write32BitCounterValue | -| (BYTE_ b_BoardHandle | -| BYTE_ b_ModulNbr, | +| (unsigned char_ b_BoardHandle | +| unsigned char_ b_ModulNbr, | | ULONG_ ul_WriteValue) | +----------------------------------------------------------------------------+ | Task : Write a 32-Bit value (ui_WriteValue) in to the selected| | module (b_ModulNbr). | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | -| BYTE_ b_ModulNbr : Module number to configure | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | +| unsigned char_ b_ModulNbr : Module number to configure | | (0 to 3) | | ULONG_ ul_WriteValue : 32-Bit write value | +----------------------------------------------------------------------------+ @@ -3316,10 +3316,10 @@ INT i_APCI1710_Write16BitCounterValue(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -INT i_APCI1710_Write32BitCounterValue(struct comedi_device * dev, - BYTE b_ModulNbr, ULONG ul_WriteValue) +int i_APCI1710_Write32BitCounterValue(struct comedi_device *dev, + unsigned char b_ModulNbr, unsigned int ul_WriteValue) { - INT i_ReturnValue = 0; + int i_ReturnValue = 0; /**************************/ /* Test the module number */ @@ -3357,18 +3357,18 @@ INT i_APCI1710_Write32BitCounterValue(struct comedi_device * dev, i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_EnableIndex (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr) | +| Function Name : _INT_ i_APCI1710_EnableIndex (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr) | +----------------------------------------------------------------------------+ | Task : Enable the INDEX actions | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | -| BYTE_ b_ModulNbr : Module number to configure | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | +| unsigned char_ b_ModulNbr : Module number to configure | | (0 to 3) | +----------------------------------------------------------------------------+ | Output Parameters : - | @@ -3383,10 +3383,10 @@ INT i_APCI1710_Write32BitCounterValue(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -INT i_APCI1710_EnableIndex(struct comedi_device * dev, BYTE b_ModulNbr) +int i_APCI1710_EnableIndex(struct comedi_device *dev, unsigned char b_ModulNbr) { - INT i_ReturnValue = 0; - ULONG ul_InterruptLatchReg; + int i_ReturnValue = 0; + unsigned int ul_InterruptLatchReg; /**************************/ /* Test the module number */ @@ -3455,18 +3455,18 @@ INT i_APCI1710_EnableIndex(struct comedi_device * dev, BYTE b_ModulNbr) i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_DisableIndex (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr) | +| Function Name : _INT_ i_APCI1710_DisableIndex (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr) | +----------------------------------------------------------------------------+ | Task : Disable the INDEX actions | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | -| BYTE_ b_ModulNbr : Module number to configure | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | +| unsigned char_ b_ModulNbr : Module number to configure | | (0 to 3) | +----------------------------------------------------------------------------+ | Output Parameters : - | @@ -3481,9 +3481,9 @@ INT i_APCI1710_EnableIndex(struct comedi_device * dev, BYTE b_ModulNbr) +----------------------------------------------------------------------------+ */ -INT i_APCI1710_DisableIndex(struct comedi_device * dev, BYTE b_ModulNbr) +int i_APCI1710_DisableIndex(struct comedi_device *dev, unsigned char b_ModulNbr) { - INT i_ReturnValue = 0; + int i_ReturnValue = 0; /**************************/ /* Test the module number */ @@ -3549,21 +3549,21 @@ INT i_APCI1710_DisableIndex(struct comedi_device * dev, BYTE b_ModulNbr) i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_EnableCompareLogic | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr) | +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr) | +----------------------------------------------------------------------------+ | Task : Enable the 32-Bit compare logic. At that moment that | | the incremental counter arrive to the compare value a | | interrupt is generated. | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | -| BYTE_ b_ModulNbr : Module number to configure | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | +| unsigned char_ b_ModulNbr : Module number to configure | | (0 to 3) | +----------------------------------------------------------------------------+ | Output Parameters : - @@ -3580,9 +3580,9 @@ INT i_APCI1710_DisableIndex(struct comedi_device * dev, BYTE b_ModulNbr) +----------------------------------------------------------------------------+ */ -INT i_APCI1710_EnableCompareLogic(struct comedi_device * dev, BYTE b_ModulNbr) +int i_APCI1710_EnableCompareLogic(struct comedi_device *dev, unsigned char b_ModulNbr) { - INT i_ReturnValue = 0; + int i_ReturnValue = 0; /**************************/ /* Test the module number */ @@ -3653,19 +3653,19 @@ INT i_APCI1710_EnableCompareLogic(struct comedi_device * dev, BYTE b_ModulNbr) i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_DisableCompareLogic | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr) | +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr) | +----------------------------------------------------------------------------+ | Task : Disable the 32-Bit compare logic. +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | -| BYTE_ b_ModulNbr : Module number to configure | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | +| unsigned char_ b_ModulNbr : Module number to configure | | (0 to 3) | +----------------------------------------------------------------------------+ | Output Parameters : - @@ -3680,9 +3680,9 @@ INT i_APCI1710_EnableCompareLogic(struct comedi_device * dev, BYTE b_ModulNbr) +----------------------------------------------------------------------------+ */ -INT i_APCI1710_DisableCompareLogic(struct comedi_device * dev, BYTE b_ModulNbr) +int i_APCI1710_DisableCompareLogic(struct comedi_device *dev, unsigned char b_ModulNbr) { - INT i_ReturnValue = 0; + int i_ReturnValue = 0; /**************************/ /* Test the module number */ @@ -3753,22 +3753,22 @@ INT i_APCI1710_DisableCompareLogic(struct comedi_device * dev, BYTE b_ModulNbr) i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_EnableFrequencyMeasurement | - | (BYTE_ b_BoardHandle, | - | BYTE_ b_ModulNbr, | - | BYTE_ b_InterruptEnable) | + | (unsigned char_ b_BoardHandle, | + | unsigned char_ b_ModulNbr, | + | unsigned char_ b_InterruptEnable) | +----------------------------------------------------------------------------+ | Task : Enables the frequency measurement function | +----------------------------------------------------------------------------+ - | Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | - | BYTE_ b_ModulNbr : Number of the module to be | + | Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | + | unsigned char_ b_ModulNbr : Number of the module to be | | configured (0 to 3) | - | BYTE_ b_InterruptEnable: Enable or disable the | + | unsigned char_ b_InterruptEnable: Enable or disable the | | interrupt. | | APCI1710_ENABLE: | | Enable the interrupt | @@ -3789,10 +3789,10 @@ INT i_APCI1710_DisableCompareLogic(struct comedi_device * dev, BYTE b_ModulNbr) +----------------------------------------------------------------------------+ */ -INT i_APCI1710_EnableFrequencyMeasurement(struct comedi_device * dev, - BYTE b_ModulNbr, BYTE b_InterruptEnable) +int i_APCI1710_EnableFrequencyMeasurement(struct comedi_device *dev, + unsigned char b_ModulNbr, unsigned char b_InterruptEnable) { - INT i_ReturnValue = 0; + int i_ReturnValue = 0; /**************************/ /* Test the module number */ @@ -3909,19 +3909,19 @@ INT i_APCI1710_EnableFrequencyMeasurement(struct comedi_device * dev, i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_DisableFrequencyMeasurement | - | (BYTE_ b_BoardHandle, | - | BYTE_ b_ModulNbr) | + | (unsigned char_ b_BoardHandle, | + | unsigned char_ b_ModulNbr) | +----------------------------------------------------------------------------+ | Task : Disables the frequency measurement function | +----------------------------------------------------------------------------+ - | Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | - | BYTE_ b_ModulNbr : Number of the module to be | + | Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | + | unsigned char_ b_ModulNbr : Number of the module to be | | configured (0 to 3) | +----------------------------------------------------------------------------+ | Output Parameters : - | @@ -3936,9 +3936,9 @@ INT i_APCI1710_EnableFrequencyMeasurement(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -INT i_APCI1710_DisableFrequencyMeasurement(struct comedi_device * dev, BYTE b_ModulNbr) +int i_APCI1710_DisableFrequencyMeasurement(struct comedi_device *dev, unsigned char b_ModulNbr) { - INT i_ReturnValue = 0; + int i_ReturnValue = 0; /**************************/ /* Test the module number */ @@ -3976,9 +3976,9 @@ INT i_APCI1710_DisableFrequencyMeasurement(struct comedi_device * dev, BYTE b_Mo s_ByteModeRegister. b_ModeRegister3 & APCI1710_DISABLE_FREQUENCY - // Begin CG 29/06/01 CG 1100/0231 -> 0701/0232 Frequence measure IRQ must be cleared + /* Begin CG 29/06/01 CG 1100/0231 -> 0701/0232 Frequence measure IRQ must be cleared */ & APCI1710_DISABLE_FREQUENCY_INT; - // End CG 29/06/01 CG 1100/0231 -> 0701/0232 Frequence measure IRQ must be cleared + /* End CG 29/06/01 CG 1100/0231 -> 0701/0232 Frequence measure IRQ must be cleared */ /***************************/ /* Write the configuration */ @@ -4026,12 +4026,12 @@ INT i_APCI1710_DisableFrequencyMeasurement(struct comedi_device * dev, BYTE b_Mo i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /*########################################################################### */ - // INSN READ + /* INSN READ */ /*########################################################################### */ @@ -4049,82 +4049,82 @@ struct comedi_insn *insn,unsigned int *data) | | Return Value : +----------------------------------------------------------------------------+ */ -INT i_APCI1710_InsnReadINCCPT(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI1710_InsnReadINCCPT(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - UINT ui_ReadType; - INT i_ReturnValue = 0; + unsigned int ui_ReadType; + int i_ReturnValue = 0; ui_ReadType = CR_CHAN(insn->chanspec); - devpriv->tsk_Current = current; // Save the current process task structure + devpriv->tsk_Current = current; /* Save the current process task structure */ switch (ui_ReadType) { case APCI1710_INCCPT_READLATCHREGISTERSTATUS: i_ReturnValue = i_APCI1710_ReadLatchRegisterStatus(dev, - (BYTE) CR_AREF(insn->chanspec), - (BYTE) CR_RANGE(insn->chanspec), (PBYTE) & data[0]); + (unsigned char) CR_AREF(insn->chanspec), + (unsigned char) CR_RANGE(insn->chanspec), (unsigned char *) &data[0]); break; case APCI1710_INCCPT_READLATCHREGISTERVALUE: i_ReturnValue = i_APCI1710_ReadLatchRegisterValue(dev, - (BYTE) CR_AREF(insn->chanspec), - (BYTE) CR_RANGE(insn->chanspec), (PULONG) & data[0]); + (unsigned char) CR_AREF(insn->chanspec), + (unsigned char) CR_RANGE(insn->chanspec), (unsigned int *) &data[0]); printk("Latch Register Value %d\n", data[0]); break; case APCI1710_INCCPT_READ16BITCOUNTERVALUE: i_ReturnValue = i_APCI1710_Read16BitCounterValue(dev, - (BYTE) CR_AREF(insn->chanspec), - (BYTE) CR_RANGE(insn->chanspec), (PUINT) & data[0]); + (unsigned char) CR_AREF(insn->chanspec), + (unsigned char) CR_RANGE(insn->chanspec), (unsigned int *) &data[0]); break; case APCI1710_INCCPT_READ32BITCOUNTERVALUE: i_ReturnValue = i_APCI1710_Read32BitCounterValue(dev, - (BYTE) CR_AREF(insn->chanspec), (PULONG) & data[0]); + (unsigned char) CR_AREF(insn->chanspec), (unsigned int *) &data[0]); break; case APCI1710_INCCPT_GETINDEXSTATUS: i_ReturnValue = i_APCI1710_GetIndexStatus(dev, - (BYTE) CR_AREF(insn->chanspec), (PBYTE) & data[0]); + (unsigned char) CR_AREF(insn->chanspec), (unsigned char *) &data[0]); break; case APCI1710_INCCPT_GETREFERENCESTATUS: i_ReturnValue = i_APCI1710_GetReferenceStatus(dev, - (BYTE) CR_AREF(insn->chanspec), (PBYTE) & data[0]); + (unsigned char) CR_AREF(insn->chanspec), (unsigned char *) &data[0]); break; case APCI1710_INCCPT_GETUASSTATUS: i_ReturnValue = i_APCI1710_GetUASStatus(dev, - (BYTE) CR_AREF(insn->chanspec), (PBYTE) & data[0]); + (unsigned char) CR_AREF(insn->chanspec), (unsigned char *) &data[0]); break; case APCI1710_INCCPT_GETCBSTATUS: i_ReturnValue = i_APCI1710_GetCBStatus(dev, - (BYTE) CR_AREF(insn->chanspec), (PBYTE) & data[0]); + (unsigned char) CR_AREF(insn->chanspec), (unsigned char *) &data[0]); break; case APCI1710_INCCPT_GET16BITCBSTATUS: i_ReturnValue = i_APCI1710_Get16BitCBStatus(dev, - (BYTE) CR_AREF(insn->chanspec), - (PBYTE) & data[0], (PBYTE) & data[1]); + (unsigned char) CR_AREF(insn->chanspec), + (unsigned char *) &data[0], (unsigned char *) &data[1]); break; case APCI1710_INCCPT_GETUDSTATUS: i_ReturnValue = i_APCI1710_GetUDStatus(dev, - (BYTE) CR_AREF(insn->chanspec), (PBYTE) & data[0]); + (unsigned char) CR_AREF(insn->chanspec), (unsigned char *) &data[0]); break; case APCI1710_INCCPT_GETINTERRUPTUDLATCHEDSTATUS: i_ReturnValue = i_APCI1710_GetInterruptUDLatchedStatus(dev, - (BYTE) CR_AREF(insn->chanspec), (PBYTE) & data[0]); + (unsigned char) CR_AREF(insn->chanspec), (unsigned char *) &data[0]); break; case APCI1710_INCCPT_READFREQUENCYMEASUREMENT: i_ReturnValue = i_APCI1710_ReadFrequencyMeasurement(dev, - (BYTE) CR_AREF(insn->chanspec), - (PBYTE) & data[0], - (PBYTE) & data[1], (PULONG) & data[2]); + (unsigned char) CR_AREF(insn->chanspec), + (unsigned char *) &data[0], + (unsigned char *) &data[1], (unsigned int *) &data[2]); break; case APCI1710_INCCPT_READINTERRUPT: @@ -4155,29 +4155,29 @@ INT i_APCI1710_InsnReadINCCPT(struct comedi_device * dev, struct comedi_subdevic if (i_ReturnValue >= 0) i_ReturnValue = insn->n; - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_ReadLatchRegisterStatus | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr, | -| BYTE_ b_LatchReg, | -| PBYTE_ pb_LatchStatus) | +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr, | +| unsigned char_ b_LatchReg, | +| unsigned char *_ pb_LatchStatus) | +----------------------------------------------------------------------------+ | Task : Read the latch register status from selected module | | (b_ModulNbr) and selected latch register (b_LatchReg). | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | -| BYTE_ b_ModulNbr : Module number to configure | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | +| unsigned char_ b_ModulNbr : Module number to configure | | (0 to 3) | -| BYTE_ b_LatchReg : Selected latch register | +| unsigned char_ b_LatchReg : Selected latch register | | 0 : for the first latch register | | 1 : for the second latch register | +----------------------------------------------------------------------------+ -| Output Parameters : PBYTE_ pb_LatchStatus : Latch register status. | +| Output Parameters : unsigned char *_ pb_LatchStatus : Latch register status. | | 0 : No latch occur | | 1 : A software latch occur | | 2 : A hardware latch occur | @@ -4193,11 +4193,11 @@ INT i_APCI1710_InsnReadINCCPT(struct comedi_device * dev, struct comedi_subdevic +----------------------------------------------------------------------------+ */ -INT i_APCI1710_ReadLatchRegisterStatus(struct comedi_device * dev, - BYTE b_ModulNbr, BYTE b_LatchReg, PBYTE pb_LatchStatus) +int i_APCI1710_ReadLatchRegisterStatus(struct comedi_device *dev, + unsigned char b_ModulNbr, unsigned char b_LatchReg, unsigned char *pb_LatchStatus) { - INT i_ReturnValue = 0; - DWORD dw_LatchReg; + int i_ReturnValue = 0; + unsigned int dw_LatchReg; /**************************/ /* Test the module number */ @@ -4220,7 +4220,7 @@ INT i_APCI1710_ReadLatchRegisterStatus(struct comedi_device * dev, ui_Address + (64 * b_ModulNbr)); *pb_LatchStatus = - (BYTE) ((dw_LatchReg >> (b_LatchReg * + (unsigned char) ((dw_LatchReg >> (b_LatchReg * 4)) & 0x3); } else { /**************************************************/ @@ -4248,24 +4248,24 @@ INT i_APCI1710_ReadLatchRegisterStatus(struct comedi_device * dev, i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_ReadLatchRegisterValue | -| (BYTE_ b_BoardHandle,| -| BYTE_ b_ModulNbr, | -| BYTE_ b_LatchReg, | +| (unsigned char_ b_BoardHandle,| +| unsigned char_ b_ModulNbr, | +| unsigned char_ b_LatchReg, | | PULONG_ pul_LatchValue) | +----------------------------------------------------------------------------+ | Task : Read the latch register value from selected module | | (b_ModulNbr) and selected latch register (b_LatchReg). | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | -| BYTE_ b_ModulNbr : Module number to configure | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | +| unsigned char_ b_ModulNbr : Module number to configure | | (0 to 3) | -| BYTE_ b_LatchReg : Selected latch register | +| unsigned char_ b_LatchReg : Selected latch register | | 0 : for the first latch register | | 1 : for the second latch register | +----------------------------------------------------------------------------+ @@ -4280,10 +4280,10 @@ INT i_APCI1710_ReadLatchRegisterStatus(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -INT i_APCI1710_ReadLatchRegisterValue(struct comedi_device * dev, - BYTE b_ModulNbr, BYTE b_LatchReg, PULONG pul_LatchValue) +int i_APCI1710_ReadLatchRegisterValue(struct comedi_device *dev, + unsigned char b_ModulNbr, unsigned char b_LatchReg, unsigned int *pul_LatchValue) { - INT i_ReturnValue = 0; + int i_ReturnValue = 0; /**************************/ /* Test the module number */ @@ -4332,28 +4332,28 @@ INT i_APCI1710_ReadLatchRegisterValue(struct comedi_device * dev, i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_Read16BitCounterValue | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr, | -| BYTE_ b_SelectedCounter, | -| PUINT_ pui_CounterValue) | +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr, | +| unsigned char_ b_SelectedCounter, | +| unsigned int *_ pui_CounterValue) | +----------------------------------------------------------------------------+ | Task : Latch the selected 16-Bit counter (b_SelectedCounter) | | from selected module (b_ModulNbr) in to the first | | latch register and return the latched value. | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | -| BYTE_ b_ModulNbr : Module number to configure | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | +| unsigned char_ b_ModulNbr : Module number to configure | | (0 to 3) | -| BYTE_ b_SelectedCounter : Selected 16-Bit counter | +| unsigned char_ b_SelectedCounter : Selected 16-Bit counter | | (0 or 1) | +----------------------------------------------------------------------------+ -| Output Parameters : PUINT_ pui_CounterValue : 16-Bit counter value | +| Output Parameters : unsigned int *_ pui_CounterValue : 16-Bit counter value | +----------------------------------------------------------------------------+ | Return Value : 0: No error | | -1: The handle parameter of the board is wrong | @@ -4364,11 +4364,11 @@ INT i_APCI1710_ReadLatchRegisterValue(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -INT i_APCI1710_Read16BitCounterValue(struct comedi_device * dev, - BYTE b_ModulNbr, BYTE b_SelectedCounter, PUINT pui_CounterValue) +int i_APCI1710_Read16BitCounterValue(struct comedi_device *dev, + unsigned char b_ModulNbr, unsigned char b_SelectedCounter, unsigned int *pui_CounterValue) { - INT i_ReturnValue = 0; - DWORD dw_LathchValue = 0; + int i_ReturnValue = 0; + unsigned int dw_LathchValue = 0; /**************************/ /* Test the module number */ @@ -4402,7 +4402,7 @@ INT i_APCI1710_Read16BitCounterValue(struct comedi_device * dev, ui_Address + 4 + (64 * b_ModulNbr)); *pui_CounterValue = - (UINT) ((dw_LathchValue >> (16 * + (unsigned int) ((dw_LathchValue >> (16 * b_SelectedCounter)) & 0xFFFFU); } else { @@ -4431,22 +4431,22 @@ INT i_APCI1710_Read16BitCounterValue(struct comedi_device * dev, i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_Read32BitCounterValue | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr, | +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr, | | PULONG_ pul_CounterValue) | +----------------------------------------------------------------------------+ | Task : Latch the 32-Bit counter from selected module | | (b_ModulNbr) in to the first latch register and return | | the latched value. | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | -| BYTE_ b_ModulNbr : Module number to configure | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | +| unsigned char_ b_ModulNbr : Module number to configure | | (0 to 3) | +----------------------------------------------------------------------------+ | Output Parameters : PULONG_ pul_CounterValue : 32-Bit counter value | @@ -4459,10 +4459,10 @@ INT i_APCI1710_Read16BitCounterValue(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -INT i_APCI1710_Read32BitCounterValue(struct comedi_device * dev, - BYTE b_ModulNbr, PULONG pul_CounterValue) +int i_APCI1710_Read32BitCounterValue(struct comedi_device *dev, + unsigned char b_ModulNbr, unsigned int *pul_CounterValue) { - INT i_ReturnValue = 0; + int i_ReturnValue = 0; /**************************/ /* Test the module number */ @@ -4507,22 +4507,22 @@ INT i_APCI1710_Read32BitCounterValue(struct comedi_device * dev, i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_GetIndexStatus (BYTE_ b_BoardHandle,| -| BYTE_ b_ModulNbr, | -| PBYTE_ pb_IndexStatus)| +| Function Name : _INT_ i_APCI1710_GetIndexStatus (unsigned char_ b_BoardHandle,| +| unsigned char_ b_ModulNbr, | +| unsigned char *_ pb_IndexStatus)| +----------------------------------------------------------------------------+ | Task : Return the index status | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | -| BYTE_ b_ModulNbr : Module number to configure | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | +| unsigned char_ b_ModulNbr : Module number to configure | | (0 to 3) | +----------------------------------------------------------------------------+ -| Output Parameters : PBYTE_ pb_IndexStatus : 0 : No INDEX occur | +| Output Parameters : unsigned char *_ pb_IndexStatus : 0 : No INDEX occur | | 1 : A INDEX occur | +----------------------------------------------------------------------------+ | Return Value : 0: No error | @@ -4535,11 +4535,11 @@ INT i_APCI1710_Read32BitCounterValue(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -INT i_APCI1710_GetIndexStatus(struct comedi_device * dev, - BYTE b_ModulNbr, PBYTE pb_IndexStatus) +int i_APCI1710_GetIndexStatus(struct comedi_device *dev, + unsigned char b_ModulNbr, unsigned char *pb_IndexStatus) { - INT i_ReturnValue = 0; - DWORD dw_StatusReg = 0; + int i_ReturnValue = 0; + unsigned int dw_StatusReg = 0; /**************************/ /* Test the module number */ @@ -4563,7 +4563,7 @@ INT i_APCI1710_GetIndexStatus(struct comedi_device * dev, dw_StatusReg = inl(devpriv->s_BoardInfos. ui_Address + 12 + (64 * b_ModulNbr)); - *pb_IndexStatus = (BYTE) (dw_StatusReg & 1); + *pb_IndexStatus = (unsigned char) (dw_StatusReg & 1); } else { /*************************************************************/ /* Index not initialised see function "i_APCI1710_InitIndex" */ @@ -4590,23 +4590,23 @@ INT i_APCI1710_GetIndexStatus(struct comedi_device * dev, i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_GetReferenceStatus | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr, | -| PBYTE_ pb_ReferenceStatus) | +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr, | +| unsigned char *_ pb_ReferenceStatus) | +----------------------------------------------------------------------------+ | Task : Return the reference status | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | -| BYTE_ b_ModulNbr : Module number to configure | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | +| unsigned char_ b_ModulNbr : Module number to configure | | (0 to 3) | +----------------------------------------------------------------------------+ -| Output Parameters : PBYTE_ pb_ReferenceStatus : 0 : No REFERENCE occur | +| Output Parameters : unsigned char *_ pb_ReferenceStatus : 0 : No REFERENCE occur | | 1 : A REFERENCE occur | +----------------------------------------------------------------------------+ | Return Value : 0: No error | @@ -4619,11 +4619,11 @@ INT i_APCI1710_GetIndexStatus(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -INT i_APCI1710_GetReferenceStatus(struct comedi_device * dev, - BYTE b_ModulNbr, PBYTE pb_ReferenceStatus) +int i_APCI1710_GetReferenceStatus(struct comedi_device *dev, + unsigned char b_ModulNbr, unsigned char *pb_ReferenceStatus) { - INT i_ReturnValue = 0; - DWORD dw_StatusReg = 0; + int i_ReturnValue = 0; + unsigned int dw_StatusReg = 0; /**************************/ /* Test the module number */ @@ -4649,7 +4649,7 @@ INT i_APCI1710_GetReferenceStatus(struct comedi_device * dev, ui_Address + 24 + (64 * b_ModulNbr)); *pb_ReferenceStatus = - (BYTE) (~dw_StatusReg & 1); + (unsigned char) (~dw_StatusReg & 1); } else { /*********************************************************************/ /* Reference not initialised see function "i_APCI1710_InitReference" */ @@ -4676,23 +4676,23 @@ INT i_APCI1710_GetReferenceStatus(struct comedi_device * dev, i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_GetUASStatus | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr, | -| PBYTE_ pb_UASStatus) | +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr, | +| unsigned char *_ pb_UASStatus) | +----------------------------------------------------------------------------+ | Task : Return the error signal (UAS) status | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | -| BYTE_ b_ModulNbr : Module number to configure | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | +| unsigned char_ b_ModulNbr : Module number to configure | | (0 to 3) | +----------------------------------------------------------------------------+ -| Output Parameters : PBYTE_ pb_UASStatus : 0 : UAS is low "0" | +| Output Parameters : unsigned char *_ pb_UASStatus : 0 : UAS is low "0" | | 1 : UAS is high "1" | +----------------------------------------------------------------------------+ | Return Value : 0: No error | @@ -4703,11 +4703,11 @@ INT i_APCI1710_GetReferenceStatus(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -INT i_APCI1710_GetUASStatus(struct comedi_device * dev, - BYTE b_ModulNbr, PBYTE pb_UASStatus) +int i_APCI1710_GetUASStatus(struct comedi_device *dev, + unsigned char b_ModulNbr, unsigned char *pb_UASStatus) { - INT i_ReturnValue = 0; - DWORD dw_StatusReg = 0; + int i_ReturnValue = 0; + unsigned int dw_StatusReg = 0; /**************************/ /* Test the module number */ @@ -4724,7 +4724,7 @@ INT i_APCI1710_GetUASStatus(struct comedi_device * dev, dw_StatusReg = inl(devpriv->s_BoardInfos. ui_Address + 24 + (64 * b_ModulNbr)); - *pb_UASStatus = (BYTE) ((dw_StatusReg >> 1) & 1); + *pb_UASStatus = (unsigned char) ((dw_StatusReg >> 1) & 1); } else { /****************************************/ /* Counter not initialised see function */ @@ -4744,23 +4744,23 @@ INT i_APCI1710_GetUASStatus(struct comedi_device * dev, } - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_GetCBStatus | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr, | -| PBYTE_ pb_CBStatus) | +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr, | +| unsigned char *_ pb_CBStatus) | +----------------------------------------------------------------------------+ | Task : Return the counter overflow status | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | -| BYTE_ b_ModulNbr : Module number to configure | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | +| unsigned char_ b_ModulNbr : Module number to configure | | (0 to 3) | +----------------------------------------------------------------------------+ -| Output Parameters : PBYTE_ pb_CBStatus : 0 : Counter no overflow | +| Output Parameters : unsigned char *_ pb_CBStatus : 0 : Counter no overflow | | 1 : Counter overflow | +----------------------------------------------------------------------------+ | Return Value : 0: No error | @@ -4771,11 +4771,11 @@ INT i_APCI1710_GetUASStatus(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -INT i_APCI1710_GetCBStatus(struct comedi_device * dev, - BYTE b_ModulNbr, PBYTE pb_CBStatus) +int i_APCI1710_GetCBStatus(struct comedi_device *dev, + unsigned char b_ModulNbr, unsigned char *pb_CBStatus) { - INT i_ReturnValue = 0; - DWORD dw_StatusReg = 0; + int i_ReturnValue = 0; + unsigned int dw_StatusReg = 0; /**************************/ /* Test the module number */ @@ -4792,7 +4792,7 @@ INT i_APCI1710_GetCBStatus(struct comedi_device * dev, dw_StatusReg = inl(devpriv->s_BoardInfos. ui_Address + 16 + (64 * b_ModulNbr)); - *pb_CBStatus = (BYTE) (dw_StatusReg & 1); + *pb_CBStatus = (unsigned char) (dw_StatusReg & 1); } else { /****************************************/ @@ -4812,31 +4812,31 @@ INT i_APCI1710_GetCBStatus(struct comedi_device * dev, i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_Get16BitCBStatus | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr, | -| PBYTE_ pb_CBStatusCounter0, | -| PBYTE_ pb_CBStatusCounter1) | +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr, | +| unsigned char *_ pb_CBStatusCounter0, | +| unsigned char *_ pb_CBStatusCounter1) | +----------------------------------------------------------------------------+ | Task : Returns the counter overflow (counter initialised to | | 2*16-bit) status from selected incremental counter | | module | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | -| BYTE_ b_ModulNbr : Module number to configure | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | +| unsigned char_ b_ModulNbr : Module number to configure | | (0 to 3) | +----------------------------------------------------------------------------+ -| Output Parameters : PBYTE_ pb_CBStatusCounter0 : 0 : No overflow occur for | +| Output Parameters : unsigned char *_ pb_CBStatusCounter0 : 0 : No overflow occur for | | the first 16-bit | | counter | | 1 : Overflow occur for the| | first 16-bit counter | -| PBYTE_ pb_CBStatusCounter1 : 0 : No overflow occur for | +| unsigned char *_ pb_CBStatusCounter1 : 0 : No overflow occur for | | the second 16-bit | | counter | | 1 : Overflow occur for the| @@ -4853,11 +4853,11 @@ INT i_APCI1710_GetCBStatus(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -INT i_APCI1710_Get16BitCBStatus(struct comedi_device * dev, - BYTE b_ModulNbr, PBYTE pb_CBStatusCounter0, PBYTE pb_CBStatusCounter1) +int i_APCI1710_Get16BitCBStatus(struct comedi_device *dev, + unsigned char b_ModulNbr, unsigned char *pb_CBStatusCounter0, unsigned char *pb_CBStatusCounter1) { - INT i_ReturnValue = 0; - DWORD dw_StatusReg = 0; + int i_ReturnValue = 0; + unsigned int dw_StatusReg = 0; /**************************/ /* Test the module number */ @@ -4894,20 +4894,20 @@ INT i_APCI1710_Get16BitCBStatus(struct comedi_device * dev, (64 * b_ModulNbr)); *pb_CBStatusCounter1 = - (BYTE) ((dw_StatusReg >> 0) & + (unsigned char) ((dw_StatusReg >> 0) & 1); *pb_CBStatusCounter0 = - (BYTE) ((dw_StatusReg >> 1) & + (unsigned char) ((dw_StatusReg >> 1) & 1); - } // if ((ps_APCI1710Variable->s_Board [b_BoardHandle].s_BoardInfos.dw_MolduleConfiguration [b_ModulNbr] & 0xFFFF) >= 0x3136) + } /* if ((ps_APCI1710Variable->s_Board [b_BoardHandle].s_BoardInfos.dw_MolduleConfiguration [b_ModulNbr] & 0xFFFF) >= 0x3136) */ else { /****************************/ /* Firmware revision error */ /****************************/ i_ReturnValue = -5; - } // if ((ps_APCI1710Variable->s_Board [b_BoardHandle].s_BoardInfos.dw_MolduleConfiguration [b_ModulNbr] & 0xFFFF) >= 0x3136) - } // if ((ps_APCI1710Variable->s_Board [b_BoardHandle].s_ModuleInfo [b_ModulNbr].s_SiemensCounterInfo.s_ModeRegister.s_ByteModeRegister.b_ModeRegister1 & 0x10) == 0x10) + } /* if ((ps_APCI1710Variable->s_Board [b_BoardHandle].s_BoardInfos.dw_MolduleConfiguration [b_ModulNbr] & 0xFFFF) >= 0x3136) */ + } /* if ((ps_APCI1710Variable->s_Board [b_BoardHandle].s_ModuleInfo [b_ModulNbr].s_SiemensCounterInfo.s_ModeRegister.s_ByteModeRegister.b_ModeRegister1 & 0x10) == 0x10) */ else { /********************************************/ /* Counter not initialised to 2*16-bit mode */ @@ -4916,8 +4916,8 @@ INT i_APCI1710_Get16BitCBStatus(struct comedi_device * dev, DPRINTK("Counter not initialised\n"); i_ReturnValue = -4; - } // if ((ps_APCI1710Variable->s_Board [b_BoardHandle].s_ModuleInfo [b_ModulNbr].s_SiemensCounterInfo.s_ModeRegister.s_ByteModeRegister.b_ModeRegister1 & 0x10) == 0x10) - } // if (ps_APCI1710Variable->s_Board [b_BoardHandle].s_ModuleInfo [b_ModulNbr].s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) + } /* if ((ps_APCI1710Variable->s_Board [b_BoardHandle].s_ModuleInfo [b_ModulNbr].s_SiemensCounterInfo.s_ModeRegister.s_ByteModeRegister.b_ModeRegister1 & 0x10) == 0x10) */ + } /* if (ps_APCI1710Variable->s_Board [b_BoardHandle].s_ModuleInfo [b_ModulNbr].s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) */ else { /****************************************/ /* Counter not initialised see function */ @@ -4926,8 +4926,8 @@ INT i_APCI1710_Get16BitCBStatus(struct comedi_device * dev, DPRINTK("Counter not initialised\n"); i_ReturnValue = -3; - } // if (ps_APCI1710Variable->s_Board [b_BoardHandle].s_ModuleInfo [b_ModulNbr].s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) - } // if (b_ModulNbr < 4) + } /* if (ps_APCI1710Variable->s_Board [b_BoardHandle].s_ModuleInfo [b_ModulNbr].s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) */ + } /* if (b_ModulNbr < 4) */ else { /*************************************************/ /* The selected module number parameter is wrong */ @@ -4935,25 +4935,25 @@ INT i_APCI1710_Get16BitCBStatus(struct comedi_device * dev, DPRINTK("The selected module number parameter is wrong\n"); i_ReturnValue = -2; - } // if (b_ModulNbr < 4) + } /* if (b_ModulNbr < 4) */ - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_GetUDStatus | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr, | -| PBYTE_ pb_UDStatus) | +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr, | +| unsigned char *_ pb_UDStatus) | +----------------------------------------------------------------------------+ | Task : Return the counter progress status | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | -| BYTE_ b_ModulNbr : Module number to configure | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | +| unsigned char_ b_ModulNbr : Module number to configure | | (0 to 3) | +----------------------------------------------------------------------------+ -| Output Parameters : PBYTE_ pb_UDStatus : 0 : Counter progress in the | +| Output Parameters : unsigned char *_ pb_UDStatus : 0 : Counter progress in the | | selected mode down | | 1 : Counter progress in the | | selected mode up | @@ -4966,11 +4966,11 @@ INT i_APCI1710_Get16BitCBStatus(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -INT i_APCI1710_GetUDStatus(struct comedi_device * dev, - BYTE b_ModulNbr, PBYTE pb_UDStatus) +int i_APCI1710_GetUDStatus(struct comedi_device *dev, + unsigned char b_ModulNbr, unsigned char *pb_UDStatus) { - INT i_ReturnValue = 0; - DWORD dw_StatusReg = 0; + int i_ReturnValue = 0; + unsigned int dw_StatusReg = 0; /**************************/ /* Test the module number */ @@ -4987,7 +4987,7 @@ INT i_APCI1710_GetUDStatus(struct comedi_device * dev, dw_StatusReg = inl(devpriv->s_BoardInfos. ui_Address + 24 + (64 * b_ModulNbr)); - *pb_UDStatus = (BYTE) ((dw_StatusReg >> 2) & 1); + *pb_UDStatus = (unsigned char) ((dw_StatusReg >> 2) & 1); } else { /****************************************/ @@ -5007,24 +5007,24 @@ INT i_APCI1710_GetUDStatus(struct comedi_device * dev, i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_GetInterruptUDLatchedStatus | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr, | -| PBYTE_ pb_UDStatus) | +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr, | +| unsigned char *_ pb_UDStatus) | +----------------------------------------------------------------------------+ | Task : Return the counter progress latched status after a | | index interrupt occur. | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | -| BYTE_ b_ModulNbr : Module number to configure | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | +| unsigned char_ b_ModulNbr : Module number to configure | | (0 to 3) | +----------------------------------------------------------------------------+ -| Output Parameters : PBYTE_ pb_UDStatus : 0 : Counter progress in the | +| Output Parameters : unsigned char *_ pb_UDStatus : 0 : Counter progress in the | | selected mode down | | 1 : Counter progress in the | | selected mode up | @@ -5040,11 +5040,11 @@ INT i_APCI1710_GetUDStatus(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -INT i_APCI1710_GetInterruptUDLatchedStatus(struct comedi_device * dev, - BYTE b_ModulNbr, PBYTE pb_UDStatus) +int i_APCI1710_GetInterruptUDLatchedStatus(struct comedi_device *dev, + unsigned char b_ModulNbr, unsigned char *pb_UDStatus) { - INT i_ReturnValue = 0; - DWORD dw_StatusReg = 0; + int i_ReturnValue = 0; + unsigned int dw_StatusReg = 0; /**************************/ /* Test the module number */ @@ -5074,7 +5074,7 @@ INT i_APCI1710_GetInterruptUDLatchedStatus(struct comedi_device * dev, dw_StatusReg = inl(devpriv->s_BoardInfos. ui_Address + 12 + (64 * b_ModulNbr)); - *pb_UDStatus = (BYTE) ((dw_StatusReg >> 1) & 1); + *pb_UDStatus = (unsigned char) ((dw_StatusReg >> 1) & 1); } else { /****************************/ /* No index interrupt occur */ @@ -5100,26 +5100,26 @@ INT i_APCI1710_GetInterruptUDLatchedStatus(struct comedi_device * dev, i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_ReadFrequencyMeasurement | - | (BYTE_ b_BoardHandle, | - | BYTE_ b_ModulNbr, | - | PBYTE_ pb_Status, | + | (unsigned char_ b_BoardHandle, | + | unsigned char_ b_ModulNbr, | + | unsigned char *_ pb_Status, | | PULONG_ pul_ReadValue) | +----------------------------------------------------------------------------+ | Task : Returns the status (pb_Status) and the number of | | increments in the set time. | | See function " i_APCI1710_InitFrequencyMeasurement " | +----------------------------------------------------------------------------+ - | Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | - | BYTE_ b_ModulNbr : Number of the module to be | + | Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | + | unsigned char_ b_ModulNbr : Number of the module to be | | configured (0 to 3) | +----------------------------------------------------------------------------+ - | Output Parameters : PBYTE_ pb_Status : Returns the frequency | + | Output Parameters : unsigned char *_ pb_Status : Returns the frequency | | measurement status | | 0 : Counting cycle not | | started. | @@ -5127,7 +5127,7 @@ INT i_APCI1710_GetInterruptUDLatchedStatus(struct comedi_device * dev, | 2 : Counting cycle stopped. | | The measurement cycle is | | completed. | - | PBYTE_ pb_UDStatus : 0 : Counter progress in the | + | unsigned char *_ pb_UDStatus : 0 : Counter progress in the | | selected mode down | | 1 : Counter progress in the | | selected mode up | @@ -5145,13 +5145,13 @@ INT i_APCI1710_GetInterruptUDLatchedStatus(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -INT i_APCI1710_ReadFrequencyMeasurement(struct comedi_device * dev, - BYTE b_ModulNbr, - PBYTE pb_Status, PBYTE pb_UDStatus, PULONG pul_ReadValue) +int i_APCI1710_ReadFrequencyMeasurement(struct comedi_device *dev, + unsigned char b_ModulNbr, + unsigned char *pb_Status, unsigned char *pb_UDStatus, unsigned int *pul_ReadValue) { - INT i_ReturnValue = 0; - UINT ui_16BitValue; - DWORD dw_StatusReg; + int i_ReturnValue = 0; + unsigned int ui_16BitValue; + unsigned int dw_StatusReg; /**************************/ /* Test the module number */ @@ -5198,7 +5198,7 @@ INT i_APCI1710_ReadFrequencyMeasurement(struct comedi_device * dev, if (dw_StatusReg & 1) { *pb_Status = 2; *pb_UDStatus = - (BYTE) ((dw_StatusReg >> + (unsigned char) ((dw_StatusReg >> 1) & 3); /******************/ @@ -5224,7 +5224,7 @@ INT i_APCI1710_ReadFrequencyMeasurement(struct comedi_device * dev, if ((*pul_ReadValue & 0xFFFFU) != 0) { ui_16BitValue = - (UINT) + (unsigned int) * pul_ReadValue & @@ -5247,7 +5247,7 @@ INT i_APCI1710_ReadFrequencyMeasurement(struct comedi_device * dev, if ((*pul_ReadValue & 0xFFFF0000UL) != 0) { ui_16BitValue = - (UINT) + (unsigned int) ( (*pul_ReadValue >> @@ -5281,7 +5281,7 @@ INT i_APCI1710_ReadFrequencyMeasurement(struct comedi_device * dev, if ((*pul_ReadValue & 0xFFFF0000UL) != 0) { ui_16BitValue = - (UINT) + (unsigned int) ( (*pul_ReadValue >> @@ -5307,7 +5307,7 @@ INT i_APCI1710_ReadFrequencyMeasurement(struct comedi_device * dev, if ((*pul_ReadValue & 0xFFFFU) != 0) { ui_16BitValue = - (UINT) + (unsigned int) * pul_ReadValue & @@ -5359,5 +5359,5 @@ INT i_APCI1710_ReadFrequencyMeasurement(struct comedi_device * dev, i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_INCCPT.h b/drivers/staging/comedi/drivers/addi-data/APCI1710_INCCPT.h index 5153cf686658..7b481107fe1d 100644 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_INCCPT.h +++ b/drivers/staging/comedi/drivers/addi-data/APCI1710_INCCPT.h @@ -132,140 +132,140 @@ #define APCI1710_INCCPT_DISABLEFREQUENCYMEASUREMENT 409 /************ Main Functions *************/ -INT i_APCI1710_InsnConfigINCCPT(struct comedi_device *dev, struct comedi_subdevice *s, +int i_APCI1710_InsnConfigINCCPT(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int * data); -INT i_APCI1710_InsnBitsINCCPT(struct comedi_device *dev, struct comedi_subdevice * s, +int i_APCI1710_InsnBitsINCCPT(struct comedi_device *dev, struct comedi_subdevice * s, struct comedi_insn *insn, unsigned int * data); -INT i_APCI1710_InsnWriteINCCPT(struct comedi_device *dev, struct comedi_subdevice * s, +int i_APCI1710_InsnWriteINCCPT(struct comedi_device *dev, struct comedi_subdevice * s, struct comedi_insn *insn, unsigned int * data); -INT i_APCI1710_InsnReadINCCPT(struct comedi_device *dev, struct comedi_subdevice * s, +int i_APCI1710_InsnReadINCCPT(struct comedi_device *dev, struct comedi_subdevice * s, struct comedi_insn *insn, unsigned int * data); /*********** Supplementary Functions********/ /* INSN CONFIG */ -INT i_APCI1710_InitCounter(struct comedi_device *dev, - BYTE b_ModulNbr, - BYTE b_CounterRange, - BYTE b_FirstCounterModus, - BYTE b_FirstCounterOption, - BYTE b_SecondCounterModus, - BYTE b_SecondCounterOption); +int i_APCI1710_InitCounter(struct comedi_device *dev, + unsigned char b_ModulNbr, + unsigned char b_CounterRange, + unsigned char b_FirstCounterModus, + unsigned char b_FirstCounterOption, + unsigned char b_SecondCounterModus, + unsigned char b_SecondCounterOption); -INT i_APCI1710_CounterAutoTest(struct comedi_device *dev, PBYTE pb_TestStatus); +int i_APCI1710_CounterAutoTest(struct comedi_device *dev, unsigned char * pb_TestStatus); -INT i_APCI1710_InitIndex(struct comedi_device *dev, - BYTE b_ModulNbr, - BYTE b_ReferenceAction, - BYTE b_IndexOperation, BYTE b_AutoMode, - BYTE b_InterruptEnable); +int i_APCI1710_InitIndex(struct comedi_device *dev, + unsigned char b_ModulNbr, + unsigned char b_ReferenceAction, + unsigned char b_IndexOperation, unsigned char b_AutoMode, + unsigned char b_InterruptEnable); -INT i_APCI1710_InitReference(struct comedi_device *dev, - BYTE b_ModulNbr, BYTE b_ReferenceLevel); +int i_APCI1710_InitReference(struct comedi_device *dev, + unsigned char b_ModulNbr, unsigned char b_ReferenceLevel); -INT i_APCI1710_InitExternalStrobe(struct comedi_device *dev, - BYTE b_ModulNbr, BYTE b_ExternalStrobe, - BYTE b_ExternalStrobeLevel); +int i_APCI1710_InitExternalStrobe(struct comedi_device *dev, + unsigned char b_ModulNbr, unsigned char b_ExternalStrobe, + unsigned char b_ExternalStrobeLevel); -INT i_APCI1710_InitCompareLogic(struct comedi_device *dev, - BYTE b_ModulNbr, UINT ui_CompareValue); +int i_APCI1710_InitCompareLogic(struct comedi_device *dev, + unsigned char b_ModulNbr, unsigned int ui_CompareValue); -INT i_APCI1710_InitFrequencyMeasurement(struct comedi_device *dev, - BYTE b_ModulNbr, - BYTE b_PCIInputClock, - BYTE b_TimingUnity, - ULONG ul_TimingInterval, - PULONG pul_RealTimingInterval); +int i_APCI1710_InitFrequencyMeasurement(struct comedi_device *dev, + unsigned char b_ModulNbr, + unsigned char b_PCIInputClock, + unsigned char b_TimingUnity, + unsigned int ul_TimingInterval, + unsigned int *pul_RealTimingInterval); /* INSN BITS */ -INT i_APCI1710_ClearCounterValue(struct comedi_device *dev, BYTE b_ModulNbr); +int i_APCI1710_ClearCounterValue(struct comedi_device *dev, unsigned char b_ModulNbr); -INT i_APCI1710_ClearAllCounterValue(struct comedi_device *dev); +int i_APCI1710_ClearAllCounterValue(struct comedi_device *dev); -INT i_APCI1710_SetInputFilter(struct comedi_device *dev, - BYTE b_ModulNbr, BYTE b_PCIInputClock, - BYTE b_Filter); +int i_APCI1710_SetInputFilter(struct comedi_device *dev, + unsigned char b_ModulNbr, unsigned char b_PCIInputClock, + unsigned char b_Filter); -INT i_APCI1710_LatchCounter(struct comedi_device *dev, - BYTE b_ModulNbr, BYTE b_LatchReg); +int i_APCI1710_LatchCounter(struct comedi_device *dev, + unsigned char b_ModulNbr, unsigned char b_LatchReg); -INT i_APCI1710_SetIndexAndReferenceSource(struct comedi_device *dev, - BYTE b_ModulNbr, - BYTE b_SourceSelection); +int i_APCI1710_SetIndexAndReferenceSource(struct comedi_device *dev, + unsigned char b_ModulNbr, + unsigned char b_SourceSelection); -INT i_APCI1710_SetDigitalChlOn(struct comedi_device *dev, BYTE b_ModulNbr); +int i_APCI1710_SetDigitalChlOn(struct comedi_device *dev, unsigned char b_ModulNbr); -INT i_APCI1710_SetDigitalChlOff(struct comedi_device *dev, BYTE b_ModulNbr); +int i_APCI1710_SetDigitalChlOff(struct comedi_device *dev, unsigned char b_ModulNbr); /* INSN WRITE */ -INT i_APCI1710_EnableLatchInterrupt(struct comedi_device *dev, BYTE b_ModulNbr); +int i_APCI1710_EnableLatchInterrupt(struct comedi_device *dev, unsigned char b_ModulNbr); -INT i_APCI1710_DisableLatchInterrupt(struct comedi_device *dev, BYTE b_ModulNbr); +int i_APCI1710_DisableLatchInterrupt(struct comedi_device *dev, unsigned char b_ModulNbr); -INT i_APCI1710_Write16BitCounterValue(struct comedi_device *dev, - BYTE b_ModulNbr, BYTE b_SelectedCounter, - UINT ui_WriteValue); +int i_APCI1710_Write16BitCounterValue(struct comedi_device *dev, + unsigned char b_ModulNbr, unsigned char b_SelectedCounter, + unsigned int ui_WriteValue); -INT i_APCI1710_Write32BitCounterValue(struct comedi_device *dev, - BYTE b_ModulNbr, ULONG ul_WriteValue); +int i_APCI1710_Write32BitCounterValue(struct comedi_device *dev, + unsigned char b_ModulNbr, unsigned int ul_WriteValue); -INT i_APCI1710_EnableIndex(struct comedi_device *dev, BYTE b_ModulNbr); +int i_APCI1710_EnableIndex(struct comedi_device *dev, unsigned char b_ModulNbr); -INT i_APCI1710_DisableIndex(struct comedi_device *dev, BYTE b_ModulNbr); +int i_APCI1710_DisableIndex(struct comedi_device *dev, unsigned char b_ModulNbr); -INT i_APCI1710_EnableCompareLogic(struct comedi_device *dev, BYTE b_ModulNbr); +int i_APCI1710_EnableCompareLogic(struct comedi_device *dev, unsigned char b_ModulNbr); -INT i_APCI1710_DisableCompareLogic(struct comedi_device *dev, BYTE b_ModulNbr); +int i_APCI1710_DisableCompareLogic(struct comedi_device *dev, unsigned char b_ModulNbr); -INT i_APCI1710_EnableFrequencyMeasurement(struct comedi_device *dev, - BYTE b_ModulNbr, - BYTE b_InterruptEnable); +int i_APCI1710_EnableFrequencyMeasurement(struct comedi_device *dev, + unsigned char b_ModulNbr, + unsigned char b_InterruptEnable); -INT i_APCI1710_DisableFrequencyMeasurement(struct comedi_device *dev, - BYTE b_ModulNbr); +int i_APCI1710_DisableFrequencyMeasurement(struct comedi_device *dev, + unsigned char b_ModulNbr); /* INSN READ */ -INT i_APCI1710_ReadLatchRegisterStatus(struct comedi_device *dev, - BYTE b_ModulNbr, BYTE b_LatchReg, - PBYTE pb_LatchStatus); +int i_APCI1710_ReadLatchRegisterStatus(struct comedi_device *dev, + unsigned char b_ModulNbr, unsigned char b_LatchReg, + unsigned char *pb_LatchStatus); -INT i_APCI1710_ReadLatchRegisterValue(struct comedi_device *dev, - BYTE b_ModulNbr, BYTE b_LatchReg, - PULONG pul_LatchValue); +int i_APCI1710_ReadLatchRegisterValue(struct comedi_device *dev, + unsigned char b_ModulNbr, unsigned char b_LatchReg, + unsigned int *pul_LatchValue); -INT i_APCI1710_Read16BitCounterValue(struct comedi_device *dev, - BYTE b_ModulNbr, BYTE b_SelectedCounter, - PUINT pui_CounterValue); +int i_APCI1710_Read16BitCounterValue(struct comedi_device *dev, + unsigned char b_ModulNbr, unsigned char b_SelectedCounter, + unsigned int *pui_CounterValue); -INT i_APCI1710_Read32BitCounterValue(struct comedi_device *dev, - BYTE b_ModulNbr, PULONG pul_CounterValue); +int i_APCI1710_Read32BitCounterValue(struct comedi_device *dev, + unsigned char b_ModulNbr, unsigned int *pul_CounterValue); -INT i_APCI1710_GetIndexStatus(struct comedi_device *dev, - BYTE b_ModulNbr, PBYTE pb_IndexStatus); +int i_APCI1710_GetIndexStatus(struct comedi_device *dev, + unsigned char b_ModulNbr, unsigned char *pb_IndexStatus); -INT i_APCI1710_GetReferenceStatus(struct comedi_device *dev, - BYTE b_ModulNbr, PBYTE pb_ReferenceStatus); +int i_APCI1710_GetReferenceStatus(struct comedi_device *dev, + unsigned char b_ModulNbr, unsigned char *pb_ReferenceStatus); -INT i_APCI1710_GetUASStatus(struct comedi_device *dev, - BYTE b_ModulNbr, PBYTE pb_UASStatus); +int i_APCI1710_GetUASStatus(struct comedi_device *dev, + unsigned char b_ModulNbr, unsigned char *pb_UASStatus); -INT i_APCI1710_GetCBStatus(struct comedi_device *dev, - BYTE b_ModulNbr, PBYTE pb_CBStatus); +int i_APCI1710_GetCBStatus(struct comedi_device *dev, + unsigned char b_ModulNbr, unsigned char *pb_CBStatus); -INT i_APCI1710_Get16BitCBStatus(struct comedi_device *dev, - BYTE b_ModulNbr, PBYTE pb_CBStatusCounter0, - PBYTE pb_CBStatusCounter1); +int i_APCI1710_Get16BitCBStatus(struct comedi_device *dev, + unsigned char b_ModulNbr, unsigned char *pb_CBStatusCounter0, + unsigned char *pb_CBStatusCounter1); -INT i_APCI1710_GetUDStatus(struct comedi_device *dev, - BYTE b_ModulNbr, PBYTE pb_UDStatus); +int i_APCI1710_GetUDStatus(struct comedi_device *dev, + unsigned char b_ModulNbr, unsigned char *pb_UDStatus); -INT i_APCI1710_GetInterruptUDLatchedStatus(struct comedi_device *dev, - BYTE b_ModulNbr, PBYTE pb_UDStatus); +int i_APCI1710_GetInterruptUDLatchedStatus(struct comedi_device *dev, + unsigned char b_ModulNbr, unsigned char *pb_UDStatus); -INT i_APCI1710_ReadFrequencyMeasurement(struct comedi_device *dev, - BYTE b_ModulNbr, - PBYTE pb_Status, PBYTE pb_UDStatus, - PULONG pul_ReadValue); +int i_APCI1710_ReadFrequencyMeasurement(struct comedi_device *dev, + unsigned char b_ModulNbr, + unsigned char *pb_Status, unsigned char *pb_UDStatus, + unsigned int *pul_ReadValue); diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Inp_cpt.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_Inp_cpt.c index 3ac6a264ef54..0fc2285c9ef8 100644 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Inp_cpt.c +++ b/drivers/staging/comedi/drivers/addi-data/APCI1710_Inp_cpt.c @@ -3,13 +3,13 @@ Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data-com - info@addi-data.com + ADDI-DATA GmbH + Dieselstrasse 3 + D-77833 Ottersweier + Tel: +19(0)7223/9493-0 + Fax: +49(0)7223/9493-92 + http://www.addi-data-com + info@addi-data.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. @@ -60,11 +60,11 @@ You shoud also find the complete GPL in the COPYING file accompanying this sourc /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_InitPulseEncoder | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr, | -| BYTE_ b_PulseEncoderNbr, | -| BYTE_ b_InputLevelSelection, | -| BYTE_ b_TriggerOutputAction, | +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr, | +| unsigned char_ b_PulseEncoderNbr, | +| unsigned char_ b_InputLevelSelection, | +| unsigned char_ b_TriggerOutputAction, | | ULONG_ ul_StartValue) | +----------------------------------------------------------------------------+ | Task : Configure the pulse encoder operating mode selected via| @@ -74,12 +74,12 @@ You shoud also find the complete GPL in the COPYING file accompanying this sourc | You must calling this function be for you call any | | other function witch access of pulse encoders. | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710| -| BYTE_ b_ModulNbr : Module number to | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710| +| unsigned char_ b_ModulNbr : Module number to | | configure (0 to 3) | -| BYTE_ b_PulseEncoderNbr : Pulse encoder selection | +| unsigned char_ b_PulseEncoderNbr : Pulse encoder selection | | (0 to 3) | -| BYTE_ b_InputLevelSelection : Input level selection | +| unsigned char_ b_InputLevelSelection : Input level selection | | (0 or 1) | | 0 : Set pulse encoder| | count the the low| @@ -87,7 +87,7 @@ You shoud also find the complete GPL in the COPYING file accompanying this sourc | 1 : Set pulse encoder| | count the the | | high level pulse.| -| BYTE_ b_TriggerOutputAction : Digital TRIGGER output | +| unsigned char_ b_TriggerOutputAction : Digital TRIGGER output | | action | | 0 : No action | | 1 : Set the trigger | @@ -104,11 +104,11 @@ You shoud also find the complete GPL in the COPYING file accompanying this sourc | encoder | | ULONG_ ul_StartValue : Pulse encoder start value| | (1 to 4294967295) - b_ModulNbr =(BYTE) CR_AREF(insn->chanspec); - b_PulseEncoderNbr =(BYTE) data[0]; - b_InputLevelSelection =(BYTE) data[1]; - b_TriggerOutputAction =(BYTE) data[2]; - ul_StartValue =(ULONG) data[3]; + b_ModulNbr =(unsigned char) CR_AREF(insn->chanspec); + b_PulseEncoderNbr =(unsigned char) data[0]; + b_InputLevelSelection =(unsigned char) data[1]; + b_TriggerOutputAction =(unsigned char) data[2]; + ul_StartValue =(unsigned int) data[3]; | +----------------------------------------------------------------------------+ | Output Parameters : - | @@ -123,23 +123,23 @@ You shoud also find the complete GPL in the COPYING file accompanying this sourc +----------------------------------------------------------------------------+ */ -INT i_APCI1710_InsnConfigInitPulseEncoder(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +int i_APCI1710_InsnConfigInitPulseEncoder(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - INT i_ReturnValue = 0; - DWORD dw_IntRegister; + int i_ReturnValue = 0; + unsigned int dw_IntRegister; - BYTE b_ModulNbr; - BYTE b_PulseEncoderNbr; - BYTE b_InputLevelSelection; - BYTE b_TriggerOutputAction; - ULONG ul_StartValue; + unsigned char b_ModulNbr; + unsigned char b_PulseEncoderNbr; + unsigned char b_InputLevelSelection; + unsigned char b_TriggerOutputAction; + unsigned int ul_StartValue; - b_ModulNbr = (BYTE) CR_AREF(insn->chanspec); - b_PulseEncoderNbr = (BYTE) data[0]; - b_InputLevelSelection = (BYTE) data[1]; - b_TriggerOutputAction = (BYTE) data[2]; - ul_StartValue = (ULONG) data[3]; + b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); + b_PulseEncoderNbr = (unsigned char) data[0]; + b_InputLevelSelection = (unsigned char) data[1]; + b_TriggerOutputAction = (unsigned char) data[2]; + ul_StartValue = (unsigned int) data[3]; i_ReturnValue = insn->n; @@ -346,17 +346,17 @@ INT i_APCI1710_InsnConfigInitPulseEncoder(struct comedi_device * dev, i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_EnablePulseEncoder | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr, | -| BYTE_ b_PulseEncoderNbr, | -| BYTE_ b_CycleSelection, | -| BYTE_ b_InterruptHandling) | +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr, | +| unsigned char_ b_PulseEncoderNbr, | +| unsigned char_ b_CycleSelection, | +| unsigned char_ b_InterruptHandling) | +----------------------------------------------------------------------------+ | Task : Enableor disable the selected pulse encoder (b_PulseEncoderNbr) | | from selected module (b_ModulNbr). Each input pulse | @@ -365,12 +365,12 @@ INT i_APCI1710_InsnConfigInitPulseEncoder(struct comedi_device * dev, | interrupt is generated when the pulse encoder has run | | down. | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710| -| BYTE_ b_ModulNbr : Module number to | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710| +| unsigned char_ b_ModulNbr : Module number to | | configure (0 to 3) | -| BYTE_ b_PulseEncoderNbr : Pulse encoder selection | +| unsigned char_ b_PulseEncoderNbr : Pulse encoder selection | | (0 to 3) | -| BYTE_ b_CycleSelection : APCI1710_CONTINUOUS: | +| unsigned char_ b_CycleSelection : APCI1710_CONTINUOUS: | | Each time the | | counting value is set| | on "0", the pulse | @@ -381,7 +381,7 @@ INT i_APCI1710_InsnConfigInitPulseEncoder(struct comedi_device * dev, | If the counter is set| | on "0", the pulse | | encoder is stopped. | -| BYTE_ b_InterruptHandling : Interrupts can be | +| unsigned char_ b_InterruptHandling : Interrupts can be | | generated, when the pulse| | encoder has run down. | | With this parameter the | @@ -393,11 +393,11 @@ INT i_APCI1710_InsnConfigInitPulseEncoder(struct comedi_device * dev, | APCI1710_DISABLE: | | Interrupts are disabled - b_ModulNbr =(BYTE) CR_AREF(insn->chanspec); - b_Action =(BYTE) data[0]; - b_PulseEncoderNbr =(BYTE) data[1]; - b_CycleSelection =(BYTE) data[2]; - b_InterruptHandling =(BYTE) data[3];| + b_ModulNbr =(unsigned char) CR_AREF(insn->chanspec); + b_Action =(unsigned char) data[0]; + b_PulseEncoderNbr =(unsigned char) data[1]; + b_CycleSelection =(unsigned char) data[2]; + b_InterruptHandling =(unsigned char) data[3];| +----------------------------------------------------------------------------+ | Output Parameters : - | +----------------------------------------------------------------------------+ @@ -414,22 +414,22 @@ INT i_APCI1710_InsnConfigInitPulseEncoder(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -INT i_APCI1710_InsnWriteEnableDisablePulseEncoder(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +int i_APCI1710_InsnWriteEnableDisablePulseEncoder(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - INT i_ReturnValue = 0; - BYTE b_ModulNbr; - BYTE b_PulseEncoderNbr; - BYTE b_CycleSelection; - BYTE b_InterruptHandling; - BYTE b_Action; + int i_ReturnValue = 0; + unsigned char b_ModulNbr; + unsigned char b_PulseEncoderNbr; + unsigned char b_CycleSelection; + unsigned char b_InterruptHandling; + unsigned char b_Action; i_ReturnValue = insn->n; - b_ModulNbr = (BYTE) CR_AREF(insn->chanspec); - b_Action = (BYTE) data[0]; - b_PulseEncoderNbr = (BYTE) data[1]; - b_CycleSelection = (BYTE) data[2]; - b_InterruptHandling = (BYTE) data[3]; + b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); + b_Action = (unsigned char) data[0]; + b_PulseEncoderNbr = (unsigned char) data[1]; + b_CycleSelection = (unsigned char) data[2]; + b_InterruptHandling = (unsigned char) data[3]; /***********************************/ /* Test the selected module number */ @@ -515,7 +515,7 @@ INT i_APCI1710_InsnWriteEnableDisablePulseEncoder(struct comedi_device * dev, | (1UL << b_PulseEncoderNbr); - devpriv->tsk_Current = current; // Save the current process task structure + devpriv->tsk_Current = current; /* Save the current process task structure */ } @@ -629,7 +629,7 @@ INT i_APCI1710_InsnWriteEnableDisablePulseEncoder(struct comedi_device * dev, (64 * b_ModulNbr)); break; - } // switch End + } /* switch End */ } else { /*********************************/ @@ -656,39 +656,39 @@ INT i_APCI1710_InsnWriteEnableDisablePulseEncoder(struct comedi_device * dev, i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_ReadPulseEncoderStatus | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr, | -| BYTE_ b_PulseEncoderNbr, | -| PBYTE_ pb_Status) | +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr, | +| unsigned char_ b_PulseEncoderNbr, | +| unsigned char *_ pb_Status) | +----------------------------------------------------------------------------+ | Task APCI1710_PULSEENCODER_READ : Reads the pulse encoder status and valuefrom selected pulse | | encoder (b_PulseEncoderNbr) from selected module | | (b_ModulNbr). | +----------------------------------------------------------------------------+ - BYTE b_Type; data[0] + unsigned char b_Type; data[0] APCI1710_PULSEENCODER_WRITE Writes a 32-bit value (ul_WriteValue) into the selected| | pulse encoder (b_PulseEncoderNbr) from selected module | | (b_ModulNbr). This operation set the new start pulse | | encoder value. APCI1710_PULSEENCODER_READ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710| -| CRAREF() BYTE_ b_ModulNbr : Module number to | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710| +| CRAREF() unsigned char_ b_ModulNbr : Module number to | | configure (0 to 3) | -| data[1] BYTE_ b_PulseEncoderNbr : Pulse encoder selection | +| data[1] unsigned char_ b_PulseEncoderNbr : Pulse encoder selection | | (0 to 3) APCI1710_PULSEENCODER_WRITE data[2] ULONG_ ul_WriteValue : 32-bit value to be | | written | +----------------------------------------------------------------------------+ -| Output Parameters : PBYTE_ pb_Status : Pulse encoder status. | +| Output Parameters : unsigned char *_ pb_Status : Pulse encoder status. | | 0 : No overflow occur| | 1 : Overflow occur PULONG_ pul_ReadValue : Pulse encoder value | | @@ -702,30 +702,30 @@ INT i_APCI1710_InsnWriteEnableDisablePulseEncoder(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -/*_INT_ i_APCI1710_ReadPulseEncoderStatus (BYTE_ b_BoardHandle, - BYTE_ b_ModulNbr, - BYTE_ b_PulseEncoderNbr, +/*_INT_ i_APCI1710_ReadPulseEncoderStatus (unsigned char_ b_BoardHandle, + unsigned char_ b_ModulNbr, + unsigned char_ b_PulseEncoderNbr, - PBYTE_ pb_Status) + unsigned char *_ pb_Status) */ -INT i_APCI1710_InsnBitsReadWritePulseEncoder(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +int i_APCI1710_InsnBitsReadWritePulseEncoder(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - INT i_ReturnValue = 0; - DWORD dw_StatusRegister; - BYTE b_ModulNbr; - BYTE b_PulseEncoderNbr; - PBYTE pb_Status; - BYTE b_Type; - PULONG pul_ReadValue; - ULONG ul_WriteValue; + int i_ReturnValue = 0; + unsigned int dw_StatusRegister; + unsigned char b_ModulNbr; + unsigned char b_PulseEncoderNbr; + unsigned char *pb_Status; + unsigned char b_Type; + unsigned int *pul_ReadValue; + unsigned int ul_WriteValue; i_ReturnValue = insn->n; - b_ModulNbr = (BYTE) CR_AREF(insn->chanspec); - b_Type = (BYTE) data[0]; - b_PulseEncoderNbr = (BYTE) data[1]; - pb_Status = (PBYTE) & data[0]; - pul_ReadValue = (PULONG) & data[1]; + b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); + b_Type = (unsigned char) data[0]; + b_PulseEncoderNbr = (unsigned char) data[1]; + pb_Status = (unsigned char *) &data[0]; + pul_ReadValue = (unsigned int *) &data[1]; /***********************************/ /* Test the selected module number */ @@ -766,7 +766,7 @@ INT i_APCI1710_InsnBitsReadWritePulseEncoder(struct comedi_device * dev, dw_StatusRegister; *pb_Status = - (BYTE) (devpriv-> + (unsigned char) (devpriv-> s_ModuleInfo[b_ModulNbr]. s_PulseEncoderModuleInfo. dw_StatusRegister >> (1 + @@ -794,7 +794,7 @@ INT i_APCI1710_InsnBitsReadWritePulseEncoder(struct comedi_device * dev, break; case APCI1710_PULSEENCODER_WRITE: - ul_WriteValue = (ULONG) data[2]; + ul_WriteValue = (unsigned int) data[2]; /*******************/ /* Write the value */ /*******************/ @@ -805,7 +805,7 @@ INT i_APCI1710_InsnBitsReadWritePulseEncoder(struct comedi_device * dev, (4 * b_PulseEncoderNbr) + (64 * b_ModulNbr)); - } //end of switch + } /* end of switch */ } else { /*********************************/ /* Pulse encoder not initialised */ @@ -831,11 +831,11 @@ INT i_APCI1710_InsnBitsReadWritePulseEncoder(struct comedi_device * dev, i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } -INT i_APCI1710_InsnReadInterruptPulseEncoder(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +int i_APCI1710_InsnReadInterruptPulseEncoder(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { data[0] = devpriv->s_InterruptParameters. diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Inp_cpt.h b/drivers/staging/comedi/drivers/addi-data/APCI1710_Inp_cpt.h index 28252873e862..61a21cc94063 100644 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Inp_cpt.h +++ b/drivers/staging/comedi/drivers/addi-data/APCI1710_Inp_cpt.h @@ -21,11 +21,11 @@ #define APCI1710_PULSEENCODER_READ 0 #define APCI1710_PULSEENCODER_WRITE 1 -INT i_APCI1710_InsnConfigInitPulseEncoder(struct comedi_device *dev, +int i_APCI1710_InsnConfigInitPulseEncoder(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -INT i_APCI1710_InsnWriteEnableDisablePulseEncoder(struct comedi_device *dev, +int i_APCI1710_InsnWriteEnableDisablePulseEncoder(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); @@ -33,7 +33,7 @@ INT i_APCI1710_InsnWriteEnableDisablePulseEncoder(struct comedi_device *dev, /* * READ PULSE ENCODER FUNCTIONS */ -INT i_APCI1710_InsnReadInterruptPulseEncoder(struct comedi_device *dev, +int i_APCI1710_InsnReadInterruptPulseEncoder(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); @@ -41,7 +41,7 @@ INT i_APCI1710_InsnReadInterruptPulseEncoder(struct comedi_device *dev, /* * WRITE PULSE ENCODER FUNCTIONS */ -INT i_APCI1710_InsnBitsReadWritePulseEncoder(struct comedi_device *dev, +int i_APCI1710_InsnBitsReadWritePulseEncoder(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Pwm.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_Pwm.c index 5ddd092a656a..138a84f572c8 100644 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Pwm.c +++ b/drivers/staging/comedi/drivers/addi-data/APCI1710_Pwm.c @@ -3,13 +3,13 @@ Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data-com - info@addi-data.com + ADDI-DATA GmbH + Dieselstrasse 3 + D-77833 Ottersweier + Tel: +19(0)7223/9493-0 + Fax: +49(0)7223/9493-92 + http://www.addi-data-com + info@addi-data.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. @@ -70,38 +70,38 @@ struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) +----------------------------------------------------------------------------+ */ -INT i_APCI1710_InsnConfigPWM(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI1710_InsnConfigPWM(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - BYTE b_ConfigType; - INT i_ReturnValue = 0; + unsigned char b_ConfigType; + int i_ReturnValue = 0; b_ConfigType = CR_CHAN(insn->chanspec); switch (b_ConfigType) { case APCI1710_PWM_INIT: - i_ReturnValue = i_APCI1710_InitPWM(dev, (BYTE) CR_AREF(insn->chanspec), // b_ModulNbr - (BYTE) data[0], //b_PWM - (BYTE) data[1], // b_ClockSelection - (BYTE) data[2], // b_TimingUnit - (ULONG) data[3], //ul_LowTiming - (ULONG) data[4], //ul_HighTiming - (PULONG) & data[0], //pul_RealLowTiming - (PULONG) & data[1] //pul_RealHighTiming + i_ReturnValue = i_APCI1710_InitPWM(dev, (unsigned char) CR_AREF(insn->chanspec), /* b_ModulNbr */ + (unsigned char) data[0], /* b_PWM */ + (unsigned char) data[1], /* b_ClockSelection */ + (unsigned char) data[2], /* b_TimingUnit */ + (unsigned int) data[3], /* ul_LowTiming */ + (unsigned int) data[4], /* ul_HighTiming */ + (unsigned int *) &data[0], /* pul_RealLowTiming */ + (unsigned int *) &data[1] /* pul_RealHighTiming */ ); break; case APCI1710_PWM_GETINITDATA: - i_ReturnValue = i_APCI1710_GetPWMInitialisation(dev, (BYTE) CR_AREF(insn->chanspec), // b_ModulNbr - (BYTE) data[0], //b_PWM - (PBYTE) & data[0], //pb_TimingUnit - (PULONG) & data[1], //pul_LowTiming - (PULONG) & data[2], //pul_HighTiming - (PBYTE) & data[3], // pb_StartLevel - (PBYTE) & data[4], // pb_StopMode - (PBYTE) & data[5], // pb_StopLevel - (PBYTE) & data[6], // pb_ExternGate - (PBYTE) & data[7], // pb_InterruptEnable - (PBYTE) & data[8] // pb_Enable + i_ReturnValue = i_APCI1710_GetPWMInitialisation(dev, (unsigned char) CR_AREF(insn->chanspec), /* b_ModulNbr */ + (unsigned char) data[0], /* b_PWM */ + (unsigned char *) &data[0], /* pb_TimingUnit */ + (unsigned int *) &data[1], /* pul_LowTiming */ + (unsigned int *) &data[2], /* pul_HighTiming */ + (unsigned char *) &data[3], /* pb_StartLevel */ + (unsigned char *) &data[4], /* pb_StopMode */ + (unsigned char *) &data[5], /* pb_StopLevel */ + (unsigned char *) &data[6], /* pb_ExternGate */ + (unsigned char *) &data[7], /* pb_InterruptEnable */ + (unsigned char *) &data[8] /* pb_Enable */ ); break; @@ -111,17 +111,17 @@ INT i_APCI1710_InsnConfigPWM(struct comedi_device * dev, struct comedi_subdevice if (i_ReturnValue >= 0) i_ReturnValue = insn->n; - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_InitPWM | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr, | -| BYTE_ b_PWM, | -| BYTE_ b_ClockSelection, | -| BYTE_ b_TimingUnit, | +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr, | +| unsigned char_ b_PWM, | +| unsigned char_ b_ClockSelection, | +| unsigned char_ b_TimingUnit, | | ULONG_ ul_LowTiming, | | ULONG_ ul_HighTiming, | | PULONG_ pul_RealLowTiming, | @@ -135,11 +135,11 @@ INT i_APCI1710_InsnConfigPWM(struct comedi_device * dev, struct comedi_subdevice | You must calling this function be for you call any | | other function witch access of the PWM. | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | -| BYTE_ b_ModulNbr : Module number to configure| +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | +| unsigned char_ b_ModulNbr : Module number to configure| | (0 to 3) | -| BYTE_ b_PWM : Selected PWM (0 or 1). | -| BYTE_ b_ClockSelection : Selection from PCI bus | +| unsigned char_ b_PWM : Selected PWM (0 or 1). | +| unsigned char_ b_ClockSelection : Selection from PCI bus | | clock | | - APCI1710_30MHZ : | | The PC have a 30 MHz | @@ -151,7 +151,7 @@ INT i_APCI1710_InsnConfigPWM(struct comedi_device * dev, struct comedi_subdevice | The APCI-1710 have a | | integrated 40Mhz | | quartz. | -| BYTE_ b_TimingUnit : Base timing Unit (0 to 4) | +| unsigned char_ b_TimingUnit : Base timing Unit (0 to 4) | | 0 : ns | | 1 : æs | | 2 : ms | @@ -179,19 +179,19 @@ INT i_APCI1710_InsnConfigPWM(struct comedi_device * dev, struct comedi_subdevice +----------------------------------------------------------------------------+ */ -INT i_APCI1710_InitPWM(struct comedi_device * dev, - BYTE b_ModulNbr, - BYTE b_PWM, - BYTE b_ClockSelection, - BYTE b_TimingUnit, - ULONG ul_LowTiming, - ULONG ul_HighTiming, - PULONG pul_RealLowTiming, PULONG pul_RealHighTiming) +int i_APCI1710_InitPWM(struct comedi_device *dev, + unsigned char b_ModulNbr, + unsigned char b_PWM, + unsigned char b_ClockSelection, + unsigned char b_TimingUnit, + unsigned int ul_LowTiming, + unsigned int ul_HighTiming, + unsigned int *pul_RealLowTiming, unsigned int *pul_RealHighTiming) { - INT i_ReturnValue = 0; - ULONG ul_LowTimerValue = 0; - ULONG ul_HighTimerValue = 0; - DWORD dw_Command; + int i_ReturnValue = 0; + unsigned int ul_LowTimerValue = 0; + unsigned int ul_HighTimerValue = 0; + unsigned int dw_Command; double d_RealLowTiming = 0; double d_RealHighTiming = 0; @@ -200,33 +200,33 @@ INT i_APCI1710_InitPWM(struct comedi_device * dev, /**************************/ if (b_ModulNbr < 4) { - /***************/ + /***************/ /* Test if PWM */ - /***************/ + /***************/ if ((devpriv->s_BoardInfos. dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF0000UL) == APCI1710_PWM) { - /**************************/ + /**************************/ /* Test the PWM selection */ - /**************************/ + /**************************/ if (b_PWM <= 1) { - /******************/ + /******************/ /* Test the clock */ - /******************/ + /******************/ if ((b_ClockSelection == APCI1710_30MHZ) || (b_ClockSelection == APCI1710_33MHZ) || (b_ClockSelection == APCI1710_40MHZ)) { - /************************/ + /************************/ /* Test the timing unit */ - /************************/ + /************************/ if (b_TimingUnit <= 4) { - /*********************************/ + /*********************************/ /* Test the low timing selection */ - /*********************************/ + /*********************************/ if (((b_ClockSelection == APCI1710_30MHZ) @@ -361,45 +361,45 @@ INT i_APCI1710_InitPWM(struct comedi_device * dev, && (ul_LowTiming <= 7UL))) { - /**********************************/ + /**********************************/ /* Test the High timing selection */ - /**********************************/ + /**********************************/ if (((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 0) && (ul_HighTiming >= 266) && (ul_HighTiming <= 0xFFFFFFFFUL)) || ((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 1) && (ul_HighTiming >= 1) && (ul_HighTiming <= 571230650UL)) || ((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 2) && (ul_HighTiming >= 1) && (ul_HighTiming <= 571230UL)) || ((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 3) && (ul_HighTiming >= 1) && (ul_HighTiming <= 571UL)) || ((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 4) && (ul_HighTiming >= 1) && (ul_HighTiming <= 9UL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 0) && (ul_HighTiming >= 242) && (ul_HighTiming <= 0xFFFFFFFFUL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 1) && (ul_HighTiming >= 1) && (ul_HighTiming <= 519691043UL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 2) && (ul_HighTiming >= 1) && (ul_HighTiming <= 519691UL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 3) && (ul_HighTiming >= 1) && (ul_HighTiming <= 520UL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 4) && (ul_HighTiming >= 1) && (ul_HighTiming <= 8UL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 0) && (ul_HighTiming >= 200) && (ul_HighTiming <= 0xFFFFFFFFUL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 1) && (ul_HighTiming >= 1) && (ul_HighTiming <= 429496729UL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 2) && (ul_HighTiming >= 1) && (ul_HighTiming <= 429496UL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 3) && (ul_HighTiming >= 1) && (ul_HighTiming <= 429UL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 4) && (ul_HighTiming >= 1) && (ul_HighTiming <= 7UL))) { - /**************************/ + /**************************/ /* Test the board version */ - /**************************/ + /**************************/ if (((b_ClockSelection == APCI1710_40MHZ) && (devpriv->s_BoardInfos.b_BoardVersion > 0)) || (b_ClockSelection != APCI1710_40MHZ)) { - /************************************/ + /************************************/ /* Calculate the low division fator */ - /************************************/ + /************************************/ fpu_begin (); switch (b_TimingUnit) { - /******/ + /******/ /* ns */ - /******/ + /******/ case 0: - /******************/ + /******************/ /* Timer 0 factor */ - /******************/ + /******************/ ul_LowTimerValue = - (ULONG) + (unsigned int) (ul_LowTiming * (0.00025 * b_ClockSelection)); - /*******************/ + /*******************/ /* Round the value */ - /*******************/ + /*******************/ if ((double)((double)ul_LowTiming * (0.00025 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) { ul_LowTimerValue @@ -409,13 +409,13 @@ INT i_APCI1710_InitPWM(struct comedi_device * dev, 1; } - /*****************************/ + /*****************************/ /* Calculate the real timing */ - /*****************************/ + /*****************************/ *pul_RealLowTiming = - (ULONG) + (unsigned int) (ul_LowTimerValue / (0.00025 * (double)b_ClockSelection)); @@ -451,7 +451,7 @@ INT i_APCI1710_InitPWM(struct comedi_device * dev, if (b_ClockSelection != APCI1710_40MHZ) { ul_LowTimerValue = - (ULONG) + (unsigned int) ( (double) (ul_LowTimerValue) @@ -461,26 +461,26 @@ INT i_APCI1710_InitPWM(struct comedi_device * dev, break; - /******/ + /******/ /* æs */ - /******/ + /******/ case 1: - /******************/ + /******************/ /* Timer 0 factor */ - /******************/ + /******************/ ul_LowTimerValue = - (ULONG) + (unsigned int) (ul_LowTiming * (0.25 * b_ClockSelection)); - /*******************/ + /*******************/ /* Round the value */ - /*******************/ + /*******************/ if ((double)((double)ul_LowTiming * (0.25 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) { ul_LowTimerValue @@ -490,13 +490,13 @@ INT i_APCI1710_InitPWM(struct comedi_device * dev, 1; } - /*****************************/ + /*****************************/ /* Calculate the real timing */ - /*****************************/ + /*****************************/ *pul_RealLowTiming = - (ULONG) + (unsigned int) (ul_LowTimerValue / (0.25 * (double)b_ClockSelection)); @@ -534,7 +534,7 @@ INT i_APCI1710_InitPWM(struct comedi_device * dev, if (b_ClockSelection != APCI1710_40MHZ) { ul_LowTimerValue = - (ULONG) + (unsigned int) ( (double) (ul_LowTimerValue) @@ -544,15 +544,15 @@ INT i_APCI1710_InitPWM(struct comedi_device * dev, break; - /******/ + /******/ /* ms */ - /******/ + /******/ case 2: - /******************/ + /******************/ /* Timer 0 factor */ - /******************/ + /******************/ ul_LowTimerValue = @@ -562,9 +562,9 @@ INT i_APCI1710_InitPWM(struct comedi_device * dev, * b_ClockSelection); - /*******************/ + /*******************/ /* Round the value */ - /*******************/ + /*******************/ if ((double)((double)ul_LowTiming * (250.0 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) { ul_LowTimerValue @@ -574,13 +574,13 @@ INT i_APCI1710_InitPWM(struct comedi_device * dev, 1; } - /*****************************/ + /*****************************/ /* Calculate the real timing */ - /*****************************/ + /*****************************/ *pul_RealLowTiming = - (ULONG) + (unsigned int) (ul_LowTimerValue / (250.0 * (double)b_ClockSelection)); @@ -616,7 +616,7 @@ INT i_APCI1710_InitPWM(struct comedi_device * dev, if (b_ClockSelection != APCI1710_40MHZ) { ul_LowTimerValue = - (ULONG) + (unsigned int) ( (double) (ul_LowTimerValue) @@ -626,27 +626,27 @@ INT i_APCI1710_InitPWM(struct comedi_device * dev, break; - /*****/ + /*****/ /* s */ - /*****/ + /*****/ case 3: - /******************/ + /******************/ /* Timer 0 factor */ - /******************/ + /******************/ ul_LowTimerValue = - (ULONG) + (unsigned int) (ul_LowTiming * (250000.0 * b_ClockSelection)); - /*******************/ + /*******************/ /* Round the value */ - /*******************/ + /*******************/ if ((double)((double)ul_LowTiming * (250000.0 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) { ul_LowTimerValue @@ -656,13 +656,13 @@ INT i_APCI1710_InitPWM(struct comedi_device * dev, 1; } - /*****************************/ + /*****************************/ /* Calculate the real timing */ - /*****************************/ + /*****************************/ *pul_RealLowTiming = - (ULONG) + (unsigned int) (ul_LowTimerValue / (250000.0 @@ -701,7 +701,7 @@ INT i_APCI1710_InitPWM(struct comedi_device * dev, if (b_ClockSelection != APCI1710_40MHZ) { ul_LowTimerValue = - (ULONG) + (unsigned int) ( (double) (ul_LowTimerValue) @@ -711,19 +711,19 @@ INT i_APCI1710_InitPWM(struct comedi_device * dev, break; - /******/ + /******/ /* mn */ - /******/ + /******/ case 4: - /******************/ + /******************/ /* Timer 0 factor */ - /******************/ + /******************/ ul_LowTimerValue = - (ULONG) + (unsigned int) ( (ul_LowTiming * @@ -733,9 +733,9 @@ INT i_APCI1710_InitPWM(struct comedi_device * dev, * b_ClockSelection)); - /*******************/ + /*******************/ /* Round the value */ - /*******************/ + /*******************/ if ((double)((double)(ul_LowTiming * 60.0) * (250000.0 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) { ul_LowTimerValue @@ -745,13 +745,13 @@ INT i_APCI1710_InitPWM(struct comedi_device * dev, 1; } - /*****************************/ + /*****************************/ /* Calculate the real timing */ - /*****************************/ + /*****************************/ *pul_RealLowTiming = - (ULONG) + (unsigned int) (ul_LowTimerValue / (250000.0 @@ -795,7 +795,7 @@ INT i_APCI1710_InitPWM(struct comedi_device * dev, if (b_ClockSelection != APCI1710_40MHZ) { ul_LowTimerValue = - (ULONG) + (unsigned int) ( (double) (ul_LowTimerValue) @@ -806,31 +806,31 @@ INT i_APCI1710_InitPWM(struct comedi_device * dev, break; } - /*************************************/ + /*************************************/ /* Calculate the high division fator */ - /*************************************/ + /*************************************/ switch (b_TimingUnit) { - /******/ + /******/ /* ns */ - /******/ + /******/ case 0: - /******************/ + /******************/ /* Timer 0 factor */ - /******************/ + /******************/ ul_HighTimerValue = - (ULONG) + (unsigned int) (ul_HighTiming * (0.00025 * b_ClockSelection)); - /*******************/ + /*******************/ /* Round the value */ - /*******************/ + /*******************/ if ((double)((double)ul_HighTiming * (0.00025 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) { ul_HighTimerValue @@ -840,13 +840,13 @@ INT i_APCI1710_InitPWM(struct comedi_device * dev, 1; } - /*****************************/ + /*****************************/ /* Calculate the real timing */ - /*****************************/ + /*****************************/ *pul_RealHighTiming = - (ULONG) + (unsigned int) (ul_HighTimerValue / (0.00025 * (double)b_ClockSelection)); @@ -882,7 +882,7 @@ INT i_APCI1710_InitPWM(struct comedi_device * dev, if (b_ClockSelection != APCI1710_40MHZ) { ul_HighTimerValue = - (ULONG) + (unsigned int) ( (double) (ul_HighTimerValue) @@ -892,26 +892,26 @@ INT i_APCI1710_InitPWM(struct comedi_device * dev, break; - /******/ + /******/ /* æs */ - /******/ + /******/ case 1: - /******************/ + /******************/ /* Timer 0 factor */ - /******************/ + /******************/ ul_HighTimerValue = - (ULONG) + (unsigned int) (ul_HighTiming * (0.25 * b_ClockSelection)); - /*******************/ + /*******************/ /* Round the value */ - /*******************/ + /*******************/ if ((double)((double)ul_HighTiming * (0.25 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) { ul_HighTimerValue @@ -921,13 +921,13 @@ INT i_APCI1710_InitPWM(struct comedi_device * dev, 1; } - /*****************************/ + /*****************************/ /* Calculate the real timing */ - /*****************************/ + /*****************************/ *pul_RealHighTiming = - (ULONG) + (unsigned int) (ul_HighTimerValue / (0.25 * (double)b_ClockSelection)); @@ -965,7 +965,7 @@ INT i_APCI1710_InitPWM(struct comedi_device * dev, if (b_ClockSelection != APCI1710_40MHZ) { ul_HighTimerValue = - (ULONG) + (unsigned int) ( (double) (ul_HighTimerValue) @@ -975,15 +975,15 @@ INT i_APCI1710_InitPWM(struct comedi_device * dev, break; - /******/ + /******/ /* ms */ - /******/ + /******/ case 2: - /******************/ + /******************/ /* Timer 0 factor */ - /******************/ + /******************/ ul_HighTimerValue = @@ -993,9 +993,9 @@ INT i_APCI1710_InitPWM(struct comedi_device * dev, * b_ClockSelection); - /*******************/ + /*******************/ /* Round the value */ - /*******************/ + /*******************/ if ((double)((double)ul_HighTiming * (250.0 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) { ul_HighTimerValue @@ -1005,13 +1005,13 @@ INT i_APCI1710_InitPWM(struct comedi_device * dev, 1; } - /*****************************/ + /*****************************/ /* Calculate the real timing */ - /*****************************/ + /*****************************/ *pul_RealHighTiming = - (ULONG) + (unsigned int) (ul_HighTimerValue / (250.0 * (double)b_ClockSelection)); @@ -1047,7 +1047,7 @@ INT i_APCI1710_InitPWM(struct comedi_device * dev, if (b_ClockSelection != APCI1710_40MHZ) { ul_HighTimerValue = - (ULONG) + (unsigned int) ( (double) (ul_HighTimerValue) @@ -1057,28 +1057,28 @@ INT i_APCI1710_InitPWM(struct comedi_device * dev, break; - /*****/ + /*****/ /* s */ - /*****/ + /*****/ case 3: - /******************/ + /******************/ /* Timer 0 factor */ - /******************/ + /******************/ ul_HighTimerValue = - (ULONG) + (unsigned int) (ul_HighTiming * (250000.0 * b_ClockSelection)); - /*******************/ + /*******************/ /* Round the value */ - /*******************/ + /*******************/ if ((double)((double)ul_HighTiming * (250000.0 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) { ul_HighTimerValue @@ -1088,13 +1088,13 @@ INT i_APCI1710_InitPWM(struct comedi_device * dev, 1; } - /*****************************/ + /*****************************/ /* Calculate the real timing */ - /*****************************/ + /*****************************/ *pul_RealHighTiming = - (ULONG) + (unsigned int) (ul_HighTimerValue / (250000.0 @@ -1133,7 +1133,7 @@ INT i_APCI1710_InitPWM(struct comedi_device * dev, if (b_ClockSelection != APCI1710_40MHZ) { ul_HighTimerValue = - (ULONG) + (unsigned int) ( (double) (ul_HighTimerValue) @@ -1143,19 +1143,19 @@ INT i_APCI1710_InitPWM(struct comedi_device * dev, break; - /******/ + /******/ /* mn */ - /******/ + /******/ case 4: - /******************/ + /******************/ /* Timer 0 factor */ - /******************/ + /******************/ ul_HighTimerValue = - (ULONG) + (unsigned int) ( (ul_HighTiming * @@ -1165,9 +1165,9 @@ INT i_APCI1710_InitPWM(struct comedi_device * dev, * b_ClockSelection)); - /*******************/ + /*******************/ /* Round the value */ - /*******************/ + /*******************/ if ((double)((double)(ul_HighTiming * 60.0) * (250000.0 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) { ul_HighTimerValue @@ -1177,13 +1177,13 @@ INT i_APCI1710_InitPWM(struct comedi_device * dev, 1; } - /*****************************/ + /*****************************/ /* Calculate the real timing */ - /*****************************/ + /*****************************/ *pul_RealHighTiming = - (ULONG) + (unsigned int) (ul_HighTimerValue / (250000.0 @@ -1227,7 +1227,7 @@ INT i_APCI1710_InitPWM(struct comedi_device * dev, if (b_ClockSelection != APCI1710_40MHZ) { ul_HighTimerValue = - (ULONG) + (unsigned int) ( (double) (ul_HighTimerValue) @@ -1239,9 +1239,9 @@ INT i_APCI1710_InitPWM(struct comedi_device * dev, } fpu_end(); - /****************************/ + /****************************/ /* Save the clock selection */ - /****************************/ + /****************************/ devpriv-> s_ModuleInfo @@ -1251,9 +1251,9 @@ INT i_APCI1710_InitPWM(struct comedi_device * dev, = b_ClockSelection; - /************************/ + /************************/ /* Save the timing unit */ - /************************/ + /************************/ devpriv-> s_ModuleInfo @@ -1265,9 +1265,9 @@ INT i_APCI1710_InitPWM(struct comedi_device * dev, = b_TimingUnit; - /****************************/ + /****************************/ /* Save the low base timing */ - /****************************/ + /****************************/ devpriv-> s_ModuleInfo @@ -1289,9 +1289,9 @@ INT i_APCI1710_InitPWM(struct comedi_device * dev, = *pul_RealLowTiming; - /****************************/ + /****************************/ /* Save the high base timing */ - /****************************/ + /****************************/ devpriv-> s_ModuleInfo @@ -1313,21 +1313,21 @@ INT i_APCI1710_InitPWM(struct comedi_device * dev, = *pul_RealHighTiming; - /************************/ + /************************/ /* Write the low timing */ - /************************/ + /************************/ outl(ul_LowTimerValue, devpriv->s_BoardInfos.ui_Address + 0 + (20 * b_PWM) + (64 * b_ModulNbr)); - /*************************/ + /*************************/ /* Write the high timing */ - /*************************/ + /*************************/ outl(ul_HighTimerValue, devpriv->s_BoardInfos.ui_Address + 4 + (20 * b_PWM) + (64 * b_ModulNbr)); - /***************************/ + /***************************/ /* Set the clock selection */ - /***************************/ + /***************************/ dw_Command = @@ -1354,15 +1354,15 @@ INT i_APCI1710_InitPWM(struct comedi_device * dev, 0x80; } - /***************************/ + /***************************/ /* Set the clock selection */ - /***************************/ + /***************************/ outl(dw_Command, devpriv->s_BoardInfos.ui_Address + 8 + (20 * b_PWM) + (64 * b_ModulNbr)); - /*************/ + /*************/ /* PWM init. */ - /*************/ + /*************/ devpriv-> s_ModuleInfo [b_ModulNbr]. @@ -1373,98 +1373,98 @@ INT i_APCI1710_InitPWM(struct comedi_device * dev, = 1; } else { - /***************************************************/ + /***************************************************/ /* You can not used the 40MHz clock selection with */ /* this board */ - /***************************************************/ + /***************************************************/ DPRINTK("You can not used the 40MHz clock selection with this board\n"); i_ReturnValue = -9; } } else { - /***************************************/ + /***************************************/ /* High base timing selection is wrong */ - /***************************************/ + /***************************************/ DPRINTK("High base timing selection is wrong\n"); i_ReturnValue = -8; } } else { - /**************************************/ + /**************************************/ /* Low base timing selection is wrong */ - /**************************************/ + /**************************************/ DPRINTK("Low base timing selection is wrong\n"); i_ReturnValue = -7; } - } // if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4)) + } /* if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4)) */ else { - /**********************************/ + /**********************************/ /* Timing unit selection is wrong */ - /**********************************/ + /**********************************/ DPRINTK("Timing unit selection is wrong\n"); i_ReturnValue = -6; - } // if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4)) - } // if ((b_ClockSelection == APCI1710_30MHZ) || (b_ClockSelection == APCI1710_33MHZ) || (b_ClockSelection == APCI1710_40MHZ)) + } /* if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4)) */ + } /* if ((b_ClockSelection == APCI1710_30MHZ) || (b_ClockSelection == APCI1710_33MHZ) || (b_ClockSelection == APCI1710_40MHZ)) */ else { - /*******************************/ + /*******************************/ /* The selected clock is wrong */ - /*******************************/ + /*******************************/ DPRINTK("The selected clock is wrong\n"); i_ReturnValue = -5; - } // if ((b_ClockSelection == APCI1710_30MHZ) || (b_ClockSelection == APCI1710_33MHZ) || (b_ClockSelection == APCI1710_40MHZ)) - } // if (b_PWM >= 0 && b_PWM <= 1) + } /* if ((b_ClockSelection == APCI1710_30MHZ) || (b_ClockSelection == APCI1710_33MHZ) || (b_ClockSelection == APCI1710_40MHZ)) */ + } /* if (b_PWM >= 0 && b_PWM <= 1) */ else { - /******************************/ + /******************************/ /* Tor PWM selection is wrong */ - /******************************/ + /******************************/ DPRINTK("Tor PWM selection is wrong\n"); i_ReturnValue = -4; - } // if (b_PWM >= 0 && b_PWM <= 1) + } /* if (b_PWM >= 0 && b_PWM <= 1) */ } else { - /**********************************/ + /**********************************/ /* The module is not a PWM module */ - /**********************************/ + /**********************************/ DPRINTK("The module is not a PWM module\n"); i_ReturnValue = -3; } } else { - /***********************/ + /***********************/ /* Module number error */ - /***********************/ + /***********************/ DPRINTK("Module number error\n"); i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_GetPWMInitialisation | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr, | -| BYTE_ b_PWM, | -| PBYTE_ pb_TimingUnit, | +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr, | +| unsigned char_ b_PWM, | +| unsigned char *_ pb_TimingUnit, | | PULONG_ pul_LowTiming, | | PULONG_ pul_HighTiming, | -| PBYTE_ pb_StartLevel, | -| PBYTE_ pb_StopMode, | -| PBYTE_ pb_StopLevel, | -| PBYTE_ pb_ExternGate, | -| PBYTE_ pb_InterruptEnable, | -| PBYTE_ pb_Enable) | +| unsigned char *_ pb_StartLevel, | +| unsigned char *_ pb_StopMode, | +| unsigned char *_ pb_StopLevel, | +| unsigned char *_ pb_ExternGate, | +| unsigned char *_ pb_InterruptEnable, | +| unsigned char *_ pb_Enable) | +----------------------------------------------------------------------------+ | Task : Return the PWM (b_PWM) initialisation from selected | | module (b_ModulNbr). You must calling the | | "i_APCI1710_InitPWM" function be for you call this | | function. | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | -| BYTE_ b_ModulNbr : Selected module number (0 to 3) | -| BYTE_ b_PWM : Selected PWM (0 or 1) | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | +| unsigned char_ b_ModulNbr : Selected module number (0 to 3) | +| unsigned char_ b_PWM : Selected PWM (0 or 1) | +----------------------------------------------------------------------------+ -| Output Parameters : PBYTE_ pb_TimingUnit : Base timing Unit (0 to 4) | +| Output Parameters : unsigned char *_ pb_TimingUnit : Base timing Unit (0 to 4) | | 0 : ns | | 1 : æs | | 2 : ms | @@ -1472,13 +1472,13 @@ INT i_APCI1710_InitPWM(struct comedi_device * dev, | 4 : mn | | PULONG_ pul_LowTiming : Low base timing value. | | PULONG_ pul_HighTiming : High base timing value. | -| PBYTE_ pb_StartLevel : Start period level | +| unsigned char *_ pb_StartLevel : Start period level | | selection | | 0 : The period start | | with a low level | | 1 : The period start | | with a high level| -| PBYTE_ pb_StopMode : Stop mode selection | +| unsigned char *_ pb_StopMode : Stop mode selection | | 0 : The PWM is stopped | | directly after the | | "i_APCI1710_DisablePWM"| @@ -1489,7 +1489,7 @@ INT i_APCI1710_InitPWM(struct comedi_device * dev, | function the PWM is | | stopped at the end | | from last period cycle| -| PBYTE_ pb_StopLevel : Stop PWM level selection | +| unsigned char *_ pb_StopLevel : Stop PWM level selection | | 0 : The output signal | | keep the level after| | the | @@ -1504,13 +1504,13 @@ INT i_APCI1710_InitPWM(struct comedi_device * dev, | the | | "i_APCI1710_DisablePWM"| | function | -| PBYTE_ pb_ExternGate : Extern gate action | +| unsigned char *_ pb_ExternGate : Extern gate action | | selection | | 0 : Extern gate signal | | not used. | | 1 : Extern gate signal | | used. | -| PBYTE_ pb_InterruptEnable : Enable or disable the PWM | +| unsigned char *_ pb_InterruptEnable : Enable or disable the PWM | | interrupt. | | - APCI1710_ENABLE : | | Enable the PWM interrupt| @@ -1519,7 +1519,7 @@ INT i_APCI1710_InitPWM(struct comedi_device * dev, | - APCI1710_DISABLE : | | Disable the PWM | | interrupt | -| PBYTE_ pb_Enable : Indicate if the PWM is | +| unsigned char *_ pb_Enable : Indicate if the PWM is | | enabled or no | | 0 : PWM not enabled | | 1 : PWM enabled | @@ -1534,138 +1534,138 @@ INT i_APCI1710_InitPWM(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -INT i_APCI1710_GetPWMInitialisation(struct comedi_device * dev, - BYTE b_ModulNbr, - BYTE b_PWM, - PBYTE pb_TimingUnit, - PULONG pul_LowTiming, - PULONG pul_HighTiming, - PBYTE pb_StartLevel, - PBYTE pb_StopMode, - PBYTE pb_StopLevel, - PBYTE pb_ExternGate, PBYTE pb_InterruptEnable, PBYTE pb_Enable) +int i_APCI1710_GetPWMInitialisation(struct comedi_device *dev, + unsigned char b_ModulNbr, + unsigned char b_PWM, + unsigned char *pb_TimingUnit, + unsigned int *pul_LowTiming, + unsigned int *pul_HighTiming, + unsigned char *pb_StartLevel, + unsigned char *pb_StopMode, + unsigned char *pb_StopLevel, + unsigned char *pb_ExternGate, unsigned char *pb_InterruptEnable, unsigned char *pb_Enable) { - INT i_ReturnValue = 0; - DWORD dw_Status; - DWORD dw_Command; + int i_ReturnValue = 0; + unsigned int dw_Status; + unsigned int dw_Command; /**************************/ /* Test the module number */ /**************************/ if (b_ModulNbr < 4) { - /***************/ + /***************/ /* Test if PWM */ - /***************/ + /***************/ if ((devpriv->s_BoardInfos. dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF0000UL) == APCI1710_PWM) { - /**************************/ + /**************************/ /* Test the PWM selection */ - /**************************/ + /**************************/ if (b_PWM <= 1) { - /***************************/ + /***************************/ /* Test if PWM initialised */ - /***************************/ + /***************************/ dw_Status = inl(devpriv->s_BoardInfos. ui_Address + 12 + (20 * b_PWM) + (64 * b_ModulNbr)); if (dw_Status & 0x10) { - /***********************/ + /***********************/ /* Read the low timing */ - /***********************/ + /***********************/ *pul_LowTiming = inl(devpriv->s_BoardInfos. ui_Address + 0 + (20 * b_PWM) + (64 * b_ModulNbr)); - /************************/ + /************************/ /* Read the high timing */ - /************************/ + /************************/ *pul_HighTiming = inl(devpriv->s_BoardInfos. ui_Address + 4 + (20 * b_PWM) + (64 * b_ModulNbr)); - /********************/ + /********************/ /* Read the command */ - /********************/ + /********************/ dw_Command = inl(devpriv->s_BoardInfos. ui_Address + 8 + (20 * b_PWM) + (64 * b_ModulNbr)); *pb_StartLevel = - (BYTE) ((dw_Command >> 5) & 1); + (unsigned char) ((dw_Command >> 5) & 1); *pb_StopMode = - (BYTE) ((dw_Command >> 0) & 1); + (unsigned char) ((dw_Command >> 0) & 1); *pb_StopLevel = - (BYTE) ((dw_Command >> 1) & 1); + (unsigned char) ((dw_Command >> 1) & 1); *pb_ExternGate = - (BYTE) ((dw_Command >> 4) & 1); + (unsigned char) ((dw_Command >> 4) & 1); *pb_InterruptEnable = - (BYTE) ((dw_Command >> 3) & 1); + (unsigned char) ((dw_Command >> 3) & 1); if (*pb_StopLevel) { *pb_StopLevel = *pb_StopLevel + - (BYTE) ((dw_Command >> + (unsigned char) ((dw_Command >> 2) & 1); } - /********************/ + /********************/ /* Read the command */ - /********************/ + /********************/ dw_Command = inl(devpriv->s_BoardInfos. ui_Address + 8 + (20 * b_PWM) + (64 * b_ModulNbr)); *pb_Enable = - (BYTE) ((dw_Command >> 0) & 1); + (unsigned char) ((dw_Command >> 0) & 1); *pb_TimingUnit = devpriv-> s_ModuleInfo[b_ModulNbr]. s_PWMModuleInfo. s_PWMInfo[b_PWM].b_TimingUnit; - } // if (dw_Status & 0x10) + } /* if (dw_Status & 0x10) */ else { - /***********************/ + /***********************/ /* PWM not initialised */ - /***********************/ + /***********************/ DPRINTK("PWM not initialised\n"); i_ReturnValue = -5; - } // if (dw_Status & 0x10) - } // if (b_PWM >= 0 && b_PWM <= 1) + } /* if (dw_Status & 0x10) */ + } /* if (b_PWM >= 0 && b_PWM <= 1) */ else { - /******************************/ + /******************************/ /* Tor PWM selection is wrong */ - /******************************/ + /******************************/ DPRINTK("Tor PWM selection is wrong\n"); i_ReturnValue = -4; - } // if (b_PWM >= 0 && b_PWM <= 1) + } /* if (b_PWM >= 0 && b_PWM <= 1) */ } else { - /**********************************/ + /**********************************/ /* The module is not a PWM module */ - /**********************************/ + /**********************************/ DPRINTK("The module is not a PWM module\n"); i_ReturnValue = -3; } } else { - /***********************/ + /***********************/ /* Module number error */ - /***********************/ + /***********************/ DPRINTK("Module number error\n"); i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* @@ -1683,33 +1683,33 @@ struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) +----------------------------------------------------------------------------+ */ -INT i_APCI1710_InsnWritePWM(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI1710_InsnWritePWM(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - BYTE b_WriteType; - INT i_ReturnValue = 0; + unsigned char b_WriteType; + int i_ReturnValue = 0; b_WriteType = CR_CHAN(insn->chanspec); switch (b_WriteType) { case APCI1710_PWM_ENABLE: i_ReturnValue = i_APCI1710_EnablePWM(dev, - (BYTE) CR_AREF(insn->chanspec), - (BYTE) data[0], - (BYTE) data[1], - (BYTE) data[2], - (BYTE) data[3], (BYTE) data[4], (BYTE) data[5]); + (unsigned char) CR_AREF(insn->chanspec), + (unsigned char) data[0], + (unsigned char) data[1], + (unsigned char) data[2], + (unsigned char) data[3], (unsigned char) data[4], (unsigned char) data[5]); break; case APCI1710_PWM_DISABLE: i_ReturnValue = i_APCI1710_DisablePWM(dev, - (BYTE) CR_AREF(insn->chanspec), (BYTE) data[0]); + (unsigned char) CR_AREF(insn->chanspec), (unsigned char) data[0]); break; case APCI1710_PWM_NEWTIMING: i_ReturnValue = i_APCI1710_SetNewPWMTiming(dev, - (BYTE) CR_AREF(insn->chanspec), - (BYTE) data[0], - (BYTE) data[1], (ULONG) data[2], (ULONG) data[3]); + (unsigned char) CR_AREF(insn->chanspec), + (unsigned char) data[0], + (unsigned char) data[1], (unsigned int) data[2], (unsigned int) data[3]); break; default: @@ -1718,20 +1718,20 @@ INT i_APCI1710_InsnWritePWM(struct comedi_device * dev, struct comedi_subdevice if (i_ReturnValue >= 0) i_ReturnValue = insn->n; - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_EnablePWM | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr, | -| BYTE_ b_PWM, | -| BYTE_ b_StartLevel, | -| BYTE_ b_StopMode, | -| BYTE_ b_StopLevel, | -| BYTE_ b_ExternGate, | -| BYTE_ b_InterruptEnable) | +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr, | +| unsigned char_ b_PWM, | +| unsigned char_ b_StartLevel, | +| unsigned char_ b_StopMode, | +| unsigned char_ b_StopLevel, | +| unsigned char_ b_ExternGate, | +| unsigned char_ b_InterruptEnable) | +----------------------------------------------------------------------------+ | Task : Enable the selected PWM (b_PWM) from selected module | | (b_ModulNbr). You must calling the "i_APCI1710_InitPWM"| @@ -1741,16 +1741,16 @@ INT i_APCI1710_InsnWritePWM(struct comedi_device * dev, struct comedi_subdevice | See function "i_APCI1710_SetBoardIntRoutineX" and the | | Interrupt mask description chapter. | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | -| BYTE_ b_ModulNbr : Selected module number | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | +| unsigned char_ b_ModulNbr : Selected module number | | (0 to 3) | -| BYTE_ b_PWM : Selected PWM (0 or 1) | -| BYTE_ b_StartLevel : Start period level selection | +| unsigned char_ b_PWM : Selected PWM (0 or 1) | +| unsigned char_ b_StartLevel : Start period level selection | | 0 : The period start with a | | low level | | 1 : The period start with a | | high level | -| BYTE_ b_StopMode : Stop mode selection | +| unsigned char_ b_StopMode : Stop mode selection | | 0 : The PWM is stopped | | directly after the | | "i_APCI1710_DisablePWM" | @@ -1761,7 +1761,7 @@ INT i_APCI1710_InsnWritePWM(struct comedi_device * dev, struct comedi_subdevice | function the PWM is | | stopped at the end from| | last period cycle. | -| BYTE_ b_StopLevel : Stop PWM level selection | +| unsigned char_ b_StopLevel : Stop PWM level selection | | 0 : The output signal keep | | the level after the | | "i_APCI1710_DisablePWM" | @@ -1774,11 +1774,11 @@ INT i_APCI1710_InsnWritePWM(struct comedi_device * dev, struct comedi_subdevice | to high after the | | "i_APCI1710_DisablePWM" | | function | -| BYTE_ b_ExternGate : Extern gate action selection | +| unsigned char_ b_ExternGate : Extern gate action selection | | 0 : Extern gate signal not | | used. | | 1 : Extern gate signal used.| -| BYTE_ b_InterruptEnable : Enable or disable the PWM | +| unsigned char_ b_InterruptEnable : Enable or disable the PWM | | interrupt. | | - APCI1710_ENABLE : | | Enable the PWM interrupt | @@ -1806,77 +1806,77 @@ INT i_APCI1710_InsnWritePWM(struct comedi_device * dev, struct comedi_subdevice +----------------------------------------------------------------------------+ */ -INT i_APCI1710_EnablePWM(struct comedi_device * dev, - BYTE b_ModulNbr, - BYTE b_PWM, - BYTE b_StartLevel, - BYTE b_StopMode, - BYTE b_StopLevel, BYTE b_ExternGate, BYTE b_InterruptEnable) +int i_APCI1710_EnablePWM(struct comedi_device *dev, + unsigned char b_ModulNbr, + unsigned char b_PWM, + unsigned char b_StartLevel, + unsigned char b_StopMode, + unsigned char b_StopLevel, unsigned char b_ExternGate, unsigned char b_InterruptEnable) { - INT i_ReturnValue = 0; - DWORD dw_Status; - DWORD dw_Command; + int i_ReturnValue = 0; + unsigned int dw_Status; + unsigned int dw_Command; - devpriv->tsk_Current = current; // Save the current process task structure + devpriv->tsk_Current = current; /* Save the current process task structure */ /**************************/ /* Test the module number */ /**************************/ if (b_ModulNbr < 4) { - /***************/ + /***************/ /* Test if PWM */ - /***************/ + /***************/ if ((devpriv->s_BoardInfos. dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF0000UL) == APCI1710_PWM) { - /**************************/ + /**************************/ /* Test the PWM selection */ - /**************************/ + /**************************/ if (b_PWM <= 1) { - /***************************/ + /***************************/ /* Test if PWM initialised */ - /***************************/ + /***************************/ dw_Status = inl(devpriv->s_BoardInfos. ui_Address + 12 + (20 * b_PWM) + (64 * b_ModulNbr)); if (dw_Status & 0x10) { - /**********************************/ + /**********************************/ /* Test the start level selection */ - /**********************************/ + /**********************************/ if (b_StartLevel <= 1) { - /**********************/ + /**********************/ /* Test the stop mode */ - /**********************/ + /**********************/ if (b_StopMode <= 1) { - /***********************/ + /***********************/ /* Test the stop level */ - /***********************/ + /***********************/ if (b_StopLevel <= 2) { - /*****************************/ + /*****************************/ /* Test the extern gate mode */ - /*****************************/ + /*****************************/ if (b_ExternGate <= 1) { - /*****************************/ + /*****************************/ /* Test the interrupt action */ - /*****************************/ + /*****************************/ if (b_InterruptEnable == APCI1710_ENABLE || b_InterruptEnable == APCI1710_DISABLE) { - /******************************************/ + /******************************************/ /* Test if interrupt function initialised */ - /******************************************/ + /******************************************/ - /********************/ + /********************/ /* Read the command */ - /********************/ + /********************/ dw_Command = @@ -1895,9 +1895,9 @@ INT i_APCI1710_EnablePWM(struct comedi_device * dev, & 0x80; - /********************/ + /********************/ /* Make the command */ - /********************/ + /********************/ dw_Command = @@ -1943,100 +1943,100 @@ INT i_APCI1710_EnablePWM(struct comedi_device * dev, = b_InterruptEnable; - /*******************/ + /*******************/ /* Set the command */ - /*******************/ + /*******************/ outl(dw_Command, devpriv->s_BoardInfos.ui_Address + 8 + (20 * b_PWM) + (64 * b_ModulNbr)); - /******************/ + /******************/ /* Enable the PWM */ - /******************/ + /******************/ outl(1, devpriv->s_BoardInfos.ui_Address + 12 + (20 * b_PWM) + (64 * b_ModulNbr)); - } // if (b_InterruptEnable == APCI1710_ENABLE || b_InterruptEnable == APCI1710_DISABLE) + } /* if (b_InterruptEnable == APCI1710_ENABLE || b_InterruptEnable == APCI1710_DISABLE) */ else { - /********************************/ + /********************************/ /* Interrupt parameter is wrong */ - /********************************/ + /********************************/ DPRINTK("Interrupt parameter is wrong\n"); i_ReturnValue = -10; - } // if (b_InterruptEnable == APCI1710_ENABLE || b_InterruptEnable == APCI1710_DISABLE) - } // if (b_ExternGate >= 0 && b_ExternGate <= 1) + } /* if (b_InterruptEnable == APCI1710_ENABLE || b_InterruptEnable == APCI1710_DISABLE) */ + } /* if (b_ExternGate >= 0 && b_ExternGate <= 1) */ else { - /*****************************************/ + /*****************************************/ /* Extern gate signal selection is wrong */ - /*****************************************/ + /*****************************************/ DPRINTK("Extern gate signal selection is wrong\n"); i_ReturnValue = -9; - } // if (b_ExternGate >= 0 && b_ExternGate <= 1) - } // if (b_StopLevel >= 0 && b_StopLevel <= 2) + } /* if (b_ExternGate >= 0 && b_ExternGate <= 1) */ + } /* if (b_StopLevel >= 0 && b_StopLevel <= 2) */ else { - /*************************************/ + /*************************************/ /* PWM stop level selection is wrong */ - /*************************************/ + /*************************************/ DPRINTK("PWM stop level selection is wrong\n"); i_ReturnValue = -8; - } // if (b_StopLevel >= 0 && b_StopLevel <= 2) - } // if (b_StopMode >= 0 && b_StopMode <= 1) + } /* if (b_StopLevel >= 0 && b_StopLevel <= 2) */ + } /* if (b_StopMode >= 0 && b_StopMode <= 1) */ else { - /************************************/ + /************************************/ /* PWM stop mode selection is wrong */ - /************************************/ + /************************************/ DPRINTK("PWM stop mode selection is wrong\n"); i_ReturnValue = -7; - } // if (b_StopMode >= 0 && b_StopMode <= 1) - } // if (b_StartLevel >= 0 && b_StartLevel <= 1) + } /* if (b_StopMode >= 0 && b_StopMode <= 1) */ + } /* if (b_StartLevel >= 0 && b_StartLevel <= 1) */ else { - /**************************************/ + /**************************************/ /* PWM start level selection is wrong */ - /**************************************/ + /**************************************/ DPRINTK("PWM start level selection is wrong\n"); i_ReturnValue = -6; - } // if (b_StartLevel >= 0 && b_StartLevel <= 1) - } // if (dw_Status & 0x10) + } /* if (b_StartLevel >= 0 && b_StartLevel <= 1) */ + } /* if (dw_Status & 0x10) */ else { - /***********************/ + /***********************/ /* PWM not initialised */ - /***********************/ + /***********************/ DPRINTK("PWM not initialised\n"); i_ReturnValue = -5; - } // if (dw_Status & 0x10) - } // if (b_PWM >= 0 && b_PWM <= 1) + } /* if (dw_Status & 0x10) */ + } /* if (b_PWM >= 0 && b_PWM <= 1) */ else { - /******************************/ + /******************************/ /* Tor PWM selection is wrong */ - /******************************/ + /******************************/ DPRINTK("Tor PWM selection is wrong\n"); i_ReturnValue = -4; - } // if (b_PWM >= 0 && b_PWM <= 1) + } /* if (b_PWM >= 0 && b_PWM <= 1) */ } else { - /**********************************/ + /**********************************/ /* The module is not a PWM module */ - /**********************************/ + /**********************************/ DPRINTK("The module is not a PWM module\n"); i_ReturnValue = -3; } } else { - /***********************/ + /***********************/ /* Module number error */ - /***********************/ + /***********************/ DPRINTK("Module number error\n"); i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_DisablePWM (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr, | -| BYTE_ b_PWM) | +| Function Name : _INT_ i_APCI1710_DisablePWM (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr, | +| unsigned char_ b_PWM) | +----------------------------------------------------------------------------+ | Task : Disable the selected PWM (b_PWM) from selected module | | (b_ModulNbr). The output signal level depend of the | @@ -2045,8 +2045,8 @@ INT i_APCI1710_EnablePWM(struct comedi_device * dev, | parameters from this function. | +----------------------------------------------------------------------------+ | Input Parameters :BYTE_ b_BoardHandle : Handle of board APCI-1710 | -| BYTE_ b_ModulNbr : Selected module number (0 to 3) | -| BYTE_ b_PWM : Selected PWM (0 or 1) | +| unsigned char_ b_ModulNbr : Selected module number (0 to 3) | +| unsigned char_ b_PWM : Selected PWM (0 or 1) | +----------------------------------------------------------------------------+ | Output Parameters : - | +----------------------------------------------------------------------------+ @@ -2062,99 +2062,99 @@ INT i_APCI1710_EnablePWM(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -INT i_APCI1710_DisablePWM(struct comedi_device * dev, BYTE b_ModulNbr, BYTE b_PWM) +int i_APCI1710_DisablePWM(struct comedi_device *dev, unsigned char b_ModulNbr, unsigned char b_PWM) { - INT i_ReturnValue = 0; - DWORD dw_Status; + int i_ReturnValue = 0; + unsigned int dw_Status; /**************************/ /* Test the module number */ /**************************/ if (b_ModulNbr < 4) { - /***************/ + /***************/ /* Test if PWM */ - /***************/ + /***************/ if ((devpriv->s_BoardInfos. dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF0000UL) == APCI1710_PWM) { - /**************************/ + /**************************/ /* Test the PWM selection */ - /**************************/ + /**************************/ if (b_PWM <= 1) { - /***************************/ + /***************************/ /* Test if PWM initialised */ - /***************************/ + /***************************/ dw_Status = inl(devpriv->s_BoardInfos. ui_Address + 12 + (20 * b_PWM) + (64 * b_ModulNbr)); if (dw_Status & 0x10) { - /***********************/ + /***********************/ /* Test if PWM enabled */ - /***********************/ + /***********************/ if (dw_Status & 0x1) { - /*******************/ + /*******************/ /* Disable the PWM */ - /*******************/ + /*******************/ outl(0, devpriv->s_BoardInfos. ui_Address + 12 + (20 * b_PWM) + (64 * b_ModulNbr)); - } // if (dw_Status & 0x1) + } /* if (dw_Status & 0x1) */ else { - /*******************/ + /*******************/ /* PWM not enabled */ - /*******************/ + /*******************/ DPRINTK("PWM not enabled\n"); i_ReturnValue = -6; - } // if (dw_Status & 0x1) - } // if (dw_Status & 0x10) + } /* if (dw_Status & 0x1) */ + } /* if (dw_Status & 0x10) */ else { - /***********************/ + /***********************/ /* PWM not initialised */ - /***********************/ + /***********************/ DPRINTK(" PWM not initialised\n"); i_ReturnValue = -5; - } // if (dw_Status & 0x10) - } // if (b_PWM >= 0 && b_PWM <= 1) + } /* if (dw_Status & 0x10) */ + } /* if (b_PWM >= 0 && b_PWM <= 1) */ else { - /******************************/ + /******************************/ /* Tor PWM selection is wrong */ - /******************************/ + /******************************/ DPRINTK("Tor PWM selection is wrong\n"); i_ReturnValue = -4; - } // if (b_PWM >= 0 && b_PWM <= 1) + } /* if (b_PWM >= 0 && b_PWM <= 1) */ } else { - /**********************************/ + /**********************************/ /* The module is not a PWM module */ - /**********************************/ + /**********************************/ DPRINTK("The module is not a PWM module\n"); i_ReturnValue = -3; } } else { - /***********************/ + /***********************/ /* Module number error */ - /***********************/ + /***********************/ DPRINTK("Module number error\n"); i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_SetNewPWMTiming | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr, | -| BYTE_ b_PWM, | -| BYTE_ b_ClockSelection, | -| BYTE_ b_TimingUnit, | +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr, | +| unsigned char_ b_PWM, | +| unsigned char_ b_ClockSelection, | +| unsigned char_ b_TimingUnit, | | ULONG_ ul_LowTiming, | | ULONG_ ul_HighTiming) | +----------------------------------------------------------------------------+ @@ -2162,11 +2162,11 @@ INT i_APCI1710_DisablePWM(struct comedi_device * dev, BYTE b_ModulNbr, BYTE b_PW | ul_TimingUnit determine the low/high timing base for | | the period. | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | -| BYTE_ b_ModulNbr : Module number to configure| +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | +| unsigned char_ b_ModulNbr : Module number to configure| | (0 to 3) | -| BYTE_ b_PWM : Selected PWM (0 or 1). | -| BYTE_ b_TimingUnit : Base timing Unit (0 to 4) | +| unsigned char_ b_PWM : Selected PWM (0 or 1). | +| unsigned char_ b_TimingUnit : Base timing Unit (0 to 4) | | 0 : ns | | 1 : æs | | 2 : ms | @@ -2189,18 +2189,18 @@ INT i_APCI1710_DisablePWM(struct comedi_device * dev, BYTE b_ModulNbr, BYTE b_PW +----------------------------------------------------------------------------+ */ -INT i_APCI1710_SetNewPWMTiming(struct comedi_device * dev, - BYTE b_ModulNbr, - BYTE b_PWM, BYTE b_TimingUnit, ULONG ul_LowTiming, ULONG ul_HighTiming) +int i_APCI1710_SetNewPWMTiming(struct comedi_device *dev, + unsigned char b_ModulNbr, + unsigned char b_PWM, unsigned char b_TimingUnit, unsigned int ul_LowTiming, unsigned int ul_HighTiming) { - BYTE b_ClockSelection; - INT i_ReturnValue = 0; - ULONG ul_LowTimerValue = 0; - ULONG ul_HighTimerValue = 0; - ULONG ul_RealLowTiming = 0; - ULONG ul_RealHighTiming = 0; - DWORD dw_Status; - DWORD dw_Command; + unsigned char b_ClockSelection; + int i_ReturnValue = 0; + unsigned int ul_LowTimerValue = 0; + unsigned int ul_HighTimerValue = 0; + unsigned int ul_RealLowTiming = 0; + unsigned int ul_RealHighTiming = 0; + unsigned int dw_Status; + unsigned int dw_Command; double d_RealLowTiming = 0; double d_RealHighTiming = 0; @@ -2209,21 +2209,21 @@ INT i_APCI1710_SetNewPWMTiming(struct comedi_device * dev, /**************************/ if (b_ModulNbr < 4) { - /***************/ + /***************/ /* Test if PWM */ - /***************/ + /***************/ if ((devpriv->s_BoardInfos. dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF0000UL) == APCI1710_PWM) { - /**************************/ + /**************************/ /* Test the PWM selection */ - /**************************/ + /**************************/ if (b_PWM <= 1) { - /***************************/ + /***************************/ /* Test if PWM initialised */ - /***************************/ + /***************************/ dw_Status = inl(devpriv->s_BoardInfos. ui_Address + 12 + (20 * b_PWM) + @@ -2235,14 +2235,14 @@ INT i_APCI1710_SetNewPWMTiming(struct comedi_device * dev, s_PWMModuleInfo. b_ClockSelection; - /************************/ + /************************/ /* Test the timing unit */ - /************************/ + /************************/ if (b_TimingUnit <= 4) { - /*********************************/ + /*********************************/ /* Test the low timing selection */ - /*********************************/ + /*********************************/ if (((b_ClockSelection == APCI1710_30MHZ) @@ -2377,37 +2377,37 @@ INT i_APCI1710_SetNewPWMTiming(struct comedi_device * dev, && (ul_LowTiming <= 7UL))) { - /**********************************/ + /**********************************/ /* Test the High timing selection */ - /**********************************/ + /**********************************/ if (((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 0) && (ul_HighTiming >= 266) && (ul_HighTiming <= 0xFFFFFFFFUL)) || ((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 1) && (ul_HighTiming >= 1) && (ul_HighTiming <= 571230650UL)) || ((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 2) && (ul_HighTiming >= 1) && (ul_HighTiming <= 571230UL)) || ((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 3) && (ul_HighTiming >= 1) && (ul_HighTiming <= 571UL)) || ((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 4) && (ul_HighTiming >= 1) && (ul_HighTiming <= 9UL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 0) && (ul_HighTiming >= 242) && (ul_HighTiming <= 0xFFFFFFFFUL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 1) && (ul_HighTiming >= 1) && (ul_HighTiming <= 519691043UL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 2) && (ul_HighTiming >= 1) && (ul_HighTiming <= 519691UL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 3) && (ul_HighTiming >= 1) && (ul_HighTiming <= 520UL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 4) && (ul_HighTiming >= 1) && (ul_HighTiming <= 8UL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 0) && (ul_HighTiming >= 200) && (ul_HighTiming <= 0xFFFFFFFFUL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 1) && (ul_HighTiming >= 1) && (ul_HighTiming <= 429496729UL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 2) && (ul_HighTiming >= 1) && (ul_HighTiming <= 429496UL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 3) && (ul_HighTiming >= 1) && (ul_HighTiming <= 429UL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 4) && (ul_HighTiming >= 1) && (ul_HighTiming <= 7UL))) { - /************************************/ + /************************************/ /* Calculate the low division fator */ - /************************************/ + /************************************/ fpu_begin(); switch (b_TimingUnit) { - /******/ + /******/ /* ns */ - /******/ + /******/ case 0: - /******************/ + /******************/ /* Timer 0 factor */ - /******************/ + /******************/ ul_LowTimerValue = - (ULONG) + (unsigned int) (ul_LowTiming * (0.00025 * b_ClockSelection)); - /*******************/ + /*******************/ /* Round the value */ - /*******************/ + /*******************/ if ((double)((double)ul_LowTiming * (0.00025 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) { ul_LowTimerValue @@ -2417,13 +2417,13 @@ INT i_APCI1710_SetNewPWMTiming(struct comedi_device * dev, 1; } - /*****************************/ + /*****************************/ /* Calculate the real timing */ - /*****************************/ + /*****************************/ ul_RealLowTiming = - (ULONG) + (unsigned int) (ul_LowTimerValue / (0.00025 * (double)b_ClockSelection)); @@ -2459,7 +2459,7 @@ INT i_APCI1710_SetNewPWMTiming(struct comedi_device * dev, if (b_ClockSelection != APCI1710_40MHZ) { ul_LowTimerValue = - (ULONG) + (unsigned int) ( (double) (ul_LowTimerValue) @@ -2469,26 +2469,26 @@ INT i_APCI1710_SetNewPWMTiming(struct comedi_device * dev, break; - /******/ + /******/ /* æs */ - /******/ + /******/ case 1: - /******************/ + /******************/ /* Timer 0 factor */ - /******************/ + /******************/ ul_LowTimerValue = - (ULONG) + (unsigned int) (ul_LowTiming * (0.25 * b_ClockSelection)); - /*******************/ + /*******************/ /* Round the value */ - /*******************/ + /*******************/ if ((double)((double)ul_LowTiming * (0.25 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) { ul_LowTimerValue @@ -2498,13 +2498,13 @@ INT i_APCI1710_SetNewPWMTiming(struct comedi_device * dev, 1; } - /*****************************/ + /*****************************/ /* Calculate the real timing */ - /*****************************/ + /*****************************/ ul_RealLowTiming = - (ULONG) + (unsigned int) (ul_LowTimerValue / (0.25 * (double)b_ClockSelection)); @@ -2542,7 +2542,7 @@ INT i_APCI1710_SetNewPWMTiming(struct comedi_device * dev, if (b_ClockSelection != APCI1710_40MHZ) { ul_LowTimerValue = - (ULONG) + (unsigned int) ( (double) (ul_LowTimerValue) @@ -2552,15 +2552,15 @@ INT i_APCI1710_SetNewPWMTiming(struct comedi_device * dev, break; - /******/ + /******/ /* ms */ - /******/ + /******/ case 2: - /******************/ + /******************/ /* Timer 0 factor */ - /******************/ + /******************/ ul_LowTimerValue = @@ -2570,9 +2570,9 @@ INT i_APCI1710_SetNewPWMTiming(struct comedi_device * dev, * b_ClockSelection); - /*******************/ + /*******************/ /* Round the value */ - /*******************/ + /*******************/ if ((double)((double)ul_LowTiming * (250.0 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) { ul_LowTimerValue @@ -2582,13 +2582,13 @@ INT i_APCI1710_SetNewPWMTiming(struct comedi_device * dev, 1; } - /*****************************/ + /*****************************/ /* Calculate the real timing */ - /*****************************/ + /*****************************/ ul_RealLowTiming = - (ULONG) + (unsigned int) (ul_LowTimerValue / (250.0 * (double)b_ClockSelection)); @@ -2624,7 +2624,7 @@ INT i_APCI1710_SetNewPWMTiming(struct comedi_device * dev, if (b_ClockSelection != APCI1710_40MHZ) { ul_LowTimerValue = - (ULONG) + (unsigned int) ( (double) (ul_LowTimerValue) @@ -2634,28 +2634,28 @@ INT i_APCI1710_SetNewPWMTiming(struct comedi_device * dev, break; - /*****/ + /*****/ /* s */ - /*****/ + /*****/ case 3: - /******************/ + /******************/ /* Timer 0 factor */ - /******************/ + /******************/ ul_LowTimerValue = - (ULONG) + (unsigned int) (ul_LowTiming * (250000.0 * b_ClockSelection)); - /*******************/ + /*******************/ /* Round the value */ - /*******************/ + /*******************/ if ((double)((double)ul_LowTiming * (250000.0 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) { ul_LowTimerValue @@ -2665,13 +2665,13 @@ INT i_APCI1710_SetNewPWMTiming(struct comedi_device * dev, 1; } - /*****************************/ + /*****************************/ /* Calculate the real timing */ - /*****************************/ + /*****************************/ ul_RealLowTiming = - (ULONG) + (unsigned int) (ul_LowTimerValue / (250000.0 @@ -2710,7 +2710,7 @@ INT i_APCI1710_SetNewPWMTiming(struct comedi_device * dev, if (b_ClockSelection != APCI1710_40MHZ) { ul_LowTimerValue = - (ULONG) + (unsigned int) ( (double) (ul_LowTimerValue) @@ -2720,19 +2720,19 @@ INT i_APCI1710_SetNewPWMTiming(struct comedi_device * dev, break; - /******/ + /******/ /* mn */ - /******/ + /******/ case 4: - /******************/ + /******************/ /* Timer 0 factor */ - /******************/ + /******************/ ul_LowTimerValue = - (ULONG) + (unsigned int) ( (ul_LowTiming * @@ -2742,9 +2742,9 @@ INT i_APCI1710_SetNewPWMTiming(struct comedi_device * dev, * b_ClockSelection)); - /*******************/ + /*******************/ /* Round the value */ - /*******************/ + /*******************/ if ((double)((double)(ul_LowTiming * 60.0) * (250000.0 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) { ul_LowTimerValue @@ -2754,13 +2754,13 @@ INT i_APCI1710_SetNewPWMTiming(struct comedi_device * dev, 1; } - /*****************************/ + /*****************************/ /* Calculate the real timing */ - /*****************************/ + /*****************************/ ul_RealLowTiming = - (ULONG) + (unsigned int) (ul_LowTimerValue / (250000.0 @@ -2804,7 +2804,7 @@ INT i_APCI1710_SetNewPWMTiming(struct comedi_device * dev, if (b_ClockSelection != APCI1710_40MHZ) { ul_LowTimerValue = - (ULONG) + (unsigned int) ( (double) (ul_LowTimerValue) @@ -2815,31 +2815,31 @@ INT i_APCI1710_SetNewPWMTiming(struct comedi_device * dev, break; } - /*************************************/ + /*************************************/ /* Calculate the high division fator */ - /*************************************/ + /*************************************/ switch (b_TimingUnit) { - /******/ + /******/ /* ns */ - /******/ + /******/ case 0: - /******************/ + /******************/ /* Timer 0 factor */ - /******************/ + /******************/ ul_HighTimerValue = - (ULONG) + (unsigned int) (ul_HighTiming * (0.00025 * b_ClockSelection)); - /*******************/ + /*******************/ /* Round the value */ - /*******************/ + /*******************/ if ((double)((double)ul_HighTiming * (0.00025 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) { ul_HighTimerValue @@ -2849,13 +2849,13 @@ INT i_APCI1710_SetNewPWMTiming(struct comedi_device * dev, 1; } - /*****************************/ + /*****************************/ /* Calculate the real timing */ - /*****************************/ + /*****************************/ ul_RealHighTiming = - (ULONG) + (unsigned int) (ul_HighTimerValue / (0.00025 * (double)b_ClockSelection)); @@ -2891,7 +2891,7 @@ INT i_APCI1710_SetNewPWMTiming(struct comedi_device * dev, if (b_ClockSelection != APCI1710_40MHZ) { ul_HighTimerValue = - (ULONG) + (unsigned int) ( (double) (ul_HighTimerValue) @@ -2901,26 +2901,26 @@ INT i_APCI1710_SetNewPWMTiming(struct comedi_device * dev, break; - /******/ + /******/ /* æs */ - /******/ + /******/ case 1: - /******************/ + /******************/ /* Timer 0 factor */ - /******************/ + /******************/ ul_HighTimerValue = - (ULONG) + (unsigned int) (ul_HighTiming * (0.25 * b_ClockSelection)); - /*******************/ + /*******************/ /* Round the value */ - /*******************/ + /*******************/ if ((double)((double)ul_HighTiming * (0.25 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) { ul_HighTimerValue @@ -2930,13 +2930,13 @@ INT i_APCI1710_SetNewPWMTiming(struct comedi_device * dev, 1; } - /*****************************/ + /*****************************/ /* Calculate the real timing */ - /*****************************/ + /*****************************/ ul_RealHighTiming = - (ULONG) + (unsigned int) (ul_HighTimerValue / (0.25 * (double)b_ClockSelection)); @@ -2974,7 +2974,7 @@ INT i_APCI1710_SetNewPWMTiming(struct comedi_device * dev, if (b_ClockSelection != APCI1710_40MHZ) { ul_HighTimerValue = - (ULONG) + (unsigned int) ( (double) (ul_HighTimerValue) @@ -2984,15 +2984,15 @@ INT i_APCI1710_SetNewPWMTiming(struct comedi_device * dev, break; - /******/ + /******/ /* ms */ - /******/ + /******/ case 2: - /******************/ + /******************/ /* Timer 0 factor */ - /******************/ + /******************/ ul_HighTimerValue = @@ -3002,9 +3002,9 @@ INT i_APCI1710_SetNewPWMTiming(struct comedi_device * dev, * b_ClockSelection); - /*******************/ + /*******************/ /* Round the value */ - /*******************/ + /*******************/ if ((double)((double)ul_HighTiming * (250.0 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) { ul_HighTimerValue @@ -3014,13 +3014,13 @@ INT i_APCI1710_SetNewPWMTiming(struct comedi_device * dev, 1; } - /*****************************/ + /*****************************/ /* Calculate the real timing */ - /*****************************/ + /*****************************/ ul_RealHighTiming = - (ULONG) + (unsigned int) (ul_HighTimerValue / (250.0 * (double)b_ClockSelection)); @@ -3056,7 +3056,7 @@ INT i_APCI1710_SetNewPWMTiming(struct comedi_device * dev, if (b_ClockSelection != APCI1710_40MHZ) { ul_HighTimerValue = - (ULONG) + (unsigned int) ( (double) (ul_HighTimerValue) @@ -3066,28 +3066,28 @@ INT i_APCI1710_SetNewPWMTiming(struct comedi_device * dev, break; - /*****/ + /*****/ /* s */ - /*****/ + /*****/ case 3: - /******************/ + /******************/ /* Timer 0 factor */ - /******************/ + /******************/ ul_HighTimerValue = - (ULONG) + (unsigned int) (ul_HighTiming * (250000.0 * b_ClockSelection)); - /*******************/ + /*******************/ /* Round the value */ - /*******************/ + /*******************/ if ((double)((double)ul_HighTiming * (250000.0 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) { ul_HighTimerValue @@ -3097,13 +3097,13 @@ INT i_APCI1710_SetNewPWMTiming(struct comedi_device * dev, 1; } - /*****************************/ + /*****************************/ /* Calculate the real timing */ - /*****************************/ + /*****************************/ ul_RealHighTiming = - (ULONG) + (unsigned int) (ul_HighTimerValue / (250000.0 @@ -3142,7 +3142,7 @@ INT i_APCI1710_SetNewPWMTiming(struct comedi_device * dev, if (b_ClockSelection != APCI1710_40MHZ) { ul_HighTimerValue = - (ULONG) + (unsigned int) ( (double) (ul_HighTimerValue) @@ -3152,19 +3152,19 @@ INT i_APCI1710_SetNewPWMTiming(struct comedi_device * dev, break; - /******/ + /******/ /* mn */ - /******/ + /******/ case 4: - /******************/ + /******************/ /* Timer 0 factor */ - /******************/ + /******************/ ul_HighTimerValue = - (ULONG) + (unsigned int) ( (ul_HighTiming * @@ -3174,9 +3174,9 @@ INT i_APCI1710_SetNewPWMTiming(struct comedi_device * dev, * b_ClockSelection)); - /*******************/ + /*******************/ /* Round the value */ - /*******************/ + /*******************/ if ((double)((double)(ul_HighTiming * 60.0) * (250000.0 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) { ul_HighTimerValue @@ -3186,13 +3186,13 @@ INT i_APCI1710_SetNewPWMTiming(struct comedi_device * dev, 1; } - /*****************************/ + /*****************************/ /* Calculate the real timing */ - /*****************************/ + /*****************************/ ul_RealHighTiming = - (ULONG) + (unsigned int) (ul_HighTimerValue / (250000.0 @@ -3236,7 +3236,7 @@ INT i_APCI1710_SetNewPWMTiming(struct comedi_device * dev, if (b_ClockSelection != APCI1710_40MHZ) { ul_HighTimerValue = - (ULONG) + (unsigned int) ( (double) (ul_HighTimerValue) @@ -3249,9 +3249,9 @@ INT i_APCI1710_SetNewPWMTiming(struct comedi_device * dev, fpu_end(); - /************************/ + /************************/ /* Save the timing unit */ - /************************/ + /************************/ devpriv-> s_ModuleInfo @@ -3263,9 +3263,9 @@ INT i_APCI1710_SetNewPWMTiming(struct comedi_device * dev, = b_TimingUnit; - /****************************/ + /****************************/ /* Save the low base timing */ - /****************************/ + /****************************/ devpriv-> s_ModuleInfo @@ -3287,9 +3287,9 @@ INT i_APCI1710_SetNewPWMTiming(struct comedi_device * dev, = ul_RealLowTiming; - /****************************/ + /****************************/ /* Save the high base timing */ - /****************************/ + /****************************/ devpriv-> s_ModuleInfo @@ -3311,21 +3311,21 @@ INT i_APCI1710_SetNewPWMTiming(struct comedi_device * dev, = ul_RealHighTiming; - /************************/ + /************************/ /* Write the low timing */ - /************************/ + /************************/ outl(ul_LowTimerValue, devpriv->s_BoardInfos.ui_Address + 0 + (20 * b_PWM) + (64 * b_ModulNbr)); - /*************************/ + /*************************/ /* Write the high timing */ - /*************************/ + /*************************/ outl(ul_HighTimerValue, devpriv->s_BoardInfos.ui_Address + 4 + (20 * b_PWM) + (64 * b_ModulNbr)); - /***************************/ + /***************************/ /* Set the clock selection */ - /***************************/ + /***************************/ dw_Command = inl @@ -3347,9 +3347,9 @@ INT i_APCI1710_SetNewPWMTiming(struct comedi_device * dev, 0x80; } - /***************************/ + /***************************/ /* Set the clock selection */ - /***************************/ + /***************************/ outl(dw_Command, devpriv-> @@ -3358,96 +3358,96 @@ INT i_APCI1710_SetNewPWMTiming(struct comedi_device * dev, + 8 + (20 * b_PWM) + (64 * b_ModulNbr)); } else { - /***************************************/ + /***************************************/ /* High base timing selection is wrong */ - /***************************************/ + /***************************************/ DPRINTK("High base timing selection is wrong\n"); i_ReturnValue = -8; } } else { - /**************************************/ + /**************************************/ /* Low base timing selection is wrong */ - /**************************************/ + /**************************************/ DPRINTK("Low base timing selection is wrong\n"); i_ReturnValue = -7; } - } // if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4)) + } /* if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4)) */ else { - /**********************************/ + /**********************************/ /* Timing unit selection is wrong */ - /**********************************/ + /**********************************/ DPRINTK("Timing unit selection is wrong\n"); i_ReturnValue = -6; - } // if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4)) - } // if (dw_Status & 0x10) + } /* if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4)) */ + } /* if (dw_Status & 0x10) */ else { - /***********************/ + /***********************/ /* PWM not initialised */ - /***********************/ + /***********************/ DPRINTK("PWM not initialised\n"); i_ReturnValue = -5; - } // if (dw_Status & 0x10) - } // if (b_PWM >= 0 && b_PWM <= 1) + } /* if (dw_Status & 0x10) */ + } /* if (b_PWM >= 0 && b_PWM <= 1) */ else { - /******************************/ + /******************************/ /* Tor PWM selection is wrong */ - /******************************/ + /******************************/ DPRINTK("Tor PWM selection is wrong\n"); i_ReturnValue = -4; - } // if (b_PWM >= 0 && b_PWM <= 1) + } /* if (b_PWM >= 0 && b_PWM <= 1) */ } else { - /**********************************/ + /**********************************/ /* The module is not a PWM module */ - /**********************************/ + /**********************************/ DPRINTK("The module is not a PWM module\n"); i_ReturnValue = -3; } } else { - /***********************/ + /***********************/ /* Module number error */ - /***********************/ + /***********************/ DPRINTK("Module number error\n"); i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_GetPWMStatus | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr, | -| BYTE_ b_PWM, | -| PBYTE_ pb_PWMOutputStatus, | -| PBYTE_ pb_ExternGateStatus) | +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr, | +| unsigned char_ b_PWM, | +| unsigned char *_ pb_PWMOutputStatus, | +| unsigned char *_ pb_ExternGateStatus) | +----------------------------------------------------------------------------+ | Task : Return the status from selected PWM (b_PWM) from | | selected module (b_ModulNbr). | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | -| BYTE_ b_PWM : Selected PWM (0 or 1) | -| BYTE_ b_ModulNbr : Selected module number (0 to 3) - b_ModulNbr =(BYTE) CR_AREF(insn->chanspec); - b_PWM =(BYTE) data[0]; +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | +| unsigned char_ b_PWM : Selected PWM (0 or 1) | +| unsigned char_ b_ModulNbr : Selected module number (0 to 3) + b_ModulNbr =(unsigned char) CR_AREF(insn->chanspec); + b_PWM =(unsigned char) data[0]; | +----------------------------------------------------------------------------+ -| Output Parameters : PBYTE_ pb_PWMOutputStatus : Return the PWM output | +| Output Parameters : unsigned char *_ pb_PWMOutputStatus : Return the PWM output | | level status. | | 0 : The PWM output level| | is low. | | 1 : The PWM output level| | is high. | -| PBYTE_ pb_ExternGateStatus : Return the extern gate | +| unsigned char *_ pb_ExternGateStatus : Return the extern gate | | level status. | | 0 : The extern gate is | | low. | | 1 : The extern gate is | | high. - pb_PWMOutputStatus =(PBYTE) data[0]; - pb_ExternGateStatus =(PBYTE) data[1]; | + pb_PWMOutputStatus =(unsigned char *) data[0]; + pb_ExternGateStatus =(unsigned char *) data[1]; | +----------------------------------------------------------------------------+ | Return Value : 0: No error | | -1: The handle parameter of the board is wrong | @@ -3460,109 +3460,109 @@ INT i_APCI1710_SetNewPWMTiming(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -INT i_APCI1710_InsnReadGetPWMStatus(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI1710_InsnReadGetPWMStatus(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - INT i_ReturnValue = 0; - DWORD dw_Status; + int i_ReturnValue = 0; + unsigned int dw_Status; - BYTE b_ModulNbr; - BYTE b_PWM; - PBYTE pb_PWMOutputStatus; - PBYTE pb_ExternGateStatus; + unsigned char b_ModulNbr; + unsigned char b_PWM; + unsigned char *pb_PWMOutputStatus; + unsigned char *pb_ExternGateStatus; i_ReturnValue = insn->n; - b_ModulNbr = (BYTE) CR_AREF(insn->chanspec); - b_PWM = (BYTE) CR_CHAN(insn->chanspec); - pb_PWMOutputStatus = (PBYTE) & data[0]; - pb_ExternGateStatus = (PBYTE) & data[1]; + b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); + b_PWM = (unsigned char) CR_CHAN(insn->chanspec); + pb_PWMOutputStatus = (unsigned char *) &data[0]; + pb_ExternGateStatus = (unsigned char *) &data[1]; /**************************/ /* Test the module number */ /**************************/ if (b_ModulNbr < 4) { - /***************/ + /***************/ /* Test if PWM */ - /***************/ + /***************/ if ((devpriv->s_BoardInfos. dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF0000UL) == APCI1710_PWM) { - /**************************/ + /**************************/ /* Test the PWM selection */ - /**************************/ + /**************************/ if (b_PWM <= 1) { - /***************************/ + /***************************/ /* Test if PWM initialised */ - /***************************/ + /***************************/ dw_Status = inl(devpriv->s_BoardInfos. ui_Address + 12 + (20 * b_PWM) + (64 * b_ModulNbr)); if (dw_Status & 0x10) { - /***********************/ + /***********************/ /* Test if PWM enabled */ - /***********************/ + /***********************/ if (dw_Status & 0x1) { *pb_PWMOutputStatus = - (BYTE) ((dw_Status >> 7) + (unsigned char) ((dw_Status >> 7) & 1); *pb_ExternGateStatus = - (BYTE) ((dw_Status >> 6) + (unsigned char) ((dw_Status >> 6) & 1); - } // if (dw_Status & 0x1) + } /* if (dw_Status & 0x1) */ else { - /*******************/ + /*******************/ /* PWM not enabled */ - /*******************/ + /*******************/ DPRINTK("PWM not enabled \n"); i_ReturnValue = -6; - } // if (dw_Status & 0x1) - } // if (dw_Status & 0x10) + } /* if (dw_Status & 0x1) */ + } /* if (dw_Status & 0x10) */ else { - /***********************/ + /***********************/ /* PWM not initialised */ - /***********************/ + /***********************/ DPRINTK("PWM not initialised\n"); i_ReturnValue = -5; - } // if (dw_Status & 0x10) - } // if (b_PWM >= 0 && b_PWM <= 1) + } /* if (dw_Status & 0x10) */ + } /* if (b_PWM >= 0 && b_PWM <= 1) */ else { - /******************************/ + /******************************/ /* Tor PWM selection is wrong */ - /******************************/ + /******************************/ DPRINTK("Tor PWM selection is wrong\n"); i_ReturnValue = -4; - } // if (b_PWM >= 0 && b_PWM <= 1) + } /* if (b_PWM >= 0 && b_PWM <= 1) */ } else { - /**********************************/ + /**********************************/ /* The module is not a PWM module */ - /**********************************/ + /**********************************/ DPRINTK("The module is not a PWM module\n"); i_ReturnValue = -3; } } else { - /***********************/ + /***********************/ /* Module number error */ - /***********************/ + /***********************/ DPRINTK("Module number error\n"); i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } -INT i_APCI1710_InsnBitsReadPWMInterrupt(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +int i_APCI1710_InsnBitsReadPWMInterrupt(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { data[0] = devpriv->s_InterruptParameters. s_FIFOInterruptParameters[devpriv-> @@ -3574,9 +3574,9 @@ INT i_APCI1710_InsnBitsReadPWMInterrupt(struct comedi_device * dev, s_FIFOInterruptParameters[devpriv-> s_InterruptParameters.ui_Read].ul_OldCounterLatchValue; - /**************************/ + /**************************/ /* Increment the read FIFO */ - /***************************/ + /***************************/ devpriv-> s_InterruptParameters. diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Pwm.h b/drivers/staging/comedi/drivers/addi-data/APCI1710_Pwm.h index c1b7f4ca47c3..bf1b4c39a1cd 100644 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Pwm.h +++ b/drivers/staging/comedi/drivers/addi-data/APCI1710_Pwm.h @@ -26,51 +26,51 @@ #define APCI1710_PWM_ENABLE 1 #define APCI1710_PWM_NEWTIMING 2 -INT i_APCI1710_InsnConfigPWM(struct comedi_device *dev, struct comedi_subdevice *s, +int i_APCI1710_InsnConfigPWM(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -INT i_APCI1710_InitPWM(struct comedi_device *dev, - BYTE b_ModulNbr, - BYTE b_PWM, - BYTE b_ClockSelection, - BYTE b_TimingUnit, - ULONG ul_LowTiming, - ULONG ul_HighTiming, - PULONG pul_RealLowTiming, PULONG pul_RealHighTiming); +int i_APCI1710_InitPWM(struct comedi_device *dev, + unsigned char b_ModulNbr, + unsigned char b_PWM, + unsigned char b_ClockSelection, + unsigned char b_TimingUnit, + unsigned int ul_LowTiming, + unsigned int ul_HighTiming, + unsigned int *pul_RealLowTiming, unsigned int *pul_RealHighTiming); -INT i_APCI1710_GetPWMInitialisation(struct comedi_device *dev, - BYTE b_ModulNbr, - BYTE b_PWM, - PBYTE pb_TimingUnit, - PULONG pul_LowTiming, - PULONG pul_HighTiming, - PBYTE pb_StartLevel, - PBYTE pb_StopMode, - PBYTE pb_StopLevel, - PBYTE pb_ExternGate, - PBYTE pb_InterruptEnable, PBYTE pb_Enable); +int i_APCI1710_GetPWMInitialisation(struct comedi_device *dev, + unsigned char b_ModulNbr, + unsigned char b_PWM, + unsigned char *pb_TimingUnit, + unsigned int *pul_LowTiming, + unsigned int *pul_HighTiming, + unsigned char *pb_StartLevel, + unsigned char *pb_StopMode, + unsigned char *pb_StopLevel, + unsigned char *pb_ExternGate, + unsigned char *pb_InterruptEnable, unsigned char *pb_Enable); -INT i_APCI1710_InsnWritePWM(struct comedi_device *dev, struct comedi_subdevice *s, +int i_APCI1710_InsnWritePWM(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -INT i_APCI1710_EnablePWM(struct comedi_device *dev, - BYTE b_ModulNbr, - BYTE b_PWM, - BYTE b_StartLevel, - BYTE b_StopMode, - BYTE b_StopLevel, BYTE b_ExternGate, - BYTE b_InterruptEnable); +int i_APCI1710_EnablePWM(struct comedi_device *dev, + unsigned char b_ModulNbr, + unsigned char b_PWM, + unsigned char b_StartLevel, + unsigned char b_StopMode, + unsigned char b_StopLevel, unsigned char b_ExternGate, + unsigned char b_InterruptEnable); -INT i_APCI1710_SetNewPWMTiming(struct comedi_device *dev, - BYTE b_ModulNbr, - BYTE b_PWM, BYTE b_TimingUnit, - ULONG ul_LowTiming, ULONG ul_HighTiming); +int i_APCI1710_SetNewPWMTiming(struct comedi_device *dev, + unsigned char b_ModulNbr, + unsigned char b_PWM, unsigned char b_TimingUnit, + unsigned int ul_LowTiming, unsigned int ul_HighTiming); -INT i_APCI1710_DisablePWM(struct comedi_device *dev, BYTE b_ModulNbr, BYTE b_PWM); +int i_APCI1710_DisablePWM(struct comedi_device *dev, unsigned char b_ModulNbr, unsigned char b_PWM); -INT i_APCI1710_InsnReadGetPWMStatus(struct comedi_device *dev, struct comedi_subdevice *s, +int i_APCI1710_InsnReadGetPWMStatus(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -INT i_APCI1710_InsnBitsReadPWMInterrupt(struct comedi_device *dev, +int i_APCI1710_InsnBitsReadPWMInterrupt(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Ssi.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_Ssi.c index bb6e1622e379..a445dab50eac 100644 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Ssi.c +++ b/drivers/staging/comedi/drivers/addi-data/APCI1710_Ssi.c @@ -3,13 +3,13 @@ Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data-com - info@addi-data.com + ADDI-DATA GmbH + Dieselstrasse 3 + D-77833 Ottersweier + Tel: +19(0)7223/9493-0 + Fax: +49(0)7223/9493-92 + http://www.addi-data-com + info@addi-data.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. @@ -65,31 +65,31 @@ You shoud also find the complete GPL in the COPYING file accompanying this sourc /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_InitSSI | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr, | -| BYTE_ b_SSIProfile, | -| BYTE_ b_PositionTurnLength, | -| BYTE_ b_TurnCptLength, | -| BYTE_ b_PCIInputClock, | +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr, | +| unsigned char_ b_SSIProfile, | +| unsigned char_ b_PositionTurnLength, | +| unsigned char_ b_TurnCptLength, | +| unsigned char_ b_PCIInputClock, | | ULONG_ ul_SSIOutputClock, | -| BYTE_ b_SSICountingMode) | +| unsigned char_ b_SSICountingMode) | +----------------------------------------------------------------------------+ | Task : Configure the SSI operating mode from selected module | | (b_ModulNbr). You must calling this function be for you| | call any other function witch access of SSI. | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710| -| BYTE_ b_ModulNbr : Module number to | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710| +| unsigned char_ b_ModulNbr : Module number to | | configure (0 to 3) | -| BYTE_ b_SSIProfile : Selection from SSI | +| unsigned char_ b_SSIProfile : Selection from SSI | | profile length (2 to 32).| -| BYTE_ b_PositionTurnLength : Selection from SSI | +| unsigned char_ b_PositionTurnLength : Selection from SSI | | position data length | | (1 to 31). | -| BYTE_ b_TurnCptLength : Selection from SSI turn | +| unsigned char_ b_TurnCptLength : Selection from SSI turn | | counter data length | | (1 to 31). | -| BYTE b_PCIInputClock : Selection from PCI bus | +| unsigned char b_PCIInputClock : Selection from PCI bus | | clock | | - APCI1710_30MHZ : | | The PC have a PCI bus | @@ -103,7 +103,7 @@ You shoud also find the complete GPL in the COPYING file accompanying this sourc | for 30 MHz selection. | | From 252 to 5 000 000 Hz| | for 33 MHz selection. | -| BYTE b_SSICountingMode : SSI counting mode | +| unsigned char b_SSICountingMode : SSI counting mode | | selection | | - APCI1710_BINARY_MODE : | | Binary counting mode. | @@ -111,12 +111,12 @@ You shoud also find the complete GPL in the COPYING file accompanying this sourc | Gray counting mode. b_ModulNbr = CR_AREF(insn->chanspec); - b_SSIProfile = (BYTE) data[0]; - b_PositionTurnLength= (BYTE) data[1]; - b_TurnCptLength = (BYTE) data[2]; - b_PCIInputClock = (BYTE) data[3]; - ul_SSIOutputClock = (ULONG) data[4]; - b_SSICountingMode = (BYTE) data[5]; | + b_SSIProfile = (unsigned char) data[0]; + b_PositionTurnLength= (unsigned char) data[1]; + b_TurnCptLength = (unsigned char) data[2]; + b_PCIInputClock = (unsigned char) data[3]; + ul_SSIOutputClock = (unsigned int) data[4]; + b_SSICountingMode = (unsigned char) data[5]; | +----------------------------------------------------------------------------+ | Output Parameters : - | +----------------------------------------------------------------------------+ @@ -133,22 +133,22 @@ You shoud also find the complete GPL in the COPYING file accompanying this sourc +----------------------------------------------------------------------------+ */ -INT i_APCI1710_InsnConfigInitSSI(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI1710_InsnConfigInitSSI(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - INT i_ReturnValue = 0; - UINT ui_TimerValue; - BYTE b_ModulNbr, b_SSIProfile, b_PositionTurnLength, b_TurnCptLength, + int i_ReturnValue = 0; + unsigned int ui_TimerValue; + unsigned char b_ModulNbr, b_SSIProfile, b_PositionTurnLength, b_TurnCptLength, b_PCIInputClock, b_SSICountingMode; - ULONG ul_SSIOutputClock; + unsigned int ul_SSIOutputClock; b_ModulNbr = CR_AREF(insn->chanspec); - b_SSIProfile = (BYTE) data[0]; - b_PositionTurnLength = (BYTE) data[1]; - b_TurnCptLength = (BYTE) data[2]; - b_PCIInputClock = (BYTE) data[3]; - ul_SSIOutputClock = (ULONG) data[4]; - b_SSICountingMode = (BYTE) data[5]; + b_SSIProfile = (unsigned char) data[0]; + b_PositionTurnLength = (unsigned char) data[1]; + b_TurnCptLength = (unsigned char) data[2]; + b_PCIInputClock = (unsigned char) data[3]; + ul_SSIOutputClock = (unsigned int) data[4]; + b_SSICountingMode = (unsigned char) data[5]; i_ReturnValue = insn->n; /**************************/ @@ -167,7 +167,7 @@ INT i_APCI1710_InsnConfigInitSSI(struct comedi_device * dev, struct comedi_subde /* Test the SSI profile length */ /*******************************/ - // CG 22/03/00 b_SSIProfile >= 2 anstatt b_SSIProfile > 2 + /* CG 22/03/00 b_SSIProfile >= 2 anstatt b_SSIProfile > 2 */ if (b_SSIProfile >= 2 && b_SSIProfile < 33) { /*************************************/ /* Test the SSI position data length */ @@ -250,9 +250,9 @@ INT i_APCI1710_InsnConfigInitSSI(struct comedi_device * dev, struct comedi_subde ui_TimerValue = - (UINT) + (unsigned int) ( - ((ULONG) (b_PCIInputClock) * 500000UL) / ul_SSIOutputClock); + ((unsigned int) (b_PCIInputClock) * 500000UL) / ul_SSIOutputClock); /************************/ /* Initialise the timer */ @@ -351,18 +351,18 @@ INT i_APCI1710_InsnConfigInitSSI(struct comedi_device * dev, struct comedi_subde i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_Read1SSIValue | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr, | -| BYTE_ b_SelectedSSI, | +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr, | +| unsigned char_ b_SelectedSSI, | | PULONG_ pul_Position, | | PULONG_ pul_TurnCpt) - INT i_APCI1710_ReadSSIValue(struct comedi_device *dev,struct comedi_subdevice *s, + int i_APCI1710_ReadSSIValue(struct comedi_device *dev,struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data) | +----------------------------------------------------------------------------+ | Task : @@ -373,22 +373,22 @@ INT i_APCI1710_InsnConfigInitSSI(struct comedi_device * dev, struct comedi_subde or Read all SSI counter (b_SelectedSSI) from | | selected module (b_ModulNbr). | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710| -| BYTE_ b_ModulNbr : Module number to | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710| +| unsigned char_ b_ModulNbr : Module number to | | configure (0 to 3) | -| BYTE_ b_SelectedSSI : Selection from SSI | +| unsigned char_ b_SelectedSSI : Selection from SSI | | counter (0 to 2) - b_ModulNbr = (BYTE) CR_AREF(insn->chanspec); - b_SelectedSSI = (BYTE) CR_CHAN(insn->chanspec); (in case of single ssi) - b_ReadType = (BYTE) CR_RANGE(insn->chanspec); + b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); + b_SelectedSSI = (unsigned char) CR_CHAN(insn->chanspec); (in case of single ssi) + b_ReadType = (unsigned char) CR_RANGE(insn->chanspec); | +----------------------------------------------------------------------------+ | Output Parameters : PULONG_ pul_Position : SSI position in the turn | | PULONG_ pul_TurnCpt : Number of turns -pul_Position = (PULONG) &data[0]; - pul_TurnCpt = (PULONG) &data[1]; | +pul_Position = (unsigned int *) &data[0]; + pul_TurnCpt = (unsigned int *) &data[1]; | +----------------------------------------------------------------------------+ | Return Value : 0: No error | | -1: The handle parameter of the board is wrong | @@ -400,37 +400,37 @@ pul_Position = (PULONG) &data[0]; +----------------------------------------------------------------------------+ */ -INT i_APCI1710_InsnReadSSIValue(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI1710_InsnReadSSIValue(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - INT i_ReturnValue = 0; - BYTE b_Cpt; - BYTE b_Length; - BYTE b_Schift; - BYTE b_SSICpt; - DWORD dw_And; - DWORD dw_And1; - DWORD dw_And2; - DWORD dw_StatusReg; - DWORD dw_CounterValue; - BYTE b_ModulNbr; - BYTE b_SelectedSSI; - BYTE b_ReadType; - PULONG pul_Position; - PULONG pul_TurnCpt; - PULONG pul_Position1; - PULONG pul_TurnCpt1; + int i_ReturnValue = 0; + unsigned char b_Cpt; + unsigned char b_Length; + unsigned char b_Schift; + unsigned char b_SSICpt; + unsigned int dw_And; + unsigned int dw_And1; + unsigned int dw_And2; + unsigned int dw_StatusReg; + unsigned int dw_CounterValue; + unsigned char b_ModulNbr; + unsigned char b_SelectedSSI; + unsigned char b_ReadType; + unsigned int *pul_Position; + unsigned int *pul_TurnCpt; + unsigned int *pul_Position1; + unsigned int *pul_TurnCpt1; i_ReturnValue = insn->n; - pul_Position1 = (PULONG) & data[0]; -// For Read1 - pul_TurnCpt1 = (PULONG) & data[1]; -// For Read all - pul_Position = (PULONG) & data[0]; //0-2 - pul_TurnCpt = (PULONG) & data[3]; //3-5 - b_ModulNbr = (BYTE) CR_AREF(insn->chanspec); - b_SelectedSSI = (BYTE) CR_CHAN(insn->chanspec); - b_ReadType = (BYTE) CR_RANGE(insn->chanspec); + pul_Position1 = (unsigned int *) &data[0]; +/* For Read1 */ + pul_TurnCpt1 = (unsigned int *) &data[1]; +/* For Read all */ + pul_Position = (unsigned int *) &data[0]; /* 0-2 */ + pul_TurnCpt = (unsigned int *) &data[3]; /* 3-5 */ + b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); + b_SelectedSSI = (unsigned char) CR_CHAN(insn->chanspec); + b_ReadType = (unsigned char) CR_RANGE(insn->chanspec); /**************************/ /* Test the module number */ @@ -477,9 +477,8 @@ INT i_APCI1710_InsnReadSSIValue(struct comedi_device * dev, struct comedi_subdev s_BoardInfos. ui_Address + (64 * b_ModulNbr)); - } - while ((dw_StatusReg & 0x1) != - 0); + } while ((dw_StatusReg & 0x1) + != 0); /******************************/ /* Read the SSI counter value */ @@ -608,8 +607,7 @@ INT i_APCI1710_InsnReadSSIValue(struct comedi_device * dev, struct comedi_subdev s_BoardInfos. ui_Address + (64 * b_ModulNbr)); - } - while ((dw_StatusReg & 0x1) != 0); + } while ((dw_StatusReg & 0x1) != 0); for (b_SSICpt = 0; b_SSICpt < 3; b_SSICpt++) { @@ -667,7 +665,7 @@ INT i_APCI1710_InsnReadSSIValue(struct comedi_device * dev, struct comedi_subdev default: printk("Read Type Inputs Wrong\n"); - } // switch ending + } /* switch ending */ } else { /***********************/ @@ -695,16 +693,16 @@ INT i_APCI1710_InsnReadSSIValue(struct comedi_device * dev, struct comedi_subdev i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_ReadSSI1DigitalInput | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr, | -| BYTE_ b_InputChannel, | -| PBYTE_ pb_ChannelStatus) | +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr, | +| unsigned char_ b_InputChannel, | +| unsigned char *_ pb_ChannelStatus) | +----------------------------------------------------------------------------+ | Task : (0) Set the digital output from selected SSI moule | @@ -716,13 +714,13 @@ INT i_APCI1710_InsnReadSSIValue(struct comedi_device * dev, struct comedi_subdev (3)Read the status from all SSI digital inputs from | | selected SSI module (b_ModulNbr) | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710| -| BYTE_ b_ModulNbr CR_AREF : Module number to | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710| +| unsigned char_ b_ModulNbr CR_AREF : Module number to | | configure (0 to 3) | -| BYTE_ b_InputChannel CR_CHAN : Selection from digital | +| unsigned char_ b_InputChannel CR_CHAN : Selection from digital | | data[0] which IOTYPE input ( 0 to 2) | +----------------------------------------------------------------------------+ -| Output Parameters : PBYTE_ pb_ChannelStatus : Digital input channel | +| Output Parameters : unsigned char *_ pb_ChannelStatus : Digital input channel | | data[0] status | | 0 : Channle is not active| | 1 : Channle is active | @@ -735,19 +733,19 @@ INT i_APCI1710_InsnReadSSIValue(struct comedi_device * dev, struct comedi_subdev +----------------------------------------------------------------------------+ */ -INT i_APCI1710_InsnBitsSSIDigitalIO(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI1710_InsnBitsSSIDigitalIO(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - INT i_ReturnValue = 0; - DWORD dw_StatusReg; - BYTE b_ModulNbr; - BYTE b_InputChannel; - PBYTE pb_ChannelStatus; - PBYTE pb_InputStatus; - BYTE b_IOType; + int i_ReturnValue = 0; + unsigned int dw_StatusReg; + unsigned char b_ModulNbr; + unsigned char b_InputChannel; + unsigned char *pb_ChannelStatus; + unsigned char *pb_InputStatus; + unsigned char b_IOType; i_ReturnValue = insn->n; - b_ModulNbr = (BYTE) CR_AREF(insn->chanspec); - b_IOType = (BYTE) data[0]; + b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); + b_IOType = (unsigned char) data[0]; /**************************/ /* Test the module number */ @@ -785,8 +783,8 @@ INT i_APCI1710_InsnBitsSSIDigitalIO(struct comedi_device * dev, struct comedi_su /* Test the digital imnput channel number */ /******************************************/ - b_InputChannel = (BYTE) CR_CHAN(insn->chanspec); - pb_ChannelStatus = (PBYTE) & data[0]; + b_InputChannel = (unsigned char) CR_CHAN(insn->chanspec); + pb_ChannelStatus = (unsigned char *) &data[0]; if (b_InputChannel <= 2) { /**************************/ @@ -797,7 +795,7 @@ INT i_APCI1710_InsnBitsSSIDigitalIO(struct comedi_device * dev, struct comedi_su inl(devpriv->s_BoardInfos. ui_Address + (64 * b_ModulNbr)); *pb_ChannelStatus = - (BYTE) (((~dw_StatusReg) >> (4 + + (unsigned char) (((~dw_StatusReg) >> (4 + b_InputChannel)) & 1); } else { @@ -814,19 +812,19 @@ INT i_APCI1710_InsnBitsSSIDigitalIO(struct comedi_device * dev, struct comedi_su /**************************/ /* Read all digital input */ /**************************/ - pb_InputStatus = (PBYTE) & data[0]; + pb_InputStatus = (unsigned char *) &data[0]; dw_StatusReg = inl(devpriv->s_BoardInfos.ui_Address + (64 * b_ModulNbr)); *pb_InputStatus = - (BYTE) (((~dw_StatusReg) >> 4) & 7); + (unsigned char) (((~dw_StatusReg) >> 4) & 7); break; default: printk("IO type wrong\n"); - } //switch end + } /* switch end */ } else { /**********************************/ /* The module is not a SSI module */ @@ -844,5 +842,5 @@ INT i_APCI1710_InsnBitsSSIDigitalIO(struct comedi_device * dev, struct comedi_su i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Ssi.h b/drivers/staging/comedi/drivers/addi-data/APCI1710_Ssi.h index 88daad1a3912..eb7f101d2d61 100644 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Ssi.h +++ b/drivers/staging/comedi/drivers/addi-data/APCI1710_Ssi.h @@ -33,11 +33,11 @@ /* * SSI INISIALISATION FUNCTION */ -INT i_APCI1710_InsnConfigInitSSI(struct comedi_device *dev, struct comedi_subdevice *s, +int i_APCI1710_InsnConfigInitSSI(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -INT i_APCI1710_InsnReadSSIValue(struct comedi_device *dev, struct comedi_subdevice *s, +int i_APCI1710_InsnReadSSIValue(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -INT i_APCI1710_InsnBitsSSIDigitalIO(struct comedi_device *dev, struct comedi_subdevice *s, +int i_APCI1710_InsnBitsSSIDigitalIO(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Tor.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_Tor.c index 90316e10a3bd..43198aafb2dc 100644 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Tor.c +++ b/drivers/staging/comedi/drivers/addi-data/APCI1710_Tor.c @@ -3,13 +3,13 @@ Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data-com - info@addi-data.com + ADDI-DATA GmbH + Dieselstrasse 3 + D-77833 Ottersweier + Tel: +19(0)7223/9493-0 + Fax: +49(0)7223/9493-92 + http://www.addi-data-com + info@addi-data.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. @@ -63,11 +63,11 @@ You shoud also find the complete GPL in the COPYING file accompanying this sourc /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_InitTorCounter | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr, | -| BYTE_ b_TorCounter, | -| BYTE_ b_PCIInputClock, | -| BYTE_ b_TimingUnit, | +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr, | +| unsigned char_ b_TorCounter, | +| unsigned char_ b_PCIInputClock, | +| unsigned char_ b_TimingUnit, | | ULONG_ ul_TimingInterval, | | PULONG_ pul_RealTimingInterval) | +----------------------------------------------------------------------------+ @@ -82,11 +82,11 @@ You shoud also find the complete GPL in the COPYING file accompanying this sourc +----------------------------------------------------------------------------+ | Input Parameters : | | - CR_AREF BYTE_ b_ModulNbr : Module number to configure | + CR_AREF unsigned char_ b_ModulNbr : Module number to configure | | (0 to 3) | -| data[0] BYTE_ b_TorCounter : Tor counter selection | +| data[0] unsigned char_ b_TorCounter : Tor counter selection | | (0 or 1). | -| data[1] BYTE_ b_PCIInputClock : Selection from PCI bus clock| +| data[1] unsigned char_ b_PCIInputClock : Selection from PCI bus clock| | - APCI1710_30MHZ : | | The PC have a PCI bus | | clock from 30 MHz | @@ -104,7 +104,7 @@ You shoud also find the complete GPL in the COPYING file accompanying this sourc | than it is not possibl to | | used the gate input for | | enabled the acquisition | -| data[2] BYTE_ b_TimingUnit : Base timing unit (0 to 4) | +| data[2] unsigned char_ b_TimingUnit : Base timing unit (0 to 4) | | 0 : ns | | 1 : µs | | 2 : ms | @@ -130,27 +130,27 @@ You shoud also find the complete GPL in the COPYING file accompanying this sourc +----------------------------------------------------------------------------+ */ -INT i_APCI1710_InsnConfigInitTorCounter(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +int i_APCI1710_InsnConfigInitTorCounter(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - INT i_ReturnValue = 0; - ULONG ul_TimerValue = 0; - DWORD dw_Command; + int i_ReturnValue = 0; + unsigned int ul_TimerValue = 0; + unsigned int dw_Command; double d_RealTimingInterval = 0; - BYTE b_ModulNbr; - BYTE b_TorCounter; - BYTE b_PCIInputClock; - BYTE b_TimingUnit; - ULONG ul_TimingInterval; - ULONG ul_RealTimingInterval = 0; + unsigned char b_ModulNbr; + unsigned char b_TorCounter; + unsigned char b_PCIInputClock; + unsigned char b_TimingUnit; + unsigned int ul_TimingInterval; + unsigned int ul_RealTimingInterval = 0; i_ReturnValue = insn->n; - b_ModulNbr = (BYTE) CR_AREF(insn->chanspec); + b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); - b_TorCounter = (BYTE) data[0]; - b_PCIInputClock = (BYTE) data[1]; - b_TimingUnit = (BYTE) data[2]; - ul_TimingInterval = (ULONG) data[3]; + b_TorCounter = (unsigned char) data[0]; + b_PCIInputClock = (unsigned char) data[1]; + b_TimingUnit = (unsigned char) data[2]; + ul_TimingInterval = (unsigned int) data[3]; printk("INPUT clock %d\n", b_PCIInputClock); /**************************/ @@ -225,7 +225,7 @@ INT i_APCI1710_InsnConfigInitTorCounter(struct comedi_device * dev, ul_TimerValue = - (ULONG) + (unsigned int) (ul_TimingInterval * (0.00025 * b_PCIInputClock)); @@ -248,7 +248,7 @@ INT i_APCI1710_InsnConfigInitTorCounter(struct comedi_device * dev, ul_RealTimingInterval = - (ULONG) + (unsigned int) (ul_TimerValue / (0.00025 * (double)b_PCIInputClock)); @@ -284,7 +284,7 @@ INT i_APCI1710_InsnConfigInitTorCounter(struct comedi_device * dev, if (b_PCIInputClock != APCI1710_40MHZ) { ul_TimerValue = - (ULONG) + (unsigned int) ( (double) (ul_TimerValue) @@ -306,7 +306,7 @@ INT i_APCI1710_InsnConfigInitTorCounter(struct comedi_device * dev, ul_TimerValue = - (ULONG) + (unsigned int) (ul_TimingInterval * (0.25 * b_PCIInputClock)); @@ -329,7 +329,7 @@ INT i_APCI1710_InsnConfigInitTorCounter(struct comedi_device * dev, ul_RealTimingInterval = - (ULONG) + (unsigned int) (ul_TimerValue / (0.25 * (double)b_PCIInputClock)); @@ -367,7 +367,7 @@ INT i_APCI1710_InsnConfigInitTorCounter(struct comedi_device * dev, if (b_PCIInputClock != APCI1710_40MHZ) { ul_TimerValue = - (ULONG) + (unsigned int) ( (double) (ul_TimerValue) @@ -413,7 +413,7 @@ INT i_APCI1710_InsnConfigInitTorCounter(struct comedi_device * dev, ul_RealTimingInterval = - (ULONG) + (unsigned int) (ul_TimerValue / (250.0 * (double)b_PCIInputClock)); @@ -449,7 +449,7 @@ INT i_APCI1710_InsnConfigInitTorCounter(struct comedi_device * dev, if (b_PCIInputClock != APCI1710_40MHZ) { ul_TimerValue = - (ULONG) + (unsigned int) ( (double) (ul_TimerValue) @@ -471,7 +471,7 @@ INT i_APCI1710_InsnConfigInitTorCounter(struct comedi_device * dev, ul_TimerValue = - (ULONG) + (unsigned int) (ul_TimingInterval * (250000.0 @@ -496,7 +496,7 @@ INT i_APCI1710_InsnConfigInitTorCounter(struct comedi_device * dev, ul_RealTimingInterval = - (ULONG) + (unsigned int) (ul_TimerValue / (250000.0 @@ -535,7 +535,7 @@ INT i_APCI1710_InsnConfigInitTorCounter(struct comedi_device * dev, if (b_PCIInputClock != APCI1710_40MHZ) { ul_TimerValue = - (ULONG) + (unsigned int) ( (double) (ul_TimerValue) @@ -557,7 +557,7 @@ INT i_APCI1710_InsnConfigInitTorCounter(struct comedi_device * dev, ul_TimerValue = - (ULONG) + (unsigned int) ( (ul_TimingInterval * @@ -585,7 +585,7 @@ INT i_APCI1710_InsnConfigInitTorCounter(struct comedi_device * dev, ul_RealTimingInterval = - (ULONG) + (unsigned int) (ul_TimerValue / (250000.0 @@ -629,7 +629,7 @@ INT i_APCI1710_InsnConfigInitTorCounter(struct comedi_device * dev, if (b_PCIInputClock != APCI1710_40MHZ) { ul_TimerValue = - (ULONG) + (unsigned int) ( (double) (ul_TimerValue) @@ -641,7 +641,7 @@ INT i_APCI1710_InsnConfigInitTorCounter(struct comedi_device * dev, } fpu_end(); - } // if (b_PCIInputClock != APCI1710_GATE_INPUT) + } /* if (b_PCIInputClock != APCI1710_GATE_INPUT) */ else { /*************************************************************/ /* 2 Clock used for the overflow and the reload from counter */ @@ -652,7 +652,7 @@ INT i_APCI1710_InsnConfigInitTorCounter(struct comedi_device * dev, ul_TimingInterval - 2; - } // if (b_PCIInputClock != APCI1710_GATE_INPUT) + } /* if (b_PCIInputClock != APCI1710_GATE_INPUT) */ /****************************/ /* Save the PCI input clock */ @@ -814,7 +814,7 @@ INT i_APCI1710_InsnConfigInitTorCounter(struct comedi_device * dev, DPRINTK("Base timing selection is wrong\n"); i_ReturnValue = -7; } - } // if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4)) + } /* if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4)) */ else { /**********************************/ /* Timing unit selection is wrong */ @@ -822,8 +822,8 @@ INT i_APCI1710_InsnConfigInitTorCounter(struct comedi_device * dev, DPRINTK("Timing unit selection is wrong\n"); i_ReturnValue = -6; - } // if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4)) - } // if ((b_PCIInputClock == APCI1710_30MHZ) || (b_PCIInputClock == APCI1710_33MHZ)) + } /* if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4)) */ + } /* if ((b_PCIInputClock == APCI1710_30MHZ) || (b_PCIInputClock == APCI1710_33MHZ)) */ else { /*****************************************/ /* The selected PCI input clock is wrong */ @@ -831,8 +831,8 @@ INT i_APCI1710_InsnConfigInitTorCounter(struct comedi_device * dev, DPRINTK("The selected PCI input clock is wrong\n"); i_ReturnValue = -5; - } // if ((b_PCIInputClock == APCI1710_30MHZ) || (b_PCIInputClock == APCI1710_33MHZ)) - } // if (b_TorCounterMode >= 0 && b_TorCounterMode <= 7) + } /* if ((b_PCIInputClock == APCI1710_30MHZ) || (b_PCIInputClock == APCI1710_33MHZ)) */ + } /* if (b_TorCounterMode >= 0 && b_TorCounterMode <= 7) */ else { /**********************************/ /* Tor Counter selection is wrong */ @@ -840,7 +840,7 @@ INT i_APCI1710_InsnConfigInitTorCounter(struct comedi_device * dev, DPRINTK("Tor Counter selection is wrong\n"); i_ReturnValue = -4; - } // if (b_TorCounterMode >= 0 && b_TorCounterMode <= 7) + } /* if (b_TorCounterMode >= 0 && b_TorCounterMode <= 7) */ } else { /******************************************/ /* The module is not a tor counter module */ @@ -857,20 +857,20 @@ INT i_APCI1710_InsnConfigInitTorCounter(struct comedi_device * dev, DPRINTK("Module number error\n"); i_ReturnValue = -2; } - data[0] = (UINT) ul_RealTimingInterval; - return (i_ReturnValue); + data[0] = (unsigned int) ul_RealTimingInterval; + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_EnableTorCounter | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr, | -| BYTE_ b_TorCounter, | -| BYTE_ b_InputMode, | -| BYTE_ b_ExternGate, | -| BYTE_ b_CycleMode, | -| BYTE_ b_InterruptEnable) | +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr, | +| unsigned char_ b_TorCounter, | +| unsigned char_ b_InputMode, | +| unsigned char_ b_ExternGate, | +| unsigned char_ b_CycleMode, | +| unsigned char_ b_InterruptEnable) | +----------------------------------------------------------------------------+ | Task : Enable the tor counter (b_TorCounter) from selected | | module (b_ModulNbr). You must calling the | @@ -883,13 +883,13 @@ INT i_APCI1710_InsnConfigInitTorCounter(struct comedi_device * dev, | The b_CycleMode parameter determine if you will | | measured a single or more cycle. | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | -| BYTE_ b_ModulNbr : Selected module number (0 to 3) | -| BYTE_ b_TorCounter : Tor counter selection (0 or 1). | -| BYTE_ b_InputMode : Input signal level selection | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | +| unsigned char_ b_ModulNbr : Selected module number (0 to 3) | +| unsigned char_ b_TorCounter : Tor counter selection (0 or 1). | +| unsigned char_ b_InputMode : Input signal level selection | | 0 : Tor count each low level | | 1 : Tor count each high level| -| BYTE_ b_ExternGate : Extern gate action selection | +| unsigned char_ b_ExternGate : Extern gate action selection | | 0 : Extern gate signal not | | used | | 1 : Extern gate signal used. | @@ -928,9 +928,9 @@ INT i_APCI1710_InsnConfigInitTorCounter(struct comedi_device * dev, | The gate input is used for the | | signal B | | | -| BYTE_ b_CycleMode : Selected the tor counter | +| unsigned char_ b_CycleMode : Selected the tor counter | | acquisition mode | -| BYTE_ b_InterruptEnable : Enable or disable the | +| unsigned char_ b_InterruptEnable : Enable or disable the | | tor counter interrupt. | | APCI1710_ENABLE: | | Enable the tor counter | @@ -959,9 +959,9 @@ INT i_APCI1710_InsnConfigInitTorCounter(struct comedi_device * dev, /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_DisableTorCounter | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr, | -| BYTE_ b_TorCounter) | +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr, | +| unsigned char_ b_TorCounter) | +----------------------------------------------------------------------------+ | Task : Disable the tor counter (b_TorCounter) from selected | | module (b_ModulNbr). If you disable the tor counter | @@ -969,9 +969,9 @@ INT i_APCI1710_InsnConfigInitTorCounter(struct comedi_device * dev, | counter witch the " i_APCI1710_EnableTorCounter" | | function, the status register is cleared | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | -| BYTE_ b_ModulNbr : Selected module number (0 to 3) | -| BYTE_ b_TorCounter : Tor counter selection (0 or 1). | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | +| unsigned char_ b_ModulNbr : Selected module number (0 to 3) | +| unsigned char_ b_TorCounter : Tor counter selection (0 or 1). | +----------------------------------------------------------------------------+ | Output Parameters : - | +----------------------------------------------------------------------------+ @@ -987,29 +987,29 @@ INT i_APCI1710_InsnConfigInitTorCounter(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -INT i_APCI1710_InsnWriteEnableDisableTorCounter(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +int i_APCI1710_InsnWriteEnableDisableTorCounter(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - INT i_ReturnValue = 0; - DWORD dw_Status; - DWORD dw_DummyRead; - DWORD dw_ConfigReg; - BYTE b_ModulNbr, b_Action; - BYTE b_TorCounter; - BYTE b_InputMode; - BYTE b_ExternGate; - BYTE b_CycleMode; - BYTE b_InterruptEnable; + int i_ReturnValue = 0; + unsigned int dw_Status; + unsigned int dw_DummyRead; + unsigned int dw_ConfigReg; + unsigned char b_ModulNbr, b_Action; + unsigned char b_TorCounter; + unsigned char b_InputMode; + unsigned char b_ExternGate; + unsigned char b_CycleMode; + unsigned char b_InterruptEnable; - b_ModulNbr = (BYTE) CR_AREF(insn->chanspec); - b_Action = (BYTE) data[0]; // enable or disable - b_TorCounter = (BYTE) data[1]; - b_InputMode = (BYTE) data[2]; - b_ExternGate = (BYTE) data[3]; - b_CycleMode = (BYTE) data[4]; - b_InterruptEnable = (BYTE) data[5]; + b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); + b_Action = (unsigned char) data[0]; /* enable or disable */ + b_TorCounter = (unsigned char) data[1]; + b_InputMode = (unsigned char) data[2]; + b_ExternGate = (unsigned char) data[3]; + b_CycleMode = (unsigned char) data[4]; + b_InterruptEnable = (unsigned char) data[5]; i_ReturnValue = insn->n;; - devpriv->tsk_Current = current; // Save the current process task structure + devpriv->tsk_Current = current; /* Save the current process task structure */ /**************************/ /* Test the module number */ /**************************/ @@ -1027,7 +1027,7 @@ INT i_APCI1710_InsnWriteEnableDisableTorCounter(struct comedi_device * dev, /**********************************/ if (b_TorCounter <= 1) { - switch (b_Action) // Enable or Disable + switch (b_Action) /* Enable or Disable */ { case APCI1710_ENABLE: /***********************************/ @@ -1149,7 +1149,7 @@ INT i_APCI1710_InsnWriteEnableDisableTorCounter(struct comedi_device * dev, | 0x780; - } // if (b_InputMode == APCI1710_TOR_SIMPLE_MODE) + } /* if (b_InputMode == APCI1710_TOR_SIMPLE_MODE) */ /***********************/ /* Test if double mode */ @@ -1166,12 +1166,12 @@ INT i_APCI1710_InsnWriteEnableDisableTorCounter(struct comedi_device * dev, | 0x180; - } // if (b_InputMode == APCI1710_TOR_DOUBLE_MODE) + } /* if (b_InputMode == APCI1710_TOR_DOUBLE_MODE) */ b_InputMode = 0; - } // if (b_InputMode > 1) + } /* if (b_InputMode > 1) */ /*******************/ /* Set the command */ @@ -1237,7 +1237,7 @@ INT i_APCI1710_InsnWriteEnableDisableTorCounter(struct comedi_device * dev, outl(1, devpriv->s_BoardInfos.ui_Address + 8 + (16 * b_TorCounter) + (64 * b_ModulNbr)); - } // if ((b_InterruptEnable == APCI1710_ENABLE) || (b_InterruptEnable == APCI1710_DISABLE)) + } /* if ((b_InterruptEnable == APCI1710_ENABLE) || (b_InterruptEnable == APCI1710_DISABLE)) */ else { /********************************/ /* Interrupt parameter is wrong */ @@ -1247,8 +1247,8 @@ INT i_APCI1710_InsnWriteEnableDisableTorCounter(struct comedi_device * dev, i_ReturnValue = -9; - } // if ((b_InterruptEnable == APCI1710_ENABLE) || (b_InterruptEnable == APCI1710_DISABLE)) - } // if ((b_CycleMode == APCI1710_SINGLE) || (b_CycleMode == APCI1710_CONTINUOUS)) + } /* if ((b_InterruptEnable == APCI1710_ENABLE) || (b_InterruptEnable == APCI1710_DISABLE)) */ + } /* if ((b_CycleMode == APCI1710_SINGLE) || (b_CycleMode == APCI1710_CONTINUOUS)) */ else { /***********************************************/ /* Tor counter acquisition mode cycle is wrong */ @@ -1258,8 +1258,8 @@ INT i_APCI1710_InsnWriteEnableDisableTorCounter(struct comedi_device * dev, i_ReturnValue = -8; - } // if ((b_CycleMode == APCI1710_SINGLE) || (b_CycleMode == APCI1710_CONTINUOUS)) - } // if (b_ExternGate >= 0 && b_ExternGate <= 1) + } /* if ((b_CycleMode == APCI1710_SINGLE) || (b_CycleMode == APCI1710_CONTINUOUS)) */ + } /* if (b_ExternGate >= 0 && b_ExternGate <= 1) */ else { /***********************************/ /* Extern gate input mode is wrong */ @@ -1268,8 +1268,8 @@ INT i_APCI1710_InsnWriteEnableDisableTorCounter(struct comedi_device * dev, DPRINTK("Extern gate input mode is wrong\n"); i_ReturnValue = -7; - } // if (b_ExternGate >= 0 && b_ExternGate <= 1) - } // if (b_InputMode >= 0 && b_InputMode <= 1) + } /* if (b_ExternGate >= 0 && b_ExternGate <= 1) */ + } /* if (b_InputMode >= 0 && b_InputMode <= 1) */ else { /***************************************/ /* Tor input signal selection is wrong */ @@ -1329,7 +1329,7 @@ INT i_APCI1710_InsnWriteEnableDisableTorCounter(struct comedi_device * dev, s_BoardInfos. ui_Address + 8 + (16 * b_TorCounter) + (64 * b_ModulNbr)); - } // if (dw_Status & 0x1) + } /* if (dw_Status & 0x1) */ else { /***************************/ /* Tor counter not enabled */ @@ -1337,8 +1337,8 @@ INT i_APCI1710_InsnWriteEnableDisableTorCounter(struct comedi_device * dev, DPRINTK("Tor counter not enabled \n"); i_ReturnValue = -6; - } // if (dw_Status & 0x1) - } // if (dw_Status & 0x10) + } /* if (dw_Status & 0x1) */ + } /* if (dw_Status & 0x10) */ else { /*******************************/ /* Tor counter not initialised */ @@ -1346,10 +1346,10 @@ INT i_APCI1710_InsnWriteEnableDisableTorCounter(struct comedi_device * dev, DPRINTK("Tor counter not initialised\n"); i_ReturnValue = -5; - } // // if (dw_Status & 0x10) + } /* // if (dw_Status & 0x10) */ - } // switch - } // if (b_TorCounter <= 1) + } /* switch */ + } /* if (b_TorCounter <= 1) */ else { /**********************************/ /* Tor counter selection is wrong */ @@ -1357,7 +1357,7 @@ INT i_APCI1710_InsnWriteEnableDisableTorCounter(struct comedi_device * dev, DPRINTK("Tor counter selection is wrong\n"); i_ReturnValue = -4; - } // if (b_TorCounter <= 1) + } /* if (b_TorCounter <= 1) */ } else { /******************************************/ /* The module is not a tor counter module */ @@ -1375,22 +1375,22 @@ INT i_APCI1710_InsnWriteEnableDisableTorCounter(struct comedi_device * dev, i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_GetTorCounterInitialisation | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr, | -| BYTE_ b_TorCounter, | -| PBYTE_ pb_TimingUnit, | +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr, | +| unsigned char_ b_TorCounter, | +| unsigned char *_ pb_TimingUnit, | | PULONG_ pul_TimingInterval, | -| PBYTE_ pb_InputMode, | -| PBYTE_ pb_ExternGate, | -| PBYTE_ pb_CycleMode, | -| PBYTE_ pb_Enable, | -| PBYTE_ pb_InterruptEnable)| +| unsigned char *_ pb_InputMode, | +| unsigned char *_ pb_ExternGate, | +| unsigned char *_ pb_CycleMode, | +| unsigned char *_ pb_Enable, | +| unsigned char *_ pb_InterruptEnable)| +----------------------------------------------------------------------------+ | Task : Enable the tor counter (b_TorCounter) from selected | | module (b_ModulNbr). You must calling the | @@ -1403,37 +1403,37 @@ INT i_APCI1710_InsnWriteEnableDisableTorCounter(struct comedi_device * dev, | The b_CycleMode parameter determine if you will | | measured a single or more cycle. | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | -| BYTE_ b_ModulNbr : Selected module number (0 to 3) | -| BYTE_ b_TorCounter : Tor counter selection (0 or 1) +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | +| unsigned char_ b_ModulNbr : Selected module number (0 to 3) | +| unsigned char_ b_TorCounter : Tor counter selection (0 or 1) b_ModulNbr = CR_AREF(insn->chanspec); b_TorCounter = CR_CHAN(insn->chanspec); . | +----------------------------------------------------------------------------+ -| Output Parameters : PBYTE_ pb_TimingUnit : Base timing unit (0 to 4) | +| Output Parameters : unsigned char *_ pb_TimingUnit : Base timing unit (0 to 4) | | 0 : ns | | 1 : µs | | 2 : ms | | 3 : s | | 4 : mn | | PULONG_ pul_TimingInterval : Base timing value. | -| PBYTE_ pb_InputMode : Input signal level | +| unsigned char *_ pb_InputMode : Input signal level | | selection | | 0 : Tor count each low level | | 1 : Tor count each high level| -| PBYTE_ pb_ExternGate : Extern gate action | +| unsigned char *_ pb_ExternGate : Extern gate action | | selection | | 0 : Extern gate signal not | | used | | 1 : Extern gate signal used| -| PBYTE_ pb_CycleMode : Tor counter acquisition | +| unsigned char *_ pb_CycleMode : Tor counter acquisition | | mode | -| PBYTE_ pb_Enable : Indicate if the tor counter| +| unsigned char *_ pb_Enable : Indicate if the tor counter| | is enabled or no | | 0 : Tor counter disabled | | 1 : Tor counter enabled | -| PBYTE_ pb_InterruptEnable : Enable or disable the | +| unsigned char *_ pb_InterruptEnable : Enable or disable the | | tor counter interrupt. | | APCI1710_ENABLE: | | Enable the tor counter | @@ -1441,13 +1441,13 @@ INT i_APCI1710_InsnWriteEnableDisableTorCounter(struct comedi_device * dev, | APCI1710_DISABLE: | | Disable the tor counter | | interrupt - pb_TimingUnit = (PBYTE) &data[0]; - pul_TimingInterval = (PULONG) &data[1]; - pb_InputMode = (PBYTE) &data[2]; - pb_ExternGate = (PBYTE) &data[3]; - pb_CycleMode = (PBYTE) &data[4]; - pb_Enable = (PBYTE) &data[5]; - pb_InterruptEnable = (PBYTE) &data[6]; + pb_TimingUnit = (unsigned char *) &data[0]; + pul_TimingInterval = (unsigned int *) &data[1]; + pb_InputMode = (unsigned char *) &data[2]; + pb_ExternGate = (unsigned char *) &data[3]; + pb_CycleMode = (unsigned char *) &data[4]; + pb_Enable = (unsigned char *) &data[5]; + pb_InterruptEnable = (unsigned char *) &data[6]; | +----------------------------------------------------------------------------+ | Return Value : 0: No error | @@ -1460,32 +1460,32 @@ INT i_APCI1710_InsnWriteEnableDisableTorCounter(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -INT i_APCI1710_InsnReadGetTorCounterInitialisation(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +int i_APCI1710_InsnReadGetTorCounterInitialisation(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - INT i_ReturnValue = 0; - DWORD dw_Status; - BYTE b_ModulNbr; - BYTE b_TorCounter; - PBYTE pb_TimingUnit; - PULONG pul_TimingInterval; - PBYTE pb_InputMode; - PBYTE pb_ExternGate; - PBYTE pb_CycleMode; - PBYTE pb_Enable; - PBYTE pb_InterruptEnable; + int i_ReturnValue = 0; + unsigned int dw_Status; + unsigned char b_ModulNbr; + unsigned char b_TorCounter; + unsigned char *pb_TimingUnit; + unsigned int *pul_TimingInterval; + unsigned char *pb_InputMode; + unsigned char *pb_ExternGate; + unsigned char *pb_CycleMode; + unsigned char *pb_Enable; + unsigned char *pb_InterruptEnable; i_ReturnValue = insn->n; b_ModulNbr = CR_AREF(insn->chanspec); b_TorCounter = CR_CHAN(insn->chanspec); - pb_TimingUnit = (PBYTE) & data[0]; - pul_TimingInterval = (PULONG) & data[1]; - pb_InputMode = (PBYTE) & data[2]; - pb_ExternGate = (PBYTE) & data[3]; - pb_CycleMode = (PBYTE) & data[4]; - pb_Enable = (PBYTE) & data[5]; - pb_InterruptEnable = (PBYTE) & data[6]; + pb_TimingUnit = (unsigned char *) &data[0]; + pul_TimingInterval = (unsigned int *) &data[1]; + pb_InputMode = (unsigned char *) &data[2]; + pb_ExternGate = (unsigned char *) &data[3]; + pb_CycleMode = (unsigned char *) &data[4]; + pb_Enable = (unsigned char *) &data[5]; + pb_InterruptEnable = (unsigned char *) &data[6]; /**************************/ /* Test the module number */ @@ -1526,9 +1526,9 @@ INT i_APCI1710_InsnReadGetTorCounterInitialisation(struct comedi_device * dev, (64 * b_ModulNbr)); *pb_CycleMode = - (BYTE) ((dw_Status >> 4) & 1); + (unsigned char) ((dw_Status >> 4) & 1); *pb_InterruptEnable = - (BYTE) ((dw_Status >> 5) & 1); + (unsigned char) ((dw_Status >> 5) & 1); /******************************************************/ /* Test if extern gate used for clock or for signal B */ @@ -1569,25 +1569,25 @@ INT i_APCI1710_InsnReadGetTorCounterInitialisation(struct comedi_device * dev, *pb_InputMode = APCI1710_TOR_QUADRUPLE_MODE; } - } // if (dw_Status & 0x400) + } /* if (dw_Status & 0x400) */ else { *pb_InputMode = 1; - } // // if (dw_Status & 0x400) + } /* // if (dw_Status & 0x400) */ /************************/ /* Extern gate not used */ /************************/ *pb_ExternGate = 0; - } // if (dw_Status & 0x600) + } /* if (dw_Status & 0x600) */ else { *pb_InputMode = - (BYTE) ((dw_Status >> 6) + (unsigned char) ((dw_Status >> 6) & 1); *pb_ExternGate = - (BYTE) ((dw_Status >> 7) + (unsigned char) ((dw_Status >> 7) & 1); - } // if (dw_Status & 0x600) + } /* if (dw_Status & 0x600) */ *pb_TimingUnit = devpriv-> @@ -1611,7 +1611,7 @@ INT i_APCI1710_InsnReadGetTorCounterInitialisation(struct comedi_device * dev, i_ReturnValue = -5; } - } // if (b_TorCounter <= 1) + } /* if (b_TorCounter <= 1) */ else { /**********************************/ /* Tor counter selection is wrong */ @@ -1619,7 +1619,7 @@ INT i_APCI1710_InsnReadGetTorCounterInitialisation(struct comedi_device * dev, DPRINTK("Tor counter selection is wrong \n"); i_ReturnValue = -4; - } // if (b_TorCounter <= 1) + } /* if (b_TorCounter <= 1) */ } else { /******************************************/ /* The module is not a tor counter module */ @@ -1637,17 +1637,17 @@ INT i_APCI1710_InsnReadGetTorCounterInitialisation(struct comedi_device * dev, i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_ReadTorCounterValue | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr, | -| BYTE_ b_TorCounter, | -| UINT_ ui_TimeOut, | -| PBYTE_ pb_TorCounterStatus, | +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr, | +| unsigned char_ b_TorCounter, | +| unsigned int_ ui_TimeOut, | +| unsigned char *_ pb_TorCounterStatus, | | PULONG_ pul_TorCounterValue) | +----------------------------------------------------------------------------+ | Task case APCI1710_TOR_GETPROGRESSSTATUS: Return the tor counter @@ -1660,15 +1660,15 @@ INT i_APCI1710_InsnReadGetTorCounterInitialisation(struct comedi_device * dev, | (pul_TorCounterValue) after a conting cycle stop | | from selected tor counter module (b_ModulNbr). | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | -| BYTE_ b_ModulNbr : Selected module number (0 to 3) | -| BYTE_ b_TorCounter : Tor counter selection (0 or 1). +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | +| unsigned char_ b_ModulNbr : Selected module number (0 to 3) | +| unsigned char_ b_TorCounter : Tor counter selection (0 or 1). b_ModulNbr = CR_AREF(insn->chanspec); - b_ReadType = (BYTE) data[0]; - b_TorCounter = (BYTE) data[1]; - ui_TimeOut = (UINT) data[2]; | + b_ReadType = (unsigned char) data[0]; + b_TorCounter = (unsigned char) data[1]; + ui_TimeOut = (unsigned int) data[2]; | +----------------------------------------------------------------------------+ -| Output Parameters : PBYTE_ pb_TorCounterStatus : Return the tor counter | +| Output Parameters : unsigned char *_ pb_TorCounterStatus : Return the tor counter | | status. | | 0 : Conting cycle not started| | Software gate not set. | @@ -1683,9 +1683,9 @@ INT i_APCI1710_InsnReadGetTorCounterInitialisation(struct comedi_device * dev, | function | | "i_APCI1710_InitTorCounter"| | 4 : Timeeout occur | -| PULONG pul_TorCounterValue : Tor counter value. - pb_TorCounterStatus=(PBYTE) &data[0]; - pul_TorCounterValue=(PULONG) &data[1]; | +| unsigned int * pul_TorCounterValue : Tor counter value. + pb_TorCounterStatus=(unsigned char *) &data[0]; + pul_TorCounterValue=(unsigned int *) &data[1]; | +----------------------------------------------------------------------------+ | Return Value : 0: No error | | -1: The handle parameter of the board is wrong | @@ -1700,27 +1700,27 @@ INT i_APCI1710_InsnReadGetTorCounterInitialisation(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -INT i_APCI1710_InsnBitsGetTorCounterProgressStatusAndValue(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +int i_APCI1710_InsnBitsGetTorCounterProgressStatusAndValue(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - INT i_ReturnValue = 0; - DWORD dw_Status; - DWORD dw_TimeOut = 0; + int i_ReturnValue = 0; + unsigned int dw_Status; + unsigned int dw_TimeOut = 0; - BYTE b_ModulNbr; - BYTE b_TorCounter; - BYTE b_ReadType; - UINT ui_TimeOut; - PBYTE pb_TorCounterStatus; - PULONG pul_TorCounterValue; + unsigned char b_ModulNbr; + unsigned char b_TorCounter; + unsigned char b_ReadType; + unsigned int ui_TimeOut; + unsigned char *pb_TorCounterStatus; + unsigned int *pul_TorCounterValue; i_ReturnValue = insn->n; b_ModulNbr = CR_AREF(insn->chanspec); - b_ReadType = (BYTE) data[0]; - b_TorCounter = (BYTE) data[1]; - ui_TimeOut = (UINT) data[2]; - pb_TorCounterStatus = (PBYTE) & data[0]; - pul_TorCounterValue = (PULONG) & data[1]; + b_ReadType = (unsigned char) data[0]; + b_TorCounter = (unsigned char) data[1]; + ui_TimeOut = (unsigned int) data[2]; + pb_TorCounterStatus = (unsigned char *) &data[0]; + pul_TorCounterValue = (unsigned int *) &data[1]; /**************************/ /* Test the module number */ @@ -1896,7 +1896,7 @@ INT i_APCI1710_InsnBitsGetTorCounterProgressStatusAndValue(struct comedi_device + (16 * b_TorCounter) + (64 * b_ModulNbr)); break; - } // if ((dw_Status & 4) == 4) + } /* if ((dw_Status & 4) == 4) */ else { /*******************************/ /* Test if measurement stopped */ @@ -1927,7 +1927,7 @@ INT i_APCI1710_InsnBitsGetTorCounterProgressStatusAndValue(struct comedi_device (16 * b_TorCounter) + (64 * b_ModulNbr)); break; - } // if ((dw_Status & 2) == 2) + } /* if ((dw_Status & 2) == 2) */ else { /*******************************/ /* Test if measurement started */ @@ -1941,7 +1941,7 @@ INT i_APCI1710_InsnBitsGetTorCounterProgressStatusAndValue(struct comedi_device *pb_TorCounterStatus = 1; - } // if ((dw_Status & 1) == 1) + } /* if ((dw_Status & 1) == 1) */ else { /***************************/ /* Measurement not started */ @@ -1950,9 +1950,9 @@ INT i_APCI1710_InsnBitsGetTorCounterProgressStatusAndValue(struct comedi_device *pb_TorCounterStatus = 0; - } // if ((dw_Status & 1) == 1) - } // if ((dw_Status & 2) == 2) - } // if ((dw_Status & 8) == 8) + } /* if ((dw_Status & 1) == 1) */ + } /* if ((dw_Status & 2) == 2) */ + } /* if ((dw_Status & 8) == 8) */ if (dw_TimeOut == ui_TimeOut) { /*****************/ @@ -1973,7 +1973,7 @@ INT i_APCI1710_InsnBitsGetTorCounterProgressStatusAndValue(struct comedi_device mdelay(1000); } - } // for (;;) + } /* for (;;) */ /*************************/ /* Test if timeout occur */ @@ -2001,8 +2001,8 @@ INT i_APCI1710_InsnBitsGetTorCounterProgressStatusAndValue(struct comedi_device default: printk("Inputs wrong\n"); - } // switch end - } // if (dw_Status & 0x1) + } /* switch end */ + } /* if (dw_Status & 0x1) */ else { /***************************/ /* Tor counter not enabled */ @@ -2010,7 +2010,7 @@ INT i_APCI1710_InsnBitsGetTorCounterProgressStatusAndValue(struct comedi_device DPRINTK("Tor counter not enabled\n"); i_ReturnValue = -6; - } // if (dw_Status & 0x1) + } /* if (dw_Status & 0x1) */ } else { /*******************************/ /* Tor counter not initialised */ @@ -2019,7 +2019,7 @@ INT i_APCI1710_InsnBitsGetTorCounterProgressStatusAndValue(struct comedi_device DPRINTK("Tor counter not initialised\n"); i_ReturnValue = -5; } - } // if (b_TorCounter <= 1) + } /* if (b_TorCounter <= 1) */ else { /**********************************/ /* Tor counter selection is wrong */ @@ -2027,7 +2027,7 @@ INT i_APCI1710_InsnBitsGetTorCounterProgressStatusAndValue(struct comedi_device DPRINTK("Tor counter selection is wrong\n"); i_ReturnValue = -4; - } // if (b_TorCounter <= 1) + } /* if (b_TorCounter <= 1) */ } else { /******************************************/ /* The module is not a tor counter module */ @@ -2045,5 +2045,5 @@ INT i_APCI1710_InsnBitsGetTorCounterProgressStatusAndValue(struct comedi_device i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Tor.h b/drivers/staging/comedi/drivers/addi-data/APCI1710_Tor.h index c245d16207b8..03a93cb26d7a 100644 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Tor.h +++ b/drivers/staging/comedi/drivers/addi-data/APCI1710_Tor.h @@ -35,23 +35,23 @@ /* * TOR_COUNTER INISIALISATION FUNCTION */ -INT i_APCI1710_InsnConfigInitTorCounter(struct comedi_device *dev, +int i_APCI1710_InsnConfigInitTorCounter(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -INT i_APCI1710_InsnWriteEnableDisableTorCounter(struct comedi_device *dev, +int i_APCI1710_InsnWriteEnableDisableTorCounter(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -INT i_APCI1710_InsnReadGetTorCounterInitialisation(struct comedi_device *dev, +int i_APCI1710_InsnReadGetTorCounterInitialisation(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); /* * TOR_COUNTER READ FUNCTION */ -INT i_APCI1710_InsnBitsGetTorCounterProgressStatusAndValue(struct comedi_device *dev, +int i_APCI1710_InsnBitsGetTorCounterProgressStatusAndValue(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Ttl.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_Ttl.c index 68b1d26bae13..d3d78d37de5c 100644 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Ttl.c +++ b/drivers/staging/comedi/drivers/addi-data/APCI1710_Ttl.c @@ -3,13 +3,13 @@ Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data-com - info@addi-data.com + ADDI-DATA GmbH + Dieselstrasse 3 + D-77833 Ottersweier + Tel: +19(0)7223/9493-0 + Fax: +49(0)7223/9493-92 + http://www.addi-data-com + info@addi-data.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. @@ -63,12 +63,12 @@ You shoud also find the complete GPL in the COPYING file accompanying this sourc /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_InitTTLIODirection | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr, | -| BYTE_ b_PortAMode, | -| BYTE_ b_PortBMode, | -| BYTE_ b_PortCMode, | -| BYTE_ b_PortDMode) | +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr, | +| unsigned char_ b_PortAMode, | +| unsigned char_ b_PortBMode, | +| unsigned char_ b_PortCMode, | +| unsigned char_ b_PortDMode) | +----------------------------------------------------------------------------+ | Task APCI1710_TTL_INIT (using defaults) : Configure the TTL I/O operating mode from selected | | module (b_ModulNbr). You must calling this function be| @@ -76,15 +76,15 @@ You shoud also find the complete GPL in the COPYING file accompanying this sourc APCI1710_TTL_INITDIRECTION(user inputs for direction) +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710| -| BYTE_ b_ModulNbr : Module number to | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710| +| unsigned char_ b_ModulNbr : Module number to | | configure (0 to 3) - b_ModulNbr = (BYTE) CR_AREF(insn->chanspec); - b_InitType = (BYTE) data[0]; - b_PortAMode = (BYTE) data[1]; - b_PortBMode = (BYTE) data[2]; - b_PortCMode = (BYTE) data[3]; - b_PortDMode = (BYTE) data[4];| + b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); + b_InitType = (unsigned char) data[0]; + b_PortAMode = (unsigned char) data[1]; + b_PortBMode = (unsigned char) data[2]; + b_PortCMode = (unsigned char) data[3]; + b_PortDMode = (unsigned char) data[4];| +----------------------------------------------------------------------------+ | Output Parameters : - | +----------------------------------------------------------------------------+ @@ -100,19 +100,19 @@ You shoud also find the complete GPL in the COPYING file accompanying this sourc +----------------------------------------------------------------------------+ */ -INT i_APCI1710_InsnConfigInitTTLIO(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI1710_InsnConfigInitTTLIO(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - INT i_ReturnValue = 0; - BYTE b_ModulNbr; - BYTE b_InitType; - BYTE b_PortAMode; - BYTE b_PortBMode; - BYTE b_PortCMode; - BYTE b_PortDMode; + int i_ReturnValue = 0; + unsigned char b_ModulNbr; + unsigned char b_InitType; + unsigned char b_PortAMode; + unsigned char b_PortBMode; + unsigned char b_PortCMode; + unsigned char b_PortDMode; - b_ModulNbr = (BYTE) CR_AREF(insn->chanspec); - b_InitType = (BYTE) data[0]; + b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); + b_InitType = (unsigned char) data[0]; i_ReturnValue = insn->n; /**************************/ @@ -172,10 +172,10 @@ INT i_APCI1710_InsnConfigInitTTLIO(struct comedi_device * dev, struct comedi_sub case APCI1710_TTL_INITDIRECTION: - b_PortAMode = (BYTE) data[1]; - b_PortBMode = (BYTE) data[2]; - b_PortCMode = (BYTE) data[3]; - b_PortDMode = (BYTE) data[4]; + b_PortAMode = (unsigned char) data[1]; + b_PortBMode = (unsigned char) data[2]; + b_PortCMode = (unsigned char) data[3]; + b_PortDMode = (unsigned char) data[4]; /********************/ /* Test the version */ @@ -322,7 +322,7 @@ INT i_APCI1710_InsnConfigInitTTLIO(struct comedi_device * dev, struct comedi_sub DPRINTK("\n"); default: printk("Bad Config Type\n"); - } // switch end + } /* switch end */ } else { /**********************************/ /* The module is not a TTL module */ @@ -340,7 +340,7 @@ INT i_APCI1710_InsnConfigInitTTLIO(struct comedi_device * dev, struct comedi_sub i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* @@ -352,11 +352,11 @@ INT i_APCI1710_InsnConfigInitTTLIO(struct comedi_device * dev, struct comedi_sub /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_ReadTTLIOChannelValue | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr, | -| BYTE_ b_SelectedPort, | -| BYTE_ b_InputChannel, | -| PBYTE_ pb_ChannelStatus) | +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr, | +| unsigned char_ b_SelectedPort, | +| unsigned char_ b_InputChannel, | +| unsigned char *_ pb_ChannelStatus) | +----------------------------------------------------------------------------+ | Task : Read the status from selected TTL digital input | | (b_InputChannel) @@ -366,32 +366,32 @@ INT i_APCI1710_InsnConfigInitTTLIO(struct comedi_device * dev, struct comedi_sub +----------------------------------------------------------------------------+ +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710| -| BYTE_ b_ModulNbr : Module number to | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710| +| unsigned char_ b_ModulNbr : Module number to | | configure (0 to 7) | -| BYTE_ b_SelectedPort, : Selection from TTL I/O | +| unsigned char_ b_SelectedPort, : Selection from TTL I/O | | port (0 to 2) | | 0 : Port A selection | | 1 : Port B selection | | 2 : Port C selection | | 3 : Port D selection | -| BYTE_ b_InputChannel : Selection from digital | +| unsigned char_ b_InputChannel : Selection from digital | | input ( 0 to 2) APCI1710_TTL_READCHANNEL b_ModulNbr = CR_AREF(insn->chanspec); b_SelectedPort= CR_RANGE(insn->chanspec); b_InputChannel= CR_CHAN(insn->chanspec); - b_ReadType = (BYTE) data[0]; + b_ReadType = (unsigned char) data[0]; APCI1710_TTL_READPORT| b_ModulNbr = CR_AREF(insn->chanspec); b_SelectedPort= CR_RANGE(insn->chanspec); - b_ReadType = (BYTE) data[0]; + b_ReadType = (unsigned char) data[0]; +----------------------------------------------------------------------------+ | Output Parameters : data[0] - PBYTE_ pb_ChannelStatus : Digital input channel | + unsigned char *_ pb_ChannelStatus : Digital input channel | | status | | 0 : Channle is not active| | 1 : Channle is active | @@ -406,20 +406,20 @@ APCI1710_TTL_READCHANNEL +----------------------------------------------------------------------------+ */ -INT i_APCI1710_InsnBitsReadTTLIO(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI1710_InsnBitsReadTTLIO(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - INT i_ReturnValue = 0; - DWORD dw_StatusReg; - BYTE b_ModulNbr; - BYTE b_SelectedPort; - BYTE b_InputChannel; - BYTE b_ReadType; - PBYTE pb_ChannelStatus; - PBYTE pb_PortValue; + int i_ReturnValue = 0; + unsigned int dw_StatusReg; + unsigned char b_ModulNbr; + unsigned char b_SelectedPort; + unsigned char b_InputChannel; + unsigned char b_ReadType; + unsigned char *pb_ChannelStatus; + unsigned char *pb_PortValue; i_ReturnValue = insn->n; - b_ReadType = (BYTE) data[0]; + b_ReadType = (unsigned char) data[0]; b_ModulNbr = CR_AREF(insn->chanspec); b_SelectedPort = CR_RANGE(insn->chanspec); b_InputChannel = CR_CHAN(insn->chanspec); @@ -439,7 +439,7 @@ INT i_APCI1710_InsnBitsReadTTLIO(struct comedi_device * dev, struct comedi_subde switch (b_ReadType) { case APCI1710_TTL_READCHANNEL: - pb_ChannelStatus = (PBYTE) & data[0]; + pb_ChannelStatus = (unsigned char *) &data[0]; /********************************/ /* Test the TTL I/O port number */ /********************************/ @@ -493,7 +493,7 @@ INT i_APCI1710_InsnBitsReadTTLIO(struct comedi_device * dev, struct comedi_subde *pb_ChannelStatus = - (BYTE) ( + (unsigned char) ( (dw_StatusReg >> (8 * b_SelectedPort)) >> b_InputChannel) & 1; @@ -533,7 +533,7 @@ INT i_APCI1710_InsnBitsReadTTLIO(struct comedi_device * dev, struct comedi_subde break; case APCI1710_TTL_READPORT: - pb_PortValue = (PBYTE) & data[0]; + pb_PortValue = (unsigned char *) &data[0]; /********************************/ /* Test the TTL I/O port number */ /********************************/ @@ -578,7 +578,7 @@ INT i_APCI1710_InsnBitsReadTTLIO(struct comedi_device * dev, struct comedi_subde (64 * b_ModulNbr)); *pb_PortValue = - (BYTE) ( + (unsigned char) ( (dw_StatusReg >> (8 * b_SelectedPort)) & 0xFF); } else { @@ -610,7 +610,7 @@ INT i_APCI1710_InsnBitsReadTTLIO(struct comedi_device * dev, struct comedi_subde default: printk("Bad ReadType\n"); - } //End Switch + } /* End Switch */ } else { /**********************************/ /* The module is not a TTL module */ @@ -628,20 +628,20 @@ INT i_APCI1710_InsnBitsReadTTLIO(struct comedi_device * dev, struct comedi_subde i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ -| Function Name : INT i_APCI1710_InsnReadTTLIOAllPortValue(comedi_device +| Function Name : int i_APCI1710_InsnReadTTLIOAllPortValue(comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) | +----------------------------------------------------------------------------+ | Task : Read the status from all digital input ports | | (port A, port B and port C) from selected TTL | | module (b_ModulNbr) | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710| -| BYTE_ b_ModulNbr : Module number to | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710| +| unsigned char_ b_ModulNbr : Module number to | | configure (0 to 3) | +----------------------------------------------------------------------------+ | Output Parameters : PULONG_ pul_PortValue : Digital TTL inputs port | @@ -655,17 +655,17 @@ INT i_APCI1710_InsnBitsReadTTLIO(struct comedi_device * dev, struct comedi_subde +----------------------------------------------------------------------------+ */ -INT i_APCI1710_InsnReadTTLIOAllPortValue(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +int i_APCI1710_InsnReadTTLIOAllPortValue(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - INT i_ReturnValue = 0; - DWORD dw_StatusReg; - BYTE b_ModulNbr; - PULONG pul_PortValue; + int i_ReturnValue = 0; + unsigned int dw_StatusReg; + unsigned char b_ModulNbr; + unsigned int *pul_PortValue; - b_ModulNbr = (BYTE) CR_AREF(insn->chanspec); + b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); i_ReturnValue = insn->n; - pul_PortValue = (PULONG) & data[0]; + pul_PortValue = (unsigned int *) &data[0]; /**************************/ /* Test the module number */ @@ -777,7 +777,7 @@ INT i_APCI1710_InsnReadTTLIOAllPortValue(struct comedi_device * dev, i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } /* @@ -789,19 +789,19 @@ INT i_APCI1710_InsnReadTTLIOAllPortValue(struct comedi_device * dev, /* +----------------------------------------------------------------------------+ | Function Name : _INT_ i_APCI1710_SetTTLIOChlOn | -| (BYTE_ b_BoardHandle, | -| BYTE_ b_ModulNbr, | -| BYTE_ b_OutputChannel) -INT i_APCI1710_InsnWriteSetTTLIOChlOnOff(struct comedi_device *dev,struct comedi_subdevice *s, +| (unsigned char_ b_BoardHandle, | +| unsigned char_ b_ModulNbr, | +| unsigned char_ b_OutputChannel) +int i_APCI1710_InsnWriteSetTTLIOChlOnOff(struct comedi_device *dev,struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data) | +----------------------------------------------------------------------------+ | Task : Sets or resets the output witch has been passed with the | | parameter b_Channel. Setting an output means setting | | an ouput high. | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE_ b_BoardHandle : Handle of board APCI-1710 | -| BYTE_ b_ModulNbr : Selected module number (0 to 3)| -| BYTE_ b_OutputChannel : Selection from digital output | +| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | +| unsigned char_ b_ModulNbr : Selected module number (0 to 3)| +| unsigned char_ b_OutputChannel : Selection from digital output | | channel (0 or 1) | | 0 : PD0 | | 1 : PD1 | @@ -811,7 +811,7 @@ INT i_APCI1710_InsnWriteSetTTLIOChlOnOff(struct comedi_device *dev,struct comedi b_ModulNbr = CR_AREF(insn->chanspec); b_OutputChannel= CR_CHAN(insn->chanspec); - ui_State = data[0]; // ON or OFF + ui_State = data[0]; /* ON or OFF */ +----------------------------------------------------------------------------+ | Output Parameters : - | +----------------------------------------------------------------------------+ @@ -825,19 +825,19 @@ INT i_APCI1710_InsnWriteSetTTLIOChlOnOff(struct comedi_device *dev,struct comedi +----------------------------------------------------------------------------+ */ -INT i_APCI1710_InsnWriteSetTTLIOChlOnOff(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +int i_APCI1710_InsnWriteSetTTLIOChlOnOff(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - INT i_ReturnValue = 0; - DWORD dw_StatusReg = 0; - BYTE b_ModulNbr; - BYTE b_OutputChannel; - UINT ui_State; + int i_ReturnValue = 0; + unsigned int dw_StatusReg = 0; + unsigned char b_ModulNbr; + unsigned char b_OutputChannel; + unsigned int ui_State; i_ReturnValue = insn->n; b_ModulNbr = CR_AREF(insn->chanspec); b_OutputChannel = CR_CHAN(insn->chanspec); - ui_State = data[0]; // ON or OFF + ui_State = data[0]; /* ON or OFF */ /**************************/ /* Test the module number */ @@ -953,7 +953,7 @@ INT i_APCI1710_InsnWriteSetTTLIOChlOnOff(struct comedi_device * dev, ui_Address + (64 * b_ModulNbr)); - if (ui_State) // ON + if (ui_State) /* ON */ { dw_StatusReg = @@ -969,7 +969,7 @@ INT i_APCI1710_InsnWriteSetTTLIOChlOnOff(struct comedi_device * dev, (b_OutputChannel % 8)); - } else // Off + } else /* Off */ { dw_StatusReg = @@ -1034,5 +1034,5 @@ INT i_APCI1710_InsnWriteSetTTLIOChlOnOff(struct comedi_device * dev, i_ReturnValue = -2; } - return (i_ReturnValue); + return i_ReturnValue; } diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Ttl.h b/drivers/staging/comedi/drivers/addi-data/APCI1710_Ttl.h index 00915ddf9218..c4f11347f243 100644 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Ttl.h +++ b/drivers/staging/comedi/drivers/addi-data/APCI1710_Ttl.h @@ -24,21 +24,21 @@ /* * TTL INISIALISATION FUNCTION */ -INT i_APCI1710_InsnConfigInitTTLIO(struct comedi_device *dev, struct comedi_subdevice *s, +int i_APCI1710_InsnConfigInitTTLIO(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); /* * TTL INPUT FUNCTION */ -INT i_APCI1710_InsnBitsReadTTLIO(struct comedi_device *dev, struct comedi_subdevice *s, +int i_APCI1710_InsnBitsReadTTLIO(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -INT i_APCI1710_InsnReadTTLIOAllPortValue(struct comedi_device *dev, +int i_APCI1710_InsnReadTTLIOAllPortValue(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); /* * TTL OUTPUT FUNCTIONS */ -INT i_APCI1710_InsnWriteSetTTLIOChlOnOff(struct comedi_device *dev, +int i_APCI1710_InsnWriteSetTTLIOChlOnOff(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); diff --git a/drivers/staging/comedi/drivers/addi-data/addi_amcc_S5920.c b/drivers/staging/comedi/drivers/addi-data/addi_amcc_S5920.c index b0907ec14667..6e9e7ed4dba9 100644 --- a/drivers/staging/comedi/drivers/addi-data/addi_amcc_S5920.c +++ b/drivers/staging/comedi/drivers/addi-data/addi_amcc_S5920.c @@ -3,13 +3,13 @@ Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data-com - info@addi-data.com + ADDI-DATA GmbH + Dieselstrasse 3 + D-77833 Ottersweier + Tel: +19(0)7223/9493-0 + Fax: +49(0)7223/9493-92 + http://www.addi-data-com + info@addi-data.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. @@ -49,37 +49,37 @@ You shoud also find the complete GPL in the COPYING file accompanying this sourc #include "addi_amcc_S5920.h" /*+----------------------------------------------------------------------------+*/ -/*| Function Name : INT i_AddiHeaderRW_ReadEeprom |*/ -/*| (INT i_NbOfWordsToRead, |*/ -/*| DWORD dw_PCIBoardEepromAddress, |*/ -/*| WORD w_EepromStartAddress, |*/ -/*| PWORD pw_DataRead) |*/ +/*| Function Name : int i_AddiHeaderRW_ReadEeprom |*/ +/*| (int i_NbOfWordsToRead, |*/ +/*| unsigned int dw_PCIBoardEepromAddress, |*/ +/*| unsigned short w_EepromStartAddress, |*/ +/*| unsigned short * pw_DataRead) |*/ /*+----------------------------------------------------------------------------+*/ /*| Task : Read word from the 5920 eeprom. |*/ /*+----------------------------------------------------------------------------+*/ -/*| Input Parameters : INT i_NbOfWordsToRead : Nbr. of word to read |*/ -/*| DWORD dw_PCIBoardEepromAddress : Address of the eeprom |*/ -/*| WORD w_EepromStartAddress : Eeprom strat address |*/ +/*| Input Parameters : int i_NbOfWordsToRead : Nbr. of word to read |*/ +/*| unsigned int dw_PCIBoardEepromAddress : Address of the eeprom |*/ +/*| unsigned short w_EepromStartAddress : Eeprom strat address |*/ /*+----------------------------------------------------------------------------+*/ -/*| Output Parameters : PWORD pw_DataRead : Read data |*/ +/*| Output Parameters : unsigned short * pw_DataRead : Read data |*/ /*+----------------------------------------------------------------------------+*/ /*| Return Value : - |*/ /*+----------------------------------------------------------------------------+*/ -INT i_AddiHeaderRW_ReadEeprom(INT i_NbOfWordsToRead, - DWORD dw_PCIBoardEepromAddress, - WORD w_EepromStartAddress, PWORD pw_DataRead) +int i_AddiHeaderRW_ReadEeprom(int i_NbOfWordsToRead, + unsigned int dw_PCIBoardEepromAddress, + unsigned short w_EepromStartAddress, unsigned short *pw_DataRead) { - DWORD dw_eeprom_busy = 0; - INT i_Counter = 0; - INT i_WordCounter; - INT i; - BYTE pb_ReadByte[1]; - BYTE b_ReadLowByte = 0; - BYTE b_ReadHighByte = 0; - BYTE b_SelectedAddressLow = 0; - BYTE b_SelectedAddressHigh = 0; - WORD w_ReadWord = 0; + unsigned int dw_eeprom_busy = 0; + int i_Counter = 0; + int i_WordCounter; + int i; + unsigned char pb_ReadByte[1]; + unsigned char b_ReadLowByte = 0; + unsigned char b_ReadHighByte = 0; + unsigned char b_SelectedAddressLow = 0; + unsigned char b_SelectedAddressHigh = 0; + unsigned short w_ReadWord = 0; for (i_WordCounter = 0; i_WordCounter < i_NbOfWordsToRead; i_WordCounter++) { @@ -88,106 +88,99 @@ INT i_AddiHeaderRW_ReadEeprom(INT i_NbOfWordsToRead, inl(dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR); dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY; - } - while (dw_eeprom_busy == EEPROM_BUSY); + } while (dw_eeprom_busy == EEPROM_BUSY); for (i_Counter = 0; i_Counter < 2; i_Counter++) { - b_SelectedAddressLow = (w_EepromStartAddress + i_Counter) % 256; //Read the low 8 bit part - b_SelectedAddressHigh = (w_EepromStartAddress + i_Counter) / 256; //Read the high 8 bit part + b_SelectedAddressLow = (w_EepromStartAddress + i_Counter) % 256; /* Read the low 8 bit part */ + b_SelectedAddressHigh = (w_EepromStartAddress + i_Counter) / 256; /* Read the high 8 bit part */ - //Select the load low address mode + /* Select the load low address mode */ outb(NVCMD_LOAD_LOW, dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR + 3); - //Wait on busy + /* Wait on busy */ do { dw_eeprom_busy = inl(dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR); dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY; - } - while (dw_eeprom_busy == EEPROM_BUSY); + } while (dw_eeprom_busy == EEPROM_BUSY); - //Load the low address + /* Load the low address */ outb(b_SelectedAddressLow, dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR + 2); - //Wait on busy + /* Wait on busy */ do { dw_eeprom_busy = inl(dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR); dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY; - } - while (dw_eeprom_busy == EEPROM_BUSY); + } while (dw_eeprom_busy == EEPROM_BUSY); - //Select the load high address mode + /* Select the load high address mode */ outb(NVCMD_LOAD_HIGH, dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR + 3); - //Wait on busy + /* Wait on busy */ do { dw_eeprom_busy = inl(dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR); dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY; - } - while (dw_eeprom_busy == EEPROM_BUSY); + } while (dw_eeprom_busy == EEPROM_BUSY); - //Load the high address + /* Load the high address */ outb(b_SelectedAddressHigh, dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR + 2); - //Wait on busy + /* Wait on busy */ do { dw_eeprom_busy = inl(dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR); dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY; - } - while (dw_eeprom_busy == EEPROM_BUSY); + } while (dw_eeprom_busy == EEPROM_BUSY); - //Select the READ mode + /* Select the READ mode */ outb(NVCMD_BEGIN_READ, dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR + 3); - //Wait on busy + /* Wait on busy */ do { dw_eeprom_busy = inl(dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR); dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY; - } - while (dw_eeprom_busy == EEPROM_BUSY); + } while (dw_eeprom_busy == EEPROM_BUSY); - //Read data into the EEPROM + /* Read data into the EEPROM */ *pb_ReadByte = inb(dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR + 2); - //Wait on busy + /* Wait on busy */ do { dw_eeprom_busy = inl(dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR); dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY; - } - while (dw_eeprom_busy == EEPROM_BUSY); + } while (dw_eeprom_busy == EEPROM_BUSY); - //Select the upper address part + /* Select the upper address part */ if (i_Counter == 0) { b_ReadLowByte = pb_ReadByte[0]; } else { b_ReadHighByte = pb_ReadByte[0]; } - //Sleep - for (i = 0; i < 10000; i++) ; + /* Sleep */ + msleep(1); } w_ReadWord = @@ -196,8 +189,8 @@ INT i_AddiHeaderRW_ReadEeprom(INT i_NbOfWordsToRead, pw_DataRead[i_WordCounter] = w_ReadWord; - w_EepromStartAddress += 2; // to read the next word + w_EepromStartAddress += 2; /* to read the next word */ - } // for (...) i_NbOfWordsToRead - return (0); + } /* for (...) i_NbOfWordsToRead */ + return 0; } diff --git a/drivers/staging/comedi/drivers/addi-data/addi_amcc_S5920.h b/drivers/staging/comedi/drivers/addi-data/addi_amcc_S5920.h index 9ae56bc3adad..622a4ac2b799 100644 --- a/drivers/staging/comedi/drivers/addi-data/addi_amcc_S5920.h +++ b/drivers/staging/comedi/drivers/addi-data/addi_amcc_S5920.h @@ -22,6 +22,6 @@ #define NVCMD_BEGIN_READ (0x7 << 5) /* nvRam begin read command */ #define NVCMD_BEGIN_WRITE (0x6 << 5) /* EEPROM begin write command */ -INT i_AddiHeaderRW_ReadEeprom(INT i_NbOfWordsToRead, - DWORD dw_PCIBoardEepromAddress, - WORD w_EepromStartAddress, PWORD pw_DataRead); +int i_AddiHeaderRW_ReadEeprom(int i_NbOfWordsToRead, + unsigned int dw_PCIBoardEepromAddress, + unsigned short w_EepromStartAddress, unsigned short *pw_DataRead); diff --git a/drivers/staging/comedi/drivers/addi-data/addi_amcc_s5933.h b/drivers/staging/comedi/drivers/addi-data/addi_amcc_s5933.h index b50774cdcf77..d288289143ea 100644 --- a/drivers/staging/comedi/drivers/addi-data/addi_amcc_s5933.h +++ b/drivers/staging/comedi/drivers/addi-data/addi_amcc_s5933.h @@ -85,7 +85,7 @@ #define AMCC_OP_REG_MRTC 0x30 #define AMCC_OP_REG_MBEF 0x34 #define AMCC_OP_REG_INTCSR 0x38 -/* INT source */ +/* int source */ #define AMCC_OP_REG_INTCSR_SRC (AMCC_OP_REG_INTCSR + 2) /* FIFO ctrl */ #define AMCC_OP_REG_INTCSR_FEC (AMCC_OP_REG_INTCSR + 3) @@ -343,7 +343,7 @@ int i_find_free_pci_card_by_position(unsigned short vendor_id, *card = amcc; return 0; /* ok, card is found */ } else { - rt_printk(" - \nCard on requested position is used b:s %d:%d!\n", + printk(" - \nCard on requested position is used b:s %d:%d!\n", pci_bus, pci_slot); return 2; /* card exist but is used */ } @@ -447,7 +447,7 @@ struct pcilst_struct *ptr_select_and_alloc_pci_card(unsigned short vendor_id, /* use autodetection */ card = ptr_find_free_pci_card_by_device(vendor_id, device_id); if (card == NULL) { - rt_printk(" - Unused card not found in system!\n"); + printk(" - Unused card not found in system!\n"); return NULL; } } else { @@ -455,18 +455,18 @@ struct pcilst_struct *ptr_select_and_alloc_pci_card(unsigned short vendor_id, pci_bus, pci_slot, &card)) { case 1: - rt_printk(" - Card not found on requested position b:s %d:%d!\n", + printk(" - Card not found on requested position b:s %d:%d!\n", pci_bus, pci_slot); return NULL; case 2: - rt_printk(" - Card on requested position is used b:s %d:%d!\n", + printk(" - Card on requested position is used b:s %d:%d!\n", pci_bus, pci_slot); return NULL; } } if (pci_card_alloc(card, i_Master) != 0) { - rt_printk(" - Can't allocate card!\n"); + printk(" - Can't allocate card!\n"); return NULL; } diff --git a/drivers/staging/comedi/drivers/addi-data/addi_common.c b/drivers/staging/comedi/drivers/addi-data/addi_common.c index 618c69b6838d..a56535fbcd3e 100644 --- a/drivers/staging/comedi/drivers/addi-data/addi_common.c +++ b/drivers/staging/comedi/drivers/addi-data/addi_common.c @@ -3,13 +3,13 @@ Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data-com - info@addi-data.com + ADDI-DATA GmbH + Dieselstrasse 3 + D-77833 Ottersweier + Tel: +19(0)7223/9493-0 + Fax: +49(0)7223/9493-92 + http://www.addi-data-com + info@addi-data.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. @@ -68,25 +68,25 @@ You shoud also find the complete GPL in the COPYING file accompanying this sourc #include "addi_common.h" #include "addi_amcc_s5933.h" -//Update-0.7.57->0.7.68MODULE_AUTHOR("ADDI-DATA GmbH "); -//Update-0.7.57->0.7.68MODULE_DESCRIPTION("Comedi ADDI-DATA module"); -//Update-0.7.57->0.7.68MODULE_LICENSE("GPL"); +/* Update-0.7.57->0.7.68MODULE_AUTHOR("ADDI-DATA GmbH "); */ +/* Update-0.7.57->0.7.68MODULE_DESCRIPTION("Comedi ADDI-DATA module"); */ +/* Update-0.7.57->0.7.68MODULE_LICENSE("GPL"); */ -#define devpriv ((addi_private *)dev->private) -#define this_board ((boardtype *)dev->board_ptr) +#define devpriv ((struct addi_private *)dev->private) +#define this_board ((struct addi_board *)dev->board_ptr) #if defined(CONFIG_APCI_1710) || defined(CONFIG_APCI_3200) || defined(CONFIG_APCI_3300) -//BYTE b_SaveFPUReg [94]; +/* BYTE b_SaveFPUReg [94]; */ void fpu_begin(void) { - //asm ("fstenv b_SaveFPUReg"); + /* asm ("fstenv b_SaveFPUReg"); */ kernel_fpu_begin(); } void fpu_end(void) { - // asm ("frstor b_SaveFPUReg"); + /* asm ("frstor b_SaveFPUReg"); */ kernel_fpu_end(); } #endif @@ -219,7 +219,7 @@ static DEFINE_PCI_DEVICE_TABLE(addi_apci_tbl) = { MODULE_DEVICE_TABLE(pci, addi_apci_tbl); -static const boardtype boardtypes[] = { +static const struct addi_board boardtypes[] = { #ifdef CONFIG_APCI_3120 {"apci3120", APCI3120_BOARD_VENDOR_ID, @@ -901,7 +901,7 @@ static const boardtype boardtypes[] = { NULL}, #endif #ifdef CONFIG_APCI_3300 - //Begin JK 20.10.2004: APCI-3300 integration + /* Begin JK .20.10.2004 = APCI-3300 integration */ {"apci3300", APCI3200_BOARD_VENDOR_ID, 0x3007, @@ -2525,16 +2525,16 @@ static const boardtype boardtypes[] = { #endif }; -#define n_boardtypes (sizeof(boardtypes)/sizeof(boardtype)) +#define n_boardtypes (sizeof(boardtypes)/sizeof(struct addi_board)) struct comedi_driver driver_addi = { - driver_name:"addi_common", - module:THIS_MODULE, - attach:i_ADDI_Attach, - detach:i_ADDI_Detach, - num_names:n_boardtypes, - board_name:&boardtypes[0].pc_DriverName, - offset:sizeof(boardtype), + .driver_name = "addi_common", + .module = THIS_MODULE, + .attach = i_ADDI_Attach, + .detach = i_ADDI_Detach, + .num_names = n_boardtypes, + .board_name = &boardtypes[0].pc_DriverName, + .offset = sizeof(struct addi_board), }; COMEDI_PCI_INITCLEANUP(driver_addi, addi_apci_tbl); @@ -2559,11 +2559,11 @@ COMEDI_PCI_INITCLEANUP(driver_addi, addi_apci_tbl); +----------------------------------------------------------------------------+ */ -static int i_ADDI_Attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int i_ADDI_Attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; int ret, pages, i, n_subdevices; - DWORD dw_Dummy; + unsigned int dw_Dummy; resource_size_t io_addr[5]; unsigned int irq; resource_size_t iobase_a, iobase_main, iobase_addon, iobase_reserved; @@ -2575,26 +2575,28 @@ static int i_ADDI_Attach(struct comedi_device * dev, struct comedi_devconfig * i sprintf(c_Identifier, "Addi-Data GmbH Comedi %s", this_board->pc_DriverName); - if ((ret = alloc_private(dev, sizeof(addi_private))) < 0) { - return -ENOMEM; - } + ret = alloc_private(dev, sizeof(struct addi_private)); + if (ret < 0) + return -ENOMEM; if (!pci_list_builded) { - v_pci_card_list_init(this_board->i_VendorId, 1); //1 for displaying the list.. + v_pci_card_list_init(this_board->i_VendorId, 1); /* 1 for displaying the list.. */ pci_list_builded = 1; } - //rt_printk("comedi%d: addi_common: board=%s",dev->minor,this_board->pc_DriverName); + /* printk("comedi%d: addi_common: board=%s",dev->minor,this_board->pc_DriverName); */ if ((this_board->i_Dma) && (it->options[2] == 0)) { i_Dma = 1; } - if ((card = ptr_select_and_alloc_pci_card(this_board->i_VendorId, - this_board->i_DeviceId, - it->options[0], - it->options[1], i_Dma)) == NULL) { + card = ptr_select_and_alloc_pci_card(this_board->i_VendorId, + this_board->i_DeviceId, + it->options[0], + it->options[1], i_Dma); + + if (card == NULL) return -EIO; - } + devpriv->allocated = 1; if ((i_pci_card_data(card, &pci_bus, &pci_slot, &pci_func, &io_addr[0], @@ -2617,63 +2619,63 @@ static int i_ADDI_Attach(struct comedi_device * dev, struct comedi_devconfig * i /************************************/ if (this_board->i_IorangeBase1 != 0) { - dev->iobase = (unsigned long)iobase_main; // DAQ base address... + dev->iobase = (unsigned long)iobase_main; /* DAQ base address... */ } else { - dev->iobase = (unsigned long)iobase_a; // DAQ base address... + dev->iobase = (unsigned long)iobase_a; /* DAQ base address... */ } dev->board_name = this_board->pc_DriverName; devpriv->amcc = card; - devpriv->iobase = (INT) dev->iobase; - devpriv->i_IobaseAmcc = (INT) iobase_a; //AMCC base address... - devpriv->i_IobaseAddon = (INT) iobase_addon; //ADD ON base address.... - devpriv->i_IobaseReserved = (INT) iobase_reserved; + devpriv->iobase = (int) dev->iobase; + devpriv->i_IobaseAmcc = (int) iobase_a; /* AMCC base address... */ + devpriv->i_IobaseAddon = (int) iobase_addon; /* ADD ON base address.... */ + devpriv->i_IobaseReserved = (int) iobase_reserved; devpriv->ps_BoardInfo = this_board; } else { dev->board_name = this_board->pc_DriverName; dev->iobase = (unsigned long)io_addr[2]; devpriv->amcc = card; - devpriv->iobase = (INT) io_addr[2]; + devpriv->iobase = (int) io_addr[2]; devpriv->ps_BoardInfo = this_board; - devpriv->i_IobaseReserved = (INT) io_addr[3]; + devpriv->i_IobaseReserved = (int) io_addr[3]; printk("\nioremap begin"); devpriv->dw_AiBase = - (ULONG_PTR) ioremap(io_addr[3], + (unsigned long) ioremap(io_addr[3], this_board->i_IorangeBase3); printk("\nioremap end"); } - //## + /* ## */ if (irq > 0) { - if (comedi_request_irq(irq, v_ADDI_Interrupt, IRQF_SHARED, + if (request_irq(irq, v_ADDI_Interrupt, IRQF_SHARED, c_Identifier, dev) < 0) { printk(", unable to allocate IRQ %u, DISABLING IT", irq); irq = 0; /* Can't use IRQ */ } else { - rt_printk("\nirq=%u", irq); + printk("\nirq=%u", irq); } } else { - rt_printk(", IRQ disabled"); + printk(", IRQ disabled"); } printk("\nOption %d %d %d\n", it->options[0], it->options[1], it->options[2]); dev->irq = irq; - // Read eepeom and fill boardtype Structure + /* Read eepeom and fill addi_board Structure */ if (this_board->i_PCIEeprom) { printk("\nPCI Eeprom used"); if (!(strcmp(this_board->pc_EepromChip, "S5920"))) { - // Set 3 wait stait + /* Set 3 wait stait */ if (!(strcmp(this_board->pc_DriverName, "apci035"))) { outl(0x80808082, devpriv->i_IobaseAmcc + 0x60); } else { outl(0x83838383, devpriv->i_IobaseAmcc + 0x60); } - // Enable the interrupt for the controler + /* Enable the interrupt for the controler */ dw_Dummy = inl(devpriv->i_IobaseAmcc + 0x38); outl(dw_Dummy | 0x2000, devpriv->i_IobaseAmcc + 0x38); printk("\nEnable the interrupt for the controler"); @@ -2694,16 +2696,15 @@ static int i_ADDI_Attach(struct comedi_device * dev, struct comedi_devconfig * i if (this_board->i_Dma) { printk("\nDMA used"); if (devpriv->us_UseDma == ADDI_ENABLE) { - // alloc DMA buffers + /* alloc DMA buffers */ devpriv->b_DmaDoubleBuffer = 0; for (i = 0; i < 2; i++) { for (pages = 4; pages >= 0; pages--) { - if ((devpriv->ul_DmaBufferVirtual[i] = - (void *) - __get_free_pages - (GFP_KERNEL, pages))) { + devpriv->ul_DmaBufferVirtual[i] = + (void *) __get_free_pages(GFP_KERNEL, pages); + + if (devpriv->ul_DmaBufferVirtual[i]) break; - } } if (devpriv->ul_DmaBufferVirtual[i]) { devpriv->ui_DmaBufferPages[i] = pages; @@ -2718,7 +2719,7 @@ static int i_ADDI_Attach(struct comedi_device * dev, struct comedi_devconfig * i } } if (!devpriv->ul_DmaBufferVirtual[0]) { - rt_printk + printk (", Can't allocate DMA buffer, DMA disabled!"); devpriv->us_UseDma = ADDI_DISABLE; } @@ -2729,7 +2730,7 @@ static int i_ADDI_Attach(struct comedi_device * dev, struct comedi_devconfig * i } if ((devpriv->us_UseDma == ADDI_ENABLE)) { - rt_printk("\nDMA ENABLED\n"); + printk("\nDMA ENABLED\n"); } else { printk("\nDMA DISABLED\n"); } @@ -2739,23 +2740,24 @@ static int i_ADDI_Attach(struct comedi_device * dev, struct comedi_devconfig * i #ifdef CONFIG_APCI_1710 i_ADDI_AttachPCI1710(dev); - // save base address + /* save base address */ devpriv->s_BoardInfos.ui_Address = io_addr[2]; #endif } else { - //Update-0.7.57->0.7.68dev->n_subdevices = 7; + /* Update-0.7.57->0.7.68dev->n_subdevices = 7; */ n_subdevices = 7; - if ((ret = alloc_subdevices(dev, n_subdevices)) < 0) + ret = alloc_subdevices(dev, n_subdevices); + if (ret < 0) return ret; - // Allocate and Initialise AI Subdevice Structures + /* Allocate and Initialise AI Subdevice Structures */ s = dev->subdevices + 0; if ((this_board->i_NbrAiChannel) || (this_board->i_NbrAiChannelDiff)) { dev->read_subdev = s; s->type = COMEDI_SUBD_AI; s->subdev_flags = - SDF_READABLE | SDF_RT | SDF_COMMON | SDF_GROUND + SDF_READABLE | SDF_COMMON | SDF_GROUND | SDF_DIFF; if (this_board->i_NbrAiChannel) { s->n_chan = this_board->i_NbrAiChannel; @@ -2786,13 +2788,11 @@ static int i_ADDI_Attach(struct comedi_device * dev, struct comedi_devconfig * i s->type = COMEDI_SUBD_UNUSED; } - // Allocate and Initialise AO Subdevice Structures + /* Allocate and Initialise AO Subdevice Structures */ s = dev->subdevices + 1; if (this_board->i_NbrAoChannel) { s->type = COMEDI_SUBD_AO; - s->subdev_flags = - SDF_WRITEABLE | SDF_GROUND | SDF_COMMON | - SDF_RT; + s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON; s->n_chan = this_board->i_NbrAoChannel; s->maxdata = this_board->i_AoMaxdata; s->len_chanlist = this_board->i_NbrAoChannel; @@ -2804,12 +2804,11 @@ static int i_ADDI_Attach(struct comedi_device * dev, struct comedi_devconfig * i } else { s->type = COMEDI_SUBD_UNUSED; } - // Allocate and Initialise DI Subdevice Structures + /* Allocate and Initialise DI Subdevice Structures */ s = dev->subdevices + 2; if (this_board->i_NbrDiChannel) { s->type = COMEDI_SUBD_DI; - s->subdev_flags = - SDF_READABLE | SDF_RT | SDF_GROUND | SDF_COMMON; + s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON; s->n_chan = this_board->i_NbrDiChannel; s->maxdata = 1; s->len_chanlist = this_board->i_NbrDiChannel; @@ -2824,20 +2823,19 @@ static int i_ADDI_Attach(struct comedi_device * dev, struct comedi_devconfig * i } else { s->type = COMEDI_SUBD_UNUSED; } - // Allocate and Initialise DO Subdevice Structures + /* Allocate and Initialise DO Subdevice Structures */ s = dev->subdevices + 3; if (this_board->i_NbrDoChannel) { s->type = COMEDI_SUBD_DO; s->subdev_flags = - SDF_READABLE | SDF_WRITEABLE | SDF_RT | - SDF_GROUND | SDF_COMMON; + SDF_READABLE | SDF_WRITEABLE | SDF_GROUND | SDF_COMMON; s->n_chan = this_board->i_NbrDoChannel; s->maxdata = this_board->i_DoMaxdata; s->len_chanlist = this_board->i_NbrDoChannel; s->range_table = &range_digital; s->io_bits = 0xf; /* all bits output */ - s->insn_config = this_board->i_hwdrv_InsnConfigDigitalOutput; //for digital output memory.. + s->insn_config = this_board->i_hwdrv_InsnConfigDigitalOutput; /* for digital output memory.. */ s->insn_write = this_board->i_hwdrv_InsnWriteDigitalOutput; s->insn_bits = @@ -2848,13 +2846,11 @@ static int i_ADDI_Attach(struct comedi_device * dev, struct comedi_devconfig * i s->type = COMEDI_SUBD_UNUSED; } - // Allocate and Initialise Timer Subdevice Structures + /* Allocate and Initialise Timer Subdevice Structures */ s = dev->subdevices + 4; if (this_board->i_Timer) { s->type = COMEDI_SUBD_TIMER; - s->subdev_flags = - SDF_WRITEABLE | SDF_RT | SDF_GROUND | - SDF_COMMON; + s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON; s->n_chan = 1; s->maxdata = 0; s->len_chanlist = 1; @@ -2868,13 +2864,12 @@ static int i_ADDI_Attach(struct comedi_device * dev, struct comedi_devconfig * i s->type = COMEDI_SUBD_UNUSED; } - // Allocate and Initialise TTL + /* Allocate and Initialise TTL */ s = dev->subdevices + 5; if (this_board->i_NbrTTLChannel) { s->type = COMEDI_SUBD_TTLIO; s->subdev_flags = - SDF_WRITEABLE | SDF_READABLE | SDF_RT | - SDF_GROUND | SDF_COMMON; + SDF_WRITEABLE | SDF_READABLE | SDF_GROUND | SDF_COMMON; s->n_chan = this_board->i_NbrTTLChannel; s->maxdata = 1; s->io_bits = 0; /* all bits input */ @@ -2926,7 +2921,7 @@ static int i_ADDI_Attach(struct comedi_device * dev, struct comedi_devconfig * i +----------------------------------------------------------------------------+ */ -static int i_ADDI_Detach(struct comedi_device * dev) +static int i_ADDI_Detach(struct comedi_device *dev) { if (dev->private) { @@ -2935,7 +2930,7 @@ static int i_ADDI_Detach(struct comedi_device * dev) } if (dev->irq) { - comedi_free_irq(dev->irq, dev); + free_irq(dev->irq, dev); } if ((devpriv->ps_BoardInfo->pc_EepromChip == NULL) @@ -2965,7 +2960,7 @@ static int i_ADDI_Detach(struct comedi_device * dev) } if (pci_list_builded) { - //v_pci_card_list_cleanup(PCI_VENDOR_ID_AMCC); + /* v_pci_card_list_cleanup(PCI_VENDOR_ID_AMCC); */ v_pci_card_list_cleanup(this_board->i_VendorId); pci_list_builded = 0; } @@ -2992,18 +2987,18 @@ static int i_ADDI_Detach(struct comedi_device * dev) +----------------------------------------------------------------------------+ */ -static int i_ADDI_Reset(struct comedi_device * dev) +static int i_ADDI_Reset(struct comedi_device *dev) { this_board->i_hwdrv_Reset(dev); return 0; } -// Interrupt function +/* Interrupt function */ /* +----------------------------------------------------------------------------+ | Function name : | -|static void v_ADDI_Interrupt(int irq, void *d PT_REGS_ARG) | +|static void v_ADDI_Interrupt(int irq, void *d) | | | +----------------------------------------------------------------------------+ | Task : Registerd interrupt routine | @@ -3018,14 +3013,14 @@ static int i_ADDI_Reset(struct comedi_device * dev) +----------------------------------------------------------------------------+ */ -static irqreturn_t v_ADDI_Interrupt(int irq, void *d PT_REGS_ARG) +static irqreturn_t v_ADDI_Interrupt(int irq, void *d) { struct comedi_device *dev = d; this_board->v_hwdrv_Interrupt(irq, d); return IRQ_RETVAL(1); } -// EEPROM Read Function +/* EEPROM Read Function */ /* +----------------------------------------------------------------------------+ | Function name : | @@ -3046,17 +3041,17 @@ static irqreturn_t v_ADDI_Interrupt(int irq, void *d PT_REGS_ARG) +----------------------------------------------------------------------------+ */ -static int i_ADDIDATA_InsnReadEeprom(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int i_ADDIDATA_InsnReadEeprom(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - WORD w_Data; - WORD w_Address; - w_Address = CR_CHAN(insn->chanspec); // address to be read as 0,1,2,3...255 + unsigned short w_Data; + unsigned short w_Address; + w_Address = CR_CHAN(insn->chanspec); /* address to be read as 0,1,2,3...255 */ w_Data = w_EepromReadWord(devpriv->i_IobaseAmcc, this_board->pc_EepromChip, 0x100 + (2 * w_Address)); data[0] = w_Data; - //multiplied by 2 bcozinput will be like 0,1,2...255 + /* multiplied by 2 bcozinput will be like 0,1,2...255 */ return insn->n; } diff --git a/drivers/staging/comedi/drivers/addi-data/addi_common.h b/drivers/staging/comedi/drivers/addi-data/addi_common.h index 19df5c1444a4..edd657b902aa 100644 --- a/drivers/staging/comedi/drivers/addi-data/addi_common.h +++ b/drivers/staging/comedi/drivers/addi-data/addi_common.h @@ -36,26 +36,12 @@ #define ERROR -1 #define SUCCESS 1 -/* variable type definition */ -typedef unsigned char BYTE, *PBYTE; -typedef short SHORT, *PSHORT; -typedef unsigned short USHORT, *PUSHORT; -typedef unsigned short WORD, *PWORD; -typedef int INT, *PINT;; -typedef unsigned int UINT, *PUINT; -typedef int LONG, *PLONG; /* 32-bit */ -typedef unsigned int ULONG, *PULONG; /* 32-bit */ -typedef unsigned int DWORD, *PDWORD; /* 32-bit */ -typedef unsigned long ULONG_PTR; - -typedef const struct comedi_lrange *PCRANGE; - -#define LOBYTE(W) (BYTE)((W) & 0xFF) -#define HIBYTE(W) (BYTE)(((W) >> 8) & 0xFF) -#define MAKEWORD(H, L) (USHORT)((L) | ((H) << 8)) -#define LOWORD(W) (USHORT)((W) & 0xFFFF) -#define HIWORD(W) (USHORT)(((W) >> 16) & 0xFFFF) -#define MAKEDWORD(H, L) (UINT)((L) | ((H) << 16)) +#define LOBYTE(W) (unsigned char)((W) & 0xFF) +#define HIBYTE(W) (unsigned char)(((W) >> 8) & 0xFF) +#define MAKEWORD(H, L) (unsigned short)((L) | ((H) << 8)) +#define LOWORD(W) (unsigned short)((W) & 0xFFFF) +#define HIWORD(W) (unsigned short)(((W) >> 16) & 0xFFFF) +#define MAKEDWORD(H, L) (unsigned int)((L) | ((H) << 16)) #define ADDI_ENABLE 1 #define ADDI_DISABLE 0 @@ -75,37 +61,37 @@ typedef const struct comedi_lrange *PCRANGE; /* Structures */ /* structure for the boardtype */ -typedef struct { - const char *pc_DriverName; // driver name - INT i_VendorId; //PCI vendor a device ID of card - INT i_DeviceId; - INT i_IorangeBase0; - INT i_IorangeBase1; - INT i_IorangeBase2; // base 2 range - INT i_IorangeBase3; // base 3 range - INT i_PCIEeprom; // eeprom present or not - char *pc_EepromChip; // type of chip - INT i_NbrAiChannel; // num of A/D chans - INT i_NbrAiChannelDiff; // num of A/D chans in diff mode - INT i_AiChannelList; // len of chanlist - INT i_NbrAoChannel; // num of D/A chans - INT i_AiMaxdata; // resolution of A/D - INT i_AoMaxdata; // resolution of D/A - PCRANGE pr_AiRangelist; // rangelist for A/D - PCRANGE pr_AoRangelist; // rangelist for D/A +struct addi_board { + const char *pc_DriverName; /* driver name */ + int i_VendorId; /* PCI vendor a device ID of card */ + int i_DeviceId; + int i_IorangeBase0; + int i_IorangeBase1; + int i_IorangeBase2; /* base 2 range */ + int i_IorangeBase3; /* base 3 range */ + int i_PCIEeprom; /* eeprom present or not */ + char *pc_EepromChip; /* type of chip */ + int i_NbrAiChannel; /* num of A/D chans */ + int i_NbrAiChannelDiff; /* num of A/D chans in diff mode */ + int i_AiChannelList; /* len of chanlist */ + int i_NbrAoChannel; /* num of D/A chans */ + int i_AiMaxdata; /* resolution of A/D */ + int i_AoMaxdata; /* resolution of D/A */ + const struct comedi_lrange *pr_AiRangelist; /* rangelist for A/D */ + const struct comedi_lrange *pr_AoRangelist; /* rangelist for D/A */ - INT i_NbrDiChannel; // Number of DI channels - INT i_NbrDoChannel; // Number of DO channels - INT i_DoMaxdata; // data to set all chanels high + int i_NbrDiChannel; /* Number of DI channels */ + int i_NbrDoChannel; /* Number of DO channels */ + int i_DoMaxdata; /* data to set all chanels high */ - INT i_NbrTTLChannel; // Number of TTL channels - PCRANGE pr_TTLRangelist; // rangelist for TTL + int i_NbrTTLChannel; /* Number of TTL channels */ + const struct comedi_lrange *pr_TTLRangelist; /* rangelist for TTL */ - INT i_Dma; // dma present or not - INT i_Timer; // timer subdevice present or not - BYTE b_AvailableConvertUnit; - UINT ui_MinAcquisitiontimeNs; // Minimum Acquisition in Nano secs - UINT ui_MinDelaytimeNs; // Minimum Delay in Nano secs + int i_Dma; /* dma present or not */ + int i_Timer; /* timer subdevice present or not */ + unsigned char b_AvailableConvertUnit; + unsigned int ui_MinAcquisitiontimeNs; /* Minimum Acquisition in Nano secs */ + unsigned int ui_MinDelaytimeNs; /* Minimum Delay in Nano secs */ /* interrupt and reset */ void (*v_hwdrv_Interrupt)(int irq, void *d); @@ -213,21 +199,21 @@ typedef struct { int (*i_hwdr_WriteTTLIOChlOnOff)(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -} boardtype; +}; -//MODULE INFO STRUCTURE +/* MODULE INFO STRUCTURE */ -typedef union { +union str_ModuleInfo { /* Incremental counter infos */ struct { union { struct { - BYTE b_ModeRegister1; - BYTE b_ModeRegister2; - BYTE b_ModeRegister3; - BYTE b_ModeRegister4; + unsigned char b_ModeRegister1; + unsigned char b_ModeRegister2; + unsigned char b_ModeRegister3; + unsigned char b_ModeRegister4; } s_ByteModeRegister; - DWORD dw_ModeRegister1_2_3_4; + unsigned int dw_ModeRegister1_2_3_4; } s_ModeRegister; struct { @@ -244,25 +230,25 @@ typedef union { /* SSI infos */ struct { - BYTE b_SSIProfile; - BYTE b_PositionTurnLength; - BYTE b_TurnCptLength; - BYTE b_SSIInit; + unsigned char b_SSIProfile; + unsigned char b_PositionTurnLength; + unsigned char b_TurnCptLength; + unsigned char b_SSIInit; } s_SSICounterInfo; /* TTL I/O infos */ struct { - BYTE b_TTLInit; - BYTE b_PortConfiguration[4]; + unsigned char b_TTLInit; + unsigned char b_PortConfiguration[4]; } s_TTLIOInfo; /* Digital I/O infos */ struct { - BYTE b_DigitalInit; - BYTE b_ChannelAMode; - BYTE b_ChannelBMode; - BYTE b_OutputMemoryEnabled; - DWORD dw_OutputMemory; + unsigned char b_DigitalInit; + unsigned char b_ChannelAMode; + unsigned char b_ChannelBMode; + unsigned char b_OutputMemoryEnabled; + unsigned int dw_OutputMemory; } s_DigitalIOInfo; /*********************/ @@ -271,14 +257,14 @@ typedef union { struct { struct { - BYTE b_82X54Init; - BYTE b_InputClockSelection; - BYTE b_InputClockLevel; - BYTE b_OutputLevel; - BYTE b_HardwareGateLevel; - DWORD dw_ConfigurationWord; + unsigned char b_82X54Init; + unsigned char b_InputClockSelection; + unsigned char b_InputClockLevel; + unsigned char b_OutputLevel; + unsigned char b_HardwareGateLevel; + unsigned int dw_ConfigurationWord; } s_82X54TimerInfo[3]; - BYTE b_InterruptMask; + unsigned char b_InterruptMask; } s_82X54ModuleInfo; /*********************/ @@ -286,13 +272,13 @@ typedef union { /*********************/ struct { - BYTE b_ChronoInit; - BYTE b_InterruptMask; - BYTE b_PCIInputClock; - BYTE b_TimingUnit; - BYTE b_CycleMode; + unsigned char b_ChronoInit; + unsigned char b_InterruptMask; + unsigned char b_PCIInputClock; + unsigned char b_TimingUnit; + unsigned char b_CycleMode; double d_TimingInterval; - DWORD dw_ConfigReg; + unsigned int dw_ConfigReg; } s_ChronoModuleInfo; /***********************/ @@ -301,154 +287,154 @@ typedef union { struct { struct { - BYTE b_PulseEncoderInit; + unsigned char b_PulseEncoderInit; } s_PulseEncoderInfo[4]; - DWORD dw_SetRegister; - DWORD dw_ControlRegister; - DWORD dw_StatusRegister; + unsigned int dw_SetRegister; + unsigned int dw_ControlRegister; + unsigned int dw_StatusRegister; } s_PulseEncoderModuleInfo; /* Tor conter infos */ struct { struct { - BYTE b_TorCounterInit; - BYTE b_TimingUnit; - BYTE b_InterruptEnable; + unsigned char b_TorCounterInit; + unsigned char b_TimingUnit; + unsigned char b_InterruptEnable; double d_TimingInterval; - ULONG ul_RealTimingInterval; + unsigned int ul_RealTimingInterval; } s_TorCounterInfo[2]; - BYTE b_PCIInputClock; + unsigned char b_PCIInputClock; } s_TorCounterModuleInfo; /* PWM infos */ struct { struct { - BYTE b_PWMInit; - BYTE b_TimingUnit; - BYTE b_InterruptEnable; + unsigned char b_PWMInit; + unsigned char b_TimingUnit; + unsigned char b_InterruptEnable; double d_LowTiming; double d_HighTiming; - ULONG ul_RealLowTiming; - ULONG ul_RealHighTiming; + unsigned int ul_RealLowTiming; + unsigned int ul_RealHighTiming; } s_PWMInfo[2]; - BYTE b_ClockSelection; + unsigned char b_ClockSelection; } s_PWMModuleInfo; /* ETM infos */ struct { struct { - BYTE b_ETMEnable; - BYTE b_ETMInterrupt; + unsigned char b_ETMEnable; + unsigned char b_ETMInterrupt; } s_ETMInfo[2]; - BYTE b_ETMInit; - BYTE b_TimingUnit; - BYTE b_ClockSelection; + unsigned char b_ETMInit; + unsigned char b_TimingUnit; + unsigned char b_ClockSelection; double d_TimingInterval; - ULONG ul_Timing; + unsigned int ul_Timing; } s_ETMModuleInfo; /* CDA infos */ struct { - BYTE b_CDAEnable; - BYTE b_CDAInterrupt; - BYTE b_CDAInit; - BYTE b_FctSelection; - BYTE b_CDAReadFIFOOverflow; + unsigned char b_CDAEnable; + unsigned char b_CDAInterrupt; + unsigned char b_CDAInit; + unsigned char b_FctSelection; + unsigned char b_CDAReadFIFOOverflow; } s_CDAModuleInfo; -} str_ModuleInfo; +}; /* Private structure for the addi_apci3120 driver */ -typedef struct { +struct addi_private { - INT iobase; - INT i_IobaseAmcc; // base+size for AMCC chip - INT i_IobaseAddon; //addon base address - INT i_IobaseReserved; - ULONG_PTR dw_AiBase; - struct pcilst_struct *amcc; // ptr too AMCC data - BYTE allocated; // we have blocked card - BYTE b_ValidDriver; // driver is ok - BYTE b_AiContinuous; // we do unlimited AI - BYTE b_AiInitialisation; - UINT ui_AiActualScan; //how many scans we finished - UINT ui_AiBufferPtr; // data buffer ptr in samples - UINT ui_AiNbrofChannels; // how many channels is measured - UINT ui_AiScanLength; // Length of actual scanlist - UINT ui_AiActualScanPosition; // position in actual scan - PUINT pui_AiChannelList; // actual chanlist - UINT ui_AiChannelList[32]; // actual chanlist - BYTE b_AiChannelConfiguration[32]; // actual chanlist - UINT ui_AiReadData[32]; - DWORD dw_AiInitialised; - UINT ui_AiTimer0; //Timer Constant for Timer0 - UINT ui_AiTimer1; //Timer constant for Timer1 - UINT ui_AiFlags; - UINT ui_AiDataLength; - short *AiData; // Pointer to sample data - UINT ui_AiNbrofScans; // number of scans to do - USHORT us_UseDma; // To use Dma or not - BYTE b_DmaDoubleBuffer; // we can use double buffering - UINT ui_DmaActualBuffer; // which buffer is used now - //*UPDATE-0.7.57->0.7.68 - //ULONG ul_DmaBufferVirtual[2];// pointers to begin of DMA buffer - short *ul_DmaBufferVirtual[2]; // pointers to begin of DMA buffer - ULONG ul_DmaBufferHw[2]; // hw address of DMA buff - UINT ui_DmaBufferSize[2]; // size of dma buffer in bytes - UINT ui_DmaBufferUsesize[2]; // which size we may now used for transfer - UINT ui_DmaBufferSamples[2]; // size in samples - UINT ui_DmaBufferPages[2]; // number of pages in buffer - BYTE b_DigitalOutputRegister; // Digital Output Register - BYTE b_OutputMemoryStatus; - BYTE b_AnalogInputChannelNbr; // Analog input channel Nbr - BYTE b_AnalogOutputChannelNbr; // Analog input Output Nbr - BYTE b_TimerSelectMode; // Contain data written at iobase + 0C - BYTE b_ModeSelectRegister; // Contain data written at iobase + 0E - USHORT us_OutputRegister; // Contain data written at iobase + 0 - BYTE b_InterruptState; - BYTE b_TimerInit; // Specify if InitTimerWatchdog was load - BYTE b_TimerStarted; // Specify if timer 2 is running or not - BYTE b_Timer2Mode; // Specify the timer 2 mode - BYTE b_Timer2Interrupt; //Timer2 interrupt enable or disable - BYTE b_AiCyclicAcquisition; // indicate cyclic acquisition - BYTE b_InterruptMode; // eoc eos or dma - BYTE b_EocEosInterrupt; // Enable disable eoc eos interrupt - UINT ui_EocEosConversionTime; - BYTE b_EocEosConversionTimeBase; - BYTE b_SingelDiff; - BYTE b_ExttrigEnable; /* To enable or disable external trigger */ + int iobase; + int i_IobaseAmcc; /* base+size for AMCC chip */ + int i_IobaseAddon; /* addon base address */ + int i_IobaseReserved; + unsigned long dw_AiBase; + struct pcilst_struct *amcc; /* ptr too AMCC data */ + unsigned char allocated; /* we have blocked card */ + unsigned char b_ValidDriver; /* driver is ok */ + unsigned char b_AiContinuous; /* we do unlimited AI */ + unsigned char b_AiInitialisation; + unsigned int ui_AiActualScan; /* how many scans we finished */ + unsigned int ui_AiBufferPtr; /* data buffer ptr in samples */ + unsigned int ui_AiNbrofChannels; /* how many channels is measured */ + unsigned int ui_AiScanLength; /* Length of actual scanlist */ + unsigned int ui_AiActualScanPosition; /* position in actual scan */ + unsigned int *pui_AiChannelList; /* actual chanlist */ + unsigned int ui_AiChannelList[32]; /* actual chanlist */ + unsigned char b_AiChannelConfiguration[32]; /* actual chanlist */ + unsigned int ui_AiReadData[32]; + unsigned int dw_AiInitialised; + unsigned int ui_AiTimer0; /* Timer Constant for Timer0 */ + unsigned int ui_AiTimer1; /* Timer constant for Timer1 */ + unsigned int ui_AiFlags; + unsigned int ui_AiDataLength; + short *AiData; /* Pointer to sample data */ + unsigned int ui_AiNbrofScans; /* number of scans to do */ + unsigned short us_UseDma; /* To use Dma or not */ + unsigned char b_DmaDoubleBuffer; /* we can use double buffering */ + unsigned int ui_DmaActualBuffer; /* which buffer is used now */ + /* UPDATE-0.7.57->0.7.68 */ + /* unsigned int ul_DmaBufferVirtual[2]; pointers to begin of DMA buffer */ + short *ul_DmaBufferVirtual[2]; /* pointers to begin of DMA buffer */ + unsigned int ul_DmaBufferHw[2]; /* hw address of DMA buff */ + unsigned int ui_DmaBufferSize[2]; /* size of dma buffer in bytes */ + unsigned int ui_DmaBufferUsesize[2]; /* which size we may now used for transfer */ + unsigned int ui_DmaBufferSamples[2]; /* size in samples */ + unsigned int ui_DmaBufferPages[2]; /* number of pages in buffer */ + unsigned char b_DigitalOutputRegister; /* Digital Output Register */ + unsigned char b_OutputMemoryStatus; + unsigned char b_AnalogInputChannelNbr; /* Analog input channel Nbr */ + unsigned char b_AnalogOutputChannelNbr; /* Analog input Output Nbr */ + unsigned char b_TimerSelectMode; /* Contain data written at iobase + 0C */ + unsigned char b_ModeSelectRegister; /* Contain data written at iobase + 0E */ + unsigned short us_OutputRegister; /* Contain data written at iobase + 0 */ + unsigned char b_InterruptState; + unsigned char b_TimerInit; /* Specify if InitTimerWatchdog was load */ + unsigned char b_TimerStarted; /* Specify if timer 2 is running or not */ + unsigned char b_Timer2Mode; /* Specify the timer 2 mode */ + unsigned char b_Timer2Interrupt; /* Timer2 interrupt enable or disable */ + unsigned char b_AiCyclicAcquisition; /* indicate cyclic acquisition */ + unsigned char b_InterruptMode; /* eoc eos or dma */ + unsigned char b_EocEosInterrupt; /* Enable disable eoc eos interrupt */ + unsigned int ui_EocEosConversionTime; + unsigned char b_EocEosConversionTimeBase; + unsigned char b_SingelDiff; + unsigned char b_ExttrigEnable; /* To enable or disable external trigger */ /* Pointer to the current process */ struct task_struct *tsk_Current; - boardtype *ps_BoardInfo; + struct addi_board *ps_BoardInfo; /* Hardware board infos for 1710 */ struct { - UINT ui_Address; /* Board address */ - UINT ui_FlashAddress; - BYTE b_InterruptNbr; /* Board interrupt number */ - BYTE b_SlotNumber; /* PCI slot number */ - BYTE b_BoardVersion; - DWORD dw_MolduleConfiguration[4]; /* Module config */ + unsigned int ui_Address; /* Board address */ + unsigned int ui_FlashAddress; + unsigned char b_InterruptNbr; /* Board interrupt number */ + unsigned char b_SlotNumber; /* PCI slot number */ + unsigned char b_BoardVersion; + unsigned int dw_MolduleConfiguration[4]; /* Module config */ } s_BoardInfos; /* Interrupt infos */ struct { - ULONG ul_InterruptOccur; /* 0 : No interrupt occur */ + unsigned int ul_InterruptOccur; /* 0 : No interrupt occur */ /* > 0 : Interrupt occur */ - UINT ui_Read; /* Read FIFO */ - UINT ui_Write; /* Write FIFO */ + unsigned int ui_Read; /* Read FIFO */ + unsigned int ui_Write; /* Write FIFO */ struct { - BYTE b_OldModuleMask; - ULONG ul_OldInterruptMask; /* Interrupt mask */ - ULONG ul_OldCounterLatchValue; /* Interrupt counter value */ + unsigned char b_OldModuleMask; + unsigned int ul_OldInterruptMask; /* Interrupt mask */ + unsigned int ul_OldCounterLatchValue; /* Interrupt counter value */ } s_FIFOInterruptParameters[APCI1710_SAVE_INTERRUPT]; } s_InterruptParameters; - str_ModuleInfo s_ModuleInfo[4]; - ULONG ul_TTLPortConfiguration[10]; + union str_ModuleInfo s_ModuleInfo[4]; + unsigned int ul_TTLPortConfiguration[10]; -} addi_private; +}; static unsigned short pci_list_builded; /* set to 1 when list of card is known */ @@ -457,6 +443,6 @@ static int i_ADDI_Attach(struct comedi_device *dev, struct comedi_devconfig *it) static int i_ADDI_Detach(struct comedi_device *dev); static int i_ADDI_Reset(struct comedi_device *dev); -static irqreturn_t v_ADDI_Interrupt(int irq, void *d PT_REGS_ARG); +static irqreturn_t v_ADDI_Interrupt(int irq, void *d); static int i_ADDIDATA_InsnReadEeprom(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); diff --git a/drivers/staging/comedi/drivers/addi-data/addi_eeprom.c b/drivers/staging/comedi/drivers/addi-data/addi_eeprom.c index a8a1bb2e8fa5..69b427390e53 100644 --- a/drivers/staging/comedi/drivers/addi-data/addi_eeprom.c +++ b/drivers/staging/comedi/drivers/addi-data/addi_eeprom.c @@ -3,13 +3,13 @@ Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data-com - info@addi-data.com + ADDI-DATA GmbH + Dieselstrasse 3 + D-77833 Ottersweier + Tel: +19(0)7223/9493-0 + Fax: +49(0)7223/9493-92 + http://www.addi-data-com + info@addi-data.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. @@ -45,19 +45,11 @@ You shoud also find the complete GPL in the COPYING file accompanying this sourc +----------+-----------+------------------------------------------------+ */ -#define NVCMD_BEGIN_READ (0x7 << 5 ) // nvRam begin read command -#define NVCMD_LOAD_LOW (0x4 << 5 ) // nvRam load low command -#define NVCMD_LOAD_HIGH (0x5 << 5 ) // nvRam load high command -#define EE76_CMD_LEN 13 // bits in instructions -#define EE_READ 0x0180 // 01 1000 0000 read instruction - -#define WORD unsigned short -#define PWORD unsigned short * -#define PDWORD unsigned int * - -#ifndef DWORD -#define DWORD unsigned int -#endif +#define NVCMD_BEGIN_READ (0x7 << 5) /* nvRam begin read command */ +#define NVCMD_LOAD_LOW (0x4 << 5) /* nvRam load low command */ +#define NVCMD_LOAD_HIGH (0x5 << 5) /* nvRam load high command */ +#define EE76_CMD_LEN 13 /* bits in instructions */ +#define EE_READ 0x0180 /* 01 1000 0000 read instruction */ #define EEPROM_DIGITALINPUT 0 #define EEPROM_DIGITALOUTPUT 1 @@ -68,107 +60,114 @@ You shoud also find the complete GPL in the COPYING file accompanying this sourc #define EEPROM_TIMER_WATCHDOG_COUNTER 10 struct str_Functionality { - BYTE b_Type; - WORD w_Address; + unsigned char b_Type; + unsigned short w_Address; }; -typedef struct { - WORD w_HeaderSize; - BYTE b_Nfunctions; +struct str_MainHeader { + unsigned short w_HeaderSize; + unsigned char b_Nfunctions; struct str_Functionality s_Functions[7]; -} str_MainHeader; +}; + +struct str_DigitalInputHeader { + unsigned short w_Nchannel; + unsigned char b_Interruptible; + unsigned short w_NinterruptLogic; +}; + +struct str_DigitalOutputHeader { + + unsigned short w_Nchannel; +}; + + +/* used for timer as well as watchdog */ + +struct str_TimerDetails { + + unsigned short w_HeaderSize; + unsigned char b_Resolution; + unsigned char b_Mode; /* in case of Watchdog it is functionality */ + unsigned short w_MinTiming; + unsigned char b_TimeBase; +}; + +struct str_TimerMainHeader { + + + unsigned short w_Ntimer; + struct str_TimerDetails s_TimerDetails[4]; /* supports 4 timers */ +}; + typedef struct { - WORD w_Nchannel; - BYTE b_Interruptible; - WORD w_NinterruptLogic; -} str_DigitalInputHeader; - -typedef struct { - WORD w_Nchannel; -} str_DigitalOutputHeader; - -// used for timer as well as watchdog - -typedef struct { - WORD w_HeaderSize; - BYTE b_Resolution; - BYTE b_Mode; // in case of Watchdog it is functionality - WORD w_MinTiming; - BYTE b_TimeBase; -} str_TimerDetails; -typedef struct { - - WORD w_Ntimer; - str_TimerDetails s_TimerDetails[4]; // supports 4 timers -} str_TimerMainHeader; - -typedef struct { - WORD w_Nchannel; - BYTE b_Resolution; + unsigned short w_Nchannel; + unsigned char b_Resolution; } str_AnalogOutputHeader; -typedef struct { - WORD w_Nchannel; - WORD w_MinConvertTiming; - WORD w_MinDelayTiming; - BYTE b_HasDma; - BYTE b_Resolution; -} str_AnalogInputHeader; +struct str_AnalogInputHeader { + unsigned short w_Nchannel; + unsigned short w_MinConvertTiming; + unsigned short w_MinDelayTiming; + unsigned char b_HasDma; + unsigned char b_Resolution; +}; + /*****************************************/ /* Read Header Functions */ /*****************************************/ -INT i_EepromReadMainHeader(WORD w_PCIBoardEepromAddress, +int i_EepromReadMainHeader(unsigned short w_PCIBoardEepromAddress, char *pc_PCIChipInformation, struct comedi_device *dev); -INT i_EepromReadDigitalInputHeader(WORD w_PCIBoardEepromAddress, - char *pc_PCIChipInformation, WORD w_Address, - str_DigitalInputHeader * s_Header); +int i_EepromReadDigitalInputHeader(unsigned short w_PCIBoardEepromAddress, + char *pc_PCIChipInformation, unsigned short w_Address, + struct str_DigitalInputHeader *s_Header); -INT i_EepromReadDigitalOutputHeader(WORD w_PCIBoardEepromAddress, - char *pc_PCIChipInformation, WORD w_Address, - str_DigitalOutputHeader * s_Header); +int i_EepromReadDigitalOutputHeader(unsigned short w_PCIBoardEepromAddress, + char *pc_PCIChipInformation, unsigned short w_Address, + struct str_DigitalOutputHeader *s_Header); -INT i_EepromReadTimerHeader(WORD w_PCIBoardEepromAddress, - char *pc_PCIChipInformation, WORD w_Address, - str_TimerMainHeader * s_Header); +int i_EepromReadTimerHeader(unsigned short w_PCIBoardEepromAddress, + char *pc_PCIChipInformation, unsigned short w_Address, + struct str_TimerMainHeader *s_Header); -INT i_EepromReadAnlogOutputHeader(WORD w_PCIBoardEepromAddress, - char *pc_PCIChipInformation, WORD w_Address, - str_AnalogOutputHeader * s_Header); +int i_EepromReadAnlogOutputHeader(unsigned short w_PCIBoardEepromAddress, + char *pc_PCIChipInformation, unsigned short w_Address, + str_AnalogOutputHeader *s_Header); -INT i_EepromReadAnlogInputHeader(WORD w_PCIBoardEepromAddress, - char *pc_PCIChipInformation, WORD w_Address, - str_AnalogInputHeader * s_Header); +int i_EepromReadAnlogInputHeader(unsigned short w_PCIBoardEepromAddress, + char *pc_PCIChipInformation, unsigned short w_Address, + struct str_AnalogInputHeader *s_Header); /******************************************/ /* Eeprom Specific Functions */ /******************************************/ -WORD w_EepromReadWord(WORD w_PCIBoardEepromAddress, char *pc_PCIChipInformation, - WORD w_EepromStartAddress); -void v_EepromWaitBusy(WORD w_PCIBoardEepromAddress); -void v_EepromClock76(DWORD dw_Address, DWORD dw_RegisterValue); -void v_EepromWaitBusy(WORD w_PCIBoardEepromAddress); -void v_EepromSendCommand76(DWORD dw_Address, DWORD dw_EepromCommand, - BYTE b_DataLengthInBits); -void v_EepromCs76Read(DWORD dw_Address, WORD w_offset, PWORD pw_Value); +unsigned short w_EepromReadWord(unsigned short w_PCIBoardEepromAddress, char *pc_PCIChipInformation, + unsigned short w_EepromStartAddress); +void v_EepromWaitBusy(unsigned short w_PCIBoardEepromAddress); +void v_EepromClock76(unsigned int dw_Address, unsigned int dw_RegisterValue); +void v_EepromWaitBusy(unsigned short w_PCIBoardEepromAddress); +void v_EepromSendCommand76(unsigned int dw_Address, unsigned int dw_EepromCommand, + unsigned char b_DataLengthInBits); +void v_EepromCs76Read(unsigned int dw_Address, unsigned short w_offset, unsigned short *pw_Value); /* +----------------------------------------------------------------------------+ -| Function Name : WORD w_EepromReadWord | -| (WORD w_PCIBoardEepromAddress, | +| Function Name : unsigned short w_EepromReadWord | +| (unsigned short w_PCIBoardEepromAddress, | | char * pc_PCIChipInformation, | -| WORD w_EepromStartAddress) | +| unsigned short w_EepromStartAddress) | +----------------------------------------------------------------------------+ | Task : Read from eepromn a word | +----------------------------------------------------------------------------+ -| Input Parameters : WORD w_PCIBoardEepromAddress : PCI eeprom address | +| Input Parameters : unsigned short w_PCIBoardEepromAddress : PCI eeprom address | | | | char *pc_PCIChipInformation : PCI Chip Type. | | | -| WORD w_EepromStartAddress : Selected eeprom address | +| unsigned short w_EepromStartAddress : Selected eeprom address | +----------------------------------------------------------------------------+ | Output Parameters : - | +----------------------------------------------------------------------------+ @@ -176,23 +175,23 @@ void v_EepromCs76Read(DWORD dw_Address, WORD w_offset, PWORD pw_Value); +----------------------------------------------------------------------------+ */ -WORD w_EepromReadWord(WORD w_PCIBoardEepromAddress, char *pc_PCIChipInformation, - WORD w_EepromStartAddress) +unsigned short w_EepromReadWord(unsigned short w_PCIBoardEepromAddress, char *pc_PCIChipInformation, + unsigned short w_EepromStartAddress) { - BYTE b_Counter = 0; + unsigned char b_Counter = 0; - BYTE b_ReadByte = 0; + unsigned char b_ReadByte = 0; - BYTE b_ReadLowByte = 0; + unsigned char b_ReadLowByte = 0; - BYTE b_ReadHighByte = 0; + unsigned char b_ReadHighByte = 0; - BYTE b_SelectedAddressLow = 0; + unsigned char b_SelectedAddressLow = 0; - BYTE b_SelectedAddressHigh = 0; + unsigned char b_SelectedAddressHigh = 0; - WORD w_ReadWord = 0; + unsigned short w_ReadWord = 0; /**************************/ @@ -207,9 +206,9 @@ WORD w_EepromReadWord(WORD w_PCIBoardEepromAddress, char *pc_PCIChipInformation, for (b_Counter = 0; b_Counter < 2; b_Counter++) { - b_SelectedAddressLow = (w_EepromStartAddress + b_Counter) % 256; //Read the low 8 bit part + b_SelectedAddressLow = (w_EepromStartAddress + b_Counter) % 256; /* Read the low 8 bit part */ - b_SelectedAddressHigh = (w_EepromStartAddress + b_Counter) / 256; //Read the high 8 bit part + b_SelectedAddressHigh = (w_EepromStartAddress + b_Counter) / 256; /* Read the high 8 bit part */ /************************************/ @@ -320,20 +319,20 @@ WORD w_EepromReadWord(WORD w_PCIBoardEepromAddress, char *pc_PCIChipInformation, b_ReadLowByte = b_ReadByte; - } // if(b_Counter==0) + } /* if(b_Counter==0) */ else { b_ReadHighByte = b_ReadByte; - } // if(b_Counter==0) + } /* if(b_Counter==0) */ - } // for (b_Counter=0; b_Counter<2; b_Counter++) + } /* for (b_Counter=0; b_Counter<2; b_Counter++) */ - w_ReadWord = (b_ReadLowByte | (((WORD) b_ReadHighByte) * 256)); + w_ReadWord = (b_ReadLowByte | (((unsigned short) b_ReadHighByte) * 256)); - } // end of if ((!strcmp(pc_PCIChipInformation, "S5920")) || (!strcmp(pc_PCIChipInformation, "S5933"))) + } /* end of if ((!strcmp(pc_PCIChipInformation, "S5920")) || (!strcmp(pc_PCIChipInformation, "S5933"))) */ if (!strcmp(pc_PCIChipInformation, "93C76")) { @@ -349,7 +348,7 @@ WORD w_EepromReadWord(WORD w_PCIBoardEepromAddress, char *pc_PCIChipInformation, } - return (w_ReadWord); + return w_ReadWord; } @@ -359,7 +358,7 @@ WORD w_EepromReadWord(WORD w_PCIBoardEepromAddress, char *pc_PCIChipInformation, | Function Name : void v_EepromWaitBusy | -| (WORD w_PCIBoardEepromAddress) | +| (unsigned short w_PCIBoardEepromAddress) | +----------------------------------------------------------------------------+ @@ -367,7 +366,7 @@ WORD w_EepromReadWord(WORD w_PCIBoardEepromAddress, char *pc_PCIChipInformation, +----------------------------------------------------------------------------+ -| Input Parameters : WORD w_PCIBoardEepromAddress : PCI eeprom base address | +| Input Parameters : unsigned short w_PCIBoardEepromAddress : PCI eeprom base address | +----------------------------------------------------------------------------+ @@ -381,10 +380,10 @@ WORD w_EepromReadWord(WORD w_PCIBoardEepromAddress, char *pc_PCIChipInformation, */ -void v_EepromWaitBusy(WORD w_PCIBoardEepromAddress) +void v_EepromWaitBusy(unsigned short w_PCIBoardEepromAddress) { - BYTE b_EepromBusy = 0; + unsigned char b_EepromBusy = 0; do { @@ -403,17 +402,16 @@ void v_EepromWaitBusy(WORD w_PCIBoardEepromAddress) /* the operator register is AMCC_OP_REG_MCSR+3 */ - /* WORD read EEPROM=0x8000 andAMCC_OP_REG_MCSR+2 */ + /* unsigned short read EEPROM=0x8000 andAMCC_OP_REG_MCSR+2 */ - /* DWORD read EEPROM=0x80000000 and AMCC_OP_REG_MCSR */ + /* unsigned int read EEPROM=0x80000000 and AMCC_OP_REG_MCSR */ /************************************************************************/ b_EepromBusy = inb(w_PCIBoardEepromAddress + 0x3F); b_EepromBusy = b_EepromBusy & 0x80; - } - while (b_EepromBusy == 0x80); + } while (b_EepromBusy == 0x80); } @@ -421,9 +419,9 @@ void v_EepromWaitBusy(WORD w_PCIBoardEepromAddress) +---------------------------------------------------------------------------------+ -| Function Name : void v_EepromClock76(DWORD dw_Address, | +| Function Name : void v_EepromClock76(unsigned int dw_Address, | -| DWORD dw_RegisterValue) | +| unsigned int dw_RegisterValue) | +---------------------------------------------------------------------------------+ @@ -431,9 +429,9 @@ void v_EepromWaitBusy(WORD w_PCIBoardEepromAddress) +---------------------------------------------------------------------------------+ -| Input Parameters : DWORD dw_Address : PCI eeprom base address | +| Input Parameters : unsigned int dw_Address : PCI eeprom base address | -| DWORD dw_RegisterValue : PCI eeprom register value to write.| +| unsigned int dw_RegisterValue : PCI eeprom register value to write.| +---------------------------------------------------------------------------------+ @@ -447,7 +445,7 @@ void v_EepromWaitBusy(WORD w_PCIBoardEepromAddress) */ -void v_EepromClock76(DWORD dw_Address, DWORD dw_RegisterValue) +void v_EepromClock76(unsigned int dw_Address, unsigned int dw_RegisterValue) { /************************/ @@ -488,11 +486,11 @@ void v_EepromClock76(DWORD dw_Address, DWORD dw_RegisterValue) +---------------------------------------------------------------------------------+ -| Function Name : void v_EepromSendCommand76(DWORD dw_Address, | +| Function Name : void v_EepromSendCommand76(unsigned int dw_Address, | -| DWORD dw_EepromCommand, | +| unsigned int dw_EepromCommand, | -| BYTE b_DataLengthInBits) | +| unsigned char b_DataLengthInBits) | +---------------------------------------------------------------------------------+ @@ -500,11 +498,11 @@ void v_EepromClock76(DWORD dw_Address, DWORD dw_RegisterValue) +---------------------------------------------------------------------------------+ -| Input Parameters : DWORD dw_Address : PCI eeprom base address | +| Input Parameters : unsigned int dw_Address : PCI eeprom base address | -| DWORD dw_EepromCommand : PCI eeprom command to write. | +| unsigned int dw_EepromCommand : PCI eeprom command to write. | -| BYTE b_DataLengthInBits : PCI eeprom command data length. | +| unsigned char b_DataLengthInBits : PCI eeprom command data length. | +---------------------------------------------------------------------------------+ @@ -518,13 +516,13 @@ void v_EepromClock76(DWORD dw_Address, DWORD dw_RegisterValue) */ -void v_EepromSendCommand76(DWORD dw_Address, DWORD dw_EepromCommand, - BYTE b_DataLengthInBits) +void v_EepromSendCommand76(unsigned int dw_Address, unsigned int dw_EepromCommand, + unsigned char b_DataLengthInBits) { char c_BitPos = 0; - DWORD dw_RegisterValue = 0; + unsigned int dw_RegisterValue = 0; /*****************************/ @@ -623,11 +621,11 @@ void v_EepromSendCommand76(DWORD dw_Address, DWORD dw_EepromCommand, +---------------------------------------------------------------------------------+ -| Function Name : void v_EepromCs76Read(DWORD dw_Address, | +| Function Name : void v_EepromCs76Read(unsigned int dw_Address, | -| WORD w_offset, | +| unsigned short w_offset, | -| PWORD pw_Value) | +| unsigned short * pw_Value) | +---------------------------------------------------------------------------------+ @@ -635,11 +633,11 @@ void v_EepromSendCommand76(DWORD dw_Address, DWORD dw_EepromCommand, +---------------------------------------------------------------------------------+ -| Input Parameters : DWORD dw_Address : PCI eeprom base address | +| Input Parameters : unsigned int dw_Address : PCI eeprom base address | -| WORD w_offset : Offset of the adress to read | +| unsigned short w_offset : Offset of the adress to read | -| PWORD pw_Value : PCI eeprom 16 bit read value. | +| unsigned short * pw_Value : PCI eeprom 16 bit read value. | +---------------------------------------------------------------------------------+ @@ -653,14 +651,14 @@ void v_EepromSendCommand76(DWORD dw_Address, DWORD dw_EepromCommand, */ -void v_EepromCs76Read(DWORD dw_Address, WORD w_offset, PWORD pw_Value) +void v_EepromCs76Read(unsigned int dw_Address, unsigned short w_offset, unsigned short *pw_Value) { char c_BitPos = 0; - DWORD dw_RegisterValue = 0; + unsigned int dw_RegisterValue = 0; - DWORD dw_RegisterValueRead = 0; + unsigned int dw_RegisterValueRead = 0; /*************************************************/ @@ -786,12 +784,12 @@ void v_EepromCs76Read(DWORD dw_Address, WORD w_offset, PWORD pw_Value) /* +----------------------------------------------------------------------------+ -| Function Name : INT i_EepromReadMainHeader(WORD w_PCIBoardEepromAddress, | +| Function Name : int i_EepromReadMainHeader(unsigned short w_PCIBoardEepromAddress, | | char * pc_PCIChipInformation,struct comedi_device *dev) | +----------------------------------------------------------------------------+ | Task : Read from eeprom Main Header | +----------------------------------------------------------------------------+ -| Input Parameters : WORD w_PCIBoardEepromAddress : PCI eeprom address | +| Input Parameters : unsigned short w_PCIBoardEepromAddress : PCI eeprom address | | | | char *pc_PCIChipInformation : PCI Chip Type. | | | @@ -804,43 +802,43 @@ void v_EepromCs76Read(DWORD dw_Address, WORD w_offset, PWORD pw_Value) +----------------------------------------------------------------------------+ */ -INT i_EepromReadMainHeader(WORD w_PCIBoardEepromAddress, +int i_EepromReadMainHeader(unsigned short w_PCIBoardEepromAddress, char *pc_PCIChipInformation, struct comedi_device *dev) { - WORD w_Temp, i, w_Count = 0; - UINT ui_Temp; - str_MainHeader s_MainHeader; - str_DigitalInputHeader s_DigitalInputHeader; - str_DigitalOutputHeader s_DigitalOutputHeader; - //str_TimerMainHeader s_TimerMainHeader,s_WatchdogMainHeader; + unsigned short w_Temp, i, w_Count = 0; + unsigned int ui_Temp; + struct str_MainHeader s_MainHeader; + struct str_DigitalInputHeader s_DigitalInputHeader; + struct str_DigitalOutputHeader s_DigitalOutputHeader; + /* struct str_TimerMainHeader s_TimerMainHeader,s_WatchdogMainHeader; */ str_AnalogOutputHeader s_AnalogOutputHeader; - str_AnalogInputHeader s_AnalogInputHeader; + struct str_AnalogInputHeader s_AnalogInputHeader; - // Read size + /* Read size */ s_MainHeader.w_HeaderSize = w_EepromReadWord(w_PCIBoardEepromAddress, pc_PCIChipInformation, 0x100 + 8); - // Read nbr of functionality + /* Read nbr of functionality */ w_Temp = w_EepromReadWord(w_PCIBoardEepromAddress, pc_PCIChipInformation, 0x100 + 10); - s_MainHeader.b_Nfunctions = (BYTE) w_Temp & 0x00FF; + s_MainHeader.b_Nfunctions = (unsigned char) w_Temp & 0x00FF; - // Read functionality details + /* Read functionality details */ for (i = 0; i < s_MainHeader.b_Nfunctions; i++) { - // Read Type + /* Read Type */ w_Temp = w_EepromReadWord(w_PCIBoardEepromAddress, pc_PCIChipInformation, 0x100 + 12 + w_Count); - s_MainHeader.s_Functions[i].b_Type = (BYTE) w_Temp & 0x3F; + s_MainHeader.s_Functions[i].b_Type = (unsigned char) w_Temp & 0x3F; w_Count = w_Count + 2; - //Read Address + /* Read Address */ s_MainHeader.s_Functions[i].w_Address = w_EepromReadWord(w_PCIBoardEepromAddress, pc_PCIChipInformation, 0x100 + 12 + w_Count); w_Count = w_Count + 2; } - // Display main header info + /* Display main header info */ for (i = 0; i < s_MainHeader.b_Nfunctions; i++) { switch (s_MainHeader.s_Functions[i].b_Type) { @@ -878,10 +876,10 @@ INT i_EepromReadMainHeader(WORD w_PCIBoardEepromAddress, s_AnalogInputHeader.w_Nchannel; this_board->i_Dma = s_AnalogInputHeader.b_HasDma; this_board->ui_MinAcquisitiontimeNs = - (UINT) s_AnalogInputHeader.w_MinConvertTiming * + (unsigned int) s_AnalogInputHeader.w_MinConvertTiming * 1000; this_board->ui_MinDelaytimeNs = - (UINT) s_AnalogInputHeader.w_MinDelayTiming * + (unsigned int) s_AnalogInputHeader.w_MinDelayTiming * 1000; ui_Temp = 0xffff; this_board->i_AiMaxdata = @@ -903,15 +901,15 @@ INT i_EepromReadMainHeader(WORD w_PCIBoardEepromAddress, break; case EEPROM_TIMER: - this_board->i_Timer = 1; //Timer subdevice present + this_board->i_Timer = 1; /* Timer subdevice present */ break; case EEPROM_WATCHDOG: - this_board->i_Timer = 1; //Timer subdevice present + this_board->i_Timer = 1; /* Timer subdevice present */ break; case EEPROM_TIMER_WATCHDOG_COUNTER: - this_board->i_Timer = 1; //Timer subdevice present + this_board->i_Timer = 1; /* Timer subdevice present */ } } @@ -920,18 +918,18 @@ INT i_EepromReadMainHeader(WORD w_PCIBoardEepromAddress, /* +----------------------------------------------------------------------------+ -| Function Name : INT i_EepromReadDigitalInputHeader(WORD | +| Function Name : int i_EepromReadDigitalInputHeader(unsigned short | | w_PCIBoardEepromAddress,char *pc_PCIChipInformation, | -| WORD w_Address,str_DigitalInputHeader *s_Header) | +| unsigned short w_Address,struct str_DigitalInputHeader *s_Header) | | | +----------------------------------------------------------------------------+ | Task : Read Digital Input Header | +----------------------------------------------------------------------------+ -| Input Parameters : WORD w_PCIBoardEepromAddress : PCI eeprom address | +| Input Parameters : unsigned short w_PCIBoardEepromAddress : PCI eeprom address | | | | char *pc_PCIChipInformation : PCI Chip Type. | | | -| str_DigitalInputHeader *s_Header: Digita Input Header | +| struct str_DigitalInputHeader *s_Header: Digita Input Header | | Pointer | +----------------------------------------------------------------------------+ | Output Parameters : - | @@ -939,23 +937,23 @@ INT i_EepromReadMainHeader(WORD w_PCIBoardEepromAddress, | Return Value : 0 | +----------------------------------------------------------------------------+ */ -INT i_EepromReadDigitalInputHeader(WORD w_PCIBoardEepromAddress, - char *pc_PCIChipInformation, WORD w_Address, - str_DigitalInputHeader * s_Header) +int i_EepromReadDigitalInputHeader(unsigned short w_PCIBoardEepromAddress, + char *pc_PCIChipInformation, unsigned short w_Address, + struct str_DigitalInputHeader *s_Header) { - WORD w_Temp; + unsigned short w_Temp; - // read nbr of channels + /* read nbr of channels */ s_Header->w_Nchannel = w_EepromReadWord(w_PCIBoardEepromAddress, pc_PCIChipInformation, 0x100 + w_Address + 6); - // interruptible or not + /* interruptible or not */ w_Temp = w_EepromReadWord(w_PCIBoardEepromAddress, pc_PCIChipInformation, 0x100 + w_Address + 8); - s_Header->b_Interruptible = (BYTE) (w_Temp >> 7) & 0x01; + s_Header->b_Interruptible = (unsigned char) (w_Temp >> 7) & 0x01; -// How many interruptible logic +/* How many interruptible logic */ s_Header->w_NinterruptLogic = w_EepromReadWord(w_PCIBoardEepromAddress, pc_PCIChipInformation, 0x100 + w_Address + 10); @@ -965,18 +963,18 @@ INT i_EepromReadDigitalInputHeader(WORD w_PCIBoardEepromAddress, /* +----------------------------------------------------------------------------+ -| Function Name : INT i_EepromReadDigitalOutputHeader(WORD | +| Function Name : int i_EepromReadDigitalOutputHeader(unsigned short | | w_PCIBoardEepromAddress,char *pc_PCIChipInformation, | -| WORD w_Address,str_DigitalOutputHeader *s_Header) | +| unsigned short w_Address,struct str_DigitalOutputHeader *s_Header) | | | +----------------------------------------------------------------------------+ | Task : Read Digital Output Header | +----------------------------------------------------------------------------+ -| Input Parameters : WORD w_PCIBoardEepromAddress : PCI eeprom address | +| Input Parameters : unsigned short w_PCIBoardEepromAddress : PCI eeprom address | | | | char *pc_PCIChipInformation : PCI Chip Type. | | | -| str_DigitalOutputHeader *s_Header: Digital Output Header| +| struct str_DigitalOutputHeader *s_Header: Digital Output Header| | Pointer | +----------------------------------------------------------------------------+ | Output Parameters : - | @@ -984,11 +982,11 @@ INT i_EepromReadDigitalInputHeader(WORD w_PCIBoardEepromAddress, | Return Value : 0 | +----------------------------------------------------------------------------+ */ -INT i_EepromReadDigitalOutputHeader(WORD w_PCIBoardEepromAddress, - char *pc_PCIChipInformation, WORD w_Address, - str_DigitalOutputHeader * s_Header) +int i_EepromReadDigitalOutputHeader(unsigned short w_PCIBoardEepromAddress, + char *pc_PCIChipInformation, unsigned short w_Address, + struct str_DigitalOutputHeader *s_Header) { -// Read Nbr channels +/* Read Nbr channels */ s_Header->w_Nchannel = w_EepromReadWord(w_PCIBoardEepromAddress, pc_PCIChipInformation, 0x100 + w_Address + 6); @@ -997,17 +995,17 @@ INT i_EepromReadDigitalOutputHeader(WORD w_PCIBoardEepromAddress, /* +----------------------------------------------------------------------------+ -| Function Name : INT i_EepromReadTimerHeader(WORD w_PCIBoardEepromAddress, | +| Function Name : int i_EepromReadTimerHeader(unsigned short w_PCIBoardEepromAddress, | | char *pc_PCIChipInformation,WORD w_Address, | -| str_TimerMainHeader *s_Header) | +| struct str_TimerMainHeader *s_Header) | +----------------------------------------------------------------------------+ | Task : Read Timer or Watchdog Header | +----------------------------------------------------------------------------+ -| Input Parameters : WORD w_PCIBoardEepromAddress : PCI eeprom address | +| Input Parameters : unsigned short w_PCIBoardEepromAddress : PCI eeprom address | | | | char *pc_PCIChipInformation : PCI Chip Type. | | | -| str_TimerMainHeader *s_Header: Timer Header | +| struct str_TimerMainHeader *s_Header: Timer Header | | Pointer | +----------------------------------------------------------------------------+ | Output Parameters : - | @@ -1015,18 +1013,18 @@ INT i_EepromReadDigitalOutputHeader(WORD w_PCIBoardEepromAddress, | Return Value : 0 | +----------------------------------------------------------------------------+ */ -INT i_EepromReadTimerHeader(WORD w_PCIBoardEepromAddress, - char *pc_PCIChipInformation, WORD w_Address, - str_TimerMainHeader * s_Header) +int i_EepromReadTimerHeader(unsigned short w_PCIBoardEepromAddress, + char *pc_PCIChipInformation, unsigned short w_Address, + struct str_TimerMainHeader *s_Header) { - WORD i, w_Size = 0, w_Temp; + unsigned short i, w_Size = 0, w_Temp; -//Read No of Timer +/* Read No of Timer */ s_Header->w_Ntimer = w_EepromReadWord(w_PCIBoardEepromAddress, pc_PCIChipInformation, 0x100 + w_Address + 6); -//Read header size +/* Read header size */ for (i = 0; i < s_Header->w_Ntimer; i++) { s_Header->s_TimerDetails[i].w_HeaderSize = @@ -1037,23 +1035,23 @@ INT i_EepromReadTimerHeader(WORD w_PCIBoardEepromAddress, pc_PCIChipInformation, 0x100 + w_Address + 8 + w_Size + 2); - //Read Resolution + /* Read Resolution */ s_Header->s_TimerDetails[i].b_Resolution = - (BYTE) (w_Temp >> 10) & 0x3F; + (unsigned char) (w_Temp >> 10) & 0x3F; - //Read Mode + /* Read Mode */ s_Header->s_TimerDetails[i].b_Mode = - (BYTE) (w_Temp >> 4) & 0x3F; + (unsigned char) (w_Temp >> 4) & 0x3F; w_Temp = w_EepromReadWord(w_PCIBoardEepromAddress, pc_PCIChipInformation, 0x100 + w_Address + 8 + w_Size + 4); - //Read MinTiming + /* Read MinTiming */ s_Header->s_TimerDetails[i].w_MinTiming = (w_Temp >> 6) & 0x3FF; - //Read Timebase - s_Header->s_TimerDetails[i].b_TimeBase = (BYTE) (w_Temp) & 0x3F; + /* Read Timebase */ + s_Header->s_TimerDetails[i].b_TimeBase = (unsigned char) (w_Temp) & 0x3F; w_Size += s_Header->s_TimerDetails[i].w_HeaderSize; } @@ -1062,13 +1060,13 @@ INT i_EepromReadTimerHeader(WORD w_PCIBoardEepromAddress, /* +----------------------------------------------------------------------------+ -| Function Name : INT i_EepromReadAnlogOutputHeader(WORD | +| Function Name : int i_EepromReadAnlogOutputHeader(unsigned short | | w_PCIBoardEepromAddress,char *pc_PCIChipInformation, | -| WORD w_Address,str_AnalogOutputHeader *s_Header) | +| unsigned short w_Address,str_AnalogOutputHeader *s_Header) | +----------------------------------------------------------------------------+ | Task : Read Nalog Output Header | +----------------------------------------------------------------------------+ -| Input Parameters : WORD w_PCIBoardEepromAddress : PCI eeprom address | +| Input Parameters : unsigned short w_PCIBoardEepromAddress : PCI eeprom address | | | | char *pc_PCIChipInformation : PCI Chip Type. | | | @@ -1081,35 +1079,35 @@ INT i_EepromReadTimerHeader(WORD w_PCIBoardEepromAddress, +----------------------------------------------------------------------------+ */ -INT i_EepromReadAnlogOutputHeader(WORD w_PCIBoardEepromAddress, - char *pc_PCIChipInformation, WORD w_Address, - str_AnalogOutputHeader * s_Header) +int i_EepromReadAnlogOutputHeader(unsigned short w_PCIBoardEepromAddress, + char *pc_PCIChipInformation, unsigned short w_Address, + str_AnalogOutputHeader *s_Header) { - WORD w_Temp; - // No of channels for 1st hard component + unsigned short w_Temp; + /* No of channels for 1st hard component */ w_Temp = w_EepromReadWord(w_PCIBoardEepromAddress, pc_PCIChipInformation, 0x100 + w_Address + 10); s_Header->w_Nchannel = (w_Temp >> 4) & 0x03FF; - // Resolution for 1st hard component + /* Resolution for 1st hard component */ w_Temp = w_EepromReadWord(w_PCIBoardEepromAddress, pc_PCIChipInformation, 0x100 + w_Address + 16); - s_Header->b_Resolution = (BYTE) (w_Temp >> 8) & 0xFF; + s_Header->b_Resolution = (unsigned char) (w_Temp >> 8) & 0xFF; return 0; } /* +----------------------------------------------------------------------------+ -| Function Name : INT i_EepromReadAnlogInputHeader(WORD | +| Function Name : int i_EepromReadAnlogInputHeader(unsigned short | | w_PCIBoardEepromAddress,char *pc_PCIChipInformation, | -| WORD w_Address,str_AnalogInputHeader *s_Header) | +| unsigned short w_Address,struct str_AnalogInputHeader *s_Header) | +----------------------------------------------------------------------------+ | Task : Read Nalog Output Header | +----------------------------------------------------------------------------+ -| Input Parameters : WORD w_PCIBoardEepromAddress : PCI eeprom address | +| Input Parameters : unsigned short w_PCIBoardEepromAddress : PCI eeprom address | | | | char *pc_PCIChipInformation : PCI Chip Type. | | | -| str_AnalogInputHeader *s_Header:Anlog Input Header | +| struct str_AnalogInputHeader *s_Header:Anlog Input Header | | Pointer | +----------------------------------------------------------------------------+ | Output Parameters : - | @@ -1118,12 +1116,12 @@ INT i_EepromReadAnlogOutputHeader(WORD w_PCIBoardEepromAddress, +----------------------------------------------------------------------------+ */ -// Reads only for ONE hardware component -INT i_EepromReadAnlogInputHeader(WORD w_PCIBoardEepromAddress, - char *pc_PCIChipInformation, WORD w_Address, - str_AnalogInputHeader * s_Header) +/* Reads only for ONE hardware component */ +int i_EepromReadAnlogInputHeader(unsigned short w_PCIBoardEepromAddress, + char *pc_PCIChipInformation, unsigned short w_Address, + struct str_AnalogInputHeader *s_Header) { - WORD w_Temp, w_Offset; + unsigned short w_Temp, w_Offset; w_Temp = w_EepromReadWord(w_PCIBoardEepromAddress, pc_PCIChipInformation, 0x100 + w_Address + 10); s_Header->w_Nchannel = (w_Temp >> 4) & 0x03FF; @@ -1135,24 +1133,24 @@ INT i_EepromReadAnlogInputHeader(WORD w_PCIBoardEepromAddress, 0x100 + w_Address + 30); w_Temp = w_EepromReadWord(w_PCIBoardEepromAddress, pc_PCIChipInformation, 0x100 + w_Address + 20); - s_Header->b_HasDma = (w_Temp >> 13) & 0x01; // whether dma present or not + s_Header->b_HasDma = (w_Temp >> 13) & 0x01; /* whether dma present or not */ - w_Temp = w_EepromReadWord(w_PCIBoardEepromAddress, pc_PCIChipInformation, 0x100 + w_Address + 72); // reading Y + w_Temp = w_EepromReadWord(w_PCIBoardEepromAddress, pc_PCIChipInformation, 0x100 + w_Address + 72); /* reading Y */ w_Temp = w_Temp & 0x00FF; - if (w_Temp) //Y>0 + if (w_Temp) /* Y>0 */ { - w_Offset = 74 + (2 * w_Temp) + (10 * (1 + (w_Temp / 16))); // offset of first analog input single header - w_Offset = w_Offset + 2; // resolution - } else //Y=0 + w_Offset = 74 + (2 * w_Temp) + (10 * (1 + (w_Temp / 16))); /* offset of first analog input single header */ + w_Offset = w_Offset + 2; /* resolution */ + } else /* Y=0 */ { w_Offset = 74; - w_Offset = w_Offset + 2; // resolution + w_Offset = w_Offset + 2; /* resolution */ } -// read Resolution +/* read Resolution */ w_Temp = w_EepromReadWord(w_PCIBoardEepromAddress, pc_PCIChipInformation, 0x100 + w_Address + w_Offset); - s_Header->b_Resolution = w_Temp & 0x001F; // last 5 bits + s_Header->b_Resolution = w_Temp & 0x001F; /* last 5 bits */ return 0; } diff --git a/drivers/staging/comedi/drivers/addi-data/amcc_s5933_58.h b/drivers/staging/comedi/drivers/addi-data/amcc_s5933_58.h index 617dc087dcbf..b76f877f250a 100644 --- a/drivers/staging/comedi/drivers/addi-data/amcc_s5933_58.h +++ b/drivers/staging/comedi/drivers/addi-data/amcc_s5933_58.h @@ -31,15 +31,15 @@ *************************/ -#define FIFO_ADVANCE_ON_BYTE_2 0x20000000 // written on base0 +#define FIFO_ADVANCE_ON_BYTE_2 0x20000000 /* written on base0 */ -#define AMWEN_ENABLE 0x02 // added for step 6 dma written on base2 +#define AMWEN_ENABLE 0x02 /* added for step 6 dma written on base2 */ #define A2P_FIFO_WRITE_ENABLE 0x01 -#define AGCSTS_TC_ENABLE 0x10000000 // Added for transfer count enable bit +#define AGCSTS_TC_ENABLE 0x10000000 /* Added for transfer count enable bit */ -// ADDON RELATED ADDITIONS -// Constant +/* ADDON RELATED ADDITIONS */ +/* Constant */ #define APCI3120_ENABLE_TRANSFER_ADD_ON_LOW 0x00 #define APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH 0x1200 #define APCI3120_A2P_FIFO_MANAGEMENT 0x04000400L @@ -52,7 +52,7 @@ #define APCI3120_DISABLE_BUS_MASTER_ADD_ON 0x0 #define APCI3120_DISABLE_BUS_MASTER_PCI 0x0 - // ADD_ON ::: this needed since apci supports 16 bit interface to add on + /* ADD_ON ::: this needed since apci supports 16 bit interface to add on */ #define APCI3120_ADD_ON_AGCSTS_LOW 0x3C #define APCI3120_ADD_ON_AGCSTS_HIGH APCI3120_ADD_ON_AGCSTS_LOW + 2 #define APCI3120_ADD_ON_MWAR_LOW 0x24 @@ -60,7 +60,7 @@ #define APCI3120_ADD_ON_MWTC_LOW 0x058 #define APCI3120_ADD_ON_MWTC_HIGH APCI3120_ADD_ON_MWTC_LOW + 2 -// AMCC +/* AMCC */ #define APCI3120_AMCC_OP_MCSR 0x3C #define APCI3120_AMCC_OP_REG_INTCSR 0x38 @@ -85,7 +85,7 @@ #define AMCC_OP_REG_MRTC 0x30 #define AMCC_OP_REG_MBEF 0x34 #define AMCC_OP_REG_INTCSR 0x38 -#define AMCC_OP_REG_INTCSR_SRC (AMCC_OP_REG_INTCSR + 2) /* INT source */ +#define AMCC_OP_REG_INTCSR_SRC (AMCC_OP_REG_INTCSR + 2) /* int source */ #define AMCC_OP_REG_INTCSR_FEC (AMCC_OP_REG_INTCSR + 3) /* FIFO ctrl */ #define AMCC_OP_REG_MCSR 0x3c #define AMCC_OP_REG_MCSR_NVDATA (AMCC_OP_REG_MCSR + 2) /* Data in byte 2 */ @@ -212,7 +212,7 @@ struct pcilst_struct { unsigned int irq; }; -struct pcilst_struct *amcc_devices; // ptr to root list of all amcc devices +struct pcilst_struct *amcc_devices; /* ptr to root list of all amcc devices */ /****************************************************************************/ @@ -267,7 +267,7 @@ void v_pci_card_list_init(unsigned short pci_vendor, char display) amcc->vendor = pcidev->vendor; amcc->device = pcidev->device; #if 0 - amcc->master = pcidev->master; // how get this information under 2.4 kernels? + amcc->master = pcidev->master; /* how get this information under 2.4 kernels? */ #endif amcc->pci_bus = pcidev->bus->number; amcc->pci_slot = PCI_SLOT(pcidev->devfn); @@ -333,17 +333,17 @@ int i_find_free_pci_card_by_position(unsigned short vendor_id, && (amcc->pci_slot == pci_slot)) { if (!(amcc->used)) { *card = amcc; - return 0; // ok, card is found + return 0; /* ok, card is found */ } else { - rt_printk + printk (" - \nCard on requested position is used b:s %d:%d!\n", pci_bus, pci_slot); - return 2; // card exist but is used + return 2; /* card exist but is used */ } } } - return 1; // no card found + return 1; /* no card found */ } /****************************************************************************/ @@ -422,11 +422,10 @@ struct pcilst_struct *ptr_select_and_alloc_pci_card(unsigned short vendor_id, { struct pcilst_struct *card; - if ((pci_bus < 1) & (pci_slot < 1)) { // use autodetection - if ((card = ptr_find_free_pci_card_by_device(vendor_id, - device_id)) == - NULL) { - rt_printk(" - Unused card not found in system!\n"); + if ((pci_bus < 1) & (pci_slot < 1)) { /* use autodetection */ + card = ptr_find_free_pci_card_by_device(vendor_id, device_id); + if (card == NULL) { + printk(" - Unused card not found in system!\n"); return NULL; } } else { @@ -434,12 +433,12 @@ struct pcilst_struct *ptr_select_and_alloc_pci_card(unsigned short vendor_id, pci_bus, pci_slot, &card)) { case 1: - rt_printk + printk (" - Card not found on requested position b:s %d:%d!\n", pci_bus, pci_slot); return NULL; case 2: - rt_printk + printk (" - Card on requested position is used b:s %d:%d!\n", pci_bus, pci_slot); return NULL; @@ -447,7 +446,7 @@ struct pcilst_struct *ptr_select_and_alloc_pci_card(unsigned short vendor_id, } if (i_pci_card_alloc(card) != 0) { - rt_printk(" - Can't allocate card!\n"); + printk(" - Can't allocate card!\n"); return NULL; } diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.c index 3f8929c09070..47517a938ec5 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.c @@ -1,15 +1,15 @@ -/** +//** @verbatim Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data-com - info@addi-data.com + ADDI-DATA GmbH + Dieselstrasse 3 + D-77833 Ottersweier + Tel: +19(0)7223/9493-0 + Fax: +49(0)7223/9493-92 + http://www.addi-data-com + info@addi-data.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. @@ -56,21 +56,22 @@ You shoud also find the complete GPL in the COPYING file accompanying this sourc #include "APCI1710_Pwm.c" #include "APCI1710_INCCPT.c" -void i_ADDI_AttachPCI1710(struct comedi_device * dev) +void i_ADDI_AttachPCI1710(struct comedi_device *dev) { struct comedi_subdevice *s; int ret = 0; int n_subdevices = 9; - //Update-0.7.57->0.7.68dev->n_subdevices = 9; - if ((ret = alloc_subdevices(dev, n_subdevices)) < 0) + /* Update-0.7.57->0.7.68dev->n_subdevices = 9; */ + ret = alloc_subdevices(dev, n_subdevices); + if (ret < 0) return; - // Allocate and Initialise Timer Subdevice Structures + /* Allocate and Initialise Timer Subdevice Structures */ s = dev->subdevices + 0; s->type = COMEDI_SUBD_TIMER; - s->subdev_flags = SDF_WRITEABLE | SDF_RT | SDF_GROUND | SDF_COMMON; + s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON; s->n_chan = 3; s->maxdata = 0; s->len_chanlist = 3; @@ -80,12 +81,12 @@ void i_ADDI_AttachPCI1710(struct comedi_device * dev) s->insn_config = i_APCI1710_InsnConfigInitTimer; s->insn_bits = i_APCI1710_InsnBitsTimer; - // Allocate and Initialise DIO Subdevice Structures + /* Allocate and Initialise DIO Subdevice Structures */ s = dev->subdevices + 1; s->type = COMEDI_SUBD_DIO; s->subdev_flags = - SDF_WRITEABLE | SDF_READABLE | SDF_RT | SDF_GROUND | SDF_COMMON; + SDF_WRITEABLE | SDF_READABLE | SDF_GROUND | SDF_COMMON; s->n_chan = 7; s->maxdata = 1; s->len_chanlist = 7; @@ -95,11 +96,11 @@ void i_ADDI_AttachPCI1710(struct comedi_device * dev) s->insn_bits = i_APCI1710_InsnBitsDigitalIOPortOnOff; s->insn_write = i_APCI1710_InsnWriteDigitalIOChlOnOff; - // Allocate and Initialise Chrono Subdevice Structures + /* Allocate and Initialise Chrono Subdevice Structures */ s = dev->subdevices + 2; s->type = COMEDI_SUBD_CHRONO; - s->subdev_flags = SDF_WRITEABLE | SDF_RT | SDF_GROUND | SDF_COMMON; + s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON; s->n_chan = 4; s->maxdata = 0; s->len_chanlist = 4; @@ -109,55 +110,55 @@ void i_ADDI_AttachPCI1710(struct comedi_device * dev) s->insn_config = i_APCI1710_InsnConfigInitChrono; s->insn_bits = i_APCI1710_InsnBitsChronoDigitalIO; - // Allocate and Initialise PWM Subdevice Structures + /* Allocate and Initialise PWM Subdevice Structures */ s = dev->subdevices + 3; s->type = COMEDI_SUBD_PWM; s->subdev_flags = - SDF_WRITEABLE | SDF_READABLE | SDF_RT | SDF_GROUND | SDF_COMMON; + SDF_WRITEABLE | SDF_READABLE | SDF_GROUND | SDF_COMMON; s->n_chan = 3; s->maxdata = 1; s->len_chanlist = 3; s->range_table = &range_digital; - s->io_bits = 0; //all bits input + s->io_bits = 0; /* all bits input */ s->insn_config = i_APCI1710_InsnConfigPWM; s->insn_read = i_APCI1710_InsnReadGetPWMStatus; s->insn_write = i_APCI1710_InsnWritePWM; s->insn_bits = i_APCI1710_InsnBitsReadPWMInterrupt; - // Allocate and Initialise TTLIO Subdevice Structures + /* Allocate and Initialise TTLIO Subdevice Structures */ s = dev->subdevices + 4; s->type = COMEDI_SUBD_TTLIO; s->subdev_flags = - SDF_WRITEABLE | SDF_READABLE | SDF_RT | SDF_GROUND | SDF_COMMON; + SDF_WRITEABLE | SDF_READABLE | SDF_GROUND | SDF_COMMON; s->n_chan = 8; s->maxdata = 1; s->len_chanlist = 8; - s->range_table = &range_apci1710_ttl; // to pass arguments in range + s->range_table = &range_apci1710_ttl; /* to pass arguments in range */ s->insn_config = i_APCI1710_InsnConfigInitTTLIO; s->insn_bits = i_APCI1710_InsnBitsReadTTLIO; s->insn_write = i_APCI1710_InsnWriteSetTTLIOChlOnOff; s->insn_read = i_APCI1710_InsnReadTTLIOAllPortValue; - // Allocate and Initialise TOR Subdevice Structures + /* Allocate and Initialise TOR Subdevice Structures */ s = dev->subdevices + 5; s->type = COMEDI_SUBD_TOR; s->subdev_flags = - SDF_WRITEABLE | SDF_READABLE | SDF_RT | SDF_GROUND | SDF_COMMON; + SDF_WRITEABLE | SDF_READABLE | SDF_GROUND | SDF_COMMON; s->n_chan = 8; s->maxdata = 1; s->len_chanlist = 8; s->range_table = &range_digital; - s->io_bits = 0; //all bits input + s->io_bits = 0; /* all bits input */ s->insn_config = i_APCI1710_InsnConfigInitTorCounter; s->insn_read = i_APCI1710_InsnReadGetTorCounterInitialisation; s->insn_write = i_APCI1710_InsnWriteEnableDisableTorCounter; s->insn_bits = i_APCI1710_InsnBitsGetTorCounterProgressStatusAndValue; - // Allocate and Initialise SSI Subdevice Structures + /* Allocate and Initialise SSI Subdevice Structures */ s = dev->subdevices + 6; s->type = COMEDI_SUBD_SSI; s->subdev_flags = - SDF_WRITEABLE | SDF_READABLE | SDF_RT | SDF_GROUND | SDF_COMMON; + SDF_WRITEABLE | SDF_READABLE | SDF_GROUND | SDF_COMMON; s->n_chan = 4; s->maxdata = 1; s->len_chanlist = 4; @@ -166,11 +167,11 @@ void i_ADDI_AttachPCI1710(struct comedi_device * dev) s->insn_read = i_APCI1710_InsnReadSSIValue; s->insn_bits = i_APCI1710_InsnBitsSSIDigitalIO; - // Allocate and Initialise PULSEENCODER Subdevice Structures + /* Allocate and Initialise PULSEENCODER Subdevice Structures */ s = dev->subdevices + 7; s->type = COMEDI_SUBD_PULSEENCODER; s->subdev_flags = - SDF_WRITEABLE | SDF_READABLE | SDF_RT | SDF_GROUND | SDF_COMMON; + SDF_WRITEABLE | SDF_READABLE | SDF_GROUND | SDF_COMMON; s->n_chan = 4; s->maxdata = 1; s->len_chanlist = 4; @@ -180,11 +181,11 @@ void i_ADDI_AttachPCI1710(struct comedi_device * dev) s->insn_bits = i_APCI1710_InsnBitsReadWritePulseEncoder; s->insn_read = i_APCI1710_InsnReadInterruptPulseEncoder; - // Allocate and Initialise INCREMENTALCOUNTER Subdevice Structures + /* Allocate and Initialise INCREMENTALCOUNTER Subdevice Structures */ s = dev->subdevices + 8; s->type = COMEDI_SUBD_INCREMENTALCOUNTER; s->subdev_flags = - SDF_WRITEABLE | SDF_READABLE | SDF_RT | SDF_GROUND | SDF_COMMON; + SDF_WRITEABLE | SDF_READABLE | SDF_GROUND | SDF_COMMON; s->n_chan = 500; s->maxdata = 1; s->len_chanlist = 500; @@ -195,14 +196,14 @@ void i_ADDI_AttachPCI1710(struct comedi_device * dev) s->insn_bits = i_APCI1710_InsnBitsINCCPT; } -int i_APCI1710_Reset(struct comedi_device * dev); +int i_APCI1710_Reset(struct comedi_device *dev); void v_APCI1710_Interrupt(int irq, void *d); -//for 1710 +/* for 1710 */ -int i_APCI1710_Reset(struct comedi_device * dev) +int i_APCI1710_Reset(struct comedi_device *dev) { int ret; - DWORD dw_Dummy; + unsigned int dw_Dummy; /*********************************/ /* Read all module configuration */ @@ -219,12 +220,12 @@ int i_APCI1710_Reset(struct comedi_device * dev) ret = inl(devpriv->s_BoardInfos.ui_Address + 252); devpriv->s_BoardInfos.dw_MolduleConfiguration[3] = ret; - // outl(0x80808082,devpriv->s_BoardInfos.ui_Address+0x60); + /* outl(0x80808082,devpriv->s_BoardInfos.ui_Address+0x60); */ outl(0x83838383, devpriv->s_BoardInfos.ui_Address + 0x60); devpriv->s_BoardInfos.b_BoardVersion = 1; - // Enable the interrupt for the controler + /* Enable the interrupt for the controler */ dw_Dummy = inl(devpriv->s_BoardInfos.ui_Address + 0x38); outl(dw_Dummy | 0x2000, devpriv->s_BoardInfos.ui_Address + 0x38); @@ -234,11 +235,11 @@ int i_APCI1710_Reset(struct comedi_device * dev) /* +----------------------------------------------------------------------------+ | Function's Name : __void__ v_APCI1710_InterruptFunction | -| (BYTE b_Interrupt, __CPPARGS) | +| (unsigned char b_Interrupt, __CPPARGS) | +----------------------------------------------------------------------------+ | Task : APCI-1710 interrupt function | +----------------------------------------------------------------------------+ -| Input Parameters : BYTE b_Interrupt : Interrupt number | +| Input Parameters : unsigned char b_Interrupt : Interrupt number | +----------------------------------------------------------------------------+ | Output Parameters : - | +----------------------------------------------------------------------------+ @@ -250,18 +251,18 @@ int i_APCI1710_Reset(struct comedi_device * dev) void v_APCI1710_Interrupt(int irq, void *d) { struct comedi_device *dev = d; - BYTE b_ModuleCpt = 0; - BYTE b_InterruptFlag = 0; - BYTE b_PWMCpt = 0; - BYTE b_TorCounterCpt = 0; - BYTE b_PulseIncoderCpt = 0; - UINT ui_16BitValue; - ULONG ul_InterruptLatchReg = 0; - ULONG ul_LatchRegisterValue = 0; - ULONG ul_82X54InterruptStatus; - ULONG ul_StatusRegister; + unsigned char b_ModuleCpt = 0; + unsigned char b_InterruptFlag = 0; + unsigned char b_PWMCpt = 0; + unsigned char b_TorCounterCpt = 0; + unsigned char b_PulseIncoderCpt = 0; + unsigned int ui_16BitValue; + unsigned int ul_InterruptLatchReg = 0; + unsigned int ul_LatchRegisterValue = 0; + unsigned int ul_82X54InterruptStatus; + unsigned int ul_StatusRegister; - str_ModuleInfo *ps_ModuleInfo; + union str_ModuleInfo *ps_ModuleInfo; printk("APCI1710 Interrupt\n"); for (b_ModuleCpt = 0; b_ModuleCpt < 4; b_ModuleCpt++, ps_ModuleInfo++) { @@ -279,7 +280,7 @@ void v_APCI1710_Interrupt(int irq, void *d) dw_MolduleConfiguration[b_ModuleCpt] & 0xFFFF0000UL) == APCI1710_82X54_TIMER) { - //printk("TIMER Interrupt Occurred\n"); + /* printk("TIMER Interrupt Occurred\n"); */ ul_82X54InterruptStatus = inl(devpriv->s_BoardInfos. ui_Address + 12 + (64 * b_ModuleCpt)); @@ -332,11 +333,11 @@ void v_APCI1710_Interrupt(int irq, void *d) /**********************/ /* Call user function */ /**********************/ - //Send a signal to from kernel to user space + /* Send a signal to from kernel to user space */ send_sig(SIGIO, devpriv->tsk_Current, 0); - } // if ((ul_82X54InterruptStatus & 0x7) != 0) - } // 82X54 timer + } /* if ((ul_82X54InterruptStatus & 0x7) != 0) */ + } /* 82X54 timer */ /***************************/ /* Test if increm. counter */ @@ -412,7 +413,7 @@ void v_APCI1710_Interrupt(int irq, void *d) /**********************/ /* Call user function */ /**********************/ - //Send a signal to from kernel to user space + /* Send a signal to from kernel to user space */ send_sig(SIGIO, devpriv->tsk_Current, 0); @@ -473,7 +474,7 @@ void v_APCI1710_Interrupt(int irq, void *d) /**********************/ /* Call user function */ /**********************/ - //Send a signal to from kernel to user space + /* Send a signal to from kernel to user space */ send_sig(SIGIO, devpriv->tsk_Current, 0); @@ -562,7 +563,7 @@ void v_APCI1710_Interrupt(int irq, void *d) /**********************/ /* Call user function */ /**********************/ - //Send a signal to from kernel to user space + /* Send a signal to from kernel to user space */ send_sig(SIGIO, devpriv->tsk_Current, 0); @@ -628,7 +629,7 @@ void v_APCI1710_Interrupt(int irq, void *d) /**********************/ /* Call user function */ /**********************/ - //Send a signal to from kernel to user space + /* Send a signal to from kernel to user space */ send_sig(SIGIO, devpriv->tsk_Current, 0); @@ -675,7 +676,7 @@ void v_APCI1710_Interrupt(int irq, void *d) if ((ul_LatchRegisterValue & 0xFFFFU) != 0) { ui_16BitValue = - (UINT) + (unsigned int) ul_LatchRegisterValue & 0xFFFFU; ul_LatchRegisterValue = @@ -693,7 +694,7 @@ void v_APCI1710_Interrupt(int irq, void *d) 0xFFFF0000UL) != 0) { ui_16BitValue = - (UINT) ( + (unsigned int) ( (ul_LatchRegisterValue >> 16) & 0xFFFFU); @@ -721,7 +722,7 @@ void v_APCI1710_Interrupt(int irq, void *d) if ((ul_LatchRegisterValue & 0xFFFF0000UL) != 0) { ui_16BitValue = - (UINT) ( + (unsigned int) ( (ul_LatchRegisterValue >> 16) & 0xFFFFU); @@ -741,7 +742,7 @@ void v_APCI1710_Interrupt(int irq, void *d) if ((ul_LatchRegisterValue & 0xFFFFU) != 0) { ui_16BitValue = - (UINT) + (unsigned int) ul_LatchRegisterValue & 0xFFFFU; ul_LatchRegisterValue = @@ -795,11 +796,11 @@ void v_APCI1710_Interrupt(int irq, void *d) /**********************/ /* Call user function */ /**********************/ - //Send a signal to from kernel to user space + /* Send a signal to from kernel to user space */ send_sig(SIGIO, devpriv->tsk_Current, 0); } - } // Incremental counter + } /* Incremental counter */ /***************/ /* Test if CDA */ @@ -870,14 +871,14 @@ void v_APCI1710_Interrupt(int irq, void *d) /* Call user function */ /**********************/ - //Send a signal to from kernel to user space + /* Send a signal to from kernel to user space */ send_sig(SIGIO, devpriv->tsk_Current, 0); - } // if (ul_StatusRegister & 1) + } /* if (ul_StatusRegister & 1) */ } - } // CDA + } /* CDA */ /***********************/ /* Test if PWM counter */ @@ -950,15 +951,15 @@ void v_APCI1710_Interrupt(int irq, void *d) /**********************/ /* Call user function */ /**********************/ - //Send a signal to from kernel to user space + /* Send a signal to from kernel to user space */ send_sig(SIGIO, devpriv->tsk_Current, 0); - } // if (ul_StatusRegister & 0x1) - } // if (APCI1710_ENABLE) - } // for (b_PWMCpt == 0; b_PWMCpt < 0; b_PWMCpt ++) - } // PWM counter + } /* if (ul_StatusRegister & 0x1) */ + } /* if (APCI1710_ENABLE) */ + } /* for (b_PWMCpt == 0; b_PWMCpt < 0; b_PWMCpt ++) */ + } /* PWM counter */ /***********************/ /* Test if tor counter */ @@ -1054,14 +1055,14 @@ void v_APCI1710_Interrupt(int irq, void *d) /* Call user function */ /**********************/ - //Send a signal to from kernel to user space + /* Send a signal to from kernel to user space */ send_sig(SIGIO, devpriv->tsk_Current, 0); - } // if (ul_StatusRegister & 0x1) - } // if (APCI1710_ENABLE) - } // for (b_TorCounterCpt == 0; b_TorCounterCpt < 0; b_TorCounterCpt ++) - } // Tor counter + } /* if (ul_StatusRegister & 0x1) */ + } /* if (APCI1710_ENABLE) */ + } /* for (b_TorCounterCpt == 0; b_TorCounterCpt < 0; b_TorCounterCpt ++) */ + } /* Tor counter */ /***********************/ /* Test if chronometer */ @@ -1071,7 +1072,7 @@ void v_APCI1710_Interrupt(int irq, void *d) dw_MolduleConfiguration[b_ModuleCpt] & 0xFFFF0000UL) == APCI1710_CHRONOMETER) { - //printk("APCI1710 Chrono Interrupt\n"); + /* printk("APCI1710 Chrono Interrupt\n"); */ /*****************************/ /* Read the interrupt status */ /*****************************/ @@ -1163,13 +1164,13 @@ void v_APCI1710_Interrupt(int irq, void *d) /**********************/ /* Call user function */ /**********************/ - //Send a signal to from kernel to user space + /* Send a signal to from kernel to user space */ send_sig(SIGIO, devpriv->tsk_Current, 0); } } - } // Chronometer + } /* Chronometer */ /*************************/ /* Test if pulse encoder */ @@ -1249,7 +1250,7 @@ void v_APCI1710_Interrupt(int irq, void *d) /**********************/ /* Call user function */ /**********************/ - //Send a signal to from kernel to user space + /* Send a signal to from kernel to user space */ send_sig(SIGIO, devpriv->tsk_Current, 0); @@ -1257,7 +1258,7 @@ void v_APCI1710_Interrupt(int irq, void *d) } } } - } //pulse encoder + } /* pulse encoder */ } return; diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.h b/drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.h index 998cbba8afeb..22b3e569ecd5 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.h +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.h @@ -44,7 +44,7 @@ #define APCI1710_SYNCHRONOUS_MODE 1 #define APCI1710_ASYNCHRONOUS_MODE 0 -//MODULE INFO STRUCTURE +/* MODULE INFO STRUCTURE */ static const struct comedi_lrange range_apci1710_ttl = { 4, { BIP_RANGE(10), diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c index e4527926c2df..016721efdbfb 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c @@ -3,13 +3,13 @@ Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data-com - info@addi-data.com + ADDI-DATA GmbH + Dieselstrasse 3 + D-77833 Ottersweier + Tel: +19(0)7223/9493-0 + Fax: +49(0)7223/9493-92 + http://www.addi-data-com + info@addi-data.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. @@ -52,9 +52,9 @@ You shoud also find the complete GPL in the COPYING file accompanying this sourc +----------------------------------------------------------------------------+ */ #include "hwdrv_apci035.h" -INT i_WatchdogNbr = 0; -INT i_Temp = 0; -INT i_Flag = 1; +int i_WatchdogNbr = 0; +int i_Temp = 0; +int i_Flag = 1; /* +----------------------------------------------------------------------------+ | Function Name : int i_APCI035_ConfigTimerWatchdog | @@ -64,42 +64,42 @@ INT i_Flag = 1; | Task : Configures The Timer , Counter or Watchdog | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | -| UINT *data : Data Pointer contains | +| unsigned int *data : Data Pointer contains | | configuration parameters as below | | | | data[0] : 0 Configure As Timer | | 1 Configure As Watchdog | - data[1] : Watchdog number +| data[1] : Watchdog number | data[2] : Time base Unit | | data[3] : Reload Value | - data[4] : External Trigger | - 1:Enable - 0:Disable - data[5] :External Trigger Level - 00 Trigger Disabled - 01 Trigger Enabled (Low level) - 10 Trigger Enabled (High Level) - 11 Trigger Enabled (High/Low level) - data[6] : External Gate | - 1:Enable - 0:Disable - data[7] : External Gate level - 00 Gate Disabled - 01 Gate Enabled (Low level) - 10 Gate Enabled (High Level) - data[8] :Warning Relay - 1: ENABLE - 0: DISABLE - data[9] :Warning Delay available - data[10] :Warning Relay Time unit - data[11] :Warning Relay Time Reload value - data[12] :Reset Relay - 1 : ENABLE - 0 : DISABLE - data[13] :Interrupt - 1 : ENABLE - 0 : DISABLE - +| data[4] : External Trigger | +| 1:Enable +| 0:Disable +| data[5] :External Trigger Level +| 00 Trigger Disabled +| 01 Trigger Enabled (Low level) +| 10 Trigger Enabled (High Level) +| 11 Trigger Enabled (High/Low level) +| data[6] : External Gate | +| 1:Enable +| 0:Disable +| data[7] : External Gate level +| 00 Gate Disabled +| 01 Gate Enabled (Low level) +| 10 Gate Enabled (High Level) +| data[8] :Warning Relay +| 1: ENABLE +| 0: DISABLE +| data[9] :Warning Delay available +| data[10] :Warning Relay Time unit +| data[11] :Warning Relay Time Reload value +| data[12] :Reset Relay +| 1 : ENABLE +| 0 : DISABLE +| data[13] :Interrupt +| 1 : ENABLE +| 0 : DISABLE +| | +----------------------------------------------------------------------------+ | Output Parameters : -- | @@ -109,12 +109,12 @@ INT i_Flag = 1; | | +----------------------------------------------------------------------------+ */ -INT i_APCI035_ConfigTimerWatchdog(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI035_ConfigTimerWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - UINT ui_Status = 0; - UINT ui_Command = 0; - UINT ui_Mode = 0; + unsigned int ui_Status = 0; + unsigned int ui_Command = 0; + unsigned int ui_Mode = 0; i_Temp = 0; devpriv->tsk_Current = current; devpriv->b_TimerSelectMode = data[0]; @@ -124,9 +124,9 @@ INT i_APCI035_ConfigTimerWatchdog(struct comedi_device * dev, struct comedi_subd } else { ui_Mode = 0; } -//ui_Command = inl(devpriv->iobase+((i_WatchdogNbr-1)*32)+12); +/* ui_Command = inl(devpriv->iobase+((i_WatchdogNbr-1)*32)+12); */ ui_Command = 0; -//ui_Command = ui_Command & 0xFFFFF9FEUL; +/* ui_Command = ui_Command & 0xFFFFF9FEUL; */ outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); ui_Command = 0; ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); @@ -153,7 +153,7 @@ INT i_APCI035_ConfigTimerWatchdog(struct comedi_device * dev, struct comedi_subd ui_Command = (ui_Command & 0xFFF719E2UL) | ui_Mode << 13UL | 0x10UL; - } //if (data[0] == ADDIDATA_TIMER) + } /* if (data[0] == ADDIDATA_TIMER) */ else { if (data[0] == ADDIDATA_WATCHDOG) { @@ -260,7 +260,7 @@ INT i_APCI035_ConfigTimerWatchdog(struct comedi_device * dev, struct comedi_subd | Task : Start / Stop The Selected Timer , or Watchdog | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | -| UINT *data : Data Pointer contains | +| unsigned int *data : Data Pointer contains | | configuration parameters as below | | | | data[0] : 0 - Stop Selected Timer/Watchdog | @@ -278,11 +278,11 @@ INT i_APCI035_ConfigTimerWatchdog(struct comedi_device * dev, struct comedi_subd | | +----------------------------------------------------------------------------+ */ -INT i_APCI035_StartStopWriteTimerWatchdog(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +int i_APCI035_StartStopWriteTimerWatchdog(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - UINT ui_Command = 0; - INT i_Count = 0; + unsigned int ui_Command = 0; + int i_Count = 0; if (data[0] == 1) { ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); @@ -292,7 +292,7 @@ INT i_APCI035_StartStopWriteTimerWatchdog(struct comedi_device * dev, ui_Command = (ui_Command & 0xFFFFF9FFUL) | 0x1UL; outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - } // if (data[0]==1) + } /* if (data[0]==1) */ if (data[0] == 2) { ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); @@ -304,16 +304,18 @@ INT i_APCI035_StartStopWriteTimerWatchdog(struct comedi_device * dev, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); } - if (data[0] == 0) //Stop The Watchdog + if (data[0] == 0) /* Stop The Watchdog */ { - //Stop The Watchdog + /* Stop The Watchdog */ ui_Command = 0; - //ui_Command = inl(devpriv->iobase+((i_WatchdogNbr-1)*32)+12); - //ui_Command = ui_Command & 0xFFFFF9FEUL; +/* +* ui_Command = inl(devpriv->iobase+((i_WatchdogNbr-1)*32)+12); +* ui_Command = ui_Command & 0xFFFFF9FEUL; +*/ outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - } // if (data[1]==0) - if (data[0] == 3) //stop all Watchdogs + } /* if (data[1]==0) */ + if (data[0] == 3) /* stop all Watchdogs */ { ui_Command = 0; for (i_Count = 1; i_Count <= 4; i_Count++) { @@ -329,7 +331,7 @@ INT i_APCI035_StartStopWriteTimerWatchdog(struct comedi_device * dev, } } - if (data[0] == 4) //start all Watchdogs + if (data[0] == 4) /* start all Watchdogs */ { ui_Command = 0; for (i_Count = 1; i_Count <= 4; i_Count++) { @@ -344,7 +346,7 @@ INT i_APCI035_StartStopWriteTimerWatchdog(struct comedi_device * dev, 0); } } - if (data[0] == 5) //trigger all Watchdogs + if (data[0] == 5) /* trigger all Watchdogs */ { ui_Command = 0; for (i_Count = 1; i_Count <= 4; i_Count++) { @@ -373,17 +375,17 @@ INT i_APCI035_StartStopWriteTimerWatchdog(struct comedi_device * dev, | Task : Read The Selected Timer , Counter or Watchdog | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | -| UINT *data : Data Pointer contains | +| unsigned int *data : Data Pointer contains | | configuration parameters as below | | | | | +----------------------------------------------------------------------------+ | Output Parameters : data[0] : software trigger status - data[1] : hardware trigger status -| data[2] : Software clear status - data[3] : Overflow status - data[4] : Timer actual value - +| data[1] : hardware trigger status +| data[2] : Software clear status +| data[3] : Overflow status +| data[4] : Timer actual value +| +----------------------------------------------------------------------------+ | Return Value : TRUE : No error occur | @@ -391,42 +393,46 @@ INT i_APCI035_StartStopWriteTimerWatchdog(struct comedi_device * dev, | | +----------------------------------------------------------------------------+ */ -INT i_APCI035_ReadTimerWatchdog(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI035_ReadTimerWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - UINT ui_Status = 0; // Status register + unsigned int ui_Status = 0; /* Status register */ i_WatchdogNbr = insn->unused[0]; - /******************/ + + /******************/ /* Get the status */ - /******************/ + /******************/ + ui_Status = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 16); - /***********************************/ + + /***********************************/ /* Get the software trigger status */ - /***********************************/ + /***********************************/ + data[0] = ((ui_Status >> 1) & 1); - /***********************************/ + /***********************************/ /* Get the hardware trigger status */ - /***********************************/ + /***********************************/ data[1] = ((ui_Status >> 2) & 1); - /*********************************/ + /*********************************/ /* Get the software clear status */ - /*********************************/ + /*********************************/ data[2] = ((ui_Status >> 3) & 1); - /***************************/ + /***************************/ /* Get the overflow status */ - /***************************/ + /***************************/ data[3] = ((ui_Status >> 0) & 1); if (devpriv->b_TimerSelectMode == ADDIDATA_TIMER) { data[4] = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 0); - } // if (devpriv->b_TimerSelectMode==ADDIDATA_TIMER) + } /* if (devpriv->b_TimerSelectMode==ADDIDATA_TIMER) */ return insn->n; } /* +----------------------------------------------------------------------------+ -| Function Name : INT i_APCI035_ConfigAnalogInput | +| Function Name : int i_APCI035_ConfigAnalogInput | | (struct comedi_device *dev,struct comedi_subdevice *s, | | struct comedi_insn *insn,unsigned int *data) | +----------------------------------------------------------------------------+ @@ -447,8 +453,8 @@ INT i_APCI035_ReadTimerWatchdog(struct comedi_device * dev, struct comedi_subdev | | +----------------------------------------------------------------------------+ */ -INT i_APCI035_ConfigAnalogInput(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI035_ConfigAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { devpriv->tsk_Current = current; outl(0x200 | 0, devpriv->iobase + 128 + 0x4); @@ -472,8 +478,8 @@ INT i_APCI035_ConfigAnalogInput(struct comedi_device * dev, struct comedi_subdev | Task : Read value of the selected channel | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | -| UINT ui_NoOfChannels : No Of Channels To read | -| UINT *data : Data Pointer to read status | +| unsigned int ui_NoOfChannels : No Of Channels To read | +| unsigned int *data : Data Pointer to read status | +----------------------------------------------------------------------------+ | Output Parameters : -- | | data[0] : Digital Value Of Input | @@ -484,10 +490,10 @@ INT i_APCI035_ConfigAnalogInput(struct comedi_device * dev, struct comedi_subdev | | +----------------------------------------------------------------------------+ */ -INT i_APCI035_ReadAnalogInput(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI035_ReadAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - UINT ui_CommandRegister = 0; + unsigned int ui_CommandRegister = 0; /******************/ /* Set the start */ /******************/ @@ -519,14 +525,14 @@ INT i_APCI035_ReadAnalogInput(struct comedi_device * dev, struct comedi_subdevic | | +----------------------------------------------------------------------------+ */ -INT i_APCI035_Reset(struct comedi_device * dev) +int i_APCI035_Reset(struct comedi_device *dev) { - INT i_Count = 0; + int i_Count = 0; for (i_Count = 1; i_Count <= 4; i_Count++) { i_WatchdogNbr = i_Count; - outl(0x0, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 0); //stop all timers + outl(0x0, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 0); /* stop all timers */ } - outl(0x0, devpriv->iobase + 128 + 12); //Disable the warning delay + outl(0x0, devpriv->iobase + 128 + 12); /* Disable the warning delay */ return 0; } @@ -551,11 +557,11 @@ INT i_APCI035_Reset(struct comedi_device * dev) static void v_APCI035_Interrupt(int irq, void *d) { struct comedi_device *dev = d; - UINT ui_StatusRegister1 = 0; - UINT ui_StatusRegister2 = 0; - UINT ui_ReadCommand = 0; - UINT ui_ChannelNumber = 0; - UINT ui_DigitalTemperature = 0; + unsigned int ui_StatusRegister1 = 0; + unsigned int ui_StatusRegister2 = 0; + unsigned int ui_ReadCommand = 0; + unsigned int ui_ChannelNumber = 0; + unsigned int ui_DigitalTemperature = 0; if (i_Temp == 1) { i_WatchdogNbr = i_Flag; i_Flag = i_Flag + 1; @@ -571,7 +577,7 @@ static void v_APCI035_Interrupt(int irq, void *d) ui_StatusRegister2 = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 20); - if ((((ui_StatusRegister1) & 0x8) == 0x8)) //Test if warning relay interrupt + if ((((ui_StatusRegister1) & 0x8) == 0x8)) /* Test if warning relay interrupt */ { /**********************************/ /* Disable the temperature warning */ @@ -587,14 +593,14 @@ static void v_APCI035_Interrupt(int irq, void *d) /* Read the digital temperature value */ /**************************************/ ui_DigitalTemperature = inl(devpriv->iobase + 128 + 60); - send_sig(SIGIO, devpriv->tsk_Current, 0); // send signal to the sample - } //if (((ui_StatusRegister1 & 0x8) == 0x8)) + send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */ + } /* if (((ui_StatusRegister1 & 0x8) == 0x8)) */ else { if ((ui_StatusRegister2 & 0x1) == 0x1) { - send_sig(SIGIO, devpriv->tsk_Current, 0); // send signal to the sample + send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */ } - } //else if (((ui_StatusRegister1 & 0x8) == 0x8)) + } /* else if (((ui_StatusRegister1 & 0x8) == 0x8)) */ return; } diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.h b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.h index 80d7c0d39aab..e0023c8cb628 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.h +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.h @@ -19,18 +19,18 @@ #define APCI035_BOARD_VENDOR_ID 0x15B8 #define APCI035_ADDRESS_RANGE 255 -INT i_TW_Number; +int i_TW_Number; struct { - INT i_Gain; - INT i_Polarity; - INT i_OffsetRange; - INT i_Coupling; - INT i_SingleDiff; - INT i_AutoCalibration; - UINT ui_ReloadValue; - UINT ui_TimeUnitReloadVal; - INT i_Interrupt; - INT i_ModuleSelection; + int i_Gain; + int i_Polarity; + int i_OffsetRange; + int i_Coupling; + int i_SingleDiff; + int i_AutoCalibration; + unsigned int ui_ReloadValue; + unsigned int ui_TimeUnitReloadVal; + int i_Interrupt; + int i_ModuleSelection; } Config_Parameters_Main; /* ANALOG INPUT RANGE */ @@ -101,23 +101,23 @@ struct comedi_lrange range_apci035_ai = { 8, { /* TIMER */ /* timer value is passed as u seconds */ -INT i_APCI035_ConfigTimerWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, +int i_APCI035_ConfigTimerWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -INT i_APCI035_StartStopWriteTimerWatchdog(struct comedi_device *dev, +int i_APCI035_StartStopWriteTimerWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -INT i_APCI035_ReadTimerWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, +int i_APCI035_ReadTimerWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); /* Temperature Related Defines (Analog Input Subdevice) */ -INT i_APCI035_ConfigAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s, +int i_APCI035_ConfigAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -INT i_APCI035_ReadAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s, +int i_APCI035_ReadAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); /* Interrupt */ static void v_APCI035_Interrupt(int irq, void *d); /* Reset functions */ -INT i_APCI035_Reset(struct comedi_device *dev); +int i_APCI035_Reset(struct comedi_device *dev); diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1032.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1032.c index 32796ceb946e..e9021cd4d341 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1032.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1032.c @@ -3,13 +3,13 @@ Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data-com - info@addi-data.com + ADDI-DATA GmbH + Dieselstrasse 3 + D-77833 Ottersweier + Tel: +19(0)7223/9493-0 + Fax: +49(0)7223/9493-92 + http://www.addi-data-com + info@addi-data.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. @@ -53,8 +53,8 @@ You shoud also find the complete GPL in the COPYING file accompanying this sourc */ #include "hwdrv_apci1032.h" #include -//Global variables -UINT ui_InterruptStatus = 0; +/* Global variables */ +unsigned int ui_InterruptStatus = 0; /* +----------------------------------------------------------------------------+ @@ -84,13 +84,13 @@ UINT ui_InterruptStatus = 0; +----------------------------------------------------------------------------+ */ -INT i_APCI1032_ConfigDigitalInput(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI1032_ConfigDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - UINT ui_TmpValue; + unsigned int ui_TmpValue; - ULONG ul_Command1 = 0; - ULONG ul_Command2 = 0; + unsigned int ul_Command1 = 0; + unsigned int ul_Command2 = 0; devpriv->tsk_Current = current; /*******************************/ @@ -107,11 +107,11 @@ INT i_APCI1032_ConfigDigitalInput(struct comedi_device * dev, struct comedi_subd outl(0x4, devpriv->iobase + APCI1032_DIGITAL_IP_IRQ); ui_TmpValue = inl(devpriv->iobase + APCI1032_DIGITAL_IP_IRQ); - } //if (data[1] == ADDIDATA_OR) + } /* if (data[1] == ADDIDATA_OR) */ else { outl(0x6, devpriv->iobase + APCI1032_DIGITAL_IP_IRQ); - } //else if(data[1] == ADDIDATA_OR) - } // if( data[0] == ADDIDATA_ENABLE) + } /* else if(data[1] == ADDIDATA_OR) */ + } /* if( data[0] == ADDIDATA_ENABLE) */ else { ul_Command1 = ul_Command1 & 0xFFFF0000; ul_Command2 = ul_Command2 & 0xFFFF0000; @@ -120,7 +120,7 @@ INT i_APCI1032_ConfigDigitalInput(struct comedi_device * dev, struct comedi_subd outl(ul_Command2, devpriv->iobase + APCI1032_DIGITAL_IP_INTERRUPT_MODE2); outl(0x0, devpriv->iobase + APCI1032_DIGITAL_IP_IRQ); - } //else if ( data[0] == ADDIDATA_ENABLE) + } /* else if ( data[0] == ADDIDATA_ENABLE) */ return insn->n; } @@ -134,7 +134,7 @@ INT i_APCI1032_ConfigDigitalInput(struct comedi_device * dev, struct comedi_subd | Task : Return the status of the digital input | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | -| UINT ui_Channel : Channel number to read | +| unsigned int ui_Channel : Channel number to read | | unsigned int *data : Data Pointer to read status | +----------------------------------------------------------------------------+ | Output Parameters : -- | @@ -144,22 +144,24 @@ INT i_APCI1032_ConfigDigitalInput(struct comedi_device * dev, struct comedi_subd | | +----------------------------------------------------------------------------+ */ -INT i_APCI1032_Read1DigitalInput(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI1032_Read1DigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - UINT ui_TmpValue = 0; - UINT ui_Channel; + unsigned int ui_TmpValue = 0; + unsigned int ui_Channel; ui_Channel = CR_CHAN(insn->chanspec); if (ui_Channel >= 0 && ui_Channel <= 31) { - ui_TmpValue = (UINT) inl(devpriv->iobase + APCI1032_DIGITAL_IP); - // since only 1 channel reqd to bring it to last bit it is rotated - // 8 +(chan - 1) times then ANDed with 1 for last bit. + ui_TmpValue = (unsigned int) inl(devpriv->iobase + APCI1032_DIGITAL_IP); +/* +* since only 1 channel reqd to bring it to last bit it is rotated 8 +* +(chan - 1) times then ANDed with 1 for last bit. +*/ *data = (ui_TmpValue >> ui_Channel) & 0x1; - } //if(ui_Channel >= 0 && ui_Channel <=31) + } /* if(ui_Channel >= 0 && ui_Channel <=31) */ else { - //comedi_error(dev," \n chan spec wrong\n"); - return -EINVAL; // "sorry channel spec wrong " - } //else if(ui_Channel >= 0 && ui_Channel <=31) + /* comedi_error(dev," \n chan spec wrong\n"); */ + return -EINVAL; /* "sorry channel spec wrong " */ + } /* else if(ui_Channel >= 0 && ui_Channel <=31) */ return insn->n; } @@ -172,8 +174,8 @@ INT i_APCI1032_Read1DigitalInput(struct comedi_device * dev, struct comedi_subde | Task : Return the status of the Requested digital inputs | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | -| UINT ui_NoOfChannels : No Of Channels To be Read | -| UINT *data : Data Pointer to read status | +| unsigned int ui_NoOfChannels : No Of Channels To be Read | +| unsigned int *data : Data Pointer to read status | +----------------------------------------------------------------------------+ | Output Parameters : -- | +----------------------------------------------------------------------------+ @@ -183,16 +185,16 @@ INT i_APCI1032_Read1DigitalInput(struct comedi_device * dev, struct comedi_subde +----------------------------------------------------------------------------+ */ -INT i_APCI1032_ReadMoreDigitalInput(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI1032_ReadMoreDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - UINT ui_PortValue = data[0]; - UINT ui_Mask = 0; - UINT ui_NoOfChannels; + unsigned int ui_PortValue = data[0]; + unsigned int ui_Mask = 0; + unsigned int ui_NoOfChannels; ui_NoOfChannels = CR_CHAN(insn->chanspec); if (data[1] == 0) { - *data = (UINT) inl(devpriv->iobase + APCI1032_DIGITAL_IP); + *data = (unsigned int) inl(devpriv->iobase + APCI1032_DIGITAL_IP); switch (ui_NoOfChannels) { case 2: ui_Mask = 3; @@ -213,16 +215,16 @@ INT i_APCI1032_ReadMoreDigitalInput(struct comedi_device * dev, struct comedi_su case 31: break; default: - //comedi_error(dev," \nchan spec wrong\n"); - return -EINVAL; // "sorry channel spec wrong " + /* comedi_error(dev," \nchan spec wrong\n"); */ + return -EINVAL; /* "sorry channel spec wrong " */ break; - } //switch(ui_NoOfChannels) - } //if(data[1]==0) + } /* switch(ui_NoOfChannels) */ + } /* if(data[1]==0) */ else { if (data[1] == 1) { *data = ui_InterruptStatus; - } //if(data[1]==1) - } //else if(data[1]==0) + } /* if(data[1]==1) */ + } /* else if(data[1]==0) */ return insn->n; } @@ -247,16 +249,16 @@ static void v_APCI1032_Interrupt(int irq, void *d) { struct comedi_device *dev = d; - UINT ui_Temp; - //disable the interrupt + unsigned int ui_Temp; + /* disable the interrupt */ ui_Temp = inl(devpriv->iobase + APCI1032_DIGITAL_IP_IRQ); outl(ui_Temp & APCI1032_DIGITAL_IP_INTERRUPT_DISABLE, devpriv->iobase + APCI1032_DIGITAL_IP_IRQ); ui_InterruptStatus = inl(devpriv->iobase + APCI1032_DIGITAL_IP_INTERRUPT_STATUS); ui_InterruptStatus = ui_InterruptStatus & 0X0000FFFF; - send_sig(SIGIO, devpriv->tsk_Current, 0); // send signal to the sample - outl(ui_Temp, devpriv->iobase + APCI1032_DIGITAL_IP_IRQ); //enable the interrupt + send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */ + outl(ui_Temp, devpriv->iobase + APCI1032_DIGITAL_IP_IRQ); /* enable the interrupt */ return; } @@ -275,11 +277,11 @@ static void v_APCI1032_Interrupt(int irq, void *d) +----------------------------------------------------------------------------+ */ -INT i_APCI1032_Reset(struct comedi_device * dev) +int i_APCI1032_Reset(struct comedi_device *dev) { - outl(0x0, devpriv->iobase + APCI1032_DIGITAL_IP_IRQ); //disable the interrupts - inl(devpriv->iobase + APCI1032_DIGITAL_IP_INTERRUPT_STATUS); //Reset the interrupt status register - outl(0x0, devpriv->iobase + APCI1032_DIGITAL_IP_INTERRUPT_MODE1); //Disable the and/or interrupt + outl(0x0, devpriv->iobase + APCI1032_DIGITAL_IP_IRQ); /* disable the interrupts */ + inl(devpriv->iobase + APCI1032_DIGITAL_IP_INTERRUPT_STATUS); /* Reset the interrupt status register */ + outl(0x0, devpriv->iobase + APCI1032_DIGITAL_IP_INTERRUPT_MODE1); /* Disable the and/or interrupt */ outl(0x0, devpriv->iobase + APCI1032_DIGITAL_IP_INTERRUPT_MODE2); return 0; } diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1032.h b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1032.h index 659ef85088cd..e29a72a568f3 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1032.h +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1032.h @@ -19,45 +19,46 @@ #define APCI1032_BOARD_VENDOR_ID 0x15B8 #define APCI1032_ADDRESS_RANGE 20 -//DIGITAL INPUT DEFINE +/* DIGITAL INPUT DEFINE */ #define APCI1032_DIGITAL_IP 0 #define APCI1032_DIGITAL_IP_INTERRUPT_MODE1 4 #define APCI1032_DIGITAL_IP_INTERRUPT_MODE2 8 #define APCI1032_DIGITAL_IP_IRQ 16 -//Digital Input IRQ Function Selection +/* Digital Input IRQ Function Selection */ #define ADDIDATA_OR 0 #define ADDIDATA_AND 1 -//Digital Input Interrupt Status +/* Digital Input Interrupt Status */ #define APCI1032_DIGITAL_IP_INTERRUPT_STATUS 12 -//Digital Input Interrupt Enable Disable. +/* Digital Input Interrupt Enable Disable. */ #define APCI1032_DIGITAL_IP_INTERRUPT_ENABLE 0x4 #define APCI1032_DIGITAL_IP_INTERRUPT_DISABLE 0xFFFFFFFB -//ADDIDATA Enable Disable +/* ADDIDATA Enable Disable */ #define ADDIDATA_ENABLE 1 #define ADDIDATA_DISABLE 0 -// Hardware Layer functions for Apci1032 +/* Hardware Layer functions for Apci1032 */ -//DI -// for di read +/* +* DI for di read +*/ -INT i_APCI1032_ConfigDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, +int i_APCI1032_ConfigDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -INT i_APCI1032_Read1DigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, +int i_APCI1032_Read1DigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -INT i_APCI1032_ReadMoreDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, +int i_APCI1032_ReadMoreDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -// Interrupt functions..... +/* Interrupt functions..... */ static void v_APCI1032_Interrupt(int irq, void *d); -//Reset -INT i_APCI1032_Reset(struct comedi_device *dev); +/* Reset */ +int i_APCI1032_Reset(struct comedi_device *dev); diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c index 2d6adcff41e3..236b8a31c824 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c @@ -3,13 +3,13 @@ Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data-com - info@addi-data.com + ADDI-DATA GmbH + Dieselstrasse 3 + D-77833 Ottersweier + Tel: +19(0)7223/9493-0 + Fax: +49(0)7223/9493-92 + http://www.addi-data-com + info@addi-data.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. @@ -77,7 +77,7 @@ int i_TimerCounter1Enabled = 0, i_TimerCounter2Enabled = | data[0] :Number of the input port on | | which the event will take place | | (1 or 2) - data[1] : The event logic for port 1 has | +| data[1] : The event logic for port 1 has | | three possibilities | | :0 APCI1500_AND :This logic | | links | @@ -137,8 +137,8 @@ int i_TimerCounter1Enabled = 0, i_TimerCounter2Enabled = +----------------------------------------------------------------------------+ */ -INT i_APCI1500_ConfigDigitalInputEvent(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { int i_PatternPolarity = 0, i_PatternTransition = 0, i_PatternMask = 0; int i_MaxChannel = 0, i_Count = 0, i_EventMask = 0; @@ -157,16 +157,16 @@ INT i_APCI1500_ConfigDigitalInputEvent(struct comedi_device * dev, if (data[0] == 1) { i_MaxChannel = 8; - } // if (data[0] == 1) + } /* if (data[0] == 1) */ else { if (data[0] == 2) { i_MaxChannel = 6; - } // if(data[0]==2) + } /* if(data[0]==2) */ else { printk("\nThe specified port event does not exist\n"); return -EINVAL; - } //else if(data[0]==2) - } //else if (data[0] == 1) + } /* else if(data[0]==2) */ + } /* else if (data[0] == 1) */ switch (data[1]) { case 0: data[1] = APCI1500_AND; @@ -180,7 +180,7 @@ INT i_APCI1500_ConfigDigitalInputEvent(struct comedi_device * dev, default: printk("\nThe specified interrupt logic does not exist\n"); return -EINVAL; - } //switch(data[1]); + } /* switch(data[1]); */ i_Logic = data[1]; for (i_Count = i_MaxChannel, i = 0; i_Count > 0; i_Count--, i++) { @@ -224,8 +224,8 @@ INT i_APCI1500_ConfigDigitalInputEvent(struct comedi_device * dev, default: printk("\nThe option indicated in the event mask does not exist\n"); return -EINVAL; - } // switch(i_EventMask) - } //for (i_Count = i_MaxChannel; i_Count >0;i_Count --) + } /* switch(i_EventMask) */ + } /* for (i_Count = i_MaxChannel; i_Count >0;i_Count --) */ if (data[0] == 1) { /****************************/ @@ -247,7 +247,7 @@ INT i_APCI1500_ConfigDigitalInputEvent(struct comedi_device * dev, /********************************************/ printk("\nTransition error on an OR PRIORITY logic\n"); return -EINVAL; - } // if (data[1]== APCI1500_OR_PRIORITY && i_PatternTransition != 0) + } /* if (data[1]== APCI1500_OR_PRIORITY && i_PatternTransition != 0) */ /*************************************/ /* Tests if more than one transition */ @@ -261,7 +261,7 @@ INT i_APCI1500_ConfigDigitalInputEvent(struct comedi_device * dev, ((i_PatternTransition >> i_Count) & 0x1); - } //for (i_Count = 0; i_Count < 8; i_Count++) + } /* for (i_Count = 0; i_Count < 8; i_Count++) */ if (i_PatternTransitionCount > 1) { /****************************************/ @@ -269,8 +269,8 @@ INT i_APCI1500_ConfigDigitalInputEvent(struct comedi_device * dev, /****************************************/ printk("\n Transition error on an AND logic\n"); return -EINVAL; - } // if (i_PatternTransitionCount > 1) - } // if (data[1]== APCI1500_AND) + } /* if (i_PatternTransitionCount > 1) */ + } /* if (data[1]== APCI1500_AND) */ /*****************************************************************/ /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */ @@ -359,12 +359,12 @@ INT i_APCI1500_ConfigDigitalInputEvent(struct comedi_device * dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - } // if(data[1]==APCI1500_AND||data[1]==APCI1500_OR||data[1]==APCI1500_OR_PRIORITY) + } /* if(data[1]==APCI1500_AND||data[1]==APCI1500_OR||data[1]==APCI1500_OR_PRIORITY) */ else { printk("\nThe choice for interrupt logic does not exist\n"); return -EINVAL; - } // else }// if(data[1]==APCI1500_AND||data[1]==APCI1500_OR||data[1]==APCI1500_OR_PRIORITY) - } // if (data[0]== 1) + } /* else }// if(data[1]==APCI1500_AND||data[1]==APCI1500_OR||data[1]==APCI1500_OR_PRIORITY) */ + } /* if (data[0]== 1) */ /************************************/ /* Test if event setting for port 2 */ @@ -487,12 +487,12 @@ INT i_APCI1500_ConfigDigitalInputEvent(struct comedi_device * dev, outb(0xF4, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - } // if (data[1] == APCI1500_OR) + } /* if (data[1] == APCI1500_OR) */ else { printk("\nThe choice for interrupt logic does not exist\n"); return -EINVAL; - } //elseif (data[1] == APCI1500_OR) - } //if(data[0]==2) + } /* elseif (data[1] == APCI1500_OR) */ + } /* if(data[0]==2) */ return insn->n; } @@ -506,11 +506,11 @@ INT i_APCI1500_ConfigDigitalInputEvent(struct comedi_device * dev, | Task : Allows or disallows a port event | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | -| UINT ui_Channel : Channel number to read | +| unsigned int ui_Channel : Channel number to read | | unsigned int *data : Data Pointer to read status | - data[0] :0 Start input event - 1 Stop input event - data[1] :No of port (1 or 2) +| data[0] :0 Start input event +| 1 Stop input event +| data[1] :No of port (1 or 2) +----------------------------------------------------------------------------+ | Output Parameters : -- | +----------------------------------------------------------------------------+ @@ -519,8 +519,8 @@ INT i_APCI1500_ConfigDigitalInputEvent(struct comedi_device * dev, | | +----------------------------------------------------------------------------+ */ -int i_APCI1500_StartStopInputEvent(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI1500_StartStopInputEvent(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i_Event1InterruptStatus = 0, i_Event2InterruptStatus = 0, i_RegValue; @@ -589,12 +589,12 @@ int i_APCI1500_StartStopInputEvent(struct comedi_device * dev, struct comedi_sub devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - } // if(i_Event1Status==1) + } /* if(i_Event1Status==1) */ else { printk("\nEvent 1 not initialised\n"); return -EINVAL; - } //else if(i_Event1Status==1) - } //if (data[1]==1) + } /* else if(i_Event1Status==1) */ + } /* if (data[1]==1) */ if (data[1] == 2) { if (i_Event2Status == 1) { @@ -640,17 +640,17 @@ int i_APCI1500_StartStopInputEvent(struct comedi_device * dev, struct comedi_sub devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_Event2InterruptStatus = 1; - } // if(i_Event2Status==1) + } /* if(i_Event2Status==1) */ else { printk("\nEvent 2 not initialised\n"); return -EINVAL; - } //else if(i_Event2Status==1) - } // if(data[1]==2) - } // if (data[1] == 1 || data[0] == 2) + } /* else if(i_Event2Status==1) */ + } /* if(data[1]==2) */ + } /* if (data[1] == 1 || data[0] == 2) */ else { printk("\nThe port parameter is in error\n"); return -EINVAL; - } //else if (data[1] == 1 || data[0] == 2) + } /* else if (data[1] == 1 || data[0] == 2) */ break; @@ -701,12 +701,12 @@ int i_APCI1500_StartStopInputEvent(struct comedi_device * dev, struct comedi_sub devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_Event1InterruptStatus = 0; - } // if(i_Event1Status==1) + } /* if(i_Event1Status==1) */ else { printk("\nEvent 1 not initialised\n"); return -EINVAL; - } //else if(i_Event1Status==1) - } //if (data[1]==1) + } /* else if(i_Event1Status==1) */ + } /* if (data[1]==1) */ if (data[1] == 2) { /*****************************/ /* Test if event initialised */ @@ -744,23 +744,23 @@ int i_APCI1500_StartStopInputEvent(struct comedi_device * dev, struct comedi_sub devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_Event2InterruptStatus = 0; - } // if(i_Event2Status==1) + } /* if(i_Event2Status==1) */ else { printk("\nEvent 2 not initialised\n"); return -EINVAL; - } //else if(i_Event2Status==1) - } //if(data[1]==2) + } /* else if(i_Event2Status==1) */ + } /* if(data[1]==2) */ - } // if (data[1] == 1 || data[1] == 2) + } /* if (data[1] == 1 || data[1] == 2) */ else { printk("\nThe port parameter is in error\n"); return -EINVAL; - } //else if (data[1] == 1 || data[1] == 2) + } /* else if (data[1] == 1 || data[1] == 2) */ break; default: printk("\nThe option of START/STOP logic does not exist\n"); return -EINVAL; - } //switch(data[0]) + } /* switch(data[0]) */ return insn->n; } @@ -774,7 +774,7 @@ int i_APCI1500_StartStopInputEvent(struct comedi_device * dev, struct comedi_sub | Task : Return the status of the digital input | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | -| UINT ui_Channel : Channel number to read | +| unsigned int ui_Channel : Channel number to read | | unsigned int *data : Data Pointer to read status | +----------------------------------------------------------------------------+ | Output Parameters : -- | @@ -784,8 +784,8 @@ int i_APCI1500_StartStopInputEvent(struct comedi_device * dev, struct comedi_sub | | +----------------------------------------------------------------------------+ */ -INT i_APCI1500_Initialisation(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI1500_Initialisation(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i_DummyRead = 0; /******************/ @@ -943,11 +943,11 @@ INT i_APCI1500_Initialisation(struct comedi_device * dev, struct comedi_subdevic | Task : Return the status of the Requested digital inputs | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | -| UINT ui_NoOfChannels : No Of Channels To be Read | -| UINT *data : Data Pointer - data[0] : 0 Read a single channel - 1 read a port value - data[1] : port value +| unsigned int ui_NoOfChannels : No Of Channels To be Read | +| unsigned int *data : Data Pointer +| data[0] : 0 Read a single channel +| 1 read a port value +| data[1] : port value +----------------------------------------------------------------------------+ | Output Parameters : -- data[0] :The read status value +----------------------------------------------------------------------------+ @@ -957,31 +957,31 @@ INT i_APCI1500_Initialisation(struct comedi_device * dev, struct comedi_subdevic +----------------------------------------------------------------------------+ */ -INT i_APCI1500_ReadMoreDigitalInput(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI1500_ReadMoreDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - UINT ui_PortValue = data[1]; - UINT ui_Mask = 0; - UINT ui_Channel; - UINT ui_TmpValue = 0; + unsigned int ui_PortValue = data[1]; + unsigned int ui_Mask = 0; + unsigned int ui_Channel; + unsigned int ui_TmpValue = 0; ui_Channel = CR_CHAN(insn->chanspec); switch (data[0]) { case 0: if (ui_Channel >= 0 && ui_Channel <= 15) { ui_TmpValue = - (UINT) inw(devpriv->i_IobaseAddon + + (unsigned int) inw(devpriv->i_IobaseAddon + APCI1500_DIGITAL_IP); *data = (ui_TmpValue >> ui_Channel) & 0x1; - } //if(ui_Channel >= 0 && ui_Channel <=15) + } /* if(ui_Channel >= 0 && ui_Channel <=15) */ else { printk("\nThe channel specification are in error\n"); - return -EINVAL; // "sorry channel spec wrong " - } //else if(ui_Channel >= 0 && ui_Channel <=15) + return -EINVAL; /* "sorry channel spec wrong " */ + } /* else if(ui_Channel >= 0 && ui_Channel <=15) */ break; case 1: - *data = (UINT) inw(devpriv->i_IobaseAddon + + *data = (unsigned int) inw(devpriv->i_IobaseAddon + APCI1500_DIGITAL_IP); switch (ui_Channel) { case 2: @@ -1001,35 +1001,35 @@ INT i_APCI1500_ReadMoreDigitalInput(struct comedi_device * dev, struct comedi_su default: printk("\nSpecified channel cannot be read \n"); - return -EINVAL; // "sorry channel spec wrong " + return -EINVAL; /* "sorry channel spec wrong " */ break; - } //switch(ui_Channel) + } /* switch(ui_Channel) */ break; default: printk("\nThe specified functionality does not exist\n"); return -EINVAL; - } //switch(data[0]) + } /* switch(data[0]) */ return insn->n; } /* +----------------------------------------------------------------------------+ | Function Name : int i_APCI1500_ConfigDigitalOutputErrorInterrupt - (struct comedi_device *dev,struct comedi_subdevice *s struct comedi_insn - *insn,unsigned int *data) | +| (struct comedi_device *dev,struct comedi_subdevice *s struct comedi_insn +| *insn,unsigned int *data) | | | +----------------------------------------------------------------------------+ | Task : Configures the digital output memory and the digital - output error interrupt | +| output error interrupt | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | | unsigned int *data : Data Pointer contains | | configuration parameters as below | | struct comedi_subdevice *s, :pointer to subdevice structure - struct comedi_insn *insn :pointer to insn structure | +| struct comedi_insn *insn :pointer to insn structure | | data[0] :1:Memory on | | 0:Memory off | - data[1] :1 Enable the voltage error interrupt +| data[1] :1 Enable the voltage error interrupt | :0 Disable the voltage error interrupt | | | +----------------------------------------------------------------------------+ @@ -1040,8 +1040,8 @@ INT i_APCI1500_ReadMoreDigitalInput(struct comedi_device * dev, struct comedi_su | | +----------------------------------------------------------------------------+ */ -int i_APCI1500_ConfigDigitalOutputErrorInterrupt(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +int i_APCI1500_ConfigDigitalOutputErrorInterrupt(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { devpriv->b_OutputMemoryStatus = data[0]; return insn->n; @@ -1056,8 +1056,8 @@ int i_APCI1500_ConfigDigitalOutputErrorInterrupt(struct comedi_device * dev, | Task : Writes port value To the selected port | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | -| UINT ui_NoOfChannels : No Of Channels To Write | -| UINT *data : Data Pointer to read status | +| unsigned int ui_NoOfChannels : No Of Channels To Write | +| unsigned int *data : Data Pointer to read status | +----------------------------------------------------------------------------+ | Output Parameters : -- | +----------------------------------------------------------------------------+ @@ -1067,24 +1067,24 @@ int i_APCI1500_ConfigDigitalOutputErrorInterrupt(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -INT i_APCI1500_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI1500_WriteDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - static UINT ui_Temp = 0; - UINT ui_Temp1; + static unsigned int ui_Temp = 0; + unsigned int ui_Temp1; - UINT ui_NoOfChannel = CR_CHAN(insn->chanspec); // get the channel + unsigned int ui_NoOfChannel = CR_CHAN(insn->chanspec); /* get the channel */ if (!devpriv->b_OutputMemoryStatus) { ui_Temp = 0; - } //if(!devpriv->b_OutputMemoryStatus ) + } /* if(!devpriv->b_OutputMemoryStatus ) */ if (data[3] == 0) { if (data[1] == 0) { data[0] = (data[0] << ui_NoOfChannel) | ui_Temp; outw(data[0], devpriv->i_IobaseAddon + APCI1500_DIGITAL_OP); - } //if(data[1]==0) + } /* if(data[1]==0) */ else { if (data[1] == 1) { switch (ui_NoOfChannel) { @@ -1113,19 +1113,19 @@ INT i_APCI1500_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subd default: comedi_error(dev, " chan spec wrong"); - return -EINVAL; // "sorry channel spec wrong " + return -EINVAL; /* "sorry channel spec wrong " */ - } //switch(ui_NoOfChannels) + } /* switch(ui_NoOfChannels) */ outw(data[0], devpriv->i_IobaseAddon + APCI1500_DIGITAL_OP); - } // if(data[1]==1) + } /* if(data[1]==1) */ else { printk("\nSpecified channel not supported\n"); - } //else if(data[1]==1) - } //elseif(data[1]==0) - } //if(data[3]==0) + } /* else if(data[1]==1) */ + } /* elseif(data[1]==0) */ + } /* if(data[3]==0) */ else { if (data[3] == 1) { if (data[1] == 0) { @@ -1140,7 +1140,7 @@ INT i_APCI1500_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subd outw(data[0], devpriv->i_IobaseAddon + APCI1500_DIGITAL_OP); - } //if(data[1]==0) + } /* if(data[1]==0) */ else { if (data[1] == 1) { switch (ui_NoOfChannel) { @@ -1190,48 +1190,48 @@ INT i_APCI1500_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subd default: comedi_error(dev, " chan spec wrong"); - return -EINVAL; // "sorry channel spec wrong " + return -EINVAL; /* "sorry channel spec wrong " */ - } //switch(ui_NoOfChannels) + } /* switch(ui_NoOfChannels) */ outw(data[0], devpriv->i_IobaseAddon + APCI1500_DIGITAL_OP); - } // if(data[1]==1) + } /* if(data[1]==1) */ else { printk("\nSpecified channel not supported\n"); - } //else if(data[1]==1) - } //elseif(data[1]==0) - } //if(data[3]==1); + } /* else if(data[1]==1) */ + } /* elseif(data[1]==0) */ + } /* if(data[3]==1); */ else { printk("\nSpecified functionality does not exist\n"); return -EINVAL; - } //if else data[3]==1) - } //if else data[3]==0) + } /* if else data[3]==1) */ + } /* if else data[3]==0) */ ui_Temp = data[0]; - return (insn->n);; + return insn->n; } /* +----------------------------------------------------------------------------+ | Function Name : int i_APCI1500_ConfigCounterTimerWatchdog(comedi_device - *dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data)| +| *dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data)| | | +----------------------------------------------------------------------------+ | Task : Configures The Watchdog | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | | struct comedi_subdevice *s, :pointer to subdevice structure - struct comedi_insn *insn :pointer to insn structure | +| struct comedi_insn *insn :pointer to insn structure | | unsigned int *data : Data Pointer to read status data[0] : 2 APCI1500_1_8_KHZ | 1 APCI1500_3_6_KHZ | | 0 APCI1500_115_KHZ - data[1] : 0 Counter1/Timer1 - 1 Counter2/Timer2 - 2 Counter3/Watchdog - data[2] : 0 Counter - 1 Timer/Watchdog - data[3] : This parameter has | +| data[1] : 0 Counter1/Timer1 +| 1 Counter2/Timer2 +| 2 Counter3/Watchdog +| data[2] : 0 Counter +| 1 Timer/Watchdog +| data[3] : This parameter has | | two meanings. | | - If the counter/timer | | is used as a counter | @@ -1243,15 +1243,15 @@ INT i_APCI1500_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subd | the divider factor | | for the output is | | given. - data[4] : 0 APCI1500_CONTINUOUS - 1 APCI1500_SINGLE - data[5] : 0 Software Trigger - 1 Hardware Trigger - - data[6] :0 Software gate - 1 Hardware gate - data[7] :0 Interrupt Disable - 1 Interrupt Enable +| data[4] : 0 APCI1500_CONTINUOUS +| 1 APCI1500_SINGLE +| data[5] : 0 Software Trigger +| 1 Hardware Trigger +| +| data[6] :0 Software gate +| 1 Hardware gate +| data[7] :0 Interrupt Disable +| 1 Interrupt Enable +----------------------------------------------------------------------------+ | Output Parameters : -- | +----------------------------------------------------------------------------+ @@ -1261,27 +1261,27 @@ INT i_APCI1500_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subd +----------------------------------------------------------------------------+ */ -int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { int i_TimerCounterMode, i_MasterConfiguration; devpriv->tsk_Current = current; -//Selection of the input clock +/* Selection of the input clock */ if (data[0] == 0 || data[0] == 1 || data[0] == 2) { outw(data[0], devpriv->i_IobaseAddon + APCI1500_CLK_SELECT); - } // if(data[0]==0||data[0]==1||data[0]==2) + } /* if(data[0]==0||data[0]==1||data[0]==2) */ else { if (data[0] != 3) { printk("\nThe option for input clock selection does not exist\n"); return -EINVAL; - } // if(data[0]!=3) - } //elseif(data[0]==0||data[0]==1||data[0]==2) - //Select the counter/timer + } /* if(data[0]!=3) */ + } /* elseif(data[0]==0||data[0]==1||data[0]==2) */ + /* Select the counter/timer */ switch (data[1]) { case COUNTER1: - //selecting counter or timer + /* selecting counter or timer */ switch (data[2]) { case 0: data[2] = APCI1500_COUNTER; @@ -1292,9 +1292,9 @@ int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device * dev, default: printk("\nThis choice is not a timer nor a counter\n"); return -EINVAL; - } // switch(data[2]) + } /* switch(data[2]) */ - //Selecting single or continuous mode + /* Selecting single or continuous mode */ switch (data[4]) { case 0: data[4] = APCI1500_CONTINUOUS; @@ -1305,7 +1305,7 @@ int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device * dev, default: printk("\nThis option for single/continuous mode does not exist\n"); return -EINVAL; - } // switch(data[4]) + } /* switch(data[4]) */ i_TimerCounterMode = data[2] | data[4] | 7; /*************************/ @@ -1428,21 +1428,21 @@ int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device * dev, outb(0x2, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - } //if(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) + } /* if(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) */ else { printk("\nError in selection of interrupt enable or disable\n"); return -EINVAL; - } //elseif(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) - } // if ((data[3]>= 0) && (data[3] <= 65535)) + } /* elseif(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) */ + } /* if ((data[3]>= 0) && (data[3] <= 65535)) */ else { printk("\nError in selection of reload value\n"); return -EINVAL; - } //else if ((data[3]>= 0) && (data[3] <= 65535)) + } /* else if ((data[3]>= 0) && (data[3] <= 65535)) */ i_TimerCounterWatchdogInterrupt = data[7]; i_TimerCounter1Init = 1; break; - case COUNTER2: //selecting counter or timer + case COUNTER2: /* selecting counter or timer */ switch (data[2]) { case 0: data[2] = APCI1500_COUNTER; @@ -1453,9 +1453,9 @@ int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device * dev, default: printk("\nThis choice is not a timer nor a counter\n"); return -EINVAL; - } // switch(data[2]) + } /* switch(data[2]) */ - //Selecting single or continuous mode + /* Selecting single or continuous mode */ switch (data[4]) { case 0: data[4] = APCI1500_CONTINUOUS; @@ -1466,9 +1466,9 @@ int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device * dev, default: printk("\nThis option for single/continuous mode does not exist\n"); return -EINVAL; - } // switch(data[4]) + } /* switch(data[4]) */ - //Selecting software or hardware trigger + /* Selecting software or hardware trigger */ switch (data[5]) { case 0: data[5] = APCI1500_SOFTWARE_TRIGGER; @@ -1479,9 +1479,9 @@ int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device * dev, default: printk("\nThis choice for software or hardware trigger does not exist\n"); return -EINVAL; - } // switch(data[5]) + } /* switch(data[5]) */ - //Selecting software or hardware gate + /* Selecting software or hardware gate */ switch (data[6]) { case 0: data[6] = APCI1500_SOFTWARE_GATE; @@ -1492,7 +1492,7 @@ int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device * dev, default: printk("\nThis choice for software or hardware gate does not exist\n"); return -EINVAL; - } // switch(data[6]) + } /* switch(data[6]) */ i_TimerCounterMode = data[2] | data[4] | data[5] | data[6] | 7; @@ -1616,21 +1616,21 @@ int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device * dev, outb(0x2, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - } //if(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) + } /* if(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) */ else { printk("\nError in selection of interrupt enable or disable\n"); return -EINVAL; - } //elseif(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) - } // if ((data[3]>= 0) && (data[3] <= 65535)) + } /* elseif(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) */ + } /* if ((data[3]>= 0) && (data[3] <= 65535)) */ else { printk("\nError in selection of reload value\n"); return -EINVAL; - } //else if ((data[3]>= 0) && (data[3] <= 65535)) + } /* else if ((data[3]>= 0) && (data[3] <= 65535)) */ i_TimerCounterWatchdogInterrupt = data[7]; i_TimerCounter2Init = 1; break; - case COUNTER3: //selecting counter or watchdog + case COUNTER3: /* selecting counter or watchdog */ switch (data[2]) { case 0: data[2] = APCI1500_COUNTER; @@ -1641,9 +1641,9 @@ int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device * dev, default: printk("\nThis choice is not a watchdog nor a counter\n"); return -EINVAL; - } // switch(data[2]) + } /* switch(data[2]) */ - //Selecting single or continuous mode + /* Selecting single or continuous mode */ switch (data[4]) { case 0: data[4] = APCI1500_CONTINUOUS; @@ -1654,9 +1654,9 @@ int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device * dev, default: printk("\nThis option for single/continuous mode does not exist\n"); return -EINVAL; - } // switch(data[4]) + } /* switch(data[4]) */ - //Selecting software or hardware gate + /* Selecting software or hardware gate */ switch (data[6]) { case 0: data[6] = APCI1500_SOFTWARE_GATE; @@ -1667,7 +1667,7 @@ int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device * dev, default: printk("\nThis choice for software or hardware gate does not exist\n"); return -EINVAL; - } // switch(data[6]) + } /* switch(data[6]) */ /*****************************/ /* Test if used for watchdog */ @@ -1680,10 +1680,10 @@ int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device * dev, /* - Pulses output */ /*****************************/ i_TimerCounterMode = data[2] | data[4] | 0x54; - } //if (data[2] == APCI1500_WATCHDOG) + } /* if (data[2] == APCI1500_WATCHDOG) */ else { i_TimerCounterMode = data[2] | data[4] | data[6] | 7; - } //elseif (data[2] == APCI1500_WATCHDOG) + } /* elseif (data[2] == APCI1500_WATCHDOG) */ /*************************/ /* Test the reload value */ /*************************/ @@ -1809,25 +1809,25 @@ int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device * dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - } //elseif(data[2]==APCI1500_COUNTER) + } /* elseif(data[2]==APCI1500_COUNTER) */ - } //if(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) + } /* if(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) */ else { printk("\nError in selection of interrupt enable or disable\n"); return -EINVAL; - } //elseif(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) - } // if ((data[3]>= 0) && (data[3] <= 65535)) + } /* elseif(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) */ + } /* if ((data[3]>= 0) && (data[3] <= 65535)) */ else { printk("\nError in selection of reload value\n"); return -EINVAL; - } //else if ((data[3]>= 0) && (data[3] <= 65535)) + } /* else if ((data[3]>= 0) && (data[3] <= 65535)) */ i_TimerCounterWatchdogInterrupt = data[7]; i_WatchdogCounter3Init = 1; break; default: printk("\nThe specified counter\timer option does not exist\n"); - } //switch(data[1]) + } /* switch(data[1]) */ i_CounterLogic = data[2]; return insn->n; } @@ -1836,22 +1836,22 @@ int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device * dev, +----------------------------------------------------------------------------+ | Function Name : int i_APCI1500_StartStopTriggerTimerCounterWatchdog | | (struct comedi_device *dev,struct comedi_subdevice *s, - struct comedi_insn *insn,unsigned int *data); | +| struct comedi_insn *insn,unsigned int *data); | +----------------------------------------------------------------------------+ | Task : Start / Stop or trigger the timer counter or Watchdog | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | | struct comedi_subdevice *s, :pointer to subdevice structure - struct comedi_insn *insn :pointer to insn structure | +| struct comedi_insn *insn :pointer to insn structure | | unsigned int *data : Data Pointer to read status | - data[0] : 0 Counter1/Timer1 - 1 Counter2/Timer2 - 2 Counter3/Watchdog - data[1] : 0 start - 1 stop - 2 Trigger - data[2] : 0 Counter - 1 Timer/Watchdog +| data[0] : 0 Counter1/Timer1 +| 1 Counter2/Timer2 +| 2 Counter3/Watchdog +| data[1] : 0 start +| 1 stop +| 2 Trigger +| data[2] : 0 Counter +| 1 Timer/Watchdog +----------------------------------------------------------------------------+ | Output Parameters : -- | +----------------------------------------------------------------------------+ @@ -1860,8 +1860,8 @@ int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device * dev, | | +----------------------------------------------------------------------------+ */ -int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { int i_CommandAndStatusValue; @@ -1871,11 +1871,11 @@ int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device * dev, case START: if (i_TimerCounter1Init == 1) { if (i_TimerCounterWatchdogInterrupt == 1) { - i_CommandAndStatusValue = 0xC4; //Enable the interrupt - } // if(i_TimerCounterWatchdogInterrupt==1) + i_CommandAndStatusValue = 0xC4; /* Enable the interrupt */ + } /* if(i_TimerCounterWatchdogInterrupt==1) */ else { - i_CommandAndStatusValue = 0xE4; //disable the interrupt - } //elseif(i_TimerCounterWatchdogInterrupt==1) + i_CommandAndStatusValue = 0xE4; /* disable the interrupt */ + } /* elseif(i_TimerCounterWatchdogInterrupt==1) */ /**************************/ /* Starts timer/counter 1 */ /**************************/ @@ -1889,7 +1889,7 @@ int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device * dev, outb(i_CommandAndStatusValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - } //if( i_TimerCounter1Init==1) + } /* if( i_TimerCounter1Init==1) */ else { printk("\nCounter/Timer1 not configured\n"); return -EINVAL; @@ -1922,14 +1922,14 @@ int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device * dev, /************************/ i_CommandAndStatusValue = 0x6; - } //if( i_TimerCounter1Enabled==1) + } /* if( i_TimerCounter1Enabled==1) */ else { /***************/ /* Set Trigger */ /***************/ i_CommandAndStatusValue = 0x2; - } //elseif(i_TimerCounter1Enabled==1) + } /* elseif(i_TimerCounter1Enabled==1) */ /********************************************/ /* Selects the commands and status register */ @@ -1940,7 +1940,7 @@ int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device * dev, outb(i_CommandAndStatusValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - } //if( i_TimerCounter1Init==1) + } /* if( i_TimerCounter1Init==1) */ else { printk("\nCounter/Timer1 not configured\n"); return -EINVAL; @@ -1950,7 +1950,7 @@ int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device * dev, default: printk("\nThe specified option for start/stop/trigger does not exist\n"); return -EINVAL; - } //switch(data[1]) + } /* switch(data[1]) */ break; case COUNTER2: @@ -1958,11 +1958,11 @@ int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device * dev, case START: if (i_TimerCounter2Init == 1) { if (i_TimerCounterWatchdogInterrupt == 1) { - i_CommandAndStatusValue = 0xC4; //Enable the interrupt - } // if(i_TimerCounterWatchdogInterrupt==1) + i_CommandAndStatusValue = 0xC4; /* Enable the interrupt */ + } /* if(i_TimerCounterWatchdogInterrupt==1) */ else { - i_CommandAndStatusValue = 0xE4; //disable the interrupt - } //elseif(i_TimerCounterWatchdogInterrupt==1) + i_CommandAndStatusValue = 0xE4; /* disable the interrupt */ + } /* elseif(i_TimerCounterWatchdogInterrupt==1) */ /**************************/ /* Starts timer/counter 2 */ /**************************/ @@ -1976,7 +1976,7 @@ int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device * dev, outb(i_CommandAndStatusValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - } //if( i_TimerCounter2Init==1) + } /* if( i_TimerCounter2Init==1) */ else { printk("\nCounter/Timer2 not configured\n"); return -EINVAL; @@ -2008,14 +2008,14 @@ int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device * dev, /************************/ i_CommandAndStatusValue = 0x6; - } //if( i_TimerCounter2Enabled==1) + } /* if( i_TimerCounter2Enabled==1) */ else { /***************/ /* Set Trigger */ /***************/ i_CommandAndStatusValue = 0x2; - } //elseif(i_TimerCounter2Enabled==1) + } /* elseif(i_TimerCounter2Enabled==1) */ /********************************************/ /* Selects the commands and status register */ @@ -2026,7 +2026,7 @@ int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device * dev, outb(i_CommandAndStatusValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - } //if( i_TimerCounter2Init==1) + } /* if( i_TimerCounter2Init==1) */ else { printk("\nCounter/Timer2 not configured\n"); return -EINVAL; @@ -2035,7 +2035,7 @@ int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device * dev, default: printk("\nThe specified option for start/stop/trigger does not exist\n"); return -EINVAL; - } //switch(data[1]) + } /* switch(data[1]) */ break; case COUNTER3: switch (data[1]) { @@ -2043,11 +2043,11 @@ int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device * dev, if (i_WatchdogCounter3Init == 1) { if (i_TimerCounterWatchdogInterrupt == 1) { - i_CommandAndStatusValue = 0xC4; //Enable the interrupt - } // if(i_TimerCounterWatchdogInterrupt==1) + i_CommandAndStatusValue = 0xC4; /* Enable the interrupt */ + } /* if(i_TimerCounterWatchdogInterrupt==1) */ else { - i_CommandAndStatusValue = 0xE4; //disable the interrupt - } //elseif(i_TimerCounterWatchdogInterrupt==1) + i_CommandAndStatusValue = 0xE4; /* disable the interrupt */ + } /* elseif(i_TimerCounterWatchdogInterrupt==1) */ /**************************/ /* Starts Watchdog/counter 3 */ /**************************/ @@ -2062,7 +2062,7 @@ int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device * dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - } // if( i_WatchdogCounter3init==1) + } /* if( i_WatchdogCounter3init==1) */ else { printk("\nWatchdog/Counter3 not configured\n"); return -EINVAL; @@ -2089,7 +2089,7 @@ int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device * dev, case TRIGGER: switch (data[2]) { - case 0: //triggering counter 3 + case 0: /* triggering counter 3 */ if (i_WatchdogCounter3Init == 1) { if (i_WatchdogCounter3Enabled == 1) { /************************/ @@ -2097,14 +2097,14 @@ int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device * dev, /************************/ i_CommandAndStatusValue = 0x6; - } //if( i_WatchdogCounter3Enabled==1) + } /* if( i_WatchdogCounter3Enabled==1) */ else { /***************/ /* Set Trigger */ /***************/ i_CommandAndStatusValue = 0x2; - } //elseif(i_WatchdogCounter3Enabled==1) + } /* elseif(i_WatchdogCounter3Enabled==1) */ /********************************************/ /* Selects the commands and status register */ @@ -2115,14 +2115,14 @@ int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device * dev, outb(i_CommandAndStatusValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - } //if( i_WatchdogCounter3Init==1) + } /* if( i_WatchdogCounter3Init==1) */ else { printk("\nCounter3 not configured\n"); return -EINVAL; } break; case 1: - //triggering Watchdog 3 + /* triggering Watchdog 3 */ if (i_WatchdogCounter3Init == 1) { /********************************************/ @@ -2134,7 +2134,7 @@ int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device * dev, outb(0x6, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - } //if( i_WatchdogCounter3Init==1) + } /* if( i_WatchdogCounter3Init==1) */ else { printk("\nWatchdog 3 not configured\n"); return -EINVAL; @@ -2143,17 +2143,17 @@ int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device * dev, default: printk("\nWrong choice of watchdog/counter3\n"); return -EINVAL; - } //switch(data[2]) + } /* switch(data[2]) */ break; default: printk("\nThe specified option for start/stop/trigger does not exist\n"); return -EINVAL; - } //switch(data[1]) + } /* switch(data[1]) */ break; default: printk("\nThe specified choice for counter/watchdog/timer does not exist\n"); return -EINVAL; - } //switch(data[0]) + } /* switch(data[0]) */ return insn->n; } @@ -2161,18 +2161,18 @@ int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device * dev, +----------------------------------------------------------------------------+ | Function Name : int i_APCI1500_ReadCounterTimerWatchdog | | (struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn, - unsigned int *data); | +| unsigned int *data); | +----------------------------------------------------------------------------+ | Task : Read The Watchdog | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | | struct comedi_subdevice *s, :pointer to subdevice structure - struct comedi_insn *insn :pointer to insn structure | +| struct comedi_insn *insn :pointer to insn structure | | unsigned int *data : Data Pointer to read status | - data[0] : 0 Counter1/Timer1 - 1 Counter2/Timer2 - 2 Counter3/Watchdog - +| data[0] : 0 Counter1/Timer1 +| 1 Counter2/Timer2 +| 2 Counter3/Watchdog +| +----------------------------------------------------------------------------+ | Output Parameters : -- | +----------------------------------------------------------------------------+ @@ -2182,13 +2182,13 @@ int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { int i_CommandAndStatusValue; switch (data[0]) { case COUNTER1: - //Read counter/timer1 + /* Read counter/timer1 */ if (i_TimerCounter1Init == 1) { if (i_TimerCounter1Enabled == 1) { /************************/ @@ -2196,14 +2196,14 @@ int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device * dev, /************************/ i_CommandAndStatusValue = 0xC; - } //if( i_TimerCounter1Init==1) + } /* if( i_TimerCounter1Init==1) */ else { /***************/ /* Set RCC */ /***************/ i_CommandAndStatusValue = 0x8; - } //elseif(i_TimerCounter1Init==1) + } /* elseif(i_TimerCounter1Init==1) */ /********************************************/ /* Selects the commands and status register */ @@ -2232,14 +2232,14 @@ int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device * dev, data[0] = data[0] | inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - } //if( i_TimerCounter1Init==1) + } /* if( i_TimerCounter1Init==1) */ else { printk("\nTimer/Counter1 not configured\n"); return -EINVAL; - } //elseif( i_TimerCounter1Init==1) + } /* elseif( i_TimerCounter1Init==1) */ break; case COUNTER2: - //Read counter/timer2 + /* Read counter/timer2 */ if (i_TimerCounter2Init == 1) { if (i_TimerCounter2Enabled == 1) { /************************/ @@ -2247,14 +2247,14 @@ int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device * dev, /************************/ i_CommandAndStatusValue = 0xC; - } //if( i_TimerCounter2Init==1) + } /* if( i_TimerCounter2Init==1) */ else { /***************/ /* Set RCC */ /***************/ i_CommandAndStatusValue = 0x8; - } //elseif(i_TimerCounter2Init==1) + } /* elseif(i_TimerCounter2Init==1) */ /********************************************/ /* Selects the commands and status register */ @@ -2283,14 +2283,14 @@ int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device * dev, data[0] = data[0] | inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - } //if( i_TimerCounter2Init==1) + } /* if( i_TimerCounter2Init==1) */ else { printk("\nTimer/Counter2 not configured\n"); return -EINVAL; - } //elseif( i_TimerCounter2Init==1) + } /* elseif( i_TimerCounter2Init==1) */ break; case COUNTER3: - //Read counter/watchdog2 + /* Read counter/watchdog2 */ if (i_WatchdogCounter3Init == 1) { if (i_WatchdogCounter3Enabled == 1) { /************************/ @@ -2298,14 +2298,14 @@ int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device * dev, /************************/ i_CommandAndStatusValue = 0xC; - } //if( i_TimerCounter2Init==1) + } /* if( i_TimerCounter2Init==1) */ else { /***************/ /* Set RCC */ /***************/ i_CommandAndStatusValue = 0x8; - } //elseif(i_WatchdogCounter3Init==1) + } /* elseif(i_WatchdogCounter3Init==1) */ /********************************************/ /* Selects the commands and status register */ @@ -2334,16 +2334,16 @@ int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device * dev, data[0] = data[0] | inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - } //if( i_WatchdogCounter3Init==1) + } /* if( i_WatchdogCounter3Init==1) */ else { printk("\nWatchdogCounter3 not configured\n"); return -EINVAL; - } //elseif( i_WatchdogCounter3Init==1) + } /* elseif( i_WatchdogCounter3Init==1) */ break; default: printk("\nThe choice of timer/counter/watchdog does not exist\n"); return -EINVAL; - } //switch(data[0]) + } /* switch(data[0]) */ return insn->n; } @@ -2352,13 +2352,13 @@ int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device * dev, +----------------------------------------------------------------------------+ | Function Name : int i_APCI1500_ReadInterruptMask | | (struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn, - unsigned int *data); | +| unsigned int *data); | +----------------------------------------------------------------------------+ | Task : Read the interrupt mask | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | | struct comedi_subdevice *s, :pointer to subdevice structure - struct comedi_insn *insn :pointer to insn structure | +| struct comedi_insn *insn :pointer to insn structure | | unsigned int *data : Data Pointer to read status | @@ -2370,8 +2370,8 @@ int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device * dev, | | +----------------------------------------------------------------------------+ */ -int i_APCI1500_ReadInterruptMask(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI1500_ReadInterruptMask(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { data[0] = i_InterruptMask; data[1] = i_InputChannel; @@ -2383,15 +2383,15 @@ int i_APCI1500_ReadInterruptMask(struct comedi_device * dev, struct comedi_subde +----------------------------------------------------------------------------+ | Function Name : int i_APCI1500_ConfigureInterrupt | | (struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn, - unsigned int *data); | +| unsigned int *data); | +----------------------------------------------------------------------------+ | Task : Configures the interrupt registers | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | | struct comedi_subdevice *s, :pointer to subdevice structure - struct comedi_insn *insn :pointer to insn structure | +| struct comedi_insn *insn :pointer to insn structure | | unsigned int *data : Data Pointer | - +| +----------------------------------------------------------------------------+ | Output Parameters : -- @@ -2401,26 +2401,26 @@ int i_APCI1500_ReadInterruptMask(struct comedi_device * dev, struct comedi_subde | | +----------------------------------------------------------------------------+ */ -int i_APCI1500_ConfigureInterrupt(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI1500_ConfigureInterrupt(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - UINT ui_Status; + unsigned int ui_Status; int i_RegValue; int i_Constant; devpriv->tsk_Current = current; outl(0x0, devpriv->i_IobaseAmcc + 0x38); if (data[0] == 1) { i_Constant = 0xC0; - } //if(data[0]==1) + } /* if(data[0]==1) */ else { if (data[0] == 0) { i_Constant = 0x00; - } //if{data[0]==0) + } /* if{data[0]==0) */ else { printk("\nThe parameter passed to driver is in error for enabling the voltage interrupt\n"); return -EINVAL; - } //else if(data[0]==0) - } //elseif(data[0]==1) + } /* else if(data[0]==0) */ + } /* elseif(data[0]==1) */ /*****************************************************/ /* Selects the mode specification register of port B */ @@ -2580,7 +2580,7 @@ static void v_APCI1500_Interrupt(int irq, void *d) { struct comedi_device *dev = d; - UINT ui_InterruptStatus = 0; + unsigned int ui_InterruptStatus = 0; int i_RegValue = 0; i_InterruptMask = 0; @@ -2599,11 +2599,11 @@ static void v_APCI1500_Interrupt(int irq, void *d) /*************************************************/ /* Selects the master interrupt control register */ /*************************************************/ - //outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL,devpriv->iobase+APCI1500_Z8536_CONTROL_REGISTER); + /* outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL,devpriv->iobase+APCI1500_Z8536_CONTROL_REGISTER); */ /**********************************************/ /* Disables the main interrupt on the board */ /**********************************************/ - //outb(0x00,devpriv->iobase+APCI1500_Z8536_CONTROL_REGISTER); + /* outb(0x00,devpriv->iobase+APCI1500_Z8536_CONTROL_REGISTER); */ /*****************************************************/ /* Selects the command and status register of port A */ @@ -2647,11 +2647,11 @@ static void v_APCI1500_Interrupt(int irq, void *d) i_InputChannel = 1 + (i_RegValue >> 1); - } // if(i_Logic==APCI1500_OR_PRIORITY) + } /* if(i_Logic==APCI1500_OR_PRIORITY) */ else { i_InputChannel = 0; - } //elseif(i_Logic==APCI1500_OR_PRIORITY) - } // if ((i_RegValue & 0x60) == 0x60) + } /* elseif(i_Logic==APCI1500_OR_PRIORITY) */ + } /* if ((i_RegValue & 0x60) == 0x60) */ /*****************************************************/ /* Selects the command and status register of port B */ @@ -2679,7 +2679,7 @@ static void v_APCI1500_Interrupt(int irq, void *d) /* Reads port B */ /****************/ i_RegValue = - inb((UINT) devpriv->iobase + + inb((unsigned int) devpriv->iobase + APCI1500_Z8536_PORT_B); i_RegValue = i_RegValue & 0xC0; @@ -2688,7 +2688,7 @@ static void v_APCI1500_Interrupt(int irq, void *d) /**************************************/ if (i_RegValue) { - //Disable the interrupt + /* Disable the interrupt */ /*****************************************************/ /* Selects the command and status register of port B */ /*****************************************************/ @@ -2697,17 +2697,17 @@ static void v_APCI1500_Interrupt(int irq, void *d) if (i_RegValue & 0x80) { i_InterruptMask = i_InterruptMask | 0x40; - } //if (i_RegValue & 0x80) + } /* if (i_RegValue & 0x80) */ if (i_RegValue & 0x40) { i_InterruptMask = i_InterruptMask | 0x80; - } //if (i_RegValue & 0x40) - } // if (i_RegValue) + } /* if (i_RegValue & 0x40) */ + } /* if (i_RegValue) */ else { i_InterruptMask = i_InterruptMask | 2; - } // if (i_RegValue) - } //if ((i_RegValue & 0x60) == 0x60) + } /* if (i_RegValue) */ + } /* if ((i_RegValue & 0x60) == 0x60) */ /*****************************************************/ /* Selects the command and status register of timer 1 */ @@ -2731,7 +2731,7 @@ static void v_APCI1500_Interrupt(int irq, void *d) devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_InterruptMask = i_InterruptMask | 4; - } // if ((i_RegValue & 0x60) == 0x60) + } /* if ((i_RegValue & 0x60) == 0x60) */ /*****************************************************/ /* Selects the command and status register of timer 2 */ /*****************************************************/ @@ -2754,7 +2754,7 @@ static void v_APCI1500_Interrupt(int irq, void *d) devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_InterruptMask = i_InterruptMask | 8; - } // if ((i_RegValue & 0x60) == 0x60) + } /* if ((i_RegValue & 0x60) == 0x60) */ /*****************************************************/ /* Selects the command and status register of timer 3 */ @@ -2779,13 +2779,13 @@ static void v_APCI1500_Interrupt(int irq, void *d) APCI1500_Z8536_CONTROL_REGISTER); if (i_CounterLogic == APCI1500_COUNTER) { i_InterruptMask = i_InterruptMask | 0x10; - } //if(i_CounterLogic==APCI1500_COUNTER) + } /* if(i_CounterLogic==APCI1500_COUNTER) */ else { i_InterruptMask = i_InterruptMask | 0x20; } - } // if ((i_RegValue & 0x60) == 0x60) + } /* if ((i_RegValue & 0x60) == 0x60) */ - send_sig(SIGIO, devpriv->tsk_Current, 0); // send signal to the sample + send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */ /***********************/ /* Enable all Interrupts */ /***********************/ @@ -2799,11 +2799,11 @@ static void v_APCI1500_Interrupt(int irq, void *d) /* Authorizes the main interrupt on the board */ /**********************************************/ outb(0xD0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - } // if ((ui_InterruptStatus & 0x800000) == 0x800000) + } /* if ((ui_InterruptStatus & 0x800000) == 0x800000) */ else { printk("\nInterrupt from unknown source\n"); - } //else if ((ui_InterruptStatus & 0x800000) == 0x800000) + } /* else if ((ui_InterruptStatus & 0x800000) == 0x800000) */ return; } @@ -2822,7 +2822,7 @@ static void v_APCI1500_Interrupt(int irq, void *d) +----------------------------------------------------------------------------+ */ -INT i_APCI1500_Reset(struct comedi_device * dev) +int i_APCI1500_Reset(struct comedi_device *dev) { int i_DummyRead = 0; i_TimerCounter1Init = 0; @@ -2982,7 +2982,7 @@ INT i_APCI1500_Reset(struct comedi_device * dev) devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deletes all interrupts */ outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - //reset all the digital outputs + /* reset all the digital outputs */ outw(0x0, devpriv->i_IobaseAddon + APCI1500_DIGITAL_OP); /*******************************/ /* Disable the board interrupt */ diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.h b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.h index 5d960b40a6a8..057903366a80 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.h +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.h @@ -17,11 +17,11 @@ /********* Definitions for APCI-1500 card *****/ -// Card Specific information +/* Card Specific information */ #define APCI1500_BOARD_VENDOR_ID 0x10e8 #define APCI1500_ADDRESS_RANGE 4 -//DIGITAL INPUT-OUTPUT DEFINE +/* DIGITAL INPUT-OUTPUT DEFINE */ #define APCI1500_DIGITAL_OP 2 #define APCI1500_DIGITAL_IP 0 diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1516.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1516.c index 5ae9a93844e7..38416356628d 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1516.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1516.c @@ -3,13 +3,13 @@ Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data-com - info@addi-data.com + ADDI-DATA GmbH + Dieselstrasse 3 + D-77833 Ottersweier + Tel: +19(0)7223/9493-0 + Fax: +49(0)7223/9493-92 + http://www.addi-data-com + info@addi-data.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. @@ -63,7 +63,7 @@ You shoud also find the complete GPL in the COPYING file accompanying this sourc +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | | struct comedi_subdevice *s, :pointer to subdevice structure - struct comedi_insn *insn :pointer to insn structure | +| struct comedi_insn *insn :pointer to insn structure | | unsigned int *data : Data Pointer to read status | +----------------------------------------------------------------------------+ | Output Parameters : -- | @@ -73,22 +73,22 @@ You shoud also find the complete GPL in the COPYING file accompanying this sourc | | +----------------------------------------------------------------------------+ */ -INT i_APCI1516_Read1DigitalInput(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI1516_Read1DigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - UINT ui_TmpValue = 0; - UINT ui_Channel; + unsigned int ui_TmpValue = 0; + unsigned int ui_Channel; ui_Channel = CR_CHAN(insn->chanspec); if (ui_Channel >= 0 && ui_Channel <= 7) { - ui_TmpValue = (UINT) inw(devpriv->iobase + APCI1516_DIGITAL_IP); - // since only 1 channel reqd to bring it to last bit it is rotated - // 8 +(chan - 1) times then ANDed with 1 for last bit. + ui_TmpValue = (unsigned int) inw(devpriv->iobase + APCI1516_DIGITAL_IP); + /* since only 1 channel reqd to bring it to last bit it is rotated */ + /* 8 +(chan - 1) times then ANDed with 1 for last bit. */ *data = (ui_TmpValue >> ui_Channel) & 0x1; - } //if(ui_Channel >= 0 && ui_Channel <=7) + } /* if(ui_Channel >= 0 && ui_Channel <=7) */ else { - //comedi_error(dev," \n chan spec wrong\n"); - return -EINVAL; // "sorry channel spec wrong " - } //else if(ui_Channel >= 0 && ui_Channel <=7) + /* comedi_error(dev," \n chan spec wrong\n"); */ + return -EINVAL; /* "sorry channel spec wrong " */ + } /* else if(ui_Channel >= 0 && ui_Channel <=7) */ return insn->n; } @@ -103,7 +103,7 @@ INT i_APCI1516_Read1DigitalInput(struct comedi_device * dev, struct comedi_subde +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | | struct comedi_subdevice *s, :pointer to subdevice structure - struct comedi_insn *insn :pointer to insn structure | +| struct comedi_insn *insn :pointer to insn structure | | unsigned int *data : Data Pointer to read status | +----------------------------------------------------------------------------+ | Output Parameters : -- | @@ -114,17 +114,17 @@ INT i_APCI1516_Read1DigitalInput(struct comedi_device * dev, struct comedi_subde +----------------------------------------------------------------------------+ */ -INT i_APCI1516_ReadMoreDigitalInput(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI1516_ReadMoreDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - UINT ui_PortValue = data[0]; - UINT ui_Mask = 0; - UINT ui_NoOfChannels; + unsigned int ui_PortValue = data[0]; + unsigned int ui_Mask = 0; + unsigned int ui_NoOfChannels; ui_NoOfChannels = CR_CHAN(insn->chanspec); - *data = (UINT) inw(devpriv->iobase + APCI1516_DIGITAL_IP); + *data = (unsigned int) inw(devpriv->iobase + APCI1516_DIGITAL_IP); switch (ui_NoOfChannels) { case 2: ui_Mask = 3; @@ -139,9 +139,9 @@ INT i_APCI1516_ReadMoreDigitalInput(struct comedi_device * dev, struct comedi_su default: printk("\nWrong parameters\n"); - return -EINVAL; // "sorry channel spec wrong " + return -EINVAL; /* "sorry channel spec wrong " */ break; - } //switch(ui_NoOfChannels) + } /* switch(ui_NoOfChannels) */ return insn->n; } @@ -149,7 +149,7 @@ INT i_APCI1516_ReadMoreDigitalInput(struct comedi_device * dev, struct comedi_su /* +----------------------------------------------------------------------------+ | Function Name : int i_APCI1516_ConfigDigitalOutput (struct comedi_device *dev, - struct comedi_subdevice *s struct comedi_insn *insn,unsigned int *data) | +| struct comedi_subdevice *s struct comedi_insn *insn,unsigned int *data) | | | +----------------------------------------------------------------------------+ | Task : Configures The Digital Output Subdevice. | @@ -158,7 +158,7 @@ INT i_APCI1516_ReadMoreDigitalInput(struct comedi_device * dev, struct comedi_su | unsigned int *data : Data Pointer contains | | configuration parameters as below | | struct comedi_subdevice *s, :pointer to subdevice structure - struct comedi_insn *insn :pointer to insn structure | +| struct comedi_insn *insn :pointer to insn structure | | data[0] :1:Memory on | | 0:Memory off | | | @@ -171,8 +171,8 @@ INT i_APCI1516_ReadMoreDigitalInput(struct comedi_device * dev, struct comedi_su | | +----------------------------------------------------------------------------+ */ -int i_APCI1516_ConfigDigitalOutput(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI1516_ConfigDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { devpriv->b_OutputMemoryStatus = data[0]; return insn->n; @@ -182,13 +182,13 @@ int i_APCI1516_ConfigDigitalOutput(struct comedi_device * dev, struct comedi_sub +----------------------------------------------------------------------------+ | Function Name : int i_APCI1516_WriteDigitalOutput | | (struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn, - unsigned int *data) | +| unsigned int *data) | +----------------------------------------------------------------------------+ | Task : Writes port value To the selected port | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | | struct comedi_subdevice *s, :pointer to subdevice structure - struct comedi_insn *insn :pointer to insn structure | +| struct comedi_insn *insn :pointer to insn structure | | unsigned int *data : Data Pointer to read status | +----------------------------------------------------------------------------+ | Output Parameters : -- | @@ -199,21 +199,21 @@ int i_APCI1516_ConfigDigitalOutput(struct comedi_device * dev, struct comedi_sub +----------------------------------------------------------------------------+ */ -INT i_APCI1516_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI1516_WriteDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - UINT ui_Temp, ui_Temp1; - UINT ui_NoOfChannel = CR_CHAN(insn->chanspec); // get the channel + unsigned int ui_Temp, ui_Temp1; + unsigned int ui_NoOfChannel = CR_CHAN(insn->chanspec); /* get the channel */ printk("EL311003 : @=%x\n", devpriv->iobase + APCI1516_DIGITAL_OP); if (devpriv->b_OutputMemoryStatus) { ui_Temp = inw(devpriv->iobase + APCI1516_DIGITAL_OP); - } //if(devpriv->b_OutputMemoryStatus ) + } /* if(devpriv->b_OutputMemoryStatus ) */ else { ui_Temp = 0; - } //if(devpriv->b_OutputMemoryStatus ) + } /* if(devpriv->b_OutputMemoryStatus ) */ if (data[3] == 0) { if (data[1] == 0) { data[0] = (data[0] << ui_NoOfChannel) | ui_Temp; @@ -222,7 +222,7 @@ INT i_APCI1516_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subd printk("EL311003 : d=%d @=%x\n", data[0], devpriv->iobase + APCI1516_DIGITAL_OP); - } //if(data[1]==0) + } /* if(data[1]==0) */ else { if (data[1] == 1) { switch (ui_NoOfChannel) { @@ -245,21 +245,21 @@ INT i_APCI1516_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subd default: comedi_error(dev, " chan spec wrong"); - return -EINVAL; // "sorry channel spec wrong " + return -EINVAL; /* "sorry channel spec wrong " */ - } //switch(ui_NoOfChannels) + } /* switch(ui_NoOfChannels) */ outw(data[0], devpriv->iobase + APCI1516_DIGITAL_OP); printk("EL311003 : d=%d @=%x\n", data[0], devpriv->iobase + APCI1516_DIGITAL_OP); - } // if(data[1]==1) + } /* if(data[1]==1) */ else { printk("\nSpecified channel not supported\n"); - } //else if(data[1]==1) - } //elseif(data[1]==0) - } //if(data[3]==0) + } /* else if(data[1]==1) */ + } /* elseif(data[1]==0) */ + } /* if(data[3]==0) */ else { if (data[3] == 1) { if (data[1] == 0) { @@ -275,7 +275,7 @@ INT i_APCI1516_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subd printk("EL311003 : d=%d @=%x\n", data[0], devpriv->iobase + APCI1516_DIGITAL_OP); - } //if(data[1]==0) + } /* if(data[1]==0) */ else { if (data[1] == 1) { switch (ui_NoOfChannel) { @@ -312,9 +312,9 @@ INT i_APCI1516_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subd default: comedi_error(dev, " chan spec wrong"); - return -EINVAL; // "sorry channel spec wrong " + return -EINVAL; /* "sorry channel spec wrong " */ - } //switch(ui_NoOfChannels) + } /* switch(ui_NoOfChannels) */ outw(data[0], devpriv->iobase + @@ -324,17 +324,17 @@ INT i_APCI1516_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subd data[0], devpriv->iobase + APCI1516_DIGITAL_OP); - } // if(data[1]==1) + } /* if(data[1]==1) */ else { printk("\nSpecified channel not supported\n"); - } //else if(data[1]==1) - } //elseif(data[1]==0) - } //if(data[3]==1); + } /* else if(data[1]==1) */ + } /* elseif(data[1]==0) */ + } /* if(data[3]==1); */ else { printk("\nSpecified functionality does not exist\n"); return -EINVAL; - } //if else data[3]==1) - } //if else data[3]==0) + } /* if else data[3]==1) */ + } /* if else data[3]==0) */ return (insn->n);; } @@ -342,13 +342,13 @@ INT i_APCI1516_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subd +----------------------------------------------------------------------------+ | Function Name : int i_APCI1516_ReadDigitalOutput | | (struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn, - unsigned int *data) | +| unsigned int *data) | +----------------------------------------------------------------------------+ | Task : Read value of the selected channel or port | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | | struct comedi_subdevice *s, :pointer to subdevice structure - struct comedi_insn *insn :pointer to insn structure | +| struct comedi_insn *insn :pointer to insn structure | | unsigned int *data : Data Pointer to read status | +----------------------------------------------------------------------------+ | Output Parameters : -- | @@ -359,17 +359,17 @@ INT i_APCI1516_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subd +----------------------------------------------------------------------------+ */ -INT i_APCI1516_ReadDigitalOutput(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI1516_ReadDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - UINT ui_Temp; - UINT ui_NoOfChannel = CR_CHAN(insn->chanspec); // get the channel + unsigned int ui_Temp; + unsigned int ui_NoOfChannel = CR_CHAN(insn->chanspec); /* get the channel */ ui_Temp = data[0]; *data = inw(devpriv->iobase + APCI1516_DIGITAL_OP_RW); if (ui_Temp == 0) { *data = (*data >> ui_NoOfChannel) & 0x1; - } //if(ui_Temp==0) + } /* if(ui_Temp==0) */ else { if (ui_Temp == 1) { switch (ui_NoOfChannel) { @@ -387,28 +387,28 @@ INT i_APCI1516_ReadDigitalOutput(struct comedi_device * dev, struct comedi_subde default: comedi_error(dev, " chan spec wrong"); - return -EINVAL; // "sorry channel spec wrong " + return -EINVAL; /* "sorry channel spec wrong " */ - } //switch(ui_NoOfChannels) - } //if(ui_Temp==1) + } /* switch(ui_NoOfChannels) */ + } /* if(ui_Temp==1) */ else { printk("\nSpecified channel not supported \n"); - } //elseif(ui_Temp==1) - } //elseif(ui_Temp==0) + } /* elseif(ui_Temp==1) */ + } /* elseif(ui_Temp==0) */ return insn->n; } /* +----------------------------------------------------------------------------+ | Function Name : int i_APCI1516_ConfigWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) | +| struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) | | | +----------------------------------------------------------------------------+ | Task : Configures The Watchdog | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | | struct comedi_subdevice *s, :pointer to subdevice structure - struct comedi_insn *insn :pointer to insn structure | +| struct comedi_insn *insn :pointer to insn structure | | unsigned int *data : Data Pointer to read status | +----------------------------------------------------------------------------+ | Output Parameters : -- | @@ -419,15 +419,15 @@ INT i_APCI1516_ReadDigitalOutput(struct comedi_device * dev, struct comedi_subde +----------------------------------------------------------------------------+ */ -int i_APCI1516_ConfigWatchdog(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI1516_ConfigWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if (data[0] == 0) { - //Disable the watchdog + /* Disable the watchdog */ outw(0x0, devpriv->i_IobaseAddon + APCI1516_WATCHDOG_ENABLEDISABLE); - //Loading the Reload value + /* Loading the Reload value */ outw(data[1], devpriv->i_IobaseAddon + APCI1516_WATCHDOG_RELOAD_VALUE); @@ -435,11 +435,11 @@ int i_APCI1516_ConfigWatchdog(struct comedi_device * dev, struct comedi_subdevic outw(data[1], devpriv->i_IobaseAddon + APCI1516_WATCHDOG_RELOAD_VALUE + 2); - } //if(data[0]==0) + } /* if(data[0]==0) */ else { printk("\nThe input parameters are wrong\n"); return -EINVAL; - } //elseif(data[0]==0) + } /* elseif(data[0]==0) */ return insn->n; } @@ -465,19 +465,19 @@ int i_APCI1516_ConfigWatchdog(struct comedi_device * dev, struct comedi_subdevic +----------------------------------------------------------------------------+ */ -int i_APCI1516_StartStopWriteWatchdog(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI1516_StartStopWriteWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { switch (data[0]) { - case 0: //stop the watchdog - outw(0x0, devpriv->i_IobaseAddon + APCI1516_WATCHDOG_ENABLEDISABLE); //disable the watchdog + case 0: /* stop the watchdog */ + outw(0x0, devpriv->i_IobaseAddon + APCI1516_WATCHDOG_ENABLEDISABLE); /* disable the watchdog */ break; - case 1: //start the watchdog + case 1: /* start the watchdog */ outw(0x0001, devpriv->i_IobaseAddon + APCI1516_WATCHDOG_ENABLEDISABLE); break; - case 2: //Software trigger + case 2: /* Software trigger */ outw(0x0201, devpriv->i_IobaseAddon + APCI1516_WATCHDOG_ENABLEDISABLE); @@ -485,7 +485,7 @@ int i_APCI1516_StartStopWriteWatchdog(struct comedi_device * dev, struct comedi_ default: printk("\nSpecified functionality does not exist\n"); return -EINVAL; - } // switch(data[0]) + } /* switch(data[0]) */ return insn->n; } @@ -510,8 +510,8 @@ int i_APCI1516_StartStopWriteWatchdog(struct comedi_device * dev, struct comedi_ +----------------------------------------------------------------------------+ */ -int i_APCI1516_ReadWatchdog(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI1516_ReadWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { data[0] = inw(devpriv->i_IobaseAddon + APCI1516_WATCHDOG_STATUS) & 0x1; return insn->n; @@ -532,9 +532,9 @@ int i_APCI1516_ReadWatchdog(struct comedi_device * dev, struct comedi_subdevice +----------------------------------------------------------------------------+ */ -INT i_APCI1516_Reset(struct comedi_device * dev) +int i_APCI1516_Reset(struct comedi_device *dev) { - outw(0x0, devpriv->iobase + APCI1516_DIGITAL_OP); //RESETS THE DIGITAL OUTPUTS + outw(0x0, devpriv->iobase + APCI1516_DIGITAL_OP); /* RESETS THE DIGITAL OUTPUTS */ outw(0x0, devpriv->i_IobaseAddon + APCI1516_WATCHDOG_ENABLEDISABLE); outw(0x0, devpriv->i_IobaseAddon + APCI1516_WATCHDOG_RELOAD_VALUE); outw(0x0, devpriv->i_IobaseAddon + APCI1516_WATCHDOG_RELOAD_VALUE + 2); diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1516.h b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1516.h index 398baa04a163..21c09ed01b1d 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1516.h +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1516.h @@ -17,17 +17,17 @@ /********* Definitions for APCI-1516 card *****/ -// Card Specific information +/* Card Specific information */ #define APCI1516_BOARD_VENDOR_ID 0x15B8 #define APCI1516_ADDRESS_RANGE 8 -//DIGITAL INPUT-OUTPUT DEFINE +/* DIGITAL INPUT-OUTPUT DEFINE */ #define APCI1516_DIGITAL_OP 4 #define APCI1516_DIGITAL_OP_RW 4 #define APCI1516_DIGITAL_IP 0 -// TIMER COUNTER WATCHDOG DEFINES +/* TIMER COUNTER WATCHDOG DEFINES */ #define ADDIDATA_WATCHDOG 2 #define APCI1516_DIGITAL_OP_WATCHDOG 0 @@ -35,24 +35,25 @@ #define APCI1516_WATCHDOG_RELOAD_VALUE 4 #define APCI1516_WATCHDOG_STATUS 16 -// Hardware Layer functions for Apci1516 +/* Hardware Layer functions for Apci1516 */ -//Digital Input -INT i_APCI1516_ReadMoreDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, +/* Digital Input */ +int i_APCI1516_ReadMoreDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -INT i_APCI1516_Read1DigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, +int i_APCI1516_Read1DigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -//Digital Output +/* Digital Output */ int i_APCI1516_ConfigDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -INT i_APCI1516_WriteDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, +int i_APCI1516_WriteDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -INT i_APCI1516_ReadDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, +int i_APCI1516_ReadDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -// TIMER -// timer value is passed as u seconds +/* +* TIMER timer value is passed as u seconds +*/ int i_APCI1516_ConfigWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); int i_APCI1516_StartStopWriteWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, @@ -60,5 +61,5 @@ int i_APCI1516_StartStopWriteWatchdog(struct comedi_device *dev, struct comedi_s int i_APCI1516_ReadWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -//reset -INT i_APCI1516_Reset(struct comedi_device *dev); +/* reset */ +int i_APCI1516_Reset(struct comedi_device *dev); diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c index a6b504c3d391..3a47c3034229 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c @@ -3,13 +3,13 @@ Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data-com - info@addi-data.com + ADDI-DATA GmbH + Dieselstrasse 3 + D-77833 Ottersweier + Tel: +19(0)7223/9493-0 + Fax: +49(0)7223/9493-92 + http://www.addi-data-com + info@addi-data.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. @@ -55,9 +55,9 @@ You shoud also find the complete GPL in the COPYING file accompanying this sourc #include #include "hwdrv_apci1564.h" -//Global variables -UINT ui_InterruptStatus_1564 = 0; -UINT ui_InterruptData, ui_Type; +/* Global variables */ +unsigned int ui_InterruptStatus_1564 = 0; +unsigned int ui_InterruptData, ui_Type; /* +----------------------------------------------------------------------------+ @@ -86,8 +86,8 @@ UINT ui_InterruptData, ui_Type; | | +----------------------------------------------------------------------------+ */ -INT i_APCI1564_ConfigDigitalInput(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI1564_ConfigDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { devpriv->tsk_Current = current; /*******************************/ @@ -106,13 +106,13 @@ INT i_APCI1564_ConfigDigitalInput(struct comedi_device * dev, struct comedi_subd outl(0x4, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + APCI1564_DIGITAL_IP_IRQ); - } // if (data[1] == ADDIDATA_OR) + } /* if (data[1] == ADDIDATA_OR) */ else { outl(0x6, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + APCI1564_DIGITAL_IP_IRQ); - } // else if (data[1] == ADDIDATA_OR) - } // if (data[0] == ADDIDATA_ENABLE) + } /* else if (data[1] == ADDIDATA_OR) */ + } /* if (data[0] == ADDIDATA_ENABLE) */ else { outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + @@ -123,7 +123,7 @@ INT i_APCI1564_ConfigDigitalInput(struct comedi_device * dev, struct comedi_subd outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + APCI1564_DIGITAL_IP_IRQ); - } // else if (data[0] == ADDIDATA_ENABLE) + } /* else if (data[0] == ADDIDATA_ENABLE) */ return insn->n; } @@ -137,7 +137,7 @@ INT i_APCI1564_ConfigDigitalInput(struct comedi_device * dev, struct comedi_subd | Task : Return the status of the digital input | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | -| UINT ui_Channel : Channel number to read | +| unsigned int ui_Channel : Channel number to read | | unsigned int *data : Data Pointer to read status | +----------------------------------------------------------------------------+ | Output Parameters : -- | @@ -147,24 +147,26 @@ INT i_APCI1564_ConfigDigitalInput(struct comedi_device * dev, struct comedi_subd | | +----------------------------------------------------------------------------+ */ -INT i_APCI1564_Read1DigitalInput(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI1564_Read1DigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - UINT ui_TmpValue = 0; - UINT ui_Channel; + unsigned int ui_TmpValue = 0; + unsigned int ui_Channel; ui_Channel = CR_CHAN(insn->chanspec); if (ui_Channel >= 0 && ui_Channel <= 31) { ui_TmpValue = - (UINT) inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP); - // since only 1 channel reqd to bring it to last bit it is rotated - // 8 +(chan - 1) times then ANDed with 1 for last bit. + (unsigned int) inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP); +/* +* since only 1 channel reqd to bring it to last bit it is rotated 8 +* +(chan - 1) times then ANDed with 1 for last bit. +*/ *data = (ui_TmpValue >> ui_Channel) & 0x1; - } // if (ui_Channel >= 0 && ui_Channel <=31) + } /* if (ui_Channel >= 0 && ui_Channel <=31) */ else { comedi_error(dev, "Not a valid channel number !!! \n"); - return -EINVAL; // "sorry channel spec wrong " - } //else if (ui_Channel >= 0 && ui_Channel <=31) + return -EINVAL; /* "sorry channel spec wrong " */ + } /* else if (ui_Channel >= 0 && ui_Channel <=31) */ return insn->n; } @@ -177,8 +179,8 @@ INT i_APCI1564_Read1DigitalInput(struct comedi_device * dev, struct comedi_subde | Task : Return the status of the Requested digital inputs | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | -| UINT ui_NoOfChannels : No Of Channels To be Read | -| UINT *data : Data Pointer to read status | +| unsigned int ui_NoOfChannels : No Of Channels To be Read | +| unsigned int *data : Data Pointer to read status | +----------------------------------------------------------------------------+ | Output Parameters : -- | +----------------------------------------------------------------------------+ @@ -187,16 +189,16 @@ INT i_APCI1564_Read1DigitalInput(struct comedi_device * dev, struct comedi_subde | | +----------------------------------------------------------------------------+ */ -INT i_APCI1564_ReadMoreDigitalInput(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI1564_ReadMoreDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - UINT ui_PortValue = data[0]; - UINT ui_Mask = 0; - UINT ui_NoOfChannels; + unsigned int ui_PortValue = data[0]; + unsigned int ui_Mask = 0; + unsigned int ui_NoOfChannels; ui_NoOfChannels = CR_CHAN(insn->chanspec); if (data[1] == 0) { - *data = (UINT) inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP); + *data = (unsigned int) inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP); switch (ui_NoOfChannels) { case 2: ui_Mask = 3; @@ -218,15 +220,15 @@ INT i_APCI1564_ReadMoreDigitalInput(struct comedi_device * dev, struct comedi_su break; default: comedi_error(dev, "Not a valid Channel number !!!\n"); - return -EINVAL; // "sorry channel spec wrong " + return -EINVAL; /* "sorry channel spec wrong " */ break; - } // switch (ui_NoOfChannels) - } // if (data[1]==0) + } /* switch (ui_NoOfChannels) */ + } /* if (data[1]==0) */ else { if (data[1] == 1) { *data = ui_InterruptStatus_1564; - } // if (data[1]==1) - } // else if (data[1]==0) + } /* if (data[1]==1) */ + } /* else if (data[1]==0) */ return insn->n; } @@ -239,7 +241,7 @@ INT i_APCI1564_ReadMoreDigitalInput(struct comedi_device * dev, struct comedi_su | Task : Configures The Digital Output Subdevice. | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | -| UINT *data : Data Pointer contains | +| unsigned int *data : Data Pointer contains | | configuration parameters as below | | | | data[1] : 1 Enable VCC Interrupt | @@ -255,34 +257,34 @@ INT i_APCI1564_ReadMoreDigitalInput(struct comedi_device * dev, struct comedi_su | | +----------------------------------------------------------------------------+ */ -INT i_APCI1564_ConfigDigitalOutput(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI1564_ConfigDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - ULONG ul_Command = 0; + unsigned int ul_Command = 0; if ((data[0] != 0) && (data[0] != 1)) { comedi_error(dev, "Not a valid Data !!! ,Data should be 1 or 0\n"); return -EINVAL; - } // if ((data[0]!=0) && (data[0]!=1)) + } /* if ((data[0]!=0) && (data[0]!=1)) */ if (data[0]) { devpriv->b_OutputMemoryStatus = ADDIDATA_ENABLE; - } // if (data[0]) + } /* if (data[0]) */ else { devpriv->b_OutputMemoryStatus = ADDIDATA_DISABLE; - } // else if (data[0]) + } /* else if (data[0]) */ if (data[1] == ADDIDATA_ENABLE) { ul_Command = ul_Command | 0x1; - } // if (data[1] == ADDIDATA_ENABLE) + } /* if (data[1] == ADDIDATA_ENABLE) */ else { ul_Command = ul_Command & 0xFFFFFFFE; - } // else if (data[1] == ADDIDATA_ENABLE) + } /* else if (data[1] == ADDIDATA_ENABLE) */ if (data[2] == ADDIDATA_ENABLE) { ul_Command = ul_Command | 0x2; - } // if (data[2] == ADDIDATA_ENABLE) + } /* if (data[2] == ADDIDATA_ENABLE) */ else { ul_Command = ul_Command & 0xFFFFFFFD; - } // else if (data[2] == ADDIDATA_ENABLE) + } /* else if (data[2] == ADDIDATA_ENABLE) */ outl(ul_Command, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP + APCI1564_DIGITAL_OP_INTERRUPT); @@ -302,8 +304,8 @@ INT i_APCI1564_ConfigDigitalOutput(struct comedi_device * dev, struct comedi_sub | Task : Writes port value To the selected port | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | -| UINT ui_NoOfChannels : No Of Channels To Write | -| UINT *data : Data Pointer to read status | +| unsigned int ui_NoOfChannels : No Of Channels To Write | +| unsigned int *data : Data Pointer to read status | +----------------------------------------------------------------------------+ | Output Parameters : -- | +----------------------------------------------------------------------------+ @@ -312,28 +314,28 @@ INT i_APCI1564_ConfigDigitalOutput(struct comedi_device * dev, struct comedi_sub | | +----------------------------------------------------------------------------+ */ -INT i_APCI1564_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI1564_WriteDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - UINT ui_Temp, ui_Temp1; - UINT ui_NoOfChannel; + unsigned int ui_Temp, ui_Temp1; + unsigned int ui_NoOfChannel; ui_NoOfChannel = CR_CHAN(insn->chanspec); if (devpriv->b_OutputMemoryStatus) { ui_Temp = inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP + APCI1564_DIGITAL_OP_RW); - } // if (devpriv->b_OutputMemoryStatus ) + } /* if (devpriv->b_OutputMemoryStatus ) */ else { ui_Temp = 0; - } // else if (devpriv->b_OutputMemoryStatus ) + } /* else if (devpriv->b_OutputMemoryStatus ) */ if (data[3] == 0) { if (data[1] == 0) { data[0] = (data[0] << ui_NoOfChannel) | ui_Temp; outl(data[0], devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP + APCI1564_DIGITAL_OP_RW); - } // if (data[1]==0) + } /* if (data[1]==0) */ else { if (data[1] == 1) { switch (ui_NoOfChannel) { @@ -362,18 +364,18 @@ INT i_APCI1564_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subd break; default: comedi_error(dev, " chan spec wrong"); - return -EINVAL; // "sorry channel spec wrong " - } // switch (ui_NoOfChannels) + return -EINVAL; /* "sorry channel spec wrong " */ + } /* switch (ui_NoOfChannels) */ outl(data[0], devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP + APCI1564_DIGITAL_OP_RW); - } // if (data[1]==1) + } /* if (data[1]==1) */ else { printk("\nSpecified channel not supported\n"); - } // else if (data[1]==1) - } // else if (data[1]==0) - } //if(data[3]==0) + } /* else if (data[1]==1) */ + } /* else if (data[1]==0) */ + } /* if(data[3]==0) */ else { if (data[3] == 1) { if (data[1] == 0) { @@ -389,7 +391,7 @@ INT i_APCI1564_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subd devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP + APCI1564_DIGITAL_OP_RW); - } // if (data[1]==0) + } /* if (data[1]==0) */ else { if (data[1] == 1) { switch (ui_NoOfChannel) { @@ -447,23 +449,23 @@ INT i_APCI1564_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subd default: comedi_error(dev, " chan spec wrong"); - return -EINVAL; // "sorry channel spec wrong " - } //switch(ui_NoOfChannels) + return -EINVAL; /* "sorry channel spec wrong " */ + } /* switch(ui_NoOfChannels) */ outl(data[0], devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP + APCI1564_DIGITAL_OP_RW); - } // if (data[1]==1) + } /* if (data[1]==1) */ else { printk("\nSpecified channel not supported\n"); - } // else if (data[1]==1) - } // else if (data[1]==0) - } // if (data[3]==1); + } /* else if (data[1]==1) */ + } /* else if (data[1]==0) */ + } /* if (data[3]==1); */ else { printk("\nSpecified functionality does not exist\n"); return -EINVAL; - } // else if (data[3]==1) - } // else if (data[3]==0) + } /* else if (data[3]==1) */ + } /* else if (data[3]==0) */ return insn->n; } @@ -476,8 +478,8 @@ INT i_APCI1564_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subd | Task : Read value of the selected channel or port | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | -| UINT ui_NoOfChannels : No Of Channels To read | -| UINT *data : Data Pointer to read status | +| unsigned int ui_NoOfChannels : No Of Channels To read | +| unsigned int *data : Data Pointer to read status | +----------------------------------------------------------------------------+ | Output Parameters : -- | +----------------------------------------------------------------------------+ @@ -486,11 +488,11 @@ INT i_APCI1564_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subd | | +----------------------------------------------------------------------------+ */ -INT i_APCI1564_ReadDigitalOutput(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI1564_ReadDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - UINT ui_Temp; - UINT ui_NoOfChannel; + unsigned int ui_Temp; + unsigned int ui_NoOfChannel; ui_NoOfChannel = CR_CHAN(insn->chanspec); ui_Temp = data[0]; @@ -498,7 +500,7 @@ INT i_APCI1564_ReadDigitalOutput(struct comedi_device * dev, struct comedi_subde APCI1564_DIGITAL_OP_RW); if (ui_Temp == 0) { *data = (*data >> ui_NoOfChannel) & 0x1; - } // if (ui_Temp==0) + } /* if (ui_Temp==0) */ else { if (ui_Temp == 1) { switch (ui_NoOfChannel) { @@ -523,14 +525,14 @@ INT i_APCI1564_ReadDigitalOutput(struct comedi_device * dev, struct comedi_subde default: comedi_error(dev, " chan spec wrong"); - return -EINVAL; // "sorry channel spec wrong " + return -EINVAL; /* "sorry channel spec wrong " */ break; - } // switch(ui_NoOfChannels) - } // if (ui_Temp==1) + } /* switch(ui_NoOfChannels) */ + } /* if (ui_Temp==1) */ else { printk("\nSpecified channel not supported \n"); - } // else if (ui_Temp==1) - } // else if (ui_Temp==0) + } /* else if (ui_Temp==1) */ + } /* else if (ui_Temp==0) */ return insn->n; } @@ -543,7 +545,7 @@ INT i_APCI1564_ReadDigitalOutput(struct comedi_device * dev, struct comedi_subde | Task : Configures The Timer , Counter or Watchdog | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | -| UINT *data : Data Pointer contains | +| unsigned int *data : Data Pointer contains | | configuration parameters as below | | | | data[0] : 0 Configure As Timer | @@ -564,34 +566,34 @@ INT i_APCI1564_ReadDigitalOutput(struct comedi_device * dev, struct comedi_subde | | +----------------------------------------------------------------------------+ */ -INT i_APCI1564_ConfigTimerCounterWatchdog(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +int i_APCI1564_ConfigTimerCounterWatchdog(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - ULONG ul_Command1 = 0; + unsigned int ul_Command1 = 0; devpriv->tsk_Current = current; if (data[0] == ADDIDATA_WATCHDOG) { devpriv->b_TimerSelectMode = ADDIDATA_WATCHDOG; - //Disable the watchdog + /* Disable the watchdog */ outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP_WATCHDOG + APCI1564_TCW_PROG); - //Loading the Reload value + /* Loading the Reload value */ outl(data[3], devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP_WATCHDOG + APCI1564_TCW_RELOAD_VALUE); - } // if (data[0]==ADDIDATA_WATCHDOG) + } /* if (data[0]==ADDIDATA_WATCHDOG) */ else if (data[0] == ADDIDATA_TIMER) { - //First Stop The Timer + /* First Stop The Timer */ ul_Command1 = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER + APCI1564_TCW_PROG); ul_Command1 = ul_Command1 & 0xFFFFF9FEUL; - outl(ul_Command1, devpriv->i_IobaseAmcc + APCI1564_TIMER + APCI1564_TCW_PROG); //Stop The Timer + outl(ul_Command1, devpriv->i_IobaseAmcc + APCI1564_TIMER + APCI1564_TCW_PROG); /* Stop The Timer */ devpriv->b_TimerSelectMode = ADDIDATA_TIMER; if (data[1] == 1) { - outl(0x02, devpriv->i_IobaseAmcc + APCI1564_TIMER + APCI1564_TCW_PROG); //Enable TIMER int & DISABLE ALL THE OTHER int SOURCES + outl(0x02, devpriv->i_IobaseAmcc + APCI1564_TIMER + APCI1564_TCW_PROG); /* Enable TIMER int & DISABLE ALL THE OTHER int SOURCES */ outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + APCI1564_DIGITAL_IP_IRQ); @@ -614,18 +616,18 @@ INT i_APCI1564_ConfigTimerCounterWatchdog(struct comedi_device * dev, outl(0x0, devpriv->iobase + APCI1564_COUNTER4 + APCI1564_TCW_IRQ); - } // if (data[1]==1) + } /* if (data[1]==1) */ else { - outl(0x0, devpriv->i_IobaseAmcc + APCI1564_TIMER + APCI1564_TCW_PROG); //disable Timer interrupt - } // else if (data[1]==1) + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_TIMER + APCI1564_TCW_PROG); /* disable Timer interrupt */ + } /* else if (data[1]==1) */ - // Loading Timebase + /* Loading Timebase */ outl(data[2], devpriv->i_IobaseAmcc + APCI1564_TIMER + APCI1564_TCW_TIMEBASE); - //Loading the Reload value + /* Loading the Reload value */ outl(data[3], devpriv->i_IobaseAmcc + APCI1564_TIMER + APCI1564_TCW_RELOAD_VALUE); @@ -635,18 +637,18 @@ INT i_APCI1564_ConfigTimerCounterWatchdog(struct comedi_device * dev, APCI1564_TCW_PROG); ul_Command1 = (ul_Command1 & 0xFFF719E2UL) | 2UL << 13UL | 0x10UL; - outl(ul_Command1, devpriv->i_IobaseAmcc + APCI1564_TIMER + APCI1564_TCW_PROG); //mode 2 - } // else if (data[0]==ADDIDATA_TIMER) + outl(ul_Command1, devpriv->i_IobaseAmcc + APCI1564_TIMER + APCI1564_TCW_PROG); /* mode 2 */ + } /* else if (data[0]==ADDIDATA_TIMER) */ else if (data[0] == ADDIDATA_COUNTER) { devpriv->b_TimerSelectMode = ADDIDATA_COUNTER; devpriv->b_ModeSelectRegister = data[5]; - //First Stop The Counter + /* First Stop The Counter */ ul_Command1 = inl(devpriv->iobase + ((data[5] - 1) * 0x20) + APCI1564_TCW_PROG); ul_Command1 = ul_Command1 & 0xFFFFF9FEUL; - outl(ul_Command1, devpriv->iobase + ((data[5] - 1) * 0x20) + APCI1564_TCW_PROG); //Stop The Timer + outl(ul_Command1, devpriv->iobase + ((data[5] - 1) * 0x20) + APCI1564_TCW_PROG); /* Stop The Timer */ /************************/ /* Set the reload value */ @@ -666,12 +668,12 @@ INT i_APCI1564_ConfigTimerCounterWatchdog(struct comedi_device * dev, /******************************/ ul_Command1 = (ul_Command1 & 0xFFFC19E2UL) | 0x80000UL | - (ULONG) ((ULONG) data[4] << 16UL); + (unsigned int) ((unsigned int) data[4] << 16UL); outl(ul_Command1, devpriv->iobase + ((data[5] - 1) * 0x20) + APCI1564_TCW_PROG); - // Enable or Disable Interrupt + /* Enable or Disable Interrupt */ ul_Command1 = (ul_Command1 & 0xFFFFF9FD) | (data[1] << 1); outl(ul_Command1, devpriv->iobase + ((data[5] - 1) * 0x20) + @@ -684,10 +686,10 @@ INT i_APCI1564_ConfigTimerCounterWatchdog(struct comedi_device * dev, outl(ul_Command1, devpriv->iobase + ((data[5] - 1) * 0x20) + APCI1564_TCW_PROG); - } // else if (data[0]==ADDIDATA_COUNTER) + } /* else if (data[0]==ADDIDATA_COUNTER) */ else { printk(" Invalid subdevice."); - } // else if (data[0]==ADDIDATA_WATCHDOG) + } /* else if (data[0]==ADDIDATA_WATCHDOG) */ return insn->n; } @@ -701,7 +703,7 @@ INT i_APCI1564_ConfigTimerCounterWatchdog(struct comedi_device * dev, | Task : Start / Stop The Selected Timer , Counter or Watchdog | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | -| UINT *data : Data Pointer contains | +| unsigned int *data : Data Pointer contains | | configuration parameters as below | | | | data[0] : 0 Timer | @@ -718,22 +720,22 @@ INT i_APCI1564_ConfigTimerCounterWatchdog(struct comedi_device * dev, | | +----------------------------------------------------------------------------+ */ -INT i_APCI1564_StartStopWriteTimerCounterWatchdog(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +int i_APCI1564_StartStopWriteTimerCounterWatchdog(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - ULONG ul_Command1 = 0; + unsigned int ul_Command1 = 0; if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) { switch (data[1]) { - case 0: //stop the watchdog - outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP_WATCHDOG + APCI1564_TCW_PROG); //disable the watchdog + case 0: /* stop the watchdog */ + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP_WATCHDOG + APCI1564_TCW_PROG); /* disable the watchdog */ break; - case 1: //start the watchdog + case 1: /* start the watchdog */ outl(0x0001, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP_WATCHDOG + APCI1564_TCW_PROG); break; - case 2: //Software trigger + case 2: /* Software trigger */ outl(0x0201, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP_WATCHDOG + @@ -742,8 +744,8 @@ INT i_APCI1564_StartStopWriteTimerCounterWatchdog(struct comedi_device * dev, default: printk("\nSpecified functionality does not exist\n"); return -EINVAL; - } // switch (data[1]) - } // if (devpriv->b_TimerSelectMode==ADDIDATA_WATCHDOG) + } /* switch (data[1]) */ + } /* if (devpriv->b_TimerSelectMode==ADDIDATA_WATCHDOG) */ if (devpriv->b_TimerSelectMode == ADDIDATA_TIMER) { if (data[1] == 1) { ul_Command1 = @@ -751,13 +753,13 @@ INT i_APCI1564_StartStopWriteTimerCounterWatchdog(struct comedi_device * dev, APCI1564_TCW_PROG); ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x1UL; - //Enable the Timer + /* Enable the Timer */ outl(ul_Command1, devpriv->i_IobaseAmcc + APCI1564_TIMER + APCI1564_TCW_PROG); - } // if (data[1]==1) + } /* if (data[1]==1) */ else if (data[1] == 0) { - //Stop The Timer + /* Stop The Timer */ ul_Command1 = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER + @@ -766,29 +768,29 @@ INT i_APCI1564_StartStopWriteTimerCounterWatchdog(struct comedi_device * dev, outl(ul_Command1, devpriv->i_IobaseAmcc + APCI1564_TIMER + APCI1564_TCW_PROG); - } // else if(data[1]==0) - } // if (devpriv->b_TimerSelectMode==ADDIDATA_TIMER) + } /* else if(data[1]==0) */ + } /* if (devpriv->b_TimerSelectMode==ADDIDATA_TIMER) */ if (devpriv->b_TimerSelectMode == ADDIDATA_COUNTER) { ul_Command1 = inl(devpriv->iobase + ((devpriv->b_ModeSelectRegister - 1) * 0x20) + APCI1564_TCW_PROG); if (data[1] == 1) { - //Start the Counter subdevice + /* Start the Counter subdevice */ ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x1UL; - } // if (data[1] == 1) + } /* if (data[1] == 1) */ else if (data[1] == 0) { - // Stops the Counter subdevice + /* Stops the Counter subdevice */ ul_Command1 = 0; - } // else if (data[1] == 0) + } /* else if (data[1] == 0) */ else if (data[1] == 2) { - // Clears the Counter subdevice + /* Clears the Counter subdevice */ ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x400; - } // else if (data[1] == 3) + } /* else if (data[1] == 3) */ outl(ul_Command1, devpriv->iobase + ((devpriv->b_ModeSelectRegister - 1) * 0x20) + APCI1564_TCW_PROG); - } // if (devpriv->b_TimerSelectMode==ADDIDATA_COUNTER) + } /* if (devpriv->b_TimerSelectMode==ADDIDATA_COUNTER) */ return insn->n; } @@ -801,7 +803,7 @@ INT i_APCI1564_StartStopWriteTimerCounterWatchdog(struct comedi_device * dev, | Task : Read The Selected Timer , Counter or Watchdog | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | -| UINT *data : Data Pointer contains | +| unsigned int *data : Data Pointer contains | | configuration parameters as below | | | @@ -813,13 +815,13 @@ INT i_APCI1564_StartStopWriteTimerCounterWatchdog(struct comedi_device * dev, | | +----------------------------------------------------------------------------+ */ -INT i_APCI1564_ReadTimerCounterWatchdog(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +int i_APCI1564_ReadTimerCounterWatchdog(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - ULONG ul_Command1 = 0; + unsigned int ul_Command1 = 0; if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) { - // Stores the status of the Watchdog + /* Stores the status of the Watchdog */ data[0] = inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP_WATCHDOG + @@ -827,18 +829,18 @@ INT i_APCI1564_ReadTimerCounterWatchdog(struct comedi_device * dev, data[1] = inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP_WATCHDOG); - } // if (devpriv->b_TimerSelectMode==ADDIDATA_WATCHDOG) + } /* if (devpriv->b_TimerSelectMode==ADDIDATA_WATCHDOG) */ else if (devpriv->b_TimerSelectMode == ADDIDATA_TIMER) { - // Stores the status of the Timer + /* Stores the status of the Timer */ data[0] = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER + APCI1564_TCW_TRIG_STATUS) & 0x1; - // Stores the Actual value of the Timer + /* Stores the Actual value of the Timer */ data[1] = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER); - } // else if (devpriv->b_TimerSelectMode==ADDIDATA_TIMER) + } /* else if (devpriv->b_TimerSelectMode==ADDIDATA_TIMER) */ else if (devpriv->b_TimerSelectMode == ADDIDATA_COUNTER) { - // Read the Counter Actual Value. + /* Read the Counter Actual Value. */ data[0] = inl(devpriv->iobase + ((devpriv->b_ModeSelectRegister - 1) * 0x20) + @@ -850,28 +852,28 @@ INT i_APCI1564_ReadTimerCounterWatchdog(struct comedi_device * dev, /***********************************/ /* Get the software trigger status */ /***********************************/ - data[1] = (BYTE) ((ul_Command1 >> 1) & 1); + data[1] = (unsigned char) ((ul_Command1 >> 1) & 1); /***********************************/ /* Get the hardware trigger status */ /***********************************/ - data[2] = (BYTE) ((ul_Command1 >> 2) & 1); + data[2] = (unsigned char) ((ul_Command1 >> 2) & 1); /*********************************/ /* Get the software clear status */ /*********************************/ - data[3] = (BYTE) ((ul_Command1 >> 3) & 1); + data[3] = (unsigned char) ((ul_Command1 >> 3) & 1); /***************************/ /* Get the overflow status */ /***************************/ - data[4] = (BYTE) ((ul_Command1 >> 0) & 1); - } // else if (devpriv->b_TimerSelectMode==ADDIDATA_COUNTER) + data[4] = (unsigned char) ((ul_Command1 >> 0) & 1); + } /* else if (devpriv->b_TimerSelectMode==ADDIDATA_COUNTER) */ else if ((devpriv->b_TimerSelectMode != ADDIDATA_TIMER) && (devpriv->b_TimerSelectMode != ADDIDATA_WATCHDOG) && (devpriv->b_TimerSelectMode != ADDIDATA_COUNTER)) { printk("\n Invalid Subdevice !!!\n"); - } // else if ((devpriv->b_TimerSelectMode!=ADDIDATA_TIMER) && (devpriv->b_TimerSelectMode!=ADDIDATA_WATCHDOG)&& (devpriv->b_TimerSelectMode!=ADDIDATA_COUNTER)) + } /* else if ((devpriv->b_TimerSelectMode!=ADDIDATA_TIMER) && (devpriv->b_TimerSelectMode!=ADDIDATA_WATCHDOG)&& (devpriv->b_TimerSelectMode!=ADDIDATA_COUNTER)) */ return insn->n; } @@ -892,8 +894,8 @@ INT i_APCI1564_ReadTimerCounterWatchdog(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -int i_APCI1564_ReadInterruptStatus(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI1564_ReadInterruptStatus(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { *data = ui_Type; return insn->n; @@ -919,10 +921,10 @@ int i_APCI1564_ReadInterruptStatus(struct comedi_device * dev, struct comedi_sub static void v_APCI1564_Interrupt(int irq, void *d) { struct comedi_device *dev = d; - UINT ui_DO, ui_DI; - UINT ui_Timer; - UINT ui_C1, ui_C2, ui_C3, ui_C4; - ULONG ul_Command2 = 0; + unsigned int ui_DO, ui_DI; + unsigned int ui_Timer; + unsigned int ui_C1, ui_C2, ui_C3, ui_C4; + unsigned int ul_Command2 = 0; ui_DI = inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + APCI1564_DIGITAL_IP_IRQ) & 0x01; ui_DO = inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP + @@ -941,7 +943,7 @@ static void v_APCI1564_Interrupt(int irq, void *d) if (ui_DI == 0 && ui_DO == 0 && ui_Timer == 0 && ui_C1 == 0 && ui_C2 == 0 && ui_C3 == 0 && ui_C4 == 0) { printk("\nInterrupt from unknown source\n"); - } // if(ui_DI==0 && ui_DO==0 && ui_Timer==0 && ui_C1==0 && ui_C2==0 && ui_C3==0 && ui_C4==0) + } /* if(ui_DI==0 && ui_DO==0 && ui_Timer==0 && ui_C1==0 && ui_C2==0 && ui_C3==0 && ui_C4==0) */ if (ui_DI == 1) { ui_DI = inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + @@ -953,116 +955,137 @@ static void v_APCI1564_Interrupt(int irq, void *d) inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + APCI1564_DIGITAL_IP_INTERRUPT_STATUS); ui_InterruptStatus_1564 = ui_InterruptStatus_1564 & 0X000FFFF0; - send_sig(SIGIO, devpriv->tsk_Current, 0); // send signal to the sample - outl(ui_DI, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + APCI1564_DIGITAL_IP_IRQ); //enable the interrupt + send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */ + outl(ui_DI, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + APCI1564_DIGITAL_IP_IRQ); /* enable the interrupt */ return; } if (ui_DO == 1) { - // Check for Digital Output interrupt Type - 1: Vcc interrupt 2: CC interrupt. + /* Check for Digital Output interrupt Type - 1: Vcc interrupt 2: CC interrupt. */ ui_Type = inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP + APCI1564_DIGITAL_OP_INTERRUPT_STATUS) & 0x3; - //Disable the Interrupt + /* Disable the Interrupt */ outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP + APCI1564_DIGITAL_OP_INTERRUPT); - //Sends signal to user space + /* Sends signal to user space */ send_sig(SIGIO, devpriv->tsk_Current, 0); - } // if (ui_DO) + } /* if (ui_DO) */ - if ((ui_Timer == 1) && (devpriv->b_TimerSelectMode = ADDIDATA_TIMER)) { - // Disable Timer Interrupt - ul_Command2 = - inl(devpriv->i_IobaseAmcc + APCI1564_TIMER + - APCI1564_TCW_PROG); - outl(0x0, - devpriv->i_IobaseAmcc + APCI1564_TIMER + - APCI1564_TCW_PROG); + if (ui_Timer == 1) { + devpriv->b_TimerSelectMode = ADDIDATA_TIMER; + if (devpriv->b_TimerSelectMode) { - //Send a signal to from kernel to user space - send_sig(SIGIO, devpriv->tsk_Current, 0); + /* Disable Timer Interrupt */ + ul_Command2 = + inl(devpriv->i_IobaseAmcc + APCI1564_TIMER + + APCI1564_TCW_PROG); + outl(0x0, + devpriv->i_IobaseAmcc + APCI1564_TIMER + + APCI1564_TCW_PROG); - // Enable Timer Interrupt + /* Send a signal to from kernel to user space */ + send_sig(SIGIO, devpriv->tsk_Current, 0); - outl(ul_Command2, - devpriv->i_IobaseAmcc + APCI1564_TIMER + - APCI1564_TCW_PROG); - } // if ((ui_Timer == 1) && (devpriv->b_TimerSelectMode =ADDIDATA_TIMER)) + /* Enable Timer Interrupt */ - if ((ui_C1 == 1) && (devpriv->b_TimerSelectMode = ADDIDATA_COUNTER)) { - // Disable Counter Interrupt - ul_Command2 = - inl(devpriv->iobase + APCI1564_COUNTER1 + - APCI1564_TCW_PROG); - outl(0x0, - devpriv->iobase + APCI1564_COUNTER1 + - APCI1564_TCW_PROG); + outl(ul_Command2, + devpriv->i_IobaseAmcc + APCI1564_TIMER + + APCI1564_TCW_PROG); + } + }/* if (ui_Timer == 1) */ - //Send a signal to from kernel to user space - send_sig(SIGIO, devpriv->tsk_Current, 0); - // Enable Counter Interrupt - outl(ul_Command2, - devpriv->iobase + APCI1564_COUNTER1 + - APCI1564_TCW_PROG); - } // if ((ui_C1 == 1) && (devpriv->b_TimerSelectMode = ADDIDATA_COUNTER)) + if (ui_C1 == 1) { + devpriv->b_TimerSelectMode = ADDIDATA_COUNTER; + if (devpriv->b_TimerSelectMode) { - if ((ui_C2 == 1) && (devpriv->b_TimerSelectMode = ADDIDATA_COUNTER)) { - // Disable Counter Interrupt - ul_Command2 = - inl(devpriv->iobase + APCI1564_COUNTER2 + - APCI1564_TCW_PROG); - outl(0x0, - devpriv->iobase + APCI1564_COUNTER2 + - APCI1564_TCW_PROG); + /* Disable Counter Interrupt */ + ul_Command2 = + inl(devpriv->iobase + APCI1564_COUNTER1 + + APCI1564_TCW_PROG); + outl(0x0, + devpriv->iobase + APCI1564_COUNTER1 + + APCI1564_TCW_PROG); - //Send a signal to from kernel to user space - send_sig(SIGIO, devpriv->tsk_Current, 0); + /* Send a signal to from kernel to user space */ + send_sig(SIGIO, devpriv->tsk_Current, 0); - // Enable Counter Interrupt - outl(ul_Command2, - devpriv->iobase + APCI1564_COUNTER2 + - APCI1564_TCW_PROG); - } // if ((ui_C2 == 1) && (devpriv->b_TimerSelectMode =ADDIDATA_COUNTER)) + /* Enable Counter Interrupt */ + outl(ul_Command2, + devpriv->iobase + APCI1564_COUNTER1 + + APCI1564_TCW_PROG); + } + } /* if (ui_C1 == 1) */ - if ((ui_C3 == 1) && (devpriv->b_TimerSelectMode = ADDIDATA_COUNTER)) { - // Disable Counter Interrupt - ul_Command2 = - inl(devpriv->iobase + APCI1564_COUNTER3 + - APCI1564_TCW_PROG); - outl(0x0, - devpriv->iobase + APCI1564_COUNTER3 + - APCI1564_TCW_PROG); + if (ui_C2 == 1) { + devpriv->b_TimerSelectMode = ADDIDATA_COUNTER; + if (devpriv->b_TimerSelectMode) { - //Send a signal to from kernel to user space - send_sig(SIGIO, devpriv->tsk_Current, 0); + /* Disable Counter Interrupt */ + ul_Command2 = + inl(devpriv->iobase + APCI1564_COUNTER2 + + APCI1564_TCW_PROG); + outl(0x0, + devpriv->iobase + APCI1564_COUNTER2 + + APCI1564_TCW_PROG); - // Enable Counter Interrupt - outl(ul_Command2, - devpriv->iobase + APCI1564_COUNTER3 + - APCI1564_TCW_PROG); - } // if ((ui_C3 == 1) && (devpriv->b_TimerSelectMode =ADDIDATA_COUNTER)) + /* Send a signal to from kernel to user space */ + send_sig(SIGIO, devpriv->tsk_Current, 0); - if ((ui_C4 == 1) && (devpriv->b_TimerSelectMode = ADDIDATA_COUNTER)) { - // Disable Counter Interrupt - ul_Command2 = - inl(devpriv->iobase + APCI1564_COUNTER4 + - APCI1564_TCW_PROG); - outl(0x0, - devpriv->iobase + APCI1564_COUNTER4 + - APCI1564_TCW_PROG); + /* Enable Counter Interrupt */ + outl(ul_Command2, + devpriv->iobase + APCI1564_COUNTER2 + + APCI1564_TCW_PROG); + } + } /* if ((ui_C2 == 1) */ - //Send a signal to from kernel to user space - send_sig(SIGIO, devpriv->tsk_Current, 0); + if (ui_C3 == 1) { + devpriv->b_TimerSelectMode = ADDIDATA_COUNTER; + if (devpriv->b_TimerSelectMode) { - // Enable Counter Interrupt - outl(ul_Command2, - devpriv->iobase + APCI1564_COUNTER4 + - APCI1564_TCW_PROG); - } // if ((ui_C4 == 1) && (devpriv->b_TimerSelectMode =ADDIDATA_COUNTER)) + /* Disable Counter Interrupt */ + ul_Command2 = + inl(devpriv->iobase + APCI1564_COUNTER3 + + APCI1564_TCW_PROG); + outl(0x0, + devpriv->iobase + APCI1564_COUNTER3 + + APCI1564_TCW_PROG); + + /* Send a signal to from kernel to user space */ + send_sig(SIGIO, devpriv->tsk_Current, 0); + + /* Enable Counter Interrupt */ + outl(ul_Command2, + devpriv->iobase + APCI1564_COUNTER3 + + APCI1564_TCW_PROG); + } + } /* if ((ui_C3 == 1) */ + + if (ui_C4 == 1) { + devpriv->b_TimerSelectMode = ADDIDATA_COUNTER; + if (devpriv->b_TimerSelectMode) { + + /* Disable Counter Interrupt */ + ul_Command2 = + inl(devpriv->iobase + APCI1564_COUNTER4 + + APCI1564_TCW_PROG); + outl(0x0, + devpriv->iobase + APCI1564_COUNTER4 + + APCI1564_TCW_PROG); + + /* Send a signal to from kernel to user space */ + send_sig(SIGIO, devpriv->tsk_Current, 0); + + /* Enable Counter Interrupt */ + outl(ul_Command2, + devpriv->iobase + APCI1564_COUNTER4 + + APCI1564_TCW_PROG); + } + } /* if (ui_C4 == 1) */ return; } @@ -1081,16 +1104,16 @@ static void v_APCI1564_Interrupt(int irq, void *d) +----------------------------------------------------------------------------+ */ -INT i_APCI1564_Reset(struct comedi_device * dev) +int i_APCI1564_Reset(struct comedi_device *dev) { - outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP_IRQ); //disable the interrupts - inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP_INTERRUPT_STATUS); //Reset the interrupt status register - outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP_INTERRUPT_MODE1); //Disable the and/or interrupt + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP_IRQ); /* disable the interrupts */ + inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP_INTERRUPT_STATUS); /* Reset the interrupt status register */ + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP_INTERRUPT_MODE1); /* Disable the and/or interrupt */ outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP_INTERRUPT_MODE2); devpriv->b_DigitalOutputRegister = 0; ui_Type = 0; - outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP); //Resets the output channels - outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP_INTERRUPT); //Disables the interrupt. + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP); /* Resets the output channels */ + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP_INTERRUPT); /* Disables the interrupt. */ outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP_WATCHDOG + APCI1564_TCW_RELOAD_VALUE); diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.h b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.h index f0c461ca5396..0780c440c44a 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.h +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.h @@ -20,45 +20,45 @@ #define APCI1564_BOARD_VENDOR_ID 0x15B8 #define APCI1564_ADDRESS_RANGE 128 -//DIGITAL INPUT-OUTPUT DEFINE -// Input defines +/* DIGITAL INPUT-OUTPUT DEFINE */ +/* Input defines */ #define APCI1564_DIGITAL_IP 0x04 #define APCI1564_DIGITAL_IP_INTERRUPT_MODE1 4 #define APCI1564_DIGITAL_IP_INTERRUPT_MODE2 8 #define APCI1564_DIGITAL_IP_IRQ 16 -// Output defines +/* Output defines */ #define APCI1564_DIGITAL_OP 0x18 #define APCI1564_DIGITAL_OP_RW 0 #define APCI1564_DIGITAL_OP_INTERRUPT 4 #define APCI1564_DIGITAL_OP_IRQ 12 -//Digital Input IRQ Function Selection +/* Digital Input IRQ Function Selection */ #define ADDIDATA_OR 0 #define ADDIDATA_AND 1 -//Digital Input Interrupt Status +/* Digital Input Interrupt Status */ #define APCI1564_DIGITAL_IP_INTERRUPT_STATUS 12 -//Digital Output Interrupt Status +/* Digital Output Interrupt Status */ #define APCI1564_DIGITAL_OP_INTERRUPT_STATUS 8 -//Digital Input Interrupt Enable Disable. +/* Digital Input Interrupt Enable Disable. */ #define APCI1564_DIGITAL_IP_INTERRUPT_ENABLE 0x4 #define APCI1564_DIGITAL_IP_INTERRUPT_DISABLE 0xFFFFFFFB -//Digital Output Interrupt Enable Disable. +/* Digital Output Interrupt Enable Disable. */ #define APCI1564_DIGITAL_OP_VCC_INTERRUPT_ENABLE 0x1 #define APCI1564_DIGITAL_OP_VCC_INTERRUPT_DISABLE 0xFFFFFFFE #define APCI1564_DIGITAL_OP_CC_INTERRUPT_ENABLE 0x2 #define APCI1564_DIGITAL_OP_CC_INTERRUPT_DISABLE 0xFFFFFFFD -//ADDIDATA Enable Disable +/* ADDIDATA Enable Disable */ #define ADDIDATA_ENABLE 1 #define ADDIDATA_DISABLE 0 -// TIMER COUNTER WATCHDOG DEFINES +/* TIMER COUNTER WATCHDOG DEFINES */ #define ADDIDATA_TIMER 0 #define ADDIDATA_COUNTER 1 @@ -78,30 +78,32 @@ #define APCI1564_TCW_WARN_TIMEVAL 24 #define APCI1564_TCW_WARN_TIMEBASE 28 -// Hardware Layer functions for Apci1564 +/* Hardware Layer functions for Apci1564 */ -//DI -// for di read -INT i_APCI1564_ConfigDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, +/* +* DI for di read +*/ +int i_APCI1564_ConfigDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -INT i_APCI1564_Read1DigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, +int i_APCI1564_Read1DigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -INT i_APCI1564_ReadMoreDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, +int i_APCI1564_ReadMoreDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -//DO +/* DO */ int i_APCI1564_ConfigDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -INT i_APCI1564_WriteDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, +int i_APCI1564_WriteDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -INT i_APCI1564_ReadDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, +int i_APCI1564_ReadDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); int i_APCI1564_ReadInterruptStatus(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -// TIMER -// timer value is passed as u seconds -INT i_APCI1564_ConfigTimerCounterWatchdog(struct comedi_device *dev, +/* +* TIMER timer value is passed as u seconds +*/ +int i_APCI1564_ConfigTimerCounterWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); int i_APCI1564_StartStopWriteTimerCounterWatchdog(struct comedi_device *dev, @@ -112,8 +114,8 @@ int i_APCI1564_ReadTimerCounterWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -// INTERRUPT +/* intERRUPT */ static void v_APCI1564_Interrupt(int irq, void *d); -// RESET -INT i_APCI1564_Reset(struct comedi_device *dev); +/* RESET */ +int i_APCI1564_Reset(struct comedi_device *dev); diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci16xx.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci16xx.c index 906d635da6b2..988e3fc2b857 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci16xx.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci16xx.c @@ -3,13 +3,13 @@ Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data-com - info@addi-data.com + ADDI-DATA GmbH + Dieselstrasse 3 + D-77833 Ottersweier + Tel: +19(0)7223/9493-0 + Fax: +49(0)7223/9493-92 + http://www.addi-data-com + info@addi-data.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. @@ -57,7 +57,7 @@ You shoud also find the complete GPL in the COPYING file accompanying this sourc /* +----------------------------------------------------------------------------+ -| Function Name : INT i_APCI16XX_InsnConfigInitTTLIO | +| Function Name : int i_APCI16XX_InsnConfigInitTTLIO | | (struct comedi_device *dev, | | struct comedi_subdevice *s, | | struct comedi_insn *insn, | @@ -69,11 +69,11 @@ You shoud also find the complete GPL in the COPYING file accompanying this sourc | for you call any other function witch access of TTL. | | APCI16XX_TTL_INITDIRECTION(user inputs for direction) | +----------------------------------------------------------------------------+ -| Input Parameters : b_InitType = (BYTE) data[0]; | -| b_Port0Mode = (BYTE) data[1]; | -| b_Port1Mode = (BYTE) data[2]; | -| b_Port2Mode = (BYTE) data[3]; | -| b_Port3Mode = (BYTE) data[4]; | +| Input Parameters : b_InitType = (unsigned char) data[0]; | +| b_Port0Mode = (unsigned char) data[1]; | +| b_Port1Mode = (unsigned char) data[2]; | +| b_Port2Mode = (unsigned char) data[3]; | +| b_Port3Mode = (unsigned char) data[4]; | | ........ | +----------------------------------------------------------------------------+ | Output Parameters : - | @@ -90,14 +90,14 @@ You shoud also find the complete GPL in the COPYING file accompanying this sourc +----------------------------------------------------------------------------+ */ -int i_APCI16XX_InsnConfigInitTTLIO(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +int i_APCI16XX_InsnConfigInitTTLIO(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - INT i_ReturnValue = insn->n; - BYTE b_Command = 0; - BYTE b_Cpt = 0; - BYTE b_NumberOfPort = - (BYTE) (devpriv->ps_BoardInfo->i_NbrTTLChannel / 8); + int i_ReturnValue = insn->n; + unsigned char b_Command = 0; + unsigned char b_Cpt = 0; + unsigned char b_NumberOfPort = + (unsigned char) (devpriv->ps_BoardInfo->i_NbrTTLChannel / 8); /************************/ /* Test the buffer size */ @@ -108,7 +108,7 @@ int i_APCI16XX_InsnConfigInitTTLIO(struct comedi_device * dev, /* Get the command */ /* **************** */ - b_Command = (BYTE) data[0]; + b_Command = (unsigned char) data[0]; /********************/ /* Test the command */ @@ -122,7 +122,7 @@ int i_APCI16XX_InsnConfigInitTTLIO(struct comedi_device * dev, /***************************************/ if ((b_Command == APCI16XX_TTL_INITDIRECTION) - && ((BYTE) (insn->n - 1) != b_NumberOfPort)) { + && ((unsigned char) (insn->n - 1) != b_NumberOfPort)) { /*******************/ /* Data size error */ /*******************/ @@ -132,7 +132,7 @@ int i_APCI16XX_InsnConfigInitTTLIO(struct comedi_device * dev, } if ((b_Command == APCI16XX_TTL_OUTPUTMEMORY) - && ((BYTE) (insn->n) != 2)) { + && ((unsigned char) (insn->n) != 2)) { /*******************/ /* Data size error */ /*******************/ @@ -182,8 +182,8 @@ int i_APCI16XX_InsnConfigInitTTLIO(struct comedi_device * dev, /************************/ printk("\nPort %d direction selection error", - (INT) b_Cpt); - i_ReturnValue = -(INT) b_Cpt; + (int) b_Cpt); + i_ReturnValue = -(int) b_Cpt; } /**************************/ @@ -239,7 +239,7 @@ int i_APCI16XX_InsnConfigInitTTLIO(struct comedi_device * dev, } } - return (i_ReturnValue); + return i_ReturnValue; } /* @@ -250,7 +250,7 @@ int i_APCI16XX_InsnConfigInitTTLIO(struct comedi_device * dev, /* +----------------------------------------------------------------------------+ -| Function Name : INT i_APCI16XX_InsnBitsReadTTLIO | +| Function Name : int i_APCI16XX_InsnBitsReadTTLIO | | (struct comedi_device *dev, | | struct comedi_subdevice *s, | | struct comedi_insn *insn, | @@ -266,11 +266,11 @@ int i_APCI16XX_InsnConfigInitTTLIO(struct comedi_device * dev, | APCI16XX_TTL_READCHANNEL | | b_SelectedPort= CR_RANGE(insn->chanspec); | | b_InputChannel= CR_CHAN(insn->chanspec); | -| b_ReadType = (BYTE) data[0]; | +| b_ReadType = (unsigned char) data[0]; | | | | APCI16XX_TTL_READPORT | | b_SelectedPort= CR_RANGE(insn->chanspec); | -| b_ReadType = (BYTE) data[0]; | +| b_ReadType = (unsigned char) data[0]; | +----------------------------------------------------------------------------+ | Output Parameters : data[0] 0 : Channle is not active | | 1 : Channle is active | @@ -283,17 +283,17 @@ int i_APCI16XX_InsnConfigInitTTLIO(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -int i_APCI16XX_InsnBitsReadTTLIO(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +int i_APCI16XX_InsnBitsReadTTLIO(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - INT i_ReturnValue = insn->n; - BYTE b_Command = 0; - BYTE b_NumberOfPort = - (BYTE) (devpriv->ps_BoardInfo->i_NbrTTLChannel / 8); - BYTE b_SelectedPort = CR_RANGE(insn->chanspec); - BYTE b_InputChannel = CR_CHAN(insn->chanspec); - BYTE *pb_Status; - DWORD dw_Status; + int i_ReturnValue = insn->n; + unsigned char b_Command = 0; + unsigned char b_NumberOfPort = + (unsigned char) (devpriv->ps_BoardInfo->i_NbrTTLChannel / 8); + unsigned char b_SelectedPort = CR_RANGE(insn->chanspec); + unsigned char b_InputChannel = CR_CHAN(insn->chanspec); + unsigned char *pb_Status; + unsigned int dw_Status; /************************/ /* Test the buffer size */ @@ -304,7 +304,7 @@ int i_APCI16XX_InsnBitsReadTTLIO(struct comedi_device * dev, /* Get the command */ /* **************** */ - b_Command = (BYTE) data[0]; + b_Command = (unsigned char) data[0]; /********************/ /* Test the command */ @@ -380,7 +380,7 @@ int i_APCI16XX_InsnBitsReadTTLIO(struct comedi_device * dev, /**************************/ if (i_ReturnValue >= 0) { - pb_Status = (PBYTE) & data[0]; + pb_Status = (unsigned char *) &data[0]; /*******************************/ /* Get the digital inpu status */ @@ -394,7 +394,7 @@ int i_APCI16XX_InsnBitsReadTTLIO(struct comedi_device * dev, /* Save the port value */ /***********************/ - *pb_Status = (BYTE) dw_Status; + *pb_Status = (unsigned char) dw_Status; /***************************************/ /* Test if read channel status command */ @@ -405,12 +405,12 @@ int i_APCI16XX_InsnBitsReadTTLIO(struct comedi_device * dev, } } - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ -| Function Name : INT i_APCI16XX_InsnReadTTLIOAllPortValue | +| Function Name : int i_APCI16XX_InsnReadTTLIOAllPortValue | | (struct comedi_device *dev, | | struct comedi_subdevice *s, | | struct comedi_insn *insn, | @@ -430,13 +430,13 @@ int i_APCI16XX_InsnBitsReadTTLIO(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -int i_APCI16XX_InsnReadTTLIOAllPortValue(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +int i_APCI16XX_InsnReadTTLIOAllPortValue(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - BYTE b_Command = (BYTE) CR_AREF(insn->chanspec); - INT i_ReturnValue = insn->n; - BYTE b_Cpt = 0; - BYTE b_NumberOfPort = 0; + unsigned char b_Command = (unsigned char) CR_AREF(insn->chanspec); + int i_ReturnValue = insn->n; + unsigned char b_Cpt = 0; + unsigned char b_NumberOfPort = 0; unsigned int *pls_ReadData = data; /********************/ @@ -450,7 +450,7 @@ int i_APCI16XX_InsnReadTTLIOAllPortValue(struct comedi_device * dev, /**********************************/ b_NumberOfPort = - (BYTE) (devpriv->ps_BoardInfo->i_NbrTTLChannel / 32); + (unsigned char) (devpriv->ps_BoardInfo->i_NbrTTLChannel / 32); if ((b_NumberOfPort * 32) < devpriv->ps_BoardInfo->i_NbrTTLChannel) { b_NumberOfPort = b_NumberOfPort + 1; @@ -524,7 +524,7 @@ int i_APCI16XX_InsnReadTTLIOAllPortValue(struct comedi_device * dev, i_ReturnValue = -100; } - return (i_ReturnValue); + return i_ReturnValue; } /* @@ -535,7 +535,7 @@ int i_APCI16XX_InsnReadTTLIOAllPortValue(struct comedi_device * dev, /* +----------------------------------------------------------------------------+ -| Function Name : INT i_APCI16XX_InsnBitsWriteTTLIO | +| Function Name : int i_APCI16XX_InsnBitsWriteTTLIO | | (struct comedi_device *dev, | | struct comedi_subdevice *s, | | struct comedi_insn *insn, | @@ -551,11 +551,11 @@ int i_APCI16XX_InsnReadTTLIOAllPortValue(struct comedi_device * dev, | APCI16XX_TTL_WRITECHANNEL_ON | APCI16XX_TTL_WRITECHANNEL_OFF | | b_SelectedPort = CR_RANGE(insn->chanspec); | | b_OutputChannel= CR_CHAN(insn->chanspec); | -| b_Command = (BYTE) data[0]; | +| b_Command = (unsigned char) data[0]; | | | | APCI16XX_TTL_WRITEPORT_ON | APCI16XX_TTL_WRITEPORT_OFF | | b_SelectedPort = CR_RANGE(insn->chanspec); | -| b_Command = (BYTE) data[0]; | +| b_Command = (unsigned char) data[0]; | +----------------------------------------------------------------------------+ | Output Parameters : data[0] : TTL output port 0 to 3 data | | data[1] : TTL output port 4 to 7 data | @@ -570,16 +570,16 @@ int i_APCI16XX_InsnReadTTLIOAllPortValue(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -int i_APCI16XX_InsnBitsWriteTTLIO(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +int i_APCI16XX_InsnBitsWriteTTLIO(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - INT i_ReturnValue = insn->n; - BYTE b_Command = 0; - BYTE b_NumberOfPort = - (BYTE) (devpriv->ps_BoardInfo->i_NbrTTLChannel / 8); - BYTE b_SelectedPort = CR_RANGE(insn->chanspec); - BYTE b_OutputChannel = CR_CHAN(insn->chanspec); - DWORD dw_Status = 0; + int i_ReturnValue = insn->n; + unsigned char b_Command = 0; + unsigned char b_NumberOfPort = + (unsigned char) (devpriv->ps_BoardInfo->i_NbrTTLChannel / 8); + unsigned char b_SelectedPort = CR_RANGE(insn->chanspec); + unsigned char b_OutputChannel = CR_CHAN(insn->chanspec); + unsigned int dw_Status = 0; /************************/ /* Test the buffer size */ @@ -590,7 +590,7 @@ int i_APCI16XX_InsnBitsWriteTTLIO(struct comedi_device * dev, /* Get the command */ /* **************** */ - b_Command = (BYTE) data[0]; + b_Command = (unsigned char) data[0]; /********************/ /* Test the command */ @@ -758,7 +758,7 @@ int i_APCI16XX_InsnBitsWriteTTLIO(struct comedi_device * dev, devpriv->iobase + 20 + ((b_SelectedPort / 4) * 4)); } - return (i_ReturnValue); + return i_ReturnValue; } /* @@ -774,7 +774,7 @@ int i_APCI16XX_InsnBitsWriteTTLIO(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -int i_APCI16XX_Reset(struct comedi_device * dev) +int i_APCI16XX_Reset(struct comedi_device *dev) { return 0; } diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2016.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2016.c index 31f55da39ea8..457917f292b7 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2016.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2016.c @@ -3,13 +3,13 @@ Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data-com - info@addi-data.com + ADDI-DATA GmbH + Dieselstrasse 3 + D-77833 Ottersweier + Tel: +19(0)7223/9493-0 + Fax: +49(0)7223/9493-92 + http://www.addi-data-com + info@addi-data.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. @@ -62,7 +62,7 @@ You shoud also find the complete GPL in the COPYING file accompanying this sourc | Task : Configures The Digital Output Subdevice. | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | -| UINT *data : Data Pointer contains | +| unsigned int *data : Data Pointer contains | | configuration parameters as below | | | | data[0] : 1 Digital Memory On | @@ -75,20 +75,20 @@ You shoud also find the complete GPL in the COPYING file accompanying this sourc | | +----------------------------------------------------------------------------+ */ -int i_APCI2016_ConfigDigitalOutput(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI2016_ConfigDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if ((data[0] != 0) && (data[0] != 1)) { comedi_error(dev, "Not a valid Data !!! ,Data should be 1 or 0\n"); return -EINVAL; - } // if ((data[0]!=0) && (data[0]!=1)) + } /* if ((data[0]!=0) && (data[0]!=1)) */ if (data[0]) { devpriv->b_OutputMemoryStatus = ADDIDATA_ENABLE; - } // if (data[0] + } /* if (data[0] */ else { devpriv->b_OutputMemoryStatus = ADDIDATA_DISABLE; - } // else if (data[0] + } /* else if (data[0] */ return insn->n; } @@ -101,8 +101,8 @@ int i_APCI2016_ConfigDigitalOutput(struct comedi_device * dev, struct comedi_sub | Task : Writes port value To the selected port | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | -| UINT ui_NoOfChannels : No Of Channels To Write | -| UINT *data : Data Pointer to read status | +| unsigned int ui_NoOfChannels : No Of Channels To Write | +| unsigned int *data : Data Pointer to read status | +----------------------------------------------------------------------------+ | Output Parameters : -- | +----------------------------------------------------------------------------+ @@ -111,34 +111,34 @@ int i_APCI2016_ConfigDigitalOutput(struct comedi_device * dev, struct comedi_sub | | +----------------------------------------------------------------------------+ */ -int i_APCI2016_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI2016_WriteDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - UINT ui_NoOfChannel; - UINT ui_Temp, ui_Temp1; + unsigned int ui_NoOfChannel; + unsigned int ui_Temp, ui_Temp1; ui_NoOfChannel = CR_CHAN(insn->chanspec); if ((ui_NoOfChannel < 0) || (ui_NoOfChannel > 15)) { comedi_error(dev, "Invalid Channel Numbers !!!, Channel Numbers must be between 0 and 15\n"); return -EINVAL; - } // if ((ui_NoOfChannel<0) || (ui_NoOfChannel>15)) + } /* if ((ui_NoOfChannel<0) || (ui_NoOfChannel>15)) */ if (devpriv->b_OutputMemoryStatus) { ui_Temp = inw(devpriv->iobase + APCI2016_DIGITAL_OP); - } // if (devpriv->b_OutputMemoryStatus ) + } /* if (devpriv->b_OutputMemoryStatus ) */ else { ui_Temp = 0; - } // else if (devpriv->b_OutputMemoryStatus ) + } /* else if (devpriv->b_OutputMemoryStatus ) */ if ((data[1] != 0) && (data[1] != 1)) { comedi_error(dev, "Invalid Data[1] value !!!, Data[1] should be 0 or 1\n"); return -EINVAL; - } // if ((data[1]!=0) && (data[1]!=1)) + } /* if ((data[1]!=0) && (data[1]!=1)) */ if (data[3] == 0) { if (data[1] == 0) { data[0] = (data[0] << ui_NoOfChannel) | ui_Temp; outw(data[0], devpriv->iobase + APCI2016_DIGITAL_OP); - } // if (data[1]==0) + } /* if (data[1]==0) */ else { if (data[1] == 1) { switch (ui_NoOfChannel) { @@ -162,16 +162,16 @@ int i_APCI2016_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subd break; default: comedi_error(dev, " chan spec wrong"); - return -EINVAL; // "sorry channel spec wrong " - } //switch(ui_NoOfChannels) + return -EINVAL; /* "sorry channel spec wrong " */ + } /* switch(ui_NoOfChannels) */ outw(data[0], devpriv->iobase + APCI2016_DIGITAL_OP); - } // if (data[1]==1) + } /* if (data[1]==1) */ else { printk("\nSpecified channel not supported\n"); - } // else if (data[1]==1) - } // else if (data[1]==0) - } // if (data[3]==0) + } /* else if (data[1]==1) */ + } /* else if (data[1]==0) */ + } /* if (data[3]==0) */ else { if (data[3] == 1) { if (data[1] == 0) { @@ -183,7 +183,7 @@ int i_APCI2016_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subd data[0] = data[0] & ui_Temp; outw(data[0], devpriv->iobase + APCI2016_DIGITAL_OP); - } // if (data[1]==0) + } /* if (data[1]==0) */ else { if (data[1] == 1) { switch (ui_NoOfChannel) { @@ -228,22 +228,22 @@ int i_APCI2016_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subd default: comedi_error(dev, " chan spec wrong"); - return -EINVAL; // "sorry channel spec wrong " - } //switch(ui_NoOfChannels) + return -EINVAL; /* "sorry channel spec wrong " */ + } /* switch(ui_NoOfChannels) */ outw(data[0], devpriv->iobase + APCI2016_DIGITAL_OP); - } // if(data[1]==1) + } /* if(data[1]==1) */ else { printk("\nSpecified channel not supported\n"); - } //else if(data[1]==1) - } //elseif(data[1]==0) - } //if(data[3]==1); + } /* else if(data[1]==1) */ + } /* elseif(data[1]==0) */ + } /* if(data[3]==1); */ else { printk("\nSpecified functionality does not exist\n"); return -EINVAL; - } //if else data[3]==1) - } //if else data[3]==0) + } /* if else data[3]==1) */ + } /* if else data[3]==0) */ return insn->n; } @@ -256,8 +256,8 @@ int i_APCI2016_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subd | Task : Read value of the selected channel or port | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | -| UINT ui_NoOfChannels : No Of Channels To read | -| UINT *data : Data Pointer to read status | +| unsigned int ui_NoOfChannels : No Of Channels To read | +| unsigned int *data : Data Pointer to read status | +----------------------------------------------------------------------------+ | Output Parameters : -- | +----------------------------------------------------------------------------+ @@ -266,27 +266,27 @@ int i_APCI2016_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subd | | +----------------------------------------------------------------------------+ */ -int i_APCI2016_BitsDigitalOutput(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI2016_BitsDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - UINT ui_Temp; - UINT ui_NoOfChannel; + unsigned int ui_Temp; + unsigned int ui_NoOfChannel; ui_NoOfChannel = CR_CHAN(insn->chanspec); if ((ui_NoOfChannel < 0) || (ui_NoOfChannel > 15)) { comedi_error(dev, "Invalid Channel Numbers !!!, Channel Numbers must be between 0 and 15\n"); return -EINVAL; - } // if ((ui_NoOfChannel<0) || (ui_NoOfChannel>15)) + } /* if ((ui_NoOfChannel<0) || (ui_NoOfChannel>15)) */ if ((data[0] != 0) && (data[0] != 1)) { comedi_error(dev, "Invalid Data[0] value !!!, Data[0] should be 0 or 1\n"); return -EINVAL; - } // if ((data[0]!=0) && (data[0]!=1)) + } /* if ((data[0]!=0) && (data[0]!=1)) */ ui_Temp = data[0]; *data = inw(devpriv->iobase + APCI2016_DIGITAL_OP_RW); if (ui_Temp == 0) { *data = (*data >> ui_NoOfChannel) & 0x1; - } // if (ui_Temp==0) + } /* if (ui_Temp==0) */ else { if (ui_Temp == 1) { switch (ui_NoOfChannel) { @@ -307,13 +307,13 @@ int i_APCI2016_BitsDigitalOutput(struct comedi_device * dev, struct comedi_subde default: comedi_error(dev, " chan spec wrong"); - return -EINVAL; // "sorry channel spec wrong " - } //switch(ui_NoOfChannel) - } // if (ui_Temp==1) + return -EINVAL; /* "sorry channel spec wrong " */ + } /* switch(ui_NoOfChannel) */ + } /* if (ui_Temp==1) */ else { printk("\nSpecified channel not supported \n"); - } // else if (ui_Temp==1) - } // if (ui_Temp==0) + } /* else if (ui_Temp==1) */ + } /* if (ui_Temp==0) */ return insn->n; } @@ -337,16 +337,16 @@ int i_APCI2016_BitsDigitalOutput(struct comedi_device * dev, struct comedi_subde | | +----------------------------------------------------------------------------+ */ -int i_APCI2016_ConfigWatchdog(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI2016_ConfigWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if (data[0] == 0) { - //Disable the watchdog + /* Disable the watchdog */ outw(0x0, devpriv->i_IobaseAddon + APCI2016_WATCHDOG_ENABLEDISABLE); - //Loading the Reload value + /* Loading the Reload value */ outw(data[1], devpriv->i_IobaseAddon + APCI2016_WATCHDOG_RELOAD_VALUE); @@ -380,20 +380,20 @@ int i_APCI2016_ConfigWatchdog(struct comedi_device * dev, struct comedi_subdevic | | +----------------------------------------------------------------------------+ */ -int i_APCI2016_StartStopWriteWatchdog(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI2016_StartStopWriteWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { switch (data[0]) { - case 0: //stop the watchdog - outw(0x0, devpriv->i_IobaseAddon + APCI2016_WATCHDOG_ENABLEDISABLE); //disable the watchdog + case 0: /* stop the watchdog */ + outw(0x0, devpriv->i_IobaseAddon + APCI2016_WATCHDOG_ENABLEDISABLE); /* disable the watchdog */ break; - case 1: //start the watchdog + case 1: /* start the watchdog */ outw(0x0001, devpriv->i_IobaseAddon + APCI2016_WATCHDOG_ENABLEDISABLE); break; - case 2: //Software trigger + case 2: /* Software trigger */ outw(0x0201, devpriv->i_IobaseAddon + APCI2016_WATCHDOG_ENABLEDISABLE); @@ -401,7 +401,7 @@ int i_APCI2016_StartStopWriteWatchdog(struct comedi_device * dev, struct comedi_ default: printk("\nSpecified functionality does not exist\n"); return -EINVAL; - } // switch(data[0]) + } /* switch(data[0]) */ return insn->n; } @@ -427,8 +427,8 @@ int i_APCI2016_StartStopWriteWatchdog(struct comedi_device * dev, struct comedi_ +----------------------------------------------------------------------------+ */ -int i_APCI2016_ReadWatchdog(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI2016_ReadWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { udelay(5); data[0] = inw(devpriv->i_IobaseAddon + APCI2016_WATCHDOG_STATUS) & 0x1; @@ -450,9 +450,9 @@ int i_APCI2016_ReadWatchdog(struct comedi_device * dev, struct comedi_subdevice +----------------------------------------------------------------------------+ */ -INT i_APCI2016_Reset(struct comedi_device * dev) +int i_APCI2016_Reset(struct comedi_device *dev) { - outw(0x0, devpriv->iobase + APCI2016_DIGITAL_OP); // Resets the digital output channels + outw(0x0, devpriv->iobase + APCI2016_DIGITAL_OP); /* Resets the digital output channels */ outw(0x0, devpriv->i_IobaseAddon + APCI2016_WATCHDOG_ENABLEDISABLE); outw(0x0, devpriv->i_IobaseAddon + APCI2016_WATCHDOG_RELOAD_VALUE); outw(0x0, devpriv->i_IobaseAddon + APCI2016_WATCHDOG_RELOAD_VALUE + 2); diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2016.h b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2016.h index 9261aacd25f1..639944c44469 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2016.h +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2016.h @@ -19,17 +19,17 @@ #define APCI2016_BOARD_VENDOR_ID 0x15B8 #define APCI2016_ADDRESS_RANGE 8 -//DIGITAL INPUT-OUTPUT DEFINE +/* DIGITAL INPUT-OUTPUT DEFINE */ #define APCI2016_DIGITAL_OP 0x04 #define APCI2016_DIGITAL_OP_RW 4 -//ADDIDATA Enable Disable +/* ADDIDATA Enable Disable */ #define ADDIDATA_ENABLE 1 #define ADDIDATA_DISABLE 0 -// TIMER COUNTER WATCHDOG DEFINES +/* TIMER COUNTER WATCHDOG DEFINES */ #define ADDIDATA_WATCHDOG 2 #define APCI2016_DIGITAL_OP_WATCHDOG 0 @@ -37,9 +37,9 @@ #define APCI2016_WATCHDOG_RELOAD_VALUE 4 #define APCI2016_WATCHDOG_STATUS 16 -// Hardware Layer functions for Apci2016 +/* Hardware Layer functions for Apci2016 */ -//DO +/* DO */ int i_APCI2016_ConfigDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); @@ -49,8 +49,10 @@ int i_APCI2016_WriteDigitalOutput(struct comedi_device *dev, struct comedi_subde int i_APCI2016_BitsDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -// TIMER -// timer value is passed as u seconds +/* +* TIMER +* timer value is passed as u seconds +*/ int i_APCI2016_ConfigWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); @@ -61,10 +63,10 @@ int i_APCI2016_StartStopWriteWatchdog(struct comedi_device *dev, struct comedi_s int i_APCI2016_ReadWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -// Interrupt functions..... +/* Interrupt functions..... */ -// void v_APCI2016_Interrupt(int irq, void *d) ; +/* void v_APCI2016_Interrupt(int irq, void *d); */ - //void v_APCI2016_Interrupt(int irq, void *d); -// RESET -INT i_APCI2016_Reset(struct comedi_device *dev); +/* void v_APCI2016_Interrupt(int irq, void *d); */ +/* RESET */ +int i_APCI2016_Reset(struct comedi_device *dev); diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2032.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2032.c index 1347bc388f3e..ec817082d170 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2032.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2032.c @@ -3,13 +3,13 @@ Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data-com - info@addi-data.com + ADDI-DATA GmbH + Dieselstrasse 3 + D-77833 Ottersweier + Tel: +19(0)7223/9493-0 + Fax: +49(0)7223/9493-92 + http://www.addi-data-com + info@addi-data.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. @@ -53,7 +53,7 @@ You shoud also find the complete GPL in the COPYING file accompanying this sourc */ #include "hwdrv_apci2032.h" -UINT ui_InterruptData, ui_Type; +unsigned int ui_InterruptData, ui_Type; /* +----------------------------------------------------------------------------+ | Function Name : int i_APCI2032_ConfigDigitalOutput | @@ -63,7 +63,7 @@ UINT ui_InterruptData, ui_Type; | Task : Configures The Digital Output Subdevice. | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | -| UINT *data : Data Pointer contains | +| unsigned int *data : Data Pointer contains | | configuration parameters as below | | | | data[1] : 1 Enable VCC Interrupt | @@ -79,36 +79,36 @@ UINT ui_InterruptData, ui_Type; | | +----------------------------------------------------------------------------+ */ -int i_APCI2032_ConfigDigitalOutput(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI2032_ConfigDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - ULONG ul_Command = 0; + unsigned int ul_Command = 0; devpriv->tsk_Current = current; if ((data[0] != 0) && (data[0] != 1)) { comedi_error(dev, "Not a valid Data !!! ,Data should be 1 or 0\n"); return -EINVAL; - } //if ( (data[0]!=0) && (data[0]!=1) ) + } /* if ( (data[0]!=0) && (data[0]!=1) ) */ if (data[0]) { devpriv->b_OutputMemoryStatus = ADDIDATA_ENABLE; - } // if (data[0]) + } /* if (data[0]) */ else { devpriv->b_OutputMemoryStatus = ADDIDATA_DISABLE; - } //else if (data[0]) + } /* else if (data[0]) */ if (data[1] == ADDIDATA_ENABLE) { ul_Command = ul_Command | 0x1; - } //if (data[1] == ADDIDATA_ENABLE) + } /* if (data[1] == ADDIDATA_ENABLE) */ else { ul_Command = ul_Command & 0xFFFFFFFE; - } //elseif (data[1] == ADDIDATA_ENABLE) + } /* elseif (data[1] == ADDIDATA_ENABLE) */ if (data[2] == ADDIDATA_ENABLE) { ul_Command = ul_Command | 0x2; - } //if (data[2] == ADDIDATA_ENABLE) + } /* if (data[2] == ADDIDATA_ENABLE) */ else { ul_Command = ul_Command & 0xFFFFFFFD; - } //elseif (data[2] == ADDIDATA_ENABLE) + } /* elseif (data[2] == ADDIDATA_ENABLE) */ outl(ul_Command, devpriv->iobase + APCI2032_DIGITAL_OP_INTERRUPT); ui_InterruptData = inl(devpriv->iobase + APCI2032_DIGITAL_OP_INTERRUPT); return insn->n; @@ -123,8 +123,8 @@ int i_APCI2032_ConfigDigitalOutput(struct comedi_device * dev, struct comedi_sub | Task : Writes port value To the selected port | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | -| UINT ui_NoOfChannels : No Of Channels To Write | -| UINT *data : Data Pointer to read status | +| unsigned int ui_NoOfChannels : No Of Channels To Write | +| unsigned int *data : Data Pointer to read status | +----------------------------------------------------------------------------+ | Output Parameters : -- | +----------------------------------------------------------------------------+ @@ -134,23 +134,23 @@ int i_APCI2032_ConfigDigitalOutput(struct comedi_device * dev, struct comedi_sub +----------------------------------------------------------------------------+ */ -INT i_APCI2032_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI2032_WriteDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - UINT ui_Temp, ui_Temp1; - UINT ui_NoOfChannel = CR_CHAN(insn->chanspec); // get the channel + unsigned int ui_Temp, ui_Temp1; + unsigned int ui_NoOfChannel = CR_CHAN(insn->chanspec); /* get the channel */ if (devpriv->b_OutputMemoryStatus) { ui_Temp = inl(devpriv->iobase + APCI2032_DIGITAL_OP); - } //if(devpriv->b_OutputMemoryStatus ) + } /* if(devpriv->b_OutputMemoryStatus ) */ else { ui_Temp = 0; - } //if(devpriv->b_OutputMemoryStatus ) + } /* if(devpriv->b_OutputMemoryStatus ) */ if (data[3] == 0) { if (data[1] == 0) { data[0] = (data[0] << ui_NoOfChannel) | ui_Temp; outl(data[0], devpriv->iobase + APCI2032_DIGITAL_OP); - } //if(data[1]==0) + } /* if(data[1]==0) */ else { if (data[1] == 1) { switch (ui_NoOfChannel) { @@ -184,18 +184,18 @@ INT i_APCI2032_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subd default: comedi_error(dev, " chan spec wrong"); - return -EINVAL; // "sorry channel spec wrong " + return -EINVAL; /* "sorry channel spec wrong " */ - } //switch(ui_NoOfChannels) + } /* switch(ui_NoOfChannels) */ outl(data[0], devpriv->iobase + APCI2032_DIGITAL_OP); - } // if(data[1]==1) + } /* if(data[1]==1) */ else { printk("\nSpecified channel not supported\n"); - } //else if(data[1]==1) - } //elseif(data[1]==0) - } //if(data[3]==0) + } /* else if(data[1]==1) */ + } /* elseif(data[1]==0) */ + } /* if(data[3]==0) */ else { if (data[3] == 1) { if (data[1] == 0) { @@ -209,7 +209,7 @@ INT i_APCI2032_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subd data[0] = data[0] & ui_Temp; outl(data[0], devpriv->iobase + APCI2032_DIGITAL_OP); - } //if(data[1]==0) + } /* if(data[1]==0) */ else { if (data[1] == 1) { switch (ui_NoOfChannel) { @@ -272,25 +272,25 @@ INT i_APCI2032_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subd default: comedi_error(dev, " chan spec wrong"); - return -EINVAL; // "sorry channel spec wrong " + return -EINVAL; /* "sorry channel spec wrong " */ - } //switch(ui_NoOfChannels) + } /* switch(ui_NoOfChannels) */ outl(data[0], devpriv->iobase + APCI2032_DIGITAL_OP); - } // if(data[1]==1) + } /* if(data[1]==1) */ else { printk("\nSpecified channel not supported\n"); - } //else if(data[1]==1) - } //elseif(data[1]==0) - } //if(data[3]==1); + } /* else if(data[1]==1) */ + } /* elseif(data[1]==0) */ + } /* if(data[3]==1); */ else { printk("\nSpecified functionality does not exist\n"); return -EINVAL; - } //if else data[3]==1) - } //if else data[3]==0) - return (insn->n);; + } /* if else data[3]==1) */ + } /* if else data[3]==0) */ + return insn->n; } /* @@ -302,8 +302,8 @@ INT i_APCI2032_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subd | Task : Read value of the selected channel or port | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | -| UINT ui_NoOfChannels : No Of Channels To read | -| UINT *data : Data Pointer to read status | +| unsigned int ui_NoOfChannels : No Of Channels To read | +| unsigned int *data : Data Pointer to read status | +----------------------------------------------------------------------------+ | Output Parameters : -- | +----------------------------------------------------------------------------+ @@ -313,17 +313,17 @@ INT i_APCI2032_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subd +----------------------------------------------------------------------------+ */ -INT i_APCI2032_ReadDigitalOutput(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI2032_ReadDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - UINT ui_Temp; - UINT ui_NoOfChannel; + unsigned int ui_Temp; + unsigned int ui_NoOfChannel; ui_NoOfChannel = CR_CHAN(insn->chanspec); ui_Temp = data[0]; *data = inl(devpriv->iobase + APCI2032_DIGITAL_OP_RW); if (ui_Temp == 0) { *data = (*data >> ui_NoOfChannel) & 0x1; - } //if (ui_Temp==0) + } /* if (ui_Temp==0) */ else { if (ui_Temp == 1) { switch (ui_NoOfChannel) { @@ -349,28 +349,28 @@ INT i_APCI2032_ReadDigitalOutput(struct comedi_device * dev, struct comedi_subde default: comedi_error(dev, " chan spec wrong"); - return -EINVAL; // "sorry channel spec wrong " + return -EINVAL; /* "sorry channel spec wrong " */ - } //switch(ui_NoOfChannels) - } //if (ui_Temp==1) + } /* switch(ui_NoOfChannels) */ + } /* if (ui_Temp==1) */ else { printk("\nSpecified channel not supported \n"); - } //elseif (ui_Temp==1) + } /* elseif (ui_Temp==1) */ } return insn->n; } /* +----------------------------------------------------------------------------+ -| Function Name : INT i_APCI2032_ConfigWatchdog(comedi_device - *dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data)| +| Function Name : int i_APCI2032_ConfigWatchdog(comedi_device +| *dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data)| | | +----------------------------------------------------------------------------+ | Task : Configures The Watchdog | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | | struct comedi_subdevice *s, :pointer to subdevice structure - struct comedi_insn *insn :pointer to insn structure | +| struct comedi_insn *insn :pointer to insn structure | | unsigned int *data : Data Pointer to read status | +----------------------------------------------------------------------------+ | Output Parameters : -- | @@ -380,15 +380,15 @@ INT i_APCI2032_ReadDigitalOutput(struct comedi_device * dev, struct comedi_subde | | +----------------------------------------------------------------------------+ */ -INT i_APCI2032_ConfigWatchdog(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI2032_ConfigWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if (data[0] == 0) { - //Disable the watchdog + /* Disable the watchdog */ outl(0x0, devpriv->iobase + APCI2032_DIGITAL_OP_WATCHDOG + APCI2032_TCW_PROG); - //Loading the Reload value + /* Loading the Reload value */ outl(data[1], devpriv->iobase + APCI2032_DIGITAL_OP_WATCHDOG + APCI2032_TCW_RELOAD_VALUE); @@ -421,19 +421,19 @@ INT i_APCI2032_ConfigWatchdog(struct comedi_device * dev, struct comedi_subdevic +----------------------------------------------------------------------------+ */ -int i_APCI2032_StartStopWriteWatchdog(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI2032_StartStopWriteWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { switch (data[0]) { - case 0: //stop the watchdog - outl(0x0, devpriv->iobase + APCI2032_DIGITAL_OP_WATCHDOG + APCI2032_TCW_PROG); //disable the watchdog + case 0: /* stop the watchdog */ + outl(0x0, devpriv->iobase + APCI2032_DIGITAL_OP_WATCHDOG + APCI2032_TCW_PROG); /* disable the watchdog */ break; - case 1: //start the watchdog + case 1: /* start the watchdog */ outl(0x0001, devpriv->iobase + APCI2032_DIGITAL_OP_WATCHDOG + APCI2032_TCW_PROG); break; - case 2: //Software trigger + case 2: /* Software trigger */ outl(0x0201, devpriv->iobase + APCI2032_DIGITAL_OP_WATCHDOG + APCI2032_TCW_PROG); @@ -449,13 +449,13 @@ int i_APCI2032_StartStopWriteWatchdog(struct comedi_device * dev, struct comedi_ +----------------------------------------------------------------------------+ | Function Name : int i_APCI2032_ReadWatchdog | | (struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn, - unsigned int *data); | +| unsigned int *data); | +----------------------------------------------------------------------------+ | Task : Read The Watchdog | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | | struct comedi_subdevice *s, :pointer to subdevice structure - struct comedi_insn *insn :pointer to insn structure | +| struct comedi_insn *insn :pointer to insn structure | | unsigned int *data : Data Pointer to read status | +----------------------------------------------------------------------------+ | Output Parameters : -- | @@ -466,8 +466,8 @@ int i_APCI2032_StartStopWriteWatchdog(struct comedi_device * dev, struct comedi_ +----------------------------------------------------------------------------+ */ -int i_APCI2032_ReadWatchdog(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI2032_ReadWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { data[0] = @@ -498,13 +498,13 @@ void v_APCI2032_Interrupt(int irq, void *d) struct comedi_device *dev = d; unsigned int ui_DO; - ui_DO = inl(devpriv->iobase + APCI2032_DIGITAL_OP_IRQ) & 0x1; //Check if VCC OR CC interrupt has occured. + ui_DO = inl(devpriv->iobase + APCI2032_DIGITAL_OP_IRQ) & 0x1; /* Check if VCC OR CC interrupt has occured. */ if (ui_DO == 0) { printk("\nInterrupt from unKnown source\n"); - } // if(ui_DO==0) + } /* if(ui_DO==0) */ if (ui_DO) { - // Check for Digital Output interrupt Type - 1: Vcc interrupt 2: CC interrupt. + /* Check for Digital Output interrupt Type - 1: Vcc interrupt 2: CC interrupt. */ ui_Type = inl(devpriv->iobase + APCI2032_DIGITAL_OP_INTERRUPT_STATUS) & 0x3; @@ -512,16 +512,16 @@ void v_APCI2032_Interrupt(int irq, void *d) devpriv->iobase + APCI2032_DIGITAL_OP + APCI2032_DIGITAL_OP_INTERRUPT); if (ui_Type == 1) { - //Sends signal to user space + /* Sends signal to user space */ send_sig(SIGIO, devpriv->tsk_Current, 0); - } // if (ui_Type==1) + } /* if (ui_Type==1) */ else { if (ui_Type == 2) { - // Sends signal to user space + /* Sends signal to user space */ send_sig(SIGIO, devpriv->tsk_Current, 0); - } //if (ui_Type==2) - } //else if (ui_Type==1) - } //if(ui_DO) + } /* if (ui_Type==2) */ + } /* else if (ui_Type==1) */ + } /* if(ui_DO) */ return; @@ -544,8 +544,8 @@ void v_APCI2032_Interrupt(int irq, void *d) +----------------------------------------------------------------------------+ */ -int i_APCI2032_ReadInterruptStatus(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI2032_ReadInterruptStatus(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { *data = ui_Type; return insn->n; @@ -567,13 +567,13 @@ int i_APCI2032_ReadInterruptStatus(struct comedi_device * dev, struct comedi_sub +----------------------------------------------------------------------------+ */ -int i_APCI2032_Reset(struct comedi_device * dev) +int i_APCI2032_Reset(struct comedi_device *dev) { devpriv->b_DigitalOutputRegister = 0; ui_Type = 0; - outl(0x0, devpriv->iobase + APCI2032_DIGITAL_OP); //Resets the output channels - outl(0x0, devpriv->iobase + APCI2032_DIGITAL_OP_INTERRUPT); //Disables the interrupt. - outl(0x0, devpriv->iobase + APCI2032_DIGITAL_OP_WATCHDOG + APCI2032_TCW_PROG); //disable the watchdog - outl(0x0, devpriv->iobase + APCI2032_DIGITAL_OP_WATCHDOG + APCI2032_TCW_RELOAD_VALUE); //reload=0 + outl(0x0, devpriv->iobase + APCI2032_DIGITAL_OP); /* Resets the output channels */ + outl(0x0, devpriv->iobase + APCI2032_DIGITAL_OP_INTERRUPT); /* Disables the interrupt. */ + outl(0x0, devpriv->iobase + APCI2032_DIGITAL_OP_WATCHDOG + APCI2032_TCW_PROG); /* disable the watchdog */ + outl(0x0, devpriv->iobase + APCI2032_DIGITAL_OP_WATCHDOG + APCI2032_TCW_RELOAD_VALUE); /* reload=0 */ return 0; } diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2032.h b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2032.h index 55002e0288b5..c971d143c249 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2032.h +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2032.h @@ -17,32 +17,32 @@ /********* Definitions for APCI-2032 card *****/ -// Card Specific information +/* Card Specific information */ #define APCI2032_BOARD_VENDOR_ID 0x15B8 #define APCI2032_ADDRESS_RANGE 63 -//DIGITAL INPUT-OUTPUT DEFINE +/* DIGITAL INPUT-OUTPUT DEFINE */ #define APCI2032_DIGITAL_OP 0 #define APCI2032_DIGITAL_OP_RW 0 #define APCI2032_DIGITAL_OP_INTERRUPT 4 #define APCI2032_DIGITAL_OP_IRQ 12 -//Digital Output Interrupt Status +/* Digital Output Interrupt Status */ #define APCI2032_DIGITAL_OP_INTERRUPT_STATUS 8 -//Digital Output Interrupt Enable Disable. +/* Digital Output Interrupt Enable Disable. */ #define APCI2032_DIGITAL_OP_VCC_INTERRUPT_ENABLE 0x1 #define APCI2032_DIGITAL_OP_VCC_INTERRUPT_DISABLE 0xFFFFFFFE #define APCI2032_DIGITAL_OP_CC_INTERRUPT_ENABLE 0x2 #define APCI2032_DIGITAL_OP_CC_INTERRUPT_DISABLE 0xFFFFFFFD -//ADDIDATA Enable Disable +/* ADDIDATA Enable Disable */ #define ADDIDATA_ENABLE 1 #define ADDIDATA_DISABLE 0 -// TIMER COUNTER WATCHDOG DEFINES +/* TIMER COUNTER WATCHDOG DEFINES */ #define ADDIDATA_WATCHDOG 2 #define APCI2032_DIGITAL_OP_WATCHDOG 16 @@ -52,30 +52,32 @@ #define APCI2032_TCW_TRIG_STATUS 16 #define APCI2032_TCW_IRQ 20 -// Hardware Layer functions for Apci2032 +/* Hardware Layer functions for Apci2032 */ -//DO +/* DO */ int i_APCI2032_ConfigDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -INT i_APCI2032_WriteDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, +int i_APCI2032_WriteDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -INT i_APCI2032_ReadDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, +int i_APCI2032_ReadDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); int i_APCI2032_ReadInterruptStatus(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -// TIMER -// timer value is passed as u seconds -INT i_APCI2032_ConfigWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, +/* TIMER + * timer value is passed as u seconds +*/ + +int i_APCI2032_ConfigWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); int i_APCI2032_StartStopWriteWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); int i_APCI2032_ReadWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -// Interrupt functions..... +/* Interrupt functions..... */ void v_APCI2032_Interrupt(int irq, void *d); -//Reset functions +/* Reset functions */ int i_APCI2032_Reset(struct comedi_device *dev); diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2200.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2200.c index 947e18ef3ab3..a853c62a4fd9 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2200.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2200.c @@ -3,13 +3,13 @@ Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data-com - info@addi-data.com + ADDI-DATA GmbH + Dieselstrasse 3 + D-77833 Ottersweier + Tel: +19(0)7223/9493-0 + Fax: +49(0)7223/9493-92 + http://www.addi-data-com + info@addi-data.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. @@ -63,7 +63,7 @@ You shoud also find the complete GPL in the COPYING file accompanying this sourc +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | | struct comedi_subdevice *s, :pointer to subdevice structure - struct comedi_insn *insn :pointer to insn structure | +| struct comedi_insn *insn :pointer to insn structure | | unsigned int *data : Data Pointer to read status | +----------------------------------------------------------------------------+ | Output Parameters : -- | @@ -73,20 +73,20 @@ You shoud also find the complete GPL in the COPYING file accompanying this sourc | | +----------------------------------------------------------------------------+ */ -INT i_APCI2200_Read1DigitalInput(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI2200_Read1DigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - UINT ui_TmpValue = 0; - UINT ui_Channel; + unsigned int ui_TmpValue = 0; + unsigned int ui_Channel; ui_Channel = CR_CHAN(insn->chanspec); if (ui_Channel >= 0 && ui_Channel <= 7) { - ui_TmpValue = (UINT) inw(devpriv->iobase + APCI2200_DIGITAL_IP); + ui_TmpValue = (unsigned int) inw(devpriv->iobase + APCI2200_DIGITAL_IP); *data = (ui_TmpValue >> ui_Channel) & 0x1; - } //if(ui_Channel >= 0 && ui_Channel <=7) + } /* if(ui_Channel >= 0 && ui_Channel <=7) */ else { printk("\nThe specified channel does not exist\n"); - return -EINVAL; // "sorry channel spec wrong " - } //else if(ui_Channel >= 0 && ui_Channel <=7) + return -EINVAL; /* "sorry channel spec wrong " */ + } /* else if(ui_Channel >= 0 && ui_Channel <=7) */ return insn->n; } @@ -101,7 +101,7 @@ INT i_APCI2200_Read1DigitalInput(struct comedi_device * dev, struct comedi_subde +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | | struct comedi_subdevice *s, :pointer to subdevice structure - struct comedi_insn *insn :pointer to insn structure | +| struct comedi_insn *insn :pointer to insn structure | | unsigned int *data : Data Pointer to read status | +----------------------------------------------------------------------------+ | Output Parameters : -- | @@ -112,17 +112,17 @@ INT i_APCI2200_Read1DigitalInput(struct comedi_device * dev, struct comedi_subde +----------------------------------------------------------------------------+ */ -INT i_APCI2200_ReadMoreDigitalInput(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI2200_ReadMoreDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - UINT ui_PortValue = data[0]; - UINT ui_Mask = 0; - UINT ui_NoOfChannels; + unsigned int ui_PortValue = data[0]; + unsigned int ui_Mask = 0; + unsigned int ui_NoOfChannels; ui_NoOfChannels = CR_CHAN(insn->chanspec); - *data = (UINT) inw(devpriv->iobase + APCI2200_DIGITAL_IP); + *data = (unsigned int) inw(devpriv->iobase + APCI2200_DIGITAL_IP); switch (ui_NoOfChannels) { case 2: ui_Mask = 3; @@ -137,9 +137,9 @@ INT i_APCI2200_ReadMoreDigitalInput(struct comedi_device * dev, struct comedi_su default: printk("\nWrong parameters\n"); - return -EINVAL; // "sorry channel spec wrong " + return -EINVAL; /* "sorry channel spec wrong " */ break; - } //switch(ui_NoOfChannels) + } /* switch(ui_NoOfChannels) */ return insn->n; } @@ -147,7 +147,7 @@ INT i_APCI2200_ReadMoreDigitalInput(struct comedi_device * dev, struct comedi_su /* +----------------------------------------------------------------------------+ | Function Name : int i_APCI2200_ConfigDigitalOutput (struct comedi_device *dev, - struct comedi_subdevice *s struct comedi_insn *insn,unsigned int *data) | +| struct comedi_subdevice *s struct comedi_insn *insn,unsigned int *data) | | | +----------------------------------------------------------------------------+ | Task : Configures The Digital Output Subdevice. | @@ -156,7 +156,7 @@ INT i_APCI2200_ReadMoreDigitalInput(struct comedi_device * dev, struct comedi_su | unsigned int *data : Data Pointer contains | | configuration parameters as below | | struct comedi_subdevice *s, :pointer to subdevice structure - struct comedi_insn *insn :pointer to insn structure | +| struct comedi_insn *insn :pointer to insn structure | | data[0] :1:Memory on | | 0:Memory off | | | @@ -169,8 +169,8 @@ INT i_APCI2200_ReadMoreDigitalInput(struct comedi_device * dev, struct comedi_su | | +----------------------------------------------------------------------------+ */ -int i_APCI2200_ConfigDigitalOutput(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI2200_ConfigDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { devpriv->b_OutputMemoryStatus = data[0]; return insn->n; @@ -180,13 +180,13 @@ int i_APCI2200_ConfigDigitalOutput(struct comedi_device * dev, struct comedi_sub +----------------------------------------------------------------------------+ | Function Name : int i_APCI2200_WriteDigitalOutput | | (struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn, - unsigned int *data) | +| unsigned int *data) | +----------------------------------------------------------------------------+ | Task : Writes port value To the selected port | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | | struct comedi_subdevice *s, :pointer to subdevice structure - struct comedi_insn *insn :pointer to insn structure | +| struct comedi_insn *insn :pointer to insn structure | | unsigned int *data : Data Pointer to read status | +----------------------------------------------------------------------------+ | Output Parameters : -- | @@ -197,23 +197,23 @@ int i_APCI2200_ConfigDigitalOutput(struct comedi_device * dev, struct comedi_sub +----------------------------------------------------------------------------+ */ -INT i_APCI2200_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI2200_WriteDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - UINT ui_Temp, ui_Temp1; - UINT ui_NoOfChannel = CR_CHAN(insn->chanspec); // get the channel + unsigned int ui_Temp, ui_Temp1; + unsigned int ui_NoOfChannel = CR_CHAN(insn->chanspec); /* get the channel */ if (devpriv->b_OutputMemoryStatus) { ui_Temp = inw(devpriv->iobase + APCI2200_DIGITAL_OP); - } //if(devpriv->b_OutputMemoryStatus ) + } /* if(devpriv->b_OutputMemoryStatus ) */ else { ui_Temp = 0; - } //if(devpriv->b_OutputMemoryStatus ) + } /* if(devpriv->b_OutputMemoryStatus ) */ if (data[3] == 0) { if (data[1] == 0) { data[0] = (data[0] << ui_NoOfChannel) | ui_Temp; outw(data[0], devpriv->iobase + APCI2200_DIGITAL_OP); - } //if(data[1]==0) + } /* if(data[1]==0) */ else { if (data[1] == 1) { switch (ui_NoOfChannel) { @@ -240,18 +240,18 @@ INT i_APCI2200_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subd break; default: comedi_error(dev, " chan spec wrong"); - return -EINVAL; // "sorry channel spec wrong " + return -EINVAL; /* "sorry channel spec wrong " */ - } //switch(ui_NoOfChannels) + } /* switch(ui_NoOfChannels) */ outw(data[0], devpriv->iobase + APCI2200_DIGITAL_OP); - } // if(data[1]==1) + } /* if(data[1]==1) */ else { printk("\nSpecified channel not supported\n"); - } //else if(data[1]==1) - } //elseif(data[1]==0) - } //if(data[3]==0) + } /* else if(data[1]==1) */ + } /* elseif(data[1]==0) */ + } /* if(data[3]==0) */ else { if (data[3] == 1) { if (data[1] == 0) { @@ -263,7 +263,7 @@ INT i_APCI2200_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subd data[0] = data[0] & ui_Temp; outw(data[0], devpriv->iobase + APCI2200_DIGITAL_OP); - } //if(data[1]==0) + } /* if(data[1]==0) */ else { if (data[1] == 1) { switch (ui_NoOfChannel) { @@ -312,38 +312,38 @@ INT i_APCI2200_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subd default: comedi_error(dev, " chan spec wrong"); - return -EINVAL; // "sorry channel spec wrong " + return -EINVAL; /* "sorry channel spec wrong " */ - } //switch(ui_NoOfChannels) + } /* switch(ui_NoOfChannels) */ outw(data[0], devpriv->iobase + APCI2200_DIGITAL_OP); - } // if(data[1]==1) + } /* if(data[1]==1) */ else { printk("\nSpecified channel not supported\n"); - } //else if(data[1]==1) - } //elseif(data[1]==0) - } //if(data[3]==1); + } /* else if(data[1]==1) */ + } /* elseif(data[1]==0) */ + } /* if(data[3]==1); */ else { printk("\nSpecified functionality does not exist\n"); return -EINVAL; - } //if else data[3]==1) - } //if else data[3]==0) - return (insn->n);; + } /* if else data[3]==1) */ + } /* if else data[3]==0) */ + return insn->n; } /* +----------------------------------------------------------------------------+ | Function Name : int i_APCI2200_ReadDigitalOutput | | (struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn, - unsigned int *data) | +| unsigned int *data) | +----------------------------------------------------------------------------+ | Task : Read value of the selected channel or port | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | | struct comedi_subdevice *s, :pointer to subdevice structure - struct comedi_insn *insn :pointer to insn structure | +| struct comedi_insn *insn :pointer to insn structure | | unsigned int *data : Data Pointer to read status | +----------------------------------------------------------------------------+ | Output Parameters : -- | @@ -354,17 +354,17 @@ INT i_APCI2200_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subd +----------------------------------------------------------------------------+ */ -INT i_APCI2200_ReadDigitalOutput(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI2200_ReadDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - UINT ui_Temp; - UINT ui_NoOfChannel = CR_CHAN(insn->chanspec); // get the channel + unsigned int ui_Temp; + unsigned int ui_NoOfChannel = CR_CHAN(insn->chanspec); /* get the channel */ ui_Temp = data[0]; *data = inw(devpriv->iobase + APCI2200_DIGITAL_OP); if (ui_Temp == 0) { *data = (*data >> ui_NoOfChannel) & 0x1; - } //if(ui_Temp==0) + } /* if(ui_Temp==0) */ else { if (ui_Temp == 1) { switch (ui_NoOfChannel) { @@ -386,28 +386,28 @@ INT i_APCI2200_ReadDigitalOutput(struct comedi_device * dev, struct comedi_subde default: comedi_error(dev, " chan spec wrong"); - return -EINVAL; // "sorry channel spec wrong " + return -EINVAL; /* "sorry channel spec wrong " */ - } //switch(ui_NoOfChannels) - } //if(ui_Temp==1) + } /* switch(ui_NoOfChannels) */ + } /* if(ui_Temp==1) */ else { printk("\nSpecified channel not supported \n"); - } //elseif(ui_Temp==1) - } //elseif(ui_Temp==0) + } /* elseif(ui_Temp==1) */ + } /* elseif(ui_Temp==0) */ return insn->n; } /* +----------------------------------------------------------------------------+ | Function Name : int i_APCI2200_ConfigWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) | +| struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) | | | +----------------------------------------------------------------------------+ | Task : Configures The Watchdog | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | | struct comedi_subdevice *s, :pointer to subdevice structure - struct comedi_insn *insn :pointer to insn structure | +| struct comedi_insn *insn :pointer to insn structure | | unsigned int *data : Data Pointer to read status | +----------------------------------------------------------------------------+ | Output Parameters : -- | @@ -418,15 +418,15 @@ INT i_APCI2200_ReadDigitalOutput(struct comedi_device * dev, struct comedi_subde +----------------------------------------------------------------------------+ */ -int i_APCI2200_ConfigWatchdog(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI2200_ConfigWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if (data[0] == 0) { - //Disable the watchdog + /* Disable the watchdog */ outw(0x0, devpriv->iobase + APCI2200_WATCHDOG + APCI2200_WATCHDOG_ENABLEDISABLE); - //Loading the Reload value + /* Loading the Reload value */ outw(data[1], devpriv->iobase + APCI2200_WATCHDOG + APCI2200_WATCHDOG_RELOAD_VALUE); @@ -434,11 +434,11 @@ int i_APCI2200_ConfigWatchdog(struct comedi_device * dev, struct comedi_subdevic outw(data[1], devpriv->iobase + APCI2200_WATCHDOG + APCI2200_WATCHDOG_RELOAD_VALUE + 2); - } //if(data[0]==0) + } /* if(data[0]==0) */ else { printk("\nThe input parameters are wrong\n"); return -EINVAL; - } //elseif(data[0]==0) + } /* elseif(data[0]==0) */ return insn->n; } @@ -464,19 +464,19 @@ int i_APCI2200_ConfigWatchdog(struct comedi_device * dev, struct comedi_subdevic +----------------------------------------------------------------------------+ */ -int i_APCI2200_StartStopWriteWatchdog(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI2200_StartStopWriteWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { switch (data[0]) { - case 0: //stop the watchdog - outw(0x0, devpriv->iobase + APCI2200_WATCHDOG + APCI2200_WATCHDOG_ENABLEDISABLE); //disable the watchdog + case 0: /* stop the watchdog */ + outw(0x0, devpriv->iobase + APCI2200_WATCHDOG + APCI2200_WATCHDOG_ENABLEDISABLE); /* disable the watchdog */ break; - case 1: //start the watchdog + case 1: /* start the watchdog */ outw(0x0001, devpriv->iobase + APCI2200_WATCHDOG + APCI2200_WATCHDOG_ENABLEDISABLE); break; - case 2: //Software trigger + case 2: /* Software trigger */ outw(0x0201, devpriv->iobase + APCI2200_WATCHDOG + APCI2200_WATCHDOG_ENABLEDISABLE); @@ -484,7 +484,7 @@ int i_APCI2200_StartStopWriteWatchdog(struct comedi_device * dev, struct comedi_ default: printk("\nSpecified functionality does not exist\n"); return -EINVAL; - } // switch(data[0]) + } /* switch(data[0]) */ return insn->n; } @@ -492,13 +492,13 @@ int i_APCI2200_StartStopWriteWatchdog(struct comedi_device * dev, struct comedi_ +----------------------------------------------------------------------------+ | Function Name : int i_APCI2200_ReadWatchdog | | (struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn, - unsigned int *data); | +| unsigned int *data); | +----------------------------------------------------------------------------+ | Task : Read The Watchdog | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | | struct comedi_subdevice *s, :pointer to subdevice structure - struct comedi_insn *insn :pointer to insn structure | +| struct comedi_insn *insn :pointer to insn structure | | unsigned int *data : Data Pointer to read status | +----------------------------------------------------------------------------+ | Output Parameters : -- | @@ -509,8 +509,8 @@ int i_APCI2200_StartStopWriteWatchdog(struct comedi_device * dev, struct comedi_ +----------------------------------------------------------------------------+ */ -int i_APCI2200_ReadWatchdog(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI2200_ReadWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { data[0] = inw(devpriv->iobase + APCI2200_WATCHDOG + @@ -533,9 +533,9 @@ int i_APCI2200_ReadWatchdog(struct comedi_device * dev, struct comedi_subdevice +----------------------------------------------------------------------------+ */ -INT i_APCI2200_Reset(struct comedi_device * dev) +int i_APCI2200_Reset(struct comedi_device *dev) { - outw(0x0, devpriv->iobase + APCI2200_DIGITAL_OP); //RESETS THE DIGITAL OUTPUTS + outw(0x0, devpriv->iobase + APCI2200_DIGITAL_OP); /* RESETS THE DIGITAL OUTPUTS */ outw(0x0, devpriv->iobase + APCI2200_WATCHDOG + APCI2200_WATCHDOG_ENABLEDISABLE); diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2200.h b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2200.h index 0a115b4c44c9..63e5f1fcecc7 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2200.h +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2200.h @@ -17,39 +17,39 @@ /********* Definitions for APCI-2200 card *****/ -// Card Specific information +/* Card Specific information */ #define APCI2200_BOARD_VENDOR_ID 0x15b8 #define APCI2200_ADDRESS_RANGE 64 -//DIGITAL INPUT-OUTPUT DEFINE +/* DIGITAL INPUT-OUTPUT DEFINE */ #define APCI2200_DIGITAL_OP 4 #define APCI2200_DIGITAL_IP 0 -// TIMER COUNTER WATCHDOG DEFINES +/* TIMER COUNTER WATCHDOG DEFINES */ #define APCI2200_WATCHDOG 0x08 #define APCI2200_WATCHDOG_ENABLEDISABLE 12 #define APCI2200_WATCHDOG_RELOAD_VALUE 4 #define APCI2200_WATCHDOG_STATUS 16 -// Hardware Layer functions for Apci2200 +/* Hardware Layer functions for Apci2200 */ -//Digital Input -INT i_APCI2200_ReadMoreDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, +/* Digital Input */ +int i_APCI2200_ReadMoreDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -INT i_APCI2200_Read1DigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, +int i_APCI2200_Read1DigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -//Digital Output +/* Digital Output */ int i_APCI2200_ConfigDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -INT i_APCI2200_WriteDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, +int i_APCI2200_WriteDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -INT i_APCI2200_ReadDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, +int i_APCI2200_ReadDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -// TIMER +/* TIMER */ int i_APCI2200_ConfigWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); int i_APCI2200_StartStopWriteWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, @@ -57,5 +57,5 @@ int i_APCI2200_StartStopWriteWatchdog(struct comedi_device *dev, struct comedi_s int i_APCI2200_ReadWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -//reset -INT i_APCI2200_Reset(struct comedi_device *dev); +/* reset */ +int i_APCI2200_Reset(struct comedi_device *dev); diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c index 68eb8dfd5139..169cee41b871 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c @@ -3,13 +3,13 @@ Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data-com - info@addi-data.com + ADDI-DATA GmbH + Dieselstrasse 3 + D-77833 Ottersweier + Tel: +19(0)7223/9493-0 + Fax: +49(0)7223/9493-92 + http://www.addi-data-com + info@addi-data.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. @@ -45,9 +45,9 @@ You shoud also find the complete GPL in the COPYING file accompanying this sourc */ #include "hwdrv_apci3120.h" -static UINT ui_Temp = 0; +static unsigned int ui_Temp = 0; -// FUNCTION DEFINITIONS +/* FUNCTION DEFINITIONS */ /* +----------------------------------------------------------------------------+ @@ -74,20 +74,20 @@ static UINT ui_Temp = 0; +----------------------------------------------------------------------------+ */ -int i_APCI3120_InsnConfigAnalogInput(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI3120_InsnConfigAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - UINT i; + unsigned int i; if ((data[0] != APCI3120_EOC_MODE) && (data[0] != APCI3120_EOS_MODE)) return -1; - // Check for Conversion time to be added ?? + /* Check for Conversion time to be added ?? */ devpriv->ui_EocEosConversionTime = data[2]; if (data[0] == APCI3120_EOS_MODE) { - //Test the number of the channel + /* Test the number of the channel */ for (i = 0; i < data[3]; i++) { if (CR_CHAN(data[4 + i]) >= this_board->i_NbrAiChannel) { @@ -102,14 +102,14 @@ int i_APCI3120_InsnConfigAnalogInput(struct comedi_device * dev, struct comedi_s devpriv->b_EocEosInterrupt = APCI3120_ENABLE; } else devpriv->b_EocEosInterrupt = APCI3120_DISABLE; - // Copy channel list and Range List to devpriv + /* Copy channel list and Range List to devpriv */ devpriv->ui_AiNbrofChannels = data[3]; for (i = 0; i < devpriv->ui_AiNbrofChannels; i++) { devpriv->ui_AiChannelList[i] = data[4 + i]; } - } else // EOC + } else /* EOC */ { devpriv->b_InterruptMode = APCI3120_EOC_MODE; if (data[1]) { @@ -145,28 +145,28 @@ int i_APCI3120_InsnConfigAnalogInput(struct comedi_device * dev, struct comedi_s +----------------------------------------------------------------------------+ */ -int i_APCI3120_InsnReadAnalogInput(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - USHORT us_ConvertTiming, us_TmpValue, i; - BYTE b_Tmp; + unsigned short us_ConvertTiming, us_TmpValue, i; + unsigned char b_Tmp; - // fix convertion time to 10 us + /* fix convertion time to 10 us */ if (!devpriv->ui_EocEosConversionTime) { printk("No timer0 Value using 10 us\n"); us_ConvertTiming = 10; } else - us_ConvertTiming = (USHORT) (devpriv->ui_EocEosConversionTime / 1000); // nano to useconds + us_ConvertTiming = (unsigned short) (devpriv->ui_EocEosConversionTime / 1000); /* nano to useconds */ - // this_board->i_hwdrv_InsnReadAnalogInput(dev,us_ConvertTiming,insn->n,&insn->chanspec,data,insn->unused[0]); + /* this_board->i_hwdrv_InsnReadAnalogInput(dev,us_ConvertTiming,insn->n,&insn->chanspec,data,insn->unused[0]); */ - // Clear software registers + /* Clear software registers */ devpriv->b_TimerSelectMode = 0; devpriv->b_ModeSelectRegister = 0; devpriv->us_OutputRegister = 0; -// devpriv->b_DigitalOutputRegister=0; +/* devpriv->b_DigitalOutputRegister=0; */ - if (insn->unused[0] == 222) // second insn read + if (insn->unused[0] == 222) /* second insn read */ { for (i = 0; i < insn->n; i++) { @@ -174,14 +174,16 @@ int i_APCI3120_InsnReadAnalogInput(struct comedi_device * dev, struct comedi_sub } } else { - devpriv->tsk_Current = current; // Save the current process task structure - //Testing if board have the new Quartz and calculate the time value - //to set in the timer + devpriv->tsk_Current = current; /* Save the current process task structure */ +/* + * Testing if board have the new Quartz and calculate the time value + * to set in the timer + */ us_TmpValue = - (USHORT) inw(devpriv->iobase + APCI3120_RD_STATUS); + (unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS); - //EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001 + /* EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001 */ if ((us_TmpValue & 0x00B0) == 0x00B0 || !strcmp(this_board->pc_DriverName, "apci3001")) { us_ConvertTiming = (us_ConvertTiming * 2) - 2; @@ -190,25 +192,26 @@ int i_APCI3120_InsnReadAnalogInput(struct comedi_device * dev, struct comedi_sub ((us_ConvertTiming * 12926) / 10000) - 1; } - us_TmpValue = (USHORT) devpriv->b_InterruptMode; + us_TmpValue = (unsigned short) devpriv->b_InterruptMode; switch (us_TmpValue) { case APCI3120_EOC_MODE: - // Testing the interrupt flag and set the EOC bit - // Clears the FIFO +/* + * Testing the interrupt flag and set the EOC bit Clears the FIFO + */ inw(devpriv->iobase + APCI3120_RESET_FIFO); - // Initialize the sequence array + /* Initialize the sequence array */ - //if (!i_APCI3120_SetupChannelList(dev,s,1,chanlist,0)) return -EINVAL; + /* if (!i_APCI3120_SetupChannelList(dev,s,1,chanlist,0)) return -EINVAL; */ if (!i_APCI3120_SetupChannelList(dev, s, 1, &insn->chanspec, 0)) return -EINVAL; - //Initialize Timer 0 mode 4 + /* Initialize Timer 0 mode 4 */ devpriv->b_TimerSelectMode = (devpriv-> b_TimerSelectMode & 0xFC) | @@ -216,14 +219,14 @@ int i_APCI3120_InsnReadAnalogInput(struct comedi_device * dev, struct comedi_sub outb(devpriv->b_TimerSelectMode, devpriv->iobase + APCI3120_TIMER_CRT1); - // Reset the scan bit and Disables the EOS, DMA, EOC interrupt + /* Reset the scan bit and Disables the EOS, DMA, EOC interrupt */ devpriv->b_ModeSelectRegister = devpriv-> b_ModeSelectRegister & APCI3120_DISABLE_SCAN; if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) { - //Disables the EOS,DMA and enables the EOC interrupt + /* Disables the EOS,DMA and enables the EOC interrupt */ devpriv->b_ModeSelectRegister = (devpriv-> b_ModeSelectRegister & @@ -241,7 +244,7 @@ int i_APCI3120_InsnReadAnalogInput(struct comedi_device * dev, struct comedi_sub outb(devpriv->b_ModeSelectRegister, devpriv->iobase + APCI3120_WRITE_MODE_SELECT); - // Sets gate 0 + /* Sets gate 0 */ devpriv->us_OutputRegister = (devpriv-> us_OutputRegister & APCI3120_CLEAR_PA_PR) | @@ -249,30 +252,30 @@ int i_APCI3120_InsnReadAnalogInput(struct comedi_device * dev, struct comedi_sub outw(devpriv->us_OutputRegister, devpriv->iobase + APCI3120_WR_ADDRESS); - // Select Timer 0 + /* Select Timer 0 */ b_Tmp = ((devpriv-> b_DigitalOutputRegister) & 0xF0) | APCI3120_SELECT_TIMER_0_WORD; outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0); - //Set the convertion time + /* Set the convertion time */ outw(us_ConvertTiming, devpriv->iobase + APCI3120_TIMER_VALUE); us_TmpValue = - (USHORT) inw(dev->iobase + APCI3120_RD_STATUS); + (unsigned short) inw(dev->iobase + APCI3120_RD_STATUS); if (devpriv->b_EocEosInterrupt == APCI3120_DISABLE) { do { - // Waiting for the end of conversion + /* Waiting for the end of conversion */ us_TmpValue = inw(devpriv->iobase + APCI3120_RD_STATUS); } while ((us_TmpValue & APCI3120_EOC) == APCI3120_EOC); - //Read the result in FIFO and put it in insn data pointer + /* Read the result in FIFO and put it in insn data pointer */ us_TmpValue = inw(devpriv->iobase + 0); *data = us_TmpValue; @@ -284,9 +287,9 @@ int i_APCI3120_InsnReadAnalogInput(struct comedi_device * dev, struct comedi_sub case APCI3120_EOS_MODE: inw(devpriv->iobase); - // Clears the FIFO + /* Clears the FIFO */ inw(devpriv->iobase + APCI3120_RESET_FIFO); - // clear PA PR and disable timer 0 + /* clear PA PR and disable timer 0 */ devpriv->us_OutputRegister = (devpriv-> @@ -301,7 +304,7 @@ int i_APCI3120_InsnReadAnalogInput(struct comedi_device * dev, struct comedi_sub devpriv->ui_AiChannelList, 0)) return -EINVAL; - //Initialize Timer 0 mode 2 + /* Initialize Timer 0 mode 2 */ devpriv->b_TimerSelectMode = (devpriv-> b_TimerSelectMode & 0xFC) | @@ -309,26 +312,26 @@ int i_APCI3120_InsnReadAnalogInput(struct comedi_device * dev, struct comedi_sub outb(devpriv->b_TimerSelectMode, devpriv->iobase + APCI3120_TIMER_CRT1); - //Select Timer 0 + /* Select Timer 0 */ b_Tmp = ((devpriv-> b_DigitalOutputRegister) & 0xF0) | APCI3120_SELECT_TIMER_0_WORD; outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0); - //Set the convertion time + /* Set the convertion time */ outw(us_ConvertTiming, devpriv->iobase + APCI3120_TIMER_VALUE); - //Set the scan bit + /* Set the scan bit */ devpriv->b_ModeSelectRegister = devpriv-> b_ModeSelectRegister | APCI3120_ENABLE_SCAN; outb(devpriv->b_ModeSelectRegister, devpriv->iobase + APCI3120_WRITE_MODE_SELECT); - //If Interrupt function is loaded + /* If Interrupt function is loaded */ if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) { - //Disables the EOC,DMA and enables the EOS interrupt + /* Disables the EOC,DMA and enables the EOS interrupt */ devpriv->b_ModeSelectRegister = (devpriv-> b_ModeSelectRegister & @@ -347,7 +350,7 @@ int i_APCI3120_InsnReadAnalogInput(struct comedi_device * dev, struct comedi_sub inw(devpriv->iobase + APCI3120_RD_STATUS); - //Sets gate 0 + /* Sets gate 0 */ devpriv->us_OutputRegister = devpriv-> @@ -355,28 +358,27 @@ int i_APCI3120_InsnReadAnalogInput(struct comedi_device * dev, struct comedi_sub outw(devpriv->us_OutputRegister, devpriv->iobase + APCI3120_WR_ADDRESS); - //Start conversion + /* Start conversion */ outw(0, devpriv->iobase + APCI3120_START_CONVERSION); - //Waiting of end of convertion if interrupt is not installed + /* Waiting of end of convertion if interrupt is not installed */ if (devpriv->b_EocEosInterrupt == APCI3120_DISABLE) { - //Waiting the end of convertion + /* Waiting the end of convertion */ do { us_TmpValue = inw(devpriv->iobase + APCI3120_RD_STATUS); - } - while ((us_TmpValue & APCI3120_EOS) != - APCI3120_EOS); + } while ((us_TmpValue & APCI3120_EOS) != + APCI3120_EOS); for (i = 0; i < devpriv->ui_AiNbrofChannels; i++) { - //Read the result in FIFO and write them in shared memory + /* Read the result in FIFO and write them in shared memory */ us_TmpValue = inw(devpriv->iobase); - data[i] = (UINT) us_TmpValue; + data[i] = (unsigned int) us_TmpValue; } - devpriv->b_InterruptMode = APCI3120_EOC_MODE; // Restore defaults. + devpriv->b_InterruptMode = APCI3120_EOC_MODE; /* Restore defaults. */ } break; @@ -384,7 +386,7 @@ int i_APCI3120_InsnReadAnalogInput(struct comedi_device * dev, struct comedi_sub printk("inputs wrong\n"); } - devpriv->ui_EocEosConversionTime = 0; // re initializing the variable; + devpriv->ui_EocEosConversionTime = 0; /* re initializing the variable; */ } return insn->n; @@ -409,38 +411,41 @@ int i_APCI3120_InsnReadAnalogInput(struct comedi_device * dev, struct comedi_sub +----------------------------------------------------------------------------+ */ -int i_APCI3120_StopCyclicAcquisition(struct comedi_device * dev, struct comedi_subdevice * s) +int i_APCI3120_StopCyclicAcquisition(struct comedi_device *dev, struct comedi_subdevice *s) { - // Disable A2P Fifo write and AMWEN signal + /* Disable A2P Fifo write and AMWEN signal */ outw(0, devpriv->i_IobaseAddon + 4); - //Disable Bus Master ADD ON + /* Disable Bus Master ADD ON */ outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0); outw(0, devpriv->i_IobaseAddon + 2); outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0); outw(0, devpriv->i_IobaseAddon + 2); - //Disable BUS Master PCI + /* Disable BUS Master PCI */ outl(0, devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR); - //outl(inl(devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR)&(~AINT_WRITE_COMPL), devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR); // stop amcc irqs - //outl(inl(devpriv->i_IobaseAmcc+AMCC_OP_REG_MCSR)&(~EN_A2P_TRANSFERS), devpriv->i_IobaseAmcc+AMCC_OP_REG_MCSR); // stop DMA + /* outl(inl(devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR)&(~AINT_WRITE_COMPL), + * devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR); stop amcc irqs */ - //Disable ext trigger + /* outl(inl(devpriv->i_IobaseAmcc+AMCC_OP_REG_MCSR)&(~EN_A2P_TRANSFERS), + * devpriv->i_IobaseAmcc+AMCC_OP_REG_MCSR); stop DMA */ + + /* Disable ext trigger */ i_APCI3120_ExttrigDisable(dev); devpriv->us_OutputRegister = 0; - //stop counters + /* stop counters */ outw(devpriv-> us_OutputRegister & APCI3120_DISABLE_TIMER0 & APCI3120_DISABLE_TIMER1, dev->iobase + APCI3120_WR_ADDRESS); outw(APCI3120_DISABLE_ALL_TIMER, dev->iobase + APCI3120_WR_ADDRESS); - //DISABLE_ALL_INTERRUPT + /* DISABLE_ALL_INTERRUPT */ outb(APCI3120_DISABLE_ALL_INTERRUPT, dev->iobase + APCI3120_WRITE_MODE_SELECT); - //Flush FIFO + /* Flush FIFO */ inb(dev->iobase + APCI3120_RESET_FIFO); inw(dev->iobase + APCI3120_RD_STATUS); devpriv->ui_AiActualScan = 0; @@ -476,13 +481,13 @@ int i_APCI3120_StopCyclicAcquisition(struct comedi_device * dev, struct comedi_s +----------------------------------------------------------------------------+ */ -int i_APCI3120_CommandTestAnalogInput(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd) +int i_APCI3120_CommandTestAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd) { int err = 0; - int tmp; // divisor1,divisor2; + int tmp; /* divisor1,divisor2; */ - // step 1: make sure trigger sources are trivially valid + /* step 1: make sure trigger sources are trivially valid */ tmp = cmd->start_src; cmd->start_src &= TRIG_NOW | TRIG_EXT; @@ -512,7 +517,7 @@ int i_APCI3120_CommandTestAnalogInput(struct comedi_device * dev, struct comedi_ if (err) return 1; - //step 2: make sure trigger sources are unique and mutually compatible + /* step 2: make sure trigger sources are unique and mutually compatible */ if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) { err++; @@ -536,14 +541,14 @@ int i_APCI3120_CommandTestAnalogInput(struct comedi_device * dev, struct comedi_ if (err) return 2; - // step 3: make sure arguments are trivially compatible + /* step 3: make sure arguments are trivially compatible */ if (cmd->start_arg != 0) { cmd->start_arg = 0; err++; } - if (cmd->scan_begin_src == TRIG_TIMER) // Test Delay timing + if (cmd->scan_begin_src == TRIG_TIMER) /* Test Delay timing */ { if (cmd->scan_begin_arg < this_board->ui_MinDelaytimeNs) { cmd->scan_begin_arg = this_board->ui_MinDelaytimeNs; @@ -551,7 +556,7 @@ int i_APCI3120_CommandTestAnalogInput(struct comedi_device * dev, struct comedi_ } } - if (cmd->convert_src == TRIG_TIMER) // Test Acquisition timing + if (cmd->convert_src == TRIG_TIMER) /* Test Acquisition timing */ { if (cmd->scan_begin_src == TRIG_TIMER) { if ((cmd->convert_arg) @@ -585,7 +590,7 @@ int i_APCI3120_CommandTestAnalogInput(struct comedi_device * dev, struct comedi_ cmd->stop_arg = 1; err++; } - } else { // TRIG_NONE + } else { /* TRIG_NONE */ if (cmd->stop_arg != 0) { cmd->stop_arg = 0; err++; @@ -595,7 +600,7 @@ int i_APCI3120_CommandTestAnalogInput(struct comedi_device * dev, struct comedi_ if (err) return 3; - // step 4: fix up any arguments + /* step 4: fix up any arguments */ if (cmd->convert_src == TRIG_TIMER) { @@ -633,19 +638,19 @@ int i_APCI3120_CommandTestAnalogInput(struct comedi_device * dev, struct comedi_ +----------------------------------------------------------------------------+ */ -int i_APCI3120_CommandAnalogInput(struct comedi_device * dev, struct comedi_subdevice * s) +int i_APCI3120_CommandAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s) { struct comedi_cmd *cmd = &s->async->cmd; - //loading private structure with cmd structure inputs + /* loading private structure with cmd structure inputs */ devpriv->ui_AiFlags = cmd->flags; devpriv->ui_AiNbrofChannels = cmd->chanlist_len; devpriv->ui_AiScanLength = cmd->scan_end_arg; devpriv->pui_AiChannelList = cmd->chanlist; - //UPDATE-0.7.57->0.7.68devpriv->AiData=s->async->data; + /* UPDATE-0.7.57->0.7.68devpriv->AiData=s->async->data; */ devpriv->AiData = s->async->prealloc_buf; - //UPDATE-0.7.57->0.7.68devpriv->ui_AiDataLength=s->async->data_len; + /* UPDATE-0.7.57->0.7.68devpriv->ui_AiDataLength=s->async->data_len; */ devpriv->ui_AiDataLength = s->async->prealloc_bufsz; if (cmd->stop_src == TRIG_COUNT) { @@ -654,11 +659,11 @@ int i_APCI3120_CommandAnalogInput(struct comedi_device * dev, struct comedi_subd devpriv->ui_AiNbrofScans = 0; } - devpriv->ui_AiTimer0 = 0; // variables changed to timer0,timer1 + devpriv->ui_AiTimer0 = 0; /* variables changed to timer0,timer1 */ devpriv->ui_AiTimer1 = 0; if ((devpriv->ui_AiNbrofScans == 0) || (devpriv->ui_AiNbrofScans == -1)) - devpriv->b_AiContinuous = 1; // user want neverending analog acquisition - // stopped using cancel + devpriv->b_AiContinuous = 1; /* user want neverending analog acquisition */ + /* stopped using cancel */ if (cmd->start_src == TRIG_EXT) devpriv->b_ExttrigEnable = APCI3120_ENABLE; @@ -666,22 +671,22 @@ int i_APCI3120_CommandAnalogInput(struct comedi_device * dev, struct comedi_subd devpriv->b_ExttrigEnable = APCI3120_DISABLE; if (cmd->scan_begin_src == TRIG_FOLLOW) { - // mode 1 or 3 + /* mode 1 or 3 */ if (cmd->convert_src == TRIG_TIMER) { - // mode 1 + /* mode 1 */ - devpriv->ui_AiTimer0 = cmd->convert_arg; // timer constant in nano seconds - //return this_board->i_hwdrv_CommandAnalogInput(1,dev,s); + devpriv->ui_AiTimer0 = cmd->convert_arg; /* timer constant in nano seconds */ + /* return this_board->i_hwdrv_CommandAnalogInput(1,dev,s); */ return i_APCI3120_CyclicAnalogInput(1, dev, s); } } if ((cmd->scan_begin_src == TRIG_TIMER) && (cmd->convert_src == TRIG_TIMER)) { - // mode 2 + /* mode 2 */ devpriv->ui_AiTimer1 = cmd->scan_begin_arg; - devpriv->ui_AiTimer0 = cmd->convert_arg; // variable changed timer2 to timer0 - //return this_board->i_hwdrv_CommandAnalogInput(2,dev,s); + devpriv->ui_AiTimer0 = cmd->convert_arg; /* variable changed timer2 to timer0 */ + /* return this_board->i_hwdrv_CommandAnalogInput(2,dev,s); */ return i_APCI3120_CyclicAnalogInput(2, dev, s); } return -1; @@ -707,73 +712,74 @@ int i_APCI3120_CommandAnalogInput(struct comedi_device * dev, struct comedi_subd +----------------------------------------------------------------------------+ */ -int i_APCI3120_CyclicAnalogInput(int mode, struct comedi_device * dev, - struct comedi_subdevice * s) +int i_APCI3120_CyclicAnalogInput(int mode, struct comedi_device *dev, + struct comedi_subdevice *s) { - BYTE b_Tmp; - UINT ui_Tmp, ui_DelayTiming = 0, ui_TimerValue1 = 0, dmalen0 = + unsigned char b_Tmp; + unsigned int ui_Tmp, ui_DelayTiming = 0, ui_TimerValue1 = 0, dmalen0 = 0, dmalen1 = 0, ui_TimerValue2 = 0, ui_TimerValue0, ui_ConvertTiming; - USHORT us_TmpValue; + unsigned short us_TmpValue; - //BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver - //devpriv->b_AiCyclicAcquisition=APCI3120_ENABLE; - //END JK 07.05.04: Comparison between WIN32 and Linux driver + /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */ + /* devpriv->b_AiCyclicAcquisition=APCI3120_ENABLE; */ + /* END JK 07.05.04: Comparison between WIN32 and Linux driver */ /*******************/ /* Resets the FIFO */ /*******************/ inb(dev->iobase + APCI3120_RESET_FIFO); - //BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver - //inw(dev->iobase+APCI3120_RD_STATUS); - //END JK 07.05.04: Comparison between WIN32 and Linux driver + /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */ + /* inw(dev->iobase+APCI3120_RD_STATUS); */ + /* END JK 07.05.04: Comparison between WIN32 and Linux driver */ /***************************/ /* Acquisition initialized */ /***************************/ - //BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver + /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */ devpriv->b_AiCyclicAcquisition = APCI3120_ENABLE; - //END JK 07.05.04: Comparison between WIN32 and Linux driver + /* END JK 07.05.04: Comparison between WIN32 and Linux driver */ - // clear software registers + /* clear software registers */ devpriv->b_TimerSelectMode = 0; devpriv->us_OutputRegister = 0; devpriv->b_ModeSelectRegister = 0; - //devpriv->b_DigitalOutputRegister=0; + /* devpriv->b_DigitalOutputRegister=0; */ - //COMMENT JK 07.05.04: Followings calls are in i_APCI3120_StartAnalogInputAcquisition + /* COMMENT JK 07.05.04: Followings calls are in i_APCI3120_StartAnalogInputAcquisition */ - /****************************/ - /* Clear Timer Write TC INT */ - /****************************/ + /****************************/ + /* Clear Timer Write TC int */ + /****************************/ outl(APCI3120_CLEAR_WRITE_TC_INT, devpriv->i_IobaseAmcc + APCI3120_AMCC_OP_REG_INTCSR); - /************************************/ + /************************************/ /* Clears the timer status register */ - /************************************/ - //BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver - //inw(dev->iobase+APCI3120_TIMER_STATUS_REGISTER); - inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER); - //END JK 07.05.04: Comparison between WIN32 and Linux driver + /************************************/ - /**************************/ + /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */ + /* inw(dev->iobase+APCI3120_TIMER_STATUS_REGISTER); */ + /* inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER); */ + /* END JK 07.05.04: Comparison between WIN32 and Linux driver */ + + /**************************/ /* Disables All Timer */ /* Sets PR and PA to 0 */ - /**************************/ + /**************************/ devpriv->us_OutputRegister = devpriv->us_OutputRegister & APCI3120_DISABLE_TIMER0 & APCI3120_DISABLE_TIMER1 & APCI3120_CLEAR_PA_PR; outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS); - /*******************/ + /*******************/ /* Resets the FIFO */ - /*******************/ - //BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver + /*******************/ + /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */ inb(devpriv->iobase + APCI3120_RESET_FIFO); - //END JK 07.05.04: Comparison between WIN32 and Linux driver + /* END JK 07.05.04: Comparison between WIN32 and Linux driver */ devpriv->ui_AiActualScan = 0; devpriv->ui_AiActualScanPosition = 0; @@ -781,7 +787,7 @@ int i_APCI3120_CyclicAnalogInput(int mode, struct comedi_device * dev, devpriv->ui_AiBufferPtr = 0; devpriv->ui_DmaActualBuffer = 0; - // value for timer2 minus -2 has to be done .....dunno y?? + /* value for timer2 minus -2 has to be done .....dunno y?? */ ui_TimerValue2 = devpriv->ui_AiNbrofScans - 2; ui_ConvertTiming = devpriv->ui_AiTimer0; @@ -795,31 +801,31 @@ int i_APCI3120_CyclicAnalogInput(int mode, struct comedi_device * dev, devpriv->pui_AiChannelList, 0)) return -EINVAL; - us_TmpValue = (USHORT) inw(dev->iobase + APCI3120_RD_STATUS); + us_TmpValue = (unsigned short) inw(dev->iobase + APCI3120_RD_STATUS); /*** EL241003 : add this section in comment because floats must not be used - if((us_TmpValue & 0x00B0)==0x00B0) + if((us_TmpValue & 0x00B0)==0x00B0) { - f_ConvertValue=(((float)ui_ConvertTiming * 0.002) - 2); - ui_TimerValue0=(UINT)f_ConvertValue; + f_ConvertValue=(((float)ui_ConvertTiming * 0.002) - 2); + ui_TimerValue0=(unsigned int)f_ConvertValue; if (mode==2) { f_DelayValue = (((float)ui_DelayTiming * 0.00002) - 2); - ui_TimerValue1 = (UINT) f_DelayValue; + ui_TimerValue1 = (unsigned int) f_DelayValue; } } - else + else { f_ConvertValue=(((float)ui_ConvertTiming * 0.0012926) - 1); - ui_TimerValue0=(UINT)f_ConvertValue; + ui_TimerValue0=(unsigned int)f_ConvertValue; if (mode == 2) { f_DelayValue = (((float)ui_DelayTiming * 0.000012926) - 1); - ui_TimerValue1 = (UINT) f_DelayValue; + ui_TimerValue1 = (unsigned int) f_DelayValue; } } ***********************************************************************************************/ /*** EL241003 Begin : add this section to replace floats calculation by integer calculations **/ - //EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001 + /* EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001 */ if ((us_TmpValue & 0x00B0) == 0x00B0 || !strcmp(this_board->pc_DriverName, "apci3001")) { ui_TimerValue0 = ui_ConvertTiming * 2 - 2000; @@ -844,79 +850,82 @@ int i_APCI3120_CyclicAnalogInput(int mode, struct comedi_device * dev, /*** EL241003 End ******************************************************************************/ if (devpriv->b_ExttrigEnable == APCI3120_ENABLE) { - i_APCI3120_ExttrigEnable(dev); // activate EXT trigger + i_APCI3120_ExttrigEnable(dev); /* activate EXT trigger */ } switch (mode) { case 1: - // init timer0 in mode 2 + /* init timer0 in mode 2 */ devpriv->b_TimerSelectMode = (devpriv-> b_TimerSelectMode & 0xFC) | APCI3120_TIMER_0_MODE_2; outb(devpriv->b_TimerSelectMode, dev->iobase + APCI3120_TIMER_CRT1); - //Select Timer 0 + /* Select Timer 0 */ b_Tmp = ((devpriv-> b_DigitalOutputRegister) & 0xF0) | APCI3120_SELECT_TIMER_0_WORD; outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0); - //Set the convertion time - outw(((USHORT) ui_TimerValue0), + /* Set the convertion time */ + outw(((unsigned short) ui_TimerValue0), dev->iobase + APCI3120_TIMER_VALUE); break; case 2: - // init timer1 in mode 2 + /* init timer1 in mode 2 */ devpriv->b_TimerSelectMode = (devpriv-> b_TimerSelectMode & 0xF3) | APCI3120_TIMER_1_MODE_2; outb(devpriv->b_TimerSelectMode, dev->iobase + APCI3120_TIMER_CRT1); - //Select Timer 1 + /* Select Timer 1 */ b_Tmp = ((devpriv-> b_DigitalOutputRegister) & 0xF0) | APCI3120_SELECT_TIMER_1_WORD; outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0); - //Set the convertion time - outw(((USHORT) ui_TimerValue1), + /* Set the convertion time */ + outw(((unsigned short) ui_TimerValue1), dev->iobase + APCI3120_TIMER_VALUE); - // init timer0 in mode 2 + /* init timer0 in mode 2 */ devpriv->b_TimerSelectMode = (devpriv-> b_TimerSelectMode & 0xFC) | APCI3120_TIMER_0_MODE_2; outb(devpriv->b_TimerSelectMode, dev->iobase + APCI3120_TIMER_CRT1); - //Select Timer 0 + /* Select Timer 0 */ b_Tmp = ((devpriv-> b_DigitalOutputRegister) & 0xF0) | APCI3120_SELECT_TIMER_0_WORD; outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0); - //Set the convertion time - outw(((USHORT) ui_TimerValue0), + /* Set the convertion time */ + outw(((unsigned short) ui_TimerValue0), dev->iobase + APCI3120_TIMER_VALUE); break; } - // ##########common for all modes################# + /* ##########common for all modes################# */ /***********************/ /* Clears the SCAN bit */ /***********************/ - //BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver - //devpriv->b_ModeSelectRegister=devpriv->b_ModeSelectRegister | APCI3120_DISABLE_SCAN; + + /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */ + /* devpriv->b_ModeSelectRegister=devpriv->b_ModeSelectRegister | APCI3120_DISABLE_SCAN; */ + devpriv->b_ModeSelectRegister = devpriv->b_ModeSelectRegister & APCI3120_DISABLE_SCAN; - //END JK 07.05.04: Comparison between WIN32 and Linux driver + /* END JK 07.05.04: Comparison between WIN32 and Linux driver */ + outb(devpriv->b_ModeSelectRegister, dev->iobase + APCI3120_WRITE_MODE_SELECT); - // If DMA is disabled + /* If DMA is disabled */ if (devpriv->us_UseDma == APCI3120_DISABLE) { - // disable EOC and enable EOS + /* disable EOC and enable EOS */ devpriv->b_InterruptMode = APCI3120_EOS_MODE; devpriv->b_EocEosInterrupt = APCI3120_ENABLE; @@ -928,15 +937,17 @@ int i_APCI3120_CyclicAnalogInput(int mode, struct comedi_device * dev, dev->iobase + APCI3120_WRITE_MODE_SELECT); if (!devpriv->b_AiContinuous) { - // configure Timer2 For counting EOS - //Reset gate 2 of Timer 2 to disable it (Set Bit D14 to 0) +/* + * configure Timer2 For counting EOS Reset gate 2 of Timer 2 to + * disable it (Set Bit D14 to 0) + */ devpriv->us_OutputRegister = devpriv-> us_OutputRegister & APCI3120_DISABLE_TIMER2; outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS); - // DISABLE TIMER INTERRUPT + /* DISABLE TIMER intERRUPT */ devpriv->b_ModeSelectRegister = devpriv-> b_ModeSelectRegister & @@ -944,7 +955,7 @@ int i_APCI3120_CyclicAnalogInput(int mode, struct comedi_device * dev, outb(devpriv->b_ModeSelectRegister, dev->iobase + APCI3120_WRITE_MODE_SELECT); - //(1) Init timer 2 in mode 0 and write timer value + /* (1) Init timer 2 in mode 0 and write timer value */ devpriv->b_TimerSelectMode = (devpriv-> b_TimerSelectMode & 0x0F) | @@ -952,7 +963,7 @@ int i_APCI3120_CyclicAnalogInput(int mode, struct comedi_device * dev, outb(devpriv->b_TimerSelectMode, dev->iobase + APCI3120_TIMER_CRT1); - //Writing LOW WORD + /* Writing LOW unsigned short */ b_Tmp = ((devpriv-> b_DigitalOutputRegister) & 0xF0) | APCI3120_SELECT_TIMER_2_LOW_WORD; @@ -960,7 +971,7 @@ int i_APCI3120_CyclicAnalogInput(int mode, struct comedi_device * dev, outw(LOWORD(ui_TimerValue2), dev->iobase + APCI3120_TIMER_VALUE); - //Writing HIGH WORD + /* Writing HIGH unsigned short */ b_Tmp = ((devpriv-> b_DigitalOutputRegister) & 0xF0) | APCI3120_SELECT_TIMER_2_HIGH_WORD; @@ -968,20 +979,20 @@ int i_APCI3120_CyclicAnalogInput(int mode, struct comedi_device * dev, outw(HIWORD(ui_TimerValue2), dev->iobase + APCI3120_TIMER_VALUE); - //(2) Reset FC_TIMER BIT Clearing timer status register + /* (2) Reset FC_TIMER BIT Clearing timer status register */ inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER); - // enable timer counter and disable watch dog + /* enable timer counter and disable watch dog */ devpriv->b_ModeSelectRegister = (devpriv-> b_ModeSelectRegister | APCI3120_ENABLE_TIMER_COUNTER) & APCI3120_DISABLE_WATCHDOG; - // select EOS clock input for timer 2 + /* select EOS clock input for timer 2 */ devpriv->b_ModeSelectRegister = devpriv-> b_ModeSelectRegister | APCI3120_TIMER2_SELECT_EOS; - // Enable timer2 interrupt + /* Enable timer2 interrupt */ devpriv->b_ModeSelectRegister = devpriv-> b_ModeSelectRegister | @@ -992,15 +1003,16 @@ int i_APCI3120_CyclicAnalogInput(int mode, struct comedi_device * dev, devpriv->b_Timer2Interrupt = APCI3120_ENABLE; } } else { - // If DMA Enabled - //BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver - //inw(dev->iobase+0);// reset EOC bit - //END JK 07.05.04: Comparison between WIN32 and Linux driver + /* If DMA Enabled */ + + /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */ + /* inw(dev->iobase+0); reset EOC bit */ + /* END JK 07.05.04: Comparison between WIN32 and Linux driver */ devpriv->b_InterruptMode = APCI3120_DMA_MODE; - /************************************/ + /************************************/ /* Disables the EOC, EOS interrupt */ - /************************************/ + /************************************/ devpriv->b_ModeSelectRegister = devpriv->b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT & APCI3120_DISABLE_EOS_INT; @@ -1012,18 +1024,18 @@ int i_APCI3120_CyclicAnalogInput(int mode, struct comedi_device * dev, if (!devpriv->b_AiContinuous) { - if (dmalen0 > (devpriv->ui_AiNbrofScans * devpriv->ui_AiScanLength * 2)) { // must we fill full first buffer? + if (dmalen0 > (devpriv->ui_AiNbrofScans * devpriv->ui_AiScanLength * 2)) { /* must we fill full first buffer? */ dmalen0 = devpriv->ui_AiNbrofScans * devpriv->ui_AiScanLength * 2; - } else if (dmalen1 > (devpriv->ui_AiNbrofScans * devpriv->ui_AiScanLength * 2 - dmalen0)) // and must we fill full second buffer when first is once filled? + } else if (dmalen1 > (devpriv->ui_AiNbrofScans * devpriv->ui_AiScanLength * 2 - dmalen0)) /* and must we fill full second buffer when first is once filled? */ dmalen1 = devpriv->ui_AiNbrofScans * devpriv->ui_AiScanLength * 2 - dmalen0; } if (devpriv->ui_AiFlags & TRIG_WAKE_EOS) { - // don't we want wake up every scan? + /* don't we want wake up every scan? */ if (dmalen0 > (devpriv->ui_AiScanLength * 2)) { dmalen0 = devpriv->ui_AiScanLength * 2; if (devpriv->ui_AiScanLength & 1) @@ -1036,7 +1048,7 @@ int i_APCI3120_CyclicAnalogInput(int mode, struct comedi_device * dev, if (dmalen1 < 4) dmalen1 = 4; } - } else { // isn't output buff smaller that our DMA buff? + } else { /* isn't output buff smaller that our DMA buff? */ if (dmalen0 > (devpriv->ui_AiDataLength)) { dmalen0 = devpriv->ui_AiDataLength; } @@ -1047,14 +1059,16 @@ int i_APCI3120_CyclicAnalogInput(int mode, struct comedi_device * dev, devpriv->ui_DmaBufferUsesize[0] = dmalen0; devpriv->ui_DmaBufferUsesize[1] = dmalen1; - //Initialize DMA + /* Initialize DMA */ - // Set Transfer count enable bit and A2P_fifo reset bit in AGCSTS register - //1 +/* + * Set Transfer count enable bit and A2P_fifo reset bit in AGCSTS + * register 1 + */ ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO; outl(ui_Tmp, devpriv->i_IobaseAmcc + AMCC_OP_REG_AGCSTS); - // changed since 16 bit interface for add on + /* changed since 16 bit interface for add on */ /*********************/ /* ENABLE BUS MASTER */ /*********************/ @@ -1066,104 +1080,121 @@ int i_APCI3120_CyclicAnalogInput(int mode, struct comedi_device * dev, outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->i_IobaseAddon + 2); - // TO VERIFIED - //BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver +/* + * TO VERIFIED BEGIN JK 07.05.04: Comparison between WIN32 and Linux + * driver + */ outw(0x1000, devpriv->i_IobaseAddon + 2); - //END JK 07.05.04: Comparison between WIN32 and Linux driver + /* END JK 07.05.04: Comparison between WIN32 and Linux driver */ - //2 No change - // A2P FIFO MANAGEMENT - // A2P fifo reset & transfer control enable - /***********************/ + /* 2 No change */ /* A2P FIFO MANAGEMENT */ - /***********************/ + /* A2P fifo reset & transfer control enable */ + + /***********************/ + /* A2P FIFO MANAGEMENT */ + /***********************/ outl(APCI3120_A2P_FIFO_MANAGEMENT, devpriv->i_IobaseAmcc + APCI3120_AMCC_OP_MCSR); - //3 - //beginning address of dma buf - //The 32 bit address of dma buffer is converted into two 16 bit addresses - // Can done by using _attach and put into into an array - // array used may be for differnet pages +/* + * 3 + * beginning address of dma buf The 32 bit address of dma buffer + * is converted into two 16 bit addresses Can done by using _attach + * and put into into an array array used may be for differnet pages + */ - // DMA Start Adress Low + /* DMA Start Adress Low */ outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0); outw((devpriv->ul_DmaBufferHw[0] & 0xFFFF), devpriv->i_IobaseAddon + 2); - /*************************/ + /*************************/ /* DMA Start Adress High */ - /*************************/ + /*************************/ outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0); outw((devpriv->ul_DmaBufferHw[0] / 65536), devpriv->i_IobaseAddon + 2); - //4 - // amount of bytes to be transfered set transfer count - // used ADDON MWTC register - //commented testing outl(devpriv->ui_DmaBufferUsesize[0], devpriv->i_IobaseAddon+AMCC_OP_REG_AMWTC); +/* + * 4 + * amount of bytes to be transfered set transfer count used ADDON + * MWTC register commented testing + * outl(devpriv->ui_DmaBufferUsesize[0], + * devpriv->i_IobaseAddon+AMCC_OP_REG_AMWTC); + */ - /**************************/ + /**************************/ /* Nbr of acquisition LOW */ - /**************************/ + /**************************/ outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0); outw((devpriv->ui_DmaBufferUsesize[0] & 0xFFFF), devpriv->i_IobaseAddon + 2); - /***************************/ + /***************************/ /* Nbr of acquisition HIGH */ - /***************************/ + /***************************/ outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0); outw((devpriv->ui_DmaBufferUsesize[0] / 65536), devpriv->i_IobaseAddon + 2); - //5 - // To configure A2P FIFO - // testing outl( FIFO_ADVANCE_ON_BYTE_2,devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR); +/* + * 5 + * To configure A2P FIFO testing outl( + * FIFO_ADVANCE_ON_BYTE_2,devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR); + */ /******************/ /* A2P FIFO RESET */ /******************/ - // TO VERIFY - //BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver +/* + * TO VERIFY BEGIN JK 07.05.04: Comparison between WIN32 and Linux + * driver + */ outl(0x04000000UL, devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR); - //END JK 07.05.04: Comparison between WIN32 and Linux driver + /* END JK 07.05.04: Comparison between WIN32 and Linux driver */ - //6 - //ENABLE A2P FIFO WRITE AND ENABLE AMWEN - // AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03 - //BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver - //outw(3,devpriv->i_IobaseAddon + 4); - //END JK 07.05.04: Comparison between WIN32 and Linux driver +/* + * 6 + * ENABLE A2P FIFO WRITE AND ENABLE AMWEN AMWEN_ENABLE | + * A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03 + */ - //7 - //initialise end of dma interrupt AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI) + /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */ + /* outw(3,devpriv->i_IobaseAddon + 4); */ + /* END JK 07.05.04: Comparison between WIN32 and Linux driver */ + +/* + * 7 + * initialise end of dma interrupt AINT_WRITE_COMPL = + * ENABLE_WRITE_TC_INT(ADDI) + */ /***************************************************/ - /* A2P FIFO CONFIGURATE, END OF DMA INTERRUPT INIT */ + /* A2P FIFO CONFIGURATE, END OF DMA intERRUPT INIT */ /***************************************************/ outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 | APCI3120_ENABLE_WRITE_TC_INT), devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR); - //BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver + /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */ /******************************************/ /* ENABLE A2P FIFO WRITE AND ENABLE AMWEN */ /******************************************/ outw(3, devpriv->i_IobaseAddon + 4); - //END JK 07.05.04: Comparison between WIN32 and Linux driver + /* END JK 07.05.04: Comparison between WIN32 and Linux driver */ /******************/ /* A2P FIFO RESET */ /******************/ - //BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver + /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */ outl(0x04000000UL, devpriv->i_IobaseAmcc + APCI3120_AMCC_OP_MCSR); - //END JK 07.05.04: Comparison between WIN32 and Linux driver + /* END JK 07.05.04: Comparison between WIN32 and Linux driver */ } if ((devpriv->us_UseDma == APCI3120_DISABLE) && !devpriv->b_AiContinuous) { - // set gate 2 to start conversion + /* set gate 2 to start conversion */ devpriv->us_OutputRegister = devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER2; outw(devpriv->us_OutputRegister, @@ -1172,14 +1203,14 @@ int i_APCI3120_CyclicAnalogInput(int mode, struct comedi_device * dev, switch (mode) { case 1: - // set gate 0 to start conversion + /* set gate 0 to start conversion */ devpriv->us_OutputRegister = devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER0; outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS); break; case 2: - // set gate 0 and gate 1 + /* set gate 0 and gate 1 */ devpriv->us_OutputRegister = devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER1; devpriv->us_OutputRegister = @@ -1196,7 +1227,7 @@ int i_APCI3120_CyclicAnalogInput(int mode, struct comedi_device * dev, /* +----------------------------------------------------------------------------+ -| INTERNAL FUNCTIONS | +| intERNAL FUNCTIONS | +----------------------------------------------------------------------------+ */ @@ -1218,7 +1249,7 @@ int i_APCI3120_CyclicAnalogInput(int mode, struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -int i_APCI3120_Reset(struct comedi_device * dev) +int i_APCI3120_Reset(struct comedi_device *dev) { unsigned int i; unsigned short us_TmpValue; @@ -1226,47 +1257,49 @@ int i_APCI3120_Reset(struct comedi_device * dev) devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE; devpriv->b_EocEosInterrupt = APCI3120_DISABLE; devpriv->b_InterruptMode = APCI3120_EOC_MODE; - devpriv->ui_EocEosConversionTime = 0; // set eoc eos conv time to 0 + devpriv->ui_EocEosConversionTime = 0; /* set eoc eos conv time to 0 */ devpriv->b_OutputMemoryStatus = 0; - // variables used in timer subdevice + /* variables used in timer subdevice */ devpriv->b_Timer2Mode = 0; devpriv->b_Timer2Interrupt = 0; - devpriv->b_ExttrigEnable = 0; // Disable ext trigger + devpriv->b_ExttrigEnable = 0; /* Disable ext trigger */ /* Disable all interrupts, watchdog for the anolog output */ devpriv->b_ModeSelectRegister = 0; outb(devpriv->b_ModeSelectRegister, dev->iobase + APCI3120_WRITE_MODE_SELECT); - // Disables all counters, ext trigger and clears PA, PR + /* Disables all counters, ext trigger and clears PA, PR */ devpriv->us_OutputRegister = 0; outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS); - //Code to set the all anolog o/p channel to 0v - //8191 is decimal value for zero(0 v)volt in bipolar mode(default) - outw(8191 | APCI3120_ANALOG_OP_CHANNEL_1, dev->iobase + APCI3120_ANALOG_OUTPUT_1); //channel 1 - outw(8191 | APCI3120_ANALOG_OP_CHANNEL_2, dev->iobase + APCI3120_ANALOG_OUTPUT_1); //channel 2 - outw(8191 | APCI3120_ANALOG_OP_CHANNEL_3, dev->iobase + APCI3120_ANALOG_OUTPUT_1); //channel 3 - outw(8191 | APCI3120_ANALOG_OP_CHANNEL_4, dev->iobase + APCI3120_ANALOG_OUTPUT_1); //channel 4 +/* + * Code to set the all anolog o/p channel to 0v 8191 is decimal + * value for zero(0 v)volt in bipolar mode(default) + */ + outw(8191 | APCI3120_ANALOG_OP_CHANNEL_1, dev->iobase + APCI3120_ANALOG_OUTPUT_1); /* channel 1 */ + outw(8191 | APCI3120_ANALOG_OP_CHANNEL_2, dev->iobase + APCI3120_ANALOG_OUTPUT_1); /* channel 2 */ + outw(8191 | APCI3120_ANALOG_OP_CHANNEL_3, dev->iobase + APCI3120_ANALOG_OUTPUT_1); /* channel 3 */ + outw(8191 | APCI3120_ANALOG_OP_CHANNEL_4, dev->iobase + APCI3120_ANALOG_OUTPUT_1); /* channel 4 */ - outw(8191 | APCI3120_ANALOG_OP_CHANNEL_5, dev->iobase + APCI3120_ANALOG_OUTPUT_2); //channel 5 - outw(8191 | APCI3120_ANALOG_OP_CHANNEL_6, dev->iobase + APCI3120_ANALOG_OUTPUT_2); //channel 6 - outw(8191 | APCI3120_ANALOG_OP_CHANNEL_7, dev->iobase + APCI3120_ANALOG_OUTPUT_2); //channel 7 - outw(8191 | APCI3120_ANALOG_OP_CHANNEL_8, dev->iobase + APCI3120_ANALOG_OUTPUT_2); //channel 8 + outw(8191 | APCI3120_ANALOG_OP_CHANNEL_5, dev->iobase + APCI3120_ANALOG_OUTPUT_2); /* channel 5 */ + outw(8191 | APCI3120_ANALOG_OP_CHANNEL_6, dev->iobase + APCI3120_ANALOG_OUTPUT_2); /* channel 6 */ + outw(8191 | APCI3120_ANALOG_OP_CHANNEL_7, dev->iobase + APCI3120_ANALOG_OUTPUT_2); /* channel 7 */ + outw(8191 | APCI3120_ANALOG_OP_CHANNEL_8, dev->iobase + APCI3120_ANALOG_OUTPUT_2); /* channel 8 */ - // Reset digital output to L0W + /* Reset digital output to L0W */ -//ES05 outb(0x0,dev->iobase+APCI3120_DIGITAL_OUTPUT); +/* ES05 outb(0x0,dev->iobase+APCI3120_DIGITAL_OUTPUT); */ udelay(10); - inw(dev->iobase + 0); //make a dummy read - inb(dev->iobase + APCI3120_RESET_FIFO); // flush FIFO - inw(dev->iobase + APCI3120_RD_STATUS); // flush A/D status register + inw(dev->iobase + 0); /* make a dummy read */ + inb(dev->iobase + APCI3120_RESET_FIFO); /* flush FIFO */ + inw(dev->iobase + APCI3120_RD_STATUS); /* flush A/D status register */ - //code to reset the RAM sequence + /* code to reset the RAM sequence */ for (i = 0; i < 16; i++) { - us_TmpValue = i << 8; //select the location + us_TmpValue = i << 8; /* select the location */ outw(us_TmpValue, dev->iobase + APCI3120_SEQ_RAM_ADDRESS); } return 0; @@ -1296,10 +1329,10 @@ int i_APCI3120_Reset(struct comedi_device * dev) +----------------------------------------------------------------------------+ */ -int i_APCI3120_SetupChannelList(struct comedi_device * dev, struct comedi_subdevice * s, +int i_APCI3120_SetupChannelList(struct comedi_device *dev, struct comedi_subdevice *s, int n_chan, unsigned int *chanlist, char check) { - unsigned int i; //, differencial=0, bipolar=0; + unsigned int i; /* , differencial=0, bipolar=0; */ unsigned int gain; unsigned short us_TmpValue; @@ -1309,29 +1342,29 @@ int i_APCI3120_SetupChannelList(struct comedi_device * dev, struct comedi_subdev comedi_error(dev, "range/channel list is empty!"); return 0; } - // All is ok, so we can setup channel/range list + /* All is ok, so we can setup channel/range list */ if (check) return 1; - //Code to set the PA and PR...Here it set PA to 0.. + /* Code to set the PA and PR...Here it set PA to 0.. */ devpriv->us_OutputRegister = devpriv->us_OutputRegister & APCI3120_CLEAR_PA_PR; devpriv->us_OutputRegister = ((n_chan - 1) & 0xf) << 8; outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS); for (i = 0; i < n_chan; i++) { - // store range list to card - us_TmpValue = CR_CHAN(chanlist[i]); // get channel number; + /* store range list to card */ + us_TmpValue = CR_CHAN(chanlist[i]); /* get channel number; */ if (CR_RANGE(chanlist[i]) < APCI3120_BIPOLAR_RANGES) { - us_TmpValue &= ((~APCI3120_UNIPOLAR) & 0xff); // set bipolar + us_TmpValue &= ((~APCI3120_UNIPOLAR) & 0xff); /* set bipolar */ } else { - us_TmpValue |= APCI3120_UNIPOLAR; // enable unipolar...... + us_TmpValue |= APCI3120_UNIPOLAR; /* enable unipolar...... */ } - gain = CR_RANGE(chanlist[i]); // get gain number - us_TmpValue |= ((gain & 0x03) << 4); //<<4 for G0 and G1 bit in RAM - us_TmpValue |= i << 8; //To select the RAM LOCATION.... + gain = CR_RANGE(chanlist[i]); /* get gain number */ + us_TmpValue |= ((gain & 0x03) << 4); /* <<4 for G0 and G1 bit in RAM */ + us_TmpValue |= i << 8; /* To select the RAM LOCATION.... */ outw(us_TmpValue, dev->iobase + APCI3120_SEQ_RAM_ADDRESS); printk("\n Gain = %i", @@ -1339,7 +1372,7 @@ int i_APCI3120_SetupChannelList(struct comedi_device * dev, struct comedi_subdev printk("\n Channel = %i", CR_CHAN(chanlist[i])); printk("\n Polarity = %i", us_TmpValue & APCI3120_UNIPOLAR); } - return 1; // we can serve this with scan logic + return 1; /* we can serve this with scan logic */ } /* @@ -1360,7 +1393,7 @@ int i_APCI3120_SetupChannelList(struct comedi_device * dev, struct comedi_subdev +----------------------------------------------------------------------------+ */ -int i_APCI3120_ExttrigEnable(struct comedi_device * dev) +int i_APCI3120_ExttrigEnable(struct comedi_device *dev) { devpriv->us_OutputRegister |= APCI3120_ENABLE_EXT_TRIGGER; @@ -1385,7 +1418,7 @@ int i_APCI3120_ExttrigEnable(struct comedi_device * dev) +----------------------------------------------------------------------------+ */ -int i_APCI3120_ExttrigDisable(struct comedi_device * dev) +int i_APCI3120_ExttrigDisable(struct comedi_device *dev) { devpriv->us_OutputRegister &= ~APCI3120_ENABLE_EXT_TRIGGER; outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS); @@ -1394,7 +1427,7 @@ int i_APCI3120_ExttrigDisable(struct comedi_device * dev) /* +----------------------------------------------------------------------------+ -| INTERRUPT FUNCTIONS | +| intERRUPT FUNCTIONS | +----------------------------------------------------------------------------+ */ @@ -1422,33 +1455,33 @@ int i_APCI3120_ExttrigDisable(struct comedi_device * dev) void v_APCI3120_Interrupt(int irq, void *d) { struct comedi_device *dev = d; - USHORT int_daq; + unsigned short int_daq; unsigned int int_amcc, ui_Check, i; - USHORT us_TmpValue; - BYTE b_DummyRead; + unsigned short us_TmpValue; + unsigned char b_DummyRead; struct comedi_subdevice *s = dev->subdevices + 0; ui_Check = 1; - int_daq = inw(dev->iobase + APCI3120_RD_STATUS) & 0xf000; // get IRQ reasons - int_amcc = inl(devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR); // get AMCC INT register + int_daq = inw(dev->iobase + APCI3120_RD_STATUS) & 0xf000; /* get IRQ reasons */ + int_amcc = inl(devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR); /* get AMCC int register */ if ((!int_daq) && (!(int_amcc & ANY_S593X_INT))) { comedi_error(dev, "IRQ from unknow source"); return; } - outl(int_amcc | 0x00ff0000, devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR); // shutdown IRQ reasons in AMCC + outl(int_amcc | 0x00ff0000, devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR); /* shutdown IRQ reasons in AMCC */ int_daq = (int_daq >> 12) & 0xF; if (devpriv->b_ExttrigEnable == APCI3120_ENABLE) { - //Disable ext trigger + /* Disable ext trigger */ i_APCI3120_ExttrigDisable(dev); devpriv->b_ExttrigEnable = APCI3120_DISABLE; } - //clear the timer 2 interrupt + /* clear the timer 2 interrupt */ inb(devpriv->i_IobaseAmcc + APCI3120_TIMER_STATUS_REGISTER); if (int_amcc & MASTER_ABORT_INT) @@ -1456,19 +1489,19 @@ void v_APCI3120_Interrupt(int irq, void *d) if (int_amcc & TARGET_ABORT_INT) comedi_error(dev, "AMCC IRQ - TARGET DMA ABORT!"); - // Ckeck if EOC interrupt + /* Ckeck if EOC interrupt */ if (((int_daq & 0x8) == 0) && (devpriv->b_InterruptMode == APCI3120_EOC_MODE)) { if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) { - // Read the AI Value + /* Read the AI Value */ devpriv->ui_AiReadData[0] = - (UINT) inw(devpriv->iobase + 0); + (unsigned int) inw(devpriv->iobase + 0); devpriv->b_EocEosInterrupt = APCI3120_DISABLE; - send_sig(SIGIO, devpriv->tsk_Current, 0); // send signal to the sample + send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */ } else { - //Disable EOC Interrupt + /* Disable EOC Interrupt */ devpriv->b_ModeSelectRegister = devpriv-> b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT; @@ -1478,10 +1511,10 @@ void v_APCI3120_Interrupt(int irq, void *d) } } - // Check If EOS interrupt + /* Check If EOS interrupt */ if ((int_daq & 0x2) && (devpriv->b_InterruptMode == APCI3120_EOS_MODE)) { - if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) // enable this in without DMA ??? + if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) /* enable this in without DMA ??? */ { if (devpriv->b_AiCyclicAcquisition == APCI3120_ENABLE) { @@ -1501,12 +1534,12 @@ void v_APCI3120_Interrupt(int irq, void *d) i++) { us_TmpValue = inw(devpriv->iobase + 0); devpriv->ui_AiReadData[i] = - (UINT) us_TmpValue; + (unsigned int) us_TmpValue; } devpriv->b_EocEosInterrupt = APCI3120_DISABLE; devpriv->b_InterruptMode = APCI3120_EOC_MODE; - send_sig(SIGIO, devpriv->tsk_Current, 0); // send signal to the sample + send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */ } @@ -1516,12 +1549,12 @@ void v_APCI3120_Interrupt(int irq, void *d) b_ModeSelectRegister & APCI3120_DISABLE_EOS_INT; outb(devpriv->b_ModeSelectRegister, dev->iobase + APCI3120_WRITE_MODE_SELECT); - devpriv->b_EocEosInterrupt = APCI3120_DISABLE; //Default settings + devpriv->b_EocEosInterrupt = APCI3120_DISABLE; /* Default settings */ devpriv->b_InterruptMode = APCI3120_EOC_MODE; } } - //Timer2 interrupt + /* Timer2 interrupt */ if (int_daq & 0x1) { switch (devpriv->b_Timer2Mode) { @@ -1534,18 +1567,18 @@ void v_APCI3120_Interrupt(int irq, void *d) outb(devpriv->b_ModeSelectRegister, dev->iobase + APCI3120_WRITE_MODE_SELECT); - // stop timer 2 + /* stop timer 2 */ devpriv->us_OutputRegister = devpriv-> us_OutputRegister & APCI3120_DISABLE_ALL_TIMER; outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS); - //stop timer 0 and timer 1 + /* stop timer 0 and timer 1 */ i_APCI3120_StopCyclicAcquisition(dev, s); devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE; - //UPDATE-0.7.57->0.7.68comedi_done(dev,s); + /* UPDATE-0.7.57->0.7.68comedi_done(dev,s); */ s->async->events |= COMEDI_CB_EOA; comedi_event(dev, s); @@ -1553,19 +1586,19 @@ void v_APCI3120_Interrupt(int irq, void *d) case APCI3120_TIMER: - //Send a signal to from kernel to user space + /* Send a signal to from kernel to user space */ send_sig(SIGIO, devpriv->tsk_Current, 0); break; case APCI3120_WATCHDOG: - //Send a signal to from kernel to user space + /* Send a signal to from kernel to user space */ send_sig(SIGIO, devpriv->tsk_Current, 0); break; default: - // disable Timer Interrupt + /* disable Timer Interrupt */ devpriv->b_ModeSelectRegister = devpriv-> @@ -1585,7 +1618,7 @@ void v_APCI3120_Interrupt(int irq, void *d) if (devpriv->b_AiCyclicAcquisition == APCI3120_ENABLE) { /****************************/ - /* Clear Timer Write TC INT */ + /* Clear Timer Write TC int */ /****************************/ outl(APCI3120_CLEAR_WRITE_TC_INT, @@ -1596,7 +1629,7 @@ void v_APCI3120_Interrupt(int irq, void *d) /* Clears the timer status register */ /************************************/ inw(dev->iobase + APCI3120_TIMER_STATUS_REGISTER); - v_APCI3120_InterruptDma(irq, d); // do some data transfer + v_APCI3120_InterruptDma(irq, d); /* do some data transfer */ } else { /* Stops the Timer */ outw(devpriv-> @@ -1630,32 +1663,8 @@ void v_APCI3120_Interrupt(int irq, void *d) +----------------------------------------------------------------------------+ */ -/* - * int i_APCI3120_InterruptHandleEos(struct comedi_device *dev) -{ - int n_chan,i; - short *data; - struct comedi_subdevice *s=dev->subdevices+0; - struct comedi_async *async = s->async; - data=async->data+async->buf_int_ptr; - n_chan=devpriv->ui_AiNbrofChannels; - for(i=0;iiobase+0); - } - async->buf_int_count+=n_chan*sizeof(short); - async->buf_int_ptr+=n_chan*sizeof(short); - comedi_eos(dev,s); - if (s->async->buf_int_ptr>=s->async->data_len) // for buffer rool over - { -*//* buffer rollover */ -/* s->async->buf_int_ptr=0; - comedi_eobuf(dev,s); - } - return 0; -}*/ -int i_APCI3120_InterruptHandleEos(struct comedi_device * dev) +int i_APCI3120_InterruptHandleEos(struct comedi_device *dev) { int n_chan, i; struct comedi_subdevice *s = dev->subdevices + 0; @@ -1704,7 +1713,7 @@ void v_APCI3120_InterruptDma(int irq, void *d) unsigned int next_dma_buf, samplesinbuf; unsigned long low_word, high_word, var; - UINT ui_Tmp; + unsigned int ui_Tmp; samplesinbuf = devpriv->ui_DmaBufferUsesize[devpriv->ui_DmaActualBuffer] - inl(devpriv->i_IobaseAmcc + AMCC_OP_REG_MWTC); @@ -1720,20 +1729,20 @@ void v_APCI3120_InterruptDma(int irq, void *d) return; } - samplesinbuf = samplesinbuf >> 1; // number of received samples + samplesinbuf = samplesinbuf >> 1; /* number of received samples */ if (devpriv->b_DmaDoubleBuffer) { - // switch DMA buffers if is used double buffering + /* switch DMA buffers if is used double buffering */ next_dma_buf = 1 - devpriv->ui_DmaActualBuffer; ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO; outl(ui_Tmp, devpriv->i_IobaseAddon + AMCC_OP_REG_AGCSTS); - // changed since 16 bit interface for add on + /* changed since 16 bit interface for add on */ outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0); outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW, devpriv->i_IobaseAddon + 2); outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0); - outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->i_IobaseAddon + 2); // 0x1000 is out putted in windows driver + outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->i_IobaseAddon + 2); /* 0x1000 is out putted in windows driver */ var = devpriv->ul_DmaBufferHw[next_dma_buf]; low_word = var & 0xffff; @@ -1761,54 +1770,18 @@ void v_APCI3120_InterruptDma(int irq, void *d) outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0); outw(high_word, devpriv->i_IobaseAddon + 2); - // To configure A2P FIFO - // ENABLE A2P FIFO WRITE AND ENABLE AMWEN - // AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03 +/* + * To configure A2P FIFO + * ENABLE A2P FIFO WRITE AND ENABLE AMWEN + * AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03 + */ outw(3, devpriv->i_IobaseAddon + 4); - //initialise end of dma interrupt AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI) + /* initialise end of dma interrupt AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI) */ outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 | APCI3120_ENABLE_WRITE_TC_INT), devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR); } -/*UPDATE-0.7.57->0.7.68 - ptr=(short *)devpriv->ul_DmaBufferVirtual[devpriv->ui_DmaActualBuffer]; - - - // if there is not enough space left in the buffer to copy all data contained in the DMABufferVirtual - if(s->async->buf_int_ptr+samplesinbuf*sizeof(short)>=devpriv->ui_AiDataLength) - { - m=(devpriv->ui_AiDataLength-s->async->buf_int_ptr)/sizeof(short); - v_APCI3120_InterruptDmaMoveBlock16bit(dev,s,(void *)ptr,((void *)(devpriv->AiData))+s->async->buf_int_ptr,m); - s->async->buf_int_count+=m*sizeof(short); - ptr+=m*sizeof(short); - samplesinbuf-=m; - s->async->buf_int_ptr=0; - comedi_eobuf(dev,s); - } - - if (samplesinbuf) - { - v_APCI3120_InterruptDmaMoveBlock16bit(dev,s,(void *)ptr,((void *)(devpriv->AiData))+s->async->buf_int_ptr,samplesinbuf); - - s->async->buf_int_count+=samplesinbuf*sizeof(short); - s->async->buf_int_ptr+=samplesinbuf*sizeof(short); - if (!(devpriv->ui_AiFlags & TRIG_WAKE_EOS)) - { - comedi_bufcheck(dev,s); - } - } - if (!devpriv->b_AiContinuous) - if ( devpriv->ui_AiActualScan>=devpriv->ui_AiNbrofScans ) - { - // all data sampled - i_APCI3120_StopCyclicAcquisition(dev,s); - devpriv->b_AiCyclicAcquisition=APCI3120_DISABLE; - //DPRINTK("\n Single DMA completed..\n"); - comedi_done(dev,s); - return; - } -*/ if (samplesinbuf) { v_APCI3120_InterruptDmaMoveBlock16bit(dev, s, devpriv->ul_DmaBufferVirtual[devpriv-> @@ -1821,7 +1794,7 @@ void v_APCI3120_InterruptDma(int irq, void *d) } if (!devpriv->b_AiContinuous) if (devpriv->ui_AiActualScan >= devpriv->ui_AiNbrofScans) { - // all data sampled + /* all data sampled */ i_APCI3120_StopCyclicAcquisition(dev, s); devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE; s->async->events |= COMEDI_CB_EOA; @@ -1829,22 +1802,26 @@ void v_APCI3120_InterruptDma(int irq, void *d) return; } - if (devpriv->b_DmaDoubleBuffer) { // switch dma buffers + if (devpriv->b_DmaDoubleBuffer) { /* switch dma buffers */ devpriv->ui_DmaActualBuffer = 1 - devpriv->ui_DmaActualBuffer; } else { - // restart DMA if is not used double buffering - //ADDED REINITIALISE THE DMA +/* + * restart DMA if is not used double buffering + * ADDED REINITIALISE THE DMA + */ ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO; outl(ui_Tmp, devpriv->i_IobaseAddon + AMCC_OP_REG_AGCSTS); - // changed since 16 bit interface for add on + /* changed since 16 bit interface for add on */ outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0); outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW, devpriv->i_IobaseAddon + 2); outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0); - outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->i_IobaseAddon + 2); // - // A2P FIFO MANAGEMENT - // A2P fifo reset & transfer control enable + outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->i_IobaseAddon + 2); /* */ +/* + * A2P FIFO MANAGEMENT + * A2P fifo reset & transfer control enable + */ outl(APCI3120_A2P_FIFO_MANAGEMENT, devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR); @@ -1858,7 +1835,7 @@ void v_APCI3120_InterruptDma(int irq, void *d) outw(high_word, devpriv->i_IobaseAddon + 2); var = devpriv->ui_DmaBufferUsesize[0]; - low_word = var & 0xffff; //changed + low_word = var & 0xffff; /* changed */ var = devpriv->ui_DmaBufferUsesize[0]; high_word = var / 65536; outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0); @@ -1866,11 +1843,13 @@ void v_APCI3120_InterruptDma(int irq, void *d) outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0); outw(high_word, devpriv->i_IobaseAddon + 2); - // To configure A2P FIFO - //ENABLE A2P FIFO WRITE AND ENABLE AMWEN - // AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03 +/* + * To configure A2P FIFO + * ENABLE A2P FIFO WRITE AND ENABLE AMWEN + * AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03 + */ outw(3, devpriv->i_IobaseAddon + 4); - //initialise end of dma interrupt AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI) + /* initialise end of dma interrupt AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI) */ outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 | APCI3120_ENABLE_WRITE_TC_INT), devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR); @@ -1897,37 +1876,8 @@ void v_APCI3120_InterruptDma(int irq, void *d) +----------------------------------------------------------------------------+ */ -/*void v_APCI3120_InterruptDmaMoveBlock16bit(struct comedi_device *dev,struct comedi_subdevice *s,short *dma,short *data,int n) -{ - int i,j,m; - - j=s->async->cur_chan; - m=devpriv->ui_AiActualScanPosition; - for(i=0;i=devpriv->ui_AiNbrofChannels) - { - m+=j; - j=0; - if(m>=devpriv->ui_AiScanLength) - { - m=0; - devpriv->ui_AiActualScan++; - if (devpriv->ui_AiFlags & TRIG_WAKE_EOS) -;//UPDATE-0.7.57->0.7.68 comedi_eos(dev,s); - } - } - } - devpriv->ui_AiActualScanPosition=m; - s->async->cur_chan=j; - -} -*/ -void v_APCI3120_InterruptDmaMoveBlock16bit(struct comedi_device * dev, - struct comedi_subdevice * s, short * dma_buffer, unsigned int num_samples) +void v_APCI3120_InterruptDmaMoveBlock16bit(struct comedi_device *dev, + struct comedi_subdevice *s, short *dma_buffer, unsigned int num_samples) { devpriv->ui_AiActualScan += (s->async->cur_chan + num_samples) / devpriv->ui_AiScanLength; @@ -1968,71 +1918,77 @@ void v_APCI3120_InterruptDmaMoveBlock16bit(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -int i_APCI3120_InsnConfigTimer(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI3120_InsnConfigTimer(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - UINT ui_Timervalue2; - USHORT us_TmpValue; - BYTE b_Tmp; + unsigned int ui_Timervalue2; + unsigned short us_TmpValue; + unsigned char b_Tmp; if (!data[1]) comedi_error(dev, "config:No timer constant !"); - devpriv->b_Timer2Interrupt = (BYTE) data[2]; // save info whether to enable or disable interrupt + devpriv->b_Timer2Interrupt = (unsigned char) data[2]; /* save info whether to enable or disable interrupt */ - ui_Timervalue2 = data[1] / 1000; // convert nano seconds to u seconds + ui_Timervalue2 = data[1] / 1000; /* convert nano seconds to u seconds */ - //this_board->i_hwdrv_InsnConfigTimer(dev, ui_Timervalue2,(BYTE)data[0]); - us_TmpValue = (USHORT) inw(devpriv->iobase + APCI3120_RD_STATUS); + /* this_board->i_hwdrv_InsnConfigTimer(dev, ui_Timervalue2,(unsigned char)data[0]); */ + us_TmpValue = (unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS); - //EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001 - // and calculate the time value to set in the timer +/* + * EL250804: Testing if board APCI3120 have the new Quartz or if it + * is an APCI3001 and calculate the time value to set in the timer + */ if ((us_TmpValue & 0x00B0) == 0x00B0 || !strcmp(this_board->pc_DriverName, "apci3001")) { - //Calculate the time value to set in the timer + /* Calculate the time value to set in the timer */ ui_Timervalue2 = ui_Timervalue2 / 50; } else { - //Calculate the time value to set in the timer + /* Calculate the time value to set in the timer */ ui_Timervalue2 = ui_Timervalue2 / 70; } - //Reset gate 2 of Timer 2 to disable it (Set Bit D14 to 0) + /* Reset gate 2 of Timer 2 to disable it (Set Bit D14 to 0) */ devpriv->us_OutputRegister = devpriv->us_OutputRegister & APCI3120_DISABLE_TIMER2; outw(devpriv->us_OutputRegister, devpriv->iobase + APCI3120_WR_ADDRESS); - // Disable TIMER Interrupt + /* Disable TIMER Interrupt */ devpriv->b_ModeSelectRegister = devpriv-> b_ModeSelectRegister & APCI3120_DISABLE_TIMER_INT & 0xEF; - // Disable Eoc and Eos Interrupts + /* Disable Eoc and Eos Interrupts */ devpriv->b_ModeSelectRegister = devpriv-> b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT & APCI3120_DISABLE_EOS_INT; outb(devpriv->b_ModeSelectRegister, devpriv->iobase + APCI3120_WRITE_MODE_SELECT); - if (data[0] == APCI3120_TIMER) //initialize timer + if (data[0] == APCI3120_TIMER) /* initialize timer */ { + /* devpriv->b_ModeSelectRegister=devpriv->b_ModeSelectRegister | + * APCI3120_ENABLE_TIMER_INT; */ - //devpriv->b_ModeSelectRegister=devpriv->b_ModeSelectRegister| APCI3120_ENABLE_TIMER_INT ; - //outb(devpriv->b_ModeSelectRegister,devpriv->iobase+APCI3120_WRITE_MODE_SELECT); + /* outb(devpriv->b_ModeSelectRegister,devpriv->iobase+APCI3120_WRITE_MODE_SELECT); */ - //Set the Timer 2 in mode 2(Timer) + /* Set the Timer 2 in mode 2(Timer) */ devpriv->b_TimerSelectMode = (devpriv-> b_TimerSelectMode & 0x0F) | APCI3120_TIMER_2_MODE_2; outb(devpriv->b_TimerSelectMode, devpriv->iobase + APCI3120_TIMER_CRT1); - //Configure the timer 2 for writing the LOW WORD of timer is Delay value - //You must make a b_tmp variable with DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0 - //you can set the digital output and configure the timer 2,and if you don't make this, digital output - //are erase (Set to 0) +/* + * Configure the timer 2 for writing the LOW unsigned short of timer + * is Delay value You must make a b_tmp variable with + * DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0 + * you can set the digital output and configure the timer 2,and if + * you don't make this, digital output are erase (Set to 0) + */ - //Writing LOW WORD + /* Writing LOW unsigned short */ b_Tmp = ((devpriv-> b_DigitalOutputRegister) & 0xF0) | APCI3120_SELECT_TIMER_2_LOW_WORD; @@ -2040,20 +1996,20 @@ int i_APCI3120_InsnConfigTimer(struct comedi_device * dev, struct comedi_subdevi outw(LOWORD(ui_Timervalue2), devpriv->iobase + APCI3120_TIMER_VALUE); - //Writing HIGH WORD + /* Writing HIGH unsigned short */ b_Tmp = ((devpriv-> b_DigitalOutputRegister) & 0xF0) | APCI3120_SELECT_TIMER_2_HIGH_WORD; outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0); outw(HIWORD(ui_Timervalue2), devpriv->iobase + APCI3120_TIMER_VALUE); - // timer2 in Timer mode enabled + /* timer2 in Timer mode enabled */ devpriv->b_Timer2Mode = APCI3120_TIMER; - } else // Initialize Watch dog + } else /* Initialize Watch dog */ { - //Set the Timer 2 in mode 5(Watchdog) + /* Set the Timer 2 in mode 5(Watchdog) */ devpriv->b_TimerSelectMode = (devpriv-> @@ -2061,12 +2017,15 @@ int i_APCI3120_InsnConfigTimer(struct comedi_device * dev, struct comedi_subdevi outb(devpriv->b_TimerSelectMode, devpriv->iobase + APCI3120_TIMER_CRT1); - //Configure the timer 2 for writing the LOW WORD of timer is Delay value - //You must make a b_tmp variable with DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0 - //you can set the digital output and configure the timer 2,and if you don't make this, digital output - //are erase (Set to 0) +/* + * Configure the timer 2 for writing the LOW unsigned short of timer + * is Delay value You must make a b_tmp variable with + * DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0 + * you can set the digital output and configure the timer 2,and if + * you don't make this, digital output are erase (Set to 0) + */ - //Writing LOW WORD + /* Writing LOW unsigned short */ b_Tmp = ((devpriv-> b_DigitalOutputRegister) & 0xF0) | APCI3120_SELECT_TIMER_2_LOW_WORD; @@ -2074,7 +2033,7 @@ int i_APCI3120_InsnConfigTimer(struct comedi_device * dev, struct comedi_subdevi outw(LOWORD(ui_Timervalue2), devpriv->iobase + APCI3120_TIMER_VALUE); - //Writing HIGH WORD + /* Writing HIGH unsigned short */ b_Tmp = ((devpriv-> b_DigitalOutputRegister) & 0xF0) | APCI3120_SELECT_TIMER_2_HIGH_WORD; @@ -2082,7 +2041,7 @@ int i_APCI3120_InsnConfigTimer(struct comedi_device * dev, struct comedi_subdevi outw(HIWORD(ui_Timervalue2), devpriv->iobase + APCI3120_TIMER_VALUE); - //watchdog enabled + /* watchdog enabled */ devpriv->b_Timer2Mode = APCI3120_WATCHDOG; } @@ -2119,13 +2078,13 @@ int i_APCI3120_InsnConfigTimer(struct comedi_device * dev, struct comedi_subdevi +----------------------------------------------------------------------------+ */ -int i_APCI3120_InsnWriteTimer(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI3120_InsnWriteTimer(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - UINT ui_Timervalue2 = 0; - USHORT us_TmpValue; - BYTE b_Tmp; + unsigned int ui_Timervalue2 = 0; + unsigned short us_TmpValue; + unsigned char b_Tmp; if ((devpriv->b_Timer2Mode != APCI3120_WATCHDOG) && (devpriv->b_Timer2Mode != APCI3120_TIMER)) { @@ -2133,7 +2092,7 @@ int i_APCI3120_InsnWriteTimer(struct comedi_device * dev, struct comedi_subdevic return -EINVAL; } - if (data[0] == 2) // write new value + if (data[0] == 2) /* write new value */ { if (devpriv->b_Timer2Mode != APCI3120_TIMER) { comedi_error(dev, @@ -2147,35 +2106,35 @@ int i_APCI3120_InsnWriteTimer(struct comedi_device * dev, struct comedi_subdevic ui_Timervalue2 = 0; } - //this_board->i_hwdrv_InsnWriteTimer(dev,data[0],ui_Timervalue2); + /* this_board->i_hwdrv_InsnWriteTimer(dev,data[0],ui_Timervalue2); */ switch (data[0]) { case APCI3120_START: - // Reset FC_TIMER BIT + /* Reset FC_TIMER BIT */ inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER); - if (devpriv->b_Timer2Mode == APCI3120_TIMER) //start timer + if (devpriv->b_Timer2Mode == APCI3120_TIMER) /* start timer */ { - //Enable Timer + /* Enable Timer */ devpriv->b_ModeSelectRegister = devpriv->b_ModeSelectRegister & 0x0B; - } else //start watch dog + } else /* start watch dog */ { - //Enable WatchDog + /* Enable WatchDog */ devpriv->b_ModeSelectRegister = (devpriv-> b_ModeSelectRegister & 0x0B) | APCI3120_ENABLE_WATCHDOG; } - //enable disable interrupt + /* enable disable interrupt */ if ((devpriv->b_Timer2Interrupt) == APCI3120_ENABLE) { devpriv->b_ModeSelectRegister = devpriv-> b_ModeSelectRegister | APCI3120_ENABLE_TIMER_INT; - // save the task structure to pass info to user + /* save the task structure to pass info to user */ devpriv->tsk_Current = current; } else { @@ -2187,9 +2146,9 @@ int i_APCI3120_InsnWriteTimer(struct comedi_device * dev, struct comedi_subdevic outb(devpriv->b_ModeSelectRegister, devpriv->iobase + APCI3120_WRITE_MODE_SELECT); - if (devpriv->b_Timer2Mode == APCI3120_TIMER) //start timer + if (devpriv->b_Timer2Mode == APCI3120_TIMER) /* start timer */ { - //For Timer mode is Gate2 must be activated **timer started + /* For Timer mode is Gate2 must be activated **timer started */ devpriv->us_OutputRegister = devpriv-> us_OutputRegister | APCI3120_ENABLE_TIMER2; @@ -2201,62 +2160,64 @@ int i_APCI3120_InsnWriteTimer(struct comedi_device * dev, struct comedi_subdevic case APCI3120_STOP: if (devpriv->b_Timer2Mode == APCI3120_TIMER) { - //Disable timer + /* Disable timer */ devpriv->b_ModeSelectRegister = devpriv-> b_ModeSelectRegister & APCI3120_DISABLE_TIMER_COUNTER; } else { - //Disable WatchDog + /* Disable WatchDog */ devpriv->b_ModeSelectRegister = devpriv-> b_ModeSelectRegister & APCI3120_DISABLE_WATCHDOG; } - // Disable timer interrupt + /* Disable timer interrupt */ devpriv->b_ModeSelectRegister = devpriv-> b_ModeSelectRegister & APCI3120_DISABLE_TIMER_INT; - // Write above states to register + /* Write above states to register */ outb(devpriv->b_ModeSelectRegister, devpriv->iobase + APCI3120_WRITE_MODE_SELECT); - // Reset Gate 2 + /* Reset Gate 2 */ devpriv->us_OutputRegister = devpriv->us_OutputRegister & APCI3120_DISABLE_TIMER_INT; outw(devpriv->us_OutputRegister, devpriv->iobase + APCI3120_WR_ADDRESS); - // Reset FC_TIMER BIT + /* Reset FC_TIMER BIT */ inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER); - // Disable timer - //devpriv->b_Timer2Mode=APCI3120_DISABLE; + /* Disable timer */ + /* devpriv->b_Timer2Mode=APCI3120_DISABLE; */ break; - case 2: //write new value to Timer + case 2: /* write new value to Timer */ if (devpriv->b_Timer2Mode != APCI3120_TIMER) { comedi_error(dev, "write :timer2 not configured in TIMER MODE"); return -EINVAL; } - // ui_Timervalue2=data[1]; // passed as argument + /* ui_Timervalue2=data[1]; // passed as argument */ us_TmpValue = - (USHORT) inw(devpriv->iobase + APCI3120_RD_STATUS); + (unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS); - //EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001 - // and calculate the time value to set in the timer +/* + * EL250804: Testing if board APCI3120 have the new Quartz or if it + * is an APCI3001 and calculate the time value to set in the timer + */ if ((us_TmpValue & 0x00B0) == 0x00B0 || !strcmp(this_board->pc_DriverName, "apci3001")) { - //Calculate the time value to set in the timer + /* Calculate the time value to set in the timer */ ui_Timervalue2 = ui_Timervalue2 / 50; } else { - //Calculate the time value to set in the timer + /* Calculate the time value to set in the timer */ ui_Timervalue2 = ui_Timervalue2 / 70; } - //Writing LOW WORD + /* Writing LOW unsigned short */ b_Tmp = ((devpriv-> b_DigitalOutputRegister) & 0xF0) | APCI3120_SELECT_TIMER_2_LOW_WORD; @@ -2265,7 +2226,7 @@ int i_APCI3120_InsnWriteTimer(struct comedi_device * dev, struct comedi_subdevic outw(LOWORD(ui_Timervalue2), devpriv->iobase + APCI3120_TIMER_VALUE); - //Writing HIGH WORD + /* Writing HIGH unsigned short */ b_Tmp = ((devpriv-> b_DigitalOutputRegister) & 0xF0) | APCI3120_SELECT_TIMER_2_HIGH_WORD; @@ -2276,7 +2237,7 @@ int i_APCI3120_InsnWriteTimer(struct comedi_device * dev, struct comedi_subdevic break; default: - return -EINVAL; // Not a valid input + return -EINVAL; /* Not a valid input */ } return insn->n; @@ -2305,21 +2266,21 @@ int i_APCI3120_InsnWriteTimer(struct comedi_device * dev, struct comedi_subdevic | | +----------------------------------------------------------------------------+ */ -int i_APCI3120_InsnReadTimer(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI3120_InsnReadTimer(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - BYTE b_Tmp; - USHORT us_TmpValue, us_TmpValue_2, us_StatusValue; + unsigned char b_Tmp; + unsigned short us_TmpValue, us_TmpValue_2, us_StatusValue; if ((devpriv->b_Timer2Mode != APCI3120_WATCHDOG) && (devpriv->b_Timer2Mode != APCI3120_TIMER)) { comedi_error(dev, "\nread:timer2 not configured "); } - //this_board->i_hwdrv_InsnReadTimer(dev,data); + /* this_board->i_hwdrv_InsnReadTimer(dev,data); */ if (devpriv->b_Timer2Mode == APCI3120_TIMER) { - //Read the LOW WORD of Timer 2 register + /* Read the LOW unsigned short of Timer 2 register */ b_Tmp = ((devpriv-> b_DigitalOutputRegister) & 0xF0) | APCI3120_SELECT_TIMER_2_LOW_WORD; @@ -2327,7 +2288,7 @@ int i_APCI3120_InsnReadTimer(struct comedi_device * dev, struct comedi_subdevice us_TmpValue = inw(devpriv->iobase + APCI3120_TIMER_VALUE); - //Read the HIGH WORD of Timer 2 register + /* Read the HIGH unsigned short of Timer 2 register */ b_Tmp = ((devpriv-> b_DigitalOutputRegister) & 0xF0) | APCI3120_SELECT_TIMER_2_HIGH_WORD; @@ -2335,20 +2296,20 @@ int i_APCI3120_InsnReadTimer(struct comedi_device * dev, struct comedi_subdevice us_TmpValue_2 = inw(devpriv->iobase + APCI3120_TIMER_VALUE); - // combining both words - data[0] = (UINT) ((us_TmpValue) | ((us_TmpValue_2) << 16)); + /* combining both words */ + data[0] = (unsigned int) ((us_TmpValue) | ((us_TmpValue_2) << 16)); - } else // Read watch dog status + } else /* Read watch dog status */ { us_StatusValue = inw(devpriv->iobase + APCI3120_RD_STATUS); us_StatusValue = ((us_StatusValue & APCI3120_FC_TIMER) >> 12) & 1; if (us_StatusValue == 1) { - // RESET FC_TIMER BIT + /* RESET FC_TIMER BIT */ inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER); } - data[0] = us_StatusValue; // when data[0] = 1 then the watch dog has rundown + data[0] = us_StatusValue; /* when data[0] = 1 then the watch dog has rundown */ } return insn->n; } @@ -2384,21 +2345,23 @@ int i_APCI3120_InsnReadDigitalInput(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - UINT ui_Chan, ui_TmpValue; + unsigned int ui_Chan, ui_TmpValue; - ui_Chan = CR_CHAN(insn->chanspec); // channel specified + ui_Chan = CR_CHAN(insn->chanspec); /* channel specified */ - //this_board->i_hwdrv_InsnReadDigitalInput(dev,ui_Chan,data); + /* this_board->i_hwdrv_InsnReadDigitalInput(dev,ui_Chan,data); */ if (ui_Chan >= 0 && ui_Chan <= 3) { - ui_TmpValue = (UINT) inw(devpriv->iobase + APCI3120_RD_STATUS); + ui_TmpValue = (unsigned int) inw(devpriv->iobase + APCI3120_RD_STATUS); - // since only 1 channel reqd to bring it to last bit it is rotated - // 8 +(chan - 1) times then ANDed with 1 for last bit. +/* + * since only 1 channel reqd to bring it to last bit it is rotated 8 + * +(chan - 1) times then ANDed with 1 for last bit. + */ *data = (ui_TmpValue >> (ui_Chan + 8)) & 1; - //return 0; + /* return 0; */ } else { - // comedi_error(dev," chan spec wrong"); - return -EINVAL; // "sorry channel spec wrong " + /* comedi_error(dev," chan spec wrong"); */ + return -EINVAL; /* "sorry channel spec wrong " */ } return insn->n; @@ -2423,18 +2386,18 @@ int i_APCI3120_InsnReadDigitalInput(struct comedi_device *dev, | | +----------------------------------------------------------------------------+ */ -int i_APCI3120_InsnBitsDigitalInput(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI3120_InsnBitsDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - UINT ui_TmpValue; - ui_TmpValue = (UINT) inw(devpriv->iobase + APCI3120_RD_STATUS); + unsigned int ui_TmpValue; + ui_TmpValue = (unsigned int) inw(devpriv->iobase + APCI3120_RD_STATUS); /***** state of 4 channels in the 11, 10, 9, 8 bits of status reg rotated right 8 times to bring them to last four bits ANDed with oxf for value. *****/ *data = (ui_TmpValue >> 8) & 0xf; - //this_board->i_hwdrv_InsnBitsDigitalInput(dev,data); + /* this_board->i_hwdrv_InsnBitsDigitalInput(dev,data); */ return insn->n; } @@ -2462,8 +2425,8 @@ int i_APCI3120_InsnBitsDigitalInput(struct comedi_device * dev, struct comedi_su +----------------------------------------------------------------------------+ */ -int i_APCI3120_InsnConfigDigitalOutput(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +int i_APCI3120_InsnConfigDigitalOutput(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { if ((data[0] != 0) && (data[0] != 1)) { @@ -2481,7 +2444,7 @@ int i_APCI3120_InsnConfigDigitalOutput(struct comedi_device * dev, if (!devpriv->b_OutputMemoryStatus) { ui_Temp = 0; - } //if(!devpriv->b_OutputMemoryStatus ) + } /* if(!devpriv->b_OutputMemoryStatus ) */ return insn->n; } @@ -2499,16 +2462,16 @@ int i_APCI3120_InsnConfigDigitalOutput(struct comedi_device * dev, | struct comedi_subdevice *s | | struct comedi_insn *insn | | unsigned int *data | - data[0] Value to be written - data[1] :1 Set digital o/p ON - data[1] 2 Set digital o/p OFF with memory ON +| data[0] Value to be written +| data[1] :1 Set digital o/p ON +| data[1] 2 Set digital o/p OFF with memory ON +----------------------------------------------------------------------------+ | Return Value : | | | +----------------------------------------------------------------------------+ */ -int i_APCI3120_InsnBitsDigitalOutput(struct comedi_device * dev, +int i_APCI3120_InsnBitsDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -2530,7 +2493,7 @@ int i_APCI3120_InsnBitsDigitalOutput(struct comedi_device * dev, default: printk("\nThe parameter passed is in error \n"); return -EINVAL; - } // switch(data[1]) + } /* switch(data[1]) */ outb(data[0], devpriv->iobase + APCI3120_DIGITAL_OUTPUT); devpriv->b_DigitalOutputRegister = data[0] & 0xF0; @@ -2567,9 +2530,9 @@ int i_APCI3120_InsnWriteDigitalOutput(struct comedi_device *dev, unsigned int *data) { - UINT ui_Temp1; + unsigned int ui_Temp1; - UINT ui_NoOfChannel = CR_CHAN(insn->chanspec); // get the channel + unsigned int ui_NoOfChannel = CR_CHAN(insn->chanspec); /* get the channel */ if ((data[0] != 0) && (data[0] != 1)) { comedi_error(dev, @@ -2586,7 +2549,7 @@ int i_APCI3120_InsnWriteDigitalOutput(struct comedi_device *dev, switch (data[1]) { case 1: data[0] = (data[0] << ui_NoOfChannel); -//ES05 data[0]=(data[0]<<4)|ui_Temp; +/* ES05 data[0]=(data[0]<<4)|ui_Temp; */ data[0] = (data[0] << 4) | devpriv->b_DigitalOutputRegister; break; @@ -2595,24 +2558,24 @@ int i_APCI3120_InsnWriteDigitalOutput(struct comedi_device *dev, ui_Temp1 = 1; ui_Temp1 = ui_Temp1 << ui_NoOfChannel; ui_Temp1 = ui_Temp1 << 4; -//ES05 ui_Temp=ui_Temp|ui_Temp1; +/* ES05 ui_Temp=ui_Temp|ui_Temp1; */ devpriv->b_DigitalOutputRegister = devpriv->b_DigitalOutputRegister | ui_Temp1; data[0] = (data[0] << ui_NoOfChannel) ^ 0xf; data[0] = data[0] << 4; -//ES05 data[0]=data[0]& ui_Temp; +/* ES05 data[0]=data[0]& ui_Temp; */ data[0] = data[0] & devpriv->b_DigitalOutputRegister; break; default: printk("\nThe parameter passed is in error \n"); return -EINVAL; - } // switch(data[1]) + } /* switch(data[1]) */ outb(data[0], devpriv->iobase + APCI3120_DIGITAL_OUTPUT); -//ES05 ui_Temp=data[0] & 0xf0; +/* ES05 ui_Temp=data[0] & 0xf0; */ devpriv->b_DigitalOutputRegister = data[0] & 0xf0; - return (insn->n); + return insn->n; } @@ -2646,14 +2609,14 @@ int i_APCI3120_InsnWriteAnalogOutput(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - UINT ui_Range, ui_Channel; - USHORT us_TmpValue; + unsigned int ui_Range, ui_Channel; + unsigned short us_TmpValue; ui_Range = CR_RANGE(insn->chanspec); ui_Channel = CR_CHAN(insn->chanspec); - //this_board->i_hwdrv_InsnWriteAnalogOutput(dev, ui_Range, ui_Channel,data[0]); - if (ui_Range) // if 1 then unipolar + /* this_board->i_hwdrv_InsnWriteAnalogOutput(dev, ui_Range, ui_Channel,data[0]); */ + if (ui_Range) /* if 1 then unipolar */ { if (data[0] != 0) @@ -2665,7 +2628,7 @@ int i_APCI3120_InsnWriteAnalogOutput(struct comedi_device *dev, ((((ui_Channel & 0x03) << 14) & 0xC000) | (1 << 13) | 8192); - } else // if 0 then bipolar + } else /* if 0 then bipolar */ { data[0] = ((((ui_Channel & 0x03) << 14) & 0xC000) | (0 << 13) | @@ -2673,24 +2636,30 @@ int i_APCI3120_InsnWriteAnalogOutput(struct comedi_device *dev, } - //out put n values at the given channel. - // rt_printk("\nwaiting for DA_READY BIT"); - do //Waiting of DA_READY BIT +/* + * out put n values at the given channel. printk("\nwaiting for + * DA_READY BIT"); + */ + do /* Waiting of DA_READY BIT */ { us_TmpValue = - ((USHORT) inw(devpriv->iobase + + ((unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS)) & 0x0001; } while (us_TmpValue != 0x0001); if (ui_Channel <= 3) - // for channel 0-3 out at the register 1 (wrDac1-8) - // data[i] typecasted to ushort since word write is to be done - outw((USHORT) data[0], +/* + * for channel 0-3 out at the register 1 (wrDac1-8) data[i] + * typecasted to ushort since word write is to be done + */ + outw((unsigned short) data[0], devpriv->iobase + APCI3120_ANALOG_OUTPUT_1); else - // for channel 4-7 out at the register 2 (wrDac5-8) - //data[i] typecasted to ushort since word write is to be done - outw((USHORT) data[0], +/* + * for channel 4-7 out at the register 2 (wrDac5-8) data[i] + * typecasted to ushort since word write is to be done + */ + outw((unsigned short) data[0], devpriv->iobase + APCI3120_ANALOG_OUTPUT_2); return insn->n; diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.h b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.h index 59d5d87a845b..fedfc9c58a88 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.h +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.h @@ -1,5 +1,5 @@ -// hwdrv_apci3120.h +/* hwdrv_apci3120.h */ /* * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. @@ -18,9 +18,9 @@ * any later version. */ -// comedi related defines +/* comedi related defines */ -//ANALOG INPUT RANGE +/* ANALOG INPUT RANGE */ static const struct comedi_lrange range_apci3120_ai = { 8, { BIP_RANGE(10), BIP_RANGE(5), @@ -33,14 +33,14 @@ static const struct comedi_lrange range_apci3120_ai = { 8, { } }; -// ANALOG OUTPUT RANGE +/* ANALOG OUTPUT RANGE */ static const struct comedi_lrange range_apci3120_ao = { 2, { BIP_RANGE(10), UNI_RANGE(10) } }; -#define APCI3120_BIPOLAR_RANGES 4 // used for test on mixture of BIP/UNI ranges +#define APCI3120_BIPOLAR_RANGES 4 /* used for test on mixture of BIP/UNI ranges */ #define APCI3120_BOARD_VENDOR_ID 0x10E8 #define APCI3120_ADDRESS_RANGE 16 @@ -55,17 +55,17 @@ static const struct comedi_lrange range_apci3120_ao = { 2, { #define APCI3120_EOS_MODE 2 #define APCI3120_DMA_MODE 3 -//DIGITAL INPUT-OUTPUT DEFINE +/* DIGITAL INPUT-OUTPUT DEFINE */ #define APCI3120_DIGITAL_OUTPUT 0x0D #define APCI3120_RD_STATUS 0x02 #define APCI3120_RD_FIFO 0x00 -// digital output insn_write ON /OFF selection +/* digital output insn_write ON /OFF selection */ #define APCI3120_SET4DIGITALOUTPUTON 1 #define APCI3120_SET4DIGITALOUTPUTOFF 0 -// analog output SELECT BIT +/* analog output SELECT BIT */ #define APCI3120_ANALOG_OP_CHANNEL_1 0x0000 #define APCI3120_ANALOG_OP_CHANNEL_2 0x4000 #define APCI3120_ANALOG_OP_CHANNEL_3 0x8000 @@ -75,32 +75,32 @@ static const struct comedi_lrange range_apci3120_ao = { 2, { #define APCI3120_ANALOG_OP_CHANNEL_7 0x8000 #define APCI3120_ANALOG_OP_CHANNEL_8 0xC000 -// Enable external trigger bit in nWrAddress +/* Enable external trigger bit in nWrAddress */ #define APCI3120_ENABLE_EXT_TRIGGER 0x8000 -//ANALOG OUTPUT AND INPUT DEFINE -#define APCI3120_UNIPOLAR 0x80 //$$ RAM sequence polarity BIT -#define APCI3120_BIPOLAR 0x00 //$$ RAM sequence polarity BIT -#define APCI3120_ANALOG_OUTPUT_1 0x08 // (ADDRESS ) -#define APCI3120_ANALOG_OUTPUT_2 0x0A // (ADDRESS ) -#define APCI3120_1_GAIN 0x00 //$$ RAM sequence Gain Bits for gain 1 -#define APCI3120_2_GAIN 0x10 //$$ RAM sequence Gain Bits for gain 2 -#define APCI3120_5_GAIN 0x20 //$$ RAM sequence Gain Bits for gain 5 -#define APCI3120_10_GAIN 0x30 //$$ RAM sequence Gain Bits for gain 10 -#define APCI3120_SEQ_RAM_ADDRESS 0x06 //$$ EARLIER NAMED APCI3120_FIFO_ADDRESS -#define APCI3120_RESET_FIFO 0x0C //(ADDRESS) -#define APCI3120_TIMER_0_MODE_2 0x01 //$$ Bits for timer mode +/* ANALOG OUTPUT AND INPUT DEFINE */ +#define APCI3120_UNIPOLAR 0x80 /* $$ RAM sequence polarity BIT */ +#define APCI3120_BIPOLAR 0x00 /* $$ RAM sequence polarity BIT */ +#define APCI3120_ANALOG_OUTPUT_1 0x08 /* (ADDRESS ) */ +#define APCI3120_ANALOG_OUTPUT_2 0x0A /* (ADDRESS ) */ +#define APCI3120_1_GAIN 0x00 /* $$ RAM sequence Gain Bits for gain 1 */ +#define APCI3120_2_GAIN 0x10 /* $$ RAM sequence Gain Bits for gain 2 */ +#define APCI3120_5_GAIN 0x20 /* $$ RAM sequence Gain Bits for gain 5 */ +#define APCI3120_10_GAIN 0x30 /* $$ RAM sequence Gain Bits for gain 10 */ +#define APCI3120_SEQ_RAM_ADDRESS 0x06 /* $$ EARLIER NAMED APCI3120_FIFO_ADDRESS */ +#define APCI3120_RESET_FIFO 0x0C /* (ADDRESS) */ +#define APCI3120_TIMER_0_MODE_2 0x01 /* $$ Bits for timer mode */ #define APCI3120_TIMER_0_MODE_4 0x2 #define APCI3120_SELECT_TIMER_0_WORD 0x00 -#define APCI3120_ENABLE_TIMER0 0x1000 //$$Gatebit 0 in nWrAddress +#define APCI3120_ENABLE_TIMER0 0x1000 /* $$Gatebit 0 in nWrAddress */ #define APCI3120_CLEAR_PR 0xF0FF #define APCI3120_CLEAR_PA 0xFFF0 #define APCI3120_CLEAR_PA_PR (APCI3120_CLEAR_PR & APCI3120_CLEAR_PA) -// nWrMode_Select -#define APCI3120_ENABLE_SCAN 0x8 //$$ bit in nWrMode_Select +/* nWrMode_Select */ +#define APCI3120_ENABLE_SCAN 0x8 /* $$ bit in nWrMode_Select */ #define APCI3120_DISABLE_SCAN (~APCI3120_ENABLE_SCAN) -#define APCI3120_ENABLE_EOS_INT 0x2 //$$ bit in nWrMode_Select +#define APCI3120_ENABLE_EOS_INT 0x2 /* $$ bit in nWrMode_Select */ #define APCI3120_DISABLE_EOS_INT (~APCI3120_ENABLE_EOS_INT) #define APCI3120_ENABLE_EOC_INT 0x1 @@ -108,50 +108,50 @@ static const struct comedi_lrange range_apci3120_ao = { 2, { #define APCI3120_DISABLE_ALL_INTERRUPT_WITHOUT_TIMER (APCI3120_DISABLE_EOS_INT & APCI3120_DISABLE_EOC_INT) #define APCI3120_DISABLE_ALL_INTERRUPT (APCI3120_DISABLE_TIMER_INT & APCI3120_DISABLE_EOS_INT & APCI3120_DISABLE_EOC_INT) -//status register bits +/* status register bits */ #define APCI3120_EOC 0x8000 #define APCI3120_EOS 0x2000 -// software trigger dummy register -#define APCI3120_START_CONVERSION 0x02 //(ADDRESS) +/* software trigger dummy register */ +#define APCI3120_START_CONVERSION 0x02 /* (ADDRESS) */ -//TIMER DEFINE +/* TIMER DEFINE */ #define APCI3120_QUARTZ_A 70 #define APCI3120_QUARTZ_B 50 #define APCI3120_TIMER 1 #define APCI3120_WATCHDOG 2 #define APCI3120_TIMER_DISABLE 0 #define APCI3120_TIMER_ENABLE 1 -#define APCI3120_ENABLE_TIMER2 0x4000 //$$ gatebit 2 in nWrAddress +#define APCI3120_ENABLE_TIMER2 0x4000 /* $$ gatebit 2 in nWrAddress */ #define APCI3120_DISABLE_TIMER2 (~APCI3120_ENABLE_TIMER2) -#define APCI3120_ENABLE_TIMER_INT 0x04 //$$ ENAIRQ_FC_Bit in nWrModeSelect +#define APCI3120_ENABLE_TIMER_INT 0x04 /* $$ ENAIRQ_FC_Bit in nWrModeSelect */ #define APCI3120_DISABLE_TIMER_INT (~APCI3120_ENABLE_TIMER_INT) -#define APCI3120_WRITE_MODE_SELECT 0x0E // (ADDRESS) +#define APCI3120_WRITE_MODE_SELECT 0x0E /* (ADDRESS) */ #define APCI3120_SELECT_TIMER_0_WORD 0x00 #define APCI3120_SELECT_TIMER_1_WORD 0x01 #define APCI3120_TIMER_1_MODE_2 0x4 -//$$ BIT FOR MODE IN nCsTimerCtr1 +/* $$ BIT FOR MODE IN nCsTimerCtr1 */ #define APCI3120_TIMER_2_MODE_0 0x0 #define APCI3120_TIMER_2_MODE_2 0x10 #define APCI3120_TIMER_2_MODE_5 0x30 -//$$ BIT FOR MODE IN nCsTimerCtr0 +/* $$ BIT FOR MODE IN nCsTimerCtr0 */ #define APCI3120_SELECT_TIMER_2_LOW_WORD 0x02 #define APCI3120_SELECT_TIMER_2_HIGH_WORD 0x03 -#define APCI3120_TIMER_CRT0 0x0D //(ADDRESS for cCsTimerCtr0) -#define APCI3120_TIMER_CRT1 0x0C //(ADDRESS for cCsTimerCtr1) +#define APCI3120_TIMER_CRT0 0x0D /* (ADDRESS for cCsTimerCtr0) */ +#define APCI3120_TIMER_CRT1 0x0C /* (ADDRESS for cCsTimerCtr1) */ -#define APCI3120_TIMER_VALUE 0x04 //ADDRESS for nCsTimerWert -#define APCI3120_TIMER_STATUS_REGISTER 0x0D //ADDRESS for delete timer 2 interrupt -#define APCI3120_RD_STATUS 0x02 //ADDRESS -#define APCI3120_WR_ADDRESS 0x00 //ADDRESS -#define APCI3120_ENABLE_WATCHDOG 0x20 //$$BIT in nWrMode_Select +#define APCI3120_TIMER_VALUE 0x04 /* ADDRESS for nCsTimerWert */ +#define APCI3120_TIMER_STATUS_REGISTER 0x0D /* ADDRESS for delete timer 2 interrupt */ +#define APCI3120_RD_STATUS 0x02 /* ADDRESS */ +#define APCI3120_WR_ADDRESS 0x00 /* ADDRESS */ +#define APCI3120_ENABLE_WATCHDOG 0x20 /* $$BIT in nWrMode_Select */ #define APCI3120_DISABLE_WATCHDOG (~APCI3120_ENABLE_WATCHDOG) -#define APCI3120_ENABLE_TIMER_COUNTER 0x10 //$$BIT in nWrMode_Select +#define APCI3120_ENABLE_TIMER_COUNTER 0x10 /* $$BIT in nWrMode_Select */ #define APCI3120_DISABLE_TIMER_COUNTER (~APCI3120_ENABLE_TIMER_COUNTER) -#define APCI3120_FC_TIMER 0x1000 //bit in status register +#define APCI3120_FC_TIMER 0x1000 /* bit in status register */ #define APCI3120_ENABLE_TIMER0 0x1000 #define APCI3120_ENABLE_TIMER1 0x2000 #define APCI3120_ENABLE_TIMER2 0x4000 @@ -159,25 +159,27 @@ static const struct comedi_lrange range_apci3120_ao = { 2, { #define APCI3120_DISABLE_TIMER1 (~APCI3120_ENABLE_TIMER1) #define APCI3120_DISABLE_TIMER2 (~APCI3120_ENABLE_TIMER2) -#define APCI3120_TIMER2_SELECT_EOS 0xC0 // ADDED on 20-6 -#define APCI3120_COUNTER 3 // on 20-6 -#define APCI3120_DISABLE_ALL_TIMER ( APCI3120_DISABLE_TIMER0 & APCI3120_DISABLE_TIMER1 & APCI3120_DISABLE_TIMER2 ) // on 20-6 +#define APCI3120_TIMER2_SELECT_EOS 0xC0 /* ADDED on 20-6 */ +#define APCI3120_COUNTER 3 /* on 20-6 */ +#define APCI3120_DISABLE_ALL_TIMER (APCI3120_DISABLE_TIMER0 & APCI3120_DISABLE_TIMER1 & APCI3120_DISABLE_TIMER2) /* on 20-6 */ #define MAX_ANALOGINPUT_CHANNELS 32 -typedef struct { - BYTE b_Type; /* EOC or EOS */ - BYTE b_InterruptFlag; /* Interrupt use or not */ - UINT ui_ConvertTiming; /* Selection of the convertion time */ - BYTE b_NbrOfChannel; /* Number of channel to read */ - UINT ui_ChannelList[MAX_ANALOGINPUT_CHANNELS]; /* Number of the channel to be read */ - UINT ui_RangeList[MAX_ANALOGINPUT_CHANNELS]; /* Gain of each channel */ +struct str_AnalogReadInformation { -} str_AnalogReadInformation; + unsigned char b_Type; /* EOC or EOS */ + unsigned char b_InterruptFlag; /* Interrupt use or not */ + unsigned int ui_ConvertTiming; /* Selection of the convertion time */ + unsigned char b_NbrOfChannel; /* Number of channel to read */ + unsigned int ui_ChannelList[MAX_ANALOGINPUT_CHANNELS]; /* Number of the channel to be read */ + unsigned int ui_RangeList[MAX_ANALOGINPUT_CHANNELS]; /* Gain of each channel */ -// Function Declaration For APCI-3120 +}; -// Internal functions + +/* Function Declaration For APCI-3120 */ + +/* Internal functions */ int i_APCI3120_SetupChannelList(struct comedi_device *dev, struct comedi_subdevice *s, int n_chan, unsigned int *chanlist, char check); int i_APCI3120_ExttrigEnable(struct comedi_device *dev); @@ -186,9 +188,9 @@ int i_APCI3120_StopCyclicAcquisition(struct comedi_device *dev, struct comedi_su int i_APCI3120_Reset(struct comedi_device *dev); int i_APCI3120_CyclicAnalogInput(int mode, struct comedi_device *dev, struct comedi_subdevice *s); -// Interrupt functions +/* Interrupt functions */ void v_APCI3120_Interrupt(int irq, void *d); -//UPDATE-0.7.57->0.7.68 void v_APCI3120_InterruptDmaMoveBlock16bit(struct comedi_device *dev,struct comedi_subdevice *s,short *dma,short *data,int n); +/* UPDATE-0.7.57->0.7.68 void v_APCI3120_InterruptDmaMoveBlock16bit(struct comedi_device *dev,struct comedi_subdevice *s,short *dma,short *data,int n); */ void v_APCI3120_InterruptDmaMoveBlock16bit(struct comedi_device *dev, struct comedi_subdevice *s, short *dma_buffer, @@ -196,7 +198,7 @@ void v_APCI3120_InterruptDmaMoveBlock16bit(struct comedi_device *dev, int i_APCI3120_InterruptHandleEos(struct comedi_device *dev); void v_APCI3120_InterruptDma(int irq, void *d); -// TIMER +/* TIMER */ int i_APCI3120_InsnConfigTimer(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); @@ -205,16 +207,19 @@ int i_APCI3120_InsnWriteTimer(struct comedi_device *dev, struct comedi_subdevice int i_APCI3120_InsnReadTimer(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -//DI -// for di read +/* +* DI for di read +*/ int i_APCI3120_InsnBitsDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); int i_APCI3120_InsnReadDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -//DO -//int i_APCI3120_WriteDigitalOutput(struct comedi_device *dev, BYTE data); +/* DO */ +/* int i_APCI3120_WriteDigitalOutput(struct comedi_device *dev, + * unsigned char data); + */ int i_APCI3120_InsnConfigDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); @@ -223,12 +228,15 @@ int i_APCI3120_InsnBitsDigitalOutput(struct comedi_device *dev, struct comedi_su int i_APCI3120_InsnWriteDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -//AO -//int i_APCI3120_Write1AnalogValue(struct comedi_device *dev,UINT ui_Range,UINT ui_Channel,UINT data ); +/* AO */ +/* int i_APCI3120_Write1AnalogValue(struct comedi_device *dev,UINT ui_Range, + * UINT ui_Channel,UINT data ); + */ + int i_APCI3120_InsnWriteAnalogOutput(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -//AI HArdware layer +/* AI HArdware layer */ int i_APCI3120_InsnConfigAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); @@ -237,5 +245,5 @@ int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev, struct comedi_subd int i_APCI3120_CommandTestAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd); int i_APCI3120_CommandAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s); -//int i_APCI3120_CancelAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s); +/* int i_APCI3120_CancelAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s); */ int i_APCI3120_StopCyclicAcquisition(struct comedi_device *dev, struct comedi_subdevice *s); diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c index 1ff66bee548d..9b53255bd45b 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c @@ -3,13 +3,13 @@ Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data-com - info@addi-data.com + ADDI-DATA GmbH + Dieselstrasse 3 + D-77833 Ottersweier + Tel: +19(0)7223/9493-0 + Fax: +49(0)7223/9493-92 + http://www.addi-data-com + info@addi-data.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. @@ -57,73 +57,73 @@ You shoud also find the complete GPL in the COPYING file accompanying this sourc +----------------------------------------------------------------------------+ */ #include "hwdrv_apci3200.h" -//Begin JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values +/* Begin JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ #include "addi_amcc_S5920.h" -//#define PRINT_INFO +/* #define PRINT_INFO */ -//End JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values +/* End JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ -//BEGIN JK 06.07.04: Management of sevrals boards +/* BEGIN JK 06.07.04: Management of sevrals boards */ /* - INT i_CJCAvailable=1; - INT i_CJCPolarity=0; - INT i_CJCGain=2;//changed from 0 to 2 - INT i_InterruptFlag=0; - INT i_ADDIDATAPolarity; - INT i_ADDIDATAGain; - INT i_AutoCalibration=0; //: auto calibration - INT i_ADDIDATAConversionTime; - INT i_ADDIDATAConversionTimeUnit; - INT i_ADDIDATAType; - INT i_ChannelNo; - INT i_ChannelCount=0; - INT i_ScanType; - INT i_FirstChannel; - INT i_LastChannel; - INT i_Sum=0; - INT i_Offset; - UINT ui_Channel_num=0; + int i_CJCAvailable=1; + int i_CJCPolarity=0; + int i_CJCGain=2;/* changed from 0 to 2 */ + int i_InterruptFlag=0; + int i_ADDIDATAPolarity; + int i_ADDIDATAGain; + int i_AutoCalibration=0; /* : auto calibration */ + int i_ADDIDATAConversionTime; + int i_ADDIDATAConversionTimeUnit; + int i_ADDIDATAType; + int i_ChannelNo; + int i_ChannelCount=0; + int i_ScanType; + int i_FirstChannel; + int i_LastChannel; + int i_Sum=0; + int i_Offset; + unsigned int ui_Channel_num=0; static int i_Count=0; - INT i_Initialised=0; - UINT ui_InterruptChannelValue[96]; //Buffer + int i_Initialised=0; + unsigned int ui_InterruptChannelValue[96]; /* Buffer */ */ -str_BoardInfos s_BoardInfos[100]; // 100 will be the max number of boards to be used -//END JK 06.07.04: Management of sevrals boards +struct str_BoardInfos s_BoardInfos[100]; /* 100 will be the max number of boards to be used */ +/* END JK 06.07.04: Management of sevrals boards */ -//Begin JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values +/* Begin JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ /*+----------------------------------------------------------------------------+*/ -/*| Function Name : INT i_AddiHeaderRW_ReadEeprom |*/ -/*| (INT i_NbOfWordsToRead, |*/ -/*| DWORD dw_PCIBoardEepromAddress, |*/ -/*| WORD w_EepromStartAddress, |*/ -/*| PWORD pw_DataRead) |*/ +/*| Function Name : int i_AddiHeaderRW_ReadEeprom |*/ +/*| (int i_NbOfWordsToRead, |*/ +/*| unsigned int dw_PCIBoardEepromAddress, |*/ +/*| unsigned short w_EepromStartAddress, |*/ +/*| unsigned short * pw_DataRead) |*/ /*+----------------------------------------------------------------------------+*/ /*| Task : Read word from the 5920 eeprom. |*/ /*+----------------------------------------------------------------------------+*/ -/*| Input Parameters : INT i_NbOfWordsToRead : Nbr. of word to read |*/ -/*| DWORD dw_PCIBoardEepromAddress : Address of the eeprom |*/ -/*| WORD w_EepromStartAddress : Eeprom strat address |*/ +/*| Input Parameters : int i_NbOfWordsToRead : Nbr. of word to read |*/ +/*| unsigned int dw_PCIBoardEepromAddress : Address of the eeprom |*/ +/*| unsigned short w_EepromStartAddress : Eeprom strat address |*/ /*+----------------------------------------------------------------------------+*/ -/*| Output Parameters : PWORD pw_DataRead : Read data |*/ +/*| Output Parameters : unsigned short * pw_DataRead : Read data |*/ /*+----------------------------------------------------------------------------+*/ /*| Return Value : - |*/ /*+----------------------------------------------------------------------------+*/ -INT i_AddiHeaderRW_ReadEeprom(INT i_NbOfWordsToRead, - DWORD dw_PCIBoardEepromAddress, - WORD w_EepromStartAddress, PWORD pw_DataRead) +int i_AddiHeaderRW_ReadEeprom(int i_NbOfWordsToRead, + unsigned int dw_PCIBoardEepromAddress, + unsigned short w_EepromStartAddress, unsigned short *pw_DataRead) { - DWORD dw_eeprom_busy = 0; - INT i_Counter = 0; - INT i_WordCounter; - INT i; - BYTE pb_ReadByte[1]; - BYTE b_ReadLowByte = 0; - BYTE b_ReadHighByte = 0; - BYTE b_SelectedAddressLow = 0; - BYTE b_SelectedAddressHigh = 0; - WORD w_ReadWord = 0; + unsigned int dw_eeprom_busy = 0; + int i_Counter = 0; + int i_WordCounter; + int i; + unsigned char pb_ReadByte[1]; + unsigned char b_ReadLowByte = 0; + unsigned char b_ReadHighByte = 0; + unsigned char b_SelectedAddressLow = 0; + unsigned char b_SelectedAddressHigh = 0; + unsigned short w_ReadWord = 0; for (i_WordCounter = 0; i_WordCounter < i_NbOfWordsToRead; i_WordCounter++) { @@ -132,106 +132,99 @@ INT i_AddiHeaderRW_ReadEeprom(INT i_NbOfWordsToRead, inl(dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR); dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY; - } - while (dw_eeprom_busy == EEPROM_BUSY); + } while (dw_eeprom_busy == EEPROM_BUSY); for (i_Counter = 0; i_Counter < 2; i_Counter++) { - b_SelectedAddressLow = (w_EepromStartAddress + i_Counter) % 256; //Read the low 8 bit part - b_SelectedAddressHigh = (w_EepromStartAddress + i_Counter) / 256; //Read the high 8 bit part + b_SelectedAddressLow = (w_EepromStartAddress + i_Counter) % 256; /* Read the low 8 bit part */ + b_SelectedAddressHigh = (w_EepromStartAddress + i_Counter) / 256; /* Read the high 8 bit part */ - //Select the load low address mode + /* Select the load low address mode */ outb(NVCMD_LOAD_LOW, dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR + 3); - //Wait on busy + /* Wait on busy */ do { dw_eeprom_busy = inl(dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR); dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY; - } - while (dw_eeprom_busy == EEPROM_BUSY); + } while (dw_eeprom_busy == EEPROM_BUSY); - //Load the low address + /* Load the low address */ outb(b_SelectedAddressLow, dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR + 2); - //Wait on busy + /* Wait on busy */ do { dw_eeprom_busy = inl(dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR); dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY; - } - while (dw_eeprom_busy == EEPROM_BUSY); + } while (dw_eeprom_busy == EEPROM_BUSY); - //Select the load high address mode + /* Select the load high address mode */ outb(NVCMD_LOAD_HIGH, dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR + 3); - //Wait on busy + /* Wait on busy */ do { dw_eeprom_busy = inl(dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR); dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY; - } - while (dw_eeprom_busy == EEPROM_BUSY); + } while (dw_eeprom_busy == EEPROM_BUSY); - //Load the high address + /* Load the high address */ outb(b_SelectedAddressHigh, dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR + 2); - //Wait on busy + /* Wait on busy */ do { dw_eeprom_busy = inl(dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR); dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY; - } - while (dw_eeprom_busy == EEPROM_BUSY); + } while (dw_eeprom_busy == EEPROM_BUSY); - //Select the READ mode + /* Select the READ mode */ outb(NVCMD_BEGIN_READ, dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR + 3); - //Wait on busy + /* Wait on busy */ do { dw_eeprom_busy = inl(dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR); dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY; - } - while (dw_eeprom_busy == EEPROM_BUSY); + } while (dw_eeprom_busy == EEPROM_BUSY); - //Read data into the EEPROM + /* Read data into the EEPROM */ *pb_ReadByte = inb(dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR + 2); - //Wait on busy + /* Wait on busy */ do { dw_eeprom_busy = inl(dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR); dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY; - } - while (dw_eeprom_busy == EEPROM_BUSY); + } while (dw_eeprom_busy == EEPROM_BUSY); - //Select the upper address part - if (i_Counter == 0) { + /* Select the upper address part */ + if (i_Counter == 0) b_ReadLowByte = pb_ReadByte[0]; - } else { + else b_ReadHighByte = pb_ReadByte[0]; - } - //Sleep - for (i = 0; i < 10000; i++) ; + + /* Sleep */ + msleep(1); } w_ReadWord = @@ -240,10 +233,10 @@ INT i_AddiHeaderRW_ReadEeprom(INT i_NbOfWordsToRead, pw_DataRead[i_WordCounter] = w_ReadWord; - w_EepromStartAddress += 2; // to read the next word + w_EepromStartAddress += 2; /* to read the next word */ - } // for (...) i_NbOfWordsToRead - return (0); + } /* for (...) i_NbOfWordsToRead */ + return 0; } /*+----------------------------------------------------------------------------+*/ @@ -258,31 +251,31 @@ INT i_AddiHeaderRW_ReadEeprom(INT i_NbOfWordsToRead, /*| Return Value : - |*/ /*+----------------------------------------------------------------------------+*/ -void v_GetAPCI3200EepromCalibrationValue(DWORD dw_PCIBoardEepromAddress, - str_BoardInfos * BoardInformations) +void v_GetAPCI3200EepromCalibrationValue(unsigned int dw_PCIBoardEepromAddress, + struct str_BoardInfos *BoardInformations) { - WORD w_AnalogInputMainHeaderAddress; - WORD w_AnalogInputComponentAddress; - WORD w_NumberOfModuls = 0; - WORD w_CurrentSources[2]; - WORD w_ModulCounter = 0; - WORD w_FirstHeaderSize = 0; - WORD w_NumberOfInputs = 0; - WORD w_CJCFlag = 0; - WORD w_NumberOfGainValue = 0; - WORD w_SingleHeaderAddress = 0; - WORD w_SingleHeaderSize = 0; - WORD w_Input = 0; - WORD w_GainFactorAddress = 0; - WORD w_GainFactorValue[2]; - WORD w_GainIndex = 0; - WORD w_GainValue = 0; + unsigned short w_AnalogInputMainHeaderAddress; + unsigned short w_AnalogInputComponentAddress; + unsigned short w_NumberOfModuls = 0; + unsigned short w_CurrentSources[2]; + unsigned short w_ModulCounter = 0; + unsigned short w_FirstHeaderSize = 0; + unsigned short w_NumberOfInputs = 0; + unsigned short w_CJCFlag = 0; + unsigned short w_NumberOfGainValue = 0; + unsigned short w_SingleHeaderAddress = 0; + unsigned short w_SingleHeaderSize = 0; + unsigned short w_Input = 0; + unsigned short w_GainFactorAddress = 0; + unsigned short w_GainFactorValue[2]; + unsigned short w_GainIndex = 0; + unsigned short w_GainValue = 0; /*****************************************/ /** Get the Analog input header address **/ /*****************************************/ - i_AddiHeaderRW_ReadEeprom(1, //i_NbOfWordsToRead - dw_PCIBoardEepromAddress, 0x116, //w_EepromStartAddress: Analog input header address + i_AddiHeaderRW_ReadEeprom(1, /* i_NbOfWordsToRead */ + dw_PCIBoardEepromAddress, 0x116, /* w_EepromStartAddress: Analog input header address */ &w_AnalogInputMainHeaderAddress); /*******************************************/ @@ -293,8 +286,8 @@ void v_GetAPCI3200EepromCalibrationValue(DWORD dw_PCIBoardEepromAddress, /******************************/ /** Get the number of moduls **/ /******************************/ - i_AddiHeaderRW_ReadEeprom(1, //i_NbOfWordsToRead - dw_PCIBoardEepromAddress, w_AnalogInputMainHeaderAddress + 0x02, //w_EepromStartAddress: Number of conponment + i_AddiHeaderRW_ReadEeprom(1, /* i_NbOfWordsToRead */ + dw_PCIBoardEepromAddress, w_AnalogInputMainHeaderAddress + 0x02, /* w_EepromStartAddress: Number of conponment */ &w_NumberOfModuls); for (w_ModulCounter = 0; w_ModulCounter < w_NumberOfModuls; @@ -309,8 +302,8 @@ void v_GetAPCI3200EepromCalibrationValue(DWORD dw_PCIBoardEepromAddress, /****************************/ /** Read first header size **/ /****************************/ - i_AddiHeaderRW_ReadEeprom(1, //i_NbOfWordsToRead - dw_PCIBoardEepromAddress, w_AnalogInputComponentAddress, // Address of the first header + i_AddiHeaderRW_ReadEeprom(1, /* i_NbOfWordsToRead */ + dw_PCIBoardEepromAddress, w_AnalogInputComponentAddress, /* Address of the first header */ &w_FirstHeaderSize); w_FirstHeaderSize = w_FirstHeaderSize >> 4; @@ -318,8 +311,8 @@ void v_GetAPCI3200EepromCalibrationValue(DWORD dw_PCIBoardEepromAddress, /***************************/ /** Read number of inputs **/ /***************************/ - i_AddiHeaderRW_ReadEeprom(1, //i_NbOfWordsToRead - dw_PCIBoardEepromAddress, w_AnalogInputComponentAddress + 0x06, // Number of inputs for the first modul + i_AddiHeaderRW_ReadEeprom(1, /* i_NbOfWordsToRead */ + dw_PCIBoardEepromAddress, w_AnalogInputComponentAddress + 0x06, /* Number of inputs for the first modul */ &w_NumberOfInputs); w_NumberOfInputs = w_NumberOfInputs >> 4; @@ -327,17 +320,17 @@ void v_GetAPCI3200EepromCalibrationValue(DWORD dw_PCIBoardEepromAddress, /***********************/ /** Read the CJC flag **/ /***********************/ - i_AddiHeaderRW_ReadEeprom(1, //i_NbOfWordsToRead - dw_PCIBoardEepromAddress, w_AnalogInputComponentAddress + 0x08, // CJC flag + i_AddiHeaderRW_ReadEeprom(1, /* i_NbOfWordsToRead */ + dw_PCIBoardEepromAddress, w_AnalogInputComponentAddress + 0x08, /* CJC flag */ &w_CJCFlag); - w_CJCFlag = (w_CJCFlag >> 3) & 0x1; // Get only the CJC flag + w_CJCFlag = (w_CJCFlag >> 3) & 0x1; /* Get only the CJC flag */ /*******************************/ /** Read number of gain value **/ /*******************************/ - i_AddiHeaderRW_ReadEeprom(1, //i_NbOfWordsToRead - dw_PCIBoardEepromAddress, w_AnalogInputComponentAddress + 0x44, // Number of gain value + i_AddiHeaderRW_ReadEeprom(1, /* i_NbOfWordsToRead */ + dw_PCIBoardEepromAddress, w_AnalogInputComponentAddress + 0x44, /* Number of gain value */ &w_NumberOfGainValue); w_NumberOfGainValue = w_NumberOfGainValue & 0xFF; @@ -354,8 +347,8 @@ void v_GetAPCI3200EepromCalibrationValue(DWORD dw_PCIBoardEepromAddress, /********************************************/ /** Read current sources value for input 1 **/ /********************************************/ - i_AddiHeaderRW_ReadEeprom(1, //i_NbOfWordsToRead - dw_PCIBoardEepromAddress, w_SingleHeaderAddress, //w_EepromStartAddress: Single header address + i_AddiHeaderRW_ReadEeprom(1, /* i_NbOfWordsToRead */ + dw_PCIBoardEepromAddress, w_SingleHeaderAddress, /* w_EepromStartAddress: Single header address */ &w_SingleHeaderSize); w_SingleHeaderSize = w_SingleHeaderSize >> 4; @@ -370,8 +363,8 @@ void v_GetAPCI3200EepromCalibrationValue(DWORD dw_PCIBoardEepromAddress, /************************************/ /** Read gain value for the module **/ /************************************/ - i_AddiHeaderRW_ReadEeprom(1, //i_NbOfWordsToRead - dw_PCIBoardEepromAddress, w_AnalogInputComponentAddress + 70 + (2 * (1 + (w_NumberOfGainValue / 16))) + (0x02 * w_GainIndex), // Gain value + i_AddiHeaderRW_ReadEeprom(1, /* i_NbOfWordsToRead */ + dw_PCIBoardEepromAddress, w_AnalogInputComponentAddress + 70 + (2 * (1 + (w_NumberOfGainValue / 16))) + (0x02 * w_GainIndex), /* Gain value */ &w_GainValue); BoardInformations->s_Module[w_ModulCounter]. @@ -386,8 +379,8 @@ void v_GetAPCI3200EepromCalibrationValue(DWORD dw_PCIBoardEepromAddress, /*************************************/ /** Read gain factor for the module **/ /*************************************/ - i_AddiHeaderRW_ReadEeprom(2, //i_NbOfWordsToRead - dw_PCIBoardEepromAddress, w_AnalogInputComponentAddress + 70 + ((2 * w_NumberOfGainValue) + (2 * (1 + (w_NumberOfGainValue / 16)))) + (0x04 * w_GainIndex), // Gain factor + i_AddiHeaderRW_ReadEeprom(2, /* i_NbOfWordsToRead */ + dw_PCIBoardEepromAddress, w_AnalogInputComponentAddress + 70 + ((2 * w_NumberOfGainValue) + (2 * (1 + (w_NumberOfGainValue / 16)))) + (0x04 * w_GainIndex), /* Gain factor */ w_GainFactorValue); BoardInformations->s_Module[w_ModulCounter]. @@ -409,7 +402,7 @@ void v_GetAPCI3200EepromCalibrationValue(DWORD dw_PCIBoardEepromAddress, /********************************************/ /** Read current sources value for input 1 **/ /********************************************/ - i_AddiHeaderRW_ReadEeprom(2, //i_NbOfWordsToRead + i_AddiHeaderRW_ReadEeprom(2, /* i_NbOfWordsToRead */ dw_PCIBoardEepromAddress, (w_Input * w_SingleHeaderSize) + w_SingleHeaderAddress + 0x0C, w_CurrentSources); @@ -432,7 +425,7 @@ void v_GetAPCI3200EepromCalibrationValue(DWORD dw_PCIBoardEepromAddress, /***************************************/ /** Read the CJC current source value **/ /***************************************/ - i_AddiHeaderRW_ReadEeprom(2, //i_NbOfWordsToRead + i_AddiHeaderRW_ReadEeprom(2, /* i_NbOfWordsToRead */ dw_PCIBoardEepromAddress, (w_Input * w_SingleHeaderSize) + w_SingleHeaderAddress + 0x0C, w_CurrentSources); @@ -453,9 +446,9 @@ void v_GetAPCI3200EepromCalibrationValue(DWORD dw_PCIBoardEepromAddress, } } -INT i_APCI3200_GetChannelCalibrationValue(struct comedi_device * dev, - unsigned int ui_Channel_num, unsigned int * CJCCurrentSource, - unsigned int * ChannelCurrentSource, unsigned int * ChannelGainFactor) +int i_APCI3200_GetChannelCalibrationValue(struct comedi_device *dev, + unsigned int ui_Channel_num, unsigned int *CJCCurrentSource, + unsigned int *ChannelCurrentSource, unsigned int *ChannelGainFactor) { int i_DiffChannel = 0; int i_Module = 0; @@ -464,9 +457,9 @@ INT i_APCI3200_GetChannelCalibrationValue(struct comedi_device * dev, printk("\n Channel = %u", ui_Channel_num); #endif - //Test if single or differential mode + /* Test if single or differential mode */ if (s_BoardInfos[dev->minor].i_ConnectionType == 1) { - //if diff + /* if diff */ if ((ui_Channel_num >= 0) && (ui_Channel_num <= 1)) i_DiffChannel = ui_Channel_num, i_Module = 0; @@ -478,7 +471,7 @@ INT i_APCI3200_GetChannelCalibrationValue(struct comedi_device * dev, i_DiffChannel = ui_Channel_num - 6, i_Module = 3; } else { - // if single + /* if single */ if ((ui_Channel_num == 0) || (ui_Channel_num == 1)) i_DiffChannel = 0, i_Module = 0; else if ((ui_Channel_num == 2) || (ui_Channel_num == 3)) @@ -497,7 +490,7 @@ INT i_APCI3200_GetChannelCalibrationValue(struct comedi_device * dev, i_DiffChannel = 1, i_Module = 3; } - //Test if thermocouple or RTD mode + /* Test if thermocouple or RTD mode */ *CJCCurrentSource = s_BoardInfos[dev->minor].s_Module[i_Module].ul_CurrentSourceCJC; #ifdef PRINT_INFO @@ -510,22 +503,22 @@ INT i_APCI3200_GetChannelCalibrationValue(struct comedi_device * dev, #ifdef PRINT_INFO printk("\n ChannelCurrentSource = %lu", *ChannelCurrentSource); #endif - // } - // } + /* } */ + /* } */ - //Channle gain factor + /* Channle gain factor */ *ChannelGainFactor = s_BoardInfos[dev->minor].s_Module[i_Module]. ul_GainFactor[s_BoardInfos[dev->minor].i_ADDIDATAGain]; #ifdef PRINT_INFO printk("\n ChannelGainFactor = %lu", *ChannelGainFactor); #endif - //End JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values + /* End JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ - return (0); + return 0; } -//End JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values +/* End JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ /* +----------------------------------------------------------------------------+ @@ -536,9 +529,9 @@ INT i_APCI3200_GetChannelCalibrationValue(struct comedi_device * dev, | Task : Read value of the selected channel or port | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | - | UINT ui_NoOfChannels : No Of Channels To read for Port + | unsigned int ui_NoOfChannels : No Of Channels To read for Port Channel Numberfor single channel - | UINT data[0] : 0: Read single channel + | unsigned int data[0] : 0: Read single channel 1: Read port value data[1] Port number +----------------------------------------------------------------------------+ @@ -550,24 +543,24 @@ INT i_APCI3200_GetChannelCalibrationValue(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -INT i_APCI3200_ReadDigitalInput(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI3200_ReadDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - UINT ui_Temp = 0; - UINT ui_NoOfChannel = 0; + unsigned int ui_Temp = 0; + unsigned int ui_NoOfChannel = 0; ui_NoOfChannel = CR_CHAN(insn->chanspec); ui_Temp = data[0]; *data = inl(devpriv->i_IobaseReserved); if (ui_Temp == 0) { *data = (*data >> ui_NoOfChannel) & 0x1; - } //if (ui_Temp==0) + } /* if (ui_Temp==0) */ else { if (ui_Temp == 1) { if (data[1] < 0 || data[1] > 1) { printk("\nThe port number is in error\n"); return -EINVAL; - } //if(data[1] < 0 || data[1] >1) + } /* if(data[1] < 0 || data[1] >1) */ switch (ui_NoOfChannel) { case 2: @@ -578,13 +571,13 @@ INT i_APCI3200_ReadDigitalInput(struct comedi_device * dev, struct comedi_subdev break; default: comedi_error(dev, " chan spec wrong"); - return -EINVAL; // "sorry channel spec wrong " + return -EINVAL; /* "sorry channel spec wrong " */ - } //switch(ui_NoOfChannels) - } //if (ui_Temp==1) + } /* switch(ui_NoOfChannels) */ + } /* if (ui_Temp==1) */ else { printk("\nSpecified channel not supported \n"); - } //elseif (ui_Temp==1) + } /* elseif (ui_Temp==1) */ } return insn->n; } @@ -608,21 +601,21 @@ INT i_APCI3200_ReadDigitalInput(struct comedi_device * dev, struct comedi_subdev | | +----------------------------------------------------------------------------+ */ -int i_APCI3200_ConfigDigitalOutput(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI3200_ConfigDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if ((data[0] != 0) && (data[0] != 1)) { comedi_error(dev, "Not a valid Data !!! ,Data should be 1 or 0\n"); return -EINVAL; - } //if ( (data[0]!=0) && (data[0]!=1) ) + } /* if ( (data[0]!=0) && (data[0]!=1) ) */ if (data[0]) { devpriv->b_OutputMemoryStatus = ADDIDATA_ENABLE; - } // if (data[0]) + } /* if (data[0]) */ else { devpriv->b_OutputMemoryStatus = ADDIDATA_DISABLE; - } //else if (data[0]) + } /* else if (data[0]) */ return insn->n; } @@ -653,23 +646,23 @@ int i_APCI3200_ConfigDigitalOutput(struct comedi_device * dev, struct comedi_sub | | +----------------------------------------------------------------------------+ */ -INT i_APCI3200_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI3200_WriteDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - UINT ui_Temp = 0, ui_Temp1 = 0; - UINT ui_NoOfChannel = CR_CHAN(insn->chanspec); // get the channel + unsigned int ui_Temp = 0, ui_Temp1 = 0; + unsigned int ui_NoOfChannel = CR_CHAN(insn->chanspec); /* get the channel */ if (devpriv->b_OutputMemoryStatus) { ui_Temp = inl(devpriv->i_IobaseAddon); - } //if(devpriv->b_OutputMemoryStatus ) + } /* if(devpriv->b_OutputMemoryStatus ) */ else { ui_Temp = 0; - } //if(devpriv->b_OutputMemoryStatus ) + } /* if(devpriv->b_OutputMemoryStatus ) */ if (data[3] == 0) { if (data[1] == 0) { data[0] = (data[0] << ui_NoOfChannel) | ui_Temp; outl(data[0], devpriv->i_IobaseAddon); - } //if(data[1]==0) + } /* if(data[1]==0) */ else { if (data[1] == 1) { switch (ui_NoOfChannel) { @@ -682,15 +675,15 @@ INT i_APCI3200_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subd case 3: data[0] = (data[0] | ui_Temp); break; - } //switch(ui_NoOfChannels) + } /* switch(ui_NoOfChannels) */ outl(data[0], devpriv->i_IobaseAddon); - } // if(data[1]==1) + } /* if(data[1]==1) */ else { printk("\nSpecified channel not supported\n"); - } //else if(data[1]==1) - } //elseif(data[1]==0) - } //if(data[3]==0) + } /* else if(data[1]==1) */ + } /* elseif(data[1]==0) */ + } /* if(data[3]==0) */ else { if (data[3] == 1) { if (data[1] == 0) { @@ -701,7 +694,7 @@ INT i_APCI3200_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subd data[0] = (data[0] << ui_NoOfChannel) ^ 0xf; data[0] = data[0] & ui_Temp; outl(data[0], devpriv->i_IobaseAddon); - } //if(data[1]==0) + } /* if(data[1]==0) */ else { if (data[1] == 1) { switch (ui_NoOfChannel) { @@ -725,21 +718,21 @@ INT i_APCI3200_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subd default: comedi_error(dev, " chan spec wrong"); - return -EINVAL; // "sorry channel spec wrong " - } //switch(ui_NoOfChannels) + return -EINVAL; /* "sorry channel spec wrong " */ + } /* switch(ui_NoOfChannels) */ outl(data[0], devpriv->i_IobaseAddon); - } // if(data[1]==1) + } /* if(data[1]==1) */ else { printk("\nSpecified channel not supported\n"); - } //else if(data[1]==1) - } //elseif(data[1]==0) - } //if(data[3]==1); + } /* else if(data[1]==1) */ + } /* elseif(data[1]==0) */ + } /* if(data[3]==1); */ else { printk("\nSpecified functionality does not exist\n"); return -EINVAL; - } //if else data[3]==1) - } //if else data[3]==0) + } /* if else data[3]==1) */ + } /* if else data[3]==0) */ return insn->n; } @@ -752,8 +745,8 @@ INT i_APCI3200_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subd | Task : Read value of the selected channel or port | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | - | UINT ui_NoOfChannels : No Of Channels To read | - | UINT *data : Data Pointer to read status | + | unsigned int ui_NoOfChannels : No Of Channels To read | + | unsigned int *data : Data Pointer to read status | data[0] :0 read single channel 1 read port value data[1] port no @@ -766,23 +759,23 @@ INT i_APCI3200_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subd | | +----------------------------------------------------------------------------+ */ -INT i_APCI3200_ReadDigitalOutput(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI3200_ReadDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - UINT ui_Temp; - UINT ui_NoOfChannel; + unsigned int ui_Temp; + unsigned int ui_NoOfChannel; ui_NoOfChannel = CR_CHAN(insn->chanspec); ui_Temp = data[0]; *data = inl(devpriv->i_IobaseAddon); if (ui_Temp == 0) { *data = (*data >> ui_NoOfChannel) & 0x1; - } // if (ui_Temp==0) + } /* if (ui_Temp==0) */ else { if (ui_Temp == 1) { if (data[1] < 0 || data[1] > 1) { printk("\nThe port selection is in error\n"); return -EINVAL; - } //if(data[1] <0 ||data[1] >1) + } /* if(data[1] <0 ||data[1] >1) */ switch (ui_NoOfChannel) { case 2: *data = (*data >> (2 * data[1])) & 3; @@ -793,20 +786,20 @@ INT i_APCI3200_ReadDigitalOutput(struct comedi_device * dev, struct comedi_subde default: comedi_error(dev, " chan spec wrong"); - return -EINVAL; // "sorry channel spec wrong " + return -EINVAL; /* "sorry channel spec wrong " */ break; - } // switch(ui_NoOfChannels) - } // if (ui_Temp==1) + } /* switch(ui_NoOfChannels) */ + } /* if (ui_Temp==1) */ else { printk("\nSpecified channel not supported \n"); - } // else if (ui_Temp==1) - } // else if (ui_Temp==0) + } /* else if (ui_Temp==1) */ + } /* else if (ui_Temp==0) */ return insn->n; } /* +----------------------------------------------------------------------------+ - | Function Name : INT i_APCI3200_ConfigAnalogInput | + | Function Name : int i_APCI3200_ConfigAnalogInput | | (struct comedi_device *dev,struct comedi_subdevice *s, | | struct comedi_insn *insn,unsigned int *data) | +----------------------------------------------------------------------------+ @@ -874,30 +867,30 @@ INT i_APCI3200_ReadDigitalOutput(struct comedi_device * dev, struct comedi_subde | | +----------------------------------------------------------------------------+ */ -INT i_APCI3200_ConfigAnalogInput(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI3200_ConfigAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - UINT ul_Config = 0, ul_Temp = 0; - UINT ui_ChannelNo = 0; - UINT ui_Dummy = 0; - INT i_err = 0; + unsigned int ul_Config = 0, ul_Temp = 0; + unsigned int ui_ChannelNo = 0; + unsigned int ui_Dummy = 0; + int i_err = 0; - //Begin JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values + /* Begin JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ #ifdef PRINT_INFO - INT i = 0, i2 = 0; + int i = 0, i2 = 0; #endif - //End JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values + /* End JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ - //BEGIN JK 06.07.04: Management of sevrals boards - // Initialize the structure + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* Initialize the structure */ if (s_BoardInfos[dev->minor].b_StructInitialized != 1) { s_BoardInfos[dev->minor].i_CJCAvailable = 1; s_BoardInfos[dev->minor].i_CJCPolarity = 0; - s_BoardInfos[dev->minor].i_CJCGain = 2; //changed from 0 to 2 + s_BoardInfos[dev->minor].i_CJCGain = 2; /* changed from 0 to 2 */ s_BoardInfos[dev->minor].i_InterruptFlag = 0; - s_BoardInfos[dev->minor].i_AutoCalibration = 0; //: auto calibration + s_BoardInfos[dev->minor].i_AutoCalibration = 0; /* : auto calibration */ s_BoardInfos[dev->minor].i_ChannelCount = 0; s_BoardInfos[dev->minor].i_Sum = 0; s_BoardInfos[dev->minor].ui_Channel_num = 0; @@ -905,11 +898,11 @@ INT i_APCI3200_ConfigAnalogInput(struct comedi_device * dev, struct comedi_subde s_BoardInfos[dev->minor].i_Initialised = 0; s_BoardInfos[dev->minor].b_StructInitialized = 1; - //Begin JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values + /* Begin JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ s_BoardInfos[dev->minor].i_ConnectionType = 0; - //End JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values + /* End JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ - //Begin JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values + /* Begin JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ memset(s_BoardInfos[dev->minor].s_Module, 0, sizeof(s_BoardInfos[dev->minor].s_Module[MAX_MODULE])); @@ -938,72 +931,72 @@ INT i_APCI3200_ConfigAnalogInput(struct comedi_device * dev, struct comedi_subde } } #endif - //End JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values + /* End JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ } if (data[0] != 0 && data[0] != 1 && data[0] != 2) { printk("\nThe selection of acquisition type is in error\n"); i_err++; - } //if(data[0]!=0 && data[0]!=1 && data[0]!=2) + } /* if(data[0]!=0 && data[0]!=1 && data[0]!=2) */ if (data[0] == 1) { if (data[14] != 0 && data[14] != 1 && data[14] != 2 && data[14] != 4) { printk("\n Error in selection of RTD connection type\n"); i_err++; - } //if(data[14]!=0 && data[14]!=1 && data[14]!=2 && data[14]!=4) - } //if(data[0]==1 ) + } /* if(data[14]!=0 && data[14]!=1 && data[14]!=2 && data[14]!=4) */ + } /* if(data[0]==1 ) */ if (data[1] < 0 || data[1] > 7) { printk("\nThe selection of gain is in error\n"); i_err++; - } // if(data[1]<0 || data[1]>7) + } /* if(data[1]<0 || data[1]>7) */ if (data[2] != 0 && data[2] != 1) { printk("\nThe selection of polarity is in error\n"); i_err++; - } //if(data[2]!=0 && data[2]!=1) + } /* if(data[2]!=0 && data[2]!=1) */ if (data[3] != 0) { printk("\nThe selection of offset range is in error\n"); i_err++; - } // if(data[3]!=0) + } /* if(data[3]!=0) */ if (data[4] != 0 && data[4] != 1) { printk("\nThe selection of coupling is in error\n"); i_err++; - } //if(data[4]!=0 && data[4]!=1) + } /* if(data[4]!=0 && data[4]!=1) */ if (data[5] != 0 && data[5] != 1) { printk("\nThe selection of single/differential mode is in error\n"); i_err++; - } //if(data[5]!=0 && data[5]!=1) + } /* if(data[5]!=0 && data[5]!=1) */ if (data[8] != 0 && data[8] != 1 && data[2] != 2) { printk("\nError in selection of functionality\n"); - } //if(data[8]!=0 && data[8]!=1 && data[2]!=2) + } /* if(data[8]!=0 && data[8]!=1 && data[2]!=2) */ if (data[12] == 0 || data[12] == 1) { if (data[6] != 20 && data[6] != 40 && data[6] != 80 && data[6] != 160) { printk("\nThe selection of conversion time reload value is in error\n"); i_err++; - } // if (data[6]!=20 && data[6]!=40 && data[6]!=80 && data[6]!=160 ) + } /* if (data[6]!=20 && data[6]!=40 && data[6]!=80 && data[6]!=160 ) */ if (data[7] != 2) { printk("\nThe selection of conversion time unit is in error\n"); i_err++; - } // if(data[7]!=2) + } /* if(data[7]!=2) */ } if (data[9] != 0 && data[9] != 1) { printk("\nThe selection of interrupt enable is in error\n"); i_err++; - } //if(data[9]!=0 && data[9]!=1) + } /* if(data[9]!=0 && data[9]!=1) */ if (data[11] < 0 || data[11] > 4) { printk("\nThe selection of module is in error\n"); i_err++; - } //if(data[11] <0 || data[11]>1) + } /* if(data[11] <0 || data[11]>1) */ if (data[12] < 0 || data[12] > 3) { printk("\nThe selection of singlechannel/scan selection is in error\n"); i_err++; - } //if(data[12] < 0 || data[12]> 3) + } /* if(data[12] < 0 || data[12]> 3) */ if (data[13] < 0 || data[13] > 16) { printk("\nThe selection of number of channels is in error\n"); i_err++; - } // if(data[13] <0 ||data[13] >15) + } /* if(data[13] <0 ||data[13] >15) */ - //BEGIN JK 06.07.04: Management of sevrals boards + /* BEGIN JK 06.07.04: Management of sevrals boards */ /* i_ChannelCount=data[13]; i_ScanType=data[12]; @@ -1014,7 +1007,7 @@ INT i_APCI3200_ConfigAnalogInput(struct comedi_device * dev, struct comedi_subde i_ADDIDATAType=data[0]; */ - // Save acquisition configuration for the actual board + /* Save acquisition configuration for the actual board */ s_BoardInfos[dev->minor].i_ChannelCount = data[13]; s_BoardInfos[dev->minor].i_ScanType = data[12]; s_BoardInfos[dev->minor].i_ADDIDATAPolarity = data[2]; @@ -1022,307 +1015,307 @@ INT i_APCI3200_ConfigAnalogInput(struct comedi_device * dev, struct comedi_subde s_BoardInfos[dev->minor].i_ADDIDATAConversionTime = data[6]; s_BoardInfos[dev->minor].i_ADDIDATAConversionTimeUnit = data[7]; s_BoardInfos[dev->minor].i_ADDIDATAType = data[0]; - //Begin JK 19.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 + /* Begin JK 19.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ s_BoardInfos[dev->minor].i_ConnectionType = data[5]; - //End JK 19.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 - //END JK 06.07.04: Management of sevrals boards + /* End JK 19.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ + /* END JK 06.07.04: Management of sevrals boards */ - //Begin JK 19.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 - memset(s_BoardInfos[dev->minor].ui_ScanValueArray, 0, (7 + 12) * sizeof(unsigned int)); // 7 is the maximal number of channels - //End JK 19.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 + /* Begin JK 19.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ + memset(s_BoardInfos[dev->minor].ui_ScanValueArray, 0, (7 + 12) * sizeof(unsigned int)); /* 7 is the maximal number of channels */ + /* End JK 19.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ - //BEGIN JK 02.07.04 : This while can't be do, it block the process when using severals boards - //while(i_InterruptFlag==1) + /* BEGIN JK 02.07.04 : This while can't be do, it block the process when using severals boards */ + /* while(i_InterruptFlag==1) */ while (s_BoardInfos[dev->minor].i_InterruptFlag == 1) { #ifndef MSXBOX udelay(1); #else - // In the case where the driver is compiled for the MSX-Box - // we used a printk to have a little delay because udelay - // seems to be broken under the MSX-Box. - // This solution hat to be studied. + /* In the case where the driver is compiled for the MSX-Box */ + /* we used a printk to have a little delay because udelay */ + /* seems to be broken under the MSX-Box. */ + /* This solution hat to be studied. */ printk(""); #endif } - //END JK 02.07.04 : This while can't be do, it block the process when using severals boards + /* END JK 02.07.04 : This while can't be do, it block the process when using severals boards */ - ui_ChannelNo = CR_CHAN(insn->chanspec); // get the channel - //BEGIN JK 06.07.04: Management of sevrals boards - //i_ChannelNo=ui_ChannelNo; - //ui_Channel_num =ui_ChannelNo; + ui_ChannelNo = CR_CHAN(insn->chanspec); /* get the channel */ + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* i_ChannelNo=ui_ChannelNo; */ + /* ui_Channel_num =ui_ChannelNo; */ s_BoardInfos[dev->minor].i_ChannelNo = ui_ChannelNo; s_BoardInfos[dev->minor].ui_Channel_num = ui_ChannelNo; - //END JK 06.07.04: Management of sevrals boards + /* END JK 06.07.04: Management of sevrals boards */ if (data[5] == 0) { if (ui_ChannelNo < 0 || ui_ChannelNo > 15) { printk("\nThe Selection of the channel is in error\n"); i_err++; - } // if(ui_ChannelNo<0 || ui_ChannelNo>15) - } //if(data[5]==0) + } /* if(ui_ChannelNo<0 || ui_ChannelNo>15) */ + } /* if(data[5]==0) */ else { if (data[14] == 2) { if (ui_ChannelNo < 0 || ui_ChannelNo > 3) { printk("\nThe Selection of the channel is in error\n"); i_err++; - } // if(ui_ChannelNo<0 || ui_ChannelNo>3) - } //if(data[14]==2) + } /* if(ui_ChannelNo<0 || ui_ChannelNo>3) */ + } /* if(data[14]==2) */ else { if (ui_ChannelNo < 0 || ui_ChannelNo > 7) { printk("\nThe Selection of the channel is in error\n"); i_err++; - } // if(ui_ChannelNo<0 || ui_ChannelNo>7) - } //elseif(data[14]==2) - } //elseif(data[5]==0) + } /* if(ui_ChannelNo<0 || ui_ChannelNo>7) */ + } /* elseif(data[14]==2) */ + } /* elseif(data[5]==0) */ if (data[12] == 0 || data[12] == 1) { switch (data[5]) { case 0: if (ui_ChannelNo >= 0 && ui_ChannelNo <= 3) { - //BEGIN JK 06.07.04: Management of sevrals boards - //i_Offset=0; + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* i_Offset=0; */ s_BoardInfos[dev->minor].i_Offset = 0; - //END JK 06.07.04: Management of sevrals boards - } //if(ui_ChannelNo >=0 && ui_ChannelNo <=3) + /* END JK 06.07.04: Management of sevrals boards */ + } /* if(ui_ChannelNo >=0 && ui_ChannelNo <=3) */ if (ui_ChannelNo >= 4 && ui_ChannelNo <= 7) { - //BEGIN JK 06.07.04: Management of sevrals boards - //i_Offset=64; + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* i_Offset=64; */ s_BoardInfos[dev->minor].i_Offset = 64; - //END JK 06.07.04: Management of sevrals boards - } //if(ui_ChannelNo >=4 && ui_ChannelNo <=7) + /* END JK 06.07.04: Management of sevrals boards */ + } /* if(ui_ChannelNo >=4 && ui_ChannelNo <=7) */ if (ui_ChannelNo >= 8 && ui_ChannelNo <= 11) { - //BEGIN JK 06.07.04: Management of sevrals boards - //i_Offset=128; + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* i_Offset=128; */ s_BoardInfos[dev->minor].i_Offset = 128; - //END JK 06.07.04: Management of sevrals boards - } //if(ui_ChannelNo >=8 && ui_ChannelNo <=11) + /* END JK 06.07.04: Management of sevrals boards */ + } /* if(ui_ChannelNo >=8 && ui_ChannelNo <=11) */ if (ui_ChannelNo >= 12 && ui_ChannelNo <= 15) { - //BEGIN JK 06.07.04: Management of sevrals boards - //i_Offset=192; + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* i_Offset=192; */ s_BoardInfos[dev->minor].i_Offset = 192; - //END JK 06.07.04: Management of sevrals boards - } //if(ui_ChannelNo >=12 && ui_ChannelNo <=15) + /* END JK 06.07.04: Management of sevrals boards */ + } /* if(ui_ChannelNo >=12 && ui_ChannelNo <=15) */ break; case 1: if (data[14] == 2) { if (ui_ChannelNo == 0) { - //BEGIN JK 06.07.04: Management of sevrals boards - //i_Offset=0; + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* i_Offset=0; */ s_BoardInfos[dev->minor].i_Offset = 0; - //END JK 06.07.04: Management of sevrals boards - } //if(ui_ChannelNo ==0 ) + /* END JK 06.07.04: Management of sevrals boards */ + } /* if(ui_ChannelNo ==0 ) */ if (ui_ChannelNo == 1) { - //BEGIN JK 06.07.04: Management of sevrals boards - //i_Offset=0; + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* i_Offset=0; */ s_BoardInfos[dev->minor].i_Offset = 64; - //END JK 06.07.04: Management of sevrals boards - } // if(ui_ChannelNo ==1) + /* END JK 06.07.04: Management of sevrals boards */ + } /* if(ui_ChannelNo ==1) */ if (ui_ChannelNo == 2) { - //BEGIN JK 06.07.04: Management of sevrals boards - //i_Offset=128; + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* i_Offset=128; */ s_BoardInfos[dev->minor].i_Offset = 128; - //END JK 06.07.04: Management of sevrals boards - } //if(ui_ChannelNo ==2 ) + /* END JK 06.07.04: Management of sevrals boards */ + } /* if(ui_ChannelNo ==2 ) */ if (ui_ChannelNo == 3) { - //BEGIN JK 06.07.04: Management of sevrals boards - //i_Offset=192; + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* i_Offset=192; */ s_BoardInfos[dev->minor].i_Offset = 192; - //END JK 06.07.04: Management of sevrals boards - } //if(ui_ChannelNo ==3) + /* END JK 06.07.04: Management of sevrals boards */ + } /* if(ui_ChannelNo ==3) */ - //BEGIN JK 06.07.04: Management of sevrals boards - //i_ChannelNo=0; + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* i_ChannelNo=0; */ s_BoardInfos[dev->minor].i_ChannelNo = 0; - //END JK 06.07.04: Management of sevrals boards + /* END JK 06.07.04: Management of sevrals boards */ ui_ChannelNo = 0; break; - } //if(data[14]==2) + } /* if(data[14]==2) */ if (ui_ChannelNo >= 0 && ui_ChannelNo <= 1) { - //BEGIN JK 06.07.04: Management of sevrals boards - //i_Offset=0; + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* i_Offset=0; */ s_BoardInfos[dev->minor].i_Offset = 0; - //END JK 06.07.04: Management of sevrals boards - } //if(ui_ChannelNo >=0 && ui_ChannelNo <=1) + /* END JK 06.07.04: Management of sevrals boards */ + } /* if(ui_ChannelNo >=0 && ui_ChannelNo <=1) */ if (ui_ChannelNo >= 2 && ui_ChannelNo <= 3) { - //BEGIN JK 06.07.04: Management of sevrals boards - //i_ChannelNo=i_ChannelNo-2; - //i_Offset=64; + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* i_ChannelNo=i_ChannelNo-2; */ + /* i_Offset=64; */ s_BoardInfos[dev->minor].i_ChannelNo = s_BoardInfos[dev->minor].i_ChannelNo - 2; s_BoardInfos[dev->minor].i_Offset = 64; - //END JK 06.07.04: Management of sevrals boards + /* END JK 06.07.04: Management of sevrals boards */ ui_ChannelNo = ui_ChannelNo - 2; - } //if(ui_ChannelNo >=2 && ui_ChannelNo <=3) + } /* if(ui_ChannelNo >=2 && ui_ChannelNo <=3) */ if (ui_ChannelNo >= 4 && ui_ChannelNo <= 5) { - //BEGIN JK 06.07.04: Management of sevrals boards - //i_ChannelNo=i_ChannelNo-4; - //i_Offset=128; + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* i_ChannelNo=i_ChannelNo-4; */ + /* i_Offset=128; */ s_BoardInfos[dev->minor].i_ChannelNo = s_BoardInfos[dev->minor].i_ChannelNo - 4; s_BoardInfos[dev->minor].i_Offset = 128; - //END JK 06.07.04: Management of sevrals boards + /* END JK 06.07.04: Management of sevrals boards */ ui_ChannelNo = ui_ChannelNo - 4; - } //if(ui_ChannelNo >=4 && ui_ChannelNo <=5) + } /* if(ui_ChannelNo >=4 && ui_ChannelNo <=5) */ if (ui_ChannelNo >= 6 && ui_ChannelNo <= 7) { - //BEGIN JK 06.07.04: Management of sevrals boards - //i_ChannelNo=i_ChannelNo-6; - //i_Offset=192; + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* i_ChannelNo=i_ChannelNo-6; */ + /* i_Offset=192; */ s_BoardInfos[dev->minor].i_ChannelNo = s_BoardInfos[dev->minor].i_ChannelNo - 6; s_BoardInfos[dev->minor].i_Offset = 192; - //END JK 06.07.04: Management of sevrals boards + /* END JK 06.07.04: Management of sevrals boards */ ui_ChannelNo = ui_ChannelNo - 6; - } //if(ui_ChannelNo >=6 && ui_ChannelNo <=7) + } /* if(ui_ChannelNo >=6 && ui_ChannelNo <=7) */ break; default: printk("\n This selection of polarity does not exist\n"); i_err++; - } //switch(data[2]) - } //if(data[12]==0 || data[12]==1) + } /* switch(data[2]) */ + } /* if(data[12]==0 || data[12]==1) */ else { switch (data[11]) { case 1: - //BEGIN JK 06.07.04: Management of sevrals boards - //i_Offset=0; + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* i_Offset=0; */ s_BoardInfos[dev->minor].i_Offset = 0; - //END JK 06.07.04: Management of sevrals boards + /* END JK 06.07.04: Management of sevrals boards */ break; case 2: - //BEGIN JK 06.07.04: Management of sevrals boards - //i_Offset=64; + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* i_Offset=64; */ s_BoardInfos[dev->minor].i_Offset = 64; - //END JK 06.07.04: Management of sevrals boards + /* END JK 06.07.04: Management of sevrals boards */ break; case 3: - //BEGIN JK 06.07.04: Management of sevrals boards - //i_Offset=128; + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* i_Offset=128; */ s_BoardInfos[dev->minor].i_Offset = 128; - //END JK 06.07.04: Management of sevrals boards + /* END JK 06.07.04: Management of sevrals boards */ break; case 4: - //BEGIN JK 06.07.04: Management of sevrals boards - //i_Offset=192; + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* i_Offset=192; */ s_BoardInfos[dev->minor].i_Offset = 192; - //END JK 06.07.04: Management of sevrals boards + /* END JK 06.07.04: Management of sevrals boards */ break; default: printk("\nError in module selection\n"); i_err++; - } // switch(data[11]) - } // elseif(data[12]==0 || data[12]==1) + } /* switch(data[11]) */ + } /* elseif(data[12]==0 || data[12]==1) */ if (i_err) { i_APCI3200_Reset(dev); return -EINVAL; } - //if(i_ScanType!=1) + /* if(i_ScanType!=1) */ if (s_BoardInfos[dev->minor].i_ScanType != 1) { - //BEGIN JK 06.07.04: Management of sevrals boards - //i_Count=0; - //i_Sum=0; + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* i_Count=0; */ + /* i_Sum=0; */ s_BoardInfos[dev->minor].i_Count = 0; s_BoardInfos[dev->minor].i_Sum = 0; - //END JK 06.07.04: Management of sevrals boards - } //if(i_ScanType!=1) + /* END JK 06.07.04: Management of sevrals boards */ + } /* if(i_ScanType!=1) */ ul_Config = data[1] | (data[2] << 6) | (data[5] << 7) | (data[3] << 8) | (data[4] << 9); - //BEGIN JK 06.07.04: Management of sevrals boards - //while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12) >> 19) & 1) != 1) ; - //END JK 06.07.04: Management of sevrals boards + /* END JK 06.07.04: Management of sevrals boards */ /*********************************/ /* Write the channel to configure */ /*********************************/ - //BEGIN JK 06.07.04: Management of sevrals boards - //outl(0 | ui_ChannelNo , devpriv->iobase+i_Offset + 0x4); + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* outl(0 | ui_ChannelNo , devpriv->iobase+i_Offset + 0x4); */ outl(0 | ui_ChannelNo, devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 0x4); - //END JK 06.07.04: Management of sevrals boards + /* END JK 06.07.04: Management of sevrals boards */ - //BEGIN JK 06.07.04: Management of sevrals boards - //while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12) >> 19) & 1) != 1) ; - //END JK 06.07.04: Management of sevrals boards + /* END JK 06.07.04: Management of sevrals boards */ /**************************/ /* Reset the configuration */ /**************************/ - //BEGIN JK 06.07.04: Management of sevrals boards - //outl(0 , devpriv->iobase+i_Offset + 0x0); + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* outl(0 , devpriv->iobase+i_Offset + 0x0); */ outl(0, devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 0x0); - //END JK 06.07.04: Management of sevrals boards + /* END JK 06.07.04: Management of sevrals boards */ - //BEGIN JK 06.07.04: Management of sevrals boards - //while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12) >> 19) & 1) != 1) ; - //END JK 06.07.04: Management of sevrals boards + /* END JK 06.07.04: Management of sevrals boards */ /***************************/ /* Write the configuration */ /***************************/ - //BEGIN JK 06.07.04: Management of sevrals boards - //outl(ul_Config , devpriv->iobase+i_Offset + 0x0); + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* outl(ul_Config , devpriv->iobase+i_Offset + 0x0); */ outl(ul_Config, devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 0x0); - //END JK 06.07.04: Management of sevrals boards + /* END JK 06.07.04: Management of sevrals boards */ /***************************/ /*Reset the calibration bit */ /***************************/ - //BEGIN JK 06.07.04: Management of sevrals boards - //ul_Temp = inl(devpriv->iobase+i_Offset + 12); + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* ul_Temp = inl(devpriv->iobase+i_Offset + 12); */ ul_Temp = inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12); - //END JK 06.07.04: Management of sevrals boards + /* END JK 06.07.04: Management of sevrals boards */ - //BEGIN JK 06.07.04: Management of sevrals boards - //while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12) >> 19) & 1) != 1) ; - //END JK 06.07.04: Management of sevrals boards + /* END JK 06.07.04: Management of sevrals boards */ - //BEGIN JK 06.07.04: Management of sevrals boards - //outl((ul_Temp & 0xFFF9FFFF) , devpriv->iobase+.i_Offset + 12); + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* outl((ul_Temp & 0xFFF9FFFF) , devpriv->iobase+.i_Offset + 12); */ outl((ul_Temp & 0xFFF9FFFF), devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12); - //END JK 06.07.04: Management of sevrals boards + /* END JK 06.07.04: Management of sevrals boards */ if (data[9] == 1) { devpriv->tsk_Current = current; - //BEGIN JK 06.07.04: Management of sevrals boards - //i_InterruptFlag=1; + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* i_InterruptFlag=1; */ s_BoardInfos[dev->minor].i_InterruptFlag = 1; - //END JK 06.07.04: Management of sevrals boards - } // if(data[9]==1) + /* END JK 06.07.04: Management of sevrals boards */ + } /* if(data[9]==1) */ else { - //BEGIN JK 06.07.04: Management of sevrals boards - //i_InterruptFlag=0; + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* i_InterruptFlag=0; */ s_BoardInfos[dev->minor].i_InterruptFlag = 0; - //END JK 06.07.04: Management of sevrals boards - } //else if(data[9]==1) + /* END JK 06.07.04: Management of sevrals boards */ + } /* else if(data[9]==1) */ - //BEGIN JK 06.07.04: Management of sevrals boards - //i_Initialised=1; + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* i_Initialised=1; */ s_BoardInfos[dev->minor].i_Initialised = 1; - //END JK 06.07.04: Management of sevrals boards + /* END JK 06.07.04: Management of sevrals boards */ - //BEGIN JK 06.07.04: Management of sevrals boards - //if(i_ScanType==1) + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* if(i_ScanType==1) */ if (s_BoardInfos[dev->minor].i_ScanType == 1) - //END JK 06.07.04: Management of sevrals boards + /* END JK 06.07.04: Management of sevrals boards */ { - //BEGIN JK 06.07.04: Management of sevrals boards - //i_Sum=i_Sum+1; + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* i_Sum=i_Sum+1; */ s_BoardInfos[dev->minor].i_Sum = s_BoardInfos[dev->minor].i_Sum + 1; - //END JK 06.07.04: Management of sevrals boards + /* END JK 06.07.04: Management of sevrals boards */ insn->unused[0] = 0; i_APCI3200_ReadAnalogInput(dev, s, insn, &ui_Dummy); @@ -1340,8 +1333,8 @@ INT i_APCI3200_ConfigAnalogInput(struct comedi_device * dev, struct comedi_subde | Task : Read value of the selected channel | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | - | UINT ui_NoOfChannels : No Of Channels To read | - | UINT *data : Data Pointer to read status | + | unsigned int ui_NoOfChannels : No Of Channels To read | + | unsigned int *data : Data Pointer to read status | +----------------------------------------------------------------------------+ | Output Parameters : -- | | data[0] : Digital Value Of Input | @@ -1361,21 +1354,21 @@ INT i_APCI3200_ConfigAnalogInput(struct comedi_device * dev, struct comedi_subde | | +----------------------------------------------------------------------------+ */ -INT i_APCI3200_ReadAnalogInput(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI3200_ReadAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - UINT ui_DummyValue = 0; + unsigned int ui_DummyValue = 0; int i_ConvertCJCCalibration; int i = 0; - //BEGIN JK 06.07.04: Management of sevrals boards - //if(i_Initialised==0) + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* if(i_Initialised==0) */ if (s_BoardInfos[dev->minor].i_Initialised == 0) - //END JK 06.07.04: Management of sevrals boards + /* END JK 06.07.04: Management of sevrals boards */ { i_APCI3200_Reset(dev); return -EINVAL; - } //if(i_Initialised==0); + } /* if(i_Initialised==0); */ #ifdef PRINT_INFO printk("\n insn->unused[0] = %i", insn->unused[0]); @@ -1386,14 +1379,14 @@ INT i_APCI3200_ReadAnalogInput(struct comedi_device * dev, struct comedi_subdevi i_APCI3200_Read1AnalogInputChannel(dev, s, insn, &ui_DummyValue); - //BEGIN JK 06.07.04: Management of sevrals boards - //ui_InterruptChannelValue[i_Count+0]=ui_DummyValue; + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* ui_InterruptChannelValue[i_Count+0]=ui_DummyValue; */ s_BoardInfos[dev->minor]. ui_InterruptChannelValue[s_BoardInfos[dev->minor]. i_Count + 0] = ui_DummyValue; - //END JK 06.07.04: Management of sevrals boards + /* END JK 06.07.04: Management of sevrals boards */ - //Begin JK 25.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values + /* Begin JK 25.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ i_APCI3200_GetChannelCalibrationValue(dev, s_BoardInfos[dev->minor].ui_Channel_num, &s_BoardInfos[dev->minor]. @@ -1414,62 +1407,62 @@ INT i_APCI3200_ReadAnalogInput(struct comedi_device * dev, struct comedi_subdevi printk("\n s_BoardInfos [dev->minor].ui_InterruptChannelValue[s_BoardInfos [dev->minor].i_Count+8] = %lu", s_BoardInfos[dev->minor].ui_InterruptChannelValue[s_BoardInfos[dev->minor].i_Count + 8]); #endif - //End JK 25.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values + /* End JK 25.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ - //BEGIN JK 06.07.04: Management of sevrals boards - //if((i_ADDIDATAType==2) && (i_InterruptFlag == FALSE) && (i_CJCAvailable==1)) + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* if((i_ADDIDATAType==2) && (i_InterruptFlag == FALSE) && (i_CJCAvailable==1)) */ if ((s_BoardInfos[dev->minor].i_ADDIDATAType == 2) && (s_BoardInfos[dev->minor].i_InterruptFlag == FALSE) && (s_BoardInfos[dev->minor].i_CJCAvailable == 1)) - //END JK 06.07.04: Management of sevrals boards + /* END JK 06.07.04: Management of sevrals boards */ { i_APCI3200_ReadCJCValue(dev, &ui_DummyValue); - //BEGIN JK 06.07.04: Management of sevrals boards - //ui_InterruptChannelValue[i_Count + 3]=ui_DummyValue; + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* ui_InterruptChannelValue[i_Count + 3]=ui_DummyValue; */ s_BoardInfos[dev->minor]. ui_InterruptChannelValue[s_BoardInfos[dev-> minor].i_Count + 3] = ui_DummyValue; - //END JK 06.07.04: Management of sevrals boards - } //if((i_ADDIDATAType==2) && (i_InterruptFlag == FALSE)) + /* END JK 06.07.04: Management of sevrals boards */ + } /* if((i_ADDIDATAType==2) && (i_InterruptFlag == FALSE)) */ else { - //BEGIN JK 06.07.04: Management of sevrals boards - //ui_InterruptChannelValue[i_Count + 3]=0; + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* ui_InterruptChannelValue[i_Count + 3]=0; */ s_BoardInfos[dev->minor]. ui_InterruptChannelValue[s_BoardInfos[dev-> minor].i_Count + 3] = 0; - //END JK 06.07.04: Management of sevrals boards - } //elseif((i_ADDIDATAType==2) && (i_InterruptFlag == FALSE) && (i_CJCAvailable==1)) + /* END JK 06.07.04: Management of sevrals boards */ + } /* elseif((i_ADDIDATAType==2) && (i_InterruptFlag == FALSE) && (i_CJCAvailable==1)) */ - //BEGIN JK 06.07.04: Management of sevrals boards - //if (( i_AutoCalibration == FALSE) && (i_InterruptFlag == FALSE)) + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* if (( i_AutoCalibration == FALSE) && (i_InterruptFlag == FALSE)) */ if ((s_BoardInfos[dev->minor].i_AutoCalibration == FALSE) && (s_BoardInfos[dev->minor].i_InterruptFlag == FALSE)) - //END JK 06.07.04: Management of sevrals boards + /* END JK 06.07.04: Management of sevrals boards */ { i_APCI3200_ReadCalibrationOffsetValue(dev, &ui_DummyValue); - //BEGIN JK 06.07.04: Management of sevrals boards - //ui_InterruptChannelValue[i_Count + 1]=ui_DummyValue; + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* ui_InterruptChannelValue[i_Count + 1]=ui_DummyValue; */ s_BoardInfos[dev->minor]. ui_InterruptChannelValue[s_BoardInfos[dev-> minor].i_Count + 1] = ui_DummyValue; - //END JK 06.07.04: Management of sevrals boards + /* END JK 06.07.04: Management of sevrals boards */ i_APCI3200_ReadCalibrationGainValue(dev, &ui_DummyValue); - //BEGIN JK 06.07.04: Management of sevrals boards - //ui_InterruptChannelValue[i_Count + 2]=ui_DummyValue; + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* ui_InterruptChannelValue[i_Count + 2]=ui_DummyValue; */ s_BoardInfos[dev->minor]. ui_InterruptChannelValue[s_BoardInfos[dev-> minor].i_Count + 2] = ui_DummyValue; - //END JK 06.07.04: Management of sevrals boards - } //if (( i_AutoCalibration == FALSE) && (i_InterruptFlag == FALSE)) + /* END JK 06.07.04: Management of sevrals boards */ + } /* if (( i_AutoCalibration == FALSE) && (i_InterruptFlag == FALSE)) */ - //BEGIN JK 06.07.04: Management of sevrals boards - //if((i_ADDIDATAType==2) && (i_InterruptFlag == FALSE)&& (i_CJCAvailable==1)) + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* if((i_ADDIDATAType==2) && (i_InterruptFlag == FALSE)&& (i_CJCAvailable==1)) */ if ((s_BoardInfos[dev->minor].i_ADDIDATAType == 2) && (s_BoardInfos[dev->minor].i_InterruptFlag == FALSE) && (s_BoardInfos[dev->minor].i_CJCAvailable == 1)) - //END JK 06.07.04: Management of sevrals boards + /* END JK 06.07.04: Management of sevrals boards */ { /**********************************************************/ /*Test if the Calibration channel must be read for the CJC */ @@ -1477,52 +1470,52 @@ INT i_APCI3200_ReadAnalogInput(struct comedi_device * dev, struct comedi_subdevi /**********************************/ /*Test if the polarity is the same */ /**********************************/ - //BEGIN JK 06.07.04: Management of sevrals boards - //if(i_CJCPolarity!=i_ADDIDATAPolarity) + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* if(i_CJCPolarity!=i_ADDIDATAPolarity) */ if (s_BoardInfos[dev->minor].i_CJCPolarity != s_BoardInfos[dev->minor].i_ADDIDATAPolarity) - //END JK 06.07.04: Management of sevrals boards + /* END JK 06.07.04: Management of sevrals boards */ { i_ConvertCJCCalibration = 1; - } //if(i_CJCPolarity!=i_ADDIDATAPolarity) + } /* if(i_CJCPolarity!=i_ADDIDATAPolarity) */ else { - //BEGIN JK 06.07.04: Management of sevrals boards - //if(i_CJCGain==i_ADDIDATAGain) + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* if(i_CJCGain==i_ADDIDATAGain) */ if (s_BoardInfos[dev->minor].i_CJCGain == s_BoardInfos[dev->minor].i_ADDIDATAGain) - //END JK 06.07.04: Management of sevrals boards + /* END JK 06.07.04: Management of sevrals boards */ { i_ConvertCJCCalibration = 0; - } //if(i_CJCGain==i_ADDIDATAGain) + } /* if(i_CJCGain==i_ADDIDATAGain) */ else { i_ConvertCJCCalibration = 1; - } //elseif(i_CJCGain==i_ADDIDATAGain) - } //elseif(i_CJCPolarity!=i_ADDIDATAPolarity) + } /* elseif(i_CJCGain==i_ADDIDATAGain) */ + } /* elseif(i_CJCPolarity!=i_ADDIDATAPolarity) */ if (i_ConvertCJCCalibration == 1) { i_APCI3200_ReadCJCCalOffset(dev, &ui_DummyValue); - //BEGIN JK 06.07.04: Management of sevrals boards - //ui_InterruptChannelValue[i_Count+4]=ui_DummyValue; + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* ui_InterruptChannelValue[i_Count+4]=ui_DummyValue; */ s_BoardInfos[dev->minor]. ui_InterruptChannelValue[s_BoardInfos [dev->minor].i_Count + 4] = ui_DummyValue; - //END JK 06.07.04: Management of sevrals boards + /* END JK 06.07.04: Management of sevrals boards */ i_APCI3200_ReadCJCCalGain(dev, &ui_DummyValue); - //BEGIN JK 06.07.04: Management of sevrals boards - //ui_InterruptChannelValue[i_Count+5]=ui_DummyValue; + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* ui_InterruptChannelValue[i_Count+5]=ui_DummyValue; */ s_BoardInfos[dev->minor]. ui_InterruptChannelValue[s_BoardInfos [dev->minor].i_Count + 5] = ui_DummyValue; - //END JK 06.07.04: Management of sevrals boards - } //if(i_ConvertCJCCalibration==1) + /* END JK 06.07.04: Management of sevrals boards */ + } /* if(i_ConvertCJCCalibration==1) */ else { - //BEGIN JK 06.07.04: Management of sevrals boards - //ui_InterruptChannelValue[i_Count+4]=0; - //ui_InterruptChannelValue[i_Count+5]=0; + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* ui_InterruptChannelValue[i_Count+4]=0; */ + /* ui_InterruptChannelValue[i_Count+5]=0; */ s_BoardInfos[dev->minor]. ui_InterruptChannelValue[s_BoardInfos @@ -1530,36 +1523,36 @@ INT i_APCI3200_ReadAnalogInput(struct comedi_device * dev, struct comedi_subdevi s_BoardInfos[dev->minor]. ui_InterruptChannelValue[s_BoardInfos [dev->minor].i_Count + 5] = 0; - //END JK 06.07.04: Management of sevrals boards - } //elseif(i_ConvertCJCCalibration==1) - } //if((i_ADDIDATAType==2) && (i_InterruptFlag == FALSE)) + /* END JK 06.07.04: Management of sevrals boards */ + } /* elseif(i_ConvertCJCCalibration==1) */ + } /* if((i_ADDIDATAType==2) && (i_InterruptFlag == FALSE)) */ - //BEGIN JK 06.07.04: Management of sevrals boards - //if(i_ScanType!=1) + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* if(i_ScanType!=1) */ if (s_BoardInfos[dev->minor].i_ScanType != 1) { - //i_Count=0; + /* i_Count=0; */ s_BoardInfos[dev->minor].i_Count = 0; - } //if(i_ScanType!=1) + } /* if(i_ScanType!=1) */ else { - //i_Count=i_Count +6; - //Begin JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values - //s_BoardInfos [dev->minor].i_Count=s_BoardInfos [dev->minor].i_Count +6; + /* i_Count=i_Count +6; */ + /* Begin JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ + /* s_BoardInfos [dev->minor].i_Count=s_BoardInfos [dev->minor].i_Count +6; */ s_BoardInfos[dev->minor].i_Count = s_BoardInfos[dev->minor].i_Count + 9; - //End JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values - } //else if(i_ScanType!=1) + /* End JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ + } /* else if(i_ScanType!=1) */ - //if((i_ScanType==1) &&(i_InterruptFlag==1)) + /* if((i_ScanType==1) &&(i_InterruptFlag==1)) */ if ((s_BoardInfos[dev->minor].i_ScanType == 1) && (s_BoardInfos[dev->minor].i_InterruptFlag == 1)) { - //i_Count=i_Count-6; - //Begin JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values - //s_BoardInfos [dev->minor].i_Count=s_BoardInfos [dev->minor].i_Count-6; + /* i_Count=i_Count-6; */ + /* Begin JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ + /* s_BoardInfos [dev->minor].i_Count=s_BoardInfos [dev->minor].i_Count-6; */ s_BoardInfos[dev->minor].i_Count = s_BoardInfos[dev->minor].i_Count - 9; - //End JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values + /* End JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ } - //if(i_ScanType==0) + /* if(i_ScanType==0) */ if (s_BoardInfos[dev->minor].i_ScanType == 0) { /* data[0]= ui_InterruptChannelValue[0]; @@ -1591,41 +1584,41 @@ INT i_APCI3200_ReadAnalogInput(struct comedi_device * dev, struct comedi_subdevi s_BoardInfos[dev->minor]. ui_InterruptChannelValue[5]; - //Begin JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values - //printk("\n 0 - i_APCI3200_GetChannelCalibrationValue data [6] = %lu, data [7] = %lu, data [8] = %lu", data [6], data [7], data [8]); + /* Begin JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ + /* printk("\n 0 - i_APCI3200_GetChannelCalibrationValue data [6] = %lu, data [7] = %lu, data [8] = %lu", data [6], data [7], data [8]); */ i_APCI3200_GetChannelCalibrationValue(dev, s_BoardInfos[dev->minor].ui_Channel_num, &data[6], &data[7], &data[8]); - //End JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values + /* End JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ } break; case 1: for (i = 0; i < insn->n; i++) { - //data[i]=ui_InterruptChannelValue[i]; + /* data[i]=ui_InterruptChannelValue[i]; */ data[i] = s_BoardInfos[dev->minor]. ui_InterruptChannelValue[i]; } - //i_Count=0; - //i_Sum=0; - //if(i_ScanType==1) + /* i_Count=0; */ + /* i_Sum=0; */ + /* if(i_ScanType==1) */ s_BoardInfos[dev->minor].i_Count = 0; s_BoardInfos[dev->minor].i_Sum = 0; if (s_BoardInfos[dev->minor].i_ScanType == 1) { - //i_Initialised=0; - //i_InterruptFlag=0; + /* i_Initialised=0; */ + /* i_InterruptFlag=0; */ s_BoardInfos[dev->minor].i_Initialised = 0; s_BoardInfos[dev->minor].i_InterruptFlag = 0; - //END JK 06.07.04: Management of sevrals boards + /* END JK 06.07.04: Management of sevrals boards */ } break; default: printk("\nThe parameters passed are in error\n"); i_APCI3200_Reset(dev); return -EINVAL; - } //switch(insn->unused[0]) + } /* switch(insn->unused[0]) */ return insn->n; } @@ -1639,8 +1632,8 @@ INT i_APCI3200_ReadAnalogInput(struct comedi_device * dev, struct comedi_subdevi | Task : Read value of the selected channel | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | - | UINT ui_NoOfChannel : Channel No to read | - | UINT *data : Data Pointer to read status | + | unsigned int ui_NoOfChannel : Channel No to read | + | unsigned int *data : Data Pointer to read status | +----------------------------------------------------------------------------+ | Output Parameters : -- | | data[0] : Digital Value read | @@ -1651,49 +1644,49 @@ INT i_APCI3200_ReadAnalogInput(struct comedi_device * dev, struct comedi_subdevi | | +----------------------------------------------------------------------------+ */ -INT i_APCI3200_Read1AnalogInputChannel(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +int i_APCI3200_Read1AnalogInputChannel(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - UINT ui_EOC = 0; - UINT ui_ChannelNo = 0; - UINT ui_CommandRegister = 0; + unsigned int ui_EOC = 0; + unsigned int ui_ChannelNo = 0; + unsigned int ui_CommandRegister = 0; - //BEGIN JK 06.07.04: Management of sevrals boards - //ui_ChannelNo=i_ChannelNo; + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* ui_ChannelNo=i_ChannelNo; */ ui_ChannelNo = s_BoardInfos[dev->minor].i_ChannelNo; - //while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); + /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12) >> 19) & 1) != 1) ; /*********************************/ /* Write the channel to configure */ /*********************************/ - //Begin JK 20.10.2004: Bad channel value is used when using differential mode - //outl(0 | ui_Channel_num , devpriv->iobase+i_Offset + 0x4); - //outl(0 | s_BoardInfos [dev->minor].ui_Channel_num , devpriv->iobase+s_BoardInfos [dev->minor].i_Offset + 0x4); + /* Begin JK 20.10.2004: Bad channel value is used when using differential mode */ + /* outl(0 | ui_Channel_num , devpriv->iobase+i_Offset + 0x4); */ + /* outl(0 | s_BoardInfos [dev->minor].ui_Channel_num , devpriv->iobase+s_BoardInfos [dev->minor].i_Offset + 0x4); */ outl(0 | s_BoardInfos[dev->minor].i_ChannelNo, devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 0x4); - //End JK 20.10.2004: Bad channel value is used when using differential mode + /* End JK 20.10.2004: Bad channel value is used when using differential mode */ /*******************************/ /* Set the convert timing unit */ /*******************************/ - //while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); + /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12) >> 19) & 1) != 1) ; - //outl(i_ADDIDATAConversionTimeUnit , devpriv->iobase+i_Offset + 36); + /* outl(i_ADDIDATAConversionTimeUnit , devpriv->iobase+i_Offset + 36); */ outl(s_BoardInfos[dev->minor].i_ADDIDATAConversionTimeUnit, devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 36); /**************************/ /* Set the convert timing */ /**************************/ - //while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); + /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12) >> 19) & 1) != 1) ; - //outl(i_ADDIDATAConversionTime , devpriv->iobase+i_Offset + 32); + /* outl(i_ADDIDATAConversionTime , devpriv->iobase+i_Offset + 32); */ outl(s_BoardInfos[dev->minor].i_ADDIDATAConversionTime, devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 32); @@ -1707,36 +1700,36 @@ INT i_APCI3200_Read1AnalogInputChannel(struct comedi_device * dev, /*Test if the interrupt is enable */ /*********************************/ - //if (i_InterruptFlag == ADDIDATA_ENABLE) + /* if (i_InterruptFlag == ADDIDATA_ENABLE) */ if (s_BoardInfos[dev->minor].i_InterruptFlag == ADDIDATA_ENABLE) { /************************/ /* Enable the interrupt */ /************************/ ui_CommandRegister = ui_CommandRegister | 0x00100000; - } //if (i_InterruptFlag == ADDIDATA_ENABLE) + } /* if (i_InterruptFlag == ADDIDATA_ENABLE) */ /******************************/ /* Write the command register */ /******************************/ - //while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); + /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12) >> 19) & 1) != 1) ; - //outl(ui_CommandRegister, devpriv->iobase+i_Offset + 8); + /* outl(ui_CommandRegister, devpriv->iobase+i_Offset + 8); */ outl(ui_CommandRegister, devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 8); /*****************************/ /*Test if interrupt is enable */ /*****************************/ - //if (i_InterruptFlag == ADDIDATA_DISABLE) + /* if (i_InterruptFlag == ADDIDATA_DISABLE) */ if (s_BoardInfos[dev->minor].i_InterruptFlag == ADDIDATA_DISABLE) { do { /*************************/ /*Read the EOC Status bit */ /*************************/ - //ui_EOC = inl(devpriv->iobase+i_Offset + 20) & 1; + /* ui_EOC = inl(devpriv->iobase+i_Offset + 20) & 1; */ ui_EOC = inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 20) & 1; @@ -1746,13 +1739,13 @@ INT i_APCI3200_Read1AnalogInputChannel(struct comedi_device * dev, /* Read the digital value of the input */ /***************************************/ - //data[0] = inl (devpriv->iobase+i_Offset + 28); + /* data[0] = inl (devpriv->iobase+i_Offset + 28); */ data[0] = inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 28); - //END JK 06.07.04: Management of sevrals boards + /* END JK 06.07.04: Management of sevrals boards */ - } // if (i_InterruptFlag == ADDIDATA_DISABLE) + } /* if (i_InterruptFlag == ADDIDATA_DISABLE) */ return 0; } @@ -1765,7 +1758,7 @@ INT i_APCI3200_Read1AnalogInputChannel(struct comedi_device * dev, | Task : Read calibration offset value of the selected channel| +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | - | UINT *data : Data Pointer to read status | + | unsigned int *data : Data Pointer to read status | +----------------------------------------------------------------------------+ | Output Parameters : -- | | data[0] : Calibration offset Value | @@ -1776,54 +1769,54 @@ INT i_APCI3200_Read1AnalogInputChannel(struct comedi_device * dev, | | +----------------------------------------------------------------------------+ */ -int i_APCI3200_ReadCalibrationOffsetValue(struct comedi_device * dev, UINT * data) +int i_APCI3200_ReadCalibrationOffsetValue(struct comedi_device *dev, unsigned int *data) { - UINT ui_Temp = 0, ui_EOC = 0; - UINT ui_CommandRegister = 0; + unsigned int ui_Temp = 0, ui_EOC = 0; + unsigned int ui_CommandRegister = 0; - //BEGIN JK 06.07.04: Management of sevrals boards - //while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12) >> 19) & 1) != 1) ; /*********************************/ /* Write the channel to configure */ /*********************************/ - //Begin JK 20.10.2004: This seems not necessary ! - //outl(0 | ui_Channel_num , devpriv->iobase+i_Offset + 0x4); - //outl(0 | s_BoardInfos [dev->minor].ui_Channel_num , devpriv->iobase+s_BoardInfos [dev->minor].i_Offset + 0x4); - //End JK 20.10.2004: This seems not necessary ! + /* Begin JK 20.10.2004: This seems not necessary ! */ + /* outl(0 | ui_Channel_num , devpriv->iobase+i_Offset + 0x4); */ + /* outl(0 | s_BoardInfos [dev->minor].ui_Channel_num , devpriv->iobase+s_BoardInfos [dev->minor].i_Offset + 0x4); */ + /* End JK 20.10.2004: This seems not necessary ! */ /*******************************/ /* Set the convert timing unit */ /*******************************/ - //while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); + /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12) >> 19) & 1) != 1) ; - //outl(i_ADDIDATAConversionTimeUnit , devpriv->iobase+i_Offset + 36); + /* outl(i_ADDIDATAConversionTimeUnit , devpriv->iobase+i_Offset + 36); */ outl(s_BoardInfos[dev->minor].i_ADDIDATAConversionTimeUnit, devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 36); /**************************/ /* Set the convert timing */ /**************************/ - //while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); + /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12) >> 19) & 1) != 1) ; - //outl(i_ADDIDATAConversionTime , devpriv->iobase+i_Offset + 32); + /* outl(i_ADDIDATAConversionTime , devpriv->iobase+i_Offset + 32); */ outl(s_BoardInfos[dev->minor].i_ADDIDATAConversionTime, devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 32); /*****************************/ /*Read the calibration offset */ /*****************************/ - //ui_Temp = inl(devpriv->iobase+i_Offset + 12); + /* ui_Temp = inl(devpriv->iobase+i_Offset + 12); */ ui_Temp = inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12); /*********************************/ /*Configure the Offset Conversion */ /*********************************/ - //while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); + /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12) >> 19) & 1) != 1) ; - //outl((ui_Temp | 0x00020000), devpriv->iobase+i_Offset + 12); + /* outl((ui_Temp | 0x00020000), devpriv->iobase+i_Offset + 12); */ outl((ui_Temp | 0x00020000), devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12); /*******************************/ @@ -1836,7 +1829,7 @@ int i_APCI3200_ReadCalibrationOffsetValue(struct comedi_device * dev, UINT * dat /*Test if the interrupt is enable */ /*********************************/ - //if (i_InterruptFlag == ADDIDATA_ENABLE) + /* if (i_InterruptFlag == ADDIDATA_ENABLE) */ if (s_BoardInfos[dev->minor].i_InterruptFlag == ADDIDATA_ENABLE) { /**********************/ @@ -1845,7 +1838,7 @@ int i_APCI3200_ReadCalibrationOffsetValue(struct comedi_device * dev, UINT * dat ui_CommandRegister = ui_CommandRegister | 0x00100000; - } //if (i_InterruptFlag == ADDIDATA_ENABLE) + } /* if (i_InterruptFlag == ADDIDATA_ENABLE) */ /**********************/ /*Start the conversion */ @@ -1855,10 +1848,10 @@ int i_APCI3200_ReadCalibrationOffsetValue(struct comedi_device * dev, UINT * dat /***************************/ /*Write the command regiter */ /***************************/ - //while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); + /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12) >> 19) & 1) != 1) ; - //outl(ui_CommandRegister, devpriv->iobase+i_Offset + 8); + /* outl(ui_CommandRegister, devpriv->iobase+i_Offset + 8); */ outl(ui_CommandRegister, devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 8); @@ -1866,7 +1859,7 @@ int i_APCI3200_ReadCalibrationOffsetValue(struct comedi_device * dev, UINT * dat /*Test if interrupt is enable */ /*****************************/ - //if (i_InterruptFlag == ADDIDATA_DISABLE) + /* if (i_InterruptFlag == ADDIDATA_DISABLE) */ if (s_BoardInfos[dev->minor].i_InterruptFlag == ADDIDATA_DISABLE) { do { @@ -1874,7 +1867,7 @@ int i_APCI3200_ReadCalibrationOffsetValue(struct comedi_device * dev, UINT * dat /*Read the EOC flag */ /*******************/ - //ui_EOC = inl (devpriv->iobase+i_Offset + 20) & 1; + /* ui_EOC = inl (devpriv->iobase+i_Offset + 20) & 1; */ ui_EOC = inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 20) & 1; @@ -1884,11 +1877,11 @@ int i_APCI3200_ReadCalibrationOffsetValue(struct comedi_device * dev, UINT * dat /*Read the digital value of the calibration Offset */ /**************************************************/ - //data[0] = inl(devpriv->iobase+i_Offset+ 28); + /* data[0] = inl(devpriv->iobase+i_Offset+ 28); */ data[0] = inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 28); - } //if (i_InterruptFlag == ADDIDATA_DISABLE) + } /* if (i_InterruptFlag == ADDIDATA_DISABLE) */ return 0; } @@ -1901,7 +1894,7 @@ int i_APCI3200_ReadCalibrationOffsetValue(struct comedi_device * dev, UINT * dat | Task : Read calibration gain value of the selected channel | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | - | UINT *data : Data Pointer to read status | + | unsigned int *data : Data Pointer to read status | +----------------------------------------------------------------------------+ | Output Parameters : -- | | data[0] : Calibration gain Value Of Input | @@ -1912,21 +1905,21 @@ int i_APCI3200_ReadCalibrationOffsetValue(struct comedi_device * dev, UINT * dat | | +----------------------------------------------------------------------------+ */ -int i_APCI3200_ReadCalibrationGainValue(struct comedi_device * dev, UINT * data) +int i_APCI3200_ReadCalibrationGainValue(struct comedi_device *dev, unsigned int *data) { - UINT ui_EOC = 0; - INT ui_CommandRegister = 0; + unsigned int ui_EOC = 0; + int ui_CommandRegister = 0; - //while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); + /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12) >> 19) & 1) != 1) ; /*********************************/ /* Write the channel to configure */ /*********************************/ - //Begin JK 20.10.2004: This seems not necessary ! - //outl(0 | ui_Channel_num , devpriv->iobase+i_Offset + 0x4); - //outl(0 | s_BoardInfos [dev->minor].ui_Channel_num , devpriv->iobase+s_BoardInfos [dev->minor].i_Offset + 0x4); - //End JK 20.10.2004: This seems not necessary ! + /* Begin JK 20.10.2004: This seems not necessary ! */ + /* outl(0 | ui_Channel_num , devpriv->iobase+i_Offset + 0x4); */ + /* outl(0 | s_BoardInfos [dev->minor].ui_Channel_num , devpriv->iobase+s_BoardInfos [dev->minor].i_Offset + 0x4); */ + /* End JK 20.10.2004: This seems not necessary ! */ /***************************/ /*Read the calibration gain */ @@ -1934,28 +1927,28 @@ int i_APCI3200_ReadCalibrationGainValue(struct comedi_device * dev, UINT * data) /*******************************/ /* Set the convert timing unit */ /*******************************/ - //while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); + /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12) >> 19) & 1) != 1) ; - //outl(i_ADDIDATAConversionTimeUnit , devpriv->iobase+i_Offset + 36); + /* outl(i_ADDIDATAConversionTimeUnit , devpriv->iobase+i_Offset + 36); */ outl(s_BoardInfos[dev->minor].i_ADDIDATAConversionTimeUnit, devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 36); /**************************/ /* Set the convert timing */ /**************************/ - //while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); + /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12) >> 19) & 1) != 1) ; - //outl(i_ADDIDATAConversionTime , devpriv->iobase+i_Offset + 32); + /* outl(i_ADDIDATAConversionTime , devpriv->iobase+i_Offset + 32); */ outl(s_BoardInfos[dev->minor].i_ADDIDATAConversionTime, devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 32); /*******************************/ /*Configure the Gain Conversion */ /*******************************/ - //while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); + /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12) >> 19) & 1) != 1) ; - //outl(0x00040000 , devpriv->iobase+i_Offset + 12); + /* outl(0x00040000 , devpriv->iobase+i_Offset + 12); */ outl(0x00040000, devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12); @@ -1969,7 +1962,7 @@ int i_APCI3200_ReadCalibrationGainValue(struct comedi_device * dev, UINT * data) /*Test if the interrupt is enable */ /*********************************/ - //if (i_InterruptFlag == ADDIDATA_ENABLE) + /* if (i_InterruptFlag == ADDIDATA_ENABLE) */ if (s_BoardInfos[dev->minor].i_InterruptFlag == ADDIDATA_ENABLE) { /**********************/ @@ -1978,7 +1971,7 @@ int i_APCI3200_ReadCalibrationGainValue(struct comedi_device * dev, UINT * data) ui_CommandRegister = ui_CommandRegister | 0x00100000; - } //if (i_InterruptFlag == ADDIDATA_ENABLE) + } /* if (i_InterruptFlag == ADDIDATA_ENABLE) */ /**********************/ /*Start the conversion */ @@ -1988,10 +1981,10 @@ int i_APCI3200_ReadCalibrationGainValue(struct comedi_device * dev, UINT * data) /***************************/ /*Write the command regiter */ /***************************/ - //while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); + /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12) >> 19) & 1) != 1) ; - //outl(ui_CommandRegister , devpriv->iobase+i_Offset + 8); + /* outl(ui_CommandRegister , devpriv->iobase+i_Offset + 8); */ outl(ui_CommandRegister, devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 8); @@ -1999,7 +1992,7 @@ int i_APCI3200_ReadCalibrationGainValue(struct comedi_device * dev, UINT * data) /*Test if interrupt is enable */ /*****************************/ - //if (i_InterruptFlag == ADDIDATA_DISABLE) + /* if (i_InterruptFlag == ADDIDATA_DISABLE) */ if (s_BoardInfos[dev->minor].i_InterruptFlag == ADDIDATA_DISABLE) { do { @@ -2008,7 +2001,7 @@ int i_APCI3200_ReadCalibrationGainValue(struct comedi_device * dev, UINT * data) /*Read the EOC flag */ /*******************/ - //ui_EOC = inl(devpriv->iobase+i_Offset + 20) & 1; + /* ui_EOC = inl(devpriv->iobase+i_Offset + 20) & 1; */ ui_EOC = inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 20) & 1; @@ -2018,12 +2011,12 @@ int i_APCI3200_ReadCalibrationGainValue(struct comedi_device * dev, UINT * data) /*Read the digital value of the calibration Gain */ /************************************************/ - //data[0] = inl(devpriv->iobase+i_Offset + 28); + /* data[0] = inl(devpriv->iobase+i_Offset + 28); */ data[0] = inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 28); - } //if (i_InterruptFlag == ADDIDATA_DISABLE) + } /* if (i_InterruptFlag == ADDIDATA_DISABLE) */ return 0; } @@ -2036,7 +2029,7 @@ int i_APCI3200_ReadCalibrationGainValue(struct comedi_device * dev, UINT * data) | Task : Read CJC value of the selected channel | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | - | UINT *data : Data Pointer to read status | + | unsigned int *data : Data Pointer to read status | +----------------------------------------------------------------------------+ | Output Parameters : -- | | data[0] : CJC Value | @@ -2048,41 +2041,41 @@ int i_APCI3200_ReadCalibrationGainValue(struct comedi_device * dev, UINT * data) +----------------------------------------------------------------------------+ */ -int i_APCI3200_ReadCJCValue(struct comedi_device * dev, unsigned int * data) +int i_APCI3200_ReadCJCValue(struct comedi_device *dev, unsigned int *data) { - UINT ui_EOC = 0; - INT ui_CommandRegister = 0; + unsigned int ui_EOC = 0; + int ui_CommandRegister = 0; /******************************/ /*Set the converting time unit */ /******************************/ - //while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); + /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12) >> 19) & 1) != 1) ; - //outl(i_ADDIDATAConversionTimeUnit , devpriv->iobase+i_Offset + 36); + /* outl(i_ADDIDATAConversionTimeUnit , devpriv->iobase+i_Offset + 36); */ outl(s_BoardInfos[dev->minor].i_ADDIDATAConversionTimeUnit, devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 36); /**************************/ /* Set the convert timing */ /**************************/ - //while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); + /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12) >> 19) & 1) != 1) ; - //outl(i_ADDIDATAConversionTime , devpriv->iobase+i_Offset + 32); + /* outl(i_ADDIDATAConversionTime , devpriv->iobase+i_Offset + 32); */ outl(s_BoardInfos[dev->minor].i_ADDIDATAConversionTime, devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 32); /******************************/ /*Configure the CJC Conversion */ /******************************/ - //while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); + /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12) >> 19) & 1) != 1) ; - //outl( 0x00000400 , devpriv->iobase+i_Offset + 4); + /* outl( 0x00000400 , devpriv->iobase+i_Offset + 4); */ outl(0x00000400, devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 4); /*******************************/ @@ -2092,7 +2085,7 @@ int i_APCI3200_ReadCJCValue(struct comedi_device * dev, unsigned int * data) /*********************************/ /*Test if the interrupt is enable */ /*********************************/ - //if (i_InterruptFlag == ADDIDATA_ENABLE) + /* if (i_InterruptFlag == ADDIDATA_ENABLE) */ if (s_BoardInfos[dev->minor].i_InterruptFlag == ADDIDATA_ENABLE) { /**********************/ /*Enable the interrupt */ @@ -2109,10 +2102,10 @@ int i_APCI3200_ReadCJCValue(struct comedi_device * dev, unsigned int * data) /***************************/ /*Write the command regiter */ /***************************/ - //while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); + /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12) >> 19) & 1) != 1) ; - //outl(ui_CommandRegister , devpriv->iobase+i_Offset + 8); + /* outl(ui_CommandRegister , devpriv->iobase+i_Offset + 8); */ outl(ui_CommandRegister, devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 8); @@ -2120,7 +2113,7 @@ int i_APCI3200_ReadCJCValue(struct comedi_device * dev, unsigned int * data) /*Test if interrupt is enable */ /*****************************/ - //if (i_InterruptFlag == ADDIDATA_DISABLE) + /* if (i_InterruptFlag == ADDIDATA_DISABLE) */ if (s_BoardInfos[dev->minor].i_InterruptFlag == ADDIDATA_DISABLE) { do { @@ -2128,7 +2121,7 @@ int i_APCI3200_ReadCJCValue(struct comedi_device * dev, unsigned int * data) /*Read the EOC flag */ /*******************/ - //ui_EOC = inl(devpriv->iobase+i_Offset + 20) & 1; + /* ui_EOC = inl(devpriv->iobase+i_Offset + 20) & 1; */ ui_EOC = inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 20) & 1; @@ -2138,12 +2131,12 @@ int i_APCI3200_ReadCJCValue(struct comedi_device * dev, unsigned int * data) /*Read the digital value of the CJC */ /***********************************/ - //data[0] = inl(devpriv->iobase+i_Offset + 28); + /* data[0] = inl(devpriv->iobase+i_Offset + 28); */ data[0] = inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 28); - } //if (i_InterruptFlag == ADDIDATA_DISABLE) + } /* if (i_InterruptFlag == ADDIDATA_DISABLE) */ return 0; } @@ -2156,7 +2149,7 @@ int i_APCI3200_ReadCJCValue(struct comedi_device * dev, unsigned int * data) | Task : Read CJC calibration offset value of the selected channel +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | - | UINT *data : Data Pointer to read status | + | unsigned int *data : Data Pointer to read status | +----------------------------------------------------------------------------+ | Output Parameters : -- | | data[0] : CJC calibration offset Value @@ -2167,47 +2160,47 @@ int i_APCI3200_ReadCJCValue(struct comedi_device * dev, unsigned int * data) | | +----------------------------------------------------------------------------+ */ -int i_APCI3200_ReadCJCCalOffset(struct comedi_device * dev, unsigned int * data) +int i_APCI3200_ReadCJCCalOffset(struct comedi_device *dev, unsigned int *data) { - UINT ui_EOC = 0; - INT ui_CommandRegister = 0; + unsigned int ui_EOC = 0; + int ui_CommandRegister = 0; /*******************************************/ /*Read calibration offset value for the CJC */ /*******************************************/ /*******************************/ /* Set the convert timing unit */ /*******************************/ - //while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); + /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12) >> 19) & 1) != 1) ; - //outl(i_ADDIDATAConversionTimeUnit , devpriv->iobase+i_Offset + 36); + /* outl(i_ADDIDATAConversionTimeUnit , devpriv->iobase+i_Offset + 36); */ outl(s_BoardInfos[dev->minor].i_ADDIDATAConversionTimeUnit, devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 36); /**************************/ /* Set the convert timing */ /**************************/ - //while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); + /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12) >> 19) & 1) != 1) ; - //outl(i_ADDIDATAConversionTime , devpriv->iobase+i_Offset + 32); + /* outl(i_ADDIDATAConversionTime , devpriv->iobase+i_Offset + 32); */ outl(s_BoardInfos[dev->minor].i_ADDIDATAConversionTime, devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 32); /******************************/ /*Configure the CJC Conversion */ /******************************/ - //while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); + /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12) >> 19) & 1) != 1) ; - //outl(0x00000400 , devpriv->iobase+i_Offset + 4); + /* outl(0x00000400 , devpriv->iobase+i_Offset + 4); */ outl(0x00000400, devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 4); /*********************************/ /*Configure the Offset Conversion */ /*********************************/ - //while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); + /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12) >> 19) & 1) != 1) ; - //outl(0x00020000, devpriv->iobase+i_Offset + 12); + /* outl(0x00020000, devpriv->iobase+i_Offset + 12); */ outl(0x00020000, devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12); /*******************************/ @@ -2218,7 +2211,7 @@ int i_APCI3200_ReadCJCCalOffset(struct comedi_device * dev, unsigned int * data) /*Test if the interrupt is enable */ /*********************************/ - //if (i_InterruptFlag == ADDIDATA_ENABLE) + /* if (i_InterruptFlag == ADDIDATA_ENABLE) */ if (s_BoardInfos[dev->minor].i_InterruptFlag == ADDIDATA_ENABLE) { /**********************/ /*Enable the interrupt */ @@ -2234,19 +2227,19 @@ int i_APCI3200_ReadCJCCalOffset(struct comedi_device * dev, unsigned int * data) /***************************/ /*Write the command regiter */ /***************************/ - //while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); + /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12) >> 19) & 1) != 1) ; - //outl(ui_CommandRegister,devpriv->iobase+i_Offset + 8); + /* outl(ui_CommandRegister,devpriv->iobase+i_Offset + 8); */ outl(ui_CommandRegister, devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 8); - //if (i_InterruptFlag == ADDIDATA_DISABLE) + /* if (i_InterruptFlag == ADDIDATA_DISABLE) */ if (s_BoardInfos[dev->minor].i_InterruptFlag == ADDIDATA_DISABLE) { do { /*******************/ /*Read the EOC flag */ /*******************/ - //ui_EOC = inl(devpriv->iobase+i_Offset + 20) & 1; + /* ui_EOC = inl(devpriv->iobase+i_Offset + 20) & 1; */ ui_EOC = inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 20) & 1; } while (ui_EOC != 1); @@ -2254,11 +2247,11 @@ int i_APCI3200_ReadCJCCalOffset(struct comedi_device * dev, unsigned int * data) /**************************************************/ /*Read the digital value of the calibration Offset */ /**************************************************/ - //data[0] = inl(devpriv->iobase+i_Offset + 28); + /* data[0] = inl(devpriv->iobase+i_Offset + 28); */ data[0] = inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 28); - } //if (i_InterruptFlag == ADDIDATA_DISABLE) + } /* if (i_InterruptFlag == ADDIDATA_DISABLE) */ return 0; } @@ -2271,8 +2264,8 @@ int i_APCI3200_ReadCJCCalOffset(struct comedi_device * dev, unsigned int * data) | Task : Read CJC calibration gain value +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | - | UINT ui_NoOfChannels : No Of Channels To read | - | UINT *data : Data Pointer to read status | + | unsigned int ui_NoOfChannels : No Of Channels To read | + | unsigned int *data : Data Pointer to read status | +----------------------------------------------------------------------------+ | Output Parameters : -- | | data[0] : CJC calibration gain value @@ -2283,44 +2276,44 @@ int i_APCI3200_ReadCJCCalOffset(struct comedi_device * dev, unsigned int * data) | | +----------------------------------------------------------------------------+ */ -int i_APCI3200_ReadCJCCalGain(struct comedi_device * dev, unsigned int * data) +int i_APCI3200_ReadCJCCalGain(struct comedi_device *dev, unsigned int *data) { - UINT ui_EOC = 0; - INT ui_CommandRegister = 0; + unsigned int ui_EOC = 0; + int ui_CommandRegister = 0; /*******************************/ /* Set the convert timing unit */ /*******************************/ - //while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); + /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12) >> 19) & 1) != 1) ; - //outl(i_ADDIDATAConversionTimeUnit , devpriv->iobase+i_Offset + 36); + /* outl(i_ADDIDATAConversionTimeUnit , devpriv->iobase+i_Offset + 36); */ outl(s_BoardInfos[dev->minor].i_ADDIDATAConversionTimeUnit, devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 36); /**************************/ /* Set the convert timing */ /**************************/ - //while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); + /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12) >> 19) & 1) != 1) ; - //outl(i_ADDIDATAConversionTime , devpriv->iobase+i_Offset + 32); + /* outl(i_ADDIDATAConversionTime , devpriv->iobase+i_Offset + 32); */ outl(s_BoardInfos[dev->minor].i_ADDIDATAConversionTime, devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 32); /******************************/ /*Configure the CJC Conversion */ /******************************/ - //while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); + /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12) >> 19) & 1) != 1) ; - //outl(0x00000400,devpriv->iobase+i_Offset + 4); + /* outl(0x00000400,devpriv->iobase+i_Offset + 4); */ outl(0x00000400, devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 4); /*******************************/ /*Configure the Gain Conversion */ /*******************************/ - //while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); + /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12) >> 19) & 1) != 1) ; - //outl(0x00040000,devpriv->iobase+i_Offset + 12); + /* outl(0x00040000,devpriv->iobase+i_Offset + 12); */ outl(0x00040000, devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12); @@ -2331,7 +2324,7 @@ int i_APCI3200_ReadCJCCalGain(struct comedi_device * dev, unsigned int * data) /*********************************/ /*Test if the interrupt is enable */ /*********************************/ - //if (i_InterruptFlag == ADDIDATA_ENABLE) + /* if (i_InterruptFlag == ADDIDATA_ENABLE) */ if (s_BoardInfos[dev->minor].i_InterruptFlag == ADDIDATA_ENABLE) { /**********************/ /*Enable the interrupt */ @@ -2345,30 +2338,30 @@ int i_APCI3200_ReadCJCCalGain(struct comedi_device * dev, unsigned int * data) /***************************/ /*Write the command regiter */ /***************************/ - //while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); + /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12) >> 19) & 1) != 1) ; - //outl(ui_CommandRegister ,devpriv->iobase+i_Offset + 8); + /* outl(ui_CommandRegister ,devpriv->iobase+i_Offset + 8); */ outl(ui_CommandRegister, devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 8); - //if (i_InterruptFlag == ADDIDATA_DISABLE) + /* if (i_InterruptFlag == ADDIDATA_DISABLE) */ if (s_BoardInfos[dev->minor].i_InterruptFlag == ADDIDATA_DISABLE) { do { /*******************/ /*Read the EOC flag */ /*******************/ - //ui_EOC = inl(devpriv->iobase+i_Offset + 20) & 1; + /* ui_EOC = inl(devpriv->iobase+i_Offset + 20) & 1; */ ui_EOC = inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 20) & 1; } while (ui_EOC != 1); /************************************************/ /*Read the digital value of the calibration Gain */ /************************************************/ - //data[0] = inl (devpriv->iobase+i_Offset + 28); + /* data[0] = inl (devpriv->iobase+i_Offset + 28); */ data[0] = inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 28); - } //if (i_InterruptFlag == ADDIDATA_DISABLE) + } /* if (i_InterruptFlag == ADDIDATA_DISABLE) */ return 0; } @@ -2404,33 +2397,33 @@ int i_APCI3200_ReadCJCCalGain(struct comedi_device * dev, unsigned int * data) +----------------------------------------------------------------------------+ */ -INT i_APCI3200_InsnBits_AnalogInput_Test(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +int i_APCI3200_InsnBits_AnalogInput_Test(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - UINT ui_Configuration = 0; - INT i_Temp; //,i_TimeUnit; - //if(i_Initialised==0) + unsigned int ui_Configuration = 0; + int i_Temp; /* ,i_TimeUnit; */ + /* if(i_Initialised==0) */ if (s_BoardInfos[dev->minor].i_Initialised == 0) { i_APCI3200_Reset(dev); return -EINVAL; - } //if(i_Initialised==0); + } /* if(i_Initialised==0); */ if (data[0] != 0 && data[0] != 1) { printk("\nError in selection of functionality\n"); i_APCI3200_Reset(dev); return -EINVAL; - } //if(data[0]!=0 && data[0]!=1) + } /* if(data[0]!=0 && data[0]!=1) */ - if (data[0] == 1) //Perform Short Circuit TEST + if (data[0] == 1) /* Perform Short Circuit TEST */ { /**************************/ /*Set the short-cicuit bit */ /**************************/ - //while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); + /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ while (((inl(devpriv->iobase + s_BoardInfos[dev->minor]. i_Offset + 12) >> 19) & 1) != 1) ; - //outl((0x00001000 |i_ChannelNo) , devpriv->iobase+i_Offset + 4); + /* outl((0x00001000 |i_ChannelNo) , devpriv->iobase+i_Offset + 4); */ outl((0x00001000 | s_BoardInfos[dev->minor].i_ChannelNo), devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 4); @@ -2439,19 +2432,19 @@ INT i_APCI3200_InsnBits_AnalogInput_Test(struct comedi_device * dev, /*************************/ /* i_TimeUnit= i_ADDIDATAConversionTimeUnit; i_ADDIDATAConversionTimeUnit= 1; */ - //i_Temp= i_InterruptFlag ; + /* i_Temp= i_InterruptFlag ; */ i_Temp = s_BoardInfos[dev->minor].i_InterruptFlag; - //i_InterruptFlag = ADDIDATA_DISABLE; + /* i_InterruptFlag = ADDIDATA_DISABLE; */ s_BoardInfos[dev->minor].i_InterruptFlag = ADDIDATA_DISABLE; i_APCI3200_Read1AnalogInputChannel(dev, s, insn, data); - //if(i_AutoCalibration == FALSE) + /* if(i_AutoCalibration == FALSE) */ if (s_BoardInfos[dev->minor].i_AutoCalibration == FALSE) { - //while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); + /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ while (((inl(devpriv->iobase + s_BoardInfos[dev->minor]. i_Offset + 12) >> 19) & 1) != 1) ; - //outl((0x00001000 |i_ChannelNo) , devpriv->iobase+i_Offset + 4); + /* outl((0x00001000 |i_ChannelNo) , devpriv->iobase+i_Offset + 4); */ outl((0x00001000 | s_BoardInfos[dev->minor]. i_ChannelNo), devpriv->iobase + @@ -2462,15 +2455,15 @@ INT i_APCI3200_InsnBits_AnalogInput_Test(struct comedi_device * dev, i_APCI3200_ReadCalibrationGainValue(dev, data); } } else { - //while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); + /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ while (((inl(devpriv->iobase + s_BoardInfos[dev->minor]. i_Offset + 12) >> 19) & 1) != 1) ; - //outl((0x00000800|i_ChannelNo) , devpriv->iobase+i_Offset + 4); + /* outl((0x00000800|i_ChannelNo) , devpriv->iobase+i_Offset + 4); */ outl((0x00000800 | s_BoardInfos[dev->minor].i_ChannelNo), devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 4); - //ui_Configuration = inl(devpriv->iobase+i_Offset + 0); + /* ui_Configuration = inl(devpriv->iobase+i_Offset + 0); */ ui_Configuration = inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 0); @@ -2479,18 +2472,18 @@ INT i_APCI3200_InsnBits_AnalogInput_Test(struct comedi_device * dev, /*************************/ /* i_TimeUnit= i_ADDIDATAConversionTimeUnit; i_ADDIDATAConversionTimeUnit= 1; */ - //i_Temp= i_InterruptFlag ; + /* i_Temp= i_InterruptFlag ; */ i_Temp = s_BoardInfos[dev->minor].i_InterruptFlag; - //i_InterruptFlag = ADDIDATA_DISABLE; + /* i_InterruptFlag = ADDIDATA_DISABLE; */ s_BoardInfos[dev->minor].i_InterruptFlag = ADDIDATA_DISABLE; i_APCI3200_Read1AnalogInputChannel(dev, s, insn, data); - //if(i_AutoCalibration == FALSE) + /* if(i_AutoCalibration == FALSE) */ if (s_BoardInfos[dev->minor].i_AutoCalibration == FALSE) { - //while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); + /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ while (((inl(devpriv->iobase + s_BoardInfos[dev->minor]. i_Offset + 12) >> 19) & 1) != 1) ; - //outl((0x00000800|i_ChannelNo) , devpriv->iobase+i_Offset + 4); + /* outl((0x00000800|i_ChannelNo) , devpriv->iobase+i_Offset + 4); */ outl((0x00000800 | s_BoardInfos[dev->minor]. i_ChannelNo), devpriv->iobase + @@ -2501,9 +2494,9 @@ INT i_APCI3200_InsnBits_AnalogInput_Test(struct comedi_device * dev, i_APCI3200_ReadCalibrationGainValue(dev, data); } } - //i_InterruptFlag=i_Temp ; + /* i_InterruptFlag=i_Temp ; */ s_BoardInfos[dev->minor].i_InterruptFlag = i_Temp; - //printk("\ni_InterruptFlag=%d\n",i_InterruptFlag); + /* printk("\ni_InterruptFlag=%d\n",i_InterruptFlag); */ return insn->n; } @@ -2529,8 +2522,8 @@ INT i_APCI3200_InsnBits_AnalogInput_Test(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -INT i_APCI3200_InsnWriteReleaseAnalogInput(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +int i_APCI3200_InsnWriteReleaseAnalogInput(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { i_APCI3200_Reset(dev); return insn->n; @@ -2560,23 +2553,23 @@ INT i_APCI3200_InsnWriteReleaseAnalogInput(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -int i_APCI3200_CommandTestAnalogInput(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd) +int i_APCI3200_CommandTestAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd) { int err = 0; - int tmp; // divisor1,divisor2; - UINT ui_ConvertTime = 0; - UINT ui_ConvertTimeBase = 0; - UINT ui_DelayTime = 0; - UINT ui_DelayTimeBase = 0; - INT i_Triggermode = 0; - INT i_TriggerEdge = 0; - INT i_NbrOfChannel = 0; - INT i_Cpt = 0; + int tmp; /* divisor1,divisor2; */ + unsigned int ui_ConvertTime = 0; + unsigned int ui_ConvertTimeBase = 0; + unsigned int ui_DelayTime = 0; + unsigned int ui_DelayTimeBase = 0; + int i_Triggermode = 0; + int i_TriggerEdge = 0; + int i_NbrOfChannel = 0; + int i_Cpt = 0; double d_ConversionTimeForAllChannels = 0.0; double d_SCANTimeNewUnit = 0.0; - // step 1: make sure trigger sources are trivially valid + /* step 1: make sure trigger sources are trivially valid */ tmp = cmd->start_src; cmd->start_src &= TRIG_NOW | TRIG_EXT; @@ -2598,10 +2591,10 @@ int i_APCI3200_CommandTestAnalogInput(struct comedi_device * dev, struct comedi_ cmd->stop_src &= TRIG_COUNT | TRIG_NONE; if (!cmd->stop_src || tmp != cmd->stop_src) err++; - //if(i_InterruptFlag==0) + /* if(i_InterruptFlag==0) */ if (s_BoardInfos[dev->minor].i_InterruptFlag == 0) { err++; - // printk("\nThe interrupt should be enabled\n"); + /* printk("\nThe interrupt should be enabled\n"); */ } if (err) { i_APCI3200_Reset(dev); @@ -2643,9 +2636,9 @@ int i_APCI3200_CommandTestAnalogInput(struct comedi_device * dev, struct comedi_ i_APCI3200_Reset(dev); return 2; } - //i_FirstChannel=cmd->chanlist[0]; + /* i_FirstChannel=cmd->chanlist[0]; */ s_BoardInfos[dev->minor].i_FirstChannel = cmd->chanlist[0]; - //i_LastChannel=cmd->chanlist[1]; + /* i_LastChannel=cmd->chanlist[1]; */ s_BoardInfos[dev->minor].i_LastChannel = cmd->chanlist[1]; if (cmd->convert_src == TRIG_TIMER) { @@ -2656,11 +2649,11 @@ int i_APCI3200_CommandTestAnalogInput(struct comedi_device * dev, struct comedi_ { printk("\nThe selection of conversion time reload value is in error\n"); err++; - } // if (ui_ConvertTime!=20 && ui_ConvertTime!=40 && ui_ConvertTime!=80 && ui_ConvertTime!=160 ) + } /* if (ui_ConvertTime!=20 && ui_ConvertTime!=40 && ui_ConvertTime!=80 && ui_ConvertTime!=160 ) */ if (ui_ConvertTimeBase != 2) { printk("\nThe selection of conversion time unit is in error\n"); err++; - } //if(ui_ConvertTimeBase!=2) + } /* if(ui_ConvertTimeBase!=2) */ } else { ui_ConvertTime = 0; ui_ConvertTimeBase = 0; @@ -2668,7 +2661,7 @@ int i_APCI3200_CommandTestAnalogInput(struct comedi_device * dev, struct comedi_ if (cmd->scan_begin_src == TRIG_FOLLOW) { ui_DelayTime = 0; ui_DelayTimeBase = 0; - } //if(cmd->scan_begin_src==TRIG_FOLLOW) + } /* if(cmd->scan_begin_src==TRIG_FOLLOW) */ else { ui_DelayTime = cmd->scan_begin_arg & 0xFFFF; ui_DelayTimeBase = cmd->scan_begin_arg >> 16; @@ -2686,7 +2679,7 @@ int i_APCI3200_CommandTestAnalogInput(struct comedi_device * dev, struct comedi_ } fpu_begin(); d_SCANTimeNewUnit = (double)ui_DelayTime; - //i_NbrOfChannel= i_LastChannel-i_FirstChannel + 4; + /* i_NbrOfChannel= i_LastChannel-i_FirstChannel + 4; */ i_NbrOfChannel = s_BoardInfos[dev->minor].i_LastChannel - s_BoardInfos[dev->minor].i_FirstChannel + 4; @@ -2736,7 +2729,7 @@ int i_APCI3200_CommandTestAnalogInput(struct comedi_device * dev, struct comedi_ err++; } fpu_end(); - } //else if(cmd->scan_begin_src==TRIG_FOLLOW) + } /* else if(cmd->scan_begin_src==TRIG_FOLLOW) */ if (err) { i_APCI3200_Reset(dev); @@ -2764,13 +2757,13 @@ int i_APCI3200_CommandTestAnalogInput(struct comedi_device * dev, struct comedi_ +----------------------------------------------------------------------------+ */ -int i_APCI3200_StopCyclicAcquisition(struct comedi_device * dev, struct comedi_subdevice * s) +int i_APCI3200_StopCyclicAcquisition(struct comedi_device *dev, struct comedi_subdevice *s) { - UINT ui_Configuration = 0; - //i_InterruptFlag=0; - //i_Initialised=0; - //i_Count=0; - //i_Sum=0; + unsigned int ui_Configuration = 0; + /* i_InterruptFlag=0; */ + /* i_Initialised=0; */ + /* i_Count=0; */ + /* i_Sum=0; */ s_BoardInfos[dev->minor].i_InterruptFlag = 0; s_BoardInfos[dev->minor].i_Initialised = 0; s_BoardInfos[dev->minor].i_Count = 0; @@ -2779,16 +2772,16 @@ int i_APCI3200_StopCyclicAcquisition(struct comedi_device * dev, struct comedi_s /*******************/ /*Read the register */ /*******************/ - //ui_Configuration = inl(devpriv->iobase+i_Offset + 8); + /* ui_Configuration = inl(devpriv->iobase+i_Offset + 8); */ ui_Configuration = inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 8); /*****************************/ /*Reset the START and IRQ bit */ /*****************************/ - //while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); + /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12) >> 19) & 1) != 1) ; - //outl((ui_Configuration & 0xFFE7FFFF),devpriv->iobase+i_Offset + 8); + /* outl((ui_Configuration & 0xFFE7FFFF),devpriv->iobase+i_Offset + 8); */ outl((ui_Configuration & 0xFFE7FFFF), devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 8); return 0; @@ -2814,52 +2807,52 @@ int i_APCI3200_StopCyclicAcquisition(struct comedi_device * dev, struct comedi_s +----------------------------------------------------------------------------+ */ -int i_APCI3200_CommandAnalogInput(struct comedi_device * dev, struct comedi_subdevice * s) +int i_APCI3200_CommandAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s) { struct comedi_cmd *cmd = &s->async->cmd; - UINT ui_Configuration = 0; - //INT i_CurrentSource = 0; - UINT ui_Trigger = 0; - UINT ui_TriggerEdge = 0; - UINT ui_Triggermode = 0; - UINT ui_ScanMode = 0; - UINT ui_ConvertTime = 0; - UINT ui_ConvertTimeBase = 0; - UINT ui_DelayTime = 0; - UINT ui_DelayTimeBase = 0; - UINT ui_DelayMode = 0; - //i_FirstChannel=cmd->chanlist[0]; - //i_LastChannel=cmd->chanlist[1]; + unsigned int ui_Configuration = 0; + /* INT i_CurrentSource = 0; */ + unsigned int ui_Trigger = 0; + unsigned int ui_TriggerEdge = 0; + unsigned int ui_Triggermode = 0; + unsigned int ui_ScanMode = 0; + unsigned int ui_ConvertTime = 0; + unsigned int ui_ConvertTimeBase = 0; + unsigned int ui_DelayTime = 0; + unsigned int ui_DelayTimeBase = 0; + unsigned int ui_DelayMode = 0; + /* i_FirstChannel=cmd->chanlist[0]; */ + /* i_LastChannel=cmd->chanlist[1]; */ s_BoardInfos[dev->minor].i_FirstChannel = cmd->chanlist[0]; s_BoardInfos[dev->minor].i_LastChannel = cmd->chanlist[1]; if (cmd->start_src == TRIG_EXT) { ui_Trigger = 1; ui_TriggerEdge = cmd->start_arg & 0xFFFF; ui_Triggermode = cmd->start_arg >> 16; - } //if(cmd->start_src==TRIG_EXT) + } /* if(cmd->start_src==TRIG_EXT) */ else { ui_Trigger = 0; - } //elseif(cmd->start_src==TRIG_EXT) + } /* elseif(cmd->start_src==TRIG_EXT) */ if (cmd->stop_src == TRIG_COUNT) { ui_ScanMode = 0; - } // if (cmd->stop_src==TRIG_COUNT) + } /* if (cmd->stop_src==TRIG_COUNT) */ else { ui_ScanMode = 2; - } //else if (cmd->stop_src==TRIG_COUNT) + } /* else if (cmd->stop_src==TRIG_COUNT) */ if (cmd->scan_begin_src == TRIG_FOLLOW) { ui_DelayTime = 0; ui_DelayTimeBase = 0; ui_DelayMode = 0; - } //if(cmd->scan_begin_src==TRIG_FOLLOW) + } /* if(cmd->scan_begin_src==TRIG_FOLLOW) */ else { ui_DelayTime = cmd->scan_begin_arg & 0xFFFF; ui_DelayTimeBase = cmd->scan_begin_arg >> 16; ui_DelayMode = 1; - } //else if(cmd->scan_begin_src==TRIG_FOLLOW) - // printk("\nui_DelayTime=%u\n",ui_DelayTime); - // printk("\nui_DelayTimeBase=%u\n",ui_DelayTimeBase); + } /* else if(cmd->scan_begin_src==TRIG_FOLLOW) */ + /* printk("\nui_DelayTime=%u\n",ui_DelayTime); */ + /* printk("\nui_DelayTimeBase=%u\n",ui_DelayTimeBase); */ if (cmd->convert_src == TRIG_TIMER) { ui_ConvertTime = cmd->convert_arg & 0xFFFF; ui_ConvertTimeBase = cmd->convert_arg >> 16; @@ -2868,34 +2861,34 @@ int i_APCI3200_CommandAnalogInput(struct comedi_device * dev, struct comedi_subd ui_ConvertTimeBase = 0; } - // if(i_ADDIDATAType ==1 || ((i_ADDIDATAType==2))) - // { + /* if(i_ADDIDATAType ==1 || ((i_ADDIDATAType==2))) */ + /* { */ /**************************************************/ /*Read the old configuration of the current source */ /**************************************************/ - //ui_Configuration = inl(devpriv->iobase+i_Offset + 12); + /* ui_Configuration = inl(devpriv->iobase+i_Offset + 12); */ ui_Configuration = inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12); /***********************************************/ /*Write the configuration of the current source */ /***********************************************/ - //while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); + /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12) >> 19) & 1) != 1) ; - //outl((ui_Configuration & 0xFFC00000 ), devpriv->iobase+i_Offset +12); + /* outl((ui_Configuration & 0xFFC00000 ), devpriv->iobase+i_Offset +12); */ outl((ui_Configuration & 0xFFC00000), devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12); - // } + /* } */ ui_Configuration = 0; - // printk("\nfirstchannel=%u\n",i_FirstChannel); - // printk("\nlastchannel=%u\n",i_LastChannel); - // printk("\nui_Trigger=%u\n",ui_Trigger); - // printk("\nui_TriggerEdge=%u\n",ui_TriggerEdge); - // printk("\nui_Triggermode=%u\n",ui_Triggermode); - // printk("\nui_DelayMode=%u\n",ui_DelayMode); - // printk("\nui_ScanMode=%u\n",ui_ScanMode); + /* printk("\nfirstchannel=%u\n",i_FirstChannel); */ + /* printk("\nlastchannel=%u\n",i_LastChannel); */ + /* printk("\nui_Trigger=%u\n",ui_Trigger); */ + /* printk("\nui_TriggerEdge=%u\n",ui_TriggerEdge); */ + /* printk("\nui_Triggermode=%u\n",ui_Triggermode); */ + /* printk("\nui_DelayMode=%u\n",ui_DelayMode); */ + /* printk("\nui_ScanMode=%u\n",ui_ScanMode); */ - //ui_Configuration = i_FirstChannel |(i_LastChannel << 8)| 0x00100000 | + /* ui_Configuration = i_FirstChannel |(i_LastChannel << 8)| 0x00100000 | */ ui_Configuration = s_BoardInfos[dev->minor].i_FirstChannel | (s_BoardInfos[dev-> minor]. @@ -2906,80 +2899,80 @@ int i_APCI3200_CommandAnalogInput(struct comedi_device * dev, struct comedi_subd /*************************/ /*Write the Configuration */ /*************************/ - //while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); + /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12) >> 19) & 1) != 1) ; - //outl( ui_Configuration, devpriv->iobase+i_Offset + 0x8); + /* outl( ui_Configuration, devpriv->iobase+i_Offset + 0x8); */ outl(ui_Configuration, devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 0x8); /***********************/ /*Write the Delay Value */ /***********************/ - //while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); + /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12) >> 19) & 1) != 1) ; - //outl(ui_DelayTime,devpriv->iobase+i_Offset + 40); + /* outl(ui_DelayTime,devpriv->iobase+i_Offset + 40); */ outl(ui_DelayTime, devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 40); /***************************/ /*Write the Delay time base */ /***************************/ - //while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); + /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12) >> 19) & 1) != 1) ; - //outl(ui_DelayTimeBase,devpriv->iobase+i_Offset + 44); + /* outl(ui_DelayTimeBase,devpriv->iobase+i_Offset + 44); */ outl(ui_DelayTimeBase, devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 44); /*********************************/ /*Write the conversion time value */ /*********************************/ - //while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); + /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12) >> 19) & 1) != 1) ; - //outl(ui_ConvertTime,devpriv->iobase+i_Offset + 32); + /* outl(ui_ConvertTime,devpriv->iobase+i_Offset + 32); */ outl(ui_ConvertTime, devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 32); /********************************/ /*Write the conversion time base */ /********************************/ - //while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); + /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12) >> 19) & 1) != 1) ; - //outl(ui_ConvertTimeBase,devpriv->iobase+i_Offset + 36); + /* outl(ui_ConvertTimeBase,devpriv->iobase+i_Offset + 36); */ outl(ui_ConvertTimeBase, devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 36); /*******************/ /*Read the register */ /*******************/ - //ui_Configuration = inl(devpriv->iobase+i_Offset + 4); + /* ui_Configuration = inl(devpriv->iobase+i_Offset + 4); */ ui_Configuration = inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 4); /******************/ /*Set the SCAN bit */ /******************/ - //while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); + /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12) >> 19) & 1) != 1) ; - //outl(((ui_Configuration & 0x1E0FF) | 0x00002000),devpriv->iobase+i_Offset + 4); + /* outl(((ui_Configuration & 0x1E0FF) | 0x00002000),devpriv->iobase+i_Offset + 4); */ outl(((ui_Configuration & 0x1E0FF) | 0x00002000), devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 4); /*******************/ /*Read the register */ /*******************/ ui_Configuration = 0; - //ui_Configuration = inl(devpriv->iobase+i_Offset + 8); + /* ui_Configuration = inl(devpriv->iobase+i_Offset + 8); */ ui_Configuration = inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 8); /*******************/ /*Set the START bit */ /*******************/ - //while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); + /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12) >> 19) & 1) != 1) ; - //outl((ui_Configuration | 0x00080000),devpriv->iobase+i_Offset + 8); + /* outl((ui_Configuration | 0x00080000),devpriv->iobase+i_Offset + 8); */ outl((ui_Configuration | 0x00080000), devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 8); return 0; @@ -3001,14 +2994,14 @@ int i_APCI3200_CommandAnalogInput(struct comedi_device * dev, struct comedi_subd +----------------------------------------------------------------------------+ */ -int i_APCI3200_Reset(struct comedi_device * dev) +int i_APCI3200_Reset(struct comedi_device *dev) { - INT i_Temp; - DWORD dw_Dummy; - //i_InterruptFlag=0; - //i_Initialised==0; - //i_Count=0; - //i_Sum=0; + int i_Temp; + unsigned int dw_Dummy; + /* i_InterruptFlag=0; */ + /* i_Initialised==0; */ + /* i_Count=0; */ + /* i_Sum=0; */ s_BoardInfos[dev->minor].i_InterruptFlag = 0; s_BoardInfos[dev->minor].i_Initialised = 0; @@ -3018,17 +3011,17 @@ int i_APCI3200_Reset(struct comedi_device * dev) outl(0x83838383, devpriv->i_IobaseAmcc + 0x60); - // Enable the interrupt for the controler + /* Enable the interrupt for the controler */ dw_Dummy = inl(devpriv->i_IobaseAmcc + 0x38); outl(dw_Dummy | 0x2000, devpriv->i_IobaseAmcc + 0x38); - outl(0, devpriv->i_IobaseAddon); //Resets the output + outl(0, devpriv->i_IobaseAddon); /* Resets the output */ /***************/ /*Empty the buffer */ /**************/ for (i_Temp = 0; i_Temp <= 95; i_Temp++) { - //ui_InterruptChannelValue[i_Temp]=0; + /* ui_InterruptChannelValue[i_Temp]=0; */ s_BoardInfos[dev->minor].ui_InterruptChannelValue[i_Temp] = 0; - } //for(i_Temp=0;i_Temp<=95;i_Temp++) + } /* for(i_Temp=0;i_Temp<=95;i_Temp++) */ /*****************************/ /*Reset the START and IRQ bit */ /*****************************/ @@ -3036,7 +3029,7 @@ int i_APCI3200_Reset(struct comedi_device * dev) while (((inl(devpriv->iobase + i_Temp + 12) >> 19) & 1) != 1) ; outl(0, devpriv->iobase + i_Temp + 8); i_Temp = i_Temp + 64; - } //for(i_Temp=0;i_Temp<=192;i_Temp+64) + } /* for(i_Temp=0;i_Temp<=192;i_Temp+64) */ return 0; } @@ -3060,26 +3053,26 @@ int i_APCI3200_Reset(struct comedi_device * dev) void v_APCI3200_Interrupt(int irq, void *d) { struct comedi_device *dev = d; - UINT ui_StatusRegister = 0; - UINT ui_ChannelNumber = 0; - INT i_CalibrationFlag = 0; - INT i_CJCFlag = 0; - UINT ui_DummyValue = 0; - UINT ui_DigitalTemperature = 0; - UINT ui_DigitalInput = 0; + unsigned int ui_StatusRegister = 0; + unsigned int ui_ChannelNumber = 0; + int i_CalibrationFlag = 0; + int i_CJCFlag = 0; + unsigned int ui_DummyValue = 0; + unsigned int ui_DigitalTemperature = 0; + unsigned int ui_DigitalInput = 0; int i_ConvertCJCCalibration; - //BEGIN JK TEST + /* BEGIN JK TEST */ int i_ReturnValue = 0; - //END JK TEST + /* END JK TEST */ - //printk ("\n i_ScanType = %i i_ADDIDATAType = %i", s_BoardInfos [dev->minor].i_ScanType, s_BoardInfos [dev->minor].i_ADDIDATAType); + /* printk ("\n i_ScanType = %i i_ADDIDATAType = %i", s_BoardInfos [dev->minor].i_ScanType, s_BoardInfos [dev->minor].i_ADDIDATAType); */ - //switch(i_ScanType) + /* switch(i_ScanType) */ switch (s_BoardInfos[dev->minor].i_ScanType) { case 0: case 1: - //switch(i_ADDIDATAType) + /* switch(i_ADDIDATAType) */ switch (s_BoardInfos[dev->minor].i_ADDIDATAType) { case 0: case 1: @@ -3087,12 +3080,12 @@ void v_APCI3200_Interrupt(int irq, void *d) /************************************/ /*Read the interrupt status register */ /************************************/ - //ui_StatusRegister = inl(devpriv->iobase+i_Offset + 16); + /* ui_StatusRegister = inl(devpriv->iobase+i_Offset + 16); */ ui_StatusRegister = inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 16); if ((ui_StatusRegister & 0x2) == 0x2) { - //i_CalibrationFlag = ((inl(devpriv->iobase+i_Offset + 12) & 0x00060000) >> 17); + /* i_CalibrationFlag = ((inl(devpriv->iobase+i_Offset + 12) & 0x00060000) >> 17); */ i_CalibrationFlag = ((inl(devpriv->iobase + s_BoardInfos[dev-> @@ -3103,12 +3096,12 @@ void v_APCI3200_Interrupt(int irq, void *d) /*************************/ /*Read the channel number */ /*************************/ - //ui_ChannelNumber = inl(devpriv->iobase+i_Offset + 24); + /* ui_ChannelNumber = inl(devpriv->iobase+i_Offset + 24); */ /*************************************/ /*Read the digital analog input value */ /*************************************/ - //ui_DigitalInput = inl(devpriv->iobase+i_Offset + 28); + /* ui_DigitalInput = inl(devpriv->iobase+i_Offset + 28); */ ui_DigitalInput = inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 28); @@ -3117,13 +3110,13 @@ void v_APCI3200_Interrupt(int irq, void *d) /* Test if the value read is the channel value */ /***********************************************/ if (i_CalibrationFlag == 0) { - //ui_InterruptChannelValue[i_Count + 0] = ui_DigitalInput; + /* ui_InterruptChannelValue[i_Count + 0] = ui_DigitalInput; */ s_BoardInfos[dev->minor]. ui_InterruptChannelValue [s_BoardInfos[dev->minor]. i_Count + 0] = ui_DigitalInput; - //Begin JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values + /* Begin JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ /* printk("\n 1 - i_APCI3200_GetChannelCalibrationValue (dev, s_BoardInfos %i", ui_ChannelNumber); i_APCI3200_GetChannelCalibrationValue (dev, s_BoardInfos [dev->minor].ui_Channel_num, @@ -3131,14 +3124,14 @@ void v_APCI3200_Interrupt(int irq, void *d) &s_BoardInfos [dev->minor].ui_InterruptChannelValue[s_BoardInfos [dev->minor].i_Count + 7], &s_BoardInfos [dev->minor].ui_InterruptChannelValue[s_BoardInfos [dev->minor].i_Count + 8]); */ - //End JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values + /* End JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ /******************************************************/ /*Start the conversion of the calibration offset value */ /******************************************************/ i_APCI3200_ReadCalibrationOffsetValue (dev, &ui_DummyValue); - } //if (i_CalibrationFlag == 0) + } /* if (i_CalibrationFlag == 0) */ /**********************************************************/ /* Test if the value read is the calibration offset value */ /**********************************************************/ @@ -3149,7 +3142,7 @@ void v_APCI3200_Interrupt(int irq, void *d) /* Save the value */ /******************/ - //ui_InterruptChannelValue[i_Count + 1] = ui_DigitalInput; + /* ui_InterruptChannelValue[i_Count + 1] = ui_DigitalInput; */ s_BoardInfos[dev->minor]. ui_InterruptChannelValue [s_BoardInfos[dev->minor]. @@ -3160,7 +3153,7 @@ void v_APCI3200_Interrupt(int irq, void *d) /******************************************************/ i_APCI3200_ReadCalibrationGainValue(dev, &ui_DummyValue); - } //if (i_CalibrationFlag == 1) + } /* if (i_CalibrationFlag == 1) */ /******************************************************/ /*Test if the value read is the calibration gain value */ /******************************************************/ @@ -3170,48 +3163,48 @@ void v_APCI3200_Interrupt(int irq, void *d) /****************/ /*Save the value */ /****************/ - //ui_InterruptChannelValue[i_Count + 2] = ui_DigitalInput; + /* ui_InterruptChannelValue[i_Count + 2] = ui_DigitalInput; */ s_BoardInfos[dev->minor]. ui_InterruptChannelValue [s_BoardInfos[dev->minor]. i_Count + 2] = ui_DigitalInput; - //if(i_ScanType==1) + /* if(i_ScanType==1) */ if (s_BoardInfos[dev->minor]. i_ScanType == 1) { - //i_InterruptFlag=0; + /* i_InterruptFlag=0; */ s_BoardInfos[dev->minor]. i_InterruptFlag = 0; - //i_Count=i_Count + 6; - //Begin JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values - //s_BoardInfos [dev->minor].i_Count=s_BoardInfos [dev->minor].i_Count + 6; + /* i_Count=i_Count + 6; */ + /* Begin JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ + /* s_BoardInfos [dev->minor].i_Count=s_BoardInfos [dev->minor].i_Count + 6; */ s_BoardInfos[dev->minor]. i_Count = s_BoardInfos[dev-> minor].i_Count + 9; - //End JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values - } //if(i_ScanType==1) + /* End JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ + } /* if(i_ScanType==1) */ else { - //i_Count=0; + /* i_Count=0; */ s_BoardInfos[dev->minor]. i_Count = 0; - } //elseif(i_ScanType==1) - //if(i_ScanType!=1) + } /* elseif(i_ScanType==1) */ + /* if(i_ScanType!=1) */ if (s_BoardInfos[dev->minor]. i_ScanType != 1) { - i_ReturnValue = send_sig(SIGIO, devpriv->tsk_Current, 0); // send signal to the sample - } //if(i_ScanType!=1) + i_ReturnValue = send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */ + } /* if(i_ScanType!=1) */ else { - //if(i_ChannelCount==i_Sum) + /* if(i_ChannelCount==i_Sum) */ if (s_BoardInfos[dev->minor]. i_ChannelCount == s_BoardInfos[dev-> minor].i_Sum) { - send_sig(SIGIO, devpriv->tsk_Current, 0); // send signal to the sample + send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */ } - } //if(i_ScanType!=1) - } //if (i_CalibrationFlag == 2) - } // if ((ui_StatusRegister & 0x2) == 0x2) + } /* if(i_ScanType!=1) */ + } /* if (i_CalibrationFlag == 2) */ + } /* if ((ui_StatusRegister & 0x2) == 0x2) */ break; @@ -3220,7 +3213,7 @@ void v_APCI3200_Interrupt(int irq, void *d) /*Read the interrupt status register */ /************************************/ - //ui_StatusRegister = inl(devpriv->iobase+i_Offset + 16); + /* ui_StatusRegister = inl(devpriv->iobase+i_Offset + 16); */ ui_StatusRegister = inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 16); @@ -3230,7 +3223,7 @@ void v_APCI3200_Interrupt(int irq, void *d) if ((ui_StatusRegister & 0x2) == 0x2) { - //i_CJCFlag = ((inl(devpriv->iobase+i_Offset + 4) & 0x00000400) >> 10); + /* i_CJCFlag = ((inl(devpriv->iobase+i_Offset + 4) & 0x00000400) >> 10); */ i_CJCFlag = ((inl(devpriv->iobase + s_BoardInfos[dev-> @@ -3238,7 +3231,7 @@ void v_APCI3200_Interrupt(int irq, void *d) i_Offset + 4) & 0x00000400) >> 10); - //i_CalibrationFlag = ((inl(devpriv->iobase+i_Offset + 12) & 0x00060000) >> 17); + /* i_CalibrationFlag = ((inl(devpriv->iobase+i_Offset + 12) & 0x00060000) >> 17); */ i_CalibrationFlag = ((inl(devpriv->iobase + s_BoardInfos[dev-> @@ -3251,19 +3244,19 @@ void v_APCI3200_Interrupt(int irq, void *d) /*Read the channel number */ /*************************/ - //ui_ChannelNumber = inl(devpriv->iobase+i_Offset + 24); + /* ui_ChannelNumber = inl(devpriv->iobase+i_Offset + 24); */ ui_ChannelNumber = inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 24); - //Begin JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values + /* Begin JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ s_BoardInfos[dev->minor].ui_Channel_num = ui_ChannelNumber; - //End JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values + /* End JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ /************************************/ /*Read the digital temperature value */ /************************************/ - //ui_DigitalTemperature = inl(devpriv->iobase+i_Offset + 28); + /* ui_DigitalTemperature = inl(devpriv->iobase+i_Offset + 28); */ ui_DigitalTemperature = inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 28); @@ -3274,7 +3267,7 @@ void v_APCI3200_Interrupt(int irq, void *d) if ((i_CalibrationFlag == 0) && (i_CJCFlag == 0)) { - //ui_InterruptChannelValue[i_Count + 0]=ui_DigitalTemperature; + /* ui_InterruptChannelValue[i_Count + 0]=ui_DigitalTemperature; */ s_BoardInfos[dev->minor]. ui_InterruptChannelValue [s_BoardInfos[dev->minor]. @@ -3287,7 +3280,7 @@ void v_APCI3200_Interrupt(int irq, void *d) i_APCI3200_ReadCJCValue(dev, &ui_DummyValue); - } //if ((i_CalibrationFlag == 0) && (i_CJCFlag == 0)) + } /* if ((i_CalibrationFlag == 0) && (i_CJCFlag == 0)) */ /*****************************************/ /*Test if the value read is the CJC value */ @@ -3295,7 +3288,7 @@ void v_APCI3200_Interrupt(int irq, void *d) if ((i_CJCFlag == 1) && (i_CalibrationFlag == 0)) { - //ui_InterruptChannelValue[i_Count + 3]=ui_DigitalTemperature; + /* ui_InterruptChannelValue[i_Count + 3]=ui_DigitalTemperature; */ s_BoardInfos[dev->minor]. ui_InterruptChannelValue [s_BoardInfos[dev->minor]. @@ -3307,7 +3300,7 @@ void v_APCI3200_Interrupt(int irq, void *d) /******************************************************/ i_APCI3200_ReadCalibrationOffsetValue (dev, &ui_DummyValue); - } // if ((i_CJCFlag == 1) && (i_CalibrationFlag == 0)) + } /* if ((i_CJCFlag == 1) && (i_CalibrationFlag == 0)) */ /********************************************************/ /*Test if the value read is the calibration offset value */ @@ -3315,7 +3308,7 @@ void v_APCI3200_Interrupt(int irq, void *d) if ((i_CalibrationFlag == 1) && (i_CJCFlag == 0)) { - //ui_InterruptChannelValue[i_Count + 1]=ui_DigitalTemperature; + /* ui_InterruptChannelValue[i_Count + 1]=ui_DigitalTemperature; */ s_BoardInfos[dev->minor]. ui_InterruptChannelValue [s_BoardInfos[dev->minor]. @@ -3328,7 +3321,7 @@ void v_APCI3200_Interrupt(int irq, void *d) i_APCI3200_ReadCalibrationGainValue(dev, &ui_DummyValue); - } //if ((i_CalibrationFlag == 1) && (i_CJCFlag == 0)) + } /* if ((i_CalibrationFlag == 1) && (i_CJCFlag == 0)) */ /******************************************************/ /*Test if the value read is the calibration gain value */ @@ -3336,7 +3329,7 @@ void v_APCI3200_Interrupt(int irq, void *d) if ((i_CalibrationFlag == 2) && (i_CJCFlag == 0)) { - //ui_InterruptChannelValue[i_Count + 2]=ui_DigitalTemperature; + /* ui_InterruptChannelValue[i_Count + 2]=ui_DigitalTemperature; */ s_BoardInfos[dev->minor]. ui_InterruptChannelValue [s_BoardInfos[dev->minor]. @@ -3349,15 +3342,15 @@ void v_APCI3200_Interrupt(int irq, void *d) /*Test if the polarity is the same */ /**********************************/ - //if(i_CJCPolarity!=i_ADDIDATAPolarity) + /* if(i_CJCPolarity!=i_ADDIDATAPolarity) */ if (s_BoardInfos[dev->minor]. i_CJCPolarity != s_BoardInfos[dev->minor]. i_ADDIDATAPolarity) { i_ConvertCJCCalibration = 1; - } //if(i_CJCPolarity!=i_ADDIDATAPolarity) + } /* if(i_CJCPolarity!=i_ADDIDATAPolarity) */ else { - //if(i_CJCGain==i_ADDIDATAGain) + /* if(i_CJCGain==i_ADDIDATAGain) */ if (s_BoardInfos[dev->minor]. i_CJCGain == s_BoardInfos[dev-> @@ -3365,12 +3358,12 @@ void v_APCI3200_Interrupt(int irq, void *d) i_ADDIDATAGain) { i_ConvertCJCCalibration = 0; - } //if(i_CJCGain==i_ADDIDATAGain) + } /* if(i_CJCGain==i_ADDIDATAGain) */ else { i_ConvertCJCCalibration = 1; - } //elseif(i_CJCGain==i_ADDIDATAGain) - } //elseif(i_CJCPolarity!=i_ADDIDATAPolarity) + } /* elseif(i_CJCGain==i_ADDIDATAGain) */ + } /* elseif(i_CJCPolarity!=i_ADDIDATAPolarity) */ if (i_ConvertCJCCalibration == 1) { /****************************************************************/ /*Start the conversion of the calibration gain value for the CJC */ @@ -3378,10 +3371,10 @@ void v_APCI3200_Interrupt(int irq, void *d) i_APCI3200_ReadCJCCalOffset(dev, &ui_DummyValue); - } //if(i_ConvertCJCCalibration==1) + } /* if(i_ConvertCJCCalibration==1) */ else { - //ui_InterruptChannelValue[i_Count + 4]=0; - //ui_InterruptChannelValue[i_Count + 5]=0; + /* ui_InterruptChannelValue[i_Count + 4]=0; */ + /* ui_InterruptChannelValue[i_Count + 5]=0; */ s_BoardInfos[dev->minor]. ui_InterruptChannelValue [s_BoardInfos[dev-> @@ -3392,8 +3385,8 @@ void v_APCI3200_Interrupt(int irq, void *d) [s_BoardInfos[dev-> minor].i_Count + 5] = 0; - } //elseif(i_ConvertCJCCalibration==1) - } //else if ((i_CalibrationFlag == 2) && (i_CJCFlag == 0)) + } /* elseif(i_ConvertCJCCalibration==1) */ + } /* else if ((i_CalibrationFlag == 2) && (i_CJCFlag == 0)) */ /********************************************************************/ /*Test if the value read is the calibration offset value for the CJC */ @@ -3401,7 +3394,7 @@ void v_APCI3200_Interrupt(int irq, void *d) if ((i_CalibrationFlag == 1) && (i_CJCFlag == 1)) { - //ui_InterruptChannelValue[i_Count + 4]=ui_DigitalTemperature; + /* ui_InterruptChannelValue[i_Count + 4]=ui_DigitalTemperature; */ s_BoardInfos[dev->minor]. ui_InterruptChannelValue [s_BoardInfos[dev->minor]. @@ -3414,7 +3407,7 @@ void v_APCI3200_Interrupt(int irq, void *d) i_APCI3200_ReadCJCCalGain(dev, &ui_DummyValue); - } //if ((i_CalibrationFlag == 1) && (i_CJCFlag == 1)) + } /* if ((i_CalibrationFlag == 1) && (i_CJCFlag == 1)) */ /******************************************************************/ /*Test if the value read is the calibration gain value for the CJC */ @@ -3422,61 +3415,61 @@ void v_APCI3200_Interrupt(int irq, void *d) if ((i_CalibrationFlag == 2) && (i_CJCFlag == 1)) { - //ui_InterruptChannelValue[i_Count + 5]=ui_DigitalTemperature; + /* ui_InterruptChannelValue[i_Count + 5]=ui_DigitalTemperature; */ s_BoardInfos[dev->minor]. ui_InterruptChannelValue [s_BoardInfos[dev->minor]. i_Count + 5] = ui_DigitalTemperature; - //if(i_ScanType==1) + /* if(i_ScanType==1) */ if (s_BoardInfos[dev->minor]. i_ScanType == 1) { - //i_InterruptFlag=0; + /* i_InterruptFlag=0; */ s_BoardInfos[dev->minor]. i_InterruptFlag = 0; - //i_Count=i_Count + 6; - //Begin JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values - //s_BoardInfos [dev->minor].i_Count=s_BoardInfos [dev->minor].i_Count + 6; + /* i_Count=i_Count + 6; */ + /* Begin JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ + /* s_BoardInfos [dev->minor].i_Count=s_BoardInfos [dev->minor].i_Count + 6; */ s_BoardInfos[dev->minor]. i_Count = s_BoardInfos[dev-> minor].i_Count + 9; - //End JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values - } //if(i_ScanType==1) + /* End JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ + } /* if(i_ScanType==1) */ else { - //i_Count=0; + /* i_Count=0; */ s_BoardInfos[dev->minor]. i_Count = 0; - } //elseif(i_ScanType==1) + } /* elseif(i_ScanType==1) */ - //if(i_ScanType!=1) + /* if(i_ScanType!=1) */ if (s_BoardInfos[dev->minor]. i_ScanType != 1) { - send_sig(SIGIO, devpriv->tsk_Current, 0); // send signal to the sample - } //if(i_ScanType!=1) + send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */ + } /* if(i_ScanType!=1) */ else { - //if(i_ChannelCount==i_Sum) + /* if(i_ChannelCount==i_Sum) */ if (s_BoardInfos[dev->minor]. i_ChannelCount == s_BoardInfos[dev-> minor].i_Sum) { - send_sig(SIGIO, devpriv->tsk_Current, 0); // send signal to the sample + send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */ - } //if(i_ChannelCount==i_Sum) - } //else if(i_ScanType!=1) - } //if ((i_CalibrationFlag == 2) && (i_CJCFlag == 1)) + } /* if(i_ChannelCount==i_Sum) */ + } /* else if(i_ScanType!=1) */ + } /* if ((i_CalibrationFlag == 2) && (i_CJCFlag == 1)) */ - } //else if ((ui_StatusRegister & 0x2) == 0x2) + } /* else if ((ui_StatusRegister & 0x2) == 0x2) */ break; - } //switch(i_ADDIDATAType) + } /* switch(i_ADDIDATAType) */ break; case 2: case 3: i_APCI3200_InterruptHandleEos(dev); break; - } //switch(i_ScanType) + } /* switch(i_ScanType) */ return; } @@ -3499,22 +3492,22 @@ void v_APCI3200_Interrupt(int irq, void *d) | | +----------------------------------------------------------------------------+ */ -int i_APCI3200_InterruptHandleEos(struct comedi_device * dev) +int i_APCI3200_InterruptHandleEos(struct comedi_device *dev) { - UINT ui_StatusRegister = 0; + unsigned int ui_StatusRegister = 0; struct comedi_subdevice *s = dev->subdevices + 0; - //BEGIN JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 - //comedi_async *async = s->async; - //UINT *data; - //data=async->data+async->buf_int_ptr;//new samples added from here onwards + /* BEGIN JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ + /* comedi_async *async = s->async; */ + /* UINT *data; */ + /* data=async->data+async->buf_int_ptr;//new samples added from here onwards */ int n = 0, i = 0; - //END JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 + /* END JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ /************************************/ /*Read the interrupt status register */ /************************************/ - //ui_StatusRegister = inl(devpriv->iobase+i_Offset + 16); + /* ui_StatusRegister = inl(devpriv->iobase+i_Offset + 16); */ ui_StatusRegister = inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 16); @@ -3526,33 +3519,33 @@ int i_APCI3200_InterruptHandleEos(struct comedi_device * dev) /*************************/ /*Read the channel number */ /*************************/ - //ui_ChannelNumber = inl(devpriv->iobase+i_Offset + 24); - //BEGIN JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 - //This value is not used - //ui_ChannelNumber = inl(devpriv->iobase+s_BoardInfos [dev->minor].i_Offset + 24); + /* ui_ChannelNumber = inl(devpriv->iobase+i_Offset + 24); */ + /* BEGIN JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ + /* This value is not used */ + /* ui_ChannelNumber = inl(devpriv->iobase+s_BoardInfos [dev->minor].i_Offset + 24); */ s->async->events = 0; - //END JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 + /* END JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ /*************************************/ /*Read the digital Analog Input value */ /*************************************/ - //data[i_Count] = inl(devpriv->iobase+i_Offset + 28); - //Begin JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 - //data[s_BoardInfos [dev->minor].i_Count] = inl(devpriv->iobase+s_BoardInfos [dev->minor].i_Offset + 28); + /* data[i_Count] = inl(devpriv->iobase+i_Offset + 28); */ + /* Begin JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ + /* data[s_BoardInfos [dev->minor].i_Count] = inl(devpriv->iobase+s_BoardInfos [dev->minor].i_Offset + 28); */ s_BoardInfos[dev->minor].ui_ScanValueArray[s_BoardInfos[dev-> minor].i_Count] = inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 28); - //End JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 + /* End JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ - //if((i_Count == (i_LastChannel-i_FirstChannel+3))) + /* if((i_Count == (i_LastChannel-i_FirstChannel+3))) */ if ((s_BoardInfos[dev->minor].i_Count == (s_BoardInfos[dev->minor].i_LastChannel - s_BoardInfos[dev->minor]. i_FirstChannel + 3))) { - //Begin JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values + /* Begin JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ s_BoardInfos[dev->minor].i_Count++; for (i = s_BoardInfos[dev->minor].i_FirstChannel; @@ -3582,61 +3575,61 @@ int i_APCI3200_InterruptHandleEos(struct comedi_device * dev) * 3) + 2]); } - //End JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values + /* End JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ - //i_Count=-1; + /* i_Count=-1; */ s_BoardInfos[dev->minor].i_Count = -1; - //async->buf_int_count+=(i_LastChannel-i_FirstChannel+4)*sizeof(UINT); - //Begin JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 - //async->buf_int_count+=(s_BoardInfos [dev->minor].i_LastChannel-s_BoardInfos [dev->minor].i_FirstChannel+4)*sizeof(UINT); - //End JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 - //async->buf_int_ptr+=(i_LastChannel-i_FirstChannel+4)*sizeof(UINT); - //Begin JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 - //async->buf_int_ptr+=(s_BoardInfos [dev->minor].i_LastChannel-s_BoardInfos [dev->minor].i_FirstChannel+4)*sizeof(UINT); - //comedi_eos(dev,s); + /* async->buf_int_count+=(i_LastChannel-i_FirstChannel+4)*sizeof(unsigned int); */ + /* Begin JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ + /* async->buf_int_count+=(s_BoardInfos [dev->minor].i_LastChannel-s_BoardInfos [dev->minor].i_FirstChannel+4)*sizeof(unsigned int); */ + /* End JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ + /* async->buf_int_ptr+=(i_LastChannel-i_FirstChannel+4)*sizeof(unsigned int); */ + /* Begin JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ + /* async->buf_int_ptr+=(s_BoardInfos [dev->minor].i_LastChannel-s_BoardInfos [dev->minor].i_FirstChannel+4)*sizeof(unsigned int); */ + /* comedi_eos(dev,s); */ - // Set the event type (Comedi Buffer End Of Scan) + /* Set the event type (Comedi Buffer End Of Scan) */ s->async->events |= COMEDI_CB_EOS; - // Test if enougth memory is available and allocate it for 7 values - //n = comedi_buf_write_alloc(s->async, 7*sizeof(unsigned int)); + /* Test if enougth memory is available and allocate it for 7 values */ + /* n = comedi_buf_write_alloc(s->async, 7*sizeof(unsigned int)); */ n = comedi_buf_write_alloc(s->async, (7 + 12) * sizeof(unsigned int)); - // If not enougth memory available, event is set to Comedi Buffer Errror + /* If not enougth memory available, event is set to Comedi Buffer Errror */ if (n > ((7 + 12) * sizeof(unsigned int))) { printk("\ncomedi_buf_write_alloc n = %i", n); s->async->events |= COMEDI_CB_ERROR; } - // Write all 7 scan values in the comedi buffer + /* Write all 7 scan values in the comedi buffer */ comedi_buf_memcpy_to(s->async, 0, (unsigned int *) s_BoardInfos[dev->minor]. ui_ScanValueArray, (7 + 12) * sizeof(unsigned int)); - // Update comedi buffer pinters indexes + /* Update comedi buffer pinters indexes */ comedi_buf_write_free(s->async, (7 + 12) * sizeof(unsigned int)); - // Send events + /* Send events */ comedi_event(dev, s); - //End JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 + /* End JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ - //BEGIN JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 - // - //if (s->async->buf_int_ptr>=s->async->data_len) // for buffer rool over - // { - // /* buffer rollover */ - // s->async->buf_int_ptr=0; - // comedi_eobuf(dev,s); - // } - //End JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 + /* BEGIN JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ + /* */ + /* if (s->async->buf_int_ptr>=s->async->data_len) // for buffer rool over */ + /* { */ + /* /* buffer rollover */ */ + /* s->async->buf_int_ptr=0; */ + /* comedi_eobuf(dev,s); */ + /* } */ + /* End JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ } - //i_Count++; + /* i_Count++; */ s_BoardInfos[dev->minor].i_Count++; } - //i_InterruptFlag=0; + /* i_InterruptFlag=0; */ s_BoardInfos[dev->minor].i_InterruptFlag = 0; return 0; } diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.h b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.h index a6f57f55e79c..f3e7ebf8c1f3 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.h +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.h @@ -15,26 +15,26 @@ * any later version. */ -// Card Specific information +/* Card Specific information */ #define APCI3200_BOARD_VENDOR_ID 0x15B8 -//#define APCI3200_ADDRESS_RANGE 264 +/* #define APCI3200_ADDRESS_RANGE 264 */ int MODULE_NO; struct { - INT i_Gain; - INT i_Polarity; - INT i_OffsetRange; - INT i_Coupling; - INT i_SingleDiff; - INT i_AutoCalibration; - UINT ui_ReloadValue; - UINT ui_TimeUnitReloadVal; - INT i_Interrupt; - INT i_ModuleSelection; + int i_Gain; + int i_Polarity; + int i_OffsetRange; + int i_Coupling; + int i_SingleDiff; + int i_AutoCalibration; + unsigned int ui_ReloadValue; + unsigned int ui_TimeUnitReloadVal; + int i_Interrupt; + int i_ModuleSelection; } Config_Parameters_Module1, Config_Parameters_Module2, Config_Parameters_Module3, Config_Parameters_Module4; -//ANALOG INPUT RANGE +/* ANALOG INPUT RANGE */ static const struct comedi_lrange range_apci3200_ai = { 8, { BIP_RANGE(10), BIP_RANGE(5), @@ -55,7 +55,7 @@ static const struct comedi_lrange range_apci3300_ai = { 4, { } }; -//Analog Input related Defines +/* Analog Input related Defines */ #define APCI3200_AI_OFFSET_GAIN 0 #define APCI3200_AI_SC_TEST 4 #define APCI3200_AI_IRQ 8 @@ -89,98 +89,102 @@ static const struct comedi_lrange range_apci3300_ai = { 4, { #define ADDIDATA_UNIPOLAR 1 #define ADDIDATA_BIPOLAR 2 -//BEGIN JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values +/* BEGIN JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ #define MAX_MODULE 4 -//END JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values +/* END JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ -typedef struct { - ULONG ul_NumberOfValue; - ULONG *pul_ResistanceValue; - ULONG *pul_TemperatureValue; -} str_ADDIDATA_RTDStruct, *pstr_ADDIDATA_RTDStruct; +struct str_ADDIDATA_RTDStruct { + unsigned int ul_NumberOfValue; + unsigned int *pul_ResistanceValue; + unsigned int *pul_TemperatureValue; +}; -//BEGIN JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values -typedef struct { - // Begin JK 05/08/2003 change for Linux +/* BEGIN JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ +struct str_Module { + + /* Begin JK 05/08/2003 change for Linux */ unsigned long ul_CurrentSourceCJC; unsigned long ul_CurrentSource[5]; - // End JK 05/08/2003 change for Linux + /* End JK 05/08/2003 change for Linux */ - // Begin CG 15/02/02 Rev 1.0 -> Rev 1.1 : Add Header Type 1 - unsigned long ul_GainFactor[8]; // Gain Factor + /* Begin CG 15/02/02 Rev 1.0 -> Rev 1.1 : Add Header Type 1 */ + unsigned long ul_GainFactor[8]; /* Gain Factor */ unsigned int w_GainValue[10]; - // End CG 15/02/02 Rev 1.0 -> Rev 1.1 : Add Header Type 1 -} str_Module; -//END JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values + /* End CG 15/02/02 Rev 1.0 -> Rev 1.1 : Add Header Type 1 */ +}; -//BEGIN JK 06.07.04: Management of sevrals boards -typedef struct { - INT i_CJCAvailable; - INT i_CJCPolarity; - INT i_CJCGain; - INT i_InterruptFlag; - INT i_ADDIDATAPolarity; - INT i_ADDIDATAGain; - INT i_AutoCalibration; - INT i_ADDIDATAConversionTime; - INT i_ADDIDATAConversionTimeUnit; - INT i_ADDIDATAType; - INT i_ChannelNo; - INT i_ChannelCount; - INT i_ScanType; - INT i_FirstChannel; - INT i_LastChannel; - INT i_Sum; - INT i_Offset; - UINT ui_Channel_num; - INT i_Count; - INT i_Initialised; - //UINT ui_InterruptChannelValue[96]; //Buffer - UINT ui_InterruptChannelValue[144]; //Buffer - BYTE b_StructInitialized; - //Begin JK 19.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 - unsigned int ui_ScanValueArray[7 + 12]; // 7 is the maximal number of channels - //End JK 19.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 +/* END JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ - //Begin JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values - INT i_ConnectionType; - INT i_NbrOfModule; - str_Module s_Module[MAX_MODULE]; - //End JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values -} str_BoardInfos; -//END JK 06.07.04: Management of sevrals boards +/* BEGIN JK 06.07.04: Management of sevrals boards */ +struct str_BoardInfos { -// Hardware Layer functions for Apci3200 + int i_CJCAvailable; + int i_CJCPolarity; + int i_CJCGain; + int i_InterruptFlag; + int i_ADDIDATAPolarity; + int i_ADDIDATAGain; + int i_AutoCalibration; + int i_ADDIDATAConversionTime; + int i_ADDIDATAConversionTimeUnit; + int i_ADDIDATAType; + int i_ChannelNo; + int i_ChannelCount; + int i_ScanType; + int i_FirstChannel; + int i_LastChannel; + int i_Sum; + int i_Offset; + unsigned int ui_Channel_num; + int i_Count; + int i_Initialised; + /* UINT ui_InterruptChannelValue[96]; //Buffer */ + unsigned int ui_InterruptChannelValue[144]; /* Buffer */ + unsigned char b_StructInitialized; + /* Begin JK 19.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ + unsigned int ui_ScanValueArray[7 + 12]; /* 7 is the maximal number of channels */ + /* End JK 19.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ -//AI + /* Begin JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ + int i_ConnectionType; + int i_NbrOfModule; + struct str_Module s_Module[MAX_MODULE]; + /* End JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ +}; -INT i_APCI3200_ConfigAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s, +/* END JK 06.07.04: Management of sevrals boards */ + +/* Hardware Layer functions for Apci3200 */ + +/* AI */ + +int i_APCI3200_ConfigAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -INT i_APCI3200_ReadAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s, +int i_APCI3200_ReadAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -INT i_APCI3200_InsnWriteReleaseAnalogInput(struct comedi_device *dev, +int i_APCI3200_InsnWriteReleaseAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -INT i_APCI3200_InsnBits_AnalogInput_Test(struct comedi_device *dev, +int i_APCI3200_InsnBits_AnalogInput_Test(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -INT i_APCI3200_StopCyclicAcquisition(struct comedi_device *dev, struct comedi_subdevice *s); -INT i_APCI3200_InterruptHandleEos(struct comedi_device *dev); -INT i_APCI3200_CommandTestAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s, +int i_APCI3200_StopCyclicAcquisition(struct comedi_device *dev, struct comedi_subdevice *s); +int i_APCI3200_InterruptHandleEos(struct comedi_device *dev); +int i_APCI3200_CommandTestAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd); -INT i_APCI3200_CommandAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s); -INT i_APCI3200_ReadDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, +int i_APCI3200_CommandAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s); +int i_APCI3200_ReadDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -//Interrupt +/* Interrupt */ void v_APCI3200_Interrupt(int irq, void *d); int i_APCI3200_InterruptHandleEos(struct comedi_device *dev); -//Reset functions -INT i_APCI3200_Reset(struct comedi_device *dev); +/* Reset functions */ +int i_APCI3200_Reset(struct comedi_device *dev); int i_APCI3200_ReadCJCCalOffset(struct comedi_device *dev, unsigned int *data); int i_APCI3200_ReadCJCValue(struct comedi_device *dev, unsigned int *data); -int i_APCI3200_ReadCalibrationGainValue(struct comedi_device *dev, UINT *data); -int i_APCI3200_ReadCalibrationOffsetValue(struct comedi_device *dev, UINT *data); +int i_APCI3200_ReadCalibrationGainValue(struct comedi_device *dev, unsigned int *data); +int i_APCI3200_ReadCalibrationOffsetValue(struct comedi_device *dev, unsigned int *data); int i_APCI3200_Read1AnalogInputChannel(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c index 20391a91da03..ef21f03fc961 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c @@ -3,13 +3,13 @@ Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data-com - info@addi-data.com + ADDI-DATA GmbH + Dieselstrasse 3 + D-77833 Ottersweier + Tel: +19(0)7223/9493-0 + Fax: +49(0)7223/9493-92 + http://www.addi-data-com + info@addi-data.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. @@ -62,8 +62,8 @@ You shoud also find the complete GPL in the COPYING file accompanying this sourc | Task : Read value of the selected channel or port | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | -| UINT ui_NoOfChannels : No Of Channels To read | -| UINT *data : Data Pointer to read status | +| unsigned int ui_NoOfChannels : No Of Channels To read | +| unsigned int *data : Data Pointer to read status | +----------------------------------------------------------------------------+ | Output Parameters : -- | +----------------------------------------------------------------------------+ @@ -73,26 +73,26 @@ You shoud also find the complete GPL in the COPYING file accompanying this sourc +----------------------------------------------------------------------------+ */ -INT i_APCI3501_ReadDigitalInput(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI3501_ReadDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - UINT ui_Temp; - UINT ui_NoOfChannel; + unsigned int ui_Temp; + unsigned int ui_NoOfChannel; ui_NoOfChannel = CR_CHAN(insn->chanspec); ui_Temp = data[0]; *data = inl(devpriv->iobase + APCI3501_DIGITAL_IP); if (ui_Temp == 0) { *data = (*data >> ui_NoOfChannel) & 0x1; - } //if (ui_Temp==0) + } /* if (ui_Temp==0) */ else { if (ui_Temp == 1) { *data = *data & 0x3; - } //if (ui_Temp==1) + } /* if (ui_Temp==1) */ else { printk("\nSpecified channel not supported \n"); - } //elseif (ui_Temp==1) - } //elseif (ui_Temp==0) + } /* elseif (ui_Temp==1) */ + } /* elseif (ui_Temp==0) */ return insn->n; } @@ -105,7 +105,7 @@ INT i_APCI3501_ReadDigitalInput(struct comedi_device * dev, struct comedi_subdev | Task : Configures The Digital Output Subdevice. | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | -| UINT *data : Data Pointer contains | +| unsigned int *data : Data Pointer contains | | configuration parameters as below | | | | data[1] : 1 Enable VCC Interrupt | @@ -121,21 +121,21 @@ INT i_APCI3501_ReadDigitalInput(struct comedi_device * dev, struct comedi_subdev | | +----------------------------------------------------------------------------+ */ -int i_APCI3501_ConfigDigitalOutput(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI3501_ConfigDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if ((data[0] != 0) && (data[0] != 1)) { comedi_error(dev, "Not a valid Data !!! ,Data should be 1 or 0\n"); return -EINVAL; - } //if ( (data[0]!=0) && (data[0]!=1) ) + } /* if ( (data[0]!=0) && (data[0]!=1) ) */ if (data[0]) { devpriv->b_OutputMemoryStatus = ADDIDATA_ENABLE; - } // if (data[0]) + } /* if (data[0]) */ else { devpriv->b_OutputMemoryStatus = ADDIDATA_DISABLE; - } //else if (data[0]) + } /* else if (data[0]) */ return insn->n; } @@ -161,33 +161,33 @@ int i_APCI3501_ConfigDigitalOutput(struct comedi_device * dev, struct comedi_sub | | +----------------------------------------------------------------------------+ */ -INT i_APCI3501_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI3501_WriteDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - UINT ui_Temp, ui_Temp1; - UINT ui_NoOfChannel = CR_CHAN(insn->chanspec); // get the channel + unsigned int ui_Temp, ui_Temp1; + unsigned int ui_NoOfChannel = CR_CHAN(insn->chanspec); /* get the channel */ if (devpriv->b_OutputMemoryStatus) { ui_Temp = inl(devpriv->iobase + APCI3501_DIGITAL_OP); - } //if(devpriv->b_OutputMemoryStatus ) + } /* if(devpriv->b_OutputMemoryStatus ) */ else { ui_Temp = 0; - } //if(devpriv->b_OutputMemoryStatus ) + } /* if(devpriv->b_OutputMemoryStatus ) */ if (data[3] == 0) { if (data[1] == 0) { data[0] = (data[0] << ui_NoOfChannel) | ui_Temp; outl(data[0], devpriv->iobase + APCI3501_DIGITAL_OP); - } //if(data[1]==0) + } /* if(data[1]==0) */ else { if (data[1] == 1) { data[0] = (data[0] << (2 * data[2])) | ui_Temp; outl(data[0], devpriv->iobase + APCI3501_DIGITAL_OP); - } // if(data[1]==1) + } /* if(data[1]==1) */ else { printk("\nSpecified channel not supported\n"); - } //else if(data[1]==1) - } //elseif(data[1]==0) - } //if(data[3]==0) + } /* else if(data[1]==1) */ + } /* elseif(data[1]==0) */ + } /* if(data[3]==0) */ else { if (data[3] == 1) { if (data[1] == 0) { @@ -201,7 +201,7 @@ INT i_APCI3501_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subd data[0] = data[0] & ui_Temp; outl(data[0], devpriv->iobase + APCI3501_DIGITAL_OP); - } //if(data[1]==0) + } /* if(data[1]==0) */ else { if (data[1] == 1) { data[0] = ~data[0] & 0x3; @@ -215,17 +215,17 @@ INT i_APCI3501_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subd outl(data[0], devpriv->iobase + APCI3501_DIGITAL_OP); - } // if(data[1]==1) + } /* if(data[1]==1) */ else { printk("\nSpecified channel not supported\n"); - } //else if(data[1]==1) - } //elseif(data[1]==0) - } //if(data[3]==1); + } /* else if(data[1]==1) */ + } /* elseif(data[1]==0) */ + } /* if(data[3]==1); */ else { printk("\nSpecified functionality does not exist\n"); return -EINVAL; - } //if else data[3]==1) - } //if else data[3]==0) + } /* if else data[3]==1) */ + } /* if else data[3]==0) */ return insn->n; } @@ -238,8 +238,8 @@ INT i_APCI3501_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subd | Task : Read value of the selected channel or port | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | -| UINT ui_NoOfChannels : No Of Channels To read | -| UINT *data : Data Pointer to read status | +| unsigned int ui_NoOfChannels : No Of Channels To read | +| unsigned int *data : Data Pointer to read status | +----------------------------------------------------------------------------+ | Output Parameters : -- | +----------------------------------------------------------------------------+ @@ -248,27 +248,27 @@ INT i_APCI3501_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subd | | +----------------------------------------------------------------------------+ */ -INT i_APCI3501_ReadDigitalOutput(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI3501_ReadDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - UINT ui_Temp; - UINT ui_NoOfChannel; + unsigned int ui_Temp; + unsigned int ui_NoOfChannel; ui_NoOfChannel = CR_CHAN(insn->chanspec); ui_Temp = data[0]; *data = inl(devpriv->iobase + APCI3501_DIGITAL_OP); if (ui_Temp == 0) { *data = (*data >> ui_NoOfChannel) & 0x1; - } // if (ui_Temp==0) + } /* if (ui_Temp==0) */ else { if (ui_Temp == 1) { *data = *data & 0x3; - } // if (ui_Temp==1) + } /* if (ui_Temp==1) */ else { printk("\nSpecified channel not supported \n"); - } // else if (ui_Temp==1) - } // else if (ui_Temp==0) + } /* else if (ui_Temp==1) */ + } /* else if (ui_Temp==0) */ return insn->n; } @@ -298,8 +298,8 @@ INT i_APCI3501_ReadDigitalOutput(struct comedi_device * dev, struct comedi_subde | | +----------------------------------------------------------------------------+ */ -INT i_APCI3501_ConfigAnalogOutput(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI3501_ConfigAnalogOutput(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { outl(data[0], devpriv->iobase + APCI3501_ANALOG_OUTPUT + @@ -336,10 +336,10 @@ INT i_APCI3501_ConfigAnalogOutput(struct comedi_device * dev, struct comedi_subd | | +----------------------------------------------------------------------------+ */ -INT i_APCI3501_WriteAnalogOutput(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +int i_APCI3501_WriteAnalogOutput(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - ULONG ul_Command1 = 0, ul_Channel_no, ul_Polarity, ul_DAC_Ready = 0;; + unsigned int ul_Command1 = 0, ul_Channel_no, ul_Polarity, ul_DAC_Ready = 0;; ul_Channel_no = CR_CHAN(insn->chanspec); @@ -349,18 +349,18 @@ INT i_APCI3501_WriteAnalogOutput(struct comedi_device * dev, struct comedi_subde printk("\nIn WriteAnalogOutput :: Not Valid Data\n"); } - } // end if(devpriv->b_InterruptMode==MODE1) + } /* end if(devpriv->b_InterruptMode==MODE1) */ else { ul_Polarity = 0; if ((*data < 0) || (*data > 8192)) { printk("\nIn WriteAnalogOutput :: Not Valid Data\n"); } - } // end else + } /* end else */ if ((ul_Channel_no < 0) || (ul_Channel_no > 7)) { printk("\nIn WriteAnalogOutput :: Not Valid Channel\n"); - } // end if((ul_Channel_no<0)||(ul_Channel_no>7)) + } /* end if((ul_Channel_no<0)||(ul_Channel_no>7)) */ ul_DAC_Ready = inl(devpriv->iobase + APCI3501_ANALOG_OUTPUT); @@ -370,11 +370,11 @@ INT i_APCI3501_WriteAnalogOutput(struct comedi_device * dev, struct comedi_subde } if (ul_DAC_Ready) { -// Output the Value on the output channels. +/* Output the Value on the output channels. */ ul_Command1 = - (ULONG) ((ULONG) (ul_Channel_no & 0xFF) | - (ULONG) ((*data << 0x8) & 0x7FFFFF00L) | - (ULONG) (ul_Polarity)); + (unsigned int) ((unsigned int) (ul_Channel_no & 0xFF) | + (unsigned int) ((*data << 0x8) & 0x7FFFFF00L) | + (unsigned int) (ul_Polarity)); outl(ul_Command1, devpriv->iobase + APCI3501_ANALOG_OUTPUT + APCI3501_AO_PROG); @@ -392,7 +392,7 @@ INT i_APCI3501_WriteAnalogOutput(struct comedi_device * dev, struct comedi_subde | Task : Configures The Timer , Counter or Watchdog | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | -| UINT *data : Data Pointer contains | +| unsigned int *data : Data Pointer contains | | configuration parameters as below | | | | data[0] : 0 Configure As Timer | @@ -410,78 +410,78 @@ INT i_APCI3501_WriteAnalogOutput(struct comedi_device * dev, struct comedi_subde | | +----------------------------------------------------------------------------+ */ -INT i_APCI3501_ConfigTimerCounterWatchdog(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +int i_APCI3501_ConfigTimerCounterWatchdog(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - ULONG ul_Command1 = 0; + unsigned int ul_Command1 = 0; devpriv->tsk_Current = current; if (data[0] == ADDIDATA_WATCHDOG) { devpriv->b_TimerSelectMode = ADDIDATA_WATCHDOG; - //Disable the watchdog - outl(0x0, devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG); //disable Wa + /* Disable the watchdog */ + outl(0x0, devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG); /* disable Wa */ if (data[1] == 1) { - //Enable TIMER int & DISABLE ALL THE OTHER int SOURCES + /* Enable TIMER int & DISABLE ALL THE OTHER int SOURCES */ outl(0x02, devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG); } else { - outl(0x0, devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG); //disable Timer interrupt + outl(0x0, devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG); /* disable Timer interrupt */ } - //Loading the Timebase value + /* Loading the Timebase value */ outl(data[2], devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_TIMEBASE); - //Loading the Reload value + /* Loading the Reload value */ outl(data[3], devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_RELOAD_VALUE); - //Set the mode - ul_Command1 = inl(devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG) | 0xFFF819E0UL; //e2->e0 + /* Set the mode */ + ul_Command1 = inl(devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG) | 0xFFF819E0UL; /* e2->e0 */ outl(ul_Command1, devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG); - } //end if(data[0]==ADDIDATA_WATCHDOG) + } /* end if(data[0]==ADDIDATA_WATCHDOG) */ else if (data[0] == ADDIDATA_TIMER) { - //First Stop The Timer + /* First Stop The Timer */ ul_Command1 = inl(devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG); ul_Command1 = ul_Command1 & 0xFFFFF9FEUL; - outl(ul_Command1, devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG); //Stop The Timer + outl(ul_Command1, devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG); /* Stop The Timer */ devpriv->b_TimerSelectMode = ADDIDATA_TIMER; if (data[1] == 1) { - //Enable TIMER int & DISABLE ALL THE OTHER int SOURCES + /* Enable TIMER int & DISABLE ALL THE OTHER int SOURCES */ outl(0x02, devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG); } else { - outl(0x0, devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG); //disable Timer interrupt + outl(0x0, devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG); /* disable Timer interrupt */ } - // Loading Timebase + /* Loading Timebase */ outl(data[2], devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_TIMEBASE); - //Loading the Reload value + /* Loading the Reload value */ outl(data[3], devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_RELOAD_VALUE); - // printk ("\nTimer Address :: %x\n", (devpriv->iobase+APCI3501_WATCHDOG)); + /* printk ("\nTimer Address :: %x\n", (devpriv->iobase+APCI3501_WATCHDOG)); */ ul_Command1 = inl(devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG); ul_Command1 = (ul_Command1 & 0xFFF719E2UL) | 2UL << 13UL | 0x10UL; - outl(ul_Command1, devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG); //mode 2 + outl(ul_Command1, devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG); /* mode 2 */ - } //end if(data[0]==ADDIDATA_TIMER) + } /* end if(data[0]==ADDIDATA_TIMER) */ return insn->n; } @@ -495,7 +495,7 @@ INT i_APCI3501_ConfigTimerCounterWatchdog(struct comedi_device * dev, | Task : Start / Stop The Selected Timer , Counter or Watchdog | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | -| UINT *data : Data Pointer contains | +| unsigned int *data : Data Pointer contains | | configuration parameters as below | | | | data[0] : 0 Timer | @@ -511,10 +511,10 @@ INT i_APCI3501_ConfigTimerCounterWatchdog(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -int i_APCI3501_StartStopWriteTimerCounterWatchdog(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +int i_APCI3501_StartStopWriteTimerCounterWatchdog(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - ULONG ul_Command1 = 0; + unsigned int ul_Command1 = 0; int i_Temp; if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) { @@ -523,15 +523,15 @@ int i_APCI3501_StartStopWriteTimerCounterWatchdog(struct comedi_device * dev, inl(devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG); ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x1UL; - //Enable the Watchdog + /* Enable the Watchdog */ outl(ul_Command1, devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG); } - else if (data[1] == 0) //Stop The Watchdog + else if (data[1] == 0) /* Stop The Watchdog */ { - //Stop The Watchdog + /* Stop The Watchdog */ ul_Command1 = inl(devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG); @@ -547,8 +547,8 @@ int i_APCI3501_StartStopWriteTimerCounterWatchdog(struct comedi_device * dev, outl(ul_Command1, devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG); - } //if(data[1]==2) - } // end if (devpriv->b_TimerSelectMode==ADDIDATA_WATCHDOG) + } /* if(data[1]==2) */ + } /* end if (devpriv->b_TimerSelectMode==ADDIDATA_WATCHDOG) */ if (devpriv->b_TimerSelectMode == ADDIDATA_TIMER) { if (data[1] == 1) { @@ -557,12 +557,12 @@ int i_APCI3501_StartStopWriteTimerCounterWatchdog(struct comedi_device * dev, inl(devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG); ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x1UL; - //Enable the Timer + /* Enable the Timer */ outl(ul_Command1, devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG); } else if (data[1] == 0) { - //Stop The Timer + /* Stop The Timer */ ul_Command1 = inl(devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG); @@ -573,7 +573,7 @@ int i_APCI3501_StartStopWriteTimerCounterWatchdog(struct comedi_device * dev, } else if (data[1] == 2) { - //Trigger the Timer + /* Trigger the Timer */ ul_Command1 = inl(devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG); @@ -583,7 +583,7 @@ int i_APCI3501_StartStopWriteTimerCounterWatchdog(struct comedi_device * dev, APCI3501_TCW_PROG); } - } // end if (devpriv->b_TimerSelectMode==ADDIDATA_TIMER) + } /* end if (devpriv->b_TimerSelectMode==ADDIDATA_TIMER) */ i_Temp = inl(devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_TRIG_STATUS) & 0x1; return insn->n; @@ -598,7 +598,7 @@ int i_APCI3501_StartStopWriteTimerCounterWatchdog(struct comedi_device * dev, | Task : Read The Selected Timer , Counter or Watchdog | +----------------------------------------------------------------------------+ | Input Parameters : struct comedi_device *dev : Driver handle | -| UINT *data : Data Pointer contains | +| unsigned int *data : Data Pointer contains | | configuration parameters as below | | | | data[0] : 0 Timer | @@ -613,8 +613,8 @@ int i_APCI3501_StartStopWriteTimerCounterWatchdog(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -int i_APCI3501_ReadTimerCounterWatchdog(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +int i_APCI3501_ReadTimerCounterWatchdog(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) { @@ -622,14 +622,14 @@ int i_APCI3501_ReadTimerCounterWatchdog(struct comedi_device * dev, inl(devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_TRIG_STATUS) & 0x1; data[1] = inl(devpriv->iobase + APCI3501_WATCHDOG); - } // end if (devpriv->b_TimerSelectMode==ADDIDATA_WATCHDOG) + } /* end if (devpriv->b_TimerSelectMode==ADDIDATA_WATCHDOG) */ else if (devpriv->b_TimerSelectMode == ADDIDATA_TIMER) { data[0] = inl(devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_TRIG_STATUS) & 0x1; data[1] = inl(devpriv->iobase + APCI3501_WATCHDOG); - } // end if (devpriv->b_TimerSelectMode==ADDIDATA_TIMER) + } /* end if (devpriv->b_TimerSelectMode==ADDIDATA_TIMER) */ else if ((devpriv->b_TimerSelectMode != ADDIDATA_TIMER) && (devpriv->b_TimerSelectMode != ADDIDATA_WATCHDOG)) { @@ -654,10 +654,10 @@ int i_APCI3501_ReadTimerCounterWatchdog(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -int i_APCI3501_Reset(struct comedi_device * dev) +int i_APCI3501_Reset(struct comedi_device *dev) { int i_Count = 0, i_temp = 0; - ULONG ul_Command1 = 0, ul_Polarity, ul_DAC_Ready = 0; + unsigned int ul_Command1 = 0, ul_Polarity, ul_DAC_Ready = 0; outl(0x0, devpriv->iobase + APCI3501_DIGITAL_OP); outl(1, devpriv->iobase + APCI3501_ANALOG_OUTPUT + APCI3501_AO_VOLT_MODE); @@ -674,11 +674,11 @@ int i_APCI3501_Reset(struct comedi_device * dev) } if (ul_DAC_Ready) { - // Output the Value on the output channels. + /* Output the Value on the output channels. */ ul_Command1 = - (ULONG) ((ULONG) (i_Count & 0xFF) | - (ULONG) ((i_temp << 0x8) & 0x7FFFFF00L) | - (ULONG) (ul_Polarity)); + (unsigned int) ((unsigned int) (i_Count & 0xFF) | + (unsigned int) ((i_temp << 0x8) & 0x7FFFFF00L) | + (unsigned int) (ul_Polarity)); outl(ul_Command1, devpriv->iobase + APCI3501_ANALOG_OUTPUT + APCI3501_AO_PROG); @@ -711,7 +711,7 @@ void v_APCI3501_Interrupt(int irq, void *d) struct comedi_device *dev = d; unsigned int ui_Timer_AOWatchdog; unsigned long ul_Command1; - // Disable Interrupt + /* Disable Interrupt */ ul_Command1 = inl(devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG); @@ -728,8 +728,9 @@ void v_APCI3501_Interrupt(int irq, void *d) return; } - // Enable Interrupt - //Send a signal to from kernel to user space +/* +* Enable Interrupt Send a signal to from kernel to user space +*/ send_sig(SIGIO, devpriv->tsk_Current, 0); ul_Command1 = inl(devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG); diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.h b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.h index 51e7b66544ac..c456d75674b8 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.h +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.h @@ -15,7 +15,7 @@ * any later version. */ -// Card Specific information +/* Card Specific information */ #define APCI3501_BOARD_VENDOR_ID 0x15B8 #define APCI3501_ADDRESS_RANGE 255 @@ -23,7 +23,7 @@ #define APCI3501_DIGITAL_OP 0x40 #define APCI3501_ANALOG_OUTPUT 0x00 -//Analog Output related Defines +/* Analog Output related Defines */ #define APCI3501_AO_VOLT_MODE 0 #define APCI3501_AO_PROG 4 #define APCI3501_AO_TRIG_SCS 8 @@ -31,14 +31,14 @@ #define BIPOLAR 1 #define MODE0 0 #define MODE1 1 -// ANALOG OUTPUT RANGE +/* ANALOG OUTPUT RANGE */ struct comedi_lrange range_apci3501_ao = { 2, { BIP_RANGE(10), UNI_RANGE(10) } }; -//Watchdog Related Defines +/* Watchdog Related Defines */ #define APCI3501_WATCHDOG 0x20 #define APCI3501_TCW_SYNC_ENABLEDISABLE 0 @@ -52,32 +52,36 @@ struct comedi_lrange range_apci3501_ao = { 2, { #define ADDIDATA_TIMER 0 #define ADDIDATA_WATCHDOG 2 -// Hardware Layer functions for Apci3501 +/* Hardware Layer functions for Apci3501 */ -//AO -INT i_APCI3501_ConfigAnalogOutput(struct comedi_device *dev, struct comedi_subdevice *s, +/* AO */ +int i_APCI3501_ConfigAnalogOutput(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -INT i_APCI3501_WriteAnalogOutput(struct comedi_device *dev, struct comedi_subdevice *s, +int i_APCI3501_WriteAnalogOutput(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -//DI -// for di read -//INT i_APCI3501_ReadDigitalInput(struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data); +/* +* DI for di read INT i_APCI3501_ReadDigitalInput(struct +* comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn +* *insn,unsigned int *data); +*/ -INT i_APCI3501_ReadDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, +int i_APCI3501_ReadDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -//DO +/* DO */ int i_APCI3501_ConfigDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -INT i_APCI3501_WriteDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, +int i_APCI3501_WriteDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -INT i_APCI3501_ReadDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, +int i_APCI3501_ReadDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -// TIMER -// timer value is passed as u seconds -INT i_APCI3501_ConfigTimerCounterWatchdog(struct comedi_device *dev, +/* TIMER + * timer value is passed as u seconds + */ + +int i_APCI3501_ConfigTimerCounterWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); int i_APCI3501_StartStopWriteTimerCounterWatchdog(struct comedi_device *dev, @@ -87,8 +91,8 @@ int i_APCI3501_StartStopWriteTimerCounterWatchdog(struct comedi_device *dev, int i_APCI3501_ReadTimerCounterWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -//Interrupt +/* Interrupt */ void v_APCI3501_Interrupt(int irq, void *d); -//Reset functions +/* Reset functions */ int i_APCI3501_Reset(struct comedi_device *dev); diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3xxx.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3xxx.c index b7268e4da64e..338727879827 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3xxx.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3xxx.c @@ -3,13 +3,13 @@ Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data-com - info@addi-data.com + ADDI-DATA GmbH + Dieselstrasse 3 + D-77833 Ottersweier + Tel: +19(0)7223/9493-0 + Fax: +49(0)7223/9493-92 + http://www.addi-data-com + info@addi-data.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. @@ -54,7 +54,7 @@ You shoud also find the complete GPL in the COPYING file accompanying this sourc /* +----------------------------------------------------------------------------+ -| Function Name : INT i_APCI3XXX_TestConversionStarted | +| Function Name : int i_APCI3XXX_TestConversionStarted | | (struct comedi_device *dev) | +----------------------------------------------------------------------------+ | Task Test if any conversion started | @@ -68,18 +68,18 @@ You shoud also find the complete GPL in the COPYING file accompanying this sourc +----------------------------------------------------------------------------+ */ -int i_APCI3XXX_TestConversionStarted(struct comedi_device * dev) +int i_APCI3XXX_TestConversionStarted(struct comedi_device *dev) { - if ((readl((void *)(devpriv->dw_AiBase + 8)) & 0x80000UL) == 0x80000UL) { - return (1); - } else { - return (0); - } + if ((readl((void *)(devpriv->dw_AiBase + 8)) & 0x80000UL) == 0x80000UL) + return 1; + else + return 0; + } /* +----------------------------------------------------------------------------+ -| Function Name : INT i_APCI3XXX_AnalogInputConfigOperatingMode | +| Function Name : int i_APCI3XXX_AnalogInputConfigOperatingMode | | (struct comedi_device *dev, | | struct comedi_subdevice *s, | | struct comedi_insn *insn, | @@ -87,9 +87,9 @@ int i_APCI3XXX_TestConversionStarted(struct comedi_device * dev) +----------------------------------------------------------------------------+ | Task Converting mode and convert time selection | +----------------------------------------------------------------------------+ -| Input Parameters : b_SingleDiff = (BYTE) data[1]; | -| b_TimeBase = (BYTE) data[2]; (0: ns, 1:micros 2:ms)| -| dw_ReloadValue = (DWORD) data[3]; | +| Input Parameters : b_SingleDiff = (unsigned char) data[1]; | +| b_TimeBase = (unsigned char) data[2]; (0: ns, 1:micros 2:ms)| +| dw_ReloadValue = (unsigned int) data[3]; | | ........ | +----------------------------------------------------------------------------+ | Output Parameters : - | @@ -105,14 +105,14 @@ int i_APCI3XXX_TestConversionStarted(struct comedi_device * dev) +----------------------------------------------------------------------------+ */ -int i_APCI3XXX_AnalogInputConfigOperatingMode(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +int i_APCI3XXX_AnalogInputConfigOperatingMode(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - INT i_ReturnValue = insn->n; - BYTE b_TimeBase = 0; - BYTE b_SingleDiff = 0; - DWORD dw_ReloadValue = 0; - DWORD dw_TestReloadValue = 0; + int i_ReturnValue = insn->n; + unsigned char b_TimeBase = 0; + unsigned char b_SingleDiff = 0; + unsigned int dw_ReloadValue = 0; + unsigned int dw_TestReloadValue = 0; /************************/ /* Test the buffer size */ @@ -123,19 +123,19 @@ int i_APCI3XXX_AnalogInputConfigOperatingMode(struct comedi_device * dev, /* Get the Singel/Diff flag */ /****************************/ - b_SingleDiff = (BYTE) data[1]; + b_SingleDiff = (unsigned char) data[1]; /****************************/ /* Get the time base unitiy */ /****************************/ - b_TimeBase = (BYTE) data[2]; + b_TimeBase = (unsigned char) data[2]; /*************************************/ /* Get the convert time reload value */ /*************************************/ - dw_ReloadValue = (DWORD) data[3]; + dw_ReloadValue = (unsigned int) data[3]; /**********************/ /* Test the time base */ @@ -186,7 +186,7 @@ int i_APCI3XXX_AnalogInputConfigOperatingMode(struct comedi_device * dev, devpriv-> ui_EocEosConversionTime = - (UINT) + (unsigned int) dw_ReloadValue; devpriv-> b_EocEosConversionTimeBase @@ -204,7 +204,7 @@ int i_APCI3XXX_AnalogInputConfigOperatingMode(struct comedi_device * dev, /* Set the convert timing unit */ /*******************************/ - writel((DWORD) + writel((unsigned int) b_TimeBase, (void *) (devpriv-> @@ -268,12 +268,12 @@ int i_APCI3XXX_AnalogInputConfigOperatingMode(struct comedi_device * dev, i_ReturnValue = -101; } - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ -| Function Name : INT i_APCI3XXX_InsnConfigAnalogInput | +| Function Name : int i_APCI3XXX_InsnConfigAnalogInput | | (struct comedi_device *dev, | | struct comedi_subdevice *s, | | struct comedi_insn *insn, | @@ -281,9 +281,9 @@ int i_APCI3XXX_AnalogInputConfigOperatingMode(struct comedi_device * dev, +----------------------------------------------------------------------------+ | Task Converting mode and convert time selection | +----------------------------------------------------------------------------+ -| Input Parameters : b_ConvertMode = (BYTE) data[0]; | -| b_TimeBase = (BYTE) data[1]; (0: ns, 1:micros 2:ms)| -| dw_ReloadValue = (DWORD) data[2]; | +| Input Parameters : b_ConvertMode = (unsigned char) data[0]; | +| b_TimeBase = (unsigned char) data[1]; (0: ns, 1:micros 2:ms)| +| dw_ReloadValue = (unsigned int) data[2]; | | ........ | +----------------------------------------------------------------------------+ | Output Parameters : - | @@ -295,17 +295,17 @@ int i_APCI3XXX_AnalogInputConfigOperatingMode(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -int i_APCI3XXX_InsnConfigAnalogInput(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +int i_APCI3XXX_InsnConfigAnalogInput(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - INT i_ReturnValue = insn->n; + int i_ReturnValue = insn->n; /************************/ /* Test the buffer size */ /************************/ if (insn->n >= 1) { - switch ((BYTE) data[0]) { + switch ((unsigned char) data[0]) { case APCI3XXX_CONFIGURATION: i_ReturnValue = i_APCI3XXX_AnalogInputConfigOperatingMode(dev, @@ -326,12 +326,12 @@ int i_APCI3XXX_InsnConfigAnalogInput(struct comedi_device * dev, i_ReturnValue = -101; } - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ -| Function Name : INT i_APCI3XXX_InsnReadAnalogInput | +| Function Name : int i_APCI3XXX_InsnReadAnalogInput | | (struct comedi_device *dev, | | struct comedi_subdevice *s, | | struct comedi_insn *insn, | @@ -355,16 +355,16 @@ int i_APCI3XXX_InsnConfigAnalogInput(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -int i_APCI3XXX_InsnReadAnalogInput(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +int i_APCI3XXX_InsnReadAnalogInput(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - INT i_ReturnValue = insn->n; - BYTE b_Configuration = (BYTE) CR_RANGE(insn->chanspec); - BYTE b_Channel = (BYTE) CR_CHAN(insn->chanspec); - DWORD dw_Temp = 0; - DWORD dw_Configuration = 0; - DWORD dw_AcquisitionCpt = 0; - BYTE b_Interrupt = 0; + int i_ReturnValue = insn->n; + unsigned char b_Configuration = (unsigned char) CR_RANGE(insn->chanspec); + unsigned char b_Channel = (unsigned char) CR_CHAN(insn->chanspec); + unsigned int dw_Temp = 0; + unsigned int dw_Configuration = 0; + unsigned int dw_AcquisitionCpt = 0; + unsigned char b_Interrupt = 0; /*************************************/ /* Test if operating mode configured */ @@ -449,8 +449,8 @@ int i_APCI3XXX_InsnReadAnalogInput(struct comedi_device * dev, dw_Configuration = (b_Configuration & 3) | - ((DWORD) (b_Configuration >> 2) - << 6) | ((DWORD) devpriv-> + ((unsigned int) (b_Configuration >> 2) + << 6) | ((unsigned int) devpriv-> b_SingelDiff << 7); /***************************/ @@ -468,7 +468,7 @@ int i_APCI3XXX_InsnReadAnalogInput(struct comedi_device * dev, writel(dw_Temp | 0x100UL, (void *)(devpriv->dw_AiBase + 4)); - writel((DWORD) b_Channel, + writel((unsigned int) b_Channel, (void *)(devpriv->dw_AiBase + 0)); @@ -535,8 +535,7 @@ int i_APCI3XXX_InsnReadAnalogInput(struct comedi_device * dev, dw_Temp = dw_Temp & 1; - } - while (dw_Temp != 1); + } while (dw_Temp != 1); /*************************/ /* Read the analog value */ @@ -585,7 +584,7 @@ int i_APCI3XXX_InsnReadAnalogInput(struct comedi_device * dev, printk("Operating mode not configured\n"); i_ReturnValue = -1; } - return (i_ReturnValue); + return i_ReturnValue; } /* @@ -607,15 +606,15 @@ int i_APCI3XXX_InsnReadAnalogInput(struct comedi_device * dev, void v_APCI3XXX_Interrupt(int irq, void *d) { struct comedi_device *dev = d; - BYTE b_CopyCpt = 0; - DWORD dw_Status = 0; + unsigned char b_CopyCpt = 0; + unsigned int dw_Status = 0; /***************************/ /* Test if interrupt occur */ /***************************/ - if (((dw_Status = readl((void *)(devpriv->dw_AiBase + 16))) & 0x2UL) == - 0x2UL) { + dw_Status = readl((void *)(devpriv->dw_AiBase + 16)); + if ( (dw_Status & 0x2UL) == 0x2UL) { /***********************/ /* Reset the interrupt */ /***********************/ @@ -635,7 +634,7 @@ void v_APCI3XXX_Interrupt(int irq, void *d) b_CopyCpt < devpriv->ui_AiNbrofChannels; b_CopyCpt++) { devpriv->ui_AiReadData[b_CopyCpt] = - (UINT) readl((void *)(devpriv-> + (unsigned int) readl((void *)(devpriv-> dw_AiBase + 28)); } @@ -662,7 +661,7 @@ void v_APCI3XXX_Interrupt(int irq, void *d) /* +----------------------------------------------------------------------------+ -| Function Name : INT i_APCI3XXX_InsnWriteAnalogOutput | +| Function Name : int i_APCI3XXX_InsnWriteAnalogOutput | | (struct comedi_device *dev, | | struct comedi_subdevice *s, | | struct comedi_insn *insn, | @@ -684,13 +683,13 @@ void v_APCI3XXX_Interrupt(int irq, void *d) +----------------------------------------------------------------------------+ */ -int i_APCI3XXX_InsnWriteAnalogOutput(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +int i_APCI3XXX_InsnWriteAnalogOutput(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - BYTE b_Range = (BYTE) CR_RANGE(insn->chanspec); - BYTE b_Channel = (BYTE) CR_CHAN(insn->chanspec); - DWORD dw_Status = 0; - INT i_ReturnValue = insn->n; + unsigned char b_Range = (unsigned char) CR_RANGE(insn->chanspec); + unsigned char b_Channel = (unsigned char) CR_CHAN(insn->chanspec); + unsigned int dw_Status = 0; + int i_ReturnValue = insn->n; /************************/ /* Test the buffer size */ @@ -729,8 +728,7 @@ int i_APCI3XXX_InsnWriteAnalogOutput(struct comedi_device * dev, dw_Status = readl((void *)(devpriv-> dw_AiBase + 96)); - } - while ((dw_Status & 0x100) != 0x100); + } while ((dw_Status & 0x100) != 0x100); } else { /***************************/ /* Channel not initialised */ @@ -757,7 +755,7 @@ int i_APCI3XXX_InsnWriteAnalogOutput(struct comedi_device * dev, i_ReturnValue = -101; } - return (i_ReturnValue); + return i_ReturnValue; } /* @@ -768,7 +766,7 @@ int i_APCI3XXX_InsnWriteAnalogOutput(struct comedi_device * dev, /* +----------------------------------------------------------------------------+ -| Function Name : INT i_APCI3XXX_InsnConfigInitTTLIO | +| Function Name : int i_APCI3XXX_InsnConfigInitTTLIO | | (struct comedi_device *dev, | | struct comedi_subdevice *s, | | struct comedi_insn *insn, | @@ -778,8 +776,8 @@ int i_APCI3XXX_InsnWriteAnalogOutput(struct comedi_device * dev, | for you call any other function witch access of TTL. | | APCI3XXX_TTL_INIT_DIRECTION_PORT2(user inputs for direction)| +----------------------------------------------------------------------------+ -| Input Parameters : b_InitType = (BYTE) data[0]; | -| b_Port2Mode = (BYTE) data[1]; | +| Input Parameters : b_InitType = (unsigned char) data[0]; | +| b_Port2Mode = (unsigned char) data[1]; | +----------------------------------------------------------------------------+ | Output Parameters : - | +----------------------------------------------------------------------------+ @@ -791,11 +789,11 @@ int i_APCI3XXX_InsnWriteAnalogOutput(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -int i_APCI3XXX_InsnConfigInitTTLIO(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +int i_APCI3XXX_InsnConfigInitTTLIO(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - INT i_ReturnValue = insn->n; - BYTE b_Command = 0; + int i_ReturnValue = insn->n; + unsigned char b_Command = 0; /************************/ /* Test the buffer size */ @@ -806,7 +804,7 @@ int i_APCI3XXX_InsnConfigInitTTLIO(struct comedi_device * dev, /* Get the command */ /* **************** */ - b_Command = (BYTE) data[0]; + b_Command = (unsigned char) data[0]; /********************/ /* Test the command */ @@ -888,7 +886,7 @@ int i_APCI3XXX_InsnConfigInitTTLIO(struct comedi_device * dev, } } - return (i_ReturnValue); + return i_ReturnValue; } /* @@ -899,7 +897,7 @@ int i_APCI3XXX_InsnConfigInitTTLIO(struct comedi_device * dev, /* +----------------------------------------------------------------------------+ -| Function Name : INT i_APCI3XXX_InsnBitsTTLIO | +| Function Name : int i_APCI3XXX_InsnBitsTTLIO | | (struct comedi_device *dev, | | struct comedi_subdevice *s, | | struct comedi_insn *insn, | @@ -919,14 +917,14 @@ int i_APCI3XXX_InsnConfigInitTTLIO(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -int i_APCI3XXX_InsnBitsTTLIO(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +int i_APCI3XXX_InsnBitsTTLIO(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - INT i_ReturnValue = insn->n; - BYTE b_ChannelCpt = 0; - DWORD dw_ChannelMask = 0; - DWORD dw_BitMask = 0; - DWORD dw_Status = 0; + int i_ReturnValue = insn->n; + unsigned char b_ChannelCpt = 0; + unsigned int dw_ChannelMask = 0; + unsigned int dw_BitMask = 0; + unsigned int dw_Status = 0; /************************/ /* Test the buffer size */ @@ -1051,12 +1049,12 @@ int i_APCI3XXX_InsnBitsTTLIO(struct comedi_device * dev, i_ReturnValue = -101; } - return (i_ReturnValue); + return i_ReturnValue; } /* +----------------------------------------------------------------------------+ -| Function Name : INT i_APCI3XXX_InsnReadTTLIO | +| Function Name : int i_APCI3XXX_InsnReadTTLIO | | (struct comedi_device *dev, | | struct comedi_subdevice *s, | | struct comedi_insn *insn, | @@ -1074,11 +1072,11 @@ int i_APCI3XXX_InsnBitsTTLIO(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -int i_APCI3XXX_InsnReadTTLIO(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +int i_APCI3XXX_InsnReadTTLIO(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - BYTE b_Channel = (BYTE) CR_CHAN(insn->chanspec); - INT i_ReturnValue = insn->n; + unsigned char b_Channel = (unsigned char) CR_CHAN(insn->chanspec); + int i_ReturnValue = insn->n; unsigned int *pls_ReadData = data; /************************/ @@ -1157,7 +1155,7 @@ int i_APCI3XXX_InsnReadTTLIO(struct comedi_device * dev, i_ReturnValue = -101; } - return (i_ReturnValue); + return i_ReturnValue; } /* @@ -1168,7 +1166,7 @@ int i_APCI3XXX_InsnReadTTLIO(struct comedi_device * dev, /* +----------------------------------------------------------------------------+ -| Function Name : INT i_APCI3XXX_InsnWriteTTLIO | +| Function Name : int i_APCI3XXX_InsnWriteTTLIO | | (struct comedi_device *dev, | | struct comedi_subdevice *s, | | struct comedi_insn *insn, | @@ -1187,20 +1185,20 @@ int i_APCI3XXX_InsnReadTTLIO(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -int i_APCI3XXX_InsnWriteTTLIO(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +int i_APCI3XXX_InsnWriteTTLIO(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - INT i_ReturnValue = insn->n; - BYTE b_Channel = (BYTE) CR_CHAN(insn->chanspec); - BYTE b_State = 0; - DWORD dw_Status = 0; + int i_ReturnValue = insn->n; + unsigned char b_Channel = (unsigned char) CR_CHAN(insn->chanspec); + unsigned char b_State = 0; + unsigned int dw_Status = 0; /************************/ /* Test the buffer size */ /************************/ if (insn->n >= 1) { - b_State = (BYTE) data[0]; + b_State = (unsigned char) data[0]; /***********************/ /* Test if read port 0 */ @@ -1269,7 +1267,7 @@ int i_APCI3XXX_InsnWriteTTLIO(struct comedi_device * dev, i_ReturnValue = -101; } - return (i_ReturnValue); + return i_ReturnValue; } /* @@ -1298,12 +1296,12 @@ int i_APCI3XXX_InsnWriteTTLIO(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -int i_APCI3XXX_InsnReadDigitalInput(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +int i_APCI3XXX_InsnReadDigitalInput(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - INT i_ReturnValue = insn->n; - BYTE b_Channel = (BYTE) CR_CHAN(insn->chanspec); - DWORD dw_Temp = 0; + int i_ReturnValue = insn->n; + unsigned char b_Channel = (unsigned char) CR_CHAN(insn->chanspec); + unsigned int dw_Temp = 0; /***************************/ /* Test the channel number */ @@ -1334,7 +1332,7 @@ int i_APCI3XXX_InsnReadDigitalInput(struct comedi_device * dev, i_ReturnValue = -3; } - return (i_ReturnValue); + return i_ReturnValue; } /* @@ -1356,11 +1354,11 @@ int i_APCI3XXX_InsnReadDigitalInput(struct comedi_device * dev, | -101 : Data size error | +----------------------------------------------------------------------------+ */ -int i_APCI3XXX_InsnBitsDigitalInput(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +int i_APCI3XXX_InsnBitsDigitalInput(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - INT i_ReturnValue = insn->n; - DWORD dw_Temp = 0; + int i_ReturnValue = insn->n; + unsigned int dw_Temp = 0; /************************/ /* Test the buffer size */ @@ -1378,7 +1376,7 @@ int i_APCI3XXX_InsnBitsDigitalInput(struct comedi_device * dev, i_ReturnValue = -101; } - return (i_ReturnValue); + return i_ReturnValue; } /* @@ -1409,14 +1407,14 @@ int i_APCI3XXX_InsnBitsDigitalInput(struct comedi_device * dev, | -101 : Data size error | +----------------------------------------------------------------------------+ */ -int i_APCI3XXX_InsnBitsDigitalOutput(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +int i_APCI3XXX_InsnBitsDigitalOutput(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - INT i_ReturnValue = insn->n; - BYTE b_ChannelCpt = 0; - DWORD dw_ChannelMask = 0; - DWORD dw_BitMask = 0; - DWORD dw_Status = 0; + int i_ReturnValue = insn->n; + unsigned char b_ChannelCpt = 0; + unsigned int dw_ChannelMask = 0; + unsigned int dw_BitMask = 0; + unsigned int dw_Status = 0; /************************/ /* Test the buffer size */ @@ -1481,7 +1479,7 @@ int i_APCI3XXX_InsnBitsDigitalOutput(struct comedi_device * dev, i_ReturnValue = -101; } - return (i_ReturnValue); + return i_ReturnValue; } /* @@ -1505,13 +1503,13 @@ int i_APCI3XXX_InsnBitsDigitalOutput(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -int i_APCI3XXX_InsnWriteDigitalOutput(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +int i_APCI3XXX_InsnWriteDigitalOutput(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - INT i_ReturnValue = insn->n; - BYTE b_Channel = CR_CHAN(insn->chanspec); - BYTE b_State = 0; - DWORD dw_Status = 0; + int i_ReturnValue = insn->n; + unsigned char b_Channel = CR_CHAN(insn->chanspec); + unsigned char b_State = 0; + unsigned int dw_Status = 0; /************************/ /* Test the buffer size */ @@ -1527,7 +1525,7 @@ int i_APCI3XXX_InsnWriteDigitalOutput(struct comedi_device * dev, /* Get the command */ /*******************/ - b_State = (BYTE) data[0]; + b_State = (unsigned char) data[0]; /********************************/ /* Read the digital output port */ @@ -1557,7 +1555,7 @@ int i_APCI3XXX_InsnWriteDigitalOutput(struct comedi_device * dev, i_ReturnValue = -101; } - return (i_ReturnValue); + return i_ReturnValue; } /* @@ -1580,12 +1578,12 @@ int i_APCI3XXX_InsnWriteDigitalOutput(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -int i_APCI3XXX_InsnReadDigitalOutput(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +int i_APCI3XXX_InsnReadDigitalOutput(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - INT i_ReturnValue = insn->n; - BYTE b_Channel = CR_CHAN(insn->chanspec); - DWORD dw_Status = 0; + int i_ReturnValue = insn->n; + unsigned char b_Channel = CR_CHAN(insn->chanspec); + unsigned int dw_Status = 0; /************************/ /* Test the buffer size */ @@ -1622,7 +1620,7 @@ int i_APCI3XXX_InsnReadDigitalOutput(struct comedi_device * dev, i_ReturnValue = -101; } - return (i_ReturnValue); + return i_ReturnValue; } /* @@ -1638,7 +1636,7 @@ int i_APCI3XXX_InsnReadDigitalOutput(struct comedi_device * dev, +----------------------------------------------------------------------------+ */ -int i_APCI3XXX_Reset(struct comedi_device * dev) +int i_APCI3XXX_Reset(struct comedi_device *dev) { unsigned char b_Cpt = 0; diff --git a/drivers/staging/comedi/drivers/addi_apci_035.c b/drivers/staging/comedi/drivers/addi_apci_035.c index bac018202fe8..da454e854c4c 100644 --- a/drivers/staging/comedi/drivers/addi_apci_035.c +++ b/drivers/staging/comedi/drivers/addi_apci_035.c @@ -1,5 +1,5 @@ #define CONFIG_APCI_035 1 -#define ADDIDATA_WATCHDOG 2 // Or shold it be something else +#define ADDIDATA_WATCHDOG 2 /* Or shold it be something else */ #include "addi-data/addi_common.c" diff --git a/drivers/staging/comedi/drivers/adl_pci6208.c b/drivers/staging/comedi/drivers/adl_pci6208.c index f710f551820d..b4807fc7eb01 100644 --- a/drivers/staging/comedi/drivers/adl_pci6208.c +++ b/drivers/staging/comedi/drivers/adl_pci6208.c @@ -61,35 +61,35 @@ struct pci6208_board { const char *name; unsigned short dev_id; /* `lspci` will show you this */ int ao_chans; - //int ao_bits; + /* int ao_bits; */ }; static const struct pci6208_board pci6208_boards[] = { /*{ - name : "pci6208v", - dev_id : 0x6208, //not sure - ao_chans: 8 - //, ao_bits : 16 + .name = "pci6208v", + .dev_id = 0x6208, // not sure + .ao_chans = 8 + // , .ao_bits = 16 }, { - name : "pci6216v", - dev_id : 0x6208, //not sure - ao_chans: 16 - //, ao_bits : 16 + .name = "pci6216v", + .dev_id = 0x6208, // not sure + .ao_chans = 16 + // , .ao_bits = 16 }, */ { - name: "pci6208a", - dev_id: 0x6208, - ao_chans:8 - //, ao_bits : 16 + .name = "pci6208a", + .dev_id = 0x6208, + .ao_chans = 8 + /* , .ao_bits = 16 */ } }; /* This is used by modprobe to translate PCI IDs to drivers. Should * only be used for PCI and ISA-PnP devices */ static DEFINE_PCI_DEVICE_TABLE(pci6208_pci_table) = { - //{ PCI_VENDOR_ID_ADLINK, 0x6208, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - //{ PCI_VENDOR_ID_ADLINK, 0x6208, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + /* { PCI_VENDOR_ID_ADLINK, 0x6208, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, */ + /* { PCI_VENDOR_ID_ADLINK, 0x6208, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, */ {PCI_VENDOR_ID_ADLINK, 0x6208, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0} }; @@ -107,35 +107,32 @@ struct pci6208_private { #define devpriv ((struct pci6208_private *)dev->private) -static int pci6208_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int pci6208_detach(struct comedi_device * dev); - -#define pci6208_board_nbr \ - (sizeof(pci6208_boards) / sizeof(struct pci6208_board)) +static int pci6208_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int pci6208_detach(struct comedi_device *dev); static struct comedi_driver driver_pci6208 = { - driver_name:PCI6208_DRIVER_NAME, - module:THIS_MODULE, - attach:pci6208_attach, - detach:pci6208_detach, + .driver_name = PCI6208_DRIVER_NAME, + .module = THIS_MODULE, + .attach = pci6208_attach, + .detach = pci6208_detach, }; COMEDI_PCI_INITCLEANUP(driver_pci6208, pci6208_pci_table); -static int pci6208_find_device(struct comedi_device * dev, int bus, int slot); +static int pci6208_find_device(struct comedi_device *dev, int bus, int slot); static int pci6208_pci_setup(struct pci_dev *pci_dev, unsigned long *io_base_ptr, int dev_minor); /*read/write functions*/ -static int pci6208_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int pci6208_ao_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -//static int pci6208_dio_insn_bits(struct comedi_device *dev,struct comedi_subdevice *s, -// struct comedi_insn *insn,unsigned int *data); -//static int pci6208_dio_insn_config(struct comedi_device *dev,struct comedi_subdevice *s, -// struct comedi_insn *insn,unsigned int *data); +static int pci6208_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int pci6208_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +/* static int pci6208_dio_insn_bits(struct comedi_device *dev,struct comedi_subdevice *s, */ +/* struct comedi_insn *insn,unsigned int *data); */ +/* static int pci6208_dio_insn_config(struct comedi_device *dev,struct comedi_subdevice *s, */ +/* struct comedi_insn *insn,unsigned int *data); */ /* * Attach is called by the Comedi core to configure the driver @@ -143,7 +140,7 @@ static int pci6208_ao_rinsn(struct comedi_device * dev, struct comedi_subdevice * in the driver structure, dev->board_ptr contains that * address. */ -static int pci6208_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int pci6208_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; int retval; @@ -176,22 +173,22 @@ static int pci6208_attach(struct comedi_device * dev, struct comedi_devconfig * s = dev->subdevices + 0; /* analog output subdevice */ s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE; //anything else to add here?? + s->subdev_flags = SDF_WRITABLE; /* anything else to add here?? */ s->n_chan = thisboard->ao_chans; - s->maxdata = 0xffff; //16-bit DAC - s->range_table = &range_bipolar10; //this needs to be checked. + s->maxdata = 0xffff; /* 16-bit DAC */ + s->range_table = &range_bipolar10; /* this needs to be checked. */ s->insn_write = pci6208_ao_winsn; s->insn_read = pci6208_ao_rinsn; - //s=dev->subdevices+1; + /* s=dev->subdevices+1; */ /* digital i/o subdevice */ - //s->type=COMEDI_SUBD_DIO; - //s->subdev_flags=SDF_READABLE|SDF_WRITABLE; - //s->n_chan=16; - //s->maxdata=1; - //s->range_table=&range_digital; - //s->insn_bits = pci6208_dio_insn_bits; - //s->insn_config = pci6208_dio_insn_config; + /* s->type=COMEDI_SUBD_DIO; */ + /* s->subdev_flags=SDF_READABLE|SDF_WRITABLE; */ + /* s->n_chan=16; */ + /* s->maxdata=1; */ + /* s->range_table=&range_digital; */ + /* s->insn_bits = pci6208_dio_insn_bits; */ + /* s->insn_config = pci6208_dio_insn_config; */ printk("attached\n"); @@ -206,7 +203,7 @@ static int pci6208_attach(struct comedi_device * dev, struct comedi_devconfig * * allocated by _attach(). dev->private and dev->subdevices are * deallocated automatically by the core. */ -static int pci6208_detach(struct comedi_device * dev) +static int pci6208_detach(struct comedi_device *dev) { printk("comedi%d: pci6208: remove\n", dev->minor); @@ -220,8 +217,8 @@ static int pci6208_detach(struct comedi_device * dev) return 0; } -static int pci6208_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pci6208_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i = 0, Data_Read; unsigned short chan = CR_CHAN(insn->chanspec); @@ -245,8 +242,8 @@ static int pci6208_ao_winsn(struct comedi_device * dev, struct comedi_subdevice /* AO subdevices should have a read insn as well as a write insn. * Usually this means copying a value stored in devpriv. */ -static int pci6208_ao_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pci6208_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i; int chan = CR_CHAN(insn->chanspec); @@ -262,51 +259,51 @@ static int pci6208_ao_rinsn(struct comedi_device * dev, struct comedi_subdevice * useful to applications if you implement the insn_bits interface. * This allows packed reading/writing of the DIO channels. The * comedi core can convert between insn_bits and insn_read/write */ -//static int pci6208_dio_insn_bits(struct comedi_device *dev,struct comedi_subdevice *s, -// struct comedi_insn *insn,unsigned int *data) -//{ -// if(insn->n!=2)return -EINVAL; +/* static int pci6208_dio_insn_bits(struct comedi_device *dev,struct comedi_subdevice *s, */ +/* struct comedi_insn *insn,unsigned int *data) */ +/* { */ +/* if(insn->n!=2)return -EINVAL; */ /* The insn data is a mask in data[0] and the new data * in data[1], each channel cooresponding to a bit. */ -// if(data[0]){ -// s->state &= ~data[0]; -// s->state |= data[0]&data[1]; +/* if(data[0]){ */ +/* s->state &= ~data[0]; */ +/* s->state |= data[0]&data[1]; */ /* Write out the new digital output lines */ - //outw(s->state,dev->iobase + SKEL_DIO); -// } + /* outw(s->state,dev->iobase + SKEL_DIO); */ +/* } */ /* on return, data[1] contains the value of the digital * input and output lines. */ - //data[1]=inw(dev->iobase + SKEL_DIO); + /* data[1]=inw(dev->iobase + SKEL_DIO); */ /* or we could just return the software copy of the output values if * it was a purely digital output subdevice */ - //data[1]=s->state; + /* data[1]=s->state; */ -// return 2; -//} +/* return 2; */ +/* } */ -//static int pci6208_dio_insn_config(struct comedi_device *dev,struct comedi_subdevice *s, -// struct comedi_insn *insn,unsigned int *data) -//{ -// int chan=CR_CHAN(insn->chanspec); +/* static int pci6208_dio_insn_config(struct comedi_device *dev,struct comedi_subdevice *s, */ +/* struct comedi_insn *insn,unsigned int *data) */ +/* { */ +/* int chan=CR_CHAN(insn->chanspec); */ /* The input or output configuration of each digital line is * configured by a special insn_config instruction. chanspec * contains the channel to be changed, and data[0] contains the * value COMEDI_INPUT or COMEDI_OUTPUT. */ -// if(data[0]==COMEDI_OUTPUT){ -// s->io_bits |= 1<io_bits &= ~(1<io_bits,dev->iobase + SKEL_DIO_CONFIG); +/* if(data[0]==COMEDI_OUTPUT){ */ +/* s->io_bits |= 1<io_bits &= ~(1<io_bits,dev->iobase + SKEL_DIO_CONFIG); */ -// return 1; -//} +/* return 1; */ +/* } */ -static int pci6208_find_device(struct comedi_device * dev, int bus, int slot) +static int pci6208_find_device(struct comedi_device *dev, int bus, int slot) { struct pci_dev *pci_dev; int i; @@ -315,11 +312,11 @@ static int pci6208_find_device(struct comedi_device * dev, int bus, int slot) pci_dev != NULL; pci_dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev)) { if (pci_dev->vendor == PCI_VENDOR_ID_ADLINK) { - for (i = 0; i < pci6208_board_nbr; i++) { + for (i = 0; i < ARRAY_SIZE(pci6208_boards); i++) { if (pci6208_boards[i].dev_id == pci_dev->device) { - // was a particular bus/slot requested? + /* was a particular bus/slot requested? */ if ((bus != 0) || (slot != 0)) { - // are we on the wrong bus/slot? + /* are we on the wrong bus/slot? */ if (pci_dev->bus->number != bus || PCI_SLOT(pci_dev->devfn) @@ -346,10 +343,10 @@ static int pci6208_find_device(struct comedi_device * dev, int bus, int slot) PCI_SLOT(pci_dev->devfn), PCI_FUNC(pci_dev->devfn), pci_dev->irq); - // TODO: Warn about non-tested boards. - //switch(board->device_id) - //{ - //}; + /* TODO: Warn about non-tested boards. */ + /* switch(board->device_id) */ + /* { */ + /* }; */ devpriv->pci_dev = pci_dev; @@ -362,19 +359,19 @@ pci6208_pci_setup(struct pci_dev *pci_dev, unsigned long *io_base_ptr, { unsigned long io_base, io_range, lcr_io_base, lcr_io_range; - // Enable PCI device and request regions + /* Enable PCI device and request regions */ if (comedi_pci_enable(pci_dev, PCI6208_DRIVER_NAME) < 0) { printk("comedi%d: Failed to enable PCI device and request regions\n", dev_minor); return -EIO; } - // Read local configuration register base address [PCI_BASE_ADDRESS #1]. + /* Read local configuration register base address [PCI_BASE_ADDRESS #1]. */ lcr_io_base = pci_resource_start(pci_dev, 1); lcr_io_range = pci_resource_len(pci_dev, 1); printk("comedi%d: local config registers at address 0x%4lx [0x%4lx]\n", dev_minor, lcr_io_base, lcr_io_range); - // Read PCI6208 register base address [PCI_BASE_ADDRESS #2]. + /* Read PCI6208 register base address [PCI_BASE_ADDRESS #2]. */ io_base = pci_resource_start(pci_dev, 2); io_range = pci_resource_end(pci_dev, 2) - io_base + 1; @@ -382,10 +379,10 @@ pci6208_pci_setup(struct pci_dev *pci_dev, unsigned long *io_base_ptr, dev_minor, io_base, io_range); *io_base_ptr = io_base; - //devpriv->io_range = io_range; - //devpriv->is_valid=0; - //devpriv->lcr_io_base=lcr_io_base; - //devpriv->lcr_io_range=lcr_io_range; + /* devpriv->io_range = io_range; */ + /* devpriv->is_valid=0; */ + /* devpriv->lcr_io_base=lcr_io_base; */ + /* devpriv->lcr_io_range=lcr_io_range; */ return 0; } diff --git a/drivers/staging/comedi/drivers/adl_pci7296.c b/drivers/staging/comedi/drivers/adl_pci7296.c index bd0f9ab226ef..d2f23a88608d 100644 --- a/drivers/staging/comedi/drivers/adl_pci7296.c +++ b/drivers/staging/comedi/drivers/adl_pci7296.c @@ -39,7 +39,7 @@ Configuration Options: #include "comedi_pci.h" #include "8255.h" -// #include "8253.h" +/* #include "8253.h" */ #define PORT1A 0 #define PORT2A 4 @@ -64,16 +64,16 @@ struct adl_pci7296_private { #define devpriv ((struct adl_pci7296_private *)dev->private) -static int adl_pci7296_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int adl_pci7296_detach(struct comedi_device * dev); +static int adl_pci7296_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int adl_pci7296_detach(struct comedi_device *dev); static struct comedi_driver driver_adl_pci7296 = { - driver_name:"adl_pci7296", - module:THIS_MODULE, - attach:adl_pci7296_attach, - detach:adl_pci7296_detach, + .driver_name = "adl_pci7296", + .module = THIS_MODULE, + .attach = adl_pci7296_attach, + .detach = adl_pci7296_detach, }; -static int adl_pci7296_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int adl_pci7296_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct pci_dev *pcidev; struct comedi_subdevice *s; @@ -115,7 +115,7 @@ static int adl_pci7296_attach(struct comedi_device * dev, struct comedi_devconfi dev->iobase = pci_resource_start(pcidev, 2); printk("comedi: base addr %4lx\n", dev->iobase); - // four 8255 digital io subdevices + /* four 8255 digital io subdevices */ s = dev->subdevices + 0; subdev_8255_init(dev, s, NULL, (unsigned long)(dev->iobase)); @@ -149,7 +149,7 @@ static int adl_pci7296_attach(struct comedi_device * dev, struct comedi_devconfi return -EIO; } -static int adl_pci7296_detach(struct comedi_device * dev) +static int adl_pci7296_detach(struct comedi_device *dev) { printk("comedi%d: pci7432: remove\n", dev->minor); @@ -159,7 +159,7 @@ static int adl_pci7296_detach(struct comedi_device * dev) } pci_dev_put(devpriv->pci_dev); } - // detach four 8255 digital io subdevices + /* detach four 8255 digital io subdevices */ if (dev->subdevices) { subdev_8255_cleanup(dev, dev->subdevices + 0); subdev_8255_cleanup(dev, dev->subdevices + 1); diff --git a/drivers/staging/comedi/drivers/adl_pci7432.c b/drivers/staging/comedi/drivers/adl_pci7432.c index a8f1715608d1..78becbdd17a8 100644 --- a/drivers/staging/comedi/drivers/adl_pci7432.c +++ b/drivers/staging/comedi/drivers/adl_pci7432.c @@ -58,26 +58,26 @@ struct adl_pci7432_private { #define devpriv ((struct adl_pci7432_private *)dev->private) -static int adl_pci7432_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int adl_pci7432_detach(struct comedi_device * dev); +static int adl_pci7432_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int adl_pci7432_detach(struct comedi_device *dev); static struct comedi_driver driver_adl_pci7432 = { - driver_name:"adl_pci7432", - module:THIS_MODULE, - attach:adl_pci7432_attach, - detach:adl_pci7432_detach, + .driver_name = "adl_pci7432", + .module = THIS_MODULE, + .attach = adl_pci7432_attach, + .detach = adl_pci7432_detach, }; /* Digital IO */ -static int adl_pci7432_di_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); +static int adl_pci7432_di_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); -static int adl_pci7432_do_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); +static int adl_pci7432_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); /* */ -static int adl_pci7432_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int adl_pci7432_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct pci_dev *pcidev; struct comedi_subdevice *s; @@ -150,7 +150,7 @@ static int adl_pci7432_attach(struct comedi_device * dev, struct comedi_devconfi return -EIO; } -static int adl_pci7432_detach(struct comedi_device * dev) +static int adl_pci7432_detach(struct comedi_device *dev) { printk("comedi%d: pci7432: remove\n", dev->minor); @@ -164,8 +164,8 @@ static int adl_pci7432_detach(struct comedi_device * dev) return 0; } -static int adl_pci7432_do_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int adl_pci7432_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { printk("comedi: pci7432_do_insn_bits called\n"); printk("comedi: data0: %8x data1: %8x\n", data[0], data[1]); @@ -184,8 +184,8 @@ static int adl_pci7432_do_insn_bits(struct comedi_device * dev, struct comedi_su return 2; } -static int adl_pci7432_di_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int adl_pci7432_di_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { printk("comedi: pci7432_di_insn_bits called\n"); printk("comedi: data0: %8x data1: %8x\n", data[0], data[1]); diff --git a/drivers/staging/comedi/drivers/adl_pci8164.c b/drivers/staging/comedi/drivers/adl_pci8164.c index adf90be79983..2d7d68af6b1e 100644 --- a/drivers/staging/comedi/drivers/adl_pci8164.c +++ b/drivers/staging/comedi/drivers/adl_pci8164.c @@ -70,40 +70,40 @@ struct adl_pci8164_private { #define devpriv ((struct adl_pci8164_private *)dev->private) -static int adl_pci8164_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int adl_pci8164_detach(struct comedi_device * dev); +static int adl_pci8164_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int adl_pci8164_detach(struct comedi_device *dev); static struct comedi_driver driver_adl_pci8164 = { - driver_name:"adl_pci8164", - module:THIS_MODULE, - attach:adl_pci8164_attach, - detach:adl_pci8164_detach, + .driver_name = "adl_pci8164", + .module = THIS_MODULE, + .attach = adl_pci8164_attach, + .detach = adl_pci8164_detach, }; -static int adl_pci8164_insn_read_msts(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); +static int adl_pci8164_insn_read_msts(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); -static int adl_pci8164_insn_read_ssts(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); +static int adl_pci8164_insn_read_ssts(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); -static int adl_pci8164_insn_read_buf0(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); +static int adl_pci8164_insn_read_buf0(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); -static int adl_pci8164_insn_read_buf1(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); +static int adl_pci8164_insn_read_buf1(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); -static int adl_pci8164_insn_write_cmd(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); +static int adl_pci8164_insn_write_cmd(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); -static int adl_pci8164_insn_write_otp(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); +static int adl_pci8164_insn_write_otp(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); -static int adl_pci8164_insn_write_buf0(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data); +static int adl_pci8164_insn_write_buf0(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -static int adl_pci8164_insn_write_buf1(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data); +static int adl_pci8164_insn_write_buf1(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -static int adl_pci8164_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int adl_pci8164_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct pci_dev *pcidev; struct comedi_subdevice *s; @@ -149,7 +149,7 @@ static int adl_pci8164_attach(struct comedi_device * dev, struct comedi_devconfi s->n_chan = 4; s->maxdata = 0xffff; s->len_chanlist = 4; - //s->range_table = &range_axis; + /* s->range_table = &range_axis; */ s->insn_read = adl_pci8164_insn_read_msts; s->insn_write = adl_pci8164_insn_write_cmd; @@ -159,7 +159,7 @@ static int adl_pci8164_attach(struct comedi_device * dev, struct comedi_devconfi s->n_chan = 4; s->maxdata = 0xffff; s->len_chanlist = 4; - //s->range_table = &range_axis; + /* s->range_table = &range_axis; */ s->insn_read = adl_pci8164_insn_read_ssts; s->insn_write = adl_pci8164_insn_write_otp; @@ -169,7 +169,7 @@ static int adl_pci8164_attach(struct comedi_device * dev, struct comedi_devconfi s->n_chan = 4; s->maxdata = 0xffff; s->len_chanlist = 4; - //s->range_table = &range_axis; + /* s->range_table = &range_axis; */ s->insn_read = adl_pci8164_insn_read_buf0; s->insn_write = adl_pci8164_insn_write_buf0; @@ -179,7 +179,7 @@ static int adl_pci8164_attach(struct comedi_device * dev, struct comedi_devconfi s->n_chan = 4; s->maxdata = 0xffff; s->len_chanlist = 4; - //s->range_table = &range_axis; + /* s->range_table = &range_axis; */ s->insn_read = adl_pci8164_insn_read_buf1; s->insn_write = adl_pci8164_insn_write_buf1; @@ -194,7 +194,7 @@ static int adl_pci8164_attach(struct comedi_device * dev, struct comedi_devconfi return -EIO; } -static int adl_pci8164_detach(struct comedi_device * dev) +static int adl_pci8164_detach(struct comedi_device *dev) { printk("comedi%d: pci8164: remove\n", dev->minor); @@ -208,8 +208,16 @@ static int adl_pci8164_detach(struct comedi_device * dev) return 0; } -static int adl_pci8164_insn_read_msts(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +/* + all the read commands are the same except for the addition a constant + * const to the data for inw() + */ +static void adl_pci8164_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data, + char *action, + unsigned short offset) { int axis, axis_reg; char *axisname; @@ -238,127 +246,51 @@ static int adl_pci8164_insn_read_msts(struct comedi_device * dev, struct comedi_ axisname = "X"; } - data[0] = inw(dev->iobase + axis_reg + PCI8164_MSTS); - printk("comedi: pci8164 MSTS read -> %04X:%04X on axis %s\n", data[0], + data[0] = inw(dev->iobase + axis_reg + offset); + printk("comedi: pci8164 %s read -> %04X:%04X on axis %s\n", action, data[0], data[1], axisname); - - return 2; } -static int adl_pci8164_insn_read_ssts(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int adl_pci8164_insn_read_msts(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - int axis, axis_reg; - char *axisname; - - axis = CR_CHAN(insn->chanspec); - - switch (axis) { - case 0: - axis_reg = PCI8164_AXIS_X; - axisname = "X"; - break; - case 1: - axis_reg = PCI8164_AXIS_Y; - axisname = "Y"; - break; - case 2: - axis_reg = PCI8164_AXIS_Z; - axisname = "Z"; - break; - case 3: - axis_reg = PCI8164_AXIS_U; - axisname = "U"; - break; - default: - axis_reg = PCI8164_AXIS_X; - axisname = "X"; - } - - data[0] = inw(dev->iobase + axis_reg + PCI8164_SSTS); - printk("comedi: pci8164 SSTS read -> %04X:%04X on axis %s\n", data[0], - data[1], axisname); - + adl_pci8164_insn_read(dev, s, insn, data, "MSTS", PCI8164_MSTS); return 2; } -static int adl_pci8164_insn_read_buf0(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int adl_pci8164_insn_read_ssts(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - int axis, axis_reg; - char *axisname; - - axis = CR_CHAN(insn->chanspec); - - switch (axis) { - case 0: - axis_reg = PCI8164_AXIS_X; - axisname = "X"; - break; - case 1: - axis_reg = PCI8164_AXIS_Y; - axisname = "Y"; - break; - case 2: - axis_reg = PCI8164_AXIS_Z; - axisname = "Z"; - break; - case 3: - axis_reg = PCI8164_AXIS_U; - axisname = "U"; - break; - default: - axis_reg = PCI8164_AXIS_X; - axisname = "X"; - } - - data[0] = inw(dev->iobase + axis_reg + PCI8164_BUF0); - printk("comedi: pci8164 BUF0 read -> %04X:%04X on axis %s\n", data[0], - data[1], axisname); - + adl_pci8164_insn_read(dev, s, insn, data, "SSTS", PCI8164_SSTS); return 2; } -static int adl_pci8164_insn_read_buf1(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int adl_pci8164_insn_read_buf0(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - int axis, axis_reg; - - char *axisname; - - axis = CR_CHAN(insn->chanspec); - - switch (axis) { - case 0: - axis_reg = PCI8164_AXIS_X; - axisname = "X"; - break; - case 1: - axis_reg = PCI8164_AXIS_Y; - axisname = "Y"; - break; - case 2: - axis_reg = PCI8164_AXIS_Z; - axisname = "Z"; - break; - case 3: - axis_reg = PCI8164_AXIS_U; - axisname = "U"; - break; - default: - axis_reg = PCI8164_AXIS_X; - axisname = "X"; - } - - data[0] = inw(dev->iobase + axis_reg + PCI8164_BUF1); - printk("comedi: pci8164 BUF1 read -> %04X:%04X on axis %s\n", data[0], - data[1], axisname); - + adl_pci8164_insn_read(dev, s, insn, data, "BUF0", PCI8164_BUF0); return 2; } -static int adl_pci8164_insn_write_cmd(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int adl_pci8164_insn_read_buf1(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + adl_pci8164_insn_read(dev, s, insn, data, "BUF1", PCI8164_BUF1); + return 2; +} + +/* + all the write commands are the same except for the addition a constant + * const to the data for outw() + */ +static void adl_pci8164_insn_out(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data, + char *action, + unsigned short offset) { unsigned int axis, axis_reg; @@ -388,124 +320,39 @@ static int adl_pci8164_insn_write_cmd(struct comedi_device * dev, struct comedi_ axisname = "X"; } - outw(data[0], dev->iobase + axis_reg + PCI8164_CMD); - printk("comedi: pci8164 CMD write -> %04X:%04X on axis %s\n", data[0], - data[1], axisname); + outw(data[0], dev->iobase + axis_reg + offset); + printk("comedi: pci8164 %s write -> %04X:%04X on axis %s\n", action, + data[0], data[1], axisname); + +} + + +static int adl_pci8164_insn_write_cmd(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + adl_pci8164_insn_out(dev, s, insn, data, "CMD", PCI8164_CMD); return 2; } -static int adl_pci8164_insn_write_otp(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int adl_pci8164_insn_write_otp(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - int axis, axis_reg; - - char *axisname; - - axis = CR_CHAN(insn->chanspec); - - switch (axis) { - case 0: - axis_reg = PCI8164_AXIS_X; - axisname = "X"; - break; - case 1: - axis_reg = PCI8164_AXIS_Y; - axisname = "Y"; - break; - case 2: - axis_reg = PCI8164_AXIS_Z; - axisname = "Z"; - break; - case 3: - axis_reg = PCI8164_AXIS_U; - axisname = "U"; - break; - default: - axis_reg = PCI8164_AXIS_X; - axisname = "X"; - } - - outw(data[0], dev->iobase + axis_reg + PCI8164_OTP); - printk("comedi: pci8164 OTP write -> %04X:%04X on axis %s\n", data[0], - data[1], axisname); - + adl_pci8164_insn_out(dev, s, insn, data, "OTP", PCI8164_OTP); return 2; } -static int adl_pci8164_insn_write_buf0(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +static int adl_pci8164_insn_write_buf0(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - int axis, axis_reg; - - char *axisname; - - axis = CR_CHAN(insn->chanspec); - - switch (axis) { - case 0: - axis_reg = PCI8164_AXIS_X; - axisname = "X"; - break; - case 1: - axis_reg = PCI8164_AXIS_Y; - axisname = "Y"; - break; - case 2: - axis_reg = PCI8164_AXIS_Z; - axisname = "Z"; - break; - case 3: - axis_reg = PCI8164_AXIS_U; - axisname = "U"; - break; - default: - axis_reg = PCI8164_AXIS_X; - axisname = "X"; - } - - outw(data[0], dev->iobase + axis_reg + PCI8164_BUF0); - printk("comedi: pci8164 BUF0 write -> %04X:%04X on axis %s\n", data[0], - data[1], axisname); - + adl_pci8164_insn_out(dev, s, insn, data, "BUF0", PCI8164_BUF0); return 2; } -static int adl_pci8164_insn_write_buf1(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +static int adl_pci8164_insn_write_buf1(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - int axis, axis_reg; - - char *axisname; - - axis = CR_CHAN(insn->chanspec); - - switch (axis) { - case 0: - axis_reg = PCI8164_AXIS_X; - axisname = "X"; - break; - case 1: - axis_reg = PCI8164_AXIS_Y; - axisname = "Y"; - break; - case 2: - axis_reg = PCI8164_AXIS_Z; - axisname = "Z"; - break; - case 3: - axis_reg = PCI8164_AXIS_U; - axisname = "U"; - break; - default: - axis_reg = PCI8164_AXIS_X; - axisname = "X"; - } - - outw(data[0], dev->iobase + axis_reg + PCI8164_BUF1); - printk("comedi: pci8164 BUF1 write -> %04X:%04X on axis %s\n", data[0], - data[1], axisname); - + adl_pci8164_insn_out(dev, s, insn, data, "BUF1", PCI8164_BUF1); return 2; } diff --git a/drivers/staging/comedi/drivers/adl_pci9111.c b/drivers/staging/comedi/drivers/adl_pci9111.c index b4a61c560c5b..0ac722e6f37a 100644 --- a/drivers/staging/comedi/drivers/adl_pci9111.c +++ b/drivers/staging/comedi/drivers/adl_pci9111.c @@ -77,6 +77,7 @@ TODO: #include "../comedidev.h" #include +#include #include "8253.h" #include "comedi_pci.h" @@ -186,24 +187,24 @@ TODO: (inb(PCI9111_IO_BASE+PCI9111_REGISTER_AD_MODE_INTERRUPT_READBACK)&0x0F) #define pci9111_trigger_and_autoscan_set(flags) \ - outb(flags,PCI9111_IO_BASE+PCI9111_REGISTER_TRIGGER_MODE_CONTROL) + outb(flags, PCI9111_IO_BASE+PCI9111_REGISTER_TRIGGER_MODE_CONTROL) #define pci9111_interrupt_and_fifo_get() \ ((inb(PCI9111_IO_BASE+PCI9111_REGISTER_AD_MODE_INTERRUPT_READBACK) >> 4) &0x03) #define pci9111_interrupt_and_fifo_set(flags) \ - outb(flags,PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CONTROL) + outb(flags, PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CONTROL) #define pci9111_interrupt_clear() \ - outb(0,PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CLEAR) + outb(0, PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CLEAR) #define pci9111_software_trigger() \ - outb(0,PCI9111_IO_BASE+PCI9111_REGISTER_SOFTWARE_TRIGGER) + outb(0, PCI9111_IO_BASE+PCI9111_REGISTER_SOFTWARE_TRIGGER) #define pci9111_fifo_reset() \ - outb(PCI9111_FFEN_SET_FIFO_ENABLE,PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CONTROL); \ - outb(PCI9111_FFEN_SET_FIFO_DISABLE,PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CONTROL); \ - outb(PCI9111_FFEN_SET_FIFO_ENABLE,PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CONTROL) + outb(PCI9111_FFEN_SET_FIFO_ENABLE, PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CONTROL); \ + outb(PCI9111_FFEN_SET_FIFO_DISABLE, PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CONTROL); \ + outb(PCI9111_FFEN_SET_FIFO_ENABLE, PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CONTROL) #define pci9111_is_fifo_full() \ ((inb(PCI9111_IO_BASE+PCI9111_REGISTER_RANGE_STATUS_READBACK)& \ @@ -218,13 +219,13 @@ TODO: PCI9111_FIFO_EMPTY_MASK)==0) #define pci9111_ai_channel_set(channel) \ - outb((channel)&PCI9111_CHANNEL_MASK,PCI9111_IO_BASE+PCI9111_REGISTER_AD_CHANNEL_CONTROL) + outb((channel)&PCI9111_CHANNEL_MASK, PCI9111_IO_BASE+PCI9111_REGISTER_AD_CHANNEL_CONTROL) #define pci9111_ai_channel_get() \ inb(PCI9111_IO_BASE+PCI9111_REGISTER_AD_CHANNEL_READBACK)&PCI9111_CHANNEL_MASK #define pci9111_ai_range_set(range) \ - outb((range)&PCI9111_RANGE_MASK,PCI9111_IO_BASE+PCI9111_REGISTER_INPUT_SIGNAL_RANGE) + outb((range)&PCI9111_RANGE_MASK, PCI9111_IO_BASE+PCI9111_REGISTER_INPUT_SIGNAL_RANGE) #define pci9111_ai_range_get() \ inb(PCI9111_IO_BASE+PCI9111_REGISTER_RANGE_STATUS_READBACK)&PCI9111_RANGE_MASK @@ -238,34 +239,34 @@ TODO: ^ PCI9111_HR_AI_RESOLUTION_2_CMP_BIT #define pci9111_ao_set_data(data) \ - outw(data&PCI9111_AO_RESOLUTION_MASK,PCI9111_IO_BASE+PCI9111_REGISTER_DA_OUTPUT) + outw(data&PCI9111_AO_RESOLUTION_MASK, PCI9111_IO_BASE+PCI9111_REGISTER_DA_OUTPUT) #define pci9111_di_get_bits() \ inw(PCI9111_IO_BASE+PCI9111_REGISTER_DIGITAL_IO) #define pci9111_do_set_bits(bits) \ - outw(bits,PCI9111_IO_BASE+PCI9111_REGISTER_DIGITAL_IO) + outw(bits, PCI9111_IO_BASE+PCI9111_REGISTER_DIGITAL_IO) #define pci9111_8254_control_set(flags) \ - outb(flags,PCI9111_IO_BASE+PCI9111_REGISTER_8254_CONTROL) + outb(flags, PCI9111_IO_BASE+PCI9111_REGISTER_8254_CONTROL) #define pci9111_8254_counter_0_set(data) \ outb(data & 0xFF, PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_0); \ - outb( (data >> 8) & 0xFF, PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_0) + outb((data >> 8) & 0xFF, PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_0) #define pci9111_8254_counter_1_set(data) \ outb(data & 0xFF, PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_1); \ - outb( (data >> 8) & 0xFF, PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_1) + outb((data >> 8) & 0xFF, PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_1) #define pci9111_8254_counter_2_set(data) \ outb(data & 0xFF, PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_2); \ - outb( (data >> 8) & 0xFF, PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_2) + outb((data >> 8) & 0xFF, PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_2) /* Function prototypes */ -static int pci9111_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int pci9111_detach(struct comedi_device * dev); -static void pci9111_ai_munge(struct comedi_device * dev, struct comedi_subdevice * s, +static int pci9111_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int pci9111_detach(struct comedi_device *dev); +static void pci9111_ai_munge(struct comedi_device *dev, struct comedi_subdevice *s, void *data, unsigned int num_bytes, unsigned int start_chan_index); static const struct comedi_lrange pci9111_hr_ai_range = { @@ -308,27 +309,27 @@ struct pci9111_board { static const struct pci9111_board pci9111_boards[] = { { - name: "pci9111_hr", - device_id:PCI9111_HR_DEVICE_ID, - ai_channel_nbr:PCI9111_AI_CHANNEL_NBR, - ao_channel_nbr:PCI9111_AO_CHANNEL_NBR, - ai_resolution:PCI9111_HR_AI_RESOLUTION, - ai_resolution_mask:PCI9111_HR_AI_RESOLUTION_MASK, - ao_resolution:PCI9111_AO_RESOLUTION, - ao_resolution_mask:PCI9111_AO_RESOLUTION_MASK, - ai_range_list:&pci9111_hr_ai_range, - ao_range_list:&range_bipolar10, - ai_acquisition_period_min_ns:PCI9111_AI_ACQUISITION_PERIOD_MIN_NS} + .name = "pci9111_hr", + .device_id = PCI9111_HR_DEVICE_ID, + .ai_channel_nbr = PCI9111_AI_CHANNEL_NBR, + .ao_channel_nbr = PCI9111_AO_CHANNEL_NBR, + .ai_resolution = PCI9111_HR_AI_RESOLUTION, + .ai_resolution_mask = PCI9111_HR_AI_RESOLUTION_MASK, + .ao_resolution = PCI9111_AO_RESOLUTION, + .ao_resolution_mask = PCI9111_AO_RESOLUTION_MASK, + .ai_range_list = &pci9111_hr_ai_range, + .ao_range_list = &range_bipolar10, + .ai_acquisition_period_min_ns = PCI9111_AI_ACQUISITION_PERIOD_MIN_NS} }; #define pci9111_board_nbr \ (sizeof(pci9111_boards)/sizeof(struct pci9111_board)) static struct comedi_driver pci9111_driver = { - driver_name:PCI9111_DRIVER_NAME, - module:THIS_MODULE, - attach:pci9111_attach, - detach:pci9111_detach, + .driver_name = PCI9111_DRIVER_NAME, + .module = THIS_MODULE, + .attach = pci9111_attach, + .detach = pci9111_detach, }; COMEDI_PCI_INITCLEANUP(pci9111_driver, pci9111_pci_table); @@ -405,7 +406,7 @@ static void plx9050_interrupt_control(unsigned long io_base, /* 8254 timer */ -static void pci9111_timer_set(struct comedi_device * dev) +static void pci9111_timer_set(struct comedi_device *dev) { pci9111_8254_control_set(PCI9111_8254_COUNTER_0 | PCI9111_8254_READ_LOAD_LSB_MSB | @@ -419,7 +420,7 @@ static void pci9111_timer_set(struct comedi_device * dev) PCI9111_8254_READ_LOAD_LSB_MSB | PCI9111_8254_MODE_2 | PCI9111_8254_BINARY_COUNTER); - comedi_udelay(1); + udelay(1); pci9111_8254_counter_2_set(dev_private->timer_divisor_2); pci9111_8254_counter_1_set(dev_private->timer_divisor_1); @@ -431,7 +432,7 @@ enum pci9111_trigger_sources { external }; -static void pci9111_trigger_source_set(struct comedi_device * dev, +static void pci9111_trigger_source_set(struct comedi_device *dev, enum pci9111_trigger_sources source) { int flags; @@ -455,7 +456,7 @@ static void pci9111_trigger_source_set(struct comedi_device * dev, pci9111_trigger_and_autoscan_set(flags); } -static void pci9111_pretrigger_set(struct comedi_device * dev, bool pretrigger) +static void pci9111_pretrigger_set(struct comedi_device *dev, bool pretrigger) { int flags; @@ -467,7 +468,7 @@ static void pci9111_pretrigger_set(struct comedi_device * dev, bool pretrigger) pci9111_trigger_and_autoscan_set(flags); } -static void pci9111_autoscan_set(struct comedi_device * dev, bool autoscan) +static void pci9111_autoscan_set(struct comedi_device *dev, bool autoscan) { int flags; @@ -489,7 +490,7 @@ enum pci9111_ISC1_sources { irq_on_external_trigger }; -static void pci9111_interrupt_source_set(struct comedi_device * dev, +static void pci9111_interrupt_source_set(struct comedi_device *dev, enum pci9111_ISC0_sources irq_0_source, enum pci9111_ISC1_sources irq_1_source) { int flags; @@ -513,7 +514,7 @@ static void pci9111_interrupt_source_set(struct comedi_device * dev, #undef AI_DO_CMD_DEBUG -static int pci9111_ai_cancel(struct comedi_device * dev, struct comedi_subdevice * s) +static int pci9111_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { /* Disable interrupts */ @@ -535,14 +536,14 @@ static int pci9111_ai_cancel(struct comedi_device * dev, struct comedi_subdevice /* Test analog input command */ -#define pci9111_check_trigger_src(src,flags) \ +#define pci9111_check_trigger_src(src, flags) \ tmp = src; \ src &= flags; \ if (!src || tmp != src) error++ static int -pci9111_ai_do_cmd_test(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_cmd * cmd) +pci9111_ai_do_cmd_test(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_cmd *cmd) { int tmp; int error = 0; @@ -740,7 +741,7 @@ pci9111_ai_do_cmd_test(struct comedi_device * dev, /* Analog input command */ -static int pci9111_ai_do_cmd(struct comedi_device * dev, struct comedi_subdevice * subdevice) +static int pci9111_ai_do_cmd(struct comedi_device *dev, struct comedi_subdevice *subdevice) { struct comedi_cmd *async_cmd = &subdevice->async->cmd; @@ -858,7 +859,7 @@ static int pci9111_ai_do_cmd(struct comedi_device * dev, struct comedi_subdevice return 0; } -static void pci9111_ai_munge(struct comedi_device * dev, struct comedi_subdevice * s, +static void pci9111_ai_munge(struct comedi_device *dev, struct comedi_subdevice *s, void *data, unsigned int num_bytes, unsigned int start_chan_index) { unsigned int i, num_samples = num_bytes / sizeof(short); @@ -884,7 +885,7 @@ static void pci9111_ai_munge(struct comedi_device * dev, struct comedi_subdevice #undef INTERRUPT_DEBUG -static irqreturn_t pci9111_interrupt(int irq, void *p_device PT_REGS_ARG) +static irqreturn_t pci9111_interrupt(int irq, void *p_device) { struct comedi_device *dev = p_device; struct comedi_subdevice *subdevice = dev->read_subdev; @@ -900,7 +901,7 @@ static irqreturn_t pci9111_interrupt(int irq, void *p_device PT_REGS_ARG) async = subdevice->async; - comedi_spin_lock_irqsave(&dev->spinlock, irq_flags); + spin_lock_irqsave(&dev->spinlock, irq_flags); /* Check if we are source of interrupt */ intcsr = inb(dev_private->lcr_io_base + @@ -918,7 +919,7 @@ static irqreturn_t pci9111_interrupt(int irq, void *p_device PT_REGS_ARG) PLX9050_LINTI2_STATUS))))) { /* Not the source of the interrupt. */ /* (N.B. not using PLX9050_SOFTWARE_INTERRUPT) */ - comedi_spin_unlock_irqrestore(&dev->spinlock, irq_flags); + spin_unlock_irqrestore(&dev->spinlock, irq_flags); return IRQ_NONE; } @@ -927,7 +928,7 @@ static irqreturn_t pci9111_interrupt(int irq, void *p_device PT_REGS_ARG) /* Interrupt comes from fifo_half-full signal */ if (pci9111_is_fifo_full()) { - comedi_spin_unlock_irqrestore(&dev->spinlock, + spin_unlock_irqrestore(&dev->spinlock, irq_flags); comedi_error(dev, PCI9111_DRIVER_NAME " fifo overflow"); pci9111_interrupt_clear(); @@ -1027,7 +1028,7 @@ static irqreturn_t pci9111_interrupt(int irq, void *p_device PT_REGS_ARG) pci9111_interrupt_clear(); - comedi_spin_unlock_irqrestore(&dev->spinlock, irq_flags); + spin_unlock_irqrestore(&dev->spinlock, irq_flags); comedi_event(dev, subdevice); @@ -1042,8 +1043,8 @@ static irqreturn_t pci9111_interrupt(int irq, void *p_device PT_REGS_ARG) #undef AI_INSN_DEBUG -static int pci9111_ai_insn_read(struct comedi_device * dev, - struct comedi_subdevice * subdevice, struct comedi_insn * insn, unsigned int * data) +static int pci9111_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *subdevice, struct comedi_insn *insn, unsigned int *data) { int resolution = ((struct pci9111_board *) dev->board_ptr)->ai_resolution; @@ -1100,8 +1101,8 @@ static int pci9111_ai_insn_read(struct comedi_device * dev, /* Analog instant output */ static int -pci9111_ao_insn_write(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +pci9111_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { int i; @@ -1115,8 +1116,8 @@ pci9111_ao_insn_write(struct comedi_device * dev, /* Analog output readback */ -static int pci9111_ao_insn_read(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +static int pci9111_ao_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { int i; @@ -1133,8 +1134,8 @@ static int pci9111_ao_insn_read(struct comedi_device * dev, /* Digital inputs */ -static int pci9111_di_insn_bits(struct comedi_device * dev, - struct comedi_subdevice * subdevice, struct comedi_insn * insn, unsigned int * data) +static int pci9111_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *subdevice, struct comedi_insn *insn, unsigned int *data) { unsigned int bits; @@ -1146,8 +1147,8 @@ static int pci9111_di_insn_bits(struct comedi_device * dev, /* Digital outputs */ -static int pci9111_do_insn_bits(struct comedi_device * dev, - struct comedi_subdevice * subdevice, struct comedi_insn * insn, unsigned int * data) +static int pci9111_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *subdevice, struct comedi_insn *insn, unsigned int *data) { unsigned int bits; @@ -1175,7 +1176,7 @@ static int pci9111_do_insn_bits(struct comedi_device * dev, /* Reset device */ -static int pci9111_reset(struct comedi_device * dev) +static int pci9111_reset(struct comedi_device *dev) { /* Set trigger source to software */ @@ -1200,7 +1201,7 @@ static int pci9111_reset(struct comedi_device * dev) /* - Register PCI device */ /* - Declare device driver capability */ -static int pci9111_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int pci9111_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *subdevice; unsigned long io_base, io_range, lcr_io_base, lcr_io_range; @@ -1297,8 +1298,7 @@ static int pci9111_attach(struct comedi_device * dev, struct comedi_devconfig * dev->irq = 0; if (pci_device->irq > 0) { - if (comedi_request_irq(pci_device->irq, - pci9111_interrupt, + if (request_irq(pci_device->irq, pci9111_interrupt, IRQF_SHARED, PCI9111_DRIVER_NAME, dev) != 0) { printk("comedi%d: unable to allocate irq %u\n", dev->minor, pci_device->irq); @@ -1309,7 +1309,8 @@ static int pci9111_attach(struct comedi_device * dev, struct comedi_devconfig * /* TODO: Add external multiplexer setup (according to option[2]). */ - if ((error = alloc_subdevices(dev, 4)) < 0) + error = alloc_subdevices(dev, 4); + if (error < 0) return error; subdevice = dev->subdevices + 0; @@ -1365,7 +1366,7 @@ static int pci9111_attach(struct comedi_device * dev, struct comedi_devconfig * /* Detach */ -static int pci9111_detach(struct comedi_device * dev) +static int pci9111_detach(struct comedi_device *dev) { /* Reset device */ @@ -1377,7 +1378,7 @@ static int pci9111_detach(struct comedi_device * dev) /* Release previously allocated irq */ if (dev->irq != 0) { - comedi_free_irq(dev->irq, dev); + free_irq(dev->irq, dev); } if (dev_private != 0 && dev_private->pci_device != 0) { diff --git a/drivers/staging/comedi/drivers/adl_pci9118.c b/drivers/staging/comedi/drivers/adl_pci9118.c index 278cf30cc4a3..65f522be9124 100644 --- a/drivers/staging/comedi/drivers/adl_pci9118.c +++ b/drivers/staging/comedi/drivers/adl_pci9118.c @@ -66,6 +66,7 @@ Configuration options: #include "../pci_ids.h" #include +#include #include "amcc_s5933.h" #include "8253.h" @@ -79,7 +80,7 @@ Configuration options: #undef DPRINTK #ifdef PCI9118_EXTDEBUG -#define DPRINTK(fmt, args...) rt_printk(fmt, ## args) +#define DPRINTK(fmt, args...) printk(fmt, ## args) #else #define DPRINTK(fmt, args...) #endif @@ -107,7 +108,7 @@ Configuration options: #define PCI9118_INTSRC 0x38 /* R: interrupt reason register */ #define PCI9118_INTCTRL 0x38 /* W: interrupt control register */ -// bits from A/D control register (PCI9118_ADCNTRL) +/* bits from A/D control register (PCI9118_ADCNTRL) */ #define AdControl_UniP 0x80 /* 1=bipolar, 0=unipolar */ #define AdControl_Diff 0x40 /* 1=differential, 0= single end inputs */ #define AdControl_SoftG 0x20 /* 1=8254 counter works, 0=counter stops */ @@ -117,7 +118,7 @@ Configuration options: #define AdControl_Int 0x02 /* 1=enable INT, 0=disable */ #define AdControl_Dma 0x01 /* 1=enable DMA, 0=disable */ -// bits from A/D function register (PCI9118_ADFUNC) +/* bits from A/D function register (PCI9118_ADFUNC) */ #define AdFunction_PDTrg 0x80 /* 1=positive, 0=negative digital trigger (only positive is correct) */ #define AdFunction_PETrg 0x40 /* 1=positive, 0=negative external trigger (only positive is correct) */ #define AdFunction_BSSH 0x20 /* 1=with sample&hold, 0=without */ @@ -127,7 +128,7 @@ Configuration options: #define AdFunction_AM 0x02 /* 1=about trigger mode, 0=not about trigger */ #define AdFunction_Start 0x01 /* 1=trigger start, 0=trigger stop */ -// bits from A/D status register (PCI9118_ADSTAT) +/* bits from A/D status register (PCI9118_ADSTAT) */ #define AdStatus_nFull 0x100 /* 0=FIFO full (fatal), 1=not full */ #define AdStatus_nHfull 0x080 /* 0=FIFO half full, 1=FIFO not half full */ #define AdStatus_nEpty 0x040 /* 0=FIFO empty, 1=FIFO not empty */ @@ -138,8 +139,8 @@ Configuration options: #define AdStatus_ADOR 0x002 /* 1=A/D overrun (fatal) */ #define AdStatus_ADrdy 0x001 /* 1=A/D already ready, 0=not ready */ -// bits for interrupt reason and control (PCI9118_INTSRC, PCI9118_INTCTRL) -// 1=interrupt occur, enable source, 0=interrupt not occur, disable source +/* bits for interrupt reason and control (PCI9118_INTSRC, PCI9118_INTCTRL) */ +/* 1=interrupt occur, enable source, 0=interrupt not occur, disable source */ #define Int_Timer 0x08 /* timer interrupt */ #define Int_About 0x04 /* about trigger complete */ #define Int_Hfull 0x02 /* A/D FIFO hlaf full */ @@ -178,27 +179,27 @@ static const struct comedi_lrange range_pci9118hg = { 8, { #define PCI9118_BIPOLAR_RANGES 4 /* used for test on mixture of BIP/UNI ranges */ -static int pci9118_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int pci9118_detach(struct comedi_device * dev); +static int pci9118_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int pci9118_detach(struct comedi_device *dev); struct boardtype { - const char *name; // board name - int vendor_id; // PCI vendor a device ID of card + const char *name; /* board name */ + int vendor_id; /* PCI vendor a device ID of card */ int device_id; - int iorange_amcc; // iorange for own S5933 region - int iorange_9118; // pass thru card region size - int n_aichan; // num of A/D chans - int n_aichand; // num of A/D chans in diff mode - int mux_aichan; // num of A/D chans with external multiplexor - int n_aichanlist; // len of chanlist - int n_aochan; // num of D/A chans - int ai_maxdata; // resolution of A/D - int ao_maxdata; // resolution of D/A - const struct comedi_lrange *rangelist_ai; // rangelist for A/D - const struct comedi_lrange *rangelist_ao; // rangelist for D/A - unsigned int ai_ns_min; // max sample speed of card v ns - unsigned int ai_pacer_min; // minimal pacer value (c1*c2 or c1 in burst) - int half_fifo_size; // size of FIFO/2 + int iorange_amcc; /* iorange for own S5933 region */ + int iorange_9118; /* pass thru card region size */ + int n_aichan; /* num of A/D chans */ + int n_aichand; /* num of A/D chans in diff mode */ + int mux_aichan; /* num of A/D chans with external multiplexor */ + int n_aichanlist; /* len of chanlist */ + int n_aochan; /* num of D/A chans */ + int ai_maxdata; /* resolution of A/D */ + int ao_maxdata; /* resolution of D/A */ + const struct comedi_lrange *rangelist_ai; /* rangelist for A/D */ + const struct comedi_lrange *rangelist_ao; /* rangelist for D/A */ + unsigned int ai_ns_min; /* max sample speed of card v ns */ + unsigned int ai_pacer_min; /* minimal pacer value (c1*c2 or c1 in burst) */ + int half_fifo_size; /* size of FIFO/2 */ }; @@ -230,75 +231,75 @@ static const struct boardtype boardtypes[] = { #define n_boardtypes (sizeof(boardtypes)/sizeof(struct boardtype)) static struct comedi_driver driver_pci9118 = { - driver_name:"adl_pci9118", - module:THIS_MODULE, - attach:pci9118_attach, - detach:pci9118_detach, - num_names:n_boardtypes, - board_name:&boardtypes[0].name, - offset:sizeof(struct boardtype), + .driver_name = "adl_pci9118", + .module = THIS_MODULE, + .attach = pci9118_attach, + .detach = pci9118_detach, + .num_names = n_boardtypes, + .board_name = &boardtypes[0].name, + .offset = sizeof(struct boardtype), }; COMEDI_PCI_INITCLEANUP(driver_pci9118, pci9118_pci_table); struct pci9118_private { - unsigned long iobase_a; // base+size for AMCC chip - unsigned int master; // master capable - struct pci_dev *pcidev; // ptr to actual pcidev - unsigned int usemux; // we want to use external multiplexor! + unsigned long iobase_a; /* base+size for AMCC chip */ + unsigned int master; /* master capable */ + struct pci_dev *pcidev; /* ptr to actual pcidev */ + unsigned int usemux; /* we want to use external multiplexor! */ #ifdef PCI9118_PARANOIDCHECK - unsigned short chanlist[PCI9118_CHANLEN + 1]; // list of scaned channel - unsigned char chanlistlen; // number of scanlist + unsigned short chanlist[PCI9118_CHANLEN + 1]; /* list of scaned channel */ + unsigned char chanlistlen; /* number of scanlist */ #endif - unsigned char AdControlReg; // A/D control register - unsigned char IntControlReg; // Interrupt control register - unsigned char AdFunctionReg; // A/D function register - char valid; // driver is ok - char ai_neverending; // we do unlimited AI - unsigned int i8254_osc_base; // frequence of onboard oscilator - unsigned int ai_do; // what do AI? 0=nothing, 1 to 4 mode - unsigned int ai_act_scan; // how many scans we finished - unsigned int ai_buf_ptr; // data buffer ptr in samples - unsigned int ai_n_chan; // how many channels is measured - unsigned int ai_n_scanlen; // len of actual scanlist - unsigned int ai_n_realscanlen; // what we must transfer for one outgoing scan include front/back adds - unsigned int ai_act_dmapos; // position in actual real stream - unsigned int ai_add_front; // how many channels we must add before scan to satisfy S&H? - unsigned int ai_add_back; // how many channels we must add before scan to satisfy DMA? - unsigned int *ai_chanlist; // actaul chanlist + unsigned char AdControlReg; /* A/D control register */ + unsigned char IntControlReg; /* Interrupt control register */ + unsigned char AdFunctionReg; /* A/D function register */ + char valid; /* driver is ok */ + char ai_neverending; /* we do unlimited AI */ + unsigned int i8254_osc_base; /* frequence of onboard oscilator */ + unsigned int ai_do; /* what do AI? 0=nothing, 1 to 4 mode */ + unsigned int ai_act_scan; /* how many scans we finished */ + unsigned int ai_buf_ptr; /* data buffer ptr in samples */ + unsigned int ai_n_chan; /* how many channels is measured */ + unsigned int ai_n_scanlen; /* len of actual scanlist */ + unsigned int ai_n_realscanlen; /* what we must transfer for one outgoing scan include front/back adds */ + unsigned int ai_act_dmapos; /* position in actual real stream */ + unsigned int ai_add_front; /* how many channels we must add before scan to satisfy S&H? */ + unsigned int ai_add_back; /* how many channels we must add before scan to satisfy DMA? */ + unsigned int *ai_chanlist; /* actaul chanlist */ unsigned int ai_timer1; unsigned int ai_timer2; unsigned int ai_flags; - char ai12_startstop; // measure can start/stop on external trigger - unsigned int ai_divisor1, ai_divisor2; // divisors for start of measure on external start + char ai12_startstop; /* measure can start/stop on external trigger */ + unsigned int ai_divisor1, ai_divisor2; /* divisors for start of measure on external start */ unsigned int ai_data_len; short *ai_data; - short ao_data[2]; // data output buffer - unsigned int ai_scans; // number of scans to do - char dma_doublebuf; // we can use double buffring - unsigned int dma_actbuf; // which buffer is used now - short *dmabuf_virt[2]; // pointers to begin of DMA buffer - unsigned long dmabuf_hw[2]; // hw address of DMA buff - unsigned int dmabuf_size[2]; // size of dma buffer in bytes - unsigned int dmabuf_use_size[2]; // which size we may now used for transfer - unsigned int dmabuf_used_size[2]; // which size was trully used + short ao_data[2]; /* data output buffer */ + unsigned int ai_scans; /* number of scans to do */ + char dma_doublebuf; /* we can use double buffring */ + unsigned int dma_actbuf; /* which buffer is used now */ + short *dmabuf_virt[2]; /* pointers to begin of DMA buffer */ + unsigned long dmabuf_hw[2]; /* hw address of DMA buff */ + unsigned int dmabuf_size[2]; /* size of dma buffer in bytes */ + unsigned int dmabuf_use_size[2]; /* which size we may now used for transfer */ + unsigned int dmabuf_used_size[2]; /* which size was trully used */ unsigned int dmabuf_panic_size[2]; - unsigned int dmabuf_samples[2]; // size in samples - int dmabuf_pages[2]; // number of pages in buffer - unsigned char cnt0_users; // bit field of 8254 CNT0 users (0-unused, 1-AO, 2-DI, 3-DO) - unsigned char exttrg_users; // bit field of external trigger users (0-AI, 1-AO, 2-DI, 3-DO) - unsigned int cnt0_divisor; // actual CNT0 divisor - void (*int_ai_func) (struct comedi_device *, struct comedi_subdevice *, unsigned short, unsigned int, unsigned short); // ptr to actual interrupt AI function - unsigned char ai16bits; // =1 16 bit card - unsigned char usedma; // =1 use DMA transfer and not INT - unsigned char useeoshandle; // =1 change WAKE_EOS DMA transfer to fit on every second - unsigned char usessh; // =1 turn on S&H support - int softsshdelay; // >0 use software S&H, numer is requested delay in ns - unsigned char softsshsample; // polarity of S&H signal in sample state - unsigned char softsshhold; // polarity of S&H signal in hold state - unsigned int ai_maskerr; // which warning was printed - unsigned int ai_maskharderr; // on which error bits stops - unsigned int ai_inttrig_start; // TRIG_INT for start + unsigned int dmabuf_samples[2]; /* size in samples */ + int dmabuf_pages[2]; /* number of pages in buffer */ + unsigned char cnt0_users; /* bit field of 8254 CNT0 users (0-unused, 1-AO, 2-DI, 3-DO) */ + unsigned char exttrg_users; /* bit field of external trigger users (0-AI, 1-AO, 2-DI, 3-DO) */ + unsigned int cnt0_divisor; /* actual CNT0 divisor */ + void (*int_ai_func) (struct comedi_device *, struct comedi_subdevice *, unsigned short, unsigned int, unsigned short); /* ptr to actual interrupt AI function */ + unsigned char ai16bits; /* =1 16 bit card */ + unsigned char usedma; /* =1 use DMA transfer and not INT */ + unsigned char useeoshandle; /* =1 change WAKE_EOS DMA transfer to fit on every second */ + unsigned char usessh; /* =1 turn on S&H support */ + int softsshdelay; /* >0 use software S&H, numer is requested delay in ns */ + unsigned char softsshsample; /* polarity of S&H signal in sample state */ + unsigned char softsshhold; /* polarity of S&H signal in hold state */ + unsigned int ai_maskerr; /* which warning was printed */ + unsigned int ai_maskharderr; /* on which error bits stops */ + unsigned int ai_inttrig_start; /* TRIG_INT for start */ }; #define devpriv ((struct pci9118_private *)dev->private) @@ -308,53 +309,53 @@ struct pci9118_private { ============================================================================== */ -static int check_channel_list(struct comedi_device * dev, struct comedi_subdevice * s, +static int check_channel_list(struct comedi_device *dev, struct comedi_subdevice *s, int n_chan, unsigned int *chanlist, int frontadd, int backadd); -static int setup_channel_list(struct comedi_device * dev, struct comedi_subdevice * s, +static int setup_channel_list(struct comedi_device *dev, struct comedi_subdevice *s, int n_chan, unsigned int *chanlist, int rot, int frontadd, int backadd, int usedma, char eoshandle); -static void start_pacer(struct comedi_device * dev, int mode, unsigned int divisor1, +static void start_pacer(struct comedi_device *dev, int mode, unsigned int divisor1, unsigned int divisor2); -static int pci9118_reset(struct comedi_device * dev); -static int pci9118_exttrg_add(struct comedi_device * dev, unsigned char source); -static int pci9118_exttrg_del(struct comedi_device * dev, unsigned char source); -static int pci9118_ai_cancel(struct comedi_device * dev, struct comedi_subdevice * s); -static void pci9118_calc_divisors(char mode, struct comedi_device * dev, - struct comedi_subdevice * s, unsigned int *tim1, unsigned int *tim2, +static int pci9118_reset(struct comedi_device *dev); +static int pci9118_exttrg_add(struct comedi_device *dev, unsigned char source); +static int pci9118_exttrg_del(struct comedi_device *dev, unsigned char source); +static int pci9118_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s); +static void pci9118_calc_divisors(char mode, struct comedi_device *dev, + struct comedi_subdevice *s, unsigned int *tim1, unsigned int *tim2, unsigned int flags, int chans, unsigned int *div1, unsigned int *div2, char usessh, unsigned int chnsshfront); /* ============================================================================== */ -static int pci9118_insn_read_ai(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pci9118_insn_read_ai(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int n, timeout; devpriv->AdControlReg = AdControl_Int & 0xff; devpriv->AdFunctionReg = AdFunction_PDTrg | AdFunction_PETrg; - outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC); // positive triggers, no S&H, no burst, burst stop, no post trigger, no about trigger, trigger stop + outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC); /* positive triggers, no S&H, no burst, burst stop, no post trigger, no about trigger, trigger stop */ if (!setup_channel_list(dev, s, 1, &insn->chanspec, 0, 0, 0, 0, 0)) return -EINVAL; - outl(0, dev->iobase + PCI9118_DELFIFO); // flush FIFO + outl(0, dev->iobase + PCI9118_DELFIFO); /* flush FIFO */ for (n = 0; n < insn->n; n++) { outw(0, dev->iobase + PCI9118_SOFTTRG); /* start conversion */ - comedi_udelay(2); + udelay(2); timeout = 100; while (timeout--) { if (inl(dev->iobase + PCI9118_ADSTAT) & AdStatus_ADrdy) goto conv_finish; - comedi_udelay(1); + udelay(1); } comedi_error(dev, "A/D insn timeout"); data[n] = 0; - outl(0, dev->iobase + PCI9118_DELFIFO); // flush FIFO + outl(0, dev->iobase + PCI9118_DELFIFO); /* flush FIFO */ return -ETIME; conv_finish: @@ -369,7 +370,7 @@ static int pci9118_insn_read_ai(struct comedi_device * dev, struct comedi_subdev } } - outl(0, dev->iobase + PCI9118_DELFIFO); // flush FIFO + outl(0, dev->iobase + PCI9118_DELFIFO); /* flush FIFO */ return n; } @@ -377,8 +378,8 @@ static int pci9118_insn_read_ai(struct comedi_device * dev, struct comedi_subdev /* ============================================================================== */ -static int pci9118_insn_write_ao(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pci9118_insn_write_ao(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int n, chanreg, ch; @@ -400,8 +401,8 @@ static int pci9118_insn_write_ao(struct comedi_device * dev, struct comedi_subde /* ============================================================================== */ -static int pci9118_insn_read_ao(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pci9118_insn_read_ao(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int n, chan; @@ -415,8 +416,8 @@ static int pci9118_insn_read_ao(struct comedi_device * dev, struct comedi_subdev /* ============================================================================== */ -static int pci9118_insn_bits_di(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pci9118_insn_bits_di(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { data[1] = inl(dev->iobase + PCI9118_DI) & 0xf; @@ -426,8 +427,8 @@ static int pci9118_insn_bits_di(struct comedi_device * dev, struct comedi_subdev /* ============================================================================== */ -static int pci9118_insn_bits_do(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pci9118_insn_bits_do(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if (data[0]) { s->state &= ~data[0]; @@ -442,7 +443,7 @@ static int pci9118_insn_bits_do(struct comedi_device * dev, struct comedi_subdev /* ============================================================================== */ -static void interrupt_pci9118_ai_mode4_switch(struct comedi_device * dev) +static void interrupt_pci9118_ai_mode4_switch(struct comedi_device *dev) { devpriv->AdFunctionReg = AdFunction_PDTrg | AdFunction_PETrg | AdFunction_AM; @@ -456,8 +457,8 @@ static void interrupt_pci9118_ai_mode4_switch(struct comedi_device * dev) outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC); } -static unsigned int defragment_dma_buffer(struct comedi_device * dev, - struct comedi_subdevice * s, short * dma_buffer, unsigned int num_samples) +static unsigned int defragment_dma_buffer(struct comedi_device *dev, + struct comedi_subdevice *s, short *dma_buffer, unsigned int num_samples) { unsigned int i = 0, j = 0; unsigned int start_pos = devpriv->ai_add_front, @@ -480,8 +481,8 @@ static unsigned int defragment_dma_buffer(struct comedi_device * dev, /* ============================================================================== */ -static unsigned int move_block_from_dma(struct comedi_device * dev, - struct comedi_subdevice * s, short * dma_buffer, unsigned int num_samples) +static unsigned int move_block_from_dma(struct comedi_device *dev, + struct comedi_subdevice *s, short *dma_buffer, unsigned int num_samples) { unsigned int num_bytes; @@ -501,8 +502,8 @@ static unsigned int move_block_from_dma(struct comedi_device * dev, /* ============================================================================== */ -static char pci9118_decode_error_status(struct comedi_device * dev, - struct comedi_subdevice * s, unsigned char m) +static char pci9118_decode_error_status(struct comedi_device *dev, + struct comedi_subdevice *s, unsigned char m) { if (m & 0x100) { comedi_error(dev, "A/D FIFO Full status (Fatal Error!)"); @@ -531,7 +532,7 @@ static char pci9118_decode_error_status(struct comedi_device * dev, return 0; } -static void pci9118_ai_munge(struct comedi_device * dev, struct comedi_subdevice * s, +static void pci9118_ai_munge(struct comedi_device *dev, struct comedi_subdevice *s, void *data, unsigned int num_bytes, unsigned int start_chan_index) { unsigned int i, num_samples = num_bytes / sizeof(short); @@ -551,8 +552,8 @@ static void pci9118_ai_munge(struct comedi_device * dev, struct comedi_subdevice /* ============================================================================== */ -static void interrupt_pci9118_ai_onesample(struct comedi_device * dev, - struct comedi_subdevice * s, unsigned short int_adstat, unsigned int int_amcc, +static void interrupt_pci9118_ai_onesample(struct comedi_device *dev, + struct comedi_subdevice *s, unsigned short int_adstat, unsigned int int_amcc, unsigned short int_daq) { register short sampl; @@ -567,8 +568,8 @@ static void interrupt_pci9118_ai_onesample(struct comedi_device * dev, #ifdef PCI9118_PARANOIDCHECK if (devpriv->ai16bits == 0) { - if ((sampl & 0x000f) != devpriv->chanlist[s->async->cur_chan]) { // data dropout! - rt_printk + if ((sampl & 0x000f) != devpriv->chanlist[s->async->cur_chan]) { /* data dropout! */ + printk ("comedi: A/D SAMPL - data dropout: received channel %d, expected %d!\n", sampl & 0x000f, devpriv->chanlist[s->async->cur_chan]); @@ -598,7 +599,7 @@ static void interrupt_pci9118_ai_onesample(struct comedi_device * dev, /* ============================================================================== */ -static void interrupt_pci9118_ai_dma(struct comedi_device * dev, struct comedi_subdevice * s, +static void interrupt_pci9118_ai_dma(struct comedi_device *dev, struct comedi_subdevice *s, unsigned short int_adstat, unsigned int int_amcc, unsigned short int_daq) { @@ -621,14 +622,14 @@ static void interrupt_pci9118_ai_dma(struct comedi_device * dev, struct comedi_s } if (int_adstat & devpriv->ai_maskerr) -// if (int_adstat & 0x106) +/* if (int_adstat & 0x106) */ if (pci9118_decode_error_status(dev, s, int_adstat)) return; - samplesinbuf = devpriv->dmabuf_use_size[devpriv->dma_actbuf] >> 1; // number of received real samples -// DPRINTK("dma_actbuf=%d\n",devpriv->dma_actbuf); + samplesinbuf = devpriv->dmabuf_use_size[devpriv->dma_actbuf] >> 1; /* number of received real samples */ +/* DPRINTK("dma_actbuf=%d\n",devpriv->dma_actbuf); */ - if (devpriv->dma_doublebuf) { // switch DMA buffers if is used double buffering + if (devpriv->dma_doublebuf) { /* switch DMA buffers if is used double buffering */ next_dma_buf = 1 - devpriv->dma_actbuf; outl(devpriv->dmabuf_hw[next_dma_buf], devpriv->iobase_a + AMCC_OP_REG_MWAR); @@ -641,15 +642,15 @@ static void interrupt_pci9118_ai_dma(struct comedi_device * dev, struct comedi_s } if (samplesinbuf) { - m = devpriv->ai_data_len >> 1; // how many samples is to end of buffer -// DPRINTK("samps=%d m=%d %d %d\n",samplesinbuf,m,s->async->buf_int_count,s->async->buf_int_ptr); + m = devpriv->ai_data_len >> 1; /* how many samples is to end of buffer */ +/* DPRINTK("samps=%d m=%d %d %d\n",samplesinbuf,m,s->async->buf_int_count,s->async->buf_int_ptr); */ sampls = m; move_block_from_dma(dev, s, devpriv->dmabuf_virt[devpriv->dma_actbuf], samplesinbuf); - m = m - sampls; // m= how many samples was transfered + m = m - sampls; /* m= how many samples was transfered */ } -// DPRINTK("YYY\n"); +/* DPRINTK("YYY\n"); */ if (!devpriv->ai_neverending) if (devpriv->ai_act_scan >= devpriv->ai_scans) { /* all data sampled */ @@ -657,9 +658,9 @@ static void interrupt_pci9118_ai_dma(struct comedi_device * dev, struct comedi_s s->async->events |= COMEDI_CB_EOA; } - if (devpriv->dma_doublebuf) { // switch dma buffers + if (devpriv->dma_doublebuf) { /* switch dma buffers */ devpriv->dma_actbuf = 1 - devpriv->dma_actbuf; - } else { // restart DMA if is not used double buffering + } else { /* restart DMA if is not used double buffering */ outl(devpriv->dmabuf_hw[0], devpriv->iobase_a + AMCC_OP_REG_MWAR); outl(devpriv->dmabuf_use_size[0], @@ -674,36 +675,36 @@ static void interrupt_pci9118_ai_dma(struct comedi_device * dev, struct comedi_s /* ============================================================================== */ -static irqreturn_t interrupt_pci9118(int irq, void *d PT_REGS_ARG) +static irqreturn_t interrupt_pci9118(int irq, void *d) { struct comedi_device *dev = d; unsigned int int_daq = 0, int_amcc, int_adstat; if (!dev->attached) - return IRQ_NONE; // not fully initialized + return IRQ_NONE; /* not fully initialized */ - int_daq = inl(dev->iobase + PCI9118_INTSRC) & 0xf; // get IRQ reasons from card - int_amcc = inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR); // get INT register from AMCC chip + int_daq = inl(dev->iobase + PCI9118_INTSRC) & 0xf; /* get IRQ reasons from card */ + int_amcc = inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR); /* get INT register from AMCC chip */ -// DPRINTK("INT daq=0x%01x amcc=0x%08x MWAR=0x%08x MWTC=0x%08x ADSTAT=0x%02x ai_do=%d\n", int_daq, int_amcc, inl(devpriv->iobase_a+AMCC_OP_REG_MWAR), inl(devpriv->iobase_a+AMCC_OP_REG_MWTC), inw(dev->iobase+PCI9118_ADSTAT)&0x1ff,devpriv->ai_do); +/* DPRINTK("INT daq=0x%01x amcc=0x%08x MWAR=0x%08x MWTC=0x%08x ADSTAT=0x%02x ai_do=%d\n", int_daq, int_amcc, inl(devpriv->iobase_a+AMCC_OP_REG_MWAR), inl(devpriv->iobase_a+AMCC_OP_REG_MWTC), inw(dev->iobase+PCI9118_ADSTAT)&0x1ff,devpriv->ai_do); */ if ((!int_daq) && (!(int_amcc & ANY_S593X_INT))) - return IRQ_NONE; // interrupt from other source + return IRQ_NONE; /* interrupt from other source */ - outl(int_amcc | 0x00ff0000, devpriv->iobase_a + AMCC_OP_REG_INTCSR); // shutdown IRQ reasons in AMCC + outl(int_amcc | 0x00ff0000, devpriv->iobase_a + AMCC_OP_REG_INTCSR); /* shutdown IRQ reasons in AMCC */ - int_adstat = inw(dev->iobase + PCI9118_ADSTAT) & 0x1ff; // get STATUS register + int_adstat = inw(dev->iobase + PCI9118_ADSTAT) & 0x1ff; /* get STATUS register */ if (devpriv->ai_do) { if (devpriv->ai12_startstop) - if ((int_adstat & AdStatus_DTH) && (int_daq & Int_DTrg)) { // start stop of measure + if ((int_adstat & AdStatus_DTH) && (int_daq & Int_DTrg)) { /* start stop of measure */ if (devpriv->ai12_startstop & START_AI_EXT) { devpriv->ai12_startstop &= ~START_AI_EXT; if (!(devpriv->ai12_startstop & STOP_AI_EXT)) - pci9118_exttrg_del(dev, EXTTRG_AI); // deactivate EXT trigger - start_pacer(dev, devpriv->ai_do, devpriv->ai_divisor1, devpriv->ai_divisor2); // start pacer + pci9118_exttrg_del(dev, EXTTRG_AI); /* deactivate EXT trigger */ + start_pacer(dev, devpriv->ai_do, devpriv->ai_divisor1, devpriv->ai_divisor2); /* start pacer */ outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL); } else { @@ -711,8 +712,8 @@ static irqreturn_t interrupt_pci9118(int irq, void *d PT_REGS_ARG) ai12_startstop & STOP_AI_EXT) { devpriv->ai12_startstop &= ~STOP_AI_EXT; - pci9118_exttrg_del(dev, EXTTRG_AI); // deactivate EXT trigger - devpriv->ai_neverending = 0; //well, on next interrupt from DMA/EOC measure will stop + pci9118_exttrg_del(dev, EXTTRG_AI); /* deactivate EXT trigger */ + devpriv->ai_neverending = 0; /* well, on next interrupt from DMA/EOC measure will stop */ } } } @@ -727,7 +728,7 @@ static irqreturn_t interrupt_pci9118(int irq, void *d PT_REGS_ARG) /* ============================================================================== */ -static int pci9118_ai_inttrig(struct comedi_device * dev, struct comedi_subdevice * s, +static int pci9118_ai_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int trignum) { if (trignum != devpriv->ai_inttrig_start) @@ -751,8 +752,8 @@ static int pci9118_ai_inttrig(struct comedi_device * dev, struct comedi_subdevic /* ============================================================================== */ -static int pci9118_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd) +static int pci9118_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd) { int err = 0; int tmp, divisor1, divisor2; @@ -949,11 +950,11 @@ static int pci9118_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevic if (cmd->scan_begin_src == TRIG_TIMER) { tmp = cmd->scan_begin_arg; -// rt_printk("S1 timer1=%u timer2=%u\n",cmd->scan_begin_arg,cmd->convert_arg); +/* printk("S1 timer1=%u timer2=%u\n",cmd->scan_begin_arg,cmd->convert_arg); */ i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1, &divisor2, &cmd->scan_begin_arg, cmd->flags & TRIG_ROUND_MASK); -// rt_printk("S2 timer1=%u timer2=%u\n",cmd->scan_begin_arg,cmd->convert_arg); +/* printk("S2 timer1=%u timer2=%u\n",cmd->scan_begin_arg,cmd->convert_arg); */ if (cmd->scan_begin_arg < this_board->ai_ns_min) cmd->scan_begin_arg = this_board->ai_ns_min; if (tmp != cmd->scan_begin_arg) @@ -965,7 +966,7 @@ static int pci9118_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevic i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1, &divisor2, &cmd->convert_arg, cmd->flags & TRIG_ROUND_MASK); -// rt_printk("s1 timer1=%u timer2=%u\n",cmd->scan_begin_arg,cmd->convert_arg); +/* printk("s1 timer1=%u timer2=%u\n",cmd->scan_begin_arg,cmd->convert_arg); */ if (cmd->convert_arg < this_board->ai_ns_min) cmd->convert_arg = this_board->ai_ns_min; if (tmp != cmd->convert_arg) @@ -979,7 +980,7 @@ static int pci9118_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevic cmd->scan_begin_arg = this_board->ai_ns_min * (cmd->scan_end_arg + 2); -// rt_printk("s2 timer1=%u timer2=%u\n",cmd->scan_begin_arg,cmd->convert_arg); +/* printk("s2 timer1=%u timer2=%u\n",cmd->scan_begin_arg,cmd->convert_arg); */ err++; } } else { @@ -988,7 +989,7 @@ static int pci9118_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevic cmd->scan_begin_arg = cmd->convert_arg * cmd->chanlist_len; -// rt_printk("s3 timer1=%u timer2=%u\n",cmd->scan_begin_arg,cmd->convert_arg); +/* printk("s3 timer1=%u timer2=%u\n",cmd->scan_begin_arg,cmd->convert_arg); */ err++; } } @@ -1001,7 +1002,7 @@ static int pci9118_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevic if (cmd->chanlist) if (!check_channel_list(dev, s, cmd->chanlist_len, cmd->chanlist, 0, 0)) - return 5; // incorrect channels list + return 5; /* incorrect channels list */ return 0; } @@ -1009,7 +1010,7 @@ static int pci9118_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevic /* ============================================================================== */ -static int Compute_and_setup_dma(struct comedi_device * dev) +static int Compute_and_setup_dma(struct comedi_device *dev) { unsigned int dmalen0, dmalen1, i; @@ -1018,32 +1019,32 @@ static int Compute_and_setup_dma(struct comedi_device * dev) dmalen1 = devpriv->dmabuf_size[1]; DPRINTK("1 dmalen0=%d dmalen1=%d ai_data_len=%d\n", dmalen0, dmalen1, devpriv->ai_data_len); - // isn't output buff smaller that our DMA buff? + /* isn't output buff smaller that our DMA buff? */ if (dmalen0 > (devpriv->ai_data_len)) { - dmalen0 = devpriv->ai_data_len & ~3L; // allign to 32bit down + dmalen0 = devpriv->ai_data_len & ~3L; /* allign to 32bit down */ } if (dmalen1 > (devpriv->ai_data_len)) { - dmalen1 = devpriv->ai_data_len & ~3L; // allign to 32bit down + dmalen1 = devpriv->ai_data_len & ~3L; /* allign to 32bit down */ } DPRINTK("2 dmalen0=%d dmalen1=%d \n", dmalen0, dmalen1); - // we want wake up every scan? + /* we want wake up every scan? */ if (devpriv->ai_flags & TRIG_WAKE_EOS) { if (dmalen0 < (devpriv->ai_n_realscanlen << 1)) { - // uff, too short DMA buffer, disable EOS support! + /* uff, too short DMA buffer, disable EOS support! */ devpriv->ai_flags &= (~TRIG_WAKE_EOS); - rt_printk + printk ("comedi%d: WAR: DMA0 buf too short, cann't support TRIG_WAKE_EOS (%d<%d)\n", dev->minor, dmalen0, devpriv->ai_n_realscanlen << 1); } else { - // short first DMA buffer to one scan + /* short first DMA buffer to one scan */ dmalen0 = devpriv->ai_n_realscanlen << 1; DPRINTK("21 dmalen0=%d ai_n_realscanlen=%d useeoshandle=%d\n", dmalen0, devpriv->ai_n_realscanlen, devpriv->useeoshandle); if (devpriv->useeoshandle) dmalen0 += 2; if (dmalen0 < 4) { - rt_printk + printk ("comedi%d: ERR: DMA0 buf len bug? (%d<4)\n", dev->minor, dmalen0); dmalen0 = 4; @@ -1052,20 +1053,20 @@ static int Compute_and_setup_dma(struct comedi_device * dev) } if (devpriv->ai_flags & TRIG_WAKE_EOS) { if (dmalen1 < (devpriv->ai_n_realscanlen << 1)) { - // uff, too short DMA buffer, disable EOS support! + /* uff, too short DMA buffer, disable EOS support! */ devpriv->ai_flags &= (~TRIG_WAKE_EOS); - rt_printk + printk ("comedi%d: WAR: DMA1 buf too short, cann't support TRIG_WAKE_EOS (%d<%d)\n", dev->minor, dmalen1, devpriv->ai_n_realscanlen << 1); } else { - // short second DMA buffer to one scan + /* short second DMA buffer to one scan */ dmalen1 = devpriv->ai_n_realscanlen << 1; DPRINTK("22 dmalen1=%d ai_n_realscanlen=%d useeoshandle=%d\n", dmalen1, devpriv->ai_n_realscanlen, devpriv->useeoshandle); if (devpriv->useeoshandle) dmalen1 -= 2; if (dmalen1 < 4) { - rt_printk + printk ("comedi%d: ERR: DMA1 buf len bug? (%d<4)\n", dev->minor, dmalen1); dmalen1 = 4; @@ -1074,26 +1075,26 @@ static int Compute_and_setup_dma(struct comedi_device * dev) } DPRINTK("3 dmalen0=%d dmalen1=%d \n", dmalen0, dmalen1); - // transfer without TRIG_WAKE_EOS + /* transfer without TRIG_WAKE_EOS */ if (!(devpriv->ai_flags & TRIG_WAKE_EOS)) { - // if it's possible then allign DMA buffers to length of scan + /* if it's possible then allign DMA buffers to length of scan */ i = dmalen0; dmalen0 = (dmalen0 / (devpriv->ai_n_realscanlen << 1)) * (devpriv->ai_n_realscanlen << 1); dmalen0 &= ~3L; if (!dmalen0) - dmalen0 = i; // uff. very long scan? + dmalen0 = i; /* uff. very long scan? */ i = dmalen1; dmalen1 = (dmalen1 / (devpriv->ai_n_realscanlen << 1)) * (devpriv->ai_n_realscanlen << 1); dmalen1 &= ~3L; if (!dmalen1) - dmalen1 = i; // uff. very long scan? - // if measure isn't neverending then test, if it whole fits into one or two DMA buffers + dmalen1 = i; /* uff. very long scan? */ + /* if measure isn't neverending then test, if it whole fits into one or two DMA buffers */ if (!devpriv->ai_neverending) { - // fits whole measure into one DMA buffer? + /* fits whole measure into one DMA buffer? */ if (dmalen0 > ((devpriv->ai_n_realscanlen << 1) * devpriv->ai_scans)) { @@ -1104,7 +1105,7 @@ static int Compute_and_setup_dma(struct comedi_device * dev) DPRINTK("3.1 dmalen0=%d dmalen1=%d \n", dmalen0, dmalen1); dmalen0 &= ~3L; - } else { // fits whole measure into two DMA buffer? + } else { /* fits whole measure into two DMA buffer? */ if (dmalen1 > ((devpriv->ai_n_realscanlen << 1) * devpriv->ai_scans - dmalen0)) @@ -1121,7 +1122,7 @@ static int Compute_and_setup_dma(struct comedi_device * dev) DPRINTK("4 dmalen0=%d dmalen1=%d \n", dmalen0, dmalen1); - // these DMA buffer size we'll be used + /* these DMA buffer size we'll be used */ devpriv->dma_actbuf = 0; devpriv->dmabuf_use_size[0] = dmalen0; devpriv->dmabuf_use_size[1] = dmalen1; @@ -1143,18 +1144,18 @@ static int Compute_and_setup_dma(struct comedi_device * dev) } #endif - outl(inl(devpriv->iobase_a + AMCC_OP_REG_MCSR) & (~EN_A2P_TRANSFERS), devpriv->iobase_a + AMCC_OP_REG_MCSR); // stop DMA + outl(inl(devpriv->iobase_a + AMCC_OP_REG_MCSR) & (~EN_A2P_TRANSFERS), devpriv->iobase_a + AMCC_OP_REG_MCSR); /* stop DMA */ outl(devpriv->dmabuf_hw[0], devpriv->iobase_a + AMCC_OP_REG_MWAR); outl(devpriv->dmabuf_use_size[0], devpriv->iobase_a + AMCC_OP_REG_MWTC); - // init DMA transfer + /* init DMA transfer */ outl(0x00000000 | AINT_WRITE_COMPL, devpriv->iobase_a + AMCC_OP_REG_INTCSR); -// outl(0x02000000|AINT_WRITE_COMPL, devpriv->iobase_a+AMCC_OP_REG_INTCSR); +/* outl(0x02000000|AINT_WRITE_COMPL, devpriv->iobase_a+AMCC_OP_REG_INTCSR); */ outl(inl(devpriv->iobase_a + AMCC_OP_REG_MCSR) | RESET_A2P_FLAGS | A2P_HI_PRIORITY | EN_A2P_TRANSFERS, devpriv->iobase_a + AMCC_OP_REG_MCSR); - outl(inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR) | EN_A2P_TRANSFERS, devpriv->iobase_a + AMCC_OP_REG_INTCSR); // allow bus mastering + outl(inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR) | EN_A2P_TRANSFERS, devpriv->iobase_a + AMCC_OP_REG_INTCSR); /* allow bus mastering */ DPRINTK("adl_pci9118 EDBG: END: Compute_and_setup_dma()\n"); return 0; @@ -1163,7 +1164,7 @@ static int Compute_and_setup_dma(struct comedi_device * dev) /* ============================================================================== */ -static int pci9118_ai_docmd_sampl(struct comedi_device * dev, struct comedi_subdevice * s) +static int pci9118_ai_docmd_sampl(struct comedi_device *dev, struct comedi_subdevice *s) { DPRINTK("adl_pci9118 EDBG: BGN: pci9118_ai_docmd_sampl(%d,) [%d]\n", dev->minor, devpriv->ai_do); @@ -1186,17 +1187,17 @@ static int pci9118_ai_docmd_sampl(struct comedi_device * dev, struct comedi_subd return -EIO; }; - devpriv->int_ai_func = interrupt_pci9118_ai_onesample; //transfer function + devpriv->int_ai_func = interrupt_pci9118_ai_onesample; /* transfer function */ if (devpriv->ai12_startstop) - pci9118_exttrg_add(dev, EXTTRG_AI); // activate EXT trigger + pci9118_exttrg_add(dev, EXTTRG_AI); /* activate EXT trigger */ if ((devpriv->ai_do == 1) || (devpriv->ai_do == 2)) devpriv->IntControlReg |= Int_Timer; devpriv->AdControlReg |= AdControl_Int; - outl(inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR) | 0x1f00, devpriv->iobase_a + AMCC_OP_REG_INTCSR); // allow INT in AMCC + outl(inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR) | 0x1f00, devpriv->iobase_a + AMCC_OP_REG_INTCSR); /* allow INT in AMCC */ if (!(devpriv->ai12_startstop & (START_AI_EXT | START_AI_INT))) { outl(devpriv->IntControlReg, dev->iobase + PCI9118_INTCTRL); @@ -1216,7 +1217,7 @@ static int pci9118_ai_docmd_sampl(struct comedi_device * dev, struct comedi_subd /* ============================================================================== */ -static int pci9118_ai_docmd_dma(struct comedi_device * dev, struct comedi_subdevice * s) +static int pci9118_ai_docmd_dma(struct comedi_device *dev, struct comedi_subdevice *s) { DPRINTK("adl_pci9118 EDBG: BGN: pci9118_ai_docmd_dma(%d,) [%d,%d]\n", dev->minor, devpriv->ai_do, devpriv->usedma); @@ -1261,10 +1262,10 @@ static int pci9118_ai_docmd_dma(struct comedi_device * dev, struct comedi_subdev }; if (devpriv->ai12_startstop) { - pci9118_exttrg_add(dev, EXTTRG_AI); // activate EXT trigger + pci9118_exttrg_add(dev, EXTTRG_AI); /* activate EXT trigger */ } - devpriv->int_ai_func = interrupt_pci9118_ai_dma; //transfer function + devpriv->int_ai_func = interrupt_pci9118_ai_dma; /* transfer function */ outl(0x02000000 | AINT_WRITE_COMPL, devpriv->iobase_a + AMCC_OP_REG_INTCSR); @@ -1287,7 +1288,7 @@ static int pci9118_ai_docmd_dma(struct comedi_device * dev, struct comedi_subdev /* ============================================================================== */ -static int pci9118_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s) +static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { struct comedi_cmd *cmd = &s->async->cmd; unsigned int addchans = 0; @@ -1307,7 +1308,7 @@ static int pci9118_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * devpriv->ai_add_back = 0; devpriv->ai_maskerr = 0x10e; - // prepare for start/stop conditions + /* prepare for start/stop conditions */ if (cmd->start_src == TRIG_EXT) devpriv->ai12_startstop |= START_AI_EXT; if (cmd->stop_src == TRIG_EXT) { @@ -1334,19 +1335,19 @@ static int pci9118_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * devpriv->ai_scans = 0; } - // use sample&hold signal? + /* use sample&hold signal? */ if (cmd->convert_src == TRIG_NOW) { devpriv->usessh = 1; - } // yes + } /* yes */ else { devpriv->usessh = 0; - } // no + } /* no */ DPRINTK("1 neverending=%d scans=%u usessh=%d ai_startstop=0x%2x\n", devpriv->ai_neverending, devpriv->ai_scans, devpriv->usessh, devpriv->ai12_startstop); - // use additional sample at end of every scan to satisty DMA 32 bit transfer? + /* use additional sample at end of every scan to satisty DMA 32 bit transfer? */ devpriv->ai_add_front = 0; devpriv->ai_add_back = 0; devpriv->useeoshandle = 0; @@ -1358,27 +1359,27 @@ static int pci9118_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * devpriv->ai_add_back = 1; } if (cmd->convert_src == TRIG_TIMER) { - devpriv->usedma = 0; // use INT transfer if scanlist have only one channel + devpriv->usedma = 0; /* use INT transfer if scanlist have only one channel */ } } if ((cmd->flags & TRIG_WAKE_EOS) && (devpriv->ai_n_scanlen & 1) && (devpriv->ai_n_scanlen > 1)) { if (cmd->scan_begin_src == TRIG_FOLLOW) { - //vpriv->useeoshandle=1; // change DMA transfer block to fit EOS on every second call - devpriv->usedma = 0; // XXX maybe can be corrected to use 16 bit DMA - } else { // well, we must insert one sample to end of EOS to meet 32 bit transfer + /* vpriv->useeoshandle=1; // change DMA transfer block to fit EOS on every second call */ + devpriv->usedma = 0; /* XXX maybe can be corrected to use 16 bit DMA */ + } else { /* well, we must insert one sample to end of EOS to meet 32 bit transfer */ devpriv->ai_add_back = 1; } } - } else { // interrupt transfer don't need any correction + } else { /* interrupt transfer don't need any correction */ devpriv->usedma = 0; } - // we need software S&H signal? It add two samples before every scan as minimum + /* we need software S&H signal? It add two samples before every scan as minimum */ if (devpriv->usessh && devpriv->softsshdelay) { devpriv->ai_add_front = 2; - if ((devpriv->usedma == 1) && (devpriv->ai_add_back == 1)) { // move it to front + if ((devpriv->usedma == 1) && (devpriv->ai_add_back == 1)) { /* move it to front */ devpriv->ai_add_front++; devpriv->ai_add_back = 0; } @@ -1387,17 +1388,17 @@ static int pci9118_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * addchans = devpriv->softsshdelay / cmd->convert_arg; if (devpriv->softsshdelay % cmd->convert_arg) addchans++; - if (addchans > (devpriv->ai_add_front - 1)) { // uff, still short :-( + if (addchans > (devpriv->ai_add_front - 1)) { /* uff, still short :-( */ devpriv->ai_add_front = addchans + 1; if (devpriv->usedma == 1) if ((devpriv->ai_add_front + devpriv->ai_n_chan + devpriv->ai_add_back) & 1) - devpriv->ai_add_front++; // round up to 32 bit + devpriv->ai_add_front++; /* round up to 32 bit */ } - } // well, we now know what must be all added + } /* well, we now know what must be all added */ - devpriv->ai_n_realscanlen = // what we must take from card in real to have ai_n_scanlen on output? + devpriv->ai_n_realscanlen = /* what we must take from card in real to have ai_n_scanlen on output? */ (devpriv->ai_add_front + devpriv->ai_n_chan + devpriv->ai_add_back) * (devpriv->ai_n_scanlen / devpriv->ai_n_chan); @@ -1408,7 +1409,7 @@ static int pci9118_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * devpriv->ai_n_chan, devpriv->ai_add_back, devpriv->ai_n_scanlen); - // check and setup channel list + /* check and setup channel list */ if (!check_channel_list(dev, s, devpriv->ai_n_chan, devpriv->ai_chanlist, devpriv->ai_add_front, devpriv->ai_add_back)) @@ -1419,9 +1420,9 @@ static int pci9118_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * devpriv->useeoshandle)) return -EINVAL; - // compute timers settings - // simplest way, fr=4Mhz/(tim1*tim2), channel manipulation without timers effect - if (((cmd->scan_begin_src == TRIG_FOLLOW) || (cmd->scan_begin_src == TRIG_EXT) || (cmd->scan_begin_src == TRIG_INT)) && (cmd->convert_src == TRIG_TIMER)) { // both timer is used for one time + /* compute timers settings */ + /* simplest way, fr=4Mhz/(tim1*tim2), channel manipulation without timers effect */ + if (((cmd->scan_begin_src == TRIG_FOLLOW) || (cmd->scan_begin_src == TRIG_EXT) || (cmd->scan_begin_src == TRIG_INT)) && (cmd->convert_src == TRIG_TIMER)) { /* both timer is used for one time */ if (cmd->scan_begin_src == TRIG_EXT) { devpriv->ai_do = 4; } else { @@ -1435,7 +1436,7 @@ static int pci9118_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * devpriv->ai_timer2 = cmd->convert_arg; } - if ((cmd->scan_begin_src == TRIG_TIMER) && ((cmd->convert_src == TRIG_TIMER) || (cmd->convert_src == TRIG_NOW))) { // double timed action + if ((cmd->scan_begin_src == TRIG_TIMER) && ((cmd->convert_src == TRIG_TIMER) || (cmd->convert_src == TRIG_NOW))) { /* double timed action */ if (!devpriv->usedma) { comedi_error(dev, "cmd->scan_begin_src=TRIG_TIMER works only with bus mastering!"); @@ -1457,15 +1458,15 @@ static int pci9118_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * devpriv->ai_do = 3; } - start_pacer(dev, -1, 0, 0); // stop pacer + start_pacer(dev, -1, 0, 0); /* stop pacer */ - devpriv->AdControlReg = 0; // bipolar, S.E., use 8254, stop 8354, internal trigger, soft trigger, disable DMA + devpriv->AdControlReg = 0; /* bipolar, S.E., use 8254, stop 8354, internal trigger, soft trigger, disable DMA */ outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL); - devpriv->AdFunctionReg = AdFunction_PDTrg | AdFunction_PETrg; // positive triggers, no S&H, no burst, burst stop, no post trigger, no about trigger, trigger stop + devpriv->AdFunctionReg = AdFunction_PDTrg | AdFunction_PETrg; /* positive triggers, no S&H, no burst, burst stop, no post trigger, no about trigger, trigger stop */ outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC); - comedi_udelay(1); - outl(0, dev->iobase + PCI9118_DELFIFO); // flush FIFO - inl(dev->iobase + PCI9118_ADSTAT); // flush A/D and INT status register + udelay(1); + outl(0, dev->iobase + PCI9118_DELFIFO); /* flush FIFO */ + inl(dev->iobase + PCI9118_ADSTAT); /* flush A/D and INT status register */ inl(dev->iobase + PCI9118_INTSRC); devpriv->ai_act_scan = 0; @@ -1473,11 +1474,10 @@ static int pci9118_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s->async->cur_chan = 0; devpriv->ai_buf_ptr = 0; - if (devpriv->usedma) { + if (devpriv->usedma) ret = pci9118_ai_docmd_dma(dev, s); - } else { + else ret = pci9118_ai_docmd_sampl(dev, s); - } DPRINTK("adl_pci9118 EDBG: END: pci9118_ai_cmd()\n"); return ret; @@ -1486,7 +1486,7 @@ static int pci9118_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * /* ============================================================================== */ -static int check_channel_list(struct comedi_device * dev, struct comedi_subdevice * s, +static int check_channel_list(struct comedi_device *dev, struct comedi_subdevice *s, int n_chan, unsigned int *chanlist, int frontadd, int backadd) { unsigned int i, differencial = 0, bipolar = 0; @@ -1497,7 +1497,7 @@ static int check_channel_list(struct comedi_device * dev, struct comedi_subdevic return 0; } if ((frontadd + n_chan + backadd) > s->len_chanlist) { - rt_printk + printk ("comedi%d: range/channel list is too long for actual configuration (%d>%d)!", dev->minor, n_chan, s->len_chanlist - frontadd - backadd); @@ -1505,11 +1505,11 @@ static int check_channel_list(struct comedi_device * dev, struct comedi_subdevic } if (CR_AREF(chanlist[0]) == AREF_DIFF) - differencial = 1; // all input must be diff + differencial = 1; /* all input must be diff */ if (CR_RANGE(chanlist[0]) < PCI9118_BIPOLAR_RANGES) - bipolar = 1; // all input must be bipolar + bipolar = 1; /* all input must be bipolar */ if (n_chan > 1) - for (i = 1; i < n_chan; i++) { // check S.E/diff + for (i = 1; i < n_chan; i++) { /* check S.E/diff */ if ((CR_AREF(chanlist[i]) == AREF_DIFF) != (differencial)) { comedi_error(dev, @@ -1537,7 +1537,7 @@ static int check_channel_list(struct comedi_device * dev, struct comedi_subdevic /* ============================================================================== */ -static int setup_channel_list(struct comedi_device * dev, struct comedi_subdevice * s, +static int setup_channel_list(struct comedi_device *dev, struct comedi_subdevice *s, int n_chan, unsigned int *chanlist, int rot, int frontadd, int backadd, int usedma, char useeos) { @@ -1552,27 +1552,27 @@ static int setup_channel_list(struct comedi_device * dev, struct comedi_subdevic } if (CR_AREF(chanlist[0]) == AREF_DIFF) - differencial = 1; // all input must be diff + differencial = 1; /* all input must be diff */ if (CR_RANGE(chanlist[0]) < PCI9118_BIPOLAR_RANGES) - bipolar = 1; // all input must be bipolar + bipolar = 1; /* all input must be bipolar */ - // All is ok, so we can setup channel/range list + /* All is ok, so we can setup channel/range list */ if (!bipolar) { - devpriv->AdControlReg |= AdControl_UniP; // set unibipolar + devpriv->AdControlReg |= AdControl_UniP; /* set unibipolar */ } else { - devpriv->AdControlReg &= ((~AdControl_UniP) & 0xff); // enable bipolar + devpriv->AdControlReg &= ((~AdControl_UniP) & 0xff); /* enable bipolar */ } if (differencial) { - devpriv->AdControlReg |= AdControl_Diff; // enable diff inputs + devpriv->AdControlReg |= AdControl_Diff; /* enable diff inputs */ } else { - devpriv->AdControlReg &= ((~AdControl_Diff) & 0xff); // set single ended inputs + devpriv->AdControlReg &= ((~AdControl_Diff) & 0xff); /* set single ended inputs */ } - outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL); // setup mode + outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL); /* setup mode */ - outl(2, dev->iobase + PCI9118_SCANMOD); // gods know why this sequence! + outl(2, dev->iobase + PCI9118_SCANMOD); /* gods know why this sequence! */ outl(0, dev->iobase + PCI9118_SCANMOD); outl(1, dev->iobase + PCI9118_SCANMOD); @@ -1582,12 +1582,12 @@ static int setup_channel_list(struct comedi_device * dev, struct comedi_subdevic devpriv->chanlist[i] = 0x55aa; #endif - if (frontadd) { // insert channels for S&H + if (frontadd) { /* insert channels for S&H */ ssh = devpriv->softsshsample; DPRINTK("FA: %04x: ", ssh); - for (i = 0; i < frontadd; i++) { // store range list to card - scanquad = CR_CHAN(chanlist[0]); // get channel number; - gain = CR_RANGE(chanlist[0]); // get gain number + for (i = 0; i < frontadd; i++) { /* store range list to card */ + scanquad = CR_CHAN(chanlist[0]); /* get channel number; */ + gain = CR_RANGE(chanlist[0]); /* get gain number */ scanquad |= ((gain & 0x03) << 8); outl(scanquad | ssh, dev->iobase + PCI9118_GAIN); DPRINTK("%02x ", scanquad | ssh); @@ -1597,23 +1597,23 @@ static int setup_channel_list(struct comedi_device * dev, struct comedi_subdevic } DPRINTK("SL: ", ssh); - for (i = 0; i < n_chan; i++) { // store range list to card - scanquad = CR_CHAN(chanlist[i]); // get channel number; + for (i = 0; i < n_chan; i++) { /* store range list to card */ + scanquad = CR_CHAN(chanlist[i]); /* get channel number; */ #ifdef PCI9118_PARANOIDCHECK devpriv->chanlist[i ^ usedma] = (scanquad & 0xf) << rot; #endif - gain = CR_RANGE(chanlist[i]); // get gain number + gain = CR_RANGE(chanlist[i]); /* get gain number */ scanquad |= ((gain & 0x03) << 8); outl(scanquad | ssh, dev->iobase + PCI9118_GAIN); DPRINTK("%02x ", scanquad | ssh); } DPRINTK("\n "); - if (backadd) { // insert channels for fit onto 32bit DMA + if (backadd) { /* insert channels for fit onto 32bit DMA */ DPRINTK("BA: %04x: ", ssh); - for (i = 0; i < backadd; i++) { // store range list to card - scanquad = CR_CHAN(chanlist[0]); // get channel number; - gain = CR_RANGE(chanlist[0]); // get gain number + for (i = 0; i < backadd; i++) { /* store range list to card */ + scanquad = CR_CHAN(chanlist[0]); /* get channel number; */ + gain = CR_RANGE(chanlist[0]); /* get gain number */ scanquad |= ((gain & 0x03) << 8); outl(scanquad | ssh, dev->iobase + PCI9118_GAIN); DPRINTK("%02x ", scanquad | ssh); @@ -1621,13 +1621,13 @@ static int setup_channel_list(struct comedi_device * dev, struct comedi_subdevic DPRINTK("\n "); } #ifdef PCI9118_PARANOIDCHECK - devpriv->chanlist[n_chan ^ usedma] = devpriv->chanlist[0 ^ usedma]; // for 32bit oerations + devpriv->chanlist[n_chan ^ usedma] = devpriv->chanlist[0 ^ usedma]; /* for 32bit oerations */ if (useeos) { - for (i = 1; i < n_chan; i++) { // store range list to card + for (i = 1; i < n_chan; i++) { /* store range list to card */ devpriv->chanlist[(n_chan + i) ^ usedma] = (CR_CHAN(chanlist[i]) & 0xf) << rot; } - devpriv->chanlist[(2 * n_chan) ^ usedma] = devpriv->chanlist[0 ^ usedma]; // for 32bit oerations + devpriv->chanlist[(2 * n_chan) ^ usedma] = devpriv->chanlist[0 ^ usedma]; /* for 32bit oerations */ useeos = 2; } else { useeos = 1; @@ -1640,19 +1640,19 @@ static int setup_channel_list(struct comedi_device * dev, struct comedi_subdevic DPRINTK("\n "); #endif #endif - outl(0, dev->iobase + PCI9118_SCANMOD); // close scan queue -// comedi_udelay(100); // important delay, or first sample will be cripled + outl(0, dev->iobase + PCI9118_SCANMOD); /* close scan queue */ +/* udelay(100); important delay, or first sample will be cripled */ DPRINTK("adl_pci9118 EDBG: END: setup_channel_list()\n"); - return 1; // we can serve this with scan logic + return 1; /* we can serve this with scan logic */ } /* ============================================================================== calculate 8254 divisors if they are used for dual timing */ -static void pci9118_calc_divisors(char mode, struct comedi_device * dev, - struct comedi_subdevice * s, unsigned int *tim1, unsigned int *tim2, +static void pci9118_calc_divisors(char mode, struct comedi_device *dev, + struct comedi_subdevice *s, unsigned int *tim1, unsigned int *tim2, unsigned int flags, int chans, unsigned int *div1, unsigned int *div2, char usessh, unsigned int chnsshfront) { @@ -1672,17 +1672,17 @@ static void pci9118_calc_divisors(char mode, struct comedi_device * dev, *tim2 = this_board->ai_ns_min; DPRINTK("1 div1=%u div2=%u timer1=%u timer2=%u\n", *div1, *div2, *tim1, *tim2); - *div1 = *tim2 / devpriv->i8254_osc_base; // convert timer (burst) + *div1 = *tim2 / devpriv->i8254_osc_base; /* convert timer (burst) */ DPRINTK("2 div1=%u div2=%u timer1=%u timer2=%u\n", *div1, *div2, *tim1, *tim2); if (*div1 < this_board->ai_pacer_min) *div1 = this_board->ai_pacer_min; DPRINTK("3 div1=%u div2=%u timer1=%u timer2=%u\n", *div1, *div2, *tim1, *tim2); - *div2 = *tim1 / devpriv->i8254_osc_base; // scan timer + *div2 = *tim1 / devpriv->i8254_osc_base; /* scan timer */ DPRINTK("4 div1=%u div2=%u timer1=%u timer2=%u\n", *div1, *div2, *tim1, *tim2); - *div2 = *div2 / *div1; // major timer is c1*c2 + *div2 = *div2 / *div1; /* major timer is c1*c2 */ DPRINTK("5 div1=%u div2=%u timer1=%u timer2=%u\n", *div1, *div2, *tim1, *tim2); if (*div2 < chans) @@ -1690,9 +1690,9 @@ static void pci9118_calc_divisors(char mode, struct comedi_device * dev, DPRINTK("6 div1=%u div2=%u timer1=%u timer2=%u\n", *div1, *div2, *tim1, *tim2); - *tim2 = *div1 * devpriv->i8254_osc_base; // real convert timer + *tim2 = *div1 * devpriv->i8254_osc_base; /* real convert timer */ - if (usessh & (chnsshfront == 0)) // use BSSH signal + if (usessh & (chnsshfront == 0)) /* use BSSH signal */ if (*div2 < (chans + 2)) *div2 = chans + 2; @@ -1710,13 +1710,13 @@ static void pci9118_calc_divisors(char mode, struct comedi_device * dev, /* ============================================================================== */ -static void start_pacer(struct comedi_device * dev, int mode, unsigned int divisor1, +static void start_pacer(struct comedi_device *dev, int mode, unsigned int divisor1, unsigned int divisor2) { outl(0x74, dev->iobase + PCI9118_CNTCTRL); outl(0xb4, dev->iobase + PCI9118_CNTCTRL); -// outl(0x30, dev->iobase + PCI9118_CNTCTRL); - comedi_udelay(1); +/* outl(0x30, dev->iobase + PCI9118_CNTCTRL); */ + udelay(1); if ((mode == 1) || (mode == 2) || (mode == 4)) { outl(divisor2 & 0xff, dev->iobase + PCI9118_CNT2); @@ -1729,29 +1729,29 @@ static void start_pacer(struct comedi_device * dev, int mode, unsigned int divis /* ============================================================================== */ -static int pci9118_exttrg_add(struct comedi_device * dev, unsigned char source) +static int pci9118_exttrg_add(struct comedi_device *dev, unsigned char source) { if (source > 3) - return -1; // incorrect source + return -1; /* incorrect source */ devpriv->exttrg_users |= (1 << source); devpriv->IntControlReg |= Int_DTrg; outl(devpriv->IntControlReg, dev->iobase + PCI9118_INTCTRL); - outl(inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR) | 0x1f00, devpriv->iobase_a + AMCC_OP_REG_INTCSR); // allow INT in AMCC + outl(inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR) | 0x1f00, devpriv->iobase_a + AMCC_OP_REG_INTCSR); /* allow INT in AMCC */ return 0; } /* ============================================================================== */ -static int pci9118_exttrg_del(struct comedi_device * dev, unsigned char source) +static int pci9118_exttrg_del(struct comedi_device *dev, unsigned char source) { if (source > 3) - return -1; // incorrect source + return -1; /* incorrect source */ devpriv->exttrg_users &= ~(1 << source); - if (!devpriv->exttrg_users) { // shutdown ext trg intterrupts + if (!devpriv->exttrg_users) { /* shutdown ext trg intterrupts */ devpriv->IntControlReg &= ~Int_DTrg; - if (!devpriv->IntControlReg) // all IRQ disabled - outl(inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR) & (~0x00001f00), devpriv->iobase_a + AMCC_OP_REG_INTCSR); // disable int in AMCC + if (!devpriv->IntControlReg) /* all IRQ disabled */ + outl(inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR) & (~0x00001f00), devpriv->iobase_a + AMCC_OP_REG_INTCSR); /* disable int in AMCC */ outl(devpriv->IntControlReg, dev->iobase + PCI9118_INTCTRL); } return 0; @@ -1760,20 +1760,20 @@ static int pci9118_exttrg_del(struct comedi_device * dev, unsigned char source) /* ============================================================================== */ -static int pci9118_ai_cancel(struct comedi_device * dev, struct comedi_subdevice * s) +static int pci9118_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { if (devpriv->usedma) - outl(inl(devpriv->iobase_a + AMCC_OP_REG_MCSR) & (~EN_A2P_TRANSFERS), devpriv->iobase_a + AMCC_OP_REG_MCSR); // stop DMA + outl(inl(devpriv->iobase_a + AMCC_OP_REG_MCSR) & (~EN_A2P_TRANSFERS), devpriv->iobase_a + AMCC_OP_REG_MCSR); /* stop DMA */ pci9118_exttrg_del(dev, EXTTRG_AI); - start_pacer(dev, 0, 0, 0); // stop 8254 counters + start_pacer(dev, 0, 0, 0); /* stop 8254 counters */ devpriv->AdFunctionReg = AdFunction_PDTrg | AdFunction_PETrg; - outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC); // positive triggers, no S&H, no burst, burst stop, no post trigger, no about trigger, trigger stop + outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC); /* positive triggers, no S&H, no burst, burst stop, no post trigger, no about trigger, trigger stop */ devpriv->AdControlReg = 0x00; - outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL); // bipolar, S.E., use 8254, stop 8354, internal trigger, soft trigger, disable INT and DMA + outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL); /* bipolar, S.E., use 8254, stop 8354, internal trigger, soft trigger, disable INT and DMA */ outl(0, dev->iobase + PCI9118_BURST); outl(1, dev->iobase + PCI9118_SCANMOD); - outl(2, dev->iobase + PCI9118_SCANMOD); // reset scan queue - outl(0, dev->iobase + PCI9118_DELFIFO); // flush FIFO + outl(2, dev->iobase + PCI9118_SCANMOD); /* reset scan queue */ + outl(0, dev->iobase + PCI9118_DELFIFO); /* flush FIFO */ devpriv->ai_do = 0; devpriv->usedma = 0; @@ -1787,7 +1787,7 @@ static int pci9118_ai_cancel(struct comedi_device * dev, struct comedi_subdevice devpriv->dma_actbuf = 0; if (!devpriv->IntControlReg) - outl(inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR) | 0x1f00, devpriv->iobase_a + AMCC_OP_REG_INTCSR); // allow INT in AMCC + outl(inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR) | 0x1f00, devpriv->iobase_a + AMCC_OP_REG_INTCSR); /* allow INT in AMCC */ return 0; } @@ -1795,36 +1795,36 @@ static int pci9118_ai_cancel(struct comedi_device * dev, struct comedi_subdevice /* ============================================================================== */ -static int pci9118_reset(struct comedi_device * dev) +static int pci9118_reset(struct comedi_device *dev) { devpriv->IntControlReg = 0; devpriv->exttrg_users = 0; inl(dev->iobase + PCI9118_INTCTRL); - outl(devpriv->IntControlReg, dev->iobase + PCI9118_INTCTRL); // disable interrupts source + outl(devpriv->IntControlReg, dev->iobase + PCI9118_INTCTRL); /* disable interrupts source */ outl(0x30, dev->iobase + PCI9118_CNTCTRL); -// outl(0xb4, dev->iobase + PCI9118_CNTCTRL); - start_pacer(dev, 0, 0, 0); // stop 8254 counters +/* outl(0xb4, dev->iobase + PCI9118_CNTCTRL); */ + start_pacer(dev, 0, 0, 0); /* stop 8254 counters */ devpriv->AdControlReg = 0; - outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL); // bipolar, S.E., use 8254, stop 8354, internal trigger, soft trigger, disable INT and DMA + outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL); /* bipolar, S.E., use 8254, stop 8354, internal trigger, soft trigger, disable INT and DMA */ outl(0, dev->iobase + PCI9118_BURST); outl(1, dev->iobase + PCI9118_SCANMOD); - outl(2, dev->iobase + PCI9118_SCANMOD); // reset scan queue + outl(2, dev->iobase + PCI9118_SCANMOD); /* reset scan queue */ devpriv->AdFunctionReg = AdFunction_PDTrg | AdFunction_PETrg; - outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC); // positive triggers, no S&H, no burst, burst stop, no post trigger, no about trigger, trigger stop + outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC); /* positive triggers, no S&H, no burst, burst stop, no post trigger, no about trigger, trigger stop */ devpriv->ao_data[0] = 2047; devpriv->ao_data[1] = 2047; - outl(devpriv->ao_data[0], dev->iobase + PCI9118_DA1); // reset A/D outs to 0V + outl(devpriv->ao_data[0], dev->iobase + PCI9118_DA1); /* reset A/D outs to 0V */ outl(devpriv->ao_data[1], dev->iobase + PCI9118_DA2); - outl(0, dev->iobase + PCI9118_DO); // reset digi outs to L - comedi_udelay(10); + outl(0, dev->iobase + PCI9118_DO); /* reset digi outs to L */ + udelay(10); inl(dev->iobase + PCI9118_AD_DATA); - outl(0, dev->iobase + PCI9118_DELFIFO); // flush FIFO - outl(0, dev->iobase + PCI9118_INTSRC); // remove INT requests - inl(dev->iobase + PCI9118_ADSTAT); // flush A/D status register - inl(dev->iobase + PCI9118_INTSRC); // flush INT requests + outl(0, dev->iobase + PCI9118_DELFIFO); /* flush FIFO */ + outl(0, dev->iobase + PCI9118_INTSRC); /* remove INT requests */ + inl(dev->iobase + PCI9118_ADSTAT); /* flush A/D status register */ + inl(dev->iobase + PCI9118_INTSRC); /* flush INT requests */ devpriv->AdControlReg = 0; - outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL); // bipolar, S.E., use 8254, stop 8354, internal trigger, soft trigger, disable INT and DMA + outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL); /* bipolar, S.E., use 8254, stop 8354, internal trigger, soft trigger, disable INT and DMA */ devpriv->cnt0_users = 0; devpriv->exttrg_users = 0; @@ -1835,7 +1835,7 @@ static int pci9118_reset(struct comedi_device * dev) /* ============================================================================== */ -static int pci9118_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int pci9118_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; int ret, pages, i; @@ -1848,19 +1848,20 @@ static int pci9118_attach(struct comedi_device * dev, struct comedi_devconfig * unsigned char pci_bus, pci_slot, pci_func; u16 u16w; - rt_printk("comedi%d: adl_pci9118: board=%s", dev->minor, + printk("comedi%d: adl_pci9118: board=%s", dev->minor, this_board->name); opt_bus = it->options[0]; opt_slot = it->options[1]; if (it->options[3] & 1) { - master = 0; // user don't want use bus master + master = 0; /* user don't want use bus master */ } else { master = 1; } - if ((ret = alloc_private(dev, sizeof(struct pci9118_private))) < 0) { - rt_printk(" - Allocation failed!\n"); + ret = alloc_private(dev, sizeof(struct pci9118_private)); + if (ret < 0) { + printk(" - Allocation failed!\n"); return -ENOMEM; } @@ -1889,10 +1890,10 @@ static int pci9118_attach(struct comedi_device * dev, struct comedi_devconfig * if (!pcidev) { if (opt_bus || opt_slot) { - rt_printk(" - Card at b:s %d:%d %s\n", + printk(" - Card at b:s %d:%d %s\n", opt_bus, opt_slot, errstr); } else { - rt_printk(" - Card %s\n", errstr); + printk(" - Card %s\n", errstr); } return -EIO; } @@ -1908,7 +1909,7 @@ static int pci9118_attach(struct comedi_device * dev, struct comedi_devconfig * iobase_a = pci_resource_start(pcidev, 0); iobase_9 = pci_resource_start(pcidev, 2); - rt_printk(", b:s:f=%d:%d:%d, io=0x%4lx, 0x%4lx", pci_bus, pci_slot, + printk(", b:s:f=%d:%d:%d, io=0x%4lx, 0x%4lx", pci_bus, pci_slot, pci_func, iobase_9, iobase_a); dev->iobase = iobase_9; @@ -1920,30 +1921,32 @@ static int pci9118_attach(struct comedi_device * dev, struct comedi_devconfig * pci9118_reset(dev); if (it->options[3] & 2) - irq = 0; // user don't want use IRQ + irq = 0; /* user don't want use IRQ */ if (irq > 0) { - if (comedi_request_irq(irq, interrupt_pci9118, IRQF_SHARED, + if (request_irq(irq, interrupt_pci9118, IRQF_SHARED, "ADLink PCI-9118", dev)) { - rt_printk(", unable to allocate IRQ %d, DISABLING IT", + printk(", unable to allocate IRQ %d, DISABLING IT", irq); irq = 0; /* Can't use IRQ */ } else { - rt_printk(", irq=%u", irq); + printk(", irq=%u", irq); } } else { - rt_printk(", IRQ disabled"); + printk(", IRQ disabled"); } dev->irq = irq; - if (master) { // alloc DMA buffers + if (master) { /* alloc DMA buffers */ devpriv->dma_doublebuf = 0; for (i = 0; i < 2; i++) { - for (pages = 4; pages >= 0; pages--) - if ((devpriv->dmabuf_virt[i] = (short *) - __get_free_pages(GFP_KERNEL, - pages))) + for (pages = 4; pages >= 0; pages--) { + devpriv->dmabuf_virt[i] = + (short *) __get_free_pages(GFP_KERNEL, + pages); + if (devpriv->dmabuf_virt[i]) break; + } if (devpriv->dmabuf_virt[i]) { devpriv->dmabuf_pages[i] = pages; devpriv->dmabuf_size[i] = PAGE_SIZE * pages; @@ -1955,7 +1958,7 @@ static int pci9118_attach(struct comedi_device * dev, struct comedi_devconfig * } } if (!devpriv->dmabuf_virt[0]) { - rt_printk(", Can't allocate DMA buffer, DMA disabled!"); + printk(", Can't allocate DMA buffer, DMA disabled!"); master = 0; } @@ -1964,26 +1967,26 @@ static int pci9118_attach(struct comedi_device * dev, struct comedi_devconfig * } - if ((devpriv->master = master)) { - rt_printk(", bus master"); - } else { - rt_printk(", no bus master"); - } + devpriv->master = master; + if (devpriv->master) + printk(", bus master"); + else + printk(", no bus master"); devpriv->usemux = 0; if (it->options[2] > 0) { devpriv->usemux = it->options[2]; if (devpriv->usemux > 256) - devpriv->usemux = 256; // max 256 channels! + devpriv->usemux = 256; /* max 256 channels! */ if (it->options[4] > 0) if (devpriv->usemux > 128) { - devpriv->usemux = 128; // max 128 channels with softare S&H! + devpriv->usemux = 128; /* max 128 channels with softare S&H! */ } - rt_printk(", ext. mux %d channels", devpriv->usemux); + printk(", ext. mux %d channels", devpriv->usemux); } devpriv->softsshdelay = it->options[4]; - if (devpriv->softsshdelay < 0) { // select sample&hold signal polarity + if (devpriv->softsshdelay < 0) { /* select sample&hold signal polarity */ devpriv->softsshdelay = -devpriv->softsshdelay; devpriv->softsshsample = 0x80; devpriv->softsshhold = 0x00; @@ -1992,12 +1995,13 @@ static int pci9118_attach(struct comedi_device * dev, struct comedi_devconfig * devpriv->softsshhold = 0x80; } - rt_printk(".\n"); + printk(".\n"); pci_read_config_word(devpriv->pcidev, PCI_COMMAND, &u16w); - pci_write_config_word(devpriv->pcidev, PCI_COMMAND, u16w | 64); // Enable parity check for parity error + pci_write_config_word(devpriv->pcidev, PCI_COMMAND, u16w | 64); /* Enable parity check for parity error */ - if ((ret = alloc_subdevices(dev, 4)) < 0) + ret = alloc_subdevices(dev, 4); + if (ret < 0) return ret; s = dev->subdevices + 0; @@ -2052,9 +2056,9 @@ static int pci9118_attach(struct comedi_device * dev, struct comedi_devconfig * s->insn_bits = pci9118_insn_bits_do; devpriv->valid = 1; - devpriv->i8254_osc_base = 250; // 250ns=4MHz - devpriv->ai_maskharderr = 0x10a; // default measure crash condition - if (it->options[5]) // disable some requested + devpriv->i8254_osc_base = 250; /* 250ns=4MHz */ + devpriv->ai_maskharderr = 0x10a; /* default measure crash condition */ + if (it->options[5]) /* disable some requested */ devpriv->ai_maskharderr &= ~it->options[5]; switch (this_board->ai_maxdata) { @@ -2071,13 +2075,13 @@ static int pci9118_attach(struct comedi_device * dev, struct comedi_devconfig * /* ============================================================================== */ -static int pci9118_detach(struct comedi_device * dev) +static int pci9118_detach(struct comedi_device *dev) { if (dev->private) { if (devpriv->valid) pci9118_reset(dev); if (dev->irq) - comedi_free_irq(dev->irq, dev); + free_irq(dev->irq, dev); if (devpriv->pcidev) { if (dev->iobase) { comedi_pci_disable(devpriv->pcidev); diff --git a/drivers/staging/comedi/drivers/adq12b.c b/drivers/staging/comedi/drivers/adq12b.c index 92f62854d6dc..d09d1493a8b7 100644 --- a/drivers/staging/comedi/drivers/adq12b.c +++ b/drivers/staging/comedi/drivers/adq12b.c @@ -81,7 +81,7 @@ If you do not specify any options, they will default to #include "../comedidev.h" -// address scheme (page 2.17 of the manual) +/* address scheme (page 2.17 of the manual) */ #define ADQ12B_SIZE 16 #define ADQ12B_CTREG 0x00 @@ -94,24 +94,24 @@ If you do not specify any options, they will default to #define ADQ12B_CONT2 0x0e #define ADQ12B_COWORD 0x0f -// mask of the bit at STINR to check end of conversion +/* mask of the bit at STINR to check end of conversion */ #define ADQ12B_EOC 0x20 #define TIMEOUT 20 -// available ranges through the PGA gains +/* available ranges through the PGA gains */ static const struct comedi_lrange range_adq12b_ai_bipolar = { 4, { - BIP_RANGE( 5 ), - BIP_RANGE( 2 ), - BIP_RANGE( 1 ), - BIP_RANGE( 0.5 ) + BIP_RANGE(5), + BIP_RANGE(2), + BIP_RANGE(1), + BIP_RANGE(0.5) }}; static const struct comedi_lrange range_adq12b_ai_unipolar = { 4, { - UNI_RANGE( 5 ), - UNI_RANGE( 2 ), - UNI_RANGE( 1 ), - UNI_RANGE( 0.5 ) + UNI_RANGE(5), + UNI_RANGE(2), + UNI_RANGE(1), + UNI_RANGE(0.5) }}; @@ -127,20 +127,20 @@ struct adq12b_board { static const struct adq12b_board adq12b_boards[] = { { - name: "adq12b", - ai_se_chans: 16, - ai_diff_chans: 8, - ai_bits: 12, - di_chans: 5, - do_chans: 8 + .name = "adq12b", + .ai_se_chans = 16, + .ai_diff_chans = 8, + .ai_bits = 12, + .di_chans = 5, + .do_chans = 8 } -// potentially, more adq-based deviced will be added +/* potentially, more adq-based deviced will be added */ /*, - name: "adq12b", - ai_chans: 16, // this is just for reference, hardcoded again later - ai_bits: 12, - di_chans: 8, - do_chans: 5 + .name = "adq12b", + .ai_chans = 16, // this is just for reference, hardcoded again later + .ai_bits = 12, + .di_chans = 8, + .do_chans = 5 }*/ }; @@ -162,7 +162,7 @@ struct adq12b_private { * the board, and also about the kernel module that contains * the device code. */ -static int adq12b_attach(struct comedi_device *dev,struct comedi_devconfig *it); +static int adq12b_attach(struct comedi_device *dev, struct comedi_devconfig *it); static int adq12b_detach(struct comedi_device *dev); static struct comedi_driver driver_adq12b={ driver_name: "adq12b", @@ -171,12 +171,12 @@ static struct comedi_driver driver_adq12b={ detach: adq12b_detach, board_name: &adq12b_boards[0].name, offset: sizeof(struct adq12b_board), - num_names: sizeof(adq12b_boards) / sizeof(struct adq12b_board), + num_names: ARRAY_SIZE(adq12b_boards), }; -static int adq12b_ai_rinsn(struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data); -static int adq12b_di_insn_bits(struct comedi_device *dev,struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data); -static int adq12b_do_insn_bits(struct comedi_device *dev,struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data); +static int adq12b_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); +static int adq12b_di_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); +static int adq12b_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); /* * Attach is called by the Comedi core to configure the driver @@ -184,7 +184,7 @@ static int adq12b_do_insn_bits(struct comedi_device *dev,struct comedi_subdevice * in the driver structure, dev->board_ptr contains that * address. */ -static int adq12b_attach(struct comedi_device *dev,struct comedi_devconfig *it) +static int adq12b_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; unsigned long iobase; @@ -194,7 +194,7 @@ static int adq12b_attach(struct comedi_device *dev,struct comedi_devconfig *it) unipolar = it->options[1]; differential = it->options[2]; - printk("comedi%d: adq12b called with options base=0x%03lx, %s and %s\n",dev->minor, iobase, (unipolar==1)?"unipolar":"bipolar", (differential==1)?"differential":"single-ended"); + printk("comedi%d: adq12b called with options base=0x%03lx, %s and %s\n", dev->minor, iobase, (unipolar==1)?"unipolar":"bipolar", (differential==1) ? "differential" : "single-ended"); /* if no address was specified, try the default 0x300 */ if (iobase == 0) { @@ -219,7 +219,7 @@ static int adq12b_attach(struct comedi_device *dev,struct comedi_devconfig *it) * Allocate the private structure area. alloc_private() is a * convenient macro defined in comedidev.h. */ - if(alloc_private(dev, sizeof(struct adq12b_private)) < 0) + if (alloc_private (dev, sizeof (struct adq12b_private)) < 0) return -ENOMEM; /* fill in devpriv structure */ @@ -236,7 +236,7 @@ static int adq12b_attach(struct comedi_device *dev,struct comedi_devconfig *it) * Allocate the subdevice structures. alloc_subdevice() is a * convenient macro defined in comedidev.h. */ - if(alloc_subdevices(dev, 3)<0) + if (alloc_subdevices (dev, 3)<0) return -ENOMEM; s = dev->subdevices+0; @@ -304,7 +304,7 @@ static int adq12b_detach(struct comedi_device *dev) kfree(devpriv); - printk("comedi%d: adq12b: removed\n",dev->minor); + printk("comedi%d: adq12b: removed\n", dev->minor); return 0; } @@ -314,7 +314,7 @@ static int adq12b_detach(struct comedi_device *dev) * mode. */ -static int adq12b_ai_rinsn(struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) +static int adq12b_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { int n, i; int range, channel; @@ -325,29 +325,29 @@ static int adq12b_ai_rinsn(struct comedi_device *dev,struct comedi_subdevice *s, channel = CR_CHAN(insn->chanspec); if (channel != devpriv->last_channel || range != devpriv->last_range) { outb((range << 4) | channel, dev->iobase + ADQ12B_CTREG); - comedi_udelay(50); /* wait for the mux to settle */ + udelay(50); /* wait for the mux to settle */ } /* trigger conversion */ status = inb(dev->iobase + ADQ12B_ADLOW); /* convert n samples */ - for(n=0; n < insn->n; n++){ + for (n=0; n < insn->n; n++){ /* wait for end of convertion */ i = 0; do { -// comedi_udelay(1); +/* udelay(1); */ status = inb(dev->iobase + ADQ12B_STINR); status = status & ADQ12B_EOC; } while (status == 0 && ++i < TIMEOUT); -// } while (++i < 10); +/* } while (++i < 10); */ /* read data */ hi = inb(dev->iobase + ADQ12B_ADHIG); lo = inb(dev->iobase + ADQ12B_ADLOW); - //rt_printk("debug: chan=%d range=%d status=%d hi=%d lo=%d\n", channel, range, status, hi, lo); + /* printk("debug: chan=%d range=%d status=%d hi=%d lo=%d\n", channel, range, status, hi, lo); */ data[n] = (hi << 8) | lo; } @@ -357,7 +357,7 @@ static int adq12b_ai_rinsn(struct comedi_device *dev,struct comedi_subdevice *s, } -static int adq12b_di_insn_bits(struct comedi_device *dev,struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data) +static int adq12b_di_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { /* only bits 0-4 have information about digital inputs */ @@ -367,7 +367,7 @@ static int adq12b_di_insn_bits(struct comedi_device *dev,struct comedi_subdevice } -static int adq12b_do_insn_bits(struct comedi_device *dev,struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data) +static int adq12b_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { int channel; diff --git a/drivers/staging/comedi/drivers/adv_pci1710.c b/drivers/staging/comedi/drivers/adv_pci1710.c index 29eac743c8e0..0b56c14e2d59 100644 --- a/drivers/staging/comedi/drivers/adv_pci1710.c +++ b/drivers/staging/comedi/drivers/adv_pci1710.c @@ -41,6 +41,8 @@ Configuration options: device will be used. */ +#include + #include "../comedidev.h" #include "comedi_pci.h" @@ -56,12 +58,12 @@ Configuration options: #undef DPRINTK #ifdef PCI171X_EXTDEBUG -#define DPRINTK(fmt, args...) rt_printk(fmt, ## args) +#define DPRINTK(fmt, args...) printk(fmt, ## args) #else #define DPRINTK(fmt, args...) #endif -// hardware types of the cards +/* hardware types of the cards */ #define TYPE_PCI171X 0 #define TYPE_PCI1713 2 #define TYPE_PCI1720 3 @@ -87,12 +89,12 @@ Configuration options: #define PCI171x_CNT2 28 /* R/W: 8254 couter 2 */ #define PCI171x_CNTCTRL 30 /* W: 8254 counter control */ -// upper bits from status register (PCI171x_STATUS) (lower is same woth control reg) +/* upper bits from status register (PCI171x_STATUS) (lower is same woth control reg) */ #define Status_FE 0x0100 /* 1=FIFO is empty */ #define Status_FH 0x0200 /* 1=FIFO is half full */ #define Status_FF 0x0400 /* 1=FIFO is full, fatal error */ #define Status_IRQ 0x0800 /* 1=IRQ occured */ -// bits from control register (PCI171x_CONTROL) +/* bits from control register (PCI171x_CONTROL) */ #define Control_CNT0 0x0040 /* 1=CNT0 have external source, 0=have internal 100kHz source */ #define Control_ONEFH 0x0020 /* 1=IRQ on FIFO is half full, 0=every sample */ #define Control_IRQEN 0x0010 /* 1=enable IRQ */ @@ -100,7 +102,7 @@ Configuration options: #define Control_EXT 0x0004 /* 1=external trigger source */ #define Control_PACER 0x0002 /* 1=enable internal 8254 trigger source */ #define Control_SW 0x0001 /* 1=enable software trigger source */ -// bits from counter control register (PCI171x_CNTCTRL) +/* bits from counter control register (PCI171x_CNTCTRL) */ #define Counter_BCD 0x0001 /* 0 = binary counter, 1 = BCD counter */ #define Counter_M0 0x0002 /* M0-M2 select modes 0-5 */ #define Counter_M1 0x0004 /* 000 = mode 0, 010 = mode 2 ... */ @@ -118,7 +120,7 @@ Configuration options: #define PCI1720_SYNCOUT 9 /* W: D/A synchronized output register */ #define PCI1720_SYNCONT 15 /* R/W: D/A synchronized control */ -// D/A synchronized control (PCI1720_SYNCONT) +/* D/A synchronized control (PCI1720_SYNCONT) */ #define Syncont_SC0 1 /* set synchronous output mode */ static const struct comedi_lrange range_pci1710_3 = { 9, { @@ -182,28 +184,28 @@ static const struct comedi_lrange range_pci171x_da = { 2, { } }; -static int pci1710_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int pci1710_detach(struct comedi_device * dev); +static int pci1710_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int pci1710_detach(struct comedi_device *dev); struct boardtype { - const char *name; // board name + const char *name; /* board name */ int device_id; - int iorange; // I/O range len - char have_irq; // 1=card support IRQ - char cardtype; // 0=1710& co. 2=1713, ... - int n_aichan; // num of A/D chans - int n_aichand; // num of A/D chans in diff mode - int n_aochan; // num of D/A chans - int n_dichan; // num of DI chans - int n_dochan; // num of DO chans - int n_counter; // num of counters - int ai_maxdata; // resolution of A/D - int ao_maxdata; // resolution of D/A - const struct comedi_lrange *rangelist_ai; // rangelist for A/D - const char *rangecode_ai; // range codes for programming - const struct comedi_lrange *rangelist_ao; // rangelist for D/A - unsigned int ai_ns_min; // max sample speed of card v ns - unsigned int fifo_half_size; // size of FIFO/2 + int iorange; /* I/O range len */ + char have_irq; /* 1=card support IRQ */ + char cardtype; /* 0=1710& co. 2=1713, ... */ + int n_aichan; /* num of A/D chans */ + int n_aichand; /* num of A/D chans in diff mode */ + int n_aochan; /* num of D/A chans */ + int n_dichan; /* num of DI chans */ + int n_dochan; /* num of DO chans */ + int n_counter; /* num of counters */ + int ai_maxdata; /* resolution of A/D */ + int ao_maxdata; /* resolution of D/A */ + const struct comedi_lrange *rangelist_ai; /* rangelist for A/D */ + const char *rangecode_ai; /* range codes for programming */ + const struct comedi_lrange *rangelist_ao; /* rangelist for D/A */ + unsigned int ai_ns_min; /* max sample speed of card v ns */ + unsigned int fifo_half_size; /* size of FIFO/2 */ }; static DEFINE_PCI_DEVICE_TABLE(pci1710_pci_table) = { @@ -250,7 +252,7 @@ static const struct boardtype boardtypes[] = { 16, 0, 0, 16, 16, 0, 0x0fff, 0x0000, &range_pci17x1, range_codes_pci17x1, NULL, 10000, 512}, - // dummy entry corresponding to driver name + /* dummy entry corresponding to driver name */ {.name = DRV_NAME}, }; @@ -267,34 +269,34 @@ static struct comedi_driver driver_pci1710 = { }; struct pci1710_private { - struct pci_dev *pcidev; // ptr to PCI device - char valid; // card is usable - char neverending_ai; // we do unlimited AI - unsigned int CntrlReg; // Control register - unsigned int i8254_osc_base; // frequence of onboard oscilator - unsigned int ai_do; // what do AI? 0=nothing, 1 to 4 mode - unsigned int ai_act_scan; // how many scans we finished - unsigned int ai_act_chan; // actual position in actual scan - unsigned int ai_buf_ptr; // data buffer ptr in samples - unsigned char ai_eos; // 1=EOS wake up + struct pci_dev *pcidev; /* ptr to PCI device */ + char valid; /* card is usable */ + char neverending_ai; /* we do unlimited AI */ + unsigned int CntrlReg; /* Control register */ + unsigned int i8254_osc_base; /* frequence of onboard oscilator */ + unsigned int ai_do; /* what do AI? 0=nothing, 1 to 4 mode */ + unsigned int ai_act_scan; /* how many scans we finished */ + unsigned int ai_act_chan; /* actual position in actual scan */ + unsigned int ai_buf_ptr; /* data buffer ptr in samples */ + unsigned char ai_eos; /* 1=EOS wake up */ unsigned char ai_et; unsigned int ai_et_CntrlReg; unsigned int ai_et_MuxVal; unsigned int ai_et_div1, ai_et_div2; - unsigned int act_chanlist[32]; // list of scaned channel - unsigned char act_chanlist_len; // len of scanlist - unsigned char act_chanlist_pos; // actual position in MUX list - unsigned char da_ranges; // copy of D/A outpit range register - unsigned int ai_scans; // len of scanlist - unsigned int ai_n_chan; // how many channels is measured - unsigned int *ai_chanlist; // actaul chanlist - unsigned int ai_flags; // flaglist - unsigned int ai_data_len; // len of data buffer - short *ai_data; // data buffer - unsigned int ai_timer1; // timers + unsigned int act_chanlist[32]; /* list of scaned channel */ + unsigned char act_chanlist_len; /* len of scanlist */ + unsigned char act_chanlist_pos; /* actual position in MUX list */ + unsigned char da_ranges; /* copy of D/A outpit range register */ + unsigned int ai_scans; /* len of scanlist */ + unsigned int ai_n_chan; /* how many channels is measured */ + unsigned int *ai_chanlist; /* actaul chanlist */ + unsigned int ai_flags; /* flaglist */ + unsigned int ai_data_len; /* len of data buffer */ + short *ai_data; /* data buffer */ + unsigned int ai_timer1; /* timers */ unsigned int ai_timer2; - short ao_data[4]; // data output buffer - unsigned int cnt0_write_wait; // after a write, wait for update of the internal state + short ao_data[4]; /* data output buffer */ + unsigned int cnt0_write_wait; /* after a write, wait for update of the internal state */ }; #define devpriv ((struct pci1710_private *)dev->private) @@ -304,16 +306,16 @@ struct pci1710_private { ============================================================================== */ -static int check_channel_list(struct comedi_device * dev, struct comedi_subdevice * s, +static int check_channel_list(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int *chanlist, unsigned int n_chan); -static void setup_channel_list(struct comedi_device * dev, struct comedi_subdevice * s, +static void setup_channel_list(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int *chanlist, unsigned int n_chan, unsigned int seglen); -static void start_pacer(struct comedi_device * dev, int mode, unsigned int divisor1, +static void start_pacer(struct comedi_device *dev, int mode, unsigned int divisor1, unsigned int divisor2); -static int pci1710_reset(struct comedi_device * dev); -static int pci171x_ai_cancel(struct comedi_device * dev, struct comedi_subdevice * s); +static int pci1710_reset(struct comedi_device *dev); +static int pci171x_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s); -static const unsigned int muxonechan[] = { 0x0000, 0x0101, 0x0202, 0x0303, 0x0404, 0x0505, 0x0606, 0x0707, // used for gain list programming +static const unsigned int muxonechan[] = { 0x0000, 0x0101, 0x0202, 0x0303, 0x0404, 0x0505, 0x0606, 0x0707, /* used for gain list programming */ 0x0808, 0x0909, 0x0a0a, 0x0b0b, 0x0c0c, 0x0d0d, 0x0e0e, 0x0f0f, 0x1010, 0x1111, 0x1212, 0x1313, 0x1414, 0x1515, 0x1616, 0x1717, 0x1818, 0x1919, 0x1a1a, 0x1b1b, 0x1c1c, 0x1d1d, 0x1e1e, 0x1f1f @@ -322,8 +324,8 @@ static const unsigned int muxonechan[] = { 0x0000, 0x0101, 0x0202, 0x0303, 0x040 /* ============================================================================== */ -static int pci171x_insn_read_ai(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pci171x_insn_read_ai(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int n, timeout; #ifdef PCI171x_PARANOIDCHECK @@ -332,7 +334,7 @@ static int pci171x_insn_read_ai(struct comedi_device * dev, struct comedi_subdev DPRINTK("adv_pci1710 EDBG: BGN: pci171x_insn_read_ai(...)\n"); devpriv->CntrlReg &= Control_CNT0; - devpriv->CntrlReg |= Control_SW; // set software trigger + devpriv->CntrlReg |= Control_SW; /* set software trigger */ outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); outb(0, dev->iobase + PCI171x_CLRFIFO); outb(0, dev->iobase + PCI171x_CLRINT); @@ -346,7 +348,7 @@ static int pci171x_insn_read_ai(struct comedi_device * dev, struct comedi_subdev outw(0, dev->iobase + PCI171x_SOFTTRG); /* start conversion */ DPRINTK("adv_pci1710 B n=%d ST=%4x\n", n, inw(dev->iobase + PCI171x_STATUS)); - //comedi_udelay(1); + /* udelay(1); */ DPRINTK("adv_pci1710 C n=%d ST=%4x\n", n, inw(dev->iobase + PCI171x_STATUS)); timeout = 100; @@ -390,8 +392,8 @@ static int pci171x_insn_read_ai(struct comedi_device * dev, struct comedi_subdev /* ============================================================================== */ -static int pci171x_insn_write_ao(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pci171x_insn_write_ao(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int n, chan, range, ofs; @@ -421,8 +423,8 @@ static int pci171x_insn_write_ao(struct comedi_device * dev, struct comedi_subde /* ============================================================================== */ -static int pci171x_insn_read_ao(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pci171x_insn_read_ao(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int n, chan; @@ -436,8 +438,8 @@ static int pci171x_insn_read_ao(struct comedi_device * dev, struct comedi_subdev /* ============================================================================== */ -static int pci171x_insn_bits_di(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pci171x_insn_bits_di(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { data[1] = inw(dev->iobase + PCI171x_DI); @@ -447,8 +449,8 @@ static int pci171x_insn_bits_di(struct comedi_device * dev, struct comedi_subdev /* ============================================================================== */ -static int pci171x_insn_bits_do(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pci171x_insn_bits_do(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if (data[0]) { s->state &= ~data[0]; @@ -463,8 +465,8 @@ static int pci171x_insn_bits_do(struct comedi_device * dev, struct comedi_subdev /* ============================================================================== */ -static int pci171x_insn_counter_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pci171x_insn_counter_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { unsigned int msb, lsb, ccntrl; int i; @@ -485,8 +487,8 @@ static int pci171x_insn_counter_read(struct comedi_device * dev, struct comedi_s /* ============================================================================== */ -static int pci171x_insn_counter_write(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pci171x_insn_counter_write(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { uint msb, lsb, ccntrl, status; @@ -512,8 +514,8 @@ static int pci171x_insn_counter_write(struct comedi_device * dev, struct comedi_ /* ============================================================================== */ -static int pci171x_insn_counter_config(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +static int pci171x_insn_counter_config(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { #ifdef unused /* This doesn't work like a normal Comedi counter config */ @@ -548,8 +550,8 @@ static int pci171x_insn_counter_config(struct comedi_device * dev, /* ============================================================================== */ -static int pci1720_insn_write_ao(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pci1720_insn_write_ao(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int n, rangereg, chan; @@ -563,7 +565,7 @@ static int pci1720_insn_write_ao(struct comedi_device * dev, struct comedi_subde for (n = 0; n < insn->n; n++) { outw(data[n], dev->iobase + PCI1720_DA0 + (chan << 1)); - outb(0, dev->iobase + PCI1720_SYNCOUT); // update outputs + outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */ } devpriv->ao_data[chan] = data[n]; @@ -586,14 +588,14 @@ static void interrupt_pci1710_every_sample(void *d) DPRINTK("adv_pci1710 EDBG: BGN: interrupt_pci1710_every_sample(...)\n"); m = inw(dev->iobase + PCI171x_STATUS); if (m & Status_FE) { - rt_printk("comedi%d: A/D FIFO empty (%4x)\n", dev->minor, m); + printk("comedi%d: A/D FIFO empty (%4x)\n", dev->minor, m); pci171x_ai_cancel(dev, s); s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; comedi_event(dev, s); return; } if (m & Status_FF) { - rt_printk + printk ("comedi%d: A/D FIFO Full status (Fatal Error!) (%4x)\n", dev->minor, m); pci171x_ai_cancel(dev, s); @@ -602,7 +604,7 @@ static void interrupt_pci1710_every_sample(void *d) return; } - outb(0, dev->iobase + PCI171x_CLRINT); // clear our INT request + outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */ DPRINTK("FOR "); for (; !(inw(dev->iobase + PCI171x_STATUS) & Status_FE);) { @@ -612,7 +614,7 @@ static void interrupt_pci1710_every_sample(void *d) if (this_board->cardtype != TYPE_PCI1713) if ((sampl & 0xf000) != devpriv->act_chanlist[s->async->cur_chan]) { - rt_printk + printk ("comedi: A/D data dropout: received data from channel %d, expected %d!\n", (sampl & 0xf000) >> 12, (devpriv->act_chanlist[s->async-> @@ -637,11 +639,11 @@ static void interrupt_pci1710_every_sample(void *d) s->async->cur_chan = 0; } - if (s->async->cur_chan == 0) { // one scan done + if (s->async->cur_chan == 0) { /* one scan done */ devpriv->ai_act_scan++; DPRINTK("adv_pci1710 EDBG: EOS1 bic %d bip %d buc %d bup %d\n", s->async->buf_int_count, s->async->buf_int_ptr, s->async->buf_user_count, s->async->buf_user_ptr); DPRINTK("adv_pci1710 EDBG: EOS2\n"); - if ((!devpriv->neverending_ai) && (devpriv->ai_act_scan >= devpriv->ai_scans)) { // all data sampled + if ((!devpriv->neverending_ai) && (devpriv->ai_act_scan >= devpriv->ai_scans)) { /* all data sampled */ pci171x_ai_cancel(dev, s); s->async->events |= COMEDI_CB_EOA; comedi_event(dev, s); @@ -650,7 +652,7 @@ static void interrupt_pci1710_every_sample(void *d) } } - outb(0, dev->iobase + PCI171x_CLRINT); // clear our INT request + outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */ DPRINTK("adv_pci1710 EDBG: END: interrupt_pci1710_every_sample(...)\n"); comedi_event(dev, s); @@ -659,7 +661,7 @@ static void interrupt_pci1710_every_sample(void *d) /* ============================================================================== */ -static int move_block_from_fifo(struct comedi_device * dev, struct comedi_subdevice * s, +static int move_block_from_fifo(struct comedi_device *dev, struct comedi_subdevice *s, int n, int turn) { int i, j; @@ -674,7 +676,7 @@ static int move_block_from_fifo(struct comedi_device * dev, struct comedi_subdev sampl = inw(dev->iobase + PCI171x_AD_DATA); if (this_board->cardtype != TYPE_PCI1713) if ((sampl & 0xf000) != devpriv->act_chanlist[j]) { - rt_printk + printk ("comedi%d: A/D FIFO data dropout: received data from channel %d, expected %d! (%d/%d/%d/%d/%d/%4x)\n", dev->minor, (sampl & 0xf000) >> 12, (devpriv-> @@ -714,7 +716,7 @@ static void interrupt_pci1710_half_fifo(void *d) DPRINTK("adv_pci1710 EDBG: BGN: interrupt_pci1710_half_fifo(...)\n"); m = inw(dev->iobase + PCI171x_STATUS); if (!(m & Status_FH)) { - rt_printk("comedi%d: A/D FIFO not half full! (%4x)\n", + printk("comedi%d: A/D FIFO not half full! (%4x)\n", dev->minor, m); pci171x_ai_cancel(dev, s); s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; @@ -722,7 +724,7 @@ static void interrupt_pci1710_half_fifo(void *d) return; } if (m & Status_FF) { - rt_printk + printk ("comedi%d: A/D FIFO Full status (Fatal Error!) (%4x)\n", dev->minor, m); pci171x_ai_cancel(dev, s); @@ -751,7 +753,7 @@ static void interrupt_pci1710_half_fifo(void *d) comedi_event(dev, s); return; } - outb(0, dev->iobase + PCI171x_CLRINT); // clear our INT request + outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */ DPRINTK("adv_pci1710 EDBG: END: interrupt_pci1710_half_fifo(...)\n"); comedi_event(dev, s); @@ -760,36 +762,36 @@ static void interrupt_pci1710_half_fifo(void *d) /* ============================================================================== */ -static irqreturn_t interrupt_service_pci1710(int irq, void *d PT_REGS_ARG) +static irqreturn_t interrupt_service_pci1710(int irq, void *d) { struct comedi_device *dev = d; DPRINTK("adv_pci1710 EDBG: BGN: interrupt_service_pci1710(%d,...)\n", irq); - if (!dev->attached) // is device attached? - return IRQ_NONE; // no, exit + if (!dev->attached) /* is device attached? */ + return IRQ_NONE; /* no, exit */ - if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ)) // is this interrupt from our board? - return IRQ_NONE; // no, exit + if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ)) /* is this interrupt from our board? */ + return IRQ_NONE; /* no, exit */ DPRINTK("adv_pci1710 EDBG: interrupt_service_pci1710() ST: %4x\n", inw(dev->iobase + PCI171x_STATUS)); - if (devpriv->ai_et) { // Switch from initial TRIG_EXT to TRIG_xxx. + if (devpriv->ai_et) { /* Switch from initial TRIG_EXT to TRIG_xxx. */ devpriv->ai_et = 0; devpriv->CntrlReg &= Control_CNT0; - devpriv->CntrlReg |= Control_SW; // set software trigger + devpriv->CntrlReg |= Control_SW; /* set software trigger */ outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); devpriv->CntrlReg = devpriv->ai_et_CntrlReg; outb(0, dev->iobase + PCI171x_CLRFIFO); outb(0, dev->iobase + PCI171x_CLRINT); outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX); outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); - // start pacer + /* start pacer */ start_pacer(dev, 1, devpriv->ai_et_div1, devpriv->ai_et_div2); return IRQ_HANDLED; } - if (devpriv->ai_eos) { // We use FIFO half full INT or not? + if (devpriv->ai_eos) { /* We use FIFO half full INT or not? */ interrupt_pci1710_every_sample(d); } else { interrupt_pci1710_half_fifo(d); @@ -801,15 +803,15 @@ static irqreturn_t interrupt_service_pci1710(int irq, void *d PT_REGS_ARG) /* ============================================================================== */ -static int pci171x_ai_docmd_and_mode(int mode, struct comedi_device * dev, - struct comedi_subdevice * s) +static int pci171x_ai_docmd_and_mode(int mode, struct comedi_device *dev, + struct comedi_subdevice *s) { unsigned int divisor1, divisor2; unsigned int seglen; DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_docmd_and_mode(%d,...)\n", mode); - start_pacer(dev, -1, 0, 0); // stop pacer + start_pacer(dev, -1, 0, 0); /* stop pacer */ seglen = check_channel_list(dev, s, devpriv->ai_chanlist, devpriv->ai_n_chan); @@ -829,7 +831,7 @@ static int pci171x_ai_docmd_and_mode(int mode, struct comedi_device * dev, devpriv->neverending_ai = 0; devpriv->CntrlReg &= Control_CNT0; - if ((devpriv->ai_flags & TRIG_WAKE_EOS)) { // don't we want wake up every scan? devpriv->ai_eos=1; + if ((devpriv->ai_flags & TRIG_WAKE_EOS)) { /* don't we want wake up every scan? devpriv->ai_eos=1; */ devpriv->ai_eos = 1; } else { devpriv->CntrlReg |= Control_ONEFH; @@ -838,7 +840,7 @@ static int pci171x_ai_docmd_and_mode(int mode, struct comedi_device * dev, if ((devpriv->ai_scans == 0) || (devpriv->ai_scans == -1)) { devpriv->neverending_ai = 1; - } //well, user want neverending + } /* well, user want neverending */ else { devpriv->neverending_ai = 0; } @@ -863,7 +865,7 @@ static int pci171x_ai_docmd_and_mode(int mode, struct comedi_device * dev, DPRINTK("adv_pci1710 EDBG: OSC base=%u div1=%u div2=%u timer=%u\n", devpriv->i8254_osc_base, divisor1, divisor2, devpriv->ai_timer1); outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); if (mode != 2) { - // start pacer + /* start pacer */ start_pacer(dev, mode, divisor1, divisor2); } else { devpriv->ai_et_div1 = divisor1; @@ -884,15 +886,15 @@ static int pci171x_ai_docmd_and_mode(int mode, struct comedi_device * dev, /* ============================================================================== */ -static void pci171x_cmdtest_out(int e, struct comedi_cmd * cmd) +static void pci171x_cmdtest_out(int e, struct comedi_cmd *cmd) { - rt_printk("adv_pci1710 e=%d startsrc=%x scansrc=%x convsrc=%x\n", e, + printk("adv_pci1710 e=%d startsrc=%x scansrc=%x convsrc=%x\n", e, cmd->start_src, cmd->scan_begin_src, cmd->convert_src); - rt_printk("adv_pci1710 e=%d startarg=%d scanarg=%d convarg=%d\n", e, + printk("adv_pci1710 e=%d startarg=%d scanarg=%d convarg=%d\n", e, cmd->start_arg, cmd->scan_begin_arg, cmd->convert_arg); - rt_printk("adv_pci1710 e=%d stopsrc=%x scanend=%x\n", e, cmd->stop_src, + printk("adv_pci1710 e=%d stopsrc=%x scanend=%x\n", e, cmd->stop_src, cmd->scan_end_src); - rt_printk("adv_pci1710 e=%d stoparg=%d scanendarg=%d chanlistlen=%d\n", + printk("adv_pci1710 e=%d stoparg=%d scanendarg=%d chanlistlen=%d\n", e, cmd->stop_arg, cmd->scan_end_arg, cmd->chanlist_len); } #endif @@ -900,8 +902,8 @@ static void pci171x_cmdtest_out(int e, struct comedi_cmd * cmd) /* ============================================================================== */ -static int pci171x_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd) +static int pci171x_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd) { int err = 0; int tmp, divisor1, divisor2; @@ -1055,7 +1057,7 @@ static int pci171x_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevic if (cmd->chanlist) { if (!check_channel_list(dev, s, cmd->chanlist, cmd->chanlist_len)) - return 5; // incorrect channels list + return 5; /* incorrect channels list */ } DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) ret=0\n"); @@ -1065,7 +1067,7 @@ static int pci171x_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevic /* ============================================================================== */ -static int pci171x_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s) +static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { struct comedi_cmd *cmd = &s->async->cmd; @@ -1084,13 +1086,13 @@ static int pci171x_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * devpriv->ai_scans = 0; } - if (cmd->scan_begin_src == TRIG_FOLLOW) { // mode 1, 2, 3 - if (cmd->convert_src == TRIG_TIMER) { // mode 1 and 2 + if (cmd->scan_begin_src == TRIG_FOLLOW) { /* mode 1, 2, 3 */ + if (cmd->convert_src == TRIG_TIMER) { /* mode 1 and 2 */ devpriv->ai_timer1 = cmd->convert_arg; return pci171x_ai_docmd_and_mode(cmd->start_src == TRIG_EXT ? 2 : 1, dev, s); } - if (cmd->convert_src == TRIG_EXT) { // mode 3 + if (cmd->convert_src == TRIG_EXT) { /* mode 3 */ return pci171x_ai_docmd_and_mode(3, dev, s); } } @@ -1104,7 +1106,7 @@ static int pci171x_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * If it's ok, then program scan/gain logic. This works for all cards. */ -static int check_channel_list(struct comedi_device * dev, struct comedi_subdevice * s, +static int check_channel_list(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int *chanlist, unsigned int n_chan) { unsigned int chansegment[32]; @@ -1118,12 +1120,12 @@ static int check_channel_list(struct comedi_device * dev, struct comedi_subdevic } if (n_chan > 1) { - chansegment[0] = chanlist[0]; // first channel is everytime ok - for (i = 1, seglen = 1; i < n_chan; i++, seglen++) { // build part of chanlist - // rt_printk("%d. %d %d\n",i,CR_CHAN(chanlist[i]),CR_RANGE(chanlist[i])); + chansegment[0] = chanlist[0]; /* first channel is everytime ok */ + for (i = 1, seglen = 1; i < n_chan; i++, seglen++) { /* build part of chanlist */ + /* printk("%d. %d %d\n",i,CR_CHAN(chanlist[i]),CR_RANGE(chanlist[i])); */ if (chanlist[0] == chanlist[i]) - break; // we detect loop, this must by finish - if (CR_CHAN(chanlist[i]) & 1) // odd channel cann't by differencial + break; /* we detect loop, this must by finish */ + if (CR_CHAN(chanlist[i]) & 1) /* odd channel cann't by differencial */ if (CR_AREF(chanlist[i]) == AREF_DIFF) { comedi_error(dev, "Odd channel can't be differential input!\n"); @@ -1133,20 +1135,20 @@ static int check_channel_list(struct comedi_device * dev, struct comedi_subdevic (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan; if (CR_AREF(chansegment[i - 1]) == AREF_DIFF) nowmustbechan = (nowmustbechan + 1) % s->n_chan; - if (nowmustbechan != CR_CHAN(chanlist[i])) { // channel list isn't continous :-( - rt_printk + if (nowmustbechan != CR_CHAN(chanlist[i])) { /* channel list isn't continous :-( */ + printk ("channel list must be continous! chanlist[%i]=%d but must be %d or %d!\n", i, CR_CHAN(chanlist[i]), nowmustbechan, CR_CHAN(chanlist[0])); return 0; } - chansegment[i] = chanlist[i]; // well, this is next correct channel in list + chansegment[i] = chanlist[i]; /* well, this is next correct channel in list */ } - for (i = 0, segpos = 0; i < n_chan; i++) { // check whole chanlist - //rt_printk("%d %d=%d %d\n",CR_CHAN(chansegment[i%seglen]),CR_RANGE(chansegment[i%seglen]),CR_CHAN(chanlist[i]),CR_RANGE(chanlist[i])); + for (i = 0, segpos = 0; i < n_chan; i++) { /* check whole chanlist */ + /* printk("%d %d=%d %d\n",CR_CHAN(chansegment[i%seglen]),CR_RANGE(chansegment[i%seglen]),CR_CHAN(chanlist[i]),CR_RANGE(chanlist[i])); */ if (chanlist[i] != chansegment[i % seglen]) { - rt_printk + printk ("bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n", i, CR_CHAN(chansegment[i]), CR_RANGE(chansegment[i]), @@ -1154,7 +1156,7 @@ static int check_channel_list(struct comedi_device * dev, struct comedi_subdevic CR_CHAN(chanlist[i % seglen]), CR_RANGE(chanlist[i % seglen]), CR_AREF(chansegment[i % seglen])); - return 0; // chan/gain list is strange + return 0; /* chan/gain list is strange */ } } } else { @@ -1163,7 +1165,7 @@ static int check_channel_list(struct comedi_device * dev, struct comedi_subdevic return seglen; } -static void setup_channel_list(struct comedi_device * dev, struct comedi_subdevice * s, +static void setup_channel_list(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int *chanlist, unsigned int n_chan, unsigned int seglen) { unsigned int i, range, chanprog; @@ -1174,7 +1176,7 @@ static void setup_channel_list(struct comedi_device * dev, struct comedi_subdevi devpriv->act_chanlist_pos = 0; DPRINTK("SegLen: %d\n", seglen); - for (i = 0; i < seglen; i++) { // store range list to card + for (i = 0; i < seglen; i++) { /* store range list to card */ chanprog = muxonechan[CR_CHAN(chanlist[i])]; outw(chanprog, dev->iobase + PCI171x_MUX); /* select channel */ range = this_board->rangecode_ai[CR_RANGE(chanlist[i])]; @@ -1200,7 +1202,7 @@ static void setup_channel_list(struct comedi_device * dev, struct comedi_subdevi /* ============================================================================== */ -static void start_pacer(struct comedi_device * dev, int mode, unsigned int divisor1, +static void start_pacer(struct comedi_device *dev, int mode, unsigned int divisor1, unsigned int divisor2) { DPRINTK("adv_pci1710 EDBG: BGN: start_pacer(%d,%u,%u)\n", mode, @@ -1220,7 +1222,7 @@ static void start_pacer(struct comedi_device * dev, int mode, unsigned int divis /* ============================================================================== */ -static int pci171x_ai_cancel(struct comedi_device * dev, struct comedi_subdevice * s) +static int pci171x_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cancel(...)\n"); @@ -1229,7 +1231,7 @@ static int pci171x_ai_cancel(struct comedi_device * dev, struct comedi_subdevice devpriv->CntrlReg &= Control_CNT0; devpriv->CntrlReg |= Control_SW; - outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); // reset any operations + outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /* reset any operations */ start_pacer(dev, -1, 0, 0); outb(0, dev->iobase + PCI171x_CLRFIFO); outb(0, dev->iobase + PCI171x_CLRINT); @@ -1249,28 +1251,28 @@ static int pci171x_ai_cancel(struct comedi_device * dev, struct comedi_subdevice /* ============================================================================== */ -static int pci171x_reset(struct comedi_device * dev) +static int pci171x_reset(struct comedi_device *dev) { DPRINTK("adv_pci1710 EDBG: BGN: pci171x_reset(...)\n"); outw(0x30, dev->iobase + PCI171x_CNTCTRL); - devpriv->CntrlReg = Control_SW | Control_CNT0; // Software trigger, CNT0=external - outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); // reset any operations - outb(0, dev->iobase + PCI171x_CLRFIFO); // clear FIFO - outb(0, dev->iobase + PCI171x_CLRINT); // clear INT request - start_pacer(dev, -1, 0, 0); // stop 8254 + devpriv->CntrlReg = Control_SW | Control_CNT0; /* Software trigger, CNT0=external */ + outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /* reset any operations */ + outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */ + outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */ + start_pacer(dev, -1, 0, 0); /* stop 8254 */ devpriv->da_ranges = 0; if (this_board->n_aochan) { - outb(devpriv->da_ranges, dev->iobase + PCI171x_DAREF); // set DACs to 0..5V - outw(0, dev->iobase + PCI171x_DA1); // set DA outputs to 0V + outb(devpriv->da_ranges, dev->iobase + PCI171x_DAREF); /* set DACs to 0..5V */ + outw(0, dev->iobase + PCI171x_DA1); /* set DA outputs to 0V */ devpriv->ao_data[0] = 0x0000; if (this_board->n_aochan > 1) { outw(0, dev->iobase + PCI171x_DA2); devpriv->ao_data[1] = 0x0000; } } - outw(0, dev->iobase + PCI171x_DO); // digital outputs to 0 - outb(0, dev->iobase + PCI171x_CLRFIFO); // clear FIFO - outb(0, dev->iobase + PCI171x_CLRINT); // clear INT request + outw(0, dev->iobase + PCI171x_DO); /* digital outputs to 0 */ + outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */ + outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */ DPRINTK("adv_pci1710 EDBG: END: pci171x_reset(...)\n"); return 0; @@ -1279,17 +1281,17 @@ static int pci171x_reset(struct comedi_device * dev) /* ============================================================================== */ -static int pci1720_reset(struct comedi_device * dev) +static int pci1720_reset(struct comedi_device *dev) { DPRINTK("adv_pci1710 EDBG: BGN: pci1720_reset(...)\n"); - outb(Syncont_SC0, dev->iobase + PCI1720_SYNCONT); // set synchronous output mode + outb(Syncont_SC0, dev->iobase + PCI1720_SYNCONT); /* set synchronous output mode */ devpriv->da_ranges = 0xAA; - outb(devpriv->da_ranges, dev->iobase + PCI1720_RANGE); // set all ranges to +/-5V - outw(0x0800, dev->iobase + PCI1720_DA0); // set outputs to 0V + outb(devpriv->da_ranges, dev->iobase + PCI1720_RANGE); /* set all ranges to +/-5V */ + outw(0x0800, dev->iobase + PCI1720_DA0); /* set outputs to 0V */ outw(0x0800, dev->iobase + PCI1720_DA1); outw(0x0800, dev->iobase + PCI1720_DA2); outw(0x0800, dev->iobase + PCI1720_DA3); - outb(0, dev->iobase + PCI1720_SYNCOUT); // update outputs + outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */ devpriv->ao_data[0] = 0x0800; devpriv->ao_data[1] = 0x0800; devpriv->ao_data[2] = 0x0800; @@ -1301,7 +1303,7 @@ static int pci1720_reset(struct comedi_device * dev) /* ============================================================================== */ -static int pci1710_reset(struct comedi_device * dev) +static int pci1710_reset(struct comedi_device *dev) { DPRINTK("adv_pci1710 EDBG: BGN: pci1710_reset(...)\n"); switch (this_board->cardtype) { @@ -1316,7 +1318,7 @@ static int pci1710_reset(struct comedi_device * dev) /* ============================================================================== */ -static int pci1710_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int pci1710_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; int ret, subdev, n_subdevices; @@ -1329,13 +1331,14 @@ static int pci1710_attach(struct comedi_device * dev, struct comedi_devconfig * int i; int board_index; - rt_printk("comedi%d: adv_pci1710: ", dev->minor); + printk("comedi%d: adv_pci1710: ", dev->minor); opt_bus = it->options[0]; opt_slot = it->options[1]; - if ((ret = alloc_private(dev, sizeof(struct pci1710_private))) < 0) { - rt_printk(" - Allocation failed!\n"); + ret = alloc_private(dev, sizeof(struct pci1710_private)); + if (ret < 0) { + printk(" - Allocation failed!\n"); return -ENOMEM; } @@ -1345,20 +1348,20 @@ static int pci1710_attach(struct comedi_device * dev, struct comedi_devconfig * board_index = this_board - boardtypes; while (NULL != (pcidev = pci_get_device(PCI_VENDOR_ID_ADVANTECH, PCI_ANY_ID, pcidev))) { - if(strcmp(this_board->name, DRV_NAME) == 0) + if (strcmp (this_board->name, DRV_NAME) == 0) { - for(i = 0; i < n_boardtypes; ++i) + for (i = 0; i < n_boardtypes; ++i) { - if(pcidev->device == boardtypes[i].device_id) + if (pcidev->device == boardtypes[i].device_id) { board_index = i; break; } } - if(i == n_boardtypes) continue; + if (i == n_boardtypes) continue; }else { - if(pcidev->device != boardtypes[board_index].device_id) continue; + if (pcidev->device != boardtypes[board_index].device_id) continue; } /* Found matching vendor/device. */ @@ -1376,17 +1379,17 @@ static int pci1710_attach(struct comedi_device * dev, struct comedi_devconfig * errstr = "failed to enable PCI device and request regions!"; continue; } - // fixup board_ptr in case we were using the dummy entry with the driver name + /* fixup board_ptr in case we were using the dummy entry with the driver name */ dev->board_ptr = &boardtypes[board_index]; break; } if (!pcidev) { if (opt_bus || opt_slot) { - rt_printk(" - Card at b:s %d:%d %s\n", + printk(" - Card at b:s %d:%d %s\n", opt_bus, opt_slot, errstr); } else { - rt_printk(" - Card %s\n", errstr); + printk(" - Card %s\n", errstr); } return -EIO; } @@ -1397,7 +1400,7 @@ static int pci1710_attach(struct comedi_device * dev, struct comedi_devconfig * irq = pcidev->irq; iobase = pci_resource_start(pcidev, 2); - rt_printk(", b:s:f=%d:%d:%d, io=0x%4lx", pci_bus, pci_slot, pci_func, + printk(", b:s:f=%d:%d:%d, io=0x%4lx", pci_bus, pci_slot, pci_func, iobase); dev->iobase = iobase; @@ -1417,8 +1420,9 @@ static int pci1710_attach(struct comedi_device * dev, struct comedi_devconfig * if (this_board->n_counter) n_subdevices++; - if ((ret = alloc_subdevices(dev, n_subdevices)) < 0) { - rt_printk(" - Allocation failed!\n"); + ret = alloc_subdevices(dev, n_subdevices); + if (ret < 0) { + printk(" - Allocation failed!\n"); return ret; } @@ -1426,18 +1430,18 @@ static int pci1710_attach(struct comedi_device * dev, struct comedi_devconfig * if (this_board->have_irq) { if (irq) { - if (comedi_request_irq(irq, interrupt_service_pci1710, + if (request_irq(irq, interrupt_service_pci1710, IRQF_SHARED, "Advantech PCI-1710", dev)) { - rt_printk + printk (", unable to allocate IRQ %d, DISABLING IT", irq); irq = 0; /* Can't use IRQ */ } else { - rt_printk(", irq=%u", irq); + printk(", irq=%u", irq); } } else { - rt_printk(", IRQ disabled"); + printk(", IRQ disabled"); } } else { irq = 0; @@ -1467,7 +1471,7 @@ static int pci1710_attach(struct comedi_device * dev, struct comedi_devconfig * s->do_cmdtest = pci171x_ai_cmdtest; s->do_cmd = pci171x_ai_cmd; } - devpriv->i8254_osc_base = 100; // 100ns=10MHz + devpriv->i8254_osc_base = 100; /* 100ns=10MHz */ subdev++; } @@ -1540,14 +1544,14 @@ static int pci1710_attach(struct comedi_device * dev, struct comedi_devconfig * /* ============================================================================== */ -static int pci1710_detach(struct comedi_device * dev) +static int pci1710_detach(struct comedi_device *dev) { if (dev->private) { if (devpriv->valid) pci1710_reset(dev); if (dev->irq) - comedi_free_irq(dev->irq, dev); + free_irq(dev->irq, dev); if (devpriv->pcidev) { if (dev->iobase) { comedi_pci_disable(devpriv->pcidev); diff --git a/drivers/staging/comedi/drivers/adv_pci1723.c b/drivers/staging/comedi/drivers/adv_pci1723.c index 81f7ee18c150..e1994a5290bd 100644 --- a/drivers/staging/comedi/drivers/adv_pci1723.c +++ b/drivers/staging/comedi/drivers/adv_pci1723.c @@ -54,7 +54,7 @@ TODO: #define ADVANTECH_VENDOR 0x13fe /* Advantech PCI vendor ID */ -// hardware types of the cards +/* hardware types of the cards */ #define TYPE_PCI1723 0 #define IORANGE_1723 0x2A @@ -92,7 +92,7 @@ TODO: #define PCI1723_SELECT_CALIBRATION 0x28 /* Select the calibration Ref_V */ -//static unsigned short pci_list_builded=0; /*=1 list of card is know */ +/* static unsigned short pci_list_builded=0; =1 list of card is know */ static const struct comedi_lrange range_pci1723 = { 1, { BIP_RANGE(10) @@ -104,27 +104,27 @@ static const struct comedi_lrange range_pci1723 = { 1, { */ struct pci1723_board { const char *name; - int vendor_id; // PCI vendor a device ID of card + int vendor_id; /* PCI vendor a device ID of card */ int device_id; int iorange; char cardtype; - int n_aochan; // num of D/A chans - int n_diochan; // num of DIO chans - int ao_maxdata; // resolution of D/A - const struct comedi_lrange *rangelist_ao; // rangelist for D/A + int n_aochan; /* num of D/A chans */ + int n_diochan; /* num of DIO chans */ + int ao_maxdata; /* resolution of D/A */ + const struct comedi_lrange *rangelist_ao; /* rangelist for D/A */ }; static const struct pci1723_board boardtypes[] = { { - name: "pci1723", - vendor_id:ADVANTECH_VENDOR, - device_id:0x1723, - iorange: IORANGE_1723, - cardtype:TYPE_PCI1723, - n_aochan:8, - n_diochan:16, - ao_maxdata:0xffff, - rangelist_ao:&range_pci1723, + .name = "pci1723", + .vendor_id = ADVANTECH_VENDOR, + .device_id = 0x1723, + .iorange = IORANGE_1723, + .cardtype = TYPE_PCI1723, + .n_aochan = 8, + .n_diochan = 16, + .ao_maxdata = 0xffff, + .rangelist_ao = &range_pci1723, }, }; @@ -143,26 +143,26 @@ MODULE_DEVICE_TABLE(pci, pci1723_pci_table); * the board, and also about the kernel module that contains * the device code. */ -static int pci1723_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int pci1723_detach(struct comedi_device * dev); +static int pci1723_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int pci1723_detach(struct comedi_device *dev); #define n_boardtypes (sizeof(boardtypes)/sizeof(struct pci1723_board)) static struct comedi_driver driver_pci1723 = { - driver_name:"adv_pci1723", - module:THIS_MODULE, - attach:pci1723_attach, - detach:pci1723_detach, + .driver_name = "adv_pci1723", + .module = THIS_MODULE, + .attach = pci1723_attach, + .detach = pci1723_detach, }; /* this structure is for data unique to this hardware driver. */ struct pci1723_private { - int valid; //card is usable; + int valid; /* card is usable; */ struct pci_dev *pcidev; - unsigned char da_range[8]; // D/A output range for each channel + unsigned char da_range[8]; /* D/A output range for each channel */ - short ao_data[8]; // data output buffer + short ao_data[8]; /* data output buffer */ }; /*the following macro to make it easy to @@ -175,35 +175,35 @@ struct pci1723_private { /* * the pci1723 card reset; */ -static int pci1723_reset(struct comedi_device * dev) +static int pci1723_reset(struct comedi_device *dev) { int i; DPRINTK("adv_pci1723 EDBG: BGN: pci1723_reset(...)\n"); - outw(0x01, dev->iobase + PCI1723_SYN_SET); // set synchronous output mode + outw(0x01, dev->iobase + PCI1723_SYN_SET); /* set synchronous output mode */ for (i = 0; i < 8; i++) { - // set all outputs to 0V + /* set all outputs to 0V */ devpriv->ao_data[i] = 0x8000; outw(devpriv->ao_data[i], dev->iobase + PCI1723_DA(i)); - // set all ranges to +/- 10V + /* set all ranges to +/- 10V */ devpriv->da_range[i] = 0; outw(((devpriv->da_range[i] << 4) | i), PCI1723_RANGE_CALIBRATION_MODE); } - outw(0, dev->iobase + PCI1723_CHANGE_CHA_OUTPUT_TYPE_STROBE); // update ranges - outw(0, dev->iobase + PCI1723_SYN_STROBE); // update outputs + outw(0, dev->iobase + PCI1723_CHANGE_CHA_OUTPUT_TYPE_STROBE); /* update ranges */ + outw(0, dev->iobase + PCI1723_SYN_STROBE); /* update outputs */ - // set asynchronous output mode + /* set asynchronous output mode */ outw(0, dev->iobase + PCI1723_SYN_SET); DPRINTK("adv_pci1723 EDBG: END: pci1723_reset(...)\n"); return 0; } -static int pci1723_insn_read_ao(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pci1723_insn_read_ao(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int n, chan; @@ -218,8 +218,8 @@ static int pci1723_insn_read_ao(struct comedi_device * dev, struct comedi_subdev /* analog data output; */ -static int pci1723_ao_write_winsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pci1723_ao_write_winsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int n, chan; chan = CR_CHAN(insn->chanspec); @@ -238,8 +238,8 @@ static int pci1723_ao_write_winsn(struct comedi_device * dev, struct comedi_subd /* digital i/o config/query */ -static int pci1723_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pci1723_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { unsigned int mask; unsigned int bits; @@ -265,12 +265,12 @@ static int pci1723_dio_insn_config(struct comedi_device * dev, struct comedi_sub return -EINVAL; } - // update hardware DIO mode - dio_mode = 0x0000; // low byte output, high byte output + /* update hardware DIO mode */ + dio_mode = 0x0000; /* low byte output, high byte output */ if ((s->io_bits & 0x00FF) == 0) - dio_mode |= 0x0001; // low byte input + dio_mode |= 0x0001; /* low byte input */ if ((s->io_bits & 0xFF00) == 0) - dio_mode |= 0x0002; // high byte input + dio_mode |= 0x0002; /* high byte input */ outw(dio_mode, dev->iobase + PCI1723_DIGITAL_IO_PORT_SET); return 1; } @@ -278,8 +278,8 @@ static int pci1723_dio_insn_config(struct comedi_device * dev, struct comedi_sub /* digital i/o bits read/write */ -static int pci1723_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pci1723_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if (data[0]) { s->state &= ~data[0]; @@ -294,7 +294,7 @@ static int pci1723_dio_insn_bits(struct comedi_device * dev, struct comedi_subde * Attach is called by the Comedi core to configure the driver * for a pci1723 board. */ -static int pci1723_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int pci1723_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; int ret, subdev, n_subdevices; @@ -304,14 +304,15 @@ static int pci1723_attach(struct comedi_device * dev, struct comedi_devconfig * int opt_bus, opt_slot; const char *errstr; - rt_printk("comedi%d: adv_pci1723: board=%s", dev->minor, + printk("comedi%d: adv_pci1723: board=%s", dev->minor, this_board->name); opt_bus = it->options[0]; opt_slot = it->options[1]; - if ((ret = alloc_private(dev, sizeof(struct pci1723_private))) < 0) { - rt_printk(" - Allocation failed!\n"); + ret = alloc_private(dev, sizeof(struct pci1723_private)); + if (ret < 0) { + printk(" - Allocation failed!\n"); return -ENOMEM; } @@ -341,10 +342,10 @@ static int pci1723_attach(struct comedi_device * dev, struct comedi_devconfig * if (!pcidev) { if (opt_bus || opt_slot) { - rt_printk(" - Card at b:s %d:%d %s\n", + printk(" - Card at b:s %d:%d %s\n", opt_bus, opt_slot, errstr); } else { - rt_printk(" - Card %s\n", errstr); + printk(" - Card %s\n", errstr); } return -EIO; } @@ -354,7 +355,7 @@ static int pci1723_attach(struct comedi_device * dev, struct comedi_devconfig * pci_func = PCI_FUNC(pcidev->devfn); iobase = pci_resource_start(pcidev, 2); - rt_printk(", b:s:f=%d:%d:%d, io=0x%4x", pci_bus, pci_slot, pci_func, + printk(", b:s:f=%d:%d:%d, io=0x%4x", pci_bus, pci_slot, pci_func, iobase); dev->iobase = iobase; @@ -369,8 +370,9 @@ static int pci1723_attach(struct comedi_device * dev, struct comedi_devconfig * if (this_board->n_diochan) n_subdevices++; - if ((ret = alloc_subdevices(dev, n_subdevices)) < 0) { - rt_printk(" - Allocation failed!\n"); + ret = alloc_subdevices(dev, n_subdevices); + if (ret < 0) { + printk(" - Allocation failed!\n"); return ret; } @@ -389,22 +391,22 @@ static int pci1723_attach(struct comedi_device * dev, struct comedi_devconfig * s->insn_write = pci1723_ao_write_winsn; s->insn_read = pci1723_insn_read_ao; - // read DIO config + /* read DIO config */ switch (inw(dev->iobase + PCI1723_DIGITAL_IO_PORT_MODE) & 0x03) { - case 0x00: // low byte output, high byte output + case 0x00: /* low byte output, high byte output */ s->io_bits = 0xFFFF; break; - case 0x01: // low byte input, high byte output + case 0x01: /* low byte input, high byte output */ s->io_bits = 0xFF00; break; - case 0x02: // low byte output, high byte input + case 0x02: /* low byte output, high byte input */ s->io_bits = 0x00FF; break; - case 0x03: // low byte input, high byte input + case 0x03: /* low byte input, high byte input */ s->io_bits = 0x0000; break; } - // read DIO port state + /* read DIO port state */ s->state = inw(dev->iobase + PCI1723_READ_DIGITAL_INPUT_DATA); subdev++; @@ -439,7 +441,7 @@ static int pci1723_attach(struct comedi_device * dev, struct comedi_devconfig * * allocated by _attach(). dev->private and dev->subdevices are * deallocated automatically by the core. */ -static int pci1723_detach(struct comedi_device * dev) +static int pci1723_detach(struct comedi_device *dev) { printk("comedi%d: pci1723: remove\n", dev->minor); diff --git a/drivers/staging/comedi/drivers/adv_pci_dio.c b/drivers/staging/comedi/drivers/adv_pci_dio.c index 2604425c3a0f..5a8c0a3bb2f8 100644 --- a/drivers/staging/comedi/drivers/adv_pci_dio.c +++ b/drivers/staging/comedi/drivers/adv_pci_dio.c @@ -40,7 +40,7 @@ Configuration options: #undef DPRINTK #ifdef PCI_DIO_EXTDEBUG -#define DPRINTK(fmt, args...) rt_printk(fmt, ## args) +#define DPRINTK(fmt, args...) printk(fmt, ## args) #else #define DPRINTK(fmt, args...) #endif @@ -183,8 +183,8 @@ enum hw_io_access { #define OMBCMD_RETRY 0x03 /* 3 times try request before error */ -static int pci_dio_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int pci_dio_detach(struct comedi_device * dev); +static int pci_dio_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int pci_dio_detach(struct comedi_device *dev); struct diosubd_data { int chans; /* num of chans */ @@ -323,10 +323,10 @@ static const struct dio_boardtype boardtypes[] = { #define n_boardtypes (sizeof(boardtypes)/sizeof(struct dio_boardtype)) static struct comedi_driver driver_pci_dio = { - driver_name:"adv_pci_dio", - module:THIS_MODULE, - attach:pci_dio_attach, - detach:pci_dio_detach + .driver_name = "adv_pci_dio", + .module = THIS_MODULE, + .attach = pci_dio_attach, + .detach = pci_dio_detach }; struct pci_dio_private { @@ -357,8 +357,8 @@ static struct pci_dio_private *pci_priv = NULL; /* list of allocated cards */ /* ============================================================================== */ -static int pci_dio_insn_bits_di_b(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pci_dio_insn_bits_di_b(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { const struct diosubd_data *d = (const struct diosubd_data *)s->private; int i; @@ -374,8 +374,8 @@ static int pci_dio_insn_bits_di_b(struct comedi_device * dev, struct comedi_subd /* ============================================================================== */ -static int pci_dio_insn_bits_di_w(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pci_dio_insn_bits_di_w(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { const struct diosubd_data *d = (const struct diosubd_data *)s->private; int i; @@ -390,8 +390,8 @@ static int pci_dio_insn_bits_di_w(struct comedi_device * dev, struct comedi_subd /* ============================================================================== */ -static int pci_dio_insn_bits_do_b(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pci_dio_insn_bits_do_b(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { const struct diosubd_data *d = (const struct diosubd_data *)s->private; int i; @@ -411,8 +411,8 @@ static int pci_dio_insn_bits_do_b(struct comedi_device * dev, struct comedi_subd /* ============================================================================== */ -static int pci_dio_insn_bits_do_w(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pci_dio_insn_bits_do_w(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { const struct diosubd_data *d = (const struct diosubd_data *)s->private; int i; @@ -432,7 +432,7 @@ static int pci_dio_insn_bits_do_w(struct comedi_device * dev, struct comedi_subd /* ============================================================================== */ -static int pci1760_unchecked_mbxrequest(struct comedi_device * dev, +static int pci1760_unchecked_mbxrequest(struct comedi_device *dev, unsigned char *omb, unsigned char *imb, int repeats) { int cnt, tout, ok = 0; @@ -443,14 +443,15 @@ static int pci1760_unchecked_mbxrequest(struct comedi_device * dev, outb(omb[2], dev->iobase + OMB2); outb(omb[3], dev->iobase + OMB3); for (tout = 0; tout < 251; tout++) { - if ((imb[2] = inb(dev->iobase + IMB2)) == omb[2]) { + imb[2] = inb(dev->iobase + IMB2); + if (imb[2] == omb[2]) { imb[0] = inb(dev->iobase + IMB0); imb[1] = inb(dev->iobase + IMB1); imb[3] = inb(dev->iobase + IMB3); ok = 1; break; } - comedi_udelay(1); + udelay(1); } if (ok) return 0; @@ -460,7 +461,7 @@ static int pci1760_unchecked_mbxrequest(struct comedi_device * dev, return -ETIME; } -static int pci1760_clear_imb2(struct comedi_device * dev) +static int pci1760_clear_imb2(struct comedi_device *dev) { unsigned char omb[4] = { 0x0, 0x0, CMD_ClearIMB2, 0x0 }; unsigned char imb[4]; @@ -470,7 +471,7 @@ static int pci1760_clear_imb2(struct comedi_device * dev) return pci1760_unchecked_mbxrequest(dev, omb, imb, OMBCMD_RETRY); } -static int pci1760_mbxrequest(struct comedi_device * dev, +static int pci1760_mbxrequest(struct comedi_device *dev, unsigned char *omb, unsigned char *imb) { if (omb[2] == CMD_ClearIMB2) { @@ -490,8 +491,8 @@ static int pci1760_mbxrequest(struct comedi_device * dev, /* ============================================================================== */ -static int pci1760_insn_bits_di(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pci1760_insn_bits_di(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { data[1] = inb(dev->iobase + IMB3); @@ -501,8 +502,8 @@ static int pci1760_insn_bits_di(struct comedi_device * dev, struct comedi_subdev /* ============================================================================== */ -static int pci1760_insn_bits_do(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pci1760_insn_bits_do(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int ret; unsigned char omb[4] = { @@ -517,7 +518,8 @@ static int pci1760_insn_bits_do(struct comedi_device * dev, struct comedi_subdev s->state &= ~data[0]; s->state |= (data[0] & data[1]); omb[0] = s->state; - if (!(ret = pci1760_mbxrequest(dev, omb, imb))) + ret = pci1760_mbxrequest(dev, omb, imb); + if (!ret) return ret; } data[1] = s->state; @@ -528,8 +530,8 @@ static int pci1760_insn_bits_do(struct comedi_device * dev, struct comedi_subdev /* ============================================================================== */ -static int pci1760_insn_cnt_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pci1760_insn_cnt_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int ret, n; unsigned char omb[4] = { @@ -541,7 +543,8 @@ static int pci1760_insn_cnt_read(struct comedi_device * dev, struct comedi_subde unsigned char imb[4]; for (n = 0; n < insn->n; n++) { - if (!(ret = pci1760_mbxrequest(dev, omb, imb))) + ret = pci1760_mbxrequest(dev, omb, imb); + if (!ret) return ret; data[n] = (imb[1] << 8) + imb[0]; } @@ -552,8 +555,8 @@ static int pci1760_insn_cnt_read(struct comedi_device * dev, struct comedi_subde /* ============================================================================== */ -static int pci1760_insn_cnt_write(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pci1760_insn_cnt_write(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int ret; unsigned char chan = CR_CHAN(insn->chanspec) & 0x07; @@ -567,20 +570,23 @@ static int pci1760_insn_cnt_write(struct comedi_device * dev, struct comedi_subd unsigned char imb[4]; if (devpriv->CntResValue[chan] != (data[0] & 0xffff)) { /* Set reset value if different */ - if (!(ret = pci1760_mbxrequest(dev, omb, imb))) + ret = pci1760_mbxrequest(dev, omb, imb); + if (!ret) return ret; devpriv->CntResValue[chan] = data[0] & 0xffff; } omb[0] = bitmask; /* reset counter to it reset value */ omb[2] = CMD_ResetIDICounters; - if (!(ret = pci1760_mbxrequest(dev, omb, imb))) + ret = pci1760_mbxrequest(dev, omb, imb); + if (!ret) return ret; if (!(bitmask & devpriv->IDICntEnable)) { /* start counter if it don't run */ omb[0] = bitmask; omb[2] = CMD_EnableIDICounters; - if (!(ret = pci1760_mbxrequest(dev, omb, imb))) + ret = pci1760_mbxrequest(dev, omb, imb); + if (!ret) return ret; devpriv->IDICntEnable |= bitmask; } @@ -590,7 +596,7 @@ static int pci1760_insn_cnt_write(struct comedi_device * dev, struct comedi_subd /* ============================================================================== */ -static int pci1760_reset(struct comedi_device * dev) +static int pci1760_reset(struct comedi_device *dev) { int i; unsigned char omb[4] = { 0x00, 0x00, 0x00, 0x00 }; @@ -667,7 +673,7 @@ static int pci1760_reset(struct comedi_device * dev) /* ============================================================================== */ -static int pci_dio_reset(struct comedi_device * dev) +static int pci_dio_reset(struct comedi_device *dev) { DPRINTK("adv_pci_dio EDBG: BGN: pci171x_reset(...)\n"); @@ -750,7 +756,7 @@ static int pci_dio_reset(struct comedi_device * dev) /* ============================================================================== */ -static int pci1760_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int pci1760_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; int subdev = 0; @@ -802,8 +808,8 @@ static int pci1760_attach(struct comedi_device * dev, struct comedi_devconfig * /* ============================================================================== */ -static int pci_dio_add_di(struct comedi_device * dev, struct comedi_subdevice * s, - const struct diosubd_data * d, int subdev) +static int pci_dio_add_di(struct comedi_device *dev, struct comedi_subdevice *s, + const struct diosubd_data *d, int subdev) { s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON | d->specflags; @@ -829,8 +835,8 @@ static int pci_dio_add_di(struct comedi_device * dev, struct comedi_subdevice * /* ============================================================================== */ -static int pci_dio_add_do(struct comedi_device * dev, struct comedi_subdevice * s, - const struct diosubd_data * d, int subdev) +static int pci_dio_add_do(struct comedi_device *dev, struct comedi_subdevice *s, + const struct diosubd_data *d, int subdev) { s->type = COMEDI_SUBD_DO; s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON; @@ -857,7 +863,7 @@ static int pci_dio_add_do(struct comedi_device * dev, struct comedi_subdevice * /* ============================================================================== */ -static int CheckAndAllocCard(struct comedi_device * dev, struct comedi_devconfig * it, +static int CheckAndAllocCard(struct comedi_device *dev, struct comedi_devconfig *it, struct pci_dev *pcidev) { struct pci_dio_private *pr, *prev; @@ -883,17 +889,18 @@ static int CheckAndAllocCard(struct comedi_device * dev, struct comedi_devconfig /* ============================================================================== */ -static int pci_dio_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int pci_dio_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; int ret, subdev, n_subdevices, i, j; unsigned long iobase; struct pci_dev *pcidev; - rt_printk("comedi%d: adv_pci_dio: ", dev->minor); + printk("comedi%d: adv_pci_dio: ", dev->minor); - if ((ret = alloc_private(dev, sizeof(struct pci_dio_private))) < 0) { - rt_printk(", Error: Cann't allocate private memory!\n"); + ret = alloc_private(dev, sizeof(struct pci_dio_private)); + if (ret < 0) { + printk(", Error: Cann't allocate private memory!\n"); return -ENOMEM; } @@ -925,18 +932,18 @@ static int pci_dio_attach(struct comedi_device * dev, struct comedi_devconfig * } if (!dev->board_ptr) { - rt_printk + printk (", Error: Requested type of the card was not found!\n"); return -EIO; } if (comedi_pci_enable(pcidev, driver_pci_dio.driver_name)) { - rt_printk + printk (", Error: Can't enable PCI device and request regions!\n"); return -EIO; } iobase = pci_resource_start(pcidev, this_board->main_pci_region); - rt_printk(", b:s:f=%d:%d:%d, io=0x%4lx", + printk(", b:s:f=%d:%d:%d, io=0x%4lx", pcidev->bus->number, PCI_SLOT(pcidev->devfn), PCI_FUNC(pcidev->devfn), iobase); @@ -959,12 +966,13 @@ static int pci_dio_attach(struct comedi_device * dev, struct comedi_devconfig * n_subdevices++; } - if ((ret = alloc_subdevices(dev, n_subdevices)) < 0) { - rt_printk(", Error: Cann't allocate subdevice memory!\n"); + ret = alloc_subdevices(dev, n_subdevices); + if (ret < 0) { + printk(", Error: Cann't allocate subdevice memory!\n"); return ret; } - rt_printk(".\n"); + printk(".\n"); subdev = 0; @@ -1011,7 +1019,7 @@ static int pci_dio_attach(struct comedi_device * dev, struct comedi_devconfig * /* ============================================================================== */ -static int pci_dio_detach(struct comedi_device * dev) +static int pci_dio_detach(struct comedi_device *dev) { int i, j; struct comedi_subdevice *s; diff --git a/drivers/staging/comedi/drivers/aio_aio12_8.c b/drivers/staging/comedi/drivers/aio_aio12_8.c index b97b4d82611b..72283ae81368 100644 --- a/drivers/staging/comedi/drivers/aio_aio12_8.c +++ b/drivers/staging/comedi/drivers/aio_aio12_8.c @@ -77,7 +77,7 @@ struct aio12_8_boardtype { static const struct aio12_8_boardtype board_types[] = { { - name: "aio_aio12_8"}, + .name = "aio_aio12_8"}, }; #define thisboard ((const struct aio12_8_boardtype *) dev->board_ptr) @@ -88,29 +88,29 @@ struct aio12_8_private { #define devpriv ((struct aio12_8_private *) dev->private) -static int aio_aio12_8_ai_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int aio_aio12_8_ai_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int n; unsigned char control = ADC_MODE_NORMAL | (CR_RANGE(insn->chanspec) << 3) | CR_CHAN(insn->chanspec); - //read status to clear EOC latch + /* read status to clear EOC latch */ inb(dev->iobase + AIO12_8_STATUS); for (n = 0; n < insn->n; n++) { int timeout = 5; - // Setup and start conversion + /* Setup and start conversion */ outb(control, dev->iobase + AIO12_8_ADC); - // Wait for conversion to complete + /* Wait for conversion to complete */ while (timeout && !(inb(dev->iobase + AIO12_8_STATUS) & STATUS_ADC_EOC)) { timeout--; printk("timeout %d\n", timeout); - comedi_udelay(1); + udelay(1); } if (timeout == 0) { comedi_error(dev, "ADC timeout"); @@ -122,8 +122,8 @@ static int aio_aio12_8_ai_read(struct comedi_device * dev, struct comedi_subdevi return n; } -static int aio_aio12_8_ao_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int aio_aio12_8_ao_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i; int val = devpriv->ao_readback[CR_CHAN(insn->chanspec)]; @@ -133,19 +133,19 @@ static int aio_aio12_8_ao_read(struct comedi_device * dev, struct comedi_subdevi return insn->n; } -static int aio_aio12_8_ao_write(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int aio_aio12_8_ao_write(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i; int chan = CR_CHAN(insn->chanspec); unsigned long port = dev->iobase + AIO12_8_DAC_0 + (2 * chan); - //enable DACs + /* enable DACs */ outb(0x01, dev->iobase + DAC_ENABLE); for (i = 0; i < insn->n; i++) { - outb(data[i] & 0xFF, port); // LSB - outb((data[i] >> 8) & 0x0F, port + 1); // MSB + outb(data[i] & 0xFF, port); /* LSB */ + outb((data[i] >> 8) & 0x0F, port + 1); /* MSB */ devpriv->ao_readback[chan] = data[i]; } return insn->n; @@ -161,7 +161,7 @@ static const struct comedi_lrange range_aio_aio12_8 = { } }; -static int aio_aio12_8_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int aio_aio12_8_attach(struct comedi_device *dev, struct comedi_devconfig *it) { int iobase; struct comedi_subdevice *s; @@ -205,7 +205,7 @@ static int aio_aio12_8_attach(struct comedi_device * dev, struct comedi_devconfi return 0; } -static int aio_aio12_8_detach(struct comedi_device * dev) +static int aio_aio12_8_detach(struct comedi_device *dev) { subdev_8255_cleanup(dev, &dev->subdevices[2]); if (dev->iobase) @@ -214,13 +214,13 @@ static int aio_aio12_8_detach(struct comedi_device * dev) } static struct comedi_driver driver_aio_aio12_8 = { - driver_name:"aio_aio12_8", - module:THIS_MODULE, - attach:aio_aio12_8_attach, - detach:aio_aio12_8_detach, - board_name:&board_types[0].name, - num_names:1, - offset:sizeof(struct aio12_8_boardtype), + .driver_name = "aio_aio12_8", + .module = THIS_MODULE, + .attach = aio_aio12_8_attach, + .detach = aio_aio12_8_detach, + .board_name = &board_types[0].name, + .num_names = 1, + .offset = sizeof(struct aio12_8_boardtype), }; COMEDI_INITCLEANUP(driver_aio_aio12_8); diff --git a/drivers/staging/comedi/drivers/aio_iiro_16.c b/drivers/staging/comedi/drivers/aio_iiro_16.c index 9160fdf0ca37..d062f8619b6e 100644 --- a/drivers/staging/comedi/drivers/aio_iiro_16.c +++ b/drivers/staging/comedi/drivers/aio_iiro_16.c @@ -52,9 +52,9 @@ struct aio_iiro_16_board { static const struct aio_iiro_16_board aio_iiro_16_boards[] = { { - name: "aio_iiro_16", - di: 16, - do_: 16}, + .name = "aio_iiro_16", + .di = 16, + .do_ = 16}, }; #define thisboard ((const struct aio_iiro_16_board *) dev->board_ptr) @@ -67,27 +67,27 @@ struct aio_iiro_16_private { #define devpriv ((struct aio_iiro_16_private *) dev->private) -static int aio_iiro_16_attach(struct comedi_device * dev, struct comedi_devconfig * it); +static int aio_iiro_16_attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int aio_iiro_16_detach(struct comedi_device * dev); +static int aio_iiro_16_detach(struct comedi_device *dev); static struct comedi_driver driver_aio_iiro_16 = { - driver_name:"aio_iiro_16", - module:THIS_MODULE, - attach:aio_iiro_16_attach, - detach:aio_iiro_16_detach, - board_name:&aio_iiro_16_boards[0].name, - offset:sizeof(struct aio_iiro_16_board), - num_names:sizeof(aio_iiro_16_boards) / sizeof(struct aio_iiro_16_board), + .driver_name = "aio_iiro_16", + .module = THIS_MODULE, + .attach = aio_iiro_16_attach, + .detach = aio_iiro_16_detach, + .board_name = &aio_iiro_16_boards[0].name, + .offset = sizeof(struct aio_iiro_16_board), + .num_names = ARRAY_SIZE(aio_iiro_16_boards), }; -static int aio_iiro_16_dio_insn_bits_read(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data); +static int aio_iiro_16_dio_insn_bits_read(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -static int aio_iiro_16_dio_insn_bits_write(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data); +static int aio_iiro_16_dio_insn_bits_write(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -static int aio_iiro_16_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int aio_iiro_16_attach(struct comedi_device *dev, struct comedi_devconfig *it) { int iobase; struct comedi_subdevice *s; @@ -132,7 +132,7 @@ static int aio_iiro_16_attach(struct comedi_device * dev, struct comedi_devconfi return 1; } -static int aio_iiro_16_detach(struct comedi_device * dev) +static int aio_iiro_16_detach(struct comedi_device *dev) { printk("comedi%d: aio_iiro_16: remove\n", dev->minor); @@ -142,8 +142,8 @@ static int aio_iiro_16_detach(struct comedi_device * dev) return 0; } -static int aio_iiro_16_dio_insn_bits_write(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +static int aio_iiro_16_dio_insn_bits_write(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { if (insn->n != 2) return -EINVAL; @@ -161,8 +161,8 @@ static int aio_iiro_16_dio_insn_bits_write(struct comedi_device * dev, return 2; } -static int aio_iiro_16_dio_insn_bits_read(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +static int aio_iiro_16_dio_insn_bits_read(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { if (insn->n != 2) return -EINVAL; diff --git a/drivers/staging/comedi/drivers/am9513.h b/drivers/staging/comedi/drivers/am9513.h index f533cf1658cf..73367d6afffe 100644 --- a/drivers/staging/comedi/drivers/am9513.h +++ b/drivers/staging/comedi/drivers/am9513.h @@ -46,33 +46,33 @@ #ifdef Am9513_8BITBUS -#define Am9513_write_register(reg,val) \ +#define Am9513_write_register(reg, val) \ do{ \ Am9513_output_control(reg); \ Am9513_output_data(val>>8); \ Am9513_output_data(val&0xff); \ - }while(0) + }while (0) -#define Am9513_read_register(reg,val) \ +#define Am9513_read_register(reg, val) \ do{ \ Am9513_output_control(reg); \ val=Am9513_input_data()<<8; \ val|=Am9513_input_data(); \ - }while(0) + }while (0) #else /* Am9513_16BITBUS */ -#define Am9513_write_register(reg,val) \ +#define Am9513_write_register(reg, val) \ do{ \ Am9513_output_control(reg); \ Am9513_output_data(val); \ - }while(0) + }while (0) -#define Am9513_read_register(reg,val) \ +#define Am9513_read_register(reg, val) \ do{ \ Am9513_output_control(reg); \ val=Am9513_input_data(); \ - }while(0) + }while (0) #endif diff --git a/drivers/staging/comedi/drivers/amcc_s5933.h b/drivers/staging/comedi/drivers/amcc_s5933.h index aceffce7ef3f..b810d5f3d971 100644 --- a/drivers/staging/comedi/drivers/amcc_s5933.h +++ b/drivers/staging/comedi/drivers/amcc_s5933.h @@ -48,12 +48,12 @@ /****************************************************************************/ #define INTCSR_OUTBOX_BYTE(x) ((x) & 0x3) #define INTCSR_OUTBOX_SELECT(x) (((x) & 0x3) << 2) -#define INTCSR_OUTBOX_EMPTY_INT 0x10 // enable outbox empty interrupt +#define INTCSR_OUTBOX_EMPTY_INT 0x10 /* enable outbox empty interrupt */ #define INTCSR_INBOX_BYTE(x) (((x) & 0x3) << 8) #define INTCSR_INBOX_SELECT(x) (((x) & 0x3) << 10) -#define INTCSR_INBOX_FULL_INT 0x1000 // enable inbox full interrupt -#define INTCSR_INBOX_INTR_STATUS 0x20000 // read, or write clear inbox full interrupt -#define INTCSR_INTR_ASSERTED 0x800000 // read only, interrupt asserted +#define INTCSR_INBOX_FULL_INT 0x1000 /* enable inbox full interrupt */ +#define INTCSR_INBOX_INTR_STATUS 0x20000 /* read, or write clear inbox full interrupt */ +#define INTCSR_INTR_ASSERTED 0x800000 /* read only, interrupt asserted */ /****************************************************************************/ /* AMCC - PCI non-volatile ram command register (byte 3 of master control/status register) */ @@ -153,7 +153,7 @@ #define AINT_IMB_SELECT 0x0000000c #define AINT_IMB_BYTE 0x00000003 -// these are bits from various different registers, needs cleanup XXX +/* these are bits from various different registers, needs cleanup XXX */ /* Enable Bus Mastering */ #define EN_A2P_TRANSFERS 0x00000400 /* FIFO Flag Reset */ diff --git a/drivers/staging/comedi/drivers/amplc_dio200.c b/drivers/staging/comedi/drivers/amplc_dio200.c index 8555e272a861..744680059faf 100644 --- a/drivers/staging/comedi/drivers/amplc_dio200.c +++ b/drivers/staging/comedi/drivers/amplc_dio200.c @@ -205,6 +205,8 @@ is packed into a short value, one bit per requested channel, in the order they appear in the channel list. */ +#include + #include "../comedidev.h" #include "comedi_pci.h" @@ -288,59 +290,59 @@ struct dio200_board { static const struct dio200_board dio200_boards[] = { { - name: "pc212e", - bustype: isa_bustype, - model: pc212e_model, - layout: pc212_layout, + .name = "pc212e", + .bustype = isa_bustype, + .model = pc212e_model, + .layout = pc212_layout, }, { - name: "pc214e", - bustype: isa_bustype, - model: pc214e_model, - layout: pc214_layout, + .name = "pc214e", + .bustype = isa_bustype, + .model = pc214e_model, + .layout = pc214_layout, }, { - name: "pc215e", - bustype: isa_bustype, - model: pc215e_model, - layout: pc215_layout, + .name = "pc215e", + .bustype = isa_bustype, + .model = pc215e_model, + .layout = pc215_layout, }, #ifdef CONFIG_COMEDI_PCI { - name: "pci215", - devid: PCI_DEVICE_ID_AMPLICON_PCI215, - bustype: pci_bustype, - model: pci215_model, - layout: pc215_layout, + .name = "pci215", + .devid = PCI_DEVICE_ID_AMPLICON_PCI215, + .bustype = pci_bustype, + .model = pci215_model, + .layout = pc215_layout, }, #endif { - name: "pc218e", - bustype: isa_bustype, - model: pc218e_model, - layout: pc218_layout, + .name = "pc218e", + .bustype = isa_bustype, + .model = pc218e_model, + .layout = pc218_layout, }, { - name: "pc272e", - bustype: isa_bustype, - model: pc272e_model, - layout: pc272_layout, + .name = "pc272e", + .bustype = isa_bustype, + .model = pc272e_model, + .layout = pc272_layout, }, #ifdef CONFIG_COMEDI_PCI { - name: "pci272", - devid: PCI_DEVICE_ID_AMPLICON_PCI272, - bustype: pci_bustype, - model: pci272_model, - layout: pc272_layout, + .name = "pci272", + .devid = PCI_DEVICE_ID_AMPLICON_PCI272, + .bustype = pci_bustype, + .model = pci272_model, + .layout = pc272_layout, }, #endif #ifdef CONFIG_COMEDI_PCI { - name: DIO200_DRIVER_NAME, - devid: PCI_DEVICE_ID_INVALID, - bustype: pci_bustype, - model: anypci_model, /* wildcard */ + .name = DIO200_DRIVER_NAME, + .devid = PCI_DEVICE_ID_INVALID, + .bustype = pci_bustype, + .model = anypci_model, /* wildcard */ }, #endif }; @@ -365,50 +367,50 @@ struct dio200_layout_struct { static const struct dio200_layout_struct dio200_layouts[] = { [pc212_layout] = { - n_subdevs:6, - sdtype: {sd_8255, sd_8254, sd_8254, sd_8254, + .n_subdevs = 6, + .sdtype = {sd_8255, sd_8254, sd_8254, sd_8254, sd_8254, sd_intr}, - sdinfo: {0x00, 0x08, 0x0C, 0x10, 0x14, + .sdinfo = {0x00, 0x08, 0x0C, 0x10, 0x14, 0x3F}, - has_int_sce:1, - has_clk_gat_sce:1, + .has_int_sce = 1, + .has_clk_gat_sce = 1, }, [pc214_layout] = { - n_subdevs:4, - sdtype: {sd_8255, sd_8255, sd_8254, + .n_subdevs = 4, + .sdtype = {sd_8255, sd_8255, sd_8254, sd_intr}, - sdinfo: {0x00, 0x08, 0x10, 0x01}, - has_int_sce:0, - has_clk_gat_sce:0, + .sdinfo = {0x00, 0x08, 0x10, 0x01}, + .has_int_sce = 0, + .has_clk_gat_sce = 0, }, [pc215_layout] = { - n_subdevs:5, - sdtype: {sd_8255, sd_8255, sd_8254, + .n_subdevs = 5, + .sdtype = {sd_8255, sd_8255, sd_8254, sd_8254, sd_intr}, - sdinfo: {0x00, 0x08, 0x10, 0x14, 0x3F}, - has_int_sce:1, - has_clk_gat_sce:1, + .sdinfo = {0x00, 0x08, 0x10, 0x14, 0x3F}, + .has_int_sce = 1, + .has_clk_gat_sce = 1, }, [pc218_layout] = { - n_subdevs:7, - sdtype: {sd_8254, sd_8254, sd_8255, sd_8254, + .n_subdevs = 7, + .sdtype = {sd_8254, sd_8254, sd_8255, sd_8254, sd_8254, sd_intr}, - sdinfo: {0x00, 0x04, 0x08, 0x0C, 0x10, + .sdinfo = {0x00, 0x04, 0x08, 0x0C, 0x10, 0x14, 0x3F}, - has_int_sce:1, - has_clk_gat_sce:1, + .has_int_sce = 1, + .has_clk_gat_sce = 1, }, [pc272_layout] = { - n_subdevs:4, - sdtype: {sd_8255, sd_8255, sd_8255, + .n_subdevs = 4, + .sdtype = {sd_8255, sd_8255, sd_8255, sd_intr}, - sdinfo: {0x00, 0x08, 0x10, 0x3F}, - has_int_sce:1, - has_clk_gat_sce:0, + .sdinfo = {0x00, 0x08, 0x10, 0x3F}, + .has_int_sce = 1, + .has_clk_gat_sce = 0, }, }; @@ -473,16 +475,16 @@ struct dio200_subdev_intr { * the board, and also about the kernel module that contains * the device code. */ -static int dio200_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int dio200_detach(struct comedi_device * dev); +static int dio200_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int dio200_detach(struct comedi_device *dev); static struct comedi_driver driver_amplc_dio200 = { - driver_name:DIO200_DRIVER_NAME, - module:THIS_MODULE, - attach:dio200_attach, - detach:dio200_detach, - board_name:&dio200_boards[0].name, - offset:sizeof(struct dio200_board), - num_names:sizeof(dio200_boards) / sizeof(struct dio200_board), + .driver_name = DIO200_DRIVER_NAME, + .module = THIS_MODULE, + .attach = dio200_attach, + .detach = dio200_detach, + .board_name = &dio200_boards[0].name, + .offset = sizeof(struct dio200_board), + .num_names = ARRAY_SIZE(dio200_boards), }; #ifdef CONFIG_COMEDI_PCI @@ -497,7 +499,7 @@ COMEDI_INITCLEANUP(driver_amplc_dio200); */ #ifdef CONFIG_COMEDI_PCI static int -dio200_find_pci(struct comedi_device * dev, int bus, int slot, +dio200_find_pci(struct comedi_device *dev, int bus, int slot, struct pci_dev **pci_dev_p) { struct pci_dev *pci_dev = NULL; @@ -572,8 +574,8 @@ dio200_request_region(unsigned minor, unsigned long from, unsigned long extent) * 'insn_bits' function for an 'INTERRUPT' subdevice. */ static int -dio200_subdev_intr_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +dio200_subdev_intr_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { struct dio200_subdev_intr *subpriv = s->private; @@ -591,7 +593,7 @@ dio200_subdev_intr_insn_bits(struct comedi_device * dev, struct comedi_subdevice /* * Called to stop acquisition for an 'INTERRUPT' subdevice. */ -static void dio200_stop_intr(struct comedi_device * dev, struct comedi_subdevice * s) +static void dio200_stop_intr(struct comedi_device *dev, struct comedi_subdevice *s) { struct dio200_subdev_intr *subpriv = s->private; @@ -605,7 +607,7 @@ static void dio200_stop_intr(struct comedi_device * dev, struct comedi_subdevice /* * Called to start acquisition for an 'INTERRUPT' subdevice. */ -static int dio200_start_intr(struct comedi_device * dev, struct comedi_subdevice * s) +static int dio200_start_intr(struct comedi_device *dev, struct comedi_subdevice *s) { unsigned int n; unsigned isn_bits; @@ -641,7 +643,7 @@ static int dio200_start_intr(struct comedi_device * dev, struct comedi_subdevice * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice. */ static int -dio200_inttrig_start_intr(struct comedi_device * dev, struct comedi_subdevice * s, +dio200_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int trignum) { struct dio200_subdev_intr *subpriv; @@ -653,12 +655,12 @@ dio200_inttrig_start_intr(struct comedi_device * dev, struct comedi_subdevice * subpriv = s->private; - comedi_spin_lock_irqsave(&subpriv->spinlock, flags); + spin_lock_irqsave(&subpriv->spinlock, flags); s->async->inttrig = 0; if (subpriv->active) { event = dio200_start_intr(dev, s); } - comedi_spin_unlock_irqrestore(&subpriv->spinlock, flags); + spin_unlock_irqrestore(&subpriv->spinlock, flags); if (event) { comedi_event(dev, s); @@ -671,7 +673,7 @@ dio200_inttrig_start_intr(struct comedi_device * dev, struct comedi_subdevice * * This is called from the interrupt service routine to handle a read * scan on an 'INTERRUPT' subdevice. */ -static int dio200_handle_read_intr(struct comedi_device * dev, struct comedi_subdevice * s) +static int dio200_handle_read_intr(struct comedi_device *dev, struct comedi_subdevice *s) { struct dio200_subdev_intr *subpriv = s->private; unsigned triggered; @@ -682,7 +684,7 @@ static int dio200_handle_read_intr(struct comedi_device * dev, struct comedi_sub triggered = 0; - comedi_spin_lock_irqsave(&subpriv->spinlock, flags); + spin_lock_irqsave(&subpriv->spinlock, flags); oldevents = s->async->events; if (subpriv->has_int_sce) { /* @@ -771,7 +773,7 @@ static int dio200_handle_read_intr(struct comedi_device * dev, struct comedi_sub } } } - comedi_spin_unlock_irqrestore(&subpriv->spinlock, flags); + spin_unlock_irqrestore(&subpriv->spinlock, flags); if (oldevents != s->async->events) { comedi_event(dev, s); @@ -783,16 +785,16 @@ static int dio200_handle_read_intr(struct comedi_device * dev, struct comedi_sub /* * 'cancel' function for an 'INTERRUPT' subdevice. */ -static int dio200_subdev_intr_cancel(struct comedi_device * dev, struct comedi_subdevice * s) +static int dio200_subdev_intr_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { struct dio200_subdev_intr *subpriv = s->private; unsigned long flags; - comedi_spin_lock_irqsave(&subpriv->spinlock, flags); + spin_lock_irqsave(&subpriv->spinlock, flags); if (subpriv->active) { dio200_stop_intr(dev, s); } - comedi_spin_unlock_irqrestore(&subpriv->spinlock, flags); + spin_unlock_irqrestore(&subpriv->spinlock, flags); return 0; } @@ -801,8 +803,8 @@ static int dio200_subdev_intr_cancel(struct comedi_device * dev, struct comedi_s * 'do_cmdtest' function for an 'INTERRUPT' subdevice. */ static int -dio200_subdev_intr_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd) +dio200_subdev_intr_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd) { int err = 0; unsigned int tmp; @@ -907,14 +909,14 @@ dio200_subdev_intr_cmdtest(struct comedi_device * dev, struct comedi_subdevice * /* * 'do_cmd' function for an 'INTERRUPT' subdevice. */ -static int dio200_subdev_intr_cmd(struct comedi_device * dev, struct comedi_subdevice * s) +static int dio200_subdev_intr_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { struct comedi_cmd *cmd = &s->async->cmd; struct dio200_subdev_intr *subpriv = s->private; unsigned long flags; int event = 0; - comedi_spin_lock_irqsave(&subpriv->spinlock, flags); + spin_lock_irqsave(&subpriv->spinlock, flags); subpriv->active = 1; /* Set up end of acquisition. */ @@ -940,7 +942,7 @@ static int dio200_subdev_intr_cmd(struct comedi_device * dev, struct comedi_subd event = dio200_start_intr(dev, s); break; } - comedi_spin_unlock_irqrestore(&subpriv->spinlock, flags); + spin_unlock_irqrestore(&subpriv->spinlock, flags); if (event) { comedi_event(dev, s); @@ -953,7 +955,7 @@ static int dio200_subdev_intr_cmd(struct comedi_device * dev, struct comedi_subd * This function initializes an 'INTERRUPT' subdevice. */ static int -dio200_subdev_intr_init(struct comedi_device * dev, struct comedi_subdevice * s, +dio200_subdev_intr_init(struct comedi_device *dev, struct comedi_subdevice *s, unsigned long iobase, unsigned valid_isns, int has_int_sce) { struct dio200_subdev_intr *subpriv; @@ -998,7 +1000,7 @@ dio200_subdev_intr_init(struct comedi_device * dev, struct comedi_subdevice * s, * This function cleans up an 'INTERRUPT' subdevice. */ static void -dio200_subdev_intr_cleanup(struct comedi_device * dev, struct comedi_subdevice * s) +dio200_subdev_intr_cleanup(struct comedi_device *dev, struct comedi_subdevice *s) { struct dio200_subdev_intr *subpriv = s->private; @@ -1010,7 +1012,7 @@ dio200_subdev_intr_cleanup(struct comedi_device * dev, struct comedi_subdevice * /* * Interrupt service routine. */ -static irqreturn_t dio200_interrupt(int irq, void *d PT_REGS_ARG) +static irqreturn_t dio200_interrupt(int irq, void *d) { struct comedi_device *dev = d; int handled; @@ -1033,8 +1035,8 @@ static irqreturn_t dio200_interrupt(int irq, void *d PT_REGS_ARG) * Handle 'insn_read' for an '8254' counter subdevice. */ static int -dio200_subdev_8254_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +dio200_subdev_8254_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { struct dio200_subdev_8254 *subpriv = s->private; int chan = CR_CHAN(insn->chanspec); @@ -1048,8 +1050,8 @@ dio200_subdev_8254_read(struct comedi_device * dev, struct comedi_subdevice * s, * Handle 'insn_write' for an '8254' counter subdevice. */ static int -dio200_subdev_8254_write(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +dio200_subdev_8254_write(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { struct dio200_subdev_8254 *subpriv = s->private; int chan = CR_CHAN(insn->chanspec); @@ -1063,7 +1065,7 @@ dio200_subdev_8254_write(struct comedi_device * dev, struct comedi_subdevice * s * Set gate source for an '8254' counter subdevice channel. */ static int -dio200_set_gate_src(struct dio200_subdev_8254 * subpriv, unsigned int counter_number, +dio200_set_gate_src(struct dio200_subdev_8254 *subpriv, unsigned int counter_number, unsigned int gate_src) { unsigned char byte; @@ -1086,7 +1088,7 @@ dio200_set_gate_src(struct dio200_subdev_8254 * subpriv, unsigned int counter_nu * Get gate source for an '8254' counter subdevice channel. */ static int -dio200_get_gate_src(struct dio200_subdev_8254 * subpriv, unsigned int counter_number) +dio200_get_gate_src(struct dio200_subdev_8254 *subpriv, unsigned int counter_number) { if (!subpriv->has_clk_gat_sce) return -1; @@ -1100,7 +1102,7 @@ dio200_get_gate_src(struct dio200_subdev_8254 * subpriv, unsigned int counter_nu * Set clock source for an '8254' counter subdevice channel. */ static int -dio200_set_clock_src(struct dio200_subdev_8254 * subpriv, unsigned int counter_number, +dio200_set_clock_src(struct dio200_subdev_8254 *subpriv, unsigned int counter_number, unsigned int clock_src) { unsigned char byte; @@ -1123,8 +1125,8 @@ dio200_set_clock_src(struct dio200_subdev_8254 * subpriv, unsigned int counter_n * Get clock source for an '8254' counter subdevice channel. */ static int -dio200_get_clock_src(struct dio200_subdev_8254 * subpriv, unsigned int counter_number, - unsigned int * period_ns) +dio200_get_clock_src(struct dio200_subdev_8254 *subpriv, unsigned int counter_number, + unsigned int *period_ns) { unsigned clock_src; @@ -1142,8 +1144,8 @@ dio200_get_clock_src(struct dio200_subdev_8254 * subpriv, unsigned int counter_n * Handle 'insn_config' for an '8254' counter subdevice. */ static int -dio200_subdev_8254_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +dio200_subdev_8254_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { struct dio200_subdev_8254 *subpriv = s->private; int ret; @@ -1194,7 +1196,7 @@ dio200_subdev_8254_config(struct comedi_device * dev, struct comedi_subdevice * * offset is the offset to the 8254 chip. */ static int -dio200_subdev_8254_init(struct comedi_device * dev, struct comedi_subdevice * s, +dio200_subdev_8254_init(struct comedi_device *dev, struct comedi_subdevice *s, unsigned long iobase, unsigned offset, int has_clk_gat_sce) { struct dio200_subdev_8254 *subpriv; @@ -1247,7 +1249,7 @@ dio200_subdev_8254_init(struct comedi_device * dev, struct comedi_subdevice * s, * This function cleans up an '8254' counter subdevice. */ static void -dio200_subdev_8254_cleanup(struct comedi_device * dev, struct comedi_subdevice * s) +dio200_subdev_8254_cleanup(struct comedi_device *dev, struct comedi_subdevice *s) { struct dio200_subdev_intr *subpriv = s->private; @@ -1262,7 +1264,7 @@ dio200_subdev_8254_cleanup(struct comedi_device * dev, struct comedi_subdevice * * in the driver structure, dev->board_ptr contains that * address. */ -static int dio200_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int dio200_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; unsigned long iobase = 0; @@ -1280,7 +1282,8 @@ static int dio200_attach(struct comedi_device * dev, struct comedi_devconfig * i printk(KERN_DEBUG "comedi%d: %s: attach\n", dev->minor, DIO200_DRIVER_NAME); - if ((ret = alloc_private(dev, sizeof(struct dio200_private))) < 0) { + ret = alloc_private(dev, sizeof(struct dio200_private)); + if (ret < 0) { printk(KERN_ERR "comedi%d: error! out of memory!\n", dev->minor); return ret; @@ -1299,7 +1302,8 @@ static int dio200_attach(struct comedi_device * dev, struct comedi_devconfig * i slot = it->options[1]; share_irq = 1; - if ((ret = dio200_find_pci(dev, bus, slot, &pci_dev)) < 0) + ret = dio200_find_pci(dev, bus, slot, &pci_dev); + if (ret < 0) return ret; devpriv->pci_dev = pci_dev; break; @@ -1337,7 +1341,9 @@ static int dio200_attach(struct comedi_device * dev, struct comedi_devconfig * i dev->iobase = iobase; layout = thislayout; - if ((ret = alloc_subdevices(dev, layout->n_subdevs)) < 0) { + + ret = alloc_subdevices(dev, layout->n_subdevs); + if (ret < 0) { printk(KERN_ERR "comedi%d: error! out of memory!\n", dev->minor); return ret; @@ -1392,7 +1398,7 @@ static int dio200_attach(struct comedi_device * dev, struct comedi_devconfig * i if (irq) { unsigned long flags = share_irq ? IRQF_SHARED : 0; - if (comedi_request_irq(irq, dio200_interrupt, flags, + if (request_irq(irq, dio200_interrupt, flags, DIO200_DRIVER_NAME, dev) >= 0) { dev->irq = irq; } else { @@ -1429,7 +1435,7 @@ static int dio200_attach(struct comedi_device * dev, struct comedi_devconfig * i * allocated by _attach(). dev->private and dev->subdevices are * deallocated automatically by the core. */ -static int dio200_detach(struct comedi_device * dev) +static int dio200_detach(struct comedi_device *dev) { const struct dio200_layout_struct *layout; unsigned n; @@ -1438,7 +1444,7 @@ static int dio200_detach(struct comedi_device * dev) DIO200_DRIVER_NAME); if (dev->irq) { - comedi_free_irq(dev->irq, dev); + free_irq(dev->irq, dev); } if (dev->subdevices) { layout = thislayout; diff --git a/drivers/staging/comedi/drivers/amplc_pc236.c b/drivers/staging/comedi/drivers/amplc_pc236.c index 2027c75feaca..48d7ccb4a3fe 100644 --- a/drivers/staging/comedi/drivers/amplc_pc236.c +++ b/drivers/staging/comedi/drivers/amplc_pc236.c @@ -27,7 +27,7 @@ Driver: amplc_pc236 Description: Amplicon PC36AT, PCI236 Author: Ian Abbott Devices: [Amplicon] PC36AT (pc36at), PCI236 (pci236 or amplc_pc236) -Updated: Wed, 22 Oct 2008 13:40:03 +0100 +Updated: Wed, 01 Apr 2009 15:41:25 +0100 Status: works Configuration options - PC36AT: @@ -45,13 +45,15 @@ as subdevice 0. Subdevice 1 pretends to be a digital input device, but it always returns 0 when read. However, if you run a command with scan_begin_src=TRIG_EXT, -a rising edge on port C bit 7 acts as an external trigger, which can be +a rising edge on port C bit 3 acts as an external trigger, which can be used to wake up tasks. This is like the comedi_parport device, but the only way to physically disable the interrupt on the PC36AT is to remove the IRQ jumper. If no interrupt is connected, then subdevice 1 is unused. */ +#include + #include "../comedidev.h" #include "comedi_pci.h" @@ -75,19 +77,19 @@ unused. * INTCSR values for PCI236. */ /* Disable interrupt, also clear any interrupt there */ -#define PCI236_INTR_DISABLE ( PLX9052_INTCSR_LI1ENAB_DISABLED \ +#define PCI236_INTR_DISABLE (PLX9052_INTCSR_LI1ENAB_DISABLED \ | PLX9052_INTCSR_LI1POL_HIGH \ | PLX9052_INTCSR_LI2POL_HIGH \ | PLX9052_INTCSR_PCIENAB_DISABLED \ | PLX9052_INTCSR_LI1SEL_EDGE \ - | PLX9052_INTCSR_LI1CLRINT_ASSERTED ) + | PLX9052_INTCSR_LI1CLRINT_ASSERTED) /* Enable interrupt, also clear any interrupt there. */ -#define PCI236_INTR_ENABLE ( PLX9052_INTCSR_LI1ENAB_ENABLED \ +#define PCI236_INTR_ENABLE (PLX9052_INTCSR_LI1ENAB_ENABLED \ | PLX9052_INTCSR_LI1POL_HIGH \ | PLX9052_INTCSR_LI2POL_HIGH \ | PLX9052_INTCSR_PCIENAB_ENABLED \ | PLX9052_INTCSR_LI1SEL_EDGE \ - | PLX9052_INTCSR_LI1CLRINT_ASSERTED ) + | PLX9052_INTCSR_LI1CLRINT_ASSERTED) /* * Board descriptions for Amplicon PC36AT and PCI236. @@ -105,27 +107,27 @@ struct pc236_board { }; static const struct pc236_board pc236_boards[] = { { - name: "pc36at", - fancy_name:"PC36AT", - bustype: isa_bustype, - model: pc36at_model, + .name = "pc36at", + .fancy_name = "PC36AT", + .bustype = isa_bustype, + .model = pc36at_model, }, #ifdef CONFIG_COMEDI_PCI { - name: "pci236", - fancy_name:"PCI236", - devid: PCI_DEVICE_ID_AMPLICON_PCI236, - bustype: pci_bustype, - model: pci236_model, + .name = "pci236", + .fancy_name = "PCI236", + .devid = PCI_DEVICE_ID_AMPLICON_PCI236, + .bustype = pci_bustype, + .model = pci236_model, }, #endif #ifdef CONFIG_COMEDI_PCI { - name: PC236_DRIVER_NAME, - fancy_name:PC236_DRIVER_NAME, - devid: PCI_DEVICE_ID_INVALID, - bustype: pci_bustype, - model: anypci_model, /* wildcard */ + .name = PC236_DRIVER_NAME, + .fancy_name = PC236_DRIVER_NAME, + .devid = PCI_DEVICE_ID_INVALID, + .bustype = pci_bustype, + .model = anypci_model, /* wildcard */ }, #endif }; @@ -165,16 +167,16 @@ struct pc236_private { * the board, and also about the kernel module that contains * the device code. */ -static int pc236_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int pc236_detach(struct comedi_device * dev); +static int pc236_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int pc236_detach(struct comedi_device *dev); static struct comedi_driver driver_amplc_pc236 = { - driver_name:PC236_DRIVER_NAME, - module:THIS_MODULE, - attach:pc236_attach, - detach:pc236_detach, - board_name:&pc236_boards[0].name, - offset:sizeof(struct pc236_board), - num_names:sizeof(pc236_boards) / sizeof(struct pc236_board), + .driver_name = PC236_DRIVER_NAME, + .module = THIS_MODULE, + .attach = pc236_attach, + .detach = pc236_detach, + .board_name = &pc236_boards[0].name, + .offset = sizeof(struct pc236_board), + .num_names = ARRAY_SIZE(pc236_boards), }; #ifdef CONFIG_COMEDI_PCI @@ -185,16 +187,16 @@ COMEDI_INITCLEANUP(driver_amplc_pc236); static int pc236_request_region(unsigned minor, unsigned long from, unsigned long extent); -static void pc236_intr_disable(struct comedi_device * dev); -static void pc236_intr_enable(struct comedi_device * dev); -static int pc236_intr_check(struct comedi_device * dev); -static int pc236_intr_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int pc236_intr_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd); -static int pc236_intr_cmd(struct comedi_device * dev, struct comedi_subdevice * s); -static int pc236_intr_cancel(struct comedi_device * dev, struct comedi_subdevice * s); -static irqreturn_t pc236_interrupt(int irq, void *d PT_REGS_ARG); +static void pc236_intr_disable(struct comedi_device *dev); +static void pc236_intr_enable(struct comedi_device *dev); +static int pc236_intr_check(struct comedi_device *dev); +static int pc236_intr_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int pc236_intr_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd); +static int pc236_intr_cmd(struct comedi_device *dev, struct comedi_subdevice *s); +static int pc236_intr_cancel(struct comedi_device *dev, struct comedi_subdevice *s); +static irqreturn_t pc236_interrupt(int irq, void *d); /* * This function looks for a PCI device matching the requested board name, @@ -202,7 +204,7 @@ static irqreturn_t pc236_interrupt(int irq, void *d PT_REGS_ARG); */ #ifdef CONFIG_COMEDI_PCI static int -pc236_find_pci(struct comedi_device * dev, int bus, int slot, +pc236_find_pci(struct comedi_device *dev, int bus, int slot, struct pci_dev **pci_dev_p) { struct pci_dev *pci_dev = NULL; @@ -264,7 +266,7 @@ pc236_find_pci(struct comedi_device * dev, int bus, int slot, * in the driver structure, dev->board_ptr contains that * address. */ -static int pc236_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int pc236_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; unsigned long iobase = 0; @@ -282,7 +284,8 @@ static int pc236_attach(struct comedi_device * dev, struct comedi_devconfig * it * Allocate the private structure area. alloc_private() is a * convenient macro defined in comedidev.h. */ - if ((ret = alloc_private(dev, sizeof(struct pc236_private))) < 0) { + ret = alloc_private(dev, sizeof(struct pc236_private)); + if (ret < 0) { printk(KERN_ERR "comedi%d: error! out of memory!\n", dev->minor); return ret; @@ -300,7 +303,8 @@ static int pc236_attach(struct comedi_device * dev, struct comedi_devconfig * it slot = it->options[1]; share_irq = 1; - if ((ret = pc236_find_pci(dev, bus, slot, &pci_dev)) < 0) + ret = pc236_find_pci(dev, bus, slot, &pci_dev); + if (ret < 0) return ret; devpriv->pci_dev = pci_dev; break; @@ -321,7 +325,9 @@ static int pc236_attach(struct comedi_device * dev, struct comedi_devconfig * it /* Enable device and reserve I/O spaces. */ #ifdef CONFIG_COMEDI_PCI if (pci_dev) { - if ((ret = comedi_pci_enable(pci_dev, PC236_DRIVER_NAME)) < 0) { + + ret = comedi_pci_enable(pci_dev, PC236_DRIVER_NAME); + if (ret < 0) { printk(KERN_ERR "comedi%d: error! cannot enable PCI device and request regions!\n", dev->minor); @@ -344,7 +350,8 @@ static int pc236_attach(struct comedi_device * dev, struct comedi_devconfig * it * Allocate the subdevice structures. alloc_subdevice() is a * convenient macro defined in comedidev.h. */ - if ((ret = alloc_subdevices(dev, 2)) < 0) { + ret = alloc_subdevices(dev, 2); + if (ret < 0) { printk(KERN_ERR "comedi%d: error! out of memory!\n", dev->minor); return ret; @@ -352,7 +359,8 @@ static int pc236_attach(struct comedi_device * dev, struct comedi_devconfig * it s = dev->subdevices + 0; /* digital i/o subdevice (8255) */ - if ((ret = subdev_8255_init(dev, s, NULL, iobase)) < 0) { + ret = subdev_8255_init(dev, s, NULL, iobase); + if (ret < 0) { printk(KERN_ERR "comedi%d: error! out of memory!\n", dev->minor); return ret; @@ -364,7 +372,7 @@ static int pc236_attach(struct comedi_device * dev, struct comedi_devconfig * it if (irq) { unsigned long flags = share_irq ? IRQF_SHARED : 0; - if (comedi_request_irq(irq, pc236_interrupt, flags, + if (request_irq(irq, pc236_interrupt, flags, PC236_DRIVER_NAME, dev) >= 0) { dev->irq = irq; s->type = COMEDI_SUBD_DI; @@ -405,7 +413,7 @@ static int pc236_attach(struct comedi_device * dev, struct comedi_devconfig * it * allocated by _attach(). dev->private and dev->subdevices are * deallocated automatically by the core. */ -static int pc236_detach(struct comedi_device * dev) +static int pc236_detach(struct comedi_device *dev) { printk(KERN_DEBUG "comedi%d: %s: detach\n", dev->minor, PC236_DRIVER_NAME); @@ -413,7 +421,7 @@ static int pc236_detach(struct comedi_device * dev) pc236_intr_disable(dev); } if (dev->irq) - comedi_free_irq(dev->irq, dev); + free_irq(dev->irq, dev); if (dev->subdevices) { subdev_8255_cleanup(dev, dev->subdevices + 0); } @@ -459,17 +467,17 @@ static int pc236_request_region(unsigned minor, unsigned long from, * configured on subdevice 1) and to physically disable the interrupt * (not possible on the PC36AT, except by removing the IRQ jumper!). */ -static void pc236_intr_disable(struct comedi_device * dev) +static void pc236_intr_disable(struct comedi_device *dev) { unsigned long flags; - comedi_spin_lock_irqsave(&dev->spinlock, flags); + spin_lock_irqsave(&dev->spinlock, flags); devpriv->enable_irq = 0; #ifdef CONFIG_COMEDI_PCI if (devpriv->lcr_iobase) outl(PCI236_INTR_DISABLE, devpriv->lcr_iobase + PLX9052_INTCSR); #endif - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); } /* @@ -477,17 +485,17 @@ static void pc236_intr_disable(struct comedi_device * dev) * configured on subdevice 1) and to physically enable the interrupt * (not possible on the PC36AT, except by (re)connecting the IRQ jumper!). */ -static void pc236_intr_enable(struct comedi_device * dev) +static void pc236_intr_enable(struct comedi_device *dev) { unsigned long flags; - comedi_spin_lock_irqsave(&dev->spinlock, flags); + spin_lock_irqsave(&dev->spinlock, flags); devpriv->enable_irq = 1; #ifdef CONFIG_COMEDI_PCI if (devpriv->lcr_iobase) outl(PCI236_INTR_ENABLE, devpriv->lcr_iobase + PLX9052_INTCSR); #endif - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); } /* @@ -497,12 +505,12 @@ static void pc236_intr_enable(struct comedi_device * dev) * interrupt. * Returns 0 if the interrupt should be ignored. */ -static int pc236_intr_check(struct comedi_device * dev) +static int pc236_intr_check(struct comedi_device *dev) { int retval = 0; unsigned long flags; - comedi_spin_lock_irqsave(&dev->spinlock, flags); + spin_lock_irqsave(&dev->spinlock, flags); if (devpriv->enable_irq) { retval = 1; #ifdef CONFIG_COMEDI_PCI @@ -519,7 +527,7 @@ static int pc236_intr_check(struct comedi_device * dev) } #endif } - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); return retval; } @@ -528,8 +536,8 @@ static int pc236_intr_check(struct comedi_device * dev) * Input from subdevice 1. * Copied from the comedi_parport driver. */ -static int pc236_intr_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pc236_intr_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { data[1] = 0; return 2; @@ -539,8 +547,8 @@ static int pc236_intr_insn(struct comedi_device * dev, struct comedi_subdevice * * Subdevice 1 command test. * Copied from the comedi_parport driver. */ -static int pc236_intr_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd) +static int pc236_intr_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd) { int err = 0; int tmp; @@ -617,7 +625,7 @@ static int pc236_intr_cmdtest(struct comedi_device * dev, struct comedi_subdevic /* * Subdevice 1 command. */ -static int pc236_intr_cmd(struct comedi_device * dev, struct comedi_subdevice * s) +static int pc236_intr_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { pc236_intr_enable(dev); @@ -627,7 +635,7 @@ static int pc236_intr_cmd(struct comedi_device * dev, struct comedi_subdevice * /* * Subdevice 1 cancel command. */ -static int pc236_intr_cancel(struct comedi_device * dev, struct comedi_subdevice * s) +static int pc236_intr_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { pc236_intr_disable(dev); @@ -638,7 +646,7 @@ static int pc236_intr_cancel(struct comedi_device * dev, struct comedi_subdevice * Interrupt service routine. * Based on the comedi_parport driver. */ -static irqreturn_t pc236_interrupt(int irq, void *d PT_REGS_ARG) +static irqreturn_t pc236_interrupt(int irq, void *d) { struct comedi_device *dev = d; struct comedi_subdevice *s = dev->subdevices + 1; diff --git a/drivers/staging/comedi/drivers/amplc_pc263.c b/drivers/staging/comedi/drivers/amplc_pc263.c index 97ac4157adaf..730b67743f0e 100644 --- a/drivers/staging/comedi/drivers/amplc_pc263.c +++ b/drivers/staging/comedi/drivers/amplc_pc263.c @@ -74,27 +74,27 @@ struct pc263_board { }; static const struct pc263_board pc263_boards[] = { { - name: "pc263", - fancy_name:"PC263", - bustype: isa_bustype, - model: pc263_model, + .name = "pc263", + .fancy_name = "PC263", + .bustype = isa_bustype, + .model = pc263_model, }, #ifdef CONFIG_COMEDI_PCI { - name: "pci263", - fancy_name:"PCI263", - devid: PCI_DEVICE_ID_AMPLICON_PCI263, - bustype: pci_bustype, - model: pci263_model, + .name = "pci263", + .fancy_name = "PCI263", + .devid = PCI_DEVICE_ID_AMPLICON_PCI263, + .bustype = pci_bustype, + .model = pci263_model, }, #endif #ifdef CONFIG_COMEDI_PCI { - name: PC263_DRIVER_NAME, - fancy_name:PC263_DRIVER_NAME, - devid: PCI_DEVICE_ID_INVALID, - bustype: pci_bustype, - model: anypci_model, /* wildcard */ + .name = PC263_DRIVER_NAME, + .fancy_name = PC263_DRIVER_NAME, + .devid = PCI_DEVICE_ID_INVALID, + .bustype = pci_bustype, + .model = anypci_model, /* wildcard */ }, #endif }; @@ -132,24 +132,24 @@ struct pc263_private { * the board, and also about the kernel module that contains * the device code. */ -static int pc263_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int pc263_detach(struct comedi_device * dev); +static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int pc263_detach(struct comedi_device *dev); static struct comedi_driver driver_amplc_pc263 = { - driver_name:PC263_DRIVER_NAME, - module:THIS_MODULE, - attach:pc263_attach, - detach:pc263_detach, - board_name:&pc263_boards[0].name, - offset:sizeof(struct pc263_board), - num_names:sizeof(pc263_boards) / sizeof(struct pc263_board), + .driver_name = PC263_DRIVER_NAME, + .module = THIS_MODULE, + .attach = pc263_attach, + .detach = pc263_detach, + .board_name = &pc263_boards[0].name, + .offset = sizeof(struct pc263_board), + .num_names = ARRAY_SIZE(pc263_boards), }; static int pc263_request_region(unsigned minor, unsigned long from, unsigned long extent); -static int pc263_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int pc263_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); +static int pc263_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int pc263_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); /* * This function looks for a PCI device matching the requested board name, @@ -157,7 +157,7 @@ static int pc263_dio_insn_config(struct comedi_device * dev, struct comedi_subde */ #ifdef CONFIG_COMEDI_PCI static int -pc263_find_pci(struct comedi_device * dev, int bus, int slot, +pc263_find_pci(struct comedi_device *dev, int bus, int slot, struct pci_dev **pci_dev_p) { struct pci_dev *pci_dev = NULL; @@ -219,7 +219,7 @@ pc263_find_pci(struct comedi_device * dev, int bus, int slot, * in the driver structure, dev->board_ptr contains that * address. */ -static int pc263_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; unsigned long iobase = 0; @@ -236,7 +236,8 @@ static int pc263_attach(struct comedi_device * dev, struct comedi_devconfig * it * convenient macro defined in comedidev.h. */ #ifdef CONFIG_COMEDI_PCI - if ((ret = alloc_private(dev, sizeof(struct pc263_private))) < 0) { + ret = alloc_private(dev, sizeof(struct pc263_private)); + if (ret < 0) { printk(KERN_ERR "comedi%d: error! out of memory!\n", dev->minor); return ret; @@ -252,7 +253,8 @@ static int pc263_attach(struct comedi_device * dev, struct comedi_devconfig * it bus = it->options[0]; slot = it->options[1]; - if ((ret = pc263_find_pci(dev, bus, slot, &pci_dev)) < 0) + ret = pc263_find_pci(dev, bus, slot, &pci_dev); + if (ret < 0) return ret; devpriv->pci_dev = pci_dev; break; @@ -273,7 +275,8 @@ static int pc263_attach(struct comedi_device * dev, struct comedi_devconfig * it /* Enable device and reserve I/O spaces. */ #ifdef CONFIG_COMEDI_PCI if (pci_dev) { - if ((ret = comedi_pci_enable(pci_dev, PC263_DRIVER_NAME)) < 0) { + ret = comedi_pci_enable(pci_dev, PC263_DRIVER_NAME); + if (ret < 0) { printk(KERN_ERR "comedi%d: error! cannot enable PCI device and request regions!\n", dev->minor); @@ -294,7 +297,8 @@ static int pc263_attach(struct comedi_device * dev, struct comedi_devconfig * it * Allocate the subdevice structures. alloc_subdevice() is a * convenient macro defined in comedidev.h. */ - if ((ret = alloc_subdevices(dev, 1)) < 0) { + ret = alloc_subdevices(dev, 1); + if (ret < 0) { printk(KERN_ERR "comedi%d: error! out of memory!\n", dev->minor); return ret; @@ -303,7 +307,7 @@ static int pc263_attach(struct comedi_device * dev, struct comedi_devconfig * it s = dev->subdevices + 0; /* digital i/o subdevice */ s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_RT; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; s->n_chan = 16; s->maxdata = 1; s->range_table = &range_digital; @@ -337,7 +341,7 @@ static int pc263_attach(struct comedi_device * dev, struct comedi_devconfig * it * allocated by _attach(). dev->private and dev->subdevices are * deallocated automatically by the core. */ -static int pc263_detach(struct comedi_device * dev) +static int pc263_detach(struct comedi_device *dev) { printk(KERN_DEBUG "comedi%d: %s: detach\n", dev->minor, PC263_DRIVER_NAME); @@ -387,8 +391,8 @@ static int pc263_request_region(unsigned minor, unsigned long from, * useful to applications if you implement the insn_bits interface. * This allows packed reading/writing of the DIO channels. The * comedi core can convert between insn_bits and insn_read/write */ -static int pc263_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pc263_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if (insn->n != 2) return -EINVAL; @@ -412,8 +416,8 @@ static int pc263_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevi return 2; } -static int pc263_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pc263_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if (insn->n != 1) return -EINVAL; diff --git a/drivers/staging/comedi/drivers/amplc_pci224.c b/drivers/staging/comedi/drivers/amplc_pci224.c index 770b96648932..d1a64e80cddb 100644 --- a/drivers/staging/comedi/drivers/amplc_pci224.c +++ b/drivers/staging/comedi/drivers/amplc_pci224.c @@ -103,6 +103,8 @@ Caveats: correctly. */ +#include + #include "../comedidev.h" #include "comedi_pci.h" @@ -356,23 +358,23 @@ struct pci224_board { static const struct pci224_board pci224_boards[] = { { - name: "pci224", - devid: PCI_DEVICE_ID_AMPLICON_PCI224, - model: pci224_model, - ao_chans:16, - ao_bits: 12, + .name = "pci224", + .devid = PCI_DEVICE_ID_AMPLICON_PCI224, + .model = pci224_model, + .ao_chans = 16, + .ao_bits = 12, }, { - name: "pci234", - devid: PCI_DEVICE_ID_AMPLICON_PCI234, - model: pci234_model, - ao_chans:4, - ao_bits: 16, + .name = "pci234", + .devid = PCI_DEVICE_ID_AMPLICON_PCI234, + .model = pci234_model, + .ao_chans = 4, + .ao_bits = 16, }, { - name: DRIVER_NAME, - devid: PCI_DEVICE_ID_INVALID, - model: any_model, /* wildcard */ + .name = DRIVER_NAME, + .devid = PCI_DEVICE_ID_INVALID, + .model = any_model, /* wildcard */ }, }; @@ -426,16 +428,16 @@ struct pci224_private { * the board, and also about the kernel module that contains * the device code. */ -static int pci224_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int pci224_detach(struct comedi_device * dev); +static int pci224_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int pci224_detach(struct comedi_device *dev); static struct comedi_driver driver_amplc_pci224 = { - driver_name:DRIVER_NAME, - module:THIS_MODULE, - attach:pci224_attach, - detach:pci224_detach, - board_name:&pci224_boards[0].name, - offset:sizeof(struct pci224_board), - num_names:sizeof(pci224_boards) / sizeof(struct pci224_board), + .driver_name = DRIVER_NAME, + .module = THIS_MODULE, + .attach = pci224_attach, + .detach = pci224_detach, + .board_name = &pci224_boards[0].name, + .offset = sizeof(struct pci224_board), + .num_names = ARRAY_SIZE(pci224_boards), }; COMEDI_PCI_INITCLEANUP(driver_amplc_pci224, pci224_pci_table); @@ -444,7 +446,7 @@ COMEDI_PCI_INITCLEANUP(driver_amplc_pci224, pci224_pci_table); * Called from the 'insn_write' function to perform a single write. */ static void -pci224_ao_set_data(struct comedi_device * dev, int chan, int range, unsigned int data) +pci224_ao_set_data(struct comedi_device *dev, int chan, int range, unsigned int data) { unsigned short mangled; @@ -477,8 +479,8 @@ pci224_ao_set_data(struct comedi_device * dev, int chan, int range, unsigned int * 'insn_write' function for AO subdevice. */ static int -pci224_ao_insn_write(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +pci224_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i; int chan, range; @@ -504,8 +506,8 @@ pci224_ao_insn_write(struct comedi_device * dev, struct comedi_subdevice * s, * command. */ static int -pci224_ao_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +pci224_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i; int chan; @@ -532,7 +534,7 @@ pci224_cascade_ns_to_timer(int osc_base, unsigned int *d1, unsigned int *d2, /* * Kills a command running on the AO subdevice. */ -static void pci224_ao_stop(struct comedi_device * dev, struct comedi_subdevice * s) +static void pci224_ao_stop(struct comedi_device *dev, struct comedi_subdevice *s) { unsigned long flags; @@ -540,7 +542,7 @@ static void pci224_ao_stop(struct comedi_device * dev, struct comedi_subdevice * return; } - comedi_spin_lock_irqsave(&devpriv->ao_spinlock, flags); + spin_lock_irqsave(&devpriv->ao_spinlock, flags); /* Kill the interrupts. */ devpriv->intsce = 0; outb(0, devpriv->iobase1 + PCI224_INT_SCE); @@ -556,10 +558,10 @@ static void pci224_ao_stop(struct comedi_device * dev, struct comedi_subdevice * * routine. */ while (devpriv->intr_running && devpriv->intr_cpuid != THISCPU) { - comedi_spin_unlock_irqrestore(&devpriv->ao_spinlock, flags); - comedi_spin_lock_irqsave(&devpriv->ao_spinlock, flags); + spin_unlock_irqrestore(&devpriv->ao_spinlock, flags); + spin_lock_irqsave(&devpriv->ao_spinlock, flags); } - comedi_spin_unlock_irqrestore(&devpriv->ao_spinlock, flags); + spin_unlock_irqrestore(&devpriv->ao_spinlock, flags); /* Reconfigure DAC for insn_write usage. */ outw(0, dev->iobase + PCI224_DACCEN); /* Disable channels. */ devpriv->daccon = COMBINE(devpriv->daccon, @@ -572,7 +574,7 @@ static void pci224_ao_stop(struct comedi_device * dev, struct comedi_subdevice * /* * Handles start of acquisition for the AO subdevice. */ -static void pci224_ao_start(struct comedi_device * dev, struct comedi_subdevice * s) +static void pci224_ao_start(struct comedi_device *dev, struct comedi_subdevice *s) { struct comedi_cmd *cmd = &s->async->cmd; unsigned long flags; @@ -585,21 +587,21 @@ static void pci224_ao_start(struct comedi_device * dev, struct comedi_subdevice comedi_event(dev, s); } else { /* Enable interrupts. */ - comedi_spin_lock_irqsave(&devpriv->ao_spinlock, flags); + spin_lock_irqsave(&devpriv->ao_spinlock, flags); if (cmd->stop_src == TRIG_EXT) { devpriv->intsce = PCI224_INTR_EXT | PCI224_INTR_DAC; } else { devpriv->intsce = PCI224_INTR_DAC; } outb(devpriv->intsce, devpriv->iobase1 + PCI224_INT_SCE); - comedi_spin_unlock_irqrestore(&devpriv->ao_spinlock, flags); + spin_unlock_irqrestore(&devpriv->ao_spinlock, flags); } } /* * Handles interrupts from the DAC FIFO. */ -static void pci224_ao_handle_fifo(struct comedi_device * dev, struct comedi_subdevice * s) +static void pci224_ao_handle_fifo(struct comedi_device *dev, struct comedi_subdevice *s) { struct comedi_cmd *cmd = &s->async->cmd; unsigned int num_scans; @@ -653,7 +655,7 @@ static void pci224_ao_handle_fifo(struct comedi_device * dev, struct comedi_subd /* Nothing left to put in the FIFO. */ pci224_ao_stop(dev, s); s->async->events |= COMEDI_CB_OVERFLOW; - rt_printk(KERN_ERR "comedi%d: " + printk(KERN_ERR "comedi%d: " "AO buffer underrun\n", dev->minor); } } @@ -728,7 +730,7 @@ static void pci224_ao_handle_fifo(struct comedi_device * dev, struct comedi_subd * Internal trigger function to start acquisition on AO subdevice. */ static int -pci224_ao_inttrig_start(struct comedi_device * dev, struct comedi_subdevice * s, +pci224_ao_inttrig_start(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int trignum) { if (trignum != 0) @@ -748,7 +750,7 @@ pci224_ao_inttrig_start(struct comedi_device * dev, struct comedi_subdevice * s, * 'do_cmdtest' function for AO subdevice. */ static int -pci224_ao_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, struct comedi_cmd * cmd) +pci224_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { int err = 0; unsigned int tmp; @@ -1015,7 +1017,7 @@ pci224_ao_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, struc /* * 'do_cmd' function for AO subdevice. */ -static int pci224_ao_cmd(struct comedi_device * dev, struct comedi_subdevice * s) +static int pci224_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { struct comedi_cmd *cmd = &s->async->cmd; int range; @@ -1153,16 +1155,16 @@ static int pci224_ao_cmd(struct comedi_device * dev, struct comedi_subdevice * s */ switch (cmd->start_src) { case TRIG_INT: - comedi_spin_lock_irqsave(&devpriv->ao_spinlock, flags); + spin_lock_irqsave(&devpriv->ao_spinlock, flags); s->async->inttrig = &pci224_ao_inttrig_start; - comedi_spin_unlock_irqrestore(&devpriv->ao_spinlock, flags); + spin_unlock_irqrestore(&devpriv->ao_spinlock, flags); break; case TRIG_EXT: /* Enable external interrupt trigger to start acquisition. */ - comedi_spin_lock_irqsave(&devpriv->ao_spinlock, flags); + spin_lock_irqsave(&devpriv->ao_spinlock, flags); devpriv->intsce |= PCI224_INTR_EXT; outb(devpriv->intsce, devpriv->iobase1 + PCI224_INT_SCE); - comedi_spin_unlock_irqrestore(&devpriv->ao_spinlock, flags); + spin_unlock_irqrestore(&devpriv->ao_spinlock, flags); break; } @@ -1172,7 +1174,7 @@ static int pci224_ao_cmd(struct comedi_device * dev, struct comedi_subdevice * s /* * 'cancel' function for AO subdevice. */ -static int pci224_ao_cancel(struct comedi_device * dev, struct comedi_subdevice * s) +static int pci224_ao_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { pci224_ao_stop(dev, s); return 0; @@ -1182,7 +1184,7 @@ static int pci224_ao_cancel(struct comedi_device * dev, struct comedi_subdevice * 'munge' data for AO command. */ static void -pci224_ao_munge(struct comedi_device * dev, struct comedi_subdevice * s, void *data, +pci224_ao_munge(struct comedi_device *dev, struct comedi_subdevice *s, void *data, unsigned int num_bytes, unsigned int chan_index) { struct comedi_async *async = s->async; @@ -1212,7 +1214,7 @@ pci224_ao_munge(struct comedi_device * dev, struct comedi_subdevice * s, void *d /* * Interrupt handler. */ -static irqreturn_t pci224_interrupt(int irq, void *d PT_REGS_ARG) +static irqreturn_t pci224_interrupt(int irq, void *d) { struct comedi_device *dev = d; struct comedi_subdevice *s = &dev->subdevices[0]; @@ -1225,14 +1227,14 @@ static irqreturn_t pci224_interrupt(int irq, void *d PT_REGS_ARG) intstat = inb(devpriv->iobase1 + PCI224_INT_SCE) & 0x3F; if (intstat) { retval = 1; - comedi_spin_lock_irqsave(&devpriv->ao_spinlock, flags); + spin_lock_irqsave(&devpriv->ao_spinlock, flags); valid_intstat = devpriv->intsce & intstat; /* Temporarily disable interrupt sources. */ curenab = devpriv->intsce & ~intstat; outb(curenab, devpriv->iobase1 + PCI224_INT_SCE); devpriv->intr_running = 1; devpriv->intr_cpuid = THISCPU; - comedi_spin_unlock_irqrestore(&devpriv->ao_spinlock, flags); + spin_unlock_irqrestore(&devpriv->ao_spinlock, flags); if (valid_intstat != 0) { cmd = &s->async->cmd; if (valid_intstat & PCI224_INTR_EXT) { @@ -1248,13 +1250,13 @@ static irqreturn_t pci224_interrupt(int irq, void *d PT_REGS_ARG) } } /* Reenable interrupt sources. */ - comedi_spin_lock_irqsave(&devpriv->ao_spinlock, flags); + spin_lock_irqsave(&devpriv->ao_spinlock, flags); if (curenab != devpriv->intsce) { outb(devpriv->intsce, devpriv->iobase1 + PCI224_INT_SCE); } devpriv->intr_running = 0; - comedi_spin_unlock_irqrestore(&devpriv->ao_spinlock, flags); + spin_unlock_irqrestore(&devpriv->ao_spinlock, flags); } return IRQ_RETVAL(retval); } @@ -1264,7 +1266,7 @@ static irqreturn_t pci224_interrupt(int irq, void *d PT_REGS_ARG) * bus and slot. */ static int -pci224_find_pci(struct comedi_device * dev, int bus, int slot, +pci224_find_pci(struct comedi_device *dev, int bus, int slot, struct pci_dev **pci_dev_p) { struct pci_dev *pci_dev = NULL; @@ -1323,7 +1325,7 @@ pci224_find_pci(struct comedi_device * dev, int bus, int slot, * in the driver structure, dev->board_ptr contains that * address. */ -static int pci224_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int pci224_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; struct pci_dev *pci_dev; @@ -1336,16 +1338,20 @@ static int pci224_attach(struct comedi_device * dev, struct comedi_devconfig * i bus = it->options[0]; slot = it->options[1]; - if ((ret = alloc_private(dev, sizeof(struct pci224_private))) < 0) { + ret = alloc_private(dev, sizeof(struct pci224_private)); + if (ret < 0) { printk(KERN_ERR "comedi%d: error! out of memory!\n", dev->minor); return ret; } - if ((ret = pci224_find_pci(dev, bus, slot, &pci_dev)) < 0) - return ret; - devpriv->pci_dev = pci_dev; - if ((ret = comedi_pci_enable(pci_dev, DRIVER_NAME)) < 0) { + ret = pci224_find_pci(dev, bus, slot, &pci_dev); + if (ret < 0) + return ret; + + devpriv->pci_dev = pci_dev; + ret = comedi_pci_enable(pci_dev, DRIVER_NAME); + if (ret < 0) { printk(KERN_ERR "comedi%d: error! cannot enable PCI device " "and request regions!\n", dev->minor); @@ -1392,7 +1398,8 @@ static int pci224_attach(struct comedi_device * dev, struct comedi_devconfig * i dev->iobase + PCI224_DACCON); /* Allocate subdevices. There is only one! */ - if ((ret = alloc_subdevices(dev, 1)) < 0) { + ret = alloc_subdevices(dev, 1); + if (ret < 0) { printk(KERN_ERR "comedi%d: error! out of memory!\n", dev->minor); return ret; @@ -1471,8 +1478,8 @@ static int pci224_attach(struct comedi_device * dev, struct comedi_devconfig * i dev->board_name = thisboard->name; if (irq) { - ret = comedi_request_irq(irq, pci224_interrupt, IRQF_SHARED, - DRIVER_NAME, dev); + ret = request_irq(irq, pci224_interrupt, IRQF_SHARED, + DRIVER_NAME, dev); if (ret < 0) { printk(KERN_ERR "comedi%d: error! " "unable to allocate irq %u\n", dev->minor, irq); @@ -1503,12 +1510,12 @@ static int pci224_attach(struct comedi_device * dev, struct comedi_devconfig * i * allocated by _attach(). dev->private and dev->subdevices are * deallocated automatically by the core. */ -static int pci224_detach(struct comedi_device * dev) +static int pci224_detach(struct comedi_device *dev) { printk(KERN_DEBUG "comedi%d: %s: detach\n", dev->minor, DRIVER_NAME); if (dev->irq) { - comedi_free_irq(dev->irq, dev); + free_irq(dev->irq, dev); } if (dev->subdevices) { struct comedi_subdevice *s; diff --git a/drivers/staging/comedi/drivers/amplc_pci230.c b/drivers/staging/comedi/drivers/amplc_pci230.c index 0c9e5737e100..21133f068bf3 100644 --- a/drivers/staging/comedi/drivers/amplc_pci230.c +++ b/drivers/staging/comedi/drivers/amplc_pci230.c @@ -187,9 +187,11 @@ Extra triggered scan functionality, interrupt bug-fix added by Steve Sharples. Support for PCI230+/260+, more triggered scan functionality, and workarounds for (or detection of) various hardware problems added by Ian Abbott. */ + #include "../comedidev.h" #include +#include #include "comedi_pci.h" #include "8253.h" @@ -455,46 +457,46 @@ struct pci230_board { }; static const struct pci230_board pci230_boards[] = { { - name: "pci230+", - id: PCI_DEVICE_ID_PCI230, - ai_chans:16, - ai_bits: 16, - ao_chans:2, - ao_bits: 12, - have_dio:1, - min_hwver:1, + .name = "pci230+", + .id = PCI_DEVICE_ID_PCI230, + .ai_chans = 16, + .ai_bits = 16, + .ao_chans = 2, + .ao_bits = 12, + .have_dio = 1, + .min_hwver = 1, }, { - name: "pci260+", - id: PCI_DEVICE_ID_PCI260, - ai_chans:16, - ai_bits: 16, - ao_chans:0, - ao_bits: 0, - have_dio:0, - min_hwver:1, + .name = "pci260+", + .id = PCI_DEVICE_ID_PCI260, + .ai_chans = 16, + .ai_bits = 16, + .ao_chans = 0, + .ao_bits = 0, + .have_dio = 0, + .min_hwver = 1, }, { - name: "pci230", - id: PCI_DEVICE_ID_PCI230, - ai_chans:16, - ai_bits: 12, - ao_chans:2, - ao_bits: 12, - have_dio:1, + .name = "pci230", + .id = PCI_DEVICE_ID_PCI230, + .ai_chans = 16, + .ai_bits = 12, + .ao_chans = 2, + .ao_bits = 12, + .have_dio = 1, }, { - name: "pci260", - id: PCI_DEVICE_ID_PCI260, - ai_chans:16, - ai_bits: 12, - ao_chans:0, - ao_bits: 0, - have_dio:0, + .name = "pci260", + .id = PCI_DEVICE_ID_PCI260, + .ai_chans = 16, + .ai_bits = 12, + .ao_chans = 0, + .ao_bits = 0, + .have_dio = 0, }, { - name: "amplc_pci230", /* Wildcard matches any above */ - id: PCI_DEVICE_ID_INVALID, + .name = "amplc_pci230", /* Wildcard matches any above */ + .id = PCI_DEVICE_ID_INVALID, }, }; @@ -601,46 +603,46 @@ static const unsigned char pci230_ao_bipolar[2] = { 0, 1 }; * the board, and also about the kernel module that contains * the device code. */ -static int pci230_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int pci230_detach(struct comedi_device * dev); +static int pci230_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int pci230_detach(struct comedi_device *dev); static struct comedi_driver driver_amplc_pci230 = { - driver_name:"amplc_pci230", - module:THIS_MODULE, - attach:pci230_attach, - detach:pci230_detach, - board_name:&pci230_boards[0].name, - offset:sizeof(pci230_boards[0]), - num_names:sizeof(pci230_boards) / sizeof(pci230_boards[0]), + .driver_name = "amplc_pci230", + .module = THIS_MODULE, + .attach = pci230_attach, + .detach = pci230_detach, + .board_name = &pci230_boards[0].name, + .offset = sizeof(pci230_boards[0]), + .num_names = ARRAY_SIZE(pci230_boards), }; COMEDI_PCI_INITCLEANUP(driver_amplc_pci230, pci230_pci_table); -static int pci230_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int pci230_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int pci230_ao_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static void pci230_ct_setup_ns_mode(struct comedi_device * dev, unsigned int ct, +static int pci230_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int pci230_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int pci230_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static void pci230_ct_setup_ns_mode(struct comedi_device *dev, unsigned int ct, unsigned int mode, uint64_t ns, unsigned int round); static void pci230_ns_to_single_timer(unsigned int *ns, unsigned int round); -static void pci230_cancel_ct(struct comedi_device * dev, unsigned int ct); -static irqreturn_t pci230_interrupt(int irq, void *d PT_REGS_ARG); -static int pci230_ao_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd); -static int pci230_ao_cmd(struct comedi_device * dev, struct comedi_subdevice * s); -static int pci230_ao_cancel(struct comedi_device * dev, struct comedi_subdevice * s); -static void pci230_ao_stop(struct comedi_device * dev, struct comedi_subdevice * s); -static void pci230_handle_ao_nofifo(struct comedi_device * dev, struct comedi_subdevice * s); -static int pci230_handle_ao_fifo(struct comedi_device * dev, struct comedi_subdevice * s); -static int pci230_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd); -static int pci230_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s); -static int pci230_ai_cancel(struct comedi_device * dev, struct comedi_subdevice * s); -static void pci230_ai_stop(struct comedi_device * dev, struct comedi_subdevice * s); -static void pci230_handle_ai(struct comedi_device * dev, struct comedi_subdevice * s); +static void pci230_cancel_ct(struct comedi_device *dev, unsigned int ct); +static irqreturn_t pci230_interrupt(int irq, void *d); +static int pci230_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd); +static int pci230_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s); +static int pci230_ao_cancel(struct comedi_device *dev, struct comedi_subdevice *s); +static void pci230_ao_stop(struct comedi_device *dev, struct comedi_subdevice *s); +static void pci230_handle_ao_nofifo(struct comedi_device *dev, struct comedi_subdevice *s); +static int pci230_handle_ao_fifo(struct comedi_device *dev, struct comedi_subdevice *s); +static int pci230_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd); +static int pci230_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s); +static int pci230_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s); +static void pci230_ai_stop(struct comedi_device *dev, struct comedi_subdevice *s); +static void pci230_handle_ai(struct comedi_device *dev, struct comedi_subdevice *s); -static short pci230_ai_read(struct comedi_device * dev) +static short pci230_ai_read(struct comedi_device *dev) { /* Read sample. */ short data = (short) inw(dev->iobase + PCI230_ADCDATA); @@ -658,7 +660,7 @@ static short pci230_ai_read(struct comedi_device * dev) return data; } -static inline unsigned short pci230_ao_mangle_datum(struct comedi_device * dev, +static inline unsigned short pci230_ao_mangle_datum(struct comedi_device *dev, short datum) { /* If a bipolar range was specified, mangle it (straight binary->twos @@ -674,7 +676,7 @@ static inline unsigned short pci230_ao_mangle_datum(struct comedi_device * dev, return (unsigned short)datum; } -static inline void pci230_ao_write_nofifo(struct comedi_device * dev, short datum, +static inline void pci230_ao_write_nofifo(struct comedi_device *dev, short datum, unsigned int chan) { /* Store unmangled datum to be read back later. */ @@ -685,7 +687,7 @@ static inline void pci230_ao_write_nofifo(struct comedi_device * dev, short datu ? PCI230_DACOUT1 : PCI230_DACOUT2)); } -static inline void pci230_ao_write_fifo(struct comedi_device * dev, short datum, +static inline void pci230_ao_write_fifo(struct comedi_device *dev, short datum, unsigned int chan) { /* Store unmangled datum to be read back later. */ @@ -702,7 +704,7 @@ static inline void pci230_ao_write_fifo(struct comedi_device * dev, short datum, * in the driver structure, dev->board_ptr contains that * address. */ -static int pci230_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int pci230_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; unsigned long iobase1, iobase2; @@ -874,8 +876,8 @@ static int pci230_attach(struct comedi_device * dev, struct comedi_devconfig * i dev->iobase + PCI230_ADCCON); /* Register the interrupt handler. */ - irq_hdl = comedi_request_irq(devpriv->pci_dev->irq, pci230_interrupt, - IRQF_SHARED, "amplc_pci230", dev); + irq_hdl = request_irq(devpriv->pci_dev->irq, pci230_interrupt, + IRQF_SHARED, "amplc_pci230", dev); if (irq_hdl < 0) { printk("comedi%d: unable to register irq, " "commands will not be available %d\n", dev->minor, @@ -959,7 +961,7 @@ static int pci230_attach(struct comedi_device * dev, struct comedi_devconfig * i * allocated by _attach(). dev->private and dev->subdevices are * deallocated automatically by the core. */ -static int pci230_detach(struct comedi_device * dev) +static int pci230_detach(struct comedi_device *dev) { printk("comedi%d: amplc_pci230: remove\n", dev->minor); @@ -968,7 +970,7 @@ static int pci230_detach(struct comedi_device * dev) subdev_8255_cleanup(dev, dev->subdevices + 2); if (dev->irq) - comedi_free_irq(dev->irq, dev); + free_irq(dev->irq, dev); if (devpriv) { if (devpriv->pci_dev) { @@ -982,7 +984,7 @@ static int pci230_detach(struct comedi_device * dev) return 0; } -static int get_resources(struct comedi_device * dev, unsigned int res_mask, +static int get_resources(struct comedi_device *dev, unsigned int res_mask, unsigned char owner) { int ok; @@ -993,7 +995,7 @@ static int get_resources(struct comedi_device * dev, unsigned int res_mask, ok = 1; claimed = 0; - comedi_spin_lock_irqsave(&devpriv->res_spinlock, irqflags); + spin_lock_irqsave(&devpriv->res_spinlock, irqflags); for (b = 1, i = 0; (i < NUM_RESOURCES) && (res_mask != 0); b <<= 1, i++) { if ((res_mask & b) != 0) { @@ -1014,24 +1016,24 @@ static int get_resources(struct comedi_device * dev, unsigned int res_mask, } } } - comedi_spin_unlock_irqrestore(&devpriv->res_spinlock, irqflags); + spin_unlock_irqrestore(&devpriv->res_spinlock, irqflags); return ok; } -static inline int get_one_resource(struct comedi_device * dev, unsigned int resource, +static inline int get_one_resource(struct comedi_device *dev, unsigned int resource, unsigned char owner) { return get_resources(dev, (1U << resource), owner); } -static void put_resources(struct comedi_device * dev, unsigned int res_mask, +static void put_resources(struct comedi_device *dev, unsigned int res_mask, unsigned char owner) { unsigned int i; unsigned int b; unsigned long irqflags; - comedi_spin_lock_irqsave(&devpriv->res_spinlock, irqflags); + spin_lock_irqsave(&devpriv->res_spinlock, irqflags); for (b = 1, i = 0; (i < NUM_RESOURCES) && (res_mask != 0); b <<= 1, i++) { if ((res_mask & b) != 0) { @@ -1041,16 +1043,16 @@ static void put_resources(struct comedi_device * dev, unsigned int res_mask, } } } - comedi_spin_unlock_irqrestore(&devpriv->res_spinlock, irqflags); + spin_unlock_irqrestore(&devpriv->res_spinlock, irqflags); } -static inline void put_one_resource(struct comedi_device * dev, unsigned int resource, +static inline void put_one_resource(struct comedi_device *dev, unsigned int resource, unsigned char owner) { put_resources(dev, (1U << resource), owner); } -static inline void put_all_resources(struct comedi_device * dev, unsigned char owner) +static inline void put_all_resources(struct comedi_device *dev, unsigned char owner) { put_resources(dev, (1U << NUM_RESOURCES) - 1, owner); } @@ -1058,8 +1060,8 @@ static inline void put_all_resources(struct comedi_device * dev, unsigned char o /* * COMEDI_SUBD_AI instruction; */ -static int pci230_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pci230_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { unsigned int n, i; unsigned int chan, range, aref; @@ -1143,12 +1145,12 @@ static int pci230_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * status = inw(dev->iobase + PCI230_ADCCON); if (!(status & PCI230_ADC_FIFO_EMPTY)) break; - comedi_udelay(1); + udelay(1); } if (i == TIMEOUT) { - /* rt_printk() should be used instead of printk() + /* printk() should be used instead of printk() * whenever the code can be called from real-time. */ - rt_printk("timeout\n"); + printk("timeout\n"); return -ETIMEDOUT; } @@ -1163,8 +1165,8 @@ static int pci230_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * /* * COMEDI_SUBD_AO instructions; */ -static int pci230_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pci230_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i; int chan, range; @@ -1191,8 +1193,8 @@ static int pci230_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * /* AO subdevices should have a read insn as well as a write insn. * Usually this means copying a value stored in devpriv. */ -static int pci230_ao_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pci230_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i; int chan = CR_CHAN(insn->chanspec); @@ -1203,8 +1205,8 @@ static int pci230_ao_rinsn(struct comedi_device * dev, struct comedi_subdevice * return i; } -static int pci230_ao_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd) +static int pci230_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd) { int err = 0; unsigned int tmp; @@ -1416,20 +1418,20 @@ static int pci230_ao_cmdtest(struct comedi_device * dev, struct comedi_subdevice return 0; } -static int pci230_ao_inttrig_scan_begin(struct comedi_device * dev, - struct comedi_subdevice * s, unsigned int trig_num) +static int pci230_ao_inttrig_scan_begin(struct comedi_device *dev, + struct comedi_subdevice *s, unsigned int trig_num) { unsigned long irqflags; if (trig_num != 0) return -EINVAL; - comedi_spin_lock_irqsave(&devpriv->ao_stop_spinlock, irqflags); + spin_lock_irqsave(&devpriv->ao_stop_spinlock, irqflags); if (test_bit(AO_CMD_STARTED, &devpriv->state)) { /* Perform scan. */ if (devpriv->hwver < 2) { /* Not using DAC FIFO. */ - comedi_spin_unlock_irqrestore(&devpriv-> + spin_unlock_irqrestore(&devpriv-> ao_stop_spinlock, irqflags); pci230_handle_ao_nofifo(dev, s); comedi_event(dev, s); @@ -1437,18 +1439,18 @@ static int pci230_ao_inttrig_scan_begin(struct comedi_device * dev, /* Using DAC FIFO. */ /* Read DACSWTRIG register to trigger conversion. */ inw(dev->iobase + PCI230P2_DACSWTRIG); - comedi_spin_unlock_irqrestore(&devpriv-> + spin_unlock_irqrestore(&devpriv-> ao_stop_spinlock, irqflags); } /* Delay. Should driver be responsible for this? */ /* XXX TODO: See if DAC busy bit can be used. */ - comedi_udelay(8); + udelay(8); } return 1; } -static void pci230_ao_start(struct comedi_device * dev, struct comedi_subdevice * s) +static void pci230_ao_start(struct comedi_device *dev, struct comedi_subdevice *s) { struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; @@ -1506,13 +1508,13 @@ static void pci230_ao_start(struct comedi_device * dev, struct comedi_subdevice if (devpriv->hwver < 2) { /* Not using DAC FIFO. */ /* Enable CT1 timer interrupt. */ - comedi_spin_lock_irqsave(&devpriv->isr_spinlock, + spin_lock_irqsave(&devpriv->isr_spinlock, irqflags); devpriv->int_en |= PCI230_INT_ZCLK_CT1; devpriv->ier |= PCI230_INT_ZCLK_CT1; outb(devpriv->ier, devpriv->iobase1 + PCI230_INT_SCE); - comedi_spin_unlock_irqrestore(&devpriv-> + spin_unlock_irqrestore(&devpriv-> isr_spinlock, irqflags); } /* Set CT1 gate high to start counting. */ @@ -1525,18 +1527,18 @@ static void pci230_ao_start(struct comedi_device * dev, struct comedi_subdevice } if (devpriv->hwver >= 2) { /* Using DAC FIFO. Enable DAC FIFO interrupt. */ - comedi_spin_lock_irqsave(&devpriv->isr_spinlock, + spin_lock_irqsave(&devpriv->isr_spinlock, irqflags); devpriv->int_en |= PCI230P2_INT_DAC; devpriv->ier |= PCI230P2_INT_DAC; outb(devpriv->ier, devpriv->iobase1 + PCI230_INT_SCE); - comedi_spin_unlock_irqrestore(&devpriv->isr_spinlock, + spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags); } } } -static int pci230_ao_inttrig_start(struct comedi_device * dev, struct comedi_subdevice * s, +static int pci230_ao_inttrig_start(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int trig_num) { if (trig_num != 0) @@ -1548,7 +1550,7 @@ static int pci230_ao_inttrig_start(struct comedi_device * dev, struct comedi_sub return 1; } -static int pci230_ao_cmd(struct comedi_device * dev, struct comedi_subdevice * s) +static int pci230_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { unsigned short daccon; unsigned int range; @@ -1624,7 +1626,7 @@ static int pci230_ao_cmd(struct comedi_device * dev, struct comedi_subdevice * s return 0; } -static int pci230_ai_check_scan_period(struct comedi_cmd * cmd) +static int pci230_ai_check_scan_period(struct comedi_cmd *cmd) { unsigned int min_scan_period, chanlist_len; int err = 0; @@ -1648,8 +1650,8 @@ static int pci230_ai_check_scan_period(struct comedi_cmd * cmd) return !err; } -static int pci230_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd) +static int pci230_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd) { int err = 0; unsigned int tmp; @@ -2034,8 +2036,8 @@ static int pci230_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice return 0; } -static void pci230_ai_update_fifo_trigger_level(struct comedi_device * dev, - struct comedi_subdevice * s) +static void pci230_ai_update_fifo_trigger_level(struct comedi_device *dev, + struct comedi_subdevice *s) { struct comedi_cmd *cmd = &s->async->cmd; unsigned int scanlen = cmd->scan_end_arg; @@ -2078,7 +2080,7 @@ static void pci230_ai_update_fifo_trigger_level(struct comedi_device * dev, } } -static int pci230_ai_inttrig_convert(struct comedi_device * dev, struct comedi_subdevice * s, +static int pci230_ai_inttrig_convert(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int trig_num) { unsigned long irqflags; @@ -2086,7 +2088,7 @@ static int pci230_ai_inttrig_convert(struct comedi_device * dev, struct comedi_s if (trig_num != 0) return -EINVAL; - comedi_spin_lock_irqsave(&devpriv->ai_stop_spinlock, irqflags); + spin_lock_irqsave(&devpriv->ai_stop_spinlock, irqflags); if (test_bit(AI_CMD_STARTED, &devpriv->state)) { unsigned int delayus; @@ -2110,19 +2112,19 @@ static int pci230_ai_inttrig_convert(struct comedi_device * dev, struct comedi_s /* single-ended or PCI230+/260+ */ delayus = 4; } - comedi_spin_unlock_irqrestore(&devpriv->ai_stop_spinlock, + spin_unlock_irqrestore(&devpriv->ai_stop_spinlock, irqflags); - comedi_udelay(delayus); + udelay(delayus); } else { - comedi_spin_unlock_irqrestore(&devpriv->ai_stop_spinlock, + spin_unlock_irqrestore(&devpriv->ai_stop_spinlock, irqflags); } return 1; } -static int pci230_ai_inttrig_scan_begin(struct comedi_device * dev, - struct comedi_subdevice * s, unsigned int trig_num) +static int pci230_ai_inttrig_scan_begin(struct comedi_device *dev, + struct comedi_subdevice *s, unsigned int trig_num) { unsigned long irqflags; unsigned char zgat; @@ -2130,7 +2132,7 @@ static int pci230_ai_inttrig_scan_begin(struct comedi_device * dev, if (trig_num != 0) return -EINVAL; - comedi_spin_lock_irqsave(&devpriv->ai_stop_spinlock, irqflags); + spin_lock_irqsave(&devpriv->ai_stop_spinlock, irqflags); if (test_bit(AI_CMD_STARTED, &devpriv->state)) { /* Trigger scan by waggling CT0 gate source. */ zgat = GAT_CONFIG(0, GAT_GND); @@ -2138,12 +2140,12 @@ static int pci230_ai_inttrig_scan_begin(struct comedi_device * dev, zgat = GAT_CONFIG(0, GAT_VCC); outb(zgat, devpriv->iobase1 + PCI230_ZGAT_SCE); } - comedi_spin_unlock_irqrestore(&devpriv->ai_stop_spinlock, irqflags); + spin_unlock_irqrestore(&devpriv->ai_stop_spinlock, irqflags); return 1; } -static void pci230_ai_start(struct comedi_device * dev, struct comedi_subdevice * s) +static void pci230_ai_start(struct comedi_device *dev, struct comedi_subdevice *s) { unsigned long irqflags; unsigned short conv; @@ -2158,11 +2160,11 @@ static void pci230_ai_start(struct comedi_device * dev, struct comedi_subdevice comedi_event(dev, s); } else { /* Enable ADC FIFO trigger level interrupt. */ - comedi_spin_lock_irqsave(&devpriv->isr_spinlock, irqflags); + spin_lock_irqsave(&devpriv->isr_spinlock, irqflags); devpriv->int_en |= PCI230_INT_ADC; devpriv->ier |= PCI230_INT_ADC; outb(devpriv->ier, devpriv->iobase1 + PCI230_INT_SCE); - comedi_spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags); + spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags); /* Update conversion trigger source which is currently set * to CT2 output, which is currently stuck high. */ @@ -2280,7 +2282,7 @@ static void pci230_ai_start(struct comedi_device * dev, struct comedi_subdevice } } -static int pci230_ai_inttrig_start(struct comedi_device * dev, struct comedi_subdevice * s, +static int pci230_ai_inttrig_start(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int trig_num) { if (trig_num != 0) @@ -2292,7 +2294,7 @@ static int pci230_ai_inttrig_start(struct comedi_device * dev, struct comedi_sub return 1; } -static int pci230_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s) +static int pci230_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { unsigned int i, chan, range, diff; unsigned int res_mask; @@ -2424,7 +2426,7 @@ static int pci230_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s * FIFO reset (above) and the second FIFO reset (below). Setting the * channel gains and scan list _before_ the first FIFO reset also * helps, though only slightly. */ - comedi_udelay(25); + udelay(25); /* Reset FIFO again. */ outw(adccon | PCI230_ADC_FIFO_RESET, dev->iobase + PCI230_ADCCON); @@ -2532,7 +2534,7 @@ static void pci230_ns_to_single_timer(unsigned int *ns, unsigned int round) return; } -static void pci230_ct_setup_ns_mode(struct comedi_device * dev, unsigned int ct, +static void pci230_ct_setup_ns_mode(struct comedi_device *dev, unsigned int ct, unsigned int mode, uint64_t ns, unsigned int round) { unsigned int clk_src; @@ -2551,7 +2553,7 @@ static void pci230_ct_setup_ns_mode(struct comedi_device * dev, unsigned int ct, i8254_write(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, ct, count); } -static void pci230_cancel_ct(struct comedi_device * dev, unsigned int ct) +static void pci230_cancel_ct(struct comedi_device *dev, unsigned int ct) { i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, ct, I8254_MODE1); @@ -2559,7 +2561,7 @@ static void pci230_cancel_ct(struct comedi_device * dev, unsigned int ct) } /* Interrupt handler */ -static irqreturn_t pci230_interrupt(int irq, void *d PT_REGS_ARG) +static irqreturn_t pci230_interrupt(int irq, void *d) { unsigned char status_int, valid_status_int; struct comedi_device *dev = (struct comedi_device *) d; @@ -2573,7 +2575,7 @@ static irqreturn_t pci230_interrupt(int irq, void *d PT_REGS_ARG) return IRQ_NONE; } - comedi_spin_lock_irqsave(&devpriv->isr_spinlock, irqflags); + spin_lock_irqsave(&devpriv->isr_spinlock, irqflags); valid_status_int = devpriv->int_en & status_int; /* Disable triggered interrupts. * (Only those interrupts that need re-enabling, are, later in the @@ -2582,7 +2584,7 @@ static irqreturn_t pci230_interrupt(int irq, void *d PT_REGS_ARG) outb(devpriv->ier, devpriv->iobase1 + PCI230_INT_SCE); devpriv->intr_running = 1; devpriv->intr_cpuid = THISCPU; - comedi_spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags); + spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags); /* * Check the source of interrupt and handle it. @@ -2611,18 +2613,18 @@ static irqreturn_t pci230_interrupt(int irq, void *d PT_REGS_ARG) } /* Reenable interrupts. */ - comedi_spin_lock_irqsave(&devpriv->isr_spinlock, irqflags); + spin_lock_irqsave(&devpriv->isr_spinlock, irqflags); if (devpriv->ier != devpriv->int_en) { devpriv->ier = devpriv->int_en; outb(devpriv->ier, devpriv->iobase1 + PCI230_INT_SCE); } devpriv->intr_running = 0; - comedi_spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags); + spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags); return IRQ_HANDLED; } -static void pci230_handle_ao_nofifo(struct comedi_device * dev, struct comedi_subdevice * s) +static void pci230_handle_ao_nofifo(struct comedi_device *dev, struct comedi_subdevice *s) { short data; int i, ret; @@ -2659,7 +2661,7 @@ static void pci230_handle_ao_nofifo(struct comedi_device * dev, struct comedi_su /* Loads DAC FIFO (if using it) from buffer. */ /* Returns 0 if AO finished due to completion or error, 1 if still going. */ -static int pci230_handle_ao_fifo(struct comedi_device * dev, struct comedi_subdevice * s) +static int pci230_handle_ao_fifo(struct comedi_device *dev, struct comedi_subdevice *s) { struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; @@ -2762,7 +2764,7 @@ static int pci230_handle_ao_fifo(struct comedi_device * dev, struct comedi_subde return running; } -static void pci230_handle_ai(struct comedi_device * dev, struct comedi_subdevice * s) +static void pci230_handle_ai(struct comedi_device *dev, struct comedi_subdevice *s) { unsigned int events = 0; unsigned int status_fifo; @@ -2861,16 +2863,16 @@ static void pci230_handle_ai(struct comedi_device * dev, struct comedi_subdevice } } -static void pci230_ao_stop(struct comedi_device * dev, struct comedi_subdevice * s) +static void pci230_ao_stop(struct comedi_device *dev, struct comedi_subdevice *s) { unsigned long irqflags; unsigned char intsrc; int started; struct comedi_cmd *cmd; - comedi_spin_lock_irqsave(&devpriv->ao_stop_spinlock, irqflags); + spin_lock_irqsave(&devpriv->ao_stop_spinlock, irqflags); started = test_and_clear_bit(AO_CMD_STARTED, &devpriv->state); - comedi_spin_unlock_irqrestore(&devpriv->ao_stop_spinlock, irqflags); + spin_unlock_irqrestore(&devpriv->ao_stop_spinlock, irqflags); if (!started) { return; } @@ -2891,17 +2893,17 @@ static void pci230_ao_stop(struct comedi_device * dev, struct comedi_subdevice * } /* Disable interrupt and wait for interrupt routine to finish running * unless we are called from the interrupt routine. */ - comedi_spin_lock_irqsave(&devpriv->isr_spinlock, irqflags); + spin_lock_irqsave(&devpriv->isr_spinlock, irqflags); devpriv->int_en &= ~intsrc; while (devpriv->intr_running && devpriv->intr_cpuid != THISCPU) { - comedi_spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags); - comedi_spin_lock_irqsave(&devpriv->isr_spinlock, irqflags); + spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags); + spin_lock_irqsave(&devpriv->isr_spinlock, irqflags); } if (devpriv->ier != devpriv->int_en) { devpriv->ier = devpriv->int_en; outb(devpriv->ier, devpriv->iobase1 + PCI230_INT_SCE); } - comedi_spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags); + spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags); if (devpriv->hwver >= 2) { /* Using DAC FIFO. Reset FIFO, clear underrun error, @@ -2916,21 +2918,21 @@ static void pci230_ao_stop(struct comedi_device * dev, struct comedi_subdevice * put_all_resources(dev, OWNER_AOCMD); } -static int pci230_ao_cancel(struct comedi_device * dev, struct comedi_subdevice * s) +static int pci230_ao_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { pci230_ao_stop(dev, s); return 0; } -static void pci230_ai_stop(struct comedi_device * dev, struct comedi_subdevice * s) +static void pci230_ai_stop(struct comedi_device *dev, struct comedi_subdevice *s) { unsigned long irqflags; struct comedi_cmd *cmd; int started; - comedi_spin_lock_irqsave(&devpriv->ai_stop_spinlock, irqflags); + spin_lock_irqsave(&devpriv->ai_stop_spinlock, irqflags); started = test_and_clear_bit(AI_CMD_STARTED, &devpriv->state); - comedi_spin_unlock_irqrestore(&devpriv->ai_stop_spinlock, irqflags); + spin_unlock_irqrestore(&devpriv->ai_stop_spinlock, irqflags); if (!started) { return; } @@ -2945,19 +2947,19 @@ static void pci230_ai_stop(struct comedi_device * dev, struct comedi_subdevice * pci230_cancel_ct(dev, 0); } - comedi_spin_lock_irqsave(&devpriv->isr_spinlock, irqflags); + spin_lock_irqsave(&devpriv->isr_spinlock, irqflags); /* Disable ADC interrupt and wait for interrupt routine to finish * running unless we are called from the interrupt routine. */ devpriv->int_en &= ~PCI230_INT_ADC; while (devpriv->intr_running && devpriv->intr_cpuid != THISCPU) { - comedi_spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags); - comedi_spin_lock_irqsave(&devpriv->isr_spinlock, irqflags); + spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags); + spin_lock_irqsave(&devpriv->isr_spinlock, irqflags); } if (devpriv->ier != devpriv->int_en) { devpriv->ier = devpriv->int_en; outb(devpriv->ier, devpriv->iobase1 + PCI230_INT_SCE); } - comedi_spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags); + spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags); /* Reset FIFO, disable FIFO and set start conversion source to none. * Keep se/diff and bip/uni settings */ @@ -2970,7 +2972,7 @@ static void pci230_ai_stop(struct comedi_device * dev, struct comedi_subdevice * put_all_resources(dev, OWNER_AICMD); } -static int pci230_ai_cancel(struct comedi_device * dev, struct comedi_subdevice * s) +static int pci230_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { pci230_ai_stop(dev, s); return 0; diff --git a/drivers/staging/comedi/drivers/c6xdigio.c b/drivers/staging/comedi/drivers/c6xdigio.c index 2efffb14610d..b204793040e2 100644 --- a/drivers/staging/comedi/drivers/c6xdigio.c +++ b/drivers/staging/comedi/drivers/c6xdigio.c @@ -77,7 +77,7 @@ struct pwmbitstype { unsigned sb4:2; }; union pwmcmdtype { - unsigned cmd; // assuming here that int is 32bit + unsigned cmd; /* assuming here that int is 32bit */ struct pwmbitstype bits; }; struct encbitstype { @@ -97,20 +97,20 @@ union encvaluetype { #define C6XDIGIO_TIME_OUT 20 -static int c6xdigio_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int c6xdigio_detach(struct comedi_device * dev); +static int c6xdigio_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int c6xdigio_detach(struct comedi_device *dev); struct comedi_driver driver_c6xdigio = { - driver_name:"c6xdigio", - module:THIS_MODULE, - attach:c6xdigio_attach, - detach:c6xdigio_detach, + .driver_name = "c6xdigio", + .module = THIS_MODULE, + .attach = c6xdigio_attach, + .detach = c6xdigio_detach, }; static void C6X_pwmInit(unsigned long baseAddr) { int timeout = 0; -//printk("Inside C6X_pwmInit\n"); +/* printk("Inside C6X_pwmInit\n"); */ WriteByteToHwPort(baseAddr, 0x70); while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0) @@ -148,7 +148,7 @@ static void C6X_pwmOutput(unsigned long baseAddr, unsigned channel, int value) int timeout = 0; unsigned tmp; - //printk("Inside C6X_pwmOutput\n"); + /* printk("Inside C6X_pwmOutput\n"); */ pwm.cmd = value; if (pwm.cmd > 498) @@ -158,7 +158,7 @@ static void C6X_pwmOutput(unsigned long baseAddr, unsigned channel, int value) if (channel == 0) { ppcmd = 0x28; - } else { // if channel == 1 + } else { /* if channel == 1 */ ppcmd = 0x30; } /* endif */ @@ -216,7 +216,7 @@ static int C6X_encInput(unsigned long baseAddr, unsigned channel) int timeout = 0; int tmp; - //printk("Inside C6X_encInput\n"); + /* printk("Inside C6X_encInput\n"); */ enc.value = 0; if (channel == 0) { @@ -304,14 +304,14 @@ static int C6X_encInput(unsigned long baseAddr, unsigned channel) timeout++; } - return (enc.value ^ 0x800000); + return enc.value ^ 0x800000; } static void C6X_encResetAll(unsigned long baseAddr) { unsigned timeout = 0; -//printk("Inside C6X_encResetAll\n"); +/* printk("Inside C6X_encResetAll\n"); */ WriteByteToHwPort(baseAddr, 0x68); while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0) @@ -338,20 +338,20 @@ static void C6X_encResetAll(unsigned long baseAddr) } } -static int c6xdigio_pwmo_insn_read(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +static int c6xdigio_pwmo_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { printk("c6xdigio_pwmo_insn_read %x\n", insn->n); return insn->n; } -static int c6xdigio_pwmo_insn_write(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +static int c6xdigio_pwmo_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { int i; int chan = CR_CHAN(insn->chanspec); - // printk("c6xdigio_pwmo_insn_write %x\n", insn->n); + /* printk("c6xdigio_pwmo_insn_write %x\n", insn->n); */ for (i = 0; i < insn->n; i++) { C6X_pwmOutput(dev->iobase, chan, data[i]); /* devpriv->ao_readback[chan] = data[i]; */ @@ -359,32 +359,30 @@ static int c6xdigio_pwmo_insn_write(struct comedi_device * dev, return i; } -//static int c6xdigio_ei_init_insn_read(struct comedi_device *dev, -// struct comedi_subdevice *s, -// struct comedi_insn *insn, -// unsigned int *data) -//{ -// printk("c6xdigio_ei_init_insn_read %x\n", insn->n); -// return insn->n; -//} +/* static int c6xdigio_ei_init_insn_read(struct comedi_device *dev, */ +/* struct comedi_subdevice *s, */ +/* struct comedi_insn *insn, */ +/* unsigned int *data) */ +/* { */ +/* printk("c6xdigio_ei_init_insn_read %x\n", insn->n); */ +/* return insn->n; */ +/* } */ -//static int c6xdigio_ei_init_insn_write(struct comedi_device *dev, -// struct comedi_subdevice *s, -// struct comedi_insn *insn, -// unsigned int *data) -//{ -// int i; -// int chan = CR_CHAN(insn->chanspec); -// -// C6X_encResetAll( dev->iobase ); -// -// return insn->n; -//} +/* static int c6xdigio_ei_init_insn_write(struct comedi_device *dev, */ +/* struct comedi_subdevice *s, */ +/* struct comedi_insn *insn, */ +/* unsigned int *data) */ +/* { */ +/* int i; */ +/* int chan = CR_CHAN(insn->chanspec); */ +/* *//* C6X_encResetAll( dev->iobase ); */ +/* *//* return insn->n; */ +/* } */ -static int c6xdigio_ei_insn_read(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +static int c6xdigio_ei_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - // printk("c6xdigio_ei__insn_read %x\n", insn->n); + /* printk("c6xdigio_ei__insn_read %x\n", insn->n); */ int n; int chan = CR_CHAN(insn->chanspec); @@ -395,19 +393,19 @@ static int c6xdigio_ei_insn_read(struct comedi_device * dev, return n; } -static void board_init(struct comedi_device * dev) +static void board_init(struct comedi_device *dev) { - //printk("Inside board_init\n"); + /* printk("Inside board_init\n"); */ C6X_pwmInit(dev->iobase); C6X_encResetAll(dev->iobase); } -//static void board_halt(struct comedi_device *dev) { -// C6X_pwmInit(dev->iobase); -//} +/* static void board_halt(struct comedi_device *dev) { */ +/* C6X_pwmInit(dev->iobase); */ +/* } */ /* options[0] - I/O port @@ -417,9 +415,9 @@ static void board_init(struct comedi_device * dev) static const struct pnp_device_id c6xdigio_pnp_tbl[] = { /* Standard LPT Printer Port */ - {.id = "PNP0400",.driver_data = 0}, + {.id = "PNP0400", .driver_data = 0}, /* ECP Printer Port */ - {.id = "PNP0401",.driver_data = 0}, + {.id = "PNP0401", .driver_data = 0}, {} }; @@ -428,7 +426,7 @@ static struct pnp_driver c6xdigio_pnp_driver = { .id_table = c6xdigio_pnp_tbl, }; -static int c6xdigio_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int c6xdigio_attach(struct comedi_device *dev, struct comedi_devconfig *it) { int result = 0; unsigned long iobase; @@ -444,11 +442,11 @@ static int c6xdigio_attach(struct comedi_device * dev, struct comedi_devconfig * dev->iobase = iobase; dev->board_name = "c6xdigio"; - result = alloc_subdevices(dev, 2); // 3 with encoder_init write + result = alloc_subdevices(dev, 2); /* 3 with encoder_init write */ if (result < 0) return result; - // Make sure that PnP ports gets activated + /* Make sure that PnP ports gets activated */ pnp_register_driver(&c6xdigio_pnp_driver); irq = it->options[1]; @@ -460,14 +458,14 @@ static int c6xdigio_attach(struct comedi_device * dev, struct comedi_devconfig * s = dev->subdevices + 0; /* pwm output subdevice */ - s->type = COMEDI_SUBD_AO; // Not sure what to put here + s->type = COMEDI_SUBD_AO; /* Not sure what to put here */ s->subdev_flags = SDF_WRITEABLE; s->n_chan = 2; /* s->trig[0] = c6xdigio_pwmo; */ s->insn_read = c6xdigio_pwmo_insn_read; s->insn_write = c6xdigio_pwmo_insn_write; s->maxdata = 500; - s->range_table = &range_bipolar10; // A suitable lie + s->range_table = &range_bipolar10; /* A suitable lie */ s = dev->subdevices + 1; /* encoder (counter) subdevice */ @@ -479,27 +477,27 @@ static int c6xdigio_attach(struct comedi_device * dev, struct comedi_devconfig * s->maxdata = 0xffffff; s->range_table = &range_unknown; - // s = dev->subdevices + 2; - // /* pwm output subdevice */ - // s->type = COMEDI_SUBD_COUNTER; // Not sure what to put here - // s->subdev_flags = SDF_WRITEABLE; - // s->n_chan = 1; - // /* s->trig[0] = c6xdigio_ei_init; */ - // s->insn_read = c6xdigio_ei_init_insn_read; - // s->insn_write = c6xdigio_ei_init_insn_write; - // s->maxdata = 0xFFFF; // Really just a don't care - // s->range_table = &range_unknown; // Not sure what to put here + /* s = dev->subdevices + 2; */ + /* pwm output subdevice */ + /* s->type = COMEDI_SUBD_COUNTER; // Not sure what to put here */ + /* s->subdev_flags = SDF_WRITEABLE; */ + /* s->n_chan = 1; */ + /* s->trig[0] = c6xdigio_ei_init; */ + /* s->insn_read = c6xdigio_ei_init_insn_read; */ + /* s->insn_write = c6xdigio_ei_init_insn_write; */ + /* s->maxdata = 0xFFFF; // Really just a don't care */ + /* s->range_table = &range_unknown; // Not sure what to put here */ - // I will call this init anyway but more than likely the DSP board will not be connect - // when device driver is loaded. + /* I will call this init anyway but more than likely the DSP board will not be connect */ + /* when device driver is loaded. */ board_init(dev); return 0; } -static int c6xdigio_detach(struct comedi_device * dev) +static int c6xdigio_detach(struct comedi_device *dev) { -// board_halt(dev); // may not need this +/* board_halt(dev); may not need this */ printk("comedi%d: c6xdigio: remove\n", dev->minor); @@ -508,7 +506,7 @@ static int c6xdigio_detach(struct comedi_device * dev) } if (dev->irq) { free_irq(dev->irq, dev); - } // Not using IRQ so I am not sure if I need this + } /* Not using IRQ so I am not sure if I need this */ pnp_unregister_driver(&c6xdigio_pnp_driver); return 0; diff --git a/drivers/staging/comedi/drivers/cb_das16_cs.c b/drivers/staging/comedi/drivers/cb_das16_cs.c index 0bfe4c954eb5..7af245b42e51 100644 --- a/drivers/staging/comedi/drivers/cb_das16_cs.c +++ b/drivers/staging/comedi/drivers/cb_das16_cs.c @@ -31,6 +31,7 @@ Status: experimental */ +#include #include "../comedidev.h" #include #include @@ -61,19 +62,19 @@ struct das16cs_board { }; static const struct das16cs_board das16cs_boards[] = { { - device_id:0x0000,/* unknown */ - name: "PC-CARD DAS16/16", - n_ao_chans:0, + .device_id = 0x0000,/* unknown */ + .name = "PC-CARD DAS16/16", + .n_ao_chans = 0, }, { - device_id:0x0039, - name: "PC-CARD DAS16/16-AO", - n_ao_chans:2, + .device_id = 0x0039, + .name = "PC-CARD DAS16/16-AO", + .n_ao_chans = 2, }, { - device_id:0x4009, - name: "PCM-DAS16s/16", - n_ao_chans:0, + .device_id = 0x4009, + .name = "PCM-DAS16s/16", + .n_ao_chans = 0, }, }; @@ -89,13 +90,13 @@ struct das16cs_private { }; #define devpriv ((struct das16cs_private *)dev->private) -static int das16cs_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int das16cs_detach(struct comedi_device * dev); +static int das16cs_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int das16cs_detach(struct comedi_device *dev); static struct comedi_driver driver_das16cs = { - driver_name:"cb_das16_cs", - module:THIS_MODULE, - attach:das16cs_attach, - detach:das16cs_detach, + .driver_name = "cb_das16_cs", + .module = THIS_MODULE, + .attach = das16cs_attach, + .detach = das16cs_detach, }; static struct pcmcia_device *cur_dev = NULL; @@ -108,26 +109,26 @@ static const struct comedi_lrange das16cs_ai_range = { 4, { } }; -static irqreturn_t das16cs_interrupt(int irq, void *d PT_REGS_ARG); -static int das16cs_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int das16cs_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s); -static int das16cs_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd); -static int das16cs_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int das16cs_ao_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int das16cs_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int das16cs_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int das16cs_timer_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int das16cs_timer_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); +static irqreturn_t das16cs_interrupt(int irq, void *d); +static int das16cs_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int das16cs_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s); +static int das16cs_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd); +static int das16cs_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int das16cs_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int das16cs_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int das16cs_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int das16cs_timer_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int das16cs_timer_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); -static int get_prodid(struct comedi_device * dev, struct pcmcia_device *link) +static int get_prodid(struct comedi_device *dev, struct pcmcia_device *link) { tuple_t tuple; u_short buf[128]; @@ -165,7 +166,7 @@ static const struct das16cs_board *das16cs_probe(struct comedi_device * dev, return NULL; } -static int das16cs_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int das16cs_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct pcmcia_device *link; struct comedi_subdevice *s; @@ -187,8 +188,8 @@ static int das16cs_attach(struct comedi_device * dev, struct comedi_devconfig * } printk("\n"); - ret = comedi_request_irq(link->irq.AssignedIRQ, das16cs_interrupt, - IRQF_SHARED, "cb_das16_cs", dev); + ret = request_irq(link->irq.AssignedIRQ, das16cs_interrupt, + IRQF_SHARED, "cb_das16_cs", dev); if (ret < 0) { return ret; } @@ -265,20 +266,20 @@ static int das16cs_attach(struct comedi_device * dev, struct comedi_devconfig * return 1; } -static int das16cs_detach(struct comedi_device * dev) +static int das16cs_detach(struct comedi_device *dev) { printk("comedi%d: das16cs: remove\n", dev->minor); if (dev->irq) { - comedi_free_irq(dev->irq, dev); + free_irq(dev->irq, dev); } return 0; } -static irqreturn_t das16cs_interrupt(int irq, void *d PT_REGS_ARG) +static irqreturn_t das16cs_interrupt(int irq, void *d) { - //struct comedi_device *dev = d; + /* struct comedi_device *dev = d; */ return IRQ_HANDLED; } @@ -286,8 +287,8 @@ static irqreturn_t das16cs_interrupt(int irq, void *d PT_REGS_ARG) * "instructions" read/write data in "one-shot" or "software-triggered" * mode. */ -static int das16cs_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int das16cs_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i; int to; @@ -328,13 +329,13 @@ static int das16cs_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice return i; } -static int das16cs_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s) +static int das16cs_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { return -EINVAL; } -static int das16cs_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd) +static int das16cs_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd) { int err = 0; int tmp; @@ -489,8 +490,8 @@ static int das16cs_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevic return 0; } -static int das16cs_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int das16cs_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i; int chan = CR_CHAN(insn->chanspec); @@ -503,7 +504,7 @@ static int das16cs_ao_winsn(struct comedi_device * dev, struct comedi_subdevice d = data[i]; outw(devpriv->status1, dev->iobase + 4); - comedi_udelay(1); + udelay(1); status1 = devpriv->status1 & ~0xf; if (chan) @@ -513,17 +514,17 @@ static int das16cs_ao_winsn(struct comedi_device * dev, struct comedi_subdevice /* printk("0x%04x\n",status1);*/ outw(status1, dev->iobase + 4); - comedi_udelay(1); + udelay(1); for (bit = 15; bit >= 0; bit--) { int b = (d >> bit) & 0x1; b <<= 1; /* printk("0x%04x\n",status1 | b | 0x0000);*/ outw(status1 | b | 0x0000, dev->iobase + 4); - comedi_udelay(1); + udelay(1); /* printk("0x%04x\n",status1 | b | 0x0004);*/ outw(status1 | b | 0x0004, dev->iobase + 4); - comedi_udelay(1); + udelay(1); } /* make high both DAC0CS and DAC1CS to load new data and update analog output*/ @@ -535,8 +536,8 @@ static int das16cs_ao_winsn(struct comedi_device * dev, struct comedi_subdevice /* AO subdevices should have a read insn as well as a write insn. * Usually this means copying a value stored in devpriv. */ -static int das16cs_ao_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int das16cs_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i; int chan = CR_CHAN(insn->chanspec); @@ -552,8 +553,8 @@ static int das16cs_ao_rinsn(struct comedi_device * dev, struct comedi_subdevice * useful to applications if you implement the insn_bits interface. * This allows packed reading/writing of the DIO channels. The * comedi core can convert between insn_bits and insn_read/write */ -static int das16cs_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int das16cs_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if (insn->n != 2) return -EINVAL; @@ -572,8 +573,8 @@ static int das16cs_dio_insn_bits(struct comedi_device * dev, struct comedi_subde return 2; } -static int das16cs_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int das16cs_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int chan = CR_CHAN(insn->chanspec); int bits; @@ -610,14 +611,14 @@ static int das16cs_dio_insn_config(struct comedi_device * dev, struct comedi_sub return insn->n; } -static int das16cs_timer_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int das16cs_timer_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { return -EINVAL; } -static int das16cs_timer_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int das16cs_timer_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { return -EINVAL; } @@ -766,15 +767,22 @@ static void das16cs_pcmcia_config(struct pcmcia_device *link) tuple.TupleData = buf; tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; + last_fn = GetFirstTuple; - if ((last_ret = pcmcia_get_first_tuple(link, &tuple)) != 0) + last_ret = pcmcia_get_first_tuple(link, &tuple); + if (last_ret != 0) goto cs_failed; + last_fn = GetTupleData; - if ((last_ret = pcmcia_get_tuple_data(link, &tuple)) != 0) + last_ret = pcmcia_get_tuple_data(link, &tuple); + if (last_ret != 0) goto cs_failed; + last_fn = ParseTuple; - if ((last_ret = pcmcia_parse_tuple(link, &tuple, &parse)) != 0) + last_ret = pcmcia_parse_tuple(&tuple, &parse); + if (last_ret != 0) goto cs_failed; + link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; @@ -792,13 +800,16 @@ static void das16cs_pcmcia_config(struct pcmcia_device *link) */ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; last_fn = GetFirstTuple; - if ((last_ret = pcmcia_get_first_tuple(link, &tuple)) != 0) + + last_ret = pcmcia_get_first_tuple(link, &tuple); + if (last_ret) goto cs_failed; + while (1) { cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); if (pcmcia_get_tuple_data(link, &tuple)) goto next_entry; - if (pcmcia_parse_tuple(link, &tuple, &parse)) + if (pcmcia_parse_tuple(&tuple, &parse)) goto next_entry; if (cfg->flags & CISTPL_CFTABLE_DEFAULT) @@ -844,7 +855,9 @@ static void das16cs_pcmcia_config(struct pcmcia_device *link) next_entry: last_fn = GetNextTuple; - if ((last_ret = pcmcia_get_next_tuple(link, &tuple)) != 0) + + last_ret = pcmcia_get_next_tuple(link, &tuple); + if (last_ret) goto cs_failed; } @@ -855,7 +868,9 @@ static void das16cs_pcmcia_config(struct pcmcia_device *link) */ if (link->conf.Attributes & CONF_ENABLE_IRQ) { last_fn = RequestIRQ; - if ((last_ret = pcmcia_request_irq(link, &link->irq)) != 0) + + last_ret = pcmcia_request_irq(link, &link->irq); + if (last_ret) goto cs_failed; } /* @@ -864,7 +879,8 @@ static void das16cs_pcmcia_config(struct pcmcia_device *link) card and host interface into "Memory and IO" mode. */ last_fn = RequestConfiguration; - if ((last_ret = pcmcia_request_configuration(link, &link->conf)) != 0) + last_ret = pcmcia_request_configuration(link, &link->conf); + if (last_ret) goto cs_failed; /* @@ -973,4 +989,4 @@ void __exit cleanup_module(void) #else COMEDI_INITCLEANUP(driver_das16cs); -#endif //CONFIG_PCMCIA +#endif /* CONFIG_PCMCIA */ diff --git a/drivers/staging/comedi/drivers/cb_pcidas.c b/drivers/staging/comedi/drivers/cb_pcidas.c index fcc551651367..702de1571223 100644 --- a/drivers/staging/comedi/drivers/cb_pcidas.c +++ b/drivers/staging/comedi/drivers/cb_pcidas.c @@ -63,6 +63,7 @@ analog triggering on 1602 series #include "../comedidev.h" #include +#include #include "8253.h" #include "8255.h" @@ -70,14 +71,14 @@ analog triggering on 1602 series #include "comedi_pci.h" #include "comedi_fc.h" -#undef CB_PCIDAS_DEBUG // disable debugging code -//#define CB_PCIDAS_DEBUG // enable debugging code +#undef CB_PCIDAS_DEBUG /* disable debugging code */ +/* #define CB_PCIDAS_DEBUG enable debugging code */ -// PCI vendor number of ComputerBoards/MeasurementComputing +/* PCI vendor number of ComputerBoards/MeasurementComputing */ #define PCI_VENDOR_ID_CB 0x1307 -#define TIMER_BASE 100 // 10MHz master clock -#define AI_BUFFER_SIZE 1024 // maximum fifo size of any supported board -#define AO_BUFFER_SIZE 1024 // maximum fifo size of any supported board +#define TIMER_BASE 100 /* 10MHz master clock */ +#define AI_BUFFER_SIZE 1024 /* maximum fifo size of any supported board */ +#define AO_BUFFER_SIZE 1024 /* maximum fifo size of any supported board */ #define NUM_CHANNELS_8800 8 #define NUM_CHANNELS_7376 1 #define NUM_CHANNELS_8402 2 @@ -85,71 +86,71 @@ analog triggering on 1602 series /* PCI-DAS base addresses */ -// indices of base address regions +/* indices of base address regions */ #define S5933_BADRINDEX 0 #define CONT_STAT_BADRINDEX 1 #define ADC_FIFO_BADRINDEX 2 #define PACER_BADRINDEX 3 #define AO_BADRINDEX 4 -// sizes of io regions +/* sizes of io regions */ #define CONT_STAT_SIZE 10 #define ADC_FIFO_SIZE 4 #define PACER_SIZE 12 #define AO_SIZE 4 /* Control/Status registers */ -#define INT_ADCFIFO 0 // INTERRUPT / ADC FIFO register -#define INT_EOS 0x1 // interrupt end of scan -#define INT_FHF 0x2 // interrupt fifo half full -#define INT_FNE 0x3 // interrupt fifo not empty -#define INT_MASK 0x3 // mask of interrupt select bits -#define INTE 0x4 // interrupt enable -#define DAHFIE 0x8 // dac half full interrupt enable -#define EOAIE 0x10 // end of aquisition interrupt enable -#define DAHFI 0x20 // dac half full read status / write interrupt clear -#define EOAI 0x40 // read end of acq. interrupt status / write clear -#define INT 0x80 // read interrupt status / write clear -#define EOBI 0x200 // read end of burst interrupt status -#define ADHFI 0x400 // read half-full interrupt status -#define ADNEI 0x800 // read fifo not empty interrupt latch status -#define ADNE 0x1000 // read, fifo not empty (realtime, not latched) status -#define DAEMIE 0x1000 // write, dac empty interrupt enable -#define LADFUL 0x2000 // read fifo overflow / write clear -#define DAEMI 0x4000 // dac fifo empty interrupt status / write clear +#define INT_ADCFIFO 0 /* INTERRUPT / ADC FIFO register */ +#define INT_EOS 0x1 /* interrupt end of scan */ +#define INT_FHF 0x2 /* interrupt fifo half full */ +#define INT_FNE 0x3 /* interrupt fifo not empty */ +#define INT_MASK 0x3 /* mask of interrupt select bits */ +#define INTE 0x4 /* interrupt enable */ +#define DAHFIE 0x8 /* dac half full interrupt enable */ +#define EOAIE 0x10 /* end of aquisition interrupt enable */ +#define DAHFI 0x20 /* dac half full read status / write interrupt clear */ +#define EOAI 0x40 /* read end of acq. interrupt status / write clear */ +#define INT 0x80 /* read interrupt status / write clear */ +#define EOBI 0x200 /* read end of burst interrupt status */ +#define ADHFI 0x400 /* read half-full interrupt status */ +#define ADNEI 0x800 /* read fifo not empty interrupt latch status */ +#define ADNE 0x1000 /* read, fifo not empty (realtime, not latched) status */ +#define DAEMIE 0x1000 /* write, dac empty interrupt enable */ +#define LADFUL 0x2000 /* read fifo overflow / write clear */ +#define DAEMI 0x4000 /* dac fifo empty interrupt status / write clear */ -#define ADCMUX_CONT 2 // ADC CHANNEL MUX AND CONTROL register +#define ADCMUX_CONT 2 /* ADC CHANNEL MUX AND CONTROL register */ #define BEGIN_SCAN(x) ((x) & 0xf) #define END_SCAN(x) (((x) & 0xf) << 4) #define GAIN_BITS(x) (((x) & 0x3) << 8) -#define UNIP 0x800 // Analog front-end unipolar for range -#define SE 0x400 // Inputs in single-ended mode -#define PACER_MASK 0x3000 // pacer source bits -#define PACER_INT 0x1000 // internal pacer -#define PACER_EXT_FALL 0x2000 // external falling edge -#define PACER_EXT_RISE 0x3000 // external rising edge -#define EOC 0x4000 // adc not busy +#define UNIP 0x800 /* Analog front-end unipolar for range */ +#define SE 0x400 /* Inputs in single-ended mode */ +#define PACER_MASK 0x3000 /* pacer source bits */ +#define PACER_INT 0x1000 /* internal pacer */ +#define PACER_EXT_FALL 0x2000 /* external falling edge */ +#define PACER_EXT_RISE 0x3000 /* external rising edge */ +#define EOC 0x4000 /* adc not busy */ -#define TRIG_CONTSTAT 4 // TRIGGER CONTROL/STATUS register -#define SW_TRIGGER 0x1 // software start trigger -#define EXT_TRIGGER 0x2 // external start trigger -#define ANALOG_TRIGGER 0x3 // external analog trigger -#define TRIGGER_MASK 0x3 // mask of bits that determine start trigger -#define TGEN 0x10 // enable external start trigger -#define BURSTE 0x20 // burst mode enable -#define XTRCL 0x80 // clear external trigger +#define TRIG_CONTSTAT 4 /* TRIGGER CONTROL/STATUS register */ +#define SW_TRIGGER 0x1 /* software start trigger */ +#define EXT_TRIGGER 0x2 /* external start trigger */ +#define ANALOG_TRIGGER 0x3 /* external analog trigger */ +#define TRIGGER_MASK 0x3 /* mask of bits that determine start trigger */ +#define TGEN 0x10 /* enable external start trigger */ +#define BURSTE 0x20 /* burst mode enable */ +#define XTRCL 0x80 /* clear external trigger */ -#define CALIBRATION_REG 6 // CALIBRATION register -#define SELECT_8800_BIT 0x100 // select 8800 caldac -#define SELECT_TRIMPOT_BIT 0x200 // select ad7376 trim pot -#define SELECT_DAC08_BIT 0x400 // select dac08 caldac +#define CALIBRATION_REG 6 /* CALIBRATION register */ +#define SELECT_8800_BIT 0x100 /* select 8800 caldac */ +#define SELECT_TRIMPOT_BIT 0x200 /* select ad7376 trim pot */ +#define SELECT_DAC08_BIT 0x400 /* select dac08 caldac */ #define CAL_SRC_BITS(x) (((x) & 0x7) << 11) -#define CAL_EN_BIT 0x4000 // read calibration source instead of analog input channel 0 -#define SERIAL_DATA_IN_BIT 0x8000 // serial data stream going to 8800 and 7376 +#define CAL_EN_BIT 0x4000 /* read calibration source instead of analog input channel 0 */ +#define SERIAL_DATA_IN_BIT 0x8000 /* serial data stream going to 8800 and 7376 */ -#define DAC_CSR 0x8 // dac control and status register +#define DAC_CSR 0x8 /* dac control and status register */ enum dac_csr_bits { - DACEN = 0x2, // dac enable - DAC_MODE_UPDATE_BOTH = 0x80, // update both dacs when dac0 is written + DACEN = 0x2, /* dac enable */ + DAC_MODE_UPDATE_BOTH = 0x80, /* update both dacs when dac0 is written */ }; static inline unsigned int DAC_RANGE(unsigned int channel, unsigned int range) { @@ -160,42 +161,42 @@ static inline unsigned int DAC_RANGE_MASK(unsigned int channel) return 0x3 << (8 + 2 * (channel & 0x1)); }; -// bits for 1602 series only +/* bits for 1602 series only */ enum dac_csr_bits_1602 { - DAC_EMPTY = 0x1, // dac fifo empty, read, write clear - DAC_START = 0x4, // start/arm dac fifo operations - DAC_PACER_MASK = 0x18, // bits that set dac pacer source - DAC_PACER_INT = 0x8, // dac internal pacing - DAC_PACER_EXT_FALL = 0x10, // dac external pacing, falling edge - DAC_PACER_EXT_RISE = 0x18, // dac external pacing, rising edge + DAC_EMPTY = 0x1, /* dac fifo empty, read, write clear */ + DAC_START = 0x4, /* start/arm dac fifo operations */ + DAC_PACER_MASK = 0x18, /* bits that set dac pacer source */ + DAC_PACER_INT = 0x8, /* dac internal pacing */ + DAC_PACER_EXT_FALL = 0x10, /* dac external pacing, falling edge */ + DAC_PACER_EXT_RISE = 0x18, /* dac external pacing, rising edge */ }; static inline unsigned int DAC_CHAN_EN(unsigned int channel) { - return 1 << (5 + (channel & 0x1)); // enable channel 0 or 1 + return 1 << (5 + (channel & 0x1)); /* enable channel 0 or 1 */ }; /* analog input fifo */ -#define ADCDATA 0 // ADC DATA register -#define ADCFIFOCLR 2 // ADC FIFO CLEAR +#define ADCDATA 0 /* ADC DATA register */ +#define ADCFIFOCLR 2 /* ADC FIFO CLEAR */ -// pacer, counter, dio registers +/* pacer, counter, dio registers */ #define ADC8254 0 #define DIO_8255 4 #define DAC8254 8 -// analog output registers for 100x, 1200 series +/* analog output registers for 100x, 1200 series */ static inline unsigned int DAC_DATA_REG(unsigned int channel) { return 2 * (channel & 0x1); } /* analog output registers for 1602 series*/ -#define DACDATA 0 // DAC DATA register -#define DACFIFOCLR 2 // DAC FIFO CLEAR +#define DACDATA 0 /* DAC DATA register */ +#define DACFIFOCLR 2 /* DAC FIFO CLEAR */ -// bit in hexadecimal representation of range index that indicates unipolar input range +/* bit in hexadecimal representation of range index that indicates unipolar input range */ #define IS_UNIPOLAR 0x4 -// analog input ranges for most boards +/* analog input ranges for most boards */ static const struct comedi_lrange cb_pcidas_ranges = { 8, { @@ -210,7 +211,7 @@ static const struct comedi_lrange cb_pcidas_ranges = { } }; -// pci-das1001 input ranges +/* pci-das1001 input ranges */ static const struct comedi_lrange cb_pcidas_alt_ranges = { 8, { @@ -225,7 +226,7 @@ static const struct comedi_lrange cb_pcidas_alt_ranges = { } }; -// analog output ranges +/* analog output ranges */ static const struct comedi_lrange cb_pcidas_ao_ranges = { 4, { @@ -244,14 +245,14 @@ enum trimpot_model { struct cb_pcidas_board { const char *name; unsigned short device_id; - int ai_se_chans; // Inputs in single-ended mode - int ai_diff_chans; // Inputs in differential mode - int ai_bits; // analog input resolution - int ai_speed; // fastest conversion period in ns - int ao_nchan; // number of analog out channels - int has_ao_fifo; // analog output has fifo - int ao_scan_speed; // analog output speed for 1602 series (for a scan, not conversion) - int fifo_size; // number of samples fifo can hold + int ai_se_chans; /* Inputs in single-ended mode */ + int ai_diff_chans; /* Inputs in differential mode */ + int ai_bits; /* analog input resolution */ + int ai_speed; /* fastest conversion period in ns */ + int ao_nchan; /* number of analog out channels */ + int has_ao_fifo; /* analog output has fifo */ + int ao_scan_speed; /* analog output speed for 1602 series (for a scan, not conversion) */ + int fifo_size; /* number of samples fifo can hold */ const struct comedi_lrange *ranges; enum trimpot_model trimpot; unsigned has_dac08:1; @@ -259,124 +260,121 @@ struct cb_pcidas_board { static const struct cb_pcidas_board cb_pcidas_boards[] = { { - name: "pci-das1602/16", - device_id:0x1, - ai_se_chans:16, - ai_diff_chans:8, - ai_bits: 16, - ai_speed:5000, - ao_nchan:2, - has_ao_fifo:1, - ao_scan_speed:10000, - fifo_size:512, - ranges: &cb_pcidas_ranges, - trimpot: AD8402, - has_dac08:1, + .name = "pci-das1602/16", + .device_id = 0x1, + .ai_se_chans = 16, + .ai_diff_chans = 8, + .ai_bits = 16, + .ai_speed = 5000, + .ao_nchan = 2, + .has_ao_fifo = 1, + .ao_scan_speed = 10000, + .fifo_size = 512, + .ranges = &cb_pcidas_ranges, + .trimpot = AD8402, + .has_dac08 = 1, }, { - name: "pci-das1200", - device_id:0xF, - ai_se_chans:16, - ai_diff_chans:8, - ai_bits: 12, - ai_speed:3200, - ao_nchan:2, - has_ao_fifo:0, - fifo_size:1024, - ranges: &cb_pcidas_ranges, - trimpot: AD7376, - has_dac08:0, + .name = "pci-das1200", + .device_id = 0xF, + .ai_se_chans = 16, + .ai_diff_chans = 8, + .ai_bits = 12, + .ai_speed = 3200, + .ao_nchan = 2, + .has_ao_fifo = 0, + .fifo_size = 1024, + .ranges = &cb_pcidas_ranges, + .trimpot = AD7376, + .has_dac08 = 0, }, { - name: "pci-das1602/12", - device_id:0x10, - ai_se_chans:16, - ai_diff_chans:8, - ai_bits: 12, - ai_speed:3200, - ao_nchan:2, - has_ao_fifo:1, - ao_scan_speed:4000, - fifo_size:1024, - ranges: &cb_pcidas_ranges, - trimpot: AD7376, - has_dac08:0, + .name = "pci-das1602/12", + .device_id = 0x10, + .ai_se_chans = 16, + .ai_diff_chans = 8, + .ai_bits = 12, + .ai_speed = 3200, + .ao_nchan = 2, + .has_ao_fifo = 1, + .ao_scan_speed = 4000, + .fifo_size = 1024, + .ranges = &cb_pcidas_ranges, + .trimpot = AD7376, + .has_dac08 = 0, }, { - name: "pci-das1200/jr", - device_id:0x19, - ai_se_chans:16, - ai_diff_chans:8, - ai_bits: 12, - ai_speed:3200, - ao_nchan:0, - has_ao_fifo:0, - fifo_size:1024, - ranges: &cb_pcidas_ranges, - trimpot: AD7376, - has_dac08:0, + .name = "pci-das1200/jr", + .device_id = 0x19, + .ai_se_chans = 16, + .ai_diff_chans = 8, + .ai_bits = 12, + .ai_speed = 3200, + .ao_nchan = 0, + .has_ao_fifo = 0, + .fifo_size = 1024, + .ranges = &cb_pcidas_ranges, + .trimpot = AD7376, + .has_dac08 = 0, }, { - name: "pci-das1602/16/jr", - device_id:0x1C, - ai_se_chans:16, - ai_diff_chans:8, - ai_bits: 16, - ai_speed:5000, - ao_nchan:0, - has_ao_fifo:0, - fifo_size:512, - ranges: &cb_pcidas_ranges, - trimpot: AD8402, - has_dac08:1, + .name = "pci-das1602/16/jr", + .device_id = 0x1C, + .ai_se_chans = 16, + .ai_diff_chans = 8, + .ai_bits = 16, + .ai_speed = 5000, + .ao_nchan = 0, + .has_ao_fifo = 0, + .fifo_size = 512, + .ranges = &cb_pcidas_ranges, + .trimpot = AD8402, + .has_dac08 = 1, }, { - name: "pci-das1000", - device_id:0x4C, - ai_se_chans:16, - ai_diff_chans:8, - ai_bits: 12, - ai_speed:4000, - ao_nchan:0, - has_ao_fifo:0, - fifo_size:1024, - ranges: &cb_pcidas_ranges, - trimpot: AD7376, - has_dac08:0, + .name = "pci-das1000", + .device_id = 0x4C, + .ai_se_chans = 16, + .ai_diff_chans = 8, + .ai_bits = 12, + .ai_speed = 4000, + .ao_nchan = 0, + .has_ao_fifo = 0, + .fifo_size = 1024, + .ranges = &cb_pcidas_ranges, + .trimpot = AD7376, + .has_dac08 = 0, }, { - name: "pci-das1001", - device_id:0x1a, - ai_se_chans:16, - ai_diff_chans:8, - ai_bits: 12, - ai_speed:6800, - ao_nchan:2, - has_ao_fifo:0, - fifo_size:1024, - ranges: &cb_pcidas_alt_ranges, - trimpot: AD7376, - has_dac08:0, + .name = "pci-das1001", + .device_id = 0x1a, + .ai_se_chans = 16, + .ai_diff_chans = 8, + .ai_bits = 12, + .ai_speed = 6800, + .ao_nchan = 2, + .has_ao_fifo = 0, + .fifo_size = 1024, + .ranges = &cb_pcidas_alt_ranges, + .trimpot = AD7376, + .has_dac08 = 0, }, { - name: "pci-das1002", - device_id:0x1b, - ai_se_chans:16, - ai_diff_chans:8, - ai_bits: 12, - ai_speed:6800, - ao_nchan:2, - has_ao_fifo:0, - fifo_size:1024, - ranges: &cb_pcidas_ranges, - trimpot: AD7376, - has_dac08:0, + .name = "pci-das1002", + .device_id = 0x1b, + .ai_se_chans = 16, + .ai_diff_chans = 8, + .ai_bits = 12, + .ai_speed = 6800, + .ao_nchan = 2, + .has_ao_fifo = 0, + .fifo_size = 1024, + .ranges = &cb_pcidas_ranges, + .trimpot = AD7376, + .has_dac08 = 0, }, }; -// Number of boards in cb_pcidas_boards -#define N_BOARDS (sizeof(cb_pcidas_boards) / sizeof(struct cb_pcidas_board)) - static DEFINE_PCI_DEVICE_TABLE(cb_pcidas_pci_table) = { {PCI_VENDOR_ID_CB, 0x0001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {PCI_VENDOR_ID_CB, 0x000f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, @@ -402,28 +400,28 @@ MODULE_DEVICE_TABLE(pci, cb_pcidas_pci_table); struct cb_pcidas_private { /* would be useful for a PCI device */ struct pci_dev *pci_dev; - // base addresses + /* base addresses */ unsigned long s5933_config; unsigned long control_status; unsigned long adc_fifo; unsigned long pacer_counter_dio; unsigned long ao_registers; - // divisors of master clock for analog input pacing + /* divisors of master clock for analog input pacing */ unsigned int divisor1; unsigned int divisor2; - volatile unsigned int count; // number of analog input samples remaining - volatile unsigned int adc_fifo_bits; // bits to write to interupt/adcfifo register - volatile unsigned int s5933_intcsr_bits; // bits to write to amcc s5933 interrupt control/status register - volatile unsigned int ao_control_bits; // bits to write to ao control and status register + volatile unsigned int count; /* number of analog input samples remaining */ + volatile unsigned int adc_fifo_bits; /* bits to write to interupt/adcfifo register */ + volatile unsigned int s5933_intcsr_bits; /* bits to write to amcc s5933 interrupt control/status register */ + volatile unsigned int ao_control_bits; /* bits to write to ao control and status register */ short ai_buffer[AI_BUFFER_SIZE]; short ao_buffer[AO_BUFFER_SIZE]; - // divisors of master clock for analog output pacing + /* divisors of master clock for analog output pacing */ unsigned int ao_divisor1; unsigned int ao_divisor2; - volatile unsigned int ao_count; // number of analog output samples remaining - int ao_value[2]; // remember what the analog outputs are set to, to allow readback - unsigned int caldac_value[NUM_CHANNELS_8800]; // for readback of caldac - unsigned int trimpot_value[NUM_CHANNELS_8402]; // for readback of trimpot + volatile unsigned int ao_count; /* number of analog output samples remaining */ + int ao_value[2]; /* remember what the analog outputs are set to, to allow readback */ + unsigned int caldac_value[NUM_CHANNELS_8800]; /* for readback of caldac */ + unsigned int trimpot_value[NUM_CHANNELS_8402]; /* for readback of trimpot */ unsigned int dac08_value; unsigned int calibration_source; }; @@ -440,66 +438,66 @@ struct cb_pcidas_private { * the board, and also about the kernel module that contains * the device code. */ -static int cb_pcidas_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int cb_pcidas_detach(struct comedi_device * dev); +static int cb_pcidas_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int cb_pcidas_detach(struct comedi_device *dev); static struct comedi_driver driver_cb_pcidas = { - driver_name:"cb_pcidas", - module:THIS_MODULE, - attach:cb_pcidas_attach, - detach:cb_pcidas_detach, + .driver_name = "cb_pcidas", + .module = THIS_MODULE, + .attach = cb_pcidas_attach, + .detach = cb_pcidas_detach, }; static int cb_pcidas_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int ai_config_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int cb_pcidas_ao_nofifo_winsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int cb_pcidas_ao_fifo_winsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int cb_pcidas_ao_readback_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int cb_pcidas_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s); -static int cb_pcidas_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd); -static int cb_pcidas_ao_cmd(struct comedi_device * dev, struct comedi_subdevice * s); + struct comedi_insn *insn, unsigned int *data); +static int ai_config_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int cb_pcidas_ao_nofifo_winsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int cb_pcidas_ao_fifo_winsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int cb_pcidas_ao_readback_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int cb_pcidas_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s); +static int cb_pcidas_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd); +static int cb_pcidas_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s); static int cb_pcidas_ao_inttrig(struct comedi_device *dev, struct comedi_subdevice *subdev, unsigned int trig_num); -static int cb_pcidas_ao_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd); -static irqreturn_t cb_pcidas_interrupt(int irq, void *d PT_REGS_ARG); -static void handle_ao_interrupt(struct comedi_device * dev, unsigned int status); -static int cb_pcidas_cancel(struct comedi_device * dev, struct comedi_subdevice * s); -static int cb_pcidas_ao_cancel(struct comedi_device * dev, struct comedi_subdevice * s); -static void cb_pcidas_load_counters(struct comedi_device * dev, unsigned int *ns, +static int cb_pcidas_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd); +static irqreturn_t cb_pcidas_interrupt(int irq, void *d); +static void handle_ao_interrupt(struct comedi_device *dev, unsigned int status); +static int cb_pcidas_cancel(struct comedi_device *dev, struct comedi_subdevice *s); +static int cb_pcidas_ao_cancel(struct comedi_device *dev, struct comedi_subdevice *s); +static void cb_pcidas_load_counters(struct comedi_device *dev, unsigned int *ns, int round_flags); -static int eeprom_read_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int caldac_read_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int caldac_write_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int trimpot_read_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int cb_pcidas_trimpot_write(struct comedi_device * dev, unsigned int channel, +static int eeprom_read_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int caldac_read_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int caldac_write_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int trimpot_read_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int cb_pcidas_trimpot_write(struct comedi_device *dev, unsigned int channel, unsigned int value); -static int trimpot_write_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int dac08_read_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int dac08_write(struct comedi_device * dev, unsigned int value); -static int dac08_write_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int caldac_8800_write(struct comedi_device * dev, unsigned int address, +static int trimpot_write_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int dac08_read_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int dac08_write(struct comedi_device *dev, unsigned int value); +static int dac08_write_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int caldac_8800_write(struct comedi_device *dev, unsigned int address, uint8_t value); -static int trimpot_7376_write(struct comedi_device * dev, uint8_t value); -static int trimpot_8402_write(struct comedi_device * dev, unsigned int channel, +static int trimpot_7376_write(struct comedi_device *dev, uint8_t value); +static int trimpot_8402_write(struct comedi_device *dev, unsigned int channel, uint8_t value); -static int nvram_read(struct comedi_device * dev, unsigned int address, - uint8_t * data); +static int nvram_read(struct comedi_device *dev, unsigned int address, + uint8_t *data); -static inline unsigned int cal_enable_bits(struct comedi_device * dev) +static inline unsigned int cal_enable_bits(struct comedi_device *dev) { return CAL_EN_BIT | CAL_SRC_BITS(devpriv->calibration_source); } @@ -508,7 +506,7 @@ static inline unsigned int cal_enable_bits(struct comedi_device * dev) * Attach is called by the Comedi core to configure the driver * for a particular board. */ -static int cb_pcidas_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int cb_pcidas_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; struct pci_dev *pcidev; @@ -531,16 +529,16 @@ static int cb_pcidas_attach(struct comedi_device * dev, struct comedi_devconfig for (pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL); pcidev != NULL; pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pcidev)) { - // is it not a computer boards card? + /* is it not a computer boards card? */ if (pcidev->vendor != PCI_VENDOR_ID_CB) continue; - // loop through cards supported by this driver - for (index = 0; index < N_BOARDS; index++) { + /* loop through cards supported by this driver */ + for (index = 0; index < ARRAY_SIZE(cb_pcidas_boards); index++) { if (cb_pcidas_boards[index].device_id != pcidev->device) continue; - // was a particular bus/slot requested? + /* was a particular bus/slot requested? */ if (it->options[0] || it->options[1]) { - // are we on the wrong bus/slot? + /* are we on the wrong bus/slot? */ if (pcidev->bus->number != it->options[0] || PCI_SLOT(pcidev->devfn) != it->options[1]) { @@ -585,19 +583,19 @@ static int cb_pcidas_attach(struct comedi_device * dev, struct comedi_devconfig devpriv->ao_registers = pci_resource_start(devpriv->pci_dev, AO_BADRINDEX); } - // disable and clear interrupts on amcc s5933 + /* disable and clear interrupts on amcc s5933 */ outl(INTCSR_INBOX_INTR_STATUS, devpriv->s5933_config + AMCC_OP_REG_INTCSR); - // get irq - if (comedi_request_irq(devpriv->pci_dev->irq, cb_pcidas_interrupt, + /* get irq */ + if (request_irq(devpriv->pci_dev->irq, cb_pcidas_interrupt, IRQF_SHARED, "cb_pcidas", dev)) { printk(" unable to allocate irq %d\n", devpriv->pci_dev->irq); return -EINVAL; } dev->irq = devpriv->pci_dev->irq; - //Initialize dev->board_name + /* Initialize dev->board_name */ dev->board_name = thisboard->name; /* @@ -628,7 +626,7 @@ static int cb_pcidas_attach(struct comedi_device * dev, struct comedi_devconfig s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_GROUND; s->n_chan = thisboard->ao_nchan; - // analog out resolution is the same as analog input resolution, so use ai_bits + /* analog out resolution is the same as analog input resolution, so use ai_bits */ s->maxdata = (1 << thisboard->ai_bits) - 1; s->range_table = &cb_pcidas_ao_ranges; s->insn_read = cb_pcidas_ao_readback_insn; @@ -650,7 +648,7 @@ static int cb_pcidas_attach(struct comedi_device * dev, struct comedi_devconfig s = dev->subdevices + 2; subdev_8255_init(dev, s, NULL, devpriv->pacer_counter_dio + DIO_8255); - // serial EEPROM, + /* serial EEPROM, */ s = dev->subdevices + 3; s->type = COMEDI_SUBD_MEMORY; s->subdev_flags = SDF_READABLE | SDF_INTERNAL; @@ -658,7 +656,7 @@ static int cb_pcidas_attach(struct comedi_device * dev, struct comedi_devconfig s->maxdata = 0xff; s->insn_read = eeprom_read_insn; - // 8800 caldac + /* 8800 caldac */ s = dev->subdevices + 4; s->type = COMEDI_SUBD_CALIB; s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; @@ -669,7 +667,7 @@ static int cb_pcidas_attach(struct comedi_device * dev, struct comedi_devconfig for (i = 0; i < s->n_chan; i++) caldac_8800_write(dev, i, s->maxdata / 2); - // trim potentiometer + /* trim potentiometer */ s = dev->subdevices + 5; s->type = COMEDI_SUBD_CALIB; s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; @@ -685,7 +683,7 @@ static int cb_pcidas_attach(struct comedi_device * dev, struct comedi_devconfig for (i = 0; i < s->n_chan; i++) cb_pcidas_trimpot_write(dev, i, s->maxdata / 2); - // dac08 caldac + /* dac08 caldac */ s = dev->subdevices + 6; if (thisboard->has_dac08) { s->type = COMEDI_SUBD_CALIB; @@ -698,13 +696,13 @@ static int cb_pcidas_attach(struct comedi_device * dev, struct comedi_devconfig } else s->type = COMEDI_SUBD_UNUSED; - // make sure mailbox 4 is empty + /* make sure mailbox 4 is empty */ inl(devpriv->s5933_config + AMCC_OP_REG_IMB4); /* Set bits to enable incoming mailbox interrupts on amcc s5933. */ devpriv->s5933_intcsr_bits = INTCSR_INBOX_BYTE(3) | INTCSR_INBOX_SELECT(3) | INTCSR_INBOX_FULL_INT; - // clear and enable interrupt on amcc s5933 + /* clear and enable interrupt on amcc s5933 */ outl(devpriv->s5933_intcsr_bits | INTCSR_INBOX_INTR_STATUS, devpriv->s5933_config + AMCC_OP_REG_INTCSR); @@ -719,24 +717,24 @@ static int cb_pcidas_attach(struct comedi_device * dev, struct comedi_devconfig * allocated by _attach(). dev->private and dev->subdevices are * deallocated automatically by the core. */ -static int cb_pcidas_detach(struct comedi_device * dev) +static int cb_pcidas_detach(struct comedi_device *dev) { printk("comedi%d: cb_pcidas: remove\n", dev->minor); if (devpriv) { if (devpriv->s5933_config) { - // disable and clear interrupts on amcc s5933 + /* disable and clear interrupts on amcc s5933 */ outl(INTCSR_INBOX_INTR_STATUS, devpriv->s5933_config + AMCC_OP_REG_INTCSR); #ifdef CB_PCIDAS_DEBUG - rt_printk("detaching, incsr is 0x%x\n", + printk("detaching, incsr is 0x%x\n", inl(devpriv->s5933_config + AMCC_OP_REG_INTCSR)); #endif } } if (dev->irq) - comedi_free_irq(dev->irq, dev); + free_irq(dev->irq, dev); if (dev->subdevices) subdev_8255_cleanup(dev, dev->subdevices + 2); if (devpriv && devpriv->pci_dev) { @@ -753,14 +751,14 @@ static int cb_pcidas_detach(struct comedi_device * dev) * "instructions" read/write data in "one-shot" or "software-triggered" * mode. */ -static int cb_pcidas_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int cb_pcidas_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int n, i; unsigned int bits; static const int timeout = 10000; int channel; - // enable calibration input if appropriate + /* enable calibration input if appropriate */ if (insn->chanspec & CR_ALT_SOURCE) { outw(cal_enable_bits(dev), devpriv->control_status + CALIBRATION_REG); @@ -769,13 +767,13 @@ static int cb_pcidas_ai_rinsn(struct comedi_device * dev, struct comedi_subdevic outw(0, devpriv->control_status + CALIBRATION_REG); channel = CR_CHAN(insn->chanspec); } - // set mux limits and gain + /* set mux limits and gain */ bits = BEGIN_SCAN(channel) | END_SCAN(channel) | GAIN_BITS(CR_RANGE(insn->chanspec)); - // set unipolar/bipolar + /* set unipolar/bipolar */ if (CR_RANGE(insn->chanspec) & IS_UNIPOLAR) bits |= UNIP; - // set singleended/differential + /* set singleended/differential */ if (CR_AREF(insn->chanspec) != AREF_DIFF) bits |= SE; outw(bits, devpriv->control_status + ADCMUX_CONT); @@ -805,7 +803,7 @@ static int cb_pcidas_ai_rinsn(struct comedi_device * dev, struct comedi_subdevic return n; } -static int ai_config_calibration_source(struct comedi_device * dev, unsigned int * data) +static int ai_config_calibration_source(struct comedi_device *dev, unsigned int *data) { static const int num_calibration_sources = 8; unsigned int source = data[1]; @@ -820,8 +818,8 @@ static int ai_config_calibration_source(struct comedi_device * dev, unsigned int return 2; } -static int ai_config_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int ai_config_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int id = data[0]; @@ -836,44 +834,44 @@ static int ai_config_insn(struct comedi_device * dev, struct comedi_subdevice * return -EINVAL; } -// analog output insn for pcidas-1000 and 1200 series -static int cb_pcidas_ao_nofifo_winsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +/* analog output insn for pcidas-1000 and 1200 series */ +static int cb_pcidas_ao_nofifo_winsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int channel; unsigned long flags; - // set channel and range + /* set channel and range */ channel = CR_CHAN(insn->chanspec); - comedi_spin_lock_irqsave(&dev->spinlock, flags); + spin_lock_irqsave(&dev->spinlock, flags); devpriv->ao_control_bits &= ~DAC_MODE_UPDATE_BOTH & ~DAC_RANGE_MASK(channel); devpriv->ao_control_bits |= DACEN | DAC_RANGE(channel, CR_RANGE(insn->chanspec)); outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR); - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); - // remember value for readback + /* remember value for readback */ devpriv->ao_value[channel] = data[0]; - // send data + /* send data */ outw(data[0], devpriv->ao_registers + DAC_DATA_REG(channel)); return 1; } -// analog output insn for pcidas-1602 series -static int cb_pcidas_ao_fifo_winsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +/* analog output insn for pcidas-1602 series */ +static int cb_pcidas_ao_fifo_winsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int channel; unsigned long flags; - // clear dac fifo + /* clear dac fifo */ outw(0, devpriv->ao_registers + DACFIFOCLR); - // set channel and range + /* set channel and range */ channel = CR_CHAN(insn->chanspec); - comedi_spin_lock_irqsave(&dev->spinlock, flags); + spin_lock_irqsave(&dev->spinlock, flags); devpriv->ao_control_bits &= ~DAC_CHAN_EN(0) & ~DAC_CHAN_EN(1) & ~DAC_RANGE_MASK(channel) & ~DAC_PACER_MASK; @@ -881,28 +879,28 @@ static int cb_pcidas_ao_fifo_winsn(struct comedi_device * dev, struct comedi_sub DACEN | DAC_RANGE(channel, CR_RANGE(insn->chanspec)) | DAC_CHAN_EN(channel) | DAC_START; outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR); - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); - // remember value for readback + /* remember value for readback */ devpriv->ao_value[channel] = data[0]; - // send data + /* send data */ outw(data[0], devpriv->ao_registers + DACDATA); return 1; } -// analog output readback insn -// XXX loses track of analog output value back after an analog ouput command is executed -static int cb_pcidas_ao_readback_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +/* analog output readback insn */ +/* XXX loses track of analog output value back after an analog ouput command is executed */ +static int cb_pcidas_ao_readback_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { data[0] = devpriv->ao_value[CR_CHAN(insn->chanspec)]; return 1; } -static int eeprom_read_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int eeprom_read_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { uint8_t nvram_data; int retval; @@ -916,16 +914,16 @@ static int eeprom_read_insn(struct comedi_device * dev, struct comedi_subdevice return 1; } -static int caldac_write_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int caldac_write_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { const unsigned int channel = CR_CHAN(insn->chanspec); return caldac_8800_write(dev, channel, data[0]); } -static int caldac_read_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int caldac_read_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { data[0] = devpriv->caldac_value[CR_CHAN(insn->chanspec)]; @@ -933,7 +931,7 @@ static int caldac_read_insn(struct comedi_device * dev, struct comedi_subdevice } /* 1602/16 pregain offset */ -static int dac08_write(struct comedi_device * dev, unsigned int value) +static int dac08_write(struct comedi_device *dev, unsigned int value) { if (devpriv->dac08_value == value) return 1; @@ -942,32 +940,32 @@ static int dac08_write(struct comedi_device * dev, unsigned int value) outw(cal_enable_bits(dev) | (value & 0xff), devpriv->control_status + CALIBRATION_REG); - comedi_udelay(1); + udelay(1); outw(cal_enable_bits(dev) | SELECT_DAC08_BIT | (value & 0xff), devpriv->control_status + CALIBRATION_REG); - comedi_udelay(1); + udelay(1); outw(cal_enable_bits(dev) | (value & 0xff), devpriv->control_status + CALIBRATION_REG); - comedi_udelay(1); + udelay(1); return 1; } -static int dac08_write_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int dac08_write_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { return dac08_write(dev, data[0]); } -static int dac08_read_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int dac08_read_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { data[0] = devpriv->dac08_value; return 1; } -static int cb_pcidas_trimpot_write(struct comedi_device * dev, +static int cb_pcidas_trimpot_write(struct comedi_device *dev, unsigned int channel, unsigned int value) { if (devpriv->trimpot_value[channel] == value) @@ -990,16 +988,16 @@ static int cb_pcidas_trimpot_write(struct comedi_device * dev, return 1; } -static int trimpot_write_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int trimpot_write_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { unsigned int channel = CR_CHAN(insn->chanspec); return cb_pcidas_trimpot_write(dev, channel, data[0]); } -static int trimpot_read_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int trimpot_read_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { unsigned int channel = CR_CHAN(insn->chanspec); @@ -1008,8 +1006,8 @@ static int trimpot_read_insn(struct comedi_device * dev, struct comedi_subdevice return 1; } -static int cb_pcidas_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd) +static int cb_pcidas_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd) { int err = 0; int tmp; @@ -1066,7 +1064,7 @@ static int cb_pcidas_ai_cmdtest(struct comedi_device * dev, struct comedi_subdev if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) err++; - // make sure trigger sources are compatible with each other + /* make sure trigger sources are compatible with each other */ if (cmd->scan_begin_src == TRIG_FOLLOW && cmd->convert_src == TRIG_NOW) err++; if (cmd->scan_begin_src != TRIG_FOLLOW && cmd->convert_src != TRIG_NOW) @@ -1138,7 +1136,7 @@ static int cb_pcidas_ai_cmdtest(struct comedi_device * dev, struct comedi_subdev if (err) return 4; - // check channel/gain list against card's limitations + /* check channel/gain list against card's limitations */ if (cmd->chanlist) { gain = CR_RANGE(cmd->chanlist[0]); start_chan = CR_CHAN(cmd->chanlist[0]); @@ -1163,31 +1161,31 @@ static int cb_pcidas_ai_cmdtest(struct comedi_device * dev, struct comedi_subdev return 0; } -static int cb_pcidas_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s) +static int cb_pcidas_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; unsigned int bits; unsigned long flags; - // make sure CAL_EN_BIT is disabled + /* make sure CAL_EN_BIT is disabled */ outw(0, devpriv->control_status + CALIBRATION_REG); - // initialize before settings pacer source and count values + /* initialize before settings pacer source and count values */ outw(0, devpriv->control_status + TRIG_CONTSTAT); - // clear fifo + /* clear fifo */ outw(0, devpriv->adc_fifo + ADCFIFOCLR); - // set mux limits, gain and pacer source + /* set mux limits, gain and pacer source */ bits = BEGIN_SCAN(CR_CHAN(cmd->chanlist[0])) | END_SCAN(CR_CHAN(cmd->chanlist[cmd->chanlist_len - 1])) | GAIN_BITS(CR_RANGE(cmd->chanlist[0])); - // set unipolar/bipolar + /* set unipolar/bipolar */ if (CR_RANGE(cmd->chanlist[0]) & IS_UNIPOLAR) bits |= UNIP; - // set singleended/differential + /* set singleended/differential */ if (CR_AREF(cmd->chanlist[0]) != AREF_DIFF) bits |= SE; - // set pacer source + /* set pacer source */ if (cmd->convert_src == TRIG_EXT || cmd->scan_begin_src == TRIG_EXT) bits |= PACER_EXT_RISE; else @@ -1195,10 +1193,10 @@ static int cb_pcidas_ai_cmd(struct comedi_device * dev, struct comedi_subdevice outw(bits, devpriv->control_status + ADCMUX_CONT); #ifdef CB_PCIDAS_DEBUG - rt_printk("comedi: sent 0x%x to adcmux control\n", bits); + printk("comedi: sent 0x%x to adcmux control\n", bits); #endif - // load counters + /* load counters */ if (cmd->convert_src == TRIG_TIMER) cb_pcidas_load_counters(dev, &cmd->convert_arg, cmd->flags & TRIG_ROUND_MASK); @@ -1206,31 +1204,31 @@ static int cb_pcidas_ai_cmd(struct comedi_device * dev, struct comedi_subdevice cb_pcidas_load_counters(dev, &cmd->scan_begin_arg, cmd->flags & TRIG_ROUND_MASK); - // set number of conversions + /* set number of conversions */ if (cmd->stop_src == TRIG_COUNT) { devpriv->count = cmd->chanlist_len * cmd->stop_arg; } - // enable interrupts - comedi_spin_lock_irqsave(&dev->spinlock, flags); + /* enable interrupts */ + spin_lock_irqsave(&dev->spinlock, flags); devpriv->adc_fifo_bits |= INTE; devpriv->adc_fifo_bits &= ~INT_MASK; if (cmd->flags & TRIG_WAKE_EOS) { if (cmd->convert_src == TRIG_NOW && cmd->chanlist_len > 1) - devpriv->adc_fifo_bits |= INT_EOS; // interrupt end of burst + devpriv->adc_fifo_bits |= INT_EOS; /* interrupt end of burst */ else - devpriv->adc_fifo_bits |= INT_FNE; // interrupt fifo not empty + devpriv->adc_fifo_bits |= INT_FNE; /* interrupt fifo not empty */ } else { - devpriv->adc_fifo_bits |= INT_FHF; //interrupt fifo half full + devpriv->adc_fifo_bits |= INT_FHF; /* interrupt fifo half full */ } #ifdef CB_PCIDAS_DEBUG - rt_printk("comedi: adc_fifo_bits are 0x%x\n", devpriv->adc_fifo_bits); + printk("comedi: adc_fifo_bits are 0x%x\n", devpriv->adc_fifo_bits); #endif - // enable (and clear) interrupts + /* enable (and clear) interrupts */ outw(devpriv->adc_fifo_bits | EOAI | INT | LADFUL, devpriv->control_status + INT_ADCFIFO); - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); - // set start trigger and burst mode + /* set start trigger and burst mode */ bits = 0; if (cmd->start_src == TRIG_NOW) bits |= SW_TRIGGER; @@ -1244,14 +1242,14 @@ static int cb_pcidas_ai_cmd(struct comedi_device * dev, struct comedi_subdevice bits |= BURSTE; outw(bits, devpriv->control_status + TRIG_CONTSTAT); #ifdef CB_PCIDAS_DEBUG - rt_printk("comedi: sent 0x%x to trig control\n", bits); + printk("comedi: sent 0x%x to trig control\n", bits); #endif return 0; } -static int cb_pcidas_ao_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd) +static int cb_pcidas_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd) { int err = 0; int tmp; @@ -1347,7 +1345,7 @@ static int cb_pcidas_ao_cmdtest(struct comedi_device * dev, struct comedi_subdev if (err) return 4; - // check channel/gain list against card's limitations + /* check channel/gain list against card's limitations */ if (cmd->chanlist && cmd->chanlist_len > 1) { if (CR_CHAN(cmd->chanlist[0]) != 0 || CR_CHAN(cmd->chanlist[1]) != 1) { @@ -1363,32 +1361,32 @@ static int cb_pcidas_ao_cmdtest(struct comedi_device * dev, struct comedi_subdev return 0; } -static int cb_pcidas_ao_cmd(struct comedi_device * dev, struct comedi_subdevice * s) +static int cb_pcidas_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; unsigned int i; unsigned long flags; - // set channel limits, gain - comedi_spin_lock_irqsave(&dev->spinlock, flags); + /* set channel limits, gain */ + spin_lock_irqsave(&dev->spinlock, flags); for (i = 0; i < cmd->chanlist_len; i++) { - // enable channel + /* enable channel */ devpriv->ao_control_bits |= DAC_CHAN_EN(CR_CHAN(cmd->chanlist[i])); - // set range + /* set range */ devpriv->ao_control_bits |= DAC_RANGE(CR_CHAN(cmd->chanlist[i]), CR_RANGE(cmd->chanlist[i])); } - // disable analog out before settings pacer source and count values + /* disable analog out before settings pacer source and count values */ outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR); - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); - // clear fifo + /* clear fifo */ outw(0, devpriv->ao_registers + DACFIFOCLR); - // load counters + /* load counters */ if (cmd->scan_begin_src == TRIG_TIMER) { i8253_cascade_ns_to_timer_2div(TIMER_BASE, &(devpriv->ao_divisor1), &(devpriv->ao_divisor2), @@ -1400,12 +1398,12 @@ static int cb_pcidas_ao_cmd(struct comedi_device * dev, struct comedi_subdevice i8254_load(devpriv->pacer_counter_dio + DAC8254, 0, 2, devpriv->ao_divisor2, 2); } - // set number of conversions + /* set number of conversions */ if (cmd->stop_src == TRIG_COUNT) { devpriv->ao_count = cmd->chanlist_len * cmd->stop_arg; } - // set pacer source - comedi_spin_lock_irqsave(&dev->spinlock, flags); + /* set pacer source */ + spin_lock_irqsave(&dev->spinlock, flags); switch (cmd->scan_begin_src) { case TRIG_TIMER: devpriv->ao_control_bits |= DAC_PACER_INT; @@ -1414,12 +1412,12 @@ static int cb_pcidas_ao_cmd(struct comedi_device * dev, struct comedi_subdevice devpriv->ao_control_bits |= DAC_PACER_EXT_RISE; break; default: - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); comedi_error(dev, "error setting dac pacer source"); return -1; break; } - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); async->inttrig = cb_pcidas_ao_inttrig; @@ -1438,7 +1436,7 @@ static int cb_pcidas_ao_inttrig(struct comedi_device *dev, if (trig_num != 0) return -EINVAL; - // load up fifo + /* load up fifo */ if (cmd->stop_src == TRIG_COUNT && devpriv->ao_count < num_points) num_points = devpriv->ao_count; @@ -1449,34 +1447,34 @@ static int cb_pcidas_ao_inttrig(struct comedi_device *dev, if (cmd->stop_src == TRIG_COUNT) { devpriv->ao_count -= num_points; } - // write data to board's fifo + /* write data to board's fifo */ outsw(devpriv->ao_registers + DACDATA, devpriv->ao_buffer, num_bytes); - // enable dac half-full and empty interrupts - comedi_spin_lock_irqsave(&dev->spinlock, flags); + /* enable dac half-full and empty interrupts */ + spin_lock_irqsave(&dev->spinlock, flags); devpriv->adc_fifo_bits |= DAEMIE | DAHFIE; #ifdef CB_PCIDAS_DEBUG - rt_printk("comedi: adc_fifo_bits are 0x%x\n", devpriv->adc_fifo_bits); + printk("comedi: adc_fifo_bits are 0x%x\n", devpriv->adc_fifo_bits); #endif - // enable and clear interrupts + /* enable and clear interrupts */ outw(devpriv->adc_fifo_bits | DAEMI | DAHFI, devpriv->control_status + INT_ADCFIFO); - // start dac + /* start dac */ devpriv->ao_control_bits |= DAC_START | DACEN | DAC_EMPTY; outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR); #ifdef CB_PCIDAS_DEBUG - rt_printk("comedi: sent 0x%x to dac control\n", + printk("comedi: sent 0x%x to dac control\n", devpriv->ao_control_bits); #endif - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); async->inttrig = NULL; return 0; } -static irqreturn_t cb_pcidas_interrupt(int irq, void *d PT_REGS_ARG) +static irqreturn_t cb_pcidas_interrupt(int irq, void *d) { struct comedi_device *dev = (struct comedi_device *) d; struct comedi_subdevice *s = dev->read_subdev; @@ -1496,16 +1494,16 @@ static irqreturn_t cb_pcidas_interrupt(int irq, void *d PT_REGS_ARG) s5933_status = inl(devpriv->s5933_config + AMCC_OP_REG_INTCSR); #ifdef CB_PCIDAS_DEBUG - rt_printk("intcsr 0x%x\n", s5933_status); - rt_printk("mbef 0x%x\n", inl(devpriv->s5933_config + AMCC_OP_REG_MBEF)); + printk("intcsr 0x%x\n", s5933_status); + printk("mbef 0x%x\n", inl(devpriv->s5933_config + AMCC_OP_REG_MBEF)); #endif if ((INTCSR_INTR_ASSERTED & s5933_status) == 0) return IRQ_NONE; - // make sure mailbox 4 is empty + /* make sure mailbox 4 is empty */ inl_p(devpriv->s5933_config + AMCC_OP_REG_IMB4); - // clear interrupt on amcc s5933 + /* clear interrupt on amcc s5933 */ outl(devpriv->s5933_intcsr_bits | INTCSR_INBOX_INTR_STATUS, devpriv->s5933_config + AMCC_OP_REG_INTCSR); @@ -1516,14 +1514,14 @@ static irqreturn_t cb_pcidas_interrupt(int irq, void *d PT_REGS_ARG) } #endif - // check for analog output interrupt + /* check for analog output interrupt */ if (status & (DAHFI | DAEMI)) { handle_ao_interrupt(dev, status); } - // check for analog input interrupts - // if fifo half-full + /* check for analog input interrupts */ + /* if fifo half-full */ if (status & ADHFI) { - // read data + /* read data */ num_samples = half_fifo; if (async->cmd.stop_src == TRIG_COUNT && num_samples > devpriv->count) { @@ -1538,15 +1536,15 @@ static irqreturn_t cb_pcidas_interrupt(int irq, void *d PT_REGS_ARG) async->events |= COMEDI_CB_EOA; cb_pcidas_cancel(dev, s); } - // clear half-full interrupt latch - comedi_spin_lock_irqsave(&dev->spinlock, flags); + /* clear half-full interrupt latch */ + spin_lock_irqsave(&dev->spinlock, flags); outw(devpriv->adc_fifo_bits | INT, devpriv->control_status + INT_ADCFIFO); - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); - // else if fifo not empty + spin_unlock_irqrestore(&dev->spinlock, flags); + /* else if fifo not empty */ } else if (status & (ADNEI | EOBI)) { for (i = 0; i < timeout; i++) { - // break if fifo is empty + /* break if fifo is empty */ if ((ADNE & inw(devpriv->control_status + INT_ADCFIFO)) == 0) break; @@ -1557,28 +1555,28 @@ static irqreturn_t cb_pcidas_interrupt(int irq, void *d PT_REGS_ARG) break; } } - // clear not-empty interrupt latch - comedi_spin_lock_irqsave(&dev->spinlock, flags); + /* clear not-empty interrupt latch */ + spin_lock_irqsave(&dev->spinlock, flags); outw(devpriv->adc_fifo_bits | INT, devpriv->control_status + INT_ADCFIFO); - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); } else if (status & EOAI) { comedi_error(dev, "bug! encountered end of aquisition interrupt?"); - // clear EOA interrupt latch - comedi_spin_lock_irqsave(&dev->spinlock, flags); + /* clear EOA interrupt latch */ + spin_lock_irqsave(&dev->spinlock, flags); outw(devpriv->adc_fifo_bits | EOAI, devpriv->control_status + INT_ADCFIFO); - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); } - //check for fifo overflow + /* check for fifo overflow */ if (status & LADFUL) { comedi_error(dev, "fifo overflow"); - // clear overflow interrupt latch - comedi_spin_lock_irqsave(&dev->spinlock, flags); + /* clear overflow interrupt latch */ + spin_lock_irqsave(&dev->spinlock, flags); outw(devpriv->adc_fifo_bits | LADFUL, devpriv->control_status + INT_ADCFIFO); - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); cb_pcidas_cancel(dev, s); async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; } @@ -1588,23 +1586,23 @@ static irqreturn_t cb_pcidas_interrupt(int irq, void *d PT_REGS_ARG) return IRQ_HANDLED; } -static void handle_ao_interrupt(struct comedi_device * dev, unsigned int status) +static void handle_ao_interrupt(struct comedi_device *dev, unsigned int status) { struct comedi_subdevice *s = dev->write_subdev; struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; unsigned int half_fifo = thisboard->fifo_size / 2; unsigned int num_points; - unsigned int flags; + unsigned long flags; async->events = 0; if (status & DAEMI) { - // clear dac empty interrupt latch - comedi_spin_lock_irqsave(&dev->spinlock, flags); + /* clear dac empty interrupt latch */ + spin_lock_irqsave(&dev->spinlock, flags); outw(devpriv->adc_fifo_bits | DAEMI, devpriv->control_status + INT_ADCFIFO); - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); if (inw(devpriv->ao_registers + DAC_CSR) & DAC_EMPTY) { if (cmd->stop_src == TRIG_NONE || (cmd->stop_src == TRIG_COUNT @@ -1618,7 +1616,7 @@ static void handle_ao_interrupt(struct comedi_device * dev, unsigned int status) } else if (status & DAHFI) { unsigned int num_bytes; - // figure out how many points we are writing to fifo + /* figure out how many points we are writing to fifo */ num_points = half_fifo; if (cmd->stop_src == TRIG_COUNT && devpriv->ao_count < num_points) @@ -1631,33 +1629,33 @@ static void handle_ao_interrupt(struct comedi_device * dev, unsigned int status) if (async->cmd.stop_src == TRIG_COUNT) { devpriv->ao_count -= num_points; } - // write data to board's fifo + /* write data to board's fifo */ outsw(devpriv->ao_registers + DACDATA, devpriv->ao_buffer, num_points); - // clear half-full interrupt latch - comedi_spin_lock_irqsave(&dev->spinlock, flags); + /* clear half-full interrupt latch */ + spin_lock_irqsave(&dev->spinlock, flags); outw(devpriv->adc_fifo_bits | DAHFI, devpriv->control_status + INT_ADCFIFO); - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); } comedi_event(dev, s); } /* cancel analog input command */ -static int cb_pcidas_cancel(struct comedi_device * dev, struct comedi_subdevice * s) +static int cb_pcidas_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { unsigned long flags; - comedi_spin_lock_irqsave(&dev->spinlock, flags); - // disable interrupts + spin_lock_irqsave(&dev->spinlock, flags); + /* disable interrupts */ devpriv->adc_fifo_bits &= ~INTE & ~EOAIE; outw(devpriv->adc_fifo_bits, devpriv->control_status + INT_ADCFIFO); - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); - // disable start trigger source and burst mode + /* disable start trigger source and burst mode */ outw(0, devpriv->control_status + TRIG_CONTSTAT); - // software pacer source + /* software pacer source */ outw(0, devpriv->control_status + ADCMUX_CONT); return 0; @@ -1669,20 +1667,20 @@ static int cb_pcidas_ao_cancel(struct comedi_device *dev, { unsigned long flags; - comedi_spin_lock_irqsave(&dev->spinlock, flags); - // disable interrupts + spin_lock_irqsave(&dev->spinlock, flags); + /* disable interrupts */ devpriv->adc_fifo_bits &= ~DAHFIE & ~DAEMIE; outw(devpriv->adc_fifo_bits, devpriv->control_status + INT_ADCFIFO); - // disable output + /* disable output */ devpriv->ao_control_bits &= ~DACEN & ~DAC_PACER_MASK; outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR); - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); return 0; } -static void cb_pcidas_load_counters(struct comedi_device * dev, unsigned int *ns, +static void cb_pcidas_load_counters(struct comedi_device *dev, unsigned int *ns, int rounding_flags) { i8253_cascade_ns_to_timer_2div(TIMER_BASE, &(devpriv->divisor1), @@ -1695,7 +1693,7 @@ static void cb_pcidas_load_counters(struct comedi_device * dev, unsigned int *ns devpriv->divisor2, 2); } -static void write_calibration_bitstream(struct comedi_device * dev, +static void write_calibration_bitstream(struct comedi_device *dev, unsigned int register_bits, unsigned int bitstream, unsigned int bitstream_length) { @@ -1707,18 +1705,18 @@ static void write_calibration_bitstream(struct comedi_device * dev, register_bits |= SERIAL_DATA_IN_BIT; else register_bits &= ~SERIAL_DATA_IN_BIT; - comedi_udelay(write_delay); + udelay(write_delay); outw(register_bits, devpriv->control_status + CALIBRATION_REG); } } -static int caldac_8800_write(struct comedi_device * dev, unsigned int address, +static int caldac_8800_write(struct comedi_device *dev, unsigned int address, uint8_t value) { static const int num_caldac_channels = 8; static const int bitstream_length = 11; unsigned int bitstream = ((address & 0x7) << 8) | value; - static const int caldac_8800_comedi_udelay = 1; + static const int caldac_8800_udelay = 1; if (address >= num_caldac_channels) { comedi_error(dev, "illegal caldac channel"); @@ -1733,30 +1731,30 @@ static int caldac_8800_write(struct comedi_device * dev, unsigned int address, write_calibration_bitstream(dev, cal_enable_bits(dev), bitstream, bitstream_length); - comedi_udelay(caldac_8800_comedi_udelay); + udelay(caldac_8800_udelay); outw(cal_enable_bits(dev) | SELECT_8800_BIT, devpriv->control_status + CALIBRATION_REG); - comedi_udelay(caldac_8800_comedi_udelay); + udelay(caldac_8800_udelay); outw(cal_enable_bits(dev), devpriv->control_status + CALIBRATION_REG); return 1; } -static int trimpot_7376_write(struct comedi_device * dev, uint8_t value) +static int trimpot_7376_write(struct comedi_device *dev, uint8_t value) { static const int bitstream_length = 7; unsigned int bitstream = value & 0x7f; unsigned int register_bits; - static const int ad7376_comedi_udelay = 1; + static const int ad7376_udelay = 1; register_bits = cal_enable_bits(dev) | SELECT_TRIMPOT_BIT; - comedi_udelay(ad7376_comedi_udelay); + udelay(ad7376_udelay); outw(register_bits, devpriv->control_status + CALIBRATION_REG); write_calibration_bitstream(dev, register_bits, bitstream, bitstream_length); - comedi_udelay(ad7376_comedi_udelay); + udelay(ad7376_udelay); outw(cal_enable_bits(dev), devpriv->control_status + CALIBRATION_REG); return 0; @@ -1765,22 +1763,22 @@ static int trimpot_7376_write(struct comedi_device * dev, uint8_t value) /* For 1602/16 only * ch 0 : adc gain * ch 1 : adc postgain offset */ -static int trimpot_8402_write(struct comedi_device * dev, unsigned int channel, +static int trimpot_8402_write(struct comedi_device *dev, unsigned int channel, uint8_t value) { static const int bitstream_length = 10; unsigned int bitstream = ((channel & 0x3) << 8) | (value & 0xff); unsigned int register_bits; - static const int ad8402_comedi_udelay = 1; + static const int ad8402_udelay = 1; register_bits = cal_enable_bits(dev) | SELECT_TRIMPOT_BIT; - comedi_udelay(ad8402_comedi_udelay); + udelay(ad8402_udelay); outw(register_bits, devpriv->control_status + CALIBRATION_REG); write_calibration_bitstream(dev, register_bits, bitstream, bitstream_length); - comedi_udelay(ad8402_comedi_udelay); + udelay(ad8402_udelay); outw(cal_enable_bits(dev), devpriv->control_status + CALIBRATION_REG); return 0; @@ -1796,12 +1794,12 @@ static int wait_for_nvram_ready(unsigned long s5933_base_addr) AMCC_OP_REG_MCSR_NVCMD) & MCSR_NV_BUSY) == 0) return 0; - comedi_udelay(1); + udelay(1); } return -1; } -static int nvram_read(struct comedi_device * dev, unsigned int address, uint8_t * data) +static int nvram_read(struct comedi_device *dev, unsigned int address, uint8_t *data) { unsigned long iobase = devpriv->s5933_config; diff --git a/drivers/staging/comedi/drivers/cb_pcidas64.c b/drivers/staging/comedi/drivers/cb_pcidas64.c index 1a580bd2247a..210b462868b7 100644 --- a/drivers/staging/comedi/drivers/cb_pcidas64.c +++ b/drivers/staging/comedi/drivers/cb_pcidas64.c @@ -85,6 +85,7 @@ TODO: #include "../comedidev.h" #include +#include #include #include "comedi_pci.h" @@ -93,17 +94,17 @@ TODO: #include "plx9080.h" #include "comedi_fc.h" -#undef PCIDAS64_DEBUG // disable debugging code -//#define PCIDAS64_DEBUG // enable debugging code +#undef PCIDAS64_DEBUG /* disable debugging code */ +/* #define PCIDAS64_DEBUG enable debugging code */ #ifdef PCIDAS64_DEBUG -#define DEBUG_PRINT(format, args...) rt_printk(format , ## args ) +#define DEBUG_PRINT(format, args...) printk(format , ## args) #else #define DEBUG_PRINT(format, args...) #endif -#define TIMER_BASE 25 // 40MHz master clock -#define PRESCALED_TIMER_BASE 10000 // 100kHz 'prescaled' clock for slow aquisition, maybe I'll support this someday +#define TIMER_BASE 25 /* 40MHz master clock */ +#define PRESCALED_TIMER_BASE 10000 /* 100kHz 'prescaled' clock for slow aquisition, maybe I'll support this someday */ #define DMA_BUFFER_SIZE 0x1000 /* maximum value that can be loaded into board's 24-bit counters*/ @@ -111,41 +112,41 @@ static const int max_counter_value = 0xffffff; /* PCI-DAS64xxx base addresses */ -// indices of base address regions +/* indices of base address regions */ enum base_address_regions { PLX9080_BADDRINDEX = 0, MAIN_BADDRINDEX = 2, DIO_COUNTER_BADDRINDEX = 3, }; -// priv(dev)->main_iobase registers +/* priv(dev)->main_iobase registers */ enum write_only_registers { - INTR_ENABLE_REG = 0x0, // interrupt enable register - HW_CONFIG_REG = 0x2, // hardware config register + INTR_ENABLE_REG = 0x0, /* interrupt enable register */ + HW_CONFIG_REG = 0x2, /* hardware config register */ DAQ_SYNC_REG = 0xc, DAQ_ATRIG_LOW_4020_REG = 0xc, - ADC_CONTROL0_REG = 0x10, // adc control register 0 - ADC_CONTROL1_REG = 0x12, // adc control register 1 + ADC_CONTROL0_REG = 0x10, /* adc control register 0 */ + ADC_CONTROL1_REG = 0x12, /* adc control register 1 */ CALIBRATION_REG = 0x14, - ADC_SAMPLE_INTERVAL_LOWER_REG = 0x16, // lower 16 bits of adc sample interval counter - ADC_SAMPLE_INTERVAL_UPPER_REG = 0x18, // upper 8 bits of adc sample interval counter - ADC_DELAY_INTERVAL_LOWER_REG = 0x1a, // lower 16 bits of delay interval counter - ADC_DELAY_INTERVAL_UPPER_REG = 0x1c, // upper 8 bits of delay interval counter - ADC_COUNT_LOWER_REG = 0x1e, // lower 16 bits of hardware conversion/scan counter - ADC_COUNT_UPPER_REG = 0x20, // upper 8 bits of hardware conversion/scan counter - ADC_START_REG = 0x22, // software trigger to start aquisition - ADC_CONVERT_REG = 0x24, // initiates single conversion - ADC_QUEUE_CLEAR_REG = 0x26, // clears adc queue - ADC_QUEUE_LOAD_REG = 0x28, // loads adc queue + ADC_SAMPLE_INTERVAL_LOWER_REG = 0x16, /* lower 16 bits of adc sample interval counter */ + ADC_SAMPLE_INTERVAL_UPPER_REG = 0x18, /* upper 8 bits of adc sample interval counter */ + ADC_DELAY_INTERVAL_LOWER_REG = 0x1a, /* lower 16 bits of delay interval counter */ + ADC_DELAY_INTERVAL_UPPER_REG = 0x1c, /* upper 8 bits of delay interval counter */ + ADC_COUNT_LOWER_REG = 0x1e, /* lower 16 bits of hardware conversion/scan counter */ + ADC_COUNT_UPPER_REG = 0x20, /* upper 8 bits of hardware conversion/scan counter */ + ADC_START_REG = 0x22, /* software trigger to start aquisition */ + ADC_CONVERT_REG = 0x24, /* initiates single conversion */ + ADC_QUEUE_CLEAR_REG = 0x26, /* clears adc queue */ + ADC_QUEUE_LOAD_REG = 0x28, /* loads adc queue */ ADC_BUFFER_CLEAR_REG = 0x2a, - ADC_QUEUE_HIGH_REG = 0x2c, // high channel for internal queue, use adc_chan_bits() inline above - DAC_CONTROL0_REG = 0x50, // dac control register 0 - DAC_CONTROL1_REG = 0x52, // dac control register 0 - DAC_SAMPLE_INTERVAL_LOWER_REG = 0x54, // lower 16 bits of dac sample interval counter - DAC_SAMPLE_INTERVAL_UPPER_REG = 0x56, // upper 8 bits of dac sample interval counter + ADC_QUEUE_HIGH_REG = 0x2c, /* high channel for internal queue, use adc_chan_bits() inline above */ + DAC_CONTROL0_REG = 0x50, /* dac control register 0 */ + DAC_CONTROL1_REG = 0x52, /* dac control register 0 */ + DAC_SAMPLE_INTERVAL_LOWER_REG = 0x54, /* lower 16 bits of dac sample interval counter */ + DAC_SAMPLE_INTERVAL_UPPER_REG = 0x56, /* upper 8 bits of dac sample interval counter */ DAC_SELECT_REG = 0x60, DAC_START_REG = 0x64, - DAC_BUFFER_CLEAR_REG = 0x66, // clear dac buffer + DAC_BUFFER_CLEAR_REG = 0x66, /* clear dac buffer */ }; static inline unsigned int dac_convert_reg(unsigned int channel) { @@ -161,7 +162,7 @@ static inline unsigned int dac_msb_4020_reg(unsigned int channel) } enum read_only_registers { - HW_STATUS_REG = 0x0, // hardware status register, reading this apparently clears pending interrupts as well + HW_STATUS_REG = 0x0, /* hardware status register, reading this apparently clears pending interrupts as well */ PIPE1_READ_REG = 0x4, ADC_READ_PNTR_REG = 0x8, LOWER_XFER_REG = 0x10, @@ -170,13 +171,13 @@ enum read_only_registers { }; enum read_write_registers { - I8255_4020_REG = 0x48, // 8255 offset, for 4020 only - ADC_QUEUE_FIFO_REG = 0x100, // external channel/gain queue, uses same bits as ADC_QUEUE_LOAD_REG + I8255_4020_REG = 0x48, /* 8255 offset, for 4020 only */ + ADC_QUEUE_FIFO_REG = 0x100, /* external channel/gain queue, uses same bits as ADC_QUEUE_LOAD_REG */ ADC_FIFO_REG = 0x200, /* adc data fifo */ DAC_FIFO_REG = 0x300, /* dac data fifo, has weird interactions with external channel queue */ }; -// priv(dev)->dio_counter_iobase registers +/* priv(dev)->dio_counter_iobase registers */ enum dio_counter_registers { DIO_8255_OFFSET = 0x0, DO_REG = 0x20, @@ -185,47 +186,47 @@ enum dio_counter_registers { DIO_DATA_60XX_REG = 0x48, }; -// bit definitions for write-only registers +/* bit definitions for write-only registers */ enum intr_enable_contents { - ADC_INTR_SRC_MASK = 0x3, // bits that set adc interrupt source - ADC_INTR_QFULL_BITS = 0x0, // interrupt fifo quater full - ADC_INTR_EOC_BITS = 0x1, // interrupt end of conversion - ADC_INTR_EOSCAN_BITS = 0x2, // interrupt end of scan - ADC_INTR_EOSEQ_BITS = 0x3, // interrupt end of sequence (probably wont use this it's pretty fancy) - EN_ADC_INTR_SRC_BIT = 0x4, // enable adc interrupt source - EN_ADC_DONE_INTR_BIT = 0x8, // enable adc aquisition done interrupt + ADC_INTR_SRC_MASK = 0x3, /* bits that set adc interrupt source */ + ADC_INTR_QFULL_BITS = 0x0, /* interrupt fifo quater full */ + ADC_INTR_EOC_BITS = 0x1, /* interrupt end of conversion */ + ADC_INTR_EOSCAN_BITS = 0x2, /* interrupt end of scan */ + ADC_INTR_EOSEQ_BITS = 0x3, /* interrupt end of sequence (probably wont use this it's pretty fancy) */ + EN_ADC_INTR_SRC_BIT = 0x4, /* enable adc interrupt source */ + EN_ADC_DONE_INTR_BIT = 0x8, /* enable adc aquisition done interrupt */ DAC_INTR_SRC_MASK = 0x30, DAC_INTR_QEMPTY_BITS = 0x0, DAC_INTR_HIGH_CHAN_BITS = 0x10, - EN_DAC_INTR_SRC_BIT = 0x40, // enable dac interrupt source + EN_DAC_INTR_SRC_BIT = 0x40, /* enable dac interrupt source */ EN_DAC_DONE_INTR_BIT = 0x80, - EN_ADC_ACTIVE_INTR_BIT = 0x200, // enable adc active interrupt - EN_ADC_STOP_INTR_BIT = 0x400, // enable adc stop trigger interrupt - EN_DAC_ACTIVE_INTR_BIT = 0x800, // enable dac active interrupt - EN_DAC_UNDERRUN_BIT = 0x4000, // enable dac underrun status bit - EN_ADC_OVERRUN_BIT = 0x8000, // enable adc overrun status bit + EN_ADC_ACTIVE_INTR_BIT = 0x200, /* enable adc active interrupt */ + EN_ADC_STOP_INTR_BIT = 0x400, /* enable adc stop trigger interrupt */ + EN_DAC_ACTIVE_INTR_BIT = 0x800, /* enable dac active interrupt */ + EN_DAC_UNDERRUN_BIT = 0x4000, /* enable dac underrun status bit */ + EN_ADC_OVERRUN_BIT = 0x8000, /* enable adc overrun status bit */ }; enum hw_config_contents { - MASTER_CLOCK_4020_MASK = 0x3, // bits that specify master clock source for 4020 - INTERNAL_CLOCK_4020_BITS = 0x1, // use 40 MHz internal master clock for 4020 - BNC_CLOCK_4020_BITS = 0x2, // use BNC input for master clock - EXT_CLOCK_4020_BITS = 0x3, // use dio input for master clock - EXT_QUEUE_BIT = 0x200, // use external channel/gain queue (more versatile than internal queue) - SLOW_DAC_BIT = 0x400, // use 225 nanosec strobe when loading dac instead of 50 nanosec - HW_CONFIG_DUMMY_BITS = 0x2000, // bit with unknown function yet given as default value in pci-das64 manual - DMA_CH_SELECT_BIT = 0x8000, // bit selects channels 1/0 for analog input/output, otherwise 0/1 - FIFO_SIZE_REG = 0x4, // allows adjustment of fifo sizes - DAC_FIFO_SIZE_MASK = 0xff00, // bits that set dac fifo size + MASTER_CLOCK_4020_MASK = 0x3, /* bits that specify master clock source for 4020 */ + INTERNAL_CLOCK_4020_BITS = 0x1, /* use 40 MHz internal master clock for 4020 */ + BNC_CLOCK_4020_BITS = 0x2, /* use BNC input for master clock */ + EXT_CLOCK_4020_BITS = 0x3, /* use dio input for master clock */ + EXT_QUEUE_BIT = 0x200, /* use external channel/gain queue (more versatile than internal queue) */ + SLOW_DAC_BIT = 0x400, /* use 225 nanosec strobe when loading dac instead of 50 nanosec */ + HW_CONFIG_DUMMY_BITS = 0x2000, /* bit with unknown function yet given as default value in pci-das64 manual */ + DMA_CH_SELECT_BIT = 0x8000, /* bit selects channels 1/0 for analog input/output, otherwise 0/1 */ + FIFO_SIZE_REG = 0x4, /* allows adjustment of fifo sizes */ + DAC_FIFO_SIZE_MASK = 0xff00, /* bits that set dac fifo size */ DAC_FIFO_BITS = 0xf800, /* 8k sample ao fifo */ }; #define DAC_FIFO_SIZE 0x2000 enum daq_atrig_low_4020_contents { - EXT_AGATE_BNC_BIT = 0x8000, // use trig/ext clk bnc input for analog gate signal - EXT_STOP_TRIG_BNC_BIT = 0x4000, // use trig/ext clk bnc input for external stop trigger signal - EXT_START_TRIG_BNC_BIT = 0x2000, // use trig/ext clk bnc input for external start trigger signal + EXT_AGATE_BNC_BIT = 0x8000, /* use trig/ext clk bnc input for analog gate signal */ + EXT_STOP_TRIG_BNC_BIT = 0x4000, /* use trig/ext clk bnc input for external stop trigger signal */ + EXT_START_TRIG_BNC_BIT = 0x2000, /* use trig/ext clk bnc input for external start trigger signal */ }; static inline uint16_t analog_trig_low_threshold_bits(uint16_t threshold) { @@ -233,34 +234,34 @@ static inline uint16_t analog_trig_low_threshold_bits(uint16_t threshold) } enum adc_control0_contents { - ADC_GATE_SRC_MASK = 0x3, // bits that select gate - ADC_SOFT_GATE_BITS = 0x1, // software gate - ADC_EXT_GATE_BITS = 0x2, // external digital gate - ADC_ANALOG_GATE_BITS = 0x3, // analog level gate - ADC_GATE_LEVEL_BIT = 0x4, // level-sensitive gate (for digital) - ADC_GATE_POLARITY_BIT = 0x8, // gate active low + ADC_GATE_SRC_MASK = 0x3, /* bits that select gate */ + ADC_SOFT_GATE_BITS = 0x1, /* software gate */ + ADC_EXT_GATE_BITS = 0x2, /* external digital gate */ + ADC_ANALOG_GATE_BITS = 0x3, /* analog level gate */ + ADC_GATE_LEVEL_BIT = 0x4, /* level-sensitive gate (for digital) */ + ADC_GATE_POLARITY_BIT = 0x8, /* gate active low */ ADC_START_TRIG_SOFT_BITS = 0x10, ADC_START_TRIG_EXT_BITS = 0x20, ADC_START_TRIG_ANALOG_BITS = 0x30, ADC_START_TRIG_MASK = 0x30, - ADC_START_TRIG_FALLING_BIT = 0x40, // trig 1 uses falling edge - ADC_EXT_CONV_FALLING_BIT = 0x800, // external pacing uses falling edge - ADC_SAMPLE_COUNTER_EN_BIT = 0x1000, // enable hardware scan counter - ADC_DMA_DISABLE_BIT = 0x4000, // disables dma - ADC_ENABLE_BIT = 0x8000, // master adc enable + ADC_START_TRIG_FALLING_BIT = 0x40, /* trig 1 uses falling edge */ + ADC_EXT_CONV_FALLING_BIT = 0x800, /* external pacing uses falling edge */ + ADC_SAMPLE_COUNTER_EN_BIT = 0x1000, /* enable hardware scan counter */ + ADC_DMA_DISABLE_BIT = 0x4000, /* disables dma */ + ADC_ENABLE_BIT = 0x8000, /* master adc enable */ }; enum adc_control1_contents { - ADC_QUEUE_CONFIG_BIT = 0x1, // should be set for boards with > 16 channels + ADC_QUEUE_CONFIG_BIT = 0x1, /* should be set for boards with > 16 channels */ CONVERT_POLARITY_BIT = 0x10, EOC_POLARITY_BIT = 0x20, - ADC_SW_GATE_BIT = 0x40, // software gate of adc - ADC_DITHER_BIT = 0x200, // turn on extra noise for dithering + ADC_SW_GATE_BIT = 0x40, /* software gate of adc */ + ADC_DITHER_BIT = 0x200, /* turn on extra noise for dithering */ RETRIGGER_BIT = 0x800, ADC_LO_CHANNEL_4020_MASK = 0x300, ADC_HI_CHANNEL_4020_MASK = 0xc00, - TWO_CHANNEL_4020_BITS = 0x1000, // two channel mode for 4020 - FOUR_CHANNEL_4020_BITS = 0x2000, // four channel mode for 4020 + TWO_CHANNEL_4020_BITS = 0x1000, /* two channel mode for 4020 */ + FOUR_CHANNEL_4020_BITS = 0x2000, /* four channel mode for 4020 */ CHANNEL_MODE_4020_MASK = 0x3000, ADC_MODE_MASK = 0xf000, }; @@ -281,10 +282,10 @@ enum calibration_contents { SELECT_8800_BIT = 0x1, SELECT_8402_64XX_BIT = 0x2, SELECT_1590_60XX_BIT = 0x2, - CAL_EN_64XX_BIT = 0x40, // calibration enable for 64xx series + CAL_EN_64XX_BIT = 0x40, /* calibration enable for 64xx series */ SERIAL_DATA_IN_BIT = 0x80, SERIAL_CLOCK_BIT = 0x100, - CAL_EN_60XX_BIT = 0x200, // calibration enable for 60xx series + CAL_EN_60XX_BIT = 0x200, /* calibration enable for 60xx series */ CAL_GAIN_BIT = 0x800, }; /* calibration sources for 6025 are: @@ -308,11 +309,11 @@ static inline uint16_t adc_convert_chan_4020_bits(unsigned int channel) }; enum adc_queue_load_contents { - UNIP_BIT = 0x800, // unipolar/bipolar bit - ADC_SE_DIFF_BIT = 0x1000, // single-ended/ differential bit - ADC_COMMON_BIT = 0x2000, // non-referenced single-ended (common-mode input) - QUEUE_EOSEQ_BIT = 0x4000, // queue end of sequence - QUEUE_EOSCAN_BIT = 0x8000, // queue end of scan + UNIP_BIT = 0x800, /* unipolar/bipolar bit */ + ADC_SE_DIFF_BIT = 0x1000, /* single-ended/ differential bit */ + ADC_COMMON_BIT = 0x2000, /* non-referenced single-ended (common-mode input) */ + QUEUE_EOSEQ_BIT = 0x4000, /* queue end of sequence */ + QUEUE_EOSCAN_BIT = 0x8000, /* queue end of scan */ }; static inline uint16_t adc_chan_bits(unsigned int channel) { @@ -320,7 +321,7 @@ static inline uint16_t adc_chan_bits(unsigned int channel) }; enum dac_control0_contents { - DAC_ENABLE_BIT = 0x8000, // dac controller enable bit + DAC_ENABLE_BIT = 0x8000, /* dac controller enable bit */ DAC_CYCLIC_STOP_BIT = 0x4000, DAC_WAVEFORM_MODE_BIT = 0x100, DAC_EXT_UPDATE_FALLING_BIT = 0x80, @@ -340,14 +341,14 @@ enum dac_control1_contents { DAC_WRITE_POLARITY_BIT = 0x800, /* board-dependent setting */ DAC1_EXT_REF_BIT = 0x200, DAC0_EXT_REF_BIT = 0x100, - DAC_OUTPUT_ENABLE_BIT = 0x80, // dac output enable bit + DAC_OUTPUT_ENABLE_BIT = 0x80, /* dac output enable bit */ DAC_UPDATE_POLARITY_BIT = 0x40, /* board-dependent setting */ DAC_SW_GATE_BIT = 0x20, DAC1_UNIPOLAR_BIT = 0x8, DAC0_UNIPOLAR_BIT = 0x2, }; -// bit definitions for read-only registers +/* bit definitions for read-only registers */ enum hw_status_contents { DAC_UNDERRUN_BIT = 0x1, ADC_OVERRUN_BIT = 0x2, @@ -378,7 +379,7 @@ static inline unsigned int adc_upper_write_ptr_code(uint16_t prepost_bits) return (prepost_bits >> 14) & 0x3; } -// I2C addresses for 4020 +/* I2C addresses for 4020 */ enum i2c_addresses { RANGE_CAL_I2C_ADDR = 0x20, CALDAC0_I2C_ADDR = 0xc, @@ -386,8 +387,8 @@ enum i2c_addresses { }; enum range_cal_i2c_contents { - ADC_SRC_4020_MASK = 0x70, // bits that set what source the adc converter measures - BNC_TRIG_THRESHOLD_0V_BIT = 0x80, // make bnc trig/ext clock threshold 0V instead of 2.5V + ADC_SRC_4020_MASK = 0x70, /* bits that set what source the adc converter measures */ + BNC_TRIG_THRESHOLD_0V_BIT = 0x80, /* make bnc trig/ext clock threshold 0V instead of 2.5V */ }; static inline uint8_t adc_src_4020_bits(unsigned int source) { @@ -395,11 +396,11 @@ static inline uint8_t adc_src_4020_bits(unsigned int source) }; static inline uint8_t attenuate_bit(unsigned int channel) { - // attenuate channel (+-5V input range) + /* attenuate channel (+-5V input range) */ return 1 << (channel & 0x3); }; -// analog input ranges for 64xx boards +/* analog input ranges for 64xx boards */ static const struct comedi_lrange ai_ranges_64xx = { 8, { @@ -468,7 +469,7 @@ static const struct comedi_lrange ai_ranges_6052 = { } }; -// analog input ranges for 4020 board +/* analog input ranges for 4020 board */ static const struct comedi_lrange ai_ranges_4020 = { 2, { @@ -477,7 +478,7 @@ static const struct comedi_lrange ai_ranges_4020 = { } }; -// analog output ranges +/* analog output ranges */ static const struct comedi_lrange ao_ranges_64xx = { 4, { @@ -543,40 +544,40 @@ struct hw_fifo_info { struct pcidas64_board { const char *name; - int device_id; // pci device id - int ai_se_chans; // number of ai inputs in single-ended mode - int ai_bits; // analog input resolution - int ai_speed; // fastest conversion period in ns + int device_id; /* pci device id */ + int ai_se_chans; /* number of ai inputs in single-ended mode */ + int ai_bits; /* analog input resolution */ + int ai_speed; /* fastest conversion period in ns */ const struct comedi_lrange *ai_range_table; - int ao_nchan; // number of analog out channels - int ao_bits; // analog output resolution - int ao_scan_speed; // analog output speed (for a scan, not conversion) + int ao_nchan; /* number of analog out channels */ + int ao_bits; /* analog output resolution */ + int ao_scan_speed; /* analog output speed (for a scan, not conversion) */ const struct comedi_lrange *ao_range_table; const int *ao_range_code; const struct hw_fifo_info *const ai_fifo; - enum register_layout layout; // different board families have slightly different registers + enum register_layout layout; /* different board families have slightly different registers */ unsigned has_8255:1; }; static const struct hw_fifo_info ai_fifo_4020 = { - num_segments:2, - max_segment_length:0x8000, - sample_packing_ratio:2, - fifo_size_reg_mask:0x7f, + .num_segments = 2, + .max_segment_length = 0x8000, + .sample_packing_ratio = 2, + .fifo_size_reg_mask = 0x7f, }; static const struct hw_fifo_info ai_fifo_64xx = { - num_segments:4, - max_segment_length:0x800, - sample_packing_ratio:1, - fifo_size_reg_mask:0x3f, + .num_segments = 4, + .max_segment_length = 0x800, + .sample_packing_ratio = 1, + .fifo_size_reg_mask = 0x3f, }; static const struct hw_fifo_info ai_fifo_60xx = { - num_segments:4, - max_segment_length:0x800, - sample_packing_ratio:1, - fifo_size_reg_mask:0x7f, + .num_segments = 4, + .max_segment_length = 0x800, + .sample_packing_ratio = 1, + .fifo_size_reg_mask = 0x7f, }; /* maximum number of dma transfers we will chain together into a ring @@ -584,7 +585,7 @@ static const struct hw_fifo_info ai_fifo_60xx = { #define MAX_AI_DMA_RING_COUNT (0x80000 / DMA_BUFFER_SIZE) #define MIN_AI_DMA_RING_COUNT (0x10000 / DMA_BUFFER_SIZE) #define AO_DMA_RING_COUNT (0x10000 / DMA_BUFFER_SIZE) -static inline unsigned int ai_dma_ring_count(struct pcidas64_board * board) +static inline unsigned int ai_dma_ring_count(struct pcidas64_board *board) { if (board->layout == LAYOUT_4020) return MAX_AI_DMA_RING_COUNT; @@ -596,84 +597,84 @@ static const int bytes_in_sample = 2; static const struct pcidas64_board pcidas64_boards[] = { { - name: "pci-das6402/16", - device_id:0x1d, - ai_se_chans:64, - ai_bits: 16, - ai_speed:5000, - ao_nchan:2, - ao_bits: 16, - ao_scan_speed:10000, - layout: LAYOUT_64XX, - ai_range_table:&ai_ranges_64xx, - ao_range_table:&ao_ranges_64xx, - ao_range_code:ao_range_code_64xx, - ai_fifo: &ai_fifo_64xx, - has_8255:1, + .name = "pci-das6402/16", + .device_id = 0x1d, + .ai_se_chans = 64, + .ai_bits = 16, + .ai_speed = 5000, + .ao_nchan = 2, + .ao_bits = 16, + .ao_scan_speed = 10000, + .layout = LAYOUT_64XX, + .ai_range_table = &ai_ranges_64xx, + .ao_range_table = &ao_ranges_64xx, + .ao_range_code = ao_range_code_64xx, + .ai_fifo = &ai_fifo_64xx, + .has_8255 = 1, }, { - name: "pci-das6402/12", // XXX check - device_id:0x1e, - ai_se_chans:64, - ai_bits: 12, - ai_speed:5000, - ao_nchan:2, - ao_bits: 12, - ao_scan_speed:10000, - layout: LAYOUT_64XX, - ai_range_table:&ai_ranges_64xx, - ao_range_table:&ao_ranges_64xx, - ao_range_code:ao_range_code_64xx, - ai_fifo: &ai_fifo_64xx, - has_8255:1, + .name = "pci-das6402/12", /* XXX check */ + .device_id = 0x1e, + .ai_se_chans = 64, + .ai_bits = 12, + .ai_speed = 5000, + .ao_nchan = 2, + .ao_bits = 12, + .ao_scan_speed = 10000, + .layout = LAYOUT_64XX, + .ai_range_table = &ai_ranges_64xx, + .ao_range_table = &ao_ranges_64xx, + .ao_range_code = ao_range_code_64xx, + .ai_fifo = &ai_fifo_64xx, + .has_8255 = 1, }, { - name: "pci-das64/m1/16", - device_id:0x35, - ai_se_chans:64, - ai_bits: 16, - ai_speed:1000, - ao_nchan:2, - ao_bits: 16, - ao_scan_speed:10000, - layout: LAYOUT_64XX, - ai_range_table:&ai_ranges_64xx, - ao_range_table:&ao_ranges_64xx, - ao_range_code:ao_range_code_64xx, - ai_fifo: &ai_fifo_64xx, - has_8255:1, + .name = "pci-das64/m1/16", + .device_id = 0x35, + .ai_se_chans = 64, + .ai_bits = 16, + .ai_speed = 1000, + .ao_nchan = 2, + .ao_bits = 16, + .ao_scan_speed = 10000, + .layout = LAYOUT_64XX, + .ai_range_table = &ai_ranges_64xx, + .ao_range_table = &ao_ranges_64xx, + .ao_range_code = ao_range_code_64xx, + .ai_fifo = &ai_fifo_64xx, + .has_8255 = 1, }, { - name: "pci-das64/m2/16", - device_id:0x36, - ai_se_chans:64, - ai_bits: 16, - ai_speed:500, - ao_nchan:2, - ao_bits: 16, - ao_scan_speed:10000, - layout: LAYOUT_64XX, - ai_range_table:&ai_ranges_64xx, - ao_range_table:&ao_ranges_64xx, - ao_range_code:ao_range_code_64xx, - ai_fifo: &ai_fifo_64xx, - has_8255:1, + .name = "pci-das64/m2/16", + .device_id = 0x36, + .ai_se_chans = 64, + .ai_bits = 16, + .ai_speed = 500, + .ao_nchan = 2, + .ao_bits = 16, + .ao_scan_speed = 10000, + .layout = LAYOUT_64XX, + .ai_range_table = &ai_ranges_64xx, + .ao_range_table = &ao_ranges_64xx, + .ao_range_code = ao_range_code_64xx, + .ai_fifo = &ai_fifo_64xx, + .has_8255 = 1, }, { - name: "pci-das64/m3/16", - device_id:0x37, - ai_se_chans:64, - ai_bits: 16, - ai_speed:333, - ao_nchan:2, - ao_bits: 16, - ao_scan_speed:10000, - layout: LAYOUT_64XX, - ai_range_table:&ai_ranges_64xx, - ao_range_table:&ao_ranges_64xx, - ao_range_code:ao_range_code_64xx, - ai_fifo: &ai_fifo_64xx, - has_8255:1, + .name = "pci-das64/m3/16", + .device_id = 0x37, + .ai_se_chans = 64, + .ai_bits = 16, + .ai_speed = 333, + .ao_nchan = 2, + .ao_bits = 16, + .ao_scan_speed = 10000, + .layout = LAYOUT_64XX, + .ai_range_table = &ai_ranges_64xx, + .ao_range_table = &ao_ranges_64xx, + .ao_range_code = ao_range_code_64xx, + .ai_fifo = &ai_fifo_64xx, + .has_8255 = 1, }, { .name = "pci-das6013", @@ -691,334 +692,328 @@ static const struct pcidas64_board pcidas64_boards[] = { .has_8255 = 0, }, { - name: "pci-das6014", - device_id:0x79, - ai_se_chans:16, - ai_bits: 16, - ai_speed:5000, - ao_nchan:2, - ao_bits: 16, - ao_scan_speed:100000, - layout: LAYOUT_60XX, - ai_range_table:&ai_ranges_60xx, - ao_range_table:&ao_ranges_60xx, - ao_range_code:ao_range_code_60xx, - ai_fifo: &ai_fifo_60xx, - has_8255:0, + .name = "pci-das6014", + .device_id = 0x79, + .ai_se_chans = 16, + .ai_bits = 16, + .ai_speed = 5000, + .ao_nchan = 2, + .ao_bits = 16, + .ao_scan_speed = 100000, + .layout = LAYOUT_60XX, + .ai_range_table = &ai_ranges_60xx, + .ao_range_table = &ao_ranges_60xx, + .ao_range_code = ao_range_code_60xx, + .ai_fifo = &ai_fifo_60xx, + .has_8255 = 0, }, { - name: "pci-das6023", - device_id:0x5d, - ai_se_chans:16, - ai_bits: 12, - ai_speed:5000, - ao_nchan:0, - ao_scan_speed:100000, - layout: LAYOUT_60XX, - ai_range_table:&ai_ranges_60xx, - ao_range_table:&ao_ranges_60xx, - ao_range_code:ao_range_code_60xx, - ai_fifo: &ai_fifo_60xx, - has_8255:1, + .name = "pci-das6023", + .device_id = 0x5d, + .ai_se_chans = 16, + .ai_bits = 12, + .ai_speed = 5000, + .ao_nchan = 0, + .ao_scan_speed = 100000, + .layout = LAYOUT_60XX, + .ai_range_table = &ai_ranges_60xx, + .ao_range_table = &ao_ranges_60xx, + .ao_range_code = ao_range_code_60xx, + .ai_fifo = &ai_fifo_60xx, + .has_8255 = 1, }, { - name: "pci-das6025", - device_id:0x5e, - ai_se_chans:16, - ai_bits: 12, - ai_speed:5000, - ao_nchan:2, - ao_bits: 12, - ao_scan_speed:100000, - layout: LAYOUT_60XX, - ai_range_table:&ai_ranges_60xx, - ao_range_table:&ao_ranges_60xx, - ao_range_code:ao_range_code_60xx, - ai_fifo: &ai_fifo_60xx, - has_8255:1, + .name = "pci-das6025", + .device_id = 0x5e, + .ai_se_chans = 16, + .ai_bits = 12, + .ai_speed = 5000, + .ao_nchan = 2, + .ao_bits = 12, + .ao_scan_speed = 100000, + .layout = LAYOUT_60XX, + .ai_range_table = &ai_ranges_60xx, + .ao_range_table = &ao_ranges_60xx, + .ao_range_code = ao_range_code_60xx, + .ai_fifo = &ai_fifo_60xx, + .has_8255 = 1, }, { - name: "pci-das6030", - device_id:0x5f, - ai_se_chans:16, - ai_bits: 16, - ai_speed:10000, - ao_nchan:2, - ao_bits: 16, - ao_scan_speed:10000, - layout: LAYOUT_60XX, - ai_range_table:&ai_ranges_6030, - ao_range_table:&ao_ranges_6030, - ao_range_code:ao_range_code_6030, - ai_fifo: &ai_fifo_60xx, - has_8255:0, + .name = "pci-das6030", + .device_id = 0x5f, + .ai_se_chans = 16, + .ai_bits = 16, + .ai_speed = 10000, + .ao_nchan = 2, + .ao_bits = 16, + .ao_scan_speed = 10000, + .layout = LAYOUT_60XX, + .ai_range_table = &ai_ranges_6030, + .ao_range_table = &ao_ranges_6030, + .ao_range_code = ao_range_code_6030, + .ai_fifo = &ai_fifo_60xx, + .has_8255 = 0, }, { - name: "pci-das6031", - device_id:0x60, - ai_se_chans:64, - ai_bits: 16, - ai_speed:10000, - ao_nchan:2, - ao_bits: 16, - ao_scan_speed:10000, - layout: LAYOUT_60XX, - ai_range_table:&ai_ranges_6030, - ao_range_table:&ao_ranges_6030, - ao_range_code:ao_range_code_6030, - ai_fifo: &ai_fifo_60xx, - has_8255:0, + .name = "pci-das6031", + .device_id = 0x60, + .ai_se_chans = 64, + .ai_bits = 16, + .ai_speed = 10000, + .ao_nchan = 2, + .ao_bits = 16, + .ao_scan_speed = 10000, + .layout = LAYOUT_60XX, + .ai_range_table = &ai_ranges_6030, + .ao_range_table = &ao_ranges_6030, + .ao_range_code = ao_range_code_6030, + .ai_fifo = &ai_fifo_60xx, + .has_8255 = 0, }, { - name: "pci-das6032", - device_id:0x61, - ai_se_chans:16, - ai_bits: 16, - ai_speed:10000, - ao_nchan:0, - layout: LAYOUT_60XX, - ai_range_table:&ai_ranges_6030, - ai_fifo: &ai_fifo_60xx, - has_8255:0, + .name = "pci-das6032", + .device_id = 0x61, + .ai_se_chans = 16, + .ai_bits = 16, + .ai_speed = 10000, + .ao_nchan = 0, + .layout = LAYOUT_60XX, + .ai_range_table = &ai_ranges_6030, + .ai_fifo = &ai_fifo_60xx, + .has_8255 = 0, }, { - name: "pci-das6033", - device_id:0x62, - ai_se_chans:64, - ai_bits: 16, - ai_speed:10000, - ao_nchan:0, - layout: LAYOUT_60XX, - ai_range_table:&ai_ranges_6030, - ai_fifo: &ai_fifo_60xx, - has_8255:0, + .name = "pci-das6033", + .device_id = 0x62, + .ai_se_chans = 64, + .ai_bits = 16, + .ai_speed = 10000, + .ao_nchan = 0, + .layout = LAYOUT_60XX, + .ai_range_table = &ai_ranges_6030, + .ai_fifo = &ai_fifo_60xx, + .has_8255 = 0, }, { - name: "pci-das6034", - device_id:0x63, - ai_se_chans:16, - ai_bits: 16, - ai_speed:5000, - ao_nchan:0, - ao_scan_speed:0, - layout: LAYOUT_60XX, - ai_range_table:&ai_ranges_60xx, - ai_fifo: &ai_fifo_60xx, - has_8255:0, + .name = "pci-das6034", + .device_id = 0x63, + .ai_se_chans = 16, + .ai_bits = 16, + .ai_speed = 5000, + .ao_nchan = 0, + .ao_scan_speed = 0, + .layout = LAYOUT_60XX, + .ai_range_table = &ai_ranges_60xx, + .ai_fifo = &ai_fifo_60xx, + .has_8255 = 0, }, { - name: "pci-das6035", - device_id:0x64, - ai_se_chans:16, - ai_bits: 16, - ai_speed:5000, - ao_nchan:2, - ao_bits: 12, - ao_scan_speed:100000, - layout: LAYOUT_60XX, - ai_range_table:&ai_ranges_60xx, - ao_range_table:&ao_ranges_60xx, - ao_range_code:ao_range_code_60xx, - ai_fifo: &ai_fifo_60xx, - has_8255:0, + .name = "pci-das6035", + .device_id = 0x64, + .ai_se_chans = 16, + .ai_bits = 16, + .ai_speed = 5000, + .ao_nchan = 2, + .ao_bits = 12, + .ao_scan_speed = 100000, + .layout = LAYOUT_60XX, + .ai_range_table = &ai_ranges_60xx, + .ao_range_table = &ao_ranges_60xx, + .ao_range_code = ao_range_code_60xx, + .ai_fifo = &ai_fifo_60xx, + .has_8255 = 0, }, { - name: "pci-das6036", - device_id:0x6f, - ai_se_chans:16, - ai_bits: 16, - ai_speed:5000, - ao_nchan:2, - ao_bits: 16, - ao_scan_speed:100000, - layout: LAYOUT_60XX, - ai_range_table:&ai_ranges_60xx, - ao_range_table:&ao_ranges_60xx, - ao_range_code:ao_range_code_60xx, - ai_fifo: &ai_fifo_60xx, - has_8255:0, + .name = "pci-das6036", + .device_id = 0x6f, + .ai_se_chans = 16, + .ai_bits = 16, + .ai_speed = 5000, + .ao_nchan = 2, + .ao_bits = 16, + .ao_scan_speed = 100000, + .layout = LAYOUT_60XX, + .ai_range_table = &ai_ranges_60xx, + .ao_range_table = &ao_ranges_60xx, + .ao_range_code = ao_range_code_60xx, + .ai_fifo = &ai_fifo_60xx, + .has_8255 = 0, }, { - name: "pci-das6040", - device_id:0x65, - ai_se_chans:16, - ai_bits: 12, - ai_speed:2000, - ao_nchan:2, - ao_bits: 12, - ao_scan_speed:1000, - layout: LAYOUT_60XX, - ai_range_table:&ai_ranges_6052, - ao_range_table:&ao_ranges_6030, - ao_range_code:ao_range_code_6030, - ai_fifo: &ai_fifo_60xx, - has_8255:0, + .name = "pci-das6040", + .device_id = 0x65, + .ai_se_chans = 16, + .ai_bits = 12, + .ai_speed = 2000, + .ao_nchan = 2, + .ao_bits = 12, + .ao_scan_speed = 1000, + .layout = LAYOUT_60XX, + .ai_range_table = &ai_ranges_6052, + .ao_range_table = &ao_ranges_6030, + .ao_range_code = ao_range_code_6030, + .ai_fifo = &ai_fifo_60xx, + .has_8255 = 0, }, { - name: "pci-das6052", - device_id:0x66, - ai_se_chans:16, - ai_bits: 16, - ai_speed:3333, - ao_nchan:2, - ao_bits: 16, - ao_scan_speed:3333, - layout: LAYOUT_60XX, - ai_range_table:&ai_ranges_6052, - ao_range_table:&ao_ranges_6030, - ao_range_code:ao_range_code_6030, - ai_fifo: &ai_fifo_60xx, - has_8255:0, + .name = "pci-das6052", + .device_id = 0x66, + .ai_se_chans = 16, + .ai_bits = 16, + .ai_speed = 3333, + .ao_nchan = 2, + .ao_bits = 16, + .ao_scan_speed = 3333, + .layout = LAYOUT_60XX, + .ai_range_table = &ai_ranges_6052, + .ao_range_table = &ao_ranges_6030, + .ao_range_code = ao_range_code_6030, + .ai_fifo = &ai_fifo_60xx, + .has_8255 = 0, }, { - name: "pci-das6070", - device_id:0x67, - ai_se_chans:16, - ai_bits: 12, - ai_speed:800, - ao_nchan:2, - ao_bits: 12, - ao_scan_speed:1000, - layout: LAYOUT_60XX, - ai_range_table:&ai_ranges_6052, - ao_range_table:&ao_ranges_6030, - ao_range_code:ao_range_code_6030, - ai_fifo: &ai_fifo_60xx, - has_8255:0, + .name = "pci-das6070", + .device_id = 0x67, + .ai_se_chans = 16, + .ai_bits = 12, + .ai_speed = 800, + .ao_nchan = 2, + .ao_bits = 12, + .ao_scan_speed = 1000, + .layout = LAYOUT_60XX, + .ai_range_table = &ai_ranges_6052, + .ao_range_table = &ao_ranges_6030, + .ao_range_code = ao_range_code_6030, + .ai_fifo = &ai_fifo_60xx, + .has_8255 = 0, }, { - name: "pci-das6071", - device_id:0x68, - ai_se_chans:64, - ai_bits: 12, - ai_speed:800, - ao_nchan:2, - ao_bits: 12, - ao_scan_speed:1000, - layout: LAYOUT_60XX, - ai_range_table:&ai_ranges_6052, - ao_range_table:&ao_ranges_6030, - ao_range_code:ao_range_code_6030, - ai_fifo: &ai_fifo_60xx, - has_8255:0, + .name = "pci-das6071", + .device_id = 0x68, + .ai_se_chans = 64, + .ai_bits = 12, + .ai_speed = 800, + .ao_nchan = 2, + .ao_bits = 12, + .ao_scan_speed = 1000, + .layout = LAYOUT_60XX, + .ai_range_table = &ai_ranges_6052, + .ao_range_table = &ao_ranges_6030, + .ao_range_code = ao_range_code_6030, + .ai_fifo = &ai_fifo_60xx, + .has_8255 = 0, }, { - name: "pci-das4020/12", - device_id:0x52, - ai_se_chans:4, - ai_bits: 12, - ai_speed:50, - ao_bits: 12, - ao_nchan:2, - ao_scan_speed:0, // no hardware pacing on ao - layout: LAYOUT_4020, - ai_range_table:&ai_ranges_4020, - ao_range_table:&ao_ranges_4020, - ao_range_code:ao_range_code_4020, - ai_fifo: &ai_fifo_4020, - has_8255:1, + .name = "pci-das4020/12", + .device_id = 0x52, + .ai_se_chans = 4, + .ai_bits = 12, + .ai_speed = 50, + .ao_bits = 12, + .ao_nchan = 2, + .ao_scan_speed = 0, /* no hardware pacing on ao */ + .layout = LAYOUT_4020, + .ai_range_table = &ai_ranges_4020, + .ao_range_table = &ao_ranges_4020, + .ao_range_code = ao_range_code_4020, + .ai_fifo = &ai_fifo_4020, + .has_8255 = 1, }, #if 0 { - name: "pci-das6402/16/jr", - device_id:0 // XXX, - ai_se_chans:64, - ai_bits: 16, - ai_speed:5000, - ao_nchan:0, - ao_scan_speed:10000, - layout: LAYOUT_64XX, - ai_range_table:&ai_ranges_64xx, - ai_fifo: ai_fifo_64xx, - has_8255:1, + .name = "pci-das6402/16/jr", + .device_id = 0 /* XXX, */ + .ai_se_chans = 64, + .ai_bits = 16, + .ai_speed = 5000, + .ao_nchan = 0, + .ao_scan_speed = 10000, + .layout = LAYOUT_64XX, + .ai_range_table = &ai_ranges_64xx, + .ai_fifo = ai_fifo_64xx, + .has_8255 = 1, }, { - name: "pci-das64/m1/16/jr", - device_id:0 // XXX, - ai_se_chans:64, - ai_bits: 16, - ai_speed:1000, - ao_nchan:0, - ao_scan_speed:10000, - layout: LAYOUT_64XX, - ai_range_table:&ai_ranges_64xx, - ai_fifo: ai_fifo_64xx, - has_8255:1, + .name = "pci-das64/m1/16/jr", + .device_id = 0 /* XXX, */ + .ai_se_chans = 64, + .ai_bits = 16, + .ai_speed = 1000, + .ao_nchan = 0, + .ao_scan_speed = 10000, + .layout = LAYOUT_64XX, + .ai_range_table = &ai_ranges_64xx, + .ai_fifo = ai_fifo_64xx, + .has_8255 = 1, }, { - name: "pci-das64/m2/16/jr", - device_id:0 // XXX, - ai_se_chans:64, - ai_bits: 16, - ai_speed:500, - ao_nchan:0, - ao_scan_speed:10000, - layout: LAYOUT_64XX, - ai_range_table:&ai_ranges_64xx, - ai_fifo: ai_fifo_64xx, - has_8255:1, + .name = "pci-das64/m2/16/jr", + .device_id = 0 /* XXX, */ + .ai_se_chans = 64, + .ai_bits = 16, + .ai_speed = 500, + .ao_nchan = 0, + .ao_scan_speed = 10000, + .layout = LAYOUT_64XX, + .ai_range_table = &ai_ranges_64xx, + .ai_fifo = ai_fifo_64xx, + .has_8255 = 1, }, { - name: "pci-das64/m3/16/jr", - device_id:0 // XXX, - ai_se_chans:64, - ai_bits: 16, - ai_speed:333, - ao_nchan:0, - ao_scan_speed:10000, - layout: LAYOUT_64XX, - ai_range_table:&ai_ranges_64xx, - ai_fifo: ai_fifo_64xx, - has_8255:1, + .name = "pci-das64/m3/16/jr", + .device_id = 0 /* XXX, */ + .ai_se_chans = 64, + .ai_bits = 16, + .ai_speed = 333, + .ao_nchan = 0, + .ao_scan_speed = 10000, + .layout = LAYOUT_64XX, + .ai_range_table = &ai_ranges_64xx, + .ai_fifo = ai_fifo_64xx, + .has_8255 = 1, }, { - name: "pci-das64/m1/14", - device_id:0, // XXX - ai_se_chans:64, - ai_bits: 14, - ai_speed:1000, - ao_nchan:2, - ao_scan_speed:10000, - layout: LAYOUT_64XX, - ai_range_table:&ai_ranges_64xx, - ai_fifo: ai_fifo_64xx, - has_8255:1, + .name = "pci-das64/m1/14", + .device_id = 0, /* XXX */ + .ai_se_chans = 64, + .ai_bits = 14, + .ai_speed = 1000, + .ao_nchan = 2, + .ao_scan_speed = 10000, + .layout = LAYOUT_64XX, + .ai_range_table = &ai_ranges_64xx, + .ai_fifo = ai_fifo_64xx, + .has_8255 = 1, }, { - name: "pci-das64/m2/14", - device_id:0, // XXX - ai_se_chans:64, - ai_bits: 14, - ai_speed:500, - ao_nchan:2, - ao_scan_speed:10000, - layout: LAYOUT_64XX, - ai_range_table:&ai_ranges_64xx, - ai_fifo: ai_fifo_64xx, - has_8255:1, + .name = "pci-das64/m2/14", + .device_id = 0, /* XXX */ + .ai_se_chans = 64, + .ai_bits = 14, + .ai_speed = 500, + .ao_nchan = 2, + .ao_scan_speed = 10000, + .layout = LAYOUT_64XX, + .ai_range_table = &ai_ranges_64xx, + .ai_fifo = ai_fifo_64xx, + .has_8255 = 1, }, { - name: "pci-das64/m3/14", - device_id:0, // XXX - ai_se_chans:64, - ai_bits: 14, - ai_speed:333, - ao_nchan:2, - ao_scan_speed:10000, - layout: LAYOUT_64XX, - ai_range_table:&ai_ranges_64xx, - ai_fifo: ai_fifo_64xx, - has_8255:1, + .name = "pci-das64/m3/14", + .device_id = 0, /* XXX */ + .ai_se_chans = 64, + .ai_bits = 14, + .ai_speed = 333, + .ao_nchan = 2, + .ao_scan_speed = 10000, + .layout = LAYOUT_64XX, + .ai_range_table = &ai_ranges_64xx, + .ai_fifo = ai_fifo_64xx, + .has_8255 = 1, }, #endif }; -// Number of boards in cb_pcidas_boards -static inline unsigned int num_boards(void) -{ - return sizeof(pcidas64_boards) / sizeof(struct pcidas64_board); -} - static DEFINE_PCI_DEVICE_TABLE(pcidas64_pci_table) = { {PCI_VENDOR_ID_COMPUTERBOARDS, 0x001d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {PCI_VENDOR_ID_COMPUTERBOARDS, 0x001e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, @@ -1049,7 +1044,7 @@ static inline struct pcidas64_board *board(const struct comedi_device * dev) return (struct pcidas64_board *) dev->board_ptr; } -static inline unsigned short se_diff_bit_6xxx(struct comedi_device * dev, +static inline unsigned short se_diff_bit_6xxx(struct comedi_device *dev, int use_differential) { if ((board(dev)->layout == LAYOUT_64XX && !use_differential) || @@ -1060,50 +1055,50 @@ static inline unsigned short se_diff_bit_6xxx(struct comedi_device * dev, }; struct ext_clock_info { - unsigned int divisor; // master clock divisor to use for scans with external master clock - unsigned int chanspec; // chanspec for master clock input when used as scan begin src + unsigned int divisor; /* master clock divisor to use for scans with external master clock */ + unsigned int chanspec; /* chanspec for master clock input when used as scan begin src */ }; /* this structure is for data unique to this hardware driver. */ struct pcidas64_private { - struct pci_dev *hw_dev; // pointer to board's pci_dev struct - // base addresses (physical) + struct pci_dev *hw_dev; /* pointer to board's pci_dev struct */ + /* base addresses (physical) */ resource_size_t plx9080_phys_iobase; resource_size_t main_phys_iobase; resource_size_t dio_counter_phys_iobase; - // base addresses (ioremapped) + /* base addresses (ioremapped) */ void *plx9080_iobase; void *main_iobase; void *dio_counter_iobase; - // local address (used by dma controller) + /* local address (used by dma controller) */ uint32_t local0_iobase; uint32_t local1_iobase; - volatile unsigned int ai_count; // number of analog input samples remaining - uint16_t *ai_buffer[MAX_AI_DMA_RING_COUNT]; // dma buffers for analog input - dma_addr_t ai_buffer_bus_addr[MAX_AI_DMA_RING_COUNT]; // physical addresses of ai dma buffers - struct plx_dma_desc *ai_dma_desc; // array of ai dma descriptors read by plx9080, allocated to get proper alignment - dma_addr_t ai_dma_desc_bus_addr; // physical address of ai dma descriptor array - volatile unsigned int ai_dma_index; // index of the ai dma descriptor/buffer that is currently being used - uint16_t *ao_buffer[AO_DMA_RING_COUNT]; // dma buffers for analog output - dma_addr_t ao_buffer_bus_addr[AO_DMA_RING_COUNT]; // physical addresses of ao dma buffers + volatile unsigned int ai_count; /* number of analog input samples remaining */ + uint16_t *ai_buffer[MAX_AI_DMA_RING_COUNT]; /* dma buffers for analog input */ + dma_addr_t ai_buffer_bus_addr[MAX_AI_DMA_RING_COUNT]; /* physical addresses of ai dma buffers */ + struct plx_dma_desc *ai_dma_desc; /* array of ai dma descriptors read by plx9080, allocated to get proper alignment */ + dma_addr_t ai_dma_desc_bus_addr; /* physical address of ai dma descriptor array */ + volatile unsigned int ai_dma_index; /* index of the ai dma descriptor/buffer that is currently being used */ + uint16_t *ao_buffer[AO_DMA_RING_COUNT]; /* dma buffers for analog output */ + dma_addr_t ao_buffer_bus_addr[AO_DMA_RING_COUNT]; /* physical addresses of ao dma buffers */ struct plx_dma_desc *ao_dma_desc; dma_addr_t ao_dma_desc_bus_addr; - volatile unsigned int ao_dma_index; // keeps track of buffer where the next ao sample should go - volatile unsigned long ao_count; // number of analog output samples remaining - volatile unsigned int ao_value[2]; // remember what the analog outputs are set to, to allow readback - unsigned int hw_revision; // stc chip hardware revision number - volatile unsigned int intr_enable_bits; // last bits sent to INTR_ENABLE_REG register - volatile uint16_t adc_control1_bits; // last bits sent to ADC_CONTROL1_REG register - volatile uint16_t fifo_size_bits; // last bits sent to FIFO_SIZE_REG register - volatile uint16_t hw_config_bits; // last bits sent to HW_CONFIG_REG register + volatile unsigned int ao_dma_index; /* keeps track of buffer where the next ao sample should go */ + volatile unsigned long ao_count; /* number of analog output samples remaining */ + volatile unsigned int ao_value[2]; /* remember what the analog outputs are set to, to allow readback */ + unsigned int hw_revision; /* stc chip hardware revision number */ + volatile unsigned int intr_enable_bits; /* last bits sent to INTR_ENABLE_REG register */ + volatile uint16_t adc_control1_bits; /* last bits sent to ADC_CONTROL1_REG register */ + volatile uint16_t fifo_size_bits; /* last bits sent to FIFO_SIZE_REG register */ + volatile uint16_t hw_config_bits; /* last bits sent to HW_CONFIG_REG register */ volatile uint16_t dac_control1_bits; - volatile uint32_t plx_control_bits; // last bits written to plx9080 control register - volatile uint32_t plx_intcsr_bits; // last bits written to plx interrupt control and status register - volatile int calibration_source; // index of calibration source readable through ai ch0 - volatile uint8_t i2c_cal_range_bits; // bits written to i2c calibration/range register - volatile unsigned int ext_trig_falling; // configure digital triggers to trigger on falling edge - // states of various devices stored to enable read-back + volatile uint32_t plx_control_bits; /* last bits written to plx9080 control register */ + volatile uint32_t plx_intcsr_bits; /* last bits written to plx interrupt control and status register */ + volatile int calibration_source; /* index of calibration source readable through ai ch0 */ + volatile uint8_t i2c_cal_range_bits; /* bits written to i2c calibration/range register */ + volatile unsigned int ext_trig_falling; /* configure digital triggers to trigger on falling edge */ + /* states of various devices stored to enable read-back */ unsigned int ad8402_state[2]; unsigned int caldac_state[8]; volatile short ai_cmd_running; @@ -1127,82 +1122,82 @@ static inline struct pcidas64_private *priv(struct comedi_device * dev) * the board, and also about the kernel module that contains * the device code. */ -static int attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int detach(struct comedi_device * dev); +static int attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int detach(struct comedi_device *dev); static struct comedi_driver driver_cb_pcidas = { - driver_name:"cb_pcidas64", - module:THIS_MODULE, - attach:attach, - detach:detach, + .driver_name = "cb_pcidas64", + .module = THIS_MODULE, + .attach = attach, + .detach = detach, }; -static int ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int ai_config_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int ao_readback_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s); -static int ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd); -static int ao_cmd(struct comedi_device * dev, struct comedi_subdevice * s); -static int ao_inttrig(struct comedi_device * dev, struct comedi_subdevice * subdev, +static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int ai_config_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int ao_readback_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s); +static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd); +static int ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s); +static int ao_inttrig(struct comedi_device *dev, struct comedi_subdevice *subdev, unsigned int trig_num); -static int ao_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd); -static irqreturn_t handle_interrupt(int irq, void *d PT_REGS_ARG); -static int ai_cancel(struct comedi_device * dev, struct comedi_subdevice * s); -static int ao_cancel(struct comedi_device * dev, struct comedi_subdevice * s); +static int ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd); +static irqreturn_t handle_interrupt(int irq, void *d); +static int ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s); +static int ao_cancel(struct comedi_device *dev, struct comedi_subdevice *s); static int dio_callback(int dir, int port, int data, unsigned long arg); static int dio_callback_4020(int dir, int port, int data, unsigned long arg); -static int di_rbits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int do_wbits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int dio_60xx_config_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int dio_60xx_wbits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int calib_read_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int calib_write_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int ad8402_read_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static void ad8402_write(struct comedi_device * dev, unsigned int channel, +static int di_rbits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int do_wbits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int dio_60xx_config_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int dio_60xx_wbits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int calib_read_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int calib_write_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int ad8402_read_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static void ad8402_write(struct comedi_device *dev, unsigned int channel, unsigned int value); -static int ad8402_write_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int eeprom_read_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static void check_adc_timing(struct comedi_device * dev, struct comedi_cmd * cmd); +static int ad8402_write_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int eeprom_read_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static void check_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd); static unsigned int get_divisor(unsigned int ns, unsigned int flags); -static void i2c_write(struct comedi_device * dev, unsigned int address, - const uint8_t * data, unsigned int length); -static void caldac_write(struct comedi_device * dev, unsigned int channel, +static void i2c_write(struct comedi_device *dev, unsigned int address, + const uint8_t *data, unsigned int length); +static void caldac_write(struct comedi_device *dev, unsigned int channel, unsigned int value); -static int caldac_8800_write(struct comedi_device * dev, unsigned int address, +static int caldac_8800_write(struct comedi_device *dev, unsigned int address, uint8_t value); -//static int dac_1590_write(struct comedi_device *dev, unsigned int dac_a, unsigned int dac_b); -static int caldac_i2c_write(struct comedi_device * dev, unsigned int caldac_channel, +/* static int dac_1590_write(struct comedi_device *dev, unsigned int dac_a, unsigned int dac_b); */ +static int caldac_i2c_write(struct comedi_device *dev, unsigned int caldac_channel, unsigned int value); -static void abort_dma(struct comedi_device * dev, unsigned int channel); -static void disable_plx_interrupts(struct comedi_device * dev); -static int set_ai_fifo_size(struct comedi_device * dev, unsigned int num_samples); -static unsigned int ai_fifo_size(struct comedi_device * dev); -static int set_ai_fifo_segment_length(struct comedi_device * dev, +static void abort_dma(struct comedi_device *dev, unsigned int channel); +static void disable_plx_interrupts(struct comedi_device *dev); +static int set_ai_fifo_size(struct comedi_device *dev, unsigned int num_samples); +static unsigned int ai_fifo_size(struct comedi_device *dev); +static int set_ai_fifo_segment_length(struct comedi_device *dev, unsigned int num_entries); -static void disable_ai_pacing(struct comedi_device * dev); -static void disable_ai_interrupts(struct comedi_device * dev); -static void enable_ai_interrupts(struct comedi_device * dev, const struct comedi_cmd * cmd); +static void disable_ai_pacing(struct comedi_device *dev); +static void disable_ai_interrupts(struct comedi_device *dev); +static void enable_ai_interrupts(struct comedi_device *dev, const struct comedi_cmd *cmd); static unsigned int get_ao_divisor(unsigned int ns, unsigned int flags); -static void load_ao_dma(struct comedi_device * dev, const struct comedi_cmd * cmd); +static void load_ao_dma(struct comedi_device *dev, const struct comedi_cmd *cmd); COMEDI_PCI_INITCLEANUP(driver_cb_pcidas, pcidas64_pci_table); -static unsigned int ai_range_bits_6xxx(const struct comedi_device * dev, +static unsigned int ai_range_bits_6xxx(const struct comedi_device *dev, unsigned int range_index) { const struct comedi_krange *range = @@ -1246,7 +1241,7 @@ static unsigned int ai_range_bits_6xxx(const struct comedi_device * dev, return bits; } -static unsigned int hw_revision(const struct comedi_device * dev, +static unsigned int hw_revision(const struct comedi_device *dev, uint16_t hw_status_bits) { if (board(dev)->layout == LAYOUT_4020) @@ -1255,7 +1250,7 @@ static unsigned int hw_revision(const struct comedi_device * dev, return (hw_status_bits >> 12) & 0xf; } -static void set_dac_range_bits(struct comedi_device * dev, volatile uint16_t * bits, +static void set_dac_range_bits(struct comedi_device *dev, volatile uint16_t *bits, unsigned int channel, unsigned int range) { unsigned int code = board(dev)->ao_range_code[range]; @@ -1269,13 +1264,13 @@ static void set_dac_range_bits(struct comedi_device * dev, volatile uint16_t * b *bits |= code << (2 * channel); }; -static inline int ao_cmd_is_supported(const struct pcidas64_board * board) +static inline int ao_cmd_is_supported(const struct pcidas64_board *board) { return board->ao_nchan && board->layout != LAYOUT_4020; } -// initialize plx9080 chip -static void init_plx9080(struct comedi_device * dev) +/* initialize plx9080 chip */ +static void init_plx9080(struct comedi_device *dev) { uint32_t bits; void *plx_iobase = priv(dev)->plx9080_iobase; @@ -1283,7 +1278,7 @@ static void init_plx9080(struct comedi_device * dev) priv(dev)->plx_control_bits = readl(priv(dev)->plx9080_iobase + PLX_CONTROL_REG); - // plx9080 dump + /* plx9080 dump */ DEBUG_PRINT(" plx interrupt status 0x%x\n", readl(plx_iobase + PLX_INTRCS_REG)); DEBUG_PRINT(" plx id bits 0x%x\n", readl(plx_iobase + PLX_ID_REG)); @@ -1327,35 +1322,35 @@ static void init_plx9080(struct comedi_device * dev) abort_dma(dev, 0); abort_dma(dev, 1); - // configure dma0 mode + /* configure dma0 mode */ bits = 0; - // enable ready input, not sure if this is necessary + /* enable ready input, not sure if this is necessary */ bits |= PLX_DMA_EN_READYIN_BIT; - // enable bterm, not sure if this is necessary + /* enable bterm, not sure if this is necessary */ bits |= PLX_EN_BTERM_BIT; - // enable dma chaining + /* enable dma chaining */ bits |= PLX_EN_CHAIN_BIT; - // enable interrupt on dma done (probably don't need this, since chain never finishes) + /* enable interrupt on dma done (probably don't need this, since chain never finishes) */ bits |= PLX_EN_DMA_DONE_INTR_BIT; - // don't increment local address during transfers (we are transferring from a fixed fifo register) + /* don't increment local address during transfers (we are transferring from a fixed fifo register) */ bits |= PLX_LOCAL_ADDR_CONST_BIT; - // route dma interrupt to pci bus + /* route dma interrupt to pci bus */ bits |= PLX_DMA_INTR_PCI_BIT; - // enable demand mode + /* enable demand mode */ bits |= PLX_DEMAND_MODE_BIT; - // enable local burst mode + /* enable local burst mode */ bits |= PLX_DMA_LOCAL_BURST_EN_BIT; - // 4020 uses 32 bit dma + /* 4020 uses 32 bit dma */ if (board(dev)->layout == LAYOUT_4020) { bits |= PLX_LOCAL_BUS_32_WIDE_BITS; - } else { // localspace0 bus is 16 bits wide + } else { /* localspace0 bus is 16 bits wide */ bits |= PLX_LOCAL_BUS_16_WIDE_BITS; } writel(bits, plx_iobase + PLX_DMA1_MODE_REG); if (ao_cmd_is_supported(board(dev))) writel(bits, plx_iobase + PLX_DMA0_MODE_REG); - // enable interrupts on plx 9080 + /* enable interrupts on plx 9080 */ priv(dev)->plx_intcsr_bits |= ICS_AERR | ICS_PERR | ICS_PIE | ICS_PLIE | ICS_PAIE | ICS_LIE | ICS_DMA0_E | ICS_DMA1_E; @@ -1365,7 +1360,7 @@ static void init_plx9080(struct comedi_device * dev) /* Allocate and initialize the subdevice structures. */ -static int setup_subdevices(struct comedi_device * dev) +static int setup_subdevices(struct comedi_device *dev) { struct comedi_subdevice *s; void *dio_8255_iobase; @@ -1396,9 +1391,9 @@ static int setup_subdevices(struct comedi_device * dev) if (board(dev)->layout == LAYOUT_4020) { unsigned int i; uint8_t data; - // set adc to read from inputs (not internal calibration sources) + /* set adc to read from inputs (not internal calibration sources) */ priv(dev)->i2c_cal_range_bits = adc_src_4020_bits(4); - // set channels to +-5 volt input ranges + /* set channels to +-5 volt input ranges */ for (i = 0; i < s->n_chan; i++) priv(dev)->i2c_cal_range_bits |= attenuate_bit(i); data = priv(dev)->i2c_cal_range_bits; @@ -1428,7 +1423,7 @@ static int setup_subdevices(struct comedi_device * dev) s->type = COMEDI_SUBD_UNUSED; } - // digital input + /* digital input */ s = dev->subdevices + 2; if (board(dev)->layout == LAYOUT_64XX) { s->type = COMEDI_SUBD_DI; @@ -1440,7 +1435,7 @@ static int setup_subdevices(struct comedi_device * dev) } else s->type = COMEDI_SUBD_UNUSED; - // digital output + /* digital output */ if (board(dev)->layout == LAYOUT_64XX) { s = dev->subdevices + 3; s->type = COMEDI_SUBD_DO; @@ -1469,7 +1464,7 @@ static int setup_subdevices(struct comedi_device * dev) } else s->type = COMEDI_SUBD_UNUSED; - // 8 channel dio for 60xx + /* 8 channel dio for 60xx */ s = dev->subdevices + 5; if (board(dev)->layout == LAYOUT_60XX) { s->type = COMEDI_SUBD_DIO; @@ -1482,7 +1477,7 @@ static int setup_subdevices(struct comedi_device * dev) } else s->type = COMEDI_SUBD_UNUSED; - // caldac + /* caldac */ s = dev->subdevices + 6; s->type = COMEDI_SUBD_CALIB; s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; @@ -1496,7 +1491,7 @@ static int setup_subdevices(struct comedi_device * dev) for (i = 0; i < s->n_chan; i++) caldac_write(dev, i, s->maxdata / 2); - // 2 channel ad8402 potentiometer + /* 2 channel ad8402 potentiometer */ s = dev->subdevices + 7; if (board(dev)->layout == LAYOUT_64XX) { s->type = COMEDI_SUBD_CALIB; @@ -1510,7 +1505,7 @@ static int setup_subdevices(struct comedi_device * dev) } else s->type = COMEDI_SUBD_UNUSED; - //serial EEPROM, if present + /* serial EEPROM, if present */ s = dev->subdevices + 8; if (readl(priv(dev)->plx9080_iobase + PLX_CONTROL_REG) & CTL_EECHK) { s->type = COMEDI_SUBD_MEMORY; @@ -1521,34 +1516,34 @@ static int setup_subdevices(struct comedi_device * dev) } else s->type = COMEDI_SUBD_UNUSED; - // user counter subd XXX + /* user counter subd XXX */ s = dev->subdevices + 9; s->type = COMEDI_SUBD_UNUSED; return 0; } -static void disable_plx_interrupts(struct comedi_device * dev) +static void disable_plx_interrupts(struct comedi_device *dev) { priv(dev)->plx_intcsr_bits = 0; writel(priv(dev)->plx_intcsr_bits, priv(dev)->plx9080_iobase + PLX_INTRCS_REG); } -static void init_stc_registers(struct comedi_device * dev) +static void init_stc_registers(struct comedi_device *dev) { uint16_t bits; unsigned long flags; - comedi_spin_lock_irqsave(&dev->spinlock, flags); + spin_lock_irqsave(&dev->spinlock, flags); - // bit should be set for 6025, although docs say boards with <= 16 chans should be cleared XXX + /* bit should be set for 6025, although docs say boards with <= 16 chans should be cleared XXX */ if (1) priv(dev)->adc_control1_bits |= ADC_QUEUE_CONFIG_BIT; writew(priv(dev)->adc_control1_bits, priv(dev)->main_iobase + ADC_CONTROL1_REG); - // 6402/16 manual says this register must be initialized to 0xff? + /* 6402/16 manual says this register must be initialized to 0xff? */ writew(0xff, priv(dev)->main_iobase + ADC_SAMPLE_INTERVAL_UPPER_REG); bits = SLOW_DAC_BIT | DMA_CH_SELECT_BIT; @@ -1561,9 +1556,9 @@ static void init_stc_registers(struct comedi_device * dev) writew(0, priv(dev)->main_iobase + DAQ_SYNC_REG); writew(0, priv(dev)->main_iobase + CALIBRATION_REG); - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); - // set fifos to maximum size + /* set fifos to maximum size */ priv(dev)->fifo_size_bits |= DAC_FIFO_BITS; set_ai_fifo_segment_length(dev, board(dev)->ai_fifo->max_segment_length); @@ -1577,11 +1572,11 @@ static void init_stc_registers(struct comedi_device * dev) disable_ai_pacing(dev); }; -int alloc_and_init_dma_members(struct comedi_device * dev) +int alloc_and_init_dma_members(struct comedi_device *dev) { int i; - // alocate pci dma buffers + /* alocate pci dma buffers */ for (i = 0; i < ai_dma_ring_count(board(dev)); i++) { priv(dev)->ai_buffer[i] = pci_alloc_consistent(priv(dev)->hw_dev, DMA_BUFFER_SIZE, @@ -1601,7 +1596,7 @@ int alloc_and_init_dma_members(struct comedi_device * dev) } } } - // allocate dma descriptors + /* allocate dma descriptors */ priv(dev)->ai_dma_desc = pci_alloc_consistent(priv(dev)->hw_dev, sizeof(struct plx_dma_desc) * ai_dma_ring_count(board(dev)), @@ -1622,7 +1617,7 @@ int alloc_and_init_dma_members(struct comedi_device * dev) DEBUG_PRINT("ao dma descriptors start at bus addr 0x%x\n", priv(dev)->ao_dma_desc_bus_addr); } - // initialize dma descriptors + /* initialize dma descriptors */ for (i = 0; i < ai_dma_ring_count(board(dev)); i++) { priv(dev)->ai_dma_desc[i].pci_start_addr = cpu_to_le32(priv(dev)->ai_buffer_bus_addr[i]); @@ -1663,7 +1658,7 @@ int alloc_and_init_dma_members(struct comedi_device * dev) return 0; } -static inline void warn_external_queue(struct comedi_device * dev) +static inline void warn_external_queue(struct comedi_device *dev) { comedi_error(dev, "AO command and AI external channel queue cannot be used simultaneously."); @@ -1697,16 +1692,16 @@ static int attach(struct comedi_device *dev, struct comedi_devconfig *it) for (pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL); pcidev != NULL; pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pcidev)) { - // is it not a computer boards card? + /* is it not a computer boards card? */ if (pcidev->vendor != PCI_VENDOR_ID_COMPUTERBOARDS) continue; - // loop through cards supported by this driver - for (index = 0; index < num_boards(); index++) { + /* loop through cards supported by this driver */ + for (index = 0; index < ARRAY_SIZE(pcidas64_boards); index++) { if (pcidas64_boards[index].device_id != pcidev->device) continue; - // was a particular bus/slot requested? + /* was a particular bus/slot requested? */ if (it->options[0] || it->options[1]) { - // are we on the wrong bus/slot? + /* are we on the wrong bus/slot? */ if (pcidev->bus->number != it->options[0] || PCI_SLOT(pcidev->devfn) != it->options[1]) { @@ -1736,7 +1731,7 @@ static int attach(struct comedi_device *dev, struct comedi_devconfig *it) } pci_set_master(pcidev); - //Initialize dev->board_name + /* Initialize dev->board_name */ dev->board_name = board(dev)->name; priv(dev)->plx9080_phys_iobase = @@ -1746,7 +1741,7 @@ static int attach(struct comedi_device *dev, struct comedi_devconfig *it) priv(dev)->dio_counter_phys_iobase = pci_resource_start(pcidev, DIO_COUNTER_BADDRINDEX); - // remap, won't work with 2.0 kernels but who cares + /* remap, won't work with 2.0 kernels but who cares */ priv(dev)->plx9080_iobase = ioremap(priv(dev)->plx9080_phys_iobase, pci_resource_len(pcidev, PLX9080_BADDRINDEX)); priv(dev)->main_iobase = ioremap(priv(dev)->main_phys_iobase, @@ -1766,7 +1761,7 @@ static int attach(struct comedi_device *dev, struct comedi_devconfig *it) DEBUG_PRINT(" diocounter remapped to 0x%p\n", priv(dev)->dio_counter_iobase); - // figure out what local addresses are + /* figure out what local addresses are */ local_range = readl(priv(dev)->plx9080_iobase + PLX_LAS0RNG_REG) & LRNG_MEM_MASK; @@ -1798,8 +1793,8 @@ static int attach(struct comedi_device *dev, struct comedi_devconfig *it) printk(" stc hardware revision %i\n", priv(dev)->hw_revision); init_plx9080(dev); init_stc_registers(dev); - // get irq - if (comedi_request_irq(pcidev->irq, handle_interrupt, IRQF_SHARED, + /* get irq */ + if (request_irq(pcidev->irq, handle_interrupt, IRQF_SHARED, "cb_pcidas64", dev)) { printk(" unable to allocate irq %u\n", pcidev->irq); return -EINVAL; @@ -1823,14 +1818,14 @@ static int attach(struct comedi_device *dev, struct comedi_devconfig *it) * allocated by _attach(). dev->private and dev->subdevices are * deallocated automatically by the core. */ -static int detach(struct comedi_device * dev) +static int detach(struct comedi_device *dev) { unsigned int i; printk("comedi%d: cb_pcidas: remove\n", dev->minor); if (dev->irq) - comedi_free_irq(dev->irq, dev); + free_irq(dev->irq, dev); if (priv(dev)) { if (priv(dev)->hw_dev) { if (priv(dev)->plx9080_iobase) { @@ -1841,7 +1836,7 @@ static int detach(struct comedi_device * dev) iounmap((void *)priv(dev)->main_iobase); if (priv(dev)->dio_counter_iobase) iounmap((void *)priv(dev)->dio_counter_iobase); - // free pci dma buffers + /* free pci dma buffers */ for (i = 0; i < ai_dma_ring_count(board(dev)); i++) { if (priv(dev)->ai_buffer[i]) pci_free_consistent(priv(dev)->hw_dev, @@ -1858,7 +1853,7 @@ static int detach(struct comedi_device * dev) priv(dev)-> ao_buffer_bus_addr[i]); } - // free dma descriptors + /* free dma descriptors */ if (priv(dev)->ai_dma_desc) pci_free_consistent(priv(dev)->hw_dev, sizeof(struct plx_dma_desc) * @@ -1883,8 +1878,8 @@ static int detach(struct comedi_device * dev) return 0; } -static int ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { unsigned int bits = 0, n, i; unsigned int channel, range, aref; @@ -1896,26 +1891,26 @@ static int ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, range = CR_RANGE(insn->chanspec); aref = CR_AREF(insn->chanspec); - // disable card's analog input interrupt sources and pacing - // 4020 generates dac done interrupts even though they are disabled + /* disable card's analog input interrupt sources and pacing */ + /* 4020 generates dac done interrupts even though they are disabled */ disable_ai_pacing(dev); - comedi_spin_lock_irqsave(&dev->spinlock, flags); + spin_lock_irqsave(&dev->spinlock, flags); if (insn->chanspec & CR_ALT_FILTER) priv(dev)->adc_control1_bits |= ADC_DITHER_BIT; else priv(dev)->adc_control1_bits &= ~ADC_DITHER_BIT; writew(priv(dev)->adc_control1_bits, priv(dev)->main_iobase + ADC_CONTROL1_REG); - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); if (board(dev)->layout != LAYOUT_4020) { - // use internal queue + /* use internal queue */ priv(dev)->hw_config_bits &= ~EXT_QUEUE_BIT; writew(priv(dev)->hw_config_bits, priv(dev)->main_iobase + HW_CONFIG_REG); - // ALT_SOURCE is internal calibration reference + /* ALT_SOURCE is internal calibration reference */ if (insn->chanspec & CR_ALT_SOURCE) { unsigned int cal_en_bit; @@ -1924,27 +1919,27 @@ static int ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, cal_en_bit = CAL_EN_60XX_BIT; else cal_en_bit = CAL_EN_64XX_BIT; - // select internal reference source to connect to channel 0 + /* select internal reference source to connect to channel 0 */ writew(cal_en_bit | adc_src_bits(priv(dev)-> calibration_source), priv(dev)->main_iobase + CALIBRATION_REG); } else { - // make sure internal calibration source is turned off + /* make sure internal calibration source is turned off */ writew(0, priv(dev)->main_iobase + CALIBRATION_REG); } - // load internal queue + /* load internal queue */ bits = 0; - // set gain + /* set gain */ bits |= ai_range_bits_6xxx(dev, CR_RANGE(insn->chanspec)); - // set single-ended / differential + /* set single-ended / differential */ bits |= se_diff_bit_6xxx(dev, aref == AREF_DIFF); if (aref == AREF_COMMON) bits |= ADC_COMMON_BIT; bits |= adc_chan_bits(channel); - // set stop channel + /* set stop channel */ writew(adc_chan_bits(channel), priv(dev)->main_iobase + ADC_QUEUE_HIGH_REG); - // set start channel, and rest of settings + /* set start channel, and rest of settings */ writew(bits, priv(dev)->main_iobase + ADC_QUEUE_LOAD_REG); } else { uint8_t old_cal_range_bits = priv(dev)->i2c_cal_range_bits; @@ -1955,16 +1950,16 @@ static int ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, priv(dev)->i2c_cal_range_bits |= adc_src_4020_bits(priv(dev)-> calibration_source); - } else { //select BNC inputs + } else { /* select BNC inputs */ priv(dev)->i2c_cal_range_bits |= adc_src_4020_bits(4); } - // select range + /* select range */ if (range == 0) priv(dev)->i2c_cal_range_bits |= attenuate_bit(channel); else priv(dev)->i2c_cal_range_bits &= ~attenuate_bit(channel); - // update calibration/range i2c register only if necessary, as it is very slow + /* update calibration/range i2c register only if necessary, as it is very slow */ if (old_cal_range_bits != priv(dev)->i2c_cal_range_bits) { uint8_t i2c_data = priv(dev)->i2c_cal_range_bits; i2c_write(dev, RANGE_CAL_I2C_ADDR, &i2c_data, @@ -1981,14 +1976,14 @@ static int ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, for (n = 0; n < insn->n; n++) { - // clear adc buffer (inside loop for 4020 sake) + /* clear adc buffer (inside loop for 4020 sake) */ writew(0, priv(dev)->main_iobase + ADC_BUFFER_CLEAR_REG); /* trigger conversion, bits sent only matter for 4020 */ writew(adc_convert_chan_4020_bits(CR_CHAN(insn->chanspec)), priv(dev)->main_iobase + ADC_CONVERT_REG); - // wait for data + /* wait for data */ for (i = 0; i < timeout; i++) { bits = readw(priv(dev)->main_iobase + HW_STATUS_REG); DEBUG_PRINT(" pipe bits 0x%x\n", pipe_full_bits(bits)); @@ -2000,12 +1995,12 @@ static int ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, if (pipe_full_bits(bits)) break; } - comedi_udelay(1); + udelay(1); } DEBUG_PRINT(" looped %i times waiting for data\n", i); if (i == timeout) { comedi_error(dev, " analog input read insn timed out"); - rt_printk(" status 0x%x\n", bits); + printk(" status 0x%x\n", bits); return -ETIME; } if (board(dev)->layout == LAYOUT_4020) @@ -2020,7 +2015,7 @@ static int ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, return n; } -static int ai_config_calibration_source(struct comedi_device * dev, unsigned int * data) +static int ai_config_calibration_source(struct comedi_device *dev, unsigned int *data) { unsigned int source = data[1]; int num_calibration_sources; @@ -2040,7 +2035,7 @@ static int ai_config_calibration_source(struct comedi_device * dev, unsigned int return 2; } -static int ai_config_block_size(struct comedi_device * dev, unsigned int * data) +static int ai_config_block_size(struct comedi_device *dev, unsigned int *data) { int fifo_size; const struct hw_fifo_info *const fifo = board(dev)->ai_fifo; @@ -2067,7 +2062,7 @@ static int ai_config_block_size(struct comedi_device * dev, unsigned int * data) return 2; } -static int ai_config_master_clock_4020(struct comedi_device * dev, unsigned int * data) +static int ai_config_master_clock_4020(struct comedi_device *dev, unsigned int *data) { unsigned int divisor = data[4]; int retval = 0; @@ -2092,8 +2087,8 @@ static int ai_config_master_clock_4020(struct comedi_device * dev, unsigned int return retval ? retval : 5; } -// XXX could add support for 60xx series -static int ai_config_master_clock(struct comedi_device * dev, unsigned int * data) +/* XXX could add support for 60xx series */ +static int ai_config_master_clock(struct comedi_device *dev, unsigned int *data) { switch (board(dev)->layout) { @@ -2108,8 +2103,8 @@ static int ai_config_master_clock(struct comedi_device * dev, unsigned int * dat return -EINVAL; } -static int ai_config_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int ai_config_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int id = data[0]; @@ -2130,8 +2125,8 @@ static int ai_config_insn(struct comedi_device * dev, struct comedi_subdevice * return -EINVAL; } -static int ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd) +static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd) { int err = 0; int tmp; @@ -2182,7 +2177,7 @@ static int ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, /* step 2: make sure trigger sources are unique and mutually compatible */ - // uniqueness check + /* uniqueness check */ if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) err++; if (cmd->scan_begin_src != TRIG_TIMER && @@ -2196,7 +2191,7 @@ static int ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_EXT) err++; - // compatibility check + /* compatibility check */ if (cmd->convert_src == TRIG_EXT && cmd->scan_begin_src == TRIG_TIMER) err++; if (cmd->stop_src != TRIG_COUNT && @@ -2220,7 +2215,7 @@ static int ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, err++; } if (cmd->scan_begin_src == TRIG_TIMER) { - // if scans are timed faster than conversion rate allows + /* if scans are timed faster than conversion rate allows */ if (cmd->convert_arg * cmd->chanlist_len > cmd->scan_begin_arg) { cmd->scan_begin_arg = @@ -2278,7 +2273,7 @@ static int ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, if (err) return 4; - // make sure user is doesn't change analog reference mid chanlist + /* make sure user is doesn't change analog reference mid chanlist */ if (cmd->chanlist) { aref = CR_AREF(cmd->chanlist[0]); for (i = 1; i < cmd->chanlist_len; i++) { @@ -2289,7 +2284,7 @@ static int ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, break; } } - // check 4020 chanlist + /* check 4020 chanlist */ if (board(dev)->layout == LAYOUT_4020) { unsigned int first_channel = CR_CHAN(cmd->chanlist[0]); for (i = 1; i < cmd->chanlist_len; i++) { @@ -2315,9 +2310,9 @@ static int ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, return 0; } -static int use_hw_sample_counter(struct comedi_cmd * cmd) +static int use_hw_sample_counter(struct comedi_cmd *cmd) { -// disable for now until I work out a race +/* disable for now until I work out a race */ return 0; if (cmd->stop_src == TRIG_COUNT && cmd->stop_arg <= max_counter_value) @@ -2326,13 +2321,13 @@ static int use_hw_sample_counter(struct comedi_cmd * cmd) return 0; } -static void setup_sample_counters(struct comedi_device * dev, struct comedi_cmd * cmd) +static void setup_sample_counters(struct comedi_device *dev, struct comedi_cmd *cmd) { if (cmd->stop_src == TRIG_COUNT) { - // set software count + /* set software count */ priv(dev)->ai_count = cmd->stop_arg * cmd->chanlist_len; } - // load hardware conversion counter + /* load hardware conversion counter */ if (use_hw_sample_counter(cmd)) { writew(cmd->stop_arg & 0xffff, priv(dev)->main_iobase + ADC_COUNT_LOWER_REG); @@ -2343,7 +2338,7 @@ static void setup_sample_counters(struct comedi_device * dev, struct comedi_cmd } } -static inline unsigned int dma_transfer_size(struct comedi_device * dev) +static inline unsigned int dma_transfer_size(struct comedi_device *dev) { unsigned int num_samples; @@ -2356,71 +2351,71 @@ static inline unsigned int dma_transfer_size(struct comedi_device * dev) return num_samples; } -static void disable_ai_pacing(struct comedi_device * dev) +static void disable_ai_pacing(struct comedi_device *dev) { unsigned long flags; disable_ai_interrupts(dev); - comedi_spin_lock_irqsave(&dev->spinlock, flags); + spin_lock_irqsave(&dev->spinlock, flags); priv(dev)->adc_control1_bits &= ~ADC_SW_GATE_BIT; writew(priv(dev)->adc_control1_bits, priv(dev)->main_iobase + ADC_CONTROL1_REG); - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); /* disable pacing, triggering, etc */ writew(ADC_DMA_DISABLE_BIT | ADC_SOFT_GATE_BITS | ADC_GATE_LEVEL_BIT, priv(dev)->main_iobase + ADC_CONTROL0_REG); } -static void disable_ai_interrupts(struct comedi_device * dev) +static void disable_ai_interrupts(struct comedi_device *dev) { unsigned long flags; - comedi_spin_lock_irqsave(&dev->spinlock, flags); + spin_lock_irqsave(&dev->spinlock, flags); priv(dev)->intr_enable_bits &= ~EN_ADC_INTR_SRC_BIT & ~EN_ADC_DONE_INTR_BIT & ~EN_ADC_ACTIVE_INTR_BIT & ~EN_ADC_STOP_INTR_BIT & ~EN_ADC_OVERRUN_BIT & ~ADC_INTR_SRC_MASK; writew(priv(dev)->intr_enable_bits, priv(dev)->main_iobase + INTR_ENABLE_REG); - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); DEBUG_PRINT("intr enable bits 0x%x\n", priv(dev)->intr_enable_bits); } -static void enable_ai_interrupts(struct comedi_device * dev, const struct comedi_cmd * cmd) +static void enable_ai_interrupts(struct comedi_device *dev, const struct comedi_cmd *cmd) { uint32_t bits; unsigned long flags; bits = EN_ADC_OVERRUN_BIT | EN_ADC_DONE_INTR_BIT | EN_ADC_ACTIVE_INTR_BIT | EN_ADC_STOP_INTR_BIT; - // Use pio transfer and interrupt on end of conversion if TRIG_WAKE_EOS flag is set. + /* Use pio transfer and interrupt on end of conversion if TRIG_WAKE_EOS flag is set. */ if (cmd->flags & TRIG_WAKE_EOS) { - // 4020 doesn't support pio transfers except for fifo dregs + /* 4020 doesn't support pio transfers except for fifo dregs */ if (board(dev)->layout != LAYOUT_4020) bits |= ADC_INTR_EOSCAN_BITS | EN_ADC_INTR_SRC_BIT; } - comedi_spin_lock_irqsave(&dev->spinlock, flags); + spin_lock_irqsave(&dev->spinlock, flags); priv(dev)->intr_enable_bits |= bits; writew(priv(dev)->intr_enable_bits, priv(dev)->main_iobase + INTR_ENABLE_REG); DEBUG_PRINT("intr enable bits 0x%x\n", priv(dev)->intr_enable_bits); - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); } -static uint32_t ai_convert_counter_6xxx(const struct comedi_device * dev, - const struct comedi_cmd * cmd) +static uint32_t ai_convert_counter_6xxx(const struct comedi_device *dev, + const struct comedi_cmd *cmd) { - // supposed to load counter with desired divisor minus 3 + /* supposed to load counter with desired divisor minus 3 */ return cmd->convert_arg / TIMER_BASE - 3; } -static uint32_t ai_scan_counter_6xxx(struct comedi_device * dev, struct comedi_cmd * cmd) +static uint32_t ai_scan_counter_6xxx(struct comedi_device *dev, struct comedi_cmd *cmd) { uint32_t count; - // figure out how long we need to delay at end of scan + /* figure out how long we need to delay at end of scan */ switch (cmd->scan_begin_src) { case TRIG_TIMER: count = (cmd->scan_begin_arg - @@ -2437,7 +2432,7 @@ static uint32_t ai_scan_counter_6xxx(struct comedi_device * dev, struct comedi_c return count - 3; } -static uint32_t ai_convert_counter_4020(struct comedi_device * dev, struct comedi_cmd * cmd) +static uint32_t ai_convert_counter_4020(struct comedi_device *dev, struct comedi_cmd *cmd) { unsigned int divisor; @@ -2448,20 +2443,20 @@ static uint32_t ai_convert_counter_4020(struct comedi_device * dev, struct comed case TRIG_OTHER: divisor = priv(dev)->ext_clock.divisor; break; - default: // should never happen + default: /* should never happen */ comedi_error(dev, "bug! failed to set ai pacing!"); divisor = 1000; break; } - // supposed to load counter with desired divisor minus 2 for 4020 + /* supposed to load counter with desired divisor minus 2 for 4020 */ return divisor - 2; } -static void select_master_clock_4020(struct comedi_device * dev, - const struct comedi_cmd * cmd) +static void select_master_clock_4020(struct comedi_device *dev, + const struct comedi_cmd *cmd) { - // select internal/external master clock + /* select internal/external master clock */ priv(dev)->hw_config_bits &= ~MASTER_CLOCK_4020_MASK; if (cmd->scan_begin_src == TRIG_OTHER) { int chanspec = priv(dev)->ext_clock.chanspec; @@ -2477,7 +2472,7 @@ static void select_master_clock_4020(struct comedi_device * dev, priv(dev)->main_iobase + HW_CONFIG_REG); } -static void select_master_clock(struct comedi_device * dev, const struct comedi_cmd * cmd) +static void select_master_clock(struct comedi_device *dev, const struct comedi_cmd *cmd) { switch (board(dev)->layout) { case LAYOUT_4020: @@ -2488,12 +2483,12 @@ static void select_master_clock(struct comedi_device * dev, const struct comedi_ } } -static inline void dma_start_sync(struct comedi_device * dev, unsigned int channel) +static inline void dma_start_sync(struct comedi_device *dev, unsigned int channel) { unsigned long flags; - // spinlock for plx dma control/status reg - comedi_spin_lock_irqsave(&dev->spinlock, flags); + /* spinlock for plx dma control/status reg */ + spin_lock_irqsave(&dev->spinlock, flags); if (channel) writeb(PLX_DMA_EN_BIT | PLX_DMA_START_BIT | PLX_CLEAR_DMA_INTR_BIT, @@ -2502,10 +2497,10 @@ static inline void dma_start_sync(struct comedi_device * dev, unsigned int chann writeb(PLX_DMA_EN_BIT | PLX_DMA_START_BIT | PLX_CLEAR_DMA_INTR_BIT, priv(dev)->plx9080_iobase + PLX_DMA0_CS_REG); - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); } -static void set_ai_pacing(struct comedi_device * dev, struct comedi_cmd * cmd) +static void set_ai_pacing(struct comedi_device *dev, struct comedi_cmd *cmd) { uint32_t convert_counter = 0, scan_counter = 0; @@ -2520,23 +2515,23 @@ static void set_ai_pacing(struct comedi_device * dev, struct comedi_cmd * cmd) scan_counter = ai_scan_counter_6xxx(dev, cmd); } - // load lower 16 bits of convert interval + /* load lower 16 bits of convert interval */ writew(convert_counter & 0xffff, priv(dev)->main_iobase + ADC_SAMPLE_INTERVAL_LOWER_REG); DEBUG_PRINT("convert counter 0x%x\n", convert_counter); - // load upper 8 bits of convert interval + /* load upper 8 bits of convert interval */ writew((convert_counter >> 16) & 0xff, priv(dev)->main_iobase + ADC_SAMPLE_INTERVAL_UPPER_REG); - // load lower 16 bits of scan delay + /* load lower 16 bits of scan delay */ writew(scan_counter & 0xffff, priv(dev)->main_iobase + ADC_DELAY_INTERVAL_LOWER_REG); - // load upper 8 bits of scan delay + /* load upper 8 bits of scan delay */ writew((scan_counter >> 16) & 0xff, priv(dev)->main_iobase + ADC_DELAY_INTERVAL_UPPER_REG); DEBUG_PRINT("scan counter 0x%x\n", scan_counter); } -static int use_internal_queue_6xxx(const struct comedi_cmd * cmd) +static int use_internal_queue_6xxx(const struct comedi_cmd *cmd) { int i; for (i = 0; i + 1 < cmd->chanlist_len; i++) { @@ -2552,7 +2547,7 @@ static int use_internal_queue_6xxx(const struct comedi_cmd * cmd) return 1; } -static int setup_channel_queue(struct comedi_device * dev, const struct comedi_cmd * cmd) +static int setup_channel_queue(struct comedi_device *dev, const struct comedi_cmd *cmd) { unsigned short bits; int i; @@ -2563,25 +2558,25 @@ static int setup_channel_queue(struct comedi_device * dev, const struct comedi_c writew(priv(dev)->hw_config_bits, priv(dev)->main_iobase + HW_CONFIG_REG); bits = 0; - // set channel + /* set channel */ bits |= adc_chan_bits(CR_CHAN(cmd->chanlist[0])); - // set gain + /* set gain */ bits |= ai_range_bits_6xxx(dev, CR_RANGE(cmd->chanlist[0])); - // set single-ended / differential + /* set single-ended / differential */ bits |= se_diff_bit_6xxx(dev, CR_AREF(cmd->chanlist[0]) == AREF_DIFF); if (CR_AREF(cmd->chanlist[0]) == AREF_COMMON) bits |= ADC_COMMON_BIT; - // set stop channel + /* set stop channel */ writew(adc_chan_bits(CR_CHAN(cmd->chanlist[cmd-> chanlist_len - 1])), priv(dev)->main_iobase + ADC_QUEUE_HIGH_REG); - // set start channel, and rest of settings + /* set start channel, and rest of settings */ writew(bits, priv(dev)->main_iobase + ADC_QUEUE_LOAD_REG); } else { - // use external queue + /* use external queue */ if (dev->write_subdev && dev->write_subdev->busy) { warn_external_queue(dev); return -EBUSY; @@ -2589,26 +2584,26 @@ static int setup_channel_queue(struct comedi_device * dev, const struct comedi_c priv(dev)->hw_config_bits |= EXT_QUEUE_BIT; writew(priv(dev)->hw_config_bits, priv(dev)->main_iobase + HW_CONFIG_REG); - // clear DAC buffer to prevent weird interactions + /* clear DAC buffer to prevent weird interactions */ writew(0, priv(dev)->main_iobase + DAC_BUFFER_CLEAR_REG); - // clear queue pointer + /* clear queue pointer */ writew(0, priv(dev)->main_iobase + ADC_QUEUE_CLEAR_REG); - // load external queue + /* load external queue */ for (i = 0; i < cmd->chanlist_len; i++) { bits = 0; - // set channel + /* set channel */ bits |= adc_chan_bits(CR_CHAN(cmd-> chanlist[i])); - // set gain + /* set gain */ bits |= ai_range_bits_6xxx(dev, CR_RANGE(cmd->chanlist[i])); - // set single-ended / differential + /* set single-ended / differential */ bits |= se_diff_bit_6xxx(dev, CR_AREF(cmd->chanlist[i]) == AREF_DIFF); if (CR_AREF(cmd->chanlist[i]) == AREF_COMMON) bits |= ADC_COMMON_BIT; - // mark end of queue + /* mark end of queue */ if (i == cmd->chanlist_len - 1) bits |= QUEUE_EOSCAN_BIT | QUEUE_EOSEQ_BIT; @@ -2622,7 +2617,7 @@ static int setup_channel_queue(struct comedi_device * dev, const struct comedi_c /* doing a queue clear is not specified in board docs, * but required for reliable operation */ writew(0, priv(dev)->main_iobase + ADC_QUEUE_CLEAR_REG); - // prime queue holding register + /* prime queue holding register */ writew(0, priv(dev)->main_iobase + ADC_QUEUE_LOAD_REG); } } else { @@ -2630,9 +2625,9 @@ static int setup_channel_queue(struct comedi_device * dev, const struct comedi_c priv(dev)->i2c_cal_range_bits; priv(dev)->i2c_cal_range_bits &= ~ADC_SRC_4020_MASK; - //select BNC inputs + /* select BNC inputs */ priv(dev)->i2c_cal_range_bits |= adc_src_4020_bits(4); - // select ranges + /* select ranges */ for (i = 0; i < cmd->chanlist_len; i++) { unsigned int channel = CR_CHAN(cmd->chanlist[i]); unsigned int range = CR_RANGE(cmd->chanlist[i]); @@ -2644,7 +2639,7 @@ static int setup_channel_queue(struct comedi_device * dev, const struct comedi_c priv(dev)->i2c_cal_range_bits &= ~attenuate_bit(channel); } - // update calibration/range i2c register only if necessary, as it is very slow + /* update calibration/range i2c register only if necessary, as it is very slow */ if (old_cal_range_bits != priv(dev)->i2c_cal_range_bits) { uint8_t i2c_data = priv(dev)->i2c_cal_range_bits; i2c_write(dev, RANGE_CAL_I2C_ADDR, &i2c_data, @@ -2654,7 +2649,7 @@ static int setup_channel_queue(struct comedi_device * dev, const struct comedi_c return 0; } -static inline void load_first_dma_descriptor(struct comedi_device * dev, +static inline void load_first_dma_descriptor(struct comedi_device *dev, unsigned int dma_channel, unsigned int descriptor_bits) { /* The transfer size, pci address, and local address registers @@ -2681,7 +2676,7 @@ static inline void load_first_dma_descriptor(struct comedi_device * dev, } } -static int ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s) +static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; @@ -2697,7 +2692,7 @@ static int ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s) if (retval < 0) return retval; - // make sure internal calibration source is turned off + /* make sure internal calibration source is turned off */ writew(0, priv(dev)->main_iobase + CALIBRATION_REG); set_ai_pacing(dev, cmd); @@ -2706,16 +2701,16 @@ static int ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s) enable_ai_interrupts(dev, cmd); - comedi_spin_lock_irqsave(&dev->spinlock, flags); + spin_lock_irqsave(&dev->spinlock, flags); /* set mode, allow conversions through software gate */ priv(dev)->adc_control1_bits |= ADC_SW_GATE_BIT; priv(dev)->adc_control1_bits &= ~ADC_DITHER_BIT; if (board(dev)->layout != LAYOUT_4020) { priv(dev)->adc_control1_bits &= ~ADC_MODE_MASK; if (cmd->convert_src == TRIG_EXT) - priv(dev)->adc_control1_bits |= adc_mode_bits(13); // good old mode 13 + priv(dev)->adc_control1_bits |= adc_mode_bits(13); /* good old mode 13 */ else - priv(dev)->adc_control1_bits |= adc_mode_bits(8); // mode 8. What else could you need? + priv(dev)->adc_control1_bits |= adc_mode_bits(8); /* mode 8. What else could you need? */ } else { priv(dev)->adc_control1_bits &= ~CHANNEL_MODE_4020_MASK; if (cmd->chanlist_len == 4) @@ -2733,22 +2728,22 @@ static int ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s) writew(priv(dev)->adc_control1_bits, priv(dev)->main_iobase + ADC_CONTROL1_REG); DEBUG_PRINT("control1 bits 0x%x\n", priv(dev)->adc_control1_bits); - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); - // clear adc buffer + /* clear adc buffer */ writew(0, priv(dev)->main_iobase + ADC_BUFFER_CLEAR_REG); if ((cmd->flags & TRIG_WAKE_EOS) == 0 || board(dev)->layout == LAYOUT_4020) { priv(dev)->ai_dma_index = 0; - // set dma transfer size + /* set dma transfer size */ for (i = 0; i < ai_dma_ring_count(board(dev)); i++) priv(dev)->ai_dma_desc[i].transfer_size = cpu_to_le32(dma_transfer_size(dev) * sizeof(uint16_t)); - // give location of first dma descriptor + /* give location of first dma descriptor */ load_first_dma_descriptor(dev, 1, priv(dev)-> ai_dma_desc_bus_addr | PLX_DESC_IN_PCI_BIT | @@ -2767,13 +2762,13 @@ static int ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s) writew(bits, priv(dev)->main_iobase + DAQ_ATRIG_LOW_4020_REG); } - comedi_spin_lock_irqsave(&dev->spinlock, flags); + spin_lock_irqsave(&dev->spinlock, flags); /* enable pacing, triggering, etc */ bits = ADC_ENABLE_BIT | ADC_SOFT_GATE_BITS | ADC_GATE_LEVEL_BIT; if (cmd->flags & TRIG_WAKE_EOS) bits |= ADC_DMA_DISABLE_BIT; - // set start trigger + /* set start trigger */ if (cmd->start_src == TRIG_EXT) { bits |= ADC_START_TRIG_EXT_BITS; if (cmd->start_arg & CR_INVERT) @@ -2787,9 +2782,9 @@ static int ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s) priv(dev)->ai_cmd_running = 1; - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); - // start aquisition + /* start aquisition */ if (cmd->start_src == TRIG_NOW) { writew(0, priv(dev)->main_iobase + ADC_START_REG); DEBUG_PRINT("soft trig\n"); @@ -2798,8 +2793,8 @@ static int ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s) return 0; } -// read num_samples from 16 bit wide ai fifo -static void pio_drain_ai_fifo_16(struct comedi_device * dev) +/* read num_samples from 16 bit wide ai fifo */ +static void pio_drain_ai_fifo_16(struct comedi_device *dev) { struct comedi_subdevice *s = dev->read_subdev; struct comedi_async *async = s->async; @@ -2810,7 +2805,7 @@ static void pio_drain_ai_fifo_16(struct comedi_device * dev) int num_samples; do { - // get least significant 15 bits + /* get least significant 15 bits */ read_index = readw(priv(dev)->main_iobase + ADC_READ_PNTR_REG) & 0x7fff; @@ -2847,7 +2842,7 @@ static void pio_drain_ai_fifo_16(struct comedi_device * dev) } if (num_samples < 0) { - rt_printk(" cb_pcidas64: bug! num_samples < 0\n"); + printk(" cb_pcidas64: bug! num_samples < 0\n"); break; } @@ -2866,7 +2861,7 @@ static void pio_drain_ai_fifo_16(struct comedi_device * dev) * dma transfers (it only supports the use of pio for draining the last remaining * points from the fifo when a data aquisition operation has completed). */ -static void pio_drain_ai_fifo_32(struct comedi_device * dev) +static void pio_drain_ai_fifo_32(struct comedi_device *dev) { struct comedi_subdevice *s = dev->read_subdev; struct comedi_async *async = s->async; @@ -2899,8 +2894,8 @@ static void pio_drain_ai_fifo_32(struct comedi_device * dev) priv(dev)->ai_count -= i; } -// empty fifo -static void pio_drain_ai_fifo(struct comedi_device * dev) +/* empty fifo */ +static void pio_drain_ai_fifo(struct comedi_device *dev) { if (board(dev)->layout == LAYOUT_4020) { pio_drain_ai_fifo_32(dev); @@ -2908,7 +2903,7 @@ static void pio_drain_ai_fifo(struct comedi_device * dev) pio_drain_ai_fifo_16(dev); } -static void drain_dma_buffers(struct comedi_device * dev, unsigned int channel) +static void drain_dma_buffers(struct comedi_device *dev, unsigned int channel) { struct comedi_async *async = dev->read_subdev->async; uint32_t next_transfer_addr; @@ -2923,7 +2918,7 @@ static void drain_dma_buffers(struct comedi_device * dev, unsigned int channel) pci_addr_reg = priv(dev)->plx9080_iobase + PLX_DMA0_PCI_ADDRESS_REG; - // loop until we have read all the full buffers + /* loop until we have read all the full buffers */ for (j = 0, next_transfer_addr = readl(pci_addr_reg); (next_transfer_addr < priv(dev)->ai_buffer_bus_addr[priv(dev)->ai_dma_index] @@ -2931,7 +2926,7 @@ static void drain_dma_buffers(struct comedi_device * dev, unsigned int channel) priv(dev)->ai_buffer_bus_addr[priv(dev)->ai_dma_index] + DMA_BUFFER_SIZE) && j < ai_dma_ring_count(board(dev)); j++) { - // transfer data from dma buffer to comedi buffer + /* transfer data from dma buffer to comedi buffer */ num_samples = dma_transfer_size(dev); if (async->cmd.stop_src == TRIG_COUNT) { if (num_samples > priv(dev)->ai_count) @@ -2954,7 +2949,7 @@ static void drain_dma_buffers(struct comedi_device * dev, unsigned int channel) * unused buffer) */ } -void handle_ai_interrupt(struct comedi_device * dev, unsigned short status, +void handle_ai_interrupt(struct comedi_device *dev, unsigned short status, unsigned int plx_status) { struct comedi_subdevice *s = dev->read_subdev; @@ -2963,15 +2958,15 @@ void handle_ai_interrupt(struct comedi_device * dev, unsigned short status, uint8_t dma1_status; unsigned long flags; - // check for fifo overrun + /* check for fifo overrun */ if (status & ADC_OVERRUN_BIT) { comedi_error(dev, "fifo overrun"); async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; } - // spin lock makes sure noone else changes plx dma control reg - comedi_spin_lock_irqsave(&dev->spinlock, flags); + /* spin lock makes sure noone else changes plx dma control reg */ + spin_lock_irqsave(&dev->spinlock, flags); dma1_status = readb(priv(dev)->plx9080_iobase + PLX_DMA1_CS_REG); - if (plx_status & ICS_DMA1_A) { // dma chan 1 interrupt + if (plx_status & ICS_DMA1_A) { /* dma chan 1 interrupt */ writeb((dma1_status & PLX_DMA_EN_BIT) | PLX_CLEAR_DMA_INTR_BIT, priv(dev)->plx9080_iobase + PLX_DMA1_CS_REG); DEBUG_PRINT("dma1 status 0x%x\n", dma1_status); @@ -2981,25 +2976,25 @@ void handle_ai_interrupt(struct comedi_device * dev, unsigned short status, } DEBUG_PRINT(" cleared dma ch1 interrupt\n"); } - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); if (status & ADC_DONE_BIT) DEBUG_PRINT("adc done interrupt\n"); - // drain fifo with pio + /* drain fifo with pio */ if ((status & ADC_DONE_BIT) || ((cmd->flags & TRIG_WAKE_EOS) && (status & ADC_INTR_PENDING_BIT) && (board(dev)->layout != LAYOUT_4020))) { DEBUG_PRINT("pio fifo drain\n"); - comedi_spin_lock_irqsave(&dev->spinlock, flags); + spin_lock_irqsave(&dev->spinlock, flags); if (priv(dev)->ai_cmd_running) { - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); pio_drain_ai_fifo(dev); } else - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); } - // if we are have all the data, then quit + /* if we are have all the data, then quit */ if ((cmd->stop_src == TRIG_COUNT && priv(dev)->ai_count <= 0) || (cmd->stop_src == TRIG_EXT && (status & ADC_STOP_BIT))) { async->events |= COMEDI_CB_EOA; @@ -3008,7 +3003,7 @@ void handle_ai_interrupt(struct comedi_device * dev, unsigned short status, cfc_handle_events(dev, s); } -static inline unsigned int prev_ao_dma_index(struct comedi_device * dev) +static inline unsigned int prev_ao_dma_index(struct comedi_device *dev) { unsigned int buffer_index; @@ -3019,7 +3014,7 @@ static inline unsigned int prev_ao_dma_index(struct comedi_device * dev) return buffer_index; } -static int last_ao_dma_load_completed(struct comedi_device * dev) +static int last_ao_dma_load_completed(struct comedi_device *dev) { unsigned int buffer_index; unsigned int transfer_address; @@ -3038,7 +3033,7 @@ static int last_ao_dma_load_completed(struct comedi_device * dev) return 1; } -static int ao_stopped_by_error(struct comedi_device * dev, const struct comedi_cmd * cmd) +static int ao_stopped_by_error(struct comedi_device *dev, const struct comedi_cmd *cmd) { if (cmd->stop_src == TRIG_NONE) return 1; @@ -3051,7 +3046,7 @@ static int ao_stopped_by_error(struct comedi_device * dev, const struct comedi_c return 0; } -static inline int ao_dma_needs_restart(struct comedi_device * dev, +static inline int ao_dma_needs_restart(struct comedi_device *dev, unsigned short dma_status) { if ((dma_status & PLX_DMA_DONE_BIT) == 0 || @@ -3063,7 +3058,7 @@ static inline int ao_dma_needs_restart(struct comedi_device * dev, return 1; } -static void restart_ao_dma(struct comedi_device * dev) +static void restart_ao_dma(struct comedi_device *dev) { unsigned int dma_desc_bits; @@ -3076,7 +3071,7 @@ static void restart_ao_dma(struct comedi_device * dev) dma_start_sync(dev, 0); } -static void handle_ao_interrupt(struct comedi_device * dev, unsigned short status, +static void handle_ao_interrupt(struct comedi_device *dev, unsigned short status, unsigned int plx_status) { struct comedi_subdevice *s = dev->write_subdev; @@ -3091,10 +3086,10 @@ static void handle_ao_interrupt(struct comedi_device * dev, unsigned short statu async = s->async; cmd = &async->cmd; - // spin lock makes sure noone else changes plx dma control reg - comedi_spin_lock_irqsave(&dev->spinlock, flags); + /* spin lock makes sure noone else changes plx dma control reg */ + spin_lock_irqsave(&dev->spinlock, flags); dma0_status = readb(priv(dev)->plx9080_iobase + PLX_DMA0_CS_REG); - if (plx_status & ICS_DMA0_A) { // dma chan 0 interrupt + if (plx_status & ICS_DMA0_A) { /* dma chan 0 interrupt */ if ((dma0_status & PLX_DMA_EN_BIT) && !(dma0_status & PLX_DMA_DONE_BIT)) writeb(PLX_DMA_EN_BIT | PLX_CLEAR_DMA_INTR_BIT, @@ -3102,7 +3097,7 @@ static void handle_ao_interrupt(struct comedi_device * dev, unsigned short statu else writeb(PLX_CLEAR_DMA_INTR_BIT, priv(dev)->plx9080_iobase + PLX_DMA0_CS_REG); - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); DEBUG_PRINT("dma0 status 0x%x\n", dma0_status); if (dma0_status & PLX_DMA_EN_BIT) { load_ao_dma(dev, cmd); @@ -3112,7 +3107,7 @@ static void handle_ao_interrupt(struct comedi_device * dev, unsigned short statu } DEBUG_PRINT(" cleared dma ch0 interrupt\n"); } else - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); if ((status & DAC_DONE_BIT)) { async->events |= COMEDI_CB_EOA; @@ -3128,7 +3123,7 @@ static void handle_ao_interrupt(struct comedi_device * dev, unsigned short statu cfc_handle_events(dev, s); } -static irqreturn_t handle_interrupt(int irq, void *d PT_REGS_ARG) +static irqreturn_t handle_interrupt(int irq, void *d) { struct comedi_device *dev = d; unsigned short status; @@ -3152,8 +3147,8 @@ static irqreturn_t handle_interrupt(int irq, void *d PT_REGS_ARG) handle_ai_interrupt(dev, status, plx_status); handle_ao_interrupt(dev, status, plx_status); - // clear possible plx9080 interrupt sources - if (plx_status & ICS_LDIA) { // clear local doorbell interrupt + /* clear possible plx9080 interrupt sources */ + if (plx_status & ICS_LDIA) { /* clear local doorbell interrupt */ plx_bits = readl(priv(dev)->plx9080_iobase + PLX_DBR_OUT_REG); writel(plx_bits, priv(dev)->plx9080_iobase + PLX_DBR_OUT_REG); DEBUG_PRINT(" cleared local doorbell bits 0x%x\n", plx_bits); @@ -3164,29 +3159,29 @@ static irqreturn_t handle_interrupt(int irq, void *d PT_REGS_ARG) return IRQ_HANDLED; } -void abort_dma(struct comedi_device * dev, unsigned int channel) +void abort_dma(struct comedi_device *dev, unsigned int channel) { unsigned long flags; - // spinlock for plx dma control/status reg - comedi_spin_lock_irqsave(&dev->spinlock, flags); + /* spinlock for plx dma control/status reg */ + spin_lock_irqsave(&dev->spinlock, flags); plx9080_abort_dma(priv(dev)->plx9080_iobase, channel); - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); } -static int ai_cancel(struct comedi_device * dev, struct comedi_subdevice * s) +static int ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { unsigned long flags; - comedi_spin_lock_irqsave(&dev->spinlock, flags); + spin_lock_irqsave(&dev->spinlock, flags); if (priv(dev)->ai_cmd_running == 0) { - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); return 0; } priv(dev)->ai_cmd_running = 0; - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); disable_ai_pacing(dev); @@ -3196,21 +3191,21 @@ static int ai_cancel(struct comedi_device * dev, struct comedi_subdevice * s) return 0; } -static int ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int chan = CR_CHAN(insn->chanspec); int range = CR_RANGE(insn->chanspec); - // do some initializing + /* do some initializing */ writew(0, priv(dev)->main_iobase + DAC_CONTROL0_REG); - // set range + /* set range */ set_dac_range_bits(dev, &priv(dev)->dac_control1_bits, chan, range); writew(priv(dev)->dac_control1_bits, priv(dev)->main_iobase + DAC_CONTROL1_REG); - // write to channel + /* write to channel */ if (board(dev)->layout == LAYOUT_4020) { writew(data[0] & 0xff, priv(dev)->main_iobase + dac_lsb_4020_reg(chan)); @@ -3220,21 +3215,21 @@ static int ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s, writew(data[0], priv(dev)->main_iobase + dac_convert_reg(chan)); } - // remember output value + /* remember output value */ priv(dev)->ao_value[chan] = data[0]; return 1; } -static int ao_readback_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int ao_readback_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { data[0] = priv(dev)->ao_value[CR_CHAN(insn->chanspec)]; return 1; } -static void set_dac_control0_reg(struct comedi_device * dev, const struct comedi_cmd * cmd) +static void set_dac_control0_reg(struct comedi_device *dev, const struct comedi_cmd *cmd) { unsigned int bits = DAC_ENABLE_BIT | WAVEFORM_GATE_LEVEL_BIT | WAVEFORM_GATE_ENABLE_BIT | WAVEFORM_GATE_SELECT_BIT; @@ -3254,7 +3249,7 @@ static void set_dac_control0_reg(struct comedi_device * dev, const struct comedi writew(bits, priv(dev)->main_iobase + DAC_CONTROL0_REG); } -static void set_dac_control1_reg(struct comedi_device * dev, const struct comedi_cmd * cmd) +static void set_dac_control1_reg(struct comedi_device *dev, const struct comedi_cmd *cmd) { int i; @@ -3271,7 +3266,7 @@ static void set_dac_control1_reg(struct comedi_device * dev, const struct comedi priv(dev)->main_iobase + DAC_CONTROL1_REG); } -static void set_dac_select_reg(struct comedi_device * dev, const struct comedi_cmd * cmd) +static void set_dac_select_reg(struct comedi_device *dev, const struct comedi_cmd *cmd) { uint16_t bits; unsigned int first_channel, last_channel; @@ -3286,7 +3281,7 @@ static void set_dac_select_reg(struct comedi_device * dev, const struct comedi_c writew(bits, priv(dev)->main_iobase + DAC_SELECT_REG); } -static void set_dac_interval_regs(struct comedi_device * dev, const struct comedi_cmd * cmd) +static void set_dac_interval_regs(struct comedi_device *dev, const struct comedi_cmd *cmd) { unsigned int divisor; @@ -3304,8 +3299,8 @@ static void set_dac_interval_regs(struct comedi_device * dev, const struct comed priv(dev)->main_iobase + DAC_SAMPLE_INTERVAL_UPPER_REG); } -static unsigned int load_ao_dma_buffer(struct comedi_device * dev, - const struct comedi_cmd * cmd) +static unsigned int load_ao_dma_buffer(struct comedi_device *dev, + const struct comedi_cmd *cmd) { unsigned int num_bytes, buffer_index, prev_buffer_index; unsigned int next_bits; @@ -3348,7 +3343,7 @@ static unsigned int load_ao_dma_buffer(struct comedi_device * dev, return num_bytes; } -static void load_ao_dma(struct comedi_device * dev, const struct comedi_cmd * cmd) +static void load_ao_dma(struct comedi_device *dev, const struct comedi_cmd *cmd) { unsigned int num_bytes; unsigned int next_transfer_addr; @@ -3370,7 +3365,7 @@ static void load_ao_dma(struct comedi_device * dev, const struct comedi_cmd * cm } while (num_bytes >= DMA_BUFFER_SIZE); } -static int prep_ao_dma(struct comedi_device * dev, const struct comedi_cmd * cmd) +static int prep_ao_dma(struct comedi_device *dev, const struct comedi_cmd *cmd) { unsigned int num_bytes; int i; @@ -3404,7 +3399,7 @@ static int prep_ao_dma(struct comedi_device * dev, const struct comedi_cmd * cmd return 0; } -static inline int external_ai_queue_in_use(struct comedi_device * dev) +static inline int external_ai_queue_in_use(struct comedi_device *dev) { if (dev->read_subdev->busy) return 0; @@ -3415,7 +3410,7 @@ static inline int external_ai_queue_in_use(struct comedi_device * dev) return 1; } -static int ao_cmd(struct comedi_device * dev, struct comedi_subdevice * s) +static int ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { struct comedi_cmd *cmd = &s->async->cmd; @@ -3440,7 +3435,7 @@ static int ao_cmd(struct comedi_device * dev, struct comedi_subdevice * s) return 0; } -static int ao_inttrig(struct comedi_device * dev, struct comedi_subdevice * s, +static int ao_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int trig_num) { struct comedi_cmd *cmd = &s->async->cmd; @@ -3463,8 +3458,8 @@ static int ao_inttrig(struct comedi_device * dev, struct comedi_subdevice * s, return 0; } -static int ao_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd) +static int ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd) { int err = 0; int tmp; @@ -3503,14 +3498,14 @@ static int ao_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, /* step 2: make sure trigger sources are unique and mutually compatible */ - // uniqueness check + /* uniqueness check */ if (cmd->start_src != TRIG_INT && cmd->start_src != TRIG_EXT) err++; if (cmd->scan_begin_src != TRIG_TIMER && cmd->scan_begin_src != TRIG_EXT) err++; - // compatibility check + /* compatibility check */ if (cmd->convert_src == TRIG_EXT && cmd->scan_begin_src == TRIG_TIMER) err++; if (cmd->stop_src != TRIG_COUNT && @@ -3579,7 +3574,7 @@ static int ao_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, return 0; } -static int ao_cancel(struct comedi_device * dev, struct comedi_subdevice * s) +static int ao_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { writew(0x0, priv(dev)->main_iobase + DAC_CONTROL0_REG); abort_dma(dev, 0); @@ -3607,8 +3602,8 @@ static int dio_callback_4020(int dir, int port, int data, unsigned long iobase) } } -static int di_rbits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int di_rbits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { unsigned int bits; @@ -3620,13 +3615,13 @@ static int di_rbits(struct comedi_device * dev, struct comedi_subdevice * s, return 2; } -static int do_wbits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int do_wbits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { data[0] &= 0xf; - // zero bits we are going to change + /* zero bits we are going to change */ s->state &= ~data[0]; - // set new bits + /* set new bits */ s->state |= data[0] & data[1]; writeb(s->state, priv(dev)->dio_counter_iobase + DO_REG); @@ -3636,8 +3631,8 @@ static int do_wbits(struct comedi_device * dev, struct comedi_subdevice * s, return 2; } -static int dio_60xx_config_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int dio_60xx_config_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { unsigned int mask; @@ -3663,8 +3658,8 @@ static int dio_60xx_config_insn(struct comedi_device * dev, struct comedi_subdev return 1; } -static int dio_60xx_wbits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int dio_60xx_wbits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if (data[0]) { s->state &= ~data[0]; @@ -3678,7 +3673,7 @@ static int dio_60xx_wbits(struct comedi_device * dev, struct comedi_subdevice * return 2; } -static void caldac_write(struct comedi_device * dev, unsigned int channel, +static void caldac_write(struct comedi_device *dev, unsigned int channel, unsigned int value) { priv(dev)->caldac_state[channel] = value; @@ -3696,8 +3691,8 @@ static void caldac_write(struct comedi_device * dev, unsigned int channel, } } -static int calib_write_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int calib_write_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int channel = CR_CHAN(insn->chanspec); @@ -3711,8 +3706,8 @@ static int calib_write_insn(struct comedi_device * dev, struct comedi_subdevice return 1; } -static int calib_read_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int calib_read_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { unsigned int channel = CR_CHAN(insn->chanspec); @@ -3721,18 +3716,18 @@ static int calib_read_insn(struct comedi_device * dev, struct comedi_subdevice * return 1; } -static void ad8402_write(struct comedi_device * dev, unsigned int channel, +static void ad8402_write(struct comedi_device *dev, unsigned int channel, unsigned int value) { static const int bitstream_length = 10; unsigned int bit, register_bits; unsigned int bitstream = ((channel & 0x3) << 8) | (value & 0xff); - static const int ad8402_comedi_udelay = 1; + static const int ad8402_udelay = 1; priv(dev)->ad8402_state[channel] = value; register_bits = SELECT_8402_64XX_BIT; - comedi_udelay(ad8402_comedi_udelay); + udelay(ad8402_udelay); writew(register_bits, priv(dev)->main_iobase + CALIBRATION_REG); for (bit = 1 << (bitstream_length - 1); bit; bit >>= 1) { @@ -3740,20 +3735,20 @@ static void ad8402_write(struct comedi_device * dev, unsigned int channel, register_bits |= SERIAL_DATA_IN_BIT; else register_bits &= ~SERIAL_DATA_IN_BIT; - comedi_udelay(ad8402_comedi_udelay); + udelay(ad8402_udelay); writew(register_bits, priv(dev)->main_iobase + CALIBRATION_REG); - comedi_udelay(ad8402_comedi_udelay); + udelay(ad8402_udelay); writew(register_bits | SERIAL_CLOCK_BIT, priv(dev)->main_iobase + CALIBRATION_REG); } - comedi_udelay(ad8402_comedi_udelay); + udelay(ad8402_udelay); writew(0, priv(dev)->main_iobase + CALIBRATION_REG); } /* for pci-das6402/16, channel 0 is analog input gain and channel 1 is offset */ -static int ad8402_write_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int ad8402_write_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int channel = CR_CHAN(insn->chanspec); @@ -3769,8 +3764,8 @@ static int ad8402_write_insn(struct comedi_device * dev, struct comedi_subdevice return 1; } -static int ad8402_read_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int ad8402_read_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { unsigned int channel = CR_CHAN(insn->chanspec); @@ -3779,7 +3774,7 @@ static int ad8402_read_insn(struct comedi_device * dev, struct comedi_subdevice return 1; } -static uint16_t read_eeprom(struct comedi_device * dev, uint8_t address) +static uint16_t read_eeprom(struct comedi_device *dev, uint8_t address) { static const int bitstream_length = 11; static const int read_command = 0x6; @@ -3789,60 +3784,60 @@ static uint16_t read_eeprom(struct comedi_device * dev, uint8_t address) priv(dev)->plx9080_iobase + PLX_CONTROL_REG; uint16_t value; static const int value_length = 16; - static const int eeprom_comedi_udelay = 1; + static const int eeprom_udelay = 1; - comedi_udelay(eeprom_comedi_udelay); + udelay(eeprom_udelay); priv(dev)->plx_control_bits &= ~CTL_EE_CLK & ~CTL_EE_CS; - // make sure we don't send anything to the i2c bus on 4020 + /* make sure we don't send anything to the i2c bus on 4020 */ priv(dev)->plx_control_bits |= CTL_USERO; writel(priv(dev)->plx_control_bits, plx_control_addr); - // activate serial eeprom - comedi_udelay(eeprom_comedi_udelay); + /* activate serial eeprom */ + udelay(eeprom_udelay); priv(dev)->plx_control_bits |= CTL_EE_CS; writel(priv(dev)->plx_control_bits, plx_control_addr); - // write read command and desired memory address + /* write read command and desired memory address */ for (bit = 1 << (bitstream_length - 1); bit; bit >>= 1) { - // set bit to be written - comedi_udelay(eeprom_comedi_udelay); + /* set bit to be written */ + udelay(eeprom_udelay); if (bitstream & bit) priv(dev)->plx_control_bits |= CTL_EE_W; else priv(dev)->plx_control_bits &= ~CTL_EE_W; writel(priv(dev)->plx_control_bits, plx_control_addr); - // clock in bit - comedi_udelay(eeprom_comedi_udelay); + /* clock in bit */ + udelay(eeprom_udelay); priv(dev)->plx_control_bits |= CTL_EE_CLK; writel(priv(dev)->plx_control_bits, plx_control_addr); - comedi_udelay(eeprom_comedi_udelay); + udelay(eeprom_udelay); priv(dev)->plx_control_bits &= ~CTL_EE_CLK; writel(priv(dev)->plx_control_bits, plx_control_addr); } - // read back value from eeprom memory location + /* read back value from eeprom memory location */ value = 0; for (bit = 1 << (value_length - 1); bit; bit >>= 1) { - // clock out bit - comedi_udelay(eeprom_comedi_udelay); + /* clock out bit */ + udelay(eeprom_udelay); priv(dev)->plx_control_bits |= CTL_EE_CLK; writel(priv(dev)->plx_control_bits, plx_control_addr); - comedi_udelay(eeprom_comedi_udelay); + udelay(eeprom_udelay); priv(dev)->plx_control_bits &= ~CTL_EE_CLK; writel(priv(dev)->plx_control_bits, plx_control_addr); - comedi_udelay(eeprom_comedi_udelay); + udelay(eeprom_udelay); if (readl(plx_control_addr) & CTL_EE_R) value |= bit; } - // deactivate eeprom serial input - comedi_udelay(eeprom_comedi_udelay); + /* deactivate eeprom serial input */ + udelay(eeprom_udelay); priv(dev)->plx_control_bits &= ~CTL_EE_CS; writel(priv(dev)->plx_control_bits, plx_control_addr); return value; } -static int eeprom_read_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int eeprom_read_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { data[0] = read_eeprom(dev, CR_CHAN(insn->chanspec)); @@ -3880,7 +3875,7 @@ static void check_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd) if (cmd->scan_begin_src == TRIG_TIMER) { scan_divisor = get_divisor(cmd->scan_begin_arg, cmd->flags); if (cmd->convert_src == TRIG_TIMER) { - // XXX check for integer overflows + /* XXX check for integer overflows */ min_scan_divisor = convert_divisor * cmd->chanlist_len; max_scan_divisor = (convert_divisor * cmd->chanlist_len - 1) + @@ -3926,8 +3921,8 @@ static unsigned int get_ao_divisor(unsigned int ns, unsigned int flags) return get_divisor(ns, flags) - 2; } -// adjusts the size of hardware fifo (which determines block size for dma xfers) -static int set_ai_fifo_size(struct comedi_device * dev, unsigned int num_samples) +/* adjusts the size of hardware fifo (which determines block size for dma xfers) */ +static int set_ai_fifo_size(struct comedi_device *dev, unsigned int num_samples) { unsigned int num_fifo_entries; int retval; @@ -3947,15 +3942,15 @@ static int set_ai_fifo_size(struct comedi_device * dev, unsigned int num_samples return num_samples; } -// query length of fifo -static unsigned int ai_fifo_size(struct comedi_device * dev) +/* query length of fifo */ +static unsigned int ai_fifo_size(struct comedi_device *dev) { return priv(dev)->ai_fifo_segment_length * board(dev)->ai_fifo->num_segments * board(dev)->ai_fifo->sample_packing_ratio; } -static int set_ai_fifo_segment_length(struct comedi_device * dev, +static int set_ai_fifo_segment_length(struct comedi_device *dev, unsigned int num_entries) { static const int increment_size = 0x100; @@ -3968,7 +3963,7 @@ static int set_ai_fifo_segment_length(struct comedi_device * dev, if (num_entries > fifo->max_segment_length) num_entries = fifo->max_segment_length; - // 1 == 256 entries, 2 == 512 entries, etc + /* 1 == 256 entries, 2 == 512 entries, etc */ num_increments = (num_entries + increment_size / 2) / increment_size; bits = (~(num_increments - 1)) & fifo->fifo_size_reg_mask; @@ -4006,7 +4001,7 @@ static int set_ai_fifo_segment_length(struct comedi_device * dev, * address 7 == dac channel 1 fine offset */ -static int caldac_8800_write(struct comedi_device * dev, unsigned int address, +static int caldac_8800_write(struct comedi_device *dev, unsigned int address, uint8_t value) { static const int num_caldac_channels = 8; @@ -4023,28 +4018,28 @@ static int caldac_8800_write(struct comedi_device * dev, unsigned int address, register_bits = 0; if (bitstream & bit) register_bits |= SERIAL_DATA_IN_BIT; - comedi_udelay(caldac_8800_udelay); + udelay(caldac_8800_udelay); writew(register_bits, priv(dev)->main_iobase + CALIBRATION_REG); register_bits |= SERIAL_CLOCK_BIT; - comedi_udelay(caldac_8800_udelay); + udelay(caldac_8800_udelay); writew(register_bits, priv(dev)->main_iobase + CALIBRATION_REG); } - comedi_udelay(caldac_8800_udelay); + udelay(caldac_8800_udelay); writew(SELECT_8800_BIT, priv(dev)->main_iobase + CALIBRATION_REG); - comedi_udelay(caldac_8800_udelay); + udelay(caldac_8800_udelay); writew(0, priv(dev)->main_iobase + CALIBRATION_REG); - comedi_udelay(caldac_8800_udelay); + udelay(caldac_8800_udelay); return 0; } -// 4020 caldacs -static int caldac_i2c_write(struct comedi_device * dev, unsigned int caldac_channel, +/* 4020 caldacs */ +static int caldac_i2c_write(struct comedi_device *dev, unsigned int caldac_channel, unsigned int value) { uint8_t serial_bytes[3]; uint8_t i2c_addr; enum pointer_bits { - // manual has gain and offset bits switched + /* manual has gain and offset bits switched */ OFFSET_0_2 = 0x1, GAIN_0_2 = 0x2, OFFSET_1_3 = 0x4, @@ -4055,35 +4050,35 @@ static int caldac_i2c_write(struct comedi_device * dev, unsigned int caldac_chan }; switch (caldac_channel) { - case 0: // chan 0 offset + case 0: /* chan 0 offset */ i2c_addr = CALDAC0_I2C_ADDR; serial_bytes[0] = OFFSET_0_2; break; - case 1: // chan 1 offset + case 1: /* chan 1 offset */ i2c_addr = CALDAC0_I2C_ADDR; serial_bytes[0] = OFFSET_1_3; break; - case 2: // chan 2 offset + case 2: /* chan 2 offset */ i2c_addr = CALDAC1_I2C_ADDR; serial_bytes[0] = OFFSET_0_2; break; - case 3: // chan 3 offset + case 3: /* chan 3 offset */ i2c_addr = CALDAC1_I2C_ADDR; serial_bytes[0] = OFFSET_1_3; break; - case 4: // chan 0 gain + case 4: /* chan 0 gain */ i2c_addr = CALDAC0_I2C_ADDR; serial_bytes[0] = GAIN_0_2; break; - case 5: // chan 1 gain + case 5: /* chan 1 gain */ i2c_addr = CALDAC0_I2C_ADDR; serial_bytes[0] = GAIN_1_3; break; - case 6: // chan 2 gain + case 6: /* chan 2 gain */ i2c_addr = CALDAC1_I2C_ADDR; serial_bytes[0] = GAIN_0_2; break; - case 7: // chan 3 gain + case 7: /* chan 3 gain */ i2c_addr = CALDAC1_I2C_ADDR; serial_bytes[0] = GAIN_1_3; break; @@ -4098,49 +4093,49 @@ static int caldac_i2c_write(struct comedi_device * dev, unsigned int caldac_chan return 0; } -// Their i2c requires a huge delay on setting clock or data high for some reason -static const int i2c_high_comedi_udelay = 1000; -static const int i2c_low_comedi_udelay = 10; +/* Their i2c requires a huge delay on setting clock or data high for some reason */ +static const int i2c_high_udelay = 1000; +static const int i2c_low_udelay = 10; -// set i2c data line high or low -static void i2c_set_sda(struct comedi_device * dev, int state) +/* set i2c data line high or low */ +static void i2c_set_sda(struct comedi_device *dev, int state) { static const int data_bit = CTL_EE_W; void *plx_control_addr = priv(dev)->plx9080_iobase + PLX_CONTROL_REG; if (state) { - // set data line high + /* set data line high */ priv(dev)->plx_control_bits &= ~data_bit; writel(priv(dev)->plx_control_bits, plx_control_addr); - comedi_udelay(i2c_high_comedi_udelay); - } else // set data line low + udelay(i2c_high_udelay); + } else /* set data line low */ { priv(dev)->plx_control_bits |= data_bit; writel(priv(dev)->plx_control_bits, plx_control_addr); - comedi_udelay(i2c_low_comedi_udelay); + udelay(i2c_low_udelay); } } -// set i2c clock line high or low -static void i2c_set_scl(struct comedi_device * dev, int state) +/* set i2c clock line high or low */ +static void i2c_set_scl(struct comedi_device *dev, int state) { static const int clock_bit = CTL_USERO; void *plx_control_addr = priv(dev)->plx9080_iobase + PLX_CONTROL_REG; if (state) { - // set clock line high + /* set clock line high */ priv(dev)->plx_control_bits &= ~clock_bit; writel(priv(dev)->plx_control_bits, plx_control_addr); - comedi_udelay(i2c_high_comedi_udelay); - } else // set clock line low + udelay(i2c_high_udelay); + } else /* set clock line low */ { priv(dev)->plx_control_bits |= clock_bit; writel(priv(dev)->plx_control_bits, plx_control_addr); - comedi_udelay(i2c_low_comedi_udelay); + udelay(i2c_low_udelay); } } -static void i2c_write_byte(struct comedi_device * dev, uint8_t byte) +static void i2c_write_byte(struct comedi_device *dev, uint8_t byte) { uint8_t bit; unsigned int num_bits = 8; @@ -4157,26 +4152,26 @@ static void i2c_write_byte(struct comedi_device * dev, uint8_t byte) } } -// we can't really read the lines, so fake it -static int i2c_read_ack(struct comedi_device * dev) +/* we can't really read the lines, so fake it */ +static int i2c_read_ack(struct comedi_device *dev) { i2c_set_scl(dev, 0); i2c_set_sda(dev, 1); i2c_set_scl(dev, 1); - return 0; // return fake acknowledge bit + return 0; /* return fake acknowledge bit */ } -// send start bit -static void i2c_start(struct comedi_device * dev) +/* send start bit */ +static void i2c_start(struct comedi_device *dev) { i2c_set_scl(dev, 1); i2c_set_sda(dev, 1); i2c_set_sda(dev, 0); } -// send stop bit -static void i2c_stop(struct comedi_device * dev) +/* send stop bit */ +static void i2c_stop(struct comedi_device *dev) { i2c_set_scl(dev, 0); i2c_set_sda(dev, 0); @@ -4184,32 +4179,32 @@ static void i2c_stop(struct comedi_device * dev) i2c_set_sda(dev, 1); } -static void i2c_write(struct comedi_device * dev, unsigned int address, - const uint8_t * data, unsigned int length) +static void i2c_write(struct comedi_device *dev, unsigned int address, + const uint8_t *data, unsigned int length) { unsigned int i; uint8_t bitstream; static const int read_bit = 0x1; -//XXX need mutex to prevent simultaneous attempts to access eeprom and i2c bus +/* XXX need mutex to prevent simultaneous attempts to access eeprom and i2c bus */ - // make sure we dont send anything to eeprom + /* make sure we dont send anything to eeprom */ priv(dev)->plx_control_bits &= ~CTL_EE_CS; i2c_stop(dev); i2c_start(dev); - // send address and write bit + /* send address and write bit */ bitstream = (address << 1) & ~read_bit; i2c_write_byte(dev, bitstream); - // get acknowledge + /* get acknowledge */ if (i2c_read_ack(dev) != 0) { comedi_error(dev, "i2c write failed: no acknowledge"); i2c_stop(dev); return; } - // write data bytes + /* write data bytes */ for (i = 0; i < length; i++) { i2c_write_byte(dev, data[i]); if (i2c_read_ack(dev) != 0) { diff --git a/drivers/staging/comedi/drivers/cb_pcidda.c b/drivers/staging/comedi/drivers/cb_pcidda.c index ed0a5eb3dd91..8f3629416188 100644 --- a/drivers/staging/comedi/drivers/cb_pcidda.c +++ b/drivers/staging/comedi/drivers/cb_pcidda.c @@ -51,66 +51,66 @@ Please report success/failure with other different cards to #include "comedi_pci.h" #include "8255.h" -#define PCI_VENDOR_ID_CB 0x1307 // PCI vendor number of ComputerBoards -#define N_BOARDS 10 // Number of boards in cb_pcidda_boards -#define EEPROM_SIZE 128 // number of entries in eeprom -#define MAX_AO_CHANNELS 8 // maximum number of ao channels for supported boards +#define PCI_VENDOR_ID_CB 0x1307 /* PCI vendor number of ComputerBoards */ +#define N_BOARDS 10 /* Number of boards in cb_pcidda_boards */ +#define EEPROM_SIZE 128 /* number of entries in eeprom */ +#define MAX_AO_CHANNELS 8 /* maximum number of ao channels for supported boards */ /* PCI-DDA base addresses */ #define DIGITALIO_BADRINDEX 2 - // DIGITAL I/O is pci_dev->resource[2] + /* DIGITAL I/O is pci_dev->resource[2] */ #define DIGITALIO_SIZE 8 - // DIGITAL I/O uses 8 I/O port addresses + /* DIGITAL I/O uses 8 I/O port addresses */ #define DAC_BADRINDEX 3 - // DAC is pci_dev->resource[3] + /* DAC is pci_dev->resource[3] */ /* Digital I/O registers */ -#define PORT1A 0 // PORT 1A DATA +#define PORT1A 0 /* PORT 1A DATA */ -#define PORT1B 1 // PORT 1B DATA +#define PORT1B 1 /* PORT 1B DATA */ -#define PORT1C 2 // PORT 1C DATA +#define PORT1C 2 /* PORT 1C DATA */ -#define CONTROL1 3 // CONTROL REGISTER 1 +#define CONTROL1 3 /* CONTROL REGISTER 1 */ -#define PORT2A 4 // PORT 2A DATA +#define PORT2A 4 /* PORT 2A DATA */ -#define PORT2B 5 // PORT 2B DATA +#define PORT2B 5 /* PORT 2B DATA */ -#define PORT2C 6 // PORT 2C DATA +#define PORT2C 6 /* PORT 2C DATA */ -#define CONTROL2 7 // CONTROL REGISTER 2 +#define CONTROL2 7 /* CONTROL REGISTER 2 */ /* DAC registers */ -#define DACONTROL 0 // D/A CONTROL REGISTER -#define SU 0000001 // Simultaneous update enabled -#define NOSU 0000000 // Simultaneous update disabled -#define ENABLEDAC 0000002 // Enable specified DAC -#define DISABLEDAC 0000000 // Disable specified DAC -#define RANGE2V5 0000000 // 2.5V -#define RANGE5V 0000200 // 5V -#define RANGE10V 0000300 // 10V -#define UNIP 0000400 // Unipolar outputs -#define BIP 0000000 // Bipolar outputs +#define DACONTROL 0 /* D/A CONTROL REGISTER */ +#define SU 0000001 /* Simultaneous update enabled */ +#define NOSU 0000000 /* Simultaneous update disabled */ +#define ENABLEDAC 0000002 /* Enable specified DAC */ +#define DISABLEDAC 0000000 /* Disable specified DAC */ +#define RANGE2V5 0000000 /* 2.5V */ +#define RANGE5V 0000200 /* 5V */ +#define RANGE10V 0000300 /* 10V */ +#define UNIP 0000400 /* Unipolar outputs */ +#define BIP 0000000 /* Bipolar outputs */ -#define DACALIBRATION1 4 // D/A CALIBRATION REGISTER 1 -//write bits -#define SERIAL_IN_BIT 0x1 // serial data input for eeprom, caldacs, reference dac +#define DACALIBRATION1 4 /* D/A CALIBRATION REGISTER 1 */ +/* write bits */ +#define SERIAL_IN_BIT 0x1 /* serial data input for eeprom, caldacs, reference dac */ #define CAL_CHANNEL_MASK (0x7 << 1) #define CAL_CHANNEL_BITS(channel) (((channel) << 1) & CAL_CHANNEL_MASK) -//read bits +/* read bits */ #define CAL_COUNTER_MASK 0x1f -#define CAL_COUNTER_OVERFLOW_BIT 0x20 // calibration counter overflow status bit -#define AO_BELOW_REF_BIT 0x40 // analog output is less than reference dac voltage -#define SERIAL_OUT_BIT 0x80 // serial data out, for reading from eeprom +#define CAL_COUNTER_OVERFLOW_BIT 0x20 /* calibration counter overflow status bit */ +#define AO_BELOW_REF_BIT 0x40 /* analog output is less than reference dac voltage */ +#define SERIAL_OUT_BIT 0x80 /* serial data out, for reading from eeprom */ -#define DACALIBRATION2 6 // D/A CALIBRATION REGISTER 2 -#define SELECT_EEPROM_BIT 0x1 // send serial data in to eeprom -#define DESELECT_REF_DAC_BIT 0x2 // don't send serial data to MAX542 reference dac -#define DESELECT_CALDAC_BIT(n) (0x4 << (n)) // don't send serial data to caldac n -#define DUMMY_BIT 0x40 // manual says to set this bit with no explanation +#define DACALIBRATION2 6 /* D/A CALIBRATION REGISTER 2 */ +#define SELECT_EEPROM_BIT 0x1 /* send serial data in to eeprom */ +#define DESELECT_REF_DAC_BIT 0x2 /* don't send serial data to MAX542 reference dac */ +#define DESELECT_CALDAC_BIT(n) (0x4 << (n)) /* don't send serial data to caldac n */ +#define DUMMY_BIT 0x40 /* manual says to set this bit with no explanation */ -#define DADATA 8 // FIRST D/A DATA REGISTER (0) +#define DADATA 8 /* FIRST D/A DATA REGISTER (0) */ static const struct comedi_lrange cb_pcidda_ranges = { 6, @@ -131,63 +131,68 @@ static const struct comedi_lrange cb_pcidda_ranges = { */ struct cb_pcidda_board { const char *name; - char status; // Driver status: - // 0 - tested - // 1 - manual read, not tested - // 2 - manual not read + char status; /* Driver status: */ + + /* + * 0 - tested + * 1 - manual read, not tested + * 2 - manual not read + */ + unsigned short device_id; int ao_chans; int ao_bits; const struct comedi_lrange *ranges; }; + static const struct cb_pcidda_board cb_pcidda_boards[] = { { - name: "pci-dda02/12", - status: 1, - device_id:0x20, - ao_chans:2, - ao_bits: 12, - ranges: &cb_pcidda_ranges, + .name = "pci-dda02/12", + .status = 1, + .device_id = 0x20, + .ao_chans = 2, + .ao_bits = 12, + .ranges = &cb_pcidda_ranges, }, { - name: "pci-dda04/12", - status: 1, - device_id:0x21, - ao_chans:4, - ao_bits: 12, - ranges: &cb_pcidda_ranges, + .name = "pci-dda04/12", + .status = 1, + .device_id = 0x21, + .ao_chans = 4, + .ao_bits = 12, + .ranges = &cb_pcidda_ranges, }, { - name: "pci-dda08/12", - status: 0, - device_id:0x22, - ao_chans:8, - ao_bits: 12, - ranges: &cb_pcidda_ranges, + .name = "pci-dda08/12", + .status = 0, + .device_id = 0x22, + .ao_chans = 8, + .ao_bits = 12, + .ranges = &cb_pcidda_ranges, }, { - name: "pci-dda02/16", - status: 2, - device_id:0x23, - ao_chans:2, - ao_bits: 16, - ranges: &cb_pcidda_ranges, + .name = "pci-dda02/16", + .status = 2, + .device_id = 0x23, + .ao_chans = 2, + .ao_bits = 16, + .ranges = &cb_pcidda_ranges, }, { - name: "pci-dda04/16", - status: 2, - device_id:0x24, - ao_chans:4, - ao_bits: 16, - ranges: &cb_pcidda_ranges, + .name = "pci-dda04/16", + .status = 2, + .device_id = 0x24, + .ao_chans = 4, + .ao_bits = 16, + .ranges = &cb_pcidda_ranges, }, { - name: "pci-dda08/16", - status: 0, - device_id:0x25, - ao_chans:8, - ao_bits: 16, - ranges: &cb_pcidda_ranges, + .name = "pci-dda08/16", + .status = 0, + .device_id = 0x25, + .ao_chans = 8, + .ao_bits = 16, + .ranges = &cb_pcidda_ranges, }, }; @@ -219,11 +224,13 @@ struct cb_pcidda_private { unsigned long digitalio; unsigned long dac; - //unsigned long control_status; - //unsigned long adc_fifo; - unsigned int dac_cal1_bits; // bits last written to da calibration register 1 - unsigned int ao_range[MAX_AO_CHANNELS]; // current range settings for output channels - u16 eeprom_data[EEPROM_SIZE]; // software copy of board's eeprom + + /* unsigned long control_status; */ + /* unsigned long adc_fifo; */ + + unsigned int dac_cal1_bits; /* bits last written to da calibration register 1 */ + unsigned int ao_range[MAX_AO_CHANNELS]; /* current range settings for output channels */ + u16 eeprom_data[EEPROM_SIZE]; /* software copy of board's eeprom */ }; /* @@ -232,20 +239,22 @@ struct cb_pcidda_private { */ #define devpriv ((struct cb_pcidda_private *)dev->private) -static int cb_pcidda_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int cb_pcidda_detach(struct comedi_device * dev); -//static int cb_pcidda_ai_rinsn(struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data); -static int cb_pcidda_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -//static int cb_pcidda_ai_cmd(struct comedi_device *dev,struct comedi_subdevice *s); -//static int cb_pcidda_ai_cmdtest(struct comedi_device *dev,struct comedi_subdevice *s, struct comedi_cmd *cmd); -//static int cb_pcidda_ns_to_timer(unsigned int *ns,int round); -static unsigned int cb_pcidda_serial_in(struct comedi_device * dev); -static void cb_pcidda_serial_out(struct comedi_device * dev, unsigned int value, +static int cb_pcidda_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int cb_pcidda_detach(struct comedi_device *dev); +/* static int cb_pcidda_ai_rinsn(struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data); */ +static int cb_pcidda_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); + +/* static int cb_pcidda_ai_cmd(struct comedi_device *dev, struct *comedi_subdevice *s);*/ +/* static int cb_pcidda_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd); */ +/* static int cb_pcidda_ns_to_timer(unsigned int *ns,int *round); */ + +static unsigned int cb_pcidda_serial_in(struct comedi_device *dev); +static void cb_pcidda_serial_out(struct comedi_device *dev, unsigned int value, unsigned int num_bits); -static unsigned int cb_pcidda_read_eeprom(struct comedi_device * dev, +static unsigned int cb_pcidda_read_eeprom(struct comedi_device *dev, unsigned int address); -static void cb_pcidda_calibrate(struct comedi_device * dev, unsigned int channel, +static void cb_pcidda_calibrate(struct comedi_device *dev, unsigned int channel, unsigned int range); /* @@ -255,17 +264,17 @@ static void cb_pcidda_calibrate(struct comedi_device * dev, unsigned int channel * the device code. */ static struct comedi_driver driver_cb_pcidda = { - driver_name:"cb_pcidda", - module:THIS_MODULE, - attach:cb_pcidda_attach, - detach:cb_pcidda_detach, + .driver_name = "cb_pcidda", + .module = THIS_MODULE, + .attach = cb_pcidda_attach, + .detach = cb_pcidda_detach, }; /* * Attach is called by the Comedi core to configure the driver * for a particular board. */ -static int cb_pcidda_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int cb_pcidda_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; struct pci_dev *pcidev; @@ -310,7 +319,7 @@ static int cb_pcidda_attach(struct comedi_device * dev, struct comedi_devconfig found: devpriv->pci_dev = pcidev; dev->board_ptr = cb_pcidda_boards + index; - // "thisboard" macro can be used from here. + /* "thisboard" macro can be used from here. */ printk("Found %s at requested position\n", thisboard->name); /* @@ -353,11 +362,12 @@ static int cb_pcidda_attach(struct comedi_device * dev, struct comedi_devconfig s->maxdata = (1 << thisboard->ao_bits) - 1; s->range_table = thisboard->ranges; s->insn_write = cb_pcidda_ao_winsn; -// s->subdev_flags |= SDF_CMD_READ; -// s->do_cmd = cb_pcidda_ai_cmd; -// s->do_cmdtest = cb_pcidda_ai_cmdtest; - // two 8255 digital io subdevices + /* s->subdev_flags |= SDF_CMD_READ; */ + /* s->do_cmd = cb_pcidda_ai_cmd; */ + /* s->do_cmdtest = cb_pcidda_ai_cmdtest; */ + + /* two 8255 digital io subdevices */ s = dev->subdevices + 1; subdev_8255_init(dev, s, NULL, devpriv->digitalio); s = dev->subdevices + 2; @@ -370,7 +380,7 @@ static int cb_pcidda_attach(struct comedi_device * dev, struct comedi_devconfig } printk("\n"); - // set calibrations dacs + /* set calibrations dacs */ for (index = 0; index < thisboard->ao_chans; index++) cb_pcidda_calibrate(dev, index, devpriv->ao_range[index]); @@ -385,7 +395,7 @@ static int cb_pcidda_attach(struct comedi_device * dev, struct comedi_devconfig * allocated by _attach(). dev->private and dev->subdevices are * deallocated automatically by the core. */ -static int cb_pcidda_detach(struct comedi_device * dev) +static int cb_pcidda_detach(struct comedi_device *dev) { /* * Deallocate the I/O ports. @@ -398,7 +408,7 @@ static int cb_pcidda_detach(struct comedi_device * dev) pci_dev_put(devpriv->pci_dev); } } - // cleanup 8255 + /* cleanup 8255 */ if (dev->subdevices) { subdev_8255_cleanup(dev, dev->subdevices + 1); subdev_8255_cleanup(dev, dev->subdevices + 2); @@ -413,7 +423,7 @@ static int cb_pcidda_detach(struct comedi_device * dev) * I will program this later... ;-) */ #if 0 -static int cb_pcidda_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s) +static int cb_pcidda_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { printk("cb_pcidda_ai_cmd\n"); printk("subdev: %d\n", cmd->subdev); @@ -432,8 +442,8 @@ static int cb_pcidda_ai_cmd(struct comedi_device * dev, struct comedi_subdevice #endif #if 0 -static int cb_pcidda_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd) +static int cb_pcidda_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd) { int err = 0; int tmp; @@ -598,8 +608,8 @@ static int cb_pcidda_ns_to_timer(unsigned int *ns, int round) } #endif -static int cb_pcidda_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int cb_pcidda_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { unsigned int command; unsigned int channel, range; @@ -607,7 +617,7 @@ static int cb_pcidda_ao_winsn(struct comedi_device * dev, struct comedi_subdevic channel = CR_CHAN(insn->chanspec); range = CR_RANGE(insn->chanspec); - // adjust calibration dacs if range has changed + /* adjust calibration dacs if range has changed */ if (range != devpriv->ao_range[channel]) cb_pcidda_calibrate(dev, channel, range); @@ -647,15 +657,15 @@ static int cb_pcidda_ao_winsn(struct comedi_device * dev, struct comedi_subdevic return 1; } -// lowlevel read from eeprom -static unsigned int cb_pcidda_serial_in(struct comedi_device * dev) +/* lowlevel read from eeprom */ +static unsigned int cb_pcidda_serial_in(struct comedi_device *dev) { unsigned int value = 0; int i; - const int value_width = 16; // number of bits wide values are + const int value_width = 16; /* number of bits wide values are */ for (i = 1; i <= value_width; i++) { - // read bits most significant bit first + /* read bits most significant bit first */ if (inw_p(devpriv->dac + DACALIBRATION1) & SERIAL_OUT_BIT) { value |= 1 << (value_width - i); } @@ -664,14 +674,14 @@ static unsigned int cb_pcidda_serial_in(struct comedi_device * dev) return value; } -// lowlevel write to eeprom/dac -static void cb_pcidda_serial_out(struct comedi_device * dev, unsigned int value, +/* lowlevel write to eeprom/dac */ +static void cb_pcidda_serial_out(struct comedi_device *dev, unsigned int value, unsigned int num_bits) { int i; for (i = 1; i <= num_bits; i++) { - // send bits most significant bit first + /* send bits most significant bit first */ if (value & (1 << (num_bits - i))) devpriv->dac_cal1_bits |= SERIAL_IN_BIT; else @@ -680,136 +690,137 @@ static void cb_pcidda_serial_out(struct comedi_device * dev, unsigned int value, } } -// reads a 16 bit value from board's eeprom -static unsigned int cb_pcidda_read_eeprom(struct comedi_device * dev, +/* reads a 16 bit value from board's eeprom */ +static unsigned int cb_pcidda_read_eeprom(struct comedi_device *dev, unsigned int address) { unsigned int i; unsigned int cal2_bits; unsigned int value; - const int max_num_caldacs = 4; // one caldac for every two dac channels - const int read_instruction = 0x6; // bits to send to tell eeprom we want to read + const int max_num_caldacs = 4; /* one caldac for every two dac channels */ + const int read_instruction = 0x6; /* bits to send to tell eeprom we want to read */ const int instruction_length = 3; const int address_length = 8; - // send serial output stream to eeprom + /* send serial output stream to eeprom */ cal2_bits = SELECT_EEPROM_BIT | DESELECT_REF_DAC_BIT | DUMMY_BIT; - // deactivate caldacs (one caldac for every two channels) + /* deactivate caldacs (one caldac for every two channels) */ for (i = 0; i < max_num_caldacs; i++) { cal2_bits |= DESELECT_CALDAC_BIT(i); } outw_p(cal2_bits, devpriv->dac + DACALIBRATION2); - // tell eeprom we want to read + /* tell eeprom we want to read */ cb_pcidda_serial_out(dev, read_instruction, instruction_length); - // send address we want to read from + /* send address we want to read from */ cb_pcidda_serial_out(dev, address, address_length); value = cb_pcidda_serial_in(dev); - // deactivate eeprom + /* deactivate eeprom */ cal2_bits &= ~SELECT_EEPROM_BIT; outw_p(cal2_bits, devpriv->dac + DACALIBRATION2); return value; } -// writes to 8 bit calibration dacs -static void cb_pcidda_write_caldac(struct comedi_device * dev, unsigned int caldac, +/* writes to 8 bit calibration dacs */ +static void cb_pcidda_write_caldac(struct comedi_device *dev, unsigned int caldac, unsigned int channel, unsigned int value) { unsigned int cal2_bits; unsigned int i; - const int num_channel_bits = 3; // caldacs use 3 bit channel specification - const int num_caldac_bits = 8; // 8 bit calibration dacs - const int max_num_caldacs = 4; // one caldac for every two dac channels + const int num_channel_bits = 3; /* caldacs use 3 bit channel specification */ + const int num_caldac_bits = 8; /* 8 bit calibration dacs */ + const int max_num_caldacs = 4; /* one caldac for every two dac channels */ /* write 3 bit channel */ cb_pcidda_serial_out(dev, channel, num_channel_bits); - // write 8 bit caldac value + /* write 8 bit caldac value */ cb_pcidda_serial_out(dev, value, num_caldac_bits); - // latch stream into appropriate caldac - // deselect reference dac +/* +* latch stream into appropriate caldac deselect reference dac +*/ cal2_bits = DESELECT_REF_DAC_BIT | DUMMY_BIT; - // deactivate caldacs (one caldac for every two channels) + /* deactivate caldacs (one caldac for every two channels) */ for (i = 0; i < max_num_caldacs; i++) { cal2_bits |= DESELECT_CALDAC_BIT(i); } - // activate the caldac we want + /* activate the caldac we want */ cal2_bits &= ~DESELECT_CALDAC_BIT(caldac); outw_p(cal2_bits, devpriv->dac + DACALIBRATION2); - // deactivate caldac + /* deactivate caldac */ cal2_bits |= DESELECT_CALDAC_BIT(caldac); outw_p(cal2_bits, devpriv->dac + DACALIBRATION2); } -// returns caldac that calibrates given analog out channel +/* returns caldac that calibrates given analog out channel */ static unsigned int caldac_number(unsigned int channel) { return channel / 2; } -// returns caldac channel that provides fine gain for given ao channel +/* returns caldac channel that provides fine gain for given ao channel */ static unsigned int fine_gain_channel(unsigned int ao_channel) { return 4 * (ao_channel % 2); } -// returns caldac channel that provides coarse gain for given ao channel +/* returns caldac channel that provides coarse gain for given ao channel */ static unsigned int coarse_gain_channel(unsigned int ao_channel) { return 1 + 4 * (ao_channel % 2); } -// returns caldac channel that provides coarse offset for given ao channel +/* returns caldac channel that provides coarse offset for given ao channel */ static unsigned int coarse_offset_channel(unsigned int ao_channel) { return 2 + 4 * (ao_channel % 2); } -// returns caldac channel that provides fine offset for given ao channel +/* returns caldac channel that provides fine offset for given ao channel */ static unsigned int fine_offset_channel(unsigned int ao_channel) { return 3 + 4 * (ao_channel % 2); } -// returns eeprom address that provides offset for given ao channel and range +/* returns eeprom address that provides offset for given ao channel and range */ static unsigned int offset_eeprom_address(unsigned int ao_channel, unsigned int range) { return 0x7 + 2 * range + 12 * ao_channel; } -// returns eeprom address that provides gain calibration for given ao channel and range +/* returns eeprom address that provides gain calibration for given ao channel and range */ static unsigned int gain_eeprom_address(unsigned int ao_channel, unsigned int range) { return 0x8 + 2 * range + 12 * ao_channel; } -// returns upper byte of eeprom entry, which gives the coarse adjustment values +/* returns upper byte of eeprom entry, which gives the coarse adjustment values */ static unsigned int eeprom_coarse_byte(unsigned int word) { return (word >> 8) & 0xff; } -// returns lower byte of eeprom entry, which gives the fine adjustment values +/* returns lower byte of eeprom entry, which gives the fine adjustment values */ static unsigned int eeprom_fine_byte(unsigned int word) { return word & 0xff; } -// set caldacs to eeprom values for given channel and range -static void cb_pcidda_calibrate(struct comedi_device * dev, unsigned int channel, +/* set caldacs to eeprom values for given channel and range */ +static void cb_pcidda_calibrate(struct comedi_device *dev, unsigned int channel, unsigned int range) { unsigned int coarse_offset, fine_offset, coarse_gain, fine_gain; - // remember range so we can tell when we need to readjust calibration + /* remember range so we can tell when we need to readjust calibration */ devpriv->ao_range[channel] = range; - // get values from eeprom data + /* get values from eeprom data */ coarse_offset = eeprom_coarse_byte(devpriv-> eeprom_data[offset_eeprom_address(channel, range)]); @@ -823,7 +834,7 @@ static void cb_pcidda_calibrate(struct comedi_device * dev, unsigned int channel eeprom_fine_byte(devpriv-> eeprom_data[gain_eeprom_address(channel, range)]); - // set caldacs + /* set caldacs */ cb_pcidda_write_caldac(dev, caldac_number(channel), coarse_offset_channel(channel), coarse_offset); cb_pcidda_write_caldac(dev, caldac_number(channel), diff --git a/drivers/staging/comedi/drivers/cb_pcidio.c b/drivers/staging/comedi/drivers/cb_pcidio.c index 71a4b1482e36..dc701273167c 100644 --- a/drivers/staging/comedi/drivers/cb_pcidio.c +++ b/drivers/staging/comedi/drivers/cb_pcidio.c @@ -53,32 +53,32 @@ Passing a zero for an option is the same as leaving it unspecified. * Some drivers use arrays such as this, other do not. */ struct pcidio_board { - const char *name; // anme of the board - int n_8255; // number of 8255 chips on board + const char *name; /* anme of the board */ + int n_8255; /* number of 8255 chips on board */ - // indices of base address regions + /* indices of base address regions */ int pcicontroler_badrindex; int dioregs_badrindex; }; static const struct pcidio_board pcidio_boards[] = { { - name: "pci-dio24", - n_8255: 1, - pcicontroler_badrindex:1, - dioregs_badrindex:2, + .name = "pci-dio24", + .n_8255 = 1, + .pcicontroler_badrindex = 1, + .dioregs_badrindex = 2, }, { - name: "pci-dio24h", - n_8255: 1, - pcicontroler_badrindex:1, - dioregs_badrindex:2, + .name = "pci-dio24h", + .n_8255 = 1, + .pcicontroler_badrindex = 1, + .dioregs_badrindex = 2, }, { - name: "pci-dio48h", - n_8255: 2, - pcicontroler_badrindex:0, - dioregs_badrindex:1, + .name = "pci-dio48h", + .n_8255 = 2, + .pcicontroler_badrindex = 0, + .dioregs_badrindex = 1, }, }; @@ -104,7 +104,7 @@ MODULE_DEVICE_TABLE(pci, pcidio_pci_table); several hardware drivers keep similar information in this structure, feel free to suggest moving the variable to the struct comedi_device struct. */ struct pcidio_private { - int data; // curently unused + int data; /* curently unused */ /* would be useful for a PCI device */ struct pci_dev *pci_dev; @@ -112,7 +112,7 @@ struct pcidio_private { /* used for DO readback, curently unused */ unsigned int do_readback[4]; /* up to 4 unsigned int suffice to hold 96 bits for PCI-DIO96 */ - unsigned long dio_reg_base; // address of port A of the first 8255 chip on board + unsigned long dio_reg_base; /* address of port A of the first 8255 chip on board */ }; /* @@ -127,15 +127,17 @@ struct pcidio_private { * the board, and also about the kernel module that contains * the device code. */ -static int pcidio_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int pcidio_detach(struct comedi_device * dev); +static int pcidio_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int pcidio_detach(struct comedi_device *dev); static struct comedi_driver driver_cb_pcidio = { - driver_name:"cb_pcidio", - module:THIS_MODULE, - attach:pcidio_attach, - detach:pcidio_detach, + .driver_name = "cb_pcidio", + .module = THIS_MODULE, + .attach = pcidio_attach, + .detach = pcidio_detach, + /* It is not necessary to implement the following members if you are * writing a driver for a ISA PnP or PCI card */ + /* Most drivers will support multiple types of boards by * having an array of board structures. These were defined * in pcidio_boards[] above. Note that the element 'name' @@ -152,10 +154,15 @@ static struct comedi_driver driver_cb_pcidio = { * the type of board in software. ISA PnP, PCI, and PCMCIA * devices are such boards. */ -// The following fields should NOT be initialized if you are dealing with PCI devices -// board_name: pcidio_boards, -// offset: sizeof(struct pcidio_board), -// num_names: sizeof(pcidio_boards) / sizeof(struct pcidio_board), + +/* The following fields should NOT be initialized if you are dealing + * with PCI devices + * + * .board_name = pcidio_boards, + * .offset = sizeof(struct pcidio_board), + * .num_names = sizeof(pcidio_boards) / sizeof(structpcidio_board), + */ + }; /*------------------------------- FUNCTIONS -----------------------------------*/ @@ -166,7 +173,7 @@ static struct comedi_driver driver_cb_pcidio = { * in the driver structure, dev->board_ptr contains that * address. */ -static int pcidio_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int pcidio_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct pci_dev *pcidev = NULL; int index; @@ -192,19 +199,19 @@ static int pcidio_attach(struct comedi_device * dev, struct comedi_devconfig * i for (pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL); pcidev != NULL; pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pcidev)) { - // is it not a computer boards card? + /* is it not a computer boards card? */ if (pcidev->vendor != PCI_VENDOR_ID_CB) continue; - // loop through cards supported by this driver + /* loop through cards supported by this driver */ for (index = 0; - index < sizeof pcidio_boards / sizeof(struct pcidio_board); + index < ARRAY_SIZE(pcidio_boards); index++) { if (pcidio_pci_table[index].device != pcidev->device) continue; - // was a particular bus/slot requested? + /* was a particular bus/slot requested? */ if (it->options[0] || it->options[1]) { - // are we on the wrong bus/slot? + /* are we on the wrong bus/slot? */ if (pcidev->bus->number != it->options[0] || PCI_SLOT(pcidev->devfn) != it->options[1]) { @@ -267,7 +274,7 @@ static int pcidio_attach(struct comedi_device * dev, struct comedi_devconfig * i * allocated by _attach(). dev->private and dev->subdevices are * deallocated automatically by the core. */ -static int pcidio_detach(struct comedi_device * dev) +static int pcidio_detach(struct comedi_device *dev) { printk("comedi%d: cb_pcidio: remove\n", dev->minor); if (devpriv) { diff --git a/drivers/staging/comedi/drivers/cb_pcimdas.c b/drivers/staging/comedi/drivers/cb_pcimdas.c index af705fa092c0..57d250c73abc 100644 --- a/drivers/staging/comedi/drivers/cb_pcimdas.c +++ b/drivers/staging/comedi/drivers/cb_pcimdas.c @@ -43,29 +43,30 @@ See http://www.measurementcomputing.com/PDFManuals/pcim-das1602_16.pdf for more #include "../comedidev.h" #include +#include #include "comedi_pci.h" #include "plx9052.h" #include "8255.h" -//#define CBPCIMDAS_DEBUG +/* #define CBPCIMDAS_DEBUG */ #undef CBPCIMDAS_DEBUG /* Registers for the PCIM-DAS1602/16 */ -// sizes of io regions (bytes) -#define BADR0_SIZE 2 //?? +/* sizes of io regions (bytes) */ +#define BADR0_SIZE 2 /* ?? */ #define BADR1_SIZE 4 #define BADR2_SIZE 6 #define BADR3_SIZE 16 #define BADR4_SIZE 4 -//DAC Offsets +/* DAC Offsets */ #define ADC_TRIG 0 #define DAC0_OFFSET 2 #define DAC1_OFFSET 4 -//AI and Counter Constants +/* AI and Counter Constants */ #define MUX_LIMITS 0 #define MAIN_CONN_DIO 1 #define ADC_STAT 2 @@ -86,37 +87,37 @@ See http://www.measurementcomputing.com/PDFManuals/pcim-das1602_16.pdf for more struct cb_pcimdas_board { const char *name; unsigned short device_id; - int ai_se_chans; // Inputs in single-ended mode - int ai_diff_chans; // Inputs in differential mode - int ai_bits; // analog input resolution - int ai_speed; // fastest conversion period in ns - int ao_nchan; // number of analog out channels - int ao_bits; // analogue output resolution - int has_ao_fifo; // analog output has fifo - int ao_scan_speed; // analog output speed for 1602 series (for a scan, not conversion) - int fifo_size; // number of samples fifo can hold - int dio_bits; // number of dio bits - int has_dio; // has DIO + int ai_se_chans; /* Inputs in single-ended mode */ + int ai_diff_chans; /* Inputs in differential mode */ + int ai_bits; /* analog input resolution */ + int ai_speed; /* fastest conversion period in ns */ + int ao_nchan; /* number of analog out channels */ + int ao_bits; /* analogue output resolution */ + int has_ao_fifo; /* analog output has fifo */ + int ao_scan_speed; /* analog output speed for 1602 series (for a scan, not conversion) */ + int fifo_size; /* number of samples fifo can hold */ + int dio_bits; /* number of dio bits */ + int has_dio; /* has DIO */ const struct comedi_lrange *ranges; }; static const struct cb_pcimdas_board cb_pcimdas_boards[] = { { - name: "PCIM-DAS1602/16", - device_id:0x56, - ai_se_chans:16, - ai_diff_chans:8, - ai_bits: 16, - ai_speed:10000, //?? - ao_nchan:2, - ao_bits: 12, - has_ao_fifo:0, //?? - ao_scan_speed:10000, - //?? - fifo_size:1024, - dio_bits:24, - has_dio: 1, -// ranges: &cb_pcimdas_ranges, + .name = "PCIM-DAS1602/16", + .device_id = 0x56, + .ai_se_chans = 16, + .ai_diff_chans = 8, + .ai_bits = 16, + .ai_speed = 10000, /* ?? */ + .ao_nchan = 2, + .ao_bits = 12, + .has_ao_fifo = 0, /* ?? */ + .ao_scan_speed = 10000, + /* ?? */ + .fifo_size = 1024, + .dio_bits = 24, + .has_dio = 1, +/* .ranges = &cb_pcimdas_ranges, */ }, }; @@ -129,7 +130,7 @@ static DEFINE_PCI_DEVICE_TABLE(cb_pcimdas_pci_table) = { MODULE_DEVICE_TABLE(pci, cb_pcimdas_pci_table); -#define N_BOARDS 1 // Max number of boards supported +#define N_BOARDS 1 /* Max number of boards supported */ /* * Useful for shorthand access to the particular board structure @@ -142,10 +143,10 @@ MODULE_DEVICE_TABLE(pci, cb_pcimdas_pci_table); struct cb_pcimdas_private { int data; - // would be useful for a PCI device + /* would be useful for a PCI device */ struct pci_dev *pci_dev; - //base addresses + /* base addresses */ unsigned long BADR0; unsigned long BADR1; unsigned long BADR2; @@ -155,11 +156,11 @@ struct cb_pcimdas_private { /* Used for AO readback */ unsigned int ao_readback[2]; - // Used for DIO - unsigned short int port_a; // copy of BADR4+0 - unsigned short int port_b; // copy of BADR4+1 - unsigned short int port_c; // copy of BADR4+2 - unsigned short int dio_mode; // copy of BADR4+3 + /* Used for DIO */ + unsigned short int port_a; /* copy of BADR4+0 */ + unsigned short int port_b; /* copy of BADR4+1 */ + unsigned short int port_c; /* copy of BADR4+2 */ + unsigned short int dio_mode; /* copy of BADR4+3 */ }; @@ -175,21 +176,21 @@ struct cb_pcimdas_private { * the board, and also about the kernel module that contains * the device code. */ -static int cb_pcimdas_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int cb_pcimdas_detach(struct comedi_device * dev); +static int cb_pcimdas_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int cb_pcimdas_detach(struct comedi_device *dev); static struct comedi_driver driver_cb_pcimdas = { - driver_name:"cb_pcimdas", - module:THIS_MODULE, - attach:cb_pcimdas_attach, - detach:cb_pcimdas_detach, + .driver_name = "cb_pcimdas", + .module = THIS_MODULE, + .attach = cb_pcimdas_attach, + .detach = cb_pcimdas_detach, }; -static int cb_pcimdas_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int cb_pcimdas_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int cb_pcimdas_ao_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); +static int cb_pcimdas_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int cb_pcimdas_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int cb_pcimdas_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); /* * Attach is called by the Comedi core to configure the driver @@ -197,12 +198,12 @@ static int cb_pcimdas_ao_rinsn(struct comedi_device * dev, struct comedi_subdevi * in the driver structure, dev->board_ptr contains that * address. */ -static int cb_pcimdas_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int cb_pcimdas_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; struct pci_dev *pcidev; int index; - //int i; + /* int i; */ printk("comedi%d: cb_pcimdas: ", dev->minor); @@ -220,17 +221,17 @@ static int cb_pcimdas_attach(struct comedi_device * dev, struct comedi_devconfig for (pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL); pcidev != NULL; pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pcidev)) { - // is it not a computer boards card? + /* is it not a computer boards card? */ if (pcidev->vendor != PCI_VENDOR_ID_COMPUTERBOARDS) continue; - // loop through cards supported by this driver + /* loop through cards supported by this driver */ for (index = 0; index < N_BOARDS; index++) { if (cb_pcimdas_boards[index].device_id != pcidev->device) continue; - // was a particular bus/slot requested? + /* was a particular bus/slot requested? */ if (it->options[0] || it->options[1]) { - // are we on the wrong bus/slot? + /* are we on the wrong bus/slot? */ if (pcidev->bus->number != it->options[0] || PCI_SLOT(pcidev->devfn) != it->options[1]) { @@ -252,7 +253,7 @@ static int cb_pcimdas_attach(struct comedi_device * dev, struct comedi_devconfig printk("Found %s on bus %i, slot %i\n", cb_pcimdas_boards[index].name, pcidev->bus->number, PCI_SLOT(pcidev->devfn)); - // Warn about non-tested features + /* Warn about non-tested features */ switch (thisboard->device_id) { case 0x56: break; @@ -280,16 +281,16 @@ static int cb_pcimdas_attach(struct comedi_device * dev, struct comedi_devconfig printk("devpriv->BADR4 = 0x%lx\n", devpriv->BADR4); #endif -// Dont support IRQ yet -// // get irq -// if(comedi_request_irq(devpriv->pci_dev->irq, cb_pcimdas_interrupt, IRQF_SHARED, "cb_pcimdas", dev )) -// { -// printk(" unable to allocate irq %u\n", devpriv->pci_dev->irq); -// return -EINVAL; -// } -// dev->irq = devpriv->pci_dev->irq; +/* Dont support IRQ yet */ +/* get irq */ +/* if(request_irq(devpriv->pci_dev->irq, cb_pcimdas_interrupt, IRQF_SHARED, "cb_pcimdas", dev )) */ +/* { */ +/* printk(" unable to allocate irq %u\n", devpriv->pci_dev->irq); */ +/* return -EINVAL; */ +/* } */ +/* dev->irq = devpriv->pci_dev->irq; */ - //Initialize dev->board_name + /* Initialize dev->board_name */ dev->board_name = thisboard->name; /* @@ -300,24 +301,24 @@ static int cb_pcimdas_attach(struct comedi_device * dev, struct comedi_devconfig return -ENOMEM; s = dev->subdevices + 0; - //dev->read_subdev=s; - // analog input subdevice + /* dev->read_subdev=s; */ + /* analog input subdevice */ s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE | SDF_GROUND; s->n_chan = thisboard->ai_se_chans; s->maxdata = (1 << thisboard->ai_bits) - 1; s->range_table = &range_unknown; - s->len_chanlist = 1; // This is the maximum chanlist length that - // the board can handle + s->len_chanlist = 1; /* This is the maximum chanlist length that */ + /* the board can handle */ s->insn_read = cb_pcimdas_ai_rinsn; s = dev->subdevices + 1; - // analog output subdevice + /* analog output subdevice */ s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE; s->n_chan = thisboard->ao_nchan; s->maxdata = 1 << thisboard->ao_bits; - s->range_table = &range_unknown; //ranges are hardware settable, but not software readable. + s->range_table = &range_unknown; /* ranges are hardware settable, but not software readable. */ s->insn_write = &cb_pcimdas_ao_winsn; s->insn_read = &cb_pcimdas_ao_rinsn; @@ -342,7 +343,7 @@ static int cb_pcimdas_attach(struct comedi_device * dev, struct comedi_devconfig * allocated by _attach(). dev->private and dev->subdevices are * deallocated automatically by the core. */ -static int cb_pcimdas_detach(struct comedi_device * dev) +static int cb_pcimdas_detach(struct comedi_device *dev) { #ifdef CBPCIMDAS_DEBUG if (devpriv) { @@ -355,7 +356,7 @@ static int cb_pcimdas_detach(struct comedi_device * dev) #endif printk("comedi%d: cb_pcimdas: remove\n", dev->minor); if (dev->irq) - comedi_free_irq(dev->irq, dev); + free_irq(dev->irq, dev); if (devpriv) { if (devpriv->pci_dev) { if (devpriv->BADR0) { @@ -372,8 +373,8 @@ static int cb_pcimdas_detach(struct comedi_device * dev) * "instructions" read/write data in "one-shot" or "software-triggered" * mode. */ -static int cb_pcimdas_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int cb_pcimdas_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int n, i; unsigned int d; @@ -382,27 +383,27 @@ static int cb_pcimdas_ai_rinsn(struct comedi_device * dev, struct comedi_subdevi unsigned short chanlims; int maxchans; - // only support sw initiated reads from a single channel + /* only support sw initiated reads from a single channel */ - //check channel number - if ((inb(devpriv->BADR3 + 2) & 0x20) == 0) //differential mode + /* check channel number */ + if ((inb(devpriv->BADR3 + 2) & 0x20) == 0) /* differential mode */ maxchans = thisboard->ai_diff_chans; else maxchans = thisboard->ai_se_chans; if (chan > (maxchans - 1)) - return -ETIMEDOUT; //*** Wrong error code. Fixme. + return -ETIMEDOUT; /* *** Wrong error code. Fixme. */ - //configure for sw initiated read + /* configure for sw initiated read */ d = inb(devpriv->BADR3 + 5); - if ((d & 0x03) > 0) { //only reset if needed. + if ((d & 0x03) > 0) { /* only reset if needed. */ d = d & 0xfd; outb(d, devpriv->BADR3 + 5); } - outb(0x01, devpriv->BADR3 + 6); //set bursting off, conversions on - outb(0x00, devpriv->BADR3 + 7); //set range to 10V. UP/BP is controlled by a switch on the board + outb(0x01, devpriv->BADR3 + 6); /* set bursting off, conversions on */ + outb(0x00, devpriv->BADR3 + 7); /* set range to 10V. UP/BP is controlled by a switch on the board */ - // write channel limits to multiplexer, set Low (bits 0-3) and High (bits 4-7) channels to chan. + /* write channel limits to multiplexer, set Low (bits 0-3) and High (bits 4-7) channels to chan. */ chanlims = chan | (chan << 4); outb(chanlims, devpriv->BADR3 + 0); @@ -411,8 +412,8 @@ static int cb_pcimdas_ai_rinsn(struct comedi_device * dev, struct comedi_subdevi /* trigger conversion */ outw(0, devpriv->BADR2 + 0); -#define TIMEOUT 1000 //typically takes 5 loops on a lightly loaded Pentium 100MHz, - //this is likely to be 100 loops on a 2GHz machine, so set 1000 as the limit. +#define TIMEOUT 1000 /* typically takes 5 loops on a lightly loaded Pentium 100MHz, */ + /* this is likely to be 100 loops on a 2GHz machine, so set 1000 as the limit. */ /* wait for conversion to end */ for (i = 0; i < TIMEOUT; i++) { @@ -428,7 +429,7 @@ static int cb_pcimdas_ai_rinsn(struct comedi_device * dev, struct comedi_subdevi d = inw(devpriv->BADR2 + 0); /* mangle the data as necessary */ - //d ^= 1<<(thisboard->ai_bits-1); // 16 bit data from ADC, so no mangle needed. + /* d ^= 1<<(thisboard->ai_bits-1); // 16 bit data from ADC, so no mangle needed. */ data[n] = d; } @@ -437,8 +438,8 @@ static int cb_pcimdas_ai_rinsn(struct comedi_device * dev, struct comedi_subdevi return n; } -static int cb_pcimdas_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int cb_pcimdas_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i; int chan = CR_CHAN(insn->chanspec); @@ -465,8 +466,8 @@ static int cb_pcimdas_ao_winsn(struct comedi_device * dev, struct comedi_subdevi /* AO subdevices should have a read insn as well as a write insn. * Usually this means copying a value stored in devpriv. */ -static int cb_pcimdas_ao_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int cb_pcimdas_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i; int chan = CR_CHAN(insn->chanspec); diff --git a/drivers/staging/comedi/drivers/cb_pcimdda.c b/drivers/staging/comedi/drivers/cb_pcimdda.c index e4c5b460fbd5..57bb1182480d 100644 --- a/drivers/staging/comedi/drivers/cb_pcimdda.c +++ b/drivers/staging/comedi/drivers/cb_pcimdda.c @@ -118,15 +118,15 @@ enum DIO_METHODS { static const struct board_struct boards[] = { { - name: "cb_pcimdda06-16", - device_id:PCI_ID_PCIM_DDA06_16, - ao_chans:6, - ao_bits: 16, - dio_chans:24, - dio_method:DIO_8255, - dio_offset:12, - regs_badrindex:3, - reg_sz: 16, + .name = "cb_pcimdda06-16", + .device_id = PCI_ID_PCIM_DDA06_16, + .ao_chans = 6, + .ao_bits = 16, + .dio_chans = 24, + .dio_method = DIO_8255, + .dio_offset = 12, + .regs_badrindex = 3, + .reg_sz = 16, } }; @@ -135,8 +135,6 @@ static const struct board_struct boards[] = { */ #define thisboard ((const struct board_struct *)dev->board_ptr) -/* Number of boards in boards[] */ -#define N_BOARDS (sizeof(boards) / sizeof(struct board_struct)) #define REG_SZ (thisboard->reg_sz) #define REGS_BADRINDEX (thisboard->regs_badrindex) @@ -181,13 +179,13 @@ struct board_private_struct { * the board, and also about the kernel module that contains * the device code. */ -static int attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int detach(struct comedi_device * dev); +static int attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int detach(struct comedi_device *dev); static struct comedi_driver cb_pcimdda_driver = { - driver_name:"cb_pcimdda", - module:THIS_MODULE, - attach:attach, - detach:detach, + .driver_name = "cb_pcimdda", + .module = THIS_MODULE, + .attach = attach, + .detach = detach, }; MODULE_AUTHOR("Calin A. Culianu "); @@ -197,10 +195,10 @@ MODULE_DESCRIPTION("Comedi low-level driver for the Computerboards PCIM-DDA " MODULE_LICENSE("GPL"); COMEDI_PCI_INITCLEANUP_NOMODULE(cb_pcimdda_driver, pci_table); -static int ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int ao_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); +static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); /*--------------------------------------------------------------------------- HELPER FUNCTION DECLARATIONS @@ -209,7 +207,7 @@ static int ao_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, /* returns a maxdata value for a given n_bits */ static inline unsigned int figure_out_maxdata(int bits) { - return (((unsigned int) 1 << bits) - 1); + return ((unsigned int) 1 << bits) - 1; } /* @@ -226,7 +224,7 @@ static inline unsigned int figure_out_maxdata(int bits) * * Otherwise, returns a -errno on error */ -static int probe(struct comedi_device * dev, const struct comedi_devconfig * it); +static int probe(struct comedi_device *dev, const struct comedi_devconfig *it); /*--------------------------------------------------------------------------- FUNCTION DEFINITIONS @@ -238,7 +236,7 @@ static int probe(struct comedi_device * dev, const struct comedi_devconfig * it) * in the driver structure, dev->board_ptr contains that * address. */ -static int attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; int err; @@ -257,7 +255,8 @@ static int attach(struct comedi_device * dev, struct comedi_devconfig * it) * it is, this is the place to do it. Otherwise, dev->board_ptr * should already be initialized. */ - if ((err = probe(dev, it))) + err = probe(dev, it); + if (err) return err; /* Output some info */ @@ -326,7 +325,7 @@ static int attach(struct comedi_device * dev, struct comedi_devconfig * it) * allocated by _attach(). dev->private and dev->subdevices are * deallocated automatically by the core. */ -static int detach(struct comedi_device * dev) +static int detach(struct comedi_device *dev) { if (devpriv) { @@ -352,8 +351,8 @@ static int detach(struct comedi_device * dev) return 0; } -static int ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i; int chan = CR_CHAN(insn->chanspec); @@ -391,8 +390,8 @@ static int ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s, all AO channels update simultaneously. This is useful for some control applications, I would imagine. */ -static int ao_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i; int chan = CR_CHAN(insn->chanspec); @@ -425,7 +424,7 @@ static int ao_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, * * Otherwise, returns a -errno on error */ -static int probe(struct comedi_device * dev, const struct comedi_devconfig * it) +static int probe(struct comedi_device *dev, const struct comedi_devconfig *it) { struct pci_dev *pcidev; int index; @@ -434,16 +433,16 @@ static int probe(struct comedi_device * dev, const struct comedi_devconfig * it) for (pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL); pcidev != NULL; pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pcidev)) { - // is it not a computer boards card? + /* is it not a computer boards card? */ if (pcidev->vendor != PCI_VENDOR_ID_COMPUTERBOARDS) continue; - // loop through cards supported by this driver - for (index = 0; index < N_BOARDS; index++) { + /* loop through cards supported by this driver */ + for (index = 0; index < ARRAY_SIZE(boards); index++) { if (boards[index].device_id != pcidev->device) continue; - // was a particular bus/slot requested? + /* was a particular bus/slot requested? */ if (it->options[0] || it->options[1]) { - // are we on the wrong bus/slot? + /* are we on the wrong bus/slot? */ if (pcidev->bus->number != it->options[0] || PCI_SLOT(pcidev->devfn) != it->options[1]) { diff --git a/drivers/staging/comedi/drivers/comedi_bond.c b/drivers/staging/comedi/drivers/comedi_bond.c index 1ee489864d3b..45cd41f7fd29 100644 --- a/drivers/staging/comedi/drivers/comedi_bond.c +++ b/drivers/staging/comedi/drivers/comedi_bond.c @@ -210,7 +210,7 @@ static struct comedi_driver driver_bonding = { */ .board_name = &bondingBoards[0].name, .offset = sizeof(struct BondingBoard), - .num_names = sizeof(bondingBoards) / sizeof(struct BondingBoard), + .num_names = ARRAY_SIZE(bondingBoards), }; static int bonding_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, diff --git a/drivers/staging/comedi/drivers/comedi_fc.c b/drivers/staging/comedi/drivers/comedi_fc.c index 9fa4cdc84d44..8ab8e733afb6 100644 --- a/drivers/staging/comedi/drivers/comedi_fc.c +++ b/drivers/staging/comedi/drivers/comedi_fc.c @@ -53,7 +53,7 @@ unsigned int cfc_write_array_to_buffer(struct comedi_subdevice *subd, void *data retval = comedi_buf_write_alloc(async, num_bytes); if (retval != num_bytes) { - rt_printk("comedi: buffer overrun\n"); + printk("comedi: buffer overrun\n"); async->events |= COMEDI_CB_OVERFLOW; return 0; } diff --git a/drivers/staging/comedi/drivers/comedi_parport.c b/drivers/staging/comedi/drivers/comedi_parport.c index a23339155ffc..f42897de640e 100644 --- a/drivers/staging/comedi/drivers/comedi_parport.c +++ b/drivers/staging/comedi/drivers/comedi_parport.c @@ -82,6 +82,7 @@ pin, which can be used to wake up tasks. */ #include "../comedidev.h" +#include #include #define PARPORT_SIZE 3 @@ -274,7 +275,7 @@ static int parport_intr_cancel(struct comedi_device *dev, struct comedi_subdevic return 0; } -static irqreturn_t parport_interrupt(int irq, void *d PT_REGS_ARG) +static irqreturn_t parport_interrupt(int irq, void *d) { struct comedi_device *dev = d; struct comedi_subdevice *s = dev->subdevices + 3; @@ -309,8 +310,8 @@ static int parport_attach(struct comedi_device *dev, struct comedi_devconfig *it irq = it->options[1]; if (irq) { printk(" irq=%u", irq); - ret = comedi_request_irq(irq, parport_interrupt, 0, - "comedi_parport", dev); + ret = request_irq(irq, parport_interrupt, 0, "comedi_parport", + dev); if (ret < 0) { printk(" irq not available\n"); return -EINVAL; @@ -384,7 +385,7 @@ static int parport_detach(struct comedi_device *dev) release_region(dev->iobase, PARPORT_SIZE); if (dev->irq) - comedi_free_irq(dev->irq, dev); + free_irq(dev->irq, dev); return 0; } diff --git a/drivers/staging/comedi/drivers/comedi_rt_timer.c b/drivers/staging/comedi/drivers/comedi_rt_timer.c deleted file mode 100644 index f40c8cffd4bb..000000000000 --- a/drivers/staging/comedi/drivers/comedi_rt_timer.c +++ /dev/null @@ -1,728 +0,0 @@ -/* - comedi/drivers/comedi_rt_timer.c - virtual driver for using RTL timing sources - - Authors: David A. Schleef, Frank M. Hess - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 1999,2001 David A. Schleef - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -************************************************************************** -*/ -/* -Driver: comedi_rt_timer -Description: Command emulator using real-time tasks -Author: ds, fmhess -Devices: -Status: works - -This driver requires RTAI or RTLinux to work correctly. It doesn't -actually drive hardware directly, but calls other drivers and uses -a real-time task to emulate commands for drivers and devices that -are incapable of native commands. Thus, you can get accurately -timed I/O on any device. - -Since the timing is all done in software, sampling jitter is much -higher than with a device that has an on-board timer, and maximum -sample rate is much lower. - -Configuration options: - [0] - minor number of device you wish to emulate commands for - [1] - subdevice number you wish to emulate commands for -*/ -/* -TODO: - Support for digital io commands could be added, except I can't see why - anyone would want to use them - What happens if device we are emulating for is de-configured? -*/ - -#include "../comedidev.h" -#include "../comedilib.h" - -#include "comedi_fc.h" - -#ifdef CONFIG_COMEDI_RTL_V1 -#include -#include -#endif -#ifdef CONFIG_COMEDI_RTL -#include -#include -#include -#include - -#ifndef RTLINUX_VERSION_CODE -#define RTLINUX_VERSION_CODE 0 -#endif -#ifndef RTLINUX_VERSION -#define RTLINUX_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) -#endif - -// begin hack to workaround broken HRT_TO_8254() function on rtlinux -#if RTLINUX_VERSION_CODE <= RTLINUX_VERSION(3,0,100) -// this function sole purpose is to divide a long long by 838 -static inline RTIME nano2count(long long ns) -{ - do_div(ns, 838); - return ns; -} - -#ifdef rt_get_time() -#undef rt_get_time() -#endif -#define rt_get_time() nano2count(gethrtime()) - -#else - -#define nano2count(x) HRT_TO_8254(x) -#endif -// end hack - -// rtl-rtai compatibility -#define rt_task_wait_period() rt_task_wait() -#define rt_pend_linux_srq(irq) rtl_global_pend_irq(irq) -#define rt_free_srq(irq) rtl_free_soft_irq(irq) -#define rt_request_srq(x,y,z) rtl_get_soft_irq(y,"timer") -#define rt_task_init(a,b,c,d,e,f,g) rt_task_init(a,b,c,d,(e)+1) -#define rt_task_resume(x) rt_task_wakeup(x) -#define rt_set_oneshot_mode() -#define start_rt_timer(x) -#define stop_rt_timer() - -#endif -#ifdef CONFIG_COMEDI_RTAI -#include -#include - -#if RTAI_VERSION_CODE < RTAI_MANGLE_VERSION(3,3,0) -#define comedi_rt_task_context_t int -#else -#define comedi_rt_task_context_t long -#endif - -#endif - -/* This defines the fastest speed we will emulate. Note that - * without a watchdog (like in RTAI), we could easily overrun our - * task period because analog input tends to be slow. */ -#define SPEED_LIMIT 100000 /* in nanoseconds */ - -static int timer_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int timer_detach(struct comedi_device * dev); -static int timer_inttrig(struct comedi_device * dev, struct comedi_subdevice * s, - unsigned int trig_num); -static int timer_start_cmd(struct comedi_device * dev, struct comedi_subdevice * s); - -static struct comedi_driver driver_timer = { - module:THIS_MODULE, - driver_name:"comedi_rt_timer", - attach:timer_attach, - detach:timer_detach, -// open: timer_open, -}; - -COMEDI_INITCLEANUP(driver_timer); - -struct timer_private { - comedi_t *device; // device we are emulating commands for - int subd; // subdevice we are emulating commands for - RT_TASK *rt_task; // rt task that starts scans - RT_TASK *scan_task; // rt task that controls conversion timing in a scan - /* io_function can point to either an input or output function - * depending on what kind of subdevice we are emulating for */ - int (*io_function) (struct comedi_device * dev, struct comedi_cmd * cmd, - unsigned int index); - // RTIME has units of 1 = 838 nanoseconds - // time at which first scan started, used to check scan timing - RTIME start; - // time between scans - RTIME scan_period; - // time between conversions in a scan - RTIME convert_period; - // flags - volatile int stop; // indicates we should stop - volatile int rt_task_active; // indicates rt_task is servicing a struct comedi_cmd - volatile int scan_task_active; // indicates scan_task is servicing a struct comedi_cmd - unsigned timer_running:1; -}; -#define devpriv ((struct timer_private *)dev->private) - -static int timer_cancel(struct comedi_device * dev, struct comedi_subdevice * s) -{ - devpriv->stop = 1; - - return 0; -} - -// checks for scan timing error -inline static int check_scan_timing(struct comedi_device * dev, - unsigned long long scan) -{ - RTIME now, timing_error; - - now = rt_get_time(); - timing_error = now - (devpriv->start + scan * devpriv->scan_period); - if (timing_error > devpriv->scan_period) { - comedi_error(dev, "timing error"); - rt_printk("scan started %i ns late\n", timing_error * 838); - return -1; - } - - return 0; -} - -// checks for conversion timing error -inline static int check_conversion_timing(struct comedi_device * dev, - RTIME scan_start, unsigned int conversion) -{ - RTIME now, timing_error; - - now = rt_get_time(); - timing_error = - now - (scan_start + conversion * devpriv->convert_period); - if (timing_error > devpriv->convert_period) { - comedi_error(dev, "timing error"); - rt_printk("conversion started %i ns late\n", - timing_error * 838); - return -1; - } - - return 0; -} - -// devpriv->io_function for an input subdevice -static int timer_data_read(struct comedi_device * dev, struct comedi_cmd * cmd, - unsigned int index) -{ - struct comedi_subdevice *s = dev->read_subdev; - int ret; - unsigned int data; - - ret = comedi_data_read(devpriv->device, devpriv->subd, - CR_CHAN(cmd->chanlist[index]), - CR_RANGE(cmd->chanlist[index]), - CR_AREF(cmd->chanlist[index]), &data); - if (ret < 0) { - comedi_error(dev, "read error"); - return -EIO; - } - if (s->flags & SDF_LSAMPL) { - cfc_write_long_to_buffer(s, data); - } else { - comedi_buf_put(s->async, data); - } - - return 0; -} - -// devpriv->io_function for an output subdevice -static int timer_data_write(struct comedi_device * dev, struct comedi_cmd * cmd, - unsigned int index) -{ - struct comedi_subdevice *s = dev->write_subdev; - unsigned int num_bytes; - short data; - unsigned int long_data; - int ret; - - if (s->flags & SDF_LSAMPL) { - num_bytes = - cfc_read_array_from_buffer(s, &long_data, - sizeof(long_data)); - } else { - num_bytes = cfc_read_array_from_buffer(s, &data, sizeof(data)); - long_data = data; - } - - if (num_bytes == 0) { - comedi_error(dev, "buffer underrun"); - return -EAGAIN; - } - ret = comedi_data_write(devpriv->device, devpriv->subd, - CR_CHAN(cmd->chanlist[index]), - CR_RANGE(cmd->chanlist[index]), - CR_AREF(cmd->chanlist[index]), long_data); - if (ret < 0) { - comedi_error(dev, "write error"); - return -EIO; - } - - return 0; -} - -// devpriv->io_function for DIO subdevices -static int timer_dio_read(struct comedi_device * dev, struct comedi_cmd * cmd, - unsigned int index) -{ - struct comedi_subdevice *s = dev->read_subdev; - int ret; - unsigned int data; - - ret = comedi_dio_bitfield(devpriv->device, devpriv->subd, 0, &data); - if (ret < 0) { - comedi_error(dev, "read error"); - return -EIO; - } - - if (s->flags & SDF_LSAMPL) - cfc_write_long_to_buffer(s, data); - else - cfc_write_to_buffer(s, data); - - return 0; -} - -// performs scans -static void scan_task_func(comedi_rt_task_context_t d) -{ - struct comedi_device *dev = (struct comedi_device *) d; - struct comedi_subdevice *s = dev->subdevices + 0; - struct comedi_async *async = s->async; - struct comedi_cmd *cmd = &async->cmd; - int i, ret; - unsigned long long n; - RTIME scan_start; - - // every struct comedi_cmd causes one execution of while loop - while (1) { - devpriv->scan_task_active = 1; - // each for loop completes one scan - for (n = 0; n < cmd->stop_arg || cmd->stop_src == TRIG_NONE; - n++) { - if (n) { - // suspend task until next scan - ret = rt_task_suspend(devpriv->scan_task); - if (ret < 0) { - comedi_error(dev, - "error suspending scan task"); - async->events |= COMEDI_CB_ERROR; - goto cleanup; - } - } - // check if stop flag was set (by timer_cancel()) - if (devpriv->stop) - goto cleanup; - ret = check_scan_timing(dev, n); - if (ret < 0) { - async->events |= COMEDI_CB_ERROR; - goto cleanup; - } - scan_start = rt_get_time(); - for (i = 0; i < cmd->scan_end_arg; i++) { - // conversion timing - if (cmd->convert_src == TRIG_TIMER && i) { - rt_task_wait_period(); - ret = check_conversion_timing(dev, - scan_start, i); - if (ret < 0) { - async->events |= - COMEDI_CB_ERROR; - goto cleanup; - } - } - ret = devpriv->io_function(dev, cmd, i); - if (ret < 0) { - async->events |= COMEDI_CB_ERROR; - goto cleanup; - } - } - s->async->events |= COMEDI_CB_BLOCK; - comedi_event(dev, s); - s->async->events = 0; - } - - cleanup: - - comedi_unlock(devpriv->device, devpriv->subd); - async->events |= COMEDI_CB_EOA; - comedi_event(dev, s); - async->events = 0; - devpriv->scan_task_active = 0; - // suspend task until next struct comedi_cmd - rt_task_suspend(devpriv->scan_task); - } -} - -static void timer_task_func(comedi_rt_task_context_t d) -{ - struct comedi_device *dev = (struct comedi_device *) d; - struct comedi_subdevice *s = dev->subdevices + 0; - struct comedi_cmd *cmd = &s->async->cmd; - int ret; - unsigned long long n; - - // every struct comedi_cmd causes one execution of while loop - while (1) { - devpriv->rt_task_active = 1; - devpriv->scan_task_active = 1; - devpriv->start = rt_get_time(); - - for (n = 0; n < cmd->stop_arg || cmd->stop_src == TRIG_NONE; - n++) { - // scan timing - if (n) - rt_task_wait_period(); - if (devpriv->scan_task_active == 0) { - goto cleanup; - } - ret = rt_task_make_periodic(devpriv->scan_task, - devpriv->start + devpriv->scan_period * n, - devpriv->convert_period); - if (ret < 0) { - comedi_error(dev, "bug!"); - } - } - - cleanup: - - devpriv->rt_task_active = 0; - // suspend until next struct comedi_cmd - rt_task_suspend(devpriv->rt_task); - } -} - -static int timer_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) -{ - struct comedi_insn xinsn = *insn; - - xinsn.data = data; - xinsn.subdev = devpriv->subd; - - return comedi_do_insn(devpriv->device, &xinsn); -} - -static int cmdtest_helper(struct comedi_cmd * cmd, - unsigned int start_src, - unsigned int scan_begin_src, - unsigned int convert_src, - unsigned int scan_end_src, unsigned int stop_src) -{ - int err = 0; - int tmp; - - tmp = cmd->start_src; - cmd->start_src &= start_src; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= scan_begin_src; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= convert_src; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= scan_end_src; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= stop_src; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; - - return err; -} - -static int timer_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd) -{ - int err = 0; - unsigned int start_src = 0; - - if (s->type == COMEDI_SUBD_AO) - start_src = TRIG_INT; - else - start_src = TRIG_NOW; - - err = cmdtest_helper(cmd, start_src, /* start_src */ - TRIG_TIMER | TRIG_FOLLOW, /* scan_begin_src */ - TRIG_NOW | TRIG_TIMER, /* convert_src */ - TRIG_COUNT, /* scan_end_src */ - TRIG_COUNT | TRIG_NONE); /* stop_src */ - if (err) - return 1; - - /* step 2: make sure trigger sources are unique and mutually - * compatible */ - - if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_INT) - err++; - if (cmd->scan_begin_src != TRIG_TIMER && - cmd->scan_begin_src != TRIG_FOLLOW) - err++; - if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_NOW) - err++; - if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) - err++; - if (cmd->scan_begin_src == TRIG_FOLLOW - && cmd->convert_src != TRIG_TIMER) - err++; - if (cmd->convert_src == TRIG_NOW && cmd->scan_begin_src != TRIG_TIMER) - err++; - - if (err) - return 2; - - /* step 3: make sure arguments are trivially compatible */ - // limit frequency, this is fairly arbitrary - if (cmd->scan_begin_src == TRIG_TIMER) { - if (cmd->scan_begin_arg < SPEED_LIMIT) { - cmd->scan_begin_arg = SPEED_LIMIT; - err++; - } - } - if (cmd->convert_src == TRIG_TIMER) { - if (cmd->convert_arg < SPEED_LIMIT) { - cmd->convert_arg = SPEED_LIMIT; - err++; - } - } - // make sure conversion and scan frequencies are compatible - if (cmd->convert_src == TRIG_TIMER && cmd->scan_begin_src == TRIG_TIMER) { - if (cmd->convert_arg * cmd->scan_end_arg > cmd->scan_begin_arg) { - cmd->scan_begin_arg = - cmd->convert_arg * cmd->scan_end_arg; - err++; - } - } - if (err) - return 3; - - /* step 4: fix up and arguments */ - if (err) - return 4; - - return 0; -} - -static int timer_cmd(struct comedi_device * dev, struct comedi_subdevice * s) -{ - int ret; - struct comedi_cmd *cmd = &s->async->cmd; - - /* hack attack: drivers are not supposed to do this: */ - dev->rt = 1; - - // make sure tasks have finished cleanup of last struct comedi_cmd - if (devpriv->rt_task_active || devpriv->scan_task_active) - return -EBUSY; - - ret = comedi_lock(devpriv->device, devpriv->subd); - if (ret < 0) { - comedi_error(dev, "failed to obtain lock"); - return ret; - } - switch (cmd->scan_begin_src) { - case TRIG_TIMER: - devpriv->scan_period = nano2count(cmd->scan_begin_arg); - break; - case TRIG_FOLLOW: - devpriv->scan_period = - nano2count(cmd->convert_arg * cmd->scan_end_arg); - break; - default: - comedi_error(dev, "bug setting scan period!"); - return -1; - break; - } - switch (cmd->convert_src) { - case TRIG_TIMER: - devpriv->convert_period = nano2count(cmd->convert_arg); - break; - case TRIG_NOW: - devpriv->convert_period = 1; - break; - default: - comedi_error(dev, "bug setting conversion period!"); - return -1; - break; - } - - if (cmd->start_src == TRIG_NOW) - return timer_start_cmd(dev, s); - - s->async->inttrig = timer_inttrig; - - return 0; -} - -static int timer_inttrig(struct comedi_device * dev, struct comedi_subdevice * s, - unsigned int trig_num) -{ - if (trig_num != 0) - return -EINVAL; - - s->async->inttrig = NULL; - - return timer_start_cmd(dev, s); -} - -static int timer_start_cmd(struct comedi_device * dev, struct comedi_subdevice * s) -{ - struct comedi_async *async = s->async; - struct comedi_cmd *cmd = &async->cmd; - RTIME now, delay, period; - int ret; - - devpriv->stop = 0; - s->async->events = 0; - - if (cmd->start_src == TRIG_NOW) - delay = nano2count(cmd->start_arg); - else - delay = 0; - - now = rt_get_time(); - /* Using 'period' this way gets around some weird bug in gcc-2.95.2 - * that generates the compile error 'internal error--unrecognizable insn' - * when rt_task_make_period() is called (observed with rtlinux-3.1, linux-2.2.19). - * - fmhess */ - period = devpriv->scan_period; - ret = rt_task_make_periodic(devpriv->rt_task, now + delay, period); - if (ret < 0) { - comedi_error(dev, "error starting rt_task"); - return ret; - } - return 0; -} - -static int timer_attach(struct comedi_device * dev, struct comedi_devconfig * it) -{ - int ret; - struct comedi_subdevice *s, *emul_s; - struct comedi_device *emul_dev; - /* These should probably be devconfig options[] */ - const int timer_priority = 4; - const int scan_priority = timer_priority + 1; - char path[20]; - - printk("comedi%d: timer: ", dev->minor); - - dev->board_name = "timer"; - - if ((ret = alloc_subdevices(dev, 1)) < 0) - return ret; - if ((ret = alloc_private(dev, sizeof(struct timer_private))) < 0) - return ret; - - sprintf(path, "/dev/comedi%d", it->options[0]); - devpriv->device = comedi_open(path); - devpriv->subd = it->options[1]; - - printk("emulating commands for minor %i, subdevice %d\n", - it->options[0], devpriv->subd); - - emul_dev = devpriv->device; - emul_s = emul_dev->subdevices + devpriv->subd; - - // input or output subdevice - s = dev->subdevices + 0; - s->type = emul_s->type; - s->subdev_flags = emul_s->subdev_flags; /* SDF_GROUND (to fool check_driver) */ - s->n_chan = emul_s->n_chan; - s->len_chanlist = 1024; - s->do_cmd = timer_cmd; - s->do_cmdtest = timer_cmdtest; - s->cancel = timer_cancel; - s->maxdata = emul_s->maxdata; - s->range_table = emul_s->range_table; - s->range_table_list = emul_s->range_table_list; - switch (emul_s->type) { - case COMEDI_SUBD_AI: - s->insn_read = timer_insn; - dev->read_subdev = s; - s->subdev_flags |= SDF_CMD_READ; - devpriv->io_function = timer_data_read; - break; - case COMEDI_SUBD_AO: - s->insn_write = timer_insn; - s->insn_read = timer_insn; - dev->write_subdev = s; - s->subdev_flags |= SDF_CMD_WRITE; - devpriv->io_function = timer_data_write; - break; - case COMEDI_SUBD_DIO: - s->insn_write = timer_insn; - s->insn_read = timer_insn; - s->insn_bits = timer_insn; - dev->read_subdev = s; - s->subdev_flags |= SDF_CMD_READ; - devpriv->io_function = timer_dio_read; - break; - default: - comedi_error(dev, "failed to determine subdevice type!"); - return -EINVAL; - } - - rt_set_oneshot_mode(); - start_rt_timer(1); - devpriv->timer_running = 1; - - devpriv->rt_task = kzalloc(sizeof(RT_TASK), GFP_KERNEL); - - // initialize real-time tasks - ret = rt_task_init(devpriv->rt_task, timer_task_func, - (comedi_rt_task_context_t) dev, 3000, timer_priority, 0, 0); - if (ret < 0) { - comedi_error(dev, "error initalizing rt_task"); - kfree(devpriv->rt_task); - devpriv->rt_task = 0; - return ret; - } - - devpriv->scan_task = kzalloc(sizeof(RT_TASK), GFP_KERNEL); - - ret = rt_task_init(devpriv->scan_task, scan_task_func, - (comedi_rt_task_context_t) dev, 3000, scan_priority, 0, 0); - if (ret < 0) { - comedi_error(dev, "error initalizing scan_task"); - kfree(devpriv->scan_task); - devpriv->scan_task = 0; - return ret; - } - - return 1; -} - -// free allocated resources -static int timer_detach(struct comedi_device * dev) -{ - printk("comedi%d: timer: remove\n", dev->minor); - - if (devpriv) { - if (devpriv->rt_task) { - rt_task_delete(devpriv->rt_task); - kfree(devpriv->rt_task); - } - if (devpriv->scan_task) { - rt_task_delete(devpriv->scan_task); - kfree(devpriv->scan_task); - } - if (devpriv->timer_running) - stop_rt_timer(); - if (devpriv->device) - comedi_close(devpriv->device); - } - return 0; -} diff --git a/drivers/staging/comedi/drivers/comedi_test.c b/drivers/staging/comedi/drivers/comedi_test.c index e679328a4f8f..9b8cf62973be 100644 --- a/drivers/staging/comedi/drivers/comedi_test.c +++ b/drivers/staging/comedi/drivers/comedi_test.c @@ -55,6 +55,7 @@ zero volts). #include #include "comedi_fc.h" +#include /* Board descriptions */ struct waveform_board { @@ -102,7 +103,7 @@ static struct comedi_driver driver_waveform = { .detach = waveform_detach, .board_name = &waveform_boards[0].name, .offset = sizeof(struct waveform_board), - .num_names = sizeof(waveform_boards) / sizeof(struct waveform_board), + .num_names = ARRAY_SIZE(waveform_boards), }; COMEDI_INITCLEANUP(driver_waveform); diff --git a/drivers/staging/comedi/drivers/contec_pci_dio.c b/drivers/staging/comedi/drivers/contec_pci_dio.c index 1f194a0a45d6..6c58e9990323 100644 --- a/drivers/staging/comedi/drivers/contec_pci_dio.c +++ b/drivers/staging/comedi/drivers/contec_pci_dio.c @@ -75,29 +75,29 @@ struct contec_private { #define devpriv ((struct contec_private *)dev->private) -static int contec_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int contec_detach(struct comedi_device * dev); +static int contec_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int contec_detach(struct comedi_device *dev); static struct comedi_driver driver_contec = { - driver_name:"contec_pci_dio", - module:THIS_MODULE, - attach:contec_attach, - detach:contec_detach, + .driver_name = "contec_pci_dio", + .module = THIS_MODULE, + .attach = contec_attach, + .detach = contec_detach, }; /* Classic digital IO */ -static int contec_di_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int contec_do_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); +static int contec_di_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int contec_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); #if 0 -static int contec_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd); +static int contec_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd); static int contec_ns_to_timer(unsigned int *ns, int round); #endif -static int contec_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int contec_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct pci_dev *pcidev; struct comedi_subdevice *s; @@ -164,7 +164,7 @@ static int contec_attach(struct comedi_device * dev, struct comedi_devconfig * i return -EIO; } -static int contec_detach(struct comedi_device * dev) +static int contec_detach(struct comedi_device *dev) { printk("comedi%d: contec: remove\n", dev->minor); @@ -179,8 +179,8 @@ static int contec_detach(struct comedi_device * dev) } #if 0 -static int contec_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd) +static int contec_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd) { printk("contec_cmdtest called\n"); return 0; @@ -192,8 +192,8 @@ static int contec_ns_to_timer(unsigned int *ns, int round) } #endif -static int contec_do_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int contec_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { printk("contec_do_insn_bits called\n"); @@ -205,19 +205,19 @@ static int contec_do_insn_bits(struct comedi_device * dev, struct comedi_subdevi if (data[0]) { s->state &= ~data[0]; s->state |= data[0] & data[1]; - rt_printk(" out: %d on %lx\n", s->state, + printk(" out: %d on %lx\n", s->state, dev->iobase + thisboard->out_offs); outw(s->state, dev->iobase + thisboard->out_offs); } return 2; } -static int contec_di_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int contec_di_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - rt_printk("contec_di_insn_bits called\n"); - rt_printk(" data: %d %d\n", data[0], data[1]); + printk("contec_di_insn_bits called\n"); + printk(" data: %d %d\n", data[0], data[1]); if (insn->n != 2) return -EINVAL; diff --git a/drivers/staging/comedi/drivers/daqboard2000.c b/drivers/staging/comedi/drivers/daqboard2000.c index 3b8444f09f28..d4526c616a99 100644 --- a/drivers/staging/comedi/drivers/daqboard2000.c +++ b/drivers/staging/comedi/drivers/daqboard2000.c @@ -119,6 +119,7 @@ Configuration options: #include "../comedidev.h" #include +#include #include "comedi_pci.h" #include "8255.h" @@ -129,7 +130,7 @@ Configuration options: #define DAQBOARD2000_DAQ_SIZE 0x1002 #define DAQBOARD2000_PLX_SIZE 0x100 -// Initialization bits for the Serial EEPROM Control Register +/* Initialization bits for the Serial EEPROM Control Register */ #define DAQBOARD2000_SECRProgPinHi 0x8001767e #define DAQBOARD2000_SECRProgPinLo 0x8000767e #define DAQBOARD2000_SECRLocalBusHi 0xc000767e @@ -137,14 +138,14 @@ Configuration options: #define DAQBOARD2000_SECRReloadHi 0xa000767e #define DAQBOARD2000_SECRReloadLo 0x8000767e -// SECR status bits +/* SECR status bits */ #define DAQBOARD2000_EEPROM_PRESENT 0x10000000 -// CPLD status bits +/* CPLD status bits */ #define DAQBOARD2000_CPLD_INIT 0x0002 #define DAQBOARD2000_CPLD_DONE 0x0004 -// Available ranges +/* Available ranges */ static const struct comedi_lrange range_daqboard2000_ai = { 13, { RANGE(-10, 10), RANGE(-5, 5), @@ -168,65 +169,65 @@ static const struct comedi_lrange range_daqboard2000_ao = { 1, { }; struct daqboard2000_hw { - volatile u16 acqControl; // 0x00 - volatile u16 acqScanListFIFO; // 0x02 - volatile u32 acqPacerClockDivLow; // 0x04 + volatile u16 acqControl; /* 0x00 */ + volatile u16 acqScanListFIFO; /* 0x02 */ + volatile u32 acqPacerClockDivLow; /* 0x04 */ - volatile u16 acqScanCounter; // 0x08 - volatile u16 acqPacerClockDivHigh; // 0x0a - volatile u16 acqTriggerCount; // 0x0c - volatile u16 fill2; // 0x0e - volatile u16 acqResultsFIFO; // 0x10 - volatile u16 fill3; // 0x12 - volatile u16 acqResultsShadow; // 0x14 - volatile u16 fill4; // 0x16 - volatile u16 acqAdcResult; // 0x18 - volatile u16 fill5; // 0x1a - volatile u16 dacScanCounter; // 0x1c - volatile u16 fill6; // 0x1e + volatile u16 acqScanCounter; /* 0x08 */ + volatile u16 acqPacerClockDivHigh; /* 0x0a */ + volatile u16 acqTriggerCount; /* 0x0c */ + volatile u16 fill2; /* 0x0e */ + volatile u16 acqResultsFIFO; /* 0x10 */ + volatile u16 fill3; /* 0x12 */ + volatile u16 acqResultsShadow; /* 0x14 */ + volatile u16 fill4; /* 0x16 */ + volatile u16 acqAdcResult; /* 0x18 */ + volatile u16 fill5; /* 0x1a */ + volatile u16 dacScanCounter; /* 0x1c */ + volatile u16 fill6; /* 0x1e */ - volatile u16 dacControl; // 0x20 - volatile u16 fill7; // 0x22 - volatile s16 dacFIFO; // 0x24 - volatile u16 fill8[2]; // 0x26 - volatile u16 dacPacerClockDiv; // 0x2a - volatile u16 refDacs; // 0x2c - volatile u16 fill9; // 0x2e + volatile u16 dacControl; /* 0x20 */ + volatile u16 fill7; /* 0x22 */ + volatile s16 dacFIFO; /* 0x24 */ + volatile u16 fill8[2]; /* 0x26 */ + volatile u16 dacPacerClockDiv; /* 0x2a */ + volatile u16 refDacs; /* 0x2c */ + volatile u16 fill9; /* 0x2e */ - volatile u16 dioControl; // 0x30 - volatile s16 dioP3hsioData; // 0x32 - volatile u16 dioP3Control; // 0x34 - volatile u16 calEepromControl; // 0x36 - volatile s16 dacSetting[4]; // 0x38 - volatile s16 dioP2ExpansionIO8Bit[32]; // 0x40 + volatile u16 dioControl; /* 0x30 */ + volatile s16 dioP3hsioData; /* 0x32 */ + volatile u16 dioP3Control; /* 0x34 */ + volatile u16 calEepromControl; /* 0x36 */ + volatile s16 dacSetting[4]; /* 0x38 */ + volatile s16 dioP2ExpansionIO8Bit[32]; /* 0x40 */ - volatile u16 ctrTmrControl; // 0x80 - volatile u16 fill10[3]; // 0x82 - volatile s16 ctrInput[4]; // 0x88 - volatile u16 fill11[8]; // 0x90 - volatile u16 timerDivisor[2]; // 0xa0 - volatile u16 fill12[6]; // 0xa4 + volatile u16 ctrTmrControl; /* 0x80 */ + volatile u16 fill10[3]; /* 0x82 */ + volatile s16 ctrInput[4]; /* 0x88 */ + volatile u16 fill11[8]; /* 0x90 */ + volatile u16 timerDivisor[2]; /* 0xa0 */ + volatile u16 fill12[6]; /* 0xa4 */ - volatile u16 dmaControl; // 0xb0 - volatile u16 trigControl; // 0xb2 - volatile u16 fill13[2]; // 0xb4 - volatile u16 calEeprom; // 0xb8 - volatile u16 acqDigitalMark; // 0xba - volatile u16 trigDacs; // 0xbc - volatile u16 fill14; // 0xbe - volatile s16 dioP2ExpansionIO16Bit[32]; // 0xc0 + volatile u16 dmaControl; /* 0xb0 */ + volatile u16 trigControl; /* 0xb2 */ + volatile u16 fill13[2]; /* 0xb4 */ + volatile u16 calEeprom; /* 0xb8 */ + volatile u16 acqDigitalMark; /* 0xba */ + volatile u16 trigDacs; /* 0xbc */ + volatile u16 fill14; /* 0xbe */ + volatile s16 dioP2ExpansionIO16Bit[32]; /* 0xc0 */ }; /* Scan Sequencer programming */ #define DAQBOARD2000_SeqStartScanList 0x0011 #define DAQBOARD2000_SeqStopScanList 0x0010 -// Prepare for acquisition +/* Prepare for acquisition */ #define DAQBOARD2000_AcqResetScanListFifo 0x0004 #define DAQBOARD2000_AcqResetResultsFifo 0x0002 #define DAQBOARD2000_AcqResetConfigPipe 0x0001 -// Acqusition status bits +/* Acqusition status bits */ #define DAQBOARD2000_AcqResultsFIFOMore1Sample 0x0001 #define DAQBOARD2000_AcqResultsFIFOHasValidData 0x0002 #define DAQBOARD2000_AcqResultsFIFOOverrun 0x0004 @@ -239,7 +240,7 @@ struct daqboard2000_hw { #define DAQBOARD2000_DacPacerOverrun 0x0200 #define DAQBOARD2000_AcqHardwareError 0x01c0 -// Scan Sequencer programming +/* Scan Sequencer programming */ #define DAQBOARD2000_SeqStartScanList 0x0011 #define DAQBOARD2000_SeqStopScanList 0x0010 @@ -254,7 +255,7 @@ struct daqboard2000_hw { #define DAQBOARD2000_AdcPacerInternalOutEnable 0x0008 #define DAQBOARD2000_AdcPacerExternalRising 0x0100 -// DAC status +/* DAC status */ #define DAQBOARD2000_DacFull 0x0001 #define DAQBOARD2000_RefBusy 0x0002 #define DAQBOARD2000_TrgBusy 0x0004 @@ -264,7 +265,7 @@ struct daqboard2000_hw { #define DAQBOARD2000_Dac2Busy 0x0040 #define DAQBOARD2000_Dac3Busy 0x0080 -// DAC control +/* DAC control */ #define DAQBOARD2000_Dac0Enable 0x0021 #define DAQBOARD2000_Dac1Enable 0x0031 #define DAQBOARD2000_Dac2Enable 0x0041 @@ -292,18 +293,18 @@ struct daqboard2000_hw { #define DAQBOARD2000_TrigEnable 0x0001 #define DAQBOARD2000_TrigDisable 0x0000 -// Reference Dac Selection +/* Reference Dac Selection */ #define DAQBOARD2000_PosRefDacSelect 0x0100 #define DAQBOARD2000_NegRefDacSelect 0x0000 -static int daqboard2000_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int daqboard2000_detach(struct comedi_device * dev); +static int daqboard2000_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int daqboard2000_detach(struct comedi_device *dev); static struct comedi_driver driver_daqboard2000 = { - driver_name:"daqboard2000", - module:THIS_MODULE, - attach:daqboard2000_attach, - detach:daqboard2000_detach, + .driver_name = "daqboard2000", + .module = THIS_MODULE, + .attach = daqboard2000_attach, + .detach = daqboard2000_detach, }; struct daq200_boardtype { @@ -338,17 +339,17 @@ struct daqboard2000_private { #define devpriv ((struct daqboard2000_private *)dev->private) -static void writeAcqScanListEntry(struct comedi_device * dev, u16 entry) +static void writeAcqScanListEntry(struct comedi_device *dev, u16 entry) { struct daqboard2000_hw *fpga = devpriv->daq; -// comedi_udelay(4); +/* udelay(4); */ fpga->acqScanListFIFO = entry & 0x00ff; -// comedi_udelay(4); +/* udelay(4); */ fpga->acqScanListFIFO = (entry >> 8) & 0x00ff; } -static void setup_sampling(struct comedi_device * dev, int chan, int gain) +static void setup_sampling(struct comedi_device *dev, int chan, int gain) { u16 word0, word1, word2, word3; @@ -393,8 +394,8 @@ static void setup_sampling(struct comedi_device * dev, int chan, int gain) writeAcqScanListEntry(dev, word3); } -static int daqboard2000_ai_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int daqboard2000_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i; struct daqboard2000_hw *fpga = devpriv->daq; @@ -425,14 +426,14 @@ static int daqboard2000_ai_insn_read(struct comedi_device * dev, struct comedi_s if (fpga->acqControl & DAQBOARD2000_AcqConfigPipeFull) { break; } - //comedi_udelay(2); + /* udelay(2); */ } fpga->acqControl = DAQBOARD2000_AdcPacerEnable; for (timeout = 0; timeout < 20; timeout++) { if (fpga->acqControl & DAQBOARD2000_AcqLogicScanning) { break; } - //comedi_udelay(2); + /* udelay(2); */ } for (timeout = 0; timeout < 20; timeout++) { if (fpga-> @@ -440,7 +441,7 @@ static int daqboard2000_ai_insn_read(struct comedi_device * dev, struct comedi_s DAQBOARD2000_AcqResultsFIFOHasValidData) { break; } - //comedi_udelay(2); + /* udelay(2); */ } data[i] = fpga->acqResultsFIFO; fpga->acqControl = DAQBOARD2000_AdcPacerDisable; @@ -450,8 +451,8 @@ static int daqboard2000_ai_insn_read(struct comedi_device * dev, struct comedi_s return i; } -static int daqboard2000_ao_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int daqboard2000_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i; int chan = CR_CHAN(insn->chanspec); @@ -463,8 +464,8 @@ static int daqboard2000_ao_insn_read(struct comedi_device * dev, struct comedi_s return i; } -static int daqboard2000_ao_insn_write(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int daqboard2000_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i; int chan = CR_CHAN(insn->chanspec); @@ -476,54 +477,54 @@ static int daqboard2000_ao_insn_write(struct comedi_device * dev, struct comedi_ * OK, since it works OK without enabling the DAC's, let's keep * it as simple as possible... */ - //fpga->dacControl = (chan + 2) * 0x0010 | 0x0001; comedi_udelay(1000); + /* fpga->dacControl = (chan + 2) * 0x0010 | 0x0001; udelay(1000); */ fpga->dacSetting[chan] = data[i]; for (timeout = 0; timeout < 20; timeout++) { if ((fpga->dacControl & ((chan + 1) * 0x0010)) == 0) { break; } - //comedi_udelay(2); + /* udelay(2); */ } devpriv->ao_readback[chan] = data[i]; /* * Since we never enabled the DAC's, we don't need to disable it... - * fpga->dacControl = (chan + 2) * 0x0010 | 0x0000; comedi_udelay(1000); + * fpga->dacControl = (chan + 2) * 0x0010 | 0x0000; udelay(1000); */ } return i; } -static void daqboard2000_resetLocalBus(struct comedi_device * dev) +static void daqboard2000_resetLocalBus(struct comedi_device *dev) { printk("daqboard2000_resetLocalBus\n"); writel(DAQBOARD2000_SECRLocalBusHi, devpriv->plx + 0x6c); - comedi_udelay(10000); + udelay(10000); writel(DAQBOARD2000_SECRLocalBusLo, devpriv->plx + 0x6c); - comedi_udelay(10000); + udelay(10000); } -static void daqboard2000_reloadPLX(struct comedi_device * dev) +static void daqboard2000_reloadPLX(struct comedi_device *dev) { printk("daqboard2000_reloadPLX\n"); writel(DAQBOARD2000_SECRReloadLo, devpriv->plx + 0x6c); - comedi_udelay(10000); + udelay(10000); writel(DAQBOARD2000_SECRReloadHi, devpriv->plx + 0x6c); - comedi_udelay(10000); + udelay(10000); writel(DAQBOARD2000_SECRReloadLo, devpriv->plx + 0x6c); - comedi_udelay(10000); + udelay(10000); } -static void daqboard2000_pulseProgPin(struct comedi_device * dev) +static void daqboard2000_pulseProgPin(struct comedi_device *dev) { printk("daqboard2000_pulseProgPin 1\n"); writel(DAQBOARD2000_SECRProgPinHi, devpriv->plx + 0x6c); - comedi_udelay(10000); + udelay(10000); writel(DAQBOARD2000_SECRProgPinLo, devpriv->plx + 0x6c); - comedi_udelay(10000); /* Not in the original code, but I like symmetry... */ + udelay(10000); /* Not in the original code, but I like symmetry... */ } -static int daqboard2000_pollCPLD(struct comedi_device * dev, int mask) +static int daqboard2000_pollCPLD(struct comedi_device *dev, int mask) { int result = 0; int i; @@ -536,17 +537,17 @@ static int daqboard2000_pollCPLD(struct comedi_device * dev, int mask) result = 1; break; } - comedi_udelay(100); + udelay(100); } - comedi_udelay(5); + udelay(5); return result; } -static int daqboard2000_writeCPLD(struct comedi_device * dev, int data) +static int daqboard2000_writeCPLD(struct comedi_device *dev, int data) { int result = 0; - comedi_udelay(10); + udelay(10); writew(data, devpriv->daq + 0x1000); if ((readw(devpriv->daq + 0x1000) & DAQBOARD2000_CPLD_INIT) == DAQBOARD2000_CPLD_INIT) { @@ -555,7 +556,7 @@ static int daqboard2000_writeCPLD(struct comedi_device * dev, int data) return result; } -static int initialize_daqboard2000(struct comedi_device * dev, +static int initialize_daqboard2000(struct comedi_device *dev, unsigned char *cpld_array, int len) { int result = -EIO; @@ -613,75 +614,75 @@ static int initialize_daqboard2000(struct comedi_device * dev, return result; } -static void daqboard2000_adcStopDmaTransfer(struct comedi_device * dev) +static void daqboard2000_adcStopDmaTransfer(struct comedi_device *dev) { /* printk("Implement: daqboard2000_adcStopDmaTransfer\n");*/ } -static void daqboard2000_adcDisarm(struct comedi_device * dev) +static void daqboard2000_adcDisarm(struct comedi_device *dev) { struct daqboard2000_hw *fpga = devpriv->daq; /* Disable hardware triggers */ - comedi_udelay(2); + udelay(2); fpga->trigControl = DAQBOARD2000_TrigAnalog | DAQBOARD2000_TrigDisable; - comedi_udelay(2); + udelay(2); fpga->trigControl = DAQBOARD2000_TrigTTL | DAQBOARD2000_TrigDisable; /* Stop the scan list FIFO from loading the configuration pipe */ - comedi_udelay(2); + udelay(2); fpga->acqControl = DAQBOARD2000_SeqStopScanList; /* Stop the pacer clock */ - comedi_udelay(2); + udelay(2); fpga->acqControl = DAQBOARD2000_AdcPacerDisable; /* Stop the input dma (abort channel 1) */ daqboard2000_adcStopDmaTransfer(dev); } -static void daqboard2000_activateReferenceDacs(struct comedi_device * dev) +static void daqboard2000_activateReferenceDacs(struct comedi_device *dev) { struct daqboard2000_hw *fpga = devpriv->daq; int timeout; - // Set the + reference dac value in the FPGA + /* Set the + reference dac value in the FPGA */ fpga->refDacs = 0x80 | DAQBOARD2000_PosRefDacSelect; for (timeout = 0; timeout < 20; timeout++) { if ((fpga->dacControl & DAQBOARD2000_RefBusy) == 0) { break; } - comedi_udelay(2); + udelay(2); } /* printk("DAQBOARD2000_PosRefDacSelect %d\n", timeout);*/ - // Set the - reference dac value in the FPGA + /* Set the - reference dac value in the FPGA */ fpga->refDacs = 0x80 | DAQBOARD2000_NegRefDacSelect; for (timeout = 0; timeout < 20; timeout++) { if ((fpga->dacControl & DAQBOARD2000_RefBusy) == 0) { break; } - comedi_udelay(2); + udelay(2); } /* printk("DAQBOARD2000_NegRefDacSelect %d\n", timeout);*/ } -static void daqboard2000_initializeCtrs(struct comedi_device * dev) +static void daqboard2000_initializeCtrs(struct comedi_device *dev) { /* printk("Implement: daqboard2000_initializeCtrs\n");*/ } -static void daqboard2000_initializeTmrs(struct comedi_device * dev) +static void daqboard2000_initializeTmrs(struct comedi_device *dev) { /* printk("Implement: daqboard2000_initializeTmrs\n");*/ } -static void daqboard2000_dacDisarm(struct comedi_device * dev) +static void daqboard2000_dacDisarm(struct comedi_device *dev) { /* printk("Implement: daqboard2000_dacDisarm\n");*/ } -static void daqboard2000_initializeAdc(struct comedi_device * dev) +static void daqboard2000_initializeAdc(struct comedi_device *dev) { daqboard2000_adcDisarm(dev); daqboard2000_activateReferenceDacs(dev); @@ -689,7 +690,7 @@ static void daqboard2000_initializeAdc(struct comedi_device * dev) daqboard2000_initializeTmrs(dev); } -static void daqboard2000_initializeDac(struct comedi_device * dev) +static void daqboard2000_initializeDac(struct comedi_device *dev) { daqboard2000_dacDisarm(dev); } @@ -717,7 +718,7 @@ static int daqboard2000_8255_cb(int dir, int port, int data, return result; } -static int daqboard2000_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int daqboard2000_attach(struct comedi_device *dev, struct comedi_devconfig *it) { int result = 0; struct comedi_subdevice *s; @@ -772,7 +773,8 @@ static int daqboard2000_attach(struct comedi_device * dev, struct comedi_devconf } } - if ((result = comedi_pci_enable(card, "daqboard2000")) < 0) { + result = comedi_pci_enable(card, "daqboard2000"); + if (result < 0) { printk(" failed to enable PCI device and request regions\n"); return -EIO; } @@ -849,7 +851,7 @@ static int daqboard2000_attach(struct comedi_device * dev, struct comedi_devconf return result; } -static int daqboard2000_detach(struct comedi_device * dev) +static int daqboard2000_detach(struct comedi_device *dev) { printk("comedi%d: daqboard2000: remove\n", dev->minor); diff --git a/drivers/staging/comedi/drivers/das08.c b/drivers/staging/comedi/drivers/das08.c index e4563331e963..c20cd8feb13d 100644 --- a/drivers/staging/comedi/drivers/das08.c +++ b/drivers/staging/comedi/drivers/das08.c @@ -65,12 +65,12 @@ driver. #define PCI_DEVICE_ID_PCIDAS08 0x29 #define PCIDAS08_SIZE 0x54 -// pci configuration registers +/* pci configuration registers */ #define INTCSR 0x4c #define INTR1_ENABLE 0x1 #define INTR1_HIGH_POLARITY 0x2 #define PCI_INTR_ENABLE 0x40 -#define INTR1_EDGE_TRIG 0x100 // requires high polarity +#define INTR1_EDGE_TRIG 0x100 /* requires high polarity */ #define CNTRL 0x50 #define CNTRL_DIR 0x2 #define CNTRL_INTR 0x4 @@ -154,20 +154,20 @@ driver. /* gainlist same as _pgx_ below */ -static int das08_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int das08_di_rbits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int das08_do_wbits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int das08jr_di_rbits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int das08jr_do_wbits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int das08jr_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int das08ao_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); +static int das08_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int das08_di_rbits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int das08_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int das08jr_di_rbits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int das08jr_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int das08jr_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int das08ao_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); static void i8254_set_mode_low(unsigned int base, int channel, unsigned int mode); @@ -248,211 +248,211 @@ static const int *const das08_gainlists[] = { static const struct das08_board_struct das08_boards[] = { { - name: "isa-das08", // cio-das08.pdf - bustype: isa, - ai: das08_ai_rinsn, - ai_nbits:12, - ai_pg: das08_pg_none, - ai_encoding:das08_encode12, - ao: NULL, - ao_nbits:12, - di: das08_di_rbits, - do_: das08_do_wbits, - do_nchan:4, - i8255_offset:8, - i8254_offset:4, - iosize: 16, // unchecked + .name = "isa-das08", /* cio-das08.pdf */ + .bustype = isa, + .ai = das08_ai_rinsn, + .ai_nbits = 12, + .ai_pg = das08_pg_none, + .ai_encoding = das08_encode12, + .ao = NULL, + .ao_nbits = 12, + .di = das08_di_rbits, + .do_ = das08_do_wbits, + .do_nchan = 4, + .i8255_offset = 8, + .i8254_offset = 4, + .iosize = 16, /* unchecked */ }, { - name: "das08-pgm", // cio-das08pgx.pdf - bustype: isa, - ai: das08_ai_rinsn, - ai_nbits:12, - ai_pg: das08_pgm, - ai_encoding:das08_encode12, - ao: NULL, - di: das08_di_rbits, - do_: das08_do_wbits, - do_nchan:4, - i8255_offset:0, - i8254_offset:0x04, - iosize: 16, // unchecked + .name = "das08-pgm", /* cio-das08pgx.pdf */ + .bustype = isa, + .ai = das08_ai_rinsn, + .ai_nbits = 12, + .ai_pg = das08_pgm, + .ai_encoding = das08_encode12, + .ao = NULL, + .di = das08_di_rbits, + .do_ = das08_do_wbits, + .do_nchan = 4, + .i8255_offset = 0, + .i8254_offset = 0x04, + .iosize = 16, /* unchecked */ }, { - name: "das08-pgh", // cio-das08pgx.pdf - bustype: isa, - ai: das08_ai_rinsn, - ai_nbits:12, - ai_pg: das08_pgh, - ai_encoding:das08_encode12, - ao: NULL, - di: das08_di_rbits, - do_: das08_do_wbits, - do_nchan:4, - i8255_offset:0, - i8254_offset:0x04, - iosize: 16, // unchecked + .name = "das08-pgh", /* cio-das08pgx.pdf */ + .bustype = isa, + .ai = das08_ai_rinsn, + .ai_nbits = 12, + .ai_pg = das08_pgh, + .ai_encoding = das08_encode12, + .ao = NULL, + .di = das08_di_rbits, + .do_ = das08_do_wbits, + .do_nchan = 4, + .i8255_offset = 0, + .i8254_offset = 0x04, + .iosize = 16, /* unchecked */ }, { - name: "das08-pgl", // cio-das08pgx.pdf - bustype: isa, - ai: das08_ai_rinsn, - ai_nbits:12, - ai_pg: das08_pgl, - ai_encoding:das08_encode12, - ao: NULL, - di: das08_di_rbits, - do_: das08_do_wbits, - do_nchan:4, - i8255_offset:0, - i8254_offset:0x04, - iosize: 16, // unchecked + .name = "das08-pgl", /* cio-das08pgx.pdf */ + .bustype = isa, + .ai = das08_ai_rinsn, + .ai_nbits = 12, + .ai_pg = das08_pgl, + .ai_encoding = das08_encode12, + .ao = NULL, + .di = das08_di_rbits, + .do_ = das08_do_wbits, + .do_nchan = 4, + .i8255_offset = 0, + .i8254_offset = 0x04, + .iosize = 16, /* unchecked */ }, { - name: "das08-aoh", // cio-das08_aox.pdf - bustype: isa, - ai: das08_ai_rinsn, - ai_nbits:12, - ai_pg: das08_pgh, - ai_encoding:das08_encode12, - ao: das08ao_ao_winsn, // 8 - ao_nbits:12, - di: das08_di_rbits, - do_: das08_do_wbits, - do_nchan:4, - i8255_offset:0x0c, - i8254_offset:0x04, - iosize: 16, // unchecked + .name = "das08-aoh", /* cio-das08_aox.pdf */ + .bustype = isa, + .ai = das08_ai_rinsn, + .ai_nbits = 12, + .ai_pg = das08_pgh, + .ai_encoding = das08_encode12, + .ao = das08ao_ao_winsn, /* 8 */ + .ao_nbits = 12, + .di = das08_di_rbits, + .do_ = das08_do_wbits, + .do_nchan = 4, + .i8255_offset = 0x0c, + .i8254_offset = 0x04, + .iosize = 16, /* unchecked */ }, { - name: "das08-aol", // cio-das08_aox.pdf - bustype: isa, - ai: das08_ai_rinsn, - ai_nbits:12, - ai_pg: das08_pgl, - ai_encoding:das08_encode12, - ao: das08ao_ao_winsn, // 8 - ao_nbits:12, - di: das08_di_rbits, - do_: das08_do_wbits, - do_nchan:4, - i8255_offset:0x0c, - i8254_offset:0x04, - iosize: 16, // unchecked + .name = "das08-aol", /* cio-das08_aox.pdf */ + .bustype = isa, + .ai = das08_ai_rinsn, + .ai_nbits = 12, + .ai_pg = das08_pgl, + .ai_encoding = das08_encode12, + .ao = das08ao_ao_winsn, /* 8 */ + .ao_nbits = 12, + .di = das08_di_rbits, + .do_ = das08_do_wbits, + .do_nchan = 4, + .i8255_offset = 0x0c, + .i8254_offset = 0x04, + .iosize = 16, /* unchecked */ }, { - name: "das08-aom", // cio-das08_aox.pdf - bustype: isa, - ai: das08_ai_rinsn, - ai_nbits:12, - ai_pg: das08_pgm, - ai_encoding:das08_encode12, - ao: das08ao_ao_winsn, // 8 - ao_nbits:12, - di: das08_di_rbits, - do_: das08_do_wbits, - do_nchan:4, - i8255_offset:0x0c, - i8254_offset:0x04, - iosize: 16, // unchecked + .name = "das08-aom", /* cio-das08_aox.pdf */ + .bustype = isa, + .ai = das08_ai_rinsn, + .ai_nbits = 12, + .ai_pg = das08_pgm, + .ai_encoding = das08_encode12, + .ao = das08ao_ao_winsn, /* 8 */ + .ao_nbits = 12, + .di = das08_di_rbits, + .do_ = das08_do_wbits, + .do_nchan = 4, + .i8255_offset = 0x0c, + .i8254_offset = 0x04, + .iosize = 16, /* unchecked */ }, { - name: "das08/jr-ao", // cio-das08-jr-ao.pdf - bustype: isa, - ai: das08_ai_rinsn, - ai_nbits:12, - ai_pg: das08_pg_none, - ai_encoding:das08_encode12, - ao: das08jr_ao_winsn, - ao_nbits:12, - di: das08jr_di_rbits, - do_: das08jr_do_wbits, - do_nchan:8, - i8255_offset:0, - i8254_offset:0, - iosize: 16, // unchecked + .name = "das08/jr-ao", /* cio-das08-jr-ao.pdf */ + .bustype = isa, + .ai = das08_ai_rinsn, + .ai_nbits = 12, + .ai_pg = das08_pg_none, + .ai_encoding = das08_encode12, + .ao = das08jr_ao_winsn, + .ao_nbits = 12, + .di = das08jr_di_rbits, + .do_ = das08jr_do_wbits, + .do_nchan = 8, + .i8255_offset = 0, + .i8254_offset = 0, + .iosize = 16, /* unchecked */ }, { - name: "das08jr-16-ao", // cio-das08jr-16-ao.pdf - bustype: isa, - ai: das08_ai_rinsn, - ai_nbits:16, - ai_pg: das08_pg_none, - ai_encoding:das08_encode12, - ao: das08jr_ao_winsn, - ao_nbits:16, - di: das08jr_di_rbits, - do_: das08jr_do_wbits, - do_nchan:8, - i8255_offset:0, - i8254_offset:0x04, - iosize: 16, // unchecked + .name = "das08jr-16-ao", /* cio-das08jr-16-ao.pdf */ + .bustype = isa, + .ai = das08_ai_rinsn, + .ai_nbits = 16, + .ai_pg = das08_pg_none, + .ai_encoding = das08_encode12, + .ao = das08jr_ao_winsn, + .ao_nbits = 16, + .di = das08jr_di_rbits, + .do_ = das08jr_do_wbits, + .do_nchan = 8, + .i8255_offset = 0, + .i8254_offset = 0x04, + .iosize = 16, /* unchecked */ }, #ifdef CONFIG_COMEDI_PCI { - name: "das08", // pci-das08 - id: PCI_DEVICE_ID_PCIDAS08, - bustype: pci, - ai: das08_ai_rinsn, - ai_nbits:12, - ai_pg: das08_bipolar5, - ai_encoding:das08_encode12, - ao: NULL, - ao_nbits:0, - di: das08_di_rbits, - do_: das08_do_wbits, - do_nchan:4, - i8255_offset:0, - i8254_offset:4, - iosize: 8, + .name = "das08", /* pci-das08 */ + .id = PCI_DEVICE_ID_PCIDAS08, + .bustype = pci, + .ai = das08_ai_rinsn, + .ai_nbits = 12, + .ai_pg = das08_bipolar5, + .ai_encoding = das08_encode12, + .ao = NULL, + .ao_nbits = 0, + .di = das08_di_rbits, + .do_ = das08_do_wbits, + .do_nchan = 4, + .i8255_offset = 0, + .i8254_offset = 4, + .iosize = 8, }, #endif { - name: "pc104-das08", - bustype: pc104, - ai: das08_ai_rinsn, - ai_nbits:12, - ai_pg: das08_pg_none, - ai_encoding:das08_encode12, - ao: NULL, - ao_nbits:0, - di: das08_di_rbits, - do_: das08_do_wbits, - do_nchan:4, - i8255_offset:0, - i8254_offset:4, - iosize: 16, // unchecked + .name = "pc104-das08", + .bustype = pc104, + .ai = das08_ai_rinsn, + .ai_nbits = 12, + .ai_pg = das08_pg_none, + .ai_encoding = das08_encode12, + .ao = NULL, + .ao_nbits = 0, + .di = das08_di_rbits, + .do_ = das08_do_wbits, + .do_nchan = 4, + .i8255_offset = 0, + .i8254_offset = 4, + .iosize = 16, /* unchecked */ }, #if 0 { - name: "das08/f", + .name = "das08/f", }, { - name: "das08jr", + .name = "das08jr", }, #endif { - name: "das08jr/16", - bustype: isa, - ai: das08_ai_rinsn, - ai_nbits:16, - ai_pg: das08_pg_none, - ai_encoding:das08_encode16, - ao: NULL, - ao_nbits:0, - di: das08jr_di_rbits, - do_: das08jr_do_wbits, - do_nchan:8, - i8255_offset:0, - i8254_offset:0, - iosize: 16, // unchecked + .name = "das08jr/16", + .bustype = isa, + .ai = das08_ai_rinsn, + .ai_nbits = 16, + .ai_pg = das08_pg_none, + .ai_encoding = das08_encode16, + .ao = NULL, + .ao_nbits = 0, + .di = das08jr_di_rbits, + .do_ = das08jr_do_wbits, + .do_nchan = 8, + .i8255_offset = 0, + .i8254_offset = 0, + .iosize = 16, /* unchecked */ }, #if 0 { - name: "das48-pga", // cio-das48-pga.pdf + .name = "das48-pga", /* cio-das48-pga.pdf */ }, { - name: "das08-pga-g2", // a KM board + .name = "das08-pga-g2", /* a KM board */ }, #endif }; @@ -460,39 +460,39 @@ static const struct das08_board_struct das08_boards[] = { #ifdef CONFIG_COMEDI_PCMCIA struct das08_board_struct das08_cs_boards[NUM_DAS08_CS_BOARDS] = { { - name: "pcm-das08", - id: 0x0, // XXX - bustype: pcmcia, - ai: das08_ai_rinsn, - ai_nbits:12, - ai_pg: das08_bipolar5, - ai_encoding:das08_pcm_encode12, - ao: NULL, - ao_nbits:0, - di: das08_di_rbits, - do_: das08_do_wbits, - do_nchan:3, - i8255_offset:0, - i8254_offset:0, - iosize: 16, + .name = "pcm-das08", + .id = 0x0, /* XXX */ + .bustype = pcmcia, + .ai = das08_ai_rinsn, + .ai_nbits = 12, + .ai_pg = das08_bipolar5, + .ai_encoding = das08_pcm_encode12, + .ao = NULL, + .ao_nbits = 0, + .di = das08_di_rbits, + .do_ = das08_do_wbits, + .do_nchan = 3, + .i8255_offset = 0, + .i8254_offset = 0, + .iosize = 16, }, - // duplicate so driver name can be used also + /* duplicate so driver name can be used also */ { - name: "das08_cs", - id: 0x0, // XXX - bustype: pcmcia, - ai: das08_ai_rinsn, - ai_nbits:12, - ai_pg: das08_bipolar5, - ai_encoding:das08_pcm_encode12, - ao: NULL, - ao_nbits:0, - di: das08_di_rbits, - do_: das08_do_wbits, - do_nchan:3, - i8255_offset:0, - i8254_offset:0, - iosize: 16, + .name = "das08_cs", + .id = 0x0, /* XXX */ + .bustype = pcmcia, + .ai = das08_ai_rinsn, + .ai_nbits = 12, + .ai_pg = das08_bipolar5, + .ai_encoding = das08_pcm_encode12, + .ao = NULL, + .ao_nbits = 0, + .di = das08_di_rbits, + .do_ = das08_do_wbits, + .do_nchan = 3, + .i8255_offset = 0, + .i8254_offset = 0, + .iosize = 16, }, }; #endif @@ -512,8 +512,8 @@ MODULE_DEVICE_TABLE(pci, das08_pci_table); #define TIMEOUT 100000 -static int das08_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int das08_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i, n; int chan; @@ -528,7 +528,7 @@ static int das08_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * inb(dev->iobase + DAS08_MSB); /* set multiplexer */ - spin_lock(&dev->spinlock); // lock to prevent race with digital output + spin_lock(&dev->spinlock); /* lock to prevent race with digital output */ devpriv->do_mux_bits &= ~DAS08_MUX_MASK; devpriv->do_mux_bits |= DAS08_MUX(chan); outb(devpriv->do_mux_bits, dev->iobase + DAS08_CONTROL); @@ -545,7 +545,7 @@ static int das08_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * /* clear over-range bits for 16-bit boards */ if (thisboard->ai_nbits == 16) if (inb(dev->iobase + DAS08_MSB) & 0x80) - rt_printk("das08: over-range\n"); + printk("das08: over-range\n"); /* trigger conversion */ outb_p(0, dev->iobase + DAS08_TRIG_12BIT); @@ -555,7 +555,7 @@ static int das08_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * break; } if (i == TIMEOUT) { - rt_printk("das08: timeout\n"); + printk("das08: timeout\n"); return -ETIME; } msb = inb(dev->iobase + DAS08_MSB); @@ -579,8 +579,8 @@ static int das08_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * return n; } -static int das08_di_rbits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int das08_di_rbits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { data[0] = 0; data[1] = DAS08_IP(inb(dev->iobase + DAS08_STATUS)); @@ -588,19 +588,19 @@ static int das08_di_rbits(struct comedi_device * dev, struct comedi_subdevice * return 2; } -static int das08_do_wbits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int das08_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int wbits; - // get current settings of digital output lines + /* get current settings of digital output lines */ wbits = (devpriv->do_mux_bits >> 4) & 0xf; - // null bits we are going to set + /* null bits we are going to set */ wbits &= ~data[0]; - // set new bit values + /* set new bit values */ wbits |= data[0] & data[1]; - // remember digital output bits - spin_lock(&dev->spinlock); // prevent race with setting of analog input mux + /* remember digital output bits */ + spin_lock(&dev->spinlock); /* prevent race with setting of analog input mux */ devpriv->do_mux_bits &= ~DAS08_DO_MASK; devpriv->do_mux_bits |= DAS08_OP(wbits); outb(devpriv->do_mux_bits, dev->iobase + DAS08_CONTROL); @@ -611,8 +611,8 @@ static int das08_do_wbits(struct comedi_device * dev, struct comedi_subdevice * return 2; } -static int das08jr_di_rbits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int das08jr_di_rbits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { data[0] = 0; data[1] = inb(dev->iobase + DAS08JR_DIO); @@ -620,12 +620,12 @@ static int das08jr_di_rbits(struct comedi_device * dev, struct comedi_subdevice return 2; } -static int das08jr_do_wbits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int das08jr_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - // null bits we are going to set + /* null bits we are going to set */ devpriv->do_bits &= ~data[0]; - // set new bit values + /* set new bit values */ devpriv->do_bits |= data[0] & data[1]; outb(devpriv->do_bits, dev->iobase + DAS08JR_DIO); @@ -634,8 +634,8 @@ static int das08jr_do_wbits(struct comedi_device * dev, struct comedi_subdevice return 2; } -static int das08jr_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int das08jr_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int n; int lsb, msb; @@ -668,8 +668,8 @@ static int das08jr_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * a different method to force an update. * */ -static int das08ao_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int das08ao_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int n; int lsb, msb; @@ -782,31 +782,31 @@ static unsigned int i8254_read_status(struct i8254_struct *st, int channel) return i8254_read_status_low(st->iobase, chan); } -static int das08_counter_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int das08_counter_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int chan = insn->chanspec; - //printk("Reading counter channel %d ",chan); + /* printk("Reading counter channel %d ",chan); */ data[0] = i8254_read_channel(&devpriv->i8254, chan); - //printk("=> 0x%08X\n",data[0]); + /* printk("=> 0x%08X\n",data[0]); */ return 1; } -static int das08_counter_write(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int das08_counter_write(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int chan = insn->chanspec; - //printk("Writing counter channel %d with 0x%04X\n",chan,data[0]); + /* printk("Writing counter channel %d with 0x%04X\n",chan,data[0]); */ i8254_write_channel(&devpriv->i8254, chan, data[0]); return 1; } -static int das08_counter_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int das08_counter_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int chan = insn->chanspec; @@ -827,25 +827,25 @@ static int das08_counter_config(struct comedi_device * dev, struct comedi_subdev return 2; } -static int das08_attach(struct comedi_device * dev, struct comedi_devconfig * it); +static int das08_attach(struct comedi_device *dev, struct comedi_devconfig *it); static struct comedi_driver driver_das08 = { - driver_name: DRV_NAME, - module:THIS_MODULE, - attach:das08_attach, - detach:das08_common_detach, - board_name:&das08_boards[0].name, - num_names:sizeof(das08_boards) / + .driver_name = DRV_NAME, + .module = THIS_MODULE, + .attach = das08_attach, + .detach = das08_common_detach, + .board_name = &das08_boards[0].name, + .num_names = sizeof(das08_boards) / sizeof(struct das08_board_struct), - offset:sizeof(struct das08_board_struct), + .offset = sizeof(struct das08_board_struct), }; -int das08_common_attach(struct comedi_device * dev, unsigned long iobase) +int das08_common_attach(struct comedi_device *dev, unsigned long iobase) { struct comedi_subdevice *s; int ret; - // allocate ioports for non-pcmcia, non-pci boards + /* allocate ioports for non-pcmcia, non-pci boards */ if ((thisboard->bustype != pcmcia) && (thisboard->bustype != pci)) { printk(" iobase 0x%lx\n", iobase); if (!request_region(iobase, thisboard->iosize, DRV_NAME)) { @@ -857,7 +857,8 @@ int das08_common_attach(struct comedi_device * dev, unsigned long iobase) dev->board_name = thisboard->name; - if ((ret = alloc_subdevices(dev, 6)) < 0) + ret = alloc_subdevices(dev, 6); + if (ret < 0) return ret; s = dev->subdevices + 0; @@ -880,7 +881,7 @@ int das08_common_attach(struct comedi_device * dev, unsigned long iobase) /* ao */ if (thisboard->ao) { s->type = COMEDI_SUBD_AO; -// XXX lacks read-back insn +/* XXX lacks read-back insn */ s->subdev_flags = SDF_WRITABLE; s->n_chan = 2; s->maxdata = (1 << thisboard->ao_nbits) - 1; @@ -952,7 +953,7 @@ int das08_common_attach(struct comedi_device * dev, unsigned long iobase) return 0; } -static int das08_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int das08_attach(struct comedi_device *dev, struct comedi_devconfig *it) { int ret; unsigned long iobase; @@ -961,11 +962,12 @@ static int das08_attach(struct comedi_device * dev, struct comedi_devconfig * it struct pci_dev *pdev; #endif - if ((ret = alloc_private(dev, sizeof(struct das08_private_struct))) < 0) + ret = alloc_private(dev, sizeof(struct das08_private_struct)); + if (ret < 0) return ret; printk("comedi%d: das08: ", dev->minor); - // deal with a pci board + /* deal with a pci board */ if (thisboard->bustype == pci) { #ifdef CONFIG_COMEDI_PCI if (it->options[0] || it->options[1]) { @@ -973,7 +975,7 @@ static int das08_attach(struct comedi_device * dev, struct comedi_devconfig * it it->options[0], it->options[1]); } printk("\n"); - // find card + /* find card */ for (pdev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL); pdev != NULL; pdev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) { @@ -995,12 +997,12 @@ static int das08_attach(struct comedi_device * dev, struct comedi_devconfig * it return -EIO; } devpriv->pdev = pdev; - // enable PCI device and reserve I/O spaces + /* enable PCI device and reserve I/O spaces */ if (comedi_pci_enable(pdev, DRV_NAME)) { printk(" Error enabling PCI device and requesting regions\n"); return -EIO; } - // read base addresses + /* read base addresses */ pci_iobase = pci_resource_start(pdev, 1); iobase = pci_resource_start(pdev, 2); printk("pcibase 0x%lx iobase 0x%lx\n", pci_iobase, iobase); @@ -1028,14 +1030,14 @@ static int das08_attach(struct comedi_device * dev, struct comedi_devconfig * it return das08_common_attach(dev, iobase); } -int das08_common_detach(struct comedi_device * dev) +int das08_common_detach(struct comedi_device *dev) { printk(KERN_INFO "comedi%d: das08: remove\n", dev->minor); if (dev->subdevices) subdev_8255_cleanup(dev, dev->subdevices + 4); - // deallocate ioports for non-pcmcia, non-pci boards + /* deallocate ioports for non-pcmcia, non-pci boards */ if ((thisboard->bustype != pcmcia) && (thisboard->bustype != pci)) { if (dev->iobase) release_region(dev->iobase, thisboard->iosize); diff --git a/drivers/staging/comedi/drivers/das08.h b/drivers/staging/comedi/drivers/das08.h index 69089ce690f2..7cdb3fc4daee 100644 --- a/drivers/staging/comedi/drivers/das08.h +++ b/drivers/staging/comedi/drivers/das08.h @@ -25,14 +25,14 @@ #define _DAS08_H enum das08_bustype { isa, pci, pcmcia, pc104 }; -// different ways ai data is encoded in first two registers +/* different ways ai data is encoded in first two registers */ enum das08_ai_encoding { das08_encode12, das08_encode16, das08_pcm_encode12 }; enum das08_lrange { das08_pg_none, das08_bipolar5, das08_pgh, das08_pgl, das08_pgm }; struct das08_board_struct { const char *name; - unsigned int id; // id for pci/pcmcia boards + unsigned int id; /* id for pci/pcmcia boards */ enum das08_bustype bustype; void *ai; unsigned int ai_nbits; @@ -45,13 +45,13 @@ struct das08_board_struct { unsigned int do_nchan; unsigned int i8255_offset; unsigned int i8254_offset; - unsigned int iosize; // number of ioports used + unsigned int iosize; /* number of ioports used */ }; struct i8254_struct { - int channels; // available channels. Some could be used internally. - int logic2phys[3]; // to know which physical channel is. - int mode[3]; // the index is the real counter. + int channels; /* available channels. Some could be used internally. */ + int logic2phys[3]; /* to know which physical channel is. */ + int mode[3]; /* the index is the real counter. */ unsigned int iobase; }; @@ -61,18 +61,18 @@ struct i8254_struct { #define I8254_CTRL 3 struct das08_private_struct { - unsigned int do_mux_bits; // bits for do/mux register on boards without seperate do register - unsigned int do_bits; // bits for do register on boards with register dedicated to digital out only + unsigned int do_mux_bits; /* bits for do/mux register on boards without seperate do register */ + unsigned int do_bits; /* bits for do register on boards with register dedicated to digital out only */ const unsigned int *pg_gainlist; - struct pci_dev *pdev; // struct for pci-das08 - unsigned int pci_iobase; // additional base address for pci-das08 + struct pci_dev *pdev; /* struct for pci-das08 */ + unsigned int pci_iobase; /* additional base address for pci-das08 */ struct i8254_struct i8254; }; #define NUM_DAS08_CS_BOARDS 2 extern struct das08_board_struct das08_cs_boards[NUM_DAS08_CS_BOARDS]; -int das08_common_attach(struct comedi_device * dev, unsigned long iobase); -int das08_common_detach(struct comedi_device * dev); +int das08_common_attach(struct comedi_device *dev, unsigned long iobase); +int das08_common_detach(struct comedi_device *dev); #endif /* _DAS08_H */ diff --git a/drivers/staging/comedi/drivers/das08_cs.c b/drivers/staging/comedi/drivers/das08_cs.c index be6c88788c4b..8e4464100e1e 100644 --- a/drivers/staging/comedi/drivers/das08_cs.c +++ b/drivers/staging/comedi/drivers/das08_cs.c @@ -46,7 +46,7 @@ Command support does not exist, but could be added for this board. #include "das08.h" -// pcmcia includes +/* pcmcia includes */ #include #include #include @@ -56,30 +56,31 @@ static struct pcmcia_device *cur_dev = NULL; #define thisboard ((const struct das08_board_struct *)dev->board_ptr) -static int das08_cs_attach(struct comedi_device * dev, struct comedi_devconfig * it); +static int das08_cs_attach(struct comedi_device *dev, struct comedi_devconfig *it); static struct comedi_driver driver_das08_cs = { - driver_name:"das08_cs", - module:THIS_MODULE, - attach:das08_cs_attach, - detach:das08_common_detach, - board_name:&das08_cs_boards[0].name, - num_names:sizeof(das08_cs_boards) / + .driver_name = "das08_cs", + .module = THIS_MODULE, + .attach = das08_cs_attach, + .detach = das08_common_detach, + .board_name = &das08_cs_boards[0].name, + .num_names = sizeof(das08_cs_boards) / sizeof(struct das08_board_struct), - offset:sizeof(struct das08_board_struct), + .offset = sizeof(struct das08_board_struct), }; -static int das08_cs_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int das08_cs_attach(struct comedi_device *dev, struct comedi_devconfig *it) { int ret; unsigned long iobase; - struct pcmcia_device *link = cur_dev; // XXX hack + struct pcmcia_device *link = cur_dev; /* XXX hack */ - if ((ret = alloc_private(dev, sizeof(struct das08_private_struct))) < 0) + ret = alloc_private(dev, sizeof(struct das08_private_struct)); + if (ret < 0) return ret; printk("comedi%d: das08_cs: ", dev->minor); - // deal with a pci board + /* deal with a pci board */ if (thisboard->bustype == pcmcia) { if (link == NULL) { @@ -264,14 +265,23 @@ static void das08_pcmcia_config(struct pcmcia_device *link) tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; last_fn = GetFirstTuple; - if ((last_ret = pcmcia_get_first_tuple(link, &tuple)) != 0) + + last_ret = pcmcia_get_first_tuple(link, &tuple); + if (last_ret) goto cs_failed; + last_fn = GetTupleData; - if ((last_ret = pcmcia_get_tuple_data(link, &tuple)) != 0) + + last_ret = pcmcia_get_tuple_data(link, &tuple); + if (last_ret) goto cs_failed; + last_fn = ParseTuple; - if ((last_ret = pcmcia_parse_tuple(&tuple, &parse)) != 0) + + last_ret = pcmcia_parse_tuple(&tuple, &parse); + if (last_ret) goto cs_failed; + link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; @@ -289,13 +299,20 @@ static void das08_pcmcia_config(struct pcmcia_device *link) */ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; last_fn = GetFirstTuple; - if ((last_ret = pcmcia_get_first_tuple(link, &tuple)) != 0) + + last_ret = pcmcia_get_first_tuple(link, &tuple); + if (last_ret) goto cs_failed; + while (1) { cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); - if ((last_ret = pcmcia_get_tuple_data(link, &tuple)) != 0) + + last_ret = pcmcia_get_tuple_data(link, &tuple); + if (last_ret) goto next_entry; - if ((last_ret = pcmcia_parse_tuple(&tuple, &parse)) != 0) + + last_ret = pcmcia_parse_tuple(&tuple, &parse); + if (last_ret) goto next_entry; if (cfg->flags & CISTPL_CFTABLE_DEFAULT) @@ -341,13 +358,16 @@ static void das08_pcmcia_config(struct pcmcia_device *link) next_entry: last_fn = GetNextTuple; - if ((last_ret = pcmcia_get_next_tuple(link, &tuple)) != 0) + + last_ret = pcmcia_get_next_tuple(link, &tuple); + if (last_ret) goto cs_failed; } if (link->conf.Attributes & CONF_ENABLE_IRQ) { last_fn = RequestIRQ; - if ((last_ret = pcmcia_request_irq(link, &link->irq)) != 0) + last_ret = pcmcia_request_irq(link, &link->irq); + if (last_ret) goto cs_failed; } @@ -357,7 +377,8 @@ static void das08_pcmcia_config(struct pcmcia_device *link) card and host interface into "Memory and IO" mode. */ last_fn = RequestConfiguration; - if ((last_ret = pcmcia_request_configuration(link, &link->conf)) != 0) + last_ret = pcmcia_request_configuration(link, &link->conf); + if (last_ret) goto cs_failed; /* diff --git a/drivers/staging/comedi/drivers/das16.c b/drivers/staging/comedi/drivers/das16.c index 6b6b042099de..59af86a8bbfb 100644 --- a/drivers/staging/comedi/drivers/das16.c +++ b/drivers/staging/comedi/drivers/das16.c @@ -79,6 +79,7 @@ Computer boards manuals also available from their website www.measurementcomputi */ #include +#include #include #include "../comedidev.h" @@ -87,16 +88,16 @@ Computer boards manuals also available from their website www.measurementcomputi #include "comedi_fc.h" #undef DEBUG -//#define DEBUG +/* #define DEBUG */ #ifdef DEBUG -#define DEBUG_PRINT(format, args...) rt_printk("das16: " format, ## args) +#define DEBUG_PRINT(format, args...) printk("das16: " format, ## args) #else #define DEBUG_PRINT(format, args...) #endif -#define DAS16_SIZE 20 // number of ioports -#define DAS16_DMA_SIZE 0xff00 // size in bytes of allocated dma buffer +#define DAS16_SIZE 20 /* number of ioports */ +#define DAS16_DMA_SIZE 0xff00 /* size in bytes of allocated dma buffer */ /* cio-das16.pdf @@ -184,7 +185,7 @@ Computer boards manuals also available from their website www.measurementcomputi */ -static const int sample_size = 2; // size in bytes of a sample from board +static const int sample_size = 2; /* size in bytes of a sample from board */ #define DAS16_TRIG 0 #define DAS16_AI_LSB 0 @@ -265,7 +266,7 @@ static const struct comedi_lrange range_das1x02_unip = { 4, { } }; static const struct comedi_lrange range_das16jr = { 9, { - // also used by 16/330 + /* also used by 16/330 */ BIP_RANGE(10), BIP_RANGE(5), BIP_RANGE(2.5), @@ -326,40 +327,40 @@ struct munge_info { unsigned have_byte:1; }; -static int das16_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int das16_do_wbits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int das16_di_rbits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int das16_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); +static int das16_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int das16_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int das16_di_rbits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int das16_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); -static int das16_cmd_test(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd); -static int das16_cmd_exec(struct comedi_device * dev, struct comedi_subdevice * s); -static int das16_cancel(struct comedi_device * dev, struct comedi_subdevice * s); -static void das16_ai_munge(struct comedi_device * dev, struct comedi_subdevice * s, +static int das16_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd); +static int das16_cmd_exec(struct comedi_device *dev, struct comedi_subdevice *s); +static int das16_cancel(struct comedi_device *dev, struct comedi_subdevice *s); +static void das16_ai_munge(struct comedi_device *dev, struct comedi_subdevice *s, void *array, unsigned int num_bytes, unsigned int start_chan_index); -static void das16_reset(struct comedi_device * dev); -static irqreturn_t das16_dma_interrupt(int irq, void *d PT_REGS_ARG); +static void das16_reset(struct comedi_device *dev); +static irqreturn_t das16_dma_interrupt(int irq, void *d); static void das16_timer_interrupt(unsigned long arg); -static void das16_interrupt(struct comedi_device * dev); +static void das16_interrupt(struct comedi_device *dev); -static unsigned int das16_set_pacer(struct comedi_device * dev, unsigned int ns, +static unsigned int das16_set_pacer(struct comedi_device *dev, unsigned int ns, int flags); -static int das1600_mode_detect(struct comedi_device * dev); -static unsigned int das16_suggest_transfer_size(struct comedi_device * dev, +static int das1600_mode_detect(struct comedi_device *dev); +static unsigned int das16_suggest_transfer_size(struct comedi_device *dev, struct comedi_cmd cmd); -static void reg_dump(struct comedi_device * dev); +static void reg_dump(struct comedi_device *dev); struct das16_board { const char *name; void *ai; unsigned int ai_nbits; - unsigned int ai_speed; // max conversion speed in nanosec + unsigned int ai_speed; /* max conversion speed in nanosec */ unsigned int ai_pg; void *ao; unsigned int ao_nbits; @@ -375,339 +376,337 @@ struct das16_board { static const struct das16_board das16_boards[] = { { - name: "das-16", - ai: das16_ai_rinsn, - ai_nbits:12, - ai_speed:15000, - ai_pg: das16_pg_none, - ao: das16_ao_winsn, - ao_nbits:12, - di: das16_di_rbits, - do_: das16_do_wbits, - i8255_offset:0x10, - i8254_offset:0x0c, - size: 0x14, - id: 0x00, + .name = "das-16", + .ai = das16_ai_rinsn, + .ai_nbits = 12, + .ai_speed = 15000, + .ai_pg = das16_pg_none, + .ao = das16_ao_winsn, + .ao_nbits = 12, + .di = das16_di_rbits, + .do_ = das16_do_wbits, + .i8255_offset = 0x10, + .i8254_offset = 0x0c, + .size = 0x14, + .id = 0x00, }, { - name: "das-16g", - ai: das16_ai_rinsn, - ai_nbits:12, - ai_speed:15000, - ai_pg: das16_pg_none, - ao: das16_ao_winsn, - ao_nbits:12, - di: das16_di_rbits, - do_: das16_do_wbits, - i8255_offset:0x10, - i8254_offset:0x0c, - size: 0x14, - id: 0x00, + .name = "das-16g", + .ai = das16_ai_rinsn, + .ai_nbits = 12, + .ai_speed = 15000, + .ai_pg = das16_pg_none, + .ao = das16_ao_winsn, + .ao_nbits = 12, + .di = das16_di_rbits, + .do_ = das16_do_wbits, + .i8255_offset = 0x10, + .i8254_offset = 0x0c, + .size = 0x14, + .id = 0x00, }, { - name: "das-16f", - ai: das16_ai_rinsn, - ai_nbits:12, - ai_speed:8500, - ai_pg: das16_pg_none, - ao: das16_ao_winsn, - ao_nbits:12, - di: das16_di_rbits, - do_: das16_do_wbits, - i8255_offset:0x10, - i8254_offset:0x0c, - size: 0x14, - id: 0x00, + .name = "das-16f", + .ai = das16_ai_rinsn, + .ai_nbits = 12, + .ai_speed = 8500, + .ai_pg = das16_pg_none, + .ao = das16_ao_winsn, + .ao_nbits = 12, + .di = das16_di_rbits, + .do_ = das16_do_wbits, + .i8255_offset = 0x10, + .i8254_offset = 0x0c, + .size = 0x14, + .id = 0x00, }, { - name: "cio-das16", // cio-das16.pdf - ai: das16_ai_rinsn, - ai_nbits:12, - ai_speed:20000, - ai_pg: das16_pg_none, - ao: das16_ao_winsn, - ao_nbits:12, - di: das16_di_rbits, - do_: das16_do_wbits, - i8255_offset:0x10, - i8254_offset:0x0c, - size: 0x14, - id: 0x80, + .name = "cio-das16", /* cio-das16.pdf */ + .ai = das16_ai_rinsn, + .ai_nbits = 12, + .ai_speed = 20000, + .ai_pg = das16_pg_none, + .ao = das16_ao_winsn, + .ao_nbits = 12, + .di = das16_di_rbits, + .do_ = das16_do_wbits, + .i8255_offset = 0x10, + .i8254_offset = 0x0c, + .size = 0x14, + .id = 0x80, }, { - name: "cio-das16/f", // das16.pdf - ai: das16_ai_rinsn, - ai_nbits:12, - ai_speed:10000, - ai_pg: das16_pg_none, - ao: das16_ao_winsn, - ao_nbits:12, - di: das16_di_rbits, - do_: das16_do_wbits, - i8255_offset:0x10, - i8254_offset:0x0c, - size: 0x14, - id: 0x80, + .name = "cio-das16/f", /* das16.pdf */ + .ai = das16_ai_rinsn, + .ai_nbits = 12, + .ai_speed = 10000, + .ai_pg = das16_pg_none, + .ao = das16_ao_winsn, + .ao_nbits = 12, + .di = das16_di_rbits, + .do_ = das16_do_wbits, + .i8255_offset = 0x10, + .i8254_offset = 0x0c, + .size = 0x14, + .id = 0x80, }, { - name: "cio-das16/jr", // cio-das16jr.pdf - ai: das16_ai_rinsn, - ai_nbits:12, - ai_speed:7692, - ai_pg: das16_pg_16jr, - ao: NULL, - di: das16_di_rbits, - do_: das16_do_wbits, - i8255_offset:0, - i8254_offset:0x0c, - size: 0x10, - id: 0x00, + .name = "cio-das16/jr", /* cio-das16jr.pdf */ + .ai = das16_ai_rinsn, + .ai_nbits = 12, + .ai_speed = 7692, + .ai_pg = das16_pg_16jr, + .ao = NULL, + .di = das16_di_rbits, + .do_ = das16_do_wbits, + .i8255_offset = 0, + .i8254_offset = 0x0c, + .size = 0x10, + .id = 0x00, }, { - name: "pc104-das16jr", // pc104-das16jr_xx.pdf - ai: das16_ai_rinsn, - ai_nbits:12, - ai_speed:3300, - ai_pg: das16_pg_16jr, - ao: NULL, - di: das16_di_rbits, - do_: das16_do_wbits, - i8255_offset:0, - i8254_offset:0x0c, - size: 0x10, - id: 0x00, + .name = "pc104-das16jr", /* pc104-das16jr_xx.pdf */ + .ai = das16_ai_rinsn, + .ai_nbits = 12, + .ai_speed = 3300, + .ai_pg = das16_pg_16jr, + .ao = NULL, + .di = das16_di_rbits, + .do_ = das16_do_wbits, + .i8255_offset = 0, + .i8254_offset = 0x0c, + .size = 0x10, + .id = 0x00, }, { - name: "cio-das16jr/16", // cio-das16jr_16.pdf - ai: das16_ai_rinsn, - ai_nbits:16, - ai_speed:10000, - ai_pg: das16_pg_16jr_16, - ao: NULL, - di: das16_di_rbits, - do_: das16_do_wbits, - i8255_offset:0, - i8254_offset:0x0c, - size: 0x10, - id: 0x00, + .name = "cio-das16jr/16", /* cio-das16jr_16.pdf */ + .ai = das16_ai_rinsn, + .ai_nbits = 16, + .ai_speed = 10000, + .ai_pg = das16_pg_16jr_16, + .ao = NULL, + .di = das16_di_rbits, + .do_ = das16_do_wbits, + .i8255_offset = 0, + .i8254_offset = 0x0c, + .size = 0x10, + .id = 0x00, }, { - name: "pc104-das16jr/16", // pc104-das16jr_xx.pdf - ai: das16_ai_rinsn, - ai_nbits:16, - ai_speed:10000, - ai_pg: das16_pg_16jr_16, - ao: NULL, - di: das16_di_rbits, - do_: das16_do_wbits, - i8255_offset:0, - i8254_offset:0x0c, - size: 0x10, - id: 0x00, + .name = "pc104-das16jr/16", /* pc104-das16jr_xx.pdf */ + .ai = das16_ai_rinsn, + .ai_nbits = 16, + .ai_speed = 10000, + .ai_pg = das16_pg_16jr_16, + .ao = NULL, + .di = das16_di_rbits, + .do_ = das16_do_wbits, + .i8255_offset = 0, + .i8254_offset = 0x0c, + .size = 0x10, + .id = 0x00, }, { - name: "das-1201", // 4924.pdf (keithley user's manual) - ai: das16_ai_rinsn, - ai_nbits:12, - ai_speed:20000, - ai_pg: das16_pg_none, - ao: NULL, - di: das16_di_rbits, - do_: das16_do_wbits, - i8255_offset:0x400, - i8254_offset:0x0c, - size: 0x408, - id: 0x20, + .name = "das-1201", /* 4924.pdf (keithley user's manual) */ + .ai = das16_ai_rinsn, + .ai_nbits = 12, + .ai_speed = 20000, + .ai_pg = das16_pg_none, + .ao = NULL, + .di = das16_di_rbits, + .do_ = das16_do_wbits, + .i8255_offset = 0x400, + .i8254_offset = 0x0c, + .size = 0x408, + .id = 0x20, }, { - name: "das-1202", // 4924.pdf (keithley user's manual) - ai: das16_ai_rinsn, - ai_nbits:12, - ai_speed:10000, - ai_pg: das16_pg_none, - ao: NULL, - di: das16_di_rbits, - do_: das16_do_wbits, - i8255_offset:0x400, - i8254_offset:0x0c, - size: 0x408, - id: 0x20, + .name = "das-1202", /* 4924.pdf (keithley user's manual) */ + .ai = das16_ai_rinsn, + .ai_nbits = 12, + .ai_speed = 10000, + .ai_pg = das16_pg_none, + .ao = NULL, + .di = das16_di_rbits, + .do_ = das16_do_wbits, + .i8255_offset = 0x400, + .i8254_offset = 0x0c, + .size = 0x408, + .id = 0x20, }, { - name: "das-1401", // 4919.pdf and 4922.pdf (keithley user's manual) - ai: das16_ai_rinsn, - ai_nbits:12, - ai_speed:10000, - ai_pg: das16_pg_1601, - ao: NULL, - di: das16_di_rbits, - do_: das16_do_wbits, - i8255_offset:0x0, - i8254_offset:0x0c, - size: 0x408, - id: 0xc0 // 4919.pdf says id bits are 0xe0, 4922.pdf says 0xc0 + .name = "das-1401", /* 4919.pdf and 4922.pdf (keithley user's manual) */ + .ai = das16_ai_rinsn, + .ai_nbits = 12, + .ai_speed = 10000, + .ai_pg = das16_pg_1601, + .ao = NULL, + .di = das16_di_rbits, + .do_ = das16_do_wbits, + .i8255_offset = 0x0, + .i8254_offset = 0x0c, + .size = 0x408, + .id = 0xc0 /* 4919.pdf says id bits are 0xe0, 4922.pdf says 0xc0 */ }, { - name: "das-1402", // 4919.pdf and 4922.pdf (keithley user's manual) - ai: das16_ai_rinsn, - ai_nbits:12, - ai_speed:10000, - ai_pg: das16_pg_1602, - ao: NULL, - di: das16_di_rbits, - do_: das16_do_wbits, - i8255_offset:0x0, - i8254_offset:0x0c, - size: 0x408, - id: 0xc0 // 4919.pdf says id bits are 0xe0, 4922.pdf says 0xc0 + .name = "das-1402", /* 4919.pdf and 4922.pdf (keithley user's manual) */ + .ai = das16_ai_rinsn, + .ai_nbits = 12, + .ai_speed = 10000, + .ai_pg = das16_pg_1602, + .ao = NULL, + .di = das16_di_rbits, + .do_ = das16_do_wbits, + .i8255_offset = 0x0, + .i8254_offset = 0x0c, + .size = 0x408, + .id = 0xc0 /* 4919.pdf says id bits are 0xe0, 4922.pdf says 0xc0 */ }, { - name: "das-1601", // 4919.pdf - ai: das16_ai_rinsn, - ai_nbits:12, - ai_speed:10000, - ai_pg: das16_pg_1601, - ao: das16_ao_winsn, - ao_nbits:12, - di: das16_di_rbits, - do_: das16_do_wbits, - i8255_offset:0x400, - i8254_offset:0x0c, - size: 0x408, - id: 0xc0}, + .name = "das-1601", /* 4919.pdf */ + .ai = das16_ai_rinsn, + .ai_nbits = 12, + .ai_speed = 10000, + .ai_pg = das16_pg_1601, + .ao = das16_ao_winsn, + .ao_nbits = 12, + .di = das16_di_rbits, + .do_ = das16_do_wbits, + .i8255_offset = 0x400, + .i8254_offset = 0x0c, + .size = 0x408, + .id = 0xc0}, { - name: "das-1602", // 4919.pdf - ai: das16_ai_rinsn, - ai_nbits:12, - ai_speed:10000, - ai_pg: das16_pg_1602, - ao: das16_ao_winsn, - ao_nbits:12, - di: das16_di_rbits, - do_: das16_do_wbits, - i8255_offset:0x400, - i8254_offset:0x0c, - size: 0x408, - id: 0xc0}, + .name = "das-1602", /* 4919.pdf */ + .ai = das16_ai_rinsn, + .ai_nbits = 12, + .ai_speed = 10000, + .ai_pg = das16_pg_1602, + .ao = das16_ao_winsn, + .ao_nbits = 12, + .di = das16_di_rbits, + .do_ = das16_do_wbits, + .i8255_offset = 0x400, + .i8254_offset = 0x0c, + .size = 0x408, + .id = 0xc0}, { - name: "cio-das1401/12", // cio-das1400_series.pdf - ai: das16_ai_rinsn, - ai_nbits:12, - ai_speed:6250, - ai_pg: das16_pg_1601, - ao: NULL, - di: das16_di_rbits, - do_: das16_do_wbits, - i8255_offset:0, - i8254_offset:0x0c, - size: 0x408, - id: 0xc0}, + .name = "cio-das1401/12", /* cio-das1400_series.pdf */ + .ai = das16_ai_rinsn, + .ai_nbits = 12, + .ai_speed = 6250, + .ai_pg = das16_pg_1601, + .ao = NULL, + .di = das16_di_rbits, + .do_ = das16_do_wbits, + .i8255_offset = 0, + .i8254_offset = 0x0c, + .size = 0x408, + .id = 0xc0}, { - name: "cio-das1402/12", // cio-das1400_series.pdf - ai: das16_ai_rinsn, - ai_nbits:12, - ai_speed:6250, - ai_pg: das16_pg_1602, - ao: NULL, - di: das16_di_rbits, - do_: das16_do_wbits, - i8255_offset:0, - i8254_offset:0x0c, - size: 0x408, - id: 0xc0}, + .name = "cio-das1402/12", /* cio-das1400_series.pdf */ + .ai = das16_ai_rinsn, + .ai_nbits = 12, + .ai_speed = 6250, + .ai_pg = das16_pg_1602, + .ao = NULL, + .di = das16_di_rbits, + .do_ = das16_do_wbits, + .i8255_offset = 0, + .i8254_offset = 0x0c, + .size = 0x408, + .id = 0xc0}, { - name: "cio-das1402/16", // cio-das1400_series.pdf - ai: das16_ai_rinsn, - ai_nbits:16, - ai_speed:10000, - ai_pg: das16_pg_1602, - ao: NULL, - di: das16_di_rbits, - do_: das16_do_wbits, - i8255_offset:0, - i8254_offset:0x0c, - size: 0x408, - id: 0xc0}, + .name = "cio-das1402/16", /* cio-das1400_series.pdf */ + .ai = das16_ai_rinsn, + .ai_nbits = 16, + .ai_speed = 10000, + .ai_pg = das16_pg_1602, + .ao = NULL, + .di = das16_di_rbits, + .do_ = das16_do_wbits, + .i8255_offset = 0, + .i8254_offset = 0x0c, + .size = 0x408, + .id = 0xc0}, { - name: "cio-das1601/12", // cio-das160x-1x.pdf - ai: das16_ai_rinsn, - ai_nbits:12, - ai_speed:6250, - ai_pg: das16_pg_1601, - ao: das16_ao_winsn, - ao_nbits:12, - di: das16_di_rbits, - do_: das16_do_wbits, - i8255_offset:0x400, - i8254_offset:0x0c, - size: 0x408, - id: 0xc0}, + .name = "cio-das1601/12", /* cio-das160x-1x.pdf */ + .ai = das16_ai_rinsn, + .ai_nbits = 12, + .ai_speed = 6250, + .ai_pg = das16_pg_1601, + .ao = das16_ao_winsn, + .ao_nbits = 12, + .di = das16_di_rbits, + .do_ = das16_do_wbits, + .i8255_offset = 0x400, + .i8254_offset = 0x0c, + .size = 0x408, + .id = 0xc0}, { - name: "cio-das1602/12", // cio-das160x-1x.pdf - ai: das16_ai_rinsn, - ai_nbits:12, - ai_speed:10000, - ai_pg: das16_pg_1602, - ao: das16_ao_winsn, - ao_nbits:12, - di: das16_di_rbits, - do_: das16_do_wbits, - i8255_offset:0x400, - i8254_offset:0x0c, - size: 0x408, - id: 0xc0}, + .name = "cio-das1602/12", /* cio-das160x-1x.pdf */ + .ai = das16_ai_rinsn, + .ai_nbits = 12, + .ai_speed = 10000, + .ai_pg = das16_pg_1602, + .ao = das16_ao_winsn, + .ao_nbits = 12, + .di = das16_di_rbits, + .do_ = das16_do_wbits, + .i8255_offset = 0x400, + .i8254_offset = 0x0c, + .size = 0x408, + .id = 0xc0}, { - name: "cio-das1602/16", // cio-das160x-1x.pdf - ai: das16_ai_rinsn, - ai_nbits:16, - ai_speed:10000, - ai_pg: das16_pg_1602, - ao: das16_ao_winsn, - ao_nbits:12, - di: das16_di_rbits, - do_: das16_do_wbits, - i8255_offset:0x400, - i8254_offset:0x0c, - size: 0x408, - id: 0xc0}, + .name = "cio-das1602/16", /* cio-das160x-1x.pdf */ + .ai = das16_ai_rinsn, + .ai_nbits = 16, + .ai_speed = 10000, + .ai_pg = das16_pg_1602, + .ao = das16_ao_winsn, + .ao_nbits = 12, + .di = das16_di_rbits, + .do_ = das16_do_wbits, + .i8255_offset = 0x400, + .i8254_offset = 0x0c, + .size = 0x408, + .id = 0xc0}, { - name: "cio-das16/330", // ? - ai: das16_ai_rinsn, - ai_nbits:12, - ai_speed:3030, - ai_pg: das16_pg_16jr, - ao: NULL, - di: das16_di_rbits, - do_: das16_do_wbits, - i8255_offset:0, - i8254_offset:0x0c, - size: 0x14, - id: 0xf0}, + .name = "cio-das16/330", /* ? */ + .ai = das16_ai_rinsn, + .ai_nbits = 12, + .ai_speed = 3030, + .ai_pg = das16_pg_16jr, + .ao = NULL, + .di = das16_di_rbits, + .do_ = das16_do_wbits, + .i8255_offset = 0, + .i8254_offset = 0x0c, + .size = 0x14, + .id = 0xf0}, #if 0 { - name: "das16/330i", // ? + .name = "das16/330i", /* ? */ }, { - name: "das16/jr/ctr5", // ? + .name = "das16/jr/ctr5", /* ? */ }, { - name: "cio-das16/m1/16", // cio-das16_m1_16.pdf, this board is a bit quirky, no dma + .name = "cio-das16/m1/16", /* cio-das16_m1_16.pdf, this board is a bit quirky, no dma */ }, #endif }; -#define n_das16_boards ((sizeof(das16_boards))/(sizeof(struct das16_board))) - -static int das16_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int das16_detach(struct comedi_device * dev); +static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int das16_detach(struct comedi_device *dev); static struct comedi_driver driver_das16 = { - driver_name:"das16", - module:THIS_MODULE, - attach:das16_attach, - detach:das16_detach, - board_name:&das16_boards[0].name, - num_names:n_das16_boards, - offset:sizeof(das16_boards[0]), + .driver_name = "das16", + .module = THIS_MODULE, + .attach = das16_attach, + .detach = das16_detach, + .board_name = &das16_boards[0].name, + .num_names = ARRAY_SIZE(das16_boards), + .offset = sizeof(das16_boards[0]), }; #define DAS16_TIMEOUT 1000 @@ -719,31 +718,31 @@ static inline int timer_period(void) return HZ / 20; } struct das16_private_struct { - unsigned int ai_unipolar; // unipolar flag - unsigned int ai_singleended; // single ended flag - unsigned int clockbase; // master clock speed in ns - volatile unsigned int control_state; // dma, interrupt and trigger control bits - volatile unsigned long adc_byte_count; // number of bytes remaining - unsigned int divisor1; // divisor dividing master clock to get conversion frequency - unsigned int divisor2; // divisor dividing master clock to get conversion frequency - unsigned int dma_chan; // dma channel + unsigned int ai_unipolar; /* unipolar flag */ + unsigned int ai_singleended; /* single ended flag */ + unsigned int clockbase; /* master clock speed in ns */ + volatile unsigned int control_state; /* dma, interrupt and trigger control bits */ + volatile unsigned long adc_byte_count; /* number of bytes remaining */ + unsigned int divisor1; /* divisor dividing master clock to get conversion frequency */ + unsigned int divisor2; /* divisor dividing master clock to get conversion frequency */ + unsigned int dma_chan; /* dma channel */ uint16_t *dma_buffer[2]; dma_addr_t dma_buffer_addr[2]; unsigned int current_buffer; - volatile unsigned int dma_transfer_size; // target number of bytes to transfer per dma shot - // user-defined analog input and output ranges defined from config options + volatile unsigned int dma_transfer_size; /* target number of bytes to transfer per dma shot */ + /* user-defined analog input and output ranges defined from config options */ struct comedi_lrange *user_ai_range_table; struct comedi_lrange *user_ao_range_table; - struct timer_list timer; // for timed interrupt + struct timer_list timer; /* for timed interrupt */ volatile short timer_running; - volatile short timer_mode; // true if using timer mode + volatile short timer_mode; /* true if using timer mode */ }; #define devpriv ((struct das16_private_struct *)(dev->private)) #define thisboard ((struct das16_board *)(dev->board_ptr)) -static int das16_cmd_test(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd) +static int das16_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd) { int err = 0, tmp; int gain, start_chan, i; @@ -757,7 +756,7 @@ static int das16_cmd_test(struct comedi_device * dev, struct comedi_subdevice * tmp = cmd->scan_begin_src; mask = TRIG_FOLLOW; - // if board supports burst mode + /* if board supports burst mode */ if (thisboard->size > 0x400) mask |= TRIG_TIMER | TRIG_EXT; cmd->scan_begin_src &= mask; @@ -766,7 +765,7 @@ static int das16_cmd_test(struct comedi_device * dev, struct comedi_subdevice * tmp = cmd->convert_src; mask = TRIG_TIMER | TRIG_EXT; - // if board supports burst mode + /* if board supports burst mode */ if (thisboard->size > 0x400) mask |= TRIG_NOW; cmd->convert_src &= mask; @@ -797,7 +796,7 @@ static int das16_cmd_test(struct comedi_device * dev, struct comedi_subdevice * if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT) err++; - // make sure scan_begin_src and convert_src dont conflict + /* make sure scan_begin_src and convert_src dont conflict */ if (cmd->scan_begin_src == TRIG_FOLLOW && cmd->convert_src == TRIG_NOW) err++; if (cmd->scan_begin_src != TRIG_FOLLOW && cmd->convert_src != TRIG_NOW) @@ -824,7 +823,7 @@ static int das16_cmd_test(struct comedi_device * dev, struct comedi_subdevice * cmd->scan_end_arg = cmd->chanlist_len; err++; } - // check against maximum frequency + /* check against maximum frequency */ if (cmd->scan_begin_src == TRIG_TIMER) { if (cmd->scan_begin_arg < thisboard->ai_speed * cmd->chanlist_len) { @@ -849,10 +848,10 @@ static int das16_cmd_test(struct comedi_device * dev, struct comedi_subdevice * if (err) return 3; - // step 4: fix up arguments + /* step 4: fix up arguments */ if (cmd->scan_begin_src == TRIG_TIMER) { unsigned int tmp = cmd->scan_begin_arg; - // set divisors, correct timing arguments + /* set divisors, correct timing arguments */ i8253_cascade_ns_to_timer_2div(devpriv->clockbase, &(devpriv->divisor1), &(devpriv->divisor2), &(cmd->scan_begin_arg), cmd->flags & TRIG_ROUND_MASK); @@ -860,7 +859,7 @@ static int das16_cmd_test(struct comedi_device * dev, struct comedi_subdevice * } if (cmd->convert_src == TRIG_TIMER) { unsigned int tmp = cmd->convert_arg; - // set divisors, correct timing arguments + /* set divisors, correct timing arguments */ i8253_cascade_ns_to_timer_2div(devpriv->clockbase, &(devpriv->divisor1), &(devpriv->divisor2), &(cmd->convert_arg), cmd->flags & TRIG_ROUND_MASK); @@ -869,7 +868,7 @@ static int das16_cmd_test(struct comedi_device * dev, struct comedi_subdevice * if (err) return 4; - // check channel/gain list against card's limitations + /* check channel/gain list against card's limitations */ if (cmd->chanlist) { gain = CR_RANGE(cmd->chanlist[0]); start_chan = CR_CHAN(cmd->chanlist[0]); @@ -893,7 +892,7 @@ static int das16_cmd_test(struct comedi_device * dev, struct comedi_subdevice * return 0; } -static int das16_cmd_exec(struct comedi_device * dev, struct comedi_subdevice * s) +static int das16_cmd_exec(struct comedi_device *dev, struct comedi_subdevice *s) { struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; @@ -916,11 +915,11 @@ static int das16_cmd_exec(struct comedi_device * dev, struct comedi_subdevice * devpriv->adc_byte_count = cmd->stop_arg * cmd->chanlist_len * sizeof(uint16_t); - // disable conversions for das1600 mode + /* disable conversions for das1600 mode */ if (thisboard->size > 0x400) { outb(DAS1600_CONV_DISABLE, dev->iobase + DAS1600_CONV); } - // set scan limits + /* set scan limits */ byte = CR_CHAN(cmd->chanlist[0]); byte |= CR_CHAN(cmd->chanlist[cmd->chanlist_len - 1]) << 4; outb(byte, dev->iobase + DAS16_MUX); @@ -945,7 +944,7 @@ static int das16_cmd_exec(struct comedi_device * dev, struct comedi_subdevice * if (thisboard->size > 0x400) { if (cmd->convert_src == TRIG_NOW) { outb(DAS1600_BURST_VAL, dev->iobase + DAS1600_BURST); - // set burst length + /* set burst length */ byte |= BURST_LEN_BITS(cmd->chanlist_len - 1); } else { outb(0, dev->iobase + DAS1600_BURST); @@ -953,7 +952,7 @@ static int das16_cmd_exec(struct comedi_device * dev, struct comedi_subdevice * } outb(byte, dev->iobase + DAS16_PACER); - // set up dma transfer + /* set up dma transfer */ flags = claim_dma_lock(); disable_dma(devpriv->dma_chan); /* clear flip-flop to make sure 2-byte registers for @@ -962,13 +961,13 @@ static int das16_cmd_exec(struct comedi_device * dev, struct comedi_subdevice * devpriv->current_buffer = 0; set_dma_addr(devpriv->dma_chan, devpriv->dma_buffer_addr[devpriv->current_buffer]); - // set appropriate size of transfer + /* set appropriate size of transfer */ devpriv->dma_transfer_size = das16_suggest_transfer_size(dev, *cmd); set_dma_count(devpriv->dma_chan, devpriv->dma_transfer_size); enable_dma(devpriv->dma_chan); release_dma_lock(flags); - // set up interrupt + /* set up interrupt */ if (devpriv->timer_mode) { devpriv->timer_running = 1; devpriv->timer.expires = jiffies + timer_period(); @@ -996,18 +995,18 @@ static int das16_cmd_exec(struct comedi_device * dev, struct comedi_subdevice * return 0; } -static int das16_cancel(struct comedi_device * dev, struct comedi_subdevice * s) +static int das16_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { unsigned long flags; - comedi_spin_lock_irqsave(&dev->spinlock, flags); + spin_lock_irqsave(&dev->spinlock, flags); /* disable interrupts, dma and pacer clocked conversions */ devpriv->control_state &= ~DAS16_INTE & ~PACING_MASK & ~DMA_ENABLE; outb(devpriv->control_state, dev->iobase + DAS16_CONTROL); if (devpriv->dma_chan) disable_dma(devpriv->dma_chan); - // disable SW timer + /* disable SW timer */ if (devpriv->timer_mode && devpriv->timer_running) { devpriv->timer_running = 0; del_timer(&devpriv->timer); @@ -1018,12 +1017,12 @@ static int das16_cancel(struct comedi_device * dev, struct comedi_subdevice * s) outb(0, dev->iobase + DAS1600_BURST); } - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); return 0; } -static void das16_reset(struct comedi_device * dev) +static void das16_reset(struct comedi_device *dev) { outb(0, dev->iobase + DAS16_STATUS); outb(0, dev->iobase + DAS16_CONTROL); @@ -1031,15 +1030,15 @@ static void das16_reset(struct comedi_device * dev) outb(0, dev->iobase + DAS16_CNTR_CONTROL); } -static int das16_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int das16_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i, n; int range; int chan; int msb, lsb; - // disable interrupts and pacing + /* disable interrupts and pacing */ devpriv->control_state &= ~DAS16_INTE & ~DMA_ENABLE & ~PACING_MASK; outb(devpriv->control_state, dev->iobase + DAS16_CONTROL); @@ -1064,7 +1063,7 @@ static int das16_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * break; } if (i == DAS16_TIMEOUT) { - rt_printk("das16: timeout\n"); + printk("das16: timeout\n"); return -ETIME; } msb = inb(dev->iobase + DAS16_AI_MSB); @@ -1079,8 +1078,8 @@ static int das16_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * return n; } -static int das16_di_rbits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int das16_di_rbits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { unsigned int bits; @@ -1091,17 +1090,17 @@ static int das16_di_rbits(struct comedi_device * dev, struct comedi_subdevice * return 2; } -static int das16_do_wbits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int das16_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { unsigned int wbits; - // only set bits that have been masked + /* only set bits that have been masked */ data[0] &= 0xf; wbits = s->state; - // zero bits that have been masked + /* zero bits that have been masked */ wbits &= ~data[0]; - // set masked bits + /* set masked bits */ wbits |= data[0] & data[1]; s->state = wbits; data[1] = wbits; @@ -1111,8 +1110,8 @@ static int das16_do_wbits(struct comedi_device * dev, struct comedi_subdevice * return 2; } -static int das16_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int das16_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i; int lsb, msb; @@ -1135,7 +1134,7 @@ static int das16_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * return i; } -static irqreturn_t das16_dma_interrupt(int irq, void *d PT_REGS_ARG) +static irqreturn_t das16_dma_interrupt(int irq, void *d) { int status; struct comedi_device *dev = d; @@ -1169,7 +1168,7 @@ static void das16_timer_interrupt(unsigned long arg) an even transfer count after disabling dma channel. */ -static int disable_dma_on_even(struct comedi_device * dev) +static int disable_dma_on_even(struct comedi_device *dev) { int residue; int i; @@ -1182,7 +1181,7 @@ static int disable_dma_on_even(struct comedi_device * dev) enable_dma(devpriv->dma_chan); for (j = 0; j < enable_timeout; ++j) { int new_residue; - comedi_udelay(2); + udelay(2); new_residue = get_dma_residue(devpriv->dma_chan); if (new_residue != residue) break; @@ -1197,7 +1196,7 @@ static int disable_dma_on_even(struct comedi_device * dev) return residue; } -static void das16_interrupt(struct comedi_device * dev) +static void das16_interrupt(struct comedi_device *dev) { unsigned long dma_flags, spin_flags; struct comedi_subdevice *s = dev->read_subdev; @@ -1210,7 +1209,7 @@ static void das16_interrupt(struct comedi_device * dev) comedi_error(dev, "premature interrupt"); return; } - // initialize async here to make sure it is not NULL + /* initialize async here to make sure it is not NULL */ async = s->async; cmd = &async->cmd; @@ -1219,9 +1218,9 @@ static void das16_interrupt(struct comedi_device * dev) return; } - comedi_spin_lock_irqsave(&dev->spinlock, spin_flags); + spin_lock_irqsave(&dev->spinlock, spin_flags); if ((devpriv->control_state & DMA_ENABLE) == 0) { - comedi_spin_unlock_irqrestore(&dev->spinlock, spin_flags); + spin_unlock_irqrestore(&dev->spinlock, spin_flags); DEBUG_PRINT("interrupt while dma disabled?\n"); return; } @@ -1230,7 +1229,7 @@ static void das16_interrupt(struct comedi_device * dev) clear_dma_ff(devpriv->dma_chan); residue = disable_dma_on_even(dev); - // figure out how many points to read + /* figure out how many points to read */ if (residue > devpriv->dma_transfer_size) { comedi_error(dev, "residue > transfer size!\n"); async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; @@ -1247,12 +1246,12 @@ static void das16_interrupt(struct comedi_device * dev) devpriv->current_buffer = (devpriv->current_buffer + 1) % 2; devpriv->adc_byte_count -= num_bytes; - // figure out how many bytes for next transfer + /* figure out how many bytes for next transfer */ if (cmd->stop_src == TRIG_COUNT && devpriv->timer_mode == 0 && devpriv->dma_transfer_size > devpriv->adc_byte_count) devpriv->dma_transfer_size = devpriv->adc_byte_count; - // re-enable dma + /* re-enable dma */ if ((async->events & COMEDI_CB_EOA) == 0) { set_dma_addr(devpriv->dma_chan, devpriv->dma_buffer_addr[devpriv->current_buffer]); @@ -1265,7 +1264,7 @@ static void das16_interrupt(struct comedi_device * dev) } release_dma_lock(dma_flags); - comedi_spin_unlock_irqrestore(&dev->spinlock, spin_flags); + spin_unlock_irqrestore(&dev->spinlock, spin_flags); cfc_write_array_to_buffer(s, devpriv->dma_buffer[buffer_index], num_bytes); @@ -1273,7 +1272,7 @@ static void das16_interrupt(struct comedi_device * dev) cfc_handle_events(dev, s); } -static unsigned int das16_set_pacer(struct comedi_device * dev, unsigned int ns, +static unsigned int das16_set_pacer(struct comedi_device *dev, unsigned int ns, int rounding_flags) { i8253_cascade_ns_to_timer_2div(devpriv->clockbase, &(devpriv->divisor1), @@ -1286,7 +1285,7 @@ static unsigned int das16_set_pacer(struct comedi_device * dev, unsigned int ns, return ns; } -static void reg_dump(struct comedi_device * dev) +static void reg_dump(struct comedi_device *dev) { DEBUG_PRINT("********DAS1600 REGISTER DUMP********\n"); DEBUG_PRINT("DAS16_MUX: %x\n", inb(dev->iobase + DAS16_MUX)); @@ -1304,7 +1303,7 @@ static void reg_dump(struct comedi_device * dev) inb(dev->iobase + DAS1600_STATUS_B)); } -static int das16_probe(struct comedi_device * dev, struct comedi_devconfig * it) +static int das16_probe(struct comedi_device *dev, struct comedi_devconfig *it) { int status; int diobits; @@ -1338,7 +1337,7 @@ static int das16_probe(struct comedi_device * dev, struct comedi_devconfig * it) return 0; } -static int das1600_mode_detect(struct comedi_device * dev) +static int das1600_mode_detect(struct comedi_device *dev) { int status = 0; @@ -1366,7 +1365,7 @@ static int das1600_mode_detect(struct comedi_device * dev) * 3 Clock speed (in MHz) */ -static int das16_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; int ret; @@ -1391,7 +1390,7 @@ static int das16_attach(struct comedi_device * dev, struct comedi_devconfig * it printk("comedi%d: das16:", dev->minor); - // check that clock setting is valid + /* check that clock setting is valid */ if (it->options[3]) { if (it->options[3] != 0 && it->options[3] != 1 && it->options[3] != 10) { @@ -1400,7 +1399,8 @@ static int das16_attach(struct comedi_device * dev, struct comedi_devconfig * it } } - if ((ret = alloc_private(dev, sizeof(struct das16_private_struct))) < 0) + ret = alloc_private(dev, sizeof(struct das16_private_struct)); + if (ret < 0) return ret; if (thisboard->size < 0x400) { @@ -1431,27 +1431,28 @@ static int das16_attach(struct comedi_device * dev, struct comedi_devconfig * it dev->iobase = iobase; - // probe id bits to make sure they are consistent + /* probe id bits to make sure they are consistent */ if (das16_probe(dev, it)) { printk(" id bits do not match selected board, aborting\n"); return -EINVAL; } dev->board_name = thisboard->name; - // get master clock speed + /* get master clock speed */ if (thisboard->size < 0x400) { if (it->options[3]) devpriv->clockbase = 1000 / it->options[3]; else - devpriv->clockbase = 1000; // 1 MHz default + devpriv->clockbase = 1000; /* 1 MHz default */ } else { das1600_mode_detect(dev); } /* now for the irq */ if (irq > 1 && irq < 8) { - if ((ret = comedi_request_irq(irq, das16_dma_interrupt, 0, - "das16", dev)) < 0) + ret = request_irq(irq, das16_dma_interrupt, 0, "das16", dev); + + if (ret < 0) return ret; dev->irq = irq; printk(" ( irq = %u )", irq); @@ -1462,10 +1463,10 @@ static int das16_attach(struct comedi_device * dev, struct comedi_devconfig * it return -EINVAL; } - // initialize dma + /* initialize dma */ dma_chan = it->options[2]; if (dma_chan == 1 || dma_chan == 3) { - // allocate dma buffers + /* allocate dma buffers */ int i; for (i = 0; i < 2; i++) { devpriv->dma_buffer[i] = pci_alloc_consistent(NULL, @@ -1491,27 +1492,27 @@ static int das16_attach(struct comedi_device * dev, struct comedi_devconfig * it return -EINVAL; } - // get any user-defined input range + /* get any user-defined input range */ if (thisboard->ai_pg == das16_pg_none && (it->options[4] || it->options[5])) { - // allocate single-range range table + /* allocate single-range range table */ devpriv->user_ai_range_table = kmalloc(sizeof(struct comedi_lrange) + sizeof(struct comedi_krange), GFP_KERNEL); - // initialize ai range + /* initialize ai range */ devpriv->user_ai_range_table->length = 1; user_ai_range = devpriv->user_ai_range_table->range; user_ai_range->min = it->options[4]; user_ai_range->max = it->options[5]; user_ai_range->flags = UNIT_volt; } - // get any user-defined output range + /* get any user-defined output range */ if (it->options[6] || it->options[7]) { - // allocate single-range range table + /* allocate single-range range table */ devpriv->user_ao_range_table = kmalloc(sizeof(struct comedi_lrange) + sizeof(struct comedi_krange), GFP_KERNEL); - // initialize ao range + /* initialize ao range */ devpriv->user_ao_range_table->length = 1; user_ao_range = devpriv->user_ao_range_table->range; user_ao_range->min = it->options[6]; @@ -1526,7 +1527,8 @@ static int das16_attach(struct comedi_device * dev, struct comedi_devconfig * it } devpriv->timer_mode = timer_mode ? 1 : 0; - if ((ret = alloc_subdevices(dev, 5)) < 0) + ret = alloc_subdevices(dev, 5); + if (ret < 0) return ret; s = dev->subdevices + 0; @@ -1545,7 +1547,7 @@ static int das16_attach(struct comedi_device * dev, struct comedi_devconfig * it s->subdev_flags |= SDF_DIFF; } s->maxdata = (1 << thisboard->ai_nbits) - 1; - if (devpriv->user_ai_range_table) { // user defined ai range + if (devpriv->user_ai_range_table) { /* user defined ai range */ s->range_table = devpriv->user_ai_range_table; } else if (devpriv->ai_unipolar) { s->range_table = das16_ai_uni_lranges[thisboard->ai_pg]; @@ -1568,7 +1570,7 @@ static int das16_attach(struct comedi_device * dev, struct comedi_devconfig * it s->subdev_flags = SDF_WRITABLE; s->n_chan = 2; s->maxdata = (1 << thisboard->ao_nbits) - 1; - if (devpriv->user_ao_range_table) { // user defined ao range + if (devpriv->user_ao_range_table) { /* user defined ao range */ s->range_table = devpriv->user_ao_range_table; } else { s->range_table = &range_unknown; @@ -1600,7 +1602,7 @@ static int das16_attach(struct comedi_device * dev, struct comedi_devconfig * it s->maxdata = 1; s->range_table = &range_digital; s->insn_bits = thisboard->do_; - // initialize digital output lines + /* initialize digital output lines */ outb(s->state, dev->iobase + DAS16_DIO); } else { s->type = COMEDI_SUBD_UNUSED; @@ -1620,7 +1622,7 @@ static int das16_attach(struct comedi_device * dev, struct comedi_devconfig * it devpriv->control_state = DAS16_IRQ(dev->irq); outb(devpriv->control_state, dev->iobase + DAS16_CONTROL); - // turn on das1600 mode if available + /* turn on das1600 mode if available */ if (thisboard->size > 0x400) { outb(DAS1600_ENABLE_VAL, dev->iobase + DAS1600_ENABLE); outb(0, dev->iobase + DAS1600_CONV); @@ -1630,7 +1632,7 @@ static int das16_attach(struct comedi_device * dev, struct comedi_devconfig * it return 0; } -static int das16_detach(struct comedi_device * dev) +static int das16_detach(struct comedi_device *dev) { printk("comedi%d: das16: remove\n", dev->minor); @@ -1656,7 +1658,7 @@ static int das16_detach(struct comedi_device * dev) } if (dev->irq) - comedi_free_irq(dev->irq, dev); + free_irq(dev->irq, dev); if (dev->iobase) { if (thisboard->size < 0x400) { @@ -1673,8 +1675,8 @@ static int das16_detach(struct comedi_device * dev) COMEDI_INITCLEANUP(driver_das16); -// utility function that suggests a dma transfer size in bytes -static unsigned int das16_suggest_transfer_size(struct comedi_device * dev, +/* utility function that suggests a dma transfer size in bytes */ +static unsigned int das16_suggest_transfer_size(struct comedi_device *dev, struct comedi_cmd cmd) { unsigned int size; @@ -1692,18 +1694,18 @@ static unsigned int das16_suggest_transfer_size(struct comedi_device * dev, freq = 1000000000 / cmd.convert_arg; else if (cmd.scan_begin_src == TRIG_TIMER) freq = (1000000000 / cmd.scan_begin_arg) * cmd.chanlist_len; - // return some default value + /* return some default value */ else freq = 0xffffffff; if (cmd.flags & TRIG_WAKE_EOS) { size = sample_size * cmd.chanlist_len; } else { - // make buffer fill in no more than 1/3 second + /* make buffer fill in no more than 1/3 second */ size = (freq / 3) * sample_size; } - // set a minimum and maximum size allowed + /* set a minimum and maximum size allowed */ if (size > DAS16_DMA_SIZE) size = DAS16_DMA_SIZE - DAS16_DMA_SIZE % sample_size; else if (size < sample_size) @@ -1715,7 +1717,7 @@ static unsigned int das16_suggest_transfer_size(struct comedi_device * dev, return size; } -static void das16_ai_munge(struct comedi_device * dev, struct comedi_subdevice * s, +static void das16_ai_munge(struct comedi_device *dev, struct comedi_subdevice *s, void *array, unsigned int num_bytes, unsigned int start_chan_index) { unsigned int i, num_samples = num_bytes / sizeof(short); diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c index 0e423e199ed6..3da8bf47cbf6 100644 --- a/drivers/staging/comedi/drivers/das16m1.c +++ b/drivers/staging/comedi/drivers/das16m1.c @@ -59,6 +59,7 @@ irq can be omitted, although the cmd interface will not work without it. */ #include +#include #include "../comedidev.h" #include "8255.h" @@ -68,9 +69,9 @@ irq can be omitted, although the cmd interface will not work without it. #define DAS16M1_SIZE 16 #define DAS16M1_SIZE2 8 -#define DAS16M1_XTAL 100 //10 MHz master clock +#define DAS16M1_XTAL 100 /* 10 MHz master clock */ -#define FIFO_SIZE 1024 // 1024 sample fifo +#define FIFO_SIZE 1024 /* 1024 sample fifo */ /* CIO-DAS16_M1.pdf @@ -92,7 +93,7 @@ irq can be omitted, although the cmd interface will not work without it. */ -#define DAS16M1_AI 0 // 16-bit wide register +#define DAS16M1_AI 0 /* 16-bit wide register */ #define AI_CHAN(x) ((x) & 0xf) #define DAS16M1_CS 2 #define EXT_TRIG_BIT 0x1 @@ -131,23 +132,23 @@ static const struct comedi_lrange range_das16m1 = { 9, } }; -static int das16m1_do_wbits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int das16m1_di_rbits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int das16m1_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); +static int das16m1_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int das16m1_di_rbits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int das16m1_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); -static int das16m1_cmd_test(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd); -static int das16m1_cmd_exec(struct comedi_device * dev, struct comedi_subdevice * s); -static int das16m1_cancel(struct comedi_device * dev, struct comedi_subdevice * s); +static int das16m1_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd); +static int das16m1_cmd_exec(struct comedi_device *dev, struct comedi_subdevice *s); +static int das16m1_cancel(struct comedi_device *dev, struct comedi_subdevice *s); -static int das16m1_poll(struct comedi_device * dev, struct comedi_subdevice * s); -static irqreturn_t das16m1_interrupt(int irq, void *d PT_REGS_ARG); -static void das16m1_handler(struct comedi_device * dev, unsigned int status); +static int das16m1_poll(struct comedi_device *dev, struct comedi_subdevice *s); +static irqreturn_t das16m1_interrupt(int irq, void *d); +static void das16m1_handler(struct comedi_device *dev, unsigned int status); -static unsigned int das16m1_set_pacer(struct comedi_device * dev, unsigned int ns, +static unsigned int das16m1_set_pacer(struct comedi_device *dev, unsigned int ns, int round_flag); static int das16m1_irq_bits(unsigned int irq); @@ -159,36 +160,34 @@ struct das16m1_board { static const struct das16m1_board das16m1_boards[] = { { - name: "cio-das16/m1", // CIO-DAS16_M1.pdf - ai_speed:1000, // 1MHz max speed + .name = "cio-das16/m1", /* CIO-DAS16_M1.pdf */ + .ai_speed = 1000, /* 1MHz max speed */ }, }; -#define das16m1_num_boards ((sizeof(das16m1_boards)) / (sizeof(das16m1_boards[0]))) - -static int das16m1_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int das16m1_detach(struct comedi_device * dev); +static int das16m1_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int das16m1_detach(struct comedi_device *dev); static struct comedi_driver driver_das16m1 = { - driver_name:"das16m1", - module:THIS_MODULE, - attach:das16m1_attach, - detach:das16m1_detach, - board_name:&das16m1_boards[0].name, - num_names:das16m1_num_boards, - offset:sizeof(das16m1_boards[0]), + .driver_name = "das16m1", + .module = THIS_MODULE, + .attach = das16m1_attach, + .detach = das16m1_detach, + .board_name = &das16m1_boards[0].name, + .num_names = ARRAY_SIZE(das16m1_boards), + .offset = sizeof(das16m1_boards[0]), }; struct das16m1_private_struct { unsigned int control_state; - volatile unsigned int adc_count; // number of samples completed + volatile unsigned int adc_count; /* number of samples completed */ /* initial value in lower half of hardware conversion counter, * needed to keep track of whether new count has been loaded into * counter yet (loaded by first sample conversion) */ u16 initial_hw_count; short ai_buffer[FIFO_SIZE]; - unsigned int do_bits; // saves status of digital output bits - unsigned int divisor1; // divides master clock to obtain conversion speed - unsigned int divisor2; // divides master clock to obtain conversion speed + unsigned int do_bits; /* saves status of digital output bits */ + unsigned int divisor1; /* divides master clock to obtain conversion speed */ + unsigned int divisor2; /* divides master clock to obtain conversion speed */ }; #define devpriv ((struct das16m1_private_struct *)(dev->private)) #define thisboard ((const struct das16m1_board *)(dev->board_ptr)) @@ -200,8 +199,8 @@ static inline short munge_sample(short data) return (data >> 4) & 0xfff; } -static int das16m1_cmd_test(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd) +static int das16m1_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd) { unsigned int err = 0, tmp, i; @@ -299,10 +298,10 @@ static int das16m1_cmd_test(struct comedi_device * dev, struct comedi_subdevice if (err) return 4; - // check chanlist against board's peculiarities + /* check chanlist against board's peculiarities */ if (cmd->chanlist && cmd->chanlist_len > 1) { for (i = 0; i < cmd->chanlist_len; i++) { - // even/odd channels must go into even/odd queue addresses + /* even/odd channels must go into even/odd queue addresses */ if ((i % 2) != (CR_CHAN(cmd->chanlist[i]) % 2)) { comedi_error(dev, "bad chanlist:\n" " even/odd channels must go have even/odd chanlist indices"); @@ -322,7 +321,7 @@ static int das16m1_cmd_test(struct comedi_device * dev, struct comedi_subdevice return 0; } -static int das16m1_cmd_exec(struct comedi_device * dev, struct comedi_subdevice * s) +static int das16m1_cmd_exec(struct comedi_device *dev, struct comedi_subdevice *s) { struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; @@ -337,7 +336,7 @@ static int das16m1_cmd_exec(struct comedi_device * dev, struct comedi_subdevice devpriv->control_state &= ~INTE & ~PACER_MASK; outb(devpriv->control_state, dev->iobase + DAS16M1_INTR_CONTROL); - // set software count + /* set software count */ devpriv->adc_count = 0; /* Initialize lower half of hardware counter, used to determine how * many samples are in fifo. Value doesn't actually load into counter @@ -361,7 +360,7 @@ static int das16m1_cmd_exec(struct comedi_device * dev, struct comedi_subdevice das16m1_set_pacer(dev, cmd->convert_arg, cmd->flags & TRIG_ROUND_MASK); - // set control & status register + /* set control & status register */ byte = 0; /* if we are using external start trigger (also board dislikes having * both start and conversion triggers external simultaneously) */ @@ -385,7 +384,7 @@ static int das16m1_cmd_exec(struct comedi_device * dev, struct comedi_subdevice return 0; } -static int das16m1_cancel(struct comedi_device * dev, struct comedi_subdevice * s) +static int das16m1_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { devpriv->control_state &= ~INTE & ~PACER_MASK; outb(devpriv->control_state, dev->iobase + DAS16M1_INTR_CONTROL); @@ -393,8 +392,8 @@ static int das16m1_cancel(struct comedi_device * dev, struct comedi_subdevice * return 0; } -static int das16m1_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int das16m1_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i, n; int byte; @@ -430,8 +429,8 @@ static int das16m1_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice return n; } -static int das16m1_di_rbits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int das16m1_di_rbits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { unsigned int bits; @@ -442,17 +441,17 @@ static int das16m1_di_rbits(struct comedi_device * dev, struct comedi_subdevice return 2; } -static int das16m1_do_wbits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int das16m1_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { unsigned int wbits; - // only set bits that have been masked + /* only set bits that have been masked */ data[0] &= 0xf; wbits = devpriv->do_bits; - // zero bits that have been masked + /* zero bits that have been masked */ wbits &= ~data[0]; - // set masked bits + /* set masked bits */ wbits |= data[0] & data[1]; devpriv->do_bits = wbits; data[1] = wbits; @@ -462,21 +461,21 @@ static int das16m1_do_wbits(struct comedi_device * dev, struct comedi_subdevice return 2; } -static int das16m1_poll(struct comedi_device * dev, struct comedi_subdevice * s) +static int das16m1_poll(struct comedi_device *dev, struct comedi_subdevice *s) { unsigned long flags; unsigned int status; - // prevent race with interrupt handler - comedi_spin_lock_irqsave(&dev->spinlock, flags); + /* prevent race with interrupt handler */ + spin_lock_irqsave(&dev->spinlock, flags); status = inb(dev->iobase + DAS16M1_CS); das16m1_handler(dev, status); - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); return s->async->buf_write_count - s->async->buf_read_count; } -static irqreturn_t das16m1_interrupt(int irq, void *d PT_REGS_ARG) +static irqreturn_t das16m1_interrupt(int irq, void *d) { int status; struct comedi_device *dev = d; @@ -485,7 +484,7 @@ static irqreturn_t das16m1_interrupt(int irq, void *d PT_REGS_ARG) comedi_error(dev, "premature interrupt"); return IRQ_HANDLED; } - // prevent race with comedi_poll() + /* prevent race with comedi_poll() */ spin_lock(&dev->spinlock); status = inb(dev->iobase + DAS16M1_CS); @@ -505,7 +504,7 @@ static irqreturn_t das16m1_interrupt(int irq, void *d PT_REGS_ARG) return IRQ_HANDLED; } -static void munge_sample_array(short * array, unsigned int num_elements) +static void munge_sample_array(short *array, unsigned int num_elements) { unsigned int i; @@ -514,7 +513,7 @@ static void munge_sample_array(short * array, unsigned int num_elements) } } -static void das16m1_handler(struct comedi_device * dev, unsigned int status) +static void das16m1_handler(struct comedi_device *dev, unsigned int status) { struct comedi_subdevice *s; struct comedi_async *async; @@ -527,7 +526,7 @@ static void das16m1_handler(struct comedi_device * dev, unsigned int status) async->events = 0; cmd = &async->cmd; - // figure out how many samples are in fifo + /* figure out how many samples are in fifo */ hw_counter = i8254_read(dev->iobase + DAS16M1_8254_FIRST, 0, 1); /* make sure hardware counter reading is not bogus due to initial value * not having been loaded yet */ @@ -542,12 +541,12 @@ static void das16m1_handler(struct comedi_device * dev, unsigned int status) * hardware counter. Work it out, and this is what you get. */ num_samples = -hw_counter - devpriv->adc_count; } - // check if we only need some of the points + /* check if we only need some of the points */ if (cmd->stop_src == TRIG_COUNT) { if (num_samples > cmd->stop_arg * cmd->chanlist_len) num_samples = cmd->stop_arg * cmd->chanlist_len; } - // make sure we dont try to get too many points if fifo has overrun + /* make sure we dont try to get too many points if fifo has overrun */ if (num_samples > FIFO_SIZE) num_samples = FIFO_SIZE; insw(dev->iobase, devpriv->ai_buffer, num_samples); @@ -578,7 +577,7 @@ static void das16m1_handler(struct comedi_device * dev, unsigned int status) /* This function takes a time in nanoseconds and sets the * * 2 pacer clocks to the closest frequency possible. It also * * returns the actual sampling period. */ -static unsigned int das16m1_set_pacer(struct comedi_device * dev, unsigned int ns, +static unsigned int das16m1_set_pacer(struct comedi_device *dev, unsigned int ns, int rounding_flags) { i8253_cascade_ns_to_timer_2div(DAS16M1_XTAL, &(devpriv->divisor1), @@ -626,7 +625,7 @@ static int das16m1_irq_bits(unsigned int irq) return -1; break; } - return (ret << 4); + return ret << 4; } /* @@ -635,7 +634,7 @@ static int das16m1_irq_bits(unsigned int irq) * 1 IRQ */ -static int das16m1_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int das16m1_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; int ret; @@ -646,8 +645,8 @@ static int das16m1_attach(struct comedi_device * dev, struct comedi_devconfig * printk("comedi%d: das16m1:", dev->minor); - if ((ret = alloc_private(dev, - sizeof(struct das16m1_private_struct))) < 0) + ret = alloc_private(dev, sizeof(struct das16m1_private_struct)); + if (ret < 0) return ret; dev->board_name = thisboard->name; @@ -669,10 +668,10 @@ static int das16m1_attach(struct comedi_device * dev, struct comedi_devconfig * /* now for the irq */ irq = it->options[1]; - // make sure it is valid + /* make sure it is valid */ if (das16m1_irq_bits(irq) >= 0) { - ret = comedi_request_irq(irq, das16m1_interrupt, 0, - driver_das16m1.driver_name, dev); + ret = request_irq(irq, das16m1_interrupt, 0, + driver_das16m1.driver_name, dev); if (ret < 0) { printk(", irq unavailable\n"); return ret; @@ -687,7 +686,8 @@ static int das16m1_attach(struct comedi_device * dev, struct comedi_devconfig * return -EINVAL; } - if ((ret = alloc_subdevices(dev, 4)) < 0) + ret = alloc_subdevices(dev, 4); + if (ret < 0) return ret; s = dev->subdevices + 0; @@ -728,10 +728,10 @@ static int das16m1_attach(struct comedi_device * dev, struct comedi_devconfig * /* 8255 */ subdev_8255_init(dev, s, NULL, dev->iobase + DAS16M1_82C55); - // disable upper half of hardware conversion counter so it doesn't mess with us + /* disable upper half of hardware conversion counter so it doesn't mess with us */ outb(TOTAL_CLEAR, dev->iobase + DAS16M1_8254_FIRST_CNTRL); - // initialize digital output lines + /* initialize digital output lines */ outb(devpriv->do_bits, dev->iobase + DAS16M1_DIO); /* set the interrupt level */ @@ -744,17 +744,17 @@ static int das16m1_attach(struct comedi_device * dev, struct comedi_devconfig * return 0; } -static int das16m1_detach(struct comedi_device * dev) +static int das16m1_detach(struct comedi_device *dev) { printk("comedi%d: das16m1: remove\n", dev->minor); -// das16m1_reset(dev); +/* das16m1_reset(dev); */ if (dev->subdevices) subdev_8255_cleanup(dev, dev->subdevices + 3); if (dev->irq) - comedi_free_irq(dev->irq, dev); + free_irq(dev->irq, dev); if (dev->iobase) { release_region(dev->iobase, DAS16M1_SIZE); diff --git a/drivers/staging/comedi/drivers/das1800.c b/drivers/staging/comedi/drivers/das1800.c index cd4cd4e6a79b..a3434088c9e6 100644 --- a/drivers/staging/comedi/drivers/das1800.c +++ b/drivers/staging/comedi/drivers/das1800.c @@ -100,6 +100,7 @@ TODO: read insn for analog out */ +#include #include "../comedidev.h" #include @@ -108,12 +109,12 @@ TODO: #include "8253.h" #include "comedi_fc.h" -// misc. defines -#define DAS1800_SIZE 16 //uses 16 io addresses -#define FIFO_SIZE 1024 // 1024 sample fifo -#define TIMER_BASE 200 // 5 Mhz master clock -#define UNIPOLAR 0x4 // bit that determines whether input range is uni/bipolar -#define DMA_BUF_SIZE 0x1ff00 // size in bytes of dma buffers +/* misc. defines */ +#define DAS1800_SIZE 16 /* uses 16 io addresses */ +#define FIFO_SIZE 1024 /* 1024 sample fifo */ +#define TIMER_BASE 200 /* 5 Mhz master clock */ +#define UNIPOLAR 0x4 /* bit that determines whether input range is uni/bipolar */ +#define DMA_BUF_SIZE 0x1ff00 /* size in bytes of dma buffers */ /* Registers for the das1800 */ #define DAS1800_FIFO 0x0 @@ -138,7 +139,7 @@ TODO: #define DMA_CH5_CH6 0x5 #define DMA_CH6_CH7 0x6 #define DMA_CH7_CH5 0x7 -#define DMA_ENABLED 0x3 //mask used to determine if dma is enabled +#define DMA_ENABLED 0x3 /* mask used to determine if dma is enabled */ #define DMA_DUAL 0x4 #define IRQ3 0x8 #define IRQ5 0x10 @@ -156,7 +157,7 @@ TODO: #define SD 0x40 #define UB 0x80 #define DAS1800_STATUS 0x7 -// bits that prevent interrupt status bits (and CVEN) from being cleared on write +/* bits that prevent interrupt status bits (and CVEN) from being cleared on write */ #define CLEAR_INTR_MASK (CVEN_MASK | 0x1f) #define INT 0x1 #define DMATC 0x2 @@ -164,14 +165,14 @@ TODO: #define OVF 0x10 #define FHF 0x20 #define FNE 0x40 -#define CVEN_MASK 0x40 // masks CVEN on write +#define CVEN_MASK 0x40 /* masks CVEN on write */ #define CVEN 0x80 #define DAS1800_BURST_LENGTH 0x8 #define DAS1800_BURST_RATE 0x9 #define DAS1800_QRAM_ADDRESS 0xa #define DAS1800_COUNTER 0xc -#define IOBASE2 0x400 //offset of additional ioports used on 'ao' cards +#define IOBASE2 0x400 /* offset of additional ioports used on 'ao' cards */ enum { das1701st, das1701st_da, das1702st, das1702st_da, das1702hr, @@ -180,39 +181,39 @@ enum { das1802hr, das1802hr_da, das1801hc, das1802hc, das1801ao, das1802ao }; -static int das1800_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int das1800_detach(struct comedi_device * dev); -static int das1800_probe(struct comedi_device * dev); -static int das1800_cancel(struct comedi_device * dev, struct comedi_subdevice * s); -static irqreturn_t das1800_interrupt(int irq, void *d PT_REGS_ARG); -static int das1800_ai_poll(struct comedi_device * dev, struct comedi_subdevice * s); -static void das1800_ai_handler(struct comedi_device * dev); -static void das1800_handle_dma(struct comedi_device * dev, struct comedi_subdevice * s, +static int das1800_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int das1800_detach(struct comedi_device *dev); +static int das1800_probe(struct comedi_device *dev); +static int das1800_cancel(struct comedi_device *dev, struct comedi_subdevice *s); +static irqreturn_t das1800_interrupt(int irq, void *d); +static int das1800_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s); +static void das1800_ai_handler(struct comedi_device *dev); +static void das1800_handle_dma(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int status); -static void das1800_flush_dma(struct comedi_device * dev, struct comedi_subdevice * s); -static void das1800_flush_dma_channel(struct comedi_device * dev, struct comedi_subdevice * s, - unsigned int channel, uint16_t * buffer); -static void das1800_handle_fifo_half_full(struct comedi_device * dev, - struct comedi_subdevice * s); -static void das1800_handle_fifo_not_empty(struct comedi_device * dev, - struct comedi_subdevice * s); -static int das1800_ai_do_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd); -static int das1800_ai_do_cmd(struct comedi_device * dev, struct comedi_subdevice * s); -static int das1800_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int das1800_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int das1800_di_rbits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int das1800_do_wbits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); +static void das1800_flush_dma(struct comedi_device *dev, struct comedi_subdevice *s); +static void das1800_flush_dma_channel(struct comedi_device *dev, struct comedi_subdevice *s, + unsigned int channel, uint16_t *buffer); +static void das1800_handle_fifo_half_full(struct comedi_device *dev, + struct comedi_subdevice *s); +static void das1800_handle_fifo_not_empty(struct comedi_device *dev, + struct comedi_subdevice *s); +static int das1800_ai_do_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd); +static int das1800_ai_do_cmd(struct comedi_device *dev, struct comedi_subdevice *s); +static int das1800_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int das1800_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int das1800_di_rbits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int das1800_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); -static int das1800_set_frequency(struct comedi_device * dev); +static int das1800_set_frequency(struct comedi_device *dev); static unsigned int burst_convert_arg(unsigned int convert_arg, int round_mode); -static unsigned int suggest_transfer_size(struct comedi_cmd * cmd); +static unsigned int suggest_transfer_size(struct comedi_cmd *cmd); -// analog input ranges +/* analog input ranges */ static const struct comedi_lrange range_ai_das1801 = { 8, { @@ -259,202 +260,202 @@ struct das1800_board { */ static const struct das1800_board das1800_boards[] = { { - name: "das-1701st", - ai_speed:6250, - resolution:12, - qram_len:256, - common: 1, - do_n_chan:4, - ao_ability:0, - ao_n_chan:0, - range_ai:&range_ai_das1801, + .name = "das-1701st", + .ai_speed = 6250, + .resolution = 12, + .qram_len = 256, + .common = 1, + .do_n_chan = 4, + .ao_ability = 0, + .ao_n_chan = 0, + .range_ai = &range_ai_das1801, }, { - name: "das-1701st-da", - ai_speed:6250, - resolution:12, - qram_len:256, - common: 1, - do_n_chan:4, - ao_ability:1, - ao_n_chan:4, - range_ai:&range_ai_das1801, + .name = "das-1701st-da", + .ai_speed = 6250, + .resolution = 12, + .qram_len = 256, + .common = 1, + .do_n_chan = 4, + .ao_ability = 1, + .ao_n_chan = 4, + .range_ai = &range_ai_das1801, }, { - name: "das-1702st", - ai_speed:6250, - resolution:12, - qram_len:256, - common: 1, - do_n_chan:4, - ao_ability:0, - ao_n_chan:0, - range_ai:&range_ai_das1802, + .name = "das-1702st", + .ai_speed = 6250, + .resolution = 12, + .qram_len = 256, + .common = 1, + .do_n_chan = 4, + .ao_ability = 0, + .ao_n_chan = 0, + .range_ai = &range_ai_das1802, }, { - name: "das-1702st-da", - ai_speed:6250, - resolution:12, - qram_len:256, - common: 1, - do_n_chan:4, - ao_ability:1, - ao_n_chan:4, - range_ai:&range_ai_das1802, + .name = "das-1702st-da", + .ai_speed = 6250, + .resolution = 12, + .qram_len = 256, + .common = 1, + .do_n_chan = 4, + .ao_ability = 1, + .ao_n_chan = 4, + .range_ai = &range_ai_das1802, }, { - name: "das-1702hr", - ai_speed:20000, - resolution:16, - qram_len:256, - common: 1, - do_n_chan:4, - ao_ability:0, - ao_n_chan:0, - range_ai:&range_ai_das1802, + .name = "das-1702hr", + .ai_speed = 20000, + .resolution = 16, + .qram_len = 256, + .common = 1, + .do_n_chan = 4, + .ao_ability = 0, + .ao_n_chan = 0, + .range_ai = &range_ai_das1802, }, { - name: "das-1702hr-da", - ai_speed:20000, - resolution:16, - qram_len:256, - common: 1, - do_n_chan:4, - ao_ability:1, - ao_n_chan:2, - range_ai:&range_ai_das1802, + .name = "das-1702hr-da", + .ai_speed = 20000, + .resolution = 16, + .qram_len = 256, + .common = 1, + .do_n_chan = 4, + .ao_ability = 1, + .ao_n_chan = 2, + .range_ai = &range_ai_das1802, }, { - name: "das-1701ao", - ai_speed:6250, - resolution:12, - qram_len:256, - common: 1, - do_n_chan:4, - ao_ability:2, - ao_n_chan:2, - range_ai:&range_ai_das1801, + .name = "das-1701ao", + .ai_speed = 6250, + .resolution = 12, + .qram_len = 256, + .common = 1, + .do_n_chan = 4, + .ao_ability = 2, + .ao_n_chan = 2, + .range_ai = &range_ai_das1801, }, { - name: "das-1702ao", - ai_speed:6250, - resolution:12, - qram_len:256, - common: 1, - do_n_chan:4, - ao_ability:2, - ao_n_chan:2, - range_ai:&range_ai_das1802, + .name = "das-1702ao", + .ai_speed = 6250, + .resolution = 12, + .qram_len = 256, + .common = 1, + .do_n_chan = 4, + .ao_ability = 2, + .ao_n_chan = 2, + .range_ai = &range_ai_das1802, }, { - name: "das-1801st", - ai_speed:3000, - resolution:12, - qram_len:256, - common: 1, - do_n_chan:4, - ao_ability:0, - ao_n_chan:0, - range_ai:&range_ai_das1801, + .name = "das-1801st", + .ai_speed = 3000, + .resolution = 12, + .qram_len = 256, + .common = 1, + .do_n_chan = 4, + .ao_ability = 0, + .ao_n_chan = 0, + .range_ai = &range_ai_das1801, }, { - name: "das-1801st-da", - ai_speed:3000, - resolution:12, - qram_len:256, - common: 1, - do_n_chan:4, - ao_ability:0, - ao_n_chan:4, - range_ai:&range_ai_das1801, + .name = "das-1801st-da", + .ai_speed = 3000, + .resolution = 12, + .qram_len = 256, + .common = 1, + .do_n_chan = 4, + .ao_ability = 0, + .ao_n_chan = 4, + .range_ai = &range_ai_das1801, }, { - name: "das-1802st", - ai_speed:3000, - resolution:12, - qram_len:256, - common: 1, - do_n_chan:4, - ao_ability:0, - ao_n_chan:0, - range_ai:&range_ai_das1802, + .name = "das-1802st", + .ai_speed = 3000, + .resolution = 12, + .qram_len = 256, + .common = 1, + .do_n_chan = 4, + .ao_ability = 0, + .ao_n_chan = 0, + .range_ai = &range_ai_das1802, }, { - name: "das-1802st-da", - ai_speed:3000, - resolution:12, - qram_len:256, - common: 1, - do_n_chan:4, - ao_ability:1, - ao_n_chan:4, - range_ai:&range_ai_das1802, + .name = "das-1802st-da", + .ai_speed = 3000, + .resolution = 12, + .qram_len = 256, + .common = 1, + .do_n_chan = 4, + .ao_ability = 1, + .ao_n_chan = 4, + .range_ai = &range_ai_das1802, }, { - name: "das-1802hr", - ai_speed:10000, - resolution:16, - qram_len:256, - common: 1, - do_n_chan:4, - ao_ability:0, - ao_n_chan:0, - range_ai:&range_ai_das1802, + .name = "das-1802hr", + .ai_speed = 10000, + .resolution = 16, + .qram_len = 256, + .common = 1, + .do_n_chan = 4, + .ao_ability = 0, + .ao_n_chan = 0, + .range_ai = &range_ai_das1802, }, { - name: "das-1802hr-da", - ai_speed:10000, - resolution:16, - qram_len:256, - common: 1, - do_n_chan:4, - ao_ability:1, - ao_n_chan:2, - range_ai:&range_ai_das1802, + .name = "das-1802hr-da", + .ai_speed = 10000, + .resolution = 16, + .qram_len = 256, + .common = 1, + .do_n_chan = 4, + .ao_ability = 1, + .ao_n_chan = 2, + .range_ai = &range_ai_das1802, }, { - name: "das-1801hc", - ai_speed:3000, - resolution:12, - qram_len:64, - common: 0, - do_n_chan:8, - ao_ability:1, - ao_n_chan:2, - range_ai:&range_ai_das1801, + .name = "das-1801hc", + .ai_speed = 3000, + .resolution = 12, + .qram_len = 64, + .common = 0, + .do_n_chan = 8, + .ao_ability = 1, + .ao_n_chan = 2, + .range_ai = &range_ai_das1801, }, { - name: "das-1802hc", - ai_speed:3000, - resolution:12, - qram_len:64, - common: 0, - do_n_chan:8, - ao_ability:1, - ao_n_chan:2, - range_ai:&range_ai_das1802, + .name = "das-1802hc", + .ai_speed = 3000, + .resolution = 12, + .qram_len = 64, + .common = 0, + .do_n_chan = 8, + .ao_ability = 1, + .ao_n_chan = 2, + .range_ai = &range_ai_das1802, }, { - name: "das-1801ao", - ai_speed:3000, - resolution:12, - qram_len:256, - common: 1, - do_n_chan:4, - ao_ability:2, - ao_n_chan:2, - range_ai:&range_ai_das1801, + .name = "das-1801ao", + .ai_speed = 3000, + .resolution = 12, + .qram_len = 256, + .common = 1, + .do_n_chan = 4, + .ao_ability = 2, + .ao_n_chan = 2, + .range_ai = &range_ai_das1801, }, { - name: "das-1802ao", - ai_speed:3000, - resolution:12, - qram_len:256, - common: 1, - do_n_chan:4, - ao_ability:2, - ao_n_chan:2, - range_ai:&range_ai_das1802, + .name = "das-1802ao", + .ai_speed = 3000, + .resolution = 12, + .qram_len = 256, + .common = 1, + .do_n_chan = 4, + .ao_ability = 2, + .ao_n_chan = 2, + .range_ai = &range_ai_das1802, }, }; @@ -485,7 +486,7 @@ struct das1800_private { #define devpriv ((struct das1800_private *)dev->private) -// analog out range for boards with basic analog out +/* analog out range for boards with basic analog out */ static const struct comedi_lrange range_ao_1 = { 1, { @@ -493,7 +494,7 @@ static const struct comedi_lrange range_ao_1 = { } }; -// analog out range for 'ao' boards +/* analog out range for 'ao' boards */ /* static const struct comedi_lrange range_ao_2 = { 2, @@ -505,13 +506,13 @@ static const struct comedi_lrange range_ao_2 = { */ static struct comedi_driver driver_das1800 = { - driver_name:"das1800", - module:THIS_MODULE, - attach:das1800_attach, - detach:das1800_detach, - num_names:sizeof(das1800_boards) / sizeof(struct das1800_board), - board_name:&das1800_boards[0].name, - offset:sizeof(struct das1800_board), + .driver_name = "das1800", + .module = THIS_MODULE, + .attach = das1800_attach, + .detach = das1800_detach, + .num_names = ARRAY_SIZE(das1800_boards), + .board_name = &das1800_boards[0].name, + .offset = sizeof(struct das1800_board), }; /* @@ -520,31 +521,31 @@ static struct comedi_driver driver_das1800 = { */ COMEDI_INITCLEANUP(driver_das1800); -static int das1800_init_dma(struct comedi_device * dev, unsigned int dma0, +static int das1800_init_dma(struct comedi_device *dev, unsigned int dma0, unsigned int dma1) { unsigned long flags; - // need an irq to do dma + /* need an irq to do dma */ if (dev->irq && dma0) { - //encode dma0 and dma1 into 2 digit hexadecimal for switch + /* encode dma0 and dma1 into 2 digit hexadecimal for switch */ switch ((dma0 & 0x7) | (dma1 << 4)) { - case 0x5: // dma0 == 5 + case 0x5: /* dma0 == 5 */ devpriv->dma_bits |= DMA_CH5; break; - case 0x6: // dma0 == 6 + case 0x6: /* dma0 == 6 */ devpriv->dma_bits |= DMA_CH6; break; - case 0x7: // dma0 == 7 + case 0x7: /* dma0 == 7 */ devpriv->dma_bits |= DMA_CH7; break; - case 0x65: // dma0 == 5, dma1 == 6 + case 0x65: /* dma0 == 5, dma1 == 6 */ devpriv->dma_bits |= DMA_CH5_CH6; break; - case 0x76: // dma0 == 6, dma1 == 7 + case 0x76: /* dma0 == 6, dma1 == 7 */ devpriv->dma_bits |= DMA_CH6_CH7; break; - case 0x57: // dma0 == 7, dma1 == 5 + case 0x57: /* dma0 == 7, dma1 == 5 */ devpriv->dma_bits |= DMA_CH7_CH5; break; default: @@ -590,7 +591,7 @@ static int das1800_init_dma(struct comedi_device * dev, unsigned int dma0, return 0; } -static int das1800_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int das1800_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; unsigned long iobase = it->options[0]; @@ -638,7 +639,7 @@ static int das1800_attach(struct comedi_device * dev, struct comedi_devconfig * dev->board_ptr = das1800_boards + board; dev->board_name = thisboard->name; - // if it is an 'ao' board with fancy analog out then we need extra io ports + /* if it is an 'ao' board with fancy analog out then we need extra io ports */ if (thisboard->ao_ability == 2) { iobase2 = iobase + IOBASE2; if (!request_region(iobase2, DAS1800_SIZE, @@ -651,7 +652,7 @@ static int das1800_attach(struct comedi_device * dev, struct comedi_devconfig * /* grab our IRQ */ if (irq) { - if (comedi_request_irq(irq, das1800_interrupt, 0, + if (request_irq(irq, das1800_interrupt, 0, driver_das1800.driver_name, dev)) { printk(" unable to allocate irq %u\n", irq); return -EINVAL; @@ -659,7 +660,7 @@ static int das1800_attach(struct comedi_device * dev, struct comedi_devconfig * } dev->irq = irq; - // set bits that tell card which irq to use + /* set bits that tell card which irq to use */ switch (irq) { case 0: break; @@ -751,12 +752,12 @@ static int das1800_attach(struct comedi_device * dev, struct comedi_devconfig * das1800_cancel(dev, dev->read_subdev); - // initialize digital out channels + /* initialize digital out channels */ outb(devpriv->do_bits, dev->iobase + DAS1800_DIGITAL); - // initialize analog out channels + /* initialize analog out channels */ if (thisboard->ao_ability == 1) { - // select 'update' dac channel for baseAddress + 0x0 + /* select 'update' dac channel for baseAddress + 0x0 */ outb(DAC(thisboard->ao_n_chan - 1), dev->iobase + DAS1800_SELECT); outw(devpriv->ao_update_bits, dev->iobase + DAS1800_DAC); @@ -765,13 +766,13 @@ static int das1800_attach(struct comedi_device * dev, struct comedi_devconfig * return 0; }; -static int das1800_detach(struct comedi_device * dev) +static int das1800_detach(struct comedi_device *dev) { /* only free stuff if it has been allocated by _attach */ if (dev->iobase) release_region(dev->iobase, DAS1800_SIZE); if (dev->irq) - comedi_free_irq(dev->irq, dev); + free_irq(dev->irq, dev); if (dev->private) { if (devpriv->iobase2) release_region(devpriv->iobase2, DAS1800_SIZE); @@ -793,7 +794,7 @@ static int das1800_detach(struct comedi_device * dev) /* probes and checks das-1800 series board type */ -static int das1800_probe(struct comedi_device * dev) +static int das1800_probe(struct comedi_device *dev) { int id; int board; @@ -867,19 +868,19 @@ static int das1800_probe(struct comedi_device * dev) return -1; } -static int das1800_ai_poll(struct comedi_device * dev, struct comedi_subdevice * s) +static int das1800_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s) { unsigned long flags; - // prevent race with interrupt handler - comedi_spin_lock_irqsave(&dev->spinlock, flags); + /* prevent race with interrupt handler */ + spin_lock_irqsave(&dev->spinlock, flags); das1800_ai_handler(dev); - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); return s->async->buf_write_count - s->async->buf_read_count; } -static irqreturn_t das1800_interrupt(int irq, void *d PT_REGS_ARG) +static irqreturn_t das1800_interrupt(int irq, void *d) { struct comedi_device *dev = d; unsigned int status; @@ -901,15 +902,15 @@ static irqreturn_t das1800_interrupt(int irq, void *d PT_REGS_ARG) } /* clear the interrupt status bit INT */ outb(CLEAR_INTR_MASK & ~INT, dev->iobase + DAS1800_STATUS); - // handle interrupt + /* handle interrupt */ das1800_ai_handler(dev); spin_unlock(&dev->spinlock); return IRQ_HANDLED; } -// the guts of the interrupt handler, that is shared with das1800_ai_poll -static void das1800_ai_handler(struct comedi_device * dev) +/* the guts of the interrupt handler, that is shared with das1800_ai_poll */ +static void das1800_ai_handler(struct comedi_device *dev) { struct comedi_subdevice *s = dev->subdevices + 0; /* analog input subdevice */ struct comedi_async *async = s->async; @@ -917,22 +918,22 @@ static void das1800_ai_handler(struct comedi_device * dev) unsigned int status = inb(dev->iobase + DAS1800_STATUS); async->events = 0; - // select adc for base address + 0 + /* select adc for base address + 0 */ outb(ADC, dev->iobase + DAS1800_SELECT); - // dma buffer full + /* dma buffer full */ if (devpriv->irq_dma_bits & DMA_ENABLED) { - // look for data from dma transfer even if dma terminal count hasn't happened yet + /* look for data from dma transfer even if dma terminal count hasn't happened yet */ das1800_handle_dma(dev, s, status); - } else if (status & FHF) { // if fifo half full + } else if (status & FHF) { /* if fifo half full */ das1800_handle_fifo_half_full(dev, s); - } else if (status & FNE) { // if fifo not empty + } else if (status & FNE) { /* if fifo not empty */ das1800_handle_fifo_not_empty(dev, s); } async->events |= COMEDI_CB_BLOCK; /* if the card's fifo has overflowed */ if (status & OVF) { - // clear OVF interrupt bit + /* clear OVF interrupt bit */ outb(CLEAR_INTR_MASK & ~OVF, dev->iobase + DAS1800_STATUS); comedi_error(dev, "DAS1800 FIFO overflow"); das1800_cancel(dev, s); @@ -940,19 +941,19 @@ static void das1800_ai_handler(struct comedi_device * dev) comedi_event(dev, s); return; } - // stop taking data if appropriate + /* stop taking data if appropriate */ /* stop_src TRIG_EXT */ if (status & CT0TC) { - // clear CT0TC interrupt bit + /* clear CT0TC interrupt bit */ outb(CLEAR_INTR_MASK & ~CT0TC, dev->iobase + DAS1800_STATUS); - // make sure we get all remaining data from board before quitting + /* make sure we get all remaining data from board before quitting */ if (devpriv->irq_dma_bits & DMA_ENABLED) das1800_flush_dma(dev, s); else das1800_handle_fifo_not_empty(dev, s); das1800_cancel(dev, s); /* disable hardware conversions */ async->events |= COMEDI_CB_EOA; - } else if (cmd->stop_src == TRIG_COUNT && devpriv->count == 0) { // stop_src TRIG_COUNT + } else if (cmd->stop_src == TRIG_COUNT && devpriv->count == 0) { /* stop_src TRIG_COUNT */ das1800_cancel(dev, s); /* disable hardware conversions */ async->events |= COMEDI_CB_EOA; } @@ -962,7 +963,7 @@ static void das1800_ai_handler(struct comedi_device * dev) return; } -static void das1800_handle_dma(struct comedi_device * dev, struct comedi_subdevice * s, +static void das1800_handle_dma(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int status) { unsigned long flags; @@ -971,7 +972,7 @@ static void das1800_handle_dma(struct comedi_device * dev, struct comedi_subdevi flags = claim_dma_lock(); das1800_flush_dma_channel(dev, s, devpriv->dma_current, devpriv->dma_current_buf); - // re-enable dma channel + /* re-enable dma channel */ set_dma_addr(devpriv->dma_current, virt_to_bus(devpriv->dma_current_buf)); set_dma_count(devpriv->dma_current, devpriv->dma_transfer_size); @@ -979,11 +980,11 @@ static void das1800_handle_dma(struct comedi_device * dev, struct comedi_subdevi release_dma_lock(flags); if (status & DMATC) { - // clear DMATC interrupt bit + /* clear DMATC interrupt bit */ outb(CLEAR_INTR_MASK & ~DMATC, dev->iobase + DAS1800_STATUS); - // switch dma channels for next time, if appropriate + /* switch dma channels for next time, if appropriate */ if (dual_dma) { - // read data from the other channel next time + /* read data from the other channel next time */ if (devpriv->dma_current == devpriv->dma0) { devpriv->dma_current = devpriv->dma1; devpriv->dma_current_buf = devpriv->ai_buf1; @@ -997,14 +998,14 @@ static void das1800_handle_dma(struct comedi_device * dev, struct comedi_subdevi return; } -static inline uint16_t munge_bipolar_sample(const struct comedi_device * dev, +static inline uint16_t munge_bipolar_sample(const struct comedi_device *dev, uint16_t sample) { sample += 1 << (thisboard->resolution - 1); return sample; } -static void munge_data(struct comedi_device * dev, uint16_t * array, +static void munge_data(struct comedi_device *dev, uint16_t *array, unsigned int num_elements) { unsigned int i; @@ -1023,8 +1024,8 @@ static void munge_data(struct comedi_device * dev, uint16_t * array, /* Utility function used by das1800_flush_dma() and das1800_handle_dma(). * Assumes dma lock is held */ -static void das1800_flush_dma_channel(struct comedi_device * dev, struct comedi_subdevice * s, - unsigned int channel, uint16_t * buffer) +static void das1800_flush_dma_channel(struct comedi_device *dev, struct comedi_subdevice *s, + unsigned int channel, uint16_t *buffer) { unsigned int num_bytes, num_samples; struct comedi_cmd *cmd = &s->async->cmd; @@ -1035,7 +1036,7 @@ static void das1800_flush_dma_channel(struct comedi_device * dev, struct comedi_ * get set correctly */ clear_dma_ff(channel); - // figure out how many points to read + /* figure out how many points to read */ num_bytes = devpriv->dma_transfer_size - get_dma_residue(channel); num_samples = num_bytes / sizeof(short); @@ -1053,7 +1054,7 @@ static void das1800_flush_dma_channel(struct comedi_device * dev, struct comedi_ /* flushes remaining data from board when external trigger has stopped aquisition * and we are using dma transfers */ -static void das1800_flush_dma(struct comedi_device * dev, struct comedi_subdevice * s) +static void das1800_flush_dma(struct comedi_device *dev, struct comedi_subdevice *s) { unsigned long flags; const int dual_dma = devpriv->irq_dma_bits & DMA_DUAL; @@ -1063,7 +1064,7 @@ static void das1800_flush_dma(struct comedi_device * dev, struct comedi_subdevic devpriv->dma_current_buf); if (dual_dma) { - // switch to other channel and flush it + /* switch to other channel and flush it */ if (devpriv->dma_current == devpriv->dma0) { devpriv->dma_current = devpriv->dma1; devpriv->dma_current_buf = devpriv->ai_buf1; @@ -1077,14 +1078,14 @@ static void das1800_flush_dma(struct comedi_device * dev, struct comedi_subdevic release_dma_lock(flags); - // get any remaining samples in fifo + /* get any remaining samples in fifo */ das1800_handle_fifo_not_empty(dev, s); return; } -static void das1800_handle_fifo_half_full(struct comedi_device * dev, - struct comedi_subdevice * s) +static void das1800_handle_fifo_half_full(struct comedi_device *dev, + struct comedi_subdevice *s) { int numPoints = 0; /* number of points to read */ struct comedi_cmd *cmd = &s->async->cmd; @@ -1102,8 +1103,8 @@ static void das1800_handle_fifo_half_full(struct comedi_device * dev, return; } -static void das1800_handle_fifo_not_empty(struct comedi_device * dev, - struct comedi_subdevice * s) +static void das1800_handle_fifo_not_empty(struct comedi_device *dev, + struct comedi_subdevice *s) { short dpnt; int unipolar; @@ -1126,7 +1127,7 @@ static void das1800_handle_fifo_not_empty(struct comedi_device * dev, return; } -static int das1800_cancel(struct comedi_device * dev, struct comedi_subdevice * s) +static int das1800_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { outb(0x0, dev->iobase + DAS1800_STATUS); /* disable conversions */ outb(0x0, dev->iobase + DAS1800_CONTROL_B); /* disable interrupts and dma */ @@ -1139,8 +1140,8 @@ static int das1800_cancel(struct comedi_device * dev, struct comedi_subdevice * } /* test analog input cmd */ -static int das1800_ai_do_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd) +static int das1800_ai_do_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd) { int err = 0; int tmp; @@ -1180,7 +1181,7 @@ static int das1800_ai_do_cmdtest(struct comedi_device * dev, struct comedi_subde /* step 2: make sure trigger sources are unique and mutually compatible */ - // uniqueness check + /* uniqueness check */ if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) err++; if (cmd->scan_begin_src != TRIG_FOLLOW && @@ -1192,7 +1193,7 @@ static int das1800_ai_do_cmdtest(struct comedi_device * dev, struct comedi_subde if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_EXT) err++; - //compatibility check + /* compatibility check */ if (cmd->scan_begin_src != TRIG_FOLLOW && cmd->convert_src != TRIG_TIMER) err++; @@ -1244,7 +1245,7 @@ static int das1800_ai_do_cmdtest(struct comedi_device * dev, struct comedi_subde /* step 4: fix up any arguments */ if (cmd->convert_src == TRIG_TIMER) { - // if we are not in burst mode + /* if we are not in burst mode */ if (cmd->scan_begin_src == TRIG_FOLLOW) { tmp_arg = cmd->convert_arg; /* calculate counter values that give desired timing */ @@ -1255,9 +1256,9 @@ static int das1800_ai_do_cmdtest(struct comedi_device * dev, struct comedi_subde if (tmp_arg != cmd->convert_arg) err++; } - // if we are in burst mode + /* if we are in burst mode */ else { - // check that convert_arg is compatible + /* check that convert_arg is compatible */ tmp_arg = cmd->convert_arg; cmd->convert_arg = burst_convert_arg(cmd->convert_arg, @@ -1266,7 +1267,7 @@ static int das1800_ai_do_cmdtest(struct comedi_device * dev, struct comedi_subde err++; if (cmd->scan_begin_src == TRIG_TIMER) { - // if scans are timed faster than conversion rate allows + /* if scans are timed faster than conversion rate allows */ if (cmd->convert_arg * cmd->chanlist_len > cmd->scan_begin_arg) { cmd->scan_begin_arg = @@ -1290,7 +1291,7 @@ static int das1800_ai_do_cmdtest(struct comedi_device * dev, struct comedi_subde if (err) return 4; - // make sure user is not trying to mix unipolar and bipolar ranges + /* make sure user is not trying to mix unipolar and bipolar ranges */ if (cmd->chanlist) { unipolar = CR_RANGE(cmd->chanlist[0]) & UNIPOLAR; for (i = 1; i < cmd->chanlist_len; i++) { @@ -1311,14 +1312,14 @@ static int das1800_ai_do_cmdtest(struct comedi_device * dev, struct comedi_subde /* analog input cmd interface */ -// first, some utility functions used in the main ai_do_cmd() +/* first, some utility functions used in the main ai_do_cmd() */ -// returns appropriate bits for control register a, depending on command +/* returns appropriate bits for control register a, depending on command */ static int control_a_bits(struct comedi_cmd cmd) { int control_a; - control_a = FFEN; //enable fifo + control_a = FFEN; /* enable fifo */ if (cmd.stop_src == TRIG_EXT) { control_a |= ATEN; } @@ -1336,7 +1337,7 @@ static int control_a_bits(struct comedi_cmd cmd) return control_a; } -// returns appropriate bits for control register c, depending on command +/* returns appropriate bits for control register c, depending on command */ static int control_c_bits(struct comedi_cmd cmd) { int control_c; @@ -1346,7 +1347,7 @@ static int control_c_bits(struct comedi_cmd cmd) * select unipolar / bipolar */ aref = CR_AREF(cmd.chanlist[0]); - control_c = UQEN; //enable upper qram addresses + control_c = UQEN; /* enable upper qram addresses */ if (aref != AREF_DIFF) control_c |= SD; if (aref == AREF_COMMON) @@ -1355,7 +1356,7 @@ static int control_c_bits(struct comedi_cmd cmd) if (CR_RANGE(cmd.chanlist[0]) & UNIPOLAR) control_c |= UB; switch (cmd.scan_begin_src) { - case TRIG_FOLLOW: // not in burst mode + case TRIG_FOLLOW: /* not in burst mode */ switch (cmd.convert_src) { case TRIG_TIMER: /* trig on cascaded counters */ @@ -1370,11 +1371,11 @@ static int control_c_bits(struct comedi_cmd cmd) } break; case TRIG_TIMER: - // burst mode with internal pacer clock + /* burst mode with internal pacer clock */ control_c |= BMDE | IPCLK; break; case TRIG_EXT: - // burst mode with external trigger + /* burst mode with external trigger */ control_c |= BMDE | XPCLK; break; default: @@ -1384,12 +1385,12 @@ static int control_c_bits(struct comedi_cmd cmd) return control_c; } -// sets up counters -static int setup_counters(struct comedi_device * dev, struct comedi_cmd cmd) +/* sets up counters */ +static int setup_counters(struct comedi_device *dev, struct comedi_cmd cmd) { - // setup cascaded counters for conversion/scan frequency + /* setup cascaded counters for conversion/scan frequency */ switch (cmd.scan_begin_src) { - case TRIG_FOLLOW: // not in burst mode + case TRIG_FOLLOW: /* not in burst mode */ if (cmd.convert_src == TRIG_TIMER) { /* set conversion frequency */ i8253_cascade_ns_to_timer_2div(TIMER_BASE, @@ -1401,7 +1402,7 @@ static int setup_counters(struct comedi_device * dev, struct comedi_cmd cmd) } } break; - case TRIG_TIMER: // in burst mode + case TRIG_TIMER: /* in burst mode */ /* set scan frequency */ i8253_cascade_ns_to_timer_2div(TIMER_BASE, &(devpriv->divisor1), &(devpriv->divisor2), &(cmd.scan_begin_arg), @@ -1414,17 +1415,17 @@ static int setup_counters(struct comedi_device * dev, struct comedi_cmd cmd) break; } - // setup counter 0 for 'about triggering' + /* setup counter 0 for 'about triggering' */ if (cmd.stop_src == TRIG_EXT) { - // load counter 0 in mode 0 + /* load counter 0 in mode 0 */ i8254_load(dev->iobase + DAS1800_COUNTER, 0, 0, 1, 0); } return 0; } -// sets up dma -static void setup_dma(struct comedi_device * dev, struct comedi_cmd cmd) +/* sets up dma */ +static void setup_dma(struct comedi_device *dev, struct comedi_cmd cmd) { unsigned long lock_flags; const int dual_dma = devpriv->irq_dma_bits & DMA_DUAL; @@ -1440,19 +1441,19 @@ static void setup_dma(struct comedi_device * dev, struct comedi_cmd cmd) * count and address get set correctly */ clear_dma_ff(devpriv->dma0); set_dma_addr(devpriv->dma0, virt_to_bus(devpriv->ai_buf0)); - // set appropriate size of transfer + /* set appropriate size of transfer */ set_dma_count(devpriv->dma0, devpriv->dma_transfer_size); devpriv->dma_current = devpriv->dma0; devpriv->dma_current_buf = devpriv->ai_buf0; enable_dma(devpriv->dma0); - // set up dual dma if appropriate + /* set up dual dma if appropriate */ if (dual_dma) { disable_dma(devpriv->dma1); /* clear flip-flop to make sure 2-byte registers for * count and address get set correctly */ clear_dma_ff(devpriv->dma1); set_dma_addr(devpriv->dma1, virt_to_bus(devpriv->ai_buf1)); - // set appropriate size of transfer + /* set appropriate size of transfer */ set_dma_count(devpriv->dma1, devpriv->dma_transfer_size); enable_dma(devpriv->dma1); } @@ -1461,17 +1462,17 @@ static void setup_dma(struct comedi_device * dev, struct comedi_cmd cmd) return; } -// programs channel/gain list into card -static void program_chanlist(struct comedi_device * dev, struct comedi_cmd cmd) +/* programs channel/gain list into card */ +static void program_chanlist(struct comedi_device *dev, struct comedi_cmd cmd) { int i, n, chan_range; unsigned long irq_flags; - const int range_mask = 0x3; //masks unipolar/bipolar bit off range + const int range_mask = 0x3; /* masks unipolar/bipolar bit off range */ const int range_bitshift = 8; n = cmd.chanlist_len; - // spinlock protects indirect addressing - comedi_spin_lock_irqsave(&dev->spinlock, irq_flags); + /* spinlock protects indirect addressing */ + spin_lock_irqsave(&dev->spinlock, irq_flags); outb(QRAM, dev->iobase + DAS1800_SELECT); /* select QRAM for baseAddress + 0x0 */ outb(n - 1, dev->iobase + DAS1800_QRAM_ADDRESS); /*set QRAM address start */ /* make channel / gain list */ @@ -1483,13 +1484,13 @@ static void program_chanlist(struct comedi_device * dev, struct comedi_cmd cmd) outw(chan_range, dev->iobase + DAS1800_QRAM); } outb(n - 1, dev->iobase + DAS1800_QRAM_ADDRESS); /*finish write to QRAM */ - comedi_spin_unlock_irqrestore(&dev->spinlock, irq_flags); + spin_unlock_irqrestore(&dev->spinlock, irq_flags); return; } -// analog input do_cmd -static int das1800_ai_do_cmd(struct comedi_device * dev, struct comedi_subdevice * s) +/* analog input do_cmd */ +static int das1800_ai_do_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { int ret; int control_a, control_c; @@ -1509,22 +1510,22 @@ static int das1800_ai_do_cmd(struct comedi_device * dev, struct comedi_subdevice } else { devpriv->irq_dma_bits |= devpriv->dma_bits; } - // interrupt on end of conversion for TRIG_WAKE_EOS + /* interrupt on end of conversion for TRIG_WAKE_EOS */ if (cmd.flags & TRIG_WAKE_EOS) { - // interrupt fifo not empty + /* interrupt fifo not empty */ devpriv->irq_dma_bits &= ~FIMD; } else { - // interrupt fifo half full + /* interrupt fifo half full */ devpriv->irq_dma_bits |= FIMD; } - // determine how many conversions we need + /* determine how many conversions we need */ if (cmd.stop_src == TRIG_COUNT) { devpriv->count = cmd.stop_arg * cmd.chanlist_len; } das1800_cancel(dev, s); - // determine proper bits for control registers + /* determine proper bits for control registers */ control_a = control_a_bits(cmd); control_c = control_c_bits(cmd); @@ -1537,14 +1538,14 @@ static int das1800_ai_do_cmd(struct comedi_device * dev, struct comedi_subdevice } setup_dma(dev, cmd); outb(control_c, dev->iobase + DAS1800_CONTROL_C); - // set conversion rate and length for burst mode + /* set conversion rate and length for burst mode */ if (control_c & BMDE) { - // program conversion period with number of microseconds minus 1 + /* program conversion period with number of microseconds minus 1 */ outb(cmd.convert_arg / 1000 - 1, dev->iobase + DAS1800_BURST_RATE); outb(cmd.chanlist_len - 1, dev->iobase + DAS1800_BURST_LENGTH); } - outb(devpriv->irq_dma_bits, dev->iobase + DAS1800_CONTROL_B); // enable irq/dma + outb(devpriv->irq_dma_bits, dev->iobase + DAS1800_CONTROL_B); /* enable irq/dma */ outb(control_a, dev->iobase + DAS1800_CONTROL_A); /* enable fifo and triggering */ outb(CVEN, dev->iobase + DAS1800_STATUS); /* enable conversions */ @@ -1552,8 +1553,8 @@ static int das1800_ai_do_cmd(struct comedi_device * dev, struct comedi_subdevice } /* read analog input */ -static int das1800_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int das1800_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i, n; int chan, range, aref, chan_range; @@ -1582,7 +1583,7 @@ static int das1800_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice /* mask of unipolar/bipolar bit from range */ range = CR_RANGE(insn->chanspec) & 0x3; chan_range = chan | (range << 8); - comedi_spin_lock_irqsave(&dev->spinlock, irq_flags); + spin_lock_irqsave(&dev->spinlock, irq_flags); outb(QRAM, dev->iobase + DAS1800_SELECT); /* select QRAM for baseAddress + 0x0 */ outb(0x0, dev->iobase + DAS1800_QRAM_ADDRESS); /* set QRAM address start */ outw(chan_range, dev->iobase + DAS1800_QRAM); @@ -1606,43 +1607,43 @@ static int das1800_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice dpnt += 1 << (thisboard->resolution - 1); data[n] = dpnt; } - comedi_spin_unlock_irqrestore(&dev->spinlock, irq_flags); + spin_unlock_irqrestore(&dev->spinlock, irq_flags); return n; } /* writes to an analog output channel */ -static int das1800_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int das1800_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int chan = CR_CHAN(insn->chanspec); -// int range = CR_RANGE(insn->chanspec); +/* int range = CR_RANGE(insn->chanspec); */ int update_chan = thisboard->ao_n_chan - 1; short output; unsigned long irq_flags; - // card expects two's complement data + /* card expects two's complement data */ output = data[0] - (1 << (thisboard->resolution - 1)); - // if the write is to the 'update' channel, we need to remember its value + /* if the write is to the 'update' channel, we need to remember its value */ if (chan == update_chan) devpriv->ao_update_bits = output; - // write to channel - comedi_spin_lock_irqsave(&dev->spinlock, irq_flags); + /* write to channel */ + spin_lock_irqsave(&dev->spinlock, irq_flags); outb(DAC(chan), dev->iobase + DAS1800_SELECT); /* select dac channel for baseAddress + 0x0 */ outw(output, dev->iobase + DAS1800_DAC); - // now we need to write to 'update' channel to update all dac channels + /* now we need to write to 'update' channel to update all dac channels */ if (chan != update_chan) { outb(DAC(update_chan), dev->iobase + DAS1800_SELECT); /* select 'update' channel for baseAddress + 0x0 */ outw(devpriv->ao_update_bits, dev->iobase + DAS1800_DAC); } - comedi_spin_unlock_irqrestore(&dev->spinlock, irq_flags); + spin_unlock_irqrestore(&dev->spinlock, irq_flags); return 1; } /* reads from digital input channels */ -static int das1800_di_rbits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int das1800_di_rbits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { data[1] = inb(dev->iobase + DAS1800_DIGITAL) & 0xf; @@ -1652,12 +1653,12 @@ static int das1800_di_rbits(struct comedi_device * dev, struct comedi_subdevice } /* writes to digital output channels */ -static int das1800_do_wbits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int das1800_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { unsigned int wbits; - // only set bits that have been masked + /* only set bits that have been masked */ data[0] &= (1 << s->n_chan) - 1; wbits = devpriv->do_bits; wbits &= ~data[0]; @@ -1672,15 +1673,15 @@ static int das1800_do_wbits(struct comedi_device * dev, struct comedi_subdevice } /* loads counters with divisor1, divisor2 from private structure */ -static int das1800_set_frequency(struct comedi_device * dev) +static int das1800_set_frequency(struct comedi_device *dev) { int err = 0; - // counter 1, mode 2 + /* counter 1, mode 2 */ if (i8254_load(dev->iobase + DAS1800_COUNTER, 0, 1, devpriv->divisor1, 2)) err++; - // counter 2, mode 2 + /* counter 2, mode 2 */ if (i8254_load(dev->iobase + DAS1800_COUNTER, 0, 2, devpriv->divisor2, 2)) err++; @@ -1697,11 +1698,11 @@ static unsigned int burst_convert_arg(unsigned int convert_arg, int round_mode) { unsigned int micro_sec; - // in burst mode, the maximum conversion time is 64 microseconds + /* in burst mode, the maximum conversion time is 64 microseconds */ if (convert_arg > 64000) convert_arg = 64000; - // the conversion time must be an integral number of microseconds + /* the conversion time must be an integral number of microseconds */ switch (round_mode) { case TRIG_ROUND_NEAREST: default: @@ -1715,21 +1716,21 @@ static unsigned int burst_convert_arg(unsigned int convert_arg, int round_mode) break; } - // return number of nanoseconds + /* return number of nanoseconds */ return micro_sec * 1000; } -// utility function that suggests a dma transfer size based on the conversion period 'ns' -static unsigned int suggest_transfer_size(struct comedi_cmd * cmd) +/* utility function that suggests a dma transfer size based on the conversion period 'ns' */ +static unsigned int suggest_transfer_size(struct comedi_cmd *cmd) { unsigned int size = DMA_BUF_SIZE; - static const int sample_size = 2; // size in bytes of one sample from board - unsigned int fill_time = 300000000; // target time in nanoseconds for filling dma buffer - unsigned int max_size; // maximum size we will allow for a transfer + static const int sample_size = 2; /* size in bytes of one sample from board */ + unsigned int fill_time = 300000000; /* target time in nanoseconds for filling dma buffer */ + unsigned int max_size; /* maximum size we will allow for a transfer */ - // make dma buffer fill in 0.3 seconds for timed modes + /* make dma buffer fill in 0.3 seconds for timed modes */ switch (cmd->scan_begin_src) { - case TRIG_FOLLOW: // not in burst mode + case TRIG_FOLLOW: /* not in burst mode */ if (cmd->convert_src == TRIG_TIMER) size = (fill_time / cmd->convert_arg) * sample_size; break; @@ -1742,9 +1743,9 @@ static unsigned int suggest_transfer_size(struct comedi_cmd * cmd) break; } - // set a minimum and maximum size allowed + /* set a minimum and maximum size allowed */ max_size = DMA_BUF_SIZE; - // if we are taking limited number of conversions, limit transfer size to that + /* if we are taking limited number of conversions, limit transfer size to that */ if (cmd->stop_src == TRIG_COUNT && cmd->stop_arg * cmd->chanlist_len * sample_size < max_size) max_size = cmd->stop_arg * cmd->chanlist_len * sample_size; diff --git a/drivers/staging/comedi/drivers/das6402.c b/drivers/staging/comedi/drivers/das6402.c index 2a8ca0525104..0114eb935305 100644 --- a/drivers/staging/comedi/drivers/das6402.c +++ b/drivers/staging/comedi/drivers/das6402.c @@ -38,6 +38,7 @@ Devices: [Keithley Metrabyte] DAS6402 (das6402) This driver has suffered bitrot. */ +#include #include "../comedidev.h" #include @@ -98,13 +99,13 @@ This driver has suffered bitrot. #define C2 0x80 #define RWLH 0x30 -static int das6402_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int das6402_detach(struct comedi_device * dev); +static int das6402_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int das6402_detach(struct comedi_device *dev); static struct comedi_driver driver_das6402 = { - driver_name:"das6402", - module:THIS_MODULE, - attach:das6402_attach, - detach:das6402_detach, + .driver_name = "das6402", + .module = THIS_MODULE, + .attach = das6402_attach, + .detach = das6402_detach, }; COMEDI_INITCLEANUP(driver_das6402); @@ -116,9 +117,9 @@ struct das6402_private { }; #define devpriv ((struct das6402_private *)dev->private) -static void das6402_ai_fifo_dregs(struct comedi_device * dev, struct comedi_subdevice * s); +static void das6402_ai_fifo_dregs(struct comedi_device *dev, struct comedi_subdevice *s); -static void das6402_setcounter(struct comedi_device * dev) +static void das6402_setcounter(struct comedi_device *dev) { BYTE p; unsigned short ctrlwrd; @@ -151,7 +152,7 @@ static void das6402_setcounter(struct comedi_device * dev) outb_p(p, dev->iobase + 14); } -static irqreturn_t intr_handler(int irq, void *d PT_REGS_ARG) +static irqreturn_t intr_handler(int irq, void *d) { struct comedi_device *dev = d; struct comedi_subdevice *s = dev->subdevices; @@ -186,7 +187,7 @@ static irqreturn_t intr_handler(int irq, void *d PT_REGS_ARG) } #if 0 -static void das6402_ai_fifo_read(struct comedi_device * dev, short * data, int n) +static void das6402_ai_fifo_read(struct comedi_device *dev, short *data, int n) { int i; @@ -195,7 +196,7 @@ static void das6402_ai_fifo_read(struct comedi_device * dev, short * data, int n } #endif -static void das6402_ai_fifo_dregs(struct comedi_device * dev, struct comedi_subdevice * s) +static void das6402_ai_fifo_dregs(struct comedi_device *dev, struct comedi_subdevice *s) { while (1) { if (!(inb(dev->iobase + 8) & 0x01)) @@ -204,7 +205,7 @@ static void das6402_ai_fifo_dregs(struct comedi_device * dev, struct comedi_subd } } -static int das6402_ai_cancel(struct comedi_device * dev, struct comedi_subdevice * s) +static int das6402_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { /* * This function should reset the board from whatever condition it @@ -226,8 +227,8 @@ static int das6402_ai_cancel(struct comedi_device * dev, struct comedi_subdevice } #ifdef unused -static int das6402_ai_mode2(struct comedi_device * dev, struct comedi_subdevice * s, - comedi_trig * it) +static int das6402_ai_mode2(struct comedi_device *dev, struct comedi_subdevice *s, + comedi_trig *it) { devpriv->das6402_ignoreirq = 1; @@ -249,7 +250,7 @@ static int das6402_ai_mode2(struct comedi_device * dev, struct comedi_subdevice } #endif -static int board_init(struct comedi_device * dev) +static int board_init(struct comedi_device *dev) { BYTE b; @@ -289,17 +290,17 @@ static int board_init(struct comedi_device * dev) return 0; } -static int das6402_detach(struct comedi_device * dev) +static int das6402_detach(struct comedi_device *dev) { if (dev->irq) - comedi_free_irq(dev->irq, dev); + free_irq(dev->irq, dev); if (dev->iobase) release_region(dev->iobase, DAS6402_SIZE); return 0; } -static int das6402_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int das6402_attach(struct comedi_device *dev, struct comedi_devconfig *it) { unsigned int irq; unsigned long iobase; @@ -324,17 +325,19 @@ static int das6402_attach(struct comedi_device * dev, struct comedi_devconfig * irq = it->options[0]; printk(" ( irq = %u )", irq); - ret = comedi_request_irq(irq, intr_handler, 0, "das6402", dev); + ret = request_irq(irq, intr_handler, 0, "das6402", dev); if (ret < 0) { printk("irq conflict\n"); return ret; } dev->irq = irq; - if ((ret = alloc_private(dev, sizeof(struct das6402_private))) < 0) + ret = alloc_private(dev, sizeof(struct das6402_private)); + if (ret < 0) return ret; - if ((ret = alloc_subdevices(dev, 1)) < 0) + ret = alloc_subdevices(dev, 1); + if (ret < 0) return ret; /* ai subdevice */ @@ -342,7 +345,7 @@ static int das6402_attach(struct comedi_device * dev, struct comedi_devconfig * s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE | SDF_GROUND; s->n_chan = 8; - //s->trig[2]=das6402_ai_mode2; + /* s->trig[2]=das6402_ai_mode2; */ s->cancel = das6402_ai_cancel; s->maxdata = (1 << 12) - 1; s->len_chanlist = 16; /* ? */ diff --git a/drivers/staging/comedi/drivers/das800.c b/drivers/staging/comedi/drivers/das800.c index 7a6656bf809c..70e9d699c7a3 100644 --- a/drivers/staging/comedi/drivers/das800.c +++ b/drivers/staging/comedi/drivers/das800.c @@ -62,6 +62,7 @@ cmd triggers supported: */ +#include #include "../comedidev.h" #include @@ -72,7 +73,7 @@ cmd triggers supported: #define DAS800_SIZE 8 #define TIMER_BASE 1000 -#define N_CHAN_AI 8 // number of analog input channels +#define N_CHAN_AI 8 /* number of analog input channels */ /* Registers for the das800 */ @@ -94,8 +95,8 @@ cmd triggers supported: #define IRQ 0x8 #define BUSY 0x80 #define DAS800_GAIN 3 -#define CIO_FFOV 0x8 // fifo overflow for cio-das802/16 -#define CIO_ENHF 0x90 // interrupt fifo half full for cio-das802/16 +#define CIO_FFOV 0x8 /* fifo overflow for cio-das802/16 */ +#define CIO_ENHF 0x90 /* interrupt fifo half full for cio-das802/16 */ #define CONTROL1 0x80 #define CONV_CONTROL 0xa0 #define SCAN_LIMITS 0xc0 @@ -113,7 +114,7 @@ struct das800_board { int resolution; }; -//analog input ranges +/* analog input ranges */ static const struct comedi_lrange range_das800_ai = { 1, { @@ -184,46 +185,46 @@ enum { das800, ciodas800, das801, ciodas801, das802, ciodas802, ciodas80216 }; static const struct das800_board das800_boards[] = { { - name: "das-800", - ai_speed:25000, - ai_range:&range_das800_ai, - resolution:12, + .name = "das-800", + .ai_speed = 25000, + .ai_range = &range_das800_ai, + .resolution = 12, }, { - name: "cio-das800", - ai_speed:20000, - ai_range:&range_das800_ai, - resolution:12, + .name = "cio-das800", + .ai_speed = 20000, + .ai_range = &range_das800_ai, + .resolution = 12, }, { - name: "das-801", - ai_speed:25000, - ai_range:&range_das801_ai, - resolution:12, + .name = "das-801", + .ai_speed = 25000, + .ai_range = &range_das801_ai, + .resolution = 12, }, { - name: "cio-das801", - ai_speed:20000, - ai_range:&range_cio_das801_ai, - resolution:12, + .name = "cio-das801", + .ai_speed = 20000, + .ai_range = &range_cio_das801_ai, + .resolution = 12, }, { - name: "das-802", - ai_speed:25000, - ai_range:&range_das802_ai, - resolution:12, + .name = "das-802", + .ai_speed = 25000, + .ai_range = &range_das802_ai, + .resolution = 12, }, { - name: "cio-das802", - ai_speed:20000, - ai_range:&range_das802_ai, - resolution:12, + .name = "cio-das802", + .ai_speed = 20000, + .ai_range = &range_das802_ai, + .resolution = 12, }, { - name: "cio-das802/16", - ai_speed:10000, - ai_range:&range_das80216_ai, - resolution:16, + .name = "cio-das802/16", + .ai_speed = 10000, + .ai_range = &range_das80216_ai, + .resolution = 16, }, }; @@ -242,47 +243,47 @@ struct das800_private { #define devpriv ((struct das800_private *)dev->private) -static int das800_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int das800_detach(struct comedi_device * dev); -static int das800_cancel(struct comedi_device * dev, struct comedi_subdevice * s); +static int das800_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int das800_detach(struct comedi_device *dev); +static int das800_cancel(struct comedi_device *dev, struct comedi_subdevice *s); static struct comedi_driver driver_das800 = { - driver_name:"das800", - module:THIS_MODULE, - attach:das800_attach, - detach:das800_detach, - num_names:sizeof(das800_boards) / sizeof(struct das800_board), - board_name:&das800_boards[0].name, - offset:sizeof(struct das800_board), + .driver_name = "das800", + .module = THIS_MODULE, + .attach = das800_attach, + .detach = das800_detach, + .num_names = ARRAY_SIZE(das800_boards), + .board_name = &das800_boards[0].name, + .offset = sizeof(struct das800_board), }; -static irqreturn_t das800_interrupt(int irq, void *d PT_REGS_ARG); -static void enable_das800(struct comedi_device * dev); -static void disable_das800(struct comedi_device * dev); -static int das800_ai_do_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd); -static int das800_ai_do_cmd(struct comedi_device * dev, struct comedi_subdevice * s); -static int das800_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int das800_di_rbits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int das800_do_wbits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int das800_probe(struct comedi_device * dev); -static int das800_set_frequency(struct comedi_device * dev); +static irqreturn_t das800_interrupt(int irq, void *d); +static void enable_das800(struct comedi_device *dev); +static void disable_das800(struct comedi_device *dev); +static int das800_ai_do_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd); +static int das800_ai_do_cmd(struct comedi_device *dev, struct comedi_subdevice *s); +static int das800_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int das800_di_rbits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int das800_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int das800_probe(struct comedi_device *dev); +static int das800_set_frequency(struct comedi_device *dev); /* checks and probes das-800 series board type */ -static int das800_probe(struct comedi_device * dev) +static int das800_probe(struct comedi_device *dev) { int id_bits; unsigned long irq_flags; int board; - // 'comedi spin lock irqsave' disables even rt interrupts, we use them to protect indirect addressing - comedi_spin_lock_irqsave(&dev->spinlock, irq_flags); + /* 'comedi spin lock irqsave' disables even rt interrupts, we use them to protect indirect addressing */ + spin_lock_irqsave(&dev->spinlock, irq_flags); outb(ID, dev->iobase + DAS800_GAIN); /* select base address + 7 to be ID register */ id_bits = inb(dev->iobase + DAS800_ID) & 0x3; /* get id bits */ - comedi_spin_unlock_irqrestore(&dev->spinlock, irq_flags); + spin_unlock_irqrestore(&dev->spinlock, irq_flags); board = thisboard - das800_boards; @@ -343,7 +344,7 @@ static int das800_probe(struct comedi_device * dev) COMEDI_INITCLEANUP(driver_das800); /* interrupt service routine */ -static irqreturn_t das800_interrupt(int irq, void *d PT_REGS_ARG) +static irqreturn_t das800_interrupt(int irq, void *d) { short i; /* loop index */ short dataPoint = 0; @@ -352,8 +353,8 @@ static irqreturn_t das800_interrupt(int irq, void *d PT_REGS_ARG) struct comedi_async *async; int status; unsigned long irq_flags; - static const int max_loops = 128; // half-fifo size for cio-das802/16 - // flags + static const int max_loops = 128; /* half-fifo size for cio-das802/16 */ + /* flags */ int fifo_empty = 0; int fifo_overflow = 0; @@ -369,13 +370,13 @@ static irqreturn_t das800_interrupt(int irq, void *d PT_REGS_ARG) */ async = s->async; - // if hardware conversions are not enabled, then quit - comedi_spin_lock_irqsave(&dev->spinlock, irq_flags); + /* if hardware conversions are not enabled, then quit */ + spin_lock_irqsave(&dev->spinlock, irq_flags); outb(CONTROL1, dev->iobase + DAS800_GAIN); /* select base address + 7 to be STATUS2 register */ status = inb(dev->iobase + DAS800_STATUS2) & STATUS2_HCEN; /* don't release spinlock yet since we want to make sure noone else disables hardware conversions */ if (status == 0) { - comedi_spin_unlock_irqrestore(&dev->spinlock, irq_flags); + spin_unlock_irqrestore(&dev->spinlock, irq_flags); return IRQ_HANDLED; } @@ -390,7 +391,7 @@ static irqreturn_t das800_interrupt(int irq, void *d PT_REGS_ARG) if (fifo_overflow) break; } else { - fifo_empty = 0; // cio-das802/16 has no fifo empty status bit + fifo_empty = 0; /* cio-das802/16 has no fifo empty status bit */ } if (fifo_empty) { break; @@ -410,12 +411,12 @@ static irqreturn_t das800_interrupt(int irq, void *d PT_REGS_ARG) /* check for fifo overflow */ if (thisboard->resolution == 12) { fifo_overflow = dataPoint & FIFO_OVF; - // else cio-das802/16 + /* else cio-das802/16 */ } else { fifo_overflow = inb(dev->iobase + DAS800_GAIN) & CIO_FFOV; } if (fifo_overflow) { - comedi_spin_unlock_irqrestore(&dev->spinlock, irq_flags); + spin_unlock_irqrestore(&dev->spinlock, irq_flags); comedi_error(dev, "DAS800 FIFO overflow"); das800_cancel(dev, dev->subdevices + 0); async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; @@ -429,10 +430,10 @@ static irqreturn_t das800_interrupt(int irq, void *d PT_REGS_ARG) outb(CONTROL1, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be control register 1 */ outb(CONTROL1_INTE | devpriv->do_bits, dev->iobase + DAS800_CONTROL1); - comedi_spin_unlock_irqrestore(&dev->spinlock, irq_flags); + spin_unlock_irqrestore(&dev->spinlock, irq_flags); /* otherwise, stop taking data */ } else { - comedi_spin_unlock_irqrestore(&dev->spinlock, irq_flags); + spin_unlock_irqrestore(&dev->spinlock, irq_flags); disable_das800(dev); /* diable hardware triggered conversions */ async->events |= COMEDI_CB_EOA; } @@ -441,7 +442,7 @@ static irqreturn_t das800_interrupt(int irq, void *d PT_REGS_ARG) return IRQ_HANDLED; } -static int das800_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int das800_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; unsigned long iobase = it->options[0]; @@ -484,7 +485,7 @@ static int das800_attach(struct comedi_device * dev, struct comedi_devconfig * i return -EINVAL; } if (irq) { - if (comedi_request_irq(irq, das800_interrupt, 0, "das800", dev)) { + if (request_irq(irq, das800_interrupt, 0, "das800", dev)) { printk("unable to allocate irq %u\n", irq); return -EINVAL; } @@ -531,15 +532,15 @@ static int das800_attach(struct comedi_device * dev, struct comedi_devconfig * i disable_das800(dev); /* initialize digital out channels */ - comedi_spin_lock_irqsave(&dev->spinlock, irq_flags); + spin_lock_irqsave(&dev->spinlock, irq_flags); outb(CONTROL1, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be control register 1 */ outb(CONTROL1_INTE | devpriv->do_bits, dev->iobase + DAS800_CONTROL1); - comedi_spin_unlock_irqrestore(&dev->spinlock, irq_flags); + spin_unlock_irqrestore(&dev->spinlock, irq_flags); return 0; }; -static int das800_detach(struct comedi_device * dev) +static int das800_detach(struct comedi_device *dev) { printk("comedi%d: das800: remove\n", dev->minor); @@ -547,11 +548,11 @@ static int das800_detach(struct comedi_device * dev) if (dev->iobase) release_region(dev->iobase, DAS800_SIZE); if (dev->irq) - comedi_free_irq(dev->irq, dev); + free_irq(dev->irq, dev); return 0; }; -static int das800_cancel(struct comedi_device * dev, struct comedi_subdevice * s) +static int das800_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { devpriv->forever = 0; devpriv->count = 0; @@ -560,32 +561,32 @@ static int das800_cancel(struct comedi_device * dev, struct comedi_subdevice * s } /* enable_das800 makes the card start taking hardware triggered conversions */ -static void enable_das800(struct comedi_device * dev) +static void enable_das800(struct comedi_device *dev) { unsigned long irq_flags; - comedi_spin_lock_irqsave(&dev->spinlock, irq_flags); - // enable fifo-half full interrupts for cio-das802/16 + spin_lock_irqsave(&dev->spinlock, irq_flags); + /* enable fifo-half full interrupts for cio-das802/16 */ if (thisboard->resolution == 16) outb(CIO_ENHF, dev->iobase + DAS800_GAIN); outb(CONV_CONTROL, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be conversion control register */ outb(CONV_HCEN, dev->iobase + DAS800_CONV_CONTROL); /* enable hardware triggering */ outb(CONTROL1, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be control register 1 */ outb(CONTROL1_INTE | devpriv->do_bits, dev->iobase + DAS800_CONTROL1); /* enable card's interrupt */ - comedi_spin_unlock_irqrestore(&dev->spinlock, irq_flags); + spin_unlock_irqrestore(&dev->spinlock, irq_flags); } /* disable_das800 stops hardware triggered conversions */ -static void disable_das800(struct comedi_device * dev) +static void disable_das800(struct comedi_device *dev) { unsigned long irq_flags; - comedi_spin_lock_irqsave(&dev->spinlock, irq_flags); + spin_lock_irqsave(&dev->spinlock, irq_flags); outb(CONV_CONTROL, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be conversion control register */ outb(0x0, dev->iobase + DAS800_CONV_CONTROL); /* disable hardware triggering of conversions */ - comedi_spin_unlock_irqrestore(&dev->spinlock, irq_flags); + spin_unlock_irqrestore(&dev->spinlock, irq_flags); } -static int das800_ai_do_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd) +static int das800_ai_do_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd) { int err = 0; int tmp; @@ -684,7 +685,7 @@ static int das800_ai_do_cmdtest(struct comedi_device * dev, struct comedi_subdev if (err) return 4; - // check channel/gain list against card's limitations + /* check channel/gain list against card's limitations */ if (cmd->chanlist) { gain = CR_RANGE(cmd->chanlist[0]); startChan = CR_CHAN(cmd->chanlist[0]); @@ -709,7 +710,7 @@ static int das800_ai_do_cmdtest(struct comedi_device * dev, struct comedi_subdev return 0; } -static int das800_ai_do_cmd(struct comedi_device * dev, struct comedi_subdevice * s) +static int das800_ai_do_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { int startChan, endChan, scan, gain; int conv_bits; @@ -729,10 +730,10 @@ static int das800_ai_do_cmd(struct comedi_device * dev, struct comedi_subdevice endChan = (startChan + async->cmd.chanlist_len - 1) % 8; scan = (endChan << 3) | startChan; - comedi_spin_lock_irqsave(&dev->spinlock, irq_flags); + spin_lock_irqsave(&dev->spinlock, irq_flags); outb(SCAN_LIMITS, dev->iobase + DAS800_GAIN); /* select base address + 2 to be scan limits register */ outb(scan, dev->iobase + DAS800_SCAN_LIMITS); /* set scan limits */ - comedi_spin_unlock_irqrestore(&dev->spinlock, irq_flags); + spin_unlock_irqrestore(&dev->spinlock, irq_flags); /* set gain */ gain = CR_RANGE(async->cmd.chanlist[0]); @@ -779,17 +780,17 @@ static int das800_ai_do_cmd(struct comedi_device * dev, struct comedi_subdevice break; } - comedi_spin_lock_irqsave(&dev->spinlock, irq_flags); + spin_lock_irqsave(&dev->spinlock, irq_flags); outb(CONV_CONTROL, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be conversion control register */ outb(conv_bits, dev->iobase + DAS800_CONV_CONTROL); - comedi_spin_unlock_irqrestore(&dev->spinlock, irq_flags); + spin_unlock_irqrestore(&dev->spinlock, irq_flags); async->events = 0; enable_das800(dev); return 0; } -static int das800_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int das800_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i, n; int chan; @@ -803,10 +804,10 @@ static int das800_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * /* set multiplexer */ chan = CR_CHAN(insn->chanspec); - comedi_spin_lock_irqsave(&dev->spinlock, irq_flags); + spin_lock_irqsave(&dev->spinlock, irq_flags); outb(CONTROL1, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be control register 1 */ outb(chan | devpriv->do_bits, dev->iobase + DAS800_CONTROL1); - comedi_spin_unlock_irqrestore(&dev->spinlock, irq_flags); + spin_unlock_irqrestore(&dev->spinlock, irq_flags); /* set gain / range */ range = CR_RANGE(insn->chanspec); @@ -815,7 +816,7 @@ static int das800_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * range &= 0xf; outb(range, dev->iobase + DAS800_GAIN); - comedi_udelay(5); + udelay(5); for (n = 0; n < insn->n; n++) { /* trigger conversion */ @@ -842,8 +843,8 @@ static int das800_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * return n; } -static int das800_di_rbits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int das800_di_rbits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { unsigned int bits; @@ -855,23 +856,23 @@ static int das800_di_rbits(struct comedi_device * dev, struct comedi_subdevice * return 2; } -static int das800_do_wbits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int das800_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int wbits; unsigned long irq_flags; - // only set bits that have been masked + /* only set bits that have been masked */ data[0] &= 0xf; wbits = devpriv->do_bits >> 4; wbits &= ~data[0]; wbits |= data[0] & data[1]; devpriv->do_bits = wbits << 4; - comedi_spin_lock_irqsave(&dev->spinlock, irq_flags); + spin_lock_irqsave(&dev->spinlock, irq_flags); outb(CONTROL1, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be control register 1 */ outb(devpriv->do_bits | CONTROL1_INTE, dev->iobase + DAS800_CONTROL1); - comedi_spin_unlock_irqrestore(&dev->spinlock, irq_flags); + spin_unlock_irqrestore(&dev->spinlock, irq_flags); data[1] = wbits; @@ -879,7 +880,7 @@ static int das800_do_wbits(struct comedi_device * dev, struct comedi_subdevice * } /* loads counters with divisor1, divisor2 from private structure */ -static int das800_set_frequency(struct comedi_device * dev) +static int das800_set_frequency(struct comedi_device *dev) { int err = 0; diff --git a/drivers/staging/comedi/drivers/dmm32at.c b/drivers/staging/comedi/drivers/dmm32at.c index 829083651edc..573cbe72b20b 100644 --- a/drivers/staging/comedi/drivers/dmm32at.c +++ b/drivers/staging/comedi/drivers/dmm32at.c @@ -74,6 +74,7 @@ Configuration Options: * options that are used with comedi_config. */ +#include #include "../comedidev.h" #include @@ -114,8 +115,8 @@ Configuration Options: #define DMM32AT_DIOC 0x0e #define DMM32AT_DIOCONF 0x0f -#define dmm_inb(cdev,reg) inb((cdev->iobase)+reg) -#define dmm_outb(cdev,reg,valu) outb(valu,(cdev->iobase)+reg) +#define dmm_inb(cdev, reg) inb((cdev->iobase)+reg) +#define dmm_outb(cdev, reg, valu) outb(valu, (cdev->iobase)+reg) /* Board register values. */ @@ -213,15 +214,15 @@ struct dmm32at_board { }; static const struct dmm32at_board dmm32at_boards[] = { { - name: "dmm32at", - ai_chans:32, - ai_bits: 16, - ai_ranges:&dmm32at_airanges, - ao_chans:4, - ao_bits: 12, - ao_ranges:&dmm32at_aoranges, - have_dio:1, - dio_chans:24, + .name = "dmm32at", + .ai_chans = 32, + .ai_bits = 16, + .ai_ranges = &dmm32at_airanges, + .ao_chans = 4, + .ao_bits = 12, + .ao_ranges = &dmm32at_aoranges, + .have_dio = 1, + .dio_chans = 24, }, }; @@ -258,13 +259,13 @@ struct dmm32at_private { * the board, and also about the kernel module that contains * the device code. */ -static int dmm32at_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int dmm32at_detach(struct comedi_device * dev); +static int dmm32at_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int dmm32at_detach(struct comedi_device *dev); static struct comedi_driver driver_dmm32at = { - driver_name:"dmm32at", - module:THIS_MODULE, - attach:dmm32at_attach, - detach:dmm32at_detach, + .driver_name = "dmm32at", + .module = THIS_MODULE, + .attach = dmm32at_attach, + .detach = dmm32at_detach, /* It is not necessary to implement the following members if you are * writing a driver for a ISA PnP or PCI card */ /* Most drivers will support multiple types of boards by @@ -283,29 +284,29 @@ static struct comedi_driver driver_dmm32at = { * the type of board in software. ISA PnP, PCI, and PCMCIA * devices are such boards. */ - board_name:&dmm32at_boards[0].name, - offset:sizeof(struct dmm32at_board), - num_names:sizeof(dmm32at_boards) / sizeof(struct dmm32at_board), + .board_name = &dmm32at_boards[0].name, + .offset = sizeof(struct dmm32at_board), + .num_names = ARRAY_SIZE(dmm32at_boards), }; /* prototypes for driver functions below */ -static int dmm32at_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int dmm32at_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int dmm32at_ao_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int dmm32at_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int dmm32at_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int dmm32at_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd); -static int dmm32at_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s); -static int dmm32at_ai_cancel(struct comedi_device * dev, struct comedi_subdevice * s); +static int dmm32at_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int dmm32at_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int dmm32at_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int dmm32at_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int dmm32at_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int dmm32at_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd); +static int dmm32at_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s); +static int dmm32at_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s); static int dmm32at_ns_to_timer(unsigned int *ns, int round); -static irqreturn_t dmm32at_isr(int irq, void *d PT_REGS_ARG); -void dmm32at_setaitimer(struct comedi_device * dev, unsigned int nansec); +static irqreturn_t dmm32at_isr(int irq, void *d); +void dmm32at_setaitimer(struct comedi_device *dev, unsigned int nansec); /* * Attach is called by the Comedi core to configure the driver @@ -313,7 +314,7 @@ void dmm32at_setaitimer(struct comedi_device * dev, unsigned int nansec); * in the driver structure, dev->board_ptr contains that * address. */ -static int dmm32at_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int dmm32at_attach(struct comedi_device *dev, struct comedi_devconfig *it) { int ret; struct comedi_subdevice *s; @@ -380,8 +381,7 @@ static int dmm32at_attach(struct comedi_device * dev, struct comedi_devconfig * /* board is there, register interrupt */ if (irq) { - ret = comedi_request_irq(irq, dmm32at_isr, 0, thisboard->name, - dev); + ret = request_irq(irq, dmm32at_isr, 0, thisboard->name, dev); if (ret < 0) { printk("irq conflict\n"); return ret; @@ -394,7 +394,7 @@ static int dmm32at_attach(struct comedi_device * dev, struct comedi_devconfig * * it is, this is the place to do it. Otherwise, dev->board_ptr * should already be initialized. */ - //dev->board_ptr = dmm32at_probe(dev); + /* dev->board_ptr = dmm32at_probe(dev); */ /* * Initialize dev->board_name. Note that we can use the "thisboard" @@ -481,11 +481,11 @@ static int dmm32at_attach(struct comedi_device * dev, struct comedi_devconfig * * allocated by _attach(). dev->private and dev->subdevices are * deallocated automatically by the core. */ -static int dmm32at_detach(struct comedi_device * dev) +static int dmm32at_detach(struct comedi_device *dev) { printk("comedi%d: dmm32at: remove\n", dev->minor); if (dev->irq) - comedi_free_irq(dev->irq, dev); + free_irq(dev->irq, dev); if (dev->iobase) release_region(dev->iobase, DMM32AT_MEMSIZE); @@ -497,8 +497,8 @@ static int dmm32at_detach(struct comedi_device * dev) * mode. */ -static int dmm32at_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int dmm32at_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int n, i; unsigned int d; @@ -512,7 +512,7 @@ static int dmm32at_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice chan = CR_CHAN(insn->chanspec) & (s->n_chan - 1); range = CR_RANGE(insn->chanspec); - //printk("channel=0x%02x, range=%d\n",chan,range); + /* printk("channel=0x%02x, range=%d\n",chan,range); */ /* zero scan and fifo control and reset fifo */ dmm_outb(dev, DMM32AT_FIFOCNTRL, DMM32AT_FIFORESET); @@ -568,14 +568,14 @@ static int dmm32at_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice return n; } -static int dmm32at_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd) +static int dmm32at_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd) { int err = 0; int tmp; int start_chan, gain, i; - //printk("dmmat32 in command test\n"); + /* printk("dmmat32 in command test\n"); */ /* cmdtest tests a particular command to see if it is valid. * Using the cmdtest ioctl, a user can create a valid cmd @@ -752,7 +752,7 @@ static int dmm32at_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevic return 0; } -static int dmm32at_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s) +static int dmm32at_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { struct comedi_cmd *cmd = &s->async->cmd; int i, range; @@ -822,13 +822,13 @@ static int dmm32at_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * } -static int dmm32at_ai_cancel(struct comedi_device * dev, struct comedi_subdevice * s) +static int dmm32at_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { devpriv->ai_scans_left = 1; return 0; } -static irqreturn_t dmm32at_isr(int irq, void *d PT_REGS_ARG) +static irqreturn_t dmm32at_isr(int irq, void *d) { unsigned char intstat; unsigned int samp; @@ -893,8 +893,8 @@ static int dmm32at_ns_to_timer(unsigned int *ns, int round) return *ns; } -static int dmm32at_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int dmm32at_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i; int chan = CR_CHAN(insn->chanspec); @@ -910,7 +910,7 @@ static int dmm32at_ao_winsn(struct comedi_device * dev, struct comedi_subdevice lo = data[i] & 0x00ff; /* high byte also contains channel number */ hi = (data[i] >> 8) + chan * (1 << 6); - //printk("writing 0x%02x 0x%02x\n",hi,lo); + /* printk("writing 0x%02x 0x%02x\n",hi,lo); */ /* write the low and high values to the board */ dmm_outb(dev, DMM32AT_DACLSB, lo); dmm_outb(dev, DMM32AT_DACMSB, hi); @@ -936,8 +936,8 @@ static int dmm32at_ao_winsn(struct comedi_device * dev, struct comedi_subdevice /* AO subdevices should have a read insn as well as a write insn. * Usually this means copying a value stored in devpriv. */ -static int dmm32at_ao_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int dmm32at_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i; int chan = CR_CHAN(insn->chanspec); @@ -953,8 +953,8 @@ static int dmm32at_ao_rinsn(struct comedi_device * dev, struct comedi_subdevice * useful to applications if you implement the insn_bits interface. * This allows packed reading/writing of the DIO channels. The * comedi core can convert between insn_bits and insn_read/write */ -static int dmm32at_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int dmm32at_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { unsigned char diobits; @@ -967,7 +967,7 @@ static int dmm32at_dio_insn_bits(struct comedi_device * dev, struct comedi_subde s->state &= ~data[0]; s->state |= data[0] & data[1]; /* Write out the new digital output lines */ - //outw(s->state,dev->iobase + DMM32AT_DIO); + /* outw(s->state,dev->iobase + DMM32AT_DIO); */ } /* get access to the DIO regs */ @@ -998,16 +998,16 @@ static int dmm32at_dio_insn_bits(struct comedi_device * dev, struct comedi_subde /* on return, data[1] contains the value of the digital * input and output lines. */ - //data[1]=inw(dev->iobase + DMM32AT_DIO); + /* data[1]=inw(dev->iobase + DMM32AT_DIO); */ /* or we could just return the software copy of the output values if * it was a purely digital output subdevice */ - //data[1]=s->state; + /* data[1]=s->state; */ return 2; } -static int dmm32at_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int dmm32at_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { unsigned char chanbit; int chan = CR_CHAN(insn->chanspec); @@ -1043,7 +1043,7 @@ static int dmm32at_dio_insn_config(struct comedi_device * dev, struct comedi_sub return 1; } -void dmm32at_setaitimer(struct comedi_device * dev, unsigned int nansec) +void dmm32at_setaitimer(struct comedi_device *dev, unsigned int nansec) { unsigned char lo1, lo2, hi2; unsigned short both2; diff --git a/drivers/staging/comedi/drivers/dt2801.c b/drivers/staging/comedi/drivers/dt2801.c index 5e0eed835d1a..25a9b213b6f1 100644 --- a/drivers/staging/comedi/drivers/dt2801.c +++ b/drivers/staging/comedi/drivers/dt2801.c @@ -88,19 +88,19 @@ Configuration options: #define DT2801_STATUS 1 #define DT2801_CMD 1 -static int dt2801_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int dt2801_detach(struct comedi_device * dev); +static int dt2801_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int dt2801_detach(struct comedi_device *dev); static struct comedi_driver driver_dt2801 = { - driver_name:"dt2801", - module:THIS_MODULE, - attach:dt2801_attach, - detach:dt2801_detach, + .driver_name = "dt2801", + .module = THIS_MODULE, + .attach = dt2801_attach, + .detach = dt2801_detach, }; COMEDI_INITCLEANUP(driver_dt2801); #if 0 -// ignore 'defined but not used' warning +/* ignore 'defined but not used' warning */ static const struct comedi_lrange range_dt2801_ai_pgh_bipolar = { 4, { RANGE(-10, 10), RANGE(-5, 5), @@ -118,7 +118,7 @@ static const struct comedi_lrange range_dt2801_ai_pgl_bipolar = { 4, { }; #if 0 -// ignore 'defined but not used' warning +/* ignore 'defined but not used' warning */ static const struct comedi_lrange range_dt2801_ai_pgh_unipolar = { 4, { RANGE(0, 10), RANGE(0, 5), @@ -152,72 +152,71 @@ struct dt2801_board { */ static const struct dt2801_board boardtypes[] = { { - name: "dt2801", - boardcode:0x09, - ad_diff: 2, - ad_chan: 16, - adbits: 12, - adrangetype:0, - dabits: 12}, + .name = "dt2801", + .boardcode = 0x09, + .ad_diff = 2, + .ad_chan = 16, + .adbits = 12, + .adrangetype = 0, + .dabits = 12}, { - name: "dt2801-a", - boardcode:0x52, - ad_diff: 2, - ad_chan: 16, - adbits: 12, - adrangetype:0, - dabits: 12}, + .name = "dt2801-a", + .boardcode = 0x52, + .ad_diff = 2, + .ad_chan = 16, + .adbits = 12, + .adrangetype = 0, + .dabits = 12}, { - name: "dt2801/5716a", - boardcode:0x82, - ad_diff: 1, - ad_chan: 16, - adbits: 16, - adrangetype:1, - dabits: 12}, + .name = "dt2801/5716a", + .boardcode = 0x82, + .ad_diff = 1, + .ad_chan = 16, + .adbits = 16, + .adrangetype = 1, + .dabits = 12}, { - name: "dt2805", - boardcode:0x12, - ad_diff: 1, - ad_chan: 16, - adbits: 12, - adrangetype:0, - dabits: 12}, + .name = "dt2805", + .boardcode = 0x12, + .ad_diff = 1, + .ad_chan = 16, + .adbits = 12, + .adrangetype = 0, + .dabits = 12}, { - name: "dt2805/5716a", - boardcode:0x92, - ad_diff: 1, - ad_chan: 16, - adbits: 16, - adrangetype:1, - dabits: 12}, + .name = "dt2805/5716a", + .boardcode = 0x92, + .ad_diff = 1, + .ad_chan = 16, + .adbits = 16, + .adrangetype = 1, + .dabits = 12}, { - name: "dt2808", - boardcode:0x20, - ad_diff: 0, - ad_chan: 16, - adbits: 12, - adrangetype:2, - dabits: 8}, + .name = "dt2808", + .boardcode = 0x20, + .ad_diff = 0, + .ad_chan = 16, + .adbits = 12, + .adrangetype = 2, + .dabits = 8}, { - name: "dt2818", - boardcode:0xa2, - ad_diff: 0, - ad_chan: 4, - adbits: 12, - adrangetype:0, - dabits: 12}, + .name = "dt2818", + .boardcode = 0xa2, + .ad_diff = 0, + .ad_chan = 4, + .adbits = 12, + .adrangetype = 0, + .dabits = 12}, { - name: "dt2809", - boardcode:0xb0, - ad_diff: 0, - ad_chan: 8, - adbits: 12, - adrangetype:1, - dabits: 12}, + .name = "dt2809", + .boardcode = 0xb0, + .ad_diff = 0, + .ad_chan = 8, + .adbits = 12, + .adrangetype = 1, + .dabits = 12}, }; -#define n_boardtypes ((sizeof(boardtypes))/(sizeof(boardtypes[0]))) #define boardtype (*(const struct dt2801_board *)dev->board_ptr) struct dt2801_private { @@ -228,16 +227,16 @@ struct dt2801_private { #define devpriv ((struct dt2801_private *)dev->private) -static int dt2801_ai_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int dt2801_ao_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int dt2801_ao_insn_write(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int dt2801_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int dt2801_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); +static int dt2801_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int dt2801_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int dt2801_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int dt2801_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int dt2801_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); /* These are the low-level routines: writecommand: write a command to the board @@ -248,7 +247,7 @@ static int dt2801_dio_insn_config(struct comedi_device * dev, struct comedi_subd /* Only checks DataOutReady-flag, not the Ready-flag as it is done in the examples of the manual. I don't see why this should be necessary. */ -static int dt2801_readdata(struct comedi_device * dev, int *data) +static int dt2801_readdata(struct comedi_device *dev, int *data) { int stat = 0; int timeout = DT2801_TIMEOUT; @@ -267,7 +266,7 @@ static int dt2801_readdata(struct comedi_device * dev, int *data) return -ETIME; } -static int dt2801_readdata2(struct comedi_device * dev, int *data) +static int dt2801_readdata2(struct comedi_device *dev, int *data) { int lb, hb; int ret; @@ -283,7 +282,7 @@ static int dt2801_readdata2(struct comedi_device * dev, int *data) return 0; } -static int dt2801_writedata(struct comedi_device * dev, unsigned int data) +static int dt2801_writedata(struct comedi_device *dev, unsigned int data) { int stat = 0; int timeout = DT2801_TIMEOUT; @@ -309,7 +308,7 @@ static int dt2801_writedata(struct comedi_device * dev, unsigned int data) return -ETIME; } -static int dt2801_writedata2(struct comedi_device * dev, unsigned int data) +static int dt2801_writedata2(struct comedi_device *dev, unsigned int data) { int ret; @@ -323,7 +322,7 @@ static int dt2801_writedata2(struct comedi_device * dev, unsigned int data) return 0; } -static int dt2801_wait_for_ready(struct comedi_device * dev) +static int dt2801_wait_for_ready(struct comedi_device *dev) { int timeout = DT2801_TIMEOUT; int stat; @@ -346,7 +345,7 @@ static int dt2801_wait_for_ready(struct comedi_device * dev) return -ETIME; } -static int dt2801_writecmd(struct comedi_device * dev, int command) +static int dt2801_writecmd(struct comedi_device *dev, int command) { int stat; @@ -364,7 +363,7 @@ static int dt2801_writecmd(struct comedi_device * dev, int command) return 0; } -static int dt2801_reset(struct comedi_device * dev) +static int dt2801_reset(struct comedi_device *dev) { int board_code = 0; unsigned int stat; @@ -381,11 +380,11 @@ static int dt2801_reset(struct comedi_device * dev) inb_p(dev->iobase + DT2801_DATA); DPRINTK("dt2801: stop\n"); - //dt2801_writecmd(dev,DT_C_STOP); + /* dt2801_writecmd(dev,DT_C_STOP); */ outb_p(DT_C_STOP, dev->iobase + DT2801_CMD); - //dt2801_wait_for_ready(dev); - comedi_udelay(100); + /* dt2801_wait_for_ready(dev); */ + udelay(100); timeout = 10000; do { stat = inb_p(dev->iobase + DT2801_STATUS); @@ -395,14 +394,15 @@ static int dt2801_reset(struct comedi_device * dev) if (!timeout) { printk("dt2801: timeout 1 status=0x%02x\n", stat); } - //printk("dt2801: reading dummy\n"); - //dt2801_readdata(dev,&board_code); + + /* printk("dt2801: reading dummy\n"); */ + /* dt2801_readdata(dev,&board_code); */ DPRINTK("dt2801: reset\n"); outb_p(DT_C_RESET, dev->iobase + DT2801_CMD); - //dt2801_writecmd(dev,DT_C_RESET); + /* dt2801_writecmd(dev,DT_C_RESET); */ - comedi_udelay(100); + udelay(100); timeout = 10000; do { stat = inb_p(dev->iobase + DT2801_STATUS); @@ -421,7 +421,7 @@ static int dt2801_reset(struct comedi_device * dev) return board_code; } -static int probe_number_of_ai_chans(struct comedi_device * dev) +static int probe_number_of_ai_chans(struct comedi_device *dev) { int n_chans; int stat; @@ -482,7 +482,7 @@ static const struct comedi_lrange *ai_range_lkup(int type, int opt) [4] - dac0 range 0=[-10,10], 1=[-5,5], 2=[-2.5,2.5] 3=[0,10], 4=[0,5] [5] - dac1 range 0=[-10,10], 1=[-5,5], 2=[-2.5,2.5] 3=[0,10], 4=[0,5] */ -static int dt2801_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int dt2801_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; unsigned long iobase; @@ -505,7 +505,7 @@ static int dt2801_attach(struct comedi_device * dev, struct comedi_devconfig * i if (!board_code) board_code = dt2801_reset(dev); - for (type = 0; type < n_boardtypes; type++) { + for (type = 0; type < ARRAY_SIZE(boardtypes); type++) { if (boardtypes[type].boardcode == board_code) goto havetype; } @@ -520,10 +520,12 @@ static int dt2801_attach(struct comedi_device * dev, struct comedi_devconfig * i n_ai_chans = probe_number_of_ai_chans(dev); printk(" (ai channels = %d)", n_ai_chans); - if ((ret = alloc_subdevices(dev, 4)) < 0) + ret = alloc_subdevices(dev, 4); + if (ret < 0) goto out; - if ((ret = alloc_private(dev, sizeof(struct dt2801_private))) < 0) + ret = alloc_private(dev, sizeof(struct dt2801_private)); + if (ret < 0) goto out; dev->board_name = boardtype.name; @@ -583,7 +585,7 @@ static int dt2801_attach(struct comedi_device * dev, struct comedi_devconfig * i return ret; } -static int dt2801_detach(struct comedi_device * dev) +static int dt2801_detach(struct comedi_device *dev) { if (dev->iobase) release_region(dev->iobase, DT2801_IOSIZE); @@ -591,7 +593,7 @@ static int dt2801_detach(struct comedi_device * dev) return 0; } -static int dt2801_error(struct comedi_device * dev, int stat) +static int dt2801_error(struct comedi_device *dev, int stat) { if (stat < 0) { if (stat == -ETIME) { @@ -609,8 +611,8 @@ static int dt2801_error(struct comedi_device * dev, int stat) return -EIO; } -static int dt2801_ai_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int dt2801_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int d; int stat; @@ -631,16 +633,16 @@ static int dt2801_ai_insn_read(struct comedi_device * dev, struct comedi_subdevi return i; } -static int dt2801_ao_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int dt2801_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { data[0] = devpriv->ao_readback[CR_CHAN(insn->chanspec)]; return 1; } -static int dt2801_ao_insn_write(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int dt2801_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { dt2801_writecmd(dev, DT_C_WRITE_DAIM); dt2801_writedata(dev, CR_CHAN(insn->chanspec)); @@ -651,8 +653,8 @@ static int dt2801_ao_insn_write(struct comedi_device * dev, struct comedi_subdev return 1; } -static int dt2801_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int dt2801_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int which = 0; @@ -675,8 +677,8 @@ static int dt2801_dio_insn_bits(struct comedi_device * dev, struct comedi_subdev return 2; } -static int dt2801_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int dt2801_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int which = 0; diff --git a/drivers/staging/comedi/drivers/dt2811.c b/drivers/staging/comedi/drivers/dt2811.c index 795932ec67d3..7853902be621 100644 --- a/drivers/staging/comedi/drivers/dt2811.c +++ b/drivers/staging/comedi/drivers/dt2811.c @@ -45,6 +45,7 @@ Configuration options: [4] - D/A 1 range (same choices) */ +#include #include "../comedidev.h" #include @@ -214,30 +215,30 @@ static const struct dt2811_board boardtypes[] = { #define this_board ((const struct dt2811_board *)dev->board_ptr) -static int dt2811_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int dt2811_detach(struct comedi_device * dev); +static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int dt2811_detach(struct comedi_device *dev); static struct comedi_driver driver_dt2811 = { - driver_name:"dt2811", - module:THIS_MODULE, - attach:dt2811_attach, - detach:dt2811_detach, - board_name:&boardtypes[0].name, - num_names:sizeof(boardtypes) / sizeof(struct dt2811_board), - offset:sizeof(struct dt2811_board), + .driver_name = "dt2811", + .module = THIS_MODULE, + .attach = dt2811_attach, + .detach = dt2811_detach, + .board_name = &boardtypes[0].name, + .num_names = ARRAY_SIZE(boardtypes), + .offset = sizeof(struct dt2811_board), }; COMEDI_INITCLEANUP(driver_dt2811); -static int dt2811_ai_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int dt2811_ao_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int dt2811_ao_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int dt2811_di_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int dt2811_do_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); +static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int dt2811_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int dt2811_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int dt2811_di_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int dt2811_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); enum { card_2811_pgh, card_2811_pgl }; @@ -265,7 +266,7 @@ static const struct comedi_lrange *dac_range_types[] = { #define DT2811_TIMEOUT 5 #if 0 -static irqreturn_t dt2811_interrupt(int irq, void *d PT_REGS_ARG) +static irqreturn_t dt2811_interrupt(int irq, void *d) { int lo, hi; int data; @@ -311,11 +312,12 @@ static irqreturn_t dt2811_interrupt(int irq, void *d PT_REGS_ARG) 2 == unipolar 5V (0V -- +5V) */ -static int dt2811_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - //int i, irq; - //unsigned long irqs; - //long flags; + /* int i, irq; */ + /* unsigned long irqs; */ + /* long flags; */ + int ret; struct comedi_subdevice *s; unsigned long iobase; @@ -334,7 +336,7 @@ static int dt2811_attach(struct comedi_device * dev, struct comedi_devconfig * i #if 0 outb(0, dev->iobase + DT2811_ADCSR); - comedi_udelay(100); + udelay(100); i = inb(dev->iobase + DT2811_ADDATLO); i = inb(dev->iobase + DT2811_ADDATHI); #endif @@ -350,7 +352,7 @@ static int dt2811_attach(struct comedi_device * dev, struct comedi_devconfig * i dev->iobase + DT2811_ADCSR); outb(0, dev->iobase + DT2811_ADGCR); - comedi_udelay(100); + udelay(100); irq = probe_irq_off(irqs); restore_flags(flags); @@ -365,7 +367,7 @@ static int dt2811_attach(struct comedi_device * dev, struct comedi_devconfig * i i = inb(dev->iobase + DT2811_ADDATLO); i = inb(dev->iobase + DT2811_ADDATHI); printk("(irq = %d)\n", irq); - ret = comedi_request_irq(irq, dt2811_interrupt, 0, + ret = request_irq(irq, dt2811_interrupt, 0, driver_name, dev); if (ret < 0) return -EIO; @@ -378,10 +380,14 @@ static int dt2811_attach(struct comedi_device * dev, struct comedi_devconfig * i } #endif - if ((ret = alloc_subdevices(dev, 4)) < 0) + ret = alloc_subdevices(dev, 4); + if (ret < 0) return ret; - if ((ret = alloc_private(dev, sizeof(struct dt2811_private))) < 0) + + ret = alloc_private(dev, sizeof(struct dt2811_private)); + if (ret < 0) return ret; + switch (it->options[2]) { case 0: devpriv->adc_mux = adc_singleended; @@ -479,12 +485,12 @@ static int dt2811_attach(struct comedi_device * dev, struct comedi_devconfig * i return 0; } -static int dt2811_detach(struct comedi_device * dev) +static int dt2811_detach(struct comedi_device *dev) { printk("comedi%d: dt2811: remove\n", dev->minor); if (dev->irq) { - comedi_free_irq(dev->irq, dev); + free_irq(dev->irq, dev); } if (dev->iobase) { release_region(dev->iobase, DT2811_SIZE); @@ -493,8 +499,8 @@ static int dt2811_detach(struct comedi_device * dev) return 0; } -static int dt2811_ai_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int chan = CR_CHAN(insn->chanspec); int timeout = DT2811_TIMEOUT; @@ -520,7 +526,7 @@ static int dt2811_ai_insn(struct comedi_device * dev, struct comedi_subdevice * #if 0 /* Wow. This is code from the Comedi stone age. But it hasn't been * replaced, so I'll let it stay. */ -int dt2811_adtrig(kdev_t minor, comedi_adtrig * adtrig) +int dt2811_adtrig(kdev_t minor, comedi_adtrig *adtrig) { struct comedi_device *dev = comedi_devices + minor; @@ -531,7 +537,7 @@ int dt2811_adtrig(kdev_t minor, comedi_adtrig * adtrig) case COMEDI_MDEMAND: dev->ntrig = adtrig->n - 1; /*printk("dt2811: AD soft trigger\n"); */ - /*outb(DT2811_CLRERROR|DT2811_INTENB,dev->iobase+DT2811_ADCSR); *//* not neccessary */ + /*outb(DT2811_CLRERROR|DT2811_INTENB,dev->iobase+DT2811_ADCSR); */ /* not neccessary */ outb(dev->curadchan, dev->iobase + DT2811_ADGCR); do_gettimeofday(&trigtime); break; @@ -544,8 +550,8 @@ int dt2811_adtrig(kdev_t minor, comedi_adtrig * adtrig) } #endif -static int dt2811_ao_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int dt2811_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i; int chan; @@ -562,8 +568,8 @@ static int dt2811_ao_insn(struct comedi_device * dev, struct comedi_subdevice * return i; } -static int dt2811_ao_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int dt2811_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i; int chan; @@ -577,8 +583,8 @@ static int dt2811_ao_insn_read(struct comedi_device * dev, struct comedi_subdevi return i; } -static int dt2811_di_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int dt2811_di_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if (insn->n != 2) return -EINVAL; @@ -588,8 +594,8 @@ static int dt2811_di_insn_bits(struct comedi_device * dev, struct comedi_subdevi return 2; } -static int dt2811_do_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int dt2811_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if (insn->n != 2) return -EINVAL; diff --git a/drivers/staging/comedi/drivers/dt2814.c b/drivers/staging/comedi/drivers/dt2814.c index 8320139160a4..5906ddddf65c 100644 --- a/drivers/staging/comedi/drivers/dt2814.c +++ b/drivers/staging/comedi/drivers/dt2814.c @@ -39,6 +39,7 @@ a power of 10, from 1 to 10^7, of which only 3 or 4 are useful. In addition, the clock does not seem to be very accurate. */ +#include #include "../comedidev.h" #include @@ -59,18 +60,18 @@ addition, the clock does not seem to be very accurate. #define DT2814_ENB 0x10 #define DT2814_CHANMASK 0x0f -static int dt2814_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int dt2814_detach(struct comedi_device * dev); +static int dt2814_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int dt2814_detach(struct comedi_device *dev); static struct comedi_driver driver_dt2814 = { - driver_name:"dt2814", - module:THIS_MODULE, - attach:dt2814_attach, - detach:dt2814_detach, + .driver_name = "dt2814", + .module = THIS_MODULE, + .attach = dt2814_attach, + .detach = dt2814_detach, }; COMEDI_INITCLEANUP(driver_dt2814); -static irqreturn_t dt2814_interrupt(int irq, void *dev PT_REGS_ARG); +static irqreturn_t dt2814_interrupt(int irq, void *dev); struct dt2814_private { @@ -83,8 +84,8 @@ struct dt2814_private { #define DT2814_TIMEOUT 10 #define DT2814_MAX_SPEED 100000 /* Arbitrary 10 khz limit */ -static int dt2814_ai_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int dt2814_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int n, i, hi, lo; int chan; @@ -97,7 +98,7 @@ static int dt2814_ai_insn_read(struct comedi_device * dev, struct comedi_subdevi for (i = 0; i < DT2814_TIMEOUT; i++) { status = inb(dev->iobase + DT2814_CSR); printk("dt2814: status: %02x\n", status); - comedi_udelay(10); + udelay(10); if (status & DT2814_FINISH) break; } @@ -134,8 +135,8 @@ static int dt2814_ns_to_timer(unsigned int *ns, unsigned int flags) return i; } -static int dt2814_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd) +static int dt2814_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd) { int err = 0; int tmp; @@ -226,7 +227,7 @@ static int dt2814_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice return 0; } -static int dt2814_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s) +static int dt2814_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { struct comedi_cmd *cmd = &s->async->cmd; int chan; @@ -245,7 +246,7 @@ static int dt2814_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s } -static int dt2814_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int dt2814_attach(struct comedi_device *dev, struct comedi_devconfig *it) { int i, irq; int ret; @@ -262,7 +263,7 @@ static int dt2814_attach(struct comedi_device * dev, struct comedi_devconfig * i dev->board_name = "dt2814"; outb(0, dev->iobase + DT2814_CSR); - comedi_udelay(100); + udelay(100); if (inb(dev->iobase + DT2814_CSR) & DT2814_ERR) { printk("reset error (fatal)\n"); return -EIO; @@ -279,7 +280,7 @@ static int dt2814_attach(struct comedi_device * dev, struct comedi_devconfig * i outb(0, dev->iobase + DT2814_CSR); - comedi_udelay(100); + udelay(100); irq = probe_irq_off(irqs); restore_flags(flags); @@ -293,7 +294,7 @@ static int dt2814_attach(struct comedi_device * dev, struct comedi_devconfig * i #endif dev->irq = 0; if (irq > 0) { - if (comedi_request_irq(irq, dt2814_interrupt, 0, "dt2814", dev)) { + if (request_irq(irq, dt2814_interrupt, 0, "dt2814", dev)) { printk("(irq %d unavailable)\n", irq); } else { printk("( irq = %d )\n", irq); @@ -309,9 +310,12 @@ static int dt2814_attach(struct comedi_device * dev, struct comedi_devconfig * i #endif } - if ((ret = alloc_subdevices(dev, 1)) < 0) + ret = alloc_subdevices(dev, 1); + if (ret < 0) return ret; - if ((ret = alloc_private(dev, sizeof(struct dt2814_private))) < 0) + + ret = alloc_private(dev, sizeof(struct dt2814_private)); + if (ret < 0) return ret; s = dev->subdevices + 0; @@ -329,12 +333,12 @@ static int dt2814_attach(struct comedi_device * dev, struct comedi_devconfig * i return 0; } -static int dt2814_detach(struct comedi_device * dev) +static int dt2814_detach(struct comedi_device *dev) { printk("comedi%d: dt2814: remove\n", dev->minor); if (dev->irq) { - comedi_free_irq(dev->irq, dev); + free_irq(dev->irq, dev); } if (dev->iobase) { release_region(dev->iobase, DT2814_SIZE); @@ -343,7 +347,7 @@ static int dt2814_detach(struct comedi_device * dev) return 0; } -static irqreturn_t dt2814_interrupt(int irq, void *d PT_REGS_ARG) +static irqreturn_t dt2814_interrupt(int irq, void *d) { int lo, hi; struct comedi_device *dev = d; diff --git a/drivers/staging/comedi/drivers/dt2815.c b/drivers/staging/comedi/drivers/dt2815.c index fccec8a77d50..b42dec60e1b7 100644 --- a/drivers/staging/comedi/drivers/dt2815.c +++ b/drivers/staging/comedi/drivers/dt2815.c @@ -75,18 +75,18 @@ static const struct comedi_lrange range_dt2815_ao_20_current = { 1, { #define DT2815_DATA 0 #define DT2815_STATUS 1 -static int dt2815_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int dt2815_detach(struct comedi_device * dev); +static int dt2815_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int dt2815_detach(struct comedi_device *dev); static struct comedi_driver driver_dt2815 = { - driver_name:"dt2815", - module:THIS_MODULE, - attach:dt2815_attach, - detach:dt2815_detach, + .driver_name = "dt2815", + .module = THIS_MODULE, + .attach = dt2815_attach, + .detach = dt2815_detach, }; COMEDI_INITCLEANUP(driver_dt2815); -static void dt2815_free_resources(struct comedi_device * dev); +static void dt2815_free_resources(struct comedi_device *dev); struct dt2815_private { @@ -97,7 +97,7 @@ struct dt2815_private { #define devpriv ((struct dt2815_private *)dev->private) -static int dt2815_wait_for_status(struct comedi_device * dev, int status) +static int dt2815_wait_for_status(struct comedi_device *dev, int status) { int i; @@ -108,8 +108,8 @@ static int dt2815_wait_for_status(struct comedi_device * dev, int status) return status; } -static int dt2815_ao_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int dt2815_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i; int chan = CR_CHAN(insn->chanspec); @@ -121,8 +121,8 @@ static int dt2815_ao_insn_read(struct comedi_device * dev, struct comedi_subdevi return i; } -static int dt2815_ao_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int dt2815_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i; int chan = CR_CHAN(insn->chanspec); @@ -135,7 +135,7 @@ static int dt2815_ao_insn(struct comedi_device * dev, struct comedi_subdevice * status = dt2815_wait_for_status(dev, 0x00); if (status != 0) { - rt_printk + printk ("dt2815: failed to write low byte on %d reason %x\n", chan, status); return -EBUSY; @@ -145,7 +145,7 @@ static int dt2815_ao_insn(struct comedi_device * dev, struct comedi_subdevice * status = dt2815_wait_for_status(dev, 0x10); if (status != 0x10) { - rt_printk + printk ("dt2815: failed to write high byte on %d reason %x\n", chan, status); return -EBUSY; @@ -179,7 +179,7 @@ static int dt2815_ao_insn(struct comedi_device * dev, struct comedi_subdevice * 1 == current */ -static int dt2815_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int dt2815_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; int i; @@ -226,7 +226,7 @@ static int dt2815_attach(struct comedi_device * dev, struct comedi_devconfig * i /* This is incredibly slow (approx 20 ms) */ unsigned int status; - comedi_udelay(1000); + udelay(1000); status = inb(dev->iobase + DT2815_STATUS); if (status == 4) { unsigned int program; @@ -248,13 +248,13 @@ static int dt2815_attach(struct comedi_device * dev, struct comedi_devconfig * i return 0; } -static void dt2815_free_resources(struct comedi_device * dev) +static void dt2815_free_resources(struct comedi_device *dev) { if (dev->iobase) release_region(dev->iobase, DT2815_SIZE); } -static int dt2815_detach(struct comedi_device * dev) +static int dt2815_detach(struct comedi_device *dev) { printk("comedi%d: dt2815: remove\n", dev->minor); diff --git a/drivers/staging/comedi/drivers/dt2817.c b/drivers/staging/comedi/drivers/dt2817.c index 2dc396a44e6f..b36f85632f87 100644 --- a/drivers/staging/comedi/drivers/dt2817.c +++ b/drivers/staging/comedi/drivers/dt2817.c @@ -47,19 +47,19 @@ Configuration options: #define DT2817_CR 0 #define DT2817_DATA 1 -static int dt2817_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int dt2817_detach(struct comedi_device * dev); +static int dt2817_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int dt2817_detach(struct comedi_device *dev); static struct comedi_driver driver_dt2817 = { - driver_name:"dt2817", - module:THIS_MODULE, - attach:dt2817_attach, - detach:dt2817_detach, + .driver_name = "dt2817", + .module = THIS_MODULE, + .attach = dt2817_attach, + .detach = dt2817_detach, }; COMEDI_INITCLEANUP(driver_dt2817); -static int dt2817_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int dt2817_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int mask; int chan; @@ -96,8 +96,8 @@ static int dt2817_dio_insn_config(struct comedi_device * dev, struct comedi_subd return 1; } -static int dt2817_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int dt2817_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { unsigned int changed; @@ -131,7 +131,7 @@ static int dt2817_dio_insn_bits(struct comedi_device * dev, struct comedi_subdev return 2; } -static int dt2817_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int dt2817_attach(struct comedi_device *dev, struct comedi_devconfig *it) { int ret; struct comedi_subdevice *s; @@ -146,7 +146,8 @@ static int dt2817_attach(struct comedi_device * dev, struct comedi_devconfig * i dev->iobase = iobase; dev->board_name = "dt2817"; - if ((ret = alloc_subdevices(dev, 1)) < 0) + ret = alloc_subdevices(dev, 1); + if (ret < 0) return ret; s = dev->subdevices + 0; @@ -167,7 +168,7 @@ static int dt2817_attach(struct comedi_device * dev, struct comedi_devconfig * i return 0; } -static int dt2817_detach(struct comedi_device * dev) +static int dt2817_detach(struct comedi_device *dev) { printk("comedi%d: dt2817: remove\n", dev->minor); diff --git a/drivers/staging/comedi/drivers/dt282x.c b/drivers/staging/comedi/drivers/dt282x.c index 4882c3e679cc..22b7304af396 100644 --- a/drivers/staging/comedi/drivers/dt282x.c +++ b/drivers/staging/comedi/drivers/dt282x.c @@ -209,132 +209,132 @@ struct dt282x_board { }; static const struct dt282x_board boardtypes[] = { - {name:"dt2821", - adbits: 12, - adchan_se:16, - adchan_di:8, - ai_speed:20000, - ispgl: 0, - dachan: 2, - dabits: 12, - }, - {name:"dt2821-f", - adbits: 12, - adchan_se:16, - adchan_di:8, - ai_speed:6500, - ispgl: 0, - dachan: 2, - dabits: 12, - }, - {name:"dt2821-g", - adbits: 12, - adchan_se:16, - adchan_di:8, - ai_speed:4000, - ispgl: 0, - dachan: 2, - dabits: 12, - }, - {name:"dt2823", - adbits: 16, - adchan_se:0, - adchan_di:4, - ai_speed:10000, - ispgl: 0, - dachan: 2, - dabits: 16, - }, - {name:"dt2824-pgh", - adbits: 12, - adchan_se:16, - adchan_di:8, - ai_speed:20000, - ispgl: 0, - dachan: 0, - dabits: 0, - }, - {name:"dt2824-pgl", - adbits: 12, - adchan_se:16, - adchan_di:8, - ai_speed:20000, - ispgl: 1, - dachan: 0, - dabits: 0, - }, - {name:"dt2825", - adbits: 12, - adchan_se:16, - adchan_di:8, - ai_speed:20000, - ispgl: 1, - dachan: 2, - dabits: 12, - }, - {name:"dt2827", - adbits: 16, - adchan_se:0, - adchan_di:4, - ai_speed:10000, - ispgl: 0, - dachan: 2, - dabits: 12, - }, - {name:"dt2828", - adbits: 12, - adchan_se:4, - adchan_di:0, - ai_speed:10000, - ispgl: 0, - dachan: 2, - dabits: 12, - }, - {name:"dt2829", - adbits: 16, - adchan_se:8, - adchan_di:0, - ai_speed:33250, - ispgl: 0, - dachan: 2, - dabits: 16, - }, - {name:"dt21-ez", - adbits: 12, - adchan_se:16, - adchan_di:8, - ai_speed:10000, - ispgl: 0, - dachan: 2, - dabits: 12, - }, - {name:"dt23-ez", - adbits: 16, - adchan_se:16, - adchan_di:8, - ai_speed:10000, - ispgl: 0, - dachan: 0, - dabits: 0, - }, - {name:"dt24-ez", - adbits: 12, - adchan_se:16, - adchan_di:8, - ai_speed:10000, - ispgl: 0, - dachan: 0, - dabits: 0, - }, - {name:"dt24-ez-pgl", - adbits: 12, - adchan_se:16, - adchan_di:8, - ai_speed:10000, - ispgl: 1, - dachan: 0, - dabits: 0, - }, + {.name = "dt2821", + .adbits = 12, + .adchan_se = 16, + .adchan_di = 8, + .ai_speed = 20000, + .ispgl = 0, + .dachan = 2, + .dabits = 12, + }, + {.name = "dt2821-f", + .adbits = 12, + .adchan_se = 16, + .adchan_di = 8, + .ai_speed = 6500, + .ispgl = 0, + .dachan = 2, + .dabits = 12, + }, + {.name = "dt2821-g", + .adbits = 12, + .adchan_se = 16, + .adchan_di = 8, + .ai_speed = 4000, + .ispgl = 0, + .dachan = 2, + .dabits = 12, + }, + {.name = "dt2823", + .adbits = 16, + .adchan_se = 0, + .adchan_di = 4, + .ai_speed = 10000, + .ispgl = 0, + .dachan = 2, + .dabits = 16, + }, + {.name = "dt2824-pgh", + .adbits = 12, + .adchan_se = 16, + .adchan_di = 8, + .ai_speed = 20000, + .ispgl = 0, + .dachan = 0, + .dabits = 0, + }, + {.name = "dt2824-pgl", + .adbits = 12, + .adchan_se = 16, + .adchan_di = 8, + .ai_speed = 20000, + .ispgl = 1, + .dachan = 0, + .dabits = 0, + }, + {.name = "dt2825", + .adbits = 12, + .adchan_se = 16, + .adchan_di = 8, + .ai_speed = 20000, + .ispgl = 1, + .dachan = 2, + .dabits = 12, + }, + {.name = "dt2827", + .adbits = 16, + .adchan_se = 0, + .adchan_di = 4, + .ai_speed = 10000, + .ispgl = 0, + .dachan = 2, + .dabits = 12, + }, + {.name = "dt2828", + .adbits = 12, + .adchan_se = 4, + .adchan_di = 0, + .ai_speed = 10000, + .ispgl = 0, + .dachan = 2, + .dabits = 12, + }, + {.name = "dt2829", + .adbits = 16, + .adchan_se = 8, + .adchan_di = 0, + .ai_speed = 33250, + .ispgl = 0, + .dachan = 2, + .dabits = 16, + }, + {.name = "dt21-ez", + .adbits = 12, + .adchan_se = 16, + .adchan_di = 8, + .ai_speed = 10000, + .ispgl = 0, + .dachan = 2, + .dabits = 12, + }, + {.name = "dt23-ez", + .adbits = 16, + .adchan_se = 16, + .adchan_di = 8, + .ai_speed = 10000, + .ispgl = 0, + .dachan = 0, + .dabits = 0, + }, + {.name = "dt24-ez", + .adbits = 12, + .adchan_se = 16, + .adchan_di = 8, + .ai_speed = 10000, + .ispgl = 0, + .dachan = 0, + .dabits = 0, + }, + {.name = "dt24-ez-pgl", + .adbits = 12, + .adchan_se = 16, + .adchan_di = 8, + .ai_speed = 10000, + .ispgl = 1, + .dachan = 0, + .dabits = 0, + }, }; #define n_boardtypes sizeof(boardtypes)/sizeof(struct dt282x_board) @@ -374,51 +374,51 @@ struct dt282x_private { * Some useless abstractions */ #define chan_to_DAC(a) ((a)&1) -#define update_dacsr(a) outw(devpriv->dacsr|(a),dev->iobase+DT2821_DACSR) -#define update_adcsr(a) outw(devpriv->adcsr|(a),dev->iobase+DT2821_ADCSR) +#define update_dacsr(a) outw(devpriv->dacsr|(a), dev->iobase+DT2821_DACSR) +#define update_adcsr(a) outw(devpriv->adcsr|(a), dev->iobase+DT2821_ADCSR) #define mux_busy() (inw(dev->iobase+DT2821_ADCSR)&DT2821_MUXBUSY) #define ad_done() (inw(dev->iobase+DT2821_ADCSR)&DT2821_ADDONE) -#define update_supcsr(a) outw(devpriv->supcsr|(a),dev->iobase+DT2821_SUPCSR) +#define update_supcsr(a) outw(devpriv->supcsr|(a), dev->iobase+DT2821_SUPCSR) /* * danger! macro abuse... a is the expression to wait on, and b is * the statement(s) to execute if it doesn't happen. */ -#define wait_for(a,b) \ +#define wait_for(a, b) \ do{ \ int _i; \ - for(_i=0;_idma_maxsize); if (size == 0) { - rt_printk("dt282x: AO underrun\n"); + printk("dt282x: AO underrun\n"); dt282x_ao_cancel(dev, s); s->async->events |= COMEDI_CB_OVERFLOW; return; @@ -472,7 +472,7 @@ static void dt282x_ao_dma_interrupt(struct comedi_device * dev) return; } -static void dt282x_ai_dma_interrupt(struct comedi_device * dev) +static void dt282x_ai_dma_interrupt(struct comedi_device *dev) { void *ptr; int size; @@ -524,7 +524,7 @@ static void dt282x_ai_dma_interrupt(struct comedi_device * dev) prep_ai_dma(dev, i, 0); } -static int prep_ai_dma(struct comedi_device * dev, int dma_index, int n) +static int prep_ai_dma(struct comedi_device *dev, int dma_index, int n) { int dma_chan; unsigned long dma_ptr; @@ -555,7 +555,7 @@ static int prep_ai_dma(struct comedi_device * dev, int dma_index, int n) return n; } -static int prep_ao_dma(struct comedi_device * dev, int dma_index, int n) +static int prep_ao_dma(struct comedi_device *dev, int dma_index, int n) { int dma_chan; unsigned long dma_ptr; @@ -577,7 +577,7 @@ static int prep_ao_dma(struct comedi_device * dev, int dma_index, int n) return n; } -static irqreturn_t dt282x_interrupt(int irq, void *d PT_REGS_ARG) +static irqreturn_t dt282x_interrupt(int irq, void *d) { struct comedi_device *dev = d; struct comedi_subdevice *s; @@ -653,7 +653,7 @@ static irqreturn_t dt282x_interrupt(int irq, void *d PT_REGS_ARG) return IRQ_RETVAL(handled); } -static void dt282x_load_changain(struct comedi_device * dev, int n, +static void dt282x_load_changain(struct comedi_device *dev, int n, unsigned int *chanlist) { unsigned int i; @@ -674,8 +674,8 @@ static void dt282x_load_changain(struct comedi_device * dev, int n, * - preload multiplexer * - trigger conversion and wait for it to finish */ -static int dt282x_ai_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int dt282x_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i; @@ -706,8 +706,8 @@ static int dt282x_ai_insn_read(struct comedi_device * dev, struct comedi_subdevi return i; } -static int dt282x_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd) +static int dt282x_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd) { int err = 0; int tmp; @@ -818,7 +818,7 @@ static int dt282x_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice return 0; } -static int dt282x_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s) +static int dt282x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { struct comedi_cmd *cmd = &s->async->cmd; int timer; @@ -879,7 +879,7 @@ static int dt282x_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s return 0; } -static void dt282x_disable_dma(struct comedi_device * dev) +static void dt282x_disable_dma(struct comedi_device *dev) { if (devpriv->usedma) { disable_dma(devpriv->dma[0].chan); @@ -887,7 +887,7 @@ static void dt282x_disable_dma(struct comedi_device * dev) } } -static int dt282x_ai_cancel(struct comedi_device * dev, struct comedi_subdevice * s) +static int dt282x_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { dt282x_disable_dma(dev); @@ -937,16 +937,16 @@ static int dt282x_ns_to_timer(int *nanosec, int round_mode) * offset binary if necessary, loads the data into the DAC * data register, and performs the conversion. */ -static int dt282x_ao_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int dt282x_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { data[0] = devpriv->ao[CR_CHAN(insn->chanspec)]; return 1; } -static int dt282x_ao_insn_write(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int dt282x_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { short d; unsigned int chan; @@ -978,8 +978,8 @@ static int dt282x_ao_insn_write(struct comedi_device * dev, struct comedi_subdev return 1; } -static int dt282x_ao_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd) +static int dt282x_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd) { int err = 0; int tmp; @@ -1029,7 +1029,7 @@ static int dt282x_ao_cmdtest(struct comedi_device * dev, struct comedi_subdevice cmd->start_arg = 0; err++; } - if (cmd->scan_begin_arg < 5000 /* XXX unknown */ ) { + if (cmd->scan_begin_arg < 5000 /* XXX unknown */) { cmd->scan_begin_arg = 5000; err++; } @@ -1069,7 +1069,7 @@ static int dt282x_ao_cmdtest(struct comedi_device * dev, struct comedi_subdevice } -static int dt282x_ao_inttrig(struct comedi_device * dev, struct comedi_subdevice * s, +static int dt282x_ao_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int x) { int size; @@ -1080,7 +1080,7 @@ static int dt282x_ao_inttrig(struct comedi_device * dev, struct comedi_subdevice size = cfc_read_array_from_buffer(s, devpriv->dma[0].buf, devpriv->dma_maxsize); if (size == 0) { - rt_printk("dt282x: AO underrun\n"); + printk("dt282x: AO underrun\n"); return -EPIPE; } prep_ao_dma(dev, 0, size); @@ -1088,7 +1088,7 @@ static int dt282x_ao_inttrig(struct comedi_device * dev, struct comedi_subdevice size = cfc_read_array_from_buffer(s, devpriv->dma[1].buf, devpriv->dma_maxsize); if (size == 0) { - rt_printk("dt282x: AO underrun\n"); + printk("dt282x: AO underrun\n"); return -EPIPE; } prep_ao_dma(dev, 1, size); @@ -1099,7 +1099,7 @@ static int dt282x_ao_inttrig(struct comedi_device * dev, struct comedi_subdevice return 1; } -static int dt282x_ao_cmd(struct comedi_device * dev, struct comedi_subdevice * s) +static int dt282x_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { int timer; struct comedi_cmd *cmd = &s->async->cmd; @@ -1132,7 +1132,7 @@ static int dt282x_ao_cmd(struct comedi_device * dev, struct comedi_subdevice * s return 0; } -static int dt282x_ao_cancel(struct comedi_device * dev, struct comedi_subdevice * s) +static int dt282x_ao_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { dt282x_disable_dma(dev); @@ -1145,8 +1145,8 @@ static int dt282x_ao_cancel(struct comedi_device * dev, struct comedi_subdevice return 0; } -static int dt282x_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int dt282x_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if (data[0]) { s->state &= ~data[0]; @@ -1159,8 +1159,8 @@ static int dt282x_dio_insn_bits(struct comedi_device * dev, struct comedi_subdev return 2; } -static int dt282x_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int dt282x_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int mask; @@ -1240,7 +1240,7 @@ enum { opt_iobase = 0, opt_irq, opt_dma1, opt_dma2, /* i/o base, irq, dma channe 9 ao0 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V, 4=±2.5 V 10 ao1 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V, 4=±2.5 V */ -static int dt282x_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it) { int i, irq; int ret; @@ -1298,19 +1298,18 @@ static int dt282x_attach(struct comedi_device * dev, struct comedi_devconfig * i /* trigger interrupt */ - comedi_udelay(100); + udelay(100); irq = probe_irq_off(irqs); restore_flags(flags); - if (0 /* error */ ) { + if (0 /* error */) { printk(" error probing irq (bad)"); } } #endif if (irq > 0) { printk(" ( irq = %d )", irq); - ret = comedi_request_irq(irq, dt282x_interrupt, 0, "dt282x", - dev); + ret = request_irq(irq, dt282x_interrupt, 0, "dt282x", dev); if (ret < 0) { printk(" failed to get irq\n"); return -EIO; @@ -1326,7 +1325,8 @@ static int dt282x_attach(struct comedi_device * dev, struct comedi_devconfig * i #endif } - if ((ret = alloc_private(dev, sizeof(struct dt282x_private))) < 0) + ret = alloc_private(dev, sizeof(struct dt282x_private)); + if (ret < 0) return ret; ret = dt282x_grab_dma(dev, it->options[opt_dma1], @@ -1334,7 +1334,8 @@ static int dt282x_attach(struct comedi_device * dev, struct comedi_devconfig * i if (ret < 0) return ret; - if ((ret = alloc_subdevices(dev, 3)) < 0) + ret = alloc_subdevices(dev, 3); + if (ret < 0) return ret; s = dev->subdevices + 0; @@ -1358,7 +1359,9 @@ static int dt282x_attach(struct comedi_device * dev, struct comedi_devconfig * i devpriv->ad_2scomp = it->options[opt_ai_twos]; s++; - if ((s->n_chan = boardtype.dachan)) { + + s->n_chan = boardtype.dachan; + if (s->n_chan) { /* ao subsystem */ s->type = COMEDI_SUBD_AO; dev->write_subdev = s; @@ -1396,10 +1399,10 @@ static int dt282x_attach(struct comedi_device * dev, struct comedi_devconfig * i return 0; } -static void free_resources(struct comedi_device * dev) +static void free_resources(struct comedi_device *dev) { if (dev->irq) { - comedi_free_irq(dev->irq, dev); + free_irq(dev->irq, dev); } if (dev->iobase) release_region(dev->iobase, DT2821_SIZE); @@ -1415,7 +1418,7 @@ static void free_resources(struct comedi_device * dev) } } -static int dt282x_detach(struct comedi_device * dev) +static int dt282x_detach(struct comedi_device *dev) { printk("comedi%d: dt282x: remove\n", dev->minor); @@ -1424,7 +1427,7 @@ static int dt282x_detach(struct comedi_device * dev) return 0; } -static int dt282x_grab_dma(struct comedi_device * dev, int dma1, int dma2) +static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2) { int ret; diff --git a/drivers/staging/comedi/drivers/dt3000.c b/drivers/staging/comedi/drivers/dt3000.c index d9467984706e..2af8b59f9061 100644 --- a/drivers/staging/comedi/drivers/dt3000.c +++ b/drivers/staging/comedi/drivers/dt3000.c @@ -59,6 +59,7 @@ AO commands are not supported. #define DEBUG 1 +#include #include "../comedidev.h" #include @@ -95,69 +96,69 @@ struct dt3k_boardtype { static const struct dt3k_boardtype dt3k_boardtypes[] = { - {name:"dt3001", - device_id:0x22, - adchan: 16, - adbits: 12, - adrange: &range_dt3000_ai, - ai_speed:3000, - dachan: 2, - dabits: 12, - }, - {name:"dt3001-pgl", - device_id:0x27, - adchan: 16, - adbits: 12, - adrange: &range_dt3000_ai_pgl, - ai_speed:3000, - dachan: 2, - dabits: 12, - }, - {name:"dt3002", - device_id:0x23, - adchan: 32, - adbits: 12, - adrange: &range_dt3000_ai, - ai_speed:3000, - dachan: 0, - dabits: 0, - }, - {name:"dt3003", - device_id:0x24, - adchan: 64, - adbits: 12, - adrange: &range_dt3000_ai, - ai_speed:3000, - dachan: 2, - dabits: 12, - }, - {name:"dt3003-pgl", - device_id:0x28, - adchan: 64, - adbits: 12, - adrange: &range_dt3000_ai_pgl, - ai_speed:3000, - dachan: 2, - dabits: 12, - }, - {name:"dt3004", - device_id:0x25, - adchan: 16, - adbits: 16, - adrange: &range_dt3000_ai, - ai_speed:10000, - dachan: 2, - dabits: 12, - }, - {name:"dt3005", /* a.k.a. 3004-200 */ - device_id:0x26, - adchan: 16, - adbits: 16, - adrange: &range_dt3000_ai, - ai_speed:5000, - dachan: 2, - dabits: 12, - }, + {.name = "dt3001", + .device_id = 0x22, + .adchan = 16, + .adbits = 12, + .adrange = &range_dt3000_ai, + .ai_speed = 3000, + .dachan = 2, + .dabits = 12, + }, + {.name = "dt3001-pgl", + .device_id = 0x27, + .adchan = 16, + .adbits = 12, + .adrange = &range_dt3000_ai_pgl, + .ai_speed = 3000, + .dachan = 2, + .dabits = 12, + }, + {.name = "dt3002", + .device_id = 0x23, + .adchan = 32, + .adbits = 12, + .adrange = &range_dt3000_ai, + .ai_speed = 3000, + .dachan = 0, + .dabits = 0, + }, + {.name = "dt3003", + .device_id = 0x24, + .adchan = 64, + .adbits = 12, + .adrange = &range_dt3000_ai, + .ai_speed = 3000, + .dachan = 2, + .dabits = 12, + }, + {.name = "dt3003-pgl", + .device_id = 0x28, + .adchan = 64, + .adbits = 12, + .adrange = &range_dt3000_ai_pgl, + .ai_speed = 3000, + .dachan = 2, + .dabits = 12, + }, + {.name = "dt3004", + .device_id = 0x25, + .adchan = 16, + .adbits = 16, + .adrange = &range_dt3000_ai, + .ai_speed = 10000, + .dachan = 2, + .dabits = 12, + }, + {.name = "dt3005", /* a.k.a. 3004-200 */ + .device_id = 0x26, + .adchan = 16, + .adbits = 16, + .adrange = &range_dt3000_ai, + .ai_speed = 5000, + .dachan = 2, + .dabits = 12, + }, }; #define n_dt3k_boards sizeof(dt3k_boardtypes)/sizeof(struct dt3k_boardtype) @@ -275,28 +276,28 @@ struct dt3k_private { #define devpriv ((struct dt3k_private *)dev->private) -static int dt3000_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int dt3000_detach(struct comedi_device * dev); +static int dt3000_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int dt3000_detach(struct comedi_device *dev); static struct comedi_driver driver_dt3000 = { - driver_name:"dt3000", - module:THIS_MODULE, - attach:dt3000_attach, - detach:dt3000_detach, + .driver_name = "dt3000", + .module = THIS_MODULE, + .attach = dt3000_attach, + .detach = dt3000_detach, }; COMEDI_PCI_INITCLEANUP(driver_dt3000, dt3k_pci_table); -static void dt3k_ai_empty_fifo(struct comedi_device * dev, struct comedi_subdevice * s); +static void dt3k_ai_empty_fifo(struct comedi_device *dev, struct comedi_subdevice *s); static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *arg, unsigned int round_mode); -static int dt3k_ai_cancel(struct comedi_device * dev, struct comedi_subdevice * s); +static int dt3k_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s); #ifdef DEBUG static void debug_intr_flags(unsigned int flags); #endif #define TIMEOUT 100 -static int dt3k_send_cmd(struct comedi_device * dev, unsigned int cmd) +static int dt3k_send_cmd(struct comedi_device *dev, unsigned int cmd) { int i; unsigned int status = 0; @@ -307,7 +308,7 @@ static int dt3k_send_cmd(struct comedi_device * dev, unsigned int cmd) status = readw(devpriv->io_addr + DPR_Command_Mbx); if ((status & DT3000_COMPLETION_MASK) != DT3000_NOTPROCESSED) break; - comedi_udelay(1); + udelay(1); } if ((status & DT3000_COMPLETION_MASK) == DT3000_NOERROR) { return 0; @@ -318,7 +319,7 @@ static int dt3k_send_cmd(struct comedi_device * dev, unsigned int cmd) return -ETIME; } -static unsigned int dt3k_readsingle(struct comedi_device * dev, unsigned int subsys, +static unsigned int dt3k_readsingle(struct comedi_device *dev, unsigned int subsys, unsigned int chan, unsigned int gain) { writew(subsys, devpriv->io_addr + DPR_SubSys); @@ -331,7 +332,7 @@ static unsigned int dt3k_readsingle(struct comedi_device * dev, unsigned int sub return readw(devpriv->io_addr + DPR_Params(2)); } -static void dt3k_writesingle(struct comedi_device * dev, unsigned int subsys, +static void dt3k_writesingle(struct comedi_device *dev, unsigned int subsys, unsigned int chan, unsigned int data) { writew(subsys, devpriv->io_addr + DPR_SubSys); @@ -345,9 +346,9 @@ static void dt3k_writesingle(struct comedi_device * dev, unsigned int subsys, static int debug_n_ints = 0; -// FIXME! Assumes shared interrupt is for this card. -// What's this debug_n_ints stuff? Obviously needs some work... -static irqreturn_t dt3k_interrupt(int irq, void *d PT_REGS_ARG) +/* FIXME! Assumes shared interrupt is for this card. */ +/* What's this debug_n_ints stuff? Obviously needs some work... */ +static irqreturn_t dt3k_interrupt(int irq, void *d) { struct comedi_device *dev = d; struct comedi_subdevice *s; @@ -400,7 +401,7 @@ static void debug_intr_flags(unsigned int flags) } #endif -static void dt3k_ai_empty_fifo(struct comedi_device * dev, struct comedi_subdevice * s) +static void dt3k_ai_empty_fifo(struct comedi_device *dev, struct comedi_subdevice *s) { int front; int rear; @@ -429,8 +430,8 @@ static void dt3k_ai_empty_fifo(struct comedi_device * dev, struct comedi_subdevi writew(rear, devpriv->io_addr + DPR_AD_Buf_Rear); } -static int dt3k_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd) +static int dt3k_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd) { int err = 0; int tmp; @@ -591,7 +592,7 @@ static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *nanosec, return (prescale << 16) | (divider); } -static int dt3k_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s) +static int dt3k_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { struct comedi_cmd *cmd = &s->async->cmd; int i; @@ -659,7 +660,7 @@ static int dt3k_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s) return 0; } -static int dt3k_ai_cancel(struct comedi_device * dev, struct comedi_subdevice * s) +static int dt3k_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { int ret; @@ -671,8 +672,8 @@ static int dt3k_ai_cancel(struct comedi_device * dev, struct comedi_subdevice * return 0; } -static int dt3k_ai_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int dt3k_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i; unsigned int chan, gain, aref; @@ -689,8 +690,8 @@ static int dt3k_ai_insn(struct comedi_device * dev, struct comedi_subdevice * s, return i; } -static int dt3k_ao_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int dt3k_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i; unsigned int chan; @@ -704,8 +705,8 @@ static int dt3k_ao_insn(struct comedi_device * dev, struct comedi_subdevice * s, return i; } -static int dt3k_ao_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int dt3k_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i; unsigned int chan; @@ -718,7 +719,7 @@ static int dt3k_ao_insn_read(struct comedi_device * dev, struct comedi_subdevice return i; } -static void dt3k_dio_config(struct comedi_device * dev, int bits) +static void dt3k_dio_config(struct comedi_device *dev, int bits) { /* XXX */ writew(SUBS_DOUT, devpriv->io_addr + DPR_SubSys); @@ -733,8 +734,8 @@ static void dt3k_dio_config(struct comedi_device * dev, int bits) dt3k_send_cmd(dev, CMD_CONFIG); } -static int dt3k_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int dt3k_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int mask; @@ -764,8 +765,8 @@ static int dt3k_dio_insn_config(struct comedi_device * dev, struct comedi_subdev return insn->n; } -static int dt3k_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int dt3k_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if (insn->n != 2) return -EINVAL; @@ -780,8 +781,8 @@ static int dt3k_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevic return 2; } -static int dt3k_mem_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int dt3k_mem_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { unsigned int addr = CR_CHAN(insn->chanspec); int i; @@ -799,9 +800,9 @@ static int dt3k_mem_insn_read(struct comedi_device * dev, struct comedi_subdevic return i; } -static int dt_pci_probe(struct comedi_device * dev, int bus, int slot); +static int dt_pci_probe(struct comedi_device *dev, int bus, int slot); -static int dt3000_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int dt3000_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; int bus, slot; @@ -811,7 +812,8 @@ static int dt3000_attach(struct comedi_device * dev, struct comedi_devconfig * i bus = it->options[0]; slot = it->options[1]; - if ((ret = alloc_private(dev, sizeof(struct dt3k_private))) < 0) + ret = alloc_private(dev, sizeof(struct dt3k_private)); + if (ret < 0) return ret; ret = dt_pci_probe(dev, bus, slot); @@ -824,14 +826,15 @@ static int dt3000_attach(struct comedi_device * dev, struct comedi_devconfig * i dev->board_name = this_board->name; - if (comedi_request_irq(devpriv->pci_dev->irq, dt3k_interrupt, - IRQF_SHARED, "dt3000", dev)) { + if (request_irq(devpriv->pci_dev->irq, dt3k_interrupt, IRQF_SHARED, + "dt3000", dev)) { printk(" unable to allocate IRQ %u\n", devpriv->pci_dev->irq); return -EINVAL; } dev->irq = devpriv->pci_dev->irq; - if ((ret = alloc_subdevices(dev, 4)) < 0) + ret = alloc_subdevices(dev, 4); + if (ret < 0) return ret; s = dev->subdevices; @@ -890,10 +893,10 @@ static int dt3000_attach(struct comedi_device * dev, struct comedi_devconfig * i return 0; } -static int dt3000_detach(struct comedi_device * dev) +static int dt3000_detach(struct comedi_device *dev) { if (dev->irq) - comedi_free_irq(dev->irq, dev); + free_irq(dev->irq, dev); if (devpriv) { if (devpriv->pci_dev) { @@ -911,9 +914,9 @@ static int dt3000_detach(struct comedi_device * dev) } static struct pci_dev *dt_pci_find_device(struct pci_dev *from, int *board); -static int setup_pci(struct comedi_device * dev); +static int setup_pci(struct comedi_device *dev); -static int dt_pci_probe(struct comedi_device * dev, int bus, int slot) +static int dt_pci_probe(struct comedi_device *dev, int bus, int slot) { int board; int ret; @@ -935,13 +938,14 @@ static int dt_pci_probe(struct comedi_device * dev, int bus, int slot) if (!devpriv->pci_dev) return 0; - if ((ret = setup_pci(dev)) < 0) + ret = setup_pci(dev); + if (ret < 0) return ret; return 1; } -static int setup_pci(struct comedi_device * dev) +static int setup_pci(struct comedi_device *dev) { resource_size_t addr; int ret; diff --git a/drivers/staging/comedi/drivers/fl512.c b/drivers/staging/comedi/drivers/fl512.c index 6d7bb37d2b1c..b8657c47d4cc 100644 --- a/drivers/staging/comedi/drivers/fl512.c +++ b/drivers/staging/comedi/drivers/fl512.c @@ -42,30 +42,30 @@ static const struct comedi_lrange range_fl512 = { 4, { } }; -static int fl512_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int fl512_detach(struct comedi_device * dev); +static int fl512_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int fl512_detach(struct comedi_device *dev); static struct comedi_driver driver_fl512 = { - driver_name:"fl512", - module:THIS_MODULE, - attach:fl512_attach, - detach:fl512_detach, + .driver_name = "fl512", + .module = THIS_MODULE, + .attach = fl512_attach, + .detach = fl512_detach, }; COMEDI_INITCLEANUP(driver_fl512); -static int fl512_ai_insn(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data); -static int fl512_ao_insn(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data); -static int fl512_ao_insn_readback(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data); +static int fl512_ai_insn(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); +static int fl512_ao_insn(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); +static int fl512_ao_insn_readback(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); /* * fl512_ai_insn : this is the analog input function */ -static int fl512_ai_insn(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +static int fl512_ai_insn(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { int n; unsigned int lo_byte, hi_byte; @@ -78,7 +78,7 @@ static int fl512_ai_insn(struct comedi_device * dev, outb(chan, iobase + 2); /* select chan */ outb(0, iobase + 3); /* start conversion */ /* XXX should test "done" flag instead of delay */ - comedi_udelay(30); /* sleep 30 usec */ + udelay(30); /* sleep 30 usec */ lo_byte = inb(iobase + 2); /* low 8 byte */ hi_byte = inb(iobase + 3) & 0xf; /* high 4 bit and mask */ data[n] = lo_byte + (hi_byte << 8); @@ -89,8 +89,8 @@ static int fl512_ai_insn(struct comedi_device * dev, /* * fl512_ao_insn : used to write to a DA port n times */ -static int fl512_ao_insn(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +static int fl512_ao_insn(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { int n; int chan = CR_CHAN(insn->chanspec); /* get chan to write */ @@ -110,8 +110,8 @@ static int fl512_ao_insn(struct comedi_device * dev, * fl512_ao_insn_readback : used to read previous values written to * DA port */ -static int fl512_ao_insn_readback(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +static int fl512_ao_insn_readback(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { int n; int chan = CR_CHAN(insn->chanspec); @@ -126,7 +126,7 @@ static int fl512_ao_insn_readback(struct comedi_device * dev, /* * start attach */ -static int fl512_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int fl512_attach(struct comedi_device *dev, struct comedi_devconfig *it) { unsigned long iobase; struct comedi_subdevice *s; /* pointer to the subdevice: @@ -177,7 +177,7 @@ static int fl512_attach(struct comedi_device * dev, struct comedi_devconfig * it return 1; } -static int fl512_detach(struct comedi_device * dev) +static int fl512_detach(struct comedi_device *dev) { if (dev->iobase) release_region(dev->iobase, FL512_SIZE); diff --git a/drivers/staging/comedi/drivers/gsc_hpdi.c b/drivers/staging/comedi/drivers/gsc_hpdi.c index 49e5c86c2dd8..b156ae717ae4 100644 --- a/drivers/staging/comedi/drivers/gsc_hpdi.c +++ b/drivers/staging/comedi/drivers/gsc_hpdi.c @@ -45,6 +45,7 @@ support could be added to this driver. */ +#include #include "../comedidev.h" #include @@ -52,31 +53,31 @@ support could be added to this driver. #include "plx9080.h" #include "comedi_fc.h" -static int hpdi_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int hpdi_detach(struct comedi_device * dev); -void abort_dma(struct comedi_device * dev, unsigned int channel); -static int hpdi_cmd(struct comedi_device * dev, struct comedi_subdevice * s); -static int hpdi_cmd_test(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd); -static int hpdi_cancel(struct comedi_device * dev, struct comedi_subdevice * s); -static irqreturn_t handle_interrupt(int irq, void *d PT_REGS_ARG); -static int dio_config_block_size(struct comedi_device * dev, unsigned int * data); +static int hpdi_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int hpdi_detach(struct comedi_device *dev); +void abort_dma(struct comedi_device *dev, unsigned int channel); +static int hpdi_cmd(struct comedi_device *dev, struct comedi_subdevice *s); +static int hpdi_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd); +static int hpdi_cancel(struct comedi_device *dev, struct comedi_subdevice *s); +static irqreturn_t handle_interrupt(int irq, void *d); +static int dio_config_block_size(struct comedi_device *dev, unsigned int *data); -#undef HPDI_DEBUG // disable debugging messages -//#define HPDI_DEBUG // enable debugging code +#undef HPDI_DEBUG /* disable debugging messages */ +/* #define HPDI_DEBUG enable debugging code */ #ifdef HPDI_DEBUG -#define DEBUG_PRINT(format, args...) rt_printk(format , ## args ) +#define DEBUG_PRINT(format, args...) printk(format , ## args) #else #define DEBUG_PRINT(format, args...) #endif -#define TIMER_BASE 50 // 20MHz master clock +#define TIMER_BASE 50 /* 20MHz master clock */ #define DMA_BUFFER_SIZE 0x10000 #define NUM_DMA_BUFFERS 4 #define NUM_DMA_DESCRIPTORS 256 -// indices of base address regions +/* indices of base address regions */ enum base_address_regions { PLX9080_BADDRINDEX = 0, HPDI_BADDRINDEX = 2, @@ -109,13 +110,13 @@ enum hpdi_registers { int command_channel_valid(unsigned int channel) { if (channel == 0 || channel > 6) { - rt_printk("gsc_hpdi: bug! invalid cable command channel\n"); + printk("gsc_hpdi: bug! invalid cable command channel\n"); return 0; } return 1; } -// bit definitions +/* bit definitions */ enum firmware_revision_bits { FEATURES_REG_PRESENT_BIT = 0x8000, @@ -184,7 +185,7 @@ enum board_status_bits { uint32_t almost_full_bits(unsigned int num_words) { -// XXX need to add or subtract one? +/* XXX need to add or subtract one? */ return (num_words << 16) & 0xff0000; } @@ -194,7 +195,7 @@ uint32_t almost_empty_bits(unsigned int num_words) } unsigned int almost_full_num_words(uint32_t bits) { -// XXX need to add or subtract one? +/* XXX need to add or subtract one? */ return (bits >> 16) & 0xffff; } unsigned int almost_empty_num_words(uint32_t bits) @@ -263,31 +264,26 @@ uint32_t intr_active_high_bit(int interrupt_source) struct hpdi_board { char *name; - int device_id; // pci device id - int subdevice_id; // pci subdevice id + int device_id; /* pci device id */ + int subdevice_id; /* pci subdevice id */ }; static const struct hpdi_board hpdi_boards[] = { { - name: "pci-hpdi32", - device_id:PCI_DEVICE_ID_PLX_9080, - subdevice_id:0x2400, + .name = "pci-hpdi32", + .device_id = PCI_DEVICE_ID_PLX_9080, + .subdevice_id = 0x2400, }, #if 0 { - name: "pxi-hpdi32", - device_id:0x9656, - subdevice_id:0x2705, + .name = "pxi-hpdi32", + .device_id = 0x9656, + .subdevice_id = 0x2705, }, #endif }; -static inline unsigned int num_boards(void) -{ - return sizeof(hpdi_boards) / sizeof(struct hpdi_board); -} - static DEFINE_PCI_DEVICE_TABLE(hpdi_pci_table) = { {PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9080, PCI_VENDOR_ID_PLX, 0x2400, 0, 0, 0}, @@ -303,25 +299,25 @@ static inline struct hpdi_board *board(const struct comedi_device * dev) struct hpdi_private { - struct pci_dev *hw_dev; // pointer to board's pci_dev struct - // base addresses (physical) + struct pci_dev *hw_dev; /* pointer to board's pci_dev struct */ + /* base addresses (physical) */ resource_size_t plx9080_phys_iobase; resource_size_t hpdi_phys_iobase; - // base addresses (ioremapped) + /* base addresses (ioremapped) */ void *plx9080_iobase; void *hpdi_iobase; - uint32_t *dio_buffer[NUM_DMA_BUFFERS]; // dma buffers - dma_addr_t dio_buffer_phys_addr[NUM_DMA_BUFFERS]; // physical addresses of dma buffers - struct plx_dma_desc *dma_desc; // array of dma descriptors read by plx9080, allocated to get proper alignment - dma_addr_t dma_desc_phys_addr; // physical address of dma descriptor array + uint32_t *dio_buffer[NUM_DMA_BUFFERS]; /* dma buffers */ + dma_addr_t dio_buffer_phys_addr[NUM_DMA_BUFFERS]; /* physical addresses of dma buffers */ + struct plx_dma_desc *dma_desc; /* array of dma descriptors read by plx9080, allocated to get proper alignment */ + dma_addr_t dma_desc_phys_addr; /* physical address of dma descriptor array */ unsigned int num_dma_descriptors; - uint32_t *desc_dio_buffer[NUM_DMA_DESCRIPTORS]; // pointer to start of buffers indexed by descriptor - volatile unsigned int dma_desc_index; // index of the dma descriptor that is currently being used + uint32_t *desc_dio_buffer[NUM_DMA_DESCRIPTORS]; /* pointer to start of buffers indexed by descriptor */ + volatile unsigned int dma_desc_index; /* index of the dma descriptor that is currently being used */ unsigned int tx_fifo_size; unsigned int rx_fifo_size; volatile unsigned long dio_count; - volatile uint32_t bits[24]; // software copies of values written to hpdi registers - volatile unsigned int block_size; // number of bytes at which to generate COMEDI_CB_BLOCK events + volatile uint32_t bits[24]; /* software copies of values written to hpdi registers */ + volatile unsigned int block_size; /* number of bytes at which to generate COMEDI_CB_BLOCK events */ unsigned dio_config_output:1; }; @@ -332,16 +328,16 @@ static inline struct hpdi_private *priv(struct comedi_device * dev) } static struct comedi_driver driver_hpdi = { - driver_name:"gsc_hpdi", - module:THIS_MODULE, - attach:hpdi_attach, - detach:hpdi_detach, + .driver_name = "gsc_hpdi", + .module = THIS_MODULE, + .attach = hpdi_attach, + .detach = hpdi_detach, }; COMEDI_PCI_INITCLEANUP(driver_hpdi, hpdi_pci_table); -static int dio_config_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int dio_config_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { switch (data[0]) { case INSN_CONFIG_DIO_OUTPUT: @@ -368,18 +364,18 @@ static int dio_config_insn(struct comedi_device * dev, struct comedi_subdevice * return -EINVAL; } -static void disable_plx_interrupts(struct comedi_device * dev) +static void disable_plx_interrupts(struct comedi_device *dev) { writel(0, priv(dev)->plx9080_iobase + PLX_INTRCS_REG); } -// initialize plx9080 chip -static void init_plx9080(struct comedi_device * dev) +/* initialize plx9080 chip */ +static void init_plx9080(struct comedi_device *dev) { uint32_t bits; void *plx_iobase = priv(dev)->plx9080_iobase; - // plx9080 dump + /* plx9080 dump */ DEBUG_PRINT(" plx interrupt status 0x%x\n", readl(plx_iobase + PLX_INTRCS_REG)); DEBUG_PRINT(" plx id bits 0x%x\n", readl(plx_iobase + PLX_ID_REG)); @@ -417,21 +413,21 @@ static void init_plx9080(struct comedi_device * dev) abort_dma(dev, 0); abort_dma(dev, 1); - // configure dma0 mode + /* configure dma0 mode */ bits = 0; - // enable ready input + /* enable ready input */ bits |= PLX_DMA_EN_READYIN_BIT; - // enable dma chaining + /* enable dma chaining */ bits |= PLX_EN_CHAIN_BIT; - // enable interrupt on dma done (probably don't need this, since chain never finishes) + /* enable interrupt on dma done (probably don't need this, since chain never finishes) */ bits |= PLX_EN_DMA_DONE_INTR_BIT; - // don't increment local address during transfers (we are transferring from a fixed fifo register) + /* don't increment local address during transfers (we are transferring from a fixed fifo register) */ bits |= PLX_LOCAL_ADDR_CONST_BIT; - // route dma interrupt to pci bus + /* route dma interrupt to pci bus */ bits |= PLX_DMA_INTR_PCI_BIT; - // enable demand mode + /* enable demand mode */ bits |= PLX_DEMAND_MODE_BIT; - // enable local burst mode + /* enable local burst mode */ bits |= PLX_DMA_LOCAL_BURST_EN_BIT; bits |= PLX_LOCAL_BUS_32_WIDE_BITS; writel(bits, plx_iobase + PLX_DMA0_MODE_REG); @@ -439,7 +435,7 @@ static void init_plx9080(struct comedi_device * dev) /* Allocate and initialize the subdevice structures. */ -static int setup_subdevices(struct comedi_device * dev) +static int setup_subdevices(struct comedi_device *dev) { struct comedi_subdevice *s; @@ -465,12 +461,12 @@ static int setup_subdevices(struct comedi_device * dev) return 0; } -static int init_hpdi(struct comedi_device * dev) +static int init_hpdi(struct comedi_device *dev) { uint32_t plx_intcsr_bits; writel(BOARD_RESET_BIT, priv(dev)->hpdi_iobase + BOARD_CONTROL_REG); - comedi_udelay(10); + udelay(10); writel(almost_empty_bits(32) | almost_full_bits(32), priv(dev)->hpdi_iobase + RX_PROG_ALMOST_REG); @@ -484,7 +480,7 @@ static int init_hpdi(struct comedi_device * dev) writel(0, priv(dev)->hpdi_iobase + INTERRUPT_CONTROL_REG); - // enable interrupts + /* enable interrupts */ plx_intcsr_bits = ICS_AERR | ICS_PERR | ICS_PIE | ICS_PLIE | ICS_PAIE | ICS_LIE | ICS_DMA0_E; @@ -493,8 +489,8 @@ static int init_hpdi(struct comedi_device * dev) return 0; } -// setup dma descriptors so a link completes every 'transfer_size' bytes -static int setup_dma_descriptors(struct comedi_device * dev, +/* setup dma descriptors so a link completes every 'transfer_size' bytes */ +static int setup_dma_descriptors(struct comedi_device *dev, unsigned int transfer_size) { unsigned int buffer_index, buffer_offset; @@ -545,7 +541,7 @@ static int setup_dma_descriptors(struct comedi_device * dev, (unsigned long)priv(dev)->dma_desc[i].next); } priv(dev)->num_dma_descriptors = i; - // fix last descriptor to point back to first + /* fix last descriptor to point back to first */ priv(dev)->dma_desc[i - 1].next = cpu_to_le32(priv(dev)->dma_desc_phys_addr | next_bits); DEBUG_PRINT(" desc %i next fixup 0x%lx\n", i - 1, @@ -556,7 +552,7 @@ static int setup_dma_descriptors(struct comedi_device * dev, return transfer_size; } -static int hpdi_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int hpdi_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct pci_dev *pcidev; int i; @@ -568,14 +564,14 @@ static int hpdi_attach(struct comedi_device * dev, struct comedi_devconfig * it) return -ENOMEM; pcidev = NULL; - for (i = 0; i < num_boards() && dev->board_ptr == NULL; i++) { + for (i = 0; i < ARRAY_SIZE(hpdi_boards) && dev->board_ptr == NULL; i++) { do { pcidev = pci_get_subsys(PCI_VENDOR_ID_PLX, hpdi_boards[i].device_id, PCI_VENDOR_ID_PLX, hpdi_boards[i].subdevice_id, pcidev); - // was a particular bus/slot requested? + /* was a particular bus/slot requested? */ if (it->options[0] || it->options[1]) { - // are we on the wrong bus/slot? + /* are we on the wrong bus/slot? */ if (pcidev->bus->number != it->options[0] || PCI_SLOT(pcidev->devfn) != it->options[1]) @@ -603,7 +599,7 @@ static int hpdi_attach(struct comedi_device * dev, struct comedi_devconfig * it) } pci_set_master(pcidev); - //Initialize dev->board_name + /* Initialize dev->board_name */ dev->board_name = board(dev)->name; priv(dev)->plx9080_phys_iobase = @@ -611,7 +607,7 @@ static int hpdi_attach(struct comedi_device * dev, struct comedi_devconfig * it) priv(dev)->hpdi_phys_iobase = pci_resource_start(pcidev, HPDI_BADDRINDEX); - // remap, won't work with 2.0 kernels but who cares + /* remap, won't work with 2.0 kernels but who cares */ priv(dev)->plx9080_iobase = ioremap(priv(dev)->plx9080_phys_iobase, pci_resource_len(pcidev, PLX9080_BADDRINDEX)); priv(dev)->hpdi_iobase = ioremap(priv(dev)->hpdi_phys_iobase, @@ -626,8 +622,8 @@ static int hpdi_attach(struct comedi_device * dev, struct comedi_devconfig * it) init_plx9080(dev); - // get irq - if (comedi_request_irq(pcidev->irq, handle_interrupt, IRQF_SHARED, + /* get irq */ + if (request_irq(pcidev->irq, handle_interrupt, IRQF_SHARED, driver_hpdi.driver_name, dev)) { printk(" unable to allocate irq %u\n", pcidev->irq); return -EINVAL; @@ -636,7 +632,7 @@ static int hpdi_attach(struct comedi_device * dev, struct comedi_devconfig * it) printk(" irq %u\n", dev->irq); - // alocate pci dma buffers + /* alocate pci dma buffers */ for (i = 0; i < NUM_DMA_BUFFERS; i++) { priv(dev)->dio_buffer[i] = pci_alloc_consistent(priv(dev)->hw_dev, DMA_BUFFER_SIZE, @@ -645,7 +641,7 @@ static int hpdi_attach(struct comedi_device * dev, struct comedi_devconfig * it) priv(dev)->dio_buffer[i], (unsigned long)priv(dev)->dio_buffer_phys_addr[i]); } - // allocate dma descriptors + /* allocate dma descriptors */ priv(dev)->dma_desc = pci_alloc_consistent(priv(dev)->hw_dev, sizeof(struct plx_dma_desc) * NUM_DMA_DESCRIPTORS, &priv(dev)->dma_desc_phys_addr); @@ -665,14 +661,14 @@ static int hpdi_attach(struct comedi_device * dev, struct comedi_devconfig * it) return init_hpdi(dev); } -static int hpdi_detach(struct comedi_device * dev) +static int hpdi_detach(struct comedi_device *dev) { unsigned int i; printk("comedi%d: gsc_hpdi: remove\n", dev->minor); if (dev->irq) - comedi_free_irq(dev->irq, dev); + free_irq(dev->irq, dev); if (priv(dev)) { if (priv(dev)->hw_dev) { if (priv(dev)->plx9080_iobase) { @@ -681,7 +677,7 @@ static int hpdi_detach(struct comedi_device * dev) } if (priv(dev)->hpdi_iobase) iounmap((void *)priv(dev)->hpdi_iobase); - // free pci dma buffers + /* free pci dma buffers */ for (i = 0; i < NUM_DMA_BUFFERS; i++) { if (priv(dev)->dio_buffer[i]) pci_free_consistent(priv(dev)->hw_dev, @@ -690,7 +686,7 @@ static int hpdi_detach(struct comedi_device * dev) priv(dev)-> dio_buffer_phys_addr[i]); } - // free dma descriptors + /* free dma descriptors */ if (priv(dev)->dma_desc) pci_free_consistent(priv(dev)->hw_dev, sizeof(struct plx_dma_desc) * @@ -706,7 +702,7 @@ static int hpdi_detach(struct comedi_device * dev) return 0; } -static int dio_config_block_size(struct comedi_device * dev, unsigned int * data) +static int dio_config_block_size(struct comedi_device *dev, unsigned int *data) { unsigned int requested_block_size; int retval; @@ -722,8 +718,8 @@ static int dio_config_block_size(struct comedi_device * dev, unsigned int * data return 2; } -static int di_cmd_test(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd) +static int di_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd) { int err = 0; int tmp; @@ -761,7 +757,7 @@ static int di_cmd_test(struct comedi_device * dev, struct comedi_subdevice * s, /* step 2: make sure trigger sources are unique and mutually compatible */ - // uniqueness check + /* uniqueness check */ if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) err++; @@ -807,7 +803,7 @@ static int di_cmd_test(struct comedi_device * dev, struct comedi_subdevice * s, if (cmd->chanlist) { for (i = 1; i < cmd->chanlist_len; i++) { if (CR_CHAN(cmd->chanlist[i]) != i) { - // XXX could support 8 channels or 16 channels + /* XXX could support 8 channels or 16 channels */ comedi_error(dev, "chanlist must be channels 0 to 31 in order"); err++; @@ -822,8 +818,8 @@ static int di_cmd_test(struct comedi_device * dev, struct comedi_subdevice * s, return 0; } -static int hpdi_cmd_test(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd) +static int hpdi_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd) { if (priv(dev)->dio_config_output) { return -EINVAL; @@ -831,14 +827,14 @@ static int hpdi_cmd_test(struct comedi_device * dev, struct comedi_subdevice * s return di_cmd_test(dev, s, cmd); } -static inline void hpdi_writel(struct comedi_device * dev, uint32_t bits, +static inline void hpdi_writel(struct comedi_device *dev, uint32_t bits, unsigned int offset) { writel(bits | priv(dev)->bits[offset / sizeof(uint32_t)], priv(dev)->hpdi_iobase + offset); } -static int di_cmd(struct comedi_device * dev, struct comedi_subdevice * s) +static int di_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { uint32_t bits; unsigned long flags; @@ -860,28 +856,28 @@ static int di_cmd(struct comedi_device * dev, struct comedi_subdevice * s) writel(0, priv(dev)->plx9080_iobase + PLX_DMA0_TRANSFER_SIZE_REG); writel(0, priv(dev)->plx9080_iobase + PLX_DMA0_PCI_ADDRESS_REG); writel(0, priv(dev)->plx9080_iobase + PLX_DMA0_LOCAL_ADDRESS_REG); - // give location of first dma descriptor + /* give location of first dma descriptor */ bits = priv(dev)-> dma_desc_phys_addr | PLX_DESC_IN_PCI_BIT | PLX_INTR_TERM_COUNT | PLX_XFER_LOCAL_TO_PCI; writel(bits, priv(dev)->plx9080_iobase + PLX_DMA0_DESCRIPTOR_REG); - // spinlock for plx dma control/status reg - comedi_spin_lock_irqsave(&dev->spinlock, flags); - // enable dma transfer + /* spinlock for plx dma control/status reg */ + spin_lock_irqsave(&dev->spinlock, flags); + /* enable dma transfer */ writeb(PLX_DMA_EN_BIT | PLX_DMA_START_BIT | PLX_CLEAR_DMA_INTR_BIT, priv(dev)->plx9080_iobase + PLX_DMA0_CS_REG); - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); if (cmd->stop_src == TRIG_COUNT) priv(dev)->dio_count = cmd->stop_arg; else priv(dev)->dio_count = 1; - // clear over/under run status flags + /* clear over/under run status flags */ writel(RX_UNDERRUN_BIT | RX_OVERRUN_BIT, priv(dev)->hpdi_iobase + BOARD_STATUS_REG); - // enable interrupts + /* enable interrupts */ writel(intr_bit(RX_FULL_INTR), priv(dev)->hpdi_iobase + INTERRUPT_CONTROL_REG); @@ -891,7 +887,7 @@ static int di_cmd(struct comedi_device * dev, struct comedi_subdevice * s) return 0; } -static int hpdi_cmd(struct comedi_device * dev, struct comedi_subdevice * s) +static int hpdi_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { if (priv(dev)->dio_config_output) { return -EINVAL; @@ -899,7 +895,7 @@ static int hpdi_cmd(struct comedi_device * dev, struct comedi_subdevice * s) return di_cmd(dev, s); } -static void drain_dma_buffers(struct comedi_device * dev, unsigned int channel) +static void drain_dma_buffers(struct comedi_device *dev, unsigned int channel) { struct comedi_async *async = dev->read_subdev->async; uint32_t next_transfer_addr; @@ -914,7 +910,7 @@ static void drain_dma_buffers(struct comedi_device * dev, unsigned int channel) pci_addr_reg = priv(dev)->plx9080_iobase + PLX_DMA0_PCI_ADDRESS_REG; - // loop until we have read all the full buffers + /* loop until we have read all the full buffers */ j = 0; for (next_transfer_addr = readl(pci_addr_reg); (next_transfer_addr < @@ -925,7 +921,7 @@ static void drain_dma_buffers(struct comedi_device * dev, unsigned int channel) dma_desc_index].pci_start_addr) + priv(dev)->block_size) && j < priv(dev)->num_dma_descriptors; j++) { - // transfer data from dma buffer to comedi buffer + /* transfer data from dma buffer to comedi buffer */ num_samples = priv(dev)->block_size / sizeof(uint32_t); if (async->cmd.stop_src == TRIG_COUNT) { if (num_samples > priv(dev)->dio_count) @@ -942,10 +938,10 @@ static void drain_dma_buffers(struct comedi_device * dev, unsigned int channel) priv(dev)->dma_desc[priv(dev)->dma_desc_index].next); DEBUG_PRINT("pci addr reg 0x%x\n", next_transfer_addr); } - // XXX check for buffer overrun somehow + /* XXX check for buffer overrun somehow */ } -static irqreturn_t handle_interrupt(int irq, void *d PT_REGS_ARG) +static irqreturn_t handle_interrupt(int irq, void *d) { struct comedi_device *dev = d; struct comedi_subdevice *s = dev->read_subdev; @@ -975,10 +971,10 @@ static irqreturn_t handle_interrupt(int irq, void *d PT_REGS_ARG) writel(hpdi_intr_status, priv(dev)->hpdi_iobase + INTERRUPT_STATUS_REG); } - // spin lock makes sure noone else changes plx dma control reg - comedi_spin_lock_irqsave(&dev->spinlock, flags); + /* spin lock makes sure noone else changes plx dma control reg */ + spin_lock_irqsave(&dev->spinlock, flags); dma0_status = readb(priv(dev)->plx9080_iobase + PLX_DMA0_CS_REG); - if (plx_status & ICS_DMA0_A) { // dma chan 0 interrupt + if (plx_status & ICS_DMA0_A) { /* dma chan 0 interrupt */ writeb((dma0_status & PLX_DMA_EN_BIT) | PLX_CLEAR_DMA_INTR_BIT, priv(dev)->plx9080_iobase + PLX_DMA0_CS_REG); @@ -988,23 +984,23 @@ static irqreturn_t handle_interrupt(int irq, void *d PT_REGS_ARG) } DEBUG_PRINT(" cleared dma ch0 interrupt\n"); } - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); - // spin lock makes sure noone else changes plx dma control reg - comedi_spin_lock_irqsave(&dev->spinlock, flags); + /* spin lock makes sure noone else changes plx dma control reg */ + spin_lock_irqsave(&dev->spinlock, flags); dma1_status = readb(priv(dev)->plx9080_iobase + PLX_DMA1_CS_REG); - if (plx_status & ICS_DMA1_A) // XXX - { // dma chan 1 interrupt + if (plx_status & ICS_DMA1_A) /* XXX */ + { /* dma chan 1 interrupt */ writeb((dma1_status & PLX_DMA_EN_BIT) | PLX_CLEAR_DMA_INTR_BIT, priv(dev)->plx9080_iobase + PLX_DMA1_CS_REG); DEBUG_PRINT("dma1 status 0x%x\n", dma1_status); DEBUG_PRINT(" cleared dma ch1 interrupt\n"); } - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); - // clear possible plx9080 interrupt sources - if (plx_status & ICS_LDIA) { // clear local doorbell interrupt + /* clear possible plx9080 interrupt sources */ + if (plx_status & ICS_LDIA) { /* clear local doorbell interrupt */ plx_bits = readl(priv(dev)->plx9080_iobase + PLX_DBR_OUT_REG); writel(plx_bits, priv(dev)->plx9080_iobase + PLX_DBR_OUT_REG); DEBUG_PRINT(" cleared local doorbell bits 0x%x\n", plx_bits); @@ -1036,19 +1032,19 @@ static irqreturn_t handle_interrupt(int irq, void *d PT_REGS_ARG) return IRQ_HANDLED; } -void abort_dma(struct comedi_device * dev, unsigned int channel) +void abort_dma(struct comedi_device *dev, unsigned int channel) { unsigned long flags; - // spinlock for plx dma control/status reg - comedi_spin_lock_irqsave(&dev->spinlock, flags); + /* spinlock for plx dma control/status reg */ + spin_lock_irqsave(&dev->spinlock, flags); plx9080_abort_dma(priv(dev)->plx9080_iobase, channel); - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); } -static int hpdi_cancel(struct comedi_device * dev, struct comedi_subdevice * s) +static int hpdi_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { hpdi_writel(dev, 0, BOARD_CONTROL_REG); diff --git a/drivers/staging/comedi/drivers/icp_multi.c b/drivers/staging/comedi/drivers/icp_multi.c index 15fce0190b2f..984f995149b6 100644 --- a/drivers/staging/comedi/drivers/icp_multi.c +++ b/drivers/staging/comedi/drivers/icp_multi.c @@ -50,6 +50,7 @@ Options: [1] - PCI slot number */ +#include #include "../comedidev.h" #include @@ -282,7 +283,7 @@ static int icp_multi_insn_read_ai(struct comedi_device *dev, struct comedi_subde readw(devpriv->io_addr + ICP_MULTI_ADC_CSR)); #endif - comedi_udelay(1); + udelay(1); #ifdef ICP_MULTI_EXTDEBUG printk("icp multi C n=%d ST=%4x\n", n, @@ -304,7 +305,7 @@ static int icp_multi_insn_read_ai(struct comedi_device *dev, struct comedi_subde ICP_MULTI_ADC_CSR)); #endif - comedi_udelay(1); + udelay(1); } /* If we reach here, a timeout has occurred */ @@ -411,7 +412,7 @@ static int icp_multi_insn_write_ao(struct comedi_device *dev, struct comedi_subd ICP_MULTI_DAC_CSR)); #endif - comedi_udelay(1); + udelay(1); } /* If we reach here, a timeout has occurred */ @@ -618,7 +619,7 @@ static int icp_multi_insn_write_ctr(struct comedi_device *dev, struct comedi_sub ============================================================================== */ -static irqreturn_t interrupt_service_icp_multi(int irq, void *d PT_REGS_ARG) +static irqreturn_t interrupt_service_icp_multi(int irq, void *d) { struct comedi_device *dev = d; int int_no; @@ -842,7 +843,7 @@ static int icp_multi_reset(struct comedi_device *dev) devpriv->io_addr + ICP_MULTI_DAC_CSR); /* Delay to allow DAC time to recover */ - comedi_udelay(1); + udelay(1); } /* Digital outputs to 0 */ writew(0, devpriv->io_addr + ICP_MULTI_DO); @@ -954,7 +955,7 @@ static int icp_multi_attach(struct comedi_device *dev, struct comedi_devconfig * if (this_board->have_irq) { if (irq) { - if (comedi_request_irq(irq, interrupt_service_icp_multi, + if (request_irq(irq, interrupt_service_icp_multi, IRQF_SHARED, "Inova Icp Multi", dev)) { printk(", unable to allocate IRQ %u, DISABLING IT", irq); irq = 0; /* Can't use IRQ */ @@ -1072,7 +1073,7 @@ static int icp_multi_detach(struct comedi_device *dev) icp_multi_reset(dev); if (dev->irq) - comedi_free_irq(dev->irq, dev); + free_irq(dev->irq, dev); if (dev->private && devpriv->io_addr) iounmap(devpriv->io_addr); diff --git a/drivers/staging/comedi/drivers/icp_multi.h b/drivers/staging/comedi/drivers/icp_multi.h index 21d84766fea8..354ba8f14f81 100644 --- a/drivers/staging/comedi/drivers/icp_multi.h +++ b/drivers/staging/comedi/drivers/icp_multi.h @@ -168,14 +168,14 @@ static int pci_card_alloc(struct pcilst_struct *inova) int i; if (!inova) { - rt_printk(" - BUG!! inova is NULL!\n"); + printk(" - BUG!! inova is NULL!\n"); return -1; } if (inova->used) return 1; if (comedi_pci_enable(inova->pcidev, "icp_multi")) { - rt_printk(" - Can't enable PCI device and request regions!\n"); + printk(" - Can't enable PCI device and request regions!\n"); return -1; } /* Resources will be accurate now. */ @@ -248,19 +248,19 @@ static struct pcilst_struct *select_and_alloc_pci_card(unsigned short vendor_id, card = find_free_pci_card_by_device(vendor_id, device_id); if (card == NULL) { - rt_printk(" - Unused card not found in system!\n"); + printk(" - Unused card not found in system!\n"); return NULL; } } else { switch (find_free_pci_card_by_position(vendor_id, device_id, pci_bus, pci_slot, &card)) { case 1: - rt_printk + printk (" - Card not found on requested position b:s %d:%d!\n", pci_bus, pci_slot); return NULL; case 2: - rt_printk + printk (" - Card on requested position is used b:s %d:%d!\n", pci_bus, pci_slot); return NULL; @@ -270,7 +270,7 @@ static struct pcilst_struct *select_and_alloc_pci_card(unsigned short vendor_id, err = pci_card_alloc(card); if (err != 0) { if (err > 0) - rt_printk(" - Can't allocate card!\n"); + printk(" - Can't allocate card!\n"); /* else: error already printed. */ return NULL; } diff --git a/drivers/staging/comedi/drivers/ii_pci20kc.c b/drivers/staging/comedi/drivers/ii_pci20kc.c index 80825ba25418..a90d65fde31e 100644 --- a/drivers/staging/comedi/drivers/ii_pci20kc.c +++ b/drivers/staging/comedi/drivers/ii_pci20kc.c @@ -158,21 +158,21 @@ struct pci20xxx_private { #define devpriv ((struct pci20xxx_private *)dev->private) #define CHAN (CR_CHAN(it->chanlist[0])) -static int pci20xxx_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int pci20xxx_detach(struct comedi_device * dev); +static int pci20xxx_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int pci20xxx_detach(struct comedi_device *dev); static struct comedi_driver driver_pci20xxx = { - driver_name:"ii_pci20kc", - module:THIS_MODULE, - attach:pci20xxx_attach, - detach:pci20xxx_detach, + .driver_name = "ii_pci20kc", + .module = THIS_MODULE, + .attach = pci20xxx_attach, + .detach = pci20xxx_detach, }; -static int pci20006_init(struct comedi_device * dev, struct comedi_subdevice * s, +static int pci20006_init(struct comedi_device *dev, struct comedi_subdevice *s, int opt0, int opt1); -static int pci20341_init(struct comedi_device * dev, struct comedi_subdevice * s, +static int pci20341_init(struct comedi_device *dev, struct comedi_subdevice *s, int opt0, int opt1); -static int pci20xxx_dio_init(struct comedi_device * dev, struct comedi_subdevice * s); +static int pci20xxx_dio_init(struct comedi_device *dev, struct comedi_subdevice *s); /* options[0] Board base address @@ -201,7 +201,7 @@ static int pci20xxx_dio_init(struct comedi_device * dev, struct comedi_subdevice 1 == unipolar 10V (0V -- +10V) 2 == bipolar 5V (-5V -- +5V) */ -static int pci20xxx_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int pci20xxx_attach(struct comedi_device *dev, struct comedi_devconfig *it) { unsigned char i; int ret; @@ -209,9 +209,12 @@ static int pci20xxx_attach(struct comedi_device * dev, struct comedi_devconfig * struct comedi_subdevice *s; union pci20xxx_subdev_private *sdp; - if ((ret = alloc_subdevices(dev, 1 + PCI20000_MODULES)) < 0) + ret = alloc_subdevices(dev, 1 + PCI20000_MODULES); + if (ret < 0) return ret; - if ((ret = alloc_private(dev, sizeof(struct pci20xxx_private))) < 0) + + ret = alloc_private(dev, sizeof(struct pci20xxx_private)); + if (ret < 0) return ret; devpriv->ioaddr = (void *)(unsigned long)it->options[0]; @@ -263,7 +266,7 @@ static int pci20xxx_attach(struct comedi_device * dev, struct comedi_devconfig * return 1; } -static int pci20xxx_detach(struct comedi_device * dev) +static int pci20xxx_detach(struct comedi_device *dev) { printk("comedi%d: pci20xxx: remove\n", dev->minor); @@ -272,10 +275,10 @@ static int pci20xxx_detach(struct comedi_device * dev) /* pci20006m */ -static int pci20006_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int pci20006_insn_write(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); +static int pci20006_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int pci20006_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); static const struct comedi_lrange *pci20006_range_list[] = { &range_bipolar10, @@ -283,7 +286,7 @@ static const struct comedi_lrange *pci20006_range_list[] = { &range_bipolar5, }; -static int pci20006_init(struct comedi_device * dev, struct comedi_subdevice * s, +static int pci20006_init(struct comedi_device *dev, struct comedi_subdevice *s, int opt0, int opt1) { union pci20xxx_subdev_private *sdp = s->private; @@ -308,8 +311,8 @@ static int pci20006_init(struct comedi_device * dev, struct comedi_subdevice * s return 0; } -static int pci20006_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pci20006_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { union pci20xxx_subdev_private *sdp = s->private; @@ -318,8 +321,8 @@ static int pci20006_insn_read(struct comedi_device * dev, struct comedi_subdevic return 1; } -static int pci20006_insn_write(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pci20006_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { union pci20xxx_subdev_private *sdp = s->private; int hi, lo; @@ -351,8 +354,8 @@ static int pci20006_insn_write(struct comedi_device * dev, struct comedi_subdevi /* PCI20341M */ -static int pci20341_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); +static int pci20341_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); static const int pci20341_timebase[] = { 0x00, 0x00, 0x00, 0x04 }; static const int pci20341_settling_time[] = { 0x58, 0x58, 0x93, 0x99 }; @@ -368,7 +371,7 @@ static const struct comedi_lrange *const pci20341_ranges[] = { &range_bipolar0_025, }; -static int pci20341_init(struct comedi_device * dev, struct comedi_subdevice * s, +static int pci20341_init(struct comedi_device *dev, struct comedi_subdevice *s, int opt0, int opt1) { union pci20xxx_subdev_private *sdp = s->private; @@ -399,8 +402,8 @@ static int pci20341_init(struct comedi_device * dev, struct comedi_subdevice * s return 0; } -static int pci20341_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pci20341_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { union pci20xxx_subdev_private *sdp = s->private; unsigned int i = 0, j = 0; @@ -445,14 +448,14 @@ static int pci20341_insn_read(struct comedi_device * dev, struct comedi_subdevic /* native DIO */ -static void pci20xxx_dio_config(struct comedi_device * dev, struct comedi_subdevice * s); -static int pci20xxx_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int pci20xxx_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); +static void pci20xxx_dio_config(struct comedi_device *dev, struct comedi_subdevice *s); +static int pci20xxx_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int pci20xxx_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); /* initialize struct pci20xxx_private */ -static int pci20xxx_dio_init(struct comedi_device * dev, struct comedi_subdevice * s) +static int pci20xxx_dio_init(struct comedi_device *dev, struct comedi_subdevice *s) { s->type = COMEDI_SUBD_DIO; @@ -471,8 +474,8 @@ static int pci20xxx_dio_init(struct comedi_device * dev, struct comedi_subdevice return 0; } -static int pci20xxx_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pci20xxx_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int mask, bits; @@ -496,8 +499,8 @@ static int pci20xxx_dio_insn_config(struct comedi_device * dev, struct comedi_su return 1; } -static int pci20xxx_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pci20xxx_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { unsigned int mask = data[0]; @@ -526,7 +529,7 @@ static int pci20xxx_dio_insn_bits(struct comedi_device * dev, struct comedi_subd return 2; } -static void pci20xxx_dio_config(struct comedi_device * dev, struct comedi_subdevice * s) +static void pci20xxx_dio_config(struct comedi_device *dev, struct comedi_subdevice *s) { unsigned char control_01; unsigned char control_23; @@ -582,7 +585,7 @@ static void pci20xxx_dio_config(struct comedi_device * dev, struct comedi_subdev } #if 0 -static void pci20xxx_do(struct comedi_device * dev, struct comedi_subdevice * s) +static void pci20xxx_do(struct comedi_device *dev, struct comedi_subdevice *s) { /* XXX if the channel is configured for input, does this do bad things? */ @@ -595,7 +598,7 @@ static void pci20xxx_do(struct comedi_device * dev, struct comedi_subdevice * s) writeb((s->state >> 24) & 0xff, devpriv->ioaddr + PCI20000_DIO_3); } -static unsigned int pci20xxx_di(struct comedi_device * dev, struct comedi_subdevice * s) +static unsigned int pci20xxx_di(struct comedi_device *dev, struct comedi_subdevice *s) { /* XXX same note as above */ unsigned int bits; diff --git a/drivers/staging/comedi/drivers/jr3_pci.c b/drivers/staging/comedi/drivers/jr3_pci.c index a3c887f3b2c6..baf83c6a9412 100644 --- a/drivers/staging/comedi/drivers/jr3_pci.c +++ b/drivers/staging/comedi/drivers/jr3_pci.c @@ -48,69 +48,20 @@ Devices: [JR3] PCI force sensor board (jr3_pci) #include "comedi_pci.h" #include "jr3_pci.h" -/* Hotplug firmware loading stuff */ - -static void comedi_fw_release(struct device *dev) -{ - printk(KERN_DEBUG "firmware_sample_driver: ghost_release\n"); -} - -static struct device comedi_fw_device = { - .init_name = "comedi", - .release = comedi_fw_release -}; - -typedef int comedi_firmware_callback(struct comedi_device * dev, - const u8 * data, size_t size); - -static int comedi_load_firmware(struct comedi_device * dev, - char *name, comedi_firmware_callback cb) -{ - int result = 0; - const struct firmware *fw; - char *firmware_path; - static const char *prefix = "comedi/"; - - firmware_path = kmalloc(strlen(prefix) + strlen(name) + 1, GFP_KERNEL); - if (!firmware_path) { - result = -ENOMEM; - } else { - firmware_path[0] = '\0'; - strcat(firmware_path, prefix); - strcat(firmware_path, name); - result = device_register(&comedi_fw_device); - if (result == 0) { - result = request_firmware(&fw, firmware_path, - &comedi_fw_device); - if (result == 0) { - if (!cb) { - result = -EINVAL; - } else { - result = cb(dev, fw->data, fw->size); - } - release_firmware(fw); - } - device_unregister(&comedi_fw_device); - } - kfree(firmware_path); - } - return result; -} - #define PCI_VENDOR_ID_JR3 0x1762 #define PCI_DEVICE_ID_JR3_1_CHANNEL 0x3111 #define PCI_DEVICE_ID_JR3_2_CHANNEL 0x3112 #define PCI_DEVICE_ID_JR3_3_CHANNEL 0x3113 #define PCI_DEVICE_ID_JR3_4_CHANNEL 0x3114 -static int jr3_pci_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int jr3_pci_detach(struct comedi_device * dev); +static int jr3_pci_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int jr3_pci_detach(struct comedi_device *dev); static struct comedi_driver driver_jr3_pci = { - driver_name:"jr3_pci", - module:THIS_MODULE, - attach:jr3_pci_attach, - detach:jr3_pci_detach, + .driver_name = "jr3_pci", + .module = THIS_MODULE, + .attach = jr3_pci_attach, + .detach = jr3_pci_detach, }; static DEFINE_PCI_DEVICE_TABLE(jr3_pci_pci_table) = { @@ -168,6 +119,41 @@ struct jr3_pci_subdev_private { int retries; }; +/* Hotplug firmware loading stuff */ + +typedef int comedi_firmware_callback(struct comedi_device *dev, + const u8 *data, size_t size); + +static int comedi_load_firmware(struct comedi_device *dev, char *name, + comedi_firmware_callback cb) +{ + int result = 0; + const struct firmware *fw; + char *firmware_path; + static const char *prefix = "comedi/"; + struct jr3_pci_dev_private *devpriv = dev->private; + + firmware_path = kmalloc(strlen(prefix) + strlen(name) + 1, GFP_KERNEL); + if (!firmware_path) { + result = -ENOMEM; + } else { + firmware_path[0] = '\0'; + strcat(firmware_path, prefix); + strcat(firmware_path, name); + result = request_firmware(&fw, firmware_path, + &devpriv->pci_dev->dev); + if (result == 0) { + if (!cb) + result = -EINVAL; + else + result = cb(dev, fw->data, fw->size); + release_firmware(fw); + } + kfree(firmware_path); + } + return result; +} + static struct poll_delay_t poll_delay_min_max(int min, int max) { struct poll_delay_t result; @@ -194,15 +180,15 @@ static void set_transforms(volatile struct jr3_channel *channel, { int i; - num &= 0x000f; // Make sure that 0 <= num <= 15 + num &= 0x000f; /* Make sure that 0 <= num <= 15 */ for (i = 0; i < 8; i++) { set_u16(&channel->transforms[num].link[i].link_type, transf.link[i].link_type); - comedi_udelay(1); + udelay(1); set_s16(&channel->transforms[num].link[i].link_amount, transf.link[i].link_amount); - comedi_udelay(1); + udelay(1); if (transf.link[i].link_type == end_x_form) { break; } @@ -273,8 +259,8 @@ static struct six_axis_t get_max_full_scales(volatile struct jr3_channel *channe return result; } -static int jr3_pci_ai_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int jr3_pci_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int result; struct jr3_pci_subdev_private *p; @@ -389,7 +375,7 @@ static int jr3_pci_ai_insn_read(struct comedi_device * dev, struct comedi_subdev return result; } -static void jr3_pci_open(struct comedi_device * dev) +static void jr3_pci_open(struct comedi_device *dev) { int i; struct jr3_pci_dev_private *devpriv = dev->private; @@ -406,14 +392,14 @@ static void jr3_pci_open(struct comedi_device * dev) } } -int read_idm_word(const u8 * data, size_t size, int *pos, unsigned int *val) +int read_idm_word(const u8 *data, size_t size, int *pos, unsigned int *val) { int result = 0; if (pos != 0 && val != 0) { - // Skip over non hex + /* Skip over non hex */ for (; *pos < size && !isxdigit(data[*pos]); (*pos)++) { } - // Collect value + /* Collect value */ *val = 0; for (; *pos < size && isxdigit(data[*pos]); (*pos)++) { char ch = tolower(data[*pos]); @@ -428,7 +414,7 @@ int read_idm_word(const u8 * data, size_t size, int *pos, unsigned int *val) return result; } -static int jr3_download_firmware(struct comedi_device * dev, const u8 * data, +static int jr3_download_firmware(struct comedi_device *dev, const u8 *data, size_t size) { /* @@ -485,17 +471,17 @@ static int jr3_download_firmware(struct comedi_device * dev, const u8 * data, count, addr); while (more && count > 0) { if (addr & 0x4000) { - // 16 bit data, never seen in real life!! + /* 16 bit data, never seen in real life!! */ unsigned int data1; more = more && read_idm_word(data, size, &pos, &data1); count--; - // printk("jr3_data, not tested\n"); - // jr3[addr + 0x20000 * pnum] = data1; + /* printk("jr3_data, not tested\n"); */ + /* jr3[addr + 0x20000 * pnum] = data1; */ } else { - // Download 24 bit program + /* Download 24 bit program */ unsigned int data1, data2; more = more @@ -510,12 +496,12 @@ static int jr3_download_firmware(struct comedi_device * dev, const u8 * data, channel[i]. program_low [addr], data1); - comedi_udelay(1); + udelay(1); set_u16(&p->iobase-> channel[i]. program_high [addr], data2); - comedi_udelay(1); + udelay(1); } } @@ -527,7 +513,7 @@ static int jr3_download_firmware(struct comedi_device * dev, const u8 * data, return result; } -static struct poll_delay_t jr3_pci_poll_subdevice(struct comedi_subdevice * s) +static struct poll_delay_t jr3_pci_poll_subdevice(struct comedi_subdevice *s) { struct poll_delay_t result = poll_delay_min_max(1000, 2000); struct jr3_pci_subdev_private *p = s->private; @@ -541,7 +527,7 @@ static struct poll_delay_t jr3_pci_poll_subdevice(struct comedi_subdevice * s) p->errors = errors; } if (errors & (watch_dog | watch_dog2 | sensor_change)) { - // Sensor communication lost, force poll mode + /* Sensor communication lost, force poll mode */ p->state = state_jr3_poll; } @@ -551,9 +537,10 @@ static struct poll_delay_t jr3_pci_poll_subdevice(struct comedi_subdevice * s) u16 serial_no = get_u16(&channel->serial_no); if ((errors & (watch_dog | watch_dog2)) || model_no == 0 || serial_no == 0) { - // Still no sensor, keep on polling. Since it takes up to - // 10 seconds for offsets to stabilize, polling each - // second should suffice. +/* + * Still no sensor, keep on polling. Since it takes up to 10 seconds + * for offsets to stabilize, polling each second should suffice. + */ result = poll_delay_min_max(1000, 2000); } else { p->retries = 0; @@ -566,7 +553,7 @@ static struct poll_delay_t jr3_pci_poll_subdevice(struct comedi_subdevice * s) case state_jr3_init_wait_for_offset:{ p->retries++; if (p->retries < 10) { - // Wait for offeset to stabilize (< 10 s according to manual) + /* Wait for offeset to stabilize (< 10 s according to manual) */ result = poll_delay_min_max(1000, 2000); } else { struct transform_t transf; @@ -582,7 +569,7 @@ static struct poll_delay_t jr3_pci_poll_subdevice(struct comedi_subdevice * s) printk("Sensor Serial = %i\n", p->serial_no); - // Transformation all zeros + /* Transformation all zeros */ transf.link[0].link_type = (enum link_types)0; transf.link[0].link_amount = 0; @@ -600,7 +587,7 @@ static struct poll_delay_t jr3_pci_poll_subdevice(struct comedi_subdevice * s) use_transform(channel, 0); p->state = state_jr3_init_transform_complete; - result = poll_delay_min_max(20, 100); // Allow 20 ms for completion + result = poll_delay_min_max(20, 100); /* Allow 20 ms for completion */ } } break; case state_jr3_init_transform_complete:{ @@ -608,7 +595,7 @@ static struct poll_delay_t jr3_pci_poll_subdevice(struct comedi_subdevice * s) printk("state_jr3_init_transform_complete complete = %d\n", is_complete(channel)); result = poll_delay_min_max(20, 100); } else { - // Set full scale + /* Set full scale */ struct six_axis_t min_full_scale; struct six_axis_t max_full_scale; @@ -639,7 +626,7 @@ static struct poll_delay_t jr3_pci_poll_subdevice(struct comedi_subdevice * s) p->state = state_jr3_init_set_full_scale_complete; - result = poll_delay_min_max(20, 100); // Allow 20 ms for completion + result = poll_delay_min_max(20, 100); /* Allow 20 ms for completion */ } } break; @@ -650,7 +637,7 @@ static struct poll_delay_t jr3_pci_poll_subdevice(struct comedi_subdevice * s) } else { volatile struct force_array *full_scale; - // Use ranges in kN or we will overflow arount 2000N! + /* Use ranges in kN or we will overflow arount 2000N! */ full_scale = &channel->full_scale; p->range[0].range.min = -get_s16(&full_scale->fx) * @@ -679,10 +666,10 @@ static struct poll_delay_t jr3_pci_poll_subdevice(struct comedi_subdevice * s) -get_s16(&full_scale->mz) * 100; p->range[5].range.max = get_s16(&full_scale->mz) * 100; - p->range[6].range.min = -get_s16(&full_scale->v1) * 100; // ?? - p->range[6].range.max = get_s16(&full_scale->v1) * 100; // ?? - p->range[7].range.min = -get_s16(&full_scale->v2) * 100; // ?? - p->range[7].range.max = get_s16(&full_scale->v2) * 100; // ?? + p->range[6].range.min = -get_s16(&full_scale->v1) * 100; /* ?? */ + p->range[6].range.max = get_s16(&full_scale->v1) * 100; /* ?? */ + p->range[7].range.min = -get_s16(&full_scale->v2) * 100; /* ?? */ + p->range[7].range.max = get_s16(&full_scale->v2) * 100; /* ?? */ p->range[8].range.min = 0; p->range[8].range.max = 65535; @@ -701,7 +688,7 @@ static struct poll_delay_t jr3_pci_poll_subdevice(struct comedi_subdevice * s) use_offset(channel, 0); p->state = state_jr3_init_use_offset_complete; - result = poll_delay_min_max(40, 100); // Allow 40 ms for completion + result = poll_delay_min_max(40, 100); /* Allow 40 ms for completion */ } } break; @@ -747,10 +734,10 @@ static void jr3_pci_poll_dev(unsigned long data) int delay; int i; - comedi_spin_lock_irqsave(&dev->spinlock, flags); + spin_lock_irqsave(&dev->spinlock, flags); delay = 1000; now = jiffies; - // Poll all channels that are ready to be polled + /* Poll all channels that are ready to be polled */ for (i = 0; i < devpriv->n_channels; i++) { struct jr3_pci_subdev_private *subdevpriv = dev->subdevices[i].private; if (now > subdevpriv->next_time_min) { @@ -762,19 +749,21 @@ static void jr3_pci_poll_dev(unsigned long data) subdevpriv->next_time_max = jiffies + msecs_to_jiffies(sub_delay.max); if (sub_delay.max && sub_delay.max < delay) { - // Wake up as late as possible -> poll as many channels as - // possible at once +/* +* Wake up as late as possible -> poll as many channels as possible +* at once +*/ delay = sub_delay.max; } } } - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); devpriv->timer.expires = jiffies + msecs_to_jiffies(delay); add_timer(&devpriv->timer); } -static int jr3_pci_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int jr3_pci_attach(struct comedi_device *dev, struct comedi_devconfig *it) { int result = 0; struct pci_dev *card = NULL; @@ -845,9 +834,12 @@ static int jr3_pci_attach(struct comedi_device * dev, struct comedi_devconfig * devpriv->pci_dev = card; dev->board_name = "jr3_pci"; } - if ((result = comedi_pci_enable(card, "jr3_pci")) < 0) { + + result = comedi_pci_enable(card, "jr3_pci"); + if (result < 0) { return -EIO; } + devpriv->pci_enabled = 1; devpriv->iobase = ioremap(pci_resource_start(card, 0), sizeof(struct jr3_t)); result = alloc_subdevices(dev, devpriv->n_channels); @@ -881,7 +873,7 @@ static int jr3_pci_attach(struct comedi_device * dev, struct comedi_devconfig * p->range[j].range.max = 1000000; for (k = 0; k < 7; k++) { p->range_table_list[j + k * 8] = - (struct comedi_lrange *) & p->range[j]; + (struct comedi_lrange *) &p->range[j]; p->maxdata_list[j + k * 8] = 0x7fff; } } @@ -890,12 +882,12 @@ static int jr3_pci_attach(struct comedi_device * dev, struct comedi_devconfig * p->range[8].range.max = 65536; p->range_table_list[56] = - (struct comedi_lrange *) & p->range[8]; + (struct comedi_lrange *) &p->range[8]; p->range_table_list[57] = - (struct comedi_lrange *) & p->range[8]; + (struct comedi_lrange *) &p->range[8]; p->maxdata_list[56] = 0xffff; p->maxdata_list[57] = 0xffff; - // Channel specific range and maxdata + /* Channel specific range and maxdata */ dev->subdevices[i].range_table = 0; dev->subdevices[i].range_table_list = p->range_table_list; @@ -904,7 +896,7 @@ static int jr3_pci_attach(struct comedi_device * dev, struct comedi_devconfig * } } - // Reset DSP card + /* Reset DSP card */ devpriv->iobase->channel[0].reset = 0; result = comedi_load_firmware(dev, "jr3pci.idm", jr3_download_firmware); @@ -913,13 +905,18 @@ static int jr3_pci_attach(struct comedi_device * dev, struct comedi_devconfig * if (result < 0) { goto out; } - // TODO: use firmware to load preferred offset tables. Suggested format: - // model serial Fx Fy Fz Mx My Mz\n - // - // comedi_load_firmware(dev, "jr3_offsets_table", jr3_download_firmware); +/* + * TODO: use firmware to load preferred offset tables. Suggested + * format: + * model serial Fx Fy Fz Mx My Mz\n + * + * comedi_load_firmware(dev, "jr3_offsets_table", jr3_download_firmware); + */ - // It takes a few milliseconds for software to settle - // as much as we can read firmware version +/* + * It takes a few milliseconds for software to settle as much as we + * can read firmware version + */ msleep_interruptible(25); for (i = 0; i < 0x18; i++) { printk("%c", @@ -927,7 +924,7 @@ static int jr3_pci_attach(struct comedi_device * dev, struct comedi_devconfig * copyright[i]) >> 8); } - // Start card timer + /* Start card timer */ for (i = 0; i < devpriv->n_channels; i++) { struct jr3_pci_subdev_private *p = dev->subdevices[i].private; @@ -944,7 +941,7 @@ static int jr3_pci_attach(struct comedi_device * dev, struct comedi_devconfig * return result; } -static int jr3_pci_detach(struct comedi_device * dev) +static int jr3_pci_detach(struct comedi_device *dev) { int i; struct jr3_pci_dev_private *devpriv = dev->private; diff --git a/drivers/staging/comedi/drivers/jr3_pci.h b/drivers/staging/comedi/drivers/jr3_pci.h index 3585f2941bca..4f4bfb24c6d6 100644 --- a/drivers/staging/comedi/drivers/jr3_pci.h +++ b/drivers/staging/comedi/drivers/jr3_pci.h @@ -2,22 +2,22 @@ * is 16 bits, but aligned on a 32 bit PCI boundary */ -static inline u16 get_u16(volatile const u32 * p) +static inline u16 get_u16(volatile const u32 *p) { return (u16) readl(p); } -static inline void set_u16(volatile u32 * p, u16 val) +static inline void set_u16(volatile u32 *p, u16 val) { writel(val, p); } -static inline s16 get_s16(volatile const s32 * p) +static inline s16 get_s16(volatile const s32 *p) { return (s16) readl(p); } -static inline void set_s16(volatile s32 * p, s16 val) +static inline void set_s16(volatile s32 *p, s16 val) { writel(val, p); } diff --git a/drivers/staging/comedi/drivers/ke_counter.c b/drivers/staging/comedi/drivers/ke_counter.c index 79f6fe5646c5..b49aed5c4a02 100644 --- a/drivers/staging/comedi/drivers/ke_counter.c +++ b/drivers/staging/comedi/drivers/ke_counter.c @@ -48,8 +48,8 @@ Kolter Electronic PCI Counter Card. /*-- function prototypes ----------------------------------------------------*/ -static int cnt_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int cnt_detach(struct comedi_device * dev); +static int cnt_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int cnt_detach(struct comedi_device *dev); static DEFINE_PCI_DEVICE_TABLE(cnt_pci_table) = { {PCI_VENDOR_ID_KOLTER, CNT_CARD_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, @@ -72,10 +72,10 @@ struct cnt_board_struct { static const struct cnt_board_struct cnt_boards[] = { { - name: CNT_DRIVER_NAME, - device_id:CNT_CARD_DEVICE_ID, - cnt_channel_nbr:3, - cnt_bits:24} + .name = CNT_DRIVER_NAME, + .device_id = CNT_CARD_DEVICE_ID, + .cnt_channel_nbr = 3, + .cnt_bits = 24} }; #define cnt_board_nbr (sizeof(cnt_boards)/sizeof(struct cnt_board_struct)) @@ -91,10 +91,10 @@ struct cnt_device_private { #define devpriv ((struct cnt_device_private *)dev->private) static struct comedi_driver cnt_driver = { - driver_name:CNT_DRIVER_NAME, - module:THIS_MODULE, - attach:cnt_attach, - detach:cnt_detach, + .driver_name = CNT_DRIVER_NAME, + .module = THIS_MODULE, + .attach = cnt_attach, + .detach = cnt_detach, }; COMEDI_PCI_INITCLEANUP(cnt_driver, cnt_pci_table); @@ -103,8 +103,8 @@ COMEDI_PCI_INITCLEANUP(cnt_driver, cnt_pci_table); /* This should be used only for resetting the counters; maybe it is better to make a special command 'reset'. */ -static int cnt_winsn(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +static int cnt_winsn(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { int chan = CR_CHAN(insn->chanspec); @@ -123,8 +123,8 @@ static int cnt_winsn(struct comedi_device * dev, /*-- counter read -----------------------------------------------------------*/ -static int cnt_rinsn(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +static int cnt_rinsn(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { unsigned char a0, a1, a2, a3, a4; int chan = CR_CHAN(insn->chanspec); @@ -148,7 +148,7 @@ static int cnt_rinsn(struct comedi_device * dev, /*-- attach -----------------------------------------------------------------*/ -static int cnt_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int cnt_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *subdevice; struct pci_dev *pci_device; @@ -157,9 +157,9 @@ static int cnt_attach(struct comedi_device * dev, struct comedi_devconfig * it) int error, i; /* allocate device private structure */ - if ((error = alloc_private(dev, sizeof(struct cnt_device_private))) < 0) { + error = alloc_private(dev, sizeof(struct cnt_device_private)); + if (error < 0) return error; - } /* Probe the device to determine what device in the series it is. */ for (pci_device = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL); @@ -203,7 +203,8 @@ static int cnt_attach(struct comedi_device * dev, struct comedi_devconfig * it) dev->board_name = board->name; /* enable PCI device and request regions */ - if ((error = comedi_pci_enable(pci_device, CNT_DRIVER_NAME)) < 0) { + error = comedi_pci_enable(pci_device, CNT_DRIVER_NAME); + if (error < 0) { printk("comedi%d: failed to enable PCI device and request regions!\n", dev->minor); return error; } @@ -213,9 +214,9 @@ static int cnt_attach(struct comedi_device * dev, struct comedi_devconfig * it) dev->iobase = io_base; /* allocate the subdevice structures */ - if ((error = alloc_subdevices(dev, 1)) < 0) { + error = alloc_subdevices(dev, 1); + if (error < 0) return error; - } subdevice = dev->subdevices + 0; dev->read_subdev = subdevice; @@ -227,10 +228,10 @@ static int cnt_attach(struct comedi_device * dev, struct comedi_devconfig * it) subdevice->insn_read = cnt_rinsn; subdevice->insn_write = cnt_winsn; - // select 20MHz clock + /* select 20MHz clock */ outb(3, dev->iobase + 248); - // reset all counters + /* reset all counters */ outb(0, dev->iobase); outb(0, dev->iobase + 0x20); outb(0, dev->iobase + 0x40); @@ -241,7 +242,7 @@ static int cnt_attach(struct comedi_device * dev, struct comedi_devconfig * it) /*-- detach -----------------------------------------------------------------*/ -static int cnt_detach(struct comedi_device * dev) +static int cnt_detach(struct comedi_device *dev) { if (devpriv && devpriv->pcidev) { if (dev->iobase) { diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index 12481a032b9f..236845871735 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -51,6 +51,7 @@ broken. */ +#include #include "../comedidev.h" #include @@ -113,7 +114,7 @@ static const struct me4000_board me4000_boards[] = { {0}, }; -#define ME4000_BOARD_VERSIONS (sizeof(me4000_boards) / sizeof(struct me4000_board) - 1) +#define ME4000_BOARD_VERSIONS (ARRAY_SIZE(me4000_boards) - 1) /*----------------------------------------------------------------------------- Comedi function prototypes @@ -183,7 +184,7 @@ static int ai_prepare(struct comedi_device *dev, static int ai_write_chanlist(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd); -static irqreturn_t me4000_ai_isr(int irq, void *dev_id PT_REGS_ARG); +static irqreturn_t me4000_ai_isr(int irq, void *dev_id); static int me4000_ai_do_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd); @@ -283,7 +284,7 @@ static int me4000_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->insn_read = me4000_ai_insn_read; if (info->irq > 0) { - if (comedi_request_irq(info->irq, me4000_ai_isr, + if (request_irq(info->irq, me4000_ai_isr, IRQF_SHARED, "ME-4000", dev)) { printk("comedi%d: me4000: me4000_attach(): Unable to allocate irq\n", dev->minor); } else { @@ -1740,7 +1741,7 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev, return 0; } -static irqreturn_t me4000_ai_isr(int irq, void *dev_id PT_REGS_ARG) +static irqreturn_t me4000_ai_isr(int irq, void *dev_id) { unsigned int tmp; struct comedi_device *dev = dev_id; diff --git a/drivers/staging/comedi/drivers/me_daq.c b/drivers/staging/comedi/drivers/me_daq.c index 0f023d009e61..f21cecaa2e09 100644 --- a/drivers/staging/comedi/drivers/me_daq.c +++ b/drivers/staging/comedi/drivers/me_daq.c @@ -50,6 +50,7 @@ from http://www.comedi.org */ +#include #include "../comedidev.h" #include "comedi_pci.h" diff --git a/drivers/staging/comedi/drivers/mite.c b/drivers/staging/comedi/drivers/mite.c index ae9017744537..22a4029c30b5 100644 --- a/drivers/staging/comedi/drivers/mite.c +++ b/drivers/staging/comedi/drivers/mite.c @@ -258,7 +258,7 @@ struct mite_channel *mite_request_channel_in_range(struct mite_struct *mite, struct mite_channel *channel = NULL; /* spin lock so mite_release_channel can be called safely from interrupts */ - comedi_spin_lock_irqsave(&mite->lock, flags); + spin_lock_irqsave(&mite->lock, flags); for (i = min_channel; i <= max_channel; ++i) { if (mite->channel_allocated[i] == 0) { mite->channel_allocated[i] = 1; @@ -267,7 +267,7 @@ struct mite_channel *mite_request_channel_in_range(struct mite_struct *mite, break; } } - comedi_spin_unlock_irqrestore(&mite->lock, flags); + spin_unlock_irqrestore(&mite->lock, flags); return channel; } @@ -277,7 +277,7 @@ void mite_release_channel(struct mite_channel *mite_chan) unsigned long flags; /* spin lock to prevent races with mite_request_channel */ - comedi_spin_lock_irqsave(&mite->lock, flags); + spin_lock_irqsave(&mite->lock, flags); if (mite->channel_allocated[mite_chan->channel]) { mite_dma_disarm(mite_chan); mite_dma_reset(mite_chan); @@ -292,7 +292,7 @@ MITE_CHCR reg isn't changed while dma is still active!) */ mite_chan->ring = NULL; mmiowb(); } - comedi_spin_unlock_irqrestore(&mite->lock, flags); + spin_unlock_irqrestore(&mite->lock, flags); } void mite_dma_arm(struct mite_channel *mite_chan) @@ -307,11 +307,11 @@ void mite_dma_arm(struct mite_channel *mite_chan) smp_mb(); /* arm */ chor = CHOR_START; - comedi_spin_lock_irqsave(&mite->lock, flags); + spin_lock_irqsave(&mite->lock, flags); mite_chan->done = 0; writel(chor, mite->mite_io_addr + MITE_CHOR(mite_chan->channel)); mmiowb(); - comedi_spin_unlock_irqrestore(&mite->lock, flags); + spin_unlock_irqrestore(&mite->lock, flags); /* mite_dma_tcr(mite, channel); */ } @@ -413,7 +413,7 @@ void mite_prep_dma(struct mite_channel *mite_chan, mcr |= CR_PSIZE32; break; default: - rt_printk + printk ("mite: bug! invalid mem bit width for dma transfer\n"); break; } @@ -433,7 +433,7 @@ void mite_prep_dma(struct mite_channel *mite_chan, dcr |= CR_PSIZE32; break; default: - rt_printk + printk ("mite: bug! invalid dev bit width for dma transfer\n"); break; } @@ -539,7 +539,7 @@ int mite_sync_input_dma(struct mite_channel *mite_chan, struct comedi_async * as nbytes = mite_bytes_written_to_memory_lb(mite_chan); if ((int)(mite_bytes_written_to_memory_ub(mite_chan) - old_alloc_count) > 0) { - rt_printk("mite: DMA overwrite of free area\n"); + printk("mite: DMA overwrite of free area\n"); async->events |= COMEDI_CB_OVERFLOW; return -1; } @@ -581,7 +581,7 @@ int mite_sync_output_dma(struct mite_channel *mite_chan, struct comedi_async * a (int)(nbytes_ub - stop_count) > 0) nbytes_ub = stop_count; if ((int)(nbytes_ub - old_alloc_count) > 0) { - rt_printk("mite: DMA underrun\n"); + printk("mite: DMA underrun\n"); async->events |= COMEDI_CB_OVERFLOW; return -1; } @@ -602,7 +602,7 @@ unsigned mite_get_status(struct mite_channel *mite_chan) unsigned status; unsigned long flags; - comedi_spin_lock_irqsave(&mite->lock, flags); + spin_lock_irqsave(&mite->lock, flags); status = readl(mite->mite_io_addr + MITE_CHSR(mite_chan->channel)); if (status & CHSR_DONE) { mite_chan->done = 1; @@ -610,7 +610,7 @@ unsigned mite_get_status(struct mite_channel *mite_chan) mite->mite_io_addr + MITE_CHOR(mite_chan->channel)); } mmiowb(); - comedi_spin_unlock_irqrestore(&mite->lock, flags); + spin_unlock_irqrestore(&mite->lock, flags); return status; } @@ -621,9 +621,9 @@ int mite_done(struct mite_channel *mite_chan) int done; mite_get_status(mite_chan); - comedi_spin_lock_irqsave(&mite->lock, flags); + spin_lock_irqsave(&mite->lock, flags); done = mite_chan->done; - comedi_spin_unlock_irqrestore(&mite->lock, flags); + spin_unlock_irqrestore(&mite->lock, flags); return done; } diff --git a/drivers/staging/comedi/drivers/mite.h b/drivers/staging/comedi/drivers/mite.h index cdaf8a31688a..31942319aa38 100644 --- a/drivers/staging/comedi/drivers/mite.h +++ b/drivers/staging/comedi/drivers/mite.h @@ -405,7 +405,7 @@ static inline int CR_RL(unsigned int retry_limit) value++; } if (value > 0x7) - rt_printk("comedi: bug! retry_limit too large\n"); + printk("comedi: bug! retry_limit too large\n"); return (value & 0x7) << 21; } diff --git a/drivers/staging/comedi/drivers/mpc624.c b/drivers/staging/comedi/drivers/mpc624.c index a151602929d9..4a0e647f631a 100644 --- a/drivers/staging/comedi/drivers/mpc624.c +++ b/drivers/staging/comedi/drivers/mpc624.c @@ -61,19 +61,19 @@ Configuration Options: #include #include -// Consecutive I/O port addresses +/* Consecutive I/O port addresses */ #define MPC624_SIZE 16 -// Offsets of different ports -#define MPC624_MASTER_CONTROL 0 // not used -#define MPC624_GNMUXCH 1 // Gain, Mux, Channel of ADC -#define MPC624_ADC 2 // read/write to/from ADC -#define MPC624_EE 3 // read/write to/from serial EEPROM via I2C -#define MPC624_LEDS 4 // write to LEDs -#define MPC624_DIO 5 // read/write to/from digital I/O ports -#define MPC624_IRQ_MASK 6 // IRQ masking enable/disable +/* Offsets of different ports */ +#define MPC624_MASTER_CONTROL 0 /* not used */ +#define MPC624_GNMUXCH 1 /* Gain, Mux, Channel of ADC */ +#define MPC624_ADC 2 /* read/write to/from ADC */ +#define MPC624_EE 3 /* read/write to/from serial EEPROM via I2C */ +#define MPC624_LEDS 4 /* write to LEDs */ +#define MPC624_DIO 5 /* read/write to/from digital I/O ports */ +#define MPC624_IRQ_MASK 6 /* IRQ masking enable/disable */ -// Register bits' names +/* Register bits' names */ #define MPC624_ADBUSY (1<<5) #define MPC624_ADSDO (1<<4) #define MPC624_ADFO (1<<3) @@ -81,19 +81,19 @@ Configuration Options: #define MPC624_ADSCK (1<<1) #define MPC624_ADSDI (1<<0) -// SDI Speed/Resolution Programming bits +/* SDI Speed/Resolution Programming bits */ #define MPC624_OSR4 (1<<31) #define MPC624_OSR3 (1<<30) #define MPC624_OSR2 (1<<29) #define MPC624_OSR1 (1<<28) #define MPC624_OSR0 (1<<27) -// 32-bit output value bits' names +/* 32-bit output value bits' names */ #define MPC624_EOC_BIT (1<<31) #define MPC624_DMY_BIT (1<<30) #define MPC624_SGN_BIT (1<<29) -// Convertion speeds +/* Convertion speeds */ /* OSR4 OSR3 OSR2 OSR1 OSR0 Convertion rate RMS noise ENOB^ * X 0 0 0 1 3.52kHz 23uV 17 * X 0 0 1 0 1.76kHz 3.5uV 20 @@ -110,123 +110,123 @@ Configuration Options: */ #define MPC624_SPEED_3_52_kHz (MPC624_OSR4 | MPC624_OSR0) -#define MPC624_SPEED_1_76_kHz (MPC624_OSR4 | MPC624_OSR1 ) +#define MPC624_SPEED_1_76_kHz (MPC624_OSR4 | MPC624_OSR1) #define MPC624_SPEED_880_Hz (MPC624_OSR4 | MPC624_OSR1 | MPC624_OSR0) -#define MPC624_SPEED_440_Hz (MPC624_OSR4 | MPC624_OSR2 ) +#define MPC624_SPEED_440_Hz (MPC624_OSR4 | MPC624_OSR2) #define MPC624_SPEED_220_Hz (MPC624_OSR4 | MPC624_OSR2 | MPC624_OSR0) -#define MPC624_SPEED_110_Hz (MPC624_OSR4 | MPC624_OSR2 | MPC624_OSR1 ) +#define MPC624_SPEED_110_Hz (MPC624_OSR4 | MPC624_OSR2 | MPC624_OSR1) #define MPC624_SPEED_55_Hz (MPC624_OSR4 | MPC624_OSR2 | MPC624_OSR1 | MPC624_OSR0) -#define MPC624_SPEED_27_5_Hz (MPC624_OSR4 | MPC624_OSR3 ) +#define MPC624_SPEED_27_5_Hz (MPC624_OSR4 | MPC624_OSR3) #define MPC624_SPEED_13_75_Hz (MPC624_OSR4 | MPC624_OSR3 | MPC624_OSR0) #define MPC624_SPEED_6_875_Hz (MPC624_OSR4 | MPC624_OSR3 | MPC624_OSR2 | MPC624_OSR1 | MPC624_OSR0) -//---------------------------------------------------------------------------- +/* ---------------------------------------------------------------------------- */ struct skel_private { - unsigned long int ulConvertionRate; // set by mpc624_attach() from driver's parameters + unsigned long int ulConvertionRate; /* set by mpc624_attach() from driver's parameters */ }; #define devpriv ((struct skel_private *)dev->private) -//---------------------------------------------------------------------------- +/* ---------------------------------------------------------------------------- */ static const struct comedi_lrange range_mpc624_bipolar1 = { 1, { -// BIP_RANGE(1.01) // this is correct, - // but my MPC-624 actually seems to have a range of 2.02 +/* BIP_RANGE(1.01) this is correct, */ + /* but my MPC-624 actually seems to have a range of 2.02 */ BIP_RANGE(2.02) } }; static const struct comedi_lrange range_mpc624_bipolar10 = { 1, { -// BIP_RANGE(10.1) // this is correct, - // but my MPC-624 actually seems to have a range of 20.2 +/* BIP_RANGE(10.1) this is correct, */ + /* but my MPC-624 actually seems to have a range of 20.2 */ BIP_RANGE(20.2) } }; -//---------------------------------------------------------------------------- -static int mpc624_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int mpc624_detach(struct comedi_device * dev); -//---------------------------------------------------------------------------- +/* ---------------------------------------------------------------------------- */ +static int mpc624_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int mpc624_detach(struct comedi_device *dev); +/* ---------------------------------------------------------------------------- */ static struct comedi_driver driver_mpc624 = { - driver_name:"mpc624", - module:THIS_MODULE, - attach:mpc624_attach, - detach:mpc624_detach + .driver_name = "mpc624", + .module = THIS_MODULE, + .attach = mpc624_attach, + .detach = mpc624_detach }; -//---------------------------------------------------------------------------- -static int mpc624_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -//---------------------------------------------------------------------------- -static int mpc624_attach(struct comedi_device * dev, struct comedi_devconfig * it) +/* ---------------------------------------------------------------------------- */ +static int mpc624_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +/* ---------------------------------------------------------------------------- */ +static int mpc624_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; unsigned long iobase; iobase = it->options[0]; - rt_printk("comedi%d: mpc624 [0x%04lx, ", dev->minor, iobase); + printk("comedi%d: mpc624 [0x%04lx, ", dev->minor, iobase); if (request_region(iobase, MPC624_SIZE, "mpc624") == NULL) { - rt_printk("I/O port(s) in use\n"); + printk("I/O port(s) in use\n"); return -EIO; } dev->iobase = iobase; dev->board_name = "mpc624"; - // Private structure initialization + /* Private structure initialization */ if (alloc_private(dev, sizeof(struct skel_private)) < 0) return -ENOMEM; switch (it->options[1]) { case 0: devpriv->ulConvertionRate = MPC624_SPEED_3_52_kHz; - rt_printk("3.52 kHz, "); + printk("3.52 kHz, "); break; case 1: devpriv->ulConvertionRate = MPC624_SPEED_1_76_kHz; - rt_printk("1.76 kHz, "); + printk("1.76 kHz, "); break; case 2: devpriv->ulConvertionRate = MPC624_SPEED_880_Hz; - rt_printk("880 Hz, "); + printk("880 Hz, "); break; case 3: devpriv->ulConvertionRate = MPC624_SPEED_440_Hz; - rt_printk("440 Hz, "); + printk("440 Hz, "); break; case 4: devpriv->ulConvertionRate = MPC624_SPEED_220_Hz; - rt_printk("220 Hz, "); + printk("220 Hz, "); break; case 5: devpriv->ulConvertionRate = MPC624_SPEED_110_Hz; - rt_printk("110 Hz, "); + printk("110 Hz, "); break; case 6: devpriv->ulConvertionRate = MPC624_SPEED_55_Hz; - rt_printk("55 Hz, "); + printk("55 Hz, "); break; case 7: devpriv->ulConvertionRate = MPC624_SPEED_27_5_Hz; - rt_printk("27.5 Hz, "); + printk("27.5 Hz, "); break; case 8: devpriv->ulConvertionRate = MPC624_SPEED_13_75_Hz; - rt_printk("13.75 Hz, "); + printk("13.75 Hz, "); break; case 9: devpriv->ulConvertionRate = MPC624_SPEED_6_875_Hz; - rt_printk("6.875 Hz, "); + printk("6.875 Hz, "); break; default: - rt_printk + printk ("illegal convertion rate setting! Valid numbers are 0..9. Using 9 => 6.875 Hz, "); devpriv->ulConvertionRate = MPC624_SPEED_3_52_kHz; } - // Subdevices structures + /* Subdevices structures */ if (alloc_subdevices(dev, 1) < 0) return -ENOMEM; @@ -237,29 +237,29 @@ static int mpc624_attach(struct comedi_device * dev, struct comedi_devconfig * i switch (it->options[1]) { default: s->maxdata = 0x3FFFFFFF; - rt_printk("30 bit, "); + printk("30 bit, "); } switch (it->options[1]) { case 0: s->range_table = &range_mpc624_bipolar1; - rt_printk("1.01V]: "); + printk("1.01V]: "); break; default: s->range_table = &range_mpc624_bipolar10; - rt_printk("10.1V]: "); + printk("10.1V]: "); } s->len_chanlist = 1; s->insn_read = mpc624_ai_rinsn; - rt_printk("attached\n"); + printk("attached\n"); return 1; } -static int mpc624_detach(struct comedi_device * dev) +static int mpc624_detach(struct comedi_device *dev) { - rt_printk("comedi%d: mpc624: remove\n", dev->minor); + printk("comedi%d: mpc624: remove\n", dev->minor); if (dev->iobase) release_region(dev->iobase, MPC624_SIZE); @@ -267,119 +267,119 @@ static int mpc624_detach(struct comedi_device * dev) return 0; } -// Timeout 200ms +/* Timeout 200ms */ #define TIMEOUT 200 -static int mpc624_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int mpc624_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int n, i; unsigned long int data_in, data_out; unsigned char ucPort; - // WARNING: We always write 0 to GNSWA bit, so the channel range is +-/10.1Vdc + /* WARNING: We always write 0 to GNSWA bit, so the channel range is +-/10.1Vdc */ outb(insn->chanspec, dev->iobase + MPC624_GNMUXCH); -// rt_printk("Channel %d: \n", insn->chanspec); +/* printk("Channel %d: \n", insn->chanspec); */ if (!insn->n) { - rt_printk("MPC624: Warning, no data to aquire\n"); + printk("MPC624: Warning, no data to aquire\n"); return 0; } for (n = 0; n < insn->n; n++) { - // Trigger the convertion + /* Trigger the convertion */ outb(MPC624_ADSCK, dev->iobase + MPC624_ADC); - comedi_udelay(1); + udelay(1); outb(MPC624_ADCS | MPC624_ADSCK, dev->iobase + MPC624_ADC); - comedi_udelay(1); + udelay(1); outb(0, dev->iobase + MPC624_ADC); - comedi_udelay(1); + udelay(1); - // Wait for the convertion to end + /* Wait for the convertion to end */ for (i = 0; i < TIMEOUT; i++) { ucPort = inb(dev->iobase + MPC624_ADC); if (ucPort & MPC624_ADBUSY) - comedi_udelay(1000); + udelay(1000); else break; } if (i == TIMEOUT) { - rt_printk("MPC624: timeout (%dms)\n", TIMEOUT); + printk("MPC624: timeout (%dms)\n", TIMEOUT); data[n] = 0; return -ETIMEDOUT; } - // Start reading data + /* Start reading data */ data_in = 0; data_out = devpriv->ulConvertionRate; - comedi_udelay(1); + udelay(1); for (i = 0; i < 32; i++) { - // Set the clock low + /* Set the clock low */ outb(0, dev->iobase + MPC624_ADC); - comedi_udelay(1); + udelay(1); - if (data_out & (1 << 31)) // the next bit is a 1 + if (data_out & (1 << 31)) /* the next bit is a 1 */ { - // Set the ADSDI line (send to MPC624) + /* Set the ADSDI line (send to MPC624) */ outb(MPC624_ADSDI, dev->iobase + MPC624_ADC); - comedi_udelay(1); - // Set the clock high + udelay(1); + /* Set the clock high */ outb(MPC624_ADSCK | MPC624_ADSDI, dev->iobase + MPC624_ADC); - } else // the next bit is a 0 + } else /* the next bit is a 0 */ { - // Set the ADSDI line (send to MPC624) + /* Set the ADSDI line (send to MPC624) */ outb(0, dev->iobase + MPC624_ADC); - comedi_udelay(1); - // Set the clock high + udelay(1); + /* Set the clock high */ outb(MPC624_ADSCK, dev->iobase + MPC624_ADC); } - // Read ADSDO on high clock (receive from MPC624) - comedi_udelay(1); + /* Read ADSDO on high clock (receive from MPC624) */ + udelay(1); data_in <<= 1; data_in |= (inb(dev->iobase + MPC624_ADC) & MPC624_ADSDO) >> 4; - comedi_udelay(1); + udelay(1); data_out <<= 1; } - // Received 32-bit long value consist of: - // 31: EOC (End Of Transmission) bit - should be 0 - // 30: DMY (Dummy) bit - should be 0 - // 29: SIG (Sign) bit - 1 if the voltage is positive, 0 if negative - // 28: MSB (Most Significant Bit) - the first bit of convertion result - // .... - // 05: LSB (Least Significant Bit) - the last bit of convertion result - // 04: sub-LSB - sub-LSBs are basically noise, but when - // 03: sub-LSB averaged properly, they can increase convertion - // 02: sub-LSB precision up to 29 bits; they can be discarded - // 01: sub-LSB without loss of resolution. - // 00: sub-LSB + /* Received 32-bit long value consist of: */ + /* 31: EOC (End Of Transmission) bit - should be 0 */ + /* 30: DMY (Dummy) bit - should be 0 */ + /* 29: SIG (Sign) bit - 1 if the voltage is positive, 0 if negative */ + /* 28: MSB (Most Significant Bit) - the first bit of convertion result */ + /* .... */ + /* 05: LSB (Least Significant Bit) - the last bit of convertion result */ + /* 04: sub-LSB - sub-LSBs are basically noise, but when */ + /* 03: sub-LSB averaged properly, they can increase convertion */ + /* 02: sub-LSB precision up to 29 bits; they can be discarded */ + /* 01: sub-LSB without loss of resolution. */ + /* 00: sub-LSB */ if (data_in & MPC624_EOC_BIT) - rt_printk("MPC624: EOC bit is set (data_in=%lu)!", + printk("MPC624: EOC bit is set (data_in=%lu)!", data_in); if (data_in & MPC624_DMY_BIT) - rt_printk("MPC624: DMY bit is set (data_in=%lu)!", + printk("MPC624: DMY bit is set (data_in=%lu)!", data_in); - if (data_in & MPC624_SGN_BIT) // check the sign bit - { // The voltage is positive - data_in &= 0x3FFFFFFF; // EOC and DMY should be 0, but we will mask them out just to be sure - data[n] = data_in; // comedi operates on unsigned numbers, so we don't clear the SGN bit - // SGN bit is still set! It's correct, since we're converting to unsigned. - } else { // The voltage is negative - // data_in contains a number in 30-bit two's complement code and we must deal with it + if (data_in & MPC624_SGN_BIT) /* check the sign bit */ + { /* The voltage is positive */ + data_in &= 0x3FFFFFFF; /* EOC and DMY should be 0, but we will mask them out just to be sure */ + data[n] = data_in; /* comedi operates on unsigned numbers, so we don't clear the SGN bit */ + /* SGN bit is still set! It's correct, since we're converting to unsigned. */ + } else { /* The voltage is negative */ + /* data_in contains a number in 30-bit two's complement code and we must deal with it */ data_in |= MPC624_SGN_BIT; data_in = ~data_in; data_in += 1; data_in &= ~(MPC624_EOC_BIT | MPC624_DMY_BIT); - // clear EOC and DMY bits + /* clear EOC and DMY bits */ data_in = 0x20000000 - data_in; data[n] = data_in; } } - // Return the number of samples read/written + /* Return the number of samples read/written */ return n; } diff --git a/drivers/staging/comedi/drivers/mpc8260cpm.c b/drivers/staging/comedi/drivers/mpc8260cpm.c index bac0a7bb9cbd..c7ee3ef10130 100644 --- a/drivers/staging/comedi/drivers/mpc8260cpm.c +++ b/drivers/staging/comedi/drivers/mpc8260cpm.c @@ -46,23 +46,23 @@ struct mpc8260cpm_private { #define devpriv ((struct mpc8260cpm_private *)dev->private) -static int mpc8260cpm_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int mpc8260cpm_detach(struct comedi_device * dev); +static int mpc8260cpm_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int mpc8260cpm_detach(struct comedi_device *dev); static struct comedi_driver driver_mpc8260cpm = { - driver_name:"mpc8260cpm", - module:THIS_MODULE, - attach:mpc8260cpm_attach, - detach:mpc8260cpm_detach, + .driver_name = "mpc8260cpm", + .module = THIS_MODULE, + .attach = mpc8260cpm_attach, + .detach = mpc8260cpm_detach, }; COMEDI_INITCLEANUP(driver_mpc8260cpm); -static int mpc8260cpm_dio_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int mpc8260cpm_dio_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); +static int mpc8260cpm_dio_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int mpc8260cpm_dio_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); -static int mpc8260cpm_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int mpc8260cpm_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; int i; @@ -93,7 +93,7 @@ static int mpc8260cpm_attach(struct comedi_device * dev, struct comedi_devconfig return 1; } -static int mpc8260cpm_detach(struct comedi_device * dev) +static int mpc8260cpm_detach(struct comedi_device *dev) { printk("comedi%d: mpc8260cpm: remove\n", dev->minor); @@ -114,8 +114,8 @@ static unsigned long *cpm_pdat(int port) } } -static int mpc8260cpm_dio_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int mpc8260cpm_dio_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int n; unsigned int d; @@ -157,8 +157,8 @@ static int mpc8260cpm_dio_config(struct comedi_device * dev, struct comedi_subde return 1; } -static int mpc8260cpm_dio_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int mpc8260cpm_dio_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int port; unsigned long *p; diff --git a/drivers/staging/comedi/drivers/multiq3.c b/drivers/staging/comedi/drivers/multiq3.c index 9e47574171de..f7cce6cc7766 100644 --- a/drivers/staging/comedi/drivers/multiq3.c +++ b/drivers/staging/comedi/drivers/multiq3.c @@ -29,6 +29,7 @@ Devices: [Quanser Consulting] MultiQ-3 (multiq3) */ +#include #include "../comedidev.h" #include @@ -82,13 +83,13 @@ Devices: [Quanser Consulting] MultiQ-3 (multiq3) #define MULTIQ3_TIMEOUT 30 -static int multiq3_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int multiq3_detach(struct comedi_device * dev); +static int multiq3_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int multiq3_detach(struct comedi_device *dev); static struct comedi_driver driver_multiq3 = { - driver_name:"multiq3", - module:THIS_MODULE, - attach:multiq3_attach, - detach:multiq3_detach, + .driver_name = "multiq3", + .module = THIS_MODULE, + .attach = multiq3_attach, + .detach = multiq3_detach, }; COMEDI_INITCLEANUP(driver_multiq3); @@ -98,8 +99,8 @@ struct multiq3_private { }; #define devpriv ((struct multiq3_private *)dev->private) -static int multiq3_ai_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int multiq3_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i, n; int chan; @@ -134,8 +135,8 @@ static int multiq3_ai_insn_read(struct comedi_device * dev, struct comedi_subdev return n; } -static int multiq3_ao_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int multiq3_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i; int chan = CR_CHAN(insn->chanspec); @@ -147,8 +148,8 @@ static int multiq3_ao_insn_read(struct comedi_device * dev, struct comedi_subdev return i; } -static int multiq3_ao_insn_write(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int multiq3_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i; int chan = CR_CHAN(insn->chanspec); @@ -165,8 +166,8 @@ static int multiq3_ao_insn_write(struct comedi_device * dev, struct comedi_subde return i; } -static int multiq3_di_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int multiq3_di_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if (insn->n != 2) return -EINVAL; @@ -176,8 +177,8 @@ static int multiq3_di_insn_bits(struct comedi_device * dev, struct comedi_subdev return 2; } -static int multiq3_do_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int multiq3_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if (insn->n != 2) return -EINVAL; @@ -191,8 +192,8 @@ static int multiq3_do_insn_bits(struct comedi_device * dev, struct comedi_subdev return 2; } -static int multiq3_encoder_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int multiq3_encoder_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int n; int chan = CR_CHAN(insn->chanspec); @@ -212,7 +213,7 @@ static int multiq3_encoder_insn_read(struct comedi_device * dev, struct comedi_s return n; } -static void encoder_reset(struct comedi_device * dev) +static void encoder_reset(struct comedi_device *dev) { int chan; for (chan = 0; chan < dev->subdevices[4].n_chan; chan++) { @@ -235,7 +236,7 @@ static void encoder_reset(struct comedi_device * dev) options[2] - number of encoder chips installed */ -static int multiq3_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int multiq3_attach(struct comedi_device *dev, struct comedi_devconfig *it) { int result = 0; unsigned long iobase; @@ -318,7 +319,7 @@ static int multiq3_attach(struct comedi_device * dev, struct comedi_devconfig * return 0; } -static int multiq3_detach(struct comedi_device * dev) +static int multiq3_detach(struct comedi_device *dev) { printk("comedi%d: multiq3: remove\n", dev->minor); diff --git a/drivers/staging/comedi/drivers/ni_6527.c b/drivers/staging/comedi/drivers/ni_6527.c index e01ecb6760f9..67adc97265bd 100644 --- a/drivers/staging/comedi/drivers/ni_6527.c +++ b/drivers/staging/comedi/drivers/ni_6527.c @@ -41,6 +41,7 @@ Updated: Sat, 25 Jan 2003 13:24:40 -0800 #define DEBUG 1 #define DEBUG_FLAGS +#include #include "../comedidev.h" #include "mite.h" @@ -75,13 +76,13 @@ Updated: Sat, 25 Jan 2003 13:24:40 -0800 #define Rising_Edge_Detection_Enable(x) (0x018+(x)) #define Falling_Edge_Detection_Enable(x) (0x020+(x)) -static int ni6527_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int ni6527_detach(struct comedi_device * dev); +static int ni6527_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int ni6527_detach(struct comedi_device *dev); static struct comedi_driver driver_ni6527 = { - driver_name:"ni6527", - module:THIS_MODULE, - attach:ni6527_attach, - detach:ni6527_detach, + .driver_name = "ni6527", + .module = THIS_MODULE, + .attach = ni6527_attach, + .detach = ni6527_detach, }; struct ni6527_board { @@ -92,12 +93,12 @@ struct ni6527_board { static const struct ni6527_board ni6527_boards[] = { { - dev_id: 0x2b20, - name: "pci-6527", + .dev_id = 0x2b20, + .name = "pci-6527", }, { - dev_id: 0x2b10, - name: "pxi-6527", + .dev_id = 0x2b10, + .name = "pxi-6527", }, }; @@ -120,10 +121,10 @@ struct ni6527_private { #define devpriv ((struct ni6527_private *)dev->private) -static int ni6527_find_device(struct comedi_device * dev, int bus, int slot); +static int ni6527_find_device(struct comedi_device *dev, int bus, int slot); -static int ni6527_di_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int ni6527_di_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int chan = CR_CHAN(insn->chanspec); unsigned int interval; @@ -170,8 +171,8 @@ static int ni6527_di_insn_config(struct comedi_device * dev, struct comedi_subde return 2; } -static int ni6527_di_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int ni6527_di_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if (insn->n != 2) return -EINVAL; @@ -183,8 +184,8 @@ static int ni6527_di_insn_bits(struct comedi_device * dev, struct comedi_subdevi return 2; } -static int ni6527_do_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int ni6527_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if (insn->n != 2) return -EINVAL; @@ -212,7 +213,7 @@ static int ni6527_do_insn_bits(struct comedi_device * dev, struct comedi_subdevi return 2; } -static irqreturn_t ni6527_interrupt(int irq, void *d PT_REGS_ARG) +static irqreturn_t ni6527_interrupt(int irq, void *d) { struct comedi_device *dev = d; struct comedi_subdevice *s = dev->subdevices + 2; @@ -233,8 +234,8 @@ static irqreturn_t ni6527_interrupt(int irq, void *d PT_REGS_ARG) return IRQ_HANDLED; } -static int ni6527_intr_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd) +static int ni6527_intr_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd) { int err = 0; int tmp; @@ -309,9 +310,9 @@ static int ni6527_intr_cmdtest(struct comedi_device * dev, struct comedi_subdevi return 0; } -static int ni6527_intr_cmd(struct comedi_device * dev, struct comedi_subdevice * s) +static int ni6527_intr_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { - //struct comedi_cmd *cmd = &s->async->cmd; + /* struct comedi_cmd *cmd = &s->async->cmd; */ writeb(ClrEdge | ClrOverflow, devpriv->mite->daq_io_addr + Clear_Register); @@ -322,15 +323,15 @@ static int ni6527_intr_cmd(struct comedi_device * dev, struct comedi_subdevice * return 0; } -static int ni6527_intr_cancel(struct comedi_device * dev, struct comedi_subdevice * s) +static int ni6527_intr_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { writeb(0x00, devpriv->mite->daq_io_addr + Master_Interrupt_Control); return 0; } -static int ni6527_intr_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int ni6527_intr_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if (insn->n < 1) return -EINVAL; @@ -339,8 +340,8 @@ static int ni6527_intr_insn_bits(struct comedi_device * dev, struct comedi_subde return 2; } -static int ni6527_intr_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int ni6527_intr_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if (insn->n < 1) return -EINVAL; @@ -364,14 +365,15 @@ static int ni6527_intr_insn_config(struct comedi_device * dev, struct comedi_sub return 2; } -static int ni6527_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int ni6527_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; int ret; printk("comedi%d: ni6527:", dev->minor); - if ((ret = alloc_private(dev, sizeof(struct ni6527_private))) < 0) + ret = alloc_private(dev, sizeof(struct ni6527_private)); + if (ret < 0) return ret; ret = ni6527_find_device(dev, it->options[0], it->options[1]); @@ -389,7 +391,8 @@ static int ni6527_attach(struct comedi_device * dev, struct comedi_devconfig * i printk(" ID=0x%02x", readb(devpriv->mite->daq_io_addr + ID_Register)); - if ((ret = alloc_subdevices(dev, 3)) < 0) + ret = alloc_subdevices(dev, 3); + if (ret < 0) return ret; s = dev->subdevices + 0; @@ -430,8 +433,8 @@ static int ni6527_attach(struct comedi_device * dev, struct comedi_devconfig * i devpriv->mite->daq_io_addr + Clear_Register); writeb(0x00, devpriv->mite->daq_io_addr + Master_Interrupt_Control); - ret = comedi_request_irq(mite_irq(devpriv->mite), ni6527_interrupt, - IRQF_SHARED, "ni6527", dev); + ret = request_irq(mite_irq(devpriv->mite), ni6527_interrupt, + IRQF_SHARED, "ni6527", dev); if (ret < 0) { printk(" irq not available"); } else @@ -442,7 +445,7 @@ static int ni6527_attach(struct comedi_device * dev, struct comedi_devconfig * i return 0; } -static int ni6527_detach(struct comedi_device * dev) +static int ni6527_detach(struct comedi_device *dev) { if (devpriv && devpriv->mite && devpriv->mite->daq_io_addr) { writeb(0x00, @@ -450,7 +453,7 @@ static int ni6527_detach(struct comedi_device * dev) } if (dev->irq) { - comedi_free_irq(dev->irq, dev); + free_irq(dev->irq, dev); } if (devpriv && devpriv->mite) { @@ -460,7 +463,7 @@ static int ni6527_detach(struct comedi_device * dev) return 0; } -static int ni6527_find_device(struct comedi_device * dev, int bus, int slot) +static int ni6527_find_device(struct comedi_device *dev, int bus, int slot) { struct mite_struct *mite; int i; diff --git a/drivers/staging/comedi/drivers/ni_65xx.c b/drivers/staging/comedi/drivers/ni_65xx.c index 6e85da16a241..35708503dec3 100644 --- a/drivers/staging/comedi/drivers/ni_65xx.c +++ b/drivers/staging/comedi/drivers/ni_65xx.c @@ -50,6 +50,7 @@ except maybe the 6514. #define _GNU_SOURCE #define DEBUG 1 #define DEBUG_FLAGS +#include #include "../comedidev.h" #include "mite.h" @@ -102,13 +103,13 @@ static inline unsigned Filter_Enable(unsigned port) #define OverflowIntEnable 0x02 #define EdgeIntEnable 0x01 -static int ni_65xx_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int ni_65xx_detach(struct comedi_device * dev); +static int ni_65xx_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int ni_65xx_detach(struct comedi_device *dev); static struct comedi_driver driver_ni_65xx = { - driver_name:"ni_65xx", - module:THIS_MODULE, - attach:ni_65xx_attach, - detach:ni_65xx_detach, + .driver_name = "ni_65xx", + .module = THIS_MODULE, + .attach = ni_65xx_attach, + .detach = ni_65xx_detach, }; struct ni_65xx_board { @@ -123,120 +124,120 @@ struct ni_65xx_board { static const struct ni_65xx_board ni_65xx_boards[] = { { - dev_id: 0x7085, - name: "pci-6509", - num_dio_ports:12, - invert_outputs:0}, + .dev_id = 0x7085, + .name = "pci-6509", + .num_dio_ports = 12, + .invert_outputs = 0}, { - dev_id: 0x1710, - name: "pxi-6509", - num_dio_ports:12, - invert_outputs:0}, + .dev_id = 0x1710, + .name = "pxi-6509", + .num_dio_ports = 12, + .invert_outputs = 0}, { - dev_id: 0x7124, - name: "pci-6510", - num_di_ports:4}, + .dev_id = 0x7124, + .name = "pci-6510", + .num_di_ports = 4}, { - dev_id: 0x70c3, - name: "pci-6511", - num_di_ports:8}, + .dev_id = 0x70c3, + .name = "pci-6511", + .num_di_ports = 8}, { - dev_id: 0x70d3, - name: "pxi-6511", - num_di_ports:8}, + .dev_id = 0x70d3, + .name = "pxi-6511", + .num_di_ports = 8}, { - dev_id: 0x70cc, - name: "pci-6512", - num_do_ports:8}, + .dev_id = 0x70cc, + .name = "pci-6512", + .num_do_ports = 8}, { - dev_id: 0x70d2, - name: "pxi-6512", - num_do_ports:8}, + .dev_id = 0x70d2, + .name = "pxi-6512", + .num_do_ports = 8}, { - dev_id: 0x70c8, - name: "pci-6513", - num_do_ports:8, - invert_outputs:1}, + .dev_id = 0x70c8, + .name = "pci-6513", + .num_do_ports = 8, + .invert_outputs = 1}, { - dev_id: 0x70d1, - name: "pxi-6513", - num_do_ports:8, - invert_outputs:1}, + .dev_id = 0x70d1, + .name = "pxi-6513", + .num_do_ports = 8, + .invert_outputs = 1}, { - dev_id: 0x7088, - name: "pci-6514", - num_di_ports:4, - num_do_ports:4, - invert_outputs:1}, + .dev_id = 0x7088, + .name = "pci-6514", + .num_di_ports = 4, + .num_do_ports = 4, + .invert_outputs = 1}, { - dev_id: 0x70CD, - name: "pxi-6514", - num_di_ports:4, - num_do_ports:4, - invert_outputs:1}, + .dev_id = 0x70CD, + .name = "pxi-6514", + .num_di_ports = 4, + .num_do_ports = 4, + .invert_outputs = 1}, { - dev_id: 0x7087, - name: "pci-6515", - num_di_ports:4, - num_do_ports:4, - invert_outputs:1}, + .dev_id = 0x7087, + .name = "pci-6515", + .num_di_ports = 4, + .num_do_ports = 4, + .invert_outputs = 1}, { - dev_id: 0x70c9, - name: "pxi-6515", - num_di_ports:4, - num_do_ports:4, - invert_outputs:1}, + .dev_id = 0x70c9, + .name = "pxi-6515", + .num_di_ports = 4, + .num_do_ports = 4, + .invert_outputs = 1}, { - dev_id: 0x7125, - name: "pci-6516", - num_do_ports:4, - invert_outputs:1}, + .dev_id = 0x7125, + .name = "pci-6516", + .num_do_ports = 4, + .invert_outputs = 1}, { - dev_id: 0x7126, - name: "pci-6517", - num_do_ports:4, - invert_outputs:1}, + .dev_id = 0x7126, + .name = "pci-6517", + .num_do_ports = 4, + .invert_outputs = 1}, { - dev_id: 0x7127, - name: "pci-6518", - num_di_ports:2, - num_do_ports:2, - invert_outputs:1}, + .dev_id = 0x7127, + .name = "pci-6518", + .num_di_ports = 2, + .num_do_ports = 2, + .invert_outputs = 1}, { - dev_id: 0x7128, - name: "pci-6519", - num_di_ports:2, - num_do_ports:2, - invert_outputs:1}, + .dev_id = 0x7128, + .name = "pci-6519", + .num_di_ports = 2, + .num_do_ports = 2, + .invert_outputs = 1}, { - dev_id: 0x71c5, - name: "pci-6520", - num_di_ports:1, - num_do_ports:1, + .dev_id = 0x71c5, + .name = "pci-6520", + .num_di_ports = 1, + .num_do_ports = 1, }, { - dev_id: 0x718b, - name: "pci-6521", - num_di_ports:1, - num_do_ports:1, + .dev_id = 0x718b, + .name = "pci-6521", + .num_di_ports = 1, + .num_do_ports = 1, }, { - dev_id: 0x718c, - name: "pxi-6521", - num_di_ports:1, - num_do_ports:1, + .dev_id = 0x718c, + .name = "pxi-6521", + .num_di_ports = 1, + .num_do_ports = 1, }, { - dev_id: 0x70a9, - name: "pci-6528", - num_di_ports:3, - num_do_ports:3, + .dev_id = 0x70a9, + .name = "pci-6528", + .num_di_ports = 3, + .num_do_ports = 3, }, { - dev_id: 0x7086, - name: "pxi-6528", - num_di_ports:3, - num_do_ports:3, + .dev_id = 0x7086, + .name = "pxi-6528", + .num_di_ports = 3, + .num_do_ports = 3, }, }; @@ -249,7 +250,7 @@ static inline unsigned ni_65xx_port_by_channel(unsigned channel) { return channel / ni_65xx_channels_per_port; } -static inline unsigned ni_65xx_total_num_ports(const struct ni_65xx_board * board) +static inline unsigned ni_65xx_total_num_ports(const struct ni_65xx_board *board) { return board->num_dio_ports + board->num_di_ports + board->num_do_ports; } @@ -312,10 +313,10 @@ static struct ni_65xx_subdevice_private *ni_65xx_alloc_subdevice_private(void) return subdev_private; } -static int ni_65xx_find_device(struct comedi_device * dev, int bus, int slot); +static int ni_65xx_find_device(struct comedi_device *dev, int bus, int slot); -static int ni_65xx_config_filter(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int ni_65xx_config_filter(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { const unsigned chan = CR_CHAN(insn->chanspec); const unsigned port = @@ -353,8 +354,8 @@ static int ni_65xx_config_filter(struct comedi_device * dev, struct comedi_subde return 2; } -static int ni_65xx_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int ni_65xx_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { unsigned port; @@ -392,8 +393,8 @@ static int ni_65xx_dio_insn_config(struct comedi_device * dev, struct comedi_sub return -EINVAL; } -static int ni_65xx_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int ni_65xx_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { unsigned base_bitfield_channel; const unsigned max_ports_per_bitfield = 5; @@ -437,12 +438,12 @@ static int ni_65xx_dio_insn_bits(struct comedi_device * dev, struct comedi_subde writeb(bits, private(dev)->mite->daq_io_addr + Port_Data(port)); -// rt_printk("wrote 0x%x to port %i\n", bits, port); +/* printk("wrote 0x%x to port %i\n", bits, port); */ } port_read_bits = readb(private(dev)->mite->daq_io_addr + Port_Data(port)); -// rt_printk("read 0x%x from port %i\n", port_read_bits, port); +/* printk("read 0x%x from port %i\n", port_read_bits, port); */ if (bitshift > 0) { port_read_bits <<= bitshift; } else { @@ -454,7 +455,7 @@ static int ni_65xx_dio_insn_bits(struct comedi_device * dev, struct comedi_subde return insn->n; } -static irqreturn_t ni_65xx_interrupt(int irq, void *d PT_REGS_ARG) +static irqreturn_t ni_65xx_interrupt(int irq, void *d) { struct comedi_device *dev = d; struct comedi_subdevice *s = dev->subdevices + 2; @@ -475,8 +476,8 @@ static irqreturn_t ni_65xx_interrupt(int irq, void *d PT_REGS_ARG) return IRQ_HANDLED; } -static int ni_65xx_intr_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd) +static int ni_65xx_intr_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd) { int err = 0; int tmp; @@ -551,9 +552,9 @@ static int ni_65xx_intr_cmdtest(struct comedi_device * dev, struct comedi_subdev return 0; } -static int ni_65xx_intr_cmd(struct comedi_device * dev, struct comedi_subdevice * s) +static int ni_65xx_intr_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { - //struct comedi_cmd *cmd = &s->async->cmd; + /* struct comedi_cmd *cmd = &s->async->cmd; */ writeb(ClrEdge | ClrOverflow, private(dev)->mite->daq_io_addr + Clear_Register); @@ -564,7 +565,7 @@ static int ni_65xx_intr_cmd(struct comedi_device * dev, struct comedi_subdevice return 0; } -static int ni_65xx_intr_cancel(struct comedi_device * dev, struct comedi_subdevice * s) +static int ni_65xx_intr_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { writeb(0x00, private(dev)->mite->daq_io_addr + Master_Interrupt_Control); @@ -572,8 +573,8 @@ static int ni_65xx_intr_cancel(struct comedi_device * dev, struct comedi_subdevi return 0; } -static int ni_65xx_intr_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int ni_65xx_intr_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if (insn->n < 1) return -EINVAL; @@ -582,8 +583,8 @@ static int ni_65xx_intr_insn_bits(struct comedi_device * dev, struct comedi_subd return 2; } -static int ni_65xx_intr_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int ni_65xx_intr_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if (insn->n < 1) return -EINVAL; @@ -619,7 +620,7 @@ static int ni_65xx_intr_insn_config(struct comedi_device * dev, struct comedi_su return 2; } -static int ni_65xx_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int ni_65xx_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; unsigned i; @@ -627,7 +628,8 @@ static int ni_65xx_attach(struct comedi_device * dev, struct comedi_devconfig * printk("comedi%d: ni_65xx:", dev->minor); - if ((ret = alloc_private(dev, sizeof(struct ni_65xx_private))) < 0) + ret = alloc_private(dev, sizeof(struct ni_65xx_private)); + if (ret < 0) return ret; ret = ni_65xx_find_device(dev, it->options[0], it->options[1]); @@ -647,7 +649,8 @@ static int ni_65xx_attach(struct comedi_device * dev, struct comedi_devconfig * printk(" ID=0x%02x", readb(private(dev)->mite->daq_io_addr + ID_Register)); - if ((ret = alloc_subdevices(dev, 4)) < 0) + ret = alloc_subdevices(dev, 4); + if (ret < 0) return ret; s = dev->subdevices + 0; @@ -700,7 +703,7 @@ static int ni_65xx_attach(struct comedi_device * dev, struct comedi_devconfig * return -ENOMEM; sprivate(s)->base_port = 0; for (i = 0; i < board(dev)->num_dio_ports; ++i) { - // configure all ports for input + /* configure all ports for input */ writeb(0x1, private(dev)->mite->daq_io_addr + Port_Select(i)); @@ -740,8 +743,8 @@ static int ni_65xx_attach(struct comedi_device * dev, struct comedi_devconfig * /* Set filter interval to 0 (32bit reg) */ writeb(0x00000000, private(dev)->mite->daq_io_addr + Filter_Interval); - ret = comedi_request_irq(dev->irq, ni_65xx_interrupt, IRQF_SHARED, - "ni_65xx", dev); + ret = request_irq(dev->irq, ni_65xx_interrupt, IRQF_SHARED, + "ni_65xx", dev); if (ret < 0) { dev->irq = 0; printk(" irq not available"); @@ -752,7 +755,7 @@ static int ni_65xx_attach(struct comedi_device * dev, struct comedi_devconfig * return 0; } -static int ni_65xx_detach(struct comedi_device * dev) +static int ni_65xx_detach(struct comedi_device *dev) { if (private(dev) && private(dev)->mite && private(dev)->mite->daq_io_addr) { @@ -762,7 +765,7 @@ static int ni_65xx_detach(struct comedi_device * dev) } if (dev->irq) { - comedi_free_irq(dev->irq, dev); + free_irq(dev->irq, dev); } if (private(dev)) { @@ -780,7 +783,7 @@ static int ni_65xx_detach(struct comedi_device * dev) return 0; } -static int ni_65xx_find_device(struct comedi_device * dev, int bus, int slot) +static int ni_65xx_find_device(struct comedi_device *dev, int bus, int slot) { struct mite_struct *mite; int i; diff --git a/drivers/staging/comedi/drivers/ni_660x.c b/drivers/staging/comedi/drivers/ni_660x.c index 14e35ba721e9..11e9b0411805 100644 --- a/drivers/staging/comedi/drivers/ni_660x.c +++ b/drivers/staging/comedi/drivers/ni_660x.c @@ -40,6 +40,7 @@ DAQ 6601/6602 User Manual (NI 322137B-01) */ +#include #include "../comedidev.h" #include "mite.h" #include "ni_tio.h" @@ -51,7 +52,7 @@ enum ni_660x_constants { }; #define NUM_PFI_CHANNELS 40 -// really there are only up to 3 dma channels, but the register layout allows for 4 +/* really there are only up to 3 dma channels, but the register layout allows for 4 */ #define MAX_DMA_CHANNEL 4 /* See Register-Level Programmer Manual page 3.1 */ @@ -194,10 +195,10 @@ static inline unsigned NI_660X_GPCT_SUBDEV(unsigned index) struct NI_660xRegisterData { - const char *name; // Register Name - int offset; // Offset from base address from GPCT chip + const char *name; /* Register Name */ + int offset; /* Offset from base address from GPCT chip */ enum ni_660x_register_direction direction; - enum ni_660x_register_width size; // 1 byte, 2 bytes, or 4 bytes + enum ni_660x_register_width size; /* 1 byte, 2 bytes, or 4 bytes */ }; @@ -302,12 +303,12 @@ static const struct NI_660xRegisterData registerData[NumRegisters] = { {"IO Config Register 38-39", 0x7A2, NI_660x_READ_WRITE, DATA_2B} }; -// kind of ENABLE for the second counter +/* kind of ENABLE for the second counter */ enum clock_config_register_bits { CounterSwap = 0x1 << 21 }; -// ioconfigreg +/* ioconfigreg */ static inline unsigned ioconfig_bitshift(unsigned pfi_channel) { if (pfi_channel % 2) @@ -334,7 +335,7 @@ static inline unsigned pfi_input_select_bits(unsigned pfi_channel, return (input_select & 0x7) << (4 + ioconfig_bitshift(pfi_channel)); } -// dma configuration register bits +/* dma configuration register bits */ static inline unsigned dma_select_mask(unsigned dma_channel) { BUG_ON(dma_channel >= MAX_DMA_CHANNEL); @@ -374,7 +375,7 @@ enum global_interrupt_config_register_bits { Global_Int_Enable_Bit = 0x80000000 }; -// Offset of the GPCT chips from the base-adress of the card +/* Offset of the GPCT chips from the base-adress of the card */ static const unsigned GPCT_OFFSET[2] = { 0x0, 0x800 }; /* First chip is at base-address + 0x00, etc. */ @@ -387,24 +388,24 @@ struct ni_660x_board { static const struct ni_660x_board ni_660x_boards[] = { { - dev_id: 0x2c60, - name: "PCI-6601", - n_chips: 1, + .dev_id = 0x2c60, + .name = "PCI-6601", + .n_chips = 1, }, { - dev_id: 0x1310, - name: "PCI-6602", - n_chips: 2, + .dev_id = 0x1310, + .name = "PCI-6602", + .n_chips = 2, }, { - dev_id: 0x1360, - name: "PXI-6602", - n_chips: 2, + .dev_id = 0x1360, + .name = "PXI-6602", + .n_chips = 2, }, { - dev_id: 0x2cc0, - name: "PXI-6608", - n_chips: 2, + .dev_id = 0x2cc0, + .name = "PXI-6608", + .n_chips = 2, }, }; @@ -428,6 +429,8 @@ struct ni_660x_private { struct mite_dma_descriptor_ring *mite_rings[NI_660X_MAX_NUM_CHIPS][counters_per_chip]; spinlock_t mite_channel_lock; + /* interrupt_lock prevents races between interrupt and comedi_poll */ + spinlock_t interrupt_lock; unsigned dma_configuration_soft_copies[NI_660X_MAX_NUM_CHIPS]; spinlock_t soft_reg_copy_lock; unsigned short pfi_output_selects[NUM_PFI_CHANNELS]; @@ -446,40 +449,40 @@ static inline const struct ni_660x_board *board(struct comedi_device * dev) #define n_ni_660x_boards (sizeof(ni_660x_boards)/sizeof(ni_660x_boards[0])) -static int ni_660x_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int ni_660x_detach(struct comedi_device * dev); -static void init_tio_chip(struct comedi_device * dev, int chipset); -static void ni_660x_select_pfi_output(struct comedi_device * dev, unsigned pfi_channel, +static int ni_660x_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int ni_660x_detach(struct comedi_device *dev); +static void init_tio_chip(struct comedi_device *dev, int chipset); +static void ni_660x_select_pfi_output(struct comedi_device *dev, unsigned pfi_channel, unsigned output_select); static struct comedi_driver driver_ni_660x = { - driver_name:"ni_660x", - module:THIS_MODULE, - attach:ni_660x_attach, - detach:ni_660x_detach, + .driver_name = "ni_660x", + .module = THIS_MODULE, + .attach = ni_660x_attach, + .detach = ni_660x_detach, }; COMEDI_PCI_INITCLEANUP(driver_ni_660x, ni_660x_pci_table); -static int ni_660x_find_device(struct comedi_device * dev, int bus, int slot); -static int ni_660x_set_pfi_routing(struct comedi_device * dev, unsigned chan, +static int ni_660x_find_device(struct comedi_device *dev, int bus, int slot); +static int ni_660x_set_pfi_routing(struct comedi_device *dev, unsigned chan, unsigned source); /* Possible instructions for a GPCT */ -static int ni_660x_GPCT_rinsn(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data); -static int ni_660x_GPCT_insn_config(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data); -static int ni_660x_GPCT_winsn(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data); +static int ni_660x_GPCT_rinsn(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); +static int ni_660x_GPCT_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); +static int ni_660x_GPCT_winsn(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); /* Possible instructions for Digital IO */ -static int ni_660x_dio_insn_config(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data); -static int ni_660x_dio_insn_bits(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data); +static int ni_660x_dio_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); +static int ni_660x_dio_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -static inline unsigned ni_660x_num_counters(struct comedi_device * dev) +static inline unsigned ni_660x_num_counters(struct comedi_device *dev) { return board(dev)->n_chips * counters_per_chip; } @@ -693,8 +696,8 @@ static enum NI_660x_Register ni_gpct_to_660x_register(enum ni_gpct_register reg) ni_660x_register = G3InterruptEnable; break; default: - rt_printk("%s: unhandled register 0x%x in switch.\n", - __FUNCTION__, reg); + printk("%s: unhandled register 0x%x in switch.\n", + __func__, reg); BUG(); return 0; break; @@ -702,7 +705,7 @@ static enum NI_660x_Register ni_gpct_to_660x_register(enum ni_gpct_register reg) return ni_660x_register; } -static inline void ni_660x_write_register(struct comedi_device * dev, +static inline void ni_660x_write_register(struct comedi_device *dev, unsigned chip_index, unsigned bits, enum NI_660x_Register reg) { void *const write_address = @@ -717,14 +720,14 @@ static inline void ni_660x_write_register(struct comedi_device * dev, writel(bits, write_address); break; default: - rt_printk("%s: %s: bug! unhandled case (reg=0x%x) in switch.\n", - __FILE__, __FUNCTION__, reg); + printk("%s: %s: bug! unhandled case (reg=0x%x) in switch.\n", + __FILE__, __func__, reg); BUG(); break; } } -static inline unsigned ni_660x_read_register(struct comedi_device * dev, +static inline unsigned ni_660x_read_register(struct comedi_device *dev, unsigned chip_index, enum NI_660x_Register reg) { void *const read_address = @@ -739,8 +742,8 @@ static inline unsigned ni_660x_read_register(struct comedi_device * dev, return readl(read_address); break; default: - rt_printk("%s: %s: bug! unhandled case (reg=0x%x) in switch.\n", - __FILE__, __FUNCTION__, reg); + printk("%s: %s: bug! unhandled case (reg=0x%x) in switch.\n", + __FILE__, __func__, reg); BUG(); break; } @@ -771,11 +774,11 @@ static inline struct mite_dma_descriptor_ring *mite_ring(struct ni_660x_private return priv->mite_rings[counter->chip_index][counter->counter_index]; } -static inline void ni_660x_set_dma_channel(struct comedi_device * dev, +static inline void ni_660x_set_dma_channel(struct comedi_device *dev, unsigned mite_channel, struct ni_gpct *counter) { unsigned long flags; - comedi_spin_lock_irqsave(&private(dev)->soft_reg_copy_lock, flags); + spin_lock_irqsave(&private(dev)->soft_reg_copy_lock, flags); private(dev)->dma_configuration_soft_copies[counter->chip_index] &= ~dma_select_mask(mite_channel); private(dev)->dma_configuration_soft_copies[counter->chip_index] |= @@ -786,14 +789,14 @@ static inline void ni_660x_set_dma_channel(struct comedi_device * dev, chip_index] | dma_reset_bit(mite_channel), DMAConfigRegister); mmiowb(); - comedi_spin_unlock_irqrestore(&private(dev)->soft_reg_copy_lock, flags); + spin_unlock_irqrestore(&private(dev)->soft_reg_copy_lock, flags); } -static inline void ni_660x_unset_dma_channel(struct comedi_device * dev, +static inline void ni_660x_unset_dma_channel(struct comedi_device *dev, unsigned mite_channel, struct ni_gpct *counter) { unsigned long flags; - comedi_spin_lock_irqsave(&private(dev)->soft_reg_copy_lock, flags); + spin_lock_irqsave(&private(dev)->soft_reg_copy_lock, flags); private(dev)->dma_configuration_soft_copies[counter->chip_index] &= ~dma_select_mask(mite_channel); private(dev)->dma_configuration_soft_copies[counter->chip_index] |= @@ -802,22 +805,22 @@ static inline void ni_660x_unset_dma_channel(struct comedi_device * dev, private(dev)->dma_configuration_soft_copies[counter-> chip_index], DMAConfigRegister); mmiowb(); - comedi_spin_unlock_irqrestore(&private(dev)->soft_reg_copy_lock, flags); + spin_unlock_irqrestore(&private(dev)->soft_reg_copy_lock, flags); } -static int ni_660x_request_mite_channel(struct comedi_device * dev, +static int ni_660x_request_mite_channel(struct comedi_device *dev, struct ni_gpct *counter, enum comedi_io_direction direction) { unsigned long flags; struct mite_channel *mite_chan; - comedi_spin_lock_irqsave(&private(dev)->mite_channel_lock, flags); + spin_lock_irqsave(&private(dev)->mite_channel_lock, flags); BUG_ON(counter->mite_chan); mite_chan = mite_request_channel(private(dev)->mite, mite_ring(private(dev), counter)); if (mite_chan == NULL) { - comedi_spin_unlock_irqrestore(&private(dev)->mite_channel_lock, + spin_unlock_irqrestore(&private(dev)->mite_channel_lock, flags); comedi_error(dev, "failed to reserve mite dma channel for counter."); @@ -826,15 +829,15 @@ static int ni_660x_request_mite_channel(struct comedi_device * dev, mite_chan->dir = direction; ni_tio_set_mite_channel(counter, mite_chan); ni_660x_set_dma_channel(dev, mite_chan->channel, counter); - comedi_spin_unlock_irqrestore(&private(dev)->mite_channel_lock, flags); + spin_unlock_irqrestore(&private(dev)->mite_channel_lock, flags); return 0; } -void ni_660x_release_mite_channel(struct comedi_device * dev, struct ni_gpct *counter) +void ni_660x_release_mite_channel(struct comedi_device *dev, struct ni_gpct *counter) { unsigned long flags; - comedi_spin_lock_irqsave(&private(dev)->mite_channel_lock, flags); + spin_lock_irqsave(&private(dev)->mite_channel_lock, flags); if (counter->mite_chan) { struct mite_channel *mite_chan = counter->mite_chan; @@ -842,15 +845,15 @@ void ni_660x_release_mite_channel(struct comedi_device * dev, struct ni_gpct *co ni_tio_set_mite_channel(counter, NULL); mite_release_channel(mite_chan); } - comedi_spin_unlock_irqrestore(&private(dev)->mite_channel_lock, flags); + spin_unlock_irqrestore(&private(dev)->mite_channel_lock, flags); } -static int ni_660x_cmd(struct comedi_device * dev, struct comedi_subdevice * s) +static int ni_660x_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { int retval; struct ni_gpct *counter = subdev_to_counter(s); -// const struct comedi_cmd *cmd = &s->async->cmd; +/* const struct comedi_cmd *cmd = &s->async->cmd; */ retval = ni_660x_request_mite_channel(dev, counter, COMEDI_INPUT); if (retval) { @@ -864,15 +867,15 @@ static int ni_660x_cmd(struct comedi_device * dev, struct comedi_subdevice * s) return retval; } -static int ni_660x_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd) +static int ni_660x_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd) { struct ni_gpct *counter = subdev_to_counter(s); return ni_tio_cmdtest(counter, cmd); } -static int ni_660x_cancel(struct comedi_device * dev, struct comedi_subdevice * s) +static int ni_660x_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { struct ni_gpct *counter = subdev_to_counter(s); int retval; @@ -882,7 +885,7 @@ static int ni_660x_cancel(struct comedi_device * dev, struct comedi_subdevice * return retval; } -static void set_tio_counterswap(struct comedi_device * dev, int chipset) +static void set_tio_counterswap(struct comedi_device *dev, int chipset) { /* See P. 3.5 of the Register-Level Programming manual. The CounterSwap bit has to be set on the second chip, otherwise @@ -895,8 +898,8 @@ static void set_tio_counterswap(struct comedi_device * dev, int chipset) ni_660x_write_register(dev, chipset, 0, ClockConfigRegister); } -static void ni_660x_handle_gpct_interrupt(struct comedi_device * dev, - struct comedi_subdevice * s) +static void ni_660x_handle_gpct_interrupt(struct comedi_device *dev, + struct comedi_subdevice *s) { ni_tio_handle_interrupt(subdev_to_counter(s), s); if (s->async->events) { @@ -909,23 +912,38 @@ static void ni_660x_handle_gpct_interrupt(struct comedi_device * dev, } } -static irqreturn_t ni_660x_interrupt(int irq, void *d PT_REGS_ARG) +static irqreturn_t ni_660x_interrupt(int irq, void *d) { struct comedi_device *dev = d; struct comedi_subdevice *s; unsigned i; + unsigned long flags; if (dev->attached == 0) return IRQ_NONE; + /* lock to avoid race with comedi_poll */ + spin_lock_irqsave(&private(dev)->interrupt_lock, flags); smp_mb(); for (i = 0; i < ni_660x_num_counters(dev); ++i) { s = dev->subdevices + NI_660X_GPCT_SUBDEV(i); ni_660x_handle_gpct_interrupt(dev, s); } + spin_unlock_irqrestore(&private(dev)->interrupt_lock, flags); return IRQ_HANDLED; } -static int ni_660x_buf_change(struct comedi_device * dev, struct comedi_subdevice * s, +static int ni_660x_input_poll(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + unsigned long flags; + /* lock to avoid race with comedi_poll */ + spin_lock_irqsave(&private(dev)->interrupt_lock, flags); + mite_sync_input_dma(subdev_to_counter(s)->mite_chan, s->async); + spin_unlock_irqrestore(&private(dev)->interrupt_lock, flags); + return comedi_buf_read_n_available(s->async); +} + +static int ni_660x_buf_change(struct comedi_device *dev, struct comedi_subdevice *s, unsigned long new_size) { int ret; @@ -938,14 +956,17 @@ static int ni_660x_buf_change(struct comedi_device * dev, struct comedi_subdevic return 0; } -static int ni_660x_allocate_private(struct comedi_device * dev) +static int ni_660x_allocate_private(struct comedi_device *dev) { int retval; unsigned i; - if ((retval = alloc_private(dev, sizeof(struct ni_660x_private))) < 0) + retval = alloc_private(dev, sizeof(struct ni_660x_private)); + if (retval < 0) return retval; + spin_lock_init(&private(dev)->mite_channel_lock); + spin_lock_init(&private(dev)->interrupt_lock); spin_lock_init(&private(dev)->soft_reg_copy_lock); for (i = 0; i < NUM_PFI_CHANNELS; ++i) { private(dev)->pfi_output_selects[i] = pfi_output_select_counter; @@ -953,7 +974,7 @@ static int ni_660x_allocate_private(struct comedi_device * dev) return 0; } -static int ni_660x_alloc_mite_rings(struct comedi_device * dev) +static int ni_660x_alloc_mite_rings(struct comedi_device *dev) { unsigned i; unsigned j; @@ -970,7 +991,7 @@ static int ni_660x_alloc_mite_rings(struct comedi_device * dev) return 0; } -static void ni_660x_free_mite_rings(struct comedi_device * dev) +static void ni_660x_free_mite_rings(struct comedi_device *dev) { unsigned i; unsigned j; @@ -982,7 +1003,7 @@ static void ni_660x_free_mite_rings(struct comedi_device * dev) } } -static int ni_660x_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int ni_660x_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; int ret; @@ -1031,7 +1052,7 @@ static int ni_660x_attach(struct comedi_device * dev, struct comedi_devconfig * s->insn_bits = ni_660x_dio_insn_bits; s->insn_config = ni_660x_dio_insn_config; s->io_bits = 0; /* all bits default to input */ - // we use the ioconfig registers to control dio direction, so zero output enables in stc dio control reg + /* we use the ioconfig registers to control dio direction, so zero output enables in stc dio control reg */ ni_660x_write_register(dev, 0, 0, STCDIOControl); private(dev)->counter_dev = ni_gpct_device_construct(dev, @@ -1055,6 +1076,7 @@ static int ni_660x_attach(struct comedi_device * dev, struct comedi_devconfig * s->len_chanlist = 1; s->do_cmdtest = &ni_660x_cmdtest; s->cancel = &ni_660x_cancel; + s->poll = &ni_660x_input_poll; s->async_dma_dir = DMA_BIDIRECTIONAL; s->buf_change = &ni_660x_buf_change; s->private = &private(dev)->counter_dev->counters[i]; @@ -1086,9 +1108,9 @@ static int ni_660x_attach(struct comedi_device * dev, struct comedi_devconfig * for (i = 0; i < board(dev)->n_chips; ++i) { set_tio_counterswap(dev, i); } - if ((ret = comedi_request_irq(mite_irq(private(dev)->mite), - &ni_660x_interrupt, IRQF_SHARED, "ni_660x", - dev)) < 0) { + ret = request_irq(mite_irq(private(dev)->mite), ni_660x_interrupt, + IRQF_SHARED, "ni_660x", dev); + if (ret < 0) { printk(" irq not available\n"); return ret; } @@ -1102,13 +1124,13 @@ static int ni_660x_attach(struct comedi_device * dev, struct comedi_devconfig * return 0; } -static int ni_660x_detach(struct comedi_device * dev) +static int ni_660x_detach(struct comedi_device *dev) { printk("comedi%d: ni_660x: remove\n", dev->minor); /* Free irq */ if (dev->irq) - comedi_free_irq(dev->irq, dev); + free_irq(dev->irq, dev); if (dev->private) { if (private(dev)->counter_dev) @@ -1122,17 +1144,17 @@ static int ni_660x_detach(struct comedi_device * dev) } static int -ni_660x_GPCT_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +ni_660x_GPCT_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { return ni_tio_rinsn(subdev_to_counter(s), insn, data); } -static void init_tio_chip(struct comedi_device * dev, int chipset) +static void init_tio_chip(struct comedi_device *dev, int chipset) { unsigned i; - // init dma configuration register + /* init dma configuration register */ private(dev)->dma_configuration_soft_copies[chipset] = 0; for (i = 0; i < MAX_DMA_CHANNEL; ++i) { private(dev)->dma_configuration_soft_copies[chipset] |= @@ -1142,26 +1164,26 @@ static void init_tio_chip(struct comedi_device * dev, int chipset) ni_660x_write_register(dev, chipset, private(dev)->dma_configuration_soft_copies[chipset], DMAConfigRegister); - for(i = 0; i < NUM_PFI_CHANNELS; ++i) + for (i = 0; i < NUM_PFI_CHANNELS; ++i) { ni_660x_write_register(dev, chipset, 0, IOConfigReg(i)); } } static int -ni_660x_GPCT_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +ni_660x_GPCT_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { return ni_tio_insn_config(subdev_to_counter(s), insn, data); } -static int ni_660x_GPCT_winsn(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +static int ni_660x_GPCT_winsn(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { return ni_tio_winsn(subdev_to_counter(s), insn, data); } -static int ni_660x_find_device(struct comedi_device * dev, int bus, int slot) +static int ni_660x_find_device(struct comedi_device *dev, int bus, int slot) { struct mite_struct *mite; int i; @@ -1188,12 +1210,12 @@ static int ni_660x_find_device(struct comedi_device * dev, int bus, int slot) return -EIO; } -static int ni_660x_dio_insn_bits(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +static int ni_660x_dio_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { unsigned base_bitfield_channel = CR_CHAN(insn->chanspec); - // Check if we have to write some bits + /* Check if we have to write some bits */ if (data[0]) { s->state &= ~(data[0] << base_bitfield_channel); s->state |= (data[0] & data[1]) << base_bitfield_channel; @@ -1208,7 +1230,7 @@ static int ni_660x_dio_insn_bits(struct comedi_device * dev, return 2; } -static void ni_660x_select_pfi_output(struct comedi_device * dev, unsigned pfi_channel, +static void ni_660x_select_pfi_output(struct comedi_device *dev, unsigned pfi_channel, unsigned output_select) { static const unsigned counter_4_7_first_pfi = 8; @@ -1218,8 +1240,8 @@ static void ni_660x_select_pfi_output(struct comedi_device * dev, unsigned pfi_c unsigned active_bits; unsigned idle_bits; - if(board(dev)->n_chips > 1) { - if(output_select == pfi_output_select_counter && + if (board (dev)->n_chips > 1) { + if (output_select == pfi_output_select_counter && pfi_channel >= counter_4_7_first_pfi && pfi_channel <= counter_4_7_last_pfi) { active_chipset = 1; @@ -1230,7 +1252,7 @@ static void ni_660x_select_pfi_output(struct comedi_device * dev, unsigned pfi_c } } - if(idle_chipset != active_chipset) { + if (idle_chipset != active_chipset) { idle_bits = ni_660x_read_register(dev, idle_chipset, IOConfigReg(pfi_channel)); idle_bits &= ~pfi_output_select_mask(pfi_channel); idle_bits |= pfi_output_select_bits(pfi_channel, pfi_output_select_high_Z); @@ -1243,7 +1265,7 @@ static void ni_660x_select_pfi_output(struct comedi_device * dev, unsigned pfi_c ni_660x_write_register(dev, active_chipset, active_bits, IOConfigReg(pfi_channel)); } -static int ni_660x_set_pfi_routing(struct comedi_device * dev, unsigned chan, +static int ni_660x_set_pfi_routing(struct comedi_device *dev, unsigned chan, unsigned source) { if (source > num_pfi_output_selects) @@ -1266,13 +1288,13 @@ static int ni_660x_set_pfi_routing(struct comedi_device * dev, unsigned chan, return 0; } -static unsigned ni_660x_get_pfi_routing(struct comedi_device * dev, unsigned chan) +static unsigned ni_660x_get_pfi_routing(struct comedi_device *dev, unsigned chan) { BUG_ON(chan >= NUM_PFI_CHANNELS); return private(dev)->pfi_output_selects[chan]; } -static void ni660x_config_filter(struct comedi_device * dev, unsigned pfi_channel, +static void ni660x_config_filter(struct comedi_device *dev, unsigned pfi_channel, enum ni_gpct_filter_select filter) { unsigned bits = ni_660x_read_register(dev, 0, IOConfigReg(pfi_channel)); @@ -1281,8 +1303,8 @@ static void ni660x_config_filter(struct comedi_device * dev, unsigned pfi_channe ni_660x_write_register(dev, 0, bits, IOConfigReg(pfi_channel)); } -static int ni_660x_dio_insn_config(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +static int ni_660x_dio_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { int chan = CR_CHAN(insn->chanspec); diff --git a/drivers/staging/comedi/drivers/ni_670x.c b/drivers/staging/comedi/drivers/ni_670x.c index d1312e073a65..71f7d3ab3aa1 100644 --- a/drivers/staging/comedi/drivers/ni_670x.c +++ b/drivers/staging/comedi/drivers/ni_670x.c @@ -41,6 +41,7 @@ Commands are not supported. */ +#include #include "../comedidev.h" #include "mite.h" @@ -69,29 +70,29 @@ struct ni_670x_board { static const struct ni_670x_board ni_670x_boards[] = { { - dev_id: 0x2c90, - name: "PCI-6703", - ao_chans:16, - ao_bits: 16, + .dev_id = 0x2c90, + .name = "PCI-6703", + .ao_chans = 16, + .ao_bits = 16, }, { - dev_id: 0x1920, - name: "PXI-6704", - ao_chans:32, - ao_bits: 16, + .dev_id = 0x1920, + .name = "PXI-6704", + .ao_chans = 32, + .ao_bits = 16, }, { - dev_id: 0x1290, - name: "PCI-6704", - ao_chans:32, - ao_bits: 16, + .dev_id = 0x1290, + .name = "PCI-6704", + .ao_chans = 32, + .ao_bits = 16, }, }; static DEFINE_PCI_DEVICE_TABLE(ni_670x_pci_table) = { {PCI_VENDOR_ID_NATINST, 0x2c90, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {PCI_VENDOR_ID_NATINST, 0x1920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - //{ PCI_VENDOR_ID_NATINST, 0x0000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + /* { PCI_VENDOR_ID_NATINST, 0x0000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, */ {0} }; @@ -111,32 +112,32 @@ struct ni_670x_private { #define devpriv ((struct ni_670x_private *)dev->private) #define n_ni_670x_boards (sizeof(ni_670x_boards)/sizeof(ni_670x_boards[0])) -static int ni_670x_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int ni_670x_detach(struct comedi_device * dev); +static int ni_670x_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int ni_670x_detach(struct comedi_device *dev); static struct comedi_driver driver_ni_670x = { - driver_name:"ni_670x", - module:THIS_MODULE, - attach:ni_670x_attach, - detach:ni_670x_detach, + .driver_name = "ni_670x", + .module = THIS_MODULE, + .attach = ni_670x_attach, + .detach = ni_670x_detach, }; COMEDI_PCI_INITCLEANUP(driver_ni_670x, ni_670x_pci_table); static struct comedi_lrange range_0_20mA = { 1, {RANGE_mA(0, 20)} }; -static int ni_670x_find_device(struct comedi_device * dev, int bus, int slot); +static int ni_670x_find_device(struct comedi_device *dev, int bus, int slot); -static int ni_670x_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int ni_670x_ao_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int ni_670x_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int ni_670x_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); +static int ni_670x_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int ni_670x_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int ni_670x_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int ni_670x_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); -static int ni_670x_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int ni_670x_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; int ret; @@ -144,7 +145,8 @@ static int ni_670x_attach(struct comedi_device * dev, struct comedi_devconfig * printk("comedi%d: ni_670x: ", dev->minor); - if ((ret = alloc_private(dev, sizeof(struct ni_670x_private))) < 0) + ret = alloc_private(dev, sizeof(struct ni_670x_private)); + if (ret < 0) return ret; ret = ni_670x_find_device(dev, it->options[0], it->options[1]); @@ -205,7 +207,7 @@ static int ni_670x_attach(struct comedi_device * dev, struct comedi_devconfig * return 1; } -static int ni_670x_detach(struct comedi_device * dev) +static int ni_670x_detach(struct comedi_device *dev) { printk("comedi%d: ni_670x: remove\n", dev->minor); @@ -216,13 +218,13 @@ static int ni_670x_detach(struct comedi_device * dev) mite_unsetup(devpriv->mite); if (dev->irq) - comedi_free_irq(dev->irq, dev); + free_irq(dev->irq, dev); return 0; } -static int ni_670x_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int ni_670x_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i; int chan = CR_CHAN(insn->chanspec); @@ -247,8 +249,8 @@ static int ni_670x_ao_winsn(struct comedi_device * dev, struct comedi_subdevice return i; } -static int ni_670x_ao_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int ni_670x_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i; int chan = CR_CHAN(insn->chanspec); @@ -259,8 +261,8 @@ static int ni_670x_ao_rinsn(struct comedi_device * dev, struct comedi_subdevice return i; } -static int ni_670x_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int ni_670x_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if (insn->n != 2) return -EINVAL; @@ -281,8 +283,8 @@ static int ni_670x_dio_insn_bits(struct comedi_device * dev, struct comedi_subde return 2; } -static int ni_670x_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int ni_670x_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int chan = CR_CHAN(insn->chanspec); @@ -308,7 +310,7 @@ static int ni_670x_dio_insn_config(struct comedi_device * dev, struct comedi_sub return insn->n; } -static int ni_670x_find_device(struct comedi_device * dev, int bus, int slot) +static int ni_670x_find_device(struct comedi_device *dev, int bus, int slot) { struct mite_struct *mite; int i; diff --git a/drivers/staging/comedi/drivers/ni_at_a2150.c b/drivers/staging/comedi/drivers/ni_at_a2150.c index 5d45bf24a5ef..45c6809031db 100644 --- a/drivers/staging/comedi/drivers/ni_at_a2150.c +++ b/drivers/staging/comedi/drivers/ni_at_a2150.c @@ -64,6 +64,7 @@ TRIG_WAKE_EOS */ +#include #include "../comedidev.h" #include @@ -73,10 +74,10 @@ TRIG_WAKE_EOS #include "comedi_fc.h" #define A2150_SIZE 28 -#define A2150_DMA_BUFFER_SIZE 0xff00 // size in bytes of dma buffer +#define A2150_DMA_BUFFER_SIZE 0xff00 /* size in bytes of dma buffer */ -//#define A2150_DEBUG // enable debugging code -#undef A2150_DEBUG // disable debugging code +/* #define A2150_DEBUG enable debugging code */ +#undef A2150_DEBUG /* disable debugging code */ /* Registers and bits */ #define CONFIG_REG 0x0 @@ -85,48 +86,48 @@ TRIG_WAKE_EOS #define CLOCK_SELECT_BITS(x) (((x) & 0x3) << 3) #define CLOCK_DIVISOR_BITS(x) (((x) & 0x3) << 5) #define CLOCK_MASK (0xf << 3) -#define ENABLE0_BIT 0x80 // enable (don't internally ground) channels 0 and 1 -#define ENABLE1_BIT 0x100 // enable (don't internally ground) channels 2 and 3 -#define AC0_BIT 0x200 // ac couple channels 0,1 -#define AC1_BIT 0x400 // ac couple channels 2,3 -#define APD_BIT 0x800 // analog power down -#define DPD_BIT 0x1000 // digital power down -#define TRIGGER_REG 0x2 // trigger config register +#define ENABLE0_BIT 0x80 /* enable (don't internally ground) channels 0 and 1 */ +#define ENABLE1_BIT 0x100 /* enable (don't internally ground) channels 2 and 3 */ +#define AC0_BIT 0x200 /* ac couple channels 0,1 */ +#define AC1_BIT 0x400 /* ac couple channels 2,3 */ +#define APD_BIT 0x800 /* analog power down */ +#define DPD_BIT 0x1000 /* digital power down */ +#define TRIGGER_REG 0x2 /* trigger config register */ #define POST_TRIGGER_BITS 0x2 #define DELAY_TRIGGER_BITS 0x3 -#define HW_TRIG_EN 0x10 // enable hardware trigger -#define FIFO_START_REG 0x6 // software start aquistion trigger -#define FIFO_RESET_REG 0x8 // clears fifo + fifo flags -#define FIFO_DATA_REG 0xa // read data -#define DMA_TC_CLEAR_REG 0xe // clear dma terminal count interrupt -#define STATUS_REG 0x12 // read only -#define FNE_BIT 0x1 // fifo not empty -#define OVFL_BIT 0x8 // fifo overflow -#define EDAQ_BIT 0x10 // end of aquisition interrupt -#define DCAL_BIT 0x20 // offset calibration in progress -#define INTR_BIT 0x40 // interrupt has occured -#define DMA_TC_BIT 0x80 // dma terminal count interrupt has occured +#define HW_TRIG_EN 0x10 /* enable hardware trigger */ +#define FIFO_START_REG 0x6 /* software start aquistion trigger */ +#define FIFO_RESET_REG 0x8 /* clears fifo + fifo flags */ +#define FIFO_DATA_REG 0xa /* read data */ +#define DMA_TC_CLEAR_REG 0xe /* clear dma terminal count interrupt */ +#define STATUS_REG 0x12 /* read only */ +#define FNE_BIT 0x1 /* fifo not empty */ +#define OVFL_BIT 0x8 /* fifo overflow */ +#define EDAQ_BIT 0x10 /* end of aquisition interrupt */ +#define DCAL_BIT 0x20 /* offset calibration in progress */ +#define INTR_BIT 0x40 /* interrupt has occured */ +#define DMA_TC_BIT 0x80 /* dma terminal count interrupt has occured */ #define ID_BITS(x) (((x) >> 8) & 0x3) -#define IRQ_DMA_CNTRL_REG 0x12 // write only -#define DMA_CHAN_BITS(x) ((x) & 0x7) // sets dma channel -#define DMA_EN_BIT 0x8 // enables dma -#define IRQ_LVL_BITS(x) (((x) & 0xf) << 4) // sets irq level -#define FIFO_INTR_EN_BIT 0x100 // enable fifo interrupts -#define FIFO_INTR_FHF_BIT 0x200 // interrupt fifo half full -#define DMA_INTR_EN_BIT 0x800 // enable interrupt on dma terminal count -#define DMA_DEM_EN_BIT 0x1000 // enables demand mode dma +#define IRQ_DMA_CNTRL_REG 0x12 /* write only */ +#define DMA_CHAN_BITS(x) ((x) & 0x7) /* sets dma channel */ +#define DMA_EN_BIT 0x8 /* enables dma */ +#define IRQ_LVL_BITS(x) (((x) & 0xf) << 4) /* sets irq level */ +#define FIFO_INTR_EN_BIT 0x100 /* enable fifo interrupts */ +#define FIFO_INTR_FHF_BIT 0x200 /* interrupt fifo half full */ +#define DMA_INTR_EN_BIT 0x800 /* enable interrupt on dma terminal count */ +#define DMA_DEM_EN_BIT 0x1000 /* enables demand mode dma */ #define I8253_BASE_REG 0x14 #define I8253_MODE_REG 0x17 -#define HW_COUNT_DISABLE 0x30 // disable hardware counting of conversions +#define HW_COUNT_DISABLE 0x30 /* disable hardware counting of conversions */ struct a2150_board { const char *name; - int clock[4]; // master clock periods, in nanoseconds - int num_clocks; // number of available master clock speeds - int ai_speed; // maximum conversion rate in nanoseconds + int clock[4]; /* master clock periods, in nanoseconds */ + int num_clocks; /* number of available master clock speeds */ + int ai_speed; /* maximum conversion rate in nanoseconds */ }; -//analog input range +/* analog input range */ static const struct comedi_lrange range_a2150 = { 1, { @@ -134,20 +135,20 @@ static const struct comedi_lrange range_a2150 = { } }; -// enum must match board indices +/* enum must match board indices */ enum { a2150_c, a2150_s }; static const struct a2150_board a2150_boards[] = { { - name: "at-a2150c", - clock: {31250, 22676, 20833, 19531}, - num_clocks:4, - ai_speed:19531, + .name = "at-a2150c", + .clock = {31250, 22676, 20833, 19531}, + .num_clocks = 4, + .ai_speed = 19531, }, { - name: "at-a2150s", - clock: {62500, 50000, 41667, 0}, - num_clocks:3, - ai_speed:41667, + .name = "at-a2150s", + .clock = {62500, 50000, 41667, 0}, + .num_clocks = 3, + .ai_speed = 41667, }, }; @@ -159,37 +160,37 @@ static const struct a2150_board a2150_boards[] = { struct a2150_private { volatile unsigned int count; /* number of data points left to be taken */ - unsigned int dma; // dma channel - s16 *dma_buffer; // dma buffer - unsigned int dma_transfer_size; // size in bytes of dma transfers - int irq_dma_bits; // irq/dma register bits - int config_bits; // config register bits + unsigned int dma; /* dma channel */ + s16 *dma_buffer; /* dma buffer */ + unsigned int dma_transfer_size; /* size in bytes of dma transfers */ + int irq_dma_bits; /* irq/dma register bits */ + int config_bits; /* config register bits */ }; #define devpriv ((struct a2150_private *)dev->private) -static int a2150_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int a2150_detach(struct comedi_device * dev); -static int a2150_cancel(struct comedi_device * dev, struct comedi_subdevice * s); +static int a2150_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int a2150_detach(struct comedi_device *dev); +static int a2150_cancel(struct comedi_device *dev, struct comedi_subdevice *s); static struct comedi_driver driver_a2150 = { - driver_name:"ni_at_a2150", - module:THIS_MODULE, - attach:a2150_attach, - detach:a2150_detach, + .driver_name = "ni_at_a2150", + .module = THIS_MODULE, + .attach = a2150_attach, + .detach = a2150_detach, }; -static irqreturn_t a2150_interrupt(int irq, void *d PT_REGS_ARG); -static int a2150_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd); -static int a2150_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s); -static int a2150_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int a2150_get_timing(struct comedi_device * dev, unsigned int *period, +static irqreturn_t a2150_interrupt(int irq, void *d); +static int a2150_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd); +static int a2150_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s); +static int a2150_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int a2150_get_timing(struct comedi_device *dev, unsigned int *period, int flags); -static int a2150_probe(struct comedi_device * dev); -static int a2150_set_chanlist(struct comedi_device * dev, unsigned int start_channel, +static int a2150_probe(struct comedi_device *dev); +static int a2150_set_chanlist(struct comedi_device *dev, unsigned int start_channel, unsigned int num_channels); /* * A convenient macro that defines init_module() and cleanup_module(), @@ -199,17 +200,17 @@ COMEDI_INITCLEANUP(driver_a2150); #ifdef A2150_DEBUG -static void ni_dump_regs(struct comedi_device * dev) +static void ni_dump_regs(struct comedi_device *dev) { - rt_printk("config bits 0x%x\n", devpriv->config_bits); - rt_printk("irq dma bits 0x%x\n", devpriv->irq_dma_bits); - rt_printk("status bits 0x%x\n", inw(dev->iobase + STATUS_REG)); + printk("config bits 0x%x\n", devpriv->config_bits); + printk("irq dma bits 0x%x\n", devpriv->irq_dma_bits); + printk("status bits 0x%x\n", inw(dev->iobase + STATUS_REG)); } #endif /* interrupt service routine */ -static irqreturn_t a2150_interrupt(int irq, void *d PT_REGS_ARG) +static irqreturn_t a2150_interrupt(int irq, void *d) { int i; int status; @@ -226,7 +227,7 @@ static irqreturn_t a2150_interrupt(int irq, void *d PT_REGS_ARG) comedi_error(dev, "premature interrupt"); return IRQ_HANDLED; } - // initialize async here to make sure s is not NULL + /* initialize async here to make sure s is not NULL */ async = s->async; async->events = 0; cmd = &async->cmd; @@ -258,7 +259,7 @@ static irqreturn_t a2150_interrupt(int irq, void *d PT_REGS_ARG) * count and address get set correctly */ clear_dma_ff(devpriv->dma); - // figure out how many points to read + /* figure out how many points to read */ max_points = devpriv->dma_transfer_size / sample_size; /* residue is the number of points left to be done on the dma * transfer. It should always be zero at this point unless @@ -269,7 +270,7 @@ static irqreturn_t a2150_interrupt(int irq, void *d PT_REGS_ARG) if (devpriv->count < num_points && cmd->stop_src == TRIG_COUNT) num_points = devpriv->count; - // figure out how many points will be stored next time + /* figure out how many points will be stored next time */ leftover = 0; if (cmd->stop_src == TRIG_NONE) { leftover = devpriv->dma_transfer_size / sample_size; @@ -288,7 +289,7 @@ static irqreturn_t a2150_interrupt(int irq, void *d PT_REGS_ARG) for (i = 0; i < num_points; i++) { /* write data point to comedi buffer */ dpnt = devpriv->dma_buffer[i]; - // convert from 2's complement to unsigned coding + /* convert from 2's complement to unsigned coding */ dpnt ^= 0x8000; cfc_write_to_buffer(s, dpnt); if (cmd->stop_src == TRIG_COUNT) { @@ -299,7 +300,7 @@ static irqreturn_t a2150_interrupt(int irq, void *d PT_REGS_ARG) } } } - // re-enable dma + /* re-enable dma */ if (leftover) { set_dma_addr(devpriv->dma, virt_to_bus(devpriv->dma_buffer)); set_dma_count(devpriv->dma, leftover * sample_size); @@ -317,14 +318,14 @@ static irqreturn_t a2150_interrupt(int irq, void *d PT_REGS_ARG) return IRQ_HANDLED; } -// probes board type, returns offset -static int a2150_probe(struct comedi_device * dev) +/* probes board type, returns offset */ +static int a2150_probe(struct comedi_device *dev) { int status = inw(dev->iobase + STATUS_REG); return ID_BITS(status); } -static int a2150_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int a2150_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; unsigned long iobase = it->options[0]; @@ -365,12 +366,12 @@ static int a2150_attach(struct comedi_device * dev, struct comedi_devconfig * it /* grab our IRQ */ if (irq) { - // check that irq is supported + /* check that irq is supported */ if (irq < 3 || irq == 8 || irq == 13 || irq > 15) { printk(" invalid irq line %u\n", irq); return -EINVAL; } - if (comedi_request_irq(irq, a2150_interrupt, 0, + if (request_irq(irq, a2150_interrupt, 0, driver_a2150.driver_name, dev)) { printk("unable to allocate irq %u\n", irq); return -EINVAL; @@ -378,7 +379,7 @@ static int a2150_attach(struct comedi_device * dev, struct comedi_devconfig * it devpriv->irq_dma_bits |= IRQ_LVL_BITS(irq); dev->irq = irq; } - // initialize dma + /* initialize dma */ if (dma) { if (dma == 4 || dma > 7) { printk(" invalid dma channel %u\n", dma); @@ -424,20 +425,20 @@ static int a2150_attach(struct comedi_device * dev, struct comedi_devconfig * it * prevent hardware count from stopping aquisition */ outw(HW_COUNT_DISABLE, dev->iobase + I8253_MODE_REG); - // set card's irq and dma levels + /* set card's irq and dma levels */ outw(devpriv->irq_dma_bits, dev->iobase + IRQ_DMA_CNTRL_REG); - // reset and sync adc clock circuitry + /* reset and sync adc clock circuitry */ outw_p(DPD_BIT | APD_BIT, dev->iobase + CONFIG_REG); outw_p(DPD_BIT, dev->iobase + CONFIG_REG); - // initialize configuration register + /* initialize configuration register */ devpriv->config_bits = 0; outw(devpriv->config_bits, dev->iobase + CONFIG_REG); - // wait until offset calibration is done, then enable analog inputs + /* wait until offset calibration is done, then enable analog inputs */ for (i = 0; i < timeout; i++) { if ((DCAL_BIT & inw(dev->iobase + STATUS_REG)) == 0) break; - comedi_udelay(1000); + udelay(1000); } if (i == timeout) { printk(" timed out waiting for offset calibration to complete\n"); @@ -449,19 +450,19 @@ static int a2150_attach(struct comedi_device * dev, struct comedi_devconfig * it return 0; }; -static int a2150_detach(struct comedi_device * dev) +static int a2150_detach(struct comedi_device *dev) { printk("comedi%d: %s: remove\n", dev->minor, driver_a2150.driver_name); /* only free stuff if it has been allocated by _attach */ if (dev->iobase) { - // put board in power-down mode + /* put board in power-down mode */ outw(APD_BIT | DPD_BIT, dev->iobase + CONFIG_REG); release_region(dev->iobase, A2150_SIZE); } if (dev->irq) - comedi_free_irq(dev->irq, dev); + free_irq(dev->irq, dev); if (devpriv) { if (devpriv->dma) free_dma(devpriv->dma); @@ -472,23 +473,23 @@ static int a2150_detach(struct comedi_device * dev) return 0; }; -static int a2150_cancel(struct comedi_device * dev, struct comedi_subdevice * s) +static int a2150_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { - // disable dma on card + /* disable dma on card */ devpriv->irq_dma_bits &= ~DMA_INTR_EN_BIT & ~DMA_EN_BIT; outw(devpriv->irq_dma_bits, dev->iobase + IRQ_DMA_CNTRL_REG); - // disable computer's dma + /* disable computer's dma */ disable_dma(devpriv->dma); - // clear fifo and reset triggering circuitry + /* clear fifo and reset triggering circuitry */ outw(0, dev->iobase + FIFO_RESET_REG); return 0; } -static int a2150_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd) +static int a2150_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd) { int err = 0; int tmp; @@ -582,7 +583,7 @@ static int a2150_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice if (err) return 4; - // check channel/gain list against card's limitations + /* check channel/gain list against card's limitations */ if (cmd->chanlist) { startChan = CR_CHAN(cmd->chanlist[0]); for (i = 1; i < cmd->chanlist_len; i++) { @@ -617,7 +618,7 @@ static int a2150_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice return 0; } -static int a2150_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s) +static int a2150_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; @@ -635,7 +636,7 @@ static int a2150_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s) " dma incompatible with hard real-time interrupt (TRIG_RT), aborting"); return -1; } - // clear fifo and reset triggering circuitry + /* clear fifo and reset triggering circuitry */ outw(0, dev->iobase + FIFO_RESET_REG); /* setup chanlist */ @@ -643,7 +644,7 @@ static int a2150_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s) cmd->chanlist_len) < 0) return -1; - // setup ac/dc coupling + /* setup ac/dc coupling */ if (CR_AREF(cmd->chanlist[0]) == AREF_OTHER) devpriv->config_bits |= AC0_BIT; else @@ -653,23 +654,23 @@ static int a2150_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s) else devpriv->config_bits &= ~AC1_BIT; - // setup timing + /* setup timing */ a2150_get_timing(dev, &cmd->scan_begin_arg, cmd->flags); - // send timing, channel, config bits + /* send timing, channel, config bits */ outw(devpriv->config_bits, dev->iobase + CONFIG_REG); - // initialize number of samples remaining + /* initialize number of samples remaining */ devpriv->count = cmd->stop_arg * cmd->chanlist_len; - // enable computer's dma + /* enable computer's dma */ lock_flags = claim_dma_lock(); disable_dma(devpriv->dma); /* clear flip-flop to make sure 2-byte registers for * count and address get set correctly */ clear_dma_ff(devpriv->dma); set_dma_addr(devpriv->dma, virt_to_bus(devpriv->dma_buffer)); - // set size of transfer to fill in 1/3 second + /* set size of transfer to fill in 1/3 second */ #define ONE_THIRD_SECOND 333333333 devpriv->dma_transfer_size = sizeof(devpriv->dma_buffer[0]) * cmd->chanlist_len * @@ -688,36 +689,36 @@ static int a2150_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s) * one spurious interrupt that has been happening */ outw(0x00, dev->iobase + DMA_TC_CLEAR_REG); - // enable dma on card + /* enable dma on card */ devpriv->irq_dma_bits |= DMA_INTR_EN_BIT | DMA_EN_BIT; outw(devpriv->irq_dma_bits, dev->iobase + IRQ_DMA_CNTRL_REG); - // may need to wait 72 sampling periods if timing was changed + /* may need to wait 72 sampling periods if timing was changed */ i8254_load(dev->iobase + I8253_BASE_REG, 0, 2, 72, 0); - // setup start triggering + /* setup start triggering */ trigger_bits = 0; - // decide if we need to wait 72 periods for valid data + /* decide if we need to wait 72 periods for valid data */ if (cmd->start_src == TRIG_NOW && (old_config_bits & CLOCK_MASK) != (devpriv->config_bits & CLOCK_MASK)) { - // set trigger source to delay trigger + /* set trigger source to delay trigger */ trigger_bits |= DELAY_TRIGGER_BITS; } else { - // otherwise no delay + /* otherwise no delay */ trigger_bits |= POST_TRIGGER_BITS; } - // enable external hardware trigger + /* enable external hardware trigger */ if (cmd->start_src == TRIG_EXT) { trigger_bits |= HW_TRIG_EN; } else if (cmd->start_src == TRIG_OTHER) { - // XXX add support for level/slope start trigger using TRIG_OTHER + /* XXX add support for level/slope start trigger using TRIG_OTHER */ comedi_error(dev, "you shouldn't see this?"); } - // send trigger config bits + /* send trigger config bits */ outw(trigger_bits, dev->iobase + TRIGGER_REG); - // start aquisition for soft trigger + /* start aquisition for soft trigger */ if (cmd->start_src == TRIG_NOW) { outw(0, dev->iobase + FIFO_START_REG); } @@ -728,35 +729,35 @@ static int a2150_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s) return 0; } -static int a2150_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int a2150_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { unsigned int i, n; static const int timeout = 100000; static const int filter_delay = 36; - // clear fifo and reset triggering circuitry + /* clear fifo and reset triggering circuitry */ outw(0, dev->iobase + FIFO_RESET_REG); /* setup chanlist */ if (a2150_set_chanlist(dev, CR_CHAN(insn->chanspec), 1) < 0) return -1; - // set dc coupling + /* set dc coupling */ devpriv->config_bits &= ~AC0_BIT; devpriv->config_bits &= ~AC1_BIT; - // send timing, channel, config bits + /* send timing, channel, config bits */ outw(devpriv->config_bits, dev->iobase + CONFIG_REG); - // disable dma on card + /* disable dma on card */ devpriv->irq_dma_bits &= ~DMA_INTR_EN_BIT & ~DMA_EN_BIT; outw(devpriv->irq_dma_bits, dev->iobase + IRQ_DMA_CNTRL_REG); - // setup start triggering + /* setup start triggering */ outw(0, dev->iobase + TRIGGER_REG); - // start aquisition for soft trigger + /* start aquisition for soft trigger */ outw(0, dev->iobase + FIFO_START_REG); /* there is a 35.6 sample delay for data to get through the antialias filter */ @@ -764,7 +765,7 @@ static int a2150_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * for (i = 0; i < timeout; i++) { if (inw(dev->iobase + STATUS_REG) & FNE_BIT) break; - comedi_udelay(1); + udelay(1); } if (i == timeout) { comedi_error(dev, "timeout"); @@ -773,12 +774,12 @@ static int a2150_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * inw(dev->iobase + FIFO_DATA_REG); } - // read data + /* read data */ for (n = 0; n < insn->n; n++) { for (i = 0; i < timeout; i++) { if (inw(dev->iobase + STATUS_REG) & FNE_BIT) break; - comedi_udelay(1); + udelay(1); } if (i == timeout) { comedi_error(dev, "timeout"); @@ -789,12 +790,12 @@ static int a2150_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * #endif data[n] = inw(dev->iobase + FIFO_DATA_REG); #ifdef A2150_DEBUG - rt_printk(" data is %i\n", data[n]); + printk(" data is %i\n", data[n]); #endif data[n] ^= 0x8000; } - // clear fifo and reset triggering circuitry + /* clear fifo and reset triggering circuitry */ outw(0, dev->iobase + FIFO_RESET_REG); return n; @@ -802,14 +803,14 @@ static int a2150_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * /* sets bits in devpriv->clock_bits to nearest approximation of requested period, * adjusts requested period to actual timing. */ -static int a2150_get_timing(struct comedi_device * dev, unsigned int *period, +static int a2150_get_timing(struct comedi_device *dev, unsigned int *period, int flags) { int lub, glb, temp; int lub_divisor_shift, lub_index, glb_divisor_shift, glb_index; int i, j; - // initialize greatest lower and least upper bounds + /* initialize greatest lower and least upper bounds */ lub_divisor_shift = 3; lub_index = 0; lub = thisboard->clock[lub_index] * (1 << lub_divisor_shift); @@ -817,19 +818,19 @@ static int a2150_get_timing(struct comedi_device * dev, unsigned int *period, glb_index = thisboard->num_clocks - 1; glb = thisboard->clock[glb_index] * (1 << glb_divisor_shift); - // make sure period is in available range + /* make sure period is in available range */ if (*period < glb) *period = glb; if (*period > lub) *period = lub; - // we can multiply period by 1, 2, 4, or 8, using (1 << i) + /* we can multiply period by 1, 2, 4, or 8, using (1 << i) */ for (i = 0; i < 4; i++) { - // there are a maximum of 4 master clocks + /* there are a maximum of 4 master clocks */ for (j = 0; j < thisboard->num_clocks; j++) { - // temp is the period in nanosec we are evaluating + /* temp is the period in nanosec we are evaluating */ temp = thisboard->clock[j] * (1 << i); - // if it is the best match yet + /* if it is the best match yet */ if (temp < lub && temp >= *period) { lub_divisor_shift = i; lub_index = j; @@ -846,7 +847,7 @@ static int a2150_get_timing(struct comedi_device * dev, unsigned int *period, switch (flags) { case TRIG_ROUND_NEAREST: default: - // if least upper bound is better approximation + /* if least upper bound is better approximation */ if (lub - *period < *period - glb) { *period = lub; } else { @@ -861,7 +862,7 @@ static int a2150_get_timing(struct comedi_device * dev, unsigned int *period, break; } - // set clock bits for config register appropriately + /* set clock bits for config register appropriately */ devpriv->config_bits &= ~CLOCK_MASK; if (*period == lub) { devpriv->config_bits |= @@ -876,7 +877,7 @@ static int a2150_get_timing(struct comedi_device * dev, unsigned int *period, return 0; } -static int a2150_set_chanlist(struct comedi_device * dev, unsigned int start_channel, +static int a2150_set_chanlist(struct comedi_device *dev, unsigned int start_channel, unsigned int num_channels) { if (start_channel + num_channels > 4) diff --git a/drivers/staging/comedi/drivers/ni_at_ao.c b/drivers/staging/comedi/drivers/ni_at_ao.c index 2cc46b672588..4e8bf9ed167c 100644 --- a/drivers/staging/comedi/drivers/ni_at_ao.c +++ b/drivers/staging/comedi/drivers/ni_at_ao.c @@ -158,12 +158,12 @@ struct atao_board { static const struct atao_board atao_boards[] = { { - name: "ai-ao-6", - n_ao_chans:6, + .name = "ai-ao-6", + .n_ao_chans = 6, }, { - name: "ai-ao-10", - n_ao_chans:10, + .name = "ai-ao-10", + .n_ao_chans = 10, }, }; @@ -181,36 +181,36 @@ struct atao_private { #define devpriv ((struct atao_private *)dev->private) -static int atao_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int atao_detach(struct comedi_device * dev); +static int atao_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int atao_detach(struct comedi_device *dev); static struct comedi_driver driver_atao = { - driver_name:"ni_at_ao", - module:THIS_MODULE, - attach:atao_attach, - detach:atao_detach, - board_name:&atao_boards[0].name, - offset:sizeof(struct atao_board), - num_names:sizeof(atao_boards) / sizeof(struct atao_board), + .driver_name = "ni_at_ao", + .module = THIS_MODULE, + .attach = atao_attach, + .detach = atao_detach, + .board_name = &atao_boards[0].name, + .offset = sizeof(struct atao_board), + .num_names = ARRAY_SIZE(atao_boards), }; COMEDI_INITCLEANUP(driver_atao); -static void atao_reset(struct comedi_device * dev); +static void atao_reset(struct comedi_device *dev); -static int atao_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int atao_ao_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int atao_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int atao_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int atao_calib_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int atao_calib_insn_write(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); +static int atao_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int atao_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int atao_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int atao_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int atao_calib_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int atao_calib_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); -static int atao_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int atao_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; unsigned long iobase; @@ -229,7 +229,7 @@ static int atao_attach(struct comedi_device * dev, struct comedi_devconfig * it) } dev->iobase = iobase; - //dev->board_ptr = atao_probe(dev); + /* dev->board_ptr = atao_probe(dev); */ dev->board_name = thisboard->name; @@ -273,7 +273,7 @@ static int atao_attach(struct comedi_device * dev, struct comedi_devconfig * it) s = dev->subdevices + 3; /* eeprom subdevice */ - //s->type=COMEDI_SUBD_EEPROM; + /* s->type=COMEDI_SUBD_EEPROM; */ s->type = COMEDI_SUBD_UNUSED; atao_reset(dev); @@ -283,7 +283,7 @@ static int atao_attach(struct comedi_device * dev, struct comedi_devconfig * it) return 0; } -static int atao_detach(struct comedi_device * dev) +static int atao_detach(struct comedi_device *dev) { printk("comedi%d: atao: remove\n", dev->minor); @@ -293,7 +293,7 @@ static int atao_detach(struct comedi_device * dev) return 0; } -static void atao_reset(struct comedi_device * dev) +static void atao_reset(struct comedi_device *dev) { /* This is the reset sequence described in the manual */ @@ -323,8 +323,8 @@ static void atao_reset(struct comedi_device * dev) outw(devpriv->cfg1, dev->iobase + ATAO_CFG1); } -static int atao_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int atao_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i; int chan = CR_CHAN(insn->chanspec); @@ -347,8 +347,8 @@ static int atao_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s return i; } -static int atao_ao_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int atao_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i; int chan = CR_CHAN(insn->chanspec); @@ -359,8 +359,8 @@ static int atao_ao_rinsn(struct comedi_device * dev, struct comedi_subdevice * s return i; } -static int atao_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int atao_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if (insn->n != 2) return -EINVAL; @@ -376,8 +376,8 @@ static int atao_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevic return 2; } -static int atao_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int atao_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int chan = CR_CHAN(insn->chanspec); unsigned int mask, bit; @@ -421,8 +421,8 @@ static int atao_dio_insn_config(struct comedi_device * dev, struct comedi_subdev * DACs. It is not explicitly stated in the manual how to access * the caldacs, but we can guess. */ -static int atao_calib_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int atao_calib_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i; for (i = 0; i < insn->n; i++) { @@ -431,8 +431,8 @@ static int atao_calib_insn_read(struct comedi_device * dev, struct comedi_subdev return insn->n; } -static int atao_calib_insn_write(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int atao_calib_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { unsigned int bitstring, bit; unsigned int chan = CR_CHAN(insn->chanspec); diff --git a/drivers/staging/comedi/drivers/ni_atmio.c b/drivers/staging/comedi/drivers/ni_atmio.c index fcc38535afc5..8839447538f2 100644 --- a/drivers/staging/comedi/drivers/ni_atmio.c +++ b/drivers/staging/comedi/drivers/ni_atmio.c @@ -93,6 +93,7 @@ are not supported. */ +#include #include "../comedidev.h" #include @@ -114,156 +115,156 @@ are not supported. #define MAX_N_CALDACS 32 -static const ni_board ni_boards[] = { - {device_id:44, - isapnp_id:0x0000,/* XXX unknown */ - name: "at-mio-16e-1", - n_adchan:16, - adbits: 12, - ai_fifo_depth:8192, - alwaysdither:0, - gainlkup:ai_gain_16, - ai_speed:800, - n_aochan:2, - aobits: 12, - ao_fifo_depth:2048, +static const struct ni_board_struct ni_boards[] = { + {.device_id = 44, + .isapnp_id = 0x0000,/* XXX unknown */ + .name = "at-mio-16e-1", + .n_adchan = 16, + .adbits = 12, + .ai_fifo_depth = 8192, + .alwaysdither = 0, + .gainlkup = ai_gain_16, + .ai_speed = 800, + .n_aochan = 2, + .aobits = 12, + .ao_fifo_depth = 2048, .ao_range_table = &range_ni_E_ao_ext, - ao_unipolar:1, - ao_speed:1000, - has_8255:0, + .ao_unipolar = 1, + .ao_speed = 1000, + .has_8255 = 0, .num_p0_dio_channels = 8, - caldac: {mb88341}, + .caldac = {mb88341}, }, - {device_id:25, - isapnp_id:0x1900, - name: "at-mio-16e-2", - n_adchan:16, - adbits: 12, - ai_fifo_depth:2048, - alwaysdither:0, - gainlkup:ai_gain_16, - ai_speed:2000, - n_aochan:2, - aobits: 12, - ao_fifo_depth:2048, + {.device_id = 25, + .isapnp_id = 0x1900, + .name = "at-mio-16e-2", + .n_adchan = 16, + .adbits = 12, + .ai_fifo_depth = 2048, + .alwaysdither = 0, + .gainlkup = ai_gain_16, + .ai_speed = 2000, + .n_aochan = 2, + .aobits = 12, + .ao_fifo_depth = 2048, .ao_range_table = &range_ni_E_ao_ext, - ao_unipolar:1, - ao_speed:1000, - has_8255:0, + .ao_unipolar = 1, + .ao_speed = 1000, + .has_8255 = 0, .num_p0_dio_channels = 8, - caldac: {mb88341}, + .caldac = {mb88341}, }, - {device_id:36, - isapnp_id:0x2400, - name: "at-mio-16e-10", - n_adchan:16, - adbits: 12, - ai_fifo_depth:512, - alwaysdither:0, - gainlkup:ai_gain_16, - ai_speed:10000, - n_aochan:2, - aobits: 12, - ao_fifo_depth:0, + {.device_id = 36, + .isapnp_id = 0x2400, + .name = "at-mio-16e-10", + .n_adchan = 16, + .adbits = 12, + .ai_fifo_depth = 512, + .alwaysdither = 0, + .gainlkup = ai_gain_16, + .ai_speed = 10000, + .n_aochan = 2, + .aobits = 12, + .ao_fifo_depth = 0, .ao_range_table = &range_ni_E_ao_ext, - ao_unipolar:1, - ao_speed:10000, + .ao_unipolar = 1, + .ao_speed = 10000, .num_p0_dio_channels = 8, - caldac: {ad8804_debug}, - has_8255:0, + .caldac = {ad8804_debug}, + .has_8255 = 0, }, - {device_id:37, - isapnp_id:0x2500, - name: "at-mio-16de-10", - n_adchan:16, - adbits: 12, - ai_fifo_depth:512, - alwaysdither:0, - gainlkup:ai_gain_16, - ai_speed:10000, - n_aochan:2, - aobits: 12, - ao_fifo_depth:0, + {.device_id = 37, + .isapnp_id = 0x2500, + .name = "at-mio-16de-10", + .n_adchan = 16, + .adbits = 12, + .ai_fifo_depth = 512, + .alwaysdither = 0, + .gainlkup = ai_gain_16, + .ai_speed = 10000, + .n_aochan = 2, + .aobits = 12, + .ao_fifo_depth = 0, .ao_range_table = &range_ni_E_ao_ext, - ao_unipolar:1, - ao_speed:10000, + .ao_unipolar = 1, + .ao_speed = 10000, .num_p0_dio_channels = 8, - caldac: {ad8804_debug}, - has_8255:1, + .caldac = {ad8804_debug}, + .has_8255 = 1, }, - {device_id:38, - isapnp_id:0x2600, - name: "at-mio-64e-3", - n_adchan:64, - adbits: 12, - ai_fifo_depth:2048, - alwaysdither:0, - gainlkup:ai_gain_16, - ai_speed:2000, - n_aochan:2, - aobits: 12, - ao_fifo_depth:2048, + {.device_id = 38, + .isapnp_id = 0x2600, + .name = "at-mio-64e-3", + .n_adchan = 64, + .adbits = 12, + .ai_fifo_depth = 2048, + .alwaysdither = 0, + .gainlkup = ai_gain_16, + .ai_speed = 2000, + .n_aochan = 2, + .aobits = 12, + .ao_fifo_depth = 2048, .ao_range_table = &range_ni_E_ao_ext, - ao_unipolar:1, - ao_speed:1000, - has_8255:0, + .ao_unipolar = 1, + .ao_speed = 1000, + .has_8255 = 0, .num_p0_dio_channels = 8, - caldac: {ad8804_debug}, + .caldac = {ad8804_debug}, }, - {device_id:39, - isapnp_id:0x2700, - name: "at-mio-16xe-50", - n_adchan:16, - adbits: 16, - ai_fifo_depth:512, - alwaysdither:1, - gainlkup:ai_gain_8, - ai_speed:50000, - n_aochan:2, - aobits: 12, - ao_fifo_depth:0, + {.device_id = 39, + .isapnp_id = 0x2700, + .name = "at-mio-16xe-50", + .n_adchan = 16, + .adbits = 16, + .ai_fifo_depth = 512, + .alwaysdither = 1, + .gainlkup = ai_gain_8, + .ai_speed = 50000, + .n_aochan = 2, + .aobits = 12, + .ao_fifo_depth = 0, .ao_range_table = &range_bipolar10, - ao_unipolar:0, - ao_speed:50000, + .ao_unipolar = 0, + .ao_speed = 50000, .num_p0_dio_channels = 8, - caldac: {dac8800, dac8043}, - has_8255:0, + .caldac = {dac8800, dac8043}, + .has_8255 = 0, }, - {device_id:50, - isapnp_id:0x0000,/* XXX unknown */ - name: "at-mio-16xe-10", - n_adchan:16, - adbits: 16, - ai_fifo_depth:512, - alwaysdither:1, - gainlkup:ai_gain_14, - ai_speed:10000, - n_aochan:2, - aobits: 16, - ao_fifo_depth:2048, + {.device_id = 50, + .isapnp_id = 0x0000,/* XXX unknown */ + .name = "at-mio-16xe-10", + .n_adchan = 16, + .adbits = 16, + .ai_fifo_depth = 512, + .alwaysdither = 1, + .gainlkup = ai_gain_14, + .ai_speed = 10000, + .n_aochan = 2, + .aobits = 16, + .ao_fifo_depth = 2048, .ao_range_table = &range_ni_E_ao_ext, - ao_unipolar:1, - ao_speed:1000, + .ao_unipolar = 1, + .ao_speed = 1000, .num_p0_dio_channels = 8, - caldac: {dac8800, dac8043, ad8522}, - has_8255:0, + .caldac = {dac8800, dac8043, ad8522}, + .has_8255 = 0, }, - {device_id:51, - isapnp_id:0x0000,/* XXX unknown */ - name: "at-ai-16xe-10", - n_adchan:16, - adbits: 16, - ai_fifo_depth:512, - alwaysdither:1, /* unknown */ - gainlkup:ai_gain_14, - ai_speed:10000, - n_aochan:0, - aobits: 0, - ao_fifo_depth:0, - ao_unipolar:0, + {.device_id = 51, + .isapnp_id = 0x0000,/* XXX unknown */ + .name = "at-ai-16xe-10", + .n_adchan = 16, + .adbits = 16, + .ai_fifo_depth = 512, + .alwaysdither = 1, /* unknown */ + .gainlkup = ai_gain_14, + .ai_speed = 10000, + .n_aochan = 0, + .aobits = 0, + .ao_fifo_depth = 0, + .ao_unipolar = 0, .num_p0_dio_channels = 8, - caldac: {dac8800, dac8043, ad8522}, - has_8255:0, + .caldac = {dac8800, dac8043, ad8522}, + .has_8255 = 0, } }; @@ -276,18 +277,19 @@ static const int ni_irqpin[] = #define NI_E_IRQ_FLAGS 0 -typedef struct { +struct ni_private { struct pnp_dev *isapnp_dev; - NI_PRIVATE_COMMON} ni_private; -#define devpriv ((ni_private *)dev->private) + NI_PRIVATE_COMMON +}; +#define devpriv ((struct ni_private *)dev->private) /* How we access registers */ -#define ni_writel(a,b) (outl((a),(b)+dev->iobase)) +#define ni_writel(a, b) (outl((a), (b)+dev->iobase)) #define ni_readl(a) (inl((a)+dev->iobase)) -#define ni_writew(a,b) (outw((a),(b)+dev->iobase)) +#define ni_writew(a, b) (outw((a), (b)+dev->iobase)) #define ni_readw(a) (inw((a)+dev->iobase)) -#define ni_writeb(a,b) (outb((a),(b)+dev->iobase)) +#define ni_writeb(a, b) (outb((a), (b)+dev->iobase)) #define ni_readb(a) (inb((a)+dev->iobase)) /* How we access windowed registers */ @@ -296,72 +298,72 @@ typedef struct { * read/written directly in the I/O space of the board. The * AT-MIO devices map the low 8 STC registers to iobase+addr*2. */ -static void ni_atmio_win_out(struct comedi_device * dev, uint16_t data, int addr) +static void ni_atmio_win_out(struct comedi_device *dev, uint16_t data, int addr) { unsigned long flags; - comedi_spin_lock_irqsave(&devpriv->window_lock, flags); + spin_lock_irqsave(&devpriv->window_lock, flags); if ((addr) < 8) { ni_writew(data, addr * 2); } else { ni_writew(addr, Window_Address); ni_writew(data, Window_Data); } - comedi_spin_unlock_irqrestore(&devpriv->window_lock, flags); + spin_unlock_irqrestore(&devpriv->window_lock, flags); } -static uint16_t ni_atmio_win_in(struct comedi_device * dev, int addr) +static uint16_t ni_atmio_win_in(struct comedi_device *dev, int addr) { unsigned long flags; uint16_t ret; - comedi_spin_lock_irqsave(&devpriv->window_lock, flags); + spin_lock_irqsave(&devpriv->window_lock, flags); if (addr < 8) { ret = ni_readw(addr * 2); } else { ni_writew(addr, Window_Address); ret = ni_readw(Window_Data); } - comedi_spin_unlock_irqrestore(&devpriv->window_lock, flags); + spin_unlock_irqrestore(&devpriv->window_lock, flags); return ret; } static struct pnp_device_id device_ids[] = { - {.id = "NIC1900",.driver_data = 0}, - {.id = "NIC2400",.driver_data = 0}, - {.id = "NIC2500",.driver_data = 0}, - {.id = "NIC2600",.driver_data = 0}, - {.id = "NIC2700",.driver_data = 0}, + {.id = "NIC1900", .driver_data = 0}, + {.id = "NIC2400", .driver_data = 0}, + {.id = "NIC2500", .driver_data = 0}, + {.id = "NIC2600", .driver_data = 0}, + {.id = "NIC2700", .driver_data = 0}, {.id = ""} }; MODULE_DEVICE_TABLE(pnp, device_ids); -static int ni_atmio_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int ni_atmio_detach(struct comedi_device * dev); +static int ni_atmio_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int ni_atmio_detach(struct comedi_device *dev); static struct comedi_driver driver_atmio = { - driver_name:"ni_atmio", - module:THIS_MODULE, - attach:ni_atmio_attach, - detach:ni_atmio_detach, + .driver_name = "ni_atmio", + .module = THIS_MODULE, + .attach = ni_atmio_attach, + .detach = ni_atmio_detach, }; COMEDI_INITCLEANUP(driver_atmio); #include "ni_mio_common.c" -static int ni_getboardtype(struct comedi_device * dev); +static int ni_getboardtype(struct comedi_device *dev); /* clean up allocated resources */ -static int ni_atmio_detach(struct comedi_device * dev) +static int ni_atmio_detach(struct comedi_device *dev) { mio_common_detach(dev); if (dev->iobase) release_region(dev->iobase, NI_SIZE); if (dev->irq) { - comedi_free_irq(dev->irq, dev); + free_irq(dev->irq, dev); } if (devpriv->isapnp_dev) pnp_device_detach(devpriv->isapnp_dev); @@ -404,7 +406,7 @@ static int ni_isapnp_find_board(struct pnp_dev **dev) return 0; } -static int ni_atmio_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int ni_atmio_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct pnp_dev *isapnp_dev; int ret; @@ -413,8 +415,10 @@ static int ni_atmio_attach(struct comedi_device * dev, struct comedi_devconfig * unsigned int irq; /* allocate private area */ - if ((ret = ni_alloc_private(dev)) < 0) + ret = ni_alloc_private(dev); + if (ret < 0) return ret; + devpriv->stc_writew = &ni_atmio_win_out; devpriv->stc_readw = &ni_atmio_win_in; devpriv->stc_writel = &win_out2; @@ -475,8 +479,10 @@ static int ni_atmio_attach(struct comedi_device * dev, struct comedi_devconfig * return -EINVAL; } printk(" ( irq = %u )", irq); - if ((ret = comedi_request_irq(irq, ni_E_interrupt, - NI_E_IRQ_FLAGS, "ni_atmio", dev)) < 0) { + ret = request_irq(irq, ni_E_interrupt, NI_E_IRQ_FLAGS, + "ni_atmio", dev); + + if (ret < 0) { printk(" irq not available\n"); return -EINVAL; } @@ -485,14 +491,15 @@ static int ni_atmio_attach(struct comedi_device * dev, struct comedi_devconfig * /* generic E series stuff in ni_mio_common.c */ - if ((ret = ni_E_init(dev, it)) < 0) { + ret = ni_E_init(dev, it); + if (ret < 0) { return ret; } return 0; } -static int ni_getboardtype(struct comedi_device * dev) +static int ni_getboardtype(struct comedi_device *dev) { int device_id = ni_read_eeprom(dev, 511); int i; diff --git a/drivers/staging/comedi/drivers/ni_atmio16d.c b/drivers/staging/comedi/drivers/ni_atmio16d.c index 35fcd172af2e..1a8c2ab20d3d 100644 --- a/drivers/staging/comedi/drivers/ni_atmio16d.c +++ b/drivers/staging/comedi/drivers/ni_atmio16d.c @@ -35,6 +35,7 @@ Devices: [National Instruments] AT-MIO-16 (atmio16), AT-MIO-16D (atmio16d) * */ +#include #include "../comedidev.h" #include @@ -111,12 +112,12 @@ struct atmio16_board_t { static const struct atmio16_board_t atmio16_boards[] = { { - name: "atmio16", - has_8255:0, + .name = "atmio16", + .has_8255 = 0, }, { - name: "atmio16d", - has_8255:1, + .name = "atmio16d", + .has_8255 = 1, }, }; @@ -125,25 +126,25 @@ static const struct atmio16_board_t atmio16_boards[] = { #define boardtype ((const struct atmio16_board_t *)dev->board_ptr) /* function prototypes */ -static int atmio16d_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int atmio16d_detach(struct comedi_device * dev); -static irqreturn_t atmio16d_interrupt(int irq, void *d PT_REGS_ARG); -static int atmio16d_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd); -static int atmio16d_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s); -static int atmio16d_ai_cancel(struct comedi_device * dev, struct comedi_subdevice * s); -static void reset_counters(struct comedi_device * dev); -static void reset_atmio16d(struct comedi_device * dev); +static int atmio16d_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int atmio16d_detach(struct comedi_device *dev); +static irqreturn_t atmio16d_interrupt(int irq, void *d); +static int atmio16d_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd); +static int atmio16d_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s); +static int atmio16d_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s); +static void reset_counters(struct comedi_device *dev); +static void reset_atmio16d(struct comedi_device *dev); /* main driver struct */ static struct comedi_driver driver_atmio16d = { - driver_name:"atmio16", - module:THIS_MODULE, - attach:atmio16d_attach, - detach:atmio16d_detach, - board_name:&atmio16_boards[0].name, - num_names:n_atmio16_boards, - offset:sizeof(struct atmio16_board_t), + .driver_name = "atmio16", + .module = THIS_MODULE, + .attach = atmio16d_attach, + .detach = atmio16d_detach, + .board_name = &atmio16_boards[0].name, + .num_names = n_atmio16_boards, + .offset = sizeof(struct atmio16_board_t), }; COMEDI_INITCLEANUP(driver_atmio16d); @@ -187,7 +188,7 @@ struct atmio16d_private { unsigned int com_reg_2_state; /* current state of command register 2 */ }; -static void reset_counters(struct comedi_device * dev) +static void reset_counters(struct comedi_device *dev) { /* Counter 2 */ outw(0xFFC2, dev->iobase + AM9513A_COM_REG); @@ -225,7 +226,7 @@ static void reset_counters(struct comedi_device * dev) outw(0, dev->iobase + AD_CLEAR_REG); } -static void reset_atmio16d(struct comedi_device * dev) +static void reset_atmio16d(struct comedi_device *dev) { int i; @@ -257,12 +258,12 @@ static void reset_atmio16d(struct comedi_device * dev) outw(2048, dev->iobase + DAC1_REG); } -static irqreturn_t atmio16d_interrupt(int irq, void *d PT_REGS_ARG) +static irqreturn_t atmio16d_interrupt(int irq, void *d) { struct comedi_device *dev = d; struct comedi_subdevice *s = dev->subdevices + 0; -// printk("atmio16d_interrupt!\n"); +/* printk("atmio16d_interrupt!\n"); */ comedi_buf_put(s->async, inw(dev->iobase + AD_FIFO_REG)); @@ -270,8 +271,8 @@ static irqreturn_t atmio16d_interrupt(int irq, void *d PT_REGS_ARG) return IRQ_HANDLED; } -static int atmio16d_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd) +static int atmio16d_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd) { int err = 0, tmp; #ifdef DEBUG1 @@ -371,7 +372,7 @@ static int atmio16d_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevi return 0; } -static int atmio16d_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s) +static int atmio16d_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { struct comedi_cmd *cmd = &s->async->cmd; unsigned int timer, base_clock; @@ -417,10 +418,10 @@ static int atmio16d_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * } else if (cmd->convert_arg < 655360000) { base_clock = CLOCK_100_KHZ; timer = cmd->convert_arg / 10000; - } else if (cmd->convert_arg <= 0xffffffff /* 6553600000 */ ) { + } else if (cmd->convert_arg <= 0xffffffff /* 6553600000 */) { base_clock = CLOCK_10_KHZ; timer = cmd->convert_arg / 100000; - } else if (cmd->convert_arg <= 0xffffffff /* 65536000000 */ ) { + } else if (cmd->convert_arg <= 0xffffffff /* 65536000000 */) { base_clock = CLOCK_1_KHZ; timer = cmd->convert_arg / 1000000; } @@ -449,11 +450,13 @@ static int atmio16d_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * outw(devpriv->com_reg_1_state, dev->iobase + COM_REG_1); } else { /* Counter 4 and 5 are needed */ - if ((tmp = sample_count & 0xFFFF)) { + + tmp = sample_count & 0xFFFF; + if (tmp) outw(tmp - 1, dev->iobase + AM9513A_DATA_REG); - } else { + else outw(0xFFFF, dev->iobase + AM9513A_DATA_REG); - } + outw(0xFF48, dev->iobase + AM9513A_COM_REG); outw(0, dev->iobase + AM9513A_DATA_REG); outw(0xFF28, dev->iobase + AM9513A_COM_REG); @@ -483,10 +486,10 @@ static int atmio16d_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * } else if (cmd->scan_begin_arg < 655360000) { base_clock = CLOCK_100_KHZ; timer = cmd->scan_begin_arg / 10000; - } else if (cmd->scan_begin_arg < 0xffffffff /* 6553600000 */ ) { + } else if (cmd->scan_begin_arg < 0xffffffff /* 6553600000 */) { base_clock = CLOCK_10_KHZ; timer = cmd->scan_begin_arg / 100000; - } else if (cmd->scan_begin_arg < 0xffffffff /* 65536000000 */ ) { + } else if (cmd->scan_begin_arg < 0xffffffff /* 65536000000 */) { base_clock = CLOCK_1_KHZ; timer = cmd->scan_begin_arg / 1000000; } @@ -519,7 +522,7 @@ static int atmio16d_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * } /* This will cancel a running acquisition operation */ -static int atmio16d_ai_cancel(struct comedi_device * dev, struct comedi_subdevice * s) +static int atmio16d_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { reset_atmio16d(dev); @@ -527,8 +530,8 @@ static int atmio16d_ai_cancel(struct comedi_device * dev, struct comedi_subdevic } /* Mode 0 is used to get a single conversion on demand */ -static int atmio16d_ai_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int atmio16d_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i, t; int chan; @@ -542,9 +545,9 @@ static int atmio16d_ai_insn_read(struct comedi_device * dev, struct comedi_subde gain = CR_RANGE(insn->chanspec); /* reset the Analog input circuitry */ - //outw( 0, dev->iobase+AD_CLEAR_REG ); + /* outw( 0, dev->iobase+AD_CLEAR_REG ); */ /* reset the Analog Input MUX Counter to 0 */ - //outw( 0, dev->iobase+MUX_CNTR_REG ); + /* outw( 0, dev->iobase+MUX_CNTR_REG ); */ /* set the Input MUX gain */ outw(chan | (gain << 6), dev->iobase + MUX_GAIN_REG); @@ -577,7 +580,7 @@ static int atmio16d_ai_insn_read(struct comedi_device * dev, struct comedi_subde } /* end waiting, now check if it timed out */ if (t == ATMIO16D_TIMEOUT) { - rt_printk("atmio16d: timeout\n"); + printk("atmio16d: timeout\n"); return -ETIME; } @@ -586,8 +589,8 @@ static int atmio16d_ai_insn_read(struct comedi_device * dev, struct comedi_subde return i; } -static int atmio16d_ao_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int atmio16d_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i; #ifdef DEBUG1 @@ -601,8 +604,8 @@ static int atmio16d_ao_insn_read(struct comedi_device * dev, struct comedi_subde return i; } -static int atmio16d_ao_insn_write(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int atmio16d_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i; int chan; @@ -636,8 +639,8 @@ static int atmio16d_ao_insn_write(struct comedi_device * dev, struct comedi_subd return i; } -static int atmio16d_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int atmio16d_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if (insn->n != 2) return -EINVAL; @@ -652,8 +655,8 @@ static int atmio16d_dio_insn_bits(struct comedi_device * dev, struct comedi_subd return 2; } -static int atmio16d_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int atmio16d_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i; int mask; @@ -706,7 +709,7 @@ static int atmio16d_dio_insn_config(struct comedi_device * dev, struct comedi_su options[12] - dac1 coding */ -static int atmio16d_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int atmio16d_attach(struct comedi_device *dev, struct comedi_devconfig *it) { unsigned int irq; unsigned long iobase; @@ -726,9 +729,12 @@ static int atmio16d_attach(struct comedi_device * dev, struct comedi_devconfig * /* board name */ dev->board_name = boardtype->name; - if ((ret = alloc_subdevices(dev, 4)) < 0) + ret = alloc_subdevices(dev, 4); + if (ret < 0) return ret; - if ((ret = alloc_private(dev, sizeof(struct atmio16d_private))) < 0) + + ret = alloc_private(dev, sizeof(struct atmio16d_private)); + if (ret < 0) return ret; /* reset the atmio16d hardware */ @@ -737,8 +743,9 @@ static int atmio16d_attach(struct comedi_device * dev, struct comedi_devconfig * /* check if our interrupt is available and get it */ irq = it->options[1]; if (irq) { - if ((ret = comedi_request_irq(irq, atmio16d_interrupt, - 0, "atmio16d", dev)) < 0) { + + ret = request_irq(irq, atmio16d_interrupt, 0, "atmio16d", dev); + if (ret < 0) { printk("failed to allocate irq %u\n", irq); return ret; } @@ -841,7 +848,7 @@ static int atmio16d_attach(struct comedi_device * dev, struct comedi_devconfig * return 0; } -static int atmio16d_detach(struct comedi_device * dev) +static int atmio16d_detach(struct comedi_device *dev) { printk("comedi%d: atmio16d: remove\n", dev->minor); @@ -849,7 +856,7 @@ static int atmio16d_detach(struct comedi_device * dev) subdev_8255_cleanup(dev, dev->subdevices + 3); if (dev->irq) - comedi_free_irq(dev->irq, dev); + free_irq(dev->irq, dev); reset_atmio16d(dev); diff --git a/drivers/staging/comedi/drivers/ni_daq_700.c b/drivers/staging/comedi/drivers/ni_daq_700.c index 61a31ad2d030..e34948205320 100644 --- a/drivers/staging/comedi/drivers/ni_daq_700.c +++ b/drivers/staging/comedi/drivers/ni_daq_700.c @@ -41,6 +41,7 @@ emu as port A output, port B input, port C N/A). IRQ is assigned but not used. */ +#include #include "../comedidev.h" #include @@ -53,36 +54,36 @@ IRQ is assigned but not used. static struct pcmcia_device *pcmcia_cur_dev = NULL; -#define DIO700_SIZE 8 // size of io region used by board +#define DIO700_SIZE 8 /* size of io region used by board */ -static int dio700_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int dio700_detach(struct comedi_device * dev); +static int dio700_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int dio700_detach(struct comedi_device *dev); enum dio700_bustype { pcmcia_bustype }; struct dio700_board { const char *name; - int device_id; // device id for pcmcia board - enum dio700_bustype bustype; // PCMCIA - int have_dio; // have daqcard-700 dio - // function pointers so we can use inb/outb or readb/writeb - // as appropriate + int device_id; /* device id for pcmcia board */ + enum dio700_bustype bustype; /* PCMCIA */ + int have_dio; /* have daqcard-700 dio */ + /* function pointers so we can use inb/outb or readb/writeb */ + /* as appropriate */ unsigned int (*read_byte) (unsigned int address); void (*write_byte) (unsigned int byte, unsigned int address); }; static const struct dio700_board dio700_boards[] = { { - name: "daqcard-700", - device_id:0x4743,// 0x10b is manufacturer id, 0x4743 is device id - bustype: pcmcia_bustype, - have_dio:1, + .name = "daqcard-700", + .device_id = 0x4743,/* 0x10b is manufacturer id, 0x4743 is device id */ + .bustype = pcmcia_bustype, + .have_dio = 1, }, { - name: "ni_daq_700", - device_id:0x4743,// 0x10b is manufacturer id, 0x4743 is device id - bustype: pcmcia_bustype, - have_dio:1, + .name = "ni_daq_700", + .device_id = 0x4743,/* 0x10b is manufacturer id, 0x4743 is device id */ + .bustype = pcmcia_bustype, + .have_dio = 1, }, }; @@ -100,13 +101,13 @@ struct dio700_private { #define devpriv ((struct dio700_private *)dev->private) static struct comedi_driver driver_dio700 = { - driver_name:"ni_daq_700", - module:THIS_MODULE, - attach:dio700_attach, - detach:dio700_detach, - num_names:sizeof(dio700_boards) / sizeof(struct dio700_board), - board_name:&dio700_boards[0].name, - offset:sizeof(struct dio700_board), + .driver_name = "ni_daq_700", + .module = THIS_MODULE, + .attach = dio700_attach, + .detach = dio700_detach, + .num_names = ARRAY_SIZE(dio700_boards), + .board_name = &dio700_boards[0].name, + .offset = sizeof(struct dio700_board), }; /* the real driver routines */ @@ -128,9 +129,9 @@ struct subdev_700_struct { #define CALLBACK_FUNC (((struct subdev_700_struct *)s->private)->cb_func) #define subdevpriv ((struct subdev_700_struct *)s->private) -static void do_config(struct comedi_device * dev, struct comedi_subdevice * s); +static void do_config(struct comedi_device *dev, struct comedi_subdevice *s); -void subdev_700_interrupt(struct comedi_device * dev, struct comedi_subdevice * s) +void subdev_700_interrupt(struct comedi_device *dev, struct comedi_subdevice *s) { short d; @@ -155,8 +156,8 @@ static int subdev_700_cb(int dir, int port, int data, unsigned long arg) } } -static int subdev_700_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int subdev_700_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if (data[0]) { s->state &= ~data[0]; @@ -173,8 +174,8 @@ static int subdev_700_insn(struct comedi_device * dev, struct comedi_subdevice * return 2; } -static int subdev_700_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int subdev_700_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { switch (data[0]) { @@ -196,13 +197,13 @@ static int subdev_700_insn_config(struct comedi_device * dev, struct comedi_subd return 1; } -static void do_config(struct comedi_device * dev, struct comedi_subdevice * s) +static void do_config(struct comedi_device *dev, struct comedi_subdevice *s) { /* use powerup defaults */ return; } -static int subdev_700_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd) +static int subdev_700_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd) { int err = 0; unsigned int tmp; @@ -276,21 +277,21 @@ static int subdev_700_cmdtest(struct comedi_device * dev, struct comedi_subdevic return 0; } -static int subdev_700_cmd(struct comedi_device * dev, struct comedi_subdevice * s) +static int subdev_700_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { /* FIXME */ return 0; } -static int subdev_700_cancel(struct comedi_device * dev, struct comedi_subdevice * s) +static int subdev_700_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { /* FIXME */ return 0; } -int subdev_700_init(struct comedi_device * dev, struct comedi_subdevice * s, int (*cb) (int, +int subdev_700_init(struct comedi_device *dev, struct comedi_subdevice *s, int (*cb) (int, int, int, unsigned long), unsigned long arg) { s->type = COMEDI_SUBD_DIO; @@ -319,7 +320,7 @@ int subdev_700_init(struct comedi_device * dev, struct comedi_subdevice * s, int return 0; } -int subdev_700_init_irq(struct comedi_device * dev, struct comedi_subdevice * s, +int subdev_700_init_irq(struct comedi_device *dev, struct comedi_subdevice *s, int (*cb) (int, int, int, unsigned long), unsigned long arg) { int ret; @@ -337,7 +338,7 @@ int subdev_700_init_irq(struct comedi_device * dev, struct comedi_subdevice * s, return 0; } -void subdev_700_cleanup(struct comedi_device * dev, struct comedi_subdevice * s) +void subdev_700_cleanup(struct comedi_device *dev, struct comedi_subdevice *s) { if (s->private) { if (subdevpriv->have_irq) { @@ -352,7 +353,7 @@ EXPORT_SYMBOL(subdev_700_init_irq); EXPORT_SYMBOL(subdev_700_cleanup); EXPORT_SYMBOL(subdev_700_interrupt); -static int dio700_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int dio700_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; unsigned long iobase = 0; @@ -365,7 +366,7 @@ static int dio700_attach(struct comedi_device * dev, struct comedi_devconfig * i if (alloc_private(dev, sizeof(struct dio700_private)) < 0) return -ENOMEM; - // get base address, irq etc. based on bustype + /* get base address, irq etc. based on bustype */ switch (thisboard->bustype) { case pcmcia_bustype: link = pcmcia_cur_dev; /* XXX hack */ @@ -415,7 +416,7 @@ static int dio700_attach(struct comedi_device * dev, struct comedi_devconfig * i return 0; }; -static int dio700_detach(struct comedi_device * dev) +static int dio700_detach(struct comedi_device *dev) { printk("comedi%d: ni_daq_700: cs-remove\n", dev->minor); @@ -425,12 +426,12 @@ static int dio700_detach(struct comedi_device * dev) if (thisboard->bustype != pcmcia_bustype && dev->iobase) release_region(dev->iobase, DIO700_SIZE); if (dev->irq) - comedi_free_irq(dev->irq, dev); + free_irq(dev->irq, dev); return 0; }; -// PCMCIA crap +/* PCMCIA crap */ /* All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If @@ -594,15 +595,21 @@ static void dio700_config(struct pcmcia_device *link) tuple.TupleData = buf; tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; - if ((last_ret = pcmcia_get_first_tuple(link, &tuple)) != 0) { + + last_ret = pcmcia_get_first_tuple(link, &tuple); + if (last_ret) { cs_error(link, GetFirstTuple, last_ret); goto cs_failed; } - if ((last_ret = pcmcia_get_tuple_data(link, &tuple)) != 0) { + + last_ret = pcmcia_get_tuple_data(link, &tuple); + if (last_ret) { cs_error(link, GetTupleData, last_ret); goto cs_failed; } - if ((last_ret = pcmcia_parse_tuple(&tuple, &parse)) != 0) { + + last_ret = pcmcia_parse_tuple(&tuple, &parse); + if (last_ret) { cs_error(link, ParseTuple, last_ret); goto cs_failed; } @@ -622,7 +629,8 @@ static void dio700_config(struct pcmcia_device *link) will only use the CIS to fill in implementation-defined details. */ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - if ((last_ret = pcmcia_get_first_tuple(link, &tuple)) != 0) { + last_ret = pcmcia_get_first_tuple(link, &tuple); + if (last_ret != 0) { cs_error(link, GetFirstTuple, last_ret); goto cs_failed; } @@ -692,7 +700,9 @@ static void dio700_config(struct pcmcia_device *link) break; next_entry: - if ((last_ret = pcmcia_get_next_tuple(link, &tuple)) != 0) { + + last_ret = pcmcia_get_next_tuple(link, &tuple); + if (last_ret) { cs_error(link, GetNextTuple, last_ret); goto cs_failed; } @@ -703,18 +713,21 @@ static void dio700_config(struct pcmcia_device *link) handler to the interrupt, unless the 'Handler' member of the irq structure is initialized. */ - if (link->conf.Attributes & CONF_ENABLE_IRQ) - if ((last_ret = pcmcia_request_irq(link, &link->irq)) != 0) { + if (link->conf.Attributes & CONF_ENABLE_IRQ) { + last_ret = pcmcia_request_irq(link, &link->irq); + if (last_ret) { cs_error(link, RequestIRQ, last_ret); goto cs_failed; } + } /* This actually configures the PCMCIA socket -- setting up the I/O windows and the interrupt mapping, and putting the card and host interface into "Memory and IO" mode. */ - if ((last_ret = pcmcia_request_configuration(link, &link->conf)) != 0) { + last_ret = pcmcia_request_configuration(link, &link->conf); + if (last_ret != 0) { cs_error(link, RequestConfiguration, last_ret); goto cs_failed; } diff --git a/drivers/staging/comedi/drivers/ni_daq_dio24.c b/drivers/staging/comedi/drivers/ni_daq_dio24.c index daec5c4b4c95..a8ac02febc66 100644 --- a/drivers/staging/comedi/drivers/ni_daq_dio24.c +++ b/drivers/staging/comedi/drivers/ni_daq_dio24.c @@ -37,9 +37,10 @@ This is just a wrapper around the 8255.o driver to properly handle the PCMCIA interface. */ -//#define LABPC_DEBUG // enable debugging messages +/* #define LABPC_DEBUG */ /* enable debugging messages */ #undef LABPC_DEBUG +#include #include "../comedidev.h" #include @@ -54,42 +55,42 @@ the PCMCIA interface. static struct pcmcia_device *pcmcia_cur_dev = NULL; -#define DIO24_SIZE 4 // size of io region used by board +#define DIO24_SIZE 4 /* size of io region used by board */ -static int dio24_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int dio24_detach(struct comedi_device * dev); +static int dio24_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int dio24_detach(struct comedi_device *dev); enum dio24_bustype { pcmcia_bustype }; -typedef struct dio24_board_struct { +struct dio24_board_struct { const char *name; - int device_id; // device id for pcmcia board - enum dio24_bustype bustype; // PCMCIA - int have_dio; // have 8255 chip - // function pointers so we can use inb/outb or readb/writeb as appropriate + int device_id; /* device id for pcmcia board */ + enum dio24_bustype bustype; /* PCMCIA */ + int have_dio; /* have 8255 chip */ + /* function pointers so we can use inb/outb or readb/writeb as appropriate */ unsigned int (*read_byte) (unsigned int address); void (*write_byte) (unsigned int byte, unsigned int address); -} dio24_board; +}; -static const dio24_board dio24_boards[] = { +static const struct dio24_board_struct dio24_boards[] = { { - name: "daqcard-dio24", - device_id:0x475c,// 0x10b is manufacturer id, 0x475c is device id - bustype: pcmcia_bustype, - have_dio:1, + .name = "daqcard-dio24", + .device_id = 0x475c,/* 0x10b is manufacturer id, 0x475c is device id */ + .bustype = pcmcia_bustype, + .have_dio = 1, }, { - name: "ni_daq_dio24", - device_id:0x475c,// 0x10b is manufacturer id, 0x475c is device id - bustype: pcmcia_bustype, - have_dio:1, + .name = "ni_daq_dio24", + .device_id = 0x475c,/* 0x10b is manufacturer id, 0x475c is device id */ + .bustype = pcmcia_bustype, + .have_dio = 1, }, }; /* * Useful for shorthand access to the particular board structure */ -#define thisboard ((const dio24_board *)dev->board_ptr) +#define thisboard ((const struct dio24_board_struct *)dev->board_ptr) struct dio24_private { @@ -100,16 +101,16 @@ struct dio24_private { #define devpriv ((struct dio24_private *)dev->private) static struct comedi_driver driver_dio24 = { - driver_name:"ni_daq_dio24", - module:THIS_MODULE, - attach:dio24_attach, - detach:dio24_detach, - num_names:sizeof(dio24_boards) / sizeof(dio24_board), - board_name:&dio24_boards[0].name, - offset:sizeof(dio24_board), + .driver_name = "ni_daq_dio24", + .module = THIS_MODULE, + .attach = dio24_attach, + .detach = dio24_detach, + .num_names = ARRAY_SIZE(dio24_boards), + .board_name = &dio24_boards[0].name, + .offset = sizeof(struct dio24_board_struct), }; -static int dio24_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int dio24_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; unsigned long iobase = 0; @@ -122,7 +123,7 @@ static int dio24_attach(struct comedi_device * dev, struct comedi_devconfig * it if (alloc_private(dev, sizeof(struct dio24_private)) < 0) return -ENOMEM; - // get base address, irq etc. based on bustype + /* get base address, irq etc. based on bustype */ switch (thisboard->bustype) { case pcmcia_bustype: link = pcmcia_cur_dev; /* XXX hack */ @@ -172,7 +173,7 @@ static int dio24_attach(struct comedi_device * dev, struct comedi_devconfig * it return 0; }; -static int dio24_detach(struct comedi_device * dev) +static int dio24_detach(struct comedi_device *dev) { printk("comedi%d: ni_daq_dio24: remove\n", dev->minor); @@ -182,12 +183,12 @@ static int dio24_detach(struct comedi_device * dev) if (thisboard->bustype != pcmcia_bustype && dev->iobase) release_region(dev->iobase, DIO24_SIZE); if (dev->irq) - comedi_free_irq(dev->irq, dev); + free_irq(dev->irq, dev); return 0; }; -// PCMCIA crap +/* PCMCIA crap */ /* All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If @@ -236,12 +237,12 @@ static void dio24_cs_detach(struct pcmcia_device *); static const dev_info_t dev_info = "ni_daq_dio24"; -typedef struct local_info_t { +struct local_info_t { struct pcmcia_device *link; dev_node_t node; int stop; struct bus_operations *bus; -} local_info_t; +}; /*====================================================================== @@ -257,14 +258,14 @@ typedef struct local_info_t { static int dio24_cs_attach(struct pcmcia_device *link) { - local_info_t *local; + struct local_info_t *local; printk(KERN_INFO "ni_daq_dio24: HOLA SOY YO - CS-attach!\n"); DEBUG(0, "dio24_cs_attach()\n"); /* Allocate space for private device-specific data */ - local = kzalloc(sizeof(local_info_t), GFP_KERNEL); + local = kzalloc(sizeof(struct local_info_t), GFP_KERNEL); if (!local) return -ENOMEM; local->link = link; @@ -309,7 +310,7 @@ static void dio24_cs_detach(struct pcmcia_device *link) DEBUG(0, "dio24_cs_detach(0x%p)\n", link); if (link->dev_node) { - ((local_info_t *) link->priv)->stop = 1; + ((struct local_info_t *) link->priv)->stop = 1; dio24_release(link); } @@ -329,7 +330,7 @@ static void dio24_cs_detach(struct pcmcia_device *link) static void dio24_config(struct pcmcia_device *link) { - local_info_t *dev = link->priv; + struct local_info_t *dev = link->priv; tuple_t tuple; cisparse_t parse; int last_ret; @@ -351,15 +352,21 @@ static void dio24_config(struct pcmcia_device *link) tuple.TupleData = buf; tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; - if ((last_ret = pcmcia_get_first_tuple(link, &tuple)) != 0) { + + last_ret = pcmcia_get_first_tuple(link, &tuple); + if (last_ret) { cs_error(link, GetFirstTuple, last_ret); goto cs_failed; } - if ((last_ret = pcmcia_get_tuple_data(link, &tuple)) != 0) { + + last_ret = pcmcia_get_tuple_data(link, &tuple); + if (last_ret) { cs_error(link, GetTupleData, last_ret); goto cs_failed; } - if ((last_ret = pcmcia_parse_tuple(&tuple, &parse)) != 0) { + + last_ret = pcmcia_parse_tuple(&tuple, &parse); + if (last_ret) { cs_error(link, ParseTuple, last_ret); goto cs_failed; } @@ -379,7 +386,9 @@ static void dio24_config(struct pcmcia_device *link) will only use the CIS to fill in implementation-defined details. */ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - if ((last_ret = pcmcia_get_first_tuple(link, &tuple)) != 0) { + + last_ret = pcmcia_get_first_tuple(link, &tuple); + if (last_ret) { cs_error(link, GetFirstTuple, last_ret); goto cs_failed; } @@ -449,7 +458,9 @@ static void dio24_config(struct pcmcia_device *link) break; next_entry: - if ((last_ret = pcmcia_get_next_tuple(link, &tuple)) != 0) { + + last_ret = pcmcia_get_next_tuple(link, &tuple); + if (last_ret) { cs_error(link, GetNextTuple, last_ret); goto cs_failed; } @@ -460,18 +471,21 @@ static void dio24_config(struct pcmcia_device *link) handler to the interrupt, unless the 'Handler' member of the irq structure is initialized. */ - if (link->conf.Attributes & CONF_ENABLE_IRQ) - if ((last_ret = pcmcia_request_irq(link, &link->irq)) != 0) { + if (link->conf.Attributes & CONF_ENABLE_IRQ) { + last_ret = pcmcia_request_irq(link, &link->irq); + if (last_ret) { cs_error(link, RequestIRQ, last_ret); goto cs_failed; } + } /* This actually configures the PCMCIA socket -- setting up the I/O windows and the interrupt mapping, and putting the card and host interface into "Memory and IO" mode. */ - if ((last_ret = pcmcia_request_configuration(link, &link->conf)) != 0) { + last_ret = pcmcia_request_configuration(link, &link->conf); + if (last_ret) { cs_error(link, RequestConfiguration, last_ret); goto cs_failed; } @@ -529,7 +543,7 @@ static void dio24_release(struct pcmcia_device *link) static int dio24_cs_suspend(struct pcmcia_device *link) { - local_info_t *local = link->priv; + struct local_info_t *local = link->priv; /* Mark the device as stopped, to block IO until later */ local->stop = 1; @@ -538,7 +552,7 @@ static int dio24_cs_suspend(struct pcmcia_device *link) static int dio24_cs_resume(struct pcmcia_device *link) { - local_info_t *local = link->priv; + struct local_info_t *local = link->priv; local->stop = 0; return 0; diff --git a/drivers/staging/comedi/drivers/ni_labpc.c b/drivers/staging/comedi/drivers/ni_labpc.c index 37898d8474cd..30e11f46a640 100644 --- a/drivers/staging/comedi/drivers/ni_labpc.c +++ b/drivers/staging/comedi/drivers/ni_labpc.c @@ -74,8 +74,9 @@ NI manuals: */ #undef LABPC_DEBUG -//#define LABPC_DEBUG // enable debugging messages +/* #define LABPC_DEBUG enable debugging messages */ +#include #include "../comedidev.h" #include @@ -89,120 +90,120 @@ NI manuals: #define DRV_NAME "ni_labpc" -#define LABPC_SIZE 32 // size of io region used by board -#define LABPC_TIMER_BASE 500 // 2 MHz master clock +#define LABPC_SIZE 32 /* size of io region used by board */ +#define LABPC_TIMER_BASE 500 /* 2 MHz master clock */ /* Registers for the lab-pc+ */ -//write-only registers +/* write-only registers */ #define COMMAND1_REG 0x0 #define ADC_GAIN_MASK (0x7 << 4) #define ADC_CHAN_BITS(x) ((x) & 0x7) -#define ADC_SCAN_EN_BIT 0x80 // enables multi channel scans +#define ADC_SCAN_EN_BIT 0x80 /* enables multi channel scans */ #define COMMAND2_REG 0x1 -#define PRETRIG_BIT 0x1 // enable pretriggering (used in conjunction with SWTRIG) -#define HWTRIG_BIT 0x2 // enable paced conversions on external trigger -#define SWTRIG_BIT 0x4 // enable paced conversions -#define CASCADE_BIT 0x8 // use two cascaded counters for pacing +#define PRETRIG_BIT 0x1 /* enable pretriggering (used in conjunction with SWTRIG) */ +#define HWTRIG_BIT 0x2 /* enable paced conversions on external trigger */ +#define SWTRIG_BIT 0x4 /* enable paced conversions */ +#define CASCADE_BIT 0x8 /* use two cascaded counters for pacing */ #define DAC_PACED_BIT(channel) (0x40 << ((channel) & 0x1)) #define COMMAND3_REG 0x2 -#define DMA_EN_BIT 0x1 // enable dma transfers -#define DIO_INTR_EN_BIT 0x2 // enable interrupts for 8255 -#define DMATC_INTR_EN_BIT 0x4 // enable dma terminal count interrupt -#define TIMER_INTR_EN_BIT 0x8 // enable timer interrupt -#define ERR_INTR_EN_BIT 0x10 // enable error interrupt -#define ADC_FNE_INTR_EN_BIT 0x20 // enable fifo not empty interrupt +#define DMA_EN_BIT 0x1 /* enable dma transfers */ +#define DIO_INTR_EN_BIT 0x2 /* enable interrupts for 8255 */ +#define DMATC_INTR_EN_BIT 0x4 /* enable dma terminal count interrupt */ +#define TIMER_INTR_EN_BIT 0x8 /* enable timer interrupt */ +#define ERR_INTR_EN_BIT 0x10 /* enable error interrupt */ +#define ADC_FNE_INTR_EN_BIT 0x20 /* enable fifo not empty interrupt */ #define ADC_CONVERT_REG 0x3 #define DAC_LSB_REG(channel) (0x4 + 2 * ((channel) & 0x1)) #define DAC_MSB_REG(channel) (0x5 + 2 * ((channel) & 0x1)) #define ADC_CLEAR_REG 0x8 #define DMATC_CLEAR_REG 0xa #define TIMER_CLEAR_REG 0xc -#define COMMAND6_REG 0xe // 1200 boards only -#define ADC_COMMON_BIT 0x1 // select ground or common-mode reference -#define ADC_UNIP_BIT 0x2 // adc unipolar -#define DAC_UNIP_BIT(channel) (0x4 << ((channel) & 0x1)) // dac unipolar -#define ADC_FHF_INTR_EN_BIT 0x20 // enable fifo half full interrupt -#define A1_INTR_EN_BIT 0x40 // enable interrupt on end of hardware count -#define ADC_SCAN_UP_BIT 0x80 // scan up from channel zero instead of down to zero +#define COMMAND6_REG 0xe /* 1200 boards only */ +#define ADC_COMMON_BIT 0x1 /* select ground or common-mode reference */ +#define ADC_UNIP_BIT 0x2 /* adc unipolar */ +#define DAC_UNIP_BIT(channel) (0x4 << ((channel) & 0x1)) /* dac unipolar */ +#define ADC_FHF_INTR_EN_BIT 0x20 /* enable fifo half full interrupt */ +#define A1_INTR_EN_BIT 0x40 /* enable interrupt on end of hardware count */ +#define ADC_SCAN_UP_BIT 0x80 /* scan up from channel zero instead of down to zero */ #define COMMAND4_REG 0xf -#define INTERVAL_SCAN_EN_BIT 0x1 // enables 'interval' scanning -#define EXT_SCAN_EN_BIT 0x2 // enables external signal on counter b1 output to trigger scan -#define EXT_CONVERT_OUT_BIT 0x4 // chooses direction (output or input) for EXTCONV* line -#define ADC_DIFF_BIT 0x8 // chooses differential inputs for adc (in conjunction with board jumper) +#define INTERVAL_SCAN_EN_BIT 0x1 /* enables 'interval' scanning */ +#define EXT_SCAN_EN_BIT 0x2 /* enables external signal on counter b1 output to trigger scan */ +#define EXT_CONVERT_OUT_BIT 0x4 /* chooses direction (output or input) for EXTCONV* line */ +#define ADC_DIFF_BIT 0x8 /* chooses differential inputs for adc (in conjunction with board jumper) */ #define EXT_CONVERT_DISABLE_BIT 0x10 -#define COMMAND5_REG 0x1c // 1200 boards only, calibration stuff -#define EEPROM_WRITE_UNPROTECT_BIT 0x4 // enable eeprom for write -#define DITHER_EN_BIT 0x8 // enable dithering -#define CALDAC_LOAD_BIT 0x10 // load calibration dac -#define SCLOCK_BIT 0x20 // serial clock - rising edge writes, falling edge reads -#define SDATA_BIT 0x40 // serial data bit for writing to eeprom or calibration dacs -#define EEPROM_EN_BIT 0x80 // enable eeprom for read/write +#define COMMAND5_REG 0x1c /* 1200 boards only, calibration stuff */ +#define EEPROM_WRITE_UNPROTECT_BIT 0x4 /* enable eeprom for write */ +#define DITHER_EN_BIT 0x8 /* enable dithering */ +#define CALDAC_LOAD_BIT 0x10 /* load calibration dac */ +#define SCLOCK_BIT 0x20 /* serial clock - rising edge writes, falling edge reads */ +#define SDATA_BIT 0x40 /* serial data bit for writing to eeprom or calibration dacs */ +#define EEPROM_EN_BIT 0x80 /* enable eeprom for read/write */ #define INTERVAL_COUNT_REG 0x1e #define INTERVAL_LOAD_REG 0x1f #define INTERVAL_LOAD_BITS 0x1 -// read-only registers +/* read-only registers */ #define STATUS1_REG 0x0 -#define DATA_AVAIL_BIT 0x1 // data is available in fifo -#define OVERRUN_BIT 0x2 // overrun has occurred -#define OVERFLOW_BIT 0x4 // fifo overflow -#define TIMER_BIT 0x8 // timer interrupt has occured -#define DMATC_BIT 0x10 // dma terminal count has occured -#define EXT_TRIG_BIT 0x40 // external trigger has occured -#define STATUS2_REG 0x1d // 1200 boards only -#define EEPROM_OUT_BIT 0x1 // programmable eeprom serial output -#define A1_TC_BIT 0x2 // counter A1 terminal count -#define FNHF_BIT 0x4 // fifo not half full +#define DATA_AVAIL_BIT 0x1 /* data is available in fifo */ +#define OVERRUN_BIT 0x2 /* overrun has occurred */ +#define OVERFLOW_BIT 0x4 /* fifo overflow */ +#define TIMER_BIT 0x8 /* timer interrupt has occured */ +#define DMATC_BIT 0x10 /* dma terminal count has occured */ +#define EXT_TRIG_BIT 0x40 /* external trigger has occured */ +#define STATUS2_REG 0x1d /* 1200 boards only */ +#define EEPROM_OUT_BIT 0x1 /* programmable eeprom serial output */ +#define A1_TC_BIT 0x2 /* counter A1 terminal count */ +#define FNHF_BIT 0x4 /* fifo not half full */ #define ADC_FIFO_REG 0xa #define DIO_BASE_REG 0x10 #define COUNTER_A_BASE_REG 0x14 #define COUNTER_A_CONTROL_REG (COUNTER_A_BASE_REG + 0x3) -#define INIT_A0_BITS 0x14 // check modes put conversion pacer output in harmless state (a0 mode 2) -#define INIT_A1_BITS 0x70 // put hardware conversion counter output in harmless state (a1 mode 0) +#define INIT_A0_BITS 0x14 /* check modes put conversion pacer output in harmless state (a0 mode 2) */ +#define INIT_A1_BITS 0x70 /* put hardware conversion counter output in harmless state (a1 mode 0) */ #define COUNTER_B_BASE_REG 0x18 -static int labpc_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int labpc_cancel(struct comedi_device * dev, struct comedi_subdevice * s); -static irqreturn_t labpc_interrupt(int irq, void *d PT_REGS_ARG); -static int labpc_drain_fifo(struct comedi_device * dev); -static void labpc_drain_dma(struct comedi_device * dev); -static void handle_isa_dma(struct comedi_device * dev); -static void labpc_drain_dregs(struct comedi_device * dev); -static int labpc_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd); -static int labpc_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s); -static int labpc_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int labpc_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int labpc_ao_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int labpc_calib_read_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int labpc_calib_write_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int labpc_eeprom_read_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int labpc_eeprom_write_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); +static int labpc_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int labpc_cancel(struct comedi_device *dev, struct comedi_subdevice *s); +static irqreturn_t labpc_interrupt(int irq, void *d); +static int labpc_drain_fifo(struct comedi_device *dev); +static void labpc_drain_dma(struct comedi_device *dev); +static void handle_isa_dma(struct comedi_device *dev); +static void labpc_drain_dregs(struct comedi_device *dev); +static int labpc_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd); +static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s); +static int labpc_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int labpc_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int labpc_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int labpc_calib_read_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int labpc_calib_write_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int labpc_eeprom_read_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int labpc_eeprom_write_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); static unsigned int labpc_suggest_transfer_size(struct comedi_cmd cmd); -static void labpc_adc_timing(struct comedi_device * dev, struct comedi_cmd * cmd); +static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd); #ifdef CONFIG_COMEDI_PCI static int labpc_find_device(struct comedi_device *dev, int bus, int slot); #endif static int labpc_dio_mem_callback(int dir, int port, int data, unsigned long arg); -static void labpc_serial_out(struct comedi_device * dev, unsigned int value, +static void labpc_serial_out(struct comedi_device *dev, unsigned int value, unsigned int num_bits); -static unsigned int labpc_serial_in(struct comedi_device * dev); -static unsigned int labpc_eeprom_read(struct comedi_device * dev, +static unsigned int labpc_serial_in(struct comedi_device *dev); +static unsigned int labpc_eeprom_read(struct comedi_device *dev, unsigned int address); -static unsigned int labpc_eeprom_read_status(struct comedi_device * dev); -static unsigned int labpc_eeprom_write(struct comedi_device * dev, +static unsigned int labpc_eeprom_read_status(struct comedi_device *dev); +static unsigned int labpc_eeprom_write(struct comedi_device *dev, unsigned int address, unsigned int value); -static void write_caldac(struct comedi_device * dev, unsigned int channel, +static void write_caldac(struct comedi_device *dev, unsigned int channel, unsigned int value); enum scan_mode { @@ -212,9 +213,9 @@ enum scan_mode { MODE_MULT_CHAN_DOWN, }; -//analog input ranges +/* analog input ranges */ #define NUM_LABPC_PLUS_AI_RANGES 16 -// indicates unipolar ranges +/* indicates unipolar ranges */ static const int labpc_plus_is_unipolar[NUM_LABPC_PLUS_AI_RANGES] = { 0, 0, @@ -234,7 +235,7 @@ static const int labpc_plus_is_unipolar[NUM_LABPC_PLUS_AI_RANGES] = { 1, }; -// map range index to gain bits +/* map range index to gain bits */ static const int labpc_plus_ai_gain_bits[NUM_LABPC_PLUS_AI_RANGES] = { 0x00, 0x10, @@ -276,7 +277,7 @@ static const struct comedi_lrange range_labpc_plus_ai = { }; #define NUM_LABPC_1200_AI_RANGES 14 -// indicates unipolar ranges +/* indicates unipolar ranges */ const int labpc_1200_is_unipolar[NUM_LABPC_1200_AI_RANGES] = { 0, 0, @@ -294,7 +295,7 @@ const int labpc_1200_is_unipolar[NUM_LABPC_1200_AI_RANGES] = { 1, }; -// map range index to gain bits +/* map range index to gain bits */ const int labpc_1200_ai_gain_bits[NUM_LABPC_1200_AI_RANGES] = { 0x00, 0x20, @@ -331,7 +332,7 @@ const struct comedi_lrange range_labpc_1200_ai = { } }; -//analog output ranges +/* analog output ranges */ #define AO_RANGE_IS_UNIPOLAR 0x1 static const struct comedi_lrange range_labpc_ao = { 2, @@ -360,58 +361,58 @@ static inline void labpc_writeb(unsigned int byte, unsigned long address) writeb(byte, (void *)address); } -static const labpc_board labpc_boards[] = { +static const struct labpc_board_struct labpc_boards[] = { { - name: "lab-pc-1200", - ai_speed:10000, - bustype: isa_bustype, - register_layout:labpc_1200_layout, - has_ao: 1, - ai_range_table:&range_labpc_1200_ai, - ai_range_code:labpc_1200_ai_gain_bits, - ai_range_is_unipolar:labpc_1200_is_unipolar, - ai_scan_up:1, - memory_mapped_io:0, + .name = "lab-pc-1200", + .ai_speed = 10000, + .bustype = isa_bustype, + .register_layout = labpc_1200_layout, + .has_ao = 1, + .ai_range_table = &range_labpc_1200_ai, + .ai_range_code = labpc_1200_ai_gain_bits, + .ai_range_is_unipolar = labpc_1200_is_unipolar, + .ai_scan_up = 1, + .memory_mapped_io = 0, }, { - name: "lab-pc-1200ai", - ai_speed:10000, - bustype: isa_bustype, - register_layout:labpc_1200_layout, - has_ao: 0, - ai_range_table:&range_labpc_1200_ai, - ai_range_code:labpc_1200_ai_gain_bits, - ai_range_is_unipolar:labpc_1200_is_unipolar, - ai_scan_up:1, - memory_mapped_io:0, + .name = "lab-pc-1200ai", + .ai_speed = 10000, + .bustype = isa_bustype, + .register_layout = labpc_1200_layout, + .has_ao = 0, + .ai_range_table = &range_labpc_1200_ai, + .ai_range_code = labpc_1200_ai_gain_bits, + .ai_range_is_unipolar = labpc_1200_is_unipolar, + .ai_scan_up = 1, + .memory_mapped_io = 0, }, { - name: "lab-pc+", - ai_speed:12000, - bustype: isa_bustype, - register_layout:labpc_plus_layout, - has_ao: 1, - ai_range_table:&range_labpc_plus_ai, - ai_range_code:labpc_plus_ai_gain_bits, - ai_range_is_unipolar:labpc_plus_is_unipolar, - ai_scan_up:0, - memory_mapped_io:0, + .name = "lab-pc+", + .ai_speed = 12000, + .bustype = isa_bustype, + .register_layout = labpc_plus_layout, + .has_ao = 1, + .ai_range_table = &range_labpc_plus_ai, + .ai_range_code = labpc_plus_ai_gain_bits, + .ai_range_is_unipolar = labpc_plus_is_unipolar, + .ai_scan_up = 0, + .memory_mapped_io = 0, }, #ifdef CONFIG_COMEDI_PCI { - name: "pci-1200", - device_id:0x161, - ai_speed:10000, - bustype: pci_bustype, - register_layout:labpc_1200_layout, - has_ao: 1, - ai_range_table:&range_labpc_1200_ai, - ai_range_code:labpc_1200_ai_gain_bits, - ai_range_is_unipolar:labpc_1200_is_unipolar, - ai_scan_up:1, - memory_mapped_io:1, + .name = "pci-1200", + .device_id = 0x161, + .ai_speed = 10000, + .bustype = pci_bustype, + .register_layout = labpc_1200_layout, + .has_ao = 1, + .ai_range_table = &range_labpc_1200_ai, + .ai_range_code = labpc_1200_ai_gain_bits, + .ai_range_is_unipolar = labpc_1200_is_unipolar, + .ai_scan_up = 1, + .memory_mapped_io = 1, }, - // dummy entry so pci board works when comedi_config is passed driver name + /* dummy entry so pci board works when comedi_config is passed driver name */ { .name = DRV_NAME, .bustype = pci_bustype, @@ -422,21 +423,21 @@ static const labpc_board labpc_boards[] = { /* * Useful for shorthand access to the particular board structure */ -#define thisboard ((labpc_board *)dev->board_ptr) +#define thisboard ((struct labpc_board_struct *)dev->board_ptr) -static const int dma_buffer_size = 0xff00; // size in bytes of dma buffer -static const int sample_size = 2; // 2 bytes per sample +static const int dma_buffer_size = 0xff00; /* size in bytes of dma buffer */ +static const int sample_size = 2; /* 2 bytes per sample */ -#define devpriv ((labpc_private *)dev->private) +#define devpriv ((struct labpc_private *)dev->private) static struct comedi_driver driver_labpc = { .driver_name = DRV_NAME, .module = THIS_MODULE, .attach = labpc_attach, .detach = labpc_common_detach, - .num_names = sizeof(labpc_boards) / sizeof(labpc_board), + .num_names = ARRAY_SIZE(labpc_boards), .board_name = &labpc_boards[0].name, - .offset = sizeof(labpc_board), + .offset = sizeof(struct labpc_board_struct), }; #ifdef CONFIG_COMEDI_PCI @@ -448,7 +449,7 @@ static DEFINE_PCI_DEVICE_TABLE(labpc_pci_table) = { MODULE_DEVICE_TABLE(pci, labpc_pci_table); #endif /* CONFIG_COMEDI_PCI */ -static inline int labpc_counter_load(struct comedi_device * dev, +static inline int labpc_counter_load(struct comedi_device *dev, unsigned long base_address, unsigned int counter_number, unsigned int count, unsigned int mode) { @@ -459,7 +460,7 @@ static inline int labpc_counter_load(struct comedi_device * dev, return i8254_load(base_address, 0, counter_number, count, mode); } -int labpc_common_attach(struct comedi_device * dev, unsigned long iobase, +int labpc_common_attach(struct comedi_device *dev, unsigned long iobase, unsigned int irq, unsigned int dma_chan) { struct comedi_subdevice *s; @@ -481,7 +482,7 @@ int labpc_common_attach(struct comedi_device * dev, unsigned long iobase, printk("io base address is zero!\n"); return -EINVAL; } - // request io regions for isa boards + /* request io regions for isa boards */ if (thisboard->bustype == isa_bustype) { /* check if io addresses are available */ if (!request_region(iobase, LABPC_SIZE, @@ -499,7 +500,7 @@ int labpc_common_attach(struct comedi_device * dev, unsigned long iobase, devpriv->read_byte = labpc_inb; devpriv->write_byte = labpc_outb; } - // initialize board's command registers + /* initialize board's command registers */ devpriv->write_byte(devpriv->command1_bits, dev->iobase + COMMAND1_REG); devpriv->write_byte(devpriv->command2_bits, dev->iobase + COMMAND2_REG); devpriv->write_byte(devpriv->command3_bits, dev->iobase + COMMAND3_REG); @@ -516,7 +517,7 @@ int labpc_common_attach(struct comedi_device * dev, unsigned long iobase, isr_flags = 0; if (thisboard->bustype == pci_bustype) isr_flags |= IRQF_SHARED; - if (comedi_request_irq(irq, labpc_interrupt, isr_flags, + if (request_irq(irq, labpc_interrupt, isr_flags, driver_labpc.driver_name, dev)) { printk("unable to allocate irq %u\n", irq); return -EINVAL; @@ -524,12 +525,12 @@ int labpc_common_attach(struct comedi_device * dev, unsigned long iobase, } dev->irq = irq; - // grab dma channel + /* grab dma channel */ if (dma_chan > 3) { printk(" invalid dma channel %u\n", dma_chan); return -EINVAL; } else if (dma_chan) { - // allocate dma buffer + /* allocate dma buffer */ devpriv->dma_buffer = kmalloc(dma_buffer_size, GFP_KERNEL | GFP_DMA); if (devpriv->dma_buffer == NULL) { @@ -562,7 +563,7 @@ int labpc_common_attach(struct comedi_device * dev, unsigned long iobase, SDF_CMD_READ; s->n_chan = 8; s->len_chanlist = 8; - s->maxdata = (1 << 12) - 1; // 12 bit resolution + s->maxdata = (1 << 12) - 1; /* 12 bit resolution */ s->range_table = thisboard->ai_range_table; s->do_cmd = labpc_ai_cmd; s->do_cmdtest = labpc_ai_cmdtest; @@ -577,7 +578,7 @@ int labpc_common_attach(struct comedi_device * dev, unsigned long iobase, s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_GROUND; s->n_chan = NUM_AO_CHAN; - s->maxdata = (1 << 12) - 1; // 12 bit resolution + s->maxdata = (1 << 12) - 1; /* 12 bit resolution */ s->range_table = &range_labpc_ao; s->insn_read = labpc_ao_rinsn; s->insn_write = labpc_ao_winsn; @@ -595,14 +596,14 @@ int labpc_common_attach(struct comedi_device * dev, unsigned long iobase, /* 8255 dio */ s = dev->subdevices + 2; - // if board uses io memory we have to give a custom callback function to the 8255 driver + /* if board uses io memory we have to give a custom callback function to the 8255 driver */ if (thisboard->memory_mapped_io) subdev_8255_init(dev, s, labpc_dio_mem_callback, (unsigned long)(dev->iobase + DIO_BASE_REG)); else subdev_8255_init(dev, s, NULL, dev->iobase + DIO_BASE_REG); - // calibration subdevices for boards that have one + /* calibration subdevices for boards that have one */ s = dev->subdevices + 3; if (thisboard->register_layout == labpc_1200_layout) { s->type = COMEDI_SUBD_CALIB; @@ -643,7 +644,7 @@ int labpc_common_attach(struct comedi_device * dev, unsigned long iobase, return 0; } -static int labpc_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int labpc_attach(struct comedi_device *dev, struct comedi_devconfig *it) { unsigned long iobase = 0; unsigned int irq = 0; @@ -653,10 +654,10 @@ static int labpc_attach(struct comedi_device * dev, struct comedi_devconfig * it #endif /* allocate and initialize dev->private */ - if (alloc_private(dev, sizeof(labpc_private)) < 0) + if (alloc_private(dev, sizeof(struct labpc_private)) < 0) return -ENOMEM; - // get base address, irq etc. based on bustype + /* get base address, irq etc. based on bustype */ switch (thisboard->bustype) { case isa_bustype: iobase = it->options[0]; @@ -692,7 +693,7 @@ static int labpc_attach(struct comedi_device * dev, struct comedi_devconfig * it return labpc_common_attach(dev, iobase, irq, dma_chan); } -// adapted from ni_pcimio for finding mite based boards (pc-1200) +/* adapted from ni_pcimio for finding mite based boards (pc-1200) */ #ifdef CONFIG_COMEDI_PCI static int labpc_find_device(struct comedi_device *dev, int bus, int slot) { @@ -701,7 +702,7 @@ static int labpc_find_device(struct comedi_device *dev, int bus, int slot) for (mite = mite_devices; mite; mite = mite->next) { if (mite->used) continue; - // if bus/slot are specified then make sure we have the right bus/slot + /* if bus/slot are specified then make sure we have the right bus/slot */ if (bus || slot) { if (bus != mite->pcidev->bus->number || slot != PCI_SLOT(mite->pcidev->devfn)) @@ -712,7 +713,7 @@ static int labpc_find_device(struct comedi_device *dev, int bus, int slot) continue; if (mite_device_id(mite) == labpc_boards[i].device_id) { devpriv->mite = mite; - // fixup board pointer, in case we were using the dummy "ni_labpc" entry + /* fixup board pointer, in case we were using the dummy "ni_labpc" entry */ dev->board_ptr = &labpc_boards[i]; return 0; } @@ -724,7 +725,7 @@ static int labpc_find_device(struct comedi_device *dev, int bus, int slot) } #endif -int labpc_common_detach(struct comedi_device * dev) +int labpc_common_detach(struct comedi_device *dev) { printk("comedi%d: ni_labpc: detach\n", dev->minor); @@ -737,7 +738,7 @@ int labpc_common_detach(struct comedi_device * dev) if (devpriv->dma_chan) free_dma(devpriv->dma_chan); if (dev->irq) - comedi_free_irq(dev->irq, dev); + free_irq(dev->irq, dev); if (thisboard->bustype == isa_bustype && dev->iobase) release_region(dev->iobase, LABPC_SIZE); #ifdef CONFIG_COMEDI_PCI @@ -748,21 +749,21 @@ int labpc_common_detach(struct comedi_device * dev) return 0; }; -static void labpc_clear_adc_fifo(const struct comedi_device * dev) +static void labpc_clear_adc_fifo(const struct comedi_device *dev) { devpriv->write_byte(0x1, dev->iobase + ADC_CLEAR_REG); devpriv->read_byte(dev->iobase + ADC_FIFO_REG); devpriv->read_byte(dev->iobase + ADC_FIFO_REG); } -static int labpc_cancel(struct comedi_device * dev, struct comedi_subdevice * s) +static int labpc_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { unsigned long flags; - comedi_spin_lock_irqsave(&dev->spinlock, flags); + spin_lock_irqsave(&dev->spinlock, flags); devpriv->command2_bits &= ~SWTRIG_BIT & ~HWTRIG_BIT & ~PRETRIG_BIT; devpriv->write_byte(devpriv->command2_bits, dev->iobase + COMMAND2_REG); - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); devpriv->command3_bits = 0; devpriv->write_byte(devpriv->command3_bits, dev->iobase + COMMAND3_REG); @@ -770,7 +771,7 @@ static int labpc_cancel(struct comedi_device * dev, struct comedi_subdevice * s) return 0; } -static enum scan_mode labpc_ai_scan_mode(const struct comedi_cmd * cmd) +static enum scan_mode labpc_ai_scan_mode(const struct comedi_cmd *cmd) { if (cmd->chanlist_len == 1) return MODE_SINGLE_CHAN; @@ -788,13 +789,13 @@ static enum scan_mode labpc_ai_scan_mode(const struct comedi_cmd * cmd) if (CR_CHAN(cmd->chanlist[0]) > CR_CHAN(cmd->chanlist[1])) return MODE_MULT_CHAN_DOWN; - rt_printk("ni_labpc: bug! this should never happen\n"); + printk("ni_labpc: bug! this should never happen\n"); return 0; } -static int labpc_ai_chanlist_invalid(const struct comedi_device * dev, - const struct comedi_cmd * cmd) +static int labpc_ai_chanlist_invalid(const struct comedi_device *dev, + const struct comedi_cmd *cmd) { int mode, channel, range, aref, i; @@ -844,7 +845,7 @@ static int labpc_ai_chanlist_invalid(const struct comedi_device * dev, } break; default: - rt_printk("ni_labpc: bug! in chanlist check\n"); + printk("ni_labpc: bug! in chanlist check\n"); return 1; break; } @@ -865,7 +866,7 @@ static int labpc_ai_chanlist_invalid(const struct comedi_device * dev, return 0; } -static int labpc_use_continuous_mode(const struct comedi_cmd * cmd) +static int labpc_use_continuous_mode(const struct comedi_cmd *cmd) { if (labpc_ai_scan_mode(cmd) == MODE_SINGLE_CHAN) return 1; @@ -876,7 +877,7 @@ static int labpc_use_continuous_mode(const struct comedi_cmd * cmd) return 0; } -static unsigned int labpc_ai_convert_period(const struct comedi_cmd * cmd) +static unsigned int labpc_ai_convert_period(const struct comedi_cmd *cmd) { if (cmd->convert_src != TRIG_TIMER) return 0; @@ -888,7 +889,7 @@ static unsigned int labpc_ai_convert_period(const struct comedi_cmd * cmd) return cmd->convert_arg; } -static void labpc_set_ai_convert_period(struct comedi_cmd * cmd, unsigned int ns) +static void labpc_set_ai_convert_period(struct comedi_cmd *cmd, unsigned int ns) { if (cmd->convert_src != TRIG_TIMER) return; @@ -902,7 +903,7 @@ static void labpc_set_ai_convert_period(struct comedi_cmd * cmd, unsigned int ns cmd->convert_arg = ns; } -static unsigned int labpc_ai_scan_period(const struct comedi_cmd * cmd) +static unsigned int labpc_ai_scan_period(const struct comedi_cmd *cmd) { if (cmd->scan_begin_src != TRIG_TIMER) return 0; @@ -914,7 +915,7 @@ static unsigned int labpc_ai_scan_period(const struct comedi_cmd * cmd) return cmd->scan_begin_arg; } -static void labpc_set_ai_scan_period(struct comedi_cmd * cmd, unsigned int ns) +static void labpc_set_ai_scan_period(struct comedi_cmd *cmd, unsigned int ns) { if (cmd->scan_begin_src != TRIG_TIMER) return; @@ -926,8 +927,8 @@ static void labpc_set_ai_scan_period(struct comedi_cmd * cmd, unsigned int ns) cmd->scan_begin_arg = ns; } -static int labpc_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd) +static int labpc_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd) { int err = 0; int tmp, tmp2; @@ -980,7 +981,7 @@ static int labpc_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice cmd->stop_src != TRIG_EXT && cmd->stop_src != TRIG_NONE) err++; - // can't have external stop and start triggers at once + /* can't have external stop and start triggers at once */ if (cmd->start_src == TRIG_EXT && cmd->stop_src == TRIG_EXT) err++; @@ -1008,7 +1009,7 @@ static int labpc_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice err++; } } - // make sure scan timing is not too fast + /* make sure scan timing is not too fast */ if (cmd->scan_begin_src == TRIG_TIMER) { if (cmd->convert_src == TRIG_TIMER && cmd->scan_begin_arg < @@ -1024,7 +1025,7 @@ static int labpc_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice err++; } } - // stop source + /* stop source */ switch (cmd->stop_src) { case TRIG_COUNT: if (!cmd->stop_arg) { @@ -1038,7 +1039,7 @@ static int labpc_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice err++; } break; - // TRIG_EXT doesn't care since it doesn't trigger off a numbered channel + /* TRIG_EXT doesn't care since it doesn't trigger off a numbered channel */ default: break; } @@ -1063,7 +1064,7 @@ static int labpc_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice return 0; } -static int labpc_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s) +static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { int channel, range, aref; unsigned long irq_flags; @@ -1081,77 +1082,77 @@ static int labpc_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s) range = CR_RANGE(cmd->chanlist[0]); aref = CR_AREF(cmd->chanlist[0]); - // make sure board is disabled before setting up aquisition - comedi_spin_lock_irqsave(&dev->spinlock, flags); + /* make sure board is disabled before setting up aquisition */ + spin_lock_irqsave(&dev->spinlock, flags); devpriv->command2_bits &= ~SWTRIG_BIT & ~HWTRIG_BIT & ~PRETRIG_BIT; devpriv->write_byte(devpriv->command2_bits, dev->iobase + COMMAND2_REG); - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); devpriv->command3_bits = 0; devpriv->write_byte(devpriv->command3_bits, dev->iobase + COMMAND3_REG); - // initialize software conversion count + /* initialize software conversion count */ if (cmd->stop_src == TRIG_COUNT) { devpriv->count = cmd->stop_arg * cmd->chanlist_len; } - // setup hardware conversion counter + /* setup hardware conversion counter */ if (cmd->stop_src == TRIG_EXT) { - // load counter a1 with count of 3 (pc+ manual says this is minimum allowed) using mode 0 + /* load counter a1 with count of 3 (pc+ manual says this is minimum allowed) using mode 0 */ ret = labpc_counter_load(dev, dev->iobase + COUNTER_A_BASE_REG, 1, 3, 0); if (ret < 0) { comedi_error(dev, "error loading counter a1"); return -1; } - } else // otherwise, just put a1 in mode 0 with no count to set its output low + } else /* otherwise, just put a1 in mode 0 with no count to set its output low */ devpriv->write_byte(INIT_A1_BITS, dev->iobase + COUNTER_A_CONTROL_REG); - // figure out what method we will use to transfer data - if (devpriv->dma_chan && // need a dma channel allocated - // dma unsafe at RT priority, and too much setup time for TRIG_WAKE_EOS for + /* figure out what method we will use to transfer data */ + if (devpriv->dma_chan && /* need a dma channel allocated */ + /* dma unsafe at RT priority, and too much setup time for TRIG_WAKE_EOS for */ (cmd->flags & (TRIG_WAKE_EOS | TRIG_RT)) == 0 && - // only available on the isa boards + /* only available on the isa boards */ thisboard->bustype == isa_bustype) { xfer = isa_dma_transfer; - } else if (thisboard->register_layout == labpc_1200_layout && // pc-plus has no fifo-half full interrupt - // wake-end-of-scan should interrupt on fifo not empty + } else if (thisboard->register_layout == labpc_1200_layout && /* pc-plus has no fifo-half full interrupt */ + /* wake-end-of-scan should interrupt on fifo not empty */ (cmd->flags & TRIG_WAKE_EOS) == 0 && - // make sure we are taking more than just a few points + /* make sure we are taking more than just a few points */ (cmd->stop_src != TRIG_COUNT || devpriv->count > 256)) { xfer = fifo_half_full_transfer; } else xfer = fifo_not_empty_transfer; devpriv->current_transfer = xfer; - // setup command6 register for 1200 boards + /* setup command6 register for 1200 boards */ if (thisboard->register_layout == labpc_1200_layout) { - // reference inputs to ground or common? + /* reference inputs to ground or common? */ if (aref != AREF_GROUND) devpriv->command6_bits |= ADC_COMMON_BIT; else devpriv->command6_bits &= ~ADC_COMMON_BIT; - // bipolar or unipolar range? + /* bipolar or unipolar range? */ if (thisboard->ai_range_is_unipolar[range]) devpriv->command6_bits |= ADC_UNIP_BIT; else devpriv->command6_bits &= ~ADC_UNIP_BIT; - // interrupt on fifo half full? + /* interrupt on fifo half full? */ if (xfer == fifo_half_full_transfer) devpriv->command6_bits |= ADC_FHF_INTR_EN_BIT; else devpriv->command6_bits &= ~ADC_FHF_INTR_EN_BIT; - // enable interrupt on counter a1 terminal count? + /* enable interrupt on counter a1 terminal count? */ if (cmd->stop_src == TRIG_EXT) devpriv->command6_bits |= A1_INTR_EN_BIT; else devpriv->command6_bits &= ~A1_INTR_EN_BIT; - // are we scanning up or down through channels? + /* are we scanning up or down through channels? */ if (labpc_ai_scan_mode(cmd) == MODE_MULT_CHAN_UP) devpriv->command6_bits |= ADC_SCAN_UP_BIT; else devpriv->command6_bits &= ~ADC_SCAN_UP_BIT; - // write to register + /* write to register */ devpriv->write_byte(devpriv->command6_bits, dev->iobase + COMMAND6_REG); } @@ -1162,23 +1163,23 @@ static int labpc_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s) channel = CR_CHAN(cmd->chanlist[cmd->chanlist_len - 1]); else channel = CR_CHAN(cmd->chanlist[0]); - // munge channel bits for differential / scan disabled mode + /* munge channel bits for differential / scan disabled mode */ if (labpc_ai_scan_mode(cmd) != MODE_SINGLE_CHAN && aref == AREF_DIFF) channel *= 2; devpriv->command1_bits |= ADC_CHAN_BITS(channel); devpriv->command1_bits |= thisboard->ai_range_code[range]; devpriv->write_byte(devpriv->command1_bits, dev->iobase + COMMAND1_REG); - // manual says to set scan enable bit on second pass + /* manual says to set scan enable bit on second pass */ if (labpc_ai_scan_mode(cmd) == MODE_MULT_CHAN_UP || labpc_ai_scan_mode(cmd) == MODE_MULT_CHAN_DOWN) { devpriv->command1_bits |= ADC_SCAN_EN_BIT; /* need a brief delay before enabling scan, or scan list will get screwed when you switch * between scan up to scan down mode - dunno why */ - comedi_udelay(1); + udelay(1); devpriv->write_byte(devpriv->command1_bits, dev->iobase + COMMAND1_REG); } - // setup any external triggering/pacing (command4 register) + /* setup any external triggering/pacing (command4 register) */ devpriv->command4_bits = 0; if (cmd->convert_src != TRIG_EXT) devpriv->command4_bits |= EXT_CONVERT_DISABLE_BIT; @@ -1189,21 +1190,21 @@ static int labpc_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s) if (cmd->scan_begin_src == TRIG_EXT) devpriv->command4_bits |= EXT_SCAN_EN_BIT; } - // single-ended/differential + /* single-ended/differential */ if (aref == AREF_DIFF) devpriv->command4_bits |= ADC_DIFF_BIT; devpriv->write_byte(devpriv->command4_bits, dev->iobase + COMMAND4_REG); devpriv->write_byte(cmd->chanlist_len, dev->iobase + INTERVAL_COUNT_REG); - // load count + /* load count */ devpriv->write_byte(INTERVAL_LOAD_BITS, dev->iobase + INTERVAL_LOAD_REG); if (cmd->convert_src == TRIG_TIMER || cmd->scan_begin_src == TRIG_TIMER) { - // set up pacing + /* set up pacing */ labpc_adc_timing(dev, cmd); - // load counter b0 in mode 3 + /* load counter b0 in mode 3 */ ret = labpc_counter_load(dev, dev->iobase + COUNTER_B_BASE_REG, 0, devpriv->divisor_b0, 3); if (ret < 0) { @@ -1211,9 +1212,9 @@ static int labpc_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s) return -1; } } - // set up conversion pacing + /* set up conversion pacing */ if (labpc_ai_convert_period(cmd)) { - // load counter a0 in mode 2 + /* load counter a0 in mode 2 */ ret = labpc_counter_load(dev, dev->iobase + COUNTER_A_BASE_REG, 0, devpriv->divisor_a0, 2); if (ret < 0) { @@ -1224,9 +1225,9 @@ static int labpc_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s) devpriv->write_byte(INIT_A0_BITS, dev->iobase + COUNTER_A_CONTROL_REG); - // set up scan pacing + /* set up scan pacing */ if (labpc_ai_scan_period(cmd)) { - // load counter b1 in mode 2 + /* load counter b1 in mode 2 */ ret = labpc_counter_load(dev, dev->iobase + COUNTER_B_BASE_REG, 1, devpriv->divisor_b1, 2); if (ret < 0) { @@ -1237,7 +1238,7 @@ static int labpc_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s) labpc_clear_adc_fifo(dev); - // set up dma transfer + /* set up dma transfer */ if (xfer == isa_dma_transfer) { irq_flags = claim_dma_lock(); disable_dma(devpriv->dma_chan); @@ -1246,7 +1247,7 @@ static int labpc_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s) clear_dma_ff(devpriv->dma_chan); set_dma_addr(devpriv->dma_chan, virt_to_bus(devpriv->dma_buffer)); - // set appropriate size of transfer + /* set appropriate size of transfer */ devpriv->dma_transfer_size = labpc_suggest_transfer_size(*cmd); if (cmd->stop_src == TRIG_COUNT && devpriv->count * sample_size < @@ -1257,25 +1258,25 @@ static int labpc_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s) set_dma_count(devpriv->dma_chan, devpriv->dma_transfer_size); enable_dma(devpriv->dma_chan); release_dma_lock(irq_flags); - // enable board's dma + /* enable board's dma */ devpriv->command3_bits |= DMA_EN_BIT | DMATC_INTR_EN_BIT; } else devpriv->command3_bits &= ~DMA_EN_BIT & ~DMATC_INTR_EN_BIT; - // enable error interrupts + /* enable error interrupts */ devpriv->command3_bits |= ERR_INTR_EN_BIT; - // enable fifo not empty interrupt? + /* enable fifo not empty interrupt? */ if (xfer == fifo_not_empty_transfer) devpriv->command3_bits |= ADC_FNE_INTR_EN_BIT; else devpriv->command3_bits &= ~ADC_FNE_INTR_EN_BIT; devpriv->write_byte(devpriv->command3_bits, dev->iobase + COMMAND3_REG); - // startup aquisition + /* startup aquisition */ - // command2 reg - // use 2 cascaded counters for pacing - comedi_spin_lock_irqsave(&dev->spinlock, flags); + /* command2 reg */ + /* use 2 cascaded counters for pacing */ + spin_lock_irqsave(&dev->spinlock, flags); devpriv->command2_bits |= CASCADE_BIT; switch (cmd->start_src) { case TRIG_EXT: @@ -1303,13 +1304,13 @@ static int labpc_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s) return -1; } devpriv->write_byte(devpriv->command2_bits, dev->iobase + COMMAND2_REG); - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); return 0; } /* interrupt service routine */ -static irqreturn_t labpc_interrupt(int irq, void *d PT_REGS_ARG) +static irqreturn_t labpc_interrupt(int irq, void *d) { struct comedi_device *dev = d; struct comedi_subdevice *s = dev->read_subdev; @@ -1325,7 +1326,7 @@ static irqreturn_t labpc_interrupt(int irq, void *d PT_REGS_ARG) cmd = &async->cmd; async->events = 0; - // read board status + /* read board status */ devpriv->status1_bits = devpriv->read_byte(dev->iobase + STATUS1_REG); if (thisboard->register_layout == labpc_1200_layout) devpriv->status2_bits = @@ -1339,7 +1340,7 @@ static irqreturn_t labpc_interrupt(int irq, void *d PT_REGS_ARG) } if (devpriv->status1_bits & OVERRUN_BIT) { - // clear error interrupt + /* clear error interrupt */ devpriv->write_byte(0x1, dev->iobase + ADC_CLEAR_REG); async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; comedi_event(dev, s); @@ -1348,7 +1349,7 @@ static irqreturn_t labpc_interrupt(int irq, void *d PT_REGS_ARG) } if (devpriv->current_transfer == isa_dma_transfer) { - // if a dma terminal count of external stop trigger has occurred + /* if a dma terminal count of external stop trigger has occurred */ if (devpriv->status1_bits & DMATC_BIT || (thisboard->register_layout == labpc_1200_layout && devpriv->status2_bits & A1_TC_BIT)) { @@ -1359,19 +1360,19 @@ static irqreturn_t labpc_interrupt(int irq, void *d PT_REGS_ARG) if (devpriv->status1_bits & TIMER_BIT) { comedi_error(dev, "handled timer interrupt?"); - // clear it + /* clear it */ devpriv->write_byte(0x1, dev->iobase + TIMER_CLEAR_REG); } if (devpriv->status1_bits & OVERFLOW_BIT) { - // clear error interrupt + /* clear error interrupt */ devpriv->write_byte(0x1, dev->iobase + ADC_CLEAR_REG); async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; comedi_event(dev, s); comedi_error(dev, "overflow"); return IRQ_HANDLED; } - // handle external stop trigger + /* handle external stop trigger */ if (cmd->stop_src == TRIG_EXT) { if (devpriv->status2_bits & A1_TC_BIT) { labpc_drain_dregs(dev); @@ -1392,8 +1393,8 @@ static irqreturn_t labpc_interrupt(int irq, void *d PT_REGS_ARG) return IRQ_HANDLED; } -// read all available samples from ai fifo -static int labpc_drain_fifo(struct comedi_device * dev) +/* read all available samples from ai fifo */ +static int labpc_drain_fifo(struct comedi_device *dev) { unsigned int lsb, msb; short data; @@ -1405,7 +1406,7 @@ static int labpc_drain_fifo(struct comedi_device * dev) for (i = 0; (devpriv->status1_bits & DATA_AVAIL_BIT) && i < timeout; i++) { - // quit if we have all the data we want + /* quit if we have all the data we want */ if (async->cmd.stop_src == TRIG_COUNT) { if (devpriv->count == 0) break; @@ -1427,7 +1428,7 @@ static int labpc_drain_fifo(struct comedi_device * dev) return 0; } -static void labpc_drain_dma(struct comedi_device * dev) +static void labpc_drain_dma(struct comedi_device *dev) { struct comedi_subdevice *s = dev->read_subdev; struct comedi_async *async = s->async; @@ -1444,7 +1445,7 @@ static void labpc_drain_dma(struct comedi_device * dev) * count and address get set correctly */ clear_dma_ff(devpriv->dma_chan); - // figure out how many points to read + /* figure out how many points to read */ max_points = devpriv->dma_transfer_size / sample_size; /* residue is the number of points left to be done on the dma * transfer. It should always be zero at this point unless @@ -1455,7 +1456,7 @@ static void labpc_drain_dma(struct comedi_device * dev) if (devpriv->count < num_points && async->cmd.stop_src == TRIG_COUNT) num_points = devpriv->count; - // figure out how many points will be stored next time + /* figure out how many points will be stored next time */ leftover = 0; if (async->cmd.stop_src != TRIG_COUNT) { leftover = devpriv->dma_transfer_size / sample_size; @@ -1472,7 +1473,7 @@ static void labpc_drain_dma(struct comedi_device * dev) if (async->cmd.stop_src == TRIG_COUNT) devpriv->count -= num_points; - // set address and count for next transfer + /* set address and count for next transfer */ set_dma_addr(devpriv->dma_chan, virt_to_bus(devpriv->dma_buffer)); set_dma_count(devpriv->dma_chan, leftover * sample_size); release_dma_lock(flags); @@ -1480,19 +1481,19 @@ static void labpc_drain_dma(struct comedi_device * dev) async->events |= COMEDI_CB_BLOCK; } -static void handle_isa_dma(struct comedi_device * dev) +static void handle_isa_dma(struct comedi_device *dev) { labpc_drain_dma(dev); enable_dma(devpriv->dma_chan); - // clear dma tc interrupt + /* clear dma tc interrupt */ devpriv->write_byte(0x1, dev->iobase + DMATC_CLEAR_REG); } /* makes sure all data aquired by board is transfered to comedi (used * when aquisition is terminated by stop_src == TRIG_EXT). */ -static void labpc_drain_dregs(struct comedi_device * dev) +static void labpc_drain_dregs(struct comedi_device *dev) { if (devpriv->current_transfer == isa_dma_transfer) labpc_drain_dma(dev); @@ -1500,8 +1501,8 @@ static void labpc_drain_dregs(struct comedi_device * dev) labpc_drain_fifo(dev); } -static int labpc_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int labpc_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i, n; int chan, range; @@ -1509,13 +1510,13 @@ static int labpc_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * int timeout = 1000; unsigned long flags; - // disable timed conversions - comedi_spin_lock_irqsave(&dev->spinlock, flags); + /* disable timed conversions */ + spin_lock_irqsave(&dev->spinlock, flags); devpriv->command2_bits &= ~SWTRIG_BIT & ~HWTRIG_BIT & ~PRETRIG_BIT; devpriv->write_byte(devpriv->command2_bits, dev->iobase + COMMAND2_REG); - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); - // disable interrupt generation and dma + /* disable interrupt generation and dma */ devpriv->command3_bits = 0; devpriv->write_byte(devpriv->command3_bits, dev->iobase + COMMAND3_REG); @@ -1524,41 +1525,41 @@ static int labpc_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * chan = CR_CHAN(insn->chanspec); range = CR_RANGE(insn->chanspec); devpriv->command1_bits |= thisboard->ai_range_code[range]; - // munge channel bits for differential/scan disabled mode + /* munge channel bits for differential/scan disabled mode */ if (CR_AREF(insn->chanspec) == AREF_DIFF) chan *= 2; devpriv->command1_bits |= ADC_CHAN_BITS(chan); devpriv->write_byte(devpriv->command1_bits, dev->iobase + COMMAND1_REG); - // setup command6 register for 1200 boards + /* setup command6 register for 1200 boards */ if (thisboard->register_layout == labpc_1200_layout) { - // reference inputs to ground or common? + /* reference inputs to ground or common? */ if (CR_AREF(insn->chanspec) != AREF_GROUND) devpriv->command6_bits |= ADC_COMMON_BIT; else devpriv->command6_bits &= ~ADC_COMMON_BIT; - // bipolar or unipolar range? + /* bipolar or unipolar range? */ if (thisboard->ai_range_is_unipolar[range]) devpriv->command6_bits |= ADC_UNIP_BIT; else devpriv->command6_bits &= ~ADC_UNIP_BIT; - // don't interrupt on fifo half full + /* don't interrupt on fifo half full */ devpriv->command6_bits &= ~ADC_FHF_INTR_EN_BIT; - // don't enable interrupt on counter a1 terminal count? + /* don't enable interrupt on counter a1 terminal count? */ devpriv->command6_bits &= ~A1_INTR_EN_BIT; - // write to register + /* write to register */ devpriv->write_byte(devpriv->command6_bits, dev->iobase + COMMAND6_REG); } - // setup command4 register + /* setup command4 register */ devpriv->command4_bits = 0; devpriv->command4_bits |= EXT_CONVERT_DISABLE_BIT; - // single-ended/differential + /* single-ended/differential */ if (CR_AREF(insn->chanspec) == AREF_DIFF) devpriv->command4_bits |= ADC_DIFF_BIT; devpriv->write_byte(devpriv->command4_bits, dev->iobase + COMMAND4_REG); - // initialize pacer counter output to make sure it doesn't cause any problems + /* initialize pacer counter output to make sure it doesn't cause any problems */ devpriv->write_byte(INIT_A0_BITS, dev->iobase + COUNTER_A_CONTROL_REG); labpc_clear_adc_fifo(dev); @@ -1571,7 +1572,7 @@ static int labpc_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * if (devpriv->read_byte(dev->iobase + STATUS1_REG) & DATA_AVAIL_BIT) break; - comedi_udelay(1); + udelay(1); } if (i == timeout) { comedi_error(dev, "timeout"); @@ -1585,9 +1586,9 @@ static int labpc_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * return n; } -// analog output insn -static int labpc_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +/* analog output insn */ +static int labpc_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int channel, range; unsigned long flags; @@ -1595,56 +1596,56 @@ static int labpc_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * channel = CR_CHAN(insn->chanspec); - // turn off pacing of analog output channel + /* turn off pacing of analog output channel */ /* note: hardware bug in daqcard-1200 means pacing cannot * be independently enabled/disabled for its the two channels */ - comedi_spin_lock_irqsave(&dev->spinlock, flags); + spin_lock_irqsave(&dev->spinlock, flags); devpriv->command2_bits &= ~DAC_PACED_BIT(channel); devpriv->write_byte(devpriv->command2_bits, dev->iobase + COMMAND2_REG); - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); - // set range + /* set range */ if (thisboard->register_layout == labpc_1200_layout) { range = CR_RANGE(insn->chanspec); if (range & AO_RANGE_IS_UNIPOLAR) devpriv->command6_bits |= DAC_UNIP_BIT(channel); else devpriv->command6_bits &= ~DAC_UNIP_BIT(channel); - // write to register + /* write to register */ devpriv->write_byte(devpriv->command6_bits, dev->iobase + COMMAND6_REG); } - // send data + /* send data */ lsb = data[0] & 0xff; msb = (data[0] >> 8) & 0xff; devpriv->write_byte(lsb, dev->iobase + DAC_LSB_REG(channel)); devpriv->write_byte(msb, dev->iobase + DAC_MSB_REG(channel)); - // remember value for readback + /* remember value for readback */ devpriv->ao_value[channel] = data[0]; return 1; } -// analog output readback insn -static int labpc_ao_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +/* analog output readback insn */ +static int labpc_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { data[0] = devpriv->ao_value[CR_CHAN(insn->chanspec)]; return 1; } -static int labpc_calib_read_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int labpc_calib_read_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { data[0] = devpriv->caldac[CR_CHAN(insn->chanspec)]; return 1; } -static int labpc_calib_write_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int labpc_calib_write_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int channel = CR_CHAN(insn->chanspec); @@ -1652,21 +1653,21 @@ static int labpc_calib_write_insn(struct comedi_device * dev, struct comedi_subd return 1; } -static int labpc_eeprom_read_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int labpc_eeprom_read_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { data[0] = devpriv->eeprom_data[CR_CHAN(insn->chanspec)]; return 1; } -static int labpc_eeprom_write_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int labpc_eeprom_write_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int channel = CR_CHAN(insn->chanspec); int ret; - // only allow writes to user area of eeprom + /* only allow writes to user area of eeprom */ if (channel < 16 || channel > 127) { printk("eeprom writes are only allowed to channels 16 through 127 (the pointer and user areas)"); return -EINVAL; @@ -1679,7 +1680,7 @@ static int labpc_eeprom_write_insn(struct comedi_device * dev, struct comedi_sub return 1; } -// utility function that suggests a dma transfer size in bytes +/* utility function that suggests a dma transfer size in bytes */ static unsigned int labpc_suggest_transfer_size(struct comedi_cmd cmd) { unsigned int size; @@ -1687,14 +1688,14 @@ static unsigned int labpc_suggest_transfer_size(struct comedi_cmd cmd) if (cmd.convert_src == TRIG_TIMER) freq = 1000000000 / cmd.convert_arg; - // return some default value + /* return some default value */ else freq = 0xffffffff; - // make buffer fill in no more than 1/3 second + /* make buffer fill in no more than 1/3 second */ size = (freq / 3) * sample_size; - // set a minimum and maximum size allowed + /* set a minimum and maximum size allowed */ if (size > dma_buffer_size) size = dma_buffer_size - dma_buffer_size % sample_size; else if (size < sample_size) @@ -1703,16 +1704,16 @@ static unsigned int labpc_suggest_transfer_size(struct comedi_cmd cmd) return size; } -// figures out what counter values to use based on command -static void labpc_adc_timing(struct comedi_device * dev, struct comedi_cmd * cmd) +/* figures out what counter values to use based on command */ +static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd) { - const int max_counter_value = 0x10000; // max value for 16 bit counter in mode 2 - const int min_counter_value = 2; // min value for 16 bit counter in mode 2 + const int max_counter_value = 0x10000; /* max value for 16 bit counter in mode 2 */ + const int min_counter_value = 2; /* min value for 16 bit counter in mode 2 */ unsigned int base_period; - // if both convert and scan triggers are TRIG_TIMER, then they both rely on counter b0 + /* if both convert and scan triggers are TRIG_TIMER, then they both rely on counter b0 */ if (labpc_ai_convert_period(cmd) && labpc_ai_scan_period(cmd)) { - // pick the lowest b0 divisor value we can (for maximum input clock speed on convert and scan counters) + /* pick the lowest b0 divisor value we can (for maximum input clock speed on convert and scan counters) */ devpriv->divisor_b0 = (labpc_ai_scan_period(cmd) - 1) / (LABPC_TIMER_BASE * max_counter_value) + 1; if (devpriv->divisor_b0 < min_counter_value) @@ -1722,7 +1723,7 @@ static void labpc_adc_timing(struct comedi_device * dev, struct comedi_cmd * cmd base_period = LABPC_TIMER_BASE * devpriv->divisor_b0; - // set a0 for conversion frequency and b1 for scan frequency + /* set a0 for conversion frequency and b1 for scan frequency */ switch (cmd->flags & TRIG_ROUND_MASK) { default: case TRIG_ROUND_NEAREST: @@ -1748,7 +1749,7 @@ static void labpc_adc_timing(struct comedi_device * dev, struct comedi_cmd * cmd labpc_ai_scan_period(cmd) / base_period; break; } - // make sure a0 and b1 values are acceptable + /* make sure a0 and b1 values are acceptable */ if (devpriv->divisor_a0 < min_counter_value) devpriv->divisor_a0 = min_counter_value; if (devpriv->divisor_a0 > max_counter_value) @@ -1757,12 +1758,12 @@ static void labpc_adc_timing(struct comedi_device * dev, struct comedi_cmd * cmd devpriv->divisor_b1 = min_counter_value; if (devpriv->divisor_b1 > max_counter_value) devpriv->divisor_b1 = max_counter_value; - // write corrected timings to command + /* write corrected timings to command */ labpc_set_ai_convert_period(cmd, base_period * devpriv->divisor_a0); labpc_set_ai_scan_period(cmd, base_period * devpriv->divisor_b1); - // if only one TRIG_TIMER is used, we can employ the generic cascaded timing functions + /* if only one TRIG_TIMER is used, we can employ the generic cascaded timing functions */ } else if (labpc_ai_scan_period(cmd)) { unsigned int scan_period; @@ -1795,51 +1796,51 @@ static int labpc_dio_mem_callback(int dir, int port, int data, } } -// lowlevel write to eeprom/dac -static void labpc_serial_out(struct comedi_device * dev, unsigned int value, +/* lowlevel write to eeprom/dac */ +static void labpc_serial_out(struct comedi_device *dev, unsigned int value, unsigned int value_width) { int i; for (i = 1; i <= value_width; i++) { - // clear serial clock + /* clear serial clock */ devpriv->command5_bits &= ~SCLOCK_BIT; - // send bits most significant bit first + /* send bits most significant bit first */ if (value & (1 << (value_width - i))) devpriv->command5_bits |= SDATA_BIT; else devpriv->command5_bits &= ~SDATA_BIT; - comedi_udelay(1); + udelay(1); devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG); - // set clock to load bit + /* set clock to load bit */ devpriv->command5_bits |= SCLOCK_BIT; - comedi_udelay(1); + udelay(1); devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG); } } -// lowlevel read from eeprom -static unsigned int labpc_serial_in(struct comedi_device * dev) +/* lowlevel read from eeprom */ +static unsigned int labpc_serial_in(struct comedi_device *dev) { unsigned int value = 0; int i; - const int value_width = 8; // number of bits wide values are + const int value_width = 8; /* number of bits wide values are */ for (i = 1; i <= value_width; i++) { - // set serial clock + /* set serial clock */ devpriv->command5_bits |= SCLOCK_BIT; - comedi_udelay(1); + udelay(1); devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG); - // clear clock bit + /* clear clock bit */ devpriv->command5_bits &= ~SCLOCK_BIT; - comedi_udelay(1); + udelay(1); devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG); - // read bits most significant bit first - comedi_udelay(1); + /* read bits most significant bit first */ + udelay(1); devpriv->status2_bits = devpriv->read_byte(dev->iobase + STATUS2_REG); if (devpriv->status2_bits & EEPROM_OUT_BIT) { @@ -1850,46 +1851,46 @@ static unsigned int labpc_serial_in(struct comedi_device * dev) return value; } -static unsigned int labpc_eeprom_read(struct comedi_device * dev, unsigned int address) +static unsigned int labpc_eeprom_read(struct comedi_device *dev, unsigned int address) { unsigned int value; - const int read_instruction = 0x3; // bits to tell eeprom to expect a read - const int write_length = 8; // 8 bit write lengths to eeprom + const int read_instruction = 0x3; /* bits to tell eeprom to expect a read */ + const int write_length = 8; /* 8 bit write lengths to eeprom */ - // enable read/write to eeprom + /* enable read/write to eeprom */ devpriv->command5_bits &= ~EEPROM_EN_BIT; - comedi_udelay(1); + udelay(1); devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG); devpriv->command5_bits |= EEPROM_EN_BIT | EEPROM_WRITE_UNPROTECT_BIT; - comedi_udelay(1); + udelay(1); devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG); - // send read instruction + /* send read instruction */ labpc_serial_out(dev, read_instruction, write_length); - // send 8 bit address to read from + /* send 8 bit address to read from */ labpc_serial_out(dev, address, write_length); - // read result + /* read result */ value = labpc_serial_in(dev); - // disable read/write to eeprom + /* disable read/write to eeprom */ devpriv->command5_bits &= ~EEPROM_EN_BIT & ~EEPROM_WRITE_UNPROTECT_BIT; - comedi_udelay(1); + udelay(1); devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG); return value; } -static unsigned int labpc_eeprom_write(struct comedi_device * dev, +static unsigned int labpc_eeprom_write(struct comedi_device *dev, unsigned int address, unsigned int value) { const int write_enable_instruction = 0x6; const int write_instruction = 0x2; - const int write_length = 8; // 8 bit write lengths to eeprom + const int write_length = 8; /* 8 bit write lengths to eeprom */ const int write_in_progress_bit = 0x1; const int timeout = 10000; int i; - // make sure there isn't already a write in progress + /* make sure there isn't already a write in progress */ for (i = 0; i < timeout; i++) { if ((labpc_eeprom_read_status(dev) & write_in_progress_bit) == 0) @@ -1899,96 +1900,96 @@ static unsigned int labpc_eeprom_write(struct comedi_device * dev, comedi_error(dev, "eeprom write timed out"); return -ETIME; } - // update software copy of eeprom + /* update software copy of eeprom */ devpriv->eeprom_data[address] = value; - // enable read/write to eeprom + /* enable read/write to eeprom */ devpriv->command5_bits &= ~EEPROM_EN_BIT; - comedi_udelay(1); + udelay(1); devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG); devpriv->command5_bits |= EEPROM_EN_BIT | EEPROM_WRITE_UNPROTECT_BIT; - comedi_udelay(1); + udelay(1); devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG); - // send write_enable instruction + /* send write_enable instruction */ labpc_serial_out(dev, write_enable_instruction, write_length); devpriv->command5_bits &= ~EEPROM_EN_BIT; - comedi_udelay(1); + udelay(1); devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG); - // send write instruction + /* send write instruction */ devpriv->command5_bits |= EEPROM_EN_BIT; - comedi_udelay(1); + udelay(1); devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG); labpc_serial_out(dev, write_instruction, write_length); - // send 8 bit address to write to + /* send 8 bit address to write to */ labpc_serial_out(dev, address, write_length); - // write value + /* write value */ labpc_serial_out(dev, value, write_length); devpriv->command5_bits &= ~EEPROM_EN_BIT; - comedi_udelay(1); + udelay(1); devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG); - // disable read/write to eeprom + /* disable read/write to eeprom */ devpriv->command5_bits &= ~EEPROM_EN_BIT & ~EEPROM_WRITE_UNPROTECT_BIT; - comedi_udelay(1); + udelay(1); devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG); return 0; } -static unsigned int labpc_eeprom_read_status(struct comedi_device * dev) +static unsigned int labpc_eeprom_read_status(struct comedi_device *dev) { unsigned int value; const int read_status_instruction = 0x5; - const int write_length = 8; // 8 bit write lengths to eeprom + const int write_length = 8; /* 8 bit write lengths to eeprom */ - // enable read/write to eeprom + /* enable read/write to eeprom */ devpriv->command5_bits &= ~EEPROM_EN_BIT; - comedi_udelay(1); + udelay(1); devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG); devpriv->command5_bits |= EEPROM_EN_BIT | EEPROM_WRITE_UNPROTECT_BIT; - comedi_udelay(1); + udelay(1); devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG); - // send read status instruction + /* send read status instruction */ labpc_serial_out(dev, read_status_instruction, write_length); - // read result + /* read result */ value = labpc_serial_in(dev); - // disable read/write to eeprom + /* disable read/write to eeprom */ devpriv->command5_bits &= ~EEPROM_EN_BIT & ~EEPROM_WRITE_UNPROTECT_BIT; - comedi_udelay(1); + udelay(1); devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG); return value; } -// writes to 8 bit calibration dacs -static void write_caldac(struct comedi_device * dev, unsigned int channel, +/* writes to 8 bit calibration dacs */ +static void write_caldac(struct comedi_device *dev, unsigned int channel, unsigned int value) { if (value == devpriv->caldac[channel]) return; devpriv->caldac[channel] = value; - // clear caldac load bit and make sure we don't write to eeprom + /* clear caldac load bit and make sure we don't write to eeprom */ devpriv->command5_bits &= ~CALDAC_LOAD_BIT & ~EEPROM_EN_BIT & ~EEPROM_WRITE_UNPROTECT_BIT; - comedi_udelay(1); + udelay(1); devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG); - // write 4 bit channel + /* write 4 bit channel */ labpc_serial_out(dev, channel, 4); - // write 8 bit caldac value + /* write 8 bit caldac value */ labpc_serial_out(dev, value, 8); - // set and clear caldac bit to load caldac value + /* set and clear caldac bit to load caldac value */ devpriv->command5_bits |= CALDAC_LOAD_BIT; - comedi_udelay(1); + udelay(1); devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG); devpriv->command5_bits &= ~CALDAC_LOAD_BIT; - comedi_udelay(1); + udelay(1); devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG); } diff --git a/drivers/staging/comedi/drivers/ni_labpc.h b/drivers/staging/comedi/drivers/ni_labpc.h index b44b0d3d02f1..c5d2d212612c 100644 --- a/drivers/staging/comedi/drivers/ni_labpc.h +++ b/drivers/staging/comedi/drivers/ni_labpc.h @@ -24,59 +24,59 @@ #ifndef _NI_LABPC_H #define _NI_LABPC_H -#define EEPROM_SIZE 256 // 256 byte eeprom -#define NUM_AO_CHAN 2 // boards have two analog output channels +#define EEPROM_SIZE 256 /* 256 byte eeprom */ +#define NUM_AO_CHAN 2 /* boards have two analog output channels */ enum labpc_bustype { isa_bustype, pci_bustype, pcmcia_bustype }; enum labpc_register_layout { labpc_plus_layout, labpc_1200_layout }; enum transfer_type { fifo_not_empty_transfer, fifo_half_full_transfer, isa_dma_transfer }; -typedef struct labpc_board_struct { +struct labpc_board_struct { const char *name; - int device_id; // device id for pci and pcmcia boards - int ai_speed; // maximum input speed in nanoseconds - enum labpc_bustype bustype; // ISA/PCI/etc. - enum labpc_register_layout register_layout; // 1200 has extra registers compared to pc+ - int has_ao; // has analog output true/false + int device_id; /* device id for pci and pcmcia boards */ + int ai_speed; /* maximum input speed in nanoseconds */ + enum labpc_bustype bustype; /* ISA/PCI/etc. */ + enum labpc_register_layout register_layout; /* 1200 has extra registers compared to pc+ */ + int has_ao; /* has analog output true/false */ const struct comedi_lrange *ai_range_table; const int *ai_range_code; const int *ai_range_is_unipolar; - unsigned ai_scan_up:1; // board can auto scan up in ai channels, not just down + unsigned ai_scan_up:1; /* board can auto scan up in ai channels, not just down */ unsigned memory_mapped_io:1; /* uses memory mapped io instead of ioports */ -} labpc_board; +}; -typedef struct { - struct mite_struct *mite; // for mite chip on pci-1200 +struct labpc_private { + struct mite_struct *mite; /* for mite chip on pci-1200 */ volatile unsigned long long count; /* number of data points left to be taken */ - unsigned int ao_value[NUM_AO_CHAN]; // software copy of analog output values - // software copys of bits written to command registers + unsigned int ao_value[NUM_AO_CHAN]; /* software copy of analog output values */ + /* software copys of bits written to command registers */ volatile unsigned int command1_bits; volatile unsigned int command2_bits; volatile unsigned int command3_bits; volatile unsigned int command4_bits; volatile unsigned int command5_bits; volatile unsigned int command6_bits; - // store last read of board status registers + /* store last read of board status registers */ volatile unsigned int status1_bits; volatile unsigned int status2_bits; unsigned int divisor_a0; /* value to load into board's counter a0 (conversion pacing) for timed conversions */ unsigned int divisor_b0; /* value to load into board's counter b0 (master) for timed conversions */ unsigned int divisor_b1; /* value to load into board's counter b1 (scan pacing) for timed conversions */ - unsigned int dma_chan; // dma channel to use - u16 *dma_buffer; // buffer ai will dma into - unsigned int dma_transfer_size; // transfer size in bytes for current transfer - enum transfer_type current_transfer; // we are using dma/fifo-half-full/etc. - unsigned int eeprom_data[EEPROM_SIZE]; // stores contents of board's eeprom - unsigned int caldac[16]; // stores settings of calibration dacs - // function pointers so we can use inb/outb or readb/writeb as appropriate + unsigned int dma_chan; /* dma channel to use */ + u16 *dma_buffer; /* buffer ai will dma into */ + unsigned int dma_transfer_size; /* transfer size in bytes for current transfer */ + enum transfer_type current_transfer; /* we are using dma/fifo-half-full/etc. */ + unsigned int eeprom_data[EEPROM_SIZE]; /* stores contents of board's eeprom */ + unsigned int caldac[16]; /* stores settings of calibration dacs */ + /* function pointers so we can use inb/outb or readb/writeb as appropriate */ unsigned int (*read_byte) (unsigned long address); void (*write_byte) (unsigned int byte, unsigned long address); -} labpc_private; +}; -int labpc_common_attach(struct comedi_device * dev, unsigned long iobase, +int labpc_common_attach(struct comedi_device *dev, unsigned long iobase, unsigned int irq, unsigned int dma); -int labpc_common_detach(struct comedi_device * dev); +int labpc_common_detach(struct comedi_device *dev); extern const int labpc_1200_is_unipolar[]; extern const int labpc_1200_ai_gain_bits[]; diff --git a/drivers/staging/comedi/drivers/ni_labpc_cs.c b/drivers/staging/comedi/drivers/ni_labpc_cs.c index ac0ce2f58f5f..fb56c03a1b9f 100644 --- a/drivers/staging/comedi/drivers/ni_labpc_cs.c +++ b/drivers/staging/comedi/drivers/ni_labpc_cs.c @@ -60,7 +60,7 @@ NI manuals: */ #undef LABPC_DEBUG -//#define LABPC_DEBUG // enable debugging messages +/* #define LABPC_DEBUG */ /* enable debugging messages */ #include "../comedidev.h" @@ -79,64 +79,64 @@ NI manuals: static struct pcmcia_device *pcmcia_cur_dev = NULL; -static int labpc_attach(struct comedi_device * dev, struct comedi_devconfig * it); +static int labpc_attach(struct comedi_device *dev, struct comedi_devconfig *it); -static const labpc_board labpc_cs_boards[] = { +static const struct labpc_board_struct labpc_cs_boards[] = { { - name: "daqcard-1200", - device_id:0x103, // 0x10b is manufacturer id, 0x103 is device id - ai_speed:10000, - bustype: pcmcia_bustype, - register_layout:labpc_1200_layout, - has_ao: 1, - ai_range_table:&range_labpc_1200_ai, - ai_range_code:labpc_1200_ai_gain_bits, - ai_range_is_unipolar:labpc_1200_is_unipolar, - ai_scan_up:0, - memory_mapped_io:0, + .name = "daqcard-1200", + .device_id = 0x103, /* 0x10b is manufacturer id, 0x103 is device id */ + .ai_speed = 10000, + .bustype = pcmcia_bustype, + .register_layout = labpc_1200_layout, + .has_ao = 1, + .ai_range_table = &range_labpc_1200_ai, + .ai_range_code = labpc_1200_ai_gain_bits, + .ai_range_is_unipolar = labpc_1200_is_unipolar, + .ai_scan_up = 0, + .memory_mapped_io = 0, }, /* duplicate entry, to support using alternate name */ { - name: "ni_labpc_cs", - device_id:0x103, - ai_speed:10000, - bustype: pcmcia_bustype, - register_layout:labpc_1200_layout, - has_ao: 1, - ai_range_table:&range_labpc_1200_ai, - ai_range_code:labpc_1200_ai_gain_bits, - ai_range_is_unipolar:labpc_1200_is_unipolar, - ai_scan_up:0, - memory_mapped_io:0, + .name = "ni_labpc_cs", + .device_id = 0x103, + .ai_speed = 10000, + .bustype = pcmcia_bustype, + .register_layout = labpc_1200_layout, + .has_ao = 1, + .ai_range_table = &range_labpc_1200_ai, + .ai_range_code = labpc_1200_ai_gain_bits, + .ai_range_is_unipolar = labpc_1200_is_unipolar, + .ai_scan_up = 0, + .memory_mapped_io = 0, }, }; /* * Useful for shorthand access to the particular board structure */ -#define thisboard ((const labpc_board *)dev->board_ptr) +#define thisboard ((const struct labpc_board_struct *)dev->board_ptr) static struct comedi_driver driver_labpc_cs = { .driver_name = "ni_labpc_cs", .module = THIS_MODULE, .attach = &labpc_attach, .detach = &labpc_common_detach, - .num_names = sizeof(labpc_cs_boards) / sizeof(labpc_board), + .num_names = ARRAY_SIZE(labpc_cs_boards), .board_name = &labpc_cs_boards[0].name, - .offset = sizeof(labpc_board), + .offset = sizeof(struct labpc_board_struct), }; -static int labpc_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int labpc_attach(struct comedi_device *dev, struct comedi_devconfig *it) { unsigned long iobase = 0; unsigned int irq = 0; struct pcmcia_device *link; /* allocate and initialize dev->private */ - if (alloc_private(dev, sizeof(labpc_private)) < 0) + if (alloc_private(dev, sizeof(struct labpc_private)) < 0) return -ENOMEM; - // get base address, irq etc. based on bustype + /* get base address, irq etc. based on bustype */ switch (thisboard->bustype) { case pcmcia_bustype: link = pcmcia_cur_dev; /* XXX hack */ @@ -213,12 +213,12 @@ static void labpc_cs_detach(struct pcmcia_device *); static const dev_info_t dev_info = "daqcard-1200"; -typedef struct local_info_t { +struct local_info_t { struct pcmcia_device *link; dev_node_t node; int stop; struct bus_operations *bus; -} local_info_t; +}; /*====================================================================== @@ -234,12 +234,12 @@ typedef struct local_info_t { static int labpc_cs_attach(struct pcmcia_device *link) { - local_info_t *local; + struct local_info_t *local; DEBUG(0, "labpc_cs_attach()\n"); /* Allocate space for private device-specific data */ - local = kzalloc(sizeof(local_info_t), GFP_KERNEL); + local = kzalloc(sizeof(struct local_info_t), GFP_KERNEL); if (!local) return -ENOMEM; local->link = link; @@ -287,7 +287,7 @@ static void labpc_cs_detach(struct pcmcia_device *link) detach(). */ if (link->dev_node) { - ((local_info_t *) link->priv)->stop = 1; + ((struct local_info_t *) link->priv)->stop = 1; labpc_release(link); } @@ -307,7 +307,7 @@ static void labpc_cs_detach(struct pcmcia_device *link) static void labpc_config(struct pcmcia_device *link) { - local_info_t *dev = link->priv; + struct local_info_t *dev = link->priv; tuple_t tuple; cisparse_t parse; int last_ret; @@ -327,15 +327,21 @@ static void labpc_config(struct pcmcia_device *link) tuple.TupleData = buf; tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; - if ((last_ret = pcmcia_get_first_tuple(link, &tuple))) { + + last_ret = pcmcia_get_first_tuple(link, &tuple); + if (last_ret) { cs_error(link, GetFirstTuple, last_ret); goto cs_failed; } - if ((last_ret = pcmcia_get_tuple_data(link, &tuple))) { + + last_ret = pcmcia_get_tuple_data(link, &tuple); + if (last_ret) { cs_error(link, GetTupleData, last_ret); goto cs_failed; } - if ((last_ret = pcmcia_parse_tuple(&tuple, &parse))) { + + last_ret = pcmcia_parse_tuple(&tuple, &parse); + if (last_ret) { cs_error(link, ParseTuple, last_ret); goto cs_failed; } @@ -355,7 +361,8 @@ static void labpc_config(struct pcmcia_device *link) will only use the CIS to fill in implementation-defined details. */ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - if ((last_ret = pcmcia_get_first_tuple(link, &tuple))) { + last_ret = pcmcia_get_first_tuple(link, &tuple); + if (last_ret) { cs_error(link, GetFirstTuple, last_ret); goto cs_failed; } @@ -422,7 +429,8 @@ static void labpc_config(struct pcmcia_device *link) break; next_entry: - if ((last_ret = pcmcia_get_next_tuple(link, &tuple))) { + last_ret = pcmcia_get_next_tuple(link, &tuple); + if (last_ret) { cs_error(link, GetNextTuple, last_ret); goto cs_failed; } @@ -433,18 +441,21 @@ static void labpc_config(struct pcmcia_device *link) handler to the interrupt, unless the 'Handler' member of the irq structure is initialized. */ - if (link->conf.Attributes & CONF_ENABLE_IRQ) - if ((last_ret = pcmcia_request_irq(link, &link->irq))) { + if (link->conf.Attributes & CONF_ENABLE_IRQ) { + last_ret = pcmcia_request_irq(link, &link->irq); + if (last_ret) { cs_error(link, RequestIRQ, last_ret); goto cs_failed; } + } /* This actually configures the PCMCIA socket -- setting up the I/O windows and the interrupt mapping, and putting the card and host interface into "Memory and IO" mode. */ - if ((last_ret = pcmcia_request_configuration(link, &link->conf))) { + last_ret = pcmcia_request_configuration(link, &link->conf); + if (last_ret) { cs_error(link, RequestConfiguration, last_ret); goto cs_failed; } @@ -501,7 +512,7 @@ static void labpc_release(struct pcmcia_device *link) static int labpc_cs_suspend(struct pcmcia_device *link) { - local_info_t *local = link->priv; + struct local_info_t *local = link->priv; /* Mark the device as stopped, to block IO until later */ local->stop = 1; @@ -510,7 +521,7 @@ static int labpc_cs_suspend(struct pcmcia_device *link) static int labpc_cs_resume(struct pcmcia_device *link) { - local_info_t *local = link->priv; + struct local_info_t *local = link->priv; local->stop = 0; return 0; diff --git a/drivers/staging/comedi/drivers/ni_mio_common.c b/drivers/staging/comedi/drivers/ni_mio_common.c index 542bd0dcd44d..d727d7533fc8 100644 --- a/drivers/staging/comedi/drivers/ni_mio_common.c +++ b/drivers/staging/comedi/drivers/ni_mio_common.c @@ -57,16 +57,17 @@ fully tested as yet. Terry Barnaby, BEAM Ltd. */ -//#define DEBUG_INTERRUPT -//#define DEBUG_STATUS_A -//#define DEBUG_STATUS_B +/* #define DEBUG_INTERRUPT */ +/* #define DEBUG_STATUS_A */ +/* #define DEBUG_STATUS_B */ +#include #include "8255.h" #include "mite.h" #include "comedi_fc.h" #ifndef MDPRINTK -#define MDPRINTK(format,args...) +#define MDPRINTK(format, args...) #endif /* A timeout count */ @@ -193,49 +194,49 @@ static const struct comedi_lrange *const ni_range_lkup[] = { [ai_gain_6143] = &range_ni_S_ai_6143 }; -static int ni_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int ni_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int ni_cdio_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd); -static int ni_cdio_cmd(struct comedi_device * dev, struct comedi_subdevice * s); -static int ni_cdio_cancel(struct comedi_device * dev, struct comedi_subdevice * s); -static void handle_cdio_interrupt(struct comedi_device * dev); -static int ni_cdo_inttrig(struct comedi_device * dev, struct comedi_subdevice * s, +static int ni_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int ni_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int ni_cdio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd); +static int ni_cdio_cmd(struct comedi_device *dev, struct comedi_subdevice *s); +static int ni_cdio_cancel(struct comedi_device *dev, struct comedi_subdevice *s); +static void handle_cdio_interrupt(struct comedi_device *dev); +static int ni_cdo_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int trignum); -static int ni_serial_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int ni_serial_hw_readwrite8(struct comedi_device * dev, struct comedi_subdevice * s, +static int ni_serial_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int ni_serial_hw_readwrite8(struct comedi_device *dev, struct comedi_subdevice *s, unsigned char data_out, unsigned char *data_in); -static int ni_serial_sw_readwrite8(struct comedi_device * dev, struct comedi_subdevice * s, +static int ni_serial_sw_readwrite8(struct comedi_device *dev, struct comedi_subdevice *s, unsigned char data_out, unsigned char *data_in); -static int ni_calib_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int ni_calib_insn_write(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); +static int ni_calib_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int ni_calib_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); -static int ni_eeprom_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int ni_m_series_eeprom_insn_read(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data); +static int ni_eeprom_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int ni_m_series_eeprom_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -static int ni_pfi_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int ni_pfi_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static unsigned ni_old_get_pfi_routing(struct comedi_device * dev, unsigned chan); +static int ni_pfi_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int ni_pfi_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static unsigned ni_old_get_pfi_routing(struct comedi_device *dev, unsigned chan); -static void ni_rtsi_init(struct comedi_device * dev); -static int ni_rtsi_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int ni_rtsi_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); +static void ni_rtsi_init(struct comedi_device *dev); +static int ni_rtsi_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int ni_rtsi_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); -static void caldac_setup(struct comedi_device * dev, struct comedi_subdevice * s); -static int ni_read_eeprom(struct comedi_device * dev, int addr); +static void caldac_setup(struct comedi_device *dev, struct comedi_subdevice *s); +static int ni_read_eeprom(struct comedi_device *dev, int addr); #ifdef DEBUG_STATUS_A static void ni_mio_print_status_a(int status); @@ -248,58 +249,58 @@ static void ni_mio_print_status_b(int status); #define ni_mio_print_status_b(a) #endif -static int ni_ai_reset(struct comedi_device * dev, struct comedi_subdevice * s); +static int ni_ai_reset(struct comedi_device *dev, struct comedi_subdevice *s); #ifndef PCIDMA -static void ni_handle_fifo_half_full(struct comedi_device * dev); -static int ni_ao_fifo_half_empty(struct comedi_device * dev, struct comedi_subdevice * s); +static void ni_handle_fifo_half_full(struct comedi_device *dev); +static int ni_ao_fifo_half_empty(struct comedi_device *dev, struct comedi_subdevice *s); #endif -static void ni_handle_fifo_dregs(struct comedi_device * dev); -static int ni_ai_inttrig(struct comedi_device * dev, struct comedi_subdevice * s, +static void ni_handle_fifo_dregs(struct comedi_device *dev); +static int ni_ai_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int trignum); -static void ni_load_channelgain_list(struct comedi_device * dev, unsigned int n_chan, +static void ni_load_channelgain_list(struct comedi_device *dev, unsigned int n_chan, unsigned int *list); -static void shutdown_ai_command(struct comedi_device * dev); +static void shutdown_ai_command(struct comedi_device *dev); -static int ni_ao_inttrig(struct comedi_device * dev, struct comedi_subdevice * s, +static int ni_ao_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int trignum); -static int ni_ao_reset(struct comedi_device * dev, struct comedi_subdevice * s); +static int ni_ao_reset(struct comedi_device *dev, struct comedi_subdevice *s); static int ni_8255_callback(int dir, int port, int data, unsigned long arg); -static int ni_gpct_insn_write(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int ni_gpct_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int ni_gpct_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int ni_gpct_cmd(struct comedi_device * dev, struct comedi_subdevice * s); -static int ni_gpct_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd); -static int ni_gpct_cancel(struct comedi_device * dev, struct comedi_subdevice * s); -static void handle_gpct_interrupt(struct comedi_device * dev, +static int ni_gpct_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int ni_gpct_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int ni_gpct_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int ni_gpct_cmd(struct comedi_device *dev, struct comedi_subdevice *s); +static int ni_gpct_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd); +static int ni_gpct_cancel(struct comedi_device *dev, struct comedi_subdevice *s); +static void handle_gpct_interrupt(struct comedi_device *dev, unsigned short counter_index); -static int init_cs5529(struct comedi_device * dev); -static int cs5529_do_conversion(struct comedi_device * dev, unsigned short *data); -static int cs5529_ai_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); +static int init_cs5529(struct comedi_device *dev); +static int cs5529_do_conversion(struct comedi_device *dev, unsigned short *data); +static int cs5529_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); #ifdef NI_CS5529_DEBUG -static unsigned int cs5529_config_read(struct comedi_device * dev, +static unsigned int cs5529_config_read(struct comedi_device *dev, unsigned int reg_select_bits); #endif -static void cs5529_config_write(struct comedi_device * dev, unsigned int value, +static void cs5529_config_write(struct comedi_device *dev, unsigned int value, unsigned int reg_select_bits); -static int ni_m_series_pwm_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int ni_6143_pwm_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); +static int ni_m_series_pwm_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int ni_6143_pwm_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); -static int ni_set_master_clock(struct comedi_device * dev, unsigned source, +static int ni_set_master_clock(struct comedi_device *dev, unsigned source, unsigned period_ns); -static void ack_a_interrupt(struct comedi_device * dev, unsigned short a_status); -static void ack_b_interrupt(struct comedi_device * dev, unsigned short b_status); +static void ack_a_interrupt(struct comedi_device *dev, unsigned short a_status); +static void ack_b_interrupt(struct comedi_device *dev, unsigned short b_status); enum aimodes { AIMODE_NONE = 0, @@ -353,19 +354,19 @@ enum timebase_nanoseconds { static const int num_adc_stages_611x = 3; -static void handle_a_interrupt(struct comedi_device * dev, unsigned short status, +static void handle_a_interrupt(struct comedi_device *dev, unsigned short status, unsigned ai_mite_status); -static void handle_b_interrupt(struct comedi_device * dev, unsigned short status, +static void handle_b_interrupt(struct comedi_device *dev, unsigned short status, unsigned ao_mite_status); -static void get_last_sample_611x(struct comedi_device * dev); -static void get_last_sample_6143(struct comedi_device * dev); +static void get_last_sample_611x(struct comedi_device *dev); +static void get_last_sample_6143(struct comedi_device *dev); -static inline void ni_set_bitfield(struct comedi_device * dev, int reg, +static inline void ni_set_bitfield(struct comedi_device *dev, int reg, unsigned bit_mask, unsigned bit_values) { unsigned long flags; - comedi_spin_lock_irqsave(&devpriv->soft_reg_copy_lock, flags); + spin_lock_irqsave(&devpriv->soft_reg_copy_lock, flags); switch (reg) { case Interrupt_A_Enable_Register: devpriv->int_a_enable_reg &= ~bit_mask; @@ -396,22 +397,22 @@ static inline void ni_set_bitfield(struct comedi_device * dev, int reg, ni_writeb(devpriv->g0_g1_select_reg, G0_G1_Select); break; default: - rt_printk("Warning %s() called with invalid register\n", - __FUNCTION__); - rt_printk("reg is %d\n", reg); + printk("Warning %s() called with invalid register\n", + __func__); + printk("reg is %d\n", reg); break; } mmiowb(); - comedi_spin_unlock_irqrestore(&devpriv->soft_reg_copy_lock, flags); + spin_unlock_irqrestore(&devpriv->soft_reg_copy_lock, flags); } #ifdef PCIDMA -static int ni_ai_drain_dma(struct comedi_device * dev); +static int ni_ai_drain_dma(struct comedi_device *dev); /* DMA channel setup */ -// negative channel means no channel -static inline void ni_set_ai_dma_channel(struct comedi_device * dev, int channel) +/* negative channel means no channel */ +static inline void ni_set_ai_dma_channel(struct comedi_device *dev, int channel) { unsigned bitfield; @@ -425,8 +426,8 @@ static inline void ni_set_ai_dma_channel(struct comedi_device * dev, int channel ni_set_bitfield(dev, AI_AO_Select, AI_DMA_Select_Mask, bitfield); } -// negative channel means no channel -static inline void ni_set_ao_dma_channel(struct comedi_device * dev, int channel) +/* negative channel means no channel */ +static inline void ni_set_ao_dma_channel(struct comedi_device *dev, int channel) { unsigned bitfield; @@ -440,8 +441,8 @@ static inline void ni_set_ao_dma_channel(struct comedi_device * dev, int channel ni_set_bitfield(dev, AI_AO_Select, AO_DMA_Select_Mask, bitfield); } -// negative mite_channel means no channel -static inline void ni_set_gpct_dma_channel(struct comedi_device * dev, +/* negative mite_channel means no channel */ +static inline void ni_set_gpct_dma_channel(struct comedi_device *dev, unsigned gpct_index, int mite_channel) { unsigned bitfield; @@ -455,12 +456,12 @@ static inline void ni_set_gpct_dma_channel(struct comedi_device * dev, bitfield); } -// negative mite_channel means no channel -static inline void ni_set_cdo_dma_channel(struct comedi_device * dev, int mite_channel) +/* negative mite_channel means no channel */ +static inline void ni_set_cdo_dma_channel(struct comedi_device *dev, int mite_channel) { unsigned long flags; - comedi_spin_lock_irqsave(&devpriv->soft_reg_copy_lock, flags); + spin_lock_irqsave(&devpriv->soft_reg_copy_lock, flags); devpriv->cdio_dma_select_reg &= ~CDO_DMA_Select_Mask; if (mite_channel >= 0) { /*XXX just guessing ni_stc_dma_channel_select_bitfield() returns the right bits, @@ -472,19 +473,19 @@ static inline void ni_set_cdo_dma_channel(struct comedi_device * dev, int mite_c } ni_writeb(devpriv->cdio_dma_select_reg, M_Offset_CDIO_DMA_Select); mmiowb(); - comedi_spin_unlock_irqrestore(&devpriv->soft_reg_copy_lock, flags); + spin_unlock_irqrestore(&devpriv->soft_reg_copy_lock, flags); } -static int ni_request_ai_mite_channel(struct comedi_device * dev) +static int ni_request_ai_mite_channel(struct comedi_device *dev) { unsigned long flags; - comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags); + spin_lock_irqsave(&devpriv->mite_channel_lock, flags); BUG_ON(devpriv->ai_mite_chan); devpriv->ai_mite_chan = mite_request_channel(devpriv->mite, devpriv->ai_mite_ring); if (devpriv->ai_mite_chan == NULL) { - comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, + spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); comedi_error(dev, "failed to reserve mite dma channel for analog input."); @@ -492,20 +493,20 @@ static int ni_request_ai_mite_channel(struct comedi_device * dev) } devpriv->ai_mite_chan->dir = COMEDI_INPUT; ni_set_ai_dma_channel(dev, devpriv->ai_mite_chan->channel); - comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); + spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); return 0; } -static int ni_request_ao_mite_channel(struct comedi_device * dev) +static int ni_request_ao_mite_channel(struct comedi_device *dev) { unsigned long flags; - comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags); + spin_lock_irqsave(&devpriv->mite_channel_lock, flags); BUG_ON(devpriv->ao_mite_chan); devpriv->ao_mite_chan = mite_request_channel(devpriv->mite, devpriv->ao_mite_ring); if (devpriv->ao_mite_chan == NULL) { - comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, + spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); comedi_error(dev, "failed to reserve mite dma channel for analog outut."); @@ -513,24 +514,24 @@ static int ni_request_ao_mite_channel(struct comedi_device * dev) } devpriv->ao_mite_chan->dir = COMEDI_OUTPUT; ni_set_ao_dma_channel(dev, devpriv->ao_mite_chan->channel); - comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); + spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); return 0; } -static int ni_request_gpct_mite_channel(struct comedi_device * dev, +static int ni_request_gpct_mite_channel(struct comedi_device *dev, unsigned gpct_index, enum comedi_io_direction direction) { unsigned long flags; struct mite_channel *mite_chan; BUG_ON(gpct_index >= NUM_GPCT); - comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags); + spin_lock_irqsave(&devpriv->mite_channel_lock, flags); BUG_ON(devpriv->counter_dev->counters[gpct_index].mite_chan); mite_chan = mite_request_channel(devpriv->mite, devpriv->gpct_mite_ring[gpct_index]); if (mite_chan == NULL) { - comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, + spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); comedi_error(dev, "failed to reserve mite dma channel for counter."); @@ -540,23 +541,23 @@ static int ni_request_gpct_mite_channel(struct comedi_device * dev, ni_tio_set_mite_channel(&devpriv->counter_dev->counters[gpct_index], mite_chan); ni_set_gpct_dma_channel(dev, gpct_index, mite_chan->channel); - comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); + spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); return 0; } -#endif // PCIDMA +#endif /* PCIDMA */ -static int ni_request_cdo_mite_channel(struct comedi_device * dev) +static int ni_request_cdo_mite_channel(struct comedi_device *dev) { #ifdef PCIDMA unsigned long flags; - comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags); + spin_lock_irqsave(&devpriv->mite_channel_lock, flags); BUG_ON(devpriv->cdo_mite_chan); devpriv->cdo_mite_chan = mite_request_channel(devpriv->mite, devpriv->cdo_mite_ring); if (devpriv->cdo_mite_chan == NULL) { - comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, + spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); comedi_error(dev, "failed to reserve mite dma channel for correlated digital outut."); @@ -564,48 +565,48 @@ static int ni_request_cdo_mite_channel(struct comedi_device * dev) } devpriv->cdo_mite_chan->dir = COMEDI_OUTPUT; ni_set_cdo_dma_channel(dev, devpriv->cdo_mite_chan->channel); - comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); -#endif // PCIDMA + spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); +#endif /* PCIDMA */ return 0; } -static void ni_release_ai_mite_channel(struct comedi_device * dev) +static void ni_release_ai_mite_channel(struct comedi_device *dev) { #ifdef PCIDMA unsigned long flags; - comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags); + spin_lock_irqsave(&devpriv->mite_channel_lock, flags); if (devpriv->ai_mite_chan) { ni_set_ai_dma_channel(dev, -1); mite_release_channel(devpriv->ai_mite_chan); devpriv->ai_mite_chan = NULL; } - comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); -#endif // PCIDMA + spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); +#endif /* PCIDMA */ } -static void ni_release_ao_mite_channel(struct comedi_device * dev) +static void ni_release_ao_mite_channel(struct comedi_device *dev) { #ifdef PCIDMA unsigned long flags; - comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags); + spin_lock_irqsave(&devpriv->mite_channel_lock, flags); if (devpriv->ao_mite_chan) { ni_set_ao_dma_channel(dev, -1); mite_release_channel(devpriv->ao_mite_chan); devpriv->ao_mite_chan = NULL; } - comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); -#endif // PCIDMA + spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); +#endif /* PCIDMA */ } -void ni_release_gpct_mite_channel(struct comedi_device * dev, unsigned gpct_index) +void ni_release_gpct_mite_channel(struct comedi_device *dev, unsigned gpct_index) { #ifdef PCIDMA unsigned long flags; BUG_ON(gpct_index >= NUM_GPCT); - comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags); + spin_lock_irqsave(&devpriv->mite_channel_lock, flags); if (devpriv->counter_dev->counters[gpct_index].mite_chan) { struct mite_channel *mite_chan = devpriv->counter_dev->counters[gpct_index].mite_chan; @@ -615,28 +616,28 @@ void ni_release_gpct_mite_channel(struct comedi_device * dev, unsigned gpct_inde counters[gpct_index], NULL); mite_release_channel(mite_chan); } - comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); -#endif // PCIDMA + spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); +#endif /* PCIDMA */ } -static void ni_release_cdo_mite_channel(struct comedi_device * dev) +static void ni_release_cdo_mite_channel(struct comedi_device *dev) { #ifdef PCIDMA unsigned long flags; - comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags); + spin_lock_irqsave(&devpriv->mite_channel_lock, flags); if (devpriv->cdo_mite_chan) { ni_set_cdo_dma_channel(dev, -1); mite_release_channel(devpriv->cdo_mite_chan); devpriv->cdo_mite_chan = NULL; } - comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); -#endif // PCIDMA + spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); +#endif /* PCIDMA */ } -// e-series boards use the second irq signals to generate dma requests for their counters +/* e-series boards use the second irq signals to generate dma requests for their counters */ #ifdef PCIDMA -static void ni_e_series_enable_second_irq(struct comedi_device * dev, +static void ni_e_series_enable_second_irq(struct comedi_device *dev, unsigned gpct_index, short enable) { if (boardtype.reg_type & ni_reg_m_series_mask) @@ -665,15 +666,15 @@ static void ni_e_series_enable_second_irq(struct comedi_device * dev, break; } } -#endif // PCIDMA +#endif /* PCIDMA */ -static void ni_clear_ai_fifo(struct comedi_device * dev) +static void ni_clear_ai_fifo(struct comedi_device *dev) { if (boardtype.reg_type == ni_reg_6143) { - // Flush the 6143 data FIFO - ni_writel(0x10, AIFIFO_Control_6143); // Flush fifo - ni_writel(0x00, AIFIFO_Control_6143); // Flush fifo - while (ni_readl(AIFIFO_Status_6143) & 0x10) ; // Wait for complete + /* Flush the 6143 data FIFO */ + ni_writel(0x10, AIFIFO_Control_6143); /* Flush fifo */ + ni_writel(0x00, AIFIFO_Control_6143); /* Flush fifo */ + while (ni_readl(AIFIFO_Status_6143) & 0x10) ; /* Wait for complete */ } else { devpriv->stc_writew(dev, 1, ADC_FIFO_Clear); if (boardtype.reg_type == ni_reg_625x) { @@ -693,13 +694,13 @@ static void ni_clear_ai_fifo(struct comedi_device * dev) } } -static void win_out2(struct comedi_device * dev, uint32_t data, int reg) +static void win_out2(struct comedi_device *dev, uint32_t data, int reg) { devpriv->stc_writew(dev, data >> 16, reg); devpriv->stc_writew(dev, data & 0xffff, reg + 1); } -static uint32_t win_in2(struct comedi_device * dev, int reg) +static uint32_t win_in2(struct comedi_device *dev, int reg) { uint32_t bits; bits = devpriv->stc_readw(dev, reg) << 16; @@ -707,36 +708,36 @@ static uint32_t win_in2(struct comedi_device * dev, int reg) return bits; } -#define ao_win_out(data,addr) ni_ao_win_outw(dev,data,addr) -static inline void ni_ao_win_outw(struct comedi_device * dev, uint16_t data, int addr) +#define ao_win_out(data, addr) ni_ao_win_outw(dev, data, addr) +static inline void ni_ao_win_outw(struct comedi_device *dev, uint16_t data, int addr) { unsigned long flags; - comedi_spin_lock_irqsave(&devpriv->window_lock, flags); + spin_lock_irqsave(&devpriv->window_lock, flags); ni_writew(addr, AO_Window_Address_611x); ni_writew(data, AO_Window_Data_611x); - comedi_spin_unlock_irqrestore(&devpriv->window_lock, flags); + spin_unlock_irqrestore(&devpriv->window_lock, flags); } -static inline void ni_ao_win_outl(struct comedi_device * dev, uint32_t data, int addr) +static inline void ni_ao_win_outl(struct comedi_device *dev, uint32_t data, int addr) { unsigned long flags; - comedi_spin_lock_irqsave(&devpriv->window_lock, flags); + spin_lock_irqsave(&devpriv->window_lock, flags); ni_writew(addr, AO_Window_Address_611x); ni_writel(data, AO_Window_Data_611x); - comedi_spin_unlock_irqrestore(&devpriv->window_lock, flags); + spin_unlock_irqrestore(&devpriv->window_lock, flags); } -static inline unsigned short ni_ao_win_inw(struct comedi_device * dev, int addr) +static inline unsigned short ni_ao_win_inw(struct comedi_device *dev, int addr) { unsigned long flags; unsigned short data; - comedi_spin_lock_irqsave(&devpriv->window_lock, flags); + spin_lock_irqsave(&devpriv->window_lock, flags); ni_writew(addr, AO_Window_Address_611x); data = ni_readw(AO_Window_Data_611x); - comedi_spin_unlock_irqrestore(&devpriv->window_lock, flags); + spin_unlock_irqrestore(&devpriv->window_lock, flags); return data; } @@ -750,7 +751,7 @@ static inline unsigned short ni_ao_win_inw(struct comedi_device * dev, int addr) * * value should only be 1 or 0. */ -static inline void ni_set_bits(struct comedi_device * dev, int reg, unsigned bits, +static inline void ni_set_bits(struct comedi_device *dev, int reg, unsigned bits, unsigned value) { unsigned bit_values; @@ -762,7 +763,7 @@ static inline void ni_set_bits(struct comedi_device * dev, int reg, unsigned bit ni_set_bitfield(dev, reg, bits, bit_values); } -static irqreturn_t ni_E_interrupt(int irq, void *d PT_REGS_ARG) +static irqreturn_t ni_E_interrupt(int irq, void *d) { struct comedi_device *dev = d; unsigned short a_status; @@ -776,18 +777,17 @@ static irqreturn_t ni_E_interrupt(int irq, void *d PT_REGS_ARG) if (dev->attached == 0) return IRQ_NONE; - smp_mb(); // make sure dev->attached is checked before handler does anything else. + smp_mb(); /* make sure dev->attached is checked before handler does anything else. */ - // lock to avoid race with comedi_poll - comedi_spin_lock_irqsave(&dev->spinlock, flags); + /* lock to avoid race with comedi_poll */ + spin_lock_irqsave(&dev->spinlock, flags); a_status = devpriv->stc_readw(dev, AI_Status_1_Register); b_status = devpriv->stc_readw(dev, AO_Status_1_Register); #ifdef PCIDMA if (mite) { unsigned long flags_too; - comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, - flags_too); + spin_lock_irqsave(&devpriv->mite_channel_lock, flags_too); if (devpriv->ai_mite_chan) { ai_mite_status = mite_get_status(devpriv->ai_mite_chan); if (ai_mite_status & CHSR_LINKC) @@ -804,8 +804,7 @@ static irqreturn_t ni_E_interrupt(int irq, void *d PT_REGS_ARG) MITE_CHOR(devpriv->ao_mite_chan-> channel)); } - comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, - flags_too); + spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags_too); } #endif ack_a_interrupt(dev, a_status); @@ -818,20 +817,20 @@ static irqreturn_t ni_E_interrupt(int irq, void *d PT_REGS_ARG) handle_gpct_interrupt(dev, 1); handle_cdio_interrupt(dev); - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); return IRQ_HANDLED; } #ifdef PCIDMA -static void ni_sync_ai_dma(struct comedi_device * dev) +static void ni_sync_ai_dma(struct comedi_device *dev) { struct comedi_subdevice *s = dev->subdevices + NI_AI_SUBDEV; unsigned long flags; - comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags); + spin_lock_irqsave(&devpriv->mite_channel_lock, flags); if (devpriv->ai_mite_chan) mite_sync_input_dma(devpriv->ai_mite_chan, s->async); - comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); + spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); } static void mite_handle_b_linkc(struct mite_struct *mite, struct comedi_device * dev) @@ -839,14 +838,14 @@ static void mite_handle_b_linkc(struct mite_struct *mite, struct comedi_device * struct comedi_subdevice *s = dev->subdevices + NI_AO_SUBDEV; unsigned long flags; - comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags); + spin_lock_irqsave(&devpriv->mite_channel_lock, flags); if (devpriv->ao_mite_chan) { mite_sync_output_dma(devpriv->ao_mite_chan, s->async); } - comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); + spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); } -static int ni_ao_wait_for_dma_load(struct comedi_device * dev) +static int ni_ao_wait_for_dma_load(struct comedi_device *dev) { static const int timeout = 10000; int i; @@ -858,7 +857,7 @@ static int ni_ao_wait_for_dma_load(struct comedi_device * dev) break; /* if we poll too often, the pci bus activity seems to slow the dma transfer down */ - comedi_udelay(10); + udelay(10); } if (i == timeout) { comedi_error(dev, "timed out waiting for dma load"); @@ -867,8 +866,8 @@ static int ni_ao_wait_for_dma_load(struct comedi_device * dev) return 0; } -#endif //PCIDMA -static void ni_handle_eos(struct comedi_device * dev, struct comedi_subdevice * s) +#endif /* PCIDMA */ +static void ni_handle_eos(struct comedi_device *dev, struct comedi_subdevice *s) { if (devpriv->aimode == AIMODE_SCAN) { #ifdef PCIDMA @@ -879,7 +878,7 @@ static void ni_handle_eos(struct comedi_device * dev, struct comedi_subdevice * ni_sync_ai_dma(dev); if ((s->async->events & COMEDI_CB_EOS)) break; - comedi_udelay(1); + udelay(1); } #else ni_handle_fifo_dregs(dev); @@ -892,7 +891,7 @@ static void ni_handle_eos(struct comedi_device * dev, struct comedi_subdevice * } } -static void shutdown_ai_command(struct comedi_device * dev) +static void shutdown_ai_command(struct comedi_device *dev) { struct comedi_subdevice *s = dev->subdevices + NI_AI_SUBDEV; @@ -906,7 +905,7 @@ static void shutdown_ai_command(struct comedi_device * dev) s->async->events |= COMEDI_CB_EOA; } -static void ni_event(struct comedi_device * dev, struct comedi_subdevice * s) +static void ni_event(struct comedi_device *dev, struct comedi_subdevice *s) { if (s->async-> events & (COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW | COMEDI_CB_EOA)) @@ -932,7 +931,7 @@ static void ni_event(struct comedi_device * dev, struct comedi_subdevice * s) comedi_event(dev, s); } -static void handle_gpct_interrupt(struct comedi_device * dev, +static void handle_gpct_interrupt(struct comedi_device *dev, unsigned short counter_index) { #ifdef PCIDMA @@ -945,7 +944,7 @@ static void handle_gpct_interrupt(struct comedi_device * dev, #endif } -static void ack_a_interrupt(struct comedi_device * dev, unsigned short a_status) +static void ack_a_interrupt(struct comedi_device *dev, unsigned short a_status) { unsigned short ack = 0; @@ -966,17 +965,17 @@ static void ack_a_interrupt(struct comedi_device * dev, unsigned short a_status) devpriv->stc_writew(dev, ack, Interrupt_A_Ack_Register); } -static void handle_a_interrupt(struct comedi_device * dev, unsigned short status, +static void handle_a_interrupt(struct comedi_device *dev, unsigned short status, unsigned ai_mite_status) { struct comedi_subdevice *s = dev->subdevices + NI_AI_SUBDEV; - //67xx boards don't have ai subdevice, but their gpct0 might generate an a interrupt + /* 67xx boards don't have ai subdevice, but their gpct0 might generate an a interrupt */ if (s->type == COMEDI_SUBD_UNUSED) return; #ifdef DEBUG_INTERRUPT - rt_printk + printk ("ni_mio_common: interrupt: a_status=%04x ai_mite_status=%08x\n", status, ai_mite_status); ni_mio_print_status_a(status); @@ -989,12 +988,12 @@ static void handle_a_interrupt(struct comedi_device * dev, unsigned short status if (ai_mite_status & ~(CHSR_INT | CHSR_LINKC | CHSR_DONE | CHSR_MRDY | CHSR_DRDY | CHSR_DRQ1 | CHSR_DRQ0 | CHSR_ERROR | CHSR_SABORT | CHSR_XFERR | CHSR_LxERR_mask)) { - rt_printk + printk ("unknown mite interrupt, ack! (ai_mite_status=%08x)\n", ai_mite_status); - //mite_print_chsr(ai_mite_status); + /* mite_print_chsr(ai_mite_status); */ s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - //disable_irq(dev->irq); + /* disable_irq(dev->irq); */ } #endif @@ -1002,7 +1001,7 @@ static void handle_a_interrupt(struct comedi_device * dev, unsigned short status if (status & (AI_Overrun_St | AI_Overflow_St | AI_SC_TC_Error_St | AI_SC_TC_St | AI_START1_St)) { if (status == 0xffff) { - rt_printk + printk ("ni_mio_common: a_status=0xffff. Card removed?\n"); /* we probably aren't even running a command now, * so it's a good idea to be careful. */ @@ -1015,7 +1014,7 @@ static void handle_a_interrupt(struct comedi_device * dev, unsigned short status } if (status & (AI_Overrun_St | AI_Overflow_St | AI_SC_TC_Error_St)) { - rt_printk("ni_mio_common: ai error a_status=%04x\n", + printk("ni_mio_common: ai error a_status=%04x\n", status); ni_mio_print_status_a(status); @@ -1031,7 +1030,7 @@ static void handle_a_interrupt(struct comedi_device * dev, unsigned short status } if (status & AI_SC_TC_St) { #ifdef DEBUG_INTERRUPT - rt_printk("ni_mio_common: SC_TC interrupt\n"); + printk("ni_mio_common: SC_TC interrupt\n"); #endif if (!devpriv->ai_continuous) { shutdown_ai_command(dev); @@ -1052,7 +1051,7 @@ static void handle_a_interrupt(struct comedi_device * dev, unsigned short status break; } } -#endif // !PCIDMA +#endif /* !PCIDMA */ if ((status & AI_STOP_St)) { ni_handle_eos(dev, s); @@ -1063,14 +1062,14 @@ static void handle_a_interrupt(struct comedi_device * dev, unsigned short status #ifdef DEBUG_INTERRUPT status = devpriv->stc_readw(dev, AI_Status_1_Register); if (status & Interrupt_A_St) { - rt_printk + printk ("handle_a_interrupt: didn't clear interrupt? status=0x%x\n", status); } #endif } -static void ack_b_interrupt(struct comedi_device * dev, unsigned short b_status) +static void ack_b_interrupt(struct comedi_device *dev, unsigned short b_status) { unsigned short ack = 0; if (b_status & AO_BC_TC_St) { @@ -1098,13 +1097,13 @@ static void ack_b_interrupt(struct comedi_device * dev, unsigned short b_status) devpriv->stc_writew(dev, ack, Interrupt_B_Ack_Register); } -static void handle_b_interrupt(struct comedi_device * dev, unsigned short b_status, +static void handle_b_interrupt(struct comedi_device *dev, unsigned short b_status, unsigned ao_mite_status) { struct comedi_subdevice *s = dev->subdevices + NI_AO_SUBDEV; - //unsigned short ack=0; + /* unsigned short ack=0; */ #ifdef DEBUG_INTERRUPT - rt_printk("ni_mio_common: interrupt: b_status=%04x m1_status=%08x\n", + printk("ni_mio_common: interrupt: b_status=%04x m1_status=%08x\n", b_status, ao_mite_status); ni_mio_print_status_b(b_status); #endif @@ -1118,10 +1117,10 @@ static void handle_b_interrupt(struct comedi_device * dev, unsigned short b_stat if (ao_mite_status & ~(CHSR_INT | CHSR_LINKC | CHSR_DONE | CHSR_MRDY | CHSR_DRDY | CHSR_DRQ1 | CHSR_DRQ0 | CHSR_ERROR | CHSR_SABORT | CHSR_XFERR | CHSR_LxERR_mask)) { - rt_printk + printk ("unknown mite interrupt, ack! (ao_mite_status=%08x)\n", ao_mite_status); - //mite_print_chsr(ao_mite_status); + /* mite_print_chsr(ao_mite_status); */ s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; } #endif @@ -1129,7 +1128,7 @@ static void handle_b_interrupt(struct comedi_device * dev, unsigned short b_stat if (b_status == 0xffff) return; if (b_status & AO_Overrun_St) { - rt_printk + printk ("ni_mio_common: AO FIFO underrun status=0x%04x status2=0x%04x\n", b_status, devpriv->stc_readw(dev, AO_Status_2_Register)); @@ -1146,7 +1145,7 @@ static void handle_b_interrupt(struct comedi_device * dev, unsigned short b_stat ret = ni_ao_fifo_half_empty(dev, s); if (!ret) { - rt_printk("ni_mio_common: AO buffer underrun\n"); + printk("ni_mio_common: AO buffer underrun\n"); ni_set_bits(dev, Interrupt_B_Enable_Register, AO_FIFO_Interrupt_Enable | AO_Error_Interrupt_Enable, 0); @@ -1170,13 +1169,13 @@ static void ni_mio_print_status_a(int status) { int i; - rt_printk("A status:"); + printk("A status:"); for (i = 15; i >= 0; i--) { if (status & (1 << i)) { - rt_printk(" %s", status_a_strings[i]); + printk(" %s", status_a_strings[i]); } } - rt_printk("\n"); + printk("\n"); } #endif @@ -1192,19 +1191,19 @@ static void ni_mio_print_status_b(int status) { int i; - rt_printk("B status:"); + printk("B status:"); for (i = 15; i >= 0; i--) { if (status & (1 << i)) { - rt_printk(" %s", status_b_strings[i]); + printk(" %s", status_b_strings[i]); } } - rt_printk("\n"); + printk("\n"); } #endif #ifndef PCIDMA -static void ni_ao_fifo_load(struct comedi_device * dev, struct comedi_subdevice * s, int n) +static void ni_ao_fifo_load(struct comedi_device *dev, struct comedi_subdevice *s, int n) { struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; @@ -1263,7 +1262,7 @@ static void ni_ao_fifo_load(struct comedi_device * dev, struct comedi_subdevice * RT code, as RT code might purposely be running close to the * metal. Needs to be fixed eventually. */ -static int ni_ao_fifo_half_empty(struct comedi_device * dev, struct comedi_subdevice * s) +static int ni_ao_fifo_half_empty(struct comedi_device *dev, struct comedi_subdevice *s) { int n; @@ -1284,7 +1283,7 @@ static int ni_ao_fifo_half_empty(struct comedi_device * dev, struct comedi_subde return 1; } -static int ni_ao_prep_fifo(struct comedi_device * dev, struct comedi_subdevice * s) +static int ni_ao_prep_fifo(struct comedi_device *dev, struct comedi_subdevice *s) { int n; @@ -1307,7 +1306,7 @@ static int ni_ao_prep_fifo(struct comedi_device * dev, struct comedi_subdevice * return n; } -static void ni_ai_fifo_read(struct comedi_device * dev, struct comedi_subdevice * s, int n) +static void ni_ai_fifo_read(struct comedi_device *dev, struct comedi_subdevice *s, int n) { struct comedi_async *async = s->async; int i; @@ -1333,7 +1332,7 @@ static void ni_ai_fifo_read(struct comedi_device * dev, struct comedi_subdevice short data[2]; u32 dl; - // This just reads the FIFO assuming the data is present, no checks on the FIFO status are performed + /* This just reads the FIFO assuming the data is present, no checks on the FIFO status are performed */ for (i = 0; i < n / 2; i++) { dl = ni_readl(AIFIFO_Data_6143); @@ -1343,7 +1342,7 @@ static void ni_ai_fifo_read(struct comedi_device * dev, struct comedi_subdevice } if (n % 2) { /* Assume there is a single sample stuck in the FIFO */ - ni_writel(0x01, AIFIFO_Control_6143); // Get stranded sample into FIFO + ni_writel(0x01, AIFIFO_Control_6143); /* Get stranded sample into FIFO */ dl = ni_readl(AIFIFO_Data_6143); data[0] = (dl >> 16) & 0xffff; cfc_write_to_buffer(s, data[0]); @@ -1364,7 +1363,7 @@ static void ni_ai_fifo_read(struct comedi_device * dev, struct comedi_subdevice } } -static void ni_handle_fifo_half_full(struct comedi_device * dev) +static void ni_handle_fifo_half_full(struct comedi_device *dev) { int n; struct comedi_subdevice *s = dev->subdevices + NI_AI_SUBDEV; @@ -1376,14 +1375,14 @@ static void ni_handle_fifo_half_full(struct comedi_device * dev) #endif #ifdef PCIDMA -static int ni_ai_drain_dma(struct comedi_device * dev) +static int ni_ai_drain_dma(struct comedi_device *dev) { int i; static const int timeout = 10000; unsigned long flags; int retval = 0; - comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags); + spin_lock_irqsave(&devpriv->mite_channel_lock, flags); if (devpriv->ai_mite_chan) { for (i = 0; i < timeout; i++) { if ((devpriv->stc_readw(dev, @@ -1392,19 +1391,19 @@ static int ni_ai_drain_dma(struct comedi_device * dev) && mite_bytes_in_transit(devpriv-> ai_mite_chan) == 0) break; - comedi_udelay(5); + udelay(5); } if (i == timeout) { - rt_printk + printk ("ni_mio_common: wait for dma drain timed out\n"); - rt_printk + printk ("mite_bytes_in_transit=%i, AI_Status1_Register=0x%x\n", mite_bytes_in_transit(devpriv->ai_mite_chan), devpriv->stc_readw(dev, AI_Status_1_Register)); retval = -1; } } - comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); + spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); ni_sync_ai_dma(dev); @@ -1414,7 +1413,7 @@ static int ni_ai_drain_dma(struct comedi_device * dev) /* Empties the AI fifo */ -static void ni_handle_fifo_dregs(struct comedi_device * dev) +static void ni_handle_fifo_dregs(struct comedi_device *dev) { struct comedi_subdevice *s = dev->subdevices + NI_AI_SUBDEV; short data[2]; @@ -1444,9 +1443,9 @@ static void ni_handle_fifo_dregs(struct comedi_device * dev) cfc_write_array_to_buffer(s, data, sizeof(data)); i += 2; } - // Check if stranded sample is present + /* Check if stranded sample is present */ if (ni_readl(AIFIFO_Status_6143) & 0x01) { - ni_writel(0x01, AIFIFO_Control_6143); // Get stranded sample into FIFO + ni_writel(0x01, AIFIFO_Control_6143); /* Get stranded sample into FIFO */ dl = ni_readl(AIFIFO_Data_6143); data[0] = (dl >> 16) & 0xffff; cfc_write_to_buffer(s, data[0]); @@ -1476,7 +1475,7 @@ static void ni_handle_fifo_dregs(struct comedi_device * dev) } } -static void get_last_sample_611x(struct comedi_device * dev) +static void get_last_sample_611x(struct comedi_device *dev) { struct comedi_subdevice *s = dev->subdevices + NI_AI_SUBDEV; short data; @@ -1493,7 +1492,7 @@ static void get_last_sample_611x(struct comedi_device * dev) } } -static void get_last_sample_6143(struct comedi_device * dev) +static void get_last_sample_6143(struct comedi_device *dev) { struct comedi_subdevice *s = dev->subdevices + NI_AI_SUBDEV; short data; @@ -1504,7 +1503,7 @@ static void get_last_sample_6143(struct comedi_device * dev) /* Check if there's a single sample stuck in the FIFO */ if (ni_readl(AIFIFO_Status_6143) & 0x01) { - ni_writel(0x01, AIFIFO_Control_6143); // Get stranded sample into FIFO + ni_writel(0x01, AIFIFO_Control_6143); /* Get stranded sample into FIFO */ dl = ni_readl(AIFIFO_Data_6143); /* This may get the hi/lo data in the wrong order */ @@ -1513,7 +1512,7 @@ static void get_last_sample_6143(struct comedi_device * dev) } } -static void ni_ai_munge(struct comedi_device * dev, struct comedi_subdevice * s, +static void ni_ai_munge(struct comedi_device *dev, struct comedi_subdevice *s, void *data, unsigned int num_bytes, unsigned int chan_index) { struct comedi_async *async = s->async; @@ -1539,7 +1538,7 @@ static void ni_ai_munge(struct comedi_device * dev, struct comedi_subdevice * s, #ifdef PCIDMA -static int ni_ai_setup_MITE_dma(struct comedi_device * dev) +static int ni_ai_setup_MITE_dma(struct comedi_device *dev) { struct comedi_subdevice *s = dev->subdevices + NI_AI_SUBDEV; int retval; @@ -1548,15 +1547,14 @@ static int ni_ai_setup_MITE_dma(struct comedi_device * dev) retval = ni_request_ai_mite_channel(dev); if (retval) return retval; -// rt_printk("comedi_debug: using mite channel %i for ai.\n", devpriv->ai_mite_chan->channel); +/* printk("comedi_debug: using mite channel %i for ai.\n", devpriv->ai_mite_chan->channel); */ /* write alloc the entire buffer */ comedi_buf_write_alloc(s->async, s->async->prealloc_bufsz); - comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags); - if(devpriv->ai_mite_chan == NULL) - { - comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); + spin_lock_irqsave(&devpriv->mite_channel_lock, flags); + if (devpriv->ai_mite_chan == NULL) { + spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); return -EIO; } @@ -1574,12 +1572,12 @@ static int ni_ai_setup_MITE_dma(struct comedi_device * dev) }; /*start the MITE */ mite_dma_arm(devpriv->ai_mite_chan); - comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); + spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); return 0; } -static int ni_ao_setup_MITE_dma(struct comedi_device * dev) +static int ni_ao_setup_MITE_dma(struct comedi_device *dev) { struct comedi_subdevice *s = dev->subdevices + NI_AO_SUBDEV; int retval; @@ -1592,7 +1590,7 @@ static int ni_ao_setup_MITE_dma(struct comedi_device * dev) /* read alloc the entire buffer */ comedi_buf_read_alloc(s->async, s->async->prealloc_bufsz); - comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags); + spin_lock_irqsave(&devpriv->mite_channel_lock, flags); if (devpriv->ao_mite_chan) { if (boardtype.reg_type & (ni_reg_611x | ni_reg_6713)) { mite_prep_dma(devpriv->ao_mite_chan, 32, 32); @@ -1604,12 +1602,12 @@ static int ni_ao_setup_MITE_dma(struct comedi_device * dev) mite_dma_arm(devpriv->ao_mite_chan); } else retval = -EIO; - comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); + spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); return retval; } -#endif // PCIDMA +#endif /* PCIDMA */ /* used for both cancel ioctl and board initialization @@ -1617,7 +1615,7 @@ static int ni_ao_setup_MITE_dma(struct comedi_device * dev) this is pretty harsh for a cancel, but it works... */ -static int ni_ai_reset(struct comedi_device * dev, struct comedi_subdevice * s) +static int ni_ai_reset(struct comedi_device *dev, struct comedi_subdevice *s) { ni_release_ai_mite_channel(dev); /* ai configuration */ @@ -1698,14 +1696,14 @@ static int ni_ai_reset(struct comedi_device * dev, struct comedi_subdevice * s) return 0; } -static int ni_ai_poll(struct comedi_device * dev, struct comedi_subdevice * s) +static int ni_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s) { unsigned long flags = 0; int count; - // lock to avoid race with interrupt handler + /* lock to avoid race with interrupt handler */ if (in_interrupt() == 0) - comedi_spin_lock_irqsave(&dev->spinlock, flags); + spin_lock_irqsave(&dev->spinlock, flags); #ifndef PCIDMA ni_handle_fifo_dregs(dev); #else @@ -1713,13 +1711,13 @@ static int ni_ai_poll(struct comedi_device * dev, struct comedi_subdevice * s) #endif count = s->async->buf_write_count - s->async->buf_read_count; if (in_interrupt() == 0) - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); return count; } -static int ni_ai_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int ni_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i, n; const unsigned int mask = (1 << boardtype.adbits) - 1; @@ -1736,7 +1734,7 @@ static int ni_ai_insn_read(struct comedi_device * dev, struct comedi_subdevice * for (n = 0; n < num_adc_stages_611x; n++) { devpriv->stc_writew(dev, AI_CONVERT_Pulse, AI_Command_1_Register); - comedi_udelay(1); + udelay(1); } for (n = 0; n < insn->n; n++) { devpriv->stc_writew(dev, AI_CONVERT_Pulse, @@ -1758,7 +1756,7 @@ static int ni_ai_insn_read(struct comedi_device * dev, struct comedi_subdevice * } } if (i == NI_TIMEOUT) { - rt_printk + printk ("ni_mio_common: timeout in 611x ni_ai_insn_read\n"); return -ETIME; } @@ -1774,13 +1772,13 @@ static int ni_ai_insn_read(struct comedi_device * dev, struct comedi_subdevice * dl = 0; for (i = 0; i < NI_TIMEOUT; i++) { if (ni_readl(AIFIFO_Status_6143) & 0x01) { - ni_writel(0x01, AIFIFO_Control_6143); // Get stranded sample into FIFO + ni_writel(0x01, AIFIFO_Control_6143); /* Get stranded sample into FIFO */ dl = ni_readl(AIFIFO_Data_6143); break; } } if (i == NI_TIMEOUT) { - rt_printk + printk ("ni_mio_common: timeout in 6143 ni_ai_insn_read\n"); return -ETIME; } @@ -1797,7 +1795,7 @@ static int ni_ai_insn_read(struct comedi_device * dev, struct comedi_subdevice * break; } if (i == NI_TIMEOUT) { - rt_printk + printk ("ni_mio_common: timeout in ni_ai_insn_read\n"); return -ETIME; } @@ -1814,7 +1812,7 @@ static int ni_ai_insn_read(struct comedi_device * dev, struct comedi_subdevice * return insn->n; } -void ni_prime_channelgain_list(struct comedi_device * dev) +void ni_prime_channelgain_list(struct comedi_device *dev) { int i; devpriv->stc_writew(dev, AI_CONVERT_Pulse, AI_Command_1_Register); @@ -1825,12 +1823,12 @@ void ni_prime_channelgain_list(struct comedi_device * dev) devpriv->stc_writew(dev, 1, ADC_FIFO_Clear); return; } - comedi_udelay(1); + udelay(1); } - rt_printk("ni_mio_common: timeout loading channel/gain list\n"); + printk("ni_mio_common: timeout loading channel/gain list\n"); } -static void ni_m_series_load_channelgain_list(struct comedi_device * dev, +static void ni_m_series_load_channelgain_list(struct comedi_device *dev, unsigned int n_chan, unsigned int *list) { unsigned int chan, range, aref; @@ -1841,7 +1839,7 @@ static void ni_m_series_load_channelgain_list(struct comedi_device * dev, devpriv->stc_writew(dev, 1, Configuration_Memory_Clear); -// offset = 1 << (boardtype.adbits - 1); +/* offset = 1 << (boardtype.adbits - 1); */ if ((list[0] & CR_ALT_SOURCE)) { unsigned bypass_bits; chan = CR_CHAN(list[0]); @@ -1859,7 +1857,7 @@ static void ni_m_series_load_channelgain_list(struct comedi_device * dev, bypass_bits |= MSeries_AI_Bypass_Gain_Bits(range_code); if (dither) bypass_bits |= MSeries_AI_Bypass_Dither_Bit; - // don't use 2's complement encoding + /* don't use 2's complement encoding */ bypass_bits |= MSeries_AI_Bypass_Polarity_Bit; ni_writel(bypass_bits, M_Offset_AI_Config_FIFO_Bypass); } else { @@ -1899,7 +1897,7 @@ static void ni_m_series_load_channelgain_list(struct comedi_device * dev, config_bits |= MSeries_AI_Config_Last_Channel_Bit; if (dither) config_bits |= MSeries_AI_Config_Dither_Bit; - // don't use 2's complement encoding + /* don't use 2's complement encoding */ config_bits |= MSeries_AI_Config_Polarity_Bit; ni_writew(config_bits, M_Offset_AI_Config_FIFO_Data); } @@ -1935,7 +1933,7 @@ static void ni_m_series_load_channelgain_list(struct comedi_device * dev, * bits 0-2: channel * valid channels are 0-3 */ -static void ni_load_channelgain_list(struct comedi_device * dev, unsigned int n_chan, +static void ni_load_channelgain_list(struct comedi_device *dev, unsigned int n_chan, unsigned int *list) { unsigned int chan, range, aref; @@ -1952,7 +1950,7 @@ static void ni_load_channelgain_list(struct comedi_device * dev, unsigned int n_ && (boardtype.reg_type != ni_reg_6143)) { if (devpriv->changain_state && devpriv->changain_spec == list[0]) { - // ready to go. + /* ready to go. */ return; } devpriv->changain_state = 1; @@ -1963,11 +1961,11 @@ static void ni_load_channelgain_list(struct comedi_device * dev, unsigned int n_ devpriv->stc_writew(dev, 1, Configuration_Memory_Clear); - // Set up Calibration mode if required + /* Set up Calibration mode if required */ if (boardtype.reg_type == ni_reg_6143) { if ((list[0] & CR_ALT_SOURCE) && !devpriv->ai_calib_source_enabled) { - // Strobe Relay enable bit + /* Strobe Relay enable bit */ ni_writew(devpriv-> ai_calib_source | Calibration_Channel_6143_RelayOn, @@ -1975,10 +1973,10 @@ static void ni_load_channelgain_list(struct comedi_device * dev, unsigned int n_ ni_writew(devpriv->ai_calib_source, Calibration_Channel_6143); devpriv->ai_calib_source_enabled = 1; - msleep_interruptible(100); // Allow relays to change + msleep_interruptible(100); /* Allow relays to change */ } else if (!(list[0] & CR_ALT_SOURCE) && devpriv->ai_calib_source_enabled) { - // Strobe Relay disable bit + /* Strobe Relay disable bit */ ni_writew(devpriv-> ai_calib_source | Calibration_Channel_6143_RelayOff, @@ -1986,7 +1984,7 @@ static void ni_load_channelgain_list(struct comedi_device * dev, unsigned int n_ ni_writew(devpriv->ai_calib_source, Calibration_Channel_6143); devpriv->ai_calib_source_enabled = 0; - msleep_interruptible(100); // Allow relays to change + msleep_interruptible(100); /* Allow relays to change */ } } @@ -2055,7 +2053,7 @@ static void ni_load_channelgain_list(struct comedi_device * dev, unsigned int n_ } } -static int ni_ns_to_timer(const struct comedi_device * dev, unsigned nanosec, +static int ni_ns_to_timer(const struct comedi_device *dev, unsigned nanosec, int round_mode) { int divider; @@ -2074,29 +2072,29 @@ static int ni_ns_to_timer(const struct comedi_device * dev, unsigned nanosec, return divider - 1; } -static unsigned ni_timer_to_ns(const struct comedi_device * dev, int timer) +static unsigned ni_timer_to_ns(const struct comedi_device *dev, int timer) { return devpriv->clock_ns * (timer + 1); } -static unsigned ni_min_ai_scan_period_ns(struct comedi_device * dev, +static unsigned ni_min_ai_scan_period_ns(struct comedi_device *dev, unsigned num_channels) { switch (boardtype.reg_type) { case ni_reg_611x: case ni_reg_6143: - // simultaneously-sampled inputs + /* simultaneously-sampled inputs */ return boardtype.ai_speed; break; default: - // multiplexed inputs + /* multiplexed inputs */ break; }; return boardtype.ai_speed * num_channels; } -static int ni_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd) +static int ni_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd) { int err = 0; int tmp; @@ -2308,7 +2306,7 @@ static int ni_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s return 0; } -static int ni_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s) +static int ni_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { const struct comedi_cmd *cmd = &s->async->cmd; int timer; @@ -2367,10 +2365,10 @@ static int ni_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s) if (cmd->chanlist_len == 1 || (boardtype.reg_type == ni_reg_611x) || (boardtype.reg_type == ni_reg_6143)) { start_stop_select |= AI_STOP_Polarity; - start_stop_select |= AI_STOP_Select(31); // logic low + start_stop_select |= AI_STOP_Select(31); /* logic low */ start_stop_select |= AI_STOP_Sync; } else { - start_stop_select |= AI_STOP_Select(19); // ai configuration memory + start_stop_select |= AI_STOP_Select(19); /* ai configuration memory */ } devpriv->stc_writew(dev, start_stop_select, AI_START_STOP_Select_Register); @@ -2381,7 +2379,7 @@ static int ni_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s) stop_count = cmd->stop_arg - 1; if (boardtype.reg_type == ni_reg_611x) { - // have to take 3 stage adc pipeline into account + /* have to take 3 stage adc pipeline into account */ stop_count += num_adc_stages_611x; } /* stage number of scans */ @@ -2396,7 +2394,7 @@ static int ni_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s) if (stop_count == 0) { devpriv->ai_cmd2 |= AI_End_On_End_Of_Scan; interrupt_a_enable |= AI_STOP_Interrupt_Enable; - // this is required to get the last sample for chanlist_len > 1, not sure why + /* this is required to get the last sample for chanlist_len > 1, not sure why */ if (cmd->chanlist_len > 1) start_stop_select |= AI_STOP_Polarity | AI_STOP_Edge; @@ -2440,7 +2438,7 @@ static int ni_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s) mode2 |= AI_SI_Reload_Mode(0); /* AI_SI_Initial_Load_Source=A */ mode2 &= ~AI_SI_Initial_Load_Source; - //mode2 |= AI_SC_Reload_Mode; + /* mode2 |= AI_SC_Reload_Mode; */ devpriv->stc_writew(dev, mode2, AI_Mode_2_Register); /* load SI */ @@ -2486,8 +2484,8 @@ static int ni_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s) /* AI_SI2_Load */ devpriv->stc_writew(dev, AI_SI2_Load, AI_Command_1_Register); - mode2 |= AI_SI2_Reload_Mode; // alternate - mode2 |= AI_SI2_Initial_Load_Source; // B + mode2 |= AI_SI2_Reload_Mode; /* alternate */ + mode2 |= AI_SI2_Initial_Load_Source; /* B */ devpriv->stc_writew(dev, mode2, AI_Mode_2_Register); break; @@ -2589,7 +2587,7 @@ static int ni_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s) if (retval) return retval; } - //mite_dump_regs(devpriv->mite); + /* mite_dump_regs(devpriv->mite); */ #endif switch (cmd->start_src) { @@ -2612,7 +2610,7 @@ static int ni_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s) return 0; } -static int ni_ai_inttrig(struct comedi_device * dev, struct comedi_subdevice * s, +static int ni_ai_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int trignum) { if (trignum != 0) @@ -2625,11 +2623,11 @@ static int ni_ai_inttrig(struct comedi_device * dev, struct comedi_subdevice * s return 1; } -static int ni_ai_config_analog_trig(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); +static int ni_ai_config_analog_trig(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); -static int ni_ai_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int ni_ai_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if (insn->n < 1) return -EINVAL; @@ -2679,8 +2677,8 @@ static int ni_ai_insn_config(struct comedi_device * dev, struct comedi_subdevice return -EINVAL; } -static int ni_ai_config_analog_trig(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int ni_ai_config_analog_trig(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { unsigned int a, b, modebits; int err = 0; @@ -2777,7 +2775,7 @@ static int ni_ai_config_analog_trig(struct comedi_device * dev, struct comedi_su } /* munge data from unsigned to 2's complement for analog output bipolar modes */ -static void ni_ao_munge(struct comedi_device * dev, struct comedi_subdevice * s, +static void ni_ao_munge(struct comedi_device *dev, struct comedi_subdevice *s, void *data, unsigned int num_bytes, unsigned int chan_index) { struct comedi_async *async = s->async; @@ -2800,8 +2798,8 @@ static void ni_ao_munge(struct comedi_device * dev, struct comedi_subdevice * s, } } -static int ni_m_series_ao_config_chanlist(struct comedi_device * dev, - struct comedi_subdevice * s, unsigned int chanspec[], unsigned int n_chans, +static int ni_m_series_ao_config_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, unsigned int chanspec[], unsigned int n_chans, int timed) { unsigned int range; @@ -2810,7 +2808,7 @@ static int ni_m_series_ao_config_chanlist(struct comedi_device * dev, int i; int invert = 0; - if(timed) { + if (timed) { for (i = 0; i < boardtype.n_aochan; ++i) { devpriv->ao_conf[i] &= ~MSeries_AO_Update_Timed_Bit; ni_writeb(devpriv->ao_conf[i], M_Offset_AO_Config_Bank(i)); @@ -2844,8 +2842,8 @@ static int ni_m_series_ao_config_chanlist(struct comedi_device * dev, M_Offset_AO_Reference_Attenuation(chan)); break; default: - rt_printk("%s: bug! unhandled ao reference voltage\n", - __FUNCTION__); + printk("%s: bug! unhandled ao reference voltage\n", + __func__); break; } switch (krange->max + krange->min) { @@ -2856,8 +2854,8 @@ static int ni_m_series_ao_config_chanlist(struct comedi_device * dev, conf |= MSeries_AO_DAC_Offset_5V_Bits; break; default: - rt_printk("%s: bug! unhandled ao offset voltage\n", - __FUNCTION__); + printk("%s: bug! unhandled ao offset voltage\n", + __func__); break; } if (timed) @@ -2869,7 +2867,7 @@ static int ni_m_series_ao_config_chanlist(struct comedi_device * dev, return invert; } -static int ni_old_ao_config_chanlist(struct comedi_device * dev, struct comedi_subdevice * s, +static int ni_old_ao_config_chanlist(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int chanspec[], unsigned int n_chans) { unsigned int range; @@ -2912,7 +2910,7 @@ static int ni_old_ao_config_chanlist(struct comedi_device * dev, struct comedi_s return invert; } -static int ni_ao_config_chanlist(struct comedi_device * dev, struct comedi_subdevice * s, +static int ni_ao_config_chanlist(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int chanspec[], unsigned int n_chans, int timed) { if (boardtype.reg_type & ni_reg_m_series_mask) @@ -2921,16 +2919,16 @@ static int ni_ao_config_chanlist(struct comedi_device * dev, struct comedi_subde else return ni_old_ao_config_chanlist(dev, s, chanspec, n_chans); } -static int ni_ao_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int ni_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { data[0] = devpriv->ao[CR_CHAN(insn->chanspec)]; return 1; } -static int ni_ao_insn_write(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int ni_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { unsigned int chan = CR_CHAN(insn->chanspec); unsigned int invert; @@ -2948,8 +2946,8 @@ static int ni_ao_insn_write(struct comedi_device * dev, struct comedi_subdevice return 1; } -static int ni_ao_insn_write_671x(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int ni_ao_insn_write_671x(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { unsigned int chan = CR_CHAN(insn->chanspec); unsigned int invert; @@ -2965,16 +2963,16 @@ static int ni_ao_insn_write_671x(struct comedi_device * dev, struct comedi_subde return 1; } -static int ni_ao_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int ni_ao_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { switch (data[0]) { case INSN_CONFIG_GET_HARDWARE_BUFFER_SIZE: - switch(data[1]) + switch (data[1]) { case COMEDI_OUTPUT: data[2] = 1 + boardtype.ao_fifo_depth * sizeof(short); - if(devpriv->mite) data[2] += devpriv->mite->fifo_size; + if (devpriv->mite) data[2] += devpriv->mite->fifo_size; break; case COMEDI_INPUT: data[2] = 0; @@ -2991,7 +2989,7 @@ static int ni_ao_insn_config(struct comedi_device * dev, struct comedi_subdevice return -EINVAL; } -static int ni_ao_inttrig(struct comedi_device * dev, struct comedi_subdevice * s, +static int ni_ao_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int trignum) { int ret; @@ -3033,7 +3031,7 @@ static int ni_ao_inttrig(struct comedi_device * dev, struct comedi_subdevice * s devpriv->stc_writew(dev, devpriv->ao_mode3, AO_Mode_3_Register); /* wait for DACs to be loaded */ for (i = 0; i < timeout; i++) { - comedi_udelay(1); + udelay(1); if ((devpriv->stc_readw(dev, Joint_Status_2_Register) & AO_TMRDACWRs_In_Progress_St) == 0) @@ -3044,7 +3042,7 @@ static int ni_ao_inttrig(struct comedi_device * dev, struct comedi_subdevice * s "timed out waiting for AO_TMRDACWRs_In_Progress_St to clear"); return -EIO; } - // stc manual says we are need to clear error interrupt after AO_TMRDACWRs_In_Progress_St clears + /* stc manual says we are need to clear error interrupt after AO_TMRDACWRs_In_Progress_St clears */ devpriv->stc_writew(dev, AO_Error_Interrupt_Ack, Interrupt_B_Ack_Register); @@ -3062,7 +3060,7 @@ static int ni_ao_inttrig(struct comedi_device * dev, struct comedi_subdevice * s return 0; } -static int ni_ao_cmd(struct comedi_device * dev, struct comedi_subdevice * s) +static int ni_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { const struct comedi_cmd *cmd = &s->async->cmd; int bits; @@ -3114,9 +3112,9 @@ static int ni_ao_cmd(struct comedi_device * dev, struct comedi_subdevice * s) case TRIG_EXT: devpriv->ao_trigger_select = AO_START1_Select(CR_CHAN(cmd->start_arg)+1); if (cmd->start_arg & CR_INVERT) - devpriv->ao_trigger_select |= AO_START1_Polarity; // 0=active high, 1=active low. see daq-stc 3-24 (p186) + devpriv->ao_trigger_select |= AO_START1_Polarity; /* 0=active high, 1=active low. see daq-stc 3-24 (p186) */ if (cmd->start_arg & CR_EDGE) - devpriv->ao_trigger_select |= AO_START1_Edge; // 0=edge detection disabled, 1=enabled + devpriv->ao_trigger_select |= AO_START1_Edge; /* 0=edge detection disabled, 1=enabled */ devpriv->stc_writew(dev, devpriv->ao_trigger_select, AO_Trigger_Select_Register); break; default: @@ -3139,9 +3137,9 @@ static int ni_ao_cmd(struct comedi_device * dev, struct comedi_subdevice * s) devpriv->stc_writew(dev, devpriv->ao_mode2, AO_Mode_2_Register); switch (cmd->stop_src) { case TRIG_COUNT: - if(boardtype.reg_type & ni_reg_m_series_mask) + if (boardtype.reg_type & ni_reg_m_series_mask) { - // this is how the NI example code does it for m-series boards, verified correct with 6259 + /* this is how the NI example code does it for m-series boards, verified correct with 6259 */ devpriv->stc_writel(dev, cmd->stop_arg - 1, AO_UC_Load_A_Register); devpriv->stc_writew(dev, AO_UC_Load, AO_Command_1_Register); }else @@ -3244,7 +3242,7 @@ static int ni_ao_cmd(struct comedi_device * dev, struct comedi_subdevice * s) bits |= AO_Number_Of_DAC_Packages; #endif devpriv->stc_writew(dev, bits, AO_Personal_Register); - // enable sending of ao dma requests + /* enable sending of ao dma requests */ devpriv->stc_writew(dev, AO_AOFREQ_Enable, AO_Start_Select_Register); devpriv->stc_writew(dev, AO_Configuration_End, Joint_Reset_Register); @@ -3261,8 +3259,8 @@ static int ni_ao_cmd(struct comedi_device * dev, struct comedi_subdevice * s) return 0; } -static int ni_ao_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd) +static int ni_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd) { int err = 0; int tmp; @@ -3384,13 +3382,13 @@ static int ni_ao_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s return 0; } -static int ni_ao_reset(struct comedi_device * dev, struct comedi_subdevice * s) +static int ni_ao_reset(struct comedi_device *dev, struct comedi_subdevice *s) { - //devpriv->ao0p=0x0000; - //ni_writew(devpriv->ao0p,AO_Configuration); + /* devpriv->ao0p=0x0000; */ + /* ni_writew(devpriv->ao0p,AO_Configuration); */ - //devpriv->ao1p=AO_Channel(1); - //ni_writew(devpriv->ao1p,AO_Configuration); + /* devpriv->ao1p=AO_Channel(1); */ + /* ni_writew(devpriv->ao1p,AO_Configuration); */ ni_release_ao_mite_channel(dev); @@ -3422,7 +3420,7 @@ static int ni_ao_reset(struct comedi_device * dev, struct comedi_subdevice * s) if (boardtype.reg_type & ni_reg_6xxx_mask) { unsigned immediate_bits = 0; unsigned i; - for(i = 0; i < s->n_chan; ++i) + for (i = 0; i < s->n_chan; ++i) { immediate_bits |= 1 << i; } @@ -3434,13 +3432,13 @@ static int ni_ao_reset(struct comedi_device * dev, struct comedi_subdevice * s) return 0; } -// digital io +/* digital io */ -static int ni_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int ni_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { #ifdef DEBUG_DIO - rt_printk("ni_dio_insn_config() chan=%d io=%d\n", + printk("ni_dio_insn_config() chan=%d io=%d\n", CR_CHAN(insn->chanspec), data[0]); #endif switch (data[0]) { @@ -3468,11 +3466,11 @@ static int ni_dio_insn_config(struct comedi_device * dev, struct comedi_subdevic return 1; } -static int ni_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int ni_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { #ifdef DEBUG_DIO - rt_printk("ni_dio_insn_bits() mask=0x%x bits=0x%x\n", data[0], data[1]); + printk("ni_dio_insn_bits() mask=0x%x bits=0x%x\n", data[0], data[1]); #endif if (insn->n != 2) return -EINVAL; @@ -3495,11 +3493,11 @@ static int ni_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice return 2; } -static int ni_m_series_dio_insn_config(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +static int ni_m_series_dio_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { #ifdef DEBUG_DIO - rt_printk("ni_m_series_dio_insn_config() chan=%d io=%d\n", + printk("ni_m_series_dio_insn_config() chan=%d io=%d\n", CR_CHAN(insn->chanspec), data[0]); #endif switch (data[0]) { @@ -3525,11 +3523,11 @@ static int ni_m_series_dio_insn_config(struct comedi_device * dev, return 1; } -static int ni_m_series_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int ni_m_series_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { #ifdef DEBUG_DIO - rt_printk("ni_m_series_dio_insn_bits() mask=0x%x bits=0x%x\n", data[0], + printk("ni_m_series_dio_insn_bits() mask=0x%x bits=0x%x\n", data[0], data[1]); #endif if (insn->n != 2) @@ -3544,8 +3542,8 @@ static int ni_m_series_dio_insn_bits(struct comedi_device * dev, struct comedi_s return 2; } -static int ni_cdio_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd) +static int ni_cdio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd) { int err = 0; int tmp; @@ -3653,7 +3651,7 @@ static int ni_cdio_cmdtest(struct comedi_device * dev, struct comedi_subdevice * return 0; } -static int ni_cdio_cmd(struct comedi_device * dev, struct comedi_subdevice * s) +static int ni_cdio_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { const struct comedi_cmd *cmd = &s->async->cmd; unsigned cdo_mode_bits = CDO_FIFO_Mode_Bit | CDO_Halt_On_Error_Bit; @@ -3690,7 +3688,7 @@ static int ni_cdio_cmd(struct comedi_device * dev, struct comedi_subdevice * s) return 0; } -static int ni_cdo_inttrig(struct comedi_device * dev, struct comedi_subdevice * s, +static int ni_cdo_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int trignum) { #ifdef PCIDMA @@ -3706,7 +3704,7 @@ static int ni_cdo_inttrig(struct comedi_device * dev, struct comedi_subdevice * comedi_buf_read_alloc(s->async, s->async->prealloc_bufsz); #ifdef PCIDMA - comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags); + spin_lock_irqsave(&devpriv->mite_channel_lock, flags); if (devpriv->cdo_mite_chan) { mite_prep_dma(devpriv->cdo_mite_chan, 32, 32); mite_dma_arm(devpriv->cdo_mite_chan); @@ -3714,17 +3712,19 @@ static int ni_cdo_inttrig(struct comedi_device * dev, struct comedi_subdevice * comedi_error(dev, "BUG: no cdo mite channel?"); retval = -EIO; } - comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); + spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); if (retval < 0) return retval; #endif -// XXX not sure what interrupt C group does -// ni_writeb(Interrupt_Group_C_Enable_Bit, M_Offset_Interrupt_C_Enable); - //wait for dma to fill output fifo +/* +* XXX not sure what interrupt C group does +* ni_writeb(Interrupt_Group_C_Enable_Bit, +* M_Offset_Interrupt_C_Enable); wait for dma to fill output fifo +*/ for (i = 0; i < timeout; ++i) { if (ni_readl(M_Offset_CDIO_Status) & CDO_FIFO_Full_Bit) break; - comedi_udelay(10); + udelay(10); } if (i == timeout) { comedi_error(dev, "dma failed to fill cdo fifo!"); @@ -3736,20 +3736,22 @@ static int ni_cdo_inttrig(struct comedi_device * dev, struct comedi_subdevice * return retval; } -static int ni_cdio_cancel(struct comedi_device * dev, struct comedi_subdevice * s) +static int ni_cdio_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { ni_writel(CDO_Disarm_Bit | CDO_Error_Interrupt_Enable_Clear_Bit | CDO_Empty_FIFO_Interrupt_Enable_Clear_Bit | CDO_FIFO_Request_Interrupt_Enable_Clear_Bit, M_Offset_CDIO_Command); -// XXX not sure what interrupt C group does -// ni_writeb(0, M_Offset_Interrupt_C_Enable); +/* +* XXX not sure what interrupt C group does ni_writeb(0, +* M_Offset_Interrupt_C_Enable); +*/ ni_writel(0, M_Offset_CDO_Mask_Enable); ni_release_cdo_mite_channel(dev); return 0; } -static void handle_cdio_interrupt(struct comedi_device * dev) +static void handle_cdio_interrupt(struct comedi_device *dev) { unsigned cdio_status; struct comedi_subdevice *s = dev->subdevices + NI_DIO_SUBDEV; @@ -3761,7 +3763,7 @@ static void handle_cdio_interrupt(struct comedi_device * dev) return; } #ifdef PCIDMA - comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags); + spin_lock_irqsave(&devpriv->mite_channel_lock, flags); if (devpriv->cdo_mite_chan) { unsigned cdo_mite_status = mite_get_status(devpriv->cdo_mite_chan); @@ -3772,26 +3774,26 @@ static void handle_cdio_interrupt(struct comedi_device * dev) } mite_sync_output_dma(devpriv->cdo_mite_chan, s->async); } - comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); + spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); #endif cdio_status = ni_readl(M_Offset_CDIO_Status); if (cdio_status & (CDO_Overrun_Bit | CDO_Underflow_Bit)) { -// rt_printk("cdio error: statux=0x%x\n", cdio_status); - ni_writel(CDO_Error_Interrupt_Confirm_Bit, M_Offset_CDIO_Command); // XXX just guessing this is needed and does something useful +/* printk("cdio error: statux=0x%x\n", cdio_status); */ + ni_writel(CDO_Error_Interrupt_Confirm_Bit, M_Offset_CDIO_Command); /* XXX just guessing this is needed and does something useful */ s->async->events |= COMEDI_CB_OVERFLOW; } if (cdio_status & CDO_FIFO_Empty_Bit) { -// rt_printk("cdio fifo empty\n"); +/* printk("cdio fifo empty\n"); */ ni_writel(CDO_Empty_FIFO_Interrupt_Enable_Clear_Bit, M_Offset_CDIO_Command); -// s->async->events |= COMEDI_CB_EOA; +/* s->async->events |= COMEDI_CB_EOA; */ } ni_event(dev, s); } -static int ni_serial_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int ni_serial_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int err = insn->n; unsigned char byte_out, byte_in = 0; @@ -3803,7 +3805,7 @@ static int ni_serial_insn_config(struct comedi_device * dev, struct comedi_subde case INSN_CONFIG_SERIAL_CLOCK: #ifdef DEBUG_DIO - rt_printk("SPI serial clock Config cd\n", data[1]); + printk("SPI serial clock Config cd\n", data[1]); #endif devpriv->serial_hw_mode = 1; devpriv->dio_control |= DIO_HW_Serial_Enable; @@ -3869,7 +3871,7 @@ static int ni_serial_insn_config(struct comedi_device * dev, struct comedi_subde err = ni_serial_sw_readwrite8(dev, s, byte_out, &byte_in); } else { - rt_printk("ni_serial_insn_config: serial disabled!\n"); + printk("ni_serial_insn_config: serial disabled!\n"); return -EINVAL; } if (err < 0) @@ -3884,14 +3886,14 @@ static int ni_serial_insn_config(struct comedi_device * dev, struct comedi_subde } -static int ni_serial_hw_readwrite8(struct comedi_device * dev, struct comedi_subdevice * s, +static int ni_serial_hw_readwrite8(struct comedi_device *dev, struct comedi_subdevice *s, unsigned char data_out, unsigned char *data_in) { unsigned int status1; int err = 0, count = 20; #ifdef DEBUG_DIO - rt_printk("ni_serial_hw_readwrite8: outputting 0x%x\n", data_out); + printk("ni_serial_hw_readwrite8: outputting 0x%x\n", data_out); #endif devpriv->dio_output &= ~DIO_Serial_Data_Mask; @@ -3914,9 +3916,9 @@ static int ni_serial_hw_readwrite8(struct comedi_device * dev, struct comedi_sub Joint_Status_1_Register)) & DIO_Serial_IO_In_Progress_St) { /* Delay one bit per loop */ - comedi_udelay((devpriv->serial_interval_ns + 999) / 1000); + udelay((devpriv->serial_interval_ns + 999) / 1000); if (--count < 0) { - rt_printk + printk ("ni_serial_hw_readwrite8: SPI serial I/O didn't finish in time!\n"); err = -ETIME; goto Error; @@ -3925,12 +3927,12 @@ static int ni_serial_hw_readwrite8(struct comedi_device * dev, struct comedi_sub /* Delay for last bit. This delay is absolutely necessary, because DIO_Serial_IO_In_Progress_St goes high one bit too early. */ - comedi_udelay((devpriv->serial_interval_ns + 999) / 1000); + udelay((devpriv->serial_interval_ns + 999) / 1000); if (data_in != NULL) { *data_in = devpriv->stc_readw(dev, DIO_Serial_Input_Register); #ifdef DEBUG_DIO - rt_printk("ni_serial_hw_readwrite8: inputted 0x%x\n", *data_in); + printk("ni_serial_hw_readwrite8: inputted 0x%x\n", *data_in); #endif } @@ -3940,17 +3942,17 @@ static int ni_serial_hw_readwrite8(struct comedi_device * dev, struct comedi_sub return err; } -static int ni_serial_sw_readwrite8(struct comedi_device * dev, struct comedi_subdevice * s, +static int ni_serial_sw_readwrite8(struct comedi_device *dev, struct comedi_subdevice *s, unsigned char data_out, unsigned char *data_in) { unsigned char mask, input = 0; #ifdef DEBUG_DIO - rt_printk("ni_serial_sw_readwrite8: outputting 0x%x\n", data_out); + printk("ni_serial_sw_readwrite8: outputting 0x%x\n", data_out); #endif /* Wait for one bit before transfer */ - comedi_udelay((devpriv->serial_interval_ns + 999) / 1000); + udelay((devpriv->serial_interval_ns + 999) / 1000); for (mask = 0x80; mask; mask >>= 1) { /* Output current bit; note that we cannot touch s->state @@ -3969,23 +3971,23 @@ static int ni_serial_sw_readwrite8(struct comedi_device * dev, struct comedi_sub devpriv->stc_writew(dev, devpriv->dio_control, DIO_Control_Register); - comedi_udelay((devpriv->serial_interval_ns + 999) / 2000); + udelay((devpriv->serial_interval_ns + 999) / 2000); devpriv->dio_control &= ~DIO_Software_Serial_Control; devpriv->stc_writew(dev, devpriv->dio_control, DIO_Control_Register); - comedi_udelay((devpriv->serial_interval_ns + 999) / 2000); + udelay((devpriv->serial_interval_ns + 999) / 2000); /* Input current bit */ if (devpriv->stc_readw(dev, DIO_Parallel_Input_Register) & DIO_SDIN) { -/* rt_printk("DIO_P_I_R: 0x%x\n", devpriv->stc_readw(dev, DIO_Parallel_Input_Register)); */ +/* printk("DIO_P_I_R: 0x%x\n", devpriv->stc_readw(dev, DIO_Parallel_Input_Register)); */ input |= mask; } } #ifdef DEBUG_DIO - rt_printk("ni_serial_sw_readwrite8: inputted 0x%x\n", input); + printk("ni_serial_sw_readwrite8: inputted 0x%x\n", input); #endif if (data_in) *data_in = input; @@ -3993,7 +3995,7 @@ static int ni_serial_sw_readwrite8(struct comedi_device * dev, struct comedi_sub return 0; } -static void mio_common_detach(struct comedi_device * dev) +static void mio_common_detach(struct comedi_device *dev) { if (dev->private) { if (devpriv->counter_dev) { @@ -4004,7 +4006,7 @@ static void mio_common_detach(struct comedi_device * dev) subdev_8255_cleanup(dev, dev->subdevices + NI_8255_DIO_SUBDEV); } -static void init_ao_67xx(struct comedi_device * dev, struct comedi_subdevice * s) +static void init_ao_67xx(struct comedi_device *dev, struct comedi_subdevice *s) { int i; @@ -4099,8 +4101,8 @@ static unsigned ni_gpct_to_stc_register(enum ni_gpct_register reg) stc_register = Interrupt_B_Enable_Register; break; default: - rt_printk("%s: unhandled register 0x%x in switch.\n", - __FUNCTION__, reg); + printk("%s: unhandled register 0x%x in switch.\n", + __func__, reg); BUG(); return 0; break; @@ -4208,15 +4210,15 @@ static unsigned ni_gpct_read_register(struct ni_gpct *counter, return 0; } -static int ni_freq_out_insn_read(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +static int ni_freq_out_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { data[0] = devpriv->clock_and_fout & FOUT_Divider_mask; return 1; } -static int ni_freq_out_insn_write(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +static int ni_freq_out_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { devpriv->clock_and_fout &= ~FOUT_Enable; devpriv->stc_writew(dev, devpriv->clock_and_fout, @@ -4229,7 +4231,7 @@ static int ni_freq_out_insn_write(struct comedi_device * dev, return insn->n; } -static int ni_set_freq_out_clock(struct comedi_device * dev, unsigned int clock_source) +static int ni_set_freq_out_clock(struct comedi_device *dev, unsigned int clock_source) { switch (clock_source) { case NI_FREQ_OUT_TIMEBASE_1_DIV_2_CLOCK_SRC: @@ -4246,8 +4248,8 @@ static int ni_set_freq_out_clock(struct comedi_device * dev, unsigned int clock_ return 3; } -static void ni_get_freq_out_clock(struct comedi_device * dev, unsigned int * clock_source, - unsigned int * clock_period_ns) +static void ni_get_freq_out_clock(struct comedi_device *dev, unsigned int *clock_source, + unsigned int *clock_period_ns) { if (devpriv->clock_and_fout & FOUT_Timebase_Select) { *clock_source = NI_FREQ_OUT_TIMEBASE_2_CLOCK_SRC; @@ -4258,8 +4260,8 @@ static void ni_get_freq_out_clock(struct comedi_device * dev, unsigned int * clo } } -static int ni_freq_out_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int ni_freq_out_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { switch (data[0]) { case INSN_CONFIG_SET_CLOCK_SRC: @@ -4274,11 +4276,11 @@ static int ni_freq_out_insn_config(struct comedi_device * dev, struct comedi_sub return -EINVAL; } -static int ni_alloc_private(struct comedi_device * dev) +static int ni_alloc_private(struct comedi_device *dev) { int ret; - ret = alloc_private(dev, sizeof(ni_private)); + ret = alloc_private(dev, sizeof(struct ni_private)); if (ret < 0) return ret; @@ -4289,7 +4291,7 @@ static int ni_alloc_private(struct comedi_device * dev) return 0; }; -static int ni_E_init(struct comedi_device * dev, struct comedi_devconfig * it) +static int ni_E_init(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; unsigned j; @@ -4419,14 +4421,14 @@ static int ni_E_init(struct comedi_device * dev, struct comedi_devconfig * it) s = dev->subdevices + NI_CALIBRATION_SUBDEV; s->type = COMEDI_SUBD_CALIB; if (boardtype.reg_type & ni_reg_m_series_mask) { - // internal PWM analog output used for AI nonlinearity calibration + /* internal PWM analog output used for AI nonlinearity calibration */ s->subdev_flags = SDF_INTERNAL; s->insn_config = &ni_m_series_pwm_config; s->n_chan = 1; s->maxdata = 0; ni_writel(0x0, M_Offset_Cal_PWM); } else if (boardtype.reg_type == ni_reg_6143) { - // internal PWM analog output used for AI nonlinearity calibration + /* internal PWM analog output used for AI nonlinearity calibration */ s->subdev_flags = SDF_INTERNAL; s->insn_config = &ni_6143_pwm_config; s->n_chan = 1; @@ -4478,7 +4480,7 @@ static int ni_E_init(struct comedi_device * dev, struct comedi_devconfig * it) if (boardtype.reg_type & ni_reg_67xx_mask) { s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE | SDF_DIFF | SDF_INTERNAL; - // one channel for each analog output channel + /* one channel for each analog output channel */ s->n_chan = boardtype.n_aochan; s->maxdata = (1 << 16) - 1; s->range_table = &range_unknown; /* XXX */ @@ -4557,7 +4559,7 @@ static int ni_E_init(struct comedi_device * dev, struct comedi_devconfig * it) /* ai configuration */ ni_ai_reset(dev, dev->subdevices + NI_AI_SUBDEV); if ((boardtype.reg_type & ni_reg_6xxx_mask) == 0) { - // BEAM is this needed for PCI-6143 ?? + /* BEAM is this needed for PCI-6143 ?? */ devpriv->clock_and_fout = Slow_Internal_Time_Divide_By_2 | Slow_Internal_Timebase | @@ -4623,8 +4625,8 @@ static int ni_8255_callback(int dir, int port, int data, unsigned long arg) presents the EEPROM as a subdevice */ -static int ni_eeprom_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int ni_eeprom_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { data[0] = ni_read_eeprom(dev, CR_CHAN(insn->chanspec)); @@ -4635,7 +4637,7 @@ static int ni_eeprom_insn_read(struct comedi_device * dev, struct comedi_subdevi reads bytes out of eeprom */ -static int ni_read_eeprom(struct comedi_device * dev, int addr) +static int ni_read_eeprom(struct comedi_device *dev, int addr) { int bit; int bitstring; @@ -4659,23 +4661,23 @@ static int ni_read_eeprom(struct comedi_device * dev, int addr) return bitstring; } -static int ni_m_series_eeprom_insn_read(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +static int ni_m_series_eeprom_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { data[0] = devpriv->eeprom_buffer[CR_CHAN(insn->chanspec)]; return 1; } -static int ni_get_pwm_config(struct comedi_device * dev, unsigned int * data) +static int ni_get_pwm_config(struct comedi_device *dev, unsigned int *data) { data[1] = devpriv->pwm_up_count * devpriv->clock_ns; data[2] = devpriv->pwm_down_count * devpriv->clock_ns; return 3; } -static int ni_m_series_pwm_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int ni_m_series_pwm_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { unsigned up_count, down_count; switch (data[0]) { @@ -4739,8 +4741,8 @@ static int ni_m_series_pwm_config(struct comedi_device * dev, struct comedi_subd return 0; } -static int ni_6143_pwm_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int ni_6143_pwm_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { unsigned up_count, down_count; switch (data[0]) { @@ -4802,20 +4804,20 @@ static int ni_6143_pwm_config(struct comedi_device * dev, struct comedi_subdevic return 0; } -static void ni_write_caldac(struct comedi_device * dev, int addr, int val); +static void ni_write_caldac(struct comedi_device *dev, int addr, int val); /* calibration subdevice */ -static int ni_calib_insn_write(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int ni_calib_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { ni_write_caldac(dev, CR_CHAN(insn->chanspec), data[0]); return 1; } -static int ni_calib_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int ni_calib_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { data[0] = devpriv->caldacs[CR_CHAN(insn->chanspec)]; @@ -4845,7 +4847,7 @@ static struct caldac_struct caldacs[] = { [ad8804_debug] = {16, 8, pack_ad8804}, }; -static void caldac_setup(struct comedi_device * dev, struct comedi_subdevice * s) +static void caldac_setup(struct comedi_device *dev, struct comedi_subdevice *s) { int i, j; int n_dacs; @@ -4898,13 +4900,13 @@ static void caldac_setup(struct comedi_device * dev, struct comedi_subdevice * s } } -static void ni_write_caldac(struct comedi_device * dev, int addr, int val) +static void ni_write_caldac(struct comedi_device *dev, int addr, int val) { unsigned int loadbit = 0, bits = 0, bit, bitstring = 0; int i; int type; - //printk("ni_write_caldac: chan=%d val=%d\n",addr,val); + /* printk("ni_write_caldac: chan=%d val=%d\n",addr,val); */ if (devpriv->caldacs[addr] == val) return; devpriv->caldacs[addr] = val; @@ -4916,7 +4918,7 @@ static void ni_write_caldac(struct comedi_device * dev, int addr, int val) if (addr < caldacs[type].n_chans) { bits = caldacs[type].packbits(addr, val, &bitstring); loadbit = SerDacLd(i); - //printk("caldac: using i=%d addr=%d %x\n",i,addr,bitstring); + /* printk("caldac: using i=%d addr=%d %x\n",i,addr,bitstring); */ break; } addr -= caldacs[type].n_chans; @@ -4924,12 +4926,12 @@ static void ni_write_caldac(struct comedi_device * dev, int addr, int val) for (bit = 1 << (bits - 1); bit; bit >>= 1) { ni_writeb(((bit & bitstring) ? 0x02 : 0), Serial_Command); - comedi_udelay(1); + udelay(1); ni_writeb(1 | ((bit & bitstring) ? 0x02 : 0), Serial_Command); - comedi_udelay(1); + udelay(1); } ni_writeb(loadbit, Serial_Command); - comedi_udelay(1); + udelay(1); ni_writeb(0, Serial_Command); } @@ -4985,7 +4987,7 @@ static int pack_ad8842(int addr, int val, int *bitstring) /* * Read the GPCTs current value. */ -static int GPCT_G_Watch(struct comedi_device * dev, int chan) +static int GPCT_G_Watch(struct comedi_device *dev, int chan) { unsigned int hi1, hi2, lo; @@ -5008,11 +5010,11 @@ static int GPCT_G_Watch(struct comedi_device * dev, int chan) return (hi1 << 16) | lo; } -static void GPCT_Reset(struct comedi_device * dev, int chan) +static void GPCT_Reset(struct comedi_device *dev, int chan) { int temp_ack_reg = 0; - //printk("GPCT_Reset..."); + /* printk("GPCT_Reset..."); */ devpriv->gpct_cur_operation[chan] = GPCT_RESET; switch (chan) { @@ -5029,7 +5031,7 @@ static void GPCT_Reset(struct comedi_device * dev, int chan) devpriv->stc_writew(dev, temp_ack_reg, Interrupt_A_Ack_Register); - //problem...this interferes with the other ctr... + /* problem...this interferes with the other ctr... */ devpriv->an_trig_etc_reg |= GPFO_0_Output_Enable; devpriv->stc_writew(dev, devpriv->an_trig_etc_reg, Analog_Trigger_Etc_Register); @@ -5065,38 +5067,38 @@ static void GPCT_Reset(struct comedi_device * dev, int chan) G_Input_Select_Register(chan)); devpriv->stc_writew(dev, 0, G_Autoincrement_Register(chan)); - //printk("exit GPCT_Reset\n"); + /* printk("exit GPCT_Reset\n"); */ } #endif -static int ni_gpct_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int ni_gpct_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { struct ni_gpct *counter = s->private; return ni_tio_insn_config(counter, insn, data); } -static int ni_gpct_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int ni_gpct_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { struct ni_gpct *counter = s->private; return ni_tio_rinsn(counter, insn, data); } -static int ni_gpct_insn_write(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int ni_gpct_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { struct ni_gpct *counter = s->private; return ni_tio_winsn(counter, insn, data); } -static int ni_gpct_cmd(struct comedi_device * dev, struct comedi_subdevice * s) +static int ni_gpct_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { int retval; #ifdef PCIDMA struct ni_gpct *counter = s->private; -// const struct comedi_cmd *cmd = &s->async->cmd; +/* const struct comedi_cmd *cmd = &s->async->cmd; */ retval = ni_request_gpct_mite_channel(dev, counter->counter_index, COMEDI_INPUT); @@ -5114,8 +5116,8 @@ static int ni_gpct_cmd(struct comedi_device * dev, struct comedi_subdevice * s) return retval; } -static int ni_gpct_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd) +static int ni_gpct_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd) { #ifdef PCIDMA struct ni_gpct *counter = s->private; @@ -5126,7 +5128,7 @@ static int ni_gpct_cmdtest(struct comedi_device * dev, struct comedi_subdevice * #endif } -static int ni_gpct_cancel(struct comedi_device * dev, struct comedi_subdevice * s) +static int ni_gpct_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { #ifdef PCIDMA struct ni_gpct *counter = s->private; @@ -5147,7 +5149,7 @@ static int ni_gpct_cancel(struct comedi_device * dev, struct comedi_subdevice * * */ -static int ni_m_series_set_pfi_routing(struct comedi_device * dev, unsigned chan, +static int ni_m_series_set_pfi_routing(struct comedi_device *dev, unsigned chan, unsigned source) { unsigned pfi_reg_index; @@ -5165,16 +5167,16 @@ static int ni_m_series_set_pfi_routing(struct comedi_device * dev, unsigned chan return 2; } -static int ni_old_set_pfi_routing(struct comedi_device * dev, unsigned chan, +static int ni_old_set_pfi_routing(struct comedi_device *dev, unsigned chan, unsigned source) { - // pre-m-series boards have fixed signals on pfi pins + /* pre-m-series boards have fixed signals on pfi pins */ if (source != ni_old_get_pfi_routing(dev, chan)) return -EINVAL; return 2; } -static int ni_set_pfi_routing(struct comedi_device * dev, unsigned chan, +static int ni_set_pfi_routing(struct comedi_device *dev, unsigned chan, unsigned source) { if (boardtype.reg_type & ni_reg_m_series_mask) @@ -5183,16 +5185,16 @@ static int ni_set_pfi_routing(struct comedi_device * dev, unsigned chan, return ni_old_set_pfi_routing(dev, chan, source); } -static unsigned ni_m_series_get_pfi_routing(struct comedi_device * dev, unsigned chan) +static unsigned ni_m_series_get_pfi_routing(struct comedi_device *dev, unsigned chan) { const unsigned array_offset = chan / 3; return MSeries_PFI_Output_Select_Source(chan, devpriv->pfi_output_select_reg[array_offset]); } -static unsigned ni_old_get_pfi_routing(struct comedi_device * dev, unsigned chan) +static unsigned ni_old_get_pfi_routing(struct comedi_device *dev, unsigned chan) { - // pre-m-series boards have fixed signals on pfi pins + /* pre-m-series boards have fixed signals on pfi pins */ switch (chan) { case 0: return NI_PFI_OUTPUT_AI_START1; @@ -5225,13 +5227,13 @@ static unsigned ni_old_get_pfi_routing(struct comedi_device * dev, unsigned chan return NI_PFI_OUTPUT_G_GATE0; break; default: - rt_printk("%s: bug, unhandled case in switch.\n", __FUNCTION__); + printk("%s: bug, unhandled case in switch.\n", __func__); break; } return 0; } -static unsigned ni_get_pfi_routing(struct comedi_device * dev, unsigned chan) +static unsigned ni_get_pfi_routing(struct comedi_device *dev, unsigned chan) { if (boardtype.reg_type & ni_reg_m_series_mask) return ni_m_series_get_pfi_routing(dev, chan); @@ -5239,7 +5241,7 @@ static unsigned ni_get_pfi_routing(struct comedi_device * dev, unsigned chan) return ni_old_get_pfi_routing(dev, chan); } -static int ni_config_filter(struct comedi_device * dev, unsigned pfi_channel, +static int ni_config_filter(struct comedi_device *dev, unsigned pfi_channel, enum ni_pfi_filter_select filter) { unsigned bits; @@ -5253,8 +5255,8 @@ static int ni_config_filter(struct comedi_device * dev, unsigned pfi_channel, return 0; } -static int ni_pfi_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int ni_pfi_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if ((boardtype.reg_type & ni_reg_m_series_mask) == 0) { return -ENOTSUPP; @@ -5268,8 +5270,8 @@ static int ni_pfi_insn_bits(struct comedi_device * dev, struct comedi_subdevice return 2; } -static int ni_pfi_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int ni_pfi_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { unsigned int chan; @@ -5312,16 +5314,16 @@ static int ni_pfi_insn_config(struct comedi_device * dev, struct comedi_subdevic * NI RTSI Bus Functions * */ -static void ni_rtsi_init(struct comedi_device * dev) +static void ni_rtsi_init(struct comedi_device *dev) { - // Initialises the RTSI bus signal switch to a default state + /* Initialises the RTSI bus signal switch to a default state */ - // Set clock mode to internal + /* Set clock mode to internal */ devpriv->clock_and_fout2 = MSeries_RTSI_10MHz_Bit; if (ni_set_master_clock(dev, NI_MIO_INTERNAL_CLOCK, 0) < 0) { - rt_printk("ni_set_master_clock failed, bug?"); + printk("ni_set_master_clock failed, bug?"); } - // default internal lines routing to RTSI bus lines + /* default internal lines routing to RTSI bus lines */ devpriv->rtsi_trig_a_output_reg = RTSI_Trig_Output_Bits(0, NI_RTSI_OUTPUT_ADR_START1) | RTSI_Trig_Output_Bits(1, @@ -5341,12 +5343,14 @@ static void ni_rtsi_init(struct comedi_device * dev) devpriv->stc_writew(dev, devpriv->rtsi_trig_b_output_reg, RTSI_Trig_B_Output_Register); - // Sets the source and direction of the 4 on board lines -// devpriv->stc_writew(dev, 0x0000, RTSI_Board_Register); +/* +* Sets the source and direction of the 4 on board lines +* devpriv->stc_writew(dev, 0x0000, RTSI_Board_Register); +*/ } -static int ni_rtsi_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int ni_rtsi_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if (insn->n != 2) return -EINVAL; @@ -5389,8 +5393,8 @@ static int ni_mseries_get_pll_parameters(unsigned reference_period_ns, } } if (best_period_picosec == 0) { - rt_printk("%s: bug, failed to find pll parameters\n", - __FUNCTION__); + printk("%s: bug, failed to find pll parameters\n", + __func__); return -EIO; } *freq_divider = best_div; @@ -5401,7 +5405,7 @@ static int ni_mseries_get_pll_parameters(unsigned reference_period_ns, return 0; } -static inline unsigned num_configurable_rtsi_channels(struct comedi_device * dev) +static inline unsigned num_configurable_rtsi_channels(struct comedi_device *dev) { if (boardtype.reg_type & ni_reg_m_series_mask) return 8; @@ -5409,7 +5413,7 @@ static inline unsigned num_configurable_rtsi_channels(struct comedi_device * dev return 7; } -static int ni_mseries_set_pll_master_clock(struct comedi_device * dev, unsigned source, +static int ni_mseries_set_pll_master_clock(struct comedi_device *dev, unsigned source, unsigned period_ns) { static const unsigned min_period_ns = 50; @@ -5422,11 +5426,11 @@ static int ni_mseries_set_pll_master_clock(struct comedi_device * dev, unsigned int retval; if (source == NI_MIO_PLL_PXI10_CLOCK) period_ns = 100; - // these limits are somewhat arbitrary, but NI advertises 1 to 20MHz range so we'll use that + /* these limits are somewhat arbitrary, but NI advertises 1 to 20MHz range so we'll use that */ if (period_ns < min_period_ns || period_ns > max_period_ns) { - rt_printk + printk ("%s: you must specify an input clock frequency between %i and %i nanosec " - "for the phased-lock loop.\n", __FUNCTION__, + "for the phased-lock loop.\n", __func__, min_period_ns, max_period_ns); return -EINVAL; } @@ -5484,8 +5488,10 @@ static int ni_mseries_set_pll_master_clock(struct comedi_device * dev, unsigned pll_control_bits |= MSeries_PLL_Divisor_Bits(freq_divider) | MSeries_PLL_Multiplier_Bits(freq_multiplier); -// rt_printk("using divider=%i, multiplier=%i for PLL. pll_control_bits = 0x%x\n", freq_divider, freq_multiplier, pll_control_bits); -// rt_printk("clock_ns=%d\n", devpriv->clock_ns); + + /* printk("using divider=%i, multiplier=%i for PLL. pll_control_bits = 0x%x\n", + * freq_divider, freq_multiplier, pll_control_bits); */ + /* printk("clock_ns=%d\n", devpriv->clock_ns); */ ni_writew(pll_control_bits, M_Offset_PLL_Control); devpriv->clock_source = source; /* it seems to typically take a few hundred microseconds for PLL to lock */ @@ -5496,15 +5502,15 @@ static int ni_mseries_set_pll_master_clock(struct comedi_device * dev, unsigned udelay(1); } if (i == timeout) { - rt_printk + printk ("%s: timed out waiting for PLL to lock to reference clock source %i with period %i ns.\n", - __FUNCTION__, source, period_ns); + __func__, source, period_ns); return -ETIMEDOUT; } return 3; } -static int ni_set_master_clock(struct comedi_device * dev, unsigned source, +static int ni_set_master_clock(struct comedi_device *dev, unsigned source, unsigned period_ns) { if (source == NI_MIO_INTERNAL_CLOCK) { @@ -5533,9 +5539,9 @@ static int ni_set_master_clock(struct comedi_device * dev, unsigned source, devpriv->rtsi_trig_direction_reg, RTSI_Trig_Direction_Register); if (period_ns == 0) { - rt_printk + printk ("%s: we don't handle an unspecified clock period correctly yet, returning error.\n", - __FUNCTION__); + __func__); return -EINVAL; } else { devpriv->clock_ns = period_ns; @@ -5548,7 +5554,7 @@ static int ni_set_master_clock(struct comedi_device * dev, unsigned source, return 3; } -static int ni_valid_rtsi_output_source(struct comedi_device * dev, unsigned chan, +static int ni_valid_rtsi_output_source(struct comedi_device *dev, unsigned chan, unsigned source) { if (chan >= num_configurable_rtsi_channels(dev)) { @@ -5556,9 +5562,9 @@ static int ni_valid_rtsi_output_source(struct comedi_device * dev, unsigned chan if (source == NI_RTSI_OUTPUT_RTSI_OSC) return 1; else { - rt_printk + printk ("%s: invalid source for channel=%i, channel %i is always the RTSI clock for pre-m-series boards.\n", - __FUNCTION__, chan, + __func__, chan, old_RTSI_clock_channel); return 0; } @@ -5589,7 +5595,7 @@ static int ni_valid_rtsi_output_source(struct comedi_device * dev, unsigned chan } } -static int ni_set_rtsi_routing(struct comedi_device * dev, unsigned chan, +static int ni_set_rtsi_routing(struct comedi_device *dev, unsigned chan, unsigned source) { if (ni_valid_rtsi_output_source(dev, chan, source) == 0) @@ -5610,7 +5616,7 @@ static int ni_set_rtsi_routing(struct comedi_device * dev, unsigned chan, return 2; } -static unsigned ni_get_rtsi_routing(struct comedi_device * dev, unsigned chan) +static unsigned ni_get_rtsi_routing(struct comedi_device *dev, unsigned chan) { if (chan < 4) { return RTSI_Trig_Output_Source(chan, @@ -5621,13 +5627,13 @@ static unsigned ni_get_rtsi_routing(struct comedi_device * dev, unsigned chan) } else { if (chan == old_RTSI_clock_channel) return NI_RTSI_OUTPUT_RTSI_OSC; - rt_printk("%s: bug! should never get here?\n", __FUNCTION__); + printk("%s: bug! should never get here?\n", __func__); return 0; } } -static int ni_rtsi_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int ni_rtsi_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { unsigned int chan = CR_CHAN(insn->chanspec); switch (data[0]) { @@ -5698,7 +5704,7 @@ static int ni_rtsi_insn_config(struct comedi_device * dev, struct comedi_subdevi return 1; } -static int cs5529_wait_for_idle(struct comedi_device * dev) +static int cs5529_wait_for_idle(struct comedi_device *dev) { unsigned short status; const int timeout = HZ; @@ -5714,15 +5720,15 @@ static int cs5529_wait_for_idle(struct comedi_device * dev) return -EIO; } } -//printk("looped %i times waiting for idle\n", i); +/* printk("looped %i times waiting for idle\n", i); */ if (i == timeout) { - rt_printk("%s: %s: timeout\n", __FILE__, __FUNCTION__); + printk("%s: %s: timeout\n", __FILE__, __func__); return -ETIME; } return 0; } -static void cs5529_command(struct comedi_device * dev, unsigned short value) +static void cs5529_command(struct comedi_device *dev, unsigned short value) { static const int timeout = 100; int i; @@ -5735,16 +5741,16 @@ static void cs5529_command(struct comedi_device * dev, unsigned short value) for (i = 0; i < timeout; i++) { if ((ni_ao_win_inw(dev, CAL_ADC_Status_67xx) & CSS_ADC_BUSY)) break; - comedi_udelay(1); + udelay(1); } -//printk("looped %i times writing command to cs5529\n", i); +/* printk("looped %i times writing command to cs5529\n", i); */ if (i == timeout) { comedi_error(dev, "possible problem - never saw adc go busy?"); } } /* write to cs5529 register */ -static void cs5529_config_write(struct comedi_device * dev, unsigned int value, +static void cs5529_config_write(struct comedi_device *dev, unsigned int value, unsigned int reg_select_bits) { ni_ao_win_outw(dev, ((value >> 16) & 0xff), @@ -5759,7 +5765,7 @@ static void cs5529_config_write(struct comedi_device * dev, unsigned int value, #ifdef NI_CS5529_DEBUG /* read from cs5529 register */ -static unsigned int cs5529_config_read(struct comedi_device * dev, +static unsigned int cs5529_config_read(struct comedi_device *dev, unsigned int reg_select_bits) { unsigned int value; @@ -5775,7 +5781,7 @@ static unsigned int cs5529_config_read(struct comedi_device * dev, } #endif -static int cs5529_do_conversion(struct comedi_device * dev, unsigned short *data) +static int cs5529_do_conversion(struct comedi_device *dev, unsigned short *data) { int retval; unsigned short status; @@ -5789,12 +5795,12 @@ static int cs5529_do_conversion(struct comedi_device * dev, unsigned short *data } status = ni_ao_win_inw(dev, CAL_ADC_Status_67xx); if (status & CSS_OSC_DETECT) { - rt_printk + printk ("ni_mio_common: cs5529 conversion error, status CSS_OSC_DETECT\n"); return -EIO; } if (status & CSS_OVERRANGE) { - rt_printk + printk ("ni_mio_common: cs5529 conversion error, overrange (ignoring)\n"); } if (data) { @@ -5805,8 +5811,8 @@ static int cs5529_do_conversion(struct comedi_device * dev, unsigned short *data return 0; } -static int cs5529_ai_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int cs5529_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int n, retval; unsigned short sample; @@ -5831,7 +5837,7 @@ static int cs5529_ai_insn_read(struct comedi_device * dev, struct comedi_subdevi return insn->n; } -static int init_cs5529(struct comedi_device * dev) +static int init_cs5529(struct comedi_device *dev) { unsigned int config_bits = CSCFG_PORT_MODE | CSCFG_WORD_RATE_2180_CYCLES; @@ -5851,11 +5857,11 @@ static int init_cs5529(struct comedi_device * dev) comedi_error(dev, "timeout or signal in init_cs5529()\n"); #endif #ifdef NI_CS5529_DEBUG - rt_printk("config: 0x%x\n", cs5529_config_read(dev, + printk("config: 0x%x\n", cs5529_config_read(dev, CSCMD_CONFIG_REGISTER)); - rt_printk("gain: 0x%x\n", cs5529_config_read(dev, + printk("gain: 0x%x\n", cs5529_config_read(dev, CSCMD_GAIN_REGISTER)); - rt_printk("offset: 0x%x\n", cs5529_config_read(dev, + printk("offset: 0x%x\n", cs5529_config_read(dev, CSCMD_OFFSET_REGISTER)); #endif return 0; diff --git a/drivers/staging/comedi/drivers/ni_mio_cs.c b/drivers/staging/comedi/drivers/ni_mio_cs.c index d6357c25aca5..4d408d410c24 100644 --- a/drivers/staging/comedi/drivers/ni_mio_cs.c +++ b/drivers/staging/comedi/drivers/ni_mio_cs.c @@ -66,103 +66,103 @@ See the notes in the ni_atmio.o driver. #define MAX_N_CALDACS 32 -static const ni_board ni_boards[] = { - {device_id:0x010d, - name: "DAQCard-ai-16xe-50", - n_adchan:16, - adbits: 16, - ai_fifo_depth:1024, - alwaysdither:0, - gainlkup:ai_gain_8, - ai_speed:5000, - n_aochan:0, - aobits: 0, - ao_fifo_depth:0, - ao_unipolar:0, - num_p0_dio_channels:8, - has_8255:0, - caldac: {dac8800, dac8043}, - }, - {device_id:0x010c, - name: "DAQCard-ai-16e-4", - n_adchan:16, - adbits: 12, - ai_fifo_depth:1024, - alwaysdither:0, - gainlkup:ai_gain_16, - ai_speed:4000, - n_aochan:0, - aobits: 0, - ao_fifo_depth:0, - ao_unipolar:0, - num_p0_dio_channels:8, - has_8255:0, - caldac: {mb88341}, /* verified */ - }, - {device_id:0x02c4, - name: "DAQCard-6062E", - n_adchan:16, - adbits: 12, - ai_fifo_depth:8192, - alwaysdither:0, - gainlkup:ai_gain_16, - ai_speed:2000, - n_aochan:2, - aobits: 12, - ao_fifo_depth:2048, - ao_range_table:&range_bipolar10, - ao_unipolar:0, - ao_speed:1176, - num_p0_dio_channels:8, - has_8255:0, - caldac: {ad8804_debug}, /* verified */ - }, - {device_id:0x075e, - name: "DAQCard-6024E", /* specs incorrect! */ - n_adchan:16, - adbits: 12, - ai_fifo_depth:1024, - alwaysdither:0, - gainlkup:ai_gain_16, - ai_speed:5000, - n_aochan:2, - aobits: 12, - ao_fifo_depth:0, - ao_range_table:&range_bipolar10, - ao_unipolar:0, - ao_speed:1000000, - num_p0_dio_channels:8, - has_8255:0, - caldac: {ad8804_debug}, - }, - {device_id:0x0245, - name: "DAQCard-6036E", /* specs incorrect! */ - n_adchan:16, - adbits: 16, - ai_fifo_depth:1024, - alwaysdither:1, - gainlkup:ai_gain_4, - ai_speed:5000, - n_aochan:2, - aobits: 16, - ao_fifo_depth:0, - ao_range_table:&range_bipolar10, - ao_unipolar:0, - ao_speed:1000000, - num_p0_dio_channels:8, - has_8255:0, - caldac: {ad8804_debug}, - }, +static const struct ni_board_struct ni_boards[] = { + {.device_id = 0x010d, + .name = "DAQCard-ai-16xe-50", + .n_adchan = 16, + .adbits = 16, + .ai_fifo_depth = 1024, + .alwaysdither = 0, + .gainlkup = ai_gain_8, + .ai_speed = 5000, + .n_aochan = 0, + .aobits = 0, + .ao_fifo_depth = 0, + .ao_unipolar = 0, + .num_p0_dio_channels = 8, + .has_8255 = 0, + .caldac = {dac8800, dac8043}, + }, + {.device_id = 0x010c, + .name = "DAQCard-ai-16e-4", + .n_adchan = 16, + .adbits = 12, + .ai_fifo_depth = 1024, + .alwaysdither = 0, + .gainlkup = ai_gain_16, + .ai_speed = 4000, + .n_aochan = 0, + .aobits = 0, + .ao_fifo_depth = 0, + .ao_unipolar = 0, + .num_p0_dio_channels = 8, + .has_8255 = 0, + .caldac = {mb88341}, /* verified */ + }, + {.device_id = 0x02c4, + .name = "DAQCard-6062E", + .n_adchan = 16, + .adbits = 12, + .ai_fifo_depth = 8192, + .alwaysdither = 0, + .gainlkup = ai_gain_16, + .ai_speed = 2000, + .n_aochan = 2, + .aobits = 12, + .ao_fifo_depth = 2048, + .ao_range_table = &range_bipolar10, + .ao_unipolar = 0, + .ao_speed = 1176, + .num_p0_dio_channels = 8, + .has_8255 = 0, + .caldac = {ad8804_debug}, /* verified */ + }, + {.device_id = 0x075e, + .name = "DAQCard-6024E", /* specs incorrect! */ + .n_adchan = 16, + .adbits = 12, + .ai_fifo_depth = 1024, + .alwaysdither = 0, + .gainlkup = ai_gain_16, + .ai_speed = 5000, + .n_aochan = 2, + .aobits = 12, + .ao_fifo_depth = 0, + .ao_range_table = &range_bipolar10, + .ao_unipolar = 0, + .ao_speed = 1000000, + .num_p0_dio_channels = 8, + .has_8255 = 0, + .caldac = {ad8804_debug}, + }, + {.device_id = 0x0245, + .name = "DAQCard-6036E", /* specs incorrect! */ + .n_adchan = 16, + .adbits = 16, + .ai_fifo_depth = 1024, + .alwaysdither = 1, + .gainlkup = ai_gain_4, + .ai_speed = 5000, + .n_aochan = 2, + .aobits = 16, + .ao_fifo_depth = 0, + .ao_range_table = &range_bipolar10, + .ao_unipolar = 0, + .ao_speed = 1000000, + .num_p0_dio_channels = 8, + .has_8255 = 0, + .caldac = {ad8804_debug}, + }, #if 0 - {device_id:0x0000, /* unknown */ - name: "DAQCard-6715", - n_adchan:0, - n_aochan:8, - aobits: 12, - ao_671x: 8192, - num_p0_dio_channels:8, - caldac: {mb88341, mb88341}, - }, + {.device_id = 0x0000, /* unknown */ + .name = "DAQCard-6715", + .n_adchan = 0, + .n_aochan = 8, + .aobits = 12, + .ao_671x = 8192, + .num_p0_dio_channels = 8, + .caldac = {mb88341, mb88341}, + }, #endif /* N.B. Update ni_mio_cs_ids[] when entries added above. */ }; @@ -183,11 +183,11 @@ struct ni_private { /* How we access registers */ -#define ni_writel(a,b) (outl((a),(b)+dev->iobase)) +#define ni_writel(a, b) (outl((a), (b)+dev->iobase)) #define ni_readl(a) (inl((a)+dev->iobase)) -#define ni_writew(a,b) (outw((a),(b)+dev->iobase)) +#define ni_writew(a, b) (outw((a), (b)+dev->iobase)) #define ni_readw(a) (inw((a)+dev->iobase)) -#define ni_writeb(a,b) (outb((a),(b)+dev->iobase)) +#define ni_writeb(a, b) (outb((a), (b)+dev->iobase)) #define ni_readb(a) (inb((a)+dev->iobase)) /* How we access windowed registers */ @@ -196,60 +196,60 @@ struct ni_private { * read/written directly in the I/O space of the board. The * DAQCard devices map the low 8 STC registers to iobase+addr*2. */ -static void mio_cs_win_out(struct comedi_device * dev, uint16_t data, int addr) +static void mio_cs_win_out(struct comedi_device *dev, uint16_t data, int addr) { unsigned long flags; - comedi_spin_lock_irqsave(&devpriv->window_lock, flags); + spin_lock_irqsave(&devpriv->window_lock, flags); if (addr < 8) { ni_writew(data, addr * 2); } else { ni_writew(addr, Window_Address); ni_writew(data, Window_Data); } - comedi_spin_unlock_irqrestore(&devpriv->window_lock, flags); + spin_unlock_irqrestore(&devpriv->window_lock, flags); } -static uint16_t mio_cs_win_in(struct comedi_device * dev, int addr) +static uint16_t mio_cs_win_in(struct comedi_device *dev, int addr) { unsigned long flags; uint16_t ret; - comedi_spin_lock_irqsave(&devpriv->window_lock, flags); + spin_lock_irqsave(&devpriv->window_lock, flags); if (addr < 8) { ret = ni_readw(addr * 2); } else { ni_writew(addr, Window_Address); ret = ni_readw(Window_Data); } - comedi_spin_unlock_irqrestore(&devpriv->window_lock, flags); + spin_unlock_irqrestore(&devpriv->window_lock, flags); return ret; } -static int mio_cs_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int mio_cs_detach(struct comedi_device * dev); +static int mio_cs_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int mio_cs_detach(struct comedi_device *dev); static struct comedi_driver driver_ni_mio_cs = { - driver_name:"ni_mio_cs", - module:THIS_MODULE, - attach:mio_cs_attach, - detach:mio_cs_detach, + .driver_name = "ni_mio_cs", + .module = THIS_MODULE, + .attach = mio_cs_attach, + .detach = mio_cs_detach, }; #include "ni_mio_common.c" -static int ni_getboardtype(struct comedi_device * dev, struct pcmcia_device *link); +static int ni_getboardtype(struct comedi_device *dev, struct pcmcia_device *link); /* clean up allocated resources */ /* called when driver is removed */ -static int mio_cs_detach(struct comedi_device * dev) +static int mio_cs_detach(struct comedi_device *dev) { mio_common_detach(dev); /* PCMCIA layer frees the IO region */ if (dev->irq) { - comedi_free_irq(dev->irq, dev); + free_irq(dev->irq, dev); } return 0; @@ -344,7 +344,7 @@ static void mio_cs_config(struct pcmcia_device *link) manfid = le16_to_cpu(buf[0]); prodid = le16_to_cpu(buf[1]); } - //printk("manfid = 0x%04x, 0x%04x\n",manfid,prodid); + /* printk("manfid = 0x%04x, 0x%04x\n",manfid,prodid); */ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; tuple.Attributes = 0; @@ -381,7 +381,7 @@ static void mio_cs_config(struct pcmcia_device *link) for (base = 0x000; base < 0x400; base += 0x20) { link->io.BasePort1 = base; ret = pcmcia_request_io(link, &link->io); - //printk("RequestIO 0x%02x\n",ret); + /* printk("RequestIO 0x%02x\n",ret); */ if (!ret) break; } @@ -393,17 +393,17 @@ static void mio_cs_config(struct pcmcia_device *link) if (ret) { printk("pcmcia_request_irq() returned error: %i\n", ret); } - //printk("RequestIRQ 0x%02x\n",ret); + /* printk("RequestIRQ 0x%02x\n",ret); */ link->conf.ConfigIndex = 1; ret = pcmcia_request_configuration(link, &link->conf); - //printk("RequestConfiguration %d\n",ret); + /* printk("RequestConfiguration %d\n",ret); */ link->dev_node = &dev_node; } -static int mio_cs_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int mio_cs_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct pcmcia_device *link; unsigned int irq; @@ -446,29 +446,33 @@ static int mio_cs_attach(struct comedi_device * dev, struct comedi_devconfig * i printk(" %s", boardtype.name); dev->board_name = boardtype.name; - if ((ret = comedi_request_irq(irq, ni_E_interrupt, NI_E_IRQ_FLAGS, - "ni_mio_cs", dev)) < 0) { + ret = request_irq(irq, ni_E_interrupt, NI_E_IRQ_FLAGS, + "ni_mio_cs", dev); + if (ret < 0) { printk(" irq not available\n"); return -EINVAL; } dev->irq = irq; /* allocate private area */ - if ((ret = ni_alloc_private(dev)) < 0) + ret = ni_alloc_private(dev); + if (ret < 0) return ret; + devpriv->stc_writew = &mio_cs_win_out; devpriv->stc_readw = &mio_cs_win_in; devpriv->stc_writel = &win_out2; devpriv->stc_readl = &win_in2; - if ((ret = ni_E_init(dev, it)) < 0) { + ret = ni_E_init(dev, it); + + if (ret < 0) return ret; - } return 0; } -static int get_prodid(struct comedi_device * dev, struct pcmcia_device *link) +static int get_prodid(struct comedi_device *dev, struct pcmcia_device *link) { tuple_t tuple; u_short buf[128]; @@ -487,7 +491,7 @@ static int get_prodid(struct comedi_device * dev, struct pcmcia_device *link) return prodid; } -static int ni_getboardtype(struct comedi_device * dev, struct pcmcia_device *link) +static int ni_getboardtype(struct comedi_device *dev, struct pcmcia_device *link) { int id; int i; diff --git a/drivers/staging/comedi/drivers/ni_pcidio.c b/drivers/staging/comedi/drivers/ni_pcidio.c index 87def2cc9a29..6b86a39aac5e 100644 --- a/drivers/staging/comedi/drivers/ni_pcidio.c +++ b/drivers/staging/comedi/drivers/ni_pcidio.c @@ -66,9 +66,10 @@ comedi_nonfree_firmware tarball available from http://www.comedi.org */ #define USE_DMA -//#define DEBUG 1 -//#define DEBUG_FLAGS +/* #define DEBUG 1 */ +/* #define DEBUG_FLAGS */ +#include #include "../comedidev.h" #include "mite.h" @@ -117,9 +118,9 @@ comedi_nonfree_firmware tarball available from http://www.comedi.org #define Waited (1<<5) #define PrimaryTC (1<<6) #define SecondaryTC (1<<7) - //#define SerialRose - //#define ReqRose - //#define Paused + /* #define SerialRose */ + /* #define ReqRose */ + /* #define Paused */ #define Group_1_First_Clear 6 /* W */ #define Group_2_First_Clear 7 /* W */ @@ -206,7 +207,7 @@ comedi_nonfree_firmware tarball available from http://www.comedi.org #define DMA_Line_Control_Group1 76 #define DMA_Line_Control_Group2 108 -// channel zero is none +/* channel zero is none */ static inline unsigned primary_DMAChannel_bits(unsigned channel) { return channel & 0x3; @@ -287,15 +288,15 @@ enum FPGA_Control_Bits { #define IntEn (TransferReady|CountExpired|Waited|PrimaryTC|SecondaryTC) #endif -static int nidio_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int nidio_detach(struct comedi_device * dev); -static int ni_pcidio_cancel(struct comedi_device * dev, struct comedi_subdevice * s); +static int nidio_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int nidio_detach(struct comedi_device *dev); +static int ni_pcidio_cancel(struct comedi_device *dev, struct comedi_subdevice *s); static struct comedi_driver driver_pcidio = { - driver_name:"ni_pcidio", - module:THIS_MODULE, - attach:nidio_attach, - detach:nidio_detach, + .driver_name = "ni_pcidio", + .module = THIS_MODULE, + .attach = nidio_attach, + .detach = nidio_detach, }; struct nidio_board { @@ -309,65 +310,65 @@ struct nidio_board { static const struct nidio_board nidio_boards[] = { { - dev_id: 0x1150, - name: "pci-dio-32hs", - n_8255: 0, - is_diodaq:1, + .dev_id = 0x1150, + .name = "pci-dio-32hs", + .n_8255 = 0, + .is_diodaq = 1, }, { - dev_id: 0x1320, - name: "pxi-6533", - n_8255: 0, - is_diodaq:1, + .dev_id = 0x1320, + .name = "pxi-6533", + .n_8255 = 0, + .is_diodaq = 1, }, { - dev_id: 0x12b0, - name: "pci-6534", - n_8255: 0, - is_diodaq:1, - uses_firmware:1, + .dev_id = 0x12b0, + .name = "pci-6534", + .n_8255 = 0, + .is_diodaq = 1, + .uses_firmware = 1, }, { - dev_id: 0x0160, - name: "pci-dio-96", - n_8255: 4, - is_diodaq:0, + .dev_id = 0x0160, + .name = "pci-dio-96", + .n_8255 = 4, + .is_diodaq = 0, }, { - dev_id: 0x1630, - name: "pci-dio-96b", - n_8255: 4, - is_diodaq:0, + .dev_id = 0x1630, + .name = "pci-dio-96b", + .n_8255 = 4, + .is_diodaq = 0, }, { - dev_id: 0x13c0, - name: "pxi-6508", - n_8255: 4, - is_diodaq:0, + .dev_id = 0x13c0, + .name = "pxi-6508", + .n_8255 = 4, + .is_diodaq = 0, }, { - dev_id: 0x0400, - name: "pci-6503", - n_8255: 1, - is_diodaq:0, + .dev_id = 0x0400, + .name = "pci-6503", + .n_8255 = 1, + .is_diodaq = 0, }, { - dev_id: 0x1250, - name: "pci-6503b", - n_8255: 1, - is_diodaq:0, + .dev_id = 0x1250, + .name = "pci-6503b", + .n_8255 = 1, + .is_diodaq = 0, }, { - dev_id: 0x17d0, - name: "pci-6503x", - n_8255: 1, - is_diodaq:0, + .dev_id = 0x17d0, + .name = "pci-6503x", + .n_8255 = 1, + .is_diodaq = 0, }, { - dev_id: 0x1800, - name: "pxi-6503", - n_8255: 1, - is_diodaq:0, + .dev_id = 0x1800, + .name = "pxi-6503", + .n_8255 = 1, + .is_diodaq = 0, }, }; @@ -401,14 +402,14 @@ struct nidio96_private { }; #define devpriv ((struct nidio96_private *)dev->private) -static int ni_pcidio_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd); -static int ni_pcidio_cmd(struct comedi_device * dev, struct comedi_subdevice * s); -static int ni_pcidio_inttrig(struct comedi_device * dev, struct comedi_subdevice * s, +static int ni_pcidio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd); +static int ni_pcidio_cmd(struct comedi_device *dev, struct comedi_subdevice *s); +static int ni_pcidio_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int trignum); -static int nidio_find_device(struct comedi_device * dev, int bus, int slot); +static int nidio_find_device(struct comedi_device *dev, int bus, int slot); static int ni_pcidio_ns_to_timer(int *nanosec, int round_mode); -static int setup_mite_dma(struct comedi_device * dev, struct comedi_subdevice * s); +static int setup_mite_dma(struct comedi_device *dev, struct comedi_subdevice *s); #ifdef DEBUG_FLAGS static void ni_pcidio_print_flags(unsigned int flags); @@ -418,18 +419,17 @@ static void ni_pcidio_print_status(unsigned int status); #define ni_pcidio_print_status(x) #endif -static int ni_pcidio_request_di_mite_channel(struct comedi_device * dev) +static int ni_pcidio_request_di_mite_channel(struct comedi_device *dev) { unsigned long flags; - comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags); + spin_lock_irqsave(&devpriv->mite_channel_lock, flags); BUG_ON(devpriv->di_mite_chan); devpriv->di_mite_chan = mite_request_channel_in_range(devpriv->mite, devpriv->di_mite_ring, 1, 2); if (devpriv->di_mite_chan == NULL) { - comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, - flags); + spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); comedi_error(dev, "failed to reserve mite dma channel."); return -EBUSY; } @@ -437,15 +437,15 @@ static int ni_pcidio_request_di_mite_channel(struct comedi_device * dev) secondary_DMAChannel_bits(devpriv->di_mite_chan->channel), devpriv->mite->daq_io_addr + DMA_Line_Control_Group1); mmiowb(); - comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); + spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); return 0; } -static void ni_pcidio_release_di_mite_channel(struct comedi_device * dev) +static void ni_pcidio_release_di_mite_channel(struct comedi_device *dev) { unsigned long flags; - comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, flags); + spin_lock_irqsave(&devpriv->mite_channel_lock, flags); if (devpriv->di_mite_chan) { mite_dma_disarm(devpriv->di_mite_chan); mite_dma_reset(devpriv->di_mite_chan); @@ -456,7 +456,7 @@ static void ni_pcidio_release_di_mite_channel(struct comedi_device * dev) devpriv->mite->daq_io_addr + DMA_Line_Control_Group1); mmiowb(); } - comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); + spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); } static int nidio96_8255_cb(int dir, int port, int data, unsigned long iobase) @@ -469,7 +469,7 @@ static int nidio96_8255_cb(int dir, int port, int data, unsigned long iobase) } } -void ni_pcidio_event(struct comedi_device * dev, struct comedi_subdevice * s) +void ni_pcidio_event(struct comedi_device *dev, struct comedi_subdevice *s) { if (s->async-> events & (COMEDI_CB_EOA | COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW)) @@ -479,14 +479,14 @@ void ni_pcidio_event(struct comedi_device * dev, struct comedi_subdevice * s) comedi_event(dev, s); } -static irqreturn_t nidio_interrupt(int irq, void *d PT_REGS_ARG) +static irqreturn_t nidio_interrupt(int irq, void *d) { struct comedi_device *dev = d; struct comedi_subdevice *s = dev->subdevices; struct comedi_async *async = s->async; struct mite_struct *mite = devpriv->mite; - //int i, j; + /* int i, j; */ long int AuxData = 0; short data1 = 0; short data2 = 0; @@ -496,9 +496,9 @@ static irqreturn_t nidio_interrupt(int irq, void *d PT_REGS_ARG) unsigned int m_status = 0; unsigned long irq_flags; - //interrupcions parasites + /* interrupcions parasites */ if (dev->attached == 0) { - // assume it's from another card + /* assume it's from another card */ return IRQ_NONE; } @@ -511,17 +511,17 @@ static irqreturn_t nidio_interrupt(int irq, void *d PT_REGS_ARG) ni_pcidio_print_flags(flags); ni_pcidio_print_status(status); - //printk("buf[0]=%08x\n",*(unsigned int *)async->prealloc_buf); - //printk("buf[4096]=%08x\n",*(unsigned int *)(async->prealloc_buf+4096)); + /* printk("buf[0]=%08x\n",*(unsigned int *)async->prealloc_buf); */ + /* printk("buf[4096]=%08x\n",*(unsigned int *)(async->prealloc_buf+4096)); */ - comedi_spin_lock_irqsave(&devpriv->mite_channel_lock, irq_flags); + spin_lock_irqsave(&devpriv->mite_channel_lock, irq_flags); if (devpriv->di_mite_chan) m_status = mite_get_status(devpriv->di_mite_chan); #ifdef MITE_DEBUG mite_print_chsr(m_status); #endif - //printk("mite_bytes_transferred: %d\n",mite_bytes_transferred(mite,DI_DMA_CHAN)); - //mite_dump_regs(mite); + /* printk("mite_bytes_transferred: %d\n",mite_bytes_transferred(mite,DI_DMA_CHAN)); */ + /* mite_dump_regs(mite); */ if (m_status & CHSR_INT) { if (m_status & CHSR_LINKC) { writel(CHOR_CLRLC, @@ -537,7 +537,7 @@ static irqreturn_t nidio_interrupt(int irq, void *d PT_REGS_ARG) disable_irq(dev->irq); } } - comedi_spin_unlock_irqrestore(&devpriv->mite_channel_lock, irq_flags); + spin_unlock_irqrestore(&devpriv->mite_channel_lock, irq_flags); while (status & DataLeft) { work++; @@ -552,7 +552,7 @@ static irqreturn_t nidio_interrupt(int irq, void *d PT_REGS_ARG) flags &= IntEn; if (flags & TransferReady) { - //DPRINTK("TransferReady\n"); + /* DPRINTK("TransferReady\n"); */ while (flags & TransferReady) { work++; if (work > 100) { @@ -569,14 +569,14 @@ static irqreturn_t nidio_interrupt(int irq, void *d PT_REGS_ARG) data2 = (AuxData & 0xffff0000) >> 16; comedi_buf_put(async, data1); comedi_buf_put(async, data2); - //DPRINTK("read:%d, %d\n",data1,data2); + /* DPRINTK("read:%d, %d\n",data1,data2); */ flags = readb(devpriv->mite->daq_io_addr + Group_1_Flags); } - //DPRINTK("buf_int_count: %d\n",async->buf_int_count); - //DPRINTK("1) IntEn=%d,flags=%d,status=%d\n",IntEn,flags,status); - //ni_pcidio_print_flags(flags); - //ni_pcidio_print_status(status); + /* DPRINTK("buf_int_count: %d\n",async->buf_int_count); */ + /* DPRINTK("1) IntEn=%d,flags=%d,status=%d\n",IntEn,flags,status); */ + /* ni_pcidio_print_flags(flags); */ + /* ni_pcidio_print_status(status); */ async->events |= COMEDI_CB_BLOCK; } @@ -621,10 +621,10 @@ static irqreturn_t nidio_interrupt(int irq, void *d PT_REGS_ARG) flags = readb(devpriv->mite->daq_io_addr + Group_1_Flags); status = readb(devpriv->mite->daq_io_addr + Interrupt_And_Window_Status); - //DPRINTK("loop end: IntEn=0x%02x,flags=0x%02x,status=0x%02x\n", - // IntEn,flags,status); - //ni_pcidio_print_flags(flags); - //ni_pcidio_print_status(status); + /* DPRINTK("loop end: IntEn=0x%02x,flags=0x%02x,status=0x%02x\n", */ + /* IntEn,flags,status); */ + /* ni_pcidio_print_flags(flags); */ + /* ni_pcidio_print_status(status); */ } out: @@ -963,7 +963,7 @@ static int ni_pcidio_cmd(struct comedi_device * dev, struct comedi_subdevice * s /* clear and enable interrupts */ writeb(0xff, devpriv->mite->daq_io_addr + Group_1_First_Clear); - //writeb(ClearExpired,devpriv->mite->daq_io_addr+Group_1_Second_Clear); + /* writeb(ClearExpired,devpriv->mite->daq_io_addr+Group_1_Second_Clear); */ writeb(IntEn, devpriv->mite->daq_io_addr + Interrupt_Control); writeb(0x03, @@ -971,7 +971,7 @@ static int ni_pcidio_cmd(struct comedi_device * dev, struct comedi_subdevice * s if (cmd->stop_src == TRIG_NONE) { devpriv->OpModeBits = DataLatching(0) | RunMode(7); - } else { // TRIG_TIMER + } else { /* TRIG_TIMER */ devpriv->OpModeBits = Numbered | RunMode(7); } if (cmd->start_src == TRIG_NOW) { @@ -1235,8 +1235,8 @@ static int nidio_attach(struct comedi_device * dev, struct comedi_devconfig * it devpriv->mite->daq_io_addr + Master_DMA_And_Interrupt_Control); - ret = comedi_request_irq(irq, nidio_interrupt, IRQF_SHARED, - "ni_pcidio", dev); + ret = request_irq(irq, nidio_interrupt, IRQF_SHARED, + "ni_pcidio", dev); if (ret < 0) { printk(" irq not available"); } @@ -1259,7 +1259,7 @@ static int nidio_detach(struct comedi_device * dev) } if (dev->irq) - comedi_free_irq(dev->irq, dev); + free_irq(dev->irq, dev); if (devpriv) { if (devpriv->di_mite_ring) { diff --git a/drivers/staging/comedi/drivers/ni_pcimio.c b/drivers/staging/comedi/drivers/ni_pcimio.c index 3a2aba7c8dd3..1d04b75dec22 100644 --- a/drivers/staging/comedi/drivers/ni_pcimio.c +++ b/drivers/staging/comedi/drivers/ni_pcimio.c @@ -101,7 +101,7 @@ Bugs: need to slow down DAC loading. I don't trust NI's claim that two writes to the PCI bus slows IO enough. I would prefer to - use comedi_udelay(). Timing specs: (clock) + use udelay(). Timing specs: (clock) AD8522 30ns DAC8043 120ns DAC8800 60ns @@ -117,7 +117,7 @@ Bugs: #include "ni_stc.h" #include "mite.h" -//#define PCI_DEBUG +/* #define PCI_DEBUG */ #define PCIDMA @@ -216,9 +216,9 @@ static const struct comedi_lrange range_ni_M_622x_ao = { 1, { } }; -static const ni_board ni_boards[] = { +static const struct ni_board_struct ni_boards[] = { { - .device_id = 0x0162, // NI also says 0x1620. typo? + .device_id = 0x0162, /* NI also says 0x1620. typo? */ .name = "pci-mio-16xe-50", .n_adchan = 16, .adbits = 16, @@ -238,7 +238,7 @@ static const ni_board ni_boards[] = { }, { .device_id = 0x1170, - .name = "pci-mio-16xe-10", // aka pci-6030E + .name = "pci-mio-16xe-10", /* aka pci-6030E */ .n_adchan = 16, .adbits = 16, .ai_fifo_depth = 512, @@ -320,7 +320,7 @@ static const ni_board ni_boards[] = { .ai_fifo_depth = 512, .alwaysdither = 0, .gainlkup = ai_gain_16, - /* Note: there have been reported problems with full speed + /* .Note = there have been reported problems with full speed * on this board */ .ai_speed = 2000, .n_aochan = 2, @@ -330,7 +330,7 @@ static const ni_board ni_boards[] = { .ao_unipolar = 1, .ao_speed = 1000, .num_p0_dio_channels = 8, - .caldac = {ad8804_debug}, // doc says mb88341 + .caldac = {ad8804_debug}, /* doc says mb88341 */ .has_8255 = 0, }, { @@ -846,7 +846,7 @@ static const ni_board ni_boards[] = { .n_adchan = 16, .adbits = 16, .ai_fifo_depth = 512, - //FIXME: guess + /* .FIXME = guess */ .gainlkup = ai_gain_622x, .ai_speed = 4000, .n_aochan = 0, @@ -1207,28 +1207,29 @@ static const ni_board ni_boards[] = { #define n_pcimio_boards ((sizeof(ni_boards)/sizeof(ni_boards[0]))) -static int pcimio_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int pcimio_detach(struct comedi_device * dev); +static int pcimio_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int pcimio_detach(struct comedi_device *dev); static struct comedi_driver driver_pcimio = { - driver_name: DRV_NAME, - module:THIS_MODULE, - attach:pcimio_attach, - detach:pcimio_detach, + .driver_name = DRV_NAME, + .module = THIS_MODULE, + .attach = pcimio_attach, + .detach = pcimio_detach, }; COMEDI_PCI_INITCLEANUP(driver_pcimio, ni_pci_table) -typedef struct { -NI_PRIVATE_COMMON} ni_private; -#define devpriv ((ni_private *)dev->private) +struct ni_private { + NI_PRIVATE_COMMON +}; +#define devpriv ((struct ni_private *)dev->private) /* How we access registers */ -#define ni_writel(a,b) (writel((a), devpriv->mite->daq_io_addr + (b))) +#define ni_writel(a, b) (writel((a), devpriv->mite->daq_io_addr + (b))) #define ni_readl(a) (readl(devpriv->mite->daq_io_addr + (a))) -#define ni_writew(a,b) (writew((a), devpriv->mite->daq_io_addr + (b))) +#define ni_writew(a, b) (writew((a), devpriv->mite->daq_io_addr + (b))) #define ni_readw(a) (readw(devpriv->mite->daq_io_addr + (a))) -#define ni_writeb(a,b) (writeb((a), devpriv->mite->daq_io_addr + (b))) +#define ni_writeb(a, b) (writeb((a), devpriv->mite->daq_io_addr + (b))) #define ni_readb(a) (readb(devpriv->mite->daq_io_addr + (a))) /* How we access STC registers */ @@ -1241,30 +1242,30 @@ NI_PRIVATE_COMMON} ni_private; /* However, the 611x boards still aren't working, so I'm disabling * non-windowed STC access temporarily */ -static void e_series_win_out(struct comedi_device * dev, uint16_t data, int reg) +static void e_series_win_out(struct comedi_device *dev, uint16_t data, int reg) { unsigned long flags; - comedi_spin_lock_irqsave(&devpriv->window_lock, flags); + spin_lock_irqsave(&devpriv->window_lock, flags); ni_writew(reg, Window_Address); ni_writew(data, Window_Data); - comedi_spin_unlock_irqrestore(&devpriv->window_lock, flags); + spin_unlock_irqrestore(&devpriv->window_lock, flags); } -static uint16_t e_series_win_in(struct comedi_device * dev, int reg) +static uint16_t e_series_win_in(struct comedi_device *dev, int reg) { unsigned long flags; uint16_t ret; - comedi_spin_lock_irqsave(&devpriv->window_lock, flags); + spin_lock_irqsave(&devpriv->window_lock, flags); ni_writew(reg, Window_Address); ret = ni_readw(Window_Data); - comedi_spin_unlock_irqrestore(&devpriv->window_lock, flags); + spin_unlock_irqrestore(&devpriv->window_lock, flags); return ret; } -static void m_series_stc_writew(struct comedi_device * dev, uint16_t data, int reg) +static void m_series_stc_writew(struct comedi_device *dev, uint16_t data, int reg) { unsigned offset; switch (reg) { @@ -1293,12 +1294,12 @@ static void m_series_stc_writew(struct comedi_device * dev, uint16_t data, int r offset = M_Offset_AI_Personal; break; case AI_SI2_Load_A_Register: - // this is actually a 32 bit register on m series boards + /* this is actually a 32 bit register on m series boards */ ni_writel(data, M_Offset_AI_SI2_Load_A); return; break; case AI_SI2_Load_B_Register: - // this is actually a 32 bit register on m series boards + /* this is actually a 32 bit register on m series boards */ ni_writel(data, M_Offset_AI_SI2_Load_B); return; break; @@ -1348,9 +1349,9 @@ static void m_series_stc_writew(struct comedi_device * dev, uint16_t data, int r offset = M_Offset_AO_FIFO_Clear; break; case DIO_Control_Register: - rt_printk + printk ("%s: FIXME: register 0x%x does not map cleanly on to m-series boards.\n", - __FUNCTION__, reg); + __func__, reg); return; break; case G_Autoincrement_Register(0): @@ -1410,8 +1411,8 @@ static void m_series_stc_writew(struct comedi_device * dev, uint16_t data, int r /* FIXME: DIO_Output_Register (16 bit reg) is replaced by M_Offset_Static_Digital_Output (32 bit) and M_Offset_SCXI_Serial_Data_Out (8 bit) */ default: - rt_printk("%s: bug! unhandled register=0x%x in switch.\n", - __FUNCTION__, reg); + printk("%s: bug! unhandled register=0x%x in switch.\n", + __func__, reg); BUG(); return; break; @@ -1419,7 +1420,7 @@ static void m_series_stc_writew(struct comedi_device * dev, uint16_t data, int r ni_writew(data, offset); } -static uint16_t m_series_stc_readw(struct comedi_device * dev, int reg) +static uint16_t m_series_stc_readw(struct comedi_device *dev, int reg) { unsigned offset; switch (reg) { @@ -1445,8 +1446,8 @@ static uint16_t m_series_stc_readw(struct comedi_device * dev, int reg) offset = M_Offset_G01_Status; break; default: - rt_printk("%s: bug! unhandled register=0x%x in switch.\n", - __FUNCTION__, reg); + printk("%s: bug! unhandled register=0x%x in switch.\n", + __func__, reg); BUG(); return 0; break; @@ -1454,7 +1455,7 @@ static uint16_t m_series_stc_readw(struct comedi_device * dev, int reg) return ni_readw(offset); } -static void m_series_stc_writel(struct comedi_device * dev, uint32_t data, int reg) +static void m_series_stc_writel(struct comedi_device *dev, uint32_t data, int reg) { unsigned offset; switch (reg) { @@ -1486,8 +1487,8 @@ static void m_series_stc_writel(struct comedi_device * dev, uint32_t data, int r offset = M_Offset_G1_Load_B; break; default: - rt_printk("%s: bug! unhandled register=0x%x in switch.\n", - __FUNCTION__, reg); + printk("%s: bug! unhandled register=0x%x in switch.\n", + __func__, reg); BUG(); return; break; @@ -1495,7 +1496,7 @@ static void m_series_stc_writel(struct comedi_device * dev, uint32_t data, int r ni_writel(data, offset); } -static uint32_t m_series_stc_readl(struct comedi_device * dev, int reg) +static uint32_t m_series_stc_readl(struct comedi_device *dev, int reg) { unsigned offset; switch (reg) { @@ -1512,8 +1513,8 @@ static uint32_t m_series_stc_readl(struct comedi_device * dev, int reg) offset = M_Offset_G1_Save; break; default: - rt_printk("%s: bug! unhandled register=0x%x in switch.\n", - __FUNCTION__, reg); + printk("%s: bug! unhandled register=0x%x in switch.\n", + __func__, reg); BUG(); return 0; break; @@ -1528,19 +1529,19 @@ static uint32_t m_series_stc_readl(struct comedi_device * dev, int reg) #include "ni_mio_common.c" -static int pcimio_find_device(struct comedi_device * dev, int bus, int slot); -static int pcimio_ai_change(struct comedi_device * dev, struct comedi_subdevice * s, +static int pcimio_find_device(struct comedi_device *dev, int bus, int slot); +static int pcimio_ai_change(struct comedi_device *dev, struct comedi_subdevice *s, unsigned long new_size); -static int pcimio_ao_change(struct comedi_device * dev, struct comedi_subdevice * s, +static int pcimio_ao_change(struct comedi_device *dev, struct comedi_subdevice *s, unsigned long new_size); -static int pcimio_gpct0_change(struct comedi_device * dev, struct comedi_subdevice * s, +static int pcimio_gpct0_change(struct comedi_device *dev, struct comedi_subdevice *s, unsigned long new_size); -static int pcimio_gpct1_change(struct comedi_device * dev, struct comedi_subdevice * s, +static int pcimio_gpct1_change(struct comedi_device *dev, struct comedi_subdevice *s, unsigned long new_size); -static int pcimio_dio_change(struct comedi_device * dev, struct comedi_subdevice * s, +static int pcimio_dio_change(struct comedi_device *dev, struct comedi_subdevice *s, unsigned long new_size); -static void m_series_init_eeprom_buffer(struct comedi_device * dev) +static void m_series_init_eeprom_buffer(struct comedi_device *dev) { static const int Start_Cal_EEPROM = 0x400; static const unsigned window_size = 10; @@ -1577,19 +1578,19 @@ static void m_series_init_eeprom_buffer(struct comedi_device * dev) writel(0x0, devpriv->mite->mite_io_addr + 0x30); } -static void init_6143(struct comedi_device * dev) +static void init_6143(struct comedi_device *dev) { - // Disable interrupts + /* Disable interrupts */ devpriv->stc_writew(dev, 0, Interrupt_Control_Register); - // Initialise 6143 AI specific bits - ni_writeb(0x00, Magic_6143); // Set G0,G1 DMA mode to E series version - ni_writeb(0x80, PipelineDelay_6143); // Set EOCMode, ADCMode and pipelinedelay - ni_writeb(0x00, EOC_Set_6143); // Set EOC Delay + /* Initialise 6143 AI specific bits */ + ni_writeb(0x00, Magic_6143); /* Set G0,G1 DMA mode to E series version */ + ni_writeb(0x80, PipelineDelay_6143); /* Set EOCMode, ADCMode and pipelinedelay */ + ni_writeb(0x00, EOC_Set_6143); /* Set EOC Delay */ - ni_writel(boardtype.ai_fifo_depth / 2, AIFIFO_Flag_6143); // Set the FIFO half full level + ni_writel(boardtype.ai_fifo_depth / 2, AIFIFO_Flag_6143); /* Set the FIFO half full level */ - // Strobe Relay disable bit + /* Strobe Relay disable bit */ devpriv->ai_calib_source_enabled = 0; ni_writew(devpriv->ai_calib_source | Calibration_Channel_6143_RelayOff, Calibration_Channel_6143); @@ -1597,11 +1598,11 @@ static void init_6143(struct comedi_device * dev) } /* cleans up allocated resources */ -static int pcimio_detach(struct comedi_device * dev) +static int pcimio_detach(struct comedi_device *dev) { mio_common_detach(dev); if (dev->irq) { - comedi_free_irq(dev->irq, dev); + free_irq(dev->irq, dev); } if (dev->private) { mite_free_ring(devpriv->ai_mite_ring); @@ -1616,7 +1617,7 @@ static int pcimio_detach(struct comedi_device * dev) return 0; } -static int pcimio_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int pcimio_attach(struct comedi_device *dev, struct comedi_devconfig *it) { int ret; @@ -1678,9 +1679,9 @@ static int pcimio_attach(struct comedi_device * dev, struct comedi_devconfig * i printk(" unknown irq (bad)\n"); } else { printk(" ( irq = %u )", dev->irq); - if ((ret = comedi_request_irq(dev->irq, ni_E_interrupt, - NI_E_IRQ_FLAGS, DRV_NAME, - dev)) < 0) { + ret = request_irq(dev->irq, ni_E_interrupt, NI_E_IRQ_FLAGS, + DRV_NAME, dev); + if (ret < 0) { printk(" irq not available\n"); dev->irq = 0; } @@ -1699,7 +1700,7 @@ static int pcimio_attach(struct comedi_device * dev, struct comedi_devconfig * i return ret; } -static int pcimio_find_device(struct comedi_device * dev, int bus, int slot) +static int pcimio_find_device(struct comedi_device *dev, int bus, int slot) { struct mite_struct *mite; int i; @@ -1727,7 +1728,7 @@ static int pcimio_find_device(struct comedi_device * dev, int bus, int slot) return -EIO; } -static int pcimio_ai_change(struct comedi_device * dev, struct comedi_subdevice * s, +static int pcimio_ai_change(struct comedi_device *dev, struct comedi_subdevice *s, unsigned long new_size) { int ret; @@ -1739,7 +1740,7 @@ static int pcimio_ai_change(struct comedi_device * dev, struct comedi_subdevice return 0; } -static int pcimio_ao_change(struct comedi_device * dev, struct comedi_subdevice * s, +static int pcimio_ao_change(struct comedi_device *dev, struct comedi_subdevice *s, unsigned long new_size) { int ret; @@ -1751,7 +1752,7 @@ static int pcimio_ao_change(struct comedi_device * dev, struct comedi_subdevice return 0; } -static int pcimio_gpct0_change(struct comedi_device * dev, struct comedi_subdevice * s, +static int pcimio_gpct0_change(struct comedi_device *dev, struct comedi_subdevice *s, unsigned long new_size) { int ret; @@ -1763,7 +1764,7 @@ static int pcimio_gpct0_change(struct comedi_device * dev, struct comedi_subdevi return 0; } -static int pcimio_gpct1_change(struct comedi_device * dev, struct comedi_subdevice * s, +static int pcimio_gpct1_change(struct comedi_device *dev, struct comedi_subdevice *s, unsigned long new_size) { int ret; @@ -1775,7 +1776,7 @@ static int pcimio_gpct1_change(struct comedi_device * dev, struct comedi_subdevi return 0; } -static int pcimio_dio_change(struct comedi_device * dev, struct comedi_subdevice * s, +static int pcimio_dio_change(struct comedi_device *dev, struct comedi_subdevice *s, unsigned long new_size) { int ret; diff --git a/drivers/staging/comedi/drivers/ni_stc.h b/drivers/staging/comedi/drivers/ni_stc.h index 1ebf521ab773..fcaedb346c44 100644 --- a/drivers/staging/comedi/drivers/ni_stc.h +++ b/drivers/staging/comedi/drivers/ni_stc.h @@ -262,7 +262,7 @@ enum Joint_Status_2_Bits { #define AO_Trigger_Once _bit0 #define AO_Mode_2_Register 39 -#define AO_FIFO_Mode_Mask ( 0x3 << 14 ) +#define AO_FIFO_Mode_Mask (0x3 << 14) enum AO_FIFO_Mode_Bits { AO_FIFO_Mode_HF_to_F = (3 << 14), AO_FIFO_Mode_F = (2 << 14), @@ -318,7 +318,7 @@ enum Clock_and_FOUT_bits { }; static inline unsigned FOUT_Divider(unsigned divider) { - return (divider & FOUT_Divider_mask); + return divider & FOUT_Divider_mask; } #define IO_Bidirection_Pin_Register 57 @@ -339,7 +339,7 @@ static inline unsigned RTSI_Output_Bit(unsigned channel, int is_mseries) max_channel = 6; } if (channel > max_channel) { - rt_printk("%s: bug, invalid RTSI_channel=%i\n", __FUNCTION__, + printk("%s: bug, invalid RTSI_channel=%i\n", __func__, channel); return 0; } @@ -521,13 +521,13 @@ enum AO_Personal_Bits { AO_FIFO_Flags_Polarity = 1 << 11, /* M Series: reserved */ AO_TMRDACWR_Pulse_Width = 1 << 12, AO_Fast_CPU = 1 << 13, /* M Series: reserved */ - AO_Number_Of_DAC_Packages = 1 << 14, // 1 for "single" mode, 0 for "dual" - AO_Multiple_DACS_Per_Package = 1 << 15 // m-series only + AO_Number_Of_DAC_Packages = 1 << 14, /* 1 for "single" mode, 0 for "dual" */ + AO_Multiple_DACS_Per_Package = 1 << 15 /* m-series only */ }; #define RTSI_Trig_A_Output_Register 79 #define RTSI_Trig_B_Output_Register 80 enum RTSI_Trig_B_Output_Bits { - RTSI_Sub_Selection_1_Bit = 0x8000 // not for m-series + RTSI_Sub_Selection_1_Bit = 0x8000 /* not for m-series */ }; static inline unsigned RTSI_Trig_Output_Bits(unsigned rtsi_channel, unsigned source) @@ -539,7 +539,7 @@ static inline unsigned RTSI_Trig_Output_Mask(unsigned rtsi_channel) return 0xf << ((rtsi_channel % 4) * 4); }; -// inverse to RTSI_Trig_Output_Bits() +/* inverse to RTSI_Trig_Output_Bits() */ static inline unsigned RTSI_Trig_Output_Source(unsigned rtsi_channel, unsigned bits) { @@ -759,7 +759,7 @@ enum Configuration_Memory_High_Bits { }; static inline unsigned int AI_CONFIG_CHANNEL(unsigned int channel) { - return (channel & 0x3f); + return channel & 0x3f; } #define ADC_FIFO_Data_Register 0x1c @@ -920,42 +920,42 @@ enum ni_reg_type { static const struct comedi_lrange range_ni_E_ao_ext; enum m_series_register_offsets { - M_Offset_CDIO_DMA_Select = 0x7, // write - M_Offset_SCXI_Status = 0x7, // read - M_Offset_AI_AO_Select = 0x9, // write, same offset as e-series - M_Offset_SCXI_Serial_Data_In = 0x9, // read - M_Offset_G0_G1_Select = 0xb, // write, same offset as e-series + M_Offset_CDIO_DMA_Select = 0x7, /* write */ + M_Offset_SCXI_Status = 0x7, /* read */ + M_Offset_AI_AO_Select = 0x9, /* write, same offset as e-series */ + M_Offset_SCXI_Serial_Data_In = 0x9, /* read */ + M_Offset_G0_G1_Select = 0xb, /* write, same offset as e-series */ M_Offset_Misc_Command = 0xf, M_Offset_SCXI_Serial_Data_Out = 0x11, M_Offset_SCXI_Control = 0x13, M_Offset_SCXI_Output_Enable = 0x15, M_Offset_AI_FIFO_Data = 0x1c, - M_Offset_Static_Digital_Output = 0x24, // write - M_Offset_Static_Digital_Input = 0x24, // read + M_Offset_Static_Digital_Output = 0x24, /* write */ + M_Offset_Static_Digital_Input = 0x24, /* read */ M_Offset_DIO_Direction = 0x28, M_Offset_Cal_PWM = 0x40, M_Offset_AI_Config_FIFO_Data = 0x5e, - M_Offset_Interrupt_C_Enable = 0x88, // write - M_Offset_Interrupt_C_Status = 0x88, // read + M_Offset_Interrupt_C_Enable = 0x88, /* write */ + M_Offset_Interrupt_C_Status = 0x88, /* read */ M_Offset_Analog_Trigger_Control = 0x8c, M_Offset_AO_Serial_Interrupt_Enable = 0xa0, - M_Offset_AO_Serial_Interrupt_Ack = 0xa1, // write - M_Offset_AO_Serial_Interrupt_Status = 0xa1, // read + M_Offset_AO_Serial_Interrupt_Ack = 0xa1, /* write */ + M_Offset_AO_Serial_Interrupt_Status = 0xa1, /* read */ M_Offset_AO_Calibration = 0xa3, M_Offset_AO_FIFO_Data = 0xa4, M_Offset_PFI_Filter = 0xb0, M_Offset_RTSI_Filter = 0xb4, M_Offset_SCXI_Legacy_Compatibility = 0xbc, - M_Offset_Interrupt_A_Ack = 0x104, // write - M_Offset_AI_Status_1 = 0x104, // read - M_Offset_Interrupt_B_Ack = 0x106, // write - M_Offset_AO_Status_1 = 0x106, // read - M_Offset_AI_Command_2 = 0x108, // write - M_Offset_G01_Status = 0x108, // read + M_Offset_Interrupt_A_Ack = 0x104, /* write */ + M_Offset_AI_Status_1 = 0x104, /* read */ + M_Offset_Interrupt_B_Ack = 0x106, /* write */ + M_Offset_AO_Status_1 = 0x106, /* read */ + M_Offset_AI_Command_2 = 0x108, /* write */ + M_Offset_G01_Status = 0x108, /* read */ M_Offset_AO_Command_2 = 0x10a, - M_Offset_AO_Status_2 = 0x10c, // read - M_Offset_G0_Command = 0x10c, // write - M_Offset_G1_Command = 0x10e, // write + M_Offset_AO_Status_2 = 0x10c, /* read */ + M_Offset_G0_Command = 0x10c, /* write */ + M_Offset_G1_Command = 0x10e, /* write */ M_Offset_G0_HW_Save = 0x110, M_Offset_G0_HW_Save_High = 0x110, M_Offset_AI_Command_1 = 0x110, @@ -973,17 +973,17 @@ enum m_series_register_offsets { M_Offset_G1_Save = 0x11c, M_Offset_G1_Save_High = 0x11c, M_Offset_G1_Save_Low = 0x11e, - M_Offset_AI_SI_Load_B = 0x120, // write - M_Offset_AO_UI_Save = 0x120, // read - M_Offset_AI_SC_Load_A = 0x124, // write - M_Offset_AO_BC_Save = 0x124, // read - M_Offset_AI_SC_Load_B = 0x128, // write - M_Offset_AO_UC_Save = 0x128, //read + M_Offset_AI_SI_Load_B = 0x120, /* write */ + M_Offset_AO_UI_Save = 0x120, /* read */ + M_Offset_AI_SC_Load_A = 0x124, /* write */ + M_Offset_AO_BC_Save = 0x124, /* read */ + M_Offset_AI_SC_Load_B = 0x128, /* write */ + M_Offset_AO_UC_Save = 0x128, /* read */ M_Offset_AI_SI2_Load_A = 0x12c, M_Offset_AI_SI2_Load_B = 0x130, M_Offset_G0_Mode = 0x134, - M_Offset_G1_Mode = 0x136, // write - M_Offset_Joint_Status_1 = 0x136, // read + M_Offset_G1_Mode = 0x136, /* write */ + M_Offset_Joint_Status_1 = 0x136, /* read */ M_Offset_G0_Load_A = 0x138, M_Offset_Joint_Status_2 = 0x13a, M_Offset_G0_Load_B = 0x13c, @@ -1007,10 +1007,10 @@ enum m_series_register_offsets { M_Offset_Analog_Trigger_Etc = 0x17a, M_Offset_AI_START_STOP_Select = 0x17c, M_Offset_AI_Trigger_Select = 0x17e, - M_Offset_AI_SI_Save = 0x180, // read - M_Offset_AI_DIV_Load_A = 0x180, // write - M_Offset_AI_SC_Save = 0x184, // read - M_Offset_AO_Start_Select = 0x184, // write + M_Offset_AI_SI_Save = 0x180, /* read */ + M_Offset_AI_DIV_Load_A = 0x180, /* write */ + M_Offset_AI_SC_Save = 0x184, /* read */ + M_Offset_AO_Start_Select = 0x184, /* write */ M_Offset_AO_Trigger_Select = 0x186, M_Offset_AO_Mode_3 = 0x18c, M_Offset_G0_Autoincrement = 0x188, @@ -1032,10 +1032,10 @@ enum m_series_register_offsets { M_Offset_G1_Counting_Mode = 0x1b2, M_Offset_G0_Second_Gate = 0x1b4, M_Offset_G1_Second_Gate = 0x1b6, - M_Offset_G0_DMA_Config = 0x1b8, // write - M_Offset_G0_DMA_Status = 0x1b8, // read - M_Offset_G1_DMA_Config = 0x1ba, // write - M_Offset_G1_DMA_Status = 0x1ba, // read + M_Offset_G0_DMA_Config = 0x1b8, /* write */ + M_Offset_G0_DMA_Status = 0x1b8, /* read */ + M_Offset_G1_DMA_Config = 0x1ba, /* write */ + M_Offset_G1_DMA_Status = 0x1ba, /* read */ M_Offset_G0_MSeries_ABZ = 0x1c0, M_Offset_G1_MSeries_ABZ = 0x1c2, M_Offset_Clock_and_Fout2 = 0x1c4, @@ -1051,10 +1051,10 @@ enum m_series_register_offsets { M_Offset_PFI_DO = 0x1de, M_Offset_AI_Config_FIFO_Bypass = 0x218, M_Offset_SCXI_DIO_Enable = 0x21c, - M_Offset_CDI_FIFO_Data = 0x220, // read - M_Offset_CDO_FIFO_Data = 0x220, // write - M_Offset_CDIO_Status = 0x224, // read - M_Offset_CDIO_Command = 0x224, // write + M_Offset_CDI_FIFO_Data = 0x220, /* read */ + M_Offset_CDO_FIFO_Data = 0x220, /* write */ + M_Offset_CDIO_Status = 0x224, /* read */ + M_Offset_CDIO_Command = 0x224, /* write */ M_Offset_CDI_Mode = 0x228, M_Offset_CDO_Mode = 0x22c, M_Offset_CDI_Mask_Enable = 0x230, @@ -1084,8 +1084,8 @@ static inline int M_Offset_Static_AI_Control(int i) 0x262, 0x263, }; - if (((unsigned)i) >= sizeof(offset) / sizeof(offset[0])) { - rt_printk("%s: invalid channel=%i\n", __FUNCTION__, i); + if (((unsigned)i) >= ARRAY_SIZE(offset)) { + printk("%s: invalid channel=%i\n", __func__, i); return offset[0]; } return offset[i]; @@ -1098,8 +1098,8 @@ static inline int M_Offset_AO_Reference_Attenuation(int channel) 0x266, 0x267 }; - if (((unsigned)channel) >= sizeof(offset) / sizeof(offset[0])) { - rt_printk("%s: invalid channel=%i\n", __FUNCTION__, channel); + if (((unsigned)channel) >= ARRAY_SIZE(offset)) { + printk("%s: invalid channel=%i\n", __func__, channel); return offset[0]; } return offset[channel]; @@ -1107,8 +1107,8 @@ static inline int M_Offset_AO_Reference_Attenuation(int channel) static inline unsigned M_Offset_PFI_Output_Select(unsigned n) { if (n < 1 || n > NUM_PFI_OUTPUT_SELECT_REGS) { - rt_printk("%s: invalid pfi output select register=%i\n", - __FUNCTION__, n); + printk("%s: invalid pfi output select register=%i\n", + __func__, n); return M_Offset_PFI_Output_Select_1; } return M_Offset_PFI_Output_Select_1 + (n - 1) * 2; @@ -1122,7 +1122,7 @@ enum MSeries_AI_Config_FIFO_Data_Bits { MSeries_AI_Config_Channel_Type_Ground_Ref_Bits = 0x3 << 6, MSeries_AI_Config_Channel_Type_Aux_Bits = 0x5 << 6, MSeries_AI_Config_Channel_Type_Ghost_Bits = 0x7 << 6, - MSeries_AI_Config_Polarity_Bit = 0x1000, // 0 for 2's complement encoding + MSeries_AI_Config_Polarity_Bit = 0x1000, /* 0 for 2's complement encoding */ MSeries_AI_Config_Dither_Bit = 0x2000, MSeries_AI_Config_Last_Channel_Bit = 0x4000, }; @@ -1151,8 +1151,8 @@ enum MSeries_Clock_and_Fout2_Bits { MSeries_PLL_In_Source_Select_RTSI7_Bits = 0x1b, MSeries_PLL_In_Source_Select_PXI_Clock10 = 0x1d, MSeries_PLL_In_Source_Select_Mask = 0x1f, - MSeries_Timebase1_Select_Bit = 0x20, // use PLL for timebase 1 - MSeries_Timebase3_Select_Bit = 0x40, // use PLL for timebase 3 + MSeries_Timebase1_Select_Bit = 0x20, /* use PLL for timebase 1 */ + MSeries_Timebase3_Select_Bit = 0x40, /* use PLL for timebase 3 */ /* use 10MHz instead of 20MHz for RTSI clock frequency. Appears to have no effect, at least on pxi-6281, which always uses 20MHz rtsi clock frequency */ @@ -1162,7 +1162,7 @@ static inline unsigned MSeries_PLL_In_Source_Select_RTSI_Bits(unsigned RTSI_channel) { if (RTSI_channel > 7) { - rt_printk("%s: bug, invalid RTSI_channel=%i\n", __FUNCTION__, + printk("%s: bug, invalid RTSI_channel=%i\n", __func__, RTSI_channel); return 0; } @@ -1183,7 +1183,7 @@ static inline unsigned MSeries_PLL_Divisor_Bits(unsigned divisor) { static const unsigned max_divisor = 0x10; if (divisor < 1 || divisor > max_divisor) { - rt_printk("%s: bug, invalid divisor=%i\n", __FUNCTION__, + printk("%s: bug, invalid divisor=%i\n", __func__, divisor); return 0; } @@ -1193,7 +1193,7 @@ static inline unsigned MSeries_PLL_Multiplier_Bits(unsigned multiplier) { static const unsigned max_multiplier = 0x100; if (multiplier < 1 || multiplier > max_multiplier) { - rt_printk("%s: bug, invalid multiplier=%i\n", __FUNCTION__, + printk("%s: bug, invalid multiplier=%i\n", __func__, multiplier); return 0; } @@ -1213,7 +1213,7 @@ enum MSeries_AI_Config_FIFO_Bypass_Bits { MSeries_AO_Bypass_AO_Cal_Sel_Mask = 0x38000, MSeries_AI_Bypass_Gain_Mask = 0x1c0000, MSeries_AI_Bypass_Dither_Bit = 0x200000, - MSeries_AI_Bypass_Polarity_Bit = 0x400000, // 0 for 2's complement encoding + MSeries_AI_Bypass_Polarity_Bit = 0x400000, /* 0 for 2's complement encoding */ MSeries_AI_Bypass_Config_FIFO_Bit = 0x80000000 }; static inline unsigned MSeries_AI_Bypass_Cal_Sel_Pos_Bits(int @@ -1239,7 +1239,7 @@ enum MSeries_AO_Config_Bank_Bits { MSeries_AO_DAC_Reference_10V_Internal_Bits = 0x0, MSeries_AO_DAC_Reference_5V_Internal_Bits = 0x8, MSeries_AO_Update_Timed_Bit = 0x40, - MSeries_AO_Bipolar_Bit = 0x80 // turns on 2's complement encoding + MSeries_AO_Bipolar_Bit = 0x80 /* turns on 2's complement encoding */ }; enum MSeries_AO_Reference_Attenuation_Bits { @@ -1266,7 +1266,7 @@ static inline unsigned MSeries_PFI_Output_Select_Bits(unsigned channel, return (source & 0x1f) << ((channel % 3) * 5); }; -// inverse to MSeries_PFI_Output_Select_Bits +/* inverse to MSeries_PFI_Output_Select_Bits */ static inline unsigned MSeries_PFI_Output_Select_Source(unsigned channel, unsigned bits) { @@ -1338,9 +1338,9 @@ enum CDIO_Command_Bits { enum CDI_Mode_Bits { CDI_Sample_Source_Select_Mask = 0x3f, CDI_Halt_On_Error_Bit = 0x200, - CDI_Polarity_Bit = 0x400, // sample clock on falling edge - CDI_FIFO_Mode_Bit = 0x800, // set for half full mode, clear for not empty mode - CDI_Data_Lane_Mask = 0x3000, // data lanes specify which dio channels map to byte or word accesses to the dio fifos + CDI_Polarity_Bit = 0x400, /* sample clock on falling edge */ + CDI_FIFO_Mode_Bit = 0x800, /* set for half full mode, clear for not empty mode */ + CDI_Data_Lane_Mask = 0x3000, /* data lanes specify which dio channels map to byte or word accesses to the dio fifos */ CDI_Data_Lane_0_15_Bits = 0x0, CDI_Data_Lane_16_31_Bits = 0x1000, CDI_Data_Lane_0_7_Bits = 0x0, @@ -1353,9 +1353,9 @@ enum CDO_Mode_Bits { CDO_Sample_Source_Select_Mask = 0x3f, CDO_Retransmit_Bit = 0x100, CDO_Halt_On_Error_Bit = 0x200, - CDO_Polarity_Bit = 0x400, // sample clock on falling edge - CDO_FIFO_Mode_Bit = 0x800, // set for half full mode, clear for not full mode - CDO_Data_Lane_Mask = 0x3000, // data lanes specify which dio channels map to byte or word accesses to the dio fifos + CDO_Polarity_Bit = 0x400, /* sample clock on falling edge */ + CDO_FIFO_Mode_Bit = 0x800, /* set for half full mode, clear for not full mode */ + CDO_Data_Lane_Mask = 0x3000, /* data lanes specify which dio channels map to byte or word accesses to the dio fifos */ CDO_Data_Lane_0_15_Bits = 0x0, CDO_Data_Lane_16_31_Bits = 0x1000, CDO_Data_Lane_0_7_Bits = 0x0, @@ -1374,7 +1374,7 @@ enum Interrupt_C_Status_Bits { #define M_SERIES_EEPROM_SIZE 1024 -typedef struct ni_board_struct { +struct ni_board_struct { int device_id; int isapnp_id; char *name; @@ -1401,11 +1401,11 @@ typedef struct ni_board_struct { unsigned int has_analog_trig:1; enum caldac_enum caldac[3]; -} ni_board; +}; -#define n_ni_boards (sizeof(ni_boards)/sizeof(ni_board)) +#define n_ni_boards (sizeof(ni_boards)/sizeof(struct ni_board_struct)) -#define boardtype (*(ni_board *)dev->board_ptr) +#define boardtype (*(struct ni_board_struct *)dev->board_ptr) #define MAX_N_AO_CHAN 8 #define NUM_GPCT 2 @@ -1418,7 +1418,7 @@ typedef struct ni_board_struct { \ unsigned short dio_output; \ unsigned short dio_control; \ - int ao0p,ao1p; \ + int ao0p, ao1p; \ int lastchan; \ int last_do; \ int rt_irq; \ diff --git a/drivers/staging/comedi/drivers/ni_tio.c b/drivers/staging/comedi/drivers/ni_tio.c index 05a957540398..785553d0cc9d 100644 --- a/drivers/staging/comedi/drivers/ni_tio.c +++ b/drivers/staging/comedi/drivers/ni_tio.c @@ -149,13 +149,13 @@ static const unsigned ni_660x_max_rtsi_channel = 6; static inline unsigned NI_660x_RTSI_Clock(unsigned n) { BUG_ON(n > ni_660x_max_rtsi_channel); - return (0xb + n); + return 0xb + n; } static const unsigned ni_660x_max_source_pin = 7; static inline unsigned NI_660x_Source_Pin_Clock(unsigned n) { BUG_ON(n > ni_660x_max_source_pin); - return (0x2 + n); + return 0x2 + n; } /* clock sources for ni e and m series boards, get bits with Gi_Source_Select_Bits() */ @@ -279,9 +279,9 @@ static void __exit ni_tio_cleanup_module(void) module_exit(ni_tio_cleanup_module); struct ni_gpct_device *ni_gpct_device_construct(struct comedi_device * dev, - void (*write_register) (struct ni_gpct * counter, unsigned bits, + void (*write_register) (struct ni_gpct *counter, unsigned bits, enum ni_gpct_register reg), - unsigned (*read_register) (struct ni_gpct * counter, + unsigned (*read_register) (struct ni_gpct *counter, enum ni_gpct_register reg), enum ni_gpct_variant variant, unsigned num_counters) { @@ -669,7 +669,7 @@ static unsigned ni_m_series_source_select_bits(unsigned int clock_source) } if (i <= ni_m_series_max_pfi_channel) break; - rt_printk("invalid clock source 0x%lx\n", + printk("invalid clock source 0x%lx\n", (unsigned long)clock_source); BUG(); ni_m_series_clock = 0; @@ -965,7 +965,7 @@ static uint64_t ni_tio_clock_period_ps(const struct ni_gpct *counter, } static void ni_tio_get_clock_src(struct ni_gpct *counter, - unsigned int * clock_source, unsigned int * period_ns) + unsigned int *clock_source, unsigned int *period_ns) { static const unsigned pico_per_nano = 1000; uint64_t temp64; @@ -1273,7 +1273,7 @@ static int ni_tio_set_other_src(struct ni_gpct *counter, unsigned index, counter_dev->regs[abz_reg] &= ~mask; counter_dev->regs[abz_reg] |= (source << shift) & mask; write_register(counter, counter_dev->regs[abz_reg], abz_reg); -// rt_printk("%s %x %d %d\n", __FUNCTION__, counter_dev->regs[abz_reg], index, source); +/* printk("%s %x %d %d\n", __func__, counter_dev->regs[abz_reg], index, source); */ return 0; } return -EINVAL; @@ -1442,7 +1442,7 @@ static unsigned ni_m_series_second_gate_to_generic_gate_source(unsigned }; static int ni_tio_get_gate_src(struct ni_gpct *counter, unsigned gate_index, - unsigned int * gate_source) + unsigned int *gate_source) { struct ni_gpct_device *counter_dev = counter->counter_dev; const unsigned mode_bits = ni_tio_get_soft_copy(counter, @@ -1534,7 +1534,7 @@ static int ni_tio_get_gate_src(struct ni_gpct *counter, unsigned gate_index, } int ni_tio_insn_config(struct ni_gpct *counter, - struct comedi_insn * insn, unsigned int * data) + struct comedi_insn *insn, unsigned int *data) { switch (data[0]) { case INSN_CONFIG_SET_COUNTER_MODE: diff --git a/drivers/staging/comedi/drivers/ni_tio.h b/drivers/staging/comedi/drivers/ni_tio.h index 0729d60b01cc..3aacfe2f2420 100644 --- a/drivers/staging/comedi/drivers/ni_tio.h +++ b/drivers/staging/comedi/drivers/ni_tio.h @@ -25,7 +25,7 @@ #include "../comedidev.h" -// forward declarations +/* forward declarations */ struct mite_struct; struct ni_gpct_device; @@ -120,9 +120,9 @@ struct ni_gpct { struct ni_gpct_device { struct comedi_device *dev; - void (*write_register) (struct ni_gpct * counter, unsigned bits, + void (*write_register) (struct ni_gpct *counter, unsigned bits, enum ni_gpct_register reg); - unsigned (*read_register) (struct ni_gpct * counter, + unsigned (*read_register) (struct ni_gpct *counter, enum ni_gpct_register reg); enum ni_gpct_variant variant; struct ni_gpct *counters; @@ -132,24 +132,24 @@ struct ni_gpct_device { }; extern struct ni_gpct_device *ni_gpct_device_construct(struct comedi_device * dev, - void (*write_register) (struct ni_gpct * counter, unsigned bits, + void (*write_register) (struct ni_gpct *counter, unsigned bits, enum ni_gpct_register reg), - unsigned (*read_register) (struct ni_gpct * counter, + unsigned (*read_register) (struct ni_gpct *counter, enum ni_gpct_register reg), enum ni_gpct_variant variant, unsigned num_counters); extern void ni_gpct_device_destroy(struct ni_gpct_device *counter_dev); extern void ni_tio_init_counter(struct ni_gpct *counter); extern int ni_tio_rinsn(struct ni_gpct *counter, - struct comedi_insn * insn, unsigned int * data); + struct comedi_insn *insn, unsigned int *data); extern int ni_tio_insn_config(struct ni_gpct *counter, - struct comedi_insn * insn, unsigned int * data); + struct comedi_insn *insn, unsigned int *data); extern int ni_tio_winsn(struct ni_gpct *counter, - struct comedi_insn * insn, unsigned int * data); + struct comedi_insn *insn, unsigned int *data); extern int ni_tio_cmd(struct ni_gpct *counter, struct comedi_async *async); extern int ni_tio_cmdtest(struct ni_gpct *counter, struct comedi_cmd * cmd); extern int ni_tio_cancel(struct ni_gpct *counter); extern void ni_tio_handle_interrupt(struct ni_gpct *counter, - struct comedi_subdevice * s); + struct comedi_subdevice *s); extern void ni_tio_set_mite_channel(struct ni_gpct *counter, struct mite_channel *mite_chan); extern void ni_tio_acknowledge_and_confirm(struct ni_gpct *counter, diff --git a/drivers/staging/comedi/drivers/ni_tio_internal.h b/drivers/staging/comedi/drivers/ni_tio_internal.h index ac5b171cbe18..920dd221da0d 100644 --- a/drivers/staging/comedi/drivers/ni_tio_internal.h +++ b/drivers/staging/comedi/drivers/ni_tio_internal.h @@ -487,8 +487,8 @@ enum Gi_Counting_Mode_Reg_Bits { #define Gi_Source_Select_Shift 2 #define Gi_Gate_Select_Shift 7 enum Gi_Input_Select_Bits { - Gi_Read_Acknowledges_Irq = 0x1, // not present on 660x - Gi_Write_Acknowledges_Irq = 0x2, // not present on 660x + Gi_Read_Acknowledges_Irq = 0x1, /* not present on 660x */ + Gi_Write_Acknowledges_Irq = 0x2, /* not present on 660x */ Gi_Source_Select_Mask = 0x7c, Gi_Gate_Select_Mask = 0x1f << Gi_Gate_Select_Shift, Gi_Gate_Select_Load_Source_Bit = 0x1000, @@ -656,7 +656,7 @@ static inline unsigned Gi_TC_Error_Confirm_Bit(unsigned counter_index) return G0_TC_Error_Confirm_Bit; } -// bits that are the same in G0/G2 and G1/G3 interrupt acknowledge registers +/* bits that are the same in G0/G2 and G1/G3 interrupt acknowledge registers */ enum Gxx_Interrupt_Acknowledge_Bits { Gi_TC_Interrupt_Ack_Bit = 0x4000, Gi_Gate_Interrupt_Ack_Bit = 0x8000 @@ -728,14 +728,14 @@ static inline void ni_tio_set_bits_transient(struct ni_gpct *counter, unsigned long flags; BUG_ON(register_index >= NITIO_Num_Registers); - comedi_spin_lock_irqsave(&counter_dev->regs_lock, flags); + spin_lock_irqsave(&counter_dev->regs_lock, flags); counter_dev->regs[register_index] &= ~bit_mask; counter_dev->regs[register_index] |= (bit_values & bit_mask); write_register(counter, counter_dev->regs[register_index] | transient_bit_values, register_index); mmiowb(); - comedi_spin_unlock_irqrestore(&counter_dev->regs_lock, flags); + spin_unlock_irqrestore(&counter_dev->regs_lock, flags); } /* ni_tio_set_bits( ) is for safely writing to registers whose bits may be @@ -761,9 +761,9 @@ static inline unsigned ni_tio_get_soft_copy(const struct ni_gpct *counter, unsigned value; BUG_ON(register_index >= NITIO_Num_Registers); - comedi_spin_lock_irqsave(&counter_dev->regs_lock, flags); + spin_lock_irqsave(&counter_dev->regs_lock, flags); value = counter_dev->regs[register_index]; - comedi_spin_unlock_irqrestore(&counter_dev->regs_lock, flags); + spin_unlock_irqrestore(&counter_dev->regs_lock, flags); return value; } diff --git a/drivers/staging/comedi/drivers/ni_tiocmd.c b/drivers/staging/comedi/drivers/ni_tiocmd.c index 16a26e73c994..5be1e1a62c0a 100644 --- a/drivers/staging/comedi/drivers/ni_tiocmd.c +++ b/drivers/staging/comedi/drivers/ni_tiocmd.c @@ -96,7 +96,7 @@ static void ni_tio_configure_dma(struct ni_gpct *counter, short enable, } } -static int ni_tio_input_inttrig(struct comedi_device * dev, struct comedi_subdevice * s, +static int ni_tio_input_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int trignum) { unsigned long flags; @@ -107,12 +107,12 @@ static int ni_tio_input_inttrig(struct comedi_device * dev, struct comedi_subdev if (trignum != 0) return -EINVAL; - comedi_spin_lock_irqsave(&counter->lock, flags); + spin_lock_irqsave(&counter->lock, flags); if (counter->mite_chan) mite_dma_arm(counter->mite_chan); else retval = -EIO; - comedi_spin_unlock_irqrestore(&counter->lock, flags); + spin_unlock_irqrestore(&counter->lock, flags); if (retval < 0) return retval; retval = ni_tio_arm(counter, 1, NI_GPCT_ARM_IMMEDIATE); @@ -171,7 +171,7 @@ static int ni_tio_input_cmd(struct ni_gpct *counter, struct comedi_async *async) static int ni_tio_output_cmd(struct ni_gpct *counter, struct comedi_async *async) { - rt_printk("ni_tio: output commands not yet implemented.\n"); + printk("ni_tio: output commands not yet implemented.\n"); return -ENOTSUPP; counter->mite_chan->dir = COMEDI_OUTPUT; @@ -213,9 +213,9 @@ int ni_tio_cmd(struct ni_gpct *counter, struct comedi_async *async) int retval = 0; unsigned long flags; - comedi_spin_lock_irqsave(&counter->lock, flags); + spin_lock_irqsave(&counter->lock, flags); if (counter->mite_chan == NULL) { - rt_printk + printk ("ni_tio: commands only supported with DMA. Interrupt-driven commands not yet implemented.\n"); retval = -EIO; } else { @@ -228,7 +228,7 @@ int ni_tio_cmd(struct ni_gpct *counter, struct comedi_async *async) } } } - comedi_spin_unlock_irqrestore(&counter->lock, flags); + spin_unlock_irqrestore(&counter->lock, flags); return retval; } @@ -342,11 +342,11 @@ int ni_tio_cancel(struct ni_gpct *counter) unsigned long flags; ni_tio_arm(counter, 0, 0); - comedi_spin_lock_irqsave(&counter->lock, flags); + spin_lock_irqsave(&counter->lock, flags); if (counter->mite_chan) { mite_dma_disarm(counter->mite_chan); } - comedi_spin_unlock_irqrestore(&counter->lock, flags); + spin_unlock_irqrestore(&counter->lock, flags); ni_tio_configure_dma(counter, 0, 0); ni_tio_set_bits(counter, @@ -365,11 +365,11 @@ static int should_ack_gate(struct ni_gpct *counter) switch (counter->counter_dev->variant) { case ni_gpct_variant_m_series: - case ni_gpct_variant_660x: // not sure if 660x really supports gate interrupts (the bits are not listed in register-level manual) + case ni_gpct_variant_660x: /* not sure if 660x really supports gate interrupts (the bits are not listed in register-level manual) */ return 1; break; case ni_gpct_variant_e_series: - comedi_spin_lock_irqsave(&counter->lock, flags); + spin_lock_irqsave(&counter->lock, flags); { if (counter->mite_chan == NULL || counter->mite_chan->dir != COMEDI_INPUT || @@ -377,7 +377,7 @@ static int should_ack_gate(struct ni_gpct *counter) retval = 1; } } - comedi_spin_unlock_irqrestore(&counter->lock, flags); + spin_unlock_irqrestore(&counter->lock, flags); break; } return retval; @@ -439,7 +439,7 @@ void ni_tio_acknowledge_and_confirm(struct ni_gpct *counter, int *gate_error, NITIO_Gxx_Joint_Status2_Reg(counter-> counter_index)) & Gi_Permanent_Stale_Bit(counter->counter_index)) { - rt_printk("%s: Gi_Permanent_Stale_Data detected.\n", + printk("%s: Gi_Permanent_Stale_Data detected.\n", __FUNCTION__); if (perm_stale_data) *perm_stale_data = 1; @@ -458,7 +458,7 @@ void ni_tio_handle_interrupt(struct ni_gpct *counter, struct comedi_subdevice * ni_tio_acknowledge_and_confirm(counter, &gate_error, &tc_error, &perm_stale_data, NULL); if (gate_error) { - rt_printk("%s: Gi_Gate_Error detected.\n", __FUNCTION__); + printk("%s: Gi_Gate_Error detected.\n", __FUNCTION__); s->async->events |= COMEDI_CB_OVERFLOW; } if (perm_stale_data) { @@ -470,16 +470,16 @@ void ni_tio_handle_interrupt(struct ni_gpct *counter, struct comedi_subdevice * if (read_register(counter, NITIO_Gi_DMA_Status_Reg(counter-> counter_index)) & Gi_DRQ_Error_Bit) { - rt_printk("%s: Gi_DRQ_Error detected.\n", __FUNCTION__); + printk("%s: Gi_DRQ_Error detected.\n", __FUNCTION__); s->async->events |= COMEDI_CB_OVERFLOW; } break; case ni_gpct_variant_e_series: break; } - comedi_spin_lock_irqsave(&counter->lock, flags); + spin_lock_irqsave(&counter->lock, flags); if (counter->mite_chan == NULL) { - comedi_spin_unlock_irqrestore(&counter->lock, flags); + spin_unlock_irqrestore(&counter->lock, flags); return; } gpct_mite_status = mite_get_status(counter->mite_chan); @@ -489,7 +489,7 @@ void ni_tio_handle_interrupt(struct ni_gpct *counter, struct comedi_subdevice * MITE_CHOR(counter->mite_chan->channel)); } mite_sync_input_dma(counter->mite_chan, s->async); - comedi_spin_unlock_irqrestore(&counter->lock, flags); + spin_unlock_irqrestore(&counter->lock, flags); } void ni_tio_set_mite_channel(struct ni_gpct *counter, @@ -497,9 +497,9 @@ void ni_tio_set_mite_channel(struct ni_gpct *counter, { unsigned long flags; - comedi_spin_lock_irqsave(&counter->lock, flags); + spin_lock_irqsave(&counter->lock, flags); counter->mite_chan = mite_chan; - comedi_spin_unlock_irqrestore(&counter->lock, flags); + spin_unlock_irqrestore(&counter->lock, flags); } static int __init ni_tiocmd_init_module(void) diff --git a/drivers/staging/comedi/drivers/pcl711.c b/drivers/staging/comedi/drivers/pcl711.c index ce42506d47b5..7b72b7af75c8 100644 --- a/drivers/staging/comedi/drivers/pcl711.c +++ b/drivers/staging/comedi/drivers/pcl711.c @@ -58,6 +58,7 @@ supported. */ +#include #include "../comedidev.h" #include @@ -156,16 +157,16 @@ static const struct pcl711_board boardtypes[] = { #define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl711_board)) #define this_board ((const struct pcl711_board *)dev->board_ptr) -static int pcl711_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int pcl711_detach(struct comedi_device * dev); +static int pcl711_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int pcl711_detach(struct comedi_device *dev); static struct comedi_driver driver_pcl711 = { - driver_name:"pcl711", - module:THIS_MODULE, - attach:pcl711_attach, - detach:pcl711_detach, - board_name:&boardtypes[0].name, - num_names:n_boardtypes, - offset:sizeof(struct pcl711_board), + .driver_name = "pcl711", + .module = THIS_MODULE, + .attach = pcl711_attach, + .detach = pcl711_detach, + .board_name = &boardtypes[0].name, + .num_names = n_boardtypes, + .offset = sizeof(struct pcl711_board), }; COMEDI_INITCLEANUP(driver_pcl711); @@ -185,7 +186,7 @@ struct pcl711_private { #define devpriv ((struct pcl711_private *)dev->private) -static irqreturn_t pcl711_interrupt(int irq, void *d PT_REGS_ARG) +static irqreturn_t pcl711_interrupt(int irq, void *d) { int lo, hi; int data; @@ -217,7 +218,7 @@ static irqreturn_t pcl711_interrupt(int irq, void *d PT_REGS_ARG) return IRQ_HANDLED; } -static void pcl711_set_changain(struct comedi_device * dev, int chan) +static void pcl711_set_changain(struct comedi_device *dev, int chan) { int chan_register; @@ -244,8 +245,8 @@ static void pcl711_set_changain(struct comedi_device * dev, int chan) } } -static int pcl711_ai_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pcl711_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i, n; int hi, lo; @@ -269,9 +270,9 @@ static int pcl711_ai_insn(struct comedi_device * dev, struct comedi_subdevice * hi = inb(dev->iobase + PCL711_AD_HI); if (!(hi & PCL711_DRDY)) goto ok; - comedi_udelay(1); + udelay(1); } - rt_printk("comedi%d: pcl711: A/D timeout\n", dev->minor); + printk("comedi%d: pcl711: A/D timeout\n", dev->minor); return -ETIME; ok: @@ -283,8 +284,8 @@ static int pcl711_ai_insn(struct comedi_device * dev, struct comedi_subdevice * return n; } -static int pcl711_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd) +static int pcl711_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd) { int tmp; int err = 0; @@ -385,7 +386,7 @@ static int pcl711_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice return 0; } -static int pcl711_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s) +static int pcl711_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { int timer1, timer2; struct comedi_cmd *cmd = &s->async->cmd; @@ -431,8 +432,8 @@ static int pcl711_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s /* analog output */ -static int pcl711_ao_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pcl711_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int n; int chan = CR_CHAN(insn->chanspec); @@ -449,8 +450,8 @@ static int pcl711_ao_insn(struct comedi_device * dev, struct comedi_subdevice * return n; } -static int pcl711_ao_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pcl711_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int n; int chan = CR_CHAN(insn->chanspec); @@ -464,8 +465,8 @@ static int pcl711_ao_insn_read(struct comedi_device * dev, struct comedi_subdevi } /* Digital port read - Untested on 8112 */ -static int pcl711_di_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pcl711_di_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if (insn->n != 2) return -EINVAL; @@ -477,8 +478,8 @@ static int pcl711_di_insn_bits(struct comedi_device * dev, struct comedi_subdevi } /* Digital port write - Untested on 8112 */ -static int pcl711_do_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pcl711_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if (insn->n != 2) return -EINVAL; @@ -498,12 +499,12 @@ static int pcl711_do_insn_bits(struct comedi_device * dev, struct comedi_subdevi } /* Free any resources that we have claimed */ -static int pcl711_detach(struct comedi_device * dev) +static int pcl711_detach(struct comedi_device *dev) { printk("comedi%d: pcl711: remove\n", dev->minor); if (dev->irq) - comedi_free_irq(dev->irq, dev); + free_irq(dev->irq, dev); if (dev->iobase) release_region(dev->iobase, PCL711_SIZE); @@ -512,7 +513,7 @@ static int pcl711_detach(struct comedi_device * dev) } /* Initialization */ -static int pcl711_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int pcl711_attach(struct comedi_device *dev, struct comedi_devconfig *it) { int ret; unsigned long iobase; @@ -541,7 +542,7 @@ static int pcl711_attach(struct comedi_device * dev, struct comedi_devconfig * i return -EINVAL; } if (irq) { - if (comedi_request_irq(irq, pcl711_interrupt, 0, "pcl711", dev)) { + if (request_irq(irq, pcl711_interrupt, 0, "pcl711", dev)) { printk("unable to allocate irq %u\n", irq); return -EINVAL; } else { @@ -550,9 +551,12 @@ static int pcl711_attach(struct comedi_device * dev, struct comedi_devconfig * i } dev->irq = irq; - if ((ret = alloc_subdevices(dev, 4)) < 0) + ret = alloc_subdevices(dev, 4); + if (ret < 0) return ret; - if ((ret = alloc_private(dev, sizeof(struct pcl711_private))) < 0) + + ret = alloc_private(dev, sizeof(struct pcl711_private)); + if (ret < 0) return ret; s = dev->subdevices + 0; diff --git a/drivers/staging/comedi/drivers/pcl724.c b/drivers/staging/comedi/drivers/pcl724.c index cd1e784f25f9..699daff3035a 100644 --- a/drivers/staging/comedi/drivers/pcl724.c +++ b/drivers/staging/comedi/drivers/pcl724.c @@ -54,18 +54,18 @@ See the source for configuration details. #define SIZE_8255 4 -// #define PCL724_IRQ 1 /* no IRQ support now */ +/* #define PCL724_IRQ 1 no IRQ support now */ -static int pcl724_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int pcl724_detach(struct comedi_device * dev); +static int pcl724_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int pcl724_detach(struct comedi_device *dev); struct pcl724_board { - const char *name; // board name - int dio; // num of DIO - int numofports; // num of 8255 subdevices - unsigned int IRQbits; // allowed interrupts - unsigned int io_range; // len of IO space + const char *name; /* board name */ + int dio; /* num of DIO */ + int numofports; /* num of 8255 subdevices */ + unsigned int IRQbits; /* allowed interrupts */ + unsigned int io_range; /* len of IO space */ char can_have96; char is_pet48; }; @@ -84,13 +84,13 @@ static const struct pcl724_board boardtypes[] = { #define this_board ((const struct pcl724_board *)dev->board_ptr) static struct comedi_driver driver_pcl724 = { - driver_name:"pcl724", - module:THIS_MODULE, - attach:pcl724_attach, - detach:pcl724_detach, - board_name:&boardtypes[0].name, - num_names:n_boardtypes, - offset:sizeof(struct pcl724_board), + .driver_name = "pcl724", + .module = THIS_MODULE, + .attach = pcl724_attach, + .detach = pcl724_detach, + .board_name = &boardtypes[0].name, + .num_names = n_boardtypes, + .offset = sizeof(struct pcl724_board), }; COMEDI_INITCLEANUP(driver_pcl724); @@ -124,7 +124,7 @@ static int subdev_8255mapped_cb(int dir, int port, int data, } } -static int pcl724_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int pcl724_attach(struct comedi_device *dev, struct comedi_devconfig *it) { unsigned long iobase; unsigned int iorange; @@ -137,7 +137,7 @@ static int pcl724_attach(struct comedi_device * dev, struct comedi_devconfig * i iorange = this_board->io_range; if ((this_board->can_have96) && ((it->options[1] == 1) || (it->options[1] == 96))) - iorange = PCL722_96_SIZE; // PCL-724 in 96 DIO configuration + iorange = PCL722_96_SIZE; /* PCL-724 in 96 DIO configuration */ printk("comedi%d: pcl724: board=%s, 0x%03lx ", dev->minor, this_board->name, iobase); if (!request_region(iobase, iorange, "pcl724")) { @@ -155,19 +155,18 @@ static int pcl724_attach(struct comedi_device * dev, struct comedi_devconfig * i irq = it->options[1]; if (irq) { /* we want to use IRQ */ if (((1 << irq) & this_board->IRQbits) == 0) { - rt_printk + printk (", IRQ %u is out of allowed range, DISABLING IT", irq); irq = 0; /* Bad IRQ */ } else { - if (comedi_request_irq(irq, interrupt_pcl724, 0, - "pcl724", dev)) { - rt_printk + if (request_irq(irq, interrupt_pcl724, 0, "pcl724", dev)) { + printk (", unable to allocate IRQ %u, DISABLING IT", irq); irq = 0; /* Can't use IRQ */ } else { - rt_printk(", irq=%u", irq); + printk(", irq=%u", irq); } } } @@ -181,9 +180,10 @@ static int pcl724_attach(struct comedi_device * dev, struct comedi_devconfig * i n_subdevices = this_board->numofports; if ((this_board->can_have96) && ((it->options[1] == 1) || (it->options[1] == 96))) - n_subdevices = 4; // PCL-724 in 96 DIO configuration + n_subdevices = 4; /* PCL-724 in 96 DIO configuration */ - if ((ret = alloc_subdevices(dev, n_subdevices)) < 0) + ret = alloc_subdevices(dev, n_subdevices); + if (ret < 0) return ret; for (i = 0; i < dev->n_subdevices; i++) { @@ -200,11 +200,11 @@ static int pcl724_attach(struct comedi_device * dev, struct comedi_devconfig * i return 0; } -static int pcl724_detach(struct comedi_device * dev) +static int pcl724_detach(struct comedi_device *dev) { int i; -// printk("comedi%d: pcl724: remove\n",dev->minor); +/* printk("comedi%d: pcl724: remove\n",dev->minor); */ for (i = 0; i < dev->n_subdevices; i++) { subdev_8255_cleanup(dev, dev->subdevices + i); @@ -212,7 +212,7 @@ static int pcl724_detach(struct comedi_device * dev) #ifdef PCL724_IRQ if (dev->irq) { - comedi_free_irq(dev->irq, dev); + free_irq(dev->irq, dev); } #endif diff --git a/drivers/staging/comedi/drivers/pcl725.c b/drivers/staging/comedi/drivers/pcl725.c index 0766ba02bd03..1347624d0519 100644 --- a/drivers/staging/comedi/drivers/pcl725.c +++ b/drivers/staging/comedi/drivers/pcl725.c @@ -20,19 +20,19 @@ Devices: [Advantech] PCL-725 (pcl725) #define PCL725_DO 0 #define PCL725_DI 1 -static int pcl725_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int pcl725_detach(struct comedi_device * dev); +static int pcl725_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int pcl725_detach(struct comedi_device *dev); static struct comedi_driver driver_pcl725 = { - driver_name:"pcl725", - module:THIS_MODULE, - attach:pcl725_attach, - detach:pcl725_detach, + .driver_name = "pcl725", + .module = THIS_MODULE, + .attach = pcl725_attach, + .detach = pcl725_detach, }; COMEDI_INITCLEANUP(driver_pcl725); -static int pcl725_do_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pcl725_do_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if (insn->n != 2) return -EINVAL; @@ -48,8 +48,8 @@ static int pcl725_do_insn(struct comedi_device * dev, struct comedi_subdevice * return 2; } -static int pcl725_di_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pcl725_di_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if (insn->n != 2) return -EINVAL; @@ -59,7 +59,7 @@ static int pcl725_di_insn(struct comedi_device * dev, struct comedi_subdevice * return 2; } -static int pcl725_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int pcl725_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; unsigned long iobase; @@ -100,7 +100,7 @@ static int pcl725_attach(struct comedi_device * dev, struct comedi_devconfig * i return 0; } -static int pcl725_detach(struct comedi_device * dev) +static int pcl725_detach(struct comedi_device *dev) { printk("comedi%d: pcl725: remove\n", dev->minor); diff --git a/drivers/staging/comedi/drivers/pcl726.c b/drivers/staging/comedi/drivers/pcl726.c index 6dbd33d7907b..149e75f0e09c 100644 --- a/drivers/staging/comedi/drivers/pcl726.c +++ b/drivers/staging/comedi/drivers/pcl726.c @@ -111,22 +111,22 @@ static const struct comedi_lrange *const rangelist_728[] = { &range_4_20mA, &range_0_20mA }; -static int pcl726_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int pcl726_detach(struct comedi_device * dev); +static int pcl726_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int pcl726_detach(struct comedi_device *dev); struct pcl726_board { - const char *name; // driver name - int n_aochan; // num of D/A chans - int num_of_ranges; // num of ranges - unsigned int IRQbits; // allowed interrupts - unsigned int io_range; // len of IO space - char have_dio; // 1=card have DI/DO ports - int di_hi; // ports for DI/DO operations + const char *name; /* driver name */ + int n_aochan; /* num of D/A chans */ + int num_of_ranges; /* num of ranges */ + unsigned int IRQbits; /* allowed interrupts */ + unsigned int io_range; /* len of IO space */ + char have_dio; /* 1=card have DI/DO ports */ + int di_hi; /* ports for DI/DO operations */ int di_lo; int do_hi; int do_lo; - const struct comedi_lrange *const *range_type_list; // list of supported ranges + const struct comedi_lrange *const *range_type_list; /* list of supported ranges */ }; @@ -152,13 +152,13 @@ static const struct pcl726_board boardtypes[] = { #define this_board ((const struct pcl726_board *)dev->board_ptr) static struct comedi_driver driver_pcl726 = { - driver_name:"pcl726", - module:THIS_MODULE, - attach:pcl726_attach, - detach:pcl726_detach, - board_name:&boardtypes[0].name, - num_names:n_boardtypes, - offset:sizeof(struct pcl726_board), + .driver_name = "pcl726", + .module = THIS_MODULE, + .attach = pcl726_attach, + .detach = pcl726_detach, + .board_name = &boardtypes[0].name, + .num_names = n_boardtypes, + .offset = sizeof(struct pcl726_board), }; COMEDI_INITCLEANUP(driver_pcl726); @@ -172,8 +172,8 @@ struct pcl726_private { #define devpriv ((struct pcl726_private *)dev->private) -static int pcl726_ao_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pcl726_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int hi, lo; int n; @@ -197,8 +197,8 @@ static int pcl726_ao_insn(struct comedi_device * dev, struct comedi_subdevice * return n; } -static int pcl726_ao_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pcl726_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int chan = CR_CHAN(insn->chanspec); int n; @@ -209,8 +209,8 @@ static int pcl726_ao_insn_read(struct comedi_device * dev, struct comedi_subdevi return n; } -static int pcl726_di_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pcl726_di_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if (insn->n != 2) return -EINVAL; @@ -221,8 +221,8 @@ static int pcl726_di_insn_bits(struct comedi_device * dev, struct comedi_subdevi return 2; } -static int pcl726_do_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pcl726_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if (insn->n != 2) return -EINVAL; @@ -241,7 +241,7 @@ static int pcl726_do_insn_bits(struct comedi_device * dev, struct comedi_subdevi return 2; } -static int pcl726_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int pcl726_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; unsigned long iobase; @@ -264,7 +264,8 @@ static int pcl726_attach(struct comedi_device * dev, struct comedi_devconfig * i dev->board_name = this_board->name; - if ((ret = alloc_private(dev, sizeof(struct pcl726_private))) < 0) + ret = alloc_private(dev, sizeof(struct pcl726_private)); + if (ret < 0) return -ENOMEM; for (i = 0; i < 12; i++) { @@ -279,19 +280,19 @@ static int pcl726_attach(struct comedi_device * dev, struct comedi_devconfig * i devpriv->first_chan = 2; if (irq) { /* we want to use IRQ */ if (((1 << irq) & boardtypes[board].IRQbits) == 0) { - rt_printk + printk (", IRQ %d is out of allowed range, DISABLING IT", irq); irq = 0; /* Bad IRQ */ } else { - if (comedi_request_irq(irq, interrupt_pcl818, 0, + if (request_irq(irq, interrupt_pcl818, 0, "pcl726", dev)) { - rt_printk + printk (", unable to allocate IRQ %d, DISABLING IT", irq); irq = 0; /* Can't use IRQ */ } else { - rt_printk(", irq=%d", irq); + printk(", irq=%d", irq); } } } @@ -302,7 +303,8 @@ static int pcl726_attach(struct comedi_device * dev, struct comedi_devconfig * i printk("\n"); - if ((ret = alloc_subdevices(dev, 3)) < 0) + ret = alloc_subdevices(dev, 3); + if (ret < 0) return ret; s = dev->subdevices + 0; @@ -360,13 +362,13 @@ static int pcl726_attach(struct comedi_device * dev, struct comedi_devconfig * i return 0; } -static int pcl726_detach(struct comedi_device * dev) +static int pcl726_detach(struct comedi_device *dev) { -// printk("comedi%d: pcl726: remove\n",dev->minor); +/* printk("comedi%d: pcl726: remove\n",dev->minor); */ #ifdef ACL6126_IRQ if (dev->irq) { - comedi_free_irq(dev->irq, dev); + free_irq(dev->irq, dev); } #endif diff --git a/drivers/staging/comedi/drivers/pcl730.c b/drivers/staging/comedi/drivers/pcl730.c index f2c6d7c5693c..408cbffae418 100644 --- a/drivers/staging/comedi/drivers/pcl730.c +++ b/drivers/staging/comedi/drivers/pcl730.c @@ -26,13 +26,13 @@ The ACL-7130 card have an 8254 timer/counter not supported by this driver. #define PCL730_DIO_LO 2 /* TTL Digital I/O low byte (D0-D7) */ #define PCL730_DIO_HI 3 /* TTL Digital I/O high byte (D8-D15) */ -static int pcl730_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int pcl730_detach(struct comedi_device * dev); +static int pcl730_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int pcl730_detach(struct comedi_device *dev); struct pcl730_board { - const char *name; // board name - unsigned int io_range; // len of I/O space + const char *name; /* board name */ + unsigned int io_range; /* len of I/O space */ }; @@ -46,19 +46,19 @@ static const struct pcl730_board boardtypes[] = { #define this_board ((const struct pcl730_board *)dev->board_ptr) static struct comedi_driver driver_pcl730 = { - driver_name:"pcl730", - module:THIS_MODULE, - attach:pcl730_attach, - detach:pcl730_detach, - board_name:&boardtypes[0].name, - num_names:n_boardtypes, - offset:sizeof(struct pcl730_board), + .driver_name = "pcl730", + .module = THIS_MODULE, + .attach = pcl730_attach, + .detach = pcl730_detach, + .board_name = &boardtypes[0].name, + .num_names = n_boardtypes, + .offset = sizeof(struct pcl730_board), }; COMEDI_INITCLEANUP(driver_pcl730); -static int pcl730_do_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pcl730_do_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if (insn->n != 2) return -EINVAL; @@ -79,8 +79,8 @@ static int pcl730_do_insn(struct comedi_device * dev, struct comedi_subdevice * return 2; } -static int pcl730_di_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pcl730_di_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if (insn->n != 2) return -EINVAL; @@ -91,7 +91,7 @@ static int pcl730_di_insn(struct comedi_device * dev, struct comedi_subdevice * return 2; } -static int pcl730_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int pcl730_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; unsigned long iobase; @@ -157,7 +157,7 @@ static int pcl730_attach(struct comedi_device * dev, struct comedi_devconfig * i return 0; } -static int pcl730_detach(struct comedi_device * dev) +static int pcl730_detach(struct comedi_device *dev) { printk("comedi%d: pcl730: remove\n", dev->minor); diff --git a/drivers/staging/comedi/drivers/pcl812.c b/drivers/staging/comedi/drivers/pcl812.c index 11dfd230e565..dd91fe9f5f51 100644 --- a/drivers/staging/comedi/drivers/pcl812.c +++ b/drivers/staging/comedi/drivers/pcl812.c @@ -107,6 +107,7 @@ Options for ACL-8113, ISO-813: 3= 20V unipolar inputs */ +#include #include "../comedidev.h" #include @@ -117,7 +118,7 @@ Options for ACL-8113, ISO-813: #undef PCL812_EXTDEBUG /* if this is defined then a lot of messages is printed */ -// hardware types of the cards +/* hardware types of the cards */ #define boardPCL812PG 0 /* and ACL-8112PG */ #define boardPCL813B 1 #define boardPCL812 2 @@ -292,27 +293,27 @@ static const struct comedi_lrange range_a821pgh_ai = { 4, { } }; -static int pcl812_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int pcl812_detach(struct comedi_device * dev); +static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int pcl812_detach(struct comedi_device *dev); struct pcl812_board { - const char *name; // board name - int board_type; // type of this board - int n_aichan; // num of AI chans in S.E. - int n_aichan_diff; // DIFF num of chans - int n_aochan; // num of DA chans - int n_dichan; // DI and DO chans + const char *name; /* board name */ + int board_type; /* type of this board */ + int n_aichan; /* num of AI chans in S.E. */ + int n_aichan_diff; /* DIFF num of chans */ + int n_aochan; /* num of DA chans */ + int n_dichan; /* DI and DO chans */ int n_dochan; - int ai_maxdata; // AI resolution - unsigned int ai_ns_min; // max sample speed of card v ns - unsigned int i8254_osc_base; // clock base - const struct comedi_lrange *rangelist_ai; // rangelist for A/D - const struct comedi_lrange *rangelist_ao; // rangelist for D/A - unsigned int IRQbits; // allowed IRQ - unsigned char DMAbits; // allowed DMA chans - unsigned char io_range; // iorange for this board - unsigned char haveMPC508; // 1=board use MPC508A multiplexor + int ai_maxdata; /* AI resolution */ + unsigned int ai_ns_min; /* max sample speed of card v ns */ + unsigned int i8254_osc_base; /* clock base */ + const struct comedi_lrange *rangelist_ai; /* rangelist for A/D */ + const struct comedi_lrange *rangelist_ao; /* rangelist for D/A */ + unsigned int IRQbits; /* allowed IRQ */ + unsigned char DMAbits; /* allowed DMA chans */ + unsigned char io_range; /* iorange for this board */ + unsigned char haveMPC508; /* 1=board use MPC508A multiplexor */ }; @@ -377,50 +378,50 @@ static const struct pcl812_board boardtypes[] = { #define this_board ((const struct pcl812_board *)dev->board_ptr) static struct comedi_driver driver_pcl812 = { - driver_name:"pcl812", - module:THIS_MODULE, - attach:pcl812_attach, - detach:pcl812_detach, - board_name:&boardtypes[0].name, - num_names:n_boardtypes, - offset:sizeof(struct pcl812_board), + .driver_name = "pcl812", + .module = THIS_MODULE, + .attach = pcl812_attach, + .detach = pcl812_detach, + .board_name = &boardtypes[0].name, + .num_names = n_boardtypes, + .offset = sizeof(struct pcl812_board), }; COMEDI_INITCLEANUP(driver_pcl812); struct pcl812_private { - unsigned char valid; // =1 device is OK - unsigned char dma; // >0 use dma ( usedDMA channel) - unsigned char use_diff; // =1 diff inputs - unsigned char use_MPC; // 1=board uses MPC508A multiplexor - unsigned char use_ext_trg; // 1=board uses external trigger - unsigned char range_correction; // =1 we must add 1 to range number - unsigned char old_chan_reg; // lastly used chan/gain pair + unsigned char valid; /* =1 device is OK */ + unsigned char dma; /* >0 use dma ( usedDMA channel) */ + unsigned char use_diff; /* =1 diff inputs */ + unsigned char use_MPC; /* 1=board uses MPC508A multiplexor */ + unsigned char use_ext_trg; /* 1=board uses external trigger */ + unsigned char range_correction; /* =1 we must add 1 to range number */ + unsigned char old_chan_reg; /* lastly used chan/gain pair */ unsigned char old_gain_reg; - unsigned char mode_reg_int; // there is stored INT number for some card - unsigned char ai_neverending; // =1 we do unlimited AI - unsigned char ai_eos; // 1=EOS wake up - unsigned char ai_dma; // =1 we use DMA - unsigned int ai_poll_ptr; // how many sampes transfer poll - unsigned int ai_scans; // len of scanlist - unsigned int ai_act_scan; // how many scans we finished - unsigned int ai_chanlist[MAX_CHANLIST_LEN]; // our copy of channel/range list - unsigned int ai_n_chan; // how many channels is measured - unsigned int ai_flags; // flaglist - unsigned int ai_data_len; // len of data buffer - short *ai_data; // data buffer - unsigned int ai_is16b; // =1 we have 16 bit card - unsigned long dmabuf[2]; // PTR to DMA buf - unsigned int dmapages[2]; // how many pages we have allocated - unsigned int hwdmaptr[2]; // HW PTR to DMA buf - unsigned int hwdmasize[2]; // DMA buf size in bytes - unsigned int dmabytestomove[2]; // how many bytes DMA transfer - int next_dma_buf; // which buffer is next to use - unsigned int dma_runs_to_end; // how many times we must switch DMA buffers - unsigned int last_dma_run; // how many bytes to transfer on last DMA buffer - unsigned int max_812_ai_mode0_rangewait; // setling time for gain - unsigned int ao_readback[2]; // data for AO readback + unsigned char mode_reg_int; /* there is stored INT number for some card */ + unsigned char ai_neverending; /* =1 we do unlimited AI */ + unsigned char ai_eos; /* 1=EOS wake up */ + unsigned char ai_dma; /* =1 we use DMA */ + unsigned int ai_poll_ptr; /* how many sampes transfer poll */ + unsigned int ai_scans; /* len of scanlist */ + unsigned int ai_act_scan; /* how many scans we finished */ + unsigned int ai_chanlist[MAX_CHANLIST_LEN]; /* our copy of channel/range list */ + unsigned int ai_n_chan; /* how many channels is measured */ + unsigned int ai_flags; /* flaglist */ + unsigned int ai_data_len; /* len of data buffer */ + short *ai_data; /* data buffer */ + unsigned int ai_is16b; /* =1 we have 16 bit card */ + unsigned long dmabuf[2]; /* PTR to DMA buf */ + unsigned int dmapages[2]; /* how many pages we have allocated */ + unsigned int hwdmaptr[2]; /* HW PTR to DMA buf */ + unsigned int hwdmasize[2]; /* DMA buf size in bytes */ + unsigned int dmabytestomove[2]; /* how many bytes DMA transfer */ + int next_dma_buf; /* which buffer is next to use */ + unsigned int dma_runs_to_end; /* how many times we must switch DMA buffers */ + unsigned int last_dma_run; /* how many bytes to transfer on last DMA buffer */ + unsigned int max_812_ai_mode0_rangewait; /* setling time for gain */ + unsigned int ao_readback[2]; /* data for AO readback */ }; @@ -429,33 +430,33 @@ struct pcl812_private { /* ============================================================================== */ -static void start_pacer(struct comedi_device * dev, int mode, unsigned int divisor1, +static void start_pacer(struct comedi_device *dev, int mode, unsigned int divisor1, unsigned int divisor2); -static void setup_range_channel(struct comedi_device * dev, struct comedi_subdevice * s, +static void setup_range_channel(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int rangechan, char wait); -static int pcl812_ai_cancel(struct comedi_device * dev, struct comedi_subdevice * s); +static int pcl812_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s); /* ============================================================================== */ -static int pcl812_ai_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pcl812_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int n; int timeout, hi; outb(devpriv->mode_reg_int | 1, dev->iobase + PCL812_MODE); /* select software trigger */ - setup_range_channel(dev, s, insn->chanspec, 1); // select channel and renge + setup_range_channel(dev, s, insn->chanspec, 1); /* select channel and renge */ for (n = 0; n < insn->n; n++) { outb(255, dev->iobase + PCL812_SOFTTRIG); /* start conversion */ - comedi_udelay(5); + udelay(5); timeout = 50; /* wait max 50us, it must finish under 33us */ while (timeout--) { hi = inb(dev->iobase + PCL812_AD_HI); if (!(hi & PCL812_DRDY)) goto conv_finish; - comedi_udelay(1); + udelay(1); } - rt_printk + printk ("comedi%d: pcl812: (%s at 0x%lx) A/D insn read timeout\n", dev->minor, dev->board_name, dev->iobase); outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE); @@ -471,24 +472,24 @@ static int pcl812_ai_insn_read(struct comedi_device * dev, struct comedi_subdevi /* ============================================================================== */ -static int acl8216_ai_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int acl8216_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int n; int timeout; outb(1, dev->iobase + PCL812_MODE); /* select software trigger */ - setup_range_channel(dev, s, insn->chanspec, 1); // select channel and renge + setup_range_channel(dev, s, insn->chanspec, 1); /* select channel and renge */ for (n = 0; n < insn->n; n++) { outb(255, dev->iobase + PCL812_SOFTTRIG); /* start conversion */ - comedi_udelay(5); + udelay(5); timeout = 50; /* wait max 50us, it must finish under 33us */ while (timeout--) { if (!(inb(dev->iobase + ACL8216_STATUS) & ACL8216_DRDY)) goto conv_finish; - comedi_udelay(1); + udelay(1); } - rt_printk + printk ("comedi%d: pcl812: (%s at 0x%lx) A/D insn read timeout\n", dev->minor, dev->board_name, dev->iobase); outb(0, dev->iobase + PCL812_MODE); @@ -507,8 +508,8 @@ static int acl8216_ai_insn_read(struct comedi_device * dev, struct comedi_subdev /* ============================================================================== */ -static int pcl812_ao_insn_write(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pcl812_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int chan = CR_CHAN(insn->chanspec); int i; @@ -527,8 +528,8 @@ static int pcl812_ao_insn_write(struct comedi_device * dev, struct comedi_subdev /* ============================================================================== */ -static int pcl812_ao_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pcl812_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int chan = CR_CHAN(insn->chanspec); int i; @@ -543,8 +544,8 @@ static int pcl812_ao_insn_read(struct comedi_device * dev, struct comedi_subdevi /* ============================================================================== */ -static int pcl812_di_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pcl812_di_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if (insn->n != 2) return -EINVAL; @@ -558,8 +559,8 @@ static int pcl812_di_insn_bits(struct comedi_device * dev, struct comedi_subdevi /* ============================================================================== */ -static int pcl812_do_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pcl812_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if (insn->n != 2) return -EINVAL; @@ -579,15 +580,15 @@ static int pcl812_do_insn_bits(struct comedi_device * dev, struct comedi_subdevi /* ============================================================================== */ -static void pcl812_cmdtest_out(int e, struct comedi_cmd * cmd) +static void pcl812_cmdtest_out(int e, struct comedi_cmd *cmd) { - rt_printk("pcl812 e=%d startsrc=%x scansrc=%x convsrc=%x\n", e, + printk("pcl812 e=%d startsrc=%x scansrc=%x convsrc=%x\n", e, cmd->start_src, cmd->scan_begin_src, cmd->convert_src); - rt_printk("pcl812 e=%d startarg=%d scanarg=%d convarg=%d\n", e, + printk("pcl812 e=%d startarg=%d scanarg=%d convarg=%d\n", e, cmd->start_arg, cmd->scan_begin_arg, cmd->convert_arg); - rt_printk("pcl812 e=%d stopsrc=%x scanend=%x\n", e, cmd->stop_src, + printk("pcl812 e=%d stopsrc=%x scanend=%x\n", e, cmd->stop_src, cmd->scan_end_src); - rt_printk("pcl812 e=%d stoparg=%d scanendarg=%d chanlistlen=%d\n", e, + printk("pcl812 e=%d stoparg=%d scanendarg=%d chanlistlen=%d\n", e, cmd->stop_arg, cmd->scan_end_arg, cmd->chanlist_len); } #endif @@ -595,14 +596,14 @@ static void pcl812_cmdtest_out(int e, struct comedi_cmd * cmd) /* ============================================================================== */ -static int pcl812_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd) +static int pcl812_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd) { int err = 0; int tmp, divisor1, divisor2; #ifdef PCL812_EXTDEBUG - rt_printk("pcl812 EDBG: BGN: pcl812_ai_cmdtest(...)\n"); + printk("pcl812 EDBG: BGN: pcl812_ai_cmdtest(...)\n"); pcl812_cmdtest_out(-1, cmd); #endif /* step 1: make sure trigger sources are trivially valid */ @@ -639,7 +640,7 @@ static int pcl812_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice if (err) { #ifdef PCL812_EXTDEBUG pcl812_cmdtest_out(1, cmd); - rt_printk + printk ("pcl812 EDBG: BGN: pcl812_ai_cmdtest(...) err=%d ret=1\n", err); #endif @@ -681,7 +682,7 @@ static int pcl812_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice if (err) { #ifdef PCL812_EXTDEBUG pcl812_cmdtest_out(2, cmd); - rt_printk + printk ("pcl812 EDBG: BGN: pcl812_ai_cmdtest(...) err=%d ret=2\n", err); #endif @@ -739,7 +740,7 @@ static int pcl812_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice if (err) { #ifdef PCL812_EXTDEBUG pcl812_cmdtest_out(3, cmd); - rt_printk + printk ("pcl812 EDBG: BGN: pcl812_ai_cmdtest(...) err=%d ret=3\n", err); #endif @@ -761,7 +762,7 @@ static int pcl812_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice if (err) { #ifdef PCL812_EXTDEBUG - rt_printk + printk ("pcl812 EDBG: BGN: pcl812_ai_cmdtest(...) err=%d ret=4\n", err); #endif @@ -774,13 +775,13 @@ static int pcl812_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice /* ============================================================================== */ -static int pcl812_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s) +static int pcl812_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { unsigned int divisor1 = 0, divisor2 = 0, i, dma_flags, bytes; struct comedi_cmd *cmd = &s->async->cmd; #ifdef PCL812_EXTDEBUG - rt_printk("pcl812 EDBG: BGN: pcl812_ai_cmd(...)\n"); + printk("pcl812 EDBG: BGN: pcl812_ai_cmd(...)\n"); #endif if (cmd->start_src != TRIG_NOW) @@ -809,18 +810,18 @@ static int pcl812_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s cmd->flags & TRIG_ROUND_MASK); } - start_pacer(dev, -1, 0, 0); // stop pacer + start_pacer(dev, -1, 0, 0); /* stop pacer */ devpriv->ai_n_chan = cmd->chanlist_len; memcpy(devpriv->ai_chanlist, cmd->chanlist, sizeof(unsigned int) * cmd->scan_end_arg); - setup_range_channel(dev, s, devpriv->ai_chanlist[0], 1); // select first channel and range + setup_range_channel(dev, s, devpriv->ai_chanlist[0], 1); /* select first channel and range */ - if (devpriv->dma) { // check if we can use DMA transfer + if (devpriv->dma) { /* check if we can use DMA transfer */ devpriv->ai_dma = 1; for (i = 1; i < devpriv->ai_n_chan; i++) if (devpriv->ai_chanlist[0] != devpriv->ai_chanlist[i]) { - devpriv->ai_dma = 0; // we cann't use DMA :-( + devpriv->ai_dma = 0; /* we cann't use DMA :-( */ break; } } else @@ -841,14 +842,14 @@ static int pcl812_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s devpriv->ai_poll_ptr = 0; s->async->cur_chan = 0; - if ((devpriv->ai_flags & TRIG_WAKE_EOS)) { // don't we want wake up every scan? + if ((devpriv->ai_flags & TRIG_WAKE_EOS)) { /* don't we want wake up every scan? */ devpriv->ai_eos = 1; if (devpriv->ai_n_chan == 1) - devpriv->ai_dma = 0; // DMA is useless for this situation + devpriv->ai_dma = 0; /* DMA is useless for this situation */ } if (devpriv->ai_dma) { - if (devpriv->ai_eos) { // we use EOS, so adapt DMA buffer to one scan + if (devpriv->ai_eos) { /* we use EOS, so adapt DMA buffer to one scan */ devpriv->dmabytestomove[0] = devpriv->ai_n_chan * sizeof(short); devpriv->dmabytestomove[1] = @@ -866,9 +867,9 @@ static int pcl812_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s if (devpriv->ai_neverending) { devpriv->dma_runs_to_end = 1; } else { - bytes = devpriv->ai_n_chan * devpriv->ai_scans * sizeof(short); // how many samples we must transfer? - devpriv->dma_runs_to_end = bytes / devpriv->dmabytestomove[0]; // how many DMA pages we must fill - devpriv->last_dma_run = bytes % devpriv->dmabytestomove[0]; //on last dma transfer must be moved + bytes = devpriv->ai_n_chan * devpriv->ai_scans * sizeof(short); /* how many samples we must transfer? */ + devpriv->dma_runs_to_end = bytes / devpriv->dmabytestomove[0]; /* how many DMA pages we must fill */ + devpriv->last_dma_run = bytes % devpriv->dmabytestomove[0]; /* on last dma transfer must be moved */ if (devpriv->dma_runs_to_end == 0) devpriv->dmabytestomove[0] = devpriv->last_dma_run; @@ -892,7 +893,7 @@ static int pcl812_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s release_dma_lock(dma_flags); enable_dma(devpriv->dma); #ifdef PCL812_EXTDEBUG - rt_printk + printk ("pcl812 EDBG: DMA %d PTR 0x%0x/0x%0x LEN %u/%u EOS %d\n", devpriv->dma, devpriv->hwdmaptr[0], devpriv->hwdmaptr[1], devpriv->dmabytestomove[0], @@ -907,13 +908,13 @@ static int pcl812_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s } if (devpriv->ai_dma) { - outb(devpriv->mode_reg_int | 2, dev->iobase + PCL812_MODE); // let's go! + outb(devpriv->mode_reg_int | 2, dev->iobase + PCL812_MODE); /* let's go! */ } else { - outb(devpriv->mode_reg_int | 6, dev->iobase + PCL812_MODE); // let's go! + outb(devpriv->mode_reg_int | 6, dev->iobase + PCL812_MODE); /* let's go! */ } #ifdef PCL812_EXTDEBUG - rt_printk("pcl812 EDBG: END: pcl812_ai_cmd(...)\n"); + printk("pcl812 EDBG: END: pcl812_ai_cmd(...)\n"); #endif return 0; @@ -939,7 +940,7 @@ static irqreturn_t interrupt_pcl812_ai_int(int irq, void *d) err = 0; break; } - comedi_udelay(1); + udelay(1); } } else { mask = 0x0fff; @@ -948,12 +949,12 @@ static irqreturn_t interrupt_pcl812_ai_int(int irq, void *d) err = 0; break; } - comedi_udelay(1); + udelay(1); } } if (err) { - rt_printk + printk ("comedi%d: pcl812: (%s at 0x%lx) A/D cmd IRQ without DRDY!\n", dev->minor, dev->board_name, dev->iobase); pcl812_ai_cancel(dev, s); @@ -984,14 +985,14 @@ static irqreturn_t interrupt_pcl812_ai_int(int irq, void *d) /* ============================================================================== */ -static void transfer_from_dma_buf(struct comedi_device * dev, struct comedi_subdevice * s, - short * ptr, unsigned int bufptr, unsigned int len) +static void transfer_from_dma_buf(struct comedi_device *dev, struct comedi_subdevice *s, + short *ptr, unsigned int bufptr, unsigned int len) { unsigned int i; s->async->events = 0; for (i = len; i; i--) { - comedi_buf_put(s->async, ptr[bufptr++]); // get one sample + comedi_buf_put(s->async, ptr[bufptr++]); /* get one sample */ if (s->async->cur_chan == 0) { devpriv->ai_act_scan++; @@ -1019,7 +1020,7 @@ static irqreturn_t interrupt_pcl812_ai_dma(int irq, void *d) short *ptr; #ifdef PCL812_EXTDEBUG - rt_printk("pcl812 EDBG: BGN: interrupt_pcl812_ai_dma(...)\n"); + printk("pcl812 EDBG: BGN: interrupt_pcl812_ai_dma(...)\n"); #endif ptr = (short *) devpriv->dmabuf[devpriv->next_dma_buf]; len = (devpriv->dmabytestomove[devpriv->next_dma_buf] >> 1) - @@ -1053,7 +1054,7 @@ static irqreturn_t interrupt_pcl812_ai_dma(int irq, void *d) transfer_from_dma_buf(dev, s, ptr, bufptr, len); #ifdef PCL812_EXTDEBUG - rt_printk("pcl812 EDBG: END: interrupt_pcl812_ai_dma(...)\n"); + printk("pcl812 EDBG: END: interrupt_pcl812_ai_dma(...)\n"); #endif return IRQ_HANDLED; } @@ -1061,7 +1062,7 @@ static irqreturn_t interrupt_pcl812_ai_dma(int irq, void *d) /* ============================================================================== */ -static irqreturn_t interrupt_pcl812(int irq, void *d PT_REGS_ARG) +static irqreturn_t interrupt_pcl812(int irq, void *d) { struct comedi_device *dev = d; @@ -1079,33 +1080,33 @@ static irqreturn_t interrupt_pcl812(int irq, void *d PT_REGS_ARG) /* ============================================================================== */ -static int pcl812_ai_poll(struct comedi_device * dev, struct comedi_subdevice * s) +static int pcl812_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s) { unsigned long flags; unsigned int top1, top2, i; if (!devpriv->ai_dma) - return 0; // poll is valid only for DMA transfer + return 0; /* poll is valid only for DMA transfer */ - comedi_spin_lock_irqsave(&dev->spinlock, flags); + spin_lock_irqsave(&dev->spinlock, flags); for (i = 0; i < 10; i++) { - top1 = get_dma_residue(devpriv->ai_dma); // where is now DMA + top1 = get_dma_residue(devpriv->ai_dma); /* where is now DMA */ top2 = get_dma_residue(devpriv->ai_dma); if (top1 == top2) break; } if (top1 != top2) { - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); return 0; } - top1 = devpriv->dmabytestomove[1 - devpriv->next_dma_buf] - top1; // where is now DMA in buffer - top1 >>= 1; // sample position + top1 = devpriv->dmabytestomove[1 - devpriv->next_dma_buf] - top1; /* where is now DMA in buffer */ + top1 >>= 1; /* sample position */ top2 = top1 - devpriv->ai_poll_ptr; - if (top2 < 1) { // no new samples - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + if (top2 < 1) { /* no new samples */ + spin_unlock_irqrestore(&dev->spinlock, flags); return 0; } @@ -1113,9 +1114,9 @@ static int pcl812_ai_poll(struct comedi_device * dev, struct comedi_subdevice * (void *)devpriv->dmabuf[1 - devpriv->next_dma_buf], devpriv->ai_poll_ptr, top2); - devpriv->ai_poll_ptr = top1; // new buffer position + devpriv->ai_poll_ptr = top1; /* new buffer position */ - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); return s->async->buf_write_count - s->async->buf_read_count; } @@ -1123,27 +1124,27 @@ static int pcl812_ai_poll(struct comedi_device * dev, struct comedi_subdevice * /* ============================================================================== */ -static void setup_range_channel(struct comedi_device * dev, struct comedi_subdevice * s, +static void setup_range_channel(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int rangechan, char wait) { - unsigned char chan_reg = CR_CHAN(rangechan); // normal board - unsigned char gain_reg = CR_RANGE(rangechan) + devpriv->range_correction; // gain index + unsigned char chan_reg = CR_CHAN(rangechan); /* normal board */ + unsigned char gain_reg = CR_RANGE(rangechan) + devpriv->range_correction; /* gain index */ if ((chan_reg == devpriv->old_chan_reg) && (gain_reg == devpriv->old_gain_reg)) - return; // we can return, no change + return; /* we can return, no change */ devpriv->old_chan_reg = chan_reg; devpriv->old_gain_reg = gain_reg; if (devpriv->use_MPC) { if (devpriv->use_diff) { - chan_reg = chan_reg | 0x30; // DIFF inputs + chan_reg = chan_reg | 0x30; /* DIFF inputs */ } else { if (chan_reg & 0x80) { - chan_reg = chan_reg | 0x20; // SE inputs 8-15 + chan_reg = chan_reg | 0x20; /* SE inputs 8-15 */ } else { - chan_reg = chan_reg | 0x10; // SE inputs 0-7 + chan_reg = chan_reg | 0x10; /* SE inputs 0-7 */ } } } @@ -1152,23 +1153,23 @@ static void setup_range_channel(struct comedi_device * dev, struct comedi_subdev outb(gain_reg, dev->iobase + PCL812_GAIN); /* select gain */ if (wait) { - comedi_udelay(devpriv->max_812_ai_mode0_rangewait); // XXX this depends on selected range and can be very long for some high gain ranges! + udelay(devpriv->max_812_ai_mode0_rangewait); /* XXX this depends on selected range and can be very long for some high gain ranges! */ } } /* ============================================================================== */ -static void start_pacer(struct comedi_device * dev, int mode, unsigned int divisor1, +static void start_pacer(struct comedi_device *dev, int mode, unsigned int divisor1, unsigned int divisor2) { #ifdef PCL812_EXTDEBUG - rt_printk("pcl812 EDBG: BGN: start_pacer(%d,%u,%u)\n", mode, divisor1, + printk("pcl812 EDBG: BGN: start_pacer(%d,%u,%u)\n", mode, divisor1, divisor2); #endif outb(0xb4, dev->iobase + PCL812_CTRCTL); outb(0x74, dev->iobase + PCL812_CTRCTL); - comedi_udelay(1); + udelay(1); if (mode == 1) { outb(divisor2 & 0xff, dev->iobase + PCL812_CTR2); @@ -1177,14 +1178,14 @@ static void start_pacer(struct comedi_device * dev, int mode, unsigned int divis outb((divisor1 >> 8) & 0xff, dev->iobase + PCL812_CTR1); } #ifdef PCL812_EXTDEBUG - rt_printk("pcl812 EDBG: END: start_pacer(...)\n"); + printk("pcl812 EDBG: END: start_pacer(...)\n"); #endif } /* ============================================================================== */ -static void free_resources(struct comedi_device * dev) +static void free_resources(struct comedi_device *dev) { if (dev->private) { @@ -1196,7 +1197,7 @@ static void free_resources(struct comedi_device * dev) free_dma(devpriv->dma); } if (dev->irq) - comedi_free_irq(dev->irq, dev); + free_irq(dev->irq, dev); if (dev->iobase) release_region(dev->iobase, this_board->io_range); } @@ -1204,19 +1205,19 @@ static void free_resources(struct comedi_device * dev) /* ============================================================================== */ -static int pcl812_ai_cancel(struct comedi_device * dev, struct comedi_subdevice * s) +static int pcl812_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { #ifdef PCL812_EXTDEBUG - rt_printk("pcl812 EDBG: BGN: pcl812_ai_cancel(...)\n"); + printk("pcl812 EDBG: BGN: pcl812_ai_cancel(...)\n"); #endif if (devpriv->ai_dma) disable_dma(devpriv->dma); outb(0, dev->iobase + PCL812_CLRINT); /* clear INT request */ outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE); /* Stop A/D */ - start_pacer(dev, -1, 0, 0); // stop 8254 + start_pacer(dev, -1, 0, 0); /* stop 8254 */ outb(0, dev->iobase + PCL812_CLRINT); /* clear INT request */ #ifdef PCL812_EXTDEBUG - rt_printk("pcl812 EDBG: END: pcl812_ai_cancel(...)\n"); + printk("pcl812 EDBG: END: pcl812_ai_cancel(...)\n"); #endif return 0; } @@ -1224,14 +1225,14 @@ static int pcl812_ai_cancel(struct comedi_device * dev, struct comedi_subdevice /* ============================================================================== */ -static void pcl812_reset(struct comedi_device * dev) +static void pcl812_reset(struct comedi_device *dev) { #ifdef PCL812_EXTDEBUG - rt_printk("pcl812 EDBG: BGN: pcl812_reset(...)\n"); + printk("pcl812 EDBG: BGN: pcl812_reset(...)\n"); #endif outb(0, dev->iobase + PCL812_MUX); outb(0 + devpriv->range_correction, dev->iobase + PCL812_GAIN); - devpriv->old_chan_reg = -1; // invalidate chain/gain memory + devpriv->old_chan_reg = -1; /* invalidate chain/gain memory */ devpriv->old_gain_reg = -1; switch (this_board->board_type) { @@ -1244,7 +1245,7 @@ static void pcl812_reset(struct comedi_device * dev) case boardA821: outb(0, dev->iobase + PCL812_DA1_LO); outb(0, dev->iobase + PCL812_DA1_HI); - start_pacer(dev, -1, 0, 0); // stop 8254 + start_pacer(dev, -1, 0, 0); /* stop 8254 */ outb(0, dev->iobase + PCL812_DO_HI); outb(0, dev->iobase + PCL812_DO_LO); outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE); @@ -1254,19 +1255,19 @@ static void pcl812_reset(struct comedi_device * dev) case boardPCL813: case boardISO813: case boardACL8113: - comedi_udelay(5); + udelay(5); break; } - comedi_udelay(5); + udelay(5); #ifdef PCL812_EXTDEBUG - rt_printk("pcl812 EDBG: END: pcl812_reset(...)\n"); + printk("pcl812 EDBG: END: pcl812_reset(...)\n"); #endif } /* ============================================================================== */ -static int pcl812_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it) { int ret, subdev; unsigned long iobase; @@ -1286,7 +1287,8 @@ static int pcl812_attach(struct comedi_device * dev, struct comedi_devconfig * i } dev->iobase = iobase; - if ((ret = alloc_private(dev, sizeof(struct pcl812_private))) < 0) { + ret = alloc_private(dev, sizeof(struct pcl812_private)); + if (ret < 0) { free_resources(dev); return ret; /* Can't alloc mem */ } @@ -1301,8 +1303,7 @@ static int pcl812_attach(struct comedi_device * dev, struct comedi_devconfig * i printk(", IRQ %u is out of allowed range, DISABLING IT", irq); irq = 0; /* Bad IRQ */ } else { - if (comedi_request_irq(irq, interrupt_pcl812, 0, - "pcl812", dev)) { + if (request_irq(irq, interrupt_pcl812, 0, "pcl812", dev)) { printk(", unable to allocate IRQ %u, DISABLING IT", irq); irq = 0; /* Can't use IRQ */ } else { @@ -1364,7 +1365,8 @@ static int pcl812_attach(struct comedi_device * dev, struct comedi_devconfig * i if (this_board->n_dochan > 0) n_subdevices++; - if ((ret = alloc_subdevices(dev, n_subdevices)) < 0) { + ret = alloc_subdevices(dev, n_subdevices); + if (ret < 0) { free_resources(dev); return ret; } @@ -1570,7 +1572,7 @@ static int pcl812_attach(struct comedi_device * dev, struct comedi_devconfig * i case boardACL8112: devpriv->max_812_ai_mode0_rangewait = 1; if (it->options[3] > 0) - devpriv->use_ext_trg = 1; // we use external trigger + devpriv->use_ext_trg = 1; /* we use external trigger */ case boardA821: devpriv->max_812_ai_mode0_rangewait = 1; devpriv->mode_reg_int = (irq << 4) & 0xf0; @@ -1594,11 +1596,11 @@ static int pcl812_attach(struct comedi_device * dev, struct comedi_devconfig * i /* ============================================================================== */ -static int pcl812_detach(struct comedi_device * dev) +static int pcl812_detach(struct comedi_device *dev) { #ifdef PCL812_EXTDEBUG - rt_printk("comedi%d: pcl812: remove\n", dev->minor); + printk("comedi%d: pcl812: remove\n", dev->minor); #endif free_resources(dev); return 0; diff --git a/drivers/staging/comedi/drivers/pcl816.c b/drivers/staging/comedi/drivers/pcl816.c index 515ba74cc7fe..19465c1b53c3 100644 --- a/drivers/staging/comedi/drivers/pcl816.c +++ b/drivers/staging/comedi/drivers/pcl816.c @@ -43,38 +43,38 @@ Configuration Options: #define DEBUG(x) x -// boards constants -// IO space len +/* boards constants */ +/* IO space len */ #define PCLx1x_RANGE 16 -//#define outb(x,y) printk("OUTB(%x, 200+%d)\n", x,y-0x200); outb(x,y) +/* #define outb(x,y) printk("OUTB(%x, 200+%d)\n", x,y-0x200); outb(x,y) */ -// INTEL 8254 counters +/* INTEL 8254 counters */ #define PCL816_CTR0 4 #define PCL816_CTR1 5 #define PCL816_CTR2 6 -// R: counter read-back register W: counter control +/* R: counter read-back register W: counter control */ #define PCL816_CTRCTL 7 -// R: A/D high byte W: A/D range control +/* R: A/D high byte W: A/D range control */ #define PCL816_RANGE 9 -// W: clear INT request +/* W: clear INT request */ #define PCL816_CLRINT 10 -// R: next mux scan channel W: mux scan channel & range control pointer +/* R: next mux scan channel W: mux scan channel & range control pointer */ #define PCL816_MUX 11 -// R/W: operation control register +/* R/W: operation control register */ #define PCL816_CONTROL 12 -// R: return status byte W: set DMA/IRQ +/* R: return status byte W: set DMA/IRQ */ #define PCL816_STATUS 13 #define PCL816_STATUS_DRDY_MASK 0x80 -// R: low byte of A/D W: soft A/D trigger +/* R: low byte of A/D W: soft A/D trigger */ #define PCL816_AD_LO 8 -// R: high byte of A/D W: A/D range control +/* R: high byte of A/D W: A/D range control */ #define PCL816_AD_HI 9 -// type of interrupt handler +/* type of interrupt handler */ #define INT_TYPE_AI1_INT 1 #define INT_TYPE_AI1_DMA 2 #define INT_TYPE_AI3_INT 4 @@ -83,7 +83,7 @@ Configuration Options: #define INT_TYPE_AI1_DMA_RTC 9 #define INT_TYPE_AI3_DMA_RTC 10 -// RTC stuff... +/* RTC stuff... */ #define RTC_IRQ 8 #define RTC_IO_EXTENT 0x10 #endif @@ -103,35 +103,35 @@ static const struct comedi_lrange range_pcl816 = { 8, { }; struct pcl816_board { - const char *name; // board name - int n_ranges; // len of range list - int n_aichan; // num of A/D chans in diferencial mode - unsigned int ai_ns_min; // minimal alllowed delay between samples (in ns) - int n_aochan; // num of D/A chans - int n_dichan; // num of DI chans - int n_dochan; // num of DO chans - const struct comedi_lrange *ai_range_type; // default A/D rangelist - const struct comedi_lrange *ao_range_type; // dafault D/A rangelist - unsigned int io_range; // len of IO space - unsigned int IRQbits; // allowed interrupts - unsigned int DMAbits; // allowed DMA chans - int ai_maxdata; // maxdata for A/D - int ao_maxdata; // maxdata for D/A - int ai_chanlist; // allowed len of channel list A/D - int ao_chanlist; // allowed len of channel list D/A - int i8254_osc_base; // 1/frequency of on board oscilator in ns + const char *name; /* board name */ + int n_ranges; /* len of range list */ + int n_aichan; /* num of A/D chans in diferencial mode */ + unsigned int ai_ns_min; /* minimal alllowed delay between samples (in ns) */ + int n_aochan; /* num of D/A chans */ + int n_dichan; /* num of DI chans */ + int n_dochan; /* num of DO chans */ + const struct comedi_lrange *ai_range_type; /* default A/D rangelist */ + const struct comedi_lrange *ao_range_type; /* dafault D/A rangelist */ + unsigned int io_range; /* len of IO space */ + unsigned int IRQbits; /* allowed interrupts */ + unsigned int DMAbits; /* allowed DMA chans */ + int ai_maxdata; /* maxdata for A/D */ + int ao_maxdata; /* maxdata for D/A */ + int ai_chanlist; /* allowed len of channel list A/D */ + int ao_chanlist; /* allowed len of channel list D/A */ + int i8254_osc_base; /* 1/frequency of on board oscilator in ns */ }; static const struct pcl816_board boardtypes[] = { {"pcl816", 8, 16, 10000, 1, 16, 16, &range_pcl816, &range_pcl816, PCLx1x_RANGE, - 0x00fc, // IRQ mask - 0x0a, // DMA mask - 0xffff, // 16-bit card - 0xffff, // D/A maxdata + 0x00fc, /* IRQ mask */ + 0x0a, /* DMA mask */ + 0xffff, /* 16-bit card */ + 0xffff, /* D/A maxdata */ 1024, - 1, // ao chan list + 1, /* ao chan list */ 100}, {"pcl814b", 8, 16, 10000, 1, 16, 16, &range_pcl816, &range_pcl816, PCLx1x_RANGE, @@ -148,8 +148,8 @@ static const struct pcl816_board boardtypes[] = { #define devpriv ((struct pcl816_private *)dev->private) #define this_board ((const struct pcl816_board *)dev->board_ptr) -static int pcl816_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int pcl816_detach(struct comedi_device * dev); +static int pcl816_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int pcl816_detach(struct comedi_device *dev); #ifdef unused static int RTC_lock = 0; /* RTC lock */ @@ -157,55 +157,55 @@ static int RTC_timer_lock = 0; /* RTC int lock */ #endif static struct comedi_driver driver_pcl816 = { - driver_name:"pcl816", - module:THIS_MODULE, - attach:pcl816_attach, - detach:pcl816_detach, - board_name:&boardtypes[0].name, - num_names:n_boardtypes, - offset:sizeof(struct pcl816_board), + .driver_name = "pcl816", + .module = THIS_MODULE, + .attach = pcl816_attach, + .detach = pcl816_detach, + .board_name = &boardtypes[0].name, + .num_names = n_boardtypes, + .offset = sizeof(struct pcl816_board), }; COMEDI_INITCLEANUP(driver_pcl816); struct pcl816_private { - unsigned int dma; // used DMA, 0=don't use DMA - int dma_rtc; // 1=RTC used with DMA, 0=no RTC alloc + unsigned int dma; /* used DMA, 0=don't use DMA */ + int dma_rtc; /* 1=RTC used with DMA, 0=no RTC alloc */ #ifdef unused - unsigned long rtc_iobase; // RTC port region + unsigned long rtc_iobase; /* RTC port region */ unsigned int rtc_iosize; unsigned int rtc_irq; #endif - unsigned long dmabuf[2]; // pointers to begin of DMA buffers - unsigned int dmapages[2]; // len of DMA buffers in PAGE_SIZEs - unsigned int hwdmaptr[2]; // hardware address of DMA buffers - unsigned int hwdmasize[2]; // len of DMA buffers in Bytes - unsigned int dmasamplsize; // size in samples hwdmasize[0]/2 - unsigned int last_top_dma; // DMA pointer in last RTC int - int next_dma_buf; // which DMA buffer will be used next round - long dma_runs_to_end; // how many we must permorm DMA transfer to end of record - unsigned long last_dma_run; // how many bytes we must transfer on last DMA page + unsigned long dmabuf[2]; /* pointers to begin of DMA buffers */ + unsigned int dmapages[2]; /* len of DMA buffers in PAGE_SIZEs */ + unsigned int hwdmaptr[2]; /* hardware address of DMA buffers */ + unsigned int hwdmasize[2]; /* len of DMA buffers in Bytes */ + unsigned int dmasamplsize; /* size in samples hwdmasize[0]/2 */ + unsigned int last_top_dma; /* DMA pointer in last RTC int */ + int next_dma_buf; /* which DMA buffer will be used next round */ + long dma_runs_to_end; /* how many we must permorm DMA transfer to end of record */ + unsigned long last_dma_run; /* how many bytes we must transfer on last DMA page */ - unsigned int ai_scans; // len of scanlist - unsigned char ai_neverending; // if=1, then we do neverending record (you must use cancel()) - int irq_free; // 1=have allocated IRQ - int irq_blocked; // 1=IRQ now uses any subdev + unsigned int ai_scans; /* len of scanlist */ + unsigned char ai_neverending; /* if=1, then we do neverending record (you must use cancel()) */ + int irq_free; /* 1=have allocated IRQ */ + int irq_blocked; /* 1=IRQ now uses any subdev */ #ifdef unused - int rtc_irq_blocked; // 1=we now do AI with DMA&RTC + int rtc_irq_blocked; /* 1=we now do AI with DMA&RTC */ #endif - int irq_was_now_closed; // when IRQ finish, there's stored int816_mode for last interrupt - int int816_mode; // who now uses IRQ - 1=AI1 int, 2=AI1 dma, 3=AI3 int, 4AI3 dma - struct comedi_subdevice *last_int_sub; // ptr to subdevice which now finish - int ai_act_scan; // how many scans we finished - unsigned int ai_act_chanlist[16]; // MUX setting for actual AI operations - unsigned int ai_act_chanlist_len; // how long is actual MUX list - unsigned int ai_act_chanlist_pos; // actual position in MUX list - unsigned int ai_poll_ptr; // how many sampes transfer poll - struct comedi_subdevice *sub_ai; // ptr to AI subdevice + int irq_was_now_closed; /* when IRQ finish, there's stored int816_mode for last interrupt */ + int int816_mode; /* who now uses IRQ - 1=AI1 int, 2=AI1 dma, 3=AI3 int, 4AI3 dma */ + struct comedi_subdevice *last_int_sub; /* ptr to subdevice which now finish */ + int ai_act_scan; /* how many scans we finished */ + unsigned int ai_act_chanlist[16]; /* MUX setting for actual AI operations */ + unsigned int ai_act_chanlist_len; /* how long is actual MUX list */ + unsigned int ai_act_chanlist_pos; /* actual position in MUX list */ + unsigned int ai_poll_ptr; /* how many sampes transfer poll */ + struct comedi_subdevice *sub_ai; /* ptr to AI subdevice */ #ifdef unused - struct timer_list rtc_irq_timer; // timer for RTC sanity check - unsigned long rtc_freq; // RTC int freq + struct timer_list rtc_irq_timer; /* timer for RTC sanity check */ + unsigned long rtc_freq; /* RTC int freq */ #endif }; @@ -213,36 +213,36 @@ struct pcl816_private { /* ============================================================================== */ -static int check_and_setup_channel_list(struct comedi_device * dev, - struct comedi_subdevice * s, unsigned int *chanlist, int chanlen); -static int pcl816_ai_cancel(struct comedi_device * dev, struct comedi_subdevice * s); -static void start_pacer(struct comedi_device * dev, int mode, unsigned int divisor1, +static int check_and_setup_channel_list(struct comedi_device *dev, + struct comedi_subdevice *s, unsigned int *chanlist, int chanlen); +static int pcl816_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s); +static void start_pacer(struct comedi_device *dev, int mode, unsigned int divisor1, unsigned int divisor2); #ifdef unused static int set_rtc_irq_bit(unsigned char bit); #endif -static int pcl816_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd); -static int pcl816_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s); +static int pcl816_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd); +static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s); /* ============================================================================== ANALOG INPUT MODE0, 816 cards, slow version */ -static int pcl816_ai_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pcl816_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int n; int timeout; DPRINTK("mode 0 analog input\n"); - // software trigger, DMA and INT off + /* software trigger, DMA and INT off */ outb(0, dev->iobase + PCL816_CONTROL); - // clear INT (conversion end) flag + /* clear INT (conversion end) flag */ outb(0, dev->iobase + PCL816_CLRINT); - // Set the input channel + /* Set the input channel */ outb(CR_CHAN(insn->chanspec) & 0xf, dev->iobase + PCL816_MUX); outb(CR_RANGE(insn->chanspec), dev->iobase + PCL816_RANGE); /* select gain */ @@ -254,7 +254,7 @@ static int pcl816_ai_insn_read(struct comedi_device * dev, struct comedi_subdevi while (timeout--) { if (!(inb(dev->iobase + PCL816_STATUS) & PCL816_STATUS_DRDY_MASK)) { - // return read value + /* return read value */ data[n] = ((inb(dev->iobase + PCL816_AD_HI) << 8) | @@ -263,9 +263,9 @@ static int pcl816_ai_insn_read(struct comedi_device * dev, struct comedi_subdevi outb(0, dev->iobase + PCL816_CLRINT); /* clear INT (conversion end) flag */ break; } - comedi_udelay(1); + udelay(1); } - // Return timeout error + /* Return timeout error */ if (!timeout) { comedi_error(dev, "A/D insn timeout\n"); data[0] = 0; @@ -293,9 +293,9 @@ static irqreturn_t interrupt_pcl816_ai_mode13_int(int irq, void *d) if (!(inb(dev->iobase + PCL816_STATUS) & PCL816_STATUS_DRDY_MASK)) break; - comedi_udelay(1); + udelay(1); } - if (!timeout) { // timeout, bail error + if (!timeout) { /* timeout, bail error */ outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */ comedi_error(dev, "A/D mode1/3 IRQ without DRDY!"); pcl816_ai_cancel(dev, s); @@ -305,7 +305,7 @@ static irqreturn_t interrupt_pcl816_ai_mode13_int(int irq, void *d) } - // get the sample + /* get the sample */ low = inb(dev->iobase + PCL816_AD_LO); hi = inb(dev->iobase + PCL816_AD_HI); @@ -334,8 +334,8 @@ static irqreturn_t interrupt_pcl816_ai_mode13_int(int irq, void *d) ============================================================================== analog input dma mode 1 & 3, 816 cards */ -static void transfer_from_dma_buf(struct comedi_device * dev, struct comedi_subdevice * s, - short * ptr, unsigned int bufptr, unsigned int len) +static void transfer_from_dma_buf(struct comedi_device *dev, struct comedi_subdevice *s, + short *ptr, unsigned int bufptr, unsigned int len) { int i; @@ -352,7 +352,7 @@ static void transfer_from_dma_buf(struct comedi_device * dev, struct comedi_subd } if (!devpriv->ai_neverending) - if (devpriv->ai_act_scan >= devpriv->ai_scans) { // all data sampled + if (devpriv->ai_act_scan >= devpriv->ai_scans) { /* all data sampled */ pcl816_ai_cancel(dev, s); s->async->events |= COMEDI_CB_EOA; s->async->events |= COMEDI_CB_BLOCK; @@ -374,12 +374,12 @@ static irqreturn_t interrupt_pcl816_ai_mode13_dma(int irq, void *d) disable_dma(devpriv->dma); this_dma_buf = devpriv->next_dma_buf; - if ((devpriv->dma_runs_to_end > -1) || devpriv->ai_neverending) { // switch dma bufs + if ((devpriv->dma_runs_to_end > -1) || devpriv->ai_neverending) { /* switch dma bufs */ devpriv->next_dma_buf = 1 - devpriv->next_dma_buf; set_dma_mode(devpriv->dma, DMA_MODE_READ); dma_flags = claim_dma_lock(); -// clear_dma_ff (devpriv->dma); +/* clear_dma_ff (devpriv->dma); */ set_dma_addr(devpriv->dma, devpriv->hwdmaptr[devpriv->next_dma_buf]); if (devpriv->dma_runs_to_end) { @@ -409,7 +409,7 @@ static irqreturn_t interrupt_pcl816_ai_mode13_dma(int irq, void *d) ============================================================================== INT procedure */ -static irqreturn_t interrupt_pcl816(int irq, void *d PT_REGS_ARG) +static irqreturn_t interrupt_pcl816(int irq, void *d) { struct comedi_device *dev = d; DPRINTK(""); @@ -433,7 +433,7 @@ static irqreturn_t interrupt_pcl816(int irq, void *d PT_REGS_ARG) (!devpriv->int816_mode)) { if (devpriv->irq_was_now_closed) { devpriv->irq_was_now_closed = 0; - // comedi_error(dev,"last IRQ.."); + /* comedi_error(dev,"last IRQ.."); */ return IRQ_HANDLED; } comedi_error(dev, "bad IRQ!"); @@ -447,28 +447,28 @@ static irqreturn_t interrupt_pcl816(int irq, void *d PT_REGS_ARG) ============================================================================== COMMAND MODE */ -static void pcl816_cmdtest_out(int e, struct comedi_cmd * cmd) +static void pcl816_cmdtest_out(int e, struct comedi_cmd *cmd) { - rt_printk("pcl816 e=%d startsrc=%x scansrc=%x convsrc=%x\n", e, + printk("pcl816 e=%d startsrc=%x scansrc=%x convsrc=%x\n", e, cmd->start_src, cmd->scan_begin_src, cmd->convert_src); - rt_printk("pcl816 e=%d startarg=%d scanarg=%d convarg=%d\n", e, + printk("pcl816 e=%d startarg=%d scanarg=%d convarg=%d\n", e, cmd->start_arg, cmd->scan_begin_arg, cmd->convert_arg); - rt_printk("pcl816 e=%d stopsrc=%x scanend=%x\n", e, cmd->stop_src, + printk("pcl816 e=%d stopsrc=%x scanend=%x\n", e, cmd->stop_src, cmd->scan_end_src); - rt_printk("pcl816 e=%d stoparg=%d scanendarg=%d chanlistlen=%d\n", e, + printk("pcl816 e=%d stoparg=%d scanendarg=%d chanlistlen=%d\n", e, cmd->stop_arg, cmd->scan_end_arg, cmd->chanlist_len); } /* ============================================================================== */ -static int pcl816_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd) +static int pcl816_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd) { int err = 0; int tmp, divisor1, divisor2; - DEBUG(rt_printk("pcl816 pcl812_ai_cmdtest\n"); + DEBUG(printk("pcl816 pcl812_ai_cmdtest\n"); pcl816_cmdtest_out(-1, cmd);); /* step 1: make sure trigger sources are trivially valid */ @@ -482,7 +482,7 @@ static int pcl816_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) err++; - if (!cmd->convert_src & (TRIG_EXT | TRIG_TIMER)) + if (!(cmd->convert_src & (TRIG_EXT | TRIG_TIMER))) err++; tmp = cmd->scan_end_src; @@ -597,7 +597,7 @@ static int pcl816_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice return 0; } -static int pcl816_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s) +static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { unsigned int divisor1 = 0, divisor2 = 0, dma_flags, bytes, dmairq; struct comedi_cmd *cmd = &s->async->cmd; @@ -610,7 +610,7 @@ static int pcl816_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s return -EINVAL; if (cmd->scan_end_arg != cmd->chanlist_len) return -EINVAL; -// if(cmd->chanlist_len>MAX_CHANLIST_LEN) return -EINVAL; +/* if(cmd->chanlist_len>MAX_CHANLIST_LEN) return -EINVAL; */ if (devpriv->irq_blocked) return -EBUSY; @@ -621,7 +621,7 @@ static int pcl816_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s i8253_cascade_ns_to_timer(this_board->i8254_osc_base, &divisor1, &divisor2, &cmd->convert_arg, cmd->flags & TRIG_ROUND_MASK); - if (divisor1 == 1) { // PCL816 crash if any divisor is set to 1 + if (divisor1 == 1) { /* PCL816 crash if any divisor is set to 1 */ divisor1 = 2; divisor2 /= 2; } @@ -631,12 +631,12 @@ static int pcl816_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s } } - start_pacer(dev, -1, 0, 0); // stop pacer + start_pacer(dev, -1, 0, 0); /* stop pacer */ if (!check_and_setup_channel_list(dev, s, cmd->chanlist, cmd->chanlist_len)) return -EINVAL; - comedi_udelay(1); + udelay(1); devpriv->ai_act_scan = 0; s->async->cur_chan = 0; @@ -652,19 +652,19 @@ static int pcl816_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s devpriv->ai_neverending = 1; } - if ((cmd->flags & TRIG_WAKE_EOS)) { // don't we want wake up every scan? + if ((cmd->flags & TRIG_WAKE_EOS)) { /* don't we want wake up every scan? */ printk("pl816: You wankt WAKE_EOS but I dont want handle it"); - // devpriv->ai_eos=1; - //if (devpriv->ai_n_chan==1) - // devpriv->dma=0; // DMA is useless for this situation + /* devpriv->ai_eos=1; */ + /* if (devpriv->ai_n_chan==1) */ + /* devpriv->dma=0; // DMA is useless for this situation */ } if (devpriv->dma) { bytes = devpriv->hwdmasize[0]; if (!devpriv->ai_neverending) { - bytes = s->async->cmd.chanlist_len * s->async->cmd.chanlist_len * sizeof(short); // how many - devpriv->dma_runs_to_end = bytes / devpriv->hwdmasize[0]; // how many DMA pages we must fill - devpriv->last_dma_run = bytes % devpriv->hwdmasize[0]; //on last dma transfer must be moved + bytes = s->async->cmd.chanlist_len * s->async->cmd.chanlist_len * sizeof(short); /* how many */ + devpriv->dma_runs_to_end = bytes / devpriv->hwdmasize[0]; /* how many DMA pages we must fill */ + devpriv->last_dma_run = bytes % devpriv->hwdmasize[0]; /* on last dma transfer must be moved */ devpriv->dma_runs_to_end--; if (devpriv->dma_runs_to_end >= 0) bytes = devpriv->hwdmasize[0]; @@ -687,14 +687,14 @@ static int pcl816_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s switch (cmd->convert_src) { case TRIG_TIMER: devpriv->int816_mode = INT_TYPE_AI1_DMA; - outb(0x32, dev->iobase + PCL816_CONTROL); // Pacer+IRQ+DMA - outb(dmairq, dev->iobase + PCL816_STATUS); // write irq and DMA to card + outb(0x32, dev->iobase + PCL816_CONTROL); /* Pacer+IRQ+DMA */ + outb(dmairq, dev->iobase + PCL816_STATUS); /* write irq and DMA to card */ break; default: devpriv->int816_mode = INT_TYPE_AI3_DMA; - outb(0x34, dev->iobase + PCL816_CONTROL); // Ext trig+IRQ+DMA - outb(dmairq, dev->iobase + PCL816_STATUS); // write irq to card + outb(0x34, dev->iobase + PCL816_CONTROL); /* Ext trig+IRQ+DMA */ + outb(dmairq, dev->iobase + PCL816_STATUS); /* write irq to card */ break; } @@ -702,32 +702,32 @@ static int pcl816_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s return 0; } -static int pcl816_ai_poll(struct comedi_device * dev, struct comedi_subdevice * s) +static int pcl816_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s) { unsigned long flags; unsigned int top1, top2, i; if (!devpriv->dma) - return 0; // poll is valid only for DMA transfer + return 0; /* poll is valid only for DMA transfer */ - comedi_spin_lock_irqsave(&dev->spinlock, flags); + spin_lock_irqsave(&dev->spinlock, flags); for (i = 0; i < 20; i++) { - top1 = get_dma_residue(devpriv->dma); // where is now DMA + top1 = get_dma_residue(devpriv->dma); /* where is now DMA */ top2 = get_dma_residue(devpriv->dma); if (top1 == top2) break; } if (top1 != top2) { - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); return 0; } - top1 = devpriv->hwdmasize[0] - top1; // where is now DMA in buffer - top1 >>= 1; // sample position + top1 = devpriv->hwdmasize[0] - top1; /* where is now DMA in buffer */ + top1 >>= 1; /* sample position */ top2 = top1 - devpriv->ai_poll_ptr; - if (top2 < 1) { // no new samples - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + if (top2 < 1) { /* no new samples */ + spin_unlock_irqrestore(&dev->spinlock, flags); return 0; } @@ -735,8 +735,8 @@ static int pcl816_ai_poll(struct comedi_device * dev, struct comedi_subdevice * (short *) devpriv->dmabuf[devpriv->next_dma_buf], devpriv->ai_poll_ptr, top2); - devpriv->ai_poll_ptr = top1; // new buffer position - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + devpriv->ai_poll_ptr = top1; /* new buffer position */ + spin_unlock_irqrestore(&dev->spinlock, flags); return s->async->buf_write_count - s->async->buf_read_count; } @@ -745,16 +745,16 @@ static int pcl816_ai_poll(struct comedi_device * dev, struct comedi_subdevice * ============================================================================== cancel any mode 1-4 AI */ -static int pcl816_ai_cancel(struct comedi_device * dev, struct comedi_subdevice * s) +static int pcl816_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { -// DEBUG(rt_printk("pcl816_ai_cancel()\n");) +/* DEBUG(printk("pcl816_ai_cancel()\n");) */ if (devpriv->irq_blocked > 0) { switch (devpriv->int816_mode) { #ifdef unused case INT_TYPE_AI1_DMA_RTC: case INT_TYPE_AI3_DMA_RTC: - set_rtc_irq_bit(0); // stop RTC + set_rtc_irq_bit(0); /* stop RTC */ del_timer(&devpriv->rtc_irq_timer); #endif case INT_TYPE_AI1_DMA: @@ -763,7 +763,7 @@ static int pcl816_ai_cancel(struct comedi_device * dev, struct comedi_subdevice case INT_TYPE_AI1_INT: case INT_TYPE_AI3_INT: outb(inb(dev->iobase + PCL816_CONTROL) & 0x73, dev->iobase + PCL816_CONTROL); /* Stop A/D */ - comedi_udelay(1); + udelay(1); outb(0, dev->iobase + PCL816_CONTROL); /* Stop A/D */ outb(0xb0, dev->iobase + PCL816_CTRCTL); /* Stop pacer */ outb(0x70, dev->iobase + PCL816_CTRCTL); @@ -776,12 +776,12 @@ static int pcl816_ai_cancel(struct comedi_device * dev, struct comedi_subdevice devpriv->irq_was_now_closed = devpriv->int816_mode; devpriv->int816_mode = 0; devpriv->last_int_sub = s; -// s->busy = 0; +/* s->busy = 0; */ break; } } - DEBUG(rt_printk("comedi: pcl816_ai_cancel() successful\n"); + DEBUG(printk("comedi: pcl816_ai_cancel() successful\n"); ) return 0; } @@ -793,34 +793,34 @@ static int pcl816_ai_cancel(struct comedi_device * dev, struct comedi_subdevice static int pcl816_check(unsigned long iobase) { outb(0x00, iobase + PCL816_MUX); - comedi_udelay(1); + udelay(1); if (inb(iobase + PCL816_MUX) != 0x00) - return 1; //there isn't card + return 1; /* there isn't card */ outb(0x55, iobase + PCL816_MUX); - comedi_udelay(1); + udelay(1); if (inb(iobase + PCL816_MUX) != 0x55) - return 1; //there isn't card + return 1; /* there isn't card */ outb(0x00, iobase + PCL816_MUX); - comedi_udelay(1); + udelay(1); outb(0x18, iobase + PCL816_CONTROL); - comedi_udelay(1); + udelay(1); if (inb(iobase + PCL816_CONTROL) != 0x18) - return 1; //there isn't card - return 0; // ok, card exist + return 1; /* there isn't card */ + return 0; /* ok, card exist */ } /* ============================================================================== reset whole PCL-816 cards */ -static void pcl816_reset(struct comedi_device * dev) +static void pcl816_reset(struct comedi_device *dev) { -// outb (0, dev->iobase + PCL818_DA_LO); // DAC=0V -// outb (0, dev->iobase + PCL818_DA_HI); -// comedi_udelay (1); -// outb (0, dev->iobase + PCL818_DO_HI); // DO=$0000 -// outb (0, dev->iobase + PCL818_DO_LO); -// comedi_udelay (1); +/* outb (0, dev->iobase + PCL818_DA_LO); DAC=0V */ +/* outb (0, dev->iobase + PCL818_DA_HI); */ +/* udelay (1); */ +/* outb (0, dev->iobase + PCL818_DO_HI); DO=$0000 */ +/* outb (0, dev->iobase + PCL818_DO_LO); */ +/* udelay (1); */ outb(0, dev->iobase + PCL816_CONTROL); outb(0, dev->iobase + PCL816_MUX); outb(0, dev->iobase + PCL816_CLRINT); @@ -835,16 +835,16 @@ static void pcl816_reset(struct comedi_device * dev) Start/stop pacer onboard pacer */ static void -start_pacer(struct comedi_device * dev, int mode, unsigned int divisor1, +start_pacer(struct comedi_device *dev, int mode, unsigned int divisor1, unsigned int divisor2) { outb(0x32, dev->iobase + PCL816_CTRCTL); outb(0xff, dev->iobase + PCL816_CTR0); outb(0x00, dev->iobase + PCL816_CTR0); - comedi_udelay(1); - outb(0xb4, dev->iobase + PCL816_CTRCTL); // set counter 2 as mode 3 - outb(0x74, dev->iobase + PCL816_CTRCTL); // set counter 1 as mode 3 - comedi_udelay(1); + udelay(1); + outb(0xb4, dev->iobase + PCL816_CTRCTL); /* set counter 2 as mode 3 */ + outb(0x74, dev->iobase + PCL816_CTRCTL); /* set counter 1 as mode 3 */ + udelay(1); if (mode == 1) { DPRINTK("mode %d, divisor1 %d, divisor2 %d\n", mode, divisor1, @@ -856,7 +856,7 @@ start_pacer(struct comedi_device * dev, int mode, unsigned int divisor1, } /* clear pending interrupts (just in case) */ -// outb(0, dev->iobase + PCL816_CLRINT); +/* outb(0, dev->iobase + PCL816_CLRINT); */ } /* @@ -865,49 +865,49 @@ start_pacer(struct comedi_device * dev, int mode, unsigned int divisor1, If it's ok, then program scan/gain logic */ static int -check_and_setup_channel_list(struct comedi_device * dev, struct comedi_subdevice * s, +check_and_setup_channel_list(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int *chanlist, int chanlen) { unsigned int chansegment[16]; unsigned int i, nowmustbechan, seglen, segpos; - // correct channel and range number check itself comedi/range.c + /* correct channel and range number check itself comedi/range.c */ if (chanlen < 1) { comedi_error(dev, "range/channel list is empty!"); return 0; } if (chanlen > 1) { - chansegment[0] = chanlist[0]; // first channel is everytime ok + chansegment[0] = chanlist[0]; /* first channel is everytime ok */ for (i = 1, seglen = 1; i < chanlen; i++, seglen++) { - // build part of chanlist - DEBUG(rt_printk("%d. %d %d\n", i, CR_CHAN(chanlist[i]), + /* build part of chanlist */ + DEBUG(printk("%d. %d %d\n", i, CR_CHAN(chanlist[i]), CR_RANGE(chanlist[i])); ) if (chanlist[0] == chanlist[i]) - break; // we detect loop, this must by finish + break; /* we detect loop, this must by finish */ nowmustbechan = (CR_CHAN(chansegment[i - 1]) + 1) % chanlen; if (nowmustbechan != CR_CHAN(chanlist[i])) { - // channel list isn't continous :-( - rt_printk + /* channel list isn't continous :-( */ + printk ("comedi%d: pcl816: channel list must be continous! chanlist[%i]=%d but must be %d or %d!\n", dev->minor, i, CR_CHAN(chanlist[i]), nowmustbechan, CR_CHAN(chanlist[0])); return 0; } - chansegment[i] = chanlist[i]; // well, this is next correct channel in list + chansegment[i] = chanlist[i]; /* well, this is next correct channel in list */ } - for (i = 0, segpos = 0; i < chanlen; i++) { // check whole chanlist - DEBUG(rt_printk("%d %d=%d %d\n", + for (i = 0, segpos = 0; i < chanlen; i++) { /* check whole chanlist */ + DEBUG(printk("%d %d=%d %d\n", CR_CHAN(chansegment[i % seglen]), CR_RANGE(chansegment[i % seglen]), CR_CHAN(chanlist[i]), CR_RANGE(chanlist[i])); ) if (chanlist[i] != chansegment[i % seglen]) { - rt_printk + printk ("comedi%d: pcl816: bad channel or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n", dev->minor, i, CR_CHAN(chansegment[i]), CR_RANGE(chansegment[i]), @@ -915,7 +915,7 @@ check_and_setup_channel_list(struct comedi_device * dev, struct comedi_subdevice CR_CHAN(chanlist[i % seglen]), CR_RANGE(chanlist[i % seglen]), CR_AREF(chansegment[i % seglen])); - return 0; // chan/gain list is strange + return 0; /* chan/gain list is strange */ } } } else { @@ -925,17 +925,17 @@ check_and_setup_channel_list(struct comedi_device * dev, struct comedi_subdevice devpriv->ai_act_chanlist_len = seglen; devpriv->ai_act_chanlist_pos = 0; - for (i = 0; i < seglen; i++) { // store range list to card + for (i = 0; i < seglen; i++) { /* store range list to card */ devpriv->ai_act_chanlist[i] = CR_CHAN(chanlist[i]); outb(CR_CHAN(chanlist[0]) & 0xf, dev->iobase + PCL816_MUX); outb(CR_RANGE(chanlist[0]), dev->iobase + PCL816_RANGE); /* select gain */ } - comedi_udelay(1); + udelay(1); outb(devpriv->ai_act_chanlist[0] | (devpriv->ai_act_chanlist[seglen - 1] << 4), dev->iobase + PCL816_MUX); /* select channel interval to scan */ - return 1; // we can serve this with MUX logic + return 1; /* we can serve this with MUX logic */ } #ifdef unused @@ -979,9 +979,9 @@ static int set_rtc_irq_bit(unsigned char bit) ============================================================================== Free any resources that we have claimed */ -static void free_resources(struct comedi_device * dev) +static void free_resources(struct comedi_device *dev) { - //rt_printk("free_resource()\n"); + /* printk("free_resource()\n"); */ if (dev->private) { pcl816_ai_cancel(dev, devpriv->sub_ai); pcl816_reset(dev); @@ -993,7 +993,7 @@ static void free_resources(struct comedi_device * dev) free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]); #ifdef unused if (devpriv->rtc_irq) - comedi_free_irq(devpriv->rtc_irq, dev); + free_irq(devpriv->rtc_irq, dev); if ((devpriv->dma_rtc) && (RTC_lock == 1)) { if (devpriv->rtc_iobase) release_region(devpriv->rtc_iobase, @@ -1006,7 +1006,7 @@ static void free_resources(struct comedi_device * dev) free_irq(dev->irq, dev); if (dev->iobase) release_region(dev->iobase, this_board->io_range); - //rt_printk("free_resource() end\n"); + /* printk("free_resource() end\n"); */ } /* @@ -1015,13 +1015,13 @@ static void free_resources(struct comedi_device * dev) Initialization */ -static int pcl816_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int pcl816_attach(struct comedi_device *dev, struct comedi_devconfig *it) { int ret; unsigned long iobase; unsigned int irq, dma; unsigned long pages; - //int i; + /* int i; */ struct comedi_subdevice *s; /* claim our I/O space */ @@ -1030,18 +1030,19 @@ static int pcl816_attach(struct comedi_device * dev, struct comedi_devconfig * i this_board->name, iobase); if (!request_region(iobase, this_board->io_range, "pcl816")) { - rt_printk("I/O port conflict\n"); + printk("I/O port conflict\n"); return -EIO; } dev->iobase = iobase; if (pcl816_check(iobase)) { - rt_printk(", I cann't detect board. FAIL!\n"); + printk(", I cann't detect board. FAIL!\n"); return -EIO; } - if ((ret = alloc_private(dev, sizeof(struct pcl816_private))) < 0) + ret = alloc_private(dev, sizeof(struct pcl816_private)); + if (ret < 0) return ret; /* Can't alloc mem */ /* set up some name stuff */ @@ -1053,19 +1054,18 @@ static int pcl816_attach(struct comedi_device * dev, struct comedi_devconfig * i irq = it->options[1]; if (irq) { /* we want to use IRQ */ if (((1 << irq) & this_board->IRQbits) == 0) { - rt_printk + printk (", IRQ %u is out of allowed range, DISABLING IT", irq); irq = 0; /* Bad IRQ */ } else { - if (comedi_request_irq(irq, interrupt_pcl816, 0, - "pcl816", dev)) { - rt_printk + if (request_irq(irq, interrupt_pcl816, 0, "pcl816", dev)) { + printk (", unable to allocate IRQ %u, DISABLING IT", irq); irq = 0; /* Can't use IRQ */ } else { - rt_printk(", irq=%u", irq); + printk(", irq=%u", irq); } } } @@ -1084,7 +1084,7 @@ static int pcl816_attach(struct comedi_device * dev, struct comedi_devconfig * i #ifdef unused /* grab RTC for DMA operations */ devpriv->dma_rtc = 0; - if (it->options[2] > 0) { // we want to use DMA + if (it->options[2] > 0) { /* we want to use DMA */ if (RTC_lock == 0) { if (!request_region(RTC_PORT(0), RTC_IO_EXTENT, "pcl816 (RTC)")) @@ -1094,12 +1094,11 @@ static int pcl816_attach(struct comedi_device * dev, struct comedi_devconfig * i devpriv->rtc_iosize = RTC_IO_EXTENT; RTC_lock++; #ifdef UNTESTED_CODE - if (!comedi_request_irq(RTC_IRQ, - interrupt_pcl816_ai_mode13_dma_rtc, 0, + if (!request_irq(RTC_IRQ, interrupt_pcl816_ai_mode13_dma_rtc, 0, "pcl816 DMA (RTC)", dev)) { devpriv->dma_rtc = 1; devpriv->rtc_irq = RTC_IRQ; - rt_printk(", dma_irq=%u", devpriv->rtc_irq); + printk(", dma_irq=%u", devpriv->rtc_irq); } else { RTC_lock--; if (RTC_lock == 0) { @@ -1130,34 +1129,34 @@ static int pcl816_attach(struct comedi_device * dev, struct comedi_devconfig * i goto no_dma; /* DMA disabled */ if (((1 << dma) & this_board->DMAbits) == 0) { - rt_printk(", DMA is out of allowed range, FAIL!\n"); + printk(", DMA is out of allowed range, FAIL!\n"); return -EINVAL; /* Bad DMA */ } ret = request_dma(dma, "pcl816"); if (ret) { - rt_printk(", unable to allocate DMA %u, FAIL!\n", dma); + printk(", unable to allocate DMA %u, FAIL!\n", dma); return -EBUSY; /* DMA isn't free */ } devpriv->dma = dma; - rt_printk(", dma=%u", dma); + printk(", dma=%u", dma); pages = 2; /* we need 16KB */ devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages); if (!devpriv->dmabuf[0]) { - rt_printk(", unable to allocate DMA buffer, FAIL!\n"); + printk(", unable to allocate DMA buffer, FAIL!\n"); /* maybe experiment with try_to_free_pages() will help .... */ return -EBUSY; /* no buffer :-( */ } devpriv->dmapages[0] = pages; devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]); devpriv->hwdmasize[0] = (1 << pages) * PAGE_SIZE; - //rt_printk("%d %d %ld, ",devpriv->dmapages[0],devpriv->hwdmasize[0],PAGE_SIZE); + /* printk("%d %d %ld, ",devpriv->dmapages[0],devpriv->hwdmasize[0],PAGE_SIZE); */ - if (devpriv->dma_rtc == 0) { // we must do duble buff :-( + if (devpriv->dma_rtc == 0) { /* we must do duble buff :-( */ devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages); if (!devpriv->dmabuf[1]) { - rt_printk + printk (", unable to allocate DMA buffer, FAIL!\n"); return -EBUSY; } @@ -1177,7 +1176,9 @@ static int pcl816_attach(struct comedi_device * dev, struct comedi_devconfig * i if (this_board->n_dochan > 0) subdevs[3] = COMEDI_SUBD_DO; */ - if ((ret = alloc_subdevices(dev, 1)) < 0) + + ret = alloc_subdevices(dev, 1); + if (ret < 0) return ret; s = dev->subdevices + 0; @@ -1188,7 +1189,7 @@ static int pcl816_attach(struct comedi_device * dev, struct comedi_devconfig * i s->subdev_flags = SDF_READABLE | SDF_CMD_READ; s->n_chan = this_board->n_aichan; s->subdev_flags |= SDF_DIFF; - //printk (", %dchans DIFF DAC - %d", s->n_chan, i); + /* printk (", %dchans DIFF DAC - %d", s->n_chan, i); */ s->maxdata = this_board->ai_maxdata; s->len_chanlist = this_board->ai_chanlist; s->range_table = this_board->ai_range_type; @@ -1229,7 +1230,7 @@ case COMEDI_SUBD_DO: pcl816_reset(dev); - rt_printk("\n"); + printk("\n"); return 0; } @@ -1238,9 +1239,9 @@ case COMEDI_SUBD_DO: ============================================================================== Removes device */ -static int pcl816_detach(struct comedi_device * dev) +static int pcl816_detach(struct comedi_device *dev) { - DEBUG(rt_printk("comedi%d: pcl816: remove\n", dev->minor); + DEBUG(printk("comedi%d: pcl816: remove\n", dev->minor); ) free_resources(dev); #ifdef unused diff --git a/drivers/staging/comedi/drivers/pcl818.c b/drivers/staging/comedi/drivers/pcl818.c index 43a9d56c6a43..039a77a66451 100644 --- a/drivers/staging/comedi/drivers/pcl818.c +++ b/drivers/staging/comedi/drivers/pcl818.c @@ -107,9 +107,9 @@ A word or two about DMA. Driver support DMA operations at two ways: #include "8253.h" -// #define PCL818_MODE13_AO 1 +/* #define PCL818_MODE13_AO 1 */ -// boards constants +/* boards constants */ #define boardPCL818L 0 #define boardPCL818H 1 @@ -118,60 +118,60 @@ A word or two about DMA. Driver support DMA operations at two ways: #define boardPCL818 4 #define boardPCL718 5 -// IO space len +/* IO space len */ #define PCLx1x_RANGE 16 -// IO space len if we use FIFO +/* IO space len if we use FIFO */ #define PCLx1xFIFO_RANGE 32 -// W: clear INT request +/* W: clear INT request */ #define PCL818_CLRINT 8 -// R: return status byte +/* R: return status byte */ #define PCL818_STATUS 8 -// R: A/D high byte W: A/D range control +/* R: A/D high byte W: A/D range control */ #define PCL818_RANGE 1 -// R: next mux scan channel W: mux scan channel & range control pointer +/* R: next mux scan channel W: mux scan channel & range control pointer */ #define PCL818_MUX 2 -// R/W: operation control register +/* R/W: operation control register */ #define PCL818_CONTROL 9 -// W: counter enable +/* W: counter enable */ #define PCL818_CNTENABLE 10 -// R: low byte of A/D W: soft A/D trigger +/* R: low byte of A/D W: soft A/D trigger */ #define PCL818_AD_LO 0 -// R: high byte of A/D W: A/D range control +/* R: high byte of A/D W: A/D range control */ #define PCL818_AD_HI 1 -// W: D/A low&high byte +/* W: D/A low&high byte */ #define PCL818_DA_LO 4 #define PCL818_DA_HI 5 -// R: low&high byte of DI +/* R: low&high byte of DI */ #define PCL818_DI_LO 3 #define PCL818_DI_HI 11 -// W: low&high byte of DO +/* W: low&high byte of DO */ #define PCL818_DO_LO 3 #define PCL818_DO_HI 11 -// W: PCL718 second D/A +/* W: PCL718 second D/A */ #define PCL718_DA2_LO 6 #define PCL718_DA2_HI 7 -// counters +/* counters */ #define PCL818_CTR0 12 #define PCL818_CTR1 13 #define PCL818_CTR2 14 -// W: counter control +/* W: counter control */ #define PCL818_CTRCTL 15 -// W: fifo enable/disable +/* W: fifo enable/disable */ #define PCL818_FI_ENABLE 6 -// W: fifo interrupt clear +/* W: fifo interrupt clear */ #define PCL818_FI_INTCLR 20 -// W: fifo interrupt clear +/* W: fifo interrupt clear */ #define PCL818_FI_FLUSH 25 -// R: fifo status +/* R: fifo status */ #define PCL818_FI_STATUS 25 -// R: one record from FIFO +/* R: one record from FIFO */ #define PCL818_FI_DATALO 23 #define PCL818_FI_DATAHI 23 -// type of interrupt handler +/* type of interrupt handler */ #define INT_TYPE_AI1_INT 1 #define INT_TYPE_AI1_DMA 2 #define INT_TYPE_AI1_FIFO 3 @@ -184,7 +184,7 @@ A word or two about DMA. Driver support DMA operations at two ways: #endif #ifdef unused -// RTC stuff... +/* RTC stuff... */ #define INT_TYPE_AI1_DMA_RTC 9 #define INT_TYPE_AI3_DMA_RTC 10 @@ -244,8 +244,8 @@ static const struct comedi_lrange range718_bipolar0_5 = { 1, {BIP_RANGE(0.5),} } static const struct comedi_lrange range718_unipolar2 = { 1, {UNI_RANGE(2),} }; static const struct comedi_lrange range718_unipolar1 = { 1, {BIP_RANGE(1),} }; -static int pcl818_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int pcl818_detach(struct comedi_device * dev); +static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int pcl818_detach(struct comedi_device *dev); #ifdef unused static int RTC_lock = 0; /* RTC lock */ @@ -254,22 +254,22 @@ static int RTC_timer_lock = 0; /* RTC int lock */ struct pcl818_board { - const char *name; // driver name - int n_ranges; // len of range list - int n_aichan_se; // num of A/D chans in single ended mode - int n_aichan_diff; // num of A/D chans in diferencial mode - unsigned int ns_min; // minimal alllowed delay between samples (in ns) - int n_aochan; // num of D/A chans - int n_dichan; // num of DI chans - int n_dochan; // num of DO chans - const struct comedi_lrange *ai_range_type; // default A/D rangelist - const struct comedi_lrange *ao_range_type; // default D/A rangelist - unsigned int io_range; // len of IO space - unsigned int IRQbits; // allowed interrupts - unsigned int DMAbits; // allowed DMA chans - int ai_maxdata; // maxdata for A/D - int ao_maxdata; // maxdata for D/A - unsigned char fifo; // 1=board has FIFO + const char *name; /* driver name */ + int n_ranges; /* len of range list */ + int n_aichan_se; /* num of A/D chans in single ended mode */ + int n_aichan_diff; /* num of A/D chans in diferencial mode */ + unsigned int ns_min; /* minimal alllowed delay between samples (in ns) */ + int n_aochan; /* num of D/A chans */ + int n_dichan; /* num of DI chans */ + int n_dochan; /* num of DO chans */ + const struct comedi_lrange *ai_range_type; /* default A/D rangelist */ + const struct comedi_lrange *ao_range_type; /* default D/A rangelist */ + unsigned int io_range; /* len of IO space */ + unsigned int IRQbits; /* allowed interrupts */ + unsigned int DMAbits; /* allowed DMA chans */ + int ai_maxdata; /* maxdata for A/D */ + int ao_maxdata; /* maxdata for D/A */ + unsigned char fifo; /* 1=board has FIFO */ int is_818; }; @@ -302,67 +302,67 @@ static const struct pcl818_board boardtypes[] = { #define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl818_board)) static struct comedi_driver driver_pcl818 = { - driver_name:"pcl818", - module:THIS_MODULE, - attach:pcl818_attach, - detach:pcl818_detach, - board_name:&boardtypes[0].name, - num_names:n_boardtypes, - offset:sizeof(struct pcl818_board), + .driver_name = "pcl818", + .module = THIS_MODULE, + .attach = pcl818_attach, + .detach = pcl818_detach, + .board_name = &boardtypes[0].name, + .num_names = n_boardtypes, + .offset = sizeof(struct pcl818_board), }; COMEDI_INITCLEANUP(driver_pcl818); struct pcl818_private { - unsigned int dma; // used DMA, 0=don't use DMA - int dma_rtc; // 1=RTC used with DMA, 0=no RTC alloc + unsigned int dma; /* used DMA, 0=don't use DMA */ + int dma_rtc; /* 1=RTC used with DMA, 0=no RTC alloc */ unsigned int io_range; #ifdef unused - unsigned long rtc_iobase; // RTC port region + unsigned long rtc_iobase; /* RTC port region */ unsigned int rtc_iosize; unsigned int rtc_irq; - struct timer_list rtc_irq_timer; // timer for RTC sanity check - unsigned long rtc_freq; // RTC int freq - int rtc_irq_blocked; // 1=we now do AI with DMA&RTC + struct timer_list rtc_irq_timer; /* timer for RTC sanity check */ + unsigned long rtc_freq; /* RTC int freq */ + int rtc_irq_blocked; /* 1=we now do AI with DMA&RTC */ #endif - unsigned long dmabuf[2]; // pointers to begin of DMA buffers - unsigned int dmapages[2]; // len of DMA buffers in PAGE_SIZEs - unsigned int hwdmaptr[2]; // hardware address of DMA buffers - unsigned int hwdmasize[2]; // len of DMA buffers in Bytes - unsigned int dmasamplsize; // size in samples hwdmasize[0]/2 - unsigned int last_top_dma; // DMA pointer in last RTC int - int next_dma_buf; // which DMA buffer will be used next round - long dma_runs_to_end; // how many we must permorm DMA transfer to end of record - unsigned long last_dma_run; // how many bytes we must transfer on last DMA page - unsigned char neverending_ai; // if=1, then we do neverending record (you must use cancel()) - unsigned int ns_min; // manimal alllowed delay between samples (in us) for actual card - int i8253_osc_base; // 1/frequency of on board oscilator in ns - int irq_free; // 1=have allocated IRQ - int irq_blocked; // 1=IRQ now uses any subdev - int irq_was_now_closed; // when IRQ finish, there's stored int818_mode for last interrupt - int ai_mode; // who now uses IRQ - 1=AI1 int, 2=AI1 dma, 3=AI3 int, 4AI3 dma - struct comedi_subdevice *last_int_sub; // ptr to subdevice which now finish - int ai_act_scan; // how many scans we finished - int ai_act_chan; // actual position in actual scan - unsigned int act_chanlist[16]; // MUX setting for actual AI operations - unsigned int act_chanlist_len; // how long is actual MUX list - unsigned int act_chanlist_pos; // actual position in MUX list - unsigned int ai_scans; // len of scanlist - unsigned int ai_n_chan; // how many channels is measured - unsigned int *ai_chanlist; // actaul chanlist - unsigned int ai_flags; // flaglist - unsigned int ai_data_len; // len of data buffer - short *ai_data; // data buffer - unsigned int ai_timer1; // timers + unsigned long dmabuf[2]; /* pointers to begin of DMA buffers */ + unsigned int dmapages[2]; /* len of DMA buffers in PAGE_SIZEs */ + unsigned int hwdmaptr[2]; /* hardware address of DMA buffers */ + unsigned int hwdmasize[2]; /* len of DMA buffers in Bytes */ + unsigned int dmasamplsize; /* size in samples hwdmasize[0]/2 */ + unsigned int last_top_dma; /* DMA pointer in last RTC int */ + int next_dma_buf; /* which DMA buffer will be used next round */ + long dma_runs_to_end; /* how many we must permorm DMA transfer to end of record */ + unsigned long last_dma_run; /* how many bytes we must transfer on last DMA page */ + unsigned char neverending_ai; /* if=1, then we do neverending record (you must use cancel()) */ + unsigned int ns_min; /* manimal alllowed delay between samples (in us) for actual card */ + int i8253_osc_base; /* 1/frequency of on board oscilator in ns */ + int irq_free; /* 1=have allocated IRQ */ + int irq_blocked; /* 1=IRQ now uses any subdev */ + int irq_was_now_closed; /* when IRQ finish, there's stored int818_mode for last interrupt */ + int ai_mode; /* who now uses IRQ - 1=AI1 int, 2=AI1 dma, 3=AI3 int, 4AI3 dma */ + struct comedi_subdevice *last_int_sub; /* ptr to subdevice which now finish */ + int ai_act_scan; /* how many scans we finished */ + int ai_act_chan; /* actual position in actual scan */ + unsigned int act_chanlist[16]; /* MUX setting for actual AI operations */ + unsigned int act_chanlist_len; /* how long is actual MUX list */ + unsigned int act_chanlist_pos; /* actual position in MUX list */ + unsigned int ai_scans; /* len of scanlist */ + unsigned int ai_n_chan; /* how many channels is measured */ + unsigned int *ai_chanlist; /* actaul chanlist */ + unsigned int ai_flags; /* flaglist */ + unsigned int ai_data_len; /* len of data buffer */ + short *ai_data; /* data buffer */ + unsigned int ai_timer1; /* timers */ unsigned int ai_timer2; - struct comedi_subdevice *sub_ai; // ptr to AI subdevice - unsigned char usefifo; // 1=use fifo + struct comedi_subdevice *sub_ai; /* ptr to AI subdevice */ + unsigned char usefifo; /* 1=use fifo */ unsigned int ao_readback[2]; }; -static const unsigned int muxonechan[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, // used for gain list programming +static const unsigned int muxonechan[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, /* used for gain list programming */ 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }; @@ -372,13 +372,13 @@ static const unsigned int muxonechan[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0 /* ============================================================================== */ -static void setup_channel_list(struct comedi_device * dev, struct comedi_subdevice * s, +static void setup_channel_list(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int *chanlist, unsigned int n_chan, unsigned int seglen); -static int check_channel_list(struct comedi_device * dev, struct comedi_subdevice * s, +static int check_channel_list(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int *chanlist, unsigned int n_chan); -static int pcl818_ai_cancel(struct comedi_device * dev, struct comedi_subdevice * s); -static void start_pacer(struct comedi_device * dev, int mode, unsigned int divisor1, +static int pcl818_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s); +static void start_pacer(struct comedi_device *dev, int mode, unsigned int divisor1, unsigned int divisor2); #ifdef unused @@ -391,8 +391,8 @@ static int rtc_setfreq_irq(int freq); ============================================================================== ANALOG INPUT MODE0, 818 cards, slow version */ -static int pcl818_ai_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pcl818_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int n; int timeout; @@ -418,7 +418,7 @@ static int pcl818_ai_insn_read(struct comedi_device * dev, struct comedi_subdevi while (timeout--) { if (inb(dev->iobase + PCL818_STATUS) & 0x10) goto conv_finish; - comedi_udelay(1); + udelay(1); } comedi_error(dev, "A/D insn timeout"); /* clear INT (conversion end) flag */ @@ -438,8 +438,8 @@ static int pcl818_ai_insn_read(struct comedi_device * dev, struct comedi_subdevi ANALOG OUTPUT MODE0, 818 cards only one sample per call is supported */ -static int pcl818_ao_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pcl818_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int n; int chan = CR_CHAN(insn->chanspec); @@ -451,8 +451,8 @@ static int pcl818_ao_insn_read(struct comedi_device * dev, struct comedi_subdevi return n; } -static int pcl818_ao_insn_write(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pcl818_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int n; int chan = CR_CHAN(insn->chanspec); @@ -460,9 +460,9 @@ static int pcl818_ao_insn_write(struct comedi_device * dev, struct comedi_subdev for (n = 0; n < insn->n; n++) { devpriv->ao_readback[chan] = data[n]; outb((data[n] & 0x000f) << 4, dev->iobase + - (chan) ? PCL718_DA2_LO : PCL818_DA_LO); + (chan ? PCL718_DA2_LO : PCL818_DA_LO)); outb((data[n] & 0x0ff0) >> 4, dev->iobase + - (chan) ? PCL718_DA2_HI : PCL818_DA_HI); + (chan ? PCL718_DA2_HI : PCL818_DA_HI)); } return n; @@ -474,8 +474,8 @@ static int pcl818_ao_insn_write(struct comedi_device * dev, struct comedi_subdev only one sample per call is supported */ -static int pcl818_di_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pcl818_di_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if (insn->n != 2) return -EINVAL; @@ -492,8 +492,8 @@ static int pcl818_di_insn_bits(struct comedi_device * dev, struct comedi_subdevi only one sample per call is supported */ -static int pcl818_do_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pcl818_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if (insn->n != 2) return -EINVAL; @@ -524,7 +524,7 @@ static irqreturn_t interrupt_pcl818_ai_mode13_int(int irq, void *d) while (timeout--) { if (inb(dev->iobase + PCL818_STATUS) & 0x10) goto conv_finish; - comedi_udelay(1); + udelay(1); } outb(0, dev->iobase + PCL818_STATUS); /* clear INT request */ comedi_error(dev, "A/D mode1/3 IRQ without DRDY!"); @@ -535,11 +535,11 @@ static irqreturn_t interrupt_pcl818_ai_mode13_int(int irq, void *d) conv_finish: low = inb(dev->iobase + PCL818_AD_LO); - comedi_buf_put(s->async, ((inb(dev->iobase + PCL818_AD_HI) << 4) | (low >> 4))); // get one sample + comedi_buf_put(s->async, ((inb(dev->iobase + PCL818_AD_HI) << 4) | (low >> 4))); /* get one sample */ outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */ - if ((low & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { // dropout! - rt_printk + if ((low & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */ + printk ("comedi: A/D mode1/3 IRQ - channel dropout %x!=%x !\n", (low & 0xf), devpriv->act_chanlist[devpriv->act_chanlist_pos]); @@ -549,7 +549,7 @@ static irqreturn_t interrupt_pcl818_ai_mode13_int(int irq, void *d) return IRQ_HANDLED; } if (s->async->cur_chan == 0) { - // rt_printk("E"); + /* printk("E"); */ devpriv->ai_act_scan--; } @@ -577,7 +577,7 @@ static irqreturn_t interrupt_pcl818_ai_mode13_dma(int irq, void *d) disable_dma(devpriv->dma); devpriv->next_dma_buf = 1 - devpriv->next_dma_buf; - if ((devpriv->dma_runs_to_end) > -1 || devpriv->neverending_ai) { // switch dma bufs + if ((devpriv->dma_runs_to_end) > -1 || devpriv->neverending_ai) { /* switch dma bufs */ set_dma_mode(devpriv->dma, DMA_MODE_READ); flags = claim_dma_lock(); set_dma_addr(devpriv->dma, @@ -591,7 +591,7 @@ static irqreturn_t interrupt_pcl818_ai_mode13_dma(int irq, void *d) release_dma_lock(flags); enable_dma(devpriv->dma); } - rt_printk("comedi: A/D mode1/3 IRQ \n"); + printk("comedi: A/D mode1/3 IRQ \n"); devpriv->dma_runs_to_end--; outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */ @@ -601,8 +601,8 @@ static irqreturn_t interrupt_pcl818_ai_mode13_dma(int irq, void *d) bufptr = 0; for (i = 0; i < len; i++) { - if ((ptr[bufptr] & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { // dropout! - rt_printk + if ((ptr[bufptr] & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */ + printk ("comedi: A/D mode1/3 DMA - channel dropout %d(card)!=%d(chanlist) at %d !\n", (ptr[bufptr] & 0xf), devpriv->act_chanlist[devpriv-> @@ -614,7 +614,7 @@ static irqreturn_t interrupt_pcl818_ai_mode13_dma(int irq, void *d) return IRQ_HANDLED; } - comedi_buf_put(s->async, ptr[bufptr++] >> 4); // get one sample + comedi_buf_put(s->async, ptr[bufptr++] >> 4); /* get one sample */ devpriv->act_chanlist_pos++; if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len) { @@ -627,7 +627,7 @@ static irqreturn_t interrupt_pcl818_ai_mode13_dma(int irq, void *d) pcl818_ai_cancel(dev, s); s->async->events |= COMEDI_CB_EOA; comedi_event(dev, s); - // printk("done int ai13 dma\n"); + /* printk("done int ai13 dma\n"); */ return IRQ_HANDLED; } } @@ -651,7 +651,7 @@ static irqreturn_t interrupt_pcl818_ai_mode13_dma_rtc(int irq, void *d) long ofs_dats; short *dmabuf = (short *) devpriv->dmabuf[0]; - //outb(2,0x378); + /* outb(2,0x378); */ switch (devpriv->ai_mode) { case INT_TYPE_AI1_DMA_RTC: case INT_TYPE_AI3_DMA_RTC: @@ -668,32 +668,32 @@ static irqreturn_t interrupt_pcl818_ai_mode13_dma_rtc(int irq, void *d) if (top1 != top2) return IRQ_HANDLED; - top1 = devpriv->hwdmasize[0] - top1; // where is now DMA in buffer + top1 = devpriv->hwdmasize[0] - top1; /* where is now DMA in buffer */ top1 >>= 1; - ofs_dats = top1 - devpriv->last_top_dma; // new samples from last call + ofs_dats = top1 - devpriv->last_top_dma; /* new samples from last call */ if (ofs_dats < 0) ofs_dats = (devpriv->dmasamplsize) + ofs_dats; if (!ofs_dats) - return IRQ_HANDLED; // exit=no new samples from last call - // obsluz data + return IRQ_HANDLED; /* exit=no new samples from last call */ + /* obsluz data */ i = devpriv->last_top_dma - 1; i &= (devpriv->dmasamplsize - 1); - if (dmabuf[i] != MAGIC_DMA_WORD) { // DMA overflow! + if (dmabuf[i] != MAGIC_DMA_WORD) { /* DMA overflow! */ comedi_error(dev, "A/D mode1/3 DMA buffer overflow!"); - //rt_printk("I %d dmabuf[i] %d %d\n",i,dmabuf[i],devpriv->dmasamplsize); + /* printk("I %d dmabuf[i] %d %d\n",i,dmabuf[i],devpriv->dmasamplsize); */ pcl818_ai_cancel(dev, s); s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; comedi_event(dev, s); return IRQ_HANDLED; } - //rt_printk("r %ld ",ofs_dats); + /* printk("r %ld ",ofs_dats); */ bufptr = devpriv->last_top_dma; for (i = 0; i < ofs_dats; i++) { - if ((dmabuf[bufptr] & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { // dropout! - rt_printk + if ((dmabuf[bufptr] & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */ + printk ("comedi: A/D mode1/3 DMA - channel dropout %d!=%d !\n", (dmabuf[bufptr] & 0xf), devpriv->act_chanlist[devpriv-> @@ -705,7 +705,7 @@ static irqreturn_t interrupt_pcl818_ai_mode13_dma_rtc(int irq, void *d) return IRQ_HANDLED; } - comedi_buf_put(s->async, dmabuf[bufptr++] >> 4); // get one sample + comedi_buf_put(s->async, dmabuf[bufptr++] >> 4); /* get one sample */ bufptr &= (devpriv->dmasamplsize - 1); if (s->async->cur_chan == 0) { @@ -717,7 +717,7 @@ static irqreturn_t interrupt_pcl818_ai_mode13_dma_rtc(int irq, void *d) pcl818_ai_cancel(dev, s); s->async->events |= COMEDI_CB_EOA; comedi_event(dev, s); - //printk("done int ai13 dma\n"); + /* printk("done int ai13 dma\n"); */ return IRQ_HANDLED; } } @@ -727,11 +727,11 @@ static irqreturn_t interrupt_pcl818_ai_mode13_dma_rtc(int irq, void *d) bufptr &= (devpriv->dmasamplsize - 1); dmabuf[bufptr] = MAGIC_DMA_WORD; comedi_event(dev, s); - //outb(0,0x378); + /* outb(0,0x378); */ return IRQ_HANDLED; } - //outb(0,0x378); + /* outb(0,0x378); */ return IRQ_HANDLED; } #endif @@ -746,7 +746,7 @@ static irqreturn_t interrupt_pcl818_ai_mode13_fifo(int irq, void *d) struct comedi_subdevice *s = dev->subdevices + 0; int i, len, lo; - outb(0, dev->iobase + PCL818_FI_INTCLR); // clear fifo int request + outb(0, dev->iobase + PCL818_FI_INTCLR); /* clear fifo int request */ lo = inb(dev->iobase + PCL818_FI_STATUS); @@ -774,8 +774,8 @@ static irqreturn_t interrupt_pcl818_ai_mode13_fifo(int irq, void *d) for (i = 0; i < len; i++) { lo = inb(dev->iobase + PCL818_FI_DATALO); - if ((lo & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { // dropout! - rt_printk + if ((lo & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */ + printk ("comedi: A/D mode1/3 FIFO - channel dropout %d!=%d !\n", (lo & 0xf), devpriv->act_chanlist[devpriv-> @@ -786,7 +786,7 @@ static irqreturn_t interrupt_pcl818_ai_mode13_fifo(int irq, void *d) return IRQ_HANDLED; } - comedi_buf_put(s->async, (lo >> 4) | (inb(dev->iobase + PCL818_FI_DATAHI) << 4)); // get one sample + comedi_buf_put(s->async, (lo >> 4) | (inb(dev->iobase + PCL818_FI_DATAHI) << 4)); /* get one sample */ if (s->async->cur_chan == 0) { devpriv->ai_act_scan--; @@ -810,7 +810,7 @@ static irqreturn_t interrupt_pcl818_ai_mode13_fifo(int irq, void *d) ============================================================================== INT procedure */ -static irqreturn_t interrupt_pcl818(int irq, void *d PT_REGS_ARG) +static irqreturn_t interrupt_pcl818(int irq, void *d) { struct comedi_device *dev = d; @@ -818,7 +818,28 @@ static irqreturn_t interrupt_pcl818(int irq, void *d PT_REGS_ARG) comedi_error(dev, "premature interrupt"); return IRQ_HANDLED; } - //rt_printk("I\n"); + /* printk("I\n"); */ + + if (devpriv->irq_blocked && devpriv->irq_was_now_closed) { + if ((devpriv->neverending_ai || (!devpriv->neverending_ai && + devpriv->ai_act_scan > 0)) && + (devpriv->ai_mode == INT_TYPE_AI1_DMA || + devpriv->ai_mode == INT_TYPE_AI3_DMA)) { + /* The cleanup from ai_cancel() has been delayed + until now because the card doesn't seem to like + being reprogrammed while a DMA transfer is in + progress. + */ + struct comedi_subdevice *s = dev->subdevices + 0; + devpriv->ai_act_scan = 0; + devpriv->neverending_ai = 0; + pcl818_ai_cancel(dev, s); + } + + outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */ + + return IRQ_HANDLED; + } switch (devpriv->ai_mode) { case INT_TYPE_AI1_DMA: @@ -843,25 +864,6 @@ static irqreturn_t interrupt_pcl818(int irq, void *d PT_REGS_ARG) if ((!dev->irq) || (!devpriv->irq_free) || (!devpriv->irq_blocked) || (!devpriv->ai_mode)) { - if (devpriv->irq_was_now_closed) { - if (devpriv->neverending_ai && - (devpriv->ai_mode == INT_TYPE_AI1_DMA - || devpriv->ai_mode == - INT_TYPE_AI3_DMA)) { - /* we had neverending ai but ai_cancel() has been called - the cleanup from ai_cancel() has been delayed until know - because the card doesn't seem to like being reprogrammed - while a DMA transfer is in progress - */ - struct comedi_subdevice *s = dev->subdevices + 0; - devpriv->ai_mode = devpriv->irq_was_now_closed; - devpriv->irq_was_now_closed = 0; - devpriv->neverending_ai = 0; - pcl818_ai_cancel(dev, s); - } - devpriv->irq_was_now_closed = 0; - return IRQ_HANDLED; - } comedi_error(dev, "bad IRQ!"); return IRQ_NONE; } @@ -874,19 +876,19 @@ static irqreturn_t interrupt_pcl818(int irq, void *d PT_REGS_ARG) ============================================================================== ANALOG INPUT MODE 1 or 3 DMA , 818 cards */ -static void pcl818_ai_mode13dma_int(int mode, struct comedi_device * dev, - struct comedi_subdevice * s) +static void pcl818_ai_mode13dma_int(int mode, struct comedi_device *dev, + struct comedi_subdevice *s) { unsigned int flags; unsigned int bytes; - rt_printk("mode13dma_int, mode: %d\n", mode); - disable_dma(devpriv->dma); // disable dma + printk("mode13dma_int, mode: %d\n", mode); + disable_dma(devpriv->dma); /* disable dma */ bytes = devpriv->hwdmasize[0]; if (!devpriv->neverending_ai) { - bytes = devpriv->ai_n_chan * devpriv->ai_scans * sizeof(short); // how many - devpriv->dma_runs_to_end = bytes / devpriv->hwdmasize[0]; // how many DMA pages we must fiil - devpriv->last_dma_run = bytes % devpriv->hwdmasize[0]; //on last dma transfer must be moved + bytes = devpriv->ai_n_chan * devpriv->ai_scans * sizeof(short); /* how many */ + devpriv->dma_runs_to_end = bytes / devpriv->hwdmasize[0]; /* how many DMA pages we must fiil */ + devpriv->last_dma_run = bytes % devpriv->hwdmasize[0]; /* on last dma transfer must be moved */ devpriv->dma_runs_to_end--; if (devpriv->dma_runs_to_end >= 0) bytes = devpriv->hwdmasize[0]; @@ -915,8 +917,8 @@ static void pcl818_ai_mode13dma_int(int mode, struct comedi_device * dev, ============================================================================== ANALOG INPUT MODE 1 or 3 DMA rtc, 818 cards */ -static void pcl818_ai_mode13dma_rtc(int mode, struct comedi_device * dev, - struct comedi_subdevice * s) +static void pcl818_ai_mode13dma_rtc(int mode, struct comedi_device *dev, + struct comedi_subdevice *s) { unsigned int flags; short *pole; @@ -928,7 +930,7 @@ static void pcl818_ai_mode13dma_rtc(int mode, struct comedi_device * dev, set_dma_count(devpriv->dma, devpriv->hwdmasize[0]); release_dma_lock(flags); enable_dma(devpriv->dma); - devpriv->last_top_dma = 0; //devpriv->hwdmasize[0]; + devpriv->last_top_dma = 0; /* devpriv->hwdmasize[0]; */ pole = (short *) devpriv->dmabuf[0]; devpriv->dmasamplsize = devpriv->hwdmasize[0] / 2; pole[devpriv->dmasamplsize - 1] = MAGIC_DMA_WORD; @@ -956,14 +958,14 @@ static void pcl818_ai_mode13dma_rtc(int mode, struct comedi_device * dev, ============================================================================== ANALOG INPUT MODE 1 or 3, 818 cards */ -static int pcl818_ai_cmd_mode(int mode, struct comedi_device * dev, - struct comedi_subdevice * s) +static int pcl818_ai_cmd_mode(int mode, struct comedi_device *dev, + struct comedi_subdevice *s) { struct comedi_cmd *cmd = &s->async->cmd; int divisor1, divisor2; unsigned int seglen; - rt_printk("pcl818_ai_cmd_mode()\n"); + printk("pcl818_ai_cmd_mode()\n"); if ((!dev->irq) && (!devpriv->dma_rtc)) { comedi_error(dev, "IRQ not defined!"); return -EINVAL; @@ -972,7 +974,7 @@ static int pcl818_ai_cmd_mode(int mode, struct comedi_device * dev, if (devpriv->irq_blocked) return -EBUSY; - start_pacer(dev, -1, 0, 0); // stop pacer + start_pacer(dev, -1, 0, 0); /* stop pacer */ seglen = check_channel_list(dev, s, devpriv->ai_chanlist, devpriv->ai_n_chan); @@ -981,7 +983,7 @@ static int pcl818_ai_cmd_mode(int mode, struct comedi_device * dev, setup_channel_list(dev, s, devpriv->ai_chanlist, devpriv->ai_n_chan, seglen); - comedi_udelay(1); + udelay(1); devpriv->ai_act_scan = devpriv->ai_scans; devpriv->ai_act_chan = 0; @@ -992,7 +994,7 @@ static int pcl818_ai_cmd_mode(int mode, struct comedi_device * dev, devpriv->dma_runs_to_end = 0; if ((devpriv->ai_scans == 0) || (devpriv->ai_scans == -1)) - devpriv->neverending_ai = 1; //well, user want neverending + devpriv->neverending_ai = 1; /* well, user want neverending */ if (mode == 1) { i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, &divisor1, @@ -1010,7 +1012,7 @@ static int pcl818_ai_cmd_mode(int mode, struct comedi_device * dev, outb(0, dev->iobase + PCL818_CNTENABLE); /* enable pacer */ switch (devpriv->dma) { - case 1: // DMA + case 1: /* DMA */ case 3: if (devpriv->dma_rtc == 0) { pcl818_ai_mode13dma_int(mode, dev, s); @@ -1025,26 +1027,32 @@ static int pcl818_ai_cmd_mode(int mode, struct comedi_device * dev, } #endif break; - case 0: // IRQ - // rt_printk("IRQ\n"); - if (mode == 1) { - devpriv->ai_mode = INT_TYPE_AI1_INT; - outb(0x83 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+IRQ */ + case 0: + if (!devpriv->usefifo) { + /* IRQ */ + /* printk("IRQ\n"); */ + if (mode == 1) { + devpriv->ai_mode = INT_TYPE_AI1_INT; + /* Pacer+IRQ */ + outb(0x83 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); + } else { + devpriv->ai_mode = INT_TYPE_AI3_INT; + /* Ext trig+IRQ */ + outb(0x82 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); + } } else { - devpriv->ai_mode = INT_TYPE_AI3_INT; - outb(0x82 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+IRQ */ - }; - break; - case -1: // FIFO - outb(1, dev->iobase + PCL818_FI_ENABLE); // enable FIFO - if (mode == 1) { - devpriv->ai_mode = INT_TYPE_AI1_FIFO; - outb(0x03, dev->iobase + PCL818_CONTROL); /* Pacer */ - } else { - devpriv->ai_mode = INT_TYPE_AI3_FIFO; - outb(0x02, dev->iobase + PCL818_CONTROL); - }; /* Ext trig */ - break; + /* FIFO */ + /* enable FIFO */ + outb(1, dev->iobase + PCL818_FI_ENABLE); + if (mode == 1) { + devpriv->ai_mode = INT_TYPE_AI1_FIFO; + /* Pacer */ + outb(0x03, dev->iobase + PCL818_CONTROL); + } else { + devpriv->ai_mode = INT_TYPE_AI3_FIFO; + outb(0x02, dev->iobase + PCL818_CONTROL); + } + } } start_pacer(dev, mode, divisor1, divisor2); @@ -1057,7 +1065,7 @@ static int pcl818_ai_cmd_mode(int mode, struct comedi_device * dev, break; } #endif - rt_printk("pcl818_ai_cmd_mode() end\n"); + printk("pcl818_ai_cmd_mode() end\n"); return 0; } @@ -1067,8 +1075,8 @@ static int pcl818_ai_cmd_mode(int mode, struct comedi_device * dev, ANALOG OUTPUT MODE 1 or 3, 818 cards */ #ifdef PCL818_MODE13_AO -static int pcl818_ao_mode13(int mode, struct comedi_device * dev, struct comedi_subdevice * s, - comedi_trig * it) +static int pcl818_ao_mode13(int mode, struct comedi_device *dev, struct comedi_subdevice *s, + comedi_trig *it) { int divisor1, divisor2; @@ -1080,7 +1088,7 @@ static int pcl818_ao_mode13(int mode, struct comedi_device * dev, struct comedi_ if (devpriv->irq_blocked) return -EBUSY; - start_pacer(dev, -1, 0, 0); // stop pacer + start_pacer(dev, -1, 0, 0); /* stop pacer */ devpriv->int13_act_scan = it->n; devpriv->int13_act_chan = 0; @@ -1120,8 +1128,8 @@ static int pcl818_ao_mode13(int mode, struct comedi_device * dev, struct comedi_ ============================================================================== ANALOG OUTPUT MODE 1, 818 cards */ -static int pcl818_ao_mode1(struct comedi_device * dev, struct comedi_subdevice * s, - comedi_trig * it) +static int pcl818_ao_mode1(struct comedi_device *dev, struct comedi_subdevice *s, + comedi_trig *it) { return pcl818_ao_mode13(1, dev, s, it); } @@ -1130,8 +1138,8 @@ static int pcl818_ao_mode1(struct comedi_device * dev, struct comedi_subdevice * ============================================================================== ANALOG OUTPUT MODE 3, 818 cards */ -static int pcl818_ao_mode3(struct comedi_device * dev, struct comedi_subdevice * s, - comedi_trig * it) +static int pcl818_ao_mode3(struct comedi_device *dev, struct comedi_subdevice *s, + comedi_trig *it) { return pcl818_ao_mode13(3, dev, s, it); } @@ -1142,12 +1150,12 @@ static int pcl818_ao_mode3(struct comedi_device * dev, struct comedi_subdevice * ============================================================================== Start/stop pacer onboard pacer */ -static void start_pacer(struct comedi_device * dev, int mode, unsigned int divisor1, +static void start_pacer(struct comedi_device *dev, int mode, unsigned int divisor1, unsigned int divisor2) { outb(0xb4, dev->iobase + PCL818_CTRCTL); outb(0x74, dev->iobase + PCL818_CTRCTL); - comedi_udelay(1); + udelay(1); if (mode == 1) { outb(divisor2 & 0xff, dev->iobase + PCL818_CTR2); @@ -1162,7 +1170,7 @@ static void start_pacer(struct comedi_device * dev, int mode, unsigned int divis Check if channel list from user is builded correctly If it's ok, then program scan/gain logic */ -static int check_channel_list(struct comedi_device * dev, struct comedi_subdevice * s, +static int check_channel_list(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int *chanlist, unsigned int n_chan) { unsigned int chansegment[16]; @@ -1175,32 +1183,36 @@ static int check_channel_list(struct comedi_device * dev, struct comedi_subdevic } if (n_chan > 1) { - // first channel is everytime ok + /* first channel is everytime ok */ chansegment[0] = chanlist[0]; - // build part of chanlist + /* build part of chanlist */ for (i = 1, seglen = 1; i < n_chan; i++, seglen++) { - // rt_printk("%d. %d %d\n",i,CR_CHAN(it->chanlist[i]),CR_RANGE(it->chanlist[i])); - // we detect loop, this must by finish + + /* printk("%d. %d * %d\n",i, + * CR_CHAN(it->chanlist[i]),CR_RANGE(it->chanlist[i]));*/ + + /* we detect loop, this must by finish */ + if (chanlist[0] == chanlist[i]) break; nowmustbechan = (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan; - if (nowmustbechan != CR_CHAN(chanlist[i])) { // channel list isn't continous :-( - rt_printk + if (nowmustbechan != CR_CHAN(chanlist[i])) { /* channel list isn't continous :-( */ + printk ("comedi%d: pcl818: channel list must be continous! chanlist[%i]=%d but must be %d or %d!\n", dev->minor, i, CR_CHAN(chanlist[i]), nowmustbechan, CR_CHAN(chanlist[0])); return 0; } - // well, this is next correct channel in list + /* well, this is next correct channel in list */ chansegment[i] = chanlist[i]; } - // check whole chanlist + /* check whole chanlist */ for (i = 0, segpos = 0; i < n_chan; i++) { - //rt_printk("%d %d=%d %d\n",CR_CHAN(chansegment[i%seglen]),CR_RANGE(chansegment[i%seglen]),CR_CHAN(it->chanlist[i]),CR_RANGE(it->chanlist[i])); + /* printk("%d %d=%d %d\n",CR_CHAN(chansegment[i%seglen]),CR_RANGE(chansegment[i%seglen]),CR_CHAN(it->chanlist[i]),CR_RANGE(it->chanlist[i])); */ if (chanlist[i] != chansegment[i % seglen]) { - rt_printk + printk ("comedi%d: pcl818: bad channel or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n", dev->minor, i, CR_CHAN(chansegment[i]), CR_RANGE(chansegment[i]), @@ -1208,17 +1220,17 @@ static int check_channel_list(struct comedi_device * dev, struct comedi_subdevic CR_CHAN(chanlist[i % seglen]), CR_RANGE(chanlist[i % seglen]), CR_AREF(chansegment[i % seglen])); - return 0; // chan/gain list is strange + return 0; /* chan/gain list is strange */ } } } else { seglen = 1; } - rt_printk("check_channel_list: seglen %d\n", seglen); + printk("check_channel_list: seglen %d\n", seglen); return seglen; } -static void setup_channel_list(struct comedi_device * dev, struct comedi_subdevice * s, +static void setup_channel_list(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int *chanlist, unsigned int n_chan, unsigned int seglen) { int i; @@ -1226,13 +1238,13 @@ static void setup_channel_list(struct comedi_device * dev, struct comedi_subdevi devpriv->act_chanlist_len = seglen; devpriv->act_chanlist_pos = 0; - for (i = 0; i < seglen; i++) { // store range list to card + for (i = 0; i < seglen; i++) { /* store range list to card */ devpriv->act_chanlist[i] = CR_CHAN(chanlist[i]); outb(muxonechan[CR_CHAN(chanlist[i])], dev->iobase + PCL818_MUX); /* select channel */ outb(CR_RANGE(chanlist[i]), dev->iobase + PCL818_RANGE); /* select gain */ } - comedi_udelay(1); + udelay(1); /* select channel interval to scan */ outb(devpriv->act_chanlist[0] | (devpriv->act_chanlist[seglen - @@ -1255,8 +1267,8 @@ static int check_single_ended(unsigned int port) /* ============================================================================== */ -static int ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd) +static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd) { int err = 0; int tmp, divisor1, divisor2; @@ -1391,7 +1403,7 @@ static int ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, if (cmd->chanlist) { if (!check_channel_list(dev, s, cmd->chanlist, cmd->chanlist_len)) - return 5; // incorrect channels list + return 5; /* incorrect channels list */ } return 0; @@ -1400,12 +1412,12 @@ static int ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, /* ============================================================================== */ -static int ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s) +static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { struct comedi_cmd *cmd = &s->async->cmd; int retval; - rt_printk("pcl818_ai_cmd()\n"); + printk("pcl818_ai_cmd()\n"); devpriv->ai_n_chan = cmd->chanlist_len; devpriv->ai_chanlist = cmd->chanlist; devpriv->ai_flags = cmd->flags; @@ -1420,14 +1432,14 @@ static int ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s) devpriv->ai_scans = 0; } - if (cmd->scan_begin_src == TRIG_FOLLOW) { // mode 1, 3 - if (cmd->convert_src == TRIG_TIMER) { // mode 1 + if (cmd->scan_begin_src == TRIG_FOLLOW) { /* mode 1, 3 */ + if (cmd->convert_src == TRIG_TIMER) { /* mode 1 */ devpriv->ai_timer1 = cmd->convert_arg; retval = pcl818_ai_cmd_mode(1, dev, s); - rt_printk("pcl818_ai_cmd() end\n"); + printk("pcl818_ai_cmd() end\n"); return retval; } - if (cmd->convert_src == TRIG_EXT) { // mode 3 + if (cmd->convert_src == TRIG_EXT) { /* mode 3 */ return pcl818_ai_cmd_mode(3, dev, s); } } @@ -1439,23 +1451,24 @@ static int ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s) ============================================================================== cancel any mode 1-4 AI */ -static int pcl818_ai_cancel(struct comedi_device * dev, struct comedi_subdevice * s) +static int pcl818_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { if (devpriv->irq_blocked > 0) { - rt_printk("pcl818_ai_cancel()\n"); - devpriv->irq_was_now_closed = devpriv->ai_mode; - devpriv->ai_mode = 0; + printk("pcl818_ai_cancel()\n"); + devpriv->irq_was_now_closed = 1; - switch (devpriv->irq_was_now_closed) { + switch (devpriv->ai_mode) { #ifdef unused case INT_TYPE_AI1_DMA_RTC: case INT_TYPE_AI3_DMA_RTC: - set_rtc_irq_bit(0); // stop RTC + set_rtc_irq_bit(0); /* stop RTC */ del_timer(&devpriv->rtc_irq_timer); #endif case INT_TYPE_AI1_DMA: case INT_TYPE_AI3_DMA: - if (devpriv->neverending_ai) { + if (devpriv->neverending_ai || + (!devpriv->neverending_ai && + devpriv->ai_act_scan > 0)) { /* wait for running dma transfer to end, do cleanup in interrupt */ goto end; } @@ -1469,14 +1482,14 @@ static int pcl818_ai_cancel(struct comedi_device * dev, struct comedi_subdevice case INT_TYPE_AO3_INT: #endif outb(inb(dev->iobase + PCL818_CONTROL) & 0x73, dev->iobase + PCL818_CONTROL); /* Stop A/D */ - comedi_udelay(1); + udelay(1); start_pacer(dev, -1, 0, 0); outb(0, dev->iobase + PCL818_AD_LO); inb(dev->iobase + PCL818_AD_LO); inb(dev->iobase + PCL818_AD_HI); outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */ outb(0, dev->iobase + PCL818_CONTROL); /* Stop A/D */ - if (devpriv->usefifo) { // FIFO shutdown + if (devpriv->usefifo) { /* FIFO shutdown */ outb(0, dev->iobase + PCL818_FI_INTCLR); outb(0, dev->iobase + PCL818_FI_FLUSH); outb(0, dev->iobase + PCL818_FI_ENABLE); @@ -1484,12 +1497,14 @@ static int pcl818_ai_cancel(struct comedi_device * dev, struct comedi_subdevice devpriv->irq_blocked = 0; devpriv->last_int_sub = s; devpriv->neverending_ai = 0; + devpriv->ai_mode = 0; + devpriv->irq_was_now_closed = 0; break; } } end: - rt_printk("pcl818_ai_cancel() end\n"); + printk("pcl818_ai_cancel() end\n"); return 0; } @@ -1500,39 +1515,39 @@ static int pcl818_ai_cancel(struct comedi_device * dev, struct comedi_subdevice static int pcl818_check(unsigned long iobase) { outb(0x00, iobase + PCL818_MUX); - comedi_udelay(1); + udelay(1); if (inb(iobase + PCL818_MUX) != 0x00) - return 1; //there isn't card + return 1; /* there isn't card */ outb(0x55, iobase + PCL818_MUX); - comedi_udelay(1); + udelay(1); if (inb(iobase + PCL818_MUX) != 0x55) - return 1; //there isn't card + return 1; /* there isn't card */ outb(0x00, iobase + PCL818_MUX); - comedi_udelay(1); + udelay(1); outb(0x18, iobase + PCL818_CONTROL); - comedi_udelay(1); + udelay(1); if (inb(iobase + PCL818_CONTROL) != 0x18) - return 1; //there isn't card - return 0; // ok, card exist + return 1; /* there isn't card */ + return 0; /* ok, card exist */ } /* ============================================================================== reset whole PCL-818 cards */ -static void pcl818_reset(struct comedi_device * dev) +static void pcl818_reset(struct comedi_device *dev) { - if (devpriv->usefifo) { // FIFO shutdown + if (devpriv->usefifo) { /* FIFO shutdown */ outb(0, dev->iobase + PCL818_FI_INTCLR); outb(0, dev->iobase + PCL818_FI_FLUSH); outb(0, dev->iobase + PCL818_FI_ENABLE); } - outb(0, dev->iobase + PCL818_DA_LO); // DAC=0V + outb(0, dev->iobase + PCL818_DA_LO); /* DAC=0V */ outb(0, dev->iobase + PCL818_DA_HI); - comedi_udelay(1); - outb(0, dev->iobase + PCL818_DO_HI); // DO=$0000 + udelay(1); + outb(0, dev->iobase + PCL818_DO_HI); /* DO=$0000 */ outb(0, dev->iobase + PCL818_DO_LO); - comedi_udelay(1); + udelay(1); outb(0, dev->iobase + PCL818_CONTROL); outb(0, dev->iobase + PCL818_CNTENABLE); outb(0, dev->iobase + PCL818_MUX); @@ -1641,9 +1656,9 @@ static int rtc_setfreq_irq(int freq) ============================================================================== Free any resources that we have claimed */ -static void free_resources(struct comedi_device * dev) +static void free_resources(struct comedi_device *dev) { - //rt_printk("free_resource()\n"); + /* printk("free_resource()\n"); */ if (dev->private) { pcl818_ai_cancel(dev, devpriv->sub_ai); pcl818_reset(dev); @@ -1655,7 +1670,7 @@ static void free_resources(struct comedi_device * dev) free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]); #ifdef unused if (devpriv->rtc_irq) - comedi_free_irq(devpriv->rtc_irq, dev); + free_irq(devpriv->rtc_irq, dev); if ((devpriv->dma_rtc) && (RTC_lock == 1)) { if (devpriv->rtc_iobase) release_region(devpriv->rtc_iobase, @@ -1670,7 +1685,7 @@ static void free_resources(struct comedi_device * dev) free_irq(dev->irq, dev); if (dev->iobase) release_region(dev->iobase, devpriv->io_range); - //rt_printk("free_resource() end\n"); + /* printk("free_resource() end\n"); */ } /* @@ -1679,15 +1694,17 @@ static void free_resources(struct comedi_device * dev) Initialization */ -static int pcl818_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it) { int ret; unsigned long iobase; - unsigned int irq, dma; + unsigned int irq; + int dma; unsigned long pages; struct comedi_subdevice *s; - if ((ret = alloc_private(dev, sizeof(struct pcl818_private))) < 0) + ret = alloc_private(dev, sizeof(struct pcl818_private)); + if (ret < 0) return ret; /* Can't alloc mem */ /* claim our I/O space */ @@ -1695,19 +1712,19 @@ static int pcl818_attach(struct comedi_device * dev, struct comedi_devconfig * i printk("comedi%d: pcl818: board=%s, ioport=0x%03lx", dev->minor, this_board->name, iobase); devpriv->io_range = this_board->io_range; - if ((this_board->fifo) && (it->options[2] == -1)) { // we've board with FIFO and we want to use FIFO + if ((this_board->fifo) && (it->options[2] == -1)) { /* we've board with FIFO and we want to use FIFO */ devpriv->io_range = PCLx1xFIFO_RANGE; devpriv->usefifo = 1; } if (!request_region(iobase, devpriv->io_range, "pcl818")) { - rt_printk("I/O port conflict\n"); + printk("I/O port conflict\n"); return -EIO; } dev->iobase = iobase; if (pcl818_check(iobase)) { - rt_printk(", I can't detect board. FAIL!\n"); + printk(", I can't detect board. FAIL!\n"); return -EIO; } @@ -1719,19 +1736,18 @@ static int pcl818_attach(struct comedi_device * dev, struct comedi_devconfig * i irq = it->options[1]; if (irq) { /* we want to use IRQ */ if (((1 << irq) & this_board->IRQbits) == 0) { - rt_printk + printk (", IRQ %u is out of allowed range, DISABLING IT", irq); irq = 0; /* Bad IRQ */ } else { - if (comedi_request_irq(irq, interrupt_pcl818, 0, - "pcl818", dev)) { - rt_printk + if (request_irq(irq, interrupt_pcl818, 0, "pcl818", dev)) { + printk (", unable to allocate IRQ %u, DISABLING IT", irq); irq = 0; /* Can't use IRQ */ } else { - rt_printk(", irq=%u", irq); + printk(", irq=%u", irq); } } } @@ -1750,7 +1766,7 @@ static int pcl818_attach(struct comedi_device * dev, struct comedi_devconfig * i #ifdef unused /* grab RTC for DMA operations */ devpriv->dma_rtc = 0; - if (it->options[2] > 0) { // we want to use DMA + if (it->options[2] > 0) { /* we want to use DMA */ if (RTC_lock == 0) { if (!request_region(RTC_PORT(0), RTC_IO_EXTENT, "pcl818 (RTC)")) @@ -1759,12 +1775,11 @@ static int pcl818_attach(struct comedi_device * dev, struct comedi_devconfig * i devpriv->rtc_iobase = RTC_PORT(0); devpriv->rtc_iosize = RTC_IO_EXTENT; RTC_lock++; - if (!comedi_request_irq(RTC_IRQ, - interrupt_pcl818_ai_mode13_dma_rtc, 0, + if (!request_irq(RTC_IRQ, interrupt_pcl818_ai_mode13_dma_rtc, 0, "pcl818 DMA (RTC)", dev)) { devpriv->dma_rtc = 1; devpriv->rtc_irq = RTC_IRQ; - rt_printk(", dma_irq=%u", devpriv->rtc_irq); + printk(", dma_irq=%u", devpriv->rtc_irq); } else { RTC_lock--; if (RTC_lock == 0) { @@ -1789,31 +1804,31 @@ static int pcl818_attach(struct comedi_device * dev, struct comedi_devconfig * i if (dma < 1) goto no_dma; /* DMA disabled */ if (((1 << dma) & this_board->DMAbits) == 0) { - rt_printk(", DMA is out of allowed range, FAIL!\n"); + printk(", DMA is out of allowed range, FAIL!\n"); return -EINVAL; /* Bad DMA */ } ret = request_dma(dma, "pcl818"); if (ret) { - rt_printk(", unable to allocate DMA %u, FAIL!\n", dma); + printk(", unable to allocate DMA %u, FAIL!\n", dma); return -EBUSY; /* DMA isn't free */ } devpriv->dma = dma; - rt_printk(", dma=%u", dma); + printk(", dma=%u", dma); pages = 2; /* we need 16KB */ devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages); if (!devpriv->dmabuf[0]) { - rt_printk(", unable to allocate DMA buffer, FAIL!\n"); + printk(", unable to allocate DMA buffer, FAIL!\n"); /* maybe experiment with try_to_free_pages() will help .... */ return -EBUSY; /* no buffer :-( */ } devpriv->dmapages[0] = pages; devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]); devpriv->hwdmasize[0] = (1 << pages) * PAGE_SIZE; - //rt_printk("%d %d %ld, ",devpriv->dmapages[0],devpriv->hwdmasize[0],PAGE_SIZE); - if (devpriv->dma_rtc == 0) { // we must do duble buff :-( + /* printk("%d %d %ld, ",devpriv->dmapages[0],devpriv->hwdmasize[0],PAGE_SIZE); */ + if (devpriv->dma_rtc == 0) { /* we must do duble buff :-( */ devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages); if (!devpriv->dmabuf[1]) { - rt_printk + printk (", unable to allocate DMA buffer, FAIL!\n"); return -EBUSY; } @@ -1826,7 +1841,8 @@ static int pcl818_attach(struct comedi_device * dev, struct comedi_devconfig * i no_dma: - if ((ret = alloc_subdevices(dev, 4)) < 0) + ret = alloc_subdevices(dev, 4); + if (ret < 0) return ret; s = dev->subdevices + 0; @@ -1858,7 +1874,7 @@ static int pcl818_attach(struct comedi_device * dev, struct comedi_devconfig * i } if (this_board->is_818) { if ((it->options[4] == 1) || (it->options[4] == 10)) - s->range_table = &range_pcl818l_h_ai; // secondary range list jumper selectable + s->range_table = &range_pcl818l_h_ai; /* secondary range list jumper selectable */ } else { switch (it->options[4]) { case 0: @@ -1971,7 +1987,7 @@ static int pcl818_attach(struct comedi_device * dev, struct comedi_devconfig * i pcl818_reset(dev); - rt_printk("\n"); + printk("\n"); return 0; } @@ -1980,9 +1996,9 @@ static int pcl818_attach(struct comedi_device * dev, struct comedi_devconfig * i ============================================================================== Removes device */ -static int pcl818_detach(struct comedi_device * dev) +static int pcl818_detach(struct comedi_device *dev) { - // rt_printk("comedi%d: pcl818: remove\n", dev->minor); + /* printk("comedi%d: pcl818: remove\n", dev->minor); */ free_resources(dev); return 0; } diff --git a/drivers/staging/comedi/drivers/pcm3724.c b/drivers/staging/comedi/drivers/pcm3724.c index a3ed3a0e855a..a5d6b1d9a1aa 100644 --- a/drivers/staging/comedi/drivers/pcm3724.c +++ b/drivers/staging/comedi/drivers/pcm3724.c @@ -62,18 +62,18 @@ Copy/pasted/hacked from pcm724.c #define CR_A_MODE(a) ((a)<<5) #define CR_CW 0x80 -static int pcm3724_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int pcm3724_detach(struct comedi_device * dev); +static int pcm3724_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int pcm3724_detach(struct comedi_device *dev); struct pcm3724_board { - const char *name; // driver name - int dio; // num of DIO - int numofports; // num of 8255 subdevices - unsigned int IRQbits; // allowed interrupts - unsigned int io_range; // len of IO space + const char *name; /* driver name */ + int dio; /* num of DIO */ + int numofports; /* num of 8255 subdevices */ + unsigned int IRQbits; /* allowed interrupts */ + unsigned int io_range; /* len of IO space */ }; -//used to track configured dios +/* used to track configured dios */ struct priv_pcm3724 { int dio_1; int dio_2; @@ -87,36 +87,36 @@ static const struct pcm3724_board boardtypes[] = { #define this_board ((const struct pcm3724_board *)dev->board_ptr) static struct comedi_driver driver_pcm3724 = { - driver_name:"pcm3724", - module:THIS_MODULE, - attach:pcm3724_attach, - detach:pcm3724_detach, - board_name:&boardtypes[0].name, - num_names:n_boardtypes, - offset:sizeof(struct pcm3724_board), + .driver_name = "pcm3724", + .module = THIS_MODULE, + .attach = pcm3724_attach, + .detach = pcm3724_detach, + .board_name = &boardtypes[0].name, + .num_names = n_boardtypes, + .offset = sizeof(struct pcm3724_board), }; COMEDI_INITCLEANUP(driver_pcm3724); -// (setq c-basic-offset 8) +/* (setq c-basic-offset 8) */ static int subdev_8255_cb(int dir, int port, int data, unsigned long arg) { unsigned long iobase = arg; unsigned char inbres; - //printk("8255cb %d %d %d %lx\n", dir,port,data,arg); + /* printk("8255cb %d %d %d %lx\n", dir,port,data,arg); */ if (dir) { - //printk("8255 cb outb(%x, %lx)\n", data, iobase+port); + /* printk("8255 cb outb(%x, %lx)\n", data, iobase+port); */ outb(data, iobase + port); return 0; } else { inbres = inb(iobase + port); - //printk("8255 cb inb(%lx) = %x\n", iobase+port, inbres); + /* printk("8255 cb inb(%lx) = %x\n", iobase+port, inbres); */ return inbres; } } -static int compute_buffer(int config, int devno, struct comedi_subdevice * s) +static int compute_buffer(int config, int devno, struct comedi_subdevice *s) { /* 1 in io_bits indicates output */ if (s->io_bits & 0x0000ff) { @@ -143,7 +143,7 @@ static int compute_buffer(int config, int devno, struct comedi_subdevice * s) return config; } -static void do_3724_config(struct comedi_device * dev, struct comedi_subdevice * s, +static void do_3724_config(struct comedi_device *dev, struct comedi_subdevice *s, int chanspec) { int config; @@ -173,11 +173,11 @@ static void do_3724_config(struct comedi_device * dev, struct comedi_subdevice * port_8255_cfg = dev->iobase + SIZE_8255 + _8255_CR; } outb(buffer_config, dev->iobase + 8); /* update buffer register */ - //printk("pcm3724 buffer_config (%lx) %d, %x\n", dev->iobase + _8255_CR, chanspec, buffer_config); + /* printk("pcm3724 buffer_config (%lx) %d, %x\n", dev->iobase + _8255_CR, chanspec, buffer_config); */ outb(config, port_8255_cfg); } -static void enable_chan(struct comedi_device * dev, struct comedi_subdevice * s, int chanspec) +static void enable_chan(struct comedi_device *dev, struct comedi_subdevice *s, int chanspec) { unsigned int mask; int gatecfg; @@ -187,9 +187,9 @@ static void enable_chan(struct comedi_device * dev, struct comedi_subdevice * s, priv = (struct priv_pcm3724 *) (dev->private); mask = 1 << CR_CHAN(chanspec); - if (s == dev->subdevices) { // subdev 0 + if (s == dev->subdevices) { /* subdev 0 */ priv->dio_1 |= mask; - } else { //subdev 1 + } else { /* subdev 1 */ priv->dio_2 |= mask; } if (priv->dio_1 & 0xff0000) { @@ -210,13 +210,13 @@ static void enable_chan(struct comedi_device * dev, struct comedi_subdevice * s, if (priv->dio_2 & 0xff) { gatecfg |= GATE_A1; } - // printk("gate control %x\n", gatecfg); + /* printk("gate control %x\n", gatecfg); */ outb(gatecfg, dev->iobase + 9); } /* overriding the 8255 insn config */ -static int subdev_3724_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int subdev_3724_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { unsigned int mask; unsigned int bits; @@ -252,7 +252,7 @@ static int subdev_3724_insn_config(struct comedi_device * dev, struct comedi_sub return 1; } -static int pcm3724_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int pcm3724_attach(struct comedi_device *dev, struct comedi_devconfig *it) { unsigned long iobase; unsigned int iorange; @@ -260,7 +260,9 @@ static int pcm3724_attach(struct comedi_device * dev, struct comedi_devconfig * iobase = it->options[0]; iorange = this_board->io_range; - if ((ret = alloc_private(dev, sizeof(struct priv_pcm3724))) < 0) + + ret = alloc_private(dev, sizeof(struct priv_pcm3724)); + if (ret < 0) return -ENOMEM; ((struct priv_pcm3724 *) (dev->private))->dio_1 = 0; @@ -279,7 +281,8 @@ static int pcm3724_attach(struct comedi_device * dev, struct comedi_devconfig * n_subdevices = this_board->numofports; - if ((ret = alloc_subdevices(dev, n_subdevices)) < 0) + ret = alloc_subdevices(dev, n_subdevices); + if (ret < 0) return ret; for (i = 0; i < dev->n_subdevices; i++) { @@ -290,7 +293,7 @@ static int pcm3724_attach(struct comedi_device * dev, struct comedi_devconfig * return 0; } -static int pcm3724_detach(struct comedi_device * dev) +static int pcm3724_detach(struct comedi_device *dev) { int i; diff --git a/drivers/staging/comedi/drivers/pcm3730.c b/drivers/staging/comedi/drivers/pcm3730.c index 1de555fe645c..ae90ea4ae3c9 100644 --- a/drivers/staging/comedi/drivers/pcm3730.c +++ b/drivers/staging/comedi/drivers/pcm3730.c @@ -19,28 +19,28 @@ Configuration options: #include -#define PCM3730_SIZE 4 // consecutive io port addresses +#define PCM3730_SIZE 4 /* consecutive io port addresses */ -#define PCM3730_DOA 0 // offsets for each port +#define PCM3730_DOA 0 /* offsets for each port */ #define PCM3730_DOB 2 #define PCM3730_DOC 3 #define PCM3730_DIA 0 #define PCM3730_DIB 2 #define PCM3730_DIC 3 -static int pcm3730_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int pcm3730_detach(struct comedi_device * dev); +static int pcm3730_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int pcm3730_detach(struct comedi_device *dev); static struct comedi_driver driver_pcm3730 = { - driver_name:"pcm3730", - module:THIS_MODULE, - attach:pcm3730_attach, - detach:pcm3730_detach, + .driver_name = "pcm3730", + .module = THIS_MODULE, + .attach = pcm3730_attach, + .detach = pcm3730_detach, }; COMEDI_INITCLEANUP(driver_pcm3730); -static int pcm3730_do_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pcm3730_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if (insn->n != 2) return -EINVAL; @@ -54,8 +54,8 @@ static int pcm3730_do_insn_bits(struct comedi_device * dev, struct comedi_subdev return 2; } -static int pcm3730_di_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pcm3730_di_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if (insn->n != 2) return -EINVAL; @@ -63,7 +63,7 @@ static int pcm3730_di_insn_bits(struct comedi_device * dev, struct comedi_subdev return 2; } -static int pcm3730_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int pcm3730_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; unsigned long iobase; @@ -141,7 +141,7 @@ static int pcm3730_attach(struct comedi_device * dev, struct comedi_devconfig * return 0; } -static int pcm3730_detach(struct comedi_device * dev) +static int pcm3730_detach(struct comedi_device *dev) { printk("comedi%d: pcm3730: remove\n", dev->minor); diff --git a/drivers/staging/comedi/drivers/pcm_common.c b/drivers/staging/comedi/drivers/pcm_common.c new file mode 100644 index 000000000000..ebd9838232af --- /dev/null +++ b/drivers/staging/comedi/drivers/pcm_common.c @@ -0,0 +1,111 @@ +#include "../comedidev.h" +#include "pcm_common.h" + +/* + * 'do_cmdtest' function for an 'INTERRUPT' subdevice. This is for + * the PCM drivers. + */ +int comedi_pcm_cmdtest(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_cmd *cmd) +{ + int err = 0; + unsigned int tmp; + + /* step 1: make sure trigger sources are trivially valid */ + + tmp = cmd->start_src; + cmd->start_src &= (TRIG_NOW | TRIG_INT); + if (!cmd->start_src || tmp != cmd->start_src) + err++; + + tmp = cmd->scan_begin_src; + cmd->scan_begin_src &= TRIG_EXT; + if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) + err++; + + tmp = cmd->convert_src; + cmd->convert_src &= TRIG_NOW; + if (!cmd->convert_src || tmp != cmd->convert_src) + err++; + + tmp = cmd->scan_end_src; + cmd->scan_end_src &= TRIG_COUNT; + if (!cmd->scan_end_src || tmp != cmd->scan_end_src) + err++; + + tmp = cmd->stop_src; + cmd->stop_src &= (TRIG_COUNT | TRIG_NONE); + if (!cmd->stop_src || tmp != cmd->stop_src) + err++; + + if (err) + return 1; + + /* step 2: make sure trigger sources are unique and mutually compatible */ + + /* these tests are true if more than one _src bit is set */ + if ((cmd->start_src & (cmd->start_src - 1)) != 0) + err++; + if ((cmd->scan_begin_src & (cmd->scan_begin_src - 1)) != 0) + err++; + if ((cmd->convert_src & (cmd->convert_src - 1)) != 0) + err++; + if ((cmd->scan_end_src & (cmd->scan_end_src - 1)) != 0) + err++; + if ((cmd->stop_src & (cmd->stop_src - 1)) != 0) + err++; + + if (err) + return 2; + + /* step 3: make sure arguments are trivially compatible */ + + /* cmd->start_src == TRIG_NOW || cmd->start_src == TRIG_INT */ + if (cmd->start_arg != 0) { + cmd->start_arg = 0; + err++; + } + + /* cmd->scan_begin_src == TRIG_EXT */ + if (cmd->scan_begin_arg != 0) { + cmd->scan_begin_arg = 0; + err++; + } + + /* cmd->convert_src == TRIG_NOW */ + if (cmd->convert_arg != 0) { + cmd->convert_arg = 0; + err++; + } + + /* cmd->scan_end_src == TRIG_COUNT */ + if (cmd->scan_end_arg != cmd->chanlist_len) { + cmd->scan_end_arg = cmd->chanlist_len; + err++; + } + + switch (cmd->stop_src) { + case TRIG_COUNT: + /* any count allowed */ + break; + case TRIG_NONE: + if (cmd->stop_arg != 0) { + cmd->stop_arg = 0; + err++; + } + break; + default: + break; + } + + if (err) + return 3; + + /* step 4: fix up any arguments */ + + /* if (err) return 4; */ + + return 0; +} + +EXPORT_SYMBOL(comedi_pcm_cmdtest); diff --git a/drivers/staging/comedi/drivers/pcm_common.h b/drivers/staging/comedi/drivers/pcm_common.h new file mode 100644 index 000000000000..cd4840c11444 --- /dev/null +++ b/drivers/staging/comedi/drivers/pcm_common.h @@ -0,0 +1,8 @@ +#ifndef _comedi_common_H +#define _comedi_common_H + +extern int comedi_pcm_cmdtest(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd); + +#endif diff --git a/drivers/staging/comedi/drivers/pcmad.c b/drivers/staging/comedi/drivers/pcmad.c index fc2a73d97c24..9bb26699f47e 100644 --- a/drivers/staging/comedi/drivers/pcmad.c +++ b/drivers/staging/comedi/drivers/pcmad.c @@ -41,6 +41,7 @@ Configuration options: 1 = two's complement */ +#include #include "../comedidev.h" #include @@ -58,12 +59,12 @@ struct pcmad_board_struct { }; static const struct pcmad_board_struct pcmad_boards[] = { { - name: "pcmad12", - n_ai_bits:12, + .name = "pcmad12", + .n_ai_bits = 12, }, { - name: "pcmad16", - n_ai_bits:16, + .name = "pcmad16", + .n_ai_bits = 16, }, }; @@ -76,24 +77,24 @@ struct pcmad_priv_struct { }; #define devpriv ((struct pcmad_priv_struct *)dev->private) -static int pcmad_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int pcmad_detach(struct comedi_device * dev); +static int pcmad_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int pcmad_detach(struct comedi_device *dev); static struct comedi_driver driver_pcmad = { - driver_name:"pcmad", - module:THIS_MODULE, - attach:pcmad_attach, - detach:pcmad_detach, - board_name:&pcmad_boards[0].name, - num_names:n_pcmad_boards, - offset:sizeof(pcmad_boards[0]), + .driver_name = "pcmad", + .module = THIS_MODULE, + .attach = pcmad_attach, + .detach = pcmad_detach, + .board_name = &pcmad_boards[0].name, + .num_names = n_pcmad_boards, + .offset = sizeof(pcmad_boards[0]), }; COMEDI_INITCLEANUP(driver_pcmad); #define TIMEOUT 100 -static int pcmad_ai_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pcmad_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i; int chan; @@ -126,7 +127,7 @@ static int pcmad_ai_insn_read(struct comedi_device * dev, struct comedi_subdevic * 2 0=single ended 1=differential * 3 0=straight binary 1=two's comp */ -static int pcmad_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int pcmad_attach(struct comedi_device *dev, struct comedi_devconfig *it) { int ret; struct comedi_subdevice *s; @@ -140,9 +141,12 @@ static int pcmad_attach(struct comedi_device * dev, struct comedi_devconfig * it } dev->iobase = iobase; - if ((ret = alloc_subdevices(dev, 1)) < 0) + ret = alloc_subdevices(dev, 1); + if (ret < 0) return ret; - if ((ret = alloc_private(dev, sizeof(struct pcmad_priv_struct))) < 0) + + ret = alloc_private(dev, sizeof(struct pcmad_priv_struct)); + if (ret < 0) return ret; dev->board_name = this_board->name; @@ -159,7 +163,7 @@ static int pcmad_attach(struct comedi_device * dev, struct comedi_devconfig * it return 0; } -static int pcmad_detach(struct comedi_device * dev) +static int pcmad_detach(struct comedi_device *dev) { printk("comedi%d: pcmad: remove\n", dev->minor); diff --git a/drivers/staging/comedi/drivers/pcmda12.c b/drivers/staging/comedi/drivers/pcmda12.c index 2a1ff465602a..6e172a6b1cb2 100644 --- a/drivers/staging/comedi/drivers/pcmda12.c +++ b/drivers/staging/comedi/drivers/pcmda12.c @@ -55,7 +55,6 @@ Configuration Options: #include /* for PCI devices */ -#define MIN(a,b) ( ((a) < (b)) ? (a) : (b) ) #define SDEV_NO ((int)(s - dev->subdevices)) #define CHANS 8 #define IOSIZE 16 @@ -83,7 +82,7 @@ static const struct comedi_lrange pcmda12_ranges = { static const struct pcmda12_board pcmda12_boards[] = { { - name: "pcmda12", + .name = "pcmda12", }, }; @@ -107,16 +106,16 @@ struct pcmda12_private { * the board, and also about the kernel module that contains * the device code. */ -static int pcmda12_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int pcmda12_detach(struct comedi_device * dev); +static int pcmda12_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int pcmda12_detach(struct comedi_device *dev); -static void zero_chans(struct comedi_device * dev); +static void zero_chans(struct comedi_device *dev); static struct comedi_driver driver = { - driver_name:"pcmda12", - module:THIS_MODULE, - attach:pcmda12_attach, - detach:pcmda12_detach, + .driver_name = "pcmda12", + .module = THIS_MODULE, + .attach = pcmda12_attach, + .detach = pcmda12_detach, /* It is not necessary to implement the following members if you are * writing a driver for a ISA PnP or PCI card */ /* Most drivers will support multiple types of boards by @@ -135,15 +134,15 @@ static struct comedi_driver driver = { * the type of board in software. ISA PnP, PCI, and PCMCIA * devices are such boards. */ - board_name:&pcmda12_boards[0].name, - offset:sizeof(struct pcmda12_board), - num_names:sizeof(pcmda12_boards) / sizeof(struct pcmda12_board), + .board_name = &pcmda12_boards[0].name, + .offset = sizeof(struct pcmda12_board), + .num_names = ARRAY_SIZE(pcmda12_boards), }; -static int ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int ao_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); +static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); /* * Attach is called by the Comedi core to configure the driver @@ -151,7 +150,7 @@ static int ao_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, * in the driver structure, dev->board_ptr contains that * address. */ -static int pcmda12_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int pcmda12_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; unsigned long iobase; @@ -220,7 +219,7 @@ static int pcmda12_attach(struct comedi_device * dev, struct comedi_devconfig * * allocated by _attach(). dev->private and dev->subdevices are * deallocated automatically by the core. */ -static int pcmda12_detach(struct comedi_device * dev) +static int pcmda12_detach(struct comedi_device *dev) { printk("comedi%d: %s: remove\n", dev->minor, driver.driver_name); if (dev->iobase) @@ -228,7 +227,7 @@ static int pcmda12_detach(struct comedi_device * dev) return 0; } -static void zero_chans(struct comedi_device * dev) +static void zero_chans(struct comedi_device *dev) { /* sets up an ASIC chip to defaults */ int i; @@ -241,8 +240,8 @@ static void zero_chans(struct comedi_device * dev) inb(LSB_PORT(0)); /* update chans. */ } -static int ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i; int chan = CR_CHAN(insn->chanspec); @@ -283,8 +282,8 @@ static int ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s, DAC outputs, which makes all AO channels update simultaneously. This is useful for some control applications, I would imagine. */ -static int ao_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i; int chan = CR_CHAN(insn->chanspec); diff --git a/drivers/staging/comedi/drivers/pcmmio.c b/drivers/staging/comedi/drivers/pcmmio.c index 01e40f1b5628..cdf501afa14e 100644 --- a/drivers/staging/comedi/drivers/pcmmio.c +++ b/drivers/staging/comedi/drivers/pcmmio.c @@ -73,11 +73,11 @@ Configuration Options: [1] - IRQ (optional -- for edge-detect interrupt support only, leave out if you don't need this feature) */ +#include #include "../comedidev.h" +#include "pcm_common.h" #include /* for PCI devices */ -#define MIN(a,b) ( ((a) < (b)) ? (a) : (b) ) - /* This stuff is all from pcmuio.c -- it refers to the DIO subdevices only */ #define CHANS_PER_PORT 8 #define PORTS_PER_ASIC 6 @@ -179,19 +179,19 @@ static const struct comedi_lrange ranges_ao = static const struct pcmmio_board pcmmio_boards[] = { { - name: "pcmmio", - dio_num_asics:1, - dio_num_ports:6, - total_iosize:32, - ai_bits: 16, - ao_bits: 16, - n_ai_chans:16, - n_ao_chans:8, - ai_range_table:&ranges_ai, - ao_range_table:&ranges_ao, - ai_rinsn:ai_rinsn, - ao_rinsn:ao_rinsn, - ao_winsn:ao_winsn}, + .name = "pcmmio", + .dio_num_asics = 1, + .dio_num_ports = 6, + .total_iosize = 32, + .ai_bits = 16, + .ao_bits = 16, + .n_ai_chans = 16, + .n_ao_chans = 8, + .ai_range_table = &ranges_ai, + .ao_range_table = &ranges_ao, + .ai_rinsn = ai_rinsn, + .ao_rinsn = ao_rinsn, + .ao_winsn = ao_winsn}, }; /* @@ -264,14 +264,14 @@ struct pcmmio_private { * the board, and also about the kernel module that contains * the device code. */ -static int pcmmio_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int pcmmio_detach(struct comedi_device * dev); +static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int pcmmio_detach(struct comedi_device *dev); static struct comedi_driver driver = { - driver_name:"pcmmio", - module:THIS_MODULE, - attach:pcmmio_attach, - detach:pcmmio_detach, + .driver_name = "pcmmio", + .module = THIS_MODULE, + .attach = pcmmio_attach, + .detach = pcmmio_detach, /* It is not necessary to implement the following members if you are * writing a driver for a ISA PnP or PCI card */ /* Most drivers will support multiple types of boards by @@ -290,29 +290,29 @@ static struct comedi_driver driver = { * the type of board in software. ISA PnP, PCI, and PCMCIA * devices are such boards. */ - board_name:&pcmmio_boards[0].name, - offset:sizeof(struct pcmmio_board), - num_names:sizeof(pcmmio_boards) / sizeof(struct pcmmio_board), + .board_name = &pcmmio_boards[0].name, + .offset = sizeof(struct pcmmio_board), + .num_names = ARRAY_SIZE(pcmmio_boards), }; -static int pcmmio_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int pcmmio_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); +static int pcmmio_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int pcmmio_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); -static irqreturn_t interrupt_pcmmio(int irq, void *d PT_REGS_ARG); +static irqreturn_t interrupt_pcmmio(int irq, void *d); static void pcmmio_stop_intr(struct comedi_device *, struct comedi_subdevice *); -static int pcmmio_cancel(struct comedi_device * dev, struct comedi_subdevice * s); -static int pcmmio_cmd(struct comedi_device * dev, struct comedi_subdevice * s); -static int pcmmio_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd); +static int pcmmio_cancel(struct comedi_device *dev, struct comedi_subdevice *s); +static int pcmmio_cmd(struct comedi_device *dev, struct comedi_subdevice *s); +static int pcmmio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd); /* some helper functions to deal with specifics of this device's registers */ -static void init_asics(struct comedi_device * dev); /* sets up/clears ASIC chips to defaults */ -static void switch_page(struct comedi_device * dev, int asic, int page); +static void init_asics(struct comedi_device *dev); /* sets up/clears ASIC chips to defaults */ +static void switch_page(struct comedi_device *dev, int asic, int page); #ifdef notused -static void lock_port(struct comedi_device * dev, int asic, int port); -static void unlock_port(struct comedi_device * dev, int asic, int port); +static void lock_port(struct comedi_device *dev, int asic, int port); +static void unlock_port(struct comedi_device *dev, int asic, int port); #endif /* @@ -321,7 +321,7 @@ static void unlock_port(struct comedi_device * dev, int asic, int port); * in the driver structure, dev->board_ptr contains that * address. */ -static int pcmmio_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; int sdev_no, chans_left, n_dio_subdevs, n_subdevs, port, asic, @@ -364,7 +364,7 @@ static int pcmmio_attach(struct comedi_device * dev, struct comedi_devconfig * i dev->iobase + 16 + asic * ASIC_IOSIZE; devpriv->asics[asic].irq = 0; /* this gets actually set at the end of this function when we - comedi_request_irqs */ + request_irqs */ spin_lock_init(&devpriv->asics[asic].spinlock); } @@ -435,7 +435,7 @@ static int pcmmio_attach(struct comedi_device * dev, struct comedi_devconfig * i s->type = COMEDI_SUBD_DIO; s->insn_bits = pcmmio_dio_insn_bits; s->insn_config = pcmmio_dio_insn_config; - s->n_chan = MIN(chans_left, MAX_CHANS_PER_SUBDEV); + s->n_chan = min(chans_left, MAX_CHANS_PER_SUBDEV); subpriv->dio.intr.asic = -1; subpriv->dio.intr.first_chan = -1; subpriv->dio.intr.asic_chan = -1; @@ -489,12 +489,12 @@ static int pcmmio_attach(struct comedi_device * dev, struct comedi_devconfig * i for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) { if (irq[asic] - && comedi_request_irq(irq[asic], interrupt_pcmmio, + && request_irq(irq[asic], interrupt_pcmmio, IRQF_SHARED, thisboard->name, dev)) { int i; /* unroll the allocated irqs.. */ for (i = asic - 1; i >= 0; --i) { - comedi_free_irq(irq[i], dev); + free_irq(irq[i], dev); devpriv->asics[i].irq = irq[i] = 0; } irq[asic] = 0; @@ -526,7 +526,7 @@ static int pcmmio_attach(struct comedi_device * dev, struct comedi_devconfig * i * allocated by _attach(). dev->private and dev->subdevices are * deallocated automatically by the core. */ -static int pcmmio_detach(struct comedi_device * dev) +static int pcmmio_detach(struct comedi_device *dev) { int i; @@ -536,7 +536,7 @@ static int pcmmio_detach(struct comedi_device * dev) for (i = 0; i < MAX_ASICS; ++i) { if (devpriv && devpriv->asics[i].irq) - comedi_free_irq(devpriv->asics[i].irq, dev); + free_irq(devpriv->asics[i].irq, dev); } if (devpriv && devpriv->sprivs) @@ -550,8 +550,8 @@ static int pcmmio_detach(struct comedi_device * dev) * useful to applications if you implement the insn_bits interface. * This allows packed reading/writing of the DIO channels. The * comedi core can convert between insn_bits and insn_read/write */ -static int pcmmio_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pcmmio_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int byte_no; if (insn->n != 2) @@ -624,8 +624,8 @@ static int pcmmio_dio_insn_bits(struct comedi_device * dev, struct comedi_subdev * configured by a special insn_config instruction. chanspec * contains the channel to be changed, and data[0] contains the * value COMEDI_INPUT or COMEDI_OUTPUT. */ -static int pcmmio_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pcmmio_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int chan = CR_CHAN(insn->chanspec), byte_no = chan / 8, bit_no = chan % 8; @@ -685,7 +685,7 @@ static int pcmmio_dio_insn_config(struct comedi_device * dev, struct comedi_subd return insn->n; } -static void init_asics(struct comedi_device * dev) +static void init_asics(struct comedi_device *dev) { /* sets up an ASIC chip to defaults */ int asic; @@ -722,7 +722,7 @@ static void init_asics(struct comedi_device * dev) } } -static void switch_page(struct comedi_device * dev, int asic, int page) +static void switch_page(struct comedi_device *dev, int asic, int page) { if (asic < 0 || asic >= thisboard->dio_num_asics) return; /* paranoia */ @@ -738,7 +738,7 @@ static void switch_page(struct comedi_device * dev, int asic, int page) } #ifdef notused -static void lock_port(struct comedi_device * dev, int asic, int port) +static void lock_port(struct comedi_device *dev, int asic, int port) { if (asic < 0 || asic >= thisboard->dio_num_asics) return; /* paranoia */ @@ -752,7 +752,7 @@ static void lock_port(struct comedi_device * dev, int asic, int port) return; } -static void unlock_port(struct comedi_device * dev, int asic, int port) +static void unlock_port(struct comedi_device *dev, int asic, int port) { if (asic < 0 || asic >= thisboard->dio_num_asics) return; /* paranoia */ @@ -765,7 +765,7 @@ static void unlock_port(struct comedi_device * dev, int asic, int port) } #endif /* notused */ -static irqreturn_t interrupt_pcmmio(int irq, void *d PT_REGS_ARG) +static irqreturn_t interrupt_pcmmio(int irq, void *d) { int asic, got1 = 0; struct comedi_device *dev = (struct comedi_device *) d; @@ -778,8 +778,7 @@ static irqreturn_t interrupt_pcmmio(int irq, void *d PT_REGS_ARG) /* it is an interrupt for ASIC #asic */ unsigned char int_pend; - comedi_spin_lock_irqsave(&devpriv->asics[asic].spinlock, - flags); + spin_lock_irqsave(&devpriv->asics[asic].spinlock, flags); int_pend = inb(iobase + REG_INT_PENDING) & 0x07; @@ -811,8 +810,7 @@ static irqreturn_t interrupt_pcmmio(int irq, void *d PT_REGS_ARG) ++got1; } - comedi_spin_unlock_irqrestore(&devpriv->asics[asic]. - spinlock, flags); + spin_unlock_irqrestore(&devpriv->asics[asic]. spinlock, flags); if (triggered) { struct comedi_subdevice *s; @@ -825,9 +823,7 @@ static irqreturn_t interrupt_pcmmio(int irq, void *d PT_REGS_ARG) unsigned long flags; unsigned oldevents; - comedi_spin_lock_irqsave - (&subpriv->dio.intr. - spinlock, flags); + spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags); oldevents = s->async->events; @@ -859,10 +855,10 @@ static irqreturn_t interrupt_pcmmio(int irq, void *d PT_REGS_ARG) } } /* Write the scan to the buffer. */ - if (comedi_buf_put(s->async, ((short *) & val)[0]) + if (comedi_buf_put(s->async, ((short *) &val)[0]) && comedi_buf_put - (s->async, ((short *) & val)[1])) { + (s->async, ((short *) &val)[1])) { s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS); } else { /* Overflow! Stop acquisition!! */ @@ -896,9 +892,7 @@ static irqreturn_t interrupt_pcmmio(int irq, void *d PT_REGS_ARG) } } - comedi_spin_unlock_irqrestore - (&subpriv->dio.intr. - spinlock, flags); + spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags); if (oldevents != s->async->events) { @@ -917,11 +911,12 @@ static irqreturn_t interrupt_pcmmio(int irq, void *d PT_REGS_ARG) return IRQ_HANDLED; } -static void pcmmio_stop_intr(struct comedi_device * dev, struct comedi_subdevice * s) +static void pcmmio_stop_intr(struct comedi_device *dev, struct comedi_subdevice *s) { int nports, firstport, asic, port; - if ((asic = subpriv->dio.intr.asic) < 0) + asic = subpriv->dio.intr.asic; + if (asic < 0) return; /* not an interrupt subdev */ subpriv->dio.intr.enabled_mask = 0; @@ -936,7 +931,7 @@ static void pcmmio_stop_intr(struct comedi_device * dev, struct comedi_subdevice } } -static int pcmmio_start_intr(struct comedi_device * dev, struct comedi_subdevice * s) +static int pcmmio_start_intr(struct comedi_device *dev, struct comedi_subdevice *s) { if (!subpriv->dio.intr.continuous && subpriv->dio.intr.stop_count == 0) { /* An empty acquisition! */ @@ -948,7 +943,8 @@ static int pcmmio_start_intr(struct comedi_device * dev, struct comedi_subdevice int nports, firstport, asic, port; struct comedi_cmd *cmd = &s->async->cmd; - if ((asic = subpriv->dio.intr.asic) < 0) + asic = subpriv->dio.intr.asic; + if (asic < 0) return 1; /* not an interrupt subdev */ subpriv->dio.intr.enabled_mask = 0; @@ -995,14 +991,14 @@ static int pcmmio_start_intr(struct comedi_device * dev, struct comedi_subdevice return 0; } -static int pcmmio_cancel(struct comedi_device * dev, struct comedi_subdevice * s) +static int pcmmio_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { unsigned long flags; - comedi_spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags); + spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags); if (subpriv->dio.intr.active) pcmmio_stop_intr(dev, s); - comedi_spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags); + spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags); return 0; } @@ -1011,7 +1007,7 @@ static int pcmmio_cancel(struct comedi_device * dev, struct comedi_subdevice * s * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice. */ static int -pcmmio_inttrig_start_intr(struct comedi_device * dev, struct comedi_subdevice * s, +pcmmio_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int trignum) { unsigned long flags; @@ -1020,12 +1016,12 @@ pcmmio_inttrig_start_intr(struct comedi_device * dev, struct comedi_subdevice * if (trignum != 0) return -EINVAL; - comedi_spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags); + spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags); s->async->inttrig = 0; if (subpriv->dio.intr.active) { event = pcmmio_start_intr(dev, s); } - comedi_spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags); + spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags); if (event) { comedi_event(dev, s); @@ -1037,13 +1033,13 @@ pcmmio_inttrig_start_intr(struct comedi_device * dev, struct comedi_subdevice * /* * 'do_cmd' function for an 'INTERRUPT' subdevice. */ -static int pcmmio_cmd(struct comedi_device * dev, struct comedi_subdevice * s) +static int pcmmio_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { struct comedi_cmd *cmd = &s->async->cmd; unsigned long flags; int event = 0; - comedi_spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags); + spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags); subpriv->dio.intr.active = 1; /* Set up end of acquisition. */ @@ -1069,7 +1065,7 @@ static int pcmmio_cmd(struct comedi_device * dev, struct comedi_subdevice * s) event = pcmmio_start_intr(dev, s); break; } - comedi_spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags); + spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags); if (event) { comedi_event(dev, s); @@ -1078,110 +1074,10 @@ static int pcmmio_cmd(struct comedi_device * dev, struct comedi_subdevice * s) return 0; } -/* - * 'do_cmdtest' function for an 'INTERRUPT' subdevice. - */ static int -pcmmio_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, struct comedi_cmd * cmd) +pcmmio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - int err = 0; - unsigned int tmp; - - /* step 1: make sure trigger sources are trivially valid */ - - tmp = cmd->start_src; - cmd->start_src &= (TRIG_NOW | TRIG_INT); - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_EXT; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_NOW; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= (TRIG_COUNT | TRIG_NONE); - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; - - if (err) - return 1; - - /* step 2: make sure trigger sources are unique and mutually compatible */ - - /* these tests are true if more than one _src bit is set */ - if ((cmd->start_src & (cmd->start_src - 1)) != 0) - err++; - if ((cmd->scan_begin_src & (cmd->scan_begin_src - 1)) != 0) - err++; - if ((cmd->convert_src & (cmd->convert_src - 1)) != 0) - err++; - if ((cmd->scan_end_src & (cmd->scan_end_src - 1)) != 0) - err++; - if ((cmd->stop_src & (cmd->stop_src - 1)) != 0) - err++; - - if (err) - return 2; - - /* step 3: make sure arguments are trivially compatible */ - - /* cmd->start_src == TRIG_NOW || cmd->start_src == TRIG_INT */ - if (cmd->start_arg != 0) { - cmd->start_arg = 0; - err++; - } - - /* cmd->scan_begin_src == TRIG_EXT */ - if (cmd->scan_begin_arg != 0) { - cmd->scan_begin_arg = 0; - err++; - } - - /* cmd->convert_src == TRIG_NOW */ - if (cmd->convert_arg != 0) { - cmd->convert_arg = 0; - err++; - } - - /* cmd->scan_end_src == TRIG_COUNT */ - if (cmd->scan_end_arg != cmd->chanlist_len) { - cmd->scan_end_arg = cmd->chanlist_len; - err++; - } - - switch (cmd->stop_src) { - case TRIG_COUNT: - /* any count allowed */ - break; - case TRIG_NONE: - if (cmd->stop_arg != 0) { - cmd->stop_arg = 0; - err++; - } - break; - default: - break; - } - - if (err) - return 3; - - /* step 4: fix up any arguments */ - - /* if (err) return 4; */ - - return 0; + return comedi_pcm_cmdtest(dev, s, cmd); } static int adc_wait_ready(unsigned long iobase) @@ -1194,8 +1090,8 @@ static int adc_wait_ready(unsigned long iobase) } /* All this is for AI and AO */ -static int ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int n; unsigned long iobase = subpriv->iobase; @@ -1258,8 +1154,8 @@ static int ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, return n; } -static int ao_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int n; for (n = 0; n < insn->n; n++) { @@ -1288,8 +1184,8 @@ static int wait_dac_ready(unsigned long iobase) return 1; } -static int ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int n; unsigned iobase = subpriv->iobase, iooffset = 0; diff --git a/drivers/staging/comedi/drivers/pcmuio.c b/drivers/staging/comedi/drivers/pcmuio.c index 4e7d8b6327fd..81ee7cdc0caf 100644 --- a/drivers/staging/comedi/drivers/pcmuio.c +++ b/drivers/staging/comedi/drivers/pcmuio.c @@ -75,11 +75,12 @@ Configuration Options: [2] - IRQ for second ASIC (pcmuio96 only - IRQ for chans 48-72 .. can be the same as first irq!) */ +#include #include "../comedidev.h" +#include "pcm_common.h" #include /* for PCI devices */ -#define MIN(a,b) ( ((a) < (b)) ? (a) : (b) ) #define CHANS_PER_PORT 8 #define PORTS_PER_ASIC 6 #define INTR_PORTS_PER_ASIC 3 @@ -155,14 +156,14 @@ struct pcmuio_board { static const struct pcmuio_board pcmuio_boards[] = { { - name: "pcmuio48", - num_asics:1, - num_ports:6, + .name = "pcmuio48", + .num_asics = 1, + .num_ports = 6, }, { - name: "pcmuio96", - num_asics:2, - num_ports:12, + .name = "pcmuio96", + .num_asics = 2, + .num_ports = 12, }, }; @@ -222,14 +223,14 @@ struct pcmuio_private { * the board, and also about the kernel module that contains * the device code. */ -static int pcmuio_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int pcmuio_detach(struct comedi_device * dev); +static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int pcmuio_detach(struct comedi_device *dev); static struct comedi_driver driver = { - driver_name:"pcmuio", - module:THIS_MODULE, - attach:pcmuio_attach, - detach:pcmuio_detach, + .driver_name = "pcmuio", + .module = THIS_MODULE, + .attach = pcmuio_attach, + .detach = pcmuio_detach, /* It is not necessary to implement the following members if you are * writing a driver for a ISA PnP or PCI card */ /* Most drivers will support multiple types of boards by @@ -248,29 +249,29 @@ static struct comedi_driver driver = { * the type of board in software. ISA PnP, PCI, and PCMCIA * devices are such boards. */ - board_name:&pcmuio_boards[0].name, - offset:sizeof(struct pcmuio_board), - num_names:sizeof(pcmuio_boards) / sizeof(struct pcmuio_board), + .board_name = &pcmuio_boards[0].name, + .offset = sizeof(struct pcmuio_board), + .num_names = ARRAY_SIZE(pcmuio_boards), }; -static int pcmuio_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int pcmuio_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); +static int pcmuio_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int pcmuio_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); -static irqreturn_t interrupt_pcmuio(int irq, void *d PT_REGS_ARG); +static irqreturn_t interrupt_pcmuio(int irq, void *d); static void pcmuio_stop_intr(struct comedi_device *, struct comedi_subdevice *); -static int pcmuio_cancel(struct comedi_device * dev, struct comedi_subdevice * s); -static int pcmuio_cmd(struct comedi_device * dev, struct comedi_subdevice * s); -static int pcmuio_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd); +static int pcmuio_cancel(struct comedi_device *dev, struct comedi_subdevice *s); +static int pcmuio_cmd(struct comedi_device *dev, struct comedi_subdevice *s); +static int pcmuio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd); /* some helper functions to deal with specifics of this device's registers */ -static void init_asics(struct comedi_device * dev); /* sets up/clears ASIC chips to defaults */ -static void switch_page(struct comedi_device * dev, int asic, int page); +static void init_asics(struct comedi_device *dev); /* sets up/clears ASIC chips to defaults */ +static void switch_page(struct comedi_device *dev, int asic, int page); #ifdef notused -static void lock_port(struct comedi_device * dev, int asic, int port); -static void unlock_port(struct comedi_device * dev, int asic, int port); +static void lock_port(struct comedi_device *dev, int asic, int port); +static void unlock_port(struct comedi_device *dev, int asic, int port); #endif /* @@ -279,7 +280,7 @@ static void unlock_port(struct comedi_device * dev, int asic, int port); * in the driver structure, dev->board_ptr contains that * address. */ -static int pcmuio_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; int sdev_no, chans_left, n_subdevs, port, asic, thisasic_chanct = 0; @@ -322,7 +323,7 @@ static int pcmuio_attach(struct comedi_device * dev, struct comedi_devconfig * i devpriv->asics[asic].iobase = dev->iobase + asic * ASIC_IOSIZE; devpriv->asics[asic].irq = 0; /* this gets actually set at the end of this function when we - comedi_request_irqs */ + request_irqs */ spin_lock_init(&devpriv->asics[asic].spinlock); } @@ -359,7 +360,7 @@ static int pcmuio_attach(struct comedi_device * dev, struct comedi_devconfig * i s->type = COMEDI_SUBD_DIO; s->insn_bits = pcmuio_dio_insn_bits; s->insn_config = pcmuio_dio_insn_config; - s->n_chan = MIN(chans_left, MAX_CHANS_PER_SUBDEV); + s->n_chan = min(chans_left, MAX_CHANS_PER_SUBDEV); subpriv->intr.asic = -1; subpriv->intr.first_chan = -1; subpriv->intr.asic_chan = -1; @@ -413,12 +414,12 @@ static int pcmuio_attach(struct comedi_device * dev, struct comedi_devconfig * i for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) { if (irq[asic] - && comedi_request_irq(irq[asic], interrupt_pcmuio, + && request_irq(irq[asic], interrupt_pcmuio, IRQF_SHARED, thisboard->name, dev)) { int i; /* unroll the allocated irqs.. */ for (i = asic - 1; i >= 0; --i) { - comedi_free_irq(irq[i], dev); + free_irq(irq[i], dev); devpriv->asics[i].irq = irq[i] = 0; } irq[asic] = 0; @@ -450,7 +451,7 @@ static int pcmuio_attach(struct comedi_device * dev, struct comedi_devconfig * i * allocated by _attach(). dev->private and dev->subdevices are * deallocated automatically by the core. */ -static int pcmuio_detach(struct comedi_device * dev) +static int pcmuio_detach(struct comedi_device *dev) { int i; @@ -460,7 +461,7 @@ static int pcmuio_detach(struct comedi_device * dev) for (i = 0; i < MAX_ASICS; ++i) { if (devpriv->asics[i].irq) - comedi_free_irq(devpriv->asics[i].irq, dev); + free_irq(devpriv->asics[i].irq, dev); } if (devpriv && devpriv->sprivs) @@ -474,8 +475,8 @@ static int pcmuio_detach(struct comedi_device * dev) * useful to applications if you implement the insn_bits interface. * This allows packed reading/writing of the DIO channels. The * comedi core can convert between insn_bits and insn_read/write */ -static int pcmuio_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pcmuio_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int byte_no; if (insn->n != 2) @@ -548,8 +549,8 @@ static int pcmuio_dio_insn_bits(struct comedi_device * dev, struct comedi_subdev * configured by a special insn_config instruction. chanspec * contains the channel to be changed, and data[0] contains the * value COMEDI_INPUT or COMEDI_OUTPUT. */ -static int pcmuio_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pcmuio_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int chan = CR_CHAN(insn->chanspec), byte_no = chan / 8, bit_no = chan % 8; @@ -609,7 +610,7 @@ static int pcmuio_dio_insn_config(struct comedi_device * dev, struct comedi_subd return insn->n; } -static void init_asics(struct comedi_device * dev) +static void init_asics(struct comedi_device *dev) { /* sets up an ASIC chip to defaults */ int asic; @@ -646,7 +647,7 @@ static void init_asics(struct comedi_device * dev) } } -static void switch_page(struct comedi_device * dev, int asic, int page) +static void switch_page(struct comedi_device *dev, int asic, int page) { if (asic < 0 || asic >= thisboard->num_asics) return; /* paranoia */ @@ -662,7 +663,7 @@ static void switch_page(struct comedi_device * dev, int asic, int page) } #ifdef notused -static void lock_port(struct comedi_device * dev, int asic, int port) +static void lock_port(struct comedi_device *dev, int asic, int port) { if (asic < 0 || asic >= thisboard->num_asics) return; /* paranoia */ @@ -675,7 +676,7 @@ static void lock_port(struct comedi_device * dev, int asic, int port) dev->iobase + ASIC_IOSIZE * asic + REG_PAGELOCK); } -static void unlock_port(struct comedi_device * dev, int asic, int port) +static void unlock_port(struct comedi_device *dev, int asic, int port) { if (asic < 0 || asic >= thisboard->num_asics) return; /* paranoia */ @@ -688,7 +689,7 @@ static void unlock_port(struct comedi_device * dev, int asic, int port) } #endif /* notused */ -static irqreturn_t interrupt_pcmuio(int irq, void *d PT_REGS_ARG) +static irqreturn_t interrupt_pcmuio(int irq, void *d) { int asic, got1 = 0; struct comedi_device *dev = (struct comedi_device *) d; @@ -701,8 +702,7 @@ static irqreturn_t interrupt_pcmuio(int irq, void *d PT_REGS_ARG) /* it is an interrupt for ASIC #asic */ unsigned char int_pend; - comedi_spin_lock_irqsave(&devpriv->asics[asic].spinlock, - flags); + spin_lock_irqsave(&devpriv->asics[asic].spinlock, flags); int_pend = inb(iobase + REG_INT_PENDING) & 0x07; @@ -734,8 +734,7 @@ static irqreturn_t interrupt_pcmuio(int irq, void *d PT_REGS_ARG) ++got1; } - comedi_spin_unlock_irqrestore(&devpriv->asics[asic]. - spinlock, flags); + spin_unlock_irqrestore(&devpriv->asics[asic].spinlock, flags); if (triggered) { struct comedi_subdevice *s; @@ -748,9 +747,7 @@ static irqreturn_t interrupt_pcmuio(int irq, void *d PT_REGS_ARG) unsigned long flags; unsigned oldevents; - comedi_spin_lock_irqsave - (&subpriv->intr. - spinlock, flags); + spin_lock_irqsave (&subpriv->intr.spinlock, flags); oldevents = s->async->events; @@ -781,10 +778,10 @@ static irqreturn_t interrupt_pcmuio(int irq, void *d PT_REGS_ARG) } } /* Write the scan to the buffer. */ - if (comedi_buf_put(s->async, ((short *) & val)[0]) + if (comedi_buf_put(s->async, ((short *) &val)[0]) && comedi_buf_put - (s->async, ((short *) & val)[1])) { + (s->async, ((short *) &val)[1])) { s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS); } else { /* Overflow! Stop acquisition!! */ @@ -816,9 +813,7 @@ static irqreturn_t interrupt_pcmuio(int irq, void *d PT_REGS_ARG) } } - comedi_spin_unlock_irqrestore - (&subpriv->intr. - spinlock, flags); + spin_unlock_irqrestore(&subpriv->intr.spinlock, flags); if (oldevents != s->async->events) { @@ -837,11 +832,12 @@ static irqreturn_t interrupt_pcmuio(int irq, void *d PT_REGS_ARG) return IRQ_HANDLED; } -static void pcmuio_stop_intr(struct comedi_device * dev, struct comedi_subdevice * s) +static void pcmuio_stop_intr(struct comedi_device *dev, struct comedi_subdevice *s) { int nports, firstport, asic, port; - if ((asic = subpriv->intr.asic) < 0) + asic = subpriv->intr.asic; + if (asic < 0) return; /* not an interrupt subdev */ subpriv->intr.enabled_mask = 0; @@ -856,7 +852,7 @@ static void pcmuio_stop_intr(struct comedi_device * dev, struct comedi_subdevice } } -static int pcmuio_start_intr(struct comedi_device * dev, struct comedi_subdevice * s) +static int pcmuio_start_intr(struct comedi_device *dev, struct comedi_subdevice *s) { if (!subpriv->intr.continuous && subpriv->intr.stop_count == 0) { /* An empty acquisition! */ @@ -868,7 +864,8 @@ static int pcmuio_start_intr(struct comedi_device * dev, struct comedi_subdevice int nports, firstport, asic, port; struct comedi_cmd *cmd = &s->async->cmd; - if ((asic = subpriv->intr.asic) < 0) + asic = subpriv->intr.asic; + if (asic < 0) return 1; /* not an interrupt subdev */ subpriv->intr.enabled_mask = 0; @@ -905,14 +902,14 @@ static int pcmuio_start_intr(struct comedi_device * dev, struct comedi_subdevice return 0; } -static int pcmuio_cancel(struct comedi_device * dev, struct comedi_subdevice * s) +static int pcmuio_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { unsigned long flags; - comedi_spin_lock_irqsave(&subpriv->intr.spinlock, flags); + spin_lock_irqsave(&subpriv->intr.spinlock, flags); if (subpriv->intr.active) pcmuio_stop_intr(dev, s); - comedi_spin_unlock_irqrestore(&subpriv->intr.spinlock, flags); + spin_unlock_irqrestore(&subpriv->intr.spinlock, flags); return 0; } @@ -921,7 +918,7 @@ static int pcmuio_cancel(struct comedi_device * dev, struct comedi_subdevice * s * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice. */ static int -pcmuio_inttrig_start_intr(struct comedi_device * dev, struct comedi_subdevice * s, +pcmuio_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int trignum) { unsigned long flags; @@ -930,12 +927,12 @@ pcmuio_inttrig_start_intr(struct comedi_device * dev, struct comedi_subdevice * if (trignum != 0) return -EINVAL; - comedi_spin_lock_irqsave(&subpriv->intr.spinlock, flags); + spin_lock_irqsave(&subpriv->intr.spinlock, flags); s->async->inttrig = 0; if (subpriv->intr.active) { event = pcmuio_start_intr(dev, s); } - comedi_spin_unlock_irqrestore(&subpriv->intr.spinlock, flags); + spin_unlock_irqrestore(&subpriv->intr.spinlock, flags); if (event) { comedi_event(dev, s); @@ -947,13 +944,13 @@ pcmuio_inttrig_start_intr(struct comedi_device * dev, struct comedi_subdevice * /* * 'do_cmd' function for an 'INTERRUPT' subdevice. */ -static int pcmuio_cmd(struct comedi_device * dev, struct comedi_subdevice * s) +static int pcmuio_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { struct comedi_cmd *cmd = &s->async->cmd; unsigned long flags; int event = 0; - comedi_spin_lock_irqsave(&subpriv->intr.spinlock, flags); + spin_lock_irqsave(&subpriv->intr.spinlock, flags); subpriv->intr.active = 1; /* Set up end of acquisition. */ @@ -979,7 +976,7 @@ static int pcmuio_cmd(struct comedi_device * dev, struct comedi_subdevice * s) event = pcmuio_start_intr(dev, s); break; } - comedi_spin_unlock_irqrestore(&subpriv->intr.spinlock, flags); + spin_unlock_irqrestore(&subpriv->intr.spinlock, flags); if (event) { comedi_event(dev, s); @@ -988,110 +985,10 @@ static int pcmuio_cmd(struct comedi_device * dev, struct comedi_subdevice * s) return 0; } -/* - * 'do_cmdtest' function for an 'INTERRUPT' subdevice. - */ static int -pcmuio_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, struct comedi_cmd * cmd) +pcmuio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - int err = 0; - unsigned int tmp; - - /* step 1: make sure trigger sources are trivially valid */ - - tmp = cmd->start_src; - cmd->start_src &= (TRIG_NOW | TRIG_INT); - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_EXT; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_NOW; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= (TRIG_COUNT | TRIG_NONE); - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; - - if (err) - return 1; - - /* step 2: make sure trigger sources are unique and mutually compatible */ - - /* these tests are true if more than one _src bit is set */ - if ((cmd->start_src & (cmd->start_src - 1)) != 0) - err++; - if ((cmd->scan_begin_src & (cmd->scan_begin_src - 1)) != 0) - err++; - if ((cmd->convert_src & (cmd->convert_src - 1)) != 0) - err++; - if ((cmd->scan_end_src & (cmd->scan_end_src - 1)) != 0) - err++; - if ((cmd->stop_src & (cmd->stop_src - 1)) != 0) - err++; - - if (err) - return 2; - - /* step 3: make sure arguments are trivially compatible */ - - /* cmd->start_src == TRIG_NOW || cmd->start_src == TRIG_INT */ - if (cmd->start_arg != 0) { - cmd->start_arg = 0; - err++; - } - - /* cmd->scan_begin_src == TRIG_EXT */ - if (cmd->scan_begin_arg != 0) { - cmd->scan_begin_arg = 0; - err++; - } - - /* cmd->convert_src == TRIG_NOW */ - if (cmd->convert_arg != 0) { - cmd->convert_arg = 0; - err++; - } - - /* cmd->scan_end_src == TRIG_COUNT */ - if (cmd->scan_end_arg != cmd->chanlist_len) { - cmd->scan_end_arg = cmd->chanlist_len; - err++; - } - - switch (cmd->stop_src) { - case TRIG_COUNT: - /* any count allowed */ - break; - case TRIG_NONE: - if (cmd->stop_arg != 0) { - cmd->stop_arg = 0; - err++; - } - break; - default: - break; - } - - if (err) - return 3; - - /* step 4: fix up any arguments */ - - /* if (err) return 4; */ - - return 0; + return comedi_pcm_cmdtest(dev, s, cmd); } /* diff --git a/drivers/staging/comedi/drivers/plx9080.h b/drivers/staging/comedi/drivers/plx9080.h index 9231ba802030..e4bbd5dc9a61 100644 --- a/drivers/staging/comedi/drivers/plx9080.h +++ b/drivers/staging/comedi/drivers/plx9080.h @@ -399,11 +399,11 @@ static inline int plx9080_abort_dma(void *iobase, unsigned int channel) /* wait to make sure done bit is zero */ for (i = 0; (dma_status & PLX_DMA_DONE_BIT) && i < timeout; i++) { - comedi_udelay(1); + udelay(1); dma_status = readb(dma_cs_addr); } if (i == timeout) { - rt_printk + printk ("plx9080: cancel() timed out waiting for dma %i done clear\n", channel); return -ETIMEDOUT; @@ -413,11 +413,11 @@ static inline int plx9080_abort_dma(void *iobase, unsigned int channel) /* wait for dma done bit */ dma_status = readb(dma_cs_addr); for (i = 0; (dma_status & PLX_DMA_DONE_BIT) == 0 && i < timeout; i++) { - comedi_udelay(1); + udelay(1); dma_status = readb(dma_cs_addr); } if (i == timeout) { - rt_printk + printk ("plx9080: cancel() timed out waiting for dma %i done set\n", channel); return -ETIMEDOUT; diff --git a/drivers/staging/comedi/drivers/poc.c b/drivers/staging/comedi/drivers/poc.c index 8a0bf6854939..47850bd15484 100644 --- a/drivers/staging/comedi/drivers/poc.c +++ b/drivers/staging/comedi/drivers/poc.c @@ -41,17 +41,17 @@ Configuration options: #include -static int poc_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int poc_detach(struct comedi_device * dev); -static int readback_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); +static int poc_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int poc_detach(struct comedi_device *dev); +static int readback_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); -static int dac02_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int pcl733_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int pcl734_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); +static int dac02_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int pcl733_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int pcl734_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); struct boarddef_struct { const char *name; @@ -70,33 +70,33 @@ struct boarddef_struct { }; static const struct boarddef_struct boards[] = { { - name: "dac02", - iosize: 8, - //setup: dac02_setup, - type: COMEDI_SUBD_AO, - n_chan: 2, - n_bits: 12, - winsn: dac02_ao_winsn, - rinsn: readback_insn, - range: &range_unknown, + .name = "dac02", + .iosize = 8, + /* .setup = dac02_setup, */ + .type = COMEDI_SUBD_AO, + .n_chan = 2, + .n_bits = 12, + .winsn = dac02_ao_winsn, + .rinsn = readback_insn, + .range = &range_unknown, }, { - name: "pcl733", - iosize: 4, - type: COMEDI_SUBD_DI, - n_chan: 32, - n_bits: 1, - insnbits:pcl733_insn_bits, - range: &range_digital, + .name = "pcl733", + .iosize = 4, + .type = COMEDI_SUBD_DI, + .n_chan = 32, + .n_bits = 1, + .insnbits = pcl733_insn_bits, + .range = &range_digital, }, { - name: "pcl734", - iosize: 4, - type: COMEDI_SUBD_DO, - n_chan: 32, - n_bits: 1, - insnbits:pcl734_insn_bits, - range: &range_digital, + .name = "pcl734", + .iosize = 4, + .type = COMEDI_SUBD_DO, + .n_chan = 32, + .n_bits = 1, + .insnbits = pcl734_insn_bits, + .range = &range_digital, }, }; @@ -104,16 +104,16 @@ static const struct boarddef_struct boards[] = { #define this_board ((const struct boarddef_struct *)dev->board_ptr) static struct comedi_driver driver_poc = { - driver_name:"poc", - module:THIS_MODULE, - attach:poc_attach, - detach:poc_detach, - board_name:&boards[0].name, - num_names:n_boards, - offset:sizeof(boards[0]), + .driver_name = "poc", + .module = THIS_MODULE, + .attach = poc_attach, + .detach = poc_detach, + .board_name = &boards[0].name, + .num_names = n_boards, + .offset = sizeof(boards[0]), }; -static int poc_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int poc_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; unsigned long iobase; @@ -159,7 +159,7 @@ static int poc_attach(struct comedi_device * dev, struct comedi_devconfig * it) return 0; } -static int poc_detach(struct comedi_device * dev) +static int poc_detach(struct comedi_device *dev) { /* only free stuff if it has been allocated by _attach */ if (dev->iobase) @@ -170,8 +170,8 @@ static int poc_detach(struct comedi_device * dev) return 0; } -static int readback_insn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int readback_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int chan; @@ -185,8 +185,8 @@ static int readback_insn(struct comedi_device * dev, struct comedi_subdevice * s #define DAC02_LSB(a) (2 * a) #define DAC02_MSB(a) (2 * a + 1) -static int dac02_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int dac02_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int temp; int chan; @@ -196,7 +196,7 @@ static int dac02_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * ((unsigned int *) dev->private)[chan] = data[0]; output = data[0]; #ifdef wrong - // convert to complementary binary if range is bipolar + /* convert to complementary binary if range is bipolar */ if ((CR_RANGE(insn->chanspec) & 0x2) == 0) output = ~output; #endif @@ -208,8 +208,8 @@ static int dac02_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * return 1; } -static int pcl733_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pcl733_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if (insn->n != 2) return -EINVAL; @@ -222,8 +222,8 @@ static int pcl733_insn_bits(struct comedi_device * dev, struct comedi_subdevice return 2; } -static int pcl734_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int pcl734_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if (insn->n != 2) return -EINVAL; diff --git a/drivers/staging/comedi/drivers/quatech_daqp_cs.c b/drivers/staging/comedi/drivers/quatech_daqp_cs.c index 795c4522867f..85b53c93e135 100644 --- a/drivers/staging/comedi/drivers/quatech_daqp_cs.c +++ b/drivers/staging/comedi/drivers/quatech_daqp_cs.c @@ -179,8 +179,8 @@ static struct local_info_t *dev_table[MAX_DEV] = { NULL, /* ... */ }; #define DAQP_AUX_FIFO_EMPTY 0x01 /* These range structures tell COMEDI how the sample values map to - * voltages. The A/D converter has four ranges: +/- 10V through - * +/- 1.25V, and the D/A converter has only one: +/- 5V. + * voltages. The A/D converter has four .ranges = +/- 10V through + * +/- 1.25V, and the D/A converter has only .one = +/- 5V. */ static const struct comedi_lrange range_daqp_ai = { 4, { @@ -197,18 +197,18 @@ static const struct comedi_lrange range_daqp_ao = { 1, {BIP_RANGE(5)} }; /* comedi interface code */ -static int daqp_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int daqp_detach(struct comedi_device * dev); +static int daqp_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int daqp_detach(struct comedi_device *dev); static struct comedi_driver driver_daqp = { - driver_name:"quatech_daqp_cs", - module:THIS_MODULE, - attach:daqp_attach, - detach:daqp_detach, + .driver_name = "quatech_daqp_cs", + .module = THIS_MODULE, + .attach = daqp_attach, + .detach = daqp_detach, }; #ifdef DAQP_DEBUG -static void daqp_dump(struct comedi_device * dev) +static void daqp_dump(struct comedi_device *dev) { printk("DAQP: status %02x; aux status %02x\n", inb(dev->iobase + DAQP_STATUS), inb(dev->iobase + DAQP_AUX)); @@ -234,7 +234,7 @@ static void hex_dump(char *str, void *ptr, int len) /* Cancel a running acquisition */ -static int daqp_ai_cancel(struct comedi_device * dev, struct comedi_subdevice * s) +static int daqp_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { struct local_info_t *local = (struct local_info_t *) s->private; @@ -262,7 +262,7 @@ static int daqp_ai_cancel(struct comedi_device * dev, struct comedi_subdevice * * which run pretty quick. */ -static void daqp_interrupt(int irq, void *dev_id PT_REGS_ARG) +static void daqp_interrupt(int irq, void *dev_id) { struct local_info_t *local = (struct local_info_t *) dev_id; struct comedi_device *dev; @@ -361,8 +361,8 @@ static void daqp_interrupt(int irq, void *dev_id PT_REGS_ARG) /* One-shot analog data acquisition routine */ -static int daqp_ai_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int daqp_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { struct local_info_t *local = (struct local_info_t *) s->private; int i; @@ -467,8 +467,8 @@ static int daqp_ns_to_timer(unsigned int *ns, int round) * the command passes. */ -static int daqp_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd) +static int daqp_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd) { int err = 0; int tmp; @@ -593,7 +593,7 @@ static int daqp_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * return 0; } -static int daqp_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s) +static int daqp_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { struct local_info_t *local = (struct local_info_t *) s->private; struct comedi_cmd *cmd = &s->async->cmd; @@ -793,8 +793,8 @@ static int daqp_ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s) /* Single-shot analog output routine */ -static int daqp_ao_insn_write(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int daqp_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { struct local_info_t *local = (struct local_info_t *) s->private; int d; @@ -820,8 +820,8 @@ static int daqp_ao_insn_write(struct comedi_device * dev, struct comedi_subdevic /* Digital input routine */ -static int daqp_di_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int daqp_di_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { struct local_info_t *local = (struct local_info_t *) s->private; @@ -836,8 +836,8 @@ static int daqp_di_insn_read(struct comedi_device * dev, struct comedi_subdevice /* Digital output routine */ -static int daqp_do_insn_write(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int daqp_do_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { struct local_info_t *local = (struct local_info_t *) s->private; @@ -856,7 +856,7 @@ static int daqp_do_insn_write(struct comedi_device * dev, struct comedi_subdevic * when it is inserted. */ -static int daqp_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int daqp_attach(struct comedi_device *dev, struct comedi_devconfig *it) { int ret; struct local_info_t *local = dev_table[it->options[0]]; @@ -908,7 +908,8 @@ static int daqp_attach(struct comedi_device * dev, struct comedi_devconfig * it) dev->iobase = local->link->io.BasePort1; - if ((ret = alloc_subdevices(dev, 4)) < 0) + ret = alloc_subdevices(dev, 4); + if (ret < 0) return ret; printk("comedi%d: attaching daqp%d (io 0x%04lx)\n", @@ -962,7 +963,7 @@ static int daqp_attach(struct comedi_device * dev, struct comedi_devconfig * it) * card is removed, daqp_cs_detach() is called by the pcmcia subsystem. */ -static int daqp_detach(struct comedi_device * dev) +static int daqp_detach(struct comedi_device *dev) { printk("comedi%d: detaching daqp\n", dev->minor); @@ -1149,15 +1150,21 @@ static void daqp_cs_config(struct pcmcia_device *link) tuple.TupleData = buf; tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; - if ((last_ret = pcmcia_get_first_tuple(link, &tuple))) { + + last_ret = pcmcia_get_first_tuple(link, &tuple); + if (last_ret) { cs_error(link, GetFirstTuple, last_ret); goto cs_failed; } - if ((last_ret = pcmcia_get_tuple_data(link, &tuple))) { + + last_ret = pcmcia_get_tuple_data(link, &tuple); + if (last_ret) { cs_error(link, GetTupleData, last_ret); goto cs_failed; } - if ((last_ret = pcmcia_parse_tuple(&tuple, &parse))) { + + last_ret = pcmcia_parse_tuple(&tuple, &parse); + if (last_ret) { cs_error(link, ParseTuple, last_ret); goto cs_failed; } @@ -1177,10 +1184,12 @@ static void daqp_cs_config(struct pcmcia_device *link) will only use the CIS to fill in implementation-defined details. */ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - if ((last_ret = pcmcia_get_first_tuple(link, &tuple))) { + last_ret = pcmcia_get_first_tuple(link, &tuple); + if (last_ret) { cs_error(link, GetFirstTuple, last_ret); goto cs_failed; } + while (1) { cistpl_cftable_entry_t dflt = { 0 }; cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); @@ -1226,7 +1235,8 @@ static void daqp_cs_config(struct pcmcia_device *link) break; next_entry: - if ((last_ret = pcmcia_get_next_tuple(link, &tuple))) { + last_ret = pcmcia_get_next_tuple(link, &tuple); + if (last_ret) { cs_error(link, GetNextTuple, last_ret); goto cs_failed; } @@ -1237,18 +1247,21 @@ static void daqp_cs_config(struct pcmcia_device *link) handler to the interrupt, unless the 'Handler' member of the irq structure is initialized. */ - if (link->conf.Attributes & CONF_ENABLE_IRQ) - if ((last_ret = pcmcia_request_irq(link, &link->irq))) { + if (link->conf.Attributes & CONF_ENABLE_IRQ) { + last_ret = pcmcia_request_irq(link, &link->irq); + if (last_ret) { cs_error(link, RequestIRQ, last_ret); goto cs_failed; } + } /* This actually configures the PCMCIA socket -- setting up the I/O windows and the interrupt mapping, and putting the card and host interface into "Memory and IO" mode. */ - if ((last_ret = pcmcia_request_configuration(link, &link->conf))) { + last_ret = pcmcia_request_configuration(link, &link->conf); + if (last_ret) { cs_error(link, RequestConfiguration, last_ret); goto cs_failed; } diff --git a/drivers/staging/comedi/drivers/rtd520.c b/drivers/staging/comedi/drivers/rtd520.c index ca347f21d140..243ee76c836d 100644 --- a/drivers/staging/comedi/drivers/rtd520.c +++ b/drivers/staging/comedi/drivers/rtd520.c @@ -101,6 +101,7 @@ Configuration options: */ +#include #include #include "../comedidev.h" @@ -135,7 +136,7 @@ Configuration options: #define RTD_DMA_TIMEOUT 33000 /* 1 msec */ #else /* by delaying, power and electrical noise are reduced somewhat */ -#define WAIT_QUIETLY comedi_udelay (1) +#define WAIT_QUIETLY udelay (1) #define RTD_ADC_TIMEOUT 2000 /* in usec */ #define RTD_DAC_TIMEOUT 2000 /* in usec */ #define RTD_DMA_TIMEOUT 1000 /* in usec */ @@ -278,22 +279,22 @@ struct rtdBoard { static const struct rtdBoard rtd520Boards[] = { { - name: "DM7520", - device_id : 0x7520, - aiChans: 16, - aiBits: 12, - aiMaxGain:32, - range10Start:6, - rangeUniStart:12, + .name = "DM7520", + .device_id = 0x7520, + .aiChans = 16, + .aiBits = 12, + .aiMaxGain = 32, + .range10Start = 6, + .rangeUniStart = 12, }, { - name: "PCI4520", - device_id : 0x4520, - aiChans: 16, - aiBits: 12, - aiMaxGain:128, - range10Start:8, - rangeUniStart:16, + .name = "PCI4520", + .device_id = 0x4520, + .aiChans = 16, + .aiBits = 12, + .aiMaxGain = 128, + .range10Start = 8, + .rangeUniStart = 16, }, }; @@ -684,10 +685,10 @@ static int rtd_attach(struct comedi_device *dev, struct comedi_devconfig *it); static int rtd_detach(struct comedi_device *dev); static struct comedi_driver rtd520Driver = { - driver_name: DRV_NAME, - module : THIS_MODULE, - attach : rtd_attach, - detach : rtd_detach, + .driver_name = DRV_NAME, + .module = THIS_MODULE, + .attach = rtd_attach, + .detach = rtd_detach, }; static int rtd_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, @@ -706,7 +707,7 @@ static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s); static int rtd_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s); /* static int rtd_ai_poll (struct comedi_device *dev,struct comedi_subdevice *s); */ static int rtd_ns_to_timer(unsigned int *ns, int roundMode); -static irqreturn_t rtd_interrupt(int irq, void *d PT_REGS_ARG); +static irqreturn_t rtd_interrupt(int irq, void *d); static int rtd520_probe_fifo_depth(struct comedi_device *dev); /* @@ -757,15 +758,15 @@ static int rtd_attach(struct comedi_device *dev, struct comedi_devconfig *it) continue; } } - for(i = 0; i < sizeof(rtd520Boards) / sizeof(rtd520Boards[0]); ++i) + for (i = 0; i < ARRAY_SIZE(rtd520Boards); ++i) { - if(pcidev->device == rtd520Boards[i].device_id) + if (pcidev->device == rtd520Boards[i].device_id) { dev->board_ptr = &rtd520Boards[i]; break; } } - if(dev->board_ptr) break; /* found one */ + if (dev->board_ptr) break; /* found one */ } if (!pcidev) { if (it->options[0] && it->options[1]) { @@ -900,7 +901,7 @@ static int rtd_attach(struct comedi_device *dev, struct comedi_devconfig *it) /* initialize board, per RTD spec */ /* also, initialize shadow registers */ RtdResetBoard(dev); - comedi_udelay(100); /* needed? */ + udelay(100); /* needed? */ RtdPlxInterruptWrite(dev, 0); RtdInterruptMask(dev, 0); /* and sets shadow */ RtdInterruptClearMask(dev, ~0); /* and sets shadow */ @@ -919,7 +920,7 @@ static int rtd_attach(struct comedi_device *dev, struct comedi_devconfig *it) /* TODO: set user out source ??? */ /* check if our interrupt is available and get it */ - ret = comedi_request_irq(devpriv->pci_dev->irq, rtd_interrupt, + ret = request_irq(devpriv->pci_dev->irq, rtd_interrupt, IRQF_SHARED, DRV_NAME, dev); if (ret < 0) { @@ -931,7 +932,7 @@ static int rtd_attach(struct comedi_device *dev, struct comedi_devconfig *it) printk("( irq=%u )", dev->irq); ret = rtd520_probe_fifo_depth(dev); - if(ret < 0) { + if (ret < 0) { return ret; } devpriv->fifoLen = ret; @@ -1032,7 +1033,7 @@ static int rtd_attach(struct comedi_device *dev, struct comedi_devconfig *it) /* disable interrupt controller */ RtdPlxInterruptWrite(dev, RtdPlxInterruptRead(dev) & ~(ICS_PLIE | ICS_DMA0_E | ICS_DMA1_E)); - comedi_free_irq(dev->irq, dev); + free_irq(dev->irq, dev); } /* release all regions that were allocated */ @@ -1111,7 +1112,7 @@ static int rtd_detach(struct comedi_device *dev) /* disable interrupt controller */ RtdPlxInterruptWrite(dev, RtdPlxInterruptRead(dev) & ~(ICS_PLIE | ICS_DMA0_E | ICS_DMA1_E)); - comedi_free_irq(dev->irq, dev); + free_irq(dev->irq, dev); } /* release all regions that were allocated */ @@ -1224,22 +1225,22 @@ static int rtd520_probe_fifo_depth(struct comedi_device *dev) unsigned fifo_status; /* trigger conversion */ RtdAdcStart(dev); - comedi_udelay(1); + udelay(1); fifo_status = RtdFifoStatus(dev); - if((fifo_status & FS_ADC_HEMPTY) == 0) { + if ((fifo_status & FS_ADC_HEMPTY) == 0) { fifo_size = 2 * i; break; } } - if(i == limit) + if (i == limit) { - rt_printk("\ncomedi: %s: failed to probe fifo size.\n", DRV_NAME); + printk("\ncomedi: %s: failed to probe fifo size.\n", DRV_NAME); return -EIO; } RtdAdcClearFifo(dev); - if(fifo_size != 0x400 && fifo_size != 0x2000) + if (fifo_size != 0x400 && fifo_size != 0x2000) { - rt_printk("\ncomedi: %s: unexpected fifo size of %i, expected 1024 or 8192.\n", + printk("\ncomedi: %s: unexpected fifo size of %i, expected 1024 or 8192.\n", DRV_NAME, fifo_size); return -EIO; } @@ -1386,7 +1387,7 @@ void abort_dma(struct comedi_device *dev, unsigned int channel) + ((channel == 0) ? LCFG_DMACSR0 : LCFG_DMACSR1); /* spinlock for plx dma control/status reg */ - /* comedi_spin_lock_irqsave( &dev->spinlock, flags ); */ + /* spin_lock_irqsave( &dev->spinlock, flags ); */ /* abort dma transfer if necessary */ status = readb(dma_cs_addr); @@ -1409,7 +1410,7 @@ void abort_dma(struct comedi_device *dev, unsigned int channel) /* disable channel (required) */ writeb(0, dma_cs_addr); - comedi_udelay(1); /* needed?? */ + udelay(1); /* needed?? */ /* set abort bit for channel */ writeb(PLX_DMA_ABORT_BIT, dma_cs_addr); @@ -1427,7 +1428,7 @@ void abort_dma(struct comedi_device *dev, unsigned int channel) } abortDmaExit: - /* comedi_spin_unlock_irqrestore( &dev->spinlock, flags ); */ + /* spin_unlock_irqrestore( &dev->spinlock, flags ); */ } /* @@ -1494,8 +1495,7 @@ static int ai_process_dma(struct comedi_device *dev, struct comedi_subdevice *s) The data conversion may someday happen in a "bottom half". */ static irqreturn_t rtd_interrupt(int irq, /* interrupt number (ignored) */ - void *d /* our data */ - PT_REGS_ARG) + void *d) /* our data */ { /* cpu context (ignored) */ struct comedi_device *dev = d; /* must be called "dev" for devpriv */ u16 status; diff --git a/drivers/staging/comedi/drivers/rti800.c b/drivers/staging/comedi/drivers/rti800.c index 334ac5773a13..f1b7e0252f13 100644 --- a/drivers/staging/comedi/drivers/rti800.c +++ b/drivers/staging/comedi/drivers/rti800.c @@ -52,6 +52,7 @@ Configuration options: [8] - DAC 1 encoding (same as DAC 0) */ +#include #include "../comedidev.h" #include @@ -89,8 +90,8 @@ Configuration options: #define Am9513_8BITBUS -#define Am9513_output_control(a) outb(a,dev->iobase+RTI800_9513A_CNTRL) -#define Am9513_output_data(a) outb(a,dev->iobase+RTI800_9513A_DATA) +#define Am9513_output_control(a) outb(a, dev->iobase+RTI800_9513A_CNTRL) +#define Am9513_output_data(a) outb(a, dev->iobase+RTI800_9513A_DATA) #define Am9513_input_data() inb(dev->iobase+RTI800_9513A_DATA) #define Am9513_input_status() inb(dev->iobase+RTI800_9513A_STATUS) @@ -131,21 +132,21 @@ static const struct rti800_board boardtypes[] = { #define this_board ((const struct rti800_board *)dev->board_ptr) -static int rti800_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int rti800_detach(struct comedi_device * dev); +static int rti800_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int rti800_detach(struct comedi_device *dev); static struct comedi_driver driver_rti800 = { - driver_name:"rti800", - module:THIS_MODULE, - attach:rti800_attach, - detach:rti800_detach, - num_names:sizeof(boardtypes) / sizeof(struct rti800_board), - board_name:&boardtypes[0].name, - offset:sizeof(struct rti800_board), + .driver_name = "rti800", + .module = THIS_MODULE, + .attach = rti800_attach, + .detach = rti800_detach, + .num_names = ARRAY_SIZE(boardtypes), + .board_name = &boardtypes[0].name, + .offset = sizeof(struct rti800_board), }; COMEDI_INITCLEANUP(driver_rti800); -static irqreturn_t rti800_interrupt(int irq, void *dev PT_REGS_ARG); +static irqreturn_t rti800_interrupt(int irq, void *dev); struct rti800_private { enum { @@ -172,16 +173,16 @@ struct rti800_private { #define RTI800_TIMEOUT 100 -static irqreturn_t rti800_interrupt(int irq, void *dev PT_REGS_ARG) +static irqreturn_t rti800_interrupt(int irq, void *dev) { return IRQ_HANDLED; } -// settling delay times in usec for different gains +/* settling delay times in usec for different gains */ static const int gaindelay[] = { 10, 20, 40, 80 }; -static int rti800_ai_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int rti800_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i, t; int status; @@ -199,9 +200,8 @@ static int rti800_ai_insn_read(struct comedi_device * dev, struct comedi_subdevi /* without a delay here, the RTI_OVERRUN bit * gets set, and you will have an error. */ if (insn->n > 0) { - BUG_ON(gain >= - sizeof(gaindelay) / sizeof(gaindelay[0])); - comedi_udelay(gaindelay[gain]); + BUG_ON(gain >= ARRAY_SIZE(gaindelay)); + udelay(gaindelay[gain]); } } @@ -210,16 +210,16 @@ static int rti800_ai_insn_read(struct comedi_device * dev, struct comedi_subdevi for (t = RTI800_TIMEOUT; t; t--) { status = inb(dev->iobase + RTI800_CSR); if (status & RTI800_OVERRUN) { - rt_printk("rti800: a/d overrun\n"); + printk("rti800: a/d overrun\n"); outb(0, dev->iobase + RTI800_CLRFLAGS); return -EIO; } if (status & RTI800_DONE) break; - comedi_udelay(1); + udelay(1); } if (t == 0) { - rt_printk("rti800: timeout\n"); + printk("rti800: timeout\n"); return -ETIME; } data[i] = inb(dev->iobase + RTI800_ADCLO); @@ -233,8 +233,8 @@ static int rti800_ai_insn_read(struct comedi_device * dev, struct comedi_subdevi return i; } -static int rti800_ao_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int rti800_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i; int chan = CR_CHAN(insn->chanspec); @@ -245,8 +245,8 @@ static int rti800_ao_insn_read(struct comedi_device * dev, struct comedi_subdevi return i; } -static int rti800_ao_insn_write(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int rti800_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int chan = CR_CHAN(insn->chanspec); int d; @@ -265,8 +265,8 @@ static int rti800_ao_insn_write(struct comedi_device * dev, struct comedi_subdev return i; } -static int rti800_di_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int rti800_di_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if (insn->n != 2) return -EINVAL; @@ -274,8 +274,8 @@ static int rti800_di_insn_bits(struct comedi_device * dev, struct comedi_subdevi return 2; } -static int rti800_do_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int rti800_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if (insn->n != 2) return -EINVAL; @@ -309,7 +309,7 @@ static int rti800_do_insn_bits(struct comedi_device * dev, struct comedi_subdevi options[8] - dac1 coding */ -static int rti800_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int rti800_attach(struct comedi_device *dev, struct comedi_devconfig *it) { unsigned int irq; unsigned long iobase; @@ -339,8 +339,8 @@ static int rti800_attach(struct comedi_device * dev, struct comedi_devconfig * i irq = it->options[1]; if (irq) { printk("( irq = %u )", irq); - if ((ret = comedi_request_irq(irq, rti800_interrupt, 0, - "rti800", dev)) < 0) { + ret = request_irq(irq, rti800_interrupt, 0, "rti800", dev); + if (ret < 0) { printk(" Failed to allocate IRQ\n"); return ret; } @@ -351,9 +351,12 @@ static int rti800_attach(struct comedi_device * dev, struct comedi_devconfig * i dev->board_name = this_board->name; - if ((ret = alloc_subdevices(dev, 4)) < 0) + ret = alloc_subdevices(dev, 4); + if (ret < 0) return ret; - if ((ret = alloc_private(dev, sizeof(struct rti800_private))) < 0) + + ret = alloc_private(dev, sizeof(struct rti800_private)); + if (ret < 0) return ret; devpriv->adc_mux = it->options[2]; @@ -444,7 +447,7 @@ static int rti800_attach(struct comedi_device * dev, struct comedi_devconfig * i return 0; } -static int rti800_detach(struct comedi_device * dev) +static int rti800_detach(struct comedi_device *dev) { printk("comedi%d: rti800: remove\n", dev->minor); @@ -452,7 +455,7 @@ static int rti800_detach(struct comedi_device * dev) release_region(dev->iobase, RTI800_SIZE); if (dev->irq) - comedi_free_irq(dev->irq, dev); + free_irq(dev->irq, dev); return 0; } diff --git a/drivers/staging/comedi/drivers/rti802.c b/drivers/staging/comedi/drivers/rti802.c index cc2c385db0b0..fffde45a352b 100644 --- a/drivers/staging/comedi/drivers/rti802.c +++ b/drivers/staging/comedi/drivers/rti802.c @@ -47,13 +47,13 @@ Configuration Options: #define RTI802_DATALOW 1 #define RTI802_DATAHIGH 2 -static int rti802_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int rti802_detach(struct comedi_device * dev); +static int rti802_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int rti802_detach(struct comedi_device *dev); static struct comedi_driver driver_rti802 = { - driver_name:"rti802", - module:THIS_MODULE, - attach:rti802_attach, - detach:rti802_detach, + .driver_name = "rti802", + .module = THIS_MODULE, + .attach = rti802_attach, + .detach = rti802_detach, }; COMEDI_INITCLEANUP(driver_rti802); @@ -68,8 +68,8 @@ struct rti802_private { #define devpriv ((struct rti802_private *)dev->private) -static int rti802_ao_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int rti802_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i; @@ -79,8 +79,8 @@ static int rti802_ao_insn_read(struct comedi_device * dev, struct comedi_subdevi return i; } -static int rti802_ao_insn_write(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int rti802_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i, d; int chan = CR_CHAN(insn->chanspec); @@ -96,7 +96,7 @@ static int rti802_ao_insn_write(struct comedi_device * dev, struct comedi_subdev return i; } -static int rti802_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int rti802_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; int i; @@ -140,7 +140,7 @@ static int rti802_attach(struct comedi_device * dev, struct comedi_devconfig * i return 0; } -static int rti802_detach(struct comedi_device * dev) +static int rti802_detach(struct comedi_device *dev) { printk("comedi%d: rti802: remove\n", dev->minor); diff --git a/drivers/staging/comedi/drivers/s526.c b/drivers/staging/comedi/drivers/s526.c index a7b6f711afca..d9509d7a3283 100644 --- a/drivers/staging/comedi/drivers/s526.c +++ b/drivers/staging/comedi/drivers/s526.c @@ -169,14 +169,14 @@ struct s526_board { static const struct s526_board s526_boards[] = { { - name: "s526", - gpct_chans:4, - gpct_bits:24, - ad_chans:8, - ad_bits: 16, - da_chans:4, - da_bits: 16, - have_dio:1, + .name = "s526", + .gpct_chans = 4, + .gpct_bits = 24, + .ad_chans = 8, + .ad_bits = 16, + .da_chans = 4, + .da_bits = 16, + .have_dio = 1, } }; @@ -217,13 +217,13 @@ struct s526_private { * the board, and also about the kernel module that contains * the device code. */ -static int s526_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int s526_detach(struct comedi_device * dev); +static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int s526_detach(struct comedi_device *dev); static struct comedi_driver driver_s526 = { - driver_name:"s526", - module:THIS_MODULE, - attach:s526_attach, - detach:s526_detach, + .driver_name = "s526", + .module = THIS_MODULE, + .attach = s526_attach, + .detach = s526_detach, /* It is not necessary to implement the following members if you are * writing a driver for a ISA PnP or PCI card */ /* Most drivers will support multiple types of boards by @@ -242,29 +242,29 @@ static struct comedi_driver driver_s526 = { * the type of board in software. ISA PnP, PCI, and PCMCIA * devices are such boards. */ - board_name:&s526_boards[0].name, - offset:sizeof(struct s526_board), - num_names:sizeof(s526_boards) / sizeof(struct s526_board), + .board_name = &s526_boards[0].name, + .offset = sizeof(struct s526_board), + .num_names = ARRAY_SIZE(s526_boards), }; -static int s526_gpct_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int s526_gpct_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int s526_gpct_winsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int s526_ai_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int s526_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int s526_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int s526_ao_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int s526_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int s526_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); +static int s526_gpct_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int s526_gpct_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int s526_gpct_winsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int s526_ai_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int s526_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int s526_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int s526_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int s526_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int s526_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); /* * Attach is called by the Comedi core to configure the driver @@ -272,13 +272,13 @@ static int s526_dio_insn_config(struct comedi_device * dev, struct comedi_subdev * in the driver structure, dev->board_ptr contains that * address. */ -static int s526_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; int iobase; int i, n; -// short value; -// int subdev_channel = 0; +/* short value; */ +/* int subdev_channel = 0; */ printk("comedi%d: s526: ", dev->minor); @@ -334,12 +334,12 @@ static int s526_attach(struct comedi_device * dev, struct comedi_devconfig * it) /* Command are not implemented yet, however they are necessary to allocate the necessary memory for the comedi_async struct (used to trigger the GPCT in case of pulsegenerator function */ - //s->do_cmd = s526_gpct_cmd; - //s->do_cmdtest = s526_gpct_cmdtest; - //s->cancel = s526_gpct_cancel; + /* s->do_cmd = s526_gpct_cmd; */ + /* s->do_cmdtest = s526_gpct_cmdtest; */ + /* s->cancel = s526_gpct_cancel; */ s = dev->subdevices + 1; - //dev->read_subdev=s; + /* dev->read_subdev=s; */ /* analog input subdevice */ s->type = COMEDI_SUBD_AI; /* we support differential */ @@ -383,18 +383,18 @@ static int s526_attach(struct comedi_device * dev, struct comedi_devconfig * it) return 1; #if 0 - // Example of Counter Application - //One-shot (software trigger) - cmReg.reg.coutSource = 0; // out RCAP - cmReg.reg.coutPolarity = 1; // Polarity inverted - cmReg.reg.autoLoadResetRcap = 1; // Auto load 0:disabled, 1:enabled - cmReg.reg.hwCtEnableSource = 3; // NOT RCAP - cmReg.reg.ctEnableCtrl = 2; // Hardware - cmReg.reg.clockSource = 2; // Internal - cmReg.reg.countDir = 1; // Down - cmReg.reg.countDirCtrl = 1; // Software - cmReg.reg.outputRegLatchCtrl = 0; // latch on read - cmReg.reg.preloadRegSel = 0; // PR0 + /* Example of Counter Application */ + /* One-shot (software trigger) */ + cmReg.reg.coutSource = 0; /* out RCAP */ + cmReg.reg.coutPolarity = 1; /* Polarity inverted */ + cmReg.reg.autoLoadResetRcap = 1; /* Auto load 0:disabled, 1:enabled */ + cmReg.reg.hwCtEnableSource = 3; /* NOT RCAP */ + cmReg.reg.ctEnableCtrl = 2; /* Hardware */ + cmReg.reg.clockSource = 2; /* Internal */ + cmReg.reg.countDir = 1; /* Down */ + cmReg.reg.countDirCtrl = 1; /* Software */ + cmReg.reg.outputRegLatchCtrl = 0; /* latch on read */ + cmReg.reg.preloadRegSel = 0; /* PR0 */ cmReg.reg.reserved = 0; outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel)); @@ -402,24 +402,24 @@ static int s526_attach(struct comedi_device * dev, struct comedi_devconfig * it) outw(0x0001, ADDR_CHAN_REG(REG_C0H, subdev_channel)); outw(0x3C68, ADDR_CHAN_REG(REG_C0L, subdev_channel)); - outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); // Reset the counter - outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); // Load the counter from PR0 + outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); /* Reset the counter */ + outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); /* Load the counter from PR0 */ - outw(0x0008, ADDR_CHAN_REG(REG_C0C, subdev_channel)); // Reset RCAP (fires one-shot) + outw(0x0008, ADDR_CHAN_REG(REG_C0C, subdev_channel)); /* Reset RCAP (fires one-shot) */ #else - // Set Counter Mode Register - cmReg.reg.coutSource = 0; // out RCAP - cmReg.reg.coutPolarity = 0; // Polarity inverted - cmReg.reg.autoLoadResetRcap = 0; // Auto load disabled - cmReg.reg.hwCtEnableSource = 2; // NOT RCAP - cmReg.reg.ctEnableCtrl = 1; // 1: Software, >1 : Hardware - cmReg.reg.clockSource = 3; // x4 - cmReg.reg.countDir = 0; // up - cmReg.reg.countDirCtrl = 0; // quadrature - cmReg.reg.outputRegLatchCtrl = 0; // latch on read - cmReg.reg.preloadRegSel = 0; // PR0 + /* Set Counter Mode Register */ + cmReg.reg.coutSource = 0; /* out RCAP */ + cmReg.reg.coutPolarity = 0; /* Polarity inverted */ + cmReg.reg.autoLoadResetRcap = 0; /* Auto load disabled */ + cmReg.reg.hwCtEnableSource = 2; /* NOT RCAP */ + cmReg.reg.ctEnableCtrl = 1; /* 1: Software, >1 : Hardware */ + cmReg.reg.clockSource = 3; /* x4 */ + cmReg.reg.countDir = 0; /* up */ + cmReg.reg.countDirCtrl = 0; /* quadrature */ + cmReg.reg.outputRegLatchCtrl = 0; /* latch on read */ + cmReg.reg.preloadRegSel = 0; /* PR0 */ cmReg.reg.reserved = 0; n = 0; @@ -429,21 +429,21 @@ static int s526_attach(struct comedi_device * dev, struct comedi_devconfig * it) udelay(1000); printk("Read back mode reg=0x%04x\n", inw(ADDR_CHAN_REG(REG_C0M, n))); - // Load the pre-laod register high word -// value = (short) (0x55); -// outw(value, ADDR_CHAN_REG(REG_C0H, n)); + /* Load the pre-laod register high word */ +/* value = (short) (0x55); */ +/* outw(value, ADDR_CHAN_REG(REG_C0H, n)); */ - // Load the pre-laod register low word -// value = (short)(0xaa55); -// outw(value, ADDR_CHAN_REG(REG_C0L, n)); + /* Load the pre-laod register low word */ +/* value = (short)(0xaa55); */ +/* outw(value, ADDR_CHAN_REG(REG_C0L, n)); */ - // Write the Counter Control Register -// outw(value, ADDR_CHAN_REG(REG_C0C, 0)); + /* Write the Counter Control Register */ +/* outw(value, ADDR_CHAN_REG(REG_C0C, 0)); */ - // Reset the counter if it is software preload + /* Reset the counter if it is software preload */ if (cmReg.reg.autoLoadResetRcap == 0) { - outw(0x8000, ADDR_CHAN_REG(REG_C0C, n)); // Reset the counter - outw(0x4000, ADDR_CHAN_REG(REG_C0C, n)); // Load the counter from PR0 + outw(0x8000, ADDR_CHAN_REG(REG_C0C, n)); /* Reset the counter */ + outw(0x4000, ADDR_CHAN_REG(REG_C0C, n)); /* Load the counter from PR0 */ } outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, n)); @@ -468,7 +468,7 @@ static int s526_attach(struct comedi_device * dev, struct comedi_devconfig * it) * allocated by _attach(). dev->private and dev->subdevices are * deallocated automatically by the core. */ -static int s526_detach(struct comedi_device * dev) +static int s526_detach(struct comedi_device *dev) { printk("comedi%d: s526: remove\n", dev->minor); @@ -478,47 +478,47 @@ static int s526_detach(struct comedi_device * dev) return 0; } -static int s526_gpct_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int s526_gpct_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - int i; // counts the Data + int i; /* counts the Data */ int counter_channel = CR_CHAN(insn->chanspec); unsigned short datalow; unsigned short datahigh; - // Check if (n > 0) + /* Check if (n > 0) */ if (insn->n <= 0) { printk("s526: INSN_READ: n should be > 0\n"); return -EINVAL; } - // Read the low word first + /* Read the low word first */ for (i = 0; i < insn->n; i++) { datalow = inw(ADDR_CHAN_REG(REG_C0L, counter_channel)); datahigh = inw(ADDR_CHAN_REG(REG_C0H, counter_channel)); data[i] = (int)(datahigh & 0x00FF); data[i] = (data[i] << 16) | (datalow & 0xFFFF); -// printk("s526 GPCT[%d]: %x(0x%04x, 0x%04x)\n", counter_channel, data[i], datahigh, datalow); +/* printk("s526 GPCT[%d]: %x(0x%04x, 0x%04x)\n", counter_channel, data[i], datahigh, datalow); */ } return i; } -static int s526_gpct_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int s526_gpct_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - int subdev_channel = CR_CHAN(insn->chanspec); // Unpack chanspec + int subdev_channel = CR_CHAN(insn->chanspec); /* Unpack chanspec */ int i; short value; -// printk("s526: GPCT_INSN_CONFIG: Configuring Channel %d\n", subdev_channel); +/* printk("s526: GPCT_INSN_CONFIG: Configuring Channel %d\n", subdev_channel); */ for (i = 0; i < MAX_GPCT_CONFIG_DATA; i++) { devpriv->s526_gpct_config[subdev_channel].data[i] = insn->data[i]; -// printk("data[%d]=%x\n", i, insn->data[i]); +/* printk("data[%d]=%x\n", i, insn->data[i]); */ } - // Check what type of Counter the user requested, data[0] contains - // the Application type + /* Check what type of Counter the user requested, data[0] contains */ + /* the Application type */ switch (insn->data[0]) { case INSN_CONFIG_GPCT_QUADRATURE_ENCODER: /* @@ -531,19 +531,19 @@ static int s526_gpct_insn_config(struct comedi_device * dev, struct comedi_subde devpriv->s526_gpct_config[subdev_channel].app = PositionMeasurement; -/* - // Example of Counter Application - //One-shot (software trigger) - cmReg.reg.coutSource = 0; // out RCAP - cmReg.reg.coutPolarity = 1; // Polarity inverted - cmReg.reg.autoLoadResetRcap = 0; // Auto load disabled - cmReg.reg.hwCtEnableSource = 3; // NOT RCAP - cmReg.reg.ctEnableCtrl = 2; // Hardware - cmReg.reg.clockSource = 2; // Internal - cmReg.reg.countDir = 1; // Down - cmReg.reg.countDirCtrl = 1; // Software - cmReg.reg.outputRegLatchCtrl = 0; // latch on read - cmReg.reg.preloadRegSel = 0; // PR0 +#if 0 + /* Example of Counter Application */ + /* One-shot (software trigger) */ + cmReg.reg.coutSource = 0; /* out RCAP */ + cmReg.reg.coutPolarity = 1; /* Polarity inverted */ + cmReg.reg.autoLoadResetRcap = 0; /* Auto load disabled */ + cmReg.reg.hwCtEnableSource = 3; /* NOT RCAP */ + cmReg.reg.ctEnableCtrl = 2; /* Hardware */ + cmReg.reg.clockSource = 2; /* Internal */ + cmReg.reg.countDir = 1; /* Down */ + cmReg.reg.countDirCtrl = 1; /* Software */ + cmReg.reg.outputRegLatchCtrl = 0; /* latch on read */ + cmReg.reg.preloadRegSel = 0; /* PR0 */ cmReg.reg.reserved = 0; outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel)); @@ -551,40 +551,40 @@ static int s526_gpct_insn_config(struct comedi_device * dev, struct comedi_subde outw(0x0001, ADDR_CHAN_REG(REG_C0H, subdev_channel)); outw(0x3C68, ADDR_CHAN_REG(REG_C0L, subdev_channel)); - outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); // Reset the counter - outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); // Load the counter from PR0 + outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); /* Reset the counter */ + outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); /* Load the counter from PR0 */ - outw(0x0008, ADDR_CHAN_REG(REG_C0C, subdev_channel)); // Reset RCAP (fires one-shot) + outw(0x0008, ADDR_CHAN_REG(REG_C0C, subdev_channel)); /* Reset RCAP (fires one-shot) */ -*/ +#endif #if 1 - // Set Counter Mode Register - cmReg.reg.coutSource = 0; // out RCAP - cmReg.reg.coutPolarity = 0; // Polarity inverted - cmReg.reg.autoLoadResetRcap = 0; // Auto load disabled - cmReg.reg.hwCtEnableSource = 2; // NOT RCAP - cmReg.reg.ctEnableCtrl = 1; // 1: Software, >1 : Hardware - cmReg.reg.clockSource = 3; // x4 - cmReg.reg.countDir = 0; // up - cmReg.reg.countDirCtrl = 0; // quadrature - cmReg.reg.outputRegLatchCtrl = 0; // latch on read - cmReg.reg.preloadRegSel = 0; // PR0 + /* Set Counter Mode Register */ + cmReg.reg.coutSource = 0; /* out RCAP */ + cmReg.reg.coutPolarity = 0; /* Polarity inverted */ + cmReg.reg.autoLoadResetRcap = 0; /* Auto load disabled */ + cmReg.reg.hwCtEnableSource = 2; /* NOT RCAP */ + cmReg.reg.ctEnableCtrl = 1; /* 1: Software, >1 : Hardware */ + cmReg.reg.clockSource = 3; /* x4 */ + cmReg.reg.countDir = 0; /* up */ + cmReg.reg.countDirCtrl = 0; /* quadrature */ + cmReg.reg.outputRegLatchCtrl = 0; /* latch on read */ + cmReg.reg.preloadRegSel = 0; /* PR0 */ cmReg.reg.reserved = 0; - // Set Counter Mode Register -// printk("s526: Counter Mode register=%x\n", cmReg.value); + /* Set Counter Mode Register */ +/* printk("s526: Counter Mode register=%x\n", cmReg.value); */ outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel)); - // Reset the counter if it is software preload + /* Reset the counter if it is software preload */ if (cmReg.reg.autoLoadResetRcap == 0) { - outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); // Reset the counter -// outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); // Load the counter from PR0 + outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); /* Reset the counter */ +/* outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); Load the counter from PR0 */ } #else - cmReg.reg.countDirCtrl = 0; // 0 quadrature, 1 software control + cmReg.reg.countDirCtrl = 0; /* 0 quadrature, 1 software control */ - // data[1] contains GPCT_X1, GPCT_X2 or GPCT_X4 + /* data[1] contains GPCT_X1, GPCT_X2 or GPCT_X4 */ if (insn->data[1] == GPCT_X2) { cmReg.reg.clockSource = 1; } else if (insn->data[1] == GPCT_X4) { @@ -593,37 +593,37 @@ static int s526_gpct_insn_config(struct comedi_device * dev, struct comedi_subde cmReg.reg.clockSource = 0; } - // When to take into account the indexpulse: + /* When to take into account the indexpulse: */ if (insn->data[2] == GPCT_IndexPhaseLowLow) { } else if (insn->data[2] == GPCT_IndexPhaseLowHigh) { } else if (insn->data[2] == GPCT_IndexPhaseHighLow) { } else if (insn->data[2] == GPCT_IndexPhaseHighHigh) { } - // Take into account the index pulse? + /* Take into account the index pulse? */ if (insn->data[3] == GPCT_RESET_COUNTER_ON_INDEX) - cmReg.reg.autoLoadResetRcap = 4; // Auto load with INDEX^ + cmReg.reg.autoLoadResetRcap = 4; /* Auto load with INDEX^ */ - // Set Counter Mode Register + /* Set Counter Mode Register */ cmReg.value = (short) (insn->data[1] & 0xFFFF); outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel)); - // Load the pre-laod register high word + /* Load the pre-laod register high word */ value = (short) ((insn->data[2] >> 16) & 0xFFFF); outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel)); - // Load the pre-laod register low word + /* Load the pre-laod register low word */ value = (short) (insn->data[2] & 0xFFFF); outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel)); - // Write the Counter Control Register + /* Write the Counter Control Register */ if (insn->data[3] != 0) { value = (short) (insn->data[3] & 0xFFFF); outw(value, ADDR_CHAN_REG(REG_C0C, subdev_channel)); } - // Reset the counter if it is software preload + /* Reset the counter if it is software preload */ if (cmReg.reg.autoLoadResetRcap == 0) { - outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); // Reset the counter - outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); // Load the counter from PR0 + outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); /* Reset the counter */ + outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); /* Load the counter from PR0 */ } #endif break; @@ -640,33 +640,33 @@ static int s526_gpct_insn_config(struct comedi_device * dev, struct comedi_subde devpriv->s526_gpct_config[subdev_channel].app = SinglePulseGeneration; - // Set Counter Mode Register + /* Set Counter Mode Register */ cmReg.value = (short) (insn->data[1] & 0xFFFF); - cmReg.reg.preloadRegSel = 0; // PR0 + cmReg.reg.preloadRegSel = 0; /* PR0 */ outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel)); - // Load the pre-laod register 0 high word + /* Load the pre-laod register 0 high word */ value = (short) ((insn->data[2] >> 16) & 0xFFFF); outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel)); - // Load the pre-laod register 0 low word + /* Load the pre-laod register 0 low word */ value = (short) (insn->data[2] & 0xFFFF); outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel)); - // Set Counter Mode Register + /* Set Counter Mode Register */ cmReg.value = (short) (insn->data[1] & 0xFFFF); - cmReg.reg.preloadRegSel = 1; // PR1 + cmReg.reg.preloadRegSel = 1; /* PR1 */ outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel)); - // Load the pre-laod register 1 high word + /* Load the pre-laod register 1 high word */ value = (short) ((insn->data[3] >> 16) & 0xFFFF); outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel)); - // Load the pre-laod register 1 low word + /* Load the pre-laod register 1 low word */ value = (short) (insn->data[3] & 0xFFFF); outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel)); - // Write the Counter Control Register + /* Write the Counter Control Register */ if (insn->data[3] != 0) { value = (short) (insn->data[3] & 0xFFFF); outw(value, ADDR_CHAN_REG(REG_C0C, subdev_channel)); @@ -685,33 +685,33 @@ static int s526_gpct_insn_config(struct comedi_device * dev, struct comedi_subde devpriv->s526_gpct_config[subdev_channel].app = PulseTrainGeneration; - // Set Counter Mode Register + /* Set Counter Mode Register */ cmReg.value = (short) (insn->data[1] & 0xFFFF); - cmReg.reg.preloadRegSel = 0; // PR0 + cmReg.reg.preloadRegSel = 0; /* PR0 */ outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel)); - // Load the pre-laod register 0 high word + /* Load the pre-laod register 0 high word */ value = (short) ((insn->data[2] >> 16) & 0xFFFF); outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel)); - // Load the pre-laod register 0 low word + /* Load the pre-laod register 0 low word */ value = (short) (insn->data[2] & 0xFFFF); outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel)); - // Set Counter Mode Register + /* Set Counter Mode Register */ cmReg.value = (short) (insn->data[1] & 0xFFFF); - cmReg.reg.preloadRegSel = 1; // PR1 + cmReg.reg.preloadRegSel = 1; /* PR1 */ outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel)); - // Load the pre-laod register 1 high word + /* Load the pre-laod register 1 high word */ value = (short) ((insn->data[3] >> 16) & 0xFFFF); outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel)); - // Load the pre-laod register 1 low word + /* Load the pre-laod register 1 low word */ value = (short) (insn->data[3] & 0xFFFF); outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel)); - // Write the Counter Control Register + /* Write the Counter Control Register */ if (insn->data[3] != 0) { value = (short) (insn->data[3] & 0xFFFF); outw(value, ADDR_CHAN_REG(REG_C0C, subdev_channel)); @@ -727,16 +727,16 @@ static int s526_gpct_insn_config(struct comedi_device * dev, struct comedi_subde return insn->n; } -static int s526_gpct_winsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int s526_gpct_winsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - int subdev_channel = CR_CHAN(insn->chanspec); // Unpack chanspec + int subdev_channel = CR_CHAN(insn->chanspec); /* Unpack chanspec */ short value; printk("s526: GPCT_INSN_WRITE on channel %d\n", subdev_channel); cmReg.value = inw(ADDR_CHAN_REG(REG_C0M, subdev_channel)); printk("s526: Counter Mode Register: %x\n", cmReg.value); - // Check what Application of Counter this channel is configured for + /* Check what Application of Counter this channel is configured for */ switch (devpriv->s526_gpct_config[subdev_channel].app) { case PositionMeasurement: printk("S526: INSN_WRITE: PM\n"); @@ -776,18 +776,18 @@ static int s526_gpct_winsn(struct comedi_device * dev, struct comedi_subdevice * value = (short) (*data & 0xFFFF); outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel)); break; - default: // Impossible + default: /* Impossible */ printk("s526: INSN_WRITE: Functionality %d not implemented yet\n", devpriv->s526_gpct_config[subdev_channel].app); return -EINVAL; break; } - // return the number of samples written + /* return the number of samples written */ return insn->n; } #define ISR_ADC_DONE 0x4 -static int s526_ai_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int s526_ai_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int result = -EINVAL; @@ -803,14 +803,14 @@ static int s526_ai_insn_config(struct comedi_device * dev, struct comedi_subdevi * enable channels here. The channel should be enabled in the * INSN_READ handler. */ - // Enable ADC interrupt + /* Enable ADC interrupt */ outw(ISR_ADC_DONE, ADDR_REG(REG_IER)); -// printk("s526: ADC current value: 0x%04x\n", inw(ADDR_REG(REG_ADC))); +/* printk("s526: ADC current value: 0x%04x\n", inw(ADDR_REG(REG_ADC))); */ devpriv->s526_ai_config = (data[0] & 0x3FF) << 5; if (data[1] > 0) - devpriv->s526_ai_config |= 0x8000; //set the delay + devpriv->s526_ai_config |= 0x8000; /* set the delay */ - devpriv->s526_ai_config |= 0x0001; // ADC start bit. + devpriv->s526_ai_config |= 0x0001; /* ADC start bit. */ return result; } @@ -819,8 +819,8 @@ static int s526_ai_insn_config(struct comedi_device * dev, struct comedi_subdevi * "instructions" read/write data in "one-shot" or "software-triggered" * mode. */ -static int s526_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int s526_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int n, i; int chan = CR_CHAN(insn->chanspec); @@ -837,8 +837,8 @@ static int s526_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s for (n = 0; n < insn->n; n++) { /* trigger conversion */ outw(value, ADDR_REG(REG_ADC)); -// printk("s526: Wrote 0x%04x to ADC\n", value); -// printk("s526: ADC reg=0x%04x\n", inw(ADDR_REG(REG_ADC))); +/* printk("s526: Wrote 0x%04x to ADC\n", value); */ +/* printk("s526: ADC reg=0x%04x\n", inw(ADDR_REG(REG_ADC))); */ #define TIMEOUT 100 /* wait for conversion to end */ @@ -850,16 +850,16 @@ static int s526_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s } } if (i == TIMEOUT) { - /* rt_printk() should be used instead of printk() + /* printk() should be used instead of printk() * whenever the code can be called from real-time. */ - rt_printk("s526: ADC(0x%04x) timeout\n", + printk("s526: ADC(0x%04x) timeout\n", inw(ADDR_REG(REG_ISR))); return -ETIMEDOUT; } /* read data */ d = inw(ADDR_REG(REG_ADD)); -// printk("AI[%d]=0x%04x\n", n, (unsigned short)(d & 0xFFFF)); +/* printk("AI[%d]=0x%04x\n", n, (unsigned short)(d & 0xFFFF)); */ /* munge data */ data[n] = d ^ 0x8000; @@ -869,27 +869,27 @@ static int s526_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s return n; } -static int s526_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int s526_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i; int chan = CR_CHAN(insn->chanspec); unsigned short val; -// printk("s526_ao_winsn\n"); +/* printk("s526_ao_winsn\n"); */ val = chan << 1; -// outw(val, dev->iobase + REG_DAC); +/* outw(val, dev->iobase + REG_DAC); */ outw(val, ADDR_REG(REG_DAC)); /* Writing a list of values to an AO channel is probably not * very useful, but that's how the interface is defined. */ for (i = 0; i < insn->n; i++) { /* a typical programming sequence */ -// outw(data[i], dev->iobase + REG_ADD); // write the data to preload register - outw(data[i], ADDR_REG(REG_ADD)); // write the data to preload register +/* outw(data[i], dev->iobase + REG_ADD); write the data to preload register */ + outw(data[i], ADDR_REG(REG_ADD)); /* write the data to preload register */ devpriv->ao_readback[chan] = data[i]; -// outw(val + 1, dev->iobase + REG_DAC); // starts the D/A conversion. - outw(val + 1, ADDR_REG(REG_DAC)); // starts the D/A conversion. +/* outw(val + 1, dev->iobase + REG_DAC); starts the D/A conversion. */ + outw(val + 1, ADDR_REG(REG_DAC)); /* starts the D/A conversion. */ } /* return the number of samples read/written */ @@ -898,8 +898,8 @@ static int s526_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s /* AO subdevices should have a read insn as well as a write insn. * Usually this means copying a value stored in devpriv. */ -static int s526_ao_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int s526_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i; int chan = CR_CHAN(insn->chanspec); @@ -915,8 +915,8 @@ static int s526_ao_rinsn(struct comedi_device * dev, struct comedi_subdevice * s * useful to applications if you implement the insn_bits interface. * This allows packed reading/writing of the DIO channels. The * comedi core can convert between insn_bits and insn_read/write */ -static int s526_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int s526_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if (insn->n != 2) return -EINVAL; @@ -932,16 +932,16 @@ static int s526_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevic /* on return, data[1] contains the value of the digital * input and output lines. */ - data[1] = inw(ADDR_REG(REG_DIO)) & 0xFF; // low 8 bits are the data + data[1] = inw(ADDR_REG(REG_DIO)) & 0xFF; /* low 8 bits are the data */ /* or we could just return the software copy of the output values if * it was a purely digital output subdevice */ - //data[1]=s->state; + /* data[1]=s->state; */ return 2; } -static int s526_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int s526_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int chan = CR_CHAN(insn->chanspec); short value; @@ -959,10 +959,10 @@ static int s526_dio_insn_config(struct comedi_device * dev, struct comedi_subdev * value COMEDI_INPUT or COMEDI_OUTPUT. */ if (data[0] == COMEDI_OUTPUT) { - value |= 1 << (chan + 10); // bit 10/11 set the group 1/2's mode + value |= 1 << (chan + 10); /* bit 10/11 set the group 1/2's mode */ s->io_bits |= (0xF << chan); } else { - value &= ~(1 << (chan + 10)); // 1 is output, 0 is input. + value &= ~(1 << (chan + 10)); /* 1 is output, 0 is input. */ s->io_bits &= ~(0xF << chan); } outw(value, ADDR_REG(REG_DIO)); diff --git a/drivers/staging/comedi/drivers/s626.c b/drivers/staging/comedi/drivers/s626.c index 30dec9dab19b..92121cf8c45c 100644 --- a/drivers/staging/comedi/drivers/s626.c +++ b/drivers/staging/comedi/drivers/s626.c @@ -68,6 +68,7 @@ INSN_CONFIG instructions: comedi_do_insn(cf,&insn); //executing configuration */ +#include #include #include @@ -95,14 +96,14 @@ struct s626_board { static const struct s626_board s626_boards[] = { { - name: "s626", - ai_chans : S626_ADC_CHANNELS, - ai_bits: 14, - ao_chans : S626_DAC_CHANNELS, - ao_bits: 13, - dio_chans : S626_DIO_CHANNELS, - dio_banks : S626_DIO_BANKS, - enc_chans : S626_ENCODER_CHANNELS, + .name = "s626", + .ai_chans = S626_ADC_CHANNELS, + .ai_bits = 14, + .ao_chans = S626_DAC_CHANNELS, + .ao_bits = 13, + .dio_chans = S626_DIO_CHANNELS, + .dio_banks = S626_DIO_BANKS, + .enc_chans = S626_ENCODER_CHANNELS, } }; @@ -122,10 +123,10 @@ static int s626_attach(struct comedi_device *dev, struct comedi_devconfig *it); static int s626_detach(struct comedi_device *dev); static struct comedi_driver driver_s626 = { - driver_name:"s626", - module : THIS_MODULE, - attach : s626_attach, - detach : s626_detach, + .driver_name = "s626", + .module = THIS_MODULE, + .attach = s626_attach, + .detach = s626_detach, }; struct s626_private { @@ -173,39 +174,39 @@ struct dio_private { }; static struct dio_private dio_private_A = { - RDDIn:LP_RDDINA, - WRDOut : LP_WRDOUTA, - RDEdgSel : LP_RDEDGSELA, - WREdgSel : LP_WREDGSELA, - RDCapSel : LP_RDCAPSELA, - WRCapSel : LP_WRCAPSELA, - RDCapFlg : LP_RDCAPFLGA, - RDIntSel : LP_RDINTSELA, - WRIntSel : LP_WRINTSELA, + .RDDIn = LP_RDDINA, + .WRDOut = LP_WRDOUTA, + .RDEdgSel = LP_RDEDGSELA, + .WREdgSel = LP_WREDGSELA, + .RDCapSel = LP_RDCAPSELA, + .WRCapSel = LP_WRCAPSELA, + .RDCapFlg = LP_RDCAPFLGA, + .RDIntSel = LP_RDINTSELA, + .WRIntSel = LP_WRINTSELA, }; static struct dio_private dio_private_B = { - RDDIn:LP_RDDINB, - WRDOut : LP_WRDOUTB, - RDEdgSel : LP_RDEDGSELB, - WREdgSel : LP_WREDGSELB, - RDCapSel : LP_RDCAPSELB, - WRCapSel : LP_WRCAPSELB, - RDCapFlg : LP_RDCAPFLGB, - RDIntSel : LP_RDINTSELB, - WRIntSel : LP_WRINTSELB, + .RDDIn = LP_RDDINB, + .WRDOut = LP_WRDOUTB, + .RDEdgSel = LP_RDEDGSELB, + .WREdgSel = LP_WREDGSELB, + .RDCapSel = LP_RDCAPSELB, + .WRCapSel = LP_WRCAPSELB, + .RDCapFlg = LP_RDCAPFLGB, + .RDIntSel = LP_RDINTSELB, + .WRIntSel = LP_WRINTSELB, }; static struct dio_private dio_private_C = { - RDDIn:LP_RDDINC, - WRDOut : LP_WRDOUTC, - RDEdgSel : LP_RDEDGSELC, - WREdgSel : LP_WREDGSELC, - RDCapSel : LP_RDCAPSELC, - WRCapSel : LP_WRCAPSELC, - RDCapFlg : LP_RDCAPFLGC, - RDIntSel : LP_RDINTSELC, - WRIntSel : LP_WRINTSELC, + .RDDIn = LP_RDDINC, + .WRDOut = LP_WRDOUTC, + .RDEdgSel = LP_RDEDGSELC, + .WREdgSel = LP_WREDGSELC, + .RDCapSel = LP_RDCAPSELC, + .WRCapSel = LP_WRCAPSELC, + .RDCapFlg = LP_RDCAPFLGC, + .RDIntSel = LP_RDINTSELC, + .WRIntSel = LP_WRINTSELC, }; /* to group dio devices (48 bits mask and data are not allowed ???) @@ -253,7 +254,7 @@ static int s626_ns_to_timer(int *nanosec, int round_mode); static int s626_ai_load_polllist(uint8_t *ppl, struct comedi_cmd *cmd); static int s626_ai_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int trignum); -static irqreturn_t s626_irq_handler(int irq, void *d PT_REGS_ARG); +static irqreturn_t s626_irq_handler(int irq, void *d); static unsigned int s626_ai_reg_to_uint(int data); /* static unsigned int s626_uint_to_reg(struct comedi_subdevice *s, int data); */ @@ -355,100 +356,100 @@ static void CountersInit(struct comedi_device *dev); /* struct enc_private; */ static struct enc_private enc_private_data[] = { { - GetEnable:GetEnable_A, - GetIntSrc : GetIntSrc_A, - GetLoadTrig : GetLoadTrig_A, - GetMode : GetMode_A, - PulseIndex : PulseIndex_A, - SetEnable : SetEnable_A, - SetIntSrc : SetIntSrc_A, - SetLoadTrig : SetLoadTrig_A, - SetMode : SetMode_A, - ResetCapFlags : ResetCapFlags_A, - MyCRA : LP_CR0A, - MyCRB : LP_CR0B, - MyLatchLsw : LP_CNTR0ALSW, - MyEventBits : EVBITS(0), + .GetEnable = GetEnable_A, + .GetIntSrc = GetIntSrc_A, + .GetLoadTrig = GetLoadTrig_A, + .GetMode = GetMode_A, + .PulseIndex = PulseIndex_A, + .SetEnable = SetEnable_A, + .SetIntSrc = SetIntSrc_A, + .SetLoadTrig = SetLoadTrig_A, + .SetMode = SetMode_A, + .ResetCapFlags = ResetCapFlags_A, + .MyCRA = LP_CR0A, + .MyCRB = LP_CR0B, + .MyLatchLsw = LP_CNTR0ALSW, + .MyEventBits = EVBITS(0), }, { - GetEnable:GetEnable_A, - GetIntSrc : GetIntSrc_A, - GetLoadTrig : GetLoadTrig_A, - GetMode : GetMode_A, - PulseIndex : PulseIndex_A, - SetEnable : SetEnable_A, - SetIntSrc : SetIntSrc_A, - SetLoadTrig : SetLoadTrig_A, - SetMode : SetMode_A, - ResetCapFlags : ResetCapFlags_A, - MyCRA : LP_CR1A, - MyCRB : LP_CR1B, - MyLatchLsw : LP_CNTR1ALSW, - MyEventBits : EVBITS(1), + .GetEnable = GetEnable_A, + .GetIntSrc = GetIntSrc_A, + .GetLoadTrig = GetLoadTrig_A, + .GetMode = GetMode_A, + .PulseIndex = PulseIndex_A, + .SetEnable = SetEnable_A, + .SetIntSrc = SetIntSrc_A, + .SetLoadTrig = SetLoadTrig_A, + .SetMode = SetMode_A, + .ResetCapFlags = ResetCapFlags_A, + .MyCRA = LP_CR1A, + .MyCRB = LP_CR1B, + .MyLatchLsw = LP_CNTR1ALSW, + .MyEventBits = EVBITS(1), }, { - GetEnable:GetEnable_A, - GetIntSrc : GetIntSrc_A, - GetLoadTrig : GetLoadTrig_A, - GetMode : GetMode_A, - PulseIndex : PulseIndex_A, - SetEnable : SetEnable_A, - SetIntSrc : SetIntSrc_A, - SetLoadTrig : SetLoadTrig_A, - SetMode : SetMode_A, - ResetCapFlags : ResetCapFlags_A, - MyCRA : LP_CR2A, - MyCRB : LP_CR2B, - MyLatchLsw : LP_CNTR2ALSW, - MyEventBits : EVBITS(2), + .GetEnable = GetEnable_A, + .GetIntSrc = GetIntSrc_A, + .GetLoadTrig = GetLoadTrig_A, + .GetMode = GetMode_A, + .PulseIndex = PulseIndex_A, + .SetEnable = SetEnable_A, + .SetIntSrc = SetIntSrc_A, + .SetLoadTrig = SetLoadTrig_A, + .SetMode = SetMode_A, + .ResetCapFlags = ResetCapFlags_A, + .MyCRA = LP_CR2A, + .MyCRB = LP_CR2B, + .MyLatchLsw = LP_CNTR2ALSW, + .MyEventBits = EVBITS(2), }, { - GetEnable:GetEnable_B, - GetIntSrc : GetIntSrc_B, - GetLoadTrig : GetLoadTrig_B, - GetMode : GetMode_B, - PulseIndex : PulseIndex_B, - SetEnable : SetEnable_B, - SetIntSrc : SetIntSrc_B, - SetLoadTrig : SetLoadTrig_B, - SetMode : SetMode_B, - ResetCapFlags : ResetCapFlags_B, - MyCRA : LP_CR0A, - MyCRB : LP_CR0B, - MyLatchLsw : LP_CNTR0BLSW, - MyEventBits : EVBITS(3), + .GetEnable = GetEnable_B, + .GetIntSrc = GetIntSrc_B, + .GetLoadTrig = GetLoadTrig_B, + .GetMode = GetMode_B, + .PulseIndex = PulseIndex_B, + .SetEnable = SetEnable_B, + .SetIntSrc = SetIntSrc_B, + .SetLoadTrig = SetLoadTrig_B, + .SetMode = SetMode_B, + .ResetCapFlags = ResetCapFlags_B, + .MyCRA = LP_CR0A, + .MyCRB = LP_CR0B, + .MyLatchLsw = LP_CNTR0BLSW, + .MyEventBits = EVBITS(3), }, { - GetEnable:GetEnable_B, - GetIntSrc : GetIntSrc_B, - GetLoadTrig : GetLoadTrig_B, - GetMode : GetMode_B, - PulseIndex : PulseIndex_B, - SetEnable : SetEnable_B, - SetIntSrc : SetIntSrc_B, - SetLoadTrig : SetLoadTrig_B, - SetMode : SetMode_B, - ResetCapFlags : ResetCapFlags_B, - MyCRA : LP_CR1A, - MyCRB : LP_CR1B, - MyLatchLsw : LP_CNTR1BLSW, - MyEventBits : EVBITS(4), + .GetEnable = GetEnable_B, + .GetIntSrc = GetIntSrc_B, + .GetLoadTrig = GetLoadTrig_B, + .GetMode = GetMode_B, + .PulseIndex = PulseIndex_B, + .SetEnable = SetEnable_B, + .SetIntSrc = SetIntSrc_B, + .SetLoadTrig = SetLoadTrig_B, + .SetMode = SetMode_B, + .ResetCapFlags = ResetCapFlags_B, + .MyCRA = LP_CR1A, + .MyCRB = LP_CR1B, + .MyLatchLsw = LP_CNTR1BLSW, + .MyEventBits = EVBITS(4), }, { - GetEnable:GetEnable_B, - GetIntSrc : GetIntSrc_B, - GetLoadTrig : GetLoadTrig_B, - GetMode : GetMode_B, - PulseIndex : PulseIndex_B, - SetEnable : SetEnable_B, - SetIntSrc : SetIntSrc_B, - SetLoadTrig : SetLoadTrig_B, - SetMode : SetMode_B, - ResetCapFlags : ResetCapFlags_B, - MyCRA : LP_CR2A, - MyCRB : LP_CR2B, - MyLatchLsw : LP_CNTR2BLSW, - MyEventBits : EVBITS(5), + .GetEnable = GetEnable_B, + .GetIntSrc = GetIntSrc_B, + .GetLoadTrig = GetLoadTrig_B, + .GetMode = GetMode_B, + .PulseIndex = PulseIndex_B, + .SetEnable = SetEnable_B, + .SetIntSrc = SetIntSrc_B, + .SetLoadTrig = SetLoadTrig_B, + .SetMode = SetMode_B, + .ResetCapFlags = ResetCapFlags_B, + .MyCRA = LP_CR2A, + .MyCRB = LP_CR2B, + .MyLatchLsw = LP_CNTR2BLSW, + .MyEventBits = EVBITS(5), }, }; @@ -596,8 +597,8 @@ static int s626_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (dev->irq == 0) { printk(" unknown irq (bad)\n"); } else { - ret = comedi_request_irq(dev->irq, s626_irq_handler, - IRQF_SHARED, "s626", dev); + ret = request_irq(dev->irq, s626_irq_handler, IRQF_SHARED, + "s626", dev); if (ret < 0) { printk(" irq not available\n"); @@ -968,7 +969,7 @@ static unsigned int s626_ai_reg_to_uint(int data) /* return 0; */ /* } */ -static irqreturn_t s626_irq_handler(int irq, void *d PT_REGS_ARG) +static irqreturn_t s626_irq_handler(int irq, void *d) { struct comedi_device *dev = d; struct comedi_subdevice *s; @@ -987,7 +988,7 @@ static irqreturn_t s626_irq_handler(int irq, void *d PT_REGS_ARG) if (dev->attached == 0) return IRQ_NONE; /* lock to avoid race with comedi_poll */ - comedi_spin_lock_irqsave(&dev->spinlock, flags); + spin_lock_irqsave(&dev->spinlock, flags); /* save interrupt enable register state */ irqstatus = readl(devpriv->base_addr + P_IER); @@ -1264,7 +1265,7 @@ static irqreturn_t s626_irq_handler(int irq, void *d PT_REGS_ARG) DEBUG("s626_irq_handler: exit interrupt service routine.\n"); - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); return IRQ_HANDLED; } @@ -1291,7 +1292,7 @@ static int s626_detach(struct comedi_device *dev) } if (dev->irq) - comedi_free_irq(dev->irq, dev); + free_irq(dev->irq, dev); if (devpriv->base_addr) iounmap(devpriv->base_addr); @@ -1574,7 +1575,7 @@ static int s626_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice for (n = 0; n < insn->n; n++) { /* Delay 10 microseconds for analog input settling. */ - comedi_udelay(10); + udelay(10); /* Start ADC by pulsing GPIO1 low. */ GpioImage = RR7146(P_GPIO); @@ -1606,7 +1607,7 @@ static int s626_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice * data value is sometimes set to the previous * conversion's data value. */ - comedi_udelay(4); + udelay(4); } /* Start a dummy conversion to cause the data from the @@ -1886,31 +1887,16 @@ static int s626_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s err++; } - if (cmd->start_src == TRIG_EXT && cmd->start_arg < 0) { - cmd->start_arg = 0; - err++; - } - if (cmd->start_src == TRIG_EXT && cmd->start_arg > 39) { cmd->start_arg = 39; err++; } - if (cmd->scan_begin_src == TRIG_EXT && cmd->scan_begin_arg < 0) { - cmd->scan_begin_arg = 0; - err++; - } - if (cmd->scan_begin_src == TRIG_EXT && cmd->scan_begin_arg > 39) { cmd->scan_begin_arg = 39; err++; } - if (cmd->convert_src == TRIG_EXT && cmd->convert_arg < 0) { - cmd->convert_arg = 0; - err++; - } - if (cmd->convert_src == TRIG_EXT && cmd->convert_arg > 39) { cmd->convert_arg = 39; err++; @@ -2373,7 +2359,7 @@ static void LoadTrimDACs(struct comedi_device *dev) register uint8_t i; /* Copy TrimDac setpoint values from EEPROM to TrimDacs. */ - for (i = 0; i < (sizeof(trimchan) / sizeof(trimchan[0])); i++) + for (i = 0; i < ARRAY_SIZE(trimchan); i++) WriteTrimDAC(dev, i, I2Cread(dev, trimadrs[i])); } diff --git a/drivers/staging/comedi/drivers/s626.h b/drivers/staging/comedi/drivers/s626.h index 891126f25099..27ae02be5300 100644 --- a/drivers/staging/comedi/drivers/s626.h +++ b/drivers/staging/comedi/drivers/s626.h @@ -63,7 +63,7 @@ */ #ifdef _DEBUG_ -#define DEBUG(...); rt_printk(__VA_ARGS__); +#define DEBUG(...); printk(__VA_ARGS__); #else #define DEBUG(...) #endif diff --git a/drivers/staging/comedi/drivers/serial2002.c b/drivers/staging/comedi/drivers/serial2002.c index 844fd5e2e3a9..db18b11b9d30 100644 --- a/drivers/staging/comedi/drivers/serial2002.c +++ b/drivers/staging/comedi/drivers/serial2002.c @@ -52,7 +52,7 @@ struct serial2002_board { static const struct serial2002_board serial2002_boards[] = { { - name: "serial2002"} + .name = "serial2002"} }; /* @@ -62,7 +62,7 @@ static const struct serial2002_board serial2002_boards[] = { struct serial2002_range_table_t { - // HACK... + /* HACK... */ int length; struct comedi_krange range; }; @@ -70,8 +70,8 @@ struct serial2002_range_table_t { struct serial2002_private { - int port; // /dev/ttyS - int speed; // baudrate + int port; /* /dev/ttyS */ + int speed; /* baudrate */ struct file *tty; unsigned int ao_readback[32]; unsigned char digital_in_mapping[32]; @@ -89,28 +89,28 @@ struct serial2002_private { */ #define devpriv ((struct serial2002_private *)dev->private) -static int serial2002_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int serial2002_detach(struct comedi_device * dev); +static int serial2002_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int serial2002_detach(struct comedi_device *dev); struct comedi_driver driver_serial2002 = { - driver_name:"serial2002", - module:THIS_MODULE, - attach:serial2002_attach, - detach:serial2002_detach, - board_name:&serial2002_boards[0].name, - offset:sizeof(struct serial2002_board), - num_names:sizeof(serial2002_boards) / sizeof(struct serial2002_board), + .driver_name = "serial2002", + .module = THIS_MODULE, + .attach = serial2002_attach, + .detach = serial2002_detach, + .board_name = &serial2002_boards[0].name, + .offset = sizeof(struct serial2002_board), + .num_names = ARRAY_SIZE(serial2002_boards), }; -static int serial2002_di_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int serial2002_do_winsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int serial2002_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int serial2002_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int serial2002_ao_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); +static int serial2002_di_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int serial2002_do_winsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int serial2002_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int serial2002_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int serial2002_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); struct serial_data { enum { is_invalid, is_digital, is_channel } kind; @@ -121,12 +121,12 @@ struct serial_data { static long tty_ioctl(struct file *f, unsigned op, unsigned long param) { #ifdef HAVE_UNLOCKED_IOCTL - if (f->f_op->unlocked_ioctl) { + if (f->f_op->unlocked_ioctl) { return f->f_op->unlocked_ioctl(f, op, param); } #endif if (f->f_op->ioctl) { - return f->f_op->ioctl(f->f_dentry->d_inode, f, op, param); + return f->f_op->ioctl(f->f_dentry->d_inode, f, op, param); } return -ENOSYS; } @@ -211,7 +211,7 @@ static int tty_read(struct file *f, int timeout) /* Device does not support poll, busy wait */ int retries = 0; while (1) { - unsigned char ch; + unsigned char ch; retries++; if (retries >= timeout) { @@ -220,10 +220,10 @@ static int tty_read(struct file *f, int timeout) f->f_pos = 0; if (f->f_op->read(f, &ch, 1, &f->f_pos) == 1) { - result = ch; + result = ch; break; } - comedi_udelay(100); + udelay(100); } } set_fs(oldfs); @@ -238,11 +238,11 @@ static void tty_setspeed(struct file *f, int speed) oldfs = get_fs(); set_fs(KERNEL_DS); { - // Set speed + /* Set speed */ struct termios settings; tty_ioctl(f, TCGETS, (unsigned long)&settings); -// printk("Speed: %d\n", settings.c_cflag & (CBAUD | CBAUDEX)); +/* printk("Speed: %d\n", settings.c_cflag & (CBAUD | CBAUDEX)); */ settings.c_iflag = 0; settings.c_oflag = 0; settings.c_lflag = 0; @@ -284,10 +284,10 @@ static void tty_setspeed(struct file *f, int speed) break; } tty_ioctl(f, TCSETS, (unsigned long)&settings); -// printk("Speed: %d\n", settings.c_cflag & (CBAUD | CBAUDEX)); +/* printk("Speed: %d\n", settings.c_cflag & (CBAUD | CBAUDEX)); */ } { - // Set low latency + /* Set low latency */ struct serial_struct settings; tty_ioctl(f, TIOCGSERIAL, (unsigned long)&settings); @@ -393,7 +393,7 @@ static void serial_write(struct file *f, struct serial_data data) } } -static void serial_2002_open(struct comedi_device * dev) +static void serial_2002_open(struct comedi_device *dev) { char port[20]; @@ -437,7 +437,7 @@ static void serial_2002_open(struct comedi_device * dev) } tty_setspeed(devpriv->tty, devpriv->speed); - poll_channel(devpriv->tty, 31); // Start reading configuration + poll_channel(devpriv->tty, 31); /* Start reading configuration */ while (1) { struct serial_data data; @@ -557,7 +557,7 @@ static void serial_2002_open(struct comedi_device * dev) } } for (i = 0; i <= 4; i++) { - // Fill in subdev data + /* Fill in subdev data */ struct config_t *c; unsigned char *mapping = 0; struct serial2002_range_table_t *range = 0; @@ -659,15 +659,15 @@ static void serial_2002_open(struct comedi_device * dev) } } -static void serial_2002_close(struct comedi_device * dev) +static void serial_2002_close(struct comedi_device *dev) { if (!IS_ERR(devpriv->tty) && (devpriv->tty != 0)) { filp_close(devpriv->tty, 0); } } -static int serial2002_di_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int serial2002_di_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int n; int chan; @@ -688,8 +688,8 @@ static int serial2002_di_rinsn(struct comedi_device * dev, struct comedi_subdevi return n; } -static int serial2002_do_winsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int serial2002_do_winsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int n; int chan; @@ -706,8 +706,8 @@ static int serial2002_do_winsn(struct comedi_device * dev, struct comedi_subdevi return n; } -static int serial2002_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int serial2002_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int n; int chan; @@ -728,8 +728,8 @@ static int serial2002_ai_rinsn(struct comedi_device * dev, struct comedi_subdevi return n; } -static int serial2002_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int serial2002_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int n; int chan; @@ -747,8 +747,8 @@ static int serial2002_ao_winsn(struct comedi_device * dev, struct comedi_subdevi return n; } -static int serial2002_ao_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int serial2002_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int n; int chan = CR_CHAN(insn->chanspec); @@ -760,8 +760,8 @@ static int serial2002_ao_rinsn(struct comedi_device * dev, struct comedi_subdevi return n; } -static int serial2002_ei_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int serial2002_ei_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int n; int chan; @@ -782,7 +782,7 @@ static int serial2002_ei_rinsn(struct comedi_device * dev, struct comedi_subdevi return n; } -static int serial2002_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int serial2002_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; @@ -849,7 +849,7 @@ static int serial2002_attach(struct comedi_device * dev, struct comedi_devconfig return 1; } -static int serial2002_detach(struct comedi_device * dev) +static int serial2002_detach(struct comedi_device *dev) { struct comedi_subdevice *s; int i; diff --git a/drivers/staging/comedi/drivers/skel.c b/drivers/staging/comedi/drivers/skel.c index c7700d134cc1..07f580a48206 100644 --- a/drivers/staging/comedi/drivers/skel.c +++ b/drivers/staging/comedi/drivers/skel.c @@ -97,16 +97,16 @@ struct skel_board { static const struct skel_board skel_boards[] = { { - name: "skel-100", - ai_chans:16, - ai_bits: 12, - have_dio:1, + .name = "skel-100", + .ai_chans = 16, + .ai_bits = 12, + .have_dio = 1, }, { - name: "skel-200", - ai_chans:8, - ai_bits: 16, - have_dio:0, + .name = "skel-200", + .ai_chans = 8, + .ai_bits = 16, + .have_dio = 0, }, }; @@ -154,13 +154,13 @@ struct skel_private { * the board, and also about the kernel module that contains * the device code. */ -static int skel_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int skel_detach(struct comedi_device * dev); +static int skel_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int skel_detach(struct comedi_device *dev); static struct comedi_driver driver_skel = { - driver_name:"dummy", - module:THIS_MODULE, - attach:skel_attach, - detach:skel_detach, + .driver_name = "dummy", + .module = THIS_MODULE, + .attach = skel_attach, + .detach = skel_detach, /* It is not necessary to implement the following members if you are * writing a driver for a ISA PnP or PCI card */ /* Most drivers will support multiple types of boards by @@ -179,23 +179,23 @@ static struct comedi_driver driver_skel = { * the type of board in software. ISA PnP, PCI, and PCMCIA * devices are such boards. */ - board_name:&skel_boards[0].name, - offset:sizeof(struct skel_board), - num_names:sizeof(skel_boards) / sizeof(struct skel_board), + .board_name = &skel_boards[0].name, + .offset = sizeof(struct skel_board), + .num_names = ARRAY_SIZE(skel_boards), }; -static int skel_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int skel_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int skel_ao_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int skel_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int skel_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data); -static int skel_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd); +static int skel_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int skel_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int skel_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int skel_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int skel_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data); +static int skel_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd); static int skel_ns_to_timer(unsigned int *ns, int round); /* @@ -204,7 +204,7 @@ static int skel_ns_to_timer(unsigned int *ns, int round); * in the driver structure, dev->board_ptr contains that * address. */ -static int skel_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int skel_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; @@ -292,7 +292,7 @@ static int skel_attach(struct comedi_device * dev, struct comedi_devconfig * it) * allocated by _attach(). dev->private and dev->subdevices are * deallocated automatically by the core. */ -static int skel_detach(struct comedi_device * dev) +static int skel_detach(struct comedi_device *dev) { printk("comedi%d: skel: remove\n", dev->minor); @@ -303,8 +303,8 @@ static int skel_detach(struct comedi_device * dev) * "instructions" read/write data in "one-shot" or "software-triggered" * mode. */ -static int skel_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int skel_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int n, i; unsigned int d; @@ -331,9 +331,9 @@ static int skel_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s break; } if (i == TIMEOUT) { - /* rt_printk() should be used instead of printk() + /* printk() should be used instead of printk() * whenever the code can be called from real-time. */ - rt_printk("timeout\n"); + printk("timeout\n"); return -ETIMEDOUT; } @@ -351,8 +351,8 @@ static int skel_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s return n; } -static int skel_ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_cmd * cmd) +static int skel_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_cmd *cmd) { int err = 0; int tmp; @@ -520,8 +520,8 @@ static int skel_ns_to_timer(unsigned int *ns, int round) return *ns; } -static int skel_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int skel_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i; int chan = CR_CHAN(insn->chanspec); @@ -541,8 +541,8 @@ static int skel_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s /* AO subdevices should have a read insn as well as a write insn. * Usually this means copying a value stored in devpriv. */ -static int skel_ao_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int skel_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int i; int chan = CR_CHAN(insn->chanspec); @@ -558,8 +558,8 @@ static int skel_ao_rinsn(struct comedi_device * dev, struct comedi_subdevice * s * useful to applications if you implement the insn_bits interface. * This allows packed reading/writing of the DIO channels. The * comedi core can convert between insn_bits and insn_read/write */ -static int skel_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int skel_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if (insn->n != 2) return -EINVAL; @@ -583,8 +583,8 @@ static int skel_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevic return 2; } -static int skel_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, - struct comedi_insn * insn, unsigned int * data) +static int skel_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { int chan = CR_CHAN(insn->chanspec); diff --git a/drivers/staging/comedi/drivers/ssv_dnp.c b/drivers/staging/comedi/drivers/ssv_dnp.c index 1628d216cdd4..13c29bb99100 100644 --- a/drivers/staging/comedi/drivers/ssv_dnp.c +++ b/drivers/staging/comedi/drivers/ssv_dnp.c @@ -61,10 +61,10 @@ struct dnp_board { static const struct dnp_board dnp_boards[] = { /* we only support one DNP 'board' */ { /* variant at the moment */ - name: "dnp-1486", - ai_chans:16, - ai_bits: 12, - have_dio:1, + .name = "dnp-1486", + .ai_chans = 16, + .ai_bits = 12, + .have_dio = 1, }, }; @@ -74,7 +74,6 @@ static const struct dnp_board dnp_boards[] = { /* we only support one DNP 'board /* This structure is for data unique to the DNP driver --------------------- */ struct dnp_private_data { - // }; @@ -89,27 +88,27 @@ struct dnp_private_data { /* In the following section we define the API of this driver. */ /* ------------------------------------------------------------------------- */ -static int dnp_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int dnp_detach(struct comedi_device * dev); +static int dnp_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int dnp_detach(struct comedi_device *dev); static struct comedi_driver driver_dnp = { - driver_name:"ssv_dnp", - module:THIS_MODULE, - attach:dnp_attach, - detach:dnp_detach, - board_name:&dnp_boards[0].name, + .driver_name = "ssv_dnp", + .module = THIS_MODULE, + .attach = dnp_attach, + .detach = dnp_detach, + .board_name = &dnp_boards[0].name, /* only necessary for non-PnP devs */ - offset:sizeof(struct dnp_board),/* like ISA-PnP, PCI or PCMCIA. */ - num_names:sizeof(dnp_boards) / sizeof(struct dnp_board), + .offset = sizeof(struct dnp_board),/* like ISA-PnP, PCI or PCMCIA. */ + .num_names = ARRAY_SIZE(dnp_boards), }; COMEDI_INITCLEANUP(driver_dnp); -static int dnp_dio_insn_bits(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data); +static int dnp_dio_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -static int dnp_dio_insn_config(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data); +static int dnp_dio_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); /* ------------------------------------------------------------------------- */ /* Attach is called by comedi core to configure the driver for a particular */ @@ -117,7 +116,7 @@ static int dnp_dio_insn_config(struct comedi_device * dev, /* dev->board_ptr contains that address. */ /* ------------------------------------------------------------------------- */ -static int dnp_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int dnp_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; @@ -126,7 +125,7 @@ static int dnp_attach(struct comedi_device * dev, struct comedi_devconfig * it) /* Autoprobing: this should find out which board we have. Currently only */ /* the 1486 board is supported and autoprobing is not implemented :-) */ - //dev->board_ptr = dnp_probe(dev); + /* dev->board_ptr = dnp_probe(dev); */ /* Initialize the name of the board. We can use the "thisboard" macro now. */ dev->board_name = thisboard->name; @@ -178,7 +177,7 @@ static int dnp_attach(struct comedi_device * dev, struct comedi_devconfig * it) /* deallocated automatically by the core. */ /* ------------------------------------------------------------------------- */ -static int dnp_detach(struct comedi_device * dev) +static int dnp_detach(struct comedi_device *dev) { /* configure all ports as input (default) */ @@ -202,8 +201,8 @@ static int dnp_detach(struct comedi_device * dev) /* are able to use these instructions as well. */ /* ------------------------------------------------------------------------- */ -static int dnp_dio_insn_bits(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +static int dnp_dio_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { if (insn->n != 2) @@ -252,8 +251,8 @@ static int dnp_dio_insn_bits(struct comedi_device * dev, /* COMEDI_INPUT or COMEDI_OUTPUT. */ /* ------------------------------------------------------------------------- */ -static int dnp_dio_insn_config(struct comedi_device * dev, - struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data) +static int dnp_dio_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { u8 register_buffer; diff --git a/drivers/staging/comedi/drivers/unioxx5.c b/drivers/staging/comedi/drivers/unioxx5.c index dd3b1119319b..96bb15ccccb1 100644 --- a/drivers/staging/comedi/drivers/unioxx5.c +++ b/drivers/staging/comedi/drivers/unioxx5.c @@ -80,38 +80,38 @@ struct unioxx5_subd_priv { unsigned char usp_prev_cn_val[3]; /* previous channel value */ }; -static int unioxx5_attach(struct comedi_device * dev, struct comedi_devconfig * it); -static int unioxx5_subdev_write(struct comedi_device * dev, struct comedi_subdevice * subdev, - struct comedi_insn * insn, unsigned int * data); -static int unioxx5_subdev_read(struct comedi_device * dev, struct comedi_subdevice * subdev, - struct comedi_insn * insn, unsigned int * data); -static int unioxx5_insn_config(struct comedi_device * dev, struct comedi_subdevice * subdev, - struct comedi_insn * insn, unsigned int * data); -static int unioxx5_detach(struct comedi_device * dev); -static int __unioxx5_subdev_init(struct comedi_subdevice * subdev, int subdev_iobase, +static int unioxx5_attach(struct comedi_device *dev, struct comedi_devconfig *it); +static int unioxx5_subdev_write(struct comedi_device *dev, struct comedi_subdevice *subdev, + struct comedi_insn *insn, unsigned int *data); +static int unioxx5_subdev_read(struct comedi_device *dev, struct comedi_subdevice *subdev, + struct comedi_insn *insn, unsigned int *data); +static int unioxx5_insn_config(struct comedi_device *dev, struct comedi_subdevice *subdev, + struct comedi_insn *insn, unsigned int *data); +static int unioxx5_detach(struct comedi_device *dev); +static int __unioxx5_subdev_init(struct comedi_subdevice *subdev, int subdev_iobase, int minor); -static int __unioxx5_digital_write(struct unioxx5_subd_priv * usp, unsigned int * data, +static int __unioxx5_digital_write(struct unioxx5_subd_priv *usp, unsigned int *data, int channel, int minor); -static int __unioxx5_digital_read(struct unioxx5_subd_priv * usp, unsigned int * data, +static int __unioxx5_digital_read(struct unioxx5_subd_priv *usp, unsigned int *data, int channel, int minor); -//static void __unioxx5_digital_config(struct unioxx5_subd_priv* usp, int mode); -static int __unioxx5_analog_write(struct unioxx5_subd_priv * usp, unsigned int * data, +/* static void __unioxx5_digital_config(struct unioxx5_subd_priv* usp, int mode); */ +static int __unioxx5_analog_write(struct unioxx5_subd_priv *usp, unsigned int *data, int channel, int minor); -static int __unioxx5_analog_read(struct unioxx5_subd_priv * usp, unsigned int * data, +static int __unioxx5_analog_read(struct unioxx5_subd_priv *usp, unsigned int *data, int channel, int minor); static int __unioxx5_define_chan_offset(int chan_num); -static void __unioxx5_analog_config(struct unioxx5_subd_priv * usp, int channel); +static void __unioxx5_analog_config(struct unioxx5_subd_priv *usp, int channel); static struct comedi_driver unioxx5_driver = { - driver_name:DRIVER_NAME, - module:THIS_MODULE, - attach:unioxx5_attach, - detach:unioxx5_detach + .driver_name = DRIVER_NAME, + .module = THIS_MODULE, + .attach = unioxx5_attach, + .detach = unioxx5_detach }; COMEDI_INITCLEANUP(unioxx5_driver); -static int unioxx5_attach(struct comedi_device * dev, struct comedi_devconfig * it) +static int unioxx5_attach(struct comedi_device *dev, struct comedi_devconfig *it) { int iobase, i, n_subd; int id, num, ba; @@ -156,8 +156,8 @@ static int unioxx5_attach(struct comedi_device * dev, struct comedi_devconfig * return 0; } -static int unioxx5_subdev_read(struct comedi_device * dev, struct comedi_subdevice * subdev, - struct comedi_insn * insn, unsigned int * data) +static int unioxx5_subdev_read(struct comedi_device *dev, struct comedi_subdevice *subdev, + struct comedi_insn *insn, unsigned int *data) { struct unioxx5_subd_priv *usp = subdev->private; int channel, type; @@ -176,8 +176,8 @@ static int unioxx5_subdev_read(struct comedi_device * dev, struct comedi_subdevi return 1; } -static int unioxx5_subdev_write(struct comedi_device * dev, struct comedi_subdevice * subdev, - struct comedi_insn * insn, unsigned int * data) +static int unioxx5_subdev_write(struct comedi_device *dev, struct comedi_subdevice *subdev, + struct comedi_insn *insn, unsigned int *data) { struct unioxx5_subd_priv *usp = subdev->private; int channel, type; @@ -197,8 +197,8 @@ static int unioxx5_subdev_write(struct comedi_device * dev, struct comedi_subdev } /* for digital modules only */ -static int unioxx5_insn_config(struct comedi_device * dev, struct comedi_subdevice * subdev, - struct comedi_insn * insn, unsigned int * data) +static int unioxx5_insn_config(struct comedi_device *dev, struct comedi_subdevice *subdev, + struct comedi_insn *insn, unsigned int *data) { int channel_offset, flags, channel = CR_CHAN(insn->chanspec), type; struct unioxx5_subd_priv *usp = subdev->private; @@ -213,7 +213,8 @@ static int unioxx5_insn_config(struct comedi_device * dev, struct comedi_subdevi return -1; } - if ((channel_offset = __unioxx5_define_chan_offset(channel)) < 0) { + channel_offset = __unioxx5_define_chan_offset(channel); + if (channel_offset < 0) { printk(KERN_ERR "comedi%d: undefined channel %d. channel range is 0 .. 23\n", dev->minor, channel); @@ -247,7 +248,7 @@ static int unioxx5_insn_config(struct comedi_device * dev, struct comedi_subdevi return 0; } -static int unioxx5_detach(struct comedi_device * dev) +static int unioxx5_detach(struct comedi_device *dev) { int i; struct comedi_subdevice *subdev; @@ -264,7 +265,7 @@ static int unioxx5_detach(struct comedi_device * dev) } /* initializing subdevice with given address */ -static int __unioxx5_subdev_init(struct comedi_subdevice * subdev, int subdev_iobase, +static int __unioxx5_subdev_init(struct comedi_subdevice *subdev, int subdev_iobase, int minor) { struct unioxx5_subd_priv *usp; @@ -275,8 +276,9 @@ static int __unioxx5_subdev_init(struct comedi_subdevice * subdev, int subdev_io return -EIO; } - if ((usp = (struct unioxx5_subd_priv *) kzalloc(sizeof(*usp), - GFP_KERNEL)) == NULL) { + usp = (struct unioxx5_subd_priv *) kzalloc(sizeof(*usp), GFP_KERNEL); + + if (usp == NULL) { printk(KERN_ERR "comedi%d: erorr! --> out of memory!\n", minor); return -1; } @@ -309,7 +311,7 @@ static int __unioxx5_subdev_init(struct comedi_subdevice * subdev, int subdev_io usp->usp_module_type[i] = inb(subdev_iobase + 6); printk(" [%d] 0x%02x |", i, usp->usp_module_type[i]); - comedi_udelay(1); + udelay(1); } printk("\n"); @@ -330,13 +332,14 @@ static int __unioxx5_subdev_init(struct comedi_subdevice * subdev, int subdev_io return 0; } -static int __unioxx5_digital_write(struct unioxx5_subd_priv * usp, unsigned int * data, +static int __unioxx5_digital_write(struct unioxx5_subd_priv *usp, unsigned int *data, int channel, int minor) { int channel_offset, val; int mask = 1 << (channel & 0x07); - if ((channel_offset = __unioxx5_define_chan_offset(channel)) < 0) { + channel_offset = __unioxx5_define_chan_offset(channel); + if (channel_offset < 0) { printk(KERN_ERR "comedi%d: undefined channel %d. channel range is 0 .. 23\n", minor, channel); @@ -357,12 +360,13 @@ static int __unioxx5_digital_write(struct unioxx5_subd_priv * usp, unsigned int } /* function for digital reading */ -static int __unioxx5_digital_read(struct unioxx5_subd_priv * usp, unsigned int * data, +static int __unioxx5_digital_read(struct unioxx5_subd_priv *usp, unsigned int *data, int channel, int minor) { int channel_offset, mask = 1 << (channel & 0x07); - if ((channel_offset = __unioxx5_define_chan_offset(channel)) < 0) { + channel_offset = __unioxx5_define_chan_offset(channel); + if (channel_offset < 0) { printk(KERN_ERR "comedi%d: undefined channel %d. channel range is 0 .. 23\n", minor, channel); @@ -380,7 +384,7 @@ static int __unioxx5_digital_read(struct unioxx5_subd_priv * usp, unsigned int * } #if 0 /* not used? */ -static void __unioxx5_digital_config(struct unioxx5_subd_priv * usp, int mode) +static void __unioxx5_digital_config(struct unioxx5_subd_priv *usp, int mode) { int i, mask; @@ -396,7 +400,7 @@ static void __unioxx5_digital_config(struct unioxx5_subd_priv * usp, int mode) } #endif -static int __unioxx5_analog_write(struct unioxx5_subd_priv * usp, unsigned int * data, +static int __unioxx5_analog_write(struct unioxx5_subd_priv *usp, unsigned int *data, int channel, int minor) { int module, i; @@ -418,7 +422,7 @@ static int __unioxx5_analog_write(struct unioxx5_subd_priv * usp, unsigned int * /* saving major byte */ usp->usp_extra_data[module][i] = (unsigned char)((*data & 0xFF00) >> 8); - //while(!((inb(usp->usp_iobase + 0)) & TxBE)); + /* while(!((inb(usp->usp_iobase + 0)) & TxBE)); */ outb(module + 1, usp->usp_iobase + 5); /* sending module number to card(1 .. 12) */ outb('W', usp->usp_iobase + 6); /* sends (W)rite command to module */ @@ -431,7 +435,7 @@ static int __unioxx5_analog_write(struct unioxx5_subd_priv * usp, unsigned int * return 1; } -static int __unioxx5_analog_read(struct unioxx5_subd_priv * usp, unsigned int * data, +static int __unioxx5_analog_read(struct unioxx5_subd_priv *usp, unsigned int *data, int channel, int minor) { int module_no, read_ch; @@ -471,7 +475,7 @@ static int __unioxx5_analog_read(struct unioxx5_subd_priv * usp, unsigned int * } /* configure channels for analog i/o (even to output, odd to input) */ -static void __unioxx5_analog_config(struct unioxx5_subd_priv * usp, int channel) +static void __unioxx5_analog_config(struct unioxx5_subd_priv *usp, int channel) { int chan_a, chan_b, conf, channel_offset; diff --git a/drivers/staging/comedi/drivers/usbdux.c b/drivers/staging/comedi/drivers/usbdux.c index d0b59e98314b..171a6f2ff74f 100644 --- a/drivers/staging/comedi/drivers/usbdux.c +++ b/drivers/staging/comedi/drivers/usbdux.c @@ -509,14 +509,19 @@ static void usbduxsub_ai_IsocIrq(struct urb *urb) for (i = 0; i < n; i++) { /* transfer data */ if (CR_RANGE(s->async->cmd.chanlist[i]) <= 1) { - comedi_buf_put + err = comedi_buf_put (s->async, - le16_to_cpu(this_usbduxsub-> - inBuffer[i]) ^ 0x800); + le16_to_cpu(this_usbduxsub-> + inBuffer[i]) ^ 0x800); } else { - comedi_buf_put + err = comedi_buf_put (s->async, - le16_to_cpu(this_usbduxsub->inBuffer[i])); + le16_to_cpu(this_usbduxsub->inBuffer[i])); + } + if (unlikely(err == 0)) { + /* buffer overflow */ + usbdux_ai_stop(this_usbduxsub, 0); + return; } } /* tell comedi that data is there */ @@ -809,32 +814,56 @@ static int usbduxsub_upload(struct usbduxsub *usbduxsub, return 0; } -static int firmwareUpload(struct usbduxsub *usbduxsub, uint8_t *firmwareBinary, +#define FIRMWARE_MAX_LEN 0x2000 + +static int firmwareUpload(struct usbduxsub *usbduxsub, + const u8 *firmwareBinary, int sizeFirmware) { int ret; + uint8_t *fwBuf; if (!firmwareBinary) return 0; + if (sizeFirmware>FIRMWARE_MAX_LEN) { + dev_err(&usbduxsub->interface->dev, + "comedi_: usbdux firmware binary it too large for FX2.\n"); + return -ENOMEM; + } + + /* we generate a local buffer for the firmware */ + fwBuf = kzalloc(sizeFirmware, GFP_KERNEL); + if (!fwBuf) { + dev_err(&usbduxsub->interface->dev, + "comedi_: mem alloc for firmware failed\n"); + return -ENOMEM; + } + memcpy(fwBuf,firmwareBinary,sizeFirmware); + ret = usbduxsub_stop(usbduxsub); if (ret < 0) { dev_err(&usbduxsub->interface->dev, "comedi_: can not stop firmware\n"); + kfree(fwBuf); return ret; } - ret = usbduxsub_upload(usbduxsub, firmwareBinary, 0, sizeFirmware); + + ret = usbduxsub_upload(usbduxsub, fwBuf, 0, sizeFirmware); if (ret < 0) { dev_err(&usbduxsub->interface->dev, "comedi_: firmware upload failed\n"); + kfree(fwBuf); return ret; } ret = usbduxsub_start(usbduxsub); if (ret < 0) { dev_err(&usbduxsub->interface->dev, "comedi_: can not start firmware\n"); + kfree(fwBuf); return ret; } + kfree(fwBuf); return 0; } @@ -2260,134 +2289,6 @@ static void tidy_up(struct usbduxsub *usbduxsub_tmp) usbduxsub_tmp->pwm_cmd_running = 0; } -static unsigned hex2unsigned(char *h) -{ - unsigned hi, lo; - - if (h[0] > '9') - hi = h[0] - 'A' + 0x0a; - else - hi = h[0] - '0'; - - if (h[1] > '9') - lo = h[1] - 'A' + 0x0a; - else - lo = h[1] - '0'; - - return hi * 0x10 + lo; -} - -/* for FX2 */ -#define FIRMWARE_MAX_LEN 0x2000 - -/* taken from David Brownell's fxload and adjusted for this driver */ -static int read_firmware(struct usbduxsub *usbduxsub, const void *firmwarePtr, - long size) -{ - struct device *dev = &usbduxsub->interface->dev; - int i = 0; - unsigned char *fp = (char *)firmwarePtr; - unsigned char *firmwareBinary; - int res = 0; - int maxAddr = 0; - - firmwareBinary = kzalloc(FIRMWARE_MAX_LEN, GFP_KERNEL); - if (!firmwareBinary) { - dev_err(dev, "comedi_: mem alloc for firmware failed\n"); - return -ENOMEM; - } - - for (;;) { - char buf[256], *cp; - char type; - int len; - int idx, off; - int j = 0; - - /* get one line */ - while ((i < size) && (fp[i] != 13) && (fp[i] != 10)) { - buf[j] = fp[i]; - i++; - j++; - if (j >= sizeof(buf)) { - dev_err(dev, "comedi_: bogus firmware file!\n"); - kfree(firmwareBinary); - return -1; - } - } - /* get rid of LF/CR/... */ - while ((i < size) && ((fp[i] == 13) || (fp[i] == 10) - || (fp[i] == 0))) { - i++; - } - - buf[j] = 0; - /* dev_dbg(dev, "comedi_: buf=%s\n", buf); */ - - /* - * EXTENSION: - * "# comment-till-end-of-line", for copyrights etc - */ - if (buf[0] == '#') - continue; - - if (buf[0] != ':') { - dev_err(dev, "comedi_: upload: not an ihex record: %s", - buf); - kfree(firmwareBinary); - return -EFAULT; - } - - /* Read the length field (up to 16 bytes) */ - len = hex2unsigned(buf + 1); - - /* Read the target offset */ - off = (hex2unsigned(buf + 3) * 0x0100) + hex2unsigned(buf + 5); - - if ((off + len) > maxAddr) - maxAddr = off + len; - - - if (maxAddr >= FIRMWARE_MAX_LEN) { - dev_err(dev, "comedi_: firmware upload goes " - "beyond FX2 RAM boundaries.\n"); - kfree(firmwareBinary); - return -EFAULT; - } - /* dev_dbg(dev, "comedi_: off=%x, len=%x:\n", off, len); */ - - /* Read the record type */ - type = hex2unsigned(buf + 7); - - /* If this is an EOF record, then make it so. */ - if (type == 1) - break; - - - if (type != 0) { - dev_err(dev, "comedi_: unsupported record type: %u\n", - type); - kfree(firmwareBinary); - return -EFAULT; - } - - for (idx = 0, cp = buf + 9; idx < len; idx += 1, cp += 2) { - firmwareBinary[idx + off] = hex2unsigned(cp); - /*printk("%02x ",firmwareBinary[idx+off]); */ - } - /*printk("\n"); */ - - if (i >= size) { - dev_err(dev, "comedi_: unexpected end of hex file\n"); - break; - } - - } - res = firmwareUpload(usbduxsub, firmwareBinary, maxAddr + 1); - kfree(firmwareBinary); - return res; -} - static void usbdux_firmware_request_complete_handler(const struct firmware *fw, void *context) { @@ -2405,7 +2306,7 @@ static void usbdux_firmware_request_complete_handler(const struct firmware *fw, * we need to upload the firmware here because fw will be * freed once we've left this function */ - ret = read_firmware(usbduxsub_tmp, fw->data, fw->size); + ret = firmwareUpload(usbduxsub_tmp, fw->data, fw->size); if (ret) { dev_err(&usbdev->dev, @@ -2662,11 +2563,13 @@ static int usbduxsub_probe(struct usb_interface *uinterf, ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, - "usbdux_firmware.hex", + "usbdux_firmware.bin", &udev->dev, usbduxsub + index, usbdux_firmware_request_complete_handler); + + if (ret) { dev_err(dev, "Could not load firmware (err=%d)\n", ret); return ret; @@ -2739,8 +2642,8 @@ static int usbdux_attach(struct comedi_device *dev, struct comedi_devconfig *it) /* trying to upload the firmware into the chip */ if (comedi_aux_data(it->options, 0) && it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH]) { - read_firmware(udev, comedi_aux_data(it->options, 0), - it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH]); + firmwareUpload(udev, comedi_aux_data(it->options, 0), + it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH]); } dev->board_name = BOARDNAME; diff --git a/drivers/staging/comedi/drivers/usbduxfast.c b/drivers/staging/comedi/drivers/usbduxfast.c index 2fb64de3f86b..939b53fa569c 100644 --- a/drivers/staging/comedi/drivers/usbduxfast.c +++ b/drivers/staging/comedi/drivers/usbduxfast.c @@ -314,7 +314,7 @@ static int usbduxfast_ai_cancel(struct comedi_device *dev, struct comedi_subdevi * analogue IN * interrupt service routine */ -static void usbduxfastsub_ai_Irq(struct urb *urb PT_REGS_ARG) +static void usbduxfastsub_ai_Irq(struct urb *urb) { int n, err; struct usbduxfastsub_s *udfs; @@ -406,7 +406,7 @@ static void usbduxfastsub_ai_Irq(struct urb *urb PT_REGS_ARG) udfs->ai_sample_count * sizeof(uint16_t)); usbduxfast_ai_stop(udfs, 0); - /* say comedi that the acquistion is over */ + /* tell comedi that the acquistion is over */ s->async->events |= COMEDI_CB_EOA; comedi_event(udfs->comedidev, s); return; @@ -414,8 +414,13 @@ static void usbduxfastsub_ai_Irq(struct urb *urb PT_REGS_ARG) udfs->ai_sample_count -= n; } /* write the full buffer to comedi */ - cfc_write_array_to_buffer(s, urb->transfer_buffer, - urb->actual_length); + err = cfc_write_array_to_buffer(s, urb->transfer_buffer, + urb->actual_length); + if (unlikely(err == 0)) { + /* buffer overflow */ + usbduxfast_ai_stop(udfs, 0); + return; + } /* tell comedi that data is there */ comedi_event(udfs->comedidev, s); @@ -524,33 +529,6 @@ static int usbduxfastsub_upload(struct usbduxfastsub_s *udfs, return 0; } -int firmwareUpload(struct usbduxfastsub_s *udfs, unsigned char *firmwareBinary, - int sizeFirmware) -{ - int ret; - - if (!firmwareBinary) - return 0; - - ret = usbduxfastsub_stop(udfs); - if (ret < 0) { - printk(KERN_ERR "comedi_: usbduxfast: can not stop firmware\n"); - return ret; - } - ret = usbduxfastsub_upload(udfs, firmwareBinary, 0, sizeFirmware); - if (ret < 0) { - printk(KERN_ERR "comedi_: usbduxfast: firmware upload failed\n"); - return ret; - } - ret = usbduxfastsub_start(udfs); - if (ret < 0) { - printk(KERN_ERR "comedi_: usbduxfast: can not start firmware\n"); - return ret; - } - - return 0; -} - int usbduxfastsub_submit_InURBs(struct usbduxfastsub_s *udfs) { int ret; @@ -1365,136 +1343,61 @@ static int usbduxfast_ai_insn_read(struct comedi_device *dev, return i; } -static unsigned hex2unsigned(char *h) -{ - unsigned hi, lo; - - if (h[0] > '9') - hi = h[0] - 'A' + 0x0a; - else - hi = h[0] - '0'; - - if (h[1] > '9') - lo = h[1] - 'A' + 0x0a; - else - lo = h[1] - '0'; - - return hi * 0x10 + lo; -} - -/* for FX2 */ #define FIRMWARE_MAX_LEN 0x2000 -/* - * taken from David Brownell's fxload and adjusted for this driver - */ -static int read_firmware(struct usbduxfastsub_s *udfs, const void *firmwarePtr, - long size) +static int firmwareUpload(struct usbduxfastsub_s *usbduxfastsub, + const u8 *firmwareBinary, + int sizeFirmware) { - int i = 0; - unsigned char *fp = (char *)firmwarePtr; - unsigned char *firmwareBinary; - int res = 0; - int maxAddr = 0; + int ret; + uint8_t *fwBuf; - firmwareBinary = kmalloc(FIRMWARE_MAX_LEN, GFP_KERNEL); - if (!firmwareBinary) { - printk(KERN_ERR "comedi_: usbduxfast: mem alloc for firmware " - " failed\n"); + if (!firmwareBinary) + return 0; + + if (sizeFirmware>FIRMWARE_MAX_LEN) { + dev_err(&usbduxfastsub->interface->dev, + "comedi_: usbduxfast firmware binary it too large for FX2.\n"); return -ENOMEM; } - for (;;) { - char buf[256], *cp; - char type; - int len; - int idx, off; - int j = 0; - - /* get one line */ - while ((i < size) && (fp[i] != 13) && (fp[i] != 10)) { - buf[j] = fp[i]; - i++; - j++; - if (j >= sizeof(buf)) { - printk(KERN_ERR "comedi_: usbduxfast: bogus " - "firmware file!\n"); - kfree(firmwareBinary); - return -1; - } - } - /* get rid of LF/CR/... */ - while ((i < size) && ((fp[i] == 13) || (fp[i] == 10) - || (fp[i] == 0))) - i++; - - buf[j] = 0; - /* printk("comedi_: buf=%s\n",buf); */ - - /* - * EXTENSION: "# comment-till-end-of-line", - * for copyrights etc - */ - if (buf[0] == '#') - continue; - - if (buf[0] != ':') { - printk(KERN_ERR "comedi_: usbduxfast: upload: not an " - "ihex record: %s", buf); - kfree(firmwareBinary); - return -EFAULT; - } - - /* Read the length field (up to 16 bytes) */ - len = hex2unsigned(buf + 1); - - /* Read the target offset */ - off = (hex2unsigned(buf + 3) * 0x0100) + hex2unsigned(buf + 5); - - if ((off + len) > maxAddr) - maxAddr = off + len; - - if (maxAddr >= FIRMWARE_MAX_LEN) { - printk(KERN_ERR "comedi_: usbduxfast: firmware upload " - "goes beyond FX2 RAM boundaries."); - kfree(firmwareBinary); - return -EFAULT; - } - /* printk("comedi_: usbduxfast: off=%x, len=%x:",off,len); */ - - /* Read the record type */ - type = hex2unsigned(buf + 7); - - /* If this is an EOF record, then make it so. */ - if (type == 1) - break; - - if (type != 0) { - printk(KERN_ERR "comedi_: usbduxfast: unsupported " - "record type: %u\n", type); - kfree(firmwareBinary); - return -EFAULT; - } - - for (idx = 0, cp = buf + 9; idx < len; idx += 1, cp += 2) { - firmwareBinary[idx + off] = hex2unsigned(cp); - /* printk("%02x ",firmwareBinary[idx+off]); */ - } - - /* printk("\n"); */ - - if (i >= size) { - printk(KERN_ERR "comedi_: usbduxfast: unexpected end " - "of hex file\n"); - break; - } - + /* we generate a local buffer for the firmware */ + fwBuf = kzalloc(sizeFirmware, GFP_KERNEL); + if (!fwBuf) { + dev_err(&usbduxfastsub->interface->dev, + "comedi_: mem alloc for firmware failed\n"); + return -ENOMEM; } - res = firmwareUpload(udfs, firmwareBinary, maxAddr + 1); - kfree(firmwareBinary); - return res; + memcpy(fwBuf,firmwareBinary,sizeFirmware); + + ret = usbduxfastsub_stop(usbduxfastsub); + if (ret < 0) { + dev_err(&usbduxfastsub->interface->dev, + "comedi_: can not stop firmware\n"); + kfree(fwBuf); + return ret; + } + + ret = usbduxfastsub_upload(usbduxfastsub, fwBuf, 0, sizeFirmware); + if (ret < 0) { + dev_err(&usbduxfastsub->interface->dev, + "comedi_: firmware upload failed\n"); + kfree(fwBuf); + return ret; + } + ret = usbduxfastsub_start(usbduxfastsub); + if (ret < 0) { + dev_err(&usbduxfastsub->interface->dev, + "comedi_: can not start firmware\n"); + kfree(fwBuf); + return ret; + } + kfree(fwBuf); + return 0; } + + static void tidy_up(struct usbduxfastsub_s *udfs) { #ifdef CONFIG_COMEDI_DEBUG @@ -1544,7 +1447,7 @@ static void usbduxfast_firmware_request_complete_handler(const struct firmware * * we need to upload the firmware here because fw will be * freed once we've left this function */ - ret = read_firmware(usbduxfastsub_tmp, fw->data, fw->size); + ret = firmwareUpload(usbduxfastsub_tmp, fw->data, fw->size); if (ret) { dev_err(&usbdev->dev, @@ -1666,7 +1569,7 @@ static int usbduxfastsub_probe(struct usb_interface *uinterf, ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, - "usbduxfast_firmware.hex", + "usbduxfast_firmware.bin", &udev->dev, usbduxfastsub + index, usbduxfast_firmware_request_complete_handler); @@ -1751,9 +1654,9 @@ static int usbduxfast_attach(struct comedi_device *dev, struct comedi_devconfig /* trying to upload the firmware into the chip */ if (comedi_aux_data(it->options, 0) && it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH]) { - read_firmware(&usbduxfastsub[index], - comedi_aux_data(it->options, 0), - it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH]); + firmwareUpload(&usbduxfastsub[index], + comedi_aux_data(it->options, 0), + it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH]); } dev->board_name = BOARDNAME; diff --git a/drivers/staging/comedi/drivers/vmk80xx.c b/drivers/staging/comedi/drivers/vmk80xx.c new file mode 100644 index 000000000000..9de43b5310d7 --- /dev/null +++ b/drivers/staging/comedi/drivers/vmk80xx.c @@ -0,0 +1,1399 @@ +/* + comedi/drivers/vmk80xx.c + Velleman USB Board Low-Level Driver + + Copyright (C) 2009 Manuel Gebele , Germany + + COMEDI - Linux Control and Measurement Device Interface + Copyright (C) 2000 David A. Schleef + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ +/* +Driver: vmk80xx +Description: Velleman USB Board Low-Level Driver +Devices: K8055/K8061 aka VM110/VM140 +Author: Manuel Gebele +Updated: Sun, 10 May 2009 11:14:59 +0200 +Status: works + +Supports: + - analog input + - analog output + - digital input + - digital output + - counter + - pwm +*/ +/* +Changelog: + +0.8.81 -3- code completely rewritten (adjust driver logic) +0.8.81 -2- full support for K8061 +0.8.81 -1- fix some mistaken among others the number of + supported boards and I/O handling + +0.7.76 -4- renamed to vmk80xx +0.7.76 -3- detect K8061 (only theoretically supported) +0.7.76 -2- code completely rewritten (adjust driver logic) +0.7.76 -1- support for digital and counter subdevice +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../comedidev.h" + +MODULE_AUTHOR("Manuel Gebele "); +MODULE_DESCRIPTION("Velleman USB Board Low-Level Driver"); +MODULE_SUPPORTED_DEVICE("K8055/K8061 aka VM110/VM140"); +MODULE_VERSION("0.8.01"); +MODULE_LICENSE("GPL"); + +enum { + DEVICE_VMK8055, + DEVICE_VMK8061 +}; + +static struct usb_device_id vmk80xx_id_table[] = { + { USB_DEVICE(0x10cf, 0x5500), .driver_info = DEVICE_VMK8055 }, + { USB_DEVICE(0x10cf, 0x5501), .driver_info = DEVICE_VMK8055 }, + { USB_DEVICE(0x10cf, 0x5502), .driver_info = DEVICE_VMK8055 }, + { USB_DEVICE(0x10cf, 0x5503), .driver_info = DEVICE_VMK8055 }, + { USB_DEVICE(0x10cf, 0x8061), .driver_info = DEVICE_VMK8061 }, + { USB_DEVICE(0x10cf, 0x8062), .driver_info = DEVICE_VMK8061 }, + { USB_DEVICE(0x10cf, 0x8063), .driver_info = DEVICE_VMK8061 }, + { USB_DEVICE(0x10cf, 0x8064), .driver_info = DEVICE_VMK8061 }, + { USB_DEVICE(0x10cf, 0x8065), .driver_info = DEVICE_VMK8061 }, + { USB_DEVICE(0x10cf, 0x8066), .driver_info = DEVICE_VMK8061 }, + { USB_DEVICE(0x10cf, 0x8067), .driver_info = DEVICE_VMK8061 }, + { USB_DEVICE(0x10cf, 0x8068), .driver_info = DEVICE_VMK8061 }, + { } /* terminating entry */ +}; + +MODULE_DEVICE_TABLE(usb, vmk80xx_id_table); + +#define VMK8055_DI_REG 0x00 +#define VMK8055_DO_REG 0x01 +#define VMK8055_AO1_REG 0x02 +#define VMK8055_AO2_REG 0x03 +#define VMK8055_AI1_REG 0x02 +#define VMK8055_AI2_REG 0x03 +#define VMK8055_CNT1_REG 0x04 +#define VMK8055_CNT2_REG 0x06 + +#define VMK8061_CH_REG 0x01 +#define VMK8061_DI_REG 0x01 +#define VMK8061_DO_REG 0x01 +#define VMK8061_PWM_REG1 0x01 +#define VMK8061_PWM_REG2 0x02 +#define VMK8061_CNT_REG 0x02 +#define VMK8061_AO_REG 0x02 +#define VMK8061_AI_REG1 0x02 +#define VMK8061_AI_REG2 0x03 + +#define VMK8055_CMD_RST 0x00 +#define VMK8055_CMD_DEB1_TIME 0x01 +#define VMK8055_CMD_DEB2_TIME 0x02 +#define VMK8055_CMD_RST_CNT1 0x03 +#define VMK8055_CMD_RST_CNT2 0x04 +#define VMK8055_CMD_WRT_AD 0x05 + +#define VMK8061_CMD_RD_AI 0x00 +#define VMK8061_CMR_RD_ALL_AI 0x01 /* !non-active! */ +#define VMK8061_CMD_SET_AO 0x02 +#define VMK8061_CMD_SET_ALL_AO 0x03 /* !non-active! */ +#define VMK8061_CMD_OUT_PWM 0x04 +#define VMK8061_CMD_RD_DI 0x05 +#define VMK8061_CMD_DO 0x06 /* !non-active! */ +#define VMK8061_CMD_CLR_DO 0x07 +#define VMK8061_CMD_SET_DO 0x08 +#define VMK8061_CMD_RD_CNT 0x09 /* TODO: completely pointless? */ +#define VMK8061_CMD_RST_CNT 0x0a /* TODO: completely pointless? */ +#define VMK8061_CMD_RD_VERSION 0x0b /* internal usage */ +#define VMK8061_CMD_RD_JMP_STAT 0x0c /* TODO: not implemented yet */ +#define VMK8061_CMD_RD_PWR_STAT 0x0d /* internal usage */ +#define VMK8061_CMD_RD_DO 0x0e +#define VMK8061_CMD_RD_AO 0x0f +#define VMK8061_CMD_RD_PWM 0x10 + +#define VMK80XX_MAX_BOARDS COMEDI_NUM_BOARD_MINORS + +#define TRANS_OUT_BUSY 1 +#define TRANS_IN_BUSY 2 +#define TRANS_IN_RUNNING 3 + +#define IC3_VERSION (1 << 0) +#define IC6_VERSION (1 << 1) + +#define URB_RCV_FLAG (1 << 0) +#define URB_SND_FLAG (1 << 1) + +#define CONFIG_VMK80XX_DEBUG +#undef CONFIG_VMK80XX_DEBUG + +#ifdef CONFIG_VMK80XX_DEBUG + static int dbgvm = 1; +#else + static int dbgvm; +#endif + +#ifdef CONFIG_COMEDI_DEBUG + static int dbgcm = 1; +#else + static int dbgcm; +#endif + +#define dbgvm(fmt, arg...) \ +do { \ + if (dbgvm) \ + printk(KERN_DEBUG fmt, ##arg); \ +} while (0) + +#define dbgcm(fmt, arg...) \ +do { \ + if (dbgcm) \ + printk(KERN_DEBUG fmt, ##arg); \ +} while (0) + +enum vmk80xx_model { + VMK8055_MODEL, + VMK8061_MODEL +}; + +struct firmware_version { + unsigned char ic3_vers[32]; /* USB-Controller */ + unsigned char ic6_vers[32]; /* CPU */ +}; + +static const struct comedi_lrange vmk8055_range = { + 1, { UNI_RANGE(5) } +}; + +static const struct comedi_lrange vmk8061_range = { + 2, { UNI_RANGE(5), UNI_RANGE(10) } +}; + +struct vmk80xx_board { + const char *name; + enum vmk80xx_model model; + const struct comedi_lrange *range; + __u8 ai_chans; + __le16 ai_bits; + __u8 ao_chans; + __le16 ao_bits; + __u8 di_chans; + __le16 di_bits; + __u8 do_chans; + __le16 do_bits; + __u8 cnt_chans; + __le16 cnt_bits; + __u8 pwm_chans; + __le16 pwm_bits; +}; + +enum { + VMK80XX_SUBD_AI, + VMK80XX_SUBD_AO, + VMK80XX_SUBD_DI, + VMK80XX_SUBD_DO, + VMK80XX_SUBD_CNT, + VMK80XX_SUBD_PWM, +}; + +struct vmk80xx_usb { + struct usb_device *udev; + struct usb_interface *intf; + struct usb_endpoint_descriptor *ep_rx; + struct usb_endpoint_descriptor *ep_tx; + struct usb_anchor rx_anchor; + struct usb_anchor tx_anchor; + struct vmk80xx_board board; + struct firmware_version fw; + struct semaphore limit_sem; + wait_queue_head_t read_wait; + wait_queue_head_t write_wait; + unsigned char *usb_rx_buf; + unsigned char *usb_tx_buf; + unsigned long flags; + int probed; + int attached; + int count; +}; + +static struct vmk80xx_usb vmb[VMK80XX_MAX_BOARDS]; + +static DEFINE_MUTEX(glb_mutex); + +static void vmk80xx_tx_callback(struct urb *urb) +{ + struct vmk80xx_usb *dev = urb->context; + int stat = urb->status; + + dbgvm("vmk80xx: %s\n", __func__); + + if (stat && !(stat == -ENOENT + || stat == -ECONNRESET + || stat == -ESHUTDOWN)) + dbgcm("comedi#: vmk80xx: %s - nonzero urb status (%d)\n", + __func__, stat); + + if (!test_bit(TRANS_OUT_BUSY, &dev->flags)) + return; + + clear_bit(TRANS_OUT_BUSY, &dev->flags); + + wake_up_interruptible(&dev->write_wait); +} + +static void vmk80xx_rx_callback(struct urb *urb) +{ + struct vmk80xx_usb *dev = urb->context; + int stat = urb->status; + + dbgvm("vmk80xx: %s\n", __func__); + + switch (stat) { + case 0: + break; + case -ENOENT: + case -ECONNRESET: + case -ESHUTDOWN: + break; + default: + dbgcm("comedi#: vmk80xx: %s - nonzero urb status (%d)\n", + __func__, stat); + goto resubmit; + } + + goto exit; +resubmit: + if (test_bit(TRANS_IN_RUNNING, &dev->flags) && dev->intf) { + usb_anchor_urb(urb, &dev->rx_anchor); + + if (!usb_submit_urb(urb, GFP_KERNEL)) + goto exit; + + err("comedi#: vmk80xx: %s - submit urb failed\n", __func__); + + usb_unanchor_urb(urb); + } +exit: + clear_bit(TRANS_IN_BUSY, &dev->flags); + + wake_up_interruptible(&dev->read_wait); +} + +static int vmk80xx_check_data_link(struct vmk80xx_usb *dev) +{ + unsigned int tx_pipe, rx_pipe; + unsigned char tx[1], rx[2]; + + dbgvm("vmk80xx: %s\n", __func__); + + tx_pipe = usb_sndbulkpipe(dev->udev, 0x01); + rx_pipe = usb_rcvbulkpipe(dev->udev, 0x81); + + tx[0] = VMK8061_CMD_RD_PWR_STAT; + + /* Check that IC6 (PIC16F871) is powered and + * running and the data link between IC3 and + * IC6 is working properly */ + usb_bulk_msg(dev->udev, tx_pipe, tx, 1, NULL, + dev->ep_tx->bInterval); + usb_bulk_msg(dev->udev, rx_pipe, rx, 2, NULL, + HZ * 10); + + return (int)rx[1]; +} + +static void vmk80xx_read_eeprom(struct vmk80xx_usb *dev, int flag) +{ + unsigned int tx_pipe, rx_pipe; + unsigned char tx[1], rx[64]; + int cnt; + + dbgvm("vmk80xx: %s\n", __func__); + + tx_pipe = usb_sndbulkpipe(dev->udev, 0x01); + rx_pipe = usb_rcvbulkpipe(dev->udev, 0x81); + + tx[0] = VMK8061_CMD_RD_VERSION; + + /* Read the firmware version info of IC3 and + * IC6 from the internal EEPROM of the IC */ + usb_bulk_msg(dev->udev, tx_pipe, tx, 1, NULL, + dev->ep_tx->bInterval); + usb_bulk_msg(dev->udev, rx_pipe, rx, 64, &cnt, + HZ * 10); + + rx[cnt] = '\0'; + + if (flag & IC3_VERSION) + strncpy(dev->fw.ic3_vers, rx + 1, 24); + else /* IC6_VERSION */ + strncpy(dev->fw.ic6_vers, rx + 25, 24); +} + +static int vmk80xx_reset_device(struct vmk80xx_usb *dev) +{ + struct urb *urb; + unsigned int tx_pipe; + int ival; + size_t size; + + dbgvm("vmk80xx: %s\n", __func__); + + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) + return -ENOMEM; + + tx_pipe = usb_sndintpipe(dev->udev, 0x01); + + ival = dev->ep_tx->bInterval; + size = le16_to_cpu(dev->ep_tx->wMaxPacketSize); + + dev->usb_tx_buf[0] = VMK8055_CMD_RST; + dev->usb_tx_buf[1] = 0x00; + dev->usb_tx_buf[2] = 0x00; + dev->usb_tx_buf[3] = 0x00; + dev->usb_tx_buf[4] = 0x00; + dev->usb_tx_buf[5] = 0x00; + dev->usb_tx_buf[6] = 0x00; + dev->usb_tx_buf[7] = 0x00; + + usb_fill_int_urb(urb, dev->udev, tx_pipe, dev->usb_tx_buf, + size, vmk80xx_tx_callback, dev, ival); + + usb_anchor_urb(urb, &dev->tx_anchor); + + return usb_submit_urb(urb, GFP_KERNEL); +} + +static void vmk80xx_build_int_urb(struct urb *urb, int flag) +{ + struct vmk80xx_usb *dev = urb->context; + __u8 rx_addr, tx_addr; + unsigned int pipe; + unsigned char *buf; + size_t size; + void (*callback)(struct urb *); + int ival; + + dbgvm("vmk80xx: %s\n", __func__); + + if (flag & URB_RCV_FLAG) { + rx_addr = dev->ep_rx->bEndpointAddress; + pipe = usb_rcvintpipe(dev->udev, rx_addr); + buf = dev->usb_rx_buf; + size = le16_to_cpu(dev->ep_rx->wMaxPacketSize); + callback = vmk80xx_rx_callback; + ival = dev->ep_rx->bInterval; + } else { /* URB_SND_FLAG */ + tx_addr = dev->ep_tx->bEndpointAddress; + pipe = usb_sndintpipe(dev->udev, tx_addr); + buf = dev->usb_tx_buf; + size = le16_to_cpu(dev->ep_tx->wMaxPacketSize); + callback = vmk80xx_tx_callback; + ival = dev->ep_tx->bInterval; + } + + usb_fill_int_urb(urb, dev->udev, pipe, buf, + size, callback, dev, ival); +} + +static void vmk80xx_do_bulk_msg(struct vmk80xx_usb *dev) +{ + __u8 tx_addr, rx_addr; + unsigned int tx_pipe, rx_pipe; + size_t size; + + dbgvm("vmk80xx: %s\n", __func__); + + set_bit(TRANS_IN_BUSY, &dev->flags); + set_bit(TRANS_OUT_BUSY, &dev->flags); + + tx_addr = dev->ep_tx->bEndpointAddress; + rx_addr = dev->ep_rx->bEndpointAddress; + tx_pipe = usb_sndbulkpipe(dev->udev, tx_addr); + rx_pipe = usb_rcvbulkpipe(dev->udev, rx_addr); + + /* The max packet size attributes of the K8061 + * input/output endpoints are identical */ + size = le16_to_cpu(dev->ep_tx->wMaxPacketSize); + + usb_bulk_msg(dev->udev, tx_pipe, dev->usb_tx_buf, + size, NULL, dev->ep_tx->bInterval); + usb_bulk_msg(dev->udev, rx_pipe, dev->usb_rx_buf, + size, NULL, HZ * 10); + + clear_bit(TRANS_OUT_BUSY, &dev->flags); + clear_bit(TRANS_IN_BUSY, &dev->flags); +} + +static int vmk80xx_read_packet(struct vmk80xx_usb *dev) +{ + struct urb *urb; + int retval; + + dbgvm("vmk80xx: %s\n", __func__); + + if (!dev->intf) + return -ENODEV; + + /* Only useful for interrupt transfers */ + if (test_bit(TRANS_IN_BUSY, &dev->flags)) + if (wait_event_interruptible(dev->read_wait, + !test_bit(TRANS_IN_BUSY, &dev->flags))) + return -ERESTART; + + if (dev->board.model == VMK8061_MODEL) { + vmk80xx_do_bulk_msg(dev); + + return 0; + } + + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) + return -ENOMEM; + + urb->context = dev; + vmk80xx_build_int_urb(urb, URB_RCV_FLAG); + + set_bit(TRANS_IN_RUNNING, &dev->flags); + set_bit(TRANS_IN_BUSY, &dev->flags); + + usb_anchor_urb(urb, &dev->rx_anchor); + + retval = usb_submit_urb(urb, GFP_KERNEL); + if (!retval) + goto exit; + + clear_bit(TRANS_IN_RUNNING, &dev->flags); + usb_unanchor_urb(urb); + +exit: + usb_free_urb(urb); + + return retval; +} + +static int vmk80xx_write_packet(struct vmk80xx_usb *dev, int cmd) +{ + struct urb *urb; + int retval; + + dbgvm("vmk80xx: %s\n", __func__); + + if (!dev->intf) + return -ENODEV; + + if (test_bit(TRANS_OUT_BUSY, &dev->flags)) + if (wait_event_interruptible(dev->write_wait, + !test_bit(TRANS_OUT_BUSY, &dev->flags))) + return -ERESTART; + + if (dev->board.model == VMK8061_MODEL) { + dev->usb_tx_buf[0] = cmd; + vmk80xx_do_bulk_msg(dev); + + return 0; + } + + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) + return -ENOMEM; + + urb->context = dev; + vmk80xx_build_int_urb(urb, URB_SND_FLAG); + + set_bit(TRANS_OUT_BUSY, &dev->flags); + + usb_anchor_urb(urb, &dev->tx_anchor); + + dev->usb_tx_buf[0] = cmd; + + retval = usb_submit_urb(urb, GFP_KERNEL); + if (!retval) + goto exit; + + clear_bit(TRANS_OUT_BUSY, &dev->flags); + usb_unanchor_urb(urb); + +exit: + usb_free_urb(urb); + + return retval; +} + +#define DIR_IN 1 +#define DIR_OUT 2 + +#define rudimentary_check(dir) \ +do { \ + if (!dev) \ + return -EFAULT; \ + if (!dev->probed) \ + return -ENODEV; \ + if (!dev->attached) \ + return -ENODEV; \ + if ((dir) & DIR_IN) { \ + if (test_bit(TRANS_IN_BUSY, &dev->flags)) \ + return -EBUSY; \ + } else { /* DIR_OUT */ \ + if (test_bit(TRANS_OUT_BUSY, &dev->flags)) \ + return -EBUSY; \ + } \ +} while (0) + +static int vmk80xx_ai_rinsn(struct comedi_device *cdev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + struct vmk80xx_usb *dev = cdev->private; + int chan, reg[2]; + int n; + + dbgvm("vmk80xx: %s\n", __func__); + + rudimentary_check(DIR_IN); + + down(&dev->limit_sem); + chan = CR_CHAN(insn->chanspec); + + switch (dev->board.model) { + case VMK8055_MODEL: + if (!chan) + reg[0] = VMK8055_AI1_REG; + else + reg[0] = VMK8055_AI2_REG; + break; + case VMK8061_MODEL: + reg[0] = VMK8061_AI_REG1; + reg[1] = VMK8061_AI_REG2; + dev->usb_tx_buf[0] = VMK8061_CMD_RD_AI; + dev->usb_tx_buf[VMK8061_CH_REG] = chan; + break; + } + + for (n = 0; n < insn->n; n++) { + if (vmk80xx_read_packet(dev)) + break; + + if (dev->board.model == VMK8055_MODEL) { + data[n] = dev->usb_rx_buf[reg[0]]; + continue; + } + + /* VMK8061_MODEL */ + data[n] = dev->usb_rx_buf[reg[0]] + 256 * + dev->usb_rx_buf[reg[1]]; + } + + up(&dev->limit_sem); + + return n; +} + +static int vmk80xx_ao_winsn(struct comedi_device *cdev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + struct vmk80xx_usb *dev = cdev->private; + int chan, cmd, reg; + int n; + + dbgvm("vmk80xx: %s\n", __func__); + + rudimentary_check(DIR_OUT); + + down(&dev->limit_sem); + chan = CR_CHAN(insn->chanspec); + + switch (dev->board.model) { + case VMK8055_MODEL: + cmd = VMK8055_CMD_WRT_AD; + if (!chan) + reg = VMK8055_AO1_REG; + else + reg = VMK8055_AO2_REG; + break; + default: /* NOTE: avoid compiler warnings */ + cmd = VMK8061_CMD_SET_AO; + reg = VMK8061_AO_REG; + dev->usb_tx_buf[VMK8061_CH_REG] = chan; + break; + } + + for (n = 0; n < insn->n; n++) { + dev->usb_tx_buf[reg] = data[n]; + + if (vmk80xx_write_packet(dev, cmd)) + break; + } + + up(&dev->limit_sem); + + return n; +} + +static int vmk80xx_ao_rinsn(struct comedi_device *cdev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + struct vmk80xx_usb *dev = cdev->private; + int chan, reg; + int n; + + dbgvm("vmk80xx: %s\n", __func__); + + rudimentary_check(DIR_IN); + + down(&dev->limit_sem); + chan = CR_CHAN(insn->chanspec); + + reg = VMK8061_AO_REG - 1; + + dev->usb_tx_buf[0] = VMK8061_CMD_RD_AO; + + for (n = 0; n < insn->n; n++) { + if (vmk80xx_read_packet(dev)) + break; + + data[n] = dev->usb_rx_buf[reg+chan]; + } + + up(&dev->limit_sem); + + return n; +} + +static int vmk80xx_di_rinsn(struct comedi_device *cdev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + struct vmk80xx_usb *dev = cdev->private; + int chan; + unsigned char *rx_buf; + int reg, inp; + int n; + + dbgvm("vmk80xx: %s\n", __func__); + + rudimentary_check(DIR_IN); + + down(&dev->limit_sem); + chan = CR_CHAN(insn->chanspec); + + rx_buf = dev->usb_rx_buf; + + if (dev->board.model == VMK8061_MODEL) { + reg = VMK8061_DI_REG; + dev->usb_tx_buf[0] = VMK8061_CMD_RD_DI; + } else + reg = VMK8055_DI_REG; + + for (n = 0; n < insn->n; n++) { + if (vmk80xx_read_packet(dev)) + break; + + if (dev->board.model == VMK8055_MODEL) + inp = (((rx_buf[reg] >> 4) & 0x03) | + ((rx_buf[reg] << 2) & 0x04) | + ((rx_buf[reg] >> 3) & 0x18)); + else + inp = rx_buf[reg]; + + data[n] = ((inp & (1 << chan)) > 0); + } + + up(&dev->limit_sem); + + return n; +} + +static int vmk80xx_do_winsn(struct comedi_device *cdev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + + struct vmk80xx_usb *dev = cdev->private; + int chan; + unsigned char *tx_buf; + int reg, cmd; + int n; + + dbgvm("vmk80xx: %s\n", __func__); + + rudimentary_check(DIR_OUT); + + down(&dev->limit_sem); + chan = CR_CHAN(insn->chanspec); + + tx_buf = dev->usb_tx_buf; + + for (n = 0; n < insn->n; n++) { + if (dev->board.model == VMK8055_MODEL) { + reg = VMK8055_DO_REG; + cmd = VMK8055_CMD_WRT_AD; + if (data[n] == 1) + tx_buf[reg] |= (1 << chan); + else + tx_buf[reg] ^= (1 << chan); + + goto write_packet; + } + + /* VMK8061_MODEL */ + reg = VMK8061_DO_REG; + if (data[n] == 1) { + cmd = VMK8061_CMD_SET_DO; + tx_buf[reg] = 1 << chan; + } else { + cmd = VMK8061_CMD_CLR_DO; + tx_buf[reg] = 0xff - (1 << chan); + } + +write_packet: + if (vmk80xx_write_packet(dev, cmd)) + break; + } + + up(&dev->limit_sem); + + return n; +} + +static int vmk80xx_do_rinsn(struct comedi_device *cdev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + struct vmk80xx_usb *dev = cdev->private; + int chan, reg, mask; + int n; + + dbgvm("vmk80xx: %s\n", __func__); + + rudimentary_check(DIR_IN); + + down(&dev->limit_sem); + chan = CR_CHAN(insn->chanspec); + + reg = VMK8061_DO_REG; + mask = 1 << chan; + + dev->usb_tx_buf[0] = VMK8061_CMD_RD_DO; + + for (n = 0; n < insn->n; n++) { + if (vmk80xx_read_packet(dev)) + break; + + data[n] = (dev->usb_rx_buf[reg] & mask) >> chan; + } + + up(&dev->limit_sem); + + return n; +} + +static int vmk80xx_cnt_rinsn(struct comedi_device *cdev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + struct vmk80xx_usb *dev = cdev->private; + int chan, reg[2]; + int n; + + dbgvm("vmk80xx: %s\n", __func__); + + rudimentary_check(DIR_IN); + + down(&dev->limit_sem); + chan = CR_CHAN(insn->chanspec); + + switch (dev->board.model) { + case VMK8055_MODEL: + if (!chan) + reg[0] = VMK8055_CNT1_REG; + else + reg[0] = VMK8055_CNT2_REG; + break; + case VMK8061_MODEL: + reg[0] = VMK8061_CNT_REG; + reg[1] = VMK8061_CNT_REG; + dev->usb_tx_buf[0] = VMK8061_CMD_RD_CNT; + break; + } + + for (n = 0; n < insn->n; n++) { + if (vmk80xx_read_packet(dev)) + break; + + if (dev->board.model == VMK8055_MODEL) { + data[n] = dev->usb_rx_buf[reg[0]]; + continue; + } + + /* VMK8061_MODEL */ + data[n] = dev->usb_rx_buf[reg[0]*(chan+1)+1] + + 256 * dev->usb_rx_buf[reg[1]*2+2]; + } + + up(&dev->limit_sem); + + return n; +} + +static int vmk80xx_cnt_cinsn(struct comedi_device *cdev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + struct vmk80xx_usb *dev = cdev->private; + unsigned int insn_cmd; + int chan, cmd, reg; + int n; + + dbgvm("vmk80xx: %s\n", __func__); + + rudimentary_check(DIR_OUT); + + down(&dev->limit_sem); + + insn_cmd = data[0]; + if (insn_cmd != INSN_CONFIG_RESET && insn_cmd != GPCT_RESET) + return -EINVAL; + + chan = CR_CHAN(insn->chanspec); + + if (dev->board.model == VMK8055_MODEL) { + if (!chan) { + cmd = VMK8055_CMD_RST_CNT1; + reg = VMK8055_CNT1_REG; + } else { + cmd = VMK8055_CMD_RST_CNT2; + reg = VMK8055_CNT2_REG; + } + + dev->usb_tx_buf[reg] = 0x00; + } else + cmd = VMK8061_CMD_RST_CNT; + + for (n = 0; n < insn->n; n++) + if (vmk80xx_write_packet(dev, cmd)) + break; + + up(&dev->limit_sem); + + return n; +} + +static int vmk80xx_cnt_winsn(struct comedi_device *cdev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + struct vmk80xx_usb *dev = cdev->private; + unsigned long debtime, val; + int chan, cmd; + int n; + + dbgvm("vmk80xx: %s\n", __func__); + + rudimentary_check(DIR_OUT); + + down(&dev->limit_sem); + chan = CR_CHAN(insn->chanspec); + + if (!chan) + cmd = VMK8055_CMD_DEB1_TIME; + else + cmd = VMK8055_CMD_DEB2_TIME; + + for (n = 0; n < insn->n; n++) { + debtime = data[n]; + if (debtime == 0) + debtime = 1; + + /* TODO: Prevent overflows */ + if (debtime > 7450) + debtime = 7450; + + val = int_sqrt(debtime * 1000 / 115); + if (((val + 1) * val) < debtime * 1000 / 115) + val += 1; + + dev->usb_tx_buf[6+chan] = val; + + if (vmk80xx_write_packet(dev, cmd)) + break; + } + + up(&dev->limit_sem); + + return n; +} + +static int vmk80xx_pwm_rinsn(struct comedi_device *cdev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + struct vmk80xx_usb *dev = cdev->private; + int reg[2]; + int n; + + dbgvm("vmk80xx: %s\n", __func__); + + rudimentary_check(DIR_IN); + + down(&dev->limit_sem); + + reg[0] = VMK8061_PWM_REG1; + reg[1] = VMK8061_PWM_REG2; + + dev->usb_tx_buf[0] = VMK8061_CMD_RD_PWM; + + for (n = 0; n < insn->n; n++) { + if (vmk80xx_read_packet(dev)) + break; + + data[n] = dev->usb_rx_buf[reg[0]] + 4 * + dev->usb_rx_buf[reg[1]]; + } + + up(&dev->limit_sem); + + return n; +} + +static int vmk80xx_pwm_winsn(struct comedi_device *cdev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + struct vmk80xx_usb *dev = cdev->private; + unsigned char *tx_buf; + int reg[2], cmd; + int n; + + dbgvm("vmk80xx: %s\n", __func__); + + rudimentary_check(DIR_OUT); + + down(&dev->limit_sem); + + tx_buf = dev->usb_tx_buf; + + reg[0] = VMK8061_PWM_REG1; + reg[1] = VMK8061_PWM_REG2; + + cmd = VMK8061_CMD_OUT_PWM; + + /* + * The followin piece of code was translated from the inline + * assembler code in the DLL source code. + * + * asm + * mov eax, k ; k is the value (data[n]) + * and al, 03h ; al are the lower 8 bits of eax + * mov lo, al ; lo is the low part (tx_buf[reg[0]]) + * mov eax, k + * shr eax, 2 ; right shift eax register by 2 + * mov hi, al ; hi is the high part (tx_buf[reg[1]]) + * end; + */ + for (n = 0; n < insn->n; n++) { + tx_buf[reg[0]] = (unsigned char)(data[n] & 0x03); + tx_buf[reg[1]] = (unsigned char)(data[n] >> 2) & 0xff; + + if (vmk80xx_write_packet(dev, cmd)) + break; + } + + up(&dev->limit_sem); + + return n; +} + +static int +vmk80xx_attach(struct comedi_device *cdev, struct comedi_devconfig *it) +{ + int i; + struct vmk80xx_usb *dev; + int n_subd; + struct comedi_subdevice *s; + int minor; + + dbgvm("vmk80xx: %s\n", __func__); + + mutex_lock(&glb_mutex); + + for (i = 0; i < VMK80XX_MAX_BOARDS; i++) + if (vmb[i].probed && !vmb[i].attached) + break; + + if (i == VMK80XX_MAX_BOARDS) { + mutex_unlock(&glb_mutex); + return -ENODEV; + } + + dev = &vmb[i]; + + down(&dev->limit_sem); + + cdev->board_name = dev->board.name; + cdev->private = dev; + + if (dev->board.model == VMK8055_MODEL) + n_subd = 5; + else + n_subd = 6; + + if (alloc_subdevices(cdev, n_subd) < 0) { + up(&dev->limit_sem); + mutex_unlock(&glb_mutex); + return -ENOMEM; + } + + /* Analog input subdevice */ + s = cdev->subdevices + VMK80XX_SUBD_AI; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND; + s->n_chan = dev->board.ai_chans; + s->maxdata = (1 << dev->board.ai_bits) - 1; + s->range_table = dev->board.range; + s->insn_read = vmk80xx_ai_rinsn; + + /* Analog output subdevice */ + s = cdev->subdevices + VMK80XX_SUBD_AO; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITEABLE | SDF_GROUND; + s->n_chan = dev->board.ao_chans; + s->maxdata = (1 << dev->board.ao_bits) - 1; + s->range_table = dev->board.range; + s->insn_write = vmk80xx_ao_winsn; + + if (dev->board.model == VMK8061_MODEL) { + s->subdev_flags |= SDF_READABLE; + s->insn_read = vmk80xx_ao_rinsn; + } + + /* Digital input subdevice */ + s = cdev->subdevices + VMK80XX_SUBD_DI; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE | SDF_GROUND; + s->n_chan = dev->board.di_chans; + s->maxdata = (1 << dev->board.di_bits) - 1; + s->insn_read = vmk80xx_di_rinsn; + + /* Digital output subdevice */ + s = cdev->subdevices + VMK80XX_SUBD_DO; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITEABLE | SDF_GROUND; + s->n_chan = dev->board.do_chans; + s->maxdata = (1 << dev->board.do_bits) - 1; + s->insn_write = vmk80xx_do_winsn; + + if (dev->board.model == VMK8061_MODEL) { + s->subdev_flags |= SDF_READABLE; + s->insn_read = vmk80xx_do_rinsn; + } + + /* Counter subdevice */ + s = cdev->subdevices + VMK80XX_SUBD_CNT; + s->type = COMEDI_SUBD_COUNTER; + s->subdev_flags = SDF_READABLE; + s->n_chan = dev->board.cnt_chans; + s->insn_read = vmk80xx_cnt_rinsn; + s->insn_config = vmk80xx_cnt_cinsn; + + if (dev->board.model == VMK8055_MODEL) { + s->subdev_flags |= SDF_WRITEABLE; + s->maxdata = (1 << dev->board.cnt_bits) - 1; + s->insn_write = vmk80xx_cnt_winsn; + } + + /* PWM subdevice */ + if (dev->board.model == VMK8061_MODEL) { + s = cdev->subdevices + VMK80XX_SUBD_PWM; + s->type = COMEDI_SUBD_PWM; + s->subdev_flags = SDF_READABLE | SDF_WRITEABLE; + s->n_chan = dev->board.pwm_chans; + s->maxdata = (1 << dev->board.pwm_bits) - 1; + s->insn_read = vmk80xx_pwm_rinsn; + s->insn_write = vmk80xx_pwm_winsn; + } + + dev->attached = 1; + + minor = cdev->minor; + + printk(KERN_INFO + "comedi%d: vmk80xx: board #%d [%s] attached to comedi\n", + minor, dev->count, dev->board.name); + + up(&dev->limit_sem); + mutex_unlock(&glb_mutex); + + return 0; +} + +static int vmk80xx_detach(struct comedi_device *cdev) +{ + struct vmk80xx_usb *dev; + int minor; + + dbgvm("vmk80xx: %s\n", __func__); + + if (!cdev) + return -EFAULT; + + dev = cdev->private; + if (!dev) + return -EFAULT; + + down(&dev->limit_sem); + + cdev->private = NULL; + dev->attached = 0; + + minor = cdev->minor; + + printk(KERN_INFO + "comedi%d: vmk80xx: board #%d [%s] detached from comedi\n", + minor, dev->count, dev->board.name); + + up(&dev->limit_sem); + + return 0; +} + +static int +vmk80xx_probe(struct usb_interface *intf, const struct usb_device_id *id) +{ + int i; + struct vmk80xx_usb *dev; + struct usb_host_interface *iface_desc; + struct usb_endpoint_descriptor *ep_desc; + size_t size; + + dbgvm("vmk80xx: %s\n", __func__); + + mutex_lock(&glb_mutex); + + for (i = 0; i < VMK80XX_MAX_BOARDS; i++) + if (!vmb[i].probed) + break; + + if (i == VMK80XX_MAX_BOARDS) { + mutex_unlock(&glb_mutex); + return -EMFILE; + } + + dev = &vmb[i]; + + memset(dev, 0x00, sizeof(struct vmk80xx_usb)); + dev->count = i; + + iface_desc = intf->cur_altsetting; + if (iface_desc->desc.bNumEndpoints != 2) + goto error; + + for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) { + ep_desc = &iface_desc->endpoint[i].desc; + + if (usb_endpoint_is_int_in(ep_desc)) { + dev->ep_rx = ep_desc; + continue; + } + + if (usb_endpoint_is_int_out(ep_desc)) { + dev->ep_tx = ep_desc; + continue; + } + + if (usb_endpoint_is_bulk_in(ep_desc)) { + dev->ep_rx = ep_desc; + continue; + } + + if (usb_endpoint_is_bulk_out(ep_desc)) { + dev->ep_tx = ep_desc; + continue; + } + } + + if (!dev->ep_rx || !dev->ep_tx) + goto error; + + size = le16_to_cpu(dev->ep_rx->wMaxPacketSize); + dev->usb_rx_buf = kmalloc(size, GFP_KERNEL); + if (!dev->usb_rx_buf) { + mutex_unlock(&glb_mutex); + return -ENOMEM; + } + + size = le16_to_cpu(dev->ep_tx->wMaxPacketSize); + dev->usb_tx_buf = kmalloc(size, GFP_KERNEL); + if (!dev->usb_tx_buf) { + kfree(dev->usb_rx_buf); + mutex_unlock(&glb_mutex); + return -ENOMEM; + } + + dev->udev = interface_to_usbdev(intf); + dev->intf = intf; + + sema_init(&dev->limit_sem, 8); + init_waitqueue_head(&dev->read_wait); + init_waitqueue_head(&dev->write_wait); + + init_usb_anchor(&dev->rx_anchor); + init_usb_anchor(&dev->tx_anchor); + + usb_set_intfdata(intf, dev); + + switch (id->driver_info) { + case DEVICE_VMK8055: + dev->board.name = "K8055 (VM110)"; + dev->board.model = VMK8055_MODEL; + dev->board.range = &vmk8055_range; + dev->board.ai_chans = 2; + dev->board.ai_bits = 8; + dev->board.ao_chans = 2; + dev->board.ao_bits = 8; + dev->board.di_chans = 5; + dev->board.di_bits = 1; + dev->board.do_chans = 8; + dev->board.do_bits = 1; + dev->board.cnt_chans = 2; + dev->board.cnt_bits = 16; + dev->board.pwm_chans = 0; + dev->board.pwm_bits = 0; + break; + case DEVICE_VMK8061: + dev->board.name = "K8061 (VM140)"; + dev->board.model = VMK8061_MODEL; + dev->board.range = &vmk8061_range; + dev->board.ai_chans = 8; + dev->board.ai_bits = 10; + dev->board.ao_chans = 8; + dev->board.ao_bits = 8; + dev->board.di_chans = 8; + dev->board.di_bits = 1; + dev->board.do_chans = 8; + dev->board.do_bits = 1; + dev->board.cnt_chans = 2; + dev->board.cnt_bits = 0; + dev->board.pwm_chans = 1; + dev->board.pwm_bits = 10; + break; + } + + if (dev->board.model == VMK8061_MODEL) { + vmk80xx_read_eeprom(dev, IC3_VERSION); + printk(KERN_INFO "comedi#: vmk80xx: %s\n", + dev->fw.ic3_vers); + + if (vmk80xx_check_data_link(dev)) { + vmk80xx_read_eeprom(dev, IC6_VERSION); + printk(KERN_INFO "comedi#: vmk80xx: %s\n", + dev->fw.ic6_vers); + } else + dbgcm("comedi#: vmk80xx: no conn. to CPU\n"); + } + + if (dev->board.model == VMK8055_MODEL) + vmk80xx_reset_device(dev); + + dev->probed = 1; + + printk(KERN_INFO "comedi#: vmk80xx: board #%d [%s] now attached\n", + dev->count, dev->board.name); + + mutex_unlock(&glb_mutex); + + return 0; +error: + mutex_unlock(&glb_mutex); + + return -ENODEV; +} + +static void vmk80xx_disconnect(struct usb_interface *intf) +{ + struct vmk80xx_usb *dev = usb_get_intfdata(intf); + + dbgvm("vmk80xx: %s\n", __func__); + + if (!dev) + return; + + mutex_lock(&glb_mutex); + down(&dev->limit_sem); + + dev->probed = 0; + usb_set_intfdata(dev->intf, NULL); + + usb_kill_anchored_urbs(&dev->rx_anchor); + usb_kill_anchored_urbs(&dev->tx_anchor); + + kfree(dev->usb_rx_buf); + kfree(dev->usb_tx_buf); + + printk(KERN_INFO "comedi#: vmk80xx: board #%d [%s] now detached\n", + dev->count, dev->board.name); + + up(&dev->limit_sem); + mutex_unlock(&glb_mutex); +} + +/* TODO: Add support for suspend, resume, pre_reset, + * post_reset and flush */ +static struct usb_driver vmk80xx_driver = { + .name = "vmk80xx", + .probe = vmk80xx_probe, + .disconnect = vmk80xx_disconnect, + .id_table = vmk80xx_id_table +}; + +static struct comedi_driver driver_vmk80xx = { + .module = THIS_MODULE, + .driver_name = "vmk80xx", + .attach = vmk80xx_attach, + .detach = vmk80xx_detach +}; + +static int __init vmk80xx_init(void) +{ + printk(KERN_INFO "vmk80xx: version 0.8.01 " + "Manuel Gebele \n"); + usb_register(&vmk80xx_driver); + return comedi_driver_register(&driver_vmk80xx); +} + +static void __exit vmk80xx_exit(void) +{ + comedi_driver_unregister(&driver_vmk80xx); + usb_deregister(&vmk80xx_driver); +} + +module_init(vmk80xx_init); +module_exit(vmk80xx_exit); diff --git a/drivers/staging/comedi/interrupt.h b/drivers/staging/comedi/interrupt.h deleted file mode 100644 index d1f09892da2e..000000000000 --- a/drivers/staging/comedi/interrupt.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - linux/interrupt.h compatibility header - - 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 __COMPAT_LINUX_INTERRUPT_H_ -#define __COMPAT_LINUX_INTERRUPT_H_ - -#include - -#ifndef IRQF_DISABLED -#define IRQF_DISABLED SA_INTERRUPT -#define IRQF_SAMPLE_RANDOM SA_SAMPLE_RANDOM -#define IRQF_SHARED SA_SHIRQ -#define IRQF_PROBE_SHARED SA_PROBEIRQ -#define IRQF_PERCPU SA_PERCPU -#ifdef SA_TRIGGER_MASK -#define IRQF_TRIGGER_NONE 0 -#define IRQF_TRIGGER_LOW SA_TRIGGER_LOW -#define IRQF_TRIGGER_HIGH SA_TRIGGER_HIGH -#define IRQF_TRIGGER_FALLING SA_TRIGGER_FALLING -#define IRQF_TRIGGER_RISING SA_TRIGGER_RISING -#define IRQF_TRIGGER_MASK SA_TRIGGER_MASK -#else -#define IRQF_TRIGGER_NONE 0 -#define IRQF_TRIGGER_LOW 0 -#define IRQF_TRIGGER_HIGH 0 -#define IRQF_TRIGGER_FALLING 0 -#define IRQF_TRIGGER_RISING 0 -#define IRQF_TRIGGER_MASK 0 -#endif -#endif - -#define PT_REGS_ARG -#define PT_REGS_CALL -#define PT_REGS_NULL - -#endif diff --git a/drivers/staging/comedi/kcomedilib/data.c b/drivers/staging/comedi/kcomedilib/data.c index 9797e13e3774..d808556460aa 100644 --- a/drivers/staging/comedi/kcomedilib/data.c +++ b/drivers/staging/comedi/kcomedilib/data.c @@ -23,9 +23,10 @@ #include "../comedi.h" #include "../comedilib.h" -#include "../comedidev.h" /* for comedi_udelay() */ +#include "../comedidev.h" #include +#include int comedi_data_write(void *dev, unsigned int subdev, unsigned int chan, unsigned int range, unsigned int aref, unsigned int data) @@ -83,7 +84,7 @@ int comedi_data_read_delayed(void *dev, unsigned int subdev, if (retval < 0) return retval; - comedi_udelay((nano_sec + 999) / 1000); + udelay((nano_sec + 999) / 1000); return comedi_data_read(dev, subdev, chan, range, aref, data); } diff --git a/drivers/staging/comedi/kcomedilib/kcomedilib_main.c b/drivers/staging/comedi/kcomedilib/kcomedilib_main.c index a4fa9571c58f..b39ea7c50b87 100644 --- a/drivers/staging/comedi/kcomedilib/kcomedilib_main.c +++ b/drivers/staging/comedi/kcomedilib/kcomedilib_main.c @@ -105,7 +105,7 @@ int comedi_loglevel(int newlevel) void comedi_perror(const char *message) { - rt_printk("%s: unknown error\n", message); + printk("%s: unknown error\n", message); } char *comedi_strerror(int err) @@ -150,10 +150,6 @@ int comedi_command(void *d, struct comedi_cmd *cmd) runflags = SRF_RUNNING; -#ifdef CONFIG_COMEDI_RT - if (comedi_switch_to_rt(dev) == 0) - runflags |= SRF_RT; -#endif comedi_set_subdevice_runflags(s, ~0, runflags); comedi_reset_async_buf(async); @@ -208,7 +204,7 @@ int comedi_do_insn(void *d, struct comedi_insn *insn) ret = -EINVAL; break; } - comedi_udelay(insn->data[0]); + udelay(insn->data[0]); ret = 1; break; case INSN_INTTRIG: @@ -217,19 +213,19 @@ int comedi_do_insn(void *d, struct comedi_insn *insn) break; } if (insn->subdev >= dev->n_subdevices) { - rt_printk("%d not usable subdevice\n", + printk("%d not usable subdevice\n", insn->subdev); ret = -EINVAL; break; } s = dev->subdevices + insn->subdev; if (!s->async) { - rt_printk("no async\n"); + printk("no async\n"); ret = -EINVAL; break; } if (!s->async->inttrig) { - rt_printk("no inttrig\n"); + printk("no inttrig\n"); ret = -EAGAIN; break; } @@ -249,7 +245,7 @@ int comedi_do_insn(void *d, struct comedi_insn *insn) s = dev->subdevices + insn->subdev; if (s->type == COMEDI_SUBD_UNUSED) { - rt_printk("%d not useable subdevice\n", insn->subdev); + printk("%d not useable subdevice\n", insn->subdev); ret = -EIO; goto error; } @@ -258,7 +254,7 @@ int comedi_do_insn(void *d, struct comedi_insn *insn) ret = check_chanlist(s, 1, &insn->chanspec); if (ret < 0) { - rt_printk("bad chanspec\n"); + printk("bad chanspec\n"); ret = -EINVAL; goto error; } @@ -295,7 +291,7 @@ int comedi_do_insn(void *d, struct comedi_insn *insn) #if 0 /* XXX do we want this? -- abbotti #if'ed it out for now. */ if (ret != insn->n) { - rt_printk("BUG: result of insn != insn.n\n"); + printk("BUG: result of insn != insn.n\n"); ret = -EINVAL; goto error; } @@ -336,7 +332,7 @@ int comedi_lock(void *d, unsigned int subdevice) s = dev->subdevices + subdevice; - comedi_spin_lock_irqsave(&s->spin_lock, flags); + spin_lock_irqsave(&s->spin_lock, flags); if (s->busy) { ret = -EBUSY; @@ -348,7 +344,7 @@ int comedi_lock(void *d, unsigned int subdevice) } } - comedi_spin_unlock_irqrestore(&s->spin_lock, flags); + spin_unlock_irqrestore(&s->spin_lock, flags); return ret; } @@ -382,7 +378,7 @@ int comedi_unlock(void *d, unsigned int subdevice) async = s->async; - comedi_spin_lock_irqsave(&s->spin_lock, flags); + spin_lock_irqsave(&s->spin_lock, flags); if (s->busy) { ret = -EBUSY; @@ -400,7 +396,7 @@ int comedi_unlock(void *d, unsigned int subdevice) ret = 0; } - comedi_spin_unlock_irqrestore(&s->spin_lock, flags); + spin_unlock_irqrestore(&s->spin_lock, flags); return ret; } @@ -449,11 +445,6 @@ int comedi_cancel(void *d, unsigned int subdevice) if (ret) return ret; -#ifdef CONFIG_COMEDI_RT - if (comedi_get_subdevice_runflags(s) & SRF_RT) - comedi_switch_to_non_rt(dev); - -#endif comedi_set_subdevice_runflags(s, SRF_RUNNING | SRF_RT, 0); s->async->inttrig = NULL; s->busy = NULL; diff --git a/drivers/staging/comedi/kcomedilib/ksyms.c b/drivers/staging/comedi/kcomedilib/ksyms.c index 3db86dabf878..314765db51fe 100644 --- a/drivers/staging/comedi/kcomedilib/ksyms.c +++ b/drivers/staging/comedi/kcomedilib/ksyms.c @@ -59,7 +59,7 @@ EXPORT_SYMBOL(comedi_close); EXPORT_SYMBOL(comedi_loglevel); EXPORT_SYMBOL(comedi_perror); EXPORT_SYMBOL(comedi_strerror); -//EXPORT_SYMBOL(comedi_errno); +/* EXPORT_SYMBOL(comedi_errno); */ EXPORT_SYMBOL(comedi_fileno); /* device queries */ @@ -73,8 +73,10 @@ EXPORT_SYMBOL(comedi_get_subdevice_type); EXPORT_SYMBOL(comedi_find_subdevice_by_type); EXPORT_SYMBOL(comedi_get_subdevice_flags); EXPORT_SYMBOL(comedi_get_n_channels); -//EXPORT_SYMBOL(comedi_range_is_chan_specific); -//EXPORT_SYMBOL(comedi_maxdata_is_chan_specific); +/* +* EXPORT_SYMBOL(comedi_range_is_chan_specific); +* EXPORT_SYMBOL(comedi_maxdata_is_chan_specific); +*/ /* channel queries */ EXPORT_SYMBOL(comedi_get_maxdata); @@ -82,25 +84,29 @@ EXPORT_SYMBOL(comedi_get_maxdata); EXPORT_SYMBOL(comedi_get_rangetype); #endif EXPORT_SYMBOL(comedi_get_n_ranges); -//EXPORT_SYMBOL(comedi_find_range); +/* EXPORT_SYMBOL(comedi_find_range); */ /* buffer queries */ EXPORT_SYMBOL(comedi_get_buffer_size); -//EXPORT_SYMBOL(comedi_get_max_buffer_size); -//EXPORT_SYMBOL(comedi_set_buffer_size); +/* +* EXPORT_SYMBOL(comedi_get_max_buffer_size); +* EXPORT_SYMBOL(comedi_set_buffer_size); +*/ EXPORT_SYMBOL(comedi_get_buffer_contents); EXPORT_SYMBOL(comedi_get_buffer_offset); /* low-level stuff */ -//EXPORT_SYMBOL(comedi_trigger); -//EXPORT_SYMBOL(comedi_do_insnlist); +/* +* EXPORT_SYMBOL(comedi_trigger); EXPORT_SYMBOL(comedi_do_insnlist); +*/ EXPORT_SYMBOL(comedi_do_insn); EXPORT_SYMBOL(comedi_lock); EXPORT_SYMBOL(comedi_unlock); /* physical units */ -//EXPORT_SYMBOL(comedi_to_phys); -//EXPORT_SYMBOL(comedi_from_phys); +/* +* EXPORT_SYMBOL(comedi_to_phys); EXPORT_SYMBOL(comedi_from_phys); +*/ /* synchronous stuff */ EXPORT_SYMBOL(comedi_data_read); @@ -113,13 +119,16 @@ EXPORT_SYMBOL(comedi_dio_write); EXPORT_SYMBOL(comedi_dio_bitfield); /* slowly varying stuff */ -//EXPORT_SYMBOL(comedi_sv_init); -//EXPORT_SYMBOL(comedi_sv_update); -//EXPORT_SYMBOL(comedi_sv_measure); +/* +* EXPORT_SYMBOL(comedi_sv_init); EXPORT_SYMBOL(comedi_sv_update); +* EXPORT_SYMBOL(comedi_sv_measure); +*/ /* commands */ -//EXPORT_SYMBOL(comedi_get_cmd_src_mask); -//EXPORT_SYMBOL(comedi_get_cmd_generic_timed); +/* +* EXPORT_SYMBOL(comedi_get_cmd_src_mask); +* EXPORT_SYMBOL(comedi_get_cmd_generic_timed); +*/ EXPORT_SYMBOL(comedi_cancel); EXPORT_SYMBOL(comedi_command); EXPORT_SYMBOL(comedi_command_test); @@ -129,12 +138,14 @@ EXPORT_SYMBOL(comedi_poll); EXPORT_SYMBOL(comedi_mark_buffer_read); EXPORT_SYMBOL(comedi_mark_buffer_written); -//EXPORT_SYMBOL(comedi_get_range); +/* EXPORT_SYMBOL(comedi_get_range); */ EXPORT_SYMBOL(comedi_get_len_chanlist); /* deprecated */ -//EXPORT_SYMBOL(comedi_get_timer); -//EXPORT_SYMBOL(comedi_timed_1chan); +/* +* EXPORT_SYMBOL(comedi_get_timer); +* EXPORT_SYMBOL(comedi_timed_1chan); +*/ /* alpha */ -//EXPORT_SYMBOL(comedi_set_global_oor_behavior); +/* EXPORT_SYMBOL(comedi_set_global_oor_behavior); */ diff --git a/drivers/staging/comedi/range.c b/drivers/staging/comedi/range.c index ac200d929f35..445909e6f334 100644 --- a/drivers/staging/comedi/range.c +++ b/drivers/staging/comedi/range.c @@ -32,7 +32,7 @@ const struct comedi_lrange range_unipolar5 = { 1, {UNI_RANGE(5)} }; const struct comedi_lrange range_unknown = { 1, {{0, 1000000, UNIT_none}} }; /* - COMEDI_RANGEINFO + COMEDI_RANGEINFO range information ioctl arg: @@ -130,8 +130,7 @@ int check_chanlist(struct comedi_subdevice *s, int n, unsigned int *chanlist) if (CR_CHAN(chanlist[i]) >= s->n_chan || CR_RANGE(chanlist[i]) >= s->range_table->length || aref_invalid(s, chanlist[i])) { - rt_printk - ("bad chanlist[%d]=0x%08x n_chan=%d range length=%d\n", + printk("bad chanlist[%d]=0x%08x n_chan=%d range length=%d\n", i, chanlist[i], s->n_chan, s->range_table->length); #if 0 @@ -147,13 +146,13 @@ int check_chanlist(struct comedi_subdevice *s, int n, unsigned int *chanlist) CR_RANGE(chanlist[i]) >= s->range_table_list[chan]->length || aref_invalid(s, chanlist[i])) { - rt_printk("bad chanlist[%d]=0x%08x\n", i, + printk("bad chanlist[%d]=0x%08x\n", i, chanlist[i]); return -EINVAL; } } } else { - rt_printk("comedi: (bug) no range type list!\n"); + printk("comedi: (bug) no range type list!\n"); return -EINVAL; } return 0; diff --git a/drivers/staging/comedi/rt.c b/drivers/staging/comedi/rt.c deleted file mode 100644 index e9f5777595ab..000000000000 --- a/drivers/staging/comedi/rt.c +++ /dev/null @@ -1,411 +0,0 @@ -/* - comedi/rt.c - comedi kernel module - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 1997-2000 David A. Schleef - - 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. - -*/ - -#undef DEBUG - -#define __NO_VERSION__ -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "rt_pend_tq.h" - -#ifdef CONFIG_COMEDI_RTAI -#include -#endif - -#ifdef CONFIG_COMEDI_FUSION -#include -#endif - -#ifdef CONFIG_COMEDI_RTL -#include -#include -#endif - -struct comedi_irq_struct { - int rt; - int irq; - irqreturn_t(*handler) (int irq, void *dev_id PT_REGS_ARG); - unsigned long flags; - const char *device; - struct comedi_device *dev_id; -}; - -static int comedi_rt_get_irq(struct comedi_irq_struct *it); -static int comedi_rt_release_irq(struct comedi_irq_struct *it); - -static struct comedi_irq_struct *comedi_irqs[NR_IRQS]; - -int comedi_request_irq(unsigned irq, irqreturn_t(*handler) (int, - void *PT_REGS_ARG), unsigned long flags, const char *device, - struct comedi_device *dev_id) -{ - struct comedi_irq_struct *it; - int ret; - /* null shared interrupt flag, since rt interrupt handlers do not - * support it, and this version of comedi_request_irq() is only - * called for kernels with rt support */ - unsigned long unshared_flags = flags & ~IRQF_SHARED; - - ret = request_irq(irq, handler, unshared_flags, device, dev_id); - if (ret < 0) { - /* we failed, so fall back on allowing shared interrupt (which we won't ever make RT) */ - if (flags & IRQF_SHARED) { - rt_printk - ("comedi: cannot get unshared interrupt, will not use RT interrupts.\n"); - ret = request_irq(irq, handler, flags, device, dev_id); - } - if (ret < 0) - return ret; - - } else { - it = kzalloc(sizeof(struct comedi_irq_struct), GFP_KERNEL); - if (!it) - return -ENOMEM; - - it->handler = handler; - it->irq = irq; - it->dev_id = dev_id; - it->device = device; - it->flags = unshared_flags; - comedi_irqs[irq] = it; - } - return 0; -} - -void comedi_free_irq(unsigned int irq, struct comedi_device *dev_id) -{ - struct comedi_irq_struct *it; - - free_irq(irq, dev_id); - - it = comedi_irqs[irq]; - if (it == NULL) - return; - - if (it->rt) { - printk("real-time IRQ allocated at board removal (ignore)\n"); - comedi_rt_release_irq(it); - } - - kfree(it); - comedi_irqs[irq] = NULL; -} - -int comedi_switch_to_rt(struct comedi_device *dev) -{ - struct comedi_irq_struct *it; - unsigned long flags; - - it = comedi_irqs[dev->irq]; - /* drivers might not be using an interrupt for commands, - or we might not have been able to get an unshared irq */ - if (it == NULL) - return -1; - - comedi_spin_lock_irqsave(&dev->spinlock, flags); - - if (!dev->rt) - comedi_rt_get_irq(it); - - dev->rt++; - it->rt = 1; - - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); - - return 0; -} - -void comedi_switch_to_non_rt(struct comedi_device *dev) -{ - struct comedi_irq_struct *it; - unsigned long flags; - - it = comedi_irqs[dev->irq]; - if (it == NULL) - return; - - comedi_spin_lock_irqsave(&dev->spinlock, flags); - - dev->rt--; - if (!dev->rt) - comedi_rt_release_irq(it); - - it->rt = 0; - - comedi_spin_unlock_irqrestore(&dev->spinlock, flags); -} - -void wake_up_int_handler(int arg1, void *arg2) -{ - wake_up_interruptible((wait_queue_head_t *) arg2); -} - -void comedi_rt_pend_wakeup(wait_queue_head_t *q) -{ - rt_pend_call(wake_up_int_handler, 0, q); -} - -/* RTAI section */ -#ifdef CONFIG_COMEDI_RTAI - -#ifndef HAVE_RT_REQUEST_IRQ_WITH_ARG -#define DECLARE_VOID_IRQ(irq) \ -static void handle_void_irq_ ## irq (void){ handle_void_irq(irq); } - -static void handle_void_irq(int irq) -{ - struct comedi_irq_struct *it; - - it = comedi_irqs[irq]; - if (it == NULL) { - rt_printk("comedi: null irq struct?\n"); - return; - } - it->handler(irq, it->dev_id PT_REGS_NULL); - rt_enable_irq(irq); /* needed by rtai-adeos, seems like it shouldn't hurt earlier versions */ -} - -DECLARE_VOID_IRQ(0); -DECLARE_VOID_IRQ(1); -DECLARE_VOID_IRQ(2); -DECLARE_VOID_IRQ(3); -DECLARE_VOID_IRQ(4); -DECLARE_VOID_IRQ(5); -DECLARE_VOID_IRQ(6); -DECLARE_VOID_IRQ(7); -DECLARE_VOID_IRQ(8); -DECLARE_VOID_IRQ(9); -DECLARE_VOID_IRQ(10); -DECLARE_VOID_IRQ(11); -DECLARE_VOID_IRQ(12); -DECLARE_VOID_IRQ(13); -DECLARE_VOID_IRQ(14); -DECLARE_VOID_IRQ(15); -DECLARE_VOID_IRQ(16); -DECLARE_VOID_IRQ(17); -DECLARE_VOID_IRQ(18); -DECLARE_VOID_IRQ(19); -DECLARE_VOID_IRQ(20); -DECLARE_VOID_IRQ(21); -DECLARE_VOID_IRQ(22); -DECLARE_VOID_IRQ(23); - -static void handle_void_irq_ptrs[] = { - handle_void_irq_0, - handle_void_irq_1, - handle_void_irq_2, - handle_void_irq_3, - handle_void_irq_4, - handle_void_irq_5, - handle_void_irq_6, - handle_void_irq_7, - handle_void_irq_8, - handle_void_irq_9, - handle_void_irq_10, - handle_void_irq_11, - handle_void_irq_12, - handle_void_irq_13, - handle_void_irq_14, - handle_void_irq_15, - handle_void_irq_16, - handle_void_irq_17, - handle_void_irq_18, - handle_void_irq_19, - handle_void_irq_20, - handle_void_irq_21, - handle_void_irq_22, - handle_void_irq_23, -}; - -static int comedi_rt_get_irq(struct comedi_irq_struct *it) -{ - rt_request_global_irq(it->irq, handle_void_irq_ptrs[it->irq]); - rt_startup_irq(it->irq); - - return 0; -} - -static int comedi_rt_release_irq(struct comedi_irq_struct *it) -{ - rt_shutdown_irq(it->irq); - rt_free_global_irq(it->irq); - return 0; -} -#else - -static int comedi_rt_get_irq(struct comedi_irq_struct *it) -{ - int ret; - - ret = rt_request_global_irq_arg(it->irq, it->handler, it->flags, - it->device, it->dev_id); - if (ret < 0) { - rt_printk("rt_request_global_irq_arg() returned %d\n", ret); - return ret; - } - rt_startup_irq(it->irq); - - return 0; -} - -static int comedi_rt_release_irq(struct comedi_irq_struct *it) -{ - rt_shutdown_irq(it->irq); - rt_free_global_irq(it->irq); - return 0; -} -#endif - -void comedi_rt_init(void) -{ - rt_mount_rtai(); - rt_pend_tq_init(); -} - -void comedi_rt_cleanup(void) -{ - rt_umount_rtai(); - rt_pend_tq_cleanup(); -} - -#endif - -/* Fusion section */ -#ifdef CONFIG_COMEDI_FUSION - -static void fusion_handle_irq(unsigned int irq, void *cookie) -{ - struct comedi_irq_struct *it = cookie; - - it->handler(irq, it->dev_id PT_REGS_NULL); - rthal_irq_enable(irq); -} - -static int comedi_rt_get_irq(struct comedi_irq_struct *it) -{ - rthal_irq_request(it->irq, fusion_handle_irq, it); - rthal_irq_enable(it->irq); - return 0; -} - -static int comedi_rt_release_irq(struct comedi_irq_struct *it) -{ - rthal_irq_disable(it->irq); - rthal_irq_release(it->irq); - return 0; -} - -void comedi_rt_init(void) -{ - rt_pend_tq_init(); -} - -void comedi_rt_cleanup(void) -{ - rt_pend_tq_cleanup(); -} - -#endif /*CONFIG_COMEDI_FUSION */ - -/* RTLinux section */ -#ifdef CONFIG_COMEDI_RTL - -static unsigned int handle_rtl_irq(unsigned int irq PT_REGS_ARG) -{ - struct comedi_irq_struct *it; - - it = comedi_irqs[irq]; - if (it == NULL) - return 0; - it->handler(irq, it->dev_id PT_REGS_NULL); - rtl_hard_enable_irq(irq); - return 0; -} - -static int comedi_rt_get_irq(struct comedi_irq_struct *it) -{ - rtl_request_global_irq(it->irq, handle_rtl_irq); - return 0; -} - -static int comedi_rt_release_irq(struct comedi_irq_struct *it) -{ - rtl_free_global_irq(it->irq); - return 0; -} - -void comedi_rt_init(void) -{ - rt_pend_tq_init(); -} - -void comedi_rt_cleanup(void) -{ - rt_pend_tq_cleanup(); -} - -#endif - -#ifdef CONFIG_COMEDI_PIRQ -static int comedi_rt_get_irq(struct comedi_irq_struct *it) -{ - int ret; - - free_irq(it->irq, it->dev_id); - ret = request_irq(it->irq, it->handler, it->flags | SA_PRIORITY, - it->device, it->dev_id); - - return ret; -} - -static int comedi_rt_release_irq(struct comedi_irq_struct *it) -{ - int ret; - - free_irq(it->irq, it->dev_id); - ret = request_irq(it->irq, it->handler, it->flags, - it->device, it->dev_id); - - return ret; -} - -void comedi_rt_init(void) -{ - /* rt_pend_tq_init(); */ -} - -void comedi_rt_cleanup(void) -{ - /* rt_pend_tq_cleanup(); */ -} -#endif diff --git a/drivers/staging/comedi/rt_pend_tq.c b/drivers/staging/comedi/rt_pend_tq.c deleted file mode 100644 index f9dfd9d40cd3..000000000000 --- a/drivers/staging/comedi/rt_pend_tq.c +++ /dev/null @@ -1,113 +0,0 @@ -#define __NO_VERSION__ -/* rt_pend_tq.c */ -#include -#include -#include -#include "comedidev.h" /* for rt spinlocks */ -#include "rt_pend_tq.h" -#ifdef CONFIG_COMEDI_RTAI -#include -#endif -#ifdef CONFIG_COMEDI_FUSION -#include -#endif -#ifdef CONFIG_COMEDI_RTL -#include -#endif - -#ifdef standalone -#include -#define rt_pend_tq_init init_module -#define rt_pend_tq_cleanup cleanup_module -#endif - -volatile static struct rt_pend_tq rt_pend_tq[RT_PEND_TQ_SIZE]; -volatile static struct rt_pend_tq *volatile rt_pend_head = rt_pend_tq, - *volatile rt_pend_tail = rt_pend_tq; -int rt_pend_tq_irq = 0; -DEFINE_SPINLOCK(rt_pend_tq_lock); - -/* WARNING: following code not checked against race conditions yet. */ -#define INC_CIRCULAR_PTR(ptr,begin,size) do {if(++(ptr)>=(begin)+(size)) (ptr)=(begin); } while(0) -#define DEC_CIRCULAR_PTR(ptr,begin,size) do {if(--(ptr)<(begin)) (ptr)=(begin)+(size)-1; } while(0) - -int rt_pend_call(void (*func) (int arg1, void *arg2), int arg1, void *arg2) -{ - unsigned long flags; - - if (func == NULL) - return -EINVAL; - if (rt_pend_tq_irq <= 0) - return -ENODEV; - comedi_spin_lock_irqsave(&rt_pend_tq_lock, flags); - INC_CIRCULAR_PTR(rt_pend_head, rt_pend_tq, RT_PEND_TQ_SIZE); - if (rt_pend_head == rt_pend_tail) { - /* overflow, we just refuse to take this request */ - DEC_CIRCULAR_PTR(rt_pend_head, rt_pend_tq, RT_PEND_TQ_SIZE); - comedi_spin_unlock_irqrestore(&rt_pend_tq_lock, flags); - return -EAGAIN; - } - rt_pend_head->func = func; - rt_pend_head->arg1 = arg1; - rt_pend_head->arg2 = arg2; - comedi_spin_unlock_irqrestore(&rt_pend_tq_lock, flags); -#ifdef CONFIG_COMEDI_RTAI - rt_pend_linux_srq(rt_pend_tq_irq); -#endif -#ifdef CONFIG_COMEDI_FUSION - rthal_apc_schedule(rt_pend_tq_irq); -#endif -#ifdef CONFIG_COMEDI_RTL - rtl_global_pend_irq(rt_pend_tq_irq); - -#endif - return 0; -} - -#ifdef CONFIG_COMEDI_RTAI -void rt_pend_irq_handler(void) -#elif defined(CONFIG_COMEDI_FUSION) -void rt_pend_irq_handler(void *cookie) -#elif defined(CONFIG_COMEDI_RTL) -void rt_pend_irq_handler(int irq, void *dev PT_REGS_ARG) -#endif -{ - while (rt_pend_head != rt_pend_tail) { - INC_CIRCULAR_PTR(rt_pend_tail, rt_pend_tq, RT_PEND_TQ_SIZE); - rt_pend_tail->func(rt_pend_tail->arg1, rt_pend_tail->arg2); - } -} - -int rt_pend_tq_init(void) -{ - rt_pend_head = rt_pend_tail = rt_pend_tq; -#ifdef CONFIG_COMEDI_RTAI - rt_pend_tq_irq = rt_request_srq(0, rt_pend_irq_handler, NULL); -#endif -#ifdef CONFIG_COMEDI_FUSION - rt_pend_tq_irq = - rthal_apc_alloc("comedi APC", rt_pend_irq_handler, NULL); -#endif -#ifdef CONFIG_COMEDI_RTL - rt_pend_tq_irq = rtl_get_soft_irq(rt_pend_irq_handler, "rt_pend_irq"); -#endif - if (rt_pend_tq_irq > 0) - printk("rt_pend_tq: RT bottom half scheduler initialized OK\n"); - else - printk("rt_pend_tq: rtl_get_soft_irq failed\n"); - return 0; -} - -void rt_pend_tq_cleanup(void) -{ - printk("rt_pend_tq: unloading\n"); -#ifdef CONFIG_COMEDI_RTAI - rt_free_srq(rt_pend_tq_irq); -#endif -#ifdef CONFIG_COMEDI_FUSION - rthal_apc_free(rt_pend_tq_irq); -#endif -#ifdef CONFIG_COMEDI_RTL - free_irq(rt_pend_tq_irq, NULL); -#endif -} diff --git a/drivers/staging/comedi/rt_pend_tq.h b/drivers/staging/comedi/rt_pend_tq.h deleted file mode 100644 index 01ed71bf409d..000000000000 --- a/drivers/staging/comedi/rt_pend_tq.h +++ /dev/null @@ -1,10 +0,0 @@ -#define RT_PEND_TQ_SIZE 16 -struct rt_pend_tq { - void (*func) (int arg1, void *arg2); - int arg1; - void *arg2; -}; -extern int rt_pend_call(void (*func) (int arg1, void *arg2), int arg1, - void *arg2); -extern int rt_pend_tq_init(void); -extern void rt_pend_tq_cleanup(void); diff --git a/drivers/staging/cpc-usb/Kconfig b/drivers/staging/cpc-usb/Kconfig new file mode 100644 index 000000000000..2be0bc9c39d0 --- /dev/null +++ b/drivers/staging/cpc-usb/Kconfig @@ -0,0 +1,4 @@ +config USB_CPC + tristate "CPC CAN USB driver" + depends on USB && PROC_FS + default n diff --git a/drivers/staging/cpc-usb/Makefile b/drivers/staging/cpc-usb/Makefile new file mode 100644 index 000000000000..3f83170a8fab --- /dev/null +++ b/drivers/staging/cpc-usb/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_USB_CPC) += cpc-usb.o + +cpc-usb-y := cpc-usb_drv.o sja2m16c_2.o diff --git a/drivers/staging/serqt_usb/TODO b/drivers/staging/cpc-usb/TODO similarity index 63% rename from drivers/staging/serqt_usb/TODO rename to drivers/staging/cpc-usb/TODO index 34ecca8992d2..000e8bbc6188 100644 --- a/drivers/staging/serqt_usb/TODO +++ b/drivers/staging/cpc-usb/TODO @@ -2,7 +2,8 @@ Things to do for this driver to get merged into the main portion of the kernel: - checkpatch cleanups - sparse clean - - port to the usb-serial layer instead of doing it all on its - own. + - remove proc code + - tie into CAN socket interfaces if possible + - figure out sane userspace api Send patches to Greg Kroah-Hartman diff --git a/drivers/staging/cpc-usb/cpc-usb_drv.c b/drivers/staging/cpc-usb/cpc-usb_drv.c new file mode 100644 index 000000000000..9bf3f98c6825 --- /dev/null +++ b/drivers/staging/cpc-usb/cpc-usb_drv.c @@ -0,0 +1,1185 @@ +/* + * CPC-USB CAN Interface Kernel Driver + * + * Copyright (C) 2004-2009 EMS Dr. Thomas Wuensche + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "cpc.h" + +#include "cpc_int.h" +#include "cpcusb.h" + +#include "sja2m16c.h" + +/* Version Information */ +#define DRIVER_AUTHOR "Sebastian Haas " +#define DRIVER_DESC "CPC-USB Driver for Linux Kernel 2.6" +#define DRIVER_VERSION CPC_DRIVER_VERSION + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_VERSION(DRIVER_VERSION); +MODULE_LICENSE("GPL v2"); + +/* Define these values to match your devices */ +#define USB_CPCUSB_VENDOR_ID 0x12D6 + +#define USB_CPCUSB_M16C_PRODUCT_ID 0x0888 +#define USB_CPCUSB_LPC2119_PRODUCT_ID 0x0444 + +#define CPC_USB_PROC_DIR CPC_PROC_DIR "cpc-usb" + +static struct proc_dir_entry *procDir; +static struct proc_dir_entry *procEntry; + +/* Module parameters */ +static int debug; +module_param(debug, int, S_IRUGO); + +/* table of devices that work with this driver */ +static struct usb_device_id cpcusb_table[] = { + {USB_DEVICE(USB_CPCUSB_VENDOR_ID, USB_CPCUSB_M16C_PRODUCT_ID)}, + {USB_DEVICE(USB_CPCUSB_VENDOR_ID, USB_CPCUSB_LPC2119_PRODUCT_ID)}, + {} /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(usb, cpcusb_table); + +/* use to prevent kernel panic if driver is unloaded + * while a programm has still open the device + */ +DECLARE_WAIT_QUEUE_HEAD(rmmodWq); +atomic_t useCount; + +static CPC_USB_T *CPCUSB_Table[CPC_USB_CARD_CNT] = { 0 }; +static unsigned int CPCUsbCnt; + +/* prevent races between open() and disconnect() */ +static DECLARE_MUTEX(disconnect_sem); + +/* local function prototypes */ +static ssize_t cpcusb_read(struct file *file, char *buffer, size_t count, + loff_t *ppos); +static ssize_t cpcusb_write(struct file *file, const char *buffer, + size_t count, loff_t *ppos); +static unsigned int cpcusb_poll(struct file *file, poll_table * wait); +static int cpcusb_open(struct inode *inode, struct file *file); +static int cpcusb_release(struct inode *inode, struct file *file); + +static int cpcusb_probe(struct usb_interface *interface, + const struct usb_device_id *id); +static void cpcusb_disconnect(struct usb_interface *interface); + +static void cpcusb_read_bulk_callback(struct urb *urb); +static void cpcusb_write_bulk_callback(struct urb *urb); +static void cpcusb_read_interrupt_callback(struct urb *urb); + +static int cpcusb_setup_intrep(CPC_USB_T *card); + +static struct file_operations cpcusb_fops = { + /* + * The owner field is part of the module-locking + * mechanism. The idea is that the kernel knows + * which module to increment the use-counter of + * BEFORE it calls the device's open() function. + * This also means that the kernel can decrement + * the use-counter again before calling release() + * or should the open() function fail. + */ + .owner = THIS_MODULE, + + .read = cpcusb_read, + .write = cpcusb_write, + .poll = cpcusb_poll, + .open = cpcusb_open, + .release = cpcusb_release, +}; + +/* + * usb class driver info in order to get a minor number from the usb core, + * and to have the device registered with devfs and the driver core + */ +static struct usb_class_driver cpcusb_class = { + .name = "usb/cpc_usb%d", + .fops = &cpcusb_fops, + .minor_base = CPC_USB_BASE_MNR, +}; + +/* usb specific object needed to register this driver with the usb subsystem */ +static struct usb_driver cpcusb_driver = { + .name = "cpc-usb", + .probe = cpcusb_probe, + .disconnect = cpcusb_disconnect, + .id_table = cpcusb_table, +}; + +static int cpcusb_create_info_output(char *buf) +{ + int i = 0, j; + + for (j = 0; j < CPC_USB_CARD_CNT; j++) { + if (CPCUSB_Table[j]) { + CPC_USB_T *card = CPCUSB_Table[j]; + CPC_CHAN_T *chan = card->chan; + + /* MINOR CHANNELNO BUSNO SLOTNO */ + i += sprintf(&buf[i], "%d %s\n", chan->minor, + card->serialNumber); + } + } + + return i; +} + +static int cpcusb_proc_read_info(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = cpcusb_create_info_output(page); + + if (len <= off + count) + *eof = 1; + *start = page + off; + len -= off; + if (len > count) + len = count; + if (len < 0) + len = 0; + + return len; +} + +/* + * Remove CPC-USB and cleanup + */ +static inline void cpcusb_delete(CPC_USB_T *card) +{ + if (card) { + if (card->chan) { + if (card->chan->buf) + vfree(card->chan->buf); + + if (card->chan->CPCWait_q) + kfree(card->chan->CPCWait_q); + + kfree(card->chan); + } + + CPCUSB_Table[card->idx] = NULL; + kfree(card); + } +} + +/* + * setup the interrupt IN endpoint of a specific CPC-USB device + */ +static int cpcusb_setup_intrep(CPC_USB_T *card) +{ + int retval = 0; + struct usb_endpoint_descriptor *ep; + + ep = &card->interface->altsetting[0].endpoint[card->num_intr_in].desc; + + card->intr_in_buffer[0] = 0; + card->free_slots = 15; /* initial size */ + + /* setup the urb */ + usb_fill_int_urb(card->intr_in_urb, card->udev, + usb_rcvintpipe(card->udev, card->num_intr_in), + card->intr_in_buffer, + sizeof(card->intr_in_buffer), + cpcusb_read_interrupt_callback, + card, + ep->bInterval); + + card->intr_in_urb->status = 0; /* needed! */ + + /* submit the urb */ + retval = usb_submit_urb(card->intr_in_urb, GFP_KERNEL); + + if (retval) + err("%s - failed submitting intr urb, error %d", __func__, + retval); + + return retval; +} + +static int cpcusb_open(struct inode *inode, struct file *file) +{ + CPC_USB_T *card = NULL; + struct usb_interface *interface; + int subminor; + int j, retval = 0; + + subminor = iminor(inode); + + /* prevent disconnects */ + down(&disconnect_sem); + + interface = usb_find_interface(&cpcusb_driver, subminor); + if (!interface) { + err("%s - error, can't find device for minor %d", + __func__, subminor); + retval = CPC_ERR_NO_INTERFACE_PRESENT; + goto exit_no_device; + } + + card = usb_get_intfdata(interface); + if (!card) { + retval = CPC_ERR_NO_INTERFACE_PRESENT; + goto exit_no_device; + } + + /* lock this device */ + down(&card->sem); + + /* increment our usage count for the driver */ + if (card->open) { + dbg("device already opened"); + retval = CPC_ERR_CHANNEL_ALREADY_OPEN; + goto exit_on_error; + } + + /* save our object in the file's private structure */ + file->private_data = card; + for (j = 0; j < CPC_USB_URB_CNT; j++) { + usb_fill_bulk_urb(card->urbs[j].urb, card->udev, + usb_rcvbulkpipe(card->udev, card->num_bulk_in), + card->urbs[j].buffer, card->urbs[j].size, + cpcusb_read_bulk_callback, card); + + retval = usb_submit_urb(card->urbs[j].urb, GFP_KERNEL); + + if (retval) { + err("%s - failed submitting read urb, error %d", + __func__, retval); + retval = CPC_ERR_TRANSMISSION_FAILED; + goto exit_on_error; + } + } + + info("%s - %d URB's submitted", __func__, j); + + ResetBuffer(card->chan); + + cpcusb_setup_intrep(card); + card->open = 1; + + atomic_inc(&useCount); + +exit_on_error: + /* unlock this device */ + up(&card->sem); + +exit_no_device: + up(&disconnect_sem); + + return retval; +} + +static unsigned int cpcusb_poll(struct file *file, poll_table * wait) +{ + CPC_USB_T *card = (CPC_USB_T *) file->private_data; + unsigned int retval = 0; + + if (!card) { + err("%s - device object lost", __func__); + return -EIO; + } + + poll_wait(file, card->chan->CPCWait_q, wait); + + if (IsBufferNotEmpty(card->chan) || !(card->present)) + retval |= (POLLIN | POLLRDNORM); + + if (card->free_slots) + retval |= (POLLOUT | POLLWRNORM); + + return retval; +} + +static int cpcusb_release(struct inode *inode, struct file *file) +{ + CPC_USB_T *card = (CPC_USB_T *) file->private_data; + int j, retval = 0; + + if (card == NULL) { + dbg("%s - object is NULL", __func__); + return CPC_ERR_NO_INTERFACE_PRESENT; + } + + /* lock our device */ + down(&card->sem); + + if (!card->open) { + dbg("%s - device not opened", __func__); + retval = CPC_ERR_NO_INTERFACE_PRESENT; + goto exit_not_opened; + } + + /* if device wasn't unplugged kill all urbs */ + if (card->present) { + /* kill read urbs */ + for (j = 0; j < CPC_USB_URB_CNT; j++) { + usb_kill_urb(card->urbs[j].urb); + } + + /* kill irq urb */ + usb_kill_urb(card->intr_in_urb); + + /* kill write urbs */ + for (j = 0; j < CPC_USB_URB_CNT; j++) { + if (atomic_read(&card->wrUrbs[j].busy)) { + usb_kill_urb(card->wrUrbs[j].urb); + wait_for_completion(&card->wrUrbs[j].finished); + } + } + } + + atomic_dec(&useCount); + + /* last process detached */ + if (atomic_read(&useCount) == 0) { + wake_up(&rmmodWq); + } + + if (!card->present && card->open) { + /* the device was unplugged before the file was released */ + up(&card->sem); + cpcusb_delete(card); + return 0; + } + + card->open = 0; + +exit_not_opened: + up(&card->sem); + + return 0; +} + +static ssize_t cpcusb_read(struct file *file, char *buffer, size_t count, + loff_t *ppos) +{ + CPC_USB_T *card = (CPC_USB_T *) file->private_data; + CPC_CHAN_T *chan; + int retval = 0; + + if (count < sizeof(CPC_MSG_T)) + return CPC_ERR_UNKNOWN; + + /* check if can read from the given address */ + if (!access_ok(VERIFY_WRITE, buffer, count)) + return CPC_ERR_UNKNOWN; + + /* lock this object */ + down(&card->sem); + + /* verify that the device wasn't unplugged */ + if (!card->present) { + up(&card->sem); + return CPC_ERR_NO_INTERFACE_PRESENT; + } + + if (IsBufferEmpty(card->chan)) { + retval = 0; + } else { + chan = card->chan; + +#if 0 + /* convert LPC2119 params back to SJA1000 params */ + if (card->deviceRevision >= 0x0200 + && chan->buf[chan->oidx].type == CPC_MSG_T_CAN_PRMS) { + LPC2119_TO_SJA1000_Params(&chan->buf[chan->oidx]); + } +#endif + + if (copy_to_user(buffer, &chan->buf[chan->oidx], count) != 0) { + retval = CPC_ERR_IO_TRANSFER; + } else { + chan->oidx = (chan->oidx + 1) % CPC_MSG_BUF_CNT; + chan->WnR = 1; + retval = sizeof(CPC_MSG_T); + } + } +/* spin_unlock_irqrestore(&card->slock, flags); */ + + /* unlock the device */ + up(&card->sem); + + return retval; +} + +#define SHIFT 1 +static inline void cpcusb_align_buffer_alignment(unsigned char *buf) +{ + /* CPC-USB uploads packed bytes. */ + CPC_MSG_T *cpc = (CPC_MSG_T *) buf; + unsigned int i; + + for (i = 0; i < cpc->length + (2 * sizeof(unsigned long)); i++) { + ((unsigned char *) &cpc->msgid)[1 + i] = + ((unsigned char *) &cpc->msgid)[1 + SHIFT + i]; + } +} + +static int cpc_get_buffer_count(CPC_CHAN_T *chan) +{ + /* check the buffer parameters */ + if (chan->iidx == chan->oidx) + return !chan->WnR ? CPC_MSG_BUF_CNT : 0; + else if (chan->iidx >= chan->oidx) + return (chan->iidx - chan->oidx) % CPC_MSG_BUF_CNT; + + return (chan->iidx + CPC_MSG_BUF_CNT - chan->oidx) % CPC_MSG_BUF_CNT; +} + +static ssize_t cpcusb_write(struct file *file, const char *buffer, + size_t count, loff_t *ppos) +{ + CPC_USB_T *card = (CPC_USB_T *) file->private_data; + CPC_USB_WRITE_URB_T *wrUrb = NULL; + + ssize_t bytes_written = 0; + int retval = 0; + int j; + + unsigned char *obuf = NULL; + unsigned char type = 0; + CPC_MSG_T *info = NULL; + + dbg("%s - entered minor %d, count = %zu, present = %d", + __func__, card->minor, count, card->present); + + if (count > sizeof(CPC_MSG_T)) + return CPC_ERR_UNKNOWN; + + /* check if can read from the given address */ + if (!access_ok(VERIFY_READ, buffer, count)) + return CPC_ERR_UNKNOWN; + + /* lock this object */ + down(&card->sem); + + /* verify that the device wasn't unplugged */ + if (!card->present) { + retval = CPC_ERR_NO_INTERFACE_PRESENT; + goto exit; + } + + /* verify that we actually have some data to write */ + if (count == 0) { + dbg("%s - write request of 0 bytes", __func__); + goto exit; + } + + if (card->free_slots <= 5) { + info = (CPC_MSG_T *) buffer; + + if (info->type != CPC_CMD_T_CLEAR_CMD_QUEUE + || card->free_slots <= 0) { + dbg("%s - send buffer full please try again %d", + __func__, card->free_slots); + retval = CPC_ERR_CAN_NO_TRANSMIT_BUF; + goto exit; + } + } + + /* Find a free write urb */ + for (j = 0; j < CPC_USB_URB_CNT; j++) { + if (!atomic_read(&card->wrUrbs[j].busy)) { + wrUrb = &card->wrUrbs[j]; /* remember found URB */ + atomic_set(&wrUrb->busy, 1); /* lock this URB */ + init_completion(&wrUrb->finished); /* init completion */ + dbg("WR URB no. %d started", j); + break; + } + } + + /* don't found write urb say error */ + if (!wrUrb) { + dbg("%s - no free send urb available", __func__); + retval = CPC_ERR_CAN_NO_TRANSMIT_BUF; + goto exit; + } + dbg("URB write req"); + + obuf = (unsigned char *) wrUrb->urb->transfer_buffer; + + /* copy the data from userspace into our transfer buffer; + * this is the only copy required. + */ + if (copy_from_user(&obuf[4], buffer, count) != 0) { + atomic_set(&wrUrb->busy, 0); /* release urb */ + retval = CPC_ERR_IO_TRANSFER; + goto exit; + } + + /* check if it is a DRIVER information message, so we can + * response to that message and not the USB + */ + info = (CPC_MSG_T *) &obuf[4]; + + bytes_written = 11 + info->length; + if (bytes_written >= wrUrb->size) { + retval = CPC_ERR_IO_TRANSFER; + goto exit; + } + + switch (info->type) { + case CPC_CMD_T_CLEAR_MSG_QUEUE: + ResetBuffer(card->chan); + break; + + case CPC_CMD_T_INQ_MSG_QUEUE_CNT: + retval = cpc_get_buffer_count(card->chan); + atomic_set(&wrUrb->busy, 0); + + goto exit; + + case CPC_CMD_T_INQ_INFO: + if (info->msg.info.source == CPC_INFOMSG_T_DRIVER) { + /* release urb cause we'll use it for driver + * information + */ + atomic_set(&wrUrb->busy, 0); + if (IsBufferFull(card->chan)) { + retval = CPC_ERR_IO_TRANSFER; + goto exit; + } + + /* it is a driver information request message and we have + * free rx slots to store the response + */ + type = info->msg.info.type; + info = &card->chan->buf[card->chan->iidx]; + + info->type = CPC_MSG_T_INFO; + info->msg.info.source = CPC_INFOMSG_T_DRIVER; + info->msg.info.type = type; + + switch (type) { + case CPC_INFOMSG_T_VERSION: + info->length = strlen(CPC_DRIVER_VERSION) + 2; + sprintf(info->msg.info.msg, "%s\n", + CPC_DRIVER_VERSION); + break; + + case CPC_INFOMSG_T_SERIAL: + info->length = strlen(CPC_DRIVER_SERIAL) + 2; + sprintf(info->msg.info.msg, "%s\n", + CPC_DRIVER_SERIAL); + break; + + default: + info->length = 2; + info->msg.info.type = + CPC_INFOMSG_T_UNKNOWN_TYPE; + } + + card->chan->WnR = 0; + card->chan->iidx = + (card->chan->iidx + 1) % CPC_MSG_BUF_CNT; + + retval = info->length; + goto exit; + } + break; + case CPC_CMD_T_CAN_PRMS: + /* Check the controller type. If it's the new CPC-USB, make sure if these are SJA1000 params */ + if (info->msg.canparams.cc_type != SJA1000 + && info->msg.canparams.cc_type != M16C_BASIC + && (card->productId == USB_CPCUSB_LPC2119_PRODUCT_ID + && info->msg.canparams.cc_type != SJA1000)) { + /* don't forget to release the urb */ + atomic_set(&wrUrb->busy, 0); + retval = CPC_ERR_WRONG_CONTROLLER_TYPE; + goto exit; + } + break; + } + + /* just convert the params if it is an old CPC-USB with M16C controller */ + if (card->productId == USB_CPCUSB_M16C_PRODUCT_ID) { + /* if it is a parameter message convert it from SJA1000 controller + * settings to M16C Basic controller settings + */ + SJA1000_TO_M16C_BASIC_Params((CPC_MSG_T *) &obuf[4]); + } + + /* don't forget the byte alignment */ + cpcusb_align_buffer_alignment(&obuf[4]); + + /* setup a the 4 byte header */ + obuf[0] = obuf[1] = obuf[2] = obuf[3] = 0; + + /* this urb was already set up, except for this write size */ + wrUrb->urb->transfer_buffer_length = bytes_written + 4; + + /* send the data out the bulk port */ + /* a character device write uses GFP_KERNEL, + unless a spinlock is held */ + retval = usb_submit_urb(wrUrb->urb, GFP_KERNEL); + if (retval) { + atomic_set(&wrUrb->busy, 0); /* release urb */ + err("%s - failed submitting write urb, error %d", + __func__, retval); + } else { + retval = bytes_written; + } + +exit: + /* unlock the device */ + up(&card->sem); + + dbg("%s - leaved", __func__); + + return retval; +} + +/* + * callback for interrupt IN urb + */ +static void cpcusb_read_interrupt_callback(struct urb *urb) +{ + CPC_USB_T *card = (CPC_USB_T *) urb->context; + int retval; + unsigned long flags; + + spin_lock_irqsave(&card->slock, flags); + + if (!card->present) { + spin_unlock_irqrestore(&card->slock, flags); + info("%s - no such device", __func__); + return; + } + + switch (urb->status) { + case 0: /* success */ + card->free_slots = card->intr_in_buffer[1]; + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + /* urb was killed */ + spin_unlock_irqrestore(&card->slock, flags); + dbg("%s - intr urb killed", __func__); + return; + default: + info("%s - nonzero urb status %d", __func__, urb->status); + break; + } + + retval = usb_submit_urb(urb, GFP_ATOMIC); + if (retval) { + err("%s - failed resubmitting intr urb, error %d", + __func__, retval); + } + + spin_unlock_irqrestore(&card->slock, flags); + wake_up_interruptible(card->chan->CPCWait_q); + + return; +} + +#define UN_SHIFT 1 +#define CPCMSG_HEADER_LEN_FIRMWARE 11 +static inline int cpcusb_unalign_and_copy_buffy(unsigned char *out, + unsigned char *in) +{ + unsigned int i, j; + + for (i = 0; i < 3; i++) + out[i] = in[i]; + + for (j = 0; j < (in[1] + (CPCMSG_HEADER_LEN_FIRMWARE - 3)); j++) + out[j + i + UN_SHIFT] = in[j + i]; + + return i + j; +} + +/* + * callback for bulk IN urb + */ +static void cpcusb_read_bulk_callback(struct urb *urb) +{ + CPC_USB_T *card = (CPC_USB_T *) urb->context; + CPC_CHAN_T *chan; + unsigned char *ibuf = urb->transfer_buffer; + int retval, msgCnt, start, again = 0; + unsigned long flags; + + if (!card) { + err("%s - device object lost", __func__); + return; + } + + spin_lock_irqsave(&card->slock, flags); + + if (!card->present) { + spin_unlock_irqrestore(&card->slock, flags); + info("%s - no such device", __func__); + return; + } + + switch (urb->status) { + case 0: /* success */ + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + /* urb was killed */ + spin_unlock_irqrestore(&card->slock, flags); + dbg("%s - read urb killed", __func__); + return; + default: + info("%s - nonzero urb status %d", __func__, urb->status); + break; + } + + if (urb->actual_length) { + msgCnt = ibuf[0] & ~0x80; + again = ibuf[0] & 0x80; + + /* we have a 4 byte header */ + start = 4; + chan = card->chan; + while (msgCnt) { + if (!(IsBufferFull(card->chan))) { + start += + cpcusb_unalign_and_copy_buffy((unsigned char *) + &chan->buf[chan->iidx], &ibuf[start]); + + if (start > urb->transfer_buffer_length) { + err("%d > %d", start, urb->transfer_buffer_length); + break; + } + + chan->WnR = 0; + chan->iidx = (chan->iidx + 1) % CPC_MSG_BUF_CNT; + msgCnt--; + } else { + break; + } + } + } + + usb_fill_bulk_urb(urb, card->udev, + usb_rcvbulkpipe(card->udev, card->num_bulk_in), + urb->transfer_buffer, + urb->transfer_buffer_length, + cpcusb_read_bulk_callback, card); + + retval = usb_submit_urb(urb, GFP_ATOMIC); + + if (retval) { + err("%s - failed resubmitting read urb, error %d", __func__, retval); + } + + spin_unlock_irqrestore(&card->slock, flags); + + wake_up_interruptible(card->chan->CPCWait_q); +} + +/* + * callback for bulk IN urb + */ +static void cpcusb_write_bulk_callback(struct urb *urb) +{ + CPC_USB_T *card = (CPC_USB_T *) urb->context; + unsigned long flags; + int j; + + spin_lock_irqsave(&card->slock, flags); + + /* find this urb */ + for (j = 0; j < CPC_USB_URB_CNT; j++) { + if (card->wrUrbs[j].urb == urb) { + dbg("URB found no. %d", j); + /* notify anyone waiting that the write has finished */ + complete(&card->wrUrbs[j].finished); + atomic_set(&card->wrUrbs[j].busy, 0); + break; + } + } + + switch (urb->status) { + case 0: /* success */ + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + /* urb was killed */ + spin_unlock_irqrestore(&card->slock, flags); + dbg("%s - write urb no. %d killed", __func__, j); + return; + default: + info("%s - nonzero urb status %d", __func__, urb->status); + break; + } + + spin_unlock_irqrestore(&card->slock, flags); + + wake_up_interruptible(card->chan->CPCWait_q); +} + +static inline int cpcusb_get_free_slot(void) +{ + int i; + + for (i = 0; i < CPC_USB_CARD_CNT; i++) { + if (!CPCUSB_Table[i]) + return i; + } + + return -1; +} + +/* + * probe function for new CPC-USB devices + */ +static int cpcusb_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + CPC_USB_T *card = NULL; + CPC_CHAN_T *chan = NULL; + + struct usb_device *udev = interface_to_usbdev(interface); + struct usb_host_interface *iface_desc; + struct usb_endpoint_descriptor *endpoint; + + int i, j, retval = -ENOMEM, slot; + + slot = cpcusb_get_free_slot(); + if (slot < 0) { + info("No more devices supported"); + return -ENOMEM; + } + + /* allocate memory for our device state and initialize it */ + card = kzalloc(sizeof(CPC_USB_T), GFP_KERNEL); + if (!card) { + err("Out of memory"); + return -ENOMEM; + } + CPCUSB_Table[slot] = card; + + /* allocate and initialize the channel struct */ + card->chan = kmalloc(sizeof(CPC_CHAN_T), GFP_KERNEL); + if (!card->chan) { + kfree(card); + err("Out of memory"); + return -ENOMEM; + } + + chan = card->chan; + memset(chan, 0, sizeof(CPC_CHAN_T)); + ResetBuffer(chan); + + init_MUTEX(&card->sem); + spin_lock_init(&card->slock); + + card->udev = udev; + card->interface = interface; + if (udev->descriptor.iSerialNumber) { + usb_string(udev, udev->descriptor.iSerialNumber, card->serialNumber, + 128); + info("Serial %s", card->serialNumber); + } + + card->productId = udev->descriptor.idProduct; + info("Product %s", + card->productId == USB_CPCUSB_LPC2119_PRODUCT_ID ? + "CPC-USB/ARM7" : "CPC-USB/M16C"); + + /* set up the endpoint information */ + /* check out the endpoints */ + /* use only the first bulk-in and bulk-out endpoints */ + iface_desc = &interface->altsetting[0]; + for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { + endpoint = &iface_desc->endpoint[i].desc; + + if (!card->num_intr_in && + (endpoint->bEndpointAddress & USB_DIR_IN) && + ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) + == USB_ENDPOINT_XFER_INT)) { + card->intr_in_urb = usb_alloc_urb(0, GFP_KERNEL); + card->num_intr_in = 1; + + if (!card->intr_in_urb) { + err("No free urbs available"); + goto error; + } + + dbg("intr_in urb %d", card->num_intr_in); + } + + if (!card->num_bulk_in && + (endpoint->bEndpointAddress & USB_DIR_IN) && + ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) + == USB_ENDPOINT_XFER_BULK)) { + card->num_bulk_in = 2; + for (j = 0; j < CPC_USB_URB_CNT; j++) { + card->urbs[j].size = endpoint->wMaxPacketSize; + card->urbs[j].urb = usb_alloc_urb(0, GFP_KERNEL); + if (!card->urbs[j].urb) { + err("No free urbs available"); + goto error; + } + card->urbs[j].buffer = + usb_buffer_alloc(udev, + card->urbs[j].size, + GFP_KERNEL, + &card->urbs[j].urb->transfer_dma); + if (!card->urbs[j].buffer) { + err("Couldn't allocate bulk_in_buffer"); + goto error; + } + } + info("%s - %d reading URB's allocated", + __func__, CPC_USB_URB_CNT); + } + + if (!card->num_bulk_out && + !(endpoint->bEndpointAddress & USB_DIR_IN) && + ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) + == USB_ENDPOINT_XFER_BULK)) { + + card->num_bulk_out = 2; + + for (j = 0; j < CPC_USB_URB_CNT; j++) { + card->wrUrbs[j].size = + endpoint->wMaxPacketSize; + card->wrUrbs[j].urb = + usb_alloc_urb(0, GFP_KERNEL); + if (!card->wrUrbs[j].urb) { + err("No free urbs available"); + goto error; + } + card->wrUrbs[j].buffer = usb_buffer_alloc(udev, + card->wrUrbs[j].size, GFP_KERNEL, + &card->wrUrbs[j].urb->transfer_dma); + + if (!card->wrUrbs[j].buffer) { + err("Couldn't allocate bulk_out_buffer"); + goto error; + } + + usb_fill_bulk_urb(card->wrUrbs[j].urb, udev, + usb_sndbulkpipe(udev, endpoint->bEndpointAddress), + card->wrUrbs[j].buffer, + card->wrUrbs[j].size, + cpcusb_write_bulk_callback, + card); + } + + info("%s - %d writing URB's allocated", __func__, CPC_USB_URB_CNT); + } + } + + if (!(card->num_bulk_in && card->num_bulk_out)) { + err("Couldn't find both bulk-in and bulk-out endpoints"); + goto error; + } + + /* allow device read, write and ioctl */ + card->present = 1; + + /* we can register the device now, as it is ready */ + usb_set_intfdata(interface, card); + retval = usb_register_dev(interface, &cpcusb_class); + + if (retval) { + /* something prevented us from registering this driver */ + err("Not able to get a minor for this device."); + usb_set_intfdata(interface, NULL); + goto error; + } + + card->chan->minor = card->minor = interface->minor; + + chan->buf = vmalloc(sizeof(CPC_MSG_T) * CPC_MSG_BUF_CNT); + if (chan->buf == NULL) { + err("Out of memory"); + retval = -ENOMEM; + goto error; + } + info("Allocated memory for %d messages (%lu kbytes)", + CPC_MSG_BUF_CNT, (long unsigned int)(sizeof(CPC_MSG_T) * CPC_MSG_BUF_CNT) / 1000); + memset(chan->buf, 0, sizeof(CPC_MSG_T) * CPC_MSG_BUF_CNT); + + ResetBuffer(chan); + + card->chan->CPCWait_q = kmalloc(sizeof(wait_queue_head_t), GFP_KERNEL); + if (!card->chan->CPCWait_q) { + err("Out of memory"); + retval = -ENOMEM; + goto error; + } + init_waitqueue_head(card->chan->CPCWait_q); + + CPCUSB_Table[slot] = card; + card->idx = slot; + CPCUsbCnt++; + + /* let the user know what node this device is now attached to */ + info("Device now attached to USB-%d", card->minor); + return 0; + +error: + for (j = 0; j < CPC_USB_URB_CNT; j++) { + if (card->urbs[j].buffer) { + usb_buffer_free(card->udev, card->urbs[j].size, + card->urbs[j].buffer, + card->urbs[j].urb->transfer_dma); + card->urbs[j].buffer = NULL; + } + if (card->urbs[j].urb) { + usb_free_urb(card->urbs[j].urb); + card->urbs[j].urb = NULL; + } + } + + cpcusb_delete(card); + return retval; +} + +/* + * called by the usb core when the device is removed from the system + */ +static void cpcusb_disconnect(struct usb_interface *interface) +{ + CPC_USB_T *card = NULL; + int minor, j; + + /* prevent races with open() */ + down(&disconnect_sem); + + card = usb_get_intfdata(interface); + usb_set_intfdata(interface, NULL); + + down(&card->sem); + + /* prevent device read, write and ioctl */ + card->present = 0; + + minor = card->minor; + + /* free all urbs and their buffers */ + for (j = 0; j < CPC_USB_URB_CNT; j++) { + /* terminate an ongoing write */ + if (atomic_read(&card->wrUrbs[j].busy)) { + usb_kill_urb(card->wrUrbs[j].urb); + wait_for_completion(&card->wrUrbs[j].finished); + } + usb_buffer_free(card->udev, card->wrUrbs[j].size, + card->wrUrbs[j].buffer, + card->wrUrbs[j].urb->transfer_dma); + usb_free_urb(card->wrUrbs[j].urb); + } + info("%d write URBs freed", CPC_USB_URB_CNT); + + /* free all urbs and their buffers */ + for (j = 0; j < CPC_USB_URB_CNT; j++) { + usb_buffer_free(card->udev, card->urbs[j].size, + card->urbs[j].buffer, + card->urbs[j].urb->transfer_dma); + usb_free_urb(card->urbs[j].urb); + } + info("%d read URBs freed", CPC_USB_URB_CNT); + usb_free_urb(card->intr_in_urb); + + /* give back our minor */ + usb_deregister_dev(interface, &cpcusb_class); + + up(&card->sem); + + /* if the device is opened, cpcusb_release will clean this up */ + if (!card->open) + cpcusb_delete(card); + else + wake_up_interruptible(card->chan->CPCWait_q); + + up(&disconnect_sem); + + CPCUsbCnt--; + info("USB-%d now disconnected", minor); +} + +static int __init CPCUsb_Init(void) +{ + int result, i; + + info(DRIVER_DESC " v" DRIVER_VERSION); + info("Build on " __DATE__ " at " __TIME__); + + for (i = 0; i < CPC_USB_CARD_CNT; i++) + CPCUSB_Table[i] = 0; + + /* register this driver with the USB subsystem */ + result = usb_register(&cpcusb_driver); + if (result) { + err("usb_register failed. Error number %d", result); + return result; + } + + procDir = proc_mkdir(CPC_USB_PROC_DIR, NULL); + if (!procDir) { + err("Could not create proc entry"); + } else { + procEntry = create_proc_read_entry("info", 0444, procDir, + cpcusb_proc_read_info, + NULL); + if (!procEntry) { + err("Could not create proc entry %s", CPC_USB_PROC_DIR "/info"); + remove_proc_entry(CPC_USB_PROC_DIR, NULL); + procDir = NULL; + } + } + + return 0; +} + +static void __exit CPCUsb_Exit(void) +{ + wait_event(rmmodWq, !atomic_read(&useCount)); + + /* deregister this driver with the USB subsystem */ + usb_deregister(&cpcusb_driver); + + if (procDir) { + if (procEntry) + remove_proc_entry("info", procDir); + remove_proc_entry(CPC_USB_PROC_DIR, NULL); + } +} + +module_init(CPCUsb_Init); +module_exit(CPCUsb_Exit); diff --git a/drivers/staging/cpc-usb/cpc.h b/drivers/staging/cpc-usb/cpc.h new file mode 100644 index 000000000000..ed8cb34d4763 --- /dev/null +++ b/drivers/staging/cpc-usb/cpc.h @@ -0,0 +1,440 @@ +/* + * CPC CAN Interface Definitions + * + * Copyright (C) 2000-2008 EMS Dr. Thomas Wuensche + * + * 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. + */ +#ifndef CPC_HEADER +#define CPC_HEADER + +// the maximum length of the union members within a CPC_MSG +// this value can be defined by the customer, but has to be +// >= 64 bytes +// however, if not defined before, we set a length of 64 byte +#if !defined(CPC_MSG_LEN) || (CPC_MSG_LEN < 64) +#undef CPC_MSG_LEN +#define CPC_MSG_LEN 64 +#endif + +// check the operating system used +#ifdef _WIN32 // running a Windows OS + +// define basic types on Windows platforms +#ifdef _MSC_VER // Visual Studio + typedef unsigned __int8 u8; + typedef unsigned __int16 u16; + typedef unsigned __int32 u32; +#else // Borland Compiler + typedef unsigned char u8; + typedef unsigned short u16; + typedef unsigned int u32; +#endif + // on Windows OS we use a byte alignment of 1 + #pragma pack(push, 1) + + // set the calling conventions for the library function calls + #define CALL_CONV __stdcall +#else + // Kernel headers already define this types + #ifndef __KERNEL__ + // define basic types + typedef unsigned char u8; + typedef unsigned short u16; + typedef unsigned int u32; + #endif + + // Linux does not use this calling convention + #define CALL_CONV +#endif + +// Transmission of events from CPC interfaces to PC can be individually +// controlled per event type. Default state is: don't transmit +// Control values are constructed by bit-or of Subject and Action +// and passed to CPC_Control() + +// Control-Values for CPC_Control() Command Subject Selection +#define CONTR_CAN_Message 0x04 +#define CONTR_Busload 0x08 +#define CONTR_CAN_State 0x0C +#define CONTR_SendAck 0x10 +#define CONTR_Filter 0x14 +#define CONTR_CmdQueue 0x18 // reserved, do not use +#define CONTR_BusError 0x1C + +// Control Command Actions +#define CONTR_CONT_OFF 0 +#define CONTR_CONT_ON 1 +#define CONTR_SING_ON 2 +// CONTR_SING_ON doesn't change CONTR_CONT_ON state, so it should be +// read as: transmit at least once + +// defines for confirmed request +#define DO_NOT_CONFIRM 0 +#define DO_CONFIRM 1 + +// event flags +#define EVENT_READ 0x01 +#define EVENT_WRITE 0x02 + +// Messages from CPC to PC contain a message object type field. +// The following message types are sent by CPC and can be used in +// handlers, others should be ignored. +#define CPC_MSG_T_RESYNC 0 // Normally to be ignored +#define CPC_MSG_T_CAN 1 // CAN data frame +#define CPC_MSG_T_BUSLOAD 2 // Busload message +#define CPC_MSG_T_STRING 3 // Normally to be ignored +#define CPC_MSG_T_CONTI 4 // Normally to be ignored +#define CPC_MSG_T_MEM 7 // Normally not to be handled +#define CPC_MSG_T_RTR 8 // CAN remote frame +#define CPC_MSG_T_TXACK 9 // Send acknowledge +#define CPC_MSG_T_POWERUP 10 // Power-up message +#define CPC_MSG_T_CMD_NO 11 // Normally to be ignored +#define CPC_MSG_T_CAN_PRMS 12 // Actual CAN parameters +#define CPC_MSG_T_ABORTED 13 // Command aborted message +#define CPC_MSG_T_CANSTATE 14 // CAN state message +#define CPC_MSG_T_RESET 15 // used to reset CAN-Controller +#define CPC_MSG_T_XCAN 16 // XCAN data frame +#define CPC_MSG_T_XRTR 17 // XCAN remote frame +#define CPC_MSG_T_INFO 18 // information strings +#define CPC_MSG_T_CONTROL 19 // used for control of interface/driver behaviour +#define CPC_MSG_T_CONFIRM 20 // response type for confirmed requests +#define CPC_MSG_T_OVERRUN 21 // response type for overrun conditions +#define CPC_MSG_T_KEEPALIVE 22 // response type for keep alive conditions +#define CPC_MSG_T_CANERROR 23 // response type for bus error conditions +#define CPC_MSG_T_DISCONNECTED 24 // response type for a disconnected interface +#define CPC_MSG_T_ERR_COUNTER 25 // RX/TX error counter of CAN controller + +#define CPC_MSG_T_FIRMWARE 100 // response type for USB firmware download + +// Messages from the PC to the CPC interface contain a command field +// Most of the command types are wrapped by the library functions and have therefore +// normally not to be used. +// However, programmers who wish to circumvent the library and talk directly +// to the drivers (mainly Linux programmers) can use the following +// command types: + +#define CPC_CMD_T_CAN 1 // CAN data frame +#define CPC_CMD_T_CONTROL 3 // used for control of interface/driver behaviour +#define CPC_CMD_T_CAN_PRMS 6 // set CAN parameters +#define CPC_CMD_T_CLEARBUF 8 // clears input queue; this is depricated, use CPC_CMD_T_CLEAR_MSG_QUEUE instead +#define CPC_CMD_T_INQ_CAN_PARMS 11 // inquire actual CAN parameters +#define CPC_CMD_T_FILTER_PRMS 12 // set filter parameter +#define CPC_CMD_T_RTR 13 // CAN remote frame +#define CPC_CMD_T_CANSTATE 14 // CAN state message +#define CPC_CMD_T_XCAN 15 // XCAN data frame +#define CPC_CMD_T_XRTR 16 // XCAN remote frame +#define CPC_CMD_T_RESET 17 // used to reset CAN-Controller +#define CPC_CMD_T_INQ_INFO 18 // miscellanous information strings +#define CPC_CMD_T_OPEN_CHAN 19 // open a channel +#define CPC_CMD_T_CLOSE_CHAN 20 // close a channel +#define CPC_CMD_T_CNTBUF 21 // this is depricated, use CPC_CMD_T_INQ_MSG_QUEUE_CNT instead +#define CPC_CMD_T_CAN_EXIT 200 // exit the CAN (disable interrupts; reset bootrate; reset output_cntr; mode = 1) + +#define CPC_CMD_T_INQ_MSG_QUEUE_CNT CPC_CMD_T_CNTBUF // inquires the count of elements in the message queue +#define CPC_CMD_T_INQ_ERR_COUNTER 25 // request the CAN controllers error counter +#define CPC_CMD_T_CLEAR_MSG_QUEUE CPC_CMD_T_CLEARBUF // clear CPC_MSG queue +#define CPC_CMD_T_CLEAR_CMD_QUEUE 28 // clear CPC_CMD queue +#define CPC_CMD_T_FIRMWARE 100 // reserved, must not be used +#define CPC_CMD_T_USB_RESET 101 // reserved, must not be used +#define CPC_CMD_T_WAIT_NOTIFY 102 // reserved, must not be used +#define CPC_CMD_T_WAIT_SETUP 103 // reserved, must not be used +#define CPC_CMD_T_ABORT 255 // Normally not to be used + +// definitions for CPC_MSG_T_INFO +// information sources +#define CPC_INFOMSG_T_UNKNOWN_SOURCE 0 +#define CPC_INFOMSG_T_INTERFACE 1 +#define CPC_INFOMSG_T_DRIVER 2 +#define CPC_INFOMSG_T_LIBRARY 3 + +// information types +#define CPC_INFOMSG_T_UNKNOWN_TYPE 0 +#define CPC_INFOMSG_T_VERSION 1 +#define CPC_INFOMSG_T_SERIAL 2 + +// definitions for controller types +#define PCA82C200 1 // Philips basic CAN controller, replaced by SJA1000 +#define SJA1000 2 // Philips basic CAN controller +#define AN82527 3 // Intel full CAN controller +#define M16C_BASIC 4 // M16C controller running in basic CAN (not full CAN) mode + +// channel open error codes +#define CPC_ERR_NO_FREE_CHANNEL -1 // no more free space within the channel array +#define CPC_ERR_CHANNEL_ALREADY_OPEN -2 // the channel is already open +#define CPC_ERR_CHANNEL_NOT_ACTIVE -3 // access to a channel not active failed +#define CPC_ERR_NO_DRIVER_PRESENT -4 // no driver at the location searched by the library +#define CPC_ERR_NO_INIFILE_PRESENT -5 // the library could not find the inifile +#define CPC_ERR_WRONG_PARAMETERS -6 // wrong parameters in the inifile +#define CPC_ERR_NO_INTERFACE_PRESENT -7 // 1. The specified interface is not connected + // 2. The interface (mostly CPC-USB) was disconnected upon operation +#define CPC_ERR_NO_MATCHING_CHANNEL -8 // the driver couldn't find a matching channel +#define CPC_ERR_NO_BUFFER_AVAILABLE -9 // the driver couldn't allocate buffer for messages +#define CPC_ERR_NO_INTERRUPT -10 // the requested interrupt couldn't be claimed +#define CPC_ERR_NO_MATCHING_INTERFACE -11 // no interface type related to this channel was found +#define CPC_ERR_NO_RESOURCES -12 // the requested resources could not be claimed +#define CPC_ERR_SOCKET -13 // error concerning TCP sockets + +// init error codes +#define CPC_ERR_WRONG_CONTROLLER_TYPE -14 // wrong CAN controller type within initialization +#define CPC_ERR_NO_RESET_MODE -15 // the controller could not be set into reset mode +#define CPC_ERR_NO_CAN_ACCESS -16 // the CAN controller could not be accessed + +// transmit error codes +#define CPC_ERR_CAN_WRONG_ID -20 // the provided CAN id is too big +#define CPC_ERR_CAN_WRONG_LENGTH -21 // the provided CAN length is too long +#define CPC_ERR_CAN_NO_TRANSMIT_BUF -22 // the transmit buffer was occupied +#define CPC_ERR_CAN_TRANSMIT_TIMEOUT -23 // The message could not be sent within a + // specified time + +// other error codes +#define CPC_ERR_SERVICE_NOT_SUPPORTED -30 // the requested service is not supported by the interface +#define CPC_ERR_IO_TRANSFER -31 // a transmission error down to the driver occurred +#define CPC_ERR_TRANSMISSION_FAILED -32 // a transmission error down to the interface occurred +#define CPC_ERR_TRANSMISSION_TIMEOUT -33 // a timeout occurred within transmission to the interface +#define CPC_ERR_OP_SYS_NOT_SUPPORTED -35 // the operating system is not supported +#define CPC_ERR_UNKNOWN -40 // an unknown error ocurred (mostly IOCTL errors) + +#define CPC_ERR_LOADING_DLL -50 // the library 'cpcwin.dll' could not be loaded +#define CPC_ERR_ASSIGNING_FUNCTION -51 // the specified function could not be assigned +#define CPC_ERR_DLL_INITIALIZATION -52 // the DLL was not initialized correctly +#define CPC_ERR_MISSING_LICFILE -55 // the file containing the licenses does not exist +#define CPC_ERR_MISSING_LICENSE -56 // a required license was not found + +// CAN state bit values. Ignore any bits not listed +#define CPC_CAN_STATE_BUSOFF 0x80 +#define CPC_CAN_STATE_ERROR 0x40 + +// Mask to help ignore undefined bits +#define CPC_CAN_STATE_MASK 0xc0 + +// CAN-Message representation in a CPC_MSG +// Message object type is CPC_MSG_T_CAN or CPC_MSG_T_RTR +// or CPC_MSG_T_XCAN or CPC_MSG_T_XRTR +typedef struct CPC_CAN_MSG { + u32 id; + u8 length; + u8 msg[8]; +} CPC_CAN_MSG_T; + + +// representation of the CAN parameters for the PCA82C200 controller +typedef struct CPC_PCA82C200_PARAMS { + u8 acc_code; // Acceptance-code for receive, Standard: 0 + u8 acc_mask; // Acceptance-mask for receive, Standard: 0xff (everything) + u8 btr0; // Bus-timing register 0 + u8 btr1; // Bus-timing register 1 + u8 outp_contr; // Output-control register +} CPC_PCA82C200_PARAMS_T; + +// representation of the CAN parameters for the SJA1000 controller +typedef struct CPC_SJA1000_PARAMS { + u8 mode; // enables single or dual acceptance filtering + u8 acc_code0; // Acceptance-code for receive, Standard: 0 + u8 acc_code1; + u8 acc_code2; + u8 acc_code3; + u8 acc_mask0; // Acceptance-mask for receive, Standard: 0xff (everything) + u8 acc_mask1; + u8 acc_mask2; + u8 acc_mask3; + u8 btr0; // Bus-timing register 0 + u8 btr1; // Bus-timing register 1 + u8 outp_contr; // Output-control register +} CPC_SJA1000_PARAMS_T; + +// representation of the CAN parameters for the M16C controller +// in basic CAN mode (means no full CAN) +typedef struct CPC_M16C_BASIC_PARAMS { + u8 con0; + u8 con1; + u8 ctlr0; + u8 ctlr1; + u8 clk; + u8 acc_std_code0; + u8 acc_std_code1; + u8 acc_ext_code0; + u8 acc_ext_code1; + u8 acc_ext_code2; + u8 acc_ext_code3; + u8 acc_std_mask0; + u8 acc_std_mask1; + u8 acc_ext_mask0; + u8 acc_ext_mask1; + u8 acc_ext_mask2; + u8 acc_ext_mask3; +} CPC_M16C_BASIC_PARAMS_T; + +// CAN params message representation +typedef struct CPC_CAN_PARAMS { + u8 cc_type; // represents the controller type + union { + CPC_M16C_BASIC_PARAMS_T m16c_basic; + CPC_SJA1000_PARAMS_T sja1000; + CPC_PCA82C200_PARAMS_T pca82c200; + } cc_params; +} CPC_CAN_PARAMS_T; + +// the following structures are slightly different for Windows and Linux +// To be able to use the 'Select' mechanism with Linux the application +// needs to know the devices file desciptor. +// This mechanism is not implemented within Windows and the file descriptor +// is therefore not needed +#ifdef _WIN32 + +// CAN init params message representation +typedef struct CPC_INIT_PARAMS { + CPC_CAN_PARAMS_T canparams; +} CPC_INIT_PARAMS_T; + +#else// Linux + +// CHAN init params representation +typedef struct CPC_CHAN_PARAMS { + int fd; +} CPC_CHAN_PARAMS_T; + +// CAN init params message representation +typedef struct CPC_INIT_PARAMS { + CPC_CHAN_PARAMS_T chanparams; + CPC_CAN_PARAMS_T canparams; +} CPC_INIT_PARAMS_T; + +#endif + +// structure for confirmed message handling +typedef struct CPC_CONFIRM { + u8 result; // error code +} CPC_CONFIRM_T; + +// structure for information requests +typedef struct CPC_INFO { + u8 source; // interface, driver or library + u8 type; // version or serial number + char msg[CPC_MSG_LEN - 2]; // string holding the requested information +} CPC_INFO_T; + +// OVERRUN /////////////////////////////////////// +// In general two types of overrun may occur. +// A hardware overrun, where the CAN controller +// lost a message, because the interrupt was +// not handled before the next messgae comes in. +// Or a software overrun, where i.e. a received +// message could not be stored in the CPC_MSG +// buffer. + +// After a software overrun has occurred +// we wait until we have CPC_OVR_GAP slots +// free in the CPC_MSG buffer. +#define CPC_OVR_GAP 10 + +// Two types of software overrun may occur. +// A received CAN message or a CAN state event +// can cause an overrun. +// Note: A CPC_CMD which would normally store +// its result immediately in the CPC_MSG +// queue may fail, because the message queue is full. +// This will not generate an overrun message, but +// will halt command execution, until this command +// is able to store its message in the message queue. +#define CPC_OVR_EVENT_CAN 0x01 +#define CPC_OVR_EVENT_CANSTATE 0x02 +#define CPC_OVR_EVENT_BUSERROR 0x04 + +// If the CAN controller lost a message +// we indicate it with the highest bit +// set in the count field. +#define CPC_OVR_HW 0x80 + +// structure for overrun conditions +typedef struct { + u8 event; + u8 count; +} CPC_OVERRUN_T; + +// CAN errors //////////////////////////////////// +// Each CAN controller type has different +// registers to record errors. +// Therefor a structure containing the specific +// errors is set up for each controller here + +// SJA1000 error structure +// see the SJA1000 datasheet for detailed +// explanation of the registers +typedef struct CPC_SJA1000_CAN_ERROR { + u8 ecc; // error capture code register + u8 rxerr; // RX error counter register + u8 txerr; // TX error counter register +} CPC_SJA1000_CAN_ERROR_T; + +// M16C error structure +// see the M16C datasheet for detailed +// explanation of the registers +typedef struct CPC_M16C_CAN_ERROR { + u8 tbd; // to be defined +} CPC_M16C_CAN_ERROR_T; + +// structure for CAN error conditions +#define CPC_CAN_ECODE_ERRFRAME 0x01 +typedef struct CPC_CAN_ERROR { + u8 ecode; + struct { + u8 cc_type; // CAN controller type + union { + CPC_SJA1000_CAN_ERROR_T sja1000; + CPC_M16C_CAN_ERROR_T m16c; + } regs; + } cc; +} CPC_CAN_ERROR_T; + +// Structure containing RX/TX error counter. +// This structure is used to request the +// values of the CAN controllers TX and RX +// error counter. +typedef struct CPC_CAN_ERR_COUNTER { + u8 rx; + u8 tx; +} CPC_CAN_ERR_COUNTER_T; + +// If this flag is set, transmissions from PC to CPC are protected against loss +#define CPC_SECURE_TO_CPC 0x01 + +// If this flag is set, transmissions from CPC to PC are protected against loss +#define CPC_SECURE_TO_PC 0x02 + +// If this flag is set, the CAN-transmit buffer is checked to be free before sending a message +#define CPC_SECURE_SEND 0x04 + +// If this flag is set, the transmission complete flag is checked +// after sending a message +// THIS IS CURRENTLY ONLY IMPLEMENTED IN THE PASSIVE INTERFACE DRIVERS +#define CPC_SECURE_TRANSMIT 0x08 + +// main message type used between library and application +typedef struct CPC_MSG { + u8 type; // type of message + u8 length; // length of data within union 'msg' + u8 msgid; // confirmation handle + u32 ts_sec; // timestamp in seconds + u32 ts_nsec; // timestamp in nano seconds + union { + u8 generic[CPC_MSG_LEN]; + CPC_CAN_MSG_T canmsg; + CPC_CAN_PARAMS_T canparams; + CPC_CONFIRM_T confirmation; + CPC_INFO_T info; + CPC_OVERRUN_T overrun; + CPC_CAN_ERROR_T error; + CPC_CAN_ERR_COUNTER_T err_counter; + u8 busload; + u8 canstate; + } msg; +} CPC_MSG_T; + +#ifdef _WIN32 +#pragma pack(pop) // reset the byte alignment +#endif + +#endif // CPC_HEADER diff --git a/drivers/staging/cpc-usb/cpc_int.h b/drivers/staging/cpc-usb/cpc_int.h new file mode 100644 index 000000000000..a0d60c080819 --- /dev/null +++ b/drivers/staging/cpc-usb/cpc_int.h @@ -0,0 +1,83 @@ +/* + * CPCLIB + * + * Copyright (C) 2000-2008 EMS Dr. Thomas Wuensche + * + * 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. + * + */ +#ifndef CPC_INT_H +#define CPC_INT_H + +#include + +#define CPC_MSG_BUF_CNT 1500 + +#define CPC_PROC_DIR "driver/" + +#undef dbg +#undef err +#undef info + +/* Use our own dbg macro */ +#define dbg(format, arg...) do { if (debug) printk( KERN_INFO format "\n" , ## arg); } while (0) +#define err(format, arg...) do { printk( KERN_INFO "ERROR " format "\n" , ## arg); } while (0) +#define info(format, arg...) do { printk( KERN_INFO format "\n" , ## arg); } while (0) + +/* Macros help using of our buffers */ +#define IsBufferFull(x) (!(x)->WnR) && ((x)->iidx == (x)->oidx) +#define IsBufferEmpty(x) ((x)->WnR) && ((x)->iidx == (x)->oidx) +#define IsBufferNotEmpty(x) (!(x)->WnR) || ((x)->iidx != (x)->oidx) +#define ResetBuffer(x) do { (x)->oidx = (x)->iidx=0; (x)->WnR = 1; } while(0); + +#define CPC_BufWriteAllowed ((chan->oidx != chan->iidx) || chan->WnR) + +typedef void (*chan_write_byte_t) (void *chan, unsigned int reg, + unsigned char val); +typedef unsigned char (*chan_read_byte_t) (void *chan, unsigned int reg); + +typedef struct CPC_CHAN { + void __iomem * canBase; // base address of SJA1000 + chan_read_byte_t read_byte; // CAN controller read access routine + chan_write_byte_t write_byte; // CAN controller write access routine + CPC_MSG_T *buf; // buffer for CPC msg + unsigned int iidx; + unsigned int oidx; + unsigned int WnR; + unsigned int minor; + unsigned int locked; + unsigned int irqDisabled; + + unsigned char cpcCtrlCANMessage; + unsigned char cpcCtrlCANState; + unsigned char cpcCtrlBUSState; + + unsigned char controllerType; + + unsigned long ovrTimeSec; + unsigned long ovrTimeNSec; + unsigned long ovrLockedBuffer; + CPC_OVERRUN_T ovr; + + /* for debugging only */ + unsigned int handledIrqs; + unsigned int lostMessages; + + unsigned int sentStdCan; + unsigned int sentExtCan; + unsigned int sentStdRtr; + unsigned int sentExtRtr; + + unsigned int recvStdCan; + unsigned int recvExtCan; + unsigned int recvStdRtr; + unsigned int recvExtRtr; + + wait_queue_head_t *CPCWait_q; + + void *private; +} CPC_CHAN_T; + +#endif diff --git a/drivers/staging/cpc-usb/cpcusb.h b/drivers/staging/cpc-usb/cpcusb.h new file mode 100644 index 000000000000..e5273ddd9e0a --- /dev/null +++ b/drivers/staging/cpc-usb/cpcusb.h @@ -0,0 +1,86 @@ +/* Header for CPC-USB Driver ******************** + * Copyright 1999, 2000, 2001 + * + * Company: EMS Dr. Thomas Wuensche + * Sonnenhang 3 + * 85304 Ilmmuenster + * Phone: +49-8441-490260 + * Fax: +49-8441-81860 + * email: support@ems-wuensche.com + * WWW: www.ems-wuensche.com + */ + +#ifndef CPCUSB_H +#define CPCUSB_H + +#undef err +#undef dbg +#undef info + +/* Use our own dbg macro */ +#define dbg(format, arg...) do { if (debug) printk(KERN_INFO "CPC-USB: " format "\n" , ## arg); } while (0) +#define info(format, arg...) do { printk(KERN_INFO "CPC-USB: " format "\n" , ## arg); } while (0) +#define err(format, arg...) do { printk(KERN_INFO "CPC-USB(ERROR): " format "\n" , ## arg); } while (0) + +#define CPC_USB_CARD_CNT 4 + +typedef struct CPC_USB_READ_URB { + unsigned char *buffer; /* the buffer to send data */ + size_t size; /* the size of the send buffer */ + struct urb *urb; /* the urb used to send data */ +} CPC_USB_READ_URB_T; + +typedef struct CPC_USB_WRITE_URB { + unsigned char *buffer; /* the buffer to send data */ + size_t size; /* the size of the send buffer */ + struct urb *urb; /* the urb used to send data */ + atomic_t busy; /* true if write urb is busy */ + struct completion finished; /* wait for the write to finish */ +} CPC_USB_WRITE_URB_T; + +#define CPC_USB_URB_CNT 10 + +typedef struct CPC_USB { + struct usb_device *udev; /* save off the usb device pointer */ + struct usb_interface *interface; /* the interface for this device */ + unsigned char minor; /* the starting minor number for this device */ + unsigned char num_ports; /* the number of ports this device has */ + int num_intr_in; /* number of interrupt in endpoints we have */ + int num_bulk_in; /* number of bulk in endpoints we have */ + int num_bulk_out; /* number of bulk out endpoints we have */ + + CPC_USB_READ_URB_T urbs[CPC_USB_URB_CNT]; + + unsigned char intr_in_buffer[4]; /* interrupt transfer buffer */ + struct urb *intr_in_urb; /* interrupt transfer urb */ + + CPC_USB_WRITE_URB_T wrUrbs[CPC_USB_URB_CNT]; + + int open; /* if the port is open or not */ + int present; /* if the device is not disconnected */ + struct semaphore sem; /* locks this structure */ + + int free_slots; /* free send slots of CPC-USB */ + int idx; + + spinlock_t slock; + + char serialNumber[128]; /* serial number */ + int productId; /* product id to differ between M16C and LPC2119 */ + CPC_CHAN_T *chan; +} CPC_USB_T; + +#define CPCTable CPCUSB_Table + +#define CPC_DRIVER_VERSION "0.724" +#define CPC_DRIVER_SERIAL "not applicable" + +#define OBUF_SIZE 255 // 4096 + +/* read timeouts -- RD_NAK_TIMEOUT * RD_EXPIRE = Number of seconds */ +#define RD_NAK_TIMEOUT (10*HZ) /* Default number of X seconds to wait */ +#define RD_EXPIRE 12 /* Number of attempts to wait X seconds */ + +#define CPC_USB_BASE_MNR 0 /* CPC-USB start at minor 0 */ + +#endif diff --git a/drivers/staging/cpc-usb/sja2m16c.h b/drivers/staging/cpc-usb/sja2m16c.h new file mode 100644 index 000000000000..654bd3fc91dc --- /dev/null +++ b/drivers/staging/cpc-usb/sja2m16c.h @@ -0,0 +1,41 @@ +#ifndef _SJA2M16C_H +#define _SJA2M16C_H + +#include "cpc.h" + +#define BAUDRATE_TOLERANCE_PERCENT 1 +#define SAMPLEPOINT_TOLERANCE_PERCENT 5 +#define SAMPLEPOINT_UPPER_LIMIT 88 + +/* M16C parameters */ +struct FIELD_C0CONR { + unsigned int brp:4; + unsigned int sam:1; + unsigned int pr:3; + unsigned int dummy:8; +}; +struct FIELD_C1CONR { + unsigned int ph1:3; + unsigned int ph2:3; + unsigned int sjw:2; + unsigned int dummy:8; +}; +typedef union C0CONR { + unsigned char c0con; + struct FIELD_C0CONR bc0con; +} C0CONR_T; +typedef union C1CONR { + unsigned char c1con; + struct FIELD_C1CONR bc1con; +} C1CONR_T; + +#define SJA_TSEG1 ((pParams->btr1 & 0x0f)+1) +#define SJA_TSEG2 (((pParams->btr1 & 0x70)>>4)+1) +#define SJA_BRP ((pParams->btr0 & 0x3f)+1) +#define SJA_SJW ((pParams->btr0 & 0xc0)>>6) +#define SJA_SAM ((pParams->btr1 & 0x80)>>7) +int baudrate_m16c(int clk, int brp, int pr, int ph1, int ph2); +int samplepoint_m16c(int brp, int pr, int ph1, int ph2); +int SJA1000_TO_M16C_BASIC_Params(CPC_MSG_T *pMsg); + +#endif diff --git a/drivers/staging/cpc-usb/sja2m16c_2.c b/drivers/staging/cpc-usb/sja2m16c_2.c new file mode 100644 index 000000000000..bf0230fb7780 --- /dev/null +++ b/drivers/staging/cpc-usb/sja2m16c_2.c @@ -0,0 +1,452 @@ +/**************************************************************************** +* +* Copyright (c) 2003,2004 by EMS Dr. Thomas Wuensche +* +* - All rights reserved - +* +* This code is provided "as is" without warranty of any kind, either +* expressed or implied, including but not limited to the liability +* concerning the freedom from material defects, the fitness for parti- +* cular purposes or the freedom of proprietary rights of third parties. +* +***************************************************************************** +* Module name.: cpcusb +***************************************************************************** +* Include file: cpc.h +***************************************************************************** +* Project.....: Windows Driver Development Kit +* Filename....: sja2m16c.cpp +* Authors.....: (GU) Gerhard Uttenthaler +* (CS) Christian Schoett +***************************************************************************** +* Short descr.: converts baudrate between SJA1000 and M16C +***************************************************************************** +* Description.: handles the baudrate conversion from SJA1000 parameters to +* M16C parameters +***************************************************************************** +* Address : EMS Dr. Thomas Wuensche +* Sonnenhang 3 +* D-85304 Ilmmuenster +* Tel. : +49-8441-490260 +* Fax. : +49-8441-81860 +* email: support@ems-wuensche.com +***************************************************************************** +* History +***************************************************************************** +* Version Date Auth Remark +* +* 01.00 ?? GU - initial release +* 01.10 ?????????? CS - adapted to fit into the USB Windows driver +* 02.00 18.08.2004 GU - improved the baudrate calculating algorithm +* - implemented acceptance filtering +* 02.10 10.09.2004 CS - adapted to fit into the USB Windows driver +***************************************************************************** +* ToDo's +***************************************************************************** +*/ + +/****************************************************************************/ +/* I N C L U D E S +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cpc.h" +#include "cpc_int.h" +#include "cpcusb.h" + +#include "sja2m16c.h" + +/*********************************************************************/ +int baudrate_m16c(int clk, int brp, int pr, int ph1, int ph2) +{ + return (16000000 / (1 << clk)) / 2 / (brp + 1) / (1 + pr + 1 + + ph1 + 1 + ph2 + + 1); +} + + +/*********************************************************************/ +int samplepoint_m16c(int brp, int pr, int ph1, int ph2) +{ + return (100 * (1 + pr + 1 + ph1 + 1)) / (1 + pr + 1 + ph1 + 1 + + ph2 + 1); +} + + +/**************************************************************************** +* Function.....: SJA1000_TO_M16C_BASIC_Params +* +* Task.........: This routine converts SJA1000 CAN btr parameters into M16C +* parameters based on the sample point and the error. In +* addition it converts the acceptance filter parameters to +* suit the M16C parameters +* +* Parameters...: None +* +* Return values: None +* +* Comments.....: +***************************************************************************** +* History +***************************************************************************** +* 19.01.2005 CS - modifed the conversion of SJA1000 filter params into +* M16C params. Due to compatibility reasons with the +* older 82C200 CAN controller the SJA1000 +****************************************************************************/ +int SJA1000_TO_M16C_BASIC_Params(CPC_MSG_T * in) +{ + int sjaBaudrate; + int sjaSamplepoint; + int *baudrate_error; // BRP[0..15], PR[0..7], PH1[0..7], PH2[0..7] + int *samplepoint_error; // BRP[0..15], PR[0..7], PH1[0..7], PH2[0..7] + int baudrate_error_merk; + int clk, brp, pr, ph1, ph2; + int clk_merk, brp_merk, pr_merk, ph1_merk, ph2_merk; + int index; + unsigned char acc_code0, acc_code1, acc_code2, acc_code3; + unsigned char acc_mask0, acc_mask1, acc_mask2, acc_mask3; + CPC_MSG_T * out; + C0CONR_T c0con; + C1CONR_T c1con; + int tmpAccCode; + int tmpAccMask; + + // we have to convert the parameters into M16C parameters + CPC_SJA1000_PARAMS_T * pParams; + + // check if the type is CAN parameters and if we have to convert the given params + if (in->type != CPC_CMD_T_CAN_PRMS + || in->msg.canparams.cc_type != SJA1000) + return 0; + pParams = + (CPC_SJA1000_PARAMS_T *) & in->msg.canparams.cc_params.sja1000; + acc_code0 = pParams->acc_code0; + acc_code1 = pParams->acc_code1; + acc_code2 = pParams->acc_code2; + acc_code3 = pParams->acc_code3; + acc_mask0 = pParams->acc_mask0; + acc_mask1 = pParams->acc_mask1; + acc_mask2 = pParams->acc_mask2; + acc_mask3 = pParams->acc_mask3; + +#ifdef _DEBUG_OUTPUT_CAN_PARAMS + info("acc_code0: %2.2Xh\n", acc_code0); + info("acc_code1: %2.2Xh\n", acc_code1); + info("acc_code2: %2.2Xh\n", acc_code2); + info("acc_code3: %2.2Xh\n", acc_code3); + info("acc_mask0: %2.2Xh\n", acc_mask0); + info("acc_mask1: %2.2Xh\n", acc_mask1); + info("acc_mask2: %2.2Xh\n", acc_mask2); + info("acc_mask3: %2.2Xh\n", acc_mask3); + +#endif /* */ + if (! + (baudrate_error = + (int *) vmalloc(sizeof(int) * 16 * 8 * 8 * 8 * 5))) { + err("Could not allocate memory\n"); + return -3; + } + if (! + (samplepoint_error = + (int *) vmalloc(sizeof(int) * 16 * 8 * 8 * 8 * 5))) { + err("Could not allocate memory\n"); + vfree(baudrate_error); + return -3; + } + memset(baudrate_error, 0xff, sizeof(baudrate_error)); + memset(samplepoint_error, 0xff, sizeof(baudrate_error)); + sjaBaudrate = + 16000000 / 2 / SJA_BRP / (1 + SJA_TSEG1 + SJA_TSEG2); + sjaSamplepoint = + 100 * (1 + SJA_TSEG1) / (1 + SJA_TSEG1 + SJA_TSEG2); + if (sjaBaudrate == 0) { + vfree(baudrate_error); + vfree(samplepoint_error); + return -2; + } + +#ifdef _DEBUG_OUTPUT_CAN_PARAMS + info("\nStarting SJA CAN params\n"); + info("-------------------------\n"); + info("TS1 : %2.2Xh TS2 : %2.2Xh\n", SJA_TSEG1, SJA_TSEG2); + info("BTR0 : %2.2Xh BTR1: %2.2Xh\n", pParams->btr0, + pParams->btr1); + info("Baudrate: %d.%dkBaud\n", sjaBaudrate / 1000, + sjaBaudrate % 1000); + info("Sample P: 0.%d\n", sjaSamplepoint); + info("\n"); + +#endif /* */ + c0con.bc0con.sam = SJA_SAM; + c1con.bc1con.sjw = SJA_SJW; + + // calculate errors for all baudrates + index = 0; + for (clk = 0; clk < 5; clk++) { + for (brp = 0; brp < 16; brp++) { + for (pr = 0; pr < 8; pr++) { + for (ph1 = 0; ph1 < 8; ph1++) { + for (ph2 = 0; ph2 < 8; ph2++) { + baudrate_error[index] = + 100 * + abs(baudrate_m16c + (clk, brp, pr, ph1, + ph2) - + sjaBaudrate) / + sjaBaudrate; + samplepoint_error[index] = + abs(samplepoint_m16c + (brp, pr, ph1, + ph2) - + sjaSamplepoint); + +#if 0 + info + ("Baudrate : %d kBaud\n", + baudrate_m16c(clk, + brp, pr, + ph1, + ph2)); + info + ("Baudrate Error: %d\n", + baudrate_error + [index]); + info + ("Sample P Error: %d\n", + samplepoint_error + [index]); + info + ("clk : %d\n", + clk); + +#endif /* */ + index++; + } + } + } + } + } + + // mark all baudrate_error entries which are outer limits + index = 0; + for (clk = 0; clk < 5; clk++) { + for (brp = 0; brp < 16; brp++) { + for (pr = 0; pr < 8; pr++) { + for (ph1 = 0; ph1 < 8; ph1++) { + for (ph2 = 0; ph2 < 8; ph2++) { + if ((baudrate_error[index] + > + BAUDRATE_TOLERANCE_PERCENT) + || + (samplepoint_error + [index] > + SAMPLEPOINT_TOLERANCE_PERCENT) + || + (samplepoint_m16c + (brp, pr, ph1, + ph2) > + SAMPLEPOINT_UPPER_LIMIT)) + { + baudrate_error + [index] = -1; + } else + if (((1 + pr + 1 + + ph1 + 1 + ph2 + + 1) < 8) + || + ((1 + pr + 1 + + ph1 + 1 + ph2 + + 1) > 25)) { + baudrate_error + [index] = -1; + } + +#if 0 + else { + info + ("Baudrate : %d kBaud\n", + baudrate_m16c + (clk, brp, pr, + ph1, ph2)); + info + ("Baudrate Error: %d\n", + baudrate_error + [index]); + info + ("Sample P Error: %d\n", + samplepoint_error + [index]); + } + +#endif /* */ + index++; + } + } + } + } + } + + // find list of minimum of baudrate_error within unmarked entries + clk_merk = brp_merk = pr_merk = ph1_merk = ph2_merk = 0; + baudrate_error_merk = 100; + index = 0; + for (clk = 0; clk < 5; clk++) { + for (brp = 0; brp < 16; brp++) { + for (pr = 0; pr < 8; pr++) { + for (ph1 = 0; ph1 < 8; ph1++) { + for (ph2 = 0; ph2 < 8; ph2++) { + if (baudrate_error[index] + != -1) { + if (baudrate_error + [index] < + baudrate_error_merk) + { + baudrate_error_merk + = + baudrate_error + [index]; + brp_merk = + brp; + pr_merk = + pr; + ph1_merk = + ph1; + ph2_merk = + ph2; + clk_merk = + clk; + +#if 0 + info + ("brp: %2.2Xh pr: %2.2Xh ph1: %2.2Xh ph2: %2.2Xh\n", + brp, + pr, + ph1, + ph2); + info + ("Baudrate : %d kBaud\n", + baudrate_m16c + (clk, + brp, + pr, + ph1, + ph2)); + info + ("Baudrate Error: %d\n", + baudrate_error + [index]); + info + ("Sample P Error: %d\n", + samplepoint_error + [index]); + +#endif /* */ + } + } + index++; + } + } + } + } + } + if (baudrate_error_merk == 100) { + info("ERROR: Could not convert CAN init parameter\n"); + vfree(baudrate_error); + vfree(samplepoint_error); + return -1; + } + + // setting m16c CAN parameter + c0con.bc0con.brp = brp_merk; + c0con.bc0con.pr = pr_merk; + c1con.bc1con.ph1 = ph1_merk; + c1con.bc1con.ph2 = ph2_merk; + +#ifdef _DEBUG_OUTPUT_CAN_PARAMS + info("\nResulting M16C CAN params\n"); + info("-------------------------\n"); + info("clk : %2.2Xh\n", clk_merk); + info("ph1 : %2.2Xh ph2: %2.2Xh\n", c1con.bc1con.ph1 + 1, + c1con.bc1con.ph2 + 1); + info("pr : %2.2Xh brp: %2.2Xh\n", c0con.bc0con.pr + 1, + c0con.bc0con.brp + 1); + info("sjw : %2.2Xh sam: %2.2Xh\n", c1con.bc1con.sjw, + c0con.bc0con.sam); + info("co1 : %2.2Xh co0: %2.2Xh\n", c1con.c1con, c0con.c0con); + info("Baudrate: %d.%dBaud\n", + baudrate_m16c(clk_merk, c0con.bc0con.brp, c0con.bc0con.pr, + c1con.bc1con.ph1, c1con.bc1con.ph2) / 1000, + baudrate_m16c(clk_merk, c0con.bc0con.brp, c0con.bc0con.pr, + c1con.bc1con.ph1, c1con.bc1con.ph2) % 1000); + info("Sample P: 0.%d\n", + samplepoint_m16c(c0con.bc0con.brp, c0con.bc0con.pr, + c1con.bc1con.ph1, c1con.bc1con.ph2)); + info("\n"); + +#endif /* */ + out = in; + out->type = 6; + out->length = sizeof(CPC_M16C_BASIC_PARAMS_T) + 1; + out->msg.canparams.cc_type = M16C_BASIC; + out->msg.canparams.cc_params.m16c_basic.con0 = c0con.c0con; + out->msg.canparams.cc_params.m16c_basic.con1 = c1con.c1con; + out->msg.canparams.cc_params.m16c_basic.ctlr0 = 0x4C; + out->msg.canparams.cc_params.m16c_basic.ctlr1 = 0x00; + out->msg.canparams.cc_params.m16c_basic.clk = clk_merk; + out->msg.canparams.cc_params.m16c_basic.acc_std_code0 = + acc_code0; + out->msg.canparams.cc_params.m16c_basic.acc_std_code1 = acc_code1; + +// info("code0: 0x%2.2X, code1: 0x%2.2X\n", out->msg.canparams.cc_params.m16c_basic.acc_std_code0, out->msg.canparams.cc_params.m16c_basic.acc_std_code1); + tmpAccCode = (acc_code1 >> 5) + (acc_code0 << 3); + out->msg.canparams.cc_params.m16c_basic.acc_std_code0 = + (unsigned char) tmpAccCode; + out->msg.canparams.cc_params.m16c_basic.acc_std_code1 = + (unsigned char) (tmpAccCode >> 8); + +// info("code0: 0x%2.2X, code1: 0x%2.2X\n", out->msg.canparams.cc_params.m16c_basic.acc_std_code0, out->msg.canparams.cc_params.m16c_basic.acc_std_code1); + out->msg.canparams.cc_params.m16c_basic.acc_std_mask0 = + ~acc_mask0; + out->msg.canparams.cc_params.m16c_basic.acc_std_mask1 = + ~acc_mask1; + +// info("mask0: 0x%2.2X, mask1: 0x%2.2X\n", out->msg.canparams.cc_params.m16c_basic.acc_std_mask0, out->msg.canparams.cc_params.m16c_basic.acc_std_mask1); + tmpAccMask = ((acc_mask1) >> 5) + ((acc_mask0) << 3); + +// info("tmpAccMask: 0x%4.4X\n", tmpAccMask); + out->msg.canparams.cc_params.m16c_basic.acc_std_mask0 = + (unsigned char) ~tmpAccMask; + out->msg.canparams.cc_params.m16c_basic.acc_std_mask1 = + (unsigned char) ~(tmpAccMask >> 8); + +// info("mask0: 0x%2.2X, mask1: 0x%2.2X\n", out->msg.canparams.cc_params.m16c_basic.acc_std_mask0, out->msg.canparams.cc_params.m16c_basic.acc_std_mask1); + out->msg.canparams.cc_params.m16c_basic.acc_ext_code0 = + (unsigned char) tmpAccCode; + out->msg.canparams.cc_params.m16c_basic.acc_ext_code1 = + (unsigned char) (tmpAccCode >> 8); + out->msg.canparams.cc_params.m16c_basic.acc_ext_code2 = acc_code2; + out->msg.canparams.cc_params.m16c_basic.acc_ext_code3 = acc_code3; + out->msg.canparams.cc_params.m16c_basic.acc_ext_mask0 = + (unsigned char) ~tmpAccMask; + out->msg.canparams.cc_params.m16c_basic.acc_ext_mask1 = + (unsigned char) ~(tmpAccMask >> 8); + out->msg.canparams.cc_params.m16c_basic.acc_ext_mask2 = + ~acc_mask2; + out->msg.canparams.cc_params.m16c_basic.acc_ext_mask3 = + ~acc_mask3; + vfree(baudrate_error); + vfree(samplepoint_error); + return 0; +} + + diff --git a/drivers/staging/echo/echo.c b/drivers/staging/echo/echo.c index 6d7217e1bd06..79d15c65bfe4 100644 --- a/drivers/staging/echo/echo.c +++ b/drivers/staging/echo/echo.c @@ -395,7 +395,7 @@ int16_t oslec_update(struct oslec_state *ec, int16_t tx, int16_t rx) old = (int)ec->fir_state.history[ec->fir_state.curr_pos] * (int)ec->fir_state.history[ec->fir_state.curr_pos]; ec->Pstates += - ((new - old) + (1 << ec->log2taps)) >> ec->log2taps; + ((new - old) + (1 << (ec->log2taps-1))) >> ec->log2taps; if (ec->Pstates < 0) ec->Pstates = 0; } diff --git a/drivers/staging/epl/EplSdoUdpu.c b/drivers/staging/epl/EplSdoUdpu.c index b409c9b7be48..c8e950fa8353 100644 --- a/drivers/staging/epl/EplSdoUdpu.c +++ b/drivers/staging/epl/EplSdoUdpu.c @@ -334,7 +334,8 @@ tEplKernel EplSdoUdpuConfig(unsigned long ulIpAddr_p, unsigned int uiPort_p) } // create Listen-Thread SdoUdpInstance_g.m_ThreadHandle = - kernel_thread(EplSdoUdpThread, &SdoUdpInstance_g, CLONE_KERNEL); + kernel_thread(EplSdoUdpThread, &SdoUdpInstance_g, + CLONE_FS | CLONE_FILES); if (SdoUdpInstance_g.m_ThreadHandle == 0) { Ret = kEplSdoUdpThreadError; goto Exit; diff --git a/drivers/staging/epl/ShbIpc-LinuxKernel.c b/drivers/staging/epl/ShbIpc-LinuxKernel.c index 497938bd09b9..12d1eccde252 100644 --- a/drivers/staging/epl/ShbIpc-LinuxKernel.c +++ b/drivers/staging/epl/ShbIpc-LinuxKernel.c @@ -532,8 +532,8 @@ tShbError ShbIpcStartSignalingNewData(tShbInstance pShbInstance_p, //create thread for signalling new data pShbMemInst->m_tThreadNewDataId = - kernel_thread(ShbIpcThreadSignalNewData, pShbInstance_p, - CLONE_KERNEL); + kernel_thread(ShbIpcThreadSignalNewData, pShbInstance_p, + CLONE_FS | CLONE_FILES); Exit: return ShbError; @@ -636,8 +636,8 @@ tShbError ShbIpcStartSignalingJobReady(tShbInstance pShbInstance_p, pShbMemHeader->m_fJobReady = FALSE; //create thread for signalling new data pShbMemInst->m_tThreadJobReadyId = - kernel_thread(ShbIpcThreadSignalJobReady, pShbInstance_p, - CLONE_KERNEL); + kernel_thread(ShbIpcThreadSignalJobReady, pShbInstance_p, + CLONE_FS | CLONE_FILES); Exit: return ShbError; } diff --git a/drivers/staging/et131x/et131x_netdev.c b/drivers/staging/et131x/et131x_netdev.c index 951c73d5db20..59e99cc7786b 100644 --- a/drivers/staging/et131x/et131x_netdev.c +++ b/drivers/staging/et131x/et131x_netdev.c @@ -585,11 +585,11 @@ int et131x_tx(struct sk_buff *skb, struct net_device *netdev) * available */ netif_stop_queue(netdev); - status = 1; + status = NETDEV_TX_BUSY; } else { DBG_WARNING(et131x_dbginfo, "Misc error; drop packet\n"); - status = 0; + status = NETDEV_TX_OK; } } diff --git a/drivers/staging/frontier/alphatrack.c b/drivers/staging/frontier/alphatrack.c index bcba17eae926..15aed87fe1bb 100644 --- a/drivers/staging/frontier/alphatrack.c +++ b/drivers/staging/frontier/alphatrack.c @@ -39,7 +39,6 @@ #include #include #include -#include #include #include diff --git a/drivers/staging/frontier/tranzport.c b/drivers/staging/frontier/tranzport.c index 274b82bd7863..ef8fcc8c67bd 100644 --- a/drivers/staging/frontier/tranzport.c +++ b/drivers/staging/frontier/tranzport.c @@ -38,7 +38,6 @@ #include #include #include -#include #include #include diff --git a/drivers/staging/go7007/go7007.txt b/drivers/staging/go7007/go7007.txt index 9f6772bc68c2..1c2907c1dc81 100644 --- a/drivers/staging/go7007/go7007.txt +++ b/drivers/staging/go7007/go7007.txt @@ -2,7 +2,7 @@ This is a driver for the WIS GO7007SB multi-format video encoder. Pete Eberlein -The driver was orignally released under the GPL and is currently hosted at: +The driver was originally released under the GPL and is currently hosted at: http://nikosapi.org/wiki/index.php/WIS_Go7007_Linux_driver The go7007 firmware can be acquired from the package on the site above. @@ -24,7 +24,7 @@ These should be used instead of the non-standard GO7007 ioctls described below. -The README files from the orignal package appear below: +The README files from the original package appears below: --------------------------------------------------------------------------- WIS GO7007SB Public Linux Driver diff --git a/drivers/staging/go7007/wis-sony-tuner.c b/drivers/staging/go7007/wis-sony-tuner.c index c965c601ac90..086896cec49b 100644 --- a/drivers/staging/go7007/wis-sony-tuner.c +++ b/drivers/staging/go7007/wis-sony-tuner.c @@ -370,7 +370,7 @@ static int set_if(struct i2c_client *client) i2c_transfer(client->adapter, &msg, 1); /* Select MPX mode if not forced by the user */ - if (force_mpx_mode >= 0 || force_mpx_mode < MPX_NUM_MODES) + if (force_mpx_mode >= 0 && force_mpx_mode < MPX_NUM_MODES) t->mpxmode = force_mpx_mode; else t->mpxmode = default_mpx_mode; diff --git a/drivers/staging/heci/heci.h b/drivers/staging/heci/heci.h index 14192e0cc227..48f120dc3b27 100644 --- a/drivers/staging/heci/heci.h +++ b/drivers/staging/heci/heci.h @@ -41,7 +41,6 @@ #ifndef _HECI_H_ #define _HECI_H_ -#include #include #include #include diff --git a/drivers/staging/heci/heci_data_structures.h b/drivers/staging/heci/heci_data_structures.h index 575e8f8e88a3..ff30386d097a 100644 --- a/drivers/staging/heci/heci_data_structures.h +++ b/drivers/staging/heci/heci_data_structures.h @@ -41,7 +41,6 @@ #ifndef _HECI_DATA_STRUCTURES_H_ #define _HECI_DATA_STRUCTURES_H_ -#include #include #include #include diff --git a/drivers/staging/heci/heci_init.c b/drivers/staging/heci/heci_init.c index a8a0da910cfb..31fd891c099d 100644 --- a/drivers/staging/heci/heci_init.c +++ b/drivers/staging/heci/heci_init.c @@ -249,7 +249,7 @@ int heci_hw_init(struct iamt_heci_device *dev) if ((dev->host_hw_state & H_IS) == H_IS) { /* acknowledge interrupt and stop interupts */ - heci_set_csr_register(dev); + heci_csr_clear_his(dev); } dev->recvd_msg = 0; DBG("reset in start the heci device.\n"); @@ -354,7 +354,7 @@ void heci_reset(struct iamt_heci_device *dev, int interrupts) dev->host_hw_state &= ~H_RST; dev->host_hw_state |= H_IG; - write_heci_register(dev, H_CSR, dev->host_hw_state); + heci_set_csr_register(dev); DBG("currently saved host_hw_state = 0x%08x.\n", dev->host_hw_state); @@ -998,8 +998,12 @@ int heci_disconnect_host_client(struct iamt_heci_device *dev, if ((!dev) || (!file_ext)) return -ENODEV; - if (file_ext->state != HECI_FILE_DISCONNECTING) + spin_lock_bh(&dev->device_lock); + if (file_ext->state != HECI_FILE_DISCONNECTING) { + spin_unlock_bh(&dev->device_lock); return 0; + } + spin_unlock_bh(&dev->device_lock); priv_cb = kzalloc(sizeof(struct heci_cb_private), GFP_KERNEL); if (!priv_cb) @@ -1012,6 +1016,7 @@ int heci_disconnect_host_client(struct iamt_heci_device *dev, if (dev->host_buffer_is_empty) { dev->host_buffer_is_empty = 0; if (heci_disconnect(dev, file_ext)) { + mdelay(10); /* Wait for hardware disconnection ready */ list_add_tail(&priv_cb->cb_list, &dev->ctrl_rd_list.heci_cb.cb_list); } else { @@ -1030,6 +1035,8 @@ int heci_disconnect_host_client(struct iamt_heci_device *dev, err = wait_event_timeout(dev->wait_recvd_msg, (HECI_FILE_DISCONNECTED == file_ext->state), timeout * HZ); + + spin_lock_bh(&dev->device_lock); if (HECI_FILE_DISCONNECTED == file_ext->state) { rets = 0; DBG("successfully disconnected from fw client.\n"); @@ -1044,7 +1051,6 @@ int heci_disconnect_host_client(struct iamt_heci_device *dev, DBG("failed to disconnect from fw client.\n"); } - spin_lock_bh(&dev->device_lock); heci_flush_list(&dev->ctrl_rd_list, file_ext); heci_flush_list(&dev->ctrl_wr_list, file_ext); spin_unlock_bh(&dev->device_lock); diff --git a/drivers/staging/heci/heci_interface.c b/drivers/staging/heci/heci_interface.c index c5f51a7ddf2c..03e1df1a88a0 100644 --- a/drivers/staging/heci/heci_interface.c +++ b/drivers/staging/heci/heci_interface.c @@ -44,12 +44,15 @@ /** - * heci_set_csr_register - write H_CSR register to the heci device + * heci_set_csr_register - write H_CSR register to the heci device, + * and ignore the H_IS bit for it is write-one-to-zero. * * @dev: device object for our driver */ void heci_set_csr_register(struct iamt_heci_device *dev) { + if ((dev->host_hw_state & H_IS) == H_IS) + dev->host_hw_state &= ~H_IS; write_heci_register(dev, H_CSR, dev->host_hw_state); dev->host_hw_state = read_heci_register(dev, H_CSR); } @@ -76,6 +79,16 @@ void heci_csr_disable_interrupts(struct iamt_heci_device *dev) heci_set_csr_register(dev); } +/** + * heci_csr_clear_his - clear H_IS bit in H_CSR + * + * @dev: device object for our driver + */ +void heci_csr_clear_his(struct iamt_heci_device *dev) +{ + write_heci_register(dev, H_CSR, dev->host_hw_state); + dev->host_hw_state = read_heci_register(dev, H_CSR); +} /** * _host_get_filled_slots - get number of device filled buffer slots @@ -185,7 +198,7 @@ int heci_write_message(struct iamt_heci_device *dev, } dev->host_hw_state |= H_IG; - write_heci_register(dev, H_CSR, dev->host_hw_state); + heci_set_csr_register(dev); dev->me_hw_state = read_heci_register(dev, ME_CSR_HA); if ((dev->me_hw_state & ME_RDY_HRA) != ME_RDY_HRA) return 0; diff --git a/drivers/staging/heci/heci_interface.h b/drivers/staging/heci/heci_interface.h index 37336ebc0a5b..34db7e52b8ef 100644 --- a/drivers/staging/heci/heci_interface.h +++ b/drivers/staging/heci/heci_interface.h @@ -42,7 +42,6 @@ #ifndef _HECI_INTERFACE_H_ #define _HECI_INTERFACE_H_ -#include #include #include #include @@ -134,6 +133,7 @@ enum client_disconnect_status_types{ void heci_set_csr_register(struct iamt_heci_device *dev); void heci_csr_enable_interrupts(struct iamt_heci_device *dev); void heci_csr_disable_interrupts(struct iamt_heci_device *dev); +void heci_csr_clear_his(struct iamt_heci_device *dev); void heci_read_slots(struct iamt_heci_device *dev, unsigned char *buffer, unsigned long buffer_length); diff --git a/drivers/staging/heci/heci_main.c b/drivers/staging/heci/heci_main.c index 00e44c781428..ddf48227e358 100644 --- a/drivers/staging/heci/heci_main.c +++ b/drivers/staging/heci/heci_main.c @@ -751,7 +751,9 @@ static int heci_open(struct inode *inode, struct file *file) (1 << (file_ext->host_client_id % 8)); spin_unlock_bh(&dev->device_lock); spin_lock(&file_ext->file_lock); + spin_lock_bh(&dev->device_lock); file_ext->state = HECI_FILE_INITIALIZING; + spin_unlock_bh(&dev->device_lock); file_ext->sm_state = 0; file->private_data = file_ext; @@ -785,8 +787,10 @@ static int heci_release(struct inode *inode, struct file *file) if (file_ext != &dev->iamthif_file_ext) { spin_lock(&file_ext->file_lock); + spin_lock_bh(&dev->device_lock); if (file_ext->state == HECI_FILE_CONNECTED) { file_ext->state = HECI_FILE_DISCONNECTING; + spin_unlock_bh(&dev->device_lock); spin_unlock(&file_ext->file_lock); DBG("disconnecting client host client = %d, " "ME client = %d\n", @@ -794,8 +798,8 @@ static int heci_release(struct inode *inode, struct file *file) file_ext->me_client_id); rets = heci_disconnect_host_client(dev, file_ext); spin_lock(&file_ext->file_lock); + spin_lock_bh(&dev->device_lock); } - spin_lock_bh(&dev->device_lock); heci_flush_queues(dev, file_ext); DBG("remove client host client = %d, ME client = %d\n", file_ext->host_client_id, @@ -954,11 +958,11 @@ static ssize_t heci_read(struct file *file, char __user *ubuf, goto out; } - spin_lock(&file_ext->read_io_lock); err = heci_start_read(dev, if_num, file_ext); + spin_lock_bh(&file_ext->read_io_lock); if (err != 0 && err != -EBUSY) { DBG("heci start read failure with status = %d\n", err); - spin_unlock(&file_ext->read_io_lock); + spin_unlock_bh(&file_ext->read_io_lock); rets = err; goto out; } @@ -966,10 +970,10 @@ static ssize_t heci_read(struct file *file, char __user *ubuf, && !waitqueue_active(&file_ext->rx_wait)) { if (file->f_flags & O_NONBLOCK) { rets = -EAGAIN; - spin_unlock(&file_ext->read_io_lock); + spin_unlock_bh(&file_ext->read_io_lock); goto out; } - spin_unlock(&file_ext->read_io_lock); + spin_unlock_bh(&file_ext->read_io_lock); if (wait_event_interruptible(file_ext->rx_wait, (HECI_READ_COMPLETE == file_ext->reading_state @@ -983,26 +987,29 @@ static ssize_t heci_read(struct file *file, char __user *ubuf, return -ERESTARTSYS; } + spin_lock_bh(&dev->device_lock); if (HECI_FILE_INITIALIZING == file_ext->state || HECI_FILE_DISCONNECTED == file_ext->state || HECI_FILE_DISCONNECTING == file_ext->state) { + spin_unlock_bh(&dev->device_lock); rets = -EBUSY; goto out; } - spin_lock(&file_ext->read_io_lock); + spin_unlock_bh(&dev->device_lock); + spin_lock_bh(&file_ext->read_io_lock); } priv_cb = file_ext->read_cb; if (!priv_cb) { - spin_unlock(&file_ext->read_io_lock); + spin_unlock_bh(&file_ext->read_io_lock); return -ENODEV; } if (file_ext->reading_state != HECI_READ_COMPLETE) { - spin_unlock(&file_ext->read_io_lock); + spin_unlock_bh(&file_ext->read_io_lock); return 0; } - spin_unlock(&file_ext->read_io_lock); + spin_unlock_bh(&file_ext->read_io_lock); /* now copy the data to user space */ copy_buffer: DBG("priv_cb->response_buffer size - %d\n", @@ -1040,11 +1047,11 @@ free: list_del(&priv_cb_pos->cb_list); spin_unlock_bh(&dev->device_lock); heci_free_cb_private(priv_cb); - spin_lock(&file_ext->read_io_lock); + spin_lock_bh(&file_ext->read_io_lock); file_ext->reading_state = HECI_IDLE; file_ext->read_cb = NULL; file_ext->read_pending = 0; - spin_unlock(&file_ext->read_io_lock); + spin_unlock_bh(&file_ext->read_io_lock); out: DBG("end heci read rets= %d\n", rets); return rets; } @@ -1088,7 +1095,7 @@ static ssize_t heci_write(struct file *file, const char __user *ubuf, if (file_ext == &dev->iamthif_file_ext) { priv_write_cb = find_pthi_read_list_entry(dev, file); if ((priv_write_cb != NULL) && - (((currtime - priv_write_cb->read_time) > + (((currtime - priv_write_cb->read_time) >= IAMTHIF_READ_TIMER) || (file_ext->reading_state == HECI_READ_COMPLETE))) { (*offset) = 0; @@ -1106,11 +1113,11 @@ static ssize_t heci_write(struct file *file, const char __user *ubuf, list_del(&priv_write_cb->cb_list); heci_free_cb_private(priv_write_cb); priv_write_cb = NULL; - spin_lock(&file_ext->read_io_lock); + spin_lock_bh(&file_ext->read_io_lock); file_ext->reading_state = HECI_IDLE; file_ext->read_cb = NULL; file_ext->read_pending = 0; - spin_unlock(&file_ext->read_io_lock); + spin_unlock_bh(&file_ext->read_io_lock); } } else if (file_ext->reading_state == HECI_IDLE && file_ext->read_pending == 0) @@ -1140,9 +1147,12 @@ static ssize_t heci_write(struct file *file, const char __user *ubuf, spin_lock(&file_ext->file_lock); file_ext->sm_state = 0; if ((length == 4) && - ((memcmp(heci_wd_state_independence_msg[0], ubuf, 4) == 0) || - (memcmp(heci_wd_state_independence_msg[1], ubuf, 4) == 0) || - (memcmp(heci_wd_state_independence_msg[2], ubuf, 4) == 0))) + ((memcmp(heci_wd_state_independence_msg[0], + priv_write_cb->request_buffer.data, 4) == 0) || + (memcmp(heci_wd_state_independence_msg[1], + priv_write_cb->request_buffer.data, 4) == 0) || + (memcmp(heci_wd_state_independence_msg[2], + priv_write_cb->request_buffer.data, 4) == 0))) file_ext->sm_state |= HECI_WD_STATE_INDEPENDENCE_MSG_SENT; spin_unlock(&file_ext->file_lock); @@ -1222,6 +1232,7 @@ static ssize_t heci_write(struct file *file, const char __user *ubuf, priv_write_cb->request_buffer.size = length; spin_lock(&file_ext->write_io_lock); + spin_lock_bh(&dev->device_lock); DBG("host client = %d, ME client = %d\n", file_ext->host_client_id, file_ext->me_client_id); if (file_ext->state != HECI_FILE_CONNECTED) { @@ -1229,7 +1240,7 @@ static ssize_t heci_write(struct file *file, const char __user *ubuf, DBG("host client = %d, is not connected to ME client = %d", file_ext->host_client_id, file_ext->me_client_id); - + spin_unlock_bh(&dev->device_lock); goto unlock; } for (i = 0; i < dev->num_heci_me_clients; i++) { @@ -1240,15 +1251,16 @@ static ssize_t heci_write(struct file *file, const char __user *ubuf, BUG_ON(dev->me_clients[i].client_id != file_ext->me_client_id); if (i == dev->num_heci_me_clients) { rets = -ENODEV; + spin_unlock_bh(&dev->device_lock); goto unlock; } if (length > dev->me_clients[i].props.max_msg_length || length <= 0) { rets = -EINVAL; + spin_unlock_bh(&dev->device_lock); goto unlock; } priv_write_cb->file_private = file_ext; - spin_lock_bh(&dev->device_lock); if (flow_ctrl_creds(dev, file_ext) && dev->host_buffer_is_empty) { spin_unlock_bh(&dev->device_lock); diff --git a/drivers/staging/heci/interrupt.c b/drivers/staging/heci/interrupt.c index aacd26243988..2a3a01a62bbf 100644 --- a/drivers/staging/heci/interrupt.c +++ b/drivers/staging/heci/interrupt.c @@ -92,6 +92,9 @@ irqreturn_t heci_isr_interrupt(int irq, void *dev_id) /* disable interrupts */ heci_csr_disable_interrupts(dev); + /* clear H_IS bit in H_CSR */ + heci_csr_clear_his(dev); + /* * Our device interrupted, schedule work the heci_bh_handler * to handle the interrupt processing. This needs to be a @@ -100,10 +103,8 @@ irqreturn_t heci_isr_interrupt(int irq, void *dev_id) PREPARE_WORK(&dev->work, heci_bh_handler); DBG("schedule work the heci_bh_handler.\n"); err = schedule_work(&dev->work); - if (!err) { - printk(KERN_ERR "heci: schedule the heci_bh_handler" - " failed error=%x\n", err); - } + if (!err) + DBG("heci_bh_handler was already on the workqueue.\n"); return IRQ_HANDLED; } @@ -251,13 +252,14 @@ end: /* acknowledge interrupt and disable interrupts */ heci_csr_disable_interrupts(dev); + /* clear H_IS bit in H_CSR */ + heci_csr_clear_his(dev); + PREPARE_WORK(&dev->work, heci_bh_handler); DBG("schedule work the heci_bh_handler.\n"); rets = schedule_work(&dev->work); - if (!rets) { - printk(KERN_ERR "heci: schedule the heci_bh_handler" - " failed error=%x\n", rets); - } + if (!rets) + DBG("heci_bh_handler was already queued.\n"); } else { heci_csr_enable_interrupts(dev); } @@ -622,7 +624,7 @@ static int heci_bh_read_client_message(struct io_heci_list *complete_list, priv_cb_pos->file_private; if ((file_ext != NULL) && (_heci_bh_state_ok(file_ext, heci_hdr))) { - spin_lock(&file_ext->read_io_lock); + spin_lock_bh(&file_ext->read_io_lock); file_ext->reading_state = HECI_READING; buffer = (unsigned char *) (priv_cb_pos->response_buffer.data + @@ -636,7 +638,7 @@ static int heci_bh_read_client_message(struct io_heci_list *complete_list, priv_cb_pos->information) { DBG("message overflow.\n"); list_del(&priv_cb_pos->cb_list); - spin_unlock(&file_ext->read_io_lock); + spin_unlock_bh(&file_ext->read_io_lock); return -ENOMEM; } if (buffer) { @@ -647,7 +649,7 @@ static int heci_bh_read_client_message(struct io_heci_list *complete_list, if (heci_hdr->msg_complete) { file_ext->status = 0; list_del(&priv_cb_pos->cb_list); - spin_unlock(&file_ext->read_io_lock); + spin_unlock_bh(&file_ext->read_io_lock); DBG("completed read host client = %d," "ME client = %d, " "data length = %lu\n", @@ -662,7 +664,7 @@ static int heci_bh_read_client_message(struct io_heci_list *complete_list, list_add_tail(&priv_cb_pos->cb_list, &complete_list->heci_cb.cb_list); } else { - spin_unlock(&file_ext->read_io_lock); + spin_unlock_bh(&file_ext->read_io_lock); } break; @@ -1054,7 +1056,7 @@ static int heci_bh_write_handler(struct io_heci_list *cmpl_list, list_del(&priv_cb_pos->cb_list); if ((HECI_WRITING == file_ext->writing_state) && (priv_cb_pos->major_file_operations == - HECI_WRITING) && + HECI_WRITE) && (file_ext != &dev->iamthif_file_ext)) { DBG("HECI WRITE COMPLETE\n"); file_ext->writing_state = diff --git a/drivers/staging/heci/io_heci.c b/drivers/staging/heci/io_heci.c index f7544a7bbbe0..1a6faf88e16c 100644 --- a/drivers/staging/heci/io_heci.c +++ b/drivers/staging/heci/io_heci.c @@ -111,7 +111,7 @@ int heci_ioctl_get_version(struct iamt_heci_device *dev, int if_num, rets = file_ext->status; /* now copy the data to user space */ - if (copy_to_user(k_msg.data, res_msg.data, res_msg.size)) { + if (copy_to_user((void __user *)k_msg.data, res_msg.data, res_msg.size)) { rets = -EFAULT; goto end; } @@ -188,7 +188,7 @@ int heci_ioctl_connect_client(struct iamt_heci_device *dev, int if_num, /* copy the message to kernel space - * use a pointer already copied into kernel space */ - if (copy_from_user(req_msg.data, k_msg.data, k_msg.size)) { + if (copy_from_user(req_msg.data, (void __user *)k_msg.data, k_msg.size)) { rets = -EFAULT; goto end; } @@ -266,7 +266,8 @@ int heci_ioctl_connect_client(struct iamt_heci_device *dev, int if_num, spin_unlock_bh(&dev->device_lock); /* now copy the data to user space */ - if (copy_to_user(k_msg.data, res_msg.data, res_msg.size)) { + if (copy_to_user((void __user *)k_msg.data, + res_msg.data, res_msg.size)) { rets = -EFAULT; goto end; } @@ -276,14 +277,16 @@ int heci_ioctl_connect_client(struct iamt_heci_device *dev, int if_num, } goto end; } + spin_unlock_bh(&dev->device_lock); + spin_lock(&file_ext->file_lock); + spin_lock_bh(&dev->device_lock); if (file_ext->state != HECI_FILE_CONNECTING) { rets = -ENODEV; - spin_unlock(&file_ext->file_lock); spin_unlock_bh(&dev->device_lock); + spin_unlock(&file_ext->file_lock); goto end; } - spin_unlock(&file_ext->file_lock); /* prepare the output buffer */ client = (struct heci_client *) res_msg.data; client->max_msg_length = dev->me_clients[i].props.max_msg_length; @@ -294,6 +297,7 @@ int heci_ioctl_connect_client(struct iamt_heci_device *dev, int if_num, if (!heci_connect(dev, file_ext)) { rets = -ENODEV; spin_unlock_bh(&dev->device_lock); + spin_unlock(&file_ext->file_lock); goto end; } else { file_ext->timer_count = HECI_CONNECT_TIMEOUT; @@ -311,16 +315,20 @@ int heci_ioctl_connect_client(struct iamt_heci_device *dev, int if_num, &dev->ctrl_wr_list.heci_cb.cb_list); } spin_unlock_bh(&dev->device_lock); + spin_unlock(&file_ext->file_lock); err = wait_event_timeout(dev->wait_recvd_msg, (HECI_FILE_CONNECTED == file_ext->state || HECI_FILE_DISCONNECTED == file_ext->state), timeout * HZ); + spin_lock_bh(&dev->device_lock); if (HECI_FILE_CONNECTED == file_ext->state) { + spin_unlock_bh(&dev->device_lock); DBG("successfully connected to FW client.\n"); rets = file_ext->status; /* now copy the data to user space */ - if (copy_to_user(k_msg.data, res_msg.data, res_msg.size)) { + if (copy_to_user((void __user *)k_msg.data, + res_msg.data, res_msg.size)) { rets = -EFAULT; goto end; } @@ -332,6 +340,7 @@ int heci_ioctl_connect_client(struct iamt_heci_device *dev, int if_num, } else { DBG("failed to connect to FW client.file_ext->state = %d.\n", file_ext->state); + spin_unlock_bh(&dev->device_lock); if (!err) { DBG("wait_event_interruptible_timeout failed on client" " connect message fw response message.\n"); @@ -394,7 +403,8 @@ int heci_ioctl_wd(struct iamt_heci_device *dev, int if_num, /* copy the message to kernel space - use a pointer already * copied into kernel space */ - if (copy_from_user(req_msg.data, k_msg.data, req_msg.size)) { + if (copy_from_user(req_msg.data, + (void __user *)k_msg.data, req_msg.size)) { rets = -EFAULT; goto end; } @@ -464,7 +474,7 @@ int heci_ioctl_bypass_wd(struct iamt_heci_device *dev, int if_num, return -EMSGSIZE; } spin_unlock(&file_ext->file_lock); - if (copy_from_user(&flag, k_msg.data, 1)) { + if (copy_from_user(&flag, (void __user *)k_msg.data, 1)) { rets = -EFAULT; goto end; } @@ -631,28 +641,39 @@ int heci_start_read(struct iamt_heci_device *dev, int if_num, DBG("received wrong function input param.\n"); return -ENODEV; } - if (file_ext->state != HECI_FILE_CONNECTED) - return -ENODEV; spin_lock_bh(&dev->device_lock); + if (file_ext->state != HECI_FILE_CONNECTED) { + spin_unlock_bh(&dev->device_lock); + return -ENODEV; + } + if (dev->heci_state != HECI_ENABLED) { spin_unlock_bh(&dev->device_lock); return -ENODEV; } spin_unlock_bh(&dev->device_lock); DBG("check if read is pending.\n"); + spin_lock_bh(&file_ext->read_io_lock); if ((file_ext->read_pending) || (file_ext->read_cb != NULL)) { DBG("read is pending.\n"); + spin_unlock_bh(&file_ext->read_io_lock); return -EBUSY; } + spin_unlock_bh(&file_ext->read_io_lock); + priv_cb = kzalloc(sizeof(struct heci_cb_private), GFP_KERNEL); if (!priv_cb) return -ENOMEM; + spin_lock_bh(&file_ext->read_io_lock); DBG("allocation call back success\n" "host client = %d, ME client = %d\n", file_ext->host_client_id, file_ext->me_client_id); + spin_unlock_bh(&file_ext->read_io_lock); + spin_lock_bh(&dev->device_lock); + spin_lock_bh(&file_ext->read_io_lock); for (i = 0; i < dev->num_heci_me_clients; i++) { if (dev->me_clients[i].client_id == file_ext->me_client_id) break; @@ -660,6 +681,7 @@ int heci_start_read(struct iamt_heci_device *dev, int if_num, } BUG_ON(dev->me_clients[i].client_id != file_ext->me_client_id); + spin_unlock_bh(&file_ext->read_io_lock); if (i == dev->num_heci_me_clients) { rets = -ENODEV; goto unlock; @@ -678,12 +700,14 @@ int heci_start_read(struct iamt_heci_device *dev, int if_num, /* make sure information is zero before we start */ priv_cb->information = 0; priv_cb->file_private = (void *) file_ext; - file_ext->read_cb = priv_cb; spin_lock_bh(&dev->device_lock); + spin_lock_bh(&file_ext->read_io_lock); + file_ext->read_cb = priv_cb; if (dev->host_buffer_is_empty) { dev->host_buffer_is_empty = 0; if (!heci_send_flow_control(dev, file_ext)) { rets = -ENODEV; + spin_unlock_bh(&file_ext->read_io_lock); goto unlock; } else { list_add_tail(&priv_cb->cb_list, @@ -693,6 +717,7 @@ int heci_start_read(struct iamt_heci_device *dev, int if_num, list_add_tail(&priv_cb->cb_list, &dev->ctrl_wr_list.heci_cb.cb_list); } + spin_unlock_bh(&file_ext->read_io_lock); spin_unlock_bh(&dev->device_lock); return rets; unlock: diff --git a/drivers/staging/meilhaus/me0600_ext_irq.c b/drivers/staging/meilhaus/me0600_ext_irq.c index 2f6fedca3223..1d098420a548 100644 --- a/drivers/staging/meilhaus/me0600_ext_irq.c +++ b/drivers/staging/meilhaus/me0600_ext_irq.c @@ -32,7 +32,6 @@ /* * Includes */ -#include #include #include @@ -434,11 +433,7 @@ me0600_ext_irq_subdevice_t *me0600_ext_irq_constructor(uint32_t plx_reg_base, subdevice->irq = irq; err = request_irq(subdevice->irq, me0600_isr, -#ifdef IRQF_DISABLED IRQF_DISABLED | IRQF_SHARED, -#else - SA_INTERRUPT | SA_SHIRQ, -#endif ME0600_NAME, (void *)subdevice); if (err) { diff --git a/drivers/staging/meilhaus/me0900_di.c b/drivers/staging/meilhaus/me0900_di.c index 4665b2acbea4..b8c448f58e36 100644 --- a/drivers/staging/meilhaus/me0900_di.c +++ b/drivers/staging/meilhaus/me0900_di.c @@ -38,7 +38,6 @@ #include #include #include -#include #include "medefines.h" #include "meinternal.h" diff --git a/drivers/staging/meilhaus/me1400_device.c b/drivers/staging/meilhaus/me1400_device.c index ca7498b9056c..a018b5f7a19b 100644 --- a/drivers/staging/meilhaus/me1400_device.c +++ b/drivers/staging/meilhaus/me1400_device.c @@ -47,7 +47,6 @@ #include #include #include -#include #include "meids.h" #include "meerror.h" diff --git a/drivers/staging/meilhaus/me1400_ext_irq.c b/drivers/staging/meilhaus/me1400_ext_irq.c index 0dc6b4519b5b..6841f41860a2 100644 --- a/drivers/staging/meilhaus/me1400_ext_irq.c +++ b/drivers/staging/meilhaus/me1400_ext_irq.c @@ -32,7 +32,6 @@ /* * Includes */ -#include #include #include @@ -458,11 +457,7 @@ me1400_ext_irq_subdevice_t *me1400_ext_irq_constructor(uint32_t device_id, subdevice->irq = irq; err = request_irq(irq, me1400_ext_irq_isr, -#ifdef IRQF_DISABLED IRQF_DISABLED | IRQF_SHARED, -#else - SA_INTERRUPT | SA_SHIRQ, -#endif ME1400_NAME, (void *)subdevice); if (err) { diff --git a/drivers/staging/meilhaus/me4600_ai.c b/drivers/staging/meilhaus/me4600_ai.c index a3cfef09a4de..e496d0c8d484 100644 --- a/drivers/staging/meilhaus/me4600_ai.c +++ b/drivers/staging/meilhaus/me4600_ai.c @@ -299,11 +299,7 @@ me4600_ai_subdevice_t *me4600_ai_constructor(uint32_t reg_base, // Register interrupt service routine. subdevice->irq = irq; if (request_irq(subdevice->irq, me4600_ai_isr, -#ifdef IRQF_DISABLED IRQF_DISABLED | IRQF_SHARED, -#else - SA_INTERRUPT | SA_SHIRQ, -#endif ME4600_NAME, subdevice)) { PERROR("Cannot register interrupt service routine.\n"); me_subdevice_deinit((me_subdevice_t *) subdevice); diff --git a/drivers/staging/meilhaus/me4600_ai.h b/drivers/staging/meilhaus/me4600_ai.h index 106e1959f9f1..7055e44f32ea 100644 --- a/drivers/staging/meilhaus/me4600_ai.h +++ b/drivers/staging/meilhaus/me4600_ai.h @@ -28,7 +28,6 @@ #ifndef _ME4600_AI_H_ #define _ME4600_AI_H_ -#include #include "mesubdevice.h" #include "meioctl.h" #include "mecirc_buf.h" diff --git a/drivers/staging/meilhaus/me4600_ao.c b/drivers/staging/meilhaus/me4600_ao.c index eb472692a7c5..4000dac057ed 100644 --- a/drivers/staging/meilhaus/me4600_ao.c +++ b/drivers/staging/meilhaus/me4600_ao.c @@ -2567,11 +2567,7 @@ me4600_ao_subdevice_t *me4600_ao_constructor(uint32_t reg_base, if (subdevice->fifo) { subdevice->irq = irq; if (request_irq(subdevice->irq, me4600_ao_isr, -#ifdef IRQF_DISABLED IRQF_DISABLED | IRQF_SHARED, -#else - SA_INTERRUPT | SA_SHIRQ, -#endif ME4600_NAME, subdevice)) { PERROR("Cannot get interrupt line.\n"); PDEBUG("free circ_buf = %p size=%d", @@ -5737,7 +5733,7 @@ me4600_ao_subdevice_t *me4600_ao_constructor(uint32_t reg_base, subdevice->irq = irq; if (request_irq - (subdevice->irq, me4600_ao_isr, SA_INTERRUPT | SA_SHIRQ, + (subdevice->irq, me4600_ao_isr, IRQF_DISABLED | IRQF_SHARED, ME4600_NAME, subdevice)) { PERROR("Cannot get interrupt line.\n"); me_subdevice_deinit((me_subdevice_t *) subdevice); diff --git a/drivers/staging/meilhaus/me4600_ext_irq.c b/drivers/staging/meilhaus/me4600_ext_irq.c index 6b33cba3da8b..cfb4adbd41ab 100644 --- a/drivers/staging/meilhaus/me4600_ext_irq.c +++ b/drivers/staging/meilhaus/me4600_ext_irq.c @@ -39,7 +39,6 @@ #include #include #include -#include #include "medefines.h" #include "meinternal.h" @@ -420,11 +419,7 @@ me4600_ext_irq_subdevice_t *me4600_ext_irq_constructor(uint32_t reg_base, subdevice->irq = irq; if (request_irq(subdevice->irq, me4600_ext_irq_isr, -#ifdef IRQF_DISABLED IRQF_DISABLED | IRQF_SHARED, -#else - SA_INTERRUPT | SA_SHIRQ, -#endif ME4600_NAME, subdevice)) { PERROR("Cannot register interrupt.\n"); kfree(subdevice); diff --git a/drivers/staging/meilhaus/me6000_ao.c b/drivers/staging/meilhaus/me6000_ao.c index f7abdbd485e4..66652dc5b967 100644 --- a/drivers/staging/meilhaus/me6000_ao.c +++ b/drivers/staging/meilhaus/me6000_ao.c @@ -2627,11 +2627,7 @@ me6000_ao_subdevice_t *me6000_ao_constructor(uint32_t reg_base, if (subdevice->fifo & ME6000_AO_HAS_FIFO) { subdevice->irq = irq; if (request_irq(subdevice->irq, me6000_ao_isr, -#ifdef IRQF_DISABLED IRQF_DISABLED | IRQF_SHARED, -#else - SA_INTERRUPT | SA_SHIRQ, -#endif ME6000_NAME, subdevice)) { PERROR("Cannot get interrupt line.\n"); PDEBUG("free circ_buf = %p size=%d", diff --git a/drivers/staging/meilhaus/me6000_ao.h b/drivers/staging/meilhaus/me6000_ao.h index ef4d0189bdea..d86fb29265f5 100644 --- a/drivers/staging/meilhaus/me6000_ao.h +++ b/drivers/staging/meilhaus/me6000_ao.h @@ -27,7 +27,6 @@ #ifndef _ME6000_AO_H_ #define _ME6000_AO_H_ -#include #include "mesubdevice.h" #include "mecirc_buf.h" #include "meioctl.h" diff --git a/drivers/staging/meilhaus/me8100_di.c b/drivers/staging/meilhaus/me8100_di.c index 301dbd8f96a1..1a3f2692d7ab 100644 --- a/drivers/staging/meilhaus/me8100_di.c +++ b/drivers/staging/meilhaus/me8100_di.c @@ -39,7 +39,6 @@ #include #include #include -#include #include "medefines.h" #include "meerror.h" @@ -633,11 +632,7 @@ me8100_di_subdevice_t *me8100_di_constructor(uint32_t me8100_reg_base, /* Register interrupt service routine. */ subdevice->irq = irq; err = request_irq(subdevice->irq, me8100_isr, -#ifdef IRQF_DISABLED IRQF_DISABLED | IRQF_SHARED, -#else - SA_INTERRUPT | SA_SHIRQ, -#endif ME8100_NAME, (void *)subdevice); if (err) { diff --git a/drivers/staging/meilhaus/me8200_di.c b/drivers/staging/meilhaus/me8200_di.c index a931fb817c7d..fd1af0f0565e 100644 --- a/drivers/staging/meilhaus/me8200_di.c +++ b/drivers/staging/meilhaus/me8200_di.c @@ -37,7 +37,6 @@ #include #include #include -#include #include "medefines.h" #include "meerror.h" @@ -801,19 +800,11 @@ me8200_di_subdevice_t *me8200_di_constructor(uint32_t me8200_regbase, subdevice->irq = irq; if (subdevice->version > 0) { // NEW err = request_irq(subdevice->irq, me8200_isr_EX, -#ifdef IRQF_DISABLED IRQF_DISABLED | IRQF_SHARED, -#else - SA_INTERRUPT | SA_SHIRQ, -#endif ME8200_NAME, (void *)subdevice); } else { //OLD err = request_irq(subdevice->irq, me8200_isr, -#ifdef IRQF_DISABLED IRQF_DISABLED | IRQF_SHARED, -#else - SA_INTERRUPT | SA_SHIRQ, -#endif ME8200_NAME, (void *)subdevice); } diff --git a/drivers/staging/meilhaus/me8200_do.c b/drivers/staging/meilhaus/me8200_do.c index 40d536c71d50..e42a137617a1 100644 --- a/drivers/staging/meilhaus/me8200_do.c +++ b/drivers/staging/meilhaus/me8200_do.c @@ -39,7 +39,6 @@ #include #include #include -#include #include "medefines.h" #include "meinternal.h" @@ -556,11 +555,7 @@ me8200_do_subdevice_t *me8200_do_constructor(uint32_t reg_base, /* Request the interrupt line */ err = request_irq(irq, me8200_do_isr, -#ifdef IRQF_DISABLED IRQF_DISABLED | IRQF_SHARED, -#else - SA_INTERRUPT | SA_SHIRQ, -#endif ME8200_NAME, (void *)subdevice); if (err) { diff --git a/drivers/staging/meilhaus/memain.c b/drivers/staging/meilhaus/memain.c index fd9f079b0ed1..c4908549192f 100644 --- a/drivers/staging/meilhaus/memain.c +++ b/drivers/staging/meilhaus/memain.c @@ -38,7 +38,7 @@ //#include #include #include -#include +#include #include #include "medefines.h" @@ -68,13 +68,6 @@ MODULE_PARM_DESC(me_bosch_fw, "Flags which signals the ME-4600 driver to load the bosch firmware (default = 0)."); #endif //BOSCH -static unsigned int major = 0; -#ifdef module_param -module_param(major, int, S_IRUGO); -#else -MODULE_PARM(major, "i"); -#endif - /* Global Driver Lock */ @@ -100,29 +93,131 @@ static int me_ioctl(struct inode *, struct file *, unsigned int, unsigned long); //static int me_probe_usb(struct usb_interface *interface, const struct usb_device_id *id); //static void me_disconnect_usb(struct usb_interface *interface); -/* Character device structure -*/ - -static struct cdev *cdevp; - /* File operations provided by the module */ -static struct file_operations me_file_operations = { +static const struct file_operations me_file_operations = { .owner = THIS_MODULE, .ioctl = me_ioctl, .open = me_open, .release = me_release, }; -struct pci_driver me_pci_driver = { +static const struct pci_device_id me_pci_table[] = { + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME1000) }, + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME1000_A) }, + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME1000_B) }, + + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME1400) }, + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME140A) }, + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME140B) }, + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME14E0) }, + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME14EA) }, + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME14EB) }, + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME140C) }, + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME140D) }, + + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME1600_4U) }, + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME1600_8U) }, + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME1600_12U) }, + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME1600_16U) }, + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME1600_16U_8I) }, + + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4610) }, + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4650) }, + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4660) }, + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4660I) }, + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4670) }, + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4670I) }, + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4670S) }, + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4670IS) }, + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4680) }, + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4680I) }, + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4680S) }, + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4680IS) }, + + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6004) }, + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6008) }, + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME600F) }, + + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6014) }, + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6018) }, + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME601F) }, + + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6034) }, + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6038) }, + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME603F) }, + + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6104) }, + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6108) }, + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME610F) }, + + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6114) }, + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6118) }, + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME611F) }, + + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6134) }, + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6138) }, + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME613F) }, + + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6044) }, + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6048) }, + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME604F) }, + + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6054) }, + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6058) }, + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME605F) }, + + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6074) }, + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6078) }, + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME607F) }, + + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6144) }, + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6148) }, + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME614F) }, + + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6154) }, + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6158) }, + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME615F) }, + + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6174) }, + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6178) }, + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME617F) }, + + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6259) }, + + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6359) }, + + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME0630) }, + + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME8100_A) }, + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME8100_B) }, + + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME8200_A) }, + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME8200_B) }, + + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME0940) }, + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME0950) }, + { PCI_VDEVICE(MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME0960) }, + + { } +}; +MODULE_DEVICE_TABLE(pci, me_pci_table); + +static struct pci_driver me_pci_driver = { .name = MEMAIN_NAME, .id_table = me_pci_table, .probe = me_probe_pci, - .remove = me_remove_pci + .remove = __devexit_p(me_remove_pci), }; -/* //me_usb_driver +/* +static struct usb_device_id me_usb_table[] = { + { USB_DEVICE(USB_VENDOR_ID_MEPHISTO_S1, USB_DEVICE_ID_MEPHISTO_S1) }, + { 0 } +}; +MODULE_DEVICE_TABLE (usb, me_usb_table); + static struct usb_driver me_usb_driver = { .name = MEMAIN_NAME, @@ -396,7 +491,8 @@ static me_device_t *get_dummy_instance(unsigned short vendor_id, return instance; } -static int me_probe_pci(struct pci_dev *dev, const struct pci_device_id *id) +static int __devinit me_probe_pci(struct pci_dev *dev, + const struct pci_device_id *id) { int err; me_pci_constructor_t constructor = NULL; @@ -424,7 +520,7 @@ static int me_probe_pci(struct pci_dev *dev, const struct pci_device_id *id) if ((constructor = (me_pci_constructor_t) symbol_get(constructor_name)) == NULL) { - if (request_module(module_name)) { + if (request_module("%s", module_name)) { PERROR("Error while request for module %s.\n", module_name); return -ENODEV; @@ -594,7 +690,7 @@ static int insert_to_device_list(me_device_t *n_device) return 0; } -static void me_remove_pci(struct pci_dev *dev) +static void __devexit me_remove_pci(struct pci_dev *dev) { int vendor_id = dev->vendor; int device_id = dev->device; @@ -1910,11 +2006,16 @@ static int me_ioctl(struct inode *inodep, return -ENOTTY; } +static struct miscdevice me_miscdev = { + .minor = MISC_DYNAMIC_MINOR, + .name = MEMAIN_NAME, + .fops = &me_file_operations, +}; + // Init and exit of module. static int memain_init(void) { int result = 0; - dev_t dev = MKDEV(major, 0); PDEBUG("executed.\n"); @@ -1943,46 +2044,14 @@ static int memain_init(void) } } */ - // Register the character device. - if (major) { - result = register_chrdev_region(dev, 1, MEMAIN_NAME); - } else { - result = alloc_chrdev_region(&dev, 0, 1, MEMAIN_NAME); - major = MAJOR(dev); - } - + result = misc_register(&me_miscdev); if (result < 0) { - PERROR("Can't get major driver no.\n"); + printk(KERN_ERR MEMAIN_NAME ": can't register misc device\n"); goto INIT_ERROR_3; } - cdevp = cdev_alloc(); - - if (!cdevp) { - PERROR("Can't get character device structure.\n"); - result = -ENOMEM; - goto INIT_ERROR_4; - } - - cdevp->ops = &me_file_operations; - - cdevp->owner = THIS_MODULE; - - result = cdev_add(cdevp, dev, 1); - - if (result < 0) { - PERROR("Cannot add character device structure.\n"); - goto INIT_ERROR_5; - } - return 0; - INIT_ERROR_5: - cdev_del(cdevp); - - INIT_ERROR_4: - unregister_chrdev_region(dev, 1); - INIT_ERROR_3: // usb_deregister(&me_usb_driver); @@ -1996,12 +2065,9 @@ static int memain_init(void) static void __exit memain_exit(void) { - dev_t dev = MKDEV(major, 0); - PDEBUG("executed.\n"); - cdev_del(cdevp); - unregister_chrdev_region(dev, 1); + misc_deregister(&me_miscdev); pci_unregister_driver(&me_pci_driver); // usb_deregister(&me_usb_driver); clear_device_list(); diff --git a/drivers/staging/meilhaus/memain.h b/drivers/staging/meilhaus/memain.h index 7616ff7f65cb..48f83679379e 100644 --- a/drivers/staging/meilhaus/memain.h +++ b/drivers/staging/meilhaus/memain.h @@ -27,200 +27,6 @@ #ifdef __KERNEL__ -/*============================================================================= - PCI device table. - This is used by modprobe to translate PCI IDs to drivers. - ===========================================================================*/ - -static struct pci_device_id me_pci_table[] __devinitdata = { - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME1000, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME1000_A, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME1000_B, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME1400, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME140A, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME140B, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME14E0, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME14EA, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME14EB, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME140C, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME140D, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME1600_4U, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME1600_8U, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME1600_12U, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME1600_16U, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME1600_16U_8I, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4610, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4650, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4660, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4660I, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4670, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4670I, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4670S, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4670IS, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4680, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4680I, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4680S, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4680IS, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6004, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6008, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME600F, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6014, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6018, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME601F, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6034, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6038, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME603F, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6104, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6108, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME610F, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6114, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6118, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME611F, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6134, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6138, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME613F, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6044, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6048, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME604F, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6054, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6058, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME605F, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6074, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6078, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME607F, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6144, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6148, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME614F, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6154, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6158, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME615F, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6174, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6178, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME617F, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6259, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME6359, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME0630, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME8100_A, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME8100_B, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME8200_A, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME8200_B, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME0940, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME0950, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME0960, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - - {0} -}; - -MODULE_DEVICE_TABLE(pci, me_pci_table); - -/*============================================================================= - USB device table. - This is used by modprobe to translate USB IDs to drivers. - ===========================================================================*/ -/* -static struct usb_device_id me_usb_table[] __devinitdata = { - { USB_DEVICE(USB_VENDOR_ID_MEPHISTO_S1, USB_DEVICE_ID_MEPHISTO_S1) }, - { 0 } -}; - -MODULE_DEVICE_TABLE (usb, me_usb_table); -*/ - /*============================================================================= Templates ===========================================================================*/ diff --git a/drivers/staging/octeon/Kconfig b/drivers/staging/octeon/Kconfig new file mode 100644 index 000000000000..536e2382de54 --- /dev/null +++ b/drivers/staging/octeon/Kconfig @@ -0,0 +1,12 @@ +config OCTEON_ETHERNET + tristate "Cavium Networks Octeon Ethernet support" + depends on CPU_CAVIUM_OCTEON + select MII + help + This driver supports the builtin ethernet ports on Cavium + Networks' products in the Octeon family. This driver supports the + CN3XXX and CN5XXX Octeon processors. + + To compile this driver as a module, choose M here. The module + will be called octeon-ethernet. + diff --git a/drivers/staging/octeon/Makefile b/drivers/staging/octeon/Makefile new file mode 100644 index 000000000000..c0a583cc2227 --- /dev/null +++ b/drivers/staging/octeon/Makefile @@ -0,0 +1,29 @@ +# 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) 2005-2009 Cavium Networks +# + +# +# Makefile for Cavium OCTEON on-board ethernet driver +# + +obj-${CONFIG_OCTEON_ETHERNET} := octeon-ethernet.o + +octeon-ethernet-objs := ethernet.o +octeon-ethernet-objs += ethernet-mdio.o +octeon-ethernet-objs += ethernet-mem.o +octeon-ethernet-objs += ethernet-proc.o +octeon-ethernet-objs += ethernet-rgmii.o +octeon-ethernet-objs += ethernet-rx.o +octeon-ethernet-objs += ethernet-sgmii.o +octeon-ethernet-objs += ethernet-spi.o +octeon-ethernet-objs += ethernet-tx.o +octeon-ethernet-objs += ethernet-xaui.o +octeon-ethernet-objs += cvmx-pko.o cvmx-spi.o cvmx-cmd-queue.o \ + cvmx-helper-board.o cvmx-helper.o cvmx-helper-xaui.o \ + cvmx-helper-rgmii.o cvmx-helper-sgmii.o cvmx-helper-npi.o \ + cvmx-helper-loop.o cvmx-helper-spi.o cvmx-helper-util.o \ + cvmx-interrupt-decodes.o cvmx-interrupt-rsl.o + diff --git a/drivers/staging/octeon/cvmx-address.h b/drivers/staging/octeon/cvmx-address.h new file mode 100644 index 000000000000..3c74d826e2e6 --- /dev/null +++ b/drivers/staging/octeon/cvmx-address.h @@ -0,0 +1,274 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2009 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +/** + * Typedefs and defines for working with Octeon physical addresses. + * + */ +#ifndef __CVMX_ADDRESS_H__ +#define __CVMX_ADDRESS_H__ + +#if 0 +typedef enum { + CVMX_MIPS_SPACE_XKSEG = 3LL, + CVMX_MIPS_SPACE_XKPHYS = 2LL, + CVMX_MIPS_SPACE_XSSEG = 1LL, + CVMX_MIPS_SPACE_XUSEG = 0LL +} cvmx_mips_space_t; +#endif + +typedef enum { + CVMX_MIPS_XKSEG_SPACE_KSEG0 = 0LL, + CVMX_MIPS_XKSEG_SPACE_KSEG1 = 1LL, + CVMX_MIPS_XKSEG_SPACE_SSEG = 2LL, + CVMX_MIPS_XKSEG_SPACE_KSEG3 = 3LL +} cvmx_mips_xkseg_space_t; + +/* decodes <14:13> of a kseg3 window address */ +typedef enum { + CVMX_ADD_WIN_SCR = 0L, + /* see cvmx_add_win_dma_dec_t for further decode */ + CVMX_ADD_WIN_DMA = 1L, + CVMX_ADD_WIN_UNUSED = 2L, + CVMX_ADD_WIN_UNUSED2 = 3L +} cvmx_add_win_dec_t; + +/* decode within DMA space */ +typedef enum { + /* + * Add store data to the write buffer entry, allocating it if + * necessary. + */ + CVMX_ADD_WIN_DMA_ADD = 0L, + /* send out the write buffer entry to DRAM */ + CVMX_ADD_WIN_DMA_SENDMEM = 1L, + /* store data must be normal DRAM memory space address in this case */ + /* send out the write buffer entry as an IOBDMA command */ + CVMX_ADD_WIN_DMA_SENDDMA = 2L, + /* see CVMX_ADD_WIN_DMA_SEND_DEC for data contents */ + /* send out the write buffer entry as an IO write */ + CVMX_ADD_WIN_DMA_SENDIO = 3L, + /* store data must be normal IO space address in this case */ + /* send out a single-tick command on the NCB bus */ + CVMX_ADD_WIN_DMA_SENDSINGLE = 4L, + /* no write buffer data needed/used */ +} cvmx_add_win_dma_dec_t; + +/* + * Physical Address Decode + * + * Octeon-I HW never interprets this X (<39:36> reserved + * for future expansion), software should set to 0. + * + * - 0x0 XXX0 0000 0000 to DRAM Cached + * - 0x0 XXX0 0FFF FFFF + * + * - 0x0 XXX0 1000 0000 to Boot Bus Uncached (Converted to 0x1 00X0 1000 0000 + * - 0x0 XXX0 1FFF FFFF + EJTAG to 0x1 00X0 1FFF FFFF) + * + * - 0x0 XXX0 2000 0000 to DRAM Cached + * - 0x0 XXXF FFFF FFFF + * + * - 0x1 00X0 0000 0000 to Boot Bus Uncached + * - 0x1 00XF FFFF FFFF + * + * - 0x1 01X0 0000 0000 to Other NCB Uncached + * - 0x1 FFXF FFFF FFFF devices + * + * Decode of all Octeon addresses + */ +typedef union { + + uint64_t u64; + /* mapped or unmapped virtual address */ + struct { + uint64_t R:2; + uint64_t offset:62; + } sva; + + /* mapped USEG virtual addresses (typically) */ + struct { + uint64_t zeroes:33; + uint64_t offset:31; + } suseg; + + /* mapped or unmapped virtual address */ + struct { + uint64_t ones:33; + uint64_t sp:2; + uint64_t offset:29; + } sxkseg; + + /* + * physical address accessed through xkphys unmapped virtual + * address. + */ + struct { + uint64_t R:2; /* CVMX_MIPS_SPACE_XKPHYS in this case */ + uint64_t cca:3; /* ignored by octeon */ + uint64_t mbz:10; + uint64_t pa:49; /* physical address */ + } sxkphys; + + /* physical address */ + struct { + uint64_t mbz:15; + /* if set, the address is uncached and resides on MCB bus */ + uint64_t is_io:1; + /* + * the hardware ignores this field when is_io==0, else + * device ID. + */ + uint64_t did:8; + /* the hardware ignores <39:36> in Octeon I */ + uint64_t unaddr:4; + uint64_t offset:36; + } sphys; + + /* physical mem address */ + struct { + /* techically, <47:40> are dont-cares */ + uint64_t zeroes:24; + /* the hardware ignores <39:36> in Octeon I */ + uint64_t unaddr:4; + uint64_t offset:36; + } smem; + + /* physical IO address */ + struct { + uint64_t mem_region:2; + uint64_t mbz:13; + /* 1 in this case */ + uint64_t is_io:1; + /* + * The hardware ignores this field when is_io==0, else + * device ID. + */ + uint64_t did:8; + /* the hardware ignores <39:36> in Octeon I */ + uint64_t unaddr:4; + uint64_t offset:36; + } sio; + + /* + * Scratchpad virtual address - accessed through a window at + * the end of kseg3 + */ + struct { + uint64_t ones:49; + /* CVMX_ADD_WIN_SCR (0) in this case */ + cvmx_add_win_dec_t csrdec:2; + uint64_t addr:13; + } sscr; + + /* there should only be stores to IOBDMA space, no loads */ + /* + * IOBDMA virtual address - accessed through a window at the + * end of kseg3 + */ + struct { + uint64_t ones:49; + uint64_t csrdec:2; /* CVMX_ADD_WIN_DMA (1) in this case */ + uint64_t unused2:3; + uint64_t type:3; + uint64_t addr:7; + } sdma; + + struct { + uint64_t didspace:24; + uint64_t unused:40; + } sfilldidspace; + +} cvmx_addr_t; + +/* These macros for used by 32 bit applications */ + +#define CVMX_MIPS32_SPACE_KSEG0 1l +#define CVMX_ADD_SEG32(segment, add) \ + (((int32_t)segment << 31) | (int32_t)(add)) + +/* + * Currently all IOs are performed using XKPHYS addressing. Linux uses + * the CvmMemCtl register to enable XKPHYS addressing to IO space from + * user mode. Future OSes may need to change the upper bits of IO + * addresses. The following define controls the upper two bits for all + * IO addresses generated by the simple executive library. + */ +#define CVMX_IO_SEG CVMX_MIPS_SPACE_XKPHYS + +/* These macros simplify the process of creating common IO addresses */ +#define CVMX_ADD_SEG(segment, add) ((((uint64_t)segment) << 62) | (add)) +#ifndef CVMX_ADD_IO_SEG +#define CVMX_ADD_IO_SEG(add) CVMX_ADD_SEG(CVMX_IO_SEG, (add)) +#endif +#define CVMX_ADDR_DIDSPACE(did) (((CVMX_IO_SEG) << 22) | ((1ULL) << 8) | (did)) +#define CVMX_ADDR_DID(did) (CVMX_ADDR_DIDSPACE(did) << 40) +#define CVMX_FULL_DID(did, subdid) (((did) << 3) | (subdid)) + + /* from include/ncb_rsl_id.v */ +#define CVMX_OCT_DID_MIS 0ULL /* misc stuff */ +#define CVMX_OCT_DID_GMX0 1ULL +#define CVMX_OCT_DID_GMX1 2ULL +#define CVMX_OCT_DID_PCI 3ULL +#define CVMX_OCT_DID_KEY 4ULL +#define CVMX_OCT_DID_FPA 5ULL +#define CVMX_OCT_DID_DFA 6ULL +#define CVMX_OCT_DID_ZIP 7ULL +#define CVMX_OCT_DID_RNG 8ULL +#define CVMX_OCT_DID_IPD 9ULL +#define CVMX_OCT_DID_PKT 10ULL +#define CVMX_OCT_DID_TIM 11ULL +#define CVMX_OCT_DID_TAG 12ULL + /* the rest are not on the IO bus */ +#define CVMX_OCT_DID_L2C 16ULL +#define CVMX_OCT_DID_LMC 17ULL +#define CVMX_OCT_DID_SPX0 18ULL +#define CVMX_OCT_DID_SPX1 19ULL +#define CVMX_OCT_DID_PIP 20ULL +#define CVMX_OCT_DID_ASX0 22ULL +#define CVMX_OCT_DID_ASX1 23ULL +#define CVMX_OCT_DID_IOB 30ULL + +#define CVMX_OCT_DID_PKT_SEND CVMX_FULL_DID(CVMX_OCT_DID_PKT, 2ULL) +#define CVMX_OCT_DID_TAG_SWTAG CVMX_FULL_DID(CVMX_OCT_DID_TAG, 0ULL) +#define CVMX_OCT_DID_TAG_TAG1 CVMX_FULL_DID(CVMX_OCT_DID_TAG, 1ULL) +#define CVMX_OCT_DID_TAG_TAG2 CVMX_FULL_DID(CVMX_OCT_DID_TAG, 2ULL) +#define CVMX_OCT_DID_TAG_TAG3 CVMX_FULL_DID(CVMX_OCT_DID_TAG, 3ULL) +#define CVMX_OCT_DID_TAG_NULL_RD CVMX_FULL_DID(CVMX_OCT_DID_TAG, 4ULL) +#define CVMX_OCT_DID_TAG_CSR CVMX_FULL_DID(CVMX_OCT_DID_TAG, 7ULL) +#define CVMX_OCT_DID_FAU_FAI CVMX_FULL_DID(CVMX_OCT_DID_IOB, 0ULL) +#define CVMX_OCT_DID_TIM_CSR CVMX_FULL_DID(CVMX_OCT_DID_TIM, 0ULL) +#define CVMX_OCT_DID_KEY_RW CVMX_FULL_DID(CVMX_OCT_DID_KEY, 0ULL) +#define CVMX_OCT_DID_PCI_6 CVMX_FULL_DID(CVMX_OCT_DID_PCI, 6ULL) +#define CVMX_OCT_DID_MIS_BOO CVMX_FULL_DID(CVMX_OCT_DID_MIS, 0ULL) +#define CVMX_OCT_DID_PCI_RML CVMX_FULL_DID(CVMX_OCT_DID_PCI, 0ULL) +#define CVMX_OCT_DID_IPD_CSR CVMX_FULL_DID(CVMX_OCT_DID_IPD, 7ULL) +#define CVMX_OCT_DID_DFA_CSR CVMX_FULL_DID(CVMX_OCT_DID_DFA, 7ULL) +#define CVMX_OCT_DID_MIS_CSR CVMX_FULL_DID(CVMX_OCT_DID_MIS, 7ULL) +#define CVMX_OCT_DID_ZIP_CSR CVMX_FULL_DID(CVMX_OCT_DID_ZIP, 0ULL) + +#endif /* __CVMX_ADDRESS_H__ */ diff --git a/drivers/staging/octeon/cvmx-asxx-defs.h b/drivers/staging/octeon/cvmx-asxx-defs.h new file mode 100644 index 000000000000..91415a85e8d2 --- /dev/null +++ b/drivers/staging/octeon/cvmx-asxx-defs.h @@ -0,0 +1,475 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2008 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +#ifndef __CVMX_ASXX_DEFS_H__ +#define __CVMX_ASXX_DEFS_H__ + +#define CVMX_ASXX_GMII_RX_CLK_SET(block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0000180ull + (((block_id) & 0) * 0x8000000ull)) +#define CVMX_ASXX_GMII_RX_DAT_SET(block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0000188ull + (((block_id) & 0) * 0x8000000ull)) +#define CVMX_ASXX_INT_EN(block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0000018ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_ASXX_INT_REG(block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0000010ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_ASXX_MII_RX_DAT_SET(block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0000190ull + (((block_id) & 0) * 0x8000000ull)) +#define CVMX_ASXX_PRT_LOOP(block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0000040ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_ASXX_RLD_BYPASS(block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0000248ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_ASXX_RLD_BYPASS_SETTING(block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0000250ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_ASXX_RLD_COMP(block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0000220ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_ASXX_RLD_DATA_DRV(block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0000218ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_ASXX_RLD_FCRAM_MODE(block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0000210ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_ASXX_RLD_NCTL_STRONG(block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0000230ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_ASXX_RLD_NCTL_WEAK(block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0000240ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_ASXX_RLD_PCTL_STRONG(block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0000228ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_ASXX_RLD_PCTL_WEAK(block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0000238ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_ASXX_RLD_SETTING(block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0000258ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_ASXX_RX_CLK_SETX(offset, block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0000020ull + (((offset) & 3) * 8) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_ASXX_RX_PRT_EN(block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0000000ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_ASXX_RX_WOL(block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0000100ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_ASXX_RX_WOL_MSK(block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0000108ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_ASXX_RX_WOL_POWOK(block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0000118ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_ASXX_RX_WOL_SIG(block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0000110ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_ASXX_TX_CLK_SETX(offset, block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0000048ull + (((offset) & 3) * 8) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_ASXX_TX_COMP_BYP(block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0000068ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_ASXX_TX_HI_WATERX(offset, block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0000080ull + (((offset) & 3) * 8) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_ASXX_TX_PRT_EN(block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0000008ull + (((block_id) & 1) * 0x8000000ull)) + +union cvmx_asxx_gmii_rx_clk_set { + uint64_t u64; + struct cvmx_asxx_gmii_rx_clk_set_s { + uint64_t reserved_5_63:59; + uint64_t setting:5; + } s; + struct cvmx_asxx_gmii_rx_clk_set_s cn30xx; + struct cvmx_asxx_gmii_rx_clk_set_s cn31xx; + struct cvmx_asxx_gmii_rx_clk_set_s cn50xx; +}; + +union cvmx_asxx_gmii_rx_dat_set { + uint64_t u64; + struct cvmx_asxx_gmii_rx_dat_set_s { + uint64_t reserved_5_63:59; + uint64_t setting:5; + } s; + struct cvmx_asxx_gmii_rx_dat_set_s cn30xx; + struct cvmx_asxx_gmii_rx_dat_set_s cn31xx; + struct cvmx_asxx_gmii_rx_dat_set_s cn50xx; +}; + +union cvmx_asxx_int_en { + uint64_t u64; + struct cvmx_asxx_int_en_s { + uint64_t reserved_12_63:52; + uint64_t txpsh:4; + uint64_t txpop:4; + uint64_t ovrflw:4; + } s; + struct cvmx_asxx_int_en_cn30xx { + uint64_t reserved_11_63:53; + uint64_t txpsh:3; + uint64_t reserved_7_7:1; + uint64_t txpop:3; + uint64_t reserved_3_3:1; + uint64_t ovrflw:3; + } cn30xx; + struct cvmx_asxx_int_en_cn30xx cn31xx; + struct cvmx_asxx_int_en_s cn38xx; + struct cvmx_asxx_int_en_s cn38xxp2; + struct cvmx_asxx_int_en_cn30xx cn50xx; + struct cvmx_asxx_int_en_s cn58xx; + struct cvmx_asxx_int_en_s cn58xxp1; +}; + +union cvmx_asxx_int_reg { + uint64_t u64; + struct cvmx_asxx_int_reg_s { + uint64_t reserved_12_63:52; + uint64_t txpsh:4; + uint64_t txpop:4; + uint64_t ovrflw:4; + } s; + struct cvmx_asxx_int_reg_cn30xx { + uint64_t reserved_11_63:53; + uint64_t txpsh:3; + uint64_t reserved_7_7:1; + uint64_t txpop:3; + uint64_t reserved_3_3:1; + uint64_t ovrflw:3; + } cn30xx; + struct cvmx_asxx_int_reg_cn30xx cn31xx; + struct cvmx_asxx_int_reg_s cn38xx; + struct cvmx_asxx_int_reg_s cn38xxp2; + struct cvmx_asxx_int_reg_cn30xx cn50xx; + struct cvmx_asxx_int_reg_s cn58xx; + struct cvmx_asxx_int_reg_s cn58xxp1; +}; + +union cvmx_asxx_mii_rx_dat_set { + uint64_t u64; + struct cvmx_asxx_mii_rx_dat_set_s { + uint64_t reserved_5_63:59; + uint64_t setting:5; + } s; + struct cvmx_asxx_mii_rx_dat_set_s cn30xx; + struct cvmx_asxx_mii_rx_dat_set_s cn50xx; +}; + +union cvmx_asxx_prt_loop { + uint64_t u64; + struct cvmx_asxx_prt_loop_s { + uint64_t reserved_8_63:56; + uint64_t ext_loop:4; + uint64_t int_loop:4; + } s; + struct cvmx_asxx_prt_loop_cn30xx { + uint64_t reserved_7_63:57; + uint64_t ext_loop:3; + uint64_t reserved_3_3:1; + uint64_t int_loop:3; + } cn30xx; + struct cvmx_asxx_prt_loop_cn30xx cn31xx; + struct cvmx_asxx_prt_loop_s cn38xx; + struct cvmx_asxx_prt_loop_s cn38xxp2; + struct cvmx_asxx_prt_loop_cn30xx cn50xx; + struct cvmx_asxx_prt_loop_s cn58xx; + struct cvmx_asxx_prt_loop_s cn58xxp1; +}; + +union cvmx_asxx_rld_bypass { + uint64_t u64; + struct cvmx_asxx_rld_bypass_s { + uint64_t reserved_1_63:63; + uint64_t bypass:1; + } s; + struct cvmx_asxx_rld_bypass_s cn38xx; + struct cvmx_asxx_rld_bypass_s cn38xxp2; + struct cvmx_asxx_rld_bypass_s cn58xx; + struct cvmx_asxx_rld_bypass_s cn58xxp1; +}; + +union cvmx_asxx_rld_bypass_setting { + uint64_t u64; + struct cvmx_asxx_rld_bypass_setting_s { + uint64_t reserved_5_63:59; + uint64_t setting:5; + } s; + struct cvmx_asxx_rld_bypass_setting_s cn38xx; + struct cvmx_asxx_rld_bypass_setting_s cn38xxp2; + struct cvmx_asxx_rld_bypass_setting_s cn58xx; + struct cvmx_asxx_rld_bypass_setting_s cn58xxp1; +}; + +union cvmx_asxx_rld_comp { + uint64_t u64; + struct cvmx_asxx_rld_comp_s { + uint64_t reserved_9_63:55; + uint64_t pctl:5; + uint64_t nctl:4; + } s; + struct cvmx_asxx_rld_comp_cn38xx { + uint64_t reserved_8_63:56; + uint64_t pctl:4; + uint64_t nctl:4; + } cn38xx; + struct cvmx_asxx_rld_comp_cn38xx cn38xxp2; + struct cvmx_asxx_rld_comp_s cn58xx; + struct cvmx_asxx_rld_comp_s cn58xxp1; +}; + +union cvmx_asxx_rld_data_drv { + uint64_t u64; + struct cvmx_asxx_rld_data_drv_s { + uint64_t reserved_8_63:56; + uint64_t pctl:4; + uint64_t nctl:4; + } s; + struct cvmx_asxx_rld_data_drv_s cn38xx; + struct cvmx_asxx_rld_data_drv_s cn38xxp2; + struct cvmx_asxx_rld_data_drv_s cn58xx; + struct cvmx_asxx_rld_data_drv_s cn58xxp1; +}; + +union cvmx_asxx_rld_fcram_mode { + uint64_t u64; + struct cvmx_asxx_rld_fcram_mode_s { + uint64_t reserved_1_63:63; + uint64_t mode:1; + } s; + struct cvmx_asxx_rld_fcram_mode_s cn38xx; + struct cvmx_asxx_rld_fcram_mode_s cn38xxp2; +}; + +union cvmx_asxx_rld_nctl_strong { + uint64_t u64; + struct cvmx_asxx_rld_nctl_strong_s { + uint64_t reserved_5_63:59; + uint64_t nctl:5; + } s; + struct cvmx_asxx_rld_nctl_strong_s cn38xx; + struct cvmx_asxx_rld_nctl_strong_s cn38xxp2; + struct cvmx_asxx_rld_nctl_strong_s cn58xx; + struct cvmx_asxx_rld_nctl_strong_s cn58xxp1; +}; + +union cvmx_asxx_rld_nctl_weak { + uint64_t u64; + struct cvmx_asxx_rld_nctl_weak_s { + uint64_t reserved_5_63:59; + uint64_t nctl:5; + } s; + struct cvmx_asxx_rld_nctl_weak_s cn38xx; + struct cvmx_asxx_rld_nctl_weak_s cn38xxp2; + struct cvmx_asxx_rld_nctl_weak_s cn58xx; + struct cvmx_asxx_rld_nctl_weak_s cn58xxp1; +}; + +union cvmx_asxx_rld_pctl_strong { + uint64_t u64; + struct cvmx_asxx_rld_pctl_strong_s { + uint64_t reserved_5_63:59; + uint64_t pctl:5; + } s; + struct cvmx_asxx_rld_pctl_strong_s cn38xx; + struct cvmx_asxx_rld_pctl_strong_s cn38xxp2; + struct cvmx_asxx_rld_pctl_strong_s cn58xx; + struct cvmx_asxx_rld_pctl_strong_s cn58xxp1; +}; + +union cvmx_asxx_rld_pctl_weak { + uint64_t u64; + struct cvmx_asxx_rld_pctl_weak_s { + uint64_t reserved_5_63:59; + uint64_t pctl:5; + } s; + struct cvmx_asxx_rld_pctl_weak_s cn38xx; + struct cvmx_asxx_rld_pctl_weak_s cn38xxp2; + struct cvmx_asxx_rld_pctl_weak_s cn58xx; + struct cvmx_asxx_rld_pctl_weak_s cn58xxp1; +}; + +union cvmx_asxx_rld_setting { + uint64_t u64; + struct cvmx_asxx_rld_setting_s { + uint64_t reserved_13_63:51; + uint64_t dfaset:5; + uint64_t dfalag:1; + uint64_t dfalead:1; + uint64_t dfalock:1; + uint64_t setting:5; + } s; + struct cvmx_asxx_rld_setting_cn38xx { + uint64_t reserved_5_63:59; + uint64_t setting:5; + } cn38xx; + struct cvmx_asxx_rld_setting_cn38xx cn38xxp2; + struct cvmx_asxx_rld_setting_s cn58xx; + struct cvmx_asxx_rld_setting_s cn58xxp1; +}; + +union cvmx_asxx_rx_clk_setx { + uint64_t u64; + struct cvmx_asxx_rx_clk_setx_s { + uint64_t reserved_5_63:59; + uint64_t setting:5; + } s; + struct cvmx_asxx_rx_clk_setx_s cn30xx; + struct cvmx_asxx_rx_clk_setx_s cn31xx; + struct cvmx_asxx_rx_clk_setx_s cn38xx; + struct cvmx_asxx_rx_clk_setx_s cn38xxp2; + struct cvmx_asxx_rx_clk_setx_s cn50xx; + struct cvmx_asxx_rx_clk_setx_s cn58xx; + struct cvmx_asxx_rx_clk_setx_s cn58xxp1; +}; + +union cvmx_asxx_rx_prt_en { + uint64_t u64; + struct cvmx_asxx_rx_prt_en_s { + uint64_t reserved_4_63:60; + uint64_t prt_en:4; + } s; + struct cvmx_asxx_rx_prt_en_cn30xx { + uint64_t reserved_3_63:61; + uint64_t prt_en:3; + } cn30xx; + struct cvmx_asxx_rx_prt_en_cn30xx cn31xx; + struct cvmx_asxx_rx_prt_en_s cn38xx; + struct cvmx_asxx_rx_prt_en_s cn38xxp2; + struct cvmx_asxx_rx_prt_en_cn30xx cn50xx; + struct cvmx_asxx_rx_prt_en_s cn58xx; + struct cvmx_asxx_rx_prt_en_s cn58xxp1; +}; + +union cvmx_asxx_rx_wol { + uint64_t u64; + struct cvmx_asxx_rx_wol_s { + uint64_t reserved_2_63:62; + uint64_t status:1; + uint64_t enable:1; + } s; + struct cvmx_asxx_rx_wol_s cn38xx; + struct cvmx_asxx_rx_wol_s cn38xxp2; +}; + +union cvmx_asxx_rx_wol_msk { + uint64_t u64; + struct cvmx_asxx_rx_wol_msk_s { + uint64_t msk:64; + } s; + struct cvmx_asxx_rx_wol_msk_s cn38xx; + struct cvmx_asxx_rx_wol_msk_s cn38xxp2; +}; + +union cvmx_asxx_rx_wol_powok { + uint64_t u64; + struct cvmx_asxx_rx_wol_powok_s { + uint64_t reserved_1_63:63; + uint64_t powerok:1; + } s; + struct cvmx_asxx_rx_wol_powok_s cn38xx; + struct cvmx_asxx_rx_wol_powok_s cn38xxp2; +}; + +union cvmx_asxx_rx_wol_sig { + uint64_t u64; + struct cvmx_asxx_rx_wol_sig_s { + uint64_t reserved_32_63:32; + uint64_t sig:32; + } s; + struct cvmx_asxx_rx_wol_sig_s cn38xx; + struct cvmx_asxx_rx_wol_sig_s cn38xxp2; +}; + +union cvmx_asxx_tx_clk_setx { + uint64_t u64; + struct cvmx_asxx_tx_clk_setx_s { + uint64_t reserved_5_63:59; + uint64_t setting:5; + } s; + struct cvmx_asxx_tx_clk_setx_s cn30xx; + struct cvmx_asxx_tx_clk_setx_s cn31xx; + struct cvmx_asxx_tx_clk_setx_s cn38xx; + struct cvmx_asxx_tx_clk_setx_s cn38xxp2; + struct cvmx_asxx_tx_clk_setx_s cn50xx; + struct cvmx_asxx_tx_clk_setx_s cn58xx; + struct cvmx_asxx_tx_clk_setx_s cn58xxp1; +}; + +union cvmx_asxx_tx_comp_byp { + uint64_t u64; + struct cvmx_asxx_tx_comp_byp_s { + uint64_t reserved_0_63:64; + } s; + struct cvmx_asxx_tx_comp_byp_cn30xx { + uint64_t reserved_9_63:55; + uint64_t bypass:1; + uint64_t pctl:4; + uint64_t nctl:4; + } cn30xx; + struct cvmx_asxx_tx_comp_byp_cn30xx cn31xx; + struct cvmx_asxx_tx_comp_byp_cn38xx { + uint64_t reserved_8_63:56; + uint64_t pctl:4; + uint64_t nctl:4; + } cn38xx; + struct cvmx_asxx_tx_comp_byp_cn38xx cn38xxp2; + struct cvmx_asxx_tx_comp_byp_cn50xx { + uint64_t reserved_17_63:47; + uint64_t bypass:1; + uint64_t reserved_13_15:3; + uint64_t pctl:5; + uint64_t reserved_5_7:3; + uint64_t nctl:5; + } cn50xx; + struct cvmx_asxx_tx_comp_byp_cn58xx { + uint64_t reserved_13_63:51; + uint64_t pctl:5; + uint64_t reserved_5_7:3; + uint64_t nctl:5; + } cn58xx; + struct cvmx_asxx_tx_comp_byp_cn58xx cn58xxp1; +}; + +union cvmx_asxx_tx_hi_waterx { + uint64_t u64; + struct cvmx_asxx_tx_hi_waterx_s { + uint64_t reserved_4_63:60; + uint64_t mark:4; + } s; + struct cvmx_asxx_tx_hi_waterx_cn30xx { + uint64_t reserved_3_63:61; + uint64_t mark:3; + } cn30xx; + struct cvmx_asxx_tx_hi_waterx_cn30xx cn31xx; + struct cvmx_asxx_tx_hi_waterx_s cn38xx; + struct cvmx_asxx_tx_hi_waterx_s cn38xxp2; + struct cvmx_asxx_tx_hi_waterx_cn30xx cn50xx; + struct cvmx_asxx_tx_hi_waterx_s cn58xx; + struct cvmx_asxx_tx_hi_waterx_s cn58xxp1; +}; + +union cvmx_asxx_tx_prt_en { + uint64_t u64; + struct cvmx_asxx_tx_prt_en_s { + uint64_t reserved_4_63:60; + uint64_t prt_en:4; + } s; + struct cvmx_asxx_tx_prt_en_cn30xx { + uint64_t reserved_3_63:61; + uint64_t prt_en:3; + } cn30xx; + struct cvmx_asxx_tx_prt_en_cn30xx cn31xx; + struct cvmx_asxx_tx_prt_en_s cn38xx; + struct cvmx_asxx_tx_prt_en_s cn38xxp2; + struct cvmx_asxx_tx_prt_en_cn30xx cn50xx; + struct cvmx_asxx_tx_prt_en_s cn58xx; + struct cvmx_asxx_tx_prt_en_s cn58xxp1; +}; + +#endif diff --git a/drivers/staging/octeon/cvmx-cmd-queue.c b/drivers/staging/octeon/cvmx-cmd-queue.c new file mode 100644 index 000000000000..976227b01273 --- /dev/null +++ b/drivers/staging/octeon/cvmx-cmd-queue.c @@ -0,0 +1,306 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2008 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +/* + * Support functions for managing command queues used for + * various hardware blocks. + */ + +#include + +#include + +#include "cvmx-config.h" +#include "cvmx-fpa.h" +#include "cvmx-cmd-queue.h" + +#include +#include +#include "cvmx-pko-defs.h" + +/** + * This application uses this pointer to access the global queue + * state. It points to a bootmem named block. + */ +__cvmx_cmd_queue_all_state_t *__cvmx_cmd_queue_state_ptr; + +/** + * Initialize the Global queue state pointer. + * + * Returns CVMX_CMD_QUEUE_SUCCESS or a failure code + */ +static cvmx_cmd_queue_result_t __cvmx_cmd_queue_init_state_ptr(void) +{ + char *alloc_name = "cvmx_cmd_queues"; +#if defined(CONFIG_CAVIUM_RESERVE32) && CONFIG_CAVIUM_RESERVE32 + extern uint64_t octeon_reserve32_memory; +#endif + + if (likely(__cvmx_cmd_queue_state_ptr)) + return CVMX_CMD_QUEUE_SUCCESS; + +#if defined(CONFIG_CAVIUM_RESERVE32) && CONFIG_CAVIUM_RESERVE32 + if (octeon_reserve32_memory) + __cvmx_cmd_queue_state_ptr = + cvmx_bootmem_alloc_named_range(sizeof(*__cvmx_cmd_queue_state_ptr), + octeon_reserve32_memory, + octeon_reserve32_memory + + (CONFIG_CAVIUM_RESERVE32 << + 20) - 1, 128, alloc_name); + else +#endif + __cvmx_cmd_queue_state_ptr = + cvmx_bootmem_alloc_named(sizeof(*__cvmx_cmd_queue_state_ptr), + 128, + alloc_name); + if (__cvmx_cmd_queue_state_ptr) + memset(__cvmx_cmd_queue_state_ptr, 0, + sizeof(*__cvmx_cmd_queue_state_ptr)); + else { + struct cvmx_bootmem_named_block_desc *block_desc = + cvmx_bootmem_find_named_block(alloc_name); + if (block_desc) + __cvmx_cmd_queue_state_ptr = + cvmx_phys_to_ptr(block_desc->base_addr); + else { + cvmx_dprintf + ("ERROR: cvmx_cmd_queue_initialize: Unable to get named block %s.\n", + alloc_name); + return CVMX_CMD_QUEUE_NO_MEMORY; + } + } + return CVMX_CMD_QUEUE_SUCCESS; +} + +/** + * Initialize a command queue for use. The initial FPA buffer is + * allocated and the hardware unit is configured to point to the + * new command queue. + * + * @queue_id: Hardware command queue to initialize. + * @max_depth: Maximum outstanding commands that can be queued. + * @fpa_pool: FPA pool the command queues should come from. + * @pool_size: Size of each buffer in the FPA pool (bytes) + * + * Returns CVMX_CMD_QUEUE_SUCCESS or a failure code + */ +cvmx_cmd_queue_result_t cvmx_cmd_queue_initialize(cvmx_cmd_queue_id_t queue_id, + int max_depth, int fpa_pool, + int pool_size) +{ + __cvmx_cmd_queue_state_t *qstate; + cvmx_cmd_queue_result_t result = __cvmx_cmd_queue_init_state_ptr(); + if (result != CVMX_CMD_QUEUE_SUCCESS) + return result; + + qstate = __cvmx_cmd_queue_get_state(queue_id); + if (qstate == NULL) + return CVMX_CMD_QUEUE_INVALID_PARAM; + + /* + * We artificially limit max_depth to 1<<20 words. It is an + * arbitrary limit. + */ + if (CVMX_CMD_QUEUE_ENABLE_MAX_DEPTH) { + if ((max_depth < 0) || (max_depth > 1 << 20)) + return CVMX_CMD_QUEUE_INVALID_PARAM; + } else if (max_depth != 0) + return CVMX_CMD_QUEUE_INVALID_PARAM; + + if ((fpa_pool < 0) || (fpa_pool > 7)) + return CVMX_CMD_QUEUE_INVALID_PARAM; + if ((pool_size < 128) || (pool_size > 65536)) + return CVMX_CMD_QUEUE_INVALID_PARAM; + + /* See if someone else has already initialized the queue */ + if (qstate->base_ptr_div128) { + if (max_depth != (int)qstate->max_depth) { + cvmx_dprintf("ERROR: cvmx_cmd_queue_initialize: " + "Queue already initalized with different " + "max_depth (%d).\n", + (int)qstate->max_depth); + return CVMX_CMD_QUEUE_INVALID_PARAM; + } + if (fpa_pool != qstate->fpa_pool) { + cvmx_dprintf("ERROR: cvmx_cmd_queue_initialize: " + "Queue already initalized with different " + "FPA pool (%u).\n", + qstate->fpa_pool); + return CVMX_CMD_QUEUE_INVALID_PARAM; + } + if ((pool_size >> 3) - 1 != qstate->pool_size_m1) { + cvmx_dprintf("ERROR: cvmx_cmd_queue_initialize: " + "Queue already initalized with different " + "FPA pool size (%u).\n", + (qstate->pool_size_m1 + 1) << 3); + return CVMX_CMD_QUEUE_INVALID_PARAM; + } + CVMX_SYNCWS; + return CVMX_CMD_QUEUE_ALREADY_SETUP; + } else { + union cvmx_fpa_ctl_status status; + void *buffer; + + status.u64 = cvmx_read_csr(CVMX_FPA_CTL_STATUS); + if (!status.s.enb) { + cvmx_dprintf("ERROR: cvmx_cmd_queue_initialize: " + "FPA is not enabled.\n"); + return CVMX_CMD_QUEUE_NO_MEMORY; + } + buffer = cvmx_fpa_alloc(fpa_pool); + if (buffer == NULL) { + cvmx_dprintf("ERROR: cvmx_cmd_queue_initialize: " + "Unable to allocate initial buffer.\n"); + return CVMX_CMD_QUEUE_NO_MEMORY; + } + + memset(qstate, 0, sizeof(*qstate)); + qstate->max_depth = max_depth; + qstate->fpa_pool = fpa_pool; + qstate->pool_size_m1 = (pool_size >> 3) - 1; + qstate->base_ptr_div128 = cvmx_ptr_to_phys(buffer) / 128; + /* + * We zeroed the now serving field so we need to also + * zero the ticket. + */ + __cvmx_cmd_queue_state_ptr-> + ticket[__cvmx_cmd_queue_get_index(queue_id)] = 0; + CVMX_SYNCWS; + return CVMX_CMD_QUEUE_SUCCESS; + } +} + +/** + * Shutdown a queue a free it's command buffers to the FPA. The + * hardware connected to the queue must be stopped before this + * function is called. + * + * @queue_id: Queue to shutdown + * + * Returns CVMX_CMD_QUEUE_SUCCESS or a failure code + */ +cvmx_cmd_queue_result_t cvmx_cmd_queue_shutdown(cvmx_cmd_queue_id_t queue_id) +{ + __cvmx_cmd_queue_state_t *qptr = __cvmx_cmd_queue_get_state(queue_id); + if (qptr == NULL) { + cvmx_dprintf("ERROR: cvmx_cmd_queue_shutdown: Unable to " + "get queue information.\n"); + return CVMX_CMD_QUEUE_INVALID_PARAM; + } + + if (cvmx_cmd_queue_length(queue_id) > 0) { + cvmx_dprintf("ERROR: cvmx_cmd_queue_shutdown: Queue still " + "has data in it.\n"); + return CVMX_CMD_QUEUE_FULL; + } + + __cvmx_cmd_queue_lock(queue_id, qptr); + if (qptr->base_ptr_div128) { + cvmx_fpa_free(cvmx_phys_to_ptr + ((uint64_t) qptr->base_ptr_div128 << 7), + qptr->fpa_pool, 0); + qptr->base_ptr_div128 = 0; + } + __cvmx_cmd_queue_unlock(qptr); + + return CVMX_CMD_QUEUE_SUCCESS; +} + +/** + * Return the number of command words pending in the queue. This + * function may be relatively slow for some hardware units. + * + * @queue_id: Hardware command queue to query + * + * Returns Number of outstanding commands + */ +int cvmx_cmd_queue_length(cvmx_cmd_queue_id_t queue_id) +{ + if (CVMX_ENABLE_PARAMETER_CHECKING) { + if (__cvmx_cmd_queue_get_state(queue_id) == NULL) + return CVMX_CMD_QUEUE_INVALID_PARAM; + } + + /* + * The cast is here so gcc with check that all values in the + * cvmx_cmd_queue_id_t enumeration are here. + */ + switch ((cvmx_cmd_queue_id_t) (queue_id & 0xff0000)) { + case CVMX_CMD_QUEUE_PKO_BASE: + /* + * FIXME: Need atomic lock on + * CVMX_PKO_REG_READ_IDX. Right now we are normally + * called with the queue lock, so that is a SLIGHT + * amount of protection. + */ + cvmx_write_csr(CVMX_PKO_REG_READ_IDX, queue_id & 0xffff); + if (OCTEON_IS_MODEL(OCTEON_CN3XXX)) { + union cvmx_pko_mem_debug9 debug9; + debug9.u64 = cvmx_read_csr(CVMX_PKO_MEM_DEBUG9); + return debug9.cn38xx.doorbell; + } else { + union cvmx_pko_mem_debug8 debug8; + debug8.u64 = cvmx_read_csr(CVMX_PKO_MEM_DEBUG8); + return debug8.cn58xx.doorbell; + } + case CVMX_CMD_QUEUE_ZIP: + case CVMX_CMD_QUEUE_DFA: + case CVMX_CMD_QUEUE_RAID: + /* FIXME: Implement other lengths */ + return 0; + case CVMX_CMD_QUEUE_DMA_BASE: + { + union cvmx_npei_dmax_counts dmax_counts; + dmax_counts.u64 = + cvmx_read_csr(CVMX_PEXP_NPEI_DMAX_COUNTS + (queue_id & 0x7)); + return dmax_counts.s.dbell; + } + case CVMX_CMD_QUEUE_END: + return CVMX_CMD_QUEUE_INVALID_PARAM; + } + return CVMX_CMD_QUEUE_INVALID_PARAM; +} + +/** + * Return the command buffer to be written to. The purpose of this + * function is to allow CVMX routine access t othe low level buffer + * for initial hardware setup. User applications should not call this + * function directly. + * + * @queue_id: Command queue to query + * + * Returns Command buffer or NULL on failure + */ +void *cvmx_cmd_queue_buffer(cvmx_cmd_queue_id_t queue_id) +{ + __cvmx_cmd_queue_state_t *qptr = __cvmx_cmd_queue_get_state(queue_id); + if (qptr && qptr->base_ptr_div128) + return cvmx_phys_to_ptr((uint64_t) qptr->base_ptr_div128 << 7); + else + return NULL; +} diff --git a/drivers/staging/octeon/cvmx-cmd-queue.h b/drivers/staging/octeon/cvmx-cmd-queue.h new file mode 100644 index 000000000000..f0cb20ffa39a --- /dev/null +++ b/drivers/staging/octeon/cvmx-cmd-queue.h @@ -0,0 +1,617 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2008 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +/* + * + * Support functions for managing command queues used for + * various hardware blocks. + * + * The common command queue infrastructure abstracts out the + * software necessary for adding to Octeon's chained queue + * structures. These structures are used for commands to the + * PKO, ZIP, DFA, RAID, and DMA engine blocks. Although each + * hardware unit takes commands and CSRs of different types, + * they all use basic linked command buffers to store the + * pending request. In general, users of the CVMX API don't + * call cvmx-cmd-queue functions directly. Instead the hardware + * unit specific wrapper should be used. The wrappers perform + * unit specific validation and CSR writes to submit the + * commands. + * + * Even though most software will never directly interact with + * cvmx-cmd-queue, knowledge of its internal working can help + * in diagnosing performance problems and help with debugging. + * + * Command queue pointers are stored in a global named block + * called "cvmx_cmd_queues". Except for the PKO queues, each + * hardware queue is stored in its own cache line to reduce SMP + * contention on spin locks. The PKO queues are stored such that + * every 16th queue is next to each other in memory. This scheme + * allows for queues being in separate cache lines when there + * are low number of queues per port. With 16 queues per port, + * the first queue for each port is in the same cache area. The + * second queues for each port are in another area, etc. This + * allows software to implement very efficient lockless PKO with + * 16 queues per port using a minimum of cache lines per core. + * All queues for a given core will be isolated in the same + * cache area. + * + * In addition to the memory pointer layout, cvmx-cmd-queue + * provides an optimized fair ll/sc locking mechanism for the + * queues. The lock uses a "ticket / now serving" model to + * maintain fair order on contended locks. In addition, it uses + * predicted locking time to limit cache contention. When a core + * know it must wait in line for a lock, it spins on the + * internal cycle counter to completely eliminate any causes of + * bus traffic. + * + */ + +#ifndef __CVMX_CMD_QUEUE_H__ +#define __CVMX_CMD_QUEUE_H__ + +#include + +#include "cvmx-fpa.h" +/** + * By default we disable the max depth support. Most programs + * don't use it and it slows down the command queue processing + * significantly. + */ +#ifndef CVMX_CMD_QUEUE_ENABLE_MAX_DEPTH +#define CVMX_CMD_QUEUE_ENABLE_MAX_DEPTH 0 +#endif + +/** + * Enumeration representing all hardware blocks that use command + * queues. Each hardware block has up to 65536 sub identifiers for + * multiple command queues. Not all chips support all hardware + * units. + */ +typedef enum { + CVMX_CMD_QUEUE_PKO_BASE = 0x00000, + +#define CVMX_CMD_QUEUE_PKO(queue) \ + ((cvmx_cmd_queue_id_t)(CVMX_CMD_QUEUE_PKO_BASE + (0xffff&(queue)))) + + CVMX_CMD_QUEUE_ZIP = 0x10000, + CVMX_CMD_QUEUE_DFA = 0x20000, + CVMX_CMD_QUEUE_RAID = 0x30000, + CVMX_CMD_QUEUE_DMA_BASE = 0x40000, + +#define CVMX_CMD_QUEUE_DMA(queue) \ + ((cvmx_cmd_queue_id_t)(CVMX_CMD_QUEUE_DMA_BASE + (0xffff&(queue)))) + + CVMX_CMD_QUEUE_END = 0x50000, +} cvmx_cmd_queue_id_t; + +/** + * Command write operations can fail if the comamnd queue needs + * a new buffer and the associated FPA pool is empty. It can also + * fail if the number of queued command words reaches the maximum + * set at initialization. + */ +typedef enum { + CVMX_CMD_QUEUE_SUCCESS = 0, + CVMX_CMD_QUEUE_NO_MEMORY = -1, + CVMX_CMD_QUEUE_FULL = -2, + CVMX_CMD_QUEUE_INVALID_PARAM = -3, + CVMX_CMD_QUEUE_ALREADY_SETUP = -4, +} cvmx_cmd_queue_result_t; + +typedef struct { + /* You have lock when this is your ticket */ + uint8_t now_serving; + uint64_t unused1:24; + /* Maximum outstanding command words */ + uint32_t max_depth; + /* FPA pool buffers come from */ + uint64_t fpa_pool:3; + /* Top of command buffer pointer shifted 7 */ + uint64_t base_ptr_div128:29; + uint64_t unused2:6; + /* FPA buffer size in 64bit words minus 1 */ + uint64_t pool_size_m1:13; + /* Number of comamnds already used in buffer */ + uint64_t index:13; +} __cvmx_cmd_queue_state_t; + +/** + * This structure contains the global state of all comamnd queues. + * It is stored in a bootmem named block and shared by all + * applications running on Octeon. Tickets are stored in a differnet + * cahce line that queue information to reduce the contention on the + * ll/sc used to get a ticket. If this is not the case, the update + * of queue state causes the ll/sc to fail quite often. + */ +typedef struct { + uint64_t ticket[(CVMX_CMD_QUEUE_END >> 16) * 256]; + __cvmx_cmd_queue_state_t state[(CVMX_CMD_QUEUE_END >> 16) * 256]; +} __cvmx_cmd_queue_all_state_t; + +/** + * Initialize a command queue for use. The initial FPA buffer is + * allocated and the hardware unit is configured to point to the + * new command queue. + * + * @queue_id: Hardware command queue to initialize. + * @max_depth: Maximum outstanding commands that can be queued. + * @fpa_pool: FPA pool the command queues should come from. + * @pool_size: Size of each buffer in the FPA pool (bytes) + * + * Returns CVMX_CMD_QUEUE_SUCCESS or a failure code + */ +cvmx_cmd_queue_result_t cvmx_cmd_queue_initialize(cvmx_cmd_queue_id_t queue_id, + int max_depth, int fpa_pool, + int pool_size); + +/** + * Shutdown a queue a free it's command buffers to the FPA. The + * hardware connected to the queue must be stopped before this + * function is called. + * + * @queue_id: Queue to shutdown + * + * Returns CVMX_CMD_QUEUE_SUCCESS or a failure code + */ +cvmx_cmd_queue_result_t cvmx_cmd_queue_shutdown(cvmx_cmd_queue_id_t queue_id); + +/** + * Return the number of command words pending in the queue. This + * function may be relatively slow for some hardware units. + * + * @queue_id: Hardware command queue to query + * + * Returns Number of outstanding commands + */ +int cvmx_cmd_queue_length(cvmx_cmd_queue_id_t queue_id); + +/** + * Return the command buffer to be written to. The purpose of this + * function is to allow CVMX routine access t othe low level buffer + * for initial hardware setup. User applications should not call this + * function directly. + * + * @queue_id: Command queue to query + * + * Returns Command buffer or NULL on failure + */ +void *cvmx_cmd_queue_buffer(cvmx_cmd_queue_id_t queue_id); + +/** + * Get the index into the state arrays for the supplied queue id. + * + * @queue_id: Queue ID to get an index for + * + * Returns Index into the state arrays + */ +static inline int __cvmx_cmd_queue_get_index(cvmx_cmd_queue_id_t queue_id) +{ + /* + * Warning: This code currently only works with devices that + * have 256 queues or less. Devices with more than 16 queues + * are layed out in memory to allow cores quick access to + * every 16th queue. This reduces cache thrashing when you are + * running 16 queues per port to support lockless operation. + */ + int unit = queue_id >> 16; + int q = (queue_id >> 4) & 0xf; + int core = queue_id & 0xf; + return unit * 256 + core * 16 + q; +} + +/** + * Lock the supplied queue so nobody else is updating it at the same + * time as us. + * + * @queue_id: Queue ID to lock + * @qptr: Pointer to the queue's global state + */ +static inline void __cvmx_cmd_queue_lock(cvmx_cmd_queue_id_t queue_id, + __cvmx_cmd_queue_state_t *qptr) +{ + extern __cvmx_cmd_queue_all_state_t + *__cvmx_cmd_queue_state_ptr; + int tmp; + int my_ticket; + prefetch(qptr); + asm volatile ( + ".set push\n" + ".set noreorder\n" + "1:\n" + /* Atomic add one to ticket_ptr */ + "ll %[my_ticket], %[ticket_ptr]\n" + /* and store the original value */ + "li %[ticket], 1\n" + /* in my_ticket */ + "baddu %[ticket], %[my_ticket]\n" + "sc %[ticket], %[ticket_ptr]\n" + "beqz %[ticket], 1b\n" + " nop\n" + /* Load the current now_serving ticket */ + "lbu %[ticket], %[now_serving]\n" + "2:\n" + /* Jump out if now_serving == my_ticket */ + "beq %[ticket], %[my_ticket], 4f\n" + /* Find out how many tickets are in front of me */ + " subu %[ticket], %[my_ticket], %[ticket]\n" + /* Use tickets in front of me minus one to delay */ + "subu %[ticket], 1\n" + /* Delay will be ((tickets in front)-1)*32 loops */ + "cins %[ticket], %[ticket], 5, 7\n" + "3:\n" + /* Loop here until our ticket might be up */ + "bnez %[ticket], 3b\n" + " subu %[ticket], 1\n" + /* Jump back up to check out ticket again */ + "b 2b\n" + /* Load the current now_serving ticket */ + " lbu %[ticket], %[now_serving]\n" + "4:\n" + ".set pop\n" : + [ticket_ptr] "=m"(__cvmx_cmd_queue_state_ptr->ticket[__cvmx_cmd_queue_get_index(queue_id)]), + [now_serving] "=m"(qptr->now_serving), [ticket] "=r"(tmp), + [my_ticket] "=r"(my_ticket) + ); +} + +/** + * Unlock the queue, flushing all writes. + * + * @qptr: Queue to unlock + */ +static inline void __cvmx_cmd_queue_unlock(__cvmx_cmd_queue_state_t *qptr) +{ + qptr->now_serving++; + CVMX_SYNCWS; +} + +/** + * Get the queue state structure for the given queue id + * + * @queue_id: Queue id to get + * + * Returns Queue structure or NULL on failure + */ +static inline __cvmx_cmd_queue_state_t + *__cvmx_cmd_queue_get_state(cvmx_cmd_queue_id_t queue_id) +{ + extern __cvmx_cmd_queue_all_state_t + *__cvmx_cmd_queue_state_ptr; + return &__cvmx_cmd_queue_state_ptr-> + state[__cvmx_cmd_queue_get_index(queue_id)]; +} + +/** + * Write an arbitrary number of command words to a command queue. + * This is a generic function; the fixed number of comamnd word + * functions yield higher performance. + * + * @queue_id: Hardware command queue to write to + * @use_locking: + * Use internal locking to ensure exclusive access for queue + * updates. If you don't use this locking you must ensure + * exclusivity some other way. Locking is strongly recommended. + * @cmd_count: Number of command words to write + * @cmds: Array of comamnds to write + * + * Returns CVMX_CMD_QUEUE_SUCCESS or a failure code + */ +static inline cvmx_cmd_queue_result_t cvmx_cmd_queue_write(cvmx_cmd_queue_id_t + queue_id, + int use_locking, + int cmd_count, + uint64_t *cmds) +{ + __cvmx_cmd_queue_state_t *qptr = __cvmx_cmd_queue_get_state(queue_id); + + /* Make sure nobody else is updating the same queue */ + if (likely(use_locking)) + __cvmx_cmd_queue_lock(queue_id, qptr); + + /* + * If a max queue length was specified then make sure we don't + * exceed it. If any part of the command would be below the + * limit we allow it. + */ + if (CVMX_CMD_QUEUE_ENABLE_MAX_DEPTH && unlikely(qptr->max_depth)) { + if (unlikely + (cvmx_cmd_queue_length(queue_id) > (int)qptr->max_depth)) { + if (likely(use_locking)) + __cvmx_cmd_queue_unlock(qptr); + return CVMX_CMD_QUEUE_FULL; + } + } + + /* + * Normally there is plenty of room in the current buffer for + * the command. + */ + if (likely(qptr->index + cmd_count < qptr->pool_size_m1)) { + uint64_t *ptr = + (uint64_t *) cvmx_phys_to_ptr((uint64_t) qptr-> + base_ptr_div128 << 7); + ptr += qptr->index; + qptr->index += cmd_count; + while (cmd_count--) + *ptr++ = *cmds++; + } else { + uint64_t *ptr; + int count; + /* + * We need a new comamnd buffer. Fail if there isn't + * one available. + */ + uint64_t *new_buffer = + (uint64_t *) cvmx_fpa_alloc(qptr->fpa_pool); + if (unlikely(new_buffer == NULL)) { + if (likely(use_locking)) + __cvmx_cmd_queue_unlock(qptr); + return CVMX_CMD_QUEUE_NO_MEMORY; + } + ptr = + (uint64_t *) cvmx_phys_to_ptr((uint64_t) qptr-> + base_ptr_div128 << 7); + /* + * Figure out how many command words will fit in this + * buffer. One location will be needed for the next + * buffer pointer. + */ + count = qptr->pool_size_m1 - qptr->index; + ptr += qptr->index; + cmd_count -= count; + while (count--) + *ptr++ = *cmds++; + *ptr = cvmx_ptr_to_phys(new_buffer); + /* + * The current buffer is full and has a link to the + * next buffer. Time to write the rest of the commands + * into the new buffer. + */ + qptr->base_ptr_div128 = *ptr >> 7; + qptr->index = cmd_count; + ptr = new_buffer; + while (cmd_count--) + *ptr++ = *cmds++; + } + + /* All updates are complete. Release the lock and return */ + if (likely(use_locking)) + __cvmx_cmd_queue_unlock(qptr); + return CVMX_CMD_QUEUE_SUCCESS; +} + +/** + * Simple function to write two command words to a command + * queue. + * + * @queue_id: Hardware command queue to write to + * @use_locking: + * Use internal locking to ensure exclusive access for queue + * updates. If you don't use this locking you must ensure + * exclusivity some other way. Locking is strongly recommended. + * @cmd1: Command + * @cmd2: Command + * + * Returns CVMX_CMD_QUEUE_SUCCESS or a failure code + */ +static inline cvmx_cmd_queue_result_t cvmx_cmd_queue_write2(cvmx_cmd_queue_id_t + queue_id, + int use_locking, + uint64_t cmd1, + uint64_t cmd2) +{ + __cvmx_cmd_queue_state_t *qptr = __cvmx_cmd_queue_get_state(queue_id); + + /* Make sure nobody else is updating the same queue */ + if (likely(use_locking)) + __cvmx_cmd_queue_lock(queue_id, qptr); + + /* + * If a max queue length was specified then make sure we don't + * exceed it. If any part of the command would be below the + * limit we allow it. + */ + if (CVMX_CMD_QUEUE_ENABLE_MAX_DEPTH && unlikely(qptr->max_depth)) { + if (unlikely + (cvmx_cmd_queue_length(queue_id) > (int)qptr->max_depth)) { + if (likely(use_locking)) + __cvmx_cmd_queue_unlock(qptr); + return CVMX_CMD_QUEUE_FULL; + } + } + + /* + * Normally there is plenty of room in the current buffer for + * the command. + */ + if (likely(qptr->index + 2 < qptr->pool_size_m1)) { + uint64_t *ptr = + (uint64_t *) cvmx_phys_to_ptr((uint64_t) qptr-> + base_ptr_div128 << 7); + ptr += qptr->index; + qptr->index += 2; + ptr[0] = cmd1; + ptr[1] = cmd2; + } else { + uint64_t *ptr; + /* + * Figure out how many command words will fit in this + * buffer. One location will be needed for the next + * buffer pointer. + */ + int count = qptr->pool_size_m1 - qptr->index; + /* + * We need a new comamnd buffer. Fail if there isn't + * one available. + */ + uint64_t *new_buffer = + (uint64_t *) cvmx_fpa_alloc(qptr->fpa_pool); + if (unlikely(new_buffer == NULL)) { + if (likely(use_locking)) + __cvmx_cmd_queue_unlock(qptr); + return CVMX_CMD_QUEUE_NO_MEMORY; + } + count--; + ptr = + (uint64_t *) cvmx_phys_to_ptr((uint64_t) qptr-> + base_ptr_div128 << 7); + ptr += qptr->index; + *ptr++ = cmd1; + if (likely(count)) + *ptr++ = cmd2; + *ptr = cvmx_ptr_to_phys(new_buffer); + /* + * The current buffer is full and has a link to the + * next buffer. Time to write the rest of the commands + * into the new buffer. + */ + qptr->base_ptr_div128 = *ptr >> 7; + qptr->index = 0; + if (unlikely(count == 0)) { + qptr->index = 1; + new_buffer[0] = cmd2; + } + } + + /* All updates are complete. Release the lock and return */ + if (likely(use_locking)) + __cvmx_cmd_queue_unlock(qptr); + return CVMX_CMD_QUEUE_SUCCESS; +} + +/** + * Simple function to write three command words to a command + * queue. + * + * @queue_id: Hardware command queue to write to + * @use_locking: + * Use internal locking to ensure exclusive access for queue + * updates. If you don't use this locking you must ensure + * exclusivity some other way. Locking is strongly recommended. + * @cmd1: Command + * @cmd2: Command + * @cmd3: Command + * + * Returns CVMX_CMD_QUEUE_SUCCESS or a failure code + */ +static inline cvmx_cmd_queue_result_t cvmx_cmd_queue_write3(cvmx_cmd_queue_id_t + queue_id, + int use_locking, + uint64_t cmd1, + uint64_t cmd2, + uint64_t cmd3) +{ + __cvmx_cmd_queue_state_t *qptr = __cvmx_cmd_queue_get_state(queue_id); + + /* Make sure nobody else is updating the same queue */ + if (likely(use_locking)) + __cvmx_cmd_queue_lock(queue_id, qptr); + + /* + * If a max queue length was specified then make sure we don't + * exceed it. If any part of the command would be below the + * limit we allow it. + */ + if (CVMX_CMD_QUEUE_ENABLE_MAX_DEPTH && unlikely(qptr->max_depth)) { + if (unlikely + (cvmx_cmd_queue_length(queue_id) > (int)qptr->max_depth)) { + if (likely(use_locking)) + __cvmx_cmd_queue_unlock(qptr); + return CVMX_CMD_QUEUE_FULL; + } + } + + /* + * Normally there is plenty of room in the current buffer for + * the command. + */ + if (likely(qptr->index + 3 < qptr->pool_size_m1)) { + uint64_t *ptr = + (uint64_t *) cvmx_phys_to_ptr((uint64_t) qptr-> + base_ptr_div128 << 7); + ptr += qptr->index; + qptr->index += 3; + ptr[0] = cmd1; + ptr[1] = cmd2; + ptr[2] = cmd3; + } else { + uint64_t *ptr; + /* + * Figure out how many command words will fit in this + * buffer. One location will be needed for the next + * buffer pointer + */ + int count = qptr->pool_size_m1 - qptr->index; + /* + * We need a new comamnd buffer. Fail if there isn't + * one available + */ + uint64_t *new_buffer = + (uint64_t *) cvmx_fpa_alloc(qptr->fpa_pool); + if (unlikely(new_buffer == NULL)) { + if (likely(use_locking)) + __cvmx_cmd_queue_unlock(qptr); + return CVMX_CMD_QUEUE_NO_MEMORY; + } + count--; + ptr = + (uint64_t *) cvmx_phys_to_ptr((uint64_t) qptr-> + base_ptr_div128 << 7); + ptr += qptr->index; + *ptr++ = cmd1; + if (count) { + *ptr++ = cmd2; + if (count > 1) + *ptr++ = cmd3; + } + *ptr = cvmx_ptr_to_phys(new_buffer); + /* + * The current buffer is full and has a link to the + * next buffer. Time to write the rest of the commands + * into the new buffer. + */ + qptr->base_ptr_div128 = *ptr >> 7; + qptr->index = 0; + ptr = new_buffer; + if (count == 0) { + *ptr++ = cmd2; + qptr->index++; + } + if (count < 2) { + *ptr++ = cmd3; + qptr->index++; + } + } + + /* All updates are complete. Release the lock and return */ + if (likely(use_locking)) + __cvmx_cmd_queue_unlock(qptr); + return CVMX_CMD_QUEUE_SUCCESS; +} + +#endif /* __CVMX_CMD_QUEUE_H__ */ diff --git a/drivers/staging/octeon/cvmx-config.h b/drivers/staging/octeon/cvmx-config.h new file mode 100644 index 000000000000..078a520481cf --- /dev/null +++ b/drivers/staging/octeon/cvmx-config.h @@ -0,0 +1,169 @@ +#ifndef __CVMX_CONFIG_H__ +#define __CVMX_CONFIG_H__ + +/************************* Config Specific Defines ************************/ +#define CVMX_LLM_NUM_PORTS 1 +#define CVMX_NULL_POINTER_PROTECT 1 +#define CVMX_ENABLE_DEBUG_PRINTS 1 +/* PKO queues per port for interface 0 (ports 0-15) */ +#define CVMX_PKO_QUEUES_PER_PORT_INTERFACE0 1 +/* PKO queues per port for interface 1 (ports 16-31) */ +#define CVMX_PKO_QUEUES_PER_PORT_INTERFACE1 1 +/* Limit on the number of PKO ports enabled for interface 0 */ +#define CVMX_PKO_MAX_PORTS_INTERFACE0 CVMX_HELPER_PKO_MAX_PORTS_INTERFACE0 +/* Limit on the number of PKO ports enabled for interface 1 */ +#define CVMX_PKO_MAX_PORTS_INTERFACE1 CVMX_HELPER_PKO_MAX_PORTS_INTERFACE1 +/* PKO queues per port for PCI (ports 32-35) */ +#define CVMX_PKO_QUEUES_PER_PORT_PCI 1 +/* PKO queues per port for Loop devices (ports 36-39) */ +#define CVMX_PKO_QUEUES_PER_PORT_LOOP 1 + +/************************* FPA allocation *********************************/ +/* Pool sizes in bytes, must be multiple of a cache line */ +#define CVMX_FPA_POOL_0_SIZE (16 * CVMX_CACHE_LINE_SIZE) +#define CVMX_FPA_POOL_1_SIZE (1 * CVMX_CACHE_LINE_SIZE) +#define CVMX_FPA_POOL_2_SIZE (8 * CVMX_CACHE_LINE_SIZE) +#define CVMX_FPA_POOL_3_SIZE (0 * CVMX_CACHE_LINE_SIZE) +#define CVMX_FPA_POOL_4_SIZE (0 * CVMX_CACHE_LINE_SIZE) +#define CVMX_FPA_POOL_5_SIZE (0 * CVMX_CACHE_LINE_SIZE) +#define CVMX_FPA_POOL_6_SIZE (0 * CVMX_CACHE_LINE_SIZE) +#define CVMX_FPA_POOL_7_SIZE (0 * CVMX_CACHE_LINE_SIZE) + +/* Pools in use */ +/* Packet buffers */ +#define CVMX_FPA_PACKET_POOL (0) +#define CVMX_FPA_PACKET_POOL_SIZE CVMX_FPA_POOL_0_SIZE +/* Work queue entrys */ +#define CVMX_FPA_WQE_POOL (1) +#define CVMX_FPA_WQE_POOL_SIZE CVMX_FPA_POOL_1_SIZE +/* PKO queue command buffers */ +#define CVMX_FPA_OUTPUT_BUFFER_POOL (2) +#define CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE CVMX_FPA_POOL_2_SIZE + +/************************* FAU allocation ********************************/ +/* The fetch and add registers are allocated here. They are arranged + * in order of descending size so that all alignment constraints are + * automatically met. The enums are linked so that the following enum + * continues allocating where the previous one left off, so the + * numbering within each enum always starts with zero. The macros + * take care of the address increment size, so the values entered + * always increase by 1. FAU registers are accessed with byte + * addresses. + */ + +#define CVMX_FAU_REG_64_ADDR(x) ((x << 3) + CVMX_FAU_REG_64_START) +typedef enum { + CVMX_FAU_REG_64_START = 0, + CVMX_FAU_REG_64_END = CVMX_FAU_REG_64_ADDR(0), +} cvmx_fau_reg_64_t; + +#define CVMX_FAU_REG_32_ADDR(x) ((x << 2) + CVMX_FAU_REG_32_START) +typedef enum { + CVMX_FAU_REG_32_START = CVMX_FAU_REG_64_END, + CVMX_FAU_REG_32_END = CVMX_FAU_REG_32_ADDR(0), +} cvmx_fau_reg_32_t; + +#define CVMX_FAU_REG_16_ADDR(x) ((x << 1) + CVMX_FAU_REG_16_START) +typedef enum { + CVMX_FAU_REG_16_START = CVMX_FAU_REG_32_END, + CVMX_FAU_REG_16_END = CVMX_FAU_REG_16_ADDR(0), +} cvmx_fau_reg_16_t; + +#define CVMX_FAU_REG_8_ADDR(x) ((x) + CVMX_FAU_REG_8_START) +typedef enum { + CVMX_FAU_REG_8_START = CVMX_FAU_REG_16_END, + CVMX_FAU_REG_8_END = CVMX_FAU_REG_8_ADDR(0), +} cvmx_fau_reg_8_t; + +/* + * The name CVMX_FAU_REG_AVAIL_BASE is provided to indicate the first + * available FAU address that is not allocated in cvmx-config.h. This + * is 64 bit aligned. + */ +#define CVMX_FAU_REG_AVAIL_BASE ((CVMX_FAU_REG_8_END + 0x7) & (~0x7ULL)) +#define CVMX_FAU_REG_END (2048) + +/********************** scratch memory allocation *************************/ +/* Scratchpad memory allocation. Note that these are byte memory + * addresses. Some uses of scratchpad (IOBDMA for example) require + * the use of 8-byte aligned addresses, so proper alignment needs to + * be taken into account. + */ +/* Generic scratch iobdma area */ +#define CVMX_SCR_SCRATCH (0) +/* First location available after cvmx-config.h allocated region. */ +#define CVMX_SCR_REG_AVAIL_BASE (8) + +/* + * CVMX_HELPER_FIRST_MBUFF_SKIP is the number of bytes to reserve + * before the beginning of the packet. If necessary, override the + * default here. See the IPD section of the hardware manual for MBUFF + * SKIP details. + */ +#define CVMX_HELPER_FIRST_MBUFF_SKIP 184 + +/* + * CVMX_HELPER_NOT_FIRST_MBUFF_SKIP is the number of bytes to reserve + * in each chained packet element. If necessary, override the default + * here. + */ +#define CVMX_HELPER_NOT_FIRST_MBUFF_SKIP 0 + +/* + * CVMX_HELPER_ENABLE_BACK_PRESSURE controls whether back pressure is + * enabled for all input ports. This controls if IPD sends + * backpressure to all ports if Octeon's FPA pools don't have enough + * packet or work queue entries. Even when this is off, it is still + * possible to get backpressure from individual hardware ports. When + * configuring backpressure, also check + * CVMX_HELPER_DISABLE_*_BACKPRESSURE below. If necessary, override + * the default here. + */ +#define CVMX_HELPER_ENABLE_BACK_PRESSURE 1 + +/* + * CVMX_HELPER_ENABLE_IPD controls if the IPD is enabled in the helper + * function. Once it is enabled the hardware starts accepting + * packets. You might want to skip the IPD enable if configuration + * changes are need from the default helper setup. If necessary, + * override the default here. + */ +#define CVMX_HELPER_ENABLE_IPD 0 + +/* + * CVMX_HELPER_INPUT_TAG_TYPE selects the type of tag that the IPD assigns + * to incoming packets. + */ +#define CVMX_HELPER_INPUT_TAG_TYPE CVMX_POW_TAG_TYPE_ORDERED + +#define CVMX_ENABLE_PARAMETER_CHECKING 0 + +/* + * The following select which fields are used by the PIP to generate + * the tag on INPUT + * 0: don't include + * 1: include + */ +#define CVMX_HELPER_INPUT_TAG_IPV6_SRC_IP 0 +#define CVMX_HELPER_INPUT_TAG_IPV6_DST_IP 0 +#define CVMX_HELPER_INPUT_TAG_IPV6_SRC_PORT 0 +#define CVMX_HELPER_INPUT_TAG_IPV6_DST_PORT 0 +#define CVMX_HELPER_INPUT_TAG_IPV6_NEXT_HEADER 0 +#define CVMX_HELPER_INPUT_TAG_IPV4_SRC_IP 0 +#define CVMX_HELPER_INPUT_TAG_IPV4_DST_IP 0 +#define CVMX_HELPER_INPUT_TAG_IPV4_SRC_PORT 0 +#define CVMX_HELPER_INPUT_TAG_IPV4_DST_PORT 0 +#define CVMX_HELPER_INPUT_TAG_IPV4_PROTOCOL 0 +#define CVMX_HELPER_INPUT_TAG_INPUT_PORT 1 + +/* Select skip mode for input ports */ +#define CVMX_HELPER_INPUT_PORT_SKIP_MODE CVMX_PIP_PORT_CFG_MODE_SKIPL2 + +/* + * Force backpressure to be disabled. This overrides all other + * backpressure configuration. + */ +#define CVMX_HELPER_DISABLE_RGMII_BACKPRESSURE 0 + +#endif /* __CVMX_CONFIG_H__ */ + diff --git a/drivers/staging/octeon/cvmx-dbg-defs.h b/drivers/staging/octeon/cvmx-dbg-defs.h new file mode 100644 index 000000000000..abbf42d05e5a --- /dev/null +++ b/drivers/staging/octeon/cvmx-dbg-defs.h @@ -0,0 +1,72 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2008 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +#ifndef __CVMX_DBG_DEFS_H__ +#define __CVMX_DBG_DEFS_H__ + +#define CVMX_DBG_DATA \ + CVMX_ADD_IO_SEG(0x00011F00000001E8ull) + +union cvmx_dbg_data { + uint64_t u64; + struct cvmx_dbg_data_s { + uint64_t reserved_23_63:41; + uint64_t c_mul:5; + uint64_t dsel_ext:1; + uint64_t data:17; + } s; + struct cvmx_dbg_data_cn30xx { + uint64_t reserved_31_63:33; + uint64_t pll_mul:3; + uint64_t reserved_23_27:5; + uint64_t c_mul:5; + uint64_t dsel_ext:1; + uint64_t data:17; + } cn30xx; + struct cvmx_dbg_data_cn30xx cn31xx; + struct cvmx_dbg_data_cn38xx { + uint64_t reserved_29_63:35; + uint64_t d_mul:4; + uint64_t dclk_mul2:1; + uint64_t cclk_div2:1; + uint64_t c_mul:5; + uint64_t dsel_ext:1; + uint64_t data:17; + } cn38xx; + struct cvmx_dbg_data_cn38xx cn38xxp2; + struct cvmx_dbg_data_cn30xx cn50xx; + struct cvmx_dbg_data_cn58xx { + uint64_t reserved_29_63:35; + uint64_t rem:6; + uint64_t c_mul:5; + uint64_t dsel_ext:1; + uint64_t data:17; + } cn58xx; + struct cvmx_dbg_data_cn58xx cn58xxp1; +}; + +#endif diff --git a/drivers/staging/octeon/cvmx-fau.h b/drivers/staging/octeon/cvmx-fau.h new file mode 100644 index 000000000000..29bdce66cdf8 --- /dev/null +++ b/drivers/staging/octeon/cvmx-fau.h @@ -0,0 +1,597 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2008 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +/* + * Interface to the hardware Fetch and Add Unit. + */ + +#ifndef __CVMX_FAU_H__ +#define __CVMX_FAU_H__ + +/* + * Octeon Fetch and Add Unit (FAU) + */ + +#define CVMX_FAU_LOAD_IO_ADDRESS cvmx_build_io_address(0x1e, 0) +#define CVMX_FAU_BITS_SCRADDR 63, 56 +#define CVMX_FAU_BITS_LEN 55, 48 +#define CVMX_FAU_BITS_INEVAL 35, 14 +#define CVMX_FAU_BITS_TAGWAIT 13, 13 +#define CVMX_FAU_BITS_NOADD 13, 13 +#define CVMX_FAU_BITS_SIZE 12, 11 +#define CVMX_FAU_BITS_REGISTER 10, 0 + +typedef enum { + CVMX_FAU_OP_SIZE_8 = 0, + CVMX_FAU_OP_SIZE_16 = 1, + CVMX_FAU_OP_SIZE_32 = 2, + CVMX_FAU_OP_SIZE_64 = 3 +} cvmx_fau_op_size_t; + +/** + * Tagwait return definition. If a timeout occurs, the error + * bit will be set. Otherwise the value of the register before + * the update will be returned. + */ +typedef struct { + uint64_t error:1; + int64_t value:63; +} cvmx_fau_tagwait64_t; + +/** + * Tagwait return definition. If a timeout occurs, the error + * bit will be set. Otherwise the value of the register before + * the update will be returned. + */ +typedef struct { + uint64_t error:1; + int32_t value:31; +} cvmx_fau_tagwait32_t; + +/** + * Tagwait return definition. If a timeout occurs, the error + * bit will be set. Otherwise the value of the register before + * the update will be returned. + */ +typedef struct { + uint64_t error:1; + int16_t value:15; +} cvmx_fau_tagwait16_t; + +/** + * Tagwait return definition. If a timeout occurs, the error + * bit will be set. Otherwise the value of the register before + * the update will be returned. + */ +typedef struct { + uint64_t error:1; + int8_t value:7; +} cvmx_fau_tagwait8_t; + +/** + * Asynchronous tagwait return definition. If a timeout occurs, + * the error bit will be set. Otherwise the value of the + * register before the update will be returned. + */ +typedef union { + uint64_t u64; + struct { + uint64_t invalid:1; + uint64_t data:63; /* unpredictable if invalid is set */ + } s; +} cvmx_fau_async_tagwait_result_t; + +/** + * Builds a store I/O address for writing to the FAU + * + * @noadd: 0 = Store value is atomically added to the current value + * 1 = Store value is atomically written over the current value + * @reg: FAU atomic register to access. 0 <= reg < 2048. + * - Step by 2 for 16 bit access. + * - Step by 4 for 32 bit access. + * - Step by 8 for 64 bit access. + * Returns Address to store for atomic update + */ +static inline uint64_t __cvmx_fau_store_address(uint64_t noadd, uint64_t reg) +{ + return CVMX_ADD_IO_SEG(CVMX_FAU_LOAD_IO_ADDRESS) | + cvmx_build_bits(CVMX_FAU_BITS_NOADD, noadd) | + cvmx_build_bits(CVMX_FAU_BITS_REGISTER, reg); +} + +/** + * Builds a I/O address for accessing the FAU + * + * @tagwait: Should the atomic add wait for the current tag switch + * operation to complete. + * - 0 = Don't wait + * - 1 = Wait for tag switch to complete + * @reg: FAU atomic register to access. 0 <= reg < 2048. + * - Step by 2 for 16 bit access. + * - Step by 4 for 32 bit access. + * - Step by 8 for 64 bit access. + * @value: Signed value to add. + * Note: When performing 32 and 64 bit access, only the low + * 22 bits are available. + * Returns Address to read from for atomic update + */ +static inline uint64_t __cvmx_fau_atomic_address(uint64_t tagwait, uint64_t reg, + int64_t value) +{ + return CVMX_ADD_IO_SEG(CVMX_FAU_LOAD_IO_ADDRESS) | + cvmx_build_bits(CVMX_FAU_BITS_INEVAL, value) | + cvmx_build_bits(CVMX_FAU_BITS_TAGWAIT, tagwait) | + cvmx_build_bits(CVMX_FAU_BITS_REGISTER, reg); +} + +/** + * Perform an atomic 64 bit add + * + * @reg: FAU atomic register to access. 0 <= reg < 2048. + * - Step by 8 for 64 bit access. + * @value: Signed value to add. + * Note: Only the low 22 bits are available. + * Returns Value of the register before the update + */ +static inline int64_t cvmx_fau_fetch_and_add64(cvmx_fau_reg_64_t reg, + int64_t value) +{ + return cvmx_read64_int64(__cvmx_fau_atomic_address(0, reg, value)); +} + +/** + * Perform an atomic 32 bit add + * + * @reg: FAU atomic register to access. 0 <= reg < 2048. + * - Step by 4 for 32 bit access. + * @value: Signed value to add. + * Note: Only the low 22 bits are available. + * Returns Value of the register before the update + */ +static inline int32_t cvmx_fau_fetch_and_add32(cvmx_fau_reg_32_t reg, + int32_t value) +{ + return cvmx_read64_int32(__cvmx_fau_atomic_address(0, reg, value)); +} + +/** + * Perform an atomic 16 bit add + * + * @reg: FAU atomic register to access. 0 <= reg < 2048. + * - Step by 2 for 16 bit access. + * @value: Signed value to add. + * Returns Value of the register before the update + */ +static inline int16_t cvmx_fau_fetch_and_add16(cvmx_fau_reg_16_t reg, + int16_t value) +{ + return cvmx_read64_int16(__cvmx_fau_atomic_address(0, reg, value)); +} + +/** + * Perform an atomic 8 bit add + * + * @reg: FAU atomic register to access. 0 <= reg < 2048. + * @value: Signed value to add. + * Returns Value of the register before the update + */ +static inline int8_t cvmx_fau_fetch_and_add8(cvmx_fau_reg_8_t reg, int8_t value) +{ + return cvmx_read64_int8(__cvmx_fau_atomic_address(0, reg, value)); +} + +/** + * Perform an atomic 64 bit add after the current tag switch + * completes + * + * @reg: FAU atomic register to access. 0 <= reg < 2048. + * - Step by 8 for 64 bit access. + * @value: Signed value to add. + * Note: Only the low 22 bits are available. + * Returns If a timeout occurs, the error bit will be set. Otherwise + * the value of the register before the update will be + * returned + */ +static inline cvmx_fau_tagwait64_t +cvmx_fau_tagwait_fetch_and_add64(cvmx_fau_reg_64_t reg, int64_t value) +{ + union { + uint64_t i64; + cvmx_fau_tagwait64_t t; + } result; + result.i64 = + cvmx_read64_int64(__cvmx_fau_atomic_address(1, reg, value)); + return result.t; +} + +/** + * Perform an atomic 32 bit add after the current tag switch + * completes + * + * @reg: FAU atomic register to access. 0 <= reg < 2048. + * - Step by 4 for 32 bit access. + * @value: Signed value to add. + * Note: Only the low 22 bits are available. + * Returns If a timeout occurs, the error bit will be set. Otherwise + * the value of the register before the update will be + * returned + */ +static inline cvmx_fau_tagwait32_t +cvmx_fau_tagwait_fetch_and_add32(cvmx_fau_reg_32_t reg, int32_t value) +{ + union { + uint64_t i32; + cvmx_fau_tagwait32_t t; + } result; + result.i32 = + cvmx_read64_int32(__cvmx_fau_atomic_address(1, reg, value)); + return result.t; +} + +/** + * Perform an atomic 16 bit add after the current tag switch + * completes + * + * @reg: FAU atomic register to access. 0 <= reg < 2048. + * - Step by 2 for 16 bit access. + * @value: Signed value to add. + * Returns If a timeout occurs, the error bit will be set. Otherwise + * the value of the register before the update will be + * returned + */ +static inline cvmx_fau_tagwait16_t +cvmx_fau_tagwait_fetch_and_add16(cvmx_fau_reg_16_t reg, int16_t value) +{ + union { + uint64_t i16; + cvmx_fau_tagwait16_t t; + } result; + result.i16 = + cvmx_read64_int16(__cvmx_fau_atomic_address(1, reg, value)); + return result.t; +} + +/** + * Perform an atomic 8 bit add after the current tag switch + * completes + * + * @reg: FAU atomic register to access. 0 <= reg < 2048. + * @value: Signed value to add. + * Returns If a timeout occurs, the error bit will be set. Otherwise + * the value of the register before the update will be + * returned + */ +static inline cvmx_fau_tagwait8_t +cvmx_fau_tagwait_fetch_and_add8(cvmx_fau_reg_8_t reg, int8_t value) +{ + union { + uint64_t i8; + cvmx_fau_tagwait8_t t; + } result; + result.i8 = cvmx_read64_int8(__cvmx_fau_atomic_address(1, reg, value)); + return result.t; +} + +/** + * Builds I/O data for async operations + * + * @scraddr: Scratch pad byte addres to write to. Must be 8 byte aligned + * @value: Signed value to add. + * Note: When performing 32 and 64 bit access, only the low + * 22 bits are available. + * @tagwait: Should the atomic add wait for the current tag switch + * operation to complete. + * - 0 = Don't wait + * - 1 = Wait for tag switch to complete + * @size: The size of the operation: + * - CVMX_FAU_OP_SIZE_8 (0) = 8 bits + * - CVMX_FAU_OP_SIZE_16 (1) = 16 bits + * - CVMX_FAU_OP_SIZE_32 (2) = 32 bits + * - CVMX_FAU_OP_SIZE_64 (3) = 64 bits + * @reg: FAU atomic register to access. 0 <= reg < 2048. + * - Step by 2 for 16 bit access. + * - Step by 4 for 32 bit access. + * - Step by 8 for 64 bit access. + * Returns Data to write using cvmx_send_single + */ +static inline uint64_t __cvmx_fau_iobdma_data(uint64_t scraddr, int64_t value, + uint64_t tagwait, + cvmx_fau_op_size_t size, + uint64_t reg) +{ + return CVMX_FAU_LOAD_IO_ADDRESS | + cvmx_build_bits(CVMX_FAU_BITS_SCRADDR, scraddr >> 3) | + cvmx_build_bits(CVMX_FAU_BITS_LEN, 1) | + cvmx_build_bits(CVMX_FAU_BITS_INEVAL, value) | + cvmx_build_bits(CVMX_FAU_BITS_TAGWAIT, tagwait) | + cvmx_build_bits(CVMX_FAU_BITS_SIZE, size) | + cvmx_build_bits(CVMX_FAU_BITS_REGISTER, reg); +} + +/** + * Perform an async atomic 64 bit add. The old value is + * placed in the scratch memory at byte address scraddr. + * + * @scraddr: Scratch memory byte address to put response in. + * Must be 8 byte aligned. + * @reg: FAU atomic register to access. 0 <= reg < 2048. + * - Step by 8 for 64 bit access. + * @value: Signed value to add. + * Note: Only the low 22 bits are available. + * Returns Placed in the scratch pad register + */ +static inline void cvmx_fau_async_fetch_and_add64(uint64_t scraddr, + cvmx_fau_reg_64_t reg, + int64_t value) +{ + cvmx_send_single(__cvmx_fau_iobdma_data + (scraddr, value, 0, CVMX_FAU_OP_SIZE_64, reg)); +} + +/** + * Perform an async atomic 32 bit add. The old value is + * placed in the scratch memory at byte address scraddr. + * + * @scraddr: Scratch memory byte address to put response in. + * Must be 8 byte aligned. + * @reg: FAU atomic register to access. 0 <= reg < 2048. + * - Step by 4 for 32 bit access. + * @value: Signed value to add. + * Note: Only the low 22 bits are available. + * Returns Placed in the scratch pad register + */ +static inline void cvmx_fau_async_fetch_and_add32(uint64_t scraddr, + cvmx_fau_reg_32_t reg, + int32_t value) +{ + cvmx_send_single(__cvmx_fau_iobdma_data + (scraddr, value, 0, CVMX_FAU_OP_SIZE_32, reg)); +} + +/** + * Perform an async atomic 16 bit add. The old value is + * placed in the scratch memory at byte address scraddr. + * + * @scraddr: Scratch memory byte address to put response in. + * Must be 8 byte aligned. + * @reg: FAU atomic register to access. 0 <= reg < 2048. + * - Step by 2 for 16 bit access. + * @value: Signed value to add. + * Returns Placed in the scratch pad register + */ +static inline void cvmx_fau_async_fetch_and_add16(uint64_t scraddr, + cvmx_fau_reg_16_t reg, + int16_t value) +{ + cvmx_send_single(__cvmx_fau_iobdma_data + (scraddr, value, 0, CVMX_FAU_OP_SIZE_16, reg)); +} + +/** + * Perform an async atomic 8 bit add. The old value is + * placed in the scratch memory at byte address scraddr. + * + * @scraddr: Scratch memory byte address to put response in. + * Must be 8 byte aligned. + * @reg: FAU atomic register to access. 0 <= reg < 2048. + * @value: Signed value to add. + * Returns Placed in the scratch pad register + */ +static inline void cvmx_fau_async_fetch_and_add8(uint64_t scraddr, + cvmx_fau_reg_8_t reg, + int8_t value) +{ + cvmx_send_single(__cvmx_fau_iobdma_data + (scraddr, value, 0, CVMX_FAU_OP_SIZE_8, reg)); +} + +/** + * Perform an async atomic 64 bit add after the current tag + * switch completes. + * + * @scraddr: Scratch memory byte address to put response in. Must be + * 8 byte aligned. If a timeout occurs, the error bit (63) + * will be set. Otherwise the value of the register before + * the update will be returned + * + * @reg: FAU atomic register to access. 0 <= reg < 2048. + * - Step by 8 for 64 bit access. + * @value: Signed value to add. + * Note: Only the low 22 bits are available. + * Returns Placed in the scratch pad register + */ +static inline void cvmx_fau_async_tagwait_fetch_and_add64(uint64_t scraddr, + cvmx_fau_reg_64_t reg, + int64_t value) +{ + cvmx_send_single(__cvmx_fau_iobdma_data + (scraddr, value, 1, CVMX_FAU_OP_SIZE_64, reg)); +} + +/** + * Perform an async atomic 32 bit add after the current tag + * switch completes. + * + * @scraddr: Scratch memory byte address to put response in. Must be + * 8 byte aligned. If a timeout occurs, the error bit (63) + * will be set. Otherwise the value of the register before + * the update will be returned + * + * @reg: FAU atomic register to access. 0 <= reg < 2048. + * - Step by 4 for 32 bit access. + * @value: Signed value to add. + * Note: Only the low 22 bits are available. + * Returns Placed in the scratch pad register + */ +static inline void cvmx_fau_async_tagwait_fetch_and_add32(uint64_t scraddr, + cvmx_fau_reg_32_t reg, + int32_t value) +{ + cvmx_send_single(__cvmx_fau_iobdma_data + (scraddr, value, 1, CVMX_FAU_OP_SIZE_32, reg)); +} + +/** + * Perform an async atomic 16 bit add after the current tag + * switch completes. + * + * @scraddr: Scratch memory byte address to put response in. Must be + * 8 byte aligned. If a timeout occurs, the error bit (63) + * will be set. Otherwise the value of the register before + * the update will be returned + * + * @reg: FAU atomic register to access. 0 <= reg < 2048. + * - Step by 2 for 16 bit access. + * @value: Signed value to add. + * + * Returns Placed in the scratch pad register + */ +static inline void cvmx_fau_async_tagwait_fetch_and_add16(uint64_t scraddr, + cvmx_fau_reg_16_t reg, + int16_t value) +{ + cvmx_send_single(__cvmx_fau_iobdma_data + (scraddr, value, 1, CVMX_FAU_OP_SIZE_16, reg)); +} + +/** + * Perform an async atomic 8 bit add after the current tag + * switch completes. + * + * @scraddr: Scratch memory byte address to put response in. Must be + * 8 byte aligned. If a timeout occurs, the error bit (63) + * will be set. Otherwise the value of the register before + * the update will be returned + * + * @reg: FAU atomic register to access. 0 <= reg < 2048. + * @value: Signed value to add. + * + * Returns Placed in the scratch pad register + */ +static inline void cvmx_fau_async_tagwait_fetch_and_add8(uint64_t scraddr, + cvmx_fau_reg_8_t reg, + int8_t value) +{ + cvmx_send_single(__cvmx_fau_iobdma_data + (scraddr, value, 1, CVMX_FAU_OP_SIZE_8, reg)); +} + +/** + * Perform an atomic 64 bit add + * + * @reg: FAU atomic register to access. 0 <= reg < 2048. + * - Step by 8 for 64 bit access. + * @value: Signed value to add. + */ +static inline void cvmx_fau_atomic_add64(cvmx_fau_reg_64_t reg, int64_t value) +{ + cvmx_write64_int64(__cvmx_fau_store_address(0, reg), value); +} + +/** + * Perform an atomic 32 bit add + * + * @reg: FAU atomic register to access. 0 <= reg < 2048. + * - Step by 4 for 32 bit access. + * @value: Signed value to add. + */ +static inline void cvmx_fau_atomic_add32(cvmx_fau_reg_32_t reg, int32_t value) +{ + cvmx_write64_int32(__cvmx_fau_store_address(0, reg), value); +} + +/** + * Perform an atomic 16 bit add + * + * @reg: FAU atomic register to access. 0 <= reg < 2048. + * - Step by 2 for 16 bit access. + * @value: Signed value to add. + */ +static inline void cvmx_fau_atomic_add16(cvmx_fau_reg_16_t reg, int16_t value) +{ + cvmx_write64_int16(__cvmx_fau_store_address(0, reg), value); +} + +/** + * Perform an atomic 8 bit add + * + * @reg: FAU atomic register to access. 0 <= reg < 2048. + * @value: Signed value to add. + */ +static inline void cvmx_fau_atomic_add8(cvmx_fau_reg_8_t reg, int8_t value) +{ + cvmx_write64_int8(__cvmx_fau_store_address(0, reg), value); +} + +/** + * Perform an atomic 64 bit write + * + * @reg: FAU atomic register to access. 0 <= reg < 2048. + * - Step by 8 for 64 bit access. + * @value: Signed value to write. + */ +static inline void cvmx_fau_atomic_write64(cvmx_fau_reg_64_t reg, int64_t value) +{ + cvmx_write64_int64(__cvmx_fau_store_address(1, reg), value); +} + +/** + * Perform an atomic 32 bit write + * + * @reg: FAU atomic register to access. 0 <= reg < 2048. + * - Step by 4 for 32 bit access. + * @value: Signed value to write. + */ +static inline void cvmx_fau_atomic_write32(cvmx_fau_reg_32_t reg, int32_t value) +{ + cvmx_write64_int32(__cvmx_fau_store_address(1, reg), value); +} + +/** + * Perform an atomic 16 bit write + * + * @reg: FAU atomic register to access. 0 <= reg < 2048. + * - Step by 2 for 16 bit access. + * @value: Signed value to write. + */ +static inline void cvmx_fau_atomic_write16(cvmx_fau_reg_16_t reg, int16_t value) +{ + cvmx_write64_int16(__cvmx_fau_store_address(1, reg), value); +} + +/** + * Perform an atomic 8 bit write + * + * @reg: FAU atomic register to access. 0 <= reg < 2048. + * @value: Signed value to write. + */ +static inline void cvmx_fau_atomic_write8(cvmx_fau_reg_8_t reg, int8_t value) +{ + cvmx_write64_int8(__cvmx_fau_store_address(1, reg), value); +} + +#endif /* __CVMX_FAU_H__ */ diff --git a/drivers/staging/octeon/cvmx-fpa-defs.h b/drivers/staging/octeon/cvmx-fpa-defs.h new file mode 100644 index 000000000000..bf5546b90110 --- /dev/null +++ b/drivers/staging/octeon/cvmx-fpa-defs.h @@ -0,0 +1,403 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2008 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +#ifndef __CVMX_FPA_DEFS_H__ +#define __CVMX_FPA_DEFS_H__ + +#define CVMX_FPA_BIST_STATUS \ + CVMX_ADD_IO_SEG(0x00011800280000E8ull) +#define CVMX_FPA_CTL_STATUS \ + CVMX_ADD_IO_SEG(0x0001180028000050ull) +#define CVMX_FPA_FPF0_MARKS \ + CVMX_ADD_IO_SEG(0x0001180028000000ull) +#define CVMX_FPA_FPF0_SIZE \ + CVMX_ADD_IO_SEG(0x0001180028000058ull) +#define CVMX_FPA_FPF1_MARKS \ + CVMX_ADD_IO_SEG(0x0001180028000008ull) +#define CVMX_FPA_FPF2_MARKS \ + CVMX_ADD_IO_SEG(0x0001180028000010ull) +#define CVMX_FPA_FPF3_MARKS \ + CVMX_ADD_IO_SEG(0x0001180028000018ull) +#define CVMX_FPA_FPF4_MARKS \ + CVMX_ADD_IO_SEG(0x0001180028000020ull) +#define CVMX_FPA_FPF5_MARKS \ + CVMX_ADD_IO_SEG(0x0001180028000028ull) +#define CVMX_FPA_FPF6_MARKS \ + CVMX_ADD_IO_SEG(0x0001180028000030ull) +#define CVMX_FPA_FPF7_MARKS \ + CVMX_ADD_IO_SEG(0x0001180028000038ull) +#define CVMX_FPA_FPFX_MARKS(offset) \ + CVMX_ADD_IO_SEG(0x0001180028000008ull + (((offset) & 7) * 8) - 8 * 1) +#define CVMX_FPA_FPFX_SIZE(offset) \ + CVMX_ADD_IO_SEG(0x0001180028000060ull + (((offset) & 7) * 8) - 8 * 1) +#define CVMX_FPA_INT_ENB \ + CVMX_ADD_IO_SEG(0x0001180028000048ull) +#define CVMX_FPA_INT_SUM \ + CVMX_ADD_IO_SEG(0x0001180028000040ull) +#define CVMX_FPA_QUE0_PAGE_INDEX \ + CVMX_ADD_IO_SEG(0x00011800280000F0ull) +#define CVMX_FPA_QUE1_PAGE_INDEX \ + CVMX_ADD_IO_SEG(0x00011800280000F8ull) +#define CVMX_FPA_QUE2_PAGE_INDEX \ + CVMX_ADD_IO_SEG(0x0001180028000100ull) +#define CVMX_FPA_QUE3_PAGE_INDEX \ + CVMX_ADD_IO_SEG(0x0001180028000108ull) +#define CVMX_FPA_QUE4_PAGE_INDEX \ + CVMX_ADD_IO_SEG(0x0001180028000110ull) +#define CVMX_FPA_QUE5_PAGE_INDEX \ + CVMX_ADD_IO_SEG(0x0001180028000118ull) +#define CVMX_FPA_QUE6_PAGE_INDEX \ + CVMX_ADD_IO_SEG(0x0001180028000120ull) +#define CVMX_FPA_QUE7_PAGE_INDEX \ + CVMX_ADD_IO_SEG(0x0001180028000128ull) +#define CVMX_FPA_QUEX_AVAILABLE(offset) \ + CVMX_ADD_IO_SEG(0x0001180028000098ull + (((offset) & 7) * 8)) +#define CVMX_FPA_QUEX_PAGE_INDEX(offset) \ + CVMX_ADD_IO_SEG(0x00011800280000F0ull + (((offset) & 7) * 8)) +#define CVMX_FPA_QUE_ACT \ + CVMX_ADD_IO_SEG(0x0001180028000138ull) +#define CVMX_FPA_QUE_EXP \ + CVMX_ADD_IO_SEG(0x0001180028000130ull) +#define CVMX_FPA_WART_CTL \ + CVMX_ADD_IO_SEG(0x00011800280000D8ull) +#define CVMX_FPA_WART_STATUS \ + CVMX_ADD_IO_SEG(0x00011800280000E0ull) + +union cvmx_fpa_bist_status { + uint64_t u64; + struct cvmx_fpa_bist_status_s { + uint64_t reserved_5_63:59; + uint64_t frd:1; + uint64_t fpf0:1; + uint64_t fpf1:1; + uint64_t ffr:1; + uint64_t fdr:1; + } s; + struct cvmx_fpa_bist_status_s cn30xx; + struct cvmx_fpa_bist_status_s cn31xx; + struct cvmx_fpa_bist_status_s cn38xx; + struct cvmx_fpa_bist_status_s cn38xxp2; + struct cvmx_fpa_bist_status_s cn50xx; + struct cvmx_fpa_bist_status_s cn52xx; + struct cvmx_fpa_bist_status_s cn52xxp1; + struct cvmx_fpa_bist_status_s cn56xx; + struct cvmx_fpa_bist_status_s cn56xxp1; + struct cvmx_fpa_bist_status_s cn58xx; + struct cvmx_fpa_bist_status_s cn58xxp1; +}; + +union cvmx_fpa_ctl_status { + uint64_t u64; + struct cvmx_fpa_ctl_status_s { + uint64_t reserved_18_63:46; + uint64_t reset:1; + uint64_t use_ldt:1; + uint64_t use_stt:1; + uint64_t enb:1; + uint64_t mem1_err:7; + uint64_t mem0_err:7; + } s; + struct cvmx_fpa_ctl_status_s cn30xx; + struct cvmx_fpa_ctl_status_s cn31xx; + struct cvmx_fpa_ctl_status_s cn38xx; + struct cvmx_fpa_ctl_status_s cn38xxp2; + struct cvmx_fpa_ctl_status_s cn50xx; + struct cvmx_fpa_ctl_status_s cn52xx; + struct cvmx_fpa_ctl_status_s cn52xxp1; + struct cvmx_fpa_ctl_status_s cn56xx; + struct cvmx_fpa_ctl_status_s cn56xxp1; + struct cvmx_fpa_ctl_status_s cn58xx; + struct cvmx_fpa_ctl_status_s cn58xxp1; +}; + +union cvmx_fpa_fpfx_marks { + uint64_t u64; + struct cvmx_fpa_fpfx_marks_s { + uint64_t reserved_22_63:42; + uint64_t fpf_wr:11; + uint64_t fpf_rd:11; + } s; + struct cvmx_fpa_fpfx_marks_s cn38xx; + struct cvmx_fpa_fpfx_marks_s cn38xxp2; + struct cvmx_fpa_fpfx_marks_s cn56xx; + struct cvmx_fpa_fpfx_marks_s cn56xxp1; + struct cvmx_fpa_fpfx_marks_s cn58xx; + struct cvmx_fpa_fpfx_marks_s cn58xxp1; +}; + +union cvmx_fpa_fpfx_size { + uint64_t u64; + struct cvmx_fpa_fpfx_size_s { + uint64_t reserved_11_63:53; + uint64_t fpf_siz:11; + } s; + struct cvmx_fpa_fpfx_size_s cn38xx; + struct cvmx_fpa_fpfx_size_s cn38xxp2; + struct cvmx_fpa_fpfx_size_s cn56xx; + struct cvmx_fpa_fpfx_size_s cn56xxp1; + struct cvmx_fpa_fpfx_size_s cn58xx; + struct cvmx_fpa_fpfx_size_s cn58xxp1; +}; + +union cvmx_fpa_fpf0_marks { + uint64_t u64; + struct cvmx_fpa_fpf0_marks_s { + uint64_t reserved_24_63:40; + uint64_t fpf_wr:12; + uint64_t fpf_rd:12; + } s; + struct cvmx_fpa_fpf0_marks_s cn38xx; + struct cvmx_fpa_fpf0_marks_s cn38xxp2; + struct cvmx_fpa_fpf0_marks_s cn56xx; + struct cvmx_fpa_fpf0_marks_s cn56xxp1; + struct cvmx_fpa_fpf0_marks_s cn58xx; + struct cvmx_fpa_fpf0_marks_s cn58xxp1; +}; + +union cvmx_fpa_fpf0_size { + uint64_t u64; + struct cvmx_fpa_fpf0_size_s { + uint64_t reserved_12_63:52; + uint64_t fpf_siz:12; + } s; + struct cvmx_fpa_fpf0_size_s cn38xx; + struct cvmx_fpa_fpf0_size_s cn38xxp2; + struct cvmx_fpa_fpf0_size_s cn56xx; + struct cvmx_fpa_fpf0_size_s cn56xxp1; + struct cvmx_fpa_fpf0_size_s cn58xx; + struct cvmx_fpa_fpf0_size_s cn58xxp1; +}; + +union cvmx_fpa_int_enb { + uint64_t u64; + struct cvmx_fpa_int_enb_s { + uint64_t reserved_28_63:36; + uint64_t q7_perr:1; + uint64_t q7_coff:1; + uint64_t q7_und:1; + uint64_t q6_perr:1; + uint64_t q6_coff:1; + uint64_t q6_und:1; + uint64_t q5_perr:1; + uint64_t q5_coff:1; + uint64_t q5_und:1; + uint64_t q4_perr:1; + uint64_t q4_coff:1; + uint64_t q4_und:1; + uint64_t q3_perr:1; + uint64_t q3_coff:1; + uint64_t q3_und:1; + uint64_t q2_perr:1; + uint64_t q2_coff:1; + uint64_t q2_und:1; + uint64_t q1_perr:1; + uint64_t q1_coff:1; + uint64_t q1_und:1; + uint64_t q0_perr:1; + uint64_t q0_coff:1; + uint64_t q0_und:1; + uint64_t fed1_dbe:1; + uint64_t fed1_sbe:1; + uint64_t fed0_dbe:1; + uint64_t fed0_sbe:1; + } s; + struct cvmx_fpa_int_enb_s cn30xx; + struct cvmx_fpa_int_enb_s cn31xx; + struct cvmx_fpa_int_enb_s cn38xx; + struct cvmx_fpa_int_enb_s cn38xxp2; + struct cvmx_fpa_int_enb_s cn50xx; + struct cvmx_fpa_int_enb_s cn52xx; + struct cvmx_fpa_int_enb_s cn52xxp1; + struct cvmx_fpa_int_enb_s cn56xx; + struct cvmx_fpa_int_enb_s cn56xxp1; + struct cvmx_fpa_int_enb_s cn58xx; + struct cvmx_fpa_int_enb_s cn58xxp1; +}; + +union cvmx_fpa_int_sum { + uint64_t u64; + struct cvmx_fpa_int_sum_s { + uint64_t reserved_28_63:36; + uint64_t q7_perr:1; + uint64_t q7_coff:1; + uint64_t q7_und:1; + uint64_t q6_perr:1; + uint64_t q6_coff:1; + uint64_t q6_und:1; + uint64_t q5_perr:1; + uint64_t q5_coff:1; + uint64_t q5_und:1; + uint64_t q4_perr:1; + uint64_t q4_coff:1; + uint64_t q4_und:1; + uint64_t q3_perr:1; + uint64_t q3_coff:1; + uint64_t q3_und:1; + uint64_t q2_perr:1; + uint64_t q2_coff:1; + uint64_t q2_und:1; + uint64_t q1_perr:1; + uint64_t q1_coff:1; + uint64_t q1_und:1; + uint64_t q0_perr:1; + uint64_t q0_coff:1; + uint64_t q0_und:1; + uint64_t fed1_dbe:1; + uint64_t fed1_sbe:1; + uint64_t fed0_dbe:1; + uint64_t fed0_sbe:1; + } s; + struct cvmx_fpa_int_sum_s cn30xx; + struct cvmx_fpa_int_sum_s cn31xx; + struct cvmx_fpa_int_sum_s cn38xx; + struct cvmx_fpa_int_sum_s cn38xxp2; + struct cvmx_fpa_int_sum_s cn50xx; + struct cvmx_fpa_int_sum_s cn52xx; + struct cvmx_fpa_int_sum_s cn52xxp1; + struct cvmx_fpa_int_sum_s cn56xx; + struct cvmx_fpa_int_sum_s cn56xxp1; + struct cvmx_fpa_int_sum_s cn58xx; + struct cvmx_fpa_int_sum_s cn58xxp1; +}; + +union cvmx_fpa_quex_available { + uint64_t u64; + struct cvmx_fpa_quex_available_s { + uint64_t reserved_29_63:35; + uint64_t que_siz:29; + } s; + struct cvmx_fpa_quex_available_s cn30xx; + struct cvmx_fpa_quex_available_s cn31xx; + struct cvmx_fpa_quex_available_s cn38xx; + struct cvmx_fpa_quex_available_s cn38xxp2; + struct cvmx_fpa_quex_available_s cn50xx; + struct cvmx_fpa_quex_available_s cn52xx; + struct cvmx_fpa_quex_available_s cn52xxp1; + struct cvmx_fpa_quex_available_s cn56xx; + struct cvmx_fpa_quex_available_s cn56xxp1; + struct cvmx_fpa_quex_available_s cn58xx; + struct cvmx_fpa_quex_available_s cn58xxp1; +}; + +union cvmx_fpa_quex_page_index { + uint64_t u64; + struct cvmx_fpa_quex_page_index_s { + uint64_t reserved_25_63:39; + uint64_t pg_num:25; + } s; + struct cvmx_fpa_quex_page_index_s cn30xx; + struct cvmx_fpa_quex_page_index_s cn31xx; + struct cvmx_fpa_quex_page_index_s cn38xx; + struct cvmx_fpa_quex_page_index_s cn38xxp2; + struct cvmx_fpa_quex_page_index_s cn50xx; + struct cvmx_fpa_quex_page_index_s cn52xx; + struct cvmx_fpa_quex_page_index_s cn52xxp1; + struct cvmx_fpa_quex_page_index_s cn56xx; + struct cvmx_fpa_quex_page_index_s cn56xxp1; + struct cvmx_fpa_quex_page_index_s cn58xx; + struct cvmx_fpa_quex_page_index_s cn58xxp1; +}; + +union cvmx_fpa_que_act { + uint64_t u64; + struct cvmx_fpa_que_act_s { + uint64_t reserved_29_63:35; + uint64_t act_que:3; + uint64_t act_indx:26; + } s; + struct cvmx_fpa_que_act_s cn30xx; + struct cvmx_fpa_que_act_s cn31xx; + struct cvmx_fpa_que_act_s cn38xx; + struct cvmx_fpa_que_act_s cn38xxp2; + struct cvmx_fpa_que_act_s cn50xx; + struct cvmx_fpa_que_act_s cn52xx; + struct cvmx_fpa_que_act_s cn52xxp1; + struct cvmx_fpa_que_act_s cn56xx; + struct cvmx_fpa_que_act_s cn56xxp1; + struct cvmx_fpa_que_act_s cn58xx; + struct cvmx_fpa_que_act_s cn58xxp1; +}; + +union cvmx_fpa_que_exp { + uint64_t u64; + struct cvmx_fpa_que_exp_s { + uint64_t reserved_29_63:35; + uint64_t exp_que:3; + uint64_t exp_indx:26; + } s; + struct cvmx_fpa_que_exp_s cn30xx; + struct cvmx_fpa_que_exp_s cn31xx; + struct cvmx_fpa_que_exp_s cn38xx; + struct cvmx_fpa_que_exp_s cn38xxp2; + struct cvmx_fpa_que_exp_s cn50xx; + struct cvmx_fpa_que_exp_s cn52xx; + struct cvmx_fpa_que_exp_s cn52xxp1; + struct cvmx_fpa_que_exp_s cn56xx; + struct cvmx_fpa_que_exp_s cn56xxp1; + struct cvmx_fpa_que_exp_s cn58xx; + struct cvmx_fpa_que_exp_s cn58xxp1; +}; + +union cvmx_fpa_wart_ctl { + uint64_t u64; + struct cvmx_fpa_wart_ctl_s { + uint64_t reserved_16_63:48; + uint64_t ctl:16; + } s; + struct cvmx_fpa_wart_ctl_s cn30xx; + struct cvmx_fpa_wart_ctl_s cn31xx; + struct cvmx_fpa_wart_ctl_s cn38xx; + struct cvmx_fpa_wart_ctl_s cn38xxp2; + struct cvmx_fpa_wart_ctl_s cn50xx; + struct cvmx_fpa_wart_ctl_s cn52xx; + struct cvmx_fpa_wart_ctl_s cn52xxp1; + struct cvmx_fpa_wart_ctl_s cn56xx; + struct cvmx_fpa_wart_ctl_s cn56xxp1; + struct cvmx_fpa_wart_ctl_s cn58xx; + struct cvmx_fpa_wart_ctl_s cn58xxp1; +}; + +union cvmx_fpa_wart_status { + uint64_t u64; + struct cvmx_fpa_wart_status_s { + uint64_t reserved_32_63:32; + uint64_t status:32; + } s; + struct cvmx_fpa_wart_status_s cn30xx; + struct cvmx_fpa_wart_status_s cn31xx; + struct cvmx_fpa_wart_status_s cn38xx; + struct cvmx_fpa_wart_status_s cn38xxp2; + struct cvmx_fpa_wart_status_s cn50xx; + struct cvmx_fpa_wart_status_s cn52xx; + struct cvmx_fpa_wart_status_s cn52xxp1; + struct cvmx_fpa_wart_status_s cn56xx; + struct cvmx_fpa_wart_status_s cn56xxp1; + struct cvmx_fpa_wart_status_s cn58xx; + struct cvmx_fpa_wart_status_s cn58xxp1; +}; + +#endif diff --git a/drivers/staging/octeon/cvmx-fpa.c b/drivers/staging/octeon/cvmx-fpa.c new file mode 100644 index 000000000000..55d9147acc85 --- /dev/null +++ b/drivers/staging/octeon/cvmx-fpa.c @@ -0,0 +1,183 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2008 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +/** + * @file + * + * Support library for the hardware Free Pool Allocator. + * + * + */ + +#include "cvmx-config.h" +#include "cvmx.h" +#include "cvmx-fpa.h" +#include "cvmx-ipd.h" + +/** + * Current state of all the pools. Use access functions + * instead of using it directly. + */ +CVMX_SHARED cvmx_fpa_pool_info_t cvmx_fpa_pool_info[CVMX_FPA_NUM_POOLS]; + +/** + * Setup a FPA pool to control a new block of memory. The + * buffer pointer must be a physical address. + * + * @pool: Pool to initialize + * 0 <= pool < 8 + * @name: Constant character string to name this pool. + * String is not copied. + * @buffer: Pointer to the block of memory to use. This must be + * accessable by all processors and external hardware. + * @block_size: Size for each block controlled by the FPA + * @num_blocks: Number of blocks + * + * Returns 0 on Success, + * -1 on failure + */ +int cvmx_fpa_setup_pool(uint64_t pool, const char *name, void *buffer, + uint64_t block_size, uint64_t num_blocks) +{ + char *ptr; + if (!buffer) { + cvmx_dprintf + ("ERROR: cvmx_fpa_setup_pool: NULL buffer pointer!\n"); + return -1; + } + if (pool >= CVMX_FPA_NUM_POOLS) { + cvmx_dprintf("ERROR: cvmx_fpa_setup_pool: Illegal pool!\n"); + return -1; + } + + if (block_size < CVMX_FPA_MIN_BLOCK_SIZE) { + cvmx_dprintf + ("ERROR: cvmx_fpa_setup_pool: Block size too small.\n"); + return -1; + } + + if (((unsigned long)buffer & (CVMX_FPA_ALIGNMENT - 1)) != 0) { + cvmx_dprintf + ("ERROR: cvmx_fpa_setup_pool: Buffer not aligned properly.\n"); + return -1; + } + + cvmx_fpa_pool_info[pool].name = name; + cvmx_fpa_pool_info[pool].size = block_size; + cvmx_fpa_pool_info[pool].starting_element_count = num_blocks; + cvmx_fpa_pool_info[pool].base = buffer; + + ptr = (char *)buffer; + while (num_blocks--) { + cvmx_fpa_free(ptr, pool, 0); + ptr += block_size; + } + return 0; +} + +/** + * Shutdown a Memory pool and validate that it had all of + * the buffers originally placed in it. + * + * @pool: Pool to shutdown + * Returns Zero on success + * - Positive is count of missing buffers + * - Negative is too many buffers or corrupted pointers + */ +uint64_t cvmx_fpa_shutdown_pool(uint64_t pool) +{ + uint64_t errors = 0; + uint64_t count = 0; + uint64_t base = cvmx_ptr_to_phys(cvmx_fpa_pool_info[pool].base); + uint64_t finish = + base + + cvmx_fpa_pool_info[pool].size * + cvmx_fpa_pool_info[pool].starting_element_count; + void *ptr; + uint64_t address; + + count = 0; + do { + ptr = cvmx_fpa_alloc(pool); + if (ptr) + address = cvmx_ptr_to_phys(ptr); + else + address = 0; + if (address) { + if ((address >= base) && (address < finish) && + (((address - + base) % cvmx_fpa_pool_info[pool].size) == 0)) { + count++; + } else { + cvmx_dprintf + ("ERROR: cvmx_fpa_shutdown_pool: Illegal address 0x%llx in pool %s(%d)\n", + (unsigned long long)address, + cvmx_fpa_pool_info[pool].name, (int)pool); + errors++; + } + } + } while (address); + +#ifdef CVMX_ENABLE_PKO_FUNCTIONS + if (pool == 0) + cvmx_ipd_free_ptr(); +#endif + + if (errors) { + cvmx_dprintf + ("ERROR: cvmx_fpa_shutdown_pool: Pool %s(%d) started at 0x%llx, ended at 0x%llx, with a step of 0x%llx\n", + cvmx_fpa_pool_info[pool].name, (int)pool, + (unsigned long long)base, (unsigned long long)finish, + (unsigned long long)cvmx_fpa_pool_info[pool].size); + return -errors; + } else + return 0; +} + +uint64_t cvmx_fpa_get_block_size(uint64_t pool) +{ + switch (pool) { + case 0: + return CVMX_FPA_POOL_0_SIZE; + case 1: + return CVMX_FPA_POOL_1_SIZE; + case 2: + return CVMX_FPA_POOL_2_SIZE; + case 3: + return CVMX_FPA_POOL_3_SIZE; + case 4: + return CVMX_FPA_POOL_4_SIZE; + case 5: + return CVMX_FPA_POOL_5_SIZE; + case 6: + return CVMX_FPA_POOL_6_SIZE; + case 7: + return CVMX_FPA_POOL_7_SIZE; + default: + return 0; + } +} diff --git a/drivers/staging/octeon/cvmx-fpa.h b/drivers/staging/octeon/cvmx-fpa.h new file mode 100644 index 000000000000..1d7788fe09f2 --- /dev/null +++ b/drivers/staging/octeon/cvmx-fpa.h @@ -0,0 +1,299 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2008 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +/** + * @file + * + * Interface to the hardware Free Pool Allocator. + * + * + */ + +#ifndef __CVMX_FPA_H__ +#define __CVMX_FPA_H__ + +#include "cvmx-address.h" +#include "cvmx-fpa-defs.h" + +#define CVMX_FPA_NUM_POOLS 8 +#define CVMX_FPA_MIN_BLOCK_SIZE 128 +#define CVMX_FPA_ALIGNMENT 128 + +/** + * Structure describing the data format used for stores to the FPA. + */ +typedef union { + uint64_t u64; + struct { + /* + * the (64-bit word) location in scratchpad to write + * to (if len != 0) + */ + uint64_t scraddr:8; + /* the number of words in the response (0 => no response) */ + uint64_t len:8; + /* the ID of the device on the non-coherent bus */ + uint64_t did:8; + /* + * the address that will appear in the first tick on + * the NCB bus. + */ + uint64_t addr:40; + } s; +} cvmx_fpa_iobdma_data_t; + +/** + * Structure describing the current state of a FPA pool. + */ +typedef struct { + /* Name it was created under */ + const char *name; + /* Size of each block */ + uint64_t size; + /* The base memory address of whole block */ + void *base; + /* The number of elements in the pool at creation */ + uint64_t starting_element_count; +} cvmx_fpa_pool_info_t; + +/** + * Current state of all the pools. Use access functions + * instead of using it directly. + */ +extern cvmx_fpa_pool_info_t cvmx_fpa_pool_info[CVMX_FPA_NUM_POOLS]; + +/* CSR typedefs have been moved to cvmx-csr-*.h */ + +/** + * Return the name of the pool + * + * @pool: Pool to get the name of + * Returns The name + */ +static inline const char *cvmx_fpa_get_name(uint64_t pool) +{ + return cvmx_fpa_pool_info[pool].name; +} + +/** + * Return the base of the pool + * + * @pool: Pool to get the base of + * Returns The base + */ +static inline void *cvmx_fpa_get_base(uint64_t pool) +{ + return cvmx_fpa_pool_info[pool].base; +} + +/** + * Check if a pointer belongs to an FPA pool. Return non-zero + * if the supplied pointer is inside the memory controlled by + * an FPA pool. + * + * @pool: Pool to check + * @ptr: Pointer to check + * Returns Non-zero if pointer is in the pool. Zero if not + */ +static inline int cvmx_fpa_is_member(uint64_t pool, void *ptr) +{ + return ((ptr >= cvmx_fpa_pool_info[pool].base) && + ((char *)ptr < + ((char *)(cvmx_fpa_pool_info[pool].base)) + + cvmx_fpa_pool_info[pool].size * + cvmx_fpa_pool_info[pool].starting_element_count)); +} + +/** + * Enable the FPA for use. Must be performed after any CSR + * configuration but before any other FPA functions. + */ +static inline void cvmx_fpa_enable(void) +{ + union cvmx_fpa_ctl_status status; + + status.u64 = cvmx_read_csr(CVMX_FPA_CTL_STATUS); + if (status.s.enb) { + cvmx_dprintf + ("Warning: Enabling FPA when FPA already enabled.\n"); + } + + /* + * Do runtime check as we allow pass1 compiled code to run on + * pass2 chips. + */ + if (cvmx_octeon_is_pass1()) { + union cvmx_fpa_fpfx_marks marks; + int i; + for (i = 1; i < 8; i++) { + marks.u64 = + cvmx_read_csr(CVMX_FPA_FPF1_MARKS + (i - 1) * 8ull); + marks.s.fpf_wr = 0xe0; + cvmx_write_csr(CVMX_FPA_FPF1_MARKS + (i - 1) * 8ull, + marks.u64); + } + + /* Enforce a 10 cycle delay between config and enable */ + cvmx_wait(10); + } + + /* FIXME: CVMX_FPA_CTL_STATUS read is unmodelled */ + status.u64 = 0; + status.s.enb = 1; + cvmx_write_csr(CVMX_FPA_CTL_STATUS, status.u64); +} + +/** + * Get a new block from the FPA + * + * @pool: Pool to get the block from + * Returns Pointer to the block or NULL on failure + */ +static inline void *cvmx_fpa_alloc(uint64_t pool) +{ + uint64_t address = + cvmx_read_csr(CVMX_ADDR_DID(CVMX_FULL_DID(CVMX_OCT_DID_FPA, pool))); + if (address) + return cvmx_phys_to_ptr(address); + else + return NULL; +} + +/** + * Asynchronously get a new block from the FPA + * + * @scr_addr: Local scratch address to put response in. This is a byte address, + * but must be 8 byte aligned. + * @pool: Pool to get the block from + */ +static inline void cvmx_fpa_async_alloc(uint64_t scr_addr, uint64_t pool) +{ + cvmx_fpa_iobdma_data_t data; + + /* + * Hardware only uses 64 bit alligned locations, so convert + * from byte address to 64-bit index + */ + data.s.scraddr = scr_addr >> 3; + data.s.len = 1; + data.s.did = CVMX_FULL_DID(CVMX_OCT_DID_FPA, pool); + data.s.addr = 0; + cvmx_send_single(data.u64); +} + +/** + * Free a block allocated with a FPA pool. Does NOT provide memory + * ordering in cases where the memory block was modified by the core. + * + * @ptr: Block to free + * @pool: Pool to put it in + * @num_cache_lines: + * Cache lines to invalidate + */ +static inline void cvmx_fpa_free_nosync(void *ptr, uint64_t pool, + uint64_t num_cache_lines) +{ + cvmx_addr_t newptr; + newptr.u64 = cvmx_ptr_to_phys(ptr); + newptr.sfilldidspace.didspace = + CVMX_ADDR_DIDSPACE(CVMX_FULL_DID(CVMX_OCT_DID_FPA, pool)); + /* Prevent GCC from reordering around free */ + barrier(); + /* value written is number of cache lines not written back */ + cvmx_write_io(newptr.u64, num_cache_lines); +} + +/** + * Free a block allocated with a FPA pool. Provides required memory + * ordering in cases where memory block was modified by core. + * + * @ptr: Block to free + * @pool: Pool to put it in + * @num_cache_lines: + * Cache lines to invalidate + */ +static inline void cvmx_fpa_free(void *ptr, uint64_t pool, + uint64_t num_cache_lines) +{ + cvmx_addr_t newptr; + newptr.u64 = cvmx_ptr_to_phys(ptr); + newptr.sfilldidspace.didspace = + CVMX_ADDR_DIDSPACE(CVMX_FULL_DID(CVMX_OCT_DID_FPA, pool)); + /* + * Make sure that any previous writes to memory go out before + * we free this buffer. This also serves as a barrier to + * prevent GCC from reordering operations to after the + * free. + */ + CVMX_SYNCWS; + /* value written is number of cache lines not written back */ + cvmx_write_io(newptr.u64, num_cache_lines); +} + +/** + * Setup a FPA pool to control a new block of memory. + * This can only be called once per pool. Make sure proper + * locking enforces this. + * + * @pool: Pool to initialize + * 0 <= pool < 8 + * @name: Constant character string to name this pool. + * String is not copied. + * @buffer: Pointer to the block of memory to use. This must be + * accessable by all processors and external hardware. + * @block_size: Size for each block controlled by the FPA + * @num_blocks: Number of blocks + * + * Returns 0 on Success, + * -1 on failure + */ +extern int cvmx_fpa_setup_pool(uint64_t pool, const char *name, void *buffer, + uint64_t block_size, uint64_t num_blocks); + +/** + * Shutdown a Memory pool and validate that it had all of + * the buffers originally placed in it. This should only be + * called by one processor after all hardware has finished + * using the pool. + * + * @pool: Pool to shutdown + * Returns Zero on success + * - Positive is count of missing buffers + * - Negative is too many buffers or corrupted pointers + */ +extern uint64_t cvmx_fpa_shutdown_pool(uint64_t pool); + +/** + * Get the size of blocks controlled by the pool + * This is resolved to a constant at compile time. + * + * @pool: Pool to access + * Returns Size of the block in bytes + */ +uint64_t cvmx_fpa_get_block_size(uint64_t pool); + +#endif /* __CVM_FPA_H__ */ diff --git a/drivers/staging/octeon/cvmx-gmxx-defs.h b/drivers/staging/octeon/cvmx-gmxx-defs.h new file mode 100644 index 000000000000..946a43a73fd7 --- /dev/null +++ b/drivers/staging/octeon/cvmx-gmxx-defs.h @@ -0,0 +1,2529 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2008 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +#ifndef __CVMX_GMXX_DEFS_H__ +#define __CVMX_GMXX_DEFS_H__ + +#define CVMX_GMXX_BAD_REG(block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000518ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_BIST(block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000400ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_CLK_EN(block_id) \ + CVMX_ADD_IO_SEG(0x00011800080007F0ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_HG2_CONTROL(block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000550ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_INF_MODE(block_id) \ + CVMX_ADD_IO_SEG(0x00011800080007F8ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_NXA_ADR(block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000510ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_PRTX_CBFC_CTL(offset, block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000580ull + (((offset) & 0) * 8) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_PRTX_CFG(offset, block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000010ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_RXX_ADR_CAM0(offset, block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000180ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_RXX_ADR_CAM1(offset, block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000188ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_RXX_ADR_CAM2(offset, block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000190ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_RXX_ADR_CAM3(offset, block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000198ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_RXX_ADR_CAM4(offset, block_id) \ + CVMX_ADD_IO_SEG(0x00011800080001A0ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_RXX_ADR_CAM5(offset, block_id) \ + CVMX_ADD_IO_SEG(0x00011800080001A8ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_RXX_ADR_CAM_EN(offset, block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000108ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_RXX_ADR_CTL(offset, block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000100ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_RXX_DECISION(offset, block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000040ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_RXX_FRM_CHK(offset, block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000020ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_RXX_FRM_CTL(offset, block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000018ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_RXX_FRM_MAX(offset, block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000030ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_RXX_FRM_MIN(offset, block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000028ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_RXX_IFG(offset, block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000058ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_RXX_INT_EN(offset, block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000008ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_RXX_INT_REG(offset, block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000000ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_RXX_JABBER(offset, block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000038ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_RXX_PAUSE_DROP_TIME(offset, block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000068ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_RXX_RX_INBND(offset, block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000060ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_RXX_STATS_CTL(offset, block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000050ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_RXX_STATS_OCTS(offset, block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000088ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_RXX_STATS_OCTS_CTL(offset, block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000098ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_RXX_STATS_OCTS_DMAC(offset, block_id) \ + CVMX_ADD_IO_SEG(0x00011800080000A8ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_RXX_STATS_OCTS_DRP(offset, block_id) \ + CVMX_ADD_IO_SEG(0x00011800080000B8ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_RXX_STATS_PKTS(offset, block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000080ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_RXX_STATS_PKTS_BAD(offset, block_id) \ + CVMX_ADD_IO_SEG(0x00011800080000C0ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_RXX_STATS_PKTS_CTL(offset, block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000090ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_RXX_STATS_PKTS_DMAC(offset, block_id) \ + CVMX_ADD_IO_SEG(0x00011800080000A0ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_RXX_STATS_PKTS_DRP(offset, block_id) \ + CVMX_ADD_IO_SEG(0x00011800080000B0ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_RXX_UDD_SKP(offset, block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000048ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_RX_BP_DROPX(offset, block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000420ull + (((offset) & 3) * 8) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_RX_BP_OFFX(offset, block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000460ull + (((offset) & 3) * 8) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_RX_BP_ONX(offset, block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000440ull + (((offset) & 3) * 8) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_RX_HG2_STATUS(block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000548ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_RX_PASS_EN(block_id) \ + CVMX_ADD_IO_SEG(0x00011800080005F8ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_RX_PASS_MAPX(offset, block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000600ull + (((offset) & 15) * 8) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_RX_PRTS(block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000410ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_RX_PRT_INFO(block_id) \ + CVMX_ADD_IO_SEG(0x00011800080004E8ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_RX_TX_STATUS(block_id) \ + CVMX_ADD_IO_SEG(0x00011800080007E8ull + (((block_id) & 0) * 0x8000000ull)) +#define CVMX_GMXX_RX_XAUI_BAD_COL(block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000538ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_RX_XAUI_CTL(block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000530ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_SMACX(offset, block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000230ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_STAT_BP(block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000520ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_TXX_APPEND(offset, block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000218ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_TXX_BURST(offset, block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000228ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_TXX_CBFC_XOFF(offset, block_id) \ + CVMX_ADD_IO_SEG(0x00011800080005A0ull + (((offset) & 0) * 8) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_TXX_CBFC_XON(offset, block_id) \ + CVMX_ADD_IO_SEG(0x00011800080005C0ull + (((offset) & 0) * 8) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_TXX_CLK(offset, block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000208ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_TXX_CTL(offset, block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000270ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_TXX_MIN_PKT(offset, block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000240ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_TXX_PAUSE_PKT_INTERVAL(offset, block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000248ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_TXX_PAUSE_PKT_TIME(offset, block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000238ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_TXX_PAUSE_TOGO(offset, block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000258ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_TXX_PAUSE_ZERO(offset, block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000260ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_TXX_SGMII_CTL(offset, block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000300ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_TXX_SLOT(offset, block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000220ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_TXX_SOFT_PAUSE(offset, block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000250ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_TXX_STAT0(offset, block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000280ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_TXX_STAT1(offset, block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000288ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_TXX_STAT2(offset, block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000290ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_TXX_STAT3(offset, block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000298ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_TXX_STAT4(offset, block_id) \ + CVMX_ADD_IO_SEG(0x00011800080002A0ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_TXX_STAT5(offset, block_id) \ + CVMX_ADD_IO_SEG(0x00011800080002A8ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_TXX_STAT6(offset, block_id) \ + CVMX_ADD_IO_SEG(0x00011800080002B0ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_TXX_STAT7(offset, block_id) \ + CVMX_ADD_IO_SEG(0x00011800080002B8ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_TXX_STAT8(offset, block_id) \ + CVMX_ADD_IO_SEG(0x00011800080002C0ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_TXX_STAT9(offset, block_id) \ + CVMX_ADD_IO_SEG(0x00011800080002C8ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_TXX_STATS_CTL(offset, block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000268ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_TXX_THRESH(offset, block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000210ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_TX_BP(block_id) \ + CVMX_ADD_IO_SEG(0x00011800080004D0ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_TX_CLK_MSKX(offset, block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000780ull + (((offset) & 1) * 8) + (((block_id) & 0) * 0x0ull)) +#define CVMX_GMXX_TX_COL_ATTEMPT(block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000498ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_TX_CORRUPT(block_id) \ + CVMX_ADD_IO_SEG(0x00011800080004D8ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_TX_HG2_REG1(block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000558ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_TX_HG2_REG2(block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000560ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_TX_IFG(block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000488ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_TX_INT_EN(block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000508ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_TX_INT_REG(block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000500ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_TX_JAM(block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000490ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_TX_LFSR(block_id) \ + CVMX_ADD_IO_SEG(0x00011800080004F8ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_TX_OVR_BP(block_id) \ + CVMX_ADD_IO_SEG(0x00011800080004C8ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_TX_PAUSE_PKT_DMAC(block_id) \ + CVMX_ADD_IO_SEG(0x00011800080004A0ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_TX_PAUSE_PKT_TYPE(block_id) \ + CVMX_ADD_IO_SEG(0x00011800080004A8ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_TX_PRTS(block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000480ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_TX_SPI_CTL(block_id) \ + CVMX_ADD_IO_SEG(0x00011800080004C0ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_TX_SPI_DRAIN(block_id) \ + CVMX_ADD_IO_SEG(0x00011800080004E0ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_TX_SPI_MAX(block_id) \ + CVMX_ADD_IO_SEG(0x00011800080004B0ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_TX_SPI_ROUNDX(offset, block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000680ull + (((offset) & 31) * 8) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_TX_SPI_THRESH(block_id) \ + CVMX_ADD_IO_SEG(0x00011800080004B8ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_TX_XAUI_CTL(block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000528ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_GMXX_XAUI_EXT_LOOPBACK(block_id) \ + CVMX_ADD_IO_SEG(0x0001180008000540ull + (((block_id) & 1) * 0x8000000ull)) + +union cvmx_gmxx_bad_reg { + uint64_t u64; + struct cvmx_gmxx_bad_reg_s { + uint64_t reserved_31_63:33; + uint64_t inb_nxa:4; + uint64_t statovr:1; + uint64_t loststat:4; + uint64_t reserved_18_21:4; + uint64_t out_ovr:16; + uint64_t ncb_ovr:1; + uint64_t out_col:1; + } s; + struct cvmx_gmxx_bad_reg_cn30xx { + uint64_t reserved_31_63:33; + uint64_t inb_nxa:4; + uint64_t statovr:1; + uint64_t reserved_25_25:1; + uint64_t loststat:3; + uint64_t reserved_5_21:17; + uint64_t out_ovr:3; + uint64_t reserved_0_1:2; + } cn30xx; + struct cvmx_gmxx_bad_reg_cn30xx cn31xx; + struct cvmx_gmxx_bad_reg_s cn38xx; + struct cvmx_gmxx_bad_reg_s cn38xxp2; + struct cvmx_gmxx_bad_reg_cn30xx cn50xx; + struct cvmx_gmxx_bad_reg_cn52xx { + uint64_t reserved_31_63:33; + uint64_t inb_nxa:4; + uint64_t statovr:1; + uint64_t loststat:4; + uint64_t reserved_6_21:16; + uint64_t out_ovr:4; + uint64_t reserved_0_1:2; + } cn52xx; + struct cvmx_gmxx_bad_reg_cn52xx cn52xxp1; + struct cvmx_gmxx_bad_reg_cn52xx cn56xx; + struct cvmx_gmxx_bad_reg_cn52xx cn56xxp1; + struct cvmx_gmxx_bad_reg_s cn58xx; + struct cvmx_gmxx_bad_reg_s cn58xxp1; +}; + +union cvmx_gmxx_bist { + uint64_t u64; + struct cvmx_gmxx_bist_s { + uint64_t reserved_17_63:47; + uint64_t status:17; + } s; + struct cvmx_gmxx_bist_cn30xx { + uint64_t reserved_10_63:54; + uint64_t status:10; + } cn30xx; + struct cvmx_gmxx_bist_cn30xx cn31xx; + struct cvmx_gmxx_bist_cn30xx cn38xx; + struct cvmx_gmxx_bist_cn30xx cn38xxp2; + struct cvmx_gmxx_bist_cn50xx { + uint64_t reserved_12_63:52; + uint64_t status:12; + } cn50xx; + struct cvmx_gmxx_bist_cn52xx { + uint64_t reserved_16_63:48; + uint64_t status:16; + } cn52xx; + struct cvmx_gmxx_bist_cn52xx cn52xxp1; + struct cvmx_gmxx_bist_cn52xx cn56xx; + struct cvmx_gmxx_bist_cn52xx cn56xxp1; + struct cvmx_gmxx_bist_s cn58xx; + struct cvmx_gmxx_bist_s cn58xxp1; +}; + +union cvmx_gmxx_clk_en { + uint64_t u64; + struct cvmx_gmxx_clk_en_s { + uint64_t reserved_1_63:63; + uint64_t clk_en:1; + } s; + struct cvmx_gmxx_clk_en_s cn52xx; + struct cvmx_gmxx_clk_en_s cn52xxp1; + struct cvmx_gmxx_clk_en_s cn56xx; + struct cvmx_gmxx_clk_en_s cn56xxp1; +}; + +union cvmx_gmxx_hg2_control { + uint64_t u64; + struct cvmx_gmxx_hg2_control_s { + uint64_t reserved_19_63:45; + uint64_t hg2tx_en:1; + uint64_t hg2rx_en:1; + uint64_t phys_en:1; + uint64_t logl_en:16; + } s; + struct cvmx_gmxx_hg2_control_s cn52xx; + struct cvmx_gmxx_hg2_control_s cn52xxp1; + struct cvmx_gmxx_hg2_control_s cn56xx; +}; + +union cvmx_gmxx_inf_mode { + uint64_t u64; + struct cvmx_gmxx_inf_mode_s { + uint64_t reserved_10_63:54; + uint64_t speed:2; + uint64_t reserved_6_7:2; + uint64_t mode:2; + uint64_t reserved_3_3:1; + uint64_t p0mii:1; + uint64_t en:1; + uint64_t type:1; + } s; + struct cvmx_gmxx_inf_mode_cn30xx { + uint64_t reserved_3_63:61; + uint64_t p0mii:1; + uint64_t en:1; + uint64_t type:1; + } cn30xx; + struct cvmx_gmxx_inf_mode_cn31xx { + uint64_t reserved_2_63:62; + uint64_t en:1; + uint64_t type:1; + } cn31xx; + struct cvmx_gmxx_inf_mode_cn31xx cn38xx; + struct cvmx_gmxx_inf_mode_cn31xx cn38xxp2; + struct cvmx_gmxx_inf_mode_cn30xx cn50xx; + struct cvmx_gmxx_inf_mode_cn52xx { + uint64_t reserved_10_63:54; + uint64_t speed:2; + uint64_t reserved_6_7:2; + uint64_t mode:2; + uint64_t reserved_2_3:2; + uint64_t en:1; + uint64_t type:1; + } cn52xx; + struct cvmx_gmxx_inf_mode_cn52xx cn52xxp1; + struct cvmx_gmxx_inf_mode_cn52xx cn56xx; + struct cvmx_gmxx_inf_mode_cn52xx cn56xxp1; + struct cvmx_gmxx_inf_mode_cn31xx cn58xx; + struct cvmx_gmxx_inf_mode_cn31xx cn58xxp1; +}; + +union cvmx_gmxx_nxa_adr { + uint64_t u64; + struct cvmx_gmxx_nxa_adr_s { + uint64_t reserved_6_63:58; + uint64_t prt:6; + } s; + struct cvmx_gmxx_nxa_adr_s cn30xx; + struct cvmx_gmxx_nxa_adr_s cn31xx; + struct cvmx_gmxx_nxa_adr_s cn38xx; + struct cvmx_gmxx_nxa_adr_s cn38xxp2; + struct cvmx_gmxx_nxa_adr_s cn50xx; + struct cvmx_gmxx_nxa_adr_s cn52xx; + struct cvmx_gmxx_nxa_adr_s cn52xxp1; + struct cvmx_gmxx_nxa_adr_s cn56xx; + struct cvmx_gmxx_nxa_adr_s cn56xxp1; + struct cvmx_gmxx_nxa_adr_s cn58xx; + struct cvmx_gmxx_nxa_adr_s cn58xxp1; +}; + +union cvmx_gmxx_prtx_cbfc_ctl { + uint64_t u64; + struct cvmx_gmxx_prtx_cbfc_ctl_s { + uint64_t phys_en:16; + uint64_t logl_en:16; + uint64_t phys_bp:16; + uint64_t reserved_4_15:12; + uint64_t bck_en:1; + uint64_t drp_en:1; + uint64_t tx_en:1; + uint64_t rx_en:1; + } s; + struct cvmx_gmxx_prtx_cbfc_ctl_s cn52xx; + struct cvmx_gmxx_prtx_cbfc_ctl_s cn56xx; +}; + +union cvmx_gmxx_prtx_cfg { + uint64_t u64; + struct cvmx_gmxx_prtx_cfg_s { + uint64_t reserved_14_63:50; + uint64_t tx_idle:1; + uint64_t rx_idle:1; + uint64_t reserved_9_11:3; + uint64_t speed_msb:1; + uint64_t reserved_4_7:4; + uint64_t slottime:1; + uint64_t duplex:1; + uint64_t speed:1; + uint64_t en:1; + } s; + struct cvmx_gmxx_prtx_cfg_cn30xx { + uint64_t reserved_4_63:60; + uint64_t slottime:1; + uint64_t duplex:1; + uint64_t speed:1; + uint64_t en:1; + } cn30xx; + struct cvmx_gmxx_prtx_cfg_cn30xx cn31xx; + struct cvmx_gmxx_prtx_cfg_cn30xx cn38xx; + struct cvmx_gmxx_prtx_cfg_cn30xx cn38xxp2; + struct cvmx_gmxx_prtx_cfg_cn30xx cn50xx; + struct cvmx_gmxx_prtx_cfg_s cn52xx; + struct cvmx_gmxx_prtx_cfg_s cn52xxp1; + struct cvmx_gmxx_prtx_cfg_s cn56xx; + struct cvmx_gmxx_prtx_cfg_s cn56xxp1; + struct cvmx_gmxx_prtx_cfg_cn30xx cn58xx; + struct cvmx_gmxx_prtx_cfg_cn30xx cn58xxp1; +}; + +union cvmx_gmxx_rxx_adr_cam0 { + uint64_t u64; + struct cvmx_gmxx_rxx_adr_cam0_s { + uint64_t adr:64; + } s; + struct cvmx_gmxx_rxx_adr_cam0_s cn30xx; + struct cvmx_gmxx_rxx_adr_cam0_s cn31xx; + struct cvmx_gmxx_rxx_adr_cam0_s cn38xx; + struct cvmx_gmxx_rxx_adr_cam0_s cn38xxp2; + struct cvmx_gmxx_rxx_adr_cam0_s cn50xx; + struct cvmx_gmxx_rxx_adr_cam0_s cn52xx; + struct cvmx_gmxx_rxx_adr_cam0_s cn52xxp1; + struct cvmx_gmxx_rxx_adr_cam0_s cn56xx; + struct cvmx_gmxx_rxx_adr_cam0_s cn56xxp1; + struct cvmx_gmxx_rxx_adr_cam0_s cn58xx; + struct cvmx_gmxx_rxx_adr_cam0_s cn58xxp1; +}; + +union cvmx_gmxx_rxx_adr_cam1 { + uint64_t u64; + struct cvmx_gmxx_rxx_adr_cam1_s { + uint64_t adr:64; + } s; + struct cvmx_gmxx_rxx_adr_cam1_s cn30xx; + struct cvmx_gmxx_rxx_adr_cam1_s cn31xx; + struct cvmx_gmxx_rxx_adr_cam1_s cn38xx; + struct cvmx_gmxx_rxx_adr_cam1_s cn38xxp2; + struct cvmx_gmxx_rxx_adr_cam1_s cn50xx; + struct cvmx_gmxx_rxx_adr_cam1_s cn52xx; + struct cvmx_gmxx_rxx_adr_cam1_s cn52xxp1; + struct cvmx_gmxx_rxx_adr_cam1_s cn56xx; + struct cvmx_gmxx_rxx_adr_cam1_s cn56xxp1; + struct cvmx_gmxx_rxx_adr_cam1_s cn58xx; + struct cvmx_gmxx_rxx_adr_cam1_s cn58xxp1; +}; + +union cvmx_gmxx_rxx_adr_cam2 { + uint64_t u64; + struct cvmx_gmxx_rxx_adr_cam2_s { + uint64_t adr:64; + } s; + struct cvmx_gmxx_rxx_adr_cam2_s cn30xx; + struct cvmx_gmxx_rxx_adr_cam2_s cn31xx; + struct cvmx_gmxx_rxx_adr_cam2_s cn38xx; + struct cvmx_gmxx_rxx_adr_cam2_s cn38xxp2; + struct cvmx_gmxx_rxx_adr_cam2_s cn50xx; + struct cvmx_gmxx_rxx_adr_cam2_s cn52xx; + struct cvmx_gmxx_rxx_adr_cam2_s cn52xxp1; + struct cvmx_gmxx_rxx_adr_cam2_s cn56xx; + struct cvmx_gmxx_rxx_adr_cam2_s cn56xxp1; + struct cvmx_gmxx_rxx_adr_cam2_s cn58xx; + struct cvmx_gmxx_rxx_adr_cam2_s cn58xxp1; +}; + +union cvmx_gmxx_rxx_adr_cam3 { + uint64_t u64; + struct cvmx_gmxx_rxx_adr_cam3_s { + uint64_t adr:64; + } s; + struct cvmx_gmxx_rxx_adr_cam3_s cn30xx; + struct cvmx_gmxx_rxx_adr_cam3_s cn31xx; + struct cvmx_gmxx_rxx_adr_cam3_s cn38xx; + struct cvmx_gmxx_rxx_adr_cam3_s cn38xxp2; + struct cvmx_gmxx_rxx_adr_cam3_s cn50xx; + struct cvmx_gmxx_rxx_adr_cam3_s cn52xx; + struct cvmx_gmxx_rxx_adr_cam3_s cn52xxp1; + struct cvmx_gmxx_rxx_adr_cam3_s cn56xx; + struct cvmx_gmxx_rxx_adr_cam3_s cn56xxp1; + struct cvmx_gmxx_rxx_adr_cam3_s cn58xx; + struct cvmx_gmxx_rxx_adr_cam3_s cn58xxp1; +}; + +union cvmx_gmxx_rxx_adr_cam4 { + uint64_t u64; + struct cvmx_gmxx_rxx_adr_cam4_s { + uint64_t adr:64; + } s; + struct cvmx_gmxx_rxx_adr_cam4_s cn30xx; + struct cvmx_gmxx_rxx_adr_cam4_s cn31xx; + struct cvmx_gmxx_rxx_adr_cam4_s cn38xx; + struct cvmx_gmxx_rxx_adr_cam4_s cn38xxp2; + struct cvmx_gmxx_rxx_adr_cam4_s cn50xx; + struct cvmx_gmxx_rxx_adr_cam4_s cn52xx; + struct cvmx_gmxx_rxx_adr_cam4_s cn52xxp1; + struct cvmx_gmxx_rxx_adr_cam4_s cn56xx; + struct cvmx_gmxx_rxx_adr_cam4_s cn56xxp1; + struct cvmx_gmxx_rxx_adr_cam4_s cn58xx; + struct cvmx_gmxx_rxx_adr_cam4_s cn58xxp1; +}; + +union cvmx_gmxx_rxx_adr_cam5 { + uint64_t u64; + struct cvmx_gmxx_rxx_adr_cam5_s { + uint64_t adr:64; + } s; + struct cvmx_gmxx_rxx_adr_cam5_s cn30xx; + struct cvmx_gmxx_rxx_adr_cam5_s cn31xx; + struct cvmx_gmxx_rxx_adr_cam5_s cn38xx; + struct cvmx_gmxx_rxx_adr_cam5_s cn38xxp2; + struct cvmx_gmxx_rxx_adr_cam5_s cn50xx; + struct cvmx_gmxx_rxx_adr_cam5_s cn52xx; + struct cvmx_gmxx_rxx_adr_cam5_s cn52xxp1; + struct cvmx_gmxx_rxx_adr_cam5_s cn56xx; + struct cvmx_gmxx_rxx_adr_cam5_s cn56xxp1; + struct cvmx_gmxx_rxx_adr_cam5_s cn58xx; + struct cvmx_gmxx_rxx_adr_cam5_s cn58xxp1; +}; + +union cvmx_gmxx_rxx_adr_cam_en { + uint64_t u64; + struct cvmx_gmxx_rxx_adr_cam_en_s { + uint64_t reserved_8_63:56; + uint64_t en:8; + } s; + struct cvmx_gmxx_rxx_adr_cam_en_s cn30xx; + struct cvmx_gmxx_rxx_adr_cam_en_s cn31xx; + struct cvmx_gmxx_rxx_adr_cam_en_s cn38xx; + struct cvmx_gmxx_rxx_adr_cam_en_s cn38xxp2; + struct cvmx_gmxx_rxx_adr_cam_en_s cn50xx; + struct cvmx_gmxx_rxx_adr_cam_en_s cn52xx; + struct cvmx_gmxx_rxx_adr_cam_en_s cn52xxp1; + struct cvmx_gmxx_rxx_adr_cam_en_s cn56xx; + struct cvmx_gmxx_rxx_adr_cam_en_s cn56xxp1; + struct cvmx_gmxx_rxx_adr_cam_en_s cn58xx; + struct cvmx_gmxx_rxx_adr_cam_en_s cn58xxp1; +}; + +union cvmx_gmxx_rxx_adr_ctl { + uint64_t u64; + struct cvmx_gmxx_rxx_adr_ctl_s { + uint64_t reserved_4_63:60; + uint64_t cam_mode:1; + uint64_t mcst:2; + uint64_t bcst:1; + } s; + struct cvmx_gmxx_rxx_adr_ctl_s cn30xx; + struct cvmx_gmxx_rxx_adr_ctl_s cn31xx; + struct cvmx_gmxx_rxx_adr_ctl_s cn38xx; + struct cvmx_gmxx_rxx_adr_ctl_s cn38xxp2; + struct cvmx_gmxx_rxx_adr_ctl_s cn50xx; + struct cvmx_gmxx_rxx_adr_ctl_s cn52xx; + struct cvmx_gmxx_rxx_adr_ctl_s cn52xxp1; + struct cvmx_gmxx_rxx_adr_ctl_s cn56xx; + struct cvmx_gmxx_rxx_adr_ctl_s cn56xxp1; + struct cvmx_gmxx_rxx_adr_ctl_s cn58xx; + struct cvmx_gmxx_rxx_adr_ctl_s cn58xxp1; +}; + +union cvmx_gmxx_rxx_decision { + uint64_t u64; + struct cvmx_gmxx_rxx_decision_s { + uint64_t reserved_5_63:59; + uint64_t cnt:5; + } s; + struct cvmx_gmxx_rxx_decision_s cn30xx; + struct cvmx_gmxx_rxx_decision_s cn31xx; + struct cvmx_gmxx_rxx_decision_s cn38xx; + struct cvmx_gmxx_rxx_decision_s cn38xxp2; + struct cvmx_gmxx_rxx_decision_s cn50xx; + struct cvmx_gmxx_rxx_decision_s cn52xx; + struct cvmx_gmxx_rxx_decision_s cn52xxp1; + struct cvmx_gmxx_rxx_decision_s cn56xx; + struct cvmx_gmxx_rxx_decision_s cn56xxp1; + struct cvmx_gmxx_rxx_decision_s cn58xx; + struct cvmx_gmxx_rxx_decision_s cn58xxp1; +}; + +union cvmx_gmxx_rxx_frm_chk { + uint64_t u64; + struct cvmx_gmxx_rxx_frm_chk_s { + uint64_t reserved_10_63:54; + uint64_t niberr:1; + uint64_t skperr:1; + uint64_t rcverr:1; + uint64_t lenerr:1; + uint64_t alnerr:1; + uint64_t fcserr:1; + uint64_t jabber:1; + uint64_t maxerr:1; + uint64_t carext:1; + uint64_t minerr:1; + } s; + struct cvmx_gmxx_rxx_frm_chk_s cn30xx; + struct cvmx_gmxx_rxx_frm_chk_s cn31xx; + struct cvmx_gmxx_rxx_frm_chk_s cn38xx; + struct cvmx_gmxx_rxx_frm_chk_s cn38xxp2; + struct cvmx_gmxx_rxx_frm_chk_cn50xx { + uint64_t reserved_10_63:54; + uint64_t niberr:1; + uint64_t skperr:1; + uint64_t rcverr:1; + uint64_t reserved_6_6:1; + uint64_t alnerr:1; + uint64_t fcserr:1; + uint64_t jabber:1; + uint64_t reserved_2_2:1; + uint64_t carext:1; + uint64_t reserved_0_0:1; + } cn50xx; + struct cvmx_gmxx_rxx_frm_chk_cn52xx { + uint64_t reserved_9_63:55; + uint64_t skperr:1; + uint64_t rcverr:1; + uint64_t reserved_5_6:2; + uint64_t fcserr:1; + uint64_t jabber:1; + uint64_t reserved_2_2:1; + uint64_t carext:1; + uint64_t reserved_0_0:1; + } cn52xx; + struct cvmx_gmxx_rxx_frm_chk_cn52xx cn52xxp1; + struct cvmx_gmxx_rxx_frm_chk_cn52xx cn56xx; + struct cvmx_gmxx_rxx_frm_chk_cn52xx cn56xxp1; + struct cvmx_gmxx_rxx_frm_chk_s cn58xx; + struct cvmx_gmxx_rxx_frm_chk_s cn58xxp1; +}; + +union cvmx_gmxx_rxx_frm_ctl { + uint64_t u64; + struct cvmx_gmxx_rxx_frm_ctl_s { + uint64_t reserved_11_63:53; + uint64_t null_dis:1; + uint64_t pre_align:1; + uint64_t pad_len:1; + uint64_t vlan_len:1; + uint64_t pre_free:1; + uint64_t ctl_smac:1; + uint64_t ctl_mcst:1; + uint64_t ctl_bck:1; + uint64_t ctl_drp:1; + uint64_t pre_strp:1; + uint64_t pre_chk:1; + } s; + struct cvmx_gmxx_rxx_frm_ctl_cn30xx { + uint64_t reserved_9_63:55; + uint64_t pad_len:1; + uint64_t vlan_len:1; + uint64_t pre_free:1; + uint64_t ctl_smac:1; + uint64_t ctl_mcst:1; + uint64_t ctl_bck:1; + uint64_t ctl_drp:1; + uint64_t pre_strp:1; + uint64_t pre_chk:1; + } cn30xx; + struct cvmx_gmxx_rxx_frm_ctl_cn31xx { + uint64_t reserved_8_63:56; + uint64_t vlan_len:1; + uint64_t pre_free:1; + uint64_t ctl_smac:1; + uint64_t ctl_mcst:1; + uint64_t ctl_bck:1; + uint64_t ctl_drp:1; + uint64_t pre_strp:1; + uint64_t pre_chk:1; + } cn31xx; + struct cvmx_gmxx_rxx_frm_ctl_cn30xx cn38xx; + struct cvmx_gmxx_rxx_frm_ctl_cn31xx cn38xxp2; + struct cvmx_gmxx_rxx_frm_ctl_cn50xx { + uint64_t reserved_11_63:53; + uint64_t null_dis:1; + uint64_t pre_align:1; + uint64_t reserved_7_8:2; + uint64_t pre_free:1; + uint64_t ctl_smac:1; + uint64_t ctl_mcst:1; + uint64_t ctl_bck:1; + uint64_t ctl_drp:1; + uint64_t pre_strp:1; + uint64_t pre_chk:1; + } cn50xx; + struct cvmx_gmxx_rxx_frm_ctl_cn50xx cn52xx; + struct cvmx_gmxx_rxx_frm_ctl_cn50xx cn52xxp1; + struct cvmx_gmxx_rxx_frm_ctl_cn50xx cn56xx; + struct cvmx_gmxx_rxx_frm_ctl_cn56xxp1 { + uint64_t reserved_10_63:54; + uint64_t pre_align:1; + uint64_t reserved_7_8:2; + uint64_t pre_free:1; + uint64_t ctl_smac:1; + uint64_t ctl_mcst:1; + uint64_t ctl_bck:1; + uint64_t ctl_drp:1; + uint64_t pre_strp:1; + uint64_t pre_chk:1; + } cn56xxp1; + struct cvmx_gmxx_rxx_frm_ctl_s cn58xx; + struct cvmx_gmxx_rxx_frm_ctl_cn30xx cn58xxp1; +}; + +union cvmx_gmxx_rxx_frm_max { + uint64_t u64; + struct cvmx_gmxx_rxx_frm_max_s { + uint64_t reserved_16_63:48; + uint64_t len:16; + } s; + struct cvmx_gmxx_rxx_frm_max_s cn30xx; + struct cvmx_gmxx_rxx_frm_max_s cn31xx; + struct cvmx_gmxx_rxx_frm_max_s cn38xx; + struct cvmx_gmxx_rxx_frm_max_s cn38xxp2; + struct cvmx_gmxx_rxx_frm_max_s cn58xx; + struct cvmx_gmxx_rxx_frm_max_s cn58xxp1; +}; + +union cvmx_gmxx_rxx_frm_min { + uint64_t u64; + struct cvmx_gmxx_rxx_frm_min_s { + uint64_t reserved_16_63:48; + uint64_t len:16; + } s; + struct cvmx_gmxx_rxx_frm_min_s cn30xx; + struct cvmx_gmxx_rxx_frm_min_s cn31xx; + struct cvmx_gmxx_rxx_frm_min_s cn38xx; + struct cvmx_gmxx_rxx_frm_min_s cn38xxp2; + struct cvmx_gmxx_rxx_frm_min_s cn58xx; + struct cvmx_gmxx_rxx_frm_min_s cn58xxp1; +}; + +union cvmx_gmxx_rxx_ifg { + uint64_t u64; + struct cvmx_gmxx_rxx_ifg_s { + uint64_t reserved_4_63:60; + uint64_t ifg:4; + } s; + struct cvmx_gmxx_rxx_ifg_s cn30xx; + struct cvmx_gmxx_rxx_ifg_s cn31xx; + struct cvmx_gmxx_rxx_ifg_s cn38xx; + struct cvmx_gmxx_rxx_ifg_s cn38xxp2; + struct cvmx_gmxx_rxx_ifg_s cn50xx; + struct cvmx_gmxx_rxx_ifg_s cn52xx; + struct cvmx_gmxx_rxx_ifg_s cn52xxp1; + struct cvmx_gmxx_rxx_ifg_s cn56xx; + struct cvmx_gmxx_rxx_ifg_s cn56xxp1; + struct cvmx_gmxx_rxx_ifg_s cn58xx; + struct cvmx_gmxx_rxx_ifg_s cn58xxp1; +}; + +union cvmx_gmxx_rxx_int_en { + uint64_t u64; + struct cvmx_gmxx_rxx_int_en_s { + uint64_t reserved_29_63:35; + uint64_t hg2cc:1; + uint64_t hg2fld:1; + uint64_t undat:1; + uint64_t uneop:1; + uint64_t unsop:1; + uint64_t bad_term:1; + uint64_t bad_seq:1; + uint64_t rem_fault:1; + uint64_t loc_fault:1; + uint64_t pause_drp:1; + uint64_t phy_dupx:1; + uint64_t phy_spd:1; + uint64_t phy_link:1; + uint64_t ifgerr:1; + uint64_t coldet:1; + uint64_t falerr:1; + uint64_t rsverr:1; + uint64_t pcterr:1; + uint64_t ovrerr:1; + uint64_t niberr:1; + uint64_t skperr:1; + uint64_t rcverr:1; + uint64_t lenerr:1; + uint64_t alnerr:1; + uint64_t fcserr:1; + uint64_t jabber:1; + uint64_t maxerr:1; + uint64_t carext:1; + uint64_t minerr:1; + } s; + struct cvmx_gmxx_rxx_int_en_cn30xx { + uint64_t reserved_19_63:45; + uint64_t phy_dupx:1; + uint64_t phy_spd:1; + uint64_t phy_link:1; + uint64_t ifgerr:1; + uint64_t coldet:1; + uint64_t falerr:1; + uint64_t rsverr:1; + uint64_t pcterr:1; + uint64_t ovrerr:1; + uint64_t niberr:1; + uint64_t skperr:1; + uint64_t rcverr:1; + uint64_t lenerr:1; + uint64_t alnerr:1; + uint64_t fcserr:1; + uint64_t jabber:1; + uint64_t maxerr:1; + uint64_t carext:1; + uint64_t minerr:1; + } cn30xx; + struct cvmx_gmxx_rxx_int_en_cn30xx cn31xx; + struct cvmx_gmxx_rxx_int_en_cn30xx cn38xx; + struct cvmx_gmxx_rxx_int_en_cn30xx cn38xxp2; + struct cvmx_gmxx_rxx_int_en_cn50xx { + uint64_t reserved_20_63:44; + uint64_t pause_drp:1; + uint64_t phy_dupx:1; + uint64_t phy_spd:1; + uint64_t phy_link:1; + uint64_t ifgerr:1; + uint64_t coldet:1; + uint64_t falerr:1; + uint64_t rsverr:1; + uint64_t pcterr:1; + uint64_t ovrerr:1; + uint64_t niberr:1; + uint64_t skperr:1; + uint64_t rcverr:1; + uint64_t reserved_6_6:1; + uint64_t alnerr:1; + uint64_t fcserr:1; + uint64_t jabber:1; + uint64_t reserved_2_2:1; + uint64_t carext:1; + uint64_t reserved_0_0:1; + } cn50xx; + struct cvmx_gmxx_rxx_int_en_cn52xx { + uint64_t reserved_29_63:35; + uint64_t hg2cc:1; + uint64_t hg2fld:1; + uint64_t undat:1; + uint64_t uneop:1; + uint64_t unsop:1; + uint64_t bad_term:1; + uint64_t bad_seq:1; + uint64_t rem_fault:1; + uint64_t loc_fault:1; + uint64_t pause_drp:1; + uint64_t reserved_16_18:3; + uint64_t ifgerr:1; + uint64_t coldet:1; + uint64_t falerr:1; + uint64_t rsverr:1; + uint64_t pcterr:1; + uint64_t ovrerr:1; + uint64_t reserved_9_9:1; + uint64_t skperr:1; + uint64_t rcverr:1; + uint64_t reserved_5_6:2; + uint64_t fcserr:1; + uint64_t jabber:1; + uint64_t reserved_2_2:1; + uint64_t carext:1; + uint64_t reserved_0_0:1; + } cn52xx; + struct cvmx_gmxx_rxx_int_en_cn52xx cn52xxp1; + struct cvmx_gmxx_rxx_int_en_cn52xx cn56xx; + struct cvmx_gmxx_rxx_int_en_cn56xxp1 { + uint64_t reserved_27_63:37; + uint64_t undat:1; + uint64_t uneop:1; + uint64_t unsop:1; + uint64_t bad_term:1; + uint64_t bad_seq:1; + uint64_t rem_fault:1; + uint64_t loc_fault:1; + uint64_t pause_drp:1; + uint64_t reserved_16_18:3; + uint64_t ifgerr:1; + uint64_t coldet:1; + uint64_t falerr:1; + uint64_t rsverr:1; + uint64_t pcterr:1; + uint64_t ovrerr:1; + uint64_t reserved_9_9:1; + uint64_t skperr:1; + uint64_t rcverr:1; + uint64_t reserved_5_6:2; + uint64_t fcserr:1; + uint64_t jabber:1; + uint64_t reserved_2_2:1; + uint64_t carext:1; + uint64_t reserved_0_0:1; + } cn56xxp1; + struct cvmx_gmxx_rxx_int_en_cn58xx { + uint64_t reserved_20_63:44; + uint64_t pause_drp:1; + uint64_t phy_dupx:1; + uint64_t phy_spd:1; + uint64_t phy_link:1; + uint64_t ifgerr:1; + uint64_t coldet:1; + uint64_t falerr:1; + uint64_t rsverr:1; + uint64_t pcterr:1; + uint64_t ovrerr:1; + uint64_t niberr:1; + uint64_t skperr:1; + uint64_t rcverr:1; + uint64_t lenerr:1; + uint64_t alnerr:1; + uint64_t fcserr:1; + uint64_t jabber:1; + uint64_t maxerr:1; + uint64_t carext:1; + uint64_t minerr:1; + } cn58xx; + struct cvmx_gmxx_rxx_int_en_cn58xx cn58xxp1; +}; + +union cvmx_gmxx_rxx_int_reg { + uint64_t u64; + struct cvmx_gmxx_rxx_int_reg_s { + uint64_t reserved_29_63:35; + uint64_t hg2cc:1; + uint64_t hg2fld:1; + uint64_t undat:1; + uint64_t uneop:1; + uint64_t unsop:1; + uint64_t bad_term:1; + uint64_t bad_seq:1; + uint64_t rem_fault:1; + uint64_t loc_fault:1; + uint64_t pause_drp:1; + uint64_t phy_dupx:1; + uint64_t phy_spd:1; + uint64_t phy_link:1; + uint64_t ifgerr:1; + uint64_t coldet:1; + uint64_t falerr:1; + uint64_t rsverr:1; + uint64_t pcterr:1; + uint64_t ovrerr:1; + uint64_t niberr:1; + uint64_t skperr:1; + uint64_t rcverr:1; + uint64_t lenerr:1; + uint64_t alnerr:1; + uint64_t fcserr:1; + uint64_t jabber:1; + uint64_t maxerr:1; + uint64_t carext:1; + uint64_t minerr:1; + } s; + struct cvmx_gmxx_rxx_int_reg_cn30xx { + uint64_t reserved_19_63:45; + uint64_t phy_dupx:1; + uint64_t phy_spd:1; + uint64_t phy_link:1; + uint64_t ifgerr:1; + uint64_t coldet:1; + uint64_t falerr:1; + uint64_t rsverr:1; + uint64_t pcterr:1; + uint64_t ovrerr:1; + uint64_t niberr:1; + uint64_t skperr:1; + uint64_t rcverr:1; + uint64_t lenerr:1; + uint64_t alnerr:1; + uint64_t fcserr:1; + uint64_t jabber:1; + uint64_t maxerr:1; + uint64_t carext:1; + uint64_t minerr:1; + } cn30xx; + struct cvmx_gmxx_rxx_int_reg_cn30xx cn31xx; + struct cvmx_gmxx_rxx_int_reg_cn30xx cn38xx; + struct cvmx_gmxx_rxx_int_reg_cn30xx cn38xxp2; + struct cvmx_gmxx_rxx_int_reg_cn50xx { + uint64_t reserved_20_63:44; + uint64_t pause_drp:1; + uint64_t phy_dupx:1; + uint64_t phy_spd:1; + uint64_t phy_link:1; + uint64_t ifgerr:1; + uint64_t coldet:1; + uint64_t falerr:1; + uint64_t rsverr:1; + uint64_t pcterr:1; + uint64_t ovrerr:1; + uint64_t niberr:1; + uint64_t skperr:1; + uint64_t rcverr:1; + uint64_t reserved_6_6:1; + uint64_t alnerr:1; + uint64_t fcserr:1; + uint64_t jabber:1; + uint64_t reserved_2_2:1; + uint64_t carext:1; + uint64_t reserved_0_0:1; + } cn50xx; + struct cvmx_gmxx_rxx_int_reg_cn52xx { + uint64_t reserved_29_63:35; + uint64_t hg2cc:1; + uint64_t hg2fld:1; + uint64_t undat:1; + uint64_t uneop:1; + uint64_t unsop:1; + uint64_t bad_term:1; + uint64_t bad_seq:1; + uint64_t rem_fault:1; + uint64_t loc_fault:1; + uint64_t pause_drp:1; + uint64_t reserved_16_18:3; + uint64_t ifgerr:1; + uint64_t coldet:1; + uint64_t falerr:1; + uint64_t rsverr:1; + uint64_t pcterr:1; + uint64_t ovrerr:1; + uint64_t reserved_9_9:1; + uint64_t skperr:1; + uint64_t rcverr:1; + uint64_t reserved_5_6:2; + uint64_t fcserr:1; + uint64_t jabber:1; + uint64_t reserved_2_2:1; + uint64_t carext:1; + uint64_t reserved_0_0:1; + } cn52xx; + struct cvmx_gmxx_rxx_int_reg_cn52xx cn52xxp1; + struct cvmx_gmxx_rxx_int_reg_cn52xx cn56xx; + struct cvmx_gmxx_rxx_int_reg_cn56xxp1 { + uint64_t reserved_27_63:37; + uint64_t undat:1; + uint64_t uneop:1; + uint64_t unsop:1; + uint64_t bad_term:1; + uint64_t bad_seq:1; + uint64_t rem_fault:1; + uint64_t loc_fault:1; + uint64_t pause_drp:1; + uint64_t reserved_16_18:3; + uint64_t ifgerr:1; + uint64_t coldet:1; + uint64_t falerr:1; + uint64_t rsverr:1; + uint64_t pcterr:1; + uint64_t ovrerr:1; + uint64_t reserved_9_9:1; + uint64_t skperr:1; + uint64_t rcverr:1; + uint64_t reserved_5_6:2; + uint64_t fcserr:1; + uint64_t jabber:1; + uint64_t reserved_2_2:1; + uint64_t carext:1; + uint64_t reserved_0_0:1; + } cn56xxp1; + struct cvmx_gmxx_rxx_int_reg_cn58xx { + uint64_t reserved_20_63:44; + uint64_t pause_drp:1; + uint64_t phy_dupx:1; + uint64_t phy_spd:1; + uint64_t phy_link:1; + uint64_t ifgerr:1; + uint64_t coldet:1; + uint64_t falerr:1; + uint64_t rsverr:1; + uint64_t pcterr:1; + uint64_t ovrerr:1; + uint64_t niberr:1; + uint64_t skperr:1; + uint64_t rcverr:1; + uint64_t lenerr:1; + uint64_t alnerr:1; + uint64_t fcserr:1; + uint64_t jabber:1; + uint64_t maxerr:1; + uint64_t carext:1; + uint64_t minerr:1; + } cn58xx; + struct cvmx_gmxx_rxx_int_reg_cn58xx cn58xxp1; +}; + +union cvmx_gmxx_rxx_jabber { + uint64_t u64; + struct cvmx_gmxx_rxx_jabber_s { + uint64_t reserved_16_63:48; + uint64_t cnt:16; + } s; + struct cvmx_gmxx_rxx_jabber_s cn30xx; + struct cvmx_gmxx_rxx_jabber_s cn31xx; + struct cvmx_gmxx_rxx_jabber_s cn38xx; + struct cvmx_gmxx_rxx_jabber_s cn38xxp2; + struct cvmx_gmxx_rxx_jabber_s cn50xx; + struct cvmx_gmxx_rxx_jabber_s cn52xx; + struct cvmx_gmxx_rxx_jabber_s cn52xxp1; + struct cvmx_gmxx_rxx_jabber_s cn56xx; + struct cvmx_gmxx_rxx_jabber_s cn56xxp1; + struct cvmx_gmxx_rxx_jabber_s cn58xx; + struct cvmx_gmxx_rxx_jabber_s cn58xxp1; +}; + +union cvmx_gmxx_rxx_pause_drop_time { + uint64_t u64; + struct cvmx_gmxx_rxx_pause_drop_time_s { + uint64_t reserved_16_63:48; + uint64_t status:16; + } s; + struct cvmx_gmxx_rxx_pause_drop_time_s cn50xx; + struct cvmx_gmxx_rxx_pause_drop_time_s cn52xx; + struct cvmx_gmxx_rxx_pause_drop_time_s cn52xxp1; + struct cvmx_gmxx_rxx_pause_drop_time_s cn56xx; + struct cvmx_gmxx_rxx_pause_drop_time_s cn56xxp1; + struct cvmx_gmxx_rxx_pause_drop_time_s cn58xx; + struct cvmx_gmxx_rxx_pause_drop_time_s cn58xxp1; +}; + +union cvmx_gmxx_rxx_rx_inbnd { + uint64_t u64; + struct cvmx_gmxx_rxx_rx_inbnd_s { + uint64_t reserved_4_63:60; + uint64_t duplex:1; + uint64_t speed:2; + uint64_t status:1; + } s; + struct cvmx_gmxx_rxx_rx_inbnd_s cn30xx; + struct cvmx_gmxx_rxx_rx_inbnd_s cn31xx; + struct cvmx_gmxx_rxx_rx_inbnd_s cn38xx; + struct cvmx_gmxx_rxx_rx_inbnd_s cn38xxp2; + struct cvmx_gmxx_rxx_rx_inbnd_s cn50xx; + struct cvmx_gmxx_rxx_rx_inbnd_s cn58xx; + struct cvmx_gmxx_rxx_rx_inbnd_s cn58xxp1; +}; + +union cvmx_gmxx_rxx_stats_ctl { + uint64_t u64; + struct cvmx_gmxx_rxx_stats_ctl_s { + uint64_t reserved_1_63:63; + uint64_t rd_clr:1; + } s; + struct cvmx_gmxx_rxx_stats_ctl_s cn30xx; + struct cvmx_gmxx_rxx_stats_ctl_s cn31xx; + struct cvmx_gmxx_rxx_stats_ctl_s cn38xx; + struct cvmx_gmxx_rxx_stats_ctl_s cn38xxp2; + struct cvmx_gmxx_rxx_stats_ctl_s cn50xx; + struct cvmx_gmxx_rxx_stats_ctl_s cn52xx; + struct cvmx_gmxx_rxx_stats_ctl_s cn52xxp1; + struct cvmx_gmxx_rxx_stats_ctl_s cn56xx; + struct cvmx_gmxx_rxx_stats_ctl_s cn56xxp1; + struct cvmx_gmxx_rxx_stats_ctl_s cn58xx; + struct cvmx_gmxx_rxx_stats_ctl_s cn58xxp1; +}; + +union cvmx_gmxx_rxx_stats_octs { + uint64_t u64; + struct cvmx_gmxx_rxx_stats_octs_s { + uint64_t reserved_48_63:16; + uint64_t cnt:48; + } s; + struct cvmx_gmxx_rxx_stats_octs_s cn30xx; + struct cvmx_gmxx_rxx_stats_octs_s cn31xx; + struct cvmx_gmxx_rxx_stats_octs_s cn38xx; + struct cvmx_gmxx_rxx_stats_octs_s cn38xxp2; + struct cvmx_gmxx_rxx_stats_octs_s cn50xx; + struct cvmx_gmxx_rxx_stats_octs_s cn52xx; + struct cvmx_gmxx_rxx_stats_octs_s cn52xxp1; + struct cvmx_gmxx_rxx_stats_octs_s cn56xx; + struct cvmx_gmxx_rxx_stats_octs_s cn56xxp1; + struct cvmx_gmxx_rxx_stats_octs_s cn58xx; + struct cvmx_gmxx_rxx_stats_octs_s cn58xxp1; +}; + +union cvmx_gmxx_rxx_stats_octs_ctl { + uint64_t u64; + struct cvmx_gmxx_rxx_stats_octs_ctl_s { + uint64_t reserved_48_63:16; + uint64_t cnt:48; + } s; + struct cvmx_gmxx_rxx_stats_octs_ctl_s cn30xx; + struct cvmx_gmxx_rxx_stats_octs_ctl_s cn31xx; + struct cvmx_gmxx_rxx_stats_octs_ctl_s cn38xx; + struct cvmx_gmxx_rxx_stats_octs_ctl_s cn38xxp2; + struct cvmx_gmxx_rxx_stats_octs_ctl_s cn50xx; + struct cvmx_gmxx_rxx_stats_octs_ctl_s cn52xx; + struct cvmx_gmxx_rxx_stats_octs_ctl_s cn52xxp1; + struct cvmx_gmxx_rxx_stats_octs_ctl_s cn56xx; + struct cvmx_gmxx_rxx_stats_octs_ctl_s cn56xxp1; + struct cvmx_gmxx_rxx_stats_octs_ctl_s cn58xx; + struct cvmx_gmxx_rxx_stats_octs_ctl_s cn58xxp1; +}; + +union cvmx_gmxx_rxx_stats_octs_dmac { + uint64_t u64; + struct cvmx_gmxx_rxx_stats_octs_dmac_s { + uint64_t reserved_48_63:16; + uint64_t cnt:48; + } s; + struct cvmx_gmxx_rxx_stats_octs_dmac_s cn30xx; + struct cvmx_gmxx_rxx_stats_octs_dmac_s cn31xx; + struct cvmx_gmxx_rxx_stats_octs_dmac_s cn38xx; + struct cvmx_gmxx_rxx_stats_octs_dmac_s cn38xxp2; + struct cvmx_gmxx_rxx_stats_octs_dmac_s cn50xx; + struct cvmx_gmxx_rxx_stats_octs_dmac_s cn52xx; + struct cvmx_gmxx_rxx_stats_octs_dmac_s cn52xxp1; + struct cvmx_gmxx_rxx_stats_octs_dmac_s cn56xx; + struct cvmx_gmxx_rxx_stats_octs_dmac_s cn56xxp1; + struct cvmx_gmxx_rxx_stats_octs_dmac_s cn58xx; + struct cvmx_gmxx_rxx_stats_octs_dmac_s cn58xxp1; +}; + +union cvmx_gmxx_rxx_stats_octs_drp { + uint64_t u64; + struct cvmx_gmxx_rxx_stats_octs_drp_s { + uint64_t reserved_48_63:16; + uint64_t cnt:48; + } s; + struct cvmx_gmxx_rxx_stats_octs_drp_s cn30xx; + struct cvmx_gmxx_rxx_stats_octs_drp_s cn31xx; + struct cvmx_gmxx_rxx_stats_octs_drp_s cn38xx; + struct cvmx_gmxx_rxx_stats_octs_drp_s cn38xxp2; + struct cvmx_gmxx_rxx_stats_octs_drp_s cn50xx; + struct cvmx_gmxx_rxx_stats_octs_drp_s cn52xx; + struct cvmx_gmxx_rxx_stats_octs_drp_s cn52xxp1; + struct cvmx_gmxx_rxx_stats_octs_drp_s cn56xx; + struct cvmx_gmxx_rxx_stats_octs_drp_s cn56xxp1; + struct cvmx_gmxx_rxx_stats_octs_drp_s cn58xx; + struct cvmx_gmxx_rxx_stats_octs_drp_s cn58xxp1; +}; + +union cvmx_gmxx_rxx_stats_pkts { + uint64_t u64; + struct cvmx_gmxx_rxx_stats_pkts_s { + uint64_t reserved_32_63:32; + uint64_t cnt:32; + } s; + struct cvmx_gmxx_rxx_stats_pkts_s cn30xx; + struct cvmx_gmxx_rxx_stats_pkts_s cn31xx; + struct cvmx_gmxx_rxx_stats_pkts_s cn38xx; + struct cvmx_gmxx_rxx_stats_pkts_s cn38xxp2; + struct cvmx_gmxx_rxx_stats_pkts_s cn50xx; + struct cvmx_gmxx_rxx_stats_pkts_s cn52xx; + struct cvmx_gmxx_rxx_stats_pkts_s cn52xxp1; + struct cvmx_gmxx_rxx_stats_pkts_s cn56xx; + struct cvmx_gmxx_rxx_stats_pkts_s cn56xxp1; + struct cvmx_gmxx_rxx_stats_pkts_s cn58xx; + struct cvmx_gmxx_rxx_stats_pkts_s cn58xxp1; +}; + +union cvmx_gmxx_rxx_stats_pkts_bad { + uint64_t u64; + struct cvmx_gmxx_rxx_stats_pkts_bad_s { + uint64_t reserved_32_63:32; + uint64_t cnt:32; + } s; + struct cvmx_gmxx_rxx_stats_pkts_bad_s cn30xx; + struct cvmx_gmxx_rxx_stats_pkts_bad_s cn31xx; + struct cvmx_gmxx_rxx_stats_pkts_bad_s cn38xx; + struct cvmx_gmxx_rxx_stats_pkts_bad_s cn38xxp2; + struct cvmx_gmxx_rxx_stats_pkts_bad_s cn50xx; + struct cvmx_gmxx_rxx_stats_pkts_bad_s cn52xx; + struct cvmx_gmxx_rxx_stats_pkts_bad_s cn52xxp1; + struct cvmx_gmxx_rxx_stats_pkts_bad_s cn56xx; + struct cvmx_gmxx_rxx_stats_pkts_bad_s cn56xxp1; + struct cvmx_gmxx_rxx_stats_pkts_bad_s cn58xx; + struct cvmx_gmxx_rxx_stats_pkts_bad_s cn58xxp1; +}; + +union cvmx_gmxx_rxx_stats_pkts_ctl { + uint64_t u64; + struct cvmx_gmxx_rxx_stats_pkts_ctl_s { + uint64_t reserved_32_63:32; + uint64_t cnt:32; + } s; + struct cvmx_gmxx_rxx_stats_pkts_ctl_s cn30xx; + struct cvmx_gmxx_rxx_stats_pkts_ctl_s cn31xx; + struct cvmx_gmxx_rxx_stats_pkts_ctl_s cn38xx; + struct cvmx_gmxx_rxx_stats_pkts_ctl_s cn38xxp2; + struct cvmx_gmxx_rxx_stats_pkts_ctl_s cn50xx; + struct cvmx_gmxx_rxx_stats_pkts_ctl_s cn52xx; + struct cvmx_gmxx_rxx_stats_pkts_ctl_s cn52xxp1; + struct cvmx_gmxx_rxx_stats_pkts_ctl_s cn56xx; + struct cvmx_gmxx_rxx_stats_pkts_ctl_s cn56xxp1; + struct cvmx_gmxx_rxx_stats_pkts_ctl_s cn58xx; + struct cvmx_gmxx_rxx_stats_pkts_ctl_s cn58xxp1; +}; + +union cvmx_gmxx_rxx_stats_pkts_dmac { + uint64_t u64; + struct cvmx_gmxx_rxx_stats_pkts_dmac_s { + uint64_t reserved_32_63:32; + uint64_t cnt:32; + } s; + struct cvmx_gmxx_rxx_stats_pkts_dmac_s cn30xx; + struct cvmx_gmxx_rxx_stats_pkts_dmac_s cn31xx; + struct cvmx_gmxx_rxx_stats_pkts_dmac_s cn38xx; + struct cvmx_gmxx_rxx_stats_pkts_dmac_s cn38xxp2; + struct cvmx_gmxx_rxx_stats_pkts_dmac_s cn50xx; + struct cvmx_gmxx_rxx_stats_pkts_dmac_s cn52xx; + struct cvmx_gmxx_rxx_stats_pkts_dmac_s cn52xxp1; + struct cvmx_gmxx_rxx_stats_pkts_dmac_s cn56xx; + struct cvmx_gmxx_rxx_stats_pkts_dmac_s cn56xxp1; + struct cvmx_gmxx_rxx_stats_pkts_dmac_s cn58xx; + struct cvmx_gmxx_rxx_stats_pkts_dmac_s cn58xxp1; +}; + +union cvmx_gmxx_rxx_stats_pkts_drp { + uint64_t u64; + struct cvmx_gmxx_rxx_stats_pkts_drp_s { + uint64_t reserved_32_63:32; + uint64_t cnt:32; + } s; + struct cvmx_gmxx_rxx_stats_pkts_drp_s cn30xx; + struct cvmx_gmxx_rxx_stats_pkts_drp_s cn31xx; + struct cvmx_gmxx_rxx_stats_pkts_drp_s cn38xx; + struct cvmx_gmxx_rxx_stats_pkts_drp_s cn38xxp2; + struct cvmx_gmxx_rxx_stats_pkts_drp_s cn50xx; + struct cvmx_gmxx_rxx_stats_pkts_drp_s cn52xx; + struct cvmx_gmxx_rxx_stats_pkts_drp_s cn52xxp1; + struct cvmx_gmxx_rxx_stats_pkts_drp_s cn56xx; + struct cvmx_gmxx_rxx_stats_pkts_drp_s cn56xxp1; + struct cvmx_gmxx_rxx_stats_pkts_drp_s cn58xx; + struct cvmx_gmxx_rxx_stats_pkts_drp_s cn58xxp1; +}; + +union cvmx_gmxx_rxx_udd_skp { + uint64_t u64; + struct cvmx_gmxx_rxx_udd_skp_s { + uint64_t reserved_9_63:55; + uint64_t fcssel:1; + uint64_t reserved_7_7:1; + uint64_t len:7; + } s; + struct cvmx_gmxx_rxx_udd_skp_s cn30xx; + struct cvmx_gmxx_rxx_udd_skp_s cn31xx; + struct cvmx_gmxx_rxx_udd_skp_s cn38xx; + struct cvmx_gmxx_rxx_udd_skp_s cn38xxp2; + struct cvmx_gmxx_rxx_udd_skp_s cn50xx; + struct cvmx_gmxx_rxx_udd_skp_s cn52xx; + struct cvmx_gmxx_rxx_udd_skp_s cn52xxp1; + struct cvmx_gmxx_rxx_udd_skp_s cn56xx; + struct cvmx_gmxx_rxx_udd_skp_s cn56xxp1; + struct cvmx_gmxx_rxx_udd_skp_s cn58xx; + struct cvmx_gmxx_rxx_udd_skp_s cn58xxp1; +}; + +union cvmx_gmxx_rx_bp_dropx { + uint64_t u64; + struct cvmx_gmxx_rx_bp_dropx_s { + uint64_t reserved_6_63:58; + uint64_t mark:6; + } s; + struct cvmx_gmxx_rx_bp_dropx_s cn30xx; + struct cvmx_gmxx_rx_bp_dropx_s cn31xx; + struct cvmx_gmxx_rx_bp_dropx_s cn38xx; + struct cvmx_gmxx_rx_bp_dropx_s cn38xxp2; + struct cvmx_gmxx_rx_bp_dropx_s cn50xx; + struct cvmx_gmxx_rx_bp_dropx_s cn52xx; + struct cvmx_gmxx_rx_bp_dropx_s cn52xxp1; + struct cvmx_gmxx_rx_bp_dropx_s cn56xx; + struct cvmx_gmxx_rx_bp_dropx_s cn56xxp1; + struct cvmx_gmxx_rx_bp_dropx_s cn58xx; + struct cvmx_gmxx_rx_bp_dropx_s cn58xxp1; +}; + +union cvmx_gmxx_rx_bp_offx { + uint64_t u64; + struct cvmx_gmxx_rx_bp_offx_s { + uint64_t reserved_6_63:58; + uint64_t mark:6; + } s; + struct cvmx_gmxx_rx_bp_offx_s cn30xx; + struct cvmx_gmxx_rx_bp_offx_s cn31xx; + struct cvmx_gmxx_rx_bp_offx_s cn38xx; + struct cvmx_gmxx_rx_bp_offx_s cn38xxp2; + struct cvmx_gmxx_rx_bp_offx_s cn50xx; + struct cvmx_gmxx_rx_bp_offx_s cn52xx; + struct cvmx_gmxx_rx_bp_offx_s cn52xxp1; + struct cvmx_gmxx_rx_bp_offx_s cn56xx; + struct cvmx_gmxx_rx_bp_offx_s cn56xxp1; + struct cvmx_gmxx_rx_bp_offx_s cn58xx; + struct cvmx_gmxx_rx_bp_offx_s cn58xxp1; +}; + +union cvmx_gmxx_rx_bp_onx { + uint64_t u64; + struct cvmx_gmxx_rx_bp_onx_s { + uint64_t reserved_9_63:55; + uint64_t mark:9; + } s; + struct cvmx_gmxx_rx_bp_onx_s cn30xx; + struct cvmx_gmxx_rx_bp_onx_s cn31xx; + struct cvmx_gmxx_rx_bp_onx_s cn38xx; + struct cvmx_gmxx_rx_bp_onx_s cn38xxp2; + struct cvmx_gmxx_rx_bp_onx_s cn50xx; + struct cvmx_gmxx_rx_bp_onx_s cn52xx; + struct cvmx_gmxx_rx_bp_onx_s cn52xxp1; + struct cvmx_gmxx_rx_bp_onx_s cn56xx; + struct cvmx_gmxx_rx_bp_onx_s cn56xxp1; + struct cvmx_gmxx_rx_bp_onx_s cn58xx; + struct cvmx_gmxx_rx_bp_onx_s cn58xxp1; +}; + +union cvmx_gmxx_rx_hg2_status { + uint64_t u64; + struct cvmx_gmxx_rx_hg2_status_s { + uint64_t reserved_48_63:16; + uint64_t phtim2go:16; + uint64_t xof:16; + uint64_t lgtim2go:16; + } s; + struct cvmx_gmxx_rx_hg2_status_s cn52xx; + struct cvmx_gmxx_rx_hg2_status_s cn52xxp1; + struct cvmx_gmxx_rx_hg2_status_s cn56xx; +}; + +union cvmx_gmxx_rx_pass_en { + uint64_t u64; + struct cvmx_gmxx_rx_pass_en_s { + uint64_t reserved_16_63:48; + uint64_t en:16; + } s; + struct cvmx_gmxx_rx_pass_en_s cn38xx; + struct cvmx_gmxx_rx_pass_en_s cn38xxp2; + struct cvmx_gmxx_rx_pass_en_s cn58xx; + struct cvmx_gmxx_rx_pass_en_s cn58xxp1; +}; + +union cvmx_gmxx_rx_pass_mapx { + uint64_t u64; + struct cvmx_gmxx_rx_pass_mapx_s { + uint64_t reserved_4_63:60; + uint64_t dprt:4; + } s; + struct cvmx_gmxx_rx_pass_mapx_s cn38xx; + struct cvmx_gmxx_rx_pass_mapx_s cn38xxp2; + struct cvmx_gmxx_rx_pass_mapx_s cn58xx; + struct cvmx_gmxx_rx_pass_mapx_s cn58xxp1; +}; + +union cvmx_gmxx_rx_prt_info { + uint64_t u64; + struct cvmx_gmxx_rx_prt_info_s { + uint64_t reserved_32_63:32; + uint64_t drop:16; + uint64_t commit:16; + } s; + struct cvmx_gmxx_rx_prt_info_cn30xx { + uint64_t reserved_19_63:45; + uint64_t drop:3; + uint64_t reserved_3_15:13; + uint64_t commit:3; + } cn30xx; + struct cvmx_gmxx_rx_prt_info_cn30xx cn31xx; + struct cvmx_gmxx_rx_prt_info_s cn38xx; + struct cvmx_gmxx_rx_prt_info_cn30xx cn50xx; + struct cvmx_gmxx_rx_prt_info_cn52xx { + uint64_t reserved_20_63:44; + uint64_t drop:4; + uint64_t reserved_4_15:12; + uint64_t commit:4; + } cn52xx; + struct cvmx_gmxx_rx_prt_info_cn52xx cn52xxp1; + struct cvmx_gmxx_rx_prt_info_cn52xx cn56xx; + struct cvmx_gmxx_rx_prt_info_cn52xx cn56xxp1; + struct cvmx_gmxx_rx_prt_info_s cn58xx; + struct cvmx_gmxx_rx_prt_info_s cn58xxp1; +}; + +union cvmx_gmxx_rx_prts { + uint64_t u64; + struct cvmx_gmxx_rx_prts_s { + uint64_t reserved_3_63:61; + uint64_t prts:3; + } s; + struct cvmx_gmxx_rx_prts_s cn30xx; + struct cvmx_gmxx_rx_prts_s cn31xx; + struct cvmx_gmxx_rx_prts_s cn38xx; + struct cvmx_gmxx_rx_prts_s cn38xxp2; + struct cvmx_gmxx_rx_prts_s cn50xx; + struct cvmx_gmxx_rx_prts_s cn52xx; + struct cvmx_gmxx_rx_prts_s cn52xxp1; + struct cvmx_gmxx_rx_prts_s cn56xx; + struct cvmx_gmxx_rx_prts_s cn56xxp1; + struct cvmx_gmxx_rx_prts_s cn58xx; + struct cvmx_gmxx_rx_prts_s cn58xxp1; +}; + +union cvmx_gmxx_rx_tx_status { + uint64_t u64; + struct cvmx_gmxx_rx_tx_status_s { + uint64_t reserved_7_63:57; + uint64_t tx:3; + uint64_t reserved_3_3:1; + uint64_t rx:3; + } s; + struct cvmx_gmxx_rx_tx_status_s cn30xx; + struct cvmx_gmxx_rx_tx_status_s cn31xx; + struct cvmx_gmxx_rx_tx_status_s cn50xx; +}; + +union cvmx_gmxx_rx_xaui_bad_col { + uint64_t u64; + struct cvmx_gmxx_rx_xaui_bad_col_s { + uint64_t reserved_40_63:24; + uint64_t val:1; + uint64_t state:3; + uint64_t lane_rxc:4; + uint64_t lane_rxd:32; + } s; + struct cvmx_gmxx_rx_xaui_bad_col_s cn52xx; + struct cvmx_gmxx_rx_xaui_bad_col_s cn52xxp1; + struct cvmx_gmxx_rx_xaui_bad_col_s cn56xx; + struct cvmx_gmxx_rx_xaui_bad_col_s cn56xxp1; +}; + +union cvmx_gmxx_rx_xaui_ctl { + uint64_t u64; + struct cvmx_gmxx_rx_xaui_ctl_s { + uint64_t reserved_2_63:62; + uint64_t status:2; + } s; + struct cvmx_gmxx_rx_xaui_ctl_s cn52xx; + struct cvmx_gmxx_rx_xaui_ctl_s cn52xxp1; + struct cvmx_gmxx_rx_xaui_ctl_s cn56xx; + struct cvmx_gmxx_rx_xaui_ctl_s cn56xxp1; +}; + +union cvmx_gmxx_smacx { + uint64_t u64; + struct cvmx_gmxx_smacx_s { + uint64_t reserved_48_63:16; + uint64_t smac:48; + } s; + struct cvmx_gmxx_smacx_s cn30xx; + struct cvmx_gmxx_smacx_s cn31xx; + struct cvmx_gmxx_smacx_s cn38xx; + struct cvmx_gmxx_smacx_s cn38xxp2; + struct cvmx_gmxx_smacx_s cn50xx; + struct cvmx_gmxx_smacx_s cn52xx; + struct cvmx_gmxx_smacx_s cn52xxp1; + struct cvmx_gmxx_smacx_s cn56xx; + struct cvmx_gmxx_smacx_s cn56xxp1; + struct cvmx_gmxx_smacx_s cn58xx; + struct cvmx_gmxx_smacx_s cn58xxp1; +}; + +union cvmx_gmxx_stat_bp { + uint64_t u64; + struct cvmx_gmxx_stat_bp_s { + uint64_t reserved_17_63:47; + uint64_t bp:1; + uint64_t cnt:16; + } s; + struct cvmx_gmxx_stat_bp_s cn30xx; + struct cvmx_gmxx_stat_bp_s cn31xx; + struct cvmx_gmxx_stat_bp_s cn38xx; + struct cvmx_gmxx_stat_bp_s cn38xxp2; + struct cvmx_gmxx_stat_bp_s cn50xx; + struct cvmx_gmxx_stat_bp_s cn52xx; + struct cvmx_gmxx_stat_bp_s cn52xxp1; + struct cvmx_gmxx_stat_bp_s cn56xx; + struct cvmx_gmxx_stat_bp_s cn56xxp1; + struct cvmx_gmxx_stat_bp_s cn58xx; + struct cvmx_gmxx_stat_bp_s cn58xxp1; +}; + +union cvmx_gmxx_txx_append { + uint64_t u64; + struct cvmx_gmxx_txx_append_s { + uint64_t reserved_4_63:60; + uint64_t force_fcs:1; + uint64_t fcs:1; + uint64_t pad:1; + uint64_t preamble:1; + } s; + struct cvmx_gmxx_txx_append_s cn30xx; + struct cvmx_gmxx_txx_append_s cn31xx; + struct cvmx_gmxx_txx_append_s cn38xx; + struct cvmx_gmxx_txx_append_s cn38xxp2; + struct cvmx_gmxx_txx_append_s cn50xx; + struct cvmx_gmxx_txx_append_s cn52xx; + struct cvmx_gmxx_txx_append_s cn52xxp1; + struct cvmx_gmxx_txx_append_s cn56xx; + struct cvmx_gmxx_txx_append_s cn56xxp1; + struct cvmx_gmxx_txx_append_s cn58xx; + struct cvmx_gmxx_txx_append_s cn58xxp1; +}; + +union cvmx_gmxx_txx_burst { + uint64_t u64; + struct cvmx_gmxx_txx_burst_s { + uint64_t reserved_16_63:48; + uint64_t burst:16; + } s; + struct cvmx_gmxx_txx_burst_s cn30xx; + struct cvmx_gmxx_txx_burst_s cn31xx; + struct cvmx_gmxx_txx_burst_s cn38xx; + struct cvmx_gmxx_txx_burst_s cn38xxp2; + struct cvmx_gmxx_txx_burst_s cn50xx; + struct cvmx_gmxx_txx_burst_s cn52xx; + struct cvmx_gmxx_txx_burst_s cn52xxp1; + struct cvmx_gmxx_txx_burst_s cn56xx; + struct cvmx_gmxx_txx_burst_s cn56xxp1; + struct cvmx_gmxx_txx_burst_s cn58xx; + struct cvmx_gmxx_txx_burst_s cn58xxp1; +}; + +union cvmx_gmxx_txx_cbfc_xoff { + uint64_t u64; + struct cvmx_gmxx_txx_cbfc_xoff_s { + uint64_t reserved_16_63:48; + uint64_t xoff:16; + } s; + struct cvmx_gmxx_txx_cbfc_xoff_s cn52xx; + struct cvmx_gmxx_txx_cbfc_xoff_s cn56xx; +}; + +union cvmx_gmxx_txx_cbfc_xon { + uint64_t u64; + struct cvmx_gmxx_txx_cbfc_xon_s { + uint64_t reserved_16_63:48; + uint64_t xon:16; + } s; + struct cvmx_gmxx_txx_cbfc_xon_s cn52xx; + struct cvmx_gmxx_txx_cbfc_xon_s cn56xx; +}; + +union cvmx_gmxx_txx_clk { + uint64_t u64; + struct cvmx_gmxx_txx_clk_s { + uint64_t reserved_6_63:58; + uint64_t clk_cnt:6; + } s; + struct cvmx_gmxx_txx_clk_s cn30xx; + struct cvmx_gmxx_txx_clk_s cn31xx; + struct cvmx_gmxx_txx_clk_s cn38xx; + struct cvmx_gmxx_txx_clk_s cn38xxp2; + struct cvmx_gmxx_txx_clk_s cn50xx; + struct cvmx_gmxx_txx_clk_s cn58xx; + struct cvmx_gmxx_txx_clk_s cn58xxp1; +}; + +union cvmx_gmxx_txx_ctl { + uint64_t u64; + struct cvmx_gmxx_txx_ctl_s { + uint64_t reserved_2_63:62; + uint64_t xsdef_en:1; + uint64_t xscol_en:1; + } s; + struct cvmx_gmxx_txx_ctl_s cn30xx; + struct cvmx_gmxx_txx_ctl_s cn31xx; + struct cvmx_gmxx_txx_ctl_s cn38xx; + struct cvmx_gmxx_txx_ctl_s cn38xxp2; + struct cvmx_gmxx_txx_ctl_s cn50xx; + struct cvmx_gmxx_txx_ctl_s cn52xx; + struct cvmx_gmxx_txx_ctl_s cn52xxp1; + struct cvmx_gmxx_txx_ctl_s cn56xx; + struct cvmx_gmxx_txx_ctl_s cn56xxp1; + struct cvmx_gmxx_txx_ctl_s cn58xx; + struct cvmx_gmxx_txx_ctl_s cn58xxp1; +}; + +union cvmx_gmxx_txx_min_pkt { + uint64_t u64; + struct cvmx_gmxx_txx_min_pkt_s { + uint64_t reserved_8_63:56; + uint64_t min_size:8; + } s; + struct cvmx_gmxx_txx_min_pkt_s cn30xx; + struct cvmx_gmxx_txx_min_pkt_s cn31xx; + struct cvmx_gmxx_txx_min_pkt_s cn38xx; + struct cvmx_gmxx_txx_min_pkt_s cn38xxp2; + struct cvmx_gmxx_txx_min_pkt_s cn50xx; + struct cvmx_gmxx_txx_min_pkt_s cn52xx; + struct cvmx_gmxx_txx_min_pkt_s cn52xxp1; + struct cvmx_gmxx_txx_min_pkt_s cn56xx; + struct cvmx_gmxx_txx_min_pkt_s cn56xxp1; + struct cvmx_gmxx_txx_min_pkt_s cn58xx; + struct cvmx_gmxx_txx_min_pkt_s cn58xxp1; +}; + +union cvmx_gmxx_txx_pause_pkt_interval { + uint64_t u64; + struct cvmx_gmxx_txx_pause_pkt_interval_s { + uint64_t reserved_16_63:48; + uint64_t interval:16; + } s; + struct cvmx_gmxx_txx_pause_pkt_interval_s cn30xx; + struct cvmx_gmxx_txx_pause_pkt_interval_s cn31xx; + struct cvmx_gmxx_txx_pause_pkt_interval_s cn38xx; + struct cvmx_gmxx_txx_pause_pkt_interval_s cn38xxp2; + struct cvmx_gmxx_txx_pause_pkt_interval_s cn50xx; + struct cvmx_gmxx_txx_pause_pkt_interval_s cn52xx; + struct cvmx_gmxx_txx_pause_pkt_interval_s cn52xxp1; + struct cvmx_gmxx_txx_pause_pkt_interval_s cn56xx; + struct cvmx_gmxx_txx_pause_pkt_interval_s cn56xxp1; + struct cvmx_gmxx_txx_pause_pkt_interval_s cn58xx; + struct cvmx_gmxx_txx_pause_pkt_interval_s cn58xxp1; +}; + +union cvmx_gmxx_txx_pause_pkt_time { + uint64_t u64; + struct cvmx_gmxx_txx_pause_pkt_time_s { + uint64_t reserved_16_63:48; + uint64_t time:16; + } s; + struct cvmx_gmxx_txx_pause_pkt_time_s cn30xx; + struct cvmx_gmxx_txx_pause_pkt_time_s cn31xx; + struct cvmx_gmxx_txx_pause_pkt_time_s cn38xx; + struct cvmx_gmxx_txx_pause_pkt_time_s cn38xxp2; + struct cvmx_gmxx_txx_pause_pkt_time_s cn50xx; + struct cvmx_gmxx_txx_pause_pkt_time_s cn52xx; + struct cvmx_gmxx_txx_pause_pkt_time_s cn52xxp1; + struct cvmx_gmxx_txx_pause_pkt_time_s cn56xx; + struct cvmx_gmxx_txx_pause_pkt_time_s cn56xxp1; + struct cvmx_gmxx_txx_pause_pkt_time_s cn58xx; + struct cvmx_gmxx_txx_pause_pkt_time_s cn58xxp1; +}; + +union cvmx_gmxx_txx_pause_togo { + uint64_t u64; + struct cvmx_gmxx_txx_pause_togo_s { + uint64_t reserved_32_63:32; + uint64_t msg_time:16; + uint64_t time:16; + } s; + struct cvmx_gmxx_txx_pause_togo_cn30xx { + uint64_t reserved_16_63:48; + uint64_t time:16; + } cn30xx; + struct cvmx_gmxx_txx_pause_togo_cn30xx cn31xx; + struct cvmx_gmxx_txx_pause_togo_cn30xx cn38xx; + struct cvmx_gmxx_txx_pause_togo_cn30xx cn38xxp2; + struct cvmx_gmxx_txx_pause_togo_cn30xx cn50xx; + struct cvmx_gmxx_txx_pause_togo_s cn52xx; + struct cvmx_gmxx_txx_pause_togo_s cn52xxp1; + struct cvmx_gmxx_txx_pause_togo_s cn56xx; + struct cvmx_gmxx_txx_pause_togo_cn30xx cn56xxp1; + struct cvmx_gmxx_txx_pause_togo_cn30xx cn58xx; + struct cvmx_gmxx_txx_pause_togo_cn30xx cn58xxp1; +}; + +union cvmx_gmxx_txx_pause_zero { + uint64_t u64; + struct cvmx_gmxx_txx_pause_zero_s { + uint64_t reserved_1_63:63; + uint64_t send:1; + } s; + struct cvmx_gmxx_txx_pause_zero_s cn30xx; + struct cvmx_gmxx_txx_pause_zero_s cn31xx; + struct cvmx_gmxx_txx_pause_zero_s cn38xx; + struct cvmx_gmxx_txx_pause_zero_s cn38xxp2; + struct cvmx_gmxx_txx_pause_zero_s cn50xx; + struct cvmx_gmxx_txx_pause_zero_s cn52xx; + struct cvmx_gmxx_txx_pause_zero_s cn52xxp1; + struct cvmx_gmxx_txx_pause_zero_s cn56xx; + struct cvmx_gmxx_txx_pause_zero_s cn56xxp1; + struct cvmx_gmxx_txx_pause_zero_s cn58xx; + struct cvmx_gmxx_txx_pause_zero_s cn58xxp1; +}; + +union cvmx_gmxx_txx_sgmii_ctl { + uint64_t u64; + struct cvmx_gmxx_txx_sgmii_ctl_s { + uint64_t reserved_1_63:63; + uint64_t align:1; + } s; + struct cvmx_gmxx_txx_sgmii_ctl_s cn52xx; + struct cvmx_gmxx_txx_sgmii_ctl_s cn52xxp1; + struct cvmx_gmxx_txx_sgmii_ctl_s cn56xx; + struct cvmx_gmxx_txx_sgmii_ctl_s cn56xxp1; +}; + +union cvmx_gmxx_txx_slot { + uint64_t u64; + struct cvmx_gmxx_txx_slot_s { + uint64_t reserved_10_63:54; + uint64_t slot:10; + } s; + struct cvmx_gmxx_txx_slot_s cn30xx; + struct cvmx_gmxx_txx_slot_s cn31xx; + struct cvmx_gmxx_txx_slot_s cn38xx; + struct cvmx_gmxx_txx_slot_s cn38xxp2; + struct cvmx_gmxx_txx_slot_s cn50xx; + struct cvmx_gmxx_txx_slot_s cn52xx; + struct cvmx_gmxx_txx_slot_s cn52xxp1; + struct cvmx_gmxx_txx_slot_s cn56xx; + struct cvmx_gmxx_txx_slot_s cn56xxp1; + struct cvmx_gmxx_txx_slot_s cn58xx; + struct cvmx_gmxx_txx_slot_s cn58xxp1; +}; + +union cvmx_gmxx_txx_soft_pause { + uint64_t u64; + struct cvmx_gmxx_txx_soft_pause_s { + uint64_t reserved_16_63:48; + uint64_t time:16; + } s; + struct cvmx_gmxx_txx_soft_pause_s cn30xx; + struct cvmx_gmxx_txx_soft_pause_s cn31xx; + struct cvmx_gmxx_txx_soft_pause_s cn38xx; + struct cvmx_gmxx_txx_soft_pause_s cn38xxp2; + struct cvmx_gmxx_txx_soft_pause_s cn50xx; + struct cvmx_gmxx_txx_soft_pause_s cn52xx; + struct cvmx_gmxx_txx_soft_pause_s cn52xxp1; + struct cvmx_gmxx_txx_soft_pause_s cn56xx; + struct cvmx_gmxx_txx_soft_pause_s cn56xxp1; + struct cvmx_gmxx_txx_soft_pause_s cn58xx; + struct cvmx_gmxx_txx_soft_pause_s cn58xxp1; +}; + +union cvmx_gmxx_txx_stat0 { + uint64_t u64; + struct cvmx_gmxx_txx_stat0_s { + uint64_t xsdef:32; + uint64_t xscol:32; + } s; + struct cvmx_gmxx_txx_stat0_s cn30xx; + struct cvmx_gmxx_txx_stat0_s cn31xx; + struct cvmx_gmxx_txx_stat0_s cn38xx; + struct cvmx_gmxx_txx_stat0_s cn38xxp2; + struct cvmx_gmxx_txx_stat0_s cn50xx; + struct cvmx_gmxx_txx_stat0_s cn52xx; + struct cvmx_gmxx_txx_stat0_s cn52xxp1; + struct cvmx_gmxx_txx_stat0_s cn56xx; + struct cvmx_gmxx_txx_stat0_s cn56xxp1; + struct cvmx_gmxx_txx_stat0_s cn58xx; + struct cvmx_gmxx_txx_stat0_s cn58xxp1; +}; + +union cvmx_gmxx_txx_stat1 { + uint64_t u64; + struct cvmx_gmxx_txx_stat1_s { + uint64_t scol:32; + uint64_t mcol:32; + } s; + struct cvmx_gmxx_txx_stat1_s cn30xx; + struct cvmx_gmxx_txx_stat1_s cn31xx; + struct cvmx_gmxx_txx_stat1_s cn38xx; + struct cvmx_gmxx_txx_stat1_s cn38xxp2; + struct cvmx_gmxx_txx_stat1_s cn50xx; + struct cvmx_gmxx_txx_stat1_s cn52xx; + struct cvmx_gmxx_txx_stat1_s cn52xxp1; + struct cvmx_gmxx_txx_stat1_s cn56xx; + struct cvmx_gmxx_txx_stat1_s cn56xxp1; + struct cvmx_gmxx_txx_stat1_s cn58xx; + struct cvmx_gmxx_txx_stat1_s cn58xxp1; +}; + +union cvmx_gmxx_txx_stat2 { + uint64_t u64; + struct cvmx_gmxx_txx_stat2_s { + uint64_t reserved_48_63:16; + uint64_t octs:48; + } s; + struct cvmx_gmxx_txx_stat2_s cn30xx; + struct cvmx_gmxx_txx_stat2_s cn31xx; + struct cvmx_gmxx_txx_stat2_s cn38xx; + struct cvmx_gmxx_txx_stat2_s cn38xxp2; + struct cvmx_gmxx_txx_stat2_s cn50xx; + struct cvmx_gmxx_txx_stat2_s cn52xx; + struct cvmx_gmxx_txx_stat2_s cn52xxp1; + struct cvmx_gmxx_txx_stat2_s cn56xx; + struct cvmx_gmxx_txx_stat2_s cn56xxp1; + struct cvmx_gmxx_txx_stat2_s cn58xx; + struct cvmx_gmxx_txx_stat2_s cn58xxp1; +}; + +union cvmx_gmxx_txx_stat3 { + uint64_t u64; + struct cvmx_gmxx_txx_stat3_s { + uint64_t reserved_32_63:32; + uint64_t pkts:32; + } s; + struct cvmx_gmxx_txx_stat3_s cn30xx; + struct cvmx_gmxx_txx_stat3_s cn31xx; + struct cvmx_gmxx_txx_stat3_s cn38xx; + struct cvmx_gmxx_txx_stat3_s cn38xxp2; + struct cvmx_gmxx_txx_stat3_s cn50xx; + struct cvmx_gmxx_txx_stat3_s cn52xx; + struct cvmx_gmxx_txx_stat3_s cn52xxp1; + struct cvmx_gmxx_txx_stat3_s cn56xx; + struct cvmx_gmxx_txx_stat3_s cn56xxp1; + struct cvmx_gmxx_txx_stat3_s cn58xx; + struct cvmx_gmxx_txx_stat3_s cn58xxp1; +}; + +union cvmx_gmxx_txx_stat4 { + uint64_t u64; + struct cvmx_gmxx_txx_stat4_s { + uint64_t hist1:32; + uint64_t hist0:32; + } s; + struct cvmx_gmxx_txx_stat4_s cn30xx; + struct cvmx_gmxx_txx_stat4_s cn31xx; + struct cvmx_gmxx_txx_stat4_s cn38xx; + struct cvmx_gmxx_txx_stat4_s cn38xxp2; + struct cvmx_gmxx_txx_stat4_s cn50xx; + struct cvmx_gmxx_txx_stat4_s cn52xx; + struct cvmx_gmxx_txx_stat4_s cn52xxp1; + struct cvmx_gmxx_txx_stat4_s cn56xx; + struct cvmx_gmxx_txx_stat4_s cn56xxp1; + struct cvmx_gmxx_txx_stat4_s cn58xx; + struct cvmx_gmxx_txx_stat4_s cn58xxp1; +}; + +union cvmx_gmxx_txx_stat5 { + uint64_t u64; + struct cvmx_gmxx_txx_stat5_s { + uint64_t hist3:32; + uint64_t hist2:32; + } s; + struct cvmx_gmxx_txx_stat5_s cn30xx; + struct cvmx_gmxx_txx_stat5_s cn31xx; + struct cvmx_gmxx_txx_stat5_s cn38xx; + struct cvmx_gmxx_txx_stat5_s cn38xxp2; + struct cvmx_gmxx_txx_stat5_s cn50xx; + struct cvmx_gmxx_txx_stat5_s cn52xx; + struct cvmx_gmxx_txx_stat5_s cn52xxp1; + struct cvmx_gmxx_txx_stat5_s cn56xx; + struct cvmx_gmxx_txx_stat5_s cn56xxp1; + struct cvmx_gmxx_txx_stat5_s cn58xx; + struct cvmx_gmxx_txx_stat5_s cn58xxp1; +}; + +union cvmx_gmxx_txx_stat6 { + uint64_t u64; + struct cvmx_gmxx_txx_stat6_s { + uint64_t hist5:32; + uint64_t hist4:32; + } s; + struct cvmx_gmxx_txx_stat6_s cn30xx; + struct cvmx_gmxx_txx_stat6_s cn31xx; + struct cvmx_gmxx_txx_stat6_s cn38xx; + struct cvmx_gmxx_txx_stat6_s cn38xxp2; + struct cvmx_gmxx_txx_stat6_s cn50xx; + struct cvmx_gmxx_txx_stat6_s cn52xx; + struct cvmx_gmxx_txx_stat6_s cn52xxp1; + struct cvmx_gmxx_txx_stat6_s cn56xx; + struct cvmx_gmxx_txx_stat6_s cn56xxp1; + struct cvmx_gmxx_txx_stat6_s cn58xx; + struct cvmx_gmxx_txx_stat6_s cn58xxp1; +}; + +union cvmx_gmxx_txx_stat7 { + uint64_t u64; + struct cvmx_gmxx_txx_stat7_s { + uint64_t hist7:32; + uint64_t hist6:32; + } s; + struct cvmx_gmxx_txx_stat7_s cn30xx; + struct cvmx_gmxx_txx_stat7_s cn31xx; + struct cvmx_gmxx_txx_stat7_s cn38xx; + struct cvmx_gmxx_txx_stat7_s cn38xxp2; + struct cvmx_gmxx_txx_stat7_s cn50xx; + struct cvmx_gmxx_txx_stat7_s cn52xx; + struct cvmx_gmxx_txx_stat7_s cn52xxp1; + struct cvmx_gmxx_txx_stat7_s cn56xx; + struct cvmx_gmxx_txx_stat7_s cn56xxp1; + struct cvmx_gmxx_txx_stat7_s cn58xx; + struct cvmx_gmxx_txx_stat7_s cn58xxp1; +}; + +union cvmx_gmxx_txx_stat8 { + uint64_t u64; + struct cvmx_gmxx_txx_stat8_s { + uint64_t mcst:32; + uint64_t bcst:32; + } s; + struct cvmx_gmxx_txx_stat8_s cn30xx; + struct cvmx_gmxx_txx_stat8_s cn31xx; + struct cvmx_gmxx_txx_stat8_s cn38xx; + struct cvmx_gmxx_txx_stat8_s cn38xxp2; + struct cvmx_gmxx_txx_stat8_s cn50xx; + struct cvmx_gmxx_txx_stat8_s cn52xx; + struct cvmx_gmxx_txx_stat8_s cn52xxp1; + struct cvmx_gmxx_txx_stat8_s cn56xx; + struct cvmx_gmxx_txx_stat8_s cn56xxp1; + struct cvmx_gmxx_txx_stat8_s cn58xx; + struct cvmx_gmxx_txx_stat8_s cn58xxp1; +}; + +union cvmx_gmxx_txx_stat9 { + uint64_t u64; + struct cvmx_gmxx_txx_stat9_s { + uint64_t undflw:32; + uint64_t ctl:32; + } s; + struct cvmx_gmxx_txx_stat9_s cn30xx; + struct cvmx_gmxx_txx_stat9_s cn31xx; + struct cvmx_gmxx_txx_stat9_s cn38xx; + struct cvmx_gmxx_txx_stat9_s cn38xxp2; + struct cvmx_gmxx_txx_stat9_s cn50xx; + struct cvmx_gmxx_txx_stat9_s cn52xx; + struct cvmx_gmxx_txx_stat9_s cn52xxp1; + struct cvmx_gmxx_txx_stat9_s cn56xx; + struct cvmx_gmxx_txx_stat9_s cn56xxp1; + struct cvmx_gmxx_txx_stat9_s cn58xx; + struct cvmx_gmxx_txx_stat9_s cn58xxp1; +}; + +union cvmx_gmxx_txx_stats_ctl { + uint64_t u64; + struct cvmx_gmxx_txx_stats_ctl_s { + uint64_t reserved_1_63:63; + uint64_t rd_clr:1; + } s; + struct cvmx_gmxx_txx_stats_ctl_s cn30xx; + struct cvmx_gmxx_txx_stats_ctl_s cn31xx; + struct cvmx_gmxx_txx_stats_ctl_s cn38xx; + struct cvmx_gmxx_txx_stats_ctl_s cn38xxp2; + struct cvmx_gmxx_txx_stats_ctl_s cn50xx; + struct cvmx_gmxx_txx_stats_ctl_s cn52xx; + struct cvmx_gmxx_txx_stats_ctl_s cn52xxp1; + struct cvmx_gmxx_txx_stats_ctl_s cn56xx; + struct cvmx_gmxx_txx_stats_ctl_s cn56xxp1; + struct cvmx_gmxx_txx_stats_ctl_s cn58xx; + struct cvmx_gmxx_txx_stats_ctl_s cn58xxp1; +}; + +union cvmx_gmxx_txx_thresh { + uint64_t u64; + struct cvmx_gmxx_txx_thresh_s { + uint64_t reserved_9_63:55; + uint64_t cnt:9; + } s; + struct cvmx_gmxx_txx_thresh_cn30xx { + uint64_t reserved_7_63:57; + uint64_t cnt:7; + } cn30xx; + struct cvmx_gmxx_txx_thresh_cn30xx cn31xx; + struct cvmx_gmxx_txx_thresh_s cn38xx; + struct cvmx_gmxx_txx_thresh_s cn38xxp2; + struct cvmx_gmxx_txx_thresh_cn30xx cn50xx; + struct cvmx_gmxx_txx_thresh_s cn52xx; + struct cvmx_gmxx_txx_thresh_s cn52xxp1; + struct cvmx_gmxx_txx_thresh_s cn56xx; + struct cvmx_gmxx_txx_thresh_s cn56xxp1; + struct cvmx_gmxx_txx_thresh_s cn58xx; + struct cvmx_gmxx_txx_thresh_s cn58xxp1; +}; + +union cvmx_gmxx_tx_bp { + uint64_t u64; + struct cvmx_gmxx_tx_bp_s { + uint64_t reserved_4_63:60; + uint64_t bp:4; + } s; + struct cvmx_gmxx_tx_bp_cn30xx { + uint64_t reserved_3_63:61; + uint64_t bp:3; + } cn30xx; + struct cvmx_gmxx_tx_bp_cn30xx cn31xx; + struct cvmx_gmxx_tx_bp_s cn38xx; + struct cvmx_gmxx_tx_bp_s cn38xxp2; + struct cvmx_gmxx_tx_bp_cn30xx cn50xx; + struct cvmx_gmxx_tx_bp_s cn52xx; + struct cvmx_gmxx_tx_bp_s cn52xxp1; + struct cvmx_gmxx_tx_bp_s cn56xx; + struct cvmx_gmxx_tx_bp_s cn56xxp1; + struct cvmx_gmxx_tx_bp_s cn58xx; + struct cvmx_gmxx_tx_bp_s cn58xxp1; +}; + +union cvmx_gmxx_tx_clk_mskx { + uint64_t u64; + struct cvmx_gmxx_tx_clk_mskx_s { + uint64_t reserved_1_63:63; + uint64_t msk:1; + } s; + struct cvmx_gmxx_tx_clk_mskx_s cn30xx; + struct cvmx_gmxx_tx_clk_mskx_s cn50xx; +}; + +union cvmx_gmxx_tx_col_attempt { + uint64_t u64; + struct cvmx_gmxx_tx_col_attempt_s { + uint64_t reserved_5_63:59; + uint64_t limit:5; + } s; + struct cvmx_gmxx_tx_col_attempt_s cn30xx; + struct cvmx_gmxx_tx_col_attempt_s cn31xx; + struct cvmx_gmxx_tx_col_attempt_s cn38xx; + struct cvmx_gmxx_tx_col_attempt_s cn38xxp2; + struct cvmx_gmxx_tx_col_attempt_s cn50xx; + struct cvmx_gmxx_tx_col_attempt_s cn52xx; + struct cvmx_gmxx_tx_col_attempt_s cn52xxp1; + struct cvmx_gmxx_tx_col_attempt_s cn56xx; + struct cvmx_gmxx_tx_col_attempt_s cn56xxp1; + struct cvmx_gmxx_tx_col_attempt_s cn58xx; + struct cvmx_gmxx_tx_col_attempt_s cn58xxp1; +}; + +union cvmx_gmxx_tx_corrupt { + uint64_t u64; + struct cvmx_gmxx_tx_corrupt_s { + uint64_t reserved_4_63:60; + uint64_t corrupt:4; + } s; + struct cvmx_gmxx_tx_corrupt_cn30xx { + uint64_t reserved_3_63:61; + uint64_t corrupt:3; + } cn30xx; + struct cvmx_gmxx_tx_corrupt_cn30xx cn31xx; + struct cvmx_gmxx_tx_corrupt_s cn38xx; + struct cvmx_gmxx_tx_corrupt_s cn38xxp2; + struct cvmx_gmxx_tx_corrupt_cn30xx cn50xx; + struct cvmx_gmxx_tx_corrupt_s cn52xx; + struct cvmx_gmxx_tx_corrupt_s cn52xxp1; + struct cvmx_gmxx_tx_corrupt_s cn56xx; + struct cvmx_gmxx_tx_corrupt_s cn56xxp1; + struct cvmx_gmxx_tx_corrupt_s cn58xx; + struct cvmx_gmxx_tx_corrupt_s cn58xxp1; +}; + +union cvmx_gmxx_tx_hg2_reg1 { + uint64_t u64; + struct cvmx_gmxx_tx_hg2_reg1_s { + uint64_t reserved_16_63:48; + uint64_t tx_xof:16; + } s; + struct cvmx_gmxx_tx_hg2_reg1_s cn52xx; + struct cvmx_gmxx_tx_hg2_reg1_s cn52xxp1; + struct cvmx_gmxx_tx_hg2_reg1_s cn56xx; +}; + +union cvmx_gmxx_tx_hg2_reg2 { + uint64_t u64; + struct cvmx_gmxx_tx_hg2_reg2_s { + uint64_t reserved_16_63:48; + uint64_t tx_xon:16; + } s; + struct cvmx_gmxx_tx_hg2_reg2_s cn52xx; + struct cvmx_gmxx_tx_hg2_reg2_s cn52xxp1; + struct cvmx_gmxx_tx_hg2_reg2_s cn56xx; +}; + +union cvmx_gmxx_tx_ifg { + uint64_t u64; + struct cvmx_gmxx_tx_ifg_s { + uint64_t reserved_8_63:56; + uint64_t ifg2:4; + uint64_t ifg1:4; + } s; + struct cvmx_gmxx_tx_ifg_s cn30xx; + struct cvmx_gmxx_tx_ifg_s cn31xx; + struct cvmx_gmxx_tx_ifg_s cn38xx; + struct cvmx_gmxx_tx_ifg_s cn38xxp2; + struct cvmx_gmxx_tx_ifg_s cn50xx; + struct cvmx_gmxx_tx_ifg_s cn52xx; + struct cvmx_gmxx_tx_ifg_s cn52xxp1; + struct cvmx_gmxx_tx_ifg_s cn56xx; + struct cvmx_gmxx_tx_ifg_s cn56xxp1; + struct cvmx_gmxx_tx_ifg_s cn58xx; + struct cvmx_gmxx_tx_ifg_s cn58xxp1; +}; + +union cvmx_gmxx_tx_int_en { + uint64_t u64; + struct cvmx_gmxx_tx_int_en_s { + uint64_t reserved_20_63:44; + uint64_t late_col:4; + uint64_t xsdef:4; + uint64_t xscol:4; + uint64_t reserved_6_7:2; + uint64_t undflw:4; + uint64_t ncb_nxa:1; + uint64_t pko_nxa:1; + } s; + struct cvmx_gmxx_tx_int_en_cn30xx { + uint64_t reserved_19_63:45; + uint64_t late_col:3; + uint64_t reserved_15_15:1; + uint64_t xsdef:3; + uint64_t reserved_11_11:1; + uint64_t xscol:3; + uint64_t reserved_5_7:3; + uint64_t undflw:3; + uint64_t reserved_1_1:1; + uint64_t pko_nxa:1; + } cn30xx; + struct cvmx_gmxx_tx_int_en_cn31xx { + uint64_t reserved_15_63:49; + uint64_t xsdef:3; + uint64_t reserved_11_11:1; + uint64_t xscol:3; + uint64_t reserved_5_7:3; + uint64_t undflw:3; + uint64_t reserved_1_1:1; + uint64_t pko_nxa:1; + } cn31xx; + struct cvmx_gmxx_tx_int_en_s cn38xx; + struct cvmx_gmxx_tx_int_en_cn38xxp2 { + uint64_t reserved_16_63:48; + uint64_t xsdef:4; + uint64_t xscol:4; + uint64_t reserved_6_7:2; + uint64_t undflw:4; + uint64_t ncb_nxa:1; + uint64_t pko_nxa:1; + } cn38xxp2; + struct cvmx_gmxx_tx_int_en_cn30xx cn50xx; + struct cvmx_gmxx_tx_int_en_cn52xx { + uint64_t reserved_20_63:44; + uint64_t late_col:4; + uint64_t xsdef:4; + uint64_t xscol:4; + uint64_t reserved_6_7:2; + uint64_t undflw:4; + uint64_t reserved_1_1:1; + uint64_t pko_nxa:1; + } cn52xx; + struct cvmx_gmxx_tx_int_en_cn52xx cn52xxp1; + struct cvmx_gmxx_tx_int_en_cn52xx cn56xx; + struct cvmx_gmxx_tx_int_en_cn52xx cn56xxp1; + struct cvmx_gmxx_tx_int_en_s cn58xx; + struct cvmx_gmxx_tx_int_en_s cn58xxp1; +}; + +union cvmx_gmxx_tx_int_reg { + uint64_t u64; + struct cvmx_gmxx_tx_int_reg_s { + uint64_t reserved_20_63:44; + uint64_t late_col:4; + uint64_t xsdef:4; + uint64_t xscol:4; + uint64_t reserved_6_7:2; + uint64_t undflw:4; + uint64_t ncb_nxa:1; + uint64_t pko_nxa:1; + } s; + struct cvmx_gmxx_tx_int_reg_cn30xx { + uint64_t reserved_19_63:45; + uint64_t late_col:3; + uint64_t reserved_15_15:1; + uint64_t xsdef:3; + uint64_t reserved_11_11:1; + uint64_t xscol:3; + uint64_t reserved_5_7:3; + uint64_t undflw:3; + uint64_t reserved_1_1:1; + uint64_t pko_nxa:1; + } cn30xx; + struct cvmx_gmxx_tx_int_reg_cn31xx { + uint64_t reserved_15_63:49; + uint64_t xsdef:3; + uint64_t reserved_11_11:1; + uint64_t xscol:3; + uint64_t reserved_5_7:3; + uint64_t undflw:3; + uint64_t reserved_1_1:1; + uint64_t pko_nxa:1; + } cn31xx; + struct cvmx_gmxx_tx_int_reg_s cn38xx; + struct cvmx_gmxx_tx_int_reg_cn38xxp2 { + uint64_t reserved_16_63:48; + uint64_t xsdef:4; + uint64_t xscol:4; + uint64_t reserved_6_7:2; + uint64_t undflw:4; + uint64_t ncb_nxa:1; + uint64_t pko_nxa:1; + } cn38xxp2; + struct cvmx_gmxx_tx_int_reg_cn30xx cn50xx; + struct cvmx_gmxx_tx_int_reg_cn52xx { + uint64_t reserved_20_63:44; + uint64_t late_col:4; + uint64_t xsdef:4; + uint64_t xscol:4; + uint64_t reserved_6_7:2; + uint64_t undflw:4; + uint64_t reserved_1_1:1; + uint64_t pko_nxa:1; + } cn52xx; + struct cvmx_gmxx_tx_int_reg_cn52xx cn52xxp1; + struct cvmx_gmxx_tx_int_reg_cn52xx cn56xx; + struct cvmx_gmxx_tx_int_reg_cn52xx cn56xxp1; + struct cvmx_gmxx_tx_int_reg_s cn58xx; + struct cvmx_gmxx_tx_int_reg_s cn58xxp1; +}; + +union cvmx_gmxx_tx_jam { + uint64_t u64; + struct cvmx_gmxx_tx_jam_s { + uint64_t reserved_8_63:56; + uint64_t jam:8; + } s; + struct cvmx_gmxx_tx_jam_s cn30xx; + struct cvmx_gmxx_tx_jam_s cn31xx; + struct cvmx_gmxx_tx_jam_s cn38xx; + struct cvmx_gmxx_tx_jam_s cn38xxp2; + struct cvmx_gmxx_tx_jam_s cn50xx; + struct cvmx_gmxx_tx_jam_s cn52xx; + struct cvmx_gmxx_tx_jam_s cn52xxp1; + struct cvmx_gmxx_tx_jam_s cn56xx; + struct cvmx_gmxx_tx_jam_s cn56xxp1; + struct cvmx_gmxx_tx_jam_s cn58xx; + struct cvmx_gmxx_tx_jam_s cn58xxp1; +}; + +union cvmx_gmxx_tx_lfsr { + uint64_t u64; + struct cvmx_gmxx_tx_lfsr_s { + uint64_t reserved_16_63:48; + uint64_t lfsr:16; + } s; + struct cvmx_gmxx_tx_lfsr_s cn30xx; + struct cvmx_gmxx_tx_lfsr_s cn31xx; + struct cvmx_gmxx_tx_lfsr_s cn38xx; + struct cvmx_gmxx_tx_lfsr_s cn38xxp2; + struct cvmx_gmxx_tx_lfsr_s cn50xx; + struct cvmx_gmxx_tx_lfsr_s cn52xx; + struct cvmx_gmxx_tx_lfsr_s cn52xxp1; + struct cvmx_gmxx_tx_lfsr_s cn56xx; + struct cvmx_gmxx_tx_lfsr_s cn56xxp1; + struct cvmx_gmxx_tx_lfsr_s cn58xx; + struct cvmx_gmxx_tx_lfsr_s cn58xxp1; +}; + +union cvmx_gmxx_tx_ovr_bp { + uint64_t u64; + struct cvmx_gmxx_tx_ovr_bp_s { + uint64_t reserved_48_63:16; + uint64_t tx_prt_bp:16; + uint64_t reserved_12_31:20; + uint64_t en:4; + uint64_t bp:4; + uint64_t ign_full:4; + } s; + struct cvmx_gmxx_tx_ovr_bp_cn30xx { + uint64_t reserved_11_63:53; + uint64_t en:3; + uint64_t reserved_7_7:1; + uint64_t bp:3; + uint64_t reserved_3_3:1; + uint64_t ign_full:3; + } cn30xx; + struct cvmx_gmxx_tx_ovr_bp_cn30xx cn31xx; + struct cvmx_gmxx_tx_ovr_bp_cn38xx { + uint64_t reserved_12_63:52; + uint64_t en:4; + uint64_t bp:4; + uint64_t ign_full:4; + } cn38xx; + struct cvmx_gmxx_tx_ovr_bp_cn38xx cn38xxp2; + struct cvmx_gmxx_tx_ovr_bp_cn30xx cn50xx; + struct cvmx_gmxx_tx_ovr_bp_s cn52xx; + struct cvmx_gmxx_tx_ovr_bp_s cn52xxp1; + struct cvmx_gmxx_tx_ovr_bp_s cn56xx; + struct cvmx_gmxx_tx_ovr_bp_s cn56xxp1; + struct cvmx_gmxx_tx_ovr_bp_cn38xx cn58xx; + struct cvmx_gmxx_tx_ovr_bp_cn38xx cn58xxp1; +}; + +union cvmx_gmxx_tx_pause_pkt_dmac { + uint64_t u64; + struct cvmx_gmxx_tx_pause_pkt_dmac_s { + uint64_t reserved_48_63:16; + uint64_t dmac:48; + } s; + struct cvmx_gmxx_tx_pause_pkt_dmac_s cn30xx; + struct cvmx_gmxx_tx_pause_pkt_dmac_s cn31xx; + struct cvmx_gmxx_tx_pause_pkt_dmac_s cn38xx; + struct cvmx_gmxx_tx_pause_pkt_dmac_s cn38xxp2; + struct cvmx_gmxx_tx_pause_pkt_dmac_s cn50xx; + struct cvmx_gmxx_tx_pause_pkt_dmac_s cn52xx; + struct cvmx_gmxx_tx_pause_pkt_dmac_s cn52xxp1; + struct cvmx_gmxx_tx_pause_pkt_dmac_s cn56xx; + struct cvmx_gmxx_tx_pause_pkt_dmac_s cn56xxp1; + struct cvmx_gmxx_tx_pause_pkt_dmac_s cn58xx; + struct cvmx_gmxx_tx_pause_pkt_dmac_s cn58xxp1; +}; + +union cvmx_gmxx_tx_pause_pkt_type { + uint64_t u64; + struct cvmx_gmxx_tx_pause_pkt_type_s { + uint64_t reserved_16_63:48; + uint64_t type:16; + } s; + struct cvmx_gmxx_tx_pause_pkt_type_s cn30xx; + struct cvmx_gmxx_tx_pause_pkt_type_s cn31xx; + struct cvmx_gmxx_tx_pause_pkt_type_s cn38xx; + struct cvmx_gmxx_tx_pause_pkt_type_s cn38xxp2; + struct cvmx_gmxx_tx_pause_pkt_type_s cn50xx; + struct cvmx_gmxx_tx_pause_pkt_type_s cn52xx; + struct cvmx_gmxx_tx_pause_pkt_type_s cn52xxp1; + struct cvmx_gmxx_tx_pause_pkt_type_s cn56xx; + struct cvmx_gmxx_tx_pause_pkt_type_s cn56xxp1; + struct cvmx_gmxx_tx_pause_pkt_type_s cn58xx; + struct cvmx_gmxx_tx_pause_pkt_type_s cn58xxp1; +}; + +union cvmx_gmxx_tx_prts { + uint64_t u64; + struct cvmx_gmxx_tx_prts_s { + uint64_t reserved_5_63:59; + uint64_t prts:5; + } s; + struct cvmx_gmxx_tx_prts_s cn30xx; + struct cvmx_gmxx_tx_prts_s cn31xx; + struct cvmx_gmxx_tx_prts_s cn38xx; + struct cvmx_gmxx_tx_prts_s cn38xxp2; + struct cvmx_gmxx_tx_prts_s cn50xx; + struct cvmx_gmxx_tx_prts_s cn52xx; + struct cvmx_gmxx_tx_prts_s cn52xxp1; + struct cvmx_gmxx_tx_prts_s cn56xx; + struct cvmx_gmxx_tx_prts_s cn56xxp1; + struct cvmx_gmxx_tx_prts_s cn58xx; + struct cvmx_gmxx_tx_prts_s cn58xxp1; +}; + +union cvmx_gmxx_tx_spi_ctl { + uint64_t u64; + struct cvmx_gmxx_tx_spi_ctl_s { + uint64_t reserved_2_63:62; + uint64_t tpa_clr:1; + uint64_t cont_pkt:1; + } s; + struct cvmx_gmxx_tx_spi_ctl_s cn38xx; + struct cvmx_gmxx_tx_spi_ctl_s cn38xxp2; + struct cvmx_gmxx_tx_spi_ctl_s cn58xx; + struct cvmx_gmxx_tx_spi_ctl_s cn58xxp1; +}; + +union cvmx_gmxx_tx_spi_drain { + uint64_t u64; + struct cvmx_gmxx_tx_spi_drain_s { + uint64_t reserved_16_63:48; + uint64_t drain:16; + } s; + struct cvmx_gmxx_tx_spi_drain_s cn38xx; + struct cvmx_gmxx_tx_spi_drain_s cn58xx; + struct cvmx_gmxx_tx_spi_drain_s cn58xxp1; +}; + +union cvmx_gmxx_tx_spi_max { + uint64_t u64; + struct cvmx_gmxx_tx_spi_max_s { + uint64_t reserved_23_63:41; + uint64_t slice:7; + uint64_t max2:8; + uint64_t max1:8; + } s; + struct cvmx_gmxx_tx_spi_max_cn38xx { + uint64_t reserved_16_63:48; + uint64_t max2:8; + uint64_t max1:8; + } cn38xx; + struct cvmx_gmxx_tx_spi_max_cn38xx cn38xxp2; + struct cvmx_gmxx_tx_spi_max_s cn58xx; + struct cvmx_gmxx_tx_spi_max_s cn58xxp1; +}; + +union cvmx_gmxx_tx_spi_roundx { + uint64_t u64; + struct cvmx_gmxx_tx_spi_roundx_s { + uint64_t reserved_16_63:48; + uint64_t round:16; + } s; + struct cvmx_gmxx_tx_spi_roundx_s cn58xx; + struct cvmx_gmxx_tx_spi_roundx_s cn58xxp1; +}; + +union cvmx_gmxx_tx_spi_thresh { + uint64_t u64; + struct cvmx_gmxx_tx_spi_thresh_s { + uint64_t reserved_6_63:58; + uint64_t thresh:6; + } s; + struct cvmx_gmxx_tx_spi_thresh_s cn38xx; + struct cvmx_gmxx_tx_spi_thresh_s cn38xxp2; + struct cvmx_gmxx_tx_spi_thresh_s cn58xx; + struct cvmx_gmxx_tx_spi_thresh_s cn58xxp1; +}; + +union cvmx_gmxx_tx_xaui_ctl { + uint64_t u64; + struct cvmx_gmxx_tx_xaui_ctl_s { + uint64_t reserved_11_63:53; + uint64_t hg_pause_hgi:2; + uint64_t hg_en:1; + uint64_t reserved_7_7:1; + uint64_t ls_byp:1; + uint64_t ls:2; + uint64_t reserved_2_3:2; + uint64_t uni_en:1; + uint64_t dic_en:1; + } s; + struct cvmx_gmxx_tx_xaui_ctl_s cn52xx; + struct cvmx_gmxx_tx_xaui_ctl_s cn52xxp1; + struct cvmx_gmxx_tx_xaui_ctl_s cn56xx; + struct cvmx_gmxx_tx_xaui_ctl_s cn56xxp1; +}; + +union cvmx_gmxx_xaui_ext_loopback { + uint64_t u64; + struct cvmx_gmxx_xaui_ext_loopback_s { + uint64_t reserved_5_63:59; + uint64_t en:1; + uint64_t thresh:4; + } s; + struct cvmx_gmxx_xaui_ext_loopback_s cn52xx; + struct cvmx_gmxx_xaui_ext_loopback_s cn52xxp1; + struct cvmx_gmxx_xaui_ext_loopback_s cn56xx; + struct cvmx_gmxx_xaui_ext_loopback_s cn56xxp1; +}; + +#endif diff --git a/drivers/staging/octeon/cvmx-helper-board.c b/drivers/staging/octeon/cvmx-helper-board.c new file mode 100644 index 000000000000..3085e38a6f99 --- /dev/null +++ b/drivers/staging/octeon/cvmx-helper-board.c @@ -0,0 +1,706 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2008 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +/* + * + * Helper functions to abstract board specific data about + * network ports from the rest of the cvmx-helper files. + */ + +#include +#include + +#include "cvmx-config.h" + +#include "cvmx-mdio.h" + +#include "cvmx-helper.h" +#include "cvmx-helper-util.h" +#include "cvmx-helper-board.h" + +#include "cvmx-gmxx-defs.h" +#include "cvmx-asxx-defs.h" + +/** + * cvmx_override_board_link_get(int ipd_port) is a function + * pointer. It is meant to allow customization of the process of + * talking to a PHY to determine link speed. It is called every + * time a PHY must be polled for link status. Users should set + * this pointer to a function before calling any cvmx-helper + * operations. + */ +cvmx_helper_link_info_t(*cvmx_override_board_link_get) (int ipd_port) = + NULL; + +/** + * Return the MII PHY address associated with the given IPD + * port. A result of -1 means there isn't a MII capable PHY + * connected to this port. On chips supporting multiple MII + * busses the bus number is encoded in bits <15:8>. + * + * This function must be modified for every new Octeon board. + * Internally it uses switch statements based on the cvmx_sysinfo + * data to determine board types and revisions. It replies on the + * fact that every Octeon board receives a unique board type + * enumeration from the bootloader. + * + * @ipd_port: Octeon IPD port to get the MII address for. + * + * Returns MII PHY address and bus number or -1. + */ +int cvmx_helper_board_get_mii_address(int ipd_port) +{ + switch (cvmx_sysinfo_get()->board_type) { + case CVMX_BOARD_TYPE_SIM: + /* Simulator doesn't have MII */ + return -1; + case CVMX_BOARD_TYPE_EBT3000: + case CVMX_BOARD_TYPE_EBT5800: + case CVMX_BOARD_TYPE_THUNDER: + case CVMX_BOARD_TYPE_NICPRO2: + /* Interface 0 is SPI4, interface 1 is RGMII */ + if ((ipd_port >= 16) && (ipd_port < 20)) + return ipd_port - 16; + else + return -1; + case CVMX_BOARD_TYPE_KODAMA: + case CVMX_BOARD_TYPE_EBH3100: + case CVMX_BOARD_TYPE_HIKARI: + case CVMX_BOARD_TYPE_CN3010_EVB_HS5: + case CVMX_BOARD_TYPE_CN3005_EVB_HS5: + case CVMX_BOARD_TYPE_CN3020_EVB_HS5: + /* + * Port 0 is WAN connected to a PHY, Port 1 is GMII + * connected to a switch + */ + if (ipd_port == 0) + return 4; + else if (ipd_port == 1) + return 9; + else + return -1; + case CVMX_BOARD_TYPE_NAC38: + /* Board has 8 RGMII ports PHYs are 0-7 */ + if ((ipd_port >= 0) && (ipd_port < 4)) + return ipd_port; + else if ((ipd_port >= 16) && (ipd_port < 20)) + return ipd_port - 16 + 4; + else + return -1; + case CVMX_BOARD_TYPE_EBH3000: + /* Board has dual SPI4 and no PHYs */ + return -1; + case CVMX_BOARD_TYPE_EBH5200: + case CVMX_BOARD_TYPE_EBH5201: + case CVMX_BOARD_TYPE_EBT5200: + /* + * Board has 4 SGMII ports. The PHYs start right after the MII + * ports MII0 = 0, MII1 = 1, SGMII = 2-5. + */ + if ((ipd_port >= 0) && (ipd_port < 4)) + return ipd_port + 2; + else + return -1; + case CVMX_BOARD_TYPE_EBH5600: + case CVMX_BOARD_TYPE_EBH5601: + case CVMX_BOARD_TYPE_EBH5610: + /* + * Board has 8 SGMII ports. 4 connect out, two connect + * to a switch, and 2 loop to each other + */ + if ((ipd_port >= 0) && (ipd_port < 4)) + return ipd_port + 1; + else + return -1; + case CVMX_BOARD_TYPE_CUST_NB5: + if (ipd_port == 2) + return 4; + else + return -1; + case CVMX_BOARD_TYPE_NIC_XLE_4G: + /* Board has 4 SGMII ports. connected QLM3(interface 1) */ + if ((ipd_port >= 16) && (ipd_port < 20)) + return ipd_port - 16 + 1; + else + return -1; + case CVMX_BOARD_TYPE_BBGW_REF: + /* + * No PHYs are connected to Octeon, everything is + * through switch. + */ + return -1; + } + + /* Some unknown board. Somebody forgot to update this function... */ + cvmx_dprintf + ("cvmx_helper_board_get_mii_address: Unknown board type %d\n", + cvmx_sysinfo_get()->board_type); + return -1; +} + +/** + * This function is the board specific method of determining an + * ethernet ports link speed. Most Octeon boards have Marvell PHYs + * and are handled by the fall through case. This function must be + * updated for boards that don't have the normal Marvell PHYs. + * + * This function must be modified for every new Octeon board. + * Internally it uses switch statements based on the cvmx_sysinfo + * data to determine board types and revisions. It relies on the + * fact that every Octeon board receives a unique board type + * enumeration from the bootloader. + * + * @ipd_port: IPD input port associated with the port we want to get link + * status for. + * + * Returns The ports link status. If the link isn't fully resolved, this must + * return zero. + */ +cvmx_helper_link_info_t __cvmx_helper_board_link_get(int ipd_port) +{ + cvmx_helper_link_info_t result; + int phy_addr; + int is_broadcom_phy = 0; + + /* Give the user a chance to override the processing of this function */ + if (cvmx_override_board_link_get) + return cvmx_override_board_link_get(ipd_port); + + /* Unless we fix it later, all links are defaulted to down */ + result.u64 = 0; + + /* + * This switch statement should handle all ports that either don't use + * Marvell PHYS, or don't support in-band status. + */ + switch (cvmx_sysinfo_get()->board_type) { + case CVMX_BOARD_TYPE_SIM: + /* The simulator gives you a simulated 1Gbps full duplex link */ + result.s.link_up = 1; + result.s.full_duplex = 1; + result.s.speed = 1000; + return result; + case CVMX_BOARD_TYPE_EBH3100: + case CVMX_BOARD_TYPE_CN3010_EVB_HS5: + case CVMX_BOARD_TYPE_CN3005_EVB_HS5: + case CVMX_BOARD_TYPE_CN3020_EVB_HS5: + /* Port 1 on these boards is always Gigabit */ + if (ipd_port == 1) { + result.s.link_up = 1; + result.s.full_duplex = 1; + result.s.speed = 1000; + return result; + } + /* Fall through to the generic code below */ + break; + case CVMX_BOARD_TYPE_CUST_NB5: + /* Port 1 on these boards is always Gigabit */ + if (ipd_port == 1) { + result.s.link_up = 1; + result.s.full_duplex = 1; + result.s.speed = 1000; + return result; + } else /* The other port uses a broadcom PHY */ + is_broadcom_phy = 1; + break; + case CVMX_BOARD_TYPE_BBGW_REF: + /* Port 1 on these boards is always Gigabit */ + if (ipd_port == 2) { + /* Port 2 is not hooked up */ + result.u64 = 0; + return result; + } else { + /* Ports 0 and 1 connect to the switch */ + result.s.link_up = 1; + result.s.full_duplex = 1; + result.s.speed = 1000; + return result; + } + break; + } + + phy_addr = cvmx_helper_board_get_mii_address(ipd_port); + if (phy_addr != -1) { + if (is_broadcom_phy) { + /* + * Below we are going to read SMI/MDIO + * register 0x19 which works on Broadcom + * parts + */ + int phy_status = + cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, + 0x19); + switch ((phy_status >> 8) & 0x7) { + case 0: + result.u64 = 0; + break; + case 1: + result.s.link_up = 1; + result.s.full_duplex = 0; + result.s.speed = 10; + break; + case 2: + result.s.link_up = 1; + result.s.full_duplex = 1; + result.s.speed = 10; + break; + case 3: + result.s.link_up = 1; + result.s.full_duplex = 0; + result.s.speed = 100; + break; + case 4: + result.s.link_up = 1; + result.s.full_duplex = 1; + result.s.speed = 100; + break; + case 5: + result.s.link_up = 1; + result.s.full_duplex = 1; + result.s.speed = 100; + break; + case 6: + result.s.link_up = 1; + result.s.full_duplex = 0; + result.s.speed = 1000; + break; + case 7: + result.s.link_up = 1; + result.s.full_duplex = 1; + result.s.speed = 1000; + break; + } + } else { + /* + * This code assumes we are using a Marvell + * Gigabit PHY. All the speed information can + * be read from register 17 in one + * go. Somebody using a different PHY will + * need to handle it above in the board + * specific area. + */ + int phy_status = + cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 17); + + /* + * If the resolve bit 11 isn't set, see if + * autoneg is turned off (bit 12, reg 0). The + * resolve bit doesn't get set properly when + * autoneg is off, so force it. + */ + if ((phy_status & (1 << 11)) == 0) { + int auto_status = + cvmx_mdio_read(phy_addr >> 8, + phy_addr & 0xff, 0); + if ((auto_status & (1 << 12)) == 0) + phy_status |= 1 << 11; + } + + /* + * Only return a link if the PHY has finished + * auto negotiation and set the resolved bit + * (bit 11) + */ + if (phy_status & (1 << 11)) { + result.s.link_up = 1; + result.s.full_duplex = ((phy_status >> 13) & 1); + switch ((phy_status >> 14) & 3) { + case 0: /* 10 Mbps */ + result.s.speed = 10; + break; + case 1: /* 100 Mbps */ + result.s.speed = 100; + break; + case 2: /* 1 Gbps */ + result.s.speed = 1000; + break; + case 3: /* Illegal */ + result.u64 = 0; + break; + } + } + } + } else if (OCTEON_IS_MODEL(OCTEON_CN3XXX) + || OCTEON_IS_MODEL(OCTEON_CN58XX) + || OCTEON_IS_MODEL(OCTEON_CN50XX)) { + /* + * We don't have a PHY address, so attempt to use + * in-band status. It is really important that boards + * not supporting in-band status never get + * here. Reading broken in-band status tends to do bad + * things + */ + union cvmx_gmxx_rxx_rx_inbnd inband_status; + int interface = cvmx_helper_get_interface_num(ipd_port); + int index = cvmx_helper_get_interface_index_num(ipd_port); + inband_status.u64 = + cvmx_read_csr(CVMX_GMXX_RXX_RX_INBND(index, interface)); + + result.s.link_up = inband_status.s.status; + result.s.full_duplex = inband_status.s.duplex; + switch (inband_status.s.speed) { + case 0: /* 10 Mbps */ + result.s.speed = 10; + break; + case 1: /* 100 Mbps */ + result.s.speed = 100; + break; + case 2: /* 1 Gbps */ + result.s.speed = 1000; + break; + case 3: /* Illegal */ + result.u64 = 0; + break; + } + } else { + /* + * We don't have a PHY address and we don't have + * in-band status. There is no way to determine the + * link speed. Return down assuming this port isn't + * wired + */ + result.u64 = 0; + } + + /* If link is down, return all fields as zero. */ + if (!result.s.link_up) + result.u64 = 0; + + return result; +} + +/** + * This function as a board specific method of changing the PHY + * speed, duplex, and auto-negotiation. This programs the PHY and + * not Octeon. This can be used to force Octeon's links to + * specific settings. + * + * @phy_addr: The address of the PHY to program + * @enable_autoneg: + * Non zero if you want to enable auto-negotiation. + * @link_info: Link speed to program. If the speed is zero and auto-negotiation + * is enabled, all possible negotiation speeds are advertised. + * + * Returns Zero on success, negative on failure + */ +int cvmx_helper_board_link_set_phy(int phy_addr, + cvmx_helper_board_set_phy_link_flags_types_t + link_flags, + cvmx_helper_link_info_t link_info) +{ + + /* Set the flow control settings based on link_flags */ + if ((link_flags & set_phy_link_flags_flow_control_mask) != + set_phy_link_flags_flow_control_dont_touch) { + cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver; + reg_autoneg_adver.u16 = + cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, + CVMX_MDIO_PHY_REG_AUTONEG_ADVER); + reg_autoneg_adver.s.asymmetric_pause = + (link_flags & set_phy_link_flags_flow_control_mask) == + set_phy_link_flags_flow_control_enable; + reg_autoneg_adver.s.pause = + (link_flags & set_phy_link_flags_flow_control_mask) == + set_phy_link_flags_flow_control_enable; + cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, + CVMX_MDIO_PHY_REG_AUTONEG_ADVER, + reg_autoneg_adver.u16); + } + + /* If speed isn't set and autoneg is on advertise all supported modes */ + if ((link_flags & set_phy_link_flags_autoneg) + && (link_info.s.speed == 0)) { + cvmx_mdio_phy_reg_control_t reg_control; + cvmx_mdio_phy_reg_status_t reg_status; + cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver; + cvmx_mdio_phy_reg_extended_status_t reg_extended_status; + cvmx_mdio_phy_reg_control_1000_t reg_control_1000; + + reg_status.u16 = + cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, + CVMX_MDIO_PHY_REG_STATUS); + reg_autoneg_adver.u16 = + cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, + CVMX_MDIO_PHY_REG_AUTONEG_ADVER); + reg_autoneg_adver.s.advert_100base_t4 = + reg_status.s.capable_100base_t4; + reg_autoneg_adver.s.advert_10base_tx_full = + reg_status.s.capable_10_full; + reg_autoneg_adver.s.advert_10base_tx_half = + reg_status.s.capable_10_half; + reg_autoneg_adver.s.advert_100base_tx_full = + reg_status.s.capable_100base_x_full; + reg_autoneg_adver.s.advert_100base_tx_half = + reg_status.s.capable_100base_x_half; + cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, + CVMX_MDIO_PHY_REG_AUTONEG_ADVER, + reg_autoneg_adver.u16); + if (reg_status.s.capable_extended_status) { + reg_extended_status.u16 = + cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, + CVMX_MDIO_PHY_REG_EXTENDED_STATUS); + reg_control_1000.u16 = + cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, + CVMX_MDIO_PHY_REG_CONTROL_1000); + reg_control_1000.s.advert_1000base_t_full = + reg_extended_status.s.capable_1000base_t_full; + reg_control_1000.s.advert_1000base_t_half = + reg_extended_status.s.capable_1000base_t_half; + cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, + CVMX_MDIO_PHY_REG_CONTROL_1000, + reg_control_1000.u16); + } + reg_control.u16 = + cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, + CVMX_MDIO_PHY_REG_CONTROL); + reg_control.s.autoneg_enable = 1; + reg_control.s.restart_autoneg = 1; + cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, + CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16); + } else if ((link_flags & set_phy_link_flags_autoneg)) { + cvmx_mdio_phy_reg_control_t reg_control; + cvmx_mdio_phy_reg_status_t reg_status; + cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver; + cvmx_mdio_phy_reg_extended_status_t reg_extended_status; + cvmx_mdio_phy_reg_control_1000_t reg_control_1000; + + reg_status.u16 = + cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, + CVMX_MDIO_PHY_REG_STATUS); + reg_autoneg_adver.u16 = + cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, + CVMX_MDIO_PHY_REG_AUTONEG_ADVER); + reg_autoneg_adver.s.advert_100base_t4 = 0; + reg_autoneg_adver.s.advert_10base_tx_full = 0; + reg_autoneg_adver.s.advert_10base_tx_half = 0; + reg_autoneg_adver.s.advert_100base_tx_full = 0; + reg_autoneg_adver.s.advert_100base_tx_half = 0; + if (reg_status.s.capable_extended_status) { + reg_extended_status.u16 = + cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, + CVMX_MDIO_PHY_REG_EXTENDED_STATUS); + reg_control_1000.u16 = + cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, + CVMX_MDIO_PHY_REG_CONTROL_1000); + reg_control_1000.s.advert_1000base_t_full = 0; + reg_control_1000.s.advert_1000base_t_half = 0; + } + switch (link_info.s.speed) { + case 10: + reg_autoneg_adver.s.advert_10base_tx_full = + link_info.s.full_duplex; + reg_autoneg_adver.s.advert_10base_tx_half = + !link_info.s.full_duplex; + break; + case 100: + reg_autoneg_adver.s.advert_100base_tx_full = + link_info.s.full_duplex; + reg_autoneg_adver.s.advert_100base_tx_half = + !link_info.s.full_duplex; + break; + case 1000: + reg_control_1000.s.advert_1000base_t_full = + link_info.s.full_duplex; + reg_control_1000.s.advert_1000base_t_half = + !link_info.s.full_duplex; + break; + } + cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, + CVMX_MDIO_PHY_REG_AUTONEG_ADVER, + reg_autoneg_adver.u16); + if (reg_status.s.capable_extended_status) + cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, + CVMX_MDIO_PHY_REG_CONTROL_1000, + reg_control_1000.u16); + reg_control.u16 = + cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, + CVMX_MDIO_PHY_REG_CONTROL); + reg_control.s.autoneg_enable = 1; + reg_control.s.restart_autoneg = 1; + cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, + CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16); + } else { + cvmx_mdio_phy_reg_control_t reg_control; + reg_control.u16 = + cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, + CVMX_MDIO_PHY_REG_CONTROL); + reg_control.s.autoneg_enable = 0; + reg_control.s.restart_autoneg = 1; + reg_control.s.duplex = link_info.s.full_duplex; + if (link_info.s.speed == 1000) { + reg_control.s.speed_msb = 1; + reg_control.s.speed_lsb = 0; + } else if (link_info.s.speed == 100) { + reg_control.s.speed_msb = 0; + reg_control.s.speed_lsb = 1; + } else if (link_info.s.speed == 10) { + reg_control.s.speed_msb = 0; + reg_control.s.speed_lsb = 0; + } + cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, + CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16); + } + return 0; +} + +/** + * This function is called by cvmx_helper_interface_probe() after it + * determines the number of ports Octeon can support on a specific + * interface. This function is the per board location to override + * this value. It is called with the number of ports Octeon might + * support and should return the number of actual ports on the + * board. + * + * This function must be modifed for every new Octeon board. + * Internally it uses switch statements based on the cvmx_sysinfo + * data to determine board types and revisions. It relys on the + * fact that every Octeon board receives a unique board type + * enumeration from the bootloader. + * + * @interface: Interface to probe + * @supported_ports: + * Number of ports Octeon supports. + * + * Returns Number of ports the actual board supports. Many times this will + * simple be "support_ports". + */ +int __cvmx_helper_board_interface_probe(int interface, int supported_ports) +{ + switch (cvmx_sysinfo_get()->board_type) { + case CVMX_BOARD_TYPE_CN3005_EVB_HS5: + if (interface == 0) + return 2; + break; + case CVMX_BOARD_TYPE_BBGW_REF: + if (interface == 0) + return 2; + break; + case CVMX_BOARD_TYPE_NIC_XLE_4G: + if (interface == 0) + return 0; + break; + /* The 2nd interface on the EBH5600 is connected to the Marvel switch, + which we don't support. Disable ports connected to it */ + case CVMX_BOARD_TYPE_EBH5600: + if (interface == 1) + return 0; + break; + } + return supported_ports; +} + +/** + * Enable packet input/output from the hardware. This function is + * called after by cvmx_helper_packet_hardware_enable() to + * perform board specific initialization. For most boards + * nothing is needed. + * + * @interface: Interface to enable + * + * Returns Zero on success, negative on failure + */ +int __cvmx_helper_board_hardware_enable(int interface) +{ + if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CN3005_EVB_HS5) { + if (interface == 0) { + /* Different config for switch port */ + cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(1, interface), 0); + cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(1, interface), 0); + /* + * Boards with gigabit WAN ports need a + * different setting that is compatible with + * 100 Mbit settings + */ + cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface), + 0xc); + cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), + 0xc); + } + } else if (cvmx_sysinfo_get()->board_type == + CVMX_BOARD_TYPE_CN3010_EVB_HS5) { + /* + * Broadcom PHYs require differnet ASX + * clocks. Unfortunately many boards don't define a + * new board Id and simply mangle the + * CN3010_EVB_HS5 + */ + if (interface == 0) { + /* + * Some boards use a hacked up bootloader that + * identifies them as CN3010_EVB_HS5 + * evaluation boards. This leads to all kinds + * of configuration problems. Detect one + * case, and print warning, while trying to do + * the right thing. + */ + int phy_addr = cvmx_helper_board_get_mii_address(0); + if (phy_addr != -1) { + int phy_identifier = + cvmx_mdio_read(phy_addr >> 8, + phy_addr & 0xff, 0x2); + /* Is it a Broadcom PHY? */ + if (phy_identifier == 0x0143) { + cvmx_dprintf("\n"); + cvmx_dprintf("ERROR:\n"); + cvmx_dprintf + ("ERROR: Board type is CVMX_BOARD_TYPE_CN3010_EVB_HS5, but Broadcom PHY found.\n"); + cvmx_dprintf + ("ERROR: The board type is mis-configured, and software malfunctions are likely.\n"); + cvmx_dprintf + ("ERROR: All boards require a unique board type to identify them.\n"); + cvmx_dprintf("ERROR:\n"); + cvmx_dprintf("\n"); + cvmx_wait(1000000000); + cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX + (0, interface), 5); + cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX + (0, interface), 5); + } + } + } + } + return 0; +} + +cvmx_helper_board_usb_clock_types_t __cvmx_helper_board_usb_get_clock_type(void) +{ + switch (cvmx_sysinfo_get()->board_type) { + case CVMX_BOARD_TYPE_BBGW_REF: + return USB_CLOCK_TYPE_CRYSTAL_12; + } + return USB_CLOCK_TYPE_REF_48; +} + +int __cvmx_helper_board_usb_get_num_ports(int supported_ports) +{ + switch (cvmx_sysinfo_get()->board_type) { + case CVMX_BOARD_TYPE_NIC_XLE_4G: + return 0; + } + + return supported_ports; +} diff --git a/drivers/staging/octeon/cvmx-helper-board.h b/drivers/staging/octeon/cvmx-helper-board.h new file mode 100644 index 000000000000..dc20b01247c4 --- /dev/null +++ b/drivers/staging/octeon/cvmx-helper-board.h @@ -0,0 +1,180 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2008 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +/** + * + * Helper functions to abstract board specific data about + * network ports from the rest of the cvmx-helper files. + * + */ +#ifndef __CVMX_HELPER_BOARD_H__ +#define __CVMX_HELPER_BOARD_H__ + +#include "cvmx-helper.h" + +typedef enum { + USB_CLOCK_TYPE_REF_12, + USB_CLOCK_TYPE_REF_24, + USB_CLOCK_TYPE_REF_48, + USB_CLOCK_TYPE_CRYSTAL_12, +} cvmx_helper_board_usb_clock_types_t; + +typedef enum { + set_phy_link_flags_autoneg = 0x1, + set_phy_link_flags_flow_control_dont_touch = 0x0 << 1, + set_phy_link_flags_flow_control_enable = 0x1 << 1, + set_phy_link_flags_flow_control_disable = 0x2 << 1, + set_phy_link_flags_flow_control_mask = 0x3 << 1, /* Mask for 2 bit wide flow control field */ +} cvmx_helper_board_set_phy_link_flags_types_t; + +/** + * cvmx_override_board_link_get(int ipd_port) is a function + * pointer. It is meant to allow customization of the process of + * talking to a PHY to determine link speed. It is called every + * time a PHY must be polled for link status. Users should set + * this pointer to a function before calling any cvmx-helper + * operations. + */ +extern cvmx_helper_link_info_t(*cvmx_override_board_link_get) (int ipd_port); + +/** + * Return the MII PHY address associated with the given IPD + * port. A result of -1 means there isn't a MII capable PHY + * connected to this port. On chips supporting multiple MII + * busses the bus number is encoded in bits <15:8>. + * + * This function must be modifed for every new Octeon board. + * Internally it uses switch statements based on the cvmx_sysinfo + * data to determine board types and revisions. It relys on the + * fact that every Octeon board receives a unique board type + * enumeration from the bootloader. + * + * @ipd_port: Octeon IPD port to get the MII address for. + * + * Returns MII PHY address and bus number or -1. + */ +extern int cvmx_helper_board_get_mii_address(int ipd_port); + +/** + * This function as a board specific method of changing the PHY + * speed, duplex, and autonegotiation. This programs the PHY and + * not Octeon. This can be used to force Octeon's links to + * specific settings. + * + * @phy_addr: The address of the PHY to program + * @link_flags: + * Flags to control autonegotiation. Bit 0 is autonegotiation + * enable/disable to maintain backware compatability. + * @link_info: Link speed to program. If the speed is zero and autonegotiation + * is enabled, all possible negotiation speeds are advertised. + * + * Returns Zero on success, negative on failure + */ +int cvmx_helper_board_link_set_phy(int phy_addr, + cvmx_helper_board_set_phy_link_flags_types_t + link_flags, + cvmx_helper_link_info_t link_info); + +/** + * This function is the board specific method of determining an + * ethernet ports link speed. Most Octeon boards have Marvell PHYs + * and are handled by the fall through case. This function must be + * updated for boards that don't have the normal Marvell PHYs. + * + * This function must be modifed for every new Octeon board. + * Internally it uses switch statements based on the cvmx_sysinfo + * data to determine board types and revisions. It relys on the + * fact that every Octeon board receives a unique board type + * enumeration from the bootloader. + * + * @ipd_port: IPD input port associated with the port we want to get link + * status for. + * + * Returns The ports link status. If the link isn't fully resolved, this must + * return zero. + */ +extern cvmx_helper_link_info_t __cvmx_helper_board_link_get(int ipd_port); + +/** + * This function is called by cvmx_helper_interface_probe() after it + * determines the number of ports Octeon can support on a specific + * interface. This function is the per board location to override + * this value. It is called with the number of ports Octeon might + * support and should return the number of actual ports on the + * board. + * + * This function must be modifed for every new Octeon board. + * Internally it uses switch statements based on the cvmx_sysinfo + * data to determine board types and revisions. It relys on the + * fact that every Octeon board receives a unique board type + * enumeration from the bootloader. + * + * @interface: Interface to probe + * @supported_ports: + * Number of ports Octeon supports. + * + * Returns Number of ports the actual board supports. Many times this will + * simple be "support_ports". + */ +extern int __cvmx_helper_board_interface_probe(int interface, + int supported_ports); + +/** + * Enable packet input/output from the hardware. This function is + * called after by cvmx_helper_packet_hardware_enable() to + * perform board specific initialization. For most boards + * nothing is needed. + * + * @interface: Interface to enable + * + * Returns Zero on success, negative on failure + */ +extern int __cvmx_helper_board_hardware_enable(int interface); + +/** + * Gets the clock type used for the USB block based on board type. + * Used by the USB code for auto configuration of clock type. + * + * Returns USB clock type enumeration + */ +cvmx_helper_board_usb_clock_types_t +__cvmx_helper_board_usb_get_clock_type(void); + +/** + * Adjusts the number of available USB ports on Octeon based on board + * specifics. + * + * @supported_ports: expected number of ports based on chip type; + * + * + * Returns number of available usb ports, based on board specifics. + * Return value is supported_ports if function does not + * override. + */ +int __cvmx_helper_board_usb_get_num_ports(int supported_ports); + +#endif /* __CVMX_HELPER_BOARD_H__ */ diff --git a/drivers/staging/octeon/cvmx-helper-fpa.c b/drivers/staging/octeon/cvmx-helper-fpa.c new file mode 100644 index 000000000000..c239e5f4ab9a --- /dev/null +++ b/drivers/staging/octeon/cvmx-helper-fpa.c @@ -0,0 +1,243 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2008 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +/** + * @file + * + * Helper functions for FPA setup. + * + */ +#include "executive-config.h" +#include "cvmx-config.h" +#include "cvmx.h" +#include "cvmx-bootmem.h" +#include "cvmx-fpa.h" +#include "cvmx-helper-fpa.h" + +/** + * Allocate memory for and initialize a single FPA pool. + * + * @pool: Pool to initialize + * @buffer_size: Size of buffers to allocate in bytes + * @buffers: Number of buffers to put in the pool. Zero is allowed + * @name: String name of the pool for debugging purposes + * Returns Zero on success, non-zero on failure + */ +static int __cvmx_helper_initialize_fpa_pool(int pool, uint64_t buffer_size, + uint64_t buffers, const char *name) +{ + uint64_t current_num; + void *memory; + uint64_t align = CVMX_CACHE_LINE_SIZE; + + /* + * Align the allocation so that power of 2 size buffers are + * naturally aligned. + */ + while (align < buffer_size) + align = align << 1; + + if (buffers == 0) + return 0; + + current_num = cvmx_read_csr(CVMX_FPA_QUEX_AVAILABLE(pool)); + if (current_num) { + cvmx_dprintf("Fpa pool %d(%s) already has %llu buffers. " + "Skipping setup.\n", + pool, name, (unsigned long long)current_num); + return 0; + } + + memory = cvmx_bootmem_alloc(buffer_size * buffers, align); + if (memory == NULL) { + cvmx_dprintf("Out of memory initializing fpa pool %d(%s).\n", + pool, name); + return -1; + } + cvmx_fpa_setup_pool(pool, name, memory, buffer_size, buffers); + return 0; +} + +/** + * Allocate memory and initialize the FPA pools using memory + * from cvmx-bootmem. Specifying zero for the number of + * buffers will cause that FPA pool to not be setup. This is + * useful if you aren't using some of the hardware and want + * to save memory. Use cvmx_helper_initialize_fpa instead of + * this function directly. + * + * @pip_pool: Should always be CVMX_FPA_PACKET_POOL + * @pip_size: Should always be CVMX_FPA_PACKET_POOL_SIZE + * @pip_buffers: + * Number of packet buffers. + * @wqe_pool: Should always be CVMX_FPA_WQE_POOL + * @wqe_size: Should always be CVMX_FPA_WQE_POOL_SIZE + * @wqe_entries: + * Number of work queue entries + * @pko_pool: Should always be CVMX_FPA_OUTPUT_BUFFER_POOL + * @pko_size: Should always be CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE + * @pko_buffers: + * PKO Command buffers. You should at minimum have two per + * each PKO queue. + * @tim_pool: Should always be CVMX_FPA_TIMER_POOL + * @tim_size: Should always be CVMX_FPA_TIMER_POOL_SIZE + * @tim_buffers: + * TIM ring buffer command queues. At least two per timer bucket + * is recommened. + * @dfa_pool: Should always be CVMX_FPA_DFA_POOL + * @dfa_size: Should always be CVMX_FPA_DFA_POOL_SIZE + * @dfa_buffers: + * DFA command buffer. A relatively small (32 for example) + * number should work. + * Returns Zero on success, non-zero if out of memory + */ +static int __cvmx_helper_initialize_fpa(int pip_pool, int pip_size, + int pip_buffers, int wqe_pool, + int wqe_size, int wqe_entries, + int pko_pool, int pko_size, + int pko_buffers, int tim_pool, + int tim_size, int tim_buffers, + int dfa_pool, int dfa_size, + int dfa_buffers) +{ + int status; + + cvmx_fpa_enable(); + + if ((pip_buffers > 0) && (pip_buffers <= 64)) + cvmx_dprintf + ("Warning: %d packet buffers may not be enough for hardware" + " prefetch. 65 or more is recommended.\n", pip_buffers); + + if (pip_pool >= 0) { + status = + __cvmx_helper_initialize_fpa_pool(pip_pool, pip_size, + pip_buffers, + "Packet Buffers"); + if (status) + return status; + } + + if (wqe_pool >= 0) { + status = + __cvmx_helper_initialize_fpa_pool(wqe_pool, wqe_size, + wqe_entries, + "Work Queue Entries"); + if (status) + return status; + } + + if (pko_pool >= 0) { + status = + __cvmx_helper_initialize_fpa_pool(pko_pool, pko_size, + pko_buffers, + "PKO Command Buffers"); + if (status) + return status; + } + + if (tim_pool >= 0) { + status = + __cvmx_helper_initialize_fpa_pool(tim_pool, tim_size, + tim_buffers, + "TIM Command Buffers"); + if (status) + return status; + } + + if (dfa_pool >= 0) { + status = + __cvmx_helper_initialize_fpa_pool(dfa_pool, dfa_size, + dfa_buffers, + "DFA Command Buffers"); + if (status) + return status; + } + + return 0; +} + +/** + * Allocate memory and initialize the FPA pools using memory + * from cvmx-bootmem. Sizes of each element in the pools is + * controlled by the cvmx-config.h header file. Specifying + * zero for any parameter will cause that FPA pool to not be + * setup. This is useful if you aren't using some of the + * hardware and want to save memory. + * + * @packet_buffers: + * Number of packet buffers to allocate + * @work_queue_entries: + * Number of work queue entries + * @pko_buffers: + * PKO Command buffers. You should at minimum have two per + * each PKO queue. + * @tim_buffers: + * TIM ring buffer command queues. At least two per timer bucket + * is recommened. + * @dfa_buffers: + * DFA command buffer. A relatively small (32 for example) + * number should work. + * Returns Zero on success, non-zero if out of memory + */ +int cvmx_helper_initialize_fpa(int packet_buffers, int work_queue_entries, + int pko_buffers, int tim_buffers, + int dfa_buffers) +{ +#ifndef CVMX_FPA_PACKET_POOL +#define CVMX_FPA_PACKET_POOL -1 +#define CVMX_FPA_PACKET_POOL_SIZE 0 +#endif +#ifndef CVMX_FPA_WQE_POOL +#define CVMX_FPA_WQE_POOL -1 +#define CVMX_FPA_WQE_POOL_SIZE 0 +#endif +#ifndef CVMX_FPA_OUTPUT_BUFFER_POOL +#define CVMX_FPA_OUTPUT_BUFFER_POOL -1 +#define CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE 0 +#endif +#ifndef CVMX_FPA_TIMER_POOL +#define CVMX_FPA_TIMER_POOL -1 +#define CVMX_FPA_TIMER_POOL_SIZE 0 +#endif +#ifndef CVMX_FPA_DFA_POOL +#define CVMX_FPA_DFA_POOL -1 +#define CVMX_FPA_DFA_POOL_SIZE 0 +#endif + return __cvmx_helper_initialize_fpa(CVMX_FPA_PACKET_POOL, + CVMX_FPA_PACKET_POOL_SIZE, + packet_buffers, CVMX_FPA_WQE_POOL, + CVMX_FPA_WQE_POOL_SIZE, + work_queue_entries, + CVMX_FPA_OUTPUT_BUFFER_POOL, + CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE, + pko_buffers, CVMX_FPA_TIMER_POOL, + CVMX_FPA_TIMER_POOL_SIZE, + tim_buffers, CVMX_FPA_DFA_POOL, + CVMX_FPA_DFA_POOL_SIZE, + dfa_buffers); +} diff --git a/drivers/staging/octeon/cvmx-helper-fpa.h b/drivers/staging/octeon/cvmx-helper-fpa.h new file mode 100644 index 000000000000..5ff8c93198de --- /dev/null +++ b/drivers/staging/octeon/cvmx-helper-fpa.h @@ -0,0 +1,64 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2008 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +/** + * @file + * + * Helper functions for FPA setup. + * + */ +#ifndef __CVMX_HELPER_H_FPA__ +#define __CVMX_HELPER_H_FPA__ + +/** + * Allocate memory and initialize the FPA pools using memory + * from cvmx-bootmem. Sizes of each element in the pools is + * controlled by the cvmx-config.h header file. Specifying + * zero for any parameter will cause that FPA pool to not be + * setup. This is useful if you aren't using some of the + * hardware and want to save memory. + * + * @packet_buffers: + * Number of packet buffers to allocate + * @work_queue_entries: + * Number of work queue entries + * @pko_buffers: + * PKO Command buffers. You should at minimum have two per + * each PKO queue. + * @tim_buffers: + * TIM ring buffer command queues. At least two per timer bucket + * is recommened. + * @dfa_buffers: + * DFA command buffer. A relatively small (32 for example) + * number should work. + * Returns Zero on success, non-zero if out of memory + */ +extern int cvmx_helper_initialize_fpa(int packet_buffers, + int work_queue_entries, int pko_buffers, + int tim_buffers, int dfa_buffers); + +#endif /* __CVMX_HELPER_H__ */ diff --git a/drivers/staging/octeon/cvmx-helper-loop.c b/drivers/staging/octeon/cvmx-helper-loop.c new file mode 100644 index 000000000000..55a571a69529 --- /dev/null +++ b/drivers/staging/octeon/cvmx-helper-loop.c @@ -0,0 +1,85 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2008 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +/* + * Functions for LOOP initialization, configuration, + * and monitoring. + */ +#include + +#include "cvmx-config.h" + +#include "cvmx-helper.h" +#include "cvmx-pip-defs.h" + +/** + * Probe a LOOP interface and determine the number of ports + * connected to it. The LOOP interface should still be down + * after this call. + * + * @interface: Interface to probe + * + * Returns Number of ports on the interface. Zero to disable. + */ +int __cvmx_helper_loop_probe(int interface) +{ + union cvmx_ipd_sub_port_fcs ipd_sub_port_fcs; + int num_ports = 4; + int port; + + /* We need to disable length checking so packet < 64 bytes and jumbo + frames don't get errors */ + for (port = 0; port < num_ports; port++) { + union cvmx_pip_prt_cfgx port_cfg; + int ipd_port = cvmx_helper_get_ipd_port(interface, port); + port_cfg.u64 = cvmx_read_csr(CVMX_PIP_PRT_CFGX(ipd_port)); + port_cfg.s.maxerr_en = 0; + port_cfg.s.minerr_en = 0; + cvmx_write_csr(CVMX_PIP_PRT_CFGX(ipd_port), port_cfg.u64); + } + + /* Disable FCS stripping for loopback ports */ + ipd_sub_port_fcs.u64 = cvmx_read_csr(CVMX_IPD_SUB_PORT_FCS); + ipd_sub_port_fcs.s.port_bit2 = 0; + cvmx_write_csr(CVMX_IPD_SUB_PORT_FCS, ipd_sub_port_fcs.u64); + return num_ports; +} + +/** + * Bringup and enable a LOOP interface. After this call packet + * I/O should be fully functional. This is called with IPD + * enabled but PKO disabled. + * + * @interface: Interface to bring up + * + * Returns Zero on success, negative on failure + */ +int __cvmx_helper_loop_enable(int interface) +{ + /* Do nothing. */ + return 0; +} diff --git a/drivers/staging/octeon/cvmx-helper-loop.h b/drivers/staging/octeon/cvmx-helper-loop.h new file mode 100644 index 000000000000..e646a6ccce75 --- /dev/null +++ b/drivers/staging/octeon/cvmx-helper-loop.h @@ -0,0 +1,59 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2008 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, + * but AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +/** + * @file + * + * Functions for LOOP initialization, configuration, + * and monitoring. + * + */ +#ifndef __CVMX_HELPER_LOOP_H__ +#define __CVMX_HELPER_LOOP_H__ + +/** + * Probe a LOOP interface and determine the number of ports + * connected to it. The LOOP interface should still be down after + * this call. + * + * @interface: Interface to probe + * + * Returns Number of ports on the interface. Zero to disable. + */ +extern int __cvmx_helper_loop_probe(int interface); + +/** + * Bringup and enable a LOOP interface. After this call packet + * I/O should be fully functional. This is called with IPD + * enabled but PKO disabled. + * + * @interface: Interface to bring up + * + * Returns Zero on success, negative on failure + */ +extern int __cvmx_helper_loop_enable(int interface); + +#endif diff --git a/drivers/staging/octeon/cvmx-helper-npi.c b/drivers/staging/octeon/cvmx-helper-npi.c new file mode 100644 index 000000000000..7388a1e72b38 --- /dev/null +++ b/drivers/staging/octeon/cvmx-helper-npi.c @@ -0,0 +1,113 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2008 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +/* + * Functions for NPI initialization, configuration, + * and monitoring. + */ +#include + +#include "cvmx-config.h" + +#include "cvmx-helper.h" + +#include "cvmx-pip-defs.h" + +/** + * Probe a NPI interface and determine the number of ports + * connected to it. The NPI interface should still be down + * after this call. + * + * @interface: Interface to probe + * + * Returns Number of ports on the interface. Zero to disable. + */ +int __cvmx_helper_npi_probe(int interface) +{ +#if CVMX_PKO_QUEUES_PER_PORT_PCI > 0 + if (OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX)) + return 4; + else if (OCTEON_IS_MODEL(OCTEON_CN56XX) + && !OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X)) + /* The packet engines didn't exist before pass 2 */ + return 4; + else if (OCTEON_IS_MODEL(OCTEON_CN52XX) + && !OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X)) + /* The packet engines didn't exist before pass 2 */ + return 4; +#if 0 + /* + * Technically CN30XX, CN31XX, and CN50XX contain packet + * engines, but nobody ever uses them. Since this is the case, + * we disable them here. + */ + else if (OCTEON_IS_MODEL(OCTEON_CN31XX) + || OCTEON_IS_MODEL(OCTEON_CN50XX)) + return 2; + else if (OCTEON_IS_MODEL(OCTEON_CN30XX)) + return 1; +#endif +#endif + return 0; +} + +/** + * Bringup and enable a NPI interface. After this call packet + * I/O should be fully functional. This is called with IPD + * enabled but PKO disabled. + * + * @interface: Interface to bring up + * + * Returns Zero on success, negative on failure + */ +int __cvmx_helper_npi_enable(int interface) +{ + /* + * On CN50XX, CN52XX, and CN56XX we need to disable length + * checking so packet < 64 bytes and jumbo frames don't get + * errors. + */ + if (!OCTEON_IS_MODEL(OCTEON_CN3XXX) && + !OCTEON_IS_MODEL(OCTEON_CN58XX)) { + int num_ports = cvmx_helper_ports_on_interface(interface); + int port; + for (port = 0; port < num_ports; port++) { + union cvmx_pip_prt_cfgx port_cfg; + int ipd_port = + cvmx_helper_get_ipd_port(interface, port); + port_cfg.u64 = + cvmx_read_csr(CVMX_PIP_PRT_CFGX(ipd_port)); + port_cfg.s.maxerr_en = 0; + port_cfg.s.minerr_en = 0; + cvmx_write_csr(CVMX_PIP_PRT_CFGX(ipd_port), + port_cfg.u64); + } + } + + /* Enables are controlled by the remote host, so nothing to do here */ + return 0; +} diff --git a/drivers/staging/octeon/cvmx-helper-npi.h b/drivers/staging/octeon/cvmx-helper-npi.h new file mode 100644 index 000000000000..908e7b08c214 --- /dev/null +++ b/drivers/staging/octeon/cvmx-helper-npi.h @@ -0,0 +1,60 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2008 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +/** + * @file + * + * Functions for NPI initialization, configuration, + * and monitoring. + * + */ +#ifndef __CVMX_HELPER_NPI_H__ +#define __CVMX_HELPER_NPI_H__ + +/** + * Probe a NPI interface and determine the number of ports + * connected to it. The NPI interface should still be down after + * this call. + * + * @interface: Interface to probe + * + * Returns Number of ports on the interface. Zero to disable. + */ +extern int __cvmx_helper_npi_probe(int interface); + +/** + * Bringup and enable a NPI interface. After this call packet + * I/O should be fully functional. This is called with IPD + * enabled but PKO disabled. + * + * @interface: Interface to bring up + * + * Returns Zero on success, negative on failure + */ +extern int __cvmx_helper_npi_enable(int interface); + +#endif diff --git a/drivers/staging/octeon/cvmx-helper-rgmii.c b/drivers/staging/octeon/cvmx-helper-rgmii.c new file mode 100644 index 000000000000..aa2d5d7fee2b --- /dev/null +++ b/drivers/staging/octeon/cvmx-helper-rgmii.c @@ -0,0 +1,525 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2008 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +/* + * Functions for RGMII/GMII/MII initialization, configuration, + * and monitoring. + */ +#include + +#include "cvmx-config.h" + + +#include "cvmx-mdio.h" +#include "cvmx-pko.h" +#include "cvmx-helper.h" +#include "cvmx-helper-board.h" + +#include +#include "cvmx-gmxx-defs.h" +#include "cvmx-asxx-defs.h" +#include "cvmx-dbg-defs.h" + +void __cvmx_interrupt_gmxx_enable(int interface); +void __cvmx_interrupt_asxx_enable(int block); + +/** + * Probe RGMII ports and determine the number present + * + * @interface: Interface to probe + * + * Returns Number of RGMII/GMII/MII ports (0-4). + */ +int __cvmx_helper_rgmii_probe(int interface) +{ + int num_ports = 0; + union cvmx_gmxx_inf_mode mode; + mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface)); + + if (mode.s.type) { + if (OCTEON_IS_MODEL(OCTEON_CN38XX) + || OCTEON_IS_MODEL(OCTEON_CN58XX)) { + cvmx_dprintf("ERROR: RGMII initialize called in " + "SPI interface\n"); + } else if (OCTEON_IS_MODEL(OCTEON_CN31XX) + || OCTEON_IS_MODEL(OCTEON_CN30XX) + || OCTEON_IS_MODEL(OCTEON_CN50XX)) { + /* + * On these chips "type" says we're in + * GMII/MII mode. This limits us to 2 ports + */ + num_ports = 2; + } else { + cvmx_dprintf("ERROR: Unsupported Octeon model in %s\n", + __func__); + } + } else { + if (OCTEON_IS_MODEL(OCTEON_CN38XX) + || OCTEON_IS_MODEL(OCTEON_CN58XX)) { + num_ports = 4; + } else if (OCTEON_IS_MODEL(OCTEON_CN31XX) + || OCTEON_IS_MODEL(OCTEON_CN30XX) + || OCTEON_IS_MODEL(OCTEON_CN50XX)) { + num_ports = 3; + } else { + cvmx_dprintf("ERROR: Unsupported Octeon model in %s\n", + __func__); + } + } + return num_ports; +} + +/** + * Put an RGMII interface in loopback mode. Internal packets sent + * out will be received back again on the same port. Externally + * received packets will echo back out. + * + * @port: IPD port number to loop. + */ +void cvmx_helper_rgmii_internal_loopback(int port) +{ + int interface = (port >> 4) & 1; + int index = port & 0xf; + uint64_t tmp; + + union cvmx_gmxx_prtx_cfg gmx_cfg; + gmx_cfg.u64 = 0; + gmx_cfg.s.duplex = 1; + gmx_cfg.s.slottime = 1; + gmx_cfg.s.speed = 1; + cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 1); + cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 0x200); + cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0x2000); + cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64); + tmp = cvmx_read_csr(CVMX_ASXX_PRT_LOOP(interface)); + cvmx_write_csr(CVMX_ASXX_PRT_LOOP(interface), (1 << index) | tmp); + tmp = cvmx_read_csr(CVMX_ASXX_TX_PRT_EN(interface)); + cvmx_write_csr(CVMX_ASXX_TX_PRT_EN(interface), (1 << index) | tmp); + tmp = cvmx_read_csr(CVMX_ASXX_RX_PRT_EN(interface)); + cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface), (1 << index) | tmp); + gmx_cfg.s.en = 1; + cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64); +} + +/** + * Workaround ASX setup errata with CN38XX pass1 + * + * @interface: Interface to setup + * @port: Port to setup (0..3) + * @cpu_clock_hz: + * Chip frequency in Hertz + * + * Returns Zero on success, negative on failure + */ +static int __cvmx_helper_errata_asx_pass1(int interface, int port, + int cpu_clock_hz) +{ + /* Set hi water mark as per errata GMX-4 */ + if (cpu_clock_hz >= 325000000 && cpu_clock_hz < 375000000) + cvmx_write_csr(CVMX_ASXX_TX_HI_WATERX(port, interface), 12); + else if (cpu_clock_hz >= 375000000 && cpu_clock_hz < 437000000) + cvmx_write_csr(CVMX_ASXX_TX_HI_WATERX(port, interface), 11); + else if (cpu_clock_hz >= 437000000 && cpu_clock_hz < 550000000) + cvmx_write_csr(CVMX_ASXX_TX_HI_WATERX(port, interface), 10); + else if (cpu_clock_hz >= 550000000 && cpu_clock_hz < 687000000) + cvmx_write_csr(CVMX_ASXX_TX_HI_WATERX(port, interface), 9); + else + cvmx_dprintf("Illegal clock frequency (%d). " + "CVMX_ASXX_TX_HI_WATERX not set\n", cpu_clock_hz); + return 0; +} + +/** + * Configure all of the ASX, GMX, and PKO regsiters required + * to get RGMII to function on the supplied interface. + * + * @interface: PKO Interface to configure (0 or 1) + * + * Returns Zero on success + */ +int __cvmx_helper_rgmii_enable(int interface) +{ + int num_ports = cvmx_helper_ports_on_interface(interface); + int port; + struct cvmx_sysinfo *sys_info_ptr = cvmx_sysinfo_get(); + union cvmx_gmxx_inf_mode mode; + union cvmx_asxx_tx_prt_en asx_tx; + union cvmx_asxx_rx_prt_en asx_rx; + + mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface)); + + if (mode.s.en == 0) + return -1; + if ((OCTEON_IS_MODEL(OCTEON_CN38XX) || + OCTEON_IS_MODEL(OCTEON_CN58XX)) && mode.s.type == 1) + /* Ignore SPI interfaces */ + return -1; + + /* Configure the ASX registers needed to use the RGMII ports */ + asx_tx.u64 = 0; + asx_tx.s.prt_en = cvmx_build_mask(num_ports); + cvmx_write_csr(CVMX_ASXX_TX_PRT_EN(interface), asx_tx.u64); + + asx_rx.u64 = 0; + asx_rx.s.prt_en = cvmx_build_mask(num_ports); + cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface), asx_rx.u64); + + /* Configure the GMX registers needed to use the RGMII ports */ + for (port = 0; port < num_ports; port++) { + /* Setting of CVMX_GMXX_TXX_THRESH has been moved to + __cvmx_helper_setup_gmx() */ + + if (cvmx_octeon_is_pass1()) + __cvmx_helper_errata_asx_pass1(interface, port, + sys_info_ptr-> + cpu_clock_hz); + else { + /* + * Configure more flexible RGMII preamble + * checking. Pass 1 doesn't support this + * feature. + */ + union cvmx_gmxx_rxx_frm_ctl frm_ctl; + frm_ctl.u64 = + cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL + (port, interface)); + /* New field, so must be compile time */ + frm_ctl.s.pre_free = 1; + cvmx_write_csr(CVMX_GMXX_RXX_FRM_CTL(port, interface), + frm_ctl.u64); + } + + /* + * Each pause frame transmitted will ask for about 10M + * bit times before resume. If buffer space comes + * available before that time has expired, an XON + * pause frame (0 time) will be transmitted to restart + * the flow. + */ + cvmx_write_csr(CVMX_GMXX_TXX_PAUSE_PKT_TIME(port, interface), + 20000); + cvmx_write_csr(CVMX_GMXX_TXX_PAUSE_PKT_INTERVAL + (port, interface), 19000); + + if (OCTEON_IS_MODEL(OCTEON_CN50XX)) { + cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(port, interface), + 16); + cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(port, interface), + 16); + } else { + cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(port, interface), + 24); + cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(port, interface), + 24); + } + } + + __cvmx_helper_setup_gmx(interface, num_ports); + + /* enable the ports now */ + for (port = 0; port < num_ports; port++) { + union cvmx_gmxx_prtx_cfg gmx_cfg; + cvmx_helper_link_autoconf(cvmx_helper_get_ipd_port + (interface, port)); + gmx_cfg.u64 = + cvmx_read_csr(CVMX_GMXX_PRTX_CFG(port, interface)); + gmx_cfg.s.en = 1; + cvmx_write_csr(CVMX_GMXX_PRTX_CFG(port, interface), + gmx_cfg.u64); + } + __cvmx_interrupt_asxx_enable(interface); + __cvmx_interrupt_gmxx_enable(interface); + + return 0; +} + +/** + * Return the link state of an IPD/PKO port as returned by + * auto negotiation. The result of this function may not match + * Octeon's link config if auto negotiation has changed since + * the last call to cvmx_helper_link_set(). + * + * @ipd_port: IPD/PKO port to query + * + * Returns Link state + */ +cvmx_helper_link_info_t __cvmx_helper_rgmii_link_get(int ipd_port) +{ + int interface = cvmx_helper_get_interface_num(ipd_port); + int index = cvmx_helper_get_interface_index_num(ipd_port); + union cvmx_asxx_prt_loop asxx_prt_loop; + + asxx_prt_loop.u64 = cvmx_read_csr(CVMX_ASXX_PRT_LOOP(interface)); + if (asxx_prt_loop.s.int_loop & (1 << index)) { + /* Force 1Gbps full duplex on internal loopback */ + cvmx_helper_link_info_t result; + result.u64 = 0; + result.s.full_duplex = 1; + result.s.link_up = 1; + result.s.speed = 1000; + return result; + } else + return __cvmx_helper_board_link_get(ipd_port); +} + +/** + * Configure an IPD/PKO port for the specified link state. This + * function does not influence auto negotiation at the PHY level. + * The passed link state must always match the link state returned + * by cvmx_helper_link_get(). It is normally best to use + * cvmx_helper_link_autoconf() instead. + * + * @ipd_port: IPD/PKO port to configure + * @link_info: The new link state + * + * Returns Zero on success, negative on failure + */ +int __cvmx_helper_rgmii_link_set(int ipd_port, + cvmx_helper_link_info_t link_info) +{ + int result = 0; + int interface = cvmx_helper_get_interface_num(ipd_port); + int index = cvmx_helper_get_interface_index_num(ipd_port); + union cvmx_gmxx_prtx_cfg original_gmx_cfg; + union cvmx_gmxx_prtx_cfg new_gmx_cfg; + union cvmx_pko_mem_queue_qos pko_mem_queue_qos; + union cvmx_pko_mem_queue_qos pko_mem_queue_qos_save[16]; + union cvmx_gmxx_tx_ovr_bp gmx_tx_ovr_bp; + union cvmx_gmxx_tx_ovr_bp gmx_tx_ovr_bp_save; + int i; + + /* Ignore speed sets in the simulator */ + if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM) + return 0; + + /* Read the current settings so we know the current enable state */ + original_gmx_cfg.u64 = + cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); + new_gmx_cfg = original_gmx_cfg; + + /* Disable the lowest level RX */ + cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface), + cvmx_read_csr(CVMX_ASXX_RX_PRT_EN(interface)) & + ~(1 << index)); + + /* Disable all queues so that TX should become idle */ + for (i = 0; i < cvmx_pko_get_num_queues(ipd_port); i++) { + int queue = cvmx_pko_get_base_queue(ipd_port) + i; + cvmx_write_csr(CVMX_PKO_REG_READ_IDX, queue); + pko_mem_queue_qos.u64 = cvmx_read_csr(CVMX_PKO_MEM_QUEUE_QOS); + pko_mem_queue_qos.s.pid = ipd_port; + pko_mem_queue_qos.s.qid = queue; + pko_mem_queue_qos_save[i] = pko_mem_queue_qos; + pko_mem_queue_qos.s.qos_mask = 0; + cvmx_write_csr(CVMX_PKO_MEM_QUEUE_QOS, pko_mem_queue_qos.u64); + } + + /* Disable backpressure */ + gmx_tx_ovr_bp.u64 = cvmx_read_csr(CVMX_GMXX_TX_OVR_BP(interface)); + gmx_tx_ovr_bp_save = gmx_tx_ovr_bp; + gmx_tx_ovr_bp.s.bp &= ~(1 << index); + gmx_tx_ovr_bp.s.en |= 1 << index; + cvmx_write_csr(CVMX_GMXX_TX_OVR_BP(interface), gmx_tx_ovr_bp.u64); + cvmx_read_csr(CVMX_GMXX_TX_OVR_BP(interface)); + + /* + * Poll the GMX state machine waiting for it to become + * idle. Preferably we should only change speed when it is + * idle. If it doesn't become idle we will still do the speed + * change, but there is a slight chance that GMX will + * lockup. + */ + cvmx_write_csr(CVMX_NPI_DBG_SELECT, + interface * 0x800 + index * 0x100 + 0x880); + CVMX_WAIT_FOR_FIELD64(CVMX_DBG_DATA, union cvmx_dbg_data, data & 7, + ==, 0, 10000); + CVMX_WAIT_FOR_FIELD64(CVMX_DBG_DATA, union cvmx_dbg_data, data & 0xf, + ==, 0, 10000); + + /* Disable the port before we make any changes */ + new_gmx_cfg.s.en = 0; + cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), new_gmx_cfg.u64); + cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); + + /* Set full/half duplex */ + if (cvmx_octeon_is_pass1()) + /* Half duplex is broken for 38XX Pass 1 */ + new_gmx_cfg.s.duplex = 1; + else if (!link_info.s.link_up) + /* Force full duplex on down links */ + new_gmx_cfg.s.duplex = 1; + else + new_gmx_cfg.s.duplex = link_info.s.full_duplex; + + /* Set the link speed. Anything unknown is set to 1Gbps */ + if (link_info.s.speed == 10) { + new_gmx_cfg.s.slottime = 0; + new_gmx_cfg.s.speed = 0; + } else if (link_info.s.speed == 100) { + new_gmx_cfg.s.slottime = 0; + new_gmx_cfg.s.speed = 0; + } else { + new_gmx_cfg.s.slottime = 1; + new_gmx_cfg.s.speed = 1; + } + + /* Adjust the clocks */ + if (link_info.s.speed == 10) { + cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 50); + cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 0x40); + cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0); + } else if (link_info.s.speed == 100) { + cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 5); + cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 0x40); + cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0); + } else { + cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 1); + cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 0x200); + cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0x2000); + } + + if (OCTEON_IS_MODEL(OCTEON_CN30XX) || OCTEON_IS_MODEL(OCTEON_CN50XX)) { + if ((link_info.s.speed == 10) || (link_info.s.speed == 100)) { + union cvmx_gmxx_inf_mode mode; + mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface)); + + /* + * Port .en .type .p0mii Configuration + * ---- --- ----- ------ ----------------------------------------- + * X 0 X X All links are disabled. + * 0 1 X 0 Port 0 is RGMII + * 0 1 X 1 Port 0 is MII + * 1 1 0 X Ports 1 and 2 are configured as RGMII ports. + * 1 1 1 X Port 1: GMII/MII; Port 2: disabled. GMII or + * MII port is selected by GMX_PRT1_CFG[SPEED]. + */ + + /* In MII mode, CLK_CNT = 1. */ + if (((index == 0) && (mode.s.p0mii == 1)) + || ((index != 0) && (mode.s.type == 1))) { + cvmx_write_csr(CVMX_GMXX_TXX_CLK + (index, interface), 1); + } + } + } + + /* Do a read to make sure all setup stuff is complete */ + cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); + + /* Save the new GMX setting without enabling the port */ + cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), new_gmx_cfg.u64); + + /* Enable the lowest level RX */ + cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface), + cvmx_read_csr(CVMX_ASXX_RX_PRT_EN(interface)) | (1 << + index)); + + /* Re-enable the TX path */ + for (i = 0; i < cvmx_pko_get_num_queues(ipd_port); i++) { + int queue = cvmx_pko_get_base_queue(ipd_port) + i; + cvmx_write_csr(CVMX_PKO_REG_READ_IDX, queue); + cvmx_write_csr(CVMX_PKO_MEM_QUEUE_QOS, + pko_mem_queue_qos_save[i].u64); + } + + /* Restore backpressure */ + cvmx_write_csr(CVMX_GMXX_TX_OVR_BP(interface), gmx_tx_ovr_bp_save.u64); + + /* Restore the GMX enable state. Port config is complete */ + new_gmx_cfg.s.en = original_gmx_cfg.s.en; + cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), new_gmx_cfg.u64); + + return result; +} + +/** + * Configure a port for internal and/or external loopback. Internal loopback + * causes packets sent by the port to be received by Octeon. External loopback + * causes packets received from the wire to sent out again. + * + * @ipd_port: IPD/PKO port to loopback. + * @enable_internal: + * Non zero if you want internal loopback + * @enable_external: + * Non zero if you want external loopback + * + * Returns Zero on success, negative on failure. + */ +int __cvmx_helper_rgmii_configure_loopback(int ipd_port, int enable_internal, + int enable_external) +{ + int interface = cvmx_helper_get_interface_num(ipd_port); + int index = cvmx_helper_get_interface_index_num(ipd_port); + int original_enable; + union cvmx_gmxx_prtx_cfg gmx_cfg; + union cvmx_asxx_prt_loop asxx_prt_loop; + + /* Read the current enable state and save it */ + gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); + original_enable = gmx_cfg.s.en; + /* Force port to be disabled */ + gmx_cfg.s.en = 0; + if (enable_internal) { + /* Force speed if we're doing internal loopback */ + gmx_cfg.s.duplex = 1; + gmx_cfg.s.slottime = 1; + gmx_cfg.s.speed = 1; + cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 1); + cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 0x200); + cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0x2000); + } + cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64); + + /* Set the loopback bits */ + asxx_prt_loop.u64 = cvmx_read_csr(CVMX_ASXX_PRT_LOOP(interface)); + if (enable_internal) + asxx_prt_loop.s.int_loop |= 1 << index; + else + asxx_prt_loop.s.int_loop &= ~(1 << index); + if (enable_external) + asxx_prt_loop.s.ext_loop |= 1 << index; + else + asxx_prt_loop.s.ext_loop &= ~(1 << index); + cvmx_write_csr(CVMX_ASXX_PRT_LOOP(interface), asxx_prt_loop.u64); + + /* Force enables in internal loopback */ + if (enable_internal) { + uint64_t tmp; + tmp = cvmx_read_csr(CVMX_ASXX_TX_PRT_EN(interface)); + cvmx_write_csr(CVMX_ASXX_TX_PRT_EN(interface), + (1 << index) | tmp); + tmp = cvmx_read_csr(CVMX_ASXX_RX_PRT_EN(interface)); + cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface), + (1 << index) | tmp); + original_enable = 1; + } + + /* Restore the enable state */ + gmx_cfg.s.en = original_enable; + cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64); + return 0; +} diff --git a/drivers/staging/octeon/cvmx-helper-rgmii.h b/drivers/staging/octeon/cvmx-helper-rgmii.h new file mode 100644 index 000000000000..ea2652604a57 --- /dev/null +++ b/drivers/staging/octeon/cvmx-helper-rgmii.h @@ -0,0 +1,110 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2008 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +/** + * @file + * + * Functions for RGMII/GMII/MII initialization, configuration, + * and monitoring. + * + */ +#ifndef __CVMX_HELPER_RGMII_H__ +#define __CVMX_HELPER_RGMII_H__ + +/** + * Probe RGMII ports and determine the number present + * + * @interface: Interface to probe + * + * Returns Number of RGMII/GMII/MII ports (0-4). + */ +extern int __cvmx_helper_rgmii_probe(int interface); + +/** + * Put an RGMII interface in loopback mode. Internal packets sent + * out will be received back again on the same port. Externally + * received packets will echo back out. + * + * @port: IPD port number to loop. + */ +extern void cvmx_helper_rgmii_internal_loopback(int port); + +/** + * Configure all of the ASX, GMX, and PKO regsiters required + * to get RGMII to function on the supplied interface. + * + * @interface: PKO Interface to configure (0 or 1) + * + * Returns Zero on success + */ +extern int __cvmx_helper_rgmii_enable(int interface); + +/** + * Return the link state of an IPD/PKO port as returned by + * auto negotiation. The result of this function may not match + * Octeon's link config if auto negotiation has changed since + * the last call to cvmx_helper_link_set(). + * + * @ipd_port: IPD/PKO port to query + * + * Returns Link state + */ +extern cvmx_helper_link_info_t __cvmx_helper_rgmii_link_get(int ipd_port); + +/** + * Configure an IPD/PKO port for the specified link state. This + * function does not influence auto negotiation at the PHY level. + * The passed link state must always match the link state returned + * by cvmx_helper_link_get(). It is normally best to use + * cvmx_helper_link_autoconf() instead. + * + * @ipd_port: IPD/PKO port to configure + * @link_info: The new link state + * + * Returns Zero on success, negative on failure + */ +extern int __cvmx_helper_rgmii_link_set(int ipd_port, + cvmx_helper_link_info_t link_info); + +/** + * Configure a port for internal and/or external loopback. Internal loopback + * causes packets sent by the port to be received by Octeon. External loopback + * causes packets received from the wire to sent out again. + * + * @ipd_port: IPD/PKO port to loopback. + * @enable_internal: + * Non zero if you want internal loopback + * @enable_external: + * Non zero if you want external loopback + * + * Returns Zero on success, negative on failure. + */ +extern int __cvmx_helper_rgmii_configure_loopback(int ipd_port, + int enable_internal, + int enable_external); + +#endif diff --git a/drivers/staging/octeon/cvmx-helper-sgmii.c b/drivers/staging/octeon/cvmx-helper-sgmii.c new file mode 100644 index 000000000000..6214e3b6d975 --- /dev/null +++ b/drivers/staging/octeon/cvmx-helper-sgmii.c @@ -0,0 +1,550 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2008 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +/* + * Functions for SGMII initialization, configuration, + * and monitoring. + */ + +#include + +#include "cvmx-config.h" + +#include "cvmx-mdio.h" +#include "cvmx-helper.h" +#include "cvmx-helper-board.h" + +#include "cvmx-gmxx-defs.h" +#include "cvmx-pcsx-defs.h" + +void __cvmx_interrupt_gmxx_enable(int interface); +void __cvmx_interrupt_pcsx_intx_en_reg_enable(int index, int block); +void __cvmx_interrupt_pcsxx_int_en_reg_enable(int index); + +/** + * Perform initialization required only once for an SGMII port. + * + * @interface: Interface to init + * @index: Index of prot on the interface + * + * Returns Zero on success, negative on failure + */ +static int __cvmx_helper_sgmii_hardware_init_one_time(int interface, int index) +{ + const uint64_t clock_mhz = cvmx_sysinfo_get()->cpu_clock_hz / 1000000; + union cvmx_pcsx_miscx_ctl_reg pcs_misc_ctl_reg; + union cvmx_pcsx_linkx_timer_count_reg pcsx_linkx_timer_count_reg; + union cvmx_gmxx_prtx_cfg gmxx_prtx_cfg; + + /* Disable GMX */ + gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); + gmxx_prtx_cfg.s.en = 0; + cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64); + + /* + * Write PCS*_LINK*_TIMER_COUNT_REG[COUNT] with the + * appropriate value. 1000BASE-X specifies a 10ms + * interval. SGMII specifies a 1.6ms interval. + */ + pcs_misc_ctl_reg.u64 = + cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface)); + pcsx_linkx_timer_count_reg.u64 = + cvmx_read_csr(CVMX_PCSX_LINKX_TIMER_COUNT_REG(index, interface)); + if (pcs_misc_ctl_reg.s.mode) { + /* 1000BASE-X */ + pcsx_linkx_timer_count_reg.s.count = + (10000ull * clock_mhz) >> 10; + } else { + /* SGMII */ + pcsx_linkx_timer_count_reg.s.count = + (1600ull * clock_mhz) >> 10; + } + cvmx_write_csr(CVMX_PCSX_LINKX_TIMER_COUNT_REG(index, interface), + pcsx_linkx_timer_count_reg.u64); + + /* + * Write the advertisement register to be used as the + * tx_Config_Reg of the autonegotiation. In + * 1000BASE-X mode, tx_Config_Reg is PCS*_AN*_ADV_REG. + * In SGMII PHY mode, tx_Config_Reg is + * PCS*_SGM*_AN_ADV_REG. In SGMII MAC mode, + * tx_Config_Reg is the fixed value 0x4001, so this + * step can be skipped. + */ + if (pcs_misc_ctl_reg.s.mode) { + /* 1000BASE-X */ + union cvmx_pcsx_anx_adv_reg pcsx_anx_adv_reg; + pcsx_anx_adv_reg.u64 = + cvmx_read_csr(CVMX_PCSX_ANX_ADV_REG(index, interface)); + pcsx_anx_adv_reg.s.rem_flt = 0; + pcsx_anx_adv_reg.s.pause = 3; + pcsx_anx_adv_reg.s.hfd = 1; + pcsx_anx_adv_reg.s.fd = 1; + cvmx_write_csr(CVMX_PCSX_ANX_ADV_REG(index, interface), + pcsx_anx_adv_reg.u64); + } else { + union cvmx_pcsx_miscx_ctl_reg pcsx_miscx_ctl_reg; + pcsx_miscx_ctl_reg.u64 = + cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface)); + if (pcsx_miscx_ctl_reg.s.mac_phy) { + /* PHY Mode */ + union cvmx_pcsx_sgmx_an_adv_reg pcsx_sgmx_an_adv_reg; + pcsx_sgmx_an_adv_reg.u64 = + cvmx_read_csr(CVMX_PCSX_SGMX_AN_ADV_REG + (index, interface)); + pcsx_sgmx_an_adv_reg.s.link = 1; + pcsx_sgmx_an_adv_reg.s.dup = 1; + pcsx_sgmx_an_adv_reg.s.speed = 2; + cvmx_write_csr(CVMX_PCSX_SGMX_AN_ADV_REG + (index, interface), + pcsx_sgmx_an_adv_reg.u64); + } else { + /* MAC Mode - Nothing to do */ + } + } + return 0; +} + +/** + * Initialize the SERTES link for the first time or after a loss + * of link. + * + * @interface: Interface to init + * @index: Index of prot on the interface + * + * Returns Zero on success, negative on failure + */ +static int __cvmx_helper_sgmii_hardware_init_link(int interface, int index) +{ + union cvmx_pcsx_mrx_control_reg control_reg; + + /* + * Take PCS through a reset sequence. + * PCS*_MR*_CONTROL_REG[PWR_DN] should be cleared to zero. + * Write PCS*_MR*_CONTROL_REG[RESET]=1 (while not changing the + * value of the other PCS*_MR*_CONTROL_REG bits). Read + * PCS*_MR*_CONTROL_REG[RESET] until it changes value to + * zero. + */ + control_reg.u64 = + cvmx_read_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface)); + if (cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM) { + control_reg.s.reset = 1; + cvmx_write_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface), + control_reg.u64); + if (CVMX_WAIT_FOR_FIELD64 + (CVMX_PCSX_MRX_CONTROL_REG(index, interface), + union cvmx_pcsx_mrx_control_reg, reset, ==, 0, 10000)) { + cvmx_dprintf("SGMII%d: Timeout waiting for port %d " + "to finish reset\n", + interface, index); + return -1; + } + } + + /* + * Write PCS*_MR*_CONTROL_REG[RST_AN]=1 to ensure a fresh + * sgmii negotiation starts. + */ + control_reg.s.rst_an = 1; + control_reg.s.an_en = 1; + control_reg.s.pwr_dn = 0; + cvmx_write_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface), + control_reg.u64); + + /* + * Wait for PCS*_MR*_STATUS_REG[AN_CPT] to be set, indicating + * that sgmii autonegotiation is complete. In MAC mode this + * isn't an ethernet link, but a link between Octeon and the + * PHY. + */ + if ((cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM) && + CVMX_WAIT_FOR_FIELD64(CVMX_PCSX_MRX_STATUS_REG(index, interface), + union cvmx_pcsx_mrx_status_reg, an_cpt, ==, 1, + 10000)) { + /* cvmx_dprintf("SGMII%d: Port %d link timeout\n", interface, index); */ + return -1; + } + return 0; +} + +/** + * Configure an SGMII link to the specified speed after the SERTES + * link is up. + * + * @interface: Interface to init + * @index: Index of prot on the interface + * @link_info: Link state to configure + * + * Returns Zero on success, negative on failure + */ +static int __cvmx_helper_sgmii_hardware_init_link_speed(int interface, + int index, + cvmx_helper_link_info_t + link_info) +{ + int is_enabled; + union cvmx_gmxx_prtx_cfg gmxx_prtx_cfg; + union cvmx_pcsx_miscx_ctl_reg pcsx_miscx_ctl_reg; + + /* Disable GMX before we make any changes. Remember the enable state */ + gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); + is_enabled = gmxx_prtx_cfg.s.en; + gmxx_prtx_cfg.s.en = 0; + cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64); + + /* Wait for GMX to be idle */ + if (CVMX_WAIT_FOR_FIELD64 + (CVMX_GMXX_PRTX_CFG(index, interface), union cvmx_gmxx_prtx_cfg, + rx_idle, ==, 1, 10000) + || CVMX_WAIT_FOR_FIELD64(CVMX_GMXX_PRTX_CFG(index, interface), + union cvmx_gmxx_prtx_cfg, tx_idle, ==, 1, + 10000)) { + cvmx_dprintf + ("SGMII%d: Timeout waiting for port %d to be idle\n", + interface, index); + return -1; + } + + /* Read GMX CFG again to make sure the disable completed */ + gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); + + /* + * Get the misc control for PCS. We will need to set the + * duplication amount. + */ + pcsx_miscx_ctl_reg.u64 = + cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface)); + + /* + * Use GMXENO to force the link down if the status we get says + * it should be down. + */ + pcsx_miscx_ctl_reg.s.gmxeno = !link_info.s.link_up; + + /* Only change the duplex setting if the link is up */ + if (link_info.s.link_up) + gmxx_prtx_cfg.s.duplex = link_info.s.full_duplex; + + /* Do speed based setting for GMX */ + switch (link_info.s.speed) { + case 10: + gmxx_prtx_cfg.s.speed = 0; + gmxx_prtx_cfg.s.speed_msb = 1; + gmxx_prtx_cfg.s.slottime = 0; + /* Setting from GMX-603 */ + pcsx_miscx_ctl_reg.s.samp_pt = 25; + cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 64); + cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0); + break; + case 100: + gmxx_prtx_cfg.s.speed = 0; + gmxx_prtx_cfg.s.speed_msb = 0; + gmxx_prtx_cfg.s.slottime = 0; + pcsx_miscx_ctl_reg.s.samp_pt = 0x5; + cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 64); + cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0); + break; + case 1000: + gmxx_prtx_cfg.s.speed = 1; + gmxx_prtx_cfg.s.speed_msb = 0; + gmxx_prtx_cfg.s.slottime = 1; + pcsx_miscx_ctl_reg.s.samp_pt = 1; + cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 512); + cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 8192); + break; + default: + break; + } + + /* Write the new misc control for PCS */ + cvmx_write_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface), + pcsx_miscx_ctl_reg.u64); + + /* Write the new GMX settings with the port still disabled */ + cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64); + + /* Read GMX CFG again to make sure the config completed */ + gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); + + /* Restore the enabled / disabled state */ + gmxx_prtx_cfg.s.en = is_enabled; + cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64); + + return 0; +} + +/** + * Bring up the SGMII interface to be ready for packet I/O but + * leave I/O disabled using the GMX override. This function + * follows the bringup documented in 10.6.3 of the manual. + * + * @interface: Interface to bringup + * @num_ports: Number of ports on the interface + * + * Returns Zero on success, negative on failure + */ +static int __cvmx_helper_sgmii_hardware_init(int interface, int num_ports) +{ + int index; + + __cvmx_helper_setup_gmx(interface, num_ports); + + for (index = 0; index < num_ports; index++) { + int ipd_port = cvmx_helper_get_ipd_port(interface, index); + __cvmx_helper_sgmii_hardware_init_one_time(interface, index); + __cvmx_helper_sgmii_link_set(ipd_port, + __cvmx_helper_sgmii_link_get + (ipd_port)); + + } + + return 0; +} + +/** + * Probe a SGMII interface and determine the number of ports + * connected to it. The SGMII interface should still be down after + * this call. + * + * @interface: Interface to probe + * + * Returns Number of ports on the interface. Zero to disable. + */ +int __cvmx_helper_sgmii_probe(int interface) +{ + union cvmx_gmxx_inf_mode mode; + + /* + * Due to errata GMX-700 on CN56XXp1.x and CN52XXp1.x, the + * interface needs to be enabled before IPD otherwise per port + * backpressure may not work properly + */ + mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface)); + mode.s.en = 1; + cvmx_write_csr(CVMX_GMXX_INF_MODE(interface), mode.u64); + return 4; +} + +/** + * Bringup and enable a SGMII interface. After this call packet + * I/O should be fully functional. This is called with IPD + * enabled but PKO disabled. + * + * @interface: Interface to bring up + * + * Returns Zero on success, negative on failure + */ +int __cvmx_helper_sgmii_enable(int interface) +{ + int num_ports = cvmx_helper_ports_on_interface(interface); + int index; + + __cvmx_helper_sgmii_hardware_init(interface, num_ports); + + for (index = 0; index < num_ports; index++) { + union cvmx_gmxx_prtx_cfg gmxx_prtx_cfg; + gmxx_prtx_cfg.u64 = + cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); + gmxx_prtx_cfg.s.en = 1; + cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), + gmxx_prtx_cfg.u64); + __cvmx_interrupt_pcsx_intx_en_reg_enable(index, interface); + } + __cvmx_interrupt_pcsxx_int_en_reg_enable(interface); + __cvmx_interrupt_gmxx_enable(interface); + return 0; +} + +/** + * Return the link state of an IPD/PKO port as returned by + * auto negotiation. The result of this function may not match + * Octeon's link config if auto negotiation has changed since + * the last call to cvmx_helper_link_set(). + * + * @ipd_port: IPD/PKO port to query + * + * Returns Link state + */ +cvmx_helper_link_info_t __cvmx_helper_sgmii_link_get(int ipd_port) +{ + cvmx_helper_link_info_t result; + union cvmx_pcsx_miscx_ctl_reg pcs_misc_ctl_reg; + int interface = cvmx_helper_get_interface_num(ipd_port); + int index = cvmx_helper_get_interface_index_num(ipd_port); + union cvmx_pcsx_mrx_control_reg pcsx_mrx_control_reg; + + result.u64 = 0; + + if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM) { + /* The simulator gives you a simulated 1Gbps full duplex link */ + result.s.link_up = 1; + result.s.full_duplex = 1; + result.s.speed = 1000; + return result; + } + + pcsx_mrx_control_reg.u64 = + cvmx_read_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface)); + if (pcsx_mrx_control_reg.s.loopbck1) { + /* Force 1Gbps full duplex link for internal loopback */ + result.s.link_up = 1; + result.s.full_duplex = 1; + result.s.speed = 1000; + return result; + } + + pcs_misc_ctl_reg.u64 = + cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface)); + if (pcs_misc_ctl_reg.s.mode) { + /* 1000BASE-X */ + /* FIXME */ + } else { + union cvmx_pcsx_miscx_ctl_reg pcsx_miscx_ctl_reg; + pcsx_miscx_ctl_reg.u64 = + cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface)); + if (pcsx_miscx_ctl_reg.s.mac_phy) { + /* PHY Mode */ + union cvmx_pcsx_mrx_status_reg pcsx_mrx_status_reg; + union cvmx_pcsx_anx_results_reg pcsx_anx_results_reg; + + /* + * Don't bother continuing if the SERTES low + * level link is down + */ + pcsx_mrx_status_reg.u64 = + cvmx_read_csr(CVMX_PCSX_MRX_STATUS_REG + (index, interface)); + if (pcsx_mrx_status_reg.s.lnk_st == 0) { + if (__cvmx_helper_sgmii_hardware_init_link + (interface, index) != 0) + return result; + } + + /* Read the autoneg results */ + pcsx_anx_results_reg.u64 = + cvmx_read_csr(CVMX_PCSX_ANX_RESULTS_REG + (index, interface)); + if (pcsx_anx_results_reg.s.an_cpt) { + /* + * Auto negotiation is complete. Set + * status accordingly. + */ + result.s.full_duplex = + pcsx_anx_results_reg.s.dup; + result.s.link_up = + pcsx_anx_results_reg.s.link_ok; + switch (pcsx_anx_results_reg.s.spd) { + case 0: + result.s.speed = 10; + break; + case 1: + result.s.speed = 100; + break; + case 2: + result.s.speed = 1000; + break; + default: + result.s.speed = 0; + result.s.link_up = 0; + break; + } + } else { + /* + * Auto negotiation isn't + * complete. Return link down. + */ + result.s.speed = 0; + result.s.link_up = 0; + } + } else { /* MAC Mode */ + + result = __cvmx_helper_board_link_get(ipd_port); + } + } + return result; +} + +/** + * Configure an IPD/PKO port for the specified link state. This + * function does not influence auto negotiation at the PHY level. + * The passed link state must always match the link state returned + * by cvmx_helper_link_get(). It is normally best to use + * cvmx_helper_link_autoconf() instead. + * + * @ipd_port: IPD/PKO port to configure + * @link_info: The new link state + * + * Returns Zero on success, negative on failure + */ +int __cvmx_helper_sgmii_link_set(int ipd_port, + cvmx_helper_link_info_t link_info) +{ + int interface = cvmx_helper_get_interface_num(ipd_port); + int index = cvmx_helper_get_interface_index_num(ipd_port); + __cvmx_helper_sgmii_hardware_init_link(interface, index); + return __cvmx_helper_sgmii_hardware_init_link_speed(interface, index, + link_info); +} + +/** + * Configure a port for internal and/or external loopback. Internal + * loopback causes packets sent by the port to be received by + * Octeon. External loopback causes packets received from the wire to + * sent out again. + * + * @ipd_port: IPD/PKO port to loopback. + * @enable_internal: + * Non zero if you want internal loopback + * @enable_external: + * Non zero if you want external loopback + * + * Returns Zero on success, negative on failure. + */ +int __cvmx_helper_sgmii_configure_loopback(int ipd_port, int enable_internal, + int enable_external) +{ + int interface = cvmx_helper_get_interface_num(ipd_port); + int index = cvmx_helper_get_interface_index_num(ipd_port); + union cvmx_pcsx_mrx_control_reg pcsx_mrx_control_reg; + union cvmx_pcsx_miscx_ctl_reg pcsx_miscx_ctl_reg; + + pcsx_mrx_control_reg.u64 = + cvmx_read_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface)); + pcsx_mrx_control_reg.s.loopbck1 = enable_internal; + cvmx_write_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface), + pcsx_mrx_control_reg.u64); + + pcsx_miscx_ctl_reg.u64 = + cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface)); + pcsx_miscx_ctl_reg.s.loopbck2 = enable_external; + cvmx_write_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface), + pcsx_miscx_ctl_reg.u64); + + __cvmx_helper_sgmii_hardware_init_link(interface, index); + return 0; +} diff --git a/drivers/staging/octeon/cvmx-helper-sgmii.h b/drivers/staging/octeon/cvmx-helper-sgmii.h new file mode 100644 index 000000000000..19b48d60857f --- /dev/null +++ b/drivers/staging/octeon/cvmx-helper-sgmii.h @@ -0,0 +1,104 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2008 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +/** + * @file + * + * Functions for SGMII initialization, configuration, + * and monitoring. + * + */ +#ifndef __CVMX_HELPER_SGMII_H__ +#define __CVMX_HELPER_SGMII_H__ + +/** + * Probe a SGMII interface and determine the number of ports + * connected to it. The SGMII interface should still be down after + * this call. + * + * @interface: Interface to probe + * + * Returns Number of ports on the interface. Zero to disable. + */ +extern int __cvmx_helper_sgmii_probe(int interface); + +/** + * Bringup and enable a SGMII interface. After this call packet + * I/O should be fully functional. This is called with IPD + * enabled but PKO disabled. + * + * @interface: Interface to bring up + * + * Returns Zero on success, negative on failure + */ +extern int __cvmx_helper_sgmii_enable(int interface); + +/** + * Return the link state of an IPD/PKO port as returned by + * auto negotiation. The result of this function may not match + * Octeon's link config if auto negotiation has changed since + * the last call to cvmx_helper_link_set(). + * + * @ipd_port: IPD/PKO port to query + * + * Returns Link state + */ +extern cvmx_helper_link_info_t __cvmx_helper_sgmii_link_get(int ipd_port); + +/** + * Configure an IPD/PKO port for the specified link state. This + * function does not influence auto negotiation at the PHY level. + * The passed link state must always match the link state returned + * by cvmx_helper_link_get(). It is normally best to use + * cvmx_helper_link_autoconf() instead. + * + * @ipd_port: IPD/PKO port to configure + * @link_info: The new link state + * + * Returns Zero on success, negative on failure + */ +extern int __cvmx_helper_sgmii_link_set(int ipd_port, + cvmx_helper_link_info_t link_info); + +/** + * Configure a port for internal and/or external loopback. Internal loopback + * causes packets sent by the port to be received by Octeon. External loopback + * causes packets received from the wire to sent out again. + * + * @ipd_port: IPD/PKO port to loopback. + * @enable_internal: + * Non zero if you want internal loopback + * @enable_external: + * Non zero if you want external loopback + * + * Returns Zero on success, negative on failure. + */ +extern int __cvmx_helper_sgmii_configure_loopback(int ipd_port, + int enable_internal, + int enable_external); + +#endif diff --git a/drivers/staging/octeon/cvmx-helper-spi.c b/drivers/staging/octeon/cvmx-helper-spi.c new file mode 100644 index 000000000000..8ba6c832471e --- /dev/null +++ b/drivers/staging/octeon/cvmx-helper-spi.c @@ -0,0 +1,195 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2008 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +void __cvmx_interrupt_gmxx_enable(int interface); +void __cvmx_interrupt_spxx_int_msk_enable(int index); +void __cvmx_interrupt_stxx_int_msk_enable(int index); + +/* + * Functions for SPI initialization, configuration, + * and monitoring. + */ +#include + +#include "cvmx-config.h" +#include "cvmx-spi.h" +#include "cvmx-helper.h" + +#include "cvmx-pip-defs.h" +#include "cvmx-pko-defs.h" + +/* + * CVMX_HELPER_SPI_TIMEOUT is used to determine how long the SPI + * initialization routines wait for SPI training. You can override the + * value using executive-config.h if necessary. + */ +#ifndef CVMX_HELPER_SPI_TIMEOUT +#define CVMX_HELPER_SPI_TIMEOUT 10 +#endif + +/** + * Probe a SPI interface and determine the number of ports + * connected to it. The SPI interface should still be down after + * this call. + * + * @interface: Interface to probe + * + * Returns Number of ports on the interface. Zero to disable. + */ +int __cvmx_helper_spi_probe(int interface) +{ + int num_ports = 0; + + if ((cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM) && + cvmx_spi4000_is_present(interface)) { + num_ports = 10; + } else { + union cvmx_pko_reg_crc_enable enable; + num_ports = 16; + /* + * Unlike the SPI4000, most SPI devices don't + * automatically put on the L2 CRC. For everything + * except for the SPI4000 have PKO append the L2 CRC + * to the packet. + */ + enable.u64 = cvmx_read_csr(CVMX_PKO_REG_CRC_ENABLE); + enable.s.enable |= 0xffff << (interface * 16); + cvmx_write_csr(CVMX_PKO_REG_CRC_ENABLE, enable.u64); + } + __cvmx_helper_setup_gmx(interface, num_ports); + return num_ports; +} + +/** + * Bringup and enable a SPI interface. After this call packet I/O + * should be fully functional. This is called with IPD enabled but + * PKO disabled. + * + * @interface: Interface to bring up + * + * Returns Zero on success, negative on failure + */ +int __cvmx_helper_spi_enable(int interface) +{ + /* + * Normally the ethernet L2 CRC is checked and stripped in the + * GMX block. When you are using SPI, this isn' the case and + * IPD needs to check the L2 CRC. + */ + int num_ports = cvmx_helper_ports_on_interface(interface); + int ipd_port; + for (ipd_port = interface * 16; ipd_port < interface * 16 + num_ports; + ipd_port++) { + union cvmx_pip_prt_cfgx port_config; + port_config.u64 = cvmx_read_csr(CVMX_PIP_PRT_CFGX(ipd_port)); + port_config.s.crc_en = 1; + cvmx_write_csr(CVMX_PIP_PRT_CFGX(ipd_port), port_config.u64); + } + + if (cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM) { + cvmx_spi_start_interface(interface, CVMX_SPI_MODE_DUPLEX, + CVMX_HELPER_SPI_TIMEOUT, num_ports); + if (cvmx_spi4000_is_present(interface)) + cvmx_spi4000_initialize(interface); + } + __cvmx_interrupt_spxx_int_msk_enable(interface); + __cvmx_interrupt_stxx_int_msk_enable(interface); + __cvmx_interrupt_gmxx_enable(interface); + return 0; +} + +/** + * Return the link state of an IPD/PKO port as returned by + * auto negotiation. The result of this function may not match + * Octeon's link config if auto negotiation has changed since + * the last call to cvmx_helper_link_set(). + * + * @ipd_port: IPD/PKO port to query + * + * Returns Link state + */ +cvmx_helper_link_info_t __cvmx_helper_spi_link_get(int ipd_port) +{ + cvmx_helper_link_info_t result; + int interface = cvmx_helper_get_interface_num(ipd_port); + int index = cvmx_helper_get_interface_index_num(ipd_port); + result.u64 = 0; + + if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM) { + /* The simulator gives you a simulated full duplex link */ + result.s.link_up = 1; + result.s.full_duplex = 1; + result.s.speed = 10000; + } else if (cvmx_spi4000_is_present(interface)) { + union cvmx_gmxx_rxx_rx_inbnd inband = + cvmx_spi4000_check_speed(interface, index); + result.s.link_up = inband.s.status; + result.s.full_duplex = inband.s.duplex; + switch (inband.s.speed) { + case 0: /* 10 Mbps */ + result.s.speed = 10; + break; + case 1: /* 100 Mbps */ + result.s.speed = 100; + break; + case 2: /* 1 Gbps */ + result.s.speed = 1000; + break; + case 3: /* Illegal */ + result.s.speed = 0; + result.s.link_up = 0; + break; + } + } else { + /* For generic SPI we can't determine the link, just return some + sane results */ + result.s.link_up = 1; + result.s.full_duplex = 1; + result.s.speed = 10000; + } + return result; +} + +/** + * Configure an IPD/PKO port for the specified link state. This + * function does not influence auto negotiation at the PHY level. + * The passed link state must always match the link state returned + * by cvmx_helper_link_get(). It is normally best to use + * cvmx_helper_link_autoconf() instead. + * + * @ipd_port: IPD/PKO port to configure + * @link_info: The new link state + * + * Returns Zero on success, negative on failure + */ +int __cvmx_helper_spi_link_set(int ipd_port, cvmx_helper_link_info_t link_info) +{ + /* Nothing to do. If we have a SPI4000 then the setup was already performed + by cvmx_spi4000_check_speed(). If not then there isn't any link + info */ + return 0; +} diff --git a/drivers/staging/octeon/cvmx-helper-spi.h b/drivers/staging/octeon/cvmx-helper-spi.h new file mode 100644 index 000000000000..69bac036d10e --- /dev/null +++ b/drivers/staging/octeon/cvmx-helper-spi.h @@ -0,0 +1,84 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2008 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +/* + * Functions for SPI initialization, configuration, + * and monitoring. + */ +#ifndef __CVMX_HELPER_SPI_H__ +#define __CVMX_HELPER_SPI_H__ + +/** + * Probe a SPI interface and determine the number of ports + * connected to it. The SPI interface should still be down after + * this call. + * + * @interface: Interface to probe + * + * Returns Number of ports on the interface. Zero to disable. + */ +extern int __cvmx_helper_spi_probe(int interface); + +/** + * Bringup and enable a SPI interface. After this call packet I/O + * should be fully functional. This is called with IPD enabled but + * PKO disabled. + * + * @interface: Interface to bring up + * + * Returns Zero on success, negative on failure + */ +extern int __cvmx_helper_spi_enable(int interface); + +/** + * Return the link state of an IPD/PKO port as returned by + * auto negotiation. The result of this function may not match + * Octeon's link config if auto negotiation has changed since + * the last call to cvmx_helper_link_set(). + * + * @ipd_port: IPD/PKO port to query + * + * Returns Link state + */ +extern cvmx_helper_link_info_t __cvmx_helper_spi_link_get(int ipd_port); + +/** + * Configure an IPD/PKO port for the specified link state. This + * function does not influence auto negotiation at the PHY level. + * The passed link state must always match the link state returned + * by cvmx_helper_link_get(). It is normally best to use + * cvmx_helper_link_autoconf() instead. + * + * @ipd_port: IPD/PKO port to configure + * @link_info: The new link state + * + * Returns Zero on success, negative on failure + */ +extern int __cvmx_helper_spi_link_set(int ipd_port, + cvmx_helper_link_info_t link_info); + +#endif diff --git a/drivers/staging/octeon/cvmx-helper-util.c b/drivers/staging/octeon/cvmx-helper-util.c new file mode 100644 index 000000000000..41ef8a40bb03 --- /dev/null +++ b/drivers/staging/octeon/cvmx-helper-util.c @@ -0,0 +1,433 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2008 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +/* + * Small helper utilities. + */ +#include + +#include + +#include "cvmx-config.h" + +#include "cvmx-fpa.h" +#include "cvmx-pip.h" +#include "cvmx-pko.h" +#include "cvmx-ipd.h" +#include "cvmx-spi.h" + +#include "cvmx-helper.h" +#include "cvmx-helper-util.h" + +#include + +/** + * Convert a interface mode into a human readable string + * + * @mode: Mode to convert + * + * Returns String + */ +const char *cvmx_helper_interface_mode_to_string(cvmx_helper_interface_mode_t + mode) +{ + switch (mode) { + case CVMX_HELPER_INTERFACE_MODE_DISABLED: + return "DISABLED"; + case CVMX_HELPER_INTERFACE_MODE_RGMII: + return "RGMII"; + case CVMX_HELPER_INTERFACE_MODE_GMII: + return "GMII"; + case CVMX_HELPER_INTERFACE_MODE_SPI: + return "SPI"; + case CVMX_HELPER_INTERFACE_MODE_PCIE: + return "PCIE"; + case CVMX_HELPER_INTERFACE_MODE_XAUI: + return "XAUI"; + case CVMX_HELPER_INTERFACE_MODE_SGMII: + return "SGMII"; + case CVMX_HELPER_INTERFACE_MODE_PICMG: + return "PICMG"; + case CVMX_HELPER_INTERFACE_MODE_NPI: + return "NPI"; + case CVMX_HELPER_INTERFACE_MODE_LOOP: + return "LOOP"; + } + return "UNKNOWN"; +} + +/** + * Debug routine to dump the packet structure to the console + * + * @work: Work queue entry containing the packet to dump + * Returns + */ +int cvmx_helper_dump_packet(cvmx_wqe_t *work) +{ + uint64_t count; + uint64_t remaining_bytes; + union cvmx_buf_ptr buffer_ptr; + uint64_t start_of_buffer; + uint8_t *data_address; + uint8_t *end_of_data; + + cvmx_dprintf("Packet Length: %u\n", work->len); + cvmx_dprintf(" Input Port: %u\n", work->ipprt); + cvmx_dprintf(" QoS: %u\n", work->qos); + cvmx_dprintf(" Buffers: %u\n", work->word2.s.bufs); + + if (work->word2.s.bufs == 0) { + union cvmx_ipd_wqe_fpa_queue wqe_pool; + wqe_pool.u64 = cvmx_read_csr(CVMX_IPD_WQE_FPA_QUEUE); + buffer_ptr.u64 = 0; + buffer_ptr.s.pool = wqe_pool.s.wqe_pool; + buffer_ptr.s.size = 128; + buffer_ptr.s.addr = cvmx_ptr_to_phys(work->packet_data); + if (likely(!work->word2.s.not_IP)) { + union cvmx_pip_ip_offset pip_ip_offset; + pip_ip_offset.u64 = cvmx_read_csr(CVMX_PIP_IP_OFFSET); + buffer_ptr.s.addr += + (pip_ip_offset.s.offset << 3) - + work->word2.s.ip_offset; + buffer_ptr.s.addr += (work->word2.s.is_v6 ^ 1) << 2; + } else { + /* + * WARNING: This code assumes that the packet + * is not RAW. If it was, we would use + * PIP_GBL_CFG[RAW_SHF] instead of + * PIP_GBL_CFG[NIP_SHF]. + */ + union cvmx_pip_gbl_cfg pip_gbl_cfg; + pip_gbl_cfg.u64 = cvmx_read_csr(CVMX_PIP_GBL_CFG); + buffer_ptr.s.addr += pip_gbl_cfg.s.nip_shf; + } + } else + buffer_ptr = work->packet_ptr; + remaining_bytes = work->len; + + while (remaining_bytes) { + start_of_buffer = + ((buffer_ptr.s.addr >> 7) - buffer_ptr.s.back) << 7; + cvmx_dprintf(" Buffer Start:%llx\n", + (unsigned long long)start_of_buffer); + cvmx_dprintf(" Buffer I : %u\n", buffer_ptr.s.i); + cvmx_dprintf(" Buffer Back: %u\n", buffer_ptr.s.back); + cvmx_dprintf(" Buffer Pool: %u\n", buffer_ptr.s.pool); + cvmx_dprintf(" Buffer Data: %llx\n", + (unsigned long long)buffer_ptr.s.addr); + cvmx_dprintf(" Buffer Size: %u\n", buffer_ptr.s.size); + + cvmx_dprintf("\t\t"); + data_address = (uint8_t *) cvmx_phys_to_ptr(buffer_ptr.s.addr); + end_of_data = data_address + buffer_ptr.s.size; + count = 0; + while (data_address < end_of_data) { + if (remaining_bytes == 0) + break; + else + remaining_bytes--; + cvmx_dprintf("%02x", (unsigned int)*data_address); + data_address++; + if (remaining_bytes && (count == 7)) { + cvmx_dprintf("\n\t\t"); + count = 0; + } else + count++; + } + cvmx_dprintf("\n"); + + if (remaining_bytes) + buffer_ptr = *(union cvmx_buf_ptr *) + cvmx_phys_to_ptr(buffer_ptr.s.addr - 8); + } + return 0; +} + +/** + * Setup Random Early Drop on a specific input queue + * + * @queue: Input queue to setup RED on (0-7) + * @pass_thresh: + * Packets will begin slowly dropping when there are less than + * this many packet buffers free in FPA 0. + * @drop_thresh: + * All incomming packets will be dropped when there are less + * than this many free packet buffers in FPA 0. + * Returns Zero on success. Negative on failure + */ +int cvmx_helper_setup_red_queue(int queue, int pass_thresh, int drop_thresh) +{ + union cvmx_ipd_qosx_red_marks red_marks; + union cvmx_ipd_red_quex_param red_param; + + /* Set RED to begin dropping packets when there are pass_thresh buffers + left. It will linearly drop more packets until reaching drop_thresh + buffers */ + red_marks.u64 = 0; + red_marks.s.drop = drop_thresh; + red_marks.s.pass = pass_thresh; + cvmx_write_csr(CVMX_IPD_QOSX_RED_MARKS(queue), red_marks.u64); + + /* Use the actual queue 0 counter, not the average */ + red_param.u64 = 0; + red_param.s.prb_con = + (255ul << 24) / (red_marks.s.pass - red_marks.s.drop); + red_param.s.avg_con = 1; + red_param.s.new_con = 255; + red_param.s.use_pcnt = 1; + cvmx_write_csr(CVMX_IPD_RED_QUEX_PARAM(queue), red_param.u64); + return 0; +} + +/** + * Setup Random Early Drop to automatically begin dropping packets. + * + * @pass_thresh: + * Packets will begin slowly dropping when there are less than + * this many packet buffers free in FPA 0. + * @drop_thresh: + * All incomming packets will be dropped when there are less + * than this many free packet buffers in FPA 0. + * Returns Zero on success. Negative on failure + */ +int cvmx_helper_setup_red(int pass_thresh, int drop_thresh) +{ + union cvmx_ipd_portx_bp_page_cnt page_cnt; + union cvmx_ipd_bp_prt_red_end ipd_bp_prt_red_end; + union cvmx_ipd_red_port_enable red_port_enable; + int queue; + int interface; + int port; + + /* Disable backpressure based on queued buffers. It needs SW support */ + page_cnt.u64 = 0; + page_cnt.s.bp_enb = 0; + page_cnt.s.page_cnt = 100; + for (interface = 0; interface < 2; interface++) { + for (port = cvmx_helper_get_first_ipd_port(interface); + port < cvmx_helper_get_last_ipd_port(interface); port++) + cvmx_write_csr(CVMX_IPD_PORTX_BP_PAGE_CNT(port), + page_cnt.u64); + } + + for (queue = 0; queue < 8; queue++) + cvmx_helper_setup_red_queue(queue, pass_thresh, drop_thresh); + + /* Shutoff the dropping based on the per port page count. SW isn't + decrementing it right now */ + ipd_bp_prt_red_end.u64 = 0; + ipd_bp_prt_red_end.s.prt_enb = 0; + cvmx_write_csr(CVMX_IPD_BP_PRT_RED_END, ipd_bp_prt_red_end.u64); + + red_port_enable.u64 = 0; + red_port_enable.s.prt_enb = 0xfffffffffull; + red_port_enable.s.avg_dly = 10000; + red_port_enable.s.prb_dly = 10000; + cvmx_write_csr(CVMX_IPD_RED_PORT_ENABLE, red_port_enable.u64); + + return 0; +} + +/** + * Setup the common GMX settings that determine the number of + * ports. These setting apply to almost all configurations of all + * chips. + * + * @interface: Interface to configure + * @num_ports: Number of ports on the interface + * + * Returns Zero on success, negative on failure + */ +int __cvmx_helper_setup_gmx(int interface, int num_ports) +{ + union cvmx_gmxx_tx_prts gmx_tx_prts; + union cvmx_gmxx_rx_prts gmx_rx_prts; + union cvmx_pko_reg_gmx_port_mode pko_mode; + union cvmx_gmxx_txx_thresh gmx_tx_thresh; + int index; + + /* Tell GMX the number of TX ports on this interface */ + gmx_tx_prts.u64 = cvmx_read_csr(CVMX_GMXX_TX_PRTS(interface)); + gmx_tx_prts.s.prts = num_ports; + cvmx_write_csr(CVMX_GMXX_TX_PRTS(interface), gmx_tx_prts.u64); + + /* Tell GMX the number of RX ports on this interface. This only + ** applies to *GMII and XAUI ports */ + if (cvmx_helper_interface_get_mode(interface) == + CVMX_HELPER_INTERFACE_MODE_RGMII + || cvmx_helper_interface_get_mode(interface) == + CVMX_HELPER_INTERFACE_MODE_SGMII + || cvmx_helper_interface_get_mode(interface) == + CVMX_HELPER_INTERFACE_MODE_GMII + || cvmx_helper_interface_get_mode(interface) == + CVMX_HELPER_INTERFACE_MODE_XAUI) { + if (num_ports > 4) { + cvmx_dprintf("__cvmx_helper_setup_gmx: Illegal " + "num_ports\n"); + return -1; + } + + gmx_rx_prts.u64 = cvmx_read_csr(CVMX_GMXX_RX_PRTS(interface)); + gmx_rx_prts.s.prts = num_ports; + cvmx_write_csr(CVMX_GMXX_RX_PRTS(interface), gmx_rx_prts.u64); + } + + /* Skip setting CVMX_PKO_REG_GMX_PORT_MODE on 30XX, 31XX, and 50XX */ + if (!OCTEON_IS_MODEL(OCTEON_CN30XX) && !OCTEON_IS_MODEL(OCTEON_CN31XX) + && !OCTEON_IS_MODEL(OCTEON_CN50XX)) { + /* Tell PKO the number of ports on this interface */ + pko_mode.u64 = cvmx_read_csr(CVMX_PKO_REG_GMX_PORT_MODE); + if (interface == 0) { + if (num_ports == 1) + pko_mode.s.mode0 = 4; + else if (num_ports == 2) + pko_mode.s.mode0 = 3; + else if (num_ports <= 4) + pko_mode.s.mode0 = 2; + else if (num_ports <= 8) + pko_mode.s.mode0 = 1; + else + pko_mode.s.mode0 = 0; + } else { + if (num_ports == 1) + pko_mode.s.mode1 = 4; + else if (num_ports == 2) + pko_mode.s.mode1 = 3; + else if (num_ports <= 4) + pko_mode.s.mode1 = 2; + else if (num_ports <= 8) + pko_mode.s.mode1 = 1; + else + pko_mode.s.mode1 = 0; + } + cvmx_write_csr(CVMX_PKO_REG_GMX_PORT_MODE, pko_mode.u64); + } + + /* + * Set GMX to buffer as much data as possible before starting + * transmit. This reduces the chances that we have a TX under + * run due to memory contention. Any packet that fits entirely + * in the GMX FIFO can never have an under run regardless of + * memory load. + */ + gmx_tx_thresh.u64 = cvmx_read_csr(CVMX_GMXX_TXX_THRESH(0, interface)); + if (OCTEON_IS_MODEL(OCTEON_CN30XX) || OCTEON_IS_MODEL(OCTEON_CN31XX) + || OCTEON_IS_MODEL(OCTEON_CN50XX)) { + /* These chips have a fixed max threshold of 0x40 */ + gmx_tx_thresh.s.cnt = 0x40; + } else { + /* Choose the max value for the number of ports */ + if (num_ports <= 1) + gmx_tx_thresh.s.cnt = 0x100 / 1; + else if (num_ports == 2) + gmx_tx_thresh.s.cnt = 0x100 / 2; + else + gmx_tx_thresh.s.cnt = 0x100 / 4; + } + /* + * SPI and XAUI can have lots of ports but the GMX hardware + * only ever has a max of 4. + */ + if (num_ports > 4) + num_ports = 4; + for (index = 0; index < num_ports; index++) + cvmx_write_csr(CVMX_GMXX_TXX_THRESH(index, interface), + gmx_tx_thresh.u64); + + return 0; +} + +/** + * Returns the IPD/PKO port number for a port on teh given + * interface. + * + * @interface: Interface to use + * @port: Port on the interface + * + * Returns IPD/PKO port number + */ +int cvmx_helper_get_ipd_port(int interface, int port) +{ + switch (interface) { + case 0: + return port; + case 1: + return port + 16; + case 2: + return port + 32; + case 3: + return port + 36; + } + return -1; +} + +/** + * Returns the interface number for an IPD/PKO port number. + * + * @ipd_port: IPD/PKO port number + * + * Returns Interface number + */ +int cvmx_helper_get_interface_num(int ipd_port) +{ + if (ipd_port < 16) + return 0; + else if (ipd_port < 32) + return 1; + else if (ipd_port < 36) + return 2; + else if (ipd_port < 40) + return 3; + else + cvmx_dprintf("cvmx_helper_get_interface_num: Illegal IPD " + "port number\n"); + + return -1; +} + +/** + * Returns the interface index number for an IPD/PKO port + * number. + * + * @ipd_port: IPD/PKO port number + * + * Returns Interface index number + */ +int cvmx_helper_get_interface_index_num(int ipd_port) +{ + if (ipd_port < 32) + return ipd_port & 15; + else if (ipd_port < 36) + return ipd_port & 3; + else if (ipd_port < 40) + return ipd_port & 3; + else + cvmx_dprintf("cvmx_helper_get_interface_index_num: " + "Illegal IPD port number\n"); + + return -1; +} diff --git a/drivers/staging/octeon/cvmx-helper-util.h b/drivers/staging/octeon/cvmx-helper-util.h new file mode 100644 index 000000000000..6a6e52fc22c1 --- /dev/null +++ b/drivers/staging/octeon/cvmx-helper-util.h @@ -0,0 +1,215 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2008 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +/* + * + * Small helper utilities. + * + */ + +#ifndef __CVMX_HELPER_UTIL_H__ +#define __CVMX_HELPER_UTIL_H__ + +/** + * Convert a interface mode into a human readable string + * + * @mode: Mode to convert + * + * Returns String + */ +extern const char + *cvmx_helper_interface_mode_to_string(cvmx_helper_interface_mode_t mode); + +/** + * Debug routine to dump the packet structure to the console + * + * @work: Work queue entry containing the packet to dump + * Returns + */ +extern int cvmx_helper_dump_packet(cvmx_wqe_t *work); + +/** + * Setup Random Early Drop on a specific input queue + * + * @queue: Input queue to setup RED on (0-7) + * @pass_thresh: + * Packets will begin slowly dropping when there are less than + * this many packet buffers free in FPA 0. + * @drop_thresh: + * All incomming packets will be dropped when there are less + * than this many free packet buffers in FPA 0. + * Returns Zero on success. Negative on failure + */ +extern int cvmx_helper_setup_red_queue(int queue, int pass_thresh, + int drop_thresh); + +/** + * Setup Random Early Drop to automatically begin dropping packets. + * + * @pass_thresh: + * Packets will begin slowly dropping when there are less than + * this many packet buffers free in FPA 0. + * @drop_thresh: + * All incomming packets will be dropped when there are less + * than this many free packet buffers in FPA 0. + * Returns Zero on success. Negative on failure + */ +extern int cvmx_helper_setup_red(int pass_thresh, int drop_thresh); + +/** + * Get the version of the CVMX libraries. + * + * Returns Version string. Note this buffer is allocated statically + * and will be shared by all callers. + */ +extern const char *cvmx_helper_get_version(void); + +/** + * Setup the common GMX settings that determine the number of + * ports. These setting apply to almost all configurations of all + * chips. + * + * @interface: Interface to configure + * @num_ports: Number of ports on the interface + * + * Returns Zero on success, negative on failure + */ +extern int __cvmx_helper_setup_gmx(int interface, int num_ports); + +/** + * Returns the IPD/PKO port number for a port on the given + * interface. + * + * @interface: Interface to use + * @port: Port on the interface + * + * Returns IPD/PKO port number + */ +extern int cvmx_helper_get_ipd_port(int interface, int port); + +/** + * Returns the IPD/PKO port number for the first port on the given + * interface. + * + * @interface: Interface to use + * + * Returns IPD/PKO port number + */ +static inline int cvmx_helper_get_first_ipd_port(int interface) +{ + return cvmx_helper_get_ipd_port(interface, 0); +} + +/** + * Returns the IPD/PKO port number for the last port on the given + * interface. + * + * @interface: Interface to use + * + * Returns IPD/PKO port number + */ +static inline int cvmx_helper_get_last_ipd_port(int interface) +{ + extern int cvmx_helper_ports_on_interface(int interface); + + return cvmx_helper_get_first_ipd_port(interface) + + cvmx_helper_ports_on_interface(interface) - 1; +} + +/** + * Free the packet buffers contained in a work queue entry. + * The work queue entry is not freed. + * + * @work: Work queue entry with packet to free + */ +static inline void cvmx_helper_free_packet_data(cvmx_wqe_t *work) +{ + uint64_t number_buffers; + union cvmx_buf_ptr buffer_ptr; + union cvmx_buf_ptr next_buffer_ptr; + uint64_t start_of_buffer; + + number_buffers = work->word2.s.bufs; + if (number_buffers == 0) + return; + buffer_ptr = work->packet_ptr; + + /* + * Since the number of buffers is not zero, we know this is + * not a dynamic short packet. We need to check if it is a + * packet received with IPD_CTL_STATUS[NO_WPTR]. If this is + * true, we need to free all buffers except for the first + * one. The caller doesn't expect their WQE pointer to be + * freed + */ + start_of_buffer = ((buffer_ptr.s.addr >> 7) - buffer_ptr.s.back) << 7; + if (cvmx_ptr_to_phys(work) == start_of_buffer) { + next_buffer_ptr = + *(union cvmx_buf_ptr *) cvmx_phys_to_ptr(buffer_ptr.s.addr - 8); + buffer_ptr = next_buffer_ptr; + number_buffers--; + } + + while (number_buffers--) { + /* + * Remember the back pointer is in cache lines, not + * 64bit words + */ + start_of_buffer = + ((buffer_ptr.s.addr >> 7) - buffer_ptr.s.back) << 7; + /* + * Read pointer to next buffer before we free the + * current buffer. + */ + next_buffer_ptr = + *(union cvmx_buf_ptr *) cvmx_phys_to_ptr(buffer_ptr.s.addr - 8); + cvmx_fpa_free(cvmx_phys_to_ptr(start_of_buffer), + buffer_ptr.s.pool, 0); + buffer_ptr = next_buffer_ptr; + } +} + +/** + * Returns the interface number for an IPD/PKO port number. + * + * @ipd_port: IPD/PKO port number + * + * Returns Interface number + */ +extern int cvmx_helper_get_interface_num(int ipd_port); + +/** + * Returns the interface index number for an IPD/PKO port + * number. + * + * @ipd_port: IPD/PKO port number + * + * Returns Interface index number + */ +extern int cvmx_helper_get_interface_index_num(int ipd_port); + +#endif /* __CVMX_HELPER_H__ */ diff --git a/drivers/staging/octeon/cvmx-helper-xaui.c b/drivers/staging/octeon/cvmx-helper-xaui.c new file mode 100644 index 000000000000..a11e6769e234 --- /dev/null +++ b/drivers/staging/octeon/cvmx-helper-xaui.c @@ -0,0 +1,348 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2008 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +/* + * Functions for XAUI initialization, configuration, + * and monitoring. + * + */ + +#include + +#include "cvmx-config.h" + +#include "cvmx-helper.h" + +#include "cvmx-pko-defs.h" +#include "cvmx-gmxx-defs.h" +#include "cvmx-pcsxx-defs.h" + +void __cvmx_interrupt_gmxx_enable(int interface); +void __cvmx_interrupt_pcsx_intx_en_reg_enable(int index, int block); +void __cvmx_interrupt_pcsxx_int_en_reg_enable(int index); +/** + * Probe a XAUI interface and determine the number of ports + * connected to it. The XAUI interface should still be down + * after this call. + * + * @interface: Interface to probe + * + * Returns Number of ports on the interface. Zero to disable. + */ +int __cvmx_helper_xaui_probe(int interface) +{ + int i; + union cvmx_gmxx_hg2_control gmx_hg2_control; + union cvmx_gmxx_inf_mode mode; + + /* + * Due to errata GMX-700 on CN56XXp1.x and CN52XXp1.x, the + * interface needs to be enabled before IPD otherwise per port + * backpressure may not work properly. + */ + mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface)); + mode.s.en = 1; + cvmx_write_csr(CVMX_GMXX_INF_MODE(interface), mode.u64); + + __cvmx_helper_setup_gmx(interface, 1); + + /* + * Setup PKO to support 16 ports for HiGig2 virtual + * ports. We're pointing all of the PKO packet ports for this + * interface to the XAUI. This allows us to use HiGig2 + * backpressure per port. + */ + for (i = 0; i < 16; i++) { + union cvmx_pko_mem_port_ptrs pko_mem_port_ptrs; + pko_mem_port_ptrs.u64 = 0; + /* + * We set each PKO port to have equal priority in a + * round robin fashion. + */ + pko_mem_port_ptrs.s.static_p = 0; + pko_mem_port_ptrs.s.qos_mask = 0xff; + /* All PKO ports map to the same XAUI hardware port */ + pko_mem_port_ptrs.s.eid = interface * 4; + pko_mem_port_ptrs.s.pid = interface * 16 + i; + cvmx_write_csr(CVMX_PKO_MEM_PORT_PTRS, pko_mem_port_ptrs.u64); + } + + /* If HiGig2 is enabled return 16 ports, otherwise return 1 port */ + gmx_hg2_control.u64 = cvmx_read_csr(CVMX_GMXX_HG2_CONTROL(interface)); + if (gmx_hg2_control.s.hg2tx_en) + return 16; + else + return 1; +} + +/** + * Bringup and enable a XAUI interface. After this call packet + * I/O should be fully functional. This is called with IPD + * enabled but PKO disabled. + * + * @interface: Interface to bring up + * + * Returns Zero on success, negative on failure + */ +int __cvmx_helper_xaui_enable(int interface) +{ + union cvmx_gmxx_prtx_cfg gmx_cfg; + union cvmx_pcsxx_control1_reg xauiCtl; + union cvmx_pcsxx_misc_ctl_reg xauiMiscCtl; + union cvmx_gmxx_tx_xaui_ctl gmxXauiTxCtl; + union cvmx_gmxx_rxx_int_en gmx_rx_int_en; + union cvmx_gmxx_tx_int_en gmx_tx_int_en; + union cvmx_pcsxx_int_en_reg pcsx_int_en_reg; + + /* (1) Interface has already been enabled. */ + + /* (2) Disable GMX. */ + xauiMiscCtl.u64 = cvmx_read_csr(CVMX_PCSXX_MISC_CTL_REG(interface)); + xauiMiscCtl.s.gmxeno = 1; + cvmx_write_csr(CVMX_PCSXX_MISC_CTL_REG(interface), xauiMiscCtl.u64); + + /* (3) Disable GMX and PCSX interrupts. */ + gmx_rx_int_en.u64 = cvmx_read_csr(CVMX_GMXX_RXX_INT_EN(0, interface)); + cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(0, interface), 0x0); + gmx_tx_int_en.u64 = cvmx_read_csr(CVMX_GMXX_TX_INT_EN(interface)); + cvmx_write_csr(CVMX_GMXX_TX_INT_EN(interface), 0x0); + pcsx_int_en_reg.u64 = cvmx_read_csr(CVMX_PCSXX_INT_EN_REG(interface)); + cvmx_write_csr(CVMX_PCSXX_INT_EN_REG(interface), 0x0); + + /* (4) Bring up the PCSX and GMX reconciliation layer. */ + /* (4)a Set polarity and lane swapping. */ + /* (4)b */ + gmxXauiTxCtl.u64 = cvmx_read_csr(CVMX_GMXX_TX_XAUI_CTL(interface)); + /* Enable better IFG packing and improves performance */ + gmxXauiTxCtl.s.dic_en = 1; + gmxXauiTxCtl.s.uni_en = 0; + cvmx_write_csr(CVMX_GMXX_TX_XAUI_CTL(interface), gmxXauiTxCtl.u64); + + /* (4)c Aply reset sequence */ + xauiCtl.u64 = cvmx_read_csr(CVMX_PCSXX_CONTROL1_REG(interface)); + xauiCtl.s.lo_pwr = 0; + xauiCtl.s.reset = 1; + cvmx_write_csr(CVMX_PCSXX_CONTROL1_REG(interface), xauiCtl.u64); + + /* Wait for PCS to come out of reset */ + if (CVMX_WAIT_FOR_FIELD64 + (CVMX_PCSXX_CONTROL1_REG(interface), union cvmx_pcsxx_control1_reg, + reset, ==, 0, 10000)) + return -1; + /* Wait for PCS to be aligned */ + if (CVMX_WAIT_FOR_FIELD64 + (CVMX_PCSXX_10GBX_STATUS_REG(interface), + union cvmx_pcsxx_10gbx_status_reg, alignd, ==, 1, 10000)) + return -1; + /* Wait for RX to be ready */ + if (CVMX_WAIT_FOR_FIELD64 + (CVMX_GMXX_RX_XAUI_CTL(interface), union cvmx_gmxx_rx_xaui_ctl, + status, ==, 0, 10000)) + return -1; + + /* (6) Configure GMX */ + gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(0, interface)); + gmx_cfg.s.en = 0; + cvmx_write_csr(CVMX_GMXX_PRTX_CFG(0, interface), gmx_cfg.u64); + + /* Wait for GMX RX to be idle */ + if (CVMX_WAIT_FOR_FIELD64 + (CVMX_GMXX_PRTX_CFG(0, interface), union cvmx_gmxx_prtx_cfg, + rx_idle, ==, 1, 10000)) + return -1; + /* Wait for GMX TX to be idle */ + if (CVMX_WAIT_FOR_FIELD64 + (CVMX_GMXX_PRTX_CFG(0, interface), union cvmx_gmxx_prtx_cfg, + tx_idle, ==, 1, 10000)) + return -1; + + /* GMX configure */ + gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(0, interface)); + gmx_cfg.s.speed = 1; + gmx_cfg.s.speed_msb = 0; + gmx_cfg.s.slottime = 1; + cvmx_write_csr(CVMX_GMXX_TX_PRTS(interface), 1); + cvmx_write_csr(CVMX_GMXX_TXX_SLOT(0, interface), 512); + cvmx_write_csr(CVMX_GMXX_TXX_BURST(0, interface), 8192); + cvmx_write_csr(CVMX_GMXX_PRTX_CFG(0, interface), gmx_cfg.u64); + + /* (7) Clear out any error state */ + cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(0, interface), + cvmx_read_csr(CVMX_GMXX_RXX_INT_REG(0, interface))); + cvmx_write_csr(CVMX_GMXX_TX_INT_REG(interface), + cvmx_read_csr(CVMX_GMXX_TX_INT_REG(interface))); + cvmx_write_csr(CVMX_PCSXX_INT_REG(interface), + cvmx_read_csr(CVMX_PCSXX_INT_REG(interface))); + + /* Wait for receive link */ + if (CVMX_WAIT_FOR_FIELD64 + (CVMX_PCSXX_STATUS1_REG(interface), union cvmx_pcsxx_status1_reg, + rcv_lnk, ==, 1, 10000)) + return -1; + if (CVMX_WAIT_FOR_FIELD64 + (CVMX_PCSXX_STATUS2_REG(interface), union cvmx_pcsxx_status2_reg, + xmtflt, ==, 0, 10000)) + return -1; + if (CVMX_WAIT_FOR_FIELD64 + (CVMX_PCSXX_STATUS2_REG(interface), union cvmx_pcsxx_status2_reg, + rcvflt, ==, 0, 10000)) + return -1; + + cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(0, interface), gmx_rx_int_en.u64); + cvmx_write_csr(CVMX_GMXX_TX_INT_EN(interface), gmx_tx_int_en.u64); + cvmx_write_csr(CVMX_PCSXX_INT_EN_REG(interface), pcsx_int_en_reg.u64); + + cvmx_helper_link_autoconf(cvmx_helper_get_ipd_port(interface, 0)); + + /* (8) Enable packet reception */ + xauiMiscCtl.s.gmxeno = 0; + cvmx_write_csr(CVMX_PCSXX_MISC_CTL_REG(interface), xauiMiscCtl.u64); + + gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(0, interface)); + gmx_cfg.s.en = 1; + cvmx_write_csr(CVMX_GMXX_PRTX_CFG(0, interface), gmx_cfg.u64); + + __cvmx_interrupt_pcsx_intx_en_reg_enable(0, interface); + __cvmx_interrupt_pcsx_intx_en_reg_enable(1, interface); + __cvmx_interrupt_pcsx_intx_en_reg_enable(2, interface); + __cvmx_interrupt_pcsx_intx_en_reg_enable(3, interface); + __cvmx_interrupt_pcsxx_int_en_reg_enable(interface); + __cvmx_interrupt_gmxx_enable(interface); + + return 0; +} + +/** + * Return the link state of an IPD/PKO port as returned by + * auto negotiation. The result of this function may not match + * Octeon's link config if auto negotiation has changed since + * the last call to cvmx_helper_link_set(). + * + * @ipd_port: IPD/PKO port to query + * + * Returns Link state + */ +cvmx_helper_link_info_t __cvmx_helper_xaui_link_get(int ipd_port) +{ + int interface = cvmx_helper_get_interface_num(ipd_port); + union cvmx_gmxx_tx_xaui_ctl gmxx_tx_xaui_ctl; + union cvmx_gmxx_rx_xaui_ctl gmxx_rx_xaui_ctl; + union cvmx_pcsxx_status1_reg pcsxx_status1_reg; + cvmx_helper_link_info_t result; + + gmxx_tx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_TX_XAUI_CTL(interface)); + gmxx_rx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_RX_XAUI_CTL(interface)); + pcsxx_status1_reg.u64 = + cvmx_read_csr(CVMX_PCSXX_STATUS1_REG(interface)); + result.u64 = 0; + + /* Only return a link if both RX and TX are happy */ + if ((gmxx_tx_xaui_ctl.s.ls == 0) && (gmxx_rx_xaui_ctl.s.status == 0) && + (pcsxx_status1_reg.s.rcv_lnk == 1)) { + result.s.link_up = 1; + result.s.full_duplex = 1; + result.s.speed = 10000; + } else { + /* Disable GMX and PCSX interrupts. */ + cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(0, interface), 0x0); + cvmx_write_csr(CVMX_GMXX_TX_INT_EN(interface), 0x0); + cvmx_write_csr(CVMX_PCSXX_INT_EN_REG(interface), 0x0); + } + return result; +} + +/** + * Configure an IPD/PKO port for the specified link state. This + * function does not influence auto negotiation at the PHY level. + * The passed link state must always match the link state returned + * by cvmx_helper_link_get(). It is normally best to use + * cvmx_helper_link_autoconf() instead. + * + * @ipd_port: IPD/PKO port to configure + * @link_info: The new link state + * + * Returns Zero on success, negative on failure + */ +int __cvmx_helper_xaui_link_set(int ipd_port, cvmx_helper_link_info_t link_info) +{ + int interface = cvmx_helper_get_interface_num(ipd_port); + union cvmx_gmxx_tx_xaui_ctl gmxx_tx_xaui_ctl; + union cvmx_gmxx_rx_xaui_ctl gmxx_rx_xaui_ctl; + + gmxx_tx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_TX_XAUI_CTL(interface)); + gmxx_rx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_RX_XAUI_CTL(interface)); + + /* If the link shouldn't be up, then just return */ + if (!link_info.s.link_up) + return 0; + + /* Do nothing if both RX and TX are happy */ + if ((gmxx_tx_xaui_ctl.s.ls == 0) && (gmxx_rx_xaui_ctl.s.status == 0)) + return 0; + + /* Bring the link up */ + return __cvmx_helper_xaui_enable(interface); +} + +/** + * Configure a port for internal and/or external loopback. Internal loopback + * causes packets sent by the port to be received by Octeon. External loopback + * causes packets received from the wire to sent out again. + * + * @ipd_port: IPD/PKO port to loopback. + * @enable_internal: + * Non zero if you want internal loopback + * @enable_external: + * Non zero if you want external loopback + * + * Returns Zero on success, negative on failure. + */ +extern int __cvmx_helper_xaui_configure_loopback(int ipd_port, + int enable_internal, + int enable_external) +{ + int interface = cvmx_helper_get_interface_num(ipd_port); + union cvmx_pcsxx_control1_reg pcsxx_control1_reg; + union cvmx_gmxx_xaui_ext_loopback gmxx_xaui_ext_loopback; + + /* Set the internal loop */ + pcsxx_control1_reg.u64 = + cvmx_read_csr(CVMX_PCSXX_CONTROL1_REG(interface)); + pcsxx_control1_reg.s.loopbck1 = enable_internal; + cvmx_write_csr(CVMX_PCSXX_CONTROL1_REG(interface), + pcsxx_control1_reg.u64); + + /* Set the external loop */ + gmxx_xaui_ext_loopback.u64 = + cvmx_read_csr(CVMX_GMXX_XAUI_EXT_LOOPBACK(interface)); + gmxx_xaui_ext_loopback.s.en = enable_external; + cvmx_write_csr(CVMX_GMXX_XAUI_EXT_LOOPBACK(interface), + gmxx_xaui_ext_loopback.u64); + + /* Take the link through a reset */ + return __cvmx_helper_xaui_enable(interface); +} diff --git a/drivers/staging/octeon/cvmx-helper-xaui.h b/drivers/staging/octeon/cvmx-helper-xaui.h new file mode 100644 index 000000000000..4b4db2f93cd4 --- /dev/null +++ b/drivers/staging/octeon/cvmx-helper-xaui.h @@ -0,0 +1,103 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2008 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +/** + * @file + * + * Functions for XAUI initialization, configuration, + * and monitoring. + * + */ +#ifndef __CVMX_HELPER_XAUI_H__ +#define __CVMX_HELPER_XAUI_H__ + +/** + * Probe a XAUI interface and determine the number of ports + * connected to it. The XAUI interface should still be down + * after this call. + * + * @interface: Interface to probe + * + * Returns Number of ports on the interface. Zero to disable. + */ +extern int __cvmx_helper_xaui_probe(int interface); + +/** + * Bringup and enable a XAUI interface. After this call packet + * I/O should be fully functional. This is called with IPD + * enabled but PKO disabled. + * + * @interface: Interface to bring up + * + * Returns Zero on success, negative on failure + */ +extern int __cvmx_helper_xaui_enable(int interface); + +/** + * Return the link state of an IPD/PKO port as returned by + * auto negotiation. The result of this function may not match + * Octeon's link config if auto negotiation has changed since + * the last call to cvmx_helper_link_set(). + * + * @ipd_port: IPD/PKO port to query + * + * Returns Link state + */ +extern cvmx_helper_link_info_t __cvmx_helper_xaui_link_get(int ipd_port); + +/** + * Configure an IPD/PKO port for the specified link state. This + * function does not influence auto negotiation at the PHY level. + * The passed link state must always match the link state returned + * by cvmx_helper_link_get(). It is normally best to use + * cvmx_helper_link_autoconf() instead. + * + * @ipd_port: IPD/PKO port to configure + * @link_info: The new link state + * + * Returns Zero on success, negative on failure + */ +extern int __cvmx_helper_xaui_link_set(int ipd_port, + cvmx_helper_link_info_t link_info); + +/** + * Configure a port for internal and/or external loopback. Internal loopback + * causes packets sent by the port to be received by Octeon. External loopback + * causes packets received from the wire to sent out again. + * + * @ipd_port: IPD/PKO port to loopback. + * @enable_internal: + * Non zero if you want internal loopback + * @enable_external: + * Non zero if you want external loopback + * + * Returns Zero on success, negative on failure. + */ +extern int __cvmx_helper_xaui_configure_loopback(int ipd_port, + int enable_internal, + int enable_external); +#endif diff --git a/drivers/staging/octeon/cvmx-helper.c b/drivers/staging/octeon/cvmx-helper.c new file mode 100644 index 000000000000..591506643d02 --- /dev/null +++ b/drivers/staging/octeon/cvmx-helper.c @@ -0,0 +1,1058 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2008 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +/* + * + * Helper functions for common, but complicated tasks. + * + */ +#include + +#include "cvmx-config.h" + +#include "cvmx-fpa.h" +#include "cvmx-pip.h" +#include "cvmx-pko.h" +#include "cvmx-ipd.h" +#include "cvmx-spi.h" +#include "cvmx-helper.h" +#include "cvmx-helper-board.h" + +#include "cvmx-pip-defs.h" +#include "cvmx-smix-defs.h" +#include "cvmx-asxx-defs.h" + +/** + * cvmx_override_pko_queue_priority(int ipd_port, uint64_t + * priorities[16]) is a function pointer. It is meant to allow + * customization of the PKO queue priorities based on the port + * number. Users should set this pointer to a function before + * calling any cvmx-helper operations. + */ +void (*cvmx_override_pko_queue_priority) (int pko_port, + uint64_t priorities[16]); + +/** + * cvmx_override_ipd_port_setup(int ipd_port) is a function + * pointer. It is meant to allow customization of the IPD port + * setup before packet input/output comes online. It is called + * after cvmx-helper does the default IPD configuration, but + * before IPD is enabled. Users should set this pointer to a + * function before calling any cvmx-helper operations. + */ +void (*cvmx_override_ipd_port_setup) (int ipd_port); + +/* Port count per interface */ +static int interface_port_count[4] = { 0, 0, 0, 0 }; + +/* Port last configured link info index by IPD/PKO port */ +static cvmx_helper_link_info_t + port_link_info[CVMX_PIP_NUM_INPUT_PORTS]; + +/** + * Return the number of interfaces the chip has. Each interface + * may have multiple ports. Most chips support two interfaces, + * but the CNX0XX and CNX1XX are exceptions. These only support + * one interface. + * + * Returns Number of interfaces on chip + */ +int cvmx_helper_get_number_of_interfaces(void) +{ + if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN52XX)) + return 4; + else + return 3; +} + +/** + * Return the number of ports on an interface. Depending on the + * chip and configuration, this can be 1-16. A value of 0 + * specifies that the interface doesn't exist or isn't usable. + * + * @interface: Interface to get the port count for + * + * Returns Number of ports on interface. Can be Zero. + */ +int cvmx_helper_ports_on_interface(int interface) +{ + return interface_port_count[interface]; +} + +/** + * Get the operating mode of an interface. Depending on the Octeon + * chip and configuration, this function returns an enumeration + * of the type of packet I/O supported by an interface. + * + * @interface: Interface to probe + * + * Returns Mode of the interface. Unknown or unsupported interfaces return + * DISABLED. + */ +cvmx_helper_interface_mode_t cvmx_helper_interface_get_mode(int interface) +{ + union cvmx_gmxx_inf_mode mode; + if (interface == 2) + return CVMX_HELPER_INTERFACE_MODE_NPI; + + if (interface == 3) { + if (OCTEON_IS_MODEL(OCTEON_CN56XX) + || OCTEON_IS_MODEL(OCTEON_CN52XX)) + return CVMX_HELPER_INTERFACE_MODE_LOOP; + else + return CVMX_HELPER_INTERFACE_MODE_DISABLED; + } + + if (interface == 0 + && cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CN3005_EVB_HS5 + && cvmx_sysinfo_get()->board_rev_major == 1) { + /* + * Lie about interface type of CN3005 board. This + * board has a switch on port 1 like the other + * evaluation boards, but it is connected over RGMII + * instead of GMII. Report GMII mode so that the + * speed is forced to 1 Gbit full duplex. Other than + * some initial configuration (which does not use the + * output of this function) there is no difference in + * setup between GMII and RGMII modes. + */ + return CVMX_HELPER_INTERFACE_MODE_GMII; + } + + /* Interface 1 is always disabled on CN31XX and CN30XX */ + if ((interface == 1) + && (OCTEON_IS_MODEL(OCTEON_CN31XX) || OCTEON_IS_MODEL(OCTEON_CN30XX) + || OCTEON_IS_MODEL(OCTEON_CN50XX) + || OCTEON_IS_MODEL(OCTEON_CN52XX))) + return CVMX_HELPER_INTERFACE_MODE_DISABLED; + + mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface)); + + if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN52XX)) { + switch (mode.cn56xx.mode) { + case 0: + return CVMX_HELPER_INTERFACE_MODE_DISABLED; + case 1: + return CVMX_HELPER_INTERFACE_MODE_XAUI; + case 2: + return CVMX_HELPER_INTERFACE_MODE_SGMII; + case 3: + return CVMX_HELPER_INTERFACE_MODE_PICMG; + default: + return CVMX_HELPER_INTERFACE_MODE_DISABLED; + } + } else { + if (!mode.s.en) + return CVMX_HELPER_INTERFACE_MODE_DISABLED; + + if (mode.s.type) { + if (OCTEON_IS_MODEL(OCTEON_CN38XX) + || OCTEON_IS_MODEL(OCTEON_CN58XX)) + return CVMX_HELPER_INTERFACE_MODE_SPI; + else + return CVMX_HELPER_INTERFACE_MODE_GMII; + } else + return CVMX_HELPER_INTERFACE_MODE_RGMII; + } +} + +/** + * Configure the IPD/PIP tagging and QoS options for a specific + * port. This function determines the POW work queue entry + * contents for a port. The setup performed here is controlled by + * the defines in executive-config.h. + * + * @ipd_port: Port to configure. This follows the IPD numbering, not the + * per interface numbering + * + * Returns Zero on success, negative on failure + */ +static int __cvmx_helper_port_setup_ipd(int ipd_port) +{ + union cvmx_pip_prt_cfgx port_config; + union cvmx_pip_prt_tagx tag_config; + + port_config.u64 = cvmx_read_csr(CVMX_PIP_PRT_CFGX(ipd_port)); + tag_config.u64 = cvmx_read_csr(CVMX_PIP_PRT_TAGX(ipd_port)); + + /* Have each port go to a different POW queue */ + port_config.s.qos = ipd_port & 0x7; + + /* Process the headers and place the IP header in the work queue */ + port_config.s.mode = CVMX_HELPER_INPUT_PORT_SKIP_MODE; + + tag_config.s.ip6_src_flag = CVMX_HELPER_INPUT_TAG_IPV6_SRC_IP; + tag_config.s.ip6_dst_flag = CVMX_HELPER_INPUT_TAG_IPV6_DST_IP; + tag_config.s.ip6_sprt_flag = CVMX_HELPER_INPUT_TAG_IPV6_SRC_PORT; + tag_config.s.ip6_dprt_flag = CVMX_HELPER_INPUT_TAG_IPV6_DST_PORT; + tag_config.s.ip6_nxth_flag = CVMX_HELPER_INPUT_TAG_IPV6_NEXT_HEADER; + tag_config.s.ip4_src_flag = CVMX_HELPER_INPUT_TAG_IPV4_SRC_IP; + tag_config.s.ip4_dst_flag = CVMX_HELPER_INPUT_TAG_IPV4_DST_IP; + tag_config.s.ip4_sprt_flag = CVMX_HELPER_INPUT_TAG_IPV4_SRC_PORT; + tag_config.s.ip4_dprt_flag = CVMX_HELPER_INPUT_TAG_IPV4_DST_PORT; + tag_config.s.ip4_pctl_flag = CVMX_HELPER_INPUT_TAG_IPV4_PROTOCOL; + tag_config.s.inc_prt_flag = CVMX_HELPER_INPUT_TAG_INPUT_PORT; + tag_config.s.tcp6_tag_type = CVMX_HELPER_INPUT_TAG_TYPE; + tag_config.s.tcp4_tag_type = CVMX_HELPER_INPUT_TAG_TYPE; + tag_config.s.ip6_tag_type = CVMX_HELPER_INPUT_TAG_TYPE; + tag_config.s.ip4_tag_type = CVMX_HELPER_INPUT_TAG_TYPE; + tag_config.s.non_tag_type = CVMX_HELPER_INPUT_TAG_TYPE; + /* Put all packets in group 0. Other groups can be used by the app */ + tag_config.s.grp = 0; + + cvmx_pip_config_port(ipd_port, port_config, tag_config); + + /* Give the user a chance to override our setting for each port */ + if (cvmx_override_ipd_port_setup) + cvmx_override_ipd_port_setup(ipd_port); + + return 0; +} + +/** + * This function probes an interface to determine the actual + * number of hardware ports connected to it. It doesn't setup the + * ports or enable them. The main goal here is to set the global + * interface_port_count[interface] correctly. Hardware setup of the + * ports will be performed later. + * + * @interface: Interface to probe + * + * Returns Zero on success, negative on failure + */ +int cvmx_helper_interface_probe(int interface) +{ + /* At this stage in the game we don't want packets to be moving yet. + The following probe calls should perform hardware setup + needed to determine port counts. Receive must still be disabled */ + switch (cvmx_helper_interface_get_mode(interface)) { + /* These types don't support ports to IPD/PKO */ + case CVMX_HELPER_INTERFACE_MODE_DISABLED: + case CVMX_HELPER_INTERFACE_MODE_PCIE: + interface_port_count[interface] = 0; + break; + /* XAUI is a single high speed port */ + case CVMX_HELPER_INTERFACE_MODE_XAUI: + interface_port_count[interface] = + __cvmx_helper_xaui_probe(interface); + break; + /* + * RGMII/GMII/MII are all treated about the same. Most + * functions refer to these ports as RGMII. + */ + case CVMX_HELPER_INTERFACE_MODE_RGMII: + case CVMX_HELPER_INTERFACE_MODE_GMII: + interface_port_count[interface] = + __cvmx_helper_rgmii_probe(interface); + break; + /* + * SPI4 can have 1-16 ports depending on the device at + * the other end. + */ + case CVMX_HELPER_INTERFACE_MODE_SPI: + interface_port_count[interface] = + __cvmx_helper_spi_probe(interface); + break; + /* + * SGMII can have 1-4 ports depending on how many are + * hooked up. + */ + case CVMX_HELPER_INTERFACE_MODE_SGMII: + case CVMX_HELPER_INTERFACE_MODE_PICMG: + interface_port_count[interface] = + __cvmx_helper_sgmii_probe(interface); + break; + /* PCI target Network Packet Interface */ + case CVMX_HELPER_INTERFACE_MODE_NPI: + interface_port_count[interface] = + __cvmx_helper_npi_probe(interface); + break; + /* + * Special loopback only ports. These are not the same + * as other ports in loopback mode. + */ + case CVMX_HELPER_INTERFACE_MODE_LOOP: + interface_port_count[interface] = + __cvmx_helper_loop_probe(interface); + break; + } + + interface_port_count[interface] = + __cvmx_helper_board_interface_probe(interface, + interface_port_count + [interface]); + + /* Make sure all global variables propagate to other cores */ + CVMX_SYNCWS; + + return 0; +} + +/** + * Setup the IPD/PIP for the ports on an interface. Packet + * classification and tagging are set for every port on the + * interface. The number of ports on the interface must already + * have been probed. + * + * @interface: Interface to setup IPD/PIP for + * + * Returns Zero on success, negative on failure + */ +static int __cvmx_helper_interface_setup_ipd(int interface) +{ + int ipd_port = cvmx_helper_get_ipd_port(interface, 0); + int num_ports = interface_port_count[interface]; + + while (num_ports--) { + __cvmx_helper_port_setup_ipd(ipd_port); + ipd_port++; + } + return 0; +} + +/** + * Setup global setting for IPD/PIP not related to a specific + * interface or port. This must be called before IPD is enabled. + * + * Returns Zero on success, negative on failure. + */ +static int __cvmx_helper_global_setup_ipd(void) +{ + /* Setup the global packet input options */ + cvmx_ipd_config(CVMX_FPA_PACKET_POOL_SIZE / 8, + CVMX_HELPER_FIRST_MBUFF_SKIP / 8, + CVMX_HELPER_NOT_FIRST_MBUFF_SKIP / 8, + /* The +8 is to account for the next ptr */ + (CVMX_HELPER_FIRST_MBUFF_SKIP + 8) / 128, + /* The +8 is to account for the next ptr */ + (CVMX_HELPER_NOT_FIRST_MBUFF_SKIP + 8) / 128, + CVMX_FPA_WQE_POOL, + CVMX_IPD_OPC_MODE_STT, + CVMX_HELPER_ENABLE_BACK_PRESSURE); + return 0; +} + +/** + * Setup the PKO for the ports on an interface. The number of + * queues per port and the priority of each PKO output queue + * is set here. PKO must be disabled when this function is called. + * + * @interface: Interface to setup PKO for + * + * Returns Zero on success, negative on failure + */ +static int __cvmx_helper_interface_setup_pko(int interface) +{ + /* + * Each packet output queue has an associated priority. The + * higher the priority, the more often it can send a packet. A + * priority of 8 means it can send in all 8 rounds of + * contention. We're going to make each queue one less than + * the last. The vector of priorities has been extended to + * support CN5xxx CPUs, where up to 16 queues can be + * associated to a port. To keep backward compatibility we + * don't change the initial 8 priorities and replicate them in + * the second half. With per-core PKO queues (PKO lockless + * operation) all queues have the same priority. + */ + uint64_t priorities[16] = + { 8, 7, 6, 5, 4, 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, 1 }; + + /* + * Setup the IPD/PIP and PKO for the ports discovered + * above. Here packet classification, tagging and output + * priorities are set. + */ + int ipd_port = cvmx_helper_get_ipd_port(interface, 0); + int num_ports = interface_port_count[interface]; + while (num_ports--) { + /* + * Give the user a chance to override the per queue + * priorities. + */ + if (cvmx_override_pko_queue_priority) + cvmx_override_pko_queue_priority(ipd_port, priorities); + + cvmx_pko_config_port(ipd_port, + cvmx_pko_get_base_queue_per_core(ipd_port, + 0), + cvmx_pko_get_num_queues(ipd_port), + priorities); + ipd_port++; + } + return 0; +} + +/** + * Setup global setting for PKO not related to a specific + * interface or port. This must be called before PKO is enabled. + * + * Returns Zero on success, negative on failure. + */ +static int __cvmx_helper_global_setup_pko(void) +{ + /* + * Disable tagwait FAU timeout. This needs to be done before + * anyone might start packet output using tags. + */ + union cvmx_iob_fau_timeout fau_to; + fau_to.u64 = 0; + fau_to.s.tout_val = 0xfff; + fau_to.s.tout_enb = 0; + cvmx_write_csr(CVMX_IOB_FAU_TIMEOUT, fau_to.u64); + return 0; +} + +/** + * Setup global backpressure setting. + * + * Returns Zero on success, negative on failure + */ +static int __cvmx_helper_global_setup_backpressure(void) +{ +#if CVMX_HELPER_DISABLE_RGMII_BACKPRESSURE + /* Disable backpressure if configured to do so */ + /* Disable backpressure (pause frame) generation */ + int num_interfaces = cvmx_helper_get_number_of_interfaces(); + int interface; + for (interface = 0; interface < num_interfaces; interface++) { + switch (cvmx_helper_interface_get_mode(interface)) { + case CVMX_HELPER_INTERFACE_MODE_DISABLED: + case CVMX_HELPER_INTERFACE_MODE_PCIE: + case CVMX_HELPER_INTERFACE_MODE_NPI: + case CVMX_HELPER_INTERFACE_MODE_LOOP: + case CVMX_HELPER_INTERFACE_MODE_XAUI: + break; + case CVMX_HELPER_INTERFACE_MODE_RGMII: + case CVMX_HELPER_INTERFACE_MODE_GMII: + case CVMX_HELPER_INTERFACE_MODE_SPI: + case CVMX_HELPER_INTERFACE_MODE_SGMII: + case CVMX_HELPER_INTERFACE_MODE_PICMG: + cvmx_gmx_set_backpressure_override(interface, 0xf); + break; + } + } +#endif + + return 0; +} + +/** + * Enable packet input/output from the hardware. This function is + * called after all internal setup is complete and IPD is enabled. + * After this function completes, packets will be accepted from the + * hardware ports. PKO should still be disabled to make sure packets + * aren't sent out partially setup hardware. + * + * @interface: Interface to enable + * + * Returns Zero on success, negative on failure + */ +static int __cvmx_helper_packet_hardware_enable(int interface) +{ + int result = 0; + switch (cvmx_helper_interface_get_mode(interface)) { + /* These types don't support ports to IPD/PKO */ + case CVMX_HELPER_INTERFACE_MODE_DISABLED: + case CVMX_HELPER_INTERFACE_MODE_PCIE: + /* Nothing to do */ + break; + /* XAUI is a single high speed port */ + case CVMX_HELPER_INTERFACE_MODE_XAUI: + result = __cvmx_helper_xaui_enable(interface); + break; + /* + * RGMII/GMII/MII are all treated about the same. Most + * functions refer to these ports as RGMII + */ + case CVMX_HELPER_INTERFACE_MODE_RGMII: + case CVMX_HELPER_INTERFACE_MODE_GMII: + result = __cvmx_helper_rgmii_enable(interface); + break; + /* + * SPI4 can have 1-16 ports depending on the device at + * the other end + */ + case CVMX_HELPER_INTERFACE_MODE_SPI: + result = __cvmx_helper_spi_enable(interface); + break; + /* + * SGMII can have 1-4 ports depending on how many are + * hooked up + */ + case CVMX_HELPER_INTERFACE_MODE_SGMII: + case CVMX_HELPER_INTERFACE_MODE_PICMG: + result = __cvmx_helper_sgmii_enable(interface); + break; + /* PCI target Network Packet Interface */ + case CVMX_HELPER_INTERFACE_MODE_NPI: + result = __cvmx_helper_npi_enable(interface); + break; + /* + * Special loopback only ports. These are not the same + * as other ports in loopback mode + */ + case CVMX_HELPER_INTERFACE_MODE_LOOP: + result = __cvmx_helper_loop_enable(interface); + break; + } + result |= __cvmx_helper_board_hardware_enable(interface); + return result; +} + +/** + * Function to adjust internal IPD pointer alignments + * + * Returns 0 on success + * !0 on failure + */ +int __cvmx_helper_errata_fix_ipd_ptr_alignment(void) +{ +#define FIX_IPD_FIRST_BUFF_PAYLOAD_BYTES \ + (CVMX_FPA_PACKET_POOL_SIZE-8-CVMX_HELPER_FIRST_MBUFF_SKIP) +#define FIX_IPD_NON_FIRST_BUFF_PAYLOAD_BYTES \ + (CVMX_FPA_PACKET_POOL_SIZE-8-CVMX_HELPER_NOT_FIRST_MBUFF_SKIP) +#define FIX_IPD_OUTPORT 0 + /* Ports 0-15 are interface 0, 16-31 are interface 1 */ +#define INTERFACE(port) (port >> 4) +#define INDEX(port) (port & 0xf) + uint64_t *p64; + cvmx_pko_command_word0_t pko_command; + union cvmx_buf_ptr g_buffer, pkt_buffer; + cvmx_wqe_t *work; + int size, num_segs = 0, wqe_pcnt, pkt_pcnt; + union cvmx_gmxx_prtx_cfg gmx_cfg; + int retry_cnt; + int retry_loop_cnt; + int mtu; + int i; + cvmx_helper_link_info_t link_info; + + /* Save values for restore at end */ + uint64_t prtx_cfg = + cvmx_read_csr(CVMX_GMXX_PRTX_CFG + (INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT))); + uint64_t tx_ptr_en = + cvmx_read_csr(CVMX_ASXX_TX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT))); + uint64_t rx_ptr_en = + cvmx_read_csr(CVMX_ASXX_RX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT))); + uint64_t rxx_jabber = + cvmx_read_csr(CVMX_GMXX_RXX_JABBER + (INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT))); + uint64_t frame_max = + cvmx_read_csr(CVMX_GMXX_RXX_FRM_MAX + (INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT))); + + /* Configure port to gig FDX as required for loopback mode */ + cvmx_helper_rgmii_internal_loopback(FIX_IPD_OUTPORT); + + /* + * Disable reception on all ports so if traffic is present it + * will not interfere. + */ + cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT)), 0); + + cvmx_wait(100000000ull); + + for (retry_loop_cnt = 0; retry_loop_cnt < 10; retry_loop_cnt++) { + retry_cnt = 100000; + wqe_pcnt = cvmx_read_csr(CVMX_IPD_PTR_COUNT); + pkt_pcnt = (wqe_pcnt >> 7) & 0x7f; + wqe_pcnt &= 0x7f; + + num_segs = (2 + pkt_pcnt - wqe_pcnt) & 3; + + if (num_segs == 0) + goto fix_ipd_exit; + + num_segs += 1; + + size = + FIX_IPD_FIRST_BUFF_PAYLOAD_BYTES + + ((num_segs - 1) * FIX_IPD_NON_FIRST_BUFF_PAYLOAD_BYTES) - + (FIX_IPD_NON_FIRST_BUFF_PAYLOAD_BYTES / 2); + + cvmx_write_csr(CVMX_ASXX_PRT_LOOP(INTERFACE(FIX_IPD_OUTPORT)), + 1 << INDEX(FIX_IPD_OUTPORT)); + CVMX_SYNC; + + g_buffer.u64 = 0; + g_buffer.s.addr = + cvmx_ptr_to_phys(cvmx_fpa_alloc(CVMX_FPA_WQE_POOL)); + if (g_buffer.s.addr == 0) { + cvmx_dprintf("WARNING: FIX_IPD_PTR_ALIGNMENT " + "buffer allocation failure.\n"); + goto fix_ipd_exit; + } + + g_buffer.s.pool = CVMX_FPA_WQE_POOL; + g_buffer.s.size = num_segs; + + pkt_buffer.u64 = 0; + pkt_buffer.s.addr = + cvmx_ptr_to_phys(cvmx_fpa_alloc(CVMX_FPA_PACKET_POOL)); + if (pkt_buffer.s.addr == 0) { + cvmx_dprintf("WARNING: FIX_IPD_PTR_ALIGNMENT " + "buffer allocation failure.\n"); + goto fix_ipd_exit; + } + pkt_buffer.s.i = 1; + pkt_buffer.s.pool = CVMX_FPA_PACKET_POOL; + pkt_buffer.s.size = FIX_IPD_FIRST_BUFF_PAYLOAD_BYTES; + + p64 = (uint64_t *) cvmx_phys_to_ptr(pkt_buffer.s.addr); + p64[0] = 0xffffffffffff0000ull; + p64[1] = 0x08004510ull; + p64[2] = ((uint64_t) (size - 14) << 48) | 0x5ae740004000ull; + p64[3] = 0x3a5fc0a81073c0a8ull; + + for (i = 0; i < num_segs; i++) { + if (i > 0) + pkt_buffer.s.size = + FIX_IPD_NON_FIRST_BUFF_PAYLOAD_BYTES; + + if (i == (num_segs - 1)) + pkt_buffer.s.i = 0; + + *(uint64_t *) cvmx_phys_to_ptr(g_buffer.s.addr + + 8 * i) = pkt_buffer.u64; + } + + /* Build the PKO command */ + pko_command.u64 = 0; + pko_command.s.segs = num_segs; + pko_command.s.total_bytes = size; + pko_command.s.dontfree = 0; + pko_command.s.gather = 1; + + gmx_cfg.u64 = + cvmx_read_csr(CVMX_GMXX_PRTX_CFG + (INDEX(FIX_IPD_OUTPORT), + INTERFACE(FIX_IPD_OUTPORT))); + gmx_cfg.s.en = 1; + cvmx_write_csr(CVMX_GMXX_PRTX_CFG + (INDEX(FIX_IPD_OUTPORT), + INTERFACE(FIX_IPD_OUTPORT)), gmx_cfg.u64); + cvmx_write_csr(CVMX_ASXX_TX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT)), + 1 << INDEX(FIX_IPD_OUTPORT)); + cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT)), + 1 << INDEX(FIX_IPD_OUTPORT)); + + mtu = + cvmx_read_csr(CVMX_GMXX_RXX_JABBER + (INDEX(FIX_IPD_OUTPORT), + INTERFACE(FIX_IPD_OUTPORT))); + cvmx_write_csr(CVMX_GMXX_RXX_JABBER + (INDEX(FIX_IPD_OUTPORT), + INTERFACE(FIX_IPD_OUTPORT)), 65392 - 14 - 4); + cvmx_write_csr(CVMX_GMXX_RXX_FRM_MAX + (INDEX(FIX_IPD_OUTPORT), + INTERFACE(FIX_IPD_OUTPORT)), 65392 - 14 - 4); + + cvmx_pko_send_packet_prepare(FIX_IPD_OUTPORT, + cvmx_pko_get_base_queue + (FIX_IPD_OUTPORT), + CVMX_PKO_LOCK_CMD_QUEUE); + cvmx_pko_send_packet_finish(FIX_IPD_OUTPORT, + cvmx_pko_get_base_queue + (FIX_IPD_OUTPORT), pko_command, + g_buffer, CVMX_PKO_LOCK_CMD_QUEUE); + + CVMX_SYNC; + + do { + work = cvmx_pow_work_request_sync(CVMX_POW_WAIT); + retry_cnt--; + } while ((work == NULL) && (retry_cnt > 0)); + + if (!retry_cnt) + cvmx_dprintf("WARNING: FIX_IPD_PTR_ALIGNMENT " + "get_work() timeout occured.\n"); + + /* Free packet */ + if (work) + cvmx_helper_free_packet_data(work); + } + +fix_ipd_exit: + + /* Return CSR configs to saved values */ + cvmx_write_csr(CVMX_GMXX_PRTX_CFG + (INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT)), + prtx_cfg); + cvmx_write_csr(CVMX_ASXX_TX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT)), + tx_ptr_en); + cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT)), + rx_ptr_en); + cvmx_write_csr(CVMX_GMXX_RXX_JABBER + (INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT)), + rxx_jabber); + cvmx_write_csr(CVMX_GMXX_RXX_FRM_MAX + (INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT)), + frame_max); + cvmx_write_csr(CVMX_ASXX_PRT_LOOP(INTERFACE(FIX_IPD_OUTPORT)), 0); + /* Set link to down so autonegotiation will set it up again */ + link_info.u64 = 0; + cvmx_helper_link_set(FIX_IPD_OUTPORT, link_info); + + /* + * Bring the link back up as autonegotiation is not done in + * user applications. + */ + cvmx_helper_link_autoconf(FIX_IPD_OUTPORT); + + CVMX_SYNC; + if (num_segs) + cvmx_dprintf("WARNING: FIX_IPD_PTR_ALIGNMENT failed.\n"); + + return !!num_segs; + +} + +/** + * Called after all internal packet IO paths are setup. This + * function enables IPD/PIP and begins packet input and output. + * + * Returns Zero on success, negative on failure + */ +int cvmx_helper_ipd_and_packet_input_enable(void) +{ + int num_interfaces; + int interface; + + /* Enable IPD */ + cvmx_ipd_enable(); + + /* + * Time to enable hardware ports packet input and output. Note + * that at this point IPD/PIP must be fully functional and PKO + * must be disabled + */ + num_interfaces = cvmx_helper_get_number_of_interfaces(); + for (interface = 0; interface < num_interfaces; interface++) { + if (cvmx_helper_ports_on_interface(interface) > 0) + __cvmx_helper_packet_hardware_enable(interface); + } + + /* Finally enable PKO now that the entire path is up and running */ + cvmx_pko_enable(); + + if ((OCTEON_IS_MODEL(OCTEON_CN31XX_PASS1) + || OCTEON_IS_MODEL(OCTEON_CN30XX_PASS1)) + && (cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM)) + __cvmx_helper_errata_fix_ipd_ptr_alignment(); + return 0; +} + +/** + * Initialize the PIP, IPD, and PKO hardware to support + * simple priority based queues for the ethernet ports. Each + * port is configured with a number of priority queues based + * on CVMX_PKO_QUEUES_PER_PORT_* where each queue is lower + * priority than the previous. + * + * Returns Zero on success, non-zero on failure + */ +int cvmx_helper_initialize_packet_io_global(void) +{ + int result = 0; + int interface; + union cvmx_l2c_cfg l2c_cfg; + union cvmx_smix_en smix_en; + const int num_interfaces = cvmx_helper_get_number_of_interfaces(); + + /* + * CN52XX pass 1: Due to a bug in 2nd order CDR, it needs to + * be disabled. + */ + if (OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_0)) + __cvmx_helper_errata_qlm_disable_2nd_order_cdr(1); + + /* + * Tell L2 to give the IOB statically higher priority compared + * to the cores. This avoids conditions where IO blocks might + * be starved under very high L2 loads. + */ + l2c_cfg.u64 = cvmx_read_csr(CVMX_L2C_CFG); + l2c_cfg.s.lrf_arb_mode = 0; + l2c_cfg.s.rfb_arb_mode = 0; + cvmx_write_csr(CVMX_L2C_CFG, l2c_cfg.u64); + + /* Make sure SMI/MDIO is enabled so we can query PHYs */ + smix_en.u64 = cvmx_read_csr(CVMX_SMIX_EN(0)); + if (!smix_en.s.en) { + smix_en.s.en = 1; + cvmx_write_csr(CVMX_SMIX_EN(0), smix_en.u64); + } + + /* Newer chips actually have two SMI/MDIO interfaces */ + if (!OCTEON_IS_MODEL(OCTEON_CN3XXX) && + !OCTEON_IS_MODEL(OCTEON_CN58XX) && + !OCTEON_IS_MODEL(OCTEON_CN50XX)) { + smix_en.u64 = cvmx_read_csr(CVMX_SMIX_EN(1)); + if (!smix_en.s.en) { + smix_en.s.en = 1; + cvmx_write_csr(CVMX_SMIX_EN(1), smix_en.u64); + } + } + + cvmx_pko_initialize_global(); + for (interface = 0; interface < num_interfaces; interface++) { + result |= cvmx_helper_interface_probe(interface); + if (cvmx_helper_ports_on_interface(interface) > 0) + cvmx_dprintf("Interface %d has %d ports (%s)\n", + interface, + cvmx_helper_ports_on_interface(interface), + cvmx_helper_interface_mode_to_string + (cvmx_helper_interface_get_mode + (interface))); + result |= __cvmx_helper_interface_setup_ipd(interface); + result |= __cvmx_helper_interface_setup_pko(interface); + } + + result |= __cvmx_helper_global_setup_ipd(); + result |= __cvmx_helper_global_setup_pko(); + + /* Enable any flow control and backpressure */ + result |= __cvmx_helper_global_setup_backpressure(); + +#if CVMX_HELPER_ENABLE_IPD + result |= cvmx_helper_ipd_and_packet_input_enable(); +#endif + return result; +} + +/** + * Does core local initialization for packet io + * + * Returns Zero on success, non-zero on failure + */ +int cvmx_helper_initialize_packet_io_local(void) +{ + return cvmx_pko_initialize_local(); +} + +/** + * Auto configure an IPD/PKO port link state and speed. This + * function basically does the equivalent of: + * cvmx_helper_link_set(ipd_port, cvmx_helper_link_get(ipd_port)); + * + * @ipd_port: IPD/PKO port to auto configure + * + * Returns Link state after configure + */ +cvmx_helper_link_info_t cvmx_helper_link_autoconf(int ipd_port) +{ + cvmx_helper_link_info_t link_info; + int interface = cvmx_helper_get_interface_num(ipd_port); + int index = cvmx_helper_get_interface_index_num(ipd_port); + + if (index >= cvmx_helper_ports_on_interface(interface)) { + link_info.u64 = 0; + return link_info; + } + + link_info = cvmx_helper_link_get(ipd_port); + if (link_info.u64 == port_link_info[ipd_port].u64) + return link_info; + + /* If we fail to set the link speed, port_link_info will not change */ + cvmx_helper_link_set(ipd_port, link_info); + + /* + * port_link_info should be the current value, which will be + * different than expect if cvmx_helper_link_set() failed. + */ + return port_link_info[ipd_port]; +} + +/** + * Return the link state of an IPD/PKO port as returned by + * auto negotiation. The result of this function may not match + * Octeon's link config if auto negotiation has changed since + * the last call to cvmx_helper_link_set(). + * + * @ipd_port: IPD/PKO port to query + * + * Returns Link state + */ +cvmx_helper_link_info_t cvmx_helper_link_get(int ipd_port) +{ + cvmx_helper_link_info_t result; + int interface = cvmx_helper_get_interface_num(ipd_port); + int index = cvmx_helper_get_interface_index_num(ipd_port); + + /* The default result will be a down link unless the code below + changes it */ + result.u64 = 0; + + if (index >= cvmx_helper_ports_on_interface(interface)) + return result; + + switch (cvmx_helper_interface_get_mode(interface)) { + case CVMX_HELPER_INTERFACE_MODE_DISABLED: + case CVMX_HELPER_INTERFACE_MODE_PCIE: + /* Network links are not supported */ + break; + case CVMX_HELPER_INTERFACE_MODE_XAUI: + result = __cvmx_helper_xaui_link_get(ipd_port); + break; + case CVMX_HELPER_INTERFACE_MODE_GMII: + if (index == 0) + result = __cvmx_helper_rgmii_link_get(ipd_port); + else { + result.s.full_duplex = 1; + result.s.link_up = 1; + result.s.speed = 1000; + } + break; + case CVMX_HELPER_INTERFACE_MODE_RGMII: + result = __cvmx_helper_rgmii_link_get(ipd_port); + break; + case CVMX_HELPER_INTERFACE_MODE_SPI: + result = __cvmx_helper_spi_link_get(ipd_port); + break; + case CVMX_HELPER_INTERFACE_MODE_SGMII: + case CVMX_HELPER_INTERFACE_MODE_PICMG: + result = __cvmx_helper_sgmii_link_get(ipd_port); + break; + case CVMX_HELPER_INTERFACE_MODE_NPI: + case CVMX_HELPER_INTERFACE_MODE_LOOP: + /* Network links are not supported */ + break; + } + return result; +} + +/** + * Configure an IPD/PKO port for the specified link state. This + * function does not influence auto negotiation at the PHY level. + * The passed link state must always match the link state returned + * by cvmx_helper_link_get(). It is normally best to use + * cvmx_helper_link_autoconf() instead. + * + * @ipd_port: IPD/PKO port to configure + * @link_info: The new link state + * + * Returns Zero on success, negative on failure + */ +int cvmx_helper_link_set(int ipd_port, cvmx_helper_link_info_t link_info) +{ + int result = -1; + int interface = cvmx_helper_get_interface_num(ipd_port); + int index = cvmx_helper_get_interface_index_num(ipd_port); + + if (index >= cvmx_helper_ports_on_interface(interface)) + return -1; + + switch (cvmx_helper_interface_get_mode(interface)) { + case CVMX_HELPER_INTERFACE_MODE_DISABLED: + case CVMX_HELPER_INTERFACE_MODE_PCIE: + break; + case CVMX_HELPER_INTERFACE_MODE_XAUI: + result = __cvmx_helper_xaui_link_set(ipd_port, link_info); + break; + /* + * RGMII/GMII/MII are all treated about the same. Most + * functions refer to these ports as RGMII. + */ + case CVMX_HELPER_INTERFACE_MODE_RGMII: + case CVMX_HELPER_INTERFACE_MODE_GMII: + result = __cvmx_helper_rgmii_link_set(ipd_port, link_info); + break; + case CVMX_HELPER_INTERFACE_MODE_SPI: + result = __cvmx_helper_spi_link_set(ipd_port, link_info); + break; + case CVMX_HELPER_INTERFACE_MODE_SGMII: + case CVMX_HELPER_INTERFACE_MODE_PICMG: + result = __cvmx_helper_sgmii_link_set(ipd_port, link_info); + break; + case CVMX_HELPER_INTERFACE_MODE_NPI: + case CVMX_HELPER_INTERFACE_MODE_LOOP: + break; + } + /* Set the port_link_info here so that the link status is updated + no matter how cvmx_helper_link_set is called. We don't change + the value if link_set failed */ + if (result == 0) + port_link_info[ipd_port].u64 = link_info.u64; + return result; +} + +/** + * Configure a port for internal and/or external loopback. Internal loopback + * causes packets sent by the port to be received by Octeon. External loopback + * causes packets received from the wire to sent out again. + * + * @ipd_port: IPD/PKO port to loopback. + * @enable_internal: + * Non zero if you want internal loopback + * @enable_external: + * Non zero if you want external loopback + * + * Returns Zero on success, negative on failure. + */ +int cvmx_helper_configure_loopback(int ipd_port, int enable_internal, + int enable_external) +{ + int result = -1; + int interface = cvmx_helper_get_interface_num(ipd_port); + int index = cvmx_helper_get_interface_index_num(ipd_port); + + if (index >= cvmx_helper_ports_on_interface(interface)) + return -1; + + switch (cvmx_helper_interface_get_mode(interface)) { + case CVMX_HELPER_INTERFACE_MODE_DISABLED: + case CVMX_HELPER_INTERFACE_MODE_PCIE: + case CVMX_HELPER_INTERFACE_MODE_SPI: + case CVMX_HELPER_INTERFACE_MODE_NPI: + case CVMX_HELPER_INTERFACE_MODE_LOOP: + break; + case CVMX_HELPER_INTERFACE_MODE_XAUI: + result = + __cvmx_helper_xaui_configure_loopback(ipd_port, + enable_internal, + enable_external); + break; + case CVMX_HELPER_INTERFACE_MODE_RGMII: + case CVMX_HELPER_INTERFACE_MODE_GMII: + result = + __cvmx_helper_rgmii_configure_loopback(ipd_port, + enable_internal, + enable_external); + break; + case CVMX_HELPER_INTERFACE_MODE_SGMII: + case CVMX_HELPER_INTERFACE_MODE_PICMG: + result = + __cvmx_helper_sgmii_configure_loopback(ipd_port, + enable_internal, + enable_external); + break; + } + return result; +} diff --git a/drivers/staging/octeon/cvmx-helper.h b/drivers/staging/octeon/cvmx-helper.h new file mode 100644 index 000000000000..51916f3cc40c --- /dev/null +++ b/drivers/staging/octeon/cvmx-helper.h @@ -0,0 +1,227 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2008 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +/* + * + * Helper functions for common, but complicated tasks. + * + */ + +#ifndef __CVMX_HELPER_H__ +#define __CVMX_HELPER_H__ + +#include "cvmx-config.h" +#include "cvmx-fpa.h" +#include "cvmx-wqe.h" + +typedef enum { + CVMX_HELPER_INTERFACE_MODE_DISABLED, + CVMX_HELPER_INTERFACE_MODE_RGMII, + CVMX_HELPER_INTERFACE_MODE_GMII, + CVMX_HELPER_INTERFACE_MODE_SPI, + CVMX_HELPER_INTERFACE_MODE_PCIE, + CVMX_HELPER_INTERFACE_MODE_XAUI, + CVMX_HELPER_INTERFACE_MODE_SGMII, + CVMX_HELPER_INTERFACE_MODE_PICMG, + CVMX_HELPER_INTERFACE_MODE_NPI, + CVMX_HELPER_INTERFACE_MODE_LOOP, +} cvmx_helper_interface_mode_t; + +typedef union { + uint64_t u64; + struct { + uint64_t reserved_20_63:44; + uint64_t link_up:1; /**< Is the physical link up? */ + uint64_t full_duplex:1; /**< 1 if the link is full duplex */ + uint64_t speed:18; /**< Speed of the link in Mbps */ + } s; +} cvmx_helper_link_info_t; + +#include "cvmx-helper-fpa.h" + +#include +#include "cvmx-helper-loop.h" +#include "cvmx-helper-npi.h" +#include "cvmx-helper-rgmii.h" +#include "cvmx-helper-sgmii.h" +#include "cvmx-helper-spi.h" +#include "cvmx-helper-util.h" +#include "cvmx-helper-xaui.h" + +/** + * cvmx_override_pko_queue_priority(int ipd_port, uint64_t + * priorities[16]) is a function pointer. It is meant to allow + * customization of the PKO queue priorities based on the port + * number. Users should set this pointer to a function before + * calling any cvmx-helper operations. + */ +extern void (*cvmx_override_pko_queue_priority) (int pko_port, + uint64_t priorities[16]); + +/** + * cvmx_override_ipd_port_setup(int ipd_port) is a function + * pointer. It is meant to allow customization of the IPD port + * setup before packet input/output comes online. It is called + * after cvmx-helper does the default IPD configuration, but + * before IPD is enabled. Users should set this pointer to a + * function before calling any cvmx-helper operations. + */ +extern void (*cvmx_override_ipd_port_setup) (int ipd_port); + +/** + * This function enables the IPD and also enables the packet interfaces. + * The packet interfaces (RGMII and SPI) must be enabled after the + * IPD. This should be called by the user program after any additional + * IPD configuration changes are made if CVMX_HELPER_ENABLE_IPD + * is not set in the executive-config.h file. + * + * Returns 0 on success + * -1 on failure + */ +extern int cvmx_helper_ipd_and_packet_input_enable(void); + +/** + * Initialize the PIP, IPD, and PKO hardware to support + * simple priority based queues for the ethernet ports. Each + * port is configured with a number of priority queues based + * on CVMX_PKO_QUEUES_PER_PORT_* where each queue is lower + * priority than the previous. + * + * Returns Zero on success, non-zero on failure + */ +extern int cvmx_helper_initialize_packet_io_global(void); + +/** + * Does core local initialization for packet io + * + * Returns Zero on success, non-zero on failure + */ +extern int cvmx_helper_initialize_packet_io_local(void); + +/** + * Returns the number of ports on the given interface. + * The interface must be initialized before the port count + * can be returned. + * + * @interface: Which interface to return port count for. + * + * Returns Port count for interface + * -1 for uninitialized interface + */ +extern int cvmx_helper_ports_on_interface(int interface); + +/** + * Return the number of interfaces the chip has. Each interface + * may have multiple ports. Most chips support two interfaces, + * but the CNX0XX and CNX1XX are exceptions. These only support + * one interface. + * + * Returns Number of interfaces on chip + */ +extern int cvmx_helper_get_number_of_interfaces(void); + +/** + * Get the operating mode of an interface. Depending on the Octeon + * chip and configuration, this function returns an enumeration + * of the type of packet I/O supported by an interface. + * + * @interface: Interface to probe + * + * Returns Mode of the interface. Unknown or unsupported interfaces return + * DISABLED. + */ +extern cvmx_helper_interface_mode_t cvmx_helper_interface_get_mode(int + interface); + +/** + * Auto configure an IPD/PKO port link state and speed. This + * function basically does the equivalent of: + * cvmx_helper_link_set(ipd_port, cvmx_helper_link_get(ipd_port)); + * + * @ipd_port: IPD/PKO port to auto configure + * + * Returns Link state after configure + */ +extern cvmx_helper_link_info_t cvmx_helper_link_autoconf(int ipd_port); + +/** + * Return the link state of an IPD/PKO port as returned by + * auto negotiation. The result of this function may not match + * Octeon's link config if auto negotiation has changed since + * the last call to cvmx_helper_link_set(). + * + * @ipd_port: IPD/PKO port to query + * + * Returns Link state + */ +extern cvmx_helper_link_info_t cvmx_helper_link_get(int ipd_port); + +/** + * Configure an IPD/PKO port for the specified link state. This + * function does not influence auto negotiation at the PHY level. + * The passed link state must always match the link state returned + * by cvmx_helper_link_get(). It is normally best to use + * cvmx_helper_link_autoconf() instead. + * + * @ipd_port: IPD/PKO port to configure + * @link_info: The new link state + * + * Returns Zero on success, negative on failure + */ +extern int cvmx_helper_link_set(int ipd_port, + cvmx_helper_link_info_t link_info); + +/** + * This function probes an interface to determine the actual + * number of hardware ports connected to it. It doesn't setup the + * ports or enable them. The main goal here is to set the global + * interface_port_count[interface] correctly. Hardware setup of the + * ports will be performed later. + * + * @interface: Interface to probe + * + * Returns Zero on success, negative on failure + */ +extern int cvmx_helper_interface_probe(int interface); + +/** + * Configure a port for internal and/or external loopback. Internal loopback + * causes packets sent by the port to be received by Octeon. External loopback + * causes packets received from the wire to sent out again. + * + * @ipd_port: IPD/PKO port to loopback. + * @enable_internal: + * Non zero if you want internal loopback + * @enable_external: + * Non zero if you want external loopback + * + * Returns Zero on success, negative on failure. + */ +extern int cvmx_helper_configure_loopback(int ipd_port, int enable_internal, + int enable_external); + +#endif /* __CVMX_HELPER_H__ */ diff --git a/drivers/staging/octeon/cvmx-interrupt-decodes.c b/drivers/staging/octeon/cvmx-interrupt-decodes.c new file mode 100644 index 000000000000..a3337e382ee9 --- /dev/null +++ b/drivers/staging/octeon/cvmx-interrupt-decodes.c @@ -0,0 +1,371 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2009 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +/* + * + * Automatically generated functions useful for enabling + * and decoding RSL_INT_BLOCKS interrupts. + * + */ + +#include + +#include "cvmx-gmxx-defs.h" +#include "cvmx-pcsx-defs.h" +#include "cvmx-pcsxx-defs.h" +#include "cvmx-spxx-defs.h" +#include "cvmx-stxx-defs.h" + +#ifndef PRINT_ERROR +#define PRINT_ERROR(format, ...) +#endif + + +/** + * __cvmx_interrupt_gmxx_rxx_int_en_enable enables all interrupt bits in cvmx_gmxx_rxx_int_en_t + */ +void __cvmx_interrupt_gmxx_rxx_int_en_enable(int index, int block) +{ + union cvmx_gmxx_rxx_int_en gmx_rx_int_en; + cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(index, block), + cvmx_read_csr(CVMX_GMXX_RXX_INT_REG(index, block))); + gmx_rx_int_en.u64 = 0; + if (OCTEON_IS_MODEL(OCTEON_CN56XX)) { + /* Skipping gmx_rx_int_en.s.reserved_29_63 */ + gmx_rx_int_en.s.hg2cc = 1; + gmx_rx_int_en.s.hg2fld = 1; + gmx_rx_int_en.s.undat = 1; + gmx_rx_int_en.s.uneop = 1; + gmx_rx_int_en.s.unsop = 1; + gmx_rx_int_en.s.bad_term = 1; + gmx_rx_int_en.s.bad_seq = 1; + gmx_rx_int_en.s.rem_fault = 1; + gmx_rx_int_en.s.loc_fault = 1; + gmx_rx_int_en.s.pause_drp = 1; + /* Skipping gmx_rx_int_en.s.reserved_16_18 */ + /*gmx_rx_int_en.s.ifgerr = 1; */ + /*gmx_rx_int_en.s.coldet = 1; // Collsion detect */ + /*gmx_rx_int_en.s.falerr = 1; // False carrier error or extend error after slottime */ + /*gmx_rx_int_en.s.rsverr = 1; // RGMII reserved opcodes */ + /*gmx_rx_int_en.s.pcterr = 1; // Bad Preamble / Protocol */ + gmx_rx_int_en.s.ovrerr = 1; + /* Skipping gmx_rx_int_en.s.reserved_9_9 */ + gmx_rx_int_en.s.skperr = 1; + gmx_rx_int_en.s.rcverr = 1; + /* Skipping gmx_rx_int_en.s.reserved_5_6 */ + /*gmx_rx_int_en.s.fcserr = 1; // FCS errors are handled when we get work */ + gmx_rx_int_en.s.jabber = 1; + /* Skipping gmx_rx_int_en.s.reserved_2_2 */ + gmx_rx_int_en.s.carext = 1; + /* Skipping gmx_rx_int_en.s.reserved_0_0 */ + } + if (OCTEON_IS_MODEL(OCTEON_CN30XX)) { + /* Skipping gmx_rx_int_en.s.reserved_19_63 */ + /*gmx_rx_int_en.s.phy_dupx = 1; */ + /*gmx_rx_int_en.s.phy_spd = 1; */ + /*gmx_rx_int_en.s.phy_link = 1; */ + /*gmx_rx_int_en.s.ifgerr = 1; */ + /*gmx_rx_int_en.s.coldet = 1; // Collsion detect */ + /*gmx_rx_int_en.s.falerr = 1; // False carrier error or extend error after slottime */ + /*gmx_rx_int_en.s.rsverr = 1; // RGMII reserved opcodes */ + /*gmx_rx_int_en.s.pcterr = 1; // Bad Preamble / Protocol */ + gmx_rx_int_en.s.ovrerr = 1; + gmx_rx_int_en.s.niberr = 1; + gmx_rx_int_en.s.skperr = 1; + gmx_rx_int_en.s.rcverr = 1; + /*gmx_rx_int_en.s.lenerr = 1; // Length errors are handled when we get work */ + gmx_rx_int_en.s.alnerr = 1; + /*gmx_rx_int_en.s.fcserr = 1; // FCS errors are handled when we get work */ + gmx_rx_int_en.s.jabber = 1; + gmx_rx_int_en.s.maxerr = 1; + gmx_rx_int_en.s.carext = 1; + gmx_rx_int_en.s.minerr = 1; + } + if (OCTEON_IS_MODEL(OCTEON_CN50XX)) { + /* Skipping gmx_rx_int_en.s.reserved_20_63 */ + gmx_rx_int_en.s.pause_drp = 1; + /*gmx_rx_int_en.s.phy_dupx = 1; */ + /*gmx_rx_int_en.s.phy_spd = 1; */ + /*gmx_rx_int_en.s.phy_link = 1; */ + /*gmx_rx_int_en.s.ifgerr = 1; */ + /*gmx_rx_int_en.s.coldet = 1; // Collsion detect */ + /*gmx_rx_int_en.s.falerr = 1; // False carrier error or extend error after slottime */ + /*gmx_rx_int_en.s.rsverr = 1; // RGMII reserved opcodes */ + /*gmx_rx_int_en.s.pcterr = 1; // Bad Preamble / Protocol */ + gmx_rx_int_en.s.ovrerr = 1; + gmx_rx_int_en.s.niberr = 1; + gmx_rx_int_en.s.skperr = 1; + gmx_rx_int_en.s.rcverr = 1; + /* Skipping gmx_rx_int_en.s.reserved_6_6 */ + gmx_rx_int_en.s.alnerr = 1; + /*gmx_rx_int_en.s.fcserr = 1; // FCS errors are handled when we get work */ + gmx_rx_int_en.s.jabber = 1; + /* Skipping gmx_rx_int_en.s.reserved_2_2 */ + gmx_rx_int_en.s.carext = 1; + /* Skipping gmx_rx_int_en.s.reserved_0_0 */ + } + if (OCTEON_IS_MODEL(OCTEON_CN38XX)) { + /* Skipping gmx_rx_int_en.s.reserved_19_63 */ + /*gmx_rx_int_en.s.phy_dupx = 1; */ + /*gmx_rx_int_en.s.phy_spd = 1; */ + /*gmx_rx_int_en.s.phy_link = 1; */ + /*gmx_rx_int_en.s.ifgerr = 1; */ + /*gmx_rx_int_en.s.coldet = 1; // Collsion detect */ + /*gmx_rx_int_en.s.falerr = 1; // False carrier error or extend error after slottime */ + /*gmx_rx_int_en.s.rsverr = 1; // RGMII reserved opcodes */ + /*gmx_rx_int_en.s.pcterr = 1; // Bad Preamble / Protocol */ + gmx_rx_int_en.s.ovrerr = 1; + gmx_rx_int_en.s.niberr = 1; + gmx_rx_int_en.s.skperr = 1; + gmx_rx_int_en.s.rcverr = 1; + /*gmx_rx_int_en.s.lenerr = 1; // Length errors are handled when we get work */ + gmx_rx_int_en.s.alnerr = 1; + /*gmx_rx_int_en.s.fcserr = 1; // FCS errors are handled when we get work */ + gmx_rx_int_en.s.jabber = 1; + gmx_rx_int_en.s.maxerr = 1; + gmx_rx_int_en.s.carext = 1; + gmx_rx_int_en.s.minerr = 1; + } + if (OCTEON_IS_MODEL(OCTEON_CN31XX)) { + /* Skipping gmx_rx_int_en.s.reserved_19_63 */ + /*gmx_rx_int_en.s.phy_dupx = 1; */ + /*gmx_rx_int_en.s.phy_spd = 1; */ + /*gmx_rx_int_en.s.phy_link = 1; */ + /*gmx_rx_int_en.s.ifgerr = 1; */ + /*gmx_rx_int_en.s.coldet = 1; // Collsion detect */ + /*gmx_rx_int_en.s.falerr = 1; // False carrier error or extend error after slottime */ + /*gmx_rx_int_en.s.rsverr = 1; // RGMII reserved opcodes */ + /*gmx_rx_int_en.s.pcterr = 1; // Bad Preamble / Protocol */ + gmx_rx_int_en.s.ovrerr = 1; + gmx_rx_int_en.s.niberr = 1; + gmx_rx_int_en.s.skperr = 1; + gmx_rx_int_en.s.rcverr = 1; + /*gmx_rx_int_en.s.lenerr = 1; // Length errors are handled when we get work */ + gmx_rx_int_en.s.alnerr = 1; + /*gmx_rx_int_en.s.fcserr = 1; // FCS errors are handled when we get work */ + gmx_rx_int_en.s.jabber = 1; + gmx_rx_int_en.s.maxerr = 1; + gmx_rx_int_en.s.carext = 1; + gmx_rx_int_en.s.minerr = 1; + } + if (OCTEON_IS_MODEL(OCTEON_CN58XX)) { + /* Skipping gmx_rx_int_en.s.reserved_20_63 */ + gmx_rx_int_en.s.pause_drp = 1; + /*gmx_rx_int_en.s.phy_dupx = 1; */ + /*gmx_rx_int_en.s.phy_spd = 1; */ + /*gmx_rx_int_en.s.phy_link = 1; */ + /*gmx_rx_int_en.s.ifgerr = 1; */ + /*gmx_rx_int_en.s.coldet = 1; // Collsion detect */ + /*gmx_rx_int_en.s.falerr = 1; // False carrier error or extend error after slottime */ + /*gmx_rx_int_en.s.rsverr = 1; // RGMII reserved opcodes */ + /*gmx_rx_int_en.s.pcterr = 1; // Bad Preamble / Protocol */ + gmx_rx_int_en.s.ovrerr = 1; + gmx_rx_int_en.s.niberr = 1; + gmx_rx_int_en.s.skperr = 1; + gmx_rx_int_en.s.rcverr = 1; + /*gmx_rx_int_en.s.lenerr = 1; // Length errors are handled when we get work */ + gmx_rx_int_en.s.alnerr = 1; + /*gmx_rx_int_en.s.fcserr = 1; // FCS errors are handled when we get work */ + gmx_rx_int_en.s.jabber = 1; + gmx_rx_int_en.s.maxerr = 1; + gmx_rx_int_en.s.carext = 1; + gmx_rx_int_en.s.minerr = 1; + } + if (OCTEON_IS_MODEL(OCTEON_CN52XX)) { + /* Skipping gmx_rx_int_en.s.reserved_29_63 */ + gmx_rx_int_en.s.hg2cc = 1; + gmx_rx_int_en.s.hg2fld = 1; + gmx_rx_int_en.s.undat = 1; + gmx_rx_int_en.s.uneop = 1; + gmx_rx_int_en.s.unsop = 1; + gmx_rx_int_en.s.bad_term = 1; + gmx_rx_int_en.s.bad_seq = 0; + gmx_rx_int_en.s.rem_fault = 1; + gmx_rx_int_en.s.loc_fault = 0; + gmx_rx_int_en.s.pause_drp = 1; + /* Skipping gmx_rx_int_en.s.reserved_16_18 */ + /*gmx_rx_int_en.s.ifgerr = 1; */ + /*gmx_rx_int_en.s.coldet = 1; // Collsion detect */ + /*gmx_rx_int_en.s.falerr = 1; // False carrier error or extend error after slottime */ + /*gmx_rx_int_en.s.rsverr = 1; // RGMII reserved opcodes */ + /*gmx_rx_int_en.s.pcterr = 1; // Bad Preamble / Protocol */ + gmx_rx_int_en.s.ovrerr = 1; + /* Skipping gmx_rx_int_en.s.reserved_9_9 */ + gmx_rx_int_en.s.skperr = 1; + gmx_rx_int_en.s.rcverr = 1; + /* Skipping gmx_rx_int_en.s.reserved_5_6 */ + /*gmx_rx_int_en.s.fcserr = 1; // FCS errors are handled when we get work */ + gmx_rx_int_en.s.jabber = 1; + /* Skipping gmx_rx_int_en.s.reserved_2_2 */ + gmx_rx_int_en.s.carext = 1; + /* Skipping gmx_rx_int_en.s.reserved_0_0 */ + } + cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(index, block), gmx_rx_int_en.u64); +} +/** + * __cvmx_interrupt_pcsx_intx_en_reg_enable enables all interrupt bits in cvmx_pcsx_intx_en_reg_t + */ +void __cvmx_interrupt_pcsx_intx_en_reg_enable(int index, int block) +{ + union cvmx_pcsx_intx_en_reg pcs_int_en_reg; + cvmx_write_csr(CVMX_PCSX_INTX_REG(index, block), + cvmx_read_csr(CVMX_PCSX_INTX_REG(index, block))); + pcs_int_en_reg.u64 = 0; + if (OCTEON_IS_MODEL(OCTEON_CN56XX)) { + /* Skipping pcs_int_en_reg.s.reserved_12_63 */ + /*pcs_int_en_reg.s.dup = 1; // This happens during normal operation */ + pcs_int_en_reg.s.sync_bad_en = 1; + pcs_int_en_reg.s.an_bad_en = 1; + pcs_int_en_reg.s.rxlock_en = 1; + pcs_int_en_reg.s.rxbad_en = 1; + /*pcs_int_en_reg.s.rxerr_en = 1; // This happens during normal operation */ + pcs_int_en_reg.s.txbad_en = 1; + pcs_int_en_reg.s.txfifo_en = 1; + pcs_int_en_reg.s.txfifu_en = 1; + pcs_int_en_reg.s.an_err_en = 1; + /*pcs_int_en_reg.s.xmit_en = 1; // This happens during normal operation */ + /*pcs_int_en_reg.s.lnkspd_en = 1; // This happens during normal operation */ + } + if (OCTEON_IS_MODEL(OCTEON_CN52XX)) { + /* Skipping pcs_int_en_reg.s.reserved_12_63 */ + /*pcs_int_en_reg.s.dup = 1; // This happens during normal operation */ + pcs_int_en_reg.s.sync_bad_en = 1; + pcs_int_en_reg.s.an_bad_en = 1; + pcs_int_en_reg.s.rxlock_en = 1; + pcs_int_en_reg.s.rxbad_en = 1; + /*pcs_int_en_reg.s.rxerr_en = 1; // This happens during normal operation */ + pcs_int_en_reg.s.txbad_en = 1; + pcs_int_en_reg.s.txfifo_en = 1; + pcs_int_en_reg.s.txfifu_en = 1; + pcs_int_en_reg.s.an_err_en = 1; + /*pcs_int_en_reg.s.xmit_en = 1; // This happens during normal operation */ + /*pcs_int_en_reg.s.lnkspd_en = 1; // This happens during normal operation */ + } + cvmx_write_csr(CVMX_PCSX_INTX_EN_REG(index, block), pcs_int_en_reg.u64); +} +/** + * __cvmx_interrupt_pcsxx_int_en_reg_enable enables all interrupt bits in cvmx_pcsxx_int_en_reg_t + */ +void __cvmx_interrupt_pcsxx_int_en_reg_enable(int index) +{ + union cvmx_pcsxx_int_en_reg pcsx_int_en_reg; + cvmx_write_csr(CVMX_PCSXX_INT_REG(index), + cvmx_read_csr(CVMX_PCSXX_INT_REG(index))); + pcsx_int_en_reg.u64 = 0; + if (OCTEON_IS_MODEL(OCTEON_CN56XX)) { + /* Skipping pcsx_int_en_reg.s.reserved_6_63 */ + pcsx_int_en_reg.s.algnlos_en = 1; + pcsx_int_en_reg.s.synlos_en = 1; + pcsx_int_en_reg.s.bitlckls_en = 1; + pcsx_int_en_reg.s.rxsynbad_en = 1; + pcsx_int_en_reg.s.rxbad_en = 1; + pcsx_int_en_reg.s.txflt_en = 1; + } + if (OCTEON_IS_MODEL(OCTEON_CN52XX)) { + /* Skipping pcsx_int_en_reg.s.reserved_6_63 */ + pcsx_int_en_reg.s.algnlos_en = 1; + pcsx_int_en_reg.s.synlos_en = 1; + pcsx_int_en_reg.s.bitlckls_en = 0; /* Happens if XAUI module is not installed */ + pcsx_int_en_reg.s.rxsynbad_en = 1; + pcsx_int_en_reg.s.rxbad_en = 1; + pcsx_int_en_reg.s.txflt_en = 1; + } + cvmx_write_csr(CVMX_PCSXX_INT_EN_REG(index), pcsx_int_en_reg.u64); +} + +/** + * __cvmx_interrupt_spxx_int_msk_enable enables all interrupt bits in cvmx_spxx_int_msk_t + */ +void __cvmx_interrupt_spxx_int_msk_enable(int index) +{ + union cvmx_spxx_int_msk spx_int_msk; + cvmx_write_csr(CVMX_SPXX_INT_REG(index), + cvmx_read_csr(CVMX_SPXX_INT_REG(index))); + spx_int_msk.u64 = 0; + if (OCTEON_IS_MODEL(OCTEON_CN38XX)) { + /* Skipping spx_int_msk.s.reserved_12_63 */ + spx_int_msk.s.calerr = 1; + spx_int_msk.s.syncerr = 1; + spx_int_msk.s.diperr = 1; + spx_int_msk.s.tpaovr = 1; + spx_int_msk.s.rsverr = 1; + spx_int_msk.s.drwnng = 1; + spx_int_msk.s.clserr = 1; + spx_int_msk.s.spiovr = 1; + /* Skipping spx_int_msk.s.reserved_2_3 */ + spx_int_msk.s.abnorm = 1; + spx_int_msk.s.prtnxa = 1; + } + if (OCTEON_IS_MODEL(OCTEON_CN58XX)) { + /* Skipping spx_int_msk.s.reserved_12_63 */ + spx_int_msk.s.calerr = 1; + spx_int_msk.s.syncerr = 1; + spx_int_msk.s.diperr = 1; + spx_int_msk.s.tpaovr = 1; + spx_int_msk.s.rsverr = 1; + spx_int_msk.s.drwnng = 1; + spx_int_msk.s.clserr = 1; + spx_int_msk.s.spiovr = 1; + /* Skipping spx_int_msk.s.reserved_2_3 */ + spx_int_msk.s.abnorm = 1; + spx_int_msk.s.prtnxa = 1; + } + cvmx_write_csr(CVMX_SPXX_INT_MSK(index), spx_int_msk.u64); +} +/** + * __cvmx_interrupt_stxx_int_msk_enable enables all interrupt bits in cvmx_stxx_int_msk_t + */ +void __cvmx_interrupt_stxx_int_msk_enable(int index) +{ + union cvmx_stxx_int_msk stx_int_msk; + cvmx_write_csr(CVMX_STXX_INT_REG(index), + cvmx_read_csr(CVMX_STXX_INT_REG(index))); + stx_int_msk.u64 = 0; + if (OCTEON_IS_MODEL(OCTEON_CN38XX)) { + /* Skipping stx_int_msk.s.reserved_8_63 */ + stx_int_msk.s.frmerr = 1; + stx_int_msk.s.unxfrm = 1; + stx_int_msk.s.nosync = 1; + stx_int_msk.s.diperr = 1; + stx_int_msk.s.datovr = 1; + stx_int_msk.s.ovrbst = 1; + stx_int_msk.s.calpar1 = 1; + stx_int_msk.s.calpar0 = 1; + } + if (OCTEON_IS_MODEL(OCTEON_CN58XX)) { + /* Skipping stx_int_msk.s.reserved_8_63 */ + stx_int_msk.s.frmerr = 1; + stx_int_msk.s.unxfrm = 1; + stx_int_msk.s.nosync = 1; + stx_int_msk.s.diperr = 1; + stx_int_msk.s.datovr = 1; + stx_int_msk.s.ovrbst = 1; + stx_int_msk.s.calpar1 = 1; + stx_int_msk.s.calpar0 = 1; + } + cvmx_write_csr(CVMX_STXX_INT_MSK(index), stx_int_msk.u64); +} diff --git a/drivers/staging/octeon/cvmx-interrupt-rsl.c b/drivers/staging/octeon/cvmx-interrupt-rsl.c new file mode 100644 index 000000000000..df50048cfbc0 --- /dev/null +++ b/drivers/staging/octeon/cvmx-interrupt-rsl.c @@ -0,0 +1,140 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2008 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +/* + * Utility functions to decode Octeon's RSL_INT_BLOCKS + * interrupts into error messages. + */ + +#include + +#include "cvmx-asxx-defs.h" +#include "cvmx-gmxx-defs.h" + +#ifndef PRINT_ERROR +#define PRINT_ERROR(format, ...) +#endif + +void __cvmx_interrupt_gmxx_rxx_int_en_enable(int index, int block); + +/** + * Enable ASX error interrupts that exist on CN3XXX, CN50XX, and + * CN58XX. + * + * @block: Interface to enable 0-1 + */ +void __cvmx_interrupt_asxx_enable(int block) +{ + int mask; + union cvmx_asxx_int_en csr; + /* + * CN38XX and CN58XX have two interfaces with 4 ports per + * interface. All other chips have a max of 3 ports on + * interface 0 + */ + if (OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX)) + mask = 0xf; /* Set enables for 4 ports */ + else + mask = 0x7; /* Set enables for 3 ports */ + + /* Enable interface interrupts */ + csr.u64 = cvmx_read_csr(CVMX_ASXX_INT_EN(block)); + csr.s.txpsh = mask; + csr.s.txpop = mask; + csr.s.ovrflw = mask; + cvmx_write_csr(CVMX_ASXX_INT_EN(block), csr.u64); +} +/** + * Enable GMX error reporting for the supplied interface + * + * @interface: Interface to enable + */ +void __cvmx_interrupt_gmxx_enable(int interface) +{ + union cvmx_gmxx_inf_mode mode; + union cvmx_gmxx_tx_int_en gmx_tx_int_en; + int num_ports; + int index; + + mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface)); + + if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN52XX)) { + if (mode.s.en) { + switch (mode.cn56xx.mode) { + case 1: /* XAUI */ + num_ports = 1; + break; + case 2: /* SGMII */ + case 3: /* PICMG */ + num_ports = 4; + break; + default: /* Disabled */ + num_ports = 0; + break; + } + } else + num_ports = 0; + } else { + if (mode.s.en) { + if (OCTEON_IS_MODEL(OCTEON_CN38XX) + || OCTEON_IS_MODEL(OCTEON_CN58XX)) { + /* + * SPI on CN38XX and CN58XX report all + * errors through port 0. RGMII needs + * to check all 4 ports + */ + if (mode.s.type) + num_ports = 1; + else + num_ports = 4; + } else { + /* + * CN30XX, CN31XX, and CN50XX have two + * or three ports. GMII and MII has 2, + * RGMII has three + */ + if (mode.s.type) + num_ports = 2; + else + num_ports = 3; + } + } else + num_ports = 0; + } + + gmx_tx_int_en.u64 = 0; + if (num_ports) { + if (OCTEON_IS_MODEL(OCTEON_CN38XX) + || OCTEON_IS_MODEL(OCTEON_CN58XX)) + gmx_tx_int_en.s.ncb_nxa = 1; + gmx_tx_int_en.s.pko_nxa = 1; + } + gmx_tx_int_en.s.undflw = (1 << num_ports) - 1; + cvmx_write_csr(CVMX_GMXX_TX_INT_EN(interface), gmx_tx_int_en.u64); + for (index = 0; index < num_ports; index++) + __cvmx_interrupt_gmxx_rxx_int_en_enable(index, interface); +} diff --git a/drivers/staging/octeon/cvmx-ipd.h b/drivers/staging/octeon/cvmx-ipd.h new file mode 100644 index 000000000000..115a552c5c7f --- /dev/null +++ b/drivers/staging/octeon/cvmx-ipd.h @@ -0,0 +1,338 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2008 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +/** + * + * Interface to the hardware Input Packet Data unit. + */ + +#ifndef __CVMX_IPD_H__ +#define __CVMX_IPD_H__ + +#include + +#include + +enum cvmx_ipd_mode { + CVMX_IPD_OPC_MODE_STT = 0LL, /* All blocks DRAM, not cached in L2 */ + CVMX_IPD_OPC_MODE_STF = 1LL, /* All bloccks into L2 */ + CVMX_IPD_OPC_MODE_STF1_STT = 2LL, /* 1st block L2, rest DRAM */ + CVMX_IPD_OPC_MODE_STF2_STT = 3LL /* 1st, 2nd blocks L2, rest DRAM */ +}; + +#ifndef CVMX_ENABLE_LEN_M8_FIX +#define CVMX_ENABLE_LEN_M8_FIX 0 +#endif + +/* CSR typedefs have been moved to cvmx-csr-*.h */ +typedef union cvmx_ipd_1st_mbuff_skip cvmx_ipd_mbuff_first_skip_t; +typedef union cvmx_ipd_1st_next_ptr_back cvmx_ipd_first_next_ptr_back_t; + +typedef cvmx_ipd_mbuff_first_skip_t cvmx_ipd_mbuff_not_first_skip_t; +typedef cvmx_ipd_first_next_ptr_back_t cvmx_ipd_second_next_ptr_back_t; + +/** + * Configure IPD + * + * @mbuff_size: Packets buffer size in 8 byte words + * @first_mbuff_skip: + * Number of 8 byte words to skip in the first buffer + * @not_first_mbuff_skip: + * Number of 8 byte words to skip in each following buffer + * @first_back: Must be same as first_mbuff_skip / 128 + * @second_back: + * Must be same as not_first_mbuff_skip / 128 + * @wqe_fpa_pool: + * FPA pool to get work entries from + * @cache_mode: + * @back_pres_enable_flag: + * Enable or disable port back pressure + */ +static inline void cvmx_ipd_config(uint64_t mbuff_size, + uint64_t first_mbuff_skip, + uint64_t not_first_mbuff_skip, + uint64_t first_back, + uint64_t second_back, + uint64_t wqe_fpa_pool, + enum cvmx_ipd_mode cache_mode, + uint64_t back_pres_enable_flag) +{ + cvmx_ipd_mbuff_first_skip_t first_skip; + cvmx_ipd_mbuff_not_first_skip_t not_first_skip; + union cvmx_ipd_packet_mbuff_size size; + cvmx_ipd_first_next_ptr_back_t first_back_struct; + cvmx_ipd_second_next_ptr_back_t second_back_struct; + union cvmx_ipd_wqe_fpa_queue wqe_pool; + union cvmx_ipd_ctl_status ipd_ctl_reg; + + first_skip.u64 = 0; + first_skip.s.skip_sz = first_mbuff_skip; + cvmx_write_csr(CVMX_IPD_1ST_MBUFF_SKIP, first_skip.u64); + + not_first_skip.u64 = 0; + not_first_skip.s.skip_sz = not_first_mbuff_skip; + cvmx_write_csr(CVMX_IPD_NOT_1ST_MBUFF_SKIP, not_first_skip.u64); + + size.u64 = 0; + size.s.mb_size = mbuff_size; + cvmx_write_csr(CVMX_IPD_PACKET_MBUFF_SIZE, size.u64); + + first_back_struct.u64 = 0; + first_back_struct.s.back = first_back; + cvmx_write_csr(CVMX_IPD_1st_NEXT_PTR_BACK, first_back_struct.u64); + + second_back_struct.u64 = 0; + second_back_struct.s.back = second_back; + cvmx_write_csr(CVMX_IPD_2nd_NEXT_PTR_BACK, second_back_struct.u64); + + wqe_pool.u64 = 0; + wqe_pool.s.wqe_pool = wqe_fpa_pool; + cvmx_write_csr(CVMX_IPD_WQE_FPA_QUEUE, wqe_pool.u64); + + ipd_ctl_reg.u64 = cvmx_read_csr(CVMX_IPD_CTL_STATUS); + ipd_ctl_reg.s.opc_mode = cache_mode; + ipd_ctl_reg.s.pbp_en = back_pres_enable_flag; + cvmx_write_csr(CVMX_IPD_CTL_STATUS, ipd_ctl_reg.u64); + + /* Note: the example RED code that used to be here has been moved to + cvmx_helper_setup_red */ +} + +/** + * Enable IPD + */ +static inline void cvmx_ipd_enable(void) +{ + union cvmx_ipd_ctl_status ipd_reg; + ipd_reg.u64 = cvmx_read_csr(CVMX_IPD_CTL_STATUS); + if (ipd_reg.s.ipd_en) { + cvmx_dprintf + ("Warning: Enabling IPD when IPD already enabled.\n"); + } + ipd_reg.s.ipd_en = 1; +#if CVMX_ENABLE_LEN_M8_FIX + if (!OCTEON_IS_MODEL(OCTEON_CN38XX_PASS2)) + ipd_reg.s.len_m8 = TRUE; +#endif + cvmx_write_csr(CVMX_IPD_CTL_STATUS, ipd_reg.u64); +} + +/** + * Disable IPD + */ +static inline void cvmx_ipd_disable(void) +{ + union cvmx_ipd_ctl_status ipd_reg; + ipd_reg.u64 = cvmx_read_csr(CVMX_IPD_CTL_STATUS); + ipd_reg.s.ipd_en = 0; + cvmx_write_csr(CVMX_IPD_CTL_STATUS, ipd_reg.u64); +} + +/** + * Supportive function for cvmx_fpa_shutdown_pool. + */ +static inline void cvmx_ipd_free_ptr(void) +{ + /* Only CN38XXp{1,2} cannot read pointer out of the IPD */ + if (!OCTEON_IS_MODEL(OCTEON_CN38XX_PASS1) + && !OCTEON_IS_MODEL(OCTEON_CN38XX_PASS2)) { + int no_wptr = 0; + union cvmx_ipd_ptr_count ipd_ptr_count; + ipd_ptr_count.u64 = cvmx_read_csr(CVMX_IPD_PTR_COUNT); + + /* Handle Work Queue Entry in cn56xx and cn52xx */ + if (octeon_has_feature(OCTEON_FEATURE_NO_WPTR)) { + union cvmx_ipd_ctl_status ipd_ctl_status; + ipd_ctl_status.u64 = cvmx_read_csr(CVMX_IPD_CTL_STATUS); + if (ipd_ctl_status.s.no_wptr) + no_wptr = 1; + } + + /* Free the prefetched WQE */ + if (ipd_ptr_count.s.wqev_cnt) { + union cvmx_ipd_wqe_ptr_valid ipd_wqe_ptr_valid; + ipd_wqe_ptr_valid.u64 = + cvmx_read_csr(CVMX_IPD_WQE_PTR_VALID); + if (no_wptr) + cvmx_fpa_free(cvmx_phys_to_ptr + ((uint64_t) ipd_wqe_ptr_valid.s. + ptr << 7), CVMX_FPA_PACKET_POOL, + 0); + else + cvmx_fpa_free(cvmx_phys_to_ptr + ((uint64_t) ipd_wqe_ptr_valid.s. + ptr << 7), CVMX_FPA_WQE_POOL, 0); + } + + /* Free all WQE in the fifo */ + if (ipd_ptr_count.s.wqe_pcnt) { + int i; + union cvmx_ipd_pwp_ptr_fifo_ctl ipd_pwp_ptr_fifo_ctl; + ipd_pwp_ptr_fifo_ctl.u64 = + cvmx_read_csr(CVMX_IPD_PWP_PTR_FIFO_CTL); + for (i = 0; i < ipd_ptr_count.s.wqe_pcnt; i++) { + ipd_pwp_ptr_fifo_ctl.s.cena = 0; + ipd_pwp_ptr_fifo_ctl.s.raddr = + ipd_pwp_ptr_fifo_ctl.s.max_cnts + + (ipd_pwp_ptr_fifo_ctl.s.wraddr + + i) % ipd_pwp_ptr_fifo_ctl.s.max_cnts; + cvmx_write_csr(CVMX_IPD_PWP_PTR_FIFO_CTL, + ipd_pwp_ptr_fifo_ctl.u64); + ipd_pwp_ptr_fifo_ctl.u64 = + cvmx_read_csr(CVMX_IPD_PWP_PTR_FIFO_CTL); + if (no_wptr) + cvmx_fpa_free(cvmx_phys_to_ptr + ((uint64_t) + ipd_pwp_ptr_fifo_ctl.s. + ptr << 7), + CVMX_FPA_PACKET_POOL, 0); + else + cvmx_fpa_free(cvmx_phys_to_ptr + ((uint64_t) + ipd_pwp_ptr_fifo_ctl.s. + ptr << 7), + CVMX_FPA_WQE_POOL, 0); + } + ipd_pwp_ptr_fifo_ctl.s.cena = 1; + cvmx_write_csr(CVMX_IPD_PWP_PTR_FIFO_CTL, + ipd_pwp_ptr_fifo_ctl.u64); + } + + /* Free the prefetched packet */ + if (ipd_ptr_count.s.pktv_cnt) { + union cvmx_ipd_pkt_ptr_valid ipd_pkt_ptr_valid; + ipd_pkt_ptr_valid.u64 = + cvmx_read_csr(CVMX_IPD_PKT_PTR_VALID); + cvmx_fpa_free(cvmx_phys_to_ptr + (ipd_pkt_ptr_valid.s.ptr << 7), + CVMX_FPA_PACKET_POOL, 0); + } + + /* Free the per port prefetched packets */ + if (1) { + int i; + union cvmx_ipd_prc_port_ptr_fifo_ctl + ipd_prc_port_ptr_fifo_ctl; + ipd_prc_port_ptr_fifo_ctl.u64 = + cvmx_read_csr(CVMX_IPD_PRC_PORT_PTR_FIFO_CTL); + + for (i = 0; i < ipd_prc_port_ptr_fifo_ctl.s.max_pkt; + i++) { + ipd_prc_port_ptr_fifo_ctl.s.cena = 0; + ipd_prc_port_ptr_fifo_ctl.s.raddr = + i % ipd_prc_port_ptr_fifo_ctl.s.max_pkt; + cvmx_write_csr(CVMX_IPD_PRC_PORT_PTR_FIFO_CTL, + ipd_prc_port_ptr_fifo_ctl.u64); + ipd_prc_port_ptr_fifo_ctl.u64 = + cvmx_read_csr + (CVMX_IPD_PRC_PORT_PTR_FIFO_CTL); + cvmx_fpa_free(cvmx_phys_to_ptr + ((uint64_t) + ipd_prc_port_ptr_fifo_ctl.s. + ptr << 7), CVMX_FPA_PACKET_POOL, + 0); + } + ipd_prc_port_ptr_fifo_ctl.s.cena = 1; + cvmx_write_csr(CVMX_IPD_PRC_PORT_PTR_FIFO_CTL, + ipd_prc_port_ptr_fifo_ctl.u64); + } + + /* Free all packets in the holding fifo */ + if (ipd_ptr_count.s.pfif_cnt) { + int i; + union cvmx_ipd_prc_hold_ptr_fifo_ctl + ipd_prc_hold_ptr_fifo_ctl; + + ipd_prc_hold_ptr_fifo_ctl.u64 = + cvmx_read_csr(CVMX_IPD_PRC_HOLD_PTR_FIFO_CTL); + + for (i = 0; i < ipd_ptr_count.s.pfif_cnt; i++) { + ipd_prc_hold_ptr_fifo_ctl.s.cena = 0; + ipd_prc_hold_ptr_fifo_ctl.s.raddr = + (ipd_prc_hold_ptr_fifo_ctl.s.praddr + + i) % ipd_prc_hold_ptr_fifo_ctl.s.max_pkt; + cvmx_write_csr(CVMX_IPD_PRC_HOLD_PTR_FIFO_CTL, + ipd_prc_hold_ptr_fifo_ctl.u64); + ipd_prc_hold_ptr_fifo_ctl.u64 = + cvmx_read_csr + (CVMX_IPD_PRC_HOLD_PTR_FIFO_CTL); + cvmx_fpa_free(cvmx_phys_to_ptr + ((uint64_t) + ipd_prc_hold_ptr_fifo_ctl.s. + ptr << 7), CVMX_FPA_PACKET_POOL, + 0); + } + ipd_prc_hold_ptr_fifo_ctl.s.cena = 1; + cvmx_write_csr(CVMX_IPD_PRC_HOLD_PTR_FIFO_CTL, + ipd_prc_hold_ptr_fifo_ctl.u64); + } + + /* Free all packets in the fifo */ + if (ipd_ptr_count.s.pkt_pcnt) { + int i; + union cvmx_ipd_pwp_ptr_fifo_ctl ipd_pwp_ptr_fifo_ctl; + ipd_pwp_ptr_fifo_ctl.u64 = + cvmx_read_csr(CVMX_IPD_PWP_PTR_FIFO_CTL); + + for (i = 0; i < ipd_ptr_count.s.pkt_pcnt; i++) { + ipd_pwp_ptr_fifo_ctl.s.cena = 0; + ipd_pwp_ptr_fifo_ctl.s.raddr = + (ipd_pwp_ptr_fifo_ctl.s.praddr + + i) % ipd_pwp_ptr_fifo_ctl.s.max_cnts; + cvmx_write_csr(CVMX_IPD_PWP_PTR_FIFO_CTL, + ipd_pwp_ptr_fifo_ctl.u64); + ipd_pwp_ptr_fifo_ctl.u64 = + cvmx_read_csr(CVMX_IPD_PWP_PTR_FIFO_CTL); + cvmx_fpa_free(cvmx_phys_to_ptr + ((uint64_t) ipd_pwp_ptr_fifo_ctl. + s.ptr << 7), + CVMX_FPA_PACKET_POOL, 0); + } + ipd_pwp_ptr_fifo_ctl.s.cena = 1; + cvmx_write_csr(CVMX_IPD_PWP_PTR_FIFO_CTL, + ipd_pwp_ptr_fifo_ctl.u64); + } + + /* Reset the IPD to get all buffers out of it */ + { + union cvmx_ipd_ctl_status ipd_ctl_status; + ipd_ctl_status.u64 = cvmx_read_csr(CVMX_IPD_CTL_STATUS); + ipd_ctl_status.s.reset = 1; + cvmx_write_csr(CVMX_IPD_CTL_STATUS, ipd_ctl_status.u64); + } + + /* Reset the PIP */ + { + union cvmx_pip_sft_rst pip_sft_rst; + pip_sft_rst.u64 = cvmx_read_csr(CVMX_PIP_SFT_RST); + pip_sft_rst.s.rst = 1; + cvmx_write_csr(CVMX_PIP_SFT_RST, pip_sft_rst.u64); + } + } +} + +#endif /* __CVMX_IPD_H__ */ diff --git a/drivers/staging/octeon/cvmx-mdio.h b/drivers/staging/octeon/cvmx-mdio.h new file mode 100644 index 000000000000..c987a75a20cf --- /dev/null +++ b/drivers/staging/octeon/cvmx-mdio.h @@ -0,0 +1,506 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2008 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +/* + * + * Interface to the SMI/MDIO hardware, including support for both IEEE 802.3 + * clause 22 and clause 45 operations. + * + */ + +#ifndef __CVMX_MIO_H__ +#define __CVMX_MIO_H__ + +#include "cvmx-smix-defs.h" + +/** + * PHY register 0 from the 802.3 spec + */ +#define CVMX_MDIO_PHY_REG_CONTROL 0 +typedef union { + uint16_t u16; + struct { + uint16_t reset:1; + uint16_t loopback:1; + uint16_t speed_lsb:1; + uint16_t autoneg_enable:1; + uint16_t power_down:1; + uint16_t isolate:1; + uint16_t restart_autoneg:1; + uint16_t duplex:1; + uint16_t collision_test:1; + uint16_t speed_msb:1; + uint16_t unidirectional_enable:1; + uint16_t reserved_0_4:5; + } s; +} cvmx_mdio_phy_reg_control_t; + +/** + * PHY register 1 from the 802.3 spec + */ +#define CVMX_MDIO_PHY_REG_STATUS 1 +typedef union { + uint16_t u16; + struct { + uint16_t capable_100base_t4:1; + uint16_t capable_100base_x_full:1; + uint16_t capable_100base_x_half:1; + uint16_t capable_10_full:1; + uint16_t capable_10_half:1; + uint16_t capable_100base_t2_full:1; + uint16_t capable_100base_t2_half:1; + uint16_t capable_extended_status:1; + uint16_t capable_unidirectional:1; + uint16_t capable_mf_preamble_suppression:1; + uint16_t autoneg_complete:1; + uint16_t remote_fault:1; + uint16_t capable_autoneg:1; + uint16_t link_status:1; + uint16_t jabber_detect:1; + uint16_t capable_extended_registers:1; + + } s; +} cvmx_mdio_phy_reg_status_t; + +/** + * PHY register 2 from the 802.3 spec + */ +#define CVMX_MDIO_PHY_REG_ID1 2 +typedef union { + uint16_t u16; + struct { + uint16_t oui_bits_3_18; + } s; +} cvmx_mdio_phy_reg_id1_t; + +/** + * PHY register 3 from the 802.3 spec + */ +#define CVMX_MDIO_PHY_REG_ID2 3 +typedef union { + uint16_t u16; + struct { + uint16_t oui_bits_19_24:6; + uint16_t model:6; + uint16_t revision:4; + } s; +} cvmx_mdio_phy_reg_id2_t; + +/** + * PHY register 4 from the 802.3 spec + */ +#define CVMX_MDIO_PHY_REG_AUTONEG_ADVER 4 +typedef union { + uint16_t u16; + struct { + uint16_t next_page:1; + uint16_t reserved_14:1; + uint16_t remote_fault:1; + uint16_t reserved_12:1; + uint16_t asymmetric_pause:1; + uint16_t pause:1; + uint16_t advert_100base_t4:1; + uint16_t advert_100base_tx_full:1; + uint16_t advert_100base_tx_half:1; + uint16_t advert_10base_tx_full:1; + uint16_t advert_10base_tx_half:1; + uint16_t selector:5; + } s; +} cvmx_mdio_phy_reg_autoneg_adver_t; + +/** + * PHY register 5 from the 802.3 spec + */ +#define CVMX_MDIO_PHY_REG_LINK_PARTNER_ABILITY 5 +typedef union { + uint16_t u16; + struct { + uint16_t next_page:1; + uint16_t ack:1; + uint16_t remote_fault:1; + uint16_t reserved_12:1; + uint16_t asymmetric_pause:1; + uint16_t pause:1; + uint16_t advert_100base_t4:1; + uint16_t advert_100base_tx_full:1; + uint16_t advert_100base_tx_half:1; + uint16_t advert_10base_tx_full:1; + uint16_t advert_10base_tx_half:1; + uint16_t selector:5; + } s; +} cvmx_mdio_phy_reg_link_partner_ability_t; + +/** + * PHY register 6 from the 802.3 spec + */ +#define CVMX_MDIO_PHY_REG_AUTONEG_EXPANSION 6 +typedef union { + uint16_t u16; + struct { + uint16_t reserved_5_15:11; + uint16_t parallel_detection_fault:1; + uint16_t link_partner_next_page_capable:1; + uint16_t local_next_page_capable:1; + uint16_t page_received:1; + uint16_t link_partner_autoneg_capable:1; + + } s; +} cvmx_mdio_phy_reg_autoneg_expansion_t; + +/** + * PHY register 9 from the 802.3 spec + */ +#define CVMX_MDIO_PHY_REG_CONTROL_1000 9 +typedef union { + uint16_t u16; + struct { + uint16_t test_mode:3; + uint16_t manual_master_slave:1; + uint16_t master:1; + uint16_t port_type:1; + uint16_t advert_1000base_t_full:1; + uint16_t advert_1000base_t_half:1; + uint16_t reserved_0_7:8; + } s; +} cvmx_mdio_phy_reg_control_1000_t; + +/** + * PHY register 10 from the 802.3 spec + */ +#define CVMX_MDIO_PHY_REG_STATUS_1000 10 +typedef union { + uint16_t u16; + struct { + uint16_t master_slave_fault:1; + uint16_t is_master:1; + uint16_t local_receiver_ok:1; + uint16_t remote_receiver_ok:1; + uint16_t remote_capable_1000base_t_full:1; + uint16_t remote_capable_1000base_t_half:1; + uint16_t reserved_8_9:2; + uint16_t idle_error_count:8; + } s; +} cvmx_mdio_phy_reg_status_1000_t; + +/** + * PHY register 15 from the 802.3 spec + */ +#define CVMX_MDIO_PHY_REG_EXTENDED_STATUS 15 +typedef union { + uint16_t u16; + struct { + uint16_t capable_1000base_x_full:1; + uint16_t capable_1000base_x_half:1; + uint16_t capable_1000base_t_full:1; + uint16_t capable_1000base_t_half:1; + uint16_t reserved_0_11:12; + } s; +} cvmx_mdio_phy_reg_extended_status_t; + +/** + * PHY register 13 from the 802.3 spec + */ +#define CVMX_MDIO_PHY_REG_MMD_CONTROL 13 +typedef union { + uint16_t u16; + struct { + uint16_t function:2; + uint16_t reserved_5_13:9; + uint16_t devad:5; + } s; +} cvmx_mdio_phy_reg_mmd_control_t; + +/** + * PHY register 14 from the 802.3 spec + */ +#define CVMX_MDIO_PHY_REG_MMD_ADDRESS_DATA 14 +typedef union { + uint16_t u16; + struct { + uint16_t address_data:16; + } s; +} cvmx_mdio_phy_reg_mmd_address_data_t; + +/* Operating request encodings. */ +#define MDIO_CLAUSE_22_WRITE 0 +#define MDIO_CLAUSE_22_READ 1 + +#define MDIO_CLAUSE_45_ADDRESS 0 +#define MDIO_CLAUSE_45_WRITE 1 +#define MDIO_CLAUSE_45_READ_INC 2 +#define MDIO_CLAUSE_45_READ 3 + +/* MMD identifiers, mostly for accessing devices withing XENPAK modules. */ +#define CVMX_MMD_DEVICE_PMA_PMD 1 +#define CVMX_MMD_DEVICE_WIS 2 +#define CVMX_MMD_DEVICE_PCS 3 +#define CVMX_MMD_DEVICE_PHY_XS 4 +#define CVMX_MMD_DEVICE_DTS_XS 5 +#define CVMX_MMD_DEVICE_TC 6 +#define CVMX_MMD_DEVICE_CL22_EXT 29 +#define CVMX_MMD_DEVICE_VENDOR_1 30 +#define CVMX_MMD_DEVICE_VENDOR_2 31 + +/* Helper function to put MDIO interface into clause 45 mode */ +static inline void __cvmx_mdio_set_clause45_mode(int bus_id) +{ + union cvmx_smix_clk smi_clk; + /* Put bus into clause 45 mode */ + smi_clk.u64 = cvmx_read_csr(CVMX_SMIX_CLK(bus_id)); + smi_clk.s.mode = 1; + smi_clk.s.preamble = 1; + cvmx_write_csr(CVMX_SMIX_CLK(bus_id), smi_clk.u64); +} + +/* Helper function to put MDIO interface into clause 22 mode */ +static inline void __cvmx_mdio_set_clause22_mode(int bus_id) +{ + union cvmx_smix_clk smi_clk; + /* Put bus into clause 22 mode */ + smi_clk.u64 = cvmx_read_csr(CVMX_SMIX_CLK(bus_id)); + smi_clk.s.mode = 0; + cvmx_write_csr(CVMX_SMIX_CLK(bus_id), smi_clk.u64); +} + +/** + * Perform an MII read. This function is used to read PHY + * registers controlling auto negotiation. + * + * @bus_id: MDIO bus number. Zero on most chips, but some chips (ex CN56XX) + * support multiple busses. + * @phy_id: The MII phy id + * @location: Register location to read + * + * Returns Result from the read or -1 on failure + */ +static inline int cvmx_mdio_read(int bus_id, int phy_id, int location) +{ + union cvmx_smix_cmd smi_cmd; + union cvmx_smix_rd_dat smi_rd; + int timeout = 1000; + + if (octeon_has_feature(OCTEON_FEATURE_MDIO_CLAUSE_45)) + __cvmx_mdio_set_clause22_mode(bus_id); + + smi_cmd.u64 = 0; + smi_cmd.s.phy_op = MDIO_CLAUSE_22_READ; + smi_cmd.s.phy_adr = phy_id; + smi_cmd.s.reg_adr = location; + cvmx_write_csr(CVMX_SMIX_CMD(bus_id), smi_cmd.u64); + + do { + cvmx_wait(1000); + smi_rd.u64 = cvmx_read_csr(CVMX_SMIX_RD_DAT(bus_id)); + } while (smi_rd.s.pending && timeout--); + + if (smi_rd.s.val) + return smi_rd.s.dat; + else + return -1; +} + +/** + * Perform an MII write. This function is used to write PHY + * registers controlling auto negotiation. + * + * @bus_id: MDIO bus number. Zero on most chips, but some chips (ex CN56XX) + * support multiple busses. + * @phy_id: The MII phy id + * @location: Register location to write + * @val: Value to write + * + * Returns -1 on error + * 0 on success + */ +static inline int cvmx_mdio_write(int bus_id, int phy_id, int location, int val) +{ + union cvmx_smix_cmd smi_cmd; + union cvmx_smix_wr_dat smi_wr; + int timeout = 1000; + + if (octeon_has_feature(OCTEON_FEATURE_MDIO_CLAUSE_45)) + __cvmx_mdio_set_clause22_mode(bus_id); + + smi_wr.u64 = 0; + smi_wr.s.dat = val; + cvmx_write_csr(CVMX_SMIX_WR_DAT(bus_id), smi_wr.u64); + + smi_cmd.u64 = 0; + smi_cmd.s.phy_op = MDIO_CLAUSE_22_WRITE; + smi_cmd.s.phy_adr = phy_id; + smi_cmd.s.reg_adr = location; + cvmx_write_csr(CVMX_SMIX_CMD(bus_id), smi_cmd.u64); + + do { + cvmx_wait(1000); + smi_wr.u64 = cvmx_read_csr(CVMX_SMIX_WR_DAT(bus_id)); + } while (smi_wr.s.pending && --timeout); + if (timeout <= 0) + return -1; + + return 0; +} + +/** + * Perform an IEEE 802.3 clause 45 MII read. This function is used to + * read PHY registers controlling auto negotiation. + * + * @bus_id: MDIO bus number. Zero on most chips, but some chips (ex CN56XX) + * support multiple busses. + * @phy_id: The MII phy id + * @device: MDIO Managable Device (MMD) id + * @location: Register location to read + * + * Returns Result from the read or -1 on failure + */ + +static inline int cvmx_mdio_45_read(int bus_id, int phy_id, int device, + int location) +{ + union cvmx_smix_cmd smi_cmd; + union cvmx_smix_rd_dat smi_rd; + union cvmx_smix_wr_dat smi_wr; + int timeout = 1000; + + if (!octeon_has_feature(OCTEON_FEATURE_MDIO_CLAUSE_45)) + return -1; + + __cvmx_mdio_set_clause45_mode(bus_id); + + smi_wr.u64 = 0; + smi_wr.s.dat = location; + cvmx_write_csr(CVMX_SMIX_WR_DAT(bus_id), smi_wr.u64); + + smi_cmd.u64 = 0; + smi_cmd.s.phy_op = MDIO_CLAUSE_45_ADDRESS; + smi_cmd.s.phy_adr = phy_id; + smi_cmd.s.reg_adr = device; + cvmx_write_csr(CVMX_SMIX_CMD(bus_id), smi_cmd.u64); + + do { + cvmx_wait(1000); + smi_wr.u64 = cvmx_read_csr(CVMX_SMIX_WR_DAT(bus_id)); + } while (smi_wr.s.pending && --timeout); + if (timeout <= 0) { + cvmx_dprintf("cvmx_mdio_45_read: bus_id %d phy_id %2d " + "device %2d register %2d TIME OUT(address)\n", + bus_id, phy_id, device, location); + return -1; + } + + smi_cmd.u64 = 0; + smi_cmd.s.phy_op = MDIO_CLAUSE_45_READ; + smi_cmd.s.phy_adr = phy_id; + smi_cmd.s.reg_adr = device; + cvmx_write_csr(CVMX_SMIX_CMD(bus_id), smi_cmd.u64); + + do { + cvmx_wait(1000); + smi_rd.u64 = cvmx_read_csr(CVMX_SMIX_RD_DAT(bus_id)); + } while (smi_rd.s.pending && timeout--); + + if (timeout <= 0) { + cvmx_dprintf("cvmx_mdio_45_read: bus_id %d phy_id %2d " + "device %2d register %2d TIME OUT(data)\n", + bus_id, phy_id, device, location); + return -1; + } + + if (smi_rd.s.val) + return smi_rd.s.dat; + else { + cvmx_dprintf("cvmx_mdio_45_read: bus_id %d phy_id %2d " + "device %2d register %2d INVALID READ\n", + bus_id, phy_id, device, location); + return -1; + } +} + +/** + * Perform an IEEE 802.3 clause 45 MII write. This function is used to + * write PHY registers controlling auto negotiation. + * + * @bus_id: MDIO bus number. Zero on most chips, but some chips (ex CN56XX) + * support multiple busses. + * @phy_id: The MII phy id + * @device: MDIO Managable Device (MMD) id + * @location: Register location to write + * @val: Value to write + * + * Returns -1 on error + * 0 on success + */ +static inline int cvmx_mdio_45_write(int bus_id, int phy_id, int device, + int location, int val) +{ + union cvmx_smix_cmd smi_cmd; + union cvmx_smix_wr_dat smi_wr; + int timeout = 1000; + + if (!octeon_has_feature(OCTEON_FEATURE_MDIO_CLAUSE_45)) + return -1; + + __cvmx_mdio_set_clause45_mode(bus_id); + + smi_wr.u64 = 0; + smi_wr.s.dat = location; + cvmx_write_csr(CVMX_SMIX_WR_DAT(bus_id), smi_wr.u64); + + smi_cmd.u64 = 0; + smi_cmd.s.phy_op = MDIO_CLAUSE_45_ADDRESS; + smi_cmd.s.phy_adr = phy_id; + smi_cmd.s.reg_adr = device; + cvmx_write_csr(CVMX_SMIX_CMD(bus_id), smi_cmd.u64); + + do { + cvmx_wait(1000); + smi_wr.u64 = cvmx_read_csr(CVMX_SMIX_WR_DAT(bus_id)); + } while (smi_wr.s.pending && --timeout); + if (timeout <= 0) + return -1; + + smi_wr.u64 = 0; + smi_wr.s.dat = val; + cvmx_write_csr(CVMX_SMIX_WR_DAT(bus_id), smi_wr.u64); + + smi_cmd.u64 = 0; + smi_cmd.s.phy_op = MDIO_CLAUSE_45_WRITE; + smi_cmd.s.phy_adr = phy_id; + smi_cmd.s.reg_adr = device; + cvmx_write_csr(CVMX_SMIX_CMD(bus_id), smi_cmd.u64); + + do { + cvmx_wait(1000); + smi_wr.u64 = cvmx_read_csr(CVMX_SMIX_WR_DAT(bus_id)); + } while (smi_wr.s.pending && --timeout); + if (timeout <= 0) + return -1; + + return 0; +} + +#endif diff --git a/drivers/staging/octeon/cvmx-packet.h b/drivers/staging/octeon/cvmx-packet.h new file mode 100644 index 000000000000..62ffe78a8c81 --- /dev/null +++ b/drivers/staging/octeon/cvmx-packet.h @@ -0,0 +1,65 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2008 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +/** + * + * Packet buffer defines. + */ + +#ifndef __CVMX_PACKET_H__ +#define __CVMX_PACKET_H__ + +/** + * This structure defines a buffer pointer on Octeon + */ +union cvmx_buf_ptr { + void *ptr; + uint64_t u64; + struct { + /* + * if set, invert the "free" pick of the overall + * packet. HW always sets this bit to 0 on inbound + * packet + */ + uint64_t i:1; + /* + * Indicates the amount to back up to get to the + * buffer start in cache lines. In most cases this is + * less than one complete cache line, so the value is + * zero. + */ + uint64_t back:4; + /* The pool that the buffer came from / goes to */ + uint64_t pool:3; + /* The size of the segment pointed to by addr (in bytes) */ + uint64_t size:16; + /* Pointer to the first byte of the data, NOT buffer */ + uint64_t addr:40; + } s; +}; + +#endif /* __CVMX_PACKET_H__ */ diff --git a/drivers/staging/octeon/cvmx-pcsx-defs.h b/drivers/staging/octeon/cvmx-pcsx-defs.h new file mode 100644 index 000000000000..d45952df5f5b --- /dev/null +++ b/drivers/staging/octeon/cvmx-pcsx-defs.h @@ -0,0 +1,370 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2008 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +#ifndef __CVMX_PCSX_DEFS_H__ +#define __CVMX_PCSX_DEFS_H__ + +#define CVMX_PCSX_ANX_ADV_REG(offset, block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0001010ull + (((offset) & 3) * 1024) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_PCSX_ANX_EXT_ST_REG(offset, block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0001028ull + (((offset) & 3) * 1024) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_PCSX_ANX_LP_ABIL_REG(offset, block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0001018ull + (((offset) & 3) * 1024) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_PCSX_ANX_RESULTS_REG(offset, block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0001020ull + (((offset) & 3) * 1024) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_PCSX_INTX_EN_REG(offset, block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0001088ull + (((offset) & 3) * 1024) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_PCSX_INTX_REG(offset, block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0001080ull + (((offset) & 3) * 1024) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_PCSX_LINKX_TIMER_COUNT_REG(offset, block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0001040ull + (((offset) & 3) * 1024) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_PCSX_LOG_ANLX_REG(offset, block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0001090ull + (((offset) & 3) * 1024) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_PCSX_MISCX_CTL_REG(offset, block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0001078ull + (((offset) & 3) * 1024) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_PCSX_MRX_CONTROL_REG(offset, block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0001000ull + (((offset) & 3) * 1024) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_PCSX_MRX_STATUS_REG(offset, block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0001008ull + (((offset) & 3) * 1024) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_PCSX_RXX_STATES_REG(offset, block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0001058ull + (((offset) & 3) * 1024) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_PCSX_RXX_SYNC_REG(offset, block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0001050ull + (((offset) & 3) * 1024) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_PCSX_SGMX_AN_ADV_REG(offset, block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0001068ull + (((offset) & 3) * 1024) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_PCSX_SGMX_LP_ADV_REG(offset, block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0001070ull + (((offset) & 3) * 1024) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_PCSX_TXX_STATES_REG(offset, block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0001060ull + (((offset) & 3) * 1024) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_PCSX_TX_RXX_POLARITY_REG(offset, block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0001048ull + (((offset) & 3) * 1024) + (((block_id) & 1) * 0x8000000ull)) + +union cvmx_pcsx_anx_adv_reg { + uint64_t u64; + struct cvmx_pcsx_anx_adv_reg_s { + uint64_t reserved_16_63:48; + uint64_t np:1; + uint64_t reserved_14_14:1; + uint64_t rem_flt:2; + uint64_t reserved_9_11:3; + uint64_t pause:2; + uint64_t hfd:1; + uint64_t fd:1; + uint64_t reserved_0_4:5; + } s; + struct cvmx_pcsx_anx_adv_reg_s cn52xx; + struct cvmx_pcsx_anx_adv_reg_s cn52xxp1; + struct cvmx_pcsx_anx_adv_reg_s cn56xx; + struct cvmx_pcsx_anx_adv_reg_s cn56xxp1; +}; + +union cvmx_pcsx_anx_ext_st_reg { + uint64_t u64; + struct cvmx_pcsx_anx_ext_st_reg_s { + uint64_t reserved_16_63:48; + uint64_t thou_xfd:1; + uint64_t thou_xhd:1; + uint64_t thou_tfd:1; + uint64_t thou_thd:1; + uint64_t reserved_0_11:12; + } s; + struct cvmx_pcsx_anx_ext_st_reg_s cn52xx; + struct cvmx_pcsx_anx_ext_st_reg_s cn52xxp1; + struct cvmx_pcsx_anx_ext_st_reg_s cn56xx; + struct cvmx_pcsx_anx_ext_st_reg_s cn56xxp1; +}; + +union cvmx_pcsx_anx_lp_abil_reg { + uint64_t u64; + struct cvmx_pcsx_anx_lp_abil_reg_s { + uint64_t reserved_16_63:48; + uint64_t np:1; + uint64_t ack:1; + uint64_t rem_flt:2; + uint64_t reserved_9_11:3; + uint64_t pause:2; + uint64_t hfd:1; + uint64_t fd:1; + uint64_t reserved_0_4:5; + } s; + struct cvmx_pcsx_anx_lp_abil_reg_s cn52xx; + struct cvmx_pcsx_anx_lp_abil_reg_s cn52xxp1; + struct cvmx_pcsx_anx_lp_abil_reg_s cn56xx; + struct cvmx_pcsx_anx_lp_abil_reg_s cn56xxp1; +}; + +union cvmx_pcsx_anx_results_reg { + uint64_t u64; + struct cvmx_pcsx_anx_results_reg_s { + uint64_t reserved_7_63:57; + uint64_t pause:2; + uint64_t spd:2; + uint64_t an_cpt:1; + uint64_t dup:1; + uint64_t link_ok:1; + } s; + struct cvmx_pcsx_anx_results_reg_s cn52xx; + struct cvmx_pcsx_anx_results_reg_s cn52xxp1; + struct cvmx_pcsx_anx_results_reg_s cn56xx; + struct cvmx_pcsx_anx_results_reg_s cn56xxp1; +}; + +union cvmx_pcsx_intx_en_reg { + uint64_t u64; + struct cvmx_pcsx_intx_en_reg_s { + uint64_t reserved_12_63:52; + uint64_t dup:1; + uint64_t sync_bad_en:1; + uint64_t an_bad_en:1; + uint64_t rxlock_en:1; + uint64_t rxbad_en:1; + uint64_t rxerr_en:1; + uint64_t txbad_en:1; + uint64_t txfifo_en:1; + uint64_t txfifu_en:1; + uint64_t an_err_en:1; + uint64_t xmit_en:1; + uint64_t lnkspd_en:1; + } s; + struct cvmx_pcsx_intx_en_reg_s cn52xx; + struct cvmx_pcsx_intx_en_reg_s cn52xxp1; + struct cvmx_pcsx_intx_en_reg_s cn56xx; + struct cvmx_pcsx_intx_en_reg_s cn56xxp1; +}; + +union cvmx_pcsx_intx_reg { + uint64_t u64; + struct cvmx_pcsx_intx_reg_s { + uint64_t reserved_12_63:52; + uint64_t dup:1; + uint64_t sync_bad:1; + uint64_t an_bad:1; + uint64_t rxlock:1; + uint64_t rxbad:1; + uint64_t rxerr:1; + uint64_t txbad:1; + uint64_t txfifo:1; + uint64_t txfifu:1; + uint64_t an_err:1; + uint64_t xmit:1; + uint64_t lnkspd:1; + } s; + struct cvmx_pcsx_intx_reg_s cn52xx; + struct cvmx_pcsx_intx_reg_s cn52xxp1; + struct cvmx_pcsx_intx_reg_s cn56xx; + struct cvmx_pcsx_intx_reg_s cn56xxp1; +}; + +union cvmx_pcsx_linkx_timer_count_reg { + uint64_t u64; + struct cvmx_pcsx_linkx_timer_count_reg_s { + uint64_t reserved_16_63:48; + uint64_t count:16; + } s; + struct cvmx_pcsx_linkx_timer_count_reg_s cn52xx; + struct cvmx_pcsx_linkx_timer_count_reg_s cn52xxp1; + struct cvmx_pcsx_linkx_timer_count_reg_s cn56xx; + struct cvmx_pcsx_linkx_timer_count_reg_s cn56xxp1; +}; + +union cvmx_pcsx_log_anlx_reg { + uint64_t u64; + struct cvmx_pcsx_log_anlx_reg_s { + uint64_t reserved_4_63:60; + uint64_t lafifovfl:1; + uint64_t la_en:1; + uint64_t pkt_sz:2; + } s; + struct cvmx_pcsx_log_anlx_reg_s cn52xx; + struct cvmx_pcsx_log_anlx_reg_s cn52xxp1; + struct cvmx_pcsx_log_anlx_reg_s cn56xx; + struct cvmx_pcsx_log_anlx_reg_s cn56xxp1; +}; + +union cvmx_pcsx_miscx_ctl_reg { + uint64_t u64; + struct cvmx_pcsx_miscx_ctl_reg_s { + uint64_t reserved_13_63:51; + uint64_t sgmii:1; + uint64_t gmxeno:1; + uint64_t loopbck2:1; + uint64_t mac_phy:1; + uint64_t mode:1; + uint64_t an_ovrd:1; + uint64_t samp_pt:7; + } s; + struct cvmx_pcsx_miscx_ctl_reg_s cn52xx; + struct cvmx_pcsx_miscx_ctl_reg_s cn52xxp1; + struct cvmx_pcsx_miscx_ctl_reg_s cn56xx; + struct cvmx_pcsx_miscx_ctl_reg_s cn56xxp1; +}; + +union cvmx_pcsx_mrx_control_reg { + uint64_t u64; + struct cvmx_pcsx_mrx_control_reg_s { + uint64_t reserved_16_63:48; + uint64_t reset:1; + uint64_t loopbck1:1; + uint64_t spdlsb:1; + uint64_t an_en:1; + uint64_t pwr_dn:1; + uint64_t reserved_10_10:1; + uint64_t rst_an:1; + uint64_t dup:1; + uint64_t coltst:1; + uint64_t spdmsb:1; + uint64_t uni:1; + uint64_t reserved_0_4:5; + } s; + struct cvmx_pcsx_mrx_control_reg_s cn52xx; + struct cvmx_pcsx_mrx_control_reg_s cn52xxp1; + struct cvmx_pcsx_mrx_control_reg_s cn56xx; + struct cvmx_pcsx_mrx_control_reg_s cn56xxp1; +}; + +union cvmx_pcsx_mrx_status_reg { + uint64_t u64; + struct cvmx_pcsx_mrx_status_reg_s { + uint64_t reserved_16_63:48; + uint64_t hun_t4:1; + uint64_t hun_xfd:1; + uint64_t hun_xhd:1; + uint64_t ten_fd:1; + uint64_t ten_hd:1; + uint64_t hun_t2fd:1; + uint64_t hun_t2hd:1; + uint64_t ext_st:1; + uint64_t reserved_7_7:1; + uint64_t prb_sup:1; + uint64_t an_cpt:1; + uint64_t rm_flt:1; + uint64_t an_abil:1; + uint64_t lnk_st:1; + uint64_t reserved_1_1:1; + uint64_t extnd:1; + } s; + struct cvmx_pcsx_mrx_status_reg_s cn52xx; + struct cvmx_pcsx_mrx_status_reg_s cn52xxp1; + struct cvmx_pcsx_mrx_status_reg_s cn56xx; + struct cvmx_pcsx_mrx_status_reg_s cn56xxp1; +}; + +union cvmx_pcsx_rxx_states_reg { + uint64_t u64; + struct cvmx_pcsx_rxx_states_reg_s { + uint64_t reserved_16_63:48; + uint64_t rx_bad:1; + uint64_t rx_st:5; + uint64_t sync_bad:1; + uint64_t sync:4; + uint64_t an_bad:1; + uint64_t an_st:4; + } s; + struct cvmx_pcsx_rxx_states_reg_s cn52xx; + struct cvmx_pcsx_rxx_states_reg_s cn52xxp1; + struct cvmx_pcsx_rxx_states_reg_s cn56xx; + struct cvmx_pcsx_rxx_states_reg_s cn56xxp1; +}; + +union cvmx_pcsx_rxx_sync_reg { + uint64_t u64; + struct cvmx_pcsx_rxx_sync_reg_s { + uint64_t reserved_2_63:62; + uint64_t sync:1; + uint64_t bit_lock:1; + } s; + struct cvmx_pcsx_rxx_sync_reg_s cn52xx; + struct cvmx_pcsx_rxx_sync_reg_s cn52xxp1; + struct cvmx_pcsx_rxx_sync_reg_s cn56xx; + struct cvmx_pcsx_rxx_sync_reg_s cn56xxp1; +}; + +union cvmx_pcsx_sgmx_an_adv_reg { + uint64_t u64; + struct cvmx_pcsx_sgmx_an_adv_reg_s { + uint64_t reserved_16_63:48; + uint64_t link:1; + uint64_t ack:1; + uint64_t reserved_13_13:1; + uint64_t dup:1; + uint64_t speed:2; + uint64_t reserved_1_9:9; + uint64_t one:1; + } s; + struct cvmx_pcsx_sgmx_an_adv_reg_s cn52xx; + struct cvmx_pcsx_sgmx_an_adv_reg_s cn52xxp1; + struct cvmx_pcsx_sgmx_an_adv_reg_s cn56xx; + struct cvmx_pcsx_sgmx_an_adv_reg_s cn56xxp1; +}; + +union cvmx_pcsx_sgmx_lp_adv_reg { + uint64_t u64; + struct cvmx_pcsx_sgmx_lp_adv_reg_s { + uint64_t reserved_16_63:48; + uint64_t link:1; + uint64_t reserved_13_14:2; + uint64_t dup:1; + uint64_t speed:2; + uint64_t reserved_1_9:9; + uint64_t one:1; + } s; + struct cvmx_pcsx_sgmx_lp_adv_reg_s cn52xx; + struct cvmx_pcsx_sgmx_lp_adv_reg_s cn52xxp1; + struct cvmx_pcsx_sgmx_lp_adv_reg_s cn56xx; + struct cvmx_pcsx_sgmx_lp_adv_reg_s cn56xxp1; +}; + +union cvmx_pcsx_txx_states_reg { + uint64_t u64; + struct cvmx_pcsx_txx_states_reg_s { + uint64_t reserved_7_63:57; + uint64_t xmit:2; + uint64_t tx_bad:1; + uint64_t ord_st:4; + } s; + struct cvmx_pcsx_txx_states_reg_s cn52xx; + struct cvmx_pcsx_txx_states_reg_s cn52xxp1; + struct cvmx_pcsx_txx_states_reg_s cn56xx; + struct cvmx_pcsx_txx_states_reg_s cn56xxp1; +}; + +union cvmx_pcsx_tx_rxx_polarity_reg { + uint64_t u64; + struct cvmx_pcsx_tx_rxx_polarity_reg_s { + uint64_t reserved_4_63:60; + uint64_t rxovrd:1; + uint64_t autorxpl:1; + uint64_t rxplrt:1; + uint64_t txplrt:1; + } s; + struct cvmx_pcsx_tx_rxx_polarity_reg_s cn52xx; + struct cvmx_pcsx_tx_rxx_polarity_reg_s cn52xxp1; + struct cvmx_pcsx_tx_rxx_polarity_reg_s cn56xx; + struct cvmx_pcsx_tx_rxx_polarity_reg_s cn56xxp1; +}; + +#endif diff --git a/drivers/staging/octeon/cvmx-pcsxx-defs.h b/drivers/staging/octeon/cvmx-pcsxx-defs.h new file mode 100644 index 000000000000..55d120fe8aed --- /dev/null +++ b/drivers/staging/octeon/cvmx-pcsxx-defs.h @@ -0,0 +1,316 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2008 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +#ifndef __CVMX_PCSXX_DEFS_H__ +#define __CVMX_PCSXX_DEFS_H__ + +#define CVMX_PCSXX_10GBX_STATUS_REG(block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0000828ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_PCSXX_BIST_STATUS_REG(block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0000870ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_PCSXX_BIT_LOCK_STATUS_REG(block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0000850ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_PCSXX_CONTROL1_REG(block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0000800ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_PCSXX_CONTROL2_REG(block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0000818ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_PCSXX_INT_EN_REG(block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0000860ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_PCSXX_INT_REG(block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0000858ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_PCSXX_LOG_ANL_REG(block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0000868ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_PCSXX_MISC_CTL_REG(block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0000848ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_PCSXX_RX_SYNC_STATES_REG(block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0000838ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_PCSXX_SPD_ABIL_REG(block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0000810ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_PCSXX_STATUS1_REG(block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0000808ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_PCSXX_STATUS2_REG(block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0000820ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_PCSXX_TX_RX_POLARITY_REG(block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0000840ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_PCSXX_TX_RX_STATES_REG(block_id) \ + CVMX_ADD_IO_SEG(0x00011800B0000830ull + (((block_id) & 1) * 0x8000000ull)) + +union cvmx_pcsxx_10gbx_status_reg { + uint64_t u64; + struct cvmx_pcsxx_10gbx_status_reg_s { + uint64_t reserved_13_63:51; + uint64_t alignd:1; + uint64_t pattst:1; + uint64_t reserved_4_10:7; + uint64_t l3sync:1; + uint64_t l2sync:1; + uint64_t l1sync:1; + uint64_t l0sync:1; + } s; + struct cvmx_pcsxx_10gbx_status_reg_s cn52xx; + struct cvmx_pcsxx_10gbx_status_reg_s cn52xxp1; + struct cvmx_pcsxx_10gbx_status_reg_s cn56xx; + struct cvmx_pcsxx_10gbx_status_reg_s cn56xxp1; +}; + +union cvmx_pcsxx_bist_status_reg { + uint64_t u64; + struct cvmx_pcsxx_bist_status_reg_s { + uint64_t reserved_1_63:63; + uint64_t bist_status:1; + } s; + struct cvmx_pcsxx_bist_status_reg_s cn52xx; + struct cvmx_pcsxx_bist_status_reg_s cn52xxp1; + struct cvmx_pcsxx_bist_status_reg_s cn56xx; + struct cvmx_pcsxx_bist_status_reg_s cn56xxp1; +}; + +union cvmx_pcsxx_bit_lock_status_reg { + uint64_t u64; + struct cvmx_pcsxx_bit_lock_status_reg_s { + uint64_t reserved_4_63:60; + uint64_t bitlck3:1; + uint64_t bitlck2:1; + uint64_t bitlck1:1; + uint64_t bitlck0:1; + } s; + struct cvmx_pcsxx_bit_lock_status_reg_s cn52xx; + struct cvmx_pcsxx_bit_lock_status_reg_s cn52xxp1; + struct cvmx_pcsxx_bit_lock_status_reg_s cn56xx; + struct cvmx_pcsxx_bit_lock_status_reg_s cn56xxp1; +}; + +union cvmx_pcsxx_control1_reg { + uint64_t u64; + struct cvmx_pcsxx_control1_reg_s { + uint64_t reserved_16_63:48; + uint64_t reset:1; + uint64_t loopbck1:1; + uint64_t spdsel1:1; + uint64_t reserved_12_12:1; + uint64_t lo_pwr:1; + uint64_t reserved_7_10:4; + uint64_t spdsel0:1; + uint64_t spd:4; + uint64_t reserved_0_1:2; + } s; + struct cvmx_pcsxx_control1_reg_s cn52xx; + struct cvmx_pcsxx_control1_reg_s cn52xxp1; + struct cvmx_pcsxx_control1_reg_s cn56xx; + struct cvmx_pcsxx_control1_reg_s cn56xxp1; +}; + +union cvmx_pcsxx_control2_reg { + uint64_t u64; + struct cvmx_pcsxx_control2_reg_s { + uint64_t reserved_2_63:62; + uint64_t type:2; + } s; + struct cvmx_pcsxx_control2_reg_s cn52xx; + struct cvmx_pcsxx_control2_reg_s cn52xxp1; + struct cvmx_pcsxx_control2_reg_s cn56xx; + struct cvmx_pcsxx_control2_reg_s cn56xxp1; +}; + +union cvmx_pcsxx_int_en_reg { + uint64_t u64; + struct cvmx_pcsxx_int_en_reg_s { + uint64_t reserved_6_63:58; + uint64_t algnlos_en:1; + uint64_t synlos_en:1; + uint64_t bitlckls_en:1; + uint64_t rxsynbad_en:1; + uint64_t rxbad_en:1; + uint64_t txflt_en:1; + } s; + struct cvmx_pcsxx_int_en_reg_s cn52xx; + struct cvmx_pcsxx_int_en_reg_s cn52xxp1; + struct cvmx_pcsxx_int_en_reg_s cn56xx; + struct cvmx_pcsxx_int_en_reg_s cn56xxp1; +}; + +union cvmx_pcsxx_int_reg { + uint64_t u64; + struct cvmx_pcsxx_int_reg_s { + uint64_t reserved_6_63:58; + uint64_t algnlos:1; + uint64_t synlos:1; + uint64_t bitlckls:1; + uint64_t rxsynbad:1; + uint64_t rxbad:1; + uint64_t txflt:1; + } s; + struct cvmx_pcsxx_int_reg_s cn52xx; + struct cvmx_pcsxx_int_reg_s cn52xxp1; + struct cvmx_pcsxx_int_reg_s cn56xx; + struct cvmx_pcsxx_int_reg_s cn56xxp1; +}; + +union cvmx_pcsxx_log_anl_reg { + uint64_t u64; + struct cvmx_pcsxx_log_anl_reg_s { + uint64_t reserved_7_63:57; + uint64_t enc_mode:1; + uint64_t drop_ln:2; + uint64_t lafifovfl:1; + uint64_t la_en:1; + uint64_t pkt_sz:2; + } s; + struct cvmx_pcsxx_log_anl_reg_s cn52xx; + struct cvmx_pcsxx_log_anl_reg_s cn52xxp1; + struct cvmx_pcsxx_log_anl_reg_s cn56xx; + struct cvmx_pcsxx_log_anl_reg_s cn56xxp1; +}; + +union cvmx_pcsxx_misc_ctl_reg { + uint64_t u64; + struct cvmx_pcsxx_misc_ctl_reg_s { + uint64_t reserved_4_63:60; + uint64_t tx_swap:1; + uint64_t rx_swap:1; + uint64_t xaui:1; + uint64_t gmxeno:1; + } s; + struct cvmx_pcsxx_misc_ctl_reg_s cn52xx; + struct cvmx_pcsxx_misc_ctl_reg_s cn52xxp1; + struct cvmx_pcsxx_misc_ctl_reg_s cn56xx; + struct cvmx_pcsxx_misc_ctl_reg_s cn56xxp1; +}; + +union cvmx_pcsxx_rx_sync_states_reg { + uint64_t u64; + struct cvmx_pcsxx_rx_sync_states_reg_s { + uint64_t reserved_16_63:48; + uint64_t sync3st:4; + uint64_t sync2st:4; + uint64_t sync1st:4; + uint64_t sync0st:4; + } s; + struct cvmx_pcsxx_rx_sync_states_reg_s cn52xx; + struct cvmx_pcsxx_rx_sync_states_reg_s cn52xxp1; + struct cvmx_pcsxx_rx_sync_states_reg_s cn56xx; + struct cvmx_pcsxx_rx_sync_states_reg_s cn56xxp1; +}; + +union cvmx_pcsxx_spd_abil_reg { + uint64_t u64; + struct cvmx_pcsxx_spd_abil_reg_s { + uint64_t reserved_2_63:62; + uint64_t tenpasst:1; + uint64_t tengb:1; + } s; + struct cvmx_pcsxx_spd_abil_reg_s cn52xx; + struct cvmx_pcsxx_spd_abil_reg_s cn52xxp1; + struct cvmx_pcsxx_spd_abil_reg_s cn56xx; + struct cvmx_pcsxx_spd_abil_reg_s cn56xxp1; +}; + +union cvmx_pcsxx_status1_reg { + uint64_t u64; + struct cvmx_pcsxx_status1_reg_s { + uint64_t reserved_8_63:56; + uint64_t flt:1; + uint64_t reserved_3_6:4; + uint64_t rcv_lnk:1; + uint64_t lpable:1; + uint64_t reserved_0_0:1; + } s; + struct cvmx_pcsxx_status1_reg_s cn52xx; + struct cvmx_pcsxx_status1_reg_s cn52xxp1; + struct cvmx_pcsxx_status1_reg_s cn56xx; + struct cvmx_pcsxx_status1_reg_s cn56xxp1; +}; + +union cvmx_pcsxx_status2_reg { + uint64_t u64; + struct cvmx_pcsxx_status2_reg_s { + uint64_t reserved_16_63:48; + uint64_t dev:2; + uint64_t reserved_12_13:2; + uint64_t xmtflt:1; + uint64_t rcvflt:1; + uint64_t reserved_3_9:7; + uint64_t tengb_w:1; + uint64_t tengb_x:1; + uint64_t tengb_r:1; + } s; + struct cvmx_pcsxx_status2_reg_s cn52xx; + struct cvmx_pcsxx_status2_reg_s cn52xxp1; + struct cvmx_pcsxx_status2_reg_s cn56xx; + struct cvmx_pcsxx_status2_reg_s cn56xxp1; +}; + +union cvmx_pcsxx_tx_rx_polarity_reg { + uint64_t u64; + struct cvmx_pcsxx_tx_rx_polarity_reg_s { + uint64_t reserved_10_63:54; + uint64_t xor_rxplrt:4; + uint64_t xor_txplrt:4; + uint64_t rxplrt:1; + uint64_t txplrt:1; + } s; + struct cvmx_pcsxx_tx_rx_polarity_reg_s cn52xx; + struct cvmx_pcsxx_tx_rx_polarity_reg_cn52xxp1 { + uint64_t reserved_2_63:62; + uint64_t rxplrt:1; + uint64_t txplrt:1; + } cn52xxp1; + struct cvmx_pcsxx_tx_rx_polarity_reg_s cn56xx; + struct cvmx_pcsxx_tx_rx_polarity_reg_cn52xxp1 cn56xxp1; +}; + +union cvmx_pcsxx_tx_rx_states_reg { + uint64_t u64; + struct cvmx_pcsxx_tx_rx_states_reg_s { + uint64_t reserved_14_63:50; + uint64_t term_err:1; + uint64_t syn3bad:1; + uint64_t syn2bad:1; + uint64_t syn1bad:1; + uint64_t syn0bad:1; + uint64_t rxbad:1; + uint64_t algn_st:3; + uint64_t rx_st:2; + uint64_t tx_st:3; + } s; + struct cvmx_pcsxx_tx_rx_states_reg_s cn52xx; + struct cvmx_pcsxx_tx_rx_states_reg_cn52xxp1 { + uint64_t reserved_13_63:51; + uint64_t syn3bad:1; + uint64_t syn2bad:1; + uint64_t syn1bad:1; + uint64_t syn0bad:1; + uint64_t rxbad:1; + uint64_t algn_st:3; + uint64_t rx_st:2; + uint64_t tx_st:3; + } cn52xxp1; + struct cvmx_pcsxx_tx_rx_states_reg_s cn56xx; + struct cvmx_pcsxx_tx_rx_states_reg_cn52xxp1 cn56xxp1; +}; + +#endif diff --git a/drivers/staging/octeon/cvmx-pip-defs.h b/drivers/staging/octeon/cvmx-pip-defs.h new file mode 100644 index 000000000000..5a369100ca68 --- /dev/null +++ b/drivers/staging/octeon/cvmx-pip-defs.h @@ -0,0 +1,1267 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2008 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +#ifndef __CVMX_PIP_DEFS_H__ +#define __CVMX_PIP_DEFS_H__ + +/* + * Enumeration representing the amount of packet processing + * and validation performed by the input hardware. + */ +enum cvmx_pip_port_parse_mode { + /* + * Packet input doesn't perform any processing of the input + * packet. + */ + CVMX_PIP_PORT_CFG_MODE_NONE = 0ull, + /* + * Full packet processing is performed with pointer starting + * at the L2 (ethernet MAC) header. + */ + CVMX_PIP_PORT_CFG_MODE_SKIPL2 = 1ull, + /* + * Input packets are assumed to be IP. Results from non IP + * packets is undefined. Pointers reference the beginning of + * the IP header. + */ + CVMX_PIP_PORT_CFG_MODE_SKIPIP = 2ull +}; + +#define CVMX_PIP_BCK_PRS \ + CVMX_ADD_IO_SEG(0x00011800A0000038ull) +#define CVMX_PIP_BIST_STATUS \ + CVMX_ADD_IO_SEG(0x00011800A0000000ull) +#define CVMX_PIP_CRC_CTLX(offset) \ + CVMX_ADD_IO_SEG(0x00011800A0000040ull + (((offset) & 1) * 8)) +#define CVMX_PIP_CRC_IVX(offset) \ + CVMX_ADD_IO_SEG(0x00011800A0000050ull + (((offset) & 1) * 8)) +#define CVMX_PIP_DEC_IPSECX(offset) \ + CVMX_ADD_IO_SEG(0x00011800A0000080ull + (((offset) & 3) * 8)) +#define CVMX_PIP_DSA_SRC_GRP \ + CVMX_ADD_IO_SEG(0x00011800A0000190ull) +#define CVMX_PIP_DSA_VID_GRP \ + CVMX_ADD_IO_SEG(0x00011800A0000198ull) +#define CVMX_PIP_FRM_LEN_CHKX(offset) \ + CVMX_ADD_IO_SEG(0x00011800A0000180ull + (((offset) & 1) * 8)) +#define CVMX_PIP_GBL_CFG \ + CVMX_ADD_IO_SEG(0x00011800A0000028ull) +#define CVMX_PIP_GBL_CTL \ + CVMX_ADD_IO_SEG(0x00011800A0000020ull) +#define CVMX_PIP_HG_PRI_QOS \ + CVMX_ADD_IO_SEG(0x00011800A00001A0ull) +#define CVMX_PIP_INT_EN \ + CVMX_ADD_IO_SEG(0x00011800A0000010ull) +#define CVMX_PIP_INT_REG \ + CVMX_ADD_IO_SEG(0x00011800A0000008ull) +#define CVMX_PIP_IP_OFFSET \ + CVMX_ADD_IO_SEG(0x00011800A0000060ull) +#define CVMX_PIP_PRT_CFGX(offset) \ + CVMX_ADD_IO_SEG(0x00011800A0000200ull + (((offset) & 63) * 8)) +#define CVMX_PIP_PRT_TAGX(offset) \ + CVMX_ADD_IO_SEG(0x00011800A0000400ull + (((offset) & 63) * 8)) +#define CVMX_PIP_QOS_DIFFX(offset) \ + CVMX_ADD_IO_SEG(0x00011800A0000600ull + (((offset) & 63) * 8)) +#define CVMX_PIP_QOS_VLANX(offset) \ + CVMX_ADD_IO_SEG(0x00011800A00000C0ull + (((offset) & 7) * 8)) +#define CVMX_PIP_QOS_WATCHX(offset) \ + CVMX_ADD_IO_SEG(0x00011800A0000100ull + (((offset) & 7) * 8)) +#define CVMX_PIP_RAW_WORD \ + CVMX_ADD_IO_SEG(0x00011800A00000B0ull) +#define CVMX_PIP_SFT_RST \ + CVMX_ADD_IO_SEG(0x00011800A0000030ull) +#define CVMX_PIP_STAT0_PRTX(offset) \ + CVMX_ADD_IO_SEG(0x00011800A0000800ull + (((offset) & 63) * 80)) +#define CVMX_PIP_STAT1_PRTX(offset) \ + CVMX_ADD_IO_SEG(0x00011800A0000808ull + (((offset) & 63) * 80)) +#define CVMX_PIP_STAT2_PRTX(offset) \ + CVMX_ADD_IO_SEG(0x00011800A0000810ull + (((offset) & 63) * 80)) +#define CVMX_PIP_STAT3_PRTX(offset) \ + CVMX_ADD_IO_SEG(0x00011800A0000818ull + (((offset) & 63) * 80)) +#define CVMX_PIP_STAT4_PRTX(offset) \ + CVMX_ADD_IO_SEG(0x00011800A0000820ull + (((offset) & 63) * 80)) +#define CVMX_PIP_STAT5_PRTX(offset) \ + CVMX_ADD_IO_SEG(0x00011800A0000828ull + (((offset) & 63) * 80)) +#define CVMX_PIP_STAT6_PRTX(offset) \ + CVMX_ADD_IO_SEG(0x00011800A0000830ull + (((offset) & 63) * 80)) +#define CVMX_PIP_STAT7_PRTX(offset) \ + CVMX_ADD_IO_SEG(0x00011800A0000838ull + (((offset) & 63) * 80)) +#define CVMX_PIP_STAT8_PRTX(offset) \ + CVMX_ADD_IO_SEG(0x00011800A0000840ull + (((offset) & 63) * 80)) +#define CVMX_PIP_STAT9_PRTX(offset) \ + CVMX_ADD_IO_SEG(0x00011800A0000848ull + (((offset) & 63) * 80)) +#define CVMX_PIP_STAT_CTL \ + CVMX_ADD_IO_SEG(0x00011800A0000018ull) +#define CVMX_PIP_STAT_INB_ERRSX(offset) \ + CVMX_ADD_IO_SEG(0x00011800A0001A10ull + (((offset) & 63) * 32)) +#define CVMX_PIP_STAT_INB_OCTSX(offset) \ + CVMX_ADD_IO_SEG(0x00011800A0001A08ull + (((offset) & 63) * 32)) +#define CVMX_PIP_STAT_INB_PKTSX(offset) \ + CVMX_ADD_IO_SEG(0x00011800A0001A00ull + (((offset) & 63) * 32)) +#define CVMX_PIP_TAG_INCX(offset) \ + CVMX_ADD_IO_SEG(0x00011800A0001800ull + (((offset) & 63) * 8)) +#define CVMX_PIP_TAG_MASK \ + CVMX_ADD_IO_SEG(0x00011800A0000070ull) +#define CVMX_PIP_TAG_SECRET \ + CVMX_ADD_IO_SEG(0x00011800A0000068ull) +#define CVMX_PIP_TODO_ENTRY \ + CVMX_ADD_IO_SEG(0x00011800A0000078ull) + +union cvmx_pip_bck_prs { + uint64_t u64; + struct cvmx_pip_bck_prs_s { + uint64_t bckprs:1; + uint64_t reserved_13_62:50; + uint64_t hiwater:5; + uint64_t reserved_5_7:3; + uint64_t lowater:5; + } s; + struct cvmx_pip_bck_prs_s cn38xx; + struct cvmx_pip_bck_prs_s cn38xxp2; + struct cvmx_pip_bck_prs_s cn56xx; + struct cvmx_pip_bck_prs_s cn56xxp1; + struct cvmx_pip_bck_prs_s cn58xx; + struct cvmx_pip_bck_prs_s cn58xxp1; +}; + +union cvmx_pip_bist_status { + uint64_t u64; + struct cvmx_pip_bist_status_s { + uint64_t reserved_18_63:46; + uint64_t bist:18; + } s; + struct cvmx_pip_bist_status_s cn30xx; + struct cvmx_pip_bist_status_s cn31xx; + struct cvmx_pip_bist_status_s cn38xx; + struct cvmx_pip_bist_status_s cn38xxp2; + struct cvmx_pip_bist_status_cn50xx { + uint64_t reserved_17_63:47; + uint64_t bist:17; + } cn50xx; + struct cvmx_pip_bist_status_s cn52xx; + struct cvmx_pip_bist_status_s cn52xxp1; + struct cvmx_pip_bist_status_s cn56xx; + struct cvmx_pip_bist_status_s cn56xxp1; + struct cvmx_pip_bist_status_s cn58xx; + struct cvmx_pip_bist_status_s cn58xxp1; +}; + +union cvmx_pip_crc_ctlx { + uint64_t u64; + struct cvmx_pip_crc_ctlx_s { + uint64_t reserved_2_63:62; + uint64_t invres:1; + uint64_t reflect:1; + } s; + struct cvmx_pip_crc_ctlx_s cn38xx; + struct cvmx_pip_crc_ctlx_s cn38xxp2; + struct cvmx_pip_crc_ctlx_s cn58xx; + struct cvmx_pip_crc_ctlx_s cn58xxp1; +}; + +union cvmx_pip_crc_ivx { + uint64_t u64; + struct cvmx_pip_crc_ivx_s { + uint64_t reserved_32_63:32; + uint64_t iv:32; + } s; + struct cvmx_pip_crc_ivx_s cn38xx; + struct cvmx_pip_crc_ivx_s cn38xxp2; + struct cvmx_pip_crc_ivx_s cn58xx; + struct cvmx_pip_crc_ivx_s cn58xxp1; +}; + +union cvmx_pip_dec_ipsecx { + uint64_t u64; + struct cvmx_pip_dec_ipsecx_s { + uint64_t reserved_18_63:46; + uint64_t tcp:1; + uint64_t udp:1; + uint64_t dprt:16; + } s; + struct cvmx_pip_dec_ipsecx_s cn30xx; + struct cvmx_pip_dec_ipsecx_s cn31xx; + struct cvmx_pip_dec_ipsecx_s cn38xx; + struct cvmx_pip_dec_ipsecx_s cn38xxp2; + struct cvmx_pip_dec_ipsecx_s cn50xx; + struct cvmx_pip_dec_ipsecx_s cn52xx; + struct cvmx_pip_dec_ipsecx_s cn52xxp1; + struct cvmx_pip_dec_ipsecx_s cn56xx; + struct cvmx_pip_dec_ipsecx_s cn56xxp1; + struct cvmx_pip_dec_ipsecx_s cn58xx; + struct cvmx_pip_dec_ipsecx_s cn58xxp1; +}; + +union cvmx_pip_dsa_src_grp { + uint64_t u64; + struct cvmx_pip_dsa_src_grp_s { + uint64_t map15:4; + uint64_t map14:4; + uint64_t map13:4; + uint64_t map12:4; + uint64_t map11:4; + uint64_t map10:4; + uint64_t map9:4; + uint64_t map8:4; + uint64_t map7:4; + uint64_t map6:4; + uint64_t map5:4; + uint64_t map4:4; + uint64_t map3:4; + uint64_t map2:4; + uint64_t map1:4; + uint64_t map0:4; + } s; + struct cvmx_pip_dsa_src_grp_s cn52xx; + struct cvmx_pip_dsa_src_grp_s cn52xxp1; + struct cvmx_pip_dsa_src_grp_s cn56xx; +}; + +union cvmx_pip_dsa_vid_grp { + uint64_t u64; + struct cvmx_pip_dsa_vid_grp_s { + uint64_t map15:4; + uint64_t map14:4; + uint64_t map13:4; + uint64_t map12:4; + uint64_t map11:4; + uint64_t map10:4; + uint64_t map9:4; + uint64_t map8:4; + uint64_t map7:4; + uint64_t map6:4; + uint64_t map5:4; + uint64_t map4:4; + uint64_t map3:4; + uint64_t map2:4; + uint64_t map1:4; + uint64_t map0:4; + } s; + struct cvmx_pip_dsa_vid_grp_s cn52xx; + struct cvmx_pip_dsa_vid_grp_s cn52xxp1; + struct cvmx_pip_dsa_vid_grp_s cn56xx; +}; + +union cvmx_pip_frm_len_chkx { + uint64_t u64; + struct cvmx_pip_frm_len_chkx_s { + uint64_t reserved_32_63:32; + uint64_t maxlen:16; + uint64_t minlen:16; + } s; + struct cvmx_pip_frm_len_chkx_s cn50xx; + struct cvmx_pip_frm_len_chkx_s cn52xx; + struct cvmx_pip_frm_len_chkx_s cn52xxp1; + struct cvmx_pip_frm_len_chkx_s cn56xx; + struct cvmx_pip_frm_len_chkx_s cn56xxp1; +}; + +union cvmx_pip_gbl_cfg { + uint64_t u64; + struct cvmx_pip_gbl_cfg_s { + uint64_t reserved_19_63:45; + uint64_t tag_syn:1; + uint64_t ip6_udp:1; + uint64_t max_l2:1; + uint64_t reserved_11_15:5; + uint64_t raw_shf:3; + uint64_t reserved_3_7:5; + uint64_t nip_shf:3; + } s; + struct cvmx_pip_gbl_cfg_s cn30xx; + struct cvmx_pip_gbl_cfg_s cn31xx; + struct cvmx_pip_gbl_cfg_s cn38xx; + struct cvmx_pip_gbl_cfg_s cn38xxp2; + struct cvmx_pip_gbl_cfg_s cn50xx; + struct cvmx_pip_gbl_cfg_s cn52xx; + struct cvmx_pip_gbl_cfg_s cn52xxp1; + struct cvmx_pip_gbl_cfg_s cn56xx; + struct cvmx_pip_gbl_cfg_s cn56xxp1; + struct cvmx_pip_gbl_cfg_s cn58xx; + struct cvmx_pip_gbl_cfg_s cn58xxp1; +}; + +union cvmx_pip_gbl_ctl { + uint64_t u64; + struct cvmx_pip_gbl_ctl_s { + uint64_t reserved_27_63:37; + uint64_t dsa_grp_tvid:1; + uint64_t dsa_grp_scmd:1; + uint64_t dsa_grp_sid:1; + uint64_t reserved_21_23:3; + uint64_t ring_en:1; + uint64_t reserved_17_19:3; + uint64_t ignrs:1; + uint64_t vs_wqe:1; + uint64_t vs_qos:1; + uint64_t l2_mal:1; + uint64_t tcp_flag:1; + uint64_t l4_len:1; + uint64_t l4_chk:1; + uint64_t l4_prt:1; + uint64_t l4_mal:1; + uint64_t reserved_6_7:2; + uint64_t ip6_eext:2; + uint64_t ip4_opts:1; + uint64_t ip_hop:1; + uint64_t ip_mal:1; + uint64_t ip_chk:1; + } s; + struct cvmx_pip_gbl_ctl_cn30xx { + uint64_t reserved_17_63:47; + uint64_t ignrs:1; + uint64_t vs_wqe:1; + uint64_t vs_qos:1; + uint64_t l2_mal:1; + uint64_t tcp_flag:1; + uint64_t l4_len:1; + uint64_t l4_chk:1; + uint64_t l4_prt:1; + uint64_t l4_mal:1; + uint64_t reserved_6_7:2; + uint64_t ip6_eext:2; + uint64_t ip4_opts:1; + uint64_t ip_hop:1; + uint64_t ip_mal:1; + uint64_t ip_chk:1; + } cn30xx; + struct cvmx_pip_gbl_ctl_cn30xx cn31xx; + struct cvmx_pip_gbl_ctl_cn30xx cn38xx; + struct cvmx_pip_gbl_ctl_cn30xx cn38xxp2; + struct cvmx_pip_gbl_ctl_cn30xx cn50xx; + struct cvmx_pip_gbl_ctl_s cn52xx; + struct cvmx_pip_gbl_ctl_s cn52xxp1; + struct cvmx_pip_gbl_ctl_s cn56xx; + struct cvmx_pip_gbl_ctl_cn56xxp1 { + uint64_t reserved_21_63:43; + uint64_t ring_en:1; + uint64_t reserved_17_19:3; + uint64_t ignrs:1; + uint64_t vs_wqe:1; + uint64_t vs_qos:1; + uint64_t l2_mal:1; + uint64_t tcp_flag:1; + uint64_t l4_len:1; + uint64_t l4_chk:1; + uint64_t l4_prt:1; + uint64_t l4_mal:1; + uint64_t reserved_6_7:2; + uint64_t ip6_eext:2; + uint64_t ip4_opts:1; + uint64_t ip_hop:1; + uint64_t ip_mal:1; + uint64_t ip_chk:1; + } cn56xxp1; + struct cvmx_pip_gbl_ctl_cn30xx cn58xx; + struct cvmx_pip_gbl_ctl_cn30xx cn58xxp1; +}; + +union cvmx_pip_hg_pri_qos { + uint64_t u64; + struct cvmx_pip_hg_pri_qos_s { + uint64_t reserved_11_63:53; + uint64_t qos:3; + uint64_t reserved_6_7:2; + uint64_t pri:6; + } s; + struct cvmx_pip_hg_pri_qos_s cn52xx; + struct cvmx_pip_hg_pri_qos_s cn52xxp1; + struct cvmx_pip_hg_pri_qos_s cn56xx; +}; + +union cvmx_pip_int_en { + uint64_t u64; + struct cvmx_pip_int_en_s { + uint64_t reserved_13_63:51; + uint64_t punyerr:1; + uint64_t lenerr:1; + uint64_t maxerr:1; + uint64_t minerr:1; + uint64_t beperr:1; + uint64_t feperr:1; + uint64_t todoovr:1; + uint64_t skprunt:1; + uint64_t badtag:1; + uint64_t prtnxa:1; + uint64_t bckprs:1; + uint64_t crcerr:1; + uint64_t pktdrp:1; + } s; + struct cvmx_pip_int_en_cn30xx { + uint64_t reserved_9_63:55; + uint64_t beperr:1; + uint64_t feperr:1; + uint64_t todoovr:1; + uint64_t skprunt:1; + uint64_t badtag:1; + uint64_t prtnxa:1; + uint64_t bckprs:1; + uint64_t crcerr:1; + uint64_t pktdrp:1; + } cn30xx; + struct cvmx_pip_int_en_cn30xx cn31xx; + struct cvmx_pip_int_en_cn30xx cn38xx; + struct cvmx_pip_int_en_cn30xx cn38xxp2; + struct cvmx_pip_int_en_cn50xx { + uint64_t reserved_12_63:52; + uint64_t lenerr:1; + uint64_t maxerr:1; + uint64_t minerr:1; + uint64_t beperr:1; + uint64_t feperr:1; + uint64_t todoovr:1; + uint64_t skprunt:1; + uint64_t badtag:1; + uint64_t prtnxa:1; + uint64_t bckprs:1; + uint64_t reserved_1_1:1; + uint64_t pktdrp:1; + } cn50xx; + struct cvmx_pip_int_en_cn52xx { + uint64_t reserved_13_63:51; + uint64_t punyerr:1; + uint64_t lenerr:1; + uint64_t maxerr:1; + uint64_t minerr:1; + uint64_t beperr:1; + uint64_t feperr:1; + uint64_t todoovr:1; + uint64_t skprunt:1; + uint64_t badtag:1; + uint64_t prtnxa:1; + uint64_t bckprs:1; + uint64_t reserved_1_1:1; + uint64_t pktdrp:1; + } cn52xx; + struct cvmx_pip_int_en_cn52xx cn52xxp1; + struct cvmx_pip_int_en_s cn56xx; + struct cvmx_pip_int_en_cn56xxp1 { + uint64_t reserved_12_63:52; + uint64_t lenerr:1; + uint64_t maxerr:1; + uint64_t minerr:1; + uint64_t beperr:1; + uint64_t feperr:1; + uint64_t todoovr:1; + uint64_t skprunt:1; + uint64_t badtag:1; + uint64_t prtnxa:1; + uint64_t bckprs:1; + uint64_t crcerr:1; + uint64_t pktdrp:1; + } cn56xxp1; + struct cvmx_pip_int_en_cn58xx { + uint64_t reserved_13_63:51; + uint64_t punyerr:1; + uint64_t reserved_9_11:3; + uint64_t beperr:1; + uint64_t feperr:1; + uint64_t todoovr:1; + uint64_t skprunt:1; + uint64_t badtag:1; + uint64_t prtnxa:1; + uint64_t bckprs:1; + uint64_t crcerr:1; + uint64_t pktdrp:1; + } cn58xx; + struct cvmx_pip_int_en_cn30xx cn58xxp1; +}; + +union cvmx_pip_int_reg { + uint64_t u64; + struct cvmx_pip_int_reg_s { + uint64_t reserved_13_63:51; + uint64_t punyerr:1; + uint64_t lenerr:1; + uint64_t maxerr:1; + uint64_t minerr:1; + uint64_t beperr:1; + uint64_t feperr:1; + uint64_t todoovr:1; + uint64_t skprunt:1; + uint64_t badtag:1; + uint64_t prtnxa:1; + uint64_t bckprs:1; + uint64_t crcerr:1; + uint64_t pktdrp:1; + } s; + struct cvmx_pip_int_reg_cn30xx { + uint64_t reserved_9_63:55; + uint64_t beperr:1; + uint64_t feperr:1; + uint64_t todoovr:1; + uint64_t skprunt:1; + uint64_t badtag:1; + uint64_t prtnxa:1; + uint64_t bckprs:1; + uint64_t crcerr:1; + uint64_t pktdrp:1; + } cn30xx; + struct cvmx_pip_int_reg_cn30xx cn31xx; + struct cvmx_pip_int_reg_cn30xx cn38xx; + struct cvmx_pip_int_reg_cn30xx cn38xxp2; + struct cvmx_pip_int_reg_cn50xx { + uint64_t reserved_12_63:52; + uint64_t lenerr:1; + uint64_t maxerr:1; + uint64_t minerr:1; + uint64_t beperr:1; + uint64_t feperr:1; + uint64_t todoovr:1; + uint64_t skprunt:1; + uint64_t badtag:1; + uint64_t prtnxa:1; + uint64_t bckprs:1; + uint64_t reserved_1_1:1; + uint64_t pktdrp:1; + } cn50xx; + struct cvmx_pip_int_reg_cn52xx { + uint64_t reserved_13_63:51; + uint64_t punyerr:1; + uint64_t lenerr:1; + uint64_t maxerr:1; + uint64_t minerr:1; + uint64_t beperr:1; + uint64_t feperr:1; + uint64_t todoovr:1; + uint64_t skprunt:1; + uint64_t badtag:1; + uint64_t prtnxa:1; + uint64_t bckprs:1; + uint64_t reserved_1_1:1; + uint64_t pktdrp:1; + } cn52xx; + struct cvmx_pip_int_reg_cn52xx cn52xxp1; + struct cvmx_pip_int_reg_s cn56xx; + struct cvmx_pip_int_reg_cn56xxp1 { + uint64_t reserved_12_63:52; + uint64_t lenerr:1; + uint64_t maxerr:1; + uint64_t minerr:1; + uint64_t beperr:1; + uint64_t feperr:1; + uint64_t todoovr:1; + uint64_t skprunt:1; + uint64_t badtag:1; + uint64_t prtnxa:1; + uint64_t bckprs:1; + uint64_t crcerr:1; + uint64_t pktdrp:1; + } cn56xxp1; + struct cvmx_pip_int_reg_cn58xx { + uint64_t reserved_13_63:51; + uint64_t punyerr:1; + uint64_t reserved_9_11:3; + uint64_t beperr:1; + uint64_t feperr:1; + uint64_t todoovr:1; + uint64_t skprunt:1; + uint64_t badtag:1; + uint64_t prtnxa:1; + uint64_t bckprs:1; + uint64_t crcerr:1; + uint64_t pktdrp:1; + } cn58xx; + struct cvmx_pip_int_reg_cn30xx cn58xxp1; +}; + +union cvmx_pip_ip_offset { + uint64_t u64; + struct cvmx_pip_ip_offset_s { + uint64_t reserved_3_63:61; + uint64_t offset:3; + } s; + struct cvmx_pip_ip_offset_s cn30xx; + struct cvmx_pip_ip_offset_s cn31xx; + struct cvmx_pip_ip_offset_s cn38xx; + struct cvmx_pip_ip_offset_s cn38xxp2; + struct cvmx_pip_ip_offset_s cn50xx; + struct cvmx_pip_ip_offset_s cn52xx; + struct cvmx_pip_ip_offset_s cn52xxp1; + struct cvmx_pip_ip_offset_s cn56xx; + struct cvmx_pip_ip_offset_s cn56xxp1; + struct cvmx_pip_ip_offset_s cn58xx; + struct cvmx_pip_ip_offset_s cn58xxp1; +}; + +union cvmx_pip_prt_cfgx { + uint64_t u64; + struct cvmx_pip_prt_cfgx_s { + uint64_t reserved_53_63:11; + uint64_t pad_len:1; + uint64_t vlan_len:1; + uint64_t lenerr_en:1; + uint64_t maxerr_en:1; + uint64_t minerr_en:1; + uint64_t grp_wat_47:4; + uint64_t qos_wat_47:4; + uint64_t reserved_37_39:3; + uint64_t rawdrp:1; + uint64_t tag_inc:2; + uint64_t dyn_rs:1; + uint64_t inst_hdr:1; + uint64_t grp_wat:4; + uint64_t hg_qos:1; + uint64_t qos:3; + uint64_t qos_wat:4; + uint64_t qos_vsel:1; + uint64_t qos_vod:1; + uint64_t qos_diff:1; + uint64_t qos_vlan:1; + uint64_t reserved_13_15:3; + uint64_t crc_en:1; + uint64_t higig_en:1; + uint64_t dsa_en:1; + uint64_t mode:2; + uint64_t reserved_7_7:1; + uint64_t skip:7; + } s; + struct cvmx_pip_prt_cfgx_cn30xx { + uint64_t reserved_37_63:27; + uint64_t rawdrp:1; + uint64_t tag_inc:2; + uint64_t dyn_rs:1; + uint64_t inst_hdr:1; + uint64_t grp_wat:4; + uint64_t reserved_27_27:1; + uint64_t qos:3; + uint64_t qos_wat:4; + uint64_t reserved_18_19:2; + uint64_t qos_diff:1; + uint64_t qos_vlan:1; + uint64_t reserved_10_15:6; + uint64_t mode:2; + uint64_t reserved_7_7:1; + uint64_t skip:7; + } cn30xx; + struct cvmx_pip_prt_cfgx_cn30xx cn31xx; + struct cvmx_pip_prt_cfgx_cn38xx { + uint64_t reserved_37_63:27; + uint64_t rawdrp:1; + uint64_t tag_inc:2; + uint64_t dyn_rs:1; + uint64_t inst_hdr:1; + uint64_t grp_wat:4; + uint64_t reserved_27_27:1; + uint64_t qos:3; + uint64_t qos_wat:4; + uint64_t reserved_18_19:2; + uint64_t qos_diff:1; + uint64_t qos_vlan:1; + uint64_t reserved_13_15:3; + uint64_t crc_en:1; + uint64_t reserved_10_11:2; + uint64_t mode:2; + uint64_t reserved_7_7:1; + uint64_t skip:7; + } cn38xx; + struct cvmx_pip_prt_cfgx_cn38xx cn38xxp2; + struct cvmx_pip_prt_cfgx_cn50xx { + uint64_t reserved_53_63:11; + uint64_t pad_len:1; + uint64_t vlan_len:1; + uint64_t lenerr_en:1; + uint64_t maxerr_en:1; + uint64_t minerr_en:1; + uint64_t grp_wat_47:4; + uint64_t qos_wat_47:4; + uint64_t reserved_37_39:3; + uint64_t rawdrp:1; + uint64_t tag_inc:2; + uint64_t dyn_rs:1; + uint64_t inst_hdr:1; + uint64_t grp_wat:4; + uint64_t reserved_27_27:1; + uint64_t qos:3; + uint64_t qos_wat:4; + uint64_t reserved_19_19:1; + uint64_t qos_vod:1; + uint64_t qos_diff:1; + uint64_t qos_vlan:1; + uint64_t reserved_13_15:3; + uint64_t crc_en:1; + uint64_t reserved_10_11:2; + uint64_t mode:2; + uint64_t reserved_7_7:1; + uint64_t skip:7; + } cn50xx; + struct cvmx_pip_prt_cfgx_s cn52xx; + struct cvmx_pip_prt_cfgx_s cn52xxp1; + struct cvmx_pip_prt_cfgx_s cn56xx; + struct cvmx_pip_prt_cfgx_cn50xx cn56xxp1; + struct cvmx_pip_prt_cfgx_cn58xx { + uint64_t reserved_37_63:27; + uint64_t rawdrp:1; + uint64_t tag_inc:2; + uint64_t dyn_rs:1; + uint64_t inst_hdr:1; + uint64_t grp_wat:4; + uint64_t reserved_27_27:1; + uint64_t qos:3; + uint64_t qos_wat:4; + uint64_t reserved_19_19:1; + uint64_t qos_vod:1; + uint64_t qos_diff:1; + uint64_t qos_vlan:1; + uint64_t reserved_13_15:3; + uint64_t crc_en:1; + uint64_t reserved_10_11:2; + uint64_t mode:2; + uint64_t reserved_7_7:1; + uint64_t skip:7; + } cn58xx; + struct cvmx_pip_prt_cfgx_cn58xx cn58xxp1; +}; + +union cvmx_pip_prt_tagx { + uint64_t u64; + struct cvmx_pip_prt_tagx_s { + uint64_t reserved_40_63:24; + uint64_t grptagbase:4; + uint64_t grptagmask:4; + uint64_t grptag:1; + uint64_t grptag_mskip:1; + uint64_t tag_mode:2; + uint64_t inc_vs:2; + uint64_t inc_vlan:1; + uint64_t inc_prt_flag:1; + uint64_t ip6_dprt_flag:1; + uint64_t ip4_dprt_flag:1; + uint64_t ip6_sprt_flag:1; + uint64_t ip4_sprt_flag:1; + uint64_t ip6_nxth_flag:1; + uint64_t ip4_pctl_flag:1; + uint64_t ip6_dst_flag:1; + uint64_t ip4_dst_flag:1; + uint64_t ip6_src_flag:1; + uint64_t ip4_src_flag:1; + uint64_t tcp6_tag_type:2; + uint64_t tcp4_tag_type:2; + uint64_t ip6_tag_type:2; + uint64_t ip4_tag_type:2; + uint64_t non_tag_type:2; + uint64_t grp:4; + } s; + struct cvmx_pip_prt_tagx_cn30xx { + uint64_t reserved_40_63:24; + uint64_t grptagbase:4; + uint64_t grptagmask:4; + uint64_t grptag:1; + uint64_t reserved_30_30:1; + uint64_t tag_mode:2; + uint64_t inc_vs:2; + uint64_t inc_vlan:1; + uint64_t inc_prt_flag:1; + uint64_t ip6_dprt_flag:1; + uint64_t ip4_dprt_flag:1; + uint64_t ip6_sprt_flag:1; + uint64_t ip4_sprt_flag:1; + uint64_t ip6_nxth_flag:1; + uint64_t ip4_pctl_flag:1; + uint64_t ip6_dst_flag:1; + uint64_t ip4_dst_flag:1; + uint64_t ip6_src_flag:1; + uint64_t ip4_src_flag:1; + uint64_t tcp6_tag_type:2; + uint64_t tcp4_tag_type:2; + uint64_t ip6_tag_type:2; + uint64_t ip4_tag_type:2; + uint64_t non_tag_type:2; + uint64_t grp:4; + } cn30xx; + struct cvmx_pip_prt_tagx_cn30xx cn31xx; + struct cvmx_pip_prt_tagx_cn30xx cn38xx; + struct cvmx_pip_prt_tagx_cn30xx cn38xxp2; + struct cvmx_pip_prt_tagx_s cn50xx; + struct cvmx_pip_prt_tagx_s cn52xx; + struct cvmx_pip_prt_tagx_s cn52xxp1; + struct cvmx_pip_prt_tagx_s cn56xx; + struct cvmx_pip_prt_tagx_s cn56xxp1; + struct cvmx_pip_prt_tagx_cn30xx cn58xx; + struct cvmx_pip_prt_tagx_cn30xx cn58xxp1; +}; + +union cvmx_pip_qos_diffx { + uint64_t u64; + struct cvmx_pip_qos_diffx_s { + uint64_t reserved_3_63:61; + uint64_t qos:3; + } s; + struct cvmx_pip_qos_diffx_s cn30xx; + struct cvmx_pip_qos_diffx_s cn31xx; + struct cvmx_pip_qos_diffx_s cn38xx; + struct cvmx_pip_qos_diffx_s cn38xxp2; + struct cvmx_pip_qos_diffx_s cn50xx; + struct cvmx_pip_qos_diffx_s cn52xx; + struct cvmx_pip_qos_diffx_s cn52xxp1; + struct cvmx_pip_qos_diffx_s cn56xx; + struct cvmx_pip_qos_diffx_s cn56xxp1; + struct cvmx_pip_qos_diffx_s cn58xx; + struct cvmx_pip_qos_diffx_s cn58xxp1; +}; + +union cvmx_pip_qos_vlanx { + uint64_t u64; + struct cvmx_pip_qos_vlanx_s { + uint64_t reserved_7_63:57; + uint64_t qos1:3; + uint64_t reserved_3_3:1; + uint64_t qos:3; + } s; + struct cvmx_pip_qos_vlanx_cn30xx { + uint64_t reserved_3_63:61; + uint64_t qos:3; + } cn30xx; + struct cvmx_pip_qos_vlanx_cn30xx cn31xx; + struct cvmx_pip_qos_vlanx_cn30xx cn38xx; + struct cvmx_pip_qos_vlanx_cn30xx cn38xxp2; + struct cvmx_pip_qos_vlanx_cn30xx cn50xx; + struct cvmx_pip_qos_vlanx_s cn52xx; + struct cvmx_pip_qos_vlanx_s cn52xxp1; + struct cvmx_pip_qos_vlanx_s cn56xx; + struct cvmx_pip_qos_vlanx_cn30xx cn56xxp1; + struct cvmx_pip_qos_vlanx_cn30xx cn58xx; + struct cvmx_pip_qos_vlanx_cn30xx cn58xxp1; +}; + +union cvmx_pip_qos_watchx { + uint64_t u64; + struct cvmx_pip_qos_watchx_s { + uint64_t reserved_48_63:16; + uint64_t mask:16; + uint64_t reserved_28_31:4; + uint64_t grp:4; + uint64_t reserved_23_23:1; + uint64_t qos:3; + uint64_t reserved_19_19:1; + uint64_t match_type:3; + uint64_t match_value:16; + } s; + struct cvmx_pip_qos_watchx_cn30xx { + uint64_t reserved_48_63:16; + uint64_t mask:16; + uint64_t reserved_28_31:4; + uint64_t grp:4; + uint64_t reserved_23_23:1; + uint64_t qos:3; + uint64_t reserved_18_19:2; + uint64_t match_type:2; + uint64_t match_value:16; + } cn30xx; + struct cvmx_pip_qos_watchx_cn30xx cn31xx; + struct cvmx_pip_qos_watchx_cn30xx cn38xx; + struct cvmx_pip_qos_watchx_cn30xx cn38xxp2; + struct cvmx_pip_qos_watchx_s cn50xx; + struct cvmx_pip_qos_watchx_s cn52xx; + struct cvmx_pip_qos_watchx_s cn52xxp1; + struct cvmx_pip_qos_watchx_s cn56xx; + struct cvmx_pip_qos_watchx_s cn56xxp1; + struct cvmx_pip_qos_watchx_cn30xx cn58xx; + struct cvmx_pip_qos_watchx_cn30xx cn58xxp1; +}; + +union cvmx_pip_raw_word { + uint64_t u64; + struct cvmx_pip_raw_word_s { + uint64_t reserved_56_63:8; + uint64_t word:56; + } s; + struct cvmx_pip_raw_word_s cn30xx; + struct cvmx_pip_raw_word_s cn31xx; + struct cvmx_pip_raw_word_s cn38xx; + struct cvmx_pip_raw_word_s cn38xxp2; + struct cvmx_pip_raw_word_s cn50xx; + struct cvmx_pip_raw_word_s cn52xx; + struct cvmx_pip_raw_word_s cn52xxp1; + struct cvmx_pip_raw_word_s cn56xx; + struct cvmx_pip_raw_word_s cn56xxp1; + struct cvmx_pip_raw_word_s cn58xx; + struct cvmx_pip_raw_word_s cn58xxp1; +}; + +union cvmx_pip_sft_rst { + uint64_t u64; + struct cvmx_pip_sft_rst_s { + uint64_t reserved_1_63:63; + uint64_t rst:1; + } s; + struct cvmx_pip_sft_rst_s cn30xx; + struct cvmx_pip_sft_rst_s cn31xx; + struct cvmx_pip_sft_rst_s cn38xx; + struct cvmx_pip_sft_rst_s cn50xx; + struct cvmx_pip_sft_rst_s cn52xx; + struct cvmx_pip_sft_rst_s cn52xxp1; + struct cvmx_pip_sft_rst_s cn56xx; + struct cvmx_pip_sft_rst_s cn56xxp1; + struct cvmx_pip_sft_rst_s cn58xx; + struct cvmx_pip_sft_rst_s cn58xxp1; +}; + +union cvmx_pip_stat0_prtx { + uint64_t u64; + struct cvmx_pip_stat0_prtx_s { + uint64_t drp_pkts:32; + uint64_t drp_octs:32; + } s; + struct cvmx_pip_stat0_prtx_s cn30xx; + struct cvmx_pip_stat0_prtx_s cn31xx; + struct cvmx_pip_stat0_prtx_s cn38xx; + struct cvmx_pip_stat0_prtx_s cn38xxp2; + struct cvmx_pip_stat0_prtx_s cn50xx; + struct cvmx_pip_stat0_prtx_s cn52xx; + struct cvmx_pip_stat0_prtx_s cn52xxp1; + struct cvmx_pip_stat0_prtx_s cn56xx; + struct cvmx_pip_stat0_prtx_s cn56xxp1; + struct cvmx_pip_stat0_prtx_s cn58xx; + struct cvmx_pip_stat0_prtx_s cn58xxp1; +}; + +union cvmx_pip_stat1_prtx { + uint64_t u64; + struct cvmx_pip_stat1_prtx_s { + uint64_t reserved_48_63:16; + uint64_t octs:48; + } s; + struct cvmx_pip_stat1_prtx_s cn30xx; + struct cvmx_pip_stat1_prtx_s cn31xx; + struct cvmx_pip_stat1_prtx_s cn38xx; + struct cvmx_pip_stat1_prtx_s cn38xxp2; + struct cvmx_pip_stat1_prtx_s cn50xx; + struct cvmx_pip_stat1_prtx_s cn52xx; + struct cvmx_pip_stat1_prtx_s cn52xxp1; + struct cvmx_pip_stat1_prtx_s cn56xx; + struct cvmx_pip_stat1_prtx_s cn56xxp1; + struct cvmx_pip_stat1_prtx_s cn58xx; + struct cvmx_pip_stat1_prtx_s cn58xxp1; +}; + +union cvmx_pip_stat2_prtx { + uint64_t u64; + struct cvmx_pip_stat2_prtx_s { + uint64_t pkts:32; + uint64_t raw:32; + } s; + struct cvmx_pip_stat2_prtx_s cn30xx; + struct cvmx_pip_stat2_prtx_s cn31xx; + struct cvmx_pip_stat2_prtx_s cn38xx; + struct cvmx_pip_stat2_prtx_s cn38xxp2; + struct cvmx_pip_stat2_prtx_s cn50xx; + struct cvmx_pip_stat2_prtx_s cn52xx; + struct cvmx_pip_stat2_prtx_s cn52xxp1; + struct cvmx_pip_stat2_prtx_s cn56xx; + struct cvmx_pip_stat2_prtx_s cn56xxp1; + struct cvmx_pip_stat2_prtx_s cn58xx; + struct cvmx_pip_stat2_prtx_s cn58xxp1; +}; + +union cvmx_pip_stat3_prtx { + uint64_t u64; + struct cvmx_pip_stat3_prtx_s { + uint64_t bcst:32; + uint64_t mcst:32; + } s; + struct cvmx_pip_stat3_prtx_s cn30xx; + struct cvmx_pip_stat3_prtx_s cn31xx; + struct cvmx_pip_stat3_prtx_s cn38xx; + struct cvmx_pip_stat3_prtx_s cn38xxp2; + struct cvmx_pip_stat3_prtx_s cn50xx; + struct cvmx_pip_stat3_prtx_s cn52xx; + struct cvmx_pip_stat3_prtx_s cn52xxp1; + struct cvmx_pip_stat3_prtx_s cn56xx; + struct cvmx_pip_stat3_prtx_s cn56xxp1; + struct cvmx_pip_stat3_prtx_s cn58xx; + struct cvmx_pip_stat3_prtx_s cn58xxp1; +}; + +union cvmx_pip_stat4_prtx { + uint64_t u64; + struct cvmx_pip_stat4_prtx_s { + uint64_t h65to127:32; + uint64_t h64:32; + } s; + struct cvmx_pip_stat4_prtx_s cn30xx; + struct cvmx_pip_stat4_prtx_s cn31xx; + struct cvmx_pip_stat4_prtx_s cn38xx; + struct cvmx_pip_stat4_prtx_s cn38xxp2; + struct cvmx_pip_stat4_prtx_s cn50xx; + struct cvmx_pip_stat4_prtx_s cn52xx; + struct cvmx_pip_stat4_prtx_s cn52xxp1; + struct cvmx_pip_stat4_prtx_s cn56xx; + struct cvmx_pip_stat4_prtx_s cn56xxp1; + struct cvmx_pip_stat4_prtx_s cn58xx; + struct cvmx_pip_stat4_prtx_s cn58xxp1; +}; + +union cvmx_pip_stat5_prtx { + uint64_t u64; + struct cvmx_pip_stat5_prtx_s { + uint64_t h256to511:32; + uint64_t h128to255:32; + } s; + struct cvmx_pip_stat5_prtx_s cn30xx; + struct cvmx_pip_stat5_prtx_s cn31xx; + struct cvmx_pip_stat5_prtx_s cn38xx; + struct cvmx_pip_stat5_prtx_s cn38xxp2; + struct cvmx_pip_stat5_prtx_s cn50xx; + struct cvmx_pip_stat5_prtx_s cn52xx; + struct cvmx_pip_stat5_prtx_s cn52xxp1; + struct cvmx_pip_stat5_prtx_s cn56xx; + struct cvmx_pip_stat5_prtx_s cn56xxp1; + struct cvmx_pip_stat5_prtx_s cn58xx; + struct cvmx_pip_stat5_prtx_s cn58xxp1; +}; + +union cvmx_pip_stat6_prtx { + uint64_t u64; + struct cvmx_pip_stat6_prtx_s { + uint64_t h1024to1518:32; + uint64_t h512to1023:32; + } s; + struct cvmx_pip_stat6_prtx_s cn30xx; + struct cvmx_pip_stat6_prtx_s cn31xx; + struct cvmx_pip_stat6_prtx_s cn38xx; + struct cvmx_pip_stat6_prtx_s cn38xxp2; + struct cvmx_pip_stat6_prtx_s cn50xx; + struct cvmx_pip_stat6_prtx_s cn52xx; + struct cvmx_pip_stat6_prtx_s cn52xxp1; + struct cvmx_pip_stat6_prtx_s cn56xx; + struct cvmx_pip_stat6_prtx_s cn56xxp1; + struct cvmx_pip_stat6_prtx_s cn58xx; + struct cvmx_pip_stat6_prtx_s cn58xxp1; +}; + +union cvmx_pip_stat7_prtx { + uint64_t u64; + struct cvmx_pip_stat7_prtx_s { + uint64_t fcs:32; + uint64_t h1519:32; + } s; + struct cvmx_pip_stat7_prtx_s cn30xx; + struct cvmx_pip_stat7_prtx_s cn31xx; + struct cvmx_pip_stat7_prtx_s cn38xx; + struct cvmx_pip_stat7_prtx_s cn38xxp2; + struct cvmx_pip_stat7_prtx_s cn50xx; + struct cvmx_pip_stat7_prtx_s cn52xx; + struct cvmx_pip_stat7_prtx_s cn52xxp1; + struct cvmx_pip_stat7_prtx_s cn56xx; + struct cvmx_pip_stat7_prtx_s cn56xxp1; + struct cvmx_pip_stat7_prtx_s cn58xx; + struct cvmx_pip_stat7_prtx_s cn58xxp1; +}; + +union cvmx_pip_stat8_prtx { + uint64_t u64; + struct cvmx_pip_stat8_prtx_s { + uint64_t frag:32; + uint64_t undersz:32; + } s; + struct cvmx_pip_stat8_prtx_s cn30xx; + struct cvmx_pip_stat8_prtx_s cn31xx; + struct cvmx_pip_stat8_prtx_s cn38xx; + struct cvmx_pip_stat8_prtx_s cn38xxp2; + struct cvmx_pip_stat8_prtx_s cn50xx; + struct cvmx_pip_stat8_prtx_s cn52xx; + struct cvmx_pip_stat8_prtx_s cn52xxp1; + struct cvmx_pip_stat8_prtx_s cn56xx; + struct cvmx_pip_stat8_prtx_s cn56xxp1; + struct cvmx_pip_stat8_prtx_s cn58xx; + struct cvmx_pip_stat8_prtx_s cn58xxp1; +}; + +union cvmx_pip_stat9_prtx { + uint64_t u64; + struct cvmx_pip_stat9_prtx_s { + uint64_t jabber:32; + uint64_t oversz:32; + } s; + struct cvmx_pip_stat9_prtx_s cn30xx; + struct cvmx_pip_stat9_prtx_s cn31xx; + struct cvmx_pip_stat9_prtx_s cn38xx; + struct cvmx_pip_stat9_prtx_s cn38xxp2; + struct cvmx_pip_stat9_prtx_s cn50xx; + struct cvmx_pip_stat9_prtx_s cn52xx; + struct cvmx_pip_stat9_prtx_s cn52xxp1; + struct cvmx_pip_stat9_prtx_s cn56xx; + struct cvmx_pip_stat9_prtx_s cn56xxp1; + struct cvmx_pip_stat9_prtx_s cn58xx; + struct cvmx_pip_stat9_prtx_s cn58xxp1; +}; + +union cvmx_pip_stat_ctl { + uint64_t u64; + struct cvmx_pip_stat_ctl_s { + uint64_t reserved_1_63:63; + uint64_t rdclr:1; + } s; + struct cvmx_pip_stat_ctl_s cn30xx; + struct cvmx_pip_stat_ctl_s cn31xx; + struct cvmx_pip_stat_ctl_s cn38xx; + struct cvmx_pip_stat_ctl_s cn38xxp2; + struct cvmx_pip_stat_ctl_s cn50xx; + struct cvmx_pip_stat_ctl_s cn52xx; + struct cvmx_pip_stat_ctl_s cn52xxp1; + struct cvmx_pip_stat_ctl_s cn56xx; + struct cvmx_pip_stat_ctl_s cn56xxp1; + struct cvmx_pip_stat_ctl_s cn58xx; + struct cvmx_pip_stat_ctl_s cn58xxp1; +}; + +union cvmx_pip_stat_inb_errsx { + uint64_t u64; + struct cvmx_pip_stat_inb_errsx_s { + uint64_t reserved_16_63:48; + uint64_t errs:16; + } s; + struct cvmx_pip_stat_inb_errsx_s cn30xx; + struct cvmx_pip_stat_inb_errsx_s cn31xx; + struct cvmx_pip_stat_inb_errsx_s cn38xx; + struct cvmx_pip_stat_inb_errsx_s cn38xxp2; + struct cvmx_pip_stat_inb_errsx_s cn50xx; + struct cvmx_pip_stat_inb_errsx_s cn52xx; + struct cvmx_pip_stat_inb_errsx_s cn52xxp1; + struct cvmx_pip_stat_inb_errsx_s cn56xx; + struct cvmx_pip_stat_inb_errsx_s cn56xxp1; + struct cvmx_pip_stat_inb_errsx_s cn58xx; + struct cvmx_pip_stat_inb_errsx_s cn58xxp1; +}; + +union cvmx_pip_stat_inb_octsx { + uint64_t u64; + struct cvmx_pip_stat_inb_octsx_s { + uint64_t reserved_48_63:16; + uint64_t octs:48; + } s; + struct cvmx_pip_stat_inb_octsx_s cn30xx; + struct cvmx_pip_stat_inb_octsx_s cn31xx; + struct cvmx_pip_stat_inb_octsx_s cn38xx; + struct cvmx_pip_stat_inb_octsx_s cn38xxp2; + struct cvmx_pip_stat_inb_octsx_s cn50xx; + struct cvmx_pip_stat_inb_octsx_s cn52xx; + struct cvmx_pip_stat_inb_octsx_s cn52xxp1; + struct cvmx_pip_stat_inb_octsx_s cn56xx; + struct cvmx_pip_stat_inb_octsx_s cn56xxp1; + struct cvmx_pip_stat_inb_octsx_s cn58xx; + struct cvmx_pip_stat_inb_octsx_s cn58xxp1; +}; + +union cvmx_pip_stat_inb_pktsx { + uint64_t u64; + struct cvmx_pip_stat_inb_pktsx_s { + uint64_t reserved_32_63:32; + uint64_t pkts:32; + } s; + struct cvmx_pip_stat_inb_pktsx_s cn30xx; + struct cvmx_pip_stat_inb_pktsx_s cn31xx; + struct cvmx_pip_stat_inb_pktsx_s cn38xx; + struct cvmx_pip_stat_inb_pktsx_s cn38xxp2; + struct cvmx_pip_stat_inb_pktsx_s cn50xx; + struct cvmx_pip_stat_inb_pktsx_s cn52xx; + struct cvmx_pip_stat_inb_pktsx_s cn52xxp1; + struct cvmx_pip_stat_inb_pktsx_s cn56xx; + struct cvmx_pip_stat_inb_pktsx_s cn56xxp1; + struct cvmx_pip_stat_inb_pktsx_s cn58xx; + struct cvmx_pip_stat_inb_pktsx_s cn58xxp1; +}; + +union cvmx_pip_tag_incx { + uint64_t u64; + struct cvmx_pip_tag_incx_s { + uint64_t reserved_8_63:56; + uint64_t en:8; + } s; + struct cvmx_pip_tag_incx_s cn30xx; + struct cvmx_pip_tag_incx_s cn31xx; + struct cvmx_pip_tag_incx_s cn38xx; + struct cvmx_pip_tag_incx_s cn38xxp2; + struct cvmx_pip_tag_incx_s cn50xx; + struct cvmx_pip_tag_incx_s cn52xx; + struct cvmx_pip_tag_incx_s cn52xxp1; + struct cvmx_pip_tag_incx_s cn56xx; + struct cvmx_pip_tag_incx_s cn56xxp1; + struct cvmx_pip_tag_incx_s cn58xx; + struct cvmx_pip_tag_incx_s cn58xxp1; +}; + +union cvmx_pip_tag_mask { + uint64_t u64; + struct cvmx_pip_tag_mask_s { + uint64_t reserved_16_63:48; + uint64_t mask:16; + } s; + struct cvmx_pip_tag_mask_s cn30xx; + struct cvmx_pip_tag_mask_s cn31xx; + struct cvmx_pip_tag_mask_s cn38xx; + struct cvmx_pip_tag_mask_s cn38xxp2; + struct cvmx_pip_tag_mask_s cn50xx; + struct cvmx_pip_tag_mask_s cn52xx; + struct cvmx_pip_tag_mask_s cn52xxp1; + struct cvmx_pip_tag_mask_s cn56xx; + struct cvmx_pip_tag_mask_s cn56xxp1; + struct cvmx_pip_tag_mask_s cn58xx; + struct cvmx_pip_tag_mask_s cn58xxp1; +}; + +union cvmx_pip_tag_secret { + uint64_t u64; + struct cvmx_pip_tag_secret_s { + uint64_t reserved_32_63:32; + uint64_t dst:16; + uint64_t src:16; + } s; + struct cvmx_pip_tag_secret_s cn30xx; + struct cvmx_pip_tag_secret_s cn31xx; + struct cvmx_pip_tag_secret_s cn38xx; + struct cvmx_pip_tag_secret_s cn38xxp2; + struct cvmx_pip_tag_secret_s cn50xx; + struct cvmx_pip_tag_secret_s cn52xx; + struct cvmx_pip_tag_secret_s cn52xxp1; + struct cvmx_pip_tag_secret_s cn56xx; + struct cvmx_pip_tag_secret_s cn56xxp1; + struct cvmx_pip_tag_secret_s cn58xx; + struct cvmx_pip_tag_secret_s cn58xxp1; +}; + +union cvmx_pip_todo_entry { + uint64_t u64; + struct cvmx_pip_todo_entry_s { + uint64_t val:1; + uint64_t reserved_62_62:1; + uint64_t entry:62; + } s; + struct cvmx_pip_todo_entry_s cn30xx; + struct cvmx_pip_todo_entry_s cn31xx; + struct cvmx_pip_todo_entry_s cn38xx; + struct cvmx_pip_todo_entry_s cn38xxp2; + struct cvmx_pip_todo_entry_s cn50xx; + struct cvmx_pip_todo_entry_s cn52xx; + struct cvmx_pip_todo_entry_s cn52xxp1; + struct cvmx_pip_todo_entry_s cn56xx; + struct cvmx_pip_todo_entry_s cn56xxp1; + struct cvmx_pip_todo_entry_s cn58xx; + struct cvmx_pip_todo_entry_s cn58xxp1; +}; + +#endif diff --git a/drivers/staging/octeon/cvmx-pip.h b/drivers/staging/octeon/cvmx-pip.h new file mode 100644 index 000000000000..78dbce8f2c5e --- /dev/null +++ b/drivers/staging/octeon/cvmx-pip.h @@ -0,0 +1,524 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2008 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +/* + * Interface to the hardware Packet Input Processing unit. + * + */ + +#ifndef __CVMX_PIP_H__ +#define __CVMX_PIP_H__ + +#include "cvmx-wqe.h" +#include "cvmx-fpa.h" +#include "cvmx-pip-defs.h" + +#define CVMX_PIP_NUM_INPUT_PORTS 40 +#define CVMX_PIP_NUM_WATCHERS 4 + +/* + * Encodes the different error and exception codes + */ +typedef enum { + CVMX_PIP_L4_NO_ERR = 0ull, + /* + * 1 = TCP (UDP) packet not long enough to cover TCP (UDP) + * header + */ + CVMX_PIP_L4_MAL_ERR = 1ull, + /* 2 = TCP/UDP checksum failure */ + CVMX_PIP_CHK_ERR = 2ull, + /* + * 3 = TCP/UDP length check (TCP/UDP length does not match IP + * length). + */ + CVMX_PIP_L4_LENGTH_ERR = 3ull, + /* 4 = illegal TCP/UDP port (either source or dest port is zero) */ + CVMX_PIP_BAD_PRT_ERR = 4ull, + /* 8 = TCP flags = FIN only */ + CVMX_PIP_TCP_FLG8_ERR = 8ull, + /* 9 = TCP flags = 0 */ + CVMX_PIP_TCP_FLG9_ERR = 9ull, + /* 10 = TCP flags = FIN+RST+* */ + CVMX_PIP_TCP_FLG10_ERR = 10ull, + /* 11 = TCP flags = SYN+URG+* */ + CVMX_PIP_TCP_FLG11_ERR = 11ull, + /* 12 = TCP flags = SYN+RST+* */ + CVMX_PIP_TCP_FLG12_ERR = 12ull, + /* 13 = TCP flags = SYN+FIN+* */ + CVMX_PIP_TCP_FLG13_ERR = 13ull +} cvmx_pip_l4_err_t; + +typedef enum { + + CVMX_PIP_IP_NO_ERR = 0ull, + /* 1 = not IPv4 or IPv6 */ + CVMX_PIP_NOT_IP = 1ull, + /* 2 = IPv4 header checksum violation */ + CVMX_PIP_IPV4_HDR_CHK = 2ull, + /* 3 = malformed (packet not long enough to cover IP hdr) */ + CVMX_PIP_IP_MAL_HDR = 3ull, + /* 4 = malformed (packet not long enough to cover len in IP hdr) */ + CVMX_PIP_IP_MAL_PKT = 4ull, + /* 5 = TTL / hop count equal zero */ + CVMX_PIP_TTL_HOP = 5ull, + /* 6 = IPv4 options / IPv6 early extension headers */ + CVMX_PIP_OPTS = 6ull +} cvmx_pip_ip_exc_t; + +/** + * NOTES + * late collision (data received before collision) + * late collisions cannot be detected by the receiver + * they would appear as JAM bits which would appear as bad FCS + * or carrier extend error which is CVMX_PIP_EXTEND_ERR + */ +typedef enum { + /* No error */ + CVMX_PIP_RX_NO_ERR = 0ull, + /* RGM+SPI 1 = partially received packet (buffering/bandwidth + * not adequate) */ + CVMX_PIP_PARTIAL_ERR = 1ull, + /* RGM+SPI 2 = receive packet too large and truncated */ + CVMX_PIP_JABBER_ERR = 2ull, + /* + * RGM 3 = max frame error (pkt len > max frame len) (with FCS + * error) + */ + CVMX_PIP_OVER_FCS_ERR = 3ull, + /* RGM+SPI 4 = max frame error (pkt len > max frame len) */ + CVMX_PIP_OVER_ERR = 4ull, + /* + * RGM 5 = nibble error (data not byte multiple - 100M and 10M + * only) + */ + CVMX_PIP_ALIGN_ERR = 5ull, + /* + * RGM 6 = min frame error (pkt len < min frame len) (with FCS + * error) + */ + CVMX_PIP_UNDER_FCS_ERR = 6ull, + /* RGM 7 = FCS error */ + CVMX_PIP_GMX_FCS_ERR = 7ull, + /* RGM+SPI 8 = min frame error (pkt len < min frame len) */ + CVMX_PIP_UNDER_ERR = 8ull, + /* RGM 9 = Frame carrier extend error */ + CVMX_PIP_EXTEND_ERR = 9ull, + /* + * RGM 10 = length mismatch (len did not match len in L2 + * length/type) + */ + CVMX_PIP_LENGTH_ERR = 10ull, + /* RGM 11 = Frame error (some or all data bits marked err) */ + CVMX_PIP_DAT_ERR = 11ull, + /* SPI 11 = DIP4 error */ + CVMX_PIP_DIP_ERR = 11ull, + /* + * RGM 12 = packet was not large enough to pass the skipper - + * no inspection could occur. + */ + CVMX_PIP_SKIP_ERR = 12ull, + /* + * RGM 13 = studder error (data not repeated - 100M and 10M + * only) + */ + CVMX_PIP_NIBBLE_ERR = 13ull, + /* RGM+SPI 16 = FCS error */ + CVMX_PIP_PIP_FCS = 16L, + /* + * RGM+SPI+PCI 17 = packet was not large enough to pass the + * skipper - no inspection could occur. + */ + CVMX_PIP_PIP_SKIP_ERR = 17L, + /* + * RGM+SPI+PCI 18 = malformed l2 (packet not long enough to + * cover L2 hdr). + */ + CVMX_PIP_PIP_L2_MAL_HDR = 18L + /* + * NOTES: xx = late collision (data received before collision) + * late collisions cannot be detected by the receiver + * they would appear as JAM bits which would appear as + * bad FCS or carrier extend error which is + * CVMX_PIP_EXTEND_ERR + */ +} cvmx_pip_rcv_err_t; + +/** + * This defines the err_code field errors in the work Q entry + */ +typedef union { + cvmx_pip_l4_err_t l4_err; + cvmx_pip_ip_exc_t ip_exc; + cvmx_pip_rcv_err_t rcv_err; +} cvmx_pip_err_t; + +/** + * Status statistics for a port + */ +typedef struct { + /* Inbound octets marked to be dropped by the IPD */ + uint32_t dropped_octets; + /* Inbound packets marked to be dropped by the IPD */ + uint32_t dropped_packets; + /* RAW PCI Packets received by PIP per port */ + uint32_t pci_raw_packets; + /* Number of octets processed by PIP */ + uint32_t octets; + /* Number of packets processed by PIP */ + uint32_t packets; + /* + * Number of indentified L2 multicast packets. Does not + * include broadcast packets. Only includes packets whose + * parse mode is SKIP_TO_L2 + */ + uint32_t multicast_packets; + /* + * Number of indentified L2 broadcast packets. Does not + * include multicast packets. Only includes packets whose + * parse mode is SKIP_TO_L2 + */ + uint32_t broadcast_packets; + /* Number of 64B packets */ + uint32_t len_64_packets; + /* Number of 65-127B packets */ + uint32_t len_65_127_packets; + /* Number of 128-255B packets */ + uint32_t len_128_255_packets; + /* Number of 256-511B packets */ + uint32_t len_256_511_packets; + /* Number of 512-1023B packets */ + uint32_t len_512_1023_packets; + /* Number of 1024-1518B packets */ + uint32_t len_1024_1518_packets; + /* Number of 1519-max packets */ + uint32_t len_1519_max_packets; + /* Number of packets with FCS or Align opcode errors */ + uint32_t fcs_align_err_packets; + /* Number of packets with length < min */ + uint32_t runt_packets; + /* Number of packets with length < min and FCS error */ + uint32_t runt_crc_packets; + /* Number of packets with length > max */ + uint32_t oversize_packets; + /* Number of packets with length > max and FCS error */ + uint32_t oversize_crc_packets; + /* Number of packets without GMX/SPX/PCI errors received by PIP */ + uint32_t inb_packets; + /* + * Total number of octets from all packets received by PIP, + * including CRC + */ + uint64_t inb_octets; + /* Number of packets with GMX/SPX/PCI errors received by PIP */ + uint16_t inb_errors; +} cvmx_pip_port_status_t; + +/** + * Definition of the PIP custom header that can be prepended + * to a packet by external hardware. + */ +typedef union { + uint64_t u64; + struct { + /* + * Documented as R - Set if the Packet is RAWFULL. If + * set, this header must be the full 8 bytes. + */ + uint64_t rawfull:1; + /* Must be zero */ + uint64_t reserved0:5; + /* PIP parse mode for this packet */ + uint64_t parse_mode:2; + /* Must be zero */ + uint64_t reserved1:1; + /* + * Skip amount, including this header, to the + * beginning of the packet + */ + uint64_t skip_len:7; + /* Must be zero */ + uint64_t reserved2:6; + /* POW input queue for this packet */ + uint64_t qos:3; + /* POW input group for this packet */ + uint64_t grp:4; + /* + * Flag to store this packet in the work queue entry, + * if possible + */ + uint64_t rs:1; + /* POW input tag type */ + uint64_t tag_type:2; + /* POW input tag */ + uint64_t tag:32; + } s; +} cvmx_pip_pkt_inst_hdr_t; + +/* CSR typedefs have been moved to cvmx-csr-*.h */ + +/** + * Configure an ethernet input port + * + * @port_num: Port number to configure + * @port_cfg: Port hardware configuration + * @port_tag_cfg: + * Port POW tagging configuration + */ +static inline void cvmx_pip_config_port(uint64_t port_num, + union cvmx_pip_prt_cfgx port_cfg, + union cvmx_pip_prt_tagx port_tag_cfg) +{ + cvmx_write_csr(CVMX_PIP_PRT_CFGX(port_num), port_cfg.u64); + cvmx_write_csr(CVMX_PIP_PRT_TAGX(port_num), port_tag_cfg.u64); +} +#if 0 +/** + * @deprecated This function is a thin wrapper around the Pass1 version + * of the CVMX_PIP_QOS_WATCHX CSR; Pass2 has added a field for + * setting the group that is incompatible with this function, + * the preferred upgrade path is to use the CSR directly. + * + * Configure the global QoS packet watchers. Each watcher is + * capable of matching a field in a packet to determine the + * QoS queue for scheduling. + * + * @watcher: Watcher number to configure (0 - 3). + * @match_type: Watcher match type + * @match_value: + * Value the watcher will match against + * @qos: QoS queue for packets matching this watcher + */ +static inline void cvmx_pip_config_watcher(uint64_t watcher, + cvmx_pip_qos_watch_types match_type, + uint64_t match_value, uint64_t qos) +{ + cvmx_pip_port_watcher_cfg_t watcher_config; + + watcher_config.u64 = 0; + watcher_config.s.match_type = match_type; + watcher_config.s.match_value = match_value; + watcher_config.s.qos = qos; + + cvmx_write_csr(CVMX_PIP_QOS_WATCHX(watcher), watcher_config.u64); +} +#endif +/** + * Configure the VLAN priority to QoS queue mapping. + * + * @vlan_priority: + * VLAN priority (0-7) + * @qos: QoS queue for packets matching this watcher + */ +static inline void cvmx_pip_config_vlan_qos(uint64_t vlan_priority, + uint64_t qos) +{ + union cvmx_pip_qos_vlanx pip_qos_vlanx; + pip_qos_vlanx.u64 = 0; + pip_qos_vlanx.s.qos = qos; + cvmx_write_csr(CVMX_PIP_QOS_VLANX(vlan_priority), pip_qos_vlanx.u64); +} + +/** + * Configure the Diffserv to QoS queue mapping. + * + * @diffserv: Diffserv field value (0-63) + * @qos: QoS queue for packets matching this watcher + */ +static inline void cvmx_pip_config_diffserv_qos(uint64_t diffserv, uint64_t qos) +{ + union cvmx_pip_qos_diffx pip_qos_diffx; + pip_qos_diffx.u64 = 0; + pip_qos_diffx.s.qos = qos; + cvmx_write_csr(CVMX_PIP_QOS_DIFFX(diffserv), pip_qos_diffx.u64); +} + +/** + * Get the status counters for a port. + * + * @port_num: Port number to get statistics for. + * @clear: Set to 1 to clear the counters after they are read + * @status: Where to put the results. + */ +static inline void cvmx_pip_get_port_status(uint64_t port_num, uint64_t clear, + cvmx_pip_port_status_t *status) +{ + union cvmx_pip_stat_ctl pip_stat_ctl; + union cvmx_pip_stat0_prtx stat0; + union cvmx_pip_stat1_prtx stat1; + union cvmx_pip_stat2_prtx stat2; + union cvmx_pip_stat3_prtx stat3; + union cvmx_pip_stat4_prtx stat4; + union cvmx_pip_stat5_prtx stat5; + union cvmx_pip_stat6_prtx stat6; + union cvmx_pip_stat7_prtx stat7; + union cvmx_pip_stat8_prtx stat8; + union cvmx_pip_stat9_prtx stat9; + union cvmx_pip_stat_inb_pktsx pip_stat_inb_pktsx; + union cvmx_pip_stat_inb_octsx pip_stat_inb_octsx; + union cvmx_pip_stat_inb_errsx pip_stat_inb_errsx; + + pip_stat_ctl.u64 = 0; + pip_stat_ctl.s.rdclr = clear; + cvmx_write_csr(CVMX_PIP_STAT_CTL, pip_stat_ctl.u64); + + stat0.u64 = cvmx_read_csr(CVMX_PIP_STAT0_PRTX(port_num)); + stat1.u64 = cvmx_read_csr(CVMX_PIP_STAT1_PRTX(port_num)); + stat2.u64 = cvmx_read_csr(CVMX_PIP_STAT2_PRTX(port_num)); + stat3.u64 = cvmx_read_csr(CVMX_PIP_STAT3_PRTX(port_num)); + stat4.u64 = cvmx_read_csr(CVMX_PIP_STAT4_PRTX(port_num)); + stat5.u64 = cvmx_read_csr(CVMX_PIP_STAT5_PRTX(port_num)); + stat6.u64 = cvmx_read_csr(CVMX_PIP_STAT6_PRTX(port_num)); + stat7.u64 = cvmx_read_csr(CVMX_PIP_STAT7_PRTX(port_num)); + stat8.u64 = cvmx_read_csr(CVMX_PIP_STAT8_PRTX(port_num)); + stat9.u64 = cvmx_read_csr(CVMX_PIP_STAT9_PRTX(port_num)); + pip_stat_inb_pktsx.u64 = + cvmx_read_csr(CVMX_PIP_STAT_INB_PKTSX(port_num)); + pip_stat_inb_octsx.u64 = + cvmx_read_csr(CVMX_PIP_STAT_INB_OCTSX(port_num)); + pip_stat_inb_errsx.u64 = + cvmx_read_csr(CVMX_PIP_STAT_INB_ERRSX(port_num)); + + status->dropped_octets = stat0.s.drp_octs; + status->dropped_packets = stat0.s.drp_pkts; + status->octets = stat1.s.octs; + status->pci_raw_packets = stat2.s.raw; + status->packets = stat2.s.pkts; + status->multicast_packets = stat3.s.mcst; + status->broadcast_packets = stat3.s.bcst; + status->len_64_packets = stat4.s.h64; + status->len_65_127_packets = stat4.s.h65to127; + status->len_128_255_packets = stat5.s.h128to255; + status->len_256_511_packets = stat5.s.h256to511; + status->len_512_1023_packets = stat6.s.h512to1023; + status->len_1024_1518_packets = stat6.s.h1024to1518; + status->len_1519_max_packets = stat7.s.h1519; + status->fcs_align_err_packets = stat7.s.fcs; + status->runt_packets = stat8.s.undersz; + status->runt_crc_packets = stat8.s.frag; + status->oversize_packets = stat9.s.oversz; + status->oversize_crc_packets = stat9.s.jabber; + status->inb_packets = pip_stat_inb_pktsx.s.pkts; + status->inb_octets = pip_stat_inb_octsx.s.octs; + status->inb_errors = pip_stat_inb_errsx.s.errs; + + if (cvmx_octeon_is_pass1()) { + /* + * Kludge to fix Octeon Pass 1 errata - Drop counts + * don't work. + */ + if (status->inb_packets > status->packets) + status->dropped_packets = + status->inb_packets - status->packets; + else + status->dropped_packets = 0; + if (status->inb_octets - status->inb_packets * 4 > + status->octets) + status->dropped_octets = + status->inb_octets - status->inb_packets * 4 - + status->octets; + else + status->dropped_octets = 0; + } +} + +/** + * Configure the hardware CRC engine + * + * @interface: Interface to configure (0 or 1) + * @invert_result: + * Invert the result of the CRC + * @reflect: Reflect + * @initialization_vector: + * CRC initialization vector + */ +static inline void cvmx_pip_config_crc(uint64_t interface, + uint64_t invert_result, uint64_t reflect, + uint32_t initialization_vector) +{ + if (OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX)) { + union cvmx_pip_crc_ctlx config; + union cvmx_pip_crc_ivx pip_crc_ivx; + + config.u64 = 0; + config.s.invres = invert_result; + config.s.reflect = reflect; + cvmx_write_csr(CVMX_PIP_CRC_CTLX(interface), config.u64); + + pip_crc_ivx.u64 = 0; + pip_crc_ivx.s.iv = initialization_vector; + cvmx_write_csr(CVMX_PIP_CRC_IVX(interface), pip_crc_ivx.u64); + } +} + +/** + * Clear all bits in a tag mask. This should be called on + * startup before any calls to cvmx_pip_tag_mask_set. Each bit + * set in the final mask represent a byte used in the packet for + * tag generation. + * + * @mask_index: Which tag mask to clear (0..3) + */ +static inline void cvmx_pip_tag_mask_clear(uint64_t mask_index) +{ + uint64_t index; + union cvmx_pip_tag_incx pip_tag_incx; + pip_tag_incx.u64 = 0; + pip_tag_incx.s.en = 0; + for (index = mask_index * 16; index < (mask_index + 1) * 16; index++) + cvmx_write_csr(CVMX_PIP_TAG_INCX(index), pip_tag_incx.u64); +} + +/** + * Sets a range of bits in the tag mask. The tag mask is used + * when the cvmx_pip_port_tag_cfg_t tag_mode is non zero. + * There are four separate masks that can be configured. + * + * @mask_index: Which tag mask to modify (0..3) + * @offset: Offset into the bitmask to set bits at. Use the GCC macro + * offsetof() to determine the offsets into packet headers. + * For example, offsetof(ethhdr, protocol) returns the offset + * of the ethernet protocol field. The bitmask selects which + * bytes to include the the tag, with bit offset X selecting + * byte at offset X from the beginning of the packet data. + * @len: Number of bytes to include. Usually this is the sizeof() + * the field. + */ +static inline void cvmx_pip_tag_mask_set(uint64_t mask_index, uint64_t offset, + uint64_t len) +{ + while (len--) { + union cvmx_pip_tag_incx pip_tag_incx; + uint64_t index = mask_index * 16 + offset / 8; + pip_tag_incx.u64 = cvmx_read_csr(CVMX_PIP_TAG_INCX(index)); + pip_tag_incx.s.en |= 0x80 >> (offset & 0x7); + cvmx_write_csr(CVMX_PIP_TAG_INCX(index), pip_tag_incx.u64); + offset++; + } +} + +#endif /* __CVMX_PIP_H__ */ diff --git a/drivers/staging/octeon/cvmx-pko-defs.h b/drivers/staging/octeon/cvmx-pko-defs.h new file mode 100644 index 000000000000..50e779cf1ad8 --- /dev/null +++ b/drivers/staging/octeon/cvmx-pko-defs.h @@ -0,0 +1,1133 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2008 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +#ifndef __CVMX_PKO_DEFS_H__ +#define __CVMX_PKO_DEFS_H__ + +#define CVMX_PKO_MEM_COUNT0 \ + CVMX_ADD_IO_SEG(0x0001180050001080ull) +#define CVMX_PKO_MEM_COUNT1 \ + CVMX_ADD_IO_SEG(0x0001180050001088ull) +#define CVMX_PKO_MEM_DEBUG0 \ + CVMX_ADD_IO_SEG(0x0001180050001100ull) +#define CVMX_PKO_MEM_DEBUG1 \ + CVMX_ADD_IO_SEG(0x0001180050001108ull) +#define CVMX_PKO_MEM_DEBUG10 \ + CVMX_ADD_IO_SEG(0x0001180050001150ull) +#define CVMX_PKO_MEM_DEBUG11 \ + CVMX_ADD_IO_SEG(0x0001180050001158ull) +#define CVMX_PKO_MEM_DEBUG12 \ + CVMX_ADD_IO_SEG(0x0001180050001160ull) +#define CVMX_PKO_MEM_DEBUG13 \ + CVMX_ADD_IO_SEG(0x0001180050001168ull) +#define CVMX_PKO_MEM_DEBUG14 \ + CVMX_ADD_IO_SEG(0x0001180050001170ull) +#define CVMX_PKO_MEM_DEBUG2 \ + CVMX_ADD_IO_SEG(0x0001180050001110ull) +#define CVMX_PKO_MEM_DEBUG3 \ + CVMX_ADD_IO_SEG(0x0001180050001118ull) +#define CVMX_PKO_MEM_DEBUG4 \ + CVMX_ADD_IO_SEG(0x0001180050001120ull) +#define CVMX_PKO_MEM_DEBUG5 \ + CVMX_ADD_IO_SEG(0x0001180050001128ull) +#define CVMX_PKO_MEM_DEBUG6 \ + CVMX_ADD_IO_SEG(0x0001180050001130ull) +#define CVMX_PKO_MEM_DEBUG7 \ + CVMX_ADD_IO_SEG(0x0001180050001138ull) +#define CVMX_PKO_MEM_DEBUG8 \ + CVMX_ADD_IO_SEG(0x0001180050001140ull) +#define CVMX_PKO_MEM_DEBUG9 \ + CVMX_ADD_IO_SEG(0x0001180050001148ull) +#define CVMX_PKO_MEM_PORT_PTRS \ + CVMX_ADD_IO_SEG(0x0001180050001010ull) +#define CVMX_PKO_MEM_PORT_QOS \ + CVMX_ADD_IO_SEG(0x0001180050001018ull) +#define CVMX_PKO_MEM_PORT_RATE0 \ + CVMX_ADD_IO_SEG(0x0001180050001020ull) +#define CVMX_PKO_MEM_PORT_RATE1 \ + CVMX_ADD_IO_SEG(0x0001180050001028ull) +#define CVMX_PKO_MEM_QUEUE_PTRS \ + CVMX_ADD_IO_SEG(0x0001180050001000ull) +#define CVMX_PKO_MEM_QUEUE_QOS \ + CVMX_ADD_IO_SEG(0x0001180050001008ull) +#define CVMX_PKO_REG_BIST_RESULT \ + CVMX_ADD_IO_SEG(0x0001180050000080ull) +#define CVMX_PKO_REG_CMD_BUF \ + CVMX_ADD_IO_SEG(0x0001180050000010ull) +#define CVMX_PKO_REG_CRC_CTLX(offset) \ + CVMX_ADD_IO_SEG(0x0001180050000028ull + (((offset) & 1) * 8)) +#define CVMX_PKO_REG_CRC_ENABLE \ + CVMX_ADD_IO_SEG(0x0001180050000020ull) +#define CVMX_PKO_REG_CRC_IVX(offset) \ + CVMX_ADD_IO_SEG(0x0001180050000038ull + (((offset) & 1) * 8)) +#define CVMX_PKO_REG_DEBUG0 \ + CVMX_ADD_IO_SEG(0x0001180050000098ull) +#define CVMX_PKO_REG_DEBUG1 \ + CVMX_ADD_IO_SEG(0x00011800500000A0ull) +#define CVMX_PKO_REG_DEBUG2 \ + CVMX_ADD_IO_SEG(0x00011800500000A8ull) +#define CVMX_PKO_REG_DEBUG3 \ + CVMX_ADD_IO_SEG(0x00011800500000B0ull) +#define CVMX_PKO_REG_ENGINE_INFLIGHT \ + CVMX_ADD_IO_SEG(0x0001180050000050ull) +#define CVMX_PKO_REG_ENGINE_THRESH \ + CVMX_ADD_IO_SEG(0x0001180050000058ull) +#define CVMX_PKO_REG_ERROR \ + CVMX_ADD_IO_SEG(0x0001180050000088ull) +#define CVMX_PKO_REG_FLAGS \ + CVMX_ADD_IO_SEG(0x0001180050000000ull) +#define CVMX_PKO_REG_GMX_PORT_MODE \ + CVMX_ADD_IO_SEG(0x0001180050000018ull) +#define CVMX_PKO_REG_INT_MASK \ + CVMX_ADD_IO_SEG(0x0001180050000090ull) +#define CVMX_PKO_REG_QUEUE_MODE \ + CVMX_ADD_IO_SEG(0x0001180050000048ull) +#define CVMX_PKO_REG_QUEUE_PTRS1 \ + CVMX_ADD_IO_SEG(0x0001180050000100ull) +#define CVMX_PKO_REG_READ_IDX \ + CVMX_ADD_IO_SEG(0x0001180050000008ull) + +union cvmx_pko_mem_count0 { + uint64_t u64; + struct cvmx_pko_mem_count0_s { + uint64_t reserved_32_63:32; + uint64_t count:32; + } s; + struct cvmx_pko_mem_count0_s cn30xx; + struct cvmx_pko_mem_count0_s cn31xx; + struct cvmx_pko_mem_count0_s cn38xx; + struct cvmx_pko_mem_count0_s cn38xxp2; + struct cvmx_pko_mem_count0_s cn50xx; + struct cvmx_pko_mem_count0_s cn52xx; + struct cvmx_pko_mem_count0_s cn52xxp1; + struct cvmx_pko_mem_count0_s cn56xx; + struct cvmx_pko_mem_count0_s cn56xxp1; + struct cvmx_pko_mem_count0_s cn58xx; + struct cvmx_pko_mem_count0_s cn58xxp1; +}; + +union cvmx_pko_mem_count1 { + uint64_t u64; + struct cvmx_pko_mem_count1_s { + uint64_t reserved_48_63:16; + uint64_t count:48; + } s; + struct cvmx_pko_mem_count1_s cn30xx; + struct cvmx_pko_mem_count1_s cn31xx; + struct cvmx_pko_mem_count1_s cn38xx; + struct cvmx_pko_mem_count1_s cn38xxp2; + struct cvmx_pko_mem_count1_s cn50xx; + struct cvmx_pko_mem_count1_s cn52xx; + struct cvmx_pko_mem_count1_s cn52xxp1; + struct cvmx_pko_mem_count1_s cn56xx; + struct cvmx_pko_mem_count1_s cn56xxp1; + struct cvmx_pko_mem_count1_s cn58xx; + struct cvmx_pko_mem_count1_s cn58xxp1; +}; + +union cvmx_pko_mem_debug0 { + uint64_t u64; + struct cvmx_pko_mem_debug0_s { + uint64_t fau:28; + uint64_t cmd:14; + uint64_t segs:6; + uint64_t size:16; + } s; + struct cvmx_pko_mem_debug0_s cn30xx; + struct cvmx_pko_mem_debug0_s cn31xx; + struct cvmx_pko_mem_debug0_s cn38xx; + struct cvmx_pko_mem_debug0_s cn38xxp2; + struct cvmx_pko_mem_debug0_s cn50xx; + struct cvmx_pko_mem_debug0_s cn52xx; + struct cvmx_pko_mem_debug0_s cn52xxp1; + struct cvmx_pko_mem_debug0_s cn56xx; + struct cvmx_pko_mem_debug0_s cn56xxp1; + struct cvmx_pko_mem_debug0_s cn58xx; + struct cvmx_pko_mem_debug0_s cn58xxp1; +}; + +union cvmx_pko_mem_debug1 { + uint64_t u64; + struct cvmx_pko_mem_debug1_s { + uint64_t i:1; + uint64_t back:4; + uint64_t pool:3; + uint64_t size:16; + uint64_t ptr:40; + } s; + struct cvmx_pko_mem_debug1_s cn30xx; + struct cvmx_pko_mem_debug1_s cn31xx; + struct cvmx_pko_mem_debug1_s cn38xx; + struct cvmx_pko_mem_debug1_s cn38xxp2; + struct cvmx_pko_mem_debug1_s cn50xx; + struct cvmx_pko_mem_debug1_s cn52xx; + struct cvmx_pko_mem_debug1_s cn52xxp1; + struct cvmx_pko_mem_debug1_s cn56xx; + struct cvmx_pko_mem_debug1_s cn56xxp1; + struct cvmx_pko_mem_debug1_s cn58xx; + struct cvmx_pko_mem_debug1_s cn58xxp1; +}; + +union cvmx_pko_mem_debug10 { + uint64_t u64; + struct cvmx_pko_mem_debug10_s { + uint64_t reserved_0_63:64; + } s; + struct cvmx_pko_mem_debug10_cn30xx { + uint64_t fau:28; + uint64_t cmd:14; + uint64_t segs:6; + uint64_t size:16; + } cn30xx; + struct cvmx_pko_mem_debug10_cn30xx cn31xx; + struct cvmx_pko_mem_debug10_cn30xx cn38xx; + struct cvmx_pko_mem_debug10_cn30xx cn38xxp2; + struct cvmx_pko_mem_debug10_cn50xx { + uint64_t reserved_49_63:15; + uint64_t ptrs1:17; + uint64_t reserved_17_31:15; + uint64_t ptrs2:17; + } cn50xx; + struct cvmx_pko_mem_debug10_cn50xx cn52xx; + struct cvmx_pko_mem_debug10_cn50xx cn52xxp1; + struct cvmx_pko_mem_debug10_cn50xx cn56xx; + struct cvmx_pko_mem_debug10_cn50xx cn56xxp1; + struct cvmx_pko_mem_debug10_cn50xx cn58xx; + struct cvmx_pko_mem_debug10_cn50xx cn58xxp1; +}; + +union cvmx_pko_mem_debug11 { + uint64_t u64; + struct cvmx_pko_mem_debug11_s { + uint64_t i:1; + uint64_t back:4; + uint64_t pool:3; + uint64_t size:16; + uint64_t reserved_0_39:40; + } s; + struct cvmx_pko_mem_debug11_cn30xx { + uint64_t i:1; + uint64_t back:4; + uint64_t pool:3; + uint64_t size:16; + uint64_t ptr:40; + } cn30xx; + struct cvmx_pko_mem_debug11_cn30xx cn31xx; + struct cvmx_pko_mem_debug11_cn30xx cn38xx; + struct cvmx_pko_mem_debug11_cn30xx cn38xxp2; + struct cvmx_pko_mem_debug11_cn50xx { + uint64_t reserved_23_63:41; + uint64_t maj:1; + uint64_t uid:3; + uint64_t sop:1; + uint64_t len:1; + uint64_t chk:1; + uint64_t cnt:13; + uint64_t mod:3; + } cn50xx; + struct cvmx_pko_mem_debug11_cn50xx cn52xx; + struct cvmx_pko_mem_debug11_cn50xx cn52xxp1; + struct cvmx_pko_mem_debug11_cn50xx cn56xx; + struct cvmx_pko_mem_debug11_cn50xx cn56xxp1; + struct cvmx_pko_mem_debug11_cn50xx cn58xx; + struct cvmx_pko_mem_debug11_cn50xx cn58xxp1; +}; + +union cvmx_pko_mem_debug12 { + uint64_t u64; + struct cvmx_pko_mem_debug12_s { + uint64_t reserved_0_63:64; + } s; + struct cvmx_pko_mem_debug12_cn30xx { + uint64_t data:64; + } cn30xx; + struct cvmx_pko_mem_debug12_cn30xx cn31xx; + struct cvmx_pko_mem_debug12_cn30xx cn38xx; + struct cvmx_pko_mem_debug12_cn30xx cn38xxp2; + struct cvmx_pko_mem_debug12_cn50xx { + uint64_t fau:28; + uint64_t cmd:14; + uint64_t segs:6; + uint64_t size:16; + } cn50xx; + struct cvmx_pko_mem_debug12_cn50xx cn52xx; + struct cvmx_pko_mem_debug12_cn50xx cn52xxp1; + struct cvmx_pko_mem_debug12_cn50xx cn56xx; + struct cvmx_pko_mem_debug12_cn50xx cn56xxp1; + struct cvmx_pko_mem_debug12_cn50xx cn58xx; + struct cvmx_pko_mem_debug12_cn50xx cn58xxp1; +}; + +union cvmx_pko_mem_debug13 { + uint64_t u64; + struct cvmx_pko_mem_debug13_s { + uint64_t i:1; + uint64_t back:4; + uint64_t pool:3; + uint64_t reserved_0_55:56; + } s; + struct cvmx_pko_mem_debug13_cn30xx { + uint64_t reserved_51_63:13; + uint64_t widx:17; + uint64_t ridx2:17; + uint64_t widx2:17; + } cn30xx; + struct cvmx_pko_mem_debug13_cn30xx cn31xx; + struct cvmx_pko_mem_debug13_cn30xx cn38xx; + struct cvmx_pko_mem_debug13_cn30xx cn38xxp2; + struct cvmx_pko_mem_debug13_cn50xx { + uint64_t i:1; + uint64_t back:4; + uint64_t pool:3; + uint64_t size:16; + uint64_t ptr:40; + } cn50xx; + struct cvmx_pko_mem_debug13_cn50xx cn52xx; + struct cvmx_pko_mem_debug13_cn50xx cn52xxp1; + struct cvmx_pko_mem_debug13_cn50xx cn56xx; + struct cvmx_pko_mem_debug13_cn50xx cn56xxp1; + struct cvmx_pko_mem_debug13_cn50xx cn58xx; + struct cvmx_pko_mem_debug13_cn50xx cn58xxp1; +}; + +union cvmx_pko_mem_debug14 { + uint64_t u64; + struct cvmx_pko_mem_debug14_s { + uint64_t reserved_0_63:64; + } s; + struct cvmx_pko_mem_debug14_cn30xx { + uint64_t reserved_17_63:47; + uint64_t ridx:17; + } cn30xx; + struct cvmx_pko_mem_debug14_cn30xx cn31xx; + struct cvmx_pko_mem_debug14_cn30xx cn38xx; + struct cvmx_pko_mem_debug14_cn30xx cn38xxp2; + struct cvmx_pko_mem_debug14_cn52xx { + uint64_t data:64; + } cn52xx; + struct cvmx_pko_mem_debug14_cn52xx cn52xxp1; + struct cvmx_pko_mem_debug14_cn52xx cn56xx; + struct cvmx_pko_mem_debug14_cn52xx cn56xxp1; +}; + +union cvmx_pko_mem_debug2 { + uint64_t u64; + struct cvmx_pko_mem_debug2_s { + uint64_t i:1; + uint64_t back:4; + uint64_t pool:3; + uint64_t size:16; + uint64_t ptr:40; + } s; + struct cvmx_pko_mem_debug2_s cn30xx; + struct cvmx_pko_mem_debug2_s cn31xx; + struct cvmx_pko_mem_debug2_s cn38xx; + struct cvmx_pko_mem_debug2_s cn38xxp2; + struct cvmx_pko_mem_debug2_s cn50xx; + struct cvmx_pko_mem_debug2_s cn52xx; + struct cvmx_pko_mem_debug2_s cn52xxp1; + struct cvmx_pko_mem_debug2_s cn56xx; + struct cvmx_pko_mem_debug2_s cn56xxp1; + struct cvmx_pko_mem_debug2_s cn58xx; + struct cvmx_pko_mem_debug2_s cn58xxp1; +}; + +union cvmx_pko_mem_debug3 { + uint64_t u64; + struct cvmx_pko_mem_debug3_s { + uint64_t reserved_0_63:64; + } s; + struct cvmx_pko_mem_debug3_cn30xx { + uint64_t i:1; + uint64_t back:4; + uint64_t pool:3; + uint64_t size:16; + uint64_t ptr:40; + } cn30xx; + struct cvmx_pko_mem_debug3_cn30xx cn31xx; + struct cvmx_pko_mem_debug3_cn30xx cn38xx; + struct cvmx_pko_mem_debug3_cn30xx cn38xxp2; + struct cvmx_pko_mem_debug3_cn50xx { + uint64_t data:64; + } cn50xx; + struct cvmx_pko_mem_debug3_cn50xx cn52xx; + struct cvmx_pko_mem_debug3_cn50xx cn52xxp1; + struct cvmx_pko_mem_debug3_cn50xx cn56xx; + struct cvmx_pko_mem_debug3_cn50xx cn56xxp1; + struct cvmx_pko_mem_debug3_cn50xx cn58xx; + struct cvmx_pko_mem_debug3_cn50xx cn58xxp1; +}; + +union cvmx_pko_mem_debug4 { + uint64_t u64; + struct cvmx_pko_mem_debug4_s { + uint64_t reserved_0_63:64; + } s; + struct cvmx_pko_mem_debug4_cn30xx { + uint64_t data:64; + } cn30xx; + struct cvmx_pko_mem_debug4_cn30xx cn31xx; + struct cvmx_pko_mem_debug4_cn30xx cn38xx; + struct cvmx_pko_mem_debug4_cn30xx cn38xxp2; + struct cvmx_pko_mem_debug4_cn50xx { + uint64_t cmnd_segs:3; + uint64_t cmnd_siz:16; + uint64_t cmnd_off:6; + uint64_t uid:3; + uint64_t dread_sop:1; + uint64_t init_dwrite:1; + uint64_t chk_once:1; + uint64_t chk_mode:1; + uint64_t active:1; + uint64_t static_p:1; + uint64_t qos:3; + uint64_t qcb_ridx:5; + uint64_t qid_off_max:4; + uint64_t qid_off:4; + uint64_t qid_base:8; + uint64_t wait:1; + uint64_t minor:2; + uint64_t major:3; + } cn50xx; + struct cvmx_pko_mem_debug4_cn52xx { + uint64_t curr_siz:8; + uint64_t curr_off:16; + uint64_t cmnd_segs:6; + uint64_t cmnd_siz:16; + uint64_t cmnd_off:6; + uint64_t uid:2; + uint64_t dread_sop:1; + uint64_t init_dwrite:1; + uint64_t chk_once:1; + uint64_t chk_mode:1; + uint64_t wait:1; + uint64_t minor:2; + uint64_t major:3; + } cn52xx; + struct cvmx_pko_mem_debug4_cn52xx cn52xxp1; + struct cvmx_pko_mem_debug4_cn52xx cn56xx; + struct cvmx_pko_mem_debug4_cn52xx cn56xxp1; + struct cvmx_pko_mem_debug4_cn50xx cn58xx; + struct cvmx_pko_mem_debug4_cn50xx cn58xxp1; +}; + +union cvmx_pko_mem_debug5 { + uint64_t u64; + struct cvmx_pko_mem_debug5_s { + uint64_t reserved_0_63:64; + } s; + struct cvmx_pko_mem_debug5_cn30xx { + uint64_t dwri_mod:1; + uint64_t dwri_sop:1; + uint64_t dwri_len:1; + uint64_t dwri_cnt:13; + uint64_t cmnd_siz:16; + uint64_t uid:1; + uint64_t xfer_wor:1; + uint64_t xfer_dwr:1; + uint64_t cbuf_fre:1; + uint64_t reserved_27_27:1; + uint64_t chk_mode:1; + uint64_t active:1; + uint64_t qos:3; + uint64_t qcb_ridx:5; + uint64_t qid_off:3; + uint64_t qid_base:7; + uint64_t wait:1; + uint64_t minor:2; + uint64_t major:4; + } cn30xx; + struct cvmx_pko_mem_debug5_cn30xx cn31xx; + struct cvmx_pko_mem_debug5_cn30xx cn38xx; + struct cvmx_pko_mem_debug5_cn30xx cn38xxp2; + struct cvmx_pko_mem_debug5_cn50xx { + uint64_t curr_ptr:29; + uint64_t curr_siz:16; + uint64_t curr_off:16; + uint64_t cmnd_segs:3; + } cn50xx; + struct cvmx_pko_mem_debug5_cn52xx { + uint64_t reserved_54_63:10; + uint64_t nxt_inflt:6; + uint64_t curr_ptr:40; + uint64_t curr_siz:8; + } cn52xx; + struct cvmx_pko_mem_debug5_cn52xx cn52xxp1; + struct cvmx_pko_mem_debug5_cn52xx cn56xx; + struct cvmx_pko_mem_debug5_cn52xx cn56xxp1; + struct cvmx_pko_mem_debug5_cn50xx cn58xx; + struct cvmx_pko_mem_debug5_cn50xx cn58xxp1; +}; + +union cvmx_pko_mem_debug6 { + uint64_t u64; + struct cvmx_pko_mem_debug6_s { + uint64_t reserved_37_63:27; + uint64_t qid_offres:4; + uint64_t qid_offths:4; + uint64_t preempter:1; + uint64_t preemptee:1; + uint64_t preempted:1; + uint64_t active:1; + uint64_t statc:1; + uint64_t qos:3; + uint64_t qcb_ridx:5; + uint64_t qid_offmax:4; + uint64_t reserved_0_11:12; + } s; + struct cvmx_pko_mem_debug6_cn30xx { + uint64_t reserved_11_63:53; + uint64_t qid_offm:3; + uint64_t static_p:1; + uint64_t work_min:3; + uint64_t dwri_chk:1; + uint64_t dwri_uid:1; + uint64_t dwri_mod:2; + } cn30xx; + struct cvmx_pko_mem_debug6_cn30xx cn31xx; + struct cvmx_pko_mem_debug6_cn30xx cn38xx; + struct cvmx_pko_mem_debug6_cn30xx cn38xxp2; + struct cvmx_pko_mem_debug6_cn50xx { + uint64_t reserved_11_63:53; + uint64_t curr_ptr:11; + } cn50xx; + struct cvmx_pko_mem_debug6_cn52xx { + uint64_t reserved_37_63:27; + uint64_t qid_offres:4; + uint64_t qid_offths:4; + uint64_t preempter:1; + uint64_t preemptee:1; + uint64_t preempted:1; + uint64_t active:1; + uint64_t statc:1; + uint64_t qos:3; + uint64_t qcb_ridx:5; + uint64_t qid_offmax:4; + uint64_t qid_off:4; + uint64_t qid_base:8; + } cn52xx; + struct cvmx_pko_mem_debug6_cn52xx cn52xxp1; + struct cvmx_pko_mem_debug6_cn52xx cn56xx; + struct cvmx_pko_mem_debug6_cn52xx cn56xxp1; + struct cvmx_pko_mem_debug6_cn50xx cn58xx; + struct cvmx_pko_mem_debug6_cn50xx cn58xxp1; +}; + +union cvmx_pko_mem_debug7 { + uint64_t u64; + struct cvmx_pko_mem_debug7_s { + uint64_t qos:5; + uint64_t tail:1; + uint64_t reserved_0_57:58; + } s; + struct cvmx_pko_mem_debug7_cn30xx { + uint64_t reserved_58_63:6; + uint64_t dwb:9; + uint64_t start:33; + uint64_t size:16; + } cn30xx; + struct cvmx_pko_mem_debug7_cn30xx cn31xx; + struct cvmx_pko_mem_debug7_cn30xx cn38xx; + struct cvmx_pko_mem_debug7_cn30xx cn38xxp2; + struct cvmx_pko_mem_debug7_cn50xx { + uint64_t qos:5; + uint64_t tail:1; + uint64_t buf_siz:13; + uint64_t buf_ptr:33; + uint64_t qcb_widx:6; + uint64_t qcb_ridx:6; + } cn50xx; + struct cvmx_pko_mem_debug7_cn50xx cn52xx; + struct cvmx_pko_mem_debug7_cn50xx cn52xxp1; + struct cvmx_pko_mem_debug7_cn50xx cn56xx; + struct cvmx_pko_mem_debug7_cn50xx cn56xxp1; + struct cvmx_pko_mem_debug7_cn50xx cn58xx; + struct cvmx_pko_mem_debug7_cn50xx cn58xxp1; +}; + +union cvmx_pko_mem_debug8 { + uint64_t u64; + struct cvmx_pko_mem_debug8_s { + uint64_t reserved_59_63:5; + uint64_t tail:1; + uint64_t buf_siz:13; + uint64_t reserved_0_44:45; + } s; + struct cvmx_pko_mem_debug8_cn30xx { + uint64_t qos:5; + uint64_t tail:1; + uint64_t buf_siz:13; + uint64_t buf_ptr:33; + uint64_t qcb_widx:6; + uint64_t qcb_ridx:6; + } cn30xx; + struct cvmx_pko_mem_debug8_cn30xx cn31xx; + struct cvmx_pko_mem_debug8_cn30xx cn38xx; + struct cvmx_pko_mem_debug8_cn30xx cn38xxp2; + struct cvmx_pko_mem_debug8_cn50xx { + uint64_t reserved_28_63:36; + uint64_t doorbell:20; + uint64_t reserved_6_7:2; + uint64_t static_p:1; + uint64_t s_tail:1; + uint64_t static_q:1; + uint64_t qos:3; + } cn50xx; + struct cvmx_pko_mem_debug8_cn52xx { + uint64_t reserved_29_63:35; + uint64_t preempter:1; + uint64_t doorbell:20; + uint64_t reserved_7_7:1; + uint64_t preemptee:1; + uint64_t static_p:1; + uint64_t s_tail:1; + uint64_t static_q:1; + uint64_t qos:3; + } cn52xx; + struct cvmx_pko_mem_debug8_cn52xx cn52xxp1; + struct cvmx_pko_mem_debug8_cn52xx cn56xx; + struct cvmx_pko_mem_debug8_cn52xx cn56xxp1; + struct cvmx_pko_mem_debug8_cn50xx cn58xx; + struct cvmx_pko_mem_debug8_cn50xx cn58xxp1; +}; + +union cvmx_pko_mem_debug9 { + uint64_t u64; + struct cvmx_pko_mem_debug9_s { + uint64_t reserved_49_63:15; + uint64_t ptrs0:17; + uint64_t reserved_0_31:32; + } s; + struct cvmx_pko_mem_debug9_cn30xx { + uint64_t reserved_28_63:36; + uint64_t doorbell:20; + uint64_t reserved_5_7:3; + uint64_t s_tail:1; + uint64_t static_q:1; + uint64_t qos:3; + } cn30xx; + struct cvmx_pko_mem_debug9_cn30xx cn31xx; + struct cvmx_pko_mem_debug9_cn38xx { + uint64_t reserved_28_63:36; + uint64_t doorbell:20; + uint64_t reserved_6_7:2; + uint64_t static_p:1; + uint64_t s_tail:1; + uint64_t static_q:1; + uint64_t qos:3; + } cn38xx; + struct cvmx_pko_mem_debug9_cn38xx cn38xxp2; + struct cvmx_pko_mem_debug9_cn50xx { + uint64_t reserved_49_63:15; + uint64_t ptrs0:17; + uint64_t reserved_17_31:15; + uint64_t ptrs3:17; + } cn50xx; + struct cvmx_pko_mem_debug9_cn50xx cn52xx; + struct cvmx_pko_mem_debug9_cn50xx cn52xxp1; + struct cvmx_pko_mem_debug9_cn50xx cn56xx; + struct cvmx_pko_mem_debug9_cn50xx cn56xxp1; + struct cvmx_pko_mem_debug9_cn50xx cn58xx; + struct cvmx_pko_mem_debug9_cn50xx cn58xxp1; +}; + +union cvmx_pko_mem_port_ptrs { + uint64_t u64; + struct cvmx_pko_mem_port_ptrs_s { + uint64_t reserved_62_63:2; + uint64_t static_p:1; + uint64_t qos_mask:8; + uint64_t reserved_16_52:37; + uint64_t bp_port:6; + uint64_t eid:4; + uint64_t pid:6; + } s; + struct cvmx_pko_mem_port_ptrs_s cn52xx; + struct cvmx_pko_mem_port_ptrs_s cn52xxp1; + struct cvmx_pko_mem_port_ptrs_s cn56xx; + struct cvmx_pko_mem_port_ptrs_s cn56xxp1; +}; + +union cvmx_pko_mem_port_qos { + uint64_t u64; + struct cvmx_pko_mem_port_qos_s { + uint64_t reserved_61_63:3; + uint64_t qos_mask:8; + uint64_t reserved_10_52:43; + uint64_t eid:4; + uint64_t pid:6; + } s; + struct cvmx_pko_mem_port_qos_s cn52xx; + struct cvmx_pko_mem_port_qos_s cn52xxp1; + struct cvmx_pko_mem_port_qos_s cn56xx; + struct cvmx_pko_mem_port_qos_s cn56xxp1; +}; + +union cvmx_pko_mem_port_rate0 { + uint64_t u64; + struct cvmx_pko_mem_port_rate0_s { + uint64_t reserved_51_63:13; + uint64_t rate_word:19; + uint64_t rate_pkt:24; + uint64_t reserved_6_7:2; + uint64_t pid:6; + } s; + struct cvmx_pko_mem_port_rate0_s cn52xx; + struct cvmx_pko_mem_port_rate0_s cn52xxp1; + struct cvmx_pko_mem_port_rate0_s cn56xx; + struct cvmx_pko_mem_port_rate0_s cn56xxp1; +}; + +union cvmx_pko_mem_port_rate1 { + uint64_t u64; + struct cvmx_pko_mem_port_rate1_s { + uint64_t reserved_32_63:32; + uint64_t rate_lim:24; + uint64_t reserved_6_7:2; + uint64_t pid:6; + } s; + struct cvmx_pko_mem_port_rate1_s cn52xx; + struct cvmx_pko_mem_port_rate1_s cn52xxp1; + struct cvmx_pko_mem_port_rate1_s cn56xx; + struct cvmx_pko_mem_port_rate1_s cn56xxp1; +}; + +union cvmx_pko_mem_queue_ptrs { + uint64_t u64; + struct cvmx_pko_mem_queue_ptrs_s { + uint64_t s_tail:1; + uint64_t static_p:1; + uint64_t static_q:1; + uint64_t qos_mask:8; + uint64_t buf_ptr:36; + uint64_t tail:1; + uint64_t index:3; + uint64_t port:6; + uint64_t queue:7; + } s; + struct cvmx_pko_mem_queue_ptrs_s cn30xx; + struct cvmx_pko_mem_queue_ptrs_s cn31xx; + struct cvmx_pko_mem_queue_ptrs_s cn38xx; + struct cvmx_pko_mem_queue_ptrs_s cn38xxp2; + struct cvmx_pko_mem_queue_ptrs_s cn50xx; + struct cvmx_pko_mem_queue_ptrs_s cn52xx; + struct cvmx_pko_mem_queue_ptrs_s cn52xxp1; + struct cvmx_pko_mem_queue_ptrs_s cn56xx; + struct cvmx_pko_mem_queue_ptrs_s cn56xxp1; + struct cvmx_pko_mem_queue_ptrs_s cn58xx; + struct cvmx_pko_mem_queue_ptrs_s cn58xxp1; +}; + +union cvmx_pko_mem_queue_qos { + uint64_t u64; + struct cvmx_pko_mem_queue_qos_s { + uint64_t reserved_61_63:3; + uint64_t qos_mask:8; + uint64_t reserved_13_52:40; + uint64_t pid:6; + uint64_t qid:7; + } s; + struct cvmx_pko_mem_queue_qos_s cn30xx; + struct cvmx_pko_mem_queue_qos_s cn31xx; + struct cvmx_pko_mem_queue_qos_s cn38xx; + struct cvmx_pko_mem_queue_qos_s cn38xxp2; + struct cvmx_pko_mem_queue_qos_s cn50xx; + struct cvmx_pko_mem_queue_qos_s cn52xx; + struct cvmx_pko_mem_queue_qos_s cn52xxp1; + struct cvmx_pko_mem_queue_qos_s cn56xx; + struct cvmx_pko_mem_queue_qos_s cn56xxp1; + struct cvmx_pko_mem_queue_qos_s cn58xx; + struct cvmx_pko_mem_queue_qos_s cn58xxp1; +}; + +union cvmx_pko_reg_bist_result { + uint64_t u64; + struct cvmx_pko_reg_bist_result_s { + uint64_t reserved_0_63:64; + } s; + struct cvmx_pko_reg_bist_result_cn30xx { + uint64_t reserved_27_63:37; + uint64_t psb2:5; + uint64_t count:1; + uint64_t rif:1; + uint64_t wif:1; + uint64_t ncb:1; + uint64_t out:1; + uint64_t crc:1; + uint64_t chk:1; + uint64_t qsb:2; + uint64_t qcb:2; + uint64_t pdb:4; + uint64_t psb:7; + } cn30xx; + struct cvmx_pko_reg_bist_result_cn30xx cn31xx; + struct cvmx_pko_reg_bist_result_cn30xx cn38xx; + struct cvmx_pko_reg_bist_result_cn30xx cn38xxp2; + struct cvmx_pko_reg_bist_result_cn50xx { + uint64_t reserved_33_63:31; + uint64_t csr:1; + uint64_t iob:1; + uint64_t out_crc:1; + uint64_t out_ctl:3; + uint64_t out_sta:1; + uint64_t out_wif:1; + uint64_t prt_chk:3; + uint64_t prt_nxt:1; + uint64_t prt_psb:6; + uint64_t ncb_inb:2; + uint64_t prt_qcb:2; + uint64_t prt_qsb:3; + uint64_t dat_dat:4; + uint64_t dat_ptr:4; + } cn50xx; + struct cvmx_pko_reg_bist_result_cn52xx { + uint64_t reserved_35_63:29; + uint64_t csr:1; + uint64_t iob:1; + uint64_t out_dat:1; + uint64_t out_ctl:3; + uint64_t out_sta:1; + uint64_t out_wif:1; + uint64_t prt_chk:3; + uint64_t prt_nxt:1; + uint64_t prt_psb:8; + uint64_t ncb_inb:2; + uint64_t prt_qcb:2; + uint64_t prt_qsb:3; + uint64_t prt_ctl:2; + uint64_t dat_dat:2; + uint64_t dat_ptr:4; + } cn52xx; + struct cvmx_pko_reg_bist_result_cn52xx cn52xxp1; + struct cvmx_pko_reg_bist_result_cn52xx cn56xx; + struct cvmx_pko_reg_bist_result_cn52xx cn56xxp1; + struct cvmx_pko_reg_bist_result_cn50xx cn58xx; + struct cvmx_pko_reg_bist_result_cn50xx cn58xxp1; +}; + +union cvmx_pko_reg_cmd_buf { + uint64_t u64; + struct cvmx_pko_reg_cmd_buf_s { + uint64_t reserved_23_63:41; + uint64_t pool:3; + uint64_t reserved_13_19:7; + uint64_t size:13; + } s; + struct cvmx_pko_reg_cmd_buf_s cn30xx; + struct cvmx_pko_reg_cmd_buf_s cn31xx; + struct cvmx_pko_reg_cmd_buf_s cn38xx; + struct cvmx_pko_reg_cmd_buf_s cn38xxp2; + struct cvmx_pko_reg_cmd_buf_s cn50xx; + struct cvmx_pko_reg_cmd_buf_s cn52xx; + struct cvmx_pko_reg_cmd_buf_s cn52xxp1; + struct cvmx_pko_reg_cmd_buf_s cn56xx; + struct cvmx_pko_reg_cmd_buf_s cn56xxp1; + struct cvmx_pko_reg_cmd_buf_s cn58xx; + struct cvmx_pko_reg_cmd_buf_s cn58xxp1; +}; + +union cvmx_pko_reg_crc_ctlx { + uint64_t u64; + struct cvmx_pko_reg_crc_ctlx_s { + uint64_t reserved_2_63:62; + uint64_t invres:1; + uint64_t refin:1; + } s; + struct cvmx_pko_reg_crc_ctlx_s cn38xx; + struct cvmx_pko_reg_crc_ctlx_s cn38xxp2; + struct cvmx_pko_reg_crc_ctlx_s cn58xx; + struct cvmx_pko_reg_crc_ctlx_s cn58xxp1; +}; + +union cvmx_pko_reg_crc_enable { + uint64_t u64; + struct cvmx_pko_reg_crc_enable_s { + uint64_t reserved_32_63:32; + uint64_t enable:32; + } s; + struct cvmx_pko_reg_crc_enable_s cn38xx; + struct cvmx_pko_reg_crc_enable_s cn38xxp2; + struct cvmx_pko_reg_crc_enable_s cn58xx; + struct cvmx_pko_reg_crc_enable_s cn58xxp1; +}; + +union cvmx_pko_reg_crc_ivx { + uint64_t u64; + struct cvmx_pko_reg_crc_ivx_s { + uint64_t reserved_32_63:32; + uint64_t iv:32; + } s; + struct cvmx_pko_reg_crc_ivx_s cn38xx; + struct cvmx_pko_reg_crc_ivx_s cn38xxp2; + struct cvmx_pko_reg_crc_ivx_s cn58xx; + struct cvmx_pko_reg_crc_ivx_s cn58xxp1; +}; + +union cvmx_pko_reg_debug0 { + uint64_t u64; + struct cvmx_pko_reg_debug0_s { + uint64_t asserts:64; + } s; + struct cvmx_pko_reg_debug0_cn30xx { + uint64_t reserved_17_63:47; + uint64_t asserts:17; + } cn30xx; + struct cvmx_pko_reg_debug0_cn30xx cn31xx; + struct cvmx_pko_reg_debug0_cn30xx cn38xx; + struct cvmx_pko_reg_debug0_cn30xx cn38xxp2; + struct cvmx_pko_reg_debug0_s cn50xx; + struct cvmx_pko_reg_debug0_s cn52xx; + struct cvmx_pko_reg_debug0_s cn52xxp1; + struct cvmx_pko_reg_debug0_s cn56xx; + struct cvmx_pko_reg_debug0_s cn56xxp1; + struct cvmx_pko_reg_debug0_s cn58xx; + struct cvmx_pko_reg_debug0_s cn58xxp1; +}; + +union cvmx_pko_reg_debug1 { + uint64_t u64; + struct cvmx_pko_reg_debug1_s { + uint64_t asserts:64; + } s; + struct cvmx_pko_reg_debug1_s cn50xx; + struct cvmx_pko_reg_debug1_s cn52xx; + struct cvmx_pko_reg_debug1_s cn52xxp1; + struct cvmx_pko_reg_debug1_s cn56xx; + struct cvmx_pko_reg_debug1_s cn56xxp1; + struct cvmx_pko_reg_debug1_s cn58xx; + struct cvmx_pko_reg_debug1_s cn58xxp1; +}; + +union cvmx_pko_reg_debug2 { + uint64_t u64; + struct cvmx_pko_reg_debug2_s { + uint64_t asserts:64; + } s; + struct cvmx_pko_reg_debug2_s cn50xx; + struct cvmx_pko_reg_debug2_s cn52xx; + struct cvmx_pko_reg_debug2_s cn52xxp1; + struct cvmx_pko_reg_debug2_s cn56xx; + struct cvmx_pko_reg_debug2_s cn56xxp1; + struct cvmx_pko_reg_debug2_s cn58xx; + struct cvmx_pko_reg_debug2_s cn58xxp1; +}; + +union cvmx_pko_reg_debug3 { + uint64_t u64; + struct cvmx_pko_reg_debug3_s { + uint64_t asserts:64; + } s; + struct cvmx_pko_reg_debug3_s cn50xx; + struct cvmx_pko_reg_debug3_s cn52xx; + struct cvmx_pko_reg_debug3_s cn52xxp1; + struct cvmx_pko_reg_debug3_s cn56xx; + struct cvmx_pko_reg_debug3_s cn56xxp1; + struct cvmx_pko_reg_debug3_s cn58xx; + struct cvmx_pko_reg_debug3_s cn58xxp1; +}; + +union cvmx_pko_reg_engine_inflight { + uint64_t u64; + struct cvmx_pko_reg_engine_inflight_s { + uint64_t reserved_40_63:24; + uint64_t engine9:4; + uint64_t engine8:4; + uint64_t engine7:4; + uint64_t engine6:4; + uint64_t engine5:4; + uint64_t engine4:4; + uint64_t engine3:4; + uint64_t engine2:4; + uint64_t engine1:4; + uint64_t engine0:4; + } s; + struct cvmx_pko_reg_engine_inflight_s cn52xx; + struct cvmx_pko_reg_engine_inflight_s cn52xxp1; + struct cvmx_pko_reg_engine_inflight_s cn56xx; + struct cvmx_pko_reg_engine_inflight_s cn56xxp1; +}; + +union cvmx_pko_reg_engine_thresh { + uint64_t u64; + struct cvmx_pko_reg_engine_thresh_s { + uint64_t reserved_10_63:54; + uint64_t mask:10; + } s; + struct cvmx_pko_reg_engine_thresh_s cn52xx; + struct cvmx_pko_reg_engine_thresh_s cn52xxp1; + struct cvmx_pko_reg_engine_thresh_s cn56xx; + struct cvmx_pko_reg_engine_thresh_s cn56xxp1; +}; + +union cvmx_pko_reg_error { + uint64_t u64; + struct cvmx_pko_reg_error_s { + uint64_t reserved_3_63:61; + uint64_t currzero:1; + uint64_t doorbell:1; + uint64_t parity:1; + } s; + struct cvmx_pko_reg_error_cn30xx { + uint64_t reserved_2_63:62; + uint64_t doorbell:1; + uint64_t parity:1; + } cn30xx; + struct cvmx_pko_reg_error_cn30xx cn31xx; + struct cvmx_pko_reg_error_cn30xx cn38xx; + struct cvmx_pko_reg_error_cn30xx cn38xxp2; + struct cvmx_pko_reg_error_s cn50xx; + struct cvmx_pko_reg_error_s cn52xx; + struct cvmx_pko_reg_error_s cn52xxp1; + struct cvmx_pko_reg_error_s cn56xx; + struct cvmx_pko_reg_error_s cn56xxp1; + struct cvmx_pko_reg_error_s cn58xx; + struct cvmx_pko_reg_error_s cn58xxp1; +}; + +union cvmx_pko_reg_flags { + uint64_t u64; + struct cvmx_pko_reg_flags_s { + uint64_t reserved_4_63:60; + uint64_t reset:1; + uint64_t store_be:1; + uint64_t ena_dwb:1; + uint64_t ena_pko:1; + } s; + struct cvmx_pko_reg_flags_s cn30xx; + struct cvmx_pko_reg_flags_s cn31xx; + struct cvmx_pko_reg_flags_s cn38xx; + struct cvmx_pko_reg_flags_s cn38xxp2; + struct cvmx_pko_reg_flags_s cn50xx; + struct cvmx_pko_reg_flags_s cn52xx; + struct cvmx_pko_reg_flags_s cn52xxp1; + struct cvmx_pko_reg_flags_s cn56xx; + struct cvmx_pko_reg_flags_s cn56xxp1; + struct cvmx_pko_reg_flags_s cn58xx; + struct cvmx_pko_reg_flags_s cn58xxp1; +}; + +union cvmx_pko_reg_gmx_port_mode { + uint64_t u64; + struct cvmx_pko_reg_gmx_port_mode_s { + uint64_t reserved_6_63:58; + uint64_t mode1:3; + uint64_t mode0:3; + } s; + struct cvmx_pko_reg_gmx_port_mode_s cn30xx; + struct cvmx_pko_reg_gmx_port_mode_s cn31xx; + struct cvmx_pko_reg_gmx_port_mode_s cn38xx; + struct cvmx_pko_reg_gmx_port_mode_s cn38xxp2; + struct cvmx_pko_reg_gmx_port_mode_s cn50xx; + struct cvmx_pko_reg_gmx_port_mode_s cn52xx; + struct cvmx_pko_reg_gmx_port_mode_s cn52xxp1; + struct cvmx_pko_reg_gmx_port_mode_s cn56xx; + struct cvmx_pko_reg_gmx_port_mode_s cn56xxp1; + struct cvmx_pko_reg_gmx_port_mode_s cn58xx; + struct cvmx_pko_reg_gmx_port_mode_s cn58xxp1; +}; + +union cvmx_pko_reg_int_mask { + uint64_t u64; + struct cvmx_pko_reg_int_mask_s { + uint64_t reserved_3_63:61; + uint64_t currzero:1; + uint64_t doorbell:1; + uint64_t parity:1; + } s; + struct cvmx_pko_reg_int_mask_cn30xx { + uint64_t reserved_2_63:62; + uint64_t doorbell:1; + uint64_t parity:1; + } cn30xx; + struct cvmx_pko_reg_int_mask_cn30xx cn31xx; + struct cvmx_pko_reg_int_mask_cn30xx cn38xx; + struct cvmx_pko_reg_int_mask_cn30xx cn38xxp2; + struct cvmx_pko_reg_int_mask_s cn50xx; + struct cvmx_pko_reg_int_mask_s cn52xx; + struct cvmx_pko_reg_int_mask_s cn52xxp1; + struct cvmx_pko_reg_int_mask_s cn56xx; + struct cvmx_pko_reg_int_mask_s cn56xxp1; + struct cvmx_pko_reg_int_mask_s cn58xx; + struct cvmx_pko_reg_int_mask_s cn58xxp1; +}; + +union cvmx_pko_reg_queue_mode { + uint64_t u64; + struct cvmx_pko_reg_queue_mode_s { + uint64_t reserved_2_63:62; + uint64_t mode:2; + } s; + struct cvmx_pko_reg_queue_mode_s cn30xx; + struct cvmx_pko_reg_queue_mode_s cn31xx; + struct cvmx_pko_reg_queue_mode_s cn38xx; + struct cvmx_pko_reg_queue_mode_s cn38xxp2; + struct cvmx_pko_reg_queue_mode_s cn50xx; + struct cvmx_pko_reg_queue_mode_s cn52xx; + struct cvmx_pko_reg_queue_mode_s cn52xxp1; + struct cvmx_pko_reg_queue_mode_s cn56xx; + struct cvmx_pko_reg_queue_mode_s cn56xxp1; + struct cvmx_pko_reg_queue_mode_s cn58xx; + struct cvmx_pko_reg_queue_mode_s cn58xxp1; +}; + +union cvmx_pko_reg_queue_ptrs1 { + uint64_t u64; + struct cvmx_pko_reg_queue_ptrs1_s { + uint64_t reserved_2_63:62; + uint64_t idx3:1; + uint64_t qid7:1; + } s; + struct cvmx_pko_reg_queue_ptrs1_s cn50xx; + struct cvmx_pko_reg_queue_ptrs1_s cn52xx; + struct cvmx_pko_reg_queue_ptrs1_s cn52xxp1; + struct cvmx_pko_reg_queue_ptrs1_s cn56xx; + struct cvmx_pko_reg_queue_ptrs1_s cn56xxp1; + struct cvmx_pko_reg_queue_ptrs1_s cn58xx; + struct cvmx_pko_reg_queue_ptrs1_s cn58xxp1; +}; + +union cvmx_pko_reg_read_idx { + uint64_t u64; + struct cvmx_pko_reg_read_idx_s { + uint64_t reserved_16_63:48; + uint64_t inc:8; + uint64_t index:8; + } s; + struct cvmx_pko_reg_read_idx_s cn30xx; + struct cvmx_pko_reg_read_idx_s cn31xx; + struct cvmx_pko_reg_read_idx_s cn38xx; + struct cvmx_pko_reg_read_idx_s cn38xxp2; + struct cvmx_pko_reg_read_idx_s cn50xx; + struct cvmx_pko_reg_read_idx_s cn52xx; + struct cvmx_pko_reg_read_idx_s cn52xxp1; + struct cvmx_pko_reg_read_idx_s cn56xx; + struct cvmx_pko_reg_read_idx_s cn56xxp1; + struct cvmx_pko_reg_read_idx_s cn58xx; + struct cvmx_pko_reg_read_idx_s cn58xxp1; +}; + +#endif diff --git a/drivers/staging/octeon/cvmx-pko.c b/drivers/staging/octeon/cvmx-pko.c new file mode 100644 index 000000000000..00db91529b19 --- /dev/null +++ b/drivers/staging/octeon/cvmx-pko.c @@ -0,0 +1,506 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2008 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +/* + * Support library for the hardware Packet Output unit. + */ + +#include + +#include "cvmx-config.h" +#include "cvmx-pko.h" +#include "cvmx-helper.h" + +/** + * Internal state of packet output + */ + +/** + * Call before any other calls to initialize the packet + * output system. This does chip global config, and should only be + * done by one core. + */ + +void cvmx_pko_initialize_global(void) +{ + int i; + uint64_t priority = 8; + union cvmx_pko_reg_cmd_buf config; + + /* + * Set the size of the PKO command buffers to an odd number of + * 64bit words. This allows the normal two word send to stay + * aligned and never span a comamnd word buffer. + */ + config.u64 = 0; + config.s.pool = CVMX_FPA_OUTPUT_BUFFER_POOL; + config.s.size = CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE / 8 - 1; + + cvmx_write_csr(CVMX_PKO_REG_CMD_BUF, config.u64); + + for (i = 0; i < CVMX_PKO_MAX_OUTPUT_QUEUES; i++) + cvmx_pko_config_port(CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID, i, 1, + &priority); + + /* + * If we aren't using all of the queues optimize PKO's + * internal memory. + */ + if (OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX) + || OCTEON_IS_MODEL(OCTEON_CN56XX) + || OCTEON_IS_MODEL(OCTEON_CN52XX)) { + int num_interfaces = cvmx_helper_get_number_of_interfaces(); + int last_port = + cvmx_helper_get_last_ipd_port(num_interfaces - 1); + int max_queues = + cvmx_pko_get_base_queue(last_port) + + cvmx_pko_get_num_queues(last_port); + if (OCTEON_IS_MODEL(OCTEON_CN38XX)) { + if (max_queues <= 32) + cvmx_write_csr(CVMX_PKO_REG_QUEUE_MODE, 2); + else if (max_queues <= 64) + cvmx_write_csr(CVMX_PKO_REG_QUEUE_MODE, 1); + } else { + if (max_queues <= 64) + cvmx_write_csr(CVMX_PKO_REG_QUEUE_MODE, 2); + else if (max_queues <= 128) + cvmx_write_csr(CVMX_PKO_REG_QUEUE_MODE, 1); + } + } +} + +/** + * This function does per-core initialization required by the PKO routines. + * This must be called on all cores that will do packet output, and must + * be called after the FPA has been initialized and filled with pages. + * + * Returns 0 on success + * !0 on failure + */ +int cvmx_pko_initialize_local(void) +{ + /* Nothing to do */ + return 0; +} + +/** + * Enables the packet output hardware. It must already be + * configured. + */ +void cvmx_pko_enable(void) +{ + union cvmx_pko_reg_flags flags; + + flags.u64 = cvmx_read_csr(CVMX_PKO_REG_FLAGS); + if (flags.s.ena_pko) + cvmx_dprintf + ("Warning: Enabling PKO when PKO already enabled.\n"); + + flags.s.ena_dwb = 1; + flags.s.ena_pko = 1; + /* + * always enable big endian for 3-word command. Does nothing + * for 2-word. + */ + flags.s.store_be = 1; + cvmx_write_csr(CVMX_PKO_REG_FLAGS, flags.u64); +} + +/** + * Disables the packet output. Does not affect any configuration. + */ +void cvmx_pko_disable(void) +{ + union cvmx_pko_reg_flags pko_reg_flags; + pko_reg_flags.u64 = cvmx_read_csr(CVMX_PKO_REG_FLAGS); + pko_reg_flags.s.ena_pko = 0; + cvmx_write_csr(CVMX_PKO_REG_FLAGS, pko_reg_flags.u64); +} + + +/** + * Reset the packet output. + */ +static void __cvmx_pko_reset(void) +{ + union cvmx_pko_reg_flags pko_reg_flags; + pko_reg_flags.u64 = cvmx_read_csr(CVMX_PKO_REG_FLAGS); + pko_reg_flags.s.reset = 1; + cvmx_write_csr(CVMX_PKO_REG_FLAGS, pko_reg_flags.u64); +} + +/** + * Shutdown and free resources required by packet output. + */ +void cvmx_pko_shutdown(void) +{ + union cvmx_pko_mem_queue_ptrs config; + int queue; + + cvmx_pko_disable(); + + for (queue = 0; queue < CVMX_PKO_MAX_OUTPUT_QUEUES; queue++) { + config.u64 = 0; + config.s.tail = 1; + config.s.index = 0; + config.s.port = CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID; + config.s.queue = queue & 0x7f; + config.s.qos_mask = 0; + config.s.buf_ptr = 0; + if (!OCTEON_IS_MODEL(OCTEON_CN3XXX)) { + union cvmx_pko_reg_queue_ptrs1 config1; + config1.u64 = 0; + config1.s.qid7 = queue >> 7; + cvmx_write_csr(CVMX_PKO_REG_QUEUE_PTRS1, config1.u64); + } + cvmx_write_csr(CVMX_PKO_MEM_QUEUE_PTRS, config.u64); + cvmx_cmd_queue_shutdown(CVMX_CMD_QUEUE_PKO(queue)); + } + __cvmx_pko_reset(); +} + +/** + * Configure a output port and the associated queues for use. + * + * @port: Port to configure. + * @base_queue: First queue number to associate with this port. + * @num_queues: Number of queues to associate with this port + * @priority: Array of priority levels for each queue. Values are + * allowed to be 0-8. A value of 8 get 8 times the traffic + * of a value of 1. A value of 0 indicates that no rounds + * will be participated in. These priorities can be changed + * on the fly while the pko is enabled. A priority of 9 + * indicates that static priority should be used. If static + * priority is used all queues with static priority must be + * contiguous starting at the base_queue, and lower numbered + * queues have higher priority than higher numbered queues. + * There must be num_queues elements in the array. + */ +cvmx_pko_status_t cvmx_pko_config_port(uint64_t port, uint64_t base_queue, + uint64_t num_queues, + const uint64_t priority[]) +{ + cvmx_pko_status_t result_code; + uint64_t queue; + union cvmx_pko_mem_queue_ptrs config; + union cvmx_pko_reg_queue_ptrs1 config1; + int static_priority_base = -1; + int static_priority_end = -1; + + if ((port >= CVMX_PKO_NUM_OUTPUT_PORTS) + && (port != CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID)) { + cvmx_dprintf("ERROR: cvmx_pko_config_port: Invalid port %llu\n", + (unsigned long long)port); + return CVMX_PKO_INVALID_PORT; + } + + if (base_queue + num_queues > CVMX_PKO_MAX_OUTPUT_QUEUES) { + cvmx_dprintf + ("ERROR: cvmx_pko_config_port: Invalid queue range %llu\n", + (unsigned long long)(base_queue + num_queues)); + return CVMX_PKO_INVALID_QUEUE; + } + + if (port != CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID) { + /* + * Validate the static queue priority setup and set + * static_priority_base and static_priority_end + * accordingly. + */ + for (queue = 0; queue < num_queues; queue++) { + /* Find first queue of static priority */ + if (static_priority_base == -1 + && priority[queue] == + CVMX_PKO_QUEUE_STATIC_PRIORITY) + static_priority_base = queue; + /* Find last queue of static priority */ + if (static_priority_base != -1 + && static_priority_end == -1 + && priority[queue] != CVMX_PKO_QUEUE_STATIC_PRIORITY + && queue) + static_priority_end = queue - 1; + else if (static_priority_base != -1 + && static_priority_end == -1 + && queue == num_queues - 1) + /* all queues are static priority */ + static_priority_end = queue; + /* + * Check to make sure all static priority + * queues are contiguous. Also catches some + * cases of static priorites not starting at + * queue 0. + */ + if (static_priority_end != -1 + && (int)queue > static_priority_end + && priority[queue] == + CVMX_PKO_QUEUE_STATIC_PRIORITY) { + cvmx_dprintf("ERROR: cvmx_pko_config_port: " + "Static priority queues aren't " + "contiguous or don't start at " + "base queue. q: %d, eq: %d\n", + (int)queue, static_priority_end); + return CVMX_PKO_INVALID_PRIORITY; + } + } + if (static_priority_base > 0) { + cvmx_dprintf("ERROR: cvmx_pko_config_port: Static " + "priority queues don't start at base " + "queue. sq: %d\n", + static_priority_base); + return CVMX_PKO_INVALID_PRIORITY; + } +#if 0 + cvmx_dprintf("Port %d: Static priority queue base: %d, " + "end: %d\n", port, + static_priority_base, static_priority_end); +#endif + } + /* + * At this point, static_priority_base and static_priority_end + * are either both -1, or are valid start/end queue + * numbers. + */ + + result_code = CVMX_PKO_SUCCESS; + +#ifdef PKO_DEBUG + cvmx_dprintf("num queues: %d (%lld,%lld)\n", num_queues, + CVMX_PKO_QUEUES_PER_PORT_INTERFACE0, + CVMX_PKO_QUEUES_PER_PORT_INTERFACE1); +#endif + + for (queue = 0; queue < num_queues; queue++) { + uint64_t *buf_ptr = NULL; + + config1.u64 = 0; + config1.s.idx3 = queue >> 3; + config1.s.qid7 = (base_queue + queue) >> 7; + + config.u64 = 0; + config.s.tail = queue == (num_queues - 1); + config.s.index = queue; + config.s.port = port; + config.s.queue = base_queue + queue; + + if (!cvmx_octeon_is_pass1()) { + config.s.static_p = static_priority_base >= 0; + config.s.static_q = (int)queue <= static_priority_end; + config.s.s_tail = (int)queue == static_priority_end; + } + /* + * Convert the priority into an enable bit field. Try + * to space the bits out evenly so the packet don't + * get grouped up + */ + switch ((int)priority[queue]) { + case 0: + config.s.qos_mask = 0x00; + break; + case 1: + config.s.qos_mask = 0x01; + break; + case 2: + config.s.qos_mask = 0x11; + break; + case 3: + config.s.qos_mask = 0x49; + break; + case 4: + config.s.qos_mask = 0x55; + break; + case 5: + config.s.qos_mask = 0x57; + break; + case 6: + config.s.qos_mask = 0x77; + break; + case 7: + config.s.qos_mask = 0x7f; + break; + case 8: + config.s.qos_mask = 0xff; + break; + case CVMX_PKO_QUEUE_STATIC_PRIORITY: + /* Pass 1 will fall through to the error case */ + if (!cvmx_octeon_is_pass1()) { + config.s.qos_mask = 0xff; + break; + } + default: + cvmx_dprintf("ERROR: cvmx_pko_config_port: Invalid " + "priority %llu\n", + (unsigned long long)priority[queue]); + config.s.qos_mask = 0xff; + result_code = CVMX_PKO_INVALID_PRIORITY; + break; + } + + if (port != CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID) { + cvmx_cmd_queue_result_t cmd_res = + cvmx_cmd_queue_initialize(CVMX_CMD_QUEUE_PKO + (base_queue + queue), + CVMX_PKO_MAX_QUEUE_DEPTH, + CVMX_FPA_OUTPUT_BUFFER_POOL, + CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE + - + CVMX_PKO_COMMAND_BUFFER_SIZE_ADJUST + * 8); + if (cmd_res != CVMX_CMD_QUEUE_SUCCESS) { + switch (cmd_res) { + case CVMX_CMD_QUEUE_NO_MEMORY: + cvmx_dprintf("ERROR: " + "cvmx_pko_config_port: " + "Unable to allocate " + "output buffer.\n"); + return CVMX_PKO_NO_MEMORY; + case CVMX_CMD_QUEUE_ALREADY_SETUP: + cvmx_dprintf + ("ERROR: cvmx_pko_config_port: Port already setup.\n"); + return CVMX_PKO_PORT_ALREADY_SETUP; + case CVMX_CMD_QUEUE_INVALID_PARAM: + default: + cvmx_dprintf + ("ERROR: cvmx_pko_config_port: Command queue initialization failed.\n"); + return CVMX_PKO_CMD_QUEUE_INIT_ERROR; + } + } + + buf_ptr = + (uint64_t *) + cvmx_cmd_queue_buffer(CVMX_CMD_QUEUE_PKO + (base_queue + queue)); + config.s.buf_ptr = cvmx_ptr_to_phys(buf_ptr); + } else + config.s.buf_ptr = 0; + + CVMX_SYNCWS; + + if (!OCTEON_IS_MODEL(OCTEON_CN3XXX)) + cvmx_write_csr(CVMX_PKO_REG_QUEUE_PTRS1, config1.u64); + cvmx_write_csr(CVMX_PKO_MEM_QUEUE_PTRS, config.u64); + } + + return result_code; +} + +#ifdef PKO_DEBUG +/** + * Show map of ports -> queues for different cores. + */ +void cvmx_pko_show_queue_map() +{ + int core, port; + int pko_output_ports = 36; + + cvmx_dprintf("port"); + for (port = 0; port < pko_output_ports; port++) + cvmx_dprintf("%3d ", port); + cvmx_dprintf("\n"); + + for (core = 0; core < CVMX_MAX_CORES; core++) { + cvmx_dprintf("\n%2d: ", core); + for (port = 0; port < pko_output_ports; port++) { + cvmx_dprintf("%3d ", + cvmx_pko_get_base_queue_per_core(port, + core)); + } + } + cvmx_dprintf("\n"); +} +#endif + +/** + * Rate limit a PKO port to a max packets/sec. This function is only + * supported on CN51XX and higher, excluding CN58XX. + * + * @port: Port to rate limit + * @packets_s: Maximum packet/sec + * @burst: Maximum number of packets to burst in a row before rate + * limiting cuts in. + * + * Returns Zero on success, negative on failure + */ +int cvmx_pko_rate_limit_packets(int port, int packets_s, int burst) +{ + union cvmx_pko_mem_port_rate0 pko_mem_port_rate0; + union cvmx_pko_mem_port_rate1 pko_mem_port_rate1; + + pko_mem_port_rate0.u64 = 0; + pko_mem_port_rate0.s.pid = port; + pko_mem_port_rate0.s.rate_pkt = + cvmx_sysinfo_get()->cpu_clock_hz / packets_s / 16; + /* No cost per word since we are limited by packets/sec, not bits/sec */ + pko_mem_port_rate0.s.rate_word = 0; + + pko_mem_port_rate1.u64 = 0; + pko_mem_port_rate1.s.pid = port; + pko_mem_port_rate1.s.rate_lim = + ((uint64_t) pko_mem_port_rate0.s.rate_pkt * burst) >> 8; + + cvmx_write_csr(CVMX_PKO_MEM_PORT_RATE0, pko_mem_port_rate0.u64); + cvmx_write_csr(CVMX_PKO_MEM_PORT_RATE1, pko_mem_port_rate1.u64); + return 0; +} + +/** + * Rate limit a PKO port to a max bits/sec. This function is only + * supported on CN51XX and higher, excluding CN58XX. + * + * @port: Port to rate limit + * @bits_s: PKO rate limit in bits/sec + * @burst: Maximum number of bits to burst before rate + * limiting cuts in. + * + * Returns Zero on success, negative on failure + */ +int cvmx_pko_rate_limit_bits(int port, uint64_t bits_s, int burst) +{ + union cvmx_pko_mem_port_rate0 pko_mem_port_rate0; + union cvmx_pko_mem_port_rate1 pko_mem_port_rate1; + uint64_t clock_rate = cvmx_sysinfo_get()->cpu_clock_hz; + uint64_t tokens_per_bit = clock_rate * 16 / bits_s; + + pko_mem_port_rate0.u64 = 0; + pko_mem_port_rate0.s.pid = port; + /* + * Each packet has a 12 bytes of interframe gap, an 8 byte + * preamble, and a 4 byte CRC. These are not included in the + * per word count. Multiply by 8 to covert to bits and divide + * by 256 for limit granularity. + */ + pko_mem_port_rate0.s.rate_pkt = (12 + 8 + 4) * 8 * tokens_per_bit / 256; + /* Each 8 byte word has 64bits */ + pko_mem_port_rate0.s.rate_word = 64 * tokens_per_bit; + + pko_mem_port_rate1.u64 = 0; + pko_mem_port_rate1.s.pid = port; + pko_mem_port_rate1.s.rate_lim = tokens_per_bit * burst / 256; + + cvmx_write_csr(CVMX_PKO_MEM_PORT_RATE0, pko_mem_port_rate0.u64); + cvmx_write_csr(CVMX_PKO_MEM_PORT_RATE1, pko_mem_port_rate1.u64); + return 0; +} diff --git a/drivers/staging/octeon/cvmx-pko.h b/drivers/staging/octeon/cvmx-pko.h new file mode 100644 index 000000000000..f068c1982497 --- /dev/null +++ b/drivers/staging/octeon/cvmx-pko.h @@ -0,0 +1,610 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2008 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +/** + * + * Interface to the hardware Packet Output unit. + * + * Starting with SDK 1.7.0, the PKO output functions now support + * two types of locking. CVMX_PKO_LOCK_ATOMIC_TAG continues to + * function similarly to previous SDKs by using POW atomic tags + * to preserve ordering and exclusivity. As a new option, you + * can now pass CVMX_PKO_LOCK_CMD_QUEUE which uses a ll/sc + * memory based locking instead. This locking has the advantage + * of not affecting the tag state but doesn't preserve packet + * ordering. CVMX_PKO_LOCK_CMD_QUEUE is appropriate in most + * generic code while CVMX_PKO_LOCK_CMD_QUEUE should be used + * with hand tuned fast path code. + * + * Some of other SDK differences visible to the command command + * queuing: + * - PKO indexes are no longer stored in the FAU. A large + * percentage of the FAU register block used to be tied up + * maintaining PKO queue pointers. These are now stored in a + * global named block. + * - The PKO use_locking parameter can now have a global + * effect. Since all application use the same named block, + * queue locking correctly applies across all operating + * systems when using CVMX_PKO_LOCK_CMD_QUEUE. + * - PKO 3 word commands are now supported. Use + * cvmx_pko_send_packet_finish3(). + * + */ + +#ifndef __CVMX_PKO_H__ +#define __CVMX_PKO_H__ + +#include "cvmx-fpa.h" +#include "cvmx-pow.h" +#include "cvmx-cmd-queue.h" +#include "cvmx-pko-defs.h" + +/* Adjust the command buffer size by 1 word so that in the case of using only + * two word PKO commands no command words stradle buffers. The useful values + * for this are 0 and 1. */ +#define CVMX_PKO_COMMAND_BUFFER_SIZE_ADJUST (1) + +#define CVMX_PKO_MAX_OUTPUT_QUEUES_STATIC 256 +#define CVMX_PKO_MAX_OUTPUT_QUEUES ((OCTEON_IS_MODEL(OCTEON_CN31XX) || \ + OCTEON_IS_MODEL(OCTEON_CN3010) || OCTEON_IS_MODEL(OCTEON_CN3005) || \ + OCTEON_IS_MODEL(OCTEON_CN50XX)) ? 32 : \ + (OCTEON_IS_MODEL(OCTEON_CN58XX) || \ + OCTEON_IS_MODEL(OCTEON_CN56XX)) ? 256 : 128) +#define CVMX_PKO_NUM_OUTPUT_PORTS 40 +/* use this for queues that are not used */ +#define CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID 63 +#define CVMX_PKO_QUEUE_STATIC_PRIORITY 9 +#define CVMX_PKO_ILLEGAL_QUEUE 0xFFFF +#define CVMX_PKO_MAX_QUEUE_DEPTH 0 + +typedef enum { + CVMX_PKO_SUCCESS, + CVMX_PKO_INVALID_PORT, + CVMX_PKO_INVALID_QUEUE, + CVMX_PKO_INVALID_PRIORITY, + CVMX_PKO_NO_MEMORY, + CVMX_PKO_PORT_ALREADY_SETUP, + CVMX_PKO_CMD_QUEUE_INIT_ERROR +} cvmx_pko_status_t; + +/** + * This enumeration represents the differnet locking modes supported by PKO. + */ +typedef enum { + /* + * PKO doesn't do any locking. It is the responsibility of the + * application to make sure that no other core is accessing + * the same queue at the smae time + */ + CVMX_PKO_LOCK_NONE = 0, + /* + * PKO performs an atomic tagswitch to insure exclusive access + * to the output queue. This will maintain packet ordering on + * output. + */ + CVMX_PKO_LOCK_ATOMIC_TAG = 1, + /* + * PKO uses the common command queue locks to insure exclusive + * access to the output queue. This is a memory based + * ll/sc. This is the most portable locking mechanism. + */ + CVMX_PKO_LOCK_CMD_QUEUE = 2, +} cvmx_pko_lock_t; + +typedef struct { + uint32_t packets; + uint64_t octets; + uint64_t doorbell; +} cvmx_pko_port_status_t; + +/** + * This structure defines the address to use on a packet enqueue + */ +typedef union { + uint64_t u64; + struct { + /* Must CVMX_IO_SEG */ + uint64_t mem_space:2; + /* Must be zero */ + uint64_t reserved:13; + /* Must be one */ + uint64_t is_io:1; + /* The ID of the device on the non-coherent bus */ + uint64_t did:8; + /* Must be zero */ + uint64_t reserved2:4; + /* Must be zero */ + uint64_t reserved3:18; + /* + * The hardware likes to have the output port in + * addition to the output queue, + */ + uint64_t port:6; + /* + * The output queue to send the packet to (0-127 are + * legal) + */ + uint64_t queue:9; + /* Must be zero */ + uint64_t reserved4:3; + } s; +} cvmx_pko_doorbell_address_t; + +/** + * Structure of the first packet output command word. + */ +typedef union { + uint64_t u64; + struct { + /* + * The size of the reg1 operation - could be 8, 16, + * 32, or 64 bits. + */ + uint64_t size1:2; + /* + * The size of the reg0 operation - could be 8, 16, + * 32, or 64 bits. + */ + uint64_t size0:2; + /* + * If set, subtract 1, if clear, subtract packet + * size. + */ + uint64_t subone1:1; + /* + * The register, subtract will be done if reg1 is + * non-zero. + */ + uint64_t reg1:11; + /* If set, subtract 1, if clear, subtract packet size */ + uint64_t subone0:1; + /* The register, subtract will be done if reg0 is non-zero */ + uint64_t reg0:11; + /* + * When set, interpret segment pointer and segment + * bytes in little endian order. + */ + uint64_t le:1; + /* + * When set, packet data not allocated in L2 cache by + * PKO. + */ + uint64_t n2:1; + /* + * If set and rsp is set, word3 contains a pointer to + * a work queue entry. + */ + uint64_t wqp:1; + /* If set, the hardware will send a response when done */ + uint64_t rsp:1; + /* + * If set, the supplied pkt_ptr is really a pointer to + * a list of pkt_ptr's. + */ + uint64_t gather:1; + /* + * If ipoffp1 is non zero, (ipoffp1-1) is the number + * of bytes to IP header, and the hardware will + * calculate and insert the UDP/TCP checksum. + */ + uint64_t ipoffp1:7; + /* + * If set, ignore the I bit (force to zero) from all + * pointer structures. + */ + uint64_t ignore_i:1; + /* + * If clear, the hardware will attempt to free the + * buffers containing the packet. + */ + uint64_t dontfree:1; + /* + * The total number of segs in the packet, if gather + * set, also gather list length. + */ + uint64_t segs:6; + /* Including L2, but no trailing CRC */ + uint64_t total_bytes:16; + } s; +} cvmx_pko_command_word0_t; + +/* CSR typedefs have been moved to cvmx-csr-*.h */ + +/** + * Definition of internal state for Packet output processing + */ +typedef struct { + /* ptr to start of buffer, offset kept in FAU reg */ + uint64_t *start_ptr; +} cvmx_pko_state_elem_t; + +/** + * Call before any other calls to initialize the packet + * output system. + */ +extern void cvmx_pko_initialize_global(void); +extern int cvmx_pko_initialize_local(void); + +/** + * Enables the packet output hardware. It must already be + * configured. + */ +extern void cvmx_pko_enable(void); + +/** + * Disables the packet output. Does not affect any configuration. + */ +extern void cvmx_pko_disable(void); + +/** + * Shutdown and free resources required by packet output. + */ + +extern void cvmx_pko_shutdown(void); + +/** + * Configure a output port and the associated queues for use. + * + * @port: Port to configure. + * @base_queue: First queue number to associate with this port. + * @num_queues: Number of queues t oassociate with this port + * @priority: Array of priority levels for each queue. Values are + * allowed to be 1-8. A value of 8 get 8 times the traffic + * of a value of 1. There must be num_queues elements in the + * array. + */ +extern cvmx_pko_status_t cvmx_pko_config_port(uint64_t port, + uint64_t base_queue, + uint64_t num_queues, + const uint64_t priority[]); + +/** + * Ring the packet output doorbell. This tells the packet + * output hardware that "len" command words have been added + * to its pending list. This command includes the required + * CVMX_SYNCWS before the doorbell ring. + * + * @port: Port the packet is for + * @queue: Queue the packet is for + * @len: Length of the command in 64 bit words + */ +static inline void cvmx_pko_doorbell(uint64_t port, uint64_t queue, + uint64_t len) +{ + cvmx_pko_doorbell_address_t ptr; + + ptr.u64 = 0; + ptr.s.mem_space = CVMX_IO_SEG; + ptr.s.did = CVMX_OCT_DID_PKT_SEND; + ptr.s.is_io = 1; + ptr.s.port = port; + ptr.s.queue = queue; + /* + * Need to make sure output queue data is in DRAM before + * doorbell write. + */ + CVMX_SYNCWS; + cvmx_write_io(ptr.u64, len); +} + +/** + * Prepare to send a packet. This may initiate a tag switch to + * get exclusive access to the output queue structure, and + * performs other prep work for the packet send operation. + * + * cvmx_pko_send_packet_finish() MUST be called after this function is called, + * and must be called with the same port/queue/use_locking arguments. + * + * The use_locking parameter allows the caller to use three + * possible locking modes. + * - CVMX_PKO_LOCK_NONE + * - PKO doesn't do any locking. It is the responsibility + * of the application to make sure that no other core + * is accessing the same queue at the smae time. + * - CVMX_PKO_LOCK_ATOMIC_TAG + * - PKO performs an atomic tagswitch to insure exclusive + * access to the output queue. This will maintain + * packet ordering on output. + * - CVMX_PKO_LOCK_CMD_QUEUE + * - PKO uses the common command queue locks to insure + * exclusive access to the output queue. This is a + * memory based ll/sc. This is the most portable + * locking mechanism. + * + * NOTE: If atomic locking is used, the POW entry CANNOT be + * descheduled, as it does not contain a valid WQE pointer. + * + * @port: Port to send it on + * @queue: Queue to use + * @use_locking: CVMX_PKO_LOCK_NONE, CVMX_PKO_LOCK_ATOMIC_TAG, or + * CVMX_PKO_LOCK_CMD_QUEUE + */ + +static inline void cvmx_pko_send_packet_prepare(uint64_t port, uint64_t queue, + cvmx_pko_lock_t use_locking) +{ + if (use_locking == CVMX_PKO_LOCK_ATOMIC_TAG) { + /* + * Must do a full switch here to handle all cases. We + * use a fake WQE pointer, as the POW does not access + * this memory. The WQE pointer and group are only + * used if this work is descheduled, which is not + * supported by the + * cvmx_pko_send_packet_prepare/cvmx_pko_send_packet_finish + * combination. Note that this is a special case in + * which these fake values can be used - this is not a + * general technique. + */ + uint32_t tag = + CVMX_TAG_SW_BITS_INTERNAL << CVMX_TAG_SW_SHIFT | + CVMX_TAG_SUBGROUP_PKO << CVMX_TAG_SUBGROUP_SHIFT | + (CVMX_TAG_SUBGROUP_MASK & queue); + cvmx_pow_tag_sw_full((cvmx_wqe_t *) cvmx_phys_to_ptr(0x80), tag, + CVMX_POW_TAG_TYPE_ATOMIC, 0); + } +} + +/** + * Complete packet output. cvmx_pko_send_packet_prepare() must be + * called exactly once before this, and the same parameters must be + * passed to both cvmx_pko_send_packet_prepare() and + * cvmx_pko_send_packet_finish(). + * + * @port: Port to send it on + * @queue: Queue to use + * @pko_command: + * PKO HW command word + * @packet: Packet to send + * @use_locking: CVMX_PKO_LOCK_NONE, CVMX_PKO_LOCK_ATOMIC_TAG, or + * CVMX_PKO_LOCK_CMD_QUEUE + * + * Returns returns CVMX_PKO_SUCCESS on success, or error code on + * failure of output + */ +static inline cvmx_pko_status_t cvmx_pko_send_packet_finish( + uint64_t port, + uint64_t queue, + cvmx_pko_command_word0_t pko_command, + union cvmx_buf_ptr packet, + cvmx_pko_lock_t use_locking) +{ + cvmx_cmd_queue_result_t result; + if (use_locking == CVMX_PKO_LOCK_ATOMIC_TAG) + cvmx_pow_tag_sw_wait(); + result = cvmx_cmd_queue_write2(CVMX_CMD_QUEUE_PKO(queue), + (use_locking == CVMX_PKO_LOCK_CMD_QUEUE), + pko_command.u64, packet.u64); + if (likely(result == CVMX_CMD_QUEUE_SUCCESS)) { + cvmx_pko_doorbell(port, queue, 2); + return CVMX_PKO_SUCCESS; + } else if ((result == CVMX_CMD_QUEUE_NO_MEMORY) + || (result == CVMX_CMD_QUEUE_FULL)) { + return CVMX_PKO_NO_MEMORY; + } else { + return CVMX_PKO_INVALID_QUEUE; + } +} + +/** + * Complete packet output. cvmx_pko_send_packet_prepare() must be + * called exactly once before this, and the same parameters must be + * passed to both cvmx_pko_send_packet_prepare() and + * cvmx_pko_send_packet_finish(). + * + * @port: Port to send it on + * @queue: Queue to use + * @pko_command: + * PKO HW command word + * @packet: Packet to send + * @addr: Plysical address of a work queue entry or physical address + * to zero on complete. + * @use_locking: CVMX_PKO_LOCK_NONE, CVMX_PKO_LOCK_ATOMIC_TAG, or + * CVMX_PKO_LOCK_CMD_QUEUE + * + * Returns returns CVMX_PKO_SUCCESS on success, or error code on + * failure of output + */ +static inline cvmx_pko_status_t cvmx_pko_send_packet_finish3( + uint64_t port, + uint64_t queue, + cvmx_pko_command_word0_t pko_command, + union cvmx_buf_ptr packet, + uint64_t addr, + cvmx_pko_lock_t use_locking) +{ + cvmx_cmd_queue_result_t result; + if (use_locking == CVMX_PKO_LOCK_ATOMIC_TAG) + cvmx_pow_tag_sw_wait(); + result = cvmx_cmd_queue_write3(CVMX_CMD_QUEUE_PKO(queue), + (use_locking == CVMX_PKO_LOCK_CMD_QUEUE), + pko_command.u64, packet.u64, addr); + if (likely(result == CVMX_CMD_QUEUE_SUCCESS)) { + cvmx_pko_doorbell(port, queue, 3); + return CVMX_PKO_SUCCESS; + } else if ((result == CVMX_CMD_QUEUE_NO_MEMORY) + || (result == CVMX_CMD_QUEUE_FULL)) { + return CVMX_PKO_NO_MEMORY; + } else { + return CVMX_PKO_INVALID_QUEUE; + } +} + +/** + * Return the pko output queue associated with a port and a specific core. + * In normal mode (PKO lockless operation is disabled), the value returned + * is the base queue. + * + * @port: Port number + * @core: Core to get queue for + * + * Returns Core-specific output queue + */ +static inline int cvmx_pko_get_base_queue_per_core(int port, int core) +{ +#ifndef CVMX_HELPER_PKO_MAX_PORTS_INTERFACE0 +#define CVMX_HELPER_PKO_MAX_PORTS_INTERFACE0 16 +#endif +#ifndef CVMX_HELPER_PKO_MAX_PORTS_INTERFACE1 +#define CVMX_HELPER_PKO_MAX_PORTS_INTERFACE1 16 +#endif + + if (port < CVMX_PKO_MAX_PORTS_INTERFACE0) + return port * CVMX_PKO_QUEUES_PER_PORT_INTERFACE0 + core; + else if (port >= 16 && port < 16 + CVMX_PKO_MAX_PORTS_INTERFACE1) + return CVMX_PKO_MAX_PORTS_INTERFACE0 * + CVMX_PKO_QUEUES_PER_PORT_INTERFACE0 + (port - + 16) * + CVMX_PKO_QUEUES_PER_PORT_INTERFACE1 + core; + else if ((port >= 32) && (port < 36)) + return CVMX_PKO_MAX_PORTS_INTERFACE0 * + CVMX_PKO_QUEUES_PER_PORT_INTERFACE0 + + CVMX_PKO_MAX_PORTS_INTERFACE1 * + CVMX_PKO_QUEUES_PER_PORT_INTERFACE1 + (port - + 32) * + CVMX_PKO_QUEUES_PER_PORT_PCI; + else if ((port >= 36) && (port < 40)) + return CVMX_PKO_MAX_PORTS_INTERFACE0 * + CVMX_PKO_QUEUES_PER_PORT_INTERFACE0 + + CVMX_PKO_MAX_PORTS_INTERFACE1 * + CVMX_PKO_QUEUES_PER_PORT_INTERFACE1 + + 4 * CVMX_PKO_QUEUES_PER_PORT_PCI + (port - + 36) * + CVMX_PKO_QUEUES_PER_PORT_LOOP; + else + /* Given the limit on the number of ports we can map to + * CVMX_MAX_OUTPUT_QUEUES_STATIC queues (currently 256, + * divided among all cores), the remaining unmapped ports + * are assigned an illegal queue number */ + return CVMX_PKO_ILLEGAL_QUEUE; +} + +/** + * For a given port number, return the base pko output queue + * for the port. + * + * @port: Port number + * Returns Base output queue + */ +static inline int cvmx_pko_get_base_queue(int port) +{ + return cvmx_pko_get_base_queue_per_core(port, 0); +} + +/** + * For a given port number, return the number of pko output queues. + * + * @port: Port number + * Returns Number of output queues + */ +static inline int cvmx_pko_get_num_queues(int port) +{ + if (port < 16) + return CVMX_PKO_QUEUES_PER_PORT_INTERFACE0; + else if (port < 32) + return CVMX_PKO_QUEUES_PER_PORT_INTERFACE1; + else if (port < 36) + return CVMX_PKO_QUEUES_PER_PORT_PCI; + else if (port < 40) + return CVMX_PKO_QUEUES_PER_PORT_LOOP; + else + return 0; +} + +/** + * Get the status counters for a port. + * + * @port_num: Port number to get statistics for. + * @clear: Set to 1 to clear the counters after they are read + * @status: Where to put the results. + */ +static inline void cvmx_pko_get_port_status(uint64_t port_num, uint64_t clear, + cvmx_pko_port_status_t *status) +{ + union cvmx_pko_reg_read_idx pko_reg_read_idx; + union cvmx_pko_mem_count0 pko_mem_count0; + union cvmx_pko_mem_count1 pko_mem_count1; + + pko_reg_read_idx.u64 = 0; + pko_reg_read_idx.s.index = port_num; + cvmx_write_csr(CVMX_PKO_REG_READ_IDX, pko_reg_read_idx.u64); + + pko_mem_count0.u64 = cvmx_read_csr(CVMX_PKO_MEM_COUNT0); + status->packets = pko_mem_count0.s.count; + if (clear) { + pko_mem_count0.s.count = port_num; + cvmx_write_csr(CVMX_PKO_MEM_COUNT0, pko_mem_count0.u64); + } + + pko_mem_count1.u64 = cvmx_read_csr(CVMX_PKO_MEM_COUNT1); + status->octets = pko_mem_count1.s.count; + if (clear) { + pko_mem_count1.s.count = port_num; + cvmx_write_csr(CVMX_PKO_MEM_COUNT1, pko_mem_count1.u64); + } + + if (OCTEON_IS_MODEL(OCTEON_CN3XXX)) { + union cvmx_pko_mem_debug9 debug9; + pko_reg_read_idx.s.index = cvmx_pko_get_base_queue(port_num); + cvmx_write_csr(CVMX_PKO_REG_READ_IDX, pko_reg_read_idx.u64); + debug9.u64 = cvmx_read_csr(CVMX_PKO_MEM_DEBUG9); + status->doorbell = debug9.cn38xx.doorbell; + } else { + union cvmx_pko_mem_debug8 debug8; + pko_reg_read_idx.s.index = cvmx_pko_get_base_queue(port_num); + cvmx_write_csr(CVMX_PKO_REG_READ_IDX, pko_reg_read_idx.u64); + debug8.u64 = cvmx_read_csr(CVMX_PKO_MEM_DEBUG8); + status->doorbell = debug8.cn58xx.doorbell; + } +} + +/** + * Rate limit a PKO port to a max packets/sec. This function is only + * supported on CN57XX, CN56XX, CN55XX, and CN54XX. + * + * @port: Port to rate limit + * @packets_s: Maximum packet/sec + * @burst: Maximum number of packets to burst in a row before rate + * limiting cuts in. + * + * Returns Zero on success, negative on failure + */ +extern int cvmx_pko_rate_limit_packets(int port, int packets_s, int burst); + +/** + * Rate limit a PKO port to a max bits/sec. This function is only + * supported on CN57XX, CN56XX, CN55XX, and CN54XX. + * + * @port: Port to rate limit + * @bits_s: PKO rate limit in bits/sec + * @burst: Maximum number of bits to burst before rate + * limiting cuts in. + * + * Returns Zero on success, negative on failure + */ +extern int cvmx_pko_rate_limit_bits(int port, uint64_t bits_s, int burst); + +#endif /* __CVMX_PKO_H__ */ diff --git a/drivers/staging/octeon/cvmx-pow.h b/drivers/staging/octeon/cvmx-pow.h new file mode 100644 index 000000000000..c5d66f272b0d --- /dev/null +++ b/drivers/staging/octeon/cvmx-pow.h @@ -0,0 +1,1982 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2008 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +/** + * Interface to the hardware Packet Order / Work unit. + * + * New, starting with SDK 1.7.0, cvmx-pow supports a number of + * extended consistency checks. The define + * CVMX_ENABLE_POW_CHECKS controls the runtime insertion of POW + * internal state checks to find common programming errors. If + * CVMX_ENABLE_POW_CHECKS is not defined, checks are by default + * enabled. For example, cvmx-pow will check for the following + * program errors or POW state inconsistency. + * - Requesting a POW operation with an active tag switch in + * progress. + * - Waiting for a tag switch to complete for an excessively + * long period. This is normally a sign of an error in locking + * causing deadlock. + * - Illegal tag switches from NULL_NULL. + * - Illegal tag switches from NULL. + * - Illegal deschedule request. + * - WQE pointer not matching the one attached to the core by + * the POW. + * + */ + +#ifndef __CVMX_POW_H__ +#define __CVMX_POW_H__ + +#include + +#include "cvmx-scratch.h" +#include "cvmx-wqe.h" + +/* Default to having all POW constancy checks turned on */ +#ifndef CVMX_ENABLE_POW_CHECKS +#define CVMX_ENABLE_POW_CHECKS 1 +#endif + +enum cvmx_pow_tag_type { + /* Tag ordering is maintained */ + CVMX_POW_TAG_TYPE_ORDERED = 0L, + /* Tag ordering is maintained, and at most one PP has the tag */ + CVMX_POW_TAG_TYPE_ATOMIC = 1L, + /* + * The work queue entry from the order - NEVER tag switch from + * NULL to NULL + */ + CVMX_POW_TAG_TYPE_NULL = 2L, + /* A tag switch to NULL, and there is no space reserved in POW + * - NEVER tag switch to NULL_NULL + * - NEVER tag switch from NULL_NULL + * - NULL_NULL is entered at the beginning of time and on a deschedule. + * - NULL_NULL can be exited by a new work request. A NULL_SWITCH + * load can also switch the state to NULL + */ + CVMX_POW_TAG_TYPE_NULL_NULL = 3L +}; + +/** + * Wait flag values for pow functions. + */ +typedef enum { + CVMX_POW_WAIT = 1, + CVMX_POW_NO_WAIT = 0, +} cvmx_pow_wait_t; + +/** + * POW tag operations. These are used in the data stored to the POW. + */ +typedef enum { + /* + * switch the tag (only) for this PP + * - the previous tag should be non-NULL in this case + * - tag switch response required + * - fields used: op, type, tag + */ + CVMX_POW_TAG_OP_SWTAG = 0L, + /* + * switch the tag for this PP, with full information + * - this should be used when the previous tag is NULL + * - tag switch response required + * - fields used: address, op, grp, type, tag + */ + CVMX_POW_TAG_OP_SWTAG_FULL = 1L, + /* + * switch the tag (and/or group) for this PP and de-schedule + * - OK to keep the tag the same and only change the group + * - fields used: op, no_sched, grp, type, tag + */ + CVMX_POW_TAG_OP_SWTAG_DESCH = 2L, + /* + * just de-schedule + * - fields used: op, no_sched + */ + CVMX_POW_TAG_OP_DESCH = 3L, + /* + * create an entirely new work queue entry + * - fields used: address, op, qos, grp, type, tag + */ + CVMX_POW_TAG_OP_ADDWQ = 4L, + /* + * just update the work queue pointer and grp for this PP + * - fields used: address, op, grp + */ + CVMX_POW_TAG_OP_UPDATE_WQP_GRP = 5L, + /* + * set the no_sched bit on the de-schedule list + * + * - does nothing if the selected entry is not on the + * de-schedule list + * + * - does nothing if the stored work queue pointer does not + * match the address field + * + * - fields used: address, index, op + * + * Before issuing a *_NSCHED operation, SW must guarantee + * that all prior deschedules and set/clr NSCHED operations + * are complete and all prior switches are complete. The + * hardware provides the opsdone bit and swdone bit for SW + * polling. After issuing a *_NSCHED operation, SW must + * guarantee that the set/clr NSCHED is complete before any + * subsequent operations. + */ + CVMX_POW_TAG_OP_SET_NSCHED = 6L, + /* + * clears the no_sched bit on the de-schedule list + * + * - does nothing if the selected entry is not on the + * de-schedule list + * + * - does nothing if the stored work queue pointer does not + * match the address field + * + * - fields used: address, index, op + * + * Before issuing a *_NSCHED operation, SW must guarantee that + * all prior deschedules and set/clr NSCHED operations are + * complete and all prior switches are complete. The hardware + * provides the opsdone bit and swdone bit for SW + * polling. After issuing a *_NSCHED operation, SW must + * guarantee that the set/clr NSCHED is complete before any + * subsequent operations. + */ + CVMX_POW_TAG_OP_CLR_NSCHED = 7L, + /* do nothing */ + CVMX_POW_TAG_OP_NOP = 15L +} cvmx_pow_tag_op_t; + +/** + * This structure defines the store data on a store to POW + */ +typedef union { + uint64_t u64; + struct { + /* + * Don't reschedule this entry. no_sched is used for + * CVMX_POW_TAG_OP_SWTAG_DESCH and + * CVMX_POW_TAG_OP_DESCH + */ + uint64_t no_sched:1; + uint64_t unused:2; + /* Tontains index of entry for a CVMX_POW_TAG_OP_*_NSCHED */ + uint64_t index:13; + /* The operation to perform */ + cvmx_pow_tag_op_t op:4; + uint64_t unused2:2; + /* + * The QOS level for the packet. qos is only used for + * CVMX_POW_TAG_OP_ADDWQ + */ + uint64_t qos:3; + /* + * The group that the work queue entry will be + * scheduled to grp is used for CVMX_POW_TAG_OP_ADDWQ, + * CVMX_POW_TAG_OP_SWTAG_FULL, + * CVMX_POW_TAG_OP_SWTAG_DESCH, and + * CVMX_POW_TAG_OP_UPDATE_WQP_GRP + */ + uint64_t grp:4; + /* + * The type of the tag. type is used for everything + * except CVMX_POW_TAG_OP_DESCH, + * CVMX_POW_TAG_OP_UPDATE_WQP_GRP, and + * CVMX_POW_TAG_OP_*_NSCHED + */ + uint64_t type:3; + /* + * The actual tag. tag is used for everything except + * CVMX_POW_TAG_OP_DESCH, + * CVMX_POW_TAG_OP_UPDATE_WQP_GRP, and + * CVMX_POW_TAG_OP_*_NSCHED + */ + uint64_t tag:32; + } s; +} cvmx_pow_tag_req_t; + +/** + * This structure describes the address to load stuff from POW + */ +typedef union { + uint64_t u64; + + /** + * Address for new work request loads (did<2:0> == 0) + */ + struct { + /* Mips64 address region. Should be CVMX_IO_SEG */ + uint64_t mem_region:2; + /* Must be zero */ + uint64_t reserved_49_61:13; + /* Must be one */ + uint64_t is_io:1; + /* the ID of POW -- did<2:0> == 0 in this case */ + uint64_t did:8; + /* Must be zero */ + uint64_t reserved_4_39:36; + /* + * If set, don't return load response until work is + * available. + */ + uint64_t wait:1; + /* Must be zero */ + uint64_t reserved_0_2:3; + } swork; + + /** + * Address for loads to get POW internal status + */ + struct { + /* Mips64 address region. Should be CVMX_IO_SEG */ + uint64_t mem_region:2; + /* Must be zero */ + uint64_t reserved_49_61:13; + /* Must be one */ + uint64_t is_io:1; + /* the ID of POW -- did<2:0> == 1 in this case */ + uint64_t did:8; + /* Must be zero */ + uint64_t reserved_10_39:30; + /* The core id to get status for */ + uint64_t coreid:4; + /* + * If set and get_cur is set, return reverse tag-list + * pointer rather than forward tag-list pointer. + */ + uint64_t get_rev:1; + /* + * If set, return current status rather than pending + * status. + */ + uint64_t get_cur:1; + /* + * If set, get the work-queue pointer rather than + * tag/type. + */ + uint64_t get_wqp:1; + /* Must be zero */ + uint64_t reserved_0_2:3; + } sstatus; + + /** + * Address for memory loads to get POW internal state + */ + struct { + /* Mips64 address region. Should be CVMX_IO_SEG */ + uint64_t mem_region:2; + /* Must be zero */ + uint64_t reserved_49_61:13; + /* Must be one */ + uint64_t is_io:1; + /* the ID of POW -- did<2:0> == 2 in this case */ + uint64_t did:8; + /* Must be zero */ + uint64_t reserved_16_39:24; + /* POW memory index */ + uint64_t index:11; + /* + * If set, return deschedule information rather than + * the standard response for work-queue index (invalid + * if the work-queue entry is not on the deschedule + * list). + */ + uint64_t get_des:1; + /* + * If set, get the work-queue pointer rather than + * tag/type (no effect when get_des set). + */ + uint64_t get_wqp:1; + /* Must be zero */ + uint64_t reserved_0_2:3; + } smemload; + + /** + * Address for index/pointer loads + */ + struct { + /* Mips64 address region. Should be CVMX_IO_SEG */ + uint64_t mem_region:2; + /* Must be zero */ + uint64_t reserved_49_61:13; + /* Must be one */ + uint64_t is_io:1; + /* the ID of POW -- did<2:0> == 3 in this case */ + uint64_t did:8; + /* Must be zero */ + uint64_t reserved_9_39:31; + /* + * when {get_rmt ==0 AND get_des_get_tail == 0}, this + * field selects one of eight POW internal-input + * queues (0-7), one per QOS level; values 8-15 are + * illegal in this case; when {get_rmt ==0 AND + * get_des_get_tail == 1}, this field selects one of + * 16 deschedule lists (per group); when get_rmt ==1, + * this field selects one of 16 memory-input queue + * lists. The two memory-input queue lists associated + * with each QOS level are: + * + * - qosgrp = 0, qosgrp = 8: QOS0 + * - qosgrp = 1, qosgrp = 9: QOS1 + * - qosgrp = 2, qosgrp = 10: QOS2 + * - qosgrp = 3, qosgrp = 11: QOS3 + * - qosgrp = 4, qosgrp = 12: QOS4 + * - qosgrp = 5, qosgrp = 13: QOS5 + * - qosgrp = 6, qosgrp = 14: QOS6 + * - qosgrp = 7, qosgrp = 15: QOS7 + */ + uint64_t qosgrp:4; + /* + * If set and get_rmt is clear, return deschedule list + * indexes rather than indexes for the specified qos + * level; if set and get_rmt is set, return the tail + * pointer rather than the head pointer for the + * specified qos level. + */ + uint64_t get_des_get_tail:1; + /* + * If set, return remote pointers rather than the + * local indexes for the specified qos level. + */ + uint64_t get_rmt:1; + /* Must be zero */ + uint64_t reserved_0_2:3; + } sindexload; + + /** + * address for NULL_RD request (did<2:0> == 4) when this is read, + * HW attempts to change the state to NULL if it is NULL_NULL (the + * hardware cannot switch from NULL_NULL to NULL if a POW entry is + * not available - software may need to recover by finishing + * another piece of work before a POW entry can ever become + * available.) + */ + struct { + /* Mips64 address region. Should be CVMX_IO_SEG */ + uint64_t mem_region:2; + /* Must be zero */ + uint64_t reserved_49_61:13; + /* Must be one */ + uint64_t is_io:1; + /* the ID of POW -- did<2:0> == 4 in this case */ + uint64_t did:8; + /* Must be zero */ + uint64_t reserved_0_39:40; + } snull_rd; +} cvmx_pow_load_addr_t; + +/** + * This structure defines the response to a load/SENDSINGLE to POW + * (except CSR reads) + */ +typedef union { + uint64_t u64; + + /** + * Response to new work request loads + */ + struct { + /* + * Set when no new work queue entry was returned. * + * If there was de-scheduled work, the HW will + * definitely return it. When this bit is set, it + * could mean either mean: + * + * - There was no work, or + * + * - There was no work that the HW could find. This + * case can happen, regardless of the wait bit value + * in the original request, when there is work in + * the IQ's that is too deep down the list. + */ + uint64_t no_work:1; + /* Must be zero */ + uint64_t reserved_40_62:23; + /* 36 in O1 -- the work queue pointer */ + uint64_t addr:40; + } s_work; + + /** + * Result for a POW Status Load (when get_cur==0 and get_wqp==0) + */ + struct { + uint64_t reserved_62_63:2; + /* Set when there is a pending non-NULL SWTAG or + * SWTAG_FULL, and the POW entry has not left the list + * for the original tag. */ + uint64_t pend_switch:1; + /* Set when SWTAG_FULL and pend_switch is set. */ + uint64_t pend_switch_full:1; + /* + * Set when there is a pending NULL SWTAG, or an + * implicit switch to NULL. + */ + uint64_t pend_switch_null:1; + /* Set when there is a pending DESCHED or SWTAG_DESCHED. */ + uint64_t pend_desched:1; + /* + * Set when there is a pending SWTAG_DESCHED and + * pend_desched is set. + */ + uint64_t pend_desched_switch:1; + /* Set when nosched is desired and pend_desched is set. */ + uint64_t pend_nosched:1; + /* Set when there is a pending GET_WORK. */ + uint64_t pend_new_work:1; + /* + * When pend_new_work is set, this bit indicates that + * the wait bit was set. + */ + uint64_t pend_new_work_wait:1; + /* Set when there is a pending NULL_RD. */ + uint64_t pend_null_rd:1; + /* Set when there is a pending CLR_NSCHED. */ + uint64_t pend_nosched_clr:1; + uint64_t reserved_51:1; + /* This is the index when pend_nosched_clr is set. */ + uint64_t pend_index:11; + /* + * This is the new_grp when (pend_desched AND + * pend_desched_switch) is set. + */ + uint64_t pend_grp:4; + uint64_t reserved_34_35:2; + /* + * This is the tag type when pend_switch or + * (pend_desched AND pend_desched_switch) are set. + */ + uint64_t pend_type:2; + /* + * - this is the tag when pend_switch or (pend_desched + * AND pend_desched_switch) are set. + */ + uint64_t pend_tag:32; + } s_sstatus0; + + /** + * Result for a POW Status Load (when get_cur==0 and get_wqp==1) + */ + struct { + uint64_t reserved_62_63:2; + /* + * Set when there is a pending non-NULL SWTAG or + * SWTAG_FULL, and the POW entry has not left the list + * for the original tag. + */ + uint64_t pend_switch:1; + /* Set when SWTAG_FULL and pend_switch is set. */ + uint64_t pend_switch_full:1; + /* + * Set when there is a pending NULL SWTAG, or an + * implicit switch to NULL. + */ + uint64_t pend_switch_null:1; + /* + * Set when there is a pending DESCHED or + * SWTAG_DESCHED. + */ + uint64_t pend_desched:1; + /* + * Set when there is a pending SWTAG_DESCHED and + * pend_desched is set. + */ + uint64_t pend_desched_switch:1; + /* Set when nosched is desired and pend_desched is set. */ + uint64_t pend_nosched:1; + /* Set when there is a pending GET_WORK. */ + uint64_t pend_new_work:1; + /* + * When pend_new_work is set, this bit indicates that + * the wait bit was set. + */ + uint64_t pend_new_work_wait:1; + /* Set when there is a pending NULL_RD. */ + uint64_t pend_null_rd:1; + /* Set when there is a pending CLR_NSCHED. */ + uint64_t pend_nosched_clr:1; + uint64_t reserved_51:1; + /* This is the index when pend_nosched_clr is set. */ + uint64_t pend_index:11; + /* + * This is the new_grp when (pend_desched AND + * pend_desched_switch) is set. + */ + uint64_t pend_grp:4; + /* This is the wqp when pend_nosched_clr is set. */ + uint64_t pend_wqp:36; + } s_sstatus1; + + /** + * Result for a POW Status Load (when get_cur==1, get_wqp==0, and + * get_rev==0) + */ + struct { + uint64_t reserved_62_63:2; + /* + * Points to the next POW entry in the tag list when + * tail == 0 (and tag_type is not NULL or NULL_NULL). + */ + uint64_t link_index:11; + /* The POW entry attached to the core. */ + uint64_t index:11; + /* + * The group attached to the core (updated when new + * tag list entered on SWTAG_FULL). + */ + uint64_t grp:4; + /* + * Set when this POW entry is at the head of its tag + * list (also set when in the NULL or NULL_NULL + * state). + */ + uint64_t head:1; + /* + * Set when this POW entry is at the tail of its tag + * list (also set when in the NULL or NULL_NULL + * state). + */ + uint64_t tail:1; + /* + * The tag type attached to the core (updated when new + * tag list entered on SWTAG, SWTAG_FULL, or + * SWTAG_DESCHED). + */ + uint64_t tag_type:2; + /* + * The tag attached to the core (updated when new tag + * list entered on SWTAG, SWTAG_FULL, or + * SWTAG_DESCHED). + */ + uint64_t tag:32; + } s_sstatus2; + + /** + * Result for a POW Status Load (when get_cur==1, get_wqp==0, and get_rev==1) + */ + struct { + uint64_t reserved_62_63:2; + /* + * Points to the prior POW entry in the tag list when + * head == 0 (and tag_type is not NULL or + * NULL_NULL). This field is unpredictable when the + * core's state is NULL or NULL_NULL. + */ + uint64_t revlink_index:11; + /* The POW entry attached to the core. */ + uint64_t index:11; + /* + * The group attached to the core (updated when new + * tag list entered on SWTAG_FULL). + */ + uint64_t grp:4; + /* Set when this POW entry is at the head of its tag + * list (also set when in the NULL or NULL_NULL + * state). + */ + uint64_t head:1; + /* + * Set when this POW entry is at the tail of its tag + * list (also set when in the NULL or NULL_NULL + * state). + */ + uint64_t tail:1; + /* + * The tag type attached to the core (updated when new + * tag list entered on SWTAG, SWTAG_FULL, or + * SWTAG_DESCHED). + */ + uint64_t tag_type:2; + /* + * The tag attached to the core (updated when new tag + * list entered on SWTAG, SWTAG_FULL, or + * SWTAG_DESCHED). + */ + uint64_t tag:32; + } s_sstatus3; + + /** + * Result for a POW Status Load (when get_cur==1, get_wqp==1, and + * get_rev==0) + */ + struct { + uint64_t reserved_62_63:2; + /* + * Points to the next POW entry in the tag list when + * tail == 0 (and tag_type is not NULL or NULL_NULL). + */ + uint64_t link_index:11; + /* The POW entry attached to the core. */ + uint64_t index:11; + /* + * The group attached to the core (updated when new + * tag list entered on SWTAG_FULL). + */ + uint64_t grp:4; + /* + * The wqp attached to the core (updated when new tag + * list entered on SWTAG_FULL). + */ + uint64_t wqp:36; + } s_sstatus4; + + /** + * Result for a POW Status Load (when get_cur==1, get_wqp==1, and + * get_rev==1) + */ + struct { + uint64_t reserved_62_63:2; + /* + * Points to the prior POW entry in the tag list when + * head == 0 (and tag_type is not NULL or + * NULL_NULL). This field is unpredictable when the + * core's state is NULL or NULL_NULL. + */ + uint64_t revlink_index:11; + /* The POW entry attached to the core. */ + uint64_t index:11; + /* + * The group attached to the core (updated when new + * tag list entered on SWTAG_FULL). + */ + uint64_t grp:4; + /* + * The wqp attached to the core (updated when new tag + * list entered on SWTAG_FULL). + */ + uint64_t wqp:36; + } s_sstatus5; + + /** + * Result For POW Memory Load (get_des == 0 and get_wqp == 0) + */ + struct { + uint64_t reserved_51_63:13; + /* + * The next entry in the input, free, descheduled_head + * list (unpredictable if entry is the tail of the + * list). + */ + uint64_t next_index:11; + /* The group of the POW entry. */ + uint64_t grp:4; + uint64_t reserved_35:1; + /* + * Set when this POW entry is at the tail of its tag + * list (also set when in the NULL or NULL_NULL + * state). + */ + uint64_t tail:1; + /* The tag type of the POW entry. */ + uint64_t tag_type:2; + /* The tag of the POW entry. */ + uint64_t tag:32; + } s_smemload0; + + /** + * Result For POW Memory Load (get_des == 0 and get_wqp == 1) + */ + struct { + uint64_t reserved_51_63:13; + /* + * The next entry in the input, free, descheduled_head + * list (unpredictable if entry is the tail of the + * list). + */ + uint64_t next_index:11; + /* The group of the POW entry. */ + uint64_t grp:4; + /* The WQP held in the POW entry. */ + uint64_t wqp:36; + } s_smemload1; + + /** + * Result For POW Memory Load (get_des == 1) + */ + struct { + uint64_t reserved_51_63:13; + /* + * The next entry in the tag list connected to the + * descheduled head. + */ + uint64_t fwd_index:11; + /* The group of the POW entry. */ + uint64_t grp:4; + /* The nosched bit for the POW entry. */ + uint64_t nosched:1; + /* There is a pending tag switch */ + uint64_t pend_switch:1; + /* + * The next tag type for the new tag list when + * pend_switch is set. + */ + uint64_t pend_type:2; + /* + * The next tag for the new tag list when pend_switch + * is set. + */ + uint64_t pend_tag:32; + } s_smemload2; + + /** + * Result For POW Index/Pointer Load (get_rmt == 0/get_des_get_tail == 0) + */ + struct { + uint64_t reserved_52_63:12; + /* + * set when there is one or more POW entries on the + * free list. + */ + uint64_t free_val:1; + /* + * set when there is exactly one POW entry on the free + * list. + */ + uint64_t free_one:1; + uint64_t reserved_49:1; + /* + * when free_val is set, indicates the first entry on + * the free list. + */ + uint64_t free_head:11; + uint64_t reserved_37:1; + /* + * when free_val is set, indicates the last entry on + * the free list. + */ + uint64_t free_tail:11; + /* + * set when there is one or more POW entries on the + * input Q list selected by qosgrp. + */ + uint64_t loc_val:1; + /* + * set when there is exactly one POW entry on the + * input Q list selected by qosgrp. + */ + uint64_t loc_one:1; + uint64_t reserved_23:1; + /* + * when loc_val is set, indicates the first entry on + * the input Q list selected by qosgrp. + */ + uint64_t loc_head:11; + uint64_t reserved_11:1; + /* + * when loc_val is set, indicates the last entry on + * the input Q list selected by qosgrp. + */ + uint64_t loc_tail:11; + } sindexload0; + + /** + * Result For POW Index/Pointer Load (get_rmt == 0/get_des_get_tail == 1) + */ + struct { + uint64_t reserved_52_63:12; + /* + * set when there is one or more POW entries on the + * nosched list. + */ + uint64_t nosched_val:1; + /* + * set when there is exactly one POW entry on the + * nosched list. + */ + uint64_t nosched_one:1; + uint64_t reserved_49:1; + /* + * when nosched_val is set, indicates the first entry + * on the nosched list. + */ + uint64_t nosched_head:11; + uint64_t reserved_37:1; + /* + * when nosched_val is set, indicates the last entry + * on the nosched list. + */ + uint64_t nosched_tail:11; + /* + * set when there is one or more descheduled heads on + * the descheduled list selected by qosgrp. + */ + uint64_t des_val:1; + /* + * set when there is exactly one descheduled head on + * the descheduled list selected by qosgrp. + */ + uint64_t des_one:1; + uint64_t reserved_23:1; + /* + * when des_val is set, indicates the first + * descheduled head on the descheduled list selected + * by qosgrp. + */ + uint64_t des_head:11; + uint64_t reserved_11:1; + /* + * when des_val is set, indicates the last descheduled + * head on the descheduled list selected by qosgrp. + */ + uint64_t des_tail:11; + } sindexload1; + + /** + * Result For POW Index/Pointer Load (get_rmt == 1/get_des_get_tail == 0) + */ + struct { + uint64_t reserved_39_63:25; + /* + * Set when this DRAM list is the current head + * (i.e. is the next to be reloaded when the POW + * hardware reloads a POW entry from DRAM). The POW + * hardware alternates between the two DRAM lists + * associated with a QOS level when it reloads work + * from DRAM into the POW unit. + */ + uint64_t rmt_is_head:1; + /* + * Set when the DRAM portion of the input Q list + * selected by qosgrp contains one or more pieces of + * work. + */ + uint64_t rmt_val:1; + /* + * Set when the DRAM portion of the input Q list + * selected by qosgrp contains exactly one piece of + * work. + */ + uint64_t rmt_one:1; + /* + * When rmt_val is set, indicates the first piece of + * work on the DRAM input Q list selected by + * qosgrp. + */ + uint64_t rmt_head:36; + } sindexload2; + + /** + * Result For POW Index/Pointer Load (get_rmt == + * 1/get_des_get_tail == 1) + */ + struct { + uint64_t reserved_39_63:25; + /* + * set when this DRAM list is the current head + * (i.e. is the next to be reloaded when the POW + * hardware reloads a POW entry from DRAM). The POW + * hardware alternates between the two DRAM lists + * associated with a QOS level when it reloads work + * from DRAM into the POW unit. + */ + uint64_t rmt_is_head:1; + /* + * set when the DRAM portion of the input Q list + * selected by qosgrp contains one or more pieces of + * work. + */ + uint64_t rmt_val:1; + /* + * set when the DRAM portion of the input Q list + * selected by qosgrp contains exactly one piece of + * work. + */ + uint64_t rmt_one:1; + /* + * when rmt_val is set, indicates the last piece of + * work on the DRAM input Q list selected by + * qosgrp. + */ + uint64_t rmt_tail:36; + } sindexload3; + + /** + * Response to NULL_RD request loads + */ + struct { + uint64_t unused:62; + /* of type cvmx_pow_tag_type_t. state is one of the + * following: + * + * - CVMX_POW_TAG_TYPE_ORDERED + * - CVMX_POW_TAG_TYPE_ATOMIC + * - CVMX_POW_TAG_TYPE_NULL + * - CVMX_POW_TAG_TYPE_NULL_NULL + */ + uint64_t state:2; + } s_null_rd; + +} cvmx_pow_tag_load_resp_t; + +/** + * This structure describes the address used for stores to the POW. + * The store address is meaningful on stores to the POW. The + * hardware assumes that an aligned 64-bit store was used for all + * these stores. Note the assumption that the work queue entry is + * aligned on an 8-byte boundary (since the low-order 3 address bits + * must be zero). Note that not all fields are used by all + * operations. + * + * NOTE: The following is the behavior of the pending switch bit at the PP + * for POW stores (i.e. when did<7:3> == 0xc) + * - did<2:0> == 0 => pending switch bit is set + * - did<2:0> == 1 => no affect on the pending switch bit + * - did<2:0> == 3 => pending switch bit is cleared + * - did<2:0> == 7 => no affect on the pending switch bit + * - did<2:0> == others => must not be used + * - No other loads/stores have an affect on the pending switch bit + * - The switch bus from POW can clear the pending switch bit + * + * NOTE: did<2:0> == 2 is used by the HW for a special single-cycle + * ADDWQ command that only contains the pointer). SW must never use + * did<2:0> == 2. + */ +typedef union { + /** + * Unsigned 64 bit integer representation of store address + */ + uint64_t u64; + + struct { + /* Memory region. Should be CVMX_IO_SEG in most cases */ + uint64_t mem_reg:2; + uint64_t reserved_49_61:13; /* Must be zero */ + uint64_t is_io:1; /* Must be one */ + /* Device ID of POW. Note that different sub-dids are used. */ + uint64_t did:8; + uint64_t reserved_36_39:4; /* Must be zero */ + /* Address field. addr<2:0> must be zero */ + uint64_t addr:36; + } stag; +} cvmx_pow_tag_store_addr_t; + +/** + * decode of the store data when an IOBDMA SENDSINGLE is sent to POW + */ +typedef union { + uint64_t u64; + + struct { + /* + * the (64-bit word) location in scratchpad to write + * to (if len != 0) + */ + uint64_t scraddr:8; + /* the number of words in the response (0 => no response) */ + uint64_t len:8; + /* the ID of the device on the non-coherent bus */ + uint64_t did:8; + uint64_t unused:36; + /* if set, don't return load response until work is available */ + uint64_t wait:1; + uint64_t unused2:3; + } s; + +} cvmx_pow_iobdma_store_t; + +/* CSR typedefs have been moved to cvmx-csr-*.h */ + +/** + * Get the POW tag for this core. This returns the current + * tag type, tag, group, and POW entry index associated with + * this core. Index is only valid if the tag type isn't NULL_NULL. + * If a tag switch is pending this routine returns the tag before + * the tag switch, not after. + * + * Returns Current tag + */ +static inline cvmx_pow_tag_req_t cvmx_pow_get_current_tag(void) +{ + cvmx_pow_load_addr_t load_addr; + cvmx_pow_tag_load_resp_t load_resp; + cvmx_pow_tag_req_t result; + + load_addr.u64 = 0; + load_addr.sstatus.mem_region = CVMX_IO_SEG; + load_addr.sstatus.is_io = 1; + load_addr.sstatus.did = CVMX_OCT_DID_TAG_TAG1; + load_addr.sstatus.coreid = cvmx_get_core_num(); + load_addr.sstatus.get_cur = 1; + load_resp.u64 = cvmx_read_csr(load_addr.u64); + result.u64 = 0; + result.s.grp = load_resp.s_sstatus2.grp; + result.s.index = load_resp.s_sstatus2.index; + result.s.type = load_resp.s_sstatus2.tag_type; + result.s.tag = load_resp.s_sstatus2.tag; + return result; +} + +/** + * Get the POW WQE for this core. This returns the work queue + * entry currently associated with this core. + * + * Returns WQE pointer + */ +static inline cvmx_wqe_t *cvmx_pow_get_current_wqp(void) +{ + cvmx_pow_load_addr_t load_addr; + cvmx_pow_tag_load_resp_t load_resp; + + load_addr.u64 = 0; + load_addr.sstatus.mem_region = CVMX_IO_SEG; + load_addr.sstatus.is_io = 1; + load_addr.sstatus.did = CVMX_OCT_DID_TAG_TAG1; + load_addr.sstatus.coreid = cvmx_get_core_num(); + load_addr.sstatus.get_cur = 1; + load_addr.sstatus.get_wqp = 1; + load_resp.u64 = cvmx_read_csr(load_addr.u64); + return (cvmx_wqe_t *) cvmx_phys_to_ptr(load_resp.s_sstatus4.wqp); +} + +#ifndef CVMX_MF_CHORD +#define CVMX_MF_CHORD(dest) CVMX_RDHWR(dest, 30) +#endif + +/** + * Print a warning if a tag switch is pending for this core + * + * @function: Function name checking for a pending tag switch + */ +static inline void __cvmx_pow_warn_if_pending_switch(const char *function) +{ + uint64_t switch_complete; + CVMX_MF_CHORD(switch_complete); + if (!switch_complete) + pr_warning("%s called with tag switch in progress\n", function); +} + +/** + * Waits for a tag switch to complete by polling the completion bit. + * Note that switches to NULL complete immediately and do not need + * to be waited for. + */ +static inline void cvmx_pow_tag_sw_wait(void) +{ + const uint64_t MAX_CYCLES = 1ull << 31; + uint64_t switch_complete; + uint64_t start_cycle = cvmx_get_cycle(); + while (1) { + CVMX_MF_CHORD(switch_complete); + if (unlikely(switch_complete)) + break; + if (unlikely(cvmx_get_cycle() > start_cycle + MAX_CYCLES)) { + pr_warning("Tag switch is taking a long time, " + "possible deadlock\n"); + start_cycle = -MAX_CYCLES - 1; + } + } +} + +/** + * Synchronous work request. Requests work from the POW. + * This function does NOT wait for previous tag switches to complete, + * so the caller must ensure that there is not a pending tag switch. + * + * @wait: When set, call stalls until work becomes avaiable, or times out. + * If not set, returns immediately. + * + * Returns Returns the WQE pointer from POW. Returns NULL if no work + * was available. + */ +static inline cvmx_wqe_t *cvmx_pow_work_request_sync_nocheck(cvmx_pow_wait_t + wait) +{ + cvmx_pow_load_addr_t ptr; + cvmx_pow_tag_load_resp_t result; + + if (CVMX_ENABLE_POW_CHECKS) + __cvmx_pow_warn_if_pending_switch(__func__); + + ptr.u64 = 0; + ptr.swork.mem_region = CVMX_IO_SEG; + ptr.swork.is_io = 1; + ptr.swork.did = CVMX_OCT_DID_TAG_SWTAG; + ptr.swork.wait = wait; + + result.u64 = cvmx_read_csr(ptr.u64); + + if (result.s_work.no_work) + return NULL; + else + return (cvmx_wqe_t *) cvmx_phys_to_ptr(result.s_work.addr); +} + +/** + * Synchronous work request. Requests work from the POW. + * This function waits for any previous tag switch to complete before + * requesting the new work. + * + * @wait: When set, call stalls until work becomes avaiable, or times out. + * If not set, returns immediately. + * + * Returns Returns the WQE pointer from POW. Returns NULL if no work + * was available. + */ +static inline cvmx_wqe_t *cvmx_pow_work_request_sync(cvmx_pow_wait_t wait) +{ + if (CVMX_ENABLE_POW_CHECKS) + __cvmx_pow_warn_if_pending_switch(__func__); + + /* Must not have a switch pending when requesting work */ + cvmx_pow_tag_sw_wait(); + return cvmx_pow_work_request_sync_nocheck(wait); + +} + +/** + * Synchronous null_rd request. Requests a switch out of NULL_NULL POW state. + * This function waits for any previous tag switch to complete before + * requesting the null_rd. + * + * Returns Returns the POW state of type cvmx_pow_tag_type_t. + */ +static inline enum cvmx_pow_tag_type cvmx_pow_work_request_null_rd(void) +{ + cvmx_pow_load_addr_t ptr; + cvmx_pow_tag_load_resp_t result; + + if (CVMX_ENABLE_POW_CHECKS) + __cvmx_pow_warn_if_pending_switch(__func__); + + /* Must not have a switch pending when requesting work */ + cvmx_pow_tag_sw_wait(); + + ptr.u64 = 0; + ptr.snull_rd.mem_region = CVMX_IO_SEG; + ptr.snull_rd.is_io = 1; + ptr.snull_rd.did = CVMX_OCT_DID_TAG_NULL_RD; + + result.u64 = cvmx_read_csr(ptr.u64); + + return (enum cvmx_pow_tag_type) result.s_null_rd.state; +} + +/** + * Asynchronous work request. Work is requested from the POW unit, + * and should later be checked with function + * cvmx_pow_work_response_async. This function does NOT wait for + * previous tag switches to complete, so the caller must ensure that + * there is not a pending tag switch. + * + * @scr_addr: Scratch memory address that response will be returned + * to, which is either a valid WQE, or a response with the + * invalid bit set. Byte address, must be 8 byte aligned. + * + * @wait: 1 to cause response to wait for work to become available (or + * timeout), 0 to cause response to return immediately + */ +static inline void cvmx_pow_work_request_async_nocheck(int scr_addr, + cvmx_pow_wait_t wait) +{ + cvmx_pow_iobdma_store_t data; + + if (CVMX_ENABLE_POW_CHECKS) + __cvmx_pow_warn_if_pending_switch(__func__); + + /* scr_addr must be 8 byte aligned */ + data.s.scraddr = scr_addr >> 3; + data.s.len = 1; + data.s.did = CVMX_OCT_DID_TAG_SWTAG; + data.s.wait = wait; + cvmx_send_single(data.u64); +} + +/** + * Asynchronous work request. Work is requested from the POW unit, + * and should later be checked with function + * cvmx_pow_work_response_async. This function waits for any previous + * tag switch to complete before requesting the new work. + * + * @scr_addr: Scratch memory address that response will be returned + * to, which is either a valid WQE, or a response with the + * invalid bit set. Byte address, must be 8 byte aligned. + * + * @wait: 1 to cause response to wait for work to become available (or + * timeout), 0 to cause response to return immediately + */ +static inline void cvmx_pow_work_request_async(int scr_addr, + cvmx_pow_wait_t wait) +{ + if (CVMX_ENABLE_POW_CHECKS) + __cvmx_pow_warn_if_pending_switch(__func__); + + /* Must not have a switch pending when requesting work */ + cvmx_pow_tag_sw_wait(); + cvmx_pow_work_request_async_nocheck(scr_addr, wait); +} + +/** + * Gets result of asynchronous work request. Performs a IOBDMA sync + * to wait for the response. + * + * @scr_addr: Scratch memory address to get result from Byte address, + * must be 8 byte aligned. + * + * Returns Returns the WQE from the scratch register, or NULL if no + * work was available. + */ +static inline cvmx_wqe_t *cvmx_pow_work_response_async(int scr_addr) +{ + cvmx_pow_tag_load_resp_t result; + + CVMX_SYNCIOBDMA; + result.u64 = cvmx_scratch_read64(scr_addr); + + if (result.s_work.no_work) + return NULL; + else + return (cvmx_wqe_t *) cvmx_phys_to_ptr(result.s_work.addr); +} + +/** + * Checks if a work queue entry pointer returned by a work + * request is valid. It may be invalid due to no work + * being available or due to a timeout. + * + * @wqe_ptr: pointer to a work queue entry returned by the POW + * + * Returns 0 if pointer is valid + * 1 if invalid (no work was returned) + */ +static inline uint64_t cvmx_pow_work_invalid(cvmx_wqe_t *wqe_ptr) +{ + return wqe_ptr == NULL; +} + +/** + * Starts a tag switch to the provided tag value and tag type. + * Completion for the tag switch must be checked for separately. This + * function does NOT update the work queue entry in dram to match tag + * value and type, so the application must keep track of these if they + * are important to the application. This tag switch command must not + * be used for switches to NULL, as the tag switch pending bit will be + * set by the switch request, but never cleared by the hardware. + * + * NOTE: This should not be used when switching from a NULL tag. Use + * cvmx_pow_tag_sw_full() instead. + * + * This function does no checks, so the caller must ensure that any + * previous tag switch has completed. + * + * @tag: new tag value + * @tag_type: new tag type (ordered or atomic) + */ +static inline void cvmx_pow_tag_sw_nocheck(uint32_t tag, + enum cvmx_pow_tag_type tag_type) +{ + cvmx_addr_t ptr; + cvmx_pow_tag_req_t tag_req; + + if (CVMX_ENABLE_POW_CHECKS) { + cvmx_pow_tag_req_t current_tag; + __cvmx_pow_warn_if_pending_switch(__func__); + current_tag = cvmx_pow_get_current_tag(); + if (current_tag.s.type == CVMX_POW_TAG_TYPE_NULL_NULL) + pr_warning("%s called with NULL_NULL tag\n", + __func__); + if (current_tag.s.type == CVMX_POW_TAG_TYPE_NULL) + pr_warning("%s called with NULL tag\n", __func__); + if ((current_tag.s.type == tag_type) + && (current_tag.s.tag == tag)) + pr_warning("%s called to perform a tag switch to the " + "same tag\n", + __func__); + if (tag_type == CVMX_POW_TAG_TYPE_NULL) + pr_warning("%s called to perform a tag switch to " + "NULL. Use cvmx_pow_tag_sw_null() instead\n", + __func__); + } + + /* + * Note that WQE in DRAM is not updated here, as the POW does + * not read from DRAM once the WQE is in flight. See hardware + * manual for complete details. It is the application's + * responsibility to keep track of the current tag value if + * that is important. + */ + + tag_req.u64 = 0; + tag_req.s.op = CVMX_POW_TAG_OP_SWTAG; + tag_req.s.tag = tag; + tag_req.s.type = tag_type; + + ptr.u64 = 0; + ptr.sio.mem_region = CVMX_IO_SEG; + ptr.sio.is_io = 1; + ptr.sio.did = CVMX_OCT_DID_TAG_SWTAG; + + /* once this store arrives at POW, it will attempt the switch + software must wait for the switch to complete separately */ + cvmx_write_io(ptr.u64, tag_req.u64); +} + +/** + * Starts a tag switch to the provided tag value and tag type. + * Completion for the tag switch must be checked for separately. This + * function does NOT update the work queue entry in dram to match tag + * value and type, so the application must keep track of these if they + * are important to the application. This tag switch command must not + * be used for switches to NULL, as the tag switch pending bit will be + * set by the switch request, but never cleared by the hardware. + * + * NOTE: This should not be used when switching from a NULL tag. Use + * cvmx_pow_tag_sw_full() instead. + * + * This function waits for any previous tag switch to complete, and also + * displays an error on tag switches to NULL. + * + * @tag: new tag value + * @tag_type: new tag type (ordered or atomic) + */ +static inline void cvmx_pow_tag_sw(uint32_t tag, + enum cvmx_pow_tag_type tag_type) +{ + if (CVMX_ENABLE_POW_CHECKS) + __cvmx_pow_warn_if_pending_switch(__func__); + + /* + * Note that WQE in DRAM is not updated here, as the POW does + * not read from DRAM once the WQE is in flight. See hardware + * manual for complete details. It is the application's + * responsibility to keep track of the current tag value if + * that is important. + */ + + /* + * Ensure that there is not a pending tag switch, as a tag + * switch cannot be started if a previous switch is still + * pending. + */ + cvmx_pow_tag_sw_wait(); + cvmx_pow_tag_sw_nocheck(tag, tag_type); +} + +/** + * Starts a tag switch to the provided tag value and tag type. + * Completion for the tag switch must be checked for separately. This + * function does NOT update the work queue entry in dram to match tag + * value and type, so the application must keep track of these if they + * are important to the application. This tag switch command must not + * be used for switches to NULL, as the tag switch pending bit will be + * set by the switch request, but never cleared by the hardware. + * + * This function must be used for tag switches from NULL. + * + * This function does no checks, so the caller must ensure that any + * previous tag switch has completed. + * + * @wqp: pointer to work queue entry to submit. This entry is + * updated to match the other parameters + * @tag: tag value to be assigned to work queue entry + * @tag_type: type of tag + * @group: group value for the work queue entry. + */ +static inline void cvmx_pow_tag_sw_full_nocheck(cvmx_wqe_t *wqp, uint32_t tag, + enum cvmx_pow_tag_type tag_type, + uint64_t group) +{ + cvmx_addr_t ptr; + cvmx_pow_tag_req_t tag_req; + + if (CVMX_ENABLE_POW_CHECKS) { + cvmx_pow_tag_req_t current_tag; + __cvmx_pow_warn_if_pending_switch(__func__); + current_tag = cvmx_pow_get_current_tag(); + if (current_tag.s.type == CVMX_POW_TAG_TYPE_NULL_NULL) + pr_warning("%s called with NULL_NULL tag\n", + __func__); + if ((current_tag.s.type == tag_type) + && (current_tag.s.tag == tag)) + pr_warning("%s called to perform a tag switch to " + "the same tag\n", + __func__); + if (tag_type == CVMX_POW_TAG_TYPE_NULL) + pr_warning("%s called to perform a tag switch to " + "NULL. Use cvmx_pow_tag_sw_null() instead\n", + __func__); + if (wqp != cvmx_phys_to_ptr(0x80)) + if (wqp != cvmx_pow_get_current_wqp()) + pr_warning("%s passed WQE(%p) doesn't match " + "the address in the POW(%p)\n", + __func__, wqp, + cvmx_pow_get_current_wqp()); + } + + /* + * Note that WQE in DRAM is not updated here, as the POW does + * not read from DRAM once the WQE is in flight. See hardware + * manual for complete details. It is the application's + * responsibility to keep track of the current tag value if + * that is important. + */ + + tag_req.u64 = 0; + tag_req.s.op = CVMX_POW_TAG_OP_SWTAG_FULL; + tag_req.s.tag = tag; + tag_req.s.type = tag_type; + tag_req.s.grp = group; + + ptr.u64 = 0; + ptr.sio.mem_region = CVMX_IO_SEG; + ptr.sio.is_io = 1; + ptr.sio.did = CVMX_OCT_DID_TAG_SWTAG; + ptr.sio.offset = CAST64(wqp); + + /* + * once this store arrives at POW, it will attempt the switch + * software must wait for the switch to complete separately. + */ + cvmx_write_io(ptr.u64, tag_req.u64); +} + +/** + * Starts a tag switch to the provided tag value and tag type. + * Completion for the tag switch must be checked for separately. This + * function does NOT update the work queue entry in dram to match tag + * value and type, so the application must keep track of these if they + * are important to the application. This tag switch command must not + * be used for switches to NULL, as the tag switch pending bit will be + * set by the switch request, but never cleared by the hardware. + * + * This function must be used for tag switches from NULL. + * + * This function waits for any pending tag switches to complete + * before requesting the tag switch. + * + * @wqp: pointer to work queue entry to submit. This entry is updated + * to match the other parameters + * @tag: tag value to be assigned to work queue entry + * @tag_type: type of tag + * @group: group value for the work queue entry. + */ +static inline void cvmx_pow_tag_sw_full(cvmx_wqe_t *wqp, uint32_t tag, + enum cvmx_pow_tag_type tag_type, + uint64_t group) +{ + if (CVMX_ENABLE_POW_CHECKS) + __cvmx_pow_warn_if_pending_switch(__func__); + + /* + * Ensure that there is not a pending tag switch, as a tag + * switch cannot be started if a previous switch is still + * pending. + */ + cvmx_pow_tag_sw_wait(); + cvmx_pow_tag_sw_full_nocheck(wqp, tag, tag_type, group); +} + +/** + * Switch to a NULL tag, which ends any ordering or + * synchronization provided by the POW for the current + * work queue entry. This operation completes immediatly, + * so completetion should not be waited for. + * This function does NOT wait for previous tag switches to complete, + * so the caller must ensure that any previous tag switches have completed. + */ +static inline void cvmx_pow_tag_sw_null_nocheck(void) +{ + cvmx_addr_t ptr; + cvmx_pow_tag_req_t tag_req; + + if (CVMX_ENABLE_POW_CHECKS) { + cvmx_pow_tag_req_t current_tag; + __cvmx_pow_warn_if_pending_switch(__func__); + current_tag = cvmx_pow_get_current_tag(); + if (current_tag.s.type == CVMX_POW_TAG_TYPE_NULL_NULL) + pr_warning("%s called with NULL_NULL tag\n", + __func__); + if (current_tag.s.type == CVMX_POW_TAG_TYPE_NULL) + pr_warning("%s called when we already have a " + "NULL tag\n", + __func__); + } + + tag_req.u64 = 0; + tag_req.s.op = CVMX_POW_TAG_OP_SWTAG; + tag_req.s.type = CVMX_POW_TAG_TYPE_NULL; + + ptr.u64 = 0; + ptr.sio.mem_region = CVMX_IO_SEG; + ptr.sio.is_io = 1; + ptr.sio.did = CVMX_OCT_DID_TAG_TAG1; + + cvmx_write_io(ptr.u64, tag_req.u64); + + /* switch to NULL completes immediately */ +} + +/** + * Switch to a NULL tag, which ends any ordering or + * synchronization provided by the POW for the current + * work queue entry. This operation completes immediatly, + * so completetion should not be waited for. + * This function waits for any pending tag switches to complete + * before requesting the switch to NULL. + */ +static inline void cvmx_pow_tag_sw_null(void) +{ + if (CVMX_ENABLE_POW_CHECKS) + __cvmx_pow_warn_if_pending_switch(__func__); + + /* + * Ensure that there is not a pending tag switch, as a tag + * switch cannot be started if a previous switch is still + * pending. + */ + cvmx_pow_tag_sw_wait(); + cvmx_pow_tag_sw_null_nocheck(); + + /* switch to NULL completes immediately */ +} + +/** + * Submits work to an input queue. This function updates the work + * queue entry in DRAM to match the arguments given. Note that the + * tag provided is for the work queue entry submitted, and is + * unrelated to the tag that the core currently holds. + * + * @wqp: pointer to work queue entry to submit. This entry is + * updated to match the other parameters + * @tag: tag value to be assigned to work queue entry + * @tag_type: type of tag + * @qos: Input queue to add to. + * @grp: group value for the work queue entry. + */ +static inline void cvmx_pow_work_submit(cvmx_wqe_t *wqp, uint32_t tag, + enum cvmx_pow_tag_type tag_type, + uint64_t qos, uint64_t grp) +{ + cvmx_addr_t ptr; + cvmx_pow_tag_req_t tag_req; + + wqp->qos = qos; + wqp->tag = tag; + wqp->tag_type = tag_type; + wqp->grp = grp; + + tag_req.u64 = 0; + tag_req.s.op = CVMX_POW_TAG_OP_ADDWQ; + tag_req.s.type = tag_type; + tag_req.s.tag = tag; + tag_req.s.qos = qos; + tag_req.s.grp = grp; + + ptr.u64 = 0; + ptr.sio.mem_region = CVMX_IO_SEG; + ptr.sio.is_io = 1; + ptr.sio.did = CVMX_OCT_DID_TAG_TAG1; + ptr.sio.offset = cvmx_ptr_to_phys(wqp); + + /* + * SYNC write to memory before the work submit. This is + * necessary as POW may read values from DRAM at this time. + */ + CVMX_SYNCWS; + cvmx_write_io(ptr.u64, tag_req.u64); +} + +/** + * This function sets the group mask for a core. The group mask + * indicates which groups each core will accept work from. There are + * 16 groups. + * + * @core_num: core to apply mask to + * @mask: Group mask. There are 16 groups, so only bits 0-15 are valid, + * representing groups 0-15. + * Each 1 bit in the mask enables the core to accept work from + * the corresponding group. + */ +static inline void cvmx_pow_set_group_mask(uint64_t core_num, uint64_t mask) +{ + union cvmx_pow_pp_grp_mskx grp_msk; + + grp_msk.u64 = cvmx_read_csr(CVMX_POW_PP_GRP_MSKX(core_num)); + grp_msk.s.grp_msk = mask; + cvmx_write_csr(CVMX_POW_PP_GRP_MSKX(core_num), grp_msk.u64); +} + +/** + * This function sets POW static priorities for a core. Each input queue has + * an associated priority value. + * + * @core_num: core to apply priorities to + * @priority: Vector of 8 priorities, one per POW Input Queue (0-7). + * Highest priority is 0 and lowest is 7. A priority value + * of 0xF instructs POW to skip the Input Queue when + * scheduling to this specific core. + * NOTE: priorities should not have gaps in values, meaning + * {0,1,1,1,1,1,1,1} is a valid configuration while + * {0,2,2,2,2,2,2,2} is not. + */ +static inline void cvmx_pow_set_priority(uint64_t core_num, + const uint8_t priority[]) +{ + /* POW priorities are supported on CN5xxx and later */ + if (!OCTEON_IS_MODEL(OCTEON_CN3XXX)) { + union cvmx_pow_pp_grp_mskx grp_msk; + + grp_msk.u64 = cvmx_read_csr(CVMX_POW_PP_GRP_MSKX(core_num)); + grp_msk.s.qos0_pri = priority[0]; + grp_msk.s.qos1_pri = priority[1]; + grp_msk.s.qos2_pri = priority[2]; + grp_msk.s.qos3_pri = priority[3]; + grp_msk.s.qos4_pri = priority[4]; + grp_msk.s.qos5_pri = priority[5]; + grp_msk.s.qos6_pri = priority[6]; + grp_msk.s.qos7_pri = priority[7]; + + /* Detect gaps between priorities and flag error */ + { + int i; + uint32_t prio_mask = 0; + + for (i = 0; i < 8; i++) + if (priority[i] != 0xF) + prio_mask |= 1 << priority[i]; + + if (prio_mask ^ ((1 << cvmx_pop(prio_mask)) - 1)) { + pr_err("POW static priorities should be " + "contiguous (0x%llx)\n", + (unsigned long long)prio_mask); + return; + } + } + + cvmx_write_csr(CVMX_POW_PP_GRP_MSKX(core_num), grp_msk.u64); + } +} + +/** + * Performs a tag switch and then an immediate deschedule. This completes + * immediatly, so completion must not be waited for. This function does NOT + * update the wqe in DRAM to match arguments. + * + * This function does NOT wait for any prior tag switches to complete, so the + * calling code must do this. + * + * Note the following CAVEAT of the Octeon HW behavior when + * re-scheduling DE-SCHEDULEd items whose (next) state is + * ORDERED: + * - If there are no switches pending at the time that the + * HW executes the de-schedule, the HW will only re-schedule + * the head of the FIFO associated with the given tag. This + * means that in many respects, the HW treats this ORDERED + * tag as an ATOMIC tag. Note that in the SWTAG_DESCH + * case (to an ORDERED tag), the HW will do the switch + * before the deschedule whenever it is possible to do + * the switch immediately, so it may often look like + * this case. + * - If there is a pending switch to ORDERED at the time + * the HW executes the de-schedule, the HW will perform + * the switch at the time it re-schedules, and will be + * able to reschedule any/all of the entries with the + * same tag. + * Due to this behavior, the RECOMMENDATION to software is + * that they have a (next) state of ATOMIC when they + * DE-SCHEDULE. If an ORDERED tag is what was really desired, + * SW can choose to immediately switch to an ORDERED tag + * after the work (that has an ATOMIC tag) is re-scheduled. + * Note that since there are never any tag switches pending + * when the HW re-schedules, this switch can be IMMEDIATE upon + * the reception of the pointer during the re-schedule. + * + * @tag: New tag value + * @tag_type: New tag type + * @group: New group value + * @no_sched: Control whether this work queue entry will be rescheduled. + * - 1 : don't schedule this work + * - 0 : allow this work to be scheduled. + */ +static inline void cvmx_pow_tag_sw_desched_nocheck( + uint32_t tag, + enum cvmx_pow_tag_type tag_type, + uint64_t group, + uint64_t no_sched) +{ + cvmx_addr_t ptr; + cvmx_pow_tag_req_t tag_req; + + if (CVMX_ENABLE_POW_CHECKS) { + cvmx_pow_tag_req_t current_tag; + __cvmx_pow_warn_if_pending_switch(__func__); + current_tag = cvmx_pow_get_current_tag(); + if (current_tag.s.type == CVMX_POW_TAG_TYPE_NULL_NULL) + pr_warning("%s called with NULL_NULL tag\n", + __func__); + if (current_tag.s.type == CVMX_POW_TAG_TYPE_NULL) + pr_warning("%s called with NULL tag. Deschedule not " + "allowed from NULL state\n", + __func__); + if ((current_tag.s.type != CVMX_POW_TAG_TYPE_ATOMIC) + && (tag_type != CVMX_POW_TAG_TYPE_ATOMIC)) + pr_warning("%s called where neither the before or " + "after tag is ATOMIC\n", + __func__); + } + + tag_req.u64 = 0; + tag_req.s.op = CVMX_POW_TAG_OP_SWTAG_DESCH; + tag_req.s.tag = tag; + tag_req.s.type = tag_type; + tag_req.s.grp = group; + tag_req.s.no_sched = no_sched; + + ptr.u64 = 0; + ptr.sio.mem_region = CVMX_IO_SEG; + ptr.sio.is_io = 1; + ptr.sio.did = CVMX_OCT_DID_TAG_TAG3; + /* + * since TAG3 is used, this store will clear the local pending + * switch bit. + */ + cvmx_write_io(ptr.u64, tag_req.u64); +} + +/** + * Performs a tag switch and then an immediate deschedule. This completes + * immediatly, so completion must not be waited for. This function does NOT + * update the wqe in DRAM to match arguments. + * + * This function waits for any prior tag switches to complete, so the + * calling code may call this function with a pending tag switch. + * + * Note the following CAVEAT of the Octeon HW behavior when + * re-scheduling DE-SCHEDULEd items whose (next) state is + * ORDERED: + * - If there are no switches pending at the time that the + * HW executes the de-schedule, the HW will only re-schedule + * the head of the FIFO associated with the given tag. This + * means that in many respects, the HW treats this ORDERED + * tag as an ATOMIC tag. Note that in the SWTAG_DESCH + * case (to an ORDERED tag), the HW will do the switch + * before the deschedule whenever it is possible to do + * the switch immediately, so it may often look like + * this case. + * - If there is a pending switch to ORDERED at the time + * the HW executes the de-schedule, the HW will perform + * the switch at the time it re-schedules, and will be + * able to reschedule any/all of the entries with the + * same tag. + * Due to this behavior, the RECOMMENDATION to software is + * that they have a (next) state of ATOMIC when they + * DE-SCHEDULE. If an ORDERED tag is what was really desired, + * SW can choose to immediately switch to an ORDERED tag + * after the work (that has an ATOMIC tag) is re-scheduled. + * Note that since there are never any tag switches pending + * when the HW re-schedules, this switch can be IMMEDIATE upon + * the reception of the pointer during the re-schedule. + * + * @tag: New tag value + * @tag_type: New tag type + * @group: New group value + * @no_sched: Control whether this work queue entry will be rescheduled. + * - 1 : don't schedule this work + * - 0 : allow this work to be scheduled. + */ +static inline void cvmx_pow_tag_sw_desched(uint32_t tag, + enum cvmx_pow_tag_type tag_type, + uint64_t group, uint64_t no_sched) +{ + if (CVMX_ENABLE_POW_CHECKS) + __cvmx_pow_warn_if_pending_switch(__func__); + + /* Need to make sure any writes to the work queue entry are complete */ + CVMX_SYNCWS; + /* + * Ensure that there is not a pending tag switch, as a tag + * switch cannot be started if a previous switch is still + * pending. + */ + cvmx_pow_tag_sw_wait(); + cvmx_pow_tag_sw_desched_nocheck(tag, tag_type, group, no_sched); +} + +/** + * Descchedules the current work queue entry. + * + * @no_sched: no schedule flag value to be set on the work queue + * entry. If this is set the entry will not be + * rescheduled. + */ +static inline void cvmx_pow_desched(uint64_t no_sched) +{ + cvmx_addr_t ptr; + cvmx_pow_tag_req_t tag_req; + + if (CVMX_ENABLE_POW_CHECKS) { + cvmx_pow_tag_req_t current_tag; + __cvmx_pow_warn_if_pending_switch(__func__); + current_tag = cvmx_pow_get_current_tag(); + if (current_tag.s.type == CVMX_POW_TAG_TYPE_NULL_NULL) + pr_warning("%s called with NULL_NULL tag\n", + __func__); + if (current_tag.s.type == CVMX_POW_TAG_TYPE_NULL) + pr_warning("%s called with NULL tag. Deschedule not " + "expected from NULL state\n", + __func__); + } + + /* Need to make sure any writes to the work queue entry are complete */ + CVMX_SYNCWS; + + tag_req.u64 = 0; + tag_req.s.op = CVMX_POW_TAG_OP_DESCH; + tag_req.s.no_sched = no_sched; + + ptr.u64 = 0; + ptr.sio.mem_region = CVMX_IO_SEG; + ptr.sio.is_io = 1; + ptr.sio.did = CVMX_OCT_DID_TAG_TAG3; + /* + * since TAG3 is used, this store will clear the local pending + * switch bit. + */ + cvmx_write_io(ptr.u64, tag_req.u64); +} + +/**************************************************** +* Define usage of bits within the 32 bit tag values. +*****************************************************/ + +/* + * Number of bits of the tag used by software. The SW bits are always + * a contiguous block of the high starting at bit 31. The hardware + * bits are always the low bits. By default, the top 8 bits of the + * tag are reserved for software, and the low 24 are set by the IPD + * unit. + */ +#define CVMX_TAG_SW_BITS (8) +#define CVMX_TAG_SW_SHIFT (32 - CVMX_TAG_SW_BITS) + +/* Below is the list of values for the top 8 bits of the tag. */ +/* + * Tag values with top byte of this value are reserved for internal + * executive uses. + */ +#define CVMX_TAG_SW_BITS_INTERNAL 0x1 +/* The executive divides the remaining 24 bits as follows: + * - the upper 8 bits (bits 23 - 16 of the tag) define a subgroup + * + * - the lower 16 bits (bits 15 - 0 of the tag) define are the value + * with the subgroup + * + * Note that this section describes the format of tags generated by + * software - refer to the hardware documentation for a description of + * the tags values generated by the packet input hardware. Subgroups + * are defined here. + */ +/* Mask for the value portion of the tag */ +#define CVMX_TAG_SUBGROUP_MASK 0xFFFF +#define CVMX_TAG_SUBGROUP_SHIFT 16 +#define CVMX_TAG_SUBGROUP_PKO 0x1 + +/* End of executive tag subgroup definitions */ + +/* + * The remaining values software bit values 0x2 - 0xff are available + * for application use. + */ + +/** + * This function creates a 32 bit tag value from the two values provided. + * + * @sw_bits: The upper bits (number depends on configuration) are set + * to this value. The remainder of bits are set by the + * hw_bits parameter. + * + * @hw_bits: The lower bits (number depends on configuration) are set + * to this value. The remainder of bits are set by the + * sw_bits parameter. + * + * Returns 32 bit value of the combined hw and sw bits. + */ +static inline uint32_t cvmx_pow_tag_compose(uint64_t sw_bits, uint64_t hw_bits) +{ + return ((sw_bits & cvmx_build_mask(CVMX_TAG_SW_BITS)) << + CVMX_TAG_SW_SHIFT) | + (hw_bits & cvmx_build_mask(32 - CVMX_TAG_SW_BITS)); +} + +/** + * Extracts the bits allocated for software use from the tag + * + * @tag: 32 bit tag value + * + * Returns N bit software tag value, where N is configurable with the + * CVMX_TAG_SW_BITS define + */ +static inline uint32_t cvmx_pow_tag_get_sw_bits(uint64_t tag) +{ + return (tag >> (32 - CVMX_TAG_SW_BITS)) & + cvmx_build_mask(CVMX_TAG_SW_BITS); +} + +/** + * + * Extracts the bits allocated for hardware use from the tag + * + * @tag: 32 bit tag value + * + * Returns (32 - N) bit software tag value, where N is configurable + * with the CVMX_TAG_SW_BITS define + */ +static inline uint32_t cvmx_pow_tag_get_hw_bits(uint64_t tag) +{ + return tag & cvmx_build_mask(32 - CVMX_TAG_SW_BITS); +} + +/** + * Store the current POW internal state into the supplied + * buffer. It is recommended that you pass a buffer of at least + * 128KB. The format of the capture may change based on SDK + * version and Octeon chip. + * + * @buffer: Buffer to store capture into + * @buffer_size: + * The size of the supplied buffer + * + * Returns Zero on sucess, negative on failure + */ +extern int cvmx_pow_capture(void *buffer, int buffer_size); + +/** + * Dump a POW capture to the console in a human readable format. + * + * @buffer: POW capture from cvmx_pow_capture() + * @buffer_size: + * Size of the buffer + */ +extern void cvmx_pow_display(void *buffer, int buffer_size); + +/** + * Return the number of POW entries supported by this chip + * + * Returns Number of POW entries + */ +extern int cvmx_pow_get_num_entries(void); + +#endif /* __CVMX_POW_H__ */ diff --git a/drivers/staging/octeon/cvmx-scratch.h b/drivers/staging/octeon/cvmx-scratch.h new file mode 100644 index 000000000000..96b70cfd6245 --- /dev/null +++ b/drivers/staging/octeon/cvmx-scratch.h @@ -0,0 +1,139 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2008 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +/** + * + * This file provides support for the processor local scratch memory. + * Scratch memory is byte addressable - all addresses are byte addresses. + * + */ + +#ifndef __CVMX_SCRATCH_H__ +#define __CVMX_SCRATCH_H__ + +/* + * Note: This define must be a long, not a long long in order to + * compile without warnings for both 32bit and 64bit. + */ +#define CVMX_SCRATCH_BASE (-32768l) /* 0xffffffffffff8000 */ + +/** + * Reads an 8 bit value from the processor local scratchpad memory. + * + * @address: byte address to read from + * + * Returns value read + */ +static inline uint8_t cvmx_scratch_read8(uint64_t address) +{ + return *CASTPTR(volatile uint8_t, CVMX_SCRATCH_BASE + address); +} + +/** + * Reads a 16 bit value from the processor local scratchpad memory. + * + * @address: byte address to read from + * + * Returns value read + */ +static inline uint16_t cvmx_scratch_read16(uint64_t address) +{ + return *CASTPTR(volatile uint16_t, CVMX_SCRATCH_BASE + address); +} + +/** + * Reads a 32 bit value from the processor local scratchpad memory. + * + * @address: byte address to read from + * + * Returns value read + */ +static inline uint32_t cvmx_scratch_read32(uint64_t address) +{ + return *CASTPTR(volatile uint32_t, CVMX_SCRATCH_BASE + address); +} + +/** + * Reads a 64 bit value from the processor local scratchpad memory. + * + * @address: byte address to read from + * + * Returns value read + */ +static inline uint64_t cvmx_scratch_read64(uint64_t address) +{ + return *CASTPTR(volatile uint64_t, CVMX_SCRATCH_BASE + address); +} + +/** + * Writes an 8 bit value to the processor local scratchpad memory. + * + * @address: byte address to write to + * @value: value to write + */ +static inline void cvmx_scratch_write8(uint64_t address, uint64_t value) +{ + *CASTPTR(volatile uint8_t, CVMX_SCRATCH_BASE + address) = + (uint8_t) value; +} + +/** + * Writes a 32 bit value to the processor local scratchpad memory. + * + * @address: byte address to write to + * @value: value to write + */ +static inline void cvmx_scratch_write16(uint64_t address, uint64_t value) +{ + *CASTPTR(volatile uint16_t, CVMX_SCRATCH_BASE + address) = + (uint16_t) value; +} + +/** + * Writes a 16 bit value to the processor local scratchpad memory. + * + * @address: byte address to write to + * @value: value to write + */ +static inline void cvmx_scratch_write32(uint64_t address, uint64_t value) +{ + *CASTPTR(volatile uint32_t, CVMX_SCRATCH_BASE + address) = + (uint32_t) value; +} + +/** + * Writes a 64 bit value to the processor local scratchpad memory. + * + * @address: byte address to write to + * @value: value to write + */ +static inline void cvmx_scratch_write64(uint64_t address, uint64_t value) +{ + *CASTPTR(volatile uint64_t, CVMX_SCRATCH_BASE + address) = value; +} + +#endif /* __CVMX_SCRATCH_H__ */ diff --git a/drivers/staging/octeon/cvmx-smix-defs.h b/drivers/staging/octeon/cvmx-smix-defs.h new file mode 100644 index 000000000000..9ae45fcbe3e3 --- /dev/null +++ b/drivers/staging/octeon/cvmx-smix-defs.h @@ -0,0 +1,178 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2008 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +#ifndef __CVMX_SMIX_DEFS_H__ +#define __CVMX_SMIX_DEFS_H__ + +#define CVMX_SMIX_CLK(offset) \ + CVMX_ADD_IO_SEG(0x0001180000001818ull + (((offset) & 1) * 256)) +#define CVMX_SMIX_CMD(offset) \ + CVMX_ADD_IO_SEG(0x0001180000001800ull + (((offset) & 1) * 256)) +#define CVMX_SMIX_EN(offset) \ + CVMX_ADD_IO_SEG(0x0001180000001820ull + (((offset) & 1) * 256)) +#define CVMX_SMIX_RD_DAT(offset) \ + CVMX_ADD_IO_SEG(0x0001180000001810ull + (((offset) & 1) * 256)) +#define CVMX_SMIX_WR_DAT(offset) \ + CVMX_ADD_IO_SEG(0x0001180000001808ull + (((offset) & 1) * 256)) + +union cvmx_smix_clk { + uint64_t u64; + struct cvmx_smix_clk_s { + uint64_t reserved_25_63:39; + uint64_t mode:1; + uint64_t reserved_21_23:3; + uint64_t sample_hi:5; + uint64_t sample_mode:1; + uint64_t reserved_14_14:1; + uint64_t clk_idle:1; + uint64_t preamble:1; + uint64_t sample:4; + uint64_t phase:8; + } s; + struct cvmx_smix_clk_cn30xx { + uint64_t reserved_21_63:43; + uint64_t sample_hi:5; + uint64_t reserved_14_15:2; + uint64_t clk_idle:1; + uint64_t preamble:1; + uint64_t sample:4; + uint64_t phase:8; + } cn30xx; + struct cvmx_smix_clk_cn30xx cn31xx; + struct cvmx_smix_clk_cn30xx cn38xx; + struct cvmx_smix_clk_cn30xx cn38xxp2; + struct cvmx_smix_clk_cn50xx { + uint64_t reserved_25_63:39; + uint64_t mode:1; + uint64_t reserved_21_23:3; + uint64_t sample_hi:5; + uint64_t reserved_14_15:2; + uint64_t clk_idle:1; + uint64_t preamble:1; + uint64_t sample:4; + uint64_t phase:8; + } cn50xx; + struct cvmx_smix_clk_s cn52xx; + struct cvmx_smix_clk_cn50xx cn52xxp1; + struct cvmx_smix_clk_s cn56xx; + struct cvmx_smix_clk_cn50xx cn56xxp1; + struct cvmx_smix_clk_cn30xx cn58xx; + struct cvmx_smix_clk_cn30xx cn58xxp1; +}; + +union cvmx_smix_cmd { + uint64_t u64; + struct cvmx_smix_cmd_s { + uint64_t reserved_18_63:46; + uint64_t phy_op:2; + uint64_t reserved_13_15:3; + uint64_t phy_adr:5; + uint64_t reserved_5_7:3; + uint64_t reg_adr:5; + } s; + struct cvmx_smix_cmd_cn30xx { + uint64_t reserved_17_63:47; + uint64_t phy_op:1; + uint64_t reserved_13_15:3; + uint64_t phy_adr:5; + uint64_t reserved_5_7:3; + uint64_t reg_adr:5; + } cn30xx; + struct cvmx_smix_cmd_cn30xx cn31xx; + struct cvmx_smix_cmd_cn30xx cn38xx; + struct cvmx_smix_cmd_cn30xx cn38xxp2; + struct cvmx_smix_cmd_s cn50xx; + struct cvmx_smix_cmd_s cn52xx; + struct cvmx_smix_cmd_s cn52xxp1; + struct cvmx_smix_cmd_s cn56xx; + struct cvmx_smix_cmd_s cn56xxp1; + struct cvmx_smix_cmd_cn30xx cn58xx; + struct cvmx_smix_cmd_cn30xx cn58xxp1; +}; + +union cvmx_smix_en { + uint64_t u64; + struct cvmx_smix_en_s { + uint64_t reserved_1_63:63; + uint64_t en:1; + } s; + struct cvmx_smix_en_s cn30xx; + struct cvmx_smix_en_s cn31xx; + struct cvmx_smix_en_s cn38xx; + struct cvmx_smix_en_s cn38xxp2; + struct cvmx_smix_en_s cn50xx; + struct cvmx_smix_en_s cn52xx; + struct cvmx_smix_en_s cn52xxp1; + struct cvmx_smix_en_s cn56xx; + struct cvmx_smix_en_s cn56xxp1; + struct cvmx_smix_en_s cn58xx; + struct cvmx_smix_en_s cn58xxp1; +}; + +union cvmx_smix_rd_dat { + uint64_t u64; + struct cvmx_smix_rd_dat_s { + uint64_t reserved_18_63:46; + uint64_t pending:1; + uint64_t val:1; + uint64_t dat:16; + } s; + struct cvmx_smix_rd_dat_s cn30xx; + struct cvmx_smix_rd_dat_s cn31xx; + struct cvmx_smix_rd_dat_s cn38xx; + struct cvmx_smix_rd_dat_s cn38xxp2; + struct cvmx_smix_rd_dat_s cn50xx; + struct cvmx_smix_rd_dat_s cn52xx; + struct cvmx_smix_rd_dat_s cn52xxp1; + struct cvmx_smix_rd_dat_s cn56xx; + struct cvmx_smix_rd_dat_s cn56xxp1; + struct cvmx_smix_rd_dat_s cn58xx; + struct cvmx_smix_rd_dat_s cn58xxp1; +}; + +union cvmx_smix_wr_dat { + uint64_t u64; + struct cvmx_smix_wr_dat_s { + uint64_t reserved_18_63:46; + uint64_t pending:1; + uint64_t val:1; + uint64_t dat:16; + } s; + struct cvmx_smix_wr_dat_s cn30xx; + struct cvmx_smix_wr_dat_s cn31xx; + struct cvmx_smix_wr_dat_s cn38xx; + struct cvmx_smix_wr_dat_s cn38xxp2; + struct cvmx_smix_wr_dat_s cn50xx; + struct cvmx_smix_wr_dat_s cn52xx; + struct cvmx_smix_wr_dat_s cn52xxp1; + struct cvmx_smix_wr_dat_s cn56xx; + struct cvmx_smix_wr_dat_s cn56xxp1; + struct cvmx_smix_wr_dat_s cn58xx; + struct cvmx_smix_wr_dat_s cn58xxp1; +}; + +#endif diff --git a/drivers/staging/octeon/cvmx-spi.c b/drivers/staging/octeon/cvmx-spi.c new file mode 100644 index 000000000000..82794d920cec --- /dev/null +++ b/drivers/staging/octeon/cvmx-spi.c @@ -0,0 +1,667 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2008 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +/* + * + * Support library for the SPI + */ +#include + +#include "cvmx-config.h" + +#include "cvmx-pko.h" +#include "cvmx-spi.h" + +#include "cvmx-spxx-defs.h" +#include "cvmx-stxx-defs.h" +#include "cvmx-srxx-defs.h" + +#define INVOKE_CB(function_p, args...) \ + do { \ + if (function_p) { \ + res = function_p(args); \ + if (res) \ + return res; \ + } \ + } while (0) + +#if CVMX_ENABLE_DEBUG_PRINTS +static const char *modes[] = + { "UNKNOWN", "TX Halfplex", "Rx Halfplex", "Duplex" }; +#endif + +/* Default callbacks, can be overridden + * using cvmx_spi_get_callbacks/cvmx_spi_set_callbacks + */ +static cvmx_spi_callbacks_t cvmx_spi_callbacks = { + .reset_cb = cvmx_spi_reset_cb, + .calendar_setup_cb = cvmx_spi_calendar_setup_cb, + .clock_detect_cb = cvmx_spi_clock_detect_cb, + .training_cb = cvmx_spi_training_cb, + .calendar_sync_cb = cvmx_spi_calendar_sync_cb, + .interface_up_cb = cvmx_spi_interface_up_cb +}; + +/** + * Get current SPI4 initialization callbacks + * + * @callbacks: Pointer to the callbacks structure.to fill + * + * Returns Pointer to cvmx_spi_callbacks_t structure. + */ +void cvmx_spi_get_callbacks(cvmx_spi_callbacks_t *callbacks) +{ + memcpy(callbacks, &cvmx_spi_callbacks, sizeof(cvmx_spi_callbacks)); +} + +/** + * Set new SPI4 initialization callbacks + * + * @new_callbacks: Pointer to an updated callbacks structure. + */ +void cvmx_spi_set_callbacks(cvmx_spi_callbacks_t *new_callbacks) +{ + memcpy(&cvmx_spi_callbacks, new_callbacks, sizeof(cvmx_spi_callbacks)); +} + +/** + * Initialize and start the SPI interface. + * + * @interface: The identifier of the packet interface to configure and + * use as a SPI interface. + * @mode: The operating mode for the SPI interface. The interface + * can operate as a full duplex (both Tx and Rx data paths + * active) or as a halfplex (either the Tx data path is + * active or the Rx data path is active, but not both). + * @timeout: Timeout to wait for clock synchronization in seconds + * @num_ports: Number of SPI ports to configure + * + * Returns Zero on success, negative of failure. + */ +int cvmx_spi_start_interface(int interface, cvmx_spi_mode_t mode, int timeout, + int num_ports) +{ + int res = -1; + + if (!(OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX))) + return res; + + /* Callback to perform SPI4 reset */ + INVOKE_CB(cvmx_spi_callbacks.reset_cb, interface, mode); + + /* Callback to perform calendar setup */ + INVOKE_CB(cvmx_spi_callbacks.calendar_setup_cb, interface, mode, + num_ports); + + /* Callback to perform clock detection */ + INVOKE_CB(cvmx_spi_callbacks.clock_detect_cb, interface, mode, timeout); + + /* Callback to perform SPI4 link training */ + INVOKE_CB(cvmx_spi_callbacks.training_cb, interface, mode, timeout); + + /* Callback to perform calendar sync */ + INVOKE_CB(cvmx_spi_callbacks.calendar_sync_cb, interface, mode, + timeout); + + /* Callback to handle interface coming up */ + INVOKE_CB(cvmx_spi_callbacks.interface_up_cb, interface, mode); + + return res; +} + +/** + * This routine restarts the SPI interface after it has lost synchronization + * with its correspondent system. + * + * @interface: The identifier of the packet interface to configure and + * use as a SPI interface. + * @mode: The operating mode for the SPI interface. The interface + * can operate as a full duplex (both Tx and Rx data paths + * active) or as a halfplex (either the Tx data path is + * active or the Rx data path is active, but not both). + * @timeout: Timeout to wait for clock synchronization in seconds + * + * Returns Zero on success, negative of failure. + */ +int cvmx_spi_restart_interface(int interface, cvmx_spi_mode_t mode, int timeout) +{ + int res = -1; + + if (!(OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX))) + return res; + + cvmx_dprintf("SPI%d: Restart %s\n", interface, modes[mode]); + + /* Callback to perform SPI4 reset */ + INVOKE_CB(cvmx_spi_callbacks.reset_cb, interface, mode); + + /* NOTE: Calendar setup is not performed during restart */ + /* Refer to cvmx_spi_start_interface() for the full sequence */ + + /* Callback to perform clock detection */ + INVOKE_CB(cvmx_spi_callbacks.clock_detect_cb, interface, mode, timeout); + + /* Callback to perform SPI4 link training */ + INVOKE_CB(cvmx_spi_callbacks.training_cb, interface, mode, timeout); + + /* Callback to perform calendar sync */ + INVOKE_CB(cvmx_spi_callbacks.calendar_sync_cb, interface, mode, + timeout); + + /* Callback to handle interface coming up */ + INVOKE_CB(cvmx_spi_callbacks.interface_up_cb, interface, mode); + + return res; +} + +/** + * Callback to perform SPI4 reset + * + * @interface: The identifier of the packet interface to configure and + * use as a SPI interface. + * @mode: The operating mode for the SPI interface. The interface + * can operate as a full duplex (both Tx and Rx data paths + * active) or as a halfplex (either the Tx data path is + * active or the Rx data path is active, but not both). + * + * Returns Zero on success, non-zero error code on failure (will cause + * SPI initialization to abort) + */ +int cvmx_spi_reset_cb(int interface, cvmx_spi_mode_t mode) +{ + union cvmx_spxx_dbg_deskew_ctl spxx_dbg_deskew_ctl; + union cvmx_spxx_clk_ctl spxx_clk_ctl; + union cvmx_spxx_bist_stat spxx_bist_stat; + union cvmx_spxx_int_msk spxx_int_msk; + union cvmx_stxx_int_msk stxx_int_msk; + union cvmx_spxx_trn4_ctl spxx_trn4_ctl; + int index; + uint64_t MS = cvmx_sysinfo_get()->cpu_clock_hz / 1000; + + /* Disable SPI error events while we run BIST */ + spxx_int_msk.u64 = cvmx_read_csr(CVMX_SPXX_INT_MSK(interface)); + cvmx_write_csr(CVMX_SPXX_INT_MSK(interface), 0); + stxx_int_msk.u64 = cvmx_read_csr(CVMX_STXX_INT_MSK(interface)); + cvmx_write_csr(CVMX_STXX_INT_MSK(interface), 0); + + /* Run BIST in the SPI interface */ + cvmx_write_csr(CVMX_SRXX_COM_CTL(interface), 0); + cvmx_write_csr(CVMX_STXX_COM_CTL(interface), 0); + spxx_clk_ctl.u64 = 0; + spxx_clk_ctl.s.runbist = 1; + cvmx_write_csr(CVMX_SPXX_CLK_CTL(interface), spxx_clk_ctl.u64); + cvmx_wait(10 * MS); + spxx_bist_stat.u64 = cvmx_read_csr(CVMX_SPXX_BIST_STAT(interface)); + if (spxx_bist_stat.s.stat0) + cvmx_dprintf + ("ERROR SPI%d: BIST failed on receive datapath FIFO\n", + interface); + if (spxx_bist_stat.s.stat1) + cvmx_dprintf("ERROR SPI%d: BIST failed on RX calendar table\n", + interface); + if (spxx_bist_stat.s.stat2) + cvmx_dprintf("ERROR SPI%d: BIST failed on TX calendar table\n", + interface); + + /* Clear the calendar table after BIST to fix parity errors */ + for (index = 0; index < 32; index++) { + union cvmx_srxx_spi4_calx srxx_spi4_calx; + union cvmx_stxx_spi4_calx stxx_spi4_calx; + + srxx_spi4_calx.u64 = 0; + srxx_spi4_calx.s.oddpar = 1; + cvmx_write_csr(CVMX_SRXX_SPI4_CALX(index, interface), + srxx_spi4_calx.u64); + + stxx_spi4_calx.u64 = 0; + stxx_spi4_calx.s.oddpar = 1; + cvmx_write_csr(CVMX_STXX_SPI4_CALX(index, interface), + stxx_spi4_calx.u64); + } + + /* Re enable reporting of error interrupts */ + cvmx_write_csr(CVMX_SPXX_INT_REG(interface), + cvmx_read_csr(CVMX_SPXX_INT_REG(interface))); + cvmx_write_csr(CVMX_SPXX_INT_MSK(interface), spxx_int_msk.u64); + cvmx_write_csr(CVMX_STXX_INT_REG(interface), + cvmx_read_csr(CVMX_STXX_INT_REG(interface))); + cvmx_write_csr(CVMX_STXX_INT_MSK(interface), stxx_int_msk.u64); + + /* Setup the CLKDLY right in the middle */ + spxx_clk_ctl.u64 = 0; + spxx_clk_ctl.s.seetrn = 0; + spxx_clk_ctl.s.clkdly = 0x10; + spxx_clk_ctl.s.runbist = 0; + spxx_clk_ctl.s.statdrv = 0; + /* This should always be on the opposite edge as statdrv */ + spxx_clk_ctl.s.statrcv = 1; + spxx_clk_ctl.s.sndtrn = 0; + spxx_clk_ctl.s.drptrn = 0; + spxx_clk_ctl.s.rcvtrn = 0; + spxx_clk_ctl.s.srxdlck = 0; + cvmx_write_csr(CVMX_SPXX_CLK_CTL(interface), spxx_clk_ctl.u64); + cvmx_wait(100 * MS); + + /* Reset SRX0 DLL */ + spxx_clk_ctl.s.srxdlck = 1; + cvmx_write_csr(CVMX_SPXX_CLK_CTL(interface), spxx_clk_ctl.u64); + + /* Waiting for Inf0 Spi4 RX DLL to lock */ + cvmx_wait(100 * MS); + + /* Enable dynamic alignment */ + spxx_trn4_ctl.s.trntest = 0; + spxx_trn4_ctl.s.jitter = 1; + spxx_trn4_ctl.s.clr_boot = 1; + spxx_trn4_ctl.s.set_boot = 0; + if (OCTEON_IS_MODEL(OCTEON_CN58XX)) + spxx_trn4_ctl.s.maxdist = 3; + else + spxx_trn4_ctl.s.maxdist = 8; + spxx_trn4_ctl.s.macro_en = 1; + spxx_trn4_ctl.s.mux_en = 1; + cvmx_write_csr(CVMX_SPXX_TRN4_CTL(interface), spxx_trn4_ctl.u64); + + spxx_dbg_deskew_ctl.u64 = 0; + cvmx_write_csr(CVMX_SPXX_DBG_DESKEW_CTL(interface), + spxx_dbg_deskew_ctl.u64); + + return 0; +} + +/** + * Callback to setup calendar and miscellaneous settings before clock detection + * + * @interface: The identifier of the packet interface to configure and + * use as a SPI interface. + * @mode: The operating mode for the SPI interface. The interface + * can operate as a full duplex (both Tx and Rx data paths + * active) or as a halfplex (either the Tx data path is + * active or the Rx data path is active, but not both). + * @num_ports: Number of ports to configure on SPI + * + * Returns Zero on success, non-zero error code on failure (will cause + * SPI initialization to abort) + */ +int cvmx_spi_calendar_setup_cb(int interface, cvmx_spi_mode_t mode, + int num_ports) +{ + int port; + int index; + if (mode & CVMX_SPI_MODE_RX_HALFPLEX) { + union cvmx_srxx_com_ctl srxx_com_ctl; + union cvmx_srxx_spi4_stat srxx_spi4_stat; + + /* SRX0 number of Ports */ + srxx_com_ctl.u64 = 0; + srxx_com_ctl.s.prts = num_ports - 1; + srxx_com_ctl.s.st_en = 0; + srxx_com_ctl.s.inf_en = 0; + cvmx_write_csr(CVMX_SRXX_COM_CTL(interface), srxx_com_ctl.u64); + + /* SRX0 Calendar Table. This round robbins through all ports */ + port = 0; + index = 0; + while (port < num_ports) { + union cvmx_srxx_spi4_calx srxx_spi4_calx; + srxx_spi4_calx.u64 = 0; + srxx_spi4_calx.s.prt0 = port++; + srxx_spi4_calx.s.prt1 = port++; + srxx_spi4_calx.s.prt2 = port++; + srxx_spi4_calx.s.prt3 = port++; + srxx_spi4_calx.s.oddpar = + ~(cvmx_dpop(srxx_spi4_calx.u64) & 1); + cvmx_write_csr(CVMX_SRXX_SPI4_CALX(index, interface), + srxx_spi4_calx.u64); + index++; + } + srxx_spi4_stat.u64 = 0; + srxx_spi4_stat.s.len = num_ports; + srxx_spi4_stat.s.m = 1; + cvmx_write_csr(CVMX_SRXX_SPI4_STAT(interface), + srxx_spi4_stat.u64); + } + + if (mode & CVMX_SPI_MODE_TX_HALFPLEX) { + union cvmx_stxx_arb_ctl stxx_arb_ctl; + union cvmx_gmxx_tx_spi_max gmxx_tx_spi_max; + union cvmx_gmxx_tx_spi_thresh gmxx_tx_spi_thresh; + union cvmx_gmxx_tx_spi_ctl gmxx_tx_spi_ctl; + union cvmx_stxx_spi4_stat stxx_spi4_stat; + union cvmx_stxx_spi4_dat stxx_spi4_dat; + + /* STX0 Config */ + stxx_arb_ctl.u64 = 0; + stxx_arb_ctl.s.igntpa = 0; + stxx_arb_ctl.s.mintrn = 0; + cvmx_write_csr(CVMX_STXX_ARB_CTL(interface), stxx_arb_ctl.u64); + + gmxx_tx_spi_max.u64 = 0; + gmxx_tx_spi_max.s.max1 = 8; + gmxx_tx_spi_max.s.max2 = 4; + gmxx_tx_spi_max.s.slice = 0; + cvmx_write_csr(CVMX_GMXX_TX_SPI_MAX(interface), + gmxx_tx_spi_max.u64); + + gmxx_tx_spi_thresh.u64 = 0; + gmxx_tx_spi_thresh.s.thresh = 4; + cvmx_write_csr(CVMX_GMXX_TX_SPI_THRESH(interface), + gmxx_tx_spi_thresh.u64); + + gmxx_tx_spi_ctl.u64 = 0; + gmxx_tx_spi_ctl.s.tpa_clr = 0; + gmxx_tx_spi_ctl.s.cont_pkt = 0; + cvmx_write_csr(CVMX_GMXX_TX_SPI_CTL(interface), + gmxx_tx_spi_ctl.u64); + + /* STX0 Training Control */ + stxx_spi4_dat.u64 = 0; + /*Minimum needed by dynamic alignment */ + stxx_spi4_dat.s.alpha = 32; + stxx_spi4_dat.s.max_t = 0xFFFF; /*Minimum interval is 0x20 */ + cvmx_write_csr(CVMX_STXX_SPI4_DAT(interface), + stxx_spi4_dat.u64); + + /* STX0 Calendar Table. This round robbins through all ports */ + port = 0; + index = 0; + while (port < num_ports) { + union cvmx_stxx_spi4_calx stxx_spi4_calx; + stxx_spi4_calx.u64 = 0; + stxx_spi4_calx.s.prt0 = port++; + stxx_spi4_calx.s.prt1 = port++; + stxx_spi4_calx.s.prt2 = port++; + stxx_spi4_calx.s.prt3 = port++; + stxx_spi4_calx.s.oddpar = + ~(cvmx_dpop(stxx_spi4_calx.u64) & 1); + cvmx_write_csr(CVMX_STXX_SPI4_CALX(index, interface), + stxx_spi4_calx.u64); + index++; + } + stxx_spi4_stat.u64 = 0; + stxx_spi4_stat.s.len = num_ports; + stxx_spi4_stat.s.m = 1; + cvmx_write_csr(CVMX_STXX_SPI4_STAT(interface), + stxx_spi4_stat.u64); + } + + return 0; +} + +/** + * Callback to perform clock detection + * + * @interface: The identifier of the packet interface to configure and + * use as a SPI interface. + * @mode: The operating mode for the SPI interface. The interface + * can operate as a full duplex (both Tx and Rx data paths + * active) or as a halfplex (either the Tx data path is + * active or the Rx data path is active, but not both). + * @timeout: Timeout to wait for clock synchronization in seconds + * + * Returns Zero on success, non-zero error code on failure (will cause + * SPI initialization to abort) + */ +int cvmx_spi_clock_detect_cb(int interface, cvmx_spi_mode_t mode, int timeout) +{ + int clock_transitions; + union cvmx_spxx_clk_stat stat; + uint64_t timeout_time; + uint64_t MS = cvmx_sysinfo_get()->cpu_clock_hz / 1000; + + /* + * Regardless of operating mode, both Tx and Rx clocks must be + * present for the SPI interface to operate. + */ + cvmx_dprintf("SPI%d: Waiting to see TsClk...\n", interface); + timeout_time = cvmx_get_cycle() + 1000ull * MS * timeout; + /* + * Require 100 clock transitions in order to avoid any noise + * in the beginning. + */ + clock_transitions = 100; + do { + stat.u64 = cvmx_read_csr(CVMX_SPXX_CLK_STAT(interface)); + if (stat.s.s4clk0 && stat.s.s4clk1 && clock_transitions) { + /* + * We've seen a clock transition, so decrement + * the number we still need. + */ + clock_transitions--; + cvmx_write_csr(CVMX_SPXX_CLK_STAT(interface), stat.u64); + stat.s.s4clk0 = 0; + stat.s.s4clk1 = 0; + } + if (cvmx_get_cycle() > timeout_time) { + cvmx_dprintf("SPI%d: Timeout\n", interface); + return -1; + } + } while (stat.s.s4clk0 == 0 || stat.s.s4clk1 == 0); + + cvmx_dprintf("SPI%d: Waiting to see RsClk...\n", interface); + timeout_time = cvmx_get_cycle() + 1000ull * MS * timeout; + /* + * Require 100 clock transitions in order to avoid any noise in the + * beginning. + */ + clock_transitions = 100; + do { + stat.u64 = cvmx_read_csr(CVMX_SPXX_CLK_STAT(interface)); + if (stat.s.d4clk0 && stat.s.d4clk1 && clock_transitions) { + /* + * We've seen a clock transition, so decrement + * the number we still need + */ + clock_transitions--; + cvmx_write_csr(CVMX_SPXX_CLK_STAT(interface), stat.u64); + stat.s.d4clk0 = 0; + stat.s.d4clk1 = 0; + } + if (cvmx_get_cycle() > timeout_time) { + cvmx_dprintf("SPI%d: Timeout\n", interface); + return -1; + } + } while (stat.s.d4clk0 == 0 || stat.s.d4clk1 == 0); + + return 0; +} + +/** + * Callback to perform link training + * + * @interface: The identifier of the packet interface to configure and + * use as a SPI interface. + * @mode: The operating mode for the SPI interface. The interface + * can operate as a full duplex (both Tx and Rx data paths + * active) or as a halfplex (either the Tx data path is + * active or the Rx data path is active, but not both). + * @timeout: Timeout to wait for link to be trained (in seconds) + * + * Returns Zero on success, non-zero error code on failure (will cause + * SPI initialization to abort) + */ +int cvmx_spi_training_cb(int interface, cvmx_spi_mode_t mode, int timeout) +{ + union cvmx_spxx_trn4_ctl spxx_trn4_ctl; + union cvmx_spxx_clk_stat stat; + uint64_t MS = cvmx_sysinfo_get()->cpu_clock_hz / 1000; + uint64_t timeout_time = cvmx_get_cycle() + 1000ull * MS * timeout; + int rx_training_needed; + + /* SRX0 & STX0 Inf0 Links are configured - begin training */ + union cvmx_spxx_clk_ctl spxx_clk_ctl; + spxx_clk_ctl.u64 = 0; + spxx_clk_ctl.s.seetrn = 0; + spxx_clk_ctl.s.clkdly = 0x10; + spxx_clk_ctl.s.runbist = 0; + spxx_clk_ctl.s.statdrv = 0; + /* This should always be on the opposite edge as statdrv */ + spxx_clk_ctl.s.statrcv = 1; + spxx_clk_ctl.s.sndtrn = 1; + spxx_clk_ctl.s.drptrn = 1; + spxx_clk_ctl.s.rcvtrn = 1; + spxx_clk_ctl.s.srxdlck = 1; + cvmx_write_csr(CVMX_SPXX_CLK_CTL(interface), spxx_clk_ctl.u64); + cvmx_wait(1000 * MS); + + /* SRX0 clear the boot bit */ + spxx_trn4_ctl.u64 = cvmx_read_csr(CVMX_SPXX_TRN4_CTL(interface)); + spxx_trn4_ctl.s.clr_boot = 1; + cvmx_write_csr(CVMX_SPXX_TRN4_CTL(interface), spxx_trn4_ctl.u64); + + /* Wait for the training sequence to complete */ + cvmx_dprintf("SPI%d: Waiting for training\n", interface); + cvmx_wait(1000 * MS); + /* Wait a really long time here */ + timeout_time = cvmx_get_cycle() + 1000ull * MS * 600; + /* + * The HRM says we must wait for 34 + 16 * MAXDIST training sequences. + * We'll be pessimistic and wait for a lot more. + */ + rx_training_needed = 500; + do { + stat.u64 = cvmx_read_csr(CVMX_SPXX_CLK_STAT(interface)); + if (stat.s.srxtrn && rx_training_needed) { + rx_training_needed--; + cvmx_write_csr(CVMX_SPXX_CLK_STAT(interface), stat.u64); + stat.s.srxtrn = 0; + } + if (cvmx_get_cycle() > timeout_time) { + cvmx_dprintf("SPI%d: Timeout\n", interface); + return -1; + } + } while (stat.s.srxtrn == 0); + + return 0; +} + +/** + * Callback to perform calendar data synchronization + * + * @interface: The identifier of the packet interface to configure and + * use as a SPI interface. + * @mode: The operating mode for the SPI interface. The interface + * can operate as a full duplex (both Tx and Rx data paths + * active) or as a halfplex (either the Tx data path is + * active or the Rx data path is active, but not both). + * @timeout: Timeout to wait for calendar data in seconds + * + * Returns Zero on success, non-zero error code on failure (will cause + * SPI initialization to abort) + */ +int cvmx_spi_calendar_sync_cb(int interface, cvmx_spi_mode_t mode, int timeout) +{ + uint64_t MS = cvmx_sysinfo_get()->cpu_clock_hz / 1000; + if (mode & CVMX_SPI_MODE_RX_HALFPLEX) { + /* SRX0 interface should be good, send calendar data */ + union cvmx_srxx_com_ctl srxx_com_ctl; + cvmx_dprintf + ("SPI%d: Rx is synchronized, start sending calendar data\n", + interface); + srxx_com_ctl.u64 = cvmx_read_csr(CVMX_SRXX_COM_CTL(interface)); + srxx_com_ctl.s.inf_en = 1; + srxx_com_ctl.s.st_en = 1; + cvmx_write_csr(CVMX_SRXX_COM_CTL(interface), srxx_com_ctl.u64); + } + + if (mode & CVMX_SPI_MODE_TX_HALFPLEX) { + /* STX0 has achieved sync */ + /* The corespondant board should be sending calendar data */ + /* Enable the STX0 STAT receiver. */ + union cvmx_spxx_clk_stat stat; + uint64_t timeout_time; + union cvmx_stxx_com_ctl stxx_com_ctl; + stxx_com_ctl.u64 = 0; + stxx_com_ctl.s.st_en = 1; + cvmx_write_csr(CVMX_STXX_COM_CTL(interface), stxx_com_ctl.u64); + + /* Waiting for calendar sync on STX0 STAT */ + cvmx_dprintf("SPI%d: Waiting to sync on STX[%d] STAT\n", + interface, interface); + timeout_time = cvmx_get_cycle() + 1000ull * MS * timeout; + /* SPX0_CLK_STAT - SPX0_CLK_STAT[STXCAL] should be 1 (bit10) */ + do { + stat.u64 = cvmx_read_csr(CVMX_SPXX_CLK_STAT(interface)); + if (cvmx_get_cycle() > timeout_time) { + cvmx_dprintf("SPI%d: Timeout\n", interface); + return -1; + } + } while (stat.s.stxcal == 0); + } + + return 0; +} + +/** + * Callback to handle interface up + * + * @interface: The identifier of the packet interface to configure and + * use as a SPI interface. + * @mode: The operating mode for the SPI interface. The interface + * can operate as a full duplex (both Tx and Rx data paths + * active) or as a halfplex (either the Tx data path is + * active or the Rx data path is active, but not both). + * + * Returns Zero on success, non-zero error code on failure (will cause + * SPI initialization to abort) + */ +int cvmx_spi_interface_up_cb(int interface, cvmx_spi_mode_t mode) +{ + union cvmx_gmxx_rxx_frm_min gmxx_rxx_frm_min; + union cvmx_gmxx_rxx_frm_max gmxx_rxx_frm_max; + union cvmx_gmxx_rxx_jabber gmxx_rxx_jabber; + + if (mode & CVMX_SPI_MODE_RX_HALFPLEX) { + union cvmx_srxx_com_ctl srxx_com_ctl; + srxx_com_ctl.u64 = cvmx_read_csr(CVMX_SRXX_COM_CTL(interface)); + srxx_com_ctl.s.inf_en = 1; + cvmx_write_csr(CVMX_SRXX_COM_CTL(interface), srxx_com_ctl.u64); + cvmx_dprintf("SPI%d: Rx is now up\n", interface); + } + + if (mode & CVMX_SPI_MODE_TX_HALFPLEX) { + union cvmx_stxx_com_ctl stxx_com_ctl; + stxx_com_ctl.u64 = cvmx_read_csr(CVMX_STXX_COM_CTL(interface)); + stxx_com_ctl.s.inf_en = 1; + cvmx_write_csr(CVMX_STXX_COM_CTL(interface), stxx_com_ctl.u64); + cvmx_dprintf("SPI%d: Tx is now up\n", interface); + } + + gmxx_rxx_frm_min.u64 = 0; + gmxx_rxx_frm_min.s.len = 64; + cvmx_write_csr(CVMX_GMXX_RXX_FRM_MIN(0, interface), + gmxx_rxx_frm_min.u64); + gmxx_rxx_frm_max.u64 = 0; + gmxx_rxx_frm_max.s.len = 64 * 1024 - 4; + cvmx_write_csr(CVMX_GMXX_RXX_FRM_MAX(0, interface), + gmxx_rxx_frm_max.u64); + gmxx_rxx_jabber.u64 = 0; + gmxx_rxx_jabber.s.cnt = 64 * 1024 - 4; + cvmx_write_csr(CVMX_GMXX_RXX_JABBER(0, interface), gmxx_rxx_jabber.u64); + + return 0; +} diff --git a/drivers/staging/octeon/cvmx-spi.h b/drivers/staging/octeon/cvmx-spi.h new file mode 100644 index 000000000000..e814648953a5 --- /dev/null +++ b/drivers/staging/octeon/cvmx-spi.h @@ -0,0 +1,269 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2008 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +/* + * + * This file contains defines for the SPI interface + */ +#ifndef __CVMX_SPI_H__ +#define __CVMX_SPI_H__ + +#include "cvmx-gmxx-defs.h" + +/* CSR typedefs have been moved to cvmx-csr-*.h */ + +typedef enum { + CVMX_SPI_MODE_UNKNOWN = 0, + CVMX_SPI_MODE_TX_HALFPLEX = 1, + CVMX_SPI_MODE_RX_HALFPLEX = 2, + CVMX_SPI_MODE_DUPLEX = 3 +} cvmx_spi_mode_t; + +/** Callbacks structure to customize SPI4 initialization sequence */ +typedef struct { + /** Called to reset SPI4 DLL */ + int (*reset_cb) (int interface, cvmx_spi_mode_t mode); + + /** Called to setup calendar */ + int (*calendar_setup_cb) (int interface, cvmx_spi_mode_t mode, + int num_ports); + + /** Called for Tx and Rx clock detection */ + int (*clock_detect_cb) (int interface, cvmx_spi_mode_t mode, + int timeout); + + /** Called to perform link training */ + int (*training_cb) (int interface, cvmx_spi_mode_t mode, int timeout); + + /** Called for calendar data synchronization */ + int (*calendar_sync_cb) (int interface, cvmx_spi_mode_t mode, + int timeout); + + /** Called when interface is up */ + int (*interface_up_cb) (int interface, cvmx_spi_mode_t mode); + +} cvmx_spi_callbacks_t; + +/** + * Return true if the supplied interface is configured for SPI + * + * @interface: Interface to check + * Returns True if interface is SPI + */ +static inline int cvmx_spi_is_spi_interface(int interface) +{ + uint64_t gmxState = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface)); + return (gmxState & 0x2) && (gmxState & 0x1); +} + +/** + * Initialize and start the SPI interface. + * + * @interface: The identifier of the packet interface to configure and + * use as a SPI interface. + * @mode: The operating mode for the SPI interface. The interface + * can operate as a full duplex (both Tx and Rx data paths + * active) or as a halfplex (either the Tx data path is + * active or the Rx data path is active, but not both). + * @timeout: Timeout to wait for clock synchronization in seconds + * @num_ports: Number of SPI ports to configure + * + * Returns Zero on success, negative of failure. + */ +extern int cvmx_spi_start_interface(int interface, cvmx_spi_mode_t mode, + int timeout, int num_ports); + +/** + * This routine restarts the SPI interface after it has lost synchronization + * with its corespondant system. + * + * @interface: The identifier of the packet interface to configure and + * use as a SPI interface. + * @mode: The operating mode for the SPI interface. The interface + * can operate as a full duplex (both Tx and Rx data paths + * active) or as a halfplex (either the Tx data path is + * active or the Rx data path is active, but not both). + * @timeout: Timeout to wait for clock synchronization in seconds + * Returns Zero on success, negative of failure. + */ +extern int cvmx_spi_restart_interface(int interface, cvmx_spi_mode_t mode, + int timeout); + +/** + * Return non-zero if the SPI interface has a SPI4000 attached + * + * @interface: SPI interface the SPI4000 is connected to + * + * Returns + */ +static inline int cvmx_spi4000_is_present(int interface) +{ + return 0; +} + +/** + * Initialize the SPI4000 for use + * + * @interface: SPI interface the SPI4000 is connected to + */ +static inline int cvmx_spi4000_initialize(int interface) +{ + return 0; +} + +/** + * Poll all the SPI4000 port and check its speed + * + * @interface: Interface the SPI4000 is on + * @port: Port to poll (0-9) + * Returns Status of the port. 0=down. All other values the port is up. + */ +static inline union cvmx_gmxx_rxx_rx_inbnd cvmx_spi4000_check_speed( + int interface, + int port) +{ + union cvmx_gmxx_rxx_rx_inbnd r; + r.u64 = 0; + return r; +} + +/** + * Get current SPI4 initialization callbacks + * + * @callbacks: Pointer to the callbacks structure.to fill + * + * Returns Pointer to cvmx_spi_callbacks_t structure. + */ +extern void cvmx_spi_get_callbacks(cvmx_spi_callbacks_t *callbacks); + +/** + * Set new SPI4 initialization callbacks + * + * @new_callbacks: Pointer to an updated callbacks structure. + */ +extern void cvmx_spi_set_callbacks(cvmx_spi_callbacks_t *new_callbacks); + +/** + * Callback to perform SPI4 reset + * + * @interface: The identifier of the packet interface to configure and + * use as a SPI interface. + * @mode: The operating mode for the SPI interface. The interface + * can operate as a full duplex (both Tx and Rx data paths + * active) or as a halfplex (either the Tx data path is + * active or the Rx data path is active, but not both). + * + * Returns Zero on success, non-zero error code on failure (will cause + * SPI initialization to abort) + */ +extern int cvmx_spi_reset_cb(int interface, cvmx_spi_mode_t mode); + +/** + * Callback to setup calendar and miscellaneous settings before clock + * detection + * + * @interface: The identifier of the packet interface to configure and + * use as a SPI interface. + * @mode: The operating mode for the SPI interface. The interface + * can operate as a full duplex (both Tx and Rx data paths + * active) or as a halfplex (either the Tx data path is + * active or the Rx data path is active, but not both). + * @num_ports: Number of ports to configure on SPI + * + * Returns Zero on success, non-zero error code on failure (will cause + * SPI initialization to abort) + */ +extern int cvmx_spi_calendar_setup_cb(int interface, cvmx_spi_mode_t mode, + int num_ports); + +/** + * Callback to perform clock detection + * + * @interface: The identifier of the packet interface to configure and + * use as a SPI interface. + * @mode: The operating mode for the SPI interface. The interface + * can operate as a full duplex (both Tx and Rx data paths + * active) or as a halfplex (either the Tx data path is + * active or the Rx data path is active, but not both). + * @timeout: Timeout to wait for clock synchronization in seconds + * + * Returns Zero on success, non-zero error code on failure (will cause + * SPI initialization to abort) + */ +extern int cvmx_spi_clock_detect_cb(int interface, cvmx_spi_mode_t mode, + int timeout); + +/** + * Callback to perform link training + * + * @interface: The identifier of the packet interface to configure and + * use as a SPI interface. + * @mode: The operating mode for the SPI interface. The interface + * can operate as a full duplex (both Tx and Rx data paths + * active) or as a halfplex (either the Tx data path is + * active or the Rx data path is active, but not both). + * @timeout: Timeout to wait for link to be trained (in seconds) + * + * Returns Zero on success, non-zero error code on failure (will cause + * SPI initialization to abort) + */ +extern int cvmx_spi_training_cb(int interface, cvmx_spi_mode_t mode, + int timeout); + +/** + * Callback to perform calendar data synchronization + * + * @interface: The identifier of the packet interface to configure and + * use as a SPI interface. + * @mode: The operating mode for the SPI interface. The interface + * can operate as a full duplex (both Tx and Rx data paths + * active) or as a halfplex (either the Tx data path is + * active or the Rx data path is active, but not both). + * @timeout: Timeout to wait for calendar data in seconds + * + * Returns Zero on success, non-zero error code on failure (will cause + * SPI initialization to abort) + */ +extern int cvmx_spi_calendar_sync_cb(int interface, cvmx_spi_mode_t mode, + int timeout); + +/** + * Callback to handle interface up + * + * @interface: The identifier of the packet interface to configure and + * use as a SPI interface. + * @mode: The operating mode for the SPI interface. The interface + * can operate as a full duplex (both Tx and Rx data paths + * active) or as a halfplex (either the Tx data path is + * active or the Rx data path is active, but not both). + * + * Returns Zero on success, non-zero error code on failure (will cause + * SPI initialization to abort) + */ +extern int cvmx_spi_interface_up_cb(int interface, cvmx_spi_mode_t mode); + +#endif /* __CVMX_SPI_H__ */ diff --git a/drivers/staging/octeon/cvmx-spxx-defs.h b/drivers/staging/octeon/cvmx-spxx-defs.h new file mode 100644 index 000000000000..b16940e32c83 --- /dev/null +++ b/drivers/staging/octeon/cvmx-spxx-defs.h @@ -0,0 +1,347 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2008 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +#ifndef __CVMX_SPXX_DEFS_H__ +#define __CVMX_SPXX_DEFS_H__ + +#define CVMX_SPXX_BCKPRS_CNT(block_id) \ + CVMX_ADD_IO_SEG(0x0001180090000340ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_SPXX_BIST_STAT(block_id) \ + CVMX_ADD_IO_SEG(0x00011800900007F8ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_SPXX_CLK_CTL(block_id) \ + CVMX_ADD_IO_SEG(0x0001180090000348ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_SPXX_CLK_STAT(block_id) \ + CVMX_ADD_IO_SEG(0x0001180090000350ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_SPXX_DBG_DESKEW_CTL(block_id) \ + CVMX_ADD_IO_SEG(0x0001180090000368ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_SPXX_DBG_DESKEW_STATE(block_id) \ + CVMX_ADD_IO_SEG(0x0001180090000370ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_SPXX_DRV_CTL(block_id) \ + CVMX_ADD_IO_SEG(0x0001180090000358ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_SPXX_ERR_CTL(block_id) \ + CVMX_ADD_IO_SEG(0x0001180090000320ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_SPXX_INT_DAT(block_id) \ + CVMX_ADD_IO_SEG(0x0001180090000318ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_SPXX_INT_MSK(block_id) \ + CVMX_ADD_IO_SEG(0x0001180090000308ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_SPXX_INT_REG(block_id) \ + CVMX_ADD_IO_SEG(0x0001180090000300ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_SPXX_INT_SYNC(block_id) \ + CVMX_ADD_IO_SEG(0x0001180090000310ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_SPXX_TPA_ACC(block_id) \ + CVMX_ADD_IO_SEG(0x0001180090000338ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_SPXX_TPA_MAX(block_id) \ + CVMX_ADD_IO_SEG(0x0001180090000330ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_SPXX_TPA_SEL(block_id) \ + CVMX_ADD_IO_SEG(0x0001180090000328ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_SPXX_TRN4_CTL(block_id) \ + CVMX_ADD_IO_SEG(0x0001180090000360ull + (((block_id) & 1) * 0x8000000ull)) + +union cvmx_spxx_bckprs_cnt { + uint64_t u64; + struct cvmx_spxx_bckprs_cnt_s { + uint64_t reserved_32_63:32; + uint64_t cnt:32; + } s; + struct cvmx_spxx_bckprs_cnt_s cn38xx; + struct cvmx_spxx_bckprs_cnt_s cn38xxp2; + struct cvmx_spxx_bckprs_cnt_s cn58xx; + struct cvmx_spxx_bckprs_cnt_s cn58xxp1; +}; + +union cvmx_spxx_bist_stat { + uint64_t u64; + struct cvmx_spxx_bist_stat_s { + uint64_t reserved_3_63:61; + uint64_t stat2:1; + uint64_t stat1:1; + uint64_t stat0:1; + } s; + struct cvmx_spxx_bist_stat_s cn38xx; + struct cvmx_spxx_bist_stat_s cn38xxp2; + struct cvmx_spxx_bist_stat_s cn58xx; + struct cvmx_spxx_bist_stat_s cn58xxp1; +}; + +union cvmx_spxx_clk_ctl { + uint64_t u64; + struct cvmx_spxx_clk_ctl_s { + uint64_t reserved_17_63:47; + uint64_t seetrn:1; + uint64_t reserved_12_15:4; + uint64_t clkdly:5; + uint64_t runbist:1; + uint64_t statdrv:1; + uint64_t statrcv:1; + uint64_t sndtrn:1; + uint64_t drptrn:1; + uint64_t rcvtrn:1; + uint64_t srxdlck:1; + } s; + struct cvmx_spxx_clk_ctl_s cn38xx; + struct cvmx_spxx_clk_ctl_s cn38xxp2; + struct cvmx_spxx_clk_ctl_s cn58xx; + struct cvmx_spxx_clk_ctl_s cn58xxp1; +}; + +union cvmx_spxx_clk_stat { + uint64_t u64; + struct cvmx_spxx_clk_stat_s { + uint64_t reserved_11_63:53; + uint64_t stxcal:1; + uint64_t reserved_9_9:1; + uint64_t srxtrn:1; + uint64_t s4clk1:1; + uint64_t s4clk0:1; + uint64_t d4clk1:1; + uint64_t d4clk0:1; + uint64_t reserved_0_3:4; + } s; + struct cvmx_spxx_clk_stat_s cn38xx; + struct cvmx_spxx_clk_stat_s cn38xxp2; + struct cvmx_spxx_clk_stat_s cn58xx; + struct cvmx_spxx_clk_stat_s cn58xxp1; +}; + +union cvmx_spxx_dbg_deskew_ctl { + uint64_t u64; + struct cvmx_spxx_dbg_deskew_ctl_s { + uint64_t reserved_30_63:34; + uint64_t fallnop:1; + uint64_t fall8:1; + uint64_t reserved_26_27:2; + uint64_t sstep_go:1; + uint64_t sstep:1; + uint64_t reserved_22_23:2; + uint64_t clrdly:1; + uint64_t dec:1; + uint64_t inc:1; + uint64_t mux:1; + uint64_t offset:5; + uint64_t bitsel:5; + uint64_t offdly:6; + uint64_t dllfrc:1; + uint64_t dlldis:1; + } s; + struct cvmx_spxx_dbg_deskew_ctl_s cn38xx; + struct cvmx_spxx_dbg_deskew_ctl_s cn38xxp2; + struct cvmx_spxx_dbg_deskew_ctl_s cn58xx; + struct cvmx_spxx_dbg_deskew_ctl_s cn58xxp1; +}; + +union cvmx_spxx_dbg_deskew_state { + uint64_t u64; + struct cvmx_spxx_dbg_deskew_state_s { + uint64_t reserved_9_63:55; + uint64_t testres:1; + uint64_t unxterm:1; + uint64_t muxsel:2; + uint64_t offset:5; + } s; + struct cvmx_spxx_dbg_deskew_state_s cn38xx; + struct cvmx_spxx_dbg_deskew_state_s cn38xxp2; + struct cvmx_spxx_dbg_deskew_state_s cn58xx; + struct cvmx_spxx_dbg_deskew_state_s cn58xxp1; +}; + +union cvmx_spxx_drv_ctl { + uint64_t u64; + struct cvmx_spxx_drv_ctl_s { + uint64_t reserved_0_63:64; + } s; + struct cvmx_spxx_drv_ctl_cn38xx { + uint64_t reserved_16_63:48; + uint64_t stx4ncmp:4; + uint64_t stx4pcmp:4; + uint64_t srx4cmp:8; + } cn38xx; + struct cvmx_spxx_drv_ctl_cn38xx cn38xxp2; + struct cvmx_spxx_drv_ctl_cn58xx { + uint64_t reserved_24_63:40; + uint64_t stx4ncmp:4; + uint64_t stx4pcmp:4; + uint64_t reserved_10_15:6; + uint64_t srx4cmp:10; + } cn58xx; + struct cvmx_spxx_drv_ctl_cn58xx cn58xxp1; +}; + +union cvmx_spxx_err_ctl { + uint64_t u64; + struct cvmx_spxx_err_ctl_s { + uint64_t reserved_9_63:55; + uint64_t prtnxa:1; + uint64_t dipcls:1; + uint64_t dippay:1; + uint64_t reserved_4_5:2; + uint64_t errcnt:4; + } s; + struct cvmx_spxx_err_ctl_s cn38xx; + struct cvmx_spxx_err_ctl_s cn38xxp2; + struct cvmx_spxx_err_ctl_s cn58xx; + struct cvmx_spxx_err_ctl_s cn58xxp1; +}; + +union cvmx_spxx_int_dat { + uint64_t u64; + struct cvmx_spxx_int_dat_s { + uint64_t reserved_32_63:32; + uint64_t mul:1; + uint64_t reserved_14_30:17; + uint64_t calbnk:2; + uint64_t rsvop:4; + uint64_t prt:8; + } s; + struct cvmx_spxx_int_dat_s cn38xx; + struct cvmx_spxx_int_dat_s cn38xxp2; + struct cvmx_spxx_int_dat_s cn58xx; + struct cvmx_spxx_int_dat_s cn58xxp1; +}; + +union cvmx_spxx_int_msk { + uint64_t u64; + struct cvmx_spxx_int_msk_s { + uint64_t reserved_12_63:52; + uint64_t calerr:1; + uint64_t syncerr:1; + uint64_t diperr:1; + uint64_t tpaovr:1; + uint64_t rsverr:1; + uint64_t drwnng:1; + uint64_t clserr:1; + uint64_t spiovr:1; + uint64_t reserved_2_3:2; + uint64_t abnorm:1; + uint64_t prtnxa:1; + } s; + struct cvmx_spxx_int_msk_s cn38xx; + struct cvmx_spxx_int_msk_s cn38xxp2; + struct cvmx_spxx_int_msk_s cn58xx; + struct cvmx_spxx_int_msk_s cn58xxp1; +}; + +union cvmx_spxx_int_reg { + uint64_t u64; + struct cvmx_spxx_int_reg_s { + uint64_t reserved_32_63:32; + uint64_t spf:1; + uint64_t reserved_12_30:19; + uint64_t calerr:1; + uint64_t syncerr:1; + uint64_t diperr:1; + uint64_t tpaovr:1; + uint64_t rsverr:1; + uint64_t drwnng:1; + uint64_t clserr:1; + uint64_t spiovr:1; + uint64_t reserved_2_3:2; + uint64_t abnorm:1; + uint64_t prtnxa:1; + } s; + struct cvmx_spxx_int_reg_s cn38xx; + struct cvmx_spxx_int_reg_s cn38xxp2; + struct cvmx_spxx_int_reg_s cn58xx; + struct cvmx_spxx_int_reg_s cn58xxp1; +}; + +union cvmx_spxx_int_sync { + uint64_t u64; + struct cvmx_spxx_int_sync_s { + uint64_t reserved_12_63:52; + uint64_t calerr:1; + uint64_t syncerr:1; + uint64_t diperr:1; + uint64_t tpaovr:1; + uint64_t rsverr:1; + uint64_t drwnng:1; + uint64_t clserr:1; + uint64_t spiovr:1; + uint64_t reserved_2_3:2; + uint64_t abnorm:1; + uint64_t prtnxa:1; + } s; + struct cvmx_spxx_int_sync_s cn38xx; + struct cvmx_spxx_int_sync_s cn38xxp2; + struct cvmx_spxx_int_sync_s cn58xx; + struct cvmx_spxx_int_sync_s cn58xxp1; +}; + +union cvmx_spxx_tpa_acc { + uint64_t u64; + struct cvmx_spxx_tpa_acc_s { + uint64_t reserved_32_63:32; + uint64_t cnt:32; + } s; + struct cvmx_spxx_tpa_acc_s cn38xx; + struct cvmx_spxx_tpa_acc_s cn38xxp2; + struct cvmx_spxx_tpa_acc_s cn58xx; + struct cvmx_spxx_tpa_acc_s cn58xxp1; +}; + +union cvmx_spxx_tpa_max { + uint64_t u64; + struct cvmx_spxx_tpa_max_s { + uint64_t reserved_32_63:32; + uint64_t max:32; + } s; + struct cvmx_spxx_tpa_max_s cn38xx; + struct cvmx_spxx_tpa_max_s cn38xxp2; + struct cvmx_spxx_tpa_max_s cn58xx; + struct cvmx_spxx_tpa_max_s cn58xxp1; +}; + +union cvmx_spxx_tpa_sel { + uint64_t u64; + struct cvmx_spxx_tpa_sel_s { + uint64_t reserved_4_63:60; + uint64_t prtsel:4; + } s; + struct cvmx_spxx_tpa_sel_s cn38xx; + struct cvmx_spxx_tpa_sel_s cn38xxp2; + struct cvmx_spxx_tpa_sel_s cn58xx; + struct cvmx_spxx_tpa_sel_s cn58xxp1; +}; + +union cvmx_spxx_trn4_ctl { + uint64_t u64; + struct cvmx_spxx_trn4_ctl_s { + uint64_t reserved_13_63:51; + uint64_t trntest:1; + uint64_t jitter:3; + uint64_t clr_boot:1; + uint64_t set_boot:1; + uint64_t maxdist:5; + uint64_t macro_en:1; + uint64_t mux_en:1; + } s; + struct cvmx_spxx_trn4_ctl_s cn38xx; + struct cvmx_spxx_trn4_ctl_s cn38xxp2; + struct cvmx_spxx_trn4_ctl_s cn58xx; + struct cvmx_spxx_trn4_ctl_s cn58xxp1; +}; + +#endif diff --git a/drivers/staging/octeon/cvmx-srxx-defs.h b/drivers/staging/octeon/cvmx-srxx-defs.h new file mode 100644 index 000000000000..d82b366c279f --- /dev/null +++ b/drivers/staging/octeon/cvmx-srxx-defs.h @@ -0,0 +1,126 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2008 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +#ifndef __CVMX_SRXX_DEFS_H__ +#define __CVMX_SRXX_DEFS_H__ + +#define CVMX_SRXX_COM_CTL(block_id) \ + CVMX_ADD_IO_SEG(0x0001180090000200ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_SRXX_IGN_RX_FULL(block_id) \ + CVMX_ADD_IO_SEG(0x0001180090000218ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_SRXX_SPI4_CALX(offset, block_id) \ + CVMX_ADD_IO_SEG(0x0001180090000000ull + (((offset) & 31) * 8) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_SRXX_SPI4_STAT(block_id) \ + CVMX_ADD_IO_SEG(0x0001180090000208ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_SRXX_SW_TICK_CTL(block_id) \ + CVMX_ADD_IO_SEG(0x0001180090000220ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_SRXX_SW_TICK_DAT(block_id) \ + CVMX_ADD_IO_SEG(0x0001180090000228ull + (((block_id) & 1) * 0x8000000ull)) + +union cvmx_srxx_com_ctl { + uint64_t u64; + struct cvmx_srxx_com_ctl_s { + uint64_t reserved_8_63:56; + uint64_t prts:4; + uint64_t st_en:1; + uint64_t reserved_1_2:2; + uint64_t inf_en:1; + } s; + struct cvmx_srxx_com_ctl_s cn38xx; + struct cvmx_srxx_com_ctl_s cn38xxp2; + struct cvmx_srxx_com_ctl_s cn58xx; + struct cvmx_srxx_com_ctl_s cn58xxp1; +}; + +union cvmx_srxx_ign_rx_full { + uint64_t u64; + struct cvmx_srxx_ign_rx_full_s { + uint64_t reserved_16_63:48; + uint64_t ignore:16; + } s; + struct cvmx_srxx_ign_rx_full_s cn38xx; + struct cvmx_srxx_ign_rx_full_s cn38xxp2; + struct cvmx_srxx_ign_rx_full_s cn58xx; + struct cvmx_srxx_ign_rx_full_s cn58xxp1; +}; + +union cvmx_srxx_spi4_calx { + uint64_t u64; + struct cvmx_srxx_spi4_calx_s { + uint64_t reserved_17_63:47; + uint64_t oddpar:1; + uint64_t prt3:4; + uint64_t prt2:4; + uint64_t prt1:4; + uint64_t prt0:4; + } s; + struct cvmx_srxx_spi4_calx_s cn38xx; + struct cvmx_srxx_spi4_calx_s cn38xxp2; + struct cvmx_srxx_spi4_calx_s cn58xx; + struct cvmx_srxx_spi4_calx_s cn58xxp1; +}; + +union cvmx_srxx_spi4_stat { + uint64_t u64; + struct cvmx_srxx_spi4_stat_s { + uint64_t reserved_16_63:48; + uint64_t m:8; + uint64_t reserved_7_7:1; + uint64_t len:7; + } s; + struct cvmx_srxx_spi4_stat_s cn38xx; + struct cvmx_srxx_spi4_stat_s cn38xxp2; + struct cvmx_srxx_spi4_stat_s cn58xx; + struct cvmx_srxx_spi4_stat_s cn58xxp1; +}; + +union cvmx_srxx_sw_tick_ctl { + uint64_t u64; + struct cvmx_srxx_sw_tick_ctl_s { + uint64_t reserved_14_63:50; + uint64_t eop:1; + uint64_t sop:1; + uint64_t mod:4; + uint64_t opc:4; + uint64_t adr:4; + } s; + struct cvmx_srxx_sw_tick_ctl_s cn38xx; + struct cvmx_srxx_sw_tick_ctl_s cn58xx; + struct cvmx_srxx_sw_tick_ctl_s cn58xxp1; +}; + +union cvmx_srxx_sw_tick_dat { + uint64_t u64; + struct cvmx_srxx_sw_tick_dat_s { + uint64_t dat:64; + } s; + struct cvmx_srxx_sw_tick_dat_s cn38xx; + struct cvmx_srxx_sw_tick_dat_s cn58xx; + struct cvmx_srxx_sw_tick_dat_s cn58xxp1; +}; + +#endif diff --git a/drivers/staging/octeon/cvmx-stxx-defs.h b/drivers/staging/octeon/cvmx-stxx-defs.h new file mode 100644 index 000000000000..4f209b62cae1 --- /dev/null +++ b/drivers/staging/octeon/cvmx-stxx-defs.h @@ -0,0 +1,292 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2008 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +#ifndef __CVMX_STXX_DEFS_H__ +#define __CVMX_STXX_DEFS_H__ + +#define CVMX_STXX_ARB_CTL(block_id) \ + CVMX_ADD_IO_SEG(0x0001180090000608ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_STXX_BCKPRS_CNT(block_id) \ + CVMX_ADD_IO_SEG(0x0001180090000688ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_STXX_COM_CTL(block_id) \ + CVMX_ADD_IO_SEG(0x0001180090000600ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_STXX_DIP_CNT(block_id) \ + CVMX_ADD_IO_SEG(0x0001180090000690ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_STXX_IGN_CAL(block_id) \ + CVMX_ADD_IO_SEG(0x0001180090000610ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_STXX_INT_MSK(block_id) \ + CVMX_ADD_IO_SEG(0x00011800900006A0ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_STXX_INT_REG(block_id) \ + CVMX_ADD_IO_SEG(0x0001180090000698ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_STXX_INT_SYNC(block_id) \ + CVMX_ADD_IO_SEG(0x00011800900006A8ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_STXX_MIN_BST(block_id) \ + CVMX_ADD_IO_SEG(0x0001180090000618ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_STXX_SPI4_CALX(offset, block_id) \ + CVMX_ADD_IO_SEG(0x0001180090000400ull + (((offset) & 31) * 8) + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_STXX_SPI4_DAT(block_id) \ + CVMX_ADD_IO_SEG(0x0001180090000628ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_STXX_SPI4_STAT(block_id) \ + CVMX_ADD_IO_SEG(0x0001180090000630ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_STXX_STAT_BYTES_HI(block_id) \ + CVMX_ADD_IO_SEG(0x0001180090000648ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_STXX_STAT_BYTES_LO(block_id) \ + CVMX_ADD_IO_SEG(0x0001180090000680ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_STXX_STAT_CTL(block_id) \ + CVMX_ADD_IO_SEG(0x0001180090000638ull + (((block_id) & 1) * 0x8000000ull)) +#define CVMX_STXX_STAT_PKT_XMT(block_id) \ + CVMX_ADD_IO_SEG(0x0001180090000640ull + (((block_id) & 1) * 0x8000000ull)) + +union cvmx_stxx_arb_ctl { + uint64_t u64; + struct cvmx_stxx_arb_ctl_s { + uint64_t reserved_6_63:58; + uint64_t mintrn:1; + uint64_t reserved_4_4:1; + uint64_t igntpa:1; + uint64_t reserved_0_2:3; + } s; + struct cvmx_stxx_arb_ctl_s cn38xx; + struct cvmx_stxx_arb_ctl_s cn38xxp2; + struct cvmx_stxx_arb_ctl_s cn58xx; + struct cvmx_stxx_arb_ctl_s cn58xxp1; +}; + +union cvmx_stxx_bckprs_cnt { + uint64_t u64; + struct cvmx_stxx_bckprs_cnt_s { + uint64_t reserved_32_63:32; + uint64_t cnt:32; + } s; + struct cvmx_stxx_bckprs_cnt_s cn38xx; + struct cvmx_stxx_bckprs_cnt_s cn38xxp2; + struct cvmx_stxx_bckprs_cnt_s cn58xx; + struct cvmx_stxx_bckprs_cnt_s cn58xxp1; +}; + +union cvmx_stxx_com_ctl { + uint64_t u64; + struct cvmx_stxx_com_ctl_s { + uint64_t reserved_4_63:60; + uint64_t st_en:1; + uint64_t reserved_1_2:2; + uint64_t inf_en:1; + } s; + struct cvmx_stxx_com_ctl_s cn38xx; + struct cvmx_stxx_com_ctl_s cn38xxp2; + struct cvmx_stxx_com_ctl_s cn58xx; + struct cvmx_stxx_com_ctl_s cn58xxp1; +}; + +union cvmx_stxx_dip_cnt { + uint64_t u64; + struct cvmx_stxx_dip_cnt_s { + uint64_t reserved_8_63:56; + uint64_t frmmax:4; + uint64_t dipmax:4; + } s; + struct cvmx_stxx_dip_cnt_s cn38xx; + struct cvmx_stxx_dip_cnt_s cn38xxp2; + struct cvmx_stxx_dip_cnt_s cn58xx; + struct cvmx_stxx_dip_cnt_s cn58xxp1; +}; + +union cvmx_stxx_ign_cal { + uint64_t u64; + struct cvmx_stxx_ign_cal_s { + uint64_t reserved_16_63:48; + uint64_t igntpa:16; + } s; + struct cvmx_stxx_ign_cal_s cn38xx; + struct cvmx_stxx_ign_cal_s cn38xxp2; + struct cvmx_stxx_ign_cal_s cn58xx; + struct cvmx_stxx_ign_cal_s cn58xxp1; +}; + +union cvmx_stxx_int_msk { + uint64_t u64; + struct cvmx_stxx_int_msk_s { + uint64_t reserved_8_63:56; + uint64_t frmerr:1; + uint64_t unxfrm:1; + uint64_t nosync:1; + uint64_t diperr:1; + uint64_t datovr:1; + uint64_t ovrbst:1; + uint64_t calpar1:1; + uint64_t calpar0:1; + } s; + struct cvmx_stxx_int_msk_s cn38xx; + struct cvmx_stxx_int_msk_s cn38xxp2; + struct cvmx_stxx_int_msk_s cn58xx; + struct cvmx_stxx_int_msk_s cn58xxp1; +}; + +union cvmx_stxx_int_reg { + uint64_t u64; + struct cvmx_stxx_int_reg_s { + uint64_t reserved_9_63:55; + uint64_t syncerr:1; + uint64_t frmerr:1; + uint64_t unxfrm:1; + uint64_t nosync:1; + uint64_t diperr:1; + uint64_t datovr:1; + uint64_t ovrbst:1; + uint64_t calpar1:1; + uint64_t calpar0:1; + } s; + struct cvmx_stxx_int_reg_s cn38xx; + struct cvmx_stxx_int_reg_s cn38xxp2; + struct cvmx_stxx_int_reg_s cn58xx; + struct cvmx_stxx_int_reg_s cn58xxp1; +}; + +union cvmx_stxx_int_sync { + uint64_t u64; + struct cvmx_stxx_int_sync_s { + uint64_t reserved_8_63:56; + uint64_t frmerr:1; + uint64_t unxfrm:1; + uint64_t nosync:1; + uint64_t diperr:1; + uint64_t datovr:1; + uint64_t ovrbst:1; + uint64_t calpar1:1; + uint64_t calpar0:1; + } s; + struct cvmx_stxx_int_sync_s cn38xx; + struct cvmx_stxx_int_sync_s cn38xxp2; + struct cvmx_stxx_int_sync_s cn58xx; + struct cvmx_stxx_int_sync_s cn58xxp1; +}; + +union cvmx_stxx_min_bst { + uint64_t u64; + struct cvmx_stxx_min_bst_s { + uint64_t reserved_9_63:55; + uint64_t minb:9; + } s; + struct cvmx_stxx_min_bst_s cn38xx; + struct cvmx_stxx_min_bst_s cn38xxp2; + struct cvmx_stxx_min_bst_s cn58xx; + struct cvmx_stxx_min_bst_s cn58xxp1; +}; + +union cvmx_stxx_spi4_calx { + uint64_t u64; + struct cvmx_stxx_spi4_calx_s { + uint64_t reserved_17_63:47; + uint64_t oddpar:1; + uint64_t prt3:4; + uint64_t prt2:4; + uint64_t prt1:4; + uint64_t prt0:4; + } s; + struct cvmx_stxx_spi4_calx_s cn38xx; + struct cvmx_stxx_spi4_calx_s cn38xxp2; + struct cvmx_stxx_spi4_calx_s cn58xx; + struct cvmx_stxx_spi4_calx_s cn58xxp1; +}; + +union cvmx_stxx_spi4_dat { + uint64_t u64; + struct cvmx_stxx_spi4_dat_s { + uint64_t reserved_32_63:32; + uint64_t alpha:16; + uint64_t max_t:16; + } s; + struct cvmx_stxx_spi4_dat_s cn38xx; + struct cvmx_stxx_spi4_dat_s cn38xxp2; + struct cvmx_stxx_spi4_dat_s cn58xx; + struct cvmx_stxx_spi4_dat_s cn58xxp1; +}; + +union cvmx_stxx_spi4_stat { + uint64_t u64; + struct cvmx_stxx_spi4_stat_s { + uint64_t reserved_16_63:48; + uint64_t m:8; + uint64_t reserved_7_7:1; + uint64_t len:7; + } s; + struct cvmx_stxx_spi4_stat_s cn38xx; + struct cvmx_stxx_spi4_stat_s cn38xxp2; + struct cvmx_stxx_spi4_stat_s cn58xx; + struct cvmx_stxx_spi4_stat_s cn58xxp1; +}; + +union cvmx_stxx_stat_bytes_hi { + uint64_t u64; + struct cvmx_stxx_stat_bytes_hi_s { + uint64_t reserved_32_63:32; + uint64_t cnt:32; + } s; + struct cvmx_stxx_stat_bytes_hi_s cn38xx; + struct cvmx_stxx_stat_bytes_hi_s cn38xxp2; + struct cvmx_stxx_stat_bytes_hi_s cn58xx; + struct cvmx_stxx_stat_bytes_hi_s cn58xxp1; +}; + +union cvmx_stxx_stat_bytes_lo { + uint64_t u64; + struct cvmx_stxx_stat_bytes_lo_s { + uint64_t reserved_32_63:32; + uint64_t cnt:32; + } s; + struct cvmx_stxx_stat_bytes_lo_s cn38xx; + struct cvmx_stxx_stat_bytes_lo_s cn38xxp2; + struct cvmx_stxx_stat_bytes_lo_s cn58xx; + struct cvmx_stxx_stat_bytes_lo_s cn58xxp1; +}; + +union cvmx_stxx_stat_ctl { + uint64_t u64; + struct cvmx_stxx_stat_ctl_s { + uint64_t reserved_5_63:59; + uint64_t clr:1; + uint64_t bckprs:4; + } s; + struct cvmx_stxx_stat_ctl_s cn38xx; + struct cvmx_stxx_stat_ctl_s cn38xxp2; + struct cvmx_stxx_stat_ctl_s cn58xx; + struct cvmx_stxx_stat_ctl_s cn58xxp1; +}; + +union cvmx_stxx_stat_pkt_xmt { + uint64_t u64; + struct cvmx_stxx_stat_pkt_xmt_s { + uint64_t reserved_32_63:32; + uint64_t cnt:32; + } s; + struct cvmx_stxx_stat_pkt_xmt_s cn38xx; + struct cvmx_stxx_stat_pkt_xmt_s cn38xxp2; + struct cvmx_stxx_stat_pkt_xmt_s cn58xx; + struct cvmx_stxx_stat_pkt_xmt_s cn58xxp1; +}; + +#endif diff --git a/drivers/staging/octeon/cvmx-wqe.h b/drivers/staging/octeon/cvmx-wqe.h new file mode 100644 index 000000000000..653610953d28 --- /dev/null +++ b/drivers/staging/octeon/cvmx-wqe.h @@ -0,0 +1,397 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2008 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +/** + * + * This header file defines the work queue entry (wqe) data structure. + * Since this is a commonly used structure that depends on structures + * from several hardware blocks, those definitions have been placed + * in this file to create a single point of definition of the wqe + * format. + * Data structures are still named according to the block that they + * relate to. + * + */ + +#ifndef __CVMX_WQE_H__ +#define __CVMX_WQE_H__ + +#include "cvmx-packet.h" + + +#define OCT_TAG_TYPE_STRING(x) \ + (((x) == CVMX_POW_TAG_TYPE_ORDERED) ? "ORDERED" : \ + (((x) == CVMX_POW_TAG_TYPE_ATOMIC) ? "ATOMIC" : \ + (((x) == CVMX_POW_TAG_TYPE_NULL) ? "NULL" : \ + "NULL_NULL"))) + +/** + * HW decode / err_code in work queue entry + */ +typedef union { + uint64_t u64; + + /* Use this struct if the hardware determines that the packet is IP */ + struct { + /* HW sets this to the number of buffers used by this packet */ + uint64_t bufs:8; + /* HW sets to the number of L2 bytes prior to the IP */ + uint64_t ip_offset:8; + /* set to 1 if we found DSA/VLAN in the L2 */ + uint64_t vlan_valid:1; + /* Set to 1 if the DSA/VLAN tag is stacked */ + uint64_t vlan_stacked:1; + uint64_t unassigned:1; + /* HW sets to the DSA/VLAN CFI flag (valid when vlan_valid) */ + uint64_t vlan_cfi:1; + /* HW sets to the DSA/VLAN_ID field (valid when vlan_valid) */ + uint64_t vlan_id:12; + /* Ring Identifier (if PCIe). Requires PIP_GBL_CTL[RING_EN]=1 */ + uint64_t pr:4; + uint64_t unassigned2:8; + /* the packet needs to be decompressed */ + uint64_t dec_ipcomp:1; + /* the packet is either TCP or UDP */ + uint64_t tcp_or_udp:1; + /* the packet needs to be decrypted (ESP or AH) */ + uint64_t dec_ipsec:1; + /* the packet is IPv6 */ + uint64_t is_v6:1; + + /* + * (rcv_error, not_IP, IP_exc, is_frag, L4_error, + * software, etc.). + */ + + /* + * reserved for software use, hardware will clear on + * packet creation. + */ + uint64_t software:1; + /* exceptional conditions below */ + /* the receive interface hardware detected an L4 error + * (only applies if !is_frag) (only applies if + * !rcv_error && !not_IP && !IP_exc && !is_frag) + * failure indicated in err_code below, decode: + * + * - 1 = Malformed L4 + * - 2 = L4 Checksum Error: the L4 checksum value is + * - 3 = UDP Length Error: The UDP length field would + * make the UDP data longer than what remains in + * the IP packet (as defined by the IP header + * length field). + * - 4 = Bad L4 Port: either the source or destination + * TCP/UDP port is 0. + * - 8 = TCP FIN Only: the packet is TCP and only the + * FIN flag set. + * - 9 = TCP No Flags: the packet is TCP and no flags + * are set. + * - 10 = TCP FIN RST: the packet is TCP and both FIN + * and RST are set. + * - 11 = TCP SYN URG: the packet is TCP and both SYN + * and URG are set. + * - 12 = TCP SYN RST: the packet is TCP and both SYN + * and RST are set. + * - 13 = TCP SYN FIN: the packet is TCP and both SYN + * and FIN are set. + */ + uint64_t L4_error:1; + /* set if the packet is a fragment */ + uint64_t is_frag:1; + /* the receive interface hardware detected an IP error + * / exception (only applies if !rcv_error && !not_IP) + * failure indicated in err_code below, decode: + * + * - 1 = Not IP: the IP version field is neither 4 nor + * 6. + * - 2 = IPv4 Header Checksum Error: the IPv4 header + * has a checksum violation. + * - 3 = IP Malformed Header: the packet is not long + * enough to contain the IP header. + * - 4 = IP Malformed: the packet is not long enough + * to contain the bytes indicated by the IP + * header. Pad is allowed. + * - 5 = IP TTL Hop: the IPv4 TTL field or the IPv6 + * Hop Count field are zero. + * - 6 = IP Options + */ + uint64_t IP_exc:1; + /* + * Set if the hardware determined that the packet is a + * broadcast. + */ + uint64_t is_bcast:1; + /* + * St if the hardware determined that the packet is a + * multi-cast. + */ + uint64_t is_mcast:1; + /* + * Set if the packet may not be IP (must be zero in + * this case). + */ + uint64_t not_IP:1; + /* + * The receive interface hardware detected a receive + * error (must be zero in this case). + */ + uint64_t rcv_error:1; + /* lower err_code = first-level descriptor of the + * work */ + /* zero for packet submitted by hardware that isn't on + * the slow path */ + /* type is cvmx_pip_err_t */ + uint64_t err_code:8; + } s; + + /* use this to get at the 16 vlan bits */ + struct { + uint64_t unused1:16; + uint64_t vlan:16; + uint64_t unused2:32; + } svlan; + + /* + * use this struct if the hardware could not determine that + * the packet is ip. + */ + struct { + /* + * HW sets this to the number of buffers used by this + * packet. + */ + uint64_t bufs:8; + uint64_t unused:8; + /* set to 1 if we found DSA/VLAN in the L2 */ + uint64_t vlan_valid:1; + /* Set to 1 if the DSA/VLAN tag is stacked */ + uint64_t vlan_stacked:1; + uint64_t unassigned:1; + /* + * HW sets to the DSA/VLAN CFI flag (valid when + * vlan_valid) + */ + uint64_t vlan_cfi:1; + /* + * HW sets to the DSA/VLAN_ID field (valid when + * vlan_valid). + */ + uint64_t vlan_id:12; + /* + * Ring Identifier (if PCIe). Requires + * PIP_GBL_CTL[RING_EN]=1 + */ + uint64_t pr:4; + uint64_t unassigned2:12; + /* + * reserved for software use, hardware will clear on + * packet creation. + */ + uint64_t software:1; + uint64_t unassigned3:1; + /* + * set if the hardware determined that the packet is + * rarp. + */ + uint64_t is_rarp:1; + /* + * set if the hardware determined that the packet is + * arp + */ + uint64_t is_arp:1; + /* + * set if the hardware determined that the packet is a + * broadcast. + */ + uint64_t is_bcast:1; + /* + * set if the hardware determined that the packet is a + * multi-cast + */ + uint64_t is_mcast:1; + /* + * set if the packet may not be IP (must be one in + * this case) + */ + uint64_t not_IP:1; + /* The receive interface hardware detected a receive + * error. Failure indicated in err_code below, + * decode: + * + * - 1 = partial error: a packet was partially + * received, but internal buffering / bandwidth + * was not adequate to receive the entire + * packet. + * - 2 = jabber error: the RGMII packet was too large + * and is truncated. + * - 3 = overrun error: the RGMII packet is longer + * than allowed and had an FCS error. + * - 4 = oversize error: the RGMII packet is longer + * than allowed. + * - 5 = alignment error: the RGMII packet is not an + * integer number of bytes + * and had an FCS error (100M and 10M only). + * - 6 = fragment error: the RGMII packet is shorter + * than allowed and had an FCS error. + * - 7 = GMX FCS error: the RGMII packet had an FCS + * error. + * - 8 = undersize error: the RGMII packet is shorter + * than allowed. + * - 9 = extend error: the RGMII packet had an extend + * error. + * - 10 = length mismatch error: the RGMII packet had + * a length that did not match the length field + * in the L2 HDR. + * - 11 = RGMII RX error/SPI4 DIP4 Error: the RGMII + * packet had one or more data reception errors + * (RXERR) or the SPI4 packet had one or more + * DIP4 errors. + * - 12 = RGMII skip error/SPI4 Abort Error: the RGMII + * packet was not large enough to cover the + * skipped bytes or the SPI4 packet was + * terminated with an About EOPS. + * - 13 = RGMII nibble error/SPI4 Port NXA Error: the + * RGMII packet had a studder error (data not + * repeated - 10/100M only) or the SPI4 packet + * was sent to an NXA. + * - 16 = FCS error: a SPI4.2 packet had an FCS error. + * - 17 = Skip error: a packet was not large enough to + * cover the skipped bytes. + * - 18 = L2 header malformed: the packet is not long + * enough to contain the L2. + */ + + uint64_t rcv_error:1; + /* + * lower err_code = first-level descriptor of the + * work + */ + /* + * zero for packet submitted by hardware that isn't on + * the slow path + */ + /* type is cvmx_pip_err_t (union, so can't use directly */ + uint64_t err_code:8; + } snoip; + +} cvmx_pip_wqe_word2; + +/** + * Work queue entry format + * + * must be 8-byte aligned + */ +typedef struct { + + /***************************************************************** + * WORD 0 + * HW WRITE: the following 64 bits are filled by HW when a packet arrives + */ + + /** + * raw chksum result generated by the HW + */ + uint16_t hw_chksum; + /** + * Field unused by hardware - available for software + */ + uint8_t unused; + /** + * Next pointer used by hardware for list maintenance. + * May be written/read by HW before the work queue + * entry is scheduled to a PP + * (Only 36 bits used in Octeon 1) + */ + uint64_t next_ptr:40; + + /***************************************************************** + * WORD 1 + * HW WRITE: the following 64 bits are filled by HW when a packet arrives + */ + + /** + * HW sets to the total number of bytes in the packet + */ + uint64_t len:16; + /** + * HW sets this to input physical port + */ + uint64_t ipprt:6; + + /** + * HW sets this to what it thought the priority of the input packet was + */ + uint64_t qos:3; + + /** + * the group that the work queue entry will be scheduled to + */ + uint64_t grp:4; + /** + * the type of the tag (ORDERED, ATOMIC, NULL) + */ + uint64_t tag_type:3; + /** + * the synchronization/ordering tag + */ + uint64_t tag:32; + + /** + * WORD 2 HW WRITE: the following 64-bits are filled in by + * hardware when a packet arrives This indicates a variety of + * status and error conditions. + */ + cvmx_pip_wqe_word2 word2; + + /** + * Pointer to the first segment of the packet. + */ + union cvmx_buf_ptr packet_ptr; + + /** + * HW WRITE: octeon will fill in a programmable amount from the + * packet, up to (at most, but perhaps less) the amount + * needed to fill the work queue entry to 128 bytes + * + * If the packet is recognized to be IP, the hardware starts + * (except that the IPv4 header is padded for appropriate + * alignment) writing here where the IP header starts. If the + * packet is not recognized to be IP, the hardware starts + * writing the beginning of the packet here. + */ + uint8_t packet_data[96]; + + /** + * If desired, SW can make the work Q entry any length. For the + * purposes of discussion here, Assume 128B always, as this is all that + * the hardware deals with. + * + */ + +} CVMX_CACHE_LINE_ALIGNED cvmx_wqe_t; + +#endif /* __CVMX_WQE_H__ */ diff --git a/drivers/staging/octeon/ethernet-defines.h b/drivers/staging/octeon/ethernet-defines.h new file mode 100644 index 000000000000..f13131b03c33 --- /dev/null +++ b/drivers/staging/octeon/ethernet-defines.h @@ -0,0 +1,136 @@ +/********************************************************************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2007 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information +**********************************************************************/ + +/* + * A few defines are used to control the operation of this driver: + * CONFIG_CAVIUM_RESERVE32 + * This kernel config options controls the amount of memory configured + * in a wired TLB entry for all processes to share. If this is set, the + * driver will use this memory instead of kernel memory for pools. This + * allows 32bit userspace application to access the buffers, but also + * requires all received packets to be copied. + * CONFIG_CAVIUM_OCTEON_NUM_PACKET_BUFFERS + * This kernel config option allows the user to control the number of + * packet and work queue buffers allocated by the driver. If this is zero, + * the driver uses the default from below. + * USE_SKBUFFS_IN_HW + * Tells the driver to populate the packet buffers with kernel skbuffs. + * This allows the driver to receive packets without copying them. It also + * means that 32bit userspace can't access the packet buffers. + * USE_32BIT_SHARED + * This define tells the driver to allocate memory for buffers from the + * 32bit sahred region instead of the kernel memory space. + * USE_HW_TCPUDP_CHECKSUM + * Controls if the Octeon TCP/UDP checksum engine is used for packet + * output. If this is zero, the kernel will perform the checksum in + * software. + * USE_MULTICORE_RECEIVE + * Process receive interrupts on multiple cores. This spreads the network + * load across the first 8 processors. If ths is zero, only one core + * processes incomming packets. + * USE_ASYNC_IOBDMA + * Use asynchronous IO access to hardware. This uses Octeon's asynchronous + * IOBDMAs to issue IO accesses without stalling. Set this to zero + * to disable this. Note that IOBDMAs require CVMSEG. + * REUSE_SKBUFFS_WITHOUT_FREE + * Allows the TX path to free an skbuff into the FPA hardware pool. This + * can significantly improve performance for forwarding and bridging, but + * may be somewhat dangerous. Checks are made, but if any buffer is reused + * without the proper Linux cleanup, the networking stack may have very + * bizarre bugs. + */ +#ifndef __ETHERNET_DEFINES_H__ +#define __ETHERNET_DEFINES_H__ + +#include "cvmx-config.h" + + +#define OCTEON_ETHERNET_VERSION "1.9" + +#ifndef CONFIG_CAVIUM_RESERVE32 +#define CONFIG_CAVIUM_RESERVE32 0 +#endif + +#if CONFIG_CAVIUM_RESERVE32 +#define USE_32BIT_SHARED 1 +#define USE_SKBUFFS_IN_HW 0 +#define REUSE_SKBUFFS_WITHOUT_FREE 0 +#else +#define USE_32BIT_SHARED 0 +#define USE_SKBUFFS_IN_HW 1 +#ifdef CONFIG_NETFILTER +#define REUSE_SKBUFFS_WITHOUT_FREE 0 +#else +#define REUSE_SKBUFFS_WITHOUT_FREE 1 +#endif +#endif + +/* Max interrupts per second per core */ +#define INTERRUPT_LIMIT 10000 + +/* Don't limit the number of interrupts */ +/*#define INTERRUPT_LIMIT 0 */ +#define USE_HW_TCPUDP_CHECKSUM 1 + +#define USE_MULTICORE_RECEIVE 1 + +/* Enable Random Early Dropping under load */ +#define USE_RED 1 +#define USE_ASYNC_IOBDMA (CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE > 0) + +/* + * Allow SW based preamble removal at 10Mbps to workaround PHYs giving + * us bad preambles. + */ +#define USE_10MBPS_PREAMBLE_WORKAROUND 1 +/* + * Use this to have all FPA frees also tell the L2 not to write data + * to memory. + */ +#define DONT_WRITEBACK(x) (x) +/* Use this to not have FPA frees control L2 */ +/*#define DONT_WRITEBACK(x) 0 */ + +/* Maximum number of packets to process per interrupt. */ +#define MAX_RX_PACKETS 120 +/* Maximum number of SKBs to try to free per xmit packet. */ +#define MAX_SKB_TO_FREE 10 +#define MAX_OUT_QUEUE_DEPTH 1000 + +#ifndef CONFIG_SMP +#undef USE_MULTICORE_RECEIVE +#define USE_MULTICORE_RECEIVE 0 +#endif + +#define IP_PROTOCOL_TCP 6 +#define IP_PROTOCOL_UDP 0x11 + +#define FAU_NUM_PACKET_BUFFERS_TO_FREE (CVMX_FAU_REG_END - sizeof(uint32_t)) +#define TOTAL_NUMBER_OF_PORTS (CVMX_PIP_NUM_INPUT_PORTS+1) + + +#endif /* __ETHERNET_DEFINES_H__ */ diff --git a/drivers/staging/octeon/ethernet-mdio.c b/drivers/staging/octeon/ethernet-mdio.c new file mode 100644 index 000000000000..93cab0a48925 --- /dev/null +++ b/drivers/staging/octeon/ethernet-mdio.c @@ -0,0 +1,231 @@ +/********************************************************************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2007 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information +**********************************************************************/ +#include +#include +#include +#include + +#include + +#include "ethernet-defines.h" +#include "octeon-ethernet.h" +#include "ethernet-mdio.h" + +#include "cvmx-helper-board.h" + +#include "cvmx-smix-defs.h" + +DECLARE_MUTEX(mdio_sem); + +/** + * Perform an MII read. Called by the generic MII routines + * + * @dev: Device to perform read for + * @phy_id: The MII phy id + * @location: Register location to read + * Returns Result from the read or zero on failure + */ +static int cvm_oct_mdio_read(struct net_device *dev, int phy_id, int location) +{ + union cvmx_smix_cmd smi_cmd; + union cvmx_smix_rd_dat smi_rd; + + smi_cmd.u64 = 0; + smi_cmd.s.phy_op = 1; + smi_cmd.s.phy_adr = phy_id; + smi_cmd.s.reg_adr = location; + cvmx_write_csr(CVMX_SMIX_CMD(0), smi_cmd.u64); + + do { + if (!in_interrupt()) + yield(); + smi_rd.u64 = cvmx_read_csr(CVMX_SMIX_RD_DAT(0)); + } while (smi_rd.s.pending); + + if (smi_rd.s.val) + return smi_rd.s.dat; + else + return 0; +} + +static int cvm_oct_mdio_dummy_read(struct net_device *dev, int phy_id, + int location) +{ + return 0xffff; +} + +/** + * Perform an MII write. Called by the generic MII routines + * + * @dev: Device to perform write for + * @phy_id: The MII phy id + * @location: Register location to write + * @val: Value to write + */ +static void cvm_oct_mdio_write(struct net_device *dev, int phy_id, int location, + int val) +{ + union cvmx_smix_cmd smi_cmd; + union cvmx_smix_wr_dat smi_wr; + + smi_wr.u64 = 0; + smi_wr.s.dat = val; + cvmx_write_csr(CVMX_SMIX_WR_DAT(0), smi_wr.u64); + + smi_cmd.u64 = 0; + smi_cmd.s.phy_op = 0; + smi_cmd.s.phy_adr = phy_id; + smi_cmd.s.reg_adr = location; + cvmx_write_csr(CVMX_SMIX_CMD(0), smi_cmd.u64); + + do { + if (!in_interrupt()) + yield(); + smi_wr.u64 = cvmx_read_csr(CVMX_SMIX_WR_DAT(0)); + } while (smi_wr.s.pending); +} + +static void cvm_oct_mdio_dummy_write(struct net_device *dev, int phy_id, + int location, int val) +{ +} + +static void cvm_oct_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) +{ + strcpy(info->driver, "cavium-ethernet"); + strcpy(info->version, OCTEON_ETHERNET_VERSION); + strcpy(info->bus_info, "Builtin"); +} + +static int cvm_oct_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct octeon_ethernet *priv = netdev_priv(dev); + int ret; + + down(&mdio_sem); + ret = mii_ethtool_gset(&priv->mii_info, cmd); + up(&mdio_sem); + + return ret; +} + +static int cvm_oct_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct octeon_ethernet *priv = netdev_priv(dev); + int ret; + + down(&mdio_sem); + ret = mii_ethtool_sset(&priv->mii_info, cmd); + up(&mdio_sem); + + return ret; +} + +static int cvm_oct_nway_reset(struct net_device *dev) +{ + struct octeon_ethernet *priv = netdev_priv(dev); + int ret; + + down(&mdio_sem); + ret = mii_nway_restart(&priv->mii_info); + up(&mdio_sem); + + return ret; +} + +static u32 cvm_oct_get_link(struct net_device *dev) +{ + struct octeon_ethernet *priv = netdev_priv(dev); + u32 ret; + + down(&mdio_sem); + ret = mii_link_ok(&priv->mii_info); + up(&mdio_sem); + + return ret; +} + +struct ethtool_ops cvm_oct_ethtool_ops = { + .get_drvinfo = cvm_oct_get_drvinfo, + .get_settings = cvm_oct_get_settings, + .set_settings = cvm_oct_set_settings, + .nway_reset = cvm_oct_nway_reset, + .get_link = cvm_oct_get_link, + .get_sg = ethtool_op_get_sg, + .get_tx_csum = ethtool_op_get_tx_csum, +}; + +/** + * IOCTL support for PHY control + * + * @dev: Device to change + * @rq: the request + * @cmd: the command + * Returns Zero on success + */ +int cvm_oct_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct octeon_ethernet *priv = netdev_priv(dev); + struct mii_ioctl_data *data = if_mii(rq); + unsigned int duplex_chg; + int ret; + + down(&mdio_sem); + ret = generic_mii_ioctl(&priv->mii_info, data, cmd, &duplex_chg); + up(&mdio_sem); + + return ret; +} + +/** + * Setup the MDIO device structures + * + * @dev: Device to setup + * + * Returns Zero on success, negative on failure + */ +int cvm_oct_mdio_setup_device(struct net_device *dev) +{ + struct octeon_ethernet *priv = netdev_priv(dev); + int phy_id = cvmx_helper_board_get_mii_address(priv->port); + if (phy_id != -1) { + priv->mii_info.dev = dev; + priv->mii_info.phy_id = phy_id; + priv->mii_info.phy_id_mask = 0xff; + priv->mii_info.supports_gmii = 1; + priv->mii_info.reg_num_mask = 0x1f; + priv->mii_info.mdio_read = cvm_oct_mdio_read; + priv->mii_info.mdio_write = cvm_oct_mdio_write; + } else { + /* Supply dummy MDIO routines so the kernel won't crash + if the user tries to read them */ + priv->mii_info.mdio_read = cvm_oct_mdio_dummy_read; + priv->mii_info.mdio_write = cvm_oct_mdio_dummy_write; + } + return 0; +} diff --git a/drivers/staging/octeon/ethernet-mdio.h b/drivers/staging/octeon/ethernet-mdio.h new file mode 100644 index 000000000000..6314141e5ef2 --- /dev/null +++ b/drivers/staging/octeon/ethernet-mdio.h @@ -0,0 +1,46 @@ +/********************************************************************* + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2007 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information +*********************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_XFRM +#include +#include +#endif /* CONFIG_XFRM */ + +extern struct ethtool_ops cvm_oct_ethtool_ops; +int cvm_oct_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +int cvm_oct_mdio_setup_device(struct net_device *dev); diff --git a/drivers/staging/octeon/ethernet-mem.c b/drivers/staging/octeon/ethernet-mem.c new file mode 100644 index 000000000000..b595903e2af1 --- /dev/null +++ b/drivers/staging/octeon/ethernet-mem.c @@ -0,0 +1,198 @@ +/********************************************************************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2007 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information +**********************************************************************/ +#include +#include +#include +#include + +#include + +#include "ethernet-defines.h" + +#include "cvmx-fpa.h" + +/** + * Fill the supplied hardware pool with skbuffs + * + * @pool: Pool to allocate an skbuff for + * @size: Size of the buffer needed for the pool + * @elements: Number of buffers to allocate + */ +static int cvm_oct_fill_hw_skbuff(int pool, int size, int elements) +{ + int freed = elements; + while (freed) { + + struct sk_buff *skb = dev_alloc_skb(size + 128); + if (unlikely(skb == NULL)) { + pr_warning + ("Failed to allocate skb for hardware pool %d\n", + pool); + break; + } + + skb_reserve(skb, 128 - (((unsigned long)skb->data) & 0x7f)); + *(struct sk_buff **)(skb->data - sizeof(void *)) = skb; + cvmx_fpa_free(skb->data, pool, DONT_WRITEBACK(size / 128)); + freed--; + } + return elements - freed; +} + +/** + * Free the supplied hardware pool of skbuffs + * + * @pool: Pool to allocate an skbuff for + * @size: Size of the buffer needed for the pool + * @elements: Number of buffers to allocate + */ +static void cvm_oct_free_hw_skbuff(int pool, int size, int elements) +{ + char *memory; + + do { + memory = cvmx_fpa_alloc(pool); + if (memory) { + struct sk_buff *skb = + *(struct sk_buff **)(memory - sizeof(void *)); + elements--; + dev_kfree_skb(skb); + } + } while (memory); + + if (elements < 0) + pr_warning("Freeing of pool %u had too many skbuffs (%d)\n", + pool, elements); + else if (elements > 0) + pr_warning("Freeing of pool %u is missing %d skbuffs\n", + pool, elements); +} + +/** + * This function fills a hardware pool with memory. Depending + * on the config defines, this memory might come from the + * kernel or global 32bit memory allocated with + * cvmx_bootmem_alloc. + * + * @pool: Pool to populate + * @size: Size of each buffer in the pool + * @elements: Number of buffers to allocate + */ +static int cvm_oct_fill_hw_memory(int pool, int size, int elements) +{ + char *memory; + int freed = elements; + + if (USE_32BIT_SHARED) { + extern uint64_t octeon_reserve32_memory; + + memory = + cvmx_bootmem_alloc_range(elements * size, 128, + octeon_reserve32_memory, + octeon_reserve32_memory + + (CONFIG_CAVIUM_RESERVE32 << 20) - + 1); + if (memory == NULL) + panic("Unable to allocate %u bytes for FPA pool %d\n", + elements * size, pool); + + pr_notice("Memory range %p - %p reserved for " + "hardware\n", memory, + memory + elements * size - 1); + + while (freed) { + cvmx_fpa_free(memory, pool, 0); + memory += size; + freed--; + } + } else { + while (freed) { + /* We need to force alignment to 128 bytes here */ + memory = kmalloc(size + 127, GFP_ATOMIC); + if (unlikely(memory == NULL)) { + pr_warning("Unable to allocate %u bytes for " + "FPA pool %d\n", + elements * size, pool); + break; + } + memory = (char *)(((unsigned long)memory + 127) & -128); + cvmx_fpa_free(memory, pool, 0); + freed--; + } + } + return elements - freed; +} + +/** + * Free memory previously allocated with cvm_oct_fill_hw_memory + * + * @pool: FPA pool to free + * @size: Size of each buffer in the pool + * @elements: Number of buffers that should be in the pool + */ +static void cvm_oct_free_hw_memory(int pool, int size, int elements) +{ + if (USE_32BIT_SHARED) { + pr_warning("Warning: 32 shared memory is not freeable\n"); + } else { + char *memory; + do { + memory = cvmx_fpa_alloc(pool); + if (memory) { + elements--; + kfree(phys_to_virt(cvmx_ptr_to_phys(memory))); + } + } while (memory); + + if (elements < 0) + pr_warning("Freeing of pool %u had too many " + "buffers (%d)\n", + pool, elements); + else if (elements > 0) + pr_warning("Warning: Freeing of pool %u is " + "missing %d buffers\n", + pool, elements); + } +} + +int cvm_oct_mem_fill_fpa(int pool, int size, int elements) +{ + int freed; + if (USE_SKBUFFS_IN_HW) + freed = cvm_oct_fill_hw_skbuff(pool, size, elements); + else + freed = cvm_oct_fill_hw_memory(pool, size, elements); + return freed; +} + +void cvm_oct_mem_empty_fpa(int pool, int size, int elements) +{ + if (USE_SKBUFFS_IN_HW) + cvm_oct_free_hw_skbuff(pool, size, elements); + else + cvm_oct_free_hw_memory(pool, size, elements); +} diff --git a/drivers/staging/octeon/ethernet-mem.h b/drivers/staging/octeon/ethernet-mem.h new file mode 100644 index 000000000000..713f2edc8b4f --- /dev/null +++ b/drivers/staging/octeon/ethernet-mem.h @@ -0,0 +1,29 @@ +/********************************************************************* + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2007 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information +********************************************************************/ + +int cvm_oct_mem_fill_fpa(int pool, int size, int elements); +void cvm_oct_mem_empty_fpa(int pool, int size, int elements); diff --git a/drivers/staging/octeon/ethernet-proc.c b/drivers/staging/octeon/ethernet-proc.c new file mode 100644 index 000000000000..8fa88fc419b7 --- /dev/null +++ b/drivers/staging/octeon/ethernet-proc.c @@ -0,0 +1,256 @@ +/********************************************************************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2007 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information +**********************************************************************/ +#include +#include +#include +#include +#include + +#include + +#include "octeon-ethernet.h" +#include "ethernet-defines.h" + +#include "cvmx-helper.h" +#include "cvmx-pip.h" + +static unsigned long long cvm_oct_stats_read_switch(struct net_device *dev, + int phy_id, int offset) +{ + struct octeon_ethernet *priv = netdev_priv(dev); + + priv->mii_info.mdio_write(dev, phy_id, 0x1d, 0xcc00 | offset); + return ((uint64_t) priv->mii_info. + mdio_read(dev, phy_id, + 0x1e) << 16) | (uint64_t) priv->mii_info. + mdio_read(dev, phy_id, 0x1f); +} + +static int cvm_oct_stats_switch_show(struct seq_file *m, void *v) +{ + static const int ports[] = { 0, 1, 2, 3, 9, -1 }; + struct net_device *dev = cvm_oct_device[0]; + int index = 0; + + while (ports[index] != -1) { + + /* Latch port */ + struct octeon_ethernet *priv = netdev_priv(dev); + + priv->mii_info.mdio_write(dev, 0x1b, 0x1d, + 0xdc00 | ports[index]); + seq_printf(m, "\nSwitch Port %d\n", ports[index]); + seq_printf(m, "InGoodOctets: %12llu\t" + "OutOctets: %12llu\t" + "64 Octets: %12llu\n", + cvm_oct_stats_read_switch(dev, 0x1b, + 0x00) | + (cvm_oct_stats_read_switch(dev, 0x1b, 0x01) << 32), + cvm_oct_stats_read_switch(dev, 0x1b, + 0x0E) | + (cvm_oct_stats_read_switch(dev, 0x1b, 0x0F) << 32), + cvm_oct_stats_read_switch(dev, 0x1b, 0x08)); + + seq_printf(m, "InBadOctets: %12llu\t" + "OutUnicast: %12llu\t" + "65-127 Octets: %12llu\n", + cvm_oct_stats_read_switch(dev, 0x1b, 0x02), + cvm_oct_stats_read_switch(dev, 0x1b, 0x10), + cvm_oct_stats_read_switch(dev, 0x1b, 0x09)); + + seq_printf(m, "InUnicast: %12llu\t" + "OutBroadcasts: %12llu\t" + "128-255 Octets: %12llu\n", + cvm_oct_stats_read_switch(dev, 0x1b, 0x04), + cvm_oct_stats_read_switch(dev, 0x1b, 0x13), + cvm_oct_stats_read_switch(dev, 0x1b, 0x0A)); + + seq_printf(m, "InBroadcasts: %12llu\t" + "OutMulticasts: %12llu\t" + "256-511 Octets: %12llu\n", + cvm_oct_stats_read_switch(dev, 0x1b, 0x06), + cvm_oct_stats_read_switch(dev, 0x1b, 0x12), + cvm_oct_stats_read_switch(dev, 0x1b, 0x0B)); + + seq_printf(m, "InMulticasts: %12llu\t" + "OutPause: %12llu\t" + "512-1023 Octets:%12llu\n", + cvm_oct_stats_read_switch(dev, 0x1b, 0x07), + cvm_oct_stats_read_switch(dev, 0x1b, 0x15), + cvm_oct_stats_read_switch(dev, 0x1b, 0x0C)); + + seq_printf(m, "InPause: %12llu\t" + "Excessive: %12llu\t" + "1024-Max Octets:%12llu\n", + cvm_oct_stats_read_switch(dev, 0x1b, 0x16), + cvm_oct_stats_read_switch(dev, 0x1b, 0x11), + cvm_oct_stats_read_switch(dev, 0x1b, 0x0D)); + + seq_printf(m, "InUndersize: %12llu\t" + "Collisions: %12llu\n", + cvm_oct_stats_read_switch(dev, 0x1b, 0x18), + cvm_oct_stats_read_switch(dev, 0x1b, 0x1E)); + + seq_printf(m, "InFragments: %12llu\t" + "Deferred: %12llu\n", + cvm_oct_stats_read_switch(dev, 0x1b, 0x19), + cvm_oct_stats_read_switch(dev, 0x1b, 0x05)); + + seq_printf(m, "InOversize: %12llu\t" + "Single: %12llu\n", + cvm_oct_stats_read_switch(dev, 0x1b, 0x1A), + cvm_oct_stats_read_switch(dev, 0x1b, 0x14)); + + seq_printf(m, "InJabber: %12llu\t" + "Multiple: %12llu\n", + cvm_oct_stats_read_switch(dev, 0x1b, 0x1B), + cvm_oct_stats_read_switch(dev, 0x1b, 0x17)); + + seq_printf(m, "In RxErr: %12llu\t" + "OutFCSErr: %12llu\n", + cvm_oct_stats_read_switch(dev, 0x1b, 0x1C), + cvm_oct_stats_read_switch(dev, 0x1b, 0x03)); + + seq_printf(m, "InFCSErr: %12llu\t" + "Late: %12llu\n", + cvm_oct_stats_read_switch(dev, 0x1b, 0x1D), + cvm_oct_stats_read_switch(dev, 0x1b, 0x1F)); + index++; + } + return 0; +} + +/** + * User is reading /proc/octeon_ethernet_stats + * + * @m: + * @v: + * Returns + */ +static int cvm_oct_stats_show(struct seq_file *m, void *v) +{ + struct octeon_ethernet *priv; + int port; + + for (port = 0; port < TOTAL_NUMBER_OF_PORTS; port++) { + + if (cvm_oct_device[port]) { + priv = netdev_priv(cvm_oct_device[port]); + + seq_printf(m, "\nOcteon Port %d (%s)\n", port, + cvm_oct_device[port]->name); + seq_printf(m, + "rx_packets: %12lu\t" + "tx_packets: %12lu\n", + priv->stats.rx_packets, + priv->stats.tx_packets); + seq_printf(m, + "rx_bytes: %12lu\t" + "tx_bytes: %12lu\n", + priv->stats.rx_bytes, priv->stats.tx_bytes); + seq_printf(m, + "rx_errors: %12lu\t" + "tx_errors: %12lu\n", + priv->stats.rx_errors, + priv->stats.tx_errors); + seq_printf(m, + "rx_dropped: %12lu\t" + "tx_dropped: %12lu\n", + priv->stats.rx_dropped, + priv->stats.tx_dropped); + seq_printf(m, + "rx_length_errors: %12lu\t" + "tx_aborted_errors: %12lu\n", + priv->stats.rx_length_errors, + priv->stats.tx_aborted_errors); + seq_printf(m, + "rx_over_errors: %12lu\t" + "tx_carrier_errors: %12lu\n", + priv->stats.rx_over_errors, + priv->stats.tx_carrier_errors); + seq_printf(m, + "rx_crc_errors: %12lu\t" + "tx_fifo_errors: %12lu\n", + priv->stats.rx_crc_errors, + priv->stats.tx_fifo_errors); + seq_printf(m, + "rx_frame_errors: %12lu\t" + "tx_heartbeat_errors: %12lu\n", + priv->stats.rx_frame_errors, + priv->stats.tx_heartbeat_errors); + seq_printf(m, + "rx_fifo_errors: %12lu\t" + "tx_window_errors: %12lu\n", + priv->stats.rx_fifo_errors, + priv->stats.tx_window_errors); + seq_printf(m, + "rx_missed_errors: %12lu\t" + "multicast: %12lu\n", + priv->stats.rx_missed_errors, + priv->stats.multicast); + } + } + + if (cvm_oct_device[0]) { + priv = netdev_priv(cvm_oct_device[0]); + if (priv->imode == CVMX_HELPER_INTERFACE_MODE_GMII) + cvm_oct_stats_switch_show(m, v); + } + return 0; +} + +/** + * /proc/octeon_ethernet_stats was openned. Use the single_open iterator + * + * @inode: + * @file: + * Returns + */ +static int cvm_oct_stats_open(struct inode *inode, struct file *file) +{ + return single_open(file, cvm_oct_stats_show, NULL); +} + +static const struct file_operations cvm_oct_stats_operations = { + .open = cvm_oct_stats_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +void cvm_oct_proc_initialize(void) +{ + struct proc_dir_entry *entry = + create_proc_entry("octeon_ethernet_stats", 0, NULL); + if (entry) + entry->proc_fops = &cvm_oct_stats_operations; +} + +void cvm_oct_proc_shutdown(void) +{ + remove_proc_entry("octeon_ethernet_stats", NULL); +} diff --git a/drivers/staging/octeon/ethernet-proc.h b/drivers/staging/octeon/ethernet-proc.h new file mode 100644 index 000000000000..82c7d9f78bc4 --- /dev/null +++ b/drivers/staging/octeon/ethernet-proc.h @@ -0,0 +1,29 @@ +/********************************************************************* + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2007 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information +*********************************************************************/ + +void cvm_oct_proc_initialize(void); +void cvm_oct_proc_shutdown(void); diff --git a/drivers/staging/octeon/ethernet-rgmii.c b/drivers/staging/octeon/ethernet-rgmii.c new file mode 100644 index 000000000000..8704133fe127 --- /dev/null +++ b/drivers/staging/octeon/ethernet-rgmii.c @@ -0,0 +1,394 @@ +/********************************************************************* + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2007 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information +**********************************************************************/ +#include +#include +#include +#include + +#include + +#include "ethernet-defines.h" +#include "octeon-ethernet.h" +#include "ethernet-util.h" + +#include "cvmx-helper.h" + +#include +#include +#include "cvmx-gmxx-defs.h" + +DEFINE_SPINLOCK(global_register_lock); + +static int number_rgmii_ports; + +static void cvm_oct_rgmii_poll(struct net_device *dev) +{ + struct octeon_ethernet *priv = netdev_priv(dev); + unsigned long flags; + cvmx_helper_link_info_t link_info; + + /* + * Take the global register lock since we are going to touch + * registers that affect more than one port. + */ + spin_lock_irqsave(&global_register_lock, flags); + + link_info = cvmx_helper_link_get(priv->port); + if (link_info.u64 == priv->link_info) { + + /* + * If the 10Mbps preamble workaround is supported and we're + * at 10Mbps we may need to do some special checking. + */ + if (USE_10MBPS_PREAMBLE_WORKAROUND && (link_info.s.speed == 10)) { + + /* + * Read the GMXX_RXX_INT_REG[PCTERR] bit and + * see if we are getting preamble errors. + */ + int interface = INTERFACE(priv->port); + int index = INDEX(priv->port); + union cvmx_gmxx_rxx_int_reg gmxx_rxx_int_reg; + gmxx_rxx_int_reg.u64 = + cvmx_read_csr(CVMX_GMXX_RXX_INT_REG + (index, interface)); + if (gmxx_rxx_int_reg.s.pcterr) { + + /* + * We are getting preamble errors at + * 10Mbps. Most likely the PHY is + * giving us packets with mis aligned + * preambles. In order to get these + * packets we need to disable preamble + * checking and do it in software. + */ + union cvmx_gmxx_rxx_frm_ctl gmxx_rxx_frm_ctl; + union cvmx_ipd_sub_port_fcs ipd_sub_port_fcs; + + /* Disable preamble checking */ + gmxx_rxx_frm_ctl.u64 = + cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL + (index, interface)); + gmxx_rxx_frm_ctl.s.pre_chk = 0; + cvmx_write_csr(CVMX_GMXX_RXX_FRM_CTL + (index, interface), + gmxx_rxx_frm_ctl.u64); + + /* Disable FCS stripping */ + ipd_sub_port_fcs.u64 = + cvmx_read_csr(CVMX_IPD_SUB_PORT_FCS); + ipd_sub_port_fcs.s.port_bit &= + 0xffffffffull ^ (1ull << priv->port); + cvmx_write_csr(CVMX_IPD_SUB_PORT_FCS, + ipd_sub_port_fcs.u64); + + /* Clear any error bits */ + cvmx_write_csr(CVMX_GMXX_RXX_INT_REG + (index, interface), + gmxx_rxx_int_reg.u64); + DEBUGPRINT("%s: Using 10Mbps with software " + "preamble removal\n", + dev->name); + } + } + spin_unlock_irqrestore(&global_register_lock, flags); + return; + } + + /* If the 10Mbps preamble workaround is allowed we need to on + preamble checking, FCS stripping, and clear error bits on + every speed change. If errors occur during 10Mbps operation + the above code will change this stuff */ + if (USE_10MBPS_PREAMBLE_WORKAROUND) { + + union cvmx_gmxx_rxx_frm_ctl gmxx_rxx_frm_ctl; + union cvmx_ipd_sub_port_fcs ipd_sub_port_fcs; + union cvmx_gmxx_rxx_int_reg gmxx_rxx_int_reg; + int interface = INTERFACE(priv->port); + int index = INDEX(priv->port); + + /* Enable preamble checking */ + gmxx_rxx_frm_ctl.u64 = + cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL(index, interface)); + gmxx_rxx_frm_ctl.s.pre_chk = 1; + cvmx_write_csr(CVMX_GMXX_RXX_FRM_CTL(index, interface), + gmxx_rxx_frm_ctl.u64); + /* Enable FCS stripping */ + ipd_sub_port_fcs.u64 = cvmx_read_csr(CVMX_IPD_SUB_PORT_FCS); + ipd_sub_port_fcs.s.port_bit |= 1ull << priv->port; + cvmx_write_csr(CVMX_IPD_SUB_PORT_FCS, ipd_sub_port_fcs.u64); + /* Clear any error bits */ + gmxx_rxx_int_reg.u64 = + cvmx_read_csr(CVMX_GMXX_RXX_INT_REG(index, interface)); + cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(index, interface), + gmxx_rxx_int_reg.u64); + } + + link_info = cvmx_helper_link_autoconf(priv->port); + priv->link_info = link_info.u64; + spin_unlock_irqrestore(&global_register_lock, flags); + + /* Tell Linux */ + if (link_info.s.link_up) { + + if (!netif_carrier_ok(dev)) + netif_carrier_on(dev); + if (priv->queue != -1) + DEBUGPRINT + ("%s: %u Mbps %s duplex, port %2d, queue %2d\n", + dev->name, link_info.s.speed, + (link_info.s.full_duplex) ? "Full" : "Half", + priv->port, priv->queue); + else + DEBUGPRINT("%s: %u Mbps %s duplex, port %2d, POW\n", + dev->name, link_info.s.speed, + (link_info.s.full_duplex) ? "Full" : "Half", + priv->port); + } else { + + if (netif_carrier_ok(dev)) + netif_carrier_off(dev); + DEBUGPRINT("%s: Link down\n", dev->name); + } +} + +static irqreturn_t cvm_oct_rgmii_rml_interrupt(int cpl, void *dev_id) +{ + union cvmx_npi_rsl_int_blocks rsl_int_blocks; + int index; + irqreturn_t return_status = IRQ_NONE; + + rsl_int_blocks.u64 = cvmx_read_csr(CVMX_NPI_RSL_INT_BLOCKS); + + /* Check and see if this interrupt was caused by the GMX0 block */ + if (rsl_int_blocks.s.gmx0) { + + int interface = 0; + /* Loop through every port of this interface */ + for (index = 0; + index < cvmx_helper_ports_on_interface(interface); + index++) { + + /* Read the GMX interrupt status bits */ + union cvmx_gmxx_rxx_int_reg gmx_rx_int_reg; + gmx_rx_int_reg.u64 = + cvmx_read_csr(CVMX_GMXX_RXX_INT_REG + (index, interface)); + gmx_rx_int_reg.u64 &= + cvmx_read_csr(CVMX_GMXX_RXX_INT_EN + (index, interface)); + /* Poll the port if inband status changed */ + if (gmx_rx_int_reg.s.phy_dupx + || gmx_rx_int_reg.s.phy_link + || gmx_rx_int_reg.s.phy_spd) { + + struct net_device *dev = + cvm_oct_device[cvmx_helper_get_ipd_port + (interface, index)]; + if (dev) + cvm_oct_rgmii_poll(dev); + gmx_rx_int_reg.u64 = 0; + gmx_rx_int_reg.s.phy_dupx = 1; + gmx_rx_int_reg.s.phy_link = 1; + gmx_rx_int_reg.s.phy_spd = 1; + cvmx_write_csr(CVMX_GMXX_RXX_INT_REG + (index, interface), + gmx_rx_int_reg.u64); + return_status = IRQ_HANDLED; + } + } + } + + /* Check and see if this interrupt was caused by the GMX1 block */ + if (rsl_int_blocks.s.gmx1) { + + int interface = 1; + /* Loop through every port of this interface */ + for (index = 0; + index < cvmx_helper_ports_on_interface(interface); + index++) { + + /* Read the GMX interrupt status bits */ + union cvmx_gmxx_rxx_int_reg gmx_rx_int_reg; + gmx_rx_int_reg.u64 = + cvmx_read_csr(CVMX_GMXX_RXX_INT_REG + (index, interface)); + gmx_rx_int_reg.u64 &= + cvmx_read_csr(CVMX_GMXX_RXX_INT_EN + (index, interface)); + /* Poll the port if inband status changed */ + if (gmx_rx_int_reg.s.phy_dupx + || gmx_rx_int_reg.s.phy_link + || gmx_rx_int_reg.s.phy_spd) { + + struct net_device *dev = + cvm_oct_device[cvmx_helper_get_ipd_port + (interface, index)]; + if (dev) + cvm_oct_rgmii_poll(dev); + gmx_rx_int_reg.u64 = 0; + gmx_rx_int_reg.s.phy_dupx = 1; + gmx_rx_int_reg.s.phy_link = 1; + gmx_rx_int_reg.s.phy_spd = 1; + cvmx_write_csr(CVMX_GMXX_RXX_INT_REG + (index, interface), + gmx_rx_int_reg.u64); + return_status = IRQ_HANDLED; + } + } + } + return return_status; +} + +int cvm_oct_rgmii_open(struct net_device *dev) +{ + union cvmx_gmxx_prtx_cfg gmx_cfg; + struct octeon_ethernet *priv = netdev_priv(dev); + int interface = INTERFACE(priv->port); + int index = INDEX(priv->port); + cvmx_helper_link_info_t link_info; + + gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); + gmx_cfg.s.en = 1; + cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64); + + if (!octeon_is_simulation()) { + link_info = cvmx_helper_link_get(priv->port); + if (!link_info.s.link_up) + netif_carrier_off(dev); + } + + return 0; +} + +int cvm_oct_rgmii_stop(struct net_device *dev) +{ + union cvmx_gmxx_prtx_cfg gmx_cfg; + struct octeon_ethernet *priv = netdev_priv(dev); + int interface = INTERFACE(priv->port); + int index = INDEX(priv->port); + + gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); + gmx_cfg.s.en = 0; + cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64); + return 0; +} + +int cvm_oct_rgmii_init(struct net_device *dev) +{ + struct octeon_ethernet *priv = netdev_priv(dev); + int r; + + cvm_oct_common_init(dev); + dev->netdev_ops->ndo_stop(dev); + + /* + * Due to GMX errata in CN3XXX series chips, it is necessary + * to take the link down immediately whne the PHY changes + * state. In order to do this we call the poll function every + * time the RGMII inband status changes. This may cause + * problems if the PHY doesn't implement inband status + * properly. + */ + if (number_rgmii_ports == 0) { + r = request_irq(OCTEON_IRQ_RML, cvm_oct_rgmii_rml_interrupt, + IRQF_SHARED, "RGMII", &number_rgmii_ports); + } + number_rgmii_ports++; + + /* + * Only true RGMII ports need to be polled. In GMII mode, port + * 0 is really a RGMII port. + */ + if (((priv->imode == CVMX_HELPER_INTERFACE_MODE_GMII) + && (priv->port == 0)) + || (priv->imode == CVMX_HELPER_INTERFACE_MODE_RGMII)) { + + if (!octeon_is_simulation()) { + + union cvmx_gmxx_rxx_int_en gmx_rx_int_en; + int interface = INTERFACE(priv->port); + int index = INDEX(priv->port); + + /* + * Enable interrupts on inband status changes + * for this port. + */ + gmx_rx_int_en.u64 = + cvmx_read_csr(CVMX_GMXX_RXX_INT_EN + (index, interface)); + gmx_rx_int_en.s.phy_dupx = 1; + gmx_rx_int_en.s.phy_link = 1; + gmx_rx_int_en.s.phy_spd = 1; + cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(index, interface), + gmx_rx_int_en.u64); + priv->poll = cvm_oct_rgmii_poll; + } + } + + return 0; +} + +void cvm_oct_rgmii_uninit(struct net_device *dev) +{ + struct octeon_ethernet *priv = netdev_priv(dev); + cvm_oct_common_uninit(dev); + + /* + * Only true RGMII ports need to be polled. In GMII mode, port + * 0 is really a RGMII port. + */ + if (((priv->imode == CVMX_HELPER_INTERFACE_MODE_GMII) + && (priv->port == 0)) + || (priv->imode == CVMX_HELPER_INTERFACE_MODE_RGMII)) { + + if (!octeon_is_simulation()) { + + union cvmx_gmxx_rxx_int_en gmx_rx_int_en; + int interface = INTERFACE(priv->port); + int index = INDEX(priv->port); + + /* + * Disable interrupts on inband status changes + * for this port. + */ + gmx_rx_int_en.u64 = + cvmx_read_csr(CVMX_GMXX_RXX_INT_EN + (index, interface)); + gmx_rx_int_en.s.phy_dupx = 0; + gmx_rx_int_en.s.phy_link = 0; + gmx_rx_int_en.s.phy_spd = 0; + cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(index, interface), + gmx_rx_int_en.u64); + } + } + + /* Remove the interrupt handler when the last port is removed. */ + number_rgmii_ports--; + if (number_rgmii_ports == 0) + free_irq(OCTEON_IRQ_RML, &number_rgmii_ports); +} diff --git a/drivers/staging/octeon/ethernet-rx.c b/drivers/staging/octeon/ethernet-rx.c new file mode 100644 index 000000000000..1b237b7e689d --- /dev/null +++ b/drivers/staging/octeon/ethernet-rx.c @@ -0,0 +1,505 @@ +/********************************************************************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2007 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information +**********************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_XFRM +#include +#include +#endif /* CONFIG_XFRM */ + +#include + +#include + +#include "ethernet-defines.h" +#include "octeon-ethernet.h" +#include "ethernet-mem.h" +#include "ethernet-util.h" + +#include "cvmx-helper.h" +#include "cvmx-wqe.h" +#include "cvmx-fau.h" +#include "cvmx-pow.h" +#include "cvmx-pip.h" +#include "cvmx-scratch.h" + +#include "cvmx-gmxx-defs.h" + +struct cvm_tasklet_wrapper { + struct tasklet_struct t; +}; + +/* + * Aligning the tasklet_struct on cachline boundries seems to decrease + * throughput even though in theory it would reduce contantion on the + * cache lines containing the locks. + */ + +static struct cvm_tasklet_wrapper cvm_oct_tasklet[NR_CPUS]; + +/** + * Interrupt handler. The interrupt occurs whenever the POW + * transitions from 0->1 packets in our group. + * + * @cpl: + * @dev_id: + * @regs: + * Returns + */ +irqreturn_t cvm_oct_do_interrupt(int cpl, void *dev_id) +{ + /* Acknowledge the interrupt */ + if (INTERRUPT_LIMIT) + cvmx_write_csr(CVMX_POW_WQ_INT, 1 << pow_receive_group); + else + cvmx_write_csr(CVMX_POW_WQ_INT, 0x10001 << pow_receive_group); + preempt_disable(); + tasklet_schedule(&cvm_oct_tasklet[smp_processor_id()].t); + preempt_enable(); + return IRQ_HANDLED; +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +/** + * This is called when the kernel needs to manually poll the + * device. For Octeon, this is simply calling the interrupt + * handler. We actually poll all the devices, not just the + * one supplied. + * + * @dev: Device to poll. Unused + */ +void cvm_oct_poll_controller(struct net_device *dev) +{ + preempt_disable(); + tasklet_schedule(&cvm_oct_tasklet[smp_processor_id()].t); + preempt_enable(); +} +#endif + +/** + * This is called on receive errors, and determines if the packet + * can be dropped early-on in cvm_oct_tasklet_rx(). + * + * @work: Work queue entry pointing to the packet. + * Returns Non-zero if the packet can be dropped, zero otherwise. + */ +static inline int cvm_oct_check_rcv_error(cvmx_wqe_t *work) +{ + if ((work->word2.snoip.err_code == 10) && (work->len <= 64)) { + /* + * Ignore length errors on min size packets. Some + * equipment incorrectly pads packets to 64+4FCS + * instead of 60+4FCS. Note these packets still get + * counted as frame errors. + */ + } else + if (USE_10MBPS_PREAMBLE_WORKAROUND + && ((work->word2.snoip.err_code == 5) + || (work->word2.snoip.err_code == 7))) { + + /* + * We received a packet with either an alignment error + * or a FCS error. This may be signalling that we are + * running 10Mbps with GMXX_RXX_FRM_CTL[PRE_CHK} + * off. If this is the case we need to parse the + * packet to determine if we can remove a non spec + * preamble and generate a correct packet. + */ + int interface = cvmx_helper_get_interface_num(work->ipprt); + int index = cvmx_helper_get_interface_index_num(work->ipprt); + union cvmx_gmxx_rxx_frm_ctl gmxx_rxx_frm_ctl; + gmxx_rxx_frm_ctl.u64 = + cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL(index, interface)); + if (gmxx_rxx_frm_ctl.s.pre_chk == 0) { + + uint8_t *ptr = + cvmx_phys_to_ptr(work->packet_ptr.s.addr); + int i = 0; + + while (i < work->len - 1) { + if (*ptr != 0x55) + break; + ptr++; + i++; + } + + if (*ptr == 0xd5) { + /* + DEBUGPRINT("Port %d received 0xd5 preamble\n", work->ipprt); + */ + work->packet_ptr.s.addr += i + 1; + work->len -= i + 5; + } else if ((*ptr & 0xf) == 0xd) { + /* + DEBUGPRINT("Port %d received 0x?d preamble\n", work->ipprt); + */ + work->packet_ptr.s.addr += i; + work->len -= i + 4; + for (i = 0; i < work->len; i++) { + *ptr = + ((*ptr & 0xf0) >> 4) | + ((*(ptr + 1) & 0xf) << 4); + ptr++; + } + } else { + DEBUGPRINT("Port %d unknown preamble, packet " + "dropped\n", + work->ipprt); + /* + cvmx_helper_dump_packet(work); + */ + cvm_oct_free_work(work); + return 1; + } + } + } else { + DEBUGPRINT("Port %d receive error code %d, packet dropped\n", + work->ipprt, work->word2.snoip.err_code); + cvm_oct_free_work(work); + return 1; + } + + return 0; +} + +/** + * Tasklet function that is scheduled on a core when an interrupt occurs. + * + * @unused: + */ +void cvm_oct_tasklet_rx(unsigned long unused) +{ + const int coreid = cvmx_get_core_num(); + uint64_t old_group_mask; + uint64_t old_scratch; + int rx_count = 0; + int number_to_free; + int num_freed; + int packet_not_copied; + + /* Prefetch cvm_oct_device since we know we need it soon */ + prefetch(cvm_oct_device); + + if (USE_ASYNC_IOBDMA) { + /* Save scratch in case userspace is using it */ + CVMX_SYNCIOBDMA; + old_scratch = cvmx_scratch_read64(CVMX_SCR_SCRATCH); + } + + /* Only allow work for our group (and preserve priorities) */ + old_group_mask = cvmx_read_csr(CVMX_POW_PP_GRP_MSKX(coreid)); + cvmx_write_csr(CVMX_POW_PP_GRP_MSKX(coreid), + (old_group_mask & ~0xFFFFull) | 1 << pow_receive_group); + + if (USE_ASYNC_IOBDMA) + cvmx_pow_work_request_async(CVMX_SCR_SCRATCH, CVMX_POW_NO_WAIT); + + while (1) { + struct sk_buff *skb = NULL; + int skb_in_hw; + cvmx_wqe_t *work; + + if (USE_ASYNC_IOBDMA) { + work = cvmx_pow_work_response_async(CVMX_SCR_SCRATCH); + } else { + if ((INTERRUPT_LIMIT == 0) + || likely(rx_count < MAX_RX_PACKETS)) + work = + cvmx_pow_work_request_sync + (CVMX_POW_NO_WAIT); + else + work = NULL; + } + prefetch(work); + if (work == NULL) + break; + + /* + * Limit each core to processing MAX_RX_PACKETS + * packets without a break. This way the RX can't + * starve the TX task. + */ + if (USE_ASYNC_IOBDMA) { + + if ((INTERRUPT_LIMIT == 0) + || likely(rx_count < MAX_RX_PACKETS)) + cvmx_pow_work_request_async_nocheck + (CVMX_SCR_SCRATCH, CVMX_POW_NO_WAIT); + else { + cvmx_scratch_write64(CVMX_SCR_SCRATCH, + 0x8000000000000000ull); + cvmx_pow_tag_sw_null_nocheck(); + } + } + + skb_in_hw = USE_SKBUFFS_IN_HW && work->word2.s.bufs == 1; + if (likely(skb_in_hw)) { + skb = + *(struct sk_buff + **)(cvm_oct_get_buffer_ptr(work->packet_ptr) - + sizeof(void *)); + prefetch(&skb->head); + prefetch(&skb->len); + } + prefetch(cvm_oct_device[work->ipprt]); + + rx_count++; + /* Immediately throw away all packets with receive errors */ + if (unlikely(work->word2.snoip.rcv_error)) { + if (cvm_oct_check_rcv_error(work)) + continue; + } + + /* + * We can only use the zero copy path if skbuffs are + * in the FPA pool and the packet fits in a single + * buffer. + */ + if (likely(skb_in_hw)) { + /* + * This calculation was changed in case the + * skb header is using a different address + * aliasing type than the buffer. It doesn't + * make any differnece now, but the new one is + * more correct. + */ + skb->data = + skb->head + work->packet_ptr.s.addr - + cvmx_ptr_to_phys(skb->head); + prefetch(skb->data); + skb->len = work->len; + skb_set_tail_pointer(skb, skb->len); + packet_not_copied = 1; + } else { + + /* + * We have to copy the packet. First allocate + * an skbuff for it. + */ + skb = dev_alloc_skb(work->len); + if (!skb) { + DEBUGPRINT("Port %d failed to allocate " + "skbuff, packet dropped\n", + work->ipprt); + cvm_oct_free_work(work); + continue; + } + + /* + * Check if we've received a packet that was + * entirely stored in the work entry. This is + * untested. + */ + if (unlikely(work->word2.s.bufs == 0)) { + uint8_t *ptr = work->packet_data; + + if (likely(!work->word2.s.not_IP)) { + /* + * The beginning of the packet + * moves for IP packets. + */ + if (work->word2.s.is_v6) + ptr += 2; + else + ptr += 6; + } + memcpy(skb_put(skb, work->len), ptr, work->len); + /* No packet buffers to free */ + } else { + int segments = work->word2.s.bufs; + union cvmx_buf_ptr segment_ptr = + work->packet_ptr; + int len = work->len; + + while (segments--) { + union cvmx_buf_ptr next_ptr = + *(union cvmx_buf_ptr *) + cvmx_phys_to_ptr(segment_ptr.s. + addr - 8); + /* + * Octeon Errata PKI-100: The segment size is + * wrong. Until it is fixed, calculate the + * segment size based on the packet pool + * buffer size. When it is fixed, the + * following line should be replaced with this + * one: int segment_size = + * segment_ptr.s.size; + */ + int segment_size = + CVMX_FPA_PACKET_POOL_SIZE - + (segment_ptr.s.addr - + (((segment_ptr.s.addr >> 7) - + segment_ptr.s.back) << 7)); + /* Don't copy more than what is left + in the packet */ + if (segment_size > len) + segment_size = len; + /* Copy the data into the packet */ + memcpy(skb_put(skb, segment_size), + cvmx_phys_to_ptr(segment_ptr.s. + addr), + segment_size); + /* Reduce the amount of bytes left + to copy */ + len -= segment_size; + segment_ptr = next_ptr; + } + } + packet_not_copied = 0; + } + + if (likely((work->ipprt < TOTAL_NUMBER_OF_PORTS) && + cvm_oct_device[work->ipprt])) { + struct net_device *dev = cvm_oct_device[work->ipprt]; + struct octeon_ethernet *priv = netdev_priv(dev); + + /* Only accept packets for devices + that are currently up */ + if (likely(dev->flags & IFF_UP)) { + skb->protocol = eth_type_trans(skb, dev); + skb->dev = dev; + + if (unlikely + (work->word2.s.not_IP + || work->word2.s.IP_exc + || work->word2.s.L4_error)) + skb->ip_summed = CHECKSUM_NONE; + else + skb->ip_summed = CHECKSUM_UNNECESSARY; + + /* Increment RX stats for virtual ports */ + if (work->ipprt >= CVMX_PIP_NUM_INPUT_PORTS) { +#ifdef CONFIG_64BIT + atomic64_add(1, (atomic64_t *)&priv->stats.rx_packets); + atomic64_add(skb->len, (atomic64_t *)&priv->stats.rx_bytes); +#else + atomic_add(1, (atomic_t *)&priv->stats.rx_packets); + atomic_add(skb->len, (atomic_t *)&priv->stats.rx_bytes); +#endif + } + netif_receive_skb(skb); + } else { + /* + * Drop any packet received for a + * device that isn't up. + */ + /* + DEBUGPRINT("%s: Device not up, packet dropped\n", + dev->name); + */ +#ifdef CONFIG_64BIT + atomic64_add(1, (atomic64_t *)&priv->stats.rx_dropped); +#else + atomic_add(1, (atomic_t *)&priv->stats.rx_dropped); +#endif + dev_kfree_skb_irq(skb); + } + } else { + /* + * Drop any packet received for a device that + * doesn't exist. + */ + DEBUGPRINT("Port %d not controlled by Linux, packet " + "dropped\n", + work->ipprt); + dev_kfree_skb_irq(skb); + } + /* + * Check to see if the skbuff and work share the same + * packet buffer. + */ + if (USE_SKBUFFS_IN_HW && likely(packet_not_copied)) { + /* + * This buffer needs to be replaced, increment + * the number of buffers we need to free by + * one. + */ + cvmx_fau_atomic_add32(FAU_NUM_PACKET_BUFFERS_TO_FREE, + 1); + + cvmx_fpa_free(work, CVMX_FPA_WQE_POOL, + DONT_WRITEBACK(1)); + } else { + cvm_oct_free_work(work); + } + } + + /* Restore the original POW group mask */ + cvmx_write_csr(CVMX_POW_PP_GRP_MSKX(coreid), old_group_mask); + if (USE_ASYNC_IOBDMA) { + /* Restore the scratch area */ + cvmx_scratch_write64(CVMX_SCR_SCRATCH, old_scratch); + } + + if (USE_SKBUFFS_IN_HW) { + /* Refill the packet buffer pool */ + number_to_free = + cvmx_fau_fetch_and_add32(FAU_NUM_PACKET_BUFFERS_TO_FREE, 0); + + if (number_to_free > 0) { + cvmx_fau_atomic_add32(FAU_NUM_PACKET_BUFFERS_TO_FREE, + -number_to_free); + num_freed = + cvm_oct_mem_fill_fpa(CVMX_FPA_PACKET_POOL, + CVMX_FPA_PACKET_POOL_SIZE, + number_to_free); + if (num_freed != number_to_free) { + cvmx_fau_atomic_add32 + (FAU_NUM_PACKET_BUFFERS_TO_FREE, + number_to_free - num_freed); + } + } + } +} + +void cvm_oct_rx_initialize(void) +{ + int i; + /* Initialize all of the tasklets */ + for (i = 0; i < NR_CPUS; i++) + tasklet_init(&cvm_oct_tasklet[i].t, cvm_oct_tasklet_rx, 0); +} + +void cvm_oct_rx_shutdown(void) +{ + int i; + /* Shutdown all of the tasklets */ + for (i = 0; i < NR_CPUS; i++) + tasklet_kill(&cvm_oct_tasklet[i].t); +} diff --git a/drivers/staging/octeon/ethernet-rx.h b/drivers/staging/octeon/ethernet-rx.h new file mode 100644 index 000000000000..a9b72b87a7a6 --- /dev/null +++ b/drivers/staging/octeon/ethernet-rx.h @@ -0,0 +1,33 @@ +/********************************************************************* + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2007 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information +*********************************************************************/ + +irqreturn_t cvm_oct_do_interrupt(int cpl, void *dev_id); +void cvm_oct_poll_controller(struct net_device *dev); +void cvm_oct_tasklet_rx(unsigned long unused); + +void cvm_oct_rx_initialize(void); +void cvm_oct_rx_shutdown(void); diff --git a/drivers/staging/octeon/ethernet-sgmii.c b/drivers/staging/octeon/ethernet-sgmii.c new file mode 100644 index 000000000000..2b54996bd85d --- /dev/null +++ b/drivers/staging/octeon/ethernet-sgmii.c @@ -0,0 +1,126 @@ +/********************************************************************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2007 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information +**********************************************************************/ +#include +#include +#include +#include + +#include + +#include "ethernet-defines.h" +#include "octeon-ethernet.h" +#include "ethernet-util.h" + +#include "cvmx-helper.h" + +#include "cvmx-gmxx-defs.h" + +int cvm_oct_sgmii_open(struct net_device *dev) +{ + union cvmx_gmxx_prtx_cfg gmx_cfg; + struct octeon_ethernet *priv = netdev_priv(dev); + int interface = INTERFACE(priv->port); + int index = INDEX(priv->port); + cvmx_helper_link_info_t link_info; + + gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); + gmx_cfg.s.en = 1; + cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64); + + if (!octeon_is_simulation()) { + link_info = cvmx_helper_link_get(priv->port); + if (!link_info.s.link_up) + netif_carrier_off(dev); + } + + return 0; +} + +int cvm_oct_sgmii_stop(struct net_device *dev) +{ + union cvmx_gmxx_prtx_cfg gmx_cfg; + struct octeon_ethernet *priv = netdev_priv(dev); + int interface = INTERFACE(priv->port); + int index = INDEX(priv->port); + + gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); + gmx_cfg.s.en = 0; + cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64); + return 0; +} + +static void cvm_oct_sgmii_poll(struct net_device *dev) +{ + struct octeon_ethernet *priv = netdev_priv(dev); + cvmx_helper_link_info_t link_info; + + link_info = cvmx_helper_link_get(priv->port); + if (link_info.u64 == priv->link_info) + return; + + link_info = cvmx_helper_link_autoconf(priv->port); + priv->link_info = link_info.u64; + + /* Tell Linux */ + if (link_info.s.link_up) { + + if (!netif_carrier_ok(dev)) + netif_carrier_on(dev); + if (priv->queue != -1) + DEBUGPRINT + ("%s: %u Mbps %s duplex, port %2d, queue %2d\n", + dev->name, link_info.s.speed, + (link_info.s.full_duplex) ? "Full" : "Half", + priv->port, priv->queue); + else + DEBUGPRINT("%s: %u Mbps %s duplex, port %2d, POW\n", + dev->name, link_info.s.speed, + (link_info.s.full_duplex) ? "Full" : "Half", + priv->port); + } else { + if (netif_carrier_ok(dev)) + netif_carrier_off(dev); + DEBUGPRINT("%s: Link down\n", dev->name); + } +} + +int cvm_oct_sgmii_init(struct net_device *dev) +{ + struct octeon_ethernet *priv = netdev_priv(dev); + cvm_oct_common_init(dev); + dev->netdev_ops->ndo_stop(dev); + if (!octeon_is_simulation()) + priv->poll = cvm_oct_sgmii_poll; + + /* FIXME: Need autoneg logic */ + return 0; +} + +void cvm_oct_sgmii_uninit(struct net_device *dev) +{ + cvm_oct_common_uninit(dev); +} diff --git a/drivers/staging/octeon/ethernet-spi.c b/drivers/staging/octeon/ethernet-spi.c new file mode 100644 index 000000000000..66190b0cb68f --- /dev/null +++ b/drivers/staging/octeon/ethernet-spi.c @@ -0,0 +1,322 @@ +/********************************************************************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2007 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information +**********************************************************************/ +#include +#include +#include +#include + +#include + +#include "ethernet-defines.h" +#include "octeon-ethernet.h" +#include "ethernet-util.h" + +#include "cvmx-spi.h" + +#include +#include "cvmx-spxx-defs.h" +#include "cvmx-stxx-defs.h" + +static int number_spi_ports; +static int need_retrain[2] = { 0, 0 }; + +static irqreturn_t cvm_oct_spi_rml_interrupt(int cpl, void *dev_id) +{ + irqreturn_t return_status = IRQ_NONE; + union cvmx_npi_rsl_int_blocks rsl_int_blocks; + + /* Check and see if this interrupt was caused by the GMX block */ + rsl_int_blocks.u64 = cvmx_read_csr(CVMX_NPI_RSL_INT_BLOCKS); + if (rsl_int_blocks.s.spx1) { /* 19 - SPX1_INT_REG & STX1_INT_REG */ + + union cvmx_spxx_int_reg spx_int_reg; + union cvmx_stxx_int_reg stx_int_reg; + + spx_int_reg.u64 = cvmx_read_csr(CVMX_SPXX_INT_REG(1)); + cvmx_write_csr(CVMX_SPXX_INT_REG(1), spx_int_reg.u64); + if (!need_retrain[1]) { + + spx_int_reg.u64 &= cvmx_read_csr(CVMX_SPXX_INT_MSK(1)); + if (spx_int_reg.s.spf) + pr_err("SPI1: SRX Spi4 interface down\n"); + if (spx_int_reg.s.calerr) + pr_err("SPI1: SRX Spi4 Calendar table " + "parity error\n"); + if (spx_int_reg.s.syncerr) + pr_err("SPI1: SRX Consecutive Spi4 DIP4 " + "errors have exceeded " + "SPX_ERR_CTL[ERRCNT]\n"); + if (spx_int_reg.s.diperr) + pr_err("SPI1: SRX Spi4 DIP4 error\n"); + if (spx_int_reg.s.tpaovr) + pr_err("SPI1: SRX Selected port has hit " + "TPA overflow\n"); + if (spx_int_reg.s.rsverr) + pr_err("SPI1: SRX Spi4 reserved control " + "word detected\n"); + if (spx_int_reg.s.drwnng) + pr_err("SPI1: SRX Spi4 receive FIFO " + "drowning/overflow\n"); + if (spx_int_reg.s.clserr) + pr_err("SPI1: SRX Spi4 packet closed on " + "non-16B alignment without EOP\n"); + if (spx_int_reg.s.spiovr) + pr_err("SPI1: SRX Spi4 async FIFO overflow\n"); + if (spx_int_reg.s.abnorm) + pr_err("SPI1: SRX Abnormal packet " + "termination (ERR bit)\n"); + if (spx_int_reg.s.prtnxa) + pr_err("SPI1: SRX Port out of range\n"); + } + + stx_int_reg.u64 = cvmx_read_csr(CVMX_STXX_INT_REG(1)); + cvmx_write_csr(CVMX_STXX_INT_REG(1), stx_int_reg.u64); + if (!need_retrain[1]) { + + stx_int_reg.u64 &= cvmx_read_csr(CVMX_STXX_INT_MSK(1)); + if (stx_int_reg.s.syncerr) + pr_err("SPI1: STX Interface encountered a " + "fatal error\n"); + if (stx_int_reg.s.frmerr) + pr_err("SPI1: STX FRMCNT has exceeded " + "STX_DIP_CNT[MAXFRM]\n"); + if (stx_int_reg.s.unxfrm) + pr_err("SPI1: STX Unexpected framing " + "sequence\n"); + if (stx_int_reg.s.nosync) + pr_err("SPI1: STX ERRCNT has exceeded " + "STX_DIP_CNT[MAXDIP]\n"); + if (stx_int_reg.s.diperr) + pr_err("SPI1: STX DIP2 error on the Spi4 " + "Status channel\n"); + if (stx_int_reg.s.datovr) + pr_err("SPI1: STX Spi4 FIFO overflow error\n"); + if (stx_int_reg.s.ovrbst) + pr_err("SPI1: STX Transmit packet burst " + "too big\n"); + if (stx_int_reg.s.calpar1) + pr_err("SPI1: STX Calendar Table Parity " + "Error Bank1\n"); + if (stx_int_reg.s.calpar0) + pr_err("SPI1: STX Calendar Table Parity " + "Error Bank0\n"); + } + + cvmx_write_csr(CVMX_SPXX_INT_MSK(1), 0); + cvmx_write_csr(CVMX_STXX_INT_MSK(1), 0); + need_retrain[1] = 1; + return_status = IRQ_HANDLED; + } + + if (rsl_int_blocks.s.spx0) { /* 18 - SPX0_INT_REG & STX0_INT_REG */ + union cvmx_spxx_int_reg spx_int_reg; + union cvmx_stxx_int_reg stx_int_reg; + + spx_int_reg.u64 = cvmx_read_csr(CVMX_SPXX_INT_REG(0)); + cvmx_write_csr(CVMX_SPXX_INT_REG(0), spx_int_reg.u64); + if (!need_retrain[0]) { + + spx_int_reg.u64 &= cvmx_read_csr(CVMX_SPXX_INT_MSK(0)); + if (spx_int_reg.s.spf) + pr_err("SPI0: SRX Spi4 interface down\n"); + if (spx_int_reg.s.calerr) + pr_err("SPI0: SRX Spi4 Calendar table " + "parity error\n"); + if (spx_int_reg.s.syncerr) + pr_err("SPI0: SRX Consecutive Spi4 DIP4 " + "errors have exceeded " + "SPX_ERR_CTL[ERRCNT]\n"); + if (spx_int_reg.s.diperr) + pr_err("SPI0: SRX Spi4 DIP4 error\n"); + if (spx_int_reg.s.tpaovr) + pr_err("SPI0: SRX Selected port has hit " + "TPA overflow\n"); + if (spx_int_reg.s.rsverr) + pr_err("SPI0: SRX Spi4 reserved control " + "word detected\n"); + if (spx_int_reg.s.drwnng) + pr_err("SPI0: SRX Spi4 receive FIFO " + "drowning/overflow\n"); + if (spx_int_reg.s.clserr) + pr_err("SPI0: SRX Spi4 packet closed on " + "non-16B alignment without EOP\n"); + if (spx_int_reg.s.spiovr) + pr_err("SPI0: SRX Spi4 async FIFO overflow\n"); + if (spx_int_reg.s.abnorm) + pr_err("SPI0: SRX Abnormal packet " + "termination (ERR bit)\n"); + if (spx_int_reg.s.prtnxa) + pr_err("SPI0: SRX Port out of range\n"); + } + + stx_int_reg.u64 = cvmx_read_csr(CVMX_STXX_INT_REG(0)); + cvmx_write_csr(CVMX_STXX_INT_REG(0), stx_int_reg.u64); + if (!need_retrain[0]) { + + stx_int_reg.u64 &= cvmx_read_csr(CVMX_STXX_INT_MSK(0)); + if (stx_int_reg.s.syncerr) + pr_err("SPI0: STX Interface encountered a " + "fatal error\n"); + if (stx_int_reg.s.frmerr) + pr_err("SPI0: STX FRMCNT has exceeded " + "STX_DIP_CNT[MAXFRM]\n"); + if (stx_int_reg.s.unxfrm) + pr_err("SPI0: STX Unexpected framing " + "sequence\n"); + if (stx_int_reg.s.nosync) + pr_err("SPI0: STX ERRCNT has exceeded " + "STX_DIP_CNT[MAXDIP]\n"); + if (stx_int_reg.s.diperr) + pr_err("SPI0: STX DIP2 error on the Spi4 " + "Status channel\n"); + if (stx_int_reg.s.datovr) + pr_err("SPI0: STX Spi4 FIFO overflow error\n"); + if (stx_int_reg.s.ovrbst) + pr_err("SPI0: STX Transmit packet burst " + "too big\n"); + if (stx_int_reg.s.calpar1) + pr_err("SPI0: STX Calendar Table Parity " + "Error Bank1\n"); + if (stx_int_reg.s.calpar0) + pr_err("SPI0: STX Calendar Table Parity " + "Error Bank0\n"); + } + + cvmx_write_csr(CVMX_SPXX_INT_MSK(0), 0); + cvmx_write_csr(CVMX_STXX_INT_MSK(0), 0); + need_retrain[0] = 1; + return_status = IRQ_HANDLED; + } + + return return_status; +} + +static void cvm_oct_spi_enable_error_reporting(int interface) +{ + union cvmx_spxx_int_msk spxx_int_msk; + union cvmx_stxx_int_msk stxx_int_msk; + + spxx_int_msk.u64 = cvmx_read_csr(CVMX_SPXX_INT_MSK(interface)); + spxx_int_msk.s.calerr = 1; + spxx_int_msk.s.syncerr = 1; + spxx_int_msk.s.diperr = 1; + spxx_int_msk.s.tpaovr = 1; + spxx_int_msk.s.rsverr = 1; + spxx_int_msk.s.drwnng = 1; + spxx_int_msk.s.clserr = 1; + spxx_int_msk.s.spiovr = 1; + spxx_int_msk.s.abnorm = 1; + spxx_int_msk.s.prtnxa = 1; + cvmx_write_csr(CVMX_SPXX_INT_MSK(interface), spxx_int_msk.u64); + + stxx_int_msk.u64 = cvmx_read_csr(CVMX_STXX_INT_MSK(interface)); + stxx_int_msk.s.frmerr = 1; + stxx_int_msk.s.unxfrm = 1; + stxx_int_msk.s.nosync = 1; + stxx_int_msk.s.diperr = 1; + stxx_int_msk.s.datovr = 1; + stxx_int_msk.s.ovrbst = 1; + stxx_int_msk.s.calpar1 = 1; + stxx_int_msk.s.calpar0 = 1; + cvmx_write_csr(CVMX_STXX_INT_MSK(interface), stxx_int_msk.u64); +} + +static void cvm_oct_spi_poll(struct net_device *dev) +{ + static int spi4000_port; + struct octeon_ethernet *priv = netdev_priv(dev); + int interface; + + for (interface = 0; interface < 2; interface++) { + + if ((priv->port == interface * 16) && need_retrain[interface]) { + + if (cvmx_spi_restart_interface + (interface, CVMX_SPI_MODE_DUPLEX, 10) == 0) { + need_retrain[interface] = 0; + cvm_oct_spi_enable_error_reporting(interface); + } + } + + /* + * The SPI4000 TWSI interface is very slow. In order + * not to bring the system to a crawl, we only poll a + * single port every second. This means negotiation + * speed changes take up to 10 seconds, but at least + * we don't waste absurd amounts of time waiting for + * TWSI. + */ + if (priv->port == spi4000_port) { + /* + * This function does nothing if it is called on an + * interface without a SPI4000. + */ + cvmx_spi4000_check_speed(interface, priv->port); + /* + * Normal ordering increments. By decrementing + * we only match once per iteration. + */ + spi4000_port--; + if (spi4000_port < 0) + spi4000_port = 10; + } + } +} + +int cvm_oct_spi_init(struct net_device *dev) +{ + int r; + struct octeon_ethernet *priv = netdev_priv(dev); + + if (number_spi_ports == 0) { + r = request_irq(OCTEON_IRQ_RML, cvm_oct_spi_rml_interrupt, + IRQF_SHARED, "SPI", &number_spi_ports); + } + number_spi_ports++; + + if ((priv->port == 0) || (priv->port == 16)) { + cvm_oct_spi_enable_error_reporting(INTERFACE(priv->port)); + priv->poll = cvm_oct_spi_poll; + } + cvm_oct_common_init(dev); + return 0; +} + +void cvm_oct_spi_uninit(struct net_device *dev) +{ + int interface; + + cvm_oct_common_uninit(dev); + number_spi_ports--; + if (number_spi_ports == 0) { + for (interface = 0; interface < 2; interface++) { + cvmx_write_csr(CVMX_SPXX_INT_MSK(interface), 0); + cvmx_write_csr(CVMX_STXX_INT_MSK(interface), 0); + } + free_irq(8 + 46, &number_spi_ports); + } +} diff --git a/drivers/staging/octeon/ethernet-tx.c b/drivers/staging/octeon/ethernet-tx.c new file mode 100644 index 000000000000..81a851390f1b --- /dev/null +++ b/drivers/staging/octeon/ethernet-tx.c @@ -0,0 +1,644 @@ +/********************************************************************* + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2007 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information +*********************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_XFRM +#include +#include +#endif /* CONFIG_XFRM */ + +#include + +#include + +#include "ethernet-defines.h" +#include "octeon-ethernet.h" +#include "ethernet-tx.h" +#include "ethernet-util.h" + +#include "cvmx-wqe.h" +#include "cvmx-fau.h" +#include "cvmx-pko.h" +#include "cvmx-helper.h" + +#include "cvmx-gmxx-defs.h" + +/* + * You can define GET_SKBUFF_QOS() to override how the skbuff output + * function determines which output queue is used. The default + * implementation always uses the base queue for the port. If, for + * example, you wanted to use the skb->priority fieid, define + * GET_SKBUFF_QOS as: #define GET_SKBUFF_QOS(skb) ((skb)->priority) + */ +#ifndef GET_SKBUFF_QOS +#define GET_SKBUFF_QOS(skb) 0 +#endif + +/** + * Packet transmit + * + * @skb: Packet to send + * @dev: Device info structure + * Returns Always returns zero + */ +int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev) +{ + cvmx_pko_command_word0_t pko_command; + union cvmx_buf_ptr hw_buffer; + uint64_t old_scratch; + uint64_t old_scratch2; + int dropped; + int qos; + int queue_it_up; + struct octeon_ethernet *priv = netdev_priv(dev); + int32_t skb_to_free; + int32_t undo; + int32_t buffers_to_free; +#if REUSE_SKBUFFS_WITHOUT_FREE + unsigned char *fpa_head; +#endif + + /* + * Prefetch the private data structure. It is larger that one + * cache line. + */ + prefetch(priv); + + /* Start off assuming no drop */ + dropped = 0; + + /* + * The check on CVMX_PKO_QUEUES_PER_PORT_* is designed to + * completely remove "qos" in the event neither interface + * supports multiple queues per port. + */ + if ((CVMX_PKO_QUEUES_PER_PORT_INTERFACE0 > 1) || + (CVMX_PKO_QUEUES_PER_PORT_INTERFACE1 > 1)) { + qos = GET_SKBUFF_QOS(skb); + if (qos <= 0) + qos = 0; + else if (qos >= cvmx_pko_get_num_queues(priv->port)) + qos = 0; + } else + qos = 0; + + if (USE_ASYNC_IOBDMA) { + /* Save scratch in case userspace is using it */ + CVMX_SYNCIOBDMA; + old_scratch = cvmx_scratch_read64(CVMX_SCR_SCRATCH); + old_scratch2 = cvmx_scratch_read64(CVMX_SCR_SCRATCH + 8); + + /* + * Fetch and increment the number of packets to be + * freed. + */ + cvmx_fau_async_fetch_and_add32(CVMX_SCR_SCRATCH + 8, + FAU_NUM_PACKET_BUFFERS_TO_FREE, + 0); + cvmx_fau_async_fetch_and_add32(CVMX_SCR_SCRATCH, + priv->fau + qos * 4, + MAX_SKB_TO_FREE); + } + + /* + * The CN3XXX series of parts has an errata (GMX-401) which + * causes the GMX block to hang if a collision occurs towards + * the end of a <68 byte packet. As a workaround for this, we + * pad packets to be 68 bytes whenever we are in half duplex + * mode. We don't handle the case of having a small packet but + * no room to add the padding. The kernel should always give + * us at least a cache line + */ + if ((skb->len < 64) && OCTEON_IS_MODEL(OCTEON_CN3XXX)) { + union cvmx_gmxx_prtx_cfg gmx_prt_cfg; + int interface = INTERFACE(priv->port); + int index = INDEX(priv->port); + + if (interface < 2) { + /* We only need to pad packet in half duplex mode */ + gmx_prt_cfg.u64 = + cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); + if (gmx_prt_cfg.s.duplex == 0) { + int add_bytes = 64 - skb->len; + if ((skb_tail_pointer(skb) + add_bytes) <= + skb_end_pointer(skb)) + memset(__skb_put(skb, add_bytes), 0, + add_bytes); + } + } + } + + /* Build the PKO buffer pointer */ + hw_buffer.u64 = 0; + hw_buffer.s.addr = cvmx_ptr_to_phys(skb->data); + hw_buffer.s.pool = 0; + hw_buffer.s.size = + (unsigned long)skb_end_pointer(skb) - (unsigned long)skb->head; + + /* Build the PKO command */ + pko_command.u64 = 0; + pko_command.s.n2 = 1; /* Don't pollute L2 with the outgoing packet */ + pko_command.s.segs = 1; + pko_command.s.total_bytes = skb->len; + pko_command.s.size0 = CVMX_FAU_OP_SIZE_32; + pko_command.s.subone0 = 1; + + pko_command.s.dontfree = 1; + pko_command.s.reg0 = priv->fau + qos * 4; + /* + * See if we can put this skb in the FPA pool. Any strange + * behavior from the Linux networking stack will most likely + * be caused by a bug in the following code. If some field is + * in use by the network stack and get carried over when a + * buffer is reused, bad thing may happen. If in doubt and + * you dont need the absolute best performance, disable the + * define REUSE_SKBUFFS_WITHOUT_FREE. The reuse of buffers has + * shown a 25% increase in performance under some loads. + */ +#if REUSE_SKBUFFS_WITHOUT_FREE + fpa_head = skb->head + 128 - ((unsigned long)skb->head & 0x7f); + if (unlikely(skb->data < fpa_head)) { + /* + * printk("TX buffer beginning can't meet FPA + * alignment constraints\n"); + */ + goto dont_put_skbuff_in_hw; + } + if (unlikely + ((skb_end_pointer(skb) - fpa_head) < CVMX_FPA_PACKET_POOL_SIZE)) { + /* + printk("TX buffer isn't large enough for the FPA\n"); + */ + goto dont_put_skbuff_in_hw; + } + if (unlikely(skb_shared(skb))) { + /* + printk("TX buffer sharing data with someone else\n"); + */ + goto dont_put_skbuff_in_hw; + } + if (unlikely(skb_cloned(skb))) { + /* + printk("TX buffer has been cloned\n"); + */ + goto dont_put_skbuff_in_hw; + } + if (unlikely(skb_header_cloned(skb))) { + /* + printk("TX buffer header has been cloned\n"); + */ + goto dont_put_skbuff_in_hw; + } + if (unlikely(skb->destructor)) { + /* + printk("TX buffer has a destructor\n"); + */ + goto dont_put_skbuff_in_hw; + } + if (unlikely(skb_shinfo(skb)->nr_frags)) { + /* + printk("TX buffer has fragments\n"); + */ + goto dont_put_skbuff_in_hw; + } + if (unlikely + (skb->truesize != + sizeof(*skb) + skb_end_pointer(skb) - skb->head)) { + /* + printk("TX buffer truesize has been changed\n"); + */ + goto dont_put_skbuff_in_hw; + } + + /* + * We can use this buffer in the FPA. We don't need the FAU + * update anymore + */ + pko_command.s.reg0 = 0; + pko_command.s.dontfree = 0; + + hw_buffer.s.back = (skb->data - fpa_head) >> 7; + *(struct sk_buff **)(fpa_head - sizeof(void *)) = skb; + + /* + * The skbuff will be reused without ever being freed. We must + * cleanup a bunch of core things. + */ + dst_release(skb_dst(skb)); + skb_dst_set(skb, NULL); +#ifdef CONFIG_XFRM + secpath_put(skb->sp); + skb->sp = NULL; +#endif + nf_reset(skb); + +#ifdef CONFIG_NET_SCHED + skb->tc_index = 0; +#ifdef CONFIG_NET_CLS_ACT + skb->tc_verd = 0; +#endif /* CONFIG_NET_CLS_ACT */ +#endif /* CONFIG_NET_SCHED */ + +dont_put_skbuff_in_hw: +#endif /* REUSE_SKBUFFS_WITHOUT_FREE */ + + /* Check if we can use the hardware checksumming */ + if (USE_HW_TCPUDP_CHECKSUM && (skb->protocol == htons(ETH_P_IP)) && + (ip_hdr(skb)->version == 4) && (ip_hdr(skb)->ihl == 5) && + ((ip_hdr(skb)->frag_off == 0) || (ip_hdr(skb)->frag_off == 1 << 14)) + && ((ip_hdr(skb)->protocol == IP_PROTOCOL_TCP) + || (ip_hdr(skb)->protocol == IP_PROTOCOL_UDP))) { + /* Use hardware checksum calc */ + pko_command.s.ipoffp1 = sizeof(struct ethhdr) + 1; + } + + if (USE_ASYNC_IOBDMA) { + /* Get the number of skbuffs in use by the hardware */ + CVMX_SYNCIOBDMA; + skb_to_free = cvmx_scratch_read64(CVMX_SCR_SCRATCH); + buffers_to_free = cvmx_scratch_read64(CVMX_SCR_SCRATCH + 8); + } else { + /* Get the number of skbuffs in use by the hardware */ + skb_to_free = cvmx_fau_fetch_and_add32(priv->fau + qos * 4, + MAX_SKB_TO_FREE); + buffers_to_free = + cvmx_fau_fetch_and_add32(FAU_NUM_PACKET_BUFFERS_TO_FREE, 0); + } + + /* + * We try to claim MAX_SKB_TO_FREE buffers. If there were not + * that many available, we have to un-claim (undo) any that + * were in excess. If skb_to_free is positive we will free + * that many buffers. + */ + undo = skb_to_free > 0 ? + MAX_SKB_TO_FREE : skb_to_free + MAX_SKB_TO_FREE; + if (undo > 0) + cvmx_fau_atomic_add32(priv->fau+qos*4, -undo); + skb_to_free = -skb_to_free > MAX_SKB_TO_FREE ? + MAX_SKB_TO_FREE : -skb_to_free; + + /* + * If we're sending faster than the receive can free them then + * don't do the HW free. + */ + if ((buffers_to_free < -100) && !pko_command.s.dontfree) { + pko_command.s.dontfree = 1; + pko_command.s.reg0 = priv->fau + qos * 4; + } + + cvmx_pko_send_packet_prepare(priv->port, priv->queue + qos, + CVMX_PKO_LOCK_CMD_QUEUE); + + /* Drop this packet if we have too many already queued to the HW */ + if (unlikely + (skb_queue_len(&priv->tx_free_list[qos]) >= MAX_OUT_QUEUE_DEPTH)) { + /* + DEBUGPRINT("%s: Tx dropped. Too many queued\n", dev->name); + */ + dropped = 1; + } + /* Send the packet to the output queue */ + else if (unlikely + (cvmx_pko_send_packet_finish + (priv->port, priv->queue + qos, pko_command, hw_buffer, + CVMX_PKO_LOCK_CMD_QUEUE))) { + DEBUGPRINT("%s: Failed to send the packet\n", dev->name); + dropped = 1; + } + + if (USE_ASYNC_IOBDMA) { + /* Restore the scratch area */ + cvmx_scratch_write64(CVMX_SCR_SCRATCH, old_scratch); + cvmx_scratch_write64(CVMX_SCR_SCRATCH + 8, old_scratch2); + } + + queue_it_up = 0; + if (unlikely(dropped)) { + dev_kfree_skb_any(skb); + priv->stats.tx_dropped++; + } else { + if (USE_SKBUFFS_IN_HW) { + /* Put this packet on the queue to be freed later */ + if (pko_command.s.dontfree) + queue_it_up = 1; + else + cvmx_fau_atomic_add32 + (FAU_NUM_PACKET_BUFFERS_TO_FREE, -1); + } else { + /* Put this packet on the queue to be freed later */ + queue_it_up = 1; + } + } + + if (queue_it_up) { + spin_lock(&priv->tx_free_list[qos].lock); + __skb_queue_tail(&priv->tx_free_list[qos], skb); + cvm_oct_free_tx_skbs(priv, skb_to_free, qos, 0); + spin_unlock(&priv->tx_free_list[qos].lock); + } else { + cvm_oct_free_tx_skbs(priv, skb_to_free, qos, 1); + } + + return 0; +} + +/** + * Packet transmit to the POW + * + * @skb: Packet to send + * @dev: Device info structure + * Returns Always returns zero + */ +int cvm_oct_xmit_pow(struct sk_buff *skb, struct net_device *dev) +{ + struct octeon_ethernet *priv = netdev_priv(dev); + void *packet_buffer; + void *copy_location; + + /* Get a work queue entry */ + cvmx_wqe_t *work = cvmx_fpa_alloc(CVMX_FPA_WQE_POOL); + if (unlikely(work == NULL)) { + DEBUGPRINT("%s: Failed to allocate a work queue entry\n", + dev->name); + priv->stats.tx_dropped++; + dev_kfree_skb(skb); + return 0; + } + + /* Get a packet buffer */ + packet_buffer = cvmx_fpa_alloc(CVMX_FPA_PACKET_POOL); + if (unlikely(packet_buffer == NULL)) { + DEBUGPRINT("%s: Failed to allocate a packet buffer\n", + dev->name); + cvmx_fpa_free(work, CVMX_FPA_WQE_POOL, DONT_WRITEBACK(1)); + priv->stats.tx_dropped++; + dev_kfree_skb(skb); + return 0; + } + + /* + * Calculate where we need to copy the data to. We need to + * leave 8 bytes for a next pointer (unused). We also need to + * include any configure skip. Then we need to align the IP + * packet src and dest into the same 64bit word. The below + * calculation may add a little extra, but that doesn't + * hurt. + */ + copy_location = packet_buffer + sizeof(uint64_t); + copy_location += ((CVMX_HELPER_FIRST_MBUFF_SKIP + 7) & 0xfff8) + 6; + + /* + * We have to copy the packet since whoever processes this + * packet will free it to a hardware pool. We can't use the + * trick of counting outstanding packets like in + * cvm_oct_xmit. + */ + memcpy(copy_location, skb->data, skb->len); + + /* + * Fill in some of the work queue fields. We may need to add + * more if the software at the other end needs them. + */ + work->hw_chksum = skb->csum; + work->len = skb->len; + work->ipprt = priv->port; + work->qos = priv->port & 0x7; + work->grp = pow_send_group; + work->tag_type = CVMX_HELPER_INPUT_TAG_TYPE; + work->tag = pow_send_group; /* FIXME */ + /* Default to zero. Sets of zero later are commented out */ + work->word2.u64 = 0; + work->word2.s.bufs = 1; + work->packet_ptr.u64 = 0; + work->packet_ptr.s.addr = cvmx_ptr_to_phys(copy_location); + work->packet_ptr.s.pool = CVMX_FPA_PACKET_POOL; + work->packet_ptr.s.size = CVMX_FPA_PACKET_POOL_SIZE; + work->packet_ptr.s.back = (copy_location - packet_buffer) >> 7; + + if (skb->protocol == htons(ETH_P_IP)) { + work->word2.s.ip_offset = 14; +#if 0 + work->word2.s.vlan_valid = 0; /* FIXME */ + work->word2.s.vlan_cfi = 0; /* FIXME */ + work->word2.s.vlan_id = 0; /* FIXME */ + work->word2.s.dec_ipcomp = 0; /* FIXME */ +#endif + work->word2.s.tcp_or_udp = + (ip_hdr(skb)->protocol == IP_PROTOCOL_TCP) + || (ip_hdr(skb)->protocol == IP_PROTOCOL_UDP); +#if 0 + /* FIXME */ + work->word2.s.dec_ipsec = 0; + /* We only support IPv4 right now */ + work->word2.s.is_v6 = 0; + /* Hardware would set to zero */ + work->word2.s.software = 0; + /* No error, packet is internal */ + work->word2.s.L4_error = 0; +#endif + work->word2.s.is_frag = !((ip_hdr(skb)->frag_off == 0) + || (ip_hdr(skb)->frag_off == + 1 << 14)); +#if 0 + /* Assume Linux is sending a good packet */ + work->word2.s.IP_exc = 0; +#endif + work->word2.s.is_bcast = (skb->pkt_type == PACKET_BROADCAST); + work->word2.s.is_mcast = (skb->pkt_type == PACKET_MULTICAST); +#if 0 + /* This is an IP packet */ + work->word2.s.not_IP = 0; + /* No error, packet is internal */ + work->word2.s.rcv_error = 0; + /* No error, packet is internal */ + work->word2.s.err_code = 0; +#endif + + /* + * When copying the data, include 4 bytes of the + * ethernet header to align the same way hardware + * does. + */ + memcpy(work->packet_data, skb->data + 10, + sizeof(work->packet_data)); + } else { +#if 0 + work->word2.snoip.vlan_valid = 0; /* FIXME */ + work->word2.snoip.vlan_cfi = 0; /* FIXME */ + work->word2.snoip.vlan_id = 0; /* FIXME */ + work->word2.snoip.software = 0; /* Hardware would set to zero */ +#endif + work->word2.snoip.is_rarp = skb->protocol == htons(ETH_P_RARP); + work->word2.snoip.is_arp = skb->protocol == htons(ETH_P_ARP); + work->word2.snoip.is_bcast = + (skb->pkt_type == PACKET_BROADCAST); + work->word2.snoip.is_mcast = + (skb->pkt_type == PACKET_MULTICAST); + work->word2.snoip.not_IP = 1; /* IP was done up above */ +#if 0 + /* No error, packet is internal */ + work->word2.snoip.rcv_error = 0; + /* No error, packet is internal */ + work->word2.snoip.err_code = 0; +#endif + memcpy(work->packet_data, skb->data, sizeof(work->packet_data)); + } + + /* Submit the packet to the POW */ + cvmx_pow_work_submit(work, work->tag, work->tag_type, work->qos, + work->grp); + priv->stats.tx_packets++; + priv->stats.tx_bytes += skb->len; + dev_kfree_skb(skb); + return 0; +} + +/** + * Transmit a work queue entry out of the ethernet port. Both + * the work queue entry and the packet data can optionally be + * freed. The work will be freed on error as well. + * + * @dev: Device to transmit out. + * @work_queue_entry: + * Work queue entry to send + * @do_free: True if the work queue entry and packet data should be + * freed. If false, neither will be freed. + * @qos: Index into the queues for this port to transmit on. This + * is used to implement QoS if their are multiple queues per + * port. This parameter must be between 0 and the number of + * queues per port minus 1. Values outside of this range will + * be change to zero. + * + * Returns Zero on success, negative on failure. + */ +int cvm_oct_transmit_qos(struct net_device *dev, void *work_queue_entry, + int do_free, int qos) +{ + unsigned long flags; + union cvmx_buf_ptr hw_buffer; + cvmx_pko_command_word0_t pko_command; + int dropped; + struct octeon_ethernet *priv = netdev_priv(dev); + cvmx_wqe_t *work = work_queue_entry; + + if (!(dev->flags & IFF_UP)) { + DEBUGPRINT("%s: Device not up\n", dev->name); + if (do_free) + cvm_oct_free_work(work); + return -1; + } + + /* The check on CVMX_PKO_QUEUES_PER_PORT_* is designed to completely + remove "qos" in the event neither interface supports + multiple queues per port */ + if ((CVMX_PKO_QUEUES_PER_PORT_INTERFACE0 > 1) || + (CVMX_PKO_QUEUES_PER_PORT_INTERFACE1 > 1)) { + if (qos <= 0) + qos = 0; + else if (qos >= cvmx_pko_get_num_queues(priv->port)) + qos = 0; + } else + qos = 0; + + /* Start off assuming no drop */ + dropped = 0; + + local_irq_save(flags); + cvmx_pko_send_packet_prepare(priv->port, priv->queue + qos, + CVMX_PKO_LOCK_CMD_QUEUE); + + /* Build the PKO buffer pointer */ + hw_buffer.u64 = 0; + hw_buffer.s.addr = work->packet_ptr.s.addr; + hw_buffer.s.pool = CVMX_FPA_PACKET_POOL; + hw_buffer.s.size = CVMX_FPA_PACKET_POOL_SIZE; + hw_buffer.s.back = work->packet_ptr.s.back; + + /* Build the PKO command */ + pko_command.u64 = 0; + pko_command.s.n2 = 1; /* Don't pollute L2 with the outgoing packet */ + pko_command.s.dontfree = !do_free; + pko_command.s.segs = work->word2.s.bufs; + pko_command.s.total_bytes = work->len; + + /* Check if we can use the hardware checksumming */ + if (unlikely(work->word2.s.not_IP || work->word2.s.IP_exc)) + pko_command.s.ipoffp1 = 0; + else + pko_command.s.ipoffp1 = sizeof(struct ethhdr) + 1; + + /* Send the packet to the output queue */ + if (unlikely + (cvmx_pko_send_packet_finish + (priv->port, priv->queue + qos, pko_command, hw_buffer, + CVMX_PKO_LOCK_CMD_QUEUE))) { + DEBUGPRINT("%s: Failed to send the packet\n", dev->name); + dropped = -1; + } + local_irq_restore(flags); + + if (unlikely(dropped)) { + if (do_free) + cvm_oct_free_work(work); + priv->stats.tx_dropped++; + } else if (do_free) + cvmx_fpa_free(work, CVMX_FPA_WQE_POOL, DONT_WRITEBACK(1)); + + return dropped; +} +EXPORT_SYMBOL(cvm_oct_transmit_qos); + +/** + * This function frees all skb that are currenty queued for TX. + * + * @dev: Device being shutdown + */ +void cvm_oct_tx_shutdown(struct net_device *dev) +{ + struct octeon_ethernet *priv = netdev_priv(dev); + unsigned long flags; + int qos; + + for (qos = 0; qos < 16; qos++) { + spin_lock_irqsave(&priv->tx_free_list[qos].lock, flags); + while (skb_queue_len(&priv->tx_free_list[qos])) + dev_kfree_skb_any(__skb_dequeue + (&priv->tx_free_list[qos])); + spin_unlock_irqrestore(&priv->tx_free_list[qos].lock, flags); + } +} diff --git a/drivers/staging/octeon/ethernet-tx.h b/drivers/staging/octeon/ethernet-tx.h new file mode 100644 index 000000000000..c0bebf750bc0 --- /dev/null +++ b/drivers/staging/octeon/ethernet-tx.h @@ -0,0 +1,57 @@ +/********************************************************************* + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2007 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information +*********************************************************************/ + +int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev); +int cvm_oct_xmit_pow(struct sk_buff *skb, struct net_device *dev); +int cvm_oct_transmit_qos(struct net_device *dev, void *work_queue_entry, + int do_free, int qos); +void cvm_oct_tx_shutdown(struct net_device *dev); + +/** + * Free dead transmit skbs. + * + * @priv: The driver data + * @skb_to_free: The number of SKBs to free (free none if negative). + * @qos: The queue to free from. + * @take_lock: If true, acquire the skb list lock. + */ +static inline void cvm_oct_free_tx_skbs(struct octeon_ethernet *priv, + int skb_to_free, + int qos, int take_lock) +{ + /* Free skbuffs not in use by the hardware. */ + if (skb_to_free > 0) { + if (take_lock) + spin_lock(&priv->tx_free_list[qos].lock); + while (skb_to_free > 0) { + dev_kfree_skb(__skb_dequeue(&priv->tx_free_list[qos])); + skb_to_free--; + } + if (take_lock) + spin_unlock(&priv->tx_free_list[qos].lock); + } +} diff --git a/drivers/staging/octeon/ethernet-util.h b/drivers/staging/octeon/ethernet-util.h new file mode 100644 index 000000000000..37b665918000 --- /dev/null +++ b/drivers/staging/octeon/ethernet-util.h @@ -0,0 +1,81 @@ +/********************************************************************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2007 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information +*********************************************************************/ + +#define DEBUGPRINT(format, ...) do { if (printk_ratelimit()) \ + printk(format, ##__VA_ARGS__); \ + } while (0) + +/** + * Given a packet data address, return a pointer to the + * beginning of the packet buffer. + * + * @packet_ptr: Packet data hardware address + * Returns Packet buffer pointer + */ +static inline void *cvm_oct_get_buffer_ptr(union cvmx_buf_ptr packet_ptr) +{ + return cvmx_phys_to_ptr(((packet_ptr.s.addr >> 7) - packet_ptr.s.back) + << 7); +} + +/** + * Given an IPD/PKO port number, return the logical interface it is + * on. + * + * @ipd_port: Port to check + * + * Returns Logical interface + */ +static inline int INTERFACE(int ipd_port) +{ + if (ipd_port < 32) /* Interface 0 or 1 for RGMII,GMII,SPI, etc */ + return ipd_port >> 4; + else if (ipd_port < 36) /* Interface 2 for NPI */ + return 2; + else if (ipd_port < 40) /* Interface 3 for loopback */ + return 3; + else if (ipd_port == 40) /* Non existant interface for POW0 */ + return 4; + else + panic("Illegal ipd_port %d passed to INTERFACE\n", ipd_port); +} + +/** + * Given an IPD/PKO port number, return the port's index on a + * logical interface. + * + * @ipd_port: Port to check + * + * Returns Index into interface port list + */ +static inline int INDEX(int ipd_port) +{ + if (ipd_port < 32) + return ipd_port & 15; + else + return ipd_port & 3; +} diff --git a/drivers/staging/octeon/ethernet-xaui.c b/drivers/staging/octeon/ethernet-xaui.c new file mode 100644 index 000000000000..0c2e7cc40f35 --- /dev/null +++ b/drivers/staging/octeon/ethernet-xaui.c @@ -0,0 +1,124 @@ +/********************************************************************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2007 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information +**********************************************************************/ +#include +#include +#include +#include + +#include + +#include "ethernet-defines.h" +#include "octeon-ethernet.h" +#include "ethernet-util.h" + +#include "cvmx-helper.h" + +#include "cvmx-gmxx-defs.h" + +int cvm_oct_xaui_open(struct net_device *dev) +{ + union cvmx_gmxx_prtx_cfg gmx_cfg; + struct octeon_ethernet *priv = netdev_priv(dev); + int interface = INTERFACE(priv->port); + int index = INDEX(priv->port); + cvmx_helper_link_info_t link_info; + + gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); + gmx_cfg.s.en = 1; + cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64); + + if (!octeon_is_simulation()) { + link_info = cvmx_helper_link_get(priv->port); + if (!link_info.s.link_up) + netif_carrier_off(dev); + } + return 0; +} + +int cvm_oct_xaui_stop(struct net_device *dev) +{ + union cvmx_gmxx_prtx_cfg gmx_cfg; + struct octeon_ethernet *priv = netdev_priv(dev); + int interface = INTERFACE(priv->port); + int index = INDEX(priv->port); + + gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); + gmx_cfg.s.en = 0; + cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64); + return 0; +} + +static void cvm_oct_xaui_poll(struct net_device *dev) +{ + struct octeon_ethernet *priv = netdev_priv(dev); + cvmx_helper_link_info_t link_info; + + link_info = cvmx_helper_link_get(priv->port); + if (link_info.u64 == priv->link_info) + return; + + link_info = cvmx_helper_link_autoconf(priv->port); + priv->link_info = link_info.u64; + + /* Tell Linux */ + if (link_info.s.link_up) { + + if (!netif_carrier_ok(dev)) + netif_carrier_on(dev); + if (priv->queue != -1) + DEBUGPRINT + ("%s: %u Mbps %s duplex, port %2d, queue %2d\n", + dev->name, link_info.s.speed, + (link_info.s.full_duplex) ? "Full" : "Half", + priv->port, priv->queue); + else + DEBUGPRINT("%s: %u Mbps %s duplex, port %2d, POW\n", + dev->name, link_info.s.speed, + (link_info.s.full_duplex) ? "Full" : "Half", + priv->port); + } else { + if (netif_carrier_ok(dev)) + netif_carrier_off(dev); + DEBUGPRINT("%s: Link down\n", dev->name); + } +} + +int cvm_oct_xaui_init(struct net_device *dev) +{ + struct octeon_ethernet *priv = netdev_priv(dev); + cvm_oct_common_init(dev); + dev->netdev_ops->ndo_stop(dev); + if (!octeon_is_simulation()) + priv->poll = cvm_oct_xaui_poll; + + return 0; +} + +void cvm_oct_xaui_uninit(struct net_device *dev) +{ + cvm_oct_common_uninit(dev); +} diff --git a/drivers/staging/octeon/ethernet.c b/drivers/staging/octeon/ethernet.c new file mode 100644 index 000000000000..b8479517dce2 --- /dev/null +++ b/drivers/staging/octeon/ethernet.c @@ -0,0 +1,861 @@ +/********************************************************************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2007 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information +**********************************************************************/ +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "ethernet-defines.h" +#include "octeon-ethernet.h" +#include "ethernet-mem.h" +#include "ethernet-rx.h" +#include "ethernet-tx.h" +#include "ethernet-mdio.h" +#include "ethernet-util.h" +#include "ethernet-proc.h" + + +#include "cvmx-pip.h" +#include "cvmx-pko.h" +#include "cvmx-fau.h" +#include "cvmx-ipd.h" +#include "cvmx-helper.h" + +#include "cvmx-gmxx-defs.h" +#include "cvmx-smix-defs.h" + +#if defined(CONFIG_CAVIUM_OCTEON_NUM_PACKET_BUFFERS) \ + && CONFIG_CAVIUM_OCTEON_NUM_PACKET_BUFFERS +int num_packet_buffers = CONFIG_CAVIUM_OCTEON_NUM_PACKET_BUFFERS; +#else +int num_packet_buffers = 1024; +#endif +module_param(num_packet_buffers, int, 0444); +MODULE_PARM_DESC(num_packet_buffers, "\n" + "\tNumber of packet buffers to allocate and store in the\n" + "\tFPA. By default, 1024 packet buffers are used unless\n" + "\tCONFIG_CAVIUM_OCTEON_NUM_PACKET_BUFFERS is defined."); + +int pow_receive_group = 15; +module_param(pow_receive_group, int, 0444); +MODULE_PARM_DESC(pow_receive_group, "\n" + "\tPOW group to receive packets from. All ethernet hardware\n" + "\twill be configured to send incomming packets to this POW\n" + "\tgroup. Also any other software can submit packets to this\n" + "\tgroup for the kernel to process."); + +int pow_send_group = -1; +module_param(pow_send_group, int, 0644); +MODULE_PARM_DESC(pow_send_group, "\n" + "\tPOW group to send packets to other software on. This\n" + "\tcontrols the creation of the virtual device pow0.\n" + "\talways_use_pow also depends on this value."); + +int always_use_pow; +module_param(always_use_pow, int, 0444); +MODULE_PARM_DESC(always_use_pow, "\n" + "\tWhen set, always send to the pow group. This will cause\n" + "\tpackets sent to real ethernet devices to be sent to the\n" + "\tPOW group instead of the hardware. Unless some other\n" + "\tapplication changes the config, packets will still be\n" + "\treceived from the low level hardware. Use this option\n" + "\tto allow a CVMX app to intercept all packets from the\n" + "\tlinux kernel. You must specify pow_send_group along with\n" + "\tthis option."); + +char pow_send_list[128] = ""; +module_param_string(pow_send_list, pow_send_list, sizeof(pow_send_list), 0444); +MODULE_PARM_DESC(pow_send_list, "\n" + "\tComma separated list of ethernet devices that should use the\n" + "\tPOW for transmit instead of the actual ethernet hardware. This\n" + "\tis a per port version of always_use_pow. always_use_pow takes\n" + "\tprecedence over this list. For example, setting this to\n" + "\t\"eth2,spi3,spi7\" would cause these three devices to transmit\n" + "\tusing the pow_send_group."); + +static int disable_core_queueing = 1; +module_param(disable_core_queueing, int, 0444); +MODULE_PARM_DESC(disable_core_queueing, "\n" + "\tWhen set the networking core's tx_queue_len is set to zero. This\n" + "\tallows packets to be sent without lock contention in the packet\n" + "\tscheduler resulting in some cases in improved throughput.\n"); + +/** + * Periodic timer to check auto negotiation + */ +static struct timer_list cvm_oct_poll_timer; + +/** + * Array of every ethernet device owned by this driver indexed by + * the ipd input port number. + */ +struct net_device *cvm_oct_device[TOTAL_NUMBER_OF_PORTS]; + +extern struct semaphore mdio_sem; + +/** + * Periodic timer tick for slow management operations + * + * @arg: Device to check + */ +static void cvm_do_timer(unsigned long arg) +{ + int32_t skb_to_free, undo; + int queues_per_port; + int qos; + struct octeon_ethernet *priv; + static int port; + + if (port >= CVMX_PIP_NUM_INPUT_PORTS) { + /* + * All ports have been polled. Start the next + * iteration through the ports in one second. + */ + port = 0; + mod_timer(&cvm_oct_poll_timer, jiffies + HZ); + return; + } + if (!cvm_oct_device[port]) + goto out; + + priv = netdev_priv(cvm_oct_device[port]); + if (priv->poll) { + /* skip polling if we don't get the lock */ + if (!down_trylock(&mdio_sem)) { + priv->poll(cvm_oct_device[port]); + up(&mdio_sem); + } + } + + queues_per_port = cvmx_pko_get_num_queues(port); + /* Drain any pending packets in the free list */ + for (qos = 0; qos < queues_per_port; qos++) { + if (skb_queue_len(&priv->tx_free_list[qos]) == 0) + continue; + skb_to_free = cvmx_fau_fetch_and_add32(priv->fau + qos * 4, + MAX_SKB_TO_FREE); + undo = skb_to_free > 0 ? + MAX_SKB_TO_FREE : skb_to_free + MAX_SKB_TO_FREE; + if (undo > 0) + cvmx_fau_atomic_add32(priv->fau+qos*4, -undo); + skb_to_free = -skb_to_free > MAX_SKB_TO_FREE ? + MAX_SKB_TO_FREE : -skb_to_free; + cvm_oct_free_tx_skbs(priv, skb_to_free, qos, 1); + } + cvm_oct_device[port]->netdev_ops->ndo_get_stats(cvm_oct_device[port]); + +out: + port++; + /* Poll the next port in a 50th of a second. + This spreads the polling of ports out a little bit */ + mod_timer(&cvm_oct_poll_timer, jiffies + HZ / 50); +} + +/** + * Configure common hardware for all interfaces + */ +static __init void cvm_oct_configure_common_hw(void) +{ + int r; + /* Setup the FPA */ + cvmx_fpa_enable(); + cvm_oct_mem_fill_fpa(CVMX_FPA_PACKET_POOL, CVMX_FPA_PACKET_POOL_SIZE, + num_packet_buffers); + cvm_oct_mem_fill_fpa(CVMX_FPA_WQE_POOL, CVMX_FPA_WQE_POOL_SIZE, + num_packet_buffers); + if (CVMX_FPA_OUTPUT_BUFFER_POOL != CVMX_FPA_PACKET_POOL) + cvm_oct_mem_fill_fpa(CVMX_FPA_OUTPUT_BUFFER_POOL, + CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE, 128); + + if (USE_RED) + cvmx_helper_setup_red(num_packet_buffers / 4, + num_packet_buffers / 8); + + /* Enable the MII interface */ + if (!octeon_is_simulation()) + cvmx_write_csr(CVMX_SMIX_EN(0), 1); + + /* Register an IRQ hander for to receive POW interrupts */ + r = request_irq(OCTEON_IRQ_WORKQ0 + pow_receive_group, + cvm_oct_do_interrupt, IRQF_SHARED, "Ethernet", + cvm_oct_device); + +#if defined(CONFIG_SMP) && 0 + if (USE_MULTICORE_RECEIVE) { + irq_set_affinity(OCTEON_IRQ_WORKQ0 + pow_receive_group, + cpu_online_mask); + } +#endif +} + +/** + * Free a work queue entry received in a intercept callback. + * + * @work_queue_entry: + * Work queue entry to free + * Returns Zero on success, Negative on failure. + */ +int cvm_oct_free_work(void *work_queue_entry) +{ + cvmx_wqe_t *work = work_queue_entry; + + int segments = work->word2.s.bufs; + union cvmx_buf_ptr segment_ptr = work->packet_ptr; + + while (segments--) { + union cvmx_buf_ptr next_ptr = *(union cvmx_buf_ptr *) + cvmx_phys_to_ptr(segment_ptr.s.addr - 8); + if (unlikely(!segment_ptr.s.i)) + cvmx_fpa_free(cvm_oct_get_buffer_ptr(segment_ptr), + segment_ptr.s.pool, + DONT_WRITEBACK(CVMX_FPA_PACKET_POOL_SIZE / + 128)); + segment_ptr = next_ptr; + } + cvmx_fpa_free(work, CVMX_FPA_WQE_POOL, DONT_WRITEBACK(1)); + + return 0; +} +EXPORT_SYMBOL(cvm_oct_free_work); + +/** + * Get the low level ethernet statistics + * + * @dev: Device to get the statistics from + * Returns Pointer to the statistics + */ +static struct net_device_stats *cvm_oct_common_get_stats(struct net_device *dev) +{ + cvmx_pip_port_status_t rx_status; + cvmx_pko_port_status_t tx_status; + struct octeon_ethernet *priv = netdev_priv(dev); + + if (priv->port < CVMX_PIP_NUM_INPUT_PORTS) { + if (octeon_is_simulation()) { + /* The simulator doesn't support statistics */ + memset(&rx_status, 0, sizeof(rx_status)); + memset(&tx_status, 0, sizeof(tx_status)); + } else { + cvmx_pip_get_port_status(priv->port, 1, &rx_status); + cvmx_pko_get_port_status(priv->port, 1, &tx_status); + } + + priv->stats.rx_packets += rx_status.inb_packets; + priv->stats.tx_packets += tx_status.packets; + priv->stats.rx_bytes += rx_status.inb_octets; + priv->stats.tx_bytes += tx_status.octets; + priv->stats.multicast += rx_status.multicast_packets; + priv->stats.rx_crc_errors += rx_status.inb_errors; + priv->stats.rx_frame_errors += rx_status.fcs_align_err_packets; + + /* + * The drop counter must be incremented atomically + * since the RX tasklet also increments it. + */ +#ifdef CONFIG_64BIT + atomic64_add(rx_status.dropped_packets, + (atomic64_t *)&priv->stats.rx_dropped); +#else + atomic_add(rx_status.dropped_packets, + (atomic_t *)&priv->stats.rx_dropped); +#endif + } + + return &priv->stats; +} + +/** + * Change the link MTU. Unimplemented + * + * @dev: Device to change + * @new_mtu: The new MTU + * + * Returns Zero on success + */ +static int cvm_oct_common_change_mtu(struct net_device *dev, int new_mtu) +{ + struct octeon_ethernet *priv = netdev_priv(dev); + int interface = INTERFACE(priv->port); + int index = INDEX(priv->port); +#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) + int vlan_bytes = 4; +#else + int vlan_bytes = 0; +#endif + + /* + * Limit the MTU to make sure the ethernet packets are between + * 64 bytes and 65535 bytes. + */ + if ((new_mtu + 14 + 4 + vlan_bytes < 64) + || (new_mtu + 14 + 4 + vlan_bytes > 65392)) { + pr_err("MTU must be between %d and %d.\n", + 64 - 14 - 4 - vlan_bytes, 65392 - 14 - 4 - vlan_bytes); + return -EINVAL; + } + dev->mtu = new_mtu; + + if ((interface < 2) + && (cvmx_helper_interface_get_mode(interface) != + CVMX_HELPER_INTERFACE_MODE_SPI)) { + /* Add ethernet header and FCS, and VLAN if configured. */ + int max_packet = new_mtu + 14 + 4 + vlan_bytes; + + if (OCTEON_IS_MODEL(OCTEON_CN3XXX) + || OCTEON_IS_MODEL(OCTEON_CN58XX)) { + /* Signal errors on packets larger than the MTU */ + cvmx_write_csr(CVMX_GMXX_RXX_FRM_MAX(index, interface), + max_packet); + } else { + /* + * Set the hardware to truncate packets larger + * than the MTU and smaller the 64 bytes. + */ + union cvmx_pip_frm_len_chkx frm_len_chk; + frm_len_chk.u64 = 0; + frm_len_chk.s.minlen = 64; + frm_len_chk.s.maxlen = max_packet; + cvmx_write_csr(CVMX_PIP_FRM_LEN_CHKX(interface), + frm_len_chk.u64); + } + /* + * Set the hardware to truncate packets larger than + * the MTU. The jabber register must be set to a + * multiple of 8 bytes, so round up. + */ + cvmx_write_csr(CVMX_GMXX_RXX_JABBER(index, interface), + (max_packet + 7) & ~7u); + } + return 0; +} + +/** + * Set the multicast list. Currently unimplemented. + * + * @dev: Device to work on + */ +static void cvm_oct_common_set_multicast_list(struct net_device *dev) +{ + union cvmx_gmxx_prtx_cfg gmx_cfg; + struct octeon_ethernet *priv = netdev_priv(dev); + int interface = INTERFACE(priv->port); + int index = INDEX(priv->port); + + if ((interface < 2) + && (cvmx_helper_interface_get_mode(interface) != + CVMX_HELPER_INTERFACE_MODE_SPI)) { + union cvmx_gmxx_rxx_adr_ctl control; + control.u64 = 0; + control.s.bcst = 1; /* Allow broadcast MAC addresses */ + + if (dev->mc_list || (dev->flags & IFF_ALLMULTI) || + (dev->flags & IFF_PROMISC)) + /* Force accept multicast packets */ + control.s.mcst = 2; + else + /* Force reject multicat packets */ + control.s.mcst = 1; + + if (dev->flags & IFF_PROMISC) + /* + * Reject matches if promisc. Since CAM is + * shut off, should accept everything. + */ + control.s.cam_mode = 0; + else + /* Filter packets based on the CAM */ + control.s.cam_mode = 1; + + gmx_cfg.u64 = + cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); + cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), + gmx_cfg.u64 & ~1ull); + + cvmx_write_csr(CVMX_GMXX_RXX_ADR_CTL(index, interface), + control.u64); + if (dev->flags & IFF_PROMISC) + cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM_EN + (index, interface), 0); + else + cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM_EN + (index, interface), 1); + + cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), + gmx_cfg.u64); + } +} + +/** + * Set the hardware MAC address for a device + * + * @dev: Device to change the MAC address for + * @addr: Address structure to change it too. MAC address is addr + 2. + * Returns Zero on success + */ +static int cvm_oct_common_set_mac_address(struct net_device *dev, void *addr) +{ + struct octeon_ethernet *priv = netdev_priv(dev); + union cvmx_gmxx_prtx_cfg gmx_cfg; + int interface = INTERFACE(priv->port); + int index = INDEX(priv->port); + + memcpy(dev->dev_addr, addr + 2, 6); + + if ((interface < 2) + && (cvmx_helper_interface_get_mode(interface) != + CVMX_HELPER_INTERFACE_MODE_SPI)) { + int i; + uint8_t *ptr = addr; + uint64_t mac = 0; + for (i = 0; i < 6; i++) + mac = (mac << 8) | (uint64_t) (ptr[i + 2]); + + gmx_cfg.u64 = + cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); + cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), + gmx_cfg.u64 & ~1ull); + + cvmx_write_csr(CVMX_GMXX_SMACX(index, interface), mac); + cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM0(index, interface), + ptr[2]); + cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM1(index, interface), + ptr[3]); + cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM2(index, interface), + ptr[4]); + cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM3(index, interface), + ptr[5]); + cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM4(index, interface), + ptr[6]); + cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM5(index, interface), + ptr[7]); + cvm_oct_common_set_multicast_list(dev); + cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), + gmx_cfg.u64); + } + return 0; +} + +/** + * Per network device initialization + * + * @dev: Device to initialize + * Returns Zero on success + */ +int cvm_oct_common_init(struct net_device *dev) +{ + static int count; + char mac[8] = { 0x00, 0x00, + octeon_bootinfo->mac_addr_base[0], + octeon_bootinfo->mac_addr_base[1], + octeon_bootinfo->mac_addr_base[2], + octeon_bootinfo->mac_addr_base[3], + octeon_bootinfo->mac_addr_base[4], + octeon_bootinfo->mac_addr_base[5] + count + }; + struct octeon_ethernet *priv = netdev_priv(dev); + + /* + * Force the interface to use the POW send if always_use_pow + * was specified or it is in the pow send list. + */ + if ((pow_send_group != -1) + && (always_use_pow || strstr(pow_send_list, dev->name))) + priv->queue = -1; + + if (priv->queue != -1 && USE_HW_TCPUDP_CHECKSUM) + dev->features |= NETIF_F_IP_CSUM; + + count++; + + /* We do our own locking, Linux doesn't need to */ + dev->features |= NETIF_F_LLTX; + SET_ETHTOOL_OPS(dev, &cvm_oct_ethtool_ops); + + cvm_oct_mdio_setup_device(dev); + dev->netdev_ops->ndo_set_mac_address(dev, mac); + dev->netdev_ops->ndo_change_mtu(dev, dev->mtu); + + /* + * Zero out stats for port so we won't mistakenly show + * counters from the bootloader. + */ + memset(dev->netdev_ops->ndo_get_stats(dev), 0, + sizeof(struct net_device_stats)); + + return 0; +} + +void cvm_oct_common_uninit(struct net_device *dev) +{ + /* Currently nothing to do */ +} + +static const struct net_device_ops cvm_oct_npi_netdev_ops = { + .ndo_init = cvm_oct_common_init, + .ndo_uninit = cvm_oct_common_uninit, + .ndo_start_xmit = cvm_oct_xmit, + .ndo_set_multicast_list = cvm_oct_common_set_multicast_list, + .ndo_set_mac_address = cvm_oct_common_set_mac_address, + .ndo_do_ioctl = cvm_oct_ioctl, + .ndo_change_mtu = cvm_oct_common_change_mtu, + .ndo_get_stats = cvm_oct_common_get_stats, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = cvm_oct_poll_controller, +#endif +}; +static const struct net_device_ops cvm_oct_xaui_netdev_ops = { + .ndo_init = cvm_oct_xaui_init, + .ndo_uninit = cvm_oct_xaui_uninit, + .ndo_open = cvm_oct_xaui_open, + .ndo_stop = cvm_oct_xaui_stop, + .ndo_start_xmit = cvm_oct_xmit, + .ndo_set_multicast_list = cvm_oct_common_set_multicast_list, + .ndo_set_mac_address = cvm_oct_common_set_mac_address, + .ndo_do_ioctl = cvm_oct_ioctl, + .ndo_change_mtu = cvm_oct_common_change_mtu, + .ndo_get_stats = cvm_oct_common_get_stats, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = cvm_oct_poll_controller, +#endif +}; +static const struct net_device_ops cvm_oct_sgmii_netdev_ops = { + .ndo_init = cvm_oct_sgmii_init, + .ndo_uninit = cvm_oct_sgmii_uninit, + .ndo_open = cvm_oct_sgmii_open, + .ndo_stop = cvm_oct_sgmii_stop, + .ndo_start_xmit = cvm_oct_xmit, + .ndo_set_multicast_list = cvm_oct_common_set_multicast_list, + .ndo_set_mac_address = cvm_oct_common_set_mac_address, + .ndo_do_ioctl = cvm_oct_ioctl, + .ndo_change_mtu = cvm_oct_common_change_mtu, + .ndo_get_stats = cvm_oct_common_get_stats, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = cvm_oct_poll_controller, +#endif +}; +static const struct net_device_ops cvm_oct_spi_netdev_ops = { + .ndo_init = cvm_oct_spi_init, + .ndo_uninit = cvm_oct_spi_uninit, + .ndo_start_xmit = cvm_oct_xmit, + .ndo_set_multicast_list = cvm_oct_common_set_multicast_list, + .ndo_set_mac_address = cvm_oct_common_set_mac_address, + .ndo_do_ioctl = cvm_oct_ioctl, + .ndo_change_mtu = cvm_oct_common_change_mtu, + .ndo_get_stats = cvm_oct_common_get_stats, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = cvm_oct_poll_controller, +#endif +}; +static const struct net_device_ops cvm_oct_rgmii_netdev_ops = { + .ndo_init = cvm_oct_rgmii_init, + .ndo_uninit = cvm_oct_rgmii_uninit, + .ndo_open = cvm_oct_rgmii_open, + .ndo_stop = cvm_oct_rgmii_stop, + .ndo_start_xmit = cvm_oct_xmit, + .ndo_set_multicast_list = cvm_oct_common_set_multicast_list, + .ndo_set_mac_address = cvm_oct_common_set_mac_address, + .ndo_do_ioctl = cvm_oct_ioctl, + .ndo_change_mtu = cvm_oct_common_change_mtu, + .ndo_get_stats = cvm_oct_common_get_stats, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = cvm_oct_poll_controller, +#endif +}; +static const struct net_device_ops cvm_oct_pow_netdev_ops = { + .ndo_init = cvm_oct_common_init, + .ndo_start_xmit = cvm_oct_xmit_pow, + .ndo_set_multicast_list = cvm_oct_common_set_multicast_list, + .ndo_set_mac_address = cvm_oct_common_set_mac_address, + .ndo_do_ioctl = cvm_oct_ioctl, + .ndo_change_mtu = cvm_oct_common_change_mtu, + .ndo_get_stats = cvm_oct_common_get_stats, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = cvm_oct_poll_controller, +#endif +}; + +/** + * Module/ driver initialization. Creates the linux network + * devices. + * + * Returns Zero on success + */ +static int __init cvm_oct_init_module(void) +{ + int num_interfaces; + int interface; + int fau = FAU_NUM_PACKET_BUFFERS_TO_FREE; + int qos; + + pr_notice("cavium-ethernet %s\n", OCTEON_ETHERNET_VERSION); + + cvm_oct_proc_initialize(); + cvm_oct_rx_initialize(); + cvm_oct_configure_common_hw(); + + cvmx_helper_initialize_packet_io_global(); + + /* Change the input group for all ports before input is enabled */ + num_interfaces = cvmx_helper_get_number_of_interfaces(); + for (interface = 0; interface < num_interfaces; interface++) { + int num_ports = cvmx_helper_ports_on_interface(interface); + int port; + + for (port = cvmx_helper_get_ipd_port(interface, 0); + port < cvmx_helper_get_ipd_port(interface, num_ports); + port++) { + union cvmx_pip_prt_tagx pip_prt_tagx; + pip_prt_tagx.u64 = + cvmx_read_csr(CVMX_PIP_PRT_TAGX(port)); + pip_prt_tagx.s.grp = pow_receive_group; + cvmx_write_csr(CVMX_PIP_PRT_TAGX(port), + pip_prt_tagx.u64); + } + } + + cvmx_helper_ipd_and_packet_input_enable(); + + memset(cvm_oct_device, 0, sizeof(cvm_oct_device)); + + /* + * Initialize the FAU used for counting packet buffers that + * need to be freed. + */ + cvmx_fau_atomic_write32(FAU_NUM_PACKET_BUFFERS_TO_FREE, 0); + + if ((pow_send_group != -1)) { + struct net_device *dev; + pr_info("\tConfiguring device for POW only access\n"); + dev = alloc_etherdev(sizeof(struct octeon_ethernet)); + if (dev) { + /* Initialize the device private structure. */ + struct octeon_ethernet *priv = netdev_priv(dev); + memset(priv, 0, sizeof(struct octeon_ethernet)); + + dev->netdev_ops = &cvm_oct_pow_netdev_ops; + priv->imode = CVMX_HELPER_INTERFACE_MODE_DISABLED; + priv->port = CVMX_PIP_NUM_INPUT_PORTS; + priv->queue = -1; + strcpy(dev->name, "pow%d"); + for (qos = 0; qos < 16; qos++) + skb_queue_head_init(&priv->tx_free_list[qos]); + + if (register_netdev(dev) < 0) { + pr_err("Failed to register ethernet " + "device for POW\n"); + kfree(dev); + } else { + cvm_oct_device[CVMX_PIP_NUM_INPUT_PORTS] = dev; + pr_info("%s: POW send group %d, receive " + "group %d\n", + dev->name, pow_send_group, + pow_receive_group); + } + } else { + pr_err("Failed to allocate ethernet device " + "for POW\n"); + } + } + + num_interfaces = cvmx_helper_get_number_of_interfaces(); + for (interface = 0; interface < num_interfaces; interface++) { + cvmx_helper_interface_mode_t imode = + cvmx_helper_interface_get_mode(interface); + int num_ports = cvmx_helper_ports_on_interface(interface); + int port; + + for (port = cvmx_helper_get_ipd_port(interface, 0); + port < cvmx_helper_get_ipd_port(interface, num_ports); + port++) { + struct octeon_ethernet *priv; + struct net_device *dev = + alloc_etherdev(sizeof(struct octeon_ethernet)); + if (!dev) { + pr_err("Failed to allocate ethernet device " + "for port %d\n", port); + continue; + } + if (disable_core_queueing) + dev->tx_queue_len = 0; + + /* Initialize the device private structure. */ + priv = netdev_priv(dev); + memset(priv, 0, sizeof(struct octeon_ethernet)); + + priv->imode = imode; + priv->port = port; + priv->queue = cvmx_pko_get_base_queue(priv->port); + priv->fau = fau - cvmx_pko_get_num_queues(port) * 4; + for (qos = 0; qos < 16; qos++) + skb_queue_head_init(&priv->tx_free_list[qos]); + for (qos = 0; qos < cvmx_pko_get_num_queues(port); + qos++) + cvmx_fau_atomic_write32(priv->fau + qos * 4, 0); + + switch (priv->imode) { + + /* These types don't support ports to IPD/PKO */ + case CVMX_HELPER_INTERFACE_MODE_DISABLED: + case CVMX_HELPER_INTERFACE_MODE_PCIE: + case CVMX_HELPER_INTERFACE_MODE_PICMG: + break; + + case CVMX_HELPER_INTERFACE_MODE_NPI: + dev->netdev_ops = &cvm_oct_npi_netdev_ops; + strcpy(dev->name, "npi%d"); + break; + + case CVMX_HELPER_INTERFACE_MODE_XAUI: + dev->netdev_ops = &cvm_oct_xaui_netdev_ops; + strcpy(dev->name, "xaui%d"); + break; + + case CVMX_HELPER_INTERFACE_MODE_LOOP: + dev->netdev_ops = &cvm_oct_npi_netdev_ops; + strcpy(dev->name, "loop%d"); + break; + + case CVMX_HELPER_INTERFACE_MODE_SGMII: + dev->netdev_ops = &cvm_oct_sgmii_netdev_ops; + strcpy(dev->name, "eth%d"); + break; + + case CVMX_HELPER_INTERFACE_MODE_SPI: + dev->netdev_ops = &cvm_oct_spi_netdev_ops; + strcpy(dev->name, "spi%d"); + break; + + case CVMX_HELPER_INTERFACE_MODE_RGMII: + case CVMX_HELPER_INTERFACE_MODE_GMII: + dev->netdev_ops = &cvm_oct_rgmii_netdev_ops; + strcpy(dev->name, "eth%d"); + break; + } + + if (!dev->netdev_ops) { + kfree(dev); + } else if (register_netdev(dev) < 0) { + pr_err("Failed to register ethernet device " + "for interface %d, port %d\n", + interface, priv->port); + kfree(dev); + } else { + cvm_oct_device[priv->port] = dev; + fau -= + cvmx_pko_get_num_queues(priv->port) * + sizeof(uint32_t); + } + } + } + + if (INTERRUPT_LIMIT) { + /* + * Set the POW timer rate to give an interrupt at most + * INTERRUPT_LIMIT times per second. + */ + cvmx_write_csr(CVMX_POW_WQ_INT_PC, + octeon_bootinfo->eclock_hz / (INTERRUPT_LIMIT * + 16 * 256) << 8); + + /* + * Enable POW timer interrupt. It will count when + * there are packets available. + */ + cvmx_write_csr(CVMX_POW_WQ_INT_THRX(pow_receive_group), + 0x1ful << 24); + } else { + /* Enable POW interrupt when our port has at least one packet */ + cvmx_write_csr(CVMX_POW_WQ_INT_THRX(pow_receive_group), 0x1001); + } + + /* Enable the poll timer for checking RGMII status */ + init_timer(&cvm_oct_poll_timer); + cvm_oct_poll_timer.data = 0; + cvm_oct_poll_timer.function = cvm_do_timer; + mod_timer(&cvm_oct_poll_timer, jiffies + HZ); + + return 0; +} + +/** + * Module / driver shutdown + * + * Returns Zero on success + */ +static void __exit cvm_oct_cleanup_module(void) +{ + int port; + + /* Disable POW interrupt */ + cvmx_write_csr(CVMX_POW_WQ_INT_THRX(pow_receive_group), 0); + + cvmx_ipd_disable(); + + /* Free the interrupt handler */ + free_irq(OCTEON_IRQ_WORKQ0 + pow_receive_group, cvm_oct_device); + + del_timer(&cvm_oct_poll_timer); + cvm_oct_rx_shutdown(); + cvmx_pko_disable(); + + /* Free the ethernet devices */ + for (port = 0; port < TOTAL_NUMBER_OF_PORTS; port++) { + if (cvm_oct_device[port]) { + cvm_oct_tx_shutdown(cvm_oct_device[port]); + unregister_netdev(cvm_oct_device[port]); + kfree(cvm_oct_device[port]); + cvm_oct_device[port] = NULL; + } + } + + cvmx_pko_shutdown(); + cvm_oct_proc_shutdown(); + + cvmx_ipd_free_ptr(); + + /* Free the HW pools */ + cvm_oct_mem_empty_fpa(CVMX_FPA_PACKET_POOL, CVMX_FPA_PACKET_POOL_SIZE, + num_packet_buffers); + cvm_oct_mem_empty_fpa(CVMX_FPA_WQE_POOL, CVMX_FPA_WQE_POOL_SIZE, + num_packet_buffers); + if (CVMX_FPA_OUTPUT_BUFFER_POOL != CVMX_FPA_PACKET_POOL) + cvm_oct_mem_empty_fpa(CVMX_FPA_OUTPUT_BUFFER_POOL, + CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE, 128); +} + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Cavium Networks "); +MODULE_DESCRIPTION("Cavium Networks Octeon ethernet driver."); +module_init(cvm_oct_init_module); +module_exit(cvm_oct_cleanup_module); diff --git a/drivers/staging/octeon/octeon-ethernet.h b/drivers/staging/octeon/octeon-ethernet.h new file mode 100644 index 000000000000..3aef9878fc0a --- /dev/null +++ b/drivers/staging/octeon/octeon-ethernet.h @@ -0,0 +1,138 @@ +/********************************************************************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2007 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information +**********************************************************************/ + +/* + * External interface for the Cavium Octeon ethernet driver. + */ +#ifndef OCTEON_ETHERNET_H +#define OCTEON_ETHERNET_H + +/** + * This is the definition of the Ethernet driver's private + * driver state stored in netdev_priv(dev). + */ +struct octeon_ethernet { + /* PKO hardware output port */ + int port; + /* PKO hardware queue for the port */ + int queue; + /* Hardware fetch and add to count outstanding tx buffers */ + int fau; + /* + * Type of port. This is one of the enums in + * cvmx_helper_interface_mode_t + */ + int imode; + /* List of outstanding tx buffers per queue */ + struct sk_buff_head tx_free_list[16]; + /* Device statistics */ + struct net_device_stats stats +; /* Generic MII info structure */ + struct mii_if_info mii_info; + /* Last negotiated link state */ + uint64_t link_info; + /* Called periodically to check link status */ + void (*poll) (struct net_device *dev); +}; + +/** + * Free a work queue entry received in a intercept callback. + * + * @work_queue_entry: + * Work queue entry to free + * Returns Zero on success, Negative on failure. + */ +int cvm_oct_free_work(void *work_queue_entry); + +/** + * Transmit a work queue entry out of the ethernet port. Both + * the work queue entry and the packet data can optionally be + * freed. The work will be freed on error as well. + * + * @dev: Device to transmit out. + * @work_queue_entry: + * Work queue entry to send + * @do_free: True if the work queue entry and packet data should be + * freed. If false, neither will be freed. + * @qos: Index into the queues for this port to transmit on. This + * is used to implement QoS if their are multiple queues per + * port. This parameter must be between 0 and the number of + * queues per port minus 1. Values outside of this range will + * be change to zero. + * + * Returns Zero on success, negative on failure. + */ +int cvm_oct_transmit_qos(struct net_device *dev, void *work_queue_entry, + int do_free, int qos); + +/** + * Transmit a work queue entry out of the ethernet port. Both + * the work queue entry and the packet data can optionally be + * freed. The work will be freed on error as well. This simply + * wraps cvmx_oct_transmit_qos() for backwards compatability. + * + * @dev: Device to transmit out. + * @work_queue_entry: + * Work queue entry to send + * @do_free: True if the work queue entry and packet data should be + * freed. If false, neither will be freed. + * + * Returns Zero on success, negative on failure. + */ +static inline int cvm_oct_transmit(struct net_device *dev, + void *work_queue_entry, int do_free) +{ + return cvm_oct_transmit_qos(dev, work_queue_entry, do_free, 0); +} + +extern int cvm_oct_rgmii_init(struct net_device *dev); +extern void cvm_oct_rgmii_uninit(struct net_device *dev); +extern int cvm_oct_rgmii_open(struct net_device *dev); +extern int cvm_oct_rgmii_stop(struct net_device *dev); + +extern int cvm_oct_sgmii_init(struct net_device *dev); +extern void cvm_oct_sgmii_uninit(struct net_device *dev); +extern int cvm_oct_sgmii_open(struct net_device *dev); +extern int cvm_oct_sgmii_stop(struct net_device *dev); + +extern int cvm_oct_spi_init(struct net_device *dev); +extern void cvm_oct_spi_uninit(struct net_device *dev); +extern int cvm_oct_xaui_init(struct net_device *dev); +extern void cvm_oct_xaui_uninit(struct net_device *dev); +extern int cvm_oct_xaui_open(struct net_device *dev); +extern int cvm_oct_xaui_stop(struct net_device *dev); + +extern int cvm_oct_common_init(struct net_device *dev); +extern void cvm_oct_common_uninit(struct net_device *dev); + +extern int always_use_pow; +extern int pow_send_group; +extern int pow_receive_group; +extern char pow_send_list[]; +extern struct net_device *cvm_oct_device[]; + +#endif diff --git a/drivers/staging/otus/80211core/ccmd.c b/drivers/staging/otus/80211core/ccmd.c index 479977973671..83dd8ba1328c 100644 --- a/drivers/staging/otus/80211core/ccmd.c +++ b/drivers/staging/otus/80211core/ccmd.c @@ -27,1019 +27,941 @@ #include "../hal/hpreg.h" -u16_t zfWlanReset(zdev_t* dev); -u32_t zfUpdateRxRate(zdev_t* dev); +u16_t zfWlanReset(zdev_t *dev); +u32_t zfUpdateRxRate(zdev_t *dev); extern void zfiUsbRecv(zdev_t *dev, zbuf_t *buf); -extern void zfiUsbRegIn(zdev_t* dev, u32_t* rsp, u16_t rspLen); -extern void zfiUsbOutComplete(zdev_t* dev, zbuf_t *buf, u8_t status, u8_t *hdr); -extern void zfiUsbRegOutComplete(zdev_t* dev); -extern u16_t zfHpReinit(zdev_t* dev, u32_t frequency); +extern void zfiUsbRegIn(zdev_t *dev, u32_t *rsp, u16_t rspLen); +extern void zfiUsbOutComplete(zdev_t *dev, zbuf_t *buf, u8_t status, u8_t *hdr); +extern void zfiUsbRegOutComplete(zdev_t *dev); +extern u16_t zfHpReinit(zdev_t *dev, u32_t frequency); /* Get size (byte) of driver core global data structure. */ /* This size will be used by driver wrapper to allocate */ /* a memory space for driver core to store global variables */ -u16_t zfiGlobalDataSize(zdev_t* dev) +u16_t zfiGlobalDataSize(zdev_t *dev) { - u32_t ret; - ret = (sizeof(struct zsWlanDev)); - zm_assert((ret>>16) == 0); - return (u16_t)ret; + u32_t ret; + ret = (sizeof(struct zsWlanDev)); + zm_assert((ret>>16) == 0); + return (u16_t)ret; } /* Initialize WLAN hardware and software, resource will be allocated */ /* for WLAN operation, must be called first before other function. */ -extern u16_t zfiWlanOpen(zdev_t* dev, struct zsCbFuncTbl* cbFuncTbl) +extern u16_t zfiWlanOpen(zdev_t *dev, struct zsCbFuncTbl *cbFuncTbl) { - //u16_t ret; - //u32_t i; - //u8_t* ch; - //u8_t bPassive; - u32_t devSize; - struct zfCbUsbFuncTbl cbUsbFuncTbl; - zmw_get_wlan_dev(dev); + /* u16_t ret; + u32_t i; + u8_t* ch; + u8_t bPassive; + */ + u32_t devSize; + struct zfCbUsbFuncTbl cbUsbFuncTbl; + zmw_get_wlan_dev(dev); - zm_debug_msg0("start"); + zm_debug_msg0("start"); - devSize = sizeof(struct zsWlanDev); - /* Zeroize zsWlanDev struct */ - zfZeroMemory((u8_t*)wd, (u16_t)devSize); + devSize = sizeof(struct zsWlanDev); + /* Zeroize zsWlanDev struct */ + zfZeroMemory((u8_t *)wd, (u16_t)devSize); #ifdef ZM_ENABLE_AGGREGATION - zfAggInit(dev); + zfAggInit(dev); #endif - zfCwmInit(dev); + zfCwmInit(dev); - wd->commTally.RateCtrlTxMPDU = 0; - wd->commTally.RateCtrlBAFail = 0; - wd->preambleTypeInUsed = ZM_PREAMBLE_TYPE_SHORT; + wd->commTally.RateCtrlTxMPDU = 0; + wd->commTally.RateCtrlBAFail = 0; + wd->preambleTypeInUsed = ZM_PREAMBLE_TYPE_SHORT; - if (cbFuncTbl == NULL) - { - /* zfcbRecvEth() is mandatory */ - zm_assert(0); - } - else - { - if (cbFuncTbl->zfcbRecvEth == NULL) - { - /* zfcbRecvEth() is mandatory */ - zm_assert(0); - } - wd->zfcbAuthNotify = cbFuncTbl->zfcbAuthNotify; - wd->zfcbAuthNotify = cbFuncTbl->zfcbAuthNotify; - wd->zfcbAsocNotify = cbFuncTbl->zfcbAsocNotify; - wd->zfcbDisAsocNotify = cbFuncTbl->zfcbDisAsocNotify; - wd->zfcbApConnectNotify = cbFuncTbl->zfcbApConnectNotify; - wd->zfcbConnectNotify = cbFuncTbl->zfcbConnectNotify; - wd->zfcbScanNotify = cbFuncTbl->zfcbScanNotify; - wd->zfcbMicFailureNotify = cbFuncTbl->zfcbMicFailureNotify; - wd->zfcbApMicFailureNotify = cbFuncTbl->zfcbApMicFailureNotify; - wd->zfcbIbssPartnerNotify = cbFuncTbl->zfcbIbssPartnerNotify; - wd->zfcbMacAddressNotify = cbFuncTbl->zfcbMacAddressNotify; - wd->zfcbSendCompleteIndication = cbFuncTbl->zfcbSendCompleteIndication; - wd->zfcbRecvEth = cbFuncTbl->zfcbRecvEth; - wd->zfcbRestoreBufData = cbFuncTbl->zfcbRestoreBufData; - wd->zfcbRecv80211 = cbFuncTbl->zfcbRecv80211; + if (cbFuncTbl == NULL) { + /* zfcbRecvEth() is mandatory */ + zm_assert(0); + } else { + if (cbFuncTbl->zfcbRecvEth == NULL) { + /* zfcbRecvEth() is mandatory */ + zm_assert(0); + } + wd->zfcbAuthNotify = cbFuncTbl->zfcbAuthNotify; + wd->zfcbAuthNotify = cbFuncTbl->zfcbAuthNotify; + wd->zfcbAsocNotify = cbFuncTbl->zfcbAsocNotify; + wd->zfcbDisAsocNotify = cbFuncTbl->zfcbDisAsocNotify; + wd->zfcbApConnectNotify = cbFuncTbl->zfcbApConnectNotify; + wd->zfcbConnectNotify = cbFuncTbl->zfcbConnectNotify; + wd->zfcbScanNotify = cbFuncTbl->zfcbScanNotify; + wd->zfcbMicFailureNotify = cbFuncTbl->zfcbMicFailureNotify; + wd->zfcbApMicFailureNotify = cbFuncTbl->zfcbApMicFailureNotify; + wd->zfcbIbssPartnerNotify = cbFuncTbl->zfcbIbssPartnerNotify; + wd->zfcbMacAddressNotify = cbFuncTbl->zfcbMacAddressNotify; + wd->zfcbSendCompleteIndication = + cbFuncTbl->zfcbSendCompleteIndication; + wd->zfcbRecvEth = cbFuncTbl->zfcbRecvEth; + wd->zfcbRestoreBufData = cbFuncTbl->zfcbRestoreBufData; + wd->zfcbRecv80211 = cbFuncTbl->zfcbRecv80211; #ifdef ZM_ENABLE_CENC - wd->zfcbCencAsocNotify = cbFuncTbl->zfcbCencAsocNotify; -#endif //ZM_ENABLE_CENC - wd->zfcbClassifyTxPacket = cbFuncTbl->zfcbClassifyTxPacket; - wd->zfcbHwWatchDogNotify = cbFuncTbl->zfcbHwWatchDogNotify; - } + wd->zfcbCencAsocNotify = cbFuncTbl->zfcbCencAsocNotify; +#endif /* ZM_ENABLE_CENC */ + wd->zfcbClassifyTxPacket = cbFuncTbl->zfcbClassifyTxPacket; + wd->zfcbHwWatchDogNotify = cbFuncTbl->zfcbHwWatchDogNotify; + } - //add by honda 0330 - cbUsbFuncTbl.zfcbUsbRecv = zfiUsbRecv; - cbUsbFuncTbl.zfcbUsbRegIn = zfiUsbRegIn; - cbUsbFuncTbl.zfcbUsbOutComplete = zfiUsbOutComplete; - cbUsbFuncTbl.zfcbUsbRegOutComplete = zfiUsbRegOutComplete; - zfwUsbRegisterCallBack(dev, &cbUsbFuncTbl); - /* Init OWN MAC address */ - wd->macAddr[0] = 0x8000; - wd->macAddr[1] = 0x0000; - wd->macAddr[2] = 0x0000; + /* add by honda 0330 */ + cbUsbFuncTbl.zfcbUsbRecv = zfiUsbRecv; + cbUsbFuncTbl.zfcbUsbRegIn = zfiUsbRegIn; + cbUsbFuncTbl.zfcbUsbOutComplete = zfiUsbOutComplete; + cbUsbFuncTbl.zfcbUsbRegOutComplete = zfiUsbRegOutComplete; + zfwUsbRegisterCallBack(dev, &cbUsbFuncTbl); + /* Init OWN MAC address */ + wd->macAddr[0] = 0x8000; + wd->macAddr[1] = 0x0000; + wd->macAddr[2] = 0x0000; - wd->regulationTable.regionCode = 0xffff; + wd->regulationTable.regionCode = 0xffff; - zfHpInit(dev, wd->frequency); + zfHpInit(dev, wd->frequency); - /* init region code */ - //wd->regulationTable.regionCode = NULL1_WORLD; //Only 2.4g RegCode - //zfHpGetRegulationTablefromRegionCode(dev, NULL1_WORLD); - //zfiWlanSetDot11DMode(dev , 1); // Enable 802.11d - /* Get the first channel */ - //wd->frequency = zfChGetFirstChannel(dev, &bPassive); + /* init region code */ + /* wd->regulationTable.regionCode = NULL1_WORLD; //Only 2.4g RegCode */ + /* zfHpGetRegulationTablefromRegionCode(dev, NULL1_WORLD); */ + /* zfiWlanSetDot11DMode(dev , 1); //Enable 802.11d */ + /* Get the first channel */ + /* wd->frequency = zfChGetFirstChannel(dev, &bPassive); */ #ifdef ZM_AP_DEBUG - //wd->frequency = 2437; + /* wd->frequency = 2437; */ #endif - //STA mode - wd->sta.mTxRate = 0x0; - wd->sta.uTxRate = 0x3; - wd->sta.mmTxRate = 0x0; - wd->sta.adapterState = ZM_STA_STATE_DISCONNECT; - wd->sta.capability[0] = 0x01; - wd->sta.capability[1] = 0x00; + /* STA mode */ + wd->sta.mTxRate = 0x0; + wd->sta.uTxRate = 0x3; + wd->sta.mmTxRate = 0x0; + wd->sta.adapterState = ZM_STA_STATE_DISCONNECT; + wd->sta.capability[0] = 0x01; + wd->sta.capability[1] = 0x00; - wd->sta.preambleTypeHT = 0; - wd->sta.htCtrlBandwidth = 0; - wd->sta.htCtrlSTBC = 0; - wd->sta.htCtrlSG = 0; - wd->sta.defaultTA = 0; - //wd->sta.activescanTickPerChannel = ZM_TIME_ACTIVE_SCAN/ZM_MS_PER_TICK; + wd->sta.preambleTypeHT = 0; + wd->sta.htCtrlBandwidth = 0; + wd->sta.htCtrlSTBC = 0; + wd->sta.htCtrlSG = 0; + wd->sta.defaultTA = 0; + /*wd->sta.activescanTickPerChannel = + *ZM_TIME_ACTIVE_SCAN/ZM_MS_PER_TICK; + */ { u8_t Dur = ZM_TIME_ACTIVE_SCAN; zfwGetActiveScanDur(dev, &Dur); - wd->sta.activescanTickPerChannel = Dur/ZM_MS_PER_TICK; + wd->sta.activescanTickPerChannel = Dur / ZM_MS_PER_TICK; } - wd->sta.passiveScanTickPerChannel = ZM_TIME_PASSIVE_SCAN/ZM_MS_PER_TICK; - wd->sta.bAutoReconnect = TRUE; - wd->sta.dropUnencryptedPkts = FALSE; + wd->sta.passiveScanTickPerChannel = ZM_TIME_PASSIVE_SCAN/ZM_MS_PER_TICK; + wd->sta.bAutoReconnect = TRUE; + wd->sta.dropUnencryptedPkts = FALSE; - /* set default to bypass all multicast packet for linux, window XP would set 0 by wrapper initialization */ + /* set default to bypass all multicast packet for linux, + * window XP would set 0 by wrapper initialization + */ wd->sta.bAllMulticast = 1; - /* Initial the RIFS Status / RIFS-like frame count / RIFS count */ - wd->sta.rifsState = ZM_RIFS_STATE_DETECTING; - wd->sta.rifsLikeFrameCnt = 0; - wd->sta.rifsCount = 0; + /* Initial the RIFS Status / RIFS-like frame count / RIFS count */ + wd->sta.rifsState = ZM_RIFS_STATE_DETECTING; + wd->sta.rifsLikeFrameCnt = 0; + wd->sta.rifsCount = 0; - wd->sta.osRxFilter = 0; - wd->sta.bSafeMode = 0; + wd->sta.osRxFilter = 0; + wd->sta.bSafeMode = 0; - //Common - zfResetSupportRate(dev, ZM_DEFAULT_SUPPORT_RATE_DISCONNECT); - wd->beaconInterval = 100; - wd->rtsThreshold = 2346; - wd->fragThreshold = 32767; - wd->wlanMode = ZM_MODE_INFRASTRUCTURE; - wd->txMCS = 0xff; //AUTO - wd->dtim = 1; - //wd->txMT = 1; //OFDM - wd->tick = 1; - wd->maxTxPower2 = 0xff; - wd->maxTxPower5 = 0xff; - wd->supportMode = 0xffffffff; - wd->ws.adhocMode = ZM_ADHOCBAND_G; - wd->ws.autoSetFrequency = 0xff; + /* Common */ + zfResetSupportRate(dev, ZM_DEFAULT_SUPPORT_RATE_DISCONNECT); + wd->beaconInterval = 100; + wd->rtsThreshold = 2346; + wd->fragThreshold = 32767; + wd->wlanMode = ZM_MODE_INFRASTRUCTURE; + wd->txMCS = 0xff; /* AUTO */ + wd->dtim = 1; + /* wd->txMT = 1; *//*OFDM */ + wd->tick = 1; + wd->maxTxPower2 = 0xff; + wd->maxTxPower5 = 0xff; + wd->supportMode = 0xffffffff; + wd->ws.adhocMode = ZM_ADHOCBAND_G; + wd->ws.autoSetFrequency = 0xff; - //AP mode - //wd->bgMode = wd->ws.bgMode; - wd->ap.ssidLen[0] = 6; - wd->ap.ssid[0][0] = 'Z'; - wd->ap.ssid[0][1] = 'D'; - wd->ap.ssid[0][2] = '1'; - wd->ap.ssid[0][3] = '2'; - wd->ap.ssid[0][4] = '2'; - wd->ap.ssid[0][5] = '1'; + /* AP mode */ + /* wd->bgMode = wd->ws.bgMode; */ + wd->ap.ssidLen[0] = 6; + wd->ap.ssid[0][0] = 'Z'; + wd->ap.ssid[0][1] = 'D'; + wd->ap.ssid[0][2] = '1'; + wd->ap.ssid[0][3] = '2'; + wd->ap.ssid[0][4] = '2'; + wd->ap.ssid[0][5] = '1'; - // Init the country iso name as NA - wd->ws.countryIsoName[0] = 0; - wd->ws.countryIsoName[1] = 0; - wd->ws.countryIsoName[2] = '\0'; + /* Init the country iso name as NA */ + wd->ws.countryIsoName[0] = 0; + wd->ws.countryIsoName[1] = 0; + wd->ws.countryIsoName[2] = '\0'; /* init fragmentation is disabled */ - //zfiWlanSetFragThreshold(dev, 0); + /* zfiWlanSetFragThreshold(dev, 0); */ /* airopeek : swSniffer 1=>on 0=>off */ wd->swSniffer = 0; - wd->XLinkMode = 0; + wd->XLinkMode = 0; -// jhlee HT 0 + /* jhlee HT 0 */ #if 1 - /* AP Mode*/ - /* Init HT Capability Info */ - wd->ap.HTCap.Data.ElementID = ZM_WLAN_EID_HT_CAPABILITY; - wd->ap.HTCap.Data.Length = 26; - //wd->ap.HTCap.Data.SupChannelWidthSet = 0; - //wd->ap.HTCap.Data.MIMOPowerSave = 3; - //wd->ap.HTCap.Data.ShortGIfor40MHz = 0; - //wd->ap.HTCap.Data.ShortGIfor20MHz = 0; - //wd->ap.HTCap.Data.DSSSandCCKin40MHz = 0; - wd->ap.HTCap.Data.AMPDUParam |= HTCAP_MaxRxAMPDU3; - wd->ap.HTCap.Data.MCSSet[0] = 0xFF; // MCS 0 ~ 7 - wd->ap.HTCap.Data.MCSSet[1] = 0xFF; // MCS 8 ~ 15 + /* AP Mode*/ + /* Init HT Capability Info */ + wd->ap.HTCap.Data.ElementID = ZM_WLAN_EID_HT_CAPABILITY; + wd->ap.HTCap.Data.Length = 26; + /*wd->ap.HTCap.Data.SupChannelWidthSet = 0; + wd->ap.HTCap.Data.MIMOPowerSave = 3; + wd->ap.HTCap.Data.ShortGIfor40MHz = 0; + wd->ap.HTCap.Data.ShortGIfor20MHz = 0; + wd->ap.HTCap.Data.DSSSandCCKin40MHz = 0; + */ + wd->ap.HTCap.Data.AMPDUParam |= HTCAP_MaxRxAMPDU3; + wd->ap.HTCap.Data.MCSSet[0] = 0xFF; /* MCS 0 ~ 7 */ + wd->ap.HTCap.Data.MCSSet[1] = 0xFF; /* MCS 8 ~ 15 */ - /* Init Extended HT Capability Info */ - wd->ap.ExtHTCap.Data.ElementID = ZM_WLAN_EID_EXTENDED_HT_CAPABILITY; - wd->ap.ExtHTCap.Data.Length = 22; - wd->ap.ExtHTCap.Data.ControlChannel = 6; - //wd->ap.ExtHTCap.Data.ExtChannelOffset = 3; - wd->ap.ExtHTCap.Data.ChannelInfo |= ExtHtCap_RecomTxWidthSet; - //wd->ap.ExtHTCap.Data.RIFSMode = 1; - wd->ap.ExtHTCap.Data.OperatingInfo |= 1; + /* Init Extended HT Capability Info */ + wd->ap.ExtHTCap.Data.ElementID = ZM_WLAN_EID_EXTENDED_HT_CAPABILITY; + wd->ap.ExtHTCap.Data.Length = 22; + wd->ap.ExtHTCap.Data.ControlChannel = 6; + /* wd->ap.ExtHTCap.Data.ExtChannelOffset = 3; */ + wd->ap.ExtHTCap.Data.ChannelInfo |= ExtHtCap_RecomTxWidthSet; + /* wd->ap.ExtHTCap.Data.RIFSMode = 1; */ + wd->ap.ExtHTCap.Data.OperatingInfo |= 1; - /* STA Mode*/ - /* Init HT Capability Info */ - wd->sta.HTCap.Data.ElementID = ZM_WLAN_EID_HT_CAPABILITY; - wd->sta.HTCap.Data.Length = 26; + /* STA Mode*/ + /* Init HT Capability Info */ + wd->sta.HTCap.Data.ElementID = ZM_WLAN_EID_HT_CAPABILITY; + wd->sta.HTCap.Data.Length = 26; - /* Test with 5G-AP : 7603 */ - //wd->sta.HTCap.Data.SupChannelWidthSet = 1; - wd->sta.HTCap.Data.HtCapInfo |= HTCAP_SMEnabled; - wd->sta.HTCap.Data.HtCapInfo |= HTCAP_SupChannelWidthSet; - wd->sta.HTCap.Data.HtCapInfo |= HTCAP_ShortGIfor40MHz; - wd->sta.HTCap.Data.HtCapInfo |= HTCAP_DSSSandCCKin40MHz; + /* Test with 5G-AP : 7603 */ + /* wd->sta.HTCap.Data.SupChannelWidthSet = 1; */ + wd->sta.HTCap.Data.HtCapInfo |= HTCAP_SMEnabled; + wd->sta.HTCap.Data.HtCapInfo |= HTCAP_SupChannelWidthSet; + wd->sta.HTCap.Data.HtCapInfo |= HTCAP_ShortGIfor40MHz; + wd->sta.HTCap.Data.HtCapInfo |= HTCAP_DSSSandCCKin40MHz; #ifndef ZM_DISABLE_AMSDU8K_SUPPORT - wd->sta.HTCap.Data.HtCapInfo |= HTCAP_MaxAMSDULength; + wd->sta.HTCap.Data.HtCapInfo |= HTCAP_MaxAMSDULength; #endif - //wd->sta.HTCap.Data.MIMOPowerSave = 0; - //wd->sta.HTCap.Data.ShortGIfor40MHz = 0; - //wd->sta.HTCap.Data.ShortGIfor20MHz = 0; - //wd->sta.HTCap.Data.DSSSandCCKin40MHz = 0; - wd->sta.HTCap.Data.AMPDUParam |= HTCAP_MaxRxAMPDU3; - wd->sta.HTCap.Data.MCSSet[0] = 0xFF; // MCS 0 ~ 7 - wd->sta.HTCap.Data.MCSSet[1] = 0xFF; // MCS 8 ~ 15 - wd->sta.HTCap.Data.PCO |= HTCAP_TransmissionTime3; - //wd->sta.HTCap.Data.TransmissionTime = 0; - /* Init Extended HT Capability Info */ - wd->sta.ExtHTCap.Data.ElementID = ZM_WLAN_EID_EXTENDED_HT_CAPABILITY; - wd->sta.ExtHTCap.Data.Length = 22; - wd->sta.ExtHTCap.Data.ControlChannel = 6; + /*wd->sta.HTCap.Data.MIMOPowerSave = 0; + wd->sta.HTCap.Data.ShortGIfor40MHz = 0; + wd->sta.HTCap.Data.ShortGIfor20MHz = 0; + wd->sta.HTCap.Data.DSSSandCCKin40MHz = 0; + */ + wd->sta.HTCap.Data.AMPDUParam |= HTCAP_MaxRxAMPDU3; + wd->sta.HTCap.Data.MCSSet[0] = 0xFF; /* MCS 0 ~ 7 */ + wd->sta.HTCap.Data.MCSSet[1] = 0xFF; /* MCS 8 ~ 15 */ + wd->sta.HTCap.Data.PCO |= HTCAP_TransmissionTime3; + /* wd->sta.HTCap.Data.TransmissionTime = 0; */ + /* Init Extended HT Capability Info */ + wd->sta.ExtHTCap.Data.ElementID = ZM_WLAN_EID_EXTENDED_HT_CAPABILITY; + wd->sta.ExtHTCap.Data.Length = 22; + wd->sta.ExtHTCap.Data.ControlChannel = 6; - //wd->sta.ExtHTCap.Data.ExtChannelOffset |= 3; - wd->sta.ExtHTCap.Data.ChannelInfo |= ExtHtCap_ExtChannelOffsetBelow; + /* wd->sta.ExtHTCap.Data.ExtChannelOffset |= 3; */ + wd->sta.ExtHTCap.Data.ChannelInfo |= ExtHtCap_ExtChannelOffsetBelow; - //wd->sta.ExtHTCap.Data.RecomTxWidthSet = 1; - //wd->sta.ExtHTCap.Data.RIFSMode = 1; - wd->sta.ExtHTCap.Data.OperatingInfo |= 1; + /* wd->sta.ExtHTCap.Data.RecomTxWidthSet = 1; */ + /* wd->sta.ExtHTCap.Data.RIFSMode = 1; */ + wd->sta.ExtHTCap.Data.OperatingInfo |= 1; #endif #if 0 - /* WME test code */ - wd->ap.qosMode[0] = 1; + /* WME test code */ + wd->ap.qosMode[0] = 1; #endif - wd->ledStruct.ledMode[0] = 0x2221; - wd->ledStruct.ledMode[1] = 0x2221; + wd->ledStruct.ledMode[0] = 0x2221; + wd->ledStruct.ledMode[1] = 0x2221; - zfTimerInit(dev); + zfTimerInit(dev); - ZM_PERFORMANCE_INIT(dev); + ZM_PERFORMANCE_INIT(dev); - zfBssInfoCreate(dev); - zfScanMgrInit(dev); - zfPowerSavingMgrInit(dev); + zfBssInfoCreate(dev); + zfScanMgrInit(dev); + zfPowerSavingMgrInit(dev); #if 0 - /* Test code */ - { - u32_t key[4] = {0xffffffff, 0xff, 0, 0}; - u16_t addr[3] = {0x8000, 0x01ab, 0x0000}; - //zfSetKey(dev, 0, 0, ZM_WEP64, addr, key); - //zfSetKey(dev, 0, 0, ZM_AES, addr, key); - //zfSetKey(dev, 64, 0, 1, wd->macAddr, key); - } + /* Test code */ + { + u32_t key[4] = {0xffffffff, 0xff, 0, 0}; + u16_t addr[3] = {0x8000, 0x01ab, 0x0000}; + /*zfSetKey(dev, 0, 0, ZM_WEP64, addr, key); + zfSetKey(dev, 0, 0, ZM_AES, addr, key); + zfSetKey(dev, 64, 0, 1, wd->macAddr, key); + */ + } #endif - // WME settings - wd->ws.staWmeEnabled = 1; // Enable WME by default - #define ZM_UAPSD_Q_SIZE 32 //2^N - wd->ap.uapsdQ = zfQueueCreate(dev, ZM_UAPSD_Q_SIZE); - zm_assert(wd->ap.uapsdQ != NULL); - wd->sta.uapsdQ = zfQueueCreate(dev, ZM_UAPSD_Q_SIZE); - zm_assert(wd->sta.uapsdQ != NULL); + /* WME settings */ + wd->ws.staWmeEnabled = 1; /* Enable WME by default */ +#define ZM_UAPSD_Q_SIZE 32 /* 2^N */ + wd->ap.uapsdQ = zfQueueCreate(dev, ZM_UAPSD_Q_SIZE); + zm_assert(wd->ap.uapsdQ != NULL); + wd->sta.uapsdQ = zfQueueCreate(dev, ZM_UAPSD_Q_SIZE); + zm_assert(wd->sta.uapsdQ != NULL); - //zfHpInit(dev, wd->frequency); + /* zfHpInit(dev, wd->frequency); */ - /* MAC address */ - //zfHpSetMacAddress(dev, wd->macAddr, 0); - zfHpGetMacAddress(dev); + /* MAC address */ + /* zfHpSetMacAddress(dev, wd->macAddr, 0); */ + zfHpGetMacAddress(dev); - zfCoreSetFrequency(dev, wd->frequency); + zfCoreSetFrequency(dev, wd->frequency); #if ZM_PCI_LOOP_BACK == 1 - zfwWriteReg(dev, ZM_REG_PCI_CONTROL, 6); + zfwWriteReg(dev, ZM_REG_PCI_CONTROL, 6); #endif /* #if ZM_PCI_LOOP_BACK == 1 */ - //zfiWlanSetDot11DMode(dev , 1); // Enable 802.11d - //zfiWlanSetDot11HDFSMode(dev , 1); // Enable 802.11h DFS - wd->sta.DFSEnable = 1; - wd->sta.capability[1] |= ZM_BIT_0; + /* zfiWlanSetDot11DMode(dev , 1); // Enable 802.11d */ + /* zfiWlanSetDot11HDFSMode(dev , 1); // Enable 802.11h DFS */ + wd->sta.DFSEnable = 1; + wd->sta.capability[1] |= ZM_BIT_0; - //zfiWlanSetFrequency(dev, 5260000, TRUE); - //zfiWlanSetAniMode(dev , 1); // Enable ANI + /* zfiWlanSetFrequency(dev, 5260000, TRUE); */ + /* zfiWlanSetAniMode(dev , 1); // Enable ANI */ - /* Trgger Rx DMA */ - zfHpStartRecv(dev); + /* Trgger Rx DMA */ + zfHpStartRecv(dev); - zm_debug_msg0("end"); + zm_debug_msg0("end"); - return 0; + return 0; } /* WLAN hardware will be shutdown and all resource will be release */ -u16_t zfiWlanClose(zdev_t* dev) +u16_t zfiWlanClose(zdev_t *dev) { - zmw_get_wlan_dev(dev); + zmw_get_wlan_dev(dev); - zm_msg0_init(ZM_LV_0, "enter"); + zm_msg0_init(ZM_LV_0, "enter"); - wd->state = ZM_WLAN_STATE_CLOSEDED; + wd->state = ZM_WLAN_STATE_CLOSEDED; - //zfiWlanDisable(dev, 1); - zfWlanReset(dev); + /* zfiWlanDisable(dev, 1); */ + zfWlanReset(dev); - zfHpStopRecv(dev); + zfHpStopRecv(dev); - /* Disable MAC */ - /* Disable PHY */ - /* Disable RF */ + /* Disable MAC */ + /* Disable PHY */ + /* Disable RF */ - zfHpRelease(dev); + zfHpRelease(dev); - zfQueueDestroy(dev, wd->ap.uapsdQ); - zfQueueDestroy(dev, wd->sta.uapsdQ); + zfQueueDestroy(dev, wd->ap.uapsdQ); + zfQueueDestroy(dev, wd->sta.uapsdQ); - zfBssInfoDestroy(dev); + zfBssInfoDestroy(dev); #ifdef ZM_ENABLE_AGGREGATION - /* add by honda */ - zfAggRxFreeBuf(dev, 1); //1 for release structure memory - /* end of add by honda */ + /* add by honda */ + zfAggRxFreeBuf(dev, 1); /* 1 for release structure memory */ + /* end of add by honda */ #endif - zm_msg0_init(ZM_LV_0, "exit"); + zm_msg0_init(ZM_LV_0, "exit"); - return 0; + return 0; } -void zfGetWrapperSetting(zdev_t* dev) +void zfGetWrapperSetting(zdev_t *dev) { - u8_t bPassive; - u16_t vapId = 0; + u8_t bPassive; + u16_t vapId = 0; - zmw_get_wlan_dev(dev); + zmw_get_wlan_dev(dev); - zmw_declare_for_critical_section(); + zmw_declare_for_critical_section(); #if 0 - if ( (wd->ws.countryIsoName[0] != 0) - || (wd->ws.countryIsoName[1] != 0) - || (wd->ws.countryIsoName[2] != '\0') ) - { - zfHpGetRegulationTablefromRegionCode( - dev, - zfHpGetRegionCodeFromIsoName(dev, wd->ws.countryIsoName) ); - } + if ((wd->ws.countryIsoName[0] != 0) + || (wd->ws.countryIsoName[1] != 0) + || (wd->ws.countryIsoName[2] != '\0')) { + zfHpGetRegulationTablefromRegionCode(dev, + zfHpGetRegionCodeFromIsoName(dev, wd->ws.countryIsoName)); + } #endif - zmw_enter_critical_section(dev); + zmw_enter_critical_section(dev); - wd->wlanMode = wd->ws.wlanMode; + wd->wlanMode = wd->ws.wlanMode; - /* set channel */ - if ( wd->ws.frequency ) - { - wd->frequency = wd->ws.frequency; - wd->ws.frequency = 0; - } - else - { - wd->frequency = zfChGetFirstChannel(dev, &bPassive); + /* set channel */ + if (wd->ws.frequency) { + wd->frequency = wd->ws.frequency; + wd->ws.frequency = 0; + } else { + wd->frequency = zfChGetFirstChannel(dev, &bPassive); - if ( wd->wlanMode == ZM_MODE_IBSS ) - { - if (wd->ws.adhocMode == ZM_ADHOCBAND_A) - { - wd->frequency = ZM_CH_A_36; - } - else - { - wd->frequency = ZM_CH_G_6; - } - } - } + if (wd->wlanMode == ZM_MODE_IBSS) { + if (wd->ws.adhocMode == ZM_ADHOCBAND_A) + wd->frequency = ZM_CH_A_36; + else + wd->frequency = ZM_CH_G_6; + } + } #ifdef ZM_AP_DEBUG - /* honda add for debug, 2437 channel 6, 2452 channel 9 */ - wd->frequency = 2437; - /* end of add by honda */ + /* honda add for debug, 2437 channel 6, 2452 channel 9 */ + wd->frequency = 2437; + /* end of add by honda */ #endif - /* set preamble type */ - switch (wd->ws.preambleType) - { - case ZM_PREAMBLE_TYPE_AUTO: - case ZM_PREAMBLE_TYPE_SHORT: - case ZM_PREAMBLE_TYPE_LONG: - wd->preambleType = wd->ws.preambleType; - break; - default: - wd->preambleType = ZM_PREAMBLE_TYPE_SHORT; - break; - } - wd->ws.preambleType = 0; + /* set preamble type */ + switch (wd->ws.preambleType) { + case ZM_PREAMBLE_TYPE_AUTO: + case ZM_PREAMBLE_TYPE_SHORT: + case ZM_PREAMBLE_TYPE_LONG: + wd->preambleType = wd->ws.preambleType; + break; + default: + wd->preambleType = ZM_PREAMBLE_TYPE_SHORT; + break; + } + wd->ws.preambleType = 0; - if ( wd->wlanMode == ZM_MODE_AP ) - { - vapId = zfwGetVapId(dev); + if (wd->wlanMode == ZM_MODE_AP) { + vapId = zfwGetVapId(dev); - if (vapId == 0xffff) - { - wd->ap.authAlgo[0] = wd->ws.authMode; - wd->ap.encryMode[0] = wd->ws.encryMode; - } - else - { - wd->ap.authAlgo[vapId + 1] = wd->ws.authMode; - wd->ap.encryMode[vapId + 1] = wd->ws.encryMode; - } - wd->ws.authMode = 0; - wd->ws.encryMode = ZM_NO_WEP; + if (vapId == 0xffff) { + wd->ap.authAlgo[0] = wd->ws.authMode; + wd->ap.encryMode[0] = wd->ws.encryMode; + } else { + wd->ap.authAlgo[vapId + 1] = wd->ws.authMode; + wd->ap.encryMode[vapId + 1] = wd->ws.encryMode; + } + wd->ws.authMode = 0; + wd->ws.encryMode = ZM_NO_WEP; - /* Get beaconInterval from WrapperSetting */ - if ((wd->ws.beaconInterval >= 20) && (wd->ws.beaconInterval <= 1000)) - { - wd->beaconInterval = wd->ws.beaconInterval; - } - else - { - wd->beaconInterval = 100; //100ms - } + /* Get beaconInterval from WrapperSetting */ + if ((wd->ws.beaconInterval >= 20) && + (wd->ws.beaconInterval <= 1000)) + wd->beaconInterval = wd->ws.beaconInterval; + else + wd->beaconInterval = 100; /* 100ms */ - if (wd->ws.dtim > 0) - { - wd->dtim = wd->ws.dtim; - } - else - { - wd->dtim = 1; - } + if (wd->ws.dtim > 0) + wd->dtim = wd->ws.dtim; + else + wd->dtim = 1; - wd->ap.qosMode = wd->ws.apWmeEnabled & 0x1; - wd->ap.uapsdEnabled = (wd->ws.apWmeEnabled & 0x2) >> 1; - } - else - { - wd->sta.authMode = wd->ws.authMode; - wd->sta.currentAuthMode = wd->ws.authMode; - wd->sta.wepStatus = wd->ws.wepStatus; - if ( wd->ws.beaconInterval ) - { - wd->beaconInterval = wd->ws.beaconInterval; - } - else - { - wd->beaconInterval = 0x64; - } + wd->ap.qosMode = wd->ws.apWmeEnabled & 0x1; + wd->ap.uapsdEnabled = (wd->ws.apWmeEnabled & 0x2) >> 1; + } else { + wd->sta.authMode = wd->ws.authMode; + wd->sta.currentAuthMode = wd->ws.authMode; + wd->sta.wepStatus = wd->ws.wepStatus; - if ( wd->wlanMode == ZM_MODE_IBSS ) - { - /* 1. Set default channel 6 (2437MHz) */ -// wd->frequency = 2437; + if (wd->ws.beaconInterval) + wd->beaconInterval = wd->ws.beaconInterval; + else + wd->beaconInterval = 0x64; - /* 2. Otus support 802.11g Mode */ - if ((wd->ws.adhocMode == ZM_ADHOCBAND_G) || - (wd->ws.adhocMode == ZM_ADHOCBAND_BG) || - (wd->ws.adhocMode == ZM_ADHOCBAND_ABG) ) { - wd->wfc.bIbssGMode = 1; - } else { - wd->wfc.bIbssGMode = 0; - } + if (wd->wlanMode == ZM_MODE_IBSS) { + /* 1. Set default channel 6 (2437MHz) */ + /* wd->frequency = 2437; */ - /* 3. set short preamble */ - //wd->sta.preambleType = ZM_PREAMBLE_TYPE_SHORT ; - } + /* 2. Otus support 802.11g Mode */ + if ((wd->ws.adhocMode == ZM_ADHOCBAND_G) || + (wd->ws.adhocMode == ZM_ADHOCBAND_BG) || + (wd->ws.adhocMode == ZM_ADHOCBAND_ABG)) + wd->wfc.bIbssGMode = 1; + else + wd->wfc.bIbssGMode = 0; - /* set ATIM window */ - if ( wd->ws.atimWindow ) - { - wd->sta.atimWindow = wd->ws.atimWindow; - } - else - { - //wd->sta.atimWindow = 0x0a; - wd->sta.atimWindow = 0; - } + /* 3. set short preamble */ + /* wd->sta.preambleType = ZM_PREAMBLE_TYPE_SHORT; */ + } - //wd->sta.connectingHiddenAP = 1;//wd->ws.connectingHiddenAP; - wd->sta.dropUnencryptedPkts = wd->ws.dropUnencryptedPkts; - wd->sta.ibssJoinOnly = wd->ws.ibssJoinOnly; + /* set ATIM window */ + if (wd->ws.atimWindow) + wd->sta.atimWindow = wd->ws.atimWindow; + else { + /* wd->sta.atimWindow = 0x0a; */ + wd->sta.atimWindow = 0; + } - if ( wd->ws.bDesiredBssid ) - { - zfMemoryCopy(wd->sta.desiredBssid, wd->ws.desiredBssid, 6); - wd->sta.bDesiredBssid = TRUE; - wd->ws.bDesiredBssid = FALSE; - } - else - { - wd->sta.bDesiredBssid = FALSE; - } + /* wd->sta.connectingHiddenAP = 1; + wd->ws.connectingHiddenAP; + */ + wd->sta.dropUnencryptedPkts = wd->ws.dropUnencryptedPkts; + wd->sta.ibssJoinOnly = wd->ws.ibssJoinOnly; - /* check ssid */ - if ( wd->ws.ssidLen != 0 ) - { - if ( (!zfMemoryIsEqual(wd->ws.ssid, wd->sta.ssid, - wd->sta.ssidLen))|| - (wd->ws.ssidLen != wd->sta.ssidLen)|| - (wd->sta.authMode == ZM_AUTH_MODE_WPA)|| - (wd->sta.authMode == ZM_AUTH_MODE_WPAPSK) || - (wd->ws.staWmeQosInfo!= 0) ) - { - /*if u-APSD test(set QosInfo), clear connectByReasso to do association (not reassociation)*/ - wd->sta.connectByReasso = FALSE; - wd->sta.failCntOfReasso = 0; - wd->sta.pmkidInfo.bssidCount = 0; + if (wd->ws.bDesiredBssid) { + zfMemoryCopy(wd->sta.desiredBssid, + wd->ws.desiredBssid, 6); + wd->sta.bDesiredBssid = TRUE; + wd->ws.bDesiredBssid = FALSE; + } else + wd->sta.bDesiredBssid = FALSE; - wd->sta.ssidLen = wd->ws.ssidLen; - zfMemoryCopy(wd->sta.ssid, wd->ws.ssid, wd->sta.ssidLen); + /* check ssid */ + if (wd->ws.ssidLen != 0) { + if ((!zfMemoryIsEqual(wd->ws.ssid, wd->sta.ssid, + wd->sta.ssidLen)) || + (wd->ws.ssidLen != wd->sta.ssidLen) || + (wd->sta.authMode == ZM_AUTH_MODE_WPA) || + (wd->sta.authMode == ZM_AUTH_MODE_WPAPSK) || + (wd->ws.staWmeQosInfo != 0)) { + /* if u-APSD test(set QosInfo), clear + connectByReasso to do association + (not reassociation) + */ + wd->sta.connectByReasso = FALSE; + wd->sta.failCntOfReasso = 0; + wd->sta.pmkidInfo.bssidCount = 0; - if ( wd->sta.ssidLen < 32 ) - { - wd->sta.ssid[wd->sta.ssidLen] = 0; - } - } - } - else - { /* ANY BSS */ - wd->sta.ssid[0] = 0; - wd->sta.ssidLen = 0; - } + wd->sta.ssidLen = wd->ws.ssidLen; + zfMemoryCopy(wd->sta.ssid, wd->ws.ssid, + wd->sta.ssidLen); - wd->sta.wmeEnabled = wd->ws.staWmeEnabled; - wd->sta.wmeQosInfo = wd->ws.staWmeQosInfo; + if (wd->sta.ssidLen < 32) + wd->sta.ssid[wd->sta.ssidLen] = 0; + } + } else { + /* ANY BSS */ + wd->sta.ssid[0] = 0; + wd->sta.ssidLen = 0; + } - } + wd->sta.wmeEnabled = wd->ws.staWmeEnabled; + wd->sta.wmeQosInfo = wd->ws.staWmeQosInfo; - zmw_leave_critical_section(dev); + } + + zmw_leave_critical_section(dev); } -u16_t zfWlanEnable(zdev_t* dev) +u16_t zfWlanEnable(zdev_t *dev) { - u8_t bssid[6] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; - u16_t i; + u8_t bssid[6] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; + u16_t i; - zmw_get_wlan_dev(dev); + zmw_get_wlan_dev(dev); - zmw_declare_for_critical_section(); + zmw_declare_for_critical_section(); - if ( wd->wlanMode == ZM_MODE_UNKNOWN ) - { - zm_debug_msg0("Unknown Mode...Skip..."); - return 0; - } + if (wd->wlanMode == ZM_MODE_UNKNOWN) { + zm_debug_msg0("Unknown Mode...Skip..."); + return 0; + } - if (wd->wlanMode == ZM_MODE_AP) - { - u16_t vapId; + if (wd->wlanMode == ZM_MODE_AP) { + u16_t vapId; - vapId = zfwGetVapId(dev); + vapId = zfwGetVapId(dev); - if (vapId == 0xffff) - { - /* AP mode */ - zfApInitStaTbl(dev); + if (vapId == 0xffff) { + /* AP mode */ + zfApInitStaTbl(dev); - /* AP default parameters */ - wd->bRate = 0xf; - wd->gRate = 0xff; - wd->bRateBasic = 0xf; - wd->gRateBasic = 0x0; - //wd->beaconInterval = 100; - wd->ap.apBitmap = 1; - wd->ap.beaconCounter = 0; - //wd->ap.vapNumber = 1; //mark by ygwei for Vap + /* AP default parameters */ + wd->bRate = 0xf; + wd->gRate = 0xff; + wd->bRateBasic = 0xf; + wd->gRateBasic = 0x0; + /* wd->beaconInterval = 100; */ + wd->ap.apBitmap = 1; + wd->ap.beaconCounter = 0; + /* wd->ap.vapNumber = 1; //mark by ygwei for Vap */ - wd->ap.hideSsid[0] = 0; - wd->ap.staAgingTimeSec = 10*60; - wd->ap.staProbingTimeSec = 60; + wd->ap.hideSsid[0] = 0; + wd->ap.staAgingTimeSec = 10*60; + wd->ap.staProbingTimeSec = 60; - for (i=0; iap.bcmcHead[i] = wd->ap.bcmcTail[i] = 0; - } + for (i = 0; i < ZM_MAX_AP_SUPPORT; i++) + wd->ap.bcmcHead[i] = wd->ap.bcmcTail[i] = 0; - //wd->ap.uniHead = wd->ap.uniTail = 0; + /* wd->ap.uniHead = wd->ap.uniTail = 0; */ - /* load AP parameters */ - wd->bRateBasic = wd->ws.bRateBasic; - wd->gRateBasic = wd->ws.gRateBasic; - wd->bgMode = wd->ws.bgMode; - if ((wd->ws.ssidLen <= 32) && (wd->ws.ssidLen != 0)) - { - wd->ap.ssidLen[0] = wd->ws.ssidLen; - for(i=0; iws.ssidLen; i++) - { - wd->ap.ssid[0][i] = wd->ws.ssid[i]; - } - wd->ws.ssidLen = 0; // Reset Wrapper Variable - } + /* load AP parameters */ + wd->bRateBasic = wd->ws.bRateBasic; + wd->gRateBasic = wd->ws.gRateBasic; + wd->bgMode = wd->ws.bgMode; + if ((wd->ws.ssidLen <= 32) && (wd->ws.ssidLen != 0)) { + wd->ap.ssidLen[0] = wd->ws.ssidLen; + for (i = 0; i < wd->ws.ssidLen; i++) + wd->ap.ssid[0][i] = wd->ws.ssid[i]; + wd->ws.ssidLen = 0; /* Reset Wrapper Variable */ + } - if (wd->ap.encryMode[0] == 0) - { - wd->ap.capab[0] = 0x001; - } - else - { - wd->ap.capab[0] = 0x011; - } - /* set Short Slot Time bit if not 11b */ - if (wd->ap.wlanType[0] != ZM_WLAN_TYPE_PURE_B) - { - wd->ap.capab[0] |= 0x400; - } + if (wd->ap.encryMode[0] == 0) + wd->ap.capab[0] = 0x001; + else + wd->ap.capab[0] = 0x011; + /* set Short Slot Time bit if not 11b */ + if (wd->ap.wlanType[0] != ZM_WLAN_TYPE_PURE_B) + wd->ap.capab[0] |= 0x400; - // wd->ap.vapNumber = 1; // mark by ygwei for Vap Test - } - else - { + /* wd->ap.vapNumber = 1; //mark by ygwei for Vap Test */ + } else { #if 0 - /* VAP Test Code */ - wd->ap.apBitmap = 0x3; - wd->ap.capab[1] = 0x401; - wd->ap.ssidLen[1] = 4; - wd->ap.ssid[1][0] = 'v'; - wd->ap.ssid[1][1] = 'a'; - wd->ap.ssid[1][2] = 'p'; - wd->ap.ssid[1][3] = '1'; - wd->ap.authAlgo[1] = wd->ws.authMode; - wd->ap.encryMode[1] = wd->ws.encryMode; - wd->ap.vapNumber = 2; + /* VAP Test Code */ + wd->ap.apBitmap = 0x3; + wd->ap.capab[1] = 0x401; + wd->ap.ssidLen[1] = 4; + wd->ap.ssid[1][0] = 'v'; + wd->ap.ssid[1][1] = 'a'; + wd->ap.ssid[1][2] = 'p'; + wd->ap.ssid[1][3] = '1'; + wd->ap.authAlgo[1] = wd->ws.authMode; + wd->ap.encryMode[1] = wd->ws.encryMode; + wd->ap.vapNumber = 2; #else - /* VAP Test Code */ - wd->ap.apBitmap = 0x1 | (0x01 << (vapId+1)); + /* VAP Test Code */ + wd->ap.apBitmap = 0x1 | (0x01 << (vapId+1)); - if ((wd->ws.ssidLen <= 32) && (wd->ws.ssidLen != 0)) - { - wd->ap.ssidLen[vapId+1] = wd->ws.ssidLen; - for(i=0; iws.ssidLen; i++) - { - wd->ap.ssid[vapId+1][i] = wd->ws.ssid[i]; - } - wd->ws.ssidLen = 0; // Reset Wrapper Variable - } + if ((wd->ws.ssidLen <= 32) && (wd->ws.ssidLen != 0)) { + wd->ap.ssidLen[vapId+1] = wd->ws.ssidLen; + for (i = 0; i < wd->ws.ssidLen; i++) + wd->ap.ssid[vapId+1][i] = + wd->ws.ssid[i]; + wd->ws.ssidLen = 0; /* Reset Wrapper Variable */ + } - if (wd->ap.encryMode[vapId+1] == 0) - { - wd->ap.capab[vapId+1] = 0x401; - } - else - { - wd->ap.capab[vapId+1] = 0x411; - } + if (wd->ap.encryMode[vapId+1] == 0) + wd->ap.capab[vapId+1] = 0x401; + else + wd->ap.capab[vapId+1] = 0x411; - wd->ap.authAlgo[vapId+1] = wd->ws.authMode; - wd->ap.encryMode[vapId+1] = wd->ws.encryMode; + wd->ap.authAlgo[vapId+1] = wd->ws.authMode; + wd->ap.encryMode[vapId+1] = wd->ws.encryMode; - /* Need to be modified when VAP is used */ - //wd->ap.vapNumber = 2; + /* Need to be modified when VAP is used */ + /* wd->ap.vapNumber = 2; */ #endif - } + } - wd->ap.vapNumber++; + wd->ap.vapNumber++; - zfCoreSetFrequency(dev, wd->frequency); + zfCoreSetFrequency(dev, wd->frequency); - zfInitMacApMode(dev); + zfInitMacApMode(dev); - /* Disable protection mode */ - zfApSetProtectionMode(dev, 0); + /* Disable protection mode */ + zfApSetProtectionMode(dev, 0); - zfApSendBeacon(dev); - } /*if (wd->wlanMode == ZM_MODE_AP) */ - else - { - zfScanMgrScanStop(dev, ZM_SCAN_MGR_SCAN_INTERNAL); - zfScanMgrScanStop(dev, ZM_SCAN_MGR_SCAN_EXTERNAL); + zfApSendBeacon(dev); + } else { /*if (wd->wlanMode == ZM_MODE_AP) */ - zmw_enter_critical_section(dev); - wd->sta.oppositeCount = 0; /* reset opposite count */ - //wd->sta.bAutoReconnect = wd->sta.bAutoReconnectEnabled; - //wd->sta.scanWithSSID = 0; - zfStaInitOppositeInfo(dev); - zmw_leave_critical_section(dev); + zfScanMgrScanStop(dev, ZM_SCAN_MGR_SCAN_INTERNAL); + zfScanMgrScanStop(dev, ZM_SCAN_MGR_SCAN_EXTERNAL); - zfStaResetStatus(dev, 0); + zmw_enter_critical_section(dev); + wd->sta.oppositeCount = 0; /* reset opposite count */ + /* wd->sta.bAutoReconnect = wd->sta.bAutoReconnectEnabled; */ + /* wd->sta.scanWithSSID = 0; */ + zfStaInitOppositeInfo(dev); + zmw_leave_critical_section(dev); - if ( (wd->sta.cmDisallowSsidLength != 0)&& - (wd->sta.ssidLen == wd->sta.cmDisallowSsidLength)&& - (zfMemoryIsEqual(wd->sta.ssid, wd->sta.cmDisallowSsid, - wd->sta.ssidLen)) && - (wd->sta.wepStatus == ZM_ENCRYPTION_TKIP)) - { /* countermeasures */ - zm_debug_msg0("countermeasures disallow association"); + zfStaResetStatus(dev, 0); - } - else - { - switch( wd->wlanMode ) - { - case ZM_MODE_IBSS: - /* some registers may be set here */ - if ( wd->sta.authMode == ZM_AUTH_MODE_WPA2PSK ) - { - zfHpSetApStaMode(dev, ZM_HAL_80211_MODE_IBSS_WPA2PSK); - } - else - { - zfHpSetApStaMode(dev, ZM_HAL_80211_MODE_IBSS_GENERAL); - } + if ((wd->sta.cmDisallowSsidLength != 0) && + (wd->sta.ssidLen == wd->sta.cmDisallowSsidLength) && + (zfMemoryIsEqual(wd->sta.ssid, wd->sta.cmDisallowSsid, + wd->sta.ssidLen)) && + (wd->sta.wepStatus == ZM_ENCRYPTION_TKIP)) {/*countermeasures*/ + zm_debug_msg0("countermeasures disallow association"); + } else { + switch (wd->wlanMode) { + case ZM_MODE_IBSS: + /* some registers may be set here */ + if (wd->sta.authMode == ZM_AUTH_MODE_WPA2PSK) + zfHpSetApStaMode(dev, + ZM_HAL_80211_MODE_IBSS_WPA2PSK); + else + zfHpSetApStaMode(dev, + ZM_HAL_80211_MODE_IBSS_GENERAL); - zm_msg0_mm(ZM_LV_0, "ZM_MODE_IBSS"); - zfIbssConnectNetwork(dev); - break; + zm_msg0_mm(ZM_LV_0, "ZM_MODE_IBSS"); + zfIbssConnectNetwork(dev); + break; - case ZM_MODE_INFRASTRUCTURE: - /* some registers may be set here */ - zfHpSetApStaMode(dev, ZM_HAL_80211_MODE_STA); + case ZM_MODE_INFRASTRUCTURE: + /* some registers may be set here */ + zfHpSetApStaMode(dev, ZM_HAL_80211_MODE_STA); - zfInfraConnectNetwork(dev); - break; + zfInfraConnectNetwork(dev); + break; - case ZM_MODE_PSEUDO: - /* some registers may be set here */ - zfHpSetApStaMode(dev, ZM_HAL_80211_MODE_STA); + case ZM_MODE_PSEUDO: + /* some registers may be set here */ + zfHpSetApStaMode(dev, ZM_HAL_80211_MODE_STA); - zfUpdateBssid(dev, bssid); - zfCoreSetFrequency(dev, wd->frequency); - break; + zfUpdateBssid(dev, bssid); + zfCoreSetFrequency(dev, wd->frequency); + break; - default: - break; - } - } + default: + break; + } + } - } + } - //if ( (wd->wlanMode != ZM_MODE_INFRASTRUCTURE)&& - // (wd->wlanMode != ZM_MODE_AP) ) - if ( wd->wlanMode == ZM_MODE_PSEUDO ) - { - /* Reset Wlan status */ - zfWlanReset(dev); + /* if ((wd->wlanMode != ZM_MODE_INFRASTRUCTURE) && + (wd->wlanMode != ZM_MODE_AP)) + */ + if (wd->wlanMode == ZM_MODE_PSEUDO) { + /* Reset Wlan status */ + zfWlanReset(dev); - if (wd->zfcbConnectNotify != NULL) - { - wd->zfcbConnectNotify(dev, ZM_STATUS_MEDIA_CONNECT, wd->sta.bssid); - } - zfChangeAdapterState(dev, ZM_STA_STATE_CONNECTED); - } + if (wd->zfcbConnectNotify != NULL) + wd->zfcbConnectNotify(dev, ZM_STATUS_MEDIA_CONNECT, + wd->sta.bssid); + zfChangeAdapterState(dev, ZM_STA_STATE_CONNECTED); + } - if(wd->wlanMode == ZM_MODE_AP) - { - if (wd->zfcbConnectNotify != NULL) - { - wd->zfcbConnectNotify(dev, ZM_STATUS_MEDIA_CONNECT, wd->sta.bssid); - } - //zfChangeAdapterState(dev, ZM_STA_STATE_CONNECTED); - } + if (wd->wlanMode == ZM_MODE_AP) { + if (wd->zfcbConnectNotify != NULL) + wd->zfcbConnectNotify(dev, ZM_STATUS_MEDIA_CONNECT, + wd->sta.bssid); + /* zfChangeAdapterState(dev, ZM_STA_STATE_CONNECTED); */ + } - // Assign default Tx Rate - if ( wd->sta.EnableHT ) - { + /* Assign default Tx Rate */ + if (wd->sta.EnableHT) { u32_t oneTxStreamCap; - oneTxStreamCap = (zfHpCapability(dev) & ZM_HP_CAP_11N_ONE_TX_STREAM); - if(oneTxStreamCap) + oneTxStreamCap = (zfHpCapability(dev) & + ZM_HP_CAP_11N_ONE_TX_STREAM); + if (oneTxStreamCap) wd->CurrentTxRateKbps = 135000; else wd->CurrentTxRateKbps = 270000; - wd->CurrentRxRateKbps = 270000; - } - else - { - wd->CurrentTxRateKbps = 54000; - wd->CurrentRxRateKbps = 54000; - } + wd->CurrentRxRateKbps = 270000; + } else { + wd->CurrentTxRateKbps = 54000; + wd->CurrentRxRateKbps = 54000; + } - wd->state = ZM_WLAN_STATE_ENABLED; + wd->state = ZM_WLAN_STATE_ENABLED; - return 0; + return 0; } /* Enable/disable Wlan operation */ -u16_t zfiWlanEnable(zdev_t* dev) +u16_t zfiWlanEnable(zdev_t *dev) { - u16_t ret; + u16_t ret; - zmw_get_wlan_dev(dev); + zmw_get_wlan_dev(dev); - zm_msg0_mm(ZM_LV_1, "Enable Wlan"); + zm_msg0_mm(ZM_LV_1, "Enable Wlan"); - zfGetWrapperSetting(dev); + zfGetWrapperSetting(dev); - zfZeroMemory((u8_t*) &wd->trafTally, sizeof(struct zsTrafTally)); + zfZeroMemory((u8_t *) &wd->trafTally, sizeof(struct zsTrafTally)); - // Reset cmMicFailureCount to 0 for new association request - if ( wd->sta.cmMicFailureCount == 1 ) - { - zfTimerCancel(dev, ZM_EVENT_CM_TIMER); - wd->sta.cmMicFailureCount = 0; - } + /* Reset cmMicFailureCount to 0 for new association request */ + if (wd->sta.cmMicFailureCount == 1) { + zfTimerCancel(dev, ZM_EVENT_CM_TIMER); + wd->sta.cmMicFailureCount = 0; + } - zfFlushVtxq(dev); - if ((wd->queueFlushed & 0x10) != 0) - { - zfHpUsbReset(dev); - } - ret = zfWlanEnable(dev); + zfFlushVtxq(dev); + if ((wd->queueFlushed & 0x10) != 0) + zfHpUsbReset(dev); - return ret; + ret = zfWlanEnable(dev); + + return ret; } /* Add a flag named ResetKeyCache to show if KeyCache should be cleared. for hostapd in AP mode, if driver receives iwconfig ioctl - after setting group key, it shouldn't clear KeyCache. */ -u16_t zfiWlanDisable(zdev_t* dev, u8_t ResetKeyCache) + after setting group key, it shouldn't clear KeyCache. +*/ +u16_t zfiWlanDisable(zdev_t *dev, u8_t ResetKeyCache) { - u16_t i; - u8_t isConnected; + u16_t i; + u8_t isConnected; - zmw_get_wlan_dev(dev); + zmw_get_wlan_dev(dev); #ifdef ZM_ENABLE_IBSS_WPA2PSK - zmw_declare_for_critical_section(); + zmw_declare_for_critical_section(); #endif - wd->state = ZM_WLAN_STATE_DISABLED; + wd->state = ZM_WLAN_STATE_DISABLED; - zm_msg0_mm(ZM_LV_1, "Disable Wlan"); + zm_msg0_mm(ZM_LV_1, "Disable Wlan"); - if ( wd->wlanMode != ZM_MODE_AP ) - { - isConnected = zfStaIsConnected(dev); + if (wd->wlanMode != ZM_MODE_AP) { + isConnected = zfStaIsConnected(dev); - if ( (wd->wlanMode == ZM_MODE_INFRASTRUCTURE)&& - (wd->sta.currentAuthMode != ZM_AUTH_MODE_WPA2) ) - { - /* send deauthentication frame */ - if (isConnected) - { - //zfiWlanDeauth(dev, NULL, 0); - zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_DEAUTH, wd->sta.bssid, 3, 0, 0); - //zmw_debug_msg0("send a Deauth frame!"); - } - } + if ((wd->wlanMode == ZM_MODE_INFRASTRUCTURE) && + (wd->sta.currentAuthMode != ZM_AUTH_MODE_WPA2)) { + /* send deauthentication frame */ + if (isConnected) { + /* zfiWlanDeauth(dev, NULL, 0); */ + zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_DEAUTH, + wd->sta.bssid, 3, 0, 0); + /* zmw_debug_msg0("send a Deauth frame!"); */ + } + } - // Remove all the connected peer stations - if ( wd->wlanMode == ZM_MODE_IBSS ) - { - wd->sta.ibssBssIsCreator = 0; - zfTimerCancel(dev, ZM_EVENT_IBSS_MONITOR); - zfStaIbssMonitoring(dev, 1); - } + /* Remove all the connected peer stations */ + if (wd->wlanMode == ZM_MODE_IBSS) { + wd->sta.ibssBssIsCreator = 0; + zfTimerCancel(dev, ZM_EVENT_IBSS_MONITOR); + zfStaIbssMonitoring(dev, 1); + } #ifdef ZM_ENABLE_IBSS_WPA2PSK - zmw_enter_critical_section(dev); - wd->sta.ibssWpa2Psk = 0; - zmw_leave_critical_section(dev); + zmw_enter_critical_section(dev); + wd->sta.ibssWpa2Psk = 0; + zmw_leave_critical_section(dev); #endif - wd->sta.wpaState = ZM_STA_WPA_STATE_INIT; + wd->sta.wpaState = ZM_STA_WPA_STATE_INIT; - /* reset connect timeout counter */ - wd->sta.connectTimeoutCount = 0; + /* reset connect timeout counter */ + wd->sta.connectTimeoutCount = 0; - /* reset connectState to None */ - wd->sta.connectState = ZM_STA_CONN_STATE_NONE; + /* reset connectState to None */ + wd->sta.connectState = ZM_STA_CONN_STATE_NONE; - /* reset leap enable variable */ - wd->sta.leapEnabled = 0; + /* reset leap enable variable */ + wd->sta.leapEnabled = 0; - /* Disable the RIFS Status / RIFS-like frame count / RIFS count */ - if( wd->sta.rifsState == ZM_RIFS_STATE_DETECTED ) - zfHpDisableRifs(dev); - wd->sta.rifsState = ZM_RIFS_STATE_DETECTING; - wd->sta.rifsLikeFrameCnt = 0; - wd->sta.rifsCount = 0; + /* Disable the RIFS Status/RIFS-like frame count/RIFS count */ + if (wd->sta.rifsState == ZM_RIFS_STATE_DETECTED) + zfHpDisableRifs(dev); + wd->sta.rifsState = ZM_RIFS_STATE_DETECTING; + wd->sta.rifsLikeFrameCnt = 0; + wd->sta.rifsCount = 0; - wd->sta.osRxFilter = 0; - wd->sta.bSafeMode = 0; + wd->sta.osRxFilter = 0; + wd->sta.bSafeMode = 0; - zfChangeAdapterState(dev, ZM_STA_STATE_DISCONNECT); - if (ResetKeyCache) - zfHpResetKeyCache(dev); + zfChangeAdapterState(dev, ZM_STA_STATE_DISCONNECT); + if (ResetKeyCache) + zfHpResetKeyCache(dev); - if (isConnected) - { - if (wd->zfcbConnectNotify != NULL) - { - wd->zfcbConnectNotify(dev, ZM_STATUS_MEDIA_CONNECTION_DISABLED, wd->sta.bssid); - } - } - else - { - if (wd->zfcbConnectNotify != NULL) - { - wd->zfcbConnectNotify(dev, ZM_STATUS_MEDIA_DISABLED, wd->sta.bssid); - } - } - } - else //if (wd->wlanMode == ZM_MODE_AP) - { - for (i=0; iap.staTable[i].valid == 1) - { - /* Reason : Sending station is leaving */ - zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_DEAUTH, - wd->ap.staTable[i].addr, 3, 0, 0); - } - } + if (isConnected) { + if (wd->zfcbConnectNotify != NULL) + wd->zfcbConnectNotify(dev, + ZM_STATUS_MEDIA_CONNECTION_DISABLED, + wd->sta.bssid); + } else { + if (wd->zfcbConnectNotify != NULL) + wd->zfcbConnectNotify(dev, + ZM_STATUS_MEDIA_DISABLED, wd->sta.bssid); + } + } else { /* if (wd->wlanMode == ZM_MODE_AP) */ + for (i = 0; i < ZM_MAX_STA_SUPPORT; i++) { + /* send deauthentication frame */ + if (wd->ap.staTable[i].valid == 1) { + /* Reason : Sending station is leaving */ + zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_DEAUTH, + wd->ap.staTable[i].addr, 3, 0, 0); + } + } - if (ResetKeyCache) - zfHpResetKeyCache(dev); + if (ResetKeyCache) + zfHpResetKeyCache(dev); - wd->ap.vapNumber--; - } + wd->ap.vapNumber--; + } - /* stop beacon */ - zfHpDisableBeacon(dev); + /* stop beacon */ + zfHpDisableBeacon(dev); - /* Flush VTxQ and MmQ */ - zfFlushVtxq(dev); - /* Flush AP PS queues */ - zfApFlushBufferedPsFrame(dev); - /* Free buffer in defragment list*/ - zfAgingDefragList(dev, 1); + /* Flush VTxQ and MmQ */ + zfFlushVtxq(dev); + /* Flush AP PS queues */ + zfApFlushBufferedPsFrame(dev); + /* Free buffer in defragment list*/ + zfAgingDefragList(dev, 1); - #ifdef ZM_ENABLE_AGGREGATION - /* add by honda */ - zfAggRxFreeBuf(dev, 0); //1 for release structure memory - /* end of add by honda */ - #endif +#ifdef ZM_ENABLE_AGGREGATION + /* add by honda */ + zfAggRxFreeBuf(dev, 0); /* 1 for release structure memory */ + /* end of add by honda */ +#endif - // Clear the information for the peer stations of IBSS or AP of Station mode - zfZeroMemory((u8_t*)wd->sta.oppositeInfo, sizeof(struct zsOppositeInfo) * ZM_MAX_OPPOSITE_COUNT); + /* Clear the information for the peer stations + of IBSS or AP of Station mode + */ + zfZeroMemory((u8_t *)wd->sta.oppositeInfo, + sizeof(struct zsOppositeInfo) * ZM_MAX_OPPOSITE_COUNT); - /* Turn off Software WEP/TKIP */ - if (wd->sta.SWEncryptEnable != 0) - { - zm_debug_msg0("Disable software encryption"); - zfStaDisableSWEncryption(dev); - } + /* Turn off Software WEP/TKIP */ + if (wd->sta.SWEncryptEnable != 0) { + zm_debug_msg0("Disable software encryption"); + zfStaDisableSWEncryption(dev); + } - /* Improve WEP/TKIP performace with HT AP, detail information please look bug#32495 */ - //zfHpSetTTSIFSTime(dev, 0x8); + /* Improve WEP/TKIP performace with HT AP, + detail information please look bug#32495 */ + /* zfHpSetTTSIFSTime(dev, 0x8); */ - return 0; + return 0; } -u16_t zfiWlanSuspend(zdev_t* dev) +u16_t zfiWlanSuspend(zdev_t *dev) { - zmw_get_wlan_dev(dev); - zmw_declare_for_critical_section(); + zmw_get_wlan_dev(dev); + zmw_declare_for_critical_section(); - // Change the HAL state to init so that any packet can't be transmitted between - // resume & HAL reinit. This would cause the chip hang issue in OTUS. - zmw_enter_critical_section(dev); - wd->halState = ZM_HAL_STATE_INIT; - zmw_leave_critical_section(dev); + /* Change the HAL state to init so that any packet + can't be transmitted between resume & HAL reinit. + This would cause the chip hang issue in OTUS. + */ + zmw_enter_critical_section(dev); + wd->halState = ZM_HAL_STATE_INIT; + zmw_leave_critical_section(dev); - return 0; + return 0; } -u16_t zfiWlanResume(zdev_t* dev, u8_t doReconn) +u16_t zfiWlanResume(zdev_t *dev, u8_t doReconn) { - u16_t ret; - zmw_get_wlan_dev(dev); - zmw_declare_for_critical_section(); + u16_t ret; + zmw_get_wlan_dev(dev); + zmw_declare_for_critical_section(); - /* Redownload firmware, Reinit MAC,PHY,RF */ - zfHpReinit(dev, wd->frequency); + /* Redownload firmware, Reinit MAC,PHY,RF */ + zfHpReinit(dev, wd->frequency); - //Set channel according to AP's configuration - zfCoreSetFrequencyExV2(dev, wd->frequency, wd->BandWidth40, - wd->ExtOffset, NULL, 1); + /* Set channel according to AP's configuration */ + zfCoreSetFrequencyExV2(dev, wd->frequency, wd->BandWidth40, + wd->ExtOffset, NULL, 1); - zfHpSetMacAddress(dev, wd->macAddr, 0); + zfHpSetMacAddress(dev, wd->macAddr, 0); - /* Start Rx */ - zfHpStartRecv(dev); + /* Start Rx */ + zfHpStartRecv(dev); - zfFlushVtxq(dev); + zfFlushVtxq(dev); - if ( wd->wlanMode != ZM_MODE_INFRASTRUCTURE && - wd->wlanMode != ZM_MODE_IBSS ) - { - return 1; - } + if (wd->wlanMode != ZM_MODE_INFRASTRUCTURE && + wd->wlanMode != ZM_MODE_IBSS) + return 1; - zm_msg0_mm(ZM_LV_1, "Resume Wlan"); - if ( (zfStaIsConnected(dev)) || (zfStaIsConnecting(dev)) ) - { - if (doReconn == 1) - { - zm_msg0_mm(ZM_LV_1, "Re-connect..."); - zmw_enter_critical_section(dev); - wd->sta.connectByReasso = FALSE; - zmw_leave_critical_section(dev); + zm_msg0_mm(ZM_LV_1, "Resume Wlan"); + if ((zfStaIsConnected(dev)) || (zfStaIsConnecting(dev))) { + if (doReconn == 1) { + zm_msg0_mm(ZM_LV_1, "Re-connect..."); + zmw_enter_critical_section(dev); + wd->sta.connectByReasso = FALSE; + zmw_leave_critical_section(dev); - zfWlanEnable(dev); - } - else if (doReconn == 0) - { - zfHpSetRollCallTable(dev); - } - } + zfWlanEnable(dev); + } else if (doReconn == 0) + zfHpSetRollCallTable(dev); + } - ret = 0; + ret = 0; - return ret; + return ret; } /************************************************************************/ @@ -1057,235 +979,227 @@ u16_t zfiWlanResume(zdev_t* dev, u8_t doReconn) /* Stephen Chen Atheros Communications, INC. 2007.1 */ /* */ /************************************************************************/ -void zfiWlanFlushAllQueuedBuffers(zdev_t* dev) +void zfiWlanFlushAllQueuedBuffers(zdev_t *dev) { - /* Flush VTxQ and MmQ */ - zfFlushVtxq(dev); - /* Flush AP PS queues */ - zfApFlushBufferedPsFrame(dev); - /* Free buffer in defragment list*/ - zfAgingDefragList(dev, 1); + /* Flush VTxQ and MmQ */ + zfFlushVtxq(dev); + /* Flush AP PS queues */ + zfApFlushBufferedPsFrame(dev); + /* Free buffer in defragment list*/ + zfAgingDefragList(dev, 1); } /* Do WLAN site survey */ -u16_t zfiWlanScan(zdev_t* dev) +u16_t zfiWlanScan(zdev_t *dev) { - u16_t ret = 1; - zmw_get_wlan_dev(dev); + u16_t ret = 1; + zmw_get_wlan_dev(dev); - zm_debug_msg0(""); + zm_debug_msg0(""); - zmw_declare_for_critical_section(); + zmw_declare_for_critical_section(); - zmw_enter_critical_section(dev); + zmw_enter_critical_section(dev); - if (wd->wlanMode == ZM_MODE_AP) - { - wd->heartBeatNotification |= ZM_BSSID_LIST_SCAN; - wd->sta.scanFrequency = 0; - //wd->sta.pUpdateBssList->bssCount = 0; - ret = 0; - } - else - { - #if 0 - if ( !zfStaBlockWlanScan(dev) ) - { - zm_debug_msg0("scan request"); - //zfTimerSchedule(dev, ZM_EVENT_SCAN, ZM_TICK_ZERO); - ret = 0; - goto start_scan; - } - #else - goto start_scan; - #endif - } + if (wd->wlanMode == ZM_MODE_AP) { + wd->heartBeatNotification |= ZM_BSSID_LIST_SCAN; + wd->sta.scanFrequency = 0; + /* wd->sta.pUpdateBssList->bssCount = 0; */ + ret = 0; + } else { +#if 0 + if (!zfStaBlockWlanScan(dev)) { + zm_debug_msg0("scan request"); + /*zfTimerSchedule(dev, ZM_EVENT_SCAN, ZM_TICK_ZERO);*/ + ret = 0; + goto start_scan; + } +#else + goto start_scan; +#endif + } - zmw_leave_critical_section(dev); + zmw_leave_critical_section(dev); - return ret; + return ret; start_scan: - zmw_leave_critical_section(dev); + zmw_leave_critical_section(dev); - if(wd->ledStruct.LEDCtrlFlagFromReg & ZM_LED_CTRL_FLAG_ALPHA) // flag for Alpha - wd->ledStruct.LEDCtrlFlag |= ZM_LED_CTRL_FLAG_ALPHA; + if (wd->ledStruct.LEDCtrlFlagFromReg & ZM_LED_CTRL_FLAG_ALPHA) { + /* flag for Alpha */ + wd->ledStruct.LEDCtrlFlag |= ZM_LED_CTRL_FLAG_ALPHA; + } - ret = zfScanMgrScanStart(dev, ZM_SCAN_MGR_SCAN_EXTERNAL); + ret = zfScanMgrScanStart(dev, ZM_SCAN_MGR_SCAN_EXTERNAL); - zm_debug_msg1("ret = ", ret); + zm_debug_msg1("ret = ", ret); - return ret; + return ret; } -/* rate */ -/* 0 : AUTO */ -/* 1 : CCK 1M */ -/* 2 : CCK 2M */ -/* 3 : CCK 5.5M */ -/* 4 : CCK 11M */ -/* 5 : OFDM 6M */ -/* 6 : OFDM 9M */ -/* 7 : OFDM 12M */ -/* 8 : OFDM 18M */ -/* 9 : OFDM 24M */ -/* 10 : OFDM 36M */ -/* 11 : OFDM 48M */ -/* 12 : OFDM 54M */ -/* 13 : MCS 0 */ -/* 28 : MCS 15 */ +/* rate */ +/* 0 : AUTO */ +/* 1 : CCK 1M */ +/* 2 : CCK 2M */ +/* 3 : CCK 5.5M */ +/* 4 : CCK 11M */ +/* 5 : OFDM 6M */ +/* 6 : OFDM 9M */ +/* 7 : OFDM 12M */ +/* 8 : OFDM 18M */ +/* 9 : OFDM 24M */ +/* 10 : OFDM 36M */ +/* 11 : OFDM 48M */ +/* 12 : OFDM 54M */ +/* 13 : MCS 0 */ +/* 28 : MCS 15 */ u16_t zcRateToMCS[] = {0xff, 0, 1, 2, 3, 0xb, 0xf, 0xa, 0xe, 0x9, 0xd, 0x8, 0xc}; u16_t zcRateToMT[] = {0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1}; -u16_t zfiWlanSetTxRate(zdev_t* dev, u16_t rate) -{ // jhlee HT 0 - zmw_get_wlan_dev(dev); +u16_t zfiWlanSetTxRate(zdev_t *dev, u16_t rate) +{ + /* jhlee HT 0 */ + zmw_get_wlan_dev(dev); - if (rate <=12) - { - wd->txMCS = zcRateToMCS[rate]; - wd->txMT = zcRateToMT[rate]; - return ZM_SUCCESS; - } - else if ((rate<=28)||(rate==13+32)) - { - wd->txMCS = rate - 12 - 1; - wd->txMT = 2; - return ZM_SUCCESS; - } + if (rate <= 12) { + wd->txMCS = zcRateToMCS[rate]; + wd->txMT = zcRateToMT[rate]; + return ZM_SUCCESS; + } else if ((rate <= 28) || (rate == 13 + 32)) { + wd->txMCS = rate - 12 - 1; + wd->txMT = 2; + return ZM_SUCCESS; + } - return ZM_ERR_INVALID_TX_RATE; + return ZM_ERR_INVALID_TX_RATE; } const u32_t zcRateIdToKbps40M[] = - { - 1000, 2000, 5500, 11000, /* 1M, 2M, 5M, 11M , 0 1 2 3*/ - 6000, 9000, 12000, 18000, /* 6M 9M 12M 18M , 4 5 6 7*/ - 24000, 36000, 48000, 54000, /* 24M 36M 48M 54M , 8 9 10 11*/ - 13500, 27000, 40500, 54000, /* MCS0 MCS1 MCS2 MCS3 , 12 13 14 15*/ - 81000, 108000, 121500, 135000, /* MCS4 MCS5 MCS6 MCS7 , 16 17 18 19*/ - 27000, 54000, 81000, 108000, /* MCS8 MCS9 MCS10 MCS11 , 20 21 22 23*/ - 162000, 216000, 243000, 270000, /* MCS12 MCS13 MCS14 MCS15 , 24 25 26 27*/ - 270000, 300000, 150000 /* MCS14SG, MCS15SG, MCS7SG , 28 29 30*/ - }; +{ + 1000, 2000, 5500, 11000, /* 1M, 2M, 5M, 11M , 0 1 2 3 */ + 6000, 9000, 12000, 18000, /* 6M 9M 12M 18M , 4 5 6 7 */ + 24000, 36000, 48000, 54000, /* 24M 36M 48M 54M , 8 9 10 11 */ + 13500, 27000, 40500, 54000, /* MCS0 MCS1 MCS2 MCS3 , 12 13 14 15 */ + 81000, 108000, 121500, 135000, /* MCS4 MCS5 MCS6 MCS7 , 16 17 18 19 */ + 27000, 54000, 81000, 108000, /* MCS8 MCS9 MCS10 MCS11 , 20 21 22 23 */ + 162000, 216000, 243000, 270000, /*MCS12 MCS13 MCS14 MCS15, 24 25 26 27*/ + 270000, 300000, 150000 /* MCS14SG, MCS15SG, MCS7SG , 28 29 30 */ +}; const u32_t zcRateIdToKbps20M[] = - { - 1000, 2000, 5500, 11000, /* 1M, 2M, 5M, 11M , 0 1 2 3*/ - 6000, 9000, 12000, 18000, /* 6M 9M 12M 18M , 4 5 6 7*/ - 24000, 36000, 48000, 54000, /* 24M 36M 48M 54M , 8 9 10 11*/ - 6500, 13000, 19500, 26000, /* MCS0 MCS1 MCS2 MCS3 , 12 13 14 15*/ - 39000, 52000, 58500, 65000, /* MCS4 MCS5 MCS6 MCS7 , 16 17 18 19*/ - 13000, 26000, 39000, 52000, /* MCS8 MCS9 MCS10 MCS11 , 20 21 22 23*/ - 78000, 104000, 117000, 130000, /* MCS12 MCS13 MCS14 MCS15 , 24 25 26 27*/ - 130000, 144400, 72200 /* MCS14SG, MCS15SG, MSG7SG , 28 29 30*/ - }; - -u32_t zfiWlanQueryTxRate(zdev_t* dev) { - u8_t rateId = 0xff; - zmw_get_wlan_dev(dev); - zmw_declare_for_critical_section(); + 1000, 2000, 5500, 11000, /* 1M, 2M, 5M, 11M , 0 1 2 3 */ + 6000, 9000, 12000, 18000, /* 6M 9M 12M 18M , 4 5 6 7 */ + 24000, 36000, 48000, 54000, /* 24M 36M 48M 54M , 8 9 10 11 */ + 6500, 13000, 19500, 26000, /* MCS0 MCS1 MCS2 MCS3 , 12 13 14 15 */ + 39000, 52000, 58500, 65000, /* MCS4 MCS5 MCS6 MCS7 , 16 17 18 19 */ + 13000, 26000, 39000, 52000, /* MCS8 MCS9 MCS10 MCS11 , 20 21 22 23 */ + 78000, 104000, 117000, 130000, /* MCS12 MCS13 MCS14 MCS15, 24 25 26 27*/ + 130000, 144400, 72200 /* MCS14SG, MCS15SG, MSG7SG , 28 29 30 */ +}; - /* If Tx rate had not been trained, return maximum Tx rate instead */ - if ((wd->wlanMode == ZM_MODE_INFRASTRUCTURE) && (zfStaIsConnected(dev))) - { - zmw_enter_critical_section(dev); - //Not in fixed rate mode - if (wd->txMCS == 0xff) - { - if ((wd->sta.oppositeInfo[0].rcCell.flag & ZM_RC_TRAINED_BIT) == 0) - { - rateId = wd->sta.oppositeInfo[0].rcCell.operationRateSet[wd->sta.oppositeInfo[0].rcCell.operationRateCount-1]; - } - else - { - rateId = wd->sta.oppositeInfo[0].rcCell.operationRateSet[wd->sta.oppositeInfo[0].rcCell.currentRateIndex]; - } - } - zmw_leave_critical_section(dev); - } - if (rateId != 0xff) - { - if (wd->sta.htCtrlBandwidth) - { - return zcRateIdToKbps40M[rateId]; - } - else - { - return zcRateIdToKbps20M[rateId]; - } - } - else - { - return wd->CurrentTxRateKbps; - } +u32_t zfiWlanQueryTxRate(zdev_t *dev) +{ + u8_t rateId = 0xff; + zmw_get_wlan_dev(dev); + zmw_declare_for_critical_section(); + + /* If Tx rate had not been trained, return maximum Tx rate instead */ + if ((wd->wlanMode == ZM_MODE_INFRASTRUCTURE) && + (zfStaIsConnected(dev))) { + zmw_enter_critical_section(dev); + /* Not in fixed rate mode */ + if (wd->txMCS == 0xff) { + if ((wd->sta.oppositeInfo[0].rcCell.flag & + ZM_RC_TRAINED_BIT) == 0) + rateId = wd->sta.oppositeInfo[0].rcCell. \ + operationRateSet[wd->sta.oppositeInfo[0]. \ + rcCell.operationRateCount-1]; + else + rateId = wd->sta.oppositeInfo[0].rcCell. \ + operationRateSet[wd->sta.oppositeInfo[0]. \ + rcCell.currentRateIndex]; + } + zmw_leave_critical_section(dev); + } + + if (rateId != 0xff) { + if (wd->sta.htCtrlBandwidth) + return zcRateIdToKbps40M[rateId]; + else + return zcRateIdToKbps20M[rateId]; + } else + return wd->CurrentTxRateKbps; } -void zfWlanUpdateRxRate(zdev_t* dev, struct zsAdditionInfo* addInfo) +void zfWlanUpdateRxRate(zdev_t *dev, struct zsAdditionInfo *addInfo) { - u32_t rxRateKbps; - zmw_get_wlan_dev(dev); - //zm_msg1_mm(ZM_LV_0, "addInfo->Tail.Data.RxMacStatus =", addInfo->Tail.Data.RxMacStatus & 0x03); + u32_t rxRateKbps; + zmw_get_wlan_dev(dev); + /* zm_msg1_mm(ZM_LV_0, "addInfo->Tail.Data.RxMacStatus =", + * addInfo->Tail.Data.RxMacStatus & 0x03); + */ - /* b5~b4: MPDU indication. */ - /* 00: Single MPDU. */ - /* 10: First MPDU of A-MPDU. */ - /* 11: Middle MPDU of A-MPDU. */ - /* 01: Last MPDU of A-MPDU. */ - /* Only First MPDU and Single MPDU have PLCP header */ - /* First MPDU : (mpduInd & 0x30) == 0x00 */ - /* Single MPDU : (mpduInd & 0x30) == 0x20 */ - if ((addInfo->Tail.Data.RxMacStatus & 0x10) == 0) - { - /* Modulation type */ - wd->modulationType = addInfo->Tail.Data.RxMacStatus & 0x03; - switch(wd->modulationType) - { - case 0x0: wd->rateField = addInfo->PlcpHeader[0] & 0xff; //CCK mode - wd->rxInfo = 0; - break; - case 0x1: wd->rateField = addInfo->PlcpHeader[0] & 0x0f; //Legacy-OFDM mode - wd->rxInfo = 0; - break; - case 0x2: wd->rateField = addInfo->PlcpHeader[3]; //HT-OFDM mode - wd->rxInfo = addInfo->PlcpHeader[6]; - break; - default: break; - } + /* b5~b4: MPDU indication. */ + /* 00: Single MPDU. */ + /* 10: First MPDU of A-MPDU. */ + /* 11: Middle MPDU of A-MPDU. */ + /* 01: Last MPDU of A-MPDU. */ + /* Only First MPDU and Single MPDU have PLCP header */ + /* First MPDU : (mpduInd & 0x30) == 0x00 */ + /* Single MPDU : (mpduInd & 0x30) == 0x20 */ + if ((addInfo->Tail.Data.RxMacStatus & 0x10) == 0) { + /* Modulation type */ + wd->modulationType = addInfo->Tail.Data.RxMacStatus & 0x03; + switch (wd->modulationType) { + /* CCK mode */ + case 0x0: + wd->rateField = addInfo->PlcpHeader[0] & 0xff; + wd->rxInfo = 0; + break; + /* Legacy-OFDM mode */ + case 0x1: + wd->rateField = addInfo->PlcpHeader[0] & 0x0f; + wd->rxInfo = 0; + break; + /* HT-OFDM mode */ + case 0x2: + wd->rateField = addInfo->PlcpHeader[3]; + wd->rxInfo = addInfo->PlcpHeader[6]; + break; + default: + break; + } - rxRateKbps = zfUpdateRxRate(dev); - if (wd->CurrentRxRateUpdated == 1) - { - if (rxRateKbps > wd->CurrentRxRateKbps) - { - wd->CurrentRxRateKbps = rxRateKbps; - } - } - else - { - wd->CurrentRxRateKbps = rxRateKbps; - wd->CurrentRxRateUpdated = 1; - } - } + rxRateKbps = zfUpdateRxRate(dev); + if (wd->CurrentRxRateUpdated == 1) { + if (rxRateKbps > wd->CurrentRxRateKbps) + wd->CurrentRxRateKbps = rxRateKbps; + } else { + wd->CurrentRxRateKbps = rxRateKbps; + wd->CurrentRxRateUpdated = 1; + } + } } + #if 0 u16_t zcIndextoRateBG[16] = {1000, 2000, 5500, 11000, 0, 0, 0, 0, 48000, - 24000, 12000, 6000, 54000, 36000, 18000, 9000}; + 24000, 12000, 6000, 54000, 36000, 18000, 9000}; u32_t zcIndextoRateN20L[16] = {6500, 13000, 19500, 26000, 39000, 52000, 58500, - 65000, 13000, 26000, 39000, 52000, 78000, 104000, - 117000, 130000}; + 65000, 13000, 26000, 39000, 52000, 78000, 104000, + 117000, 130000}; u32_t zcIndextoRateN20S[16] = {7200, 14400, 21700, 28900, 43300, 57800, 65000, - 72200, 14400, 28900, 43300, 57800, 86700, 115600, - 130000, 144400}; -u32_t zcIndextoRateN40L[16] = {13500, 27000, 40500, 54000, 81000, 108000, 121500, - 135000, 27000, 54000, 81000, 108000, 162000, 216000, - 243000, 270000}; -u32_t zcIndextoRateN40S[16] = {15000, 30000, 45000, 60000, 90000, 120000, 135000, - 150000, 30000, 60000, 90000, 120000, 180000, 240000, - 270000, 300000}; + 72200, 14400, 28900, 43300, 57800, 86700, 115600, + 130000, 144400}; +u32_t zcIndextoRateN40L[16] = {13500, 27000, 40500, 54000, 81000, 108000, + 121500, 135000, 27000, 54000, 81000, 108000, + 162000, 216000, 243000, 270000}; +u32_t zcIndextoRateN40S[16] = {15000, 30000, 45000, 60000, 90000, 120000, + 135000, 150000, 30000, 60000, 90000, 120000, + 180000, 240000, 270000, 300000}; #endif extern u16_t zcIndextoRateBG[16]; @@ -1294,568 +1208,558 @@ extern u32_t zcIndextoRateN20S[16]; extern u32_t zcIndextoRateN40L[16]; extern u32_t zcIndextoRateN40S[16]; -u32_t zfiWlanQueryRxRate(zdev_t* dev) +u32_t zfiWlanQueryRxRate(zdev_t *dev) { - zmw_get_wlan_dev(dev); + zmw_get_wlan_dev(dev); - wd->CurrentRxRateUpdated = 0; - return wd->CurrentRxRateKbps; + wd->CurrentRxRateUpdated = 0; + return wd->CurrentRxRateKbps; } -u32_t zfUpdateRxRate(zdev_t* dev) +u32_t zfUpdateRxRate(zdev_t *dev) { - u8_t mcs, bandwidth; - u32_t rxRateKbps = 130000; - zmw_get_wlan_dev(dev); + u8_t mcs, bandwidth; + u32_t rxRateKbps = 130000; + zmw_get_wlan_dev(dev); - switch (wd->modulationType) - { - case 0x0: //CCK mode - switch (wd->rateField) - { - case 0x0a: rxRateKbps = 1000; - break; - case 0x14: rxRateKbps = 2000; + switch (wd->modulationType) { + /* CCK mode */ + case 0x0: + switch (wd->rateField) { + case 0x0a: + rxRateKbps = 1000; + break; + case 0x14: + rxRateKbps = 2000; - case 0x37: rxRateKbps = 5500; - break; - case 0x6e: rxRateKbps = 11000; - break; - default: - break; - } - break; - case 0x1: //Legacy-OFDM mode - if (wd->rateField <= 15) - { - rxRateKbps = zcIndextoRateBG[wd->rateField]; - } - break; - case 0x2: //HT-OFDM mode - mcs = wd->rateField & 0x7F; - bandwidth = wd->rateField & 0x80; - if (mcs <= 15) - { - if (bandwidth != 0) - { - if((wd->rxInfo & 0x80) != 0) - { - /* Short GI 40 MHz MIMO Rate */ - rxRateKbps = zcIndextoRateN40S[mcs]; - } - else - { - /* Long GI 40 MHz MIMO Rate */ - rxRateKbps = zcIndextoRateN40L[mcs]; - } - } - else - { - if((wd->rxInfo & 0x80) != 0) - { - /* Short GI 20 MHz MIMO Rate */ - rxRateKbps = zcIndextoRateN20S[mcs]; - } - else - { - /* Long GI 20 MHz MIMO Rate */ - rxRateKbps = zcIndextoRateN20L[mcs]; - } - } - } - break; - default: - break; - } - //zm_msg1_mm(ZM_LV_0, "wd->CurrentRxRateKbps=", wd->CurrentRxRateKbps); + case 0x37: + rxRateKbps = 5500; + break; + case 0x6e: + rxRateKbps = 11000; + break; + default: + break; + } + break; + /* Legacy-OFDM mode */ + case 0x1: + if (wd->rateField <= 15) + rxRateKbps = zcIndextoRateBG[wd->rateField]; + break; + /* HT-OFDM mode */ + case 0x2: + mcs = wd->rateField & 0x7F; + bandwidth = wd->rateField & 0x80; + if (mcs <= 15) { + if (bandwidth != 0) { + if ((wd->rxInfo & 0x80) != 0) { + /* Short GI 40 MHz MIMO Rate */ + rxRateKbps = zcIndextoRateN40S[mcs]; + } else { + /* Long GI 40 MHz MIMO Rate */ + rxRateKbps = zcIndextoRateN40L[mcs]; + } + } else { + if ((wd->rxInfo & 0x80) != 0) { + /* Short GI 20 MHz MIMO Rate */ + rxRateKbps = zcIndextoRateN20S[mcs]; + } else { + /* Long GI 20 MHz MIMO Rate */ + rxRateKbps = zcIndextoRateN20L[mcs]; + } + } + } + break; + default: + break; + } + /* zm_msg1_mm(ZM_LV_0, "wd->CurrentRxRateKbps=", + wd->CurrentRxRateKbps); + */ - // ToDo: use bandwith field to define 40MB - return rxRateKbps; + /* ToDo: use bandwith field to define 40MB */ + return rxRateKbps; } /* Get WLAN stastics */ -u16_t zfiWlanGetStatistics(zdev_t* dev) +u16_t zfiWlanGetStatistics(zdev_t *dev) { - /* Return link statistics */ - return 0; + /* Return link statistics */ + return 0; } -u16_t zfiWlanReset(zdev_t* dev) +u16_t zfiWlanReset(zdev_t *dev) { - zmw_get_wlan_dev(dev); + zmw_get_wlan_dev(dev); - wd->state = ZM_WLAN_STATE_DISABLED; + wd->state = ZM_WLAN_STATE_DISABLED; - return zfWlanReset(dev); + return zfWlanReset(dev); } /* Reset WLAN */ -u16_t zfWlanReset(zdev_t* dev) +u16_t zfWlanReset(zdev_t *dev) { - u8_t isConnected; - zmw_get_wlan_dev(dev); + u8_t isConnected; + zmw_get_wlan_dev(dev); - zmw_declare_for_critical_section(); + zmw_declare_for_critical_section(); - zm_debug_msg0("zfWlanReset"); + zm_debug_msg0("zfWlanReset"); - isConnected = zfStaIsConnected(dev); + isConnected = zfStaIsConnected(dev); - //if ( wd->wlanMode != ZM_MODE_AP ) - { - if ( (wd->wlanMode == ZM_MODE_INFRASTRUCTURE)&& - (wd->sta.currentAuthMode != ZM_AUTH_MODE_WPA2) ) - { - /* send deauthentication frame */ - if (isConnected) - { - //zfiWlanDeauth(dev, NULL, 0); - zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_DEAUTH, wd->sta.bssid, 3, 0, 0); - //zmw_debug_msg0("send a Deauth frame!"); - } - } - } + /* if ( wd->wlanMode != ZM_MODE_AP ) */ + { + if ((wd->wlanMode == ZM_MODE_INFRASTRUCTURE) && + (wd->sta.currentAuthMode != ZM_AUTH_MODE_WPA2)) { + /* send deauthentication frame */ + if (isConnected) { + /* zfiWlanDeauth(dev, NULL, 0); */ + zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_DEAUTH, + wd->sta.bssid, 3, 0, 0); + /* zmw_debug_msg0("send a Deauth frame!"); */ + } + } + } - zfChangeAdapterState(dev, ZM_STA_STATE_DISCONNECT); - zfHpResetKeyCache(dev); + zfChangeAdapterState(dev, ZM_STA_STATE_DISCONNECT); + zfHpResetKeyCache(dev); - if (isConnected) - { - //zfiWlanDisable(dev); - if (wd->zfcbConnectNotify != NULL) - { - wd->zfcbConnectNotify(dev, ZM_STATUS_MEDIA_CONNECTION_RESET, wd->sta.bssid); - } - } - else - { - if (wd->zfcbConnectNotify != NULL) - { - wd->zfcbConnectNotify(dev, ZM_STATUS_MEDIA_RESET, wd->sta.bssid); - } - } + if (isConnected) { + /* zfiWlanDisable(dev); */ + if (wd->zfcbConnectNotify != NULL) + wd->zfcbConnectNotify(dev, + ZM_STATUS_MEDIA_CONNECTION_RESET, wd->sta.bssid); + } else { + if (wd->zfcbConnectNotify != NULL) + wd->zfcbConnectNotify(dev, ZM_STATUS_MEDIA_RESET, + wd->sta.bssid); + } - /* stop beacon */ - zfHpDisableBeacon(dev); + /* stop beacon */ + zfHpDisableBeacon(dev); - /* Free buffer in defragment list*/ - zfAgingDefragList(dev, 1); + /* Free buffer in defragment list*/ + zfAgingDefragList(dev, 1); - /* Flush VTxQ and MmQ */ - zfFlushVtxq(dev); + /* Flush VTxQ and MmQ */ + zfFlushVtxq(dev); - #ifdef ZM_ENABLE_AGGREGATION - /* add by honda */ - zfAggRxFreeBuf(dev, 0); //1 for release structure memory - /* end of add by honda */ - #endif - - zfStaRefreshBlockList(dev, 1); - - zmw_enter_critical_section(dev); - - zfTimerCancel(dev, ZM_EVENT_IBSS_MONITOR); - zfTimerCancel(dev, ZM_EVENT_CM_BLOCK_TIMER); - zfTimerCancel(dev, ZM_EVENT_CM_DISCONNECT); - - wd->sta.connectState = ZM_STA_CONN_STATE_NONE; - wd->sta.connectByReasso = FALSE; - wd->sta.cmDisallowSsidLength = 0; - wd->sta.bAutoReconnect = 0; - wd->sta.InternalScanReq = 0; - wd->sta.encryMode = ZM_NO_WEP; - wd->sta.wepStatus = ZM_ENCRYPTION_WEP_DISABLED; - wd->sta.wpaState = ZM_STA_WPA_STATE_INIT; - wd->sta.cmMicFailureCount = 0; - wd->sta.ibssBssIsCreator = 0; -#ifdef ZM_ENABLE_IBSS_WPA2PSK - wd->sta.ibssWpa2Psk = 0; +#ifdef ZM_ENABLE_AGGREGATION + /* add by honda */ + zfAggRxFreeBuf(dev, 0); /* 1 for release structure memory */ + /* end of add by honda */ #endif - /* reset connect timeout counter */ - wd->sta.connectTimeoutCount = 0; - /* reset leap enable variable */ - wd->sta.leapEnabled = 0; + zfStaRefreshBlockList(dev, 1); - /* Reset the RIFS Status / RIFS-like frame count / RIFS count */ - if( wd->sta.rifsState == ZM_RIFS_STATE_DETECTED ) - zfHpDisableRifs(dev); - wd->sta.rifsState = ZM_RIFS_STATE_DETECTING; - wd->sta.rifsLikeFrameCnt = 0; - wd->sta.rifsCount = 0; + zmw_enter_critical_section(dev); - wd->sta.osRxFilter = 0; - wd->sta.bSafeMode = 0; + zfTimerCancel(dev, ZM_EVENT_IBSS_MONITOR); + zfTimerCancel(dev, ZM_EVENT_CM_BLOCK_TIMER); + zfTimerCancel(dev, ZM_EVENT_CM_DISCONNECT); - // Clear the information for the peer stations of IBSS or AP of Station mode - zfZeroMemory((u8_t*)wd->sta.oppositeInfo, sizeof(struct zsOppositeInfo) * ZM_MAX_OPPOSITE_COUNT); + wd->sta.connectState = ZM_STA_CONN_STATE_NONE; + wd->sta.connectByReasso = FALSE; + wd->sta.cmDisallowSsidLength = 0; + wd->sta.bAutoReconnect = 0; + wd->sta.InternalScanReq = 0; + wd->sta.encryMode = ZM_NO_WEP; + wd->sta.wepStatus = ZM_ENCRYPTION_WEP_DISABLED; + wd->sta.wpaState = ZM_STA_WPA_STATE_INIT; + wd->sta.cmMicFailureCount = 0; + wd->sta.ibssBssIsCreator = 0; +#ifdef ZM_ENABLE_IBSS_WPA2PSK + wd->sta.ibssWpa2Psk = 0; +#endif + /* reset connect timeout counter */ + wd->sta.connectTimeoutCount = 0; - zmw_leave_critical_section(dev); + /* reset leap enable variable */ + wd->sta.leapEnabled = 0; - zfScanMgrScanStop(dev, ZM_SCAN_MGR_SCAN_INTERNAL); - zfScanMgrScanStop(dev, ZM_SCAN_MGR_SCAN_EXTERNAL); + /* Reset the RIFS Status / RIFS-like frame count / RIFS count */ + if (wd->sta.rifsState == ZM_RIFS_STATE_DETECTED) + zfHpDisableRifs(dev); + wd->sta.rifsState = ZM_RIFS_STATE_DETECTING; + wd->sta.rifsLikeFrameCnt = 0; + wd->sta.rifsCount = 0; - /* Turn off Software WEP/TKIP */ - if (wd->sta.SWEncryptEnable != 0) - { - zm_debug_msg0("Disable software encryption"); - zfStaDisableSWEncryption(dev); - } + wd->sta.osRxFilter = 0; + wd->sta.bSafeMode = 0; - /* Improve WEP/TKIP performace with HT AP, detail information please look bug#32495 */ - //zfHpSetTTSIFSTime(dev, 0x8); + /* Clear the information for the peer + stations of IBSS or AP of Station mode + */ + zfZeroMemory((u8_t *)wd->sta.oppositeInfo, + sizeof(struct zsOppositeInfo) * ZM_MAX_OPPOSITE_COUNT); - /* Keep Pseudo mode */ - if ( wd->wlanMode != ZM_MODE_PSEUDO ) - { - wd->wlanMode = ZM_MODE_INFRASTRUCTURE; - } - return 0; + zmw_leave_critical_section(dev); + + zfScanMgrScanStop(dev, ZM_SCAN_MGR_SCAN_INTERNAL); + zfScanMgrScanStop(dev, ZM_SCAN_MGR_SCAN_EXTERNAL); + + /* Turn off Software WEP/TKIP */ + if (wd->sta.SWEncryptEnable != 0) { + zm_debug_msg0("Disable software encryption"); + zfStaDisableSWEncryption(dev); + } + + /* Improve WEP/TKIP performace with HT AP, + detail information please look bug#32495 + */ + /* zfHpSetTTSIFSTime(dev, 0x8); */ + + /* Keep Pseudo mode */ + if (wd->wlanMode != ZM_MODE_PSEUDO) + wd->wlanMode = ZM_MODE_INFRASTRUCTURE; + + return 0; } /* Deauthenticate a STA */ -u16_t zfiWlanDeauth(zdev_t* dev, u16_t* macAddr, u16_t reason) +u16_t zfiWlanDeauth(zdev_t *dev, u16_t *macAddr, u16_t reason) { - zmw_get_wlan_dev(dev); + zmw_get_wlan_dev(dev); - if ( wd->wlanMode == ZM_MODE_AP ) - { - //u16_t id; + if (wd->wlanMode == ZM_MODE_AP) { + /* u16_t id; */ - /* - * we will reset all key in zfHpResetKeyCache() when call - * zfiWlanDisable(), if we want to reset PairwiseKey for each sta, - * need to use a nullAddr to let keyindex not match. - * otherwise hardware will still find PairwiseKey when AP change - * encryption mode from WPA to WEP - */ + /* + * we will reset all key in zfHpResetKeyCache() when call + * zfiWlanDisable(), if we want to reset PairwiseKey for each + * sta, need to use a nullAddr to let keyindex not match. + * otherwise hardware will still find PairwiseKey when AP change + * encryption mode from WPA to WEP + */ - /* - if ((id = zfApFindSta(dev, macAddr)) != 0xffff) - { - u32_t key[8]; - u16_t nullAddr[3] = { 0x0, 0x0, 0x0 }; + /* + if ((id = zfApFindSta(dev, macAddr)) != 0xffff) + { + u32_t key[8]; + u16_t nullAddr[3] = { 0x0, 0x0, 0x0 }; - if (wd->ap.staTable[i].encryMode != ZM_NO_WEP) - { - zfHpSetApPairwiseKey(dev, nullAddr, - ZM_NO_WEP, &key[0], &key[4], i+1); - } - //zfHpSetApPairwiseKey(dev, (u16_t *)macAddr, - // ZM_NO_WEP, &key[0], &key[4], id+1); - wd->ap.staTable[id].encryMode = ZM_NO_WEP; - wd->ap.staTable[id].keyIdx = 0xff; - } - */ + if (wd->ap.staTable[i].encryMode != ZM_NO_WEP) + { + zfHpSetApPairwiseKey(dev, nullAddr, + ZM_NO_WEP, &key[0], &key[4], i+1); + } + //zfHpSetApPairwiseKey(dev, (u16_t *)macAddr, + // ZM_NO_WEP, &key[0], &key[4], id+1); + wd->ap.staTable[id].encryMode = ZM_NO_WEP; + wd->ap.staTable[id].keyIdx = 0xff; + } + */ - zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_DEAUTH, macAddr, reason, 0, 0); - } - else - { - zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_DEAUTH, wd->sta.bssid, 3, 0, 0); - } + zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_DEAUTH, macAddr, + reason, 0, 0); + } else + zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_DEAUTH, + wd->sta.bssid, 3, 0, 0); - /* Issue DEAUTH command to FW */ - return 0; + /* Issue DEAUTH command to FW */ + return 0; } /* XP packet filter feature : */ -/* 1=>enable: All multicast address packets, not just the ones enumerated in the multicast address list. */ +/* 1=>enable: All multicast address packets, not just the ones */ +/* enumerated in the multicast address list. */ /* 0=>disable */ -void zfiWlanSetAllMulticast(zdev_t* dev, u32_t setting) +void zfiWlanSetAllMulticast(zdev_t *dev, u32_t setting) { - zmw_get_wlan_dev(dev); - zm_msg1_mm(ZM_LV_0, "sta.bAllMulticast = ", setting); - wd->sta.bAllMulticast = (u8_t)setting; + zmw_get_wlan_dev(dev); + zm_msg1_mm(ZM_LV_0, "sta.bAllMulticast = ", setting); + wd->sta.bAllMulticast = (u8_t)setting; } /* HT configure API */ -void zfiWlanSetHTCtrl(zdev_t* dev, u32_t *setting, u32_t forceTxTPC) +void zfiWlanSetHTCtrl(zdev_t *dev, u32_t *setting, u32_t forceTxTPC) { - zmw_get_wlan_dev(dev); + zmw_get_wlan_dev(dev); - wd->preambleType = (u8_t)setting[0]; - wd->sta.preambleTypeHT = (u8_t)setting[1]; - wd->sta.htCtrlBandwidth = (u8_t)setting[2]; - wd->sta.htCtrlSTBC = (u8_t)setting[3]; - wd->sta.htCtrlSG = (u8_t)setting[4]; - wd->sta.defaultTA = (u8_t)setting[5]; - wd->enableAggregation = (u8_t)setting[6]; - wd->enableWDS = (u8_t)setting[7]; + wd->preambleType = (u8_t)setting[0]; + wd->sta.preambleTypeHT = (u8_t)setting[1]; + wd->sta.htCtrlBandwidth = (u8_t)setting[2]; + wd->sta.htCtrlSTBC = (u8_t)setting[3]; + wd->sta.htCtrlSG = (u8_t)setting[4]; + wd->sta.defaultTA = (u8_t)setting[5]; + wd->enableAggregation = (u8_t)setting[6]; + wd->enableWDS = (u8_t)setting[7]; - wd->forceTxTPC = forceTxTPC; + wd->forceTxTPC = forceTxTPC; } /* FB50 in OS XP, RD private test code */ -void zfiWlanQueryHTCtrl(zdev_t* dev, u32_t *setting, u32_t *forceTxTPC) +void zfiWlanQueryHTCtrl(zdev_t *dev, u32_t *setting, u32_t *forceTxTPC) { - zmw_get_wlan_dev(dev); + zmw_get_wlan_dev(dev); - setting[0] = wd->preambleType; - setting[1] = wd->sta.preambleTypeHT; - setting[2] = wd->sta.htCtrlBandwidth; - setting[3] = wd->sta.htCtrlSTBC; - setting[4] = wd->sta.htCtrlSG; - setting[5] = wd->sta.defaultTA; - setting[6] = wd->enableAggregation; - setting[7] = wd->enableWDS; + setting[0] = wd->preambleType; + setting[1] = wd->sta.preambleTypeHT; + setting[2] = wd->sta.htCtrlBandwidth; + setting[3] = wd->sta.htCtrlSTBC; + setting[4] = wd->sta.htCtrlSG; + setting[5] = wd->sta.defaultTA; + setting[6] = wd->enableAggregation; + setting[7] = wd->enableWDS; - *forceTxTPC = wd->forceTxTPC; + *forceTxTPC = wd->forceTxTPC; } -void zfiWlanDbg(zdev_t* dev, u8_t setting) +void zfiWlanDbg(zdev_t *dev, u8_t setting) { - zmw_get_wlan_dev(dev); + zmw_get_wlan_dev(dev); - wd->enableHALDbgInfo = setting; + wd->enableHALDbgInfo = setting; } /* FB50 in OS XP, RD private test code */ -void zfiWlanSetRxPacketDump(zdev_t* dev, u32_t setting) +void zfiWlanSetRxPacketDump(zdev_t *dev, u32_t setting) { - zmw_get_wlan_dev(dev); - if (setting) - { - wd->rxPacketDump = 1; /* enable */ - } - else - { - wd->rxPacketDump = 0; /* disable */ - } + zmw_get_wlan_dev(dev); + if (setting) + wd->rxPacketDump = 1; /* enable */ + else + wd->rxPacketDump = 0; /* disable */ } /* FB50 in OS XP, RD private test code */ /* Tally */ -void zfiWlanResetTally(zdev_t* dev) +void zfiWlanResetTally(zdev_t *dev) { - zmw_get_wlan_dev(dev); + zmw_get_wlan_dev(dev); - zmw_declare_for_critical_section(); + zmw_declare_for_critical_section(); - zmw_enter_critical_section(dev); + zmw_enter_critical_section(dev); - wd->commTally.txUnicastFrm = 0; //txUnicastFrames - wd->commTally.txMulticastFrm = 0; //txMulticastFrames - wd->commTally.txUnicastOctets = 0; //txUniOctets byte size - wd->commTally.txMulticastOctets = 0; //txMultiOctets byte size - wd->commTally.txFrmUpperNDIS = 0; - wd->commTally.txFrmDrvMgt = 0; - wd->commTally.RetryFailCnt = 0; - wd->commTally.Hw_TotalTxFrm = 0; //Hardware total Tx Frame - wd->commTally.Hw_RetryCnt = 0; //txMultipleRetriesFrames - wd->commTally.Hw_UnderrunCnt = 0;// - wd->commTally.DriverRxFrmCnt = 0;// - wd->commTally.rxUnicastFrm = 0; //rxUnicastFrames - wd->commTally.rxMulticastFrm = 0; //rxMulticastFrames - wd->commTally.NotifyNDISRxFrmCnt = 0;// - wd->commTally.rxUnicastOctets = 0; //rxUniOctets byte size - wd->commTally.rxMulticastOctets = 0; //rxMultiOctets byte size - wd->commTally.DriverDiscardedFrm = 0;// Discard by ValidateFrame - wd->commTally.LessThanDataMinLen = 0;// - wd->commTally.GreaterThanMaxLen = 0;// - wd->commTally.DriverDiscardedFrmCauseByMulticastList = 0; - wd->commTally.DriverDiscardedFrmCauseByFrmCtrl = 0; - wd->commTally.rxNeedFrgFrm = 0; // need more frg frm - wd->commTally.DriverRxMgtFrmCnt = 0; - wd->commTally.rxBroadcastFrm = 0; //Receive broadcast frame count - wd->commTally.rxBroadcastOctets = 0; //Receive broadcast frame byte size - wd->commTally.Hw_TotalRxFrm = 0;// - wd->commTally.Hw_CRC16Cnt = 0; //rxPLCPCRCErrCnt - wd->commTally.Hw_CRC32Cnt = 0; //rxCRC32ErrCnt - wd->commTally.Hw_DecrypErr_UNI = 0;// - wd->commTally.Hw_DecrypErr_Mul = 0;// - wd->commTally.Hw_RxFIFOOverrun = 0;// - wd->commTally.Hw_RxTimeOut = 0; - wd->commTally.LossAP = 0;// + wd->commTally.txUnicastFrm = 0; /* txUnicastFrames */ + wd->commTally.txMulticastFrm = 0; /* txMulticastFrames */ + wd->commTally.txUnicastOctets = 0; /* txUniOctets byte size */ + wd->commTally.txMulticastOctets = 0; /* txMultiOctets byte size */ + wd->commTally.txFrmUpperNDIS = 0; + wd->commTally.txFrmDrvMgt = 0; + wd->commTally.RetryFailCnt = 0; + wd->commTally.Hw_TotalTxFrm = 0; /* Hardware total Tx Frame */ + wd->commTally.Hw_RetryCnt = 0; /* txMultipleRetriesFrames */ + wd->commTally.Hw_UnderrunCnt = 0; + wd->commTally.DriverRxFrmCnt = 0; + wd->commTally.rxUnicastFrm = 0; /* rxUnicastFrames */ + wd->commTally.rxMulticastFrm = 0; /* rxMulticastFrames */ + wd->commTally.NotifyNDISRxFrmCnt = 0; + wd->commTally.rxUnicastOctets = 0; /* rxUniOctets byte size */ + wd->commTally.rxMulticastOctets = 0; /* rxMultiOctets byte size */ + wd->commTally.DriverDiscardedFrm = 0; /* Discard by ValidateFrame */ + wd->commTally.LessThanDataMinLen = 0; + wd->commTally.GreaterThanMaxLen = 0; + wd->commTally.DriverDiscardedFrmCauseByMulticastList = 0; + wd->commTally.DriverDiscardedFrmCauseByFrmCtrl = 0; + wd->commTally.rxNeedFrgFrm = 0; /* need more frg frm */ + wd->commTally.DriverRxMgtFrmCnt = 0; + wd->commTally.rxBroadcastFrm = 0;/* Receive broadcast frame count */ + wd->commTally.rxBroadcastOctets = 0;/*Receive broadcast framebyte size*/ + wd->commTally.Hw_TotalRxFrm = 0; + wd->commTally.Hw_CRC16Cnt = 0; /* rxPLCPCRCErrCnt */ + wd->commTally.Hw_CRC32Cnt = 0; /* rxCRC32ErrCnt */ + wd->commTally.Hw_DecrypErr_UNI = 0; + wd->commTally.Hw_DecrypErr_Mul = 0; + wd->commTally.Hw_RxFIFOOverrun = 0; + wd->commTally.Hw_RxTimeOut = 0; + wd->commTally.LossAP = 0; - wd->commTally.Tx_MPDU = 0; - wd->commTally.BA_Fail = 0; - wd->commTally.Hw_Tx_AMPDU = 0; - wd->commTally.Hw_Tx_MPDU = 0; + wd->commTally.Tx_MPDU = 0; + wd->commTally.BA_Fail = 0; + wd->commTally.Hw_Tx_AMPDU = 0; + wd->commTally.Hw_Tx_MPDU = 0; - wd->commTally.txQosDropCount[0] = 0; - wd->commTally.txQosDropCount[1] = 0; - wd->commTally.txQosDropCount[2] = 0; - wd->commTally.txQosDropCount[3] = 0; - wd->commTally.txQosDropCount[4] = 0; + wd->commTally.txQosDropCount[0] = 0; + wd->commTally.txQosDropCount[1] = 0; + wd->commTally.txQosDropCount[2] = 0; + wd->commTally.txQosDropCount[3] = 0; + wd->commTally.txQosDropCount[4] = 0; - wd->commTally.Hw_RxMPDU = 0; - wd->commTally.Hw_RxDropMPDU = 0; - wd->commTally.Hw_RxDelMPDU = 0; + wd->commTally.Hw_RxMPDU = 0; + wd->commTally.Hw_RxDropMPDU = 0; + wd->commTally.Hw_RxDelMPDU = 0; - wd->commTally.Hw_RxPhyMiscError = 0; - wd->commTally.Hw_RxPhyXRError = 0; - wd->commTally.Hw_RxPhyOFDMError = 0; - wd->commTally.Hw_RxPhyCCKError = 0; - wd->commTally.Hw_RxPhyHTError = 0; - wd->commTally.Hw_RxPhyTotalCount = 0; + wd->commTally.Hw_RxPhyMiscError = 0; + wd->commTally.Hw_RxPhyXRError = 0; + wd->commTally.Hw_RxPhyOFDMError = 0; + wd->commTally.Hw_RxPhyCCKError = 0; + wd->commTally.Hw_RxPhyHTError = 0; + wd->commTally.Hw_RxPhyTotalCount = 0; -#if (defined(GCCK) && defined(OFDM)) - wd->commTally.rx11bDataFrame = 0; - wd->commTally.rxOFDMDataFrame = 0; +#if (defined(GCCK) && defined(OFDM)) + wd->commTally.rx11bDataFrame = 0; + wd->commTally.rxOFDMDataFrame = 0; #endif - zmw_leave_critical_section(dev); + zmw_leave_critical_section(dev); } /* FB50 in OS XP, RD private test code */ -void zfiWlanQueryTally(zdev_t* dev, struct zsCommTally *tally) +void zfiWlanQueryTally(zdev_t *dev, struct zsCommTally *tally) { - zmw_get_wlan_dev(dev); + zmw_get_wlan_dev(dev); - zmw_declare_for_critical_section(); + zmw_declare_for_critical_section(); - zmw_enter_critical_section(dev); - zfMemoryCopy((u8_t*)tally, (u8_t*)&wd->commTally, sizeof(struct zsCommTally)); - zmw_leave_critical_section(dev); -} -void zfiWlanQueryTrafTally(zdev_t* dev, struct zsTrafTally *tally) -{ - zmw_get_wlan_dev(dev); - - zmw_declare_for_critical_section(); - - zmw_enter_critical_section(dev); - zfMemoryCopy((u8_t*)tally, (u8_t*)&wd->trafTally, sizeof(struct zsTrafTally)); - zmw_leave_critical_section(dev); + zmw_enter_critical_section(dev); + zfMemoryCopy((u8_t *)tally, (u8_t *)&wd->commTally, + sizeof(struct zsCommTally)); + zmw_leave_critical_section(dev); } -void zfiWlanQueryMonHalRxInfo(zdev_t* dev, struct zsMonHalRxInfo *monHalRxInfo) +void zfiWlanQueryTrafTally(zdev_t *dev, struct zsTrafTally *tally) { - zfHpQueryMonHalRxInfo(dev, (u8_t *)monHalRxInfo); + zmw_get_wlan_dev(dev); + + zmw_declare_for_critical_section(); + + zmw_enter_critical_section(dev); + zfMemoryCopy((u8_t *)tally, (u8_t *)&wd->trafTally, + sizeof(struct zsTrafTally)); + zmw_leave_critical_section(dev); +} + +void zfiWlanQueryMonHalRxInfo(zdev_t *dev, struct zsMonHalRxInfo *monHalRxInfo) +{ + zfHpQueryMonHalRxInfo(dev, (u8_t *)monHalRxInfo); } /* parse the modeMDKEnable to DrvCore */ -void zfiDKEnable(zdev_t* dev, u32_t enable) +void zfiDKEnable(zdev_t *dev, u32_t enable) { - zmw_get_wlan_dev(dev); + zmw_get_wlan_dev(dev); - wd->modeMDKEnable = enable; - zm_debug_msg1("modeMDKEnable = ", wd->modeMDKEnable); + wd->modeMDKEnable = enable; + zm_debug_msg1("modeMDKEnable = ", wd->modeMDKEnable); } /* airoPeek */ -u32_t zfiWlanQueryPacketTypePromiscuous(zdev_t* dev) +u32_t zfiWlanQueryPacketTypePromiscuous(zdev_t *dev) { - zmw_get_wlan_dev(dev); + zmw_get_wlan_dev(dev); - return wd->swSniffer; + return wd->swSniffer; } /* airoPeek */ -void zfiWlanSetPacketTypePromiscuous(zdev_t* dev, u32_t setValue) +void zfiWlanSetPacketTypePromiscuous(zdev_t *dev, u32_t setValue) { - zmw_get_wlan_dev(dev); + zmw_get_wlan_dev(dev); - wd->swSniffer = setValue; - zm_msg1_mm(ZM_LV_0, "wd->swSniffer ", wd->swSniffer); - if (setValue) - { - /* write register for sniffer mode */ - zfHpSetSnifferMode(dev, 1); - zm_msg0_mm(ZM_LV_1, "enalbe sniffer mode"); - } - else - { - zfHpSetSnifferMode(dev, 0); - zm_msg0_mm(ZM_LV_0, "disalbe sniffer mode"); - } + wd->swSniffer = setValue; + zm_msg1_mm(ZM_LV_0, "wd->swSniffer ", wd->swSniffer); + if (setValue) { + /* write register for sniffer mode */ + zfHpSetSnifferMode(dev, 1); + zm_msg0_mm(ZM_LV_1, "enalbe sniffer mode"); + } else { + zfHpSetSnifferMode(dev, 0); + zm_msg0_mm(ZM_LV_0, "disalbe sniffer mode"); + } } -void zfiWlanSetXLinkMode(zdev_t* dev, u32_t setValue) +void zfiWlanSetXLinkMode(zdev_t *dev, u32_t setValue) { - zmw_get_wlan_dev(dev); + zmw_get_wlan_dev(dev); - wd->XLinkMode = setValue; - if (setValue) - { - /* write register for sniffer mode */ - zfHpSetSnifferMode(dev, 1); - } - else - { - zfHpSetSnifferMode(dev, 0); - } + wd->XLinkMode = setValue; + if (setValue) { + /* write register for sniffer mode */ + zfHpSetSnifferMode(dev, 1); + } else + zfHpSetSnifferMode(dev, 0); } -extern void zfStaChannelManagement(zdev_t* dev, u8_t scan); -void zfiSetChannelManagement(zdev_t* dev, u32_t setting) +extern void zfStaChannelManagement(zdev_t *dev, u8_t scan); + +void zfiSetChannelManagement(zdev_t *dev, u32_t setting) { - zmw_get_wlan_dev(dev); + zmw_get_wlan_dev(dev); - switch (setting) - { - case 1: - wd->sta.EnableHT = 1; - wd->BandWidth40 = 1; - wd->ExtOffset = 1; - break; - case 3: - wd->sta.EnableHT = 1; - wd->BandWidth40 = 1; - wd->ExtOffset = 3; - break; - case 0: - wd->sta.EnableHT = 1; - wd->BandWidth40 = 0; - wd->ExtOffset = 0; - break; - default: - wd->BandWidth40 = 0; - wd->ExtOffset = 0; - break; + switch (setting) { + case 1: + wd->sta.EnableHT = 1; + wd->BandWidth40 = 1; + wd->ExtOffset = 1; + break; + case 3: + wd->sta.EnableHT = 1; + wd->BandWidth40 = 1; + wd->ExtOffset = 3; + break; + case 0: + wd->sta.EnableHT = 1; + wd->BandWidth40 = 0; + wd->ExtOffset = 0; + break; + default: + wd->BandWidth40 = 0; + wd->ExtOffset = 0; + break; + } - } - zfCoreSetFrequencyEx(dev, wd->frequency, wd->BandWidth40, - wd->ExtOffset, NULL); + zfCoreSetFrequencyEx(dev, wd->frequency, wd->BandWidth40, + wd->ExtOffset, NULL); } -void zfiSetRifs(zdev_t* dev, u16_t setting) +void zfiSetRifs(zdev_t *dev, u16_t setting) { - zmw_get_wlan_dev(dev); + zmw_get_wlan_dev(dev); - wd->sta.ie.HtInfo.ChannelInfo |= ExtHtCap_RIFSMode; - wd->sta.EnableHT = 1; - switch (setting) - { - case 0: - wd->sta.HT2040 = 0; -// zfHpSetRifs(dev, 1, 0, (wd->sta.currentFrequency < 3000)? 1:0); - break; - case 1: - wd->sta.HT2040 = 1; -// zfHpSetRifs(dev, 1, 1, (wd->sta.currentFrequency < 3000)? 1:0); - break; - default: - wd->sta.HT2040 = 0; -// zfHpSetRifs(dev, 1, 0, (wd->sta.currentFrequency < 3000)? 1:0); - break; - } + wd->sta.ie.HtInfo.ChannelInfo |= ExtHtCap_RIFSMode; + wd->sta.EnableHT = 1; + + switch (setting) { + case 0: + wd->sta.HT2040 = 0; + /* zfHpSetRifs(dev, 1, 0, + * (wd->sta.currentFrequency < 3000)? 1:0); + */ + break; + case 1: + wd->sta.HT2040 = 1; + /* zfHpSetRifs(dev, 1, 1, + * (wd->sta.currentFrequency < 3000)? 1:0); + */ + break; + default: + wd->sta.HT2040 = 0; + /* zfHpSetRifs(dev, 1, 0, + * (wd->sta.currentFrequency < 3000)? 1:0); + */ + break; + } } -void zfiCheckRifs(zdev_t* dev) +void zfiCheckRifs(zdev_t *dev) { - zmw_get_wlan_dev(dev); + zmw_get_wlan_dev(dev); - if(wd->sta.ie.HtInfo.ChannelInfo & ExtHtCap_RIFSMode) - { -// zfHpSetRifs(dev, wd->sta.EnableHT, wd->sta.HT2040, (wd->sta.currentFrequency < 3000)? 1:0); - } + if (wd->sta.ie.HtInfo.ChannelInfo & ExtHtCap_RIFSMode) + ; + /* zfHpSetRifs(dev, wd->sta.EnableHT, wd->sta.HT2040, + * (wd->sta.currentFrequency < 3000)? 1:0); + */ } -void zfiSetReorder(zdev_t* dev, u16_t value) +void zfiSetReorder(zdev_t *dev, u16_t value) { - zmw_get_wlan_dev(dev); + zmw_get_wlan_dev(dev); - wd->reorder = value; + wd->reorder = value; } -void zfiSetSeqDebug(zdev_t* dev, u16_t value) +void zfiSetSeqDebug(zdev_t *dev, u16_t value) { - zmw_get_wlan_dev(dev); + zmw_get_wlan_dev(dev); - wd->seq_debug = value; + wd->seq_debug = value; } diff --git a/drivers/staging/otus/80211core/coid.c b/drivers/staging/otus/80211core/coid.c index 88f8d3491a80..0524e1f36f0d 100644 --- a/drivers/staging/otus/80211core/coid.c +++ b/drivers/staging/otus/80211core/coid.c @@ -2013,7 +2013,7 @@ u16_t zfiConfigWdsPort(zdev_t* dev, u8_t wdsPortId, u16_t flag, u16_t* wdsAddr, zmw_get_wlan_dev(dev); - if (wdsPortId > ZM_MAX_WDS_SUPPORT) + if (wdsPortId >= ZM_MAX_WDS_SUPPORT) { return ZM_ERR_WDS_PORT_ID; } diff --git a/drivers/staging/p9auth/p9auth.c b/drivers/staging/p9auth/p9auth.c index 3cac89b26faf..9111dcba37a1 100644 --- a/drivers/staging/p9auth/p9auth.c +++ b/drivers/staging/p9auth/p9auth.c @@ -180,8 +180,12 @@ static ssize_t cap_write(struct file *filp, const char __user *buf, if (down_interruptible(&dev->sem)) return -ERESTARTSYS; + user_buf_running = NULL; + hash_str = NULL; node_ptr = kmalloc(sizeof(struct cap_node), GFP_KERNEL); user_buf = kzalloc(count, GFP_KERNEL); + if (!node_ptr || !user_buf) + goto out; if (copy_from_user(user_buf, buf, count)) { retval = -EFAULT; @@ -193,11 +197,21 @@ static ssize_t cap_write(struct file *filp, const char __user *buf, * hashed capability supplied by the user to the list of hashes */ if (0 == iminor(filp->f_dentry->d_inode)) { + if (count > CAP_NODE_SIZE) { + retval = -EINVAL; + goto out; + } printk(KERN_INFO "Capability being written to /dev/caphash : \n"); hexdump(user_buf, count); memcpy(node_ptr->data, user_buf, count); list_add(&(node_ptr->list), &(dev->head->list)); + node_ptr = NULL; } else { + if (!cap_devices[0].head || + list_empty(&(cap_devices[0].head->list))) { + retval = -EINVAL; + goto out; + } /* * break the supplied string into tokens with @ as the * delimiter If the string is "user1@user2@randomstring" we @@ -208,6 +222,10 @@ static ssize_t cap_write(struct file *filp, const char __user *buf, source_user = strsep(&user_buf_running, "@"); target_user = strsep(&user_buf_running, "@"); rand_str = strsep(&user_buf_running, "@"); + if (!source_user || !target_user || !rand_str) { + retval = -EINVAL; + goto out; + } /* hash the string user1@user2 with rand_str as the key */ len = strlen(source_user) + strlen(target_user) + 1; @@ -224,7 +242,7 @@ static ssize_t cap_write(struct file *filp, const char __user *buf, retval = -EFAULT; goto out; } - memcpy(node_ptr->data, result, CAP_NODE_SIZE); + memcpy(node_ptr->data, result, CAP_NODE_SIZE); /* why? */ /* Change the process's uid if the hash is present in the * list of hashes */ @@ -299,6 +317,10 @@ static ssize_t cap_write(struct file *filp, const char __user *buf, dev->size = *f_pos; out: + kfree(node_ptr); + kfree(user_buf); + kfree(user_buf_running); + kfree(hash_str); up(&dev->sem); return retval; } diff --git a/drivers/staging/panel/lcd-panel-cgram.txt b/drivers/staging/panel/lcd-panel-cgram.txt index f9ceef4322a3..7f82c905763d 100644 --- a/drivers/staging/panel/lcd-panel-cgram.txt +++ b/drivers/staging/panel/lcd-panel-cgram.txt @@ -3,7 +3,7 @@ characters 0 to 7. The escape code to define a new character is '\e[LG' followed by one digit from 0 to 7, representing the character number, and up to 8 couples of hex digits terminated by a semi-colon (';'). Each couple of digits represents a line, with 1-bits for each -illuminated pixel with LSB on the right. Lines are numberred from the +illuminated pixel with LSB on the right. Lines are numbered from the top of the character to the bottom. On a 5x7 matrix, only the 5 lower bits of the 7 first bytes are used for each character. If the string is incomplete, only complete lines will be redefined. Here are some diff --git a/drivers/staging/pata_rdc/Kconfig b/drivers/staging/pata_rdc/Kconfig new file mode 100644 index 000000000000..7a406b023057 --- /dev/null +++ b/drivers/staging/pata_rdc/Kconfig @@ -0,0 +1,6 @@ +config RDC_17F3101X + tristate "RDC_17F3101X IDE support" + depends on PCI && ATA && ATA_SFF + ---help--- + This is an experimental driver for RDC_17F31011 and + RDC_17F31012 IDE driver. diff --git a/drivers/staging/pata_rdc/Makefile b/drivers/staging/pata_rdc/Makefile new file mode 100644 index 000000000000..f952c16f4b28 --- /dev/null +++ b/drivers/staging/pata_rdc/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_RDC_17F3101X) += pata_rdc.o + diff --git a/drivers/staging/pata_rdc/pata_rdc.c b/drivers/staging/pata_rdc/pata_rdc.c new file mode 100644 index 000000000000..6252745250ef --- /dev/null +++ b/drivers/staging/pata_rdc/pata_rdc.c @@ -0,0 +1,955 @@ +#include +#include +#include + +#include +#include + +#include +#include + +#include "pata_rdc.h" + +static const struct pci_device_id rdc_pata_id_table[] = { + { PCI_DEVICE(0x17F3, 0x1011), RDC_17F31011}, + { PCI_DEVICE(0x17F3, 0x1012), RDC_17F31012}, + { } /* terminate list */ +}; +MODULE_DEVICE_TABLE(pci, rdc_pata_id_table); + +/* see ATA Host Adapters Standards. */ +static struct pci_bits ATA_Decode_Enable_Bits[] = { + { 0x41U, 1U, 0x80UL, 0x80UL }, /* port (Channel) 0 */ + { 0x43U, 1U, 0x80UL, 0x80UL }, /* port (Channel) 1 */ +}; + +static uint PCIDeviceIO_ReadPCIConfiguration(struct pci_dev *pdev, uint Offset, uint Length, void *pBuffer) +{ + uint funcresult; + unchar *pchar; + uint i; + + funcresult = TRUE; + + pchar = pBuffer; + + for (i = 0; i < Length; i++) { + pci_read_config_byte(pdev, Offset, pchar); + Offset++; + pchar++; + } + + funcresult = TRUE; + + goto funcexit; +funcexit: + + return funcresult; +} + +static uint PCIDeviceIO_WritePCIConfiguration(struct pci_dev *pdev, uint Offset, uint Length, void *pBuffer) +{ + uint funcresult; + unchar *pchar; + uint i; + + funcresult = TRUE; + + pchar = pBuffer; + + for (i = 0; i < Length; i++) { + pci_write_config_byte(pdev, Offset, *pchar); + Offset++; + pchar++; + } + + funcresult = TRUE; + + goto funcexit; +funcexit: + + return funcresult; +} + +static uint ATAHostAdapter_SetPrimaryPIO(struct pci_dev *pdev, uint DeviceID, + uint PIOTimingMode, uint DMAEnable, + uint PrefetchPostingEnable) +{ + uint funcresult; + uint result; + uint ATATimingRegister; + uint Device1TimingRegister; + + funcresult = TRUE; + + ATATimingRegister = 0; + Device1TimingRegister = 0; + + result = PCIDeviceIO_ReadPCIConfiguration(pdev, + ATAConfiguration_ID_PrimaryTiming + ATAConfiguration_PCIOffset, + ATAConfiguration_ID_PrimaryTiming_Size, + &ATATimingRegister); + if (result == FALSE) { + funcresult = FALSE; + goto funcexit; + } + + result = PCIDeviceIO_ReadPCIConfiguration(pdev, + ATAConfiguration_ID_Device1Timing + ATAConfiguration_PCIOffset, + ATAConfiguration_ID_Device1Timing_Size, + &Device1TimingRegister); + if (result == FALSE) { + funcresult = FALSE; + goto funcexit; + } + + ATATimingRegister |= ATAConfiguration_PrimaryTiming_Device1TimingRegisterEnable; + + switch (DeviceID) { + case 0: + /* mask clear */ + ATATimingRegister &= ~(ATAConfiguration_PrimaryTiming_Device0FastTimingEnable | + ATAConfiguration_PrimaryTiming_Device0IORDYSampleModeEnable | + ATAConfiguration_PrimaryTiming_Device0PrefetchandPostingEnable | + ATAConfiguration_PrimaryTiming_Device0DMATimingEnable | + ATAConfiguration_PrimaryTiming_Device0RecoveryMode | + ATAConfiguration_PrimaryTiming_Device0IORDYSampleMode); + + if (PIOTimingMode > PIO0) + ATATimingRegister |= ATAConfiguration_PrimaryTiming_Device0FastTimingEnable; + + if (PIOTimingMode >= PIO3) + ATATimingRegister |= ATAConfiguration_PrimaryTiming_Device0IORDYSampleModeEnable; + + if (PIOTimingMode >= PIO2 && PrefetchPostingEnable == TRUE) + ATATimingRegister |= ATAConfiguration_PrimaryTiming_Device0PrefetchandPostingEnable; + + if (DMAEnable == TRUE && PIOTimingMode >= PIO2) + ATATimingRegister |= ATAConfiguration_PrimaryTiming_Device0DMATimingEnable; + + if (PIOTimingMode <= PIO2) + ATATimingRegister |= ATAConfiguration_PrimaryTiming_Device0RecoveryMode_0; + else if (PIOTimingMode == PIO3) + ATATimingRegister |= ATAConfiguration_PrimaryTiming_Device0RecoveryMode_1; + else if (PIOTimingMode == PIO4) + ATATimingRegister |= ATAConfiguration_PrimaryTiming_Device0RecoveryMode_3; + + if (PIOTimingMode <= PIO1) + ATATimingRegister |= ATAConfiguration_PrimaryTiming_Device0IORDYSampleMode_0; + else if (PIOTimingMode == PIO2) + ATATimingRegister |= ATAConfiguration_PrimaryTiming_Device0IORDYSampleMode_1; + else if (PIOTimingMode <= PIO4) + ATATimingRegister |= ATAConfiguration_PrimaryTiming_Device0IORDYSampleMode_2; + break; + case 1: + ATATimingRegister &= ~(ATAConfiguration_PrimaryTiming_Device1FastTimingEnable | + ATAConfiguration_PrimaryTiming_Device1IORDYSampleModeEnable | + ATAConfiguration_PrimaryTiming_Device1PrefetchandPostingEnable | + ATAConfiguration_PrimaryTiming_Device1DMATimingEnable); + + if (PIOTimingMode > PIO0) + ATATimingRegister |= ATAConfiguration_PrimaryTiming_Device1FastTimingEnable; + + if (PIOTimingMode >= PIO3) + ATATimingRegister |= ATAConfiguration_PrimaryTiming_Device1IORDYSampleModeEnable; + + if (PIOTimingMode >= PIO2 && PrefetchPostingEnable == TRUE) + ATATimingRegister |= ATAConfiguration_PrimaryTiming_Device1PrefetchandPostingEnable; + + if (DMAEnable == TRUE && PIOTimingMode >= PIO2) + ATATimingRegister |= ATAConfiguration_PrimaryTiming_Device1DMATimingEnable; + + Device1TimingRegister &= ~(ATAConfiguration_Device1Timing_PrimaryRecoveryMode | + ATAConfiguration_Device1Timing_PrimaryIORDYSampleMode); + + if (PIOTimingMode <= PIO2) + Device1TimingRegister |= ATAConfiguration_Device1Timing_PrimaryRecoveryMode_0; + else if (PIOTimingMode == PIO3) + Device1TimingRegister |= ATAConfiguration_Device1Timing_PrimaryRecoveryMode_1; + else if (PIOTimingMode == PIO4) + Device1TimingRegister |= ATAConfiguration_Device1Timing_PrimaryRecoveryMode_3; + + if (PIOTimingMode <= PIO1) + Device1TimingRegister |= ATAConfiguration_Device1Timing_PrimaryIORDYSampleMode_0; + else if (PIOTimingMode == PIO2) + Device1TimingRegister |= ATAConfiguration_Device1Timing_PrimaryIORDYSampleMode_1; + else if (PIOTimingMode <= PIO4) + Device1TimingRegister |= ATAConfiguration_Device1Timing_PrimaryIORDYSampleMode_2; + break; + default: + funcresult = FALSE; + goto funcexit; + break; + } + + result = PCIDeviceIO_WritePCIConfiguration(pdev, + ATAConfiguration_ID_PrimaryTiming + ATAConfiguration_PCIOffset, + ATAConfiguration_ID_PrimaryTiming_Size, + &ATATimingRegister); + if (result == FALSE) { + funcresult = FALSE; + goto funcexit; + } + + result = PCIDeviceIO_WritePCIConfiguration(pdev, + ATAConfiguration_ID_Device1Timing + ATAConfiguration_PCIOffset, + ATAConfiguration_ID_Device1Timing_Size, + &Device1TimingRegister); + if (result == FALSE) { + funcresult = FALSE; + goto funcexit; + } + + goto funcexit; +funcexit: + + return funcresult; +} + +static uint ATAHostAdapter_SetSecondaryPIO(struct pci_dev *pdev, uint DeviceID, + uint PIOTimingMode, uint DMAEnable, + uint PrefetchPostingEnable) +{ + uint funcresult; + uint result; + uint ATATimingRegister; + uint Device1TimingRegister; + + funcresult = TRUE; + + ATATimingRegister = 0; + Device1TimingRegister = 0; + + result = PCIDeviceIO_ReadPCIConfiguration(pdev, + ATAConfiguration_ID_SecondaryTiming + ATAConfiguration_PCIOffset, + ATAConfiguration_ID_SecondaryTiming_Size, + &ATATimingRegister); + if (result == FALSE) { + funcresult = FALSE; + goto funcexit; + } + + result = PCIDeviceIO_ReadPCIConfiguration(pdev, + ATAConfiguration_ID_Device1Timing + ATAConfiguration_PCIOffset, + ATAConfiguration_ID_Device1Timing_Size, + &Device1TimingRegister); + if (result == FALSE) { + funcresult = FALSE; + goto funcexit; + } + + ATATimingRegister |= ATAConfiguration_PrimaryTiming_Device1TimingRegisterEnable; + + switch (DeviceID) { + case 0: + /* mask clear */ + ATATimingRegister &= ~(ATAConfiguration_PrimaryTiming_Device0FastTimingEnable | + ATAConfiguration_PrimaryTiming_Device0IORDYSampleModeEnable | + ATAConfiguration_PrimaryTiming_Device0PrefetchandPostingEnable | + ATAConfiguration_PrimaryTiming_Device0DMATimingEnable | + ATAConfiguration_PrimaryTiming_Device0RecoveryMode | + ATAConfiguration_PrimaryTiming_Device0IORDYSampleMode); + + if (PIOTimingMode > PIO0) + ATATimingRegister |= ATAConfiguration_PrimaryTiming_Device0FastTimingEnable; + + if (PIOTimingMode >= PIO3) + ATATimingRegister |= ATAConfiguration_PrimaryTiming_Device0IORDYSampleModeEnable; + + if (PIOTimingMode >= PIO2 && PrefetchPostingEnable == TRUE) + ATATimingRegister |= ATAConfiguration_PrimaryTiming_Device0PrefetchandPostingEnable; + + if (DMAEnable == TRUE && PIOTimingMode >= PIO2) + ATATimingRegister |= ATAConfiguration_PrimaryTiming_Device0DMATimingEnable; + + if (PIOTimingMode <= PIO2) + ATATimingRegister |= ATAConfiguration_PrimaryTiming_Device0RecoveryMode_0; + else if (PIOTimingMode == PIO3) + ATATimingRegister |= ATAConfiguration_PrimaryTiming_Device0RecoveryMode_1; + else if (PIOTimingMode == PIO4) + ATATimingRegister |= ATAConfiguration_PrimaryTiming_Device0RecoveryMode_3; + + if (PIOTimingMode <= PIO1) + ATATimingRegister |= ATAConfiguration_PrimaryTiming_Device0IORDYSampleMode_0; + else if (PIOTimingMode == PIO2) + ATATimingRegister |= ATAConfiguration_PrimaryTiming_Device0IORDYSampleMode_1; + else if (PIOTimingMode <= PIO4) + ATATimingRegister |= ATAConfiguration_PrimaryTiming_Device0IORDYSampleMode_2; + break; + case 1: + ATATimingRegister &= ~(ATAConfiguration_PrimaryTiming_Device1FastTimingEnable | + ATAConfiguration_PrimaryTiming_Device1IORDYSampleModeEnable | + ATAConfiguration_PrimaryTiming_Device1PrefetchandPostingEnable | + ATAConfiguration_PrimaryTiming_Device1DMATimingEnable); + + if (PIOTimingMode > PIO0) + ATATimingRegister |= ATAConfiguration_PrimaryTiming_Device1FastTimingEnable; + + if (PIOTimingMode >= PIO3) + ATATimingRegister |= ATAConfiguration_PrimaryTiming_Device1IORDYSampleModeEnable; + + if (PIOTimingMode >= PIO2 && PrefetchPostingEnable == TRUE) + ATATimingRegister |= ATAConfiguration_PrimaryTiming_Device1PrefetchandPostingEnable; + + if (DMAEnable == TRUE && PIOTimingMode >= PIO2) + ATATimingRegister |= ATAConfiguration_PrimaryTiming_Device1DMATimingEnable; + + Device1TimingRegister &= ~(ATAConfiguration_Device1Timing_SecondaryRecoveryMode | + ATAConfiguration_Device1Timing_SecondaryIORDYSampleMode); + + if (PIOTimingMode <= PIO2) + Device1TimingRegister |= ATAConfiguration_Device1Timing_SecondaryRecoveryMode_0; + else if (PIOTimingMode == PIO3) + Device1TimingRegister |= ATAConfiguration_Device1Timing_SecondaryRecoveryMode_1; + else if (PIOTimingMode == PIO4) + Device1TimingRegister |= ATAConfiguration_Device1Timing_SecondaryRecoveryMode_3; + + if (PIOTimingMode <= PIO1) + Device1TimingRegister |= ATAConfiguration_Device1Timing_SecondaryIORDYSampleMode_0; + else if (PIOTimingMode == PIO2) + Device1TimingRegister |= ATAConfiguration_Device1Timing_SecondaryIORDYSampleMode_1; + else if (PIOTimingMode <= PIO4) + Device1TimingRegister |= ATAConfiguration_Device1Timing_SecondaryIORDYSampleMode_2; + break; + default: + funcresult = FALSE; + goto funcexit; + break; + } + + result = PCIDeviceIO_WritePCIConfiguration(pdev, + ATAConfiguration_ID_SecondaryTiming + ATAConfiguration_PCIOffset, + ATAConfiguration_ID_SecondaryTiming_Size, + &ATATimingRegister); + if (result == FALSE) { + funcresult = FALSE; + goto funcexit; + } + + result = PCIDeviceIO_WritePCIConfiguration(pdev, + ATAConfiguration_ID_Device1Timing + ATAConfiguration_PCIOffset, + ATAConfiguration_ID_Device1Timing_Size, + &Device1TimingRegister); + if (result == FALSE) { + funcresult = FALSE; + goto funcexit; + } + + goto funcexit; +funcexit: + return funcresult; +} + +static uint ATAHostAdapter_SetPrimaryUDMA(struct pci_dev *pdev, uint DeviceID, + uint UDMAEnable, uint UDMATimingMode) +{ + uint funcresult; + uint result; + uint UDMAControlRegister; + uint UDMATimingRegister; + ulong IDEIOConfigurationRegister; + + funcresult = TRUE; + UDMAControlRegister = 0; + UDMATimingRegister = 0; + IDEIOConfigurationRegister = 0; + + result = PCIDeviceIO_ReadPCIConfiguration(pdev, + ATAConfiguration_ID_UDMAControl + ATAConfiguration_PCIOffset, + ATAConfiguration_ID_UDMAControl_Size, + &UDMAControlRegister); + if (result == FALSE) { + funcresult = FALSE; + goto funcexit; + } + + result = PCIDeviceIO_ReadPCIConfiguration(pdev, + ATAConfiguration_ID_UDMATiming + ATAConfiguration_PCIOffset, + ATAConfiguration_ID_UDMATiming_Size, + &UDMATimingRegister); + if (result == FALSE) { + funcresult = FALSE; + goto funcexit; + } + + result = PCIDeviceIO_ReadPCIConfiguration(pdev, + ATAConfiguration_ID_IDEIOConfiguration + ATAConfiguration_PCIOffset, + ATAConfiguration_ID_IDEIOConfiguration_Size, + &IDEIOConfigurationRegister); + if (result == FALSE) { + funcresult = FALSE; + goto funcexit; + } + + /*Rom Code will determine the device cable type and ATA 100.*/ + /*IDEIOConfigurationRegister |= ATAConfiguration_IDEIOConfiguration_DeviceCable80Report;*/ + /*IDEIOConfigurationRegister |= ATAConfiguration_IDEIOConfiguration_ATA100IsSupported;*/ + + switch (DeviceID) { + case 0: + UDMAControlRegister &= ~(ATAConfiguration_UDMAControl_PrimaryDevice0UDMAModeEnable); + if (UDMAEnable == TRUE) + UDMAControlRegister |= ATAConfiguration_UDMAControl_PrimaryDevice0UDMAModeEnable; + + IDEIOConfigurationRegister &= ~(ATAConfiguration_IDEIOConfiguration_PrimaryDevice066MhzEnable | + ATAConfiguration_IDEIOConfiguration_PrimaryDevice0100MhzEnable); + + if (UDMATimingMode >= UDMA5) + IDEIOConfigurationRegister |= ATAConfiguration_IDEIOConfiguration_PrimaryDevice0100MhzEnable; + else if (UDMATimingMode >= UDMA3) + IDEIOConfigurationRegister |= ATAConfiguration_IDEIOConfiguration_PrimaryDevice066MhzEnable; + + /* if 80 cable report */ + UDMATimingRegister &= ~(ATAConfiguration_UDMATiming_PrimaryDevice0CycleTime); + + if (UDMATimingMode == UDMA0) { + UDMATimingRegister |= ATAConfiguration_UDMATiming_PrimaryDevice0CycleTime_0; + } else if (UDMATimingMode == UDMA1 || + UDMATimingMode == UDMA3 || + UDMATimingMode == UDMA5) { + UDMATimingRegister |= ATAConfiguration_UDMATiming_PrimaryDevice0CycleTime_1; + } else if (UDMATimingMode == UDMA2 || + UDMATimingMode == UDMA4) { + UDMATimingRegister |= ATAConfiguration_UDMATiming_PrimaryDevice0CycleTime_2; + } + break; + case 1: + UDMAControlRegister &= ~(ATAConfiguration_UDMAControl_PrimaryDevice1UDMAModeEnable); + if (UDMAEnable == TRUE) + UDMAControlRegister |= ATAConfiguration_UDMAControl_PrimaryDevice1UDMAModeEnable; + + IDEIOConfigurationRegister &= ~(ATAConfiguration_IDEIOConfiguration_PrimaryDevice166MhzEnable | + ATAConfiguration_IDEIOConfiguration_PrimaryDevice1100MhzEnable); + + if (UDMATimingMode >= UDMA5) + IDEIOConfigurationRegister |= ATAConfiguration_IDEIOConfiguration_PrimaryDevice1100MhzEnable; + else if (UDMATimingMode >= UDMA3) + IDEIOConfigurationRegister |= ATAConfiguration_IDEIOConfiguration_PrimaryDevice166MhzEnable; + + /* if 80 cable report */ + UDMATimingRegister &= ~(ATAConfiguration_UDMATiming_PrimaryDevice1CycleTime); + + if (UDMATimingMode == UDMA0) { + UDMATimingRegister |= ATAConfiguration_UDMATiming_PrimaryDevice1CycleTime_0; + } else if (UDMATimingMode == UDMA1 || + UDMATimingMode == UDMA3 || + UDMATimingMode == UDMA5) { + UDMATimingRegister |= ATAConfiguration_UDMATiming_PrimaryDevice1CycleTime_1; + } else if (UDMATimingMode == UDMA2 || + UDMATimingMode == UDMA4) { + UDMATimingRegister |= ATAConfiguration_UDMATiming_PrimaryDevice1CycleTime_2; + } + break; + default: + funcresult = FALSE; + goto funcexit; + break; + } + + result = PCIDeviceIO_WritePCIConfiguration(pdev, + ATAConfiguration_ID_UDMAControl + ATAConfiguration_PCIOffset, + ATAConfiguration_ID_UDMAControl_Size, + &UDMAControlRegister); + if (result == FALSE) { + funcresult = FALSE; + goto funcexit; + } + + result = PCIDeviceIO_WritePCIConfiguration(pdev, + ATAConfiguration_ID_UDMATiming + ATAConfiguration_PCIOffset, + ATAConfiguration_ID_UDMATiming_Size, + &UDMATimingRegister); + if (result == FALSE) { + funcresult = FALSE; + goto funcexit; + } + + result = PCIDeviceIO_WritePCIConfiguration(pdev, + ATAConfiguration_ID_IDEIOConfiguration + ATAConfiguration_PCIOffset, + ATAConfiguration_ID_IDEIOConfiguration_Size, + &IDEIOConfigurationRegister); + if (result == FALSE) { + funcresult = FALSE; + goto funcexit; + } + + goto funcexit; +funcexit: + return funcresult; +} + +static uint ATAHostAdapter_SetSecondaryUDMA(struct pci_dev *pdev, uint DeviceID, + uint UDMAEnable, uint UDMATimingMode) +{ + uint funcresult; + uint result; + uint UDMAControlRegister; + uint UDMATimingRegister; + ulong IDEIOConfigurationRegister; + + funcresult = TRUE; + + UDMAControlRegister = 0; + UDMATimingRegister = 0; + IDEIOConfigurationRegister = 0; + + result = PCIDeviceIO_ReadPCIConfiguration(pdev, + ATAConfiguration_ID_UDMAControl + ATAConfiguration_PCIOffset, + ATAConfiguration_ID_UDMAControl_Size, + &UDMAControlRegister); + if (result == FALSE) { + funcresult = FALSE; + goto funcexit; + } + + result = PCIDeviceIO_ReadPCIConfiguration(pdev, + ATAConfiguration_ID_UDMATiming + ATAConfiguration_PCIOffset, + ATAConfiguration_ID_UDMATiming_Size, + &UDMATimingRegister); + if (result == FALSE) { + funcresult = FALSE; + goto funcexit; + } + + result = PCIDeviceIO_ReadPCIConfiguration(pdev, + ATAConfiguration_ID_IDEIOConfiguration + ATAConfiguration_PCIOffset, + ATAConfiguration_ID_IDEIOConfiguration_Size, + &IDEIOConfigurationRegister); + if (result == FALSE) { + funcresult = FALSE; + goto funcexit; + } + + /* Rom Code will determine the device cable type and ATA 100. */ + /* IDEIOConfigurationRegister |= ATAConfiguration_IDEIOConfiguration_DeviceCable80Report; */ + /* IDEIOConfigurationRegister |= ATAConfiguration_IDEIOConfiguration_ATA100IsSupported; */ + + switch (DeviceID) { + case 0: + UDMAControlRegister &= ~(ATAConfiguration_UDMAControl_SecondaryDevice0UDMAModeEnable); + if (UDMAEnable == TRUE) + UDMAControlRegister |= ATAConfiguration_UDMAControl_SecondaryDevice0UDMAModeEnable; + + IDEIOConfigurationRegister &= ~(ATAConfiguration_IDEIOConfiguration_SecondaryDevice066MhzEnable | + ATAConfiguration_IDEIOConfiguration_SecondaryDevice0100MhzEnable); + + if (UDMATimingMode >= UDMA5) + IDEIOConfigurationRegister |= ATAConfiguration_IDEIOConfiguration_SecondaryDevice0100MhzEnable; + else if (UDMATimingMode >= UDMA3) + IDEIOConfigurationRegister |= ATAConfiguration_IDEIOConfiguration_SecondaryDevice066MhzEnable; + + /* if 80 cable report */ + UDMATimingRegister &= ~(ATAConfiguration_UDMATiming_SecondaryDevice0CycleTime); + + if (UDMATimingMode == UDMA0) { + UDMATimingRegister |= ATAConfiguration_UDMATiming_SecondaryDevice0CycleTime_0; + } else if (UDMATimingMode == UDMA1 || + UDMATimingMode == UDMA3 || + UDMATimingMode == UDMA5) { + UDMATimingRegister |= ATAConfiguration_UDMATiming_SecondaryDevice0CycleTime_1; + } else if (UDMATimingMode == UDMA2 || + UDMATimingMode == UDMA4) { + UDMATimingRegister |= ATAConfiguration_UDMATiming_SecondaryDevice0CycleTime_2; + } + break; + case 1: + UDMAControlRegister &= ~(ATAConfiguration_UDMAControl_SecondaryDevice1UDMAModeEnable); + if (UDMAEnable == TRUE) + UDMAControlRegister |= ATAConfiguration_UDMAControl_SecondaryDevice1UDMAModeEnable; + + IDEIOConfigurationRegister &= ~(ATAConfiguration_IDEIOConfiguration_SecondaryDevice166MhzEnable | + ATAConfiguration_IDEIOConfiguration_SecondaryDevice1100MhzEnable); + + if (UDMATimingMode >= UDMA5) + IDEIOConfigurationRegister |= ATAConfiguration_IDEIOConfiguration_SecondaryDevice1100MhzEnable; + else if (UDMATimingMode >= UDMA3) + IDEIOConfigurationRegister |= ATAConfiguration_IDEIOConfiguration_SecondaryDevice166MhzEnable; + + /* if 80 cable report */ + UDMATimingRegister &= ~(ATAConfiguration_UDMATiming_SecondaryDevice1CycleTime); + + if (UDMATimingMode == UDMA0) { + UDMATimingRegister |= ATAConfiguration_UDMATiming_SecondaryDevice1CycleTime_0; + } else if (UDMATimingMode == UDMA1 || + UDMATimingMode == UDMA3 || + UDMATimingMode == UDMA5) { + UDMATimingRegister |= ATAConfiguration_UDMATiming_SecondaryDevice1CycleTime_1; + } else if (UDMATimingMode == UDMA2 || + UDMATimingMode == UDMA4) { + UDMATimingRegister |= ATAConfiguration_UDMATiming_SecondaryDevice1CycleTime_2; + } + break; + default: + funcresult = FALSE; + goto funcexit; + break; + } + + result = PCIDeviceIO_WritePCIConfiguration(pdev, + ATAConfiguration_ID_UDMAControl + ATAConfiguration_PCIOffset, + ATAConfiguration_ID_UDMAControl_Size, + &UDMAControlRegister); + if (result == FALSE) { + funcresult = FALSE; + goto funcexit; + } + + result = PCIDeviceIO_WritePCIConfiguration(pdev, + ATAConfiguration_ID_UDMATiming + ATAConfiguration_PCIOffset, + ATAConfiguration_ID_UDMATiming_Size, + &UDMATimingRegister); + if (result == FALSE) { + funcresult = FALSE; + goto funcexit; + } + + result = PCIDeviceIO_WritePCIConfiguration(pdev, + ATAConfiguration_ID_IDEIOConfiguration + ATAConfiguration_PCIOffset, + ATAConfiguration_ID_IDEIOConfiguration_Size, + &IDEIOConfigurationRegister); + if (result == FALSE) { + funcresult = FALSE; + goto funcexit; + } + + goto funcexit; +funcexit: + return funcresult; +} + +static int rdc_pata_port_start(struct ata_port *ap) +{ + uint Channel; + + Channel = ap->port_no; + dev_dbg(ap->dev, "%s: Channel: %u\n", __func__, Channel); + if (ap->ioaddr.bmdma_addr) { + return ata_port_start(ap); + } else { + dev_dbg(ap->dev, "%s: return 0!!!\n", __func__); + return 0; + } +} + +static void rdc_pata_port_stop(struct ata_port *ap) +{ + uint Channel; + + Channel = ap->port_no; + + dev_dbg(ap->dev, "%s Channel: %u\n", __func__, Channel); +} + +static int rdc_pata_prereset(struct ata_link *link, unsigned long deadline) +{ + struct pci_dev *pdev; + struct ata_port *ap; + uint Channel; + + dev_dbg(link->ap->dev, "%s\n", __func__); + + ap = link->ap; + pdev = to_pci_dev(ap->host->dev); + + Channel = ap->port_no; + + /* test ATA Decode Enable Bits, should be enable. */ + if (!pci_test_config_bits(pdev, &ATA_Decode_Enable_Bits[Channel])) { + dev_dbg(link->ap->dev, "%s: Channel: %u, Decode Disable\n", + __func__, Channel); + return -ENOENT; + } else { + dev_dbg(link->ap->dev, "%s: Channel: %u, Decode Enable\n", + __func__, Channel); + return ata_std_prereset(link, deadline); + } +} + +static int rdc_pata_cable_detect(struct ata_port *ap) +{ + struct pci_dev *pdev; + uint Channel; + uint Mask; + u32 u32Value; + + dev_dbg(ap->dev, "%s\n", __func__); + + pdev = to_pci_dev(ap->host->dev); + + Channel = ap->port_no; + + if (Channel == 0) + Mask = ATAConfiguration_IDEIOConfiguration_PrimaryDeviceCable80Report; + else + Mask = ATAConfiguration_IDEIOConfiguration_SecondaryDeviceCable80Report; + + /* check BIOS cable detect results */ + pci_read_config_dword(pdev, ATAConfiguration_ID_IDEIOConfiguration + ATAConfiguration_PCIOffset, &u32Value); + + if ((u32Value & Mask) == 0) { + dev_dbg(ap->dev, "%s: Channel: %u, PATA40 \n", + __func__, Channel); + return ATA_CBL_PATA40; + } else { + dev_dbg(ap->dev, "%s: Channel: %u, PATA80 \n", + __func__, Channel); + return ATA_CBL_PATA80; + } +} + +static void rdc_pata_set_piomode(struct ata_port *ap, struct ata_device *adev) +{ + struct pci_dev *pdev; + uint Channel; + uint DeviceID; + uint PIOTimingMode; + uint PrefetchPostingEnable; + + dev_dbg(ap->dev, "%s\n", __func__); + + pdev = to_pci_dev(ap->host->dev); + + Channel = ap->port_no; + DeviceID = adev->devno; + /* + * piomode = 0, 1, 2, 3... ; adev->pio_mode = XFER_PIO_0, XFER_PIO_1, + * XFER_PIO_2, XFER_PIO_3... + */ + PIOTimingMode = adev->pio_mode - XFER_PIO_0; + + if (adev->class == ATA_DEV_ATA) { + PrefetchPostingEnable = TRUE; + } else { + /* ATAPI, CD DVD Rom */ + PrefetchPostingEnable = FALSE; + } + + /* PIO configuration clears DTE unconditionally. It will be + * programmed in set_dmamode which is guaranteed to be called + * after set_piomode if any DMA mode is available. + */ + + /* Ensure the UDMA bit is off - it will be turned back on if UDMA is + * selected */ + + if (Channel == 0) { + ATAHostAdapter_SetPrimaryPIO( + pdev, + DeviceID, + PIOTimingMode, + TRUE, + PrefetchPostingEnable + ); + + ATAHostAdapter_SetPrimaryUDMA( + pdev, + DeviceID, + FALSE, + UDMA0 + ); + } else { + ATAHostAdapter_SetSecondaryPIO( + pdev, + DeviceID, + PIOTimingMode, + TRUE, + PrefetchPostingEnable + ); + + ATAHostAdapter_SetSecondaryUDMA( + pdev, + DeviceID, + FALSE, + UDMA0 + ); + } + dev_dbg(ap->dev, "%s: Channel: %u, DeviceID: %u, PIO: %d\n", + __func__, Channel, DeviceID, PIOTimingMode); +} + +static void rdc_pata_set_dmamode(struct ata_port *ap, struct ata_device *adev) +{ + struct pci_dev *pdev; + uint Channel; + uint DeviceID; + uint PIOTimingMode; + uint PrefetchPostingEnable; + uint DMATimingMode; + uint UDMAEnable; + + dev_dbg(ap->dev, "%s\n", __func__); + + pdev = to_pci_dev(ap->host->dev); + + Channel = ap->port_no; + DeviceID = adev->devno; + PIOTimingMode = adev->pio_mode - XFER_PIO_0; /* piomode = 0, 1, 2, 3... ; adev->pio_mode = XFER_PIO_0, XFER_PIO_1, XFER_PIO_2, XFER_PIO_3... */ + DMATimingMode = adev->dma_mode; /* UDMA or MDMA */ + + if (adev->class == ATA_DEV_ATA) { + PrefetchPostingEnable = TRUE; + } else { + /* ATAPI, CD DVD Rom */ + PrefetchPostingEnable = FALSE; + } + + if (ap->udma_mask == 0) { + /* ata_port dont support udma. depend on hardware spec. */ + UDMAEnable = FALSE; + } else { + UDMAEnable = TRUE; + } + + if (Channel == 0) { + if (DMATimingMode >= XFER_UDMA_0) { + /* UDMA */ + ATAHostAdapter_SetPrimaryPIO(pdev, + DeviceID, + PIOTimingMode, + TRUE, + PrefetchPostingEnable); + + ATAHostAdapter_SetPrimaryUDMA(pdev, + DeviceID, + UDMAEnable, + DMATimingMode - XFER_UDMA_0); + dev_dbg(ap->dev, + "%s: Channel: %u, DeviceID: %u, UDMA: %u\n", + __func__, Channel, DeviceID, + (uint)(DMATimingMode - XFER_UDMA_0)); + } else { + /* MDMA */ + ATAHostAdapter_SetPrimaryPIO(pdev, + DeviceID, + (DMATimingMode - XFER_MW_DMA_0) + PIO2, /* MDMA0 = PIO2 */ + TRUE, + PrefetchPostingEnable); + + ATAHostAdapter_SetPrimaryUDMA(pdev, + DeviceID, + FALSE, + UDMA0); + dev_dbg(ap->dev, + "%s: Channel: %u, DeviceID: %u, MDMA: %u\n", + __func__, Channel, DeviceID, + (uint)(DMATimingMode - XFER_MW_DMA_0)); + } + } else { + if (DMATimingMode >= XFER_UDMA_0) { + /* UDMA */ + ATAHostAdapter_SetSecondaryPIO(pdev, + DeviceID, + PIOTimingMode, + TRUE, + PrefetchPostingEnable); + + ATAHostAdapter_SetSecondaryUDMA(pdev, + DeviceID, + UDMAEnable, + DMATimingMode - XFER_UDMA_0); + dev_dbg(ap->dev, + "%s: Channel: %u, DeviceID: %u, UDMA: %u\n", + __func__, Channel, DeviceID, + (uint)(DMATimingMode - XFER_UDMA_0)); + } else { + /* MDMA */ + ATAHostAdapter_SetSecondaryPIO(pdev, + DeviceID, + (DMATimingMode - XFER_MW_DMA_0) + PIO2, /* MDMA0 = PIO2 */ + TRUE, + PrefetchPostingEnable); + + ATAHostAdapter_SetSecondaryUDMA(pdev, + DeviceID, + FALSE, + UDMA0); + dev_dbg(ap->dev, + "%s: Channel: %u, DeviceID: %u, MDMA: %u \n", + __func__, Channel, DeviceID, + (uint)(DMATimingMode - XFER_MW_DMA_0)); + } + } +} + +static struct scsi_host_template rdc_pata_sht = { + ATA_BMDMA_SHT(KBUILD_MODNAME), +}; + +static struct ata_port_operations rdc_pata_ops = { + .inherits = &ata_bmdma_port_ops, + + .port_start = rdc_pata_port_start, + .port_stop = rdc_pata_port_stop, + .prereset = rdc_pata_prereset, + .cable_detect = rdc_pata_cable_detect, + .set_piomode = rdc_pata_set_piomode, + .set_dmamode = rdc_pata_set_dmamode, +}; + +static struct ata_port_info rdc_pata_port_info[] = { + [RDC_17F31011] = { + .flags = ATA_FLAG_SLAVE_POSS, + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ + .udma_mask = ATA_UDMA5, /* udma0-5 */ + .port_ops = &rdc_pata_ops, + }, + + [RDC_17F31012] = { + .flags = ATA_FLAG_SLAVE_POSS, + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ + .udma_mask = ATA_UDMA5, /* udma0-5 */ + .port_ops = &rdc_pata_ops, + }, +}; + +static int __devinit rdc_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct ata_port_info port_info[2]; + const struct ata_port_info *ppinfo[] = { &port_info[0], &port_info[1] }; + + int rc; + + dev_dbg(&pdev->dev, "%s\n", __func__); + + port_info[0] = rdc_pata_port_info[ent->driver_data]; + port_info[1] = rdc_pata_port_info[ent->driver_data]; + + rc = pci_enable_device(pdev); + if (rc) { + dev_dbg(&pdev->dev, "%s pci_enable_device failed\n", __func__); + return rc; + } + pci_intx(pdev, 1); + + return ata_pci_sff_init_one(pdev, ppinfo, &rdc_pata_sht, NULL); +} + +static struct pci_driver rdc_pata_driver = { + .name = KBUILD_MODNAME, + .id_table = rdc_pata_id_table, + .probe = rdc_init_one, + .remove = ata_pci_remove_one, +#ifdef CONFIG_PM + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, +#endif +}; + +static int __init pata_rdc_init(void) +{ + return pci_register_driver(&rdc_pata_driver); +} + +static void __exit pata_rdc_exit(void) +{ + pci_unregister_driver(&rdc_pata_driver); +} + +module_init(pata_rdc_init); +module_exit(pata_rdc_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("RDC PCI IDE Driver"); diff --git a/drivers/staging/pata_rdc/pata_rdc.h b/drivers/staging/pata_rdc/pata_rdc.h new file mode 100644 index 000000000000..a833339886d9 --- /dev/null +++ b/drivers/staging/pata_rdc/pata_rdc.h @@ -0,0 +1,144 @@ +#ifndef pata_rdc_H +#define pata_rdc_H + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +/* ATA Configuration Register ID offset address size */ +#define ATAConfiguration_PCIOffset 0x40 +#define ATAConfiguration_ID_PrimaryTiming 0x00 +#define ATAConfiguration_ID_SecondaryTiming 0x02 +#define ATAConfiguration_ID_Device1Timing 0x04 +#define ATAConfiguration_ID_UDMAControl 0x08 +#define ATAConfiguration_ID_UDMATiming 0x0A +#define ATAConfiguration_ID_IDEIOConfiguration 0x14 + +#define ATAConfiguration_ID_PrimaryTiming_Size 2 +#define ATAConfiguration_ID_SecondaryTiming_Size 2 +#define ATAConfiguration_ID_Device1Timing_Size 1 +#define ATAConfiguration_ID_UDMAControl_Size 1 +#define ATAConfiguration_ID_UDMATiming_Size 2 +#define ATAConfiguration_ID_IDEIOConfiguration_Size 4 + +/* ATA Configuration Register bit define */ +#define ATAConfiguration_PrimaryTiming_Device0FastTimingEnable 0x0001 +#define ATAConfiguration_PrimaryTiming_Device0IORDYSampleModeEnable 0x0002 /* PIO 3 or greater */ +#define ATAConfiguration_PrimaryTiming_Device0PrefetchandPostingEnable 0x0004 /* PIO 2 or greater */ +#define ATAConfiguration_PrimaryTiming_Device0DMATimingEnable 0x0008 +#define ATAConfiguration_PrimaryTiming_Device1FastTimingEnable 0x0010 +#define ATAConfiguration_PrimaryTiming_Device1IORDYSampleModeEnable 0x0020 /* PIO 3 or greater */ +#define ATAConfiguration_PrimaryTiming_Device1PrefetchandPostingEnable 0x0040 /* PIO 2 or greater */ +#define ATAConfiguration_PrimaryTiming_Device1DMATimingEnable 0x0080 +#define ATAConfiguration_PrimaryTiming_Device0RecoveryMode 0x0300 +#define ATAConfiguration_PrimaryTiming_Device0RecoveryMode_0 0x0000 /* PIO 0, PIO 2, MDMA 0 */ +#define ATAConfiguration_PrimaryTiming_Device0RecoveryMode_1 0x0100 /* PIO 3, MDMA 1 */ +#define ATAConfiguration_PrimaryTiming_Device0RecoveryMode_2 0x0200 /* X */ +#define ATAConfiguration_PrimaryTiming_Device0RecoveryMode_3 0x0300 /* PIO 4, MDMA 2 */ +#define ATAConfiguration_PrimaryTiming_Device0IORDYSampleMode 0x3000 +#define ATAConfiguration_PrimaryTiming_Device0IORDYSampleMode_0 0x0000 /* PIO 0 */ +#define ATAConfiguration_PrimaryTiming_Device0IORDYSampleMode_1 0x1000 /* PIO 2, MDMA 0 */ +#define ATAConfiguration_PrimaryTiming_Device0IORDYSampleMode_2 0x2000 /* PIO 3, PIO 4, MDMA 1, MDMA 2 */ +#define ATAConfiguration_PrimaryTiming_Device0IORDYSampleMode_3 0x3000 /* X */ +#define ATAConfiguration_PrimaryTiming_Device1TimingRegisterEnable 0x4000 +#define ATAConfiguration_PrimaryTiming_IDEDecodeEnable 0x8000 + +#define ATAConfiguration_Device1Timing_PrimaryRecoveryMode 0x0003 +#define ATAConfiguration_Device1Timing_PrimaryRecoveryMode_0 0x0000 +#define ATAConfiguration_Device1Timing_PrimaryRecoveryMode_1 0x0001 +#define ATAConfiguration_Device1Timing_PrimaryRecoveryMode_2 0x0002 +#define ATAConfiguration_Device1Timing_PrimaryRecoveryMode_3 0x0003 +#define ATAConfiguration_Device1Timing_PrimaryIORDYSampleMode 0x000C +#define ATAConfiguration_Device1Timing_PrimaryIORDYSampleMode_0 0x0000 +#define ATAConfiguration_Device1Timing_PrimaryIORDYSampleMode_1 0x0004 +#define ATAConfiguration_Device1Timing_PrimaryIORDYSampleMode_2 0x0008 +#define ATAConfiguration_Device1Timing_PrimaryIORDYSampleMode_3 0x000C +#define ATAConfiguration_Device1Timing_SecondaryRecoveryMode 0x0030 +#define ATAConfiguration_Device1Timing_SecondaryRecoveryMode_0 0x0000 +#define ATAConfiguration_Device1Timing_SecondaryRecoveryMode_1 0x0010 +#define ATAConfiguration_Device1Timing_SecondaryRecoveryMode_2 0x0020 +#define ATAConfiguration_Device1Timing_SecondaryRecoveryMode_3 0x0030 +#define ATAConfiguration_Device1Timing_SecondaryIORDYSampleMode 0x00C0 +#define ATAConfiguration_Device1Timing_SecondaryIORDYSampleMode_0 0x0000 +#define ATAConfiguration_Device1Timing_SecondaryIORDYSampleMode_1 0x0040 +#define ATAConfiguration_Device1Timing_SecondaryIORDYSampleMode_2 0x0080 +#define ATAConfiguration_Device1Timing_SecondaryIORDYSampleMode_3 0x00C0 + +#define ATAConfiguration_UDMAControl_PrimaryDevice0UDMAModeEnable 0x0001 +#define ATAConfiguration_UDMAControl_PrimaryDevice1UDMAModeEnable 0x0002 +#define ATAConfiguration_UDMAControl_SecondaryDevice0UDMAModeEnable 0x0004 +#define ATAConfiguration_UDMAControl_SecondaryDevice1UDMAModeEnable 0x0008 + +#define ATAConfiguration_UDMATiming_PrimaryDevice0CycleTime 0x0003 +#define ATAConfiguration_UDMATiming_PrimaryDevice0CycleTime_0 0x0000 /* UDMA 0 */ +#define ATAConfiguration_UDMATiming_PrimaryDevice0CycleTime_1 0x0001 /* UDMA 1, UDMA 3, UDMA 5 */ +#define ATAConfiguration_UDMATiming_PrimaryDevice0CycleTime_2 0x0002 /* UDMA 2, UDMA 4 */ +#define ATAConfiguration_UDMATiming_PrimaryDevice0CycleTime_3 0x0003 /* X */ +#define ATAConfiguration_UDMATiming_PrimaryDevice1CycleTime 0x0030 +#define ATAConfiguration_UDMATiming_PrimaryDevice1CycleTime_0 0x0000 /* UDMA 0 */ +#define ATAConfiguration_UDMATiming_PrimaryDevice1CycleTime_1 0x0010 /* UDMA 1, UDMA 3, UDMA 5 */ +#define ATAConfiguration_UDMATiming_PrimaryDevice1CycleTime_2 0x0020 /* UDMA 2, UDMA 4 */ +#define ATAConfiguration_UDMATiming_PrimaryDevice1CycleTime_3 0x0030 /* X */ +#define ATAConfiguration_UDMATiming_SecondaryDevice0CycleTime 0x0300 +#define ATAConfiguration_UDMATiming_SecondaryDevice0CycleTime_0 0x0000 /* UDMA 0 */ +#define ATAConfiguration_UDMATiming_SecondaryDevice0CycleTime_1 0x0100 /* UDMA 1, UDMA 3, UDMA 5 */ +#define ATAConfiguration_UDMATiming_SecondaryDevice0CycleTime_2 0x0200 /* UDMA 2, UDMA 4 */ +#define ATAConfiguration_UDMATiming_SecondaryDevice0CycleTime_3 0x0300 /* X */ +#define ATAConfiguration_UDMATiming_SecondaryDevice1CycleTime 0x3000 +#define ATAConfiguration_UDMATiming_SecondaryDevice1CycleTime_0 0x0000 /* UDMA 0 */ +#define ATAConfiguration_UDMATiming_SecondaryDevice1CycleTime_1 0x1000 /* UDMA 1, UDMA 3, UDMA 5 */ +#define ATAConfiguration_UDMATiming_SecondaryDevice1CycleTime_2 0x2000 /* UDMA 2, UDMA 4 */ +#define ATAConfiguration_UDMATiming_SecondaryDevice1CycleTime_3 0x3000 /* X */ + +#define ATAConfiguration_IDEIOConfiguration_PrimaryDevice066MhzEnable 0x00000001 /* UDMA 3, UDMA 4 */ +#define ATAConfiguration_IDEIOConfiguration_PrimaryDevice166MhzEnable 0x00000002 +#define ATAConfiguration_IDEIOConfiguration_SecondaryDevice066MhzEnable 0x00000004 +#define ATAConfiguration_IDEIOConfiguration_SecondaryDevice166MhzEnable 0x00000008 +#define ATAConfiguration_IDEIOConfiguration_DeviceCable80Report 0x000000F0 +#define ATAConfiguration_IDEIOConfiguration_PrimaryDeviceCable80Report 0x00000030 +#define ATAConfiguration_IDEIOConfiguration_PrimaryDevice0Cable80Report 0x00000010 /* UDMA 3, UDMA 4, UDMA 5 */ +#define ATAConfiguration_IDEIOConfiguration_PrimaryDevice1Cable80Report 0x00000020 +#define ATAConfiguration_IDEIOConfiguration_SecondaryDeviceCable80Report 0x000000C0 +#define ATAConfiguration_IDEIOConfiguration_SecondaryDevice0Cable80Report 0x00000040 +#define ATAConfiguration_IDEIOConfiguration_SecondaryDevice1Cable80Report 0x00000080 +#define ATAConfiguration_IDEIOConfiguration_PrimaryDevice0100MhzEnable 0x00001000 /* UDMA 5 */ +#define ATAConfiguration_IDEIOConfiguration_PrimaryDevice1100MhzEnable 0x00002000 +#define ATAConfiguration_IDEIOConfiguration_SecondaryDevice0100MhzEnable 0x00004000 +#define ATAConfiguration_IDEIOConfiguration_SecondaryDevice1100MhzEnable 0x00008000 +#define ATAConfiguration_IDEIOConfiguration_ATA100IsSupported 0x00F00000 + +enum _PIOTimingMode { + PIO0 = 0, + PIO1, + PIO2, /* MDMA 0 */ + PIO3, /* MDMA 1 */ + PIO4 /* MDMA 2 */ +}; + +enum _DMATimingMode { + MDMA0 = 0, + MDMA1, + MDMA2 +}; + +enum _UDMATimingMode { + UDMA0 = 0, + UDMA1, + UDMA2, + UDMA3, + UDMA4, + UDMA5 +}; + + +enum rdc_controller_ids { + /* controller IDs */ + RDC_17F31011, + RDC_17F31012 +}; + +#endif diff --git a/drivers/staging/pohmelfs/crypto.c b/drivers/staging/pohmelfs/crypto.c index 31d765de92ce..19781ad782fb 100644 --- a/drivers/staging/pohmelfs/crypto.c +++ b/drivers/staging/pohmelfs/crypto.c @@ -832,8 +832,7 @@ int pohmelfs_trans_crypt(struct netfs_trans *trans, struct pohmelfs_sb *psb) return pohmelfs_crypto_thread_get(psb, pohmelfs_trans_crypt_action, trans); } -struct pohmelfs_crypto_input_action_data -{ +struct pohmelfs_crypto_input_action_data { struct page *page; struct pohmelfs_crypto_engine *e; u64 iv; diff --git a/drivers/staging/pohmelfs/dir.c b/drivers/staging/pohmelfs/dir.c index b5799842fb84..4c58e22c1fbe 100644 --- a/drivers/staging/pohmelfs/dir.c +++ b/drivers/staging/pohmelfs/dir.c @@ -562,7 +562,7 @@ struct dentry *pohmelfs_lookup(struct inode *dir, struct dentry *dentry, struct if (!inode) { dprintk("%s: No inode for ino: %lu, name: '%s', hash: %x.\n", __func__, ino, str.name, str.hash); - //return NULL; + /* return NULL; */ return ERR_PTR(-EACCES); } } else { @@ -692,9 +692,9 @@ static int pohmelfs_remove_entry(struct inode *dir, struct dentry *dentry) n = pohmelfs_search_hash(parent, str.hash); if (n) { pohmelfs_fix_offset(parent, n); - if (test_bit(NETFS_INODE_REMOTE_SYNCED, &pi->state)) { + if (test_bit(NETFS_INODE_REMOTE_SYNCED, &pi->state)) pohmelfs_remove_child(pi, n); - } + pohmelfs_name_free(parent, n); err = 0; } @@ -1006,9 +1006,8 @@ static int pohmelfs_rename(struct inode *old_dir, struct dentry *old_dentry, pi = POHMELFS_I(inode); old_parent = POHMELFS_I(old_dir); - if (new_dir) { + if (new_dir) new_dir->i_sb->s_op->write_inode(new_dir, 0); - } old_hash = jhash(old_dentry->d_name.name, old_dentry->d_name.len, 0); str.hash = jhash(new_dentry->d_name.name, new_dentry->d_name.len, 0); diff --git a/drivers/staging/pohmelfs/inode.c b/drivers/staging/pohmelfs/inode.c index b2eaf9047266..7b605795b770 100644 --- a/drivers/staging/pohmelfs/inode.c +++ b/drivers/staging/pohmelfs/inode.c @@ -386,7 +386,7 @@ static int pohmelfs_write_inode_create_children(struct inode *inode) if (inode && (inode->i_state & I_DIRTY)) { struct pohmelfs_inode *pi = POHMELFS_I(inode); pohmelfs_write_create_inode(pi); - //pohmelfs_meta_command(pi, NETFS_INODE_INFO, 0, NULL, NULL, 0); + /* pohmelfs_meta_command(pi, NETFS_INODE_INFO, 0, NULL, NULL, 0); */ iput(inode); } } @@ -845,7 +845,7 @@ static void pohmelfs_destroy_inode(struct inode *inode) struct pohmelfs_sb *psb = POHMELFS_SB(sb); struct pohmelfs_inode *pi = POHMELFS_I(inode); - //pohmelfs_data_unlock(pi, 0, inode->i_size, POHMELFS_READ_LOCK); + /* pohmelfs_data_unlock(pi, 0, inode->i_size, POHMELFS_READ_LOCK); */ pohmelfs_inode_del_inode(psb, pi); @@ -943,7 +943,7 @@ err_out_unlock: return ret; } -const static struct file_operations pohmelfs_file_ops = { +static const struct file_operations pohmelfs_file_ops = { .open = generic_file_open, .fsync = pohmelfs_fsync, @@ -1529,9 +1529,9 @@ static void pohmelfs_drop_scan(struct work_struct *work) struct pohmelfs_inode *pi; unsigned int count = 0; - while ((pi = pohmelfs_get_inode_from_list(psb, &psb->drop_list, &count))) { + while ((pi = pohmelfs_get_inode_from_list(psb, &psb->drop_list, &count))) pohmelfs_put_inode_count(pi, count); - } + pohmelfs_check_states(psb); if (psb->drop_scan_timeout) @@ -1568,9 +1568,8 @@ static void pohmelfs_trans_scan_state(struct netfs_state *st) rb_node = rb_next(rb_node); err = -ETIMEDOUT; - if (timeout && (++dst->retries < psb->trans_retries)) { + if (timeout && (++dst->retries < psb->trans_retries)) err = netfs_trans_resend(t, psb); - } if (err || (t->flags & NETFS_TRANS_SINGLE_DST)) { if (netfs_trans_remove_nolock(dst, st)) @@ -1777,7 +1776,7 @@ static int pohmelfs_show_stats(struct seq_file *m, struct vfsmount *mnt) seq_printf(m, "%u ", ctl->idx); if (ctl->addr.sa_family == AF_INET) { struct sockaddr_in *sin = (struct sockaddr_in *)&st->ctl.addr; - //seq_printf(m, "%pi4:%u", &sin->sin_addr.s_addr, ntohs(sin->sin_port)); + /* seq_printf(m, "%pi4:%u", &sin->sin_addr.s_addr, ntohs(sin->sin_port)); */ seq_printf(m, "%u.%u.%u.%u:%u", NIPQUAD(sin->sin_addr.s_addr), ntohs(sin->sin_port)); } else if (ctl->addr.sa_family == AF_INET6) { struct sockaddr_in6 *sin = (struct sockaddr_in6 *)&st->ctl.addr; diff --git a/drivers/staging/pohmelfs/net.c b/drivers/staging/pohmelfs/net.c index 11ecac026ca7..5f312c91aab6 100644 --- a/drivers/staging/pohmelfs/net.c +++ b/drivers/staging/pohmelfs/net.c @@ -168,8 +168,7 @@ int pohmelfs_data_recv_and_check(struct netfs_state *st, void *data, unsigned in * Polling machinery. */ -struct netfs_poll_helper -{ +struct netfs_poll_helper { poll_table pt; struct netfs_state *st; }; @@ -915,9 +914,9 @@ static int pohmelfs_recv(void *data) unsigned char *hash = e->data; dprintk("%s: received hash: ", __func__); - for (i=0; icsize; ++i) { + for (i=0; icsize; ++i) printk("%02x ", hash[i]); - } + printk("\n"); } #endif diff --git a/drivers/staging/pohmelfs/netfs.h b/drivers/staging/pohmelfs/netfs.h index c78cfcb042fb..3b60c611ba80 100644 --- a/drivers/staging/pohmelfs/netfs.h +++ b/drivers/staging/pohmelfs/netfs.h @@ -30,8 +30,7 @@ * Network command structure. * Will be extended. */ -struct netfs_cmd -{ +struct netfs_cmd { __u16 cmd; /* Command number */ __u16 csize; /* Attached crypto information size */ __u16 cpad; /* Attached padding size */ @@ -96,8 +95,7 @@ enum { */ #define _K_SS_MAXSIZE 128 -struct saddr -{ +struct saddr { unsigned short sa_family; char addr[_K_SS_MAXSIZE]; }; @@ -107,8 +105,7 @@ enum { POHMELFS_CRYPTO_CIPHER, }; -struct pohmelfs_crypto -{ +struct pohmelfs_crypto { unsigned int idx; /* Config index */ unsigned short strlen; /* Size of the attached crypto string including 0-byte * "cbc(aes)" for example */ @@ -123,8 +120,7 @@ struct pohmelfs_crypto /* * Configuration command used to create table of different remote servers. */ -struct pohmelfs_ctl -{ +struct pohmelfs_ctl { __u32 idx; /* Config index */ __u32 type; /* Socket type */ __u32 proto; /* Socket protocol */ @@ -137,8 +133,7 @@ struct pohmelfs_ctl /* * Ack for userspace about requested command. */ -struct pohmelfs_cn_ack -{ +struct pohmelfs_cn_ack { struct cn_msg msg; int error; int msg_num; @@ -150,8 +145,7 @@ struct pohmelfs_cn_ack * Inode info structure used to sync with server. * Check what stat() returns. */ -struct netfs_inode_info -{ +struct netfs_inode_info { unsigned int mode; unsigned int nlink; unsigned int uid; @@ -205,8 +199,7 @@ enum pohmelfs_capabilities { /* Extended attributes support on/off */ #define POHMELFS_FLAGS_XATTR (1<<1) -struct netfs_root_capabilities -{ +struct netfs_root_capabilities { __u64 nr_files; __u64 used, avail; __u64 flags; @@ -220,8 +213,7 @@ static inline void netfs_convert_root_capabilities(struct netfs_root_capabilitie cap->flags = __cpu_to_be64(cap->flags); } -struct netfs_crypto_capabilities -{ +struct netfs_crypto_capabilities { unsigned short hash_strlen; /* Hash string length, like "hmac(sha1) including 0 byte "*/ unsigned short cipher_strlen; /* Cipher string length with the same format */ unsigned int cipher_keysize; /* Cipher key size */ @@ -241,8 +233,7 @@ enum pohmelfs_lock_type { POHMELFS_WRITE_LOCK, }; -struct netfs_lock -{ +struct netfs_lock { __u64 start; __u64 ino; __u32 size; @@ -268,8 +259,7 @@ static inline void netfs_convert_lock(struct netfs_lock *lock) /* * Private POHMELFS cache of objects in directory. */ -struct pohmelfs_name -{ +struct pohmelfs_name { struct rb_node hash_node; struct list_head sync_create_entry; @@ -286,8 +276,7 @@ struct pohmelfs_name /* * POHMELFS inode. Main object. */ -struct pohmelfs_inode -{ +struct pohmelfs_inode { struct list_head inode_entry; /* Entry in superblock list. * Objects which are not bound to dentry require to be dropped * in ->put_super() @@ -318,8 +307,7 @@ typedef int (* netfs_trans_complete_t)(struct page **pages, unsigned int page_nu struct netfs_state; struct pohmelfs_sb; -struct netfs_trans -{ +struct netfs_trans { /* * Transaction header and attached contiguous data live here. */ @@ -426,8 +414,7 @@ static inline void netfs_trans_reset(struct netfs_trans *t) t->complete = NULL; } -struct netfs_trans_dst -{ +struct netfs_trans_dst { struct list_head trans_entry; struct rb_node state_entry; @@ -456,8 +443,7 @@ int netfs_trans_remove_nolock(struct netfs_trans_dst *dst, struct netfs_state *s int netfs_trans_init(void); void netfs_trans_exit(void); -struct pohmelfs_crypto_engine -{ +struct pohmelfs_crypto_engine { u64 iv; /* Crypto IV for current operation */ unsigned long timeout; /* Crypto waiting timeout */ unsigned int size; /* Size of crypto scratchpad */ @@ -474,8 +460,7 @@ struct pohmelfs_crypto_engine unsigned int page_num; }; -struct pohmelfs_crypto_thread -{ +struct pohmelfs_crypto_thread { struct list_head thread_entry; struct task_struct *thread; @@ -497,8 +482,7 @@ void pohmelfs_crypto_thread_make_ready(struct pohmelfs_crypto_thread *th); /* * Network state, attached to one server. */ -struct netfs_state -{ +struct netfs_state { struct mutex __state_lock; /* Can not allow to use the same socket simultaneously */ struct mutex __state_send_lock; struct netfs_cmd cmd; /* Cached command */ @@ -580,8 +564,7 @@ static inline unsigned int netfs_state_poll(struct netfs_state *st) struct pohmelfs_config; -struct pohmelfs_sb -{ +struct pohmelfs_sb { struct rb_root mcache_root; struct mutex mcache_lock; atomic_long_t mcache_gen; @@ -718,15 +701,13 @@ static inline void pohmelfs_put_inode(struct pohmelfs_inode *pi) spin_unlock(&psb->ino_lock); } -struct pohmelfs_config -{ +struct pohmelfs_config { struct list_head config_entry; struct netfs_state state; }; -struct pohmelfs_config_group -{ +struct pohmelfs_config_group { /* * Entry in the global config group list. */ @@ -814,8 +795,7 @@ void pohmelfs_switch_active(struct pohmelfs_sb *psb); int pohmelfs_construct_path_string(struct pohmelfs_inode *pi, void *data, int len); int pohmelfs_path_length(struct pohmelfs_inode *pi); -struct pohmelfs_crypto_completion -{ +struct pohmelfs_crypto_completion { struct completion complete; int error; }; @@ -864,7 +844,7 @@ static inline int pohmelfs_need_lock(struct pohmelfs_inode *pi, int type) int __init pohmelfs_mcache_init(void); void pohmelfs_mcache_exit(void); -//#define CONFIG_POHMELFS_DEBUG +/* #define CONFIG_POHMELFS_DEBUG */ #ifdef CONFIG_POHMELFS_DEBUG #define dprintka(f, a...) printk(f, ##a) @@ -891,8 +871,7 @@ static inline void netfs_trans_put(struct netfs_trans *t) } } -struct pohmelfs_mcache -{ +struct pohmelfs_mcache { struct rb_node mcache_entry; struct completion complete; diff --git a/drivers/staging/pohmelfs/trans.c b/drivers/staging/pohmelfs/trans.c index fef5f9bd6920..4587f6d546aa 100644 --- a/drivers/staging/pohmelfs/trans.c +++ b/drivers/staging/pohmelfs/trans.c @@ -101,7 +101,8 @@ static int netfs_trans_send_pages(struct netfs_trans *t, struct netfs_state *st) goto err_out; } - msg.msg_flags = MSG_WAITALL|(attached_pages == 1)?0:MSG_MORE; + msg.msg_flags = MSG_WAITALL | (attached_pages == 1 ? 0 : + MSG_MORE); err = kernel_sendpage(st->socket, page, 0, size, msg.msg_flags); if (err <= 0) { @@ -177,9 +178,9 @@ int netfs_trans_send(struct netfs_trans *t, struct netfs_state *st) err_out_unlock_return: - if (st->need_reset) { + if (st->need_reset) netfs_state_exit(st); - } + netfs_state_unlock_send(st); dprintk("%s: t: %p, gen: %u, err: %d.\n", diff --git a/drivers/staging/rspiusb/rspiusb.c b/drivers/staging/rspiusb/rspiusb.c index ecaffb503111..1cdfe69585ea 100644 --- a/drivers/staging/rspiusb/rspiusb.c +++ b/drivers/staging/rspiusb/rspiusb.c @@ -39,7 +39,11 @@ static int debug; #endif /* Use our own dbg macro */ #undef dbg -#define dbg(format, arg...) do { if (debug) printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg); } while (0) +#define dbg(format, arg...) \ + do { \ + if (debug) \ + printk(KERN_DEBUG __FILE__ ": " format "\n" , ##arg); \ + } while (0) /* Version Information */ #define DRIVER_VERSION "V1.0.1" @@ -63,52 +67,58 @@ static DECLARE_MUTEX(disconnect_sem); /* Structure to hold all of our device specific stuff */ struct device_extension { - struct usb_device *udev; /* save off the usb device pointer */ - struct usb_interface *interface; /* the interface for this device */ - unsigned char minor; /* the starting minor number for this device */ + struct usb_device *udev; /* save off the usb device pointer */ + struct usb_interface *interface; /* the interface for this device */ + unsigned char minor; /* the starting minor number + * for this device + */ size_t bulk_in_size_returned; int bulk_in_byte_trk; struct urb ***PixelUrb; int frameIdx; int urbIdx; unsigned int *maplist_numPagesMapped; - int open; /* if the port is open or not */ - int present; /* if the device is not disconnected */ - int userBufMapped; /* has the user buffer been mapped? */ - struct scatterlist **sgl; /* scatter-gather list for user buffer */ + int open; /* if the port is open or not */ + int present; /* if the device is not disconnected */ + int userBufMapped; /* has the user buffer been mapped ? */ + struct scatterlist **sgl; /* scatter-gather list for user buffer */ unsigned int *sgEntries; struct kref kref; int gotPixelData; int pendingWrite; char **pendedPixelUrbs; - int iama; /*PIXIS or ST133 */ - int num_frames; /* the number of frames that will fit in the user buffer */ + int iama; /* PIXIS or ST133 */ + int num_frames; /* the number of frames that will fit + * in the user buffer + */ int active_frame; unsigned long frameSize; struct semaphore sem; - //FX2 specific endpoints - unsigned int hEP[8]; + unsigned int hEP[8]; /* FX2 specific endpoints */ }; -#define to_pi_dev(d) container_of( d, struct device_extension, kref ) +#define to_pi_dev(d) container_of(d, struct device_extension, kref) + +/* Prototypes */ static int MapUserBuffer(struct ioctl_struct *, struct device_extension *); static int UnMapUserBuffer(struct device_extension *); static int piusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); -static int piusb_output(struct ioctl_struct *, unsigned char *, int, struct device_extension *); +static int piusb_output(struct ioctl_struct *, unsigned char *, int, + struct device_extension *); static struct usb_driver piusb_driver; /* table of devices that work with this driver */ static struct usb_device_id pi_device_table[] = { {USB_DEVICE(VENDOR_ID, ST133_PID)}, {USB_DEVICE(VENDOR_ID, PIXIS_PID)}, - {0, } /* Terminating entry */ + {0, } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, pi_device_table); -static int lastErr = 0; -static int errCnt = 0; +static int lastErr; +static int errCnt; static void piusb_delete(struct kref *kref) { @@ -143,25 +153,29 @@ static int piusb_open(struct inode *inode, struct file *file) } dbg("Alternate Setting = %d", interface->num_altsetting); - pdx->frameIdx = pdx->urbIdx = 0; + pdx->bulk_in_size_returned = 0; + pdx->bulk_in_byte_trk = 0; + pdx->PixelUrb = NULL; + pdx->frameIdx = 0; + pdx->urbIdx = 0; + pdx->maplist_numPagesMapped = NULL; + pdx->userBufMapped = 0; + pdx->sgl = NULL; + pdx->sgEntries = NULL; pdx->gotPixelData = 0; pdx->pendingWrite = 0; - pdx->frameSize = 0; + pdx->pendedPixelUrbs = NULL; pdx->num_frames = 0; pdx->active_frame = 0; - pdx->bulk_in_byte_trk = 0; - pdx->userBufMapped = 0; - pdx->pendedPixelUrbs = NULL; - pdx->sgEntries = NULL; - pdx->sgl = NULL; - pdx->maplist_numPagesMapped = NULL; - pdx->PixelUrb = NULL; - pdx->bulk_in_size_returned = 0; + pdx->frameSize = 0; + /* increment our usage count for the device */ kref_get(&pdx->kref); + /* save our object in the file's private structure */ file->private_data = pdx; - exit_no_device: + +exit_no_device: return retval; } @@ -174,13 +188,91 @@ static int piusb_release(struct inode *inode, struct file *file) pdx = (struct device_extension *)file->private_data; if (pdx == NULL) { dbg("%s - object is NULL", __func__); - return -ENODEV; + retval = -ENODEV; + goto object_null; } /* decrement the count on our device */ kref_put(&pdx->kref, piusb_delete); + +object_null: return retval; } +static int pixis_io(struct ioctl_struct *ctrl, struct device_extension *pdx, + struct ioctl_struct *arg) +{ + unsigned int numToRead = 0; + unsigned int totalRead = 0; + unsigned char *uBuf; + int numbytes; + int i; + + uBuf = kmalloc(ctrl->numbytes, GFP_KERNEL); + if (!uBuf) { + dbg("Alloc for uBuf failed"); + return 0; + } + numbytes = (int) ctrl->numbytes; + numToRead = (unsigned int) ctrl->numbytes; + dbg("numbytes to read = %d", numbytes); + dbg("endpoint # %d", ctrl->endpoint); + + if (copy_from_user(uBuf, ctrl->pData, numbytes)) { + dbg("copying ctrl->pData to dummyBuf failed"); + return -EFAULT; + } + + do { + i = usb_bulk_msg(pdx->udev, pdx->hEP[ctrl->endpoint], + (uBuf + totalRead), + /* EP0 can only handle 64 bytes at a time */ + (numToRead > 64) ? 64 : numToRead, + &numbytes, HZ * 10); + if (i) { + dbg("CMD = %s, Address = 0x%02X", + ((uBuf[3] == 0x02) ? "WRITE" : "READ"), + uBuf[1]); + dbg("Number of bytes Attempted to read = %d", + (int)ctrl->numbytes); + dbg("Blocking ReadI/O Failed with status %d", i); + kfree(uBuf); + return -1; + } + dbg("Pixis EP0 Read %d bytes", numbytes); + totalRead += numbytes; + numToRead -= numbytes; + } while (numToRead); + + memcpy(ctrl->pData, uBuf, totalRead); + dbg("Total Bytes Read from PIXIS EP0 = %d", totalRead); + ctrl->numbytes = totalRead; + + if (copy_to_user(arg, ctrl, sizeof(struct ioctl_struct))) + dbg("copy_to_user failed in IORB"); + + kfree(uBuf); + return ctrl->numbytes; +} + +static int pixel_data(struct ioctl_struct *ctrl, struct device_extension *pdx) +{ + int i; + + if (!pdx->gotPixelData) + return 0; + + pdx->gotPixelData = 0; + ctrl->numbytes = pdx->bulk_in_size_returned; + pdx->bulk_in_size_returned -= pdx->frameSize; + + for (i = 0; i < pdx->maplist_numPagesMapped[pdx->active_frame]; i++) + SetPageDirty(sg_page(&pdx->sgl[pdx->active_frame][i])); + + pdx->active_frame = ((pdx->active_frame + 1) % pdx->num_frames); + + return ctrl->numbytes; +} + /** * piusb_ioctl */ @@ -190,12 +282,9 @@ static int piusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, struct device_extension *pdx; char dummyCtlBuf[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; unsigned long devRB = 0; - int i = 0; int err = 0; int retval = 0; struct ioctl_struct ctrl; - unsigned char *uBuf; - int numbytes = 0; unsigned short controlData = 0; pdx = (struct device_extension *)file->private_data; @@ -206,18 +295,22 @@ static int piusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, } /* fill in your device specific stuff here */ if (_IOC_DIR(cmd) & _IOC_READ) - err = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd)); + err = !access_ok(VERIFY_WRITE, (void __user *)arg, + _IOC_SIZE(cmd)); else if (_IOC_DIR(cmd) & _IOC_WRITE) - err = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd)); + err = !access_ok(VERIFY_READ, (void __user *)arg, + _IOC_SIZE(cmd)); if (err) { dev_err(&pdx->udev->dev, "return with error = %d\n", err); return -EFAULT; } switch (cmd) { case PIUSB_GETVNDCMD: - if (copy_from_user - (&ctrl, (void __user *)arg, sizeof(struct ioctl_struct))) - info("copy_from_user failed\n"); + if (__copy_from_user + (&ctrl, (void __user *)arg, sizeof(struct ioctl_struct))) { + dev_err(&pdx->udev->dev, "copy_from_user failed\n"); + return -EFAULT; + } dbg("%s %x\n", "Get Vendor Command = ", ctrl.cmd); retval = usb_control_msg(pdx->udev, usb_rcvctrlpipe(pdx->udev, 0), @@ -227,167 +320,85 @@ static int piusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, dbg("FW Version returned from HW = %ld.%ld", (devRB >> 8), (devRB & 0xFF)); } - return devRB; + if (retval >= 0) + retval = (int)devRB; + return retval; + case PIUSB_SETVNDCMD: - if (copy_from_user - (&ctrl, (void __user *)arg, sizeof(struct ioctl_struct))) - info("copy_from_user failed\n"); -// dbg( "%s %x", "Set Vendor Command = ",ctrl.cmd ); + if (__copy_from_user + (&ctrl, (void __user *)arg, sizeof(struct ioctl_struct))) { + dev_err(&pdx->udev->dev, "copy_from_user failed\n"); + return -EFAULT; + } + /* dbg( "%s %x", "Set Vendor Command = ",ctrl.cmd ); */ controlData = ctrl.pData[0]; controlData |= (ctrl.pData[1] << 8); -// dbg( "%s %d", "Vendor Data =",controlData ); - retval = usb_control_msg(pdx->udev, usb_sndctrlpipe(pdx->udev, 0), ctrl.cmd, (USB_DIR_OUT | USB_TYPE_VENDOR), /* | USB_RECIP_ENDPOINT), */ - controlData, - 0, - &dummyCtlBuf, ctrl.numbytes, HZ * 10); + /* dbg( "%s %d", "Vendor Data =",controlData ); */ + retval = usb_control_msg(pdx->udev, + usb_sndctrlpipe(pdx->udev, 0), + ctrl.cmd, + (USB_DIR_OUT | USB_TYPE_VENDOR + /* | USB_RECIP_ENDPOINT */), + controlData, 0, + &dummyCtlBuf, ctrl.numbytes, HZ * 10); return retval; - break; + case PIUSB_ISHIGHSPEED: return ((pdx->udev->speed == USB_SPEED_HIGH) ? 1 : 0); - break; + case PIUSB_WRITEPIPE: - if (copy_from_user(&ctrl, (void __user *)arg, _IOC_SIZE(cmd))) - info("copy_from_user WRITE_DUMMY failed\n"); + if (__copy_from_user(&ctrl, (void __user *)arg, _IOC_SIZE(cmd))) { + dev_err(&pdx->udev->dev, + "copy_from_user WRITE_DUMMY failed\n"); + return -EFAULT; + } if (!access_ok(VERIFY_READ, ctrl.pData, ctrl.numbytes)) { dbg("can't access pData"); return 0; } - piusb_output(&ctrl, ctrl.pData /*uBuf */ , ctrl.numbytes, pdx); + piusb_output(&ctrl, ctrl.pData /* uBuf */, ctrl.numbytes, pdx); return ctrl.numbytes; - break; - case PIUSB_USERBUFFER: - if (copy_from_user - (&ctrl, (void __user *)arg, sizeof(struct ioctl_struct))) - info("copy_from_user failed\n"); - return MapUserBuffer((struct ioctl_struct *) & ctrl, pdx); - break; - case PIUSB_UNMAP_USERBUFFER: - UnMapUserBuffer(pdx); - return 0; - break; - case PIUSB_READPIPE: - if (copy_from_user - (&ctrl, (void __user *)arg, sizeof(struct ioctl_struct))) - info("copy_from_user failed\n"); - switch (ctrl.endpoint) { - case 0: //ST133 Pixel Data or PIXIS IO - if (pdx->iama == PIXIS_PID) { - unsigned int numToRead = 0; - unsigned int totalRead = 0; - uBuf = kmalloc(ctrl.numbytes, GFP_KERNEL); - if (!uBuf) { - dbg("Alloc for uBuf failed"); - return 0; - } - numbytes = ctrl.numbytes; - numToRead = numbytes; - dbg("numbytes to read = %d", numbytes); - dbg("endpoint # %d", ctrl.endpoint); - if (copy_from_user(uBuf, ctrl.pData, numbytes)) - dbg("copying ctrl.pData to dummyBuf failed"); - do { - i = usb_bulk_msg(pdx->udev, pdx->hEP[ctrl.endpoint], (uBuf + totalRead), (numToRead > 64) ? 64 : numToRead, &numbytes, HZ * 10); //EP0 can only handle 64 bytes at a time - if (i) { - dbg("CMD = %s, Address = 0x%02X", ((uBuf[3] == 0x02) ? "WRITE" : "READ"), uBuf[1]); - dbg("Number of bytes Attempted to read = %d", (int)ctrl.numbytes); - dbg("Blocking ReadI/O Failed with status %d", i); - kfree(uBuf); - return -1; - } else { - dbg("Pixis EP0 Read %d bytes", - numbytes); - totalRead += numbytes; - numToRead -= numbytes; - } - } - while (numToRead); - memcpy(ctrl.pData, uBuf, totalRead); - dbg("Total Bytes Read from PIXIS EP0 = %d", - totalRead); - ctrl.numbytes = totalRead; - if (copy_to_user - ((struct ioctl_struct *) arg, &ctrl, - sizeof(struct ioctl_struct))) - dbg("copy_to_user failed in IORB"); - kfree(uBuf); - return ctrl.numbytes; - } else //ST133 Pixel Data - { - if (!pdx->gotPixelData) - return 0; - else { - pdx->gotPixelData = 0; - ctrl.numbytes = - pdx->bulk_in_size_returned; - pdx->bulk_in_size_returned -= - pdx->frameSize; - for (i = 0; i < pdx->maplist_numPagesMapped[pdx->active_frame]; i++) - SetPageDirty(pdx->sgl[pdx->active_frame][i].page_link); - pdx->active_frame = - ((pdx->active_frame + - 1) % pdx->num_frames); - return ctrl.numbytes; - } - } - break; - case 1: //ST133IO - case 4: //PIXIS IO - uBuf = kmalloc(ctrl.numbytes, GFP_KERNEL); - if (!uBuf) { - dbg("Alloc for uBuf failed"); - return 0; - } - numbytes = ctrl.numbytes; -// dbg( "numbytes to read = %d", numbytes ); - if (copy_from_user(uBuf, ctrl.pData, numbytes)) - dbg("copying ctrl.pData to dummyBuf failed"); - i = usb_bulk_msg(pdx->udev, pdx->hEP[ctrl.endpoint], - uBuf, numbytes, &numbytes, HZ * 10); - if (i) { - dbg("Blocking ReadI/O Failed with status %d", - i); - kfree(uBuf); - return -1; - } else { - ctrl.numbytes = numbytes; - memcpy(ctrl.pData, uBuf, numbytes); - if (copy_to_user - ((struct ioctl_struct *) arg, &ctrl, - sizeof(struct ioctl_struct))) - dbg("copy_to_user failed in IORB"); - kfree(uBuf); - return ctrl.numbytes; - } - break; - case 2: //PIXIS Ping - case 3: //PIXIS Pong - if (!pdx->gotPixelData) - return 0; - else { - pdx->gotPixelData = 0; - ctrl.numbytes = pdx->bulk_in_size_returned; - pdx->bulk_in_size_returned -= pdx->frameSize; - for (i = 0; - i < - pdx->maplist_numPagesMapped[pdx-> - active_frame]; - i++) - SetPageDirty(pdx->sgl[pdx->active_frame][i].page_link); - pdx->active_frame = - ((pdx->active_frame + 1) % pdx->num_frames); - return ctrl.numbytes; - } - break; + case PIUSB_USERBUFFER: + if (__copy_from_user + (&ctrl, (void __user *)arg, sizeof(struct ioctl_struct))) { + dev_err(&pdx->udev->dev, "copy_from_user failed\n"); + return -EFAULT; } + return MapUserBuffer((struct ioctl_struct *) &ctrl, pdx); + + case PIUSB_UNMAP_USERBUFFER: + retval = UnMapUserBuffer(pdx); + return retval; + + case PIUSB_READPIPE: + if (__copy_from_user(&ctrl, (void __user *)arg, + sizeof(struct ioctl_struct))) { + dev_err(&pdx->udev->dev, "copy_from_user failed\n"); + return -EFAULT; + } + if (((0 == ctrl.endpoint) && (PIXIS_PID == pdx->iama)) || + (1 == ctrl.endpoint) || /* ST133IO */ + (4 == ctrl.endpoint)) /* PIXIS IO */ + return pixis_io(&ctrl, pdx, + (struct ioctl_struct *)arg); + else if ((0 == ctrl.endpoint) || /* ST133 Pixel Data */ + (2 == ctrl.endpoint) || /* PIXIS Ping */ + (3 == ctrl.endpoint)) /* PIXIS Pong */ + return pixel_data(&ctrl, pdx); + break; + case PIUSB_WHATCAMERA: return pdx->iama; + case PIUSB_SETFRAMESIZE: dbg("PIUSB_SETFRAMESIZE"); - if (copy_from_user - (&ctrl, (void __user *)arg, sizeof(struct ioctl_struct))) - info("copy_from_user failed\n"); + if (__copy_from_user + (&ctrl, (void __user *)arg, sizeof(struct ioctl_struct))) { + dev_err(&pdx->udev->dev, "copy_from_user failed\n"); + return -EFAULT; + } pdx->frameSize = ctrl.numbytes; pdx->num_frames = ctrl.numFrames; if (!pdx->sgl) @@ -410,6 +421,7 @@ static int piusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, kmalloc(sizeof(char *) * pdx->num_frames, GFP_KERNEL); return 0; + default: dbg("%s\n", "No IOCTL found"); break; @@ -436,7 +448,7 @@ static void piusb_write_bulk_callback(struct urb *urb) urb->transfer_buffer, urb->transfer_dma); } -int piusb_output(struct ioctl_struct * io, unsigned char *uBuf, int len, +int piusb_output(struct ioctl_struct *io, unsigned char *uBuf, int len, struct device_extension *pdx) { struct urb *urb = NULL; @@ -449,10 +461,13 @@ int piusb_output(struct ioctl_struct * io, unsigned char *uBuf, int len, usb_buffer_alloc(pdx->udev, len, GFP_KERNEL, &urb->transfer_dma); if (!kbuf) { - info("buffer_alloc failed\n"); + dev_err(&pdx->udev->dev, "buffer_alloc failed\n"); return -ENOMEM; } - memcpy(kbuf, uBuf, len); + if(__copy_from_user(kbuf, uBuf, len)) { + dev_err(&pdx->udev->dev, "__copy_from_user failed\n"); + return -EFAULT; + } usb_fill_bulk_urb(urb, pdx->udev, pdx->hEP[io->endpoint], kbuf, len, piusb_write_bulk_callback, pdx); urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; @@ -472,6 +487,7 @@ static int UnMapUserBuffer(struct device_extension *pdx) int i = 0; int k = 0; unsigned int epAddr; + for (k = 0; k < pdx->num_frames; k++) { dbg("Killing Urbs for Frame %d", k); for (i = 0; i < pdx->sgEntries[k]; i++) { @@ -485,23 +501,19 @@ static int UnMapUserBuffer(struct device_extension *pdx) } for (k = 0; k < pdx->num_frames; k++) { - if (pdx->iama == PIXIS_PID) //if so, which EP should we map this frame to - { - if (k % 2) //check to see if this should use EP4(PONG) - { - epAddr = pdx->hEP[3]; //PONG, odd frames - } else { - epAddr = pdx->hEP[2]; //PING, even frames and zero - } - } else //ST133 only has 1 endpoint for Pixel data transfer - { + if (pdx->iama == PIXIS_PID) + /* which EP should we map this frame to ? */ + /* PONG, odd frames: hEP[3] */ + /* PING, even frames and zero hEP[2] */ + epAddr = (k % 2) ? pdx->hEP[3] : pdx->hEP[2]; + else + /* ST133 only has 1 endpoint for Pixel data transfer */ epAddr = pdx->hEP[0]; - } + usb_buffer_unmap_sg(pdx->udev, epAddr, pdx->sgl[k], pdx->maplist_numPagesMapped[k]); - for (i = 0; i < pdx->maplist_numPagesMapped[k]; i++) { - page_cache_release(pdx->sgl[k][i].page_link); - } + for (i = 0; i < pdx->maplist_numPagesMapped[k]; i++) + page_cache_release(sg_page(&pdx->sgl[k][i])); kfree(pdx->sgl[k]); kfree(pdx->PixelUrb[k]); kfree(pdx->pendedPixelUrbs[k]); @@ -509,6 +521,7 @@ static int UnMapUserBuffer(struct device_extension *pdx) pdx->PixelUrb[k] = NULL; pdx->pendedPixelUrbs[k] = NULL; } + kfree(pdx->sgEntries); vfree(pdx->maplist_numPagesMapped); pdx->sgEntries = NULL; @@ -519,6 +532,7 @@ static int UnMapUserBuffer(struct device_extension *pdx) pdx->sgl = NULL; pdx->pendedPixelUrbs = NULL; pdx->PixelUrb = NULL; + return 0; } @@ -539,26 +553,25 @@ static void piusb_readPIXEL_callback(struct urb *urb) pdx->pendedPixelUrbs[pdx->frameIdx][pdx->urbIdx] = 0; } else { pdx->bulk_in_byte_trk += urb->actual_length; - { - i = usb_submit_urb(urb, GFP_ATOMIC); //resubmit the URB - if (i) { - errCnt++; - if (i != lastErr) { - dbg("submit urb in callback failed with error code %d", i); - lastErr = i; - } - } else { - pdx->urbIdx++; //point to next URB when we callback - if (pdx->bulk_in_byte_trk >= pdx->frameSize) { - pdx->bulk_in_size_returned = - pdx->bulk_in_byte_trk; - pdx->bulk_in_byte_trk = 0; - pdx->gotPixelData = 1; - pdx->frameIdx = - ((pdx->frameIdx + - 1) % pdx->num_frames); - pdx->urbIdx = 0; - } + i = usb_submit_urb(urb, GFP_ATOMIC); /* resubmit the URB */ + if (i) { + errCnt++; + if (i != lastErr) { + dbg("submit urb in callback failed " + "with error code %d", i); + lastErr = i; + } + } else { + pdx->urbIdx++; /* point to next URB when we callback */ + if (pdx->bulk_in_byte_trk >= pdx->frameSize) { + pdx->bulk_in_size_returned = + pdx->bulk_in_byte_trk; + pdx->bulk_in_byte_trk = 0; + pdx->gotPixelData = 1; + pdx->frameIdx = + ((pdx->frameIdx + + 1) % pdx->num_frames); + pdx->urbIdx = 0; } } } @@ -566,24 +579,37 @@ static void piusb_readPIXEL_callback(struct urb *urb) /* MapUserBuffer( inputs: - struct ioctl_struct *io - structure containing user address, frame #, and size + struct ioctl_struct *io - structure containing user address, + frame #, and size struct device_extension *pdx - the PIUSB device extension + returns: int - status of the task + Notes: - MapUserBuffer maps a buffer passed down through an ioctl. The user buffer is Page Aligned by the app - and then passed down. The function get_free_pages(...) does the actual mapping of the buffer from user space to - kernel space. From there a scatterlist is created from all the pages. The next function called is to usb_buffer_map_sg - which allocated DMA addresses for each page, even coalescing them if possible. The DMA address is placed in the scatterlist - structure. The function returns the number of DMA addresses. This may or may not be equal to the number of pages that - the user buffer uses. We then build an URB for each DMA address and then submit them. + MapUserBuffer maps a buffer passed down through an ioctl. + The user buffer is Page Aligned by the app and then passed down. + The function get_free_pages(...) does the actual mapping of the buffer + from user space to kernel space. + From there a scatterlist is created from all the pages. + The next function called is to usb_buffer_map_sg which allocated + DMA addresses for each page, even coalescing them if possible. + The DMA address is placed in the scatterlist structure. + The function returns the number of DMA addresses. + This may or may not be equal to the number of pages that + the user buffer uses. + We then build an URB for each DMA address and then submit them. +*/ + +/* +int MapUserBuffer(unsigned long uaddr, unsigned long numbytes, + unsigned long frameInfo, struct device_extension *pdx) */ -//int MapUserBuffer( unsigned long uaddr, unsigned long numbytes, unsigned long frameInfo, struct device_extension *pdx ) static int MapUserBuffer(struct ioctl_struct *io, struct device_extension *pdx) { unsigned long uaddr; unsigned long numbytes; - int frameInfo; //which frame we're mapping + int frameInfo; /* which frame we're mapping */ unsigned int epAddr = 0; unsigned long count = 0; int i = 0; @@ -591,45 +617,45 @@ static int MapUserBuffer(struct ioctl_struct *io, struct device_extension *pdx) int err = 0; struct page **maplist_p; int numPagesRequired; + frameInfo = io->numFrames; uaddr = (unsigned long)io->pData; numbytes = io->numbytes; - if (pdx->iama == PIXIS_PID) //if so, which EP should we map this frame to - { - if (frameInfo % 2) //check to see if this should use EP4(PONG) - { - epAddr = pdx->hEP[3]; //PONG, odd frames - } else { - epAddr = pdx->hEP[2]; //PING, even frames and zero - } + if (pdx->iama == PIXIS_PID) { + /* which EP should we map this frame to ? */ + /* PONG, odd frames: hEP[3] */ + /* PING, even frames and zero hEP[2] */ + epAddr = (frameInfo % 2) ? pdx->hEP[3] : pdx->hEP[2]; dbg("Pixis Frame #%d: EP=%d", frameInfo, (epAddr == pdx->hEP[2]) ? 2 : 4); - } else //ST133 only has 1 endpoint for Pixel data transfer - { + } else { /* ST133 only has 1 endpoint for Pixel data transfer */ epAddr = pdx->hEP[0]; dbg("ST133 Frame #%d: EP=2", frameInfo); } count = numbytes; dbg("UserAddress = 0x%08lX", uaddr); dbg("numbytes = %d", (int)numbytes); - //number of pages to map the entire user space DMA buffer + + /* number of pages to map the entire user space DMA buffer */ numPagesRequired = ((uaddr & ~PAGE_MASK) + count + ~PAGE_MASK) >> PAGE_SHIFT; dbg("Number of pages needed = %d", numPagesRequired); - maplist_p = vmalloc(numPagesRequired * sizeof(struct page)); //, GFP_ATOMIC); + maplist_p = vmalloc(numPagesRequired * sizeof(struct page)); if (!maplist_p) { dbg("Can't Allocate Memory for maplist_p"); return -ENOMEM; } - //map the user buffer to kernel memory + + /* map the user buffer to kernel memory */ down_write(¤t->mm->mmap_sem); - pdx->maplist_numPagesMapped[frameInfo] = get_user_pages(current, current->mm, (uaddr & PAGE_MASK), numPagesRequired, WRITE, 0, //Don't Force - maplist_p, - NULL); + pdx->maplist_numPagesMapped[frameInfo] = get_user_pages(current, + current->mm, (uaddr & PAGE_MASK), numPagesRequired, + WRITE, 0 /* Don't Force*/, maplist_p, NULL); up_write(¤t->mm->mmap_sem); dbg("Number of pages mapped = %d", pdx->maplist_numPagesMapped[frameInfo]); + for (i = 0; i < pdx->maplist_numPagesMapped[frameInfo]; i++) flush_dcache_page(maplist_p[i]); if (!pdx->maplist_numPagesMapped[frameInfo]) { @@ -637,7 +663,10 @@ static int MapUserBuffer(struct ioctl_struct *io, struct device_extension *pdx) vfree(maplist_p); return -ENOMEM; } - //need to create a scatterlist that spans each frame that can fit into the mapped buffer + + /* need to create a scatterlist that spans each frame + * that can fit into the mapped buffer + */ pdx->sgl[frameInfo] = kmalloc((pdx->maplist_numPagesMapped[frameInfo] * sizeof(struct scatterlist)), GFP_ATOMIC); @@ -646,7 +675,7 @@ static int MapUserBuffer(struct ioctl_struct *io, struct device_extension *pdx) dbg("can't allocate mem for sgl"); return -ENOMEM; } - pdx->sgl[frameInfo][0].page_link = maplist_p[0]; + sg_assign_page(&pdx->sgl[frameInfo][0], maplist_p[0]); pdx->sgl[frameInfo][0].offset = uaddr & ~PAGE_MASK; if (pdx->maplist_numPagesMapped[frameInfo] > 1) { pdx->sgl[frameInfo][0].length = @@ -654,10 +683,10 @@ static int MapUserBuffer(struct ioctl_struct *io, struct device_extension *pdx) count -= pdx->sgl[frameInfo][0].length; for (k = 1; k < pdx->maplist_numPagesMapped[frameInfo]; k++) { pdx->sgl[frameInfo][k].offset = 0; - pdx->sgl[frameInfo][k].page_link = maplist_p[k]; + sg_assign_page(&pdx->sgl[frameInfo][k], maplist_p[k]); pdx->sgl[frameInfo][k].length = (count < PAGE_SIZE) ? count : PAGE_SIZE; - count -= PAGE_SIZE; //example had PAGE_SIZE here; + count -= PAGE_SIZE; /* example had PAGE_SIZE here */ } } else { pdx->sgl[frameInfo][0].length = count; @@ -668,7 +697,8 @@ static int MapUserBuffer(struct ioctl_struct *io, struct device_extension *pdx) dbg("number of sgEntries = %d", pdx->sgEntries[frameInfo]); pdx->userBufMapped = 1; vfree(maplist_p); - //Create and Send the URB's for each s/g entry + + /* Create and Send the URB's for each s/g entry */ pdx->PixelUrb[frameInfo] = kmalloc(pdx->sgEntries[frameInfo] * sizeof(struct urb *), GFP_KERNEL); @@ -677,7 +707,8 @@ static int MapUserBuffer(struct ioctl_struct *io, struct device_extension *pdx) return -ENOMEM; } for (i = 0; i < pdx->sgEntries[frameInfo]; i++) { - pdx->PixelUrb[frameInfo][i] = usb_alloc_urb(0, GFP_KERNEL); //0 because we're using BULK transfers + /* 0 iso packets because we're using BULK transfers */ + pdx->PixelUrb[frameInfo][i] = usb_alloc_urb(0, GFP_KERNEL); usb_fill_bulk_urb(pdx->PixelUrb[frameInfo][i], pdx->udev, epAddr, @@ -691,7 +722,8 @@ static int MapUserBuffer(struct ioctl_struct *io, struct device_extension *pdx) pdx->PixelUrb[frameInfo][i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP | URB_NO_INTERRUPT; } - pdx->PixelUrb[frameInfo][--i]->transfer_flags &= ~URB_NO_INTERRUPT; //only interrupt when last URB completes + /* only interrupt when last URB completes */ + pdx->PixelUrb[frameInfo][--i]->transfer_flags &= ~URB_NO_INTERRUPT; pdx->pendedPixelUrbs[frameInfo] = kmalloc((pdx->sgEntries[frameInfo] * sizeof(char)), GFP_KERNEL); if (!pdx->pendedPixelUrbs[frameInfo]) @@ -702,13 +734,13 @@ static int MapUserBuffer(struct ioctl_struct *io, struct device_extension *pdx) dbg("%s %d\n", "submit urb error =", err); pdx->pendedPixelUrbs[frameInfo][i] = 0; return err; - } else - pdx->pendedPixelUrbs[frameInfo][i] = 1;; + } + pdx->pendedPixelUrbs[frameInfo][i] = 1; } return 0; } -static struct file_operations piusb_fops = { +static const struct file_operations piusb_fops = { .owner = THIS_MODULE, .ioctl = piusb_ioctl, .open = piusb_open, @@ -751,9 +783,9 @@ static int piusb_probe(struct usb_interface *interface, /* See if the device offered us matches what we can accept */ if ((pdx->udev->descriptor.idVendor != VENDOR_ID) || ((pdx->udev->descriptor.idProduct != PIXIS_PID) - && (pdx->udev->descriptor.idProduct != ST133_PID))) { + && (pdx->udev->descriptor.idProduct != ST133_PID))) return -ENODEV; - } + pdx->iama = pdx->udev->descriptor.idProduct; if (debug) { @@ -807,7 +839,7 @@ static int piusb_probe(struct usb_interface *interface, dbg("PI USB2.0 device now attached to piusb-%d", pdx->minor); return 0; - error: +error: if (pdx) kref_put(&pdx->kref, piusb_delete); return retval; @@ -828,12 +860,17 @@ static void piusb_disconnect(struct usb_interface *interface) { struct device_extension *pdx; int minor = interface->minor; + lock_kernel(); + pdx = usb_get_intfdata(interface); usb_set_intfdata(interface, NULL); + /* give back our minor */ usb_deregister_dev(interface, &piusb_class); + unlock_kernel(); + /* prevent device read, write and ioctl */ pdx->present = 0; kref_put(&pdx->kref, piusb_delete); @@ -853,16 +890,20 @@ static struct usb_driver piusb_driver = { static int __init piusb_init(void) { int result; + + lastErr = 0; + errCnt = 0; + /* register this driver with the USB subsystem */ result = usb_register(&piusb_driver); - if (result) { + if (result) printk(KERN_ERR KBUILD_MODNAME - ": usb_register failed. Error number %d\n", result); - return result; - } - printk(KERN_INFO KBUILD_MODNAME ":%s: %s\n", DRIVER_DESC, - DRIVER_VERSION); - return 0; + ": usb_register failed. Error number %d\n", + result); + else + printk(KERN_INFO KBUILD_MODNAME ":%s: %s\n", DRIVER_DESC, + DRIVER_VERSION); + return result; } /** diff --git a/drivers/staging/rspiusb/rspiusb.h b/drivers/staging/rspiusb/rspiusb.h index 965cd2d8c194..3fc1db7b1c4c 100644 --- a/drivers/staging/rspiusb/rspiusb.h +++ b/drivers/staging/rspiusb/rspiusb.h @@ -3,20 +3,28 @@ #define PIUSB_MAGIC 'm' #define PIUSB_IOCTL_BASE 192 -#define PIUSB_GETVNDCMD _IOR(PIUSB_MAGIC, PIUSB_IOCTL_BASE + 1, struct ioctl_struct) -#define PIUSB_SETVNDCMD _IOW(PIUSB_MAGIC, PIUSB_IOCTL_BASE + 2, struct ioctl_struct) -#define PIUSB_WRITEPIPE _IOW(PIUSB_MAGIC, PIUSB_IOCTL_BASE + 3, struct ioctl_struct) -#define PIUSB_READPIPE _IOR(PIUSB_MAGIC, PIUSB_IOCTL_BASE + 4, struct ioctl_struct) -#define PIUSB_SETFRAMESIZE _IOW(PIUSB_MAGIC, PIUSB_IOCTL_BASE + 5, struct ioctl_struct) -#define PIUSB_WHATCAMERA _IO(PIUSB_MAGIC, PIUSB_IOCTL_BASE + 6) -#define PIUSB_USERBUFFER _IOW(PIUSB_MAGIC, PIUSB_IOCTL_BASE + 7, struct ioctl_struct) -#define PIUSB_ISHIGHSPEED _IO(PIUSB_MAGIC, PIUSB_IOCTL_BASE + 8) -#define PIUSB_UNMAP_USERBUFFER _IOW(PIUSB_MAGIC, PIUSB_IOCTL_BASE + 9, struct ioctl_struct) + +#define PIUSB_IOR(offset) \ + _IOR(PIUSB_MAGIC, PIUSB_IOCTL_BASE + offset, struct ioctl_struct) +#define PIUSB_IOW(offset) \ + _IOW(PIUSB_MAGIC, PIUSB_IOCTL_BASE + offset, struct ioctl_struct) +#define PIUSB_IO(offset) \ + _IO(PIUSB_MAGIC, PIUSB_IOCTL_BASE + offset) + +#define PIUSB_GETVNDCMD PIUSB_IOR(1) +#define PIUSB_SETVNDCMD PIUSB_IOW(2) +#define PIUSB_WRITEPIPE PIUSB_IOW(3) +#define PIUSB_READPIPE PIUSB_IOR(4) +#define PIUSB_SETFRAMESIZE PIUSB_IOW(5) +#define PIUSB_WHATCAMERA PIUSB_IO(6) +#define PIUSB_USERBUFFER PIUSB_IOW(7) +#define PIUSB_ISHIGHSPEED PIUSB_IO(8) +#define PIUSB_UNMAP_USERBUFFER PIUSB_IOW(9) struct ioctl_struct { unsigned char cmd; unsigned long numbytes; - unsigned char dir; //1=out;0=in + unsigned char dir; /* 1=out; 0=in */ int endpoint; int numFrames; unsigned char *pData; diff --git a/drivers/staging/rt2860/2860_main_dev.c b/drivers/staging/rt2860/2860_main_dev.c index ff7f83380736..c7038e03a4dc 100644 --- a/drivers/staging/rt2860/2860_main_dev.c +++ b/drivers/staging/rt2860/2860_main_dev.c @@ -37,13 +37,6 @@ #include "rt_config.h" - -#ifdef MULTIPLE_CARD_SUPPORT -// record whether the card in the card list is used in the card file -extern UINT8 MC_CardUsed[]; -#endif // MULTIPLE_CARD_SUPPORT // - - extern INT __devinit rt28xx_probe(IN void *_dev_p, IN void *_dev_id_p, IN UINT argc, OUT PRTMP_ADAPTER *ppAd); @@ -110,13 +103,10 @@ static struct pci_device_id rt2860_pci_tbl[] __devinitdata = }; MODULE_DEVICE_TABLE(pci, rt2860_pci_tbl); -#ifdef CONFIG_STA_SUPPORT MODULE_LICENSE("GPL"); #ifdef MODULE_VERSION MODULE_VERSION(STA_DRIVER_VERSION); #endif -#endif // CONFIG_STA_SUPPORT // - // // Our PCI driver structure @@ -328,14 +318,6 @@ static VOID __devexit rt2860_remove_one( if (pAd != NULL) { -#ifdef MULTIPLE_CARD_SUPPORT - if ((pAd->MC_RowID >= 0) && (pAd->MC_RowID <= MAX_NUM_OF_MULTIPLE_CARD)) - MC_CardUsed[pAd->MC_RowID] = 0; // not clear MAC address -#endif // MULTIPLE_CARD_SUPPORT // - - - - // Unregister network device unregister_netdev(net_dev); @@ -494,10 +476,8 @@ static void rx_done_tasklet(unsigned long data) pObj = (POS_COOKIE) pAd->OS_Cookie; pAd->int_pending &= ~(INT_RX); -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - bReschedule = STARxDoneInterruptHandle(pAd, 0); -#endif // CONFIG_STA_SUPPORT // + + bReschedule = STARxDoneInterruptHandle(pAd, 0); RTMP_INT_LOCK(&pAd->irq_lock, flags); /* @@ -933,15 +913,8 @@ rt2860_interrupt(int irq, void *dev_instance) RTMPHandleTBTTInterrupt(pAd); } - - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - if (IntSource.word & AutoWakeupInt) - RTMPHandleTwakeupInterrupt(pAd); - } -#endif // CONFIG_STA_SUPPORT // + if (IntSource.word & AutoWakeupInt) + RTMPHandleTwakeupInterrupt(pAd); return IRQ_HANDLED; } @@ -1182,9 +1155,7 @@ VOID RT28xx_UpdateBeaconToAsic( else { ptr = (PUCHAR)&pAd->BeaconTxWI; -#ifdef RT_BIG_ENDIAN - RTMPWIEndianChange(ptr, TYPE_TXWI); -#endif + for (i=0; iCommonCfg.RegTransmitSetting.field.BW = BW_20; //pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_NONE; // We didn't set the ExtCh as NONE due to it'll set in RTMPSetHT() } -#if 0 - switch (pAd->CommonCfg.CountryRegion & 0x7f) - { - case REGION_0_BG_BAND: // 1 -11 - case REGION_1_BG_BAND: // 1 - 13 - case REGION_5_BG_BAND: // 1 - 14 - if (Channel <= 4) - { - pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_ABOVE; - } - else if (Channel >= 8) - { - if ((ChannelNum - Channel) < 4) - pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_BELOW; - } - break; - - case REGION_2_BG_BAND: // 10 - 11 - case REGION_3_BG_BAND: // 10 - 13 - case REGION_4_BG_BAND: // 14 - pAd->CommonCfg.RegTransmitSetting.field.BW = BW_20; - break; - - case REGION_6_BG_BAND: // 3 - 9 - if (Channel <= 5) - pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_ABOVE; - else if (Channel == 6) - pAd->CommonCfg.RegTransmitSetting.field.BW = BW_20; - else if (Channel >= 7) - pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_BELOW; - break; - - case REGION_7_BG_BAND: // 5 - 13 - if (Channel <= 8) - pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_ABOVE; - else if (Channel >= 10) - pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_BELOW; - break; - - default: // Error. should never happen - break; - } -#endif } } @@ -1273,8 +1229,6 @@ static inline VOID N_SetCenCh( pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel; } } -#endif // DOT11_N_SUPPORT // - static inline UINT8 GetCuntryMaxTxPwr( IN PRTMP_ADAPTER pAd, diff --git a/drivers/staging/rt2860/common/2860_rtmp_init.c b/drivers/staging/rt2860/common/2860_rtmp_init.c index 546f304ec330..0bc0fb99d2e4 100644 --- a/drivers/staging/rt2860/common/2860_rtmp_init.c +++ b/drivers/staging/rt2860/common/2860_rtmp_init.c @@ -173,9 +173,6 @@ NDIS_STATUS RTMPAllocTxRxRingMemory( pTxD->SDPtr0 = BufBasePaLow; // advance to next ring descriptor address pTxD->DMADONE = 1; -#ifdef RT_BIG_ENDIAN - RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); -#endif RingBasePaLow += TXD_SIZE; RingBaseVa = (PUCHAR) RingBaseVa + TXD_SIZE; @@ -236,9 +233,6 @@ NDIS_STATUS RTMPAllocTxRxRingMemory( pTxD = (PTXD_STRUC) pAd->MgmtRing.Cell[index].AllocVa; pTxD->DMADONE = 1; -#ifdef RT_BIG_ENDIAN - RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); -#endif // no pre-allocated buffer required in MgmtRing for scatter-gather case } DBGPRINT(RT_DEBUG_TRACE, ("MGMT Ring: total %d entry allocated\n", index)); @@ -318,10 +312,6 @@ NDIS_STATUS RTMPAllocTxRxRingMemory( pRxD = (PRXD_STRUC) pAd->RxRing.Cell[index].AllocVa; pRxD->SDP0 = RTMP_GetPhysicalAddressLow(pDmaBuf->AllocPa); pRxD->DDONE = 0; - -#ifdef RT_BIG_ENDIAN - RTMPDescriptorEndianChange((PUCHAR)pRxD, TYPE_RXD); -#endif } DBGPRINT(RT_DEBUG_TRACE, ("Rx Ring: total %d entry allocated\n", index)); @@ -821,10 +811,6 @@ PNDIS_PACKET GetPacketFromRxRing( IN OUT UINT32 *pRxPending) { PRXD_STRUC pRxD; -#ifdef RT_BIG_ENDIAN - PRXD_STRUC pDestRxD; - RXD_STRUC RxD; -#endif PNDIS_PACKET pRxPacket = NULL; PNDIS_PACKET pNewPacket; PVOID AllocVa; @@ -853,15 +839,8 @@ PNDIS_PACKET GetPacketFromRxRing( } -#ifdef RT_BIG_ENDIAN - pDestRxD = (PRXD_STRUC) pAd->RxRing.Cell[pAd->RxRing.RxSwReadIdx].AllocVa; - RxD = *pDestRxD; - pRxD = &RxD; - RTMPDescriptorEndianChange((PUCHAR)pRxD, TYPE_RXD); -#else // Point to Rx indexed rx ring descriptor pRxD = (PRXD_STRUC) pAd->RxRing.Cell[pAd->RxRing.RxSwReadIdx].AllocVa; -#endif if (pRxD->DDONE == 0) { @@ -904,10 +883,6 @@ PNDIS_PACKET GetPacketFromRxRing( *pRxPending = *pRxPending - 1; // update rx descriptor and kick rx -#ifdef RT_BIG_ENDIAN - RTMPDescriptorEndianChange((PUCHAR)pRxD, TYPE_RXD); - WriteBackToDescriptor((PUCHAR)pDestRxD, (PUCHAR)pRxD, FALSE, TYPE_RXD); -#endif INC_RING_INDEX(pAd->RxRing.RxSwReadIdx, RX_RING_SIZE); pAd->RxRing.RxCpuIdx = (pAd->RxRing.RxSwReadIdx == 0) ? (RX_RING_SIZE-1) : (pAd->RxRing.RxSwReadIdx-1); diff --git a/drivers/staging/rt2860/common/action.c b/drivers/staging/rt2860/common/action.c index d6f530fb857f..a4d9fdc0736e 100644 --- a/drivers/staging/rt2860/common/action.c +++ b/drivers/staging/rt2860/common/action.c @@ -72,17 +72,12 @@ VOID ActionStateMachineInit( StateMachineSetAction(S, ACT_IDLE, MT2_PEER_QOS_CATE, (STATE_MACHINE_FUNC)PeerQOSAction); StateMachineSetAction(S, ACT_IDLE, MT2_PEER_DLS_CATE, (STATE_MACHINE_FUNC)ReservedAction); -#ifdef QOS_DLS_SUPPORT - StateMachineSetAction(S, ACT_IDLE, MT2_PEER_DLS_CATE, (STATE_MACHINE_FUNC)PeerDLSAction); -#endif // QOS_DLS_SUPPORT // -#ifdef DOT11_N_SUPPORT StateMachineSetAction(S, ACT_IDLE, MT2_PEER_BA_CATE, (STATE_MACHINE_FUNC)PeerBAAction); StateMachineSetAction(S, ACT_IDLE, MT2_PEER_HT_CATE, (STATE_MACHINE_FUNC)PeerHTAction); StateMachineSetAction(S, ACT_IDLE, MT2_MLME_ADD_BA_CATE, (STATE_MACHINE_FUNC)MlmeADDBAAction); StateMachineSetAction(S, ACT_IDLE, MT2_MLME_ORI_DELBA_CATE, (STATE_MACHINE_FUNC)MlmeDELBAAction); StateMachineSetAction(S, ACT_IDLE, MT2_MLME_REC_DELBA_CATE, (STATE_MACHINE_FUNC)MlmeDELBAAction); -#endif // DOT11_N_SUPPORT // StateMachineSetAction(S, ACT_IDLE, MT2_PEER_PUBLIC_CATE, (STATE_MACHINE_FUNC)PeerPublicAction); StateMachineSetAction(S, ACT_IDLE, MT2_PEER_RM_CATE, (STATE_MACHINE_FUNC)PeerRMAction); @@ -92,7 +87,6 @@ VOID ActionStateMachineInit( StateMachineSetAction(S, ACT_IDLE, MT2_ACT_INVALID, (STATE_MACHINE_FUNC)MlmeInvalidAction); } -#ifdef DOT11_N_SUPPORT VOID MlmeADDBAAction( IN PRTMP_ADAPTER pAd, IN MLME_QUEUE_ELEM *Elem) @@ -131,21 +125,12 @@ VOID MlmeADDBAAction( pBAEntry =&pAd->BATable.BAOriEntry[Idx]; } -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { if (ADHOC_ON(pAd)) ActHeaderInit(pAd, &Frame.Hdr, pInfo->pAddr, pAd->CurrentAddress, pAd->CommonCfg.Bssid); else -#ifdef QOS_DLS_SUPPORT - if (pAd->MacTab.Content[pInfo->Wcid].ValidAsDls) - ActHeaderInit(pAd, &Frame.Hdr, pInfo->pAddr, pAd->CurrentAddress, pAd->CommonCfg.Bssid); - else -#endif // QOS_DLS_SUPPORT // ActHeaderInit(pAd, &Frame.Hdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pInfo->pAddr); - } -#endif // CONFIG_STA_SUPPORT // Frame.Category = CATEGORY_BA; Frame.Action = ADDBA_REQ; @@ -220,10 +205,8 @@ VOID MlmeDELBAAction( // SEND BAR (Send BAR to refresh peer reordering buffer.) Idx = pAd->MacTab.Content[pInfo->Wcid].BAOriWcidArray[pInfo->TID]; -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - BarHeaderInit(pAd, &FrameBar, pAd->MacTab.Content[pInfo->Wcid].Addr, pAd->CurrentAddress); -#endif // CONFIG_STA_SUPPORT // + + BarHeaderInit(pAd, &FrameBar, pAd->MacTab.Content[pInfo->Wcid].Addr, pAd->CurrentAddress); FrameBar.StartingSeq.field.FragNum = 0; // make sure sequence not clear in DEL funciton. FrameBar.StartingSeq.field.StartSeq = pAd->MacTab.Content[pInfo->Wcid].TxSeq[pInfo->TID]; // make sure sequence not clear in DEL funciton. @@ -241,20 +224,14 @@ VOID MlmeDELBAAction( // SEND DELBA FRAME FrameLen = 0; -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) + { if (ADHOC_ON(pAd)) ActHeaderInit(pAd, &Frame.Hdr, pAd->MacTab.Content[pInfo->Wcid].Addr, pAd->CurrentAddress, pAd->CommonCfg.Bssid); else -#ifdef QOS_DLS_SUPPORT - if (pAd->MacTab.Content[pInfo->Wcid].ValidAsDls) - ActHeaderInit(pAd, &Frame.Hdr, pAd->MacTab.Content[pInfo->Wcid].Addr, pAd->CurrentAddress, pAd->CommonCfg.Bssid); - else -#endif // QOS_DLS_SUPPORT // ActHeaderInit(pAd, &Frame.Hdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pAd->MacTab.Content[pInfo->Wcid].Addr); } -#endif // CONFIG_STA_SUPPORT // + Frame.Category = CATEGORY_BA; Frame.Action = DELBA; Frame.DelbaParm.Initiator = pInfo->Initiator; @@ -271,7 +248,6 @@ VOID MlmeDELBAAction( DBGPRINT(RT_DEBUG_TRACE, ("BA - MlmeDELBAAction() . 3 DELBA sent. Initiator(%d)\n", pInfo->Initiator)); } } -#endif // DOT11_N_SUPPORT // VOID MlmeQOSAction( IN PRTMP_ADAPTER pAd, @@ -299,40 +275,6 @@ VOID PeerQOSAction( { } -#ifdef QOS_DLS_SUPPORT -VOID PeerDLSAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - UCHAR Action = Elem->Msg[LENGTH_802_11+1]; - - switch(Action) - { - case ACTION_DLS_REQUEST: -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - PeerDlsReqAction(pAd, Elem); -#endif // CONFIG_STA_SUPPORT // - break; - - case ACTION_DLS_RESPONSE: -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - PeerDlsRspAction(pAd, Elem); -#endif // CONFIG_STA_SUPPORT // - break; - - case ACTION_DLS_TEARDOWN: -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - PeerDlsTearDownAction(pAd, Elem); -#endif // CONFIG_STA_SUPPORT // - break; - } -} -#endif // QOS_DLS_SUPPORT // - -#ifdef DOT11_N_SUPPORT VOID PeerBAAction( IN PRTMP_ADAPTER pAd, IN MLME_QUEUE_ELEM *Elem) @@ -353,320 +295,12 @@ VOID PeerBAAction( } } - -#ifdef DOT11N_DRAFT3 - -#ifdef CONFIG_STA_SUPPORT -VOID StaPublicAction( - IN PRTMP_ADAPTER pAd, - IN UCHAR Bss2040Coexist) -{ - BSS_2040_COEXIST_IE BssCoexist; - MLME_SCAN_REQ_STRUCT ScanReq; - - BssCoexist.word = Bss2040Coexist; - // AP asks Station to return a 20/40 BSS Coexistence mgmt frame. So we first starts a scan, then send back 20/40 BSS Coexistence mgmt frame - if ((BssCoexist.field.InfoReq == 1) && (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_SCAN_2040))) - { - // Clear record first. After scan , will update those bit and send back to transmiter. - pAd->CommonCfg.BSSCoexist2040.field.InfoReq = 1; - pAd->CommonCfg.BSSCoexist2040.field.Intolerant40 = 0; - pAd->CommonCfg.BSSCoexist2040.field.BSS20WidthReq = 0; - // Fill out stuff for scan request - ScanParmFill(pAd, &ScanReq, ZeroSsid, 0, BSS_ANY, SCAN_2040_BSS_COEXIST); - MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq); - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN; - } -} - - -/* -Description : Build Intolerant Channel Rerpot from Trigger event table. -return : how many bytes copied. -*/ -ULONG BuildIntolerantChannelRep( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDest) -{ - ULONG FrameLen = 0; - ULONG ReadOffset = 0; - UCHAR i; - UCHAR LastRegClass = 0xff; - PUCHAR pLen; - - for ( i = 0;i < MAX_TRIGGER_EVENT;i++) - { - if (pAd->CommonCfg.TriggerEventTab.EventA[i].bValid == TRUE) - { - if (pAd->CommonCfg.TriggerEventTab.EventA[i].RegClass == LastRegClass) - { - *(pDest + ReadOffset) = (UCHAR)pAd->CommonCfg.TriggerEventTab.EventA[i].Channel; - *pLen++; - ReadOffset++; - FrameLen++; - } - else - { - *(pDest + ReadOffset) = IE_2040_BSS_INTOLERANT_REPORT; // IE - *(pDest + ReadOffset + 1) = 2; // Len = RegClass byte + channel byte. - pLen = pDest + ReadOffset + 1; - LastRegClass = pAd->CommonCfg.TriggerEventTab.EventA[i].RegClass; - *(pDest + ReadOffset + 2) = LastRegClass; // Len = RegClass byte + channel byte. - *(pDest + ReadOffset + 3) = (UCHAR)pAd->CommonCfg.TriggerEventTab.EventA[i].Channel; - FrameLen += 4; - ReadOffset += 4; - } - - } - } - return FrameLen; -} - - -/* -Description : Send 20/40 BSS Coexistence Action frame If one trigger event is triggered. -*/ -VOID Send2040CoexistAction( - IN PRTMP_ADAPTER pAd, - IN UCHAR Wcid, - IN BOOLEAN bAddIntolerantCha) -{ - PUCHAR pOutBuffer = NULL; - NDIS_STATUS NStatus; - FRAME_ACTION_HDR Frame; - ULONG FrameLen; - ULONG IntolerantChaRepLen; - - IntolerantChaRepLen = 0; - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory - if(NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_ERROR,("ACT - Send2040CoexistAction() allocate memory failed \n")); - return; - } - ActHeaderInit(pAd, &Frame.Hdr, pAd->MacTab.Content[Wcid].Addr, pAd->CommonCfg.Bssid); - Frame.Category = CATEGORY_PUBLIC; - Frame.Action = ACTION_BSS_2040_COEXIST; - - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(FRAME_ACTION_HDR), &Frame, - END_OF_ARGS); - - *(pOutBuffer + FrameLen) = pAd->CommonCfg.BSSCoexist2040.word; - FrameLen++; - - if (bAddIntolerantCha == TRUE) - IntolerantChaRepLen = BuildIntolerantChannelRep(pAd, pOutBuffer + FrameLen); - - MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen + IntolerantChaRepLen); - DBGPRINT(RT_DEBUG_ERROR,("ACT - Send2040CoexistAction( BSSCoexist2040 = 0x%x ) \n", pAd->CommonCfg.BSSCoexist2040.word)); - -} - - -/* - ========================================================================== - Description: - After scan, Update 20/40 BSS Coexistence IE and send out. - According to 802.11n D3.03 11.14.10 - - Parameters: - ========================================================================== - */ -VOID Update2040CoexistFrameAndNotify( - IN PRTMP_ADAPTER pAd, - IN UCHAR Wcid, - IN BOOLEAN bAddIntolerantCha) -{ - BSS_2040_COEXIST_IE OldValue; - - OldValue.word = pAd->CommonCfg.BSSCoexist2040.word; - if ((pAd->CommonCfg.TriggerEventTab.EventANo > 0) || (pAd->CommonCfg.TriggerEventTab.EventBCountDown > 0)) - pAd->CommonCfg.BSSCoexist2040.field.BSS20WidthReq = 1; - - // Need to check !!!! - // How STA will set Intolerant40 if implementation dependent. Now we don't set this bit first.!!!!! - // So Only check BSS20WidthReq change. - if (OldValue.field.BSS20WidthReq != pAd->CommonCfg.BSSCoexist2040.field.BSS20WidthReq) - { - Send2040CoexistAction(pAd, Wcid, bAddIntolerantCha); - } -} -#endif // CONFIG_STA_SUPPORT // - - -BOOLEAN ChannelSwitchSanityCheck( - IN PRTMP_ADAPTER pAd, - IN UCHAR Wcid, - IN UCHAR NewChannel, - IN UCHAR Secondary) -{ - UCHAR i; - - if (Wcid >= MAX_LEN_OF_MAC_TABLE) - return FALSE; - - if ((NewChannel > 7) && (Secondary == 1)) - return FALSE; - - if ((NewChannel < 5) && (Secondary == 3)) - return FALSE; - - // 0. Check if new channel is in the channellist. - for (i = 0;i < pAd->ChannelListNum;i++) - { - if (pAd->ChannelList[i].Channel == NewChannel) - { - break; - } - } - - if (i == pAd->ChannelListNum) - return FALSE; - - return TRUE; -} - - -VOID ChannelSwitchAction( - IN PRTMP_ADAPTER pAd, - IN UCHAR Wcid, - IN UCHAR NewChannel, - IN UCHAR Secondary) -{ - UCHAR BBPValue = 0; - ULONG MACValue; - - DBGPRINT(RT_DEBUG_TRACE,("SPECTRUM - ChannelSwitchAction(NewChannel = %d , Secondary = %d) \n", NewChannel, Secondary)); - - if (ChannelSwitchSanityCheck(pAd, Wcid, NewChannel, Secondary) == FALSE) - return; - - // 1. Switches to BW = 20. - if (Secondary == 0) - { - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); - BBPValue&= (~0x18); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); - if (pAd->MACVersion == 0x28600100) - { - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, 0x16); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, 0x08); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R73, 0x11); - DBGPRINT(RT_DEBUG_TRACE, ("!!!rt2860C !!! \n" )); - } - pAd->CommonCfg.BBPCurrentBW = BW_20; - pAd->CommonCfg.Channel = NewChannel; - pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel; - AsicSwitchChannel(pAd, pAd->CommonCfg.Channel,FALSE); - AsicLockChannel(pAd, pAd->CommonCfg.Channel); - pAd->MacTab.Content[Wcid].HTPhyMode.field.BW = 0; - DBGPRINT(RT_DEBUG_TRACE, ("!!!20MHz !!! \n" )); - } - // 1. Switches to BW = 40 And Station supports BW = 40. - else if (((Secondary == 1) || (Secondary == 3)) && (pAd->CommonCfg.HtCapability.HtCapInfo.ChannelWidth == 1)) - { - pAd->CommonCfg.Channel = NewChannel; - - if (Secondary == 1) - { - // Secondary above. - pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel + 2; - RTMP_IO_READ32(pAd, TX_BAND_CFG, &MACValue); - MACValue &= 0xfe; - RTMP_IO_WRITE32(pAd, TX_BAND_CFG, MACValue); - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); - BBPValue&= (~0x18); - BBPValue|= (0x10); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BBPValue); - BBPValue&= (~0x20); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BBPValue); - DBGPRINT(RT_DEBUG_TRACE, ("!!!40MHz Lower LINK UP !!! Control Channel at Below. Central = %d \n", pAd->CommonCfg.CentralChannel )); - } - else - { - // Secondary below. - pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel - 2; - RTMP_IO_READ32(pAd, TX_BAND_CFG, &MACValue); - MACValue &= 0xfe; - MACValue |= 0x1; - RTMP_IO_WRITE32(pAd, TX_BAND_CFG, MACValue); - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); - BBPValue&= (~0x18); - BBPValue|= (0x10); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BBPValue); - BBPValue&= (~0x20); - BBPValue|= (0x20); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BBPValue); - DBGPRINT(RT_DEBUG_TRACE, ("!!!40MHz Upper LINK UP !!! Control Channel at UpperCentral = %d \n", pAd->CommonCfg.CentralChannel )); - } - pAd->CommonCfg.BBPCurrentBW = BW_40; - AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE); - AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel); - pAd->MacTab.Content[Wcid].HTPhyMode.field.BW = 1; - } -} -#endif // DOT11N_DRAFT3 // -#endif // DOT11_N_SUPPORT // - VOID PeerPublicAction( IN PRTMP_ADAPTER pAd, IN MLME_QUEUE_ELEM *Elem) { -#ifdef DOT11N_DRAFT3 - UCHAR Action = Elem->Msg[LENGTH_802_11+1]; -#endif // DOT11N_DRAFT3 // - if (Elem->Wcid >= MAX_LEN_OF_MAC_TABLE) return; - -#ifdef DOT11N_DRAFT3 - switch(Action) - { - case ACTION_BSS_2040_COEXIST: // Format defined in IEEE 7.4.7a.1 in 11n Draf3.03 - { - //UCHAR BssCoexist; - BSS_2040_COEXIST_ELEMENT *pCoexistInfo; - BSS_2040_COEXIST_IE *pBssCoexistIe; - BSS_2040_INTOLERANT_CH_REPORT *pIntolerantReport = NULL; - - if (Elem->MsgLen <= (LENGTH_802_11 + sizeof(BSS_2040_COEXIST_ELEMENT)) ) - { - DBGPRINT(RT_DEBUG_ERROR, ("ACTION - 20/40 BSS Coexistence Management Frame length too short! len = %ld!\n", Elem->MsgLen)); - break; - } - DBGPRINT(RT_DEBUG_TRACE, ("ACTION - 20/40 BSS Coexistence Management action----> \n")); - hex_dump("CoexistenceMgmtFrame", Elem->Msg, Elem->MsgLen); - - - pCoexistInfo = (BSS_2040_COEXIST_ELEMENT *) &Elem->Msg[LENGTH_802_11+2]; - //hex_dump("CoexistInfo", (PUCHAR)pCoexistInfo, sizeof(BSS_2040_COEXIST_ELEMENT)); - if (Elem->MsgLen >= (LENGTH_802_11 + sizeof(BSS_2040_COEXIST_ELEMENT) + sizeof(BSS_2040_INTOLERANT_CH_REPORT))) - { - pIntolerantReport = (BSS_2040_INTOLERANT_CH_REPORT *)((PUCHAR)pCoexistInfo + sizeof(BSS_2040_COEXIST_ELEMENT)); - } - //hex_dump("IntolerantReport ", (PUCHAR)pIntolerantReport, sizeof(BSS_2040_INTOLERANT_CH_REPORT)); - - pBssCoexistIe = (BSS_2040_COEXIST_IE *)(&pCoexistInfo->BssCoexistIe); - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - if (INFRA_ON(pAd)) - { - StaPublicAction(pAd, pCoexistInfo); - } - } -#endif // CONFIG_STA_SUPPORT // - - } - break; - } - -#endif // DOT11N_DRAFT3 // - } @@ -694,7 +328,6 @@ VOID PeerRMAction( return; } -#ifdef DOT11_N_SUPPORT static VOID respond_ht_information_exchange_action( IN PRTMP_ADAPTER pAd, IN MLME_QUEUE_ELEM *Elem) @@ -721,15 +354,12 @@ static VOID respond_ht_information_exchange_action( NdisZeroMemory(&HTINFOframe, sizeof(FRAME_HT_INFO)); // 2-1. Prepare ADDBA Response frame. -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { if (ADHOC_ON(pAd)) ActHeaderInit(pAd, &HTINFOframe.Hdr, pAddr, pAd->CurrentAddress, pAd->CommonCfg.Bssid); else ActHeaderInit(pAd, &HTINFOframe.Hdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pAddr); } -#endif // CONFIG_STA_SUPPORT // HTINFOframe.Category = CATEGORY_HT; HTINFOframe.Action = HT_INFO_EXCHANGE; @@ -745,51 +375,6 @@ static VOID respond_ht_information_exchange_action( MlmeFreeMemory(pAd, pOutBuffer); } - -#ifdef DOT11N_DRAFT3 -VOID SendNotifyBWActionFrame( - IN PRTMP_ADAPTER pAd, - IN UCHAR Wcid, - IN UCHAR apidx) -{ - PUCHAR pOutBuffer = NULL; - NDIS_STATUS NStatus; - FRAME_ACTION_HDR Frame; - ULONG FrameLen; - PUCHAR pAddr1; - - - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory - if(NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_ERROR,("ACT - SendNotifyBWAction() allocate memory failed \n")); - return; - } - - if (Wcid == MCAST_WCID) - pAddr1 = &BROADCAST_ADDR[0]; - else - pAddr1 = pAd->MacTab.Content[Wcid].Addr; - ActHeaderInit(pAd, &Frame.Hdr, pAddr1, pAd->ApCfg.MBSSID[apidx].Bssid, pAd->ApCfg.MBSSID[apidx].Bssid); - - Frame.Category = CATEGORY_HT; - Frame.Action = NOTIFY_BW_ACTION; - - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(FRAME_ACTION_HDR), &Frame, - END_OF_ARGS); - - *(pOutBuffer + FrameLen) = pAd->CommonCfg.AddHTInfo.AddHtInfo.RecomWidth; - FrameLen++; - - - MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); - DBGPRINT(RT_DEBUG_TRACE,("ACT - SendNotifyBWAction(NotifyBW= %d)!\n", pAd->CommonCfg.AddHTInfo.AddHtInfo.RecomWidth)); - -} -#endif // DOT11N_DRAFT3 // - - VOID PeerHTAction( IN PRTMP_ADAPTER pAd, IN MLME_QUEUE_ELEM *Elem) @@ -803,7 +388,7 @@ VOID PeerHTAction( { case NOTIFY_BW_ACTION: DBGPRINT(RT_DEBUG_TRACE,("ACTION - HT Notify Channel bandwidth action----> \n")); -#ifdef CONFIG_STA_SUPPORT + if(pAd->StaActive.SupportedPhyInfo.bHtEnable == FALSE) { // Note, this is to patch DIR-1353 AP. When the AP set to Wep, it will use legacy mode. But AP still keeps @@ -813,7 +398,6 @@ VOID PeerHTAction( Elem->Msg[LENGTH_802_11+2] )); break; } -#endif // CONFIG_STA_SUPPORT // if (Elem->Msg[LENGTH_802_11+2] == 0) // 7.4.8.2. if value is 1, keep the same as supported channel bandwidth. pAd->MacTab.Content[Elem->Wcid].HTPhyMode.field.BW = 0; @@ -881,11 +465,6 @@ VOID ORIBATimerTimeout( INT i, total; UCHAR TID; -#ifdef RALINK_ATE - if (ATE_ON(pAd)) - return; -#endif // RALINK_ATE // - total = pAd->MacTab.Size * NUM_OF_TID; for (i = 1; ((i 0)) ; i++) @@ -938,10 +517,8 @@ VOID SendRefreshBAR( } Sequence = pEntry->TxSeq[TID]; -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - BarHeaderInit(pAd, &FrameBar, pEntry->Addr, pAd->CurrentAddress); -#endif // CONFIG_STA_SUPPORT // + + BarHeaderInit(pAd, &FrameBar, pEntry->Addr, pAd->CurrentAddress); FrameBar.StartingSeq.field.FragNum = 0; // make sure sequence not clear in DEL function. FrameBar.StartingSeq.field.StartSeq = Sequence; // make sure sequence not clear in DEL funciton. @@ -950,15 +527,20 @@ VOID SendRefreshBAR( MakeOutgoingFrame(pOutBuffer, &FrameLen, sizeof(FRAME_BAR), &FrameBar, END_OF_ARGS); + if (1) // Now we always send BAR. { +#ifndef RT30xx MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); +#endif +#ifdef RT30xx + MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); +#endif } MlmeFreeMemory(pAd, pOutBuffer); } } } -#endif // DOT11_N_SUPPORT // VOID ActHeaderInit( IN PRTMP_ADAPTER pAd, diff --git a/drivers/staging/rt2860/common/action.h b/drivers/staging/rt2860/common/action.h index ce3877dce81b..cfc2a5f8d1aa 100644 --- a/drivers/staging/rt2860/common/action.h +++ b/drivers/staging/rt2860/common/action.h @@ -41,17 +41,10 @@ typedef struct PACKED __HT_INFO_OCTET { -#ifdef RT_BIG_ENDIAN - UCHAR Reserved:5; - UCHAR STA_Channel_Width:1; - UCHAR Forty_MHz_Intolerant:1; - UCHAR Request:1; -#else UCHAR Request:1; UCHAR Forty_MHz_Intolerant:1; UCHAR STA_Channel_Width:1; UCHAR Reserved:5; -#endif } HT_INFORMATION_OCTET; diff --git a/drivers/staging/rt2860/common/ba_action.c b/drivers/staging/rt2860/common/ba_action.c index 591d1e2158da..b95a341caacd 100644 --- a/drivers/staging/rt2860/common/ba_action.c +++ b/drivers/staging/rt2860/common/ba_action.c @@ -25,8 +25,6 @@ ************************************************************************* */ -#ifdef DOT11_N_SUPPORT - #include "../rt_config.h" @@ -132,10 +130,7 @@ void Announce_Reordering_Packet(IN PRTMP_ADAPTER pAd, // pass this 802.3 packet to upper layer or forward this packet to WM directly // -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - ANNOUNCE_OR_FORWARD_802_3_PACKET(pAd, pPacket, RTMP_GET_PACKET_IF(pPacket)); -#endif // CONFIG_STA_SUPPORT // + ANNOUNCE_OR_FORWARD_802_3_PACKET(pAd, pPacket, RTMP_GET_PACKET_IF(pPacket)); } } @@ -449,9 +444,6 @@ void ba_flush_reordering_timeout_mpdus( && (pBAEntry->list.qlen > 0) ) { -// printk("timeout[%d] (%lx-%lx = %d > %d): %x, ", pBAEntry->list.qlen, Now32, (pBAEntry->LastIndSeqAtTimer), -// (int)((long) Now32 - (long)(pBAEntry->LastIndSeqAtTimer)), REORDERING_PACKET_TIMEOUT, -// pBAEntry->LastIndSeq); // // force LastIndSeq to shift to LastIndSeq+1 // @@ -468,22 +460,7 @@ void ba_flush_reordering_timeout_mpdus( pBAEntry->LastIndSeq = Sequence; } - //printk("%x, flush one!\n", pBAEntry->LastIndSeq); - } -#if 0 - else if ( - (RTMP_TIME_AFTER((unsigned long)Now32, (unsigned long)(pBAEntry->LastIndSeqAtTimer+(MAX_REORDERING_PACKET_TIMEOUT))) && - (pBAEntry->list.qlen > 1)) - ) - { - DBGPRINT(RT_DEBUG_TRACE,("timeout[%d] (%lx-%lx = %d > %d): %x\n ", pBAEntry->list.qlen, Now32, (pBAEntry->LastIndSeqAtTimer), - (int)((long) Now32 - (long)(pBAEntry->LastIndSeqAtTimer)), MAX_REORDERING_PACKET_TIMEOUT, - pBAEntry->LastIndSeq)); - ba_refresh_reordering_mpdus(pAd, pBAEntry); - pBAEntry->LastIndSeqAtTimer = Now32; - } -#endif } @@ -554,6 +531,13 @@ VOID BAOriSessionSetUp( pBAEntry->TimeOutValue = TimeOut; pBAEntry->pAdapter = pAd; +#ifdef RT30xx + DBGPRINT(RT_DEBUG_TRACE,("Send AddBA to %02x:%02x:%02x:%02x:%02x:%02x Tid:%d isForced:%d Wcid:%d\n" + ,pEntry->Addr[0],pEntry->Addr[1],pEntry->Addr[2] + ,pEntry->Addr[3],pEntry->Addr[4],pEntry->Addr[5] + ,TID,isForced,pEntry->Aid)); +#endif + if (!(pEntry->TXBAbitmap & (1<ORIBATimer, GET_TIMER_FUNCTION(BAOriSessionSetupTimeout), pBAEntry, FALSE); @@ -610,11 +594,7 @@ VOID BAOriSessionAdd( return; } - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - BarHeaderInit(pAd, &FrameBar, pAd->MacTab.Content[pBAEntry->Wcid].Addr, pAd->CurrentAddress); -#endif // CONFIG_STA_SUPPORT // + BarHeaderInit(pAd, &FrameBar, pAd->MacTab.Content[pBAEntry->Wcid].Addr, pAd->CurrentAddress); FrameBar.StartingSeq.field.FragNum = 0; // make sure sequence not clear in DEL function. FrameBar.StartingSeq.field.StartSeq = pBAEntry->Sequence; // make sure sequence not clear in DEL funciton. @@ -701,10 +681,6 @@ BOOLEAN BARecSessionAdd( RTMPInitTimer(pAd, &pBAEntry->RECBATimer, GET_TIMER_FUNCTION(BARecSessionIdleTimeout), pBAEntry, TRUE); } -#if 0 // for debugging - RTMPSetTimer(&pBAEntry->RECBATimer, REC_BA_SESSION_IDLE_TIMEOUT); -#endif - // Set Bitmap flag. pEntry->RXBAbitmap |= (1<BARecWcidArray[TID] = Idx; @@ -1083,20 +1059,9 @@ VOID BAOriSessionSetupTimeout( pAd = pBAEntry->pAdapter; -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - // Do nothing if monitor mode is on - if (MONITOR_ON(pAd)) - return; - } -#endif // CONFIG_STA_SUPPORT // - -#ifdef RALINK_ATE - // Nothing to do in ATE mode. - if (ATE_ON(pAd)) + // Do nothing if monitor mode is on + if (MONITOR_ON(pAd)) return; -#endif // RALINK_ATE // pEntry = &pAd->MacTab.Content[pBAEntry->Wcid]; @@ -1113,8 +1078,16 @@ VOID BAOriSessionSetupTimeout( AddbaReq.Token = pBAEntry->Token; MlmeEnqueue(pAd, ACTION_STATE_MACHINE, MT2_MLME_ADD_BA_CATE, sizeof(MLME_ADDBA_REQ_STRUCT), (PVOID)&AddbaReq); RT28XX_MLME_HANDLER(pAd); +#ifndef RT30xx DBGPRINT(RT_DEBUG_TRACE,("BA Ori Session Timeout(%d) : Send ADD BA again\n", pBAEntry->Token)); - +#endif +#ifdef RT30xx + DBGPRINT(RT_DEBUG_TRACE,("BA Ori Session Timeout(%d) to %02x:%02x:%02x:%02x:%02x:%02x Tid:%d Wcid:%d\n" + ,pBAEntry->Token + ,pEntry->Addr[0],pEntry->Addr[1],pEntry->Addr[2] + ,pEntry->Addr[3],pEntry->Addr[4],pEntry->Addr[5] + ,pBAEntry->TID,pEntry->Aid)); +#endif pBAEntry->Token++; RTMPSetTimer(&pBAEntry->ORIBATimer, ORI_BA_SESSION_TIMEOUT); } @@ -1229,21 +1202,15 @@ VOID PeerAddBAReqAction( } NdisZeroMemory(&ADDframe, sizeof(FRAME_ADDBA_RSP)); + // 2-1. Prepare ADDBA Response frame. -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { if (ADHOC_ON(pAd)) ActHeaderInit(pAd, &ADDframe.Hdr, pAddr, pAd->CurrentAddress, pAd->CommonCfg.Bssid); else -#ifdef QOS_DLS_SUPPORT - if (pAd->MacTab.Content[Elem->Wcid].ValidAsDls) - ActHeaderInit(pAd, &ADDframe.Hdr, pAddr, pAd->CurrentAddress, pAd->CommonCfg.Bssid); - else -#endif // QOS_DLS_SUPPORT // ActHeaderInit(pAd, &ADDframe.Hdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pAddr); } -#endif // CONFIG_STA_SUPPORT // + ADDframe.Category = CATEGORY_BA; ADDframe.Action = ADDBA_RESP; ADDframe.Token = pAddreqFrame->Token; @@ -1310,9 +1277,7 @@ VOID PeerAddBARspAction( } // Rcv Decline StatusCode if ((pFrame->StatusCode == 37) -#ifdef CONFIG_STA_SUPPORT || ((pAd->OpMode == OPMODE_STA) && STA_TGN_WIFI_ON(pAd) && (pFrame->StatusCode != 0)) -#endif // CONFIG_STA_SUPPORT // ) { pAd->MacTab.Content[Elem->Wcid].BADeclineBitmap |= 1<BaParm.TID; @@ -1426,6 +1391,10 @@ VOID SendPSMPAction( //ULONG Idx; FRAME_PSMP_ACTION Frame; ULONG FrameLen; +#ifdef RT30xx + UCHAR bbpdata=0; + UINT32 macdata; +#endif // RT30xx // NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory if (NStatus != NDIS_STATUS_SUCCESS) @@ -1433,22 +1402,62 @@ VOID SendPSMPAction( DBGPRINT(RT_DEBUG_ERROR,("BA - MlmeADDBAAction() allocate memory failed \n")); return; } -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - ActHeaderInit(pAd, &Frame.Hdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pAd->MacTab.Content[Wcid].Addr); -#endif // CONFIG_STA_SUPPORT // + + ActHeaderInit(pAd, &Frame.Hdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pAd->MacTab.Content[Wcid].Addr); Frame.Category = CATEGORY_HT; Frame.Action = SMPS_ACTION; switch (Psmp) { case MMPS_ENABLE: +#ifdef RT30xx + if (IS_RT3090(pAd)) + { + // disable MMPS BBP control register + RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &bbpdata); + bbpdata &= ~(0x04); //bit 2 + RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, bbpdata); + + // disable MMPS MAC control register + RTMP_IO_READ32(pAd, 0x1210, &macdata); + macdata &= ~(0x09); //bit 0, 3 + RTMP_IO_WRITE32(pAd, 0x1210, macdata); + } +#endif // RT30xx // Frame.Psmp = 0; break; case MMPS_DYNAMIC: +#ifdef RT30xx + if (IS_RT3090(pAd)) + { + // enable MMPS BBP control register + RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &bbpdata); + bbpdata |= 0x04; //bit 2 + RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, bbpdata); + + // enable MMPS MAC control register + RTMP_IO_READ32(pAd, 0x1210, &macdata); + macdata |= 0x09; //bit 0, 3 + RTMP_IO_WRITE32(pAd, 0x1210, macdata); + } +#endif // RT30xx // Frame.Psmp = 3; break; case MMPS_STATIC: +#ifdef RT30xx + if (IS_RT3090(pAd)) + { + // enable MMPS BBP control register + RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &bbpdata); + bbpdata |= 0x04; //bit 2 + RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, bbpdata); + + // enable MMPS MAC control register + RTMP_IO_READ32(pAd, 0x1210, &macdata); + macdata |= 0x09; //bit 0, 3 + RTMP_IO_WRITE32(pAd, 0x1210, macdata); + } +#endif // RT30xx // Frame.Psmp = 1; break; } @@ -1501,10 +1510,7 @@ void convert_reordering_packet_to_preAMSDU_or_802_3_packet( // a. pointer pRxBlk->pData to payload // b. modify pRxBlk->DataSize -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - RTMP_802_11_REMOVE_LLC_AND_CONVERT_TO_802_3(pRxBlk, Header802_3); -#endif // CONFIG_STA_SUPPORT // + RTMP_802_11_REMOVE_LLC_AND_CONVERT_TO_802_3(pRxBlk, Header802_3); ASSERT(pRxBlk->pRxPacket); pRxPkt = RTPKT_TO_OSPKT(pRxBlk->pRxPacket); @@ -1519,18 +1525,9 @@ void convert_reordering_packet_to_preAMSDU_or_802_3_packet( // if (!RX_BLK_TEST_FLAG(pRxBlk, fRX_AMSDU)) { - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { #ifdef LINUX - NdisMoveMemory(skb_push(pRxPkt, LENGTH_802_3), Header802_3, LENGTH_802_3); + NdisMoveMemory(skb_push(pRxPkt, LENGTH_802_3), Header802_3, LENGTH_802_3); #endif -#ifdef UCOS - NdisMoveMemory(net_pkt_push(pRxPkt, LENGTH_802_3), Header802_3, LENGTH_802_3); -#endif - } -#endif // CONFIG_STA_SUPPORT // } } @@ -1598,13 +1595,9 @@ static VOID ba_enqueue_reordering_packet( } else { -#if 0 - DBGPRINT(RT_DEBUG_ERROR, ("!!! (%d:%d) Can't allocate reordering mpdu blk\n", - blk_count, pBAEntry->list.qlen)); -#else DBGPRINT(RT_DEBUG_ERROR, ("!!! (%d) Can't allocate reordering mpdu blk\n", pBAEntry->list.qlen)); -#endif + /* * flush all pending reordering mpdus * and receving mpdu to upper layer @@ -1652,29 +1645,11 @@ VOID Indicate_AMPDU_Packet( if (!RX_BLK_TEST_FLAG(pRxBlk, fRX_AMSDU) && (pRxBlk->DataSize > MAX_RX_PKT_LEN)) { -#if 0 // sample take off, no use - static int err_size; - - err_size++; - if (err_size > 20) { - printk("AMPDU DataSize = %d\n", pRxBlk->DataSize); - hex_dump("802.11 Header", (UCHAR *)pRxBlk->pHeader, 24); - hex_dump("Payload", pRxBlk->pData, 64); - err_size = 0; - } -#endif // release packet RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); return; } - -#if 0 // test - /* Rec BA Session had been torn down */ - INDICATE_LEGACY_OR_AMSDU(pAd, pRxBlk, FromWhichBSSID); - return; -#endif - if (Wcid < MAX_LEN_OF_MAC_TABLE) { Idx = pAd->MacTab.Content[Wcid].BARecWcidArray[TID]; @@ -1769,10 +1744,6 @@ VOID Indicate_AMPDU_Packet( // else { -#if 0 - ba_refresh_reordering_mpdus(pAd, pBAEntry); - INDICATE_LEGACY_OR_AMSDU(pAd, pRxBlk, FromWhichBSSID); -#else LONG WinStartSeq, TmpSeq; @@ -1794,9 +1765,5 @@ VOID Indicate_AMPDU_Packet( { pBAEntry->LastIndSeq = TmpSeq; } -#endif } } - -#endif // DOT11_N_SUPPORT // - diff --git a/drivers/staging/rt2860/common/cmm_data.c b/drivers/staging/rt2860/common/cmm_data.c index b3f88f52af7c..66eca202eae4 100644 --- a/drivers/staging/rt2860/common/cmm_data.c +++ b/drivers/staging/rt2860/common/cmm_data.c @@ -105,7 +105,9 @@ NDIS_STATUS MiniportMMRequest( PNDIS_PACKET pPacket; NDIS_STATUS Status = NDIS_STATUS_SUCCESS; ULONG FreeNum; +#ifdef RT2860 unsigned long IrqFlags = 0; +#endif UCHAR IrqState; UCHAR rtmpHwHdr[TXINFO_SIZE + TXWI_SIZE]; //RTMP_HW_HDR_LEN]; @@ -117,9 +119,10 @@ NDIS_STATUS MiniportMMRequest( IrqState = pAd->irq_disabled; +#ifdef RT2860 if ((pAd->MACVersion == 0x28600100) && (!IrqState)) RTMP_IRQ_LOCK(&pAd->irq_lock, IrqFlags); - +#endif do { // Reset is in progress, stop immediately @@ -172,14 +175,15 @@ NDIS_STATUS MiniportMMRequest( } while (FALSE); +#ifdef RT2860 // 2860C use Tx Ring if ((pAd->MACVersion == 0x28600100) && (!IrqState)) RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags); - +#endif return Status; } - +#ifdef RT2860 NDIS_STATUS MiniportMMRequestUnlock( IN PRTMP_ADAPTER pAd, IN UCHAR QueIdx, @@ -247,7 +251,115 @@ NDIS_STATUS MiniportMMRequestUnlock( return Status; } +#endif +#ifdef RT30xx +NDIS_STATUS MlmeDataHardTransmit( + IN PRTMP_ADAPTER pAd, + IN UCHAR QueIdx, + IN PNDIS_PACKET pPacket); +#define MAX_DATAMM_RETRY 3 +/* + ======================================================================== + + Routine Description: + API for MLME to transmit management frame to AP (BSS Mode) + or station (IBSS Mode) + + Arguments: + pAd Pointer to our adapter + pData Pointer to the outgoing 802.11 frame + Length Size of outgoing management frame + + Return Value: + NDIS_STATUS_FAILURE + NDIS_STATUS_PENDING + NDIS_STATUS_SUCCESS + + IRQL = PASSIVE_LEVEL + IRQL = DISPATCH_LEVEL + + Note: + + ======================================================================== +*/ +NDIS_STATUS MiniportDataMMRequest( + IN PRTMP_ADAPTER pAd, + IN UCHAR QueIdx, + IN PUCHAR pData, + IN UINT Length) +{ + PNDIS_PACKET pPacket; + NDIS_STATUS Status = NDIS_STATUS_SUCCESS; + ULONG FreeNum; + int retry = 0; + UCHAR IrqState; + UCHAR rtmpHwHdr[TXINFO_SIZE + TXWI_SIZE]; //RTMP_HW_HDR_LEN]; + + ASSERT(Length <= MGMT_DMA_BUFFER_SIZE); + + // 2860C use Tx Ring + IrqState = pAd->irq_disabled; + + do + { + // Reset is in progress, stop immediately + if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS) || + RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)|| + !RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_START_UP)) + { + Status = NDIS_STATUS_FAILURE; + break; + } + + // Check Free priority queue + // Since we use PBF Queue2 for management frame. Its corresponding DMA ring should be using TxRing. + + // 2860C use Tx Ring + + // free Tx(QueIdx) resources + FreeNum = GET_TXRING_FREENO(pAd, QueIdx); + + if ((FreeNum > 0)) + { + // We need to reserve space for rtmp hardware header. i.e., TxWI for RT2860 and TxInfo+TxWI for RT2870 + NdisZeroMemory(&rtmpHwHdr, (TXINFO_SIZE + TXWI_SIZE)); + Status = RTMPAllocateNdisPacket(pAd, &pPacket, (PUCHAR)&rtmpHwHdr, (TXINFO_SIZE + TXWI_SIZE), pData, Length); + if (Status != NDIS_STATUS_SUCCESS) + { + DBGPRINT(RT_DEBUG_WARN, ("MiniportMMRequest (error:: can't allocate NDIS PACKET)\n")); + break; + } + + //pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_CCK; + //pAd->CommonCfg.MlmeRate = RATE_2; + + + Status = MlmeDataHardTransmit(pAd, QueIdx, pPacket); + if (Status != NDIS_STATUS_SUCCESS) + RTMPFreeNdisPacket(pAd, pPacket); + retry = MAX_DATAMM_RETRY; + } + else + { + retry ++; + + printk("retry %d\n", retry); + pAd->RalinkCounters.MgmtRingFullCount++; + + if (retry >= MAX_DATAMM_RETRY) + { + DBGPRINT(RT_DEBUG_ERROR, ("Qidx(%d), not enough space in DataRing, MgmtRingFullCount=%ld!\n", + QueIdx, pAd->RalinkCounters.MgmtRingFullCount)); + } + } + + } while (retry < MAX_DATAMM_RETRY); + + + return Status; +} +#endif /* RT30xx */ /* ======================================================================== @@ -283,14 +395,16 @@ NDIS_STATUS MlmeHardTransmit( return NDIS_STATUS_FAILURE; } +#ifdef RT2860 if ( pAd->MACVersion == 0x28600100 ) return MlmeHardTransmitTxRing(pAd,QueIdx,pPacket); else +#endif return MlmeHardTransmitMgmtRing(pAd,QueIdx,pPacket); } - +#ifdef RT2860 NDIS_STATUS MlmeHardTransmitTxRing( IN PRTMP_ADAPTER pAd, IN UCHAR QueIdx, @@ -300,10 +414,6 @@ NDIS_STATUS MlmeHardTransmitTxRing( PUCHAR pSrcBufVA; UINT SrcBufLen; PTXD_STRUC pTxD; -#ifdef RT_BIG_ENDIAN - PTXD_STRUC pDestTxD; - TXD_STRUC TxD; -#endif PHEADER_802_11 pHeader_802_11; BOOLEAN bAckRequired, bInsertTimestamp; ULONG SrcBufPA; @@ -335,14 +445,7 @@ NDIS_STATUS MlmeHardTransmitTxRing( SwIdx = pAd->TxRing[QueIdx].TxCpuIdx; -#ifndef RT_BIG_ENDIAN pTxD = (PTXD_STRUC) pAd->TxRing[QueIdx].Cell[SwIdx].AllocVa; -#else - pDestTxD = (PTXD_STRUC)pAd->TxRing[QueIdx].Cell[SwIdx].AllocVa; - TxD = *pDestTxD; - pTxD = &TxD; - RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); -#endif if (pAd->TxRing[QueIdx].Cell[SwIdx].pNdisPacket) { @@ -350,15 +453,10 @@ NDIS_STATUS MlmeHardTransmitTxRing( return NDIS_STATUS_FAILURE; } + // outgoing frame always wakeup PHY to prevent frame lost + if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) + AsicForceWakeup(pAd, FROM_TX); -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - // outgoing frame always wakeup PHY to prevent frame lost - if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) - AsicForceWakeup(pAd, FROM_TX); - } -#endif // CONFIG_STA_SUPPORT // pFirstTxWI =(PTXWI_STRUC)pSrcBufVA; pHeader_802_11 = (PHEADER_802_11) (pSrcBufVA + TXWI_SIZE); @@ -388,7 +486,7 @@ NDIS_STATUS MlmeHardTransmitTxRing( // // // In WMM-UAPSD, mlme frame should be set psm as power saving but probe request frame -#ifdef CONFIG_STA_SUPPORT + // Data-Null packets alse pass through MMRequest in RT2860, however, we hope control the psm bit to pass APSD if (pHeader_802_11->FC.Type != BTYPE_DATA) { @@ -401,7 +499,6 @@ NDIS_STATUS MlmeHardTransmitTxRing( pHeader_802_11->FC.PwrMgmt = pAd->CommonCfg.bAPSDForcePowerSave; } } -#endif // CONFIG_STA_SUPPORT // bInsertTimestamp = FALSE; if (pHeader_802_11->FC.Type == BTYPE_CNTL) // must be PS-POLL @@ -438,9 +535,6 @@ NDIS_STATUS MlmeHardTransmitTxRing( return (NDIS_STATUS_FAILURE); } -#ifdef RT_BIG_ENDIAN - RTMPFrameEndianChange(pAd, (PUCHAR)pHeader_802_11, DIR_WRITE, FALSE); -#endif // // fill scatter-and-gather buffer list into TXD. Internally created NDIS PACKET // should always has only one ohysical buffer, and the whole frame size equals @@ -470,9 +564,7 @@ NDIS_STATUS MlmeHardTransmitTxRing( pAd->TxRing[QueIdx].Cell[SwIdx].pNdisPacket = pPacket; pAd->TxRing[QueIdx].Cell[SwIdx].pNextNdisPacket = NULL; -#ifdef RT_BIG_ENDIAN - RTMPWIEndianChange((PUCHAR)pFirstTxWI, TYPE_TXWI); -#endif + SrcBufPA = PCI_MAP_SINGLE(pAd, pSrcBufVA, SrcBufLen, 0, PCI_DMA_TODEVICE); @@ -484,11 +576,6 @@ NDIS_STATUS MlmeHardTransmitTxRing( pTxD->SDPtr0 = SrcBufPA; pTxD->DMADONE = 0; -#ifdef RT_BIG_ENDIAN - RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); - WriteBackToDescriptor((PUCHAR)pDestTxD, (PUCHAR)pTxD, FALSE, TYPE_TXD); -#endif - pAd->RalinkCounters.KickTxCount++; pAd->RalinkCounters.OneSecTxDoneCount++; @@ -499,7 +586,25 @@ NDIS_STATUS MlmeHardTransmitTxRing( return NDIS_STATUS_SUCCESS; } +#endif /* RT2860 */ +#ifdef RT30xx +NDIS_STATUS MlmeDataHardTransmit( + IN PRTMP_ADAPTER pAd, + IN UCHAR QueIdx, + IN PNDIS_PACKET pPacket) +{ + if ((pAd->CommonCfg.RadarDetect.RDMode != RD_NORMAL_MODE) + ) + { + return NDIS_STATUS_FAILURE; + } + +#ifdef RT2870 + return MlmeHardTransmitMgmtRing(pAd,QueIdx,pPacket); +#endif // RT2870 // +} +#endif /* RT30xx */ NDIS_STATUS MlmeHardTransmitMgmtRing( IN PRTMP_ADAPTER pAd, @@ -525,14 +630,14 @@ NDIS_STATUS MlmeHardTransmitMgmtRing( return NDIS_STATUS_FAILURE; } -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - // outgoing frame always wakeup PHY to prevent frame lost - if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) - AsicForceWakeup(pAd, FROM_TX); - } -#endif // CONFIG_STA_SUPPORT // + // outgoing frame always wakeup PHY to prevent frame lost + if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) +#ifdef RT2860 + AsicForceWakeup(pAd, FROM_TX); +#endif +#ifdef RT2870 + AsicForceWakeup(pAd, TRUE); +#endif pFirstTxWI = (PTXWI_STRUC)(pSrcBufVA + TXINFO_SIZE); pHeader_802_11 = (PHEADER_802_11) (pSrcBufVA + TXINFO_SIZE + TXWI_SIZE); //TXWI_SIZE); @@ -556,14 +661,10 @@ NDIS_STATUS MlmeHardTransmitMgmtRing( pMacEntry = MacTableLookup(pAd, pHeader_802_11->Addr1); } -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { // Fixed W52 with Activity scan issue in ABG_MIXED and ABGN_MIXED mode. if (pAd->CommonCfg.PhyMode == PHY_11ABG_MIXED -#ifdef DOT11_N_SUPPORT || pAd->CommonCfg.PhyMode == PHY_11ABGN_MIXED -#endif // DOT11_N_SUPPORT // ) { if (pAd->LatchRfRegs.Channel > 14) @@ -572,7 +673,6 @@ NDIS_STATUS MlmeHardTransmitMgmtRing( pAd->CommonCfg.MlmeTransmit.field.MODE = 0; } } -#endif // CONFIG_STA_SUPPORT // // // Should not be hard code to set PwrMgmt to 0 (PWR_ACTIVE) @@ -582,7 +682,7 @@ NDIS_STATUS MlmeHardTransmitMgmtRing( // pHeader_802_11->FC.PwrMgmt = 0; // (pAd->StaCfg.Psm == PWR_SAVE); // // In WMM-UAPSD, mlme frame should be set psm as power saving but probe request frame -#ifdef CONFIG_STA_SUPPORT + // Data-Null packets alse pass through MMRequest in RT2860, however, we hope control the psm bit to pass APSD if ((pHeader_802_11->FC.Type != BTYPE_DATA) && (pHeader_802_11->FC.Type != BTYPE_CNTL)) { @@ -592,18 +692,15 @@ NDIS_STATUS MlmeHardTransmitMgmtRing( else pHeader_802_11->FC.PwrMgmt = PWR_ACTIVE; } -#endif // CONFIG_STA_SUPPORT // bInsertTimestamp = FALSE; if (pHeader_802_11->FC.Type == BTYPE_CNTL) // must be PS-POLL { -#ifdef CONFIG_STA_SUPPORT //Set PM bit in ps-poll, to fix WLK 1.2 PowerSaveMode_ext failure issue. if ((pAd->OpMode == OPMODE_STA) && (pHeader_802_11->FC.SubType == SUBTYPE_PS_POLL)) { pHeader_802_11->FC.PwrMgmt = PWR_SAVE; } -#endif // CONFIG_STA_SUPPORT // bAckRequired = FALSE; } else // BTYPE_MGMT or BTYPE_DATA(must be NULL frame) @@ -639,10 +736,6 @@ NDIS_STATUS MlmeHardTransmitMgmtRing( return (NDIS_STATUS_FAILURE); } -#ifdef RT_BIG_ENDIAN - RTMPFrameEndianChange(pAd, (PUCHAR)pHeader_802_11, DIR_WRITE, FALSE); -#endif - // // fill scatter-and-gather buffer list into TXD. Internally created NDIS PACKET // should always has only one ohysical buffer, and the whole frame size equals @@ -669,10 +762,6 @@ NDIS_STATUS MlmeHardTransmitMgmtRing( IFS_BACKOFF, FALSE, &pMacEntry->MaxHTPhyMode); } -#ifdef RT_BIG_ENDIAN - RTMPWIEndianChange((PUCHAR)pFirstTxWI, TYPE_TXWI); -#endif - // Now do hardware-depened kick out. HAL_KickOutMgmtTx(pAd, QueIdx, pPacket, pSrcBufVA, SrcBufLen); @@ -752,9 +841,7 @@ static UCHAR TxPktClassification( UCHAR TxFrameType = TX_UNKOWN_FRAME; UCHAR Wcid; MAC_TABLE_ENTRY *pMacEntry = NULL; -#ifdef DOT11_N_SUPPORT BOOLEAN bHTRate = FALSE; -#endif // DOT11_N_SUPPORT // Wcid = RTMP_GET_PACKET_WCID(pPacket); if (Wcid == MCAST_WCID) @@ -768,7 +855,6 @@ static UCHAR TxPktClassification( { // It's a specific packet need to force low rate, i.e., bDHCPFrame, bEAPOLFrame, bWAIFrame TxFrameType = TX_LEGACY_FRAME; } -#ifdef DOT11_N_SUPPORT else if (IS_HT_RATE(pMacEntry)) { // it's a 11n capable packet @@ -788,7 +874,6 @@ static UCHAR TxPktClassification( else TxFrameType = TX_LEGACY_FRAME; } -#endif // DOT11_N_SUPPORT // else { // it's a legacy b/g packet. if ((CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_AGGREGATION_CAPABLE) && pAd->CommonCfg.bAggregationCapable) && @@ -874,16 +959,15 @@ BOOLEAN RTMP_FillTxBlkInfo( TX_BLK_SET_FLAG(pTxBlk, fTX_bAckRequired); { - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - - // If support WMM, enable it. - if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED)) - TX_BLK_SET_FLAG(pTxBlk, fTX_bWMM); - } -#endif // CONFIG_STA_SUPPORT // + // If support WMM, enable it. +#ifdef RT2860 + if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED)) +#endif +#ifdef RT2870 + if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED) && + CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_WMM_CAPABLE)) +#endif + TX_BLK_SET_FLAG(pTxBlk, fTX_bWMM); } if (pTxBlk->TxFrameType == TX_LEGACY_FRAME) @@ -892,7 +976,7 @@ BOOLEAN RTMP_FillTxBlkInfo( ((pAd->OpMode == OPMODE_AP) && (pMacEntry->MaxHTPhyMode.field.MODE == MODE_CCK) && (pMacEntry->MaxHTPhyMode.field.MCS == RATE_1))) { // Specific packet, i.e., bDHCPFrame, bEAPOLFrame, bWAIFrame, need force low rate. pTxBlk->pTransmit = &pAd->MacTab.Content[MCAST_WCID].HTPhyMode; -#ifdef DOT11_N_SUPPORT + // Modify the WMM bit for ICV issue. If we have a packet with EOSP field need to set as 1, how to handle it??? if (IS_HT_STA(pTxBlk->pMacEntry) && (CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_RALINK_CHIPSET)) && @@ -901,16 +985,13 @@ BOOLEAN RTMP_FillTxBlkInfo( TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bWMM); TX_BLK_SET_FLAG(pTxBlk, fTX_bForceNonQoS); } -#endif // DOT11_N_SUPPORT // } -#ifdef DOT11_N_SUPPORT if ( (IS_HT_RATE(pMacEntry) == FALSE) && (CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_PIGGYBACK_CAPABLE))) { // Currently piggy-back only support when peer is operate in b/g mode. TX_BLK_SET_FLAG(pTxBlk, fTX_bPiggyBack); } -#endif // DOT11_N_SUPPORT // if (RTMP_GET_PACKET_MOREDATA(pPacket)) { @@ -932,6 +1013,11 @@ BOOLEAN RTMP_FillTxBlkInfo( } return TRUE; + +#ifdef RT30xx +FillTxBlkErr: + return FALSE; +#endif } @@ -963,13 +1049,10 @@ BOOLEAN CanDoAggregateTransmit( return FALSE; } -#ifdef CONFIG_STA_SUPPORT if ((INFRA_ON(pAd)) && (pAd->OpMode == OPMODE_STA)) // must be unicast to AP return TRUE; else -#endif // CONFIG_STA_SUPPORT // return FALSE; - } @@ -1022,6 +1105,7 @@ VOID RTMPDeQueuePacket( if (QIdx == NUM_OF_TX_RING) { sQIdx = 0; +//PS packets use HCCA queue when dequeue from PS unicast queue (WiFi WPA2 MA9_DT1 for Marvell B STA) eQIdx = 3; // 4 ACs, start from 0. } else @@ -1064,7 +1148,7 @@ VOID RTMPDeQueuePacket( DEQUEUE_UNLOCK(&pAd->irq_lock, bIntContext, IrqFlags); break; } - +#ifdef RT2860 FreeNumber[QueIdx] = GET_TXRING_FREENO(pAd, QueIdx); #ifdef DBG_DIAGNOSE @@ -1089,7 +1173,7 @@ VOID RTMPDeQueuePacket( RTMPFreeTXDUponTxDmaDone(pAd, QueIdx); FreeNumber[QueIdx] = GET_TXRING_FREENO(pAd, QueIdx); } - +#endif /* RT2860 */ // probe the Queue Head pQueue = &pAd->TxSwQueue[QueIdx]; if ((pEntry = pQueue->Head) == NULL) @@ -1158,32 +1242,29 @@ VOID RTMPDeQueuePacket( pTxBlk->TxFrameType = TX_LEGACY_FRAME; } +#ifdef RT2870 + DEQUEUE_UNLOCK(&pAd->irq_lock, bIntContext, IrqFlags); +#endif // RT2870 // Count += pTxBlk->TxPacketList.Number; - // Do HardTransmit now. -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - Status = STAHardTransmit(pAd, pTxBlk, QueIdx); -#endif // CONFIG_STA_SUPPORT // + // Do HardTransmit now. + Status = STAHardTransmit(pAd, pTxBlk, QueIdx); +#ifdef RT2860 DEQUEUE_UNLOCK(&pAd->irq_lock, bIntContext, IrqFlags); // static rate also need NICUpdateFifoStaCounters() function. //if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED)) NICUpdateFifoStaCounters(pAd); +#endif } RT28XX_STOP_DEQUEUE(pAd, QueIdx, IrqFlags); - -#ifdef BLOCK_NET_IF - if ((pAd->blockQueueTab[QueIdx].SwTxQueueBlockFlag == TRUE) - && (pAd->TxSwQueue[QueIdx].Number < 1)) - { - releaseNetIf(&pAd->blockQueueTab[QueIdx]); - } -#endif // BLOCK_NET_IF // - +#ifdef RT2870 + if (!hasTxDesc) + RTUSBKickBulkOut(pAd); +#endif // RT2870 // } } @@ -1318,7 +1399,6 @@ VOID RTMPWriteTxWI( pTxWI->NSEQ = NSeq; // John tune the performace with Intel Client in 20 MHz performance -#ifdef DOT11_N_SUPPORT BASize = pAd->CommonCfg.TxBASize; if( BASize >7 ) @@ -1326,7 +1406,6 @@ VOID RTMPWriteTxWI( pTxWI->BAWinSize = BASize; pTxWI->ShortGI = pTransmit->field.ShortGI; pTxWI->STBC = pTransmit->field.STBC; -#endif // DOT11_N_SUPPORT // pTxWI->WirelessCliID = WCID; pTxWI->MPDUtotalByteCount = Length; @@ -1334,16 +1413,11 @@ VOID RTMPWriteTxWI( // If CCK or OFDM, BW must be 20 pTxWI->BW = (pTransmit->field.MODE <= MODE_OFDM) ? (BW_20) : (pTransmit->field.BW); -#ifdef DOT11N_DRAFT3 - if (pTxWI->BW) - pTxWI->BW = (pAd->CommonCfg.AddHTInfo.AddHtInfo.RecomWidth == 0) ? (BW_20) : (pTransmit->field.BW); -#endif // DOT11N_DRAFT3 // pTxWI->MCS = pTransmit->field.MCS; pTxWI->PHYMODE = pTransmit->field.MODE; pTxWI->CFACK = CfAck; -#ifdef DOT11_N_SUPPORT if (pMac) { if (pAd->CommonCfg.bMIMOPSEnable) @@ -1373,7 +1447,6 @@ VOID RTMPWriteTxWI( pTxWI->MpduDensity = pMac->MpduDensity; } } -#endif // DOT11_N_SUPPORT // pTxWI->PacketId = pTxWI->MCS; NdisMoveMemory(pOutTxWI, &TxWI, sizeof(TXWI_STRUC)); @@ -1387,10 +1460,7 @@ VOID RTMPWriteTxWI_Data( { HTTRANSMIT_SETTING *pTransmit; PMAC_TABLE_ENTRY pMacEntry; -#ifdef DOT11_N_SUPPORT UCHAR BASize; -#endif // DOT11_N_SUPPORT // - ASSERT(pTxWI); @@ -1409,15 +1479,6 @@ VOID RTMPWriteTxWI_Data( pTxWI->ACK = TX_BLK_TEST_FLAG(pTxBlk, fTX_bAckRequired); pTxWI->txop = pTxBlk->FrameGap; -#ifdef CONFIG_STA_SUPPORT -#ifdef QOS_DLS_SUPPORT - if (pMacEntry && - (pAd->StaCfg.BssType == BSS_INFRA) && - (pMacEntry->ValidAsDls == TRUE)) - pTxWI->WirelessCliID = BSSID_WCID; - else -#endif // QOS_DLS_SUPPORT // -#endif // CONFIG_STA_SUPPORT // pTxWI->WirelessCliID = pTxBlk->Wcid; pTxWI->MPDUtotalByteCount = pTxBlk->MpduHeaderLen + pTxBlk->SrcBufLen; @@ -1425,11 +1486,6 @@ VOID RTMPWriteTxWI_Data( // If CCK or OFDM, BW must be 20 pTxWI->BW = (pTransmit->field.MODE <= MODE_OFDM) ? (BW_20) : (pTransmit->field.BW); -#ifdef DOT11_N_SUPPORT -#ifdef DOT11N_DRAFT3 - if (pTxWI->BW) - pTxWI->BW = (pAd->CommonCfg.AddHTInfo.AddHtInfo.RecomWidth == 0) ? (BW_20) : (pTransmit->field.BW); -#endif // DOT11N_DRAFT3 // pTxWI->AMPDU = ((pTxBlk->TxFrameType == TX_AMPDU_FRAME) ? TRUE : FALSE); // John tune the performace with Intel Client in 20 MHz performance @@ -1446,12 +1502,10 @@ VOID RTMPWriteTxWI_Data( pTxWI->BAWinSize = BASize; pTxWI->ShortGI = pTransmit->field.ShortGI; pTxWI->STBC = pTransmit->field.STBC; -#endif // DOT11_N_SUPPORT // pTxWI->MCS = pTransmit->field.MCS; pTxWI->PHYMODE = pTransmit->field.MODE; -#ifdef DOT11_N_SUPPORT if (pMacEntry) { if ((pMacEntry->MmpsMode == MMPS_DYNAMIC) && (pTransmit->field.MCS > 7)) @@ -1478,7 +1532,6 @@ VOID RTMPWriteTxWI_Data( pTxWI->MpduDensity = pMacEntry->MpduDensity; } } -#endif // DOT11_N_SUPPORT // #ifdef DBG_DIAGNOSE if (pTxBlk->QueIdx== 0) @@ -1523,15 +1576,9 @@ VOID RTMPWriteTxWI_Cache( pTxWI->PacketId = pTransmit->field.MCS; } -#ifdef DOT11_N_SUPPORT pTxWI->AMPDU = ((pMacEntry->NoBADataCountDown == 0) ? TRUE: FALSE); pTxWI->MIMOps = 0; -#ifdef DOT11N_DRAFT3 - if (pTxWI->BW) - pTxWI->BW = (pAd->CommonCfg.AddHTInfo.AddHtInfo.RecomWidth == 0) ? (BW_20) : (pTransmit->field.BW); -#endif // DOT11N_DRAFT3 // - if (pAd->CommonCfg.bMIMOPSEnable) { // MIMO Power Save Mode @@ -1550,7 +1597,6 @@ VOID RTMPWriteTxWI_Cache( } } } -#endif // DOT11_N_SUPPORT // #ifdef DBG_DIAGNOSE if (pTxBlk->QueIdx== 0) @@ -1665,12 +1711,10 @@ BOOLEAN PeerIsAggreOn( if (pMacEntry != NULL && CLIENT_STATUS_TEST_FLAG(pMacEntry, AFlags)) { -#ifdef DOT11_N_SUPPORT if (pMacEntry->HTPhyMode.field.MODE >= MODE_HTMIX) { return TRUE; } -#endif // DOT11_N_SUPPORT // #ifdef AGGREGATION_SUPPORT if (TxRate >= RATE_6 && pAd->CommonCfg.bAggregationCapable && (!(OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED) && CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_WMM_CAPABLE)))) @@ -1748,16 +1792,13 @@ PQUEUE_HEADER RTMPCheckTxSwQueue( return (NULL); } - +#ifdef RT2860 BOOLEAN RTMPFreeTXDUponTxDmaDone( IN PRTMP_ADAPTER pAd, IN UCHAR QueIdx) { PRTMP_TX_RING pTxRing; PTXD_STRUC pTxD; -#ifdef RT_BIG_ENDIAN - PTXD_STRUC pDestTxD; -#endif PNDIS_PACKET pPacket; UCHAR FREE = 0; TXD_STRUC TxD, *pOriTxD; @@ -1771,111 +1812,19 @@ BOOLEAN RTMPFreeTXDUponTxDmaDone( RTMP_IO_READ32(pAd, TX_DTX_IDX0 + QueIdx * RINGREG_DIFF, &pTxRing->TxDmaIdx); while (pTxRing->TxSwFreeIdx != pTxRing->TxDmaIdx) { -#ifdef RALINK_ATE -#ifdef RALINK_28xx_QA - PHEADER_802_11 pHeader80211; - - if ((ATE_ON(pAd)) && (pAd->ate.bQATxStart == TRUE)) - { - if (pAd->ate.QID == QueIdx) - { - pAd->ate.TxDoneCount++; - //pAd->ate.Repeat++; - pAd->RalinkCounters.KickTxCount++; - - /* always use QID_AC_BE and FIFO_EDCA */ - ASSERT(pAd->ate.QID == 0); - pAd->ate.TxAc0++; - - FREE++; -#ifndef RT_BIG_ENDIAN - pTxD = (PTXD_STRUC) (pTxRing->Cell[pTxRing->TxSwFreeIdx].AllocVa); - pOriTxD = pTxD; - NdisMoveMemory(&TxD, pTxD, sizeof(TXD_STRUC)); - pTxD = &TxD; -#else - pDestTxD = (PTXD_STRUC) (pTxRing->Cell[pTxRing->TxSwFreeIdx].AllocVa); - pOriTxD = pDestTxD ; - TxD = *pDestTxD; - pTxD = &TxD; - RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); -#endif - pTxD->DMADONE = 0; - - pHeader80211 = pTxRing->Cell[pTxRing->TxSwFreeIdx].DmaBuf.AllocVa + sizeof(TXWI_STRUC); -#ifdef RT_BIG_ENDIAN - RTMPFrameEndianChange(pAd, (PUCHAR)pHeader80211, DIR_READ, FALSE); -#endif - pHeader80211->Sequence = ++pAd->ate.seq; -#ifdef RT_BIG_ENDIAN - RTMPFrameEndianChange(pAd, (PUCHAR)pHeader80211, DIR_WRITE, FALSE); -#endif - - if ((pAd->ate.bQATxStart == TRUE) && (pAd->ate.Mode & ATE_TXFRAME) && (pAd->ate.TxDoneCount < pAd->ate.TxCount)) - { - pAd->RalinkCounters.TransmittedByteCount += (pTxD->SDLen1 + pTxD->SDLen0); - pAd->RalinkCounters.OneSecDmaDoneCount[QueIdx] ++; - INC_RING_INDEX(pTxRing->TxSwFreeIdx, TX_RING_SIZE); - /* get tx_tdx_idx again */ - RTMP_IO_READ32(pAd, TX_DTX_IDX0 + QueIdx * RINGREG_DIFF , &pTxRing->TxDmaIdx); - goto kick_out; - } - else if ((pAd->ate.TxStatus == 1)/* or (pAd->ate.bQATxStart == TRUE) ??? */ && (pAd->ate.TxDoneCount == pAd->ate.TxCount))//<========================PETER - { - DBGPRINT(RT_DEBUG_TRACE,("all Tx is done\n")); - // Tx status enters idle mode. - pAd->ate.TxStatus = 0; - } - else if (!(pAd->ate.Mode & ATE_TXFRAME)) - { - /* not complete sending yet, but someone press the Stop TX botton. */ - DBGPRINT(RT_DEBUG_ERROR,("not complete sending yet, but someone pressed the Stop TX bottom\n")); - DBGPRINT(RT_DEBUG_ERROR,("pAd->ate.Mode = 0x%02x\n", pAd->ate.Mode)); - } - else - { - DBGPRINT(RT_DEBUG_OFF,("pTxRing->TxSwFreeIdx = %d\n", pTxRing->TxSwFreeIdx)); - } -#ifndef RT_BIG_ENDIAN - NdisMoveMemory(pOriTxD, pTxD, sizeof(TXD_STRUC)); -#else - RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); - *pDestTxD = TxD; -#endif // RT_BIG_ENDIAN // - - INC_RING_INDEX(pTxRing->TxSwFreeIdx, TX_RING_SIZE); - continue; - } - } -#endif // RALINK_28xx_QA // -#endif // RALINK_ATE // - // static rate also need NICUpdateFifoStaCounters() function. //if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED)) NICUpdateFifoStaCounters(pAd); /* Note : If (pAd->ate.bQATxStart == TRUE), we will never reach here. */ FREE++; -#ifndef RT_BIG_ENDIAN pTxD = (PTXD_STRUC) (pTxRing->Cell[pTxRing->TxSwFreeIdx].AllocVa); pOriTxD = pTxD; NdisMoveMemory(&TxD, pTxD, sizeof(TXD_STRUC)); pTxD = &TxD; -#else - pDestTxD = (PTXD_STRUC) (pTxRing->Cell[pTxRing->TxSwFreeIdx].AllocVa); - pOriTxD = pDestTxD ; - TxD = *pDestTxD; - pTxD = &TxD; - RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); -#endif pTxD->DMADONE = 0; - -#ifdef RALINK_ATE - /* Execution of this block is not allowed when ATE is running. */ - if (!(ATE_ON(pAd))) -#endif // RALINK_ATE // /*====================================================================*/ { pPacket = pTxRing->Cell[pTxRing->TxSwFreeIdx].pNdisPacket; @@ -1915,59 +1864,8 @@ BOOLEAN RTMPFreeTXDUponTxDmaDone( INC_RING_INDEX(pTxRing->TxSwFreeIdx, TX_RING_SIZE); /* get tx_tdx_idx again */ RTMP_IO_READ32(pAd, TX_DTX_IDX0 + QueIdx * RINGREG_DIFF , &pTxRing->TxDmaIdx); -#ifdef RT_BIG_ENDIAN - RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); - *pDestTxD = TxD; -#else + NdisMoveMemory(pOriTxD, pTxD, sizeof(TXD_STRUC)); -#endif - -#ifdef RALINK_ATE -#ifdef RALINK_28xx_QA -kick_out: -#endif // RALINK_28xx_QA // - - // - // ATE_TXCONT mode also need to send some normal frames, so let it in. - // ATE_STOP must be changed not to be 0xff - // to prevent it from running into this block. - // - if ((pAd->ate.Mode & ATE_TXFRAME) && (pAd->ate.QID == QueIdx)) - { - // TxDoneCount++ has been done if QA is used. - if (pAd->ate.bQATxStart == FALSE) - { - pAd->ate.TxDoneCount++; - } - if (((pAd->ate.TxCount - pAd->ate.TxDoneCount + 1) >= TX_RING_SIZE)) - { - /* Note : We increase TxCpuIdx here, not TxSwFreeIdx ! */ - INC_RING_INDEX(pAd->TxRing[QueIdx].TxCpuIdx, TX_RING_SIZE); -#ifndef RT_BIG_ENDIAN//<==========================PETER - pTxD = (PTXD_STRUC) (pTxRing->Cell[pAd->TxRing[QueIdx].TxCpuIdx].AllocVa); - pOriTxD = pTxD; - NdisMoveMemory(&TxD, pTxD, sizeof(TXD_STRUC)); - pTxD = &TxD; -#else - pDestTxD = (PTXD_STRUC) (pTxRing->Cell[pAd->TxRing[QueIdx].TxCpuIdx].AllocVa); - pOriTxD = pDestTxD ; - TxD = *pDestTxD; - pTxD = &TxD; - RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); -#endif - pTxD->DMADONE = 0; -#ifndef RT_BIG_ENDIAN//<==========================PETER - NdisMoveMemory(pOriTxD, pTxD, sizeof(TXD_STRUC)); -#else - RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); - *pDestTxD = TxD; -#endif - // kick Tx-Ring. - RTMP_IO_WRITE32(pAd, TX_CTX_IDX0 + QueIdx * RINGREG_DIFF, pAd->TxRing[QueIdx].TxCpuIdx); - pAd->RalinkCounters.KickTxCount++; - } - } -#endif // RALINK_ATE // } @@ -2050,10 +1948,6 @@ VOID RTMPHandleMgmtRingDmaDoneInterrupt( IN PRTMP_ADAPTER pAd) { PTXD_STRUC pTxD; -#ifdef RT_BIG_ENDIAN - PTXD_STRUC pDestTxD; - TXD_STRUC TxD; -#endif PNDIS_PACKET pPacket; UCHAR FREE = 0; PRTMP_MGMT_RING pMgmtRing = &pAd->MgmtRing; @@ -2064,14 +1958,7 @@ VOID RTMPHandleMgmtRingDmaDoneInterrupt( while (pMgmtRing->TxSwFreeIdx!= pMgmtRing->TxDmaIdx) { FREE++; -#ifdef RT_BIG_ENDIAN - pDestTxD = (PTXD_STRUC) (pMgmtRing->Cell[pAd->MgmtRing.TxSwFreeIdx].AllocVa); - TxD = *pDestTxD; - pTxD = &TxD; - RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); -#else pTxD = (PTXD_STRUC) (pMgmtRing->Cell[pAd->MgmtRing.TxSwFreeIdx].AllocVa); -#endif pTxD->DMADONE = 0; pPacket = pMgmtRing->Cell[pMgmtRing->TxSwFreeIdx].pNdisPacket; @@ -2091,11 +1978,6 @@ VOID RTMPHandleMgmtRingDmaDoneInterrupt( } pMgmtRing->Cell[pMgmtRing->TxSwFreeIdx].pNextNdisPacket = NULL; INC_RING_INDEX(pMgmtRing->TxSwFreeIdx, MGMT_RING_SIZE); - -#ifdef RT_BIG_ENDIAN - RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); - WriteBackToDescriptor((PUCHAR)pDestTxD, (PUCHAR)pTxD, TRUE, TYPE_TXD); -#endif } NdisReleaseSpinLock(&pAd->MgmtRingLock); @@ -2293,6 +2175,7 @@ VOID DBGPRINT_RX_RING( DBGPRINT_RAW(RT_DEBUG_TRACE,(" RxSwReadIdx [%d]=", AC0freeIdx)); DBGPRINT_RAW(RT_DEBUG_TRACE,(" pending-NDIS=%ld\n", pAd->RalinkCounters.PendingNdisPacketCount)); } +#endif /* RT2860 */ /* ======================================================================== @@ -2352,7 +2235,15 @@ VOID RTMPResumeMsduTransmission( { DBGPRINT(RT_DEBUG_TRACE,("SCAN done, resume MSDU transmission ...\n")); - +#ifdef RT30xx + // After finish BSS_SCAN_IN_PROGRESS, we need to restore Current R66 value + // R66 should not be 0 + if (pAd->BbpTuning.R66CurrentValue == 0) + { + pAd->BbpTuning.R66CurrentValue = 0x38; + DBGPRINT_ERR(("RTMPResumeMsduTransmission, R66CurrentValue=0...\n")); + } +#endif RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, pAd->BbpTuning.R66CurrentValue); RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS); @@ -2401,7 +2292,6 @@ UINT deaggregate_AMSDU_announce( // convert to 802.3 header CONVERT_TO_802_3(Header802_3, pDA, pSA, pPayload, PayloadSize, pRemovedLLCSNAP); -#ifdef CONFIG_STA_SUPPORT if ((Header802_3[12] == 0x88) && (Header802_3[13] == 0x8E) ) { // avoid local heap overflow, use dyanamic allocation @@ -2411,10 +2301,7 @@ UINT deaggregate_AMSDU_announce( WpaEAPOLKeyAction(pAd, Elem); kfree(Elem); } -#endif // CONFIG_STA_SUPPORT // -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { if (pRemovedLLCSNAP) { @@ -2423,15 +2310,11 @@ UINT deaggregate_AMSDU_announce( NdisMoveMemory(pPayload, &Header802_3[0], LENGTH_802_3); } } -#endif // CONFIG_STA_SUPPORT // pClonePacket = ClonePacket(pAd, pPacket, pPayload, PayloadSize); if (pClonePacket) { -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - ANNOUNCE_OR_FORWARD_802_3_PACKET(pAd, pClonePacket, RTMP_GET_PACKET_IF(pPacket)); -#endif // CONFIG_STA_SUPPORT // + ANNOUNCE_OR_FORWARD_802_3_PACKET(pAd, pClonePacket, RTMP_GET_PACKET_IF(pPacket)); } @@ -2527,11 +2410,9 @@ MAC_TABLE_ENTRY *MacTableInsertEntry( return NULL; FirstWcid = 1; -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) + if (pAd->StaCfg.BssType == BSS_INFRA) FirstWcid = 2; -#endif // CONFIG_STA_SUPPORT // // allocate one MAC entry NdisAcquireSpinLock(&pAd->MacTabLock); @@ -2542,11 +2423,6 @@ MAC_TABLE_ENTRY *MacTableInsertEntry( (pAd->MacTab.Content[i].ValidAsWDS == FALSE) && (pAd->MacTab.Content[i].ValidAsApCli== FALSE) && (pAd->MacTab.Content[i].ValidAsMesh == FALSE) -#ifdef CONFIG_STA_SUPPORT -#ifdef QOS_DLS_SUPPORT - && (pAd->MacTab.Content[i].ValidAsDls == FALSE) -#endif // QOS_DLS_SUPPORT // -#endif // CONFIG_STA_SUPPORT // ) { pEntry = &pAd->MacTab.Content[i]; @@ -2558,24 +2434,7 @@ MAC_TABLE_ENTRY *MacTableInsertEntry( pEntry->PairwiseKey.KeyLen = 0; pEntry->PairwiseKey.CipherAlg = CIPHER_NONE; } -#ifdef CONFIG_STA_SUPPORT -#ifdef QOS_DLS_SUPPORT - if (apidx >= MIN_NET_DEVICE_FOR_DLS) { - pEntry->ValidAsCLI = FALSE; - pEntry->ValidAsWDS = FALSE; - pEntry->ValidAsApCli = FALSE; - pEntry->ValidAsMesh = FALSE; - pEntry->ValidAsDls = TRUE; - pEntry->isCached = FALSE; - } - else -#endif // QOS_DLS_SUPPORT // -#endif // CONFIG_STA_SUPPORT // - { - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { pEntry->ValidAsCLI = TRUE; pEntry->ValidAsWDS = FALSE; @@ -2583,7 +2442,6 @@ MAC_TABLE_ENTRY *MacTableInsertEntry( pEntry->ValidAsMesh = FALSE; pEntry->ValidAsDls = FALSE; } -#endif // CONFIG_STA_SUPPORT // } pEntry->bIAmBadAtheros = FALSE; @@ -2600,43 +2458,32 @@ MAC_TABLE_ENTRY *MacTableInsertEntry( pEntry->apidx = (apidx - MIN_NET_DEVICE_FOR_APCLI); else if (pEntry->ValidAsWDS) pEntry->apidx = (apidx - MIN_NET_DEVICE_FOR_WDS); -#ifdef CONFIG_STA_SUPPORT -#ifdef QOS_DLS_SUPPORT - else if (pEntry->ValidAsDls) - pEntry->apidx = (apidx - MIN_NET_DEVICE_FOR_DLS); -#endif // QOS_DLS_SUPPORT // -#endif // CONFIG_STA_SUPPORT // else pEntry->apidx = apidx; { - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { pEntry->AuthMode = pAd->StaCfg.AuthMode; pEntry->WepStatus = pAd->StaCfg.WepStatus; pEntry->PrivacyFilter = Ndis802_11PrivFilterAcceptAll; +#ifdef RT2860 AsicRemovePairwiseKeyEntry(pAd, pEntry->apidx, (UCHAR)i); +#endif } -#endif // CONFIG_STA_SUPPORT // } pEntry->GTKState = REKEY_NEGOTIATING; pEntry->PairwiseKey.KeyLen = 0; pEntry->PairwiseKey.CipherAlg = CIPHER_NONE; -#ifdef CONFIG_STA_SUPPORT + +#ifdef RT2860 if ((pAd->OpMode == OPMODE_STA) && (pAd->StaCfg.BssType == BSS_ADHOC)) pEntry->PortSecured = WPA_802_1X_PORT_SECURED; else -#ifdef QOS_DLS_SUPPORT - if (pEntry->ValidAsDls == TRUE) - pEntry->PortSecured = WPA_802_1X_PORT_SECURED; - else -#endif //QOS_DLS_SUPPORT -#endif // CONFIG_STA_SUPPORT // +#endif pEntry->PortSecured = WPA_802_1X_PORT_NOT_SECURED; + pEntry->PMKID_CacheIdx = ENTRY_NOT_FOUND; COPY_MAC_ADDR(pEntry->Addr, pAddr); pEntry->Sst = SST_NOT_AUTH; @@ -2706,11 +2553,6 @@ BOOLEAN MacTableDeleteEntry( pEntry = &pAd->MacTab.Content[wcid]; if (pEntry && (pEntry->ValidAsCLI || pEntry->ValidAsApCli || pEntry->ValidAsWDS || pEntry->ValidAsMesh -#ifdef CONFIG_STA_SUPPORT -#ifdef QOS_DLS_SUPPORT - || pEntry->ValidAsDls -#endif // QOS_DLS_SUPPORT // -#endif // CONFIG_STA_SUPPORT // )) { if (MAC_ADDR_EQUAL(pEntry->Addr, pAddr)) @@ -2719,11 +2561,8 @@ BOOLEAN MacTableDeleteEntry( // Delete this entry from ASIC on-chip WCID Table RT28XX_STA_ENTRY_MAC_RESET(pAd, wcid); -#ifdef DOT11_N_SUPPORT // free resources of BA BASessionTearDownALL(pAd, pEntry->Aid); -#endif // DOT11_N_SUPPORT // - pPrevEntry = NULL; pProbeEntry = pAd->MacTab.Hash[HashIdx]; @@ -2777,10 +2616,13 @@ BOOLEAN MacTableDeleteEntry( //Reset operating mode when no Sta. if (pAd->MacTab.Size == 0) { -#ifdef DOT11_N_SUPPORT pAd->CommonCfg.AddHTInfo.AddHtInfo2.OperaionMode = 0; -#endif // DOT11_N_SUPPORT // +#ifndef RT30xx AsicUpdateProtect(pAd, 0 /*pAd->CommonCfg.AddHTInfo.AddHtInfo2.OperaionMode*/, (ALLN_SETPROTECT), TRUE, 0 /*pAd->MacTab.fAnyStationNonGF*/); +#endif +#ifdef RT30xx + RT28XX_UPDATE_PROTECT(pAd); // edit by johnli, fix "in_interrupt" error when call "MacTableDeleteEntry" in Rx tasklet +#endif } return TRUE; @@ -2804,19 +2646,22 @@ VOID MacTableReset( for (i=1; iMacTab.Content[i].ValidAsCLI == TRUE) { - -#ifdef DOT11_N_SUPPORT // free resources of BA BASessionTearDownALL(pAd, i); -#endif // DOT11_N_SUPPORT // pAd->MacTab.Content[i].ValidAsCLI = FALSE; +#ifdef RT2870 + NdisZeroMemory(pAd->MacTab.Content[i].Addr, 6); + RT28XX_STA_ENTRY_MAC_RESET(pAd, i); +#endif // RT2870 // //AsicDelWcidTab(pAd, i); } @@ -3116,10 +2961,7 @@ VOID Indicate_Legacy_Packet( // 2. remove LLC // a. pointer pRxBlk->pData to payload // b. modify pRxBlk->DataSize -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - RTMP_802_11_REMOVE_LLC_AND_CONVERT_TO_802_3(pRxBlk, Header802_3); -#endif // CONFIG_STA_SUPPORT // + RTMP_802_11_REMOVE_LLC_AND_CONVERT_TO_802_3(pRxBlk, Header802_3); if (pRxBlk->DataSize > MAX_RX_PKT_LEN) { @@ -3132,17 +2974,44 @@ VOID Indicate_Legacy_Packet( STATS_INC_RX_PACKETS(pAd, FromWhichBSSID); +#ifdef RT2870 + if (pAd->CommonCfg.bDisableReordering == 0) + { + PBA_REC_ENTRY pBAEntry; + ULONG Now32; + UCHAR Wcid = pRxBlk->pRxWI->WirelessCliID; + UCHAR TID = pRxBlk->pRxWI->TID; + USHORT Idx; + +#define REORDERING_PACKET_TIMEOUT ((100 * HZ)/1000) // system ticks -- 100 ms + + if (Wcid < MAX_LEN_OF_MAC_TABLE) + { + Idx = pAd->MacTab.Content[Wcid].BARecWcidArray[TID]; + if (Idx != 0) + { + pBAEntry = &pAd->BATable.BARecEntry[Idx]; + // update last rx time + NdisGetSystemUpTime(&Now32); + if ((pBAEntry->list.qlen > 0) && + RTMP_TIME_AFTER((unsigned long)Now32, (unsigned long)(pBAEntry->LastIndSeqAtTimer+(REORDERING_PACKET_TIMEOUT))) + ) + { + printk("Indicate_Legacy_Packet():flush reordering_timeout_mpdus! RxWI->Flags=%d, pRxWI.TID=%d, RxD->AMPDU=%d!\n", pRxBlk->Flags, pRxBlk->pRxWI->TID, pRxBlk->RxD.AMPDU); + hex_dump("Dump the legacy Packet:", GET_OS_PKT_DATAPTR(pRxBlk->pRxPacket), 64); + ba_flush_reordering_timeout_mpdus(pAd, pBAEntry, Now32); + } + } + } + } +#endif // RT2870 // wlan_802_11_to_802_3_packet(pAd, pRxBlk, Header802_3, FromWhichBSSID); // // pass this 802.3 packet to upper layer or forward this packet to WM directly // -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - ANNOUNCE_OR_FORWARD_802_3_PACKET(pAd, pRxPacket, FromWhichBSSID); -#endif // CONFIG_STA_SUPPORT // - + ANNOUNCE_OR_FORWARD_802_3_PACKET(pAd, pRxPacket, FromWhichBSSID); } @@ -3152,22 +3021,18 @@ VOID CmmRxnonRalinkFrameIndicate( IN RX_BLK *pRxBlk, IN UCHAR FromWhichBSSID) { -#ifdef DOT11_N_SUPPORT if (RX_BLK_TEST_FLAG(pRxBlk, fRX_AMPDU) && (pAd->CommonCfg.bDisableReordering == 0)) { Indicate_AMPDU_Packet(pAd, pRxBlk, FromWhichBSSID); } else -#endif // DOT11_N_SUPPORT // { -#ifdef DOT11_N_SUPPORT if (RX_BLK_TEST_FLAG(pRxBlk, fRX_AMSDU)) { // handle A-MSDU Indicate_AMSDU_Packet(pAd, pRxBlk, FromWhichBSSID); } else -#endif // DOT11_N_SUPPORT // { Indicate_Legacy_Packet(pAd, pRxBlk, FromWhichBSSID); } @@ -3205,11 +3070,7 @@ VOID CmmRxRalinkFrameIndicate( } // get 802.3 Header and remove LLC -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - RTMP_802_11_REMOVE_LLC_AND_CONVERT_TO_802_3(pRxBlk, Header802_3); -#endif // CONFIG_STA_SUPPORT // - + RTMP_802_11_REMOVE_LLC_AND_CONVERT_TO_802_3(pRxBlk, Header802_3); ASSERT(pRxBlk->pRxPacket); @@ -3219,10 +3080,8 @@ VOID CmmRxRalinkFrameIndicate( Payload2Size = Msdu2Size - LENGTH_802_3; pData2 = pRxBlk->pData + Payload1Size + LENGTH_802_3; -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - pPacket2 = duplicate_pkt(pAd, (pData2-LENGTH_802_3), LENGTH_802_3, pData2, Payload2Size, FromWhichBSSID); -#endif // CONFIG_STA_SUPPORT // + + pPacket2 = duplicate_pkt(pAd, (pData2-LENGTH_802_3), LENGTH_802_3, pData2, Payload2Size, FromWhichBSSID); if (!pPacket2) { @@ -3235,17 +3094,11 @@ VOID CmmRxRalinkFrameIndicate( pRxBlk->DataSize = Payload1Size; wlan_802_11_to_802_3_packet(pAd, pRxBlk, Header802_3, FromWhichBSSID); -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - ANNOUNCE_OR_FORWARD_802_3_PACKET(pAd, pRxBlk->pRxPacket, FromWhichBSSID); -#endif // CONFIG_STA_SUPPORT // + ANNOUNCE_OR_FORWARD_802_3_PACKET(pAd, pRxBlk->pRxPacket, FromWhichBSSID); if (pPacket2) { -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - ANNOUNCE_OR_FORWARD_802_3_PACKET(pAd, pPacket2, FromWhichBSSID); -#endif // CONFIG_STA_SUPPORT // + ANNOUNCE_OR_FORWARD_802_3_PACKET(pAd, pPacket2, FromWhichBSSID); } } @@ -3388,15 +3241,11 @@ VOID Indicate_EAPOL_Packet( { MAC_TABLE_ENTRY *pEntry = NULL; - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { pEntry = &pAd->MacTab.Content[BSSID_WCID]; STARxEAPOLFrameIndicate(pAd, pEntry, pRxBlk, FromWhichBSSID); return; } -#endif // CONFIG_STA_SUPPORT // if (pEntry == NULL) { diff --git a/drivers/staging/rt2860/common/cmm_data_2860.c b/drivers/staging/rt2860/common/cmm_data_2860.c index fae741e4beeb..fb1735533b74 100644 --- a/drivers/staging/rt2860/common/cmm_data_2860.c +++ b/drivers/staging/rt2860/common/cmm_data_2860.c @@ -110,10 +110,6 @@ USHORT RtmpPCI_WriteSingleTxResource( UCHAR *pDMAHeaderBufVA; USHORT TxIdx, RetTxIdx; PTXD_STRUC pTxD; -#ifdef RT_BIG_ENDIAN - PTXD_STRUC pDestTxD; - TXD_STRUC TxD; -#endif UINT32 BufBasePaLow; PRTMP_TX_RING pTxRing; USHORT hwHeaderLen; @@ -137,13 +133,8 @@ USHORT RtmpPCI_WriteSingleTxResource( // // build Tx Descriptor // -#ifndef RT_BIG_ENDIAN pTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa; -#else - pDestTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa; - TxD = *pDestTxD; - pTxD = &TxD; -#endif + NdisZeroMemory(pTxD, TXD_SIZE); pTxD->SDPtr0 = BufBasePaLow; @@ -154,12 +145,6 @@ USHORT RtmpPCI_WriteSingleTxResource( pTxD->LastSec1 = (bIsLast) ? 1 : 0; RTMPWriteTxDescriptor(pAd, pTxD, FALSE, FIFO_EDCA); -#ifdef RT_BIG_ENDIAN - RTMPWIEndianChange((PUCHAR)(pDMAHeaderBufVA + TXINFO_SIZE), TYPE_TXWI); - RTMPFrameEndianChange(pAd, (PUCHAR)(pDMAHeaderBufVA + TXINFO_SIZE + TXWI_SIZE), DIR_WRITE, FALSE); - RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); - WriteBackToDescriptor((PUCHAR)pDestTxD, (PUCHAR)pTxD, FALSE, TYPE_TXD); -#endif // RT_BIG_ENDIAN // RetTxIdx = TxIdx; // @@ -184,10 +169,6 @@ USHORT RtmpPCI_WriteMultiTxResource( UCHAR *pDMAHeaderBufVA; USHORT TxIdx, RetTxIdx; PTXD_STRUC pTxD; -#ifdef RT_BIG_ENDIAN - PTXD_STRUC pDestTxD; - TXD_STRUC TxD; -#endif UINT32 BufBasePaLow; PRTMP_TX_RING pTxRing; USHORT hwHdrLen; @@ -231,13 +212,8 @@ USHORT RtmpPCI_WriteMultiTxResource( // // build Tx Descriptor // -#ifndef RT_BIG_ENDIAN pTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa; -#else - pDestTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa; - TxD = *pDestTxD; - pTxD = &TxD; -#endif + NdisZeroMemory(pTxD, TXD_SIZE); pTxD->SDPtr0 = BufBasePaLow; @@ -249,17 +225,6 @@ USHORT RtmpPCI_WriteMultiTxResource( RTMPWriteTxDescriptor(pAd, pTxD, FALSE, FIFO_EDCA); -#ifdef RT_BIG_ENDIAN - if (frameNum == 0) - RTMPFrameEndianChange(pAd, (PUCHAR)(pDMAHeaderBufVA+ TXINFO_SIZE + TXWI_SIZE), DIR_WRITE, FALSE); - - if (frameNum != 0) - RTMPWIEndianChange((PUCHAR)(pDMAHeaderBufVA + TXINFO_SIZE), TYPE_TXWI); - - RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); - WriteBackToDescriptor((PUCHAR)pDestTxD, (PUCHAR)pTxD, FALSE, TYPE_TXD); -#endif // RT_BIG_ENDIAN // - RetTxIdx = TxIdx; // // Update Tx index @@ -290,10 +255,6 @@ VOID RtmpPCI_FinalWriteTxResource( pTxRing = &pAd->TxRing[pTxBlk->QueIdx]; pTxWI = (PTXWI_STRUC) pTxRing->Cell[FirstTxIdx].DmaBuf.AllocVa; pTxWI->MPDUtotalByteCount = totalMPDUSize; -#ifdef RT_BIG_ENDIAN - RTMPWIEndianChange((PUCHAR)pTxWI, TYPE_TXWI); -#endif // RT_BIG_ENDIAN // - } @@ -303,10 +264,6 @@ VOID RtmpPCIDataLastTxIdx( IN USHORT LastTxIdx) { PTXD_STRUC pTxD; -#ifdef RT_BIG_ENDIAN - PTXD_STRUC pDestTxD; - TXD_STRUC TxD; -#endif PRTMP_TX_RING pTxRing; // @@ -317,21 +274,9 @@ VOID RtmpPCIDataLastTxIdx( // // build Tx Descriptor // -#ifndef RT_BIG_ENDIAN pTxD = (PTXD_STRUC) pTxRing->Cell[LastTxIdx].AllocVa; -#else - pDestTxD = (PTXD_STRUC) pTxRing->Cell[LastTxIdx].AllocVa; - TxD = *pDestTxD; - pTxD = &TxD; -#endif pTxD->LastSec1 = 1; - -#ifdef RT_BIG_ENDIAN - RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); - WriteBackToDescriptor((PUCHAR)pDestTxD, (PUCHAR)pTxD, FALSE, TYPE_TXD); -#endif // RT_BIG_ENDIAN // - } @@ -344,10 +289,6 @@ USHORT RtmpPCI_WriteFragTxResource( UCHAR *pDMAHeaderBufVA; USHORT TxIdx, RetTxIdx; PTXD_STRUC pTxD; -#ifdef RT_BIG_ENDIAN - PTXD_STRUC pDestTxD; - TXD_STRUC TxD; -#endif UINT32 BufBasePaLow; PRTMP_TX_RING pTxRing; USHORT hwHeaderLen; @@ -373,13 +314,8 @@ USHORT RtmpPCI_WriteFragTxResource( // // Build Tx Descriptor // -#ifndef RT_BIG_ENDIAN pTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa; -#else - pDestTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa; - TxD = *pDestTxD; - pTxD = &TxD; -#endif + NdisZeroMemory(pTxD, TXD_SIZE); if (fragNum == pTxBlk->TotalFragNum) @@ -397,13 +333,6 @@ USHORT RtmpPCI_WriteFragTxResource( RTMPWriteTxDescriptor(pAd, pTxD, FALSE, FIFO_EDCA); -#ifdef RT_BIG_ENDIAN - RTMPWIEndianChange((PUCHAR)(pDMAHeaderBufVA + TXINFO_SIZE), TYPE_TXWI); - RTMPFrameEndianChange(pAd, (PUCHAR)(pDMAHeaderBufVA + TXINFO_SIZE + TXWI_SIZE), DIR_WRITE, FALSE); - RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); - WriteBackToDescriptor((PUCHAR)pDestTxD, (PUCHAR)pTxD, FALSE, TYPE_TXD); -#endif // RT_BIG_ENDIAN // - RetTxIdx = TxIdx; pTxBlk->Priv += pTxBlk->SrcBufLen; @@ -431,20 +360,9 @@ int RtmpPCIMgmtKickOut( IN UINT SrcBufLen) { PTXD_STRUC pTxD; -#ifdef RT_BIG_ENDIAN - PTXD_STRUC pDestTxD; - TXD_STRUC TxD; -#endif ULONG SwIdx = pAd->MgmtRing.TxCpuIdx; -#ifdef RT_BIG_ENDIAN - pDestTxD = (PTXD_STRUC)pAd->MgmtRing.Cell[SwIdx].AllocVa; - TxD = *pDestTxD; - pTxD = &TxD; - RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); -#else pTxD = (PTXD_STRUC) pAd->MgmtRing.Cell[SwIdx].AllocVa; -#endif pAd->MgmtRing.Cell[SwIdx].pNdisPacket = pPacket; pAd->MgmtRing.Cell[SwIdx].pNextNdisPacket = NULL; @@ -457,11 +375,6 @@ int RtmpPCIMgmtKickOut( pTxD->SDPtr0 = PCI_MAP_SINGLE(pAd, pSrcBufVA, SrcBufLen, 0, PCI_DMA_TODEVICE);; pTxD->SDLen0 = SrcBufLen; -#ifdef RT_BIG_ENDIAN - RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); - WriteBackToDescriptor((PUCHAR)pDestTxD, (PUCHAR)pTxD, FALSE, TYPE_TXD); -#endif - pAd->RalinkCounters.KickTxCount++; pAd->RalinkCounters.OneSecTxDoneCount++; @@ -473,8 +386,6 @@ int RtmpPCIMgmtKickOut( return 0; } - -#ifdef CONFIG_STA_SUPPORT /* ======================================================================== @@ -570,12 +481,11 @@ NDIS_STATUS RTMPCheckRxError( if (pRxD->CipherErr == 2) { pWpaKey = &pAd->SharedKey[BSS0][pRxWI->KeyIndex]; -#ifdef WPA_SUPPLICANT_SUPPORT + if (pAd->StaCfg.WpaSupplicantUP) WpaSendMicFailureToWpaSupplicant(pAd, (pWpaKey->Type == PAIRWISEKEY) ? TRUE:FALSE); else -#endif // WPA_SUPPLICANT_SUPPORT // RTMPReportMicError(pAd, pWpaKey); if (((pRxD->CipherErr & 2) == 2) && pAd->CommonCfg.bWirelessEvent && INFRA_ON(pAd)) @@ -1128,8 +1038,6 @@ VOID RadioOnExec( } } -#endif // CONFIG_STA_SUPPORT // - VOID RT28xxPciMlmeRadioOn( IN PRTMP_ADAPTER pAd) { @@ -1163,7 +1071,6 @@ VOID RT28xxPciMlmeRadioOn( RTMPSetLED(pAd, LED_RADIO_ON); } -#ifdef CONFIG_STA_SUPPORT if ((pAd->OpMode == OPMODE_STA) && (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))) { @@ -1176,7 +1083,6 @@ VOID RT28xxPciMlmeRadioOn( RTMPCancelTimer(&pAd->Mlme.RadioOnOffTimer, &Cancelled); RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 10); } -#endif // CONFIG_STA_SUPPORT // } VOID RT28xxPciMlmeRadioOFF( @@ -1199,8 +1105,6 @@ VOID RT28xxPciMlmeRadioOFF( // Set LED RTMPSetLED(pAd, LED_RADIO_OFF); -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { BOOLEAN Cancelled; @@ -1249,7 +1153,6 @@ VOID RT28xxPciMlmeRadioOFF( return; } } -#endif // CONFIG_STA_SUPPORT // // Set Radio off flag RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF); diff --git a/drivers/staging/rt2860/common/cmm_info.c b/drivers/staging/rt2860/common/cmm_info.c index c3e13195e121..306c3a21f905 100644 --- a/drivers/staging/rt2860/common/cmm_info.c +++ b/drivers/staging/rt2860/common/cmm_info.c @@ -63,7 +63,6 @@ INT Show_FragThreshold_Proc( IN PRTMP_ADAPTER pAd, OUT PUCHAR pBuf); -#ifdef DOT11_N_SUPPORT INT Show_HtBw_Proc( IN PRTMP_ADAPTER pAd, OUT PUCHAR pBuf); @@ -103,7 +102,6 @@ INT Show_HtAmsdu_Proc( INT Show_HtAutoBa_Proc( IN PRTMP_ADAPTER pAd, OUT PUCHAR pBuf); -#endif // DOT11_N_SUPPORT // INT Show_CountryRegion_Proc( IN PRTMP_ADAPTER pAd, @@ -133,11 +131,9 @@ INT Show_IEEE80211H_Proc( IN PRTMP_ADAPTER pAd, OUT PUCHAR pBuf); -#ifdef CONFIG_STA_SUPPORT INT Show_NetworkType_Proc( IN PRTMP_ADAPTER pAd, OUT PUCHAR pBuf); -#endif // CONFIG_STA_SUPPORT // INT Show_AuthMode_Proc( IN PRTMP_ADAPTER pAd, @@ -184,7 +180,6 @@ static struct { {"BGProtection", Show_BGProtection_Proc}, {"RTSThreshold", Show_RTSThreshold_Proc}, {"FragThreshold", Show_FragThreshold_Proc}, -#ifdef DOT11_N_SUPPORT {"HtBw", Show_HtBw_Proc}, {"HtMcs", Show_HtMcs_Proc}, {"HtGi", Show_HtGi_Proc}, @@ -195,7 +190,6 @@ static struct { {"HtRdg", Show_HtRdg_Proc}, {"HtAmsdu", Show_HtAmsdu_Proc}, {"HtAutoBa", Show_HtAutoBa_Proc}, -#endif // DOT11_N_SUPPORT // {"CountryRegion", Show_CountryRegion_Proc}, {"CountryRegionABand", Show_CountryRegionABand_Proc}, {"CountryCode", Show_CountryCode_Proc}, @@ -207,9 +201,7 @@ static struct { {"WmmCapable", Show_WmmCapable_Proc}, #endif {"IEEE80211H", Show_IEEE80211H_Proc}, -#ifdef CONFIG_STA_SUPPORT {"NetworkType", Show_NetworkType_Proc}, -#endif // CONFIG_STA_SUPPORT // {"AuthMode", Show_AuthMode_Proc}, {"EncrypType", Show_EncrypType_Proc}, {"DefaultKeyID", Show_DefaultKeyID_Proc}, @@ -233,11 +225,7 @@ INT Set_DriverVersion_Proc( IN PRTMP_ADAPTER pAd, IN PUCHAR arg) { - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - DBGPRINT(RT_DEBUG_TRACE, ("Driver version-%s\n", STA_DRIVER_VERSION)); -#endif // CONFIG_STA_SUPPORT // + DBGPRINT(RT_DEBUG_TRACE, ("Driver version-%s\n", STA_DRIVER_VERSION)); return TRUE; } @@ -259,10 +247,6 @@ INT Set_CountryRegion_Proc( region = simple_strtol(arg, 0, 10); -#ifdef EXT_BUILD_CHANNEL_LIST - return -EOPNOTSUPP; -#endif // EXT_BUILD_CHANNEL_LIST // - // Country can be set only when EEPROM not programmed if (pAd->CommonCfg.CountryRegion & 0x80) { @@ -309,10 +293,6 @@ INT Set_CountryRegionABand_Proc( region = simple_strtol(arg, 0, 10); -#ifdef EXT_BUILD_CHANNEL_LIST - return -EOPNOTSUPP; -#endif // EXT_BUILD_CHANNEL_LIST // - // Country can be set only when EEPROM not programmed if (pAd->CommonCfg.CountryRegionForABand & 0x80) { @@ -355,20 +335,15 @@ INT Set_WirelessMode_Proc( WirelessMode = simple_strtol(arg, 0, 10); - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { INT MaxPhyMode = PHY_11G; -#ifdef DOT11_N_SUPPORT MaxPhyMode = PHY_11N_5G; -#endif // DOT11_N_SUPPORT // if (WirelessMode <= MaxPhyMode) { RTMPSetPhyMode(pAd, WirelessMode); -#ifdef DOT11_N_SUPPORT + if (WirelessMode >= PHY_11ABGN_MIXED) { pAd->CommonCfg.BACapability.field.AutoBA = TRUE; @@ -379,7 +354,7 @@ INT Set_WirelessMode_Proc( pAd->CommonCfg.BACapability.field.AutoBA = FALSE; pAd->CommonCfg.REGBACapability.field.AutoBA = FALSE; } -#endif // DOT11_N_SUPPORT // + // Set AdhocMode rates if (pAd->StaCfg.BssType == BSS_ADHOC) { @@ -393,14 +368,11 @@ INT Set_WirelessMode_Proc( success = FALSE; } } -#endif // CONFIG_STA_SUPPORT // // it is needed to set SSID to take effect if (success == TRUE) { -#ifdef DOT11_N_SUPPORT SetCommonHT(pAd); -#endif // DOT11_N_SUPPORT // DBGPRINT(RT_DEBUG_TRACE, ("Set_WirelessMode_Proc::(=%ld)\n", WirelessMode)); } else @@ -431,14 +403,11 @@ INT Set_Channel_Proc( // check if this channel is valid if (ChannelSanity(pAd, Channel) == TRUE) { -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { pAd->CommonCfg.Channel = Channel; if (MONITOR_ON(pAd)) { -#ifdef DOT11_N_SUPPORT N_ChannelCheck(pAd); if (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED && pAd->CommonCfg.RegTransmitSetting.field.BW == BW_40) @@ -450,7 +419,6 @@ INT Set_Channel_Proc( pAd->CommonCfg.Channel, pAd->CommonCfg.CentralChannel)); } else -#endif // DOT11_N_SUPPORT // { AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); AsicLockChannel(pAd, pAd->CommonCfg.Channel); @@ -458,16 +426,11 @@ INT Set_Channel_Proc( } } } -#endif // CONFIG_STA_SUPPORT // success = TRUE; } else { - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - success = FALSE; -#endif // CONFIG_STA_SUPPORT // + success = FALSE; } @@ -523,14 +486,10 @@ INT Set_TxPower_Proc( TxPower = (ULONG) simple_strtol(arg, 0, 10); if (TxPower <= 100) { - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { pAd->CommonCfg.TxPowerDefault = TxPower; pAd->CommonCfg.TxPowerPercentage = pAd->CommonCfg.TxPowerDefault; } -#endif // CONFIG_STA_SUPPORT // success = TRUE; } else @@ -595,22 +554,16 @@ INT Set_TxPreamble_Proc( { case Rt802_11PreambleShort: pAd->CommonCfg.TxPreamble = Preamble; -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - MlmeSetTxPreamble(pAd, Rt802_11PreambleShort); -#endif // CONFIG_STA_SUPPORT // + + MlmeSetTxPreamble(pAd, Rt802_11PreambleShort); break; case Rt802_11PreambleLong: -#ifdef CONFIG_STA_SUPPORT case Rt802_11PreambleAuto: // if user wants AUTO, initialize to LONG here, then change according to AP's // capability upon association. -#endif // CONFIG_STA_SUPPORT // pAd->CommonCfg.TxPreamble = Preamble; -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - MlmeSetTxPreamble(pAd, Rt802_11PreambleLong); -#endif // CONFIG_STA_SUPPORT // + + MlmeSetTxPreamble(pAd, Rt802_11PreambleLong); break; default: //Invalid argument return FALSE; @@ -639,10 +592,8 @@ INT Set_RTSThreshold_Proc( if((RtsThresh > 0) && (RtsThresh <= MAX_RTS_THRESHOLD)) pAd->CommonCfg.RtsThreshold = (USHORT)RtsThresh; -#ifdef CONFIG_STA_SUPPORT else if (RtsThresh == 0) pAd->CommonCfg.RtsThreshold = MAX_RTS_THRESHOLD; -#endif // CONFIG_STA_SUPPORT // else return FALSE; //Invalid argument @@ -683,15 +634,12 @@ INT Set_FragThreshold_Proc( pAd->CommonCfg.FragmentThreshold = (USHORT)FragThresh; } -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { if (pAd->CommonCfg.FragmentThreshold == MAX_FRAG_THRESHOLD) pAd->CommonCfg.bUseZeroToDisableFragment = TRUE; else pAd->CommonCfg.bUseZeroToDisableFragment = FALSE; } -#endif // CONFIG_STA_SUPPORT // DBGPRINT(RT_DEBUG_TRACE, ("Set_FragThreshold_Proc::(FragThreshold=%d)\n", pAd->CommonCfg.FragmentThreshold)); @@ -814,6 +762,7 @@ INT Show_DescInfo_Proc( IN PRTMP_ADAPTER pAd, IN PUCHAR arg) { +#ifdef RT2860 INT i, QueIdx=0; PRT28XX_RXD_STRUC pRxD; PTXD_STRUC pTxD; @@ -844,7 +793,7 @@ INT Show_DescInfo_Proc( hex_dump("Rx Descriptor", (char *)pRxD, 16); printk("pRxD->DDONE = %x\n", pRxD->DDONE); } - +#endif /* RT2860 */ return TRUE; } @@ -912,7 +861,6 @@ BOOLEAN RTMPCheckStrPrintAble( ======================================================================== */ -#ifdef CONFIG_STA_SUPPORT VOID RTMPSetDesiredRates( IN PRTMP_ADAPTER pAdapter, IN LONG Rates) @@ -1125,10 +1073,7 @@ NDIS_STATUS RTMPWPARemoveKeyProc( return (Status); } -#endif // CONFIG_STA_SUPPORT // - -#ifdef CONFIG_STA_SUPPORT /* ======================================================================== @@ -1178,7 +1123,6 @@ VOID RTMPWPARemoveAllKeys( } } -#endif // CONFIG_STA_SUPPORT // /* ======================================================================== @@ -1202,19 +1146,11 @@ VOID RTMPSetPhyMode( INT i; // the selected phymode must be supported by the RF IC encoded in E2PROM - // if no change, do nothing - /* bug fix - if (pAd->CommonCfg.PhyMode == phymode) - return; - */ pAd->CommonCfg.PhyMode = (UCHAR)phymode; DBGPRINT(RT_DEBUG_TRACE,("RTMPSetPhyMode : PhyMode=%d, channel=%d \n", pAd->CommonCfg.PhyMode, pAd->CommonCfg.Channel)); -#ifdef EXT_BUILD_CHANNEL_LIST - BuildChannelListEx(pAd); -#else + BuildChannelList(pAd); -#endif // EXT_BUILD_CHANNEL_LIST // // sanity check user setting for (i = 0; i < pAd->ChannelListNum; i++) @@ -1225,10 +1161,7 @@ VOID RTMPSetPhyMode( if (i == pAd->ChannelListNum) { -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - pAd->CommonCfg.Channel = FirstChannel(pAd); -#endif // CONFIG_STA_SUPPORT // + pAd->CommonCfg.Channel = FirstChannel(pAd); DBGPRINT(RT_DEBUG_ERROR, ("RTMPSetPhyMode: channel is out of range, use first channel=%d \n", pAd->CommonCfg.Channel)); } @@ -1253,12 +1186,10 @@ VOID RTMPSetPhyMode( case PHY_11G: case PHY_11BG_MIXED: case PHY_11ABG_MIXED: -#ifdef DOT11_N_SUPPORT case PHY_11N_2_4G: case PHY_11ABGN_MIXED: case PHY_11BGN_MIXED: case PHY_11GN_MIXED: -#endif // DOT11_N_SUPPORT // pAd->CommonCfg.SupRate[0] = 0x82; // 1 mbps, in units of 0.5 Mbps, basic rate pAd->CommonCfg.SupRate[1] = 0x84; // 2 mbps, in units of 0.5 Mbps, basic rate pAd->CommonCfg.SupRate[2] = 0x8B; // 5.5 mbps, in units of 0.5 Mbps, basic rate @@ -1288,11 +1219,9 @@ VOID RTMPSetPhyMode( break; case PHY_11A: -#ifdef DOT11_N_SUPPORT case PHY_11AN_MIXED: case PHY_11AGN_MIXED: case PHY_11N_5G: -#endif // DOT11_N_SUPPORT // pAd->CommonCfg.SupRate[0] = 0x8C; // 6 mbps, in units of 0.5 Mbps, basic rate pAd->CommonCfg.SupRate[1] = 0x12; // 9 mbps, in units of 0.5 Mbps pAd->CommonCfg.SupRate[2] = 0x98; // 12 mbps, in units of 0.5 Mbps, basic rate @@ -1322,8 +1251,6 @@ VOID RTMPSetPhyMode( pAd->CommonCfg.BandState = UNKNOWN_BAND; } - -#ifdef DOT11_N_SUPPORT /* ======================================================================== Routine Description: @@ -1492,6 +1419,16 @@ VOID RTMPSetHT( pAd->CommonCfg.DesiredHtPhy.RxSTBC = 0; } +#ifndef RT30xx +#ifdef RT2870 + /* Frank recommend ,If not, Tx maybe block in high power. Rx has no problem*/ + if(IS_RT3070(pAd) && ((pAd->RfIcType == RFIC_3020) || (pAd->RfIcType == RFIC_2020))) + { + pAd->CommonCfg.HtCapability.HtCapInfo.TxSTBC = 0; + pAd->CommonCfg.DesiredHtPhy.TxSTBC = 0; + } +#endif // RT2870 // +#endif if(pHTPhyMode->SHORTGI == GI_400) { @@ -1539,14 +1476,7 @@ VOID RTMPSetHT( } AsicSetEdcaParm(pAd, &pAd->CommonCfg.APEdcaParm); - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - RTMPSetIndividualHT(pAd, 0); - } -#endif // CONFIG_STA_SUPPORT // - + RTMPSetIndividualHT(pAd, 0); } /* @@ -1571,16 +1501,12 @@ VOID RTMPSetIndividualHT( do { - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { pDesired_ht_phy = &pAd->StaCfg.DesiredHtPhyInfo; DesiredMcs = pAd->StaCfg.DesiredTransmitSetting.field.MCS; //pAd->StaCfg.bAutoTxRateSwitch = (DesiredMcs == MCS_AUTO) ? TRUE : FALSE; break; } -#endif // CONFIG_STA_SUPPORT // } while (FALSE); if (pDesired_ht_phy == NULL) @@ -1710,7 +1636,6 @@ VOID RTMPUpdateHTIE( DBGPRINT(RT_DEBUG_TRACE,("RTMPUpdateHTIE <== \n")); } -#endif // DOT11_N_SUPPORT // /* ======================================================================== @@ -1732,8 +1657,6 @@ VOID RTMPAddWcidAttributeEntry( USHORT Wcid = 0; { -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { if (BssIdx > BSS0) { @@ -1748,39 +1671,22 @@ VOID RTMPAddWcidAttributeEntry( Wcid = pEntry->Aid; else if (pEntry && INFRA_ON(pAd)) { -#ifdef QOS_DLS_SUPPORT - if (pEntry->ValidAsDls == TRUE) - Wcid = pEntry->Aid; - else -#endif // QOS_DLS_SUPPORT // Wcid = BSSID_WCID; } else Wcid = MCAST_WCID; } -#endif // CONFIG_STA_SUPPORT // } // Update WCID attribute table offset = MAC_WCID_ATTRIBUTE_BASE + (Wcid * HW_WCID_ATTRI_SIZE); -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { if (pEntry && pEntry->ValidAsMesh) WCIDAttri = (CipherAlg<<1) | PAIRWISEKEYTABLE; -#ifdef QOS_DLS_SUPPORT - else if ((pEntry) && (pEntry->ValidAsDls) && - ((CipherAlg == CIPHER_TKIP) || - (CipherAlg == CIPHER_TKIP_NO_MIC) || - (CipherAlg == CIPHER_AES) || - (CipherAlg == CIPHER_NONE))) - WCIDAttri = (CipherAlg<<1) | PAIRWISEKEYTABLE; -#endif // QOS_DLS_SUPPORT // else WCIDAttri = (CipherAlg<<1) | SHAREDKEYTABLE; } -#endif // CONFIG_STA_SUPPORT // RTMP_IO_WRITE32(pAd, offset, WCIDAttri); @@ -1801,7 +1707,12 @@ VOID RTMPAddWcidAttributeEntry( } // For key index and ext IV bit, so only need to update the position(offset+3). +#ifdef RT2860 RTMP_IO_WRITE8(pAd, offset+3, IVEIV); +#endif +#ifdef RT2870 + RTUSBMultiWrite_OneByte(pAd, offset+3, &IVEIV); +#endif // RT2870 // DBGPRINT(RT_DEBUG_TRACE,("RTMPAddWcidAttributeEntry: WCID #%d, KeyIndex #%d, Alg=%s\n",Wcid, KeyIdx, CipherName[CipherAlg])); DBGPRINT(RT_DEBUG_TRACE,(" WCIDAttri = 0x%x \n", WCIDAttri)); @@ -1864,7 +1775,6 @@ CHAR *GetAuthMode(CHAR auth) return "UNKNOW"; } -#if 1 //#ifndef UCOS /* ========================================================================== Description: @@ -1912,11 +1822,10 @@ VOID RTMPIoctlGetSiteSurvey( "Ch", "SSID", "BSSID", "Enc", "Auth", "Siganl(%)", "W-Mode", " NT"); WaitCnt = 0; -#ifdef CONFIG_STA_SUPPORT pAdapter->StaCfg.bScanReqIsFromWebUI = TRUE; + while ((ScanRunning(pAdapter) == TRUE) && (WaitCnt++ < 200)) OS_WAIT(500); -#endif // CONFIG_STA_SUPPORT // for(i=0; iScanTab.BssNr ;i++) { @@ -1982,9 +1891,7 @@ VOID RTMPIoctlGetSiteSurvey( sprintf(msg+strlen(msg),"\n"); } -#ifdef CONFIG_STA_SUPPORT pAdapter->StaCfg.bScanReqIsFromWebUI = FALSE; -#endif // CONFIG_STA_SUPPORT // wrq->u.data.length = strlen(msg); Status = copy_to_user(wrq->u.data.pointer, msg, wrq->u.data.length); @@ -2010,9 +1917,7 @@ VOID RTMPIoctlGetMacTable( COPY_MAC_ADDR(MacTab.Entry[MacTab.Num].Addr, &pAd->MacTab.Content[i].Addr); MacTab.Entry[MacTab.Num].Aid = (UCHAR)pAd->MacTab.Content[i].Aid; MacTab.Entry[MacTab.Num].Psm = pAd->MacTab.Content[i].PsMode; -#ifdef DOT11_N_SUPPORT MacTab.Entry[MacTab.Num].MimoPs = pAd->MacTab.Content[i].MmpsMode; -#endif // DOT11_N_SUPPORT // // Fill in RSSI per entry MacTab.Entry[MacTab.Num].AvgRssi0 = pAd->MacTab.Content[i].RssiSample.AvgRssi0; @@ -2072,9 +1977,7 @@ VOID RTMPIoctlGetMacTable( kfree(msg); } -#endif // UCOS // -#ifdef DOT11_N_SUPPORT INT Set_BASetup_Proc( IN PRTMP_ADAPTER pAd, IN PUCHAR arg) @@ -2089,7 +1992,6 @@ INT Set_BASetup_Proc( =>The six 2 digit hex-decimal number previous are the Mac address, =>The seventh decimal number is the tid value. */ - //printk("\n%s\n", arg); if(strlen(arg) < 19) //Mac address acceptable format 01:02:03:04:05:06 length 17 plus the "-" and tid value in decimal format. return FALSE; @@ -2283,9 +2185,7 @@ INT Set_HtMcs_Proc( IN PUCHAR arg) { ULONG HtMcs, Mcs_tmp; -#ifdef CONFIG_STA_SUPPORT BOOLEAN bAutoRate = FALSE; -#endif // CONFIG_STA_SUPPORT // Mcs_tmp = simple_strtol(arg, 0, 10); @@ -2294,8 +2194,6 @@ INT Set_HtMcs_Proc( else HtMcs = MCS_AUTO; -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { pAd->StaCfg.DesiredTransmitSetting.field.MCS = HtMcs; pAd->StaCfg.bAutoTxRateSwitch = (HtMcs == MCS_AUTO) ? TRUE:FALSE; @@ -2330,7 +2228,6 @@ INT Set_HtMcs_Proc( if (ADHOC_ON(pAd)) return TRUE; } -#endif // CONFIG_STA_SUPPORT // SetCommonHT(pAd); @@ -2592,13 +2489,26 @@ INT Set_HtAutoBa_Proc( Value = simple_strtol(arg, 0, 10); if (Value == 0) + { pAd->CommonCfg.BACapability.field.AutoBA = FALSE; +#ifdef RT30xx + pAd->CommonCfg.BACapability.field.Policy = BA_NOTUSE; +#endif + } else if (Value == 1) + { pAd->CommonCfg.BACapability.field.AutoBA = TRUE; +#ifdef RT30xx + pAd->CommonCfg.BACapability.field.Policy = IMMED_BA; +#endif + } else return FALSE; //Invalid argument pAd->CommonCfg.REGBACapability.field.AutoBA = pAd->CommonCfg.BACapability.field.AutoBA; +#ifdef RT30xx + pAd->CommonCfg.REGBACapability.field.Policy = pAd->CommonCfg.BACapability.field.Policy; +#endif SetCommonHT(pAd); DBGPRINT(RT_DEBUG_TRACE, ("Set_HtAutoBa_Proc::(HtAutoBa=%d)\n",pAd->CommonCfg.BACapability.field.AutoBA)); @@ -2762,10 +2672,7 @@ INT Set_HtMimoPs_Proc( return TRUE; } -#endif // DOT11_N_SUPPORT // - -#ifdef DOT11_N_SUPPORT INT SetCommonHT( IN PRTMP_ADAPTER pAd) { @@ -2787,7 +2694,6 @@ INT SetCommonHT( return TRUE; } -#endif // DOT11_N_SUPPORT // INT Set_FixedTxMode_Proc( IN PRTMP_ADAPTER pAd, @@ -2804,45 +2710,13 @@ INT Set_FixedTxMode_Proc( fix_tx_mode = FIXED_TXMODE_CCK; } -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode = fix_tx_mode; -#endif // CONFIG_STA_SUPPORT // + pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode = fix_tx_mode; DBGPRINT(RT_DEBUG_TRACE, ("Set_FixedTxMode_Proc::(FixedTxMode=%d)\n", fix_tx_mode)); return TRUE; } -#ifdef CONFIG_APSTA_MIXED_SUPPORT -INT Set_OpMode_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ULONG Value; - - Value = simple_strtol(arg, 0, 10); - - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_ERROR, ("Can not switch operate mode on interface up !! \n")); - return FALSE; - } - - if (Value == 0) - pAd->OpMode = OPMODE_STA; - else if (Value == 1) - pAd->OpMode = OPMODE_AP; - else - return FALSE; //Invalid argument - - DBGPRINT(RT_DEBUG_TRACE, ("Set_OpMode_Proc::(OpMode=%s)\n", pAd->OpMode == 1 ? "AP Mode" : "STA Mode")); - - return TRUE; -} -#endif // CONFIG_APSTA_MIXED_SUPPORT // - - ///////////////////////////////////////////////////////////////////////// PCHAR RTMPGetRalinkAuthModeStr( IN NDIS_802_11_AUTHENTICATION_MODE authMode) @@ -2851,7 +2725,9 @@ PCHAR RTMPGetRalinkAuthModeStr( { case Ndis802_11AuthModeOpen: return "OPEN"; +#if defined(RT2860) || defined(RT30xx) default: +#endif case Ndis802_11AuthModeWPAPSK: return "WPAPSK"; case Ndis802_11AuthModeShared: @@ -2866,8 +2742,14 @@ PCHAR RTMPGetRalinkAuthModeStr( return "WPAPSKWPA2PSK"; case Ndis802_11AuthModeWPA1WPA2: return "WPA1WPA2"; +#ifndef RT30xx case Ndis802_11AuthModeWPANone: return "WPANONE"; +#ifdef RT2870 + default: + return "UNKNOW"; +#endif +#endif } } @@ -2876,7 +2758,9 @@ PCHAR RTMPGetRalinkEncryModeStr( { switch(encryMode) { +#if defined(RT2860) || defined(RT30xx) default: +#endif case Ndis802_11WEPDisabled: return "NONE"; case Ndis802_11WEPEnabled: @@ -2887,6 +2771,10 @@ PCHAR RTMPGetRalinkEncryModeStr( return "AES"; case Ndis802_11Encryption4Enabled: return "TKIPAES"; +#if !defined(RT2860) && !defined(RT30xx) + default: + return "UNKNOW"; +#endif } } @@ -2911,7 +2799,7 @@ INT RTMPShowCfgValue( { sprintf(pBuf, "\n"); for (PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC = RTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC; PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC->name; PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC++) - sprintf(pBuf, "%s%s\n", pBuf, PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC->name); + sprintf(pBuf + strlen(pBuf), "%s\n", PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC->name); } return Status; @@ -2921,11 +2809,7 @@ INT Show_SSID_Proc( IN PRTMP_ADAPTER pAd, OUT PUCHAR pBuf) { - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - sprintf(pBuf, "\t%s", pAd->CommonCfg.Ssid); -#endif // CONFIG_STA_SUPPORT // + sprintf(pBuf, "\t%s", pAd->CommonCfg.Ssid); return 0; } @@ -2950,7 +2834,6 @@ INT Show_WirelessMode_Proc( case PHY_11G: sprintf(pBuf, "\t11G"); break; -#ifdef DOT11_N_SUPPORT case PHY_11ABGN_MIXED: sprintf(pBuf, "\t11A/B/G/N"); break; @@ -2972,7 +2855,6 @@ INT Show_WirelessMode_Proc( case PHY_11N_5G: sprintf(pBuf, "\t11N only with 5G"); break; -#endif // DOT11_N_SUPPORT // default: sprintf(pBuf, "\tUnknow Value(%d)", pAd->CommonCfg.PhyMode); break; @@ -3066,7 +2948,6 @@ INT Show_FragThreshold_Proc( return 0; } -#ifdef DOT11_N_SUPPORT INT Show_HtBw_Proc( IN PRTMP_ADAPTER pAd, OUT PUCHAR pBuf) @@ -3086,11 +2967,7 @@ INT Show_HtMcs_Proc( IN PRTMP_ADAPTER pAd, OUT PUCHAR pBuf) { - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - sprintf(pBuf, "\t%u", pAd->StaCfg.DesiredTransmitSetting.field.MCS); -#endif // CONFIG_STA_SUPPORT // + sprintf(pBuf, "\t%u", pAd->StaCfg.DesiredTransmitSetting.field.MCS); return 0; } @@ -3191,7 +3068,6 @@ INT Show_HtAutoBa_Proc( sprintf(pBuf, "\t%s", pAd->CommonCfg.BACapability.field.AutoBA ? "TRUE":"FALSE"); return 0; } -#endif // DOT11_N_SUPPORT // INT Show_CountryRegion_Proc( IN PRTMP_ADAPTER pAd, @@ -3232,11 +3108,7 @@ INT Show_WmmCapable_Proc( IN PRTMP_ADAPTER pAd, OUT PUCHAR pBuf) { - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - sprintf(pBuf, "\t%s", pAd->CommonCfg.bWmmCapable ? "TRUE":"FALSE"); -#endif // CONFIG_STA_SUPPORT // + sprintf(pBuf, "\t%s", pAd->CommonCfg.bWmmCapable ? "TRUE":"FALSE"); return 0; } @@ -3250,7 +3122,6 @@ INT Show_IEEE80211H_Proc( return 0; } -#ifdef CONFIG_STA_SUPPORT INT Show_NetworkType_Proc( IN PRTMP_ADAPTER pAd, OUT PUCHAR pBuf) @@ -3275,7 +3146,6 @@ INT Show_NetworkType_Proc( } return 0; } -#endif // CONFIG_STA_SUPPORT // INT Show_AuthMode_Proc( IN PRTMP_ADAPTER pAd, @@ -3283,10 +3153,7 @@ INT Show_AuthMode_Proc( { NDIS_802_11_AUTHENTICATION_MODE AuthMode = Ndis802_11AuthModeOpen; -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - AuthMode = pAd->StaCfg.AuthMode; -#endif // CONFIG_STA_SUPPORT // + AuthMode = pAd->StaCfg.AuthMode; if ((AuthMode >= Ndis802_11AuthModeOpen) && (AuthMode <= Ndis802_11AuthModeWPA1PSKWPA2PSK)) @@ -3303,10 +3170,7 @@ INT Show_EncrypType_Proc( { NDIS_802_11_WEP_STATUS WepStatus = Ndis802_11WEPDisabled; -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - WepStatus = pAd->StaCfg.WepStatus; -#endif // CONFIG_STA_SUPPORT // + WepStatus = pAd->StaCfg.WepStatus; if ((WepStatus >= Ndis802_11WEPEnabled) && (WepStatus <= Ndis802_11Encryption4KeyAbsent)) @@ -3323,10 +3187,7 @@ INT Show_DefaultKeyID_Proc( { UCHAR DefaultKeyId = 0; -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - DefaultKeyId = pAd->StaCfg.DefaultKeyId; -#endif // CONFIG_STA_SUPPORT // + DefaultKeyId = pAd->StaCfg.DefaultKeyId; sprintf(pBuf, "\t%d", DefaultKeyId); @@ -3396,11 +3257,7 @@ INT Show_WPAPSK_Proc( INT idx; UCHAR PMK[32] = {0}; - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - NdisMoveMemory(PMK, pAd->StaCfg.PMK, 32); -#endif // CONFIG_STA_SUPPORT // + NdisMoveMemory(PMK, pAd->StaCfg.PMK, 32); sprintf(pBuf, "\tPMK = "); for (idx = 0; idx < 32; idx++) diff --git a/drivers/staging/rt2860/common/cmm_sanity.c b/drivers/staging/rt2860/common/cmm_sanity.c index b0f070d43135..843e44e41abe 100644 --- a/drivers/staging/rt2860/common/cmm_sanity.c +++ b/drivers/staging/rt2860/common/cmm_sanity.c @@ -275,9 +275,7 @@ BOOLEAN PeerBeaconAndProbeRspSanity( OUT PQOS_CAPABILITY_PARM pQosCapability, OUT ULONG *pRalinkIe, OUT UCHAR *pHtCapabilityLen, -#ifdef CONFIG_STA_SUPPORT OUT UCHAR *pPreNHtCapabilityLen, -#endif // CONFIG_STA_SUPPORT // OUT HT_CAPABILITY_IE *pHtCapability, OUT UCHAR *AddHtInfoLen, OUT ADD_HT_INFO_IE *AddHtInfo, @@ -286,9 +284,7 @@ BOOLEAN PeerBeaconAndProbeRspSanity( OUT PNDIS_802_11_VARIABLE_IEs pVIE) { CHAR *Ptr; -#ifdef CONFIG_STA_SUPPORT CHAR TimLen; -#endif // CONFIG_STA_SUPPORT // PFRAME_802_11 pFrame; PEID_STRUCT pEid; UCHAR SubType; @@ -316,10 +312,8 @@ BOOLEAN PeerBeaconAndProbeRspSanity( *pAironetCellPowerLimit = 0xFF; // Default of AironetCellPowerLimit is 0xFF *LengthVIE = 0; // Set the length of VIE to init value 0 *pHtCapabilityLen = 0; // Set the length of VIE to init value 0 -#ifdef CONFIG_STA_SUPPORT if (pAd->OpMode == OPMODE_STA) *pPreNHtCapabilityLen = 0; // Set the length of VIE to init value 0 -#endif // CONFIG_STA_SUPPORT // *AddHtInfoLen = 0; // Set the length of VIE to init value 0 *pRalinkIe = 0; *pNewChannel = 0; @@ -428,8 +422,6 @@ BOOLEAN PeerBeaconAndProbeRspSanity( *(USHORT *)(&pHtCapability->HtCapInfo) = cpu2le16(*(USHORT *)(&pHtCapability->HtCapInfo)); *(USHORT *)(&pHtCapability->ExtHtCapInfo) = cpu2le16(*(USHORT *)(&pHtCapability->ExtHtCapInfo)); -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { *pPreNHtCapabilityLen = 0; // Nnow we only support 26 bytes. @@ -437,7 +429,6 @@ BOOLEAN PeerBeaconAndProbeRspSanity( NdisMoveMemory(Ptr + *LengthVIE, &pEid->Eid, pEid->Len + 2); *LengthVIE += (pEid->Len + 2); } -#endif // CONFIG_STA_SUPPORT // } else { @@ -458,14 +449,11 @@ BOOLEAN PeerBeaconAndProbeRspSanity( *(USHORT *)(&AddHtInfo->AddHtInfo2) = cpu2le16(*(USHORT *)(&AddHtInfo->AddHtInfo2)); *(USHORT *)(&AddHtInfo->AddHtInfo3) = cpu2le16(*(USHORT *)(&AddHtInfo->AddHtInfo3)); -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { Ptr = (PUCHAR) pVIE; NdisMoveMemory(Ptr + *LengthVIE, &pEid->Eid, pEid->Len + 2); *LengthVIE += (pEid->Len + 2); } -#endif // CONFIG_STA_SUPPORT // } else { @@ -492,8 +480,7 @@ BOOLEAN PeerBeaconAndProbeRspSanity( if(pEid->Len == 1) { *pChannel = *pEid->Octet; -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) + { if (ChannelSanity(pAd, *pChannel) == 0) { @@ -501,7 +488,7 @@ BOOLEAN PeerBeaconAndProbeRspSanity( return FALSE; } } -#endif // CONFIG_STA_SUPPORT // + Sanity |= 0x4; } else @@ -539,14 +526,13 @@ BOOLEAN PeerBeaconAndProbeRspSanity( } break; -#ifdef CONFIG_STA_SUPPORT case IE_TIM: if(INFRA_ON(pAd) && SubType == SUBTYPE_BEACON) { GetTimBit((PUCHAR)pEid, pAd->StaActive.Aid, &TimLen, pBcastFlag, pDtimCount, pDtimPeriod, pMessageToMe); } break; -#endif // CONFIG_STA_SUPPORT // + case IE_CHANNEL_SWITCH_ANNOUNCEMENT: if(pEid->Len == 3) { @@ -568,8 +554,6 @@ BOOLEAN PeerBeaconAndProbeRspSanity( else *pRalinkIe = 0xf0000000; // Set to non-zero value (can't set bit0-2) to represent this is Ralink Chip. So at linkup, we will set ralinkchip flag. } -#ifdef CONFIG_STA_SUPPORT -#ifdef DOT11_N_SUPPORT // This HT IE is before IEEE draft set HT IE value.2006-09-28 by Jan. // Other vendors had production before IE_HT_CAP value is assigned. To backward support those old-firmware AP, @@ -588,8 +572,6 @@ BOOLEAN PeerBeaconAndProbeRspSanity( *AddHtInfoLen = SIZE_ADD_HT_INFO_IE; } } -#endif // DOT11_N_SUPPORT // -#endif // CONFIG_STA_SUPPORT // else if (NdisEqualMemory(pEid->Octet, WPA_OUI, 4)) { // Copy to pVIE which will report to microsoft bssid list. @@ -712,15 +694,6 @@ BOOLEAN PeerBeaconAndProbeRspSanity( *LengthVIE += (pEid->Len + 2); } break; -#ifdef CONFIG_STA_SUPPORT -#ifdef EXT_BUILD_CHANNEL_LIST - case IE_COUNTRY: - Ptr = (PUCHAR) pVIE; - NdisMoveMemory(Ptr + *LengthVIE, &pEid->Eid, pEid->Len + 2); - *LengthVIE += (pEid->Len + 2); - break; -#endif // EXT_BUILD_CHANNEL_LIST // -#endif // CONFIG_STA_SUPPORT // default: break; @@ -731,8 +704,6 @@ BOOLEAN PeerBeaconAndProbeRspSanity( } // For some 11a AP. it did not have the channel EID, patch here -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { UCHAR LatchRfChannel = MsgChannel; if ((pAd->LatchRfRegs.Channel > 14) && ((Sanity & 0x4) == 0)) @@ -744,7 +715,6 @@ BOOLEAN PeerBeaconAndProbeRspSanity( Sanity |= 0x4; } } -#endif // CONFIG_STA_SUPPORT // if (Sanity != 0x7) { @@ -758,76 +728,6 @@ BOOLEAN PeerBeaconAndProbeRspSanity( } -#ifdef DOT11N_DRAFT3 -/* - ========================================================================== - Description: - MLME message sanity check for some IE addressed in 802.11n d3.03. - Return: - TRUE if all parameters are OK, FALSE otherwise - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -BOOLEAN PeerBeaconAndProbeRspSanity2( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT UCHAR *RegClass) -{ - CHAR *Ptr; - PFRAME_802_11 pFrame; - PEID_STRUCT pEid; - ULONG Length = 0; - - pFrame = (PFRAME_802_11)Msg; - - *RegClass = 0; - Ptr = pFrame->Octet; - Length += LENGTH_802_11; - - // get timestamp from payload and advance the pointer - Ptr += TIMESTAMP_LEN; - Length += TIMESTAMP_LEN; - - // get beacon interval from payload and advance the pointer - Ptr += 2; - Length += 2; - - // get capability info from payload and advance the pointer - Ptr += 2; - Length += 2; - - pEid = (PEID_STRUCT) Ptr; - - // get variable fields from payload and advance the pointer - while ((Length + 2 + pEid->Len) <= MsgLen) - { - switch(pEid->Eid) - { - case IE_SUPP_REG_CLASS: - if(pEid->Len > 0) - { - *RegClass = *pEid->Octet; - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("PeerBeaconAndProbeRspSanity - wrong IE_SSID (len=%d)\n",pEid->Len)); - return FALSE; - } - break; - } - - Length = Length + 2 + pEid->Len; // Eid[1] + Len[1]+ content[Len] - pEid = (PEID_STRUCT)((UCHAR*)pEid + 2 + pEid->Len); - } - - return TRUE; - -} -#endif // DOT11N_DRAFT3 // - /* ========================================================================== Description: @@ -855,10 +755,8 @@ BOOLEAN MlmeScanReqSanity( if ((*pBssType == BSS_INFRA || *pBssType == BSS_ADHOC || *pBssType == BSS_ANY) && (*pScanType == SCAN_ACTIVE || *pScanType == SCAN_PASSIVE -#ifdef CONFIG_STA_SUPPORT || *pScanType == SCAN_CISCO_PASSIVE || *pScanType == SCAN_CISCO_ACTIVE || *pScanType == SCAN_CISCO_CHANNEL_LOAD || *pScanType == SCAN_CISCO_NOISE -#endif // CONFIG_STA_SUPPORT // )) { return TRUE; @@ -940,9 +838,6 @@ BOOLEAN PeerAuthSanity( NdisMoveMemory(pStatus, &pFrame->Octet[4], 2); if ((*pAlg == Ndis802_11AuthModeOpen) -#ifdef LEAP_SUPPORT - || (*pAlg == CISCO_AuthModeLEAP) -#endif // LEAP_SUPPORT // ) { if (*pSeq == 1 || *pSeq == 2) @@ -1003,9 +898,6 @@ BOOLEAN MlmeAuthReqSanity( *pAlg = pInfo->Alg; if (((*pAlg == Ndis802_11AuthModeShared) ||(*pAlg == Ndis802_11AuthModeOpen) -#ifdef LEAP_SUPPORT - || (*pAlg == CISCO_AuthModeLEAP) -#endif // LEAP_SUPPORT // ) && ((*pAddr & 0x01) == 0)) { @@ -1344,290 +1236,3 @@ BOOLEAN PeerWpaMessageSanity( return TRUE; } - -#ifdef CONFIG_STA_SUPPORT -#ifdef QOS_DLS_SUPPORT -BOOLEAN MlmeDlsReqSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PRT_802_11_DLS *pDLS, - OUT PUSHORT pReason) -{ - MLME_DLS_REQ_STRUCT *pInfo; - - pInfo = (MLME_DLS_REQ_STRUCT *)Msg; - - *pDLS = pInfo->pDLS; - *pReason = pInfo->Reason; - - return TRUE; -} -#endif // QOS_DLS_SUPPORT // -#endif // CONFIG_STA_SUPPORT // - -#ifdef QOS_DLS_SUPPORT -BOOLEAN PeerDlsReqSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PUCHAR pDA, - OUT PUCHAR pSA, - OUT USHORT *pCapabilityInfo, - OUT USHORT *pDlsTimeout, - OUT UCHAR *pRatesLen, - OUT UCHAR Rates[], - OUT UCHAR *pHtCapabilityLen, - OUT HT_CAPABILITY_IE *pHtCapability) -{ - CHAR *Ptr; - PFRAME_802_11 Fr = (PFRAME_802_11)Msg; - PEID_STRUCT eid_ptr; - - // to prevent caller from using garbage output value - *pCapabilityInfo = 0; - *pDlsTimeout = 0; - *pHtCapabilityLen = 0; - - Ptr = Fr->Octet; - - // offset to destination MAC address (Category and Action field) - Ptr += 2; - - // get DA from payload and advance the pointer - NdisMoveMemory(pDA, Ptr, MAC_ADDR_LEN); - Ptr += MAC_ADDR_LEN; - - // get SA from payload and advance the pointer - NdisMoveMemory(pSA, Ptr, MAC_ADDR_LEN); - Ptr += MAC_ADDR_LEN; - - // get capability info from payload and advance the pointer - NdisMoveMemory(pCapabilityInfo, Ptr, 2); - Ptr += 2; - - // get capability info from payload and advance the pointer - NdisMoveMemory(pDlsTimeout, Ptr, 2); - Ptr += 2; - - // Category and Action field + DA + SA + capability + Timeout - eid_ptr = (PEID_STRUCT) &Fr->Octet[18]; - - while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((UCHAR*)Fr + MsgLen)) - { - switch(eid_ptr->Eid) - { - case IE_SUPP_RATES: - if ((eid_ptr->Len <= MAX_LEN_OF_SUPPORTED_RATES) && (eid_ptr->Len > 0)) - { - NdisMoveMemory(Rates, eid_ptr->Octet, eid_ptr->Len); - DBGPRINT(RT_DEBUG_TRACE, ("PeerDlsReqSanity - IE_SUPP_RATES., Len=%d. Rates[0]=%x\n",eid_ptr->Len, Rates[0])); - DBGPRINT(RT_DEBUG_TRACE, ("Rates[1]=%x %x %x %x %x %x %x\n", Rates[1], Rates[2], Rates[3], Rates[4], Rates[5], Rates[6], Rates[7])); - *pRatesLen = eid_ptr->Len; - } - else - { - *pRatesLen = 8; - Rates[0] = 0x82; - Rates[1] = 0x84; - Rates[2] = 0x8b; - Rates[3] = 0x96; - Rates[4] = 0x12; - Rates[5] = 0x24; - Rates[6] = 0x48; - Rates[7] = 0x6c; - DBGPRINT(RT_DEBUG_TRACE, ("PeerDlsReqSanity - wrong IE_SUPP_RATES., Len=%d\n",eid_ptr->Len)); - } - break; - - case IE_EXT_SUPP_RATES: - if (eid_ptr->Len + *pRatesLen <= MAX_LEN_OF_SUPPORTED_RATES) - { - NdisMoveMemory(&Rates[*pRatesLen], eid_ptr->Octet, eid_ptr->Len); - *pRatesLen = (*pRatesLen) + eid_ptr->Len; - } - else - { - NdisMoveMemory(&Rates[*pRatesLen], eid_ptr->Octet, MAX_LEN_OF_SUPPORTED_RATES - (*pRatesLen)); - *pRatesLen = MAX_LEN_OF_SUPPORTED_RATES; - } - break; - - case IE_HT_CAP: - if (eid_ptr->Len >= sizeof(HT_CAPABILITY_IE)) - { - NdisMoveMemory(pHtCapability, eid_ptr->Octet, sizeof(HT_CAPABILITY_IE)); - - *(USHORT *)(&pHtCapability->HtCapInfo) = cpu2le16(*(USHORT *)(&pHtCapability->HtCapInfo)); - *(USHORT *)(&pHtCapability->ExtHtCapInfo) = cpu2le16(*(USHORT *)(&pHtCapability->ExtHtCapInfo)); - *pHtCapabilityLen = sizeof(HT_CAPABILITY_IE); - - DBGPRINT(RT_DEBUG_TRACE, ("PeerDlsReqSanity - IE_HT_CAP\n")); - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("PeerDlsReqSanity - wrong IE_HT_CAP.eid_ptr->Len = %d\n", eid_ptr->Len)); - } - break; - - default: - break; - } - - eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len); - } - - return TRUE; -} - -BOOLEAN PeerDlsRspSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PUCHAR pDA, - OUT PUCHAR pSA, - OUT USHORT *pCapabilityInfo, - OUT USHORT *pStatus, - OUT UCHAR *pRatesLen, - OUT UCHAR Rates[], - OUT UCHAR *pHtCapabilityLen, - OUT HT_CAPABILITY_IE *pHtCapability) -{ - CHAR *Ptr; - PFRAME_802_11 Fr = (PFRAME_802_11)Msg; - PEID_STRUCT eid_ptr; - - // to prevent caller from using garbage output value - *pStatus = 0; - *pCapabilityInfo = 0; - *pHtCapabilityLen = 0; - - Ptr = Fr->Octet; - - // offset to destination MAC address (Category and Action field) - Ptr += 2; - - // get status code from payload and advance the pointer - NdisMoveMemory(pStatus, Ptr, 2); - Ptr += 2; - - // get DA from payload and advance the pointer - NdisMoveMemory(pDA, Ptr, MAC_ADDR_LEN); - Ptr += MAC_ADDR_LEN; - - // get SA from payload and advance the pointer - NdisMoveMemory(pSA, Ptr, MAC_ADDR_LEN); - Ptr += MAC_ADDR_LEN; - - if (pStatus == 0) - { - // get capability info from payload and advance the pointer - NdisMoveMemory(pCapabilityInfo, Ptr, 2); - Ptr += 2; - } - - // Category and Action field + status code + DA + SA + capability - eid_ptr = (PEID_STRUCT) &Fr->Octet[18]; - - while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((UCHAR*)Fr + MsgLen)) - { - switch(eid_ptr->Eid) - { - case IE_SUPP_RATES: - if ((eid_ptr->Len <= MAX_LEN_OF_SUPPORTED_RATES) && (eid_ptr->Len > 0)) - { - NdisMoveMemory(Rates, eid_ptr->Octet, eid_ptr->Len); - DBGPRINT(RT_DEBUG_TRACE, ("PeerDlsRspSanity - IE_SUPP_RATES., Len=%d. Rates[0]=%x\n",eid_ptr->Len, Rates[0])); - DBGPRINT(RT_DEBUG_TRACE, ("Rates[1]=%x %x %x %x %x %x %x\n", Rates[1], Rates[2], Rates[3], Rates[4], Rates[5], Rates[6], Rates[7])); - *pRatesLen = eid_ptr->Len; - } - else - { - *pRatesLen = 8; - Rates[0] = 0x82; - Rates[1] = 0x84; - Rates[2] = 0x8b; - Rates[3] = 0x96; - Rates[4] = 0x12; - Rates[5] = 0x24; - Rates[6] = 0x48; - Rates[7] = 0x6c; - DBGPRINT(RT_DEBUG_TRACE, ("PeerDlsRspSanity - wrong IE_SUPP_RATES., Len=%d\n",eid_ptr->Len)); - } - break; - - case IE_EXT_SUPP_RATES: - if (eid_ptr->Len + *pRatesLen <= MAX_LEN_OF_SUPPORTED_RATES) - { - NdisMoveMemory(&Rates[*pRatesLen], eid_ptr->Octet, eid_ptr->Len); - *pRatesLen = (*pRatesLen) + eid_ptr->Len; - } - else - { - NdisMoveMemory(&Rates[*pRatesLen], eid_ptr->Octet, MAX_LEN_OF_SUPPORTED_RATES - (*pRatesLen)); - *pRatesLen = MAX_LEN_OF_SUPPORTED_RATES; - } - break; - - case IE_HT_CAP: - if (eid_ptr->Len >= sizeof(HT_CAPABILITY_IE)) - { - NdisMoveMemory(pHtCapability, eid_ptr->Octet, sizeof(HT_CAPABILITY_IE)); - - *(USHORT *)(&pHtCapability->HtCapInfo) = cpu2le16(*(USHORT *)(&pHtCapability->HtCapInfo)); - *(USHORT *)(&pHtCapability->ExtHtCapInfo) = cpu2le16(*(USHORT *)(&pHtCapability->ExtHtCapInfo)); - *pHtCapabilityLen = sizeof(HT_CAPABILITY_IE); - - DBGPRINT(RT_DEBUG_TRACE, ("PeerDlsRspSanity - IE_HT_CAP\n")); - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("PeerDlsRspSanity - wrong IE_HT_CAP.eid_ptr->Len = %d\n", eid_ptr->Len)); - } - break; - - default: - break; - } - - eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len); - } - - return TRUE; -} - -BOOLEAN PeerDlsTearDownSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PUCHAR pDA, - OUT PUCHAR pSA, - OUT USHORT *pReason) -{ - CHAR *Ptr; - PFRAME_802_11 Fr = (PFRAME_802_11)Msg; - - // to prevent caller from using garbage output value - *pReason = 0; - - Ptr = Fr->Octet; - - // offset to destination MAC address (Category and Action field) - Ptr += 2; - - // get DA from payload and advance the pointer - NdisMoveMemory(pDA, Ptr, MAC_ADDR_LEN); - Ptr += MAC_ADDR_LEN; - - // get SA from payload and advance the pointer - NdisMoveMemory(pSA, Ptr, MAC_ADDR_LEN); - Ptr += MAC_ADDR_LEN; - - // get reason code from payload and advance the pointer - NdisMoveMemory(pReason, Ptr, 2); - Ptr += 2; - - return TRUE; -} -#endif // QOS_DLS_SUPPORT // - diff --git a/drivers/staging/rt2860/common/cmm_sync.c b/drivers/staging/rt2860/common/cmm_sync.c index d29e0b630e2e..a6e1b6ddfe57 100644 --- a/drivers/staging/rt2860/common/cmm_sync.c +++ b/drivers/staging/rt2860/common/cmm_sync.c @@ -95,9 +95,7 @@ VOID BuildChannelList( // if not 11a-only mode, channel list starts from 2.4Ghz band if ((pAd->CommonCfg.PhyMode != PHY_11A) -#ifdef DOT11_N_SUPPORT && (pAd->CommonCfg.PhyMode != PHY_11AN_MIXED) && (pAd->CommonCfg.PhyMode != PHY_11N_5G) -#endif // DOT11_N_SUPPORT // ) { switch (pAd->CommonCfg.CountryRegion & 0x7f) @@ -146,10 +144,8 @@ VOID BuildChannelList( } if ((pAd->CommonCfg.PhyMode == PHY_11A) || (pAd->CommonCfg.PhyMode == PHY_11ABG_MIXED) -#ifdef DOT11_N_SUPPORT || (pAd->CommonCfg.PhyMode == PHY_11ABGN_MIXED) || (pAd->CommonCfg.PhyMode == PHY_11AN_MIXED) || (pAd->CommonCfg.PhyMode == PHY_11AGN_MIXED) || (pAd->CommonCfg.PhyMode == PHY_11N_5G) -#endif // DOT11_N_SUPPORT // ) { switch (pAd->CommonCfg.CountryRegionForABand & 0x7f) @@ -383,33 +379,18 @@ VOID ScanNextChannel( NDIS_STATUS NStatus; ULONG FrameLen = 0; UCHAR SsidLen = 0, ScanType = pAd->MlmeAux.ScanType, BBPValue = 0; -#ifdef CONFIG_STA_SUPPORT USHORT Status; PHEADER_802_11 pHdr80211; -#endif // CONFIG_STA_SUPPORT // UINT ScanTimeIn5gChannel = SHORT_CHANNEL_TIME; -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - if (MONITOR_ON(pAd)) - return; - } -#endif // CONFIG_STA_SUPPORT // - -#ifdef RALINK_ATE - // Nothing to do in ATE mode. - if (ATE_ON(pAd)) + if (MONITOR_ON(pAd)) return; -#endif // RALINK_ATE // if (pAd->MlmeAux.Channel == 0) { if ((pAd->CommonCfg.BBPCurrentBW == BW_40) -#ifdef CONFIG_STA_SUPPORT && (INFRA_ON(pAd) || (pAd->OpMode == OPMODE_AP)) -#endif // CONFIG_STA_SUPPORT // ) { AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE); @@ -427,8 +408,6 @@ VOID ScanNextChannel( DBGPRINT(RT_DEBUG_TRACE, ("SYNC - End of SCAN, restore to channel %d, Total BSS[%02d]\n",pAd->CommonCfg.Channel, pAd->ScanTab.BssNr)); } -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { // // To prevent data lost. @@ -458,31 +437,35 @@ VOID ScanNextChannel( Status = MLME_SUCCESS; MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_SCAN_CONF, 2, &Status); } -#endif // CONFIG_STA_SUPPORT // - RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS); } +#ifdef RT2870 + else if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST) && (pAd->OpMode == OPMODE_STA)) + { + pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; + MlmeCntlConfirm(pAd, MT2_SCAN_CONF, MLME_FAIL_NO_RESOURCE); + } +#endif // RT2870 // else { -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { // BBP and RF are not accessible in PS mode, we has to wake them up first if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) +#ifdef RT2860 AsicForceWakeup(pAd, FROM_TX); - +#endif +#ifdef RT2870 + AsicForceWakeup(pAd, TRUE); +#endif // leave PSM during scanning. otherwise we may lost ProbeRsp & BEACON if (pAd->StaCfg.Psm == PWR_SAVE) MlmeSetPsmBit(pAd, PWR_ACTIVE); } -#endif // CONFIG_STA_SUPPORT // AsicSwitchChannel(pAd, pAd->MlmeAux.Channel, TRUE); AsicLockChannel(pAd, pAd->MlmeAux.Channel); -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { if (pAd->MlmeAux.Channel > 14) { @@ -492,19 +475,8 @@ VOID ScanNextChannel( ScanTimeIn5gChannel = MIN_CHANNEL_TIME; } } - -#ifdef CARRIER_DETECTION_SUPPORT // Roger sync Carrier - // carrier detection - if (pAd->CommonCfg.CarrierDetect.Enable == TRUE) - { - ScanType = SCAN_PASSIVE; - ScanTimeIn5gChannel = MIN_CHANNEL_TIME; - } -#endif // CARRIER_DETECTION_SUPPORT // } -#endif // CONFIG_STA_SUPPORT // - //Global country domain(ch1-11:active scan, ch12-14 passive scan) if ((pAd->MlmeAux.Channel <= 14) && (pAd->MlmeAux.Channel >= 12) && ((pAd->CommonCfg.CountryRegion & 0x7f) == REGION_31_BG_BAND)) { @@ -515,7 +487,6 @@ VOID ScanNextChannel( // Chnage the channel scan time for CISCO stuff based on its IAPP announcement if (ScanType == FAST_SCAN_ACTIVE) RTMPSetTimer(&pAd->MlmeAux.ScanTimer, FAST_ACTIVE_SCAN_TIME); -#ifdef CONFIG_STA_SUPPORT else if (((ScanType == SCAN_CISCO_ACTIVE) || (ScanType == SCAN_CISCO_PASSIVE) || (ScanType == SCAN_CISCO_CHANNEL_LOAD) || @@ -526,13 +497,10 @@ VOID ScanNextChannel( else RTMPSetTimer(&pAd->MlmeAux.ScanTimer, pAd->StaCfg.CCXScanTime); } -#endif // CONFIG_STA_SUPPORT // else // must be SCAN_PASSIVE or SCAN_ACTIVE { if ((pAd->CommonCfg.PhyMode == PHY_11ABG_MIXED) -#ifdef DOT11_N_SUPPORT || (pAd->CommonCfg.PhyMode == PHY_11ABGN_MIXED) || (pAd->CommonCfg.PhyMode == PHY_11AGN_MIXED) -#endif // DOT11_N_SUPPORT // ) { if (pAd->MlmeAux.Channel > 14) @@ -551,14 +519,12 @@ VOID ScanNextChannel( if (NStatus != NDIS_STATUS_SUCCESS) { DBGPRINT(RT_DEBUG_TRACE, ("SYNC - ScanNextChannel() allocate memory fail\n")); -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) + { pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; Status = MLME_FAIL_NO_RESOURCE; MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_SCAN_CONF, 2, &Status); } -#endif // CONFIG_STA_SUPPORT // return; } @@ -592,78 +558,35 @@ VOID ScanNextChannel( FrameLen += Tmp; } -#ifdef DOT11_N_SUPPORT if (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) { ULONG Tmp; UCHAR HtLen; UCHAR BROADCOM[4] = {0x0, 0x90, 0x4c, 0x33}; -#ifdef RT_BIG_ENDIAN - HT_CAPABILITY_IE HtCapabilityTmp; -#endif + if (pAd->bBroadComHT == TRUE) { HtLen = pAd->MlmeAux.HtCapabilityLen + 4; -#ifdef RT_BIG_ENDIAN - NdisMoveMemory(&HtCapabilityTmp, &pAd->MlmeAux.HtCapability, SIZE_HT_CAP_IE); - *(USHORT *)(&HtCapabilityTmp.HtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.HtCapInfo)); - *(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo)); - MakeOutgoingFrame(pOutBuffer + FrameLen, &Tmp, - 1, &WpaIe, - 1, &HtLen, - 4, &BROADCOM[0], - pAd->MlmeAux.HtCapabilityLen, &HtCapabilityTmp, - END_OF_ARGS); -#else MakeOutgoingFrame(pOutBuffer + FrameLen, &Tmp, 1, &WpaIe, 1, &HtLen, 4, &BROADCOM[0], pAd->MlmeAux.HtCapabilityLen, &pAd->MlmeAux.HtCapability, END_OF_ARGS); -#endif // RT_BIG_ENDIAN // } else { HtLen = pAd->MlmeAux.HtCapabilityLen; -#ifdef RT_BIG_ENDIAN - NdisMoveMemory(&HtCapabilityTmp, &pAd->CommonCfg.HtCapability, SIZE_HT_CAP_IE); - *(USHORT *)(&HtCapabilityTmp.HtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.HtCapInfo)); - *(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo)); - MakeOutgoingFrame(pOutBuffer + FrameLen, &Tmp, - 1, &HtCapIe, - 1, &HtLen, - HtLen, &HtCapabilityTmp, - END_OF_ARGS); -#else MakeOutgoingFrame(pOutBuffer + FrameLen, &Tmp, 1, &HtCapIe, 1, &HtLen, HtLen, &pAd->CommonCfg.HtCapability, END_OF_ARGS); -#endif // RT_BIG_ENDIAN // } FrameLen += Tmp; - -#ifdef DOT11N_DRAFT3 - if (pAd->CommonCfg.BACapability.field.b2040CoexistScanSup == 1) - { - ULONG Tmp; - HtLen = 1; - MakeOutgoingFrame(pOutBuffer + FrameLen, &Tmp, - 1, &ExtHtCapIe, - 1, &HtLen, - 1, &pAd->CommonCfg.BSSCoexist2040.word, - END_OF_ARGS); - - FrameLen += Tmp; - } -#endif // DOT11N_DRAFT3 // } -#endif // DOT11_N_SUPPORT // - MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); MlmeFreeMemory(pAd, pOutBuffer); @@ -671,11 +594,7 @@ VOID ScanNextChannel( // For SCAN_CISCO_PASSIVE, do nothing and silently wait for beacon or other probe reponse -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - pAd->Mlme.SyncMachine.CurrState = SCAN_LISTEN; -#endif // CONFIG_STA_SUPPORT // - + pAd->Mlme.SyncMachine.CurrState = SCAN_LISTEN; } } diff --git a/drivers/staging/rt2860/common/cmm_wpa.c b/drivers/staging/rt2860/common/cmm_wpa.c index 69baf522fa01..bda69e76867e 100644 --- a/drivers/staging/rt2860/common/cmm_wpa.c +++ b/drivers/staging/rt2860/common/cmm_wpa.c @@ -39,10 +39,14 @@ // WPA OUI UCHAR OUI_WPA_NONE_AKM[4] = {0x00, 0x50, 0xF2, 0x00}; UCHAR OUI_WPA_VERSION[4] = {0x00, 0x50, 0xF2, 0x01}; +#ifndef RT30xx UCHAR OUI_WPA_WEP40[4] = {0x00, 0x50, 0xF2, 0x01}; +#endif UCHAR OUI_WPA_TKIP[4] = {0x00, 0x50, 0xF2, 0x02}; UCHAR OUI_WPA_CCMP[4] = {0x00, 0x50, 0xF2, 0x04}; +#ifndef RT30xx UCHAR OUI_WPA_WEP104[4] = {0x00, 0x50, 0xF2, 0x05}; +#endif UCHAR OUI_WPA_8021X_AKM[4] = {0x00, 0x50, 0xF2, 0x01}; UCHAR OUI_WPA_PSK_AKM[4] = {0x00, 0x50, 0xF2, 0x02}; // WPA2 OUI @@ -51,7 +55,9 @@ UCHAR OUI_WPA2_TKIP[4] = {0x00, 0x0F, 0xAC, 0x02}; UCHAR OUI_WPA2_CCMP[4] = {0x00, 0x0F, 0xAC, 0x04}; UCHAR OUI_WPA2_8021X_AKM[4] = {0x00, 0x0F, 0xAC, 0x01}; UCHAR OUI_WPA2_PSK_AKM[4] = {0x00, 0x0F, 0xAC, 0x02}; +#ifndef RT30xx UCHAR OUI_WPA2_WEP104[4] = {0x00, 0x0F, 0xAC, 0x05}; +#endif // MSA OUI UCHAR OUI_MSA_8021X_AKM[4] = {0x00, 0x0F, 0xAC, 0x05}; // Not yet final - IEEE 802.11s-D1.06 UCHAR OUI_MSA_PSK_AKM[4] = {0x00, 0x0F, 0xAC, 0x06}; // Not yet final - IEEE 802.11s-D1.06 @@ -370,7 +376,7 @@ static VOID RTMPInsertRsnIeCipher( break; } -#ifdef CONFIG_STA_SUPPORT +#ifndef RT30xx if ((pAd->OpMode == OPMODE_STA) && (pAd->StaCfg.GroupCipher != Ndis802_11Encryption2Enabled) && (pAd->StaCfg.GroupCipher != Ndis802_11Encryption3Enabled)) @@ -386,8 +392,7 @@ static VOID RTMPInsertRsnIeCipher( break; } } -#endif // CONFIG_STA_SUPPORT // - +#endif // swap for big-endian platform pRsnie_cipher->version = cpu2le16(pRsnie_cipher->version); pRsnie_cipher->ucount = cpu2le16(pRsnie_cipher->ucount); @@ -448,7 +453,7 @@ static VOID RTMPInsertRsnIeCipher( break; } -#ifdef CONFIG_STA_SUPPORT +#ifndef RT30xx if ((pAd->OpMode == OPMODE_STA) && (pAd->StaCfg.GroupCipher != Ndis802_11Encryption2Enabled) && (pAd->StaCfg.GroupCipher != Ndis802_11Encryption3Enabled)) @@ -464,8 +469,7 @@ static VOID RTMPInsertRsnIeCipher( break; } } -#endif // CONFIG_STA_SUPPORT // - +#endif // swap for big-endian platform pRsnie_cipher->version = cpu2le16(pRsnie_cipher->version); pRsnie_cipher->ucount = cpu2le16(pRsnie_cipher->ucount); @@ -621,23 +625,19 @@ VOID RTMPMakeRSNIE( UCHAR PrimaryRsnie; BOOLEAN bMixCipher = FALSE; // indicate the pairwise and group cipher are different UCHAR p_offset; - WPA_MIX_PAIR_CIPHER FlexibleCipher = MIX_CIPHER_NOTUSE; // it provide the more flexible cipher combination in WPA-WPA2 and TKIPAES mode + WPA_MIX_PAIR_CIPHER FlexibleCipher = WPA_TKIPAES_WPA2_TKIPAES; // it provide the more flexible cipher combination in WPA-WPA2 and TKIPAES mode rsnielen_cur_p = NULL; rsnielen_ex_cur_p = NULL; { -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { -#ifdef WPA_SUPPLICANT_SUPPORT if (pAd->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_DISABLE) { if (AuthMode < Ndis802_11AuthModeWPA) return; } else -#endif // WPA_SUPPLICANT_SUPPORT // { // Support WPAPSK or WPA2PSK in STA-Infra mode // Support WPANone in STA-Adhoc mode @@ -660,7 +660,6 @@ VOID RTMPMakeRSNIE( bMixCipher = pAd->StaCfg.bMixCipher; } -#endif // CONFIG_STA_SUPPORT // } // indicate primary RSNIE as WPA or WPA2 @@ -1131,11 +1130,6 @@ BOOLEAN RTMPParseEapolKeyData( return FALSE; } - -#ifdef CONFIG_STA_SUPPORT - // Todo -#endif // CONFIG_STA_SUPPORT // - return TRUE; } diff --git a/drivers/staging/rt2860/common/dfs.c b/drivers/staging/rt2860/common/dfs.c index b09bba5cb206..23330f2661d9 100644 --- a/drivers/staging/rt2860/common/dfs.c +++ b/drivers/staging/rt2860/common/dfs.c @@ -80,18 +80,6 @@ VOID BbpRadarDetectionStart( RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, 124, 0x28); RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, 125, 0xff); -#if 0 - // toggle Rx enable bit for radar detection. - // it's Andy's recommand. - { - UINT32 Value; - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value |= (0x1 << 3); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - Value &= ~(0x1 << 3); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - } -#endif RadarPeriod = ((UINT)RdIdleTimeTable[pAd->CommonCfg.RadarDetect.RDDurRegion][0] + (UINT)pAd->CommonCfg.RadarDetect.DfsSessionTime) < 250 ? (RdIdleTimeTable[pAd->CommonCfg.RadarDetect.RDDurRegion][0] + pAd->CommonCfg.RadarDetect.DfsSessionTime) : 250; @@ -314,15 +302,6 @@ ULONG RTMPReadRadarDuration( { ULONG result = 0; -#ifdef DFS_SUPPORT - UINT8 duration1 = 0, duration2 = 0, duration3 = 0; - - BBP_IO_READ8_BY_REG_ID(pAd, BBP_R116, &duration1); - BBP_IO_READ8_BY_REG_ID(pAd, BBP_R117, &duration2); - BBP_IO_READ8_BY_REG_ID(pAd, BBP_R118, &duration3); - result = (duration1 << 16) + (duration2 << 8) + duration3; -#endif // DFS_SUPPORT // - return result; } diff --git a/drivers/staging/rt2860/common/eeprom.c b/drivers/staging/rt2860/common/eeprom.c index bed2d666629c..9729323baca5 100644 --- a/drivers/staging/rt2860/common/eeprom.c +++ b/drivers/staging/rt2860/common/eeprom.c @@ -73,12 +73,16 @@ USHORT ShiftInBits( RaiseClock(pAd, &x); RTMP_IO_READ32(pAd, E2PROM_CSR, &x); - +#ifdef RT30xx + LowerClock(pAd, &x); //prevent read failed +#endif x &= ~(EEDI); if(x & EEDO) data |= 1; +#ifndef RT30xx LowerClock(pAd, &x); +#endif } return data; @@ -181,6 +185,15 @@ USHORT RTMP_EEPROM_READ16( UINT32 x; USHORT data; +#ifdef RT30xx + if (pAd->NicConfig2.field.AntDiversity) + { + pAd->EepromAccess = TRUE; + } +//2008/09/11:KH add to support efuse<-- +//2008/09/11:KH add to support efuse--> +{ +#endif Offset /= 2; // reset bits and set EECS RTMP_IO_READ32(pAd, E2PROM_CSR, &x); @@ -188,9 +201,17 @@ USHORT RTMP_EEPROM_READ16( x |= EECS; RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); +#ifdef RT30xx + // patch can not access e-Fuse issue + if (!IS_RT3090(pAd)) + { +#endif // kick a pulse RaiseClock(pAd, &x); LowerClock(pAd, &x); +#ifdef RT30xx + } +#endif // output the read_opcode and register number in that order ShiftOutBits(pAd, EEPROM_READ_OPCODE, 3); @@ -201,6 +222,17 @@ USHORT RTMP_EEPROM_READ16( EEpromCleanup(pAd); +#ifdef RT30xx + // Antenna and EEPROM access are both using EESK pin, + // Therefor we should avoid accessing EESK at the same time + // Then restore antenna after EEPROM access + if ((pAd->NicConfig2.field.AntDiversity) || (pAd->RfIcType == RFIC_3020)) + { + pAd->EepromAccess = FALSE; + AsicSetRxAnt(pAd, pAd->RxAnt.Pair1PrimaryRxAnt); + } +} +#endif return data; } //ReadEEprom @@ -211,6 +243,15 @@ VOID RTMP_EEPROM_WRITE16( { UINT32 x; +#ifdef RT30xx + if (pAd->NicConfig2.field.AntDiversity) + { + pAd->EepromAccess = TRUE; + } + //2008/09/11:KH add to support efuse<-- +//2008/09/11:KH add to support efuse--> + { +#endif Offset /= 2; EWEN(pAd); @@ -221,9 +262,17 @@ VOID RTMP_EEPROM_WRITE16( x |= EECS; RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); +#ifdef RT30xx + // patch can not access e-Fuse issue + if (!IS_RT3090(pAd)) + { +#endif // kick a pulse RaiseClock(pAd, &x); LowerClock(pAd, &x); +#ifdef RT30xx + } +#endif // output the read_opcode ,register number and data in that order ShiftOutBits(pAd, EEPROM_WRITE_OPCODE, 3); @@ -240,5 +289,1222 @@ VOID RTMP_EEPROM_WRITE16( EWDS(pAd); EEpromCleanup(pAd); + +#ifdef RT30xx + // Antenna and EEPROM access are both using EESK pin, + // Therefor we should avoid accessing EESK at the same time + // Then restore antenna after EEPROM access + if ((pAd->NicConfig2.field.AntDiversity) || (pAd->RfIcType == RFIC_3020)) + { + pAd->EepromAccess = FALSE; + AsicSetRxAnt(pAd, pAd->RxAnt.Pair1PrimaryRxAnt); + } +} +#endif } +//2008/09/11:KH add to support efuse<-- +#ifdef RT30xx +/* + ======================================================================== + + Routine Description: + + Arguments: + + Return Value: + + IRQL = + + Note: + + ======================================================================== +*/ +UCHAR eFuseReadRegisters( + IN PRTMP_ADAPTER pAd, + IN USHORT Offset, + IN USHORT Length, + OUT USHORT* pData) +{ + EFUSE_CTRL_STRUC eFuseCtrlStruc; + int i; + USHORT efuseDataOffset; + UINT32 data; + + RTMP_IO_READ32(pAd, EFUSE_CTRL, (PUINT32) &eFuseCtrlStruc); + + //Step0. Write 10-bit of address to EFSROM_AIN (0x580, bit25:bit16). The address must be 16-byte alignment. + //Use the eeprom logical address and covert to address to block number + eFuseCtrlStruc.field.EFSROM_AIN = Offset & 0xfff0; + + //Step1. Write EFSROM_MODE (0x580, bit7:bit6) to 0. + eFuseCtrlStruc.field.EFSROM_MODE = 0; + + //Step2. Write EFSROM_KICK (0x580, bit30) to 1 to kick-off physical read procedure. + eFuseCtrlStruc.field.EFSROM_KICK = 1; + + NdisMoveMemory(&data, &eFuseCtrlStruc, 4); + RTMP_IO_WRITE32(pAd, EFUSE_CTRL, data); + + //Step3. Polling EFSROM_KICK(0x580, bit30) until it become 0 again. + i = 0; + while(i < 100) + { + //rtmp.HwMemoryReadDword(EFUSE_CTRL, (DWORD *) &eFuseCtrlStruc, 4); + RTMP_IO_READ32(pAd, EFUSE_CTRL, (PUINT32) &eFuseCtrlStruc); + if(eFuseCtrlStruc.field.EFSROM_KICK == 0) + { + break; + } + RTMPusecDelay(2); + i++; + } + + //if EFSROM_AOUT is not found in physical address, write 0xffff + if (eFuseCtrlStruc.field.EFSROM_AOUT == 0x3f) + { + for(i=0; i> (8*(Offset & 0x3)); + + NdisMoveMemory(pData, &data, Length); + } + + return (UCHAR) eFuseCtrlStruc.field.EFSROM_AOUT; + +} + +/* + ======================================================================== + + Routine Description: + + Arguments: + + Return Value: + + IRQL = + + Note: + + ======================================================================== +*/ +VOID eFusePhysicalReadRegisters( + IN PRTMP_ADAPTER pAd, + IN USHORT Offset, + IN USHORT Length, + OUT USHORT* pData) +{ + EFUSE_CTRL_STRUC eFuseCtrlStruc; + int i; + USHORT efuseDataOffset; + UINT32 data; + + RTMP_IO_READ32(pAd, EFUSE_CTRL, (PUINT32) &eFuseCtrlStruc); + + //Step0. Write 10-bit of address to EFSROM_AIN (0x580, bit25:bit16). The address must be 16-byte alignment. + eFuseCtrlStruc.field.EFSROM_AIN = Offset & 0xfff0; + + //Step1. Write EFSROM_MODE (0x580, bit7:bit6) to 1. + //Read in physical view + eFuseCtrlStruc.field.EFSROM_MODE = 1; + + //Step2. Write EFSROM_KICK (0x580, bit30) to 1 to kick-off physical read procedure. + eFuseCtrlStruc.field.EFSROM_KICK = 1; + + NdisMoveMemory(&data, &eFuseCtrlStruc, 4); + RTMP_IO_WRITE32(pAd, EFUSE_CTRL, data); + + //Step3. Polling EFSROM_KICK(0x580, bit30) until it become 0 again. + i = 0; + while(i < 100) + { + RTMP_IO_READ32(pAd, EFUSE_CTRL, (PUINT32) &eFuseCtrlStruc); + if(eFuseCtrlStruc.field.EFSROM_KICK == 0) + break; + RTMPusecDelay(2); + i++; + } + + //Step4. Read 16-byte of data from EFUSE_DATA0-3 (0x59C-0x590) + //Because the size of each EFUSE_DATA is 4 Bytes, the size of address of each is 2 bits. + //The previous 2 bits is the EFUSE_DATA number, the last 2 bits is used to decide which bytes + //Decide which EFUSE_DATA to read + //590:F E D C + //594:B A 9 8 + //598:7 6 5 4 + //59C:3 2 1 0 + efuseDataOffset = EFUSE_DATA3 - (Offset & 0xC) ; + + RTMP_IO_READ32(pAd, efuseDataOffset, &data); + + data = data >> (8*(Offset & 0x3)); + + NdisMoveMemory(pData, &data, Length); + +} + +/* + ======================================================================== + + Routine Description: + + Arguments: + + Return Value: + + IRQL = + + Note: + + ======================================================================== +*/ +VOID eFuseReadPhysical( + IN PRTMP_ADAPTER pAd, + IN PUSHORT lpInBuffer, + IN ULONG nInBufferSize, + OUT PUSHORT lpOutBuffer, + IN ULONG nOutBufferSize +) +{ + USHORT* pInBuf = (USHORT*)lpInBuffer; + USHORT* pOutBuf = (USHORT*)lpOutBuffer; + + USHORT Offset = pInBuf[0]; //addr + USHORT Length = pInBuf[1]; //length + int i; + + for(i=0; i> 2; + data = pData[0] & 0xffff; + //The offset should be 0x***10 or 0x***00 + if((Offset % 4) != 0) + { + eFuseDataBuffer[efuseDataOffset] = (eFuseDataBuffer[efuseDataOffset] & 0xffff) | (data << 16); + } + else + { + eFuseDataBuffer[efuseDataOffset] = (eFuseDataBuffer[efuseDataOffset] & 0xffff0000) | data; + } + + efuseDataOffset = EFUSE_DATA3; + for(i=0; i< 4; i++) + { + RTMP_IO_WRITE32(pAd, efuseDataOffset, eFuseDataBuffer[i]); + efuseDataOffset -= 4; + } + ///////////////////////////////////////////////////////////////// + + //Step1. Write 10-bit of address to EFSROM_AIN (0x580, bit25:bit16). The address must be 16-byte alignment. + eFuseCtrlStruc.field.EFSROM_AIN = Offset & 0xfff0; + + //Step2. Write EFSROM_MODE (0x580, bit7:bit6) to 3. + eFuseCtrlStruc.field.EFSROM_MODE = 3; + + //Step3. Write EFSROM_KICK (0x580, bit30) to 1 to kick-off physical write procedure. + eFuseCtrlStruc.field.EFSROM_KICK = 1; + + NdisMoveMemory(&data, &eFuseCtrlStruc, 4); + RTMP_IO_WRITE32(pAd, EFUSE_CTRL, data); + + //Step4. Polling EFSROM_KICK(0x580, bit30) until it become 0 again. It��s done. + i = 0; + while(i < 100) + { + RTMP_IO_READ32(pAd, EFUSE_CTRL, (PUINT32) &eFuseCtrlStruc); + + if(eFuseCtrlStruc.field.EFSROM_KICK == 0) + break; + + RTMPusecDelay(2); + i++; + } +} + +/* + ======================================================================== + + Routine Description: + + Arguments: + + Return Value: + + IRQL = + + Note: + + ======================================================================== +*/ +NTSTATUS eFuseWriteRegisters( + IN PRTMP_ADAPTER pAd, + IN USHORT Offset, + IN USHORT Length, + IN USHORT* pData) +{ + USHORT i; + USHORT eFuseData; + USHORT LogicalAddress, BlkNum = 0xffff; + UCHAR EFSROM_AOUT; + + USHORT addr,tmpaddr, InBuf[3], tmpOffset; + USHORT buffer[8]; + BOOLEAN bWriteSuccess = TRUE; + + DBGPRINT(RT_DEBUG_TRACE, ("eFuseWriteRegisters Offset=%x, pData=%x\n", Offset, *pData)); + + //Step 0. find the entry in the mapping table + //The address of EEPROM is 2-bytes alignment. + //The last bit is used for alignment, so it must be 0. + tmpOffset = Offset & 0xfffe; + EFSROM_AOUT = eFuseReadRegisters(pAd, tmpOffset, 2, &eFuseData); + + if( EFSROM_AOUT == 0x3f) + { //find available logical address pointer + //the logical address does not exist, find an empty one + //from the first address of block 45=16*45=0x2d0 to the last address of block 47 + //==>48*16-3(reserved)=2FC + for (i=EFUSE_USAGE_MAP_START; i<=EFUSE_USAGE_MAP_END; i+=2) + { + //Retrive the logical block nubmer form each logical address pointer + //It will access two logical address pointer each time. + eFusePhysicalReadRegisters(pAd, i, 2, &LogicalAddress); + if( (LogicalAddress & 0xff) == 0) + {//Not used logical address pointer + BlkNum = i-EFUSE_USAGE_MAP_START; + break; + } + else if(( (LogicalAddress >> 8) & 0xff) == 0) + {//Not used logical address pointer + if (i != EFUSE_USAGE_MAP_END) + { + BlkNum = i-EFUSE_USAGE_MAP_START+1; + } + break; + } + } + } + else + { + BlkNum = EFSROM_AOUT; + } + + DBGPRINT(RT_DEBUG_TRACE, ("eFuseWriteRegisters BlkNum = %d \n", BlkNum)); + + if(BlkNum == 0xffff) + { + DBGPRINT(RT_DEBUG_TRACE, ("eFuseWriteRegisters: out of free E-fuse space!!!\n")); + return FALSE; + } + + //Step 1. Save data of this block which is pointed by the avaible logical address pointer + // read and save the original block data + for(i =0; i<8; i++) + { + addr = BlkNum * 0x10 ; + + InBuf[0] = addr+2*i; + InBuf[1] = 2; + InBuf[2] = 0x0; + + eFuseReadPhysical(pAd, &InBuf[0], 4, &InBuf[2], 2); + + buffer[i] = InBuf[2]; + } + + //Step 2. Update the data in buffer, and write the data to Efuse + buffer[ (Offset >> 1) % 8] = pData[0]; + + do + { + //Step 3. Write the data to Efuse + if(!bWriteSuccess) + { + for(i =0; i<8; i++) + { + addr = BlkNum * 0x10 ; + + InBuf[0] = addr+2*i; + InBuf[1] = 2; + InBuf[2] = buffer[i]; + + eFuseWritePhysical(pAd, &InBuf[0], 6, NULL, 2); + } + } + else + { + addr = BlkNum * 0x10 ; + + InBuf[0] = addr+(Offset % 16); + InBuf[1] = 2; + InBuf[2] = pData[0]; + + eFuseWritePhysical(pAd, &InBuf[0], 6, NULL, 2); + } + + //Step 4. Write mapping table + addr = EFUSE_USAGE_MAP_START+BlkNum; + + tmpaddr = addr; + + if(addr % 2 != 0) + addr = addr -1; + InBuf[0] = addr; + InBuf[1] = 2; + + //convert the address from 10 to 8 bit ( bit7, 6 = parity and bit5 ~ 0 = bit9~4), and write to logical map entry + tmpOffset = Offset; + tmpOffset >>= 4; + tmpOffset |= ((~((tmpOffset & 0x01) ^ ( tmpOffset >> 1 & 0x01) ^ (tmpOffset >> 2 & 0x01) ^ (tmpOffset >> 3 & 0x01))) << 6) & 0x40; + tmpOffset |= ((~( (tmpOffset >> 2 & 0x01) ^ (tmpOffset >> 3 & 0x01) ^ (tmpOffset >> 4 & 0x01) ^ ( tmpOffset >> 5 & 0x01))) << 7) & 0x80; + + // write the logical address + if(tmpaddr%2 != 0) + InBuf[2] = tmpOffset<<8; + else + InBuf[2] = tmpOffset; + + eFuseWritePhysical(pAd,&InBuf[0], 6, NULL, 0); + + //Step 5. Compare data if not the same, invalidate the mapping entry, then re-write the data until E-fuse is exhausted + bWriteSuccess = TRUE; + for(i =0; i<8; i++) + { + addr = BlkNum * 0x10 ; + + InBuf[0] = addr+2*i; + InBuf[1] = 2; + InBuf[2] = 0x0; + + eFuseReadPhysical(pAd, &InBuf[0], 4, &InBuf[2], 2); + + if(buffer[i] != InBuf[2]) + { + bWriteSuccess = FALSE; + break; + } + } + + //Step 6. invlidate mapping entry and find a free mapping entry if not succeed + if (!bWriteSuccess) + { + DBGPRINT(RT_DEBUG_TRACE, ("Not bWriteSuccess BlkNum = %d\n", BlkNum)); + + // the offset of current mapping entry + addr = EFUSE_USAGE_MAP_START+BlkNum; + + //find a new mapping entry + BlkNum = 0xffff; + for (i=EFUSE_USAGE_MAP_START; i<=EFUSE_USAGE_MAP_END; i+=2) + { + eFusePhysicalReadRegisters(pAd, i, 2, &LogicalAddress); + if( (LogicalAddress & 0xff) == 0) + { + BlkNum = i-EFUSE_USAGE_MAP_START; + break; + } + else if(( (LogicalAddress >> 8) & 0xff) == 0) + { + if (i != EFUSE_USAGE_MAP_END) + { + BlkNum = i+1-EFUSE_USAGE_MAP_START; + } + break; + } + } + DBGPRINT(RT_DEBUG_TRACE, ("Not bWriteSuccess new BlkNum = %d\n", BlkNum)); + if(BlkNum == 0xffff) + { + DBGPRINT(RT_DEBUG_TRACE, ("eFuseWriteRegisters: out of free E-fuse space!!!\n")); + return FALSE; + } + + //invalidate the original mapping entry if new entry is not found + tmpaddr = addr; + + if(addr % 2 != 0) + addr = addr -1; + InBuf[0] = addr; + InBuf[1] = 2; + + eFuseReadPhysical(pAd, &InBuf[0], 4, &InBuf[2], 2); + + // write the logical address + if(tmpaddr%2 != 0) + { + // Invalidate the high byte + for (i=8; i<15; i++) + { + if( ( (InBuf[2] >> i) & 0x01) == 0) + { + InBuf[2] |= (0x1 <> i) & 0x01) == 0) + { + InBuf[2] |= (0x1 <bUseEfuse) + return FALSE; + for (i = EFUSE_USAGE_MAP_START; i <= EFUSE_USAGE_MAP_END; i+=2) + { + eFusePhysicalReadRegisters(pAd, i, 2, &LogicalAddress); + if( (LogicalAddress & 0xff) == 0) + { + efusefreenum= (UCHAR) (EFUSE_USAGE_MAP_END-i+1); + break; + } + else if(( (LogicalAddress >> 8) & 0xff) == 0) + { + efusefreenum = (UCHAR) (EFUSE_USAGE_MAP_END-i); + break; + } + + if(i == EFUSE_USAGE_MAP_END) + efusefreenum = 0; + } + printk("efuseFreeNumber is %d\n",efusefreenum); + return TRUE; +} +INT set_eFusedump_Proc( + IN PRTMP_ADAPTER pAd, + IN PUCHAR arg) +{ +USHORT InBuf[3]; + INT i=0; + if(!pAd->bUseEfuse) + return FALSE; + for(i =0; i0) + { + + NdisMoveMemory(src, arg, strlen(arg)); + } + + else + { + + NdisMoveMemory(src, "RT30xxEEPROM.bin", BinFileSize); + } + + DBGPRINT(RT_DEBUG_TRACE, ("FileName=%s\n",src)); + buffer = kmalloc(MAX_EEPROM_BIN_FILE_SIZE, MEM_ALLOC_FLAG); + + if(buffer == NULL) + { + kfree(src); + return FALSE; +} + PDATA=kmalloc(sizeof(USHORT)*8,MEM_ALLOC_FLAG); + + if(PDATA==NULL) + { + kfree(src); + + kfree(buffer); + return FALSE; + } + /* Don't change to uid 0, let the file be opened as the "normal" user */ +#if 0 + orgfsuid = current->fsuid; + orgfsgid = current->fsgid; + current->fsuid=current->fsgid = 0; +#endif + orgfs = get_fs(); + set_fs(KERNEL_DS); + + if (src && *src) + { + srcf = filp_open(src, O_RDONLY, 0); + if (IS_ERR(srcf)) + { + DBGPRINT(RT_DEBUG_ERROR, ("--> Error %ld opening %s\n", -PTR_ERR(srcf),src)); + return FALSE; + } + else + { + // The object must have a read method + if (srcf->f_op && srcf->f_op->read) + { + memset(buffer, 0x00, MAX_EEPROM_BIN_FILE_SIZE); + while(srcf->f_op->read(srcf, &buffer[i], 1, &srcf->f_pos)==1) + { + DBGPRINT(RT_DEBUG_TRACE, ("%02X ",buffer[i])); + if((i+1)%8==0) + DBGPRINT(RT_DEBUG_TRACE, ("\n")); + i++; + if(i>=MAX_EEPROM_BIN_FILE_SIZE) + { + DBGPRINT(RT_DEBUG_ERROR, ("--> Error %ld reading %s, The file is too large[1024]\n", -PTR_ERR(srcf),src)); + kfree(PDATA); + kfree(buffer); + kfree(src); + return FALSE; + } + } + } + else + { + DBGPRINT(RT_DEBUG_ERROR, ("--> Error!! System doest not support read function\n")); + kfree(PDATA); + kfree(buffer); + kfree(src); + return FALSE; + } + } + + + } + else + { + DBGPRINT(RT_DEBUG_ERROR, ("--> Error src or srcf is null\n")); + kfree(PDATA); + kfree(buffer); + return FALSE; + + } + + + retval=filp_close(srcf,NULL); + + if (retval) + { + DBGPRINT(RT_DEBUG_TRACE, ("--> Error %d closing %s\n", -retval, src)); + } + set_fs(orgfs); +#if 0 + current->fsuid = orgfsuid; + current->fsgid = orgfsgid; +#endif + for(j=0;j48*16-3(reserved)=2FC + bAllocateNewBlk=TRUE; + for (i=EFUSE_USAGE_MAP_START; i<=EFUSE_USAGE_MAP_END; i+=2) + { + //Retrive the logical block nubmer form each logical address pointer + //It will access two logical address pointer each time. + eFusePhysicalReadRegisters(pAd, i, 2, &LogicalAddress); + if( (LogicalAddress & 0xff) == 0) + {//Not used logical address pointer + BlkNum = i-EFUSE_USAGE_MAP_START; + break; + } + else if(( (LogicalAddress >> 8) & 0xff) == 0) + {//Not used logical address pointer + if (i != EFUSE_USAGE_MAP_END) + { + BlkNum = i-EFUSE_USAGE_MAP_START+1; + } + break; + } + } + } + else + { + bAllocateNewBlk=FALSE; + BlkNum = EFSROM_AOUT; + } + + DBGPRINT(RT_DEBUG_TRACE, ("eFuseWriteRegisters BlkNum = %d \n", BlkNum)); + + if(BlkNum == 0xffff) + { + DBGPRINT(RT_DEBUG_TRACE, ("eFuseWriteRegisters: out of free E-fuse space!!!\n")); + return FALSE; + } + //Step 1.1.0 + //If the block is not existing in mapping table, create one + //and write down the 16-bytes data to the new block + if(bAllocateNewBlk) + { + DBGPRINT(RT_DEBUG_TRACE, ("Allocate New Blk\n")); + efuseDataOffset = EFUSE_DATA3; + for(i=0; i< 4; i++) + { + DBGPRINT(RT_DEBUG_TRACE, ("Allocate New Blk, Data%d=%04x%04x\n",3-i,pData[2*i+1],pData[2*i])); + tempbuffer=((pData[2*i+1]<<16)&0xffff0000)|pData[2*i]; + + + RTMP_IO_WRITE32(pAd, efuseDataOffset,tempbuffer); + efuseDataOffset -= 4; + + } + ///////////////////////////////////////////////////////////////// + + //Step1.1.1. Write 10-bit of address to EFSROM_AIN (0x580, bit25:bit16). The address must be 16-byte alignment. + eFuseCtrlStruc.field.EFSROM_AIN = BlkNum* 0x10 ; + + //Step1.1.2. Write EFSROM_MODE (0x580, bit7:bit6) to 3. + eFuseCtrlStruc.field.EFSROM_MODE = 3; + + //Step1.1.3. Write EFSROM_KICK (0x580, bit30) to 1 to kick-off physical write procedure. + eFuseCtrlStruc.field.EFSROM_KICK = 1; + + NdisMoveMemory(&data, &eFuseCtrlStruc, 4); + + RTMP_IO_WRITE32(pAd, EFUSE_CTRL, data); + + //Step1.1.4. Polling EFSROM_KICK(0x580, bit30) until it become 0 again. It��s done. + i = 0; + while(i < 100) + { + RTMP_IO_READ32(pAd, EFUSE_CTRL, (PUINT32) &eFuseCtrlStruc); + + if(eFuseCtrlStruc.field.EFSROM_KICK == 0) + break; + + RTMPusecDelay(2); + i++; + } + + } + else + { //Step1.2. + //If the same logical number is existing, check if the writting data and the data + //saving in this block are the same. + ///////////////////////////////////////////////////////////////// + //read current values of 16-byte block + RTMP_IO_READ32(pAd, EFUSE_CTRL, (PUINT32) &eFuseCtrlStruc); + + //Step1.2.0. Write 10-bit of address to EFSROM_AIN (0x580, bit25:bit16). The address must be 16-byte alignment. + eFuseCtrlStruc.field.EFSROM_AIN = Offset & 0xfff0; + + //Step1.2.1. Write EFSROM_MODE (0x580, bit7:bit6) to 1. + eFuseCtrlStruc.field.EFSROM_MODE = 0; + + //Step1.2.2. Write EFSROM_KICK (0x580, bit30) to 1 to kick-off physical read procedure. + eFuseCtrlStruc.field.EFSROM_KICK = 1; + + NdisMoveMemory(&data, &eFuseCtrlStruc, 4); + RTMP_IO_WRITE32(pAd, EFUSE_CTRL, data); + + //Step1.2.3. Polling EFSROM_KICK(0x580, bit30) until it become 0 again. + i = 0; + while(i < 100) + { + RTMP_IO_READ32(pAd, EFUSE_CTRL, (PUINT32) &eFuseCtrlStruc); + + if(eFuseCtrlStruc.field.EFSROM_KICK == 0) + break; + RTMPusecDelay(2); + i++; + } + + //Step1.2.4. Read 16-byte of data from EFUSE_DATA0-3 (0x59C-0x590) + efuseDataOffset = EFUSE_DATA3; + for(i=0; i< 4; i++) + { + RTMP_IO_READ32(pAd, efuseDataOffset, (PUINT32) &buffer[i]); + efuseDataOffset -= 4; + } + //Step1.2.5. Check if the data of efuse and the writing data are the same. + for(i =0; i<4; i++) + { + tempbuffer=((pData[2*i+1]<<16)&0xffff0000)|pData[2*i]; + DBGPRINT(RT_DEBUG_TRACE, ("buffer[%d]=%x,pData[%d]=%x,pData[%d]=%x,tempbuffer=%x\n",i,buffer[i],2*i,pData[2*i],2*i+1,pData[2*i+1],tempbuffer)); + + if(((buffer[i]&0xffff0000)==(pData[2*i+1]<<16))&&((buffer[i]&0xffff)==pData[2*i])) + bNotWrite&=TRUE; + else + { + bNotWrite&=FALSE; + break; + } + } + if(!bNotWrite) + { + printk("The data is not the same\n"); + + for(i =0; i<8; i++) + { + addr = BlkNum * 0x10 ; + + InBuf[0] = addr+2*i; + InBuf[1] = 2; + InBuf[2] = pData[i]; + + eFuseWritePhysical(pAd, &InBuf[0], 6, NULL, 2); + } + + } + else + return TRUE; + } + + + + //Step 2. Write mapping table + addr = EFUSE_USAGE_MAP_START+BlkNum; + + tmpaddr = addr; + + if(addr % 2 != 0) + addr = addr -1; + InBuf[0] = addr; + InBuf[1] = 2; + + //convert the address from 10 to 8 bit ( bit7, 6 = parity and bit5 ~ 0 = bit9~4), and write to logical map entry + tmpOffset = Offset; + tmpOffset >>= 4; + tmpOffset |= ((~((tmpOffset & 0x01) ^ ( tmpOffset >> 1 & 0x01) ^ (tmpOffset >> 2 & 0x01) ^ (tmpOffset >> 3 & 0x01))) << 6) & 0x40; + tmpOffset |= ((~( (tmpOffset >> 2 & 0x01) ^ (tmpOffset >> 3 & 0x01) ^ (tmpOffset >> 4 & 0x01) ^ ( tmpOffset >> 5 & 0x01))) << 7) & 0x80; + + // write the logical address + if(tmpaddr%2 != 0) + InBuf[2] = tmpOffset<<8; + else + InBuf[2] = tmpOffset; + + eFuseWritePhysical(pAd,&InBuf[0], 6, NULL, 0); + + //Step 3. Compare data if not the same, invalidate the mapping entry, then re-write the data until E-fuse is exhausted + bWriteSuccess = TRUE; + for(i =0; i<8; i++) + { + addr = BlkNum * 0x10 ; + + InBuf[0] = addr+2*i; + InBuf[1] = 2; + InBuf[2] = 0x0; + + eFuseReadPhysical(pAd, &InBuf[0], 4, &InBuf[2], 2); + DBGPRINT(RT_DEBUG_TRACE, ("addr=%x, buffer[i]=%x,InBuf[2]=%x\n",InBuf[0],pData[i],InBuf[2])); + if(pData[i] != InBuf[2]) + { + bWriteSuccess = FALSE; + break; + } + } + + //Step 4. invlidate mapping entry and find a free mapping entry if not succeed + + if (!bWriteSuccess&&Loop<2) + { + DBGPRINT(RT_DEBUG_TRACE, ("eFuseWriteRegistersFromBin::Not bWriteSuccess BlkNum = %d\n", BlkNum)); + + // the offset of current mapping entry + addr = EFUSE_USAGE_MAP_START+BlkNum; + + //find a new mapping entry + BlkNum = 0xffff; + for (i=EFUSE_USAGE_MAP_START; i<=EFUSE_USAGE_MAP_END; i+=2) + { + eFusePhysicalReadRegisters(pAd, i, 2, &LogicalAddress); + if( (LogicalAddress & 0xff) == 0) + { + BlkNum = i-EFUSE_USAGE_MAP_START; + break; + } + else if(( (LogicalAddress >> 8) & 0xff) == 0) + { + if (i != EFUSE_USAGE_MAP_END) + { + BlkNum = i+1-EFUSE_USAGE_MAP_START; + } + break; + } + } + DBGPRINT(RT_DEBUG_TRACE, ("eFuseWriteRegistersFromBin::Not bWriteSuccess new BlkNum = %d\n", BlkNum)); + if(BlkNum == 0xffff) + { + DBGPRINT(RT_DEBUG_TRACE, ("eFuseWriteRegistersFromBin: out of free E-fuse space!!!\n")); + return FALSE; + } + + //invalidate the original mapping entry if new entry is not found + tmpaddr = addr; + + if(addr % 2 != 0) + addr = addr -1; + InBuf[0] = addr; + InBuf[1] = 2; + + eFuseReadPhysical(pAd, &InBuf[0], 4, &InBuf[2], 2); + + // write the logical address + if(tmpaddr%2 != 0) + { + // Invalidate the high byte + for (i=8; i<15; i++) + { + if( ( (InBuf[2] >> i) & 0x01) == 0) + { + InBuf[2] |= (0x1 <> i) & 0x01) == 0) + { + InBuf[2] |= (0x1 < diff --git a/drivers/staging/rt2860/common/md5.c b/drivers/staging/rt2860/common/md5.c index 774776b4b8c3..ad883ca2ffc8 100644 --- a/drivers/staging/rt2860/common/md5.c +++ b/drivers/staging/rt2860/common/md5.c @@ -131,19 +131,7 @@ void hmac_md5(u8 *key, size_t key_len, u8 *data, size_t data_len, u8 *mac) MD5Final(mac, &context); /* finish up 2nd pass */ } -#ifndef RT_BIG_ENDIAN #define byteReverse(buf, len) /* Nothing */ -#else -void byteReverse(unsigned char *buf, unsigned longs); -void byteReverse(unsigned char *buf, unsigned longs) -{ - do { - *(UINT32 *)buf = SWAP32(*(UINT32 *)buf); - buf += 4; - } while (--longs); -} -#endif - /* ========================== MD5 implementation =========================== */ // four base functions for MD5 diff --git a/drivers/staging/rt2860/common/mlme.c b/drivers/staging/rt2860/common/mlme.c index c00f9ab9c46c..bb6fccbdca41 100644 --- a/drivers/staging/rt2860/common/mlme.c +++ b/drivers/staging/rt2860/common/mlme.c @@ -50,11 +50,7 @@ UCHAR Ccx2QosInfo[] = {0x00, 0x40, 0x96, 0x04}; UCHAR RALINK_OUI[] = {0x00, 0x0c, 0x43}; UCHAR BROADCOM_OUI[] = {0x00, 0x90, 0x4c}; UCHAR WPS_OUI[] = {0x00, 0x50, 0xf2, 0x04}; -#ifdef CONFIG_STA_SUPPORT -#ifdef DOT11_N_SUPPORT UCHAR PRE_N_HT_OUI[] = {0x00, 0x90, 0x4c}; -#endif // DOT11_N_SUPPORT // -#endif // CONFIG_STA_SUPPORT // UCHAR RateSwitchTable[] = { // Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) @@ -130,7 +126,6 @@ UCHAR RateSwitchTable11G[] = { 0x07, 0x10, 7, 10, 13, }; -#ifdef DOT11_N_SUPPORT UCHAR RateSwitchTable11N1S[] = { // Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) 0x09, 0x00, 0, 0, 0, // Initial used item after association @@ -287,7 +282,6 @@ UCHAR RateSwitchTable11BGN3SForABand[] = { // 3*3 0x0a, 0x20, 23, 8, 25, 0x0b, 0x22, 23, 8, 25, }; -#endif // DOT11_N_SUPPORT // PUCHAR ReasonString[] = { /* 0 */ "Reserved", @@ -334,14 +328,9 @@ USHORT RateIdTo500Kbps[] = { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108, 144, UCHAR SsidIe = IE_SSID; UCHAR SupRateIe = IE_SUPP_RATES; UCHAR ExtRateIe = IE_EXT_SUPP_RATES; -#ifdef DOT11_N_SUPPORT UCHAR HtCapIe = IE_HT_CAP; UCHAR AddHtInfoIe = IE_ADD_HT; UCHAR NewExtChanIe = IE_SECONDARY_CH_OFFSET; -#ifdef DOT11N_DRAFT3 -UCHAR ExtHtCapIe = IE_EXT_CAPABILITY; -#endif // DOT11N_DRAFT3 // -#endif // DOT11_N_SUPPORT // UCHAR ErpIe = IE_ERP; UCHAR DsIe = IE_DS_PARM; UCHAR TimIe = IE_TIM; @@ -349,6 +338,9 @@ UCHAR WpaIe = IE_WPA; UCHAR Wpa2Ie = IE_WPA2; UCHAR IbssIe = IE_IBSS_PARM; UCHAR Ccx2Ie = IE_CCX_V2; +#ifdef RT2870 +UCHAR WapiIe = IE_WAPI; +#endif extern UCHAR WPA_OUI[]; @@ -457,7 +449,13 @@ FREQUENCY_ITEM FreqItems3020[] = {13, 247, 2, 2}, {14, 248, 2, 4}, }; +#ifndef RT30xx #define NUM_OF_3020_CHNL (sizeof(FreqItems3020) / sizeof(FREQUENCY_ITEM)) +#endif +#ifdef RT30xx +//2008/07/10:KH Modified to share this variable +UCHAR NUM_OF_3020_CHNL=(sizeof(FreqItems3020) / sizeof(FREQUENCY_ITEM)); +#endif /* ========================================================================== @@ -488,8 +486,6 @@ NDIS_STATUS MlmeInit( pAd->Mlme.bRunning = FALSE; NdisAllocateSpinLock(&pAd->Mlme.TaskLock); -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { BssTableInit(&pAd->ScanTab); @@ -501,18 +497,10 @@ NDIS_STATUS MlmeInit( WpaPskStateMachineInit(pAd, &pAd->Mlme.WpaPskMachine, pAd->Mlme.WpaPskFunc); AironetStateMachineInit(pAd, &pAd->Mlme.AironetMachine, pAd->Mlme.AironetFunc); -#ifdef QOS_DLS_SUPPORT - DlsStateMachineInit(pAd, &pAd->Mlme.DlsMachine, pAd->Mlme.DlsFunc); -#endif // QOS_DLS_SUPPORT // - - // Since we are using switch/case to implement it, the init is different from the above // state machine init MlmeCntlInit(pAd, &pAd->Mlme.CntlMachine, NULL); } -#endif // CONFIG_STA_SUPPORT // - - ActionStateMachineInit(pAd, &pAd->Mlme.ActMachine, pAd->Mlme.ActFunc); @@ -525,9 +513,7 @@ NDIS_STATUS MlmeInit( // software-based RX Antenna diversity RTMPInitTimer(pAd, &pAd->Mlme.RxAntEvalTimer, GET_TIMER_FUNCTION(AsicRxAntEvalTimeout), pAd, FALSE); - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) +#ifdef RT2860 { if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE)) { @@ -536,8 +522,7 @@ NDIS_STATUS MlmeInit( RTMPInitTimer(pAd, &pAd->Mlme.RadioOnOffTimer, GET_TIMER_FUNCTION(RadioOnExec), pAd, FALSE); } } -#endif // CONFIG_STA_SUPPORT // - +#endif } while (FALSE); DBGPRINT(RT_DEBUG_TRACE, ("<-- MLME Initialize\n")); @@ -563,9 +548,6 @@ VOID MlmeHandler( IN PRTMP_ADAPTER pAd) { MLME_QUEUE_ELEM *Elem = NULL; -#ifdef APCLI_SUPPORT - SHORT apcliIfIndex; -#endif // Only accept MLME and Frame from peer side, no other (control/data) frame should // get into this state machine @@ -592,23 +574,24 @@ VOID MlmeHandler( break; } -#ifdef RALINK_ATE - if(ATE_ON(pAd)) - { - DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now in MlmeHandler\n")); - break; - } -#endif // RALINK_ATE // - //From message type, determine which state machine I should drive if (MlmeDequeue(&pAd->Mlme.Queue, &Elem)) { +#ifdef RT2870 + if (Elem->MsgType == MT2_RESET_CONF) + { + DBGPRINT_RAW(RT_DEBUG_TRACE, ("!!! reset MLME state machine !!!\n")); + MlmeRestartStateMachine(pAd); + Elem->Occupied = FALSE; + Elem->MsgLen = 0; + continue; + } +#endif // RT2870 // // if dequeue success switch (Elem->Machine) { // STA state machines -#ifdef CONFIG_STA_SUPPORT case ASSOC_STATE_MACHINE: StateMachinePerformAction(pAd, &pAd->Mlme.AssocMachine, Elem); break; @@ -627,22 +610,9 @@ VOID MlmeHandler( case WPA_PSK_STATE_MACHINE: StateMachinePerformAction(pAd, &pAd->Mlme.WpaPskMachine, Elem); break; -#ifdef LEAP_SUPPORT - case LEAP_STATE_MACHINE: - LeapMachinePerformAction(pAd, &pAd->Mlme.LeapMachine, Elem); - break; -#endif case AIRONET_STATE_MACHINE: StateMachinePerformAction(pAd, &pAd->Mlme.AironetMachine, Elem); break; - -#ifdef QOS_DLS_SUPPORT - case DLS_STATE_MACHINE: - StateMachinePerformAction(pAd, &pAd->Mlme.DlsMachine, Elem); - break; -#endif // QOS_DLS_SUPPORT // -#endif // CONFIG_STA_SUPPORT // - case ACTION_STATE_MACHINE: StateMachinePerformAction(pAd, &pAd->Mlme.ActMachine, Elem); break; @@ -687,6 +657,9 @@ VOID MlmeHalt( IN PRTMP_ADAPTER pAd) { BOOLEAN Cancelled; +#ifdef RT3070 + UINT32 TxPinCfg = 0x00050F0F; +#endif // RT3070 // DBGPRINT(RT_DEBUG_TRACE, ("==> MlmeHalt\n")); @@ -696,12 +669,7 @@ VOID MlmeHalt( AsicDisableSync(pAd); } -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { -#ifdef QOS_DLS_SUPPORT - UCHAR i; -#endif // QOS_DLS_SUPPORT // // Cancel pending timers RTMPCancelTimer(&pAd->MlmeAux.AssocTimer, &Cancelled); RTMPCancelTimer(&pAd->MlmeAux.ReassocTimer, &Cancelled); @@ -709,20 +677,14 @@ VOID MlmeHalt( RTMPCancelTimer(&pAd->MlmeAux.AuthTimer, &Cancelled); RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer, &Cancelled); RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &Cancelled); +#ifdef RT2860 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE)) { RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled); RTMPCancelTimer(&pAd->Mlme.RadioOnOffTimer, &Cancelled); } - -#ifdef QOS_DLS_SUPPORT - for (i=0; iStaCfg.DLSEntry[i].Timer, &Cancelled); - } -#endif // QOS_DLS_SUPPORT // +#endif } -#endif // CONFIG_STA_SUPPORT // RTMPCancelTimer(&pAd->Mlme.PeriodicTimer, &Cancelled); RTMPCancelTimer(&pAd->Mlme.RxAntEvalTimer, &Cancelled); @@ -734,6 +696,27 @@ VOID MlmeHalt( // Set LED RTMPSetLED(pAd, LED_HALT); RTMPSetSignalLED(pAd, -100); // Force signal strength Led to be turned off, firmware is not done it. +#ifdef RT2870 + { + LED_CFG_STRUC LedCfg; + RTMP_IO_READ32(pAd, LED_CFG, &LedCfg.word); + LedCfg.field.LedPolar = 0; + LedCfg.field.RLedMode = 0; + LedCfg.field.GLedMode = 0; + LedCfg.field.YLedMode = 0; + RTMP_IO_WRITE32(pAd, LED_CFG, LedCfg.word); + } +#endif // RT2870 // +#ifdef RT3070 + // + // Turn off LNA_PE + // + if (IS_RT3070(pAd) || IS_RT3071(pAd)) + { + TxPinCfg &= 0xFFFFF0F0; + RTUSBWriteMACRegister(pAd, TX_PIN_CFG, TxPinCfg); + } +#endif // RT3070 // } RTMPusecDelay(5000); // 5 msec to gurantee Ant Diversity timer canceled @@ -804,6 +787,7 @@ VOID MlmePeriodicExec( ULONG TxTotalCnt; PRTMP_ADAPTER pAd = (RTMP_ADAPTER *)FunctionContext; +#ifdef RT2860 //Baron 2008/07/10 //printk("Baron_Test:\t%s", RTMPGetRalinkEncryModeStr(pAd->StaCfg.WepStatus)); //If the STA security setting is OPEN or WEP, pAd->StaCfg.WpaSupplicantUP = 0. @@ -817,8 +801,6 @@ VOID MlmePeriodicExec( pAd->StaCfg.WpaSupplicantUP = 1; } -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { // If Hardware controlled Radio enabled, we have to check GPIO pin2 every 2 second. // Move code to here, because following code will return when radio is off @@ -858,7 +840,7 @@ VOID MlmePeriodicExec( } } } -#endif // CONFIG_STA_SUPPORT // +#endif /* RT2860 */ // Do nothing if the driver is starting halt state. // This might happen when timer already been fired before cancel timer with mlmehalt @@ -868,7 +850,7 @@ VOID MlmePeriodicExec( fRTMP_ADAPTER_RESET_IN_PROGRESS)))) return; - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) +#ifdef RT2860 { if ((pAd->RalinkCounters.LastReceivedByteCount == pAd->RalinkCounters.ReceivedByteCount) && (pAd->StaCfg.bRadio == TRUE)) { @@ -906,23 +888,9 @@ VOID MlmePeriodicExec( AsicResetFromDMABusy(pAd); } } - +#endif /* RT2860 */ RT28XX_MLME_PRE_SANITY_CHECK(pAd); -#ifdef RALINK_ATE - /* Do not show RSSI until "Normal 1 second Mlme PeriodicExec". */ - if (ATE_ON(pAd)) - { - if (pAd->Mlme.PeriodicRound % MLME_TASK_EXEC_MULTIPLE != (MLME_TASK_EXEC_MULTIPLE - 1)) - { - pAd->Mlme.PeriodicRound ++; - return; - } - } -#endif // RALINK_ATE // - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { // Do nothing if monitor mode is on if (MONITOR_ON(pAd)) @@ -947,26 +915,26 @@ VOID MlmePeriodicExec( } } } -#endif // CONFIG_STA_SUPPORT // pAd->bUpdateBcnCntDone = FALSE; // RECBATimerTimeout(SystemSpecific1,FunctionContext,SystemSpecific2,SystemSpecific3); pAd->Mlme.PeriodicRound ++; +#ifdef RT3070 + // execute every 100ms, update the Tx FIFO Cnt for update Tx Rate. + NICUpdateFifoStaCounters(pAd); +#endif // RT3070 // // execute every 500ms if ((pAd->Mlme.PeriodicRound % 5 == 0) && RTMPAutoRateSwitchCheck(pAd)/*(OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED))*/) { -#ifdef CONFIG_STA_SUPPORT // perform dynamic tx rate switching based on past TX history - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { if ((OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) ) && (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE))) MlmeDynamicTxRateSwitching(pAd); } -#endif // CONFIG_STA_SUPPORT // } // Normal 1 second Mlme PeriodicExec. @@ -974,30 +942,6 @@ VOID MlmePeriodicExec( { pAd->Mlme.OneSecPeriodicRound ++; -#ifdef RALINK_ATE - if (ATE_ON(pAd)) - { - /* request from Baron : move this routine from later to here */ - /* for showing Rx error count in ATE RXFRAME */ - NICUpdateRawCounters(pAd); - if (pAd->ate.bRxFer == 1) - { - pAd->ate.RxTotalCnt += pAd->ate.RxCntPerSec; - ate_print(KERN_EMERG "MlmePeriodicExec: Rx packet cnt = %d/%d\n", pAd->ate.RxCntPerSec, pAd->ate.RxTotalCnt); - pAd->ate.RxCntPerSec = 0; - - if (pAd->ate.RxAntennaSel == 0) - ate_print(KERN_EMERG "MlmePeriodicExec: Rx AvgRssi0=%d, AvgRssi1=%d, AvgRssi2=%d\n\n", - pAd->ate.AvgRssi0, pAd->ate.AvgRssi1, pAd->ate.AvgRssi2); - else - ate_print(KERN_EMERG "MlmePeriodicExec: Rx AvgRssi=%d\n\n", pAd->ate.AvgRssi0); - } - MlmeResetRalinkCounters(pAd); - return; - } -#endif // RALINK_ATE // - - if (rx_Total) { @@ -1029,12 +973,12 @@ VOID MlmePeriodicExec( // the dynamic tuning mechanism below are based on most up-to-date information NICUpdateRawCounters(pAd); +#ifdef RT2870 + RT2870_WatchDog(pAd); +#endif // RT2870 // -#ifdef DOT11_N_SUPPORT // Need statistics after read counter. So put after NICUpdateRawCounters ORIBATimerTimeout(pAd); -#endif // DOT11_N_SUPPORT // - // The time period for checking antenna is according to traffic if (pAd->Mlme.bEnableAutoAntennaCheck) @@ -1043,6 +987,7 @@ VOID MlmePeriodicExec( pAd->RalinkCounters.OneSecTxRetryOkCount + pAd->RalinkCounters.OneSecTxFailCount; + // dynamic adjust antenna evaluation period according to the traffic if (TxTotalCnt > 50) { if (pAd->Mlme.OneSecPeriodicRound % 10 == 0) @@ -1059,17 +1004,14 @@ VOID MlmePeriodicExec( } } -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - STAMlmePeriodicExec(pAd); -#endif // CONFIG_STA_SUPPORT // + STAMlmePeriodicExec(pAd); MlmeResetRalinkCounters(pAd); -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { +#ifdef RT2860 if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST) && (pAd->bPCIclkOff == FALSE)) +#endif { // When Adhoc beacon is enabled and RTS/CTS is enabled, there is a chance that hardware MAC FSM will run into a deadlock // and sending CTS-to-self over and over. @@ -1091,41 +1033,32 @@ VOID MlmePeriodicExec( } } } -#endif // CONFIG_STA_SUPPORT // RT28XX_MLME_HANDLER(pAd); } - pAd->bUpdateBcnCntDone = FALSE; } -#ifdef CONFIG_STA_SUPPORT VOID STAMlmePeriodicExec( PRTMP_ADAPTER pAd) { +#ifdef RT2860 ULONG TxTotalCnt; +#endif +#ifdef RT2870 + ULONG TxTotalCnt; + int i; +#endif -// -// We return here in ATE mode, because the statistics -// that ATE needs are not collected via this routine. -// -#ifdef RALINK_ATE - // It is supposed that we will never reach here in ATE mode. - ASSERT(!(ATE_ON(pAd))); - if (ATE_ON(pAd)) - return; -#endif // RALINK_ATE // - -#ifdef WPA_SUPPLICANT_SUPPORT if (pAd->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_DISABLE) -#endif // WPA_SUPPLICANT_SUPPORT // { // WPA MIC error should block association attempt for 60 seconds if (pAd->StaCfg.bBlockAssoc && (pAd->StaCfg.LastMicErrorTime + (60 * OS_HZ) < pAd->Mlme.Now32)) pAd->StaCfg.bBlockAssoc = FALSE; } +#ifdef RT2860 //Baron 2008/07/10 //printk("Baron_Test:\t%s", RTMPGetRalinkEncryModeStr(pAd->StaCfg.WepStatus)); //If the STA security setting is OPEN or WEP, pAd->StaCfg.WpaSupplicantUP = 0. @@ -1138,6 +1071,7 @@ VOID STAMlmePeriodicExec( { pAd->StaCfg.WpaSupplicantUP = 1; } +#endif if ((pAd->PreMediaState != pAd->IndicateMediaState) && (pAd->CommonCfg.bWirelessEvent)) { @@ -1148,6 +1082,7 @@ VOID STAMlmePeriodicExec( pAd->PreMediaState = pAd->IndicateMediaState; } +#ifdef RT2860 if ((pAd->OpMode == OPMODE_STA) && (IDLE_ON(pAd)) && (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE)) && (pAd->Mlme.SyncMachine.CurrState == SYNC_IDLE) && @@ -1157,6 +1092,7 @@ VOID STAMlmePeriodicExec( { RT28xxPciAsicRadioOff(pAd, GUI_IDLE_POWER_SAVE, 0); } +#endif @@ -1179,11 +1115,6 @@ VOID STAMlmePeriodicExec( if (INFRA_ON(pAd)) { -#ifdef QOS_DLS_SUPPORT - // Check DLS time out, then tear down those session - RTMPCheckDLSTimeOut(pAd); -#endif // QOS_DLS_SUPPORT // - // Is PSM bit consistent with user power management policy? // This is the only place that will set PSM bit ON. if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) @@ -1228,26 +1159,11 @@ VOID STAMlmePeriodicExec( // Lost AP, send disconnect & link down event LinkDown(pAd, FALSE); -#ifdef WPA_SUPPLICANT_SUPPORT -#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT - if (pAd->StaCfg.WpaSupplicantUP) - { - union iwreq_data wrqu; - //send disassociate event to wpa_supplicant - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.flags = RT_DISASSOC_EVENT_FLAG; - wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); - } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // -#endif // WPA_SUPPLICANT_SUPPORT // - -#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT { union iwreq_data wrqu; memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN); wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // MlmeAutoReconnectLastSSID(pAd); } @@ -1273,6 +1189,7 @@ VOID STAMlmePeriodicExec( } else if (ADHOC_ON(pAd)) { +#ifdef RT2860 // 2003-04-17 john. this is a patch that driver forces a BEACON out if ASIC fails // the "TX BEACON competition" for the entire past 1 sec. // So that even when ASIC's BEACONgen engine been blocked @@ -1297,7 +1214,6 @@ VOID STAMlmePeriodicExec( pAd->StaCfg.AdhocBOnlyJoined = FALSE; } -#ifdef DOT11_N_SUPPORT if (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) { if ((pAd->StaCfg.AdhocBGJoined) && @@ -1314,7 +1230,7 @@ VOID STAMlmePeriodicExec( pAd->StaCfg.Adhoc20NJoined = FALSE; } } -#endif // DOT11_N_SUPPORT // +#endif /* RT2860 */ //radar detect if ((pAd->CommonCfg.Channel > 14) @@ -1339,6 +1255,19 @@ VOID STAMlmePeriodicExec( MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_START_REQ, sizeof(MLME_START_REQ_STRUCT), &StartReq); pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_START; } + +#ifdef RT2870 + for (i = 1; i < MAX_LEN_OF_MAC_TABLE; i++) + { + MAC_TABLE_ENTRY *pEntry = &pAd->MacTab.Content[i]; + + if (pEntry->ValidAsCLI == FALSE) + continue; + + if (pEntry->LastBeaconRxTime + ADHOC_BEACON_LOST_TIME < pAd->Mlme.Now32) + MacTableDeleteEntry(pAd, pEntry->Aid, pEntry->Addr); + } +#endif } else // no INFRA nor ADHOC connection { @@ -1378,14 +1307,6 @@ VOID STAMlmePeriodicExec( } else { -#ifdef CARRIER_DETECTION_SUPPORT // Roger sync Carrier - if (pAd->CommonCfg.CarrierDetect.Enable == TRUE) - { - if ((pAd->Mlme.OneSecPeriodicRound % 5) == 1) - MlmeAutoReconnectLastSSID(pAd); - } - else -#endif // CARRIER_DETECTION_SUPPORT // MlmeAutoReconnectLastSSID(pAd); } } @@ -1394,7 +1315,6 @@ VOID STAMlmePeriodicExec( SKIP_AUTO_SCAN_CONN: -#ifdef DOT11_N_SUPPORT if ((pAd->MacTab.Content[BSSID_WCID].TXBAbitmap !=0) && (pAd->MacTab.fAnyBASession == FALSE)) { pAd->MacTab.fAnyBASession = TRUE; @@ -1405,15 +1325,6 @@ SKIP_AUTO_SCAN_CONN: pAd->MacTab.fAnyBASession = FALSE; AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, ALLN_SETPROTECT, FALSE, FALSE); } -#endif // DOT11_N_SUPPORT // - - -#ifdef DOT11_N_SUPPORT -#ifdef DOT11N_DRAFT3 - if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_SCAN_2040)) - TriEventCounterMaintenance(pAd); -#endif // DOT11N_DRAFT3 // -#endif // DOT11_N_SUPPORT // return; } @@ -1473,7 +1384,6 @@ VOID MlmeAutoReconnectLastSSID( RT28XX_MLME_HANDLER(pAd); } } -#endif // CONFIG_STA_SUPPORT // /* ========================================================================== @@ -1522,15 +1432,19 @@ VOID MlmeSelectTxRateTable( break; } -#ifdef CONFIG_STA_SUPPORT if ((pAd->OpMode == OPMODE_STA) && ADHOC_ON(pAd)) { -#ifdef DOT11_N_SUPPORT if ((pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) && +#ifdef RT2860 !pAd->StaCfg.AdhocBOnlyJoined && !pAd->StaCfg.AdhocBGJoined && (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0xff) && ((pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0x00) || (pAd->Antenna.field.TxPath == 1))) +#endif +#ifdef RT2870 + (pEntry->HTCapability.MCSSet[0] == 0xff) && + ((pEntry->HTCapability.MCSSet[1] == 0x00) || (pAd->Antenna.field.TxPath == 1))) +#endif {// 11N 1S Adhoc *ppTable = RateSwitchTable11N1S; *pTableSize = RateSwitchTable11N1S[0]; @@ -1538,10 +1452,16 @@ VOID MlmeSelectTxRateTable( } else if ((pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) && +#ifdef RT2860 !pAd->StaCfg.AdhocBOnlyJoined && !pAd->StaCfg.AdhocBGJoined && (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0xff) && (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0xff) && +#endif +#ifdef RT2870 + (pEntry->HTCapability.MCSSet[0] == 0xff) && + (pEntry->HTCapability.MCSSet[1] == 0xff) && +#endif (pAd->Antenna.field.TxPath == 2)) {// 11N 2S Adhoc if (pAd->LatchRfRegs.Channel <= 14) @@ -1559,7 +1479,7 @@ VOID MlmeSelectTxRateTable( } else -#endif // DOT11_N_SUPPORT // +#ifdef RT2860 if (pAd->CommonCfg.PhyMode == PHY_11B) { *ppTable = RateSwitchTable11B; @@ -1568,6 +1488,12 @@ VOID MlmeSelectTxRateTable( } else if((pAd->LatchRfRegs.Channel <= 14) && (pAd->StaCfg.AdhocBOnlyJoined == TRUE)) +#endif +#ifdef RT2870 + if ((pEntry->RateLen == 4) + && (pEntry->HTCapability.MCSSet[0] == 0) && (pEntry->HTCapability.MCSSet[1] == 0) + ) +#endif { // USe B Table when Only b-only Station in my IBSS . *ppTable = RateSwitchTable11B; @@ -1591,9 +1517,7 @@ VOID MlmeSelectTxRateTable( } break; } -#endif // CONFIG_STA_SUPPORT // -#ifdef DOT11_N_SUPPORT if ((pEntry->RateLen == 12) && (pEntry->HTCapability.MCSSet[0] == 0xff) && ((pEntry->HTCapability.MCSSet[1] == 0x00) || (pAd->CommonCfg.TxStream == 1))) {// 11BGN 1S AP @@ -1650,12 +1574,13 @@ VOID MlmeSelectTxRateTable( break; } -#endif // DOT11_N_SUPPORT // + //else if ((pAd->StaActive.SupRateLen == 4) && (pAd->StaActive.ExtRateLen == 0) && (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0) && (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0)) if ((pEntry->RateLen == 4) -#ifdef DOT11_N_SUPPORT +#ifndef RT30xx +//Iverson mark for Adhoc b mode,sta will use rate 54 Mbps when connect with sta b/g/n mode && (pEntry->HTCapability.MCSSet[0] == 0) && (pEntry->HTCapability.MCSSet[1] == 0) -#endif // DOT11_N_SUPPORT // +#endif ) {// B only AP *ppTable = RateSwitchTable11B; @@ -1667,9 +1592,7 @@ VOID MlmeSelectTxRateTable( //else if ((pAd->StaActive.SupRateLen + pAd->StaActive.ExtRateLen > 8) && (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0) && (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0)) if ((pEntry->RateLen > 8) -#ifdef DOT11_N_SUPPORT && (pEntry->HTCapability.MCSSet[0] == 0) && (pEntry->HTCapability.MCSSet[1] == 0) -#endif // DOT11_N_SUPPORT // ) {// B/G mixed AP *ppTable = RateSwitchTable11BG; @@ -1681,9 +1604,7 @@ VOID MlmeSelectTxRateTable( //else if ((pAd->StaActive.SupRateLen + pAd->StaActive.ExtRateLen == 8) && (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0) && (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0)) if ((pEntry->RateLen == 8) -#ifdef DOT11_N_SUPPORT && (pEntry->HTCapability.MCSSet[0] == 0) && (pEntry->HTCapability.MCSSet[1] == 0) -#endif // DOT11_N_SUPPORT // ) {// G only AP *ppTable = RateSwitchTable11G; @@ -1692,16 +1613,10 @@ VOID MlmeSelectTxRateTable( break; } -#ifdef DOT11_N_SUPPORT -#endif // DOT11_N_SUPPORT // -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { -#ifdef DOT11_N_SUPPORT //else if ((pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0) && (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0)) if ((pEntry->HTCapability.MCSSet[0] == 0) && (pEntry->HTCapability.MCSSet[1] == 0)) -#endif // DOT11_N_SUPPORT // { // Legacy mode if (pAd->CommonCfg.MaxTxRate <= RATE_11) { @@ -1724,7 +1639,7 @@ VOID MlmeSelectTxRateTable( } break; } -#ifdef DOT11_N_SUPPORT + if (pAd->LatchRfRegs.Channel <= 14) { if (pAd->CommonCfg.TxStream == 1) @@ -1759,15 +1674,13 @@ VOID MlmeSelectTxRateTable( DBGPRINT_RAW(RT_DEBUG_ERROR,("DRS: unkown mode,default use 11N 2S AP \n")); } } -#endif // DOT11_N_SUPPORT // + DBGPRINT_RAW(RT_DEBUG_ERROR,("DRS: unkown mode (SupRateLen=%d, ExtRateLen=%d, MCSSet[0]=0x%x, MCSSet[1]=0x%x)\n", pAd->StaActive.SupRateLen, pAd->StaActive.ExtRateLen, pAd->StaActive.SupportedPhyInfo.MCSSet[0], pAd->StaActive.SupportedPhyInfo.MCSSet[1])); } -#endif // CONFIG_STA_SUPPORT // } while(FALSE); } -#ifdef CONFIG_STA_SUPPORT /* ========================================================================== Description: @@ -1921,14 +1834,6 @@ VOID MlmeCalculateChannelQuality( CHAR MaxRssi; ULONG BeaconLostTime = BEACON_LOST_TIME; -#ifdef CARRIER_DETECTION_SUPPORT // Roger sync Carrier - // longer beacon lost time when carrier detection enabled - if (pAd->CommonCfg.CarrierDetect.Enable == TRUE) - { - BeaconLostTime = BEACON_LOST_TIME + BEACON_LOST_TIME/2; - } -#endif // CARRIER_DETECTION_SUPPORT // - MaxRssi = RTMPMaxRssi(pAd, pAd->StaCfg.RssiSample.LastRssi0, pAd->StaCfg.RssiSample.LastRssi1, pAd->StaCfg.RssiSample.LastRssi2); // @@ -1993,13 +1898,11 @@ VOID MlmeSetTxRate( { UCHAR MaxMode = MODE_OFDM; -#ifdef DOT11_N_SUPPORT MaxMode = MODE_HTGREENFIELD; if (pTxRate->STBC && (pAd->StaCfg.MaxHTPhyMode.field.STBC) && (pAd->Antenna.field.TxPath == 2)) pAd->StaCfg.HTPhyMode.field.STBC = STBC_USE; else -#endif // DOT11_N_SUPPORT // pAd->StaCfg.HTPhyMode.field.STBC = STBC_NONE; if (pTxRate->CurrMCS < MCS_AUTO) @@ -2029,14 +1932,11 @@ VOID MlmeSetTxRate( if (pTxRate->Mode <= MaxMode) pAd->StaCfg.HTPhyMode.field.MODE = pTxRate->Mode; -#ifdef DOT11_N_SUPPORT if (pTxRate->ShortGI && (pAd->StaCfg.MaxHTPhyMode.field.ShortGI)) pAd->StaCfg.HTPhyMode.field.ShortGI = GI_400; else -#endif // DOT11_N_SUPPORT // pAd->StaCfg.HTPhyMode.field.ShortGI = GI_800; -#ifdef DOT11_N_SUPPORT // Reexam each bandwidth's SGI support. if (pAd->StaCfg.HTPhyMode.field.ShortGI == GI_400) { @@ -2080,17 +1980,15 @@ VOID MlmeSetTxRate( { AsicUpdateProtect(pAd, HT_RTSCTS_6M, ALLN_SETPROTECT, TRUE, (BOOLEAN)pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent); } -#endif // DOT11_N_SUPPORT // pEntry->HTPhyMode.field.STBC = pAd->StaCfg.HTPhyMode.field.STBC; pEntry->HTPhyMode.field.ShortGI = pAd->StaCfg.HTPhyMode.field.ShortGI; pEntry->HTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; pEntry->HTPhyMode.field.MODE = pAd->StaCfg.HTPhyMode.field.MODE; -#ifdef DOT11_N_SUPPORT + if ((pAd->StaCfg.MaxHTPhyMode.field.MODE == MODE_HTGREENFIELD) && pAd->WIFItestbed.bGreenField) pEntry->HTPhyMode.field.MODE = MODE_HTGREENFIELD; -#endif // DOT11_N_SUPPORT // } pAd->LastTxRate = (USHORT)(pEntry->HTPhyMode.word); @@ -2130,18 +2028,6 @@ VOID MlmeDynamicTxRateSwitching( ULONG TxRetransmit = 0, TxSuccess = 0, TxFailCount = 0; MAC_TABLE_ENTRY *pEntry; -#ifdef RALINK_ATE - if (ATE_ON(pAd)) - { - return; - } -#endif // RALINK_ATE // - - /*if (pAd->Antenna.field.RxPath > 1) - Rssi = (pAd->StaCfg.RssiSample.AvgRssi0 + pAd->StaCfg.RssiSample.AvgRssi1) >> 1; - else - Rssi = pAd->StaCfg.RssiSample.AvgRssi0;*/ - // // walk through MAC table, see if need to change AP's TX rate toward each entry // @@ -2155,7 +2041,15 @@ VOID MlmeDynamicTxRateSwitching( if ((pAd->MacTab.Size == 1) || (pEntry->ValidAsDls)) { +#ifdef RT2860 Rssi = RTMPMaxRssi(pAd, (CHAR)pAd->StaCfg.RssiSample.AvgRssi0, (CHAR)pAd->StaCfg.RssiSample.AvgRssi1, (CHAR)pAd->StaCfg.RssiSample.AvgRssi2); +#endif +#ifdef RT2870 + Rssi = RTMPMaxRssi(pAd, + pAd->StaCfg.RssiSample.AvgRssi0, + pAd->StaCfg.RssiSample.AvgRssi1, + pAd->StaCfg.RssiSample.AvgRssi2); +#endif // Update statistic counter RTMP_IO_READ32(pAd, TX_STA_CNT0, &TxStaCnt0.word); @@ -2185,7 +2079,21 @@ VOID MlmeDynamicTxRateSwitching( } else { +#ifdef RT2860 Rssi = RTMPMaxRssi(pAd, (CHAR)pEntry->RssiSample.AvgRssi0, (CHAR)pEntry->RssiSample.AvgRssi1, (CHAR)pEntry->RssiSample.AvgRssi2); +#endif +#ifdef RT2870 + if (INFRA_ON(pAd) && (i == 1)) + Rssi = RTMPMaxRssi(pAd, + pAd->StaCfg.RssiSample.AvgRssi0, + pAd->StaCfg.RssiSample.AvgRssi1, + pAd->StaCfg.RssiSample.AvgRssi2); + else + Rssi = RTMPMaxRssi(pAd, + pEntry->RssiSample.AvgRssi0, + pEntry->RssiSample.AvgRssi1, + pEntry->RssiSample.AvgRssi2); +#endif TxTotalCnt = pEntry->OneSecTxNoRetryOkCount + pEntry->OneSecTxRetryOkCount + @@ -2242,14 +2150,12 @@ VOID MlmeDynamicTxRateSwitching( pCurrTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(CurrRateIdx+1)*5]; -#ifdef DOT11_N_SUPPORT if ((Rssi > -65) && (pCurrTxRate->Mode >= MODE_HTMIX)) { TrainUp = (pCurrTxRate->TrainUp + (pCurrTxRate->TrainUp >> 1)); TrainDown = (pCurrTxRate->TrainDown + (pCurrTxRate->TrainDown >> 1)); } else -#endif // DOT11_N_SUPPORT // { TrainUp = pCurrTxRate->TrainUp; TrainDown = pCurrTxRate->TrainDown; @@ -2327,7 +2233,6 @@ VOID MlmeDynamicTxRateSwitching( { MCS14 = idx; } - //else if ((pCurrTxRate->CurrMCS == MCS_15)/* && (pCurrTxRate->ShortGI == GI_800)*/) //we hope to use ShortGI as initial rate else if ((pCurrTxRate->CurrMCS == MCS_15) && (pCurrTxRate->ShortGI == GI_800)) //we hope to use ShortGI as initial rate, however Atheros's chip has bugs when short GI { MCS15 = idx; @@ -2373,7 +2278,7 @@ VOID MlmeDynamicTxRateSwitching( RssiOffset = 8; } } -#ifdef DOT11_N_SUPPORT + /*if (MCS15)*/ if ((pTable == RateSwitchTable11BGN3S) || (pTable == RateSwitchTable11N3S) || @@ -2439,7 +2344,6 @@ VOID MlmeDynamicTxRateSwitching( TxRateIdx = MCS0; } else -#endif // DOT11_N_SUPPORT // {// Legacy mode if (MCS7 && (Rssi > -70)) TxRateIdx = MCS7; @@ -2613,7 +2517,12 @@ VOID StaQuickResponeForRateUpExec( UCHAR UpRateIdx = 0, DownRateIdx = 0, CurrRateIdx = 0; ULONG TxTotalCnt; ULONG TxErrorRatio = 0; +#ifdef RT2860 BOOLEAN bTxRateChanged = TRUE; //, bUpgradeQuality = FALSE; +#endif +#ifdef RT2870 + BOOLEAN bTxRateChanged; //, bUpgradeQuality = FALSE; +#endif PRTMP_TX_RATE_SWITCH pCurrTxRate, pNextTxRate = NULL; PUCHAR pTable; UCHAR TableSize = 0; @@ -2638,11 +2547,25 @@ VOID StaQuickResponeForRateUpExec( if (RTMPCheckEntryEnableAutoRateSwitch(pAd, pEntry) == FALSE) continue; +#ifdef RT2860 //Rssi = RTMPMaxRssi(pAd, (CHAR)pAd->StaCfg.AvgRssi0, (CHAR)pAd->StaCfg.AvgRssi1, (CHAR)pAd->StaCfg.AvgRssi2); if (pAd->Antenna.field.TxPath > 1) Rssi = (pAd->StaCfg.RssiSample.AvgRssi0 + pAd->StaCfg.RssiSample.AvgRssi1) >> 1; else Rssi = pAd->StaCfg.RssiSample.AvgRssi0; +#endif +#ifdef RT2870 + if (INFRA_ON(pAd) && (i == 1)) + Rssi = RTMPMaxRssi(pAd, + pAd->StaCfg.RssiSample.AvgRssi0, + pAd->StaCfg.RssiSample.AvgRssi1, + pAd->StaCfg.RssiSample.AvgRssi2); + else + Rssi = RTMPMaxRssi(pAd, + pEntry->RssiSample.AvgRssi0, + pEntry->RssiSample.AvgRssi1, + pEntry->RssiSample.AvgRssi2); +#endif CurrRateIdx = pAd->CommonCfg.TxRateIndex; @@ -2667,14 +2590,12 @@ VOID StaQuickResponeForRateUpExec( pCurrTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(CurrRateIdx+1)*5]; -#ifdef DOT11_N_SUPPORT if ((Rssi > -65) && (pCurrTxRate->Mode >= MODE_HTMIX)) { TrainUp = (pCurrTxRate->TrainUp + (pCurrTxRate->TrainUp >> 1)); TrainDown = (pCurrTxRate->TrainDown + (pCurrTxRate->TrainDown >> 1)); } else -#endif // DOT11_N_SUPPORT // { TrainUp = pCurrTxRate->TrainUp; TrainDown = pCurrTxRate->TrainDown; @@ -2784,6 +2705,9 @@ VOID StaQuickResponeForRateUpExec( pAd->DrsCounters.TxRateUpPenalty = 0; NdisZeroMemory(pAd->DrsCounters.TxQuality, sizeof(USHORT) * MAX_STEP_OF_TX_RATE_SWITCH); NdisZeroMemory(pAd->DrsCounters.PER, sizeof(UCHAR) * MAX_STEP_OF_TX_RATE_SWITCH); +#ifdef RT2870 + bTxRateChanged = TRUE; +#endif } // if rate-down happen, only clear DownRate's bad history else if (pAd->CommonCfg.TxRateIndex < CurrRateIdx) @@ -2793,6 +2717,9 @@ VOID StaQuickResponeForRateUpExec( pAd->DrsCounters.TxRateUpPenalty = 0; // no penalty pAd->DrsCounters.TxQuality[pAd->CommonCfg.TxRateIndex] = 0; pAd->DrsCounters.PER[pAd->CommonCfg.TxRateIndex] = 0; +#ifdef RT2870 + bTxRateChanged = TRUE; +#endif } else { @@ -2848,7 +2775,13 @@ VOID MlmeCheckPsmChange( if (INFRA_ON(pAd) && (PowerMode != Ndis802_11PowerModeCAM) && (pAd->StaCfg.Psm == PWR_ACTIVE) && +#ifdef RT2860 RTMP_TEST_PSFLAG(pAd, fRTMP_PS_CAN_GO_SLEEP)) +#endif +#if !defined(RT2860) && !defined(RT30xx) + (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE)) +#endif +#ifndef RT30xx { NdisGetSystemUpTime(&pAd->Mlme.LastSendNULLpsmTime); pAd->RalinkCounters.RxCountSinceLastNULL = 0; @@ -2862,6 +2795,42 @@ VOID MlmeCheckPsmChange( RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, TRUE); } } +#endif +#ifdef RT30xx +// (! RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) + (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) /*&& + (pAd->RalinkCounters.OneSecTxNoRetryOkCount == 0) && + (pAd->RalinkCounters.OneSecTxRetryOkCount == 0)*/) + { + // add by johnli, use Rx OK data count per second to calculate throughput + // If Ttraffic is too high ( > 400 Rx per second), don't go to sleep mode. If tx rate is low, use low criteria + // Mode=CCK/MCS=3 => 11 Mbps, Mode=OFDM/MCS=3 => 18 Mbps + if (((pAd->StaCfg.HTPhyMode.field.MCS <= 3) && +/* Iverson mark + (pAd->StaCfg.HTPhyMode.field.MODE <= MODE_OFDM) && +*/ + (pAd->RalinkCounters.OneSecRxOkDataCnt < (ULONG)100)) || + ((pAd->StaCfg.HTPhyMode.field.MCS > 3) && +/* Iverson mark + (pAd->StaCfg.HTPhyMode.field.MODE > MODE_OFDM) && +*/ + (pAd->RalinkCounters.OneSecRxOkDataCnt < (ULONG)400))) + { + // Get this time + NdisGetSystemUpTime(&pAd->Mlme.LastSendNULLpsmTime); + pAd->RalinkCounters.RxCountSinceLastNULL = 0; + MlmeSetPsmBit(pAd, PWR_SAVE); + if (!(pAd->CommonCfg.bAPSDCapable && pAd->CommonCfg.APEdcaParm.bAPSDCapable)) + { + RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, FALSE); + } + else + { + RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, TRUE); + } + } + } +#endif } // IRQL = PASSIVE_LEVEL @@ -2876,10 +2845,10 @@ VOID MlmeSetPsmBit( RTMP_IO_READ32(pAd, AUTO_RSP_CFG, &csr4.word); csr4.field.AckCtsPsmBit = (psm == PWR_SAVE)? 1:0; RTMP_IO_WRITE32(pAd, AUTO_RSP_CFG, csr4.word); +#ifndef RT30xx DBGPRINT(RT_DEBUG_TRACE, ("MlmeSetPsmBit = %d\n", psm)); +#endif } -#endif // CONFIG_STA_SUPPORT // - // IRQL = DISPATCH_LEVEL VOID MlmeSetTxPreamble( @@ -3018,9 +2987,6 @@ VOID MlmeUpdateTxRates( //=========================================================================== //=========================================================================== - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { pHtPhy = &pAd->StaCfg.HTPhyMode; pMaxHtPhy = &pAd->StaCfg.MaxHTPhyMode; @@ -3036,7 +3002,6 @@ VOID MlmeUpdateTxRates( MaxDesire = RATE_11; } } -#endif // CONFIG_STA_SUPPORT // pAd->CommonCfg.MaxDesiredRate = MaxDesire; pMinHtPhy->word = 0; @@ -3065,7 +3030,6 @@ VOID MlmeUpdateTxRates( } #endif -#ifdef CONFIG_STA_SUPPORT if ((ADHOC_ON(pAd) || INFRA_ON(pAd)) && (pAd->OpMode == OPMODE_STA)) { pSupRate = &pAd->StaActive.SupRate[0]; @@ -3074,7 +3038,6 @@ VOID MlmeUpdateTxRates( ExtRateLen = pAd->StaActive.ExtRateLen; } else -#endif // CONFIG_STA_SUPPORT // { pSupRate = &pAd->CommonCfg.SupRate[0]; pExtRate = &pAd->CommonCfg.ExtRate[0]; @@ -3151,10 +3114,9 @@ VOID MlmeUpdateTxRates( if (*auto_rate_cur_p) { short dbm = 0; -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - dbm = pAd->StaCfg.RssiSample.AvgRssi0 - pAd->BbpRssiToDbmDelta; -#endif // CONFIG_STA_SUPPORT // + + dbm = pAd->StaCfg.RssiSample.AvgRssi0 - pAd->BbpRssiToDbmDelta; + if (bLinkUp == TRUE) pAd->CommonCfg.TxRate = RATE_24; else @@ -3212,9 +3174,7 @@ VOID MlmeUpdateTxRates( { case PHY_11BG_MIXED: case PHY_11B: -#ifdef DOT11_N_SUPPORT case PHY_11BGN_MIXED: -#endif // DOT11_N_SUPPORT // pAd->CommonCfg.MlmeRate = RATE_1; pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_CCK; pAd->CommonCfg.MlmeTransmit.field.MCS = RATE_1; @@ -3222,22 +3182,18 @@ VOID MlmeUpdateTxRates( break; case PHY_11G: case PHY_11A: -#ifdef DOT11_N_SUPPORT case PHY_11AGN_MIXED: case PHY_11GN_MIXED: case PHY_11N_2_4G: case PHY_11AN_MIXED: case PHY_11N_5G: -#endif // DOT11_N_SUPPORT // pAd->CommonCfg.MlmeRate = RATE_6; pAd->CommonCfg.RtsRate = RATE_6; pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM; pAd->CommonCfg.MlmeTransmit.field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate]; break; case PHY_11ABG_MIXED: -#ifdef DOT11_N_SUPPORT case PHY_11ABGN_MIXED: -#endif // DOT11_N_SUPPORT // if (pAd->CommonCfg.Channel <= 14) { pAd->CommonCfg.MlmeRate = RATE_1; @@ -3280,7 +3236,6 @@ VOID MlmeUpdateTxRates( pAd->CommonCfg.MlmeTransmit.word, pAd->MacTab.Content[BSSID_WCID].MinHTPhyMode.word ,pAd->MacTab.Content[BSSID_WCID].MaxHTPhyMode.word ,pAd->MacTab.Content[BSSID_WCID].HTPhyMode.word )); } -#ifdef DOT11_N_SUPPORT /* ========================================================================== Description: @@ -3313,8 +3268,6 @@ VOID MlmeUpdateHtTxRates( auto_rate_cur_p = NULL; -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { pDesireHtPhy = &pAd->StaCfg.DesiredHtPhyInfo; pActiveHtPhy = &pAd->StaCfg.DesiredHtPhyInfo; @@ -3324,9 +3277,7 @@ VOID MlmeUpdateHtTxRates( auto_rate_cur_p = &pAd->StaCfg.bAutoTxRateSwitch; } -#endif // CONFIG_STA_SUPPORT // -#ifdef CONFIG_STA_SUPPORT if ((ADHOC_ON(pAd) || INFRA_ON(pAd)) && (pAd->OpMode == OPMODE_STA)) { if (pAd->StaActive.SupportedPhyInfo.bHtEnable == FALSE) @@ -3342,7 +3293,6 @@ VOID MlmeUpdateHtTxRates( pMaxHtPhy->field.STBC = STBC_NONE; } else -#endif // CONFIG_STA_SUPPORT // { if (pDesireHtPhy->bHtEnable == FALSE) return; @@ -3393,7 +3343,6 @@ VOID MlmeUpdateHtTxRates( pMinHtPhy->field.STBC = 0; pMinHtPhy->field.ShortGI = 0; //If STA assigns fixed rate. update to fixed here. -#ifdef CONFIG_STA_SUPPORT if ( (pAd->OpMode == OPMODE_STA) && (pDesireHtPhy->MCSSet[0] != 0xff)) { if (pDesireHtPhy->MCSSet[4] != 0) @@ -3417,8 +3366,6 @@ VOID MlmeUpdateHtTxRates( break; } } -#endif // CONFIG_STA_SUPPORT // - // Decide ht rate pHtPhy->field.STBC = pMaxHtPhy->field.STBC; @@ -3438,7 +3385,6 @@ VOID MlmeUpdateHtTxRates( pHtPhy->field.BW, pHtPhy->field.ShortGI, pHtPhy->field.MODE)); DBGPRINT(RT_DEBUG_TRACE,("MlmeUpdateHtTxRates<=== \n")); } -#endif // DOT11_N_SUPPORT // // IRQL = DISPATCH_LEVEL VOID MlmeRadioOff( @@ -3483,7 +3429,6 @@ VOID BssTableInit( } } -#ifdef DOT11_N_SUPPORT VOID BATableInit( IN PRTMP_ADAPTER pAd, IN BA_TABLE *Tab) @@ -3503,7 +3448,6 @@ VOID BATableInit( Tab->BAOriEntry[i].ORI_BA_Status = Originator_NONE; } } -#endif // DOT11_N_SUPPORT // /*! \brief search the BSS table by SSID * \param p_tab pointer to the bss table @@ -3613,7 +3557,6 @@ VOID BssTableDeleteEntry( } } -#ifdef DOT11_N_SUPPORT /* ======================================================================== Routine Description: @@ -3645,7 +3588,6 @@ VOID BATableDeleteORIEntry( NdisReleaseSpinLock(&pAd->BATabLock); } } -#endif // DOT11_N_SUPPORT // /*! \brief * \param @@ -3762,7 +3704,7 @@ VOID BssEntrySet( pBss->AddHtInfoLen = 0; pBss->HtCapabilityLen = 0; -#ifdef DOT11_N_SUPPORT + if (HtCapabilityLen> 0) { pBss->HtCapabilityLen = HtCapabilityLen; @@ -3782,7 +3724,6 @@ VOID BssEntrySet( } } } -#endif // DOT11_N_SUPPORT // BssCipherParse(pBss); @@ -3800,8 +3741,6 @@ VOID BssEntrySet( else pBss->QbssLoad.bValid = FALSE; -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { PEID_STRUCT pEid; USHORT Length = 0; @@ -3809,11 +3748,9 @@ VOID BssEntrySet( NdisZeroMemory(&pBss->WpaIE.IE[0], MAX_CUSTOM_LEN); NdisZeroMemory(&pBss->RsnIE.IE[0], MAX_CUSTOM_LEN); -#ifdef EXT_BUILD_CHANNEL_LIST - NdisZeroMemory(&pBss->CountryString[0], 3); - pBss->bHasCountryIE = FALSE; -#endif // EXT_BUILD_CHANNEL_LIST // + pEid = (PEID_STRUCT) pVIE; + while ((Length + 2 + (USHORT)pEid->Len) <= LengthVIE) { switch(pEid->Eid) @@ -3842,18 +3779,11 @@ VOID BssEntrySet( NdisMoveMemory(pBss->RsnIE.IE, pEid, pBss->RsnIE.IELen); } break; -#ifdef EXT_BUILD_CHANNEL_LIST - case IE_COUNTRY: - NdisMoveMemory(&pBss->CountryString[0], pEid->Octet, 3); - pBss->bHasCountryIE = TRUE; - break; -#endif // EXT_BUILD_CHANNEL_LIST // } Length = Length + 2 + (USHORT)pEid->Len; // Eid[1] + Len[1]+ content[Len] pEid = (PEID_STRUCT)((UCHAR*)pEid + 2 + pEid->Len); } } -#endif // CONFIG_STA_SUPPORT // } /*! @@ -3947,120 +3877,23 @@ ULONG BssTableSetEntry( } else { +#ifdef RT30xx + /* avoid Hidden SSID form beacon to overwirite correct SSID from probe response */ + if ((SSID_EQUAL(Ssid, SsidLen, Tab->BssEntry[Idx].Ssid, Tab->BssEntry[Idx].SsidLen)) || + (NdisEqualMemory(Tab->BssEntry[Idx].Ssid, ZeroSsid, Tab->BssEntry[Idx].SsidLen))) + { +#endif BssEntrySet(pAd, &Tab->BssEntry[Idx], pBssid, Ssid, SsidLen, BssType, BeaconPeriod,CfParm, AtimWin, CapabilityInfo, SupRate, SupRateLen, ExtRate, ExtRateLen,pHtCapability, pAddHtInfo,HtCapabilityLen, AddHtInfoLen, NewExtChanOffset, ChannelNo, Rssi, TimeStamp, CkipFlag, pEdcaParm, pQosCapability, pQbssLoad, LengthVIE, pVIE); +#ifdef RT30xx + } +#endif } return Idx; } -#ifdef CONFIG_STA_SUPPORT -#ifdef DOT11_N_SUPPORT -#ifdef DOT11N_DRAFT3 -VOID TriEventInit( - IN PRTMP_ADAPTER pAd) -{ - UCHAR i; - - for (i = 0;i < MAX_TRIGGER_EVENT;i++) - pAd->CommonCfg.TriggerEventTab.EventA[i].bValid = FALSE; - - pAd->CommonCfg.TriggerEventTab.EventANo = 0; - pAd->CommonCfg.TriggerEventTab.EventBCountDown = 0; -} - -ULONG TriEventTableSetEntry( - IN PRTMP_ADAPTER pAd, - OUT TRIGGER_EVENT_TAB *Tab, - IN PUCHAR pBssid, - IN HT_CAPABILITY_IE *pHtCapability, - IN UCHAR HtCapabilityLen, - IN UCHAR RegClass, - IN UCHAR ChannelNo) -{ - // Event A - if (HtCapabilityLen == 0) - { - if (Tab->EventANo < MAX_TRIGGER_EVENT) - { - RTMPMoveMemory(Tab->EventA[Tab->EventANo].BSSID, pBssid, 6); - Tab->EventA[Tab->EventANo].bValid = TRUE; - Tab->EventA[Tab->EventANo].Channel = ChannelNo; - Tab->EventA[Tab->EventANo].CDCounter = pAd->CommonCfg.Dot11BssWidthChanTranDelay; - if (RegClass != 0) - { - // Beacon has Regulatory class IE. So use beacon's - Tab->EventA[Tab->EventANo].RegClass = RegClass; - } - else - { - // Use Station's Regulatory class instead. - if (pAd->StaActive.SupportedHtPhy.bHtEnable == TRUE) - { - if (pAd->CommonCfg.CentralChannel > pAd->CommonCfg.Channel) - { - Tab->EventA[Tab->EventANo].RegClass = 32; - } - else if (pAd->CommonCfg.CentralChannel < pAd->CommonCfg.Channel) - Tab->EventA[Tab->EventANo].RegClass = 33; - } - else - Tab->EventA[Tab->EventANo].RegClass = ??; - - } - - Tab->EventANo ++; - } - } - else if (pHtCapability->HtCapInfo.Intolerant40) - { - Tab->EventBCountDown = pAd->CommonCfg.Dot11BssWidthChanTranDelay; - } - -} - -/* - ======================================================================== - Routine Description: - Trigger Event table Maintainence called once every second. - - Arguments: - // IRQL = DISPATCH_LEVEL - ======================================================================== -*/ -VOID TriEventCounterMaintenance( - IN PRTMP_ADAPTER pAd) -{ - UCHAR i; - BOOLEAN bNotify = FALSE; - for (i = 0;i < MAX_TRIGGER_EVENT;i++) - { - if (pAd->CommonCfg.TriggerEventTab.EventA[i].bValid && (pAd->CommonCfg.TriggerEventTab.EventA[i].CDCounter > 0)) - { - pAd->CommonCfg.TriggerEventTab.EventA[i].CDCounter--; - if (pAd->CommonCfg.TriggerEventTab.EventA[i].CDCounter == 0) - { - pAd->CommonCfg.TriggerEventTab.EventA[i].bValid = FALSE; - pAd->CommonCfg.TriggerEventTab.EventANo --; - // Need to send 20/40 Coexistence Notify frame if has status change. - bNotify = TRUE; - } - } - } - if (pAd->CommonCfg.TriggerEventTab.EventBCountDown > 0) - { - pAd->CommonCfg.TriggerEventTab.EventBCountDown--; - if (pAd->CommonCfg.TriggerEventTab.EventBCountDown == 0) - bNotify = TRUE; - } - - if (bNotify == TRUE) - Update2040CoexistFrameAndNotify(pAd, BSSID_WCID, TRUE); -} -#endif // DOT11N_DRAFT3 // -#endif // DOT11_N_SUPPORT // - // IRQL = DISPATCH_LEVEL VOID BssTableSsidSort( IN PRTMP_ADAPTER pAd, @@ -4079,9 +3912,6 @@ VOID BssTableSsidSort( if (((pAd->CommonCfg.bIEEE80211H == 1) && (pAd->MlmeAux.Channel > 14) && RadarChannelCheck(pAd, pInBss->Channel)) -#ifdef CARRIER_DETECTION_SUPPORT // Roger sync Carrier - || (pAd->CommonCfg.CarrierDetect.Enable == TRUE) -#endif // CARRIER_DETECTION_SUPPORT // ) { if (pInBss->Hidden) @@ -4093,18 +3923,6 @@ VOID BssTableSsidSort( { BSS_ENTRY *pOutBss = &OutTab->BssEntry[OutTab->BssNr]; - -#ifdef EXT_BUILD_CHANNEL_LIST - // If no Country IE exists no Connection will be established when IEEE80211dClientMode is strict. - if ((pAd->StaCfg.IEEE80211dClientMode == Rt802_11_D_Strict) && - (pInBss->bHasCountryIE == FALSE)) - { - DBGPRINT(RT_DEBUG_TRACE,("StaCfg.IEEE80211dClientMode == Rt802_11_D_Strict, but this AP doesn't have country IE.\n")); - continue; - } -#endif // EXT_BUILD_CHANNEL_LIST // - -#ifdef DOT11_N_SUPPORT // 2.4G/5G N only mode if ((pInBss->HtCapabilityLen == 0) && ((pAd->CommonCfg.PhyMode == PHY_11N_2_4G) || (pAd->CommonCfg.PhyMode == PHY_11N_5G))) @@ -4112,7 +3930,6 @@ VOID BssTableSsidSort( DBGPRINT(RT_DEBUG_TRACE,("STA is in N-only Mode, this AP don't have Ht capability in Beacon.\n")); continue; } -#endif // DOT11_N_SUPPORT // // New for WPA2 // Check the Authmode first @@ -4132,9 +3949,14 @@ VOID BssTableSsidSort( continue; // check group cipher +#ifndef RT30xx if ((pAd->StaCfg.WepStatus < pInBss->WPA.GroupCipher) && (pInBss->WPA.GroupCipher != Ndis802_11GroupWEP40Enabled) && (pInBss->WPA.GroupCipher != Ndis802_11GroupWEP104Enabled)) +#endif +#ifdef RT30xx + if (pAd->StaCfg.WepStatus < pInBss->WPA.GroupCipher) +#endif continue; // check pairwise cipher, skip if none matched @@ -4153,9 +3975,14 @@ VOID BssTableSsidSort( continue; // check group cipher +#ifndef RT30xx if ((pAd->StaCfg.WepStatus < pInBss->WPA.GroupCipher) && (pInBss->WPA2.GroupCipher != Ndis802_11GroupWEP40Enabled) && (pInBss->WPA2.GroupCipher != Ndis802_11GroupWEP104Enabled)) +#endif +#ifdef RT30xx + if (pAd->StaCfg.WepStatus < pInBss->WPA2.GroupCipher) +#endif continue; // check pairwise cipher, skip if none matched @@ -4185,7 +4012,6 @@ VOID BssTableSsidSort( if (SsidLen == 0) continue; -#ifdef DOT11_N_SUPPORT // If both station and AP use 40MHz, still need to check if the 40MHZ band's legality in my country region // If this 40MHz wideband is not allowed in my country list, use bandwidth 20MHZ instead, if ((pInBss->CentralChannel != pInBss->Channel) && @@ -4205,7 +4031,6 @@ VOID BssTableSsidSort( } } } -#endif // DOT11_N_SUPPORT // // copy matching BSS from InTab to OutTab NdisMoveMemory(pOutBss, pInBss, sizeof(BSS_ENTRY)); @@ -4216,8 +4041,6 @@ VOID BssTableSsidSort( { BSS_ENTRY *pOutBss = &OutTab->BssEntry[OutTab->BssNr]; - -#ifdef DOT11_N_SUPPORT // 2.4G/5G N only mode if ((pInBss->HtCapabilityLen == 0) && ((pAd->CommonCfg.PhyMode == PHY_11N_2_4G) || (pAd->CommonCfg.PhyMode == PHY_11N_5G))) @@ -4225,7 +4048,6 @@ VOID BssTableSsidSort( DBGPRINT(RT_DEBUG_TRACE,("STA is in N-only Mode, this AP don't have Ht capability in Beacon.\n")); continue; } -#endif // DOT11_N_SUPPORT // // New for WPA2 // Check the Authmode first @@ -4281,7 +4103,6 @@ VOID BssTableSsidSort( else if (pAd->StaCfg.WepStatus != pInBss->WepStatus) continue; -#ifdef DOT11_N_SUPPORT // If both station and AP use 40MHz, still need to check if the 40MHZ band's legality in my country region // If this 40MHz wideband is not allowed in my country list, use bandwidth 20MHZ instead, if ((pInBss->CentralChannel != pInBss->Channel) && @@ -4294,7 +4115,6 @@ VOID BssTableSsidSort( pAd->CommonCfg.RegTransmitSetting.field.BW = BW_40; } } -#endif // DOT11_N_SUPPORT // // copy matching BSS from InTab to OutTab NdisMoveMemory(pOutBss, pInBss, sizeof(BSS_ENTRY)); @@ -4330,8 +4150,6 @@ VOID BssTableSortByRssi( } } } -#endif // CONFIG_STA_SUPPORT // - VOID BssCipherParse( IN OUT PBSS_ENTRY pBss) @@ -4442,10 +4260,16 @@ VOID BssCipherParse( switch (*pTmp) { case 1: +#ifndef RT30xx pBss->WPA.GroupCipher = Ndis802_11GroupWEP40Enabled; break; case 5: pBss->WPA.GroupCipher = Ndis802_11GroupWEP104Enabled; +#endif +#ifdef RT30xx + case 5: // Although WEP is not allowed in WPA related auth mode, we parse it anyway + pBss->WPA.GroupCipher = Ndis802_11Encryption1Enabled; +#endif break; case 2: pBss->WPA.GroupCipher = Ndis802_11Encryption2Enabled; @@ -4532,7 +4356,6 @@ VOID BssCipherParse( pBss->AuthMode = Ndis802_11AuthModeWPANone; pBss->AuthModeAux = Ndis802_11AuthModeWPANone; pBss->WepStatus = pBss->WPA.GroupCipher; - // Patched bugs for old driver if (pBss->WPA.PairCipherAux == Ndis802_11WEPDisabled) pBss->WPA.PairCipherAux = pBss->WPA.GroupCipher; } @@ -4562,10 +4385,16 @@ VOID BssCipherParse( switch (pCipher->Type) { case 1: +#ifndef RT30xx pBss->WPA2.GroupCipher = Ndis802_11GroupWEP40Enabled; break; case 5: pBss->WPA2.GroupCipher = Ndis802_11GroupWEP104Enabled; +#endif +#ifdef RT30xx + case 5: // Although WEP is not allowed in WPA related auth mode, we parse it anyway + pBss->WPA2.GroupCipher = Ndis802_11Encryption1Enabled; +#endif break; case 2: pBss->WPA2.GroupCipher = Ndis802_11Encryption2Enabled; @@ -4659,7 +4488,6 @@ VOID BssCipherParse( pBss->WPA.PairCipherAux = pBss->WPA2.PairCipherAux; pBss->WPA.GroupCipher = pBss->WPA2.GroupCipher; pBss->WepStatus = pBss->WPA.GroupCipher; - // Patched bugs for old driver if (pBss->WPA.PairCipherAux == Ndis802_11WEPDisabled) pBss->WPA.PairCipherAux = pBss->WPA.GroupCipher; } @@ -4735,10 +4563,9 @@ VOID MgtMacHeaderInit( pHdr80211->FC.SubType = SubType; pHdr80211->FC.ToDs = ToDs; COPY_MAC_ADDR(pHdr80211->Addr1, pDA); -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - COPY_MAC_ADDR(pHdr80211->Addr2, pAd->CurrentAddress); -#endif // CONFIG_STA_SUPPORT // + + COPY_MAC_ADDR(pHdr80211->Addr2, pAd->CurrentAddress); + COPY_MAC_ADDR(pHdr80211->Addr3, pBssid); } @@ -4925,12 +4752,6 @@ BOOLEAN MlmeEnqueueForRecv( INT MsgType; MLME_QUEUE *Queue = (MLME_QUEUE *)&pAd->Mlme.Queue; -#ifdef RALINK_ATE - /* Nothing to do in ATE mode */ - if(ATE_ON(pAd)) - return FALSE; -#endif // RALINK_ATE // - // Do nothing if the driver is starting halt state. // This might happen when timer already been fired before cancel timer with mlmehalt if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) @@ -4951,8 +4772,6 @@ BOOLEAN MlmeEnqueueForRecv( return FALSE; } -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { if (!MsgTypeSubst(pAd, pFrame, &Machine, &MsgType)) { @@ -4960,7 +4779,6 @@ BOOLEAN MlmeEnqueueForRecv( return FALSE; } } -#endif // CONFIG_STA_SUPPORT // // OK, we got all the informations, it is time to put things into queue NdisAcquireSpinLock(&(Queue->Lock)); @@ -5028,13 +4846,14 @@ BOOLEAN MlmeDequeue( VOID MlmeRestartStateMachine( IN PRTMP_ADAPTER pAd) { +#ifdef RT2860 MLME_QUEUE_ELEM *Elem = NULL; -#ifdef CONFIG_STA_SUPPORT +#endif BOOLEAN Cancelled; -#endif // CONFIG_STA_SUPPORT // DBGPRINT(RT_DEBUG_TRACE, ("MlmeRestartStateMachine \n")); +#ifdef RT2860 NdisAcquireSpinLock(&pAd->Mlme.TaskLock); if(pAd->Mlme.bRunning) { @@ -5062,13 +4881,9 @@ VOID MlmeRestartStateMachine( DBGPRINT_ERR(("MlmeRestartStateMachine: MlmeQueue empty\n")); } } +#endif /* RT2860 */ -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { -#ifdef QOS_DLS_SUPPORT - UCHAR i; -#endif // QOS_DLS_SUPPORT // // Cancel all timer events // Be careful to cancel new added timer RTMPCancelTimer(&pAd->MlmeAux.AssocTimer, &Cancelled); @@ -5077,15 +4892,7 @@ VOID MlmeRestartStateMachine( RTMPCancelTimer(&pAd->MlmeAux.AuthTimer, &Cancelled); RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer, &Cancelled); RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &Cancelled); - -#ifdef QOS_DLS_SUPPORT - for (i=0; iStaCfg.DLSEntry[i].Timer, &Cancelled); - } -#endif // QOS_DLS_SUPPORT // } -#endif // CONFIG_STA_SUPPORT // // Change back to original channel in case of doing scan AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); @@ -5094,8 +4901,6 @@ VOID MlmeRestartStateMachine( // Resume MSDU which is turned off durning scan RTMPResumeMsduTransmission(pAd); -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { // Set all state machines back IDLE pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; @@ -5104,16 +4909,14 @@ VOID MlmeRestartStateMachine( pAd->Mlme.AuthRspMachine.CurrState = AUTH_RSP_IDLE; pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; pAd->Mlme.ActMachine.CurrState = ACT_IDLE; -#ifdef QOS_DLS_SUPPORT - pAd->Mlme.DlsMachine.CurrState = DLS_IDLE; -#endif // QOS_DLS_SUPPORT // } -#endif // CONFIG_STA_SUPPORT // +#ifdef RT2860 // Remove running state NdisAcquireSpinLock(&pAd->Mlme.TaskLock); pAd->Mlme.bRunning = FALSE; NdisReleaseSpinLock(&pAd->Mlme.TaskLock); +#endif } /*! \brief test if the MLME Queue is empty @@ -5191,7 +4994,6 @@ VOID MlmeQueueDestroy( IRQL = DISPATCH_LEVEL */ -#ifdef CONFIG_STA_SUPPORT BOOLEAN MsgTypeSubst( IN PRTMP_ADAPTER pAd, IN PFRAME_802_11 pFrame, @@ -5215,16 +5017,6 @@ BOOLEAN MsgTypeSubst( *MsgType = MT2_AIRONET_MSG; return (TRUE); } -#ifdef LEAP_SUPPORT - if ( pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP ) //LEAP - { - // LEAP frames - *Machine = LEAP_STATE_MACHINE; - EAPType = *((UCHAR*)pFrame + LENGTH_802_11 + LENGTH_802_1_H + 1); - return (LeapMsgTypeSubst(EAPType, MsgType)); - } - else -#endif // LEAP_SUPPORT // { *Machine = WPA_PSK_STATE_MACHINE; EAPType = *((UCHAR*)pFrame + LENGTH_802_11 + LENGTH_802_1_H + 1); @@ -5311,7 +5103,6 @@ BOOLEAN MsgTypeSubst( return TRUE; } -#endif // CONFIG_STA_SUPPORT // // =========================================================================================== // state_machine.c @@ -5533,7 +5324,6 @@ VOID AsicUpdateAutoFallBackTable( } } break; -#ifdef DOT11_N_SUPPORT case 2: //HT-MIX case 3: //HT-GF { @@ -5595,7 +5385,6 @@ VOID AsicUpdateAutoFallBackTable( } } break; -#endif // DOT11_N_SUPPORT // } pNextTxRate = pCurrTxRate; @@ -5637,12 +5426,6 @@ VOID AsicUpdateProtect( UCHAR i; UINT32 MacReg = 0; -#ifdef RALINK_ATE - if (ATE_ON(pAd)) - return; -#endif // RALINK_ATE // - -#ifdef DOT11_N_SUPPORT if (!(pAd->CommonCfg.bHTProtect) && (OperationMode != 8)) { return; @@ -5656,19 +5439,14 @@ VOID AsicUpdateProtect( SetMask = ALLN_SETPROTECT; OperationMode = 8; } -#endif // DOT11_N_SUPPORT // // Config ASIC RTS threshold register RTMP_IO_READ32(pAd, TX_RTS_CFG, &MacReg); MacReg &= 0xFF0000FF; -#if 0 - MacReg |= (pAd->CommonCfg.RtsThreshold << 8); -#else - // If the user want disable RtsThreshold and enbale Amsdu/Ralink-Aggregation, set the RtsThreshold as 4096 + + // If the user want disable RtsThreshold and enable Amsdu/Ralink-Aggregation, set the RtsThreshold as 4096 if (( -#ifdef DOT11_N_SUPPORT (pAd->CommonCfg.BACapability.field.AmsduEnable) || -#endif // DOT11_N_SUPPORT // (pAd->CommonCfg.bAggregationCapable == TRUE)) && pAd->CommonCfg.RtsThreshold == MAX_RTS_THRESHOLD) { @@ -5678,7 +5456,6 @@ VOID AsicUpdateProtect( { MacReg |= (pAd->CommonCfg.RtsThreshold << 8); } -#endif RTMP_IO_WRITE32(pAd, TX_RTS_CFG, MacReg); @@ -5717,7 +5494,6 @@ VOID AsicUpdateProtect( Protect[1] = ProtCfg.word; } -#ifdef DOT11_N_SUPPORT // Decide HT frame protection. if ((SetMask & ALLN_SETPROTECT) != 0) { @@ -5848,7 +5624,6 @@ VOID AsicUpdateProtect( break; } } -#endif // DOT11_N_SUPPORT // offset = CCK_PROT_CFG; for (i = 0;i < 6;i++) @@ -5860,6 +5635,276 @@ VOID AsicUpdateProtect( } } +#ifdef RT30xx +/* + ======================================================================== + + Routine Description: Write RT30xx RF register through MAC + + Arguments: + + Return Value: + + IRQL = + + Note: + + ======================================================================== +*/ +NTSTATUS RT30xxWriteRFRegister( + IN PRTMP_ADAPTER pAd, + IN UCHAR RegID, + IN UCHAR Value) +{ + RF_CSR_CFG_STRUC rfcsr; + UINT i = 0; + + do + { + RTMP_IO_READ32(pAd, RF_CSR_CFG, &rfcsr.word); + + if (!rfcsr.field.RF_CSR_KICK) + break; + i++; + } + while ((i < RETRY_LIMIT) && (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))); + + if ((i == RETRY_LIMIT) || (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))) + { + DBGPRINT_RAW(RT_DEBUG_ERROR, ("Retry count exhausted or device removed!!!\n")); + return STATUS_UNSUCCESSFUL; + } + + rfcsr.field.RF_CSR_WR = 1; + rfcsr.field.RF_CSR_KICK = 1; + rfcsr.field.TESTCSR_RFACC_REGNUM = RegID; + rfcsr.field.RF_CSR_DATA = Value; + + RTMP_IO_WRITE32(pAd, RF_CSR_CFG, rfcsr.word); + + return STATUS_SUCCESS; +} + + +/* + ======================================================================== + + Routine Description: Read RT30xx RF register through MAC + + Arguments: + + Return Value: + + IRQL = + + Note: + + ======================================================================== +*/ +NTSTATUS RT30xxReadRFRegister( + IN PRTMP_ADAPTER pAd, + IN UCHAR RegID, + IN PUCHAR pValue) +{ + RF_CSR_CFG_STRUC rfcsr; + UINT i=0, k=0; + + for (i=0; iMACVersion & 0xffff) >= 0x0211) && (pAd->NicConfig2.field.ExternalLNAForG == 0)) + { + RFValue |= 0x20; + } + RT30xxWriteRFRegister(pAd, RF_R17, RFValue); + + // RX_LO1_en, RF R20 register Bit 3 to 0 + RT30xxReadRFRegister(pAd, RF_R20, &RFValue); + RFValue &= (~0x08); + RT30xxWriteRFRegister(pAd, RF_R20, RFValue); + + // RX_LO2_en, RF R21 register Bit 3 to 0 + RT30xxReadRFRegister(pAd, RF_R21, &RFValue); + RFValue &= (~0x08); + RT30xxWriteRFRegister(pAd, RF_R21, RFValue); + + // LDORF_VC, RF R27 register Bit 2 to 0 + RT30xxReadRFRegister(pAd, RF_R27, &RFValue); + if ((pAd->MACVersion & 0xffff) < 0x0211) + RFValue = (RFValue & (~0x77)) | 0x3; + else + RFValue = (RFValue & (~0x77)); + RT30xxWriteRFRegister(pAd, RF_R27, RFValue); + /* end johnli */ +} + +/* + ========================================================================== + Description: + + Load RF sleep-mode setup + + ========================================================================== + */ +VOID RT30xxLoadRFSleepModeSetup( + IN PRTMP_ADAPTER pAd) +{ + UCHAR RFValue; + UINT32 MACValue; + + // RF_BLOCK_en. RF R1 register Bit 0 to 0 + RT30xxReadRFRegister(pAd, RF_R01, &RFValue); + RFValue &= (~0x01); + RT30xxWriteRFRegister(pAd, RF_R01, RFValue); + + // VCO_IC, RF R7 register Bit 4 & Bit 5 to 0 + RT30xxReadRFRegister(pAd, RF_R07, &RFValue); + RFValue &= (~0x30); + RT30xxWriteRFRegister(pAd, RF_R07, RFValue); + + // Idoh, RF R9 register Bit 1, Bit 2 & Bit 3 to 0 + RT30xxReadRFRegister(pAd, RF_R09, &RFValue); + RFValue &= (~0x0E); + RT30xxWriteRFRegister(pAd, RF_R09, RFValue); + + // RX_CTB_en, RF R21 register Bit 7 to 0 + RT30xxReadRFRegister(pAd, RF_R21, &RFValue); + RFValue &= (~0x80); + RT30xxWriteRFRegister(pAd, RF_R21, RFValue); + + // LDORF_VC, RF R27 register Bit 0, Bit 1 & Bit 2 to 1 + RT30xxReadRFRegister(pAd, RF_R27, &RFValue); + RFValue |= 0x77; + RT30xxWriteRFRegister(pAd, RF_R27, RFValue); + + RTMP_IO_READ32(pAd, LDO_CFG0, &MACValue); + MACValue |= 0x1D000000; + RTMP_IO_WRITE32(pAd, LDO_CFG0, MACValue); +} + +/* + ========================================================================== + Description: + + Reverse RF sleep-mode setup + + ========================================================================== + */ +VOID RT30xxReverseRFSleepModeSetup( + IN PRTMP_ADAPTER pAd) +{ + UCHAR RFValue; + UINT32 MACValue; + + // RF_BLOCK_en, RF R1 register Bit 0 to 1 + RT30xxReadRFRegister(pAd, RF_R01, &RFValue); + RFValue |= 0x01; + RT30xxWriteRFRegister(pAd, RF_R01, RFValue); + + // VCO_IC, RF R7 register Bit 4 & Bit 5 to 1 + RT30xxReadRFRegister(pAd, RF_R07, &RFValue); + RFValue |= 0x30; + RT30xxWriteRFRegister(pAd, RF_R07, RFValue); + + // Idoh, RF R9 register Bit 1, Bit 2 & Bit 3 to 1 + RT30xxReadRFRegister(pAd, RF_R09, &RFValue); + RFValue |= 0x0E; + RT30xxWriteRFRegister(pAd, RF_R09, RFValue); + + // RX_CTB_en, RF R21 register Bit 7 to 1 + RT30xxReadRFRegister(pAd, RF_R21, &RFValue); + RFValue |= 0x80; + RT30xxWriteRFRegister(pAd, RF_R21, RFValue); + + // LDORF_VC, RF R27 register Bit 2 to 0 + RT30xxReadRFRegister(pAd, RF_R27, &RFValue); + if ((pAd->MACVersion & 0xffff) < 0x0211) + RFValue = (RFValue & (~0x77)) | 0x3; + else + RFValue = (RFValue & (~0x77)); + RT30xxWriteRFRegister(pAd, RF_R27, RFValue); + + // RT3071 version E has fixed this issue + if ((pAd->NicConfig2.field.DACTestBit == 1) && ((pAd->MACVersion & 0xffff) < 0x0211)) + { + // patch tx EVM issue temporarily + RTMP_IO_READ32(pAd, LDO_CFG0, &MACValue); + MACValue = ((MACValue & 0xE0FFFFFF) | 0x0D000000); + RTMP_IO_WRITE32(pAd, LDO_CFG0, MACValue); + } + else + { + RTMP_IO_READ32(pAd, LDO_CFG0, &MACValue); + MACValue = ((MACValue & 0xE0FFFFFF) | 0x01000000); + RTMP_IO_WRITE32(pAd, LDO_CFG0, MACValue); + } +} +// end johnli +#endif // RT30xx // + /* ========================================================================== Description: @@ -5881,6 +5926,21 @@ VOID AsicSwitchChannel( RTMP_RF_REGS *RFRegTable; // Search Tx power value +#ifdef RT30xx + // We can't use ChannelList to search channel, since some central channl's txpowr doesn't list + // in ChannelList, so use TxPower array instead. + // + for (index = 0; index < MAX_NUM_OF_CHANNELS; index++) + { + if (Channel == pAd->TxPower[index].Channel) + { + TxPwer = pAd->TxPower[index].Power; + TxPwer2 = pAd->TxPower[index].Power2; + break; + } + } +#endif +#ifndef RT30xx for (index = 0; index < pAd->ChannelListNum; index++) { if (Channel == pAd->ChannelList[index].Channel) @@ -5890,12 +5950,152 @@ VOID AsicSwitchChannel( break; } } +#endif if (index == MAX_NUM_OF_CHANNELS) { +#ifndef RT30xx DBGPRINT(RT_DEBUG_ERROR, ("AsicSwitchChannel: Cant find the Channel#%d \n", Channel)); +#endif +#ifdef RT30xx + DBGPRINT(RT_DEBUG_ERROR, ("AsicSwitchChannel: Can't find the Channel#%d \n", Channel)); +#endif } +#ifdef RT2870 + // The RF programming sequence is difference between 3xxx and 2xxx +#ifdef RT30xx + if ((IS_RT3070(pAd) || IS_RT3090(pAd)) && ((pAd->RfIcType == RFIC_3020) || (pAd->RfIcType == RFIC_2020) || + (pAd->RfIcType == RFIC_3021) || (pAd->RfIcType == RFIC_3022))) +#endif +#ifndef RT30xx + if (IS_RT3070(pAd) && ((pAd->RfIcType == RFIC_3020) || (pAd->RfIcType == RFIC_2020))) +#endif + { + /* modify by WY for Read RF Reg. error */ + UCHAR RFValue; + + for (index = 0; index < NUM_OF_3020_CHNL; index++) + { + if (Channel == FreqItems3020[index].Channel) + { + // Programming channel parameters + RT30xxWriteRFRegister(pAd, RF_R02, FreqItems3020[index].N); + RT30xxWriteRFRegister(pAd, RF_R03, FreqItems3020[index].K); + +#ifndef RT30xx + RT30xxReadRFRegister(pAd, RF_R06, (PUCHAR)&RFValue); + RFValue = (RFValue & 0xFC) | FreqItems3020[index].R; + RT30xxWriteRFRegister(pAd, RF_R06, (UCHAR)RFValue); + + // Set Tx Power + RT30xxReadRFRegister(pAd, RF_R12, (PUCHAR)&RFValue); + RFValue = (RFValue & 0xE0) | TxPwer; + RT30xxWriteRFRegister(pAd, RF_R12, (UCHAR)RFValue); + + // Set RF offset + RT30xxReadRFRegister(pAd, RF_R23, (PUCHAR)&RFValue); + RFValue = (RFValue & 0x80) | pAd->RfFreqOffset; + RT30xxWriteRFRegister(pAd, RF_R23, (UCHAR)RFValue); +#endif +#ifdef RT30xx + RT30xxReadRFRegister(pAd, RF_R06, &RFValue); + RFValue = (RFValue & 0xFC) | FreqItems3020[index].R; + RT30xxWriteRFRegister(pAd, RF_R06, RFValue); + + // Set Tx0 Power + RT30xxReadRFRegister(pAd, RF_R12, &RFValue); + RFValue = (RFValue & 0xE0) | TxPwer; + RT30xxWriteRFRegister(pAd, RF_R12, RFValue); + + // Set Tx1 Power + RT30xxReadRFRegister(pAd, RF_R13, &RFValue); + RFValue = (RFValue & 0xE0) | TxPwer2; + RT30xxWriteRFRegister(pAd, RF_R13, RFValue); + + // Tx/Rx Stream setting + RT30xxReadRFRegister(pAd, RF_R01, &RFValue); + //if (IS_RT3090(pAd)) + // RFValue |= 0x01; // Enable RF block. + RFValue &= 0x03; //clear bit[7~2] + if (pAd->Antenna.field.TxPath == 1) + RFValue |= 0xA0; + else if (pAd->Antenna.field.TxPath == 2) + RFValue |= 0x80; + if (pAd->Antenna.field.RxPath == 1) + RFValue |= 0x50; + else if (pAd->Antenna.field.RxPath == 2) + RFValue |= 0x40; + RT30xxWriteRFRegister(pAd, RF_R01, RFValue); + + // Set RF offset + RT30xxReadRFRegister(pAd, RF_R23, &RFValue); + RFValue = (RFValue & 0x80) | pAd->RfFreqOffset; + RT30xxWriteRFRegister(pAd, RF_R23, RFValue); +#endif + + // Set BW + if (!bScan && (pAd->CommonCfg.BBPCurrentBW == BW_40)) + { + RFValue = pAd->Mlme.CaliBW40RfR24; + //DISABLE_11N_CHECK(pAd); + } + else + { + RFValue = pAd->Mlme.CaliBW20RfR24; + } +#ifndef RT30xx + RT30xxWriteRFRegister(pAd, RF_R24, (UCHAR)RFValue); + + // Enable RF tuning + RT30xxReadRFRegister(pAd, RF_R07, (PUCHAR)&RFValue); + RFValue = RFValue | 0x1; + RT30xxWriteRFRegister(pAd, RF_R07, (UCHAR)RFValue); + + // latch channel for future usage. + pAd->LatchRfRegs.Channel = Channel; +#endif +#ifdef RT30xx + RT30xxWriteRFRegister(pAd, RF_R24, RFValue); + RT30xxWriteRFRegister(pAd, RF_R31, RFValue); + + // Enable RF tuning + RT30xxReadRFRegister(pAd, RF_R07, &RFValue); + RFValue = RFValue | 0x1; + RT30xxWriteRFRegister(pAd, RF_R07, RFValue); + + // latch channel for future usage. + pAd->LatchRfRegs.Channel = Channel; + + DBGPRINT(RT_DEBUG_TRACE, ("SwitchChannel#%d(RF=%d, Pwr0=%d, Pwr1=%d, %dT), N=0x%02X, K=0x%02X, R=0x%02X\n", + Channel, + pAd->RfIcType, + TxPwer, + TxPwer2, + pAd->Antenna.field.TxPath, + FreqItems3020[index].N, + FreqItems3020[index].K, + FreqItems3020[index].R)); +#endif + + break; + } + } + +#ifndef RT30xx + DBGPRINT(RT_DEBUG_TRACE, ("SwitchChannel#%d(RF=%d, Pwr0=%d, Pwr1=%d, %dT), N=0x%02X, K=0x%02X, R=0x%02X\n", + Channel, + pAd->RfIcType, + TxPwer, + TxPwer2, + pAd->Antenna.field.TxPath, + FreqItems3020[index].N, + FreqItems3020[index].K, + FreqItems3020[index].R)); +#endif + } + else +#endif // RT2870 // { RFRegTable = RF2850RegTable; @@ -6149,6 +6349,53 @@ VOID AsicAntennaSelect( IN PRTMP_ADAPTER pAd, IN UCHAR Channel) { +#ifdef RT30xx + if (pAd->Mlme.OneSecPeriodicRound % 2 == 1) + { + // patch for AsicSetRxAnt failed + pAd->RxAnt.EvaluatePeriod = 0; + + // check every 2 second. If rcv-beacon less than 5 in the past 2 second, then AvgRSSI is no longer a + // valid indication of the distance between this AP and its clients. + if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) + { + SHORT realavgrssi1; + + // if no traffic then reset average rssi to trigger evaluation + if (pAd->StaCfg.NumOfAvgRssiSample < 5) + { + pAd->RxAnt.Pair1LastAvgRssi = (-99); + pAd->RxAnt.Pair2LastAvgRssi = (-99); + DBGPRINT(RT_DEBUG_TRACE, ("MlmePeriodicExec: no traffic/beacon, reset RSSI\n")); + } + + pAd->StaCfg.NumOfAvgRssiSample = 0; + realavgrssi1 = (pAd->RxAnt.Pair1AvgRssi[pAd->RxAnt.Pair1PrimaryRxAnt] >> 3); + + DBGPRINT(RT_DEBUG_TRACE,("Ant-realrssi0(%d), Lastrssi0(%d), EvaluateStableCnt=%d\n", realavgrssi1, pAd->RxAnt.Pair1LastAvgRssi, pAd->RxAnt.EvaluateStableCnt)); + + // if the difference between two rssi is larger or less than 5, then evaluate the other antenna + if ((pAd->RxAnt.EvaluateStableCnt < 2) || (realavgrssi1 > (pAd->RxAnt.Pair1LastAvgRssi + 5)) || (realavgrssi1 < (pAd->RxAnt.Pair1LastAvgRssi - 5))) + { + pAd->RxAnt.Pair1LastAvgRssi = realavgrssi1; + AsicEvaluateRxAnt(pAd); + } + } + else + { + // if not connected, always switch antenna to try to connect + UCHAR temp; + + temp = pAd->RxAnt.Pair1PrimaryRxAnt; + pAd->RxAnt.Pair1PrimaryRxAnt = pAd->RxAnt.Pair1SecondaryRxAnt; + pAd->RxAnt.Pair1SecondaryRxAnt = temp; + + DBGPRINT(RT_DEBUG_TRACE, ("MlmePeriodicExec: no connect, switch to another one to try connection\n")); + + AsicSetRxAnt(pAd, pAd->RxAnt.Pair1PrimaryRxAnt); + } + } +#endif /* RT30xx */ } /* @@ -6218,11 +6465,13 @@ VOID AsicAdjustTxPower( ULONG TxPwr[5]; CHAR Value; +#ifdef RT2860 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE) || (pAd->bPCIclkOff == TRUE) || RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF) || RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) return; +#endif if (pAd->CommonCfg.BBPCurrentBW == BW_40) { @@ -6364,95 +6613,6 @@ VOID AsicAdjustTxPower( RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R1, &BbpR1); BbpR1 &= 0xFC; -#ifdef SINGLE_SKU - // Handle regulatory max tx power constrain - do - { - UCHAR TxPwrInEEPROM = 0xFF, CountryTxPwr = 0xFF, criterion; - UCHAR AdjustMaxTxPwr[40]; - - if (pAd->CommonCfg.Channel > 14) // 5G band - TxPwrInEEPROM = ((pAd->CommonCfg.DefineMaxTxPwr & 0xFF00) >> 8); - else // 2.4G band - TxPwrInEEPROM = (pAd->CommonCfg.DefineMaxTxPwr & 0x00FF); - CountryTxPwr = GetCuntryMaxTxPwr(pAd, pAd->CommonCfg.Channel); - - // error handling, range check - if ((TxPwrInEEPROM > 0x50) || (CountryTxPwr > 0x50)) - { - DBGPRINT(RT_DEBUG_ERROR,("AsicAdjustTxPower - Invalid max tx power (=0x%02x), CountryTxPwr=%d\n", TxPwrInEEPROM, CountryTxPwr)); - break; - } - - criterion = *((PUCHAR)TxPwr + 2) & 0xF; // FAE use OFDM 6M as criterion - - DBGPRINT_RAW(RT_DEBUG_TRACE,("AsicAdjustTxPower (criterion=%d, TxPwrInEEPROM=%d, CountryTxPwr=%d)\n", criterion, TxPwrInEEPROM, CountryTxPwr)); - - // Adjust max tx power according to the relationship of tx power in E2PROM - for (i=0; i<5; i++) - { - // CCK will have 4dBm larger than OFDM - // Therefore, we should separate to parse the tx power field - if (i == 0) - { - for (j=0; j<8; j++) - { - Value = (CHAR)((TxPwr[i] >> j*4) & 0x0F); - - if (j < 4) - { - // CCK will have 4dBm larger than OFDM - AdjustMaxTxPwr[i*8+j] = TxPwrInEEPROM + (Value - criterion) + 4; - } - else - { - AdjustMaxTxPwr[i*8+j] = TxPwrInEEPROM + (Value - criterion); - } - DBGPRINT_RAW(RT_DEBUG_TRACE,("AsicAdjustTxPower (i/j=%d/%d, Value=%d, %d)\n", i, j, Value, AdjustMaxTxPwr[i*8+j])); - } - } - else - { - for (j=0; j<8; j++) - { - Value = (CHAR)((TxPwr[i] >> j*4) & 0x0F); - - AdjustMaxTxPwr[i*8+j] = TxPwrInEEPROM + (Value - criterion); - DBGPRINT_RAW(RT_DEBUG_TRACE,("AsicAdjustTxPower (i/j=%d/%d, Value=%d, %d)\n", i, j, Value, AdjustMaxTxPwr[i*8+j])); - } - } - } - - // Adjust tx power according to the relationship - for (i=0; i<5; i++) - { - if (TxPwr[i] != 0xffffffff) - { - for (j=0; j<8; j++) - { - Value = (CHAR)((TxPwr[i] >> j*4) & 0x0F); - - // The system tx power is larger than the regulatory, the power should be restrain - if (AdjustMaxTxPwr[i*8+j] > CountryTxPwr) - { - // decrease to zero and don't need to take care BBPR1 - if ((Value - (AdjustMaxTxPwr[i*8+j] - CountryTxPwr)) > 0) - Value -= (AdjustMaxTxPwr[i*8+j] - CountryTxPwr); - else - Value = 0; - - DBGPRINT_RAW(RT_DEBUG_TRACE,("AsicAdjustTxPower (i/j=%d/%d, Value=%d, %d)\n", i, j, Value, AdjustMaxTxPwr[i*8+j])); - } - else - DBGPRINT_RAW(RT_DEBUG_TRACE,("AsicAdjustTxPower (i/j=%d/%d, Value=%d, %d, no change)\n", i, j, Value, AdjustMaxTxPwr[i*8+j])); - - TxPwr[i] = (TxPwr[i] & ~(0x0000000F << j*4)) | (Value << j*4); - } - } - } - } while (FALSE); -#endif // SINGLE_SKU // - /* calculate delta power based on the percentage specified from UI */ // E2PROM setting is calibrated for maximum TX power (i.e. 100%) // We lower TX power here according to the percentage specified from UI @@ -6522,7 +6682,6 @@ VOID AsicAdjustTxPower( } -#ifdef CONFIG_STA_SUPPORT /* ========================================================================== Description: @@ -6568,12 +6727,22 @@ VOID AsicForceSleep( */ VOID AsicForceWakeup( IN PRTMP_ADAPTER pAd, +#ifdef RT2860 IN UCHAR Level) +#endif +#ifdef RT2870 + IN BOOLEAN bFromTx) +#endif { DBGPRINT(RT_DEBUG_TRACE, ("--> AsicForceWakeup \n")); +#ifdef RT2860 RT28XX_STA_FORCE_WAKEUP(pAd, Level); +#endif +#ifdef RT2870 + RT28XX_STA_FORCE_WAKEUP(pAd, bFromTx); +#endif } -#endif // CONFIG_STA_SUPPORT // + /* ========================================================================== Description: @@ -6688,9 +6857,7 @@ VOID AsicDisableRDG( Data &= 0xFFFFFF00; if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_DYNAMIC_BE_TXOP_ACTIVE) -#ifdef DOT11_N_SUPPORT && (pAd->MacTab.fAnyStationMIMOPSDynamic == FALSE) -#endif // DOT11_N_SUPPORT // ) { // For CWC test, change txop from 0x30 to 0x20 in TxBurst mode @@ -6745,8 +6912,7 @@ VOID AsicEnableBssSync( DBGPRINT(RT_DEBUG_TRACE, ("--->AsicEnableBssSync(INFRA mode)\n")); RTMP_IO_READ32(pAd, BCN_TIME_CFG, &csr.word); -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) + { csr.field.BeaconInterval = pAd->CommonCfg.BeaconPeriod << 4; // ASIC register in units of 1/16 TU csr.field.bTsfTicking = 1; @@ -6754,7 +6920,7 @@ VOID AsicEnableBssSync( csr.field.bBeaconGen = 0; // do NOT generate BEACON csr.field.bTBTTEnable = 1; } -#endif // CONFIG_STA_SUPPORT // + RTMP_IO_WRITE32(pAd, BCN_TIME_CFG, csr.word); } @@ -6785,6 +6951,7 @@ VOID AsicEnableIbssSync( csr9.field.bTsfTicking = 0; RTMP_IO_WRITE32(pAd, BCN_TIME_CFG, csr9.word); +#ifdef RT2860 // move BEACON TXD and frame content to on-chip memory ptr = (PUCHAR)&pAd->BeaconTxWI; for (i=0; iBeaconTxWI; + for (i=0; iBeaconBuf; + for (i=0; i< pAd->BeaconTxWI.MPDUtotalByteCount; i+=2) + { + RTUSBMultiWrite(pAd, HW_BEACON_BASE0 + TXWI_SIZE + i, ptr, 2); + ptr +=2; + } +#endif // RT2870 // // start sending BEACON csr9.field.BeaconInterval = pAd->CommonCfg.BeaconPeriod << 4; // ASIC register in units of 1/16 TU @@ -6949,8 +7134,7 @@ VOID AsicSetEdcaParm( Ac2Cfg.field.Cwmin = pEdcaParm->Cwmin[QID_AC_VI]; Ac2Cfg.field.Cwmax = pEdcaParm->Cwmax[QID_AC_VI]; Ac2Cfg.field.Aifsn = pEdcaParm->Aifsn[QID_AC_VI]; -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) + { // Tuning for Wi-Fi WMM S06 if (pAd->CommonCfg.bWiFiTest && @@ -6958,15 +7142,22 @@ VOID AsicSetEdcaParm( Ac2Cfg.field.Aifsn -= 1; // Tuning for TGn Wi-Fi 5.2.32 - // STA TestBed changes in this item: conexant legacy sta ==> broadcom 11n sta + // STA TestBed changes in this item: connexant legacy sta ==> broadcom 11n sta if (STA_TGN_WIFI_ON(pAd) && pEdcaParm->Aifsn[QID_AC_VI] == 10) { Ac0Cfg.field.Aifsn = 3; Ac2Cfg.field.AcTxop = 5; } + +#ifdef RT30xx + if (pAd->RfIcType == RFIC_3020 || pAd->RfIcType == RFIC_2020) + { + // Tuning for WiFi WMM S3-T07: connexant legacy sta ==> broadcom 11n sta. + Ac2Cfg.field.Aifsn = 5; + } +#endif // RT30xx // } -#endif // CONFIG_STA_SUPPORT // Ac3Cfg.field.AcTxop = pEdcaParm->Txop[QID_AC_VO]; Ac3Cfg.field.Cwmin = pEdcaParm->Cwmin[QID_AC_VO]; @@ -7008,10 +7199,9 @@ VOID AsicSetEdcaParm( CwminCsr.field.Cwmin0 = pEdcaParm->Cwmin[QID_AC_BE]; CwminCsr.field.Cwmin1 = pEdcaParm->Cwmin[QID_AC_BK]; CwminCsr.field.Cwmin2 = pEdcaParm->Cwmin[QID_AC_VI]; -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - CwminCsr.field.Cwmin3 = pEdcaParm->Cwmin[QID_AC_VO] - 1; //for TGn wifi test -#endif // CONFIG_STA_SUPPORT // + + CwminCsr.field.Cwmin3 = pEdcaParm->Cwmin[QID_AC_VO] - 1; //for TGn wifi test + RTMP_IO_WRITE32(pAd, WMM_CWMIN_CFG, CwminCsr.word); CwmaxCsr.word = 0; @@ -7025,8 +7215,7 @@ VOID AsicSetEdcaParm( AifsnCsr.field.Aifsn0 = Ac0Cfg.field.Aifsn; //pEdcaParm->Aifsn[QID_AC_BE]; AifsnCsr.field.Aifsn1 = Ac1Cfg.field.Aifsn; //pEdcaParm->Aifsn[QID_AC_BK]; AifsnCsr.field.Aifsn2 = Ac2Cfg.field.Aifsn; //pEdcaParm->Aifsn[QID_AC_VI]; -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) + { // Tuning for Wi-Fi WMM S06 if (pAd->CommonCfg.bWiFiTest && @@ -7034,20 +7223,25 @@ VOID AsicSetEdcaParm( AifsnCsr.field.Aifsn2 = Ac2Cfg.field.Aifsn - 4; // Tuning for TGn Wi-Fi 5.2.32 - // STA TestBed changes in this item: conexant legacy sta ==> broadcom 11n sta + // STA TestBed changes in this item: connexant legacy sta ==> broadcom 11n sta if (STA_TGN_WIFI_ON(pAd) && pEdcaParm->Aifsn[QID_AC_VI] == 10) { AifsnCsr.field.Aifsn0 = 3; AifsnCsr.field.Aifsn2 = 7; } +#ifdef RT2870 + if (INFRA_ON(pAd)) + CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[BSSID_WCID], fCLIENT_STATUS_WMM_CAPABLE); +#endif } -#endif // CONFIG_STA_SUPPORT // -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - AifsnCsr.field.Aifsn3 = Ac3Cfg.field.Aifsn - 1; //pEdcaParm->Aifsn[QID_AC_VO]; //for TGn wifi test -#endif // CONFIG_STA_SUPPORT // + AifsnCsr.field.Aifsn3 = Ac3Cfg.field.Aifsn - 1; //pEdcaParm->Aifsn[QID_AC_VO]; //for TGn wifi test +#ifdef RT30xx + if (pAd->RfIcType == RFIC_3020 || pAd->RfIcType == RFIC_2020) + AifsnCsr.field.Aifsn2 = 0x2; //pEdcaParm->Aifsn[QID_AC_VI]; //for WiFi WMM S4-T04. +#endif // RT30xx // + RTMP_IO_WRITE32(pAd, WMM_AIFSN_CFG, AifsnCsr.word); NdisMoveMemory(&pAd->CommonCfg.APEdcaParm, pEdcaParm, sizeof(EDCA_PARM)); @@ -7098,10 +7292,8 @@ VOID AsicSetSlotTime( ULONG SlotTime; UINT32 RegValue = 0; -#ifdef CONFIG_STA_SUPPORT if (pAd->CommonCfg.Channel > 14) bUseShortSlotTime = TRUE; -#endif // CONFIG_STA_SUPPORT // if (bUseShortSlotTime) OPSTATUS_SET_FLAG(pAd, fOP_STATUS_SHORT_SLOT_INUSED); @@ -7110,36 +7302,31 @@ VOID AsicSetSlotTime( SlotTime = (bUseShortSlotTime)? 9 : 20; -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { +#ifndef RT30xx // force using short SLOT time for FAE to demo performance when TxBurst is ON if (((pAd->StaActive.SupportedPhyInfo.bHtEnable == FALSE) && (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED))) -#ifdef DOT11_N_SUPPORT || ((pAd->StaActive.SupportedPhyInfo.bHtEnable == TRUE) && (pAd->CommonCfg.BACapability.field.Policy == BA_NOTUSE)) -#endif // DOT11_N_SUPPORT // ) { // In this case, we will think it is doing Wi-Fi test // And we will not set to short slot when bEnableTxBurst is TRUE. } else if (pAd->CommonCfg.bEnableTxBurst) +#endif +#ifdef RT30xx + if (pAd->CommonCfg.bEnableTxBurst) +#endif SlotTime = 9; } -#endif // CONFIG_STA_SUPPORT // // // For some reasons, always set it to short slot time. // // ToDo: Should consider capability with 11B // -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - if (pAd->StaCfg.BssType == BSS_ADHOC) - SlotTime = 20; - } -#endif // CONFIG_STA_SUPPORT // + if (pAd->StaCfg.BssType == BSS_ADHOC) + SlotTime = 20; RTMP_IO_READ32(pAd, BKOFF_SLOT_CFG, &RegValue); RegValue = RegValue & 0xFFFFFF00; @@ -7170,7 +7357,9 @@ VOID AsicAddSharedKeyEntry( { ULONG offset; //, csr0; SHAREDKEY_MODE_STRUC csr1; +#ifdef RT2860 INT i; +#endif DBGPRINT(RT_DEBUG_TRACE, ("AsicAddSharedKeyEntry BssIndex=%d, KeyIdx=%d\n", BssIndex,KeyIdx)); //============================================================================================ @@ -7192,28 +7381,43 @@ VOID AsicAddSharedKeyEntry( // // fill key material - key + TX MIC + RX MIC // + offset = SHARED_KEY_TABLE_BASE + (4*BssIndex + KeyIdx)*HW_KEY_ENTRY_SIZE; +#ifdef RT2860 for (i=0; iTxTsc; UCHAR CipherAlg = pCipherKey->CipherAlg; SHAREDKEY_MODE_STRUC csr1; +#ifdef RT2860 UCHAR i; +#endif DBGPRINT(RT_DEBUG_TRACE, ("==> AsicAddKeyEntry\n")); // @@ -7404,10 +7610,15 @@ VOID AsicAddKeyEntry( // 2.) Set Key to Asic // //for (i = 0; i < KeyLen; i++) +#ifdef RT2860 for (i = 0; i < MAX_LEN_OF_PEER_KEY; i++) { RTMP_IO_WRITE8(pAd, offset + i, pKey[i]); } +#endif +#ifdef RT2870 + RTUSBMultiWrite(pAd, offset, pKey, MAX_LEN_OF_PEER_KEY); +#endif offset += MAX_LEN_OF_PEER_KEY; // @@ -7415,19 +7626,29 @@ VOID AsicAddKeyEntry( // if (pTxMic) { +#ifdef RT2860 for (i = 0; i < 8; i++) { RTMP_IO_WRITE8(pAd, offset + i, pTxMic[i]); } +#endif +#ifdef RT2870 + RTUSBMultiWrite(pAd, offset, pTxMic, 8); +#endif } offset += LEN_TKIP_TXMICK; if (pRxMic) { +#ifdef RT2860 for (i = 0; i < 8; i++) { RTMP_IO_WRITE8(pAd, offset + i, pRxMic[i]); } +#endif +#ifdef RT2870 + RTUSBMultiWrite(pAd, offset, pRxMic, 8); +#endif } @@ -7437,6 +7658,7 @@ VOID AsicAddKeyEntry( // if (bTxKey) { +#ifdef RT2860 offset = MAC_IVEIV_TABLE_BASE + (WCID * HW_IVEIV_ENTRY_SIZE); // // Write IV @@ -7460,6 +7682,26 @@ VOID AsicAddKeyEntry( RTMP_IO_WRITE8(pAd, offset + i, pTxtsc[i + 2]); } +#endif +#ifdef RT2870 + UINT32 tmpVal; + + // + // Write IV + // + IV4 = (KeyIdx << 6); + if ((CipherAlg == CIPHER_TKIP) || (CipherAlg == CIPHER_TKIP_NO_MIC) ||(CipherAlg == CIPHER_AES)) + IV4 |= 0x20; // turn on extension bit means EIV existence + + tmpVal = pTxtsc[1] + (((pTxtsc[1] | 0x20) & 0x7f) << 8) + (pTxtsc[0] << 16) + (IV4 << 24); + RTMP_IO_WRITE32(pAd, offset, tmpVal); + + // + // Write EIV + // + offset += 4; + RTMP_IO_WRITE32(pAd, offset, *(PUINT32)&pCipherKey->TxTsc[2]); +#endif // RT2870 // AsicUpdateWCIDAttribute(pAd, WCID, BssIndex, CipherAlg, bUsePairewiseKeyTable); } @@ -7524,10 +7766,15 @@ VOID AsicAddPairwiseKeyEntry( // EKEY offset = PAIRWISE_KEY_TABLE_BASE + (WCID * HW_KEY_ENTRY_SIZE); +#ifdef RT2860 for (i=0; iKey[0], MAX_LEN_OF_PEER_KEY); +#endif // RT2870 // for (i=0; iTxMic[0], 8); +#endif // RT2870 // } offset += 8; if (pRxMic) { +#ifdef RT2860 for (i=0; i<8; i++) { RTMP_IO_WRITE8(pAd, offset+i, pRxMic[i]); } +#endif +#ifdef RT2870 + RTUSBMultiWrite(pAd, offset, &pCipherKey->RxMic[0], 8); +#endif // RT2870 // } DBGPRINT(RT_DEBUG_TRACE,("AsicAddPairwiseKeyEntry: WCID #%d Alg=%s\n",WCID, CipherName[CipherAlg])); @@ -7599,9 +7856,7 @@ BOOLEAN AsicSendCommandToMcu( HOST_CMD_CSR_STRUC H2MCmd; H2M_MAILBOX_STRUC H2MMailbox; ULONG i = 0; -#ifdef RALINK_ATE - static UINT32 j = 0; -#endif // RALINK_ATE // + do { RTMP_IO_READ32(pAd, H2M_MAILBOX_CSR, &H2MMailbox.word); @@ -7611,33 +7866,10 @@ BOOLEAN AsicSendCommandToMcu( RTMPusecDelay(2); } while(i++ < 100); - if (i >= 100) + if (i > 100) { -#ifdef RALINK_ATE - if (pAd->ate.bFWLoading == TRUE) - { - /* reloading firmware when received iwpriv cmd "ATE=ATESTOP" */ - if (j > 0) - { - if (j % 64 != 0) - { - DBGPRINT(RT_DEBUG_ERROR, ("#")); - } - else - { - DBGPRINT(RT_DEBUG_ERROR, ("\n")); - } - ++j; - } - else if (j == 0) - { - DBGPRINT(RT_DEBUG_ERROR, ("Loading firmware. Please wait for a moment...\n")); - ++j; - } - } - else -#endif // RALINK_ATE // { +#ifdef RT2860 UINT32 Data; // Reset DMA @@ -7659,21 +7891,15 @@ BOOLEAN AsicSendCommandToMcu( RTMP_IO_READ32(pAd, PBF_SYS_CTRL, &Data); Data &= 0xfffffffd; RTMP_IO_WRITE32(pAd, PBF_SYS_CTRL, Data); +#endif /* RT2860 */ DBGPRINT_ERR(("H2M_MAILBOX still hold by MCU. command fail\n")); } //return FALSE; +#ifdef RT2870 + return FALSE; +#endif } -#ifdef RALINK_ATE - else if (pAd->ate.bFWLoading == TRUE) - { - /* reloading of firmware is completed */ - pAd->ate.bFWLoading = FALSE; - DBGPRINT(RT_DEBUG_ERROR, ("\n")); - j = 0; - } -#endif // RALINK_ATE // - H2MMailbox.field.Owner = 1; // pass ownership to MCU H2MMailbox.field.CmdToken = Token; H2MMailbox.field.HighByte = Arg1; @@ -7691,6 +7917,7 @@ BOOLEAN AsicSendCommandToMcu( return TRUE; } +#ifdef RT2860 BOOLEAN AsicCheckCommanOk( IN PRTMP_ADAPTER pAd, IN UCHAR Command) @@ -7755,6 +7982,7 @@ BOOLEAN AsicCheckCommanOk( return FALSE; } +#endif /* RT8260 */ /* ======================================================================== @@ -7797,8 +8025,6 @@ VOID RTMPCheckRates( NdisMoveMemory(SupRate, NewRate, NewRateLen); } -#ifdef CONFIG_STA_SUPPORT -#ifdef DOT11_N_SUPPORT BOOLEAN RTMPCheckChannel( IN PRTMP_ADAPTER pAd, IN UCHAR CentralChannel, @@ -7944,8 +8170,6 @@ BOOLEAN RTMPCheckHt( COPY_AP_HTSETTINGS_FROM_BEACON(pAd, pHtCapability); return TRUE; } -#endif // DOT11_N_SUPPORT // -#endif // CONFIG_STA_SUPPORT // /* ======================================================================== @@ -7978,10 +8202,8 @@ VOID RTMPUpdateMlmeRate( MinimumRate = RATE_1; break; case PHY_11BG_MIXED: -#ifdef DOT11_N_SUPPORT case PHY_11ABGN_MIXED: case PHY_11BGN_MIXED: -#endif // DOT11_N_SUPPORT // if ((pAd->MlmeAux.SupRateLen == 4) && (pAd->MlmeAux.ExtRateLen == 0)) // B only AP @@ -7995,13 +8217,11 @@ VOID RTMPUpdateMlmeRate( MinimumRate = RATE_6; break; case PHY_11A: -#ifdef DOT11_N_SUPPORT case PHY_11N_2_4G: // rt2860 need to check mlmerate for 802.11n case PHY_11GN_MIXED: case PHY_11AGN_MIXED: case PHY_11AN_MIXED: case PHY_11N_5G: -#endif // DOT11_N_SUPPORT // ProperMlmeRate = RATE_24; MinimumRate = RATE_6; break; @@ -8111,6 +8331,58 @@ CHAR RTMPMaxRssi( return larger; } +#ifdef RT30xx +// Antenna divesity use GPIO3 and EESK pin for control +// Antenna and EEPROM access are both using EESK pin, +// Therefor we should avoid accessing EESK at the same time +// Then restore antenna after EEPROM access +VOID AsicSetRxAnt( + IN PRTMP_ADAPTER pAd, + IN UCHAR Ant) +{ +#ifdef RT30xx + UINT32 Value; + UINT32 x; + + if ((pAd->EepromAccess) || + (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS)) || + (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) || + (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF)) || + (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))) + { + return; + } + + // the antenna selection is through firmware and MAC register(GPIO3) + if (Ant == 0) + { + // Main antenna + RTMP_IO_READ32(pAd, E2PROM_CSR, &x); + x |= (EESK); + RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); + + RTMP_IO_READ32(pAd, GPIO_CTRL_CFG, &Value); + Value &= ~(0x0808); + RTMP_IO_WRITE32(pAd, GPIO_CTRL_CFG, Value); + DBGPRINT_RAW(RT_DEBUG_TRACE, ("AsicSetRxAnt, switch to main antenna\n")); + } + else + { + // Aux antenna + RTMP_IO_READ32(pAd, E2PROM_CSR, &x); + x &= ~(EESK); + RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); + + RTMP_IO_READ32(pAd, GPIO_CTRL_CFG, &Value); + Value &= ~(0x0808); + Value |= 0x08; + RTMP_IO_WRITE32(pAd, GPIO_CTRL_CFG, Value); + DBGPRINT_RAW(RT_DEBUG_TRACE, ("AsicSetRxAnt, switch to aux antenna\n")); + } +#endif // RT30xx // +} +#endif /* RT30xx */ + /* ======================================================================== Routine Description: @@ -8129,14 +8401,7 @@ VOID AsicEvaluateRxAnt( { UCHAR BBPR3 = 0; -#ifdef RALINK_ATE - if (ATE_ON(pAd)) - return; -#endif // RALINK_ATE // - - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) +#ifndef RT30xx { if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS | fRTMP_ADAPTER_HALT_IN_PROGRESS | @@ -8148,7 +8413,6 @@ VOID AsicEvaluateRxAnt( if (pAd->StaCfg.Psm == PWR_SAVE) return; } -#endif // CONFIG_STA_SUPPORT // RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BBPR3); BBPR3 &= (~0x18); @@ -8165,10 +8429,11 @@ VOID AsicEvaluateRxAnt( BBPR3 |= (0x0); } RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BBPR3); -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) + +#ifdef RT2860 pAd->StaCfg.BBPR3 = BBPR3; -#endif // CONFIG_STA_SUPPORT // +#endif +#ifdef RT2870 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) ) { @@ -8187,6 +8452,90 @@ VOID AsicEvaluateRxAnt( pAd->Mlme.bLowThroughput = TRUE; } } +#endif +#endif /* RT30xx */ +#ifdef RT30xx + if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS | + fRTMP_ADAPTER_HALT_IN_PROGRESS | + fRTMP_ADAPTER_RADIO_OFF | + fRTMP_ADAPTER_NIC_NOT_EXIST | + fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS) || + OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE) +#ifdef RT30xx + || (pAd->EepromAccess) +#endif // RT30xx // + ) + return; + + + { + //if (pAd->StaCfg.Psm == PWR_SAVE) + // return; + } + + // two antenna selection mechanism- one is antenna diversity, the other is failed antenna remove + // one is antenna diversity:there is only one antenna can rx and tx + // the other is failed antenna remove:two physical antenna can rx and tx + if (pAd->NicConfig2.field.AntDiversity) + { + DBGPRINT(RT_DEBUG_TRACE,("AntDiv - before evaluate Pair1-Ant (%d,%d)\n", + pAd->RxAnt.Pair1PrimaryRxAnt, pAd->RxAnt.Pair1SecondaryRxAnt)); + + AsicSetRxAnt(pAd, pAd->RxAnt.Pair1SecondaryRxAnt); + + pAd->RxAnt.EvaluatePeriod = 1; // 1:Means switch to SecondaryRxAnt, 0:Means switch to Pair1PrimaryRxAnt + pAd->RxAnt.FirstPktArrivedWhenEvaluate = FALSE; + pAd->RxAnt.RcvPktNumWhenEvaluate = 0; + + // a one-shot timer to end the evalution + // dynamic adjust antenna evaluation period according to the traffic + if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) + RTMPSetTimer(&pAd->Mlme.RxAntEvalTimer, 100); + else + RTMPSetTimer(&pAd->Mlme.RxAntEvalTimer, 300); + } + else + { + if (pAd->StaCfg.Psm == PWR_SAVE) + return; + + RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BBPR3); + BBPR3 &= (~0x18); + if(pAd->Antenna.field.RxPath == 3) + { + BBPR3 |= (0x10); + } + else if(pAd->Antenna.field.RxPath == 2) + { + BBPR3 |= (0x8); + } + else if(pAd->Antenna.field.RxPath == 1) + { + BBPR3 |= (0x0); + } + RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BBPR3); + } +#endif /* RT30xx */ + + if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) + ) + { + ULONG TxTotalCnt = pAd->RalinkCounters.OneSecTxNoRetryOkCount + + pAd->RalinkCounters.OneSecTxRetryOkCount + + pAd->RalinkCounters.OneSecTxFailCount; + + // dynamic adjust antenna evaluation period according to the traffic + if (TxTotalCnt > 50) + { + RTMPSetTimer(&pAd->Mlme.RxAntEvalTimer, 20); + pAd->Mlme.bLowThroughput = FALSE; + } + else + { + RTMPSetTimer(&pAd->Mlme.RxAntEvalTimer, 300); + pAd->Mlme.bLowThroughput = TRUE; + } + } } /* @@ -8209,19 +8558,10 @@ VOID AsicRxAntEvalTimeout( IN PVOID SystemSpecific3) { RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext; -#ifdef CONFIG_STA_SUPPORT UCHAR BBPR3 = 0; CHAR larger = -127, rssi0, rssi1, rssi2; -#endif // CONFIG_STA_SUPPORT // -#ifdef RALINK_ATE - if (ATE_ON(pAd)) - return; -#endif // RALINK_ATE // - - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) +#ifndef RT30xx { if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS) || RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS) || @@ -8279,11 +8619,111 @@ VOID AsicRxAntEvalTimeout( BBPR3 |= (0x0); } RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BBPR3); +#ifdef RT2860 pAd->StaCfg.BBPR3 = BBPR3; +#endif } +#endif /* RT30xx */ +#ifdef RT30xx + if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS | + fRTMP_ADAPTER_HALT_IN_PROGRESS | + fRTMP_ADAPTER_RADIO_OFF | + fRTMP_ADAPTER_NIC_NOT_EXIST) || + OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE) +#ifdef RT30xx + || (pAd->EepromAccess) +#endif // RT30xx // + ) + return; -#endif // CONFIG_STA_SUPPORT // + { + //if (pAd->StaCfg.Psm == PWR_SAVE) + // return; + if (pAd->NicConfig2.field.AntDiversity) + { + if ((pAd->RxAnt.RcvPktNumWhenEvaluate != 0) && (pAd->RxAnt.Pair1AvgRssi[pAd->RxAnt.Pair1SecondaryRxAnt] >= pAd->RxAnt.Pair1AvgRssi[pAd->RxAnt.Pair1PrimaryRxAnt])) + { + UCHAR temp; + + // + // select PrimaryRxAntPair + // Role change, Used Pair1SecondaryRxAnt as PrimaryRxAntPair. + // Since Pair1SecondaryRxAnt Quality good than Pair1PrimaryRxAnt + // + temp = pAd->RxAnt.Pair1PrimaryRxAnt; + pAd->RxAnt.Pair1PrimaryRxAnt = pAd->RxAnt.Pair1SecondaryRxAnt; + pAd->RxAnt.Pair1SecondaryRxAnt = temp; + + pAd->RxAnt.Pair1LastAvgRssi = (pAd->RxAnt.Pair1AvgRssi[pAd->RxAnt.Pair1SecondaryRxAnt] >> 3); + pAd->RxAnt.EvaluateStableCnt = 0; + } + else + { + // if the evaluated antenna is not better than original, switch back to original antenna + AsicSetRxAnt(pAd, pAd->RxAnt.Pair1PrimaryRxAnt); + pAd->RxAnt.EvaluateStableCnt ++; + } + + pAd->RxAnt.EvaluatePeriod = 0; // 1:Means switch to SecondaryRxAnt, 0:Means switch to Pair1PrimaryRxAnt + + DBGPRINT(RT_DEBUG_TRACE,("AsicRxAntEvalAction::After Eval(fix in #%d), <%d, %d>, RcvPktNumWhenEvaluate=%ld\n", + pAd->RxAnt.Pair1PrimaryRxAnt, (pAd->RxAnt.Pair1AvgRssi[0] >> 3), (pAd->RxAnt.Pair1AvgRssi[1] >> 3), pAd->RxAnt.RcvPktNumWhenEvaluate)); + } + else + { + if (pAd->StaCfg.Psm == PWR_SAVE) + return; + + // if the traffic is low, use average rssi as the criteria + if (pAd->Mlme.bLowThroughput == TRUE) + { + rssi0 = pAd->StaCfg.RssiSample.LastRssi0; + rssi1 = pAd->StaCfg.RssiSample.LastRssi1; + rssi2 = pAd->StaCfg.RssiSample.LastRssi2; + } + else + { + rssi0 = pAd->StaCfg.RssiSample.AvgRssi0; + rssi1 = pAd->StaCfg.RssiSample.AvgRssi1; + rssi2 = pAd->StaCfg.RssiSample.AvgRssi2; + } + + if(pAd->Antenna.field.RxPath == 3) + { + larger = max(rssi0, rssi1); + + if (larger > (rssi2 + 20)) + pAd->Mlme.RealRxPath = 2; + else + pAd->Mlme.RealRxPath = 3; + } + else if(pAd->Antenna.field.RxPath == 2) + { + if (rssi0 > (rssi1 + 20)) + pAd->Mlme.RealRxPath = 1; + else + pAd->Mlme.RealRxPath = 2; + } + + RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BBPR3); + BBPR3 &= (~0x18); + if(pAd->Mlme.RealRxPath == 3) + { + BBPR3 |= (0x10); + } + else if(pAd->Mlme.RealRxPath == 2) + { + BBPR3 |= (0x8); + } + else if(pAd->Mlme.RealRxPath == 1) + { + BBPR3 |= (0x0); + } + RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BBPR3); + } + } +#endif /* RT30xx */ } @@ -8350,9 +8790,6 @@ BOOLEAN RTMPCheckEntryEnableAutoRateSwitch( { BOOLEAN result = TRUE; - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { // only associated STA counts if (pEntry && (pEntry->ValidAsCLI) && (pEntry->Sst == SST_ASSOC)) @@ -8361,15 +8798,7 @@ BOOLEAN RTMPCheckEntryEnableAutoRateSwitch( } else result = FALSE; - -#ifdef QOS_DLS_SUPPORT - if (pEntry && (pEntry->ValidAsDls)) - result = pAd->StaCfg.bAutoTxRateSwitch; -#endif // QOS_DLS_SUPPORT // } -#endif // CONFIG_STA_SUPPORT // - - return result; } @@ -8378,14 +8807,9 @@ BOOLEAN RTMPCheckEntryEnableAutoRateSwitch( BOOLEAN RTMPAutoRateSwitchCheck( IN PRTMP_ADAPTER pAd) { + if (pAd->StaCfg.bAutoTxRateSwitch) + return TRUE; -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - if (pAd->StaCfg.bAutoTxRateSwitch) - return TRUE; - } -#endif // CONFIG_STA_SUPPORT // return FALSE; } @@ -8411,13 +8835,7 @@ UCHAR RTMPStaFixedTxMode( { UCHAR tx_mode = FIXED_TXMODE_HT; - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - tx_mode = (UCHAR)pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode; - } -#endif // CONFIG_STA_SUPPORT // + tx_mode = (UCHAR)pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode; return tx_mode; } @@ -8474,7 +8892,6 @@ VOID RTMPUpdateLegacyTxSetting( } } -#ifdef CONFIG_STA_SUPPORT /* ========================================================================== Description: @@ -8505,7 +8922,12 @@ VOID AsicStaBbpTuning( && (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) ) && !(OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) +#ifdef RT2860 && (pAd->bPCIclkOff == FALSE)) +#endif +#ifdef RT2870 + ) +#endif { RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R66, &OrigR66Value); R66 = OrigR66Value; @@ -8517,6 +8939,45 @@ VOID AsicStaBbpTuning( if (pAd->LatchRfRegs.Channel <= 14) { //BG band +#ifdef RT2870 + // RT3070 is a no LNA solution, it should have different control regarding to AGC gain control + // Otherwise, it will have some throughput side effect when low RSSI +#ifndef RT30xx + if (IS_RT3070(pAd)) +#endif +#ifdef RT30xx + if (IS_RT30xx(pAd)) +#endif + { + if (Rssi > RSSI_FOR_MID_LOW_SENSIBILITY) + { + R66 = 0x1C + 2*GET_LNA_GAIN(pAd) + 0x20; + if (OrigR66Value != R66) + { +#ifndef RT30xx + RTUSBWriteBBPRegister(pAd, BBP_R66, R66); +#endif +#ifdef RT30xx + RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); +#endif + } + } + else + { + R66 = 0x1C + 2*GET_LNA_GAIN(pAd); + if (OrigR66Value != R66) + { +#ifndef RT30xx + RTUSBWriteBBPRegister(pAd, BBP_R66, R66); +#endif +#ifdef RT30xx + RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); +#endif + } + } + } + else +#endif // RT2870 // { if (Rssi > RSSI_FOR_MID_LOW_SENSIBILITY) { @@ -8582,6 +9043,7 @@ VOID AsicStaBbpTuning( } } +#ifdef RT2860 VOID AsicResetFromDMABusy( IN PRTMP_ADAPTER pAd) { @@ -8681,7 +9143,7 @@ VOID AsicResetPBF( DBGPRINT(RT_DEBUG_TRACE, ("<--- Asic HardReset PBF !!!! \n")); } } -#endif // CONFIG_STA_SUPPORT // +#endif /* RT2860 */ VOID RTMPSetAGCInitValue( IN PRTMP_ADAPTER pAd, @@ -8701,13 +9163,11 @@ VOID RTMPSetAGCInitValue( R66 = (UCHAR)(0x32 + (GET_LNA_GAIN(pAd)*5)/3); RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); } -#ifdef DOT11_N_SUPPORT else { R66 = (UCHAR)(0x3A + (GET_LNA_GAIN(pAd)*5)/3); RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); } -#endif // DOT11_N_SUPPORT // } } @@ -8722,6 +9182,15 @@ VOID AsicTurnOffRFClk( UCHAR index; RTMP_RF_REGS *RFRegTable; +#ifdef RT30xx + // The RF programming sequence is difference between 3xxx and 2xxx + if (IS_RT3090(pAd)) + { + RT30xxLoadRFSleepModeSetup(pAd); // add by johnli, RF power sequence setup, load RF sleep-mode setup + } + else + { +#endif // RT30xx // RFRegTable = RF2850RegTable; switch (pAd->RfIcType) @@ -8763,6 +9232,10 @@ VOID AsicTurnOffRFClk( default: break; } +#ifdef RT30xx + } +#endif // RT30xx // + } @@ -8776,6 +9249,14 @@ VOID AsicTurnOnRFClk( UCHAR index; RTMP_RF_REGS *RFRegTable; +#ifdef RT30xx + // The RF programming sequence is difference between 3xxx and 2xxx + if (IS_RT3090(pAd)) + { + } + else + { +#endif // RT30xx // RFRegTable = RF2850RegTable; switch (pAd->RfIcType) @@ -8822,9 +9303,14 @@ VOID AsicTurnOnRFClk( break; } +#ifndef RT30xx DBGPRINT(RT_DEBUG_TRACE, ("AsicTurnOnRFClk#%d(RF=%d, ) , R2=0x%08x\n", Channel, pAd->RfIcType, R2)); +#endif +#ifdef RT30xx + } +#endif // RT30xx // } diff --git a/drivers/staging/rt2860/common/netif_block.c b/drivers/staging/rt2860/common/netif_block.c deleted file mode 100644 index d3f7d087e7f0..000000000000 --- a/drivers/staging/rt2860/common/netif_block.c +++ /dev/null @@ -1,144 +0,0 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * 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 "../rt_config.h" -#include "netif_block.h" - -static NETIF_ENTRY freeNetIfEntryPool[FREE_NETIF_POOL_SIZE]; -static LIST_HEADER freeNetIfEntryList; - -void initblockQueueTab( - IN PRTMP_ADAPTER pAd) -{ - int i; - - initList(&freeNetIfEntryList); - for (i = 0; i < FREE_NETIF_POOL_SIZE; i++) - insertTailList(&freeNetIfEntryList, (PLIST_ENTRY)&freeNetIfEntryPool[i]); - - for (i=0; i < NUM_OF_TX_RING; i++) - initList(&pAd->blockQueueTab[i].NetIfList); - - return; -} - -BOOLEAN blockNetIf( - IN PBLOCK_QUEUE_ENTRY pBlockQueueEntry, - IN PNET_DEV pNetDev) -{ - PNETIF_ENTRY pNetIfEntry = NULL; - - if ((pNetIfEntry = (PNETIF_ENTRY)removeHeadList(&freeNetIfEntryList)) != NULL) - { - netif_stop_queue(pNetDev); - pNetIfEntry->pNetDev = pNetDev; - insertTailList(&pBlockQueueEntry->NetIfList, (PLIST_ENTRY)pNetIfEntry); - - pBlockQueueEntry->SwTxQueueBlockFlag = TRUE; - DBGPRINT(RT_DEBUG_TRACE, ("netif_stop_queue(%s)\n", pNetDev->name)); - } - else - return FALSE; - - return TRUE; -} - -VOID releaseNetIf( - IN PBLOCK_QUEUE_ENTRY pBlockQueueEntry) -{ - PNETIF_ENTRY pNetIfEntry = NULL; - PLIST_HEADER pNetIfList = &pBlockQueueEntry->NetIfList; - - while((pNetIfEntry = (PNETIF_ENTRY)removeHeadList(pNetIfList)) != NULL) - { - PNET_DEV pNetDev = pNetIfEntry->pNetDev; - netif_wake_queue(pNetDev); - insertTailList(&freeNetIfEntryList, (PLIST_ENTRY)pNetIfEntry); - - DBGPRINT(RT_DEBUG_TRACE, ("netif_wake_queue(%s)\n", pNetDev->name)); - } - pBlockQueueEntry->SwTxQueueBlockFlag = FALSE; - return; -} - - -VOID StopNetIfQueue( - IN PRTMP_ADAPTER pAd, - IN UCHAR QueIdx, - IN PNDIS_PACKET pPacket) -{ - PNET_DEV NetDev = NULL; - UCHAR IfIdx = 0; - BOOLEAN valid = FALSE; - -#ifdef APCLI_SUPPORT - if (RTMP_GET_PACKET_NET_DEVICE(pPacket) >= MIN_NET_DEVICE_FOR_APCLI) - { - IfIdx = (RTMP_GET_PACKET_NET_DEVICE(pPacket) - MIN_NET_DEVICE_FOR_APCLI) % MAX_APCLI_NUM; - NetDev = pAd->ApCfg.ApCliTab[IfIdx].dev; - } - else -#endif // APCLI_SUPPORT // -#ifdef WDS_SUPPORT - if (RTMP_GET_PACKET_NET_DEVICE(pPacket) >= MIN_NET_DEVICE_FOR_WDS) - { - IfIdx = (RTMP_GET_PACKET_NET_DEVICE(pPacket) - MIN_NET_DEVICE_FOR_WDS) % MAX_WDS_ENTRY; - NetDev = pAd->WdsTab.WdsEntry[IfIdx].dev; - } - else -#endif // WDS_SUPPORT // - { -#ifdef MBSS_SUPPORT - if (pAd->OpMode == OPMODE_AP) - { - IfIdx = (RTMP_GET_PACKET_NET_DEVICE(pPacket) - MIN_NET_DEVICE_FOR_MBSSID) % MAX_MBSSID_NUM; - NetDev = pAd->ApCfg.MBSSID[IfIdx].MSSIDDev; - } - else - { - IfIdx = MAIN_MBSSID; - NetDev = pAd->net_dev; - } -#else - IfIdx = MAIN_MBSSID; - NetDev = pAd->net_dev; -#endif - } - - // WMM support 4 software queues. - // One software queue full doesn't mean device have no capbility to transmit packet. - // So disable block Net-If queue function while WMM enable. -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - valid = (pAd->CommonCfg.bWmmCapable == TRUE) ? FALSE : TRUE; -#endif // CONFIG_STA_SUPPORT // - - if (valid) - blockNetIf(&pAd->blockQueueTab[QueIdx], NetDev); - return; -} - diff --git a/drivers/staging/rt2860/common/netif_block.h b/drivers/staging/rt2860/common/netif_block.h deleted file mode 100644 index 6e5151c41095..000000000000 --- a/drivers/staging/rt2860/common/netif_block.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - */ - -#ifndef __NET_IF_BLOCK_H__ -#define __NET_IF_BLOCK_H__ - -//#include -#include "link_list.h" -#include "rtmp.h" - -#define FREE_NETIF_POOL_SIZE 32 - -typedef struct _NETIF_ENTRY -{ - struct _NETIF_ENTRY *pNext; - PNET_DEV pNetDev; -} NETIF_ENTRY, *PNETIF_ENTRY; - -void initblockQueueTab( - IN PRTMP_ADAPTER pAd); - -BOOLEAN blockNetIf( - IN PBLOCK_QUEUE_ENTRY pBlockQueueEntry, - IN PNET_DEV pNetDev); - -VOID releaseNetIf( - IN PBLOCK_QUEUE_ENTRY pBlockQueueEntry); - -VOID StopNetIfQueue( - IN PRTMP_ADAPTER pAd, - IN UCHAR QueIdx, - IN PNDIS_PACKET pPacket); -#endif // __NET_IF_BLOCK_H__ - diff --git a/drivers/staging/rt2860/common/rtmp_init.c b/drivers/staging/rt2860/common/rtmp_init.c index 8a00cee3ee91..004f53023b0f 100644 --- a/drivers/staging/rt2860/common/rtmp_init.c +++ b/drivers/staging/rt2860/common/rtmp_init.c @@ -38,8 +38,18 @@ Jan Lee 2006-09-15 RT2860. Change for 802.11n , EEPROM, Led, BA, HT. */ #include "../rt_config.h" -#include "firmware.h" +#ifndef RT30xx +#ifdef RT2860 +#include "firmware.h" #include +#endif +#ifdef RT2870 +#include "../../rt2870/common/firmware.h" +#endif +#endif +#ifdef RT30xx +#include "../../rt3070/firmware.h" +#endif UCHAR BIT8[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}; ULONG BIT32[] = {0x00000001, 0x00000002, 0x00000004, 0x00000008, @@ -90,6 +100,22 @@ const unsigned short ccitt_16Table[] = { #define ByteCRC16(v, crc) \ (unsigned short)((crc << 8) ^ ccitt_16Table[((crc >> 8) ^ (v)) & 255]) +#ifdef RT2870 +unsigned char BitReverse(unsigned char x) +{ + int i; + unsigned char Temp=0; + for(i=0; ; i++) + { + if(x & 0x80) Temp |= 0x80; + if(i==7) break; + x <<= 1; + Temp >>= 1; + } + return Temp; +} +#endif + // // BBP register initialization set // @@ -114,6 +140,38 @@ REG_PAIR BBPRegTable[] = { // // RF register initialization set // +#ifdef RT2870 +REG_PAIR RT30xx_RFRegTable[] = { + {RF_R04, 0x40}, + {RF_R05, 0x03}, + {RF_R06, 0x02}, + {RF_R07, 0x70}, + {RF_R09, 0x0F}, +#ifndef RT30xx + {RF_R10, 0x71}, +#endif +#ifdef RT30xx + {RF_R10, 0x41}, +#endif + {RF_R11, 0x21}, + {RF_R12, 0x7B}, + {RF_R14, 0x90}, + {RF_R15, 0x58}, + {RF_R16, 0xB3}, + {RF_R17, 0x92}, + {RF_R18, 0x2C}, + {RF_R19, 0x02}, + {RF_R20, 0xBA}, + {RF_R21, 0xDB}, + {RF_R24, 0x16}, + {RF_R25, 0x01}, +#ifndef RT30xx + {RF_R27, 0x03}, +#endif + {RF_R29, 0x1F}, +}; +#define NUM_RF_REG_PARMS (sizeof(RT30xx_RFRegTable) / sizeof(REG_PAIR)) +#endif // RT2870 // // // ASIC register initialization sets @@ -146,10 +204,18 @@ RTMP_REG_PAIR MACRegTable[] = { {AUTO_RSP_CFG, 0x00000013}, // Initial Auto_Responder, because QA will turn off Auto-Responder {CCK_PROT_CFG, 0x05740003 /*0x01740003*/}, // Initial Auto_Responder, because QA will turn off Auto-Responder. And RTS threshold is enabled. {OFDM_PROT_CFG, 0x05740003 /*0x01740003*/}, // Initial Auto_Responder, because QA will turn off Auto-Responder. And RTS threshold is enabled. +//PS packets use Tx1Q (for HCCA) when dequeue from PS unicast queue (WiFi WPA2 MA9_DT1 for Marvell B STA) +#ifdef RT2870 + {PBF_CFG, 0xf40006}, // Only enable Queue 2 + {MM40_PROT_CFG, 0x3F44084}, // Initial Auto_Responder, because QA will turn off Auto-Responder + {WPDMA_GLO_CFG, 0x00000030}, +#endif // RT2870 // {GF20_PROT_CFG, 0x01744004}, // set 19:18 --> Short NAV for MIMO PS {GF40_PROT_CFG, 0x03F44084}, {MM20_PROT_CFG, 0x01744004}, +#ifdef RT2860 {MM40_PROT_CFG, 0x03F54084}, +#endif {TXOP_CTRL_CFG, 0x0000583f, /*0x0000243f*/ /*0x000024bf*/}, //Extension channel backoff. {TX_RTS_CFG, 0x00092b20}, {EXP_ACK_TIME, 0x002400ca}, // default value @@ -163,20 +229,22 @@ RTMP_REG_PAIR MACRegTable[] = { {PWR_PIN_CFG, 0x00000003}, // patch for 2880-E }; - -#ifdef CONFIG_STA_SUPPORT RTMP_REG_PAIR STAMACRegTable[] = { {WMM_AIFSN_CFG, 0x00002273}, {WMM_CWMIN_CFG, 0x00002344}, {WMM_CWMAX_CFG, 0x000034aa}, }; -#endif // CONFIG_STA_SUPPORT // #define NUM_MAC_REG_PARMS (sizeof(MACRegTable) / sizeof(RTMP_REG_PAIR)) -#ifdef CONFIG_STA_SUPPORT #define NUM_STA_MAC_REG_PARMS (sizeof(STAMACRegTable) / sizeof(RTMP_REG_PAIR)) -#endif // CONFIG_STA_SUPPORT // +#ifdef RT2870 +// +// RT2870 Firmware Spec only used 1 oct for version expression +// +#define FIRMWARE_MINOR_VERSION 7 + +#endif // RT2870 // // New 8k byte firmware size for RT3071/RT3072 #define FIRMWAREIMAGE_MAX_LENGTH 0x2000 @@ -186,7 +254,9 @@ RTMP_REG_PAIR STAMACRegTable[] = { #define FIRMWAREIMAGEV1_LENGTH 0x1000 #define FIRMWAREIMAGEV2_LENGTH 0x1000 +#ifdef RT2860 #define FIRMWARE_MINOR_VERSION 2 +#endif /* @@ -244,7 +314,9 @@ NDIS_STATUS RTMPAllocAdapterBlock( // Init spin locks NdisAllocateSpinLock(&pAd->MgmtRingLock); +#ifdef RT2860 NdisAllocateSpinLock(&pAd->RxRingLock); +#endif for (index =0 ; index < NUM_OF_TX_RING; index++) { @@ -974,67 +1046,6 @@ VOID RTMPReadChannelPwr( // 4. Print and Debug choffset = 14 + 12 + 16 + 7; - - -#if 0 - // Init the 802.11j channel number for TX channel power - // 0. 20MHz - for (i = 0; i < 3; i++) - { - pAd->TxPower11J[i].Channel = 8 + i * 4; - pAd->TxPower11J[i].BW = BW_20; - } - - for (i = 0; i < 4; i++) - { - pAd->TxPower11J[i + 3].Channel = 34 + i * 4; - pAd->TxPower11J[i + 3].BW = BW_20; - } - - for (i = 0; i < 4; i++) - { - pAd->TxPower11J[i + 7].Channel = 184 + i * 4; - pAd->TxPower11J[i + 7].BW = BW_20; - } - - // 0. 10MHz - for (i = 0; i < 2; i++) - { - pAd->TxPower11J[i + 11].Channel = 7 + i; - pAd->TxPower11J[i + 11].BW = BW_10; - } - pAd->TxPower11J[13].Channel = 11; - pAd->TxPower11J[13].BW = BW_10; - - for (i = 0; i < 3; i++) - { - pAd->TxPower11J[i + 14].Channel = 183 + i; - pAd->TxPower11J[i + 14].BW= BW_10; - } - - for (i = 0; i < 3; i++) - { - pAd->TxPower11J[i + 17].Channel = 187 + i; - pAd->TxPower11J[i + 17].BW = BW_10; - } - for (i = 0; i < 10; i++) - { - Power.word = RTMP_EEPROM_READ16(pAd, EEPROM_Japan_TX_PWR_OFFSET + i * 2); - Power2.word = RTMP_EEPROM_READ16(pAd, EEPROM_Japan_TX2_PWR_OFFSET + i * 2); - - if ((Power.field.Byte0 < 36) && (Power.field.Byte0 > -6)) - pAd->TxPower11J[i * 2].Power = Power.field.Byte0; - - if ((Power.field.Byte1 < 36) && (Power.field.Byte1 > -6)) - pAd->TxPower11J[i * 2 + 1].Power = Power.field.Byte1; - - if ((Power2.field.Byte0 < 36) && (Power2.field.Byte0 > -6)) - pAd->TxPower11J[i * 2].Power2 = Power2.field.Byte0; - - if ((Power2.field.Byte1 < 36) && (Power2.field.Byte1 > -6)) - pAd->TxPower11J[i * 2 + 1].Power2 = Power2.field.Byte1; - } -#endif } /* @@ -1071,6 +1082,425 @@ NDIS_STATUS NICReadRegParameters( } +#ifdef RT2870 +/* + ======================================================================== + + Routine Description: + For RF filter calibration purpose + + Arguments: + pAd Pointer to our adapter + + Return Value: + None + + IRQL = PASSIVE_LEVEL + + ======================================================================== +*/ +#ifndef RT30xx +VOID RTUSBFilterCalibration( + IN PRTMP_ADAPTER pAd) +{ + UCHAR R55x = 0, value, FilterTarget = 0x1E, BBPValue; + UINT loop = 0, count = 0, loopcnt = 0, ReTry = 0; + UCHAR RF_R24_Value = 0; + + // Give bbp filter initial value + pAd->Mlme.CaliBW20RfR24 = 0x16; + pAd->Mlme.CaliBW40RfR24 = 0x36; //Bit[5] must be 1 for BW 40 + + do + { + if (loop == 1) //BandWidth = 40 MHz + { + // Write 0x27 to RF_R24 to program filter + RF_R24_Value = 0x27; + RT30xxWriteRFRegister(pAd, RF_R24, RF_R24_Value); + FilterTarget = 0x19; + + // when calibrate BW40, BBP mask must set to BW40. + RTUSBReadBBPRegister(pAd, BBP_R4, &BBPValue); + BBPValue&= (~0x18); + BBPValue|= (0x10); + RTUSBWriteBBPRegister(pAd, BBP_R4, BBPValue); + } + else //BandWidth = 20 MHz + { + // Write 0x07 to RF_R24 to program filter + RF_R24_Value = 0x07; + RT30xxWriteRFRegister(pAd, RF_R24, RF_R24_Value); + FilterTarget = 0x16; + } + + // Write 0x01 to RF_R22 to enable baseband loopback mode + RT30xxReadRFRegister(pAd, RF_R22, &value); + value |= 0x01; + RT30xxWriteRFRegister(pAd, RF_R22, value); + + // Write 0x00 to BBP_R24 to set power & frequency of passband test tone + RTUSBWriteBBPRegister(pAd, BBP_R24, 0); + + do + { + // Write 0x90 to BBP_R25 to transmit test tone + RTUSBWriteBBPRegister(pAd, BBP_R25, 0x90); + + RTMPusecDelay(1000); + // Read BBP_R55[6:0] for received power, set R55x = BBP_R55[6:0] + RTUSBReadBBPRegister(pAd, BBP_R55, &value); + R55x = value & 0xFF; + + } while ((ReTry++ < 100) && (R55x == 0)); + + // Write 0x06 to BBP_R24 to set power & frequency of stopband test tone + RTUSBWriteBBPRegister(pAd, BBP_R24, 0x06); + + while(TRUE) + { + // Write 0x90 to BBP_R25 to transmit test tone + RTUSBWriteBBPRegister(pAd, BBP_R25, 0x90); + + //We need to wait for calibration + RTMPusecDelay(1000); + RTUSBReadBBPRegister(pAd, BBP_R55, &value); + value &= 0xFF; + if ((R55x - value) < FilterTarget) + { + RF_R24_Value ++; + } + else if ((R55x - value) == FilterTarget) + { + RF_R24_Value ++; + count ++; + } + else + { + break; + } + + // prevent infinite loop cause driver hang. + if (loopcnt++ > 100) + { + DBGPRINT(RT_DEBUG_ERROR, ("RTUSBFilterCalibration - can't find a valid value, loopcnt=%d stop calibrating", loopcnt)); + break; + } + + // Write RF_R24 to program filter + RT30xxWriteRFRegister(pAd, RF_R24, RF_R24_Value); + } + + if (count > 0) + { + RF_R24_Value = RF_R24_Value - ((count) ? (1) : (0)); + } + + // Store for future usage + if (loopcnt < 100) + { + if (loop++ == 0) + { + //BandWidth = 20 MHz + pAd->Mlme.CaliBW20RfR24 = (UCHAR)RF_R24_Value; + } + else + { + //BandWidth = 40 MHz + pAd->Mlme.CaliBW40RfR24 = (UCHAR)RF_R24_Value; + break; + } + } + else + break; + + RT30xxWriteRFRegister(pAd, RF_R24, RF_R24_Value); + + // reset count + count = 0; + } while(TRUE); + + // + // Set back to initial state + // + RTUSBWriteBBPRegister(pAd, BBP_R24, 0); + + RT30xxReadRFRegister(pAd, RF_R22, &value); + value &= ~(0x01); + RT30xxWriteRFRegister(pAd, RF_R22, value); + + // set BBP back to BW20 + RTUSBReadBBPRegister(pAd, BBP_R4, &BBPValue); + BBPValue&= (~0x18); + RTUSBWriteBBPRegister(pAd, BBP_R4, BBPValue); + + DBGPRINT(RT_DEBUG_TRACE, ("RTUSBFilterCalibration - CaliBW20RfR24=0x%x, CaliBW40RfR24=0x%x\n", pAd->Mlme.CaliBW20RfR24, pAd->Mlme.CaliBW40RfR24)); +} +#endif /* RT30xx */ +#ifdef RT30xx +VOID RTMPFilterCalibration( + IN PRTMP_ADAPTER pAd) +{ + UCHAR R55x = 0, value, FilterTarget = 0x1E, BBPValue=0; + UINT loop = 0, count = 0, loopcnt = 0, ReTry = 0; + UCHAR RF_R24_Value = 0; + + // Give bbp filter initial value + pAd->Mlme.CaliBW20RfR24 = 0x1F; + pAd->Mlme.CaliBW40RfR24 = 0x2F; //Bit[5] must be 1 for BW 40 + + do + { + if (loop == 1) //BandWidth = 40 MHz + { + // Write 0x27 to RF_R24 to program filter + RF_R24_Value = 0x27; + RT30xxWriteRFRegister(pAd, RF_R24, RF_R24_Value); + if (IS_RT3090(pAd)) + FilterTarget = 0x15; + else + FilterTarget = 0x19; + + // when calibrate BW40, BBP mask must set to BW40. + RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); + BBPValue&= (~0x18); + BBPValue|= (0x10); + RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); + + // set to BW40 + RT30xxReadRFRegister(pAd, RF_R31, &value); + value |= 0x20; + RT30xxWriteRFRegister(pAd, RF_R31, value); + } + else //BandWidth = 20 MHz + { + // Write 0x07 to RF_R24 to program filter + RF_R24_Value = 0x07; + RT30xxWriteRFRegister(pAd, RF_R24, RF_R24_Value); + if (IS_RT3090(pAd)) + FilterTarget = 0x13; + else + FilterTarget = 0x16; + + // set to BW20 + RT30xxReadRFRegister(pAd, RF_R31, &value); + value &= (~0x20); + RT30xxWriteRFRegister(pAd, RF_R31, value); + } + + // Write 0x01 to RF_R22 to enable baseband loopback mode + RT30xxReadRFRegister(pAd, RF_R22, &value); + value |= 0x01; + RT30xxWriteRFRegister(pAd, RF_R22, value); + + // Write 0x00 to BBP_R24 to set power & frequency of passband test tone + RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R24, 0); + + do + { + // Write 0x90 to BBP_R25 to transmit test tone + RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R25, 0x90); + + RTMPusecDelay(1000); + // Read BBP_R55[6:0] for received power, set R55x = BBP_R55[6:0] + RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R55, &value); + R55x = value & 0xFF; + + } while ((ReTry++ < 100) && (R55x == 0)); + + // Write 0x06 to BBP_R24 to set power & frequency of stopband test tone + RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R24, 0x06); + + while(TRUE) + { + // Write 0x90 to BBP_R25 to transmit test tone + RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R25, 0x90); + + //We need to wait for calibration + RTMPusecDelay(1000); + RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R55, &value); + value &= 0xFF; + if ((R55x - value) < FilterTarget) + { + RF_R24_Value ++; + } + else if ((R55x - value) == FilterTarget) + { + RF_R24_Value ++; + count ++; + } + else + { + break; + } + + // prevent infinite loop cause driver hang. + if (loopcnt++ > 100) + { + DBGPRINT(RT_DEBUG_ERROR, ("RTMPFilterCalibration - can't find a valid value, loopcnt=%d stop calibrating", loopcnt)); + break; + } + + // Write RF_R24 to program filter + RT30xxWriteRFRegister(pAd, RF_R24, RF_R24_Value); + } + + if (count > 0) + { + RF_R24_Value = RF_R24_Value - ((count) ? (1) : (0)); + } + + // Store for future usage + if (loopcnt < 100) + { + if (loop++ == 0) + { + //BandWidth = 20 MHz + pAd->Mlme.CaliBW20RfR24 = (UCHAR)RF_R24_Value; + } + else + { + //BandWidth = 40 MHz + pAd->Mlme.CaliBW40RfR24 = (UCHAR)RF_R24_Value; + break; + } + } + else + break; + + RT30xxWriteRFRegister(pAd, RF_R24, RF_R24_Value); + + // reset count + count = 0; + } while(TRUE); + + // + // Set back to initial state + // + RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R24, 0); + + RT30xxReadRFRegister(pAd, RF_R22, &value); + value &= ~(0x01); + RT30xxWriteRFRegister(pAd, RF_R22, value); + + // set BBP back to BW20 + RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); + BBPValue&= (~0x18); + RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); + + DBGPRINT(RT_DEBUG_TRACE, ("RTMPFilterCalibration - CaliBW20RfR24=0x%x, CaliBW40RfR24=0x%x\n", pAd->Mlme.CaliBW20RfR24, pAd->Mlme.CaliBW40RfR24)); +} +#endif /* RT30xx */ + +VOID NICInitRT30xxRFRegisters(IN PRTMP_ADAPTER pAd) +{ + INT i; + // Driver must read EEPROM to get RfIcType before initial RF registers + // Initialize RF register to default value +#ifndef RT30xx + if (IS_RT3070(pAd) && ((pAd->RfIcType == RFIC_3020) ||(pAd->RfIcType == RFIC_2020))) + { + // Init RF calibration + // Driver should toggle RF R30 bit7 before init RF registers + ULONG RfReg = 0; + RT30xxReadRFRegister(pAd, RF_R30, (PUCHAR)&RfReg); + RfReg |= 0x80; + RT30xxWriteRFRegister(pAd, RF_R30, (UCHAR)RfReg); + RTMPusecDelay(1000); + RfReg &= 0x7F; + RT30xxWriteRFRegister(pAd, RF_R30, (UCHAR)RfReg); + + // Initialize RF register to default value + for (i = 0; i < NUM_RF_REG_PARMS; i++) + { + RT30xxWriteRFRegister(pAd, RT30xx_RFRegTable[i].Register, RT30xx_RFRegTable[i].Value); + } + + //For RF filter Calibration + RTUSBFilterCalibration(pAd); + } +#endif +#ifdef RT30xx + if (IS_RT3070(pAd) || IS_RT3071(pAd)) + { + // Init RF calibration + // Driver should toggle RF R30 bit7 before init RF registers + UINT32 RfReg = 0; + UINT32 data; + + RT30xxReadRFRegister(pAd, RF_R30, (PUCHAR)&RfReg); + RfReg |= 0x80; + RT30xxWriteRFRegister(pAd, RF_R30, (UCHAR)RfReg); + RTMPusecDelay(1000); + RfReg &= 0x7F; + RT30xxWriteRFRegister(pAd, RF_R30, (UCHAR)RfReg); + + // Initialize RF register to default value + for (i = 0; i < NUM_RF_REG_PARMS; i++) + { + RT30xxWriteRFRegister(pAd, RT30xx_RFRegTable[i].Register, RT30xx_RFRegTable[i].Value); + } + + // add by johnli + if (IS_RT3070(pAd)) + { + // Update MAC 0x05D4 from 01xxxxxx to 0Dxxxxxx (voltage 1.2V to 1.35V) for RT3070 to improve yield rate + RTUSBReadMACRegister(pAd, LDO_CFG0, &data); + data = ((data & 0xF0FFFFFF) | 0x0D000000); + RTUSBWriteMACRegister(pAd, LDO_CFG0, data); + } + else if (IS_RT3071(pAd)) + { + // Driver should set RF R6 bit6 on before init RF registers + RT30xxReadRFRegister(pAd, RF_R06, (PUCHAR)&RfReg); + RfReg |= 0x40; + RT30xxWriteRFRegister(pAd, RF_R06, (UCHAR)RfReg); + + // init R31 + RT30xxWriteRFRegister(pAd, RF_R31, 0x14); + + // RT3071 version E has fixed this issue + if ((pAd->NicConfig2.field.DACTestBit == 1) && ((pAd->MACVersion & 0xffff) < 0x0211)) + { + // patch tx EVM issue temporarily + RTUSBReadMACRegister(pAd, LDO_CFG0, &data); + data = ((data & 0xE0FFFFFF) | 0x0D000000); + RTUSBWriteMACRegister(pAd, LDO_CFG0, data); + } + else + { + RTMP_IO_READ32(pAd, LDO_CFG0, &data); + data = ((data & 0xE0FFFFFF) | 0x01000000); + RTMP_IO_WRITE32(pAd, LDO_CFG0, data); + } + + // patch LNA_PE_G1 failed issue + RTUSBReadMACRegister(pAd, GPIO_SWITCH, &data); + data &= ~(0x20); + RTUSBWriteMACRegister(pAd, GPIO_SWITCH, data); + } + + //For RF filter Calibration + RTMPFilterCalibration(pAd); + + // Initialize RF R27 register, set RF R27 must be behind RTMPFilterCalibration() + if ((pAd->MACVersion & 0xffff) < 0x0211) + RT30xxWriteRFRegister(pAd, RF_R27, 0x3); + + // set led open drain enable + RTUSBReadMACRegister(pAd, OPT_14, &data); + data |= 0x01; + RTUSBWriteMACRegister(pAd, OPT_14, data); + + if (IS_RT3071(pAd)) + { + // add by johnli, RF power sequence setup, load RF normal operation-mode setup + RT30xxLoadRFNormalModeSetup(pAd); + } + } +#endif +} +#endif // RT2870 // /* @@ -1245,11 +1675,25 @@ VOID NICReadEEPROMParameters( Antenna.word = pAd->EEPROMDefaultValue[0]; if (Antenna.word == 0xFFFF) { +#ifdef RT30xx + if(IS_RT3090(pAd)) + { + Antenna.word = 0; + Antenna.field.RfIcType = RFIC_3020; + Antenna.field.TxPath = 1; + Antenna.field.RxPath = 1; + } + else + { +#endif // RT30xx // Antenna.word = 0; Antenna.field.RfIcType = RFIC_2820; Antenna.field.TxPath = 1; Antenna.field.RxPath = 2; DBGPRINT(RT_DEBUG_WARN, ("E2PROM error, hard code as 0x%04x\n", Antenna.word)); +#ifdef RT30xx + } +#endif // RT30xx // } // Choose the desired Tx&Rx stream. @@ -1277,12 +1721,10 @@ VOID NICReadEEPROMParameters( NicConfig2.word = pAd->EEPROMDefaultValue[1]; - - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { +#ifndef RT30xx NicConfig2.word = 0; +#endif if ((NicConfig2.word & 0x00ff) == 0xff) { NicConfig2.word &= 0xff00; @@ -1293,7 +1735,6 @@ VOID NICReadEEPROMParameters( NicConfig2.word &= 0x00ff; } } -#endif // CONFIG_STA_SUPPORT // if (NicConfig2.field.DynamicTxAgcControl == 1) pAd->bAutoTxAgcA = pAd->bAutoTxAgcG = TRUE; @@ -1314,13 +1755,11 @@ VOID NICReadEEPROMParameters( if ((pAd->CommonCfg.PhyMode == PHY_11ABG_MIXED) || (pAd->CommonCfg.PhyMode == PHY_11A)) pAd->CommonCfg.PhyMode = PHY_11BG_MIXED; -#ifdef DOT11_N_SUPPORT else if ((pAd->CommonCfg.PhyMode == PHY_11ABGN_MIXED) || (pAd->CommonCfg.PhyMode == PHY_11AN_MIXED) || (pAd->CommonCfg.PhyMode == PHY_11AGN_MIXED) || (pAd->CommonCfg.PhyMode == PHY_11N_5G)) pAd->CommonCfg.PhyMode = PHY_11BGN_MIXED; -#endif // DOT11_N_SUPPORT // } // Read TSSI reference and TSSI boundary for temperature compensation. This is ugly @@ -1411,9 +1850,7 @@ VOID NICReadEEPROMParameters( TmpPhy = pAd->CommonCfg.PhyMode; pAd->CommonCfg.PhyMode = 0xff; RTMPSetPhyMode(pAd, TmpPhy); -#ifdef DOT11_N_SUPPORT SetCommonHT(pAd); -#endif // DOT11_N_SUPPORT // } // @@ -1480,10 +1917,13 @@ VOID NICReadEEPROMParameters( RTMPReadTxPwrPerRate(pAd); -#ifdef SINGLE_SKU - //pAd->CommonCfg.DefineMaxTxPwr = RTMP_EEPROM_READ16(pAd, EEPROM_DEFINE_MAX_TXPWR); - RT28xx_EEPROM_READ16(pAd, EEPROM_DEFINE_MAX_TXPWR, pAd->CommonCfg.DefineMaxTxPwr); -#endif // SINGLE_SKU // +#ifdef RT30xx + if (IS_RT30xx(pAd)) + { + eFusePhysicalReadRegisters(pAd, EFUSE_TAG, 2, &value); + pAd->EFuseTag = (value & 0xff); + } +#endif // RT30xx // DBGPRINT(RT_DEBUG_TRACE, ("<-- NICReadEEPROMParameters\n")); } @@ -1509,10 +1949,8 @@ VOID NICReadEEPROMParameters( VOID NICInitAsicFromEEPROM( IN PRTMP_ADAPTER pAd) { -#ifdef CONFIG_STA_SUPPORT UINT32 data = 0; UCHAR BBPR1 = 0; -#endif // CONFIG_STA_SUPPORT // USHORT i; EEPROM_ANTENNA_STRUC Antenna; EEPROM_NIC_CONFIG2_STRUC NicConfig2; @@ -1531,16 +1969,49 @@ VOID NICInitAsicFromEEPROM( } } +#ifndef RT30xx Antenna.word = pAd->Antenna.word; +#endif +#ifdef RT30xx + Antenna.word = pAd->EEPROMDefaultValue[0]; + if (Antenna.word == 0xFFFF) + { + DBGPRINT(RT_DEBUG_ERROR, ("E2PROM error, hard code as 0x%04x\n", Antenna.word)); + BUG_ON(Antenna.word == 0xFFFF); + } +#endif pAd->Mlme.RealRxPath = (UCHAR) Antenna.field.RxPath; pAd->RfIcType = (UCHAR) Antenna.field.RfIcType; +#ifdef RT30xx + DBGPRINT(RT_DEBUG_WARN, ("pAd->RfIcType = %d, RealRxPath=%d, TxPath = %d\n", pAd->RfIcType, pAd->Mlme.RealRxPath,Antenna.field.TxPath)); + + // Save the antenna for future use + pAd->Antenna.word = Antenna.word; +#endif NicConfig2.word = pAd->EEPROMDefaultValue[1]; +#ifdef RT30xx + { + if ((NicConfig2.word & 0x00ff) == 0xff) + { + NicConfig2.word &= 0xff00; + } + if ((NicConfig2.word >> 8) == 0xff) + { + NicConfig2.word &= 0x00ff; + } + } +#endif // Save the antenna for future use pAd->NicConfig2.word = NicConfig2.word; +#ifdef RT30xx + // set default antenna as main + if (pAd->RfIcType == RFIC_3020) + AsicSetRxAnt(pAd, pAd->RxAnt.Pair1PrimaryRxAnt); +#endif // // Send LED Setting to MCU. // @@ -1549,7 +2020,13 @@ VOID NICInitAsicFromEEPROM( pAd->LedCntl.word = 0x01; pAd->Led1 = 0x5555; pAd->Led2 = 0x2221; +#ifdef RT2860 pAd->Led3 = 0xA9F8; +#endif + +#ifdef RT2870 + pAd->Led3 = 0x5627; +#endif // RT2870 // } AsicSendCommandToMcu(pAd, 0x52, 0xff, (UCHAR)pAd->Led1, (UCHAR)(pAd->Led1 >> 8)); @@ -1558,8 +2035,6 @@ VOID NICInitAsicFromEEPROM( pAd->LedIndicatorStregth = 0xFF; RTMPSetSignalLED(pAd, -100); // Force signal strength Led to be turned off, before link up -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { // Read Hardware controlled Radio state enable bit if (NicConfig2.field.HardwareRadioControl == 1) @@ -1585,13 +2060,14 @@ VOID NICInitAsicFromEEPROM( else { RTMPSetLED(pAd, LED_RADIO_ON); +#ifdef RT2860 AsicSendCommandToMcu(pAd, 0x30, 0xff, 0xff, 0x02); AsicSendCommandToMcu(pAd, 0x31, PowerWakeCID, 0x00, 0x00); // 2-1. wait command ok. AsicCheckCommanOk(pAd, PowerWakeCID); +#endif } } -#endif // CONFIG_STA_SUPPORT // // Turn off patching for cardbus controller if (NicConfig2.field.CardbusAcceleration == 1) @@ -1624,8 +2100,6 @@ VOID NICInitAsicFromEEPROM( } RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BBPR3); -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { // Handle the difference when 1T RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R1, &BBPR1); @@ -1637,7 +2111,7 @@ VOID NICInitAsicFromEEPROM( DBGPRINT(RT_DEBUG_TRACE, ("Use Hw Radio Control Pin=%d; if used Pin=%d;\n", pAd->CommonCfg.bHardwareRadio, pAd->CommonCfg.bHardwareRadio)); } -#endif // CONFIG_STA_SUPPORT // + DBGPRINT(RT_DEBUG_TRACE, ("TxPath = %d, RxPath = %d, RFIC=%d, Polar+LED mode=%x\n", pAd->Antenna.field.TxPath, pAd->Antenna.field.RxPath, pAd->RfIcType, pAd->LedCntl.word)); DBGPRINT(RT_DEBUG_TRACE, ("<-- NICInitAsicFromEEPROM\n")); } @@ -1666,8 +2140,10 @@ NDIS_STATUS NICInitializeAdapter( { NDIS_STATUS Status = NDIS_STATUS_SUCCESS; WPDMA_GLO_CFG_STRUC GloCfg; +#ifdef RT2860 UINT32 Value; DELAY_INT_CFG_STRUC IntCfg; +#endif ULONG i =0, j=0; AC_TXOP_CSR0_STRUC csr0; @@ -1706,9 +2182,11 @@ retry: // asic simulation sequence put this ahead before loading firmware. // pbf hardware reset +#ifdef RT2860 RTMP_IO_WRITE32(pAd, WPDMA_RST_IDX, 0x1003f); // 0x10000 for reset rx, 0x3f resets all 6 tx rings. RTMP_IO_WRITE32(pAd, PBF_SYS_CTRL, 0xe1f); RTMP_IO_WRITE32(pAd, PBF_SYS_CTRL, 0xe00); +#endif // Initialze ASIC for TX & Rx operation if (NICInitializeAsic(pAd , bHardReset) != NDIS_STATUS_SUCCESS) @@ -1722,6 +2200,7 @@ retry: } +#ifdef RT2860 // Write AC_BK base address register Value = RTMP_GetPhysicalAddressLow(pAd->TxRing[QID_AC_BK].Cell[0].AllocPa); RTMP_IO_WRITE32(pAd, TX_BASE_PTR1, Value); @@ -1794,6 +2273,7 @@ retry: // Write RX_RING_CSR register Value = RX_RING_SIZE; RTMP_IO_WRITE32(pAd, RX_MAX_CNT, Value); +#endif /* RT2860 */ // WMM parameter @@ -1812,6 +2292,7 @@ retry: RTMP_IO_WRITE32(pAd, WMM_TXOP1_CFG, csr0.word); +#ifdef RT2860 // 3. Set DMA global configuration except TX_DMA_EN and RX_DMA_EN bits: i = 0; do @@ -1830,6 +2311,7 @@ retry: IntCfg.word = 0; RTMP_IO_WRITE32(pAd, DELAY_INT_CFG, IntCfg.word); +#endif // reset action @@ -1865,36 +2347,133 @@ NDIS_STATUS NICInitializeAsic( ULONG Index = 0; UCHAR R0 = 0xff; UINT32 MacCsr12 = 0, Counter = 0; +#ifdef RT2870 + UINT32 MacCsr0 = 0; + NTSTATUS Status; + UCHAR Value = 0xff; +#endif // RT2870 // +#ifdef RT30xx + UINT32 eFuseCtrl; +#endif // RT30xx // USHORT KeyIdx; INT i,apidx; DBGPRINT(RT_DEBUG_TRACE, ("--> NICInitializeAsic\n")); +#ifdef RT2860 if (bHardReset == TRUE) { RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x3); } else RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x1); +#endif +#ifdef RT2870 + // + // Make sure MAC gets ready after NICLoadFirmware(). + // + Index = 0; + + //To avoid hang-on issue when interface up in kernel 2.4, + //we use a local variable "MacCsr0" instead of using "pAd->MACVersion" directly. + do + { + RTMP_IO_READ32(pAd, MAC_CSR0, &MacCsr0); + + if ((MacCsr0 != 0x00) && (MacCsr0 != 0xFFFFFFFF)) + break; + + RTMPusecDelay(10); + } while (Index++ < 100); + + pAd->MACVersion = MacCsr0; + DBGPRINT(RT_DEBUG_TRACE, ("MAC_CSR0 [ Ver:Rev=0x%08x]\n", pAd->MACVersion)); + // turn on bit13 (set to zero) after rt2860D. This is to solve high-current issue. + RTMP_IO_READ32(pAd, PBF_SYS_CTRL, &MacCsr12); + MacCsr12 &= (~0x2000); + RTMP_IO_WRITE32(pAd, PBF_SYS_CTRL, MacCsr12); + + RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x3); + RTMP_IO_WRITE32(pAd, USB_DMA_CFG, 0x0); + Status = RTUSBVenderReset(pAd); +#endif RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x0); + // Initialize MAC register to default value +#ifdef RT2860 for (Index = 0; Index < NUM_MAC_REG_PARMS; Index++) { RTMP_IO_WRITE32(pAd, MACRegTable[Index].Register, MACRegTable[Index].Value); } +#endif +#ifdef RT2870 + for(Index=0; IndexMACVersion & 0xffff) < 0x0211) + { + if (pAd->NicConfig2.field.DACTestBit == 1) + { + RTMP_IO_WRITE32(pAd, TX_SW_CFG2, 0x1F); // To fix throughput drop drastically + } + else + { + RTMP_IO_WRITE32(pAd, TX_SW_CFG2, 0x0F); // To fix throughput drop drastically + } + } + else + { + RTMP_IO_WRITE32(pAd, TX_SW_CFG2, 0x0); + } + } + else if (IS_RT3070(pAd)) + { + RTMP_IO_WRITE32(pAd, TX_SW_CFG1, 0); + RTMP_IO_WRITE32(pAd, TX_SW_CFG2, 0x1F); // To fix throughput drop drastically + } +#endif // RT30xx // // // Before program BBP, we need to wait BBP/RF get wake up. @@ -1935,11 +2514,69 @@ NDIS_STATUS NICInitializeAsic( RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBPRegTable[Index].Register, BBPRegTable[Index].Value); } +#ifndef RT30xx // for rt2860E and after, init BBP_R84 with 0x19. This is for extension channel overlapping IOT. if ((pAd->MACVersion&0xffff) != 0x0101) RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R84, 0x19); +#ifdef RT2870 + //write RT3070 BBP wchich different with 2870 after write RT2870 BBP + if (IS_RT3070(pAd)) + { + RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, 0x0a); + RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R84, 0x99); + RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R105, 0x05); + } +#endif // RT2870 // +#endif +#ifdef RT30xx + // for rt2860E and after, init BBP_R84 with 0x19. This is for extension channel overlapping IOT. + // RT3090 should not program BBP R84 to 0x19, otherwise TX will block. + if (((pAd->MACVersion&0xffff) != 0x0101) && (!IS_RT30xx(pAd))) + RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R84, 0x19); +// add by johnli, RF power sequence setup + if (IS_RT30xx(pAd)) + { //update for RT3070/71/72/90/91/92. + RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R79, 0x13); + RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R80, 0x05); + RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R81, 0x33); + } + + if (IS_RT3090(pAd)) + { + UCHAR bbpreg=0; + + // enable DC filter + if ((pAd->MACVersion & 0xffff) >= 0x0211) + { + RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R103, 0xc0); + } + + // improve power consumption + RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R138, &bbpreg); + if (pAd->Antenna.field.TxPath == 1) + { + // turn off tx DAC_1 + bbpreg = (bbpreg | 0x20); + } + + if (pAd->Antenna.field.RxPath == 1) + { + // turn off tx ADC_1 + bbpreg &= (~0x2); + } + RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R138, bbpreg); + + // improve power consumption in RT3071 Ver.E + if ((pAd->MACVersion & 0xffff) >= 0x0211) + { + RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R31, &bbpreg); + bbpreg &= (~0x3); + RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R31, bbpreg); + } + } +#endif if (pAd->MACVersion == 0x28600100) { RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, 0x16); @@ -1956,10 +2593,20 @@ NDIS_STATUS NICInitializeAsic( RTMP_IO_WRITE32(pAd, MAX_LEN_CFG, csr); } +#ifdef RT2870 +{ + UCHAR MAC_Value[]={0xff,0xff,0xff,0xff,0xff,0xff,0xff,0,0}; + + //Initialize WCID table + Value = 0xff; + for(Index =0 ;Index < 254;Index++) + { + RTUSBMultiWrite(pAd, (USHORT)(MAC_WCID_BASE + Index * 8), MAC_Value, 8); + } +} +#endif // RT2870 // // Add radio off control -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { if (pAd->StaCfg.bRadio == FALSE) { @@ -1968,7 +2615,6 @@ NDIS_STATUS NICInitializeAsic( DBGPRINT(RT_DEBUG_TRACE, ("Set Radio Off\n")); } } -#endif // CONFIG_STA_SUPPORT // // Clear raw counters RTMP_IO_READ32(pAd, RX_STA_CNT0, &Counter); @@ -2006,21 +2652,48 @@ NDIS_STATUS NICInitializeAsic( RTMP_IO_WRITE32(pAd, pAd->BeaconOffset[apidx] + i, 0x00); } } +#ifdef RT2870 + AsicDisableSync(pAd); + // Clear raw counters + RTMP_IO_READ32(pAd, RX_STA_CNT0, &Counter); + RTMP_IO_READ32(pAd, RX_STA_CNT1, &Counter); + RTMP_IO_READ32(pAd, RX_STA_CNT2, &Counter); + RTMP_IO_READ32(pAd, TX_STA_CNT0, &Counter); + RTMP_IO_READ32(pAd, TX_STA_CNT1, &Counter); + RTMP_IO_READ32(pAd, TX_STA_CNT2, &Counter); + // Default PCI clock cycle per ms is different as default setting, which is based on PCI. + RTMP_IO_READ32(pAd, USB_CYC_CFG, &Counter); + Counter&=0xffffff00; + Counter|=0x000001e; + RTMP_IO_WRITE32(pAd, USB_CYC_CFG, Counter); +#endif // RT2870 // +#ifdef RT30xx + pAd->bUseEfuse=FALSE; + RTMP_IO_READ32(pAd, EFUSE_CTRL, &eFuseCtrl); + pAd->bUseEfuse = ( (eFuseCtrl & 0x80000000) == 0x80000000) ? 1 : 0; + if(pAd->bUseEfuse) + { + DBGPRINT(RT_DEBUG_TRACE, ("NVM is Efuse\n")); + } + else + { + DBGPRINT(RT_DEBUG_TRACE, ("NVM is EEPROM\n")); + + } +#endif // RT30xx // -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { // for rt2860E and after, init TXOP_CTRL_CFG with 0x583f. This is for extension channel overlapping IOT. if ((pAd->MACVersion&0xffff) != 0x0101) RTMP_IO_WRITE32(pAd, TXOP_CTRL_CFG, 0x583f); } -#endif // CONFIG_STA_SUPPORT // DBGPRINT(RT_DEBUG_TRACE, ("<-- NICInitializeAsic\n")); return NDIS_STATUS_SUCCESS; } +#ifdef RT2860 VOID NICRestoreBBPValue( IN PRTMP_ADAPTER pAd) { @@ -2144,6 +2817,7 @@ VOID NICRestoreBBPValue( DBGPRINT(RT_DEBUG_TRACE, ("<--- NICRestoreBBPValue !!!!!!!!!!!!!!!!!!!!!!! \n")); } +#endif /* RT2860 */ /* ======================================================================== @@ -2214,12 +2888,6 @@ VOID NICUpdateFifoStaCounters( CHAR reTry; UCHAR succMCS; -#ifdef RALINK_ATE - /* Nothing to do in ATE mode */ - if (ATE_ON(pAd)) - return; -#endif // RALINK_ATE // - do { RTMP_IO_READ32(pAd, TX_STA_FIFO, &StaFifo.word); @@ -2244,10 +2912,8 @@ VOID NICUpdateFifoStaCounters( pEntry->DebugFIFOCount++; -#ifdef DOT11_N_SUPPORT if (StaFifo.field.TxBF) // 3*3 pEntry->TxBFCount++; -#endif // DOT11_N_SUPPORT // #ifdef UAPSD_AP_SUPPORT UAPSD_SP_AUE_Handle(pAd, pEntry, StaFifo.field.TxSuccess); @@ -2261,23 +2927,15 @@ VOID NICUpdateFifoStaCounters( if (pEntry->FIFOCount >= 1) { DBGPRINT(RT_DEBUG_TRACE, ("#")); -#if 0 - SendRefreshBAR(pAd, pEntry); pEntry->NoBADataCountDown = 64; -#else -#ifdef DOT11_N_SUPPORT - pEntry->NoBADataCountDown = 64; -#endif // DOT11_N_SUPPORT // if(pEntry->PsMode == PWR_ACTIVE) { -#ifdef DOT11_N_SUPPORT int tid; for (tid=0; tidAid, tid, FALSE, FALSE); } -#endif // DOT11_N_SUPPORT // // Update the continuous transmission counter except PS mode pEntry->ContinueTxFailCnt++; @@ -2289,14 +2947,10 @@ VOID NICUpdateFifoStaCounters( pEntry->FIFOCount = 0; pEntry->ContinueTxFailCnt = 0; } -#endif - //pEntry->FIFOCount = 0; } - //pEntry->bSendBAR = TRUE; } else { -#ifdef DOT11_N_SUPPORT if ((pEntry->PsMode != PWR_SAVE) && (pEntry->NoBADataCountDown > 0)) { pEntry->NoBADataCountDown--; @@ -2305,7 +2959,7 @@ VOID NICUpdateFifoStaCounters( DBGPRINT(RT_DEBUG_TRACE, ("@\n")); } } -#endif // DOT11_N_SUPPORT // + pEntry->FIFOCount = 0; pEntry->OneSecTxNoRetryOkCount++; // update NoDataIdleCount when sucessful send packet to STA. @@ -2416,6 +3070,22 @@ VOID NICUpdateRawCounters( // Update RX Overflow counter pAd->Counters8023.RxNoBuffer += (RxStaCnt2.field.RxFifoOverflowCount); +#ifdef RT2870 + if (pAd->RalinkCounters.RxCount != pAd->watchDogRxCnt) + { + pAd->watchDogRxCnt = pAd->RalinkCounters.RxCount; + pAd->watchDogRxOverFlowCnt = 0; + } + else + { + if (RxStaCnt2.field.RxFifoOverflowCount) + pAd->watchDogRxOverFlowCnt++; + else + pAd->watchDogRxOverFlowCnt = 0; + } +#endif // RT2870 // + + if (!pAd->bUpdateBcnCntDone) { // Update BEACON sent count @@ -2643,217 +3313,46 @@ VOID NICEraseFirmware( NDIS_STATUS NICLoadFirmware( IN PRTMP_ADAPTER pAd) { -#ifdef BIN_IN_FILE -#define NICLF_DEFAULT_USE() \ - flg_default_firm_use = TRUE; \ - printk("%s - Use default firmware!\n", __func__); - - NDIS_STATUS Status = NDIS_STATUS_SUCCESS; - PUCHAR src; - struct file *srcf; - INT retval, orgfsuid, orgfsgid, i; - mm_segment_t orgfs; - PUCHAR pFirmwareImage; - UINT FileLength = 0; - UINT32 MacReg; - ULONG Index; - ULONG firm; - BOOLEAN flg_default_firm_use = FALSE; - - - DBGPRINT(RT_DEBUG_TRACE, ("===> %s\n", __func__)); - - /* init */ - pFirmwareImage = NULL; - src = RTMP_FIRMWARE_FILE_NAME; - - /* save uid and gid used for filesystem access. - set user and group to 0 (root) */ - orgfsuid = current->fsuid; - orgfsgid = current->fsgid; - current->fsuid = current->fsgid = 0; - orgfs = get_fs(); - set_fs(KERNEL_DS); - - pAd->FirmwareVersion = (FIRMWARE_MAJOR_VERSION << 8) + \ - FIRMWARE_MINOR_VERSION; - - - /* allocate firmware buffer */ - pFirmwareImage = kmalloc(MAX_FIRMWARE_IMAGE_SIZE, MEM_ALLOC_FLAG); - if (pFirmwareImage == NULL) - { - /* allocate fail, use default firmware array in firmware.h */ - printk("%s - Allocate memory fail!\n", __func__); - NICLF_DEFAULT_USE(); - } - else - { - /* allocate ok! zero the firmware buffer */ - memset(pFirmwareImage, 0x00, MAX_FIRMWARE_IMAGE_SIZE); - } /* End of if */ - - - /* if ok, read firmware file from *.bin file */ - if (flg_default_firm_use == FALSE) - { - do - { - /* open the bin file */ - srcf = filp_open(src, O_RDONLY, 0); - - if (IS_ERR(srcf)) - { - printk("%s - Error %ld opening %s\n", - __func__, -PTR_ERR(srcf), src); - NICLF_DEFAULT_USE(); - break; - } /* End of if */ - - /* the object must have a read method */ - if ((srcf->f_op == NULL) || (srcf->f_op->read == NULL)) - { - printk("%s - %s does not have a write method\n", __func__, src); - NICLF_DEFAULT_USE(); - break; - } /* End of if */ - - /* read the firmware from the file *.bin */ - FileLength = srcf->f_op->read(srcf, - pFirmwareImage, - MAX_FIRMWARE_IMAGE_SIZE, - &srcf->f_pos); - - if (FileLength != MAX_FIRMWARE_IMAGE_SIZE) - { - printk("%s: error file length (=%d) in RT2860AP.BIN\n", - __func__, FileLength); - NICLF_DEFAULT_USE(); - break; - } - else - { - PUCHAR ptr = pFirmwareImage; - USHORT crc = 0xffff; - - - /* calculate firmware CRC */ - for(i=0; i<(MAX_FIRMWARE_IMAGE_SIZE-2); i++, ptr++) - crc = ByteCRC16(bitrev8(*ptr), crc); - /* End of for */ - - if ((pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-2] != \ - (UCHAR)bitrev8((UCHAR)(crc>>8))) || - (pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-1] != \ - (UCHAR)bitrev8((UCHAR)crc))) - { - /* CRC fail */ - printk("%s: CRC = 0x%02x 0x%02x " - "error, should be 0x%02x 0x%02x\n", - __func__, - pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-2], - pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-1], - (UCHAR)(crc>>8), (UCHAR)(crc)); - NICLF_DEFAULT_USE(); - break; - } - else - { - /* firmware is ok */ - pAd->FirmwareVersion = \ - (pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-4] << 8) + - pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-3]; - - /* check if firmware version of the file is too old */ - if ((pAd->FirmwareVersion) < \ - ((FIRMWARE_MAJOR_VERSION << 8) + - FIRMWARE_MINOR_VERSION)) - { - printk("%s: firmware version too old!\n", __func__); - NICLF_DEFAULT_USE(); - break; - } /* End of if */ - } /* End of if */ - - DBGPRINT(RT_DEBUG_TRACE, - ("NICLoadFirmware: CRC ok, ver=%d.%d\n", - pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-4], - pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-3])); - } /* End of if (FileLength == MAX_FIRMWARE_IMAGE_SIZE) */ - break; - } while(TRUE); - - /* close firmware file */ - if (IS_ERR(srcf)) - ; - else - { - retval = filp_close(srcf, NULL); - if (retval) - { - DBGPRINT(RT_DEBUG_ERROR, - ("--> Error %d closing %s\n", -retval, src)); - } /* End of if */ - } /* End of if */ - } /* End of if */ - - - /* write firmware to ASIC */ - if (flg_default_firm_use == TRUE) - { - /* use default fimeware, free allocated buffer */ - if (pFirmwareImage != NULL) - kfree(pFirmwareImage); - /* End of if */ - - /* use default *.bin array */ - pFirmwareImage = FirmwareImage; - FileLength = sizeof(FirmwareImage); - } /* End of if */ - - /* enable Host program ram write selection */ - RTMP_IO_WRITE32(pAd, PBF_SYS_CTRL, 0x10000); - - for(i=0; ifsuid = orgfsuid; - current->fsgid = orgfsgid; -#else - NDIS_STATUS Status = NDIS_STATUS_SUCCESS; PUCHAR pFirmwareImage; ULONG FileLength, Index; //ULONG firm; UINT32 MacReg = 0; +#ifdef RT2870 + UINT32 Version = (pAd->MACVersion >> 16); +#endif // RT2870 // pFirmwareImage = FirmwareImage; FileLength = sizeof(FirmwareImage); +#ifdef RT2870 + // New 8k byte firmware size for RT3071/RT3072 + //printk("Usb Chip\n"); + if (FIRMWAREIMAGE_LENGTH == FIRMWAREIMAGE_MAX_LENGTH) + //The firmware image consists of two parts. One is the origianl and the other is the new. + //Use Second Part + { + if ((Version != 0x2860) && (Version != 0x2872) && (Version != 0x3070)) + { // Use Firmware V2. + //printk("KH:Use New Version,part2\n"); + pFirmwareImage = (PUCHAR)&FirmwareImage[FIRMWAREIMAGEV1_LENGTH]; + FileLength = FIRMWAREIMAGEV2_LENGTH; + } + else + { + //printk("KH:Use New Version,part1\n"); + pFirmwareImage = FirmwareImage; + FileLength = FIRMWAREIMAGEV1_LENGTH; + } + } + else + { + DBGPRINT(RT_DEBUG_ERROR, ("KH: bin file should be 8KB.\n")); + Status = NDIS_STATUS_FAILURE; + } + +#endif // RT2870 // + RT28XX_WRITE_FIRMWARE(pAd, pFirmwareImage, FileLength); -#endif /* check if MCU is ready */ Index = 0; @@ -2867,7 +3366,7 @@ NDIS_STATUS NICLoadFirmware( RTMPusecDelay(1000); } while (Index++ < 1000); - if (Index >= 1000) + if (Index > 1000) { Status = NDIS_STATUS_FAILURE; DBGPRINT(RT_DEBUG_ERROR, ("NICLoadFirmware: MCU is not ready\n\n\n")); @@ -3118,6 +3617,31 @@ VOID UserCfgInit( // // part I. intialize common configuration // +#ifdef RT2870 + pAd->BulkOutReq = 0; + + pAd->BulkOutComplete = 0; + pAd->BulkOutCompleteOther = 0; + pAd->BulkOutCompleteCancel = 0; + pAd->BulkInReq = 0; + pAd->BulkInComplete = 0; + pAd->BulkInCompleteFail = 0; + + //pAd->QuickTimerP = 100; + //pAd->TurnAggrBulkInCount = 0; + pAd->bUsbTxBulkAggre = 0; + + // init as unsed value to ensure driver will set to MCU once. + pAd->LedIndicatorStregth = 0xFF; + + pAd->CommonCfg.MaxPktOneTxBulk = 2; + pAd->CommonCfg.TxBulkFactor = 1; + pAd->CommonCfg.RxBulkFactor =1; + + pAd->CommonCfg.TxPower = 100; //mW + + NdisZeroMemory(&pAd->CommonCfg.IOTestParm, sizeof(pAd->CommonCfg.IOTestParm)); +#endif // RT2870 // for(key_index=0; key_indexEepromAccess = FALSE; +#endif pAd->Antenna.word = 0; pAd->CommonCfg.BBPCurrentBW = BW_20; pAd->LedCntl.word = 0; +#ifdef RT2860 pAd->LedIndicatorStregth = 0; pAd->RLnkCtrlOffset = 0; pAd->HostLnkCtrlOffset = 0; pAd->CheckDmaBusyCount = 0; +#endif pAd->bAutoTxAgcA = FALSE; // Default is OFF pAd->bAutoTxAgcG = FALSE; // Default is OFF @@ -3176,23 +3705,11 @@ VOID UserCfgInit( NdisZeroMemory(&pAd->BeaconTxWI, sizeof(pAd->BeaconTxWI)); -#ifdef DOT11_N_SUPPORT NdisZeroMemory(&pAd->CommonCfg.HtCapability, sizeof(pAd->CommonCfg.HtCapability)); pAd->HTCEnable = FALSE; pAd->bBroadComHT = FALSE; pAd->CommonCfg.bRdg = FALSE; -#ifdef DOT11N_DRAFT3 - pAd->CommonCfg.Dot11OBssScanPassiveDwell = dot11OBSSScanPassiveDwell; // Unit : TU. 5~1000 - pAd->CommonCfg.Dot11OBssScanActiveDwell = dot11OBSSScanActiveDwell; // Unit : TU. 10~1000 - pAd->CommonCfg.Dot11BssWidthTriggerScanInt = dot11BSSWidthTriggerScanInterval; // Unit : Second - pAd->CommonCfg.Dot11OBssScanPassiveTotalPerChannel = dot11OBSSScanPassiveTotalPerChannel; // Unit : TU. 200~10000 - pAd->CommonCfg.Dot11OBssScanActiveTotalPerChannel = dot11OBSSScanActiveTotalPerChannel; // Unit : TU. 20~10000 - pAd->CommonCfg.Dot11BssWidthChanTranDelayFactor = dot11BSSWidthChannelTransactionDelayFactor; - pAd->CommonCfg.Dot11OBssScanActivityThre = dot11BSSScanActivityThreshold; // Unit : percentage - pAd->CommonCfg.Dot11BssWidthChanTranDelay = (pAd->CommonCfg.Dot11BssWidthTriggerScanInt * pAd->CommonCfg.Dot11BssWidthChanTranDelayFactor); -#endif // DOT11N_DRAFT3 // - NdisZeroMemory(&pAd->CommonCfg.AddHTInfo, sizeof(pAd->CommonCfg.AddHTInfo)); pAd->CommonCfg.BACapability.field.MMPSmode = MMPS_ENABLE; pAd->CommonCfg.BACapability.field.MpduDensity = 0; @@ -3213,7 +3730,6 @@ VOID UserCfgInit( pAd->CommonCfg.TxBASize = 7; pAd->CommonCfg.REGBACapability.word = pAd->CommonCfg.BACapability.word; -#endif // DOT11_N_SUPPORT // //pAd->CommonCfg.HTPhyMode.field.BW = BW_20; //pAd->CommonCfg.HTPhyMode.field.MCS = MCS_AUTO; @@ -3230,8 +3746,6 @@ VOID UserCfgInit( // // part II. intialize STA specific configuration // -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { RX_FILTER_SET_FLAG(pAd, fRX_FILTER_ACCEPT_DIRECT); RX_FILTER_CLEAR_FLAG(pAd, fRX_FILTER_ACCEPT_MULTICAST); @@ -3270,11 +3784,6 @@ VOID UserCfgInit( pAd->StaCfg.DesiredTransmitSetting.field.MCS = MCS_AUTO; } -#ifdef EXT_BUILD_CHANNEL_LIST - pAd->StaCfg.IEEE80211dClientMode = Rt802_11_D_None; -#endif // EXT_BUILD_CHANNEL_LIST // -#endif // CONFIG_STA_SUPPORT // - // global variables mXXXX used in MAC protocol state machines OPSTATUS_SET_FLAG(pAd, fOP_STATUS_RECEIVE_DTIM); OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_ADHOC_ON); @@ -3284,21 +3793,12 @@ VOID UserCfgInit( pAd->CommonCfg.PhyMode = PHY_11BG_MIXED; // default PHY mode OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED); // CCK use LONG preamble -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { // user desired power mode pAd->StaCfg.WindowsPowerMode = Ndis802_11PowerModeCAM; pAd->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeCAM; pAd->StaCfg.bWindowsACCAMEnable = FALSE; -#ifdef LEAP_SUPPORT - // CCX v1.0 releated init value - RTMPInitTimer(pAd, &pAd->StaCfg.LeapAuthTimer, GET_TIMER_FUNCTION(LeapAuthTimeout), pAd, FALSE); - pAd->StaCfg.LeapAuthMode = CISCO_AuthModeLEAPNone; - pAd->StaCfg.bCkipOn = FALSE; -#endif // LEAP_SUPPORT // - RTMPInitTimer(pAd, &pAd->StaCfg.StaQuickResponeForRateUpTimer, GET_TIMER_FUNCTION(StaQuickResponeForRateUpExec), pAd, FALSE); pAd->StaCfg.StaQuickResponeForRateUpTimerRunning = FALSE; @@ -3326,17 +3826,11 @@ VOID UserCfgInit( NdisZeroMemory(pAd->nickname, IW_ESSID_MAX_SIZE+1); sprintf(pAd->nickname, "%s", STA_NIC_DEVICE_NAME); RTMPInitTimer(pAd, &pAd->StaCfg.WpaDisassocAndBlockAssocTimer, GET_TIMER_FUNCTION(WpaDisassocApAndBlockAssoc), pAd, FALSE); -#ifdef WPA_SUPPLICANT_SUPPORT pAd->StaCfg.IEEE8021X = FALSE; pAd->StaCfg.IEEE8021x_required_keys = FALSE; pAd->StaCfg.WpaSupplicantUP = WPA_SUPPLICANT_DISABLE; -#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT pAd->StaCfg.WpaSupplicantUP = WPA_SUPPLICANT_ENABLE; -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // -#endif // WPA_SUPPLICANT_SUPPORT // - } -#endif // CONFIG_STA_SUPPORT // // Default for extra information is not valid pAd->ExtraInfo = EXTRA_INFO_CLEAR; @@ -3373,41 +3867,12 @@ VOID UserCfgInit( InitializeQueueHeader(&pAd->MacTab.McastPsQueue); NdisAllocateSpinLock(&pAd->MacTabLock); -#ifdef RALINK_ATE - NdisZeroMemory(&pAd->ate, sizeof(ATE_INFO)); - pAd->ate.Mode = ATE_STOP; - pAd->ate.TxCount = 200;/* to exceed TX_RING_SIZE ... */ - pAd->ate.TxLength = 1024; - pAd->ate.TxWI.ShortGI = 0;// LONG GI : 800 ns - pAd->ate.TxWI.PHYMODE = MODE_CCK; - pAd->ate.TxWI.MCS = 3; - pAd->ate.TxWI.BW = BW_20; - pAd->ate.Channel = 1; - pAd->ate.QID = QID_AC_BE; - pAd->ate.Addr1[0] = 0x00; - pAd->ate.Addr1[1] = 0x11; - pAd->ate.Addr1[2] = 0x22; - pAd->ate.Addr1[3] = 0xAA; - pAd->ate.Addr1[4] = 0xBB; - pAd->ate.Addr1[5] = 0xCC; - NdisMoveMemory(pAd->ate.Addr2, pAd->ate.Addr1, ETH_LENGTH_OF_ADDRESS); - NdisMoveMemory(pAd->ate.Addr3, pAd->ate.Addr1, ETH_LENGTH_OF_ADDRESS); - pAd->ate.bRxFer = 0; - pAd->ate.bQATxStart = FALSE; - pAd->ate.bQARxStart = FALSE; - pAd->ate.bFWLoading = FALSE; -#ifdef RALINK_28xx_QA - //pAd->ate.Repeat = 0; - pAd->ate.TxStatus = 0; - pAd->ate.AtePid = THREAD_PID_INIT_VALUE; -#endif // RALINK_28xx_QA // -#endif // RALINK_ATE // - - pAd->CommonCfg.bWiFiTest = FALSE; +#ifdef RT2860 pAd->bPCIclkOff = FALSE; RTMP_SET_PSFLAG(pAd, fRTMP_PS_CAN_GO_SLEEP); +#endif DBGPRINT(RT_DEBUG_TRACE, ("<-- UserCfgInit\n")); } @@ -3509,6 +3974,9 @@ VOID RTMPInitTimer( pTimer->State = FALSE; pTimer->cookie = (ULONG) pData; +#ifdef RT2870 + pTimer->pAd = pAd; +#endif // RT2870 // RTMP_OS_Init_Timer(pAd, &pTimer->TimerObj, pTimerFunc, (PVOID) pTimer); } @@ -3635,6 +4103,12 @@ VOID RTMPCancelTimer( if (*pCancelled == TRUE) pTimer->State = TRUE; +#ifdef RT2870 + // We need to go-through the TimerQ to findout this timer handler and remove it if + // it's still waiting for execution. + + RT2870_TimerQ_Remove(pTimer->pAd, pTimer); +#endif // RT2870 // } else { @@ -3674,13 +4148,6 @@ VOID RTMPSetLED( UCHAR HighByte = 0; UCHAR LowByte; -// In ATE mode of RT2860 AP/STA, we have erased 8051 firmware. -// So LED mode is not supported when ATE is running. -#ifdef RALINK_ATE - if (ATE_ON(pAd)) - return; -#endif // RALINK_ATE // - LowByte = pAd->LedCntl.field.LedMode&0x7f; switch (Status) { diff --git a/drivers/staging/rt2860/common/rtmp_tkip.c b/drivers/staging/rt2860/common/rtmp_tkip.c index a87ea3a5d3ea..4a7fda69f9b4 100644 --- a/drivers/staging/rt2860/common/rtmp_tkip.c +++ b/drivers/staging/rt2860/common/rtmp_tkip.c @@ -199,15 +199,9 @@ typedef struct PACKED _IV_CONTROL_ { struct PACKED { -#ifdef RT_BIG_ENDIAN - UCHAR KeyID:2; - UCHAR ExtIV:1; - UCHAR Rsvd:5; -#else UCHAR Rsvd:5; UCHAR ExtIV:1; UCHAR KeyID:2; -#endif } field; UCHAR Byte; } CONTROL; @@ -1114,10 +1108,6 @@ BOOLEAN RTMPSoftDecryptTKIP( UCHAR MIC[8]; UCHAR TrailMIC[8]; -#ifdef RT_BIG_ENDIAN - RTMPFrameEndianChange(pAd, (PUCHAR)pData, DIR_READ, FALSE); -#endif - fc0 = *pData; fc1 = *(pData + 1); @@ -1224,9 +1214,6 @@ BOOLEAN RTMPSoftDecryptTKIP( return (FALSE); } -#ifdef RT_BIG_ENDIAN - RTMPFrameEndianChange(pAd, (PUCHAR)pData, DIR_READ, FALSE); -#endif return TRUE; } @@ -1266,10 +1253,6 @@ BOOLEAN RTMPSoftDecryptAES( UCHAR MIC[8]; UCHAR TrailMIC[8]; -#ifdef RT_BIG_ENDIAN - RTMPFrameEndianChange(pAd, (PUCHAR)pData, DIR_READ, FALSE); -#endif - fc0 = *pData; fc1 = *(pData + 1); @@ -1437,10 +1420,6 @@ BOOLEAN RTMPSoftDecryptAES( return FALSE; } -#ifdef RT_BIG_ENDIAN - RTMPFrameEndianChange(pAd, (PUCHAR)pData, DIR_READ, FALSE); -#endif - return TRUE; } diff --git a/drivers/staging/rt2860/common/rtmp_wep.c b/drivers/staging/rt2860/common/rtmp_wep.c index ffe26c237950..8e833e7011bd 100644 --- a/drivers/staging/rt2860/common/rtmp_wep.c +++ b/drivers/staging/rt2860/common/rtmp_wep.c @@ -144,14 +144,12 @@ VOID RTMPInitWepEngine( pAd->PrivateInfo.FCSCRC32 = PPPINITFCS32; //Init crc32. -#ifdef CONFIG_STA_SUPPORT if (pAd->StaCfg.bCkipOn && (pAd->StaCfg.CkipFlag & 0x10) && (pAd->OpMode == OPMODE_STA)) { ARCFOUR_INIT(&pAd->PrivateInfo.WEPCONTEXT, pKey, KeyLen); //INIT SBOX, KEYLEN+3(IV) NdisMoveMemory(pDest, pKey, 3); //Append Init Vector } else -#endif // CONFIG_STA_SUPPORT // { NdisMoveMemory(WEPKEY + 3, pKey, KeyLen); diff --git a/drivers/staging/rt2860/common/spectrum.c b/drivers/staging/rt2860/common/spectrum.c index b3650ec46563..101c2923ca37 100644 --- a/drivers/staging/rt2860/common/spectrum.c +++ b/drivers/staging/rt2860/common/spectrum.c @@ -1060,27 +1060,6 @@ VOID NotifyChSwAnnToPeerAPs( IN UINT8 ChSwMode, IN UINT8 Channel) { -#ifdef WDS_SUPPORT - if (!((pRA[0] & 0xff) == 0xff)) // is pRA a broadcase address. - { - INT i; - // info neighbor APs that Radar signal found throgh WDS link. - for (i = 0; i < MAX_WDS_ENTRY; i++) - { - if (ValidWdsEntry(pAd, i)) - { - PUCHAR pDA = pAd->WdsTab.WdsEntry[i].PeerWdsAddr; - - // DA equal to SA. have no necessary orignal AP which found Radar signal. - if (MAC_ADDR_EQUAL(pTA, pDA)) - continue; - - // send Channel Switch Action frame to info Neighbro APs. - EnqueueChSwAnn(pAd, pDA, ChSwMode, Channel); - } - } - } -#endif // WDS_SUPPORT // } static VOID StartDFSProcedure( @@ -1090,9 +1069,9 @@ static VOID StartDFSProcedure( { // start DFS procedure pAd->CommonCfg.Channel = Channel; -#ifdef DOT11_N_SUPPORT + N_ChannelCheck(pAd); -#endif // DOT11_N_SUPPORT // + pAd->CommonCfg.RadarDetect.RDMode = RD_SWITCHING_MODE; pAd->CommonCfg.RadarDetect.CSCount = 0; } @@ -1475,10 +1454,8 @@ static VOID PeerChSwAnnAction( { CH_SW_ANN_INFO ChSwAnnInfo; PFRAME_802_11 pFr = (PFRAME_802_11)Elem->Msg; -#ifdef CONFIG_STA_SUPPORT UCHAR index = 0, Channel = 0, NewChannel = 0; ULONG Bssidx = 0; -#endif // CONFIG_STA_SUPPORT // NdisZeroMemory(&ChSwAnnInfo, sizeof(CH_SW_ANN_INFO)); if (! PeerChSwAnnSanity(pAd, Elem->Msg, Elem->MsgLen, &ChSwAnnInfo)) @@ -1487,8 +1464,6 @@ static VOID PeerChSwAnnAction( return; } - -#ifdef CONFIG_STA_SUPPORT if (pAd->OpMode == OPMODE_STA) { Bssidx = BssTableSearch(&pAd->ScanTab, pFr->Hdr.Addr3, pAd->CommonCfg.Channel); @@ -1535,7 +1510,6 @@ static VOID PeerChSwAnnAction( } } } -#endif // CONFIG_STA_SUPPORT // return; } @@ -1596,7 +1570,12 @@ static VOID PeerMeasureReportAction( if ((pMeasureReportInfo = kmalloc(sizeof(MEASURE_RPI_REPORT), GFP_ATOMIC)) == NULL) { +#ifndef RT30xx DBGPRINT(RT_DEBUG_ERROR, ("%s unable to alloc memory for measure report buffer (size=%zu).\n", __func__, sizeof(MEASURE_RPI_REPORT))); +#endif +#ifdef RT30xx + DBGPRINT(RT_DEBUG_ERROR, ("%s unable to alloc memory for measure report buffer (size=%d).\n", __func__, sizeof(MEASURE_RPI_REPORT))); +#endif return; } @@ -1756,28 +1735,6 @@ VOID PeerSpectrumAction( case SPEC_CHANNEL_SWITCH: { -#ifdef DOT11N_DRAFT3 - SEC_CHA_OFFSET_IE Secondary; - CHA_SWITCH_ANNOUNCE_IE ChannelSwitch; - - // 802.11h only has Channel Switch Announcement IE. - RTMPMoveMemory(&ChannelSwitch, &Elem->Msg[LENGTH_802_11+4], sizeof (CHA_SWITCH_ANNOUNCE_IE)); - - // 802.11n D3.03 adds secondary channel offset element in the end. - if (Elem->MsgLen == (LENGTH_802_11 + 2 + sizeof (CHA_SWITCH_ANNOUNCE_IE) + sizeof (SEC_CHA_OFFSET_IE))) - { - RTMPMoveMemory(&Secondary, &Elem->Msg[LENGTH_802_11+9], sizeof (SEC_CHA_OFFSET_IE)); - } - else - { - Secondary.SecondaryChannelOffset = 0; - } - - if ((Elem->Msg[LENGTH_802_11+2] == IE_CHANNEL_SWITCH_ANNOUNCEMENT) && (Elem->Msg[LENGTH_802_11+3] == 3)) - { - ChannelSwitchAction(pAd, Elem->Wcid, ChannelSwitch.NewChannel, Secondary.SecondaryChannelOffset); - } -#endif // DOT11N_DRAFT3 // } PeerChSwAnnAction(pAd, Elem); break; diff --git a/drivers/staging/rt2860/leap.h b/drivers/staging/rt2860/leap.h deleted file mode 100644 index 6818c1ff4d73..000000000000 --- a/drivers/staging/rt2860/leap.h +++ /dev/null @@ -1,215 +0,0 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - leap.h - - Abstract: - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Name Date Modification logs -*/ -#ifndef __LEAP_H__ -#define __LEAP_H__ - -// Messages for Associate state machine -#define LEAP_MACHINE_BASE 30 - -#define LEAP_MSG_REQUEST_IDENTITY 31 -#define LEAP_MSG_REQUEST_LEAP 32 -#define LEAP_MSG_SUCCESS 33 -#define LEAP_MSG_FAILED 34 -#define LEAP_MSG_RESPONSE_LEAP 35 -#define LEAP_MSG_EAPOLKEY 36 -#define LEAP_MSG_UNKNOWN 37 -#define LEAP_MSG 38 -//! assoc state-machine states -#define LEAP_IDLE 0 -#define LEAP_WAIT_IDENTITY_REQUEST 1 -#define LEAP_WAIT_CHANLLENGE_REQUEST 2 -#define LEAP_WAIT_SUCCESS 3 -#define LEAP_WAIT_CHANLLENGE_RESPONSE 4 -#define LEAP_WAIT_EAPOLKEY 5 - -#define LEAP_REASON_INVALID_AUTH 0x01 -#define LEAP_REASON_AUTH_TIMEOUT 0x02 -#define LEAP_REASON_CHALLENGE_FROM_AP_FAILED 0x03 -#define LEAP_REASON_CHALLENGE_TO_AP_FAILED 0x04 - -#define CISCO_AuthModeLEAP 0x80 -#define CISCO_AuthModeLEAPNone 0x00 -#define LEAP_AUTH_TIMEOUT 30000 -#define LEAP_CHALLENGE_RESPONSE_LENGTH 24 -#define LEAP_CHALLENGE_REQUEST_LENGTH 8 - -typedef struct _LEAP_EAPOL_HEADER_ { - UCHAR Version; - UCHAR Type; - UCHAR Length[2]; -} LEAP_EAPOL_HEADER, *PLEAP_EAPOL_HEADER; - -typedef struct _LEAP_EAPOL_PACKET_ { - UCHAR Code; - UCHAR Identifier; - UCHAR Length[2]; - UCHAR Type; -} LEAP_EAPOL_PACKET, *PLEAP_EAPOL_PACKET; - -typedef struct _LEAP_EAP_CONTENTS_ { - UCHAR Version; - UCHAR Reserved; - UCHAR Length; -} LEAP_EAP_CONTENTS, *PLEAP_EAP_CONTENTS; - -/*** EAPOL key ***/ -typedef struct _EAPOL_KEY_HEADER_ { - UCHAR Type; - UCHAR Length[2]; - UCHAR Counter[8]; - UCHAR IV[16]; - UCHAR Index; - UCHAR Signature[16]; -} EAPOL_KEY_HEADER, *PEAPOL_KEY_HEADER; - -BOOLEAN LeapMsgTypeSubst( - IN UCHAR EAPType, - OUT ULONG *MsgType); - -VOID LeapMachinePerformAction( - IN PRTMP_ADAPTER pAd, - IN STATE_MACHINE *S, - IN MLME_QUEUE_ELEM *Elem); - -VOID LeapMacHeaderInit( - IN PRTMP_ADAPTER pAd, - IN OUT PHEADER_802_11 pHdr80211, - IN UCHAR wep, - IN PUCHAR pAddr3); - -VOID LeapStartAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID LeapIdentityAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID LeapPeerChallengeAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID HashPwd( - IN PUCHAR pwd, - IN INT pwdlen, - OUT PUCHAR hash); - -VOID PeerChallengeResponse( - IN PUCHAR szChallenge, - IN PUCHAR smbPasswd, - OUT PUCHAR szResponse); - -VOID ParityKey( - OUT PUCHAR szOut, - IN PUCHAR szIn); - -VOID DesKey( - OUT ULONG k[16][2], - IN PUCHAR key, - IN INT decrypt); - -VOID Des( - IN ULONG ks[16][2], - OUT UCHAR block[8]); - -VOID DesEncrypt( - IN PUCHAR szClear, - IN PUCHAR szKey, - OUT PUCHAR szOut); - -VOID LeapNetworkChallengeAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID LeapNetworkChallengeResponse( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID HashpwdHash( - IN PUCHAR hash, - IN PUCHAR hashhash); - -VOID ProcessSessionKey( - OUT PUCHAR SessionKey, - IN PUCHAR hash2, - IN PUCHAR ChallengeToRadius, - IN PUCHAR ChallengeResponseFromRadius, - IN PUCHAR ChallengeFromRadius, - IN PUCHAR ChallengeResponseToRadius); - -VOID LeapEapolKeyAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID RogueApTableInit( - IN ROGUEAP_TABLE *Tab); - -ULONG RogueApTableSearch( - IN ROGUEAP_TABLE *Tab, - IN PUCHAR pAddr); - -VOID RogueApEntrySet( - IN PRTMP_ADAPTER pAd, - OUT ROGUEAP_ENTRY *pRogueAp, - IN PUCHAR pAddr, - IN UCHAR FaileCode); - -ULONG RogueApTableSetEntry( - IN PRTMP_ADAPTER pAd, - OUT ROGUEAP_TABLE *Tab, - IN PUCHAR pAddr, - IN UCHAR FaileCode); - -VOID RogueApTableDeleteEntry( - IN OUT ROGUEAP_TABLE *Tab, - IN PUCHAR pAddr); - -VOID LeapAuthTimeout( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); - -VOID LeapSendRogueAPReport( - IN PRTMP_ADAPTER pAd); - -BOOLEAN CCKMAssocRspSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen); - -#endif // __LEAP_H__ diff --git a/drivers/staging/rt2860/mlme.h b/drivers/staging/rt2860/mlme.h index 5cb61652b668..3d1a8284fbd4 100644 --- a/drivers/staging/rt2860/mlme.h +++ b/drivers/staging/rt2860/mlme.h @@ -73,17 +73,7 @@ #define MAX_CHANNEL_TIME 140 // unit: msec, for single band scan #define FAST_ACTIVE_SCAN_TIME 30 // Active scan waiting for probe response time #define CW_MIN_IN_BITS 4 // actual CwMin = 2^CW_MIN_IN_BITS - 1 - - -#ifdef CONFIG_STA_SUPPORT -#ifndef CONFIG_AP_SUPPORT #define CW_MAX_IN_BITS 10 // actual CwMax = 2^CW_MAX_IN_BITS - 1 -#endif -#endif // CONFIG_STA_SUPPORT // - -#ifdef CONFIG_APSTA_MIXED_SUPPORT -extern UINT32 CW_MAX_IN_BITS; -#endif // CONFIG_APSTA_MIXED_SUPPORT // // Note: RSSI_TO_DBM_OFFSET has been changed to variable for new RF (2004-0720). // SHould not refer to this constant anymore @@ -115,10 +105,7 @@ extern UINT32 CW_MAX_IN_BITS; #define BSS_NOT_FOUND 0xFFFFFFFF - -#ifdef CONFIG_STA_SUPPORT #define MAX_LEN_OF_MLME_QUEUE 40 //10 -#endif // CONFIG_STA_SUPPORT // #define SCAN_PASSIVE 18 // scan with no probe request, only wait beacon and probe response #define SCAN_ACTIVE 19 // scan with probe request, and wait beacon and probe response @@ -128,10 +115,6 @@ extern UINT32 CW_MAX_IN_BITS; #define SCAN_CISCO_CHANNEL_LOAD 23 // Single channel passive scan for channel load collection #define FAST_SCAN_ACTIVE 24 // scan with probe request, and wait beacon and probe response -#ifdef DOT11N_DRAFT3 -#define SCAN_2040_BSS_COEXIST 26 -#endif // DOT11N_DRAFT3 // - #define MAC_ADDR_IS_GROUP(Addr) (((Addr[0]) & 0x01)) #define MAC_ADDR_HASH(Addr) (Addr[0] ^ Addr[1] ^ Addr[2] ^ Addr[3] ^ Addr[4] ^ Addr[5]) #define MAC_ADDR_HASH_INDEX(Addr) (MAC_ADDR_HASH(Addr) % HASH_TABLE_SIZE) @@ -204,22 +187,6 @@ if (((__pEntry)) != NULL) \ // // HT Capability INFO field in HT Cap IE . typedef struct PACKED { -#ifdef RT_BIG_ENDIAN - USHORT LSIGTxopProSup:1; - USHORT Forty_Mhz_Intolerant:1; - USHORT PSMP:1; - USHORT CCKmodein40:1; - USHORT AMsduSize:1; - USHORT DelayedBA:1; //rt2860c not support - USHORT RxSTBC:2; - USHORT TxSTBC:1; - USHORT ShortGIfor40:1; //for40MHz - USHORT ShortGIfor20:1; - USHORT GF:1; //green field - USHORT MimoPs:2;//momi power safe - USHORT ChannelWidth:1; - USHORT AdvCoding:1; -#else USHORT AdvCoding:1; USHORT ChannelWidth:1; USHORT MimoPs:2;//momi power safe @@ -234,53 +201,29 @@ typedef struct PACKED { USHORT PSMP:1; USHORT Forty_Mhz_Intolerant:1; USHORT LSIGTxopProSup:1; -#endif /* !RT_BIG_ENDIAN */ } HT_CAP_INFO, *PHT_CAP_INFO; // HT Capability INFO field in HT Cap IE . typedef struct PACKED { -#ifdef RT_BIG_ENDIAN - UCHAR rsv:3;//momi power safe - UCHAR MpduDensity:3; - UCHAR MaxRAmpduFactor:2; -#else UCHAR MaxRAmpduFactor:2; UCHAR MpduDensity:3; UCHAR rsv:3;//momi power safe -#endif /* !RT_BIG_ENDIAN */ } HT_CAP_PARM, *PHT_CAP_PARM; // HT Capability INFO field in HT Cap IE . typedef struct PACKED { UCHAR MCSSet[10]; UCHAR SupRate[2]; // unit : 1Mbps -#ifdef RT_BIG_ENDIAN - UCHAR rsv:3; - UCHAR MpduDensity:1; - UCHAR TxStream:2; - UCHAR TxRxNotEqual:1; - UCHAR TxMCSSetDefined:1; -#else UCHAR TxMCSSetDefined:1; UCHAR TxRxNotEqual:1; UCHAR TxStream:2; UCHAR MpduDensity:1; UCHAR rsv:3; -#endif // RT_BIG_ENDIAN // UCHAR rsv3[3]; } HT_MCS_SET, *PHT_MCS_SET; // HT Capability INFO field in HT Cap IE . typedef struct PACKED { -#ifdef RT_BIG_ENDIAN - USHORT rsv2:4; - USHORT RDGSupport:1; //reverse Direction Grant support - USHORT PlusHTC:1; //+HTC control field support - USHORT MCSFeedback:2; //0:no MCS feedback, 2:unsolicited MCS feedback, 3:Full MCS feedback, 1:rsv. - USHORT rsv:5;//momi power safe - USHORT TranTime:2; - USHORT Pco:1; -#else USHORT Pco:1; USHORT TranTime:2; USHORT rsv:5;//momi power safe @@ -288,33 +231,10 @@ typedef struct PACKED { USHORT PlusHTC:1; //+HTC control field support USHORT RDGSupport:1; //reverse Direction Grant support USHORT rsv2:4; -#endif /* RT_BIG_ENDIAN */ } EXT_HT_CAP_INFO, *PEXT_HT_CAP_INFO; // HT Beamforming field in HT Cap IE . typedef struct PACKED _HT_BF_CAP{ -#ifdef RT_BIG_ENDIAN - ULONG rsv:3; - ULONG ChanEstimation:2; - ULONG CSIRowBFSup:2; - ULONG ComSteerBFAntSup:2; - ULONG NoComSteerBFAntSup:2; - ULONG CSIBFAntSup:2; - ULONG MinGrouping:2; - ULONG ExpComBF:2; - ULONG ExpNoComBF:2; - ULONG ExpCSIFbk:2; - ULONG ExpComSteerCapable:1; - ULONG ExpNoComSteerCapable:1; - ULONG ExpCSICapable:1; - ULONG Calibration:2; - ULONG ImpTxBFCapable:1; - ULONG TxNDPCapable:1; - ULONG RxNDPCapable:1; - ULONG TxSoundCapable:1; - ULONG RxSoundCapable:1; - ULONG TxBFRecCapable:1; -#else ULONG TxBFRecCapable:1; ULONG RxSoundCapable:1; ULONG TxSoundCapable:1; @@ -335,21 +255,10 @@ typedef struct PACKED _HT_BF_CAP{ ULONG CSIRowBFSup:2; ULONG ChanEstimation:2; ULONG rsv:3; -#endif // RT_BIG_ENDIAN // } HT_BF_CAP, *PHT_BF_CAP; // HT antenna selection field in HT Cap IE . typedef struct PACKED _HT_AS_CAP{ -#ifdef RT_BIG_ENDIAN - UCHAR rsv:1; - UCHAR TxSoundPPDU:1; - UCHAR RxASel:1; - UCHAR AntIndFbk:1; - UCHAR ExpCSIFbk:1; - UCHAR AntIndFbkTxASEL:1; - UCHAR ExpCSIFbkTxASEL:1; - UCHAR AntSelect:1; -#else UCHAR AntSelect:1; UCHAR ExpCSIFbkTxASEL:1; UCHAR AntIndFbkTxASEL:1; @@ -358,7 +267,6 @@ typedef struct PACKED _HT_AS_CAP{ UCHAR RxASel:1; UCHAR TxSoundPPDU:1; UCHAR rsv:1; -#endif // RT_BIG_ENDIAN // } HT_AS_CAP, *PHT_AS_CAP; // Draft 1.0 set IE length 26, but is extensible.. @@ -402,17 +310,10 @@ typedef struct PACKED _OVERLAP_BSS_SCAN_IE{ // 7.3.2.56. 20/40 Coexistence element used in Element ID = 72 = IE_2040_BSS_COEXIST typedef union PACKED _BSS_2040_COEXIST_IE{ struct PACKED { - #ifdef RT_BIG_ENDIAN - UCHAR rsv:5; - UCHAR BSS20WidthReq:1; - UCHAR Intolerant40:1; - UCHAR InfoReq:1; - #else UCHAR InfoReq:1; UCHAR Intolerant40:1; // Inter-BSS. set 1 when prohibits a receiving BSS from operating as a 20/40 Mhz BSS. UCHAR BSS20WidthReq:1; // Intra-BSS set 1 when prohibits a receiving AP from operating its BSS as a 20/40MHz BSS. UCHAR rsv:5; -#endif // RT_BIG_ENDIAN // } field; UCHAR word; } BSS_2040_COEXIST_IE, *PBSS_2040_COEXIST_IE; @@ -438,17 +339,10 @@ typedef struct _TRIGGER_EVENT_TAB{ // 7.3.27 20/40 Bss Coexistence Mgmt capability used in extended capabilities information IE( ID = 127 = IE_EXT_CAPABILITY). // This is the first octet and was defined in 802.11n D3.03 and 802.11yD9.0 typedef struct PACKED _EXT_CAP_INFO_ELEMENT{ -#ifdef RT_BIG_ENDIAN - UCHAR rsv2:5; - UCHAR ExtendChannelSwitch:1; - UCHAR rsv:1; - UCHAR BssCoexistMgmtSupport:1; -#else UCHAR BssCoexistMgmtSupport:1; UCHAR rsv:1; UCHAR ExtendChannelSwitch:1; UCHAR rsv2:5; -#endif // RT_BIG_ENDIAN // }EXT_CAP_INFO_ELEMENT, *PEXT_CAP_INFO_ELEMENT; @@ -494,18 +388,6 @@ typedef struct { //This structure substracts ralink supports from all 802.11n-related features. //Features not listed here but contained in 802.11n spec are not supported in rt2860. typedef struct { -#ifdef RT_BIG_ENDIAN - USHORT rsv:5; - USHORT AmsduSize:1; // Max receiving A-MSDU size - USHORT AmsduEnable:1; // Enable to transmit A-MSDU. Suggest disable. We should use A-MPDU to gain best benifit of 802.11n - USHORT RxSTBC:2; // 2 bits - USHORT TxSTBC:1; - USHORT ShortGIfor40:1; //for40MHz - USHORT ShortGIfor20:1; - USHORT GF:1; //green field - USHORT MimoPs:2;//mimo power safe MMPS_ - USHORT ChannelWidth:1; -#else USHORT ChannelWidth:1; USHORT MimoPs:2;//mimo power safe MMPS_ USHORT GF:1; //green field @@ -516,34 +398,18 @@ typedef struct { USHORT AmsduEnable:1; // Enable to transmit A-MSDU. Suggest disable. We should use A-MPDU to gain best benifit of 802.11n USHORT AmsduSize:1; // Max receiving A-MSDU size USHORT rsv:5; -#endif //Substract from Addiont HT INFO IE -#ifdef RT_BIG_ENDIAN - UCHAR RecomWidth:1; - UCHAR ExtChanOffset:2; // Please not the difference with following UCHAR NewExtChannelOffset; from 802.11n - UCHAR MpduDensity:3; - UCHAR MaxRAmpduFactor:2; -#else UCHAR MaxRAmpduFactor:2; UCHAR MpduDensity:3; UCHAR ExtChanOffset:2; // Please not the difference with following UCHAR NewExtChannelOffset; from 802.11n UCHAR RecomWidth:1; -#endif -#ifdef RT_BIG_ENDIAN - USHORT rsv2:11; - USHORT OBSS_NonHTExist:1; - USHORT rsv3:1; - USHORT NonGfPresent:1; - USHORT OperaionMode:2; -#else USHORT OperaionMode:2; USHORT NonGfPresent:1; USHORT rsv3:1; USHORT OBSS_NonHTExist:1; USHORT rsv2:11; -#endif // New Extension Channel Offset IE UCHAR NewExtChannelOffset; @@ -553,50 +419,24 @@ typedef struct { // field in Addtional HT Information IE . typedef struct PACKED { -#ifdef RT_BIG_ENDIAN - UCHAR SerInterGranu:3; - UCHAR S_PSMPSup:1; - UCHAR RifsMode:1; - UCHAR RecomWidth:1; - UCHAR ExtChanOffset:2; -#else UCHAR ExtChanOffset:2; UCHAR RecomWidth:1; UCHAR RifsMode:1; UCHAR S_PSMPSup:1; //Indicate support for scheduled PSMP UCHAR SerInterGranu:3; //service interval granularity -#endif } ADD_HTINFO, *PADD_HTINFO; typedef struct PACKED{ -#ifdef RT_BIG_ENDIAN - USHORT rsv2:11; - USHORT OBSS_NonHTExist:1; - USHORT rsv:1; - USHORT NonGfPresent:1; - USHORT OperaionMode:2; -#else USHORT OperaionMode:2; USHORT NonGfPresent:1; USHORT rsv:1; USHORT OBSS_NonHTExist:1; USHORT rsv2:11; -#endif } ADD_HTINFO2, *PADD_HTINFO2; // TODO: Need sync with spec about the definition of StbcMcs. In Draft 3.03, it's reserved. typedef struct PACKED{ -#ifdef RT_BIG_ENDIAN - USHORT rsv:4; - USHORT PcoPhase:1; - USHORT PcoActive:1; - USHORT LsigTxopProt:1; - USHORT STBCBeacon:1; - USHORT DualCTSProtect:1; - USHORT DualBeacon:1; - USHORT StbcMcs:6; -#else USHORT StbcMcs:6; USHORT DualBeacon:1; USHORT DualCTSProtect:1; @@ -605,7 +445,6 @@ typedef struct PACKED{ USHORT PcoActive:1; USHORT PcoPhase:1; USHORT rsv:4; -#endif // RT_BIG_ENDIAN // } ADD_HTINFO3, *PADD_HTINFO3; #define SIZE_ADD_HT_INFO_IE 22 @@ -624,22 +463,6 @@ typedef struct PACKED{ // 4-byte HTC field. maybe included in any frame except non-QOS data frame. The Order bit must set 1. typedef struct PACKED { -#ifdef RT_BIG_ENDIAN - UINT32 RDG:1; //RDG / More PPDU - UINT32 ACConstraint:1; //feedback request - UINT32 rsv:5; //calibration sequence - UINT32 ZLFAnnouce:1; // ZLF announcement - UINT32 CSISTEERING:2; //CSI/ STEERING - UINT32 FBKReq:2; //feedback request - UINT32 CalSeq:2; //calibration sequence - UINT32 CalPos:2; // calibration position - UINT32 MFBorASC:7; //Link adaptation feedback containing recommended MCS. 0x7f for no feedback or not available - UINT32 MFS:3; //SET to the received value of MRS. 0x111 for unsolicited MFB. - UINT32 MRSorASI:3; // MRQ Sequence identifier. unchanged during entire procedure. 0x000-0x110. - UINT32 MRQ:1; //MCS feedback. Request for a MCS feedback - UINT32 TRQ:1; //sounding request - UINT32 MA:1; //management action payload exist in (QoS Null+HTC) -#else UINT32 MA:1; //management action payload exist in (QoS Null+HTC) UINT32 TRQ:1; //sounding request UINT32 MRQ:1; //MCS feedback. Request for a MCS feedback @@ -654,41 +477,19 @@ typedef struct PACKED { UINT32 rsv:5; //calibration sequence UINT32 ACConstraint:1; //feedback request UINT32 RDG:1; //RDG / More PPDU -#endif /* !RT_BIG_ENDIAN */ } HT_CONTROL, *PHT_CONTROL; // 2-byte QOS CONTROL field typedef struct PACKED { -#ifdef RT_BIG_ENDIAN - USHORT Txop_QueueSize:8; - USHORT AMsduPresent:1; - USHORT AckPolicy:2; //0: normal ACK 1:No ACK 2:scheduled under MTBA/PSMP 3: BA - USHORT EOSP:1; - USHORT TID:4; -#else USHORT TID:4; USHORT EOSP:1; USHORT AckPolicy:2; //0: normal ACK 1:No ACK 2:scheduled under MTBA/PSMP 3: BA USHORT AMsduPresent:1; USHORT Txop_QueueSize:8; -#endif /* !RT_BIG_ENDIAN */ } QOS_CONTROL, *PQOS_CONTROL; // 2-byte Frame control field typedef struct PACKED { -#ifdef RT_BIG_ENDIAN - USHORT Order:1; // Strict order expected - USHORT Wep:1; // Wep data - USHORT MoreData:1; // More data bit - USHORT PwrMgmt:1; // Power management bit - USHORT Retry:1; // Retry status bit - USHORT MoreFrag:1; // More fragment bit - USHORT FrDs:1; // From DS indication - USHORT ToDs:1; // To DS indication - USHORT SubType:4; // MSDU subtype - USHORT Type:2; // MSDU type - USHORT Ver:2; // Protocol version -#else USHORT Ver:2; // Protocol version USHORT Type:2; // MSDU type USHORT SubType:4; // MSDU subtype @@ -700,7 +501,6 @@ typedef struct PACKED { USHORT MoreData:1; // More data bit USHORT Wep:1; // Wep data USHORT Order:1; // Strict order expected -#endif /* !RT_BIG_ENDIAN */ } FRAME_CONTROL, *PFRAME_CONTROL; typedef struct PACKED _HEADER_802_11 { @@ -709,13 +509,8 @@ typedef struct PACKED _HEADER_802_11 { UCHAR Addr1[MAC_ADDR_LEN]; UCHAR Addr2[MAC_ADDR_LEN]; UCHAR Addr3[MAC_ADDR_LEN]; -#ifdef RT_BIG_ENDIAN - USHORT Sequence:12; - USHORT Frag:4; -#else USHORT Frag:4; USHORT Sequence:12; -#endif /* !RT_BIG_ENDIAN */ UCHAR Octet[0]; } HEADER_802_11, *PHEADER_802_11; @@ -739,42 +534,24 @@ typedef struct PACKED _HEADER_802_3 { ////Block ACK related format // 2-byte BA Parameter field in DELBA frames to terminate an already set up bA typedef struct PACKED{ -#ifdef RT_BIG_ENDIAN - USHORT TID:4; // value of TC os TS - USHORT Initiator:1; // 1: originator 0:recipient - USHORT Rsv:11; // always set to 0 -#else USHORT Rsv:11; // always set to 0 USHORT Initiator:1; // 1: originator 0:recipient USHORT TID:4; // value of TC os TS -#endif /* !RT_BIG_ENDIAN */ } DELBA_PARM, *PDELBA_PARM; // 2-byte BA Parameter Set field in ADDBA frames to signal parm for setting up a BA typedef struct PACKED { -#ifdef RT_BIG_ENDIAN - USHORT BufSize:10; // number of buffe of size 2304 octetsr - USHORT TID:4; // value of TC os TS - USHORT BAPolicy:1; // 1: immediately BA 0:delayed BA - USHORT AMSDUSupported:1; // 0: not permitted 1: permitted -#else USHORT AMSDUSupported:1; // 0: not permitted 1: permitted USHORT BAPolicy:1; // 1: immediately BA 0:delayed BA USHORT TID:4; // value of TC os TS USHORT BufSize:10; // number of buffe of size 2304 octetsr -#endif /* !RT_BIG_ENDIAN */ } BA_PARM, *PBA_PARM; // 2-byte BA Starting Seq CONTROL field typedef union PACKED { struct PACKED { -#ifdef RT_BIG_ENDIAN - USHORT StartSeq:12; // sequence number of the 1st MSDU for which this BAR is sent - USHORT FragNum:4; // always set to 0 -#else USHORT FragNum:4; // always set to 0 USHORT StartSeq:12; // sequence number of the 1st MSDU for which this BAR is sent -#endif /* RT_BIG_ENDIAN */ } field; USHORT word; } BASEQ_CONTROL, *PBASEQ_CONTROL; @@ -782,63 +559,34 @@ typedef union PACKED { //BAControl and BARControl are the same // 2-byte BA CONTROL field in BA frame typedef struct PACKED { -#ifdef RT_BIG_ENDIAN - USHORT TID:4; - USHORT Rsv:9; - USHORT Compressed:1; - USHORT MTID:1; //EWC V1.24 - USHORT ACKPolicy:1; // only related to N-Delayed BA. But not support in RT2860b. 0:NormalACK 1:No ACK -#else USHORT ACKPolicy:1; // only related to N-Delayed BA. But not support in RT2860b. 0:NormalACK 1:No ACK USHORT MTID:1; //EWC V1.24 USHORT Compressed:1; USHORT Rsv:9; USHORT TID:4; -#endif /* !RT_BIG_ENDIAN */ } BA_CONTROL, *PBA_CONTROL; // 2-byte BAR CONTROL field in BAR frame typedef struct PACKED { -#ifdef RT_BIG_ENDIAN - USHORT TID:4; - USHORT Rsv1:9; - USHORT Compressed:1; - USHORT MTID:1; //if this bit1, use FRAME_MTBA_REQ, if 0, use FRAME_BA_REQ - USHORT ACKPolicy:1; -#else USHORT ACKPolicy:1; // 0:normal ack, 1:no ack. USHORT MTID:1; //if this bit1, use FRAME_MTBA_REQ, if 0, use FRAME_BA_REQ USHORT Compressed:1; USHORT Rsv1:9; USHORT TID:4; -#endif /* !RT_BIG_ENDIAN */ } BAR_CONTROL, *PBAR_CONTROL; // BARControl in MTBAR frame typedef struct PACKED { -#ifdef RT_BIG_ENDIAN - USHORT NumTID:4; - USHORT Rsv1:9; - USHORT Compressed:1; - USHORT MTID:1; - USHORT ACKPolicy:1; -#else USHORT ACKPolicy:1; USHORT MTID:1; USHORT Compressed:1; USHORT Rsv1:9; USHORT NumTID:4; -#endif /* !RT_BIG_ENDIAN */ } MTBAR_CONTROL, *PMTBAR_CONTROL; typedef struct PACKED { -#ifdef RT_BIG_ENDIAN - USHORT TID:4; - USHORT Rsv1:12; -#else USHORT Rsv1:12; USHORT TID:4; -#endif /* !RT_BIG_ENDIAN */ } PER_TID_INFO, *PPER_TID_INFO; typedef struct { @@ -1058,15 +806,6 @@ typedef struct { // QBSS Info field in QSTA's assoc req typedef struct PACKED { -#ifdef RT_BIG_ENDIAN - UCHAR Rsv2:1; - UCHAR MaxSPLength:2; - UCHAR Rsv1:1; - UCHAR UAPSD_AC_BE:1; - UCHAR UAPSD_AC_BK:1; - UCHAR UAPSD_AC_VI:1; - UCHAR UAPSD_AC_VO:1; -#else UCHAR UAPSD_AC_VO:1; UCHAR UAPSD_AC_VI:1; UCHAR UAPSD_AC_BK:1; @@ -1074,20 +813,13 @@ typedef struct PACKED { UCHAR Rsv1:1; UCHAR MaxSPLength:2; UCHAR Rsv2:1; -#endif /* !RT_BIG_ENDIAN */ } QBSS_STA_INFO_PARM, *PQBSS_STA_INFO_PARM; // QBSS Info field in QAP's Beacon/ProbeRsp typedef struct PACKED { -#ifdef RT_BIG_ENDIAN - UCHAR UAPSD:1; - UCHAR Rsv:3; - UCHAR ParamSetCount:4; -#else UCHAR ParamSetCount:4; UCHAR Rsv:3; UCHAR UAPSD:1; -#endif /* !RT_BIG_ENDIAN */ } QBSS_AP_INFO_PARM, *PQBSS_AP_INFO_PARM; // QOS Capability reported in QAP's BEACON/ProbeRsp @@ -1101,13 +833,10 @@ typedef struct { UCHAR EdcaUpdateCount; } QOS_CAPABILITY_PARM, *PQOS_CAPABILITY_PARM; -#ifdef CONFIG_STA_SUPPORT typedef struct { UCHAR IELen; UCHAR IE[MAX_CUSTOM_LEN]; } WPA_IE_; -#endif // CONFIG_STA_SUPPORT // - typedef struct { UCHAR Bssid[MAC_ADDR_LEN]; @@ -1167,14 +896,8 @@ typedef struct { EDCA_PARM EdcaParm; QOS_CAPABILITY_PARM QosCapability; QBSS_LOAD_PARM QbssLoad; -#ifdef CONFIG_STA_SUPPORT WPA_IE_ WpaIE; WPA_IE_ RsnIE; -#ifdef EXT_BUILD_CHANNEL_LIST - UCHAR CountryString[3]; - BOOLEAN bHasCountryIE; -#endif // EXT_BUILD_CHANNEL_LIST // -#endif // CONFIG_STA_SUPPORT // } BSS_ENTRY, *PBSS_ENTRY; typedef struct { @@ -1333,29 +1056,6 @@ typedef struct _MLME_START_REQ_STRUCT { UCHAR SsidLen; } MLME_START_REQ_STRUCT, *PMLME_START_REQ_STRUCT; -#ifdef CONFIG_STA_SUPPORT -#ifdef QOS_DLS_SUPPORT -// structure for DLS -typedef struct _RT_802_11_DLS { - USHORT TimeOut; // Use to time out while slience, unit: second , set by UI - USHORT CountDownTimer; // Use to time out while slience,unit: second , used by driver only - NDIS_802_11_MAC_ADDRESS MacAddr; // set by UI - UCHAR Status; // 0: none , 1: wait STAkey, 2: finish DLS setup , set by driver only - BOOLEAN Valid; // 1: valid , 0: invalid , set by UI, use to setup or tear down DLS link - RALINK_TIMER_STRUCT Timer; // Use to time out while handshake - USHORT Sequence; - USHORT MacTabMatchWCID; // ASIC - BOOLEAN bHTCap; - PVOID pAd; -} RT_802_11_DLS, *PRT_802_11_DLS; - -typedef struct _MLME_DLS_REQ_STRUCT { - PRT_802_11_DLS pDLS; - USHORT Reason; -} MLME_DLS_REQ_STRUCT, *PMLME_DLS_REQ_STRUCT; -#endif // QOS_DLS_SUPPORT // -#endif // CONFIG_STA_SUPPORT // - typedef struct PACKED { UCHAR Eid; UCHAR Len; @@ -1365,21 +1065,12 @@ typedef struct PACKED { typedef struct PACKED _RTMP_TX_RATE_SWITCH { UCHAR ItemNo; -#ifdef RT_BIG_ENDIAN - UCHAR Rsv2:2; - UCHAR Mode:2; - UCHAR Rsv1:1; - UCHAR BW:1; - UCHAR ShortGI:1; - UCHAR STBC:1; -#else UCHAR STBC:1; UCHAR ShortGI:1; UCHAR BW:1; UCHAR Rsv1:1; UCHAR Mode:2; UCHAR Rsv2:2; -#endif UCHAR CurrMCS; UCHAR TrainUp; UCHAR TrainDown; diff --git a/drivers/staging/rt2860/oid.h b/drivers/staging/rt2860/oid.h index 5e6ed9f62f9d..8519afccd979 100644 --- a/drivers/staging/rt2860/oid.h +++ b/drivers/staging/rt2860/oid.h @@ -80,13 +80,8 @@ #define MAX_LENGTH_OF_SUPPORT_RATES 12 // 1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54 #define MAX_NUMBER_OF_DLS_ENTRY 4 -#ifndef UNDER_CE - #define OID_GEN_MACHINE_NAME 0x0001021A -#ifdef RALINK_ATE -#define RT_QUERY_ATE_TXDONE_COUNT 0x0401 -#endif // RALINK_ATE // #define RT_QUERY_SIGNAL_CONTEXT 0x0402 #define RT_SET_IAPP_PID 0x0404 #define RT_SET_APD_PID 0x0405 @@ -163,7 +158,7 @@ #define RT_OID_802_11_QUERY_LAST_RX_RATE 0x0613 #define RT_OID_802_11_TX_POWER_LEVEL_1 0x0614 #define RT_OID_802_11_QUERY_PIDVID 0x0615 -//for WPA_SUPPLICANT_SUPPORT + #define OID_SET_COUNTERMEASURES 0x0616 #define OID_802_11_SET_IEEE8021X 0x0617 #define OID_802_11_SET_IEEE8021X_REQUIRE_KEY 0x0618 @@ -388,9 +383,6 @@ typedef struct PACKED _RADIUS_CONF RADIUS_KEY_INFO RadiusInfo[8/*MAX_MBSSID_NUM*/]; } RADIUS_CONF, *PRADIUS_CONF; - - -#ifdef CONFIG_STA_SUPPORT // Key mapping keys require a BSSID typedef struct _NDIS_802_11_KEY { @@ -401,7 +393,6 @@ typedef struct _NDIS_802_11_KEY NDIS_802_11_KEY_RSC KeyRSC; UCHAR KeyMaterial[1]; // variable length depending on above field } NDIS_802_11_KEY, *PNDIS_802_11_KEY; -#endif // CONFIG_STA_SUPPORT // typedef struct _NDIS_802_11_REMOVE_KEY { @@ -544,8 +535,10 @@ typedef enum _NDIS_802_11_WEP_STATUS Ndis802_11Encryption3KeyAbsent, Ndis802_11Encryption4Enabled, // TKIP or AES mix Ndis802_11Encryption4KeyAbsent, +#ifndef RT30xx Ndis802_11GroupWEP40Enabled, Ndis802_11GroupWEP104Enabled, +#endif } NDIS_802_11_WEP_STATUS, *PNDIS_802_11_WEP_STATUS, NDIS_802_11_ENCRYPTION_STATUS, *PNDIS_802_11_ENCRYPTION_STATUS; @@ -605,7 +598,6 @@ typedef enum _NDIS_802_11_MEDIA_STREAM_MODE // PMKID Structures typedef UCHAR NDIS_802_11_PMKID_VALUE[16]; -#ifdef CONFIG_STA_SUPPORT typedef struct _BSSID_INFO { NDIS_802_11_MAC_ADDRESS BSSID; @@ -618,8 +610,6 @@ typedef struct _NDIS_802_11_PMKID UINT BSSIDInfoCount; BSSID_INFO BSSIDInfo[1]; } NDIS_802_11_PMKID, *PNDIS_802_11_PMKID; -#endif // CONFIG_STA_SUPPORT // - typedef struct _NDIS_802_11_AUTHENTICATION_ENCRYPTION { @@ -636,9 +626,6 @@ typedef struct _NDIS_802_11_CAPABILITY NDIS_802_11_AUTHENTICATION_ENCRYPTION AuthenticationEncryptionSupported[1]; } NDIS_802_11_CAPABILITY, *PNDIS_802_11_CAPABILITY; -//#endif //of WIN 2k -#endif //UNDER_CE - #if WIRELESS_EXT <= 11 #ifndef SIOCDEVPRIVATE #define SIOCDEVPRIVATE 0x8BE0 @@ -646,21 +633,20 @@ typedef struct _NDIS_802_11_CAPABILITY #define SIOCIWFIRSTPRIV SIOCDEVPRIVATE #endif -#ifdef CONFIG_STA_SUPPORT +#ifdef RT30xx +#define RT_PRIV_IOCTL_EXT (SIOCIWFIRSTPRIV + 0x01) // Sync. with AP for wsc upnp daemon +#endif #define RTPRIV_IOCTL_SET (SIOCIWFIRSTPRIV + 0x02) #ifdef DBG #define RTPRIV_IOCTL_BBP (SIOCIWFIRSTPRIV + 0x03) #define RTPRIV_IOCTL_MAC (SIOCIWFIRSTPRIV + 0x05) +#ifdef RT30xx +#define RTPRIV_IOCTL_RF (SIOCIWFIRSTPRIV + 0x13) +#endif #define RTPRIV_IOCTL_E2P (SIOCIWFIRSTPRIV + 0x07) #endif -#ifdef RALINK_ATE -#ifdef RALINK_28xx_QA -#define RTPRIV_IOCTL_ATE (SIOCIWFIRSTPRIV + 0x08) -#endif // RALINK_28xx_QA // -#endif // RALINK_ATE // - #define RTPRIV_IOCTL_STATISTICS (SIOCIWFIRSTPRIV + 0x09) #define RTPRIV_IOCTL_ADD_PMKID_CACHE (SIOCIWFIRSTPRIV + 0x0A) #define RTPRIV_IOCTL_RADIUS_DATA (SIOCIWFIRSTPRIV + 0x0C) @@ -674,67 +660,61 @@ enum { SHOW_DRVIER_VERION = 5, SHOW_BA_INFO = 6, SHOW_DESC_INFO = 7, +#ifdef RT2870 + SHOW_RXBULK_INFO = 8, + SHOW_TXBULK_INFO = 9, +#endif // RT2870 // RAIO_OFF = 10, RAIO_ON = 11, -#ifdef QOS_DLS_SUPPORT - SHOW_DLS_ENTRY_INFO = 19, -#endif // QOS_DLS_SUPPORT // SHOW_CFG_VALUE = 20, +#if !defined(RT2860) && !defined(RT30xx) + SHOW_ADHOC_ENTRY_INFO = 21, +#endif }; -#endif // CONFIG_STA_SUPPORT // - -#ifdef SNMP_SUPPORT -//SNMP ieee 802dot11, kathy , 2008_0220 -// dot11res(3) -#define RT_OID_802_11_MANUFACTUREROUI 0x0700 -#define RT_OID_802_11_MANUFACTURERNAME 0x0701 -#define RT_OID_802_11_RESOURCETYPEIDNAME 0x0702 - -// dot11smt(1) -#define RT_OID_802_11_PRIVACYOPTIONIMPLEMENTED 0x0703 -#define RT_OID_802_11_POWERMANAGEMENTMODE 0x0704 -#define OID_802_11_WEPDEFAULTKEYVALUE 0x0705 // read , write -#define OID_802_11_WEPDEFAULTKEYID 0x0706 -#define RT_OID_802_11_WEPKEYMAPPINGLENGTH 0x0707 -#define OID_802_11_SHORTRETRYLIMIT 0x0708 -#define OID_802_11_LONGRETRYLIMIT 0x0709 -#define RT_OID_802_11_PRODUCTID 0x0710 -#define RT_OID_802_11_MANUFACTUREID 0x0711 - -// //dot11Phy(4) -#define OID_802_11_CURRENTCHANNEL 0x0712 - -//dot11mac -#define RT_OID_802_11_MAC_ADDRESS 0x0713 -#endif // SNMP_SUPPORT // - #define OID_802_11_BUILD_CHANNEL_EX 0x0714 #define OID_802_11_GET_CH_LIST 0x0715 #define OID_802_11_GET_COUNTRY_CODE 0x0716 #define OID_802_11_GET_CHANNEL_GEOGRAPHY 0x0717 +#ifdef RT30xx +#define RT_OID_WSC_SET_PASSPHRASE 0x0740 // passphrase for wpa(2)-psk +#define RT_OID_WSC_DRIVER_AUTO_CONNECT 0x0741 +#define RT_OID_WSC_QUERY_DEFAULT_PROFILE 0x0742 +#define RT_OID_WSC_SET_CONN_BY_PROFILE_INDEX 0x0743 +#define RT_OID_WSC_SET_ACTION 0x0744 +#define RT_OID_WSC_SET_SSID 0x0745 +#define RT_OID_WSC_SET_PIN_CODE 0x0746 +#define RT_OID_WSC_SET_MODE 0x0747 // PIN or PBC +#define RT_OID_WSC_SET_CONF_MODE 0x0748 // Enrollee or Registrar +#define RT_OID_WSC_SET_PROFILE 0x0749 + +#define RT_OID_802_11_WSC_QUERY_PROFILE 0x0750 +// for consistency with RT61 +#define RT_OID_WSC_QUERY_STATUS 0x0751 +#define RT_OID_WSC_PIN_CODE 0x0752 +#define RT_OID_WSC_UUID 0x0753 +#define RT_OID_WSC_SET_SELECTED_REGISTRAR 0x0754 +#define RT_OID_WSC_EAPMSG 0x0755 +#define RT_OID_WSC_MANUFACTURER 0x0756 +#define RT_OID_WSC_MODEL_NAME 0x0757 +#define RT_OID_WSC_MODEL_NO 0x0758 +#define RT_OID_WSC_SERIAL_NO 0x0759 +#define RT_OID_WSC_MAC_ADDRESS 0x0760 +#endif + #ifdef LLTD_SUPPORT // for consistency with RT61 #define RT_OID_GET_PHY_MODE 0x761 #endif // LLTD_SUPPORT // +#if defined(RT2860) || defined(RT30xx) // New for MeetingHouse Api support #define OID_MH_802_1X_SUPPORTED 0xFFEDC100 +#endif // MIMO Tx parameter, ShortGI, MCS, STBC, etc. these are fields in TXWI. Don't change this definition!!! typedef union _HTTRANSMIT_SETTING { -#ifdef RT_BIG_ENDIAN - struct { - USHORT MODE:2; // Use definition MODE_xxx. - USHORT TxBF:1; - USHORT rsv:2; - USHORT STBC:2; //SPACE - USHORT ShortGI:1; - USHORT BW:1; //channel bandwidth 20MHz or 40 MHz - USHORT MCS:7; // MCS - } field; -#else struct { USHORT MCS:7; // MCS USHORT BW:1; //channel bandwidth 20MHz or 40 MHz @@ -744,7 +724,6 @@ typedef union _HTTRANSMIT_SETTING { USHORT TxBF:1; USHORT MODE:2; // Use definition MODE_xxx. } field; -#endif USHORT word; } HTTRANSMIT_SETTING, *PHTTRANSMIT_SETTING; @@ -755,14 +734,12 @@ typedef enum _RT_802_11_PREAMBLE { } RT_802_11_PREAMBLE, *PRT_802_11_PREAMBLE; // Only for STA, need to sync with AP -// 2005-03-08 match current RaConfig. typedef enum _RT_802_11_PHY_MODE { PHY_11BG_MIXED = 0, PHY_11B, PHY_11A, PHY_11ABG_MIXED, PHY_11G, -#ifdef DOT11_N_SUPPORT PHY_11ABGN_MIXED, // both band 5 PHY_11N_2_4G, // 11n-only with 2.4G band 6 PHY_11GN_MIXED, // 2.4G band 7 @@ -770,7 +747,6 @@ typedef enum _RT_802_11_PHY_MODE { PHY_11BGN_MIXED, // if check 802.11b. 9 PHY_11AGN_MIXED, // if check 802.11b. 10 PHY_11N_5G, // 11n-only with 5G band 11 -#endif // DOT11_N_SUPPORT // } RT_802_11_PHY_MODE; // put all proprietery for-query objects here to reduce # of Query_OID @@ -937,54 +913,14 @@ typedef struct _RT_LLTD_ASSOICATION_TABLE { } RT_LLTD_ASSOICATION_TABLE, *PRT_LLTD_ASSOICATION_TABLE; #endif // LLTD_SUPPORT // -#ifdef CONFIG_STA_SUPPORT -#ifdef QOS_DLS_SUPPORT -//rt2860, kathy 2007-0118 -// structure for DLS -typedef struct _RT_802_11_DLS_UI { - USHORT TimeOut; // unit: second , set by UI - USHORT CountDownTimer; // unit: second , used by driver only - NDIS_802_11_MAC_ADDRESS MacAddr; // set by UI - UCHAR Status; // 0: none , 1: wait STAkey, 2: finish DLS setup , set by driver only - BOOLEAN Valid; // 1: valid , 0: invalid , set by UI, use to setup or tear down DLS link -} RT_802_11_DLS_UI, *PRT_802_11_DLS_UI; - -typedef struct _RT_802_11_DLS_INFO { - RT_802_11_DLS_UI Entry[MAX_NUMBER_OF_DLS_ENTRY]; - UCHAR num; -} RT_802_11_DLS_INFO, *PRT_802_11_DLS_INFO; - -typedef enum _RT_802_11_DLS_MODE { - DLS_NONE, - DLS_WAIT_KEY, - DLS_FINISH -} RT_802_11_DLS_MODE; -#endif // QOS_DLS_SUPPORT // - -#ifdef WPA_SUPPLICANT_SUPPORT -#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT -#define RT_ASSOC_EVENT_FLAG 0x0101 -#define RT_DISASSOC_EVENT_FLAG 0x0102 -#define RT_REQIE_EVENT_FLAG 0x0103 -#define RT_RESPIE_EVENT_FLAG 0x0104 -#define RT_ASSOCINFO_EVENT_FLAG 0x0105 -#define RT_PMKIDCAND_FLAG 0x0106 -#define RT_INTERFACE_DOWN 0x0107 -#define RT_INTERFACE_UP 0x0108 -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // -#endif // WPA_SUPPLICANT_SUPPORT // -#endif // CONFIG_STA_SUPPORT // - #define MAX_CUSTOM_LEN 128 -#ifdef CONFIG_STA_SUPPORT typedef enum _RT_802_11_D_CLIENT_MODE { Rt802_11_D_None, Rt802_11_D_Flexible, Rt802_11_D_Strict, } RT_802_11_D_CLIENT_MODE, *PRT_802_11_D_CLIENT_MODE; -#endif // CONFIG_STA_SUPPORT // typedef struct _RT_CHANNEL_LIST_INFO { @@ -992,6 +928,27 @@ typedef struct _RT_CHANNEL_LIST_INFO UCHAR ChannelListNum; // number of channel in ChannelList[] } RT_CHANNEL_LIST_INFO, *PRT_CHANNEL_LIST_INFO; +#ifdef RT2870 +// WSC configured credential +typedef struct _WSC_CREDENTIAL +{ + NDIS_802_11_SSID SSID; // mandatory + USHORT AuthType; // mandatory, 1: open, 2: wpa-psk, 4: shared, 8:wpa, 0x10: wpa2, 0x20: wpa2-psk + USHORT EncrType; // mandatory, 1: none, 2: wep, 4: tkip, 8: aes + UCHAR Key[64]; // mandatory, Maximum 64 byte + USHORT KeyLength; + UCHAR MacAddr[6]; // mandatory, AP MAC address + UCHAR KeyIndex; // optional, default is 1 + UCHAR Rsvd[3]; // Make alignment +} WSC_CREDENTIAL, *PWSC_CREDENTIAL; + +// WSC configured profiles +typedef struct _WSC_PROFILE +{ + UINT ProfileCnt; + WSC_CREDENTIAL Profile[8]; // Support up to 8 profiles +} WSC_PROFILE, *PWSC_PROFILE; +#endif #endif // _OID_H_ diff --git a/drivers/staging/rt2860/rt28xx.h b/drivers/staging/rt2860/rt28xx.h index e5e6f0a8de63..6e71acb16dc3 100644 --- a/drivers/staging/rt2860/rt28xx.h +++ b/drivers/staging/rt2860/rt28xx.h @@ -47,6 +47,15 @@ #define PCI_EECTRL 0x0004 #define PCI_MCUCTRL 0x0008 +#ifdef RT30xx +#define OPT_14 0x114 + +typedef int NTSTATUS; +#define RETRY_LIMIT 10 +#define STATUS_SUCCESS 0x00 +#define STATUS_UNSUCCESSFUL 0x01 +#endif + // // SCH/DMA registers - base address 0x0200 // @@ -54,32 +63,6 @@ // #define DMA_CSR0 0x200 #define INT_SOURCE_CSR 0x200 -#ifdef RT_BIG_ENDIAN -typedef union _INT_SOURCE_CSR_STRUC { - struct { - UINT32 :14; - UINT32 TxCoherent:1; - UINT32 RxCoherent:1; - UINT32 GPTimer:1; - UINT32 AutoWakeup:1;//bit14 - UINT32 TXFifoStatusInt:1;//FIFO Statistics is full, sw should read 0x171c - UINT32 PreTBTT:1; - UINT32 TBTTInt:1; - UINT32 RxTxCoherent:1; - UINT32 MCUCommandINT:1; - UINT32 MgmtDmaDone:1; - UINT32 HccaDmaDone:1; - UINT32 Ac3DmaDone:1; - UINT32 Ac2DmaDone:1; - UINT32 Ac1DmaDone:1; - UINT32 Ac0DmaDone:1; - UINT32 RxDone:1; - UINT32 TxDelayINT:1; //delayed interrupt, not interrupt until several int or time limit hit - UINT32 RxDelayINT:1; //dealyed interrupt - } field; - UINT32 word; -} INT_SOURCE_CSR_STRUC, *PINT_SOURCE_CSR_STRUC; -#else typedef union _INT_SOURCE_CSR_STRUC { struct { UINT32 RxDelayINT:1; @@ -104,32 +87,11 @@ typedef union _INT_SOURCE_CSR_STRUC { } field; UINT32 word; } INT_SOURCE_CSR_STRUC, *PINT_SOURCE_CSR_STRUC; -#endif // // INT_MASK_CSR: Interrupt MASK register. 1: the interrupt is mask OFF // #define INT_MASK_CSR 0x204 -#ifdef RT_BIG_ENDIAN -typedef union _INT_MASK_CSR_STRUC { - struct { - UINT32 TxCoherent:1; - UINT32 RxCoherent:1; - UINT32 :20; - UINT32 MCUCommandINT:1; - UINT32 MgmtDmaDone:1; - UINT32 HccaDmaDone:1; - UINT32 Ac3DmaDone:1; - UINT32 Ac2DmaDone:1; - UINT32 Ac1DmaDone:1; - UINT32 Ac0DmaDone:1; - UINT32 RxDone:1; - UINT32 TxDelay:1; - UINT32 RXDelay_INT_MSK:1; - } field; - UINT32 word; -}INT_MASK_CSR_STRUC, *PINT_MASK_CSR_STRUC; -#else typedef union _INT_MASK_CSR_STRUC { struct { UINT32 RXDelay_INT_MSK:1; @@ -148,24 +110,8 @@ typedef union _INT_MASK_CSR_STRUC { } field; UINT32 word; } INT_MASK_CSR_STRUC, *PINT_MASK_CSR_STRUC; -#endif + #define WPDMA_GLO_CFG 0x208 -#ifdef RT_BIG_ENDIAN -typedef union _WPDMA_GLO_CFG_STRUC { - struct { - UINT32 HDR_SEG_LEN:16; - UINT32 RXHdrScater:8; - UINT32 BigEndian:1; - UINT32 EnTXWriteBackDDONE:1; - UINT32 WPDMABurstSIZE:2; - UINT32 RxDMABusy:1; - UINT32 EnableRxDMA:1; - UINT32 TxDMABusy:1; - UINT32 EnableTxDMA:1; - } field; - UINT32 word; -}WPDMA_GLO_CFG_STRUC, *PWPDMA_GLO_CFG_STRUC; -#else typedef union _WPDMA_GLO_CFG_STRUC { struct { UINT32 EnableTxDMA:1; @@ -180,24 +126,8 @@ typedef union _WPDMA_GLO_CFG_STRUC { } field; UINT32 word; } WPDMA_GLO_CFG_STRUC, *PWPDMA_GLO_CFG_STRUC; -#endif + #define WPDMA_RST_IDX 0x20c -#ifdef RT_BIG_ENDIAN -typedef union _WPDMA_RST_IDX_STRUC { - struct { - UINT32 :15; - UINT32 RST_DRX_IDX0:1; - UINT32 rsv:10; - UINT32 RST_DTX_IDX5:1; - UINT32 RST_DTX_IDX4:1; - UINT32 RST_DTX_IDX3:1; - UINT32 RST_DTX_IDX2:1; - UINT32 RST_DTX_IDX1:1; - UINT32 RST_DTX_IDX0:1; - } field; - UINT32 word; -}WPDMA_RST_IDX_STRUC, *PWPDMA_RST_IDX_STRUC; -#else typedef union _WPDMA_RST_IDX_STRUC { struct { UINT32 RST_DTX_IDX0:1; @@ -212,21 +142,8 @@ typedef union _WPDMA_RST_IDX_STRUC { } field; UINT32 word; } WPDMA_RST_IDX_STRUC, *PWPDMA_RST_IDX_STRUC; -#endif + #define DELAY_INT_CFG 0x0210 -#ifdef RT_BIG_ENDIAN -typedef union _DELAY_INT_CFG_STRUC { - struct { - UINT32 TXDLY_INT_EN:1; - UINT32 TXMAX_PINT:7; - UINT32 TXMAX_PTIME:8; - UINT32 RXDLY_INT_EN:1; - UINT32 RXMAX_PINT:7; - UINT32 RXMAX_PTIME:8; - } field; - UINT32 word; -}DELAY_INT_CFG_STRUC, *PDELAY_INT_CFG_STRUC; -#else typedef union _DELAY_INT_CFG_STRUC { struct { UINT32 RXMAX_PTIME:8; @@ -238,20 +155,8 @@ typedef union _DELAY_INT_CFG_STRUC { } field; UINT32 word; } DELAY_INT_CFG_STRUC, *PDELAY_INT_CFG_STRUC; -#endif + #define WMM_AIFSN_CFG 0x0214 -#ifdef RT_BIG_ENDIAN -typedef union _AIFSN_CSR_STRUC { - struct { - UINT32 Rsv:16; - UINT32 Aifsn3:4; // for AC_VO - UINT32 Aifsn2:4; // for AC_VI - UINT32 Aifsn1:4; // for AC_BK - UINT32 Aifsn0:4; // for AC_BE - } field; - UINT32 word; -} AIFSN_CSR_STRUC, *PAIFSN_CSR_STRUC; -#else typedef union _AIFSN_CSR_STRUC { struct { UINT32 Aifsn0:4; // for AC_BE @@ -262,23 +167,11 @@ typedef union _AIFSN_CSR_STRUC { } field; UINT32 word; } AIFSN_CSR_STRUC, *PAIFSN_CSR_STRUC; -#endif + // // CWMIN_CSR: CWmin for each EDCA AC // #define WMM_CWMIN_CFG 0x0218 -#ifdef RT_BIG_ENDIAN -typedef union _CWMIN_CSR_STRUC { - struct { - UINT32 Rsv:16; - UINT32 Cwmin3:4; // for AC_VO - UINT32 Cwmin2:4; // for AC_VI - UINT32 Cwmin1:4; // for AC_BK - UINT32 Cwmin0:4; // for AC_BE - } field; - UINT32 word; -} CWMIN_CSR_STRUC, *PCWMIN_CSR_STRUC; -#else typedef union _CWMIN_CSR_STRUC { struct { UINT32 Cwmin0:4; // for AC_BE @@ -289,24 +182,11 @@ typedef union _CWMIN_CSR_STRUC { } field; UINT32 word; } CWMIN_CSR_STRUC, *PCWMIN_CSR_STRUC; -#endif // // CWMAX_CSR: CWmin for each EDCA AC // #define WMM_CWMAX_CFG 0x021c -#ifdef RT_BIG_ENDIAN -typedef union _CWMAX_CSR_STRUC { - struct { - UINT32 Rsv:16; - UINT32 Cwmax3:4; // for AC_VO - UINT32 Cwmax2:4; // for AC_VI - UINT32 Cwmax1:4; // for AC_BK - UINT32 Cwmax0:4; // for AC_BE - } field; - UINT32 word; -} CWMAX_CSR_STRUC, *PCWMAX_CSR_STRUC; -#else typedef union _CWMAX_CSR_STRUC { struct { UINT32 Cwmax0:4; // for AC_BE @@ -317,22 +197,11 @@ typedef union _CWMAX_CSR_STRUC { } field; UINT32 word; } CWMAX_CSR_STRUC, *PCWMAX_CSR_STRUC; -#endif - // // AC_TXOP_CSR0: AC_BK/AC_BE TXOP register // #define WMM_TXOP0_CFG 0x0220 -#ifdef RT_BIG_ENDIAN -typedef union _AC_TXOP_CSR0_STRUC { - struct { - USHORT Ac1Txop; // for AC_BE, in unit of 32us - USHORT Ac0Txop; // for AC_BK, in unit of 32us - } field; - UINT32 word; -} AC_TXOP_CSR0_STRUC, *PAC_TXOP_CSR0_STRUC; -#else typedef union _AC_TXOP_CSR0_STRUC { struct { USHORT Ac0Txop; // for AC_BK, in unit of 32us @@ -340,21 +209,11 @@ typedef union _AC_TXOP_CSR0_STRUC { } field; UINT32 word; } AC_TXOP_CSR0_STRUC, *PAC_TXOP_CSR0_STRUC; -#endif // // AC_TXOP_CSR1: AC_VO/AC_VI TXOP register // #define WMM_TXOP1_CFG 0x0224 -#ifdef RT_BIG_ENDIAN -typedef union _AC_TXOP_CSR1_STRUC { - struct { - USHORT Ac3Txop; // for AC_VO, in unit of 32us - USHORT Ac2Txop; // for AC_VI, in unit of 32us - } field; - UINT32 word; -} AC_TXOP_CSR1_STRUC, *PAC_TXOP_CSR1_STRUC; -#else typedef union _AC_TXOP_CSR1_STRUC { struct { USHORT Ac2Txop; // for AC_VI, in unit of 32us @@ -362,7 +221,7 @@ typedef union _AC_TXOP_CSR1_STRUC { } field; UINT32 word; } AC_TXOP_CSR1_STRUC, *PAC_TXOP_CSR1_STRUC; -#endif + #define RINGREG_DIFF 0x10 #define GPIO_CTRL_CFG 0x0228 //MAC_CSR13 #define MCU_CMD_CFG 0x022c @@ -398,25 +257,7 @@ typedef union _AC_TXOP_CSR1_STRUC { #define RX_CRX_IDX 0x0298 #define RX_DRX_IDX 0x029c #define USB_DMA_CFG 0x02a0 -#ifdef RT_BIG_ENDIAN -typedef union _USB_DMA_CFG_STRUC { - struct { - UINT32 TxBusy:1; //USB DMA TX FSM busy . debug only - UINT32 RxBusy:1; //USB DMA RX FSM busy . debug only - UINT32 EpoutValid:6; //OUT endpoint data valid. debug only - UINT32 TxBulkEn:1; //Enable USB DMA Tx - UINT32 RxBulkEn:1; //Enable USB DMA Rx - UINT32 RxBulkAggEn:1; //Enable Rx Bulk Aggregation - UINT32 TxopHalt:1; //Halt TXOP count down when TX buffer is full. - UINT32 TxClear:1; //Clear USB DMA TX path - UINT32 rsv:2; - UINT32 phyclear:1; //phy watch dog enable. write 1 - UINT32 RxBulkAggLmt:8; //Rx Bulk Aggregation Limit in unit of 1024 bytes - UINT32 RxBulkAggTOut:8; //Rx Bulk Aggregation TimeOut in unit of 33ns - } field; - UINT32 word; -} USB_DMA_CFG_STRUC, *PUSB_DMA_CFG_STRUC; -#else + typedef union _USB_DMA_CFG_STRUC { struct { UINT32 RxBulkAggTOut:8; //Rx Bulk Aggregation TimeOut in unit of 33ns @@ -434,7 +275,6 @@ typedef union _USB_DMA_CFG_STRUC { } field; UINT32 word; } USB_DMA_CFG_STRUC, *PUSB_DMA_CFG_STRUC; -#endif // // 3 PBF registers @@ -451,6 +291,36 @@ typedef union _USB_DMA_CFG_STRUC { #define PBF_DBG 0x043c #define PBF_CAP_CTRL 0x0440 +#ifdef RT30xx +// eFuse registers +#define EFUSE_CTRL 0x0580 +#define EFUSE_DATA0 0x0590 +#define EFUSE_DATA1 0x0594 +#define EFUSE_DATA2 0x0598 +#define EFUSE_DATA3 0x059c +#define EFUSE_USAGE_MAP_START 0x2d0 +#define EFUSE_USAGE_MAP_END 0x2fc +#define EFUSE_TAG 0x2fe +#define EFUSE_USAGE_MAP_SIZE 45 + +typedef union _EFUSE_CTRL_STRUC { + struct { + UINT32 EFSROM_AOUT:6; + UINT32 EFSROM_MODE:2; + UINT32 EFSROM_LDO_OFF_TIME:6; + UINT32 EFSROM_LDO_ON_TIME:2; + UINT32 EFSROM_AIN:10; + UINT32 RESERVED:4; + UINT32 EFSROM_KICK:1; + UINT32 SEL_EFUSE:1; + } field; + UINT32 word; +} EFUSE_CTRL_STRUC, *PEFUSE_CTRL_STRUC; + +#define LDO_CFG0 0x05d4 +#define GPIO_SWITCH 0x05dc +#endif /* RT30xx */ + // // 4 MAC registers // @@ -458,15 +328,6 @@ typedef union _USB_DMA_CFG_STRUC { // 4.1 MAC SYSTEM configuration registers (offset:0x1000) // #define MAC_CSR0 0x1000 -#ifdef RT_BIG_ENDIAN -typedef union _ASIC_VER_ID_STRUC { - struct { - USHORT ASICVer; // version : 2860 - USHORT ASICRev; // reversion : 0 - } field; - UINT32 word; -} ASIC_VER_ID_STRUC, *PASIC_VER_ID_STRUC; -#else typedef union _ASIC_VER_ID_STRUC { struct { USHORT ASICRev; // reversion : 0 @@ -474,24 +335,13 @@ typedef union _ASIC_VER_ID_STRUC { } field; UINT32 word; } ASIC_VER_ID_STRUC, *PASIC_VER_ID_STRUC; -#endif + #define MAC_SYS_CTRL 0x1004 //MAC_CSR1 #define MAC_ADDR_DW0 0x1008 // MAC ADDR DW0 #define MAC_ADDR_DW1 0x100c // MAC ADDR DW1 // // MAC_CSR2: STA MAC register 0 // -#ifdef RT_BIG_ENDIAN -typedef union _MAC_DW0_STRUC { - struct { - UCHAR Byte3; // MAC address byte 3 - UCHAR Byte2; // MAC address byte 2 - UCHAR Byte1; // MAC address byte 1 - UCHAR Byte0; // MAC address byte 0 - } field; - UINT32 word; -} MAC_DW0_STRUC, *PMAC_DW0_STRUC; -#else typedef union _MAC_DW0_STRUC { struct { UCHAR Byte0; // MAC address byte 0 @@ -501,22 +351,10 @@ typedef union _MAC_DW0_STRUC { } field; UINT32 word; } MAC_DW0_STRUC, *PMAC_DW0_STRUC; -#endif // // MAC_CSR3: STA MAC register 1 // -#ifdef RT_BIG_ENDIAN -typedef union _MAC_DW1_STRUC { - struct { - UCHAR Rsvd1; - UCHAR U2MeMask; - UCHAR Byte5; // MAC address byte 5 - UCHAR Byte4; // MAC address byte 4 - } field; - UINT32 word; -} MAC_DW1_STRUC, *PMAC_DW1_STRUC; -#else typedef union _MAC_DW1_STRUC { struct { UCHAR Byte4; // MAC address byte 4 @@ -526,7 +364,6 @@ typedef union _MAC_DW1_STRUC { } field; UINT32 word; } MAC_DW1_STRUC, *PMAC_DW1_STRUC; -#endif #define MAC_BSSID_DW0 0x1010 // MAC BSSID DW0 #define MAC_BSSID_DW1 0x1014 // MAC BSSID DW1 @@ -534,18 +371,6 @@ typedef union _MAC_DW1_STRUC { // // MAC_CSR5: BSSID register 1 // -#ifdef RT_BIG_ENDIAN -typedef union _MAC_CSR5_STRUC { - struct { - USHORT Rsvd:11; - USHORT MBssBcnNum:3; - USHORT BssIdMode:2; // 0: one BSSID, 10: 4 BSSID, 01: 2 BSSID , 11: 8BSSID - UCHAR Byte5; // BSSID byte 5 - UCHAR Byte4; // BSSID byte 4 - } field; - UINT32 word; -} MAC_CSR5_STRUC, *PMAC_CSR5_STRUC; -#else typedef union _MAC_CSR5_STRUC { struct { UCHAR Byte4; // BSSID byte 4 @@ -556,27 +381,12 @@ typedef union _MAC_CSR5_STRUC { } field; UINT32 word; } MAC_CSR5_STRUC, *PMAC_CSR5_STRUC; -#endif #define MAX_LEN_CFG 0x1018 // rt2860b max 16k bytes. bit12:13 Maximum PSDU length (power factor) 0:2^13, 1:2^14, 2:2^15, 3:2^16 #define BBP_CSR_CFG 0x101c // // // BBP_CSR_CFG: BBP serial control register // -#ifdef RT_BIG_ENDIAN -typedef union _BBP_CSR_CFG_STRUC { - struct { - UINT32 :12; - UINT32 BBP_RW_MODE:1; // 0: use serial mode 1:parallel - UINT32 BBP_PAR_DUR:1; // 0: 4 MAC clock cycles 1: 8 MAC clock cycles - UINT32 Busy:1; // 1: ASIC is busy execute BBP programming. - UINT32 fRead:1; // 0: Write BBP, 1: Read BBP - UINT32 RegNum:8; // Selected BBP register - UINT32 Value:8; // Register value to program into BBP - } field; - UINT32 word; -} BBP_CSR_CFG_STRUC, *PBBP_CSR_CFG_STRUC; -#else typedef union _BBP_CSR_CFG_STRUC { struct { UINT32 Value:8; // Register value to program into BBP @@ -589,23 +399,11 @@ typedef union _BBP_CSR_CFG_STRUC { } field; UINT32 word; } BBP_CSR_CFG_STRUC, *PBBP_CSR_CFG_STRUC; -#endif + #define RF_CSR_CFG0 0x1020 // // RF_CSR_CFG: RF control register // -#ifdef RT_BIG_ENDIAN -typedef union _RF_CSR_CFG0_STRUC { - struct { - UINT32 Busy:1; // 0: idle 1: 8busy - UINT32 Sel:1; // 0:RF_LE0 activate 1:RF_LE1 activate - UINT32 StandbyMode:1; // 0: high when stand by 1: low when standby - UINT32 bitwidth:5; // Selected BBP register - UINT32 RegIdAndContent:24; // Register value to program into BBP - } field; - UINT32 word; -} RF_CSR_CFG0_STRUC, *PRF_CSR_CFG0_STRUC; -#else typedef union _RF_CSR_CFG0_STRUC { struct { UINT32 RegIdAndContent:24; // Register value to program into BBP @@ -616,18 +414,8 @@ typedef union _RF_CSR_CFG0_STRUC { } field; UINT32 word; } RF_CSR_CFG0_STRUC, *PRF_CSR_CFG0_STRUC; -#endif + #define RF_CSR_CFG1 0x1024 -#ifdef RT_BIG_ENDIAN -typedef union _RF_CSR_CFG1_STRUC { - struct { - UINT32 rsv:7; // 0: idle 1: 8busy - UINT32 RFGap:5; // Gap between BB_CONTROL_RF and RF_LE. 0: 3 system clock cycle (37.5usec) 1: 5 system clock cycle (62.5usec) - UINT32 RegIdAndContent:24; // Register value to program into BBP - } field; - UINT32 word; -} RF_CSR_CFG1_STRUC, *PRF_CSR_CFG1_STRUC; -#else typedef union _RF_CSR_CFG1_STRUC { struct { UINT32 RegIdAndContent:24; // Register value to program into BBP @@ -636,17 +424,8 @@ typedef union _RF_CSR_CFG1_STRUC { } field; UINT32 word; } RF_CSR_CFG1_STRUC, *PRF_CSR_CFG1_STRUC; -#endif + #define RF_CSR_CFG2 0x1028 // -#ifdef RT_BIG_ENDIAN -typedef union _RF_CSR_CFG2_STRUC { - struct { - UINT32 rsv:8; // 0: idle 1: 8busy - UINT32 RegIdAndContent:24; // Register value to program into BBP - } field; - UINT32 word; -} RF_CSR_CFG2_STRUC, *PRF_CSR_CFG2_STRUC; -#else typedef union _RF_CSR_CFG2_STRUC { struct { UINT32 RegIdAndContent:24; // Register value to program into BBP @@ -654,24 +433,8 @@ typedef union _RF_CSR_CFG2_STRUC { } field; UINT32 word; } RF_CSR_CFG2_STRUC, *PRF_CSR_CFG2_STRUC; -#endif + #define LED_CFG 0x102c // MAC_CSR14 -#ifdef RT_BIG_ENDIAN -typedef union _LED_CFG_STRUC { - struct { - UINT32 :1; - UINT32 LedPolar:1; // Led Polarity. 0: active low1: active high - UINT32 YLedMode:2; // yellow Led Mode - UINT32 GLedMode:2; // green Led Mode - UINT32 RLedMode:2; // red Led Mode 0: off1: blinking upon TX2: periodic slow blinking3: always on - UINT32 rsv:2; - UINT32 SlowBlinkPeriod:6; // slow blinking period. unit:1ms - UINT32 OffPeriod:8; // blinking off period unit 1ms - UINT32 OnPeriod:8; // blinking on period unit 1ms - } field; - UINT32 word; -} LED_CFG_STRUC, *PLED_CFG_STRUC; -#else typedef union _LED_CFG_STRUC { struct { UINT32 OnPeriod:8; // blinking on period unit 1ms @@ -686,24 +449,11 @@ typedef union _LED_CFG_STRUC { } field; UINT32 word; } LED_CFG_STRUC, *PLED_CFG_STRUC; -#endif + // // 4.2 MAC TIMING configuration registers (offset:0x1100) // #define XIFS_TIME_CFG 0x1100 // MAC_CSR8 MAC_CSR9 -#ifdef RT_BIG_ENDIAN -typedef union _IFS_SLOT_CFG_STRUC { - struct { - UINT32 rsv:2; - UINT32 BBRxendEnable:1; // reference RXEND signal to begin XIFS defer - UINT32 EIFS:9; // unit 1us - UINT32 OfdmXifsTime:4; //OFDM SIFS. unit 1us. Applied after OFDM RX when MAC doesn't reference BBP signal BBRXEND - UINT32 OfdmSifsTime:8; // unit 1us. Applied after OFDM RX/TX - UINT32 CckmSifsTime:8; // unit 1us. Applied after CCK RX/TX - } field; - UINT32 word; -} IFS_SLOT_CFG_STRUC, *PIFS_SLOT_CFG_STRUC; -#else typedef union _IFS_SLOT_CFG_STRUC { struct { UINT32 CckmSifsTime:8; // unit 1us. Applied after CCK RX/TX @@ -715,7 +465,6 @@ typedef union _IFS_SLOT_CFG_STRUC { } field; UINT32 word; } IFS_SLOT_CFG_STRUC, *PIFS_SLOT_CFG_STRUC; -#endif #define BKOFF_SLOT_CFG 0x1104 // mac_csr9 last 8 bits #define NAV_TIME_CFG 0x1108 // NAV (MAC_CSR15) @@ -729,20 +478,6 @@ typedef union _IFS_SLOT_CFG_STRUC { // // BCN_TIME_CFG : Synchronization control register // -#ifdef RT_BIG_ENDIAN -typedef union _BCN_TIME_CFG_STRUC { - struct { - UINT32 TxTimestampCompensate:8; - UINT32 :3; - UINT32 bBeaconGen:1; // Enable beacon generator - UINT32 bTBTTEnable:1; - UINT32 TsfSyncMode:2; // Enable TSF sync, 00: disable, 01: infra mode, 10: ad-hoc mode - UINT32 bTsfTicking:1; // Enable TSF auto counting - UINT32 BeaconInterval:16; // in unit of 1/16 TU - } field; - UINT32 word; -} BCN_TIME_CFG_STRUC, *PBCN_TIME_CFG_STRUC; -#else typedef union _BCN_TIME_CFG_STRUC { struct { UINT32 BeaconInterval:16; // in unit of 1/16 TU @@ -755,7 +490,7 @@ typedef union _BCN_TIME_CFG_STRUC { } field; UINT32 word; } BCN_TIME_CFG_STRUC, *PBCN_TIME_CFG_STRUC; -#endif + #define TBTT_SYNC_CFG 0x1118 // txrx_csr10 #define TSF_TIMER_DW0 0x111C // Local TSF timer lsb 32 bits. Read-only #define TSF_TIMER_DW1 0x1120 // msb 32 bits. Read-only. @@ -773,17 +508,6 @@ typedef union _BCN_TIME_CFG_STRUC { // // AUTO_WAKEUP_CFG: Manual power control / status register // -#ifdef RT_BIG_ENDIAN -typedef union _AUTO_WAKEUP_STRUC { - struct { - UINT32 :16; - UINT32 EnableAutoWakeup:1; // 0:sleep, 1:awake - UINT32 NumofSleepingTbtt:7; // ForceWake has high privilege than PutToSleep when both set - UINT32 AutoLeadTime:8; - } field; - UINT32 word; -} AUTO_WAKEUP_STRUC, *PAUTO_WAKEUP_STRUC; -#else typedef union _AUTO_WAKEUP_STRUC { struct { UINT32 AutoLeadTime:8; @@ -793,7 +517,7 @@ typedef union _AUTO_WAKEUP_STRUC { } field; UINT32 word; } AUTO_WAKEUP_STRUC, *PAUTO_WAKEUP_STRUC; -#endif + // // 4.3 MAC TX configuration registers (offset:0x1300) // @@ -802,18 +526,6 @@ typedef union _AUTO_WAKEUP_STRUC { #define EDCA_AC1_CFG 0x1304 #define EDCA_AC2_CFG 0x1308 #define EDCA_AC3_CFG 0x130c -#ifdef RT_BIG_ENDIAN -typedef union _EDCA_AC_CFG_STRUC { - struct { - UINT32 :12; // - UINT32 Cwmax:4; //unit power of 2 - UINT32 Cwmin:4; // - UINT32 Aifsn:4; // # of slot time - UINT32 AcTxop:8; // in unit of 32us - } field; - UINT32 word; -} EDCA_AC_CFG_STRUC, *PEDCA_AC_CFG_STRUC; -#else typedef union _EDCA_AC_CFG_STRUC { struct { UINT32 AcTxop:8; // in unit of 32us @@ -824,7 +536,6 @@ typedef union _EDCA_AC_CFG_STRUC { } field; UINT32 word; } EDCA_AC_CFG_STRUC, *PEDCA_AC_CFG_STRUC; -#endif #define EDCA_TID_AC_MAP 0x1310 #define TX_PWR_CFG_0 0x1314 @@ -841,17 +552,6 @@ typedef union _EDCA_AC_CFG_STRUC { #define TXOP_CTRL_CFG 0x1340 #define TX_RTS_CFG 0x1344 -#ifdef RT_BIG_ENDIAN -typedef union _TX_RTS_CFG_STRUC { - struct { - UINT32 rsv:7; - UINT32 RtsFbkEn:1; // enable rts rate fallback - UINT32 RtsThres:16; // unit:byte - UINT32 AutoRtsRetryLimit:8; - } field; - UINT32 word; -} TX_RTS_CFG_STRUC, *PTX_RTS_CFG_STRUC; -#else typedef union _TX_RTS_CFG_STRUC { struct { UINT32 AutoRtsRetryLimit:8; @@ -861,20 +561,8 @@ typedef union _TX_RTS_CFG_STRUC { } field; UINT32 word; } TX_RTS_CFG_STRUC, *PTX_RTS_CFG_STRUC; -#endif + #define TX_TIMEOUT_CFG 0x1348 -#ifdef RT_BIG_ENDIAN -typedef union _TX_TIMEOUT_CFG_STRUC { - struct { - UINT32 rsv2:8; - UINT32 TxopTimeout:8; //TXOP timeout value for TXOP truncation. It is recommended that (SLOT_TIME) > (TX_OP_TIMEOUT) > (RX_ACK_TIMEOUT) - UINT32 RxAckTimeout:8; // unit:slot. Used for TX precedure - UINT32 MpduLifeTime:4; // expiration time = 2^(9+MPDU LIFE TIME) us - UINT32 rsv:4; - } field; - UINT32 word; -} TX_TIMEOUT_CFG_STRUC, *PTX_TIMEOUT_CFG_STRUC; -#else typedef union _TX_TIMEOUT_CFG_STRUC { struct { UINT32 rsv:4; @@ -885,23 +573,8 @@ typedef union _TX_TIMEOUT_CFG_STRUC { } field; UINT32 word; } TX_TIMEOUT_CFG_STRUC, *PTX_TIMEOUT_CFG_STRUC; -#endif -#define TX_RTY_CFG 0x134c -#ifdef RT_BIG_ENDIAN -typedef union PACKED _TX_RTY_CFG_STRUC { - struct { - UINT32 rsv:1; - UINT32 TxautoFBEnable:1; // Tx retry PHY rate auto fallback enable - UINT32 AggRtyMode:1; // Aggregate MPDU retry mode. 0:expired by retry limit, 1: expired by mpdu life timer - UINT32 NonAggRtyMode:1; // Non-Aggregate MPDU retry mode. 0:expired by retry limit, 1: expired by mpdu life timer - UINT32 LongRtyThre:12; // Long retry threshoold - UINT32 LongRtyLimit:8; //long retry limit - UINT32 ShortRtyLimit:8; // short retry limit - } field; - UINT32 word; -} TX_RTY_CFG_STRUC, *PTX_RTY_CFG_STRUC; -#else +#define TX_RTY_CFG 0x134c typedef union PACKED _TX_RTY_CFG_STRUC { struct { UINT32 ShortRtyLimit:8; // short retry limit @@ -914,24 +587,8 @@ typedef union PACKED _TX_RTY_CFG_STRUC { } field; UINT32 word; } TX_RTY_CFG_STRUC, *PTX_RTY_CFG_STRUC; -#endif + #define TX_LINK_CFG 0x1350 -#ifdef RT_BIG_ENDIAN -typedef union PACKED _TX_LINK_CFG_STRUC { - struct PACKED { - UINT32 RemotMFS:8; //remote MCS feedback sequence number - UINT32 RemotMFB:8; // remote MCS feedback - UINT32 rsv:3; // - UINT32 TxCFAckEn:1; // Piggyback CF-ACK enable - UINT32 TxRDGEn:1; // RDG TX enable - UINT32 TxMRQEn:1; // MCS request TX enable - UINT32 RemoteUMFSEnable:1; // remote unsolicit MFB enable. 0: not apply remote remote unsolicit (MFS=7) - UINT32 MFBEnable:1; // TX apply remote MFB 1:enable - UINT32 RemoteMFBLifeTime:8; //remote MFB life time. unit : 32us - } field; - UINT32 word; -} TX_LINK_CFG_STRUC, *PTX_LINK_CFG_STRUC; -#else typedef union PACKED _TX_LINK_CFG_STRUC { struct PACKED { UINT32 RemoteMFBLifeTime:8; //remote MFB life time. unit : 32us @@ -946,23 +603,8 @@ typedef union PACKED _TX_LINK_CFG_STRUC { } field; UINT32 word; } TX_LINK_CFG_STRUC, *PTX_LINK_CFG_STRUC; -#endif + #define HT_FBK_CFG0 0x1354 -#ifdef RT_BIG_ENDIAN -typedef union PACKED _HT_FBK_CFG0_STRUC { - struct { - UINT32 HTMCS7FBK:4; - UINT32 HTMCS6FBK:4; - UINT32 HTMCS5FBK:4; - UINT32 HTMCS4FBK:4; - UINT32 HTMCS3FBK:4; - UINT32 HTMCS2FBK:4; - UINT32 HTMCS1FBK:4; - UINT32 HTMCS0FBK:4; - } field; - UINT32 word; -} HT_FBK_CFG0_STRUC, *PHT_FBK_CFG0_STRUC; -#else typedef union PACKED _HT_FBK_CFG0_STRUC { struct { UINT32 HTMCS0FBK:4; @@ -976,23 +618,8 @@ typedef union PACKED _HT_FBK_CFG0_STRUC { } field; UINT32 word; } HT_FBK_CFG0_STRUC, *PHT_FBK_CFG0_STRUC; -#endif + #define HT_FBK_CFG1 0x1358 -#ifdef RT_BIG_ENDIAN -typedef union _HT_FBK_CFG1_STRUC { - struct { - UINT32 HTMCS15FBK:4; - UINT32 HTMCS14FBK:4; - UINT32 HTMCS13FBK:4; - UINT32 HTMCS12FBK:4; - UINT32 HTMCS11FBK:4; - UINT32 HTMCS10FBK:4; - UINT32 HTMCS9FBK:4; - UINT32 HTMCS8FBK:4; - } field; - UINT32 word; -} HT_FBK_CFG1_STRUC, *PHT_FBK_CFG1_STRUC; -#else typedef union _HT_FBK_CFG1_STRUC { struct { UINT32 HTMCS8FBK:4; @@ -1006,23 +633,8 @@ typedef union _HT_FBK_CFG1_STRUC { } field; UINT32 word; } HT_FBK_CFG1_STRUC, *PHT_FBK_CFG1_STRUC; -#endif + #define LG_FBK_CFG0 0x135c -#ifdef RT_BIG_ENDIAN -typedef union _LG_FBK_CFG0_STRUC { - struct { - UINT32 OFDMMCS7FBK:4; //initial value is 6 - UINT32 OFDMMCS6FBK:4; //initial value is 5 - UINT32 OFDMMCS5FBK:4; //initial value is 4 - UINT32 OFDMMCS4FBK:4; //initial value is 3 - UINT32 OFDMMCS3FBK:4; //initial value is 2 - UINT32 OFDMMCS2FBK:4; //initial value is 1 - UINT32 OFDMMCS1FBK:4; //initial value is 0 - UINT32 OFDMMCS0FBK:4; //initial value is 0 - } field; - UINT32 word; -} LG_FBK_CFG0_STRUC, *PLG_FBK_CFG0_STRUC; -#else typedef union _LG_FBK_CFG0_STRUC { struct { UINT32 OFDMMCS0FBK:4; //initial value is 0 @@ -1036,20 +648,8 @@ typedef union _LG_FBK_CFG0_STRUC { } field; UINT32 word; } LG_FBK_CFG0_STRUC, *PLG_FBK_CFG0_STRUC; -#endif + #define LG_FBK_CFG1 0x1360 -#ifdef RT_BIG_ENDIAN -typedef union _LG_FBK_CFG1_STRUC { - struct { - UINT32 rsv:16; - UINT32 CCKMCS3FBK:4; //initial value is 2 - UINT32 CCKMCS2FBK:4; //initial value is 1 - UINT32 CCKMCS1FBK:4; //initial value is 0 - UINT32 CCKMCS0FBK:4; //initial value is 0 - } field; - UINT32 word; -} LG_FBK_CFG1_STRUC, *PLG_FBK_CFG1_STRUC; -#else typedef union _LG_FBK_CFG1_STRUC { struct { UINT32 CCKMCS0FBK:4; //initial value is 0 @@ -1060,7 +660,6 @@ typedef union _LG_FBK_CFG1_STRUC { } field; UINT32 word; } LG_FBK_CFG1_STRUC, *PLG_FBK_CFG1_STRUC; -#endif //======================================================= //================ Protection Paramater================================ @@ -1070,24 +669,6 @@ typedef union _LG_FBK_CFG1_STRUC { #define ASIC_LONGNAV 2 #define ASIC_RTS 1 #define ASIC_CTS 2 -#ifdef RT_BIG_ENDIAN -typedef union _PROT_CFG_STRUC { - struct { - UINT32 rsv:5; - UINT32 RTSThEn:1; //RTS threshold enable on CCK TX - UINT32 TxopAllowGF40:1; //CCK TXOP allowance.0:disallow. - UINT32 TxopAllowGF20:1; //CCK TXOP allowance.0:disallow. - UINT32 TxopAllowMM40:1; //CCK TXOP allowance.0:disallow. - UINT32 TxopAllowMM20:1; //CCK TXOP allowance. 0:disallow. - UINT32 TxopAllowOfdm:1; //CCK TXOP allowance.0:disallow. - UINT32 TxopAllowCck:1; //CCK TXOP allowance.0:disallow. - UINT32 ProtectNav:2; //TXOP protection type for CCK TX. 0:None, 1:ShortNAVprotect, 2:LongNAVProtect, 3:rsv - UINT32 ProtectCtrl:2; //Protection control frame type for CCK TX. 1:RTS/CTS, 2:CTS-to-self, 0:None, 3:rsv - UINT32 ProtectRate:16; //Protection control frame rate for CCK TX(RTS/CTS/CFEnd). - } field; - UINT32 word; -} PROT_CFG_STRUC, *PPROT_CFG_STRUC; -#else typedef union _PROT_CFG_STRUC { struct { UINT32 ProtectRate:16; //Protection control frame rate for CCK TX(RTS/CTS/CFEnd). @@ -1104,7 +685,6 @@ typedef union _PROT_CFG_STRUC { } field; UINT32 word; } PROT_CFG_STRUC, *PPROT_CFG_STRUC; -#endif #define OFDM_PROT_CFG 0x1368 //OFDM Protection #define MM20_PROT_CFG 0x136C //MM20 Protection @@ -1122,22 +702,6 @@ typedef union _PROT_CFG_STRUC { // // TXRX_CSR4: Auto-Responder/ // -#ifdef RT_BIG_ENDIAN -typedef union _AUTO_RSP_CFG_STRUC { - struct { - UINT32 :24; - UINT32 AckCtsPsmBit:1; // Power bit value in conrtrol frame - UINT32 DualCTSEn:1; // Power bit value in conrtrol frame - UINT32 rsv:1; // Power bit value in conrtrol frame - UINT32 AutoResponderPreamble:1; // 0:long, 1:short preamble - UINT32 CTS40MRef:1; // Response CTS 40MHz duplicate mode - UINT32 CTS40MMode:1; // Response CTS 40MHz duplicate mode - UINT32 BACAckPolicyEnable:1; // 0:long, 1:short preamble - UINT32 AutoResponderEnable:1; - } field; - UINT32 word; -} AUTO_RSP_CFG_STRUC, *PAUTO_RSP_CFG_STRUC; -#else typedef union _AUTO_RSP_CFG_STRUC { struct { UINT32 AutoResponderEnable:1; @@ -1152,7 +716,6 @@ typedef union _AUTO_RSP_CFG_STRUC { } field; UINT32 word; } AUTO_RSP_CFG_STRUC, *PAUTO_RSP_CFG_STRUC; -#endif #define LEGACY_BASIC_RATE 0x1408 // TXRX_CSR5 0x3054 #define HT_BASIC_RATE 0x140c @@ -1185,15 +748,6 @@ typedef union _AUTO_RSP_CFG_STRUC { // // RX_STA_CNT0_STRUC: RX PLCP error count & RX CRC error count // -#ifdef RT_BIG_ENDIAN -typedef union _RX_STA_CNT0_STRUC { - struct { - USHORT PhyErr; - USHORT CrcErr; - } field; - UINT32 word; -} RX_STA_CNT0_STRUC, *PRX_STA_CNT0_STRUC; -#else typedef union _RX_STA_CNT0_STRUC { struct { USHORT CrcErr; @@ -1201,20 +755,10 @@ typedef union _RX_STA_CNT0_STRUC { } field; UINT32 word; } RX_STA_CNT0_STRUC, *PRX_STA_CNT0_STRUC; -#endif // // RX_STA_CNT1_STRUC: RX False CCA count & RX LONG frame count // -#ifdef RT_BIG_ENDIAN -typedef union _RX_STA_CNT1_STRUC { - struct { - USHORT PlcpErr; - USHORT FalseCca; - } field; - UINT32 word; -} RX_STA_CNT1_STRUC, *PRX_STA_CNT1_STRUC; -#else typedef union _RX_STA_CNT1_STRUC { struct { USHORT FalseCca; @@ -1222,20 +766,10 @@ typedef union _RX_STA_CNT1_STRUC { } field; UINT32 word; } RX_STA_CNT1_STRUC, *PRX_STA_CNT1_STRUC; -#endif // // RX_STA_CNT2_STRUC: // -#ifdef RT_BIG_ENDIAN -typedef union _RX_STA_CNT2_STRUC { - struct { - USHORT RxFifoOverflowCount; - USHORT RxDupliCount; - } field; - UINT32 word; -} RX_STA_CNT2_STRUC, *PRX_STA_CNT2_STRUC; -#else typedef union _RX_STA_CNT2_STRUC { struct { USHORT RxDupliCount; @@ -1243,20 +777,11 @@ typedef union _RX_STA_CNT2_STRUC { } field; UINT32 word; } RX_STA_CNT2_STRUC, *PRX_STA_CNT2_STRUC; -#endif + #define TX_STA_CNT0 0x170C // // // STA_CSR3: TX Beacon count // -#ifdef RT_BIG_ENDIAN -typedef union _TX_STA_CNT0_STRUC { - struct { - USHORT TxBeaconCount; - USHORT TxFailCount; - } field; - UINT32 word; -} TX_STA_CNT0_STRUC, *PTX_STA_CNT0_STRUC; -#else typedef union _TX_STA_CNT0_STRUC { struct { USHORT TxFailCount; @@ -1264,20 +789,11 @@ typedef union _TX_STA_CNT0_STRUC { } field; UINT32 word; } TX_STA_CNT0_STRUC, *PTX_STA_CNT0_STRUC; -#endif + #define TX_STA_CNT1 0x1710 // // // TX_STA_CNT1: TX tx count // -#ifdef RT_BIG_ENDIAN -typedef union _TX_STA_CNT1_STRUC { - struct { - USHORT TxRetransmit; - USHORT TxSuccess; - } field; - UINT32 word; -} TX_STA_CNT1_STRUC, *PTX_STA_CNT1_STRUC; -#else typedef union _TX_STA_CNT1_STRUC { struct { USHORT TxSuccess; @@ -1285,20 +801,11 @@ typedef union _TX_STA_CNT1_STRUC { } field; UINT32 word; } TX_STA_CNT1_STRUC, *PTX_STA_CNT1_STRUC; -#endif + #define TX_STA_CNT2 0x1714 // // // TX_STA_CNT2: TX tx count // -#ifdef RT_BIG_ENDIAN -typedef union _TX_STA_CNT2_STRUC { - struct { - USHORT TxUnderFlowCount; - USHORT TxZeroLenCount; - } field; - UINT32 word; -} TX_STA_CNT2_STRUC, *PTX_STA_CNT2_STRUC; -#else typedef union _TX_STA_CNT2_STRUC { struct { USHORT TxZeroLenCount; @@ -1306,28 +813,11 @@ typedef union _TX_STA_CNT2_STRUC { } field; UINT32 word; } TX_STA_CNT2_STRUC, *PTX_STA_CNT2_STRUC; -#endif + #define TX_STA_FIFO 0x1718 // // // TX_STA_FIFO_STRUC: TX Result for specific PID status fifo register // -#ifdef RT_BIG_ENDIAN -typedef union PACKED _TX_STA_FIFO_STRUC { - struct { - UINT32 Reserve:2; - UINT32 TxBF:1; // 3*3 - UINT32 SuccessRate:13; //include MCS, mode ,shortGI, BW settingSame format as TXWI Word 0 Bit 31-16. -// UINT32 SuccessRate:16; //include MCS, mode ,shortGI, BW settingSame format as TXWI Word 0 Bit 31-16. - UINT32 wcid:8; //wireless client index - UINT32 TxAckRequired:1; // ack required - UINT32 TxAggre:1; // Tx is aggregated - UINT32 TxSuccess:1; // Tx success. whether success or not - UINT32 PidType:4; - UINT32 bValid:1; // 1:This register contains a valid TX result - } field; - UINT32 word; -} TX_STA_FIFO_STRUC, *PTX_STA_FIFO_STRUC; -#else typedef union PACKED _TX_STA_FIFO_STRUC { struct { UINT32 bValid:1; // 1:This register contains a valid TX result @@ -1343,18 +833,9 @@ typedef union PACKED _TX_STA_FIFO_STRUC { } field; UINT32 word; } TX_STA_FIFO_STRUC, *PTX_STA_FIFO_STRUC; -#endif + // Debug counter #define TX_AGG_CNT 0x171c -#ifdef RT_BIG_ENDIAN -typedef union _TX_AGG_CNT_STRUC { - struct { - USHORT AggTxCount; - USHORT NonAggTxCount; - } field; - UINT32 word; -} TX_AGG_CNT_STRUC, *PTX_AGG_CNT_STRUC; -#else typedef union _TX_AGG_CNT_STRUC { struct { USHORT NonAggTxCount; @@ -1362,18 +843,9 @@ typedef union _TX_AGG_CNT_STRUC { } field; UINT32 word; } TX_AGG_CNT_STRUC, *PTX_AGG_CNT_STRUC; -#endif + // Debug counter #define TX_AGG_CNT0 0x1720 -#ifdef RT_BIG_ENDIAN -typedef union _TX_AGG_CNT0_STRUC { - struct { - USHORT AggSize2Count; - USHORT AggSize1Count; - } field; - UINT32 word; -} TX_AGG_CNT0_STRUC, *PTX_AGG_CNT0_STRUC; -#else typedef union _TX_AGG_CNT0_STRUC { struct { USHORT AggSize1Count; @@ -1381,18 +853,9 @@ typedef union _TX_AGG_CNT0_STRUC { } field; UINT32 word; } TX_AGG_CNT0_STRUC, *PTX_AGG_CNT0_STRUC; -#endif + // Debug counter #define TX_AGG_CNT1 0x1724 -#ifdef RT_BIG_ENDIAN -typedef union _TX_AGG_CNT1_STRUC { - struct { - USHORT AggSize4Count; - USHORT AggSize3Count; - } field; - UINT32 word; -} TX_AGG_CNT1_STRUC, *PTX_AGG_CNT1_STRUC; -#else typedef union _TX_AGG_CNT1_STRUC { struct { USHORT AggSize3Count; @@ -1400,17 +863,8 @@ typedef union _TX_AGG_CNT1_STRUC { } field; UINT32 word; } TX_AGG_CNT1_STRUC, *PTX_AGG_CNT1_STRUC; -#endif + #define TX_AGG_CNT2 0x1728 -#ifdef RT_BIG_ENDIAN -typedef union _TX_AGG_CNT2_STRUC { - struct { - USHORT AggSize6Count; - USHORT AggSize5Count; - } field; - UINT32 word; -} TX_AGG_CNT2_STRUC, *PTX_AGG_CNT2_STRUC; -#else typedef union _TX_AGG_CNT2_STRUC { struct { USHORT AggSize5Count; @@ -1418,18 +872,9 @@ typedef union _TX_AGG_CNT2_STRUC { } field; UINT32 word; } TX_AGG_CNT2_STRUC, *PTX_AGG_CNT2_STRUC; -#endif + // Debug counter #define TX_AGG_CNT3 0x172c -#ifdef RT_BIG_ENDIAN -typedef union _TX_AGG_CNT3_STRUC { - struct { - USHORT AggSize8Count; - USHORT AggSize7Count; - } field; - UINT32 word; -} TX_AGG_CNT3_STRUC, *PTX_AGG_CNT3_STRUC; -#else typedef union _TX_AGG_CNT3_STRUC { struct { USHORT AggSize7Count; @@ -1437,18 +882,9 @@ typedef union _TX_AGG_CNT3_STRUC { } field; UINT32 word; } TX_AGG_CNT3_STRUC, *PTX_AGG_CNT3_STRUC; -#endif + // Debug counter #define TX_AGG_CNT4 0x1730 -#ifdef RT_BIG_ENDIAN -typedef union _TX_AGG_CNT4_STRUC { - struct { - USHORT AggSize10Count; - USHORT AggSize9Count; - } field; - UINT32 word; -} TX_AGG_CNT4_STRUC, *PTX_AGG_CNT4_STRUC; -#else typedef union _TX_AGG_CNT4_STRUC { struct { USHORT AggSize9Count; @@ -1456,17 +892,8 @@ typedef union _TX_AGG_CNT4_STRUC { } field; UINT32 word; } TX_AGG_CNT4_STRUC, *PTX_AGG_CNT4_STRUC; -#endif + #define TX_AGG_CNT5 0x1734 -#ifdef RT_BIG_ENDIAN -typedef union _TX_AGG_CNT5_STRUC { - struct { - USHORT AggSize12Count; - USHORT AggSize11Count; - } field; - UINT32 word; -} TX_AGG_CNT5_STRUC, *PTX_AGG_CNT5_STRUC; -#else typedef union _TX_AGG_CNT5_STRUC { struct { USHORT AggSize11Count; @@ -1474,17 +901,8 @@ typedef union _TX_AGG_CNT5_STRUC { } field; UINT32 word; } TX_AGG_CNT5_STRUC, *PTX_AGG_CNT5_STRUC; -#endif + #define TX_AGG_CNT6 0x1738 -#ifdef RT_BIG_ENDIAN -typedef union _TX_AGG_CNT6_STRUC { - struct { - USHORT AggSize14Count; - USHORT AggSize13Count; - } field; - UINT32 word; -} TX_AGG_CNT6_STRUC, *PTX_AGG_CNT6_STRUC; -#else typedef union _TX_AGG_CNT6_STRUC { struct { USHORT AggSize13Count; @@ -1492,17 +910,8 @@ typedef union _TX_AGG_CNT6_STRUC { } field; UINT32 word; } TX_AGG_CNT6_STRUC, *PTX_AGG_CNT6_STRUC; -#endif + #define TX_AGG_CNT7 0x173c -#ifdef RT_BIG_ENDIAN -typedef union _TX_AGG_CNT7_STRUC { - struct { - USHORT AggSize16Count; - USHORT AggSize15Count; - } field; - UINT32 word; -} TX_AGG_CNT7_STRUC, *PTX_AGG_CNT7_STRUC; -#else typedef union _TX_AGG_CNT7_STRUC { struct { USHORT AggSize15Count; @@ -1510,17 +919,8 @@ typedef union _TX_AGG_CNT7_STRUC { } field; UINT32 word; } TX_AGG_CNT7_STRUC, *PTX_AGG_CNT7_STRUC; -#endif + #define MPDU_DENSITY_CNT 0x1740 -#ifdef RT_BIG_ENDIAN -typedef union _MPDU_DEN_CNT_STRUC { - struct { - USHORT RXZeroDelCount; //RX zero length delimiter count - USHORT TXZeroDelCount; //TX zero length delimiter count - } field; - UINT32 word; -} MPDU_DEN_CNT_STRUC, *PMPDU_DEN_CNT_STRUC; -#else typedef union _MPDU_DEN_CNT_STRUC { struct { USHORT TXZeroDelCount; //TX zero length delimiter count @@ -1528,7 +928,7 @@ typedef union _MPDU_DEN_CNT_STRUC { } field; UINT32 word; } MPDU_DEN_CNT_STRUC, *PMPDU_DEN_CNT_STRUC; -#endif + // // TXRX control registers - base address 0x3000 // @@ -1554,52 +954,28 @@ typedef union _MPDU_DEN_CNT_STRUC { #define SHAREDKEYTABLE 0 #define PAIRWISEKEYTABLE 1 +typedef union _SHAREDKEY_MODE_STRUC { + struct { + UINT32 Bss0Key0CipherAlg:3; + UINT32 :1; + UINT32 Bss0Key1CipherAlg:3; + UINT32 :1; + UINT32 Bss0Key2CipherAlg:3; + UINT32 :1; + UINT32 Bss0Key3CipherAlg:3; + UINT32 :1; + UINT32 Bss1Key0CipherAlg:3; + UINT32 :1; + UINT32 Bss1Key1CipherAlg:3; + UINT32 :1; + UINT32 Bss1Key2CipherAlg:3; + UINT32 :1; + UINT32 Bss1Key3CipherAlg:3; + UINT32 :1; + } field; + UINT32 word; +} SHAREDKEY_MODE_STRUC, *PSHAREDKEY_MODE_STRUC; -#ifdef RT_BIG_ENDIAN -typedef union _SHAREDKEY_MODE_STRUC { - struct { - UINT32 :1; - UINT32 Bss1Key3CipherAlg:3; - UINT32 :1; - UINT32 Bss1Key2CipherAlg:3; - UINT32 :1; - UINT32 Bss1Key1CipherAlg:3; - UINT32 :1; - UINT32 Bss1Key0CipherAlg:3; - UINT32 :1; - UINT32 Bss0Key3CipherAlg:3; - UINT32 :1; - UINT32 Bss0Key2CipherAlg:3; - UINT32 :1; - UINT32 Bss0Key1CipherAlg:3; - UINT32 :1; - UINT32 Bss0Key0CipherAlg:3; - } field; - UINT32 word; -} SHAREDKEY_MODE_STRUC, *PSHAREDKEY_MODE_STRUC; -#else -typedef union _SHAREDKEY_MODE_STRUC { - struct { - UINT32 Bss0Key0CipherAlg:3; - UINT32 :1; - UINT32 Bss0Key1CipherAlg:3; - UINT32 :1; - UINT32 Bss0Key2CipherAlg:3; - UINT32 :1; - UINT32 Bss0Key3CipherAlg:3; - UINT32 :1; - UINT32 Bss1Key0CipherAlg:3; - UINT32 :1; - UINT32 Bss1Key1CipherAlg:3; - UINT32 :1; - UINT32 Bss1Key2CipherAlg:3; - UINT32 :1; - UINT32 Bss1Key3CipherAlg:3; - UINT32 :1; - } field; - UINT32 word; -} SHAREDKEY_MODE_STRUC, *PSHAREDKEY_MODE_STRUC; -#endif // 64-entry for pairwise key table typedef struct _HW_WCID_ENTRY { // 8-byte per entry UCHAR Address[6]; @@ -1670,10 +1046,16 @@ typedef struct _HW_WCID_ENTRY { // 8-byte per entry #define E2PROM_CSR 0x0004 #define IO_CNTL_CSR 0x77d0 +#ifdef RT2860 // 8051 firmware image for RT2860 - base address = 0x4000 #define FIRMWARE_IMAGE_BASE 0x2000 #define MAX_FIRMWARE_IMAGE_SIZE 0x2000 // 8kbyte - +#endif +#ifdef RT2870 +// 8051 firmware image for usb - use last-half base address = 0x3000 +#define FIRMWARE_IMAGE_BASE 0x3000 +#define MAX_FIRMWARE_IMAGE_SIZE 0x1000 // 4kbyte +#endif // RT2870 // // ================================================================ // Tx / Rx / Mgmt ring descriptor definition @@ -1754,6 +1136,9 @@ typedef struct _HW_WCID_ENTRY { // 8-byte per entry #define BBP_R22 22 #define BBP_R24 24 #define BBP_R25 25 +#ifdef RT30xx +#define BBP_R31 31 +#endif #define BBP_R49 49 //TSSI #define BBP_R50 50 #define BBP_R51 51 @@ -1771,6 +1156,10 @@ typedef struct _HW_WCID_ENTRY { // 8-byte per entry #define BBP_R73 73 #define BBP_R75 75 #define BBP_R77 77 +#ifdef RT30xx +#define BBP_R79 79 +#define BBP_R80 80 +#endif #define BBP_R81 81 #define BBP_R82 82 #define BBP_R83 83 @@ -1792,6 +1181,9 @@ typedef struct _HW_WCID_ENTRY { // 8-byte per entry #define BBP_R121 121 #define BBP_R122 122 #define BBP_R123 123 +#ifdef RT30xx +#define BBP_R138 138 // add by johnli, RF power sequence setup, ADC dynamic on/off control +#endif // RT30xx // #define BBPR94_DEFAULT 0x06 // Add 1 value will gain 1db @@ -1872,15 +1264,6 @@ typedef struct _HW_KEY_ENTRY { // 32-byte per entry //8.1.2 IV/EIV format : 2DW //8.1.3 RX attribute entry format : 1DW -#ifdef RT_BIG_ENDIAN -typedef struct _MAC_ATTRIBUTE_STRUC { - UINT32 rsv:22; - UINT32 RXWIUDF:3; - UINT32 BSSIDIdx:3; //multipleBSS index for the WCID - UINT32 PairKeyMode:3; - UINT32 KeyTab:1; // 0 for shared key table. 1 for pairwise key table -} MAC_ATTRIBUTE_STRUC, *PMAC_ATTRIBUTE_STRUC; -#else typedef struct _MAC_ATTRIBUTE_STRUC { UINT32 KeyTab:1; // 0 for shared key table. 1 for pairwise key table UINT32 PairKeyMode:3; @@ -1888,8 +1271,6 @@ typedef struct _MAC_ATTRIBUTE_STRUC { UINT32 RXWIUDF:3; UINT32 rsv:22; } MAC_ATTRIBUTE_STRUC, *PMAC_ATTRIBUTE_STRUC; -#endif - // ================================================================================= // TX / RX ring descriptor format @@ -1904,29 +1285,6 @@ typedef struct _MAC_ATTRIBUTE_STRUC { // // TX descriptor format, Tx ring, Mgmt Ring // -#ifdef RT_BIG_ENDIAN -typedef struct PACKED _TXD_STRUC { - // Word 0 - UINT32 SDPtr0; - // Word 1 - UINT32 DMADONE:1; - UINT32 LastSec0:1; - UINT32 SDLen0:14; - UINT32 Burst:1; - UINT32 LastSec1:1; - UINT32 SDLen1:14; - // Word 2 - UINT32 SDPtr1; - // Word 3 - UINT32 ICO:1; - UINT32 UCO:1; - UINT32 TCO:1; - UINT32 rsv:2; - UINT32 QSEL:2; // select on-chip FIFO ID for 2nd-stage output scheduler.0:MGMT, 1:HCCA 2:EDCA - UINT32 WIV:1; // Wireless Info Valid. 1 if Driver already fill WI, o if DMA needs to copy WI to correctposition - UINT32 rsv2:24; -} TXD_STRUC, *PTXD_STRUC; -#else typedef struct PACKED _TXD_STRUC { // Word 0 UINT32 SDPtr0; @@ -1948,8 +1306,6 @@ typedef struct PACKED _TXD_STRUC { UINT32 UCO:1; // UINT32 ICO:1; // } TXD_STRUC, *PTXD_STRUC; -#endif - // // TXD Wireless Information format for Tx ring and Mgmt Ring @@ -1957,40 +1313,6 @@ typedef struct PACKED _TXD_STRUC { //txop : for txop mode // 0:txop for the MPDU frame will be handles by ASIC by register // 1/2/3:the MPDU frame is send after PIFS/backoff/SIFS -#ifdef RT_BIG_ENDIAN -typedef struct PACKED _TXWI_STRUC { - // Word 0 - UINT32 PHYMODE:2; - UINT32 TxBF:1; // 3*3 - UINT32 rsv2:1; - UINT32 Ifs:1; // - UINT32 STBC:2; //channel bandwidth 20MHz or 40 MHz - UINT32 ShortGI:1; - UINT32 BW:1; //channel bandwidth 20MHz or 40 MHz - UINT32 MCS:7; - - UINT32 rsv:6; - UINT32 txop:2; //tx back off mode 0:HT TXOP rule , 1:PIFS TX ,2:Backoff, 3:sifs only when previous frame exchange is successful. - UINT32 MpduDensity:3; - UINT32 AMPDU:1; - - UINT32 TS:1; - UINT32 CFACK:1; - UINT32 MIMOps:1; // the remote peer is in dynamic MIMO-PS mode - UINT32 FRAG:1; // 1 to inform TKIP engine this is a fragment. - // Word 1 - UINT32 PacketId:4; - UINT32 MPDUtotalByteCount:12; - UINT32 WirelessCliID:8; - UINT32 BAWinSize:6; - UINT32 NSEQ:1; - UINT32 ACK:1; - // Word 2 - UINT32 IV; - // Word 3 - UINT32 EIV; -} TXWI_STRUC, *PTXWI_STRUC; -#else typedef struct PACKED _TXWI_STRUC { // Word 0 UINT32 FRAG:1; // 1 to inform TKIP engine this is a fragment. @@ -2023,45 +1345,11 @@ typedef struct PACKED _TXWI_STRUC { //Word3 UINT32 EIV; } TXWI_STRUC, *PTXWI_STRUC; -#endif + // // Rx descriptor format, Rx Ring // -#ifdef RT_BIG_ENDIAN -typedef struct PACKED _RXD_STRUC { - // Word 0 - UINT32 SDP0; - // Word 1 - UINT32 DDONE:1; - UINT32 LS0:1; - UINT32 SDL0:14; - UINT32 Rsv:2; - UINT32 SDL1:14; - // Word 2 - UINT32 SDP1; - // Word 3 - UINT32 Rsv1:13; - UINT32 PlcpRssil:1;// To be moved - UINT32 PlcpSignal:1; // To be moved - UINT32 Decrypted:1; // this frame is being decrypted. - UINT32 AMPDU:1; - UINT32 L2PAD:1; - UINT32 RSSI:1; - UINT32 HTC:1; - UINT32 AMSDU:1; // rx with 802.3 header, not 802.11 header. obsolete. - UINT32 CipherErr:2; // 0: decryption okay, 1:ICV error, 2:MIC error, 3:KEY not valid - UINT32 Crc:1; // 1: CRC error - UINT32 MyBss:1; // 1: this frame belongs to the same BSSID - UINT32 Bcast:1; // 1: this is a broadcast frame - UINT32 Mcast:1; // 1: this is a multicast frame - UINT32 U2M:1; // 1: this RX frame is unicast to me - UINT32 FRAG:1; - UINT32 NULLDATA:1; - UINT32 DATA:1; - UINT32 BA:1; - -} RXD_STRUC, *PRXD_STRUC, RT28XX_RXD_STRUC, *PRT28XX_RXD_STRUC; -#else +#ifdef RT2860 typedef struct PACKED _RXD_STRUC { // Word 0 UINT32 SDP0; @@ -2094,39 +1382,11 @@ typedef struct PACKED _RXD_STRUC { UINT32 PlcpRssil:1;// To be moved UINT32 Rsv1:13; } RXD_STRUC, *PRXD_STRUC, RT28XX_RXD_STRUC, *PRT28XX_RXD_STRUC; -#endif +#endif /* RT2860 */ + // // RXWI wireless information format, in PBF. invisible in driver. // -#ifdef RT_BIG_ENDIAN -typedef struct PACKED _RXWI_STRUC { - // Word 0 - UINT32 TID:4; - UINT32 MPDUtotalByteCount:12; - UINT32 UDF:3; - UINT32 BSSID:3; - UINT32 KeyIndex:2; - UINT32 WirelessCliID:8; - // Word 1 - UINT32 PHYMODE:2; // 1: this RX frame is unicast to me - UINT32 rsv:3; - UINT32 STBC:2; - UINT32 ShortGI:1; - UINT32 BW:1; - UINT32 MCS:7; - UINT32 SEQUENCE:12; - UINT32 FRAG:4; - // Word 2 - UINT32 rsv1:8; - UINT32 RSSI2:8; - UINT32 RSSI1:8; - UINT32 RSSI0:8; - // Word 3 - UINT32 rsv2:16; - UINT32 SNR1:8; - UINT32 SNR0:8; -} RXWI_STRUC, *PRXWI_STRUC; -#else typedef struct PACKED _RXWI_STRUC { // Word 0 UINT32 WirelessCliID:8; @@ -2154,8 +1414,6 @@ typedef struct PACKED _RXWI_STRUC { UINT32 SNR1:8; UINT32 rsv2:16; } RXWI_STRUC, *PRXWI_STRUC; -#endif - // ================================================================================= // HOST-MCU communication data structure @@ -2164,17 +1422,6 @@ typedef struct PACKED _RXWI_STRUC { // // H2M_MAILBOX_CSR: Host-to-MCU Mailbox // -#ifdef RT_BIG_ENDIAN -typedef union _H2M_MAILBOX_STRUC { - struct { - UINT32 Owner:8; - UINT32 CmdToken:8; // 0xff tells MCU not to report CmdDoneInt after excuting the command - UINT32 HighByte:8; - UINT32 LowByte:8; - } field; - UINT32 word; -} H2M_MAILBOX_STRUC, *PH2M_MAILBOX_STRUC; -#else typedef union _H2M_MAILBOX_STRUC { struct { UINT32 LowByte:8; @@ -2184,22 +1431,10 @@ typedef union _H2M_MAILBOX_STRUC { } field; UINT32 word; } H2M_MAILBOX_STRUC, *PH2M_MAILBOX_STRUC; -#endif // // M2H_CMD_DONE_CSR: MCU-to-Host command complete indication // -#ifdef RT_BIG_ENDIAN -typedef union _M2H_CMD_DONE_STRUC { - struct { - UINT32 CmdToken3; - UINT32 CmdToken2; - UINT32 CmdToken1; - UINT32 CmdToken0; - } field; - UINT32 word; -} M2H_CMD_DONE_STRUC, *PM2H_CMD_DONE_STRUC; -#else typedef union _M2H_CMD_DONE_STRUC { struct { UINT32 CmdToken0; @@ -2209,22 +1444,10 @@ typedef union _M2H_CMD_DONE_STRUC { } field; UINT32 word; } M2H_CMD_DONE_STRUC, *PM2H_CMD_DONE_STRUC; -#endif - - // // MCU_LEDCS: MCU LED Control Setting. // -#ifdef RT_BIG_ENDIAN -typedef union _MCU_LEDCS_STRUC { - struct { - UCHAR Polarity:1; - UCHAR LedMode:7; - } field; - UCHAR word; -} MCU_LEDCS_STRUC, *PMCU_LEDCS_STRUC; -#else typedef union _MCU_LEDCS_STRUC { struct { UCHAR LedMode:7; @@ -2232,7 +1455,7 @@ typedef union _MCU_LEDCS_STRUC { } field; UCHAR word; } MCU_LEDCS_STRUC, *PMCU_LEDCS_STRUC; -#endif + // ================================================================================= // Register format // ================================================================================= @@ -2240,18 +1463,6 @@ typedef union _MCU_LEDCS_STRUC { //NAV_TIME_CFG :NAV -#ifdef RT_BIG_ENDIAN -typedef union _NAV_TIME_CFG_STRUC { - struct { - USHORT rsv:6; - USHORT ZeroSifs:1; // Applied zero SIFS timer after OFDM RX 0: disable - USHORT Eifs:9; // in unit of 1-us - UCHAR SlotTime; // in unit of 1-us - UCHAR Sifs; // in unit of 1-us - } field; - UINT32 word; -} NAV_TIME_CFG_STRUC, *PNAV_TIME_CFG_STRUC; -#else typedef union _NAV_TIME_CFG_STRUC { struct { UCHAR Sifs; // in unit of 1-us @@ -2262,44 +1473,10 @@ typedef union _NAV_TIME_CFG_STRUC { } field; UINT32 word; } NAV_TIME_CFG_STRUC, *PNAV_TIME_CFG_STRUC; -#endif - - - - // // RX_FILTR_CFG: /RX configuration register // -#ifdef RT_BIG_ENDIAN -typedef union RX_FILTR_CFG_STRUC { - struct { - UINT32 :15; - UINT32 DropRsvCntlType:1; - - UINT32 DropBAR:1; // - UINT32 DropBA:1; // - UINT32 DropPsPoll:1; // Drop Ps-Poll - UINT32 DropRts:1; // Drop Ps-Poll - - UINT32 DropCts:1; // Drop Ps-Poll - UINT32 DropAck:1; // Drop Ps-Poll - UINT32 DropCFEnd:1; // Drop Ps-Poll - UINT32 DropCFEndAck:1; // Drop Ps-Poll - - UINT32 DropDuplicate:1; // Drop duplicate frame - UINT32 DropBcast:1; // Drop broadcast frames - UINT32 DropMcast:1; // Drop multicast frames - UINT32 DropVerErr:1; // Drop version error frame - - UINT32 DropNotMyBSSID:1; // Drop fram ToDs bit is true - UINT32 DropNotToMe:1; // Drop not to me unicast frame - UINT32 DropPhyErr:1; // Drop physical error - UINT32 DropCRCErr:1; // Drop CRC error - } field; - UINT32 word; -} RX_FILTR_CFG_STRUC, *PRX_FILTR_CFG_STRUC; -#else typedef union _RX_FILTR_CFG_STRUC { struct { UINT32 DropCRCErr:1; // Drop CRC error @@ -2327,26 +1504,10 @@ typedef union _RX_FILTR_CFG_STRUC { } field; UINT32 word; } RX_FILTR_CFG_STRUC, *PRX_FILTR_CFG_STRUC; -#endif - - - // // PHY_CSR4: RF serial control register // -#ifdef RT_BIG_ENDIAN -typedef union _PHY_CSR4_STRUC { - struct { - UINT32 Busy:1; // 1: ASIC is busy execute RF programming. - UINT32 PLL_LD:1; // RF PLL_LD status - UINT32 IFSelect:1; // 1: select IF to program, 0: select RF to program - UINT32 NumberOfBits:5; // Number of bits used in RFRegValue (I:20, RFMD:22) - UINT32 RFRegValue:24; // Register value (include register id) serial out to RF/IF chip. - } field; - UINT32 word; -} PHY_CSR4_STRUC, *PPHY_CSR4_STRUC; -#else typedef union _PHY_CSR4_STRUC { struct { UINT32 RFRegValue:24; // Register value (include register id) serial out to RF/IF chip. @@ -2357,35 +1518,10 @@ typedef union _PHY_CSR4_STRUC { } field; UINT32 word; } PHY_CSR4_STRUC, *PPHY_CSR4_STRUC; -#endif - // // SEC_CSR5: shared key table security mode register // -#ifdef RT_BIG_ENDIAN -typedef union _SEC_CSR5_STRUC { - struct { - UINT32 :1; - UINT32 Bss3Key3CipherAlg:3; - UINT32 :1; - UINT32 Bss3Key2CipherAlg:3; - UINT32 :1; - UINT32 Bss3Key1CipherAlg:3; - UINT32 :1; - UINT32 Bss3Key0CipherAlg:3; - UINT32 :1; - UINT32 Bss2Key3CipherAlg:3; - UINT32 :1; - UINT32 Bss2Key2CipherAlg:3; - UINT32 :1; - UINT32 Bss2Key1CipherAlg:3; - UINT32 :1; - UINT32 Bss2Key0CipherAlg:3; - } field; - UINT32 word; -} SEC_CSR5_STRUC, *PSEC_CSR5_STRUC; -#else typedef union _SEC_CSR5_STRUC { struct { UINT32 Bss2Key0CipherAlg:3; @@ -2407,21 +1543,10 @@ typedef union _SEC_CSR5_STRUC { } field; UINT32 word; } SEC_CSR5_STRUC, *PSEC_CSR5_STRUC; -#endif - // // HOST_CMD_CSR: For HOST to interrupt embedded processor // -#ifdef RT_BIG_ENDIAN -typedef union _HOST_CMD_CSR_STRUC { - struct { - UINT32 Rsv:24; - UINT32 HostCommand:8; - } field; - UINT32 word; -} HOST_CMD_CSR_STRUC, *PHOST_CMD_CSR_STRUC; -#else typedef union _HOST_CMD_CSR_STRUC { struct { UINT32 HostCommand:8; @@ -2429,8 +1554,6 @@ typedef union _HOST_CMD_CSR_STRUC { } field; UINT32 word; } HOST_CMD_CSR_STRUC, *PHOST_CMD_CSR_STRUC; -#endif - // // AIFSN_CSR: AIFSN for each EDCA AC @@ -2441,21 +1564,6 @@ typedef union _HOST_CMD_CSR_STRUC { // // E2PROM_CSR: EEPROM control register // -#ifdef RT_BIG_ENDIAN -typedef union _E2PROM_CSR_STRUC { - struct { - UINT32 Rsvd:25; - UINT32 LoadStatus:1; // 1:loading, 0:done - UINT32 Type:1; // 1: 93C46, 0:93C66 - UINT32 EepromDO:1; - UINT32 EepromDI:1; - UINT32 EepromCS:1; - UINT32 EepromSK:1; - UINT32 Reload:1; // Reload EEPROM content, write one to reload, self-cleared. - } field; - UINT32 word; -} E2PROM_CSR_STRUC, *PE2PROM_CSR_STRUC; -#else typedef union _E2PROM_CSR_STRUC { struct { UINT32 Reload:1; // Reload EEPROM content, write one to reload, self-cleared. @@ -2469,8 +1577,6 @@ typedef union _E2PROM_CSR_STRUC { } field; UINT32 word; } E2PROM_CSR_STRUC, *PE2PROM_CSR_STRUC; -#endif - // ------------------------------------------------------------------- // E2PROM data layout @@ -2479,17 +1585,6 @@ typedef union _E2PROM_CSR_STRUC { // // EEPROM antenna select format // -#ifdef RT_BIG_ENDIAN -typedef union _EEPROM_ANTENNA_STRUC { - struct { - USHORT Rsv:4; - USHORT RfIcType:4; // see E2PROM document - USHORT TxPath:4; // 1: 1T, 2: 2T - USHORT RxPath:4; // 1: 1R, 2: 2R, 3: 3R - } field; - USHORT word; -} EEPROM_ANTENNA_STRUC, *PEEPROM_ANTENNA_STRUC; -#else typedef union _EEPROM_ANTENNA_STRUC { struct { USHORT RxPath:4; // 1: 1R, 2: 2R, 3: 3R @@ -2499,26 +1594,7 @@ typedef union _EEPROM_ANTENNA_STRUC { } field; USHORT word; } EEPROM_ANTENNA_STRUC, *PEEPROM_ANTENNA_STRUC; -#endif -#ifdef RT_BIG_ENDIAN -typedef union _EEPROM_NIC_CINFIG2_STRUC { - struct { - USHORT Rsv2:6; // must be 0 - USHORT BW40MAvailForA:1; // 0:enable, 1:disable - USHORT BW40MAvailForG:1; // 0:enable, 1:disable - USHORT EnableWPSPBC:1; // WPS PBC Control bit - USHORT BW40MSidebandForA:1; - USHORT BW40MSidebandForG:1; - USHORT CardbusAcceleration:1; // !!! NOTE: 0 - enable, 1 - disable - USHORT ExternalLNAForA:1; // external LNA enable for 5G - USHORT ExternalLNAForG:1; // external LNA enable for 2.4G - USHORT DynamicTxAgcControl:1; // - USHORT HardwareRadioControl:1; // Whether RF is controlled by driver or HW. 1:enable hw control, 0:disable - } field; - USHORT word; -} EEPROM_NIC_CONFIG2_STRUC, *PEEPROM_NIC_CONFIG2_STRUC; -#else typedef union _EEPROM_NIC_CINFIG2_STRUC { struct { USHORT HardwareRadioControl:1; // 1:enable, 0:disable @@ -2531,24 +1607,22 @@ typedef union _EEPROM_NIC_CINFIG2_STRUC { USHORT EnableWPSPBC:1; // WPS PBC Control bit USHORT BW40MAvailForG:1; // 0:enable, 1:disable USHORT BW40MAvailForA:1; // 0:enable, 1:disable +#ifndef RT30xx USHORT Rsv2:6; // must be 0 +#endif +#ifdef RT30xx + USHORT Rsv1:1; // must be 0 + USHORT AntDiversity:1; // Antenna diversity + USHORT Rsv2:3; // must be 0 + USHORT DACTestBit:1; // control if driver should patch the DAC issue +#endif } field; USHORT word; } EEPROM_NIC_CONFIG2_STRUC, *PEEPROM_NIC_CONFIG2_STRUC; -#endif // // TX_PWR Value valid range 0xFA(-6) ~ 0x24(36) // -#ifdef RT_BIG_ENDIAN -typedef union _EEPROM_TX_PWR_STRUC { - struct { - CHAR Byte1; // High Byte - CHAR Byte0; // Low Byte - } field; - USHORT word; -} EEPROM_TX_PWR_STRUC, *PEEPROM_TX_PWR_STRUC; -#else typedef union _EEPROM_TX_PWR_STRUC { struct { CHAR Byte0; // Low Byte @@ -2556,17 +1630,7 @@ typedef union _EEPROM_TX_PWR_STRUC { } field; USHORT word; } EEPROM_TX_PWR_STRUC, *PEEPROM_TX_PWR_STRUC; -#endif -#ifdef RT_BIG_ENDIAN -typedef union _EEPROM_VERSION_STRUC { - struct { - UCHAR Version; // High Byte - UCHAR FaeReleaseNumber; // Low Byte - } field; - USHORT word; -} EEPROM_VERSION_STRUC, *PEEPROM_VERSION_STRUC; -#else typedef union _EEPROM_VERSION_STRUC { struct { UCHAR FaeReleaseNumber; // Low Byte @@ -2574,25 +1638,7 @@ typedef union _EEPROM_VERSION_STRUC { } field; USHORT word; } EEPROM_VERSION_STRUC, *PEEPROM_VERSION_STRUC; -#endif -#ifdef RT_BIG_ENDIAN -typedef union _EEPROM_LED_STRUC { - struct { - USHORT Rsvd:3; // Reserved - USHORT LedMode:5; // Led mode. - USHORT PolarityGPIO_4:1; // Polarity GPIO#4 setting. - USHORT PolarityGPIO_3:1; // Polarity GPIO#3 setting. - USHORT PolarityGPIO_2:1; // Polarity GPIO#2 setting. - USHORT PolarityGPIO_1:1; // Polarity GPIO#1 setting. - USHORT PolarityGPIO_0:1; // Polarity GPIO#0 setting. - USHORT PolarityACT:1; // Polarity ACT setting. - USHORT PolarityRDY_A:1; // Polarity RDY_A setting. - USHORT PolarityRDY_G:1; // Polarity RDY_G setting. - } field; - USHORT word; -} EEPROM_LED_STRUC, *PEEPROM_LED_STRUC; -#else typedef union _EEPROM_LED_STRUC { struct { USHORT PolarityRDY_G:1; // Polarity RDY_G setting. @@ -2608,18 +1654,7 @@ typedef union _EEPROM_LED_STRUC { } field; USHORT word; } EEPROM_LED_STRUC, *PEEPROM_LED_STRUC; -#endif -#ifdef RT_BIG_ENDIAN -typedef union _EEPROM_TXPOWER_DELTA_STRUC { - struct { - UCHAR TxPowerEnable:1;// Enable - UCHAR Type:1; // 1: plus the delta value, 0: minus the delta value - UCHAR DeltaValue:6; // Tx Power dalta value (MAX=4) - } field; - UCHAR value; -} EEPROM_TXPOWER_DELTA_STRUC, *PEEPROM_TXPOWER_DELTA_STRUC; -#else typedef union _EEPROM_TXPOWER_DELTA_STRUC { struct { UCHAR DeltaValue:6; // Tx Power dalta value (MAX=4) @@ -2628,22 +1663,10 @@ typedef union _EEPROM_TXPOWER_DELTA_STRUC { } field; UCHAR value; } EEPROM_TXPOWER_DELTA_STRUC, *PEEPROM_TXPOWER_DELTA_STRUC; -#endif // // QOS_CSR0: TXOP holder address0 register // -#ifdef RT_BIG_ENDIAN -typedef union _QOS_CSR0_STRUC { - struct { - UCHAR Byte3; // MAC address byte 3 - UCHAR Byte2; // MAC address byte 2 - UCHAR Byte1; // MAC address byte 1 - UCHAR Byte0; // MAC address byte 0 - } field; - UINT32 word; -} QOS_CSR0_STRUC, *PQOS_CSR0_STRUC; -#else typedef union _QOS_CSR0_STRUC { struct { UCHAR Byte0; // MAC address byte 0 @@ -2653,22 +1676,10 @@ typedef union _QOS_CSR0_STRUC { } field; UINT32 word; } QOS_CSR0_STRUC, *PQOS_CSR0_STRUC; -#endif // // QOS_CSR1: TXOP holder address1 register // -#ifdef RT_BIG_ENDIAN -typedef union _QOS_CSR1_STRUC { - struct { - UCHAR Rsvd1; - UCHAR Rsvd0; - UCHAR Byte5; // MAC address byte 5 - UCHAR Byte4; // MAC address byte 4 - } field; - UINT32 word; -} QOS_CSR1_STRUC, *PQOS_CSR1_STRUC; -#else typedef union _QOS_CSR1_STRUC { struct { UCHAR Byte4; // MAC address byte 4 @@ -2678,22 +1689,8 @@ typedef union _QOS_CSR1_STRUC { } field; UINT32 word; } QOS_CSR1_STRUC, *PQOS_CSR1_STRUC; -#endif #define RF_CSR_CFG 0x500 -#ifdef RT_BIG_ENDIAN -typedef union _RF_CSR_CFG_STRUC { - struct { - UINT Rsvd1:14; // Reserved - UINT RF_CSR_KICK:1; // kick RF register read/write - UINT RF_CSR_WR:1; // 0: read 1: write - UINT Rsvd2:3; // Reserved - UINT TESTCSR_RFACC_REGNUM:5; // RF register ID - UINT RF_CSR_DATA:8; // DATA - } field; - UINT word; -} RF_CSR_CFG_STRUC, *PRF_CSR_CFG_STRUC; -#else typedef union _RF_CSR_CFG_STRUC { struct { UINT RF_CSR_DATA:8; // DATA @@ -2705,6 +1702,5 @@ typedef union _RF_CSR_CFG_STRUC { } field; UINT word; } RF_CSR_CFG_STRUC, *PRF_CSR_CFG_STRUC; -#endif #endif // __RT28XX_H__ diff --git a/drivers/staging/rt2860/rt_ate.c b/drivers/staging/rt2860/rt_ate.c deleted file mode 100644 index 1ed73c9e6b60..000000000000 --- a/drivers/staging/rt2860/rt_ate.c +++ /dev/null @@ -1,6009 +0,0 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * 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 "rt_config.h" - -#ifdef RALINK_ATE -UCHAR TemplateFrame[24] = {0x08/* Data type */,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0xAA,0xBB,0x12,0x34,0x56,0x00,0x11,0x22,0xAA,0xBB,0xCC,0x00,0x00}; // 802.11 MAC Header, Type:Data, Length:24bytes -extern RTMP_RF_REGS RF2850RegTable[]; -extern UCHAR NUM_OF_2850_CHNL; - -static CHAR CCKRateTable[] = {0, 1, 2, 3, 8, 9, 10, 11, -1}; /* CCK Mode. */ -static CHAR OFDMRateTable[] = {0, 1, 2, 3, 4, 5, 6, 7, -1}; /* OFDM Mode. */ -static CHAR HTMIXRateTable[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, -1}; /* HT Mix Mode. */ - -static INT TxDmaBusy( - IN PRTMP_ADAPTER pAd); - -static INT RxDmaBusy( - IN PRTMP_ADAPTER pAd); - -static VOID RtmpDmaEnable( - IN PRTMP_ADAPTER pAd, - IN INT Enable); - -static VOID BbpSoftReset( - IN PRTMP_ADAPTER pAd); - -static VOID RtmpRfIoWrite( - IN PRTMP_ADAPTER pAd); - -static INT ATESetUpFrame( - IN PRTMP_ADAPTER pAd, - IN UINT32 TxIdx); - -static INT ATETxPwrHandler( - IN PRTMP_ADAPTER pAd, - IN char index); - -static INT ATECmdHandler( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -static int CheckMCSValid( - IN UCHAR Mode, - IN UCHAR Mcs); - -static VOID ATEWriteTxWI( - IN PRTMP_ADAPTER pAd, - IN PTXWI_STRUC pOutTxWI, - IN BOOLEAN FRAG, - IN BOOLEAN CFACK, - IN BOOLEAN InsTimestamp, - IN BOOLEAN AMPDU, - IN BOOLEAN Ack, - IN BOOLEAN NSeq, // HW new a sequence. - IN UCHAR BASize, - IN UCHAR WCID, - IN ULONG Length, - IN UCHAR PID, - IN UCHAR TID, - IN UCHAR TxRate, - IN UCHAR Txopmode, - IN BOOLEAN CfAck, - IN HTTRANSMIT_SETTING *pTransmit); - - -static VOID SetJapanFilter( - IN PRTMP_ADAPTER pAd); - -/*=========================end of prototype=========================*/ - -static INT TxDmaBusy( - IN PRTMP_ADAPTER pAd) -{ - INT result; - WPDMA_GLO_CFG_STRUC GloCfg; - - RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word); // disable DMA - if (GloCfg.field.TxDMABusy) - result = 1; - else - result = 0; - - return result; -} - -static INT RxDmaBusy( - IN PRTMP_ADAPTER pAd) -{ - INT result; - WPDMA_GLO_CFG_STRUC GloCfg; - - RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word); // disable DMA - if (GloCfg.field.RxDMABusy) - result = 1; - else - result = 0; - - return result; -} - -static VOID RtmpDmaEnable( - IN PRTMP_ADAPTER pAd, - IN INT Enable) -{ - BOOLEAN value; - ULONG WaitCnt; - WPDMA_GLO_CFG_STRUC GloCfg; - - value = Enable > 0 ? 1 : 0; - - // check DMA is in busy mode. - WaitCnt = 0; - while (TxDmaBusy(pAd) || RxDmaBusy(pAd)) - { - RTMPusecDelay(10); - if (WaitCnt++ > 100) - break; - } - - RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word); // disable DMA - GloCfg.field.EnableTxDMA = value; - GloCfg.field.EnableRxDMA = value; - RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, GloCfg.word); // abort all TX rings - RTMPusecDelay(5000); - - return; -} - - -static VOID BbpSoftReset( - IN PRTMP_ADAPTER pAd) -{ - UCHAR BbpData = 0; - - // Soft reset, set BBP R21 bit0=1->0 - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R21, &BbpData); - BbpData |= 0x00000001; //set bit0=1 - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R21, BbpData); - - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R21, &BbpData); - BbpData &= ~(0x00000001); //set bit0=0 - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R21, BbpData); - - return; -} - -static VOID RtmpRfIoWrite( - IN PRTMP_ADAPTER pAd) -{ - // Set RF value 1's set R3[bit2] = [0] - RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R1); - RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R2); - RTMP_RF_IO_WRITE32(pAd, (pAd->LatchRfRegs.R3 & (~0x04))); - RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R4); - - RTMPusecDelay(200); - - // Set RF value 2's set R3[bit2] = [1] - RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R1); - RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R2); - RTMP_RF_IO_WRITE32(pAd, (pAd->LatchRfRegs.R3 | 0x04)); - RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R4); - - RTMPusecDelay(200); - - // Set RF value 3's set R3[bit2] = [0] - RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R1); - RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R2); - RTMP_RF_IO_WRITE32(pAd, (pAd->LatchRfRegs.R3 & (~0x04))); - RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R4); - - return; -} - -static int CheckMCSValid( - UCHAR Mode, - UCHAR Mcs) -{ - int i; - PCHAR pRateTab; - - switch(Mode) - { - case 0: - pRateTab = CCKRateTable; - break; - case 1: - pRateTab = OFDMRateTable; - break; - case 2: - case 3: - pRateTab = HTMIXRateTable; - break; - default: - ATEDBGPRINT(RT_DEBUG_ERROR, ("unrecognizable Tx Mode %d\n", Mode)); - return -1; - break; - } - - i = 0; - while(pRateTab[i] != -1) - { - if (pRateTab[i] == Mcs) - return 0; - i++; - } - - return -1; -} - -#if 1 -static INT ATETxPwrHandler( - IN PRTMP_ADAPTER pAd, - IN char index) -{ - ULONG R; - CHAR TxPower; - UCHAR Bbp94 = 0; - BOOLEAN bPowerReduce = FALSE; - -#ifdef RALINK_28xx_QA - if ((pAd->ate.bQATxStart == TRUE) || (pAd->ate.bQARxStart == TRUE)) - { - /* When QA is used for Tx, pAd->ate.TxPower0/1 and real tx power - ** are not synchronized. - */ -/* - pAd->ate.TxPower0 = pAd->LatchRfRegs.xxx; - pAd->ate.TxPower1 = pAd->LatchRfRegs.xxx; -*/ - return 0; - } - else -#endif // RALINK_28xx_QA // - { - TxPower = index == 0 ? pAd->ate.TxPower0 : pAd->ate.TxPower1; - - if (pAd->ate.Channel <= 14) - { - if (TxPower > 31) - { - // - // R3, R4 can't large than 31 (0x24), 31 ~ 36 used by BBP 94 - // - R = 31; - if (TxPower <= 36) - Bbp94 = BBPR94_DEFAULT + (UCHAR)(TxPower - 31); - } - else if (TxPower < 0) - { - // - // R3, R4 can't less than 0, -1 ~ -6 used by BBP 94 - // - R = 0; - if (TxPower >= -6) - Bbp94 = BBPR94_DEFAULT + TxPower; - } - else - { - // 0 ~ 31 - R = (ULONG) TxPower; - Bbp94 = BBPR94_DEFAULT; - } - - ATEDBGPRINT(RT_DEBUG_TRACE, ("%s (TxPower=%d, R=%ld, BBP_R94=%d)\n", __func__, TxPower, R, Bbp94)); - } - else// 5.5 GHz - { - if (TxPower > 15) - { - // - // R3, R4 can't large than 15 (0x0F) - // - R = 15; - } - else if (TxPower < 0) - { - // - // R3, R4 can't less than 0 - // - // -1 ~ -7 - ASSERT((TxPower >= -7)); - R = (ULONG)(TxPower + 7); - bPowerReduce = TRUE; - } - else - { - // 0 ~ 15 - R = (ULONG) TxPower; - } - - ATEDBGPRINT(RT_DEBUG_TRACE, ("%s (TxPower=%d, R=%lu)\n", __func__, TxPower, R)); - } - - if (pAd->ate.Channel <= 14) - { - if (index == 0) - { - R = R << 9; // shift TX power control to correct RF(R3) register bit position - R |= (pAd->LatchRfRegs.R3 & 0xffffc1ff); - pAd->LatchRfRegs.R3 = R; - } - else - { - R = R << 6; // shift TX power control to correct RF(R4) register bit position - R |= (pAd->LatchRfRegs.R4 & 0xfffff83f); - pAd->LatchRfRegs.R4 = R; - } - } - else// 5.5GHz - { - if (bPowerReduce == FALSE) - { - if (index == 0) - { - R = (R << 10) | (1 << 9); // shift TX power control to correct RF(R3) register bit position - R |= (pAd->LatchRfRegs.R3 & 0xffffc1ff); - pAd->LatchRfRegs.R3 = R; - } - else - { - R = (R << 7) | (1 << 6); // shift TX power control to correct RF(R4) register bit position - R |= (pAd->LatchRfRegs.R4 & 0xfffff83f); - pAd->LatchRfRegs.R4 = R; - } - } - else - { - if (index == 0) - { - R = (R << 10); // shift TX power control to correct RF(R3) register bit position - R |= (pAd->LatchRfRegs.R3 & 0xffffc1ff); - - /* Clear bit 9 of R3 to reduce 7dB. */ - pAd->LatchRfRegs.R3 = (R & (~(1 << 9))); - } - else - { - R = (R << 7); // shift TX power control to correct RF(R4) register bit position - R |= (pAd->LatchRfRegs.R4 & 0xfffff83f); - - /* Clear bit 6 of R4 to reduce 7dB. */ - pAd->LatchRfRegs.R4 = (R & (~(1 << 6))); - } - } - } - - RtmpRfIoWrite(pAd); - - return 0; - } -} -#else// 1 // -static INT ATETxPwrHandler( - IN PRTMP_ADAPTER pAd, - IN char index) -{ - ULONG R; - CHAR TxPower; - UCHAR Bbp94 = 0; - -#ifdef RALINK_28xx_QA - if ((pAd->ate.bQATxStart == TRUE) || (pAd->ate.bQARxStart == TRUE)) - { - // TODO: how to get current TxPower0/1 from pAd->LatchRfRegs ? - /* When QA is used for Tx, pAd->ate.TxPower0/1 and real tx power - ** are not synchronized. - */ -/* - pAd->ate.TxPower0 = pAd->LatchRfRegs.xxx; - pAd->ate.TxPower1 = pAd->LatchRfRegs.xxx; -*/ - return 0; - } - else -#endif // RALINK_28xx_QA // - { - TxPower = index == 0 ? pAd->ate.TxPower0 : pAd->ate.TxPower1; - - if (TxPower > 31) - { - // - // R3, R4 can't large than 36 (0x24), 31 ~ 36 used by BBP 94 - // - R = 31; - if (TxPower <= 36) - Bbp94 = BBPR94_DEFAULT + (UCHAR)(TxPower - 31); - } - else if (TxPower < 0) - { - // - // R3, R4 can't less than 0, -1 ~ -6 used by BBP 94 - // - R = 0; - if (TxPower >= -6) - Bbp94 = BBPR94_DEFAULT + TxPower; - } - else - { - // 0 ~ 31 - R = (ULONG) TxPower; - Bbp94 = BBPR94_DEFAULT; - } - - ATEDBGPRINT(RT_DEBUG_TRACE, ("%s (TxPower=%d, R3=%ld, BBP_R94=%d)\n", __func__, TxPower, R, Bbp94)); - - if (pAd->ate.Channel <= 14) - { - if (index == 0) - { - R = R << 9; // shift TX power control to correct RF(R3) register bit position - R |= (pAd->LatchRfRegs.R3 & 0xffffc1ff); - pAd->LatchRfRegs.R3 = R; - } - else - { - R = R << 6; // shift TX power control to correct RF(R4) register bit position - R |= (pAd->LatchRfRegs.R4 & 0xfffff83f); - pAd->LatchRfRegs.R4 = R; - } - } - else - { - if (index == 0) - { - R = (R << 10) | (1 << 9); // shift TX power control to correct RF(R3) register bit position - R |= (pAd->LatchRfRegs.R3 & 0xffffc1ff); - pAd->LatchRfRegs.R3 = R; - } - else - { - R = (R << 7) | (1 << 6); // shift TX power control to correct RF(R4) register bit position - R |= (pAd->LatchRfRegs.R4 & 0xfffff83f); - pAd->LatchRfRegs.R4 = R; - } - } - - RtmpRfIoWrite(pAd); - - return 0; - } -} -#endif // 1 // -/* - ========================================================================== - Description: - Set ATE operation mode to - 0. ATESTART = Start ATE Mode - 1. ATESTOP = Stop ATE Mode - 2. TXCONT = Continuous Transmit - 3. TXCARR = Transmit Carrier - 4. TXFRAME = Transmit Frames - 5. RXFRAME = Receive Frames -#ifdef RALINK_28xx_QA - 6. TXSTOP = Stop Any Type of Transmition - 7. RXSTOP = Stop Receiving Frames -#endif // RALINK_28xx_QA // - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -static INT ATECmdHandler( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - UINT32 Value = 0; - UCHAR BbpData; - UINT32 MacData = 0; - PTXD_STRUC pTxD; - INT index; - UINT i=0, atemode; - PRXD_STRUC pRxD; - PRTMP_TX_RING pTxRing = &pAd->TxRing[QID_AC_BE]; -#ifndef UCOS - NDIS_STATUS Status = NDIS_STATUS_SUCCESS; -#endif // UCOS // -#ifdef RT_BIG_ENDIAN - PTXD_STRUC pDestTxD; - TXD_STRUC TxD; -#endif - ATEDBGPRINT(RT_DEBUG_TRACE, ("===> ATECmdHandler()\n")); - - ATEAsicSwitchChannel(pAd); - AsicLockChannel(pAd, pAd->ate.Channel); - - RTMPusecDelay(5000); - - // read MAC_SYS_CTRL and backup MAC_SYS_CTRL value. - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &MacData); - - // Default value in BBP R22 is 0x0. - BbpData = 0; - - // clean bit4 to stop continuous Tx production test. - MacData &= 0xFFFFFFEF; - - if (!strcmp(arg, "ATESTART")) //Enter ATE mode and set Tx/Rx Idle - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE: ATESTART\n")); - -#ifndef UCOS - // check if we have removed the firmware - if (!(ATE_ON(pAd))) - { - NICEraseFirmware(pAd); - } -#endif // !UCOS // - atemode = pAd->ate.Mode; - pAd->ate.Mode = ATE_START; -// pAd->ate.TxDoneCount = pAd->ate.TxCount; - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, MacData); - - if (atemode & ATE_TXCARR) - { - // No Carrier Test set BBP R22 bit7=0, bit6=0, bit[5~0]=0x0 - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R22, &BbpData); - BbpData &= 0xFFFFFF00; //clear bit7, bit6, bit[5~0] - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); - } - else if (atemode & ATE_TXCARRSUPP) - { - // No Cont. TX set BBP R22 bit7=0 - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R22, &BbpData); - BbpData &= ~(1 << 7); //set bit7=0 - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); - - // No Carrier Suppression set BBP R24 bit0=0 - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R24, &BbpData); - BbpData &= 0xFFFFFFFE; //clear bit0 - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R24, BbpData); - } - // We should free some resource which was allocated when ATE_TXFRAME , ATE_STOP, and ATE_TXCONT. - else if ((atemode & ATE_TXFRAME) || (atemode == ATE_STOP)) - { - PRTMP_TX_RING pTxRing = &pAd->TxRing[QID_AC_BE]; - - if (atemode & ATE_TXCONT) - { - // No Cont. TX set BBP R22 bit7=0 - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R22, &BbpData); - BbpData &= ~(1 << 7); //set bit7=0 - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); - } - // Abort Tx, Rx DMA. - RtmpDmaEnable(pAd, 0); - for (i=0; iTxRing[QID_AC_BE].Cell[i].AllocVa; -#else - pDestTxD = (PTXD_STRUC)pAd->TxRing[QID_AC_BE].Cell[i].AllocVa; - TxD = *pDestTxD; - pTxD = &TxD; - RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); -#endif - pTxD->DMADONE = 0; - pPacket = pTxRing->Cell[i].pNdisPacket; - if (pPacket) - { - PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr0, pTxD->SDLen0, PCI_DMA_TODEVICE); - RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_SUCCESS); - } - //Always assign pNdisPacket as NULL after clear - pTxRing->Cell[i].pNdisPacket = NULL; - - pPacket = pTxRing->Cell[i].pNextNdisPacket; - if (pPacket) - { - PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr1, pTxD->SDLen1, PCI_DMA_TODEVICE); - RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_SUCCESS); - } - //Always assign pNextNdisPacket as NULL after clear - pTxRing->Cell[i].pNextNdisPacket = NULL; -#ifdef RT_BIG_ENDIAN - RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); - WriteBackToDescriptor((PUCHAR)pDestTxD, (PUCHAR)pTxD, FALSE, TYPE_TXD); -#endif - } - // Start Tx, RX DMA - RtmpDmaEnable(pAd, 1); - } - // reset Rx statistics. - pAd->ate.LastSNR0 = 0; - pAd->ate.LastSNR1 = 0; - pAd->ate.LastRssi0 = 0; - pAd->ate.LastRssi1 = 0; - pAd->ate.LastRssi2 = 0; - pAd->ate.AvgRssi0 = 0; - pAd->ate.AvgRssi1 = 0; - pAd->ate.AvgRssi2 = 0; - pAd->ate.AvgRssi0X8 = 0; - pAd->ate.AvgRssi1X8 = 0; - pAd->ate.AvgRssi2X8 = 0; - pAd->ate.NumOfAvgRssiSample = 0; - -#ifdef RALINK_28xx_QA - // Tx frame - pAd->ate.bQATxStart = FALSE; - pAd->ate.bQARxStart = FALSE; - pAd->ate.seq = 0; - - // counters - pAd->ate.U2M = 0; - pAd->ate.OtherData = 0; - pAd->ate.Beacon = 0; - pAd->ate.OtherCount = 0; - pAd->ate.TxAc0 = 0; - pAd->ate.TxAc1 = 0; - pAd->ate.TxAc2 = 0; - pAd->ate.TxAc3 = 0; - pAd->ate.TxHCCA = 0; - pAd->ate.TxMgmt = 0; - pAd->ate.RSSI0 = 0; - pAd->ate.RSSI1 = 0; - pAd->ate.RSSI2 = 0; - pAd->ate.SNR0 = 0; - pAd->ate.SNR1 = 0; - - // control - pAd->ate.TxDoneCount = 0; - pAd->ate.TxStatus = 0; // task Tx status // 0 --> task is idle, 1 --> task is running -#endif // RALINK_28xx_QA // - - // Soft reset BBP. - BbpSoftReset(pAd); - - -#ifdef CONFIG_STA_SUPPORT - // - // LinkDown() has "AsicDisableSync();" and "RTMP_BBP_IO_R/W8_BY_REG_ID();" inside. - // -// LinkDown(pAd, FALSE); -// AsicEnableBssSync(pAd); -#ifndef UCOS - netif_stop_queue(pAd->net_dev); -#endif // !UCOS // - // - // If we skip "LinkDown()", we should disable protection - // to prevent from sending out RTS or CTS-to-self. - // - ATEDisableAsicProtect(pAd); - RTMPStationStop(pAd); -#endif // CONFIG_STA_SUPPORT // - - /* Disable Tx */ - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value &= ~(1 << 2); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - - /* Disable Rx */ - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value &= ~(1 << 3); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - } - else if (!strcmp(arg, "ATESTOP")) - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE: ATESTOP\n")); - - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, MacData); // recover the MAC_SYS_CTRL register back. - - // Disable Tx, Rx - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value &= (0xfffffff3); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - - // Abort Tx, RX DMA. - RtmpDmaEnable(pAd, 0); - -#ifndef UCOS - pAd->ate.bFWLoading = TRUE; - Status = NICLoadFirmware(pAd); - if (Status != NDIS_STATUS_SUCCESS) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("NICLoadFirmware failed, Status[=0x%08x]\n", Status)); - return FALSE; - } -#endif // !UCOS // - pAd->ate.Mode = ATE_STOP; - - -#ifdef CONFIG_STA_SUPPORT - // - // Even the firmware has been loaded, - // we still could use ATE_BBP_IO_READ8_BY_REG_ID(). - // But this is not suggested. - // - BbpSoftReset(pAd); -#endif // CONFIG_STA_SUPPORT // - - NICDisableInterrupt(pAd); - - NICInitializeAdapter(pAd, TRUE); - - - // Reinitialize Rx Ring before Rx DMA is enabled. - // The nightmare of >>>RxCoherent<<< was gone ! - for (index = 0; index < RX_RING_SIZE; index++) - { - pRxD = (PRXD_STRUC) pAd->RxRing.Cell[index].AllocVa; - pRxD->DDONE = 0; - } - - // We should read EEPROM for all cases. - NICReadEEPROMParameters(pAd, NULL); - NICInitAsicFromEEPROM(pAd); - - AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); - AsicLockChannel(pAd, pAd->CommonCfg.Channel); - - // - // Enable Interrupt - // - - // - // These steps are only for APAutoSelectChannel(). - // -#if 0 - //pAd->bStaFifoTest = TRUE; - pAd->int_enable_reg = ((DELAYINTMASK) | (RxINT|TxDataInt|TxMgmtInt)) & ~(0x03); - pAd->int_disable_mask = 0; - pAd->int_pending = 0; -#endif - RTMP_IO_WRITE32(pAd, INT_SOURCE_CSR, 0xffffffff); // clear garbage interrupts - NICEnableInterrupt(pAd); - - -/*=========================================================================*/ - /* restore RX_FILTR_CFG */ -#ifdef CONFIG_STA_SUPPORT - /* restore RX_FILTR_CFG due to that QA maybe set it to 0x3 */ - RTMP_IO_WRITE32(pAd, RX_FILTR_CFG, STANORMAL); -#endif // CONFIG_STA_SUPPORT // -/*=========================================================================*/ - - // Enable Tx - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value |= (1 << 2); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - - // Enable Tx, Rx DMA. - RtmpDmaEnable(pAd, 1); - - // Enable Rx - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value |= (1 << 3); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - - -#ifdef CONFIG_STA_SUPPORT - RTMPStationStart(pAd); -#endif // CONFIG_STA_SUPPORT // -#ifndef UCOS - netif_start_queue(pAd->net_dev); -#endif // !UCOS // - } - else if (!strcmp(arg, "TXCARR")) // Tx Carrier - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE: TXCARR\n")); - pAd->ate.Mode |= ATE_TXCARR; - - // QA has done the following steps if it is used. - if (pAd->ate.bQATxStart == FALSE) - { - // Soft reset BBP. - BbpSoftReset(pAd); - - // Carrier Test set BBP R22 bit7=1, bit6=1, bit[5~0]=0x01 - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R22, &BbpData); - BbpData &= 0xFFFFFF00; //clear bit7, bit6, bit[5~0] - BbpData |= 0x000000C1; //set bit7=1, bit6=1, bit[5~0]=0x01 - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); - - // set MAC_SYS_CTRL(0x1004) Continuous Tx Production Test (bit4) = 1 - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value = Value | 0x00000010; - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - } - } - else if (!strcmp(arg, "TXCONT")) // Tx Continue - { - if (pAd->ate.bQATxStart == TRUE) - { - /* set MAC_SYS_CTRL(0x1004) bit4(Continuous Tx Production Test) - and bit2(MAC TX enable) back to zero. */ - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &MacData); - MacData &= 0xFFFFFFEB; - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, MacData); - - // set BBP R22 bit7=0 - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R22, &BbpData); - BbpData &= 0xFFFFFF7F; //set bit7=0 - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); - } - - /* for TxCont mode. - ** Step 1: Send 50 packets first then wait for a moment. - ** Step 2: Send more 50 packet then start continue mode. - */ - ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE: TXCONT\n")); - // Step 1: send 50 packets first. - pAd->ate.Mode |= ATE_TXCONT; - pAd->ate.TxCount = 50; - /* Do it after Tx/Rx DMA is aborted. */ -// pAd->ate.TxDoneCount = 0; - - // Soft reset BBP. - BbpSoftReset(pAd); - - // Abort Tx, RX DMA. - RtmpDmaEnable(pAd, 0); - - // Fix can't smooth kick - { - RTMP_IO_READ32(pAd, TX_DTX_IDX0 + QID_AC_BE * 0x10, &pTxRing->TxDmaIdx); - pTxRing->TxSwFreeIdx = pTxRing->TxDmaIdx; - pTxRing->TxCpuIdx = pTxRing->TxDmaIdx; - RTMP_IO_WRITE32(pAd, TX_CTX_IDX0 + QID_AC_BE * 0x10, pTxRing->TxCpuIdx); - } - - pAd->ate.TxDoneCount = 0; - - /* Only needed if we have to send some normal frames. */ - SetJapanFilter(pAd); - - for (i = 0; (i < TX_RING_SIZE-1) && (i < pAd->ate.TxCount); i++) - { - PNDIS_PACKET pPacket; - UINT32 TxIdx = pTxRing->TxCpuIdx; - -#ifndef RT_BIG_ENDIAN - pTxD = (PTXD_STRUC)pTxRing->Cell[TxIdx].AllocVa; -#else - pDestTxD = (PTXD_STRUC)pTxRing->Cell[TxIdx].AllocVa; - TxD = *pDestTxD; - pTxD = &TxD; - RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); -#endif - // Clean current cell. - pPacket = pTxRing->Cell[TxIdx].pNdisPacket; - if (pPacket) - { - PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr0, pTxD->SDLen0, PCI_DMA_TODEVICE); - RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_SUCCESS); - } - //Always assign pNdisPacket as NULL after clear - pTxRing->Cell[TxIdx].pNdisPacket = NULL; - - pPacket = pTxRing->Cell[TxIdx].pNextNdisPacket; - if (pPacket) - { - PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr1, pTxD->SDLen1, PCI_DMA_TODEVICE); - RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_SUCCESS); - } - //Always assign pNextNdisPacket as NULL after clear - pTxRing->Cell[TxIdx].pNextNdisPacket = NULL; - -#ifdef RT_BIG_ENDIAN - RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); - WriteBackToDescriptor((PUCHAR)pDestTxD, (PUCHAR)pTxD, FALSE, TYPE_TXD); -#endif - - if (ATESetUpFrame(pAd, TxIdx) != 0) - break; - - INC_RING_INDEX(pTxRing->TxCpuIdx, TX_RING_SIZE); - } - - // Setup frame format. - ATESetUpFrame(pAd, pTxRing->TxCpuIdx); - - // Start Tx, RX DMA. - RtmpDmaEnable(pAd, 1); - - // Enable Tx - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value |= (1 << 2); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - - // Disable Rx - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value &= ~(1 << 3); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - -#ifdef RALINK_28xx_QA - if (pAd->ate.bQATxStart == TRUE) - { - pAd->ate.TxStatus = 1; - //pAd->ate.Repeat = 0; - } -#endif // RALINK_28xx_QA // - - // kick Tx-Ring. - RTMP_IO_WRITE32(pAd, TX_CTX_IDX0 + QID_AC_BE * RINGREG_DIFF, pAd->TxRing[QID_AC_BE].TxCpuIdx); - - RTMPusecDelay(5000); - - - // Step 2: send more 50 packets then start continue mode. - // Abort Tx, RX DMA. - RtmpDmaEnable(pAd, 0); - - // Cont. TX set BBP R22 bit7=1 - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R22, &BbpData); - BbpData |= 0x00000080; //set bit7=1 - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); - - pAd->ate.TxCount = 50; - - // Fix can't smooth kick - { - RTMP_IO_READ32(pAd, TX_DTX_IDX0 + QID_AC_BE * 0x10, &pTxRing->TxDmaIdx); - pTxRing->TxSwFreeIdx = pTxRing->TxDmaIdx; - pTxRing->TxCpuIdx = pTxRing->TxDmaIdx; - RTMP_IO_WRITE32(pAd, TX_CTX_IDX0 + QID_AC_BE * 0x10, pTxRing->TxCpuIdx); - } - - pAd->ate.TxDoneCount = 0; - - SetJapanFilter(pAd); - - for (i = 0; (i < TX_RING_SIZE-1) && (i < pAd->ate.TxCount); i++) - { - PNDIS_PACKET pPacket; - UINT32 TxIdx = pTxRing->TxCpuIdx; - -#ifndef RT_BIG_ENDIAN - pTxD = (PTXD_STRUC)pTxRing->Cell[TxIdx].AllocVa; -#else - pDestTxD = (PTXD_STRUC)pTxRing->Cell[TxIdx].AllocVa; - TxD = *pDestTxD; - pTxD = &TxD; - RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); -#endif - // clean current cell. - pPacket = pTxRing->Cell[TxIdx].pNdisPacket; - if (pPacket) - { - PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr0, pTxD->SDLen0, PCI_DMA_TODEVICE); - RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_SUCCESS); - } - //Always assign pNdisPacket as NULL after clear - pTxRing->Cell[TxIdx].pNdisPacket = NULL; - - pPacket = pTxRing->Cell[TxIdx].pNextNdisPacket; - if (pPacket) - { - PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr1, pTxD->SDLen1, PCI_DMA_TODEVICE); - RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_SUCCESS); - } - //Always assign pNextNdisPacket as NULL after clear - pTxRing->Cell[TxIdx].pNextNdisPacket = NULL; - -#ifdef RT_BIG_ENDIAN - RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); - WriteBackToDescriptor((PUCHAR)pDestTxD, (PUCHAR)pTxD, FALSE, TYPE_TXD); -#endif - - if (ATESetUpFrame(pAd, TxIdx) != 0) - break; - - INC_RING_INDEX(pTxRing->TxCpuIdx, TX_RING_SIZE); - } - - ATESetUpFrame(pAd, pTxRing->TxCpuIdx); - - // Start Tx, RX DMA. - RtmpDmaEnable(pAd, 1); - - // Enable Tx - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value |= (1 << 2); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - - // Disable Rx - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value &= ~(1 << 3); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - -#ifdef RALINK_28xx_QA - if (pAd->ate.bQATxStart == TRUE) - { - pAd->ate.TxStatus = 1; - //pAd->ate.Repeat = 0; - } -#endif // RALINK_28xx_QA // - - // kick Tx-Ring. - RTMP_IO_WRITE32(pAd, TX_CTX_IDX0 + QID_AC_BE * RINGREG_DIFF, pAd->TxRing[QID_AC_BE].TxCpuIdx); - - RTMPusecDelay(500); - - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &MacData); - MacData |= 0x00000010; - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, MacData); - } - else if (!strcmp(arg, "TXFRAME")) // Tx Frames - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE: TXFRAME(Count=%d)\n", pAd->ate.TxCount)); - pAd->ate.Mode |= ATE_TXFRAME; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); - - // Soft reset BBP. - BbpSoftReset(pAd); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, MacData); - - // Abort Tx, RX DMA. - RtmpDmaEnable(pAd, 0); - - // Fix can't smooth kick - { - RTMP_IO_READ32(pAd, TX_DTX_IDX0 + QID_AC_BE * 0x10, &pTxRing->TxDmaIdx); - pTxRing->TxSwFreeIdx = pTxRing->TxDmaIdx; - pTxRing->TxCpuIdx = pTxRing->TxDmaIdx; - RTMP_IO_WRITE32(pAd, TX_CTX_IDX0 + QID_AC_BE * 0x10, pTxRing->TxCpuIdx); - } - - pAd->ate.TxDoneCount = 0; - - SetJapanFilter(pAd); - - for (i = 0; (i < TX_RING_SIZE-1) && (i < pAd->ate.TxCount); i++) - { - PNDIS_PACKET pPacket; - UINT32 TxIdx = pTxRing->TxCpuIdx; - -#ifndef RT_BIG_ENDIAN - pTxD = (PTXD_STRUC)pTxRing->Cell[TxIdx].AllocVa; -#else - pDestTxD = (PTXD_STRUC)pTxRing->Cell[TxIdx].AllocVa; - TxD = *pDestTxD; - pTxD = &TxD; - RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); -#endif - // Clean current cell. - pPacket = pTxRing->Cell[TxIdx].pNdisPacket; - if (pPacket) - { - PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr0, pTxD->SDLen0, PCI_DMA_TODEVICE); - RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_SUCCESS); - } - //Always assign pNdisPacket as NULL after clear - pTxRing->Cell[TxIdx].pNdisPacket = NULL; - - pPacket = pTxRing->Cell[TxIdx].pNextNdisPacket; - if (pPacket) - { - PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr1, pTxD->SDLen1, PCI_DMA_TODEVICE); - RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_SUCCESS); - } - //Always assign pNextNdisPacket as NULL after clear - pTxRing->Cell[TxIdx].pNextNdisPacket = NULL; - -#ifdef RT_BIG_ENDIAN - RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); - WriteBackToDescriptor((PUCHAR)pDestTxD, (PUCHAR)pTxD, FALSE, TYPE_TXD); -#endif - - if (ATESetUpFrame(pAd, TxIdx) != 0) - break; - - INC_RING_INDEX(pTxRing->TxCpuIdx, TX_RING_SIZE); - - } - - ATESetUpFrame(pAd, pTxRing->TxCpuIdx); - - // Start Tx, Rx DMA. - RtmpDmaEnable(pAd, 1); - - // Enable Tx - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value |= (1 << 2); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); -#ifdef RALINK_28xx_QA - // add this for LoopBack mode - if (pAd->ate.bQARxStart == FALSE) - { - // Disable Rx - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value &= ~(1 << 3); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - } - - if (pAd->ate.bQATxStart == TRUE) - { - pAd->ate.TxStatus = 1; - //pAd->ate.Repeat = 0; - } -#else - // Disable Rx - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value &= ~(1 << 3); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); -#endif // RALINK_28xx_QA // - - RTMP_IO_READ32(pAd, TX_DTX_IDX0 + QID_AC_BE * RINGREG_DIFF, &pAd->TxRing[QID_AC_BE].TxDmaIdx); - // kick Tx-Ring. - RTMP_IO_WRITE32(pAd, TX_CTX_IDX0 + QID_AC_BE * RINGREG_DIFF, pAd->TxRing[QID_AC_BE].TxCpuIdx); - - pAd->RalinkCounters.KickTxCount++; - } -#ifdef RALINK_28xx_QA - else if (!strcmp(arg, "TXSTOP")) - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE: TXSTOP\n")); - atemode = pAd->ate.Mode; - pAd->ate.Mode &= ATE_TXSTOP; - pAd->ate.bQATxStart = FALSE; -// pAd->ate.TxDoneCount = pAd->ate.TxCount; - - if (atemode & ATE_TXCARR) - { - // No Carrier Test set BBP R22 bit7=0, bit6=0, bit[5~0]=0x0 - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R22, &BbpData); - BbpData &= 0xFFFFFF00; //clear bit7, bit6, bit[5~0] - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); - } - else if (atemode & ATE_TXCARRSUPP) - { - // No Cont. TX set BBP R22 bit7=0 - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R22, &BbpData); - BbpData &= ~(1 << 7); //set bit7=0 - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); - - // No Carrier Suppression set BBP R24 bit0=0 - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R24, &BbpData); - BbpData &= 0xFFFFFFFE; //clear bit0 - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R24, BbpData); - } - // We should free some resource which allocate when ATE_TXFRAME , ATE_STOP, and ATE_TXCONT. - else if ((atemode & ATE_TXFRAME) || (atemode == ATE_STOP)) - { - - PRTMP_TX_RING pTxRing = &pAd->TxRing[QID_AC_BE]; - - if (atemode & ATE_TXCONT) - { - // No Cont. TX set BBP R22 bit7=0 - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R22, &BbpData); - BbpData &= ~(1 << 7); //set bit7=0 - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); - } - - // Abort Tx, Rx DMA. - RtmpDmaEnable(pAd, 0); - for (i=0; iTxRing[QID_AC_BE].Cell[i].AllocVa; -#else - pDestTxD = (PTXD_STRUC)pAd->TxRing[QID_AC_BE].Cell[i].AllocVa; - TxD = *pDestTxD; - pTxD = &TxD; - RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); -#endif - pTxD->DMADONE = 0; - pPacket = pTxRing->Cell[i].pNdisPacket; - if (pPacket) - { - PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr0, pTxD->SDLen0, PCI_DMA_TODEVICE); - RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_SUCCESS); - } - //Always assign pNdisPacket as NULL after clear - pTxRing->Cell[i].pNdisPacket = NULL; - - pPacket = pTxRing->Cell[i].pNextNdisPacket; - if (pPacket) - { - PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr1, pTxD->SDLen1, PCI_DMA_TODEVICE); - RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_SUCCESS); - } - //Always assign pNextNdisPacket as NULL after clear - pTxRing->Cell[i].pNextNdisPacket = NULL; -#ifdef RT_BIG_ENDIAN - RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); - WriteBackToDescriptor((PUCHAR)pDestTxD, (PUCHAR)pTxD, FALSE, TYPE_TXD); -#endif - } - // Enable Tx, Rx DMA - RtmpDmaEnable(pAd, 1); - - } - - // control -// pAd->ate.TxDoneCount = 0; - pAd->ate.TxStatus = 0; // task Tx status // 0 --> task is idle, 1 --> task is running - - // Soft reset BBP. - BbpSoftReset(pAd); - - // Disable Tx - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value &= ~(1 << 2); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - } - else if (!strcmp(arg, "RXSTOP")) - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE: RXSTOP\n")); - atemode = pAd->ate.Mode; - pAd->ate.Mode &= ATE_RXSTOP; - pAd->ate.bQARxStart = FALSE; -// pAd->ate.TxDoneCount = pAd->ate.TxCount; - - if (atemode & ATE_TXCARR) - { - ; - } - else if (atemode & ATE_TXCARRSUPP) - { - ; - } - - // We should free some resource which was allocated when ATE_TXFRAME , ATE_STOP, and ATE_TXCONT. - else if ((atemode & ATE_TXFRAME) || (atemode == ATE_STOP)) - { - if (atemode & ATE_TXCONT) - { - ; - } - } - - // control -// pAd->ate.TxDoneCount = 0; -// pAd->ate.TxStatus = 0; // task Tx status // 0 --> task is idle, 1 --> task is running - - // Soft reset BBP. - BbpSoftReset(pAd); - - // Disable Rx - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value &= ~(1 << 3); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - } -#endif // RALINK_28xx_QA // - else if (!strcmp(arg, "RXFRAME")) // Rx Frames - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE: RXFRAME\n")); - - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, MacData); - - pAd->ate.Mode |= ATE_RXFRAME; - - // Disable Tx of MAC block. - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value &= ~(1 << 2); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - - // Enable Rx of MAC block. - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value |= (1 << 3); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE: Invalid arg!\n")); - return FALSE; - } - RTMPusecDelay(5000); - - ATEDBGPRINT(RT_DEBUG_TRACE, ("<=== ATECmdHandler()\n")); - - return TRUE; -} -/* */ -/* */ -/*=======================End of RT2860=======================*/ - - -/*======================Start of RT2870======================*/ -/* */ -/* */ - - -INT Set_ATE_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - if (ATECmdHandler(pAd, arg)) - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_Proc Success\n")); - - - return TRUE; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_Proc Failed\n")); - return FALSE; - } -} - -/* - ========================================================================== - Description: - Set ATE ADDR1=DA for TxFrame(AP : To DS = 0 ; From DS = 1) - or - Set ATE ADDR3=DA for TxFrame(STA : To DS = 1 ; From DS = 0) - - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_ATE_DA_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - CHAR *value; - INT i; - - if(strlen(arg) != 17) //Mac address acceptable format 01:02:03:04:05:06 length 17 - return FALSE; - - for (i=0, value = rstrtok(arg, ":"); value; value = rstrtok(NULL, ":")) - { - if((strlen(value) != 2) || (!isxdigit(*value)) || (!isxdigit(*(value+1))) ) - return FALSE; //Invalid - - -#ifdef CONFIG_STA_SUPPORT - AtoH(value, &pAd->ate.Addr3[i++], 1); -#endif // CONFIG_STA_SUPPORT // - } - - if(i != 6) - return FALSE; //Invalid - - -#ifdef CONFIG_STA_SUPPORT - ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_DA_Proc (DA = %2X:%2X:%2X:%2X:%2X:%2X)\n", pAd->ate.Addr3[0], - pAd->ate.Addr3[1], pAd->ate.Addr3[2], pAd->ate.Addr3[3], pAd->ate.Addr3[4], pAd->ate.Addr3[5])); -#endif // CONFIG_STA_SUPPORT // - - ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_DA_Proc Success\n")); - - return TRUE; -} - -/* - ========================================================================== - Description: - Set ATE ADDR3=SA for TxFrame(AP : To DS = 0 ; From DS = 1) - or - Set ATE ADDR2=SA for TxFrame(STA : To DS = 1 ; From DS = 0) - - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_ATE_SA_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - CHAR *value; - INT i; - - if(strlen(arg) != 17) //Mac address acceptable format 01:02:03:04:05:06 length 17 - return FALSE; - - for (i=0, value = rstrtok(arg, ":"); value; value = rstrtok(NULL, ":")) - { - if((strlen(value) != 2) || (!isxdigit(*value)) || (!isxdigit(*(value+1))) ) - return FALSE; //Invalid - - -#ifdef CONFIG_STA_SUPPORT - AtoH(value, &pAd->ate.Addr2[i++], 1); -#endif // CONFIG_STA_SUPPORT // - } - - if(i != 6) - return FALSE; //Invalid - - -#ifdef CONFIG_STA_SUPPORT - ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_SA_Proc (SA = %2X:%2X:%2X:%2X:%2X:%2X)\n", pAd->ate.Addr2[0], - pAd->ate.Addr2[1], pAd->ate.Addr2[2], pAd->ate.Addr2[3], pAd->ate.Addr2[4], pAd->ate.Addr2[5])); -#endif // CONFIG_STA_SUPPORT // - - ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_SA_Proc Success\n")); - - return TRUE; -} - -/* - ========================================================================== - Description: - Set ATE ADDR2=BSSID for TxFrame(AP : To DS = 0 ; From DS = 1) - or - Set ATE ADDR1=BSSID for TxFrame(STA : To DS = 1 ; From DS = 0) - - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_ATE_BSSID_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - CHAR *value; - INT i; - - if(strlen(arg) != 17) //Mac address acceptable format 01:02:03:04:05:06 length 17 - return FALSE; - - for (i=0, value = rstrtok(arg, ":"); value; value = rstrtok(NULL, ":")) - { - if((strlen(value) != 2) || (!isxdigit(*value)) || (!isxdigit(*(value+1))) ) - return FALSE; //Invalid - - -#ifdef CONFIG_STA_SUPPORT - AtoH(value, &pAd->ate.Addr1[i++], 1); -#endif // CONFIG_STA_SUPPORT // - } - - if(i != 6) - return FALSE; //Invalid - - -#ifdef CONFIG_STA_SUPPORT - ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_BSSID_Proc (BSSID = %2X:%2X:%2X:%2X:%2X:%2X)\n", pAd->ate.Addr1[0], - pAd->ate.Addr1[1], pAd->ate.Addr1[2], pAd->ate.Addr1[3], pAd->ate.Addr1[4], pAd->ate.Addr1[5])); -#endif // CONFIG_STA_SUPPORT // - - ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_BSSID_Proc Success\n")); - - return TRUE; -} - -/* - ========================================================================== - Description: - Set ATE Tx Channel - - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_ATE_CHANNEL_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - UCHAR channel; - - channel = simple_strtol(arg, 0, 10); - - if ((channel < 1) || (channel > 216))// to allow A band channel : ((channel < 1) || (channel > 14)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_CHANNEL_Proc::Out of range, it should be in range of 1~14.\n")); - return FALSE; - } - pAd->ate.Channel = channel; - - ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_CHANNEL_Proc (ATE Channel = %d)\n", pAd->ate.Channel)); - ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_CHANNEL_Proc Success\n")); - - - return TRUE; -} - -/* - ========================================================================== - Description: - Set ATE Tx Power0 - - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_ATE_TX_POWER0_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - CHAR TxPower; - - TxPower = simple_strtol(arg, 0, 10); - - if (pAd->ate.Channel <= 14) - { - if ((TxPower > 31) || (TxPower < 0)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_POWER0_Proc::Out of range (Value=%d)\n", TxPower)); - return FALSE; - } - } - else// 5.5GHz - { - if ((TxPower > 15) || (TxPower < -7)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_POWER0_Proc::Out of range (Value=%d)\n", TxPower)); - return FALSE; - } - } - - pAd->ate.TxPower0 = TxPower; - ATETxPwrHandler(pAd, 0); - ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_POWER0_Proc Success\n")); - - - return TRUE; -} - -/* - ========================================================================== - Description: - Set ATE Tx Power1 - - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_ATE_TX_POWER1_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - CHAR TxPower; - - TxPower = simple_strtol(arg, 0, 10); - - if (pAd->ate.Channel <= 14) - { - if ((TxPower > 31) || (TxPower < 0)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_POWER1_Proc::Out of range (Value=%d)\n", TxPower)); - return FALSE; - } - } - else - { - if ((TxPower > 15) || (TxPower < -7)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_POWER1_Proc::Out of range (Value=%d)\n", TxPower)); - return FALSE; - } - } - - pAd->ate.TxPower1 = TxPower; - ATETxPwrHandler(pAd, 1); - ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_POWER1_Proc Success\n")); - - - return TRUE; -} - -/* - ========================================================================== - Description: - Set ATE Tx Antenna - - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_ATE_TX_Antenna_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - CHAR value; - - value = simple_strtol(arg, 0, 10); - - if ((value > 2) || (value < 0)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_Antenna_Proc::Out of range (Value=%d)\n", value)); - return FALSE; - } - - pAd->ate.TxAntennaSel = value; - - ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_TX_Antenna_Proc (Antenna = %d)\n", pAd->ate.TxAntennaSel)); - ATEDBGPRINT(RT_DEBUG_TRACE,("Ralink: Set_ATE_TX_Antenna_Proc Success\n")); - - - return TRUE; -} - -/* - ========================================================================== - Description: - Set ATE Rx Antenna - - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_ATE_RX_Antenna_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - CHAR value; - - value = simple_strtol(arg, 0, 10); - - if ((value > 3) || (value < 0)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_RX_Antenna_Proc::Out of range (Value=%d)\n", value)); - return FALSE; - } - - pAd->ate.RxAntennaSel = value; - - ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_RX_Antenna_Proc (Antenna = %d)\n", pAd->ate.RxAntennaSel)); - ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_RX_Antenna_Proc Success\n")); - - - return TRUE; -} - -/* - ========================================================================== - Description: - Set ATE RF frequence offset - - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_ATE_TX_FREQOFFSET_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - UCHAR RFFreqOffset; - ULONG R4; - - RFFreqOffset = simple_strtol(arg, 0, 10); - - if(RFFreqOffset >= 64) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_FREQOFFSET_Proc::Out of range, it should be in range of 0~63.\n")); - return FALSE; - } - - pAd->ate.RFFreqOffset = RFFreqOffset; - R4 = pAd->ate.RFFreqOffset << 15; // shift TX power control to correct RF register bit position - R4 |= (pAd->LatchRfRegs.R4 & ((~0x001f8000))); - pAd->LatchRfRegs.R4 = R4; - - RtmpRfIoWrite(pAd); - - ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_TX_FREQOFFSET_Proc (RFFreqOffset = %d)\n", pAd->ate.RFFreqOffset)); - ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_FREQOFFSET_Proc Success\n")); - - - return TRUE; -} - -/* - ========================================================================== - Description: - Set ATE RF BW - - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_ATE_TX_BW_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - int i; - UCHAR value = 0; - UCHAR BBPCurrentBW; - - BBPCurrentBW = simple_strtol(arg, 0, 10); - - if(BBPCurrentBW == 0) - pAd->ate.TxWI.BW = BW_20; - else - pAd->ate.TxWI.BW = BW_40; - - if(pAd->ate.TxWI.BW == BW_20) - { - if(pAd->ate.Channel <= 14) - { - for (i=0; i<5; i++) - { - if (pAd->Tx20MPwrCfgGBand[i] != 0xffffffff) - { - RTMP_IO_WRITE32(pAd, TX_PWR_CFG_0 + i*4, pAd->Tx20MPwrCfgGBand[i]); - RTMPusecDelay(5000); - } - } - } - else - { - for (i=0; i<5; i++) - { - if (pAd->Tx20MPwrCfgABand[i] != 0xffffffff) - { - RTMP_IO_WRITE32(pAd, TX_PWR_CFG_0 + i*4, pAd->Tx20MPwrCfgABand[i]); - RTMPusecDelay(5000); - } - } - } - - //Set BBP R4 bit[4:3]=0:0 - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &value); - value &= (~0x18); - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, value); - - //Set BBP R66=0x3C - value = 0x3C; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, value); - //Set BBP R68=0x0B - //to improve Rx sensitivity. - value = 0x0B; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R68, value); - //Set BBP R69=0x16 - value = 0x16; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, value); - //Set BBP R70=0x08 - value = 0x08; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, value); - //Set BBP R73=0x11 - value = 0x11; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R73, value); - - // If Channel=14, Bandwidth=20M and Mode=CCK, Set BBP R4 bit5=1 - // (Japan filter coefficients) - // This segment of code will only works when ATETXMODE and ATECHANNEL - // were set to MODE_CCK and 14 respectively before ATETXBW is set to 0. - //===================================================================== - if (pAd->ate.Channel == 14) - { - int TxMode = pAd->ate.TxWI.PHYMODE; - if (TxMode == MODE_CCK) - { - // when Channel==14 && Mode==CCK && BandWidth==20M, BBP R4 bit5=1 - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &value); - value |= 0x20; //set bit5=1 - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, value); - } - } - - //===================================================================== - // If bandwidth != 40M, RF Reg4 bit 21 = 0. - pAd->LatchRfRegs.R4 &= ~0x00200000; - RtmpRfIoWrite(pAd); - } - else if(pAd->ate.TxWI.BW == BW_40) - { - if(pAd->ate.Channel <= 14) - { - for (i=0; i<5; i++) - { - if (pAd->Tx40MPwrCfgGBand[i] != 0xffffffff) - { - RTMP_IO_WRITE32(pAd, TX_PWR_CFG_0 + i*4, pAd->Tx40MPwrCfgGBand[i]); - RTMPusecDelay(5000); - } - } - } - else - { - for (i=0; i<5; i++) - { - if (pAd->Tx40MPwrCfgABand[i] != 0xffffffff) - { - RTMP_IO_WRITE32(pAd, TX_PWR_CFG_0 + i*4, pAd->Tx40MPwrCfgABand[i]); - RTMPusecDelay(5000); - } - } -#ifdef DOT11_N_SUPPORT - if ((pAd->ate.TxWI.PHYMODE >= MODE_HTMIX) && (pAd->ate.TxWI.MCS == 7)) - { - value = 0x28; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R67, value); - } -#endif // DOT11_N_SUPPORT // - } - - //Set BBP R4 bit[4:3]=1:0 - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &value); - value &= (~0x18); - value |= 0x10; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, value); - - //Set BBP R66=0x3C - value = 0x3C; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, value); - //Set BBP R68=0x0C - //to improve Rx sensitivity. - value = 0x0C; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R68, value); - //Set BBP R69=0x1A - value = 0x1A; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, value); - //Set BBP R70=0x0A - value = 0x0A; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, value); - //Set BBP R73=0x16 - value = 0x16; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R73, value); - - // If bandwidth = 40M, set RF Reg4 bit 21 = 1. - pAd->LatchRfRegs.R4 |= 0x00200000; - RtmpRfIoWrite(pAd); - } - - ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_TX_BW_Proc (BBPCurrentBW = %d)\n", pAd->ate.TxWI.BW)); - ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_BW_Proc Success\n")); - - - return TRUE; -} - -/* - ========================================================================== - Description: - Set ATE Tx frame length - - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_ATE_TX_LENGTH_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - pAd->ate.TxLength = simple_strtol(arg, 0, 10); - - if((pAd->ate.TxLength < 24) || (pAd->ate.TxLength > (MAX_FRAME_SIZE - 34/* == 2312 */))) - { - pAd->ate.TxLength = (MAX_FRAME_SIZE - 34/* == 2312 */); - ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_LENGTH_Proc::Out of range, it should be in range of 24~%d.\n", (MAX_FRAME_SIZE - 34/* == 2312 */))); - return FALSE; - } - - ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_TX_LENGTH_Proc (TxLength = %d)\n", pAd->ate.TxLength)); - ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_LENGTH_Proc Success\n")); - - - return TRUE; -} - -/* - ========================================================================== - Description: - Set ATE Tx frame count - - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_ATE_TX_COUNT_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - pAd->ate.TxCount = simple_strtol(arg, 0, 10); - - ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_TX_COUNT_Proc (TxCount = %d)\n", pAd->ate.TxCount)); - ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_COUNT_Proc Success\n")); - - - return TRUE; -} - -/* - ========================================================================== - Description: - Set ATE Tx frame MCS - - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_ATE_TX_MCS_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - UCHAR MCS; - int result; - - MCS = simple_strtol(arg, 0, 10); - result = CheckMCSValid(pAd->ate.TxWI.PHYMODE, MCS); - - if (result != -1) - { - pAd->ate.TxWI.MCS = (UCHAR)MCS; - } - else - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_MCS_Proc::Out of range, refer to rate table.\n")); - return FALSE; - } - - ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_TX_MCS_Proc (MCS = %d)\n", pAd->ate.TxWI.MCS)); - ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_MCS_Proc Success\n")); - - - return TRUE; -} - -/* - ========================================================================== - Description: - Set ATE Tx frame Mode - 0: MODE_CCK - 1: MODE_OFDM - 2: MODE_HTMIX - 3: MODE_HTGREENFIELD - - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_ATE_TX_MODE_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - pAd->ate.TxWI.PHYMODE = simple_strtol(arg, 0, 10); - - if(pAd->ate.TxWI.PHYMODE > 3) - { - pAd->ate.TxWI.PHYMODE = 0; - ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_MODE_Proc::Out of range. it should be in range of 0~3\n")); - ATEDBGPRINT(RT_DEBUG_ERROR, ("0: CCK, 1: OFDM, 2: HT_MIX, 3: HT_GREEN_FIELD.\n")); - return FALSE; - } - - ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_TX_MODE_Proc (TxMode = %d)\n", pAd->ate.TxWI.PHYMODE)); - ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_MODE_Proc Success\n")); - - - return TRUE; -} - -/* - ========================================================================== - Description: - Set ATE Tx frame GI - - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_ATE_TX_GI_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - pAd->ate.TxWI.ShortGI = simple_strtol(arg, 0, 10); - - if(pAd->ate.TxWI.ShortGI > 1) - { - pAd->ate.TxWI.ShortGI = 0; - ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_GI_Proc::Out of range\n")); - return FALSE; - } - - ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_TX_GI_Proc (GI = %d)\n", pAd->ate.TxWI.ShortGI)); - ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_GI_Proc Success\n")); - - - return TRUE; -} - -/* - ========================================================================== - Description: - ========================================================================== - */ -INT Set_ATE_RX_FER_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - pAd->ate.bRxFer = simple_strtol(arg, 0, 10); - - if (pAd->ate.bRxFer == 1) - { - pAd->ate.RxCntPerSec = 0; - pAd->ate.RxTotalCnt = 0; - } - - ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_RX_FER_Proc (bRxFer = %d)\n", pAd->ate.bRxFer)); - ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_RX_FER_Proc Success\n")); - - - return TRUE; -} - -INT Set_ATE_Read_RF_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ate_print(KERN_EMERG "R1 = %lx\n", pAd->LatchRfRegs.R1); - ate_print(KERN_EMERG "R2 = %lx\n", pAd->LatchRfRegs.R2); - ate_print(KERN_EMERG "R3 = %lx\n", pAd->LatchRfRegs.R3); - ate_print(KERN_EMERG "R4 = %lx\n", pAd->LatchRfRegs.R4); - - return TRUE; -} - -INT Set_ATE_Write_RF1_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - UINT32 value = simple_strtol(arg, 0, 16); - - pAd->LatchRfRegs.R1 = value; - RtmpRfIoWrite(pAd); - - return TRUE; -} - -INT Set_ATE_Write_RF2_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - UINT32 value = simple_strtol(arg, 0, 16); - - pAd->LatchRfRegs.R2 = value; - RtmpRfIoWrite(pAd); - - return TRUE; -} - -INT Set_ATE_Write_RF3_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - UINT32 value = simple_strtol(arg, 0, 16); - - pAd->LatchRfRegs.R3 = value; - RtmpRfIoWrite(pAd); - - return TRUE; -} - -INT Set_ATE_Write_RF4_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - UINT32 value = simple_strtol(arg, 0, 16); - - pAd->LatchRfRegs.R4 = value; - RtmpRfIoWrite(pAd); - - return TRUE; -} - -/* - ========================================================================== - Description: - Load and Write EEPROM from a binary file prepared in advance. - - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -#ifndef UCOS -INT Set_ATE_Load_E2P_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - BOOLEAN ret = FALSE; - PUCHAR src = EEPROM_BIN_FILE_NAME; - struct file *srcf; - INT32 retval, orgfsuid, orgfsgid; - mm_segment_t orgfs; - USHORT WriteEEPROM[(EEPROM_SIZE/2)]; - UINT32 FileLength = 0; - UINT32 value = simple_strtol(arg, 0, 10); - - ATEDBGPRINT(RT_DEBUG_ERROR, ("===> %s (value=%d)\n\n", __func__, value)); - - if (value > 0) - { - /* zero the e2p buffer */ - NdisZeroMemory((PUCHAR)WriteEEPROM, EEPROM_SIZE); - - /* save uid and gid used for filesystem access. - ** set user and group to 0 (root) - */ - orgfsuid = current->fsuid; - orgfsgid = current->fsgid; - /* as root */ - current->fsuid = current->fsgid = 0; - orgfs = get_fs(); - set_fs(KERNEL_DS); - - do - { - /* open the bin file */ - srcf = filp_open(src, O_RDONLY, 0); - - if (IS_ERR(srcf)) - { - ate_print("%s - Error %ld opening %s\n", __func__, -PTR_ERR(srcf), src); - break; - } - - /* the object must have a read method */ - if ((srcf->f_op == NULL) || (srcf->f_op->read == NULL)) - { - ate_print("%s - %s does not have a read method\n", __func__, src); - break; - } - - /* read the firmware from the file *.bin */ - FileLength = srcf->f_op->read(srcf, - (PUCHAR)WriteEEPROM, - EEPROM_SIZE, - &srcf->f_pos); - - if (FileLength != EEPROM_SIZE) - { - ate_print("%s: error file length (=%d) in e2p.bin\n", - __func__, FileLength); - break; - } - else - { - /* write the content of .bin file to EEPROM */ - rt_ee_write_all(pAd, WriteEEPROM); - ret = TRUE; - } - break; - } while(TRUE); - - /* close firmware file */ - if (IS_ERR(srcf)) - { - ; - } - else - { - retval = filp_close(srcf, NULL); - if (retval) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("--> Error %d closing %s\n", -retval, src)); - - } - } - - /* restore */ - set_fs(orgfs); - current->fsuid = orgfsuid; - current->fsgid = orgfsgid; - } - ATEDBGPRINT(RT_DEBUG_ERROR, ("<=== %s (ret=%d)\n", __func__, ret)); - - return ret; - -} -#else -INT Set_ATE_Load_E2P_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - USHORT WriteEEPROM[(EEPROM_SIZE/2)]; - struct iwreq *wrq = (struct iwreq *)arg; - - ATEDBGPRINT(RT_DEBUG_TRACE, ("===> %s (wrq->u.data.length = %d)\n\n", __func__, wrq->u.data.length)); - - if (wrq->u.data.length != EEPROM_SIZE) - { - ate_print("%s: error length (=%d) from host\n", - __func__, wrq->u.data.length); - return FALSE; - } - else/* (wrq->u.data.length == EEPROM_SIZE) */ - { - /* zero the e2p buffer */ - NdisZeroMemory((PUCHAR)WriteEEPROM, EEPROM_SIZE); - - /* fill the local buffer */ - NdisMoveMemory((PUCHAR)WriteEEPROM, wrq->u.data.pointer, wrq->u.data.length); - - do - { - /* write the content of .bin file to EEPROM */ - rt_ee_write_all(pAd, WriteEEPROM); - - } while(FALSE); - } - - ATEDBGPRINT(RT_DEBUG_TRACE, ("<=== %s\n", __func__)); - - return TRUE; - -} -#endif // !UCOS // - -INT Set_ATE_Read_E2P_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - USHORT buffer[EEPROM_SIZE/2]; - USHORT *p; - int i; - - rt_ee_read_all(pAd, (USHORT *)buffer); - p = buffer; - for (i = 0; i < (EEPROM_SIZE/2); i++) - { - ate_print("%4.4x ", *p); - if (((i+1) % 16) == 0) - ate_print("\n"); - p++; - } - return TRUE; -} - -INT Set_ATE_Show_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ate_print("Mode=%d\n", pAd->ate.Mode); - ate_print("TxPower0=%d\n", pAd->ate.TxPower0); - ate_print("TxPower1=%d\n", pAd->ate.TxPower1); - ate_print("TxAntennaSel=%d\n", pAd->ate.TxAntennaSel); - ate_print("RxAntennaSel=%d\n", pAd->ate.RxAntennaSel); - ate_print("BBPCurrentBW=%d\n", pAd->ate.TxWI.BW); - ate_print("GI=%d\n", pAd->ate.TxWI.ShortGI); - ate_print("MCS=%d\n", pAd->ate.TxWI.MCS); - ate_print("TxMode=%d\n", pAd->ate.TxWI.PHYMODE); - ate_print("Addr1=%02x:%02x:%02x:%02x:%02x:%02x\n", - pAd->ate.Addr1[0], pAd->ate.Addr1[1], pAd->ate.Addr1[2], pAd->ate.Addr1[3], pAd->ate.Addr1[4], pAd->ate.Addr1[5]); - ate_print("Addr2=%02x:%02x:%02x:%02x:%02x:%02x\n", - pAd->ate.Addr2[0], pAd->ate.Addr2[1], pAd->ate.Addr2[2], pAd->ate.Addr2[3], pAd->ate.Addr2[4], pAd->ate.Addr2[5]); - ate_print("Addr3=%02x:%02x:%02x:%02x:%02x:%02x\n", - pAd->ate.Addr3[0], pAd->ate.Addr3[1], pAd->ate.Addr3[2], pAd->ate.Addr3[3], pAd->ate.Addr3[4], pAd->ate.Addr3[5]); - ate_print("Channel=%d\n", pAd->ate.Channel); - ate_print("TxLength=%d\n", pAd->ate.TxLength); - ate_print("TxCount=%u\n", pAd->ate.TxCount); - ate_print("RFFreqOffset=%d\n", pAd->ate.RFFreqOffset); - ate_print(KERN_EMERG "Set_ATE_Show_Proc Success\n"); - return TRUE; -} - -INT Set_ATE_Help_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ate_print("ATE=ATESTART, ATESTOP, TXCONT, TXCARR, TXFRAME, RXFRAME\n"); - ate_print("ATEDA\n"); - ate_print("ATESA\n"); - ate_print("ATEBSSID\n"); - ate_print("ATECHANNEL, range:0~14(unless A band !)\n"); - ate_print("ATETXPOW0, set power level of antenna 1.\n"); - ate_print("ATETXPOW1, set power level of antenna 2.\n"); - ate_print("ATETXANT, set TX antenna. 0:all, 1:antenna one, 2:antenna two.\n"); - ate_print("ATERXANT, set RX antenna.0:all, 1:antenna one, 2:antenna two, 3:antenna three.\n"); - ate_print("ATETXFREQOFFSET, set frequency offset, range 0~63\n"); - ate_print("ATETXBW, set BandWidth, 0:20MHz, 1:40MHz.\n"); - ate_print("ATETXLEN, set Frame length, range 24~%d\n", (MAX_FRAME_SIZE - 34/* == 2312 */)); - ate_print("ATETXCNT, set how many frame going to transmit.\n"); - ate_print("ATETXMCS, set MCS, reference to rate table.\n"); - ate_print("ATETXMODE, set Mode 0:CCK, 1:OFDM, 2:HT-Mix, 3:GreenField, reference to rate table.\n"); - ate_print("ATETXGI, set GI interval, 0:Long, 1:Short\n"); - ate_print("ATERXFER, 0:disable Rx Frame error rate. 1:enable Rx Frame error rate.\n"); - ate_print("ATERRF, show all RF registers.\n"); - ate_print("ATEWRF1, set RF1 register.\n"); - ate_print("ATEWRF2, set RF2 register.\n"); - ate_print("ATEWRF3, set RF3 register.\n"); - ate_print("ATEWRF4, set RF4 register.\n"); - ate_print("ATELDE2P, load EEPROM from .bin file.\n"); - ate_print("ATERE2P, display all EEPROM content.\n"); - ate_print("ATESHOW, display all parameters of ATE.\n"); - ate_print("ATEHELP, online help.\n"); - - return TRUE; -} - -/* - ========================================================================== - Description: - - AsicSwitchChannel() dedicated for ATE. - - ========================================================================== -*/ -VOID ATEAsicSwitchChannel( - IN PRTMP_ADAPTER pAd) -{ - UINT32 R2 = 0, R3 = DEFAULT_RF_TX_POWER, R4 = 0, Value = 0; - CHAR TxPwer = 0, TxPwer2 = 0; - UCHAR index, BbpValue = 0, R66 = 0x30; - RTMP_RF_REGS *RFRegTable; - UCHAR Channel; - -#ifdef RALINK_28xx_QA - if ((pAd->ate.bQATxStart == TRUE) || (pAd->ate.bQARxStart == TRUE)) - { - if (pAd->ate.Channel != pAd->LatchRfRegs.Channel) - { - pAd->ate.Channel = pAd->LatchRfRegs.Channel; - } - return; - } - else -#endif // RALINK_28xx_QA // - Channel = pAd->ate.Channel; - - // Select antenna - AsicAntennaSelect(pAd, Channel); - - // fill Tx power value - TxPwer = pAd->ate.TxPower0; - TxPwer2 = pAd->ate.TxPower1; - - RFRegTable = RF2850RegTable; - - switch (pAd->RfIcType) - { - /* But only 2850 and 2750 support 5.5GHz band... */ - case RFIC_2820: - case RFIC_2850: - case RFIC_2720: - case RFIC_2750: - - for (index = 0; index < NUM_OF_2850_CHNL; index++) - { - if (Channel == RFRegTable[index].Channel) - { - R2 = RFRegTable[index].R2; - if (pAd->Antenna.field.TxPath == 1) - { - R2 |= 0x4000; // If TXpath is 1, bit 14 = 1; - } - - if (pAd->Antenna.field.RxPath == 2) - { - switch (pAd->ate.RxAntennaSel) - { - case 1: - R2 |= 0x20040; - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BbpValue); - BbpValue &= 0xE4; - BbpValue |= 0x00; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BbpValue); - break; - case 2: - R2 |= 0x10040; - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BbpValue); - BbpValue &= 0xE4; - BbpValue |= 0x01; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BbpValue); - break; - default: - R2 |= 0x40; - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BbpValue); - BbpValue &= 0xE4; - /* Only enable two Antenna to receive. */ - BbpValue |= 0x08; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BbpValue); - break; - } - } - else if (pAd->Antenna.field.RxPath == 1) - { - R2 |= 0x20040; // write 1 to off RxPath - } - - if (pAd->Antenna.field.TxPath == 2) - { - if (pAd->ate.TxAntennaSel == 1) - { - R2 |= 0x4000; // If TX Antenna select is 1 , bit 14 = 1; Disable Ant 2 - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R1, &BbpValue); - BbpValue &= 0xE7; //11100111B - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R1, BbpValue); - } - else if (pAd->ate.TxAntennaSel == 2) - { - R2 |= 0x8000; // If TX Antenna select is 2 , bit 15 = 1; Disable Ant 1 - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R1, &BbpValue); - BbpValue &= 0xE7; - BbpValue |= 0x08; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R1, BbpValue); - } - else - { - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R1, &BbpValue); - BbpValue &= 0xE7; - BbpValue |= 0x10; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R1, BbpValue); - } - } - if (pAd->Antenna.field.RxPath == 3) - { - switch (pAd->ate.RxAntennaSel) - { - case 1: - R2 |= 0x20040; - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BbpValue); - BbpValue &= 0xE4; - BbpValue |= 0x00; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BbpValue); - break; - case 2: - R2 |= 0x10040; - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BbpValue); - BbpValue &= 0xE4; - BbpValue |= 0x01; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BbpValue); - break; - case 3: - R2 |= 0x30000; - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BbpValue); - BbpValue &= 0xE4; - BbpValue |= 0x02; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BbpValue); - break; - default: - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BbpValue); - BbpValue &= 0xE4; - BbpValue |= 0x10; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BbpValue); - break; - } - } - - if (Channel > 14) - { - // initialize R3, R4 - R3 = (RFRegTable[index].R3 & 0xffffc1ff); - R4 = (RFRegTable[index].R4 & (~0x001f87c0)) | (pAd->ate.RFFreqOffset << 15); - - // According the Rory's suggestion to solve the middle range issue. - // 5.5G band power range: 0xF9~0X0F, TX0 Reg3 bit9/TX1 Reg4 bit6="0" means the TX power reduce 7dB - // R3 - if ((TxPwer >= -7) && (TxPwer < 0)) - { - TxPwer = (7+TxPwer); - TxPwer = (TxPwer > 0xF) ? (0xF) : (TxPwer); - R3 |= (TxPwer << 10); - ATEDBGPRINT(RT_DEBUG_TRACE, ("ATEAsicSwitchChannel: TxPwer=%d \n", TxPwer)); - } - else - { - TxPwer = (TxPwer > 0xF) ? (0xF) : (TxPwer); - R3 |= (TxPwer << 10) | (1 << 9); - } - - // R4 - if ((TxPwer2 >= -7) && (TxPwer2 < 0)) - { - TxPwer2 = (7+TxPwer2); - TxPwer2 = (TxPwer2 > 0xF) ? (0xF) : (TxPwer2); - R4 |= (TxPwer2 << 7); - ATEDBGPRINT(RT_DEBUG_TRACE, ("ATEAsicSwitchChannel: TxPwer2=%d \n", TxPwer2)); - } - else - { - TxPwer2 = (TxPwer2 > 0xF) ? (0xF) : (TxPwer2); - R4 |= (TxPwer2 << 7) | (1 << 6); - } - } - else - { - R3 = (RFRegTable[index].R3 & 0xffffc1ff) | (TxPwer << 9); // set TX power0 - R4 = (RFRegTable[index].R4 & (~0x001f87c0)) | (pAd->ate.RFFreqOffset << 15) | (TxPwer2 <<6);// Set freq offset & TxPwr1 - } - - // Based on BBP current mode before changing RF channel. - if (pAd->ate.TxWI.BW == BW_40) - { - R4 |=0x200000; - } - - // Update variables - pAd->LatchRfRegs.Channel = Channel; - pAd->LatchRfRegs.R1 = RFRegTable[index].R1; - pAd->LatchRfRegs.R2 = R2; - pAd->LatchRfRegs.R3 = R3; - pAd->LatchRfRegs.R4 = R4; - - RtmpRfIoWrite(pAd); - - break; - } - } - break; - - default: - break; - } - - // Change BBP setting during switch from a->g, g->a - if (Channel <= 14) - { - ULONG TxPinCfg = 0x00050F0A;// 2007.10.09 by Brian : 0x0005050A ==> 0x00050F0A - - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R62, (0x37 - GET_LNA_GAIN(pAd))); - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R63, (0x37 - GET_LNA_GAIN(pAd))); - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R64, (0x37 - GET_LNA_GAIN(pAd))); - - /* For 1T/2R chip only... */ - if (pAd->NicConfig2.field.ExternalLNAForG) - { - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R82, 0x62); - } - else - { - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R82, 0x84); - } - - // According the Rory's suggestion to solve the middle range issue. - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R86, &BbpValue); - ASSERT((BbpValue == 0x00)); - if ((BbpValue != 0x00)) - { - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R86, 0x00); - } - - // 5.5GHz band selection PIN, bit1 and bit2 are complement - RTMP_IO_READ32(pAd, TX_BAND_CFG, &Value); - Value &= (~0x6); - Value |= (0x04); - RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Value); - - // Turn off unused PA or LNA when only 1T or 1R. - if (pAd->Antenna.field.TxPath == 1) - { - TxPinCfg &= 0xFFFFFFF3; - } - if (pAd->Antenna.field.RxPath == 1) - { - TxPinCfg &= 0xFFFFF3FF; - } - - RTMP_IO_WRITE32(pAd, TX_PIN_CFG, TxPinCfg); - } - else - { - ULONG TxPinCfg = 0x00050F05;//2007.10.09 by Brian : 0x00050505 ==> 0x00050F05 - - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R62, (0x37 - GET_LNA_GAIN(pAd))); - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R63, (0x37 - GET_LNA_GAIN(pAd))); - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R64, (0x37 - GET_LNA_GAIN(pAd))); - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R82, 0xF2); - - // According the Rory's suggestion to solve the middle range issue. - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R86, &BbpValue); - ASSERT((BbpValue == 0x00)); - if ((BbpValue != 0x00)) - { - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R86, 0x00); - } - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R91, &BbpValue); - ASSERT((BbpValue == 0x04)); - - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R92, &BbpValue); - ASSERT((BbpValue == 0x00)); - - // 5.5GHz band selection PIN, bit1 and bit2 are complement - RTMP_IO_READ32(pAd, TX_BAND_CFG, &Value); - Value &= (~0x6); - Value |= (0x02); - RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Value); - - // Turn off unused PA or LNA when only 1T or 1R. - if (pAd->Antenna.field.TxPath == 1) - { - TxPinCfg &= 0xFFFFFFF3; - } - if (pAd->Antenna.field.RxPath == 1) - { - TxPinCfg &= 0xFFFFF3FF; - } - - RTMP_IO_WRITE32(pAd, TX_PIN_CFG, TxPinCfg); - } - - // R66 should be set according to Channel and use 20MHz when scanning - if (Channel <= 14) - { - // BG band - R66 = 0x2E + GET_LNA_GAIN(pAd); - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); - } - else - { - // 5.5 GHz band - if (pAd->ate.TxWI.BW == BW_20) - { - R66 = (UCHAR)(0x32 + (GET_LNA_GAIN(pAd)*5)/3); - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); - } - else - { - R66 = (UCHAR)(0x3A + (GET_LNA_GAIN(pAd)*5)/3); - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); - } - } - - // - // On 11A, We should delay and wait RF/BBP to be stable - // and the appropriate time should be 1000 micro seconds - // 2005/06/05 - On 11G, We also need this delay time. Otherwise it's difficult to pass the WHQL. - // - RTMPusecDelay(1000); - - if (Channel > 14) - { - // When 5.5GHz band the LSB of TxPwr will be used to reduced 7dB or not. - ATEDBGPRINT(RT_DEBUG_TRACE, ("SwitchChannel#%d(RF=%d, %dT) to , R1=0x%08lx, R2=0x%08lx, R3=0x%08lx, R4=0x%08lx\n", - Channel, - pAd->RfIcType, - pAd->Antenna.field.TxPath, - pAd->LatchRfRegs.R1, - pAd->LatchRfRegs.R2, - pAd->LatchRfRegs.R3, - pAd->LatchRfRegs.R4)); - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("SwitchChannel#%d(RF=%d, Pwr0=%u, Pwr1=%u, %dT) to , R1=0x%08lx, R2=0x%08lx, R3=0x%08lx, R4=0x%08lx\n", - Channel, - pAd->RfIcType, - (R3 & 0x00003e00) >> 9, - (R4 & 0x000007c0) >> 6, - pAd->Antenna.field.TxPath, - pAd->LatchRfRegs.R1, - pAd->LatchRfRegs.R2, - pAd->LatchRfRegs.R3, - pAd->LatchRfRegs.R4)); - } -} - -// -// In fact, no one will call this routine so far ! -// -/* - ========================================================================== - Description: - Gives CCK TX rate 2 more dB TX power. - This routine works only in ATE mode. - - calculate desired Tx power in RF R3.Tx0~5, should consider - - 0. if current radio is a noisy environment (pAd->DrsCounters.fNoisyEnvironment) - 1. TxPowerPercentage - 2. auto calibration based on TSSI feedback - 3. extra 2 db for CCK - 4. -10 db upon very-short distance (AvgRSSI >= -40db) to AP - - NOTE: Since this routine requires the value of (pAd->DrsCounters.fNoisyEnvironment), - it should be called AFTER MlmeDynamicTxRateSwitching() - ========================================================================== - */ -VOID ATEAsicAdjustTxPower( - IN PRTMP_ADAPTER pAd) -{ - INT i, j; - CHAR DeltaPwr = 0; - BOOLEAN bAutoTxAgc = FALSE; - UCHAR TssiRef, *pTssiMinusBoundary, *pTssiPlusBoundary, TxAgcStep; - UCHAR BbpR49 = 0, idx; - PCHAR pTxAgcCompensate; - ULONG TxPwr[5]; - CHAR Value; - - /* no one calls this procedure so far */ - if (pAd->ate.TxWI.BW == BW_40) - { - if (pAd->ate.Channel > 14) - { - TxPwr[0] = pAd->Tx40MPwrCfgABand[0]; - TxPwr[1] = pAd->Tx40MPwrCfgABand[1]; - TxPwr[2] = pAd->Tx40MPwrCfgABand[2]; - TxPwr[3] = pAd->Tx40MPwrCfgABand[3]; - TxPwr[4] = pAd->Tx40MPwrCfgABand[4]; - } - else - { - TxPwr[0] = pAd->Tx40MPwrCfgGBand[0]; - TxPwr[1] = pAd->Tx40MPwrCfgGBand[1]; - TxPwr[2] = pAd->Tx40MPwrCfgGBand[2]; - TxPwr[3] = pAd->Tx40MPwrCfgGBand[3]; - TxPwr[4] = pAd->Tx40MPwrCfgGBand[4]; - } - } - else - { - if (pAd->ate.Channel > 14) - { - TxPwr[0] = pAd->Tx20MPwrCfgABand[0]; - TxPwr[1] = pAd->Tx20MPwrCfgABand[1]; - TxPwr[2] = pAd->Tx20MPwrCfgABand[2]; - TxPwr[3] = pAd->Tx20MPwrCfgABand[3]; - TxPwr[4] = pAd->Tx20MPwrCfgABand[4]; - } - else - { - TxPwr[0] = pAd->Tx20MPwrCfgGBand[0]; - TxPwr[1] = pAd->Tx20MPwrCfgGBand[1]; - TxPwr[2] = pAd->Tx20MPwrCfgGBand[2]; - TxPwr[3] = pAd->Tx20MPwrCfgGBand[3]; - TxPwr[4] = pAd->Tx20MPwrCfgGBand[4]; - } - } - - // TX power compensation for temperature variation based on TSSI. - // Do it per 4 seconds. - if (pAd->Mlme.OneSecPeriodicRound % 4 == 0) - { - if (pAd->ate.Channel <= 14) - { - /* bg channel */ - bAutoTxAgc = pAd->bAutoTxAgcG; - TssiRef = pAd->TssiRefG; - pTssiMinusBoundary = &pAd->TssiMinusBoundaryG[0]; - pTssiPlusBoundary = &pAd->TssiPlusBoundaryG[0]; - TxAgcStep = pAd->TxAgcStepG; - pTxAgcCompensate = &pAd->TxAgcCompensateG; - } - else - { - /* a channel */ - bAutoTxAgc = pAd->bAutoTxAgcA; - TssiRef = pAd->TssiRefA; - pTssiMinusBoundary = &pAd->TssiMinusBoundaryA[0]; - pTssiPlusBoundary = &pAd->TssiPlusBoundaryA[0]; - TxAgcStep = pAd->TxAgcStepA; - pTxAgcCompensate = &pAd->TxAgcCompensateA; - } - - if (bAutoTxAgc) - { - /* BbpR49 is unsigned char */ - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R49, &BbpR49); - - /* (p) TssiPlusBoundaryG[0] = 0 = (m) TssiMinusBoundaryG[0] */ - /* compensate: +4 +3 +2 +1 0 -1 -2 -3 -4 * steps */ - /* step value is defined in pAd->TxAgcStepG for tx power value */ - - /* [4]+1+[4] p4 p3 p2 p1 o1 m1 m2 m3 m4 */ - /* ex: 0x00 0x15 0x25 0x45 0x88 0xA0 0xB5 0xD0 0xF0 - above value are examined in mass factory production */ - /* [4] [3] [2] [1] [0] [1] [2] [3] [4] */ - - /* plus is 0x10 ~ 0x40, minus is 0x60 ~ 0x90 */ - /* if value is between p1 ~ o1 or o1 ~ s1, no need to adjust tx power */ - /* if value is 0x65, tx power will be -= TxAgcStep*(2-1) */ - - if (BbpR49 > pTssiMinusBoundary[1]) - { - // Reading is larger than the reference value. - // Check for how large we need to decrease the Tx power. - for (idx = 1; idx < 5; idx++) - { - if (BbpR49 <= pTssiMinusBoundary[idx]) // Found the range - break; - } - // The index is the step we should decrease, idx = 0 means there is nothing to compensate -// if (R3 > (ULONG) (TxAgcStep * (idx-1))) - *pTxAgcCompensate = -(TxAgcStep * (idx-1)); -// else -// *pTxAgcCompensate = -((UCHAR)R3); - - DeltaPwr += (*pTxAgcCompensate); - ATEDBGPRINT(RT_DEBUG_TRACE, ("-- Tx Power, BBP R1=%x, TssiRef=%x, TxAgcStep=%x, step = -%d\n", - BbpR49, TssiRef, TxAgcStep, idx-1)); - } - else if (BbpR49 < pTssiPlusBoundary[1]) - { - // Reading is smaller than the reference value - // check for how large we need to increase the Tx power - for (idx = 1; idx < 5; idx++) - { - if (BbpR49 >= pTssiPlusBoundary[idx]) // Found the range - break; - } - // The index is the step we should increase, idx = 0 means there is nothing to compensate - *pTxAgcCompensate = TxAgcStep * (idx-1); - DeltaPwr += (*pTxAgcCompensate); - ATEDBGPRINT(RT_DEBUG_TRACE, ("++ Tx Power, BBP R1=%x, TssiRef=%x, TxAgcStep=%x, step = +%d\n", - BbpR49, TssiRef, TxAgcStep, idx-1)); - } - else - { - *pTxAgcCompensate = 0; - ATEDBGPRINT(RT_DEBUG_TRACE, (" Tx Power, BBP R1=%x, TssiRef=%x, TxAgcStep=%x, step = +%d\n", - BbpR49, TssiRef, TxAgcStep, 0)); - } - } - } - else - { - if (pAd->ate.Channel <= 14) - { - bAutoTxAgc = pAd->bAutoTxAgcG; - pTxAgcCompensate = &pAd->TxAgcCompensateG; - } - else - { - bAutoTxAgc = pAd->bAutoTxAgcA; - pTxAgcCompensate = &pAd->TxAgcCompensateA; - } - - if (bAutoTxAgc) - DeltaPwr += (*pTxAgcCompensate); - } - - /* calculate delta power based on the percentage specified from UI */ - // E2PROM setting is calibrated for maximum TX power (i.e. 100%) - // We lower TX power here according to the percentage specified from UI - if (pAd->CommonCfg.TxPowerPercentage == 0xffffffff) // AUTO TX POWER control - ; - else if (pAd->CommonCfg.TxPowerPercentage > 90) // 91 ~ 100% & AUTO, treat as 100% in terms of mW - ; - else if (pAd->CommonCfg.TxPowerPercentage > 60) // 61 ~ 90%, treat as 75% in terms of mW - { - DeltaPwr -= 1; - } - else if (pAd->CommonCfg.TxPowerPercentage > 30) // 31 ~ 60%, treat as 50% in terms of mW - { - DeltaPwr -= 3; - } - else if (pAd->CommonCfg.TxPowerPercentage > 15) // 16 ~ 30%, treat as 25% in terms of mW - { - DeltaPwr -= 6; - } - else if (pAd->CommonCfg.TxPowerPercentage > 9) // 10 ~ 15%, treat as 12.5% in terms of mW - { - DeltaPwr -= 9; - } - else // 0 ~ 9 %, treat as MIN(~3%) in terms of mW - { - DeltaPwr -= 12; - } - - /* reset different new tx power for different TX rate */ - for(i=0; i<5; i++) - { - if (TxPwr[i] != 0xffffffff) - { - for (j=0; j<8; j++) - { - Value = (CHAR)((TxPwr[i] >> j*4) & 0x0F); /* 0 ~ 15 */ - - if ((Value + DeltaPwr) < 0) - { - Value = 0; /* min */ - } - else if ((Value + DeltaPwr) > 0xF) - { - Value = 0xF; /* max */ - } - else - { - Value += DeltaPwr; /* temperature compensation */ - } - - /* fill new value to CSR offset */ - TxPwr[i] = (TxPwr[i] & ~(0x0000000F << j*4)) | (Value << j*4); - } - - /* write tx power value to CSR */ - /* TX_PWR_CFG_0 (8 tx rate) for TX power for OFDM 12M/18M - TX power for OFDM 6M/9M - TX power for CCK5.5M/11M - TX power for CCK1M/2M */ - /* TX_PWR_CFG_1 ~ TX_PWR_CFG_4 */ - RTMP_IO_WRITE32(pAd, TX_PWR_CFG_0 + i*4, TxPwr[i]); - - - } - } - -} - -/* - ======================================================================== - Routine Description: - Write TxWI for ATE mode. - - Return Value: - None - ======================================================================== -*/ -static VOID ATEWriteTxWI( - IN PRTMP_ADAPTER pAd, - IN PTXWI_STRUC pOutTxWI, - IN BOOLEAN FRAG, - IN BOOLEAN CFACK, - IN BOOLEAN InsTimestamp, - IN BOOLEAN AMPDU, - IN BOOLEAN Ack, - IN BOOLEAN NSeq, // HW new a sequence. - IN UCHAR BASize, - IN UCHAR WCID, - IN ULONG Length, - IN UCHAR PID, - IN UCHAR TID, - IN UCHAR TxRate, - IN UCHAR Txopmode, - IN BOOLEAN CfAck, - IN HTTRANSMIT_SETTING *pTransmit) -{ - TXWI_STRUC TxWI; - PTXWI_STRUC pTxWI; - - // - // Always use Long preamble before verifiation short preamble functionality works well. - // Todo: remove the following line if short preamble functionality works - // - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED); - NdisZeroMemory(&TxWI, TXWI_SIZE); - pTxWI = &TxWI; - - pTxWI->FRAG= FRAG; - - pTxWI->CFACK = CFACK; - pTxWI->TS= InsTimestamp; - pTxWI->AMPDU = AMPDU; - pTxWI->ACK = Ack; - pTxWI->txop= Txopmode; - - pTxWI->NSEQ = NSeq; - // John tune the performace with Intel Client in 20 MHz performance - if( BASize >7 ) - BASize =7; - - pTxWI->BAWinSize = BASize; - pTxWI->WirelessCliID = WCID; - pTxWI->MPDUtotalByteCount = Length; - pTxWI->PacketId = PID; - - // If CCK or OFDM, BW must be 20 - pTxWI->BW = (pTransmit->field.MODE <= MODE_OFDM) ? (BW_20) : (pTransmit->field.BW); - pTxWI->ShortGI = pTransmit->field.ShortGI; - pTxWI->STBC = pTransmit->field.STBC; - - pTxWI->MCS = pTransmit->field.MCS; - pTxWI->PHYMODE = pTransmit->field.MODE; - pTxWI->CFACK = CfAck; - pTxWI->MIMOps = 0; - pTxWI->MpduDensity = 0; - - pTxWI->PacketId = pTxWI->MCS; - NdisMoveMemory(pOutTxWI, &TxWI, sizeof(TXWI_STRUC)); - - return; -} - -/* - ======================================================================== - - Routine Description: - Disable protection for ATE. - ======================================================================== -*/ -VOID ATEDisableAsicProtect( - IN PRTMP_ADAPTER pAd) -{ - PROT_CFG_STRUC ProtCfg, ProtCfg4; - UINT32 Protect[6]; - USHORT offset; - UCHAR i; - UINT32 MacReg = 0; - - // Config ASIC RTS threshold register - RTMP_IO_READ32(pAd, TX_RTS_CFG, &MacReg); - MacReg &= 0xFF0000FF; - MacReg |= (pAd->CommonCfg.RtsThreshold << 8); - RTMP_IO_WRITE32(pAd, TX_RTS_CFG, MacReg); - - // Initial common protection settings - RTMPZeroMemory(Protect, sizeof(Protect)); - ProtCfg4.word = 0; - ProtCfg.word = 0; - ProtCfg.field.TxopAllowGF40 = 1; - ProtCfg.field.TxopAllowGF20 = 1; - ProtCfg.field.TxopAllowMM40 = 1; - ProtCfg.field.TxopAllowMM20 = 1; - ProtCfg.field.TxopAllowOfdm = 1; - ProtCfg.field.TxopAllowCck = 1; - ProtCfg.field.RTSThEn = 1; - ProtCfg.field.ProtectNav = ASIC_SHORTNAV; - - // Handle legacy(B/G) protection - ProtCfg.field.ProtectRate = pAd->CommonCfg.RtsRate; - ProtCfg.field.ProtectCtrl = 0; - Protect[0] = ProtCfg.word; - Protect[1] = ProtCfg.word; - - // NO PROTECT - // 1.All STAs in the BSS are 20/40 MHz HT - // 2. in ai 20/40MHz BSS - // 3. all STAs are 20MHz in a 20MHz BSS - // Pure HT. no protection. - - // MM20_PROT_CFG - // Reserved (31:27) - // PROT_TXOP(25:20) -- 010111 - // PROT_NAV(19:18) -- 01 (Short NAV protection) - // PROT_CTRL(17:16) -- 00 (None) - // PROT_RATE(15:0) -- 0x4004 (OFDM 24M) - Protect[2] = 0x01744004; - - // MM40_PROT_CFG - // Reserved (31:27) - // PROT_TXOP(25:20) -- 111111 - // PROT_NAV(19:18) -- 01 (Short NAV protection) - // PROT_CTRL(17:16) -- 00 (None) - // PROT_RATE(15:0) -- 0x4084 (duplicate OFDM 24M) - Protect[3] = 0x03f44084; - - // CF20_PROT_CFG - // Reserved (31:27) - // PROT_TXOP(25:20) -- 010111 - // PROT_NAV(19:18) -- 01 (Short NAV protection) - // PROT_CTRL(17:16) -- 00 (None) - // PROT_RATE(15:0) -- 0x4004 (OFDM 24M) - Protect[4] = 0x01744004; - - // CF40_PROT_CFG - // Reserved (31:27) - // PROT_TXOP(25:20) -- 111111 - // PROT_NAV(19:18) -- 01 (Short NAV protection) - // PROT_CTRL(17:16) -- 00 (None) - // PROT_RATE(15:0) -- 0x4084 (duplicate OFDM 24M) - Protect[5] = 0x03f44084; - - pAd->CommonCfg.IOTestParm.bRTSLongProtOn = FALSE; - - offset = CCK_PROT_CFG; - for (i = 0;i < 6;i++) - RTMP_IO_WRITE32(pAd, offset + i*4, Protect[i]); - -} - - -/* There are two ways to convert Rssi */ -#if 1 -// -// The way used with GET_LNA_GAIN(). -// -CHAR ATEConvertToRssi( - IN PRTMP_ADAPTER pAd, - IN CHAR Rssi, - IN UCHAR RssiNumber) -{ - UCHAR RssiOffset, LNAGain; - - // Rssi equals to zero should be an invalid value - if (Rssi == 0) - return -99; - - LNAGain = GET_LNA_GAIN(pAd); - if (pAd->LatchRfRegs.Channel > 14) - { - if (RssiNumber == 0) - RssiOffset = pAd->ARssiOffset0; - else if (RssiNumber == 1) - RssiOffset = pAd->ARssiOffset1; - else - RssiOffset = pAd->ARssiOffset2; - } - else - { - if (RssiNumber == 0) - RssiOffset = pAd->BGRssiOffset0; - else if (RssiNumber == 1) - RssiOffset = pAd->BGRssiOffset1; - else - RssiOffset = pAd->BGRssiOffset2; - } - - return (-12 - RssiOffset - LNAGain - Rssi); -} -#else -// -// The way originally used in ATE of rt2860ap. -// -CHAR ATEConvertToRssi( - IN PRTMP_ADAPTER pAd, - IN CHAR Rssi, - IN UCHAR RssiNumber) -{ - UCHAR RssiOffset, LNAGain; - - // Rssi equals to zero should be an invalid value - if (Rssi == 0) - return -99; - - if (pAd->LatchRfRegs.Channel > 14) - { - LNAGain = pAd->ALNAGain; - if (RssiNumber == 0) - RssiOffset = pAd->ARssiOffset0; - else if (RssiNumber == 1) - RssiOffset = pAd->ARssiOffset1; - else - RssiOffset = pAd->ARssiOffset2; - } - else - { - LNAGain = pAd->BLNAGain; - if (RssiNumber == 0) - RssiOffset = pAd->BGRssiOffset0; - else if (RssiNumber == 1) - RssiOffset = pAd->BGRssiOffset1; - else - RssiOffset = pAd->BGRssiOffset2; - } - - return (-32 - RssiOffset + LNAGain - Rssi); -} -#endif /* end of #if 1 */ - -/* - ======================================================================== - - Routine Description: - Set Japan filter coefficients if needed. - Note: - This routine should only be called when - entering TXFRAME mode or TXCONT mode. - - ======================================================================== -*/ -static VOID SetJapanFilter( - IN PRTMP_ADAPTER pAd) -{ - UCHAR BbpData = 0; - - // - // If Channel=14 and Bandwidth=20M and Mode=CCK, set BBP R4 bit5=1 - // (Japan Tx filter coefficients)when (TXFRAME or TXCONT). - // - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BbpData); - - if ((pAd->ate.TxWI.PHYMODE == MODE_CCK) && (pAd->ate.Channel == 14) && (pAd->ate.TxWI.BW == BW_20)) - { - BbpData |= 0x20; // turn on - ATEDBGPRINT(RT_DEBUG_TRACE, ("SetJapanFilter!!!\n")); - } - else - { - BbpData &= 0xdf; // turn off - ATEDBGPRINT(RT_DEBUG_TRACE, ("ClearJapanFilter!!!\n")); - } - - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BbpData); -} - -VOID ATESampleRssi( - IN PRTMP_ADAPTER pAd, - IN PRXWI_STRUC pRxWI) -{ - /* There are two ways to collect RSSI. */ -#if 1 - //pAd->LastRxRate = (USHORT)((pRxWI->MCS) + (pRxWI->BW <<7) + (pRxWI->ShortGI <<8)+ (pRxWI->PHYMODE <<14)) ; - if (pRxWI->RSSI0 != 0) - { - pAd->ate.LastRssi0 = ATEConvertToRssi(pAd, (CHAR) pRxWI->RSSI0, RSSI_0); - pAd->ate.AvgRssi0X8 = (pAd->ate.AvgRssi0X8 - pAd->ate.AvgRssi0) + pAd->ate.LastRssi0; - pAd->ate.AvgRssi0 = pAd->ate.AvgRssi0X8 >> 3; - } - if (pRxWI->RSSI1 != 0) - { - pAd->ate.LastRssi1 = ATEConvertToRssi(pAd, (CHAR) pRxWI->RSSI1, RSSI_1); - pAd->ate.AvgRssi1X8 = (pAd->ate.AvgRssi1X8 - pAd->ate.AvgRssi1) + pAd->ate.LastRssi1; - pAd->ate.AvgRssi1 = pAd->ate.AvgRssi1X8 >> 3; - } - if (pRxWI->RSSI2 != 0) - { - pAd->ate.LastRssi2 = ATEConvertToRssi(pAd, (CHAR) pRxWI->RSSI2, RSSI_2); - pAd->ate.AvgRssi2X8 = (pAd->ate.AvgRssi2X8 - pAd->ate.AvgRssi2) + pAd->ate.LastRssi2; - pAd->ate.AvgRssi2 = pAd->ate.AvgRssi2X8 >> 3; - } - - pAd->ate.LastSNR0 = (CHAR)(pRxWI->SNR0);// CHAR ==> UCHAR ? - pAd->ate.LastSNR1 = (CHAR)(pRxWI->SNR1);// CHAR ==> UCHAR ? - - pAd->ate.NumOfAvgRssiSample ++; -#else - pAd->ate.LastSNR0 = (CHAR)(pRxWI->SNR0); - pAd->ate.LastSNR1 = (CHAR)(pRxWI->SNR1); - pAd->ate.RxCntPerSec++; - pAd->ate.LastRssi0 = ATEConvertToRssi(pAd, (CHAR) pRxWI->RSSI0, RSSI_0); - pAd->ate.LastRssi1 = ATEConvertToRssi(pAd, (CHAR) pRxWI->RSSI1, RSSI_1); - pAd->ate.LastRssi2 = ATEConvertToRssi(pAd, (CHAR) pRxWI->RSSI2, RSSI_2); - pAd->ate.AvgRssi0X8 = (pAd->ate.AvgRssi0X8 - pAd->ate.AvgRssi0) + pAd->ate.LastRssi0; - pAd->ate.AvgRssi0 = pAd->ate.AvgRssi0X8 >> 3; - pAd->ate.AvgRssi1X8 = (pAd->ate.AvgRssi1X8 - pAd->ate.AvgRssi1) + pAd->ate.LastRssi1; - pAd->ate.AvgRssi1 = pAd->ate.AvgRssi1X8 >> 3; - pAd->ate.AvgRssi2X8 = (pAd->ate.AvgRssi2X8 - pAd->ate.AvgRssi2) + pAd->ate.LastRssi2; - pAd->ate.AvgRssi2 = pAd->ate.AvgRssi2X8 >> 3; - pAd->ate.NumOfAvgRssiSample ++; -#endif -} - -#ifdef CONFIG_STA_SUPPORT -VOID RTMPStationStop( - IN PRTMP_ADAPTER pAd) -{ -// BOOLEAN Cancelled; - - ATEDBGPRINT(RT_DEBUG_TRACE, ("==> RTMPStationStop\n")); - -#if 0 - RTMPCancelTimer(&pAd->MlmeAux.AssocTimer, &Cancelled); - RTMPCancelTimer(&pAd->MlmeAux.ReassocTimer, &Cancelled); - RTMPCancelTimer(&pAd->MlmeAux.DisassocTimer, &Cancelled); - RTMPCancelTimer(&pAd->MlmeAux.AuthTimer, &Cancelled); - RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer, &Cancelled); - RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &Cancelled); -#endif - // For rx statistics, we need to keep this timer running. -// RTMPCancelTimer(&pAd->Mlme.PeriodicTimer, &Cancelled); - - ATEDBGPRINT(RT_DEBUG_TRACE, ("<== RTMPStationStop\n")); -} - -VOID RTMPStationStart( - IN PRTMP_ADAPTER pAd) -{ - ATEDBGPRINT(RT_DEBUG_TRACE, ("==> RTMPStationStart\n")); -epAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; - // - // We did not cancel this timer when entering ATE mode. - // -// RTMPSetTimer(&pAd->Mlme.PeriodicTimer, MLME_TASK_EXEC_INTV); - ATEDBGPRINT(RT_DEBUG_TRACE, ("<== RTMPStationStart\n")); -} -#endif // CONFIG_STA_SUPPORT // - -/* - ========================================================================== - Description: - Setup Frame format. - NOTE: - This routine should only be used in ATE mode. - ========================================================================== - */ -static INT ATESetUpFrame( - IN PRTMP_ADAPTER pAd, - IN UINT32 TxIdx) -{ - UINT j; - PTXD_STRUC pTxD; -#ifdef RT_BIG_ENDIAN - PTXD_STRUC pDestTxD; - TXD_STRUC TxD; -#endif - PNDIS_PACKET pPacket; - PUCHAR pDest; - PVOID AllocVa; - NDIS_PHYSICAL_ADDRESS AllocPa; - HTTRANSMIT_SETTING TxHTPhyMode; - - PRTMP_TX_RING pTxRing = &pAd->TxRing[QID_AC_BE]; - PTXWI_STRUC pTxWI = (PTXWI_STRUC) pTxRing->Cell[TxIdx].DmaBuf.AllocVa; - PUCHAR pDMAHeaderBufVA = (PUCHAR) pTxRing->Cell[TxIdx].DmaBuf.AllocVa; - -#ifdef RALINK_28xx_QA - PHEADER_802_11 pHeader80211; -#endif // RALINK_28xx_QA // - - if (pAd->ate.bQATxStart == TRUE) - { - // always use QID_AC_BE and FIFO_EDCA - - // fill TxWI - TxHTPhyMode.field.BW = pAd->ate.TxWI.BW; - TxHTPhyMode.field.ShortGI = pAd->ate.TxWI.ShortGI; - TxHTPhyMode.field.STBC = 0; - TxHTPhyMode.field.MCS = pAd->ate.TxWI.MCS; - TxHTPhyMode.field.MODE = pAd->ate.TxWI.PHYMODE; - ATEWriteTxWI(pAd, pTxWI, pAd->ate.TxWI.FRAG, pAd->ate.TxWI.CFACK, pAd->ate.TxWI.TS, pAd->ate.TxWI.AMPDU, pAd->ate.TxWI.ACK, pAd->ate.TxWI.NSEQ, - pAd->ate.TxWI.BAWinSize, 0, pAd->ate.TxWI.MPDUtotalByteCount, pAd->ate.TxWI.PacketId, 0, 0, pAd->ate.TxWI.txop/*IFS_HTTXOP*/, pAd->ate.TxWI.CFACK/*FALSE*/, &TxHTPhyMode); - } - else - { - TxHTPhyMode.field.BW = pAd->ate.TxWI.BW; - TxHTPhyMode.field.ShortGI = pAd->ate.TxWI.ShortGI; - TxHTPhyMode.field.STBC = 0; - TxHTPhyMode.field.MCS = pAd->ate.TxWI.MCS; - TxHTPhyMode.field.MODE = pAd->ate.TxWI.PHYMODE; - ATEWriteTxWI(pAd, pTxWI, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, - 4, 0, pAd->ate.TxLength, 0, 0, 0, IFS_HTTXOP, FALSE, &TxHTPhyMode); - } - - // fill 802.11 header. -#ifdef RALINK_28xx_QA - if (pAd->ate.bQATxStart == TRUE) - { - NdisMoveMemory(pDMAHeaderBufVA+TXWI_SIZE, pAd->ate.Header, pAd->ate.HLen); - } - else -#endif // RALINK_28xx_QA // - { - NdisMoveMemory(pDMAHeaderBufVA+TXWI_SIZE, TemplateFrame, LENGTH_802_11); - NdisMoveMemory(pDMAHeaderBufVA+TXWI_SIZE+4, pAd->ate.Addr1, ETH_LENGTH_OF_ADDRESS); - NdisMoveMemory(pDMAHeaderBufVA+TXWI_SIZE+10, pAd->ate.Addr2, ETH_LENGTH_OF_ADDRESS); - NdisMoveMemory(pDMAHeaderBufVA+TXWI_SIZE+16, pAd->ate.Addr3, ETH_LENGTH_OF_ADDRESS); - } - -#ifdef RT_BIG_ENDIAN - RTMPFrameEndianChange(pAd, (((PUCHAR)pDMAHeaderBufVA)+TXWI_SIZE), DIR_READ, FALSE); -#endif // RT_BIG_ENDIAN // - - /* alloc buffer for payload */ -#ifdef RALINK_28xx_QA - if (pAd->ate.bQATxStart == TRUE) - { - /* Why not use RTMP_AllocateTxPacketBuffer() instead of RTMP_AllocateRxPacketBuffer()? */ - pPacket = RTMP_AllocateRxPacketBuffer(pAd, pAd->ate.DLen + 0x100, FALSE, &AllocVa, &AllocPa); - } - else -#endif // RALINK_28xx_QA // - { - /* Why not use RTMP_AllocateTxPacketBuffer() instead of RTMP_AllocateRxPacketBuffer()? */ - pPacket = RTMP_AllocateRxPacketBuffer(pAd, pAd->ate.TxLength, FALSE, &AllocVa, &AllocPa); - } - - if (pPacket == NULL) - { - pAd->ate.TxCount = 0; - ATEDBGPRINT(RT_DEBUG_TRACE, ("%s fail to alloc packet space.\n", __func__)); - return -1; - } - pTxRing->Cell[TxIdx].pNextNdisPacket = pPacket; - - pDest = (PUCHAR) AllocVa; - -#ifdef RALINK_28xx_QA - if (pAd->ate.bQATxStart == TRUE) - { - RTPKT_TO_OSPKT(pPacket)->len = pAd->ate.DLen; - } - else -#endif // RALINK_28xx_QA // - { - RTPKT_TO_OSPKT(pPacket)->len = pAd->ate.TxLength - LENGTH_802_11; - } - - // Prepare frame payload -#ifdef RALINK_28xx_QA - if (pAd->ate.bQATxStart == TRUE) - { - // copy pattern - if ((pAd->ate.PLen != 0)) - { - int j; - - for (j = 0; j < pAd->ate.DLen; j+=pAd->ate.PLen) - { - memcpy(RTPKT_TO_OSPKT(pPacket)->data + j, pAd->ate.Pattern, pAd->ate.PLen); - } - } - } - else -#endif // RALINK_28xx_QA // - { - for(j = 0; j < RTPKT_TO_OSPKT(pPacket)->len; j++) - pDest[j] = 0xA5; - } - - // - // build Tx Descriptor - // -#ifndef RT_BIG_ENDIAN - pTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa; -#else - pDestTxD = (PTXD_STRUC)pTxRing->Cell[TxIdx].AllocVa; - TxD = *pDestTxD; - pTxD = &TxD; -#endif // !RT_BIG_ENDIAN // - -#ifdef RALINK_28xx_QA - if (pAd->ate.bQATxStart == TRUE) - { - // prepare TxD - NdisZeroMemory(pTxD, TXD_SIZE); - RTMPWriteTxDescriptor(pAd, pTxD, FALSE, FIFO_EDCA); - // build TX DESC - pTxD->SDPtr0 = RTMP_GetPhysicalAddressLow(pTxRing->Cell[TxIdx].DmaBuf.AllocPa); - pTxD->SDLen0 = TXWI_SIZE + pAd->ate.HLen; - pTxD->LastSec0 = 0; - pTxD->SDPtr1 = AllocPa; - pTxD->SDLen1 = RTPKT_TO_OSPKT(pPacket)->len; - pTxD->LastSec1 = 1; - - pDest = (PUCHAR)pTxWI; - pDest += TXWI_SIZE; - pHeader80211 = (PHEADER_802_11)pDest; - - // modify sequence number.... - if (pAd->ate.TxDoneCount == 0) - { - pAd->ate.seq = pHeader80211->Sequence; - } - else - pHeader80211->Sequence = ++pAd->ate.seq; - } - else -#endif // RALINK_28xx_QA // - { - NdisZeroMemory(pTxD, TXD_SIZE); - RTMPWriteTxDescriptor(pAd, pTxD, FALSE, FIFO_EDCA); - // build TX DESC - pTxD->SDPtr0 = RTMP_GetPhysicalAddressLow (pTxRing->Cell[TxIdx].DmaBuf.AllocPa); - pTxD->SDLen0 = TXWI_SIZE + LENGTH_802_11; - pTxD->LastSec0 = 0; - pTxD->SDPtr1 = AllocPa; - pTxD->SDLen1 = RTPKT_TO_OSPKT(pPacket)->len; - pTxD->LastSec1 = 1; - } - -#ifdef RT_BIG_ENDIAN - RTMPWIEndianChange((PUCHAR)pTxWI, TYPE_TXWI); - RTMPFrameEndianChange(pAd, (((PUCHAR)pDMAHeaderBufVA)+TXWI_SIZE), DIR_WRITE, FALSE); - RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); - WriteBackToDescriptor((PUCHAR)pDestTxD, (PUCHAR)pTxD, FALSE, TYPE_TXD); -#endif // RT_BIG_ENDIAN // - return 0; -} -/* */ -/* */ -/*=======================End of RT2860=======================*/ - - -VOID rt_ee_read_all(PRTMP_ADAPTER pAd, USHORT *Data) -{ - USHORT i; - USHORT value; - - for (i = 0 ; i < EEPROM_SIZE/2 ; ) - { - /* "value" is expecially for some compilers... */ - RT28xx_EEPROM_READ16(pAd, i*2, value); - Data[i] = value; - i++; - } -} - -VOID rt_ee_write_all(PRTMP_ADAPTER pAd, USHORT *Data) -{ - USHORT i; - USHORT value; - - for (i = 0 ; i < EEPROM_SIZE/2 ; ) - { - /* "value" is expecially for some compilers... */ - value = Data[i]; - RT28xx_EEPROM_WRITE16(pAd, i*2, value); - i ++; - } -} -#ifdef RALINK_28xx_QA -VOID ATE_QA_Statistics( - IN PRTMP_ADAPTER pAd, - IN PRXWI_STRUC pRxWI, - IN PRT28XX_RXD_STRUC pRxD, - IN PHEADER_802_11 pHeader) -{ - // update counter first - if (pHeader != NULL) - { - if (pHeader->FC.Type == BTYPE_DATA) - { - if (pRxD->U2M) - pAd->ate.U2M++; - else - pAd->ate.OtherData++; - } - else if (pHeader->FC.Type == BTYPE_MGMT) - { - if (pHeader->FC.SubType == SUBTYPE_BEACON) - pAd->ate.Beacon++; - else - pAd->ate.OtherCount++; - } - else if (pHeader->FC.Type == BTYPE_CNTL) - { - pAd->ate.OtherCount++; - } - } - pAd->ate.RSSI0 = pRxWI->RSSI0; - pAd->ate.RSSI1 = pRxWI->RSSI1; - pAd->ate.RSSI2 = pRxWI->RSSI2; - pAd->ate.SNR0 = pRxWI->SNR0; - pAd->ate.SNR1 = pRxWI->SNR1; -} - -/* command id with Cmd Type == 0x0008(for 28xx)/0x0005(for iNIC) */ -#define RACFG_CMD_RF_WRITE_ALL 0x0000 -#define RACFG_CMD_E2PROM_READ16 0x0001 -#define RACFG_CMD_E2PROM_WRITE16 0x0002 -#define RACFG_CMD_E2PROM_READ_ALL 0x0003 -#define RACFG_CMD_E2PROM_WRITE_ALL 0x0004 -#define RACFG_CMD_IO_READ 0x0005 -#define RACFG_CMD_IO_WRITE 0x0006 -#define RACFG_CMD_IO_READ_BULK 0x0007 -#define RACFG_CMD_BBP_READ8 0x0008 -#define RACFG_CMD_BBP_WRITE8 0x0009 -#define RACFG_CMD_BBP_READ_ALL 0x000a -#define RACFG_CMD_GET_COUNTER 0x000b -#define RACFG_CMD_CLEAR_COUNTER 0x000c - -#define RACFG_CMD_RSV1 0x000d -#define RACFG_CMD_RSV2 0x000e -#define RACFG_CMD_RSV3 0x000f - -#define RACFG_CMD_TX_START 0x0010 -#define RACFG_CMD_GET_TX_STATUS 0x0011 -#define RACFG_CMD_TX_STOP 0x0012 -#define RACFG_CMD_RX_START 0x0013 -#define RACFG_CMD_RX_STOP 0x0014 -#define RACFG_CMD_GET_NOISE_LEVEL 0x0015 - -#define RACFG_CMD_ATE_START 0x0080 -#define RACFG_CMD_ATE_STOP 0x0081 - -#define RACFG_CMD_ATE_START_TX_CARRIER 0x0100 -#define RACFG_CMD_ATE_START_TX_CONT 0x0101 -#define RACFG_CMD_ATE_START_TX_FRAME 0x0102 -#define RACFG_CMD_ATE_SET_BW 0x0103 -#define RACFG_CMD_ATE_SET_TX_POWER0 0x0104 -#define RACFG_CMD_ATE_SET_TX_POWER1 0x0105 -#define RACFG_CMD_ATE_SET_FREQ_OFFSET 0x0106 -#define RACFG_CMD_ATE_GET_STATISTICS 0x0107 -#define RACFG_CMD_ATE_RESET_COUNTER 0x0108 -#define RACFG_CMD_ATE_SEL_TX_ANTENNA 0x0109 -#define RACFG_CMD_ATE_SEL_RX_ANTENNA 0x010a -#define RACFG_CMD_ATE_SET_PREAMBLE 0x010b -#define RACFG_CMD_ATE_SET_CHANNEL 0x010c -#define RACFG_CMD_ATE_SET_ADDR1 0x010d -#define RACFG_CMD_ATE_SET_ADDR2 0x010e -#define RACFG_CMD_ATE_SET_ADDR3 0x010f -#define RACFG_CMD_ATE_SET_RATE 0x0110 -#define RACFG_CMD_ATE_SET_TX_FRAME_LEN 0x0111 -#define RACFG_CMD_ATE_SET_TX_FRAME_COUNT 0x0112 -#define RACFG_CMD_ATE_START_RX_FRAME 0x0113 -#define RACFG_CMD_ATE_E2PROM_READ_BULK 0x0114 -#define RACFG_CMD_ATE_E2PROM_WRITE_BULK 0x0115 -#define RACFG_CMD_ATE_IO_WRITE_BULK 0x0116 -#define RACFG_CMD_ATE_BBP_READ_BULK 0x0117 -#define RACFG_CMD_ATE_BBP_WRITE_BULK 0x0118 -#define RACFG_CMD_ATE_RF_READ_BULK 0x0119 -#define RACFG_CMD_ATE_RF_WRITE_BULK 0x011a - - - -#define A2Hex(_X, _p) \ -{ \ - UCHAR *p; \ - _X = 0; \ - p = _p; \ - while (((*p >= 'a') && (*p <= 'f')) || ((*p >= 'A') && (*p <= 'F')) || ((*p >= '0') && (*p <= '9'))) \ - { \ - if ((*p >= 'a') && (*p <= 'f')) \ - _X = _X * 16 + *p - 87; \ - else if ((*p >= 'A') && (*p <= 'F')) \ - _X = _X * 16 + *p - 55; \ - else if ((*p >= '0') && (*p <= '9')) \ - _X = _X * 16 + *p - 48; \ - p++; \ - } \ -} - - -static VOID memcpy_exl(PRTMP_ADAPTER pAd, UCHAR *dst, UCHAR *src, ULONG len); -static VOID memcpy_exs(PRTMP_ADAPTER pAd, UCHAR *dst, UCHAR *src, ULONG len); -static VOID RTMP_IO_READ_BULK(PRTMP_ADAPTER pAd, UCHAR *dst, UCHAR *src, UINT32 len); - -#ifdef UCOS -int ate_copy_to_user( - IN PUCHAR payload, - IN PUCHAR msg, - IN INT len) -{ - memmove(payload, msg, len); - return 0; -} - -#undef copy_to_user -#define copy_to_user(x,y,z) ate_copy_to_user((PUCHAR)x, (PUCHAR)y, z) -#endif // UCOS // - -#define LEN_OF_ARG 16 - -VOID RtmpDoAte( - IN PRTMP_ADAPTER pAdapter, - IN struct iwreq *wrq) -{ - unsigned short Command_Id; - struct ate_racfghdr *pRaCfg; - INT Status = NDIS_STATUS_SUCCESS; - - - - if((pRaCfg = kmalloc(sizeof(struct ate_racfghdr), GFP_KERNEL)) == NULL) - { - Status = -EINVAL; - return; - } - - NdisZeroMemory(pRaCfg, sizeof(struct ate_racfghdr)); - - if (copy_from_user((PUCHAR)pRaCfg, wrq->u.data.pointer, wrq->u.data.length)) - { - Status = -EFAULT; - kfree(pRaCfg); - return; - } - - - Command_Id = ntohs(pRaCfg->command_id); - - ATEDBGPRINT(RT_DEBUG_TRACE,("\n%s: Command_Id = 0x%04x !\n", __func__, Command_Id)); - - switch (Command_Id) - { - // We will get this command when QA starts. - case RACFG_CMD_ATE_START: - { - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_START\n")); - - // prepare feedback as soon as we can to avoid QA timeout. - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - ATEDBGPRINT(RT_DEBUG_TRACE, ("wrq->u.data.length = %d\n", wrq->u.data.length)); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("copy_to_user() fail in case RACFG_CMD_ATE_START\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_START is done !\n")); - } - Set_ATE_Proc(pAdapter, "ATESTART"); - } - break; - - // We will get this command either QA is closed or ated is killed by user. - case RACFG_CMD_ATE_STOP: - { -#ifndef UCOS - INT32 ret; -#endif // !UCOS // - - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_STOP\n")); - - // Distinguish this command came from QA(via ated) - // or ate daemon according to the existence of pid in payload. - // No need to prepare feedback if this cmd came directly from ate daemon. - pRaCfg->length = ntohs(pRaCfg->length); - - if (pRaCfg->length == sizeof(pAdapter->ate.AtePid)) - { - // This command came from QA. - // Get the pid of ATE daemon. - memcpy((UCHAR *)&pAdapter->ate.AtePid, - (&pRaCfg->data[0]) - 2/* == &(pRaCfg->status) */, - sizeof(pAdapter->ate.AtePid)); - - // prepare feedback as soon as we can to avoid QA timeout. - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - ATEDBGPRINT(RT_DEBUG_TRACE, ("wrq->u.data.length = %d\n", wrq->u.data.length)); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_STOP\n")); - Status = -EFAULT; - } - - // - // kill ATE daemon when leaving ATE mode. - // We must kill ATE daemon first before setting ATESTOP, - // or Microsoft will report sth. wrong. -#ifndef UCOS - ret = KILL_THREAD_PID(pAdapter->ate.AtePid, SIGTERM, 1); - if (ret) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("%s: unable to signal thread\n", pAdapter->net_dev->name)); - } -#endif // !UCOS // - } - - // AP might have in ATE_STOP mode due to cmd from QA. - if (ATE_ON(pAdapter)) - { - // Someone has killed ate daemon while QA GUI is still open. - Set_ATE_Proc(pAdapter, "ATESTOP"); - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_AP_START is done !\n")); - } - } - break; - - case RACFG_CMD_RF_WRITE_ALL: - { - UINT32 R1, R2, R3, R4; - USHORT channel; - - memcpy(&R1, pRaCfg->data-2, 4); - memcpy(&R2, pRaCfg->data+2, 4); - memcpy(&R3, pRaCfg->data+6, 4); - memcpy(&R4, pRaCfg->data+10, 4); - memcpy(&channel, pRaCfg->data+14, 2); - - pAdapter->LatchRfRegs.R1 = ntohl(R1); - pAdapter->LatchRfRegs.R2 = ntohl(R2); - pAdapter->LatchRfRegs.R3 = ntohl(R3); - pAdapter->LatchRfRegs.R4 = ntohl(R4); - pAdapter->LatchRfRegs.Channel = ntohs(channel); - - RTMP_RF_IO_WRITE32(pAdapter, pAdapter->LatchRfRegs.R1); - RTMP_RF_IO_WRITE32(pAdapter, pAdapter->LatchRfRegs.R2); - RTMP_RF_IO_WRITE32(pAdapter, pAdapter->LatchRfRegs.R3); - RTMP_RF_IO_WRITE32(pAdapter, pAdapter->LatchRfRegs.R4); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - ATEDBGPRINT(RT_DEBUG_TRACE, ("wrq->u.data.length = %d\n", wrq->u.data.length)); - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_RF_WRITE_ALL\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_RF_WRITE_ALL is done !\n")); - } - } - break; - - case RACFG_CMD_E2PROM_READ16: - { - USHORT offset, value, tmp; - - offset = ntohs(pRaCfg->status); - /* "tmp" is expecially for some compilers... */ - RT28xx_EEPROM_READ16(pAdapter, offset, tmp); - value = tmp; - value = htons(value); - - ATEDBGPRINT(RT_DEBUG_TRACE,("EEPROM Read offset = 0x%04x, value = 0x%04x\n", offset, value)); - - // prepare feedback - pRaCfg->length = htons(4); - pRaCfg->status = htons(0); - memcpy(pRaCfg->data, &value, 2); - - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - ATEDBGPRINT(RT_DEBUG_TRACE, ("sizeof(struct ate_racfghdr) = %d\n", sizeof(struct ate_racfghdr))); - ATEDBGPRINT(RT_DEBUG_TRACE, ("wrq->u.data.length = %d\n", wrq->u.data.length)); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_E2PROM_READ16\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_E2PROM_READ16 is done !\n")); - } - } - break; - - case RACFG_CMD_E2PROM_WRITE16: - { - USHORT offset, value; - - offset = ntohs(pRaCfg->status); - memcpy(&value, pRaCfg->data, 2); - value = ntohs(value); - RT28xx_EEPROM_WRITE16(pAdapter, offset, value); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_E2PROM_WRITE16\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_E2PROM_WRITE16 is done !\n")); - } - } - break; - - case RACFG_CMD_E2PROM_READ_ALL: - { - USHORT buffer[EEPROM_SIZE/2]; - - rt_ee_read_all(pAdapter,(USHORT *)buffer); - memcpy_exs(pAdapter, pRaCfg->data, (UCHAR *)buffer, EEPROM_SIZE); - - // prepare feedback - pRaCfg->length = htons(2+EEPROM_SIZE); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_E2PROM_READ_ALL\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_E2PROM_READ_ALL is done !\n")); - } - } - break; - - case RACFG_CMD_E2PROM_WRITE_ALL: - { - USHORT buffer[EEPROM_SIZE/2]; - - NdisZeroMemory((UCHAR *)buffer, EEPROM_SIZE); - memcpy_exs(pAdapter, (UCHAR *)buffer, (UCHAR *)&pRaCfg->status, EEPROM_SIZE); - rt_ee_write_all(pAdapter,(USHORT *)buffer); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_E2PROM_WRITE_ALL\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("RACFG_CMD_E2PROM_WRITE_ALL is done !\n")); - } - - } - break; - - case RACFG_CMD_IO_READ: - { - UINT32 offset; - UINT32 value; - - memcpy(&offset, &pRaCfg->status, 4); - offset = ntohl(offset); - - // We do not need the base address. - // So just extract the offset out. - offset &= 0x0000FFFF; - RTMP_IO_READ32(pAdapter, offset, &value); - value = htonl(value); - - // prepare feedback - pRaCfg->length = htons(6); - pRaCfg->status = htons(0); - memcpy(pRaCfg->data, &value, 4); - - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_IO_READ\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_IO_READ is done !\n")); - } - } - break; - - case RACFG_CMD_IO_WRITE: - { - UINT32 offset, value; - - memcpy(&offset, pRaCfg->data-2, 4); - memcpy(&value, pRaCfg->data+2, 4); - - offset = ntohl(offset); - - // We do not need the base address. - // So just extract out the offset. - offset &= 0x0000FFFF; - value = ntohl(value); - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_IO_WRITE: offset = %x, value = %x\n", offset, value)); - RTMP_IO_WRITE32(pAdapter, offset, value); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_IO_WRITE\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_IO_WRITE is done !\n")); - } - } - break; - - case RACFG_CMD_IO_READ_BULK: - { - UINT32 offset; - USHORT len; - - memcpy(&offset, &pRaCfg->status, 4); - offset = ntohl(offset); - - // We do not need the base address. - // So just extract the offset. - offset &= 0x0000FFFF; - memcpy(&len, pRaCfg->data+2, 2); - len = ntohs(len); - - if (len > 371) - { - ATEDBGPRINT(RT_DEBUG_TRACE,("len is too large, make it smaller\n")); - pRaCfg->length = htons(2); - pRaCfg->status = htons(1); - break; - } - - RTMP_IO_READ_BULK(pAdapter, pRaCfg->data, (UCHAR *)offset, len*4);// unit in four bytes - - // prepare feedback - pRaCfg->length = htons(2+len*4);// unit in four bytes - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_IO_READ_BULK\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_IO_READ_BULK is done !\n")); - } - } - break; - - case RACFG_CMD_BBP_READ8: - { - USHORT offset; - UCHAR value; - - value = 0; - offset = ntohs(pRaCfg->status); - - if (ATE_ON(pAdapter)) - { - ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, offset, &value); - } - else - { - RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, offset, &value); - } - // prepare feedback - pRaCfg->length = htons(3); - pRaCfg->status = htons(0); - pRaCfg->data[0] = value; - - ATEDBGPRINT(RT_DEBUG_TRACE,("BBP value = %x\n", value)); - - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_BBP_READ8\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_BBP_READ8 is done !\n")); - } - } - break; - case RACFG_CMD_BBP_WRITE8: - { - USHORT offset; - UCHAR value; - - offset = ntohs(pRaCfg->status); - memcpy(&value, pRaCfg->data, 1); - - if (ATE_ON(pAdapter)) - { - ATE_BBP_IO_WRITE8_BY_REG_ID(pAdapter, offset, value); - } - else - { - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, offset, value); - } - - if ((offset == BBP_R1) || (offset == BBP_R3)) - { - SyncTxRxConfig(pAdapter, offset, value); - } - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_BBP_WRITE8\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_BBP_WRITE8 is done !\n")); - } - } - break; - - case RACFG_CMD_BBP_READ_ALL: - { - USHORT j; - - for (j = 0; j < 137; j++) - { - pRaCfg->data[j] = 0; - - if (ATE_ON(pAdapter)) - { - ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, j, &pRaCfg->data[j]); - } - else - { - RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, j, &pRaCfg->data[j]); - } - } - - // prepare feedback - pRaCfg->length = htons(2+137); - pRaCfg->status = htons(0); - - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_BBP_READ_ALL\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_BBP_READ_ALL is done !\n")); - } - } - - break; - - case RACFG_CMD_ATE_E2PROM_READ_BULK: - { - USHORT offset; - USHORT len; - USHORT buffer[EEPROM_SIZE/2]; - - offset = ntohs(pRaCfg->status); - memcpy(&len, pRaCfg->data, 2); - len = ntohs(len); - - rt_ee_read_all(pAdapter,(USHORT *)buffer); - if (offset + len <= EEPROM_SIZE) - memcpy_exs(pAdapter, pRaCfg->data, (UCHAR *)buffer+offset, len); - else - ATEDBGPRINT(RT_DEBUG_ERROR, ("exceed EEPROM size\n")); - - // prepare feedback - pRaCfg->length = htons(2+len); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_E2PROM_READ_BULK\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_E2PROM_READ_BULK is done !\n")); - } - - } - break; - - case RACFG_CMD_ATE_E2PROM_WRITE_BULK: - { - USHORT offset; - USHORT len; - USHORT buffer[EEPROM_SIZE/2]; - - offset = ntohs(pRaCfg->status); - memcpy(&len, pRaCfg->data, 2); - len = ntohs(len); - - rt_ee_read_all(pAdapter,(USHORT *)buffer); - memcpy_exs(pAdapter, (UCHAR *)buffer + offset, (UCHAR *)pRaCfg->data + 2, len); - rt_ee_write_all(pAdapter,(USHORT *)buffer); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_E2PROM_WRITE_BULK\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("RACFG_CMD_ATE_E2PROM_WRITE_BULK is done !\n")); - } - - } - break; - - case RACFG_CMD_ATE_IO_WRITE_BULK: - { - UINT32 offset, i, value; - USHORT len; - - memcpy(&offset, &pRaCfg->status, 4); - offset = ntohl(offset); - memcpy(&len, pRaCfg->data+2, 2); - len = ntohs(len); - - for (i = 0; i < len; i += 4) - { - memcpy_exl(pAdapter, (UCHAR *)&value, pRaCfg->data+4+i, 4); - printk("Write %x %x\n", offset + i, value); - RTMP_IO_WRITE32(pAdapter, (offset +i) & 0xffff, value); - } - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_IO_WRITE_BULK\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("RACFG_CMD_ATE_IO_WRITE_BULK is done !\n")); - } - - } - break; - - case RACFG_CMD_ATE_BBP_READ_BULK: - { - USHORT offset; - USHORT len; - USHORT j; - - offset = ntohs(pRaCfg->status); - memcpy(&len, pRaCfg->data, 2); - len = ntohs(len); - - - for (j = offset; j < (offset+len); j++) - { - pRaCfg->data[j - offset] = 0; - - if (pAdapter->ate.Mode == ATE_STOP) - { - RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, j, &pRaCfg->data[j - offset]); - } - else - { - ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, j, &pRaCfg->data[j - offset]); - } - } - - // prepare feedback - pRaCfg->length = htons(2+len); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_BBP_READ_BULK\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_BBP_READ_BULK is done !\n")); - } - - } - break; - - case RACFG_CMD_ATE_BBP_WRITE_BULK: - { - USHORT offset; - USHORT len; - USHORT j; - UCHAR *value; - - offset = ntohs(pRaCfg->status); - memcpy(&len, pRaCfg->data, 2); - len = ntohs(len); - - for (j = offset; j < (offset+len); j++) - { - value = pRaCfg->data + 2 + (j - offset); - if (pAdapter->ate.Mode == ATE_STOP) - { - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, j, *value); - } - else - { - ATE_BBP_IO_WRITE8_BY_REG_ID(pAdapter, j, *value); - } - } - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_BBP_WRITE_BULK\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_BBP_WRITE_BULK is done !\n")); - } - } - break; - -#ifdef CONFIG_RALINK_RT3052 - case RACFG_CMD_ATE_RF_READ_BULK: - { - USHORT offset; - USHORT len; - USHORT j; - - offset = ntohs(pRaCfg->status); - memcpy(&len, pRaCfg->data, 2); - len = ntohs(len); - - for (j = offset; j < (offset+len); j++) - { - pRaCfg->data[j - offset] = 0; - RT30xxReadRFRegister(pAdapter, j, &pRaCfg->data[j - offset]); - } - - // prepare feedback - pRaCfg->length = htons(2+len); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_RF_READ_BULK\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_RF_READ_BULK is done !\n")); - } - - } - break; - - case RACFG_CMD_ATE_RF_WRITE_BULK: - { - USHORT offset; - USHORT len; - USHORT j; - UCHAR *value; - - offset = ntohs(pRaCfg->status); - memcpy(&len, pRaCfg->data, 2); - len = ntohs(len); - - for (j = offset; j < (offset+len); j++) - { - value = pRaCfg->data + 2 + (j - offset); - RT30xxWriteRFRegister(pAdapter, j, *value); - } - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_RF_WRITE_BULK\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_RF_WRITE_BULK is done !\n")); - } - - } - break; -#endif - - - case RACFG_CMD_GET_NOISE_LEVEL: - { - UCHAR channel; - INT32 buffer[3][10];/* 3 : RxPath ; 10 : no. of per rssi samples */ - - channel = (ntohs(pRaCfg->status) & 0x00FF); - CalNoiseLevel(pAdapter, channel, buffer); - memcpy_exl(pAdapter, (UCHAR *)pRaCfg->data, (UCHAR *)&(buffer[0][0]), (sizeof(INT32)*3*10)); - - // prepare feedback - pRaCfg->length = htons(2 + (sizeof(INT32)*3*10)); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_GET_NOISE_LEVEL\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_GET_NOISE_LEVEL is done !\n")); - } - } - break; - - case RACFG_CMD_GET_COUNTER: - { - memcpy_exl(pAdapter, &pRaCfg->data[0], (UCHAR *)&pAdapter->ate.U2M, 4); - memcpy_exl(pAdapter, &pRaCfg->data[4], (UCHAR *)&pAdapter->ate.OtherData, 4); - memcpy_exl(pAdapter, &pRaCfg->data[8], (UCHAR *)&pAdapter->ate.Beacon, 4); - memcpy_exl(pAdapter, &pRaCfg->data[12], (UCHAR *)&pAdapter->ate.OtherCount, 4); - memcpy_exl(pAdapter, &pRaCfg->data[16], (UCHAR *)&pAdapter->ate.TxAc0, 4); - memcpy_exl(pAdapter, &pRaCfg->data[20], (UCHAR *)&pAdapter->ate.TxAc1, 4); - memcpy_exl(pAdapter, &pRaCfg->data[24], (UCHAR *)&pAdapter->ate.TxAc2, 4); - memcpy_exl(pAdapter, &pRaCfg->data[28], (UCHAR *)&pAdapter->ate.TxAc3, 4); - memcpy_exl(pAdapter, &pRaCfg->data[32], (UCHAR *)&pAdapter->ate.TxHCCA, 4); - memcpy_exl(pAdapter, &pRaCfg->data[36], (UCHAR *)&pAdapter->ate.TxMgmt, 4); - memcpy_exl(pAdapter, &pRaCfg->data[40], (UCHAR *)&pAdapter->ate.RSSI0, 4); - memcpy_exl(pAdapter, &pRaCfg->data[44], (UCHAR *)&pAdapter->ate.RSSI1, 4); - memcpy_exl(pAdapter, &pRaCfg->data[48], (UCHAR *)&pAdapter->ate.RSSI2, 4); - memcpy_exl(pAdapter, &pRaCfg->data[52], (UCHAR *)&pAdapter->ate.SNR0, 4); - memcpy_exl(pAdapter, &pRaCfg->data[56], (UCHAR *)&pAdapter->ate.SNR1, 4); - - pRaCfg->length = htons(2+60); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_GET_COUNTER\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_GET_COUNTER is done !\n")); - } - } - break; - - case RACFG_CMD_CLEAR_COUNTER: - { - pAdapter->ate.U2M = 0; - pAdapter->ate.OtherData = 0; - pAdapter->ate.Beacon = 0; - pAdapter->ate.OtherCount = 0; - pAdapter->ate.TxAc0 = 0; - pAdapter->ate.TxAc1 = 0; - pAdapter->ate.TxAc2 = 0; - pAdapter->ate.TxAc3 = 0; - pAdapter->ate.TxHCCA = 0; - pAdapter->ate.TxMgmt = 0; - pAdapter->ate.TxDoneCount = 0; - - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_CLEAR_COUNTER\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_CLEAR_COUNTER is done !\n")); - } - } - - break; - - case RACFG_CMD_TX_START: - { - USHORT *p; - USHORT err = 1; - UCHAR Bbp22Value = 0, Bbp24Value = 0; - - if ((pAdapter->ate.TxStatus != 0) && (pAdapter->ate.Mode & ATE_TXFRAME)) - { - ATEDBGPRINT(RT_DEBUG_TRACE,("Ate Tx is already running, to run next Tx, you must stop it first\n")); - err = 2; - goto TX_START_ERROR; - } - else if ((pAdapter->ate.TxStatus != 0) && !(pAdapter->ate.Mode & ATE_TXFRAME)) - { - int i = 0; - - while ((i++ < 10) && (pAdapter->ate.TxStatus != 0)) - { - RTMPusecDelay(5000); - } - - // force it to stop - pAdapter->ate.TxStatus = 0; - pAdapter->ate.TxDoneCount = 0; - //pAdapter->ate.Repeat = 0; - pAdapter->ate.bQATxStart = FALSE; - } - - // If pRaCfg->length == 0, this "RACFG_CMD_TX_START" is for Carrier test or Carrier Suppression. - if (ntohs(pRaCfg->length) != 0) - { - // Get frame info - - NdisMoveMemory(&pAdapter->ate.TxWI, pRaCfg->data + 2, 16); -#ifdef RT_BIG_ENDIAN - RTMPWIEndianChange((PUCHAR)&pAdapter->ate.TxWI, TYPE_TXWI); -#endif // RT_BIG_ENDIAN // - - NdisMoveMemory(&pAdapter->ate.TxCount, pRaCfg->data + 18, 4); - pAdapter->ate.TxCount = ntohl(pAdapter->ate.TxCount); - - p = (USHORT *)(&pRaCfg->data[22]); - //p = pRaCfg->data + 22; - // always use QID_AC_BE - pAdapter->ate.QID = 0; - p = (USHORT *)(&pRaCfg->data[24]); - //p = pRaCfg->data + 24; - pAdapter->ate.HLen = ntohs(*p); - - if (pAdapter->ate.HLen > 32) - { - ATEDBGPRINT(RT_DEBUG_ERROR,("pAdapter->ate.HLen > 32\n")); - err = 3; - goto TX_START_ERROR; - } - - NdisMoveMemory(&pAdapter->ate.Header, pRaCfg->data + 26, pAdapter->ate.HLen); - - - pAdapter->ate.PLen = ntohs(pRaCfg->length) - (pAdapter->ate.HLen + 28); - - if (pAdapter->ate.PLen > 32) - { - ATEDBGPRINT(RT_DEBUG_ERROR,("pAdapter->ate.PLen > 32\n")); - err = 4; - goto TX_START_ERROR; - } - - NdisMoveMemory(&pAdapter->ate.Pattern, pRaCfg->data + 26 + pAdapter->ate.HLen, pAdapter->ate.PLen); - pAdapter->ate.DLen = pAdapter->ate.TxWI.MPDUtotalByteCount - pAdapter->ate.HLen; - } - - ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, BBP_R22, &Bbp22Value); - - switch (Bbp22Value) - { - case BBP22_TXFRAME: - { - if (pAdapter->ate.TxCount == 0) - { - pAdapter->ate.TxCount = 0xFFFFFFFF; - } - ATEDBGPRINT(RT_DEBUG_TRACE,("START TXFRAME\n")); - pAdapter->ate.bQATxStart = TRUE; - Set_ATE_Proc(pAdapter, "TXFRAME"); - } - break; - - case BBP22_TXCONT_OR_CARRSUPP: - { - ATEDBGPRINT(RT_DEBUG_TRACE,("BBP22_TXCONT_OR_CARRSUPP\n")); - ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, 24, &Bbp24Value); - - switch (Bbp24Value) - { - case BBP24_TXCONT: - { - ATEDBGPRINT(RT_DEBUG_TRACE,("START TXCONT\n")); - pAdapter->ate.bQATxStart = TRUE; - Set_ATE_Proc(pAdapter, "TXCONT"); - } - break; - - case BBP24_CARRSUPP: - { - ATEDBGPRINT(RT_DEBUG_TRACE,("START TXCARRSUPP\n")); - pAdapter->ate.bQATxStart = TRUE; - pAdapter->ate.Mode |= ATE_TXCARRSUPP; - } - break; - - default: - { - ATEDBGPRINT(RT_DEBUG_ERROR,("Unknown Start TX subtype !")); - } - break; - } - } - break; - - case BBP22_TXCARR: - { - ATEDBGPRINT(RT_DEBUG_TRACE,("START TXCARR\n")); - pAdapter->ate.bQATxStart = TRUE; - Set_ATE_Proc(pAdapter, "TXCARR"); - } - break; - - default: - { - ATEDBGPRINT(RT_DEBUG_ERROR,("Unknown Start TX subtype !")); - } - break; - } - - if (pAdapter->ate.bQATxStart == TRUE) - { - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() was failed in case RACFG_CMD_TX_START\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_TX_START is done !\n")); - } - break; - } - -TX_START_ERROR: - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(err); - - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_TX_START\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("feedback of TX_START_ERROR is done !\n")); - } - } - break; - - case RACFG_CMD_GET_TX_STATUS: - { - UINT32 count; - - // prepare feedback - pRaCfg->length = htons(6); - pRaCfg->status = htons(0); - count = htonl(pAdapter->ate.TxDoneCount); - NdisMoveMemory(pRaCfg->data, &count, 4); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_GET_TX_STATUS\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_GET_TX_STATUS is done !\n")); - } - } - break; - - case RACFG_CMD_TX_STOP: - { - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_TX_STOP\n")); - - Set_ATE_Proc(pAdapter, "TXSTOP"); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("copy_to_user() fail in case RACFG_CMD_TX_STOP\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_TX_STOP is done !\n")); - } - } - break; - - case RACFG_CMD_RX_START: - { - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_RX_START\n")); - - pAdapter->ate.bQARxStart = TRUE; - Set_ATE_Proc(pAdapter, "RXFRAME"); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_RX_START\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_RX_START is done !\n")); - } - } - break; - - case RACFG_CMD_RX_STOP: - { - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_RX_STOP\n")); - - Set_ATE_Proc(pAdapter, "RXSTOP"); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_RX_STOP\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_RX_STOP is done !\n")); - } - } - break; - - /* The following cases are for new ATE GUI(not QA). */ - /*==================================================*/ - case RACFG_CMD_ATE_START_TX_CARRIER: - { - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_START_TX_CARRIER\n")); - - Set_ATE_Proc(pAdapter, "TXCARR"); - - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - ATEDBGPRINT(RT_DEBUG_TRACE, ("wrq->u.data.length = %d\n", wrq->u.data.length)); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_START_TX_CARRIER\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_START_TX_CARRIER is done !\n")); - } - } - break; - - case RACFG_CMD_ATE_START_TX_CONT: - { - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_START_TX_CONT\n")); - - Set_ATE_Proc(pAdapter, "TXCONT"); - - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - ATEDBGPRINT(RT_DEBUG_TRACE, ("wrq->u.data.length = %d\n", wrq->u.data.length)); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_START_TX_CONT\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_START_TX_CONT is done !\n")); - } - } - break; - - case RACFG_CMD_ATE_START_TX_FRAME: - { - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_START_TX_FRAME\n")); - - Set_ATE_Proc(pAdapter, "TXFRAME"); - - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - ATEDBGPRINT(RT_DEBUG_TRACE, ("wrq->u.data.length = %d\n", wrq->u.data.length)); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_START_TX_FRAME\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_START_TX_FRAME is done !\n")); - } - } - break; - - case RACFG_CMD_ATE_SET_BW: - { - SHORT value = 0; - UCHAR str[LEN_OF_ARG]; - - NdisZeroMemory(str, LEN_OF_ARG); - - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_BW\n")); - - memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); - value = ntohs(value); - sprintf((PCHAR)str, "%d", value); - - Set_ATE_TX_BW_Proc(pAdapter, str); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_BW\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_BW is done !\n")); - } - } - break; - - case RACFG_CMD_ATE_SET_TX_POWER0: - { - SHORT value = 0; - UCHAR str[LEN_OF_ARG]; - - NdisZeroMemory(str, LEN_OF_ARG); - - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_TX_POWER0\n")); - - memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); - value = ntohs(value); - sprintf((PCHAR)str, "%d", value); - Set_ATE_TX_POWER0_Proc(pAdapter, str); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_TX_POWER0\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_TX_POWER0 is done !\n")); - } - } - break; - - case RACFG_CMD_ATE_SET_TX_POWER1: - { - SHORT value = 0; - UCHAR str[LEN_OF_ARG]; - - NdisZeroMemory(str, LEN_OF_ARG); - - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_TX_POWER1\n")); - - memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); - value = ntohs(value); - sprintf((PCHAR)str, "%d", value); - Set_ATE_TX_POWER1_Proc(pAdapter, str); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_TX_POWER1\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_TX_POWER1 is done !\n")); - } - } - break; - - case RACFG_CMD_ATE_SET_FREQ_OFFSET: - { - SHORT value = 0; - UCHAR str[LEN_OF_ARG]; - - NdisZeroMemory(str, LEN_OF_ARG); - - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_FREQ_OFFSET\n")); - - memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); - value = ntohs(value); - sprintf((PCHAR)str, "%d", value); - Set_ATE_TX_FREQOFFSET_Proc(pAdapter, str); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_FREQ_OFFSET\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_FREQ_OFFSET is done !\n")); - } - } - break; - - case RACFG_CMD_ATE_GET_STATISTICS: - { - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_GET_STATISTICS\n")); - - memcpy_exl(pAdapter, &pRaCfg->data[0], (UCHAR *)&pAdapter->ate.TxDoneCount, 4); - memcpy_exl(pAdapter, &pRaCfg->data[4], (UCHAR *)&pAdapter->WlanCounters.RetryCount.u.LowPart, 4); - memcpy_exl(pAdapter, &pRaCfg->data[8], (UCHAR *)&pAdapter->WlanCounters.FailedCount.u.LowPart, 4); - memcpy_exl(pAdapter, &pRaCfg->data[12], (UCHAR *)&pAdapter->WlanCounters.RTSSuccessCount.u.LowPart, 4); - memcpy_exl(pAdapter, &pRaCfg->data[16], (UCHAR *)&pAdapter->WlanCounters.RTSFailureCount.u.LowPart, 4); - memcpy_exl(pAdapter, &pRaCfg->data[20], (UCHAR *)&pAdapter->WlanCounters.ReceivedFragmentCount.QuadPart, 4); - memcpy_exl(pAdapter, &pRaCfg->data[24], (UCHAR *)&pAdapter->WlanCounters.FCSErrorCount.u.LowPart, 4); - memcpy_exl(pAdapter, &pRaCfg->data[28], (UCHAR *)&pAdapter->Counters8023.RxNoBuffer, 4); - memcpy_exl(pAdapter, &pRaCfg->data[32], (UCHAR *)&pAdapter->WlanCounters.FrameDuplicateCount.u.LowPart, 4); - memcpy_exl(pAdapter, &pRaCfg->data[36], (UCHAR *)&pAdapter->RalinkCounters.OneSecFalseCCACnt, 4); - - if (pAdapter->ate.RxAntennaSel == 0) - { - INT32 RSSI0 = 0; - INT32 RSSI1 = 0; - INT32 RSSI2 = 0; - - RSSI0 = (INT32)(pAdapter->ate.LastRssi0 - pAdapter->BbpRssiToDbmDelta); - RSSI1 = (INT32)(pAdapter->ate.LastRssi1 - pAdapter->BbpRssiToDbmDelta); - RSSI2 = (INT32)(pAdapter->ate.LastRssi2 - pAdapter->BbpRssiToDbmDelta); - memcpy_exl(pAdapter, &pRaCfg->data[40], (UCHAR *)&RSSI0, 4); - memcpy_exl(pAdapter, &pRaCfg->data[44], (UCHAR *)&RSSI1, 4); - memcpy_exl(pAdapter, &pRaCfg->data[48], (UCHAR *)&RSSI2, 4); - pRaCfg->length = htons(2+52); - } - else - { - INT32 RSSI0 = 0; - - RSSI0 = (INT32)(pAdapter->ate.LastRssi0 - pAdapter->BbpRssiToDbmDelta); - memcpy_exl(pAdapter, &pRaCfg->data[40], (UCHAR *)&RSSI0, 4); - pRaCfg->length = htons(2+44); - } - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_GET_STATISTICS\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_GET_STATISTICS is done !\n")); - } - } - break; - - case RACFG_CMD_ATE_RESET_COUNTER: - { - SHORT value = 1; - UCHAR str[LEN_OF_ARG]; - - NdisZeroMemory(str, LEN_OF_ARG); - - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_RESET_COUNTER\n")); - - sprintf((PCHAR)str, "%d", value); - Set_ResetStatCounter_Proc(pAdapter, str); - - pAdapter->ate.TxDoneCount = 0; - - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_RESET_COUNTER\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_RESET_COUNTER is done !\n")); - } - } - - break; - - case RACFG_CMD_ATE_SEL_TX_ANTENNA: - { - SHORT value = 0; - UCHAR str[LEN_OF_ARG]; - - NdisZeroMemory(str, LEN_OF_ARG); - - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SEL_TX_ANTENNA\n")); - - memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); - value = ntohs(value); - sprintf((PCHAR)str, "%d", value); - Set_ATE_TX_Antenna_Proc(pAdapter, str); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SEL_TX_ANTENNA\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SEL_TX_ANTENNA is done !\n")); - } - } - break; - - case RACFG_CMD_ATE_SEL_RX_ANTENNA: - { - SHORT value = 0; - UCHAR str[LEN_OF_ARG]; - - NdisZeroMemory(str, LEN_OF_ARG); - - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SEL_RX_ANTENNA\n")); - - memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); - value = ntohs(value); - sprintf((PCHAR)str, "%d", value); - Set_ATE_RX_Antenna_Proc(pAdapter, str); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SEL_RX_ANTENNA\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SEL_RX_ANTENNA is done !\n")); - } - } - break; - - case RACFG_CMD_ATE_SET_PREAMBLE: - { - SHORT value = 0; - UCHAR str[LEN_OF_ARG]; - - NdisZeroMemory(str, LEN_OF_ARG); - - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_PREAMBLE\n")); - - memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); - value = ntohs(value); - sprintf((PCHAR)str, "%d", value); - Set_ATE_TX_MODE_Proc(pAdapter, str); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_PREAMBLE\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_PREAMBLE is done !\n")); - } - } - break; - - case RACFG_CMD_ATE_SET_CHANNEL: - { - SHORT value = 0; - UCHAR str[LEN_OF_ARG]; - - NdisZeroMemory(str, LEN_OF_ARG); - - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_CHANNEL\n")); - - memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); - value = ntohs(value); - sprintf((PCHAR)str, "%d", value); - Set_ATE_CHANNEL_Proc(pAdapter, str); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_CHANNEL\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_CHANNEL is done !\n")); - } - } - break; - - case RACFG_CMD_ATE_SET_ADDR1: - { - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_ADDR1\n")); - - // Addr is an array of UCHAR, - // so no need to perform endian swap. - memcpy(pAdapter->ate.Addr1, (PUCHAR)(pRaCfg->data - 2), MAC_ADDR_LEN); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_ADDR1\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_ADDR1 is done !\n (ADDR1 = %2X:%2X:%2X:%2X:%2X:%2X)\n", pAdapter->ate.Addr1[0], - pAdapter->ate.Addr1[1], pAdapter->ate.Addr1[2], pAdapter->ate.Addr1[3], pAdapter->ate.Addr1[4], pAdapter->ate.Addr1[5])); - } - } - break; - - case RACFG_CMD_ATE_SET_ADDR2: - { - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_ADDR2\n")); - - // Addr is an array of UCHAR, - // so no need to perform endian swap. - memcpy(pAdapter->ate.Addr2, (PUCHAR)(pRaCfg->data - 2), MAC_ADDR_LEN); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_ADDR2\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_ADDR2 is done !\n (ADDR2 = %2X:%2X:%2X:%2X:%2X:%2X)\n", pAdapter->ate.Addr2[0], - pAdapter->ate.Addr2[1], pAdapter->ate.Addr2[2], pAdapter->ate.Addr2[3], pAdapter->ate.Addr2[4], pAdapter->ate.Addr2[5])); - } - } - break; - - case RACFG_CMD_ATE_SET_ADDR3: - { - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_ADDR3\n")); - - // Addr is an array of UCHAR, - // so no need to perform endian swap. - memcpy(pAdapter->ate.Addr3, (PUCHAR)(pRaCfg->data - 2), MAC_ADDR_LEN); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_ADDR3\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_ADDR3 is done !\n (ADDR3 = %2X:%2X:%2X:%2X:%2X:%2X)\n", pAdapter->ate.Addr3[0], - pAdapter->ate.Addr3[1], pAdapter->ate.Addr3[2], pAdapter->ate.Addr3[3], pAdapter->ate.Addr3[4], pAdapter->ate.Addr3[5])); - } - } - break; - - case RACFG_CMD_ATE_SET_RATE: - { - SHORT value = 0; - UCHAR str[LEN_OF_ARG]; - - NdisZeroMemory(str, LEN_OF_ARG); - - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_RATE\n")); - - memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); - value = ntohs(value); - sprintf((PCHAR)str, "%d", value); - Set_ATE_TX_MCS_Proc(pAdapter, str); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_RATE\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_RATE is done !\n")); - } - } - break; - - case RACFG_CMD_ATE_SET_TX_FRAME_LEN: - { - SHORT value = 0; - UCHAR str[LEN_OF_ARG]; - - NdisZeroMemory(str, LEN_OF_ARG); - - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_TX_FRAME_LEN\n")); - - memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); - value = ntohs(value); - sprintf((PCHAR)str, "%d", value); - Set_ATE_TX_LENGTH_Proc(pAdapter, str); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_TX_FRAME_LEN\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_TX_FRAME_LEN is done !\n")); - } - } - break; - - case RACFG_CMD_ATE_SET_TX_FRAME_COUNT: - { - USHORT value = 0; - UCHAR str[LEN_OF_ARG]; - - NdisZeroMemory(str, LEN_OF_ARG); - - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_TX_FRAME_COUNT\n")); - - memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); - value = ntohs(value); - /* TX_FRAME_COUNT == 0 means tx infinitely */ - if (value == 0) - { - /* Use TxCount = 0xFFFFFFFF to approximate the infinity. */ - pAdapter->ate.TxCount = 0xFFFFFFFF; - ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_TX_COUNT_Proc (TxCount = %d)\n", pAdapter->ate.TxCount)); - ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_COUNT_Proc Success\n")); - - - } - else - { - sprintf((PCHAR)str, "%d", value); - Set_ATE_TX_COUNT_Proc(pAdapter, str); - } - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_TX_FRAME_COUNT\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_TX_FRAME_COUNT is done !\n")); - } - } - break; - - case RACFG_CMD_ATE_START_RX_FRAME: - { - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_RX_START\n")); - - Set_ATE_Proc(pAdapter, "RXFRAME"); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_RX_START\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_RX_START is done !\n")); - } - } - break; - default: - break; - } - ASSERT(pRaCfg != NULL); - if (pRaCfg != NULL) - { - kfree(pRaCfg); - } - return; -} - -VOID BubbleSort(INT32 n, INT32 a[]) -{ - INT32 k, j, temp; - - for (k = n-1; k>0; k--) - { - for (j = 0; j a[j+1]) - { - temp = a[j]; - a[j]=a[j+1]; - a[j+1]=temp; - } - } - } -} - -VOID CalNoiseLevel(PRTMP_ADAPTER pAd, UCHAR channel, INT32 RSSI[3][10]) -{ - INT32 RSSI0, RSSI1, RSSI2; - CHAR Rssi0Offset, Rssi1Offset, Rssi2Offset; - UCHAR BbpR50Rssi0 = 0, BbpR51Rssi1 = 0, BbpR52Rssi2 = 0; - UCHAR Org_BBP66value = 0, Org_BBP69value = 0, Org_BBP70value = 0, data = 0; - USHORT LNA_Gain = 0; - INT32 j = 0; - UCHAR Org_Channel = pAd->ate.Channel; - USHORT GainValue = 0, OffsetValue = 0; - - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R66, &Org_BBP66value); - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R69, &Org_BBP69value); - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R70, &Org_BBP70value); - - //********************************************************************** - // Read the value of LNA gain and Rssi offset - //********************************************************************** - RT28xx_EEPROM_READ16(pAd, EEPROM_LNA_OFFSET, GainValue); - - // for Noise Level - if (channel <= 14) - { - LNA_Gain = GainValue & 0x00FF; - - RT28xx_EEPROM_READ16(pAd, EEPROM_RSSI_BG_OFFSET, OffsetValue); - Rssi0Offset = OffsetValue & 0x00FF; - Rssi1Offset = (OffsetValue & 0xFF00) >> 8; - RT28xx_EEPROM_READ16(pAd, (EEPROM_RSSI_BG_OFFSET + 2)/* 0x48 */, OffsetValue); - Rssi2Offset = OffsetValue & 0x00FF; - } - else - { - LNA_Gain = (GainValue & 0xFF00) >> 8; - - RT28xx_EEPROM_READ16(pAd, EEPROM_RSSI_A_OFFSET, OffsetValue); - Rssi0Offset = OffsetValue & 0x00FF; - Rssi1Offset = (OffsetValue & 0xFF00) >> 8; - RT28xx_EEPROM_READ16(pAd, (EEPROM_RSSI_A_OFFSET + 2)/* 0x4C */, OffsetValue); - Rssi2Offset = OffsetValue & 0x00FF; - } - //********************************************************************** - { - pAd->ate.Channel = channel; - ATEAsicSwitchChannel(pAd); - mdelay(5); - - data = 0x10; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, data); - data = 0x40; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, data); - data = 0x40; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, data); - mdelay(5); - - // Start Rx - pAd->ate.bQARxStart = TRUE; - Set_ATE_Proc(pAd, "RXFRAME"); - - mdelay(5); - - for (j = 0; j < 10; j++) - { - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R50, &BbpR50Rssi0); - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R51, &BbpR51Rssi1); - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R52, &BbpR52Rssi2); - - mdelay(10); - - // Calculate RSSI 0 - if (BbpR50Rssi0 == 0) - { - RSSI0 = -100; - } - else - { - RSSI0 = (INT32)(-12 - BbpR50Rssi0 - LNA_Gain - Rssi0Offset); - } - RSSI[0][j] = RSSI0; - - if ( pAd->Antenna.field.RxPath >= 2 ) // 2R - { - // Calculate RSSI 1 - if (BbpR51Rssi1 == 0) - { - RSSI1 = -100; - } - else - { - RSSI1 = (INT32)(-12 - BbpR51Rssi1 - LNA_Gain - Rssi1Offset); - } - RSSI[1][j] = RSSI1; - } - - if ( pAd->Antenna.field.RxPath >= 3 ) // 3R - { - // Calculate RSSI 2 - if (BbpR52Rssi2 == 0) - RSSI2 = -100; - else - RSSI2 = (INT32)(-12 - BbpR52Rssi2 - LNA_Gain - Rssi2Offset); - - RSSI[2][j] = RSSI2; - } - } - - // Stop Rx - Set_ATE_Proc(pAd, "RXSTOP"); - - mdelay(5); - -#if 0// Debug Message................ - ate_print("\n**********************************************************\n"); - ate_print("Noise Level: Channel %d\n", channel); - ate_print("RSSI0 = %d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n", - RSSI[0][0], RSSI[0][1], RSSI[0][2], - RSSI[0][3], RSSI[0][4], RSSI[0][5], - RSSI[0][6], RSSI[0][7], RSSI[0][8], - RSSI[0][9]); - if ( pAd->Antenna.field.RxPath >= 2 ) // 2R - { - ate_print("RSSI1 = %d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n", - RSSI[1][0], RSSI[1][1], RSSI[1][2], - RSSI[1][3], RSSI[1][4], RSSI[1][5], - RSSI[1][6], RSSI[1][7], RSSI[1][8], - RSSI[1][9]); - } - if ( pAd->Antenna.field.RxPath >= 3 ) // 3R - { - ate_print("RSSI2 = %d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n", - RSSI[2][0], RSSI[2][1], RSSI[2][2], - RSSI[2][3], RSSI[2][4], RSSI[2][5], - RSSI[2][6], RSSI[2][7], RSSI[2][8], - RSSI[2][9]); - } -#endif // 0 // - BubbleSort(10, RSSI[0]); // 1R - - if ( pAd->Antenna.field.RxPath >= 2 ) // 2R - { - BubbleSort(10, RSSI[1]); - } - - if ( pAd->Antenna.field.RxPath >= 3 ) // 3R - { - BubbleSort(10, RSSI[2]); - } - -#if 0// Debug Message................ - ate_print("\nAfter Sorting....Channel %d\n", channel); - ate_print("RSSI0 = %d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n", - RSSI[0][0], RSSI[0][1], RSSI[0][2], - RSSI[0][3], RSSI[0][4], RSSI[0][5], - RSSI[0][6], RSSI[0][7], RSSI[0][8], - RSSI[0][9]); - if ( pAd->Antenna.field.RxPath >= 2 ) // 2R - { - ate_print("RSSI1 = %d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n", - RSSI[1][0], RSSI[1][1], RSSI[1][2], - RSSI[1][3], RSSI[1][4], RSSI[1][5], - RSSI[1][6], RSSI[1][7], RSSI[1][8], - RSSI[1][9]); - } - if ( pAd->Antenna.field.RxPath >= 3 ) // 3R - { - ate_print("RSSI2 = %d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n", - RSSI[2][0], RSSI[2][1], RSSI[2][2], - RSSI[2][3], RSSI[2][4], RSSI[2][5], - RSSI[2][6], RSSI[2][7], RSSI[2][8], - RSSI[2][9]); - } - ate_print("**********************************************************\n"); -#endif // 0 // - } - - pAd->ate.Channel = Org_Channel; - ATEAsicSwitchChannel(pAd); - - // Restore original value - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, Org_BBP66value); - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, Org_BBP69value); - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, Org_BBP70value); - - return; -} - -BOOLEAN SyncTxRxConfig(PRTMP_ADAPTER pAd, USHORT offset, UCHAR value) -{ - UCHAR tmp = 0, bbp_data = 0; - - if (ATE_ON(pAd)) - { - ATE_BBP_IO_READ8_BY_REG_ID(pAd, offset, &bbp_data); - } - else - { - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, offset, &bbp_data); - } - - /* confirm again */ - ASSERT(bbp_data == value); - - switch(offset) - { - case BBP_R1: - /* Need to sync. tx configuration with legacy ATE. */ - tmp = (bbp_data & ((1 << 4) | (1 << 3))/* 0x18 */) >> 3; - switch(tmp) - { - /* The BBP R1 bit[4:3] = 2 :: Both DACs will be used by QA. */ - case 2: - /* All */ - pAd->ate.TxAntennaSel = 0; - break; - /* The BBP R1 bit[4:3] = 0 :: DAC 0 will be used by QA. */ - case 0: - /* Antenna one */ - pAd->ate.TxAntennaSel = 1; - break; - /* The BBP R1 bit[4:3] = 1 :: DAC 1 will be used by QA. */ - case 1: - /* Antenna two */ - pAd->ate.TxAntennaSel = 2; - break; - default: - DBGPRINT(RT_DEBUG_TRACE, ("%s -- Sth. wrong! : return FALSE; \n", __func__)); - return FALSE; - } - break;/* case BBP_R1 */ - - case BBP_R3: - /* Need to sync. rx configuration with legacy ATE. */ - tmp = (bbp_data & ((1 << 1) | (1 << 0))/* 0x03 */); - switch(tmp) - { - /* The BBP R3 bit[1:0] = 3 :: All ADCs will be used by QA. */ - case 3: - /* All */ - pAd->ate.RxAntennaSel = 0; - break; - /* The BBP R3 bit[1:0] = 0 :: ADC 0 will be used by QA, */ - /* unless the BBP R3 bit[4:3] = 2 */ - case 0: - /* Antenna one */ - pAd->ate.RxAntennaSel = 1; - tmp = ((bbp_data & ((1 << 4) | (1 << 3))/* 0x03 */) >> 3); - if (tmp == 2)// 3R - { - /* Default : All ADCs will be used by QA */ - pAd->ate.RxAntennaSel = 0; - } - break; - /* The BBP R3 bit[1:0] = 1 :: ADC 1 will be used by QA. */ - case 1: - /* Antenna two */ - pAd->ate.RxAntennaSel = 2; - break; - /* The BBP R3 bit[1:0] = 2 :: ADC 2 will be used by QA. */ - case 2: - /* Antenna three */ - pAd->ate.RxAntennaSel = 3; - break; - default: - DBGPRINT(RT_DEBUG_ERROR, ("%s -- Impossible! : return FALSE; \n", __func__)); - return FALSE; - } - break;/* case BBP_R3 */ - - default: - DBGPRINT(RT_DEBUG_ERROR, ("%s -- Sth. wrong! : return FALSE; \n", __func__)); - return FALSE; - - } - return TRUE; -} - -static VOID memcpy_exl(PRTMP_ADAPTER pAd, UCHAR *dst, UCHAR *src, ULONG len) -{ - ULONG i, Value = 0; - ULONG *pDst, *pSrc; - UCHAR *p8; - - p8 = src; - pDst = (ULONG *) dst; - pSrc = (ULONG *) src; - - for (i = 0 ; i < (len/4); i++) - { - /* For alignment issue, we need a variable "Value". */ - memmove(&Value, pSrc, 4); - Value = htonl(Value); - memmove(pDst, &Value, 4); - pDst++; - pSrc++; - } - if ((len % 4) != 0) - { - /* wish that it will never reach here */ - memmove(&Value, pSrc, (len % 4)); - Value = htonl(Value); - memmove(pDst, &Value, (len % 4)); - } -} - -static VOID memcpy_exs(PRTMP_ADAPTER pAd, UCHAR *dst, UCHAR *src, ULONG len) -{ - ULONG i; - UCHAR *pDst, *pSrc; - - pDst = dst; - pSrc = src; - - for (i = 0; i < (len/2); i++) - { - memmove(pDst, pSrc, 2); - *((USHORT *)pDst) = htons(*((USHORT *)pDst)); - pDst+=2; - pSrc+=2; - } - - if ((len % 2) != 0) - { - memmove(pDst, pSrc, 1); - } -} - -static VOID RTMP_IO_READ_BULK(PRTMP_ADAPTER pAd, UCHAR *dst, UCHAR *src, UINT32 len) -{ - UINT32 i, Value; - UINT32 *pDst, *pSrc; - - pDst = (UINT32 *) dst; - pSrc = (UINT32 *) src; - - for (i = 0 ; i < (len/4); i++) - { - RTMP_IO_READ32(pAd, (ULONG)pSrc, &Value); - Value = htonl(Value); - memmove(pDst, &Value, 4); - pDst++; - pSrc++; - } - return; -} - -// TODO: -#if 0 -/* These work only when RALINK_ATE is defined */ -INT Set_TxStart_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ULONG value = simple_strtol(arg, 0, 10); - UCHAR buffer[26] = {0x88, 0x02, 0x2c, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x00, 0x55, 0x44, 0x33, 0x22, 0x11, 0xc0, 0x22, 0x00, 0x00}; - POS_COOKIE pObj; - - if (pAd->ate.TxStatus != 0) - return FALSE; - - pAd->ate.TxInfo = 0x04000000; - bzero(&pAd->ate.TxWI, sizeof(TXWI_STRUC)); - pAd->ate.TxWI.PHYMODE = 0;// MODE_CCK - pAd->ate.TxWI.MPDUtotalByteCount = 1226; - pAd->ate.TxWI.MCS = 3; - //pAd->ate.Mode = ATE_START; - pAd->ate.Mode |= ATE_TXFRAME; - pAd->ate.TxCount = value; - pAd->ate.QID = 0; - pAd->ate.HLen = 26; - pAd->ate.PLen = 0; - pAd->ate.DLen = 1200; - memcpy(pAd->ate.Header, buffer, 26); - pAd->ate.bQATxStart = TRUE; - //pObj = (POS_COOKIE) pAd->OS_Cookie; - //tasklet_hi_schedule(&pObj->AteTxTask); - return TRUE; -} -#endif /* end of #if 0 */ - -INT Set_TxStop_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ATEDBGPRINT(RT_DEBUG_TRACE,("Set_TxStop_Proc\n")); - - if (Set_ATE_Proc(pAd, "TXSTOP")) - { - return TRUE; -} - else - { - return FALSE; - } -} - -INT Set_RxStop_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ATEDBGPRINT(RT_DEBUG_TRACE,("Set_RxStop_Proc\n")); - - if (Set_ATE_Proc(pAd, "RXSTOP")) - { - return TRUE; -} - else - { - return FALSE; - } -} - -#if 0 -INT Set_EEWrite_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - USHORT offset = 0, value; - PUCHAR p2 = arg; - - while((*p2 != ':') && (*p2 != '\0')) - { - p2++; - } - - if (*p2 == ':') - { - A2Hex(offset, arg); - A2Hex(value, p2+ 1); - } - else - { - A2Hex(value, arg); - } - - if (offset >= EEPROM_SIZE) - { - ate_print("Offset can not exceed EEPROM_SIZE( == 0x%04x)\n", EEPROM_SIZE); - return FALSE; - } - - RTMP_EEPROM_WRITE16(pAd, offset, value); - - return TRUE; -} - -INT Set_BBPRead_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - UCHAR value = 0, offset; - - A2Hex(offset, arg); - - if (ATE_ON(pAd)) - { - ATE_BBP_IO_READ8_BY_REG_ID(pAd, offset, &value); - } - else - { - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, offset, &value); - } - - ate_print("%x\n", value); - - return TRUE; -} - - -INT Set_BBPWrite_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - USHORT offset = 0; - PUCHAR p2 = arg; - UCHAR value; - - while((*p2 != ':') && (*p2 != '\0')) - { - p2++; - } - - if (*p2 == ':') - { - A2Hex(offset, arg); - A2Hex(value, p2+ 1); - } - else - { - A2Hex(value, arg); - } - - if (ATE_ON(pAd)) - { - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, offset, value); - } - else - { - RTNP_BBP_IO_WRITE8_BY_REG_ID(pAd, offset, value); - } - - return TRUE; -} - -INT Set_RFWrite_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - PUCHAR p2, p3, p4; - ULONG R1, R2, R3, R4; - - p2 = arg; - - while((*p2 != ':') && (*p2 != '\0')) - { - p2++; - } - - if (*p2 != ':') - return FALSE; - - p3 = p2 + 1; - - while((*p3 != ':') && (*p3 != '\0')) - { - p3++; - } - - if (*p3 != ':') - return FALSE; - - p4 = p3 + 1; - - while((*p4 != ':') && (*p4 != '\0')) - { - p4++; - } - - if (*p4 != ':') - return FALSE; - - - A2Hex(R1, arg); - A2Hex(R2, p2 + 1); - A2Hex(R3, p3 + 1); - A2Hex(R4, p4 + 1); - - RTMP_RF_IO_WRITE32(pAd, R1); - RTMP_RF_IO_WRITE32(pAd, R2); - RTMP_RF_IO_WRITE32(pAd, R3); - RTMP_RF_IO_WRITE32(pAd, R4); - - return TRUE; -} -#endif // end of #if 0 // -#endif // RALINK_28xx_QA // - -#endif // RALINK_ATE // - diff --git a/drivers/staging/rt2860/rt_ate.h b/drivers/staging/rt2860/rt_ate.h deleted file mode 100644 index 38f5c4af5462..000000000000 --- a/drivers/staging/rt2860/rt_ate.h +++ /dev/null @@ -1,347 +0,0 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - */ - -#ifndef __ATE_H__ -#define __ATE_H__ - -#ifndef UCOS -#define ate_print printk -#define ATEDBGPRINT DBGPRINT -#define EEPROM_SIZE 0x200 -#ifdef CONFIG_STA_SUPPORT -#define EEPROM_BIN_FILE_NAME "/etc/Wireless/RT2860STA/e2p.bin" -#endif // CONFIG_STA_SUPPORT // - -#else // !UCOS // -#define fATE_LOAD_EEPROM 0x0C43 -#ifdef CONFIG_PRINTK -extern INT ConsoleResponse(IN PUCHAR buff); -extern int (*remote_display)(char *); -extern void puts (const char *s); - -/* specificly defined to redirect and show ate-related messages to host. */ -/* Try to define ate_print as a macro. */ -#define ate_print(fmt, args...) \ -do{ int (*org_remote_display)(char *) = NULL; \ - org_remote_display = remote_display;\ - /* Save original "remote_display" */\ - remote_display = (int (*)(char *))ConsoleResponse; \ - printk(fmt, ## args); \ - /* Restore the remote_display function pointer */ \ - remote_display = org_remote_display; }while(0) - -#define ATEDBGPRINT(Level, Fmt) \ -{ \ - if ((Level) <= RTDebugLevel) \ - { \ - ate_print Fmt; \ - } \ -} -#endif // CONFIG_PRINTK // -#endif // !UCOS // - -#define ATE_ON(_p) (((_p)->ate.Mode) != ATE_STOP) - -/* RT2880_iNIC will define "RT2860". */ -#define ATE_BBP_IO_READ8_BY_REG_ID(_A, _I, _pV) \ -{ \ - BBP_CSR_CFG_STRUC BbpCsr; \ - int i, k; \ - for (i=0; iBbpWriteLatch[_I]; \ - } \ -} - -#define ATE_BBP_IO_WRITE8_BY_REG_ID(_A, _I, _V) \ -{ \ - BBP_CSR_CFG_STRUC BbpCsr; \ - int BusyCnt; \ - for (BusyCnt=0; BusyCntBbpWriteLatch[_I] = _V; \ - break; \ - } \ - if (BusyCnt == MAX_BUSY_COUNT) \ - { \ - ATEDBGPRINT(RT_DEBUG_ERROR, ("BBP write R%d fail\n", _I)); \ - } \ -} - -/* RT2880_iNIC will define RT2860. */ -#define EEPROM_SIZE 0x200 -/* iNIC has its own EEPROM_BIN_FILE_NAME */ -#ifndef UCOS -#ifdef CONFIG_STA_SUPPORT -#define EEPROM_BIN_FILE_NAME "/etc/Wireless/RT2860STA/e2p.bin" -#endif // CONFIG_STA_SUPPORT // -#endif // !UCOS // - - - -VOID rt_ee_read_all( - IN PRTMP_ADAPTER pAd, - OUT USHORT *Data); - - -VOID rt_ee_write_all( - IN PRTMP_ADAPTER pAd, - IN USHORT *Data); - -INT Set_ATE_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_DA_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_SA_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_BSSID_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_CHANNEL_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_TX_POWER0_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_TX_POWER1_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_TX_Antenna_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_RX_Antenna_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_TX_FREQOFFSET_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_TX_BW_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_TX_LENGTH_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_TX_COUNT_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_TX_MCS_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_TX_MODE_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_TX_GI_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - - -INT Set_ATE_RX_FER_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_Read_RF_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_Write_RF1_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_Write_RF2_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_Write_RF3_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_Write_RF4_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_Load_E2P_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_Read_E2P_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_Show_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_Help_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -#ifdef RALINK_ATE -#ifdef RALINK_28xx_QA -VOID ATE_QA_Statistics( - IN PRTMP_ADAPTER pAd, - IN PRXWI_STRUC pRxWI, - IN PRT28XX_RXD_STRUC p28xxRxD, - IN PHEADER_802_11 pHeader); - -VOID RtmpDoAte( - IN PRTMP_ADAPTER pAdapter, - IN struct iwreq *wrq); - -VOID BubbleSort( - IN INT32 n, - IN INT32 a[]); - -VOID CalNoiseLevel( - IN PRTMP_ADAPTER pAdapter, - IN UCHAR channel, - OUT INT32 buffer[3][10]); - -BOOLEAN SyncTxRxConfig( - IN PRTMP_ADAPTER pAdapter, - IN USHORT offset, - IN UCHAR value); - -#if 0 -INT Set_TxStart_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); -#endif // 0 // - -INT Set_TxStop_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_RxStop_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -#if 0 -INT Set_EERead_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_EEWrite_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_BBPRead_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_BBPWrite_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_RFWrite_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); -#endif // end of #if 0 // -#endif // RALINK_28xx_QA // -#endif // RALINK_ATE // - -VOID ATEAsicSwitchChannel( - IN PRTMP_ADAPTER pAd); - -VOID ATEAsicAdjustTxPower( - IN PRTMP_ADAPTER pAd); - -VOID ATEDisableAsicProtect( - IN PRTMP_ADAPTER pAd); - -CHAR ATEConvertToRssi( - IN PRTMP_ADAPTER pAd, - IN CHAR Rssi, - IN UCHAR RssiNumber); - -VOID ATESampleRssi( - IN PRTMP_ADAPTER pAd, - IN PRXWI_STRUC pRxWI); - - -#ifdef CONFIG_STA_SUPPORT -VOID RTMPStationStop( - IN PRTMP_ADAPTER pAd); - -VOID RTMPStationStart( - IN PRTMP_ADAPTER pAd); -#endif // CONFIG_STA_SUPPORT // -#endif // __ATE_H__ // diff --git a/drivers/staging/rt2860/rt_config.h b/drivers/staging/rt2860/rt_config.h index a67024fb4373..a19cbe1dedeb 100644 --- a/drivers/staging/rt2860/rt_config.h +++ b/drivers/staging/rt2860/rt_config.h @@ -41,20 +41,18 @@ #define __RT_CONFIG_H__ #include "rtmp_type.h" -#ifdef UCOS -#include "includes.h" -#include -#include "rt_ucos.h" -#endif - #ifdef LINUX #include "rt_linux.h" #endif #include "rtmp_def.h" #include "rt28xx.h" +#ifdef RT2860 #include "rt2860.h" - +#endif +#ifdef RT2870 +#include "../rt2870/rt2870.h" +#endif // RT2870 // #include "oid.h" #include "mlme.h" @@ -66,31 +64,10 @@ #include "chlist.h" #include "spectrum.h" -#ifdef LEAP_SUPPORT -#include "leap.h" -#endif // LEAP_SUPPORT // - -#ifdef BLOCK_NET_IF -#include "netif_block.h" -#endif // BLOCK_NET_IF // - #ifdef IGMP_SNOOP_SUPPORT #include "igmp_snoop.h" #endif // IGMP_SNOOP_SUPPORT // -#ifdef RALINK_ATE -#include "rt_ate.h" -#endif // RALINK_ATE // - -#ifdef CONFIG_STA_SUPPORT -#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT -#ifndef WPA_SUPPLICANT_SUPPORT -#error "Build for being controlled by NetworkManager or wext, please set HAS_WPA_SUPPLICANT=y and HAS_NATIVE_WPA_SUPPLICANT_SUPPORT=y" -#endif // WPA_SUPPLICANT_SUPPORT // -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // - -#endif // CONFIG_STA_SUPPORT // - #ifdef IKANOS_VX_1X0 #include "vr_ikans.h" #endif // IKANOS_VX_1X0 // diff --git a/drivers/staging/rt2860/rt_linux.c b/drivers/staging/rt2860/rt_linux.c index f3c128c72a21..80176b20db07 100644 --- a/drivers/staging/rt2860/rt_linux.c +++ b/drivers/staging/rt2860/rt_linux.c @@ -33,9 +33,10 @@ BUILD_TIMER_FUNCTION(MlmePeriodicExec); BUILD_TIMER_FUNCTION(AsicRxAntEvalTimeout); BUILD_TIMER_FUNCTION(APSDPeriodicExec); BUILD_TIMER_FUNCTION(AsicRfTuningExec); +#ifdef RT2870 +BUILD_TIMER_FUNCTION(BeaconUpdateExec); +#endif // RT2870 // - -#ifdef CONFIG_STA_SUPPORT BUILD_TIMER_FUNCTION(BeaconTimeout); BUILD_TIMER_FUNCTION(ScanTimeout); BUILD_TIMER_FUNCTION(AuthTimeout); @@ -43,17 +44,12 @@ BUILD_TIMER_FUNCTION(AssocTimeout); BUILD_TIMER_FUNCTION(ReassocTimeout); BUILD_TIMER_FUNCTION(DisassocTimeout); BUILD_TIMER_FUNCTION(LinkDownExec); -#ifdef LEAP_SUPPORT -BUILD_TIMER_FUNCTION(LeapAuthTimeout); -#endif BUILD_TIMER_FUNCTION(StaQuickResponeForRateUpExec); BUILD_TIMER_FUNCTION(WpaDisassocApAndBlockAssoc); +#ifdef RT2860 BUILD_TIMER_FUNCTION(PsPollWakeExec); BUILD_TIMER_FUNCTION(RadioOnExec); -#ifdef QOS_DLS_SUPPORT -BUILD_TIMER_FUNCTION(DlsTimeoutAction); -#endif // QOS_DLS_SUPPORT // -#endif // CONFIG_STA_SUPPORT // +#endif // for wireless system event message char const *pWirelessSysEventText[IW_SYS_EVENT_TYPE_NUM] = { @@ -290,9 +286,9 @@ VOID RTMPFreeAdapter( NdisFreeSpinLock(&pAd->MgmtRingLock); - +#ifdef RT2860 NdisFreeSpinLock(&pAd->RxRingLock); - +#endif for (index =0 ; index < NUM_OF_TX_RING; index++) { NdisFreeSpinLock(&pAd->TxSwQueueLock[index]); @@ -495,12 +491,7 @@ PNET_DEV get_netdev_from_bssid( { PNET_DEV dev_p = NULL; -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - dev_p = pAd->net_dev; - } -#endif // CONFIG_STA_SUPPORT // + dev_p = pAd->net_dev; ASSERT(dev_p); return dev_p; /* return one of MBSS */ @@ -656,13 +647,8 @@ void wlan_802_11_to_802_3_packet( // // -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - NdisMoveMemory(skb_push(pOSPkt, LENGTH_802_3), pHeader802_3, LENGTH_802_3); -#endif // CONFIG_STA_SUPPORT // - } - - + NdisMoveMemory(skb_push(pOSPkt, LENGTH_802_3), pHeader802_3, LENGTH_802_3); +} void announce_802_3_packet( IN PRTMP_ADAPTER pAd, @@ -824,8 +810,6 @@ VOID RTMPSendWirelessEvent( #endif /* WIRELESS_EXT >= 15 */ } - -#ifdef CONFIG_STA_SUPPORT void send_monitor_packets( IN PRTMP_ADAPTER pAd, IN RX_BLK *pRxBlk) @@ -850,7 +834,12 @@ void send_monitor_packets( if (pRxBlk->DataSize + sizeof(wlan_ng_prism2_header) > RX_BUFFER_AGGRESIZE) { +#ifndef RT30xx DBGPRINT(RT_DEBUG_ERROR, ("%s : Size is too large! (%zu)\n", __func__, pRxBlk->DataSize + sizeof(wlan_ng_prism2_header))); +#endif +#ifdef RT30xx + DBGPRINT(RT_DEBUG_ERROR, ("%s : Size is too large! (%d)\n", __func__, pRxBlk->DataSize + sizeof(wlan_ng_prism2_header))); +#endif goto err_free_sk_buff; } @@ -957,13 +946,11 @@ void send_monitor_packets( ph->noise.len = 4; ph->noise.data = 0; -#ifdef DOT11_N_SUPPORT if (pRxBlk->pRxWI->PHYMODE >= MODE_HTMIX) { rate_index = 16 + ((UCHAR)pRxBlk->pRxWI->BW *16) + ((UCHAR)pRxBlk->pRxWI->ShortGI *32) + ((UCHAR)pRxBlk->pRxWI->MCS); } else -#endif // DOT11_N_SUPPORT // if (pRxBlk->pRxWI->PHYMODE == MODE_OFDM) rate_index = (UCHAR)(pRxBlk->pRxWI->MCS) + 4; else @@ -996,8 +983,6 @@ err_free_sk_buff: return; } -#endif // CONFIG_STA_SUPPORT // - void rtmp_os_thread_init(PUCHAR pThreadName, PVOID pNotify) { diff --git a/drivers/staging/rt2860/rt_linux.h b/drivers/staging/rt2860/rt_linux.h index 708923cecaa2..85175c182432 100644 --- a/drivers/staging/rt2860/rt_linux.h +++ b/drivers/staging/rt2860/rt_linux.h @@ -42,8 +42,10 @@ #include "rtmp_type.h" #include -#include #include +#if !defined(RT2860) && !defined(RT30xx) +#include +#endif #include #include @@ -65,6 +67,9 @@ #include +#ifdef RT30xx +#include +#endif #include // load firmware @@ -88,23 +93,31 @@ typedef int (*HARD_START_XMIT_FUNC)(struct sk_buff *skb, struct net_device *net_ // add by kathy -#ifdef CONFIG_STA_SUPPORT +#ifdef RT2860 #define STA_PROFILE_PATH "/etc/Wireless/RT2860STA/RT2860STA.dat" #define STA_RTMP_FIRMWARE_FILE_NAME "/etc/Wireless/RT2860STA/RT2860STA.bin" #define STA_NIC_DEVICE_NAME "RT2860STA" #define STA_DRIVER_VERSION "1.8.1.1" -#ifdef MULTIPLE_CARD_SUPPORT -#define CARD_INFO_PATH "/etc/Wireless/RT2860STA/RT2860STACard.dat" -#endif // MULTIPLE_CARD_SUPPORT // - - -#endif // CONFIG_STA_SUPPORT // +#endif +#ifdef RT2870 +#define STA_PROFILE_PATH "/etc/Wireless/RT2870STA/RT2870STA.dat" +#define STA_RT2870_IMAGE_FILE_NAME "/etc/Wireless/RT2870STA/rt2870.bin" +#define STA_NIC_DEVICE_NAME "RT2870STA" +#ifndef RT30xx +#define STA_DRIVER_VERSION "1.4.0.0" +#endif +#ifdef RT30xx +#define STA_DRIVER_VERSION "2.0.1.0" +#endif +#endif +#ifdef RT2860 #ifndef PCI_DEVICE #define PCI_DEVICE(vend,dev) \ .vendor = (vend), .device = (dev), \ .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID #endif // PCI_DEVICE // +#endif #define RTMP_TIME_AFTER(a,b) \ (typecheck(unsigned long, (unsigned long)a) && \ @@ -144,24 +157,23 @@ typedef int (*HARD_START_XMIT_FUNC)(struct sk_buff *skb, struct net_device *net_ #define MIN_NET_DEVICE_FOR_WDS 0x10 //0x40,0x50,0x60,0x70 #define MIN_NET_DEVICE_FOR_APCLI 0x20 #define MIN_NET_DEVICE_FOR_MESH 0x30 -#ifdef CONFIG_STA_SUPPORT #define MIN_NET_DEVICE_FOR_DLS 0x40 -#endif // CONFIG_STA_SUPPORT // - -#ifdef CONFIG_STA_SUPPORT #define NDIS_PACKET_TYPE_DIRECTED 0 #define NDIS_PACKET_TYPE_MULTICAST 1 #define NDIS_PACKET_TYPE_BROADCAST 2 #define NDIS_PACKET_TYPE_ALL_MULTICAST 3 -#endif // CONFIG_STA_SUPPORT // +#ifndef RT30xx typedef struct pid * THREAD_PID; +#ifdef RT2860 #define THREAD_PID_INIT_VALUE NULL +#endif #define GET_PID(_v) find_get_pid(_v) #define GET_PID_NUMBER(_v) pid_nr(_v) #define CHECK_PID_LEGALITY(_pid) if (pid_nr(_pid) >= 0) #define KILL_THREAD_PID(_A, _B, _C) kill_pid(_A, _B, _C) +#endif struct os_lock { spinlock_t lock; @@ -170,10 +182,25 @@ struct os_lock { struct os_cookie { +#ifdef RT2860 struct pci_dev *pci_dev; struct pci_dev *parent_pci_dev; dma_addr_t pAd_pa; +#endif +#ifdef RT2870 + struct usb_device *pUsb_Dev; +#ifndef RT30xx + struct task_struct *MLMEThr_task; + struct task_struct *RTUSBCmdThr_task; + struct task_struct *TimerQThr_task; +#endif +#ifdef RT30xx + struct pid *MLMEThr_pid; + struct pid *RTUSBCmdThr_pid; + struct pid *TimerQThr_pid; +#endif +#endif // RT2870 // struct tasklet_struct rx_done_task; struct tasklet_struct mgmt_dma_done_task; @@ -183,8 +210,14 @@ struct os_cookie { struct tasklet_struct ac3_dma_done_task; struct tasklet_struct hcca_dma_done_task; struct tasklet_struct tbtt_task; +#ifdef RT2860 struct tasklet_struct fifo_statistic_full_task; - +#endif +#ifdef RT2870 + struct tasklet_struct null_frame_complete_task; + struct tasklet_struct rts_frame_complete_task; + struct tasklet_struct pspoll_frame_complete_task; +#endif // RT2870 // unsigned long apd_pid; //802.1x daemon pid INT ioctl_if_type; @@ -198,13 +231,7 @@ typedef struct _VIRTUAL_ADAPTER } VIRTUAL_ADAPTER, PVIRTUAL_ADAPTER; #undef ASSERT -#define ASSERT(x) \ -{ \ - if (!(x)) \ - { \ - printk(KERN_WARNING __FILE__ ":%d assert " #x "failed\n", __LINE__); \ - } \ -} +#define ASSERT(x) typedef struct os_cookie * POS_COOKIE; typedef struct pci_dev * PPCI_DEV; @@ -238,6 +265,7 @@ void linux_pci_unmap_single(void *handle, dma_addr_t dma_addr, size_t size, int #define RT2860_PCI_DEVICE_ID 0x0601 +#ifdef RT2860 #define PCI_MAP_SINGLE(_handle, _ptr, _size, _sd_idx, _dir) \ linux_pci_map_single(_handle, _ptr, _size, _sd_idx, _dir) @@ -252,7 +280,12 @@ void linux_pci_unmap_single(void *handle, dma_addr_t dma_addr, size_t size, int #define DEV_ALLOC_SKB(_length) \ dev_alloc_skb(_length) +#endif +#ifdef RT2870 +#define PCI_MAP_SINGLE(_handle, _ptr, _size, _dir) (ULONG)0 +#define PCI_UNMAP_SINGLE(_handle, _ptr, _size, _dir) +#endif // RT2870 // #define BEACON_FRAME_DMA_CACHE_WBACK(_ptr, _size) \ @@ -266,9 +299,20 @@ void linux_pci_unmap_single(void *handle, dma_addr_t dma_addr, size_t size, int #define NdisMIndicateStatus(_w, _x, _y, _z) - typedef struct timer_list RTMP_OS_TIMER; +#ifdef RT2870 +/* ----------------- Timer Related MARCO ---------------*/ +// In RT2870, we have a lot of timer functions and will read/write register, it's +// not allowed in Linux USB sub-system to do it ( because of sleep issue when submit +// to ctrl pipe). So we need a wrapper function to take care it. + +typedef VOID (*RT2870_TIMER_HANDLE)( + IN PVOID SystemSpecific1, + IN PVOID FunctionContext, + IN PVOID SystemSpecific2, + IN PVOID SystemSpecific3); +#endif // RT2870 // typedef struct _RALINK_TIMER_STRUCT { @@ -279,9 +323,42 @@ typedef struct _RALINK_TIMER_STRUCT { BOOLEAN Repeat; // True if periodic timer ULONG TimerValue; // Timer value in milliseconds ULONG cookie; // os specific object +#ifdef RT2870 + RT2870_TIMER_HANDLE handle; + void *pAd; +#endif // RT2870 // } RALINK_TIMER_STRUCT, *PRALINK_TIMER_STRUCT; +#ifdef RT2870 + +typedef enum _RT2870_KERNEL_THREAD_STATUS_ +{ + RT2870_THREAD_UNKNOWN = 0, + RT2870_THREAD_INITED = 1, + RT2870_THREAD_RUNNING = 2, + RT2870_THREAD_STOPED = 4, +}RT2870_KERNEL_THREAD_STATUS; + +#define RT2870_THREAD_CAN_DO_INSERT (RT2870_THREAD_INITED |RT2870_THREAD_RUNNING) + +typedef struct _RT2870_TIMER_ENTRY_ +{ + RALINK_TIMER_STRUCT *pRaTimer; + struct _RT2870_TIMER_ENTRY_ *pNext; +}RT2870_TIMER_ENTRY; + + +#define TIMER_QUEUE_SIZE_MAX 128 +typedef struct _RT2870_TIMER_QUEUE_ +{ + unsigned int status; + UCHAR *pTimerQPoll; + RT2870_TIMER_ENTRY *pQPollFreeList; + RT2870_TIMER_ENTRY *pQHead; + RT2870_TIMER_ENTRY *pQTail; +}RT2870_TIMER_QUEUE; +#endif // RT2870 // //#define DBG 1 @@ -371,6 +448,7 @@ extern ULONG RTDebugLevel; spin_unlock_irqrestore((spinlock_t *)(__lock), ((unsigned long)__irqflag)); \ } +#ifdef RT2860 #if defined(INF_TWINPASS) || defined(INF_DANUBE) || defined(IKANOS_VX_1X0) //Patch for ASIC turst read/write bug, needs to remove after metel fix #define RTMP_IO_READ32(_A, _R, _pV) \ @@ -472,7 +550,32 @@ extern ULONG RTDebugLevel; writew((_V), (PUSHORT)((_A)->CSRBaseAddress + (_R))); \ } #endif +#endif /* RT2860 */ +#ifdef RT2870 +//Patch for ASIC turst read/write bug, needs to remove after metel fix +#define RTMP_IO_READ32(_A, _R, _pV) \ + RTUSBReadMACRegister(_A, _R, _pV) +#define RTMP_IO_READ8(_A, _R, _pV) \ +{ \ +} + +#define RTMP_IO_WRITE32(_A, _R, _V) \ + RTUSBWriteMACRegister(_A, _R, _V) + + +#define RTMP_IO_WRITE8(_A, _R, _V) \ +{ \ + USHORT _Val = _V; \ + RTUSBSingleWrite(_A, _R, _Val); \ +} + + +#define RTMP_IO_WRITE16(_A, _R, _V) \ +{ \ + RTUSBSingleWrite(_A, _R, _V); \ +} +#endif // RT2870 // #ifndef wait_event_interruptible_timeout #define __wait_event_interruptible_timeout(wq, condition, ret) \ @@ -515,7 +618,6 @@ do { \ wait_event_interruptible_timeout(_wait, 0, ONE_TICK); } -/* Modified by Wu Xi-Kun 4/21/2006 */ typedef void (*TIMER_FUNCTION)(unsigned long); #define COPY_MAC_ADDR(Addr1, Addr2) memcpy((Addr1), (Addr2), MAC_ADDR_LEN) @@ -523,6 +625,7 @@ typedef void (*TIMER_FUNCTION)(unsigned long); #define MlmeAllocateMemory(_pAd, _ppVA) os_alloc_mem(_pAd, _ppVA, MGMT_DMA_BUFFER_SIZE) #define MlmeFreeMemory(_pAd, _pVA) os_free_mem(_pAd, _pVA) +#ifdef RT2860 #define BUILD_TIMER_FUNCTION(_func) \ void linux_##_func(unsigned long data) \ { \ @@ -532,7 +635,22 @@ void linux_##_func(unsigned long data) \ if (pTimer->Repeat) \ RTMP_OS_Add_Timer(&pTimer->TimerObj, pTimer->TimerValue); \ } - +#endif +#ifdef RT2870 +#define BUILD_TIMER_FUNCTION(_func) \ +void linux_##_func(unsigned long data) \ +{ \ + PRALINK_TIMER_STRUCT _pTimer = (PRALINK_TIMER_STRUCT)data; \ + RT2870_TIMER_ENTRY *_pQNode; \ + RTMP_ADAPTER *_pAd; \ + \ + _pTimer->handle = _func; \ + _pAd = (RTMP_ADAPTER *)_pTimer->pAd; \ + _pQNode = RT2870_TimerQ_Insert(_pAd, _pTimer); \ + if ((_pQNode == NULL) && (_pAd->TimerQ.status & RT2870_THREAD_CAN_DO_INSERT)) \ + RTMP_OS_Add_Timer(&_pTimer->TimerObj, HZ); \ +} +#endif // RT2870 // #define DECLARE_TIMER_FUNCTION(_func) \ @@ -546,9 +664,10 @@ DECLARE_TIMER_FUNCTION(MlmeRssiReportExec); DECLARE_TIMER_FUNCTION(AsicRxAntEvalTimeout); DECLARE_TIMER_FUNCTION(APSDPeriodicExec); DECLARE_TIMER_FUNCTION(AsicRfTuningExec); +#ifdef RT2870 +DECLARE_TIMER_FUNCTION(BeaconUpdateExec); +#endif // RT2870 // - -#ifdef CONFIG_STA_SUPPORT DECLARE_TIMER_FUNCTION(BeaconTimeout); DECLARE_TIMER_FUNCTION(ScanTimeout); DECLARE_TIMER_FUNCTION(AuthTimeout); @@ -556,19 +675,11 @@ DECLARE_TIMER_FUNCTION(AssocTimeout); DECLARE_TIMER_FUNCTION(ReassocTimeout); DECLARE_TIMER_FUNCTION(DisassocTimeout); DECLARE_TIMER_FUNCTION(LinkDownExec); -#ifdef LEAP_SUPPORT -DECLARE_TIMER_FUNCTION(LeapAuthTimeout); -#endif DECLARE_TIMER_FUNCTION(StaQuickResponeForRateUpExec); DECLARE_TIMER_FUNCTION(WpaDisassocApAndBlockAssoc); DECLARE_TIMER_FUNCTION(PsPollWakeExec); DECLARE_TIMER_FUNCTION(RadioOnExec); -#ifdef QOS_DLS_SUPPORT -DECLARE_TIMER_FUNCTION(DlsTimeoutAction); -#endif // QOS_DLS_SUPPORT // -#endif // CONFIG_STA_SUPPORT // - void RTMP_GetCurrentSystemTime(LARGE_INTEGER *time); @@ -676,10 +787,6 @@ void RTMP_GetCurrentSystemTime(LARGE_INTEGER *time); #define RTMP_GET_PACKET_MOREDATA(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+7]) -#if 0 -//#define RTMP_SET_PACKET_DHCP(_p, _flg) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11] = _flg) -//#define RTMP_GET_PACKET_DHCP(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) -#else // // Sepcific Pakcet Type definition // @@ -759,8 +866,6 @@ void RTMP_GetCurrentSystemTime(LARGE_INTEGER *time); #define RTMP_GET_PACKET_IPV4(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11] & RTMP_PACKET_SPECIFIC_IPV4) -#endif - // If this flag is set, it indicates that this EAPoL frame MUST be clear. #define RTMP_SET_PACKET_CLEAR_EAP_FRAME(_p, _flg) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+12] = _flg) @@ -884,6 +989,7 @@ int rt28xx_packet_xmit(struct sk_buff *skb); void rtmp_os_thread_init(PUCHAR pThreadName, PVOID pNotify); +#ifdef RT2860 #if !defined(PCI_CAP_ID_EXP) #define PCI_CAP_ID_EXP 0x10 #endif @@ -897,5 +1003,5 @@ void rtmp_os_thread_init(PUCHAR pThreadName, PVOID pNotify); #endif #define PCIBUS_INTEL_VENDOR 0x8086 - +#endif diff --git a/drivers/staging/rt2860/rt_main_dev.c b/drivers/staging/rt2860/rt_main_dev.c index 6c4396f0903b..f298b9bcec39 100644 --- a/drivers/staging/rt2860/rt_main_dev.c +++ b/drivers/staging/rt2860/rt_main_dev.c @@ -40,17 +40,6 @@ #define FORTY_MHZ_INTOLERANT_INTERVAL (60*1000) // 1 min -#ifdef MULTIPLE_CARD_SUPPORT -// record whether the card in the card list is used in the card file -UINT8 MC_CardUsed[MAX_NUM_OF_MULTIPLE_CARD]; -// record used card mac address in the card list -static UINT8 MC_CardMac[MAX_NUM_OF_MULTIPLE_CARD][6]; -#endif // MULTIPLE_CARD_SUPPORT // - -#ifdef CONFIG_APSTA_MIXED_SUPPORT -UINT32 CW_MAX_IN_BITS; -#endif // CONFIG_APSTA_MIXED_SUPPORT // - /*---------------------------------------------------------------------*/ /* Private Variables Used */ /*---------------------------------------------------------------------*/ @@ -65,13 +54,13 @@ MODULE_PARM_DESC (mac, "rt28xx: wireless mac addr"); /*---------------------------------------------------------------------*/ /* Prototypes of Functions Used */ /*---------------------------------------------------------------------*/ -#ifdef DOT11_N_SUPPORT extern BOOLEAN ba_reordering_resource_init(PRTMP_ADAPTER pAd, int num); extern void ba_reordering_resource_release(PRTMP_ADAPTER pAd); -#endif // DOT11_N_SUPPORT // extern NDIS_STATUS NICLoadRateSwitchingParams(IN PRTMP_ADAPTER pAd); +#ifdef RT2860 extern void init_thread_task(PRTMP_ADAPTER pAd); +#endif // public function prototype INT __devinit rt28xx_probe(IN void *_dev_p, IN void *_dev_id_p, @@ -83,13 +72,7 @@ INT rt28xx_send_packets(IN struct sk_buff *skb_p, IN struct net_device *net_dev) static void CfgInitHook(PRTMP_ADAPTER pAd); -#ifdef CONFIG_STA_SUPPORT extern const struct iw_handler_def rt28xx_iw_handler_def; -#endif // CONFIG_STA_SUPPORT // - -#ifdef CONFIG_APSTA_MIXED_SUPPORT -extern const struct iw_handler_def rt28xx_ap_iw_handler_def; -#endif // CONFIG_APSTA_MIXED_SUPPORT // #if WIRELESS_EXT >= 12 // This function will be called when query /proc @@ -206,6 +189,12 @@ int rt28xx_close(IN PNET_DEV dev) RTMP_ADAPTER *pAd = net_dev->ml_priv; BOOLEAN Cancelled = FALSE; UINT32 i = 0; +#ifdef RT2870 + DECLARE_WAIT_QUEUE_HEAD(unlink_wakeup); + DECLARE_WAITQUEUE(wait, current); + + //RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_REMOVE_IN_PROGRESS); +#endif // RT2870 // DBGPRINT(RT_DEBUG_TRACE, ("===> rt28xx_close\n")); @@ -214,54 +203,26 @@ int rt28xx_close(IN PNET_DEV dev) if (pAd == NULL) return 0; // close ok - -#ifdef WDS_SUPPORT - WdsDown(pAd); -#endif // WDS_SUPPORT // - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { // If dirver doesn't wake up firmware here, // NICLoadFirmware will hang forever when interface is up again. +#ifdef RT2860 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE) || RTMP_SET_PSFLAG(pAd, fRTMP_PS_SET_PCI_CLK_OFF_COMMAND) || RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF)) +#endif +#ifdef RT2870 + if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) +#endif { +#ifdef RT2860 AsicForceWakeup(pAd, RTMP_HALT); +#endif +#ifdef RT2870 + AsicForceWakeup(pAd, TRUE); +#endif } -#ifdef QOS_DLS_SUPPORT - // send DLS-TEAR_DOWN message, - if (pAd->CommonCfg.bDLSCapable) - { - UCHAR i; - - // tear down local dls table entry - for (i=0; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH)) - { - RTMPSendDLSTearDownFrame(pAd, pAd->StaCfg.DLSEntry[i].MacAddr); - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - pAd->StaCfg.DLSEntry[i].Valid = FALSE; - } - } - - // tear down peer dls table entry - for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH)) - { - RTMPSendDLSTearDownFrame(pAd, pAd->StaCfg.DLSEntry[i].MacAddr); - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - pAd->StaCfg.DLSEntry[i].Valid = FALSE; - } - } - RT28XX_MLME_HANDLER(pAd); - } -#endif // QOS_DLS_SUPPORT // - if (INFRA_ON(pAd) && (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))) { @@ -287,6 +248,9 @@ int rt28xx_close(IN PNET_DEV dev) RTMPusecDelay(1000); } +#ifdef RT2870 + RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_REMOVE_IN_PROGRESS); +#endif // RT2870 // #ifdef CCX_SUPPORT RTMPCancelTimer(&pAd->StaCfg.LeapAuthTimer, &Cancelled); @@ -295,22 +259,11 @@ int rt28xx_close(IN PNET_DEV dev) RTMPCancelTimer(&pAd->StaCfg.StaQuickResponeForRateUpTimer, &Cancelled); RTMPCancelTimer(&pAd->StaCfg.WpaDisassocAndBlockAssocTimer, &Cancelled); -#ifdef WPA_SUPPLICANT_SUPPORT -#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT - { - union iwreq_data wrqu; - // send wireless event to wpa_supplicant for infroming interface down. - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.flags = RT_INTERFACE_DOWN; - wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); - } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // -#endif // WPA_SUPPLICANT_SUPPORT // - MlmeRadioOff(pAd); +#ifdef RT2860 pAd->bPCIclkOff = FALSE; +#endif } -#endif // CONFIG_STA_SUPPORT // RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS); @@ -323,25 +276,52 @@ int rt28xx_close(IN PNET_DEV dev) } } +#ifdef RT2870 + // ensure there are no more active urbs. + add_wait_queue (&unlink_wakeup, &wait); + pAd->wait = &unlink_wakeup; + + // maybe wait for deletions to finish. + i = 0; + //while((i < 25) && atomic_read(&pAd->PendingRx) > 0) + while(i < 25) + { + unsigned long IrqFlags; + + RTMP_IRQ_LOCK(&pAd->BulkInLock, IrqFlags); + if (pAd->PendingRx == 0) + { + RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); + break; + } + RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); + + msleep(UNLINK_TIMEOUT_MS); //Time in millisecond + i++; + } + pAd->wait = NULL; + remove_wait_queue (&unlink_wakeup, &wait); +#endif // RT2870 // + +#ifdef RT2870 + // We need clear timerQ related structure before exits of the timer thread. + RT2870_TimerQ_Exit(pAd); + // Close kernel threads or tasklets + RT28xxThreadTerminate(pAd); +#endif // RT2870 // + // Stop Mlme state machine MlmeHalt(pAd); // Close kernel threads or tasklets kill_thread_task(pAd); - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - MacTableReset(pAd); - } -#endif // CONFIG_STA_SUPPORT // - + MacTableReset(pAd); MeasureReqTabExit(pAd); TpcReqTabExit(pAd); - +#ifdef RT2860 if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_ACTIVE)) { NICDisableInterrupt(pAd); @@ -357,18 +337,15 @@ int rt28xx_close(IN PNET_DEV dev) RT28XX_IRQ_RELEASE(net_dev) RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE); } - +#endif // Free Ring or USB buffers RTMPFreeTxRxRingMemory(pAd); RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS); -#ifdef DOT11_N_SUPPORT // Free BA reorder resource ba_reordering_resource_release(pAd); -#endif // DOT11_N_SUPPORT // - RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_START_UP); @@ -377,17 +354,19 @@ int rt28xx_close(IN PNET_DEV dev) static int rt28xx_init(IN struct net_device *net_dev) { +#ifdef RT2860 PRTMP_ADAPTER pAd = (PRTMP_ADAPTER)net_dev->ml_priv; +#endif +#ifdef RT2870 + PRTMP_ADAPTER pAd = net_dev->ml_priv; +#endif UINT index; UCHAR TmpPhy; NDIS_STATUS Status; UINT32 MacCsr0 = 0; - -#ifdef DOT11_N_SUPPORT // Allocate BA Reordering memory ba_reordering_resource_init(pAd, MAX_REORDERING_MPDU_NUM); -#endif // DOT11_N_SUPPORT // // Make sure MAC gets ready. index = 0; @@ -403,11 +382,11 @@ static int rt28xx_init(IN struct net_device *net_dev) } while (index++ < 100); DBGPRINT(RT_DEBUG_TRACE, ("MAC_CSR0 [ Ver:Rev=0x%08x]\n", pAd->MACVersion)); +/*Iverson patch PCIE L1 issue */ // Disable DMA RT28XXDMADisable(pAd); - // Load 8051 firmware Status = NICLoadFirmware(pAd); if (Status != NDIS_STATUS_SUCCESS) @@ -420,10 +399,12 @@ static int rt28xx_init(IN struct net_device *net_dev) // Disable interrupts here which is as soon as possible // This statement should never be true. We might consider to remove it later +#ifdef RT2860 if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_ACTIVE)) { NICDisableInterrupt(pAd); } +#endif Status = RTMPAllocTxRxRingMemory(pAd); if (Status != NDIS_STATUS_SUCCESS) @@ -448,6 +429,10 @@ static int rt28xx_init(IN struct net_device *net_dev) // UserCfgInit(pAd); +#ifdef RT2870 + // We need init timerQ related structure before create the timer thread. + RT2870_TimerQ_Init(pAd); +#endif // RT2870 // RT28XX_TASK_THREAD_INIT(pAd, Status); if (Status != NDIS_STATUS_SUCCESS) @@ -455,15 +440,7 @@ static int rt28xx_init(IN struct net_device *net_dev) CfgInitHook(pAd); - -#ifdef BLOCK_NET_IF - initblockQueueTab(pAd); -#endif // BLOCK_NET_IF // - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - NdisAllocateSpinLock(&pAd->MacTabLock); -#endif // CONFIG_STA_SUPPORT // + NdisAllocateSpinLock(&pAd->MacTabLock); MeasureReqTabInit(pAd); TpcReqTabInit(pAd); @@ -489,10 +466,17 @@ static int rt28xx_init(IN struct net_device *net_dev) goto err4; } +#ifdef RT2870 + pAd->CommonCfg.bMultipleIRP = FALSE; + + if (pAd->CommonCfg.bMultipleIRP) + pAd->CommonCfg.NumOfBulkInIRP = RX_RING_SIZE; + else + pAd->CommonCfg.NumOfBulkInIRP = 1; +#endif // RT2870 // //Init Ba Capability parameters. -#ifdef DOT11_N_SUPPORT pAd->CommonCfg.DesiredHtPhy.MpduDensity = (UCHAR)pAd->CommonCfg.BACapability.field.MpduDensity; pAd->CommonCfg.DesiredHtPhy.AmsduEnable = (USHORT)pAd->CommonCfg.BACapability.field.AmsduEnable; pAd->CommonCfg.DesiredHtPhy.AmsduSize = (USHORT)pAd->CommonCfg.BACapability.field.AmsduSize; @@ -501,7 +485,6 @@ static int rt28xx_init(IN struct net_device *net_dev) pAd->CommonCfg.HtCapability.HtCapInfo.MimoPs = (USHORT)pAd->CommonCfg.BACapability.field.MMPSmode; pAd->CommonCfg.HtCapability.HtCapInfo.AMsduSize = (USHORT)pAd->CommonCfg.BACapability.field.AmsduSize; pAd->CommonCfg.HtCapability.HtCapParm.MpduDensity = (UCHAR)pAd->CommonCfg.BACapability.field.MpduDensity; -#endif // DOT11_N_SUPPORT // printk("2. Phy Mode = %d\n", pAd->CommonCfg.PhyMode); @@ -516,9 +499,7 @@ static int rt28xx_init(IN struct net_device *net_dev) TmpPhy = pAd->CommonCfg.PhyMode; pAd->CommonCfg.PhyMode = 0xff; RTMPSetPhyMode(pAd, TmpPhy); -#ifdef DOT11_N_SUPPORT SetCommonHT(pAd); -#endif // DOT11_N_SUPPORT // // No valid channels. if (pAd->ChannelListNum == 0) @@ -527,11 +508,14 @@ static int rt28xx_init(IN struct net_device *net_dev) goto err4; } -#ifdef DOT11_N_SUPPORT printk("MCS Set = %02x %02x %02x %02x %02x\n", pAd->CommonCfg.HtCapability.MCSSet[0], pAd->CommonCfg.HtCapability.MCSSet[1], pAd->CommonCfg.HtCapability.MCSSet[2], pAd->CommonCfg.HtCapability.MCSSet[3], pAd->CommonCfg.HtCapability.MCSSet[4]); -#endif // DOT11_N_SUPPORT // + +#ifdef RT2870 + //Init RT30xx RFRegisters after read RFIC type from EEPROM + NICInitRT30xxRFRegisters(pAd); +#endif // RT2870 // #ifdef IKANOS_VX_1X0 VR_IKANOS_FP_Init(pAd->ApCfg.BssidNum, pAd->PermanentAddress); @@ -543,8 +527,10 @@ static int rt28xx_init(IN struct net_device *net_dev) AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); AsicLockChannel(pAd, pAd->CommonCfg.Channel); +#ifndef RT30xx // 8051 firmware require the signal during booting time. AsicSendCommandToMcu(pAd, 0x72, 0xFF, 0x00, 0x00); +#endif if (pAd && (Status != NDIS_STATUS_SUCCESS)) { @@ -561,9 +547,24 @@ static int rt28xx_init(IN struct net_device *net_dev) // Microsoft HCT require driver send a disconnect event after driver initialization. OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED); RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_MEDIA_STATE_CHANGE); + DBGPRINT(RT_DEBUG_TRACE, ("NDIS_STATUS_MEDIA_DISCONNECT Event B!\n")); +#ifdef RT2870 + RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS); + RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_REMOVE_IN_PROGRESS); + + // + // Support multiple BulkIn IRP, + // the value on pAd->CommonCfg.NumOfBulkInIRP may be large than 1. + // + for(index=0; indexCommonCfg.NumOfBulkInIRP; index++) + { + RTUSBBulkReceive(pAd); + DBGPRINT(RT_DEBUG_TRACE, ("RTUSBBulkReceive!\n" )); + } +#endif // RT2870 // }// end of else @@ -578,17 +579,12 @@ err3: err2: RTMPFreeTxRxRingMemory(pAd); err1: - -#ifdef DOT11_N_SUPPORT os_free_mem(pAd, pAd->mpdu_blk_pool.mem); // free BA pool -#endif // DOT11_N_SUPPORT // RT28XX_IRQ_RELEASE(net_dev); // shall not set ml_priv to NULL here because the ml_priv didn't been free yet. //net_dev->ml_priv = 0; -#ifdef INF_AMAZON_SE -err0: -#endif // INF_AMAZON_SE // + printk("!!! %s Initialized fail !!!\n", RT28xx_CHIP_NAME); return FALSE; } /* End of rt28xx_init */ @@ -625,27 +621,6 @@ int rt28xx_open(IN PNET_DEV dev) return -1; } -#ifdef CONFIG_APSTA_MIXED_SUPPORT - if (pAd->OpMode == OPMODE_AP) - { - CW_MAX_IN_BITS = 6; - } - else if (pAd->OpMode == OPMODE_STA) - { - CW_MAX_IN_BITS = 10; - } - -#if WIRELESS_EXT >= 12 - if (net_dev->priv_flags == INT_MAIN) - { - if (pAd->OpMode == OPMODE_AP) - net_dev->wireless_handlers = (struct iw_handler_def *) &rt28xx_ap_iw_handler_def; - else if (pAd->OpMode == OPMODE_STA) - net_dev->wireless_handlers = (struct iw_handler_def *) &rt28xx_iw_handler_def; - } -#endif // WIRELESS_EXT >= 12 // -#endif // CONFIG_APSTA_MIXED_SUPPORT // - // Init pObj = (POS_COOKIE)pAd->OS_Cookie; @@ -664,13 +639,8 @@ int rt28xx_open(IN PNET_DEV dev) if (rt28xx_init(net_dev) == FALSE) goto err; -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - NdisZeroMemory(pAd->StaCfg.dev_name, 16); - NdisMoveMemory(pAd->StaCfg.dev_name, net_dev->name, strlen(net_dev->name)); - } -#endif // CONFIG_STA_SUPPORT // + NdisZeroMemory(pAd->StaCfg.dev_name, 16); + NdisMoveMemory(pAd->StaCfg.dev_name, net_dev->name, strlen(net_dev->name)); // Set up the Mac address NdisMoveMemory(net_dev->dev_addr, (void *) pAd->CurrentAddress, 6); @@ -680,24 +650,6 @@ int rt28xx_open(IN PNET_DEV dev) // Various AP function init -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { -#ifdef WPA_SUPPLICANT_SUPPORT -#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT - { - union iwreq_data wrqu; - // send wireless event to wpa_supplicant for infroming interface down. - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.flags = RT_INTERFACE_UP; - wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); - } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // -#endif // WPA_SUPPLICANT_SUPPORT // - - } -#endif // CONFIG_STA_SUPPORT // - // Enable Interrupt RT28XX_IRQ_ENABLE(pAd); @@ -711,11 +663,9 @@ int rt28xx_open(IN PNET_DEV dev) printk("0x1300 = %08x\n", reg); } -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) +#ifdef RT2860 RTMPInitPCIeLinkCtrlValue(pAd); -#endif // CONFIG_STA_SUPPORT // - +#endif return (retval); err: @@ -745,26 +695,12 @@ static NDIS_STATUS rt_ieee80211_if_setup(struct net_device *dev, PRTMP_ADAPTER p CHAR slot_name[IFNAMSIZ]; struct net_device *device; - - //ether_setup(dev); - -#ifdef CONFIG_STA_SUPPORT #if WIRELESS_EXT >= 12 if (pAd->OpMode == OPMODE_STA) { dev->wireless_handlers = &rt28xx_iw_handler_def; } #endif //WIRELESS_EXT >= 12 -#endif // CONFIG_STA_SUPPORT // - -#ifdef CONFIG_APSTA_MIXED_SUPPORT -#if WIRELESS_EXT >= 12 - if (pAd->OpMode == OPMODE_AP) - { - dev->wireless_handlers = &rt28xx_ap_iw_handler_def; - } -#endif //WIRELESS_EXT >= 12 -#endif // CONFIG_APSTA_MIXED_SUPPORT // #if WIRELESS_EXT < 21 dev->get_wireless_stats = rt28xx_get_wireless_stats; @@ -774,11 +710,6 @@ static NDIS_STATUS rt_ieee80211_if_setup(struct net_device *dev, PRTMP_ADAPTER p // find available device name for (i = 0; i < 8; i++) { -#ifdef MULTIPLE_CARD_SUPPORT - if (pAd->MC_RowID >= 0) - sprintf(slot_name, "ra%02d_%d", pAd->MC_RowID, i); - else -#endif // MULTIPLE_CARD_SUPPORT // sprintf(slot_name, "ra%d", i); device = dev_get_by_name(dev_net(dev), slot_name); @@ -796,11 +727,6 @@ static NDIS_STATUS rt_ieee80211_if_setup(struct net_device *dev, PRTMP_ADAPTER p } else { -#ifdef MULTIPLE_CARD_SUPPORT - if (pAd->MC_RowID >= 0) - sprintf(dev->name, "ra%02d_%d", pAd->MC_RowID, i); - else -#endif // MULTIPLE_CARD_SUPPORT // sprintf(dev->name, "ra%d", i); Status = NDIS_STATUS_SUCCESS; } @@ -809,369 +735,6 @@ static NDIS_STATUS rt_ieee80211_if_setup(struct net_device *dev, PRTMP_ADAPTER p } - -#ifdef MULTIPLE_CARD_SUPPORT -/* -======================================================================== -Routine Description: - Get card profile path. - -Arguments: - pAd - -Return Value: - TRUE - Find a card profile - FALSE - use default profile - -Note: -======================================================================== -*/ -extern INT RTMPGetKeyParameter( - IN PCHAR key, - OUT PCHAR dest, - IN INT destsize, - IN PCHAR buffer); - -BOOLEAN RTMP_CardInfoRead( - IN PRTMP_ADAPTER pAd) -{ -#define MC_SELECT_CARDID 0 /* use CARD ID (0 ~ 31) to identify different cards */ -#define MC_SELECT_MAC 1 /* use CARD MAC to identify different cards */ -#define MC_SELECT_CARDTYPE 2 /* use CARD type (abgn or bgn) to identify different cards */ - -#define LETTER_CASE_TRANSLATE(txt_p, card_id) \ - { UINT32 _len; char _char; \ - for(_len=0; _lenfsuid; - orgfsgid = current->fsgid; - current->fsuid = current->fsgid = 0; - orgfs = get_fs(); - set_fs(KERNEL_DS); - - // get RF IC type - RTMP_IO_READ32(pAd, E2PROM_CSR, &data); - - if ((data & 0x30) == 0) - pAd->EEPROMAddressNum = 6; // 93C46 - else if ((data & 0x30) == 0x10) - pAd->EEPROMAddressNum = 8; // 93C66 - else - pAd->EEPROMAddressNum = 8; // 93C86 - - RT28xx_EEPROM_READ16(pAd, EEPROM_NIC1_OFFSET, antenna.word); - - if ((antenna.field.RfIcType == RFIC_2850) || - (antenna.field.RfIcType == RFIC_2750)) - { - /* ABGN card */ - strcpy(RFIC_word, "abgn"); - } - else - { - /* BGN card */ - strcpy(RFIC_word, "bgn"); - } - - // get MAC address - RT28xx_EEPROM_READ16(pAd, 0x04, addr01); - RT28xx_EEPROM_READ16(pAd, 0x06, addr23); - RT28xx_EEPROM_READ16(pAd, 0x08, addr45); - - mac[0] = (UCHAR)(addr01 & 0xff); - mac[1] = (UCHAR)(addr01 >> 8); - mac[2] = (UCHAR)(addr23 & 0xff); - mac[3] = (UCHAR)(addr23 >> 8); - mac[4] = (UCHAR)(addr45 & 0xff); - mac[5] = (UCHAR)(addr45 >> 8); - - // open card information file - srcf = filp_open(CARD_INFO_PATH, O_RDONLY, 0); - if (IS_ERR(srcf)) - { - /* card information file does not exist */ - DBGPRINT(RT_DEBUG_TRACE, - ("--> Error %ld opening %s\n", -PTR_ERR(srcf), CARD_INFO_PATH)); - return FALSE; - } - - if (srcf->f_op && srcf->f_op->read) - { - /* card information file exists so reading the card information */ - memset(buffer, 0x00, MAX_INI_BUFFER_SIZE); - retval = srcf->f_op->read(srcf, buffer, MAX_INI_BUFFER_SIZE, &srcf->f_pos); - if (retval < 0) - { - /* read fail */ - DBGPRINT(RT_DEBUG_TRACE, - ("--> Read %s error %d\n", CARD_INFO_PATH, -retval)); - } - else - { - /* get card selection method */ - memset(tmpbuf, 0x00, MAX_PARAM_BUFFER_SIZE); - card_select_method = MC_SELECT_CARDTYPE; // default - - if (RTMPGetKeyParameter("SELECT", tmpbuf, 256, buffer)) - { - if (strcmp(tmpbuf, "CARDID") == 0) - card_select_method = MC_SELECT_CARDID; - else if (strcmp(tmpbuf, "MAC") == 0) - card_select_method = MC_SELECT_MAC; - else if (strcmp(tmpbuf, "CARDTYPE") == 0) - card_select_method = MC_SELECT_CARDTYPE; - } - - DBGPRINT(RT_DEBUG_TRACE, - ("MC> Card Selection = %d\n", card_select_method)); - - // init - card_free_id = -1; - card_nouse_id = -1; - card_same_mac_id = -1; - card_match_id = -1; - - // search current card information records - for(card_index=0; - card_index Free = %d, Same = %d, NOUSE = %d\n", - card_free_id, card_same_mac_id, card_nouse_id)); - - if ((card_same_mac_id >= 0) && - ((card_select_method == MC_SELECT_CARDID) || - (card_select_method == MC_SELECT_CARDTYPE))) - { - // same MAC entry is found - card_match_id = card_same_mac_id; - - if (card_select_method == MC_SELECT_CARDTYPE) - { - // for CARDTYPE - sprintf(card_id_buf, "%02dCARDTYPE%s", - card_match_id, RFIC_word); - - if ((start_ptr=rtstrstruncasecmp(buffer, card_id_buf)) != NULL) - { - // we found the card ID - LETTER_CASE_TRANSLATE(start_ptr, card_id_buf); - } - } - } - else - { - // the card is 1st plug-in, try to find the match card profile - switch(card_select_method) - { - case MC_SELECT_CARDID: // CARDID - default: - if (card_free_id >= 0) - card_match_id = card_free_id; - else - card_match_id = card_nouse_id; - break; - - case MC_SELECT_MAC: // MAC - sprintf(card_id_buf, "MAC%02x:%02x:%02x:%02x:%02x:%02x", - mac[0], mac[1], mac[2], - mac[3], mac[4], mac[5]); - - /* try to find the key word in the card file */ - if ((start_ptr=rtstrstruncasecmp(buffer, card_id_buf)) != NULL) - { - LETTER_CASE_TRANSLATE(start_ptr, card_id_buf); - - /* get the row ID (2 ASCII characters) */ - start_ptr -= 2; - card_id_buf[0] = *(start_ptr); - card_id_buf[1] = *(start_ptr+1); - card_id_buf[2] = 0x00; - - card_match_id = simple_strtol(card_id_buf, 0, 10); - } - break; - - case MC_SELECT_CARDTYPE: // CARDTYPE - card_nouse_id = -1; - - for(card_index=0; - card_index= 0) - { - // make up search keyword - switch(card_select_method) - { - case MC_SELECT_CARDID: // CARDID - sprintf(card_id_buf, "%02dCARDID", card_match_id); - break; - - case MC_SELECT_MAC: // MAC - sprintf(card_id_buf, - "%02dmac%02x:%02x:%02x:%02x:%02x:%02x", - card_match_id, - mac[0], mac[1], mac[2], - mac[3], mac[4], mac[5]); - break; - - case MC_SELECT_CARDTYPE: // CARDTYPE - default: - sprintf(card_id_buf, "%02dcardtype%s", - card_match_id, RFIC_word); - break; - } - - DBGPRINT(RT_DEBUG_TRACE, ("Search Keyword = %s\n", card_id_buf)); - - // read card file path - if (RTMPGetKeyParameter(card_id_buf, tmpbuf, 256, buffer)) - { - if (strlen(tmpbuf) < sizeof(pAd->MC_FileName)) - { - // backup card information - pAd->MC_RowID = card_match_id; /* base 0 */ - MC_CardUsed[card_match_id] = 1; - memcpy(MC_CardMac[card_match_id], mac, sizeof(mac)); - - // backup card file path - NdisMoveMemory(pAd->MC_FileName, tmpbuf , strlen(tmpbuf)); - pAd->MC_FileName[strlen(tmpbuf)] = '\0'; - flg_match_ok = TRUE; - - DBGPRINT(RT_DEBUG_TRACE, - ("Card Profile Name = %s\n", pAd->MC_FileName)); - } - else - { - DBGPRINT(RT_DEBUG_ERROR, - ("Card Profile Name length too large!\n")); - } - } - else - { - DBGPRINT(RT_DEBUG_ERROR, - ("Can not find search key word in card.dat!\n")); - } - - if ((flg_match_ok != TRUE) && - (card_match_id < MAX_NUM_OF_MULTIPLE_CARD)) - { - MC_CardUsed[card_match_id] = 0; - memset(MC_CardMac[card_match_id], 0, sizeof(mac)); - } - } // if (card_match_id >= 0) - } - } - - // close file - retval = filp_close(srcf, NULL); - set_fs(orgfs); - current->fsuid = orgfsuid; - current->fsgid = orgfsgid; - kfree(buffer); - kfree(tmpbuf); - return flg_match_ok; -} -#endif // MULTIPLE_CARD_SUPPORT // - - /* ======================================================================== Routine Description: @@ -1198,12 +761,17 @@ INT __devinit rt28xx_probe( PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) NULL; INT status; PVOID handle; +#ifdef RT2860 struct pci_dev *dev_p = (struct pci_dev *)_dev_p; +#endif +#ifdef RT2870 + struct usb_interface *intf = (struct usb_interface *)_dev_p; + struct usb_device *dev_p = interface_to_usbdev(intf); + dev_p = usb_get_dev(dev_p); +#endif // RT2870 // -#ifdef CONFIG_STA_SUPPORT DBGPRINT(RT_DEBUG_TRACE, ("STA Driver version-%s\n", STA_DRIVER_VERSION)); -#endif // CONFIG_STA_SUPPORT // net_dev = alloc_etherdev(sizeof(PRTMP_ADAPTER)); if (net_dev == NULL) @@ -1214,13 +782,12 @@ INT __devinit rt28xx_probe( } netif_stop_queue(net_dev); -#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT + /* for supporting Network Manager */ /* Set the sysfs physical device reference for the network logical device * if set prior to registration will cause a symlink during initialization. */ SET_NETDEV_DEV(net_dev, &(dev_p->dev)); -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // // Allocate RTMP_ADAPTER miniport adapter structure handle = kmalloc(sizeof(struct os_cookie), GFP_KERNEL); @@ -1235,32 +802,13 @@ INT __devinit rt28xx_probe( RT28XXNetDevInit(_dev_p, net_dev, pAd); -#ifdef CONFIG_STA_SUPPORT pAd->StaCfg.OriDevType = net_dev->type; -#endif // CONFIG_STA_SUPPORT // // Post config if (RT28XXProbePostConfig(_dev_p, pAd, 0) == FALSE) goto err_out_unmap; -#ifdef CONFIG_STA_SUPPORT pAd->OpMode = OPMODE_STA; -#endif // CONFIG_STA_SUPPORT // - - -#ifdef MULTIPLE_CARD_SUPPORT - // find its profile path - pAd->MC_RowID = -1; // use default profile path - RTMP_CardInfoRead(pAd); - - if (pAd->MC_RowID == -1) -#ifdef CONFIG_STA_SUPPORT - strcpy(pAd->MC_FileName, STA_PROFILE_PATH); -#endif // CONFIG_STA_SUPPORT // - - DBGPRINT(RT_DEBUG_TRACE, - ("MC> ROW = %d, PATH = %s\n", pAd->MC_RowID, pAd->MC_FileName)); -#endif // MULTIPLE_CARD_SUPPORT // // sample move if (rt_ieee80211_if_setup(net_dev, pAd) != NDIS_STATUS_SUCCESS) @@ -1317,17 +865,6 @@ int rt28xx_packet_xmit(struct sk_buff *skb) int status = 0; PNDIS_PACKET pPacket = (PNDIS_PACKET) skb; - /* RT2870STA does this in RTMPSendPackets() */ -#ifdef RALINK_ATE - if (ATE_ON(pAd)) - { - RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_RESOURCES); - return 0; - } -#endif // RALINK_ATE // - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { // Drop send request since we are in monitor mode if (MONITOR_ON(pAd)) @@ -1336,7 +873,6 @@ int rt28xx_packet_xmit(struct sk_buff *skb) goto done; } } -#endif // CONFIG_STA_SUPPORT // // EapolStart size is 18 if (skb->len < 14) @@ -1354,16 +890,7 @@ int rt28xx_packet_xmit(struct sk_buff *skb) } #endif - - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - - STASendPackets((NDIS_HANDLE)pAd, (PPNDIS_PACKET) &pPacket, 1); - } - -#endif // CONFIG_STA_SUPPORT // + STASendPackets((NDIS_HANDLE)pAd, (PPNDIS_PACKET) &pPacket, 1); status = 0; done: @@ -1432,10 +959,8 @@ struct iw_statistics *rt28xx_get_wireless_stats( if(pAd->iw_stats.qual.qual > 100) pAd->iw_stats.qual.qual = 100; -#ifdef CONFIG_STA_SUPPORT if (pAd->OpMode == OPMODE_STA) pAd->iw_stats.qual.level = RTMPMaxRssi(pAd, pAd->StaCfg.RssiSample.LastRssi0, pAd->StaCfg.RssiSample.LastRssi1, pAd->StaCfg.RssiSample.LastRssi2); -#endif // CONFIG_STA_SUPPORT // pAd->iw_stats.qual.noise = pAd->BbpWriteLatch[66]; // noise level (dBm) @@ -1487,13 +1012,7 @@ INT rt28xx_ioctl( return -ENETDOWN; } - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - ret = rt28xx_sta_ioctl(net_dev, rq, cmd); - } -#endif // CONFIG_STA_SUPPORT // + ret = rt28xx_sta_ioctl(net_dev, rq, cmd); return ret; } diff --git a/drivers/staging/rt2860/rt_profile.c b/drivers/staging/rt2860/rt_profile.c index 62141f376972..d92b14328d40 100644 --- a/drivers/staging/rt2860/rt_profile.c +++ b/drivers/staging/rt2860/rt_profile.c @@ -27,12 +27,10 @@ #include "rt_config.h" -#ifdef DOT11_N_SUPPORT static void HTParametersHook( IN PRTMP_ADAPTER pAd, IN CHAR *pValueStr, IN CHAR *pInput); -#endif // DOT11_N_SUPPORT // #define ETH_MAC_ADDR_STR_LEN 17 // in format of xx:xx:xx:xx:xx:xx @@ -756,9 +754,6 @@ static void rtmp_read_key_parms_from_file(IN PRTMP_ADAPTER pAd, char *tmpbuf, c //DefaultKeyID if(RTMPGetKeyParameter("DefaultKeyID", tmpbuf, 25, buffer)) { - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { KeyIdx = simple_strtol(tmpbuf, 0, 10); if((KeyIdx >= 1 ) && (KeyIdx <= 4)) @@ -768,7 +763,6 @@ static void rtmp_read_key_parms_from_file(IN PRTMP_ADAPTER pAd, char *tmpbuf, c DBGPRINT(RT_DEBUG_TRACE, ("DefaultKeyID(0~3)=%d\n", pAd->StaCfg.DefaultKeyId)); } -#endif // CONFIG_STA_SUPPORT // } @@ -783,8 +777,6 @@ static void rtmp_read_key_parms_from_file(IN PRTMP_ADAPTER pAd, char *tmpbuf, c KeyType[i] = simple_strtol(macptr, 0, 10); } -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { sprintf(tok_str, "Key%dStr", idx + 1); if (RTMPGetCriticalParameter(tok_str, tmpbuf, 128, buffer)) @@ -792,13 +784,10 @@ static void rtmp_read_key_parms_from_file(IN PRTMP_ADAPTER pAd, char *tmpbuf, c rtmp_parse_key_buffer_from_file(pAd, tmpbuf, KeyType[BSS0], BSS0, idx); } } -#endif // CONFIG_STA_SUPPORT // } } } - -#ifdef CONFIG_STA_SUPPORT static void rtmp_read_sta_wmm_parms_from_file(IN PRTMP_ADAPTER pAd, char *tmpbuf, char *buffer) { PUCHAR macptr; @@ -821,23 +810,6 @@ static void rtmp_read_sta_wmm_parms_from_file(IN PRTMP_ADAPTER pAd, char *tmpbu DBGPRINT(RT_DEBUG_TRACE, ("WmmCapable=%d\n", pAd->CommonCfg.bWmmCapable)); } -#ifdef QOS_DLS_SUPPORT - //DLSCapable - if(RTMPGetKeyParameter("DLSCapable", tmpbuf, 32, buffer)) - { - if(simple_strtol(tmpbuf, 0, 10) != 0) //Enable - { - pAd->CommonCfg.bDLSCapable = TRUE; - } - else //Disable - { - pAd->CommonCfg.bDLSCapable = FALSE; - } - - DBGPRINT(RT_DEBUG_TRACE, ("bDLSCapable=%d\n", pAd->CommonCfg.bDLSCapable)); - } -#endif // QOS_DLS_SUPPORT // - //AckPolicy for AC_BK, AC_BE, AC_VI, AC_VO if(RTMPGetKeyParameter("AckPolicy", tmpbuf, 32, buffer)) { @@ -882,8 +854,6 @@ static void rtmp_read_sta_wmm_parms_from_file(IN PRTMP_ADAPTER pAd, char *tmpbu } } -#endif // CONFIG_STA_SUPPORT // - NDIS_STATUS RTMPReadParametersHook( IN PRTMP_ADAPTER pAd) @@ -896,10 +866,7 @@ NDIS_STATUS RTMPReadParametersHook( CHAR *tmpbuf; ULONG RtsThresh; ULONG FragThresh; -#ifdef CONFIG_STA_SUPPORT UCHAR keyMaterial[40]; -#endif // CONFIG_STA_SUPPORT // - PUCHAR macptr; INT i = 0; @@ -915,21 +882,17 @@ NDIS_STATUS RTMPReadParametersHook( return NDIS_STATUS_FAILURE; } -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - src = STA_PROFILE_PATH; -#endif // CONFIG_STA_SUPPORT // -#ifdef MULTIPLE_CARD_SUPPORT - src = pAd->MC_FileName; -#endif // MULTIPLE_CARD_SUPPORT // + src = STA_PROFILE_PATH; // Save uid and gid used for filesystem access. // Set user and group to 0 (root) +#ifndef RT30xx orgfsuid = current_fsuid(); orgfsgid = current_fsgid(); /* Hm, can't really do this nicely anymore, so rely on these files * being set to the proper permission to read them... */ /* current->cred->fsuid = current->cred->fsgid = 0; */ +#endif orgfs = get_fs(); set_fs(KERNEL_DS); @@ -970,12 +933,7 @@ NDIS_STATUS RTMPReadParametersHook( if(RTMPGetKeyParameter("CountryCode", tmpbuf, 25, buffer)) { NdisMoveMemory(pAd->CommonCfg.CountryCode, tmpbuf , 2); -#ifdef CONFIG_STA_SUPPORT -#ifdef EXT_BUILD_CHANNEL_LIST - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - NdisMoveMemory(pAd->StaCfg.StaOriCountryCode, tmpbuf , 2); -#endif // EXT_BUILD_CHANNEL_LIST // -#endif // CONFIG_STA_SUPPORT // + if (strlen(pAd->CommonCfg.CountryCode) != 0) { pAd->CommonCfg.bCountryFlag = TRUE; @@ -991,12 +949,6 @@ NDIS_STATUS RTMPReadParametersHook( pAd->CommonCfg.Geography = Geography; pAd->CommonCfg.CountryCode[2] = (pAd->CommonCfg.Geography == BOTH) ? ' ' : ((pAd->CommonCfg.Geography == IDOR) ? 'I' : 'O'); -#ifdef CONFIG_STA_SUPPORT -#ifdef EXT_BUILD_CHANNEL_LIST - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - pAd->StaCfg.StaOriGeography = pAd->CommonCfg.Geography; -#endif // EXT_BUILD_CHANNEL_LIST // -#endif // CONFIG_STA_SUPPORT // DBGPRINT(RT_DEBUG_TRACE, ("ChannelGeography=%d\n", pAd->CommonCfg.Geography)); } } @@ -1006,9 +958,6 @@ NDIS_STATUS RTMPReadParametersHook( pAd->CommonCfg.CountryCode[2] = ' '; } - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { //SSID if (RTMPGetCriticalParameter("SSID", tmpbuf, 256, buffer)) @@ -1028,10 +977,7 @@ NDIS_STATUS RTMPReadParametersHook( } } } -#endif // CONFIG_STA_SUPPORT // -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { //NetworkType if (RTMPGetKeyParameter("NetworkType", tmpbuf, 25, buffer)) @@ -1046,7 +992,7 @@ NDIS_STATUS RTMPReadParametersHook( DBGPRINT(RT_DEBUG_TRACE, ("%s::(NetworkType=%d)\n", __func__, pAd->StaCfg.BssType)); } } -#endif // CONFIG_STA_SUPPORT // + //Channel if(RTMPGetKeyParameter("Channel", tmpbuf, 10, buffer)) { @@ -1058,9 +1004,7 @@ NDIS_STATUS RTMPReadParametersHook( { int value = 0, maxPhyMode = PHY_11G; -#ifdef DOT11_N_SUPPORT maxPhyMode = PHY_11N_5G; -#endif // DOT11_N_SUPPORT // value = simple_strtol(tmpbuf, 0, 10); @@ -1086,10 +1030,9 @@ NDIS_STATUS RTMPReadParametersHook( if(RTMPGetKeyParameter("TxPower", tmpbuf, 10, buffer)) { pAd->CommonCfg.TxPowerPercentage = (ULONG) simple_strtol(tmpbuf, 0, 10); -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - pAd->CommonCfg.TxPowerDefault = pAd->CommonCfg.TxPowerPercentage; -#endif // CONFIG_STA_SUPPORT // + + pAd->CommonCfg.TxPowerDefault = pAd->CommonCfg.TxPowerPercentage; + DBGPRINT(RT_DEBUG_TRACE, ("TxPower=%ld\n", pAd->CommonCfg.TxPowerPercentage)); } //BGProtection @@ -1206,11 +1149,7 @@ NDIS_STATUS RTMPReadParametersHook( #endif // AGGREGATION_SUPPORT // // WmmCapable - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - rtmp_read_sta_wmm_parms_from_file(pAd, tmpbuf, buffer); -#endif // CONFIG_STA_SUPPORT // + rtmp_read_sta_wmm_parms_from_file(pAd, tmpbuf, buffer); //ShortSlot if(RTMPGetKeyParameter("ShortSlot", tmpbuf, 10, buffer)) @@ -1313,8 +1252,6 @@ NDIS_STATUS RTMPReadParametersHook( //AuthMode if(RTMPGetKeyParameter("AuthMode", tmpbuf, 128, buffer)) { -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { if ((strcmp(tmpbuf, "WEPAUTO") == 0) || (strcmp(tmpbuf, "wepauto") == 0)) pAd->StaCfg.AuthMode = Ndis802_11AuthModeAutoSwitch; @@ -1326,12 +1263,10 @@ NDIS_STATUS RTMPReadParametersHook( pAd->StaCfg.AuthMode = Ndis802_11AuthModeWPANone; else if ((strcmp(tmpbuf, "WPA2PSK") == 0) || (strcmp(tmpbuf, "wpa2psk") == 0)) pAd->StaCfg.AuthMode = Ndis802_11AuthModeWPA2PSK; -#ifdef WPA_SUPPLICANT_SUPPORT else if ((strcmp(tmpbuf, "WPA") == 0) || (strcmp(tmpbuf, "wpa") == 0)) pAd->StaCfg.AuthMode = Ndis802_11AuthModeWPA; else if ((strcmp(tmpbuf, "WPA2") == 0) || (strcmp(tmpbuf, "wpa2") == 0)) pAd->StaCfg.AuthMode = Ndis802_11AuthModeWPA2; -#endif // WPA_SUPPLICANT_SUPPORT // else pAd->StaCfg.AuthMode = Ndis802_11AuthModeOpen; @@ -1339,14 +1274,10 @@ NDIS_STATUS RTMPReadParametersHook( DBGPRINT(RT_DEBUG_TRACE, ("%s::(EncrypType=%d)\n", __func__, pAd->StaCfg.WepStatus)); } -#endif // CONFIG_STA_SUPPORT // } //EncrypType if(RTMPGetKeyParameter("EncrypType", tmpbuf, 128, buffer)) { - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { if ((strcmp(tmpbuf, "WEP") == 0) || (strcmp(tmpbuf, "wep") == 0)) pAd->StaCfg.WepStatus = Ndis802_11WEPEnabled; @@ -1365,13 +1296,8 @@ NDIS_STATUS RTMPReadParametersHook( DBGPRINT(RT_DEBUG_TRACE, ("%s::(EncrypType=%d)\n", __func__, pAd->StaCfg.WepStatus)); } -#endif // CONFIG_STA_SUPPORT // } - - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { if(RTMPGetCriticalParameter("WPAPSK", tmpbuf, 512, buffer)) { @@ -1420,38 +1346,20 @@ NDIS_STATUS RTMPReadParametersHook( } } } -#endif // CONFIG_STA_SUPPORT // //DefaultKeyID, KeyType, KeyStr rtmp_read_key_parms_from_file(pAd, tmpbuf, buffer); -#ifdef DOT11_N_SUPPORT HTParametersHook(pAd, tmpbuf, buffer); -#endif // DOT11_N_SUPPORT // - -#ifdef CARRIER_DETECTION_SUPPORT - //CarrierDetect - if(RTMPGetKeyParameter("CarrierDetect", tmpbuf, 128, buffer)) - { - if ((strncmp(tmpbuf, "0", 1) == 0)) - pAd->CommonCfg.CarrierDetect.Enable = FALSE; - else if ((strncmp(tmpbuf, "1", 1) == 0)) - pAd->CommonCfg.CarrierDetect.Enable = TRUE; - else - pAd->CommonCfg.CarrierDetect.Enable = FALSE; - - DBGPRINT(RT_DEBUG_TRACE, ("CarrierDetect.Enable=%d\n", pAd->CommonCfg.CarrierDetect.Enable)); - } - else - pAd->CommonCfg.CarrierDetect.Enable = FALSE; -#endif // CARRIER_DETECTION_SUPPORT // - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { //PSMode +#ifdef RT2860 if (RTMPGetKeyParameter("PSMode", tmpbuf, 32, buffer)) +#endif +#ifdef RT2870 + if (RTMPGetKeyParameter("PSMode", tmpbuf, 10, buffer)) +#endif { if (pAd->StaCfg.BssType == BSS_INFRA) { @@ -1534,8 +1442,23 @@ NDIS_STATUS RTMPReadParametersHook( DBGPRINT(RT_DEBUG_TRACE, ("TGnWifiTest=%d\n", pAd->StaCfg.bTGnWifiTest)); } } -#endif // CONFIG_STA_SUPPORT // +#ifdef RT30xx + { + if(RTMPGetKeyParameter("AntDiversity", tmpbuf, 10, buffer)) + { + for (i = 0, macptr = rstrtok(tmpbuf,";"); macptr; macptr = rstrtok(NULL,";"), i++) + { + if(simple_strtol(macptr, 0, 10) != 0) //Enable + pAd->CommonCfg.bRxAntDiversity = TRUE; + else //Disable + pAd->CommonCfg.bRxAntDiversity = FALSE; + + DBGPRINT(RT_DEBUG_ERROR, ("AntDiversity=%d\n", pAd->CommonCfg.bRxAntDiversity)); + } + } + } +#endif // RT30xx // } } else @@ -1554,18 +1477,12 @@ NDIS_STATUS RTMPReadParametersHook( set_fs(orgfs); -#if 0 - current->cred->fsuid = orgfsuid; - current->cred->fsgid = orgfsgid; -#endif - kfree(buffer); kfree(tmpbuf); return (NDIS_STATUS_SUCCESS); } -#ifdef DOT11_N_SUPPORT static void HTParametersHook( IN PRTMP_ADAPTER pAd, IN CHAR *pValueStr, @@ -1654,12 +1571,21 @@ static void HTParametersHook( if (Value == 0) { pAd->CommonCfg.BACapability.field.AutoBA = FALSE; +#ifdef RT30xx + pAd->CommonCfg.BACapability.field.Policy = BA_NOTUSE; +#endif } else { pAd->CommonCfg.BACapability.field.AutoBA = TRUE; +#ifdef RT30xx + pAd->CommonCfg.BACapability.field.Policy = IMMED_BA; +#endif } pAd->CommonCfg.REGBACapability.field.AutoBA = pAd->CommonCfg.BACapability.field.AutoBA; +#ifdef RT30xx + pAd->CommonCfg.REGBACapability.field.Policy = pAd->CommonCfg.BACapability.field.Policy; +#endif DBGPRINT(RT_DEBUG_TRACE, ("HT: Auto BA = %s\n", (Value==0) ? "Disable" : "Enable")); } @@ -1804,8 +1730,6 @@ static void HTParametersHook( { UCHAR fix_tx_mode; -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { fix_tx_mode = FIXED_TXMODE_HT; @@ -1837,7 +1761,6 @@ static void HTParametersHook( DBGPRINT(RT_DEBUG_TRACE, ("Fixed Tx Mode = %d\n", fix_tx_mode)); } -#endif // CONFIG_STA_SUPPORT // } @@ -1882,9 +1805,6 @@ static void HTParametersHook( // MSC if (RTMPGetKeyParameter("HT_MCS", pValueStr, 50, pInput)) { - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { Value = simple_strtol(pValueStr, 0, 10); @@ -1901,7 +1821,6 @@ static void HTParametersHook( DBGPRINT(RT_DEBUG_TRACE, ("HT: MCS = AUTO\n")); } } -#endif // CONFIG_STA_SUPPORT // } // STBC @@ -1977,5 +1896,3 @@ static void HTParametersHook( } } -#endif // DOT11_N_SUPPORT // - diff --git a/drivers/staging/rt2860/rtmp.h b/drivers/staging/rt2860/rtmp.h index b904b7886c28..25c31998d071 100644 --- a/drivers/staging/rt2860/rtmp.h +++ b/drivers/staging/rt2860/rtmp.h @@ -43,25 +43,112 @@ #include "link_list.h" #include "spectrum_def.h" - -#ifdef CONFIG_STA_SUPPORT #include "aironet.h" -#endif // CONFIG_STA_SUPPORT // //#define DBG_DIAGNOSE 1 -#if defined(CONFIG_AP_SUPPORT) && defined(CONFIG_STA_SUPPORT) -#define IF_DEV_CONFIG_OPMODE_ON_AP(_pAd) if(_pAd->OpMode == OPMODE_AP) -#define IF_DEV_CONFIG_OPMODE_ON_STA(_pAd) if(_pAd->OpMode == OPMODE_STA) -#else -#define IF_DEV_CONFIG_OPMODE_ON_AP(_pAd) -#define IF_DEV_CONFIG_OPMODE_ON_STA(_pAd) -#endif - #define VIRTUAL_IF_INC(__pAd) ((__pAd)->VirtualIfCnt++) #define VIRTUAL_IF_DEC(__pAd) ((__pAd)->VirtualIfCnt--) #define VIRTUAL_IF_NUM(__pAd) ((__pAd)->VirtualIfCnt) +#ifdef RT2870 +//////////////////////////////////////////////////////////////////////////// +// The TX_BUFFER structure forms the transmitted USB packet to the device +//////////////////////////////////////////////////////////////////////////// +typedef struct __TX_BUFFER{ + union { + UCHAR WirelessPacket[TX_BUFFER_NORMSIZE]; + HEADER_802_11 NullFrame; + PSPOLL_FRAME PsPollPacket; + RTS_FRAME RTSFrame; + }field; + UCHAR Aggregation[4]; //Buffer for save Aggregation size. +} TX_BUFFER, *PTX_BUFFER; + +typedef struct __HTTX_BUFFER{ + union { + UCHAR WirelessPacket[MAX_TXBULK_SIZE]; + HEADER_802_11 NullFrame; + PSPOLL_FRAME PsPollPacket; + RTS_FRAME RTSFrame; + }field; + UCHAR Aggregation[4]; //Buffer for save Aggregation size. +} HTTX_BUFFER, *PHTTX_BUFFER; + + +// used to track driver-generated write irps +typedef struct _TX_CONTEXT +{ + PVOID pAd; //Initialized in MiniportInitialize + PURB pUrb; //Initialized in MiniportInitialize + PIRP pIrp; //used to cancel pending bulk out. + //Initialized in MiniportInitialize + PTX_BUFFER TransferBuffer; //Initialized in MiniportInitialize + ULONG BulkOutSize; + UCHAR BulkOutPipeId; + UCHAR SelfIdx; + BOOLEAN InUse; + BOOLEAN bWaitingBulkOut; // at least one packet is in this TxContext, ready for making IRP anytime. + BOOLEAN bFullForBulkOut; // all tx buffer are full , so waiting for tx bulkout. + BOOLEAN IRPPending; + BOOLEAN LastOne; + BOOLEAN bAggregatible; + UCHAR Header_802_3[LENGTH_802_3]; + UCHAR Rsv[2]; + ULONG DataOffset; + UINT TxRate; + dma_addr_t data_dma; // urb dma on linux + +} TX_CONTEXT, *PTX_CONTEXT, **PPTX_CONTEXT; + + +// used to track driver-generated write irps +typedef struct _HT_TX_CONTEXT +{ + PVOID pAd; //Initialized in MiniportInitialize + PURB pUrb; //Initialized in MiniportInitialize + PIRP pIrp; //used to cancel pending bulk out. + //Initialized in MiniportInitialize + PHTTX_BUFFER TransferBuffer; //Initialized in MiniportInitialize + ULONG BulkOutSize; // Indicate the total bulk-out size in bytes in one bulk-transmission + UCHAR BulkOutPipeId; + BOOLEAN IRPPending; + BOOLEAN LastOne; + BOOLEAN bCurWriting; + BOOLEAN bRingEmpty; + BOOLEAN bCopySavePad; + UCHAR SavedPad[8]; + UCHAR Header_802_3[LENGTH_802_3]; + ULONG CurWritePosition; // Indicate the buffer offset which packet will be inserted start from. + ULONG CurWriteRealPos; // Indicate the buffer offset which packet now are writing to. + ULONG NextBulkOutPosition; // Indicate the buffer start offset of a bulk-transmission + ULONG ENextBulkOutPosition; // Indicate the buffer end offset of a bulk-transmission + UINT TxRate; + dma_addr_t data_dma; // urb dma on linux +} HT_TX_CONTEXT, *PHT_TX_CONTEXT, **PPHT_TX_CONTEXT; + + +// +// Structure to keep track of receive packets and buffers to indicate +// receive data to the protocol. +// +typedef struct _RX_CONTEXT +{ + PUCHAR TransferBuffer; + PVOID pAd; + PIRP pIrp;//used to cancel pending bulk in. + PURB pUrb; + //These 2 Boolean shouldn't both be 1 at the same time. + ULONG BulkInOffset; // number of packets waiting for reordering . + BOOLEAN bRxHandling; // Notify this packet is being process now. + BOOLEAN InUse; // USB Hardware Occupied. Wait for USB HW to put packet. + BOOLEAN Readable; // Receive Complete back. OK for driver to indicate receiving packet. + BOOLEAN IRPPending; // TODO: To be removed + atomic_t IrpLock; + NDIS_SPIN_LOCK RxContextLock; + dma_addr_t data_dma; // urb dma on linux +} RX_CONTEXT, *PRX_CONTEXT; +#endif // RT2870 // // @@ -136,14 +223,9 @@ extern UCHAR SsidIe; extern UCHAR SupRateIe; extern UCHAR ExtRateIe; -#ifdef DOT11_N_SUPPORT extern UCHAR HtCapIe; extern UCHAR AddHtInfoIe; extern UCHAR NewExtChanIe; -#ifdef DOT11N_DRAFT3 -extern UCHAR ExtHtCapIe; -#endif // DOT11N_DRAFT3 // -#endif // DOT11_N_SUPPORT // extern UCHAR ErpIe; extern UCHAR DsIe; @@ -152,9 +234,15 @@ extern UCHAR WpaIe; extern UCHAR Wpa2Ie; extern UCHAR IbssIe; extern UCHAR Ccx2Ie; +#ifdef RT30xx +extern UCHAR WapiIe; +#endif extern UCHAR WPA_OUI[]; extern UCHAR RSN_OUI[]; +#ifdef RT30xx +extern UCHAR WAPI_OUI[]; +#endif extern UCHAR WME_INFO_ELEM[]; extern UCHAR WME_PARM_ELEM[]; extern UCHAR Ccx2QosInfo[]; @@ -168,7 +256,6 @@ extern UCHAR RateSwitchTable11B[]; extern UCHAR RateSwitchTable11G[]; extern UCHAR RateSwitchTable11BG[]; -#ifdef DOT11_N_SUPPORT extern UCHAR RateSwitchTable11BGN1S[]; extern UCHAR RateSwitchTable11BGN2S[]; extern UCHAR RateSwitchTable11BGN2SForABand[]; @@ -176,97 +263,10 @@ extern UCHAR RateSwitchTable11N1S[]; extern UCHAR RateSwitchTable11N2S[]; extern UCHAR RateSwitchTable11N2SForABand[]; -#ifdef CONFIG_STA_SUPPORT extern UCHAR PRE_N_HT_OUI[]; -#endif // CONFIG_STA_SUPPORT // -#endif // DOT11_N_SUPPORT // #define MAXSEQ (0xFFF) -#ifdef RALINK_ATE -typedef struct _ATE_INFO { - UCHAR Mode; - CHAR TxPower0; - CHAR TxPower1; - CHAR TxAntennaSel; - CHAR RxAntennaSel; - TXWI_STRUC TxWI; // TXWI - USHORT QID; - UCHAR Addr1[MAC_ADDR_LEN]; - UCHAR Addr2[MAC_ADDR_LEN]; - UCHAR Addr3[MAC_ADDR_LEN]; - UCHAR Channel; - UINT32 TxLength; - UINT32 TxCount; - UINT32 TxDoneCount; // Tx DMA Done - UINT32 RFFreqOffset; - BOOLEAN bRxFer; - BOOLEAN bQATxStart; // Have compiled QA in and use it to ATE tx. - BOOLEAN bQARxStart; // Have compiled QA in and use it to ATE rx. - BOOLEAN bFWLoading; // Reload firmware when ATE is done. - UINT32 RxTotalCnt; - UINT32 RxCntPerSec; - - CHAR LastSNR0; // last received SNR - CHAR LastSNR1; // last received SNR for 2nd antenna - CHAR LastRssi0; // last received RSSI - CHAR LastRssi1; // last received RSSI for 2nd antenna - CHAR LastRssi2; // last received RSSI for 3rd antenna - CHAR AvgRssi0; // last 8 frames' average RSSI - CHAR AvgRssi1; // last 8 frames' average RSSI - CHAR AvgRssi2; // last 8 frames' average RSSI - SHORT AvgRssi0X8; // sum of last 8 frames' RSSI - SHORT AvgRssi1X8; // sum of last 8 frames' RSSI - SHORT AvgRssi2X8; // sum of last 8 frames' RSSI - - UINT32 NumOfAvgRssiSample; - -#ifdef RALINK_28xx_QA - // Tx frame - USHORT HLen; // Header Length - USHORT PLen; // Pattern Length - UCHAR Header[32]; // Header buffer - UCHAR Pattern[32]; // Pattern buffer - USHORT DLen; // Data Length - USHORT seq; - UINT32 CID; - THREAD_PID AtePid; - // counters - UINT32 U2M; - UINT32 OtherData; - UINT32 Beacon; - UINT32 OtherCount; - UINT32 TxAc0; - UINT32 TxAc1; - UINT32 TxAc2; - UINT32 TxAc3; - UINT32 TxHCCA; - UINT32 TxMgmt; - UINT32 RSSI0; - UINT32 RSSI1; - UINT32 RSSI2; - UINT32 SNR0; - UINT32 SNR1; - // control - //UINT32 Repeat; // Tx Cpu count - UCHAR TxStatus; // task Tx status // 0 --> task is idle, 1 --> task is running -#endif // RALINK_28xx_QA // -} ATE_INFO, *PATE_INFO; - -#ifdef RALINK_28xx_QA -struct ate_racfghdr { - UINT32 magic_no; - USHORT command_type; - USHORT command_id; - USHORT length; - USHORT sequence; - USHORT status; - UCHAR data[2046]; -} __attribute__((packed)); -#endif // RALINK_28xx_QA // -#endif // RALINK_ATE // - -#ifdef DOT11_N_SUPPORT struct reordering_mpdu { struct reordering_mpdu *next; @@ -287,7 +287,6 @@ struct reordering_mpdu_pool NDIS_SPIN_LOCK lock; struct reordering_list freelist; }; -#endif // DOT11_N_SUPPORT // typedef struct _RSSI_SAMPLE { CHAR LastRssi0; // last received RSSI @@ -364,12 +363,14 @@ typedef struct _QUEUE_HEADER { #define RTMP_TEST_FLAG(_M, _F) (((_M)->Flags & (_F)) != 0) #define RTMP_TEST_FLAGS(_M, _F) (((_M)->Flags & (_F)) == (_F)) +#ifdef RT2860 // Macro for power save flag. #define RTMP_SET_PSFLAG(_M, _F) ((_M)->PSFlags |= (_F)) #define RTMP_CLEAR_PSFLAG(_M, _F) ((_M)->PSFlags &= ~(_F)) #define RTMP_CLEAR_PSFLAGS(_M) ((_M)->PSFlags = 0) #define RTMP_TEST_PSFLAG(_M, _F) (((_M)->PSFlags & (_F)) != 0) #define RTMP_TEST_PSFLAGS(_M, _F) (((_M)->PSFlags & (_F)) == (_F)) +#endif #define OPSTATUS_SET_FLAG(_pAd, _F) ((_pAd)->CommonCfg.OpStatusFlags |= (_F)) #define OPSTATUS_CLEAR_FLAG(_pAd, _F) ((_pAd)->CommonCfg.OpStatusFlags &= ~(_F)) @@ -383,14 +384,12 @@ typedef struct _QUEUE_HEADER { #define RX_FILTER_CLEAR_FLAG(_pAd, _F) ((_pAd)->CommonCfg.PacketFilter &= ~(_F)) #define RX_FILTER_TEST_FLAG(_pAd, _F) (((_pAd)->CommonCfg.PacketFilter & (_F)) != 0) -#ifdef CONFIG_STA_SUPPORT #define STA_NO_SECURITY_ON(_p) (_p->StaCfg.WepStatus == Ndis802_11EncryptionDisabled) #define STA_WEP_ON(_p) (_p->StaCfg.WepStatus == Ndis802_11Encryption1Enabled) #define STA_TKIP_ON(_p) (_p->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) #define STA_AES_ON(_p) (_p->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) #define STA_TGN_WIFI_ON(_p) (_p->StaCfg.bTGnWifiTest == TRUE) -#endif // CONFIG_STA_SUPPORT // #define CKIP_KP_ON(_p) ((((_p)->StaCfg.CkipFlag) & 0x10) && ((_p)->StaCfg.bCkipCmicOn == TRUE)) #define CKIP_CMIC_ON(_p) ((((_p)->StaCfg.CkipFlag) & 0x08) && ((_p)->StaCfg.bCkipCmicOn == TRUE)) @@ -401,7 +400,17 @@ typedef struct _QUEUE_HEADER { (_idx) = (_idx+1) % (_RingSize); \ } +#ifdef RT30xx +// We will have a cost down version which mac version is 0x3090xxxx +#define IS_RT3090(_pAd) ((((_pAd)->MACVersion & 0xffff0000) == 0x30710000) || (((_pAd)->MACVersion & 0xffff0000) == 0x30900000)) +#endif #define IS_RT3070(_pAd) (((_pAd)->MACVersion & 0xffff0000) == 0x30700000) +#ifdef RT30xx +#define IS_RT3071(_pAd) (((_pAd)->MACVersion & 0xffff0000) == 0x30710000) +#define IS_RT2070(_pAd) (((_pAd)->RfIcType == RFIC_2020) || ((_pAd)->EFuseTag == 0x27)) + +#define IS_RT30xx(_pAd) (((_pAd)->MACVersion & 0xfff00000) == 0x30700000) +#endif #define RING_PACKET_INIT(_TxRing, _idx) \ { \ @@ -437,7 +446,6 @@ typedef struct _QUEUE_HEADER { } \ } -#ifdef DOT11_N_SUPPORT // StaActive.SupportedHtPhy.MCSSet is copied from AP beacon. Don't need to update here. #define COPY_HTSETTINGS_FROM_MLME_AUX_TO_ACTIVE_CFG(_pAd) \ { \ @@ -461,7 +469,6 @@ typedef struct _QUEUE_HEADER { _pAd->MacTab.Content[BSSID_WCID].MmpsMode= (UCHAR)(_pHtCapability->HtCapInfo.MimoPs); \ _pAd->MacTab.Content[BSSID_WCID].MaxRAmpduFactor = (UCHAR)(_pHtCapability->HtCapParm.MaxRAmpduFactor); \ } -#endif // DOT11_N_SUPPORT // // // MACRO for 32-bit PCI register read / write @@ -483,6 +490,7 @@ typedef struct _QUEUE_HEADER { // #define MAX_BUSY_COUNT 100 // Number of retry before failing access BBP & RF indirect register // +#ifdef RT2860 #define RTMP_RF_IO_WRITE32(_A, _V) \ { \ PHY_CSR4_STRUC Value; \ @@ -646,7 +654,20 @@ typedef struct _QUEUE_HEADER { } \ } \ } +#endif /* RT2860 */ +#ifdef RT2870 +#define RTMP_RF_IO_WRITE32(_A, _V) RTUSBWriteRFRegister(_A, _V) +#define RTMP_BBP_IO_READ8_BY_REG_ID(_A, _I, _pV) RTUSBReadBBPRegister(_A, _I, _pV) +#define RTMP_BBP_IO_WRITE8_BY_REG_ID(_A, _I, _V) RTUSBWriteBBPRegister(_A, _I, _V) +#define BBP_IO_WRITE8_BY_REG_ID(_A, _I, _V) RTUSBWriteBBPRegister(_A, _I, _V) +#define BBP_IO_READ8_BY_REG_ID(_A, _I, _pV) RTUSBReadBBPRegister(_A, _I, _pV) +#endif // RT2870 // + +#ifdef RT30xx +#define RTMP_RF_IO_READ8_BY_REG_ID(_A, _I, _pV) RT30xxReadRFRegister(_A, _I, _pV) +#define RTMP_RF_IO_WRITE8_BY_REG_ID(_A, _I, _V) RT30xxWriteRFRegister(_A, _I, _V) +#endif // RT30xx // #define MAP_CHANNEL_ID_TO_KHZ(ch, khz) { \ switch (ch) \ @@ -897,6 +918,7 @@ typedef struct _RTMP_SCATTER_GATHER_LIST { // Enqueue this frame to MLME engine // We need to enqueue the whole frame because MLME need to pass data type // information from 802.11 header +#ifdef RT2860 #define REPORT_MGMT_FRAME_TO_MLME(_pAd, Wcid, _pFrame, _FrameSize, _Rssi0, _Rssi1, _Rssi2, _PlcpSignal) \ { \ UINT32 High32TSF, Low32TSF; \ @@ -904,6 +926,49 @@ typedef struct _RTMP_SCATTER_GATHER_LIST { RTMP_IO_READ32(_pAd, TSF_TIMER_DW0, &Low32TSF); \ MlmeEnqueueForRecv(_pAd, Wcid, High32TSF, Low32TSF, (UCHAR)_Rssi0, (UCHAR)_Rssi1,(UCHAR)_Rssi2,_FrameSize, _pFrame, (UCHAR)_PlcpSignal); \ } +#endif +#ifdef RT2870 +#define REPORT_MGMT_FRAME_TO_MLME(_pAd, Wcid, _pFrame, _FrameSize, _Rssi0, _Rssi1, _Rssi2, _PlcpSignal) \ +{ \ + UINT32 High32TSF=0, Low32TSF=0; \ + MlmeEnqueueForRecv(_pAd, Wcid, High32TSF, Low32TSF, (UCHAR)_Rssi0, (UCHAR)_Rssi1,(UCHAR)_Rssi2,_FrameSize, _pFrame, (UCHAR)_PlcpSignal); \ +} +#endif // RT2870 // + +#ifdef RT30xx +//Need to collect each ant's rssi concurrently +//rssi1 is report to pair2 Ant and rss2 is reprot to pair1 Ant when 4 Ant +#define COLLECT_RX_ANTENNA_AVERAGE_RSSI(_pAd, _rssi1, _rssi2) \ +{ \ + SHORT AvgRssi; \ + UCHAR UsedAnt; \ + if (_pAd->RxAnt.EvaluatePeriod == 0) \ + { \ + UsedAnt = _pAd->RxAnt.Pair1PrimaryRxAnt; \ + AvgRssi = _pAd->RxAnt.Pair1AvgRssi[UsedAnt]; \ + if (AvgRssi < 0) \ + AvgRssi = AvgRssi - (AvgRssi >> 3) + _rssi1; \ + else \ + AvgRssi = _rssi1 << 3; \ + _pAd->RxAnt.Pair1AvgRssi[UsedAnt] = AvgRssi; \ + } \ + else \ + { \ + UsedAnt = _pAd->RxAnt.Pair1SecondaryRxAnt; \ + AvgRssi = _pAd->RxAnt.Pair1AvgRssi[UsedAnt]; \ + if ((AvgRssi < 0) && (_pAd->RxAnt.FirstPktArrivedWhenEvaluate)) \ + AvgRssi = AvgRssi - (AvgRssi >> 3) + _rssi1; \ + else \ + { \ + _pAd->RxAnt.FirstPktArrivedWhenEvaluate = TRUE; \ + AvgRssi = _rssi1 << 3; \ + } \ + _pAd->RxAnt.Pair1AvgRssi[UsedAnt] = AvgRssi; \ + _pAd->RxAnt.RcvPktNumWhenEvaluate++; \ + } \ +} +#endif // RT30xx // + #define NDIS_QUERY_BUFFER(_NdisBuf, _ppVA, _pBufLen) \ NdisQueryBuffer(_NdisBuf, _ppVA, _pBufLen) @@ -916,7 +981,7 @@ typedef struct _RTMP_SCATTER_GATHER_LIST { // #define JapanChannelCheck(channel) ((channel == 52) || (channel == 56) || (channel == 60) || (channel == 64)) -#ifdef CONFIG_STA_SUPPORT +#ifdef RT2860 #define STA_PORT_SECURED(_pAd) \ { \ _pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; \ @@ -925,8 +990,16 @@ typedef struct _RTMP_SCATTER_GATHER_LIST { _pAd->MacTab.Content[BSSID_WCID].PortSecured = _pAd->StaCfg.PortSecured; \ NdisReleaseSpinLock(&(_pAd)->MacTabLock); \ } -#endif // CONFIG_STA_SUPPORT // - +#endif +#ifdef RT2870 +#define STA_PORT_SECURED(_pAd) \ +{ \ + _pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; \ + NdisAcquireSpinLock(&_pAd->MacTabLock); \ + _pAd->MacTab.Content[BSSID_WCID].PortSecured = _pAd->StaCfg.PortSecured; \ + NdisReleaseSpinLock(&_pAd->MacTabLock); \ +} +#endif // // Register set pair for initialzation register set definition @@ -975,17 +1048,10 @@ typedef struct _RTMP_DMABUF typedef union _HEADER_802_11_SEQ{ -#ifdef RT_BIG_ENDIAN - struct { - USHORT Sequence:12; - USHORT Frag:4; - } field; -#else struct { USHORT Frag:4; USHORT Sequence:12; } field; -#endif USHORT value; } HEADER_802_11_SEQ, *PHEADER_802_11_SEQ; @@ -1002,7 +1068,12 @@ typedef struct _RTMP_REORDERBUF UCHAR DataOffset; USHORT Datasize; ULONG AllocSize; +#ifdef RT2860 NDIS_PHYSICAL_ADDRESS AllocPa; // TxBuf physical address +#endif +#ifdef RT2870 + PUCHAR AllocPa; +#endif // RT2870 // } RTMP_REORDERBUF, *PRTMP_REORDERBUF; // @@ -1101,7 +1172,9 @@ typedef struct _COUNTER_802_11 { typedef struct _COUNTER_RALINK { ULONG TransmittedByteCount; // both successful and failure, used to calculate TX throughput +#ifdef RT2860 ULONG LastReceivedByteCount; +#endif ULONG ReceivedByteCount; // both CRC okay and CRC error, used to calculate RX throughput ULONG BeenDisassociatedCount; ULONG BadCQIAutoRecoveryCount; @@ -1124,6 +1197,9 @@ typedef struct _COUNTER_RALINK { UINT32 OneSecFrameDuplicateCount; +#ifdef RT2870 + ULONG OneSecTransmittedByteCount; // both successful and failure, used to calculate TX throughput +#endif // RT2870 // UINT32 OneSecTxNoRetryOkCount; UINT32 OneSecTxRetryOkCount; @@ -1197,15 +1273,6 @@ typedef struct _ARCFOUR // MIMO Tx parameter, ShortGI, MCS, STBC, etc. these are fields in TXWI too. just copy to TXWI. typedef struct _RECEIVE_SETTING { -#ifdef RT_BIG_ENDIAN - USHORT MIMO:1; - USHORT OFDM:1; - USHORT rsv:3; - USHORT STBC:2; //SPACE - USHORT ShortGI:1; - USHORT Mode:2; //channel bandwidth 20MHz or 40 MHz - USHORT NumOfRX:2; // MIMO. WE HAVE 3R -#else USHORT NumOfRX:2; // MIMO. WE HAVE 3R USHORT Mode:2; //channel bandwidth 20MHz or 40 MHz USHORT ShortGI:1; @@ -1213,7 +1280,6 @@ typedef struct _RECEIVE_SETTING { USHORT rsv:3; USHORT OFDM:1; USHORT MIMO:1; -#endif } RECEIVE_SETTING, *PRECEIVE_SETTING; // Shared key data structure @@ -1230,9 +1296,7 @@ typedef struct _CIPHER_KEY { UCHAR RxTsc[6]; // 48bit TSC value UCHAR CipherAlg; // 0-none, 1:WEP64, 2:WEP128, 3:TKIP, 4:AES, 5:CKIP64, 6:CKIP128 UCHAR KeyLen; -#ifdef CONFIG_STA_SUPPORT UCHAR BssId[6]; -#endif // CONFIG_STA_SUPPORT // // Key length for each key, 0: entry is invalid UCHAR Type; // Indicate Pairwise/Group when reporting MIC error } CIPHER_KEY, *PCIPHER_KEY; @@ -1248,6 +1312,9 @@ typedef struct _BBP_TUNING_STRUCT { typedef struct _SOFT_RX_ANT_DIVERSITY_STRUCT { UCHAR EvaluatePeriod; // 0:not evalute status, 1: evaluate status, 2: switching status +#ifdef RT30xx + UCHAR EvaluateStableCnt; +#endif UCHAR Pair1PrimaryRxAnt; // 0:Ant-E1, 1:Ant-E2 UCHAR Pair1SecondaryRxAnt; // 0:Ant-E1, 1:Ant-E2 UCHAR Pair2PrimaryRxAnt; // 0:Ant-E3, 1:Ant-E4 @@ -1368,9 +1435,6 @@ typedef struct _BBP_R66_TUNING { typedef struct _CHANNEL_TX_POWER { USHORT RemainingTimeForUse; //unit: sec UCHAR Channel; -#ifdef DOT11N_DRAFT3 - BOOLEAN bEffectedChannel; // For BW 40 operating in 2.4GHz , the "effected channel" is the channel that is covered in 40Mhz. -#endif // DOT11N_DRAFT3 // CHAR Power; CHAR Power2; UCHAR MaxTxPwr; @@ -1393,7 +1457,6 @@ typedef enum _ABGBAND_STATE_ { } ABGBAND_STATE; typedef struct _MLME_STRUCT { -#ifdef CONFIG_STA_SUPPORT // STA state machines STATE_MACHINE CntlMachine; STATE_MACHINE AssocMachine; @@ -1409,20 +1472,10 @@ typedef struct _MLME_STRUCT { STATE_MACHINE_FUNC SyncFunc[SYNC_FUNC_SIZE]; STATE_MACHINE_FUNC WpaPskFunc[WPA_PSK_FUNC_SIZE]; STATE_MACHINE_FUNC AironetFunc[AIRONET_FUNC_SIZE]; -#endif // CONFIG_STA_SUPPORT // STATE_MACHINE_FUNC ActFunc[ACT_FUNC_SIZE]; // Action STATE_MACHINE ActMachine; - -#ifdef QOS_DLS_SUPPORT - STATE_MACHINE DlsMachine; - STATE_MACHINE_FUNC DlsFunc[DLS_FUNC_SIZE]; -#endif // QOS_DLS_SUPPORT // - - - - ULONG ChannelQuality; // 0..100, Channel Quality Indication for Roaming ULONG Now32; // latch the value of NdisGetSystemUpTime() ULONG LastSendNULLpsmTime; @@ -1437,9 +1490,11 @@ typedef struct _MLME_STRUCT { RALINK_TIMER_STRUCT APSDPeriodicTimer; RALINK_TIMER_STRUCT LinkDownTimer; RALINK_TIMER_STRUCT LinkUpTimer; +#ifdef RT2860 UCHAR bPsPollTimerRunning; RALINK_TIMER_STRUCT PsPollTimer; RALINK_TIMER_STRUCT RadioOnOffTimer; +#endif ULONG PeriodicRound; ULONG OneSecPeriodicRound; @@ -1448,7 +1503,10 @@ typedef struct _MLME_STRUCT { BOOLEAN bEnableAutoAntennaCheck; RALINK_TIMER_STRUCT RxAntEvalTimer; - +#ifdef RT2870 + UCHAR CaliBW40RfR24; + UCHAR CaliBW20RfR24; +#endif // RT2870 // } MLME_STRUCT, *PMLME_STRUCT; // structure for radar detection and channel switch @@ -1471,23 +1529,6 @@ typedef struct _RADAR_DETECT_STRUCT { UINT8 LongPulseRadarTh; } RADAR_DETECT_STRUCT, *PRADAR_DETECT_STRUCT; -#ifdef CARRIER_DETECTION_SUPPORT -typedef enum CD_STATE_n -{ - CD_NORMAL, - CD_SILENCE, - CD_MAX_STATE -} CD_STATE; - -typedef struct CARRIER_DETECTION_s -{ - BOOLEAN Enable; - UINT8 CDSessionTime; - UINT8 CDPeriod; - CD_STATE CD_State; -} CARRIER_DETECTION, *PCARRIER_DETECTION; -#endif // CARRIER_DETECTION_SUPPORT // - typedef enum _REC_BLOCKACK_STATUS { Recipient_NONE=0, @@ -1504,7 +1545,6 @@ typedef enum _ORI_BLOCKACK_STATUS Originator_Done } ORI_BLOCKACK_STATUS, *PORI_BLOCKACK_STATUS; -#ifdef DOT11_N_SUPPORT typedef struct _BA_ORI_ENTRY{ UCHAR Wcid; UCHAR TID; @@ -1568,21 +1608,6 @@ typedef struct _QUERYBA_TABLE{ } QUERYBA_TABLE, *PQUERYBA_TABLE; typedef union _BACAP_STRUC { -#ifdef RT_BIG_ENDIAN - struct { - UINT32 :4; - UINT32 b2040CoexistScanSup:1; //As Sta, support do 2040 coexistence scan for AP. As Ap, support monitor trigger event to check if can use BW 40MHz. - UINT32 bHtAdhoc:1; // adhoc can use ht rate. - UINT32 MMPSmode:2; // MIMO power save more, 0:static, 1:dynamic, 2:rsv, 3:mimo enable - UINT32 AmsduSize:1; // 0:3839, 1:7935 bytes. UINT MSDUSizeToBytes[] = { 3839, 7935}; - UINT32 AmsduEnable:1; //Enable AMSDU transmisstion - UINT32 MpduDensity:3; - UINT32 Policy:2; // 0: DELAY_BA 1:IMMED_BA (//BA Policy subfiled value in ADDBA frame) 2:BA-not use - UINT32 AutoBA:1; // automatically BA - UINT32 TxBAWinLimit:8; - UINT32 RxBAWinLimit:8; - } field; -#else struct { UINT32 RxBAWinLimit:8; UINT32 TxBAWinLimit:8; @@ -1596,10 +1621,8 @@ typedef union _BACAP_STRUC { UINT32 b2040CoexistScanSup:1; //As Sta, support do 2040 coexistence scan for AP. As Ap, support monitor trigger event to check if can use BW 40MHz. UINT32 :4; } field; -#endif UINT32 word; } BACAP_STRUC, *PBACAP_STRUC; -#endif // DOT11_N_SUPPORT // //This structure is for all 802.11n card InterOptibilityTest action. Reset all Num every n second. (Details see MLMEPeriodic) typedef struct _IOT_STRUC { @@ -1614,30 +1637,15 @@ typedef struct _IOT_STRUC { UCHAR RTSShortProt; UCHAR RTSLongProt; BOOLEAN bRTSLongProtOn; -#ifdef CONFIG_STA_SUPPORT BOOLEAN bLastAtheros; BOOLEAN bCurrentAtheros; BOOLEAN bNowAtherosBurstOn; BOOLEAN bNextDisableRxBA; BOOLEAN bToggle; -#endif // CONFIG_STA_SUPPORT // } IOT_STRUC, *PIOT_STRUC; // This is the registry setting for 802.11n transmit setting. Used in advanced page. typedef union _REG_TRANSMIT_SETTING { -#ifdef RT_BIG_ENDIAN - struct { - UINT32 rsv:13; - UINT32 EXTCHA:2; - UINT32 HTMODE:1; - UINT32 TRANSNO:2; - UINT32 STBC:1; //SPACE - UINT32 ShortGI:1; - UINT32 BW:1; //channel bandwidth 20MHz or 40 MHz - UINT32 TxBF:1; // 3*3 - UINT32 rsv0:10; - } field; -#else struct { UINT32 rsv0:10; UINT32 TxBF:1; @@ -1649,26 +1657,16 @@ typedef union _REG_TRANSMIT_SETTING { UINT32 EXTCHA:2; UINT32 rsv:13; } field; -#endif UINT32 word; } REG_TRANSMIT_SETTING, *PREG_TRANSMIT_SETTING; typedef union _DESIRED_TRANSMIT_SETTING { -#ifdef RT_BIG_ENDIAN - struct { - USHORT rsv:3; - USHORT FixedTxMode:2; // If MCS isn't AUTO, fix rate in CCK, OFDM or HT mode. - USHORT PhyMode:4; - USHORT MCS:7; // MCS - } field; -#else struct { USHORT MCS:7; // MCS USHORT PhyMode:4; USHORT FixedTxMode:2; // If MCS isn't AUTO, fix rate in CCK, OFDM or HT mode. USHORT rsv:3; } field; -#endif USHORT word; } DESIRED_TRANSMIT_SETTING, *PDESIRED_TRANSMIT_SETTING; @@ -1707,6 +1705,19 @@ typedef struct { UCHAR bit_offset = wcid & 0x7; \ ad_p->ApCfg.MBSSID[apidx].TimBitmaps[tim_offset] |= BIT8[bit_offset]; } +#ifdef RT2870 +#define BEACON_BITMAP_MASK 0xff +typedef struct _BEACON_SYNC_STRUCT_ +{ + UCHAR BeaconBuf[HW_BEACON_MAX_COUNT][HW_BEACON_OFFSET]; + UCHAR BeaconTxWI[HW_BEACON_MAX_COUNT][TXWI_SIZE]; + ULONG TimIELocationInBeacon[HW_BEACON_MAX_COUNT]; + ULONG CapabilityInfoLocationInBeacon[HW_BEACON_MAX_COUNT]; + BOOLEAN EnableBeacon; // trigger to enable beacon transmission. + UCHAR BeaconBitMap; // NOTE: If the MAX_MBSSID_NUM is larger than 8, this parameter need to change. + UCHAR DtimBitOn; // NOTE: If the MAX_MBSSID_NUM is larger than 8, this parameter need to change. +}BEACON_SYNC_STRUCT; +#endif // RT2870 // typedef struct _MULTISSID_STRUCT { UCHAR Bssid[MAC_ADDR_LEN]; @@ -1813,17 +1824,6 @@ typedef struct _MULTISSID_STRUCT { UCHAR BcnBufIdx; } MULTISSID_STRUCT, *PMULTISSID_STRUCT; - - -#ifdef DOT11N_DRAFT3 -typedef enum _BSS2040COEXIST_FLAG{ - BSS_2040_COEXIST_DISABLE = 0, - BSS_2040_COEXIST_TIMER_FIRED = 1, - BSS_2040_COEXIST_INFO_SYNC = 2, - BSS_2040_COEXIST_INFO_NOTIFY = 4, -}BSS2040COEXIST_FLAG; -#endif // DOT11N_DRAFT3 // - // configuration common to OPMODE_AP as well as OPMODE_STA typedef struct _COMMON_CONFIG { @@ -1886,10 +1886,9 @@ typedef struct _COMMON_CONFIG { ULONG TxPowerPercentage; // 0~100 % ULONG TxPowerDefault; // keep for TxPowerPercentage -#ifdef DOT11_N_SUPPORT BACAP_STRUC BACapability; // NO USE = 0XFF ; IMMED_BA =1 ; DELAY_BA=0 BACAP_STRUC REGBACapability; // NO USE = 0XFF ; IMMED_BA =1 ; DELAY_BA=0 -#endif // DOT11_N_SUPPORT // + IOT_STRUC IOTestParm; // 802.11n InterOpbility Test Parameter; ULONG TxPreamble; // Rt802_11PreambleLong, Rt802_11PreambleShort, Rt802_11PreambleAuto BOOLEAN bUseZeroToDisableFragment; // Microsoft use 0 as disable @@ -1901,17 +1900,14 @@ typedef struct _COMMON_CONFIG { BOOLEAN bIEEE80211H; // 1: enable IEEE802.11h spec. ULONG DisableOLBCDetect; // 0: enable OLBC detect; 1 disable OLBC detect -#ifdef DOT11_N_SUPPORT BOOLEAN bRdg; -#endif // DOT11_N_SUPPORT // + BOOLEAN bWmmCapable; // 0:disable WMM, 1:enable WMM QOS_CAPABILITY_PARM APQosCapability; // QOS capability of the current associated AP EDCA_PARM APEdcaParm; // EDCA parameters of the current associated AP QBSS_LOAD_PARM APQbssLoad; // QBSS load of the current associated AP UCHAR AckPolicy[4]; // ACK policy of the specified AC. see ACK_xxx -#ifdef CONFIG_STA_SUPPORT BOOLEAN bDLSCapable; // 0:disable DLS, 1:enable DLS -#endif // CONFIG_STA_SUPPORT // // a bitmap of BOOLEAN flags. each bit represent an operation status of a particular // BOOLEAN control, either ON or OFF. These flags should always be accessed via // OPSTATUS_TEST_FLAG(), OPSTATUS_SET_FLAG(), OP_STATUS_CLEAR_FLAG() macros. @@ -1920,15 +1916,13 @@ typedef struct _COMMON_CONFIG { BOOLEAN NdisRadioStateOff; //For HCT 12.0, set this flag to TRUE instead of called MlmeRadioOff. ABGBAND_STATE BandState; // For setting BBP used on B/G or A mode. +#ifdef RT30xx + BOOLEAN bRxAntDiversity; // 0:disable, 1:enable Software Rx Antenna Diversity. +#endif // IEEE802.11H--DFS. RADAR_DETECT_STRUCT RadarDetect; -#ifdef CARRIER_DETECTION_SUPPORT - CARRIER_DETECTION CarrierDetect; -#endif // CARRIER_DETECTION_SUPPORT // - -#ifdef DOT11_N_SUPPORT // HT UCHAR BASize; // USer desired BAWindowSize. Should not exceed our max capability //RT_HT_CAPABILITY SupportedHtPhy; @@ -1939,33 +1933,6 @@ typedef struct _COMMON_CONFIG { //This IE is included in channel switch ammouncement frames 7.4.1.5, beacons, probe Rsp. NEW_EXT_CHAN_IE NewExtChanOffset; //7.3.2.20A, 1 if extension channel is above the control channel, 3 if below, 0 if not present -#ifdef DOT11N_DRAFT3 - UCHAR Bss2040CoexistFlag; // bit 0: bBssCoexistTimerRunning, bit 1: NeedSyncAddHtInfo. - RALINK_TIMER_STRUCT Bss2040CoexistTimer; - - //This IE is used for 20/40 BSS Coexistence. - BSS_2040_COEXIST_IE BSS2040CoexistInfo; - // ====== 11n D3.0 =======================> - USHORT Dot11OBssScanPassiveDwell; // Unit : TU. 5~1000 - USHORT Dot11OBssScanActiveDwell; // Unit : TU. 10~1000 - USHORT Dot11BssWidthTriggerScanInt; // Unit : Second - USHORT Dot11OBssScanPassiveTotalPerChannel; // Unit : TU. 200~10000 - USHORT Dot11OBssScanActiveTotalPerChannel; // Unit : TU. 20~10000 - USHORT Dot11BssWidthChanTranDelayFactor; - USHORT Dot11OBssScanActivityThre; // Unit : percentage - - ULONG Dot11BssWidthChanTranDelay; // multiple of (Dot11BssWidthTriggerScanInt * Dot11BssWidthChanTranDelayFactor) - ULONG CountDownCtr; // CountDown Counter from (Dot11BssWidthTriggerScanInt * Dot11BssWidthChanTranDelayFactor) - - NDIS_SPIN_LOCK TriggerEventTabLock; - BSS_2040_COEXIST_IE LastBSSCoexist2040; - BSS_2040_COEXIST_IE BSSCoexist2040; - TRIGGER_EVENT_TAB TriggerEventTab; - UCHAR ChannelListIdx; - // <====== 11n D3.0 ======================= - BOOLEAN bOverlapScanning; -#endif // DOT11N_DRAFT3 // - BOOLEAN bHTProtect; BOOLEAN bMIMOPSEnable; BOOLEAN bBADecline; @@ -1976,7 +1943,6 @@ typedef struct _COMMON_CONFIG { ULONG LastRcvBSSWidthTriggerEventsTime; UCHAR TxBASize; -#endif // DOT11_N_SUPPORT // // Enable wireless event BOOLEAN bWirelessEvent; @@ -1994,6 +1960,20 @@ typedef struct _COMMON_CONFIG { BOOLEAN bHardwareRadio; // Hardware controlled Radio enabled +#ifdef RT2870 + BOOLEAN bMultipleIRP; // Multiple Bulk IN flag + UCHAR NumOfBulkInIRP; // if bMultipleIRP == TRUE, NumOfBulkInIRP will be 4 otherwise be 1 + RT_HT_CAPABILITY SupportedHtPhy; + ULONG MaxPktOneTxBulk; + UCHAR TxBulkFactor; + UCHAR RxBulkFactor; + + BEACON_SYNC_STRUCT *pBeaconSync; + RALINK_TIMER_STRUCT BeaconUpdateTimer; + UINT32 BeaconAdjust; + UINT32 BeaconFactor; + UINT32 BeaconRemain; +#endif // RT2870 // NDIS_SPIN_LOCK MeasureReqTabLock; @@ -2006,16 +1986,8 @@ typedef struct _COMMON_CONFIG { #ifdef MCAST_RATE_SPECIFIC HTTRANSMIT_SETTING MCastPhyMode; #endif // MCAST_RATE_SPECIFIC // - -#ifdef SINGLE_SKU - UINT16 DefineMaxTxPwr; -#endif // SINGLE_SKU // - - } COMMON_CONFIG, *PCOMMON_CONFIG; - -#ifdef CONFIG_STA_SUPPORT /* Modified by Wu Xi-Kun 4/21/2006 */ // STA configuration and status typedef struct _STA_ADMIN_CONFIG { @@ -2103,11 +2075,11 @@ typedef struct _STA_ADMIN_CONFIG { BOOLEAN bRadio; // Radio state, And of Sw & Hw radio state BOOLEAN bHardwareRadio; // Hardware controlled Radio enabled BOOLEAN bShowHiddenSSID; // Show all known SSID in SSID list get operation - +#ifdef RT2860 BOOLEAN AdhocBOnlyJoined; // Indicate Adhoc B Join. BOOLEAN AdhocBGJoined; // Indicate Adhoc B/G Join. BOOLEAN Adhoc20NJoined; // Indicate Adhoc 20MHz N Join. - +#endif // New for WPA, windows want us to to keep association information and // Fixed IEs from last association response NDIS_802_11_ASSOCIATION_INFORMATION AssocInfo; @@ -2189,10 +2161,6 @@ typedef struct _STA_ADMIN_CONFIG { UCHAR DtimCount; // 0.. DtimPeriod-1 UCHAR DtimPeriod; // default = 3 -#ifdef QOS_DLS_SUPPORT - RT_802_11_DLS DLSEntry[MAX_NUM_OF_DLS_ENTRY]; - UCHAR DlsReplayCounter[8]; -#endif // QOS_DLS_SUPPORT // //////////////////////////////////////////////////////////////////////////////////////// // This is only for WHQL test. BOOLEAN WhqlTest; @@ -2203,7 +2171,6 @@ typedef struct _STA_ADMIN_CONFIG { BOOLEAN bFastRoaming; // 0:disable fast roaming, 1:enable fast roaming CHAR dBmToRoam; // the condition to roam when receiving Rssi less than this value. It's negative value. -#ifdef WPA_SUPPLICANT_SUPPORT BOOLEAN IEEE8021X; BOOLEAN IEEE8021x_required_keys; CIPHER_KEY DesireSharedKey[4]; // Record user desired WEP keys @@ -2214,7 +2181,6 @@ typedef struct _STA_ADMIN_CONFIG { // 2: driver takes care of scanning, AP selection, and IEEE 802.11 association parameters UCHAR WpaSupplicantUP; UCHAR WpaSupplicantScanCount; -#endif // WPA_SUPPLICANT_SUPPORT // CHAR dev_name[16]; USHORT OriDevType; @@ -2227,13 +2193,9 @@ typedef struct _STA_ADMIN_CONFIG { RT_HT_PHY_INFO DesiredHtPhyInfo; BOOLEAN bAutoTxRateSwitch; +#ifdef RT2860 UCHAR BBPR3; - -#ifdef EXT_BUILD_CHANNEL_LIST - UCHAR IEEE80211dClientMode; - UCHAR StaOriCountryCode[3]; - UCHAR StaOriGeography; -#endif // EXT_BUILD_CHANNEL_LIST // +#endif } STA_ADMIN_CONFIG, *PSTA_ADMIN_CONFIG; // This data structure keep the current active BSS/IBSS's configuration that this STA @@ -2259,7 +2221,15 @@ typedef struct _STA_ACTIVE_CONFIG { RT_HT_PHY_INFO SupportedPhyInfo; RT_HT_CAPABILITY SupportedHtPhy; } STA_ACTIVE_CONFIG, *PSTA_ACTIVE_CONFIG; -#endif // CONFIG_STA_SUPPORT // + +#ifdef RT2870 +// for USB interface, avoid in interrupt when write key +typedef struct RT_ADD_PAIRWISE_KEY_ENTRY { + NDIS_802_11_MAC_ADDRESS MacAddr; + USHORT MacTabMatchWCID; // ASIC + CIPHER_KEY CipherKey; +} RT_ADD_PAIRWISE_KEY_ENTRY,*PRT_ADD_PAIRWISE_KEY_ENTRY; +#endif // RT2870 // // ----------- start of AP -------------------------- // AUTH-RSP State Machine Aux data structure @@ -2325,14 +2295,11 @@ typedef struct _MAC_TABLE_ENTRY { UINT32 StaConnectTime; // the live time of this station since associated with AP - -#ifdef DOT11_N_SUPPORT BOOLEAN bSendBAR; USHORT NoBADataCountDown; UINT32 CachedBuf[16]; // UINT (4 bytes) for alignment UINT TxBFCount; // 3*3 -#endif // DOT11_N_SUPPORT // UINT FIFOCount; UINT DebugFIFOCount; UINT DebugTxCount; @@ -2356,14 +2323,6 @@ typedef struct _MAC_TABLE_ENTRY { UCHAR TxRateUpPenalty; // extra # of second penalty due to last unstable condition //==================================================== - - -#ifdef CONFIG_STA_SUPPORT -#ifdef QOS_DLS_SUPPORT - UINT MatchDlsEntryIdx; // indicate the index in pAd->StaCfg.DLSEntry -#endif // QOS_DLS_SUPPORT // -#endif // CONFIG_STA_SUPPORT // - BOOLEAN fNoisyEnvironment; BOOLEAN fLastSecAccordingRSSI; UCHAR LastSecTxRateChangeAction; // 0: no change, 1:rate UP, 2:rate down @@ -2377,10 +2336,8 @@ typedef struct _MAC_TABLE_ENTRY { // see fOP_STATUS_xxx in RTMP_DEF.C for detail bit definition. fCLIENT_STATUS_AMSDU_INUSED ULONG ClientStatusFlags; - // TODO: Shall we move that to DOT11_N_SUPPORT??? HTTRANSMIT_SETTING HTPhyMode, MaxHTPhyMode, MinHTPhyMode;// For transmit phy setting in TXWI. -#ifdef DOT11_N_SUPPORT // HT EWC MIMO-N used parameters USHORT RXBAbitmap; // fill to on-chip RXWI_BA_BITMASK in 8.1.3RX attribute entry format USHORT TXBAbitmap; // This bitmap as originator, only keep in software used to mark AMPDU bit in TXWI @@ -2398,11 +2355,6 @@ typedef struct _MAC_TABLE_ENTRY { HT_CAPABILITY_IE HTCapability; -#ifdef DOT11N_DRAFT3 - UCHAR BSS2040CoexistenceMgmtSupport; -#endif // DOT11N_DRAFT3 // -#endif // DOT11_N_SUPPORT // - BOOLEAN bAutoTxRateSwitch; UCHAR RateLen; @@ -2416,6 +2368,9 @@ typedef struct _MAC_TABLE_ENTRY { UINT32 TXMCSSuccessful[16]; UINT32 TXMCSFailed[16]; UINT32 TXMCSAutoFallBack[16][16]; +#ifdef RT2870 + ULONG LastBeaconRxTime; +#endif } MAC_TABLE_ENTRY, *PMAC_TABLE_ENTRY; typedef struct _MAC_TABLE { @@ -2427,16 +2382,16 @@ typedef struct _MAC_TABLE { BOOLEAN fAnyStationInPsm; BOOLEAN fAnyStationBadAtheros; // Check if any Station is atheros 802.11n Chip. We need to use RTS/CTS with Atheros 802,.11n chip. BOOLEAN fAnyTxOPForceDisable; // Check if it is necessary to disable BE TxOP -#ifdef DOT11_N_SUPPORT +#ifdef RT2870 + BOOLEAN fAllStationAsRalink; // Check if all stations are ralink-chipset +#endif BOOLEAN fAnyStationIsLegacy; // Check if I use legacy rate to transmit to my BSS Station/ BOOLEAN fAnyStationNonGF; // Check if any Station can't support GF. BOOLEAN fAnyStation20Only; // Check if any Station can't support GF. BOOLEAN fAnyStationMIMOPSDynamic; // Check if any Station is MIMO Dynamic BOOLEAN fAnyBASession; // Check if there is BA session. Force turn on RTS/CTS -#endif // DOT11_N_SUPPORT // } MAC_TABLE, *PMAC_TABLE; -#ifdef DOT11_N_SUPPORT #define IS_HT_STA(_pMacEntry) \ (_pMacEntry->MaxHTPhyMode.field.MODE >= MODE_HTMIX) @@ -2445,7 +2400,6 @@ typedef struct _MAC_TABLE { #define PEER_IS_HT_RATE(_pMacEntry) \ (_pMacEntry->HTPhyMode.field.MODE >= MODE_HTMIX) -#endif // DOT11_N_SUPPORT // typedef struct _WDS_ENTRY { BOOLEAN Valid; @@ -2549,10 +2503,6 @@ typedef struct _APCLI_STRUCT { UCHAR SNonce[32]; // SNonce for WPA-PSK UCHAR GNonce[32]; // GNonce for WPA-PSK from authenticator -#ifdef WSC_AP_SUPPORT - WSC_CTRL WscControl; -#endif // WSC_AP_SUPPORT // - HTTRANSMIT_SETTING HTPhyMode, MaxHTPhyMode, MinHTPhyMode; RT_HT_PHY_INFO DesiredHtPhyInfo; BOOLEAN bAutoTxRateSwitch; @@ -2561,14 +2511,6 @@ typedef struct _APCLI_STRUCT { // ----------- end of AP ---------------------------- -#ifdef BLOCK_NET_IF -typedef struct _BLOCK_QUEUE_ENTRY -{ - BOOLEAN SwTxQueueBlockFlag; - LIST_HEADER NetIfList; -} BLOCK_QUEUE_ENTRY, *PBLOCK_QUEUE_ENTRY; -#endif // BLOCK_NET_IF // - struct wificonf { BOOLEAN bShortGI; @@ -2600,28 +2542,6 @@ typedef struct _INF_USB_CONFIG }; #endif // IKANOS_VX_1X0 // -#ifdef NINTENDO_AP -typedef struct _NINDO_CTRL_BLOCK { - - RT_NINTENDO_TABLE DS_TABLE; - -#ifdef CHIP25XX - spinlock_t NINTENDO_TABLE_Lock; -#else - NDIS_SPIN_LOCK NINTENDO_TABLE_Lock; -#endif // CHIP25XX // - - UCHAR NINTENDO_UP_BUFFER[512]; - UCHAR Local_KeyIdx; - CIPHER_KEY Local_SharedKey; - UCHAR Local_bHideSsid; - UCHAR Local_AuthMode; - UCHAR Local_WepStatus; - USHORT Local_CapabilityInfo; -} NINDO_CTRL_BLOCK; -#endif // NINTENDO_AP // - - #ifdef DBG_DIAGNOSE #define DIAGNOSE_TIME 10 // 10 sec typedef struct _RtmpDiagStrcut_ @@ -2660,6 +2580,7 @@ typedef struct _RTMP_ADAPTER PNET_DEV net_dev; ULONG VirtualIfCnt; +#ifdef RT2860 USHORT LnkCtrlBitMask; USHORT RLnkCtrlConfiguration; USHORT RLnkCtrlOffset; @@ -2686,11 +2607,51 @@ typedef struct _RTMP_ADAPTER RTMP_DMABUF RxDescRing; // Shared memory for RX descriptors RTMP_DMABUF TxDescRing[NUM_OF_TX_RING]; // Shared memory for Tx descriptors RTMP_TX_RING TxRing[NUM_OF_TX_RING]; // AC0~4 + HCCA - +#endif NDIS_SPIN_LOCK irq_lock; UCHAR irq_disabled; +#ifdef RT2870 +/*****************************************************************************************/ +/* USB related parameters */ +/*****************************************************************************************/ + struct usb_config_descriptor *config; + UINT BulkInEpAddr; // bulk-in endpoint address + UINT BulkOutEpAddr[6]; // bulk-out endpoint address + + UINT NumberOfPipes; + USHORT BulkOutMaxPacketSize; + USHORT BulkInMaxPacketSize; + + //======Control Flags + LONG PendingIoCount; + ULONG BulkFlags; + BOOLEAN bUsbTxBulkAggre; // Flags for bulk out data priority + + + //======Timer Thread + RT2870_TIMER_QUEUE TimerQ; + NDIS_SPIN_LOCK TimerQLock; + + + //======Cmd Thread + CmdQ CmdQ; + NDIS_SPIN_LOCK CmdQLock; // CmdQLock spinlock + + BOOLEAN TimerFunc_kill; + BOOLEAN mlme_kill; + + + //======Semaphores (event) + struct semaphore mlme_semaphore; /* to sleep thread on */ + struct semaphore RTUSBCmd_semaphore; /* to sleep thread on */ + struct semaphore RTUSBTimer_semaphore; + struct completion TimerQComplete; + struct completion mlmeComplete; + struct completion CmdQComplete; + wait_queue_head_t *wait; +#endif // RT2870 // /*****************************************************************************************/ @@ -2704,6 +2665,22 @@ typedef struct _RTMP_ADAPTER BOOLEAN DeQueueRunning[NUM_OF_TX_RING]; // for ensuring RTUSBDeQueuePacket get call once NDIS_SPIN_LOCK DeQueueLock[NUM_OF_TX_RING]; +#ifdef RT2870 + // Data related context and AC specified, 4 AC supported + NDIS_SPIN_LOCK BulkOutLock[6]; // BulkOut spinlock for 4 ACs + NDIS_SPIN_LOCK MLMEBulkOutLock; // MLME BulkOut lock + + HT_TX_CONTEXT TxContext[NUM_OF_TX_RING]; + NDIS_SPIN_LOCK TxContextQueueLock[NUM_OF_TX_RING]; // TxContextQueue spinlock + + // 4 sets of Bulk Out index and pending flag + UCHAR NextBulkOutIndex[4]; // only used for 4 EDCA bulkout pipe + + BOOLEAN BulkOutPending[6]; // used for total 6 bulkout pipe + UCHAR bulkResetPipeid; + BOOLEAN MgmtBulkPending; + ULONG bulkResetReq[6]; +#endif // RT2870 // // resource for software backlog queues QUEUE_HEADER TxSwQueue[NUM_OF_TX_RING]; // 4 AC + 1 HCCA @@ -2717,10 +2694,20 @@ typedef struct _RTMP_ADAPTER /*****************************************************************************************/ /* Rx related parameters */ /*****************************************************************************************/ - +#ifdef RT2860 RTMP_RX_RING RxRing; NDIS_SPIN_LOCK RxRingLock; // Rx Ring spinlock - +#endif +#ifdef RT2870 + RX_CONTEXT RxContext[RX_RING_SIZE]; // 1 for redundant multiple IRP bulk in. + NDIS_SPIN_LOCK BulkInLock; // BulkIn spinlock for 4 ACs + UCHAR PendingRx; // The Maxima pending Rx value should be RX_RING_SIZE. + UCHAR NextRxBulkInIndex; // Indicate the current RxContext Index which hold by Host controller. + UCHAR NextRxBulkInReadIndex; // Indicate the current RxContext Index which driver can read & process it. + ULONG NextRxBulkInPosition; // Want to contatenate 2 URB buffer while 1st is bulkin failed URB. This Position is 1st URB TransferLength. + ULONG TransferBufferLength; // current length of the packet buffer + ULONG ReadPosition; // current read position in a packet buffer +#endif // RT2870 // /*****************************************************************************************/ @@ -2734,6 +2721,10 @@ typedef struct _RTMP_ADAPTER ULONG EepromVersion; // byte 0: version, byte 1: revision, byte 2~3: unused UCHAR EEPROMAddressNum; // 93c46=6 93c66=8 USHORT EEPROMDefaultValue[NUM_EEPROM_BBP_PARMS]; +#ifdef RT30xx + BOOLEAN EepromAccess; + UCHAR EFuseTag; +#endif ULONG FirmwareVersion; // byte 0: Minor version, byte 1: Major version, otherwise unused. // --------------------------- @@ -2826,11 +2817,19 @@ typedef struct _RTMP_ADAPTER PSPOLL_FRAME PsPollFrame; HEADER_802_11 NullFrame; +#ifdef RT2870 + TX_CONTEXT BeaconContext[BEACON_RING_SIZE]; + TX_CONTEXT NullContext; + TX_CONTEXT PsPollContext; + TX_CONTEXT RTSContext; +#endif // RT2870 // + + + //=========AP=========== //=======STA=========== -#ifdef CONFIG_STA_SUPPORT /* Modified by Wu Xi-Kun 4/21/2006 */ // ----------------------------------------------- // STA specific configuration & operation status @@ -2840,7 +2839,6 @@ typedef struct _RTMP_ADAPTER STA_ACTIVE_CONFIG StaActive; // valid only when ADHOC_ON(pAd) || INFRA_ON(pAd) CHAR nickname[IW_ESSID_MAX_SIZE+1]; // nickname, only used in the iwconfig i/f NDIS_MEDIA_STATE PreMediaState; -#endif // CONFIG_STA_SUPPORT // //=======Common=========== // OP mode: either AP or STA @@ -2848,7 +2846,6 @@ typedef struct _RTMP_ADAPTER NDIS_MEDIA_STATE IndicateMediaState; // Base on Indication state, default is NdisMediaStateDisConnected - // MAT related parameters // configuration: read from Registry & E2PROM BOOLEAN bLocalAdminMAC; // Use user changed MAC @@ -2869,9 +2866,8 @@ typedef struct _RTMP_ADAPTER MAC_TABLE MacTab; // ASIC on-chip WCID entry table. At TX, ASIC always use key according to this on-chip table. NDIS_SPIN_LOCK MacTabLock; -#ifdef DOT11_N_SUPPORT BA_TABLE BATable; -#endif // DOT11_N_SUPPORT // + NDIS_SPIN_LOCK BATabLock; RALINK_TIMER_STRUCT RECBATimer; @@ -2890,16 +2886,13 @@ typedef struct _RTMP_ADAPTER // flags, see fRTMP_ADAPTER_xxx flags ULONG Flags; // Represent current device status +#ifdef RT2860 ULONG PSFlags; // Power Save operation flag. +#endif // current TX sequence # USHORT Sequence; -#ifdef UNDER_CE - NDIS_HANDLE hGiISR; -#endif - - // Control disconnect / connect event generation //+++Didn't used anymore ULONG LinkDownTime; @@ -2928,6 +2921,14 @@ typedef struct _RTMP_ADAPTER /*****************************************************************************************/ /* Statistic related parameters */ /*****************************************************************************************/ +#ifdef RT2870 + ULONG BulkOutDataOneSecCount; + ULONG BulkInDataOneSecCount; + ULONG BulkLastOneSecCount; // BulkOutDataOneSecCount + BulkInDataOneSecCount + ULONG watchDogRxCnt; + ULONG watchDogRxOverFlowCnt; + ULONG watchDogTxPendingCnt[NUM_OF_TX_RING]; +#endif // RT2870 // BOOLEAN bUpdateBcnCntDone; ULONG watchDogMacDeadlock; // prevent MAC/BBP into deadlock condition @@ -2967,13 +2968,7 @@ typedef struct _RTMP_ADAPTER struct wificonf WIFItestbed; -#ifdef RALINK_ATE - ATE_INFO ate; -#endif // RALINK_ATE // - -#ifdef DOT11_N_SUPPORT struct reordering_mpdu_pool mpdu_blk_pool; -#endif // DOT11_N_SUPPORT // ULONG OneSecondnonBEpackets; // record non BE packets per second @@ -2983,17 +2978,6 @@ typedef struct _RTMP_ADAPTER struct net_device_stats stats; -#ifdef BLOCK_NET_IF - BLOCK_QUEUE_ENTRY blockQueueTab[NUM_OF_TX_RING]; -#endif // BLOCK_NET_IF // - - - -#ifdef MULTIPLE_CARD_SUPPORT - INT32 MC_RowID; - UCHAR MC_FileName[256]; -#endif // MULTIPLE_CARD_SUPPORT // - ULONG TbttTickCount; #ifdef PCI_MSI_SUPPORT BOOLEAN HaveMsi; @@ -3007,11 +2991,6 @@ typedef struct _RTMP_ADAPTER UCHAR flg_be_adjust; ULONG be_adjust_last_time; -#ifdef NINTENDO_AP - NINDO_CTRL_BLOCK nindo_ctrl_block; -#endif // NINTENDO_AP // - - #ifdef IKANOS_VX_1X0 struct IKANOS_TX_INFO IkanosTxInfo; struct IKANOS_TX_INFO IkanosRxInfo[MAX_MBSSID_NUM + MAX_WDS_ENTRY + MAX_APCLI_NUM + MAX_MESH_NUM]; @@ -3024,6 +3003,13 @@ typedef struct _RTMP_ADAPTER UINT8 PM_FlgSuspend; + +#ifdef RT30xx +//======efuse + BOOLEAN bUseEfuse; + BOOLEAN bEEPROMFile; +#endif // RT30xx // + } RTMP_ADAPTER, *PRTMP_ADAPTER; // @@ -3176,7 +3162,7 @@ typedef struct _TX_BLK_ //------------------------------------------------------------------------------------------ - +#ifdef RT2860 // // Enable & Disable NIC interrupt via writing interrupt mask register // Since it use ADAPTER structure, it have to be put after structure definition. @@ -3210,243 +3196,6 @@ __inline VOID NICEnableInterrupt( RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_ACTIVE); } -#ifdef RT_BIG_ENDIAN -static inline VOID WriteBackToDescriptor( - IN PUCHAR Dest, - IN PUCHAR Src, - IN BOOLEAN DoEncrypt, - IN ULONG DescriptorType) -{ - UINT32 *p1, *p2; - - p1 = ((UINT32 *)Dest); - p2 = ((UINT32 *)Src); - - *p1 = *p2; - *(p1+2) = *(p2+2); - *(p1+3) = *(p2+3); - *(p1+1) = *(p2+1); // Word 1; this must be written back last -} - -/* - ======================================================================== - - Routine Description: - Endian conversion of Tx/Rx descriptor . - - Arguments: - pAd Pointer to our adapter - pData Pointer to Tx/Rx descriptor - DescriptorType Direction of the frame - - Return Value: - None - - Note: - Call this function when read or update descriptor - ======================================================================== -*/ -static inline VOID RTMPWIEndianChange( - IN PUCHAR pData, - IN ULONG DescriptorType) -{ - int size; - int i; - - size = ((DescriptorType == TYPE_TXWI) ? TXWI_SIZE : RXWI_SIZE); - - if(DescriptorType == TYPE_TXWI) - { - *((UINT32 *)(pData)) = SWAP32(*((UINT32 *)(pData))); // Byte 0~3 - *((UINT32 *)(pData + 4)) = SWAP32(*((UINT32 *)(pData+4))); // Byte 4~7 - } - else - { - for(i=0; i < size/4 ; i++) - *(((UINT32 *)pData) +i) = SWAP32(*(((UINT32 *)pData)+i)); - } -} - -/* - ======================================================================== - - Routine Description: - Endian conversion of Tx/Rx descriptor . - - Arguments: - pAd Pointer to our adapter - pData Pointer to Tx/Rx descriptor - DescriptorType Direction of the frame - - Return Value: - None - - Note: - Call this function when read or update descriptor - ======================================================================== -*/ -static inline VOID RTMPDescriptorEndianChange( - IN PUCHAR pData, - IN ULONG DescriptorType) -{ - *((UINT32 *)(pData)) = SWAP32(*((UINT32 *)(pData))); // Byte 0~3 - *((UINT32 *)(pData + 8)) = SWAP32(*((UINT32 *)(pData+8))); // Byte 8~11 - *((UINT32 *)(pData +12)) = SWAP32(*((UINT32 *)(pData + 12))); // Byte 12~15 - *((UINT32 *)(pData + 4)) = SWAP32(*((UINT32 *)(pData + 4))); // Byte 4~7, this must be swapped last -} - -/* - ======================================================================== - - Routine Description: - Endian conversion of all kinds of 802.11 frames . - - Arguments: - pAd Pointer to our adapter - pData Pointer to the 802.11 frame structure - Dir Direction of the frame - FromRxDoneInt Caller is from RxDone interrupt - - Return Value: - None - - Note: - Call this function when read or update buffer data - ======================================================================== -*/ -static inline VOID RTMPFrameEndianChange( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pData, - IN ULONG Dir, - IN BOOLEAN FromRxDoneInt) -{ - PHEADER_802_11 pFrame; - PUCHAR pMacHdr; - - // swab 16 bit fields - Frame Control field - if(Dir == DIR_READ) - { - *(USHORT *)pData = SWAP16(*(USHORT *)pData); - } - - pFrame = (PHEADER_802_11) pData; - pMacHdr = (PUCHAR) pFrame; - - // swab 16 bit fields - Duration/ID field - *(USHORT *)(pMacHdr + 2) = SWAP16(*(USHORT *)(pMacHdr + 2)); - - // swab 16 bit fields - Sequence Control field - *(USHORT *)(pMacHdr + 22) = SWAP16(*(USHORT *)(pMacHdr + 22)); - - if(pFrame->FC.Type == BTYPE_MGMT) - { - switch(pFrame->FC.SubType) - { - case SUBTYPE_ASSOC_REQ: - case SUBTYPE_REASSOC_REQ: - // swab 16 bit fields - CapabilityInfo field - pMacHdr += sizeof(HEADER_802_11); - *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); - - // swab 16 bit fields - Listen Interval field - pMacHdr += 2; - *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); - break; - - case SUBTYPE_ASSOC_RSP: - case SUBTYPE_REASSOC_RSP: - // swab 16 bit fields - CapabilityInfo field - pMacHdr += sizeof(HEADER_802_11); - *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); - - // swab 16 bit fields - Status Code field - pMacHdr += 2; - *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); - - // swab 16 bit fields - AID field - pMacHdr += 2; - *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); - break; - - case SUBTYPE_AUTH: - // If from APHandleRxDoneInterrupt routine, it is still a encrypt format. - // The convertion is delayed to RTMPHandleDecryptionDoneInterrupt. - if(!FromRxDoneInt && pFrame->FC.Wep == 1) - break; - else - { - // swab 16 bit fields - Auth Alg No. field - pMacHdr += sizeof(HEADER_802_11); - *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); - - // swab 16 bit fields - Auth Seq No. field - pMacHdr += 2; - *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); - - // swab 16 bit fields - Status Code field - pMacHdr += 2; - *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); - } - break; - - case SUBTYPE_BEACON: - case SUBTYPE_PROBE_RSP: - // swab 16 bit fields - BeaconInterval field - pMacHdr += (sizeof(HEADER_802_11) + TIMESTAMP_LEN); - *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); - - // swab 16 bit fields - CapabilityInfo field - pMacHdr += sizeof(USHORT); - *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); - break; - - case SUBTYPE_DEAUTH: - case SUBTYPE_DISASSOC: - // swab 16 bit fields - Reason code field - pMacHdr += sizeof(HEADER_802_11); - *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); - break; - } - } - else if( pFrame->FC.Type == BTYPE_DATA ) - { - } - else if(pFrame->FC.Type == BTYPE_CNTL) - { - switch(pFrame->FC.SubType) - { - case SUBTYPE_BLOCK_ACK_REQ: - { - PFRAME_BA_REQ pBAReq = (PFRAME_BA_REQ)pFrame; - *(USHORT *)(&pBAReq->BARControl) = SWAP16(*(USHORT *)(&pBAReq->BARControl)); - pBAReq->BAStartingSeq.word = SWAP16(pBAReq->BAStartingSeq.word); - } - break; - case SUBTYPE_BLOCK_ACK: - // For Block Ack packet, the HT_CONTROL field is in the same offset with Addr3 - *(UINT32 *)(&pFrame->Addr3[0]) = SWAP32(*(UINT32 *)(&pFrame->Addr3[0])); - break; - - case SUBTYPE_ACK: - //For ACK packet, the HT_CONTROL field is in the same offset with Addr2 - *(UINT32 *)(&pFrame->Addr2[0])= SWAP32(*(UINT32 *)(&pFrame->Addr2[0])); - break; - } - } - else - { - DBGPRINT(RT_DEBUG_ERROR,("Invalid Frame Type!!!\n")); - } - - // swab 16 bit fields - Frame Control - if(Dir == DIR_WRITE) - { - *(USHORT *)pData = SWAP16(*(USHORT *)pData); - } -} -#endif // RT_BIG_ENDIAN // - - static inline VOID ConvertMulticastIP2MAC( IN PUCHAR pIpAddr, IN PUCHAR *ppMacAddr, @@ -3484,6 +3233,7 @@ static inline VOID ConvertMulticastIP2MAC( return; } +#endif /* RT2860 */ BOOLEAN RTMPCheckForHang( IN NDIS_HANDLE MiniportAdapterContext @@ -3523,6 +3273,10 @@ NDIS_STATUS NICReadRegParameters( IN NDIS_HANDLE WrapperConfigurationContext ); +#ifdef RT2870 +VOID NICInitRT30xxRFRegisters( + IN PRTMP_ADAPTER pAd); +#endif // RT2870 // VOID NICReadEEPROMParameters( IN PRTMP_ADAPTER pAd, @@ -3541,10 +3295,10 @@ NDIS_STATUS NICInitializeAdapter( NDIS_STATUS NICInitializeAsic( IN PRTMP_ADAPTER pAd, IN BOOLEAN bHardReset); - +#ifdef RT2860 VOID NICRestoreBBPValue( IN PRTMP_ADAPTER pAd); - +#endif VOID NICIssueReset( IN PRTMP_ADAPTER pAd); @@ -3691,7 +3445,6 @@ VOID MlmeQOSAction( IN PRTMP_ADAPTER pAd, IN MLME_QUEUE_ELEM *Elem); -#ifdef DOT11_N_SUPPORT VOID PeerAddBAReqAction( IN PRTMP_ADAPTER pAd, IN MLME_QUEUE_ELEM *Elem); @@ -3707,53 +3460,12 @@ VOID PeerDelBAAction( VOID PeerBAAction( IN PRTMP_ADAPTER pAd, IN MLME_QUEUE_ELEM *Elem); -#endif // DOT11_N_SUPPORT // VOID SendPSMPAction( IN PRTMP_ADAPTER pAd, IN UCHAR Wcid, IN UCHAR Psmp); - -#ifdef DOT11N_DRAFT3 -VOID SendBSS2040CoexistMgmtAction( - IN PRTMP_ADAPTER pAd, - IN UCHAR Wcid, - IN UCHAR apidx, - IN UCHAR InfoReq); - -VOID SendNotifyBWActionFrame( - IN PRTMP_ADAPTER pAd, - IN UCHAR Wcid, - IN UCHAR apidx); - -BOOLEAN ChannelSwitchSanityCheck( - IN PRTMP_ADAPTER pAd, - IN UCHAR Wcid, - IN UCHAR NewChannel, - IN UCHAR Secondary); - -VOID ChannelSwitchAction( - IN PRTMP_ADAPTER pAd, - IN UCHAR Wcid, - IN UCHAR Channel, - IN UCHAR Secondary); - -ULONG BuildIntolerantChannelRep( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDest); - -VOID Update2040CoexistFrameAndNotify( - IN PRTMP_ADAPTER pAd, - IN UCHAR Wcid, - IN BOOLEAN bAddIntolerantCha); - -VOID Send2040CoexistAction( - IN PRTMP_ADAPTER pAd, - IN UCHAR Wcid, - IN BOOLEAN bAddIntolerantCha); -#endif // DOT11N_DRAFT3 // - VOID PeerRMAction( IN PRTMP_ADAPTER pAd, IN MLME_QUEUE_ELEM *Elem); @@ -3762,44 +3474,22 @@ VOID PeerPublicAction( IN PRTMP_ADAPTER pAd, IN MLME_QUEUE_ELEM *Elem); -#ifdef CONFIG_STA_SUPPORT VOID StaPublicAction( IN PRTMP_ADAPTER pAd, IN UCHAR Bss2040Coexist); -#endif // CONFIG_STA_SUPPORT // - VOID PeerBSSTranAction( IN PRTMP_ADAPTER pAd, IN MLME_QUEUE_ELEM *Elem); -#ifdef DOT11_N_SUPPORT VOID PeerHTAction( IN PRTMP_ADAPTER pAd, IN MLME_QUEUE_ELEM *Elem); -#endif // DOT11_N_SUPPORT // VOID PeerQOSAction( IN PRTMP_ADAPTER pAd, IN MLME_QUEUE_ELEM *Elem); -#ifdef QOS_DLS_SUPPORT -VOID PeerDLSAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); -#endif // QOS_DLS_SUPPORT // - -#ifdef CONFIG_STA_SUPPORT -#ifdef QOS_DLS_SUPPORT -VOID DlsParmFill( - IN PRTMP_ADAPTER pAd, - IN OUT MLME_DLS_REQ_STRUCT *pDlsReq, - IN PRT_802_11_DLS pDls, - IN USHORT reason); -#endif // QOS_DLS_SUPPORT // -#endif // CONFIG_STA_SUPPORT // - -#ifdef DOT11_N_SUPPORT VOID RECBATimerTimeout( IN PVOID SystemSpecific1, IN PVOID FunctionContext, @@ -3812,7 +3502,6 @@ VOID ORIBATimerTimeout( VOID SendRefreshBAR( IN PRTMP_ADAPTER pAd, IN MAC_TABLE_ENTRY *pEntry); -#endif // DOT11_N_SUPPORT // VOID ActHeaderInit( IN PRTMP_ADAPTER pAd, @@ -3845,7 +3534,6 @@ BOOLEAN QosBADataParse( IN USHORT Datasize, IN UINT CurRxIndex); -#ifdef DOT11_N_SUPPORT BOOLEAN CntlEnqueueForRecv( IN PRTMP_ADAPTER pAd, IN ULONG Wcid, @@ -3854,7 +3542,6 @@ BOOLEAN CntlEnqueueForRecv( VOID BaAutoManSwitch( IN PRTMP_ADAPTER pAd); -#endif // DOT11_N_SUPPORT // VOID HTIOTCheck( IN PRTMP_ADAPTER pAd, @@ -4010,7 +3697,13 @@ NDIS_STATUS MiniportMMRequest( IN UCHAR QueIdx, IN PUCHAR pData, IN UINT Length); - +#ifdef RT2870 +NDIS_STATUS MiniportDataMMRequest( + IN PRTMP_ADAPTER pAd, + IN UCHAR QueIdx, + IN PUCHAR pData, + IN UINT Length); +#endif VOID RTMPSendNullFrame( IN PRTMP_ADAPTER pAd, IN UCHAR TxRate, @@ -4039,7 +3732,6 @@ PQUEUE_HEADER RTMPCheckTxSwQueue( IN PRTMP_ADAPTER pAd, OUT UCHAR *QueIdx); -#ifdef CONFIG_STA_SUPPORT VOID RTMPReportMicError( IN PRTMP_ADAPTER pAd, IN PCIPHER_KEY pWpaKey); @@ -4053,7 +3745,6 @@ VOID WpaDisassocApAndBlockAssoc( IN PVOID FunctionContext, IN PVOID SystemSpecific2, IN PVOID SystemSpecific3); -#endif // CONFIG_STA_SUPPORT // NDIS_STATUS RTMPCloneNdisPacket( IN PRTMP_ADAPTER pAd, @@ -4193,7 +3884,6 @@ VOID AsicRfTuningExec( IN PVOID SystemSpecific2, IN PVOID SystemSpecific3); -#ifdef CONFIG_STA_SUPPORT VOID AsicSleepThenAutoWakeup( IN PRTMP_ADAPTER pAd, IN USHORT TbttNumToNextWakeUp); @@ -4203,8 +3893,12 @@ VOID AsicForceSleep( VOID AsicForceWakeup( IN PRTMP_ADAPTER pAd, +#ifdef RT2860 IN UCHAR Level); -#endif // CONFIG_STA_SUPPORT // +#endif +#ifdef RT2870 + IN BOOLEAN bFromTx); +#endif VOID AsicSetBssid( IN PRTMP_ADAPTER pAd, @@ -4298,11 +3992,11 @@ BOOLEAN AsicSendCommandToMcu( IN UCHAR Token, IN UCHAR Arg0, IN UCHAR Arg1); - +#ifdef RT2860 BOOLEAN AsicCheckCommanOk( IN PRTMP_ADAPTER pAd, IN UCHAR Command); - +#endif VOID MacAddrRandomBssid( IN PRTMP_ADAPTER pAd, OUT PUCHAR pAddr); @@ -4325,11 +4019,9 @@ VOID MlmeRadioOn( VOID BssTableInit( IN BSS_TABLE *Tab); -#ifdef DOT11_N_SUPPORT VOID BATableInit( IN PRTMP_ADAPTER pAd, IN BA_TABLE *Tab); -#endif // DOT11_N_SUPPORT // ULONG BssTableSearch( IN BSS_TABLE *Tab, @@ -4355,7 +4047,6 @@ VOID BssTableDeleteEntry( IN PUCHAR pBssid, IN UCHAR Channel); -#ifdef DOT11_N_SUPPORT VOID BATableDeleteORIEntry( IN OUT PRTMP_ADAPTER pAd, IN BA_ORI_ENTRY *pBAORIEntry); @@ -4376,7 +4067,6 @@ VOID BATableTearRECEntry( IN UCHAR TID, IN UCHAR WCID, IN BOOLEAN ALL); -#endif // DOT11_N_SUPPORT // VOID BssEntrySet( IN PRTMP_ADAPTER pAd, @@ -4438,7 +4128,6 @@ ULONG BssTableSetEntry( IN USHORT LengthVIE, IN PNDIS_802_11_VARIABLE_IEs pVIE); -#ifdef DOT11_N_SUPPORT VOID BATableInsertEntry( IN PRTMP_ADAPTER pAd, IN USHORT Aid, @@ -4449,31 +4138,6 @@ VOID BATableInsertEntry( IN UCHAR OriginatorStatus, IN BOOLEAN IsRecipient); -#ifdef DOT11N_DRAFT3 -VOID Bss2040CoexistTimeOut( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); - - -VOID TriEventInit( - IN PRTMP_ADAPTER pAd); - -ULONG TriEventTableSetEntry( - IN PRTMP_ADAPTER pAd, - OUT TRIGGER_EVENT_TAB *Tab, - IN PUCHAR pBssid, - IN HT_CAPABILITY_IE *pHtCapability, - IN UCHAR HtCapabilityLen, - IN UCHAR RegClass, - IN UCHAR ChannelNo); - -VOID TriEventCounterMaintenance( - IN PRTMP_ADAPTER pAd); -#endif // DOT11N_DRAFT3 // -#endif // DOT11_N_SUPPORT // - VOID BssTableSsidSort( IN PRTMP_ADAPTER pAd, OUT BSS_TABLE *OutTab, @@ -4638,6 +4302,12 @@ VOID InvalidStateWhenDisassociate( IN PRTMP_ADAPTER pAd, IN MLME_QUEUE_ELEM *Elem); +#ifdef RT2870 +VOID MlmeCntlConfirm( + IN PRTMP_ADAPTER pAd, + IN ULONG MsgType, + IN USHORT Msg); +#endif // RT2870 // VOID ComposePsPoll( IN PRTMP_ADAPTER pAd); @@ -4721,142 +4391,6 @@ VOID PeerAuthSimpleRspGenAndSend( // Private routines in dls.c // -#ifdef CONFIG_STA_SUPPORT -#ifdef QOS_DLS_SUPPORT -void DlsStateMachineInit( - IN PRTMP_ADAPTER pAd, - IN STATE_MACHINE *Sm, - OUT STATE_MACHINE_FUNC Trans[]); - -VOID MlmeDlsReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID PeerDlsReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID PeerDlsRspAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID MlmeDlsTearDownAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID PeerDlsTearDownAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID RTMPCheckDLSTimeOut( - IN PRTMP_ADAPTER pAd); - -BOOLEAN RTMPRcvFrameDLSCheck( - IN PRTMP_ADAPTER pAd, - IN PHEADER_802_11 pHeader, - IN ULONG Len, - IN PRT28XX_RXD_STRUC pRxD); - -INT RTMPCheckDLSFrame( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDA); - -VOID RTMPSendDLSTearDownFrame( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDA); - -NDIS_STATUS RTMPSendSTAKeyRequest( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDA); - -NDIS_STATUS RTMPSendSTAKeyHandShake( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDA); - -VOID DlsTimeoutAction( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); - -BOOLEAN MlmeDlsReqSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PRT_802_11_DLS *pDLS, - OUT PUSHORT pReason); - -INT Set_DlsEntryInfo_Display_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -MAC_TABLE_ENTRY *MacTableInsertDlsEntry( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pAddr, - IN UINT DlsEntryIdx); - -BOOLEAN MacTableDeleteDlsEntry( - IN PRTMP_ADAPTER pAd, - IN USHORT wcid, - IN PUCHAR pAddr); - -MAC_TABLE_ENTRY *DlsEntryTableLookup( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pAddr, - IN BOOLEAN bResetIdelCount); - -MAC_TABLE_ENTRY *DlsEntryTableLookupByWcid( - IN PRTMP_ADAPTER pAd, - IN UCHAR wcid, - IN PUCHAR pAddr, - IN BOOLEAN bResetIdelCount); - -INT Set_DlsAddEntry_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_DlsTearDownEntry_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); -#endif // QOS_DLS_SUPPORT // -#endif // CONFIG_STA_SUPPORT // - -#ifdef QOS_DLS_SUPPORT -BOOLEAN PeerDlsReqSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PUCHAR pDA, - OUT PUCHAR pSA, - OUT USHORT *pCapabilityInfo, - OUT USHORT *pDlsTimeout, - OUT UCHAR *pRatesLen, - OUT UCHAR Rates[], - OUT UCHAR *pHtCapabilityLen, - OUT HT_CAPABILITY_IE *pHtCapability); - -BOOLEAN PeerDlsRspSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PUCHAR pDA, - OUT PUCHAR pSA, - OUT USHORT *pCapabilityInfo, - OUT USHORT *pStatus, - OUT UCHAR *pRatesLen, - OUT UCHAR Rates[], - OUT UCHAR *pHtCapabilityLen, - OUT HT_CAPABILITY_IE *pHtCapability); - -BOOLEAN PeerDlsTearDownSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PUCHAR pDA, - OUT PUCHAR pSA, - OUT USHORT *pReason); -#endif // QOS_DLS_SUPPORT // - //======================================== VOID SyncStateMachineInit( @@ -4961,12 +4495,6 @@ VOID CntlWaitAssocProc( IN PRTMP_ADAPTER pAd, IN MLME_QUEUE_ELEM *Elem); -#ifdef QOS_DLS_SUPPORT -VOID CntlOidDLSSetupProc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); -#endif // QOS_DLS_SUPPORT // - VOID LinkUp( IN PRTMP_ADAPTER pAd, IN UCHAR BssType); @@ -5113,9 +4641,7 @@ BOOLEAN PeerBeaconAndProbeRspSanity( OUT PQOS_CAPABILITY_PARM pQosCapability, OUT ULONG *pRalinkIe, OUT UCHAR *pHtCapabilityLen, -#ifdef CONFIG_STA_SUPPORT OUT UCHAR *pPreNHtCapabilityLen, -#endif // CONFIG_STA_SUPPORT // OUT HT_CAPABILITY_IE *pHtCapability, OUT UCHAR *AddHtInfoLen, OUT ADD_HT_INFO_IE *AddHtInfo, @@ -5343,23 +4869,19 @@ VOID MlmeUpdateTxRates( IN BOOLEAN bLinkUp, IN UCHAR apidx); -#ifdef DOT11_N_SUPPORT VOID MlmeUpdateHtTxRates( IN PRTMP_ADAPTER pAd, IN UCHAR apidx); -#endif // DOT11_N_SUPPORT // VOID RTMPCheckRates( IN PRTMP_ADAPTER pAd, IN OUT UCHAR SupRate[], IN OUT UCHAR *SupRateLen); -#ifdef CONFIG_STA_SUPPORT BOOLEAN RTMPCheckChannel( IN PRTMP_ADAPTER pAd, IN UCHAR CentralChannel, IN UCHAR Channel); -#endif // CONFIG_STA_SUPPORT // BOOLEAN RTMPCheckHt( IN PRTMP_ADAPTER pAd, @@ -5388,6 +4910,12 @@ CHAR RTMPMaxRssi( IN CHAR Rssi1, IN CHAR Rssi2); +#ifdef RT30xx +VOID AsicSetRxAnt( + IN PRTMP_ADAPTER pAd, + IN UCHAR Ant); +#endif + VOID AsicEvaluateRxAnt( IN PRTMP_ADAPTER pAd); @@ -5600,15 +5128,12 @@ VOID RTMPIndicateWPA2Status( VOID RTMPOPModeSwitching( IN PRTMP_ADAPTER pAd); -#ifdef CONFIG_STA_SUPPORT VOID RTMPAddBSSIDCipher( IN PRTMP_ADAPTER pAd, IN UCHAR Aid, IN PNDIS_802_11_KEY pKey, IN UCHAR CipherAlg); -#endif // CONFIG_STA_SUPPORT // -#ifdef DOT11_N_SUPPORT VOID RTMPSetHT( IN PRTMP_ADAPTER pAd, IN OID_SET_HT_PHYMODE *pHTPhyMode); @@ -5616,7 +5141,6 @@ VOID RTMPSetHT( VOID RTMPSetIndividualHT( IN PRTMP_ADAPTER pAd, IN UCHAR apidx); -#endif // DOT11_N_SUPPORT // VOID RTMPSendWirelessEvent( IN PRTMP_ADAPTER pAd, @@ -5793,13 +5317,6 @@ CHAR ConvertToRssi( IN CHAR Rssi, IN UCHAR RssiNumber); - -#ifdef DOT11N_DRAFT3 -VOID BuildEffectedChannelList( - IN PRTMP_ADAPTER pAd); -#endif // DOT11N_DRAFT3 // - - VOID APAsicEvaluateRxAnt( IN PRTMP_ADAPTER pAd); @@ -6072,6 +5589,10 @@ VOID RTMPSendTriggerFrame( IN UCHAR TxRate, IN BOOLEAN bQosNull); +#ifdef RT30xx +VOID RTMPFilterCalibration( + IN PRTMP_ADAPTER pAd); +#endif // RT30xx // /* timeout -- ms */ VOID RTMP_SetPeriodicTimer( @@ -6263,7 +5784,6 @@ UCHAR VLAN_8023_Header_Copy( OUT PUCHAR pData, IN UCHAR FromWhichBSSID); -#ifdef DOT11_N_SUPPORT void ba_flush_reordering_timeout_mpdus( IN PRTMP_ADAPTER pAd, IN PBA_REC_ENTRY pBAEntry, @@ -6281,7 +5801,6 @@ VOID BAOriSessionSetUp( VOID BASessionTearDownALL( IN OUT PRTMP_ADAPTER pAd, IN UCHAR Wcid); -#endif // DOT11_N_SUPPORT // BOOLEAN OS_Need_Clone_Packet(void); @@ -6429,7 +5948,6 @@ INT Set_ResetStatCounter_Proc( IN PRTMP_ADAPTER pAd, IN PUCHAR arg); -#ifdef DOT11_N_SUPPORT INT Set_BASetup_Proc( IN PRTMP_ADAPTER pAd, IN PUCHAR arg); @@ -6530,24 +6048,17 @@ INT Set_HtMIMOPSmode_Proc( INT Set_HtTxBASize_Proc( IN PRTMP_ADAPTER pAd, IN PUCHAR arg); -#endif // DOT11_N_SUPPORT // - - -#ifdef CONFIG_STA_SUPPORT //Dls , kathy VOID RTMPSendDLSTearDownFrame( IN PRTMP_ADAPTER pAd, IN PUCHAR pDA); -#ifdef DOT11_N_SUPPORT //Block ACK VOID QueryBATABLE( IN PRTMP_ADAPTER pAd, OUT PQUERYBA_TABLE pBAT); -#endif // DOT11_N_SUPPORT // -#ifdef WPA_SUPPLICANT_SUPPORT INT WpaCheckEapCode( IN PRTMP_ADAPTER pAd, IN PUCHAR pFrame, @@ -6560,26 +6071,16 @@ VOID WpaSendMicFailureToWpaSupplicant( VOID SendAssocIEsToWpaSupplicant( IN PRTMP_ADAPTER pAd); -#endif // WPA_SUPPLICANT_SUPPORT // -#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT int wext_notify_event_assoc( IN RTMP_ADAPTER *pAd); -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // -#endif // CONFIG_STA_SUPPORT // - - - -#ifdef DOT11_N_SUPPORT VOID Handle_BSS_Width_Trigger_Events( IN PRTMP_ADAPTER pAd); void build_ext_channel_switch_ie( IN PRTMP_ADAPTER pAd, IN HT_EXT_CHANNEL_SWITCH_ANNOUNCEMENT_IE *pIE); -#endif // DOT11_N_SUPPORT // - BOOLEAN APRxDoneInterruptHandle( IN PRTMP_ADAPTER pAd); @@ -6588,7 +6089,6 @@ BOOLEAN STARxDoneInterruptHandle( IN PRTMP_ADAPTER pAd, IN BOOLEAN argc); -#ifdef DOT11_N_SUPPORT // AMPDU packet indication VOID Indicate_AMPDU_Packet( IN PRTMP_ADAPTER pAd, @@ -6600,7 +6100,6 @@ VOID Indicate_AMSDU_Packet( IN PRTMP_ADAPTER pAd, IN RX_BLK *pRxBlk, IN UCHAR FromWhichBSSID); -#endif // DOT11_N_SUPPORT // // Normal legacy Rx packet indication VOID Indicate_Legacy_Packet( @@ -6630,8 +6129,6 @@ UINT deaggregate_AMSDU_announce( IN PUCHAR pData, IN ULONG DataSize); - -#ifdef CONFIG_STA_SUPPORT // remove LLC and get 802_3 Header #define RTMP_802_11_REMOVE_LLC_AND_CONVERT_TO_802_3(_pRxBlk, _pHeader802_3) \ { \ @@ -6662,8 +6159,6 @@ UINT deaggregate_AMSDU_announce( CONVERT_TO_802_3(_pHeader802_3, _pDA, _pSA, _pRxBlk->pData, \ _pRxBlk->DataSize, _pRemovedLLCSNAP); \ } -#endif // CONFIG_STA_SUPPORT // - BOOLEAN APFowardWirelessStaToWirelessSta( IN PRTMP_ADAPTER pAd, @@ -6680,13 +6175,9 @@ VOID Sta_Announce_or_Forward_802_3_Packet( IN PNDIS_PACKET pPacket, IN UCHAR FromWhichBSSID); - -#ifdef CONFIG_STA_SUPPORT #define ANNOUNCE_OR_FORWARD_802_3_PACKET(_pAd, _pPacket, _FromWhichBSS)\ Sta_Announce_or_Forward_802_3_Packet(_pAd, _pPacket, _FromWhichBSS); //announce_802_3_packet(_pAd, _pPacket); -#endif // CONFIG_STA_SUPPORT // - PNDIS_PACKET DuplicatePacket( IN PRTMP_ADAPTER pAd, @@ -6729,22 +6220,6 @@ PNDIS_PACKET RTMPDeFragmentDataFrame( IN RX_BLK *pRxBlk); //////////////////////////////////////// - - - - - -#ifdef SNMP_SUPPORT -//for snmp , kathy -typedef struct _DefaultKeyIdxValue -{ - UCHAR KeyIdx; - UCHAR Value[16]; -} DefaultKeyIdxValue, *PDefaultKeyIdxValue; -#endif - - -#ifdef CONFIG_STA_SUPPORT enum { DIDmsg_lnxind_wlansniffrm = 0x00000044, DIDmsg_lnxind_wlansniffrm_hosttime = 0x00010044, @@ -6857,18 +6332,11 @@ struct iw_statistics *rt28xx_get_wireless_stats( VOID RTMPSetDesiredRates( IN PRTMP_ADAPTER pAdapter, IN LONG Rates); -#endif // CONFIG_STA_SUPPORT // INT Set_FixedTxMode_Proc( IN PRTMP_ADAPTER pAd, IN PUCHAR arg); -#ifdef CONFIG_APSTA_MIXED_SUPPORT -INT Set_OpMode_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); -#endif // CONFIG_APSTA_MIXED_SUPPORT // - static inline char* GetPhyMode( int Mode) { @@ -6879,13 +6347,11 @@ static inline char* GetPhyMode( case MODE_OFDM: return "OFDM"; -#ifdef DOT11_N_SUPPORT case MODE_HTMIX: return "HTMIX"; case MODE_HTGREENFIELD: return "GREEN"; -#endif // DOT11_N_SUPPORT // default: return "N/A"; } @@ -6902,10 +6368,8 @@ static inline char* GetBW( case BW_20: return "20M"; -#ifdef DOT11_N_SUPPORT case BW_40: return "40M"; -#endif // DOT11_N_SUPPORT // default: return "N/A"; } @@ -6945,13 +6409,10 @@ INT rt28xx_ioctl( IN OUT struct ifreq *rq, IN INT cmd); - -#ifdef CONFIG_STA_SUPPORT INT rt28xx_sta_ioctl( IN struct net_device *net_dev, IN OUT struct ifreq *rq, IN INT cmd); -#endif // CONFIG_STA_SUPPORT // BOOLEAN RT28XXSecurityKeyAdd( IN PRTMP_ADAPTER pAd, @@ -6971,6 +6432,7 @@ void kill_thread_task(PRTMP_ADAPTER pAd); void tbtt_tasklet(unsigned long data); +#ifdef RT2860 // // Function Prototype in cmm_data_2860.c // @@ -7035,7 +6497,6 @@ NDIS_STATUS RTMPCheckRxError( IN PRXWI_STRUC pRxWI, IN PRT28XX_RXD_STRUC pRxD); -#ifdef CONFIG_STA_SUPPORT VOID RTMPInitPCIeLinkCtrlValue( IN PRTMP_ADAPTER pAd); @@ -7078,13 +6539,13 @@ VOID RadioOnExec( IN PVOID FunctionContext, IN PVOID SystemSpecific2, IN PVOID SystemSpecific3); -#endif // CONFIG_STA_SUPPORT // VOID RT28xxPciMlmeRadioOn( IN PRTMP_ADAPTER pAd); VOID RT28xxPciMlmeRadioOFF( IN PRTMP_ADAPTER pAd); +#endif /* RT2860 */ VOID AsicTurnOffRFClk( IN PRTMP_ADAPTER pAd, @@ -7094,6 +6555,493 @@ VOID AsicTurnOnRFClk( IN PRTMP_ADAPTER pAd, IN UCHAR Channel); +#ifdef RT30xx +NTSTATUS RT30xxWriteRFRegister( + IN PRTMP_ADAPTER pAd, + IN UCHAR RegID, + IN UCHAR Value); + +NTSTATUS RT30xxReadRFRegister( + IN PRTMP_ADAPTER pAd, + IN UCHAR RegID, + IN PUCHAR pValue); + +//2008/09/11:KH add to support efuse<-- +UCHAR eFuseReadRegisters( + IN PRTMP_ADAPTER pAd, + IN USHORT Offset, + IN USHORT Length, + OUT USHORT* pData); + +VOID eFuseReadPhysical( + IN PRTMP_ADAPTER pAd, + IN PUSHORT lpInBuffer, + IN ULONG nInBufferSize, + OUT PUSHORT lpOutBuffer, + IN ULONG nOutBufferSize +); + +NTSTATUS eFuseRead( + IN PRTMP_ADAPTER pAd, + IN USHORT Offset, + OUT PUCHAR pData, + IN USHORT Length); + +VOID eFusePhysicalWriteRegisters( + IN PRTMP_ADAPTER pAd, + IN USHORT Offset, + IN USHORT Length, + OUT USHORT* pData); + +NTSTATUS eFuseWriteRegisters( + IN PRTMP_ADAPTER pAd, + IN USHORT Offset, + IN USHORT Length, + IN USHORT* pData); + +VOID eFuseWritePhysical( + IN PRTMP_ADAPTER pAd, + PUSHORT lpInBuffer, + ULONG nInBufferSize, + PUCHAR lpOutBuffer, + ULONG nOutBufferSize +); + +NTSTATUS eFuseWrite( + IN PRTMP_ADAPTER pAd, + IN USHORT Offset, + IN PUCHAR pData, + IN USHORT length); + +INT set_eFuseGetFreeBlockCount_Proc( + IN PRTMP_ADAPTER pAd, + IN PUCHAR arg); + +INT set_eFusedump_Proc( + IN PRTMP_ADAPTER pAd, + IN PUCHAR arg); + +INT set_eFuseLoadFromBin_Proc( + IN PRTMP_ADAPTER pAd, + IN PUCHAR arg); + +NTSTATUS eFuseWriteRegistersFromBin( + IN PRTMP_ADAPTER pAd, + IN USHORT Offset, + IN USHORT Length, + IN USHORT* pData); + +VOID eFusePhysicalReadRegisters( + IN PRTMP_ADAPTER pAd, + IN USHORT Offset, + IN USHORT Length, + OUT USHORT* pData); + +NDIS_STATUS NICLoadEEPROM( + IN PRTMP_ADAPTER pAd); + +BOOLEAN bNeedLoadEEPROM( + IN PRTMP_ADAPTER pAd); +//2008/09/11:KH add to support efuse--> +#endif // RT30xx // + +#ifdef RT30xx +// add by johnli, RF power sequence setup +VOID RT30xxLoadRFNormalModeSetup( + IN PRTMP_ADAPTER pAd); + +VOID RT30xxLoadRFSleepModeSetup( + IN PRTMP_ADAPTER pAd); + +VOID RT30xxReverseRFSleepModeSetup( + IN PRTMP_ADAPTER pAd); +// end johnli +#endif // RT30xx // + +#ifdef RT2870 +// +// Function Prototype in rtusb_bulk.c +// +VOID RTUSBInitTxDesc( + IN PRTMP_ADAPTER pAd, + IN PTX_CONTEXT pTxContext, + IN UCHAR BulkOutPipeId, + IN usb_complete_t Func); + +VOID RTUSBInitHTTxDesc( + IN PRTMP_ADAPTER pAd, + IN PHT_TX_CONTEXT pTxContext, + IN UCHAR BulkOutPipeId, + IN ULONG BulkOutSize, + IN usb_complete_t Func); + +VOID RTUSBInitRxDesc( + IN PRTMP_ADAPTER pAd, + IN PRX_CONTEXT pRxContext); + +VOID RTUSBCleanUpDataBulkOutQueue( + IN PRTMP_ADAPTER pAd); + +VOID RTUSBCancelPendingBulkOutIRP( + IN PRTMP_ADAPTER pAd); + +VOID RTUSBBulkOutDataPacket( + IN PRTMP_ADAPTER pAd, + IN UCHAR BulkOutPipeId, + IN UCHAR Index); + +VOID RTUSBBulkOutNullFrame( + IN PRTMP_ADAPTER pAd); + +VOID RTUSBBulkOutRTSFrame( + IN PRTMP_ADAPTER pAd); + +VOID RTUSBCancelPendingBulkInIRP( + IN PRTMP_ADAPTER pAd); + +VOID RTUSBCancelPendingIRPs( + IN PRTMP_ADAPTER pAd); + +VOID RTUSBBulkOutMLMEPacket( + IN PRTMP_ADAPTER pAd, + IN UCHAR Index); + +VOID RTUSBBulkOutPsPoll( + IN PRTMP_ADAPTER pAd); + +VOID RTUSBCleanUpMLMEBulkOutQueue( + IN PRTMP_ADAPTER pAd); + +VOID RTUSBKickBulkOut( + IN PRTMP_ADAPTER pAd); + +VOID RTUSBBulkReceive( + IN PRTMP_ADAPTER pAd); + +VOID DoBulkIn( + IN RTMP_ADAPTER *pAd); + +VOID RTUSBInitRxDesc( + IN PRTMP_ADAPTER pAd, + IN PRX_CONTEXT pRxContext); + +VOID RTUSBBulkRxHandle( + IN unsigned long data); + +// +// Function Prototype in rtusb_io.c +// +NTSTATUS RTUSBMultiRead( + IN PRTMP_ADAPTER pAd, + IN USHORT Offset, + OUT PUCHAR pData, + IN USHORT length); + +NTSTATUS RTUSBMultiWrite( + IN PRTMP_ADAPTER pAd, + IN USHORT Offset, + IN PUCHAR pData, + IN USHORT length); + +NTSTATUS RTUSBMultiWrite_OneByte( + IN PRTMP_ADAPTER pAd, + IN USHORT Offset, + IN PUCHAR pData); + +NTSTATUS RTUSBReadBBPRegister( + IN PRTMP_ADAPTER pAd, + IN UCHAR Id, + IN PUCHAR pValue); + +NTSTATUS RTUSBWriteBBPRegister( + IN PRTMP_ADAPTER pAd, + IN UCHAR Id, + IN UCHAR Value); + +NTSTATUS RTUSBWriteRFRegister( + IN PRTMP_ADAPTER pAd, + IN UINT32 Value); + +#ifndef RT30xx +NTSTATUS RT30xxWriteRFRegister( + IN PRTMP_ADAPTER pAd, + IN UCHAR RegID, + IN UCHAR Value); + +NTSTATUS RT30xxReadRFRegister( + IN PRTMP_ADAPTER pAd, + IN UCHAR RegID, + IN PUCHAR pValue); +#endif + +NTSTATUS RTUSB_VendorRequest( + IN PRTMP_ADAPTER pAd, + IN UINT32 TransferFlags, + IN UCHAR ReservedBits, + IN UCHAR Request, + IN USHORT Value, + IN USHORT Index, + IN PVOID TransferBuffer, + IN UINT32 TransferBufferLength); + +NTSTATUS RTUSBReadEEPROM( + IN PRTMP_ADAPTER pAd, + IN USHORT Offset, + OUT PUCHAR pData, + IN USHORT length); + +NTSTATUS RTUSBWriteEEPROM( + IN PRTMP_ADAPTER pAd, + IN USHORT Offset, + IN PUCHAR pData, + IN USHORT length); + +VOID RTUSBPutToSleep( + IN PRTMP_ADAPTER pAd); + +NTSTATUS RTUSBWakeUp( + IN PRTMP_ADAPTER pAd); + +VOID RTUSBInitializeCmdQ( + IN PCmdQ cmdq); + +NDIS_STATUS RTUSBEnqueueCmdFromNdis( + IN PRTMP_ADAPTER pAd, + IN NDIS_OID Oid, + IN BOOLEAN SetInformation, + IN PVOID pInformationBuffer, + IN UINT32 InformationBufferLength); + +NDIS_STATUS RTUSBEnqueueInternalCmd( + IN PRTMP_ADAPTER pAd, + IN NDIS_OID Oid, + IN PVOID pInformationBuffer, + IN UINT32 InformationBufferLength); + +VOID RTUSBDequeueCmd( + IN PCmdQ cmdq, + OUT PCmdQElmt *pcmdqelmt); + +INT RTUSBCmdThread( + IN OUT PVOID Context); + +INT TimerQThread( + IN OUT PVOID Context); + +RT2870_TIMER_ENTRY *RT2870_TimerQ_Insert( + IN RTMP_ADAPTER *pAd, + IN RALINK_TIMER_STRUCT *pTimer); + +BOOLEAN RT2870_TimerQ_Remove( + IN RTMP_ADAPTER *pAd, + IN RALINK_TIMER_STRUCT *pTimer); + +void RT2870_TimerQ_Exit( + IN RTMP_ADAPTER *pAd); + +void RT2870_TimerQ_Init( + IN RTMP_ADAPTER *pAd); + +VOID RT2870_BssBeaconExit( + IN RTMP_ADAPTER *pAd); + +VOID RT2870_BssBeaconStop( + IN RTMP_ADAPTER *pAd); + +VOID RT2870_BssBeaconStart( + IN RTMP_ADAPTER * pAd); + +VOID RT2870_BssBeaconInit( + IN RTMP_ADAPTER *pAd); + +VOID RT2870_WatchDog( + IN RTMP_ADAPTER *pAd); + +NTSTATUS RTUSBWriteMACRegister( + IN PRTMP_ADAPTER pAd, + IN USHORT Offset, + IN UINT32 Value); + +NTSTATUS RTUSBReadMACRegister( + IN PRTMP_ADAPTER pAd, + IN USHORT Offset, + OUT PUINT32 pValue); + +NTSTATUS RTUSBSingleWrite( + IN RTMP_ADAPTER *pAd, + IN USHORT Offset, + IN USHORT Value); + +NTSTATUS RTUSBFirmwareRun( + IN PRTMP_ADAPTER pAd); + +NTSTATUS RTUSBFirmwareWrite( + IN PRTMP_ADAPTER pAd, + IN PUCHAR pFwImage, + IN ULONG FwLen); + +NTSTATUS RTUSBFirmwareOpmode( + IN PRTMP_ADAPTER pAd, + OUT PUINT32 pValue); + +NTSTATUS RTUSBVenderReset( + IN PRTMP_ADAPTER pAd); + +NDIS_STATUS RTUSBSetHardWareRegister( + IN PRTMP_ADAPTER pAdapter, + IN PVOID pBuf); + +NDIS_STATUS RTUSBQueryHardWareRegister( + IN PRTMP_ADAPTER pAdapter, + IN PVOID pBuf); + +VOID CMDHandler( + IN PRTMP_ADAPTER pAd); + + +NDIS_STATUS CreateThreads( + IN struct net_device *net_dev ); + + +VOID MacTableInitialize( + IN PRTMP_ADAPTER pAd); + +VOID MlmeSetPsm( + IN PRTMP_ADAPTER pAd, + IN USHORT psm); + +NDIS_STATUS RTMPWPAAddKeyProc( + IN PRTMP_ADAPTER pAd, + IN PVOID pBuf); + +VOID AsicRxAntEvalAction( + IN PRTMP_ADAPTER pAd); + +void append_pkt( + IN PRTMP_ADAPTER pAd, + IN PUCHAR pHeader802_3, + IN UINT HdrLen, + IN PUCHAR pData, + IN ULONG DataSize, + OUT PNDIS_PACKET *ppPacket); + +UINT deaggregate_AMSDU_announce( + IN PRTMP_ADAPTER pAd, + PNDIS_PACKET pPacket, + IN PUCHAR pData, + IN ULONG DataSize); + +NDIS_STATUS RTMPCheckRxError( + IN PRTMP_ADAPTER pAd, + IN PHEADER_802_11 pHeader, + IN PRXWI_STRUC pRxWI, + IN PRT28XX_RXD_STRUC pRxINFO); + + +VOID RTUSBMlmeHardTransmit( + IN PRTMP_ADAPTER pAd, + IN PMGMT_STRUC pMgmt); + +INT MlmeThread( + IN PVOID Context); + +// +// Function Prototype in rtusb_data.c +// +NDIS_STATUS RTUSBFreeDescriptorRequest( + IN PRTMP_ADAPTER pAd, + IN UCHAR BulkOutPipeId, + IN UINT32 NumberRequired); + + +BOOLEAN RTUSBNeedQueueBackForAgg( + IN RTMP_ADAPTER *pAd, + IN UCHAR BulkOutPipeId); + + +VOID RTMPWriteTxInfo( + IN PRTMP_ADAPTER pAd, + IN PTXINFO_STRUC pTxInfo, + IN USHORT USBDMApktLen, + IN BOOLEAN bWiv, + IN UCHAR QueueSel, + IN UCHAR NextValid, + IN UCHAR TxBurst); + +// +// Function Prototype in cmm_data_2870.c +// +USHORT RtmpUSB_WriteSubTxResource( + IN PRTMP_ADAPTER pAd, + IN TX_BLK *pTxBlk, + IN BOOLEAN bIsLast, + OUT USHORT *FreeNumber); + +USHORT RtmpUSB_WriteSingleTxResource( + IN PRTMP_ADAPTER pAd, + IN TX_BLK *pTxBlk, + IN BOOLEAN bIsLast, + OUT USHORT *FreeNumber); + +USHORT RtmpUSB_WriteFragTxResource( + IN PRTMP_ADAPTER pAd, + IN TX_BLK *pTxBlk, + IN UCHAR fragNum, + OUT USHORT *FreeNumber); + +USHORT RtmpUSB_WriteMultiTxResource( + IN PRTMP_ADAPTER pAd, + IN TX_BLK *pTxBlk, + IN UCHAR frameNum, + OUT USHORT *FreeNumber); + +VOID RtmpUSB_FinalWriteTxResource( + IN PRTMP_ADAPTER pAd, + IN TX_BLK *pTxBlk, + IN USHORT totalMPDUSize, +#ifdef RT2860 + IN USHORT FirstTxIdx); +#endif + IN USHORT TxIdx); + +VOID RtmpUSBDataLastTxIdx( + IN PRTMP_ADAPTER pAd, + IN UCHAR QueIdx, + IN USHORT TxIdx); + +VOID RtmpUSBDataKickOut( + IN PRTMP_ADAPTER pAd, + IN TX_BLK *pTxBlk, + IN UCHAR QueIdx); + + +int RtmpUSBMgmtKickOut( + IN RTMP_ADAPTER *pAd, + IN UCHAR QueIdx, + IN PNDIS_PACKET pPacket, + IN PUCHAR pSrcBufVA, + IN UINT SrcBufLen); + +VOID RtmpUSBNullFrameKickOut( + IN RTMP_ADAPTER *pAd, + IN UCHAR QueIdx, + IN UCHAR *pNullFrame, + IN UINT32 frameLen); + +VOID RT28xxUsbStaAsicForceWakeup( + IN PRTMP_ADAPTER pAd, + IN BOOLEAN bFromTx); + +VOID RT28xxUsbStaAsicSleepThenAutoWakeup( + IN PRTMP_ADAPTER pAd, + IN USHORT TbttNumToNextWakeUp); + +VOID RT28xxUsbMlmeRadioOn( + IN PRTMP_ADAPTER pAd); + +VOID RT28xxUsbMlmeRadioOFF( + IN PRTMP_ADAPTER pAd); +#endif // RT2870 // //////////////////////////////////////// @@ -7120,10 +7068,10 @@ PCHAR RTMPGetRalinkEncryModeStr( IN USHORT encryMode); ////////////////////////////////////// -#ifdef CONFIG_STA_SUPPORT VOID AsicStaBbpTuning( IN PRTMP_ADAPTER pAd); +#ifdef RT2860 VOID AsicResetFromDMABusy( IN PRTMP_ADAPTER pAd); @@ -7135,7 +7083,16 @@ VOID AsicResetMAC( VOID AsicResetPBF( IN PRTMP_ADAPTER pAd); -#endif // CONFIG_STA_SUPPORT // +#endif +#ifdef RT2870 +BOOLEAN StaAddMacTableEntry( + IN PRTMP_ADAPTER pAd, + IN PMAC_TABLE_ENTRY pEntry, + IN UCHAR MaxSupportedRateIn500Kbps, + IN HT_CAPABILITY_IE *pHtCapability, + IN UCHAR HtCapabilityLen, + IN USHORT CapabilityInfo); +#endif void RTMP_IndicateMediaState( IN PRTMP_ADAPTER pAd); diff --git a/drivers/staging/rt2860/rtmp_def.h b/drivers/staging/rt2860/rtmp_def.h index 25a53d83a0d7..5dde860cbbd4 100644 --- a/drivers/staging/rt2860/rtmp_def.h +++ b/drivers/staging/rt2860/rtmp_def.h @@ -54,15 +54,6 @@ #define NIC_TAG ((ULONG)'0682') #define NIC_DBG_STRING ("**RT28xx**") -#ifdef SNMP_SUPPORT -// for snmp -// to get manufacturer OUI, kathy, 2008_0220 -#define ManufacturerOUI_LEN 3 -#define ManufacturerNAME ("Ralink Technology Company.") -#define ResourceTypeIdName ("Ralink_ID") -#endif - - #define RALINK_2883_VERSION ((UINT32)0x28830300) #define RALINK_2880E_VERSION ((UINT32)0x28720200) #define RALINK_3070_VERSION ((UINT32)0x30700200) @@ -111,6 +102,7 @@ // Entry number for each DMA descriptor ring // +#ifdef RT2860 #define TX_RING_SIZE 64 //64 #define MGMT_RING_SIZE 128 #define RX_RING_SIZE 128 //64 @@ -118,12 +110,15 @@ #define MAX_DMA_DONE_PROCESS TX_RING_SIZE #define MAX_TX_DONE_PROCESS TX_RING_SIZE //8 #define LOCAL_TXBUF_SIZE 2 - - -#ifdef MULTIPLE_CARD_SUPPORT -// MC: Multple Cards -#define MAX_NUM_OF_MULTIPLE_CARD 32 -#endif // MULTIPLE_CARD_SUPPORT // +#endif +#ifdef RT2870 +#define TX_RING_SIZE 8 // 1 +#define PRIO_RING_SIZE 8 +#define MGMT_RING_SIZE 32 // PRIO_RING_SIZE +#define RX_RING_SIZE 8 +#define MAX_TX_PROCESS 4 +#define LOCAL_TXBUF_SIZE 2048 +#endif // RT2870 // #define MAX_RX_PROCESS 128 //64 //32 #define NUM_OF_LOCAL_TXBUF 2 @@ -153,7 +148,11 @@ #define MAX_PACKETS_IN_PS_QUEUE 128 //32 #define WMM_NUM_OF_AC 4 /* AC0, AC1, AC2, and AC3 */ - +#ifdef RT30xx +//2008/09/11:KH add to support efuse<-- +#define MAX_EEPROM_BIN_FILE_SIZE 1024 +//2008/09/11:KH add to support efuse--> +#endif // RxFilter #define STANORMAL 0x17f97 @@ -210,6 +209,7 @@ #define fOP_STATUS_WAKEUP_NOW 0x00008000 #define fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE 0x00020000 +#ifdef RT2860 // // RTMP_ADAPTER PSFlags : related to advanced power save. // @@ -222,10 +222,7 @@ // Indicate driver should IMMEDIATELY fo to sleep after receiving AP's beacon in which doesn't indicate unicate nor multicast packets for me //. This flag is used ONLY in RTMPHandleRxDoneInterrupt routine. #define fRTMP_PS_GO_TO_SLEEP_NOW 0x00000008 - -#ifdef DOT11N_DRAFT3 -#define fOP_STATUS_SCAN_2040 0x00040000 -#endif // DOT11N_DRAFT3 // +#endif #define CCKSETPROTECT 0x1 #define OFDMSETPROTECT 0x2 @@ -251,10 +248,6 @@ #define fCLIENT_STATUS_MCSFEEDBACK_CAPABLE 0x00000400 #define fCLIENT_STATUS_APSD_CAPABLE 0x00000800 /* UAPSD STATION */ -#ifdef DOT11N_DRAFT3 -#define fCLIENT_STATUS_BSSCOEXIST_CAPABLE 0x00001000 -#endif // DOT11N_DRAFT3 // - #define fCLIENT_STATUS_RALINK_CHIPSET 0x00100000 // // STA configuration flags @@ -330,16 +323,14 @@ #define MAX_MESH_NUM 0 #define MAX_APCLI_NUM 0 -#ifdef APCLI_SUPPORT -#undef MAX_APCLI_NUM -#define MAX_APCLI_NUM 1 -#endif // APCLI_SUPPORT // #define MAX_MBSSID_NUM 1 +#if defined(RT2860) || defined(RT30xx) #ifdef MBSS_SUPPORT #undef MAX_MBSSID_NUM #define MAX_MBSSID_NUM (8 - MAX_MESH_NUM - MAX_APCLI_NUM) #endif // MBSS_SUPPORT // +#endif /* sanity check for apidx */ #define MBSS_MR_APIDX_SANITY_CHECK(apidx) \ @@ -582,6 +573,9 @@ // For 802.11n D3.03 //#define IE_NEW_EXT_CHA_OFFSET 62 // 802.11n d1. New extension channel offset elemet #define IE_SECONDARY_CH_OFFSET 62 // 802.11n D3.03 Secondary Channel Offset element +#ifdef RT2870 +#define IE_WAPI 68 // WAPI information element +#endif #define IE_2040_BSS_COEXIST 72 // 802.11n D3.0.3 #define IE_2040_BSS_INTOLERANT_REPORT 73 // 802.11n D3.03 #define IE_OVERLAPBSS_SCAN_PARM 74 // 802.11n D3.03 @@ -630,9 +624,10 @@ #define AP_CNTL_STATE_MACHINE 15 #define AP_WPA_STATE_MACHINE 16 -#ifdef QOS_DLS_SUPPORT -#define DLS_STATE_MACHINE 26 -#endif // QOS_DLS_SUPPORT // +#ifdef RT30xx +#define WSC_STATE_MACHINE 17 +#define WSC_UPNP_STATE_MACHINE 18 +#endif // // STA's CONTROL/CONNECT state machine: states, events, total function # @@ -647,6 +642,9 @@ #define CNTL_WAIT_AUTH2 7 #define CNTL_WAIT_OID_LIST_SCAN 8 #define CNTL_WAIT_OID_DISASSOC 9 +#ifdef RT2870 +#define CNTL_WAIT_SCAN_FOR_CONNECT 10 +#endif // RT2870 // #define MT2_ASSOC_CONF 34 #define MT2_AUTH_CONF 35 @@ -948,79 +946,6 @@ #define AP_WPA_FUNC_SIZE (AP_MAX_WPA_PTK_STATE * AP_MAX_WPA_MSG) -#ifdef APCLI_SUPPORT -//ApCli authentication state machine -#define APCLI_AUTH_REQ_IDLE 0 -#define APCLI_AUTH_WAIT_SEQ2 1 -#define APCLI_AUTH_WAIT_SEQ4 2 -#define APCLI_MAX_AUTH_STATE 3 - -#define APCLI_AUTH_MACHINE_BASE 0 -#define APCLI_MT2_MLME_AUTH_REQ 0 -#define APCLI_MT2_MLME_DEAUTH_REQ 1 -#define APCLI_MT2_PEER_AUTH_EVEN 2 -#define APCLI_MT2_PEER_DEAUTH 3 -#define APCLI_MT2_AUTH_TIMEOUT 4 -#define APCLI_MAX_AUTH_MSG 5 - -#define APCLI_AUTH_FUNC_SIZE (APCLI_MAX_AUTH_STATE * APCLI_MAX_AUTH_MSG) - -//ApCli association state machine -#define APCLI_ASSOC_IDLE 0 -#define APCLI_ASSOC_WAIT_RSP 1 -#define APCLI_MAX_ASSOC_STATE 2 - -#define APCLI_ASSOC_MACHINE_BASE 0 -#define APCLI_MT2_MLME_ASSOC_REQ 0 -#define APCLI_MT2_MLME_DISASSOC_REQ 1 -#define APCLI_MT2_PEER_DISASSOC_REQ 2 -#define APCLI_MT2_PEER_ASSOC_RSP 3 -#define APCLI_MT2_ASSOC_TIMEOUT 4 -#define APCLI_MAX_ASSOC_MSG 5 - -#define APCLI_ASSOC_FUNC_SIZE (APCLI_MAX_ASSOC_STATE * APCLI_MAX_ASSOC_MSG) - -//ApCli sync state machine -#define APCLI_SYNC_IDLE 0 // merge NO_BSS,IBSS_IDLE,IBSS_ACTIVE and BSS in to 1 state -#define APCLI_JOIN_WAIT_PROBE_RSP 1 -#define APCLI_MAX_SYNC_STATE 2 - -#define APCLI_SYNC_MACHINE_BASE 0 -#define APCLI_MT2_MLME_PROBE_REQ 0 -#define APCLI_MT2_PEER_PROBE_RSP 1 -#define APCLI_MT2_PROBE_TIMEOUT 2 -#define APCLI_MAX_SYNC_MSG 3 - -#define APCLI_SYNC_FUNC_SIZE (APCLI_MAX_SYNC_STATE * APCLI_MAX_SYNC_MSG) - -//ApCli ctrl state machine -#define APCLI_CTRL_DISCONNECTED 0 // merge NO_BSS,IBSS_IDLE,IBSS_ACTIVE and BSS in to 1 state -#define APCLI_CTRL_PROBE 1 -#define APCLI_CTRL_AUTH 2 -#define APCLI_CTRL_AUTH_2 3 -#define APCLI_CTRL_ASSOC 4 -#define APCLI_CTRL_DEASSOC 5 -#define APCLI_CTRL_CONNECTED 6 -#define APCLI_MAX_CTRL_STATE 7 - -#define APCLI_CTRL_MACHINE_BASE 0 -#define APCLI_CTRL_JOIN_REQ 0 -#define APCLI_CTRL_PROBE_RSP 1 -#define APCLI_CTRL_AUTH_RSP 2 -#define APCLI_CTRL_DISCONNECT_REQ 3 -#define APCLI_CTRL_PEER_DISCONNECT_REQ 4 -#define APCLI_CTRL_ASSOC_RSP 5 -#define APCLI_CTRL_DEASSOC_RSP 6 -#define APCLI_CTRL_JOIN_REQ_TIMEOUT 7 -#define APCLI_CTRL_AUTH_REQ_TIMEOUT 8 -#define APCLI_CTRL_ASSOC_REQ_TIMEOUT 9 -#define APCLI_MAX_CTRL_MSG 10 - -#define APCLI_CTRL_FUNC_SIZE (APCLI_MAX_CTRL_STATE * APCLI_MAX_CTRL_MSG) - -#endif // APCLI_SUPPORT // - - // ============================================================================= // value domain of 802.11 header FC.Tyte, which is b3..b2 of the 1st-byte of MAC header @@ -1107,10 +1032,9 @@ // Preamble MODE in TxD #define MODE_CCK 0 #define MODE_OFDM 1 -#ifdef DOT11_N_SUPPORT #define MODE_HTMIX 2 #define MODE_HTGREENFIELD 3 -#endif // DOT11_N_SUPPORT // + // MCS for CCK. BW.SGI.STBC are reserved #define MCS_LONGP_RATE_1 0 // long preamble CCK 1Mbps #define MCS_LONGP_RATE_2 1 // long preamble CCK 1Mbps @@ -1157,12 +1081,10 @@ #define MCS_32 32 #define MCS_AUTO 33 -#ifdef DOT11_N_SUPPORT // OID_HTPHYMODE // MODE #define HTMODE_MM 0 #define HTMODE_GF 1 -#endif // DOT11_N_SUPPORT // // Fixed Tx MODE - HT, CCK or OFDM #define FIXED_TXMODE_HT 0 @@ -1174,15 +1096,12 @@ #define BW_BOTH BAND_WIDTH_BOTH #define BW_10 BAND_WIDTH_10 // 802.11j has 10MHz. This definition is for internal usage. doesn't fill in the IE or other field. -#ifdef DOT11_N_SUPPORT // SHORTGI #define GI_400 GAP_INTERVAL_400 // only support in HT mode #define GI_BOTH GAP_INTERVAL_BOTH -#endif // DOT11_N_SUPPORT // #define GI_800 GAP_INTERVAL_800 // STBC #define STBC_NONE 0 -#ifdef DOT11_N_SUPPORT #define STBC_USE 1 // limited use in rt2860b phy #define RXSTBC_ONE 1 // rx support of one spatial stream #define RXSTBC_TWO 2 // rx support of 1 and 2 spatial stream @@ -1204,8 +1123,6 @@ #define AMSDU_0 0 #define AMSDU_1 1 -#endif // DOT11_N_SUPPORT // - // MCS use 7 bits #define TXRATEMIMO 0x80 #define TXRATEMCS 0x7F @@ -1298,6 +1215,10 @@ #define RFIC_2750 4 // 2.4G/5G 1T2R #define RFIC_3020 5 // 2.4G 1T1R #define RFIC_2020 6 // 2.4G B/G +#ifdef RT30xx +#define RFIC_3021 7 // 2.4G 1T2R +#define RFIC_3022 8 // 2.4G 2T2R +#endif // LED Status. #define LED_LINK_DOWN 0 @@ -1353,17 +1274,6 @@ #define OPMODE_AP 1 //#define OPMODE_L3_BRG 2 // as AP and STA at the same time -#ifdef RT_BIG_ENDIAN -#define DIR_READ 0 -#define DIR_WRITE 1 -#define TYPE_TXD 0 -#define TYPE_RXD 1 -#define TYPE_TXINFO 0 -#define TYPE_RXINFO 1 -#define TYPE_TXWI 0 -#define TYPE_RXWI 1 -#endif - // ========================= AP rtmp_def.h =========================== // value domain for pAd->EventTab.Log[].Event #define EVENT_RESET_ACCESS_POINT 0 // Log = "hh:mm:ss Restart Access Point" @@ -1410,24 +1320,6 @@ #define INT_MESH 0x0500 // Use bitmap to allow coexist of ATE_TXFRAME and ATE_RXFRAME(i.e.,to support LoopBack mode) -#ifdef RALINK_ATE -#define ATE_START 0x00 // Start ATE -#define ATE_STOP 0x80 // Stop ATE -#define ATE_TXCONT 0x05 // Continuous Transmit -#define ATE_TXCARR 0x09 // Transmit Carrier -#define ATE_TXCARRSUPP 0x11 // Transmit Carrier Suppression -#define ATE_TXFRAME 0x01 // Transmit Frames -#define ATE_RXFRAME 0x02 // Receive Frames -#ifdef RALINK_28xx_QA -#define ATE_TXSTOP 0xe2 // Stop Transmition(i.e., TXCONT, TXCARR, TXCARRSUPP, and TXFRAME) -#define ATE_RXSTOP 0xfd // Stop receiving Frames -#define BBP22_TXFRAME 0x00 // Transmit Frames -#define BBP22_TXCONT_OR_CARRSUPP 0x80 // Continuous Transmit or Carrier Suppression -#define BBP22_TXCARR 0xc1 // Transmit Carrier -#define BBP24_TXCONT 0x00 // Continuous Transmit -#define BBP24_CARRSUPP 0x01 // Carrier Suppression -#endif // RALINK_28xx_QA // -#endif // RALINK_ATE // // WEP Key TYPE #define WEP_HEXADECIMAL_TYPE 0 @@ -1498,7 +1390,6 @@ // End - WIRELESS EVENTS definition -#ifdef CONFIG_STA_SUPPORT // definition for DLS, kathy #define MAX_NUM_OF_INIT_DLS_ENTRY 1 #define MAX_NUM_OF_DLS_ENTRY MAX_NUMBER_OF_DLS_ENTRY @@ -1508,15 +1399,12 @@ #define MAX_RX_REORDERBUF 64 #define DEFAULT_TX_TIMEOUT 30 #define DEFAULT_RX_TIMEOUT 30 -#ifndef CONFIG_AP_SUPPORT #define MAX_BARECI_SESSION 8 -#endif #ifndef IW_ESSID_MAX_SIZE /* Maximum size of the ESSID and pAd->nickname strings */ #define IW_ESSID_MAX_SIZE 32 #endif -#endif // CONFIG_STA_SUPPORT // #ifdef MCAST_RATE_SPECIFIC #define MCAST_DISABLE 0 @@ -1525,6 +1413,7 @@ #define MCAST_HTMIX 3 #endif // MCAST_RATE_SPECIFIC // +#ifdef RT2860 // For AsicRadioOff/AsicRadioOn/AsicForceWakeup function // This is to indicate from where to call this function. #define DOT11POWERSAVE 0 // TO do .11 power save sleep @@ -1532,8 +1421,14 @@ #define RTMP_HALT 2 // Called from Halt handler. #define GUI_IDLE_POWER_SAVE 3 // Call to sleep before link up with AP #define FROM_TX 4 // Force wake up from Tx packet. - - +#endif +#ifdef RT2870 +// For AsicRadioOff/AsicRadioOn function +#define DOT11POWERSAVE 0 +#define GUIRADIO_OFF 1 +#define RTMP_HALT 2 +#define GUI_IDLE_POWER_SAVE 3 +#endif // definition for WpaSupport flag #define WPA_SUPPLICANT_DISABLE 0 @@ -1564,23 +1459,6 @@ (UINT64)(((UINT64)(x) & (UINT64) 0x00ff000000000000ULL) >> 40) | \ (UINT64)(((UINT64)(x) & (UINT64) 0xff00000000000000ULL) >> 56) )) -#ifdef RT_BIG_ENDIAN - -#define cpu2le64(x) SWAP64((x)) -#define le2cpu64(x) SWAP64((x)) -#define cpu2le32(x) SWAP32((x)) -#define le2cpu32(x) SWAP32((x)) -#define cpu2le16(x) SWAP16((x)) -#define le2cpu16(x) SWAP16((x)) -#define cpu2be64(x) ((UINT64)(x)) -#define be2cpu64(x) ((UINT64)(x)) -#define cpu2be32(x) ((UINT32)(x)) -#define be2cpu32(x) ((UINT32)(x)) -#define cpu2be16(x) ((UINT16)(x)) -#define be2cpu16(x) ((UINT16)(x)) - -#else // Little_Endian - #define cpu2le64(x) ((UINT64)(x)) #define le2cpu64(x) ((UINT64)(x)) #define cpu2le32(x) ((UINT32)(x)) @@ -1594,8 +1472,6 @@ #define cpu2be16(x) SWAP16((x)) #define be2cpu16(x) SWAP16((x)) -#endif // RT_BIG_ENDIAN - #endif // __RTMP_DEF_H__ diff --git a/drivers/staging/rt2860/spectrum.h b/drivers/staging/rt2860/spectrum.h index 60f25dbdba9f..0a878ba81b48 100644 --- a/drivers/staging/rt2860/spectrum.h +++ b/drivers/staging/rt2860/spectrum.h @@ -46,16 +46,6 @@ typedef struct PACKED _CH_SW_ANN_INFO typedef union PACKED _MEASURE_REQ_MODE { -#ifdef RT_BIG_ENDIAN - struct PACKED - { - UINT8 Rev1:4; - UINT8 Report:1; - UINT8 Request:1; - UINT8 Enable:1; - UINT8 Rev0:1; - } field; -#else struct PACKED { UINT8 Rev0:1; @@ -64,7 +54,6 @@ typedef union PACKED _MEASURE_REQ_MODE UINT8 Report:1; UINT8 Rev1:4; } field; -#endif // RT_BIG_ENDIAN // UINT8 word; } MEASURE_REQ_MODE, *PMEASURE_REQ_MODE; @@ -85,17 +74,6 @@ typedef struct PACKED _MEASURE_REQ_INFO typedef union PACKED _MEASURE_BASIC_REPORT_MAP { -#ifdef RT_BIG_ENDIAN - struct PACKED - { - UINT8 Rev:3; - UINT8 Unmeasure:1; - UINT8 Radar:1; - UINT8 UnidentifiedSignal:1; - UINT8 OfdmPreamble:1; - UINT8 BSS:1; - } field; -#else struct PACKED { UINT8 BSS:1; @@ -105,7 +83,6 @@ typedef union PACKED _MEASURE_BASIC_REPORT_MAP UINT8 Unmeasure:1; UINT8 Rev:3; } field; -#endif // RT_BIG_ENDIAN // UINT8 word; } MEASURE_BASIC_REPORT_MAP, *PMEASURE_BASIC_REPORT_MAP; @@ -137,17 +114,10 @@ typedef union PACKED _MEASURE_REPORT_MODE { struct PACKED { -#ifdef RT_BIG_ENDIAN - UINT8 Rev:5; - UINT8 Refused:1; - UINT8 Incapable:1; - UINT8 Late:1; -#else UINT8 Late:1; UINT8 Incapable:1; UINT8 Refused:1; UINT8 Rev:5; -#endif // RT_BIG_ENDIAN // } field; UINT8 word; } MEASURE_REPORT_MODE, *PMEASURE_REPORT_MODE; diff --git a/drivers/staging/rt2860/sta/assoc.c b/drivers/staging/rt2860/sta/assoc.c index 34f1c1490f44..a0734c65bc2f 100644 --- a/drivers/staging/rt2860/sta/assoc.c +++ b/drivers/staging/rt2860/sta/assoc.c @@ -341,7 +341,6 @@ VOID MlmeAssocReqAction( FrameLen += tmp; } -#ifdef DOT11_N_SUPPORT // HT if ((pAd->MlmeAux.HtCapabilityLen > 0) && (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) { @@ -360,32 +359,14 @@ VOID MlmeAssocReqAction( } else { -#ifdef RT_BIG_ENDIAN - HT_CAPABILITY_IE HtCapabilityTmp; -#endif - -#ifndef RT_BIG_ENDIAN MakeOutgoingFrame(pOutBuffer + FrameLen, &TmpLen, 1, &HtCapIe, 1, &pAd->MlmeAux.HtCapabilityLen, pAd->MlmeAux.HtCapabilityLen, &pAd->MlmeAux.HtCapability, END_OF_ARGS); -#else - NdisZeroMemory(&HtCapabilityTmp, sizeof(HT_CAPABILITY_IE)); - NdisMoveMemory(&HtCapabilityTmp, &pAd->MlmeAux.HtCapability, pAd->MlmeAux.HtCapabilityLen); - *(USHORT *)(&HtCapabilityTmp.HtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.HtCapInfo)); - *(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo)); - - MakeOutgoingFrame(pOutBuffer + FrameLen, &TmpLen, - 1, &HtCapIe, - 1, &pAd->MlmeAux.HtCapabilityLen, - pAd->MlmeAux.HtCapabilityLen,&HtCapabilityTmp, - END_OF_ARGS); -#endif } FrameLen += TmpLen; } -#endif // DOT11_N_SUPPORT // // add Ralink proprietary IE to inform AP this STA is going to use AGGREGATION or PIGGY-BACK+AGGREGATION // Case I: (Aggregation + Piggy-Back) @@ -473,6 +454,11 @@ VOID MlmeAssocReqAction( RSNIe = IE_WPA2; } +#ifdef RT30xx +#ifdef SIOCSIWGENIE + if (pAd->StaCfg.WpaSupplicantUP != 1) +#endif // SIOCSIWGENIE // +#endif RTMPMakeRSNIE(pAd, pAd->StaCfg.AuthMode, pAd->StaCfg.WepStatus, BSS0); // Check for WPA PMK cache list @@ -499,6 +485,17 @@ VOID MlmeAssocReqAction( } } +#ifdef RT30xx +#ifdef SIOCSIWGENIE + if (pAd->StaCfg.WpaSupplicantUP == 1) + { + MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, + pAd->StaCfg.RSNIE_Len, pAd->StaCfg.RSN_IE, + END_OF_ARGS); + } + else +#endif +#endif { MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, 1, &RSNIe, @@ -509,6 +506,11 @@ VOID MlmeAssocReqAction( FrameLen += tmp; +#ifdef RT30xx +#ifdef SIOCSIWGENIE + if (pAd->StaCfg.WpaSupplicantUP != 1) +#endif +#endif { // Append Variable IE NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, &RSNIe, 1); @@ -560,34 +562,6 @@ VOID MlmeAssocReqAction( END_OF_ARGS); FrameLen += tmp; - // - // Add CipherSuite CCKM or LeapTkip if setting. - // -#ifdef LEAP_SUPPORT - if (LEAP_CCKM_ON(pAd)) - { - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - CipherSuiteCiscoCCKMLen, CipherSuiteCiscoCCKM, - END_OF_ARGS); - FrameLen += tmp; - - // Third add RSN - NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, CipherSuiteCiscoCCKM, CipherSuiteCiscoCCKMLen); //Save CipherSuite - VarIesOffset += CipherSuiteCiscoCCKMLen; - } - else if ((pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) && (pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled)) - { - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - CipherSuiteCCXTkipLen, CipherSuiteCCXTkip, - END_OF_ARGS); - FrameLen += tmp; - - // Third add RSN - NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, CipherSuiteCCXTkip, CipherSuiteCCXTkipLen); - VarIesOffset += CipherSuiteCCXTkipLen; - } -#endif // LEAP_SUPPORT // - // Add by James 03/06/27 // Set Variable IEs Length pAd->StaCfg.ReqVarIELen = VarIesOffset; @@ -647,23 +621,6 @@ VOID MlmeReassocReqAction( NDIS_STATUS NStatus; ULONG tmp; PUCHAR pOutBuffer = NULL; -//CCX 2.X -#ifdef LEAP_SUPPORT - UCHAR CkipFlag; - UCHAR CkipNegotiationBuffer[CKIP_NEGOTIATION_LENGTH]; - UCHAR AironetCkipIe = IE_AIRONET_CKIP; - UCHAR AironetCkipLen = CKIP_NEGOTIATION_LENGTH; - UCHAR AironetIPAddressIE = IE_AIRONET_IPADDRESS; - UCHAR AironetIPAddressLen = AIRONET_IPADDRESS_LENGTH; - UCHAR AironetIPAddressBuffer[AIRONET_IPADDRESS_LENGTH] = {0x00, 0x40, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00}; - UCHAR AironetCCKMReassocIE = IE_AIRONET_CCKMREASSOC; - UCHAR AironetCCKMReassocLen = AIRONET_CCKMREASSOC_LENGTH; - UCHAR AironetCCKMReassocBuffer[AIRONET_CCKMREASSOC_LENGTH]; - UCHAR AironetOUI[] = {0x00, 0x40, 0x96, 0x00}; - UCHAR MICMN[16]; - UCHAR CalcMicBuffer[80]; - ULONG CalcMicBufferLen = 0; -#endif // LEAP_SUPPORT // USHORT Status; // Block all authentication request durning WPA block period @@ -738,7 +695,6 @@ VOID MlmeReassocReqAction( FrameLen += tmp; } -#ifdef DOT11_N_SUPPORT // HT if ((pAd->MlmeAux.HtCapabilityLen > 0) && (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) { @@ -765,7 +721,6 @@ VOID MlmeReassocReqAction( } FrameLen += TmpLen; } -#endif // DOT11_N_SUPPORT // // add Ralink proprietary IE to inform AP this STA is going to use AGGREGATION or PIGGY-BACK+AGGREGATION // Case I: (Aggregation + Piggy-Back) @@ -805,73 +760,6 @@ VOID MlmeReassocReqAction( END_OF_ARGS); FrameLen += TmpLen; } -#ifdef LEAP_SUPPORT - if (LEAP_CCKM_ON(pAd) && (pAd->StaCfg.CCKMLinkUpFlag == TRUE)) - { - CkipFlag = pAd->StaCfg.CkipFlag; // We have update that at PeerBeaconAtJoinRequest() - if (CkipFlag != 0) - { - NdisZeroMemory(CkipNegotiationBuffer, CKIP_NEGOTIATION_LENGTH); - CkipNegotiationBuffer[2] = 0x66; - // Make it try KP & MIC, since we have to follow the result from AssocRsp - CkipNegotiationBuffer[8] = 0x18; - CkipNegotiationBuffer[CKIP_NEGOTIATION_LENGTH - 1] = 0x22; - - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - 1, &AironetCkipIe, - 1, &AironetCkipLen, - AironetCkipLen, CkipNegotiationBuffer, - END_OF_ARGS); - FrameLen += tmp; - } - - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - 1, &AironetIPAddressIE, - 1, &AironetIPAddressLen, - AironetIPAddressLen, AironetIPAddressBuffer, - END_OF_ARGS); - FrameLen += tmp; - - // - // The RN is incremented before each reassociation request. - // - pAd->StaCfg.CCKMRN++; - // - // Calculate MIC = hmac-md5(krk, STA-ID|BSSID|RSNIE|TSF|RN); - // - COPY_MAC_ADDR(CalcMicBuffer, pAd->CurrentAddress); - CalcMicBufferLen = MAC_ADDR_LEN; - COPY_MAC_ADDR(CalcMicBuffer + CalcMicBufferLen, pAd->MlmeAux.Bssid); - CalcMicBufferLen += MAC_ADDR_LEN; - NdisMoveMemory(CalcMicBuffer + CalcMicBufferLen, CipherSuiteCiscoCCKM, CipherSuiteCiscoCCKMLen); - CalcMicBufferLen += CipherSuiteCiscoCCKMLen; - NdisMoveMemory(CalcMicBuffer + CalcMicBufferLen, (PUCHAR) &pAd->StaCfg.CCKMBeaconAtJoinTimeStamp, sizeof(pAd->StaCfg.CCKMBeaconAtJoinTimeStamp)); - CalcMicBufferLen += sizeof(pAd->StaCfg.CCKMBeaconAtJoinTimeStamp); - NdisMoveMemory(CalcMicBuffer + CalcMicBufferLen, (PUCHAR)&pAd->StaCfg.CCKMRN, sizeof(pAd->StaCfg.CCKMRN)); - CalcMicBufferLen += sizeof(pAd->StaCfg.CCKMRN); - hmac_md5(pAd->StaCfg.KRK, LEN_EAP_MICK, CalcMicBuffer, CalcMicBufferLen, MICMN); - - // - // fill up CCKM reassociation request element - // - NdisMoveMemory(AironetCCKMReassocBuffer, AironetOUI, 4); - NdisMoveMemory(AironetCCKMReassocBuffer + 4, (PUCHAR)&pAd->StaCfg.CCKMBeaconAtJoinTimeStamp, 8); - NdisMoveMemory(AironetCCKMReassocBuffer + 12, (PUCHAR) &pAd->StaCfg.CCKMRN, 4); - NdisMoveMemory(AironetCCKMReassocBuffer +16, MICMN, 8); - - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - 1, &AironetCCKMReassocIE, - 1, &AironetCCKMReassocLen, - AironetCCKMReassocLen, AironetCCKMReassocBuffer, - END_OF_ARGS); - FrameLen += tmp; - - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - CipherSuiteCiscoCCKMLen,CipherSuiteCiscoCCKM, - END_OF_ARGS); - FrameLen += tmp; - } -#endif // LEAP_SUPPORT // // Add CCX v2 request if CCX2 admin state is on if (pAd->StaCfg.CCXControl.field.Enable == 1) @@ -927,36 +815,6 @@ VOID MlmeDisassocReqAction( ULONG Timeout = 0; USHORT Status; -#ifdef QOS_DLS_SUPPORT - // send DLS-TEAR_DOWN message, - if (pAd->CommonCfg.bDLSCapable) - { - UCHAR i; - - // tear down local dls table entry - for (i=0; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH)) - { - RTMPSendDLSTearDownFrame(pAd, pAd->StaCfg.DLSEntry[i].MacAddr); - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - pAd->StaCfg.DLSEntry[i].Valid = FALSE; - } - } - - // tear down peer dls table entry - for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH)) - { - RTMPSendDLSTearDownFrame(pAd, pAd->StaCfg.DLSEntry[i].MacAddr); - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - pAd->StaCfg.DLSEntry[i].Valid = FALSE; - } - } - } -#endif // QOS_DLS_SUPPORT // - // skip sanity check pDisassocReq = (PMLME_DISASSOC_REQ_STRUCT)(Elem->Msg); @@ -999,27 +857,11 @@ VOID MlmeDisassocReqAction( RTMPSetTimer(&pAd->MlmeAux.DisassocTimer, Timeout); /* in mSec */ pAd->Mlme.AssocMachine.CurrState = DISASSOC_WAIT_RSP; -#ifdef WPA_SUPPLICANT_SUPPORT -#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT - if (pAd->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_DISABLE) - { - union iwreq_data wrqu; - //send disassociate event to wpa_supplicant - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.flags = RT_DISASSOC_EVENT_FLAG; - wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); - } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // -#endif // WPA_SUPPLICANT_SUPPORT // - -#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT { union iwreq_data wrqu; memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN); wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // - } /* @@ -1057,31 +899,15 @@ VOID PeerAssocRspAction( if(MAC_ADDR_EQUAL(Addr2, pAd->MlmeAux.Bssid)) { DBGPRINT(RT_DEBUG_TRACE, ("PeerAssocRspAction():ASSOC - receive ASSOC_RSP to me (status=%d)\n", Status)); -#ifdef DOT11_N_SUPPORT DBGPRINT(RT_DEBUG_TRACE, ("PeerAssocRspAction():MacTable [%d].AMsduSize = %d. ClientStatusFlags = 0x%lx \n",Elem->Wcid, pAd->MacTab.Content[BSSID_WCID].AMsduSize, pAd->MacTab.Content[BSSID_WCID].ClientStatusFlags)); -#endif // DOT11_N_SUPPORT // RTMPCancelTimer(&pAd->MlmeAux.AssocTimer, &TimerCancelled); if(Status == MLME_SUCCESS) { +#ifdef RT2860 // go to procedure listed on page 376 AssocPostProc(pAd, Addr2, CapabilityInfo, Aid, SupRate, SupRateLen, ExtRate, ExtRateLen, &EdcaParm, &HtCapability, HtCapabilityLen, &AddHtInfo); -#ifdef WPA_SUPPLICANT_SUPPORT -#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT - if (pAd->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_DISABLE) - { - union iwreq_data wrqu; - - SendAssocIEsToWpaSupplicant(pAd); - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.flags = RT_ASSOC_EVENT_FLAG; - wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); - } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // -#endif // WPA_SUPPLICANT_SUPPORT // - -#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT { union iwreq_data wrqu; wext_notify_event_assoc(pAd); @@ -1091,9 +917,29 @@ VOID PeerAssocRspAction( wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // +#endif +#ifdef RT2870 + UCHAR MaxSupportedRateIn500Kbps = 0; + UCHAR idx; + // supported rates array may not be sorted. sort it and find the maximum rate + for (idx=0; idxMacTab.Content[BSSID_WCID], MaxSupportedRateIn500Kbps, &HtCapability, HtCapabilityLen, CapabilityInfo); +#endif pAd->StaCfg.CkipFlag = CkipFlag; if (CkipFlag & 0x18) { @@ -1109,14 +955,6 @@ VOID PeerAssocRspAction( } else { - // Faile on Association, we need to check the status code - // Is that a Rogue AP? -#ifdef LEAP_SUPPORT - if ((pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) && (Status == MLME_ALG_NOT_SUPPORT)) - { //Possibly Rogue AP - RogueApTableSetEntry(pAd, &pAd->StaCfg.RogueApTab, pAd->MlmeAux.Bssid, LEAP_REASON_INVALID_AUTH); - } -#endif // LEAP_SUPPORT // } pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_ASSOC_CONF, 2, &Status); @@ -1172,21 +1010,6 @@ VOID PeerReassocRspAction( AssocPostProc(pAd, Addr2, CapabilityInfo, Aid, SupRate, SupRateLen, ExtRate, ExtRateLen, &EdcaParm, &HtCapability, HtCapabilityLen, &AddHtInfo); -#ifdef WPA_SUPPLICANT_SUPPORT -#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT - if (pAd->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_DISABLE) - { - union iwreq_data wrqu; - - SendAssocIEsToWpaSupplicant(pAd); - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.flags = RT_ASSOC_EVENT_FLAG; - wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); - } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // -#endif // WPA_SUPPLICANT_SUPPORT // - -#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT { union iwreq_data wrqu; wext_notify_event_assoc(pAd); @@ -1196,41 +1019,9 @@ VOID PeerReassocRspAction( wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // } - // - // Cisco Leap CCKM supported Re-association. - // -#ifdef LEAP_SUPPORT - if (LEAP_CCKM_ON(pAd) && (pAd->StaCfg.CCKMLinkUpFlag == TRUE)) - { - if (CCKMAssocRspSanity(pAd, Elem->Msg, Elem->MsgLen) == TRUE) - { - pAd->StaCfg.CkipFlag = CkipFlag; - if (CkipFlag & 0x18) - { - NdisZeroMemory(pAd->StaCfg.TxSEQ, 4); - NdisZeroMemory(pAd->StaCfg.RxSEQ, 4); - NdisZeroMemory(pAd->StaCfg.CKIPMIC, 4); - pAd->StaCfg.GIV[0] = RandomByte(pAd); - pAd->StaCfg.GIV[1] = RandomByte(pAd); - pAd->StaCfg.GIV[2] = RandomByte(pAd); - pAd->StaCfg.bCkipOn = TRUE; - DBGPRINT(RT_DEBUG_TRACE, (" pAd->StaCfg.CkipFlag = 0x%02x\n", pAd->StaCfg.CkipFlag)); - } - - pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_REASSOC_CONF, 2, &Status); - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - CCKMAssocRspSanity() sanity check fail\n")); - } - } - else -#endif // LEAP_SUPPORT // { // CkipFlag is no use for reassociate pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; @@ -1275,7 +1066,7 @@ VOID AssocPostProc( COPY_MAC_ADDR(pAd->MlmeAux.Bssid, pAddr2); pAd->MlmeAux.Aid = Aid; pAd->MlmeAux.CapabilityInfo = CapabilityInfo & SUPPORTED_CAPABILITY_INFO; -#ifdef DOT11_N_SUPPORT + // Some HT AP might lost WMM IE. We add WMM ourselves. beacuase HT requires QoS on. if ((HtCapabilityLen > 0) && (pEdcaParm->bValid == FALSE)) { @@ -1301,7 +1092,6 @@ VOID AssocPostProc( pEdcaParm->Txop[3] = 48; } -#endif // DOT11_N_SUPPORT // NdisMoveMemory(&pAd->MlmeAux.APEdcaParm, pEdcaParm, sizeof(EDCA_PARM)); @@ -1315,7 +1105,6 @@ VOID AssocPostProc( NdisMoveMemory(pAd->MlmeAux.ExtRate, ExtRate, ExtRateLen); RTMPCheckRates(pAd, pAd->MlmeAux.ExtRate, &pAd->MlmeAux.ExtRateLen); -#ifdef DOT11_N_SUPPORT if (HtCapabilityLen > 0) { RTMPCheckHt(pAd, BSSID_WCID, pHtCapability, pAddHtInfo); @@ -1324,7 +1113,6 @@ VOID AssocPostProc( DBGPRINT(RT_DEBUG_TRACE, ("AssocPostProc===> (Mmps=%d, AmsduSize=%d, )\n", pAd->MacTab.Content[BSSID_WCID].MmpsMode, pAd->MacTab.Content[BSSID_WCID].AMsduSize)); -#endif // DOT11_N_SUPPORT // // Set New WPA information Idx = BssTableSearch(&pAd->ScanTab, pAddr2, pAd->MlmeAux.Channel); @@ -1414,21 +1202,6 @@ VOID PeerDisassocAction( RTMPSendWirelessEvent(pAd, IW_DISASSOC_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); } - -#ifdef LEAP_SUPPORT - if (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) - { - // Cisco_LEAP has start a timer - // We should cancel it if using LEAP - RTMPCancelTimer(&pAd->StaCfg.LeapAuthTimer, &TimerCancelled); - //Check is it mach the LEAP Authentication failed as possible a Rogue AP - //on it's PortSecured not equal to WPA_802_1X_PORT_SECURED while process the Association. - if ((pAd->Mlme.LeapMachine.CurrState != LEAP_IDLE) && (pAd->StaCfg.PortSecured != WPA_802_1X_PORT_SECURED)) - { - RogueApTableSetEntry(pAd, &pAd->StaCfg.RogueApTab, Addr2, LEAP_REASON_AUTH_TIMEOUT); - } - } -#endif // LEAP_SUPPORT // // // Get Current System time and Turn on AdjacentAPReport // @@ -1437,26 +1210,11 @@ VOID PeerDisassocAction( LinkDown(pAd, TRUE); pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; -#ifdef WPA_SUPPLICANT_SUPPORT -#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT - if (pAd->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_DISABLE) - { - union iwreq_data wrqu; - //send disassociate event to wpa_supplicant - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.flags = RT_DISASSOC_EVENT_FLAG; - wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); - } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // -#endif // WPA_SUPPLICANT_SUPPORT // - -#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT { union iwreq_data wrqu; memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN); wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // } } else @@ -1739,36 +1497,6 @@ VOID SwitchBetweenWepAndCkip( } } -#ifdef WPA_SUPPLICANT_SUPPORT -#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT -VOID SendAssocIEsToWpaSupplicant( - IN PRTMP_ADAPTER pAd) -{ - union iwreq_data wrqu; - unsigned char custom[IW_CUSTOM_MAX] = {0}; - - if ((pAd->StaCfg.ReqVarIELen + 17) <= IW_CUSTOM_MAX) - { - sprintf(custom, "ASSOCINFO_ReqIEs="); - NdisMoveMemory(custom+17, pAd->StaCfg.ReqVarIEs, pAd->StaCfg.ReqVarIELen); - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.length = pAd->StaCfg.ReqVarIELen + 17; - wrqu.data.flags = RT_REQIE_EVENT_FLAG; - wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, custom); - - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.flags = RT_ASSOCINFO_EVENT_FLAG; - wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); - } - else - DBGPRINT(RT_DEBUG_TRACE, ("pAd->StaCfg.ReqVarIELen + 17 > MAX_CUSTOM_LEN\n")); - - return; -} -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // -#endif // WPA_SUPPLICANT_SUPPORT // - -#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT int wext_notify_event_assoc( IN RTMP_ADAPTER *pAd) { @@ -1791,7 +1519,7 @@ int wext_notify_event_assoc( wrqu.data.length = (pAd->StaCfg.ReqVarIELen*2) + 17; sprintf(custom, "ASSOCINFO(ReqIEs="); for (idx=0; idxStaCfg.ReqVarIELen; idx++) - sprintf(custom, "%s%02x", custom, pAd->StaCfg.ReqVarIEs[idx]); + sprintf(custom + strlen(custom), "%02x", pAd->StaCfg.ReqVarIEs[idx]); wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, custom); } else @@ -1801,5 +1529,227 @@ int wext_notify_event_assoc( return 0; } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // +#ifdef RT2870 +BOOLEAN StaAddMacTableEntry( + IN PRTMP_ADAPTER pAd, + IN PMAC_TABLE_ENTRY pEntry, + IN UCHAR MaxSupportedRateIn500Kbps, + IN HT_CAPABILITY_IE *pHtCapability, + IN UCHAR HtCapabilityLen, + IN USHORT CapabilityInfo) +{ + UCHAR MaxSupportedRate = RATE_11; + + if (ADHOC_ON(pAd)) + CLIENT_STATUS_CLEAR_FLAG(pEntry, fCLIENT_STATUS_WMM_CAPABLE); + + switch (MaxSupportedRateIn500Kbps) + { + case 108: MaxSupportedRate = RATE_54; break; + case 96: MaxSupportedRate = RATE_48; break; + case 72: MaxSupportedRate = RATE_36; break; + case 48: MaxSupportedRate = RATE_24; break; + case 36: MaxSupportedRate = RATE_18; break; + case 24: MaxSupportedRate = RATE_12; break; + case 18: MaxSupportedRate = RATE_9; break; + case 12: MaxSupportedRate = RATE_6; break; + case 22: MaxSupportedRate = RATE_11; break; + case 11: MaxSupportedRate = RATE_5_5; break; + case 4: MaxSupportedRate = RATE_2; break; + case 2: MaxSupportedRate = RATE_1; break; + default: MaxSupportedRate = RATE_11; break; + } + + if ((pAd->CommonCfg.PhyMode == PHY_11G) && (MaxSupportedRate < RATE_FIRST_OFDM_RATE)) + return FALSE; + + // 11n only + if (((pAd->CommonCfg.PhyMode == PHY_11N_2_4G) || (pAd->CommonCfg.PhyMode == PHY_11N_5G))&& (HtCapabilityLen == 0)) + return FALSE; + + if (!pEntry) + return FALSE; + + NdisAcquireSpinLock(&pAd->MacTabLock); + if (pEntry) + { + pEntry->PortSecured = WPA_802_1X_PORT_SECURED; + if ((MaxSupportedRate < RATE_FIRST_OFDM_RATE) || + (pAd->CommonCfg.PhyMode == PHY_11B)) + { + pEntry->RateLen = 4; + if (MaxSupportedRate >= RATE_FIRST_OFDM_RATE) + MaxSupportedRate = RATE_11; + } + else + pEntry->RateLen = 12; + + pEntry->MaxHTPhyMode.word = 0; + pEntry->MinHTPhyMode.word = 0; + pEntry->HTPhyMode.word = 0; + pEntry->MaxSupportedRate = MaxSupportedRate; + if (pEntry->MaxSupportedRate < RATE_FIRST_OFDM_RATE) + { + pEntry->MaxHTPhyMode.field.MODE = MODE_CCK; + pEntry->MaxHTPhyMode.field.MCS = pEntry->MaxSupportedRate; + pEntry->MinHTPhyMode.field.MODE = MODE_CCK; + pEntry->MinHTPhyMode.field.MCS = pEntry->MaxSupportedRate; + pEntry->HTPhyMode.field.MODE = MODE_CCK; + pEntry->HTPhyMode.field.MCS = pEntry->MaxSupportedRate; + } + else + { + pEntry->MaxHTPhyMode.field.MODE = MODE_OFDM; + pEntry->MaxHTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; + pEntry->MinHTPhyMode.field.MODE = MODE_OFDM; + pEntry->MinHTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; + pEntry->HTPhyMode.field.MODE = MODE_OFDM; + pEntry->HTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; + } + pEntry->CapabilityInfo = CapabilityInfo; + CLIENT_STATUS_CLEAR_FLAG(pEntry, fCLIENT_STATUS_AGGREGATION_CAPABLE); + CLIENT_STATUS_CLEAR_FLAG(pEntry, fCLIENT_STATUS_PIGGYBACK_CAPABLE); + } + + // If this Entry supports 802.11n, upgrade to HT rate. + if ((HtCapabilityLen != 0) && (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) + { + UCHAR j, bitmask; //k,bitmask; + CHAR i; + + if (ADHOC_ON(pAd)) + CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_WMM_CAPABLE); + if ((pHtCapability->HtCapInfo.GF) && (pAd->CommonCfg.DesiredHtPhy.GF)) + { + pEntry->MaxHTPhyMode.field.MODE = MODE_HTGREENFIELD; + } + else + { + pEntry->MaxHTPhyMode.field.MODE = MODE_HTMIX; + pAd->MacTab.fAnyStationNonGF = TRUE; + pAd->CommonCfg.AddHTInfo.AddHtInfo2.NonGfPresent = 1; + } + + if ((pHtCapability->HtCapInfo.ChannelWidth) && (pAd->CommonCfg.DesiredHtPhy.ChannelWidth)) + { + pEntry->MaxHTPhyMode.field.BW= BW_40; + pEntry->MaxHTPhyMode.field.ShortGI = ((pAd->CommonCfg.DesiredHtPhy.ShortGIfor40)&(pHtCapability->HtCapInfo.ShortGIfor40)); + } + else + { + pEntry->MaxHTPhyMode.field.BW = BW_20; + pEntry->MaxHTPhyMode.field.ShortGI = ((pAd->CommonCfg.DesiredHtPhy.ShortGIfor20)&(pHtCapability->HtCapInfo.ShortGIfor20)); + pAd->MacTab.fAnyStation20Only = TRUE; + } + + // 3*3 + if (pAd->MACVersion >= RALINK_2883_VERSION && pAd->MACVersion < RALINK_3070_VERSION) + pEntry->MaxHTPhyMode.field.TxBF = pAd->CommonCfg.RegTransmitSetting.field.TxBF; + + // find max fixed rate + for (i=23; i>=0; i--) // 3*3 + { + j = i/8; + bitmask = (1<<(i-(j*8))); + if ((pAd->StaCfg.DesiredHtPhyInfo.MCSSet[j] & bitmask) && (pHtCapability->MCSSet[j] & bitmask)) + { + pEntry->MaxHTPhyMode.field.MCS = i; + break; + } + if (i==0) + break; + } + + + if (pAd->StaCfg.DesiredTransmitSetting.field.MCS != MCS_AUTO) + { + if (pAd->StaCfg.DesiredTransmitSetting.field.MCS == 32) + { + // Fix MCS as HT Duplicated Mode + pEntry->MaxHTPhyMode.field.BW = 1; + pEntry->MaxHTPhyMode.field.MODE = MODE_HTMIX; + pEntry->MaxHTPhyMode.field.STBC = 0; + pEntry->MaxHTPhyMode.field.ShortGI = 0; + pEntry->MaxHTPhyMode.field.MCS = 32; + } + else if (pEntry->MaxHTPhyMode.field.MCS > pAd->StaCfg.HTPhyMode.field.MCS) + { + // STA supports fixed MCS + pEntry->MaxHTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; + } + } + + pEntry->MaxHTPhyMode.field.STBC = (pHtCapability->HtCapInfo.RxSTBC & (pAd->CommonCfg.DesiredHtPhy.TxSTBC)); + pEntry->MpduDensity = pHtCapability->HtCapParm.MpduDensity; + pEntry->MaxRAmpduFactor = pHtCapability->HtCapParm.MaxRAmpduFactor; + pEntry->MmpsMode = (UCHAR)pHtCapability->HtCapInfo.MimoPs; + pEntry->AMsduSize = (UCHAR)pHtCapability->HtCapInfo.AMsduSize; + pEntry->HTPhyMode.word = pEntry->MaxHTPhyMode.word; + + if (pAd->CommonCfg.DesiredHtPhy.AmsduEnable && (pAd->CommonCfg.REGBACapability.field.AutoBA == FALSE)) + CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_AMSDU_INUSED); + if (pHtCapability->HtCapInfo.ShortGIfor20) + CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_SGI20_CAPABLE); + if (pHtCapability->HtCapInfo.ShortGIfor40) + CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_SGI40_CAPABLE); + if (pHtCapability->HtCapInfo.TxSTBC) + CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_TxSTBC_CAPABLE); + if (pHtCapability->HtCapInfo.RxSTBC) + CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_RxSTBC_CAPABLE); + if (pHtCapability->ExtHtCapInfo.PlusHTC) + CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_HTC_CAPABLE); + if (pAd->CommonCfg.bRdg && pHtCapability->ExtHtCapInfo.RDGSupport) + CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_RDG_CAPABLE); + if (pHtCapability->ExtHtCapInfo.MCSFeedback == 0x03) + CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_MCSFEEDBACK_CAPABLE); + } + else + { + pAd->MacTab.fAnyStationIsLegacy = TRUE; + } + + NdisMoveMemory(&pEntry->HTCapability, pHtCapability, sizeof(HT_CAPABILITY_IE)); + + pEntry->HTPhyMode.word = pEntry->MaxHTPhyMode.word; + pEntry->CurrTxRate = pEntry->MaxSupportedRate; + + // Set asic auto fall back + if (pAd->StaCfg.bAutoTxRateSwitch == TRUE) + { + PUCHAR pTable; + UCHAR TableSize = 0; + + MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize, &pEntry->CurrTxRateIndex); + pEntry->bAutoTxRateSwitch = TRUE; + } + else + { + pEntry->HTPhyMode.field.MODE = pAd->StaCfg.HTPhyMode.field.MODE; + pEntry->HTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; + pEntry->bAutoTxRateSwitch = FALSE; + + // If the legacy mode is set, overwrite the transmit setting of this entry. + RTMPUpdateLegacyTxSetting((UCHAR)pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode, pEntry); + } + + pEntry->PortSecured = WPA_802_1X_PORT_SECURED; + pEntry->Sst = SST_ASSOC; + pEntry->AuthState = AS_AUTH_OPEN; + pEntry->AuthMode = pAd->StaCfg.AuthMode; + pEntry->WepStatus = pAd->StaCfg.WepStatus; + + NdisReleaseSpinLock(&pAd->MacTabLock); + + { + union iwreq_data wrqu; + wext_notify_event_assoc(pAd); + + memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN); + memcpy(wrqu.ap_addr.sa_data, pAd->MlmeAux.Bssid, MAC_ADDR_LEN); + wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); + + } + return TRUE; +} +#endif /* RT2870 */ diff --git a/drivers/staging/rt2860/sta/auth.c b/drivers/staging/rt2860/sta/auth.c index 73fb8d6ea76f..d8414eac42f8 100644 --- a/drivers/staging/rt2860/sta/auth.c +++ b/drivers/staging/rt2860/sta/auth.c @@ -218,15 +218,9 @@ VOID PeerAuthRspAtSeq2Action( { // Authentication Mode "LEAP" has allow for CCX 1.X if ((pAd->MlmeAux.Alg == Ndis802_11AuthModeOpen) -#ifdef LEAP_SUPPORT - || (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) -#endif // LEAP_SUPPORT // ) { pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; -#ifdef LEAP_SUPPORT - pAd->Mlme.LeapMachine.CurrState = LEAP_IDLE; -#endif // LEAP_SUPPORT // MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status); } else @@ -282,14 +276,6 @@ VOID PeerAuthRspAtSeq2Action( } else { -#ifdef LEAP_SUPPORT - if (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) - { - //Invalid Authentication possible rogue AP - //Add this Ap to Rogue AP. - RogueApTableSetEntry(pAd, &pAd->StaCfg.RogueApTab, Addr2, LEAP_REASON_INVALID_AUTH); - } -#endif // LEAP_SUPPORT // pAd->StaCfg.AuthFailReason = Status; COPY_MAC_ADDR(pAd->StaCfg.AuthFailSta, Addr2); pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; diff --git a/drivers/staging/rt2860/sta/auth_rsp.c b/drivers/staging/rt2860/sta/auth_rsp.c index f7aa4b99cf56..cc639b1c6c13 100644 --- a/drivers/staging/rt2860/sta/auth_rsp.c +++ b/drivers/staging/rt2860/sta/auth_rsp.c @@ -127,36 +127,17 @@ VOID PeerDeauthAction( { DBGPRINT(RT_DEBUG_TRACE,("AUTH_RSP - receive DE-AUTH from our AP (Reason=%d)\n", Reason)); - -#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT { union iwreq_data wrqu; memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN); wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // - // send wireless event - for deauthentication if (pAd->CommonCfg.bWirelessEvent) RTMPSendWirelessEvent(pAd, IW_DEAUTH_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); LinkDown(pAd, TRUE); - - // Authentication Mode Cisco_LEAP has start a timer - // We should cancel it if using LEAP -#ifdef LEAP_SUPPORT - if (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) - { - RTMPCancelTimer(&pAd->StaCfg.LeapAuthTimer, &TimerCancelled); - //Check is it mach the LEAP Authentication failed as possible a Rogue AP - //on it's PortSecured not equal to WPA_802_1X_PORT_SECURED while process the Authenticaton. - if ((pAd->StaCfg.PortSecured != WPA_802_1X_PORT_SECURED) && (pAd->Mlme.LeapMachine.CurrState != LEAP_IDLE)) - { - RogueApTableSetEntry(pAd, &pAd->StaCfg.RogueApTab, Addr2, LEAP_REASON_AUTH_TIMEOUT); - } - } -#endif // LEAP_SUPPORT // } } else diff --git a/drivers/staging/rt2860/sta/connect.c b/drivers/staging/rt2860/sta/connect.c index d8bcc76688a6..ac7135186665 100644 --- a/drivers/staging/rt2860/sta/connect.c +++ b/drivers/staging/rt2860/sta/connect.c @@ -178,13 +178,6 @@ VOID MlmeCntlMachinePerformAction( pAd->bLedOnScanning = FALSE; RTMPSetLED(pAd, pAd->LedStatus); } -#ifdef DOT11N_DRAFT3 - // AP sent a 2040Coexistence mgmt frame, then station perform a scan, and then send back the respone. - if (pAd->CommonCfg.BSSCoexist2040.field.InfoReq == 1) - { - Update2040CoexistFrameAndNotify(pAd, BSSID_WCID, TRUE); - } -#endif // DOT11N_DRAFT3 // } break; @@ -195,6 +188,38 @@ VOID MlmeCntlMachinePerformAction( pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; } break; +#ifdef RT2870 + // + // This state is for that we want to connect to an AP but + // it didn't find on BSS List table. So we need to scan the air first, + // after that we can try to connect to the desired AP if available. + // + case CNTL_WAIT_SCAN_FOR_CONNECT: + if(Elem->MsgType == MT2_SCAN_CONF) + { + // Resume TxRing after SCANING complete. We hope the out-of-service time + // won't be too long to let upper layer time-out the waiting frames + RTMPResumeMsduTransmission(pAd); +#ifdef CCX_SUPPORT + if (pAd->StaCfg.CCXReqType != MSRN_TYPE_UNUSED) + { + // Cisco scan request is finished, prepare beacon report + MlmeEnqueue(pAd, AIRONET_STATE_MACHINE, MT2_AIRONET_SCAN_DONE, 0, NULL); + } +#endif // CCX_SUPPORT // + pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; + + // + // Check if we can connect to. + // + BssTableSsidSort(pAd, &pAd->MlmeAux.SsidBssTab, pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.AutoReconnectSsidLen); + if (pAd->MlmeAux.SsidBssTab.BssNr > 0) + { + MlmeAutoReconnectLastSSID(pAd); + } + } + break; +#endif // RT2870 // default: DBGPRINT_ERR(("!ERROR! CNTL - Illegal message type(=%ld)", Elem->MsgType)); break; @@ -234,19 +259,11 @@ VOID CntlIdleProc( break; case OID_802_11_DISASSOCIATE: -#ifdef RALINK_ATE - if(ATE_ON(pAd)) - { - DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now\n")); - break; - } -#endif // RALINK_ATE // DisassocParmFill(pAd, &DisassocReq, pAd->CommonCfg.Bssid, REASON_DISASSOC_STA_LEAVING); MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ, sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq); pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_DISASSOC; -#ifdef WPA_SUPPLICANT_SUPPORT + if (pAd->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_ENABLE_WITH_WEB_UI) -#endif // WPA_SUPPLICANT_SUPPORT // { // Set the AutoReconnectSsid to prevent it reconnect to old SSID // Since calling this indicate user don't want to connect to that SSID anymore. @@ -263,12 +280,6 @@ VOID CntlIdleProc( WpaMicFailureReportFrame(pAd, Elem); break; -#ifdef QOS_DLS_SUPPORT - case RT_OID_802_11_SET_DLS_PARAM: - CntlOidDLSSetupProc(pAd, Elem); - break; -#endif // QOS_DLS_SUPPORT // - default: DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Illegal message in CntlIdleProc(MsgType=%ld)\n",Elem->MsgType)); break; @@ -283,13 +294,6 @@ VOID CntlOidScanProc( ULONG BssIdx = BSS_NOT_FOUND; BSS_ENTRY CurrBss; -#ifdef RALINK_ATE -/* Disable scanning when ATE is running. */ - if (ATE_ON(pAd)) - return; -#endif // RALINK_ATE // - - // record current BSS if network is connected. // 2003-2-13 do not include current IBSS if this is the only STA in this IBSS. if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) @@ -337,9 +341,11 @@ VOID CntlOidSsidProc( MLME_DISASSOC_REQ_STRUCT DisassocReq; ULONG Now; +#ifdef RT2860 // BBP and RF are not accessible in PS mode, we has to wake them up first if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) AsicForceWakeup(pAd, RTMP_HALT); +#endif // Step 1. record the desired user settings to MlmeAux NdisZeroMemory(pAd->MlmeAux.Ssid, MAX_LEN_OF_SSID); @@ -377,9 +383,6 @@ VOID CntlOidSsidProc( (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) -#ifdef LEAP_SUPPORT - || (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) -#endif // LEAP_SUPPORT // ) && (pAd->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED)) { @@ -420,7 +423,7 @@ VOID CntlOidSsidProc( } pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; -#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT + { union iwreq_data wrqu; @@ -429,7 +432,6 @@ VOID CntlOidSsidProc( wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // } } else if (INFRA_ON(pAd)) @@ -513,12 +515,6 @@ VOID CntlOidRTBssidProc( MLME_DISASSOC_REQ_STRUCT DisassocReq; MLME_JOIN_REQ_STRUCT JoinReq; -#ifdef RALINK_ATE -/* No need to perform this routine when ATE is running. */ - if (ATE_ON(pAd)) - return; -#endif // RALINK_ATE // - // record user desired settings COPY_MAC_ADDR(pAd->MlmeAux.Bssid, pOidBssid); pAd->MlmeAux.BssType = pAd->StaCfg.BssType; @@ -558,7 +554,7 @@ VOID CntlOidRTBssidProc( // already connected to the same BSSID, go back to idle state directly DBGPRINT(RT_DEBUG_TRACE, ("CNTL - already in this BSSID. ignore this SET_BSSID request\n")); pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; -#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT + { union iwreq_data wrqu; @@ -567,7 +563,6 @@ VOID CntlOidRTBssidProc( wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // } else { @@ -672,113 +667,6 @@ VOID CntlMlmeRoamingProc( IterateOnBssTab(pAd); } -#ifdef QOS_DLS_SUPPORT -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== -*/ -VOID CntlOidDLSSetupProc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - PRT_802_11_DLS pDLS = (PRT_802_11_DLS)Elem->Msg; - MLME_DLS_REQ_STRUCT MlmeDlsReq; - INT i; - USHORT reason = REASON_UNSPECIFY; - - DBGPRINT(RT_DEBUG_TRACE,("CNTL - (OID set %02x:%02x:%02x:%02x:%02x:%02x with Valid=%d, Status=%d, TimeOut=%d, CountDownTimer=%d)\n", - pDLS->MacAddr[0], pDLS->MacAddr[1], pDLS->MacAddr[2], pDLS->MacAddr[3], pDLS->MacAddr[4], pDLS->MacAddr[5], - pDLS->Valid, pDLS->Status, pDLS->TimeOut, pDLS->CountDownTimer)); - - if (!pAd->CommonCfg.bDLSCapable) - return; - - // DLS will not be supported when Adhoc mode - if (INFRA_ON(pAd)) - { - for (i = 0; i < MAX_NUM_OF_DLS_ENTRY; i++) - { - if (pDLS->Valid && pAd->StaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) && - (pDLS->TimeOut == pAd->StaCfg.DLSEntry[i].TimeOut) && MAC_ADDR_EQUAL(pDLS->MacAddr, pAd->StaCfg.DLSEntry[i].MacAddr)) - { - // 1. Same setting, just drop it - DBGPRINT(RT_DEBUG_TRACE,("CNTL - setting unchanged\n")); - break; - } - else if (!pDLS->Valid && pAd->StaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) && - MAC_ADDR_EQUAL(pDLS->MacAddr, pAd->StaCfg.DLSEntry[i].MacAddr)) - { - // 2. Disable DLS link case, just tear down DLS link - reason = REASON_QOS_UNWANTED_MECHANISM; - pAd->StaCfg.DLSEntry[i].Valid = FALSE; - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); - MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_TEAR_DOWN, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); - DBGPRINT(RT_DEBUG_TRACE,("CNTL - start tear down procedure\n")); - break; - } - else if ((i < MAX_NUM_OF_DLS_ENTRY) && pDLS->Valid && !pAd->StaCfg.DLSEntry[i].Valid) - { - // 3. Enable case, start DLS setup procedure - NdisMoveMemory(&pAd->StaCfg.DLSEntry[i], pDLS, sizeof(RT_802_11_DLS_UI)); - - //Update countdown timer - pAd->StaCfg.DLSEntry[i].CountDownTimer = pAd->StaCfg.DLSEntry[i].TimeOut; - DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); - MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_REQ, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); - DBGPRINT(RT_DEBUG_TRACE,("CNTL - DLS setup case\n")); - break; - } - else if ((i < MAX_NUM_OF_DLS_ENTRY) && pDLS->Valid && pAd->StaCfg.DLSEntry[i].Valid && - (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) && !MAC_ADDR_EQUAL(pDLS->MacAddr, pAd->StaCfg.DLSEntry[i].MacAddr)) - { - // 4. update mac case, tear down old DLS and setup new DLS - reason = REASON_QOS_UNWANTED_MECHANISM; - pAd->StaCfg.DLSEntry[i].Valid = FALSE; - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); - MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_TEAR_DOWN, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); - NdisMoveMemory(&pAd->StaCfg.DLSEntry[i], pDLS, sizeof(RT_802_11_DLS_UI)); - DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); - MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_REQ, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); - DBGPRINT(RT_DEBUG_TRACE,("CNTL - DLS tear down and restart case\n")); - break; - } - else if (pDLS->Valid && pAd->StaCfg.DLSEntry[i].Valid && - MAC_ADDR_EQUAL(pDLS->MacAddr, pAd->StaCfg.DLSEntry[i].MacAddr) && (pAd->StaCfg.DLSEntry[i].TimeOut != pDLS->TimeOut)) - { - // 5. update timeout case, start DLS setup procedure (no tear down) - pAd->StaCfg.DLSEntry[i].TimeOut = pDLS->TimeOut; - //Update countdown timer - pAd->StaCfg.DLSEntry[i].CountDownTimer = pAd->StaCfg.DLSEntry[i].TimeOut; - DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); - MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_REQ, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); - DBGPRINT(RT_DEBUG_TRACE,("CNTL - DLS update timeout case\n")); - break; - } - else if (pDLS->Valid && pAd->StaCfg.DLSEntry[i].Valid && - (pAd->StaCfg.DLSEntry[i].Status != DLS_FINISH) && MAC_ADDR_EQUAL(pDLS->MacAddr, pAd->StaCfg.DLSEntry[i].MacAddr)) - { - // 6. re-setup case, start DLS setup procedure (no tear down) - DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); - MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_REQ, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); - DBGPRINT(RT_DEBUG_TRACE,("CNTL - DLS retry setup procedure\n")); - break; - } - else - { - DBGPRINT(RT_DEBUG_WARN,("CNTL - DLS not changed in entry - %d - Valid=%d, Status=%d, TimeOut=%d\n", - i, pAd->StaCfg.DLSEntry[i].Valid, pAd->StaCfg.DLSEntry[i].Status, pAd->StaCfg.DLSEntry[i].TimeOut)); - } - } - } -} -#endif // QOS_DLS_SUPPORT // - /* ========================================================================== Description: @@ -870,14 +758,6 @@ VOID CntlWaitJoinProc( // 2. joined a new INFRA network, start from authentication else { -#ifdef LEAP_SUPPORT - // Add AuthMode "LEAP" for CCX 1.X - if (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) - { - AuthParmFill(pAd, &AuthReq, pAd->MlmeAux.Bssid, CISCO_AuthModeLEAP); - } - else -#endif // LEAP_SUPPORT // { // either Ndis802_11AuthModeShared or Ndis802_11AuthModeAutoSwitch, try shared key first if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeShared) || @@ -937,7 +817,7 @@ VOID CntlWaitStartProc( DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Channel=%d, Start adhoc on W53(52,56,60,64) Channels are not accepted\n", pAd->CommonCfg.Channel)); return; } -#ifdef DOT11_N_SUPPORT + if (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) { N_ChannelCheck(pAd); @@ -961,7 +841,6 @@ VOID CntlWaitStartProc( } } else -#endif // DOT11_N_SUPPORT // { pAd->StaActive.SupportedPhyInfo.bHtEnable = FALSE; } @@ -974,9 +853,6 @@ VOID CntlWaitStartProc( { pAd->CommonCfg.RadarDetect.RDMode = RD_SILENCE_MODE; pAd->CommonCfg.RadarDetect.RDCount = 0; -#ifdef DFS_SUPPORT - BbpRadarDetectionStart(pAd); -#endif // DFS_SUPPORT // } DBGPRINT(RT_DEBUG_TRACE, ("CNTL - start a new IBSS = %02x:%02x:%02x:%02x:%02x:%02x ...\n", @@ -1016,21 +892,6 @@ VOID CntlWaitAuthProc( AssocParmFill(pAd, &AssocReq, pAd->MlmeAux.Bssid, pAd->MlmeAux.CapabilityInfo, ASSOC_TIMEOUT, pAd->StaCfg.DefaultListenCount); -#ifdef LEAP_SUPPORT - // - // Cisco Leap CCKM supported Re-association. - // - if (LEAP_CCKM_ON(pAd) && (pAd->StaCfg.CCKMLinkUpFlag == TRUE)) - { - //if CCKM is turn on , that's mean Fast Reauthentication - //Use CCKM Reassociation instead of normal association for Fast Roaming. - MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_REASSOC_REQ, - sizeof(MLME_ASSOC_REQ_STRUCT), &AssocReq); - - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_REASSOC; - } - else -#endif // LEAP_SUPPORT // { MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_ASSOC_REQ, sizeof(MLME_ASSOC_REQ_STRUCT), &AssocReq); @@ -1044,14 +905,7 @@ VOID CntlWaitAuthProc( // ageing-out. The previous authentication attempt must have let it remove us. // so try Authentication again may help. For D-Link DWL-900AP+ compatibility. DBGPRINT(RT_DEBUG_TRACE, ("CNTL - AUTH FAIL, try again...\n")); -#ifdef LEAP_SUPPORT - //Add AuthMode "LEAP" for CCX 1.X - if (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) - { - AuthParmFill(pAd, &AuthReq, pAd->MlmeAux.Bssid, CISCO_AuthModeLEAP); - } - else -#endif // LEAP_SUPPORT // + { if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeShared) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeAutoSwitch)) @@ -1103,20 +957,6 @@ VOID CntlWaitAuthProc2( } else { -#ifdef LEAP_SUPPORT - // Process LEAP first, since it use different control variable - // We don't want to affect other poven operation - if (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) - { - // LEAP Auth not success, try next BSS - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - *LEAP* AUTH FAIL, give up; try next BSS\n")); - DBGPRINT(RT_DEBUG_TRACE, ("Total match BSSID [=%d]\n", pAd->MlmeAux.SsidBssTab.BssNr)); - pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; - pAd->MlmeAux.BssIdx++; - IterateOnBssTab(pAd); - } - else -#endif // LEAP_SUPPORT // if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeAutoSwitch) && (pAd->MlmeAux.Alg == Ndis802_11AuthModeShared)) { @@ -1205,14 +1045,6 @@ VOID CntlWaitReassocProc( if (pAd->CommonCfg.bWirelessEvent) RTMPSendWirelessEvent(pAd, IW_ASSOC_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); - -#ifdef LEAP_SUPPORT - if (LEAP_CCKM_ON(pAd)) - { - STA_PORT_SECURED(pAd); - pAd->StaCfg.WpaState = SS_FINISH; - } -#endif // LEAP_SUPPORT // pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Re-assocition successful on BSS #%ld\n", pAd->MlmeAux.RoamIdx)); } @@ -1226,6 +1058,44 @@ VOID CntlWaitReassocProc( } } + +#ifdef RT2870 +VOID AdhocTurnOnQos( + IN PRTMP_ADAPTER pAd) +{ +#define AC0_DEF_TXOP 0 +#define AC1_DEF_TXOP 0 +#define AC2_DEF_TXOP 94 +#define AC3_DEF_TXOP 47 + + // Turn on QOs if use HT rate. + if (pAd->CommonCfg.APEdcaParm.bValid == FALSE) + { + pAd->CommonCfg.APEdcaParm.bValid = TRUE; + pAd->CommonCfg.APEdcaParm.Aifsn[0] = 3; + pAd->CommonCfg.APEdcaParm.Aifsn[1] = 7; + pAd->CommonCfg.APEdcaParm.Aifsn[2] = 1; + pAd->CommonCfg.APEdcaParm.Aifsn[3] = 1; + + pAd->CommonCfg.APEdcaParm.Cwmin[0] = 4; + pAd->CommonCfg.APEdcaParm.Cwmin[1] = 4; + pAd->CommonCfg.APEdcaParm.Cwmin[2] = 3; + pAd->CommonCfg.APEdcaParm.Cwmin[3] = 2; + + pAd->CommonCfg.APEdcaParm.Cwmax[0] = 10; + pAd->CommonCfg.APEdcaParm.Cwmax[1] = 6; + pAd->CommonCfg.APEdcaParm.Cwmax[2] = 4; + pAd->CommonCfg.APEdcaParm.Cwmax[3] = 3; + + pAd->CommonCfg.APEdcaParm.Txop[0] = 0; + pAd->CommonCfg.APEdcaParm.Txop[1] = 0; + pAd->CommonCfg.APEdcaParm.Txop[2] = AC2_DEF_TXOP; + pAd->CommonCfg.APEdcaParm.Txop[3] = AC3_DEF_TXOP; + } + AsicSetEdcaParm(pAd, &pAd->CommonCfg.APEdcaParm); +} +#endif /* RT2870 */ + /* ========================================================================== Description: @@ -1244,12 +1114,14 @@ VOID LinkUp( UCHAR Value = 0, idx; MAC_TABLE_ENTRY *pEntry = NULL, *pCurrEntry; +#ifdef RT2860 if (RTMP_TEST_PSFLAG(pAd, fRTMP_PS_SET_PCI_CLK_OFF_COMMAND)) { RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_HALT); RTMPusecDelay(6000); pAd->bPCIclkOff = FALSE; } +#endif pEntry = &pAd->MacTab.Content[BSSID_WCID]; @@ -1266,15 +1138,15 @@ VOID LinkUp( COPY_SETTINGS_FROM_MLME_AUX_TO_ACTIVE_CFG(pAd); -#ifdef DOT11_N_SUPPORT COPY_HTSETTINGS_FROM_MLME_AUX_TO_ACTIVE_CFG(pAd); -#endif // DOT11_N_SUPPORT // + // It's quite difficult to tell if a newly added KEY is WEP or CKIP until a new BSS // is formed (either ASSOC/RE-ASSOC done or IBSS started. LinkUP should be a safe place // to examine if cipher algorithm switching is required. //rt2860b. Don't know why need this SwitchBetweenWepAndCkip(pAd); +#ifdef RT2860 // Before power save before link up function, We will force use 1R. // So after link up, check Rx antenna # again. RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &Value); @@ -1292,17 +1164,30 @@ VOID LinkUp( } RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, Value); pAd->StaCfg.BBPR3 = Value; +#endif /* RT2860 */ if (BssType == BSS_ADHOC) { OPSTATUS_SET_FLAG(pAd, fOP_STATUS_ADHOC_ON); OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_INFRA_ON); -#ifdef CARRIER_DETECTION_SUPPORT // Roger sync Carrier - // No carrier detection when adhoc - // CarrierDetectionStop(pAd); - pAd->CommonCfg.CarrierDetect.CD_State = CD_NORMAL; -#endif // CARRIER_DETECTION_SUPPORT // +#ifdef RT30xx + if ((pAd->CommonCfg.HtCapability.HtCapInfo.ChannelWidth == BW_40) && + (pAd->CommonCfg.AddHTInfo.AddHtInfo.ExtChanOffset == EXTCHA_ABOVE)) + { + pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel + 2; + } + else if ((pAd->CommonCfg.Channel > 2) && + (pAd->CommonCfg.HtCapability.HtCapInfo.ChannelWidth == BW_40) && + (pAd->CommonCfg.AddHTInfo.AddHtInfo.ExtChanOffset == EXTCHA_BELOW)) + { + pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel - 2; + } +#endif +#ifdef RT2870 + if (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) + AdhocTurnOnQos(pAd); +#endif DBGPRINT(RT_DEBUG_TRACE, ("!!!Adhoc LINK UP !!! \n" )); } @@ -1321,7 +1206,6 @@ VOID LinkUp( Value |= pAd->CommonCfg.RegTransmitSetting.field.TxBF; RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, Value); -#ifdef DOT11_N_SUPPORT // Change to AP channel if ((pAd->CommonCfg.CentralChannel > pAd->CommonCfg.Channel) && (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40)) { @@ -1339,7 +1223,9 @@ VOID LinkUp( RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &Value); Value &= (~0x20); RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, Value); +#ifdef RT2860 pAd->StaCfg.BBPR3 = Value; +#endif RTMP_IO_READ32(pAd, TX_BAND_CFG, &Data); Data &= 0xfffffffe; @@ -1374,7 +1260,9 @@ VOID LinkUp( RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &Value); Value |= (0x20); RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, Value); +#ifdef RT2860 pAd->StaCfg.BBPR3 = Value; +#endif if (pAd->MACVersion == 0x28600100) { @@ -1387,7 +1275,6 @@ VOID LinkUp( DBGPRINT(RT_DEBUG_TRACE, ("!!! 40MHz Upper LINK UP !!! Control Channel at UpperCentral = %d \n", pAd->CommonCfg.CentralChannel )); } else -#endif // DOT11_N_SUPPORT // { pAd->CommonCfg.BBPCurrentBW = BW_20; pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel; @@ -1405,7 +1292,9 @@ VOID LinkUp( RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &Value); Value &= (~0x20); RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, Value); +#ifdef RT2860 pAd->StaCfg.BBPR3 = Value; +#endif if (pAd->MACVersion == 0x28600100) { @@ -1427,9 +1316,7 @@ VOID LinkUp( DBGPRINT(RT_DEBUG_TRACE, ("!!! LINK UP !!! (BssType=%d, AID=%d, ssid=%s, Channel=%d, CentralChannel = %d)\n", BssType, pAd->StaActive.Aid, pAd->CommonCfg.Ssid, pAd->CommonCfg.Channel, pAd->CommonCfg.CentralChannel)); -#ifdef DOT11_N_SUPPORT DBGPRINT(RT_DEBUG_TRACE, ("!!! LINK UP !!! (Density =%d, )\n", pAd->MacTab.Content[BSSID_WCID].MpduDensity)); -#endif // DOT11_N_SUPPORT // AsicSetBssid(pAd, pAd->CommonCfg.Bssid); @@ -1439,7 +1326,6 @@ VOID LinkUp( // Call this for RTS protectionfor legacy rate, we will always enable RTS threshold, but normally it will not hit AsicUpdateProtect(pAd, 0, (OFDMSETPROTECT | CCKSETPROTECT), TRUE, FALSE); -#ifdef DOT11_N_SUPPORT if ((pAd->StaActive.SupportedPhyInfo.bHtEnable == TRUE)) { // Update HT protectionfor based on AP's operating mode. @@ -1450,7 +1336,6 @@ VOID LinkUp( else AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, ALLN_SETPROTECT, FALSE, FALSE); } -#endif // DOT11_N_SUPPORT // NdisZeroMemory(&pAd->DrsCounters, sizeof(COUNTER_DRS)); @@ -1467,9 +1352,6 @@ VOID LinkUp( if (pAd->CommonCfg.RadarDetect.RDMode == RD_SILENCE_MODE) { -#ifdef DFS_SUPPORT - RadarDetectionStop(pAd); -#endif // DFS_SUPPORT // } pAd->CommonCfg.RadarDetect.RDMode = RD_NORMAL_MODE; @@ -1602,7 +1484,9 @@ VOID LinkUp( IV |= (pAd->StaCfg.DefaultKeyId << 30); AsicUpdateWCIDIVEIV(pAd, BSSID_WCID, IV, 0); +#ifdef RT2860 RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_CAN_GO_SLEEP); +#endif } // NOTE: // the decision of using "short slot time" or not may change dynamically due to @@ -1643,15 +1527,11 @@ VOID LinkUp( // If WEP is enabled, add paiewise and shared key -#ifdef WPA_SUPPLICANT_SUPPORT if (((pAd->StaCfg.WpaSupplicantUP)&& (pAd->StaCfg.WepStatus == Ndis802_11WEPEnabled)&& (pAd->StaCfg.PortSecured == WPA_802_1X_PORT_SECURED)) || ((pAd->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_DISABLE)&& (pAd->StaCfg.WepStatus == Ndis802_11WEPEnabled))) -#else - if (pAd->StaCfg.WepStatus == Ndis802_11WEPEnabled) -#endif // WPA_SUPPLICANT_SUPPORT // { PUCHAR Key; UCHAR CipherAlg; @@ -1687,9 +1567,14 @@ VOID LinkUp( { pAd->IndicateMediaState = NdisMediaStateConnected; pAd->ExtraInfo = GENERAL_LINK_UP; +#ifdef RT2870 + RTMP_IndicateMediaState(pAd); +#endif } // -- +#ifdef RT2860 RTMP_IndicateMediaState(pAd); +#endif // Add BSSID in my MAC Table. NdisAcquireSpinLock(&pAd->MacTabLock); @@ -1700,6 +1585,9 @@ VOID LinkUp( pAd->MacTab.Size = 1; // infra mode always set MACtab size =1. pAd->MacTab.Content[BSSID_WCID].Sst = SST_ASSOC; pAd->MacTab.Content[BSSID_WCID].AuthState = SST_ASSOC; +#ifdef RT30xx + pAd->MacTab.Content[BSSID_WCID].AuthMode = pAd->StaCfg.AuthMode; +#endif pAd->MacTab.Content[BSSID_WCID].WepStatus = pAd->StaCfg.WepStatus; NdisReleaseSpinLock(&pAd->MacTabLock); @@ -1707,17 +1595,8 @@ VOID LinkUp( pAd->MacTab.Content[BSSID_WCID].ClientStatusFlags)); MlmeUpdateTxRates(pAd, TRUE, BSS0); -#ifdef DOT11_N_SUPPORT MlmeUpdateHtTxRates(pAd, BSS0); DBGPRINT(RT_DEBUG_TRACE, ("!!! LINK UP !! (StaActive.bHtEnable =%d, )\n", pAd->StaActive.SupportedPhyInfo.bHtEnable)); -#endif // DOT11_N_SUPPORT // - - // - // Report Adjacent AP report. - // -#ifdef LEAP_SUPPORT - CCXAdjacentAPReport(pAd); -#endif // LEAP_SUPPORT // if (pAd->CommonCfg.bAggregationCapable) { @@ -1737,12 +1616,11 @@ VOID LinkUp( if (pAd->MlmeAux.APRalinkIe != 0x0) { -#ifdef DOT11_N_SUPPORT if (CLIENT_STATUS_TEST_FLAG(&pAd->MacTab.Content[BSSID_WCID], fCLIENT_STATUS_RDG_CAPABLE)) { AsicEnableRDG(pAd); } -#endif // DOT11_N_SUPPORT // + OPSTATUS_SET_FLAG(pAd, fCLIENT_STATUS_RALINK_CHIPSET); CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[BSSID_WCID], fCLIENT_STATUS_RALINK_CHIPSET); } @@ -1753,9 +1631,7 @@ VOID LinkUp( } } -#ifdef DOT11_N_SUPPORT DBGPRINT(RT_DEBUG_TRACE, ("NDIS_STATUS_MEDIA_CONNECT Event B!.BACapability = %x. ClientStatusFlags = %lx\n", pAd->CommonCfg.BACapability.word, pAd->MacTab.Content[BSSID_WCID].ClientStatusFlags)); -#endif // DOT11_N_SUPPORT // // Set LED RTMPSetLED(pAd, LED_LINK_UP); @@ -1780,13 +1656,13 @@ VOID LinkUp( if (pAd->StaCfg.bAutoTxRateSwitch == FALSE) { pEntry->bAutoTxRateSwitch = FALSE; -#ifdef DOT11_N_SUPPORT + if (pEntry->HTPhyMode.field.MCS == 32) pEntry->HTPhyMode.field.ShortGI = GI_800; if ((pEntry->HTPhyMode.field.MCS > MCS_7) || (pEntry->HTPhyMode.field.MCS == 32)) pEntry->HTPhyMode.field.STBC = STBC_NONE; -#endif // DOT11_N_SUPPORT // + // If the legacy mode is set, overwrite the transmit setting of this entry. if (pEntry->HTPhyMode.field.MODE <= MODE_OFDM) RTMPUpdateLegacyTxSetting((UCHAR)pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode, pEntry); @@ -1815,7 +1691,6 @@ VOID LinkUp( RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R1, Value); } -#ifdef DOT11_N_SUPPORT if (pAd->StaActive.SupportedPhyInfo.bHtEnable == FALSE) { } @@ -1825,7 +1700,6 @@ VOID LinkUp( // Because our Init value is 1 at MACRegTable. RTMP_IO_WRITE32(pAd, MAX_LEN_CFG, 0x0fff); } -#endif // DOT11_N_SUPPORT // // Patch for Marvel AP to gain high throughput // Need to set as following, @@ -1837,9 +1711,15 @@ VOID LinkUp( // Txop can only be modified when RDG is off, WMM is disable and TxBurst is enable // // if 1. Legacy AP WMM on, or 2. 11n AP, AMPDU disable. Force turn off burst no matter what bEnableTxBurst is. -#ifdef DOT11_N_SUPPORT +#ifdef RT30xx + if (!((pAd->CommonCfg.RxStream == 1)&&(pAd->CommonCfg.TxStream == 1)) && + (((pAd->StaActive.SupportedPhyInfo.bHtEnable == FALSE) && OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED)) + || ((pAd->StaActive.SupportedPhyInfo.bHtEnable == TRUE) && (pAd->CommonCfg.BACapability.field.Policy == BA_NOTUSE)))) +#endif +#ifndef RT30xx if (((pAd->StaActive.SupportedPhyInfo.bHtEnable == FALSE) && (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED))) || ((pAd->StaActive.SupportedPhyInfo.bHtEnable == TRUE) && (pAd->CommonCfg.BACapability.field.Policy == BA_NOTUSE))) +#endif { RTMP_IO_READ32(pAd, EDCA_AC0_CFG, &Data); Data &= 0xFFFFFF00; @@ -1849,7 +1729,6 @@ VOID LinkUp( DBGPRINT(RT_DEBUG_TRACE, ("Txburst 1\n")); } else -#endif // DOT11_N_SUPPORT // if (pAd->CommonCfg.bEnableTxBurst) { RTMP_IO_READ32(pAd, EDCA_AC0_CFG, &Data); @@ -1871,7 +1750,6 @@ VOID LinkUp( DBGPRINT(RT_DEBUG_TRACE, ("Txburst 3\n")); } -#ifdef DOT11_N_SUPPORT // Re-check to turn on TX burst or not. if ((pAd->CommonCfg.IOTestParm.bLastAtheros == TRUE) && ((STA_WEP_ON(pAd))||(STA_TKIP_ON(pAd)))) { @@ -1891,7 +1769,6 @@ VOID LinkUp( { pAd->CommonCfg.IOTestParm.bNextDisableRxBA = FALSE; } -#endif // DOT11_N_SUPPORT // pAd->CommonCfg.IOTestParm.bLastAtheros = FALSE; COPY_MAC_ADDR(pAd->CommonCfg.LastBssid, pAd->CommonCfg.Bssid); @@ -1924,17 +1801,9 @@ VOID LinkUp( } RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS); +#ifdef RT2860 RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_GO_TO_SLEEP_NOW); - -#ifdef DOT11_N_SUPPORT -#ifdef DOT11N_DRAFT3 - if ((pAd->CommonCfg.BACapability.field.b2040CoexistScanSup) && (pAd->CommonCfg.Channel <= 11)) - { - OPSTATUS_SET_FLAG(pAd, fOP_STATUS_SCAN_2040); - BuildEffectedChannelList(pAd); - } -#endif // DOT11N_DRAFT3 // -#endif // DOT11_N_SUPPORT // +#endif } /* @@ -1967,23 +1836,21 @@ VOID LinkDown( IN BOOLEAN IsReqFromAP) { UCHAR i, ByteValue = 0; +#ifdef RT2860 BOOLEAN Cancelled; +#endif // Do nothing if monitor mode is on if (MONITOR_ON(pAd)) return; -#ifdef RALINK_ATE - // Nothing to do in ATE mode. - if (ATE_ON(pAd)) - return; -#endif // RALINK_ATE // - +#ifdef RT2860 RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_GO_TO_SLEEP_NOW); RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled); // Not allow go to sleep within linkdown function. RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_CAN_GO_SLEEP); +#endif if (pAd->CommonCfg.bWirelessEvent) { @@ -1993,6 +1860,7 @@ VOID LinkDown( DBGPRINT(RT_DEBUG_TRACE, ("!!! LINK DOWN !!!\n")); OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED); +#ifdef RT2860 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE)) { BOOLEAN Cancelled; @@ -2009,6 +1877,7 @@ VOID LinkDown( } pAd->bPCIclkOff = FALSE; +#endif if (ADHOC_ON(pAd)) // Adhoc mode link down { DBGPRINT(RT_DEBUG_TRACE, ("!!! LINK DOWN 1!!!\n")); @@ -2025,33 +1894,6 @@ VOID LinkDown( { DBGPRINT(RT_DEBUG_TRACE, ("!!! LINK DOWN 2!!!\n")); -#ifdef QOS_DLS_SUPPORT - // DLS tear down frame must be sent before link down - // send DLS-TEAR_DOWN message - if (pAd->CommonCfg.bDLSCapable) - { - // tear down local dls table entry - for (i=0; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH)) - { - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - RTMPSendDLSTearDownFrame(pAd, pAd->StaCfg.DLSEntry[i].MacAddr); - } - } - - // tear down peer dls table entry - for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH)) - { - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - RTMPSendDLSTearDownFrame(pAd, pAd->StaCfg.DLSEntry[i].MacAddr); - } - } - } -#endif // QOS_DLS_SUPPORT // - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_INFRA_ON); OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED); @@ -2095,17 +1937,6 @@ VOID LinkDown( NdisMoveMemory(pAd->StaCfg.CCXAdjacentAPSsid, pAd->CommonCfg.Ssid, pAd->StaCfg.CCXAdjacentAPSsidLen); COPY_MAC_ADDR(pAd->StaCfg.CCXAdjacentAPBssid, pAd->CommonCfg.Bssid); } - -#ifdef EXT_BUILD_CHANNEL_LIST - // Country IE of the AP will be evaluated and will be used. - if (pAd->StaCfg.IEEE80211dClientMode != Rt802_11_D_None) - { - NdisMoveMemory(&pAd->CommonCfg.CountryCode[0], &pAd->StaCfg.StaOriCountryCode[0], 2); - pAd->CommonCfg.Geography = pAd->StaCfg.StaOriGeography; - BuildChannelListEx(pAd); - } -#endif // EXT_BUILD_CHANNEL_LIST // - } for (i=1; iCommonCfg.Ssid, MAX_LEN_OF_SSID); pAd->CommonCfg.SsidLen = 0; } -#ifdef DOT11_N_SUPPORT + NdisZeroMemory(&pAd->MlmeAux.HtCapability, sizeof(HT_CAPABILITY_IE)); NdisZeroMemory(&pAd->MlmeAux.AddHtInfo, sizeof(ADD_HT_INFO_IE)); pAd->MlmeAux.HtCapabilityLen = 0; pAd->MlmeAux.NewExtChannelOffset = 0xff; -#endif // DOT11_N_SUPPORT // // Reset WPA-PSK state. Only reset when supplicant enabled if (pAd->StaCfg.WpaState != SS_NOTUSE) @@ -2150,11 +1980,6 @@ VOID LinkDown( pAd->StaCfg.WpaState = SS_START; // Clear Replay counter NdisZeroMemory(pAd->StaCfg.ReplayCounter, 8); - -#ifdef QOS_DLS_SUPPORT - if (pAd->CommonCfg.bDLSCapable) - NdisZeroMemory(pAd->StaCfg.DlsReplayCounter, 8); -#endif // QOS_DLS_SUPPORT // } @@ -2169,7 +1994,7 @@ VOID LinkDown( } // 802.1x port control -#ifdef WPA_SUPPLICANT_SUPPORT + // Prevent clear PortSecured here with static WEP // NetworkManger set security policy first then set SSID to connect AP. if (pAd->StaCfg.WpaSupplicantUP && @@ -2179,7 +2004,6 @@ VOID LinkDown( pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; } else -#endif // WPA_SUPPLICANT_SUPPORT // { pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; pAd->StaCfg.PrivacyFilter = Ndis802_11PrivFilter8021xWEP; @@ -2199,13 +2023,18 @@ VOID LinkDown( // Update extra information to link is up pAd->ExtraInfo = GENERAL_LINK_DOWN; +#ifdef RT2860 pAd->StaCfg.AdhocBOnlyJoined = FALSE; pAd->StaCfg.AdhocBGJoined = FALSE; pAd->StaCfg.Adhoc20NJoined = FALSE; +#endif pAd->StaActive.SupportedPhyInfo.bHtEnable = FALSE; // Reset the Current AP's IP address NdisZeroMemory(pAd->StaCfg.AironetIPAddress, 4); +#ifdef RT2870 + pAd->bUsbTxBulkAggre = FALSE; +#endif // RT2870 // // Clean association information NdisZeroMemory(&pAd->StaCfg.AssocInfo, sizeof(NDIS_802_11_ASSOCIATION_INFORMATION)); @@ -2227,7 +2056,6 @@ VOID LinkDown( pAd->CommonCfg.MlmeRate = pAd->CommonCfg.BasicMlmeRate; pAd->CommonCfg.RtsRate = pAd->CommonCfg.BasicMlmeRate; -#ifdef DOT11_N_SUPPORT // // After Link down, reset piggy-back setting in ASIC. Disable RDG. // @@ -2238,7 +2066,7 @@ VOID LinkDown( ByteValue &= (~0x18); RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, ByteValue); } -#endif // DOT11_N_SUPPORT // + // Reset DAC RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R1, &ByteValue); ByteValue &= (~0x18); @@ -2251,9 +2079,7 @@ VOID LinkDown( RTMPSetPiggyBack(pAd,FALSE); OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_PIGGYBACK_INUSED); -#ifdef DOT11_N_SUPPORT pAd->CommonCfg.BACapability.word = pAd->CommonCfg.REGBACapability.word; -#endif // DOT11_N_SUPPORT // // Restore all settings in the following. AsicUpdateProtect(pAd, 0, (ALLN_SETPROTECT|CCKSETPROTECT|OFDMSETPROTECT), TRUE, FALSE); @@ -2261,43 +2087,35 @@ VOID LinkDown( pAd->CommonCfg.IOTestParm.bCurrentAtheros = FALSE; pAd->CommonCfg.IOTestParm.bNowAtherosBurstOn = FALSE; -#ifdef DOT11_N_SUPPORT -#ifdef DOT11N_DRAFT3 - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SCAN_2040); - pAd->CommonCfg.BSSCoexist2040.word = 0; - TriEventInit(pAd); - for (i = 0; i < (pAd->ChannelListNum - 1); i++) - { - pAd->ChannelList[i].bEffectedChannel = FALSE; - } -#endif // DOT11N_DRAFT3 // -#endif // DOT11_N_SUPPORT // - RTMP_IO_WRITE32(pAd, MAX_LEN_CFG, 0x1fff); RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS); +#ifdef RT2860 // Allow go to sleep after linkdown steps. RTMP_SET_PSFLAG(pAd, fRTMP_PS_CAN_GO_SLEEP); +#endif -#ifdef WPA_SUPPLICANT_SUPPORT -#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT - if (pAd->StaCfg.WpaSupplicantUP) { - union iwreq_data wrqu; - //send disassociate event to wpa_supplicant - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.flags = RT_DISASSOC_EVENT_FLAG; - wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); - } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // -#endif // WPA_SUPPLICANT_SUPPORT // - -#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT { union iwreq_data wrqu; memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN); wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // + +#ifdef RT30xx + if (IS_RT3090(pAd)) + { + UINT32 macdata; + // disable MMPS BBP control register + RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &ByteValue); + ByteValue &= ~(0x04); //bit 2 + RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, ByteValue); + + // disable MMPS MAC control register + RTMP_IO_READ32(pAd, 0x1210, &macdata); + macdata &= ~(0x09); //bit 0, 3 + RTMP_IO_WRITE32(pAd, 0x1210, macdata); + } +#endif // RT30xx // } /* @@ -2457,26 +2275,6 @@ VOID ScanParmFill( ScanReq->ScanType = ScanType; } -#ifdef QOS_DLS_SUPPORT -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== -*/ -VOID DlsParmFill( - IN PRTMP_ADAPTER pAd, - IN OUT MLME_DLS_REQ_STRUCT *pDlsReq, - IN PRT_802_11_DLS pDls, - IN USHORT reason) -{ - pDlsReq->pDLS = pDls; - pDlsReq->Reason = reason; -} -#endif // QOS_DLS_SUPPORT // - /* ========================================================================== Description: @@ -2523,21 +2321,61 @@ VOID AuthParmFill( ========================================================================== */ + + +#ifdef RT2870 + +VOID MlmeCntlConfirm( + IN PRTMP_ADAPTER pAd, + IN ULONG MsgType, + IN USHORT Msg) +{ + MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MsgType, sizeof(USHORT), &Msg); +} +#endif + VOID ComposePsPoll( IN PRTMP_ADAPTER pAd) { +#ifdef RT2870 + PTXINFO_STRUC pTxInfo; + PTXWI_STRUC pTxWI; + + DBGPRINT(RT_DEBUG_TRACE, ("ComposePsPoll\n")); +#endif NdisZeroMemory(&pAd->PsPollFrame, sizeof(PSPOLL_FRAME)); + +#ifdef RT2870 + pAd->PsPollFrame.FC.PwrMgmt = 0; +#endif pAd->PsPollFrame.FC.Type = BTYPE_CNTL; pAd->PsPollFrame.FC.SubType = SUBTYPE_PS_POLL; pAd->PsPollFrame.Aid = pAd->StaActive.Aid | 0xC000; COPY_MAC_ADDR(pAd->PsPollFrame.Bssid, pAd->CommonCfg.Bssid); COPY_MAC_ADDR(pAd->PsPollFrame.Ta, pAd->CurrentAddress); + +#ifdef RT2870 + RTMPZeroMemory(&pAd->PsPollContext.TransferBuffer->field.WirelessPacket[0], 100); + pTxInfo = (PTXINFO_STRUC)&pAd->PsPollContext.TransferBuffer->field.WirelessPacket[0]; + RTMPWriteTxInfo(pAd, pTxInfo, (USHORT)(sizeof(PSPOLL_FRAME)+TXWI_SIZE), TRUE, EpToQueue[MGMTPIPEIDX], FALSE, FALSE); + pTxWI = (PTXWI_STRUC)&pAd->PsPollContext.TransferBuffer->field.WirelessPacket[TXINFO_SIZE]; + RTMPWriteTxWI(pAd, pTxWI, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, 0, BSSID_WCID, (sizeof(PSPOLL_FRAME)), + 0, 0, (UCHAR)pAd->CommonCfg.MlmeTransmit.field.MCS, IFS_BACKOFF, FALSE, &pAd->CommonCfg.MlmeTransmit); + RTMPMoveMemory(&pAd->PsPollContext.TransferBuffer->field.WirelessPacket[TXWI_SIZE+TXINFO_SIZE], &pAd->PsPollFrame, sizeof(PSPOLL_FRAME)); + // Append 4 extra zero bytes. + pAd->PsPollContext.BulkOutSize = TXINFO_SIZE + TXWI_SIZE + sizeof(PSPOLL_FRAME) + 4; +#endif } // IRQL = DISPATCH_LEVEL VOID ComposeNullFrame( IN PRTMP_ADAPTER pAd) { +#ifdef RT2870 + PTXINFO_STRUC pTxInfo; + PTXWI_STRUC pTxWI; +#endif + NdisZeroMemory(&pAd->NullFrame, sizeof(HEADER_802_11)); pAd->NullFrame.FC.Type = BTYPE_DATA; pAd->NullFrame.FC.SubType = SUBTYPE_NULL_FUNC; @@ -2545,6 +2383,16 @@ VOID ComposeNullFrame( COPY_MAC_ADDR(pAd->NullFrame.Addr1, pAd->CommonCfg.Bssid); COPY_MAC_ADDR(pAd->NullFrame.Addr2, pAd->CurrentAddress); COPY_MAC_ADDR(pAd->NullFrame.Addr3, pAd->CommonCfg.Bssid); +#ifdef RT2870 + RTMPZeroMemory(&pAd->NullContext.TransferBuffer->field.WirelessPacket[0], 100); + pTxInfo = (PTXINFO_STRUC)&pAd->NullContext.TransferBuffer->field.WirelessPacket[0]; + RTMPWriteTxInfo(pAd, pTxInfo, (USHORT)(sizeof(HEADER_802_11)+TXWI_SIZE), TRUE, EpToQueue[MGMTPIPEIDX], FALSE, FALSE); + pTxWI = (PTXWI_STRUC)&pAd->NullContext.TransferBuffer->field.WirelessPacket[TXINFO_SIZE]; + RTMPWriteTxWI(pAd, pTxWI, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, 0, BSSID_WCID, (sizeof(HEADER_802_11)), + 0, 0, (UCHAR)pAd->CommonCfg.MlmeTransmit.field.MCS, IFS_BACKOFF, FALSE, &pAd->CommonCfg.MlmeTransmit); + RTMPMoveMemory(&pAd->NullContext.TransferBuffer->field.WirelessPacket[TXWI_SIZE+TXINFO_SIZE], &pAd->NullFrame, sizeof(HEADER_802_11)); + pAd->NullContext.BulkOutSize = TXINFO_SIZE + TXWI_SIZE + sizeof(pAd->NullFrame) + 4; +#endif } @@ -2688,22 +2536,15 @@ ULONG MakeIbssBeacon( FrameLen += tmp; } -#ifdef DOT11_N_SUPPORT if ((pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) { ULONG TmpLen; UCHAR HtLen, HtLen1; -#ifdef RT_BIG_ENDIAN - HT_CAPABILITY_IE HtCapabilityTmp; - ADD_HT_INFO_IE addHTInfoTmp; - USHORT b2lTmp, b2lTmp2; -#endif - // add HT Capability IE HtLen = sizeof(pAd->CommonCfg.HtCapability); HtLen1 = sizeof(pAd->CommonCfg.AddHTInfo); -#ifndef RT_BIG_ENDIAN + MakeOutgoingFrame(pBeaconFrame+FrameLen, &TmpLen, 1, &HtCapIe, 1, &HtLen, @@ -2712,27 +2553,9 @@ ULONG MakeIbssBeacon( 1, &HtLen1, HtLen1, &pAd->CommonCfg.AddHTInfo, END_OF_ARGS); -#else - NdisMoveMemory(&HtCapabilityTmp, &pAd->CommonCfg.HtCapability, HtLen); - *(USHORT *)(&HtCapabilityTmp.HtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.HtCapInfo)); - *(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo)); - NdisMoveMemory(&addHTInfoTmp, &pAd->CommonCfg.AddHTInfo, HtLen1); - *(USHORT *)(&addHTInfoTmp.AddHtInfo2) = SWAP16(*(USHORT *)(&addHTInfoTmp.AddHtInfo2)); - *(USHORT *)(&addHTInfoTmp.AddHtInfo3) = SWAP16(*(USHORT *)(&addHTInfoTmp.AddHtInfo3)); - - MakeOutgoingFrame(pBeaconFrame+FrameLen, &TmpLen, - 1, &HtCapIe, - 1, &HtLen, - HtLen, &HtCapabilityTmp, - 1, &AddHtInfoIe, - 1, &HtLen1, - HtLen1, &addHTInfoTmp, - END_OF_ARGS); -#endif FrameLen += TmpLen; } -#endif // DOT11_N_SUPPORT // //beacon use reserved WCID 0xff if (pAd->CommonCfg.Channel > 14) @@ -2749,11 +2572,6 @@ ULONG MakeIbssBeacon( PID_MGMT, PID_BEACON, RATE_1, IFS_HTTXOP, FALSE, &Transmit); } -#ifdef RT_BIG_ENDIAN - RTMPFrameEndianChange(pAd, pBeaconFrame, DIR_WRITE, FALSE); - RTMPWIEndianChange((PUCHAR)pTxWI, TYPE_TXWI); -#endif - DBGPRINT(RT_DEBUG_TRACE, ("MakeIbssBeacon (len=%ld), SupRateLen=%d, ExtRateLen=%d, Channel=%d, PhyMode=%d\n", FrameLen, SupRateLen, ExtRateLen, pAd->CommonCfg.Channel, pAd->CommonCfg.PhyMode)); return FrameLen; diff --git a/drivers/staging/rt2860/sta/dls.c b/drivers/staging/rt2860/sta/dls.c deleted file mode 100644 index 873cf7f1de93..000000000000 --- a/drivers/staging/rt2860/sta/dls.c +++ /dev/null @@ -1,2197 +0,0 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - dls.c - - Abstract: - Handle WMM-DLS state machine - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Rory Chen 02-14-2006 - Arvin Tai 06-03-2008 Modified for RT28xx - */ - -#include "../rt_config.h" - -/* - ========================================================================== - Description: - dls state machine init, including state transition and timer init - Parameters: - Sm - pointer to the dls state machine - Note: - The state machine looks like this - - DLS_IDLE - MT2_MLME_DLS_REQUEST MlmeDlsReqAction - MT2_PEER_DLS_REQUEST PeerDlsReqAction - MT2_PEER_DLS_RESPONSE PeerDlsRspAction - MT2_MLME_DLS_TEARDOWN MlmeTearDownAction - MT2_PEER_DLS_TEARDOWN PeerTearDownAction - - IRQL = PASSIVE_LEVEL - - ========================================================================== - */ -void DlsStateMachineInit( - IN PRTMP_ADAPTER pAd, - IN STATE_MACHINE *Sm, - OUT STATE_MACHINE_FUNC Trans[]) -{ - UCHAR i; - - StateMachineInit(Sm, (STATE_MACHINE_FUNC*)Trans, MAX_DLS_STATE, MAX_DLS_MSG, (STATE_MACHINE_FUNC)Drop, DLS_IDLE, DLS_MACHINE_BASE); - - // the first column - StateMachineSetAction(Sm, DLS_IDLE, MT2_MLME_DLS_REQ, (STATE_MACHINE_FUNC)MlmeDlsReqAction); - StateMachineSetAction(Sm, DLS_IDLE, MT2_PEER_DLS_REQ, (STATE_MACHINE_FUNC)PeerDlsReqAction); - StateMachineSetAction(Sm, DLS_IDLE, MT2_PEER_DLS_RSP, (STATE_MACHINE_FUNC)PeerDlsRspAction); - StateMachineSetAction(Sm, DLS_IDLE, MT2_MLME_DLS_TEAR_DOWN, (STATE_MACHINE_FUNC)MlmeDlsTearDownAction); - StateMachineSetAction(Sm, DLS_IDLE, MT2_PEER_DLS_TEAR_DOWN, (STATE_MACHINE_FUNC)PeerDlsTearDownAction); - - for (i=0; iStaCfg.DLSEntry[i].pAd = pAd; - RTMPInitTimer(pAd, &pAd->StaCfg.DLSEntry[i].Timer, GET_TIMER_FUNCTION(DlsTimeoutAction), pAd, FALSE); - } -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID MlmeDlsReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - PUCHAR pOutBuffer = NULL; - NDIS_STATUS NStatus; - ULONG FrameLen = 0; - HEADER_802_11 DlsReqHdr; - PRT_802_11_DLS pDLS = NULL; - UCHAR Category = CATEGORY_DLS; - UCHAR Action = ACTION_DLS_REQUEST; - ULONG tmp; - USHORT reason; - ULONG Timeout; - BOOLEAN TimerCancelled; - - if(!MlmeDlsReqSanity(pAd, Elem->Msg, Elem->MsgLen, &pDLS, &reason)) - return; - - DBGPRINT(RT_DEBUG_TRACE,("DLS - MlmeDlsReqAction() \n")); - - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory - if (NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_ERROR,("DLS - MlmeDlsReqAction() allocate memory failed \n")); - return; - } - - ActHeaderInit(pAd, &DlsReqHdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pAd->CommonCfg.Bssid); - - // Build basic frame first - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(HEADER_802_11), &DlsReqHdr, - 1, &Category, - 1, &Action, - 6, &pDLS->MacAddr, - 6, pAd->CurrentAddress, - 2, &pAd->StaActive.CapabilityInfo, - 2, &pDLS->TimeOut, - 1, &SupRateIe, - 1, &pAd->MlmeAux.SupRateLen, - pAd->MlmeAux.SupRateLen, pAd->MlmeAux.SupRate, - END_OF_ARGS); - - if (pAd->MlmeAux.ExtRateLen != 0) - { - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - 1, &ExtRateIe, - 1, &pAd->MlmeAux.ExtRateLen, - pAd->MlmeAux.ExtRateLen, pAd->MlmeAux.ExtRate, - END_OF_ARGS); - FrameLen += tmp; - } - -#ifdef DOT11_N_SUPPORT - if ((pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) - { - UCHAR HtLen; - -#ifdef RT_BIG_ENDIAN - HT_CAPABILITY_IE HtCapabilityTmp; -#endif - - // add HT Capability IE - HtLen = sizeof(HT_CAPABILITY_IE); -#ifndef RT_BIG_ENDIAN - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - 1, &HtCapIe, - 1, &HtLen, - HtLen, &pAd->CommonCfg.HtCapability, - END_OF_ARGS); -#else - NdisMoveMemory(&HtCapabilityTmp, &pAd->CommonCfg.HtCapability, HtLen); - *(USHORT *)(&HtCapabilityTmp.HtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.HtCapInfo)); - *(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo)); - - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - 1, &HtCapIe, - 1, &HtLen, - HtLen, &HtCapabilityTmp, - END_OF_ARGS); -#endif - FrameLen = FrameLen + tmp; - } -#endif // DOT11_N_SUPPORT // - - RTMPCancelTimer(&pDLS->Timer, &TimerCancelled); - Timeout = DLS_TIMEOUT; - RTMPSetTimer(&pDLS->Timer, Timeout); - - MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID PeerDlsReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - PUCHAR pOutBuffer = NULL; - NDIS_STATUS NStatus; - ULONG FrameLen = 0; - USHORT StatusCode = MLME_SUCCESS; - HEADER_802_11 DlsRspHdr; - UCHAR Category = CATEGORY_DLS; - UCHAR Action = ACTION_DLS_RESPONSE; - ULONG tmp; - USHORT CapabilityInfo; - UCHAR DA[MAC_ADDR_LEN], SA[MAC_ADDR_LEN]; - USHORT DLSTimeOut; - SHORT i; - ULONG Timeout; - BOOLEAN TimerCancelled; - PRT_802_11_DLS pDLS = NULL; - UCHAR MaxSupportedRateIn500Kbps = 0; - UCHAR SupportedRatesLen; - UCHAR SupportedRates[MAX_LEN_OF_SUPPORTED_RATES]; - UCHAR HtCapabilityLen; - HT_CAPABILITY_IE HtCapability; - - if (!PeerDlsReqSanity(pAd, Elem->Msg, Elem->MsgLen, DA, SA, &CapabilityInfo, &DLSTimeOut, - &SupportedRatesLen, &SupportedRates[0], &HtCapabilityLen, &HtCapability)) - return; - - // supported rates array may not be sorted. sort it and find the maximum rate - for (i = 0; i < SupportedRatesLen; i++) - { - if (MaxSupportedRateIn500Kbps < (SupportedRates[i] & 0x7f)) - MaxSupportedRateIn500Kbps = SupportedRates[i] & 0x7f; - } - - DBGPRINT(RT_DEBUG_TRACE,("DLS - PeerDlsReqAction() from %02x:%02x:%02x:%02x:%02x:%02x\n", SA[0], SA[1], SA[2], SA[3], SA[4], SA[5])); - - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory - if (NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_ERROR,("DLS - PeerDlsReqAction() allocate memory failed \n")); - return; - } - - if (!INFRA_ON(pAd)) - { - StatusCode = MLME_REQUEST_DECLINED; - } - else if (!pAd->CommonCfg.bWmmCapable) - { - StatusCode = MLME_DEST_STA_IS_NOT_A_QSTA; - } - else if (!pAd->CommonCfg.bDLSCapable) - { - StatusCode = MLME_REQUEST_DECLINED; - } - else - { - // find table to update parameters - for (i = (MAX_NUM_OF_DLS_ENTRY-1); i >= 0; i--) - { - if (pAd->StaCfg.DLSEntry[i].Valid && MAC_ADDR_EQUAL(SA, pAd->StaCfg.DLSEntry[i].MacAddr)) - { - if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - pAd->StaCfg.DLSEntry[i].Status = DLS_WAIT_KEY; - else - { - RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); - pAd->StaCfg.DLSEntry[i].Status = DLS_FINISH; - } - - pAd->StaCfg.DLSEntry[i].Sequence = 0; - pAd->StaCfg.DLSEntry[i].TimeOut = DLSTimeOut; - pAd->StaCfg.DLSEntry[i].CountDownTimer = DLSTimeOut; - if (HtCapabilityLen != 0) - pAd->StaCfg.DLSEntry[i].bHTCap = TRUE; - else - pAd->StaCfg.DLSEntry[i].bHTCap = FALSE; - pDLS = &pAd->StaCfg.DLSEntry[i]; - break; - } - } - - // can not find in table, create a new one - if (i < 0) - { - DBGPRINT(RT_DEBUG_TRACE,("DLS - PeerDlsReqAction() can not find same entry \n")); - for (i=(MAX_NUM_OF_DLS_ENTRY - 1); i >= MAX_NUM_OF_INIT_DLS_ENTRY; i--) - { - if (!pAd->StaCfg.DLSEntry[i].Valid) - { - MAC_TABLE_ENTRY *pEntry; - UCHAR MaxSupportedRate = RATE_11; - - if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - { - pAd->StaCfg.DLSEntry[i].Status = DLS_WAIT_KEY; - } - else - { - RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); - pAd->StaCfg.DLSEntry[i].Status = DLS_FINISH; - } - - pAd->StaCfg.DLSEntry[i].Sequence = 0; - pAd->StaCfg.DLSEntry[i].Valid = TRUE; - pAd->StaCfg.DLSEntry[i].TimeOut = DLSTimeOut; - pAd->StaCfg.DLSEntry[i].CountDownTimer = DLSTimeOut; - NdisMoveMemory(pAd->StaCfg.DLSEntry[i].MacAddr, SA, MAC_ADDR_LEN); - if (HtCapabilityLen != 0) - pAd->StaCfg.DLSEntry[i].bHTCap = TRUE; - else - pAd->StaCfg.DLSEntry[i].bHTCap = FALSE; - pDLS = &pAd->StaCfg.DLSEntry[i]; - pEntry = MacTableInsertDlsEntry(pAd, SA, i); - - switch (MaxSupportedRateIn500Kbps) - { - case 108: MaxSupportedRate = RATE_54; break; - case 96: MaxSupportedRate = RATE_48; break; - case 72: MaxSupportedRate = RATE_36; break; - case 48: MaxSupportedRate = RATE_24; break; - case 36: MaxSupportedRate = RATE_18; break; - case 24: MaxSupportedRate = RATE_12; break; - case 18: MaxSupportedRate = RATE_9; break; - case 12: MaxSupportedRate = RATE_6; break; - case 22: MaxSupportedRate = RATE_11; break; - case 11: MaxSupportedRate = RATE_5_5; break; - case 4: MaxSupportedRate = RATE_2; break; - case 2: MaxSupportedRate = RATE_1; break; - default: MaxSupportedRate = RATE_11; break; - } - - pEntry->MaxSupportedRate = min(pAd->CommonCfg.MaxTxRate, MaxSupportedRate); - - if (pEntry->MaxSupportedRate < RATE_FIRST_OFDM_RATE) - { - pEntry->MaxHTPhyMode.field.MODE = MODE_CCK; - pEntry->MaxHTPhyMode.field.MCS = pEntry->MaxSupportedRate; - pEntry->MinHTPhyMode.field.MODE = MODE_CCK; - pEntry->MinHTPhyMode.field.MCS = pEntry->MaxSupportedRate; - pEntry->HTPhyMode.field.MODE = MODE_CCK; - pEntry->HTPhyMode.field.MCS = pEntry->MaxSupportedRate; - } - else - { - pEntry->MaxHTPhyMode.field.MODE = MODE_OFDM; - pEntry->MaxHTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; - pEntry->MinHTPhyMode.field.MODE = MODE_OFDM; - pEntry->MinHTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; - pEntry->HTPhyMode.field.MODE = MODE_OFDM; - pEntry->HTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; - } - - pEntry->MaxHTPhyMode.field.BW = BW_20; - pEntry->MinHTPhyMode.field.BW = BW_20; - -#ifdef DOT11_N_SUPPORT - pEntry->HTCapability.MCSSet[0] = 0; - pEntry->HTCapability.MCSSet[1] = 0; - - // If this Entry supports 802.11n, upgrade to HT rate. - if ((HtCapabilityLen != 0) && (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) - { - UCHAR j, bitmask; //k,bitmask; - CHAR ii; - - DBGPRINT(RT_DEBUG_OFF, ("DLS - PeerDlsReqAction() Receive Peer HT Capable STA from %02x:%02x:%02x:%02x:%02x:%02x\n", - SA[0], SA[1], SA[2], SA[3], SA[4], SA[5])); - - if ((HtCapability.HtCapInfo.GF) && (pAd->CommonCfg.DesiredHtPhy.GF)) - { - pEntry->MaxHTPhyMode.field.MODE = MODE_HTGREENFIELD; - } - else - { - pEntry->MaxHTPhyMode.field.MODE = MODE_HTMIX; - pAd->MacTab.fAnyStationNonGF = TRUE; - pAd->CommonCfg.AddHTInfo.AddHtInfo2.NonGfPresent = 1; - } - - if ((HtCapability.HtCapInfo.ChannelWidth) && (pAd->CommonCfg.DesiredHtPhy.ChannelWidth)) - { - pEntry->MaxHTPhyMode.field.BW= BW_40; - pEntry->MaxHTPhyMode.field.ShortGI = ((pAd->CommonCfg.DesiredHtPhy.ShortGIfor40)&(HtCapability.HtCapInfo.ShortGIfor40)); - } - else - { - pEntry->MaxHTPhyMode.field.BW = BW_20; - pEntry->MaxHTPhyMode.field.ShortGI = ((pAd->CommonCfg.DesiredHtPhy.ShortGIfor20)&(HtCapability.HtCapInfo.ShortGIfor20)); - pAd->MacTab.fAnyStation20Only = TRUE; - } - - // find max fixed rate - for (ii=15; ii>=0; ii--) - { - j = ii/8; - bitmask = (1<<(ii-(j*8))); - if ( (pAd->StaCfg.DesiredHtPhyInfo.MCSSet[j]&bitmask) && (HtCapability.MCSSet[j]&bitmask)) - { - pEntry->MaxHTPhyMode.field.MCS = ii; - break; - } - if (ii==0) - break; - } - - - if (pAd->StaCfg.DesiredTransmitSetting.field.MCS != MCS_AUTO) - { - - printk("@@@ pAd->CommonCfg.RegTransmitSetting.field.MCS = %d\n", - pAd->StaCfg.DesiredTransmitSetting.field.MCS); - if (pAd->StaCfg.DesiredTransmitSetting.field.MCS == 32) - { - // Fix MCS as HT Duplicated Mode - pEntry->MaxHTPhyMode.field.BW = 1; - pEntry->MaxHTPhyMode.field.MODE = MODE_HTMIX; - pEntry->MaxHTPhyMode.field.STBC = 0; - pEntry->MaxHTPhyMode.field.ShortGI = 0; - pEntry->MaxHTPhyMode.field.MCS = 32; - } - else if (pEntry->MaxHTPhyMode.field.MCS > pAd->StaCfg.HTPhyMode.field.MCS) - { - // STA supports fixed MCS - pEntry->MaxHTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; - } - } - - pEntry->MaxHTPhyMode.field.STBC = (HtCapability.HtCapInfo.RxSTBC & (pAd->CommonCfg.DesiredHtPhy.TxSTBC)); - pEntry->MpduDensity = HtCapability.HtCapParm.MpduDensity; - pEntry->MaxRAmpduFactor = HtCapability.HtCapParm.MaxRAmpduFactor; - pEntry->MmpsMode = (UCHAR)HtCapability.HtCapInfo.MimoPs; - pEntry->AMsduSize = (UCHAR)HtCapability.HtCapInfo.AMsduSize; - pEntry->HTPhyMode.word = pEntry->MaxHTPhyMode.word; - - if (HtCapability.HtCapInfo.ShortGIfor20) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_SGI20_CAPABLE); - if (HtCapability.HtCapInfo.ShortGIfor40) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_SGI40_CAPABLE); - if (HtCapability.HtCapInfo.TxSTBC) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_TxSTBC_CAPABLE); - if (HtCapability.HtCapInfo.RxSTBC) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_RxSTBC_CAPABLE); - if (HtCapability.ExtHtCapInfo.PlusHTC) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_HTC_CAPABLE); - if (pAd->CommonCfg.bRdg && HtCapability.ExtHtCapInfo.RDGSupport) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_RDG_CAPABLE); - if (HtCapability.ExtHtCapInfo.MCSFeedback == 0x03) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_MCSFEEDBACK_CAPABLE); - - NdisMoveMemory(&pEntry->HTCapability, &HtCapability, sizeof(HT_CAPABILITY_IE)); - } -#endif // DOT11_N_SUPPORT // - - pEntry->HTPhyMode.word = pEntry->MaxHTPhyMode.word; - pEntry->CurrTxRate = pEntry->MaxSupportedRate; - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_WMM_CAPABLE); - - if (pAd->StaCfg.bAutoTxRateSwitch == TRUE) - { - PUCHAR pTable; - UCHAR TableSize = 0; - - MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize, &pEntry->CurrTxRateIndex); - pEntry->bAutoTxRateSwitch = TRUE; - } - else - { - pEntry->HTPhyMode.field.MODE = pAd->StaCfg.HTPhyMode.field.MODE; - pEntry->HTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; - pEntry->bAutoTxRateSwitch = FALSE; - - RTMPUpdateLegacyTxSetting((UCHAR)pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode, pEntry); - } - pEntry->RateLen = SupportedRatesLen; - - break; - } - } - } - StatusCode = MLME_SUCCESS; - - // can not find in table, create a new one - if (i < 0) - { - StatusCode = MLME_QOS_UNSPECIFY; - DBGPRINT(RT_DEBUG_ERROR,("DLS - PeerDlsReqAction() DLSEntry table full(only can support %d DLS session) \n", MAX_NUM_OF_DLS_ENTRY - MAX_NUM_OF_INIT_DLS_ENTRY)); - } - else - { - DBGPRINT(RT_DEBUG_TRACE,("DLS - PeerDlsReqAction() use entry(%d) %02x:%02x:%02x:%02x:%02x:%02x\n", - i, SA[0], SA[1], SA[2], SA[3], SA[4], SA[5])); - } - } - - ActHeaderInit(pAd, &DlsRspHdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pAd->CommonCfg.Bssid); - - // Build basic frame first - if (StatusCode == MLME_SUCCESS) - { - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(HEADER_802_11), &DlsRspHdr, - 1, &Category, - 1, &Action, - 2, &StatusCode, - 6, SA, - 6, pAd->CurrentAddress, - 2, &pAd->StaActive.CapabilityInfo, - 1, &SupRateIe, - 1, &pAd->MlmeAux.SupRateLen, - pAd->MlmeAux.SupRateLen, pAd->MlmeAux.SupRate, - END_OF_ARGS); - - if (pAd->MlmeAux.ExtRateLen != 0) - { - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - 1, &ExtRateIe, - 1, &pAd->MlmeAux.ExtRateLen, - pAd->MlmeAux.ExtRateLen, pAd->MlmeAux.ExtRate, - END_OF_ARGS); - FrameLen += tmp; - } - -#ifdef DOT11_N_SUPPORT - if ((pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) - { - UCHAR HtLen; - -#ifdef RT_BIG_ENDIAN - HT_CAPABILITY_IE HtCapabilityTmp; -#endif - - // add HT Capability IE - HtLen = sizeof(HT_CAPABILITY_IE); -#ifndef RT_BIG_ENDIAN - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - 1, &HtCapIe, - 1, &HtLen, - HtLen, &pAd->CommonCfg.HtCapability, - END_OF_ARGS); -#else - NdisMoveMemory(&HtCapabilityTmp, &pAd->CommonCfg.HtCapability, HtLen); - *(USHORT *)(&HtCapabilityTmp.HtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.HtCapInfo)); - *(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo)); - - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - 1, &HtCapIe, - 1, &HtLen, - HtLen, &HtCapabilityTmp, - END_OF_ARGS); -#endif - FrameLen = FrameLen + tmp; - } -#endif // DOT11_N_SUPPORT // - - if (pDLS && (pDLS->Status != DLS_FINISH)) - { - RTMPCancelTimer(&pDLS->Timer, &TimerCancelled); - Timeout = DLS_TIMEOUT; - RTMPSetTimer(&pDLS->Timer, Timeout); - } - } - else - { - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(HEADER_802_11), &DlsRspHdr, - 1, &Category, - 1, &Action, - 2, &StatusCode, - 6, SA, - 6, pAd->CurrentAddress, - END_OF_ARGS); - } - - MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID PeerDlsRspAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - USHORT CapabilityInfo; - UCHAR DA[MAC_ADDR_LEN], SA[MAC_ADDR_LEN]; - USHORT StatusCode; - SHORT i; - BOOLEAN TimerCancelled; - UCHAR MaxSupportedRateIn500Kbps = 0; - UCHAR SupportedRatesLen; - UCHAR SupportedRates[MAX_LEN_OF_SUPPORTED_RATES]; - UCHAR HtCapabilityLen; - HT_CAPABILITY_IE HtCapability; - - if (!pAd->CommonCfg.bDLSCapable) - return; - - if (!INFRA_ON(pAd)) - return; - - if (!PeerDlsRspSanity(pAd, Elem->Msg, Elem->MsgLen, DA, SA, &CapabilityInfo, &StatusCode, - &SupportedRatesLen, &SupportedRates[0], &HtCapabilityLen, &HtCapability)) - return; - - // supported rates array may not be sorted. sort it and find the maximum rate - for (i=0; iStaCfg.DLSEntry[i].Valid && MAC_ADDR_EQUAL(SA, pAd->StaCfg.DLSEntry[i].MacAddr)) - { - if (StatusCode == MLME_SUCCESS) - { - MAC_TABLE_ENTRY *pEntry; - UCHAR MaxSupportedRate = RATE_11; - - pEntry = MacTableInsertDlsEntry(pAd, SA, i); - - switch (MaxSupportedRateIn500Kbps) - { - case 108: MaxSupportedRate = RATE_54; break; - case 96: MaxSupportedRate = RATE_48; break; - case 72: MaxSupportedRate = RATE_36; break; - case 48: MaxSupportedRate = RATE_24; break; - case 36: MaxSupportedRate = RATE_18; break; - case 24: MaxSupportedRate = RATE_12; break; - case 18: MaxSupportedRate = RATE_9; break; - case 12: MaxSupportedRate = RATE_6; break; - case 22: MaxSupportedRate = RATE_11; break; - case 11: MaxSupportedRate = RATE_5_5; break; - case 4: MaxSupportedRate = RATE_2; break; - case 2: MaxSupportedRate = RATE_1; break; - default: MaxSupportedRate = RATE_11; break; - } - - pEntry->MaxSupportedRate = min(pAd->CommonCfg.MaxTxRate, MaxSupportedRate); - - if (pEntry->MaxSupportedRate < RATE_FIRST_OFDM_RATE) - { - pEntry->MaxHTPhyMode.field.MODE = MODE_CCK; - pEntry->MaxHTPhyMode.field.MCS = pEntry->MaxSupportedRate; - pEntry->MinHTPhyMode.field.MODE = MODE_CCK; - pEntry->MinHTPhyMode.field.MCS = pEntry->MaxSupportedRate; - pEntry->HTPhyMode.field.MODE = MODE_CCK; - pEntry->HTPhyMode.field.MCS = pEntry->MaxSupportedRate; - } - else - { - pEntry->MaxHTPhyMode.field.MODE = MODE_OFDM; - pEntry->MaxHTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; - pEntry->MinHTPhyMode.field.MODE = MODE_OFDM; - pEntry->MinHTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; - pEntry->HTPhyMode.field.MODE = MODE_OFDM; - pEntry->HTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; - } - - pEntry->MaxHTPhyMode.field.BW = BW_20; - pEntry->MinHTPhyMode.field.BW = BW_20; - -#ifdef DOT11_N_SUPPORT - pEntry->HTCapability.MCSSet[0] = 0; - pEntry->HTCapability.MCSSet[1] = 0; - - // If this Entry supports 802.11n, upgrade to HT rate. - if ((HtCapabilityLen != 0) && (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) - { - UCHAR j, bitmask; //k,bitmask; - CHAR ii; - - DBGPRINT(RT_DEBUG_OFF, ("DLS - PeerDlsRspAction Receive Peer HT Capable STA from %02x:%02x:%02x:%02x:%02x:%02x\n", - SA[0], SA[1], SA[2], SA[3], SA[4], SA[5])); - - if ((HtCapability.HtCapInfo.GF) && (pAd->CommonCfg.DesiredHtPhy.GF)) - { - pEntry->MaxHTPhyMode.field.MODE = MODE_HTGREENFIELD; - } - else - { - pEntry->MaxHTPhyMode.field.MODE = MODE_HTMIX; - pAd->MacTab.fAnyStationNonGF = TRUE; - pAd->CommonCfg.AddHTInfo.AddHtInfo2.NonGfPresent = 1; - } - - if ((HtCapability.HtCapInfo.ChannelWidth) && (pAd->CommonCfg.DesiredHtPhy.ChannelWidth)) - { - pEntry->MaxHTPhyMode.field.BW= BW_40; - pEntry->MaxHTPhyMode.field.ShortGI = ((pAd->CommonCfg.DesiredHtPhy.ShortGIfor40)&(HtCapability.HtCapInfo.ShortGIfor40)); - } - else - { - pEntry->MaxHTPhyMode.field.BW = BW_20; - pEntry->MaxHTPhyMode.field.ShortGI = ((pAd->CommonCfg.DesiredHtPhy.ShortGIfor20)&(HtCapability.HtCapInfo.ShortGIfor20)); - pAd->MacTab.fAnyStation20Only = TRUE; - } - - // find max fixed rate - for (ii=15; ii>=0; ii--) - { - j = ii/8; - bitmask = (1<<(ii-(j*8))); - if ( (pAd->StaCfg.DesiredHtPhyInfo.MCSSet[j]&bitmask) && (HtCapability.MCSSet[j]&bitmask)) - { - pEntry->MaxHTPhyMode.field.MCS = ii; - break; - } - if (ii==0) - break; - } - - if (pAd->StaCfg.DesiredTransmitSetting.field.MCS != MCS_AUTO) - { - if (pAd->StaCfg.DesiredTransmitSetting.field.MCS == 32) - { - // Fix MCS as HT Duplicated Mode - pEntry->MaxHTPhyMode.field.BW = 1; - pEntry->MaxHTPhyMode.field.MODE = MODE_HTMIX; - pEntry->MaxHTPhyMode.field.STBC = 0; - pEntry->MaxHTPhyMode.field.ShortGI = 0; - pEntry->MaxHTPhyMode.field.MCS = 32; - } - else if (pEntry->MaxHTPhyMode.field.MCS > pAd->StaCfg.HTPhyMode.field.MCS) - { - // STA supports fixed MCS - pEntry->MaxHTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; - } - } - - pEntry->MaxHTPhyMode.field.STBC = (HtCapability.HtCapInfo.RxSTBC & (pAd->CommonCfg.DesiredHtPhy.TxSTBC)); - pEntry->MpduDensity = HtCapability.HtCapParm.MpduDensity; - pEntry->MaxRAmpduFactor = HtCapability.HtCapParm.MaxRAmpduFactor; - pEntry->MmpsMode = (UCHAR)HtCapability.HtCapInfo.MimoPs; - pEntry->AMsduSize = (UCHAR)HtCapability.HtCapInfo.AMsduSize; - pEntry->HTPhyMode.word = pEntry->MaxHTPhyMode.word; - - if (HtCapability.HtCapInfo.ShortGIfor20) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_SGI20_CAPABLE); - if (HtCapability.HtCapInfo.ShortGIfor40) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_SGI40_CAPABLE); - if (HtCapability.HtCapInfo.TxSTBC) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_TxSTBC_CAPABLE); - if (HtCapability.HtCapInfo.RxSTBC) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_RxSTBC_CAPABLE); - if (HtCapability.ExtHtCapInfo.PlusHTC) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_HTC_CAPABLE); - if (pAd->CommonCfg.bRdg && HtCapability.ExtHtCapInfo.RDGSupport) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_RDG_CAPABLE); - if (HtCapability.ExtHtCapInfo.MCSFeedback == 0x03) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_MCSFEEDBACK_CAPABLE); - - NdisMoveMemory(&pEntry->HTCapability, &HtCapability, sizeof(HT_CAPABILITY_IE)); - } -#endif // DOT11_N_SUPPORT // - pEntry->HTPhyMode.word = pEntry->MaxHTPhyMode.word; - pEntry->CurrTxRate = pEntry->MaxSupportedRate; - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_WMM_CAPABLE); - - if (pAd->StaCfg.bAutoTxRateSwitch == TRUE) - { - PUCHAR pTable; - UCHAR TableSize = 0; - - MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize, &pEntry->CurrTxRateIndex); - pEntry->bAutoTxRateSwitch = TRUE; - } - else - { - pEntry->HTPhyMode.field.MODE = pAd->StaCfg.HTPhyMode.field.MODE; - pEntry->HTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; - pEntry->bAutoTxRateSwitch = FALSE; - - RTMPUpdateLegacyTxSetting((UCHAR)pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode, pEntry); - } - pEntry->RateLen = SupportedRatesLen; - - if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - { - // If support WPA or WPA2, start STAKey hand shake, - // If failed hand shake, just tear down peer DLS - if (RTMPSendSTAKeyRequest(pAd, pAd->StaCfg.DLSEntry[i].MacAddr) != NDIS_STATUS_SUCCESS) - { - MLME_DLS_REQ_STRUCT MlmeDlsReq; - USHORT reason = REASON_QOS_CIPHER_NOT_SUPPORT; - - DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); - MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_TEAR_DOWN, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - pAd->StaCfg.DLSEntry[i].Valid = FALSE; - DBGPRINT(RT_DEBUG_ERROR,("DLS - PeerDlsRspAction failed when call RTMPSendSTAKeyRequest \n")); - } - else - { - pAd->StaCfg.DLSEntry[i].Status = DLS_WAIT_KEY; - DBGPRINT(RT_DEBUG_TRACE,("DLS - waiting for STAKey handshake procedure\n")); - } - } - else - { - RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); - pAd->StaCfg.DLSEntry[i].Status = DLS_FINISH; - DBGPRINT(RT_DEBUG_TRACE,("DLS - PeerDlsRspAction() from %02x:%02x:%02x:%02x:%02x:%02x Succeed with WEP or no security\n", SA[0], SA[1], SA[2], SA[3], SA[4], SA[5])); - } - - //initialize seq no for DLS frames. - pAd->StaCfg.DLSEntry[i].Sequence = 0; - if (HtCapabilityLen != 0) - pAd->StaCfg.DLSEntry[i].bHTCap = TRUE; - else - pAd->StaCfg.DLSEntry[i].bHTCap = FALSE; - } - else - { - // DLS setup procedure failed. - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - pAd->StaCfg.DLSEntry[i].Valid = FALSE; - RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); - DBGPRINT(RT_DEBUG_ERROR,("DLS - PeerDlsRspAction failed with StatusCode=%d \n", StatusCode)); - } - } - } - - if (i >= MAX_NUM_OF_INIT_DLS_ENTRY) - { - DBGPRINT(RT_DEBUG_TRACE,("DLS - PeerDlsRspAction() update timeout value \n")); - for (i=(MAX_NUM_OF_DLS_ENTRY-1); i>=MAX_NUM_OF_INIT_DLS_ENTRY; i--) - { - if (pAd->StaCfg.DLSEntry[i].Valid && MAC_ADDR_EQUAL(SA, pAd->StaCfg.DLSEntry[i].MacAddr)) - { - if (StatusCode == MLME_SUCCESS) - { - MAC_TABLE_ENTRY *pEntry; - UCHAR MaxSupportedRate = RATE_11; - - pEntry = MacTableInsertDlsEntry(pAd, SA, i); - - switch (MaxSupportedRateIn500Kbps) - { - case 108: MaxSupportedRate = RATE_54; break; - case 96: MaxSupportedRate = RATE_48; break; - case 72: MaxSupportedRate = RATE_36; break; - case 48: MaxSupportedRate = RATE_24; break; - case 36: MaxSupportedRate = RATE_18; break; - case 24: MaxSupportedRate = RATE_12; break; - case 18: MaxSupportedRate = RATE_9; break; - case 12: MaxSupportedRate = RATE_6; break; - case 22: MaxSupportedRate = RATE_11; break; - case 11: MaxSupportedRate = RATE_5_5; break; - case 4: MaxSupportedRate = RATE_2; break; - case 2: MaxSupportedRate = RATE_1; break; - default: MaxSupportedRate = RATE_11; break; - } - - pEntry->MaxSupportedRate = min(pAd->CommonCfg.MaxTxRate, MaxSupportedRate); - - if (pEntry->MaxSupportedRate < RATE_FIRST_OFDM_RATE) - { - pEntry->MaxHTPhyMode.field.MODE = MODE_CCK; - pEntry->MaxHTPhyMode.field.MCS = pEntry->MaxSupportedRate; - pEntry->MinHTPhyMode.field.MODE = MODE_CCK; - pEntry->MinHTPhyMode.field.MCS = pEntry->MaxSupportedRate; - pEntry->HTPhyMode.field.MODE = MODE_CCK; - pEntry->HTPhyMode.field.MCS = pEntry->MaxSupportedRate; - } - else - { - pEntry->MaxHTPhyMode.field.MODE = MODE_OFDM; - pEntry->MaxHTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; - pEntry->MinHTPhyMode.field.MODE = MODE_OFDM; - pEntry->MinHTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; - pEntry->HTPhyMode.field.MODE = MODE_OFDM; - pEntry->HTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; - } - - pEntry->MaxHTPhyMode.field.BW = BW_20; - pEntry->MinHTPhyMode.field.BW = BW_20; - -#ifdef DOT11_N_SUPPORT - pEntry->HTCapability.MCSSet[0] = 0; - pEntry->HTCapability.MCSSet[1] = 0; - - // If this Entry supports 802.11n, upgrade to HT rate. - if ((HtCapabilityLen != 0) && (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) - { - UCHAR j, bitmask; //k,bitmask; - CHAR ii; - - DBGPRINT(RT_DEBUG_OFF, ("DLS - PeerDlsRspAction Receive Peer HT Capable STA from %02x:%02x:%02x:%02x:%02x:%02x\n", - SA[0], SA[1], SA[2], SA[3], SA[4], SA[5])); - - if ((HtCapability.HtCapInfo.GF) && (pAd->CommonCfg.DesiredHtPhy.GF)) - { - pEntry->MaxHTPhyMode.field.MODE = MODE_HTGREENFIELD; - } - else - { - pEntry->MaxHTPhyMode.field.MODE = MODE_HTMIX; - pAd->MacTab.fAnyStationNonGF = TRUE; - pAd->CommonCfg.AddHTInfo.AddHtInfo2.NonGfPresent = 1; - } - - if ((HtCapability.HtCapInfo.ChannelWidth) && (pAd->CommonCfg.DesiredHtPhy.ChannelWidth)) - { - pEntry->MaxHTPhyMode.field.BW= BW_40; - pEntry->MaxHTPhyMode.field.ShortGI = ((pAd->CommonCfg.DesiredHtPhy.ShortGIfor40)&(HtCapability.HtCapInfo.ShortGIfor40)); - } - else - { - pEntry->MaxHTPhyMode.field.BW = BW_20; - pEntry->MaxHTPhyMode.field.ShortGI = ((pAd->CommonCfg.DesiredHtPhy.ShortGIfor20)&(HtCapability.HtCapInfo.ShortGIfor20)); - pAd->MacTab.fAnyStation20Only = TRUE; - } - - // find max fixed rate - for (ii=15; ii>=0; ii--) - { - j = ii/8; - bitmask = (1<<(ii-(j*8))); - if ( (pAd->StaCfg.DesiredHtPhyInfo.MCSSet[j]&bitmask) && (HtCapability.MCSSet[j]&bitmask)) - { - pEntry->MaxHTPhyMode.field.MCS = ii; - break; - } - if (ii==0) - break; - } - - if (pAd->StaCfg.DesiredTransmitSetting.field.MCS != MCS_AUTO) - { - printk("@@@ pAd->CommonCfg.RegTransmitSetting.field.MCS = %d\n", - pAd->StaCfg.DesiredTransmitSetting.field.MCS); - if (pAd->StaCfg.DesiredTransmitSetting.field.MCS == 32) - { - // Fix MCS as HT Duplicated Mode - pEntry->MaxHTPhyMode.field.BW = 1; - pEntry->MaxHTPhyMode.field.MODE = MODE_HTMIX; - pEntry->MaxHTPhyMode.field.STBC = 0; - pEntry->MaxHTPhyMode.field.ShortGI = 0; - pEntry->MaxHTPhyMode.field.MCS = 32; - } - else if (pEntry->MaxHTPhyMode.field.MCS > pAd->StaCfg.HTPhyMode.field.MCS) - { - // STA supports fixed MCS - pEntry->MaxHTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; - } - } - - pEntry->MaxHTPhyMode.field.STBC = (HtCapability.HtCapInfo.RxSTBC & (pAd->CommonCfg.DesiredHtPhy.TxSTBC)); - pEntry->MpduDensity = HtCapability.HtCapParm.MpduDensity; - pEntry->MaxRAmpduFactor = HtCapability.HtCapParm.MaxRAmpduFactor; - pEntry->MmpsMode = (UCHAR)HtCapability.HtCapInfo.MimoPs; - pEntry->AMsduSize = (UCHAR)HtCapability.HtCapInfo.AMsduSize; - pEntry->HTPhyMode.word = pEntry->MaxHTPhyMode.word; - - if (HtCapability.HtCapInfo.ShortGIfor20) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_SGI20_CAPABLE); - if (HtCapability.HtCapInfo.ShortGIfor40) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_SGI40_CAPABLE); - if (HtCapability.HtCapInfo.TxSTBC) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_TxSTBC_CAPABLE); - if (HtCapability.HtCapInfo.RxSTBC) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_RxSTBC_CAPABLE); - if (HtCapability.ExtHtCapInfo.PlusHTC) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_HTC_CAPABLE); - if (pAd->CommonCfg.bRdg && HtCapability.ExtHtCapInfo.RDGSupport) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_RDG_CAPABLE); - if (HtCapability.ExtHtCapInfo.MCSFeedback == 0x03) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_MCSFEEDBACK_CAPABLE); - - NdisMoveMemory(&pEntry->HTCapability, &HtCapability, sizeof(HT_CAPABILITY_IE)); - } -#endif // DOT11_N_SUPPORT // - - pEntry->HTPhyMode.word = pEntry->MaxHTPhyMode.word; - pEntry->CurrTxRate = pEntry->MaxSupportedRate; - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_WMM_CAPABLE); - - if (pAd->StaCfg.bAutoTxRateSwitch == TRUE) - { - PUCHAR pTable; - UCHAR TableSize = 0; - - MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize, &pEntry->CurrTxRateIndex); - pEntry->bAutoTxRateSwitch = TRUE; - } - else - { - pEntry->HTPhyMode.field.MODE = pAd->StaCfg.HTPhyMode.field.MODE; - pEntry->HTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; - pEntry->bAutoTxRateSwitch = FALSE; - - RTMPUpdateLegacyTxSetting((UCHAR)pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode, pEntry); - } - pEntry->RateLen = SupportedRatesLen; - - if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - { - // If support WPA or WPA2, start STAKey hand shake, - // If failed hand shake, just tear down peer DLS - if (RTMPSendSTAKeyRequest(pAd, pAd->StaCfg.DLSEntry[i].MacAddr) != NDIS_STATUS_SUCCESS) - { - MLME_DLS_REQ_STRUCT MlmeDlsReq; - USHORT reason = REASON_QOS_CIPHER_NOT_SUPPORT; - - DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); - MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_TEAR_DOWN, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - pAd->StaCfg.DLSEntry[i].Valid = FALSE; - DBGPRINT(RT_DEBUG_ERROR,("DLS - PeerDlsRspAction failed when call RTMPSendSTAKeyRequest \n")); - } - else - { - pAd->StaCfg.DLSEntry[i].Status = DLS_WAIT_KEY; - DBGPRINT(RT_DEBUG_TRACE,("DLS - waiting for STAKey handshake procedure\n")); - } - } - else - { - RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); - pAd->StaCfg.DLSEntry[i].Status = DLS_FINISH; - DBGPRINT(RT_DEBUG_TRACE,("DLS - PeerDlsRspAction() from %02x:%02x:%02x:%02x:%02x:%02x Succeed with WEP or no security\n", SA[0], SA[1], SA[2], SA[3], SA[4], SA[5])); - } - pAd->StaCfg.DLSEntry[i].Sequence = 0; - if (HtCapabilityLen != 0) - pAd->StaCfg.DLSEntry[i].bHTCap = TRUE; - else - pAd->StaCfg.DLSEntry[i].bHTCap = FALSE; - } - else - { - // DLS setup procedure failed. - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - pAd->StaCfg.DLSEntry[i].Valid = FALSE; - RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); - DBGPRINT(RT_DEBUG_ERROR,("DLS - PeerDlsRspAction failed with StatusCode=%d \n", StatusCode)); - } - } - } - } -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID MlmeDlsTearDownAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - PUCHAR pOutBuffer = NULL; - NDIS_STATUS NStatus; - ULONG FrameLen = 0; - UCHAR Category = CATEGORY_DLS; - UCHAR Action = ACTION_DLS_TEARDOWN; - USHORT ReasonCode = REASON_QOS_UNSPECIFY; - HEADER_802_11 DlsTearDownHdr; - PRT_802_11_DLS pDLS; - BOOLEAN TimerCancelled; - UCHAR i; - - if(!MlmeDlsReqSanity(pAd, Elem->Msg, Elem->MsgLen, &pDLS, &ReasonCode)) - return; - - DBGPRINT(RT_DEBUG_TRACE,("DLS - MlmeDlsTearDownAction() with ReasonCode=%d \n", ReasonCode)); - - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory - if (NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_ERROR,("DLS - MlmeDlsTearDownAction() allocate memory failed \n")); - return; - } - - ActHeaderInit(pAd, &DlsTearDownHdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pAd->CommonCfg.Bssid); - - // Build basic frame first - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(HEADER_802_11), &DlsTearDownHdr, - 1, &Category, - 1, &Action, - 6, &pDLS->MacAddr, - 6, pAd->CurrentAddress, - 2, &ReasonCode, - END_OF_ARGS); - - MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); - RTMPCancelTimer(&pDLS->Timer, &TimerCancelled); - - // Remove key in local dls table entry - for (i = 0; i < MAX_NUM_OF_INIT_DLS_ENTRY; i++) - { - if (MAC_ADDR_EQUAL(pDLS->MacAddr, pAd->StaCfg.DLSEntry[i].MacAddr)) - { - MacTableDeleteDlsEntry(pAd, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID, pAd->StaCfg.DLSEntry[i].MacAddr); - } - } - - // clear peer dls table entry - for (i = MAX_NUM_OF_INIT_DLS_ENTRY; i < MAX_NUM_OF_DLS_ENTRY; i++) - { - if (MAC_ADDR_EQUAL(pDLS->MacAddr, pAd->StaCfg.DLSEntry[i].MacAddr)) - { - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - pAd->StaCfg.DLSEntry[i].Valid = FALSE; - RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); - MacTableDeleteDlsEntry(pAd, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID, pAd->StaCfg.DLSEntry[i].MacAddr); - } - } -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID PeerDlsTearDownAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - UCHAR DA[MAC_ADDR_LEN], SA[MAC_ADDR_LEN]; - USHORT ReasonCode; - UINT i; - BOOLEAN TimerCancelled; - - if (!pAd->CommonCfg.bDLSCapable) - return; - - if (!INFRA_ON(pAd)) - return; - - if (!PeerDlsTearDownSanity(pAd, Elem->Msg, Elem->MsgLen, DA, SA, &ReasonCode)) - return; - - DBGPRINT(RT_DEBUG_TRACE,("DLS - PeerDlsTearDownAction() from %02x:%02x:%02x:%02x:%02x:%02x with ReasonCode=%d\n", SA[0], SA[1], SA[2], SA[3], SA[4], SA[5], ReasonCode)); - - // clear local dls table entry - for (i=0; iStaCfg.DLSEntry[i].Valid && MAC_ADDR_EQUAL(SA, pAd->StaCfg.DLSEntry[i].MacAddr)) - { - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - pAd->StaCfg.DLSEntry[i].Valid = FALSE; - RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); - //AsicDelWcidTab(pAd, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID); - //AsicRemovePairwiseKeyEntry(pAd, BSS0, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID); - MacTableDeleteDlsEntry(pAd, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID, pAd->StaCfg.DLSEntry[i].MacAddr); - } - } - - // clear peer dls table entry - for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid && MAC_ADDR_EQUAL(SA, pAd->StaCfg.DLSEntry[i].MacAddr)) - { - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - pAd->StaCfg.DLSEntry[i].Valid = FALSE; - RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); - //AsicDelWcidTab(pAd, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID); - //AsicRemovePairwiseKeyEntry(pAd, BSS0, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID); - MacTableDeleteDlsEntry(pAd, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID, pAd->StaCfg.DLSEntry[i].MacAddr); - } - } -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID RTMPCheckDLSTimeOut( - IN PRTMP_ADAPTER pAd) -{ - ULONG i; - MLME_DLS_REQ_STRUCT MlmeDlsReq; - USHORT reason = REASON_QOS_UNSPECIFY; - - if (! pAd->CommonCfg.bDLSCapable) - return; - - if (! INFRA_ON(pAd)) - return; - - // If timeout value is equaled to zero, it means always not be timeout. - - // update local dls table entry - for (i=0; iStaCfg.DLSEntry[i].Valid) && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) - && (pAd->StaCfg.DLSEntry[i].TimeOut != 0)) - { - pAd->StaCfg.DLSEntry[i].CountDownTimer --; - - if (pAd->StaCfg.DLSEntry[i].CountDownTimer == 0) - { - reason = REASON_QOS_REQUEST_TIMEOUT; - pAd->StaCfg.DLSEntry[i].Valid = FALSE; - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); - MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_TEAR_DOWN, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); - } - } - } - - // update peer dls table entry - for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid) && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) - && (pAd->StaCfg.DLSEntry[i].TimeOut != 0)) - { - pAd->StaCfg.DLSEntry[i].CountDownTimer --; - - if (pAd->StaCfg.DLSEntry[i].CountDownTimer == 0) - { - reason = REASON_QOS_REQUEST_TIMEOUT; - pAd->StaCfg.DLSEntry[i].Valid = FALSE; - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); - MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_TEAR_DOWN, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); - } - } - } -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -BOOLEAN RTMPRcvFrameDLSCheck( - IN PRTMP_ADAPTER pAd, - IN PHEADER_802_11 pHeader, - IN ULONG Len, - IN PRT28XX_RXD_STRUC pRxD) -{ - ULONG i; - BOOLEAN bFindEntry = FALSE; - BOOLEAN bSTAKeyFrame = FALSE; - PEAPOL_PACKET pEap; - PUCHAR pProto, pAddr = NULL; - PUCHAR pSTAKey = NULL; - UCHAR ZeroReplay[LEN_KEY_DESC_REPLAY]; - UCHAR Mic[16], OldMic[16]; - UCHAR digest[80]; - UCHAR DlsPTK[80]; - UCHAR temp[64]; - BOOLEAN TimerCancelled; - CIPHER_KEY PairwiseKey; - - - if (! pAd->CommonCfg.bDLSCapable) - return bSTAKeyFrame; - - if (! INFRA_ON(pAd)) - return bSTAKeyFrame; - - if (! (pHeader->FC.SubType & 0x08)) - return bSTAKeyFrame; - - if (Len < LENGTH_802_11 + 6 + 2 + 2) - return bSTAKeyFrame; - - pProto = (PUCHAR)pHeader + LENGTH_802_11 + 2 + 6; // QOS Control field , 0xAA 0xAA 0xAA 0x00 0x00 0x00 - pAddr = pHeader->Addr2; - - // L2PAD bit on will pad 2 bytes at LLC - if (pRxD->L2PAD) - { - pProto += 2; - } - - if (RTMPEqualMemory(EAPOL, pProto, 2) && (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA)) - { - pEap = (PEAPOL_PACKET) (pProto + 2); - - DBGPRINT(RT_DEBUG_TRACE,("DLS - Sniff Len=%ld, DataLen=%d, KeyMic=%d, Install=%d, KeyAck=%d, Secure=%d, EKD_DL=%d, Error=%d, Request=%d\n", Len, - (LENGTH_802_11 + 6 + 2 + 2 + sizeof(EAPOL_PACKET) - MAX_LEN_OF_RSNIE + 16), - pEap->KeyDesc.KeyInfo.KeyMic, - pEap->KeyDesc.KeyInfo.Install, - pEap->KeyDesc.KeyInfo.KeyAck, - pEap->KeyDesc.KeyInfo.Secure, - pEap->KeyDesc.KeyInfo.EKD_DL, - pEap->KeyDesc.KeyInfo.Error, - pEap->KeyDesc.KeyInfo.Request)); - - if ((Len >= (LENGTH_802_11 + 6 + 2 + 2 + sizeof(EAPOL_PACKET) - MAX_LEN_OF_RSNIE + 16)) && pEap->KeyDesc.KeyInfo.KeyMic - && pEap->KeyDesc.KeyInfo.Install && pEap->KeyDesc.KeyInfo.KeyAck && pEap->KeyDesc.KeyInfo.Secure - && pEap->KeyDesc.KeyInfo.EKD_DL && !pEap->KeyDesc.KeyInfo.Error && !pEap->KeyDesc.KeyInfo.Request) - { - // First validate replay counter, only accept message with larger replay counter - // Let equal pass, some AP start with all zero replay counter - NdisZeroMemory(ZeroReplay, LEN_KEY_DESC_REPLAY); - if ((RTMPCompareMemory(pEap->KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY) != 1) && - (RTMPCompareMemory(pEap->KeyDesc.ReplayCounter, ZeroReplay, LEN_KEY_DESC_REPLAY) != 0)) - return bSTAKeyFrame; - - //RTMPMoveMemory(pAd->StaCfg.ReplayCounter, pEap->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); - RTMPMoveMemory(pAd->StaCfg.DlsReplayCounter, pEap->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); - DBGPRINT(RT_DEBUG_TRACE,("DLS - Sniff replay counter (%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x) Len=%ld, KeyDataLen=%d\n", - pAd->StaCfg.ReplayCounter[0], pAd->StaCfg.ReplayCounter[1], pAd->StaCfg.ReplayCounter[2], - pAd->StaCfg.ReplayCounter[3], pAd->StaCfg.ReplayCounter[4], pAd->StaCfg.ReplayCounter[5], - pAd->StaCfg.ReplayCounter[6], pAd->StaCfg.ReplayCounter[7], Len, pEap->KeyDesc.KeyData[1])); - - // put these code segment to get the replay counter - if (pAd->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED) - return bSTAKeyFrame; - - // Check MIC value - // Save the MIC and replace with zero - // use proprietary PTK - NdisZeroMemory(temp, 64); - NdisMoveMemory(temp, "IEEE802.11 WIRELESS ACCESS POINT", 32); - WpaCountPTK(pAd, temp, temp, pAd->CommonCfg.Bssid, temp, pAd->CurrentAddress, DlsPTK, LEN_PTK); - - NdisMoveMemory(OldMic, pEap->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); - NdisZeroMemory(pEap->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); - if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) - { - // AES - HMAC_SHA1((PUCHAR) pEap, pEap->Body_Len[1] + 4, DlsPTK, LEN_EAP_MICK, digest); - NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); - } - else - { - hmac_md5(DlsPTK, LEN_EAP_MICK, (PUCHAR) pEap, pEap->Body_Len[1] + 4, Mic); - } - - if (!NdisEqualMemory(OldMic, Mic, LEN_KEY_DESC_MIC)) - { - DBGPRINT(RT_DEBUG_ERROR, ("MIC Different in Msg1 of STAKey handshake! \n")); - return bSTAKeyFrame; - } - else - DBGPRINT(RT_DEBUG_TRACE, ("MIC VALID in Msg1 of STAKey handshake! \n")); -#if 1 - if ((pEap->KeyDesc.KeyData[0] == 0xDD) && (pEap->KeyDesc.KeyData[2] == 0x00) && (pEap->KeyDesc.KeyData[3] == 0x0C) - && (pEap->KeyDesc.KeyData[4] == 0x43) && (pEap->KeyDesc.KeyData[5] == 0x02)) - { - pAddr = pEap->KeyDesc.KeyData + 8; // Tpe(1), Len(1), OUI(3), DataType(1), Reserved(2) - pSTAKey = pEap->KeyDesc.KeyData + 14; // Tpe(1), Len(1), OUI(3), DataType(1), Reserved(2), STAKey_Mac_Addr(6) - - DBGPRINT(RT_DEBUG_TRACE,("DLS - Receive STAKey Message-1 from %02x:%02x:%02x:%02x:%02x:%02x Len=%ld, KeyDataLen=%d\n", - pAddr[0], pAddr[1], pAddr[2], pAddr[3], pAddr[4], pAddr[5], Len, pEap->KeyDesc.KeyData[1])); - - bSTAKeyFrame = TRUE; - } -#else - if ((pEap->KeyDesc.KeyData[0] == 0xDD) && (pEap->KeyDesc.KeyData[2] == 0x00) && (pEap->KeyDesc.KeyData[3] == 0x0F) - && (pEap->KeyDesc.KeyData[4] == 0xAC) && (pEap->KeyDesc.KeyData[5] == 0x02)) - { - pAddr = pEap->KeyDesc.KeyData + 8; // Tpe(1), Len(1), OUI(3), DataType(1), Reserved(2) - pSTAKey = pEap->KeyDesc.KeyData + 14; // Tpe(1), Len(1), OUI(3), DataType(1), Reserved(2), STAKey_Mac_Addr(6) - - DBGPRINT(RT_DEBUG_TRACE,("DLS - Receive STAKey Message-1 from %02x:%02x:%02x:%02x:%02x:%02x Len=%d, KeyDataLen=%d\n", - pAddr[0], pAddr[1], pAddr[2], pAddr[3], pAddr[4], pAddr[5], Len, pEap->KeyDesc.KeyData[1])); - - bSTAKeyFrame = TRUE; - } -#endif - - } - else if (Len >= (LENGTH_802_11 + 6 + 2 + 2 + sizeof(EAPOL_PACKET) - MAX_LEN_OF_RSNIE)) - { -#if 0 - RTMPMoveMemory(pAd->StaCfg.ReplayCounter, pEap->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); - -#endif - RTMPMoveMemory(pAd->StaCfg.DlsReplayCounter, pEap->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); - DBGPRINT(RT_DEBUG_TRACE,("DLS - Sniff replay counter 2(%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x) Len=%ld, KeyDataLen=%d\n", - pAd->StaCfg.ReplayCounter[0], pAd->StaCfg.ReplayCounter[1], pAd->StaCfg.ReplayCounter[2], - pAd->StaCfg.ReplayCounter[3], pAd->StaCfg.ReplayCounter[4], pAd->StaCfg.ReplayCounter[5], - pAd->StaCfg.ReplayCounter[6], pAd->StaCfg.ReplayCounter[7], Len, pEap->KeyDesc.KeyData[1])); - - } - } - - // If timeout value is equaled to zero, it means always not be timeout. - // update local dls table entry - for (i= 0; i < MAX_NUM_OF_INIT_DLS_ENTRY; i++) - { - if (pAd->StaCfg.DLSEntry[i].Valid && MAC_ADDR_EQUAL(pAddr, pAd->StaCfg.DLSEntry[i].MacAddr)) - { - if (bSTAKeyFrame) - { - PMAC_TABLE_ENTRY pEntry; - - // STAKey frame, add pairwise key table - pAd->StaCfg.DLSEntry[i].Status = DLS_FINISH; - RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); - - PairwiseKey.KeyLen = LEN_TKIP_EK; - NdisMoveMemory(PairwiseKey.Key, &pSTAKey[0], LEN_TKIP_EK); - NdisMoveMemory(PairwiseKey.TxMic, &pSTAKey[16], LEN_TKIP_RXMICK); - NdisMoveMemory(PairwiseKey.RxMic, &pSTAKey[24], LEN_TKIP_TXMICK); - - PairwiseKey.CipherAlg = pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg; - - pEntry = DlsEntryTableLookup(pAd, pAd->StaCfg.DLSEntry[i].MacAddr, TRUE); - //AsicAddKeyEntry(pAd, (USHORT)(i + 2), BSS0, 0, &PairwiseKey, TRUE, TRUE); // reserve 0 for multicast, 1 for unicast - //AsicUpdateRxWCIDTable(pAd, (USHORT)(i + 2), pAddr); - // Add Pair-wise key to Asic - AsicAddPairwiseKeyEntry(pAd, - pAd->StaCfg.DLSEntry[i].MacAddr, - (UCHAR)pAd->StaCfg.DLSEntry[i].MacTabMatchWCID, - &PairwiseKey); - - RTMPAddWcidAttributeEntry(pAd, - BSS0, - 0, - PairwiseKey.CipherAlg, - pEntry); - - NdisMoveMemory(&pEntry->PairwiseKey, &PairwiseKey, sizeof(CIPHER_KEY)); - DBGPRINT(RT_DEBUG_TRACE,("DLS - Receive STAKey Message-1 (Peer STA MAC Address STAKey) \n")); - - RTMPSendSTAKeyHandShake(pAd, pAd->StaCfg.DLSEntry[i].MacAddr); - - DBGPRINT(RT_DEBUG_TRACE,("DLS - Finish STAKey handshake procedure (Initiator side)\n")); - } - else - { - // Data frame, update timeout value - if (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) - { - pAd->StaCfg.DLSEntry[i].CountDownTimer = pAd->StaCfg.DLSEntry[i].TimeOut; - //AsicUpdateRxWCIDTable(pAd, (USHORT)(i + 2), pAddr); - } - } - - bFindEntry = TRUE; - } - } - - // update peer dls table entry - for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid && MAC_ADDR_EQUAL(pAddr, pAd->StaCfg.DLSEntry[i].MacAddr)) - { - if (bSTAKeyFrame) - { - PMAC_TABLE_ENTRY pEntry = NULL; - - // STAKey frame, add pairwise key table, and send STAkey Msg-2 - pAd->StaCfg.DLSEntry[i].Status = DLS_FINISH; - RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); - - PairwiseKey.KeyLen = LEN_TKIP_EK; - NdisMoveMemory(PairwiseKey.Key, &pSTAKey[0], LEN_TKIP_EK); - NdisMoveMemory(PairwiseKey.TxMic, &pSTAKey[16], LEN_TKIP_RXMICK); - NdisMoveMemory(PairwiseKey.RxMic, &pSTAKey[24], LEN_TKIP_TXMICK); - - PairwiseKey.CipherAlg = pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg; - - pEntry = DlsEntryTableLookup(pAd, pAd->StaCfg.DLSEntry[i].MacAddr, TRUE); - //AsicAddKeyEntry(pAd, (USHORT)(i + 2), BSS0, 0, &PairwiseKey, TRUE, TRUE); // reserve 0 for multicast, 1 for unicast - //AsicUpdateRxWCIDTable(pAd, (USHORT)(i + 2), pAddr); - // Add Pair-wise key to Asic - AsicAddPairwiseKeyEntry(pAd, - pAd->StaCfg.DLSEntry[i].MacAddr, - (UCHAR)pAd->StaCfg.DLSEntry[i].MacTabMatchWCID, - &PairwiseKey); - - RTMPAddWcidAttributeEntry(pAd, - BSS0, - 0, - PairwiseKey.CipherAlg, - pEntry); - NdisMoveMemory(&pEntry->PairwiseKey, &PairwiseKey, sizeof(CIPHER_KEY)); - DBGPRINT(RT_DEBUG_TRACE,("DLS - Receive STAKey Message-1 (Initiator STA MAC Address STAKey)\n")); - - // If support WPA or WPA2, start STAKey hand shake, - // If failed hand shake, just tear down peer DLS - if (RTMPSendSTAKeyHandShake(pAd, pAddr) != NDIS_STATUS_SUCCESS) - { - MLME_DLS_REQ_STRUCT MlmeDlsReq; - USHORT reason = REASON_QOS_CIPHER_NOT_SUPPORT; - - pAd->StaCfg.DLSEntry[i].Valid = FALSE; - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); - MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_TEAR_DOWN, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); - } - else - { - DBGPRINT(RT_DEBUG_TRACE,("DLS - Finish STAKey handshake procedure (Peer side)\n")); - } - } - else - { - // Data frame, update timeout value - if (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) - { - pAd->StaCfg.DLSEntry[i].CountDownTimer = pAd->StaCfg.DLSEntry[i].TimeOut; - } - } - - bFindEntry = TRUE; - } - } - - - return bSTAKeyFrame; -} - -/* - ======================================================================== - - Routine Description: - Check if the frame can be sent through DLS direct link interface - - Arguments: - pAd Pointer to adapter - - Return Value: - DLS entry index - - Note: - - ======================================================================== -*/ -INT RTMPCheckDLSFrame( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDA) -{ - INT rval = -1; - INT i; - - if (!pAd->CommonCfg.bDLSCapable) - return rval; - - if (!INFRA_ON(pAd)) - return rval; - - do{ - // check local dls table entry - for (i=0; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) && - MAC_ADDR_EQUAL(pDA, pAd->StaCfg.DLSEntry[i].MacAddr)) - { - rval = i; - break; - } - } - - // check peer dls table entry - for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) && - MAC_ADDR_EQUAL(pDA, pAd->StaCfg.DLSEntry[i].MacAddr)) - { - rval = i; - break; - } - } - } while (FALSE); - - return rval; -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID RTMPSendDLSTearDownFrame( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDA) -{ - PUCHAR pOutBuffer = NULL; - NDIS_STATUS NStatus; - HEADER_802_11 DlsTearDownHdr; - ULONG FrameLen = 0; - USHORT Reason = REASON_QOS_QSTA_LEAVING_QBSS; - UCHAR Category = CATEGORY_DLS; - UCHAR Action = ACTION_DLS_TEARDOWN; - UCHAR i = 0; - - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS) || - RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) - return; - - DBGPRINT(RT_DEBUG_TRACE, ("Send DLS TearDown Frame \n")); - - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory - if (NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_ERROR,("ASSOC - RTMPSendDLSTearDownFrame() allocate memory failed \n")); - return; - } - - ActHeaderInit(pAd, &DlsTearDownHdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pAd->CommonCfg.Bssid); - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(HEADER_802_11), &DlsTearDownHdr, - 1, &Category, - 1, &Action, - 6, pDA, - 6, pAd->CurrentAddress, - 2, &Reason, - END_OF_ARGS); - - MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); - - // Remove key in local dls table entry - for (i = 0; i < MAX_NUM_OF_INIT_DLS_ENTRY; i++) - { - if (pAd->StaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) - && MAC_ADDR_EQUAL(pDA, pAd->StaCfg.DLSEntry[i].MacAddr)) - { - MacTableDeleteDlsEntry(pAd, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID, pAd->StaCfg.DLSEntry[i].MacAddr); - } - } - - // Remove key in peer dls table entry - for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) - && MAC_ADDR_EQUAL(pDA, pAd->StaCfg.DLSEntry[i].MacAddr)) - { - MacTableDeleteDlsEntry(pAd, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID, pAd->StaCfg.DLSEntry[i].MacAddr); - } - } - - DBGPRINT(RT_DEBUG_TRACE, ("Send DLS TearDown Frame and remove key in (i=%d) \n", i)); -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -NDIS_STATUS RTMPSendSTAKeyRequest( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDA) -{ - UCHAR Header802_3[14]; - NDIS_STATUS NStatus; - ULONG FrameLen = 0; - EAPOL_PACKET Packet; - UCHAR Mic[16]; - UCHAR digest[80]; - PUCHAR pOutBuffer = NULL; - PNDIS_PACKET pNdisPacket; - UCHAR temp[64]; - UCHAR DlsPTK[80]; - - DBGPRINT(RT_DEBUG_TRACE,("DLS - RTMPSendSTAKeyRequest() to %02x:%02x:%02x:%02x:%02x:%02x\n", pDA[0], pDA[1], pDA[2], pDA[3], pDA[4], pDA[5])); - - pAd->Sequence ++; - MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL); - - // Zero message body - NdisZeroMemory(&Packet, sizeof(Packet)); - Packet.ProVer = EAPOL_VER; - Packet.ProType = EAPOLKey; - Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE + 6 + MAC_ADDR_LEN; // data field contain KDE andPeer MAC address - - // STAKey Message is as EAPOL-Key(1,1,0,0,G/0,0,0, MIC, 0,Peer MAC KDE) - if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) - { - Packet.KeyDesc.Type = WPA1_KEY_DESC; - } - else if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)) - { - Packet.KeyDesc.Type = WPA2_KEY_DESC; - } - - // Key descriptor version - Packet.KeyDesc.KeyInfo.KeyDescVer = - (((pAd->StaCfg.PairCipher == Ndis802_11Encryption3Enabled) || (pAd->StaCfg.GroupCipher == Ndis802_11Encryption3Enabled)) ? (DESC_TYPE_AES) : (DESC_TYPE_TKIP)); - - Packet.KeyDesc.KeyInfo.KeyMic = 1; - Packet.KeyDesc.KeyInfo.Secure = 1; - Packet.KeyDesc.KeyInfo.Request = 1; - - Packet.KeyDesc.KeyDataLen[1] = 12; - - // use our own OUI to distinguish proprietary with standard. - Packet.KeyDesc.KeyData[0] = 0xDD; - Packet.KeyDesc.KeyData[1] = 0x0A; - Packet.KeyDesc.KeyData[2] = 0x00; - Packet.KeyDesc.KeyData[3] = 0x0C; - Packet.KeyDesc.KeyData[4] = 0x43; - Packet.KeyDesc.KeyData[5] = 0x03; - NdisMoveMemory(&Packet.KeyDesc.KeyData[6], pDA, MAC_ADDR_LEN); - - NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pAd->StaCfg.DlsReplayCounter, LEN_KEY_DESC_REPLAY); - - // Allocate buffer for transmitting message - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); - if (NStatus != NDIS_STATUS_SUCCESS) - return NStatus; - - // Prepare EAPOL frame for MIC calculation - // Be careful, only EAPOL frame is counted for MIC calculation - MakeOutgoingFrame(pOutBuffer, &FrameLen, - Packet.Body_Len[1] + 4, &Packet, - END_OF_ARGS); - - // use proprietary PTK - NdisZeroMemory(temp, 64); - NdisMoveMemory(temp, "IEEE802.11 WIRELESS ACCESS POINT", 32); - WpaCountPTK(pAd, temp, temp, pAd->CommonCfg.Bssid, temp, pAd->CurrentAddress, DlsPTK, LEN_PTK); - - // calculate MIC - if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) - { - // AES - NdisZeroMemory(digest, sizeof(digest)); - HMAC_SHA1(pOutBuffer, FrameLen, DlsPTK, LEN_EAP_MICK, digest); - NdisMoveMemory(Packet.KeyDesc.KeyMic, digest, LEN_KEY_DESC_MIC); - } - else - { - NdisZeroMemory(Mic, sizeof(Mic)); - hmac_md5(DlsPTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic); - NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC); - } - - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(Header802_3), Header802_3, - Packet.Body_Len[1] + 4, &Packet, - END_OF_ARGS); - - NStatus = RTMPAllocateNdisPacket(pAd, &pNdisPacket, NULL, 0, pOutBuffer, FrameLen); - if (NStatus == NDIS_STATUS_SUCCESS) - { - RTMP_SET_PACKET_WCID(pNdisPacket, BSSID_WCID); - STASendPacket(pAd, pNdisPacket); - RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, MAX_TX_PROCESS); - } - - MlmeFreeMemory(pAd, pOutBuffer); - - DBGPRINT(RT_DEBUG_TRACE, ("RTMPSendSTAKeyRequest- Send STAKey request (NStatus=%x, FrameLen=%ld)\n", NStatus, FrameLen)); - - return NStatus; -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -NDIS_STATUS RTMPSendSTAKeyHandShake( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDA) -{ - UCHAR Header802_3[14]; - NDIS_STATUS NStatus; - ULONG FrameLen = 0; - EAPOL_PACKET Packet; - UCHAR Mic[16]; - UCHAR digest[80]; - PUCHAR pOutBuffer = NULL; - PNDIS_PACKET pNdisPacket; - UCHAR temp[64]; - UCHAR DlsPTK[80]; // Due to dirver can not get PTK, use proprietary PTK - - DBGPRINT(RT_DEBUG_TRACE,("DLS - RTMPSendSTAKeyHandShake() to %02x:%02x:%02x:%02x:%02x:%02x\n", pDA[0], pDA[1], pDA[2], pDA[3], pDA[4], pDA[5])); - - pAd->Sequence ++; - MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL); - - // Zero message body - NdisZeroMemory(&Packet, sizeof(Packet)); - Packet.ProVer = EAPOL_VER; - Packet.ProType = EAPOLKey; - Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE + 6 + MAC_ADDR_LEN; // data field contain KDE and Peer MAC address - - // STAKey Message is as EAPOL-Key(1,1,0,0,G/0,0,0, MIC, 0,Peer MAC KDE) - if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) - { - Packet.KeyDesc.Type = WPA1_KEY_DESC; - } - else if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)) - { - Packet.KeyDesc.Type = WPA2_KEY_DESC; - } - - // Key descriptor version - Packet.KeyDesc.KeyInfo.KeyDescVer = - (((pAd->StaCfg.PairCipher == Ndis802_11Encryption3Enabled) || (pAd->StaCfg.GroupCipher == Ndis802_11Encryption3Enabled)) ? (DESC_TYPE_AES) : (DESC_TYPE_TKIP)); - - Packet.KeyDesc.KeyInfo.KeyMic = 1; - Packet.KeyDesc.KeyInfo.Secure = 1; - - Packet.KeyDesc.KeyDataLen[1] = 12; - - // use our own OUI to distinguish proprietary with standard. - Packet.KeyDesc.KeyData[0] = 0xDD; - Packet.KeyDesc.KeyData[1] = 0x0A; - Packet.KeyDesc.KeyData[2] = 0x00; - Packet.KeyDesc.KeyData[3] = 0x0C; - Packet.KeyDesc.KeyData[4] = 0x43; - Packet.KeyDesc.KeyData[5] = 0x03; - NdisMoveMemory(&Packet.KeyDesc.KeyData[6], pDA, MAC_ADDR_LEN); - - NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pAd->StaCfg.DlsReplayCounter, LEN_KEY_DESC_REPLAY); - - // Allocate buffer for transmitting message - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); - if (NStatus != NDIS_STATUS_SUCCESS) - return NStatus; - - // Prepare EAPOL frame for MIC calculation - // Be careful, only EAPOL frame is counted for MIC calculation - MakeOutgoingFrame(pOutBuffer, &FrameLen, - Packet.Body_Len[1] + 4, &Packet, - END_OF_ARGS); - - // use proprietary PTK - NdisZeroMemory(temp, 64); - NdisMoveMemory(temp, "IEEE802.11 WIRELESS ACCESS POINT", 32); - WpaCountPTK(pAd, temp, temp, pAd->CommonCfg.Bssid, temp, pAd->CurrentAddress, DlsPTK, LEN_PTK); - - // calculate MIC - if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) - { - // AES - NdisZeroMemory(digest, sizeof(digest)); - HMAC_SHA1(pOutBuffer, FrameLen, DlsPTK, LEN_EAP_MICK, digest); - NdisMoveMemory(Packet.KeyDesc.KeyMic, digest, LEN_KEY_DESC_MIC); - } - else - { - NdisZeroMemory(Mic, sizeof(Mic)); - hmac_md5(DlsPTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic); - NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC); - } - - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(Header802_3), Header802_3, - Packet.Body_Len[1] + 4, &Packet, - END_OF_ARGS); - - NStatus = RTMPAllocateNdisPacket(pAd, &pNdisPacket, NULL, 0, pOutBuffer, FrameLen); - if (NStatus == NDIS_STATUS_SUCCESS) - { - RTMP_SET_PACKET_WCID(pNdisPacket, BSSID_WCID); - STASendPacket(pAd, pNdisPacket); - RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, MAX_TX_PROCESS); - } - - MlmeFreeMemory(pAd, pOutBuffer); - - DBGPRINT(RT_DEBUG_TRACE, ("RTMPSendSTAKeyHandShake- Send STAKey Message-2 (NStatus=%x, FrameLen=%ld)\n", NStatus, FrameLen)); - - return NStatus; -} - -VOID DlsTimeoutAction( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3) -{ - MLME_DLS_REQ_STRUCT MlmeDlsReq; - USHORT reason; - PRT_802_11_DLS pDLS = (PRT_802_11_DLS)FunctionContext; - PRTMP_ADAPTER pAd = pDLS->pAd; - - DBGPRINT(RT_DEBUG_TRACE, ("DlsTimeout - Tear down DLS links (%02x:%02x:%02x:%02x:%02x:%02x)\n", - pDLS->MacAddr[0], pDLS->MacAddr[1], pDLS->MacAddr[2], pDLS->MacAddr[3], pDLS->MacAddr[4], pDLS->MacAddr[5])); - - if ((pDLS) && (pDLS->Valid)) - { - reason = REASON_QOS_REQUEST_TIMEOUT; - pDLS->Valid = FALSE; - pDLS->Status = DLS_NONE; - DlsParmFill(pAd, &MlmeDlsReq, pDLS, reason); - MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_TEAR_DOWN, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); - RT28XX_MLME_HANDLER(pAd); - } -} - -/* -================================================================ -Description : because DLS and CLI share the same WCID table in ASIC. -Mesh entry also insert to pAd->MacTab.content[]. Such is marked as ValidAsDls = TRUE. -Also fills the pairwise key. -Because front MAX_AID_BA entries have direct mapping to BAEntry, which is only used as CLI. So we insert Dls -from index MAX_AID_BA. -================================================================ -*/ -MAC_TABLE_ENTRY *MacTableInsertDlsEntry( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pAddr, - IN UINT DlsEntryIdx) -{ - PMAC_TABLE_ENTRY pEntry = NULL; - - DBGPRINT(RT_DEBUG_TRACE, ("====> MacTableInsertDlsEntry\n")); - // if FULL, return - if (pAd->MacTab.Size >= MAX_LEN_OF_MAC_TABLE) - return NULL; - - do - { - if((pEntry = DlsEntryTableLookup(pAd, pAddr, TRUE)) != NULL) - break; - - // allocate one MAC entry - pEntry = MacTableInsertEntry(pAd, pAddr, DlsEntryIdx + MIN_NET_DEVICE_FOR_DLS, TRUE); - if (pEntry) - { - pAd->StaCfg.DLSEntry[DlsEntryIdx].MacTabMatchWCID = pEntry->Aid; - pEntry->MatchDlsEntryIdx = DlsEntryIdx; - pEntry->AuthMode = pAd->StaCfg.AuthMode; - pEntry->WepStatus = pAd->StaCfg.WepStatus; - pEntry->PortSecured = WPA_802_1X_PORT_SECURED; - - DBGPRINT(RT_DEBUG_TRACE, ("MacTableInsertDlsEntry - allocate entry #%d, Total= %d\n",pEntry->Aid, pAd->MacTab.Size)); - - // If legacy WEP is used, set pair-wise cipherAlg into WCID attribute table for this entry - if ((pEntry->ValidAsDls) && (pEntry->WepStatus == Ndis802_11WEPEnabled)) - { - UCHAR KeyIdx = 0; - UCHAR CipherAlg = 0; - - KeyIdx = pAd->StaCfg.DefaultKeyId; - - CipherAlg = pAd->SharedKey[BSS0][KeyIdx].CipherAlg; - - RTMPAddWcidAttributeEntry(pAd, - BSS0, - pAd->StaCfg.DefaultKeyId, - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, - pEntry); - } - - break; - } - } while(FALSE); - - DBGPRINT(RT_DEBUG_TRACE, ("<==== MacTableInsertDlsEntry\n")); - - return pEntry; -} - - -/* - ========================================================================== - Description: - Delete all Mesh Entry in pAd->MacTab - ========================================================================== - */ -BOOLEAN MacTableDeleteDlsEntry( - IN PRTMP_ADAPTER pAd, - IN USHORT wcid, - IN PUCHAR pAddr) -{ - DBGPRINT(RT_DEBUG_TRACE, ("====> MacTableDeleteDlsEntry\n")); - - if (!VALID_WCID(wcid)) - return FALSE; - - MacTableDeleteEntry(pAd, wcid, pAddr); - - DBGPRINT(RT_DEBUG_TRACE, ("<==== MacTableDeleteDlsEntry\n")); - - return TRUE; -} - -MAC_TABLE_ENTRY *DlsEntryTableLookup( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pAddr, - IN BOOLEAN bResetIdelCount) -{ - ULONG HashIdx; - MAC_TABLE_ENTRY *pEntry = NULL; - - RTMP_SEM_LOCK(&pAd->MacTabLock); - HashIdx = MAC_ADDR_HASH_INDEX(pAddr); - pEntry = pAd->MacTab.Hash[HashIdx]; - - while (pEntry) - { - if ((pEntry->ValidAsDls == TRUE) - && MAC_ADDR_EQUAL(pEntry->Addr, pAddr)) - { - if(bResetIdelCount) - pEntry->NoDataIdleCount = 0; - break; - } - else - pEntry = pEntry->pNext; - } - - RTMP_SEM_UNLOCK(&pAd->MacTabLock); - return pEntry; -} - -MAC_TABLE_ENTRY *DlsEntryTableLookupByWcid( - IN PRTMP_ADAPTER pAd, - IN UCHAR wcid, - IN PUCHAR pAddr, - IN BOOLEAN bResetIdelCount) -{ - ULONG DLsIndex; - PMAC_TABLE_ENTRY pCurEntry = NULL; - PMAC_TABLE_ENTRY pEntry = NULL; - - if (!VALID_WCID(wcid)) - return NULL; - - RTMP_SEM_LOCK(&pAd->MacTabLock); - - do - { - pCurEntry = &pAd->MacTab.Content[wcid]; - - DLsIndex = 0xff; - if ((pCurEntry) && (pCurEntry->ValidAsDls== TRUE)) - { - DLsIndex = pCurEntry->MatchDlsEntryIdx; - } - - if (DLsIndex == 0xff) - break; - - if (MAC_ADDR_EQUAL(pCurEntry->Addr, pAddr)) - { - if(bResetIdelCount) - pCurEntry->NoDataIdleCount = 0; - pEntry = pCurEntry; - break; - } - } while(FALSE); - - RTMP_SEM_UNLOCK(&pAd->MacTabLock); - - return pEntry; -} - -INT Set_DlsEntryInfo_Display_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - INT i; - - printk("\n%-19s%-8s\n", "MAC", "TIMEOUT\n"); - for (i=0; iStaCfg.DLSEntry[i].Valid) && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH)) - { - PMAC_TABLE_ENTRY pEntry = &pAd->MacTab.Content[pAd->StaCfg.DLSEntry[i].MacTabMatchWCID]; - - printk("%02x:%02x:%02x:%02x:%02x:%02x ", - pAd->StaCfg.DLSEntry[i].MacAddr[0], pAd->StaCfg.DLSEntry[i].MacAddr[1], pAd->StaCfg.DLSEntry[i].MacAddr[2], - pAd->StaCfg.DLSEntry[i].MacAddr[3], pAd->StaCfg.DLSEntry[i].MacAddr[4], pAd->StaCfg.DLSEntry[i].MacAddr[5]); - printk("%-8d\n", pAd->StaCfg.DLSEntry[i].TimeOut); - - printk("\n"); - printk("\n%-19s%-4s%-4s%-4s%-4s%-8s%-7s%-7s%-7s%-10s%-6s%-6s%-6s%-6s\n", - "MAC", "AID", "BSS", "PSM", "WMM", "MIMOPS", "RSSI0", "RSSI1", "RSSI2", "PhMd", "BW", "MCS", "SGI", "STBC"); - printk("%02X:%02X:%02X:%02X:%02X:%02X ", - pEntry->Addr[0], pEntry->Addr[1], pEntry->Addr[2], - pEntry->Addr[3], pEntry->Addr[4], pEntry->Addr[5]); - printk("%-4d", (int)pEntry->Aid); - printk("%-4d", (int)pEntry->apidx); - printk("%-4d", (int)pEntry->PsMode); - printk("%-4d", (int)CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_WMM_CAPABLE)); - printk("%-8d", (int)pEntry->MmpsMode); - printk("%-7d", pEntry->RssiSample.AvgRssi0); - printk("%-7d", pEntry->RssiSample.AvgRssi1); - printk("%-7d", pEntry->RssiSample.AvgRssi2); - printk("%-10s", GetPhyMode(pEntry->HTPhyMode.field.MODE)); - printk("%-6s", GetBW(pEntry->HTPhyMode.field.BW)); - printk("%-6d", pEntry->HTPhyMode.field.MCS); - printk("%-6d", pEntry->HTPhyMode.field.ShortGI); - printk("%-6d", pEntry->HTPhyMode.field.STBC); - printk("%-10d, %d, %d%%\n", pEntry->DebugFIFOCount, pEntry->DebugTxCount, - (pEntry->DebugTxCount) ? ((pEntry->DebugTxCount-pEntry->DebugFIFOCount)*100/pEntry->DebugTxCount) : 0); - printk("\n"); - - } - } - - return TRUE; -} - -INT Set_DlsAddEntry_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - UCHAR mac[MAC_ADDR_LEN]; - USHORT Timeout; - char *token, sepValue[] = ":", DASH = '-'; - INT i; - RT_802_11_DLS Dls; - - if(strlen(arg) < 19) //Mac address acceptable format 01:02:03:04:05:06 length 17 plus the "-" and timeout value in decimal format. - return FALSE; - - token = strchr(arg, DASH); - if ((token != NULL) && (strlen(token)>1)) - { - Timeout = simple_strtol((token+1), 0, 10); - - *token = '\0'; - for (i = 0, token = rstrtok(arg, &sepValue[0]); token; token = rstrtok(NULL, &sepValue[0]), i++) - { - if((strlen(token) != 2) || (!isxdigit(*token)) || (!isxdigit(*(token+1)))) - return FALSE; - AtoH(token, (PUCHAR)(&mac[i]), 1); - } - if(i != 6) - return FALSE; - - printk("\n%02x:%02x:%02x:%02x:%02x:%02x-%d", mac[0], mac[1], - mac[2], mac[3], mac[4], mac[5], (int)Timeout); - - NdisZeroMemory(&Dls, sizeof(RT_802_11_DLS)); - Dls.TimeOut = Timeout; - COPY_MAC_ADDR(Dls.MacAddr, mac); - Dls.Valid = 1; - - MlmeEnqueue(pAd, - MLME_CNTL_STATE_MACHINE, - RT_OID_802_11_SET_DLS_PARAM, - sizeof(RT_802_11_DLS), - &Dls); - - return TRUE; - } - - return FALSE; - -} - -INT Set_DlsTearDownEntry_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - UCHAR macAddr[MAC_ADDR_LEN]; - CHAR *value; - INT i; - RT_802_11_DLS Dls; - - if(strlen(arg) != 17) //Mac address acceptable format 01:02:03:04:05:06 length 17 - return FALSE; - - for (i=0, value = rstrtok(arg,":"); value; value = rstrtok(NULL,":")) - { - if((strlen(value) != 2) || (!isxdigit(*value)) || (!isxdigit(*(value+1))) ) - return FALSE; //Invalid - - AtoH(value, &macAddr[i++], 2); - } - - printk("\n%02x:%02x:%02x:%02x:%02x:%02x", macAddr[0], macAddr[1], - macAddr[2], macAddr[3], macAddr[4], macAddr[5]); - - NdisZeroMemory(&Dls, sizeof(RT_802_11_DLS)); - COPY_MAC_ADDR(Dls.MacAddr, macAddr); - Dls.Valid = 0; - - MlmeEnqueue(pAd, - MLME_CNTL_STATE_MACHINE, - RT_OID_802_11_SET_DLS_PARAM, - sizeof(RT_802_11_DLS), - &Dls); - - return TRUE; -} - diff --git a/drivers/staging/rt2860/sta/rtmp_data.c b/drivers/staging/rt2860/sta/rtmp_data.c index c5e76a2da56d..b41ce230c501 100644 --- a/drivers/staging/rt2860/sta/rtmp_data.c +++ b/drivers/staging/rt2860/sta/rtmp_data.c @@ -50,7 +50,6 @@ VOID STARxEAPOLFrameIndicate( PRXWI_STRUC pRxWI = pRxBlk->pRxWI; UCHAR *pTmpBuf; -#ifdef WPA_SUPPLICANT_SUPPORT if (pAd->StaCfg.WpaSupplicantUP) { // All EAPoL frames have to pass to upper layer (ex. WPA_SUPPLICANT daemon) @@ -75,6 +74,7 @@ VOID STARxEAPOLFrameIndicate( if (pAd->StaCfg.DesireSharedKey[idx].KeyLen > 0) { +#ifdef RT2860 MAC_TABLE_ENTRY *pEntry = &pAd->MacTab.Content[BSSID_WCID]; // Set key material and cipherAlg to Asic @@ -88,6 +88,32 @@ VOID STARxEAPOLFrameIndicate( pAd->IndicateMediaState = NdisMediaStateConnected; pAd->ExtraInfo = GENERAL_LINK_UP; +#endif +#ifdef RT2870 + union + { + char buf[sizeof(NDIS_802_11_WEP)+MAX_LEN_OF_KEY- 1]; + NDIS_802_11_WEP keyinfo; + } WepKey; + int len; + + + NdisZeroMemory(&WepKey, sizeof(WepKey)); + len =pAd->StaCfg.DesireSharedKey[idx].KeyLen; + + NdisMoveMemory(WepKey.keyinfo.KeyMaterial, + pAd->StaCfg.DesireSharedKey[idx].Key, + pAd->StaCfg.DesireSharedKey[idx].KeyLen); + + WepKey.keyinfo.KeyIndex = 0x80000000 + idx; + WepKey.keyinfo.KeyLength = len; + pAd->SharedKey[BSS0][idx].KeyLen =(UCHAR) (len <= 5 ? 5 : 13); + + pAd->IndicateMediaState = NdisMediaStateConnected; + pAd->ExtraInfo = GENERAL_LINK_UP; + // need to enqueue cmd to thread + RTUSBEnqueueCmdFromNdis(pAd, OID_802_11_ADD_WEP, TRUE, &WepKey, sizeof(WepKey.keyinfo) + len - 1); +#endif // RT2870 // // For Preventing ShardKey Table is cleared by remove key procedure. pAd->SharedKey[BSS0][idx].CipherAlg = CipherAlg; pAd->SharedKey[BSS0][idx].KeyLen = pAd->StaCfg.DesireSharedKey[idx].KeyLen; @@ -103,7 +129,6 @@ VOID STARxEAPOLFrameIndicate( } } else -#endif // WPA_SUPPLICANT_SUPPORT // { // Special DATA frame that has to pass to MLME // 1. Cisco Aironet frames for CCX2. We need pass it to MLME for special process @@ -168,20 +193,16 @@ VOID STARxDataFrameAnnounce( // ARALINK CmmRxRalinkFrameIndicate(pAd, pEntry, pRxBlk, FromWhichBSSID); } -#ifdef QOS_DLS_SUPPORT - RX_BLK_CLEAR_FLAG(pRxBlk, fRX_DLS); -#endif // QOS_DLS_SUPPORT // } else { RX_BLK_SET_FLAG(pRxBlk, fRX_EAP); -#ifdef DOT11_N_SUPPORT + if (RX_BLK_TEST_FLAG(pRxBlk, fRX_AMPDU) && (pAd->CommonCfg.bDisableReordering == 0)) { Indicate_AMPDU_Packet(pAd, pRxBlk, FromWhichBSSID); } else -#endif // DOT11_N_SUPPORT // { // Determin the destination of the EAP frame // to WPA state machine or upper layer @@ -226,13 +247,11 @@ BOOLEAN STACheckTkipMICValue( { DBGPRINT_RAW(RT_DEBUG_ERROR,("Rx MIC Value error 2\n")); -#ifdef WPA_SUPPLICANT_SUPPORT if (pAd->StaCfg.WpaSupplicantUP) { WpaSendMicFailureToWpaSupplicant(pAd, (pWpaKey->Type == PAIRWISEKEY) ? TRUE : FALSE); } else -#endif // WPA_SUPPLICANT_SUPPORT // { RTMPReportMicError(pAd, pWpaKey); } @@ -276,14 +295,6 @@ VOID STAHandleRxDataFrame( return; } -#ifdef QOS_DLS_SUPPORT - //if ((pHeader->FC.FrDs == 0) && (pHeader->FC.ToDs == 0)) - if (RTMPRcvFrameDLSCheck(pAd, pHeader, pRxWI->MPDUtotalByteCount, pRxD)) - { - return; - } -#endif // QOS_DLS_SUPPORT // - // Drop not my BSS frames if (pRxD->MyBss == 0) { @@ -342,10 +353,7 @@ VOID STAHandleRxDataFrame( } // Drop not my BSS frame (we can not only check the MyBss bit in RxD) -#ifdef QOS_DLS_SUPPORT - if (!pAd->CommonCfg.bDLSCapable) - { -#endif // QOS_DLS_SUPPORT // + if (INFRA_ON(pAd)) { // Infrastructure mode, check address 2 for BSSID @@ -368,9 +376,6 @@ VOID STAHandleRxDataFrame( return; } } -#ifdef QOS_DLS_SUPPORT - } -#endif // QOS_DLS_SUPPORT // // // find pEntry @@ -391,11 +396,6 @@ VOID STAHandleRxDataFrame( if (INFRA_ON(pAd)) { RX_BLK_SET_FLAG(pRxBlk, fRX_INFRA); -#ifdef QOS_DLS_SUPPORT - if ((pHeader->FC.FrDs == 0) && (pHeader->FC.ToDs == 0)) - RX_BLK_SET_FLAG(pRxBlk, fRX_DLS); - else -#endif // QOS_DLS_SUPPORT // ASSERT(pRxWI->WirelessCliID == BSSID_WCID); } @@ -453,12 +453,10 @@ VOID STAHandleRxDataFrame( else #endif { -#ifdef DOT11_N_SUPPORT RX_BLK_SET_FLAG(pRxBlk, fRX_HTC); // skip HTC contorl field pRxBlk->pData += 4; pRxBlk->DataSize -= 4; -#endif // DOT11_N_SUPPORT // } } @@ -471,13 +469,10 @@ VOID STAHandleRxDataFrame( pRxBlk->pData += 2; } -#ifdef DOT11_N_SUPPORT if (pRxD->BA) { RX_BLK_SET_FLAG(pRxBlk, fRX_AMPDU); } -#endif // DOT11_N_SUPPORT // - // // Case I Process Broadcast & Multicast data frame @@ -509,18 +504,6 @@ VOID STAHandleRxDataFrame( { pAd->LastRxRate = (USHORT)((pRxWI->MCS) + (pRxWI->BW <<7) + (pRxWI->ShortGI <<8)+ (pRxWI->PHYMODE <<14)) ; - -#ifdef QOS_DLS_SUPPORT - if (RX_BLK_TEST_FLAG(pRxBlk, fRX_DLS)) - { - MAC_TABLE_ENTRY *pDlsEntry = NULL; - - pDlsEntry = DlsEntryTableLookupByWcid(pAd, pRxWI->WirelessCliID, pHeader->Addr2, TRUE); - if(pDlsEntry) - Update_Rssi_Sample(pAd, &pDlsEntry->RssiSample, pRxWI); - } - else -#endif // QOS_DLS_SUPPORT // if (ADHOC_ON(pAd)) { pEntry = MacTableLookup(pAd, pHeader->Addr2); @@ -592,7 +575,13 @@ VOID STAHandleRxMgmtFrame( { // We should collect RSSI not only U2M data but also my beacon +#ifdef RT30xx + if ((pHeader->FC.SubType == SUBTYPE_BEACON) && (MAC_ADDR_EQUAL(&pAd->CommonCfg.Bssid, &pHeader->Addr2)) + && (pAd->RxAnt.EvaluatePeriod == 0)) +#endif +#ifndef RT30xx if ((pHeader->FC.SubType == SUBTYPE_BEACON) && (MAC_ADDR_EQUAL(&pAd->CommonCfg.Bssid, &pHeader->Addr2))) +#endif { Update_Rssi_Sample(pAd, &pAd->StaCfg.RssiSample, pRxWI); @@ -600,6 +589,18 @@ VOID STAHandleRxMgmtFrame( pAd->StaCfg.LastSNR1 = (UCHAR)(pRxWI->SNR1); } +#ifdef RT30xx + // collect rssi information for antenna diversity + if (pAd->NicConfig2.field.AntDiversity) + { + if ((pRxD->U2M) || ((pHeader->FC.SubType == SUBTYPE_BEACON) && (MAC_ADDR_EQUAL(&pAd->CommonCfg.Bssid, &pHeader->Addr2)))) + { + COLLECT_RX_ANTENNA_AVERAGE_RSSI(pAd, ConvertToRssi(pAd, (UCHAR)pRxWI->RSSI0, RSSI_0), 0); //Note: RSSI2 not used on RT73 + pAd->StaCfg.NumOfAvgRssiSample ++; + } + } +#endif // RT30xx // + // First check the size, it MUST not exceed the mlme queue size if (pRxWI->MPDUtotalByteCount > MGMT_DMA_BUFFER_SIZE) { @@ -618,21 +619,17 @@ VOID STAHandleRxControlFrame( IN PRTMP_ADAPTER pAd, IN RX_BLK *pRxBlk) { -#ifdef DOT11_N_SUPPORT PRXWI_STRUC pRxWI = pRxBlk->pRxWI; -#endif // DOT11_N_SUPPORT // PHEADER_802_11 pHeader = pRxBlk->pHeader; PNDIS_PACKET pRxPacket = pRxBlk->pRxPacket; switch (pHeader->FC.SubType) { case SUBTYPE_BLOCK_ACK_REQ: -#ifdef DOT11_N_SUPPORT { CntlEnqueueForRecv(pAd, pRxWI->WirelessCliID, (pRxWI->MPDUtotalByteCount), (PFRAME_BA_REQ)pHeader); } break; -#endif // DOT11_N_SUPPORT // case SUBTYPE_BLOCK_ACK: case SUBTYPE_ACK: default: @@ -691,12 +688,14 @@ BOOLEAN STARxDoneInterruptHandle( break; } +#ifdef RT2860 if (RxProcessed++ > MAX_RX_PROCESS_CNT) { // need to reschedule rx handle bReschedule = TRUE; break; } +#endif RxProcessed ++; // test @@ -721,11 +720,6 @@ BOOLEAN STARxDoneInterruptHandle( pRxWI = (PRXWI_STRUC) pData; pHeader = (PHEADER_802_11) (pData+RXWI_SIZE) ; -#ifdef RT_BIG_ENDIAN - RTMPFrameEndianChange(pAd, (PUCHAR)pHeader, DIR_READ, TRUE); - RTMPWIEndianChange((PUCHAR)pRxWI, TYPE_RXWI); -#endif - // build RxCell RxCell.pRxWI = pRxWI; RxCell.pHeader = pHeader; @@ -749,22 +743,6 @@ BOOLEAN STARxDoneInterruptHandle( break; } /* RT2870 invokes STARxDoneInterruptHandle() in rtusb_bulk.c */ -#ifdef RALINK_ATE - if (ATE_ON(pAd)) - { - pAd->ate.RxCntPerSec++; - ATESampleRssi(pAd, pRxWI); -#ifdef RALINK_28xx_QA - if (pAd->ate.bQARxStart == TRUE) - { - /* (*pRxD) has been swapped in GetPacketFromRxRing() */ - ATE_QA_Statistics(pAd, pRxWI, pRxD, pHeader); - } -#endif // RALINK_28xx_QA // - RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_SUCCESS); - continue; - } -#endif // RALINK_ATE // // Check for all RxD errors Status = RTMPCheckRxError(pAd, pHeader, pRxWI, pRxD); @@ -807,6 +785,7 @@ BOOLEAN STARxDoneInterruptHandle( } } +#ifdef RT2860 // fRTMP_PS_GO_TO_SLEEP_NOW is set if receiving beacon. if (RTMP_TEST_PSFLAG(pAd, fRTMP_PS_GO_TO_SLEEP_NOW) && (INFRA_ON(pAd))) { @@ -814,6 +793,7 @@ BOOLEAN STARxDoneInterruptHandle( AsicSleepThenAutoWakeup(pAd, pAd->ThisTbttNumToNextWakeUp); bReschedule = FALSE; } +#endif return bReschedule; } @@ -831,7 +811,12 @@ BOOLEAN STARxDoneInterruptHandle( VOID RTMPHandleTwakeupInterrupt( IN PRTMP_ADAPTER pAd) { +#ifdef RT2860 AsicForceWakeup(pAd, DOT11POWERSAVE); +#endif +#ifdef RT2870 + AsicForceWakeup(pAd, FALSE); +#endif } /* @@ -885,17 +870,6 @@ VOID STASendPackets( { // Record that orignal packet source is from NDIS layer,so that // later on driver knows how to release this NDIS PACKET -#ifdef QOS_DLS_SUPPORT - MAC_TABLE_ENTRY *pEntry; - PUCHAR pSrcBufVA = GET_OS_PKT_DATAPTR(pPacket); - - pEntry = MacTableLookup(pAd, pSrcBufVA); - if (pEntry && (pEntry->ValidAsDls == TRUE)) - { - RTMP_SET_PACKET_WCID(pPacket, pEntry->Aid); - } - else -#endif // QOS_DLS_SUPPORT // RTMP_SET_PACKET_WCID(pPacket, 0); // this field is useless when in STA mode RTMP_SET_PACKET_SOURCE(pPacket, PKTSRC_NDIS); NDIS_SET_PACKET_STATUS(pPacket, NDIS_STATUS_PENDING); @@ -977,18 +951,6 @@ NDIS_STATUS STASendPacket( { if(INFRA_ON(pAd)) { -#ifdef QOS_DLS_SUPPORT - USHORT tmpWcid; - - tmpWcid = RTMP_GET_PACKET_WCID(pPacket); - if (VALID_WCID(tmpWcid) && - (pAd->MacTab.Content[tmpWcid].ValidAsDls== TRUE)) - { - pEntry = &pAd->MacTab.Content[tmpWcid]; - Rate = pAd->MacTab.Content[tmpWcid].CurrTxRate; - } - else -#endif // QOS_DLS_SUPPORT // { pEntry = &pAd->MacTab.Content[BSSID_WCID]; RTMP_SET_PACKET_WCID(pPacket, BSSID_WCID); @@ -1039,12 +1001,7 @@ NDIS_STATUS STASendPacket( (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) -#ifdef WPA_SUPPLICANT_SUPPORT || (pAd->StaCfg.IEEE8021X == TRUE) -#endif // WPA_SUPPLICANT_SUPPORT // -#ifdef LEAP_SUPPORT - || (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) -#endif // LEAP_SUPPORT // ) && ((pAd->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED) || (pAd->StaCfg.MicErrCnt >= 2)) && (RTMP_GET_PACKET_EAPOL(pPacket)== FALSE) @@ -1070,10 +1027,8 @@ NDIS_STATUS STASendPacket( NumberOfFrag = 1; // Aggregation overwhelms fragmentation else if (CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_AMSDU_INUSED)) NumberOfFrag = 1; // Aggregation overwhelms fragmentation -#ifdef DOT11_N_SUPPORT else if ((pAd->StaCfg.HTPhyMode.field.MODE == MODE_HTMIX) || (pAd->StaCfg.HTPhyMode.field.MODE == MODE_HTGREENFIELD)) NumberOfFrag = 1; // MIMO RATE overwhelms fragmentation -#endif // DOT11_N_SUPPORT // else { // The calculated "NumberOfFrag" is a rough estimation because of various @@ -1110,7 +1065,13 @@ NDIS_STATUS STASendPacket( // UserPriority = 0; QueIdx = QID_AC_BE; +#ifdef RT2860 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED)) +#endif +#ifdef RT2870 + if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED) && + CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_WMM_CAPABLE)) +#endif { USHORT Protocol; UCHAR LlcSnapLen = 0, Byte0, Byte1; @@ -1163,9 +1124,6 @@ NDIS_STATUS STASendPacket( if (pAd->TxSwQueue[QueIdx].Number >= MAX_PACKETS_IN_QUEUE) { RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags); -#ifdef BLOCK_NET_IF - StopNetIfQueue(pAd, QueIdx, pPacket); -#endif // BLOCK_NET_IF // RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); return NDIS_STATUS_FAILURE; @@ -1176,9 +1134,13 @@ NDIS_STATUS STASendPacket( } RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags); -#ifdef DOT11_N_SUPPORT if ((pAd->CommonCfg.BACapability.field.AutoBA == TRUE)&& +#ifdef RT2860 (pAd->StaActive.SupportedPhyInfo.bHtEnable == TRUE)) +#endif +#ifdef RT2870 + IS_HT_STA(pEntry)) +#endif { if (((pEntry->TXBAbitmap & (1<BADeclineBitmap & (1<RalinkCounters.OneSecOsTxCount[QueIdx]++; // TODO: for debug only. to be removed return NDIS_STATUS_SUCCESS; @@ -1223,14 +1184,27 @@ NDIS_STATUS STASendPacket( ======================================================================== */ + +#ifdef RT2870 +/* + Actually, this function used to check if the TxHardware Queue still has frame need to send. + If no frame need to send, go to sleep, else, still wake up. +*/ +#endif NDIS_STATUS RTMPFreeTXDRequest( IN PRTMP_ADAPTER pAd, IN UCHAR QueIdx, IN UCHAR NumberRequired, IN PUCHAR FreeNumberIs) { +#ifdef RT2860 ULONG FreeNumber = 0; +#endif NDIS_STATUS Status = NDIS_STATUS_FAILURE; +#ifdef RT2870 + unsigned long IrqFlags; + HT_TX_CONTEXT *pHTTXContext; +#endif switch (QueIdx) { @@ -1239,6 +1213,7 @@ NDIS_STATUS RTMPFreeTXDRequest( case QID_AC_VI: case QID_AC_VO: case QID_HCCA: +#ifdef RT2860 if (pAd->TxRing[QueIdx].TxSwFreeIdx > pAd->TxRing[QueIdx].TxCpuIdx) FreeNumber = pAd->TxRing[QueIdx].TxSwFreeIdx - pAd->TxRing[QueIdx].TxCpuIdx - 1; else @@ -1246,9 +1221,27 @@ NDIS_STATUS RTMPFreeTXDRequest( if (FreeNumber >= NumberRequired) Status = NDIS_STATUS_SUCCESS; +#endif +#ifdef RT2870 + { + pHTTXContext = &pAd->TxContext[QueIdx]; + RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); + if ((pHTTXContext->CurWritePosition != pHTTXContext->ENextBulkOutPosition) || + (pHTTXContext->IRPPending == TRUE)) + { + Status = NDIS_STATUS_FAILURE; + } + else + { + Status = NDIS_STATUS_SUCCESS; + } + RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); + } +#endif break; case QID_MGMT: +#ifdef RT2860 if (pAd->MgmtRing.TxSwFreeIdx > pAd->MgmtRing.TxCpuIdx) FreeNumber = pAd->MgmtRing.TxSwFreeIdx - pAd->MgmtRing.TxCpuIdx - 1; else @@ -1256,13 +1249,22 @@ NDIS_STATUS RTMPFreeTXDRequest( if (FreeNumber >= NumberRequired) Status = NDIS_STATUS_SUCCESS; +#endif +#ifdef RT2870 + if (pAd->MgmtRing.TxSwFreeIdx != MGMT_RING_SIZE) + Status = NDIS_STATUS_FAILURE; + else + Status = NDIS_STATUS_SUCCESS; +#endif break; default: DBGPRINT(RT_DEBUG_ERROR,("RTMPFreeTXDRequest::Invalid QueIdx(=%d)\n", QueIdx)); break; } +#ifdef RT2860 *FreeNumberIs = (UCHAR)FreeNumber; +#endif return (Status); } @@ -1283,22 +1285,12 @@ VOID RTMPSendNullFrame( ULONG Length; PHEADER_802_11 pHeader_802_11; - -#ifdef RALINK_ATE - if(ATE_ON(pAd)) - { - return; - } -#endif // RALINK_ATE // - // WPA 802.1x secured port control if (((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) -#ifdef WPA_SUPPLICANT_SUPPORT || (pAd->StaCfg.IEEE8021X == TRUE) -#endif ) && (pAd->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED)) { @@ -1402,30 +1394,6 @@ VOID STAFindCipherAlgorithm( } else if (Cipher == Ndis802_11Encryption1Enabled) { -#ifdef LEAP_SUPPORT - if (pAd->StaCfg.CkipFlag & 0x10) // Cisco CKIP KP is on - { - if (LEAP_CCKM_ON(pAd)) - { - if (((*pSrcBufVA & 0x01) && (ADHOC_ON(pAd)))) - KeyIdx = 1; - else - KeyIdx = 0; - } - else - KeyIdx = pAd->StaCfg.DefaultKeyId; - } - else if (pAd->StaCfg.CkipFlag & 0x08) // only CKIP CMIC - KeyIdx = pAd->StaCfg.DefaultKeyId; - else if (LEAP_CCKM_ON(pAd)) - { - if ((*pSrcBufVA & 0x01) && (ADHOC_ON(pAd))) - KeyIdx = 1; - else - KeyIdx = 0; - } - else // standard WEP64 or WEP128 -#endif // LEAP_SUPPORT // KeyIdx = pAd->StaCfg.DefaultKeyId; } else if ((Cipher == Ndis802_11Encryption2Enabled) || @@ -1443,13 +1411,11 @@ VOID STAFindCipherAlgorithm( CipherAlg = CIPHER_NONE; else if ((Cipher == Ndis802_11EncryptionDisabled) || (pAd->SharedKey[BSS0][KeyIdx].KeyLen == 0)) CipherAlg = CIPHER_NONE; -#ifdef WPA_SUPPLICANT_SUPPORT else if ( pAd->StaCfg.WpaSupplicantUP && (Cipher == Ndis802_11Encryption1Enabled) && (pAd->StaCfg.IEEE8021X == TRUE) && (pAd->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED)) CipherAlg = CIPHER_NONE; -#endif // WPA_SUPPLICANT_SUPPORT // else { //Header_802_11.FC.Wep = 1; @@ -1467,12 +1433,7 @@ VOID STABuildCommon802_11Header( IN PRTMP_ADAPTER pAd, IN TX_BLK *pTxBlk) { - HEADER_802_11 *pHeader_802_11; -#ifdef QOS_DLS_SUPPORT - BOOLEAN bDLSFrame = FALSE; - INT DlsEntryIndex = 0; -#endif // QOS_DLS_SUPPORT // // // MAKE A COMMON 802.11 HEADER @@ -1489,19 +1450,6 @@ VOID STABuildCommon802_11Header( pHeader_802_11->FC.Type = BTYPE_DATA; pHeader_802_11->FC.SubType = ((TX_BLK_TEST_FLAG(pTxBlk, fTX_bWMM)) ? SUBTYPE_QDATA : SUBTYPE_DATA); -#ifdef QOS_DLS_SUPPORT - if (INFRA_ON(pAd)) - { - // Check if the frame can be sent through DLS direct link interface - // If packet can be sent through DLS, then force aggregation disable. (Hard to determine peer STA's capability) - DlsEntryIndex = RTMPCheckDLSFrame(pAd, pTxBlk->pSrcBufHeader); - if (DlsEntryIndex >= 0) - bDLSFrame = TRUE; - else - bDLSFrame = FALSE; - } -#endif // QOS_DLS_SUPPORT // - if (pTxBlk->pMacEntry) { if (TX_BLK_TEST_FLAG(pTxBlk, fTX_bForceNonQoS)) @@ -1511,14 +1459,6 @@ VOID STABuildCommon802_11Header( } else { -#ifdef QOS_DLS_SUPPORT - if (bDLSFrame) - { - pHeader_802_11->Sequence = pAd->StaCfg.DLSEntry[DlsEntryIndex].Sequence; - pAd->StaCfg.DLSEntry[DlsEntryIndex].Sequence = (pAd->StaCfg.DLSEntry[DlsEntryIndex].Sequence+1) & MAXSEQ; - } - else -#endif // QOS_DLS_SUPPORT // { pHeader_802_11->Sequence = pTxBlk->pMacEntry->TxSeq[pTxBlk->UserPriority]; pTxBlk->pMacEntry->TxSeq[pTxBlk->UserPriority] = (pTxBlk->pMacEntry->TxSeq[pTxBlk->UserPriority]+1) & MAXSEQ; @@ -1538,16 +1478,6 @@ VOID STABuildCommon802_11Header( { if (INFRA_ON(pAd)) { -#ifdef QOS_DLS_SUPPORT - if (bDLSFrame) - { - COPY_MAC_ADDR(pHeader_802_11->Addr1, pTxBlk->pSrcBufHeader); - COPY_MAC_ADDR(pHeader_802_11->Addr2, pAd->CurrentAddress); - COPY_MAC_ADDR(pHeader_802_11->Addr3, pAd->CommonCfg.Bssid); - pHeader_802_11->FC.ToDs = 0; - } - else -#endif // QOS_DLS_SUPPORT // { COPY_MAC_ADDR(pHeader_802_11->Addr1, pAd->CommonCfg.Bssid); COPY_MAC_ADDR(pHeader_802_11->Addr2, pAd->CurrentAddress); @@ -1576,7 +1506,6 @@ VOID STABuildCommon802_11Header( pHeader_802_11->FC.PwrMgmt = (pAd->StaCfg.Psm == PWR_SAVE); } -#ifdef DOT11_N_SUPPORT VOID STABuildCache802_11Header( IN RTMP_ADAPTER *pAd, IN TX_BLK *pTxBlk, @@ -1603,29 +1532,7 @@ VOID STABuildCache802_11Header( pMacEntry->TxSeq[pTxBlk->UserPriority] = (pMacEntry->TxSeq[pTxBlk->UserPriority]+1) & MAXSEQ; { - // Check if the frame can be sent through DLS direct link interface - // If packet can be sent through DLS, then force aggregation disable. (Hard to determine peer STA's capability) -#ifdef QOS_DLS_SUPPORT - BOOLEAN bDLSFrame = FALSE; - INT DlsEntryIndex = 0; - - DlsEntryIndex = RTMPCheckDLSFrame(pAd, pTxBlk->pSrcBufHeader); - if (DlsEntryIndex >= 0) - bDLSFrame = TRUE; - else - bDLSFrame = FALSE; -#endif // QOS_DLS_SUPPORT // - // The addr3 of normal packet send from DS is Dest Mac address. -#ifdef QOS_DLS_SUPPORT - if (bDLSFrame) - { - COPY_MAC_ADDR(pHeader80211->Addr1, pTxBlk->pSrcBufHeader); - COPY_MAC_ADDR(pHeader80211->Addr3, pAd->CommonCfg.Bssid); - pHeader80211->FC.ToDs = 0; - } - else -#endif // QOS_DLS_SUPPORT // if (ADHOC_ON(pAd)) COPY_MAC_ADDR(pHeader80211->Addr3, pAd->CommonCfg.Bssid); else @@ -1640,7 +1547,6 @@ VOID STABuildCache802_11Header( else pHeader80211->FC.PwrMgmt = (pAd->StaCfg.Psm == PWR_SAVE); } -#endif // DOT11_N_SUPPORT // static inline PUCHAR STA_Build_ARalink_Frame_Header( IN RTMP_ADAPTER *pAd, @@ -1700,7 +1606,6 @@ static inline PUCHAR STA_Build_ARalink_Frame_Header( } -#ifdef DOT11_N_SUPPORT static inline PUCHAR STA_Build_AMSDU_Frame_Header( IN RTMP_ADAPTER *pAd, IN TX_BLK *pTxBlk) @@ -1890,7 +1795,9 @@ VOID STA_AMPDU_Frame_Tx( // // Kick out Tx // +#ifdef RT2860 if (!RTMP_TEST_PSFLAG(pAd, fRTMP_PS_DISABLE_TX)) +#endif HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx); pAd->RalinkCounters.KickTxCount++; @@ -2021,10 +1928,11 @@ VOID STA_AMSDU_Frame_Tx( // // Kick out Tx // +#ifdef RT2860 if (!RTMP_TEST_PSFLAG(pAd, fRTMP_PS_DISABLE_TX)) +#endif HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx); } -#endif // DOT11_N_SUPPORT // VOID STA_Legacy_Frame_Tx( IN PRTMP_ADAPTER pAd, @@ -2142,7 +2050,9 @@ VOID STA_Legacy_Frame_Tx( // // Kick out Tx // +#ifdef RT2860 if (!RTMP_TEST_PSFLAG(pAd, fRTMP_PS_DISABLE_TX)) +#endif HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx); } @@ -2253,7 +2163,9 @@ VOID STA_ARalink_Frame_Tx( // // Kick out Tx // +#ifdef RT2860 if (!RTMP_TEST_PSFLAG(pAd, fRTMP_PS_DISABLE_TX)) +#endif HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx); } @@ -2513,15 +2425,6 @@ NDIS_STATUS STAHardTransmit( pPacket = QUEUE_ENTRY_TO_PACKET(pTxBlk->TxPacketList.Head); -#if 0 //def CARRIER_DETECTION_SUPPORT // Roger sync Carrier - if ((pAd->CommonCfg.CarrierDetect.Enable == TRUE) && (isCarrierDetectExist(pAd) == TRUE)) - { - DBGPRINT(RT_DEBUG_INFO,("STAHardTransmit --> radar detect not in normal mode !!!\n")); - RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); - return (NDIS_STATUS_FAILURE); - } -#endif // CARRIER_DETECTION_SUPPORT // - // ------------------------------------------------------------------ // STEP 1. WAKE UP PHY // outgoing frame always wakeup PHY to prevent frame lost and @@ -2531,7 +2434,12 @@ NDIS_STATUS STAHardTransmit( if ((pAd->StaCfg.Psm == PWR_SAVE) && OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) { DBGPRINT_RAW(RT_DEBUG_TRACE, ("AsicForceWakeup At HardTx\n")); +#ifdef RT2860 AsicForceWakeup(pAd, FROM_TX); +#endif +#ifdef RT2870 + AsicForceWakeup(pAd, TRUE); +#endif } // It should not change PSM bit, when APSD turn on. @@ -2546,14 +2454,12 @@ NDIS_STATUS STAHardTransmit( switch (pTxBlk->TxFrameType) { -#ifdef DOT11_N_SUPPORT case TX_AMPDU_FRAME: STA_AMPDU_Frame_Tx(pAd, pTxBlk); break; case TX_AMSDU_FRAME: STA_AMSDU_Frame_Tx(pAd, pTxBlk); break; -#endif // DOT11_N_SUPPORT // case TX_LEGACY_FRAME: STA_Legacy_Frame_Tx(pAd, pTxBlk); break; diff --git a/drivers/staging/rt2860/sta/sanity.c b/drivers/staging/rt2860/sta/sanity.c index 239872464bed..7d530f601602 100644 --- a/drivers/staging/rt2860/sta/sanity.c +++ b/drivers/staging/rt2860/sta/sanity.c @@ -184,7 +184,6 @@ BOOLEAN PeerAssocRspSanity( } break; -#ifdef DOT11_N_SUPPORT case IE_ADD_HT: case IE_ADD_HT2: if (pEid->Len >= sizeof(ADD_HT_INFO_IE)) @@ -213,7 +212,6 @@ BOOLEAN PeerAssocRspSanity( { DBGPRINT(RT_DEBUG_WARN, ("PeerAssocRspSanity - wrong IE_SECONDARY_CH_OFFSET. \n")); } -#endif // DOT11_N_SUPPORT // break; case IE_AIRONET_CKIP: // 0. Check Aironet IE length, it must be larger or equal to 28 diff --git a/drivers/staging/rt2860/sta/sync.c b/drivers/staging/rt2860/sta/sync.c index 148037a79d51..87b5e49cec54 100644 --- a/drivers/staging/rt2860/sta/sync.c +++ b/drivers/staging/rt2860/sta/sync.c @@ -37,6 +37,7 @@ */ #include "../rt_config.h" +#ifdef RT2860 #define AC0_DEF_TXOP 0 #define AC1_DEF_TXOP 0 #define AC2_DEF_TXOP 94 @@ -71,6 +72,10 @@ VOID AdhocTurnOnQos( } AsicSetEdcaParm(pAd, &pAd->CommonCfg.APEdcaParm); } +#endif /* RT2860 */ +#ifdef RT2870 +#define ADHOC_ENTRY_BEACON_LOST_TIME (2*OS_HZ) // 2 sec +#endif /* ========================================================================== @@ -141,7 +146,6 @@ VOID BeaconTimeout( if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) return; -#ifdef DOT11_N_SUPPORT if ((pAd->CommonCfg.BBPCurrentBW == BW_40) ) { @@ -154,7 +158,6 @@ VOID BeaconTimeout( RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); DBGPRINT(RT_DEBUG_TRACE, ("SYNC - End of SCAN, restore to 40MHz channel %d, Total BSS[%02d]\n",pAd->CommonCfg.CentralChannel, pAd->ScanTab.BssNr)); } -#endif // DOT11_N_SUPPORT // MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_BEACON_TIMEOUT, 0, NULL); RT28XX_MLME_HANDLER(pAd); @@ -228,6 +231,7 @@ VOID MlmeScanReqAction( // Increase the scan retry counters. pAd->StaCfg.ScanCnt++; +#ifdef RT2860 if ((OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE)) && (IDLE_ON(pAd)) && (pAd->StaCfg.bRadio == TRUE) && @@ -235,6 +239,7 @@ VOID MlmeScanReqAction( { RT28xxPciAsicRadioOn(pAd, GUI_IDLE_POWER_SAVE); } +#endif // first check the parameter sanity if (MlmeScanReqSanity(pAd, @@ -347,6 +352,7 @@ VOID MlmeJoinReqAction( DBGPRINT(RT_DEBUG_TRACE, ("SYNC - MlmeJoinReqAction(BSS #%ld)\n", pInfo->BssIdx)); +#ifdef RT2860 if ((OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE)) && (IDLE_ON(pAd)) && (pAd->StaCfg.bRadio == TRUE) && @@ -354,6 +360,7 @@ VOID MlmeJoinReqAction( { RT28xxPciAsicRadioOn(pAd, GUI_IDLE_POWER_SAVE); } +#endif // reset all the timers RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &TimerCancelled); @@ -375,22 +382,6 @@ VOID MlmeJoinReqAction( pAd->MlmeAux.Channel = pBss->Channel; pAd->MlmeAux.CentralChannel = pBss->CentralChannel; -#ifdef EXT_BUILD_CHANNEL_LIST - // Country IE of the AP will be evaluated and will be used. - if ((pAd->StaCfg.IEEE80211dClientMode != Rt802_11_D_None) && - (pBss->bHasCountryIE == TRUE)) - { - NdisMoveMemory(&pAd->CommonCfg.CountryCode[0], &pBss->CountryString[0], 2); - if (pBss->CountryString[2] == 'I') - pAd->CommonCfg.Geography = IDOR; - else if (pBss->CountryString[2] == 'O') - pAd->CommonCfg.Geography = ODOR; - else - pAd->CommonCfg.Geography = BOTH; - BuildChannelListEx(pAd); - } -#endif // EXT_BUILD_CHANNEL_LIST // - // Let BBP register at 20MHz to do scan RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); BBPValue &= (~0x18); @@ -407,9 +398,6 @@ VOID MlmeJoinReqAction( if (((pAd->CommonCfg.bIEEE80211H == 1) && (pAd->MlmeAux.Channel > 14) && RadarChannelCheck(pAd, pAd->MlmeAux.Channel)) -#ifdef CARRIER_DETECTION_SUPPORT // Roger sync Carrier - || (pAd->CommonCfg.CarrierDetect.Enable == TRUE) -#endif // CARRIER_DETECTION_SUPPORT // ) { // @@ -541,7 +529,7 @@ VOID MlmeStartReqAction( pAd->MlmeAux.ExtRateLen = pAd->CommonCfg.ExtRateLen; NdisMoveMemory(pAd->MlmeAux.ExtRate, pAd->CommonCfg.ExtRate, MAX_LEN_OF_SUPPORTED_RATES); RTMPCheckRates(pAd, pAd->MlmeAux.ExtRate, &pAd->MlmeAux.ExtRateLen); -#ifdef DOT11_N_SUPPORT + if (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) { RTMPUpdateHTIE(&pAd->CommonCfg.DesiredHtPhy, &pAd->StaCfg.DesiredHtPhyInfo.MCSSet[0], &pAd->MlmeAux.HtCapability, &pAd->MlmeAux.AddHtInfo); @@ -550,7 +538,6 @@ VOID MlmeStartReqAction( DBGPRINT(RT_DEBUG_TRACE, ("SYNC -pAd->StaActive.SupportedHtPhy.bHtEnable = TRUE\n")); } else -#endif // DOT11_N_SUPPORT // { pAd->MlmeAux.HtCapabilityLen = 0; pAd->StaActive.SupportedPhyInfo.bHtEnable = FALSE; @@ -618,10 +605,9 @@ VOID PeerBeaconAtScanAction( // Init Variable IE structure pVIE = (PNDIS_802_11_VARIABLE_IEs) VarIE; pVIE->Length = 0; -#ifdef DOT11_N_SUPPORT + RTMPZeroMemory(&HtCapability, sizeof(HtCapability)); RTMPZeroMemory(&AddHtInfo, sizeof(ADD_HT_INFO_IE)); -#endif // DOT11_N_SUPPORT // if (PeerBeaconAndProbeRspSanity(pAd, Elem->Msg, @@ -672,11 +658,9 @@ VOID PeerBeaconAtScanAction( Rssi = RTMPMaxRssi(pAd, ConvertToRssi(pAd, Elem->Rssi0, RSSI_0), ConvertToRssi(pAd, Elem->Rssi1, RSSI_1), ConvertToRssi(pAd, Elem->Rssi2, RSSI_2)); - -#ifdef DOT11_N_SUPPORT if ((HtCapabilityLen > 0) || (PreNHtCapabilityLen > 0)) HtCapabilityLen = SIZE_HT_CAP_IE; -#endif // DOT11_N_SUPPORT // + if ((pAd->StaCfg.CCXReqType != MSRN_TYPE_UNUSED) && (Channel == pAd->StaCfg.CCXScanChannel)) { Idx = BssTableSetEntry(pAd, &pAd->StaCfg.CCXBssTab, Bssid, Ssid, SsidLen, BssType, BeaconPeriod, @@ -698,16 +682,7 @@ VOID PeerBeaconAtScanAction( &CfParm, AtimWin, CapabilityInfo, SupRate, SupRateLen, ExtRate, ExtRateLen, &HtCapability, &AddHtInfo, HtCapabilityLen, AddHtInfoLen, NewExtChannelOffset, Channel, Rssi, TimeStamp, CkipFlag, &EdcaParm, &QosCapability, &QbssLoad, LenVIE, pVIE); -#ifdef DOT11_N_SUPPORT -#ifdef DOT11N_DRAFT3 - if (pAd->ChannelList[pAd->CommonCfg.ChannelListIdx].bEffectedChannel == TRUE) - { - UCHAR RegClass; - PeerBeaconAndProbeRspSanity2(pAd, Elem->Msg, Elem->MsgLen, &RegClass); - TriEventTableSetEntry(pAd, &pAd->CommonCfg.TriggerEventTab, Bssid, &HtCapability, HtCapabilityLen, RegClass, Channel); - } -#endif // DOT11N_DRAFT3 // -#endif // DOT11_N_SUPPORT // + if (Idx != BSS_NOT_FOUND) { NdisMoveMemory(pAd->ScanTab.BssEntry[Idx].PTSF, &Elem->Msg[24], 4); @@ -755,9 +730,7 @@ VOID PeerBeaconAtJoinAction( UCHAR HtCapabilityLen = 0, PreNHtCapabilityLen = 0; UCHAR AddHtInfoLen; UCHAR NewExtChannelOffset = 0xff; -#ifdef DOT11_N_SUPPORT UCHAR CentralChannel; -#endif // DOT11_N_SUPPORT // // Init Variable IE structure pVIE = (PNDIS_802_11_VARIABLE_IEs) VarIE; @@ -873,7 +846,7 @@ VOID PeerBeaconAtJoinAction( RTMPCheckRates(pAd, pAd->MlmeAux.ExtRate, &pAd->MlmeAux.ExtRateLen); NdisZeroMemory(pAd->StaActive.SupportedPhyInfo.MCSSet, 16); -#ifdef DOT11_N_SUPPORT + pAd->MlmeAux.NewExtChannelOffset = NewExtChannelOffset; pAd->MlmeAux.HtCapabilityLen = HtCapabilityLen; @@ -918,7 +891,6 @@ VOID PeerBeaconAtJoinAction( } else -#endif // DOT11_N_SUPPORT // { // To prevent error, let legacy AP must have same CentralChannel and Channel. if ((HtCapabilityLen == 0) && (PreNHtCapabilityLen == 0)) @@ -933,9 +905,7 @@ VOID PeerBeaconAtJoinAction( // copy QOS related information if ((pAd->CommonCfg.bWmmCapable) -#ifdef DOT11_N_SUPPORT || (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) -#endif // DOT11_N_SUPPORT // ) { NdisMoveMemory(&pAd->MlmeAux.APEdcaParm, &EdcaParm, sizeof(EDCA_PARM)); @@ -952,15 +922,6 @@ VOID PeerBeaconAtJoinAction( DBGPRINT(RT_DEBUG_TRACE, ("SYNC - after JOIN, SupRateLen=%d, ExtRateLen=%d\n", pAd->MlmeAux.SupRateLen, pAd->MlmeAux.ExtRateLen)); -#ifdef LEAP_SUPPORT - // Update CkipFlag - pAd->StaCfg.CkipFlag = CkipFlag; - - // Keep TimeStamp for Re-Association used. - if (LEAP_CCKM_ON(pAd) && (pAd->StaCfg.CCKMLinkUpFlag == TRUE)) - pAd->StaCfg.CCKMBeaconAtJoinTimeStamp = TimeStamp; -#endif // LEAP_SUPPORT // - if (AironetCellPowerLimit != 0xFF) { //We need to change our TxPower for CCX 2.0 AP Control of Client Transmit Power @@ -1018,14 +979,6 @@ VOID PeerBeacon( UCHAR AddHtInfoLen; UCHAR NewExtChannelOffset = 0xff; - -#ifdef RALINK_ATE - if (ATE_ON(pAd)) - { - return; - } -#endif // RALINK_ATE // - if (!(INFRA_ON(pAd) || ADHOC_ON(pAd) )) return; @@ -1093,14 +1046,12 @@ VOID PeerBeacon( if (pAd->Mlme.CntlMachine.CurrState == CNTL_WAIT_DISASSOC) return; -#ifdef DOT11_N_SUPPORT // Copy Control channel for this BSSID. if (AddHtInfoLen != 0) Channel = AddHtInfo.ControlChan; if ((HtCapabilityLen > 0) || (PreNHtCapabilityLen > 0)) HtCapabilityLen = SIZE_HT_CAP_IE; -#endif // DOT11_N_SUPPORT // // // Housekeeping "SsidBssTab" table for later-on ROAMing usage. @@ -1165,6 +1116,10 @@ VOID PeerBeacon( // Add the safeguard against the mismatch of adhoc wep status if (pAd->StaCfg.WepStatus != pAd->ScanTab.BssEntry[Bssidx].WepStatus) { +#ifdef RT30xx + DBGPRINT(RT_DEBUG_TRACE, ("SYNC - Not matched wep status %d %d\n", pAd->StaCfg.WepStatus, pAd->ScanTab.BssEntry[Bssidx].WepStatus)); + DBGPRINT(RT_DEBUG_TRACE, ("bssid=%s\n", pAd->ScanTab.BssEntry[Bssidx].Bssid)); +#endif return; } @@ -1228,11 +1183,14 @@ VOID PeerBeacon( pAd->CommonCfg.TxPowerPercentage = pAd->CommonCfg.TxPowerDefault; } +#ifdef RT2860 // at least one 11b peer joined. downgrade the MaxTxRate to 11Mbps // after last 11b peer left for several seconds, we'll auto switch back to 11G rate // in MlmePeriodicExec() +#endif if (ADHOC_ON(pAd) && (CAP_IS_IBSS_ON(CapabilityInfo))) { +#ifdef RT2860 BOOLEAN bRestart; BOOLEAN bnRestart; @@ -1260,7 +1218,7 @@ VOID PeerBeacon( pAd->StaCfg.Last11bBeaconRxTime = Now; break; } -#ifdef DOT11_N_SUPPORT + // Update Ht Phy. if ((pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) { @@ -1316,7 +1274,6 @@ VOID PeerBeacon( } else -#endif // DOT11_N_SUPPORT // { RTMPZeroMemory(&pAd->MlmeAux.HtCapability, SIZE_HT_CAP_IE); RTMPZeroMemory(&pAd->MlmeAux.AddHtInfo, SIZE_ADD_HT_INFO_IE); @@ -1330,7 +1287,6 @@ VOID PeerBeacon( MakeIbssBeacon(pAd); // re-build BEACON frame AsicEnableIbssSync(pAd); // copy to on-chip memory } -#ifdef DOT11_N_SUPPORT else if ((bRestart == TRUE) && (bnRestart == TRUE)) { MlmeUpdateTxRates(pAd, FALSE, BSS0); @@ -1338,7 +1294,6 @@ VOID PeerBeacon( MakeIbssBeacon(pAd); // re-build BEACON frame AsicEnableIbssSync(pAd); // copy to on-chip memory } -#endif // DOT11_N_SUPPORT // // At least another peer in this IBSS, declare MediaState as CONNECTED if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) @@ -1402,29 +1357,12 @@ VOID PeerBeacon( } MlmeUpdateTxRates(pAd, FALSE, 0); } -#ifdef DOT11_N_SUPPORT else { MlmeUpdateTxRates(pAd, FALSE, 0); MlmeUpdateHtTxRates(pAd, BSS0); } -#endif // DOT11_N_SUPPORT // -#ifdef WPA_SUPPLICANT_SUPPORT -#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT - if (pAd->StaCfg.WpaSupplicantUP) - { - union iwreq_data wrqu; - - SendAssocIEsToWpaSupplicant(pAd); - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.flags = RT_ASSOC_EVENT_FLAG; - wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); - } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // -#endif // WPA_SUPPLICANT_SUPPORT // - -#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT { union iwreq_data wrqu; wext_notify_event_assoc(pAd); @@ -1434,10 +1372,82 @@ VOID PeerBeacon( wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // } } } +#endif /* RT2860 */ +#ifdef RT2870 + UCHAR MaxSupportedRateIn500Kbps = 0; + UCHAR idx; + MAC_TABLE_ENTRY *pEntry; + + // supported rates array may not be sorted. sort it and find the maximum rate + for (idx=0; idxWcid == RESERVED_WCID)) || + (pEntry && ((pEntry->LastBeaconRxTime + ADHOC_ENTRY_BEACON_LOST_TIME) < Now))) + { + if (pEntry == NULL) + // Another adhoc joining, add to our MAC table. + pEntry = MacTableInsertEntry(pAd, Addr2, BSS0, FALSE); + + if (StaAddMacTableEntry(pAd, pEntry, MaxSupportedRateIn500Kbps, &HtCapability, HtCapabilityLen, CapabilityInfo) == FALSE) + { + DBGPRINT(RT_DEBUG_TRACE, ("ADHOC - Add Entry failed.\n")); + return; + } + + if (pEntry && + (Elem->Wcid == RESERVED_WCID)) + { + idx = pAd->StaCfg.DefaultKeyId; + RT28XX_STA_SECURITY_INFO_ADD(pAd, BSS0, idx, pEntry); + } + } + + if (pEntry && pEntry->ValidAsCLI) + pEntry->LastBeaconRxTime = Now; + + // At least another peer in this IBSS, declare MediaState as CONNECTED + if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) + { + OPSTATUS_SET_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED); + + pAd->IndicateMediaState = NdisMediaStateConnected; + RTMP_IndicateMediaState(pAd); + pAd->ExtraInfo = GENERAL_LINK_UP; + AsicSetBssid(pAd, pAd->CommonCfg.Bssid); + + // 2003/03/12 - john + // Make sure this entry in "ScanTab" table, thus complies to Microsoft's policy that + // "site survey" result should always include the current connected network. + // + Bssidx = BssTableSearch(&pAd->ScanTab, Bssid, Channel); + if (Bssidx == BSS_NOT_FOUND) + { + Bssidx = BssTableSetEntry(pAd, &pAd->ScanTab, Bssid, Ssid, SsidLen, BssType, BeaconPeriod, + &CfParm, AtimWin, CapabilityInfo, SupRate, SupRateLen, ExtRate, ExtRateLen, &HtCapability, + &AddHtInfo, HtCapabilityLen, AddHtInfoLen, NewExtChannelOffset, Channel, RealRssi, TimeStamp, 0, + &EdcaParm, &QosCapability, &QbssLoad, LenVIE, pVIE); + } + DBGPRINT(RT_DEBUG_TRACE, ("ADHOC fOP_STATUS_MEDIA_STATE_CONNECTED.\n")); + } +#endif /* RT2870 */ } if (INFRA_ON(pAd)) @@ -1476,7 +1486,6 @@ VOID PeerBeacon( DBGPRINT(RT_DEBUG_WARN, ("SYNC - AP changed B/G protection to %d\n", bUseBGProtection)); } -#ifdef DOT11_N_SUPPORT // check Ht protection mode. and adhere to the Non-GF device indication by AP. if ((AddHtInfoLen != 0) && ((AddHtInfo.AddHtInfo2.OperaionMode != pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode) || @@ -1493,7 +1502,6 @@ VOID PeerBeacon( DBGPRINT(RT_DEBUG_TRACE, ("SYNC - AP changed N OperaionMode to %d\n", pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode)); } -#endif // DOT11_N_SUPPORT // if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED) && ERP_IS_USE_BARKER_PREAMBLE(Erp)) @@ -1528,10 +1536,12 @@ VOID PeerBeacon( // 5. otherwise, put PHY back to sleep to save battery. if (MessageToMe) { +#ifdef RT2860 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE)) { RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, pAd->StaCfg.BBPR3); } +#endif if (pAd->CommonCfg.bAPSDCapable && pAd->CommonCfg.APEdcaParm.bAPSDCapable && pAd->CommonCfg.bAPSDAC_BE && pAd->CommonCfg.bAPSDAC_BK && pAd->CommonCfg.bAPSDAC_VI && pAd->CommonCfg.bAPSDAC_VO) { @@ -1542,10 +1552,12 @@ VOID PeerBeacon( } else if (BcastFlag && (DtimCount == 0) && OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_RECEIVE_DTIM)) { +#ifdef RT2860 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE)) { RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, pAd->StaCfg.BBPR3); } +#endif } else if ((pAd->TxSwQueue[QID_AC_BK].Number != 0) || (pAd->TxSwQueue[QID_AC_BE].Number != 0) || @@ -1559,10 +1571,12 @@ VOID PeerBeacon( { // TODO: consider scheduled HCCA. might not be proper to use traditional DTIM-based power-saving scheme // can we cheat here (i.e. just check MGMT & AC_BE) for better performance? +#ifdef RT2860 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE)) { RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, pAd->StaCfg.BBPR3); } +#endif } else { @@ -1577,10 +1591,14 @@ VOID PeerBeacon( if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) { +#ifdef RT2860 // Set a flag to go to sleep . Then after parse this RxDoneInterrupt, will go to sleep mode. RTMP_SET_PSFLAG(pAd, fRTMP_PS_GO_TO_SLEEP_NOW); pAd->ThisTbttNumToNextWakeUp = TbttNumToNextWakeUp; - //AsicSleepThenAutoWakeup(pAd, TbttNumToNextWakeUp); +#endif +#ifdef RT2870 + AsicSleepThenAutoWakeup(pAd, TbttNumToNextWakeUp); +#endif } } } @@ -1603,9 +1621,7 @@ VOID PeerProbeReqAction( UCHAR Addr2[MAC_ADDR_LEN]; CHAR Ssid[MAX_LEN_OF_SSID]; UCHAR SsidLen; -#ifdef DOT11_N_SUPPORT UCHAR HtLen, AddHtLen, NewExtLen; -#endif // DOT11_N_SUPPORT // HEADER_802_11 ProbeRspHdr; NDIS_STATUS NStatus; PUCHAR pOutBuffer = NULL; @@ -1678,7 +1694,7 @@ VOID PeerProbeReqAction( END_OF_ARGS); FrameLen += tmp; } -#ifdef DOT11_N_SUPPORT + if (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) { ULONG TmpLen; @@ -1711,7 +1727,7 @@ VOID PeerProbeReqAction( } FrameLen += TmpLen; } -#endif // DOT11_N_SUPPORT // + MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); MlmeFreeMemory(pAd, pOutBuffer); } @@ -1811,14 +1827,6 @@ VOID InvalidStateWhenStart( VOID EnqueuePsPoll( IN PRTMP_ADAPTER pAd) { -#ifdef RALINK_ATE - if (ATE_ON(pAd)) - { - return; - } -#endif // RALINK_ATE // - - if (pAd->StaCfg.WindowsPowerMode == Ndis802_11PowerModeLegacy_PSP) pAd->PsPollFrame.FC.PwrMgmt = PWR_SAVE; MiniportMMRequest(pAd, 0, (PUCHAR)&pAd->PsPollFrame, sizeof(PSPOLL_FRAME)); @@ -1861,88 +1869,6 @@ VOID EnqueueProbeRequest( } -#ifdef DOT11_N_SUPPORT -#ifdef DOT11N_DRAFT3 -VOID BuildEffectedChannelList( - IN PRTMP_ADAPTER pAd) -{ - UCHAR EChannel[11]; - UCHAR i, j, k; - UCHAR UpperChannel = 0, LowerChannel = 0; - - RTMPZeroMemory(EChannel, 11); - i = 0; - // Find upper channel and lower channel. - if (pAd->CommonCfg.CentralChannel < pAd->CommonCfg.Channel) - { - UpperChannel = pAd->CommonCfg.Channel; - LowerChannel = pAd->CommonCfg.CentralChannel; - } - else if (pAd->CommonCfg.CentralChannel > pAd->CommonCfg.Channel) - { - UpperChannel = pAd->CommonCfg.CentralChannel; - LowerChannel = pAd->CommonCfg.Channel; - } - else - { - return; - } - - // Record channels that is below lower channel.. - if (LowerChannel > 1) - { - EChannel[0] = LowerChannel - 1; - i = 1; - if (LowerChannel > 2) - { - EChannel[1] = LowerChannel - 2; - i = 2; - if (LowerChannel > 3) - { - EChannel[2] = LowerChannel - 3; - i = 3; - } - } - } - // Record channels that is between lower channel and upper channel. - for (k = LowerChannel;k < UpperChannel;k++) - { - EChannel[i] = k; - i++; - } - // Record channels that is above upper channel.. - if (LowerChannel < 11) - { - EChannel[i] = UpperChannel + 1; - i++; - if (LowerChannel < 10) - { - EChannel[i] = LowerChannel + 2; - i++; - if (LowerChannel < 9) - { - EChannel[i] = LowerChannel + 3; - i++; - } - } - } - // - for (j = 0;j < i;j++) - { - for (k = 0;k < pAd->ChannelListNum;k++) - { - if (pAd->ChannelList[k].Channel == EChannel[j]) - { - pAd->ChannelList[k].bEffectedChannel = TRUE; - DBGPRINT(RT_DEBUG_TRACE,(" EffectedChannel( =%d)\n", EChannel[j])); - break; - } - } - } -} -#endif // DOT11N_DRAFT3 // -#endif // DOT11_N_SUPPORT // - BOOLEAN ScanRunning( IN PRTMP_ADAPTER pAd) { diff --git a/drivers/staging/rt2860/sta/wpa.c b/drivers/staging/rt2860/sta/wpa.c index 2609d845fd5c..58274364d78c 100644 --- a/drivers/staging/rt2860/sta/wpa.c +++ b/drivers/staging/rt2860/sta/wpa.c @@ -1384,10 +1384,12 @@ VOID WpaGroupMsg1Action( pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_TKIP; else if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption3Enabled) pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_AES; +#ifndef RT30xx else if (pAd->StaCfg.GroupCipher == Ndis802_11GroupWEP40Enabled) pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_WEP64; else if (pAd->StaCfg.GroupCipher == Ndis802_11GroupWEP104Enabled) pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_WEP128; +#endif //hex_dump("Group Key :", pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, LEN_TKIP_EK); } @@ -1764,7 +1766,12 @@ BOOLEAN ParseKeyData( // Get GTK length - refer to IEEE 802.11i-2004 p.82 GTKLEN = pKDE->Len -6; +#ifdef RT30xx + if (GTKLEN < LEN_AES_KEY) +#endif +#ifndef RT30xx if (GTKLEN < MIN_LEN_OF_GTK) +#endif { DBGPRINT(RT_DEBUG_ERROR, ("ERROR: GTK Key length is too short (%d) \n", GTKLEN)); return FALSE; @@ -1790,10 +1797,12 @@ BOOLEAN ParseKeyData( pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_TKIP; else if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption3Enabled) pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_AES; +#ifndef RT30xx else if (pAd->StaCfg.GroupCipher == Ndis802_11GroupWEP40Enabled) pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_WEP64; else if (pAd->StaCfg.GroupCipher == Ndis802_11GroupWEP104Enabled) pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_WEP128; +#endif return TRUE; @@ -1915,8 +1924,6 @@ VOID RTMPReportMicError( } } - -#ifdef WPA_SUPPLICANT_SUPPORT #define LENGTH_EAP_H 4 // If the received frame is EAP-Packet ,find out its EAP-Code (Request(0x01), Response(0x02), Success(0x03), Failure(0x04)). INT WpaCheckEapCode( @@ -1957,7 +1964,6 @@ VOID WpaSendMicFailureToWpaSupplicant( return; } -#endif // WPA_SUPPLICANT_SUPPORT // VOID WpaMicFailureReportFrame( IN PRTMP_ADAPTER pAd, diff --git a/drivers/staging/rt2860/sta_ioctl.c b/drivers/staging/rt2860/sta_ioctl.c index c5452f152a21..eb0109ad2fc0 100644 --- a/drivers/staging/rt2860/sta_ioctl.c +++ b/drivers/staging/rt2860/sta_ioctl.c @@ -49,10 +49,6 @@ extern ULONG RTDebugLevel; #define GROUP_KEY_NO 4 -#define IWE_STREAM_ADD_EVENT(_A, _B, _C, _D, _E) iwe_stream_add_event(_A, _B, _C, _D, _E) -#define IWE_STREAM_ADD_POINT(_A, _B, _C, _D, _E) iwe_stream_add_point(_A, _B, _C, _D, _E) -#define IWE_STREAM_ADD_VALUE(_A, _B, _C, _D, _E, _F) iwe_stream_add_value(_A, _B, _C, _D, _E, _F) - extern UCHAR CipherWpa2Template[]; extern UCHAR CipherWpaPskTkip[]; extern UCHAR CipherWpaPskTkipLen; @@ -89,12 +85,12 @@ struct iw_priv_args privtab[] = { 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "radio_off" }, { RAIO_ON, 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "radio_on" }, -#ifdef QOS_DLS_SUPPORT - { SHOW_DLS_ENTRY_INFO, - 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "dlsentryinfo" }, -#endif // QOS_DLS_SUPPORT // { SHOW_CFG_VALUE, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "show" }, +#if !defined(RT2860) && !defined(RT30xx) + { SHOW_ADHOC_ENTRY_INFO, + 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "adhocEntry" }, +#endif /* --- sub-ioctls relations --- */ #ifdef DBG @@ -104,6 +100,11 @@ struct iw_priv_args privtab[] = { { RTPRIV_IOCTL_MAC, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | 1024, "mac"}, +#ifdef RT30xx +{ RTPRIV_IOCTL_RF, + IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, + "rf"}, +#endif // RT30xx // { RTPRIV_IOCTL_E2P, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | 1024, "e2p"}, @@ -168,16 +169,16 @@ INT Set_PSMode_Proc( IN PRTMP_ADAPTER pAdapter, IN PUCHAR arg); -#ifdef WPA_SUPPLICANT_SUPPORT INT Set_Wpa_Support( IN PRTMP_ADAPTER pAd, IN PUCHAR arg); -#endif // WPA_SUPPLICANT_SUPPORT // #ifdef DBG +#if !defined(RT2860) && !defined(RT30xx) VOID RTMPIoctlBBP( IN PRTMP_ADAPTER pAdapter, IN struct iwreq *wrq); +#endif VOID RTMPIoctlMAC( IN PRTMP_ADAPTER pAdapter, @@ -186,6 +187,12 @@ VOID RTMPIoctlMAC( VOID RTMPIoctlE2PROM( IN PRTMP_ADAPTER pAdapter, IN struct iwreq *wrq); + +#ifdef RT30xx +VOID RTMPIoctlRF( + IN PRTMP_ADAPTER pAdapter, + IN struct iwreq *wrq); +#endif // RT30xx // #endif // DBG // @@ -197,11 +204,9 @@ INT Set_FragTest_Proc( IN PRTMP_ADAPTER pAdapter, IN PUCHAR arg); -#ifdef DOT11_N_SUPPORT INT Set_TGnWifiTest_Proc( IN PRTMP_ADAPTER pAd, IN PUCHAR arg); -#endif // DOT11_N_SUPPORT // INT Set_LongRetryLimit_Proc( IN PRTMP_ADAPTER pAdapter, @@ -211,17 +216,11 @@ INT Set_ShortRetryLimit_Proc( IN PRTMP_ADAPTER pAdapter, IN PUCHAR arg); -#ifdef EXT_BUILD_CHANNEL_LIST -INT Set_Ieee80211dClientMode_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); -#endif // EXT_BUILD_CHANNEL_LIST // - -#ifdef CARRIER_DETECTION_SUPPORT -INT Set_CarrierDetect_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); -#endif // CARRIER_DETECTION_SUPPORT // +#if !defined(RT2860) && !defined(RT30xx) +INT Show_Adhoc_MacTable_Proc( + IN PRTMP_ADAPTER pAd, + IN PCHAR extra); +#endif static struct { CHAR *name; @@ -239,7 +238,6 @@ static struct { {"BGProtection", Set_BGProtection_Proc}, {"RTSThreshold", Set_RTSThreshold_Proc}, {"FragThreshold", Set_FragThreshold_Proc}, -#ifdef DOT11_N_SUPPORT {"HtBw", Set_HtBw_Proc}, {"HtMcs", Set_HtMcs_Proc}, {"HtGi", Set_HtGi_Proc}, @@ -253,8 +251,6 @@ static struct { {"HtBaDecline", Set_BADecline_Proc}, {"HtProtect", Set_HtProtect_Proc}, {"HtMimoPs", Set_HtMimoPs_Proc}, -#endif // DOT11_N_SUPPORT // - #ifdef AGGREGATION_SUPPORT {"PktAggregate", Set_PktAggregate_Proc}, #endif @@ -277,68 +273,19 @@ static struct { #ifdef DBG {"Debug", Set_Debug_Proc}, #endif - -#ifdef RALINK_ATE - {"ATE", Set_ATE_Proc}, - {"ATEDA", Set_ATE_DA_Proc}, - {"ATESA", Set_ATE_SA_Proc}, - {"ATEBSSID", Set_ATE_BSSID_Proc}, - {"ATECHANNEL", Set_ATE_CHANNEL_Proc}, - {"ATETXPOW0", Set_ATE_TX_POWER0_Proc}, - {"ATETXPOW1", Set_ATE_TX_POWER1_Proc}, - {"ATETXANT", Set_ATE_TX_Antenna_Proc}, - {"ATERXANT", Set_ATE_RX_Antenna_Proc}, - {"ATETXFREQOFFSET", Set_ATE_TX_FREQOFFSET_Proc}, - {"ATETXBW", Set_ATE_TX_BW_Proc}, - {"ATETXLEN", Set_ATE_TX_LENGTH_Proc}, - {"ATETXCNT", Set_ATE_TX_COUNT_Proc}, - {"ATETXMCS", Set_ATE_TX_MCS_Proc}, - {"ATETXMODE", Set_ATE_TX_MODE_Proc}, - {"ATETXGI", Set_ATE_TX_GI_Proc}, - {"ATERXFER", Set_ATE_RX_FER_Proc}, - {"ATERRF", Set_ATE_Read_RF_Proc}, - {"ATEWRF1", Set_ATE_Write_RF1_Proc}, - {"ATEWRF2", Set_ATE_Write_RF2_Proc}, - {"ATEWRF3", Set_ATE_Write_RF3_Proc}, - {"ATEWRF4", Set_ATE_Write_RF4_Proc}, - {"ATELDE2P", Set_ATE_Load_E2P_Proc}, - {"ATERE2P", Set_ATE_Read_E2P_Proc}, - {"ATESHOW", Set_ATE_Show_Proc}, - {"ATEHELP", Set_ATE_Help_Proc}, - -#ifdef RALINK_28xx_QA - {"TxStop", Set_TxStop_Proc}, - {"RxStop", Set_RxStop_Proc}, -#endif // RALINK_28xx_QA // -#endif // RALINK_ATE // - -#ifdef WPA_SUPPLICANT_SUPPORT {"WpaSupport", Set_Wpa_Support}, -#endif // WPA_SUPPLICANT_SUPPORT // - - - {"FixedTxMode", Set_FixedTxMode_Proc}, -#ifdef CONFIG_APSTA_MIXED_SUPPORT - {"OpMode", Set_OpMode_Proc}, -#endif // CONFIG_APSTA_MIXED_SUPPORT // -#ifdef DOT11_N_SUPPORT {"TGnWifiTest", Set_TGnWifiTest_Proc}, {"ForceGF", Set_ForceGF_Proc}, -#endif // DOT11_N_SUPPORT // -#ifdef QOS_DLS_SUPPORT - {"DlsAddEntry", Set_DlsAddEntry_Proc}, - {"DlsTearDownEntry", Set_DlsTearDownEntry_Proc}, -#endif // QOS_DLS_SUPPORT // {"LongRetry", Set_LongRetryLimit_Proc}, {"ShortRetry", Set_ShortRetryLimit_Proc}, -#ifdef EXT_BUILD_CHANNEL_LIST - {"11dClientMode", Set_Ieee80211dClientMode_Proc}, -#endif // EXT_BUILD_CHANNEL_LIST // -#ifdef CARRIER_DETECTION_SUPPORT - {"CarrierDetect", Set_CarrierDetect_Proc}, -#endif // CARRIER_DETECTION_SUPPORT // - +//2008/09/11:KH add to support efuse<-- +#ifdef RT30xx + {"efuseFreeNumber", set_eFuseGetFreeBlockCount_Proc}, + {"efuseDump", set_eFusedump_Proc}, + {"efuseLoadFromBin", set_eFuseLoadFromBin_Proc}, +#endif // RT30xx // +//2008/09/11:KH add to support efuse--> {NULL,} }; @@ -352,6 +299,7 @@ VOID RTMPAddKey( DBGPRINT(RT_DEBUG_TRACE, ("RTMPAddKey ------>\n")); +#ifdef RT2860 RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_CAN_GO_SLEEP); if (RTMP_TEST_PSFLAG(pAd, fRTMP_PS_SET_PCI_CLK_OFF_COMMAND)) { @@ -365,6 +313,7 @@ VOID RTMPAddKey( RTMPusecDelay(6000); pAd->bPCIclkOff = FALSE; } +#endif if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) { @@ -380,14 +329,13 @@ VOID RTMPAddKey( NdisZeroMemory(&pAd->SharedKey[BSS0][0], sizeof(CIPHER_KEY)); pAd->SharedKey[BSS0][0].KeyLen = LEN_TKIP_EK; NdisMoveMemory(pAd->SharedKey[BSS0][0].Key, pKey->KeyMaterial, LEN_TKIP_EK); -#ifdef WPA_SUPPLICANT_SUPPORT + if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled) { NdisMoveMemory(pAd->SharedKey[BSS0][0].RxMic, pKey->KeyMaterial + LEN_TKIP_EK, LEN_TKIP_TXMICK); NdisMoveMemory(pAd->SharedKey[BSS0][0].TxMic, pKey->KeyMaterial + LEN_TKIP_EK + LEN_TKIP_TXMICK, LEN_TKIP_RXMICK); } else -#endif // WPA_SUPPLICANT_SUPPORT // { NdisMoveMemory(pAd->SharedKey[BSS0][0].TxMic, pKey->KeyMaterial + LEN_TKIP_EK, LEN_TKIP_TXMICK); NdisMoveMemory(pAd->SharedKey[BSS0][0].RxMic, pKey->KeyMaterial + LEN_TKIP_EK + LEN_TKIP_TXMICK, LEN_TKIP_RXMICK); @@ -440,14 +388,13 @@ VOID RTMPAddKey( NdisZeroMemory(&pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId], sizeof(CIPHER_KEY)); pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].KeyLen = LEN_TKIP_EK; NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, pKey->KeyMaterial, LEN_TKIP_EK); -#ifdef WPA_SUPPLICANT_SUPPORT + if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption2Enabled) { NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic, pKey->KeyMaterial + LEN_TKIP_EK, LEN_TKIP_TXMICK); NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, pKey->KeyMaterial + LEN_TKIP_EK + LEN_TKIP_TXMICK, LEN_TKIP_RXMICK); } else -#endif // WPA_SUPPLICANT_SUPPORT // { NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, pKey->KeyMaterial + LEN_TKIP_EK, LEN_TKIP_TXMICK); NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic, pKey->KeyMaterial + LEN_TKIP_EK + LEN_TKIP_TXMICK, LEN_TKIP_RXMICK); @@ -559,8 +506,10 @@ VOID RTMPAddKey( } } end: +#ifdef RT2860 RTMP_SET_PSFLAG(pAd, fRTMP_PS_CAN_GO_SLEEP); DBGPRINT(RT_DEBUG_INFO, ("<------ RTMPAddKey\n")); +#endif return; } @@ -582,8 +531,12 @@ rt_ioctl_giwname(struct net_device *dev, char *name, char *extra) { // PRTMP_ADAPTER pAdapter = dev->ml_priv; - +#ifdef RT2860 strncpy(name, "RT2860 Wireless", IFNAMSIZ); +#endif +#ifdef RT2870 + strncpy(name, "RT2870 Wireless", IFNAMSIZ); +#endif // RT2870 // return 0; } @@ -625,7 +578,12 @@ int rt_ioctl_giwfreq(struct net_device *dev, struct iw_freq *freq, char *extra) { VIRTUAL_ADAPTER *pVirtualAd = NULL; +#ifndef RT30xx PRTMP_ADAPTER pAdapter = NULL; +#endif +#ifdef RT30xx + PRTMP_ADAPTER pAdapter; +#endif UCHAR ch; ULONG m; @@ -636,7 +594,9 @@ int rt_ioctl_giwfreq(struct net_device *dev, else { pVirtualAd = dev->ml_priv; +#ifndef RT30xx if (pVirtualAd && pVirtualAd->RtmpDev) +#endif pAdapter = pVirtualAd->RtmpDev->ml_priv; } @@ -696,6 +656,7 @@ int rt_ioctl_giwmode(struct net_device *dev, struct iw_request_info *info, __u32 *mode, char *extra) { +#ifndef RT30xx PRTMP_ADAPTER pAdapter = NULL; VIRTUAL_ADAPTER *pVirtualAd = NULL; @@ -716,6 +677,10 @@ int rt_ioctl_giwmode(struct net_device *dev, So the net_dev->ml_priv will be NULL in 2rd open */ return -ENETDOWN; } +#endif +#ifdef RT30xx + PRTMP_ADAPTER pAdapter = dev->ml_priv; +#endif if (ADHOC_ON(pAdapter)) *mode = IW_MODE_ADHOC; @@ -759,12 +724,18 @@ int rt_ioctl_giwrange(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *extra) { +#ifndef RT30xx PRTMP_ADAPTER pAdapter = NULL; VIRTUAL_ADAPTER *pVirtualAd = NULL; +#endif +#ifdef RT30xx + PRTMP_ADAPTER pAdapter = dev->ml_priv; +#endif struct iw_range *range = (struct iw_range *) extra; u16 val; int i; +#ifndef RT30xx if (dev->priv_flags == INT_MAIN) { pAdapter = dev->ml_priv; @@ -782,6 +753,7 @@ int rt_ioctl_giwrange(struct net_device *dev, So the net_dev->ml_priv will be NULL in 2rd open */ return -ENETDOWN; } +#endif DBGPRINT(RT_DEBUG_TRACE ,("===>rt_ioctl_giwrange\n")); data->length = sizeof(struct iw_range); @@ -901,6 +873,7 @@ int rt_ioctl_giwap(struct net_device *dev, struct iw_request_info *info, struct sockaddr *ap_addr, char *extra) { +#ifndef RT30xx PRTMP_ADAPTER pAdapter = NULL; VIRTUAL_ADAPTER *pVirtualAd = NULL; @@ -921,20 +894,22 @@ int rt_ioctl_giwap(struct net_device *dev, So the net_dev->ml_priv will be NULL in 2rd open */ return -ENETDOWN; } +#endif +#ifdef RT30xx + PRTMP_ADAPTER pAdapter = dev->ml_priv; +#endif if (INFRA_ON(pAdapter) || ADHOC_ON(pAdapter)) { ap_addr->sa_family = ARPHRD_ETHER; memcpy(ap_addr->sa_data, &pAdapter->CommonCfg.Bssid, ETH_ALEN); } -#ifdef WPA_SUPPLICANT_SUPPORT // Add for RT2870 else if (pAdapter->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_DISABLE) { ap_addr->sa_family = ARPHRD_ETHER; memcpy(ap_addr->sa_data, &pAdapter->MlmeAux.Bssid, ETH_ALEN); } -#endif // WPA_SUPPLICANT_SUPPORT // else { DBGPRINT(RT_DEBUG_TRACE, ("IOCTL::SIOCGIWAP(=EMPTY)\n")); @@ -1041,7 +1016,7 @@ int rt_ioctl_siwscan(struct net_device *dev, DBGPRINT(RT_DEBUG_TRACE, ("!!! Driver is in Monitor Mode now !!!\n")); return -EINVAL; } - +#ifdef RT2860 if ((pAdapter->OpMode == OPMODE_STA) && (IDLE_ON(pAdapter)) && (pAdapter->StaCfg.bRadio == TRUE) && (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_IDLE_RADIO_OFF))) @@ -1051,13 +1026,11 @@ int rt_ioctl_siwscan(struct net_device *dev, // Check if still radio off. else if (pAdapter->bPCIclkOff == TRUE) return 0; - -#ifdef WPA_SUPPLICANT_SUPPORT +#endif if (pAdapter->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_ENABLE) { pAdapter->StaCfg.WpaSupplicantScanCount++; } -#endif // WPA_SUPPLICANT_SUPPORT // pAdapter->StaCfg.bScanReqIsFromWebUI = TRUE; if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) @@ -1065,7 +1038,6 @@ int rt_ioctl_siwscan(struct net_device *dev, do{ Now = jiffies; -#ifdef WPA_SUPPLICANT_SUPPORT if ((pAdapter->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_ENABLE) && (pAdapter->StaCfg.WpaSupplicantScanCount > 3)) { @@ -1073,7 +1045,6 @@ int rt_ioctl_siwscan(struct net_device *dev, Status = NDIS_STATUS_SUCCESS; break; } -#endif // WPA_SUPPLICANT_SUPPORT // if ((OPSTATUS_TEST_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED)) && ((pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || @@ -1133,13 +1104,10 @@ int rt_ioctl_giwscan(struct net_device *dev, return -EAGAIN; } - -#ifdef WPA_SUPPLICANT_SUPPORT if (pAdapter->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_ENABLE) { pAdapter->StaCfg.WpaSupplicantScanCount = 0; } -#endif // WPA_SUPPLICANT_SUPPORT // if (pAdapter->ScanTab.BssNr == 0) { @@ -1175,7 +1143,88 @@ int rt_ioctl_giwscan(struct net_device *dev, memcpy(iwe.u.ap_addr.sa_data, &pAdapter->ScanTab.BssEntry[i].Bssid, ETH_ALEN); previous_ev = current_ev; - current_ev = IWE_STREAM_ADD_EVENT(info, 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); +#ifdef RT30xx + if (current_ev == previous_ev) +#if WIRELESS_EXT >= 17 + return -E2BIG; +#else + break; +#endif + + /* + Protocol: + it will show scanned AP's WirelessMode . + it might be + 802.11a + 802.11a/n + 802.11g/n + 802.11b/g/n + 802.11g + 802.11b/g + */ + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWNAME; + + + { + PBSS_ENTRY pBssEntry=&pAdapter->ScanTab.BssEntry[i]; + BOOLEAN isGonly=FALSE; + int rateCnt=0; + + if (pBssEntry->Channel>14) + { + if (pBssEntry->HtCapabilityLen!=0) + strcpy(iwe.u.name,"802.11a/n"); + else + strcpy(iwe.u.name,"802.11a"); + } + else + { + /* + if one of non B mode rate is set supported rate . it mean G only. + */ + for (rateCnt=0;rateCntSupRateLen;rateCnt++) + { + /* + 6Mbps(140) 9Mbps(146) and >=12Mbps(152) are supported rate , it mean G only. + */ + if (pBssEntry->SupRate[rateCnt]==140 || pBssEntry->SupRate[rateCnt]==146 || pBssEntry->SupRate[rateCnt]>=152) + isGonly=TRUE; + } + + for (rateCnt=0;rateCntExtRateLen;rateCnt++) + { + if (pBssEntry->ExtRate[rateCnt]==140 || pBssEntry->ExtRate[rateCnt]==146 || pBssEntry->ExtRate[rateCnt]>=152) + isGonly=TRUE; + } + + + if (pBssEntry->HtCapabilityLen!=0) + { + if (isGonly==TRUE) + strcpy(iwe.u.name,"802.11g/n"); + else + strcpy(iwe.u.name,"802.11b/g/n"); + } + else + { + if (isGonly==TRUE) + strcpy(iwe.u.name,"802.11g"); + else + { + if (pBssEntry->SupRateLen==4 && pBssEntry->ExtRateLen==0) + strcpy(iwe.u.name,"802.11b"); + else + strcpy(iwe.u.name,"802.11b/g"); + } + } + } + } + + previous_ev = current_ev; + current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_ADDR_LEN); +#endif /* RT30xx */ if (current_ev == previous_ev) #if WIRELESS_EXT >= 17 return -E2BIG; @@ -1191,7 +1240,7 @@ int rt_ioctl_giwscan(struct net_device *dev, iwe.u.data.flags = 1; previous_ev = current_ev; - current_ev = IWE_STREAM_ADD_POINT(info, current_ev,end_buf, &iwe, pAdapter->ScanTab.BssEntry[i].Ssid); + current_ev = iwe_stream_add_point(info, current_ev,end_buf, &iwe, pAdapter->ScanTab.BssEntry[i].Ssid); if (current_ev == previous_ev) #if WIRELESS_EXT >= 17 return -E2BIG; @@ -1218,7 +1267,7 @@ int rt_ioctl_giwscan(struct net_device *dev, iwe.len = IW_EV_UINT_LEN; previous_ev = current_ev; - current_ev = IWE_STREAM_ADD_EVENT(info, 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); if (current_ev == previous_ev) #if WIRELESS_EXT >= 17 return -E2BIG; @@ -1238,7 +1287,7 @@ int rt_ioctl_giwscan(struct net_device *dev, iwe.u.freq.i = 0; previous_ev = current_ev; - current_ev = IWE_STREAM_ADD_EVENT(info, 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 (current_ev == previous_ev) #if WIRELESS_EXT >= 17 return -E2BIG; @@ -1253,7 +1302,7 @@ int rt_ioctl_giwscan(struct net_device *dev, iwe.u.qual.level = 0; iwe.u.qual.noise = 0; set_quality(pAdapter, &iwe.u.qual, pAdapter->ScanTab.BssEntry[i].Rssi); - current_ev = IWE_STREAM_ADD_EVENT(info, 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); if (current_ev == previous_ev) #if WIRELESS_EXT >= 17 return -E2BIG; @@ -1271,7 +1320,7 @@ int rt_ioctl_giwscan(struct net_device *dev, iwe.u.data.flags = IW_ENCODE_DISABLED; previous_ev = current_ev; - current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf,&iwe, (char *)pAdapter->SharedKey[BSS0][(iwe.u.data.flags & IW_ENCODE_INDEX)-1].Key); + current_ev = iwe_stream_add_point(info, current_ev, end_buf,&iwe, (char *)pAdapter->SharedKey[BSS0][(iwe.u.data.flags & IW_ENCODE_INDEX)-1].Key); if (current_ev == previous_ev) #if WIRELESS_EXT >= 17 return -E2BIG; @@ -1299,7 +1348,7 @@ int rt_ioctl_giwscan(struct net_device *dev, iwe.u.bitrate.value = (tmpRate/2) * 1000000; iwe.u.bitrate.disabled = 0; - current_val = IWE_STREAM_ADD_VALUE(info, current_ev, + current_val = iwe_stream_add_value(info, current_ev, current_val, end_buf, &iwe, IW_EV_PARAM_LEN); @@ -1323,7 +1372,7 @@ int rt_ioctl_giwscan(struct net_device *dev, pAdapter->ScanTab.BssEntry[i].WpaIE.IELen); iwe.cmd = IWEVGENIE; iwe.u.data.length = pAdapter->ScanTab.BssEntry[i].WpaIE.IELen; - current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe, custom); + current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, custom); if (current_ev == previous_ev) #if WIRELESS_EXT >= 17 return -E2BIG; @@ -1341,7 +1390,7 @@ int rt_ioctl_giwscan(struct net_device *dev, pAdapter->ScanTab.BssEntry[i].RsnIE.IELen); iwe.cmd = IWEVGENIE; iwe.u.data.length = pAdapter->ScanTab.BssEntry[i].RsnIE.IELen; - current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe, custom); + current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, custom); if (current_ev == previous_ev) #if WIRELESS_EXT >= 17 return -E2BIG; @@ -1360,9 +1409,9 @@ int rt_ioctl_giwscan(struct net_device *dev, iwe.u.data.length = (pAdapter->ScanTab.BssEntry[i].WpaIE.IELen * 2) + 7; NdisMoveMemory(custom, "wpa_ie=", 7); for (idx = 0; idx < pAdapter->ScanTab.BssEntry[i].WpaIE.IELen; idx++) - sprintf(custom, "%s%02x", custom, pAdapter->ScanTab.BssEntry[i].WpaIE.IE[idx]); + sprintf(custom + strlen(custom), "%02x", pAdapter->ScanTab.BssEntry[i].WpaIE.IE[idx]); previous_ev = current_ev; - current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe, custom); + current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, custom); if (current_ev == previous_ev) #if WIRELESS_EXT >= 17 return -E2BIG; @@ -1380,9 +1429,9 @@ int rt_ioctl_giwscan(struct net_device *dev, iwe.u.data.length = (pAdapter->ScanTab.BssEntry[i].RsnIE.IELen * 2) + 7; NdisMoveMemory(custom, "rsn_ie=", 7); for (idx = 0; idx < pAdapter->ScanTab.BssEntry[i].RsnIE.IELen; idx++) - sprintf(custom, "%s%02x", custom, pAdapter->ScanTab.BssEntry[i].RsnIE.IE[idx]); + sprintf(custom + strlen(custom), "%02x", pAdapter->ScanTab.BssEntry[i].RsnIE.IE[idx]); previous_ev = current_ev; - current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe, custom); + current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, custom); if (current_ev == previous_ev) #if WIRELESS_EXT >= 17 return -E2BIG; @@ -1445,6 +1494,7 @@ int rt_ioctl_giwessid(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *essid) { +#ifndef RT30xx PRTMP_ADAPTER pAdapter = NULL; VIRTUAL_ADAPTER *pVirtualAd = NULL; @@ -1465,6 +1515,10 @@ int rt_ioctl_giwessid(struct net_device *dev, So the net_dev->ml_priv will be NULL in 2rd open */ return -ENETDOWN; } +#endif +#ifdef RT30xx + PRTMP_ADAPTER pAdapter = dev->ml_priv; +#endif data->flags = 1; if (MONITOR_ON(pAdapter)) @@ -1479,6 +1533,14 @@ int rt_ioctl_giwessid(struct net_device *dev, data->length = pAdapter->CommonCfg.SsidLen; memcpy(essid, pAdapter->CommonCfg.Ssid, pAdapter->CommonCfg.SsidLen); } +#ifdef RT2870 + // Add for RT2870 + else if (pAdapter->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_DISABLE) + { + data->length = pAdapter->CommonCfg.SsidLen; + memcpy(essid, pAdapter->CommonCfg.Ssid, pAdapter->CommonCfg.SsidLen); + } +#endif // RT2870 // else {//the ANY ssid was specified data->length = 0; @@ -1516,6 +1578,7 @@ int rt_ioctl_giwnickn(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *nickname) { +#ifndef RT30xx PRTMP_ADAPTER pAdapter = NULL; VIRTUAL_ADAPTER *pVirtualAd = NULL; @@ -1536,6 +1599,10 @@ int rt_ioctl_giwnickn(struct net_device *dev, So the net_dev->ml_priv will be NULL in 2rd open */ return -ENETDOWN; } +#endif +#ifdef RT30xx + PRTMP_ADAPTER pAdapter = dev->ml_priv; +#endif if (data->length > strlen(pAdapter->nickname) + 1) data->length = strlen(pAdapter->nickname) + 1; @@ -1579,6 +1646,7 @@ int rt_ioctl_giwrts(struct net_device *dev, struct iw_request_info *info, struct iw_param *rts, char *extra) { +#ifndef RT30xx PRTMP_ADAPTER pAdapter = NULL; VIRTUAL_ADAPTER *pVirtualAd = NULL; @@ -1599,6 +1667,10 @@ int rt_ioctl_giwrts(struct net_device *dev, So the net_dev->ml_priv will be NULL in 2rd open */ return -ENETDOWN; } +#endif +#ifdef RT30xx + PRTMP_ADAPTER pAdapter = dev->ml_priv; +#endif //check if the interface is down if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) @@ -1645,6 +1717,7 @@ int rt_ioctl_giwfrag(struct net_device *dev, struct iw_request_info *info, struct iw_param *frag, char *extra) { +#ifndef RT30xx PRTMP_ADAPTER pAdapter = NULL; VIRTUAL_ADAPTER *pVirtualAd = NULL; @@ -1665,6 +1738,10 @@ int rt_ioctl_giwfrag(struct net_device *dev, So the net_dev->ml_priv will be NULL in 2rd open */ return -ENETDOWN; } +#endif +#ifdef RT30xx + PRTMP_ADAPTER pAdapter = dev->ml_priv; +#endif //check if the interface is down if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) @@ -1705,8 +1782,13 @@ int rt_ioctl_siwencode(struct net_device *dev, pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; goto done; } +#ifndef RT30xx else if ((erq->length == 0) && (erq->flags & IW_ENCODE_RESTRICTED || erq->flags & IW_ENCODE_OPEN)) +#endif +#ifdef RT30xx + else if (erq->flags & IW_ENCODE_RESTRICTED || erq->flags & IW_ENCODE_OPEN) +#endif { STA_PORT_SECURED(pAdapter); pAdapter->StaCfg.PairCipher = Ndis802_11WEPEnabled; @@ -1717,7 +1799,9 @@ int rt_ioctl_siwencode(struct net_device *dev, pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeShared; else pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; +#ifndef RT30xx goto done; +#endif } if (erq->length > 0) @@ -1736,6 +1820,12 @@ int rt_ioctl_siwencode(struct net_device *dev, //Using default key keyIdx = pAdapter->StaCfg.DefaultKeyId; } +#ifdef RT30xx + else + { + pAdapter->StaCfg.DefaultKeyId=keyIdx; + } +#endif NdisZeroMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, 16); @@ -1787,7 +1877,11 @@ rt_ioctl_giwencode(struct net_device *dev, struct iw_request_info *info, struct iw_point *erq, char *key) { +#ifdef RT30xx + PRTMP_ADAPTER pAdapter = dev->ml_priv; +#endif int kid; +#ifndef RT30xx PRTMP_ADAPTER pAdapter = NULL; VIRTUAL_ADAPTER *pVirtualAd = NULL; @@ -1808,6 +1902,7 @@ rt_ioctl_giwencode(struct net_device *dev, So the net_dev->ml_priv will be NULL in 2rd open */ return -ENETDOWN; } +#endif //check if the interface is down if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) @@ -1952,14 +2047,6 @@ rt_private_get_statistics(struct net_device *dev, struct iw_request_info *info, memset(extra, 0x00, IW_PRIV_SIZE_MASK); sprintf(extra, "\n\n"); -#ifdef RALINK_ATE - if (ATE_ON(pAd)) - { - sprintf(extra+strlen(extra), "Tx success = %ld\n", (ULONG)pAd->ate.TxDoneCount); - //sprintf(extra+strlen(extra), "Tx success without retry = %ld\n", (ULONG)pAd->ate.TxDoneCount); - } - else -#endif // RALINK_ATE // { sprintf(extra+strlen(extra), "Tx success = %ld\n", (ULONG)pAd->WlanCounters.TransmittedFragmentCount.QuadPart); sprintf(extra+strlen(extra), "Tx success without retry = %ld\n", (ULONG)pAd->WlanCounters.TransmittedFragmentCount.QuadPart - (ULONG)pAd->WlanCounters.RetryCount.QuadPart); @@ -1975,31 +2062,12 @@ rt_private_get_statistics(struct net_device *dev, struct iw_request_info *info, sprintf(extra+strlen(extra), "Rx duplicate frame = %ld\n", (ULONG)pAd->WlanCounters.FrameDuplicateCount.QuadPart); sprintf(extra+strlen(extra), "False CCA (one second) = %ld\n", (ULONG)pAd->RalinkCounters.OneSecFalseCCACnt); -#ifdef RALINK_ATE - if (ATE_ON(pAd)) - { - if (pAd->ate.RxAntennaSel == 0) - { - sprintf(extra+strlen(extra), "RSSI-A = %ld\n", (LONG)(pAd->ate.LastRssi0 - pAd->BbpRssiToDbmDelta)); - sprintf(extra+strlen(extra), "RSSI-B (if available) = %ld\n", (LONG)(pAd->ate.LastRssi1 - pAd->BbpRssiToDbmDelta)); - sprintf(extra+strlen(extra), "RSSI-C (if available) = %ld\n\n", (LONG)(pAd->ate.LastRssi2 - pAd->BbpRssiToDbmDelta)); - } - else - { - sprintf(extra+strlen(extra), "RSSI = %ld\n", (LONG)(pAd->ate.LastRssi0 - pAd->BbpRssiToDbmDelta)); - } - } - else -#endif // RALINK_ATE // { sprintf(extra+strlen(extra), "RSSI-A = %ld\n", (LONG)(pAd->StaCfg.RssiSample.LastRssi0 - pAd->BbpRssiToDbmDelta)); sprintf(extra+strlen(extra), "RSSI-B (if available) = %ld\n", (LONG)(pAd->StaCfg.RssiSample.LastRssi1 - pAd->BbpRssiToDbmDelta)); sprintf(extra+strlen(extra), "RSSI-C (if available) = %ld\n\n", (LONG)(pAd->StaCfg.RssiSample.LastRssi2 - pAd->BbpRssiToDbmDelta)); } -#ifdef WPA_SUPPLICANT_SUPPORT sprintf(extra+strlen(extra), "WpaSupplicantUP = %d\n\n", pAd->StaCfg.WpaSupplicantUP); -#endif // WPA_SUPPLICANT_SUPPORT // - wrq->length = strlen(extra) + 1; // 1: size of '\0' DBGPRINT(RT_DEBUG_TRACE, ("<== rt_private_get_statistics, wrq->length = %d\n", wrq->length)); @@ -2007,7 +2075,6 @@ rt_private_get_statistics(struct net_device *dev, struct iw_request_info *info, return Status; } -#ifdef DOT11_N_SUPPORT void getBaInfo( IN PRTMP_ADAPTER pAd, IN PUCHAR pOutBuf) @@ -2022,8 +2089,7 @@ void getBaInfo( if (((pEntry->ValidAsCLI || pEntry->ValidAsApCli) && (pEntry->Sst == SST_ASSOC)) || (pEntry->ValidAsWDS) || (pEntry->ValidAsMesh)) { - sprintf(pOutBuf, "%s\n%02X:%02X:%02X:%02X:%02X:%02X (Aid = %d) (AP) -\n", - pOutBuf, + sprintf(pOutBuf + strlen(pOutBuf), "\n%02X:%02X:%02X:%02X:%02X:%02X (Aid = %d) (AP) -\n", pEntry->Addr[0], pEntry->Addr[1], pEntry->Addr[2], pEntry->Addr[3], pEntry->Addr[4], pEntry->Addr[5], pEntry->Aid); @@ -2033,7 +2099,7 @@ void getBaInfo( if (pEntry->BARecWcidArray[j] != 0) { pRecBAEntry =&pAd->BATable.BARecEntry[pEntry->BARecWcidArray[j]]; - sprintf(pOutBuf, "%sTID=%d, BAWinSize=%d, LastIndSeq=%d, ReorderingPkts=%d\n", pOutBuf, j, pRecBAEntry->BAWinSize, pRecBAEntry->LastIndSeq, pRecBAEntry->list.qlen); + sprintf(pOutBuf + strlen(pOutBuf), "TID=%d, BAWinSize=%d, LastIndSeq=%d, ReorderingPkts=%d\n", j, pRecBAEntry->BAWinSize, pRecBAEntry->LastIndSeq, pRecBAEntry->list.qlen); } } sprintf(pOutBuf, "%s\n", pOutBuf); @@ -2044,7 +2110,7 @@ void getBaInfo( if (pEntry->BAOriWcidArray[j] != 0) { pOriBAEntry =&pAd->BATable.BAOriEntry[pEntry->BAOriWcidArray[j]]; - sprintf(pOutBuf, "%sTID=%d, BAWinSize=%d, StartSeq=%d, CurTxSeq=%d\n", pOutBuf, j, pOriBAEntry->BAWinSize, pOriBAEntry->Sequence, pEntry->TxSeq[j]); + sprintf(pOutBuf + strlen(pOutBuf), "TID=%d, BAWinSize=%d, StartSeq=%d, CurTxSeq=%d\n", j, pOriBAEntry->BAWinSize, pOriBAEntry->Sequence, pEntry->TxSeq[j]); } } sprintf(pOutBuf, "%s\n\n", pOutBuf); @@ -2055,7 +2121,6 @@ void getBaInfo( return; } -#endif // DOT11_N_SUPPORT // static int rt_private_show(struct net_device *dev, struct iw_request_info *info, @@ -2101,12 +2166,10 @@ rt_private_show(struct net_device *dev, struct iw_request_info *info, case SHOW_CONN_STATUS: if (MONITOR_ON(pAd)) { -#ifdef DOT11_N_SUPPORT if (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED && pAd->CommonCfg.RegTransmitSetting.field.BW) sprintf(extra, "Monitor Mode(CentralChannel %d)\n", pAd->CommonCfg.CentralChannel); else -#endif // DOT11_N_SUPPORT // sprintf(extra, "Monitor Mode(Channel %d)\n", pAd->CommonCfg.Channel); } else @@ -2140,12 +2203,10 @@ rt_private_show(struct net_device *dev, struct iw_request_info *info, sprintf(extra, "Driver version-%s, %s %s\n", STA_DRIVER_VERSION, __DATE__, __TIME__ ); wrq->length = strlen(extra) + 1; // 1: size of '\0' break; -#ifdef DOT11_N_SUPPORT case SHOW_BA_INFO: getBaInfo(pAd, extra); wrq->length = strlen(extra) + 1; // 1: size of '\0' break; -#endif // DOT11_N_SUPPORT // case SHOW_DESC_INFO: { Show_DescInfo_Proc(pAd, NULL); @@ -2174,6 +2235,14 @@ rt_private_show(struct net_device *dev, struct iw_request_info *info, wrq->length = strlen(extra) + 1; // 1: size of '\0' break; case RAIO_ON: +#ifdef RT2870 + if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) + { + sprintf(extra, "Scanning\n"); + wrq->length = strlen(extra) + 1; // 1: size of '\0' + break; + } +#endif pAd->StaCfg.bSwRadio = TRUE; //if (pAd->StaCfg.bRadio != (pAd->StaCfg.bHwRadio && pAd->StaCfg.bSwRadio)) { @@ -2189,16 +2258,6 @@ rt_private_show(struct net_device *dev, struct iw_request_info *info, wrq->length = strlen(extra) + 1; // 1: size of '\0' break; - -#ifdef QOS_DLS_SUPPORT - case SHOW_DLS_ENTRY_INFO: - { - Set_DlsEntryInfo_Display_Proc(pAd, NULL); - wrq->length = 0; // 1: size of '\0' - } - break; -#endif // QOS_DLS_SUPPORT // - case SHOW_CFG_VALUE: { Status = RTMPShowCfgValue(pAd, wrq->pointer, extra); @@ -2206,6 +2265,12 @@ rt_private_show(struct net_device *dev, struct iw_request_info *info, wrq->length = strlen(extra) + 1; // 1: size of '\0' } break; +#if !defined(RT2860) && !defined(RT30xx) + case SHOW_ADHOC_ENTRY_INFO: + Show_Adhoc_MacTable_Proc(pAd, extra); + wrq->length = strlen(extra) + 1; // 1: size of '\0' + break; +#endif default: DBGPRINT(RT_DEBUG_TRACE, ("%s - unknow subcmd = %d\n", __func__, subcmd)); break; @@ -2312,9 +2377,7 @@ int rt_ioctl_siwauth(struct net_device *dev, pAdapter->StaCfg.WepStatus = Ndis802_11WEPEnabled; pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; pAdapter->StaCfg.PairCipher = Ndis802_11WEPEnabled; -#ifdef WPA_SUPPLICANT_SUPPORT pAdapter->StaCfg.IEEE8021X = FALSE; -#endif // WPA_SUPPLICANT_SUPPORT // } else if (param->value == IW_AUTH_CIPHER_TKIP) { @@ -2356,22 +2419,16 @@ int rt_ioctl_siwauth(struct net_device *dev, if (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) { pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA; -#ifdef WPA_SUPPLICANT_SUPPORT pAdapter->StaCfg.IEEE8021X = FALSE; -#endif // WPA_SUPPLICANT_SUPPORT // } else if (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) { pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA2; -#ifdef WPA_SUPPLICANT_SUPPORT pAdapter->StaCfg.IEEE8021X = FALSE; -#endif // WPA_SUPPLICANT_SUPPORT // } -#ifdef WPA_SUPPLICANT_SUPPORT else // WEP 1x pAdapter->StaCfg.IEEE8021X = TRUE; -#endif // WPA_SUPPLICANT_SUPPORT // } else if (param->value == 0) { @@ -2457,6 +2514,7 @@ void fnSetCipherKey( IN BOOLEAN bGTK, IN struct iw_encode_ext *ext) { +#ifdef RT2860 RTMP_CLEAR_PSFLAG(pAdapter, fRTMP_PS_CAN_GO_SLEEP); if (RTMP_TEST_PSFLAG(pAdapter, fRTMP_PS_SET_PCI_CLK_OFF_COMMAND)) { @@ -2470,7 +2528,7 @@ void fnSetCipherKey( RTMPusecDelay(6000); pAdapter->bPCIclkOff = FALSE; } - +#endif NdisZeroMemory(&pAdapter->SharedKey[BSS0][keyIdx], sizeof(CIPHER_KEY)); pAdapter->SharedKey[BSS0][keyIdx].KeyLen = LEN_TKIP_EK; NdisMoveMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, ext->key, LEN_TKIP_EK); @@ -2501,8 +2559,9 @@ void fnSetCipherKey( keyIdx, pAdapter->SharedKey[BSS0][keyIdx].CipherAlg, &pAdapter->MacTab.Content[BSSID_WCID]); - +#ifdef RT2860 RTMP_SET_PSFLAG(pAdapter, fRTMP_PS_CAN_GO_SLEEP); +#endif } int rt_ioctl_siwencodeext(struct net_device *dev, @@ -2567,7 +2626,7 @@ int rt_ioctl_siwencodeext(struct net_device *dev, NdisZeroMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, 16); NdisMoveMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, ext->key, ext->key_len); - +#ifndef RT30xx if (pAdapter->StaCfg.GroupCipher == Ndis802_11GroupWEP40Enabled || pAdapter->StaCfg.GroupCipher == Ndis802_11GroupWEP104Enabled) { @@ -2582,6 +2641,7 @@ int rt_ioctl_siwencodeext(struct net_device *dev, // Indicate Connected for GUI pAdapter->IndicateMediaState = NdisMediaStateConnected; } +#endif break; case IW_ENCODE_ALG_TKIP: DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_TKIP - keyIdx = %d, ext->key_len = %d\n", __func__, keyIdx, ext->key_len)); @@ -2752,7 +2812,6 @@ int rt_ioctl_giwgenie(struct net_device *dev, return 0; } -#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT #ifdef SIOCSIWGENIE if (pAd->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_ENABLE) { @@ -2764,7 +2823,6 @@ int rt_ioctl_giwgenie(struct net_device *dev, } else #endif // SIOCSIWGENIE // -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // { UCHAR RSNIe = IE_WPA; @@ -2895,15 +2953,13 @@ rt_private_ioctl_bbp(struct net_device *dev, struct iw_request_info *info, DBGPRINT(RT_DEBUG_TRACE, ("this_char=%s, value=%s\n", this_char, value)); if (sscanf(this_char, "%d", &(bbpId)) == 1) { +#ifndef RT30xx if (bbpId <= 136) +#endif // RT30xx // +#ifdef RT30xx + if (bbpId <= 138) // edit by johnli, RF power sequence setup, add BBP R138 for ADC dynamic on/off control +#endif // RT30xx // { -#ifdef RALINK_ATE - if (ATE_ON(pAdapter)) - { - ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); - } - else -#endif // RALINK_ATE // { RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); } @@ -2927,17 +2983,13 @@ rt_private_ioctl_bbp(struct net_device *dev, struct iw_request_info *info, { //Write if ((sscanf(this_char, "%d", &(bbpId)) == 1) && (sscanf(value, "%x", &(bbpValue)) == 1)) { +#ifndef RT30xx if (bbpId <= 136) +#endif // RT30xx // +#ifdef RT30xx + if (bbpId <= 138) // edit by johnli, RF power sequence setup, add BBP R138 for ADC dynamic on/off control +#endif // RT30xx // { -#ifdef RALINK_ATE - if (ATE_ON(pAdapter)) - { - ATE_BBP_IO_WRITE8_BY_REG_ID(pAdapter, bbpId, bbpValue); - //Read it back for showing - ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); - } - else -#endif // RALINK_ATE // { RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, bbpId, bbpValue); //Read it back for showing @@ -2968,21 +3020,24 @@ next: { memset(extra, 0x00, IW_PRIV_SIZE_MASK); sprintf(extra, "\n"); +#ifndef RT30xx for (bbpId = 0; bbpId <= 136; bbpId++) +#endif // RT30xx // +#ifdef RT30xx + for (bbpId = 0; bbpId <= 138; bbpId++) // edit by johnli, RF power sequence setup, add BBP R138 for ADC dynamic on/off control +#endif // RT30xx // { if (strlen(extra) >= (IW_PRIV_SIZE_MASK - 10)) break; -#ifdef RALINK_ATE - if (ATE_ON(pAdapter)) - { - ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); - } - else -#endif // RALINK_ATE // RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); +#ifndef RT30xx sprintf(extra+strlen(extra), "R%02d[0x%02X]:%02X ", bbpId, bbpId*2, regBBP); if (bbpId%5 == 4) sprintf(extra+strlen(extra), "\n"); +#endif +#ifdef RT30xx + sprintf(extra+strlen(extra), "%03d = %02X\n", bbpId, regBBP); // edit by johnli, change display format +#endif } wrq->length = strlen(extra) + 1; // 1: size of '\0' @@ -3022,9 +3077,7 @@ int rt_ioctl_siwrate(struct net_device *dev, (pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MODE <= MODE_OFDM)) RTMPSetDesiredRates(pAd, -1); -#ifdef DOT11_N_SUPPORT SetCommonHT(pAd); -#endif // DOT11_N_SUPPORT // } else { @@ -3037,9 +3090,7 @@ int rt_ioctl_siwrate(struct net_device *dev, else { pAd->StaCfg.DesiredTransmitSetting.field.MCS = MCS_AUTO; -#ifdef DOT11_N_SUPPORT SetCommonHT(pAd); -#endif // DOT11_N_SUPPORT // } DBGPRINT(RT_DEBUG_TRACE, ("rt_ioctl_siwrate::(HtMcs=%d)\n",pAd->StaCfg.DesiredTransmitSetting.field.MCS)); } @@ -3087,13 +3138,11 @@ int rt_ioctl_giwrate(struct net_device *dev, else ht_setting.word = pAd->MacTab.Content[BSSID_WCID].HTPhyMode.word; -#ifdef DOT11_N_SUPPORT if (ht_setting.field.MODE >= MODE_HTMIX) { rate_index = 12 + ((UCHAR)ht_setting.field.BW *24) + ((UCHAR)ht_setting.field.ShortGI *48) + ((UCHAR)ht_setting.field.MCS); } else -#endif // DOT11_N_SUPPORT // if (ht_setting.field.MODE == MODE_OFDM) rate_index = (UCHAR)(ht_setting.field.MCS) + 4; else if (ht_setting.field.MODE == MODE_CCK) @@ -3184,11 +3233,7 @@ static const iw_handler rt_handler[] = static const iw_handler rt_priv_handlers[] = { (iw_handler) NULL, /* + 0x00 */ (iw_handler) NULL, /* + 0x01 */ -#ifndef CONFIG_AP_SUPPORT (iw_handler) rt_ioctl_setparam, /* + 0x02 */ -#else - (iw_handler) NULL, /* + 0x02 */ -#endif // CONFIG_AP_SUPPORT // #ifdef DBG (iw_handler) rt_private_ioctl_bbp, /* + 0x03 */ #else @@ -3258,27 +3303,13 @@ INT RTMPSetInformation( ULONG PowerTemp; BOOLEAN RadioState; BOOLEAN StateMachineTouched = FALSE; -#ifdef DOT11_N_SUPPORT OID_SET_HT_PHYMODE HT_PhyMode; //11n ,kathy -#endif // DOT11_N_SUPPORT // -#ifdef WPA_SUPPLICANT_SUPPORT PNDIS_802_11_PMKID pPmkId = NULL; BOOLEAN IEEE8021xState = FALSE; BOOLEAN IEEE8021x_required_keys = FALSE; UCHAR wpa_supplicant_enable = 0; -#endif // WPA_SUPPLICANT_SUPPORT // -#ifdef SNMP_SUPPORT - TX_RTY_CFG_STRUC tx_rty_cfg; - ULONG ShortRetryLimit, LongRetryLimit; - UCHAR ctmp; -#endif // SNMP_SUPPORT // - - -#ifdef DOT11_N_SUPPORT MaxPhyMode = PHY_11N_5G; -#endif // DOT11_N_SUPPORT // - DBGPRINT(RT_DEBUG_TRACE, ("-->RTMPSetInformation(), 0x%08x\n", cmd&0x7FFF)); switch(cmd & 0x7FFF) { @@ -3298,21 +3329,12 @@ INT RTMPSetInformation( pAdapter->CommonCfg.PhyMode = 0xff; // Build all corresponding channel information RTMPSetPhyMode(pAdapter, TmpPhy); -#ifdef DOT11_N_SUPPORT SetCommonHT(pAdapter); -#endif // DOT11_N_SUPPORT // DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_COUNTRY_REGION (A:%d B/G:%d)\n", pAdapter->CommonCfg.CountryRegionForABand, pAdapter->CommonCfg.CountryRegion)); } break; case OID_802_11_BSSID_LIST_SCAN: - #ifdef RALINK_ATE - if (ATE_ON(pAdapter)) - { - DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now\n")); - break; - } -#endif // RALINK_ATE // Now = jiffies; DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_BSSID_LIST_SCAN, TxCnt = %d \n", pAdapter->RalinkCounters.LastOneSecTotalTxCount)); @@ -3414,13 +3436,6 @@ INT RTMPSetInformation( } break; case OID_802_11_BSSID: -#ifdef RALINK_ATE - if (ATE_ON(pAdapter)) - { - DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now\n")); - break; - } -#endif // RALINK_ATE // if (wrq->u.data.length != sizeof(NDIS_802_11_MAC_ADDRESS)) Status = -EINVAL; else @@ -3492,9 +3507,7 @@ INT RTMPSetInformation( if (PhyMode <= MaxPhyMode) { RTMPSetPhyMode(pAdapter, PhyMode); -#ifdef DOT11_N_SUPPORT SetCommonHT(pAdapter); -#endif // DOT11_N_SUPPORT // } DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_PHY_MODE (=%d)\n", PhyMode)); } @@ -3513,9 +3526,14 @@ INT RTMPSetInformation( { // allow dynamic change of "USE OFDM rate or not" in ADHOC mode // if setting changed, need to reset current TX rate as well as BEACON frame format +#ifdef RT30xx + pAdapter->CommonCfg.PhyMode = StaConfig.AdhocMode; +#endif if (pAdapter->StaCfg.BssType == BSS_ADHOC) { +#ifndef RT30xx pAdapter->CommonCfg.PhyMode = StaConfig.AdhocMode; +#endif RTMPSetPhyMode(pAdapter, PhyMode); MlmeUpdateTxRates(pAdapter, FALSE, 0); MakeIbssBeacon(pAdapter); // re-build BEACON frame @@ -3679,6 +3697,15 @@ INT RTMPSetInformation( pAdapter->Counters8023.RxNoBuffer = 0; pAdapter->Counters8023.GoodReceives = 0; pAdapter->Counters8023.RxNoBuffer = 0; +#ifdef RT2870 + pAdapter->BulkOutComplete = 0; + pAdapter->BulkOutCompleteOther= 0; + pAdapter->BulkOutCompleteCancel = 0; + pAdapter->BulkOutReq = 0; + pAdapter->BulkInReq= 0; + pAdapter->BulkInComplete = 0; + pAdapter->BulkInCompleteFail = 0; +#endif // RT2870 // DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_RESET_COUNTERS \n")); break; case OID_802_11_RTS_THRESHOLD: @@ -3763,10 +3790,10 @@ INT RTMPSetInformation( RTMPSetPhyMode(pAdapter, PHY_11A); else Status = -EINVAL; -#ifdef DOT11_N_SUPPORT + if (Status == NDIS_STATUS_SUCCESS) SetCommonHT(pAdapter); -#endif // DOT11_N_SUPPORT // + DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_NETWORK_TYPE_IN_USE (=%d)\n",NetType)); } break; @@ -3910,7 +3937,6 @@ INT RTMPSetInformation( pAdapter->bConfigChanged = TRUE; } break; -#ifdef DOT11_N_SUPPORT case RT_OID_802_11_SET_HT_PHYMODE: if (wrq->u.data.length != sizeof(OID_SET_HT_PHYMODE)) Status = -EINVAL; @@ -3929,7 +3955,6 @@ INT RTMPSetInformation( pAdapter->StaCfg.HTPhyMode.field.MCS, pAdapter->StaCfg.HTPhyMode.field.BW, pAdapter->StaCfg.HTPhyMode.field.ShortGI, pAdapter->StaCfg.HTPhyMode.field.STBC)); break; -#endif // DOT11_N_SUPPORT // case RT_OID_802_11_SET_APSD_SETTING: if (wrq->u.data.length != sizeof(ULONG)) Status = -EINVAL; @@ -3970,62 +3995,7 @@ INT RTMPSetInformation( DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_SET_APSD_PSM (bAPSDForcePowerSave:%d)\n", pAdapter->CommonCfg.bAPSDForcePowerSave)); } break; -#ifdef QOS_DLS_SUPPORT - case RT_OID_802_11_SET_DLS: - if (wrq->u.data.length != sizeof(ULONG)) - Status = -EINVAL; - else - { - BOOLEAN oldvalue = pAdapter->CommonCfg.bDLSCapable; - Status = copy_from_user(&pAdapter->CommonCfg.bDLSCapable, wrq->u.data.pointer, wrq->u.data.length); - if (oldvalue && !pAdapter->CommonCfg.bDLSCapable) - { - int i; - // tear down local dls table entry - for (i=0; iStaCfg.DLSEntry[i].Valid && (pAdapter->StaCfg.DLSEntry[i].Status == DLS_FINISH)) - { - pAdapter->StaCfg.DLSEntry[i].Status = DLS_NONE; - pAdapter->StaCfg.DLSEntry[i].Valid = FALSE; - RTMPSendDLSTearDownFrame(pAdapter, pAdapter->StaCfg.DLSEntry[i].MacAddr); - } - } - // tear down peer dls table entry - for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid && (pAdapter->StaCfg.DLSEntry[i].Status == DLS_FINISH)) - { - pAdapter->StaCfg.DLSEntry[i].Status = DLS_NONE; - pAdapter->StaCfg.DLSEntry[i].Valid = FALSE; - RTMPSendDLSTearDownFrame(pAdapter, pAdapter->StaCfg.DLSEntry[i].MacAddr); - } - } - } - - DBGPRINT(RT_DEBUG_TRACE,("Set::RT_OID_802_11_SET_DLS (=%d)\n", pAdapter->CommonCfg.bDLSCapable)); - } - break; - - case RT_OID_802_11_SET_DLS_PARAM: - if (wrq->u.data.length != sizeof(RT_802_11_DLS_UI)) - Status = -EINVAL; - else - { - RT_802_11_DLS Dls; - - NdisZeroMemory(&Dls, sizeof(RT_802_11_DLS)); - RTMPMoveMemory(&Dls, wrq->u.data.pointer, sizeof(RT_802_11_DLS_UI)); - MlmeEnqueue(pAdapter, - MLME_CNTL_STATE_MACHINE, - RT_OID_802_11_SET_DLS_PARAM, - sizeof(RT_802_11_DLS), - &Dls); - DBGPRINT(RT_DEBUG_TRACE,("Set::RT_OID_802_11_SET_DLS_PARAM \n")); - } - break; -#endif // QOS_DLS_SUPPORT // case RT_OID_802_11_SET_WMM: if (wrq->u.data.length != sizeof(BOOLEAN)) Status = -EINVAL; @@ -4037,13 +4007,6 @@ INT RTMPSetInformation( break; case OID_802_11_DISASSOCIATE: -#ifdef RALINK_ATE - if (ATE_ON(pAdapter)) - { - DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now\n")); - break; - } -#endif // RALINK_ATE // // // Set NdisRadioStateOff to TRUE, instead of called MlmeRadioOff. // Later on, NDIS_802_11_BSSID_LIST_EX->NumberOfItems should be 0 @@ -4074,8 +4037,6 @@ INT RTMPSetInformation( StateMachineTouched = TRUE; } break; - -#ifdef DOT11_N_SUPPORT case RT_OID_802_11_SET_IMME_BA_CAP: if (wrq->u.data.length != sizeof(OID_BACAP_STRUC)) Status = -EINVAL; @@ -4230,8 +4191,6 @@ INT RTMPSetInformation( } } break; -#endif // DOT11_N_SUPPORT // - // For WPA_SUPPLICANT to set static wep key case OID_802_11_ADD_WEP: pWepKey = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); @@ -4285,19 +4244,21 @@ INT RTMPSetInformation( // Default key for tx (shared key) if (pWepKey->KeyIndex & 0x80000000) { -#ifdef WPA_SUPPLICANT_SUPPORT // set key material and key length NdisZeroMemory(pAdapter->StaCfg.DesireSharedKey[KeyIdx].Key, 16); pAdapter->StaCfg.DesireSharedKey[KeyIdx].KeyLen = (UCHAR) pWepKey->KeyLength; NdisMoveMemory(pAdapter->StaCfg.DesireSharedKey[KeyIdx].Key, &pWepKey->KeyMaterial, pWepKey->KeyLength); pAdapter->StaCfg.DesireSharedKeyId = KeyIdx; pAdapter->StaCfg.DesireSharedKey[KeyIdx].CipherAlg = CipherAlg; -#endif // WPA_SUPPLICANT_SUPPORT // pAdapter->StaCfg.DefaultKeyId = (UCHAR) KeyIdx; } - -#ifdef WPA_SUPPLICANT_SUPPORT +#ifndef RT30xx +#ifdef RT2860 if ((pAdapter->StaCfg.WpaSupplicantUP != 0) && +#endif +#ifdef RT2870 + if ((pAdapter->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_DISABLE) && +#endif (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA)) { Key = pWepKey->KeyMaterial; @@ -4314,7 +4275,10 @@ INT RTMPSetInformation( pAdapter->IndicateMediaState = NdisMediaStateConnected; } else if (pAdapter->StaCfg.PortSecured == WPA_802_1X_PORT_SECURED) -#endif // WPA_SUPPLICANT_SUPPORT +#endif +#ifdef RT30xx + if (pAdapter->StaCfg.PortSecured == WPA_802_1X_PORT_SECURED) +#endif { Key = pAdapter->SharedKey[BSS0][KeyIdx].Key; @@ -4335,7 +4299,6 @@ INT RTMPSetInformation( } kfree(pWepKey); break; -#ifdef WPA_SUPPLICANT_SUPPORT case OID_SET_COUNTERMEASURES: if (wrq->u.data.length != sizeof(int)) Status = -EINVAL; @@ -4469,95 +4432,6 @@ INT RTMPSetInformation( if(pPmkId) kfree(pPmkId); break; -#endif // WPA_SUPPLICANT_SUPPORT // - - - -#ifdef SNMP_SUPPORT - case OID_802_11_SHORTRETRYLIMIT: - if (wrq->u.data.length != sizeof(ULONG)) - Status = -EINVAL; - else - { - Status = copy_from_user(&ShortRetryLimit, wrq->u.data.pointer, wrq->u.data.length); - RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); - tx_rty_cfg.field.ShortRtyLimit = ShortRetryLimit; - RTMP_IO_WRITE32(pAdapter, TX_RTY_CFG, tx_rty_cfg.word); - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_SHORTRETRYLIMIT (tx_rty_cfg.field.ShortRetryLimit=%d, ShortRetryLimit=%ld)\n", tx_rty_cfg.field.ShortRtyLimit, ShortRetryLimit)); - } - break; - - case OID_802_11_LONGRETRYLIMIT: - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_LONGRETRYLIMIT \n")); - if (wrq->u.data.length != sizeof(ULONG)) - Status = -EINVAL; - else - { - Status = copy_from_user(&LongRetryLimit, wrq->u.data.pointer, wrq->u.data.length); - RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); - tx_rty_cfg.field.LongRtyLimit = LongRetryLimit; - RTMP_IO_WRITE32(pAdapter, TX_RTY_CFG, tx_rty_cfg.word); - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_LONGRETRYLIMIT (tx_rty_cfg.field.LongRetryLimit= %d,LongRetryLimit=%ld)\n", tx_rty_cfg.field.LongRtyLimit, LongRetryLimit)); - } - break; - - case OID_802_11_WEPDEFAULTKEYVALUE: - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_WEPDEFAULTKEYVALUE\n")); - pKey = kmalloc(wrq->u.data.length, GFP_KERNEL); - Status = copy_from_user(pKey, wrq->u.data.pointer, wrq->u.data.length); - //pKey = &WepKey; - - if ( pKey->Length != wrq->u.data.length) - { - Status = -EINVAL; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_WEPDEFAULTKEYVALUE, Failed!!\n")); - } - KeyIdx = pKey->KeyIndex & 0x0fffffff; - DBGPRINT(RT_DEBUG_TRACE,("pKey->KeyIndex =%d, pKey->KeyLength=%d\n", pKey->KeyIndex, pKey->KeyLength)); - - // it is a shared key - if (KeyIdx > 4) - Status = -EINVAL; - else - { - pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen = (UCHAR) pKey->KeyLength; - NdisMoveMemory(&pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].Key, &pKey->KeyMaterial, pKey->KeyLength); - if (pKey->KeyIndex & 0x80000000) - { - // Default key for tx (shared key) - pAdapter->StaCfg.DefaultKeyId = (UCHAR) KeyIdx; - } - //RestartAPIsRequired = TRUE; - } - break; - - - case OID_802_11_WEPDEFAULTKEYID: - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_WEPDEFAULTKEYID \n")); - - if (wrq->u.data.length != sizeof(UCHAR)) - Status = -EINVAL; - else - Status = copy_from_user(&pAdapter->StaCfg.DefaultKeyId, wrq->u.data.pointer, wrq->u.data.length); - - break; - - - case OID_802_11_CURRENTCHANNEL: - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_CURRENTCHANNEL \n")); - if (wrq->u.data.length != sizeof(UCHAR)) - Status = -EINVAL; - else - { - Status = copy_from_user(&ctmp, wrq->u.data.pointer, wrq->u.data.length); - sprintf(&ctmp,"%d", ctmp); - Set_Channel_Proc(pAdapter, &ctmp); - } - break; -#endif - - - default: DBGPRINT(RT_DEBUG_TRACE, ("Set::unknown IOCTL's subcmd = 0x%08x\n", cmd)); Status = -EOPNOTSUPP; @@ -4599,16 +4473,6 @@ INT RTMPQueryInformation( UCHAR driverVersion[8]; OID_SET_HT_PHYMODE *pHTPhyMode = NULL; - -#ifdef SNMP_SUPPORT - //for snmp, kathy - DefaultKeyIdxValue *pKeyIdxValue; - INT valueLen; - TX_RTY_CFG_STRUC tx_rty_cfg; - ULONG ShortRetryLimit, LongRetryLimit; - UCHAR tmp[64]; -#endif //SNMP - switch(cmd) { case RT_OID_DEVICE_NAME: @@ -4625,16 +4489,6 @@ INT RTMPQueryInformation( Status = -EFAULT; } break; -#ifdef RALINK_ATE - case RT_QUERY_ATE_TXDONE_COUNT: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_QUERY_ATE_TXDONE_COUNT \n")); - wrq->u.data.length = sizeof(UINT32); - if (copy_to_user(wrq->u.data.pointer, &pAdapter->ate.TxDoneCount, wrq->u.data.length)) - { - Status = -EFAULT; - } - break; -#endif // RALINK_ATE // case OID_802_11_BSSID_LIST: if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) { @@ -4776,14 +4630,6 @@ INT RTMPQueryInformation( Status = copy_to_user(wrq->u.data.pointer, &MediaState, wrq->u.data.length); break; case OID_802_11_BSSID: -#ifdef RALINK_ATE - if (ATE_ON(pAdapter)) - { - DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now\n")); - Status = NDIS_STATUS_RESOURCES; - break; - } -#endif // RALINK_ATE // if (INFRA_ON(pAdapter) || ADHOC_ON(pAdapter)) { Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.Bssid, sizeof(NDIS_802_11_MAC_ADDRESS)); @@ -5121,7 +4967,6 @@ INT RTMPQueryInformation( Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.bWmmCapable, wrq->u.data.length); DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_WMM (=%d)\n", pAdapter->CommonCfg.bWmmCapable)); break; -#ifdef WPA_SUPPLICANT_SUPPORT case RT_OID_NEW_DRIVER: { UCHAR enabled = 1; @@ -5135,8 +4980,6 @@ INT RTMPQueryInformation( Status = copy_to_user(wrq->u.data.pointer, &pAdapter->StaCfg.WpaSupplicantUP, wrq->u.data.length); DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_WPA_SUPPLICANT_SUPPORT (=%d)\n", pAdapter->StaCfg.WpaSupplicantUP)); break; -#endif // WPA_SUPPLICANT_SUPPORT // - case RT_OID_DRIVER_DEVICE_NAME: DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_DRIVER_DEVICE_NAME \n")); wrq->u.data.length = 16; @@ -5211,154 +5054,20 @@ INT RTMPQueryInformation( case RT_OID_QUERY_MULTIPLE_CARD_SUPPORT: wrq->u.data.length = sizeof(UCHAR); i = 0; -#ifdef MULTIPLE_CARD_SUPPORT - i = 1; -#endif // MULTIPLE_CARD_SUPPORT // if (copy_to_user(wrq->u.data.pointer, &i, wrq->u.data.length)) { Status = -EFAULT; } DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_QUERY_MULTIPLE_CARD_SUPPORT(=%d) \n", i)); break; -#ifdef SNMP_SUPPORT - case RT_OID_802_11_MAC_ADDRESS: - wrq->u.data.length = MAC_ADDR_LEN; - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CurrentAddress, wrq->u.data.length); - break; - - case RT_OID_802_11_MANUFACTUREROUI: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_MANUFACTUREROUI \n")); - wrq->u.data.length = ManufacturerOUI_LEN; - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CurrentAddress, wrq->u.data.length); - break; - - case RT_OID_802_11_MANUFACTURERNAME: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_MANUFACTURERNAME \n")); - wrq->u.data.length = strlen(ManufacturerNAME); - Status = copy_to_user(wrq->u.data.pointer, ManufacturerNAME, wrq->u.data.length); - break; - - case RT_OID_802_11_RESOURCETYPEIDNAME: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_RESOURCETYPEIDNAME \n")); - wrq->u.data.length = strlen(ResourceTypeIdName); - Status = copy_to_user(wrq->u.data.pointer, ResourceTypeIdName, wrq->u.data.length); - break; - - case RT_OID_802_11_PRIVACYOPTIONIMPLEMENTED: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_PRIVACYOPTIONIMPLEMENTED \n")); - ulInfo = 1; // 1 is support wep else 2 is not support. - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - break; - - case RT_OID_802_11_POWERMANAGEMENTMODE: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_POWERMANAGEMENTMODE \n")); - if (pAdapter->StaCfg.Psm == PSMP_ACTION) - ulInfo = 1; // 1 is power active else 2 is power save. - else - ulInfo = 2; - - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - break; - - case OID_802_11_WEPDEFAULTKEYVALUE: - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_WEPDEFAULTKEYVALUE \n")); - //KeyIdxValue.KeyIdx = pAd->PortCfg.MBSSID[pAd->IoctlIF].DefaultKeyId; - pKeyIdxValue = wrq->u.data.pointer; - DBGPRINT(RT_DEBUG_TRACE,("KeyIdxValue.KeyIdx = %d, \n",pKeyIdxValue->KeyIdx)); - valueLen = pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen; - NdisMoveMemory(pKeyIdxValue->Value, - &pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].Key, - valueLen); - pKeyIdxValue->Value[valueLen]='\0'; - - wrq->u.data.length = sizeof(DefaultKeyIdxValue); - - Status = copy_to_user(wrq->u.data.pointer, pKeyIdxValue, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE,("DefaultKeyId = %d, total len = %d, str len=%d, KeyValue= %02x %02x %02x %02x \n", pAdapter->StaCfg.DefaultKeyId, wrq->u.data.length, pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen, - pAdapter->SharedKey[BSS0][0].Key[0], - pAdapter->SharedKey[BSS0][1].Key[0], - pAdapter->SharedKey[BSS0][2].Key[0], - pAdapter->SharedKey[BSS0][3].Key[0])); - break; - - case OID_802_11_WEPDEFAULTKEYID: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_WEPDEFAULTKEYID \n")); - wrq->u.data.length = sizeof(UCHAR); - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->StaCfg.DefaultKeyId, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("DefaultKeyId =%d \n", pAdapter->StaCfg.DefaultKeyId)); - break; - - case RT_OID_802_11_WEPKEYMAPPINGLENGTH: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_WEPKEYMAPPINGLENGTH \n")); - wrq->u.data.length = sizeof(UCHAR); - Status = copy_to_user(wrq->u.data.pointer, - &pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen, - wrq->u.data.length); - break; - - case OID_802_11_SHORTRETRYLIMIT: - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_SHORTRETRYLIMIT \n")); - wrq->u.data.length = sizeof(ULONG); - RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); - ShortRetryLimit = tx_rty_cfg.field.ShortRtyLimit; - DBGPRINT(RT_DEBUG_TRACE, ("ShortRetryLimit =%ld, tx_rty_cfg.field.ShortRetryLimit=%d\n", ShortRetryLimit, tx_rty_cfg.field.ShortRtyLimit)); - Status = copy_to_user(wrq->u.data.pointer, &ShortRetryLimit, wrq->u.data.length); - break; - - case OID_802_11_LONGRETRYLIMIT: - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_LONGRETRYLIMIT \n")); - wrq->u.data.length = sizeof(ULONG); - RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); - LongRetryLimit = tx_rty_cfg.field.LongRtyLimit; - DBGPRINT(RT_DEBUG_TRACE, ("LongRetryLimit =%ld, tx_rty_cfg.field.LongRtyLimit=%d\n", LongRetryLimit, tx_rty_cfg.field.LongRtyLimit)); - Status = copy_to_user(wrq->u.data.pointer, &LongRetryLimit, wrq->u.data.length); - break; - - case RT_OID_802_11_PRODUCTID: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_PRODUCTID \n")); - - { - - USHORT device_id; - if (((POS_COOKIE)pAdapter->OS_Cookie)->pci_dev != NULL) - pci_read_config_word(((POS_COOKIE)pAdapter->OS_Cookie)->pci_dev, PCI_DEVICE_ID, &device_id); - else - DBGPRINT(RT_DEBUG_TRACE, (" pci_dev = NULL\n")); - sprintf(tmp, "%04x %04x\n", NIC_PCI_VENDOR_ID, device_id); - } - wrq->u.data.length = strlen(tmp); - Status = copy_to_user(wrq->u.data.pointer, tmp, wrq->u.data.length); - break; - - case RT_OID_802_11_MANUFACTUREID: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_MANUFACTUREID \n")); - wrq->u.data.length = strlen(ManufacturerNAME); - Status = copy_to_user(wrq->u.data.pointer, ManufacturerNAME, wrq->u.data.length); - break; - - case OID_802_11_CURRENTCHANNEL: - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_CURRENTCHANNEL \n")); - wrq->u.data.length = sizeof(UCHAR); - DBGPRINT(RT_DEBUG_TRACE, ("sizeof UCHAR=%d, channel=%d \n", sizeof(UCHAR), pAdapter->CommonCfg.Channel)); - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.Channel, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Status=%d\n", Status)); - break; -#endif //SNMP_SUPPORT case OID_802_11_BUILD_CHANNEL_EX: { UCHAR value; DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_BUILD_CHANNEL_EX \n")); wrq->u.data.length = sizeof(UCHAR); -#ifdef EXT_BUILD_CHANNEL_LIST - DBGPRINT(RT_DEBUG_TRACE, ("Support EXT_BUILD_CHANNEL_LIST.\n")); - value = 1; -#else DBGPRINT(RT_DEBUG_TRACE, ("Doesn't support EXT_BUILD_CHANNEL_LIST.\n")); value = 0; -#endif // EXT_BUILD_CHANNEL_LIST // Status = copy_to_user(wrq->u.data.pointer, &value, 1); DBGPRINT(RT_DEBUG_TRACE, ("Status=%d\n", Status)); } @@ -5409,35 +5118,6 @@ INT RTMPQueryInformation( DBGPRINT(RT_DEBUG_TRACE, ("Status=%d\n", Status)); break; - -#ifdef QOS_DLS_SUPPORT - case RT_OID_802_11_QUERY_DLS: - wrq->u.data.length = sizeof(BOOLEAN); - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.bDLSCapable, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_DLS(=%d)\n", pAdapter->CommonCfg.bDLSCapable)); - break; - - case RT_OID_802_11_QUERY_DLS_PARAM: - { - PRT_802_11_DLS_INFO pDlsInfo = kmalloc(sizeof(RT_802_11_DLS_INFO), GFP_ATOMIC); - if (pDlsInfo == NULL) - break; - - for (i=0; iEntry[i], &pAdapter->StaCfg.DLSEntry[i], sizeof(RT_802_11_DLS_UI)); - } - - pDlsInfo->num = MAX_NUM_OF_DLS_ENTRY; - wrq->u.data.length = sizeof(RT_802_11_DLS_INFO); - Status = copy_to_user(wrq->u.data.pointer, pDlsInfo, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_DLS_PARAM\n")); - - if (pDlsInfo) - kfree(pDlsInfo); - } - break; -#endif // QOS_DLS_SUPPORT // default: DBGPRINT(RT_DEBUG_TRACE, ("Query::unknown IOCTL's subcmd = 0x%08x\n", cmd)); Status = -EOPNOTSUPP; @@ -5480,14 +5160,6 @@ INT rt28xx_sta_ioctl( //check if the interface is down if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) { -#ifdef CONFIG_APSTA_MIXED_SUPPORT - if (wrq->u.data.pointer == NULL) - { - return Status; - } - - if (strstr(wrq->u.data.pointer, "OpMode") == NULL) -#endif // CONFIG_APSTA_MIXED_SUPPORT // { DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); return -ENETDOWN; @@ -5501,15 +5173,6 @@ INT rt28xx_sta_ioctl( switch(cmd) { -#ifdef RALINK_ATE -#ifdef RALINK_28xx_QA - case RTPRIV_IOCTL_ATE: - { - RtmpDoAte(pAd, wrq); - } - break; -#endif // RALINK_28xx_QA // -#endif // RALINK_ATE // case SIOCGIFHWADDR: DBGPRINT(RT_DEBUG_TRACE, ("IOCTL::SIOCGIFHWADDR\n")); memcpy(wrq->u.name, pAd->CurrentAddress, ETH_ALEN); @@ -5640,6 +5303,9 @@ INT rt28xx_sta_ioctl( Status = -EOPNOTSUPP; break; case RT_PRIV_IOCTL: +#ifdef RT30xx + case RT_PRIV_IOCTL_EXT: +#endif subcmd = wrq->u.data.flags; if( subcmd & OID_GET_SET_TOGGLE) Status = RTMPSetInformation(pAd, rq, subcmd); @@ -5671,6 +5337,11 @@ INT rt28xx_sta_ioctl( case RTPRIV_IOCTL_E2P: RTMPIoctlE2PROM(pAd, wrq); break; +#ifdef RT30xx + case RTPRIV_IOCTL_RF: + RTMPIoctlRF(pAd, wrq); + break; +#endif // RT30xx // #endif // DBG // case SIOCETHTOOL: break; @@ -5766,6 +5437,9 @@ INT Set_WmmCapable_Proc( bWmmCapable = simple_strtol(arg, 0, 10); if ((bWmmCapable == 1) +#ifdef RT2870 + && (pAd->NumberOfPipes >= 5) +#endif // RT2870 // ) pAd->CommonCfg.bWmmCapable = TRUE; else if (bWmmCapable == 0) @@ -5873,19 +5547,14 @@ INT Set_NetworkType_Proc( DBGPRINT(RT_DEBUG_TRACE, ("fOP_STATUS_MEDIA_STATE_CONNECTED \n")); if (pAdapter->CommonCfg.CentralChannel == 0) { -#ifdef DOT11_N_SUPPORT if (pAdapter->CommonCfg.PhyMode == PHY_11AN_MIXED) pAdapter->CommonCfg.CentralChannel = 36; else -#endif // DOT11_N_SUPPORT // pAdapter->CommonCfg.CentralChannel = 6; } -#ifdef DOT11_N_SUPPORT else N_ChannelCheck(pAdapter); -#endif // DOT11_N_SUPPORT // -#ifdef DOT11_N_SUPPORT if (pAdapter->CommonCfg.PhyMode >= PHY_11ABGN_MIXED && pAdapter->CommonCfg.RegTransmitSetting.field.BW == BW_40 && pAdapter->CommonCfg.RegTransmitSetting.field.EXTCHA == EXTCHA_ABOVE) @@ -5936,7 +5605,6 @@ INT Set_NetworkType_Proc( pAdapter->CommonCfg.CentralChannel)); } else -#endif // DOT11_N_SUPPORT // { // 20MHz RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, BBP_R4, &bbpValue); @@ -5997,12 +5665,10 @@ INT Set_AuthMode_Proc( pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPANone; else if ((strcmp(arg, "WPA2PSK") == 0) || (strcmp(arg, "wpa2psk") == 0)) pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA2PSK; -#ifdef WPA_SUPPLICANT_SUPPORT else if ((strcmp(arg, "WPA") == 0) || (strcmp(arg, "wpa") == 0)) pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA; else if ((strcmp(arg, "WPA2") == 0) || (strcmp(arg, "wpa2") == 0)) pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA2; -#endif // WPA_SUPPLICANT_SUPPORT // else return FALSE; @@ -6544,7 +6210,6 @@ INT Set_PSMode_Proc( return TRUE; } -#ifdef WPA_SUPPLICANT_SUPPORT /* ========================================================================== Description: @@ -6575,7 +6240,6 @@ INT Set_Wpa_Support( return TRUE; } -#endif // WPA_SUPPLICANT_SUPPORT // #ifdef DBG /* @@ -6608,7 +6272,9 @@ VOID RTMPIoctlMAC( UCHAR temp[16], temp2[16]; UINT32 macValue = 0; INT Status; - +#ifdef RT30xx + BOOLEAN bIsPrintAllMAC = FALSE; +#endif memset(msg, 0x00, 1024); if (wrq->u.data.length > 1) //No parameters. @@ -6659,7 +6325,13 @@ VOID RTMPIoctlMAC( sprintf(msg+strlen(msg), "[0x%08lX]:%08X ", macAddr , macValue); } else +#ifndef RT30xx {//Invalid parametes, so default printk all bbp +#endif +#ifdef RT30xx + {//Invalid parametes, so default printk all mac + bIsPrintAllMAC = TRUE; +#endif goto next; } } @@ -6730,13 +6402,6 @@ VOID RTMPIoctlMAC( UCHAR R66; pAdapter->BbpTuning.bEnable = FALSE; R66 = 0x26 + GET_LNA_GAIN(pAdapter); -#ifdef RALINK_ATE - if (ATE_ON(pAdapter)) - { - ATE_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R66, (0x26 + GET_LNA_GAIN(pAdapter))); - } - else -#endif // RALINK_ATE // RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R66, (0x26 + GET_LNA_GAIN(pAdapter))); DBGPRINT(RT_DEBUG_TRACE,("turn off R17 tuning, restore to 0x%02x\n", R66)); } @@ -6750,7 +6415,52 @@ VOID RTMPIoctlMAC( } } } +#ifdef RT30xx + else + bIsPrintAllMAC = TRUE; +#endif next: +#ifdef RT30xx + if (bIsPrintAllMAC) + { + struct file *file_w; + PCHAR fileName = "MacDump.txt"; + mm_segment_t orig_fs; + + orig_fs = get_fs(); + set_fs(KERNEL_DS); + + // open file + file_w = filp_open(fileName, O_WRONLY|O_CREAT, 0); + if (IS_ERR(file_w)) + { + DBGPRINT(RT_DEBUG_TRACE, ("-->2) %s: Error %ld opening %s\n", __func__, -PTR_ERR(file_w), fileName)); + } + else + { + if (file_w->f_op && file_w->f_op->write) + { + file_w->f_pos = 0; + macAddr = 0x1000; + + while (macAddr <= 0x1800) + { + RTMP_IO_READ32(pAdapter, macAddr, &macValue); + sprintf(msg, "%08lx = %08X\n", macAddr, macValue); + + // write data to file + file_w->f_op->write(file_w, msg, strlen(msg), &file_w->f_pos); + + printk("%s", msg); + macAddr += 4; + } + sprintf(msg, "\nDump all MAC values to %s\n", fileName); + } + filp_close(file_w, NULL); + } + set_fs(orig_fs); + } +#endif /* RT30xx */ if(strlen(msg) == 1) sprintf(msg+strlen(msg), "===>Error command format!"); @@ -6791,7 +6501,9 @@ VOID RTMPIoctlE2PROM( UCHAR temp[16], temp2[16]; USHORT eepValue; int Status; - +#ifdef RT30xx + BOOLEAN bIsPrintAllE2P = FALSE; +#endif memset(msg, 0x00, 1024); if (wrq->u.data.length > 1) //No parameters. @@ -6845,6 +6557,9 @@ VOID RTMPIoctlE2PROM( } else {//Invalid parametes, so default printk all bbp +#ifdef RT30xx + bIsPrintAllE2P = TRUE; +#endif goto next; } } @@ -6903,7 +6618,52 @@ VOID RTMPIoctlE2PROM( sprintf(msg+strlen(msg), "[0x%02X]:%02X ", eepAddr, eepValue); } } +#ifdef RT30xx + else + bIsPrintAllE2P = TRUE; +#endif next: +#ifdef RT30xx + if (bIsPrintAllE2P) + { + struct file *file_w; + PCHAR fileName = "EEPROMDump.txt"; + mm_segment_t orig_fs; + + orig_fs = get_fs(); + set_fs(KERNEL_DS); + + // open file + file_w = filp_open(fileName, O_WRONLY|O_CREAT, 0); + if (IS_ERR(file_w)) + { + DBGPRINT(RT_DEBUG_TRACE, ("-->2) %s: Error %ld opening %s\n", __func__, -PTR_ERR(file_w), fileName)); + } + else + { + if (file_w->f_op && file_w->f_op->write) + { + file_w->f_pos = 0; + eepAddr = 0x00; + + while (eepAddr <= 0xFE) + { + RT28xx_EEPROM_READ16(pAdapter, eepAddr, eepValue); + sprintf(msg, "%08x = %04x\n", eepAddr , eepValue); + + // write data to file + file_w->f_op->write(file_w, msg, strlen(msg), &file_w->f_pos); + + printk("%s", msg); + eepAddr += 2; + } + sprintf(msg, "\nDump all EEPROM values to %s\n", fileName); + } + filp_close(file_w, NULL); + } + set_fs(orig_fs); + } +#endif /* RT30xx */ if(strlen(msg) == 1) sprintf(msg+strlen(msg), "===>Error command format!"); @@ -6914,6 +6674,154 @@ next: DBGPRINT(RT_DEBUG_TRACE, ("<==RTMPIoctlE2PROM\n")); } +#ifdef RT30xx +/* + ========================================================================== + Description: + Read / Write RF register +Arguments: + pAdapter Pointer to our adapter + wrq Pointer to the ioctl argument + + Return Value: + None + + Note: + Usage: + 1.) iwpriv ra0 rf ==> read all RF registers + 2.) iwpriv ra0 rf 1 ==> read RF where RegID=1 + 3.) iwpriv ra0 rf 1=10 ==> write RF R1=0x10 + ========================================================================== +*/ +VOID RTMPIoctlRF( + IN PRTMP_ADAPTER pAdapter, + IN struct iwreq *wrq) +{ + CHAR *this_char; + CHAR *value; + UCHAR regRF = 0; + CHAR msg[2048]; + CHAR arg[255]; + INT rfId; + LONG rfValue; + int Status; + BOOLEAN bIsPrintAllRF = FALSE; + + + memset(msg, 0x00, 2048); + if (wrq->u.data.length > 1) //No parameters. + { + Status = copy_from_user(arg, wrq->u.data.pointer, (wrq->u.data.length > 255) ? 255 : wrq->u.data.length); + sprintf(msg, "\n"); + + //Parsing Read or Write + this_char = arg; + if (!*this_char) + goto next; + + if ((value = strchr(this_char, '=')) != NULL) + *value++ = 0; + + if (!value || !*value) + { //Read + if (sscanf(this_char, "%d", &(rfId)) == 1) + { + if (rfId <= 31) + { + // In RT2860 ATE mode, we do not load 8051 firmware. + //We must access RF directly. + // For RT2870 ATE mode, ATE_RF_IO_WRITE8(/READ8)_BY_REG_ID are redefined. + // according to Andy, Gary, David require. + // the command rf shall read rf register directly for dubug. + // BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); + RT30xxReadRFRegister(pAdapter, rfId, ®RF); + + sprintf(msg+strlen(msg), "R%02d[0x%02x]:%02X ", rfId, rfId*2, regRF); + } + else + {//Invalid parametes, so default printk all RF + bIsPrintAllRF = TRUE; + goto next; + } + } + else + { //Invalid parametes, so default printk all RF + bIsPrintAllRF = TRUE; + goto next; + } + } + else + { //Write + if ((sscanf(this_char, "%d", &(rfId)) == 1) && (sscanf(value, "%lx", &(rfValue)) == 1)) + { + if (rfId <= 31) + { + // In RT2860 ATE mode, we do not load 8051 firmware. + // We should access RF registers directly. + // For RT2870 ATE mode, ATE_RF_IO_WRITE8/READ8_BY_REG_ID are redefined. + { + // according to Andy, Gary, David require. + // the command RF shall read/write RF register directly for dubug. + //BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); + //BBP_IO_WRITE8_BY_REG_ID(pAdapter, (UCHAR)bbpId,(UCHAR) bbpValue); + RT30xxReadRFRegister(pAdapter, rfId, ®RF); + RT30xxWriteRFRegister(pAdapter, (UCHAR)rfId,(UCHAR) rfValue); + //Read it back for showing + //BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); + RT30xxReadRFRegister(pAdapter, rfId, ®RF); + sprintf(msg+strlen(msg), "R%02d[0x%02X]:%02X\n", rfId, rfId*2, regRF); + } + } + else + {//Invalid parametes, so default printk all RF + bIsPrintAllRF = TRUE; + } + } + else + { //Invalid parametes, so default printk all RF + bIsPrintAllRF = TRUE; + } + } + } + else + bIsPrintAllRF = TRUE; +next: + if (bIsPrintAllRF) + { + memset(msg, 0x00, 2048); + sprintf(msg, "\n"); + for (rfId = 0; rfId <= 31; rfId++) + { + // according to Andy, Gary, David require. + // the command RF shall read/write RF register directly for dubug. + RT30xxReadRFRegister(pAdapter, rfId, ®RF); + sprintf(msg+strlen(msg), "%03d = %02X\n", rfId, regRF); + } + // Copy the information into the user buffer + DBGPRINT(RT_DEBUG_TRACE, ("strlen(msg)=%d\n", (UINT32)strlen(msg))); + wrq->u.data.length = strlen(msg); + if (copy_to_user(wrq->u.data.pointer, msg, wrq->u.data.length)) + { + DBGPRINT(RT_DEBUG_TRACE, ("%s: copy_to_user() fail\n", __func__)); + } + } + else + { + if(strlen(msg) == 1) + sprintf(msg+strlen(msg), "===>Error command format!"); + + DBGPRINT(RT_DEBUG_TRACE, ("copy to user [msg=%s]\n", msg)); + // Copy the information into the user buffer + DBGPRINT(RT_DEBUG_TRACE, ("strlen(msg) =%d\n", (UINT32)strlen(msg))); + + // Copy the information into the user buffer + wrq->u.data.length = strlen(msg); + Status = copy_to_user(wrq->u.data.pointer, msg, wrq->u.data.length); + } + + DBGPRINT(RT_DEBUG_TRACE, ("<==RTMPIoctlRF\n\n")); +} +#endif // RT30xx // #endif // DBG // @@ -6960,37 +6868,47 @@ INT Set_ShortRetryLimit_Proc( return TRUE; } -#ifdef EXT_BUILD_CHANNEL_LIST -INT Set_Ieee80211dClientMode_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) +#if !defined(RT2860) && !defined(RT30xx) +INT Show_Adhoc_MacTable_Proc( + IN PRTMP_ADAPTER pAd, + IN PCHAR extra) { - if (simple_strtol(arg, 0, 10) == 0) - pAdapter->StaCfg.IEEE80211dClientMode = Rt802_11_D_None; - else if (simple_strtol(arg, 0, 10) == 1) - pAdapter->StaCfg.IEEE80211dClientMode = Rt802_11_D_Flexible; - else if (simple_strtol(arg, 0, 10) == 2) - pAdapter->StaCfg.IEEE80211dClientMode = Rt802_11_D_Strict; - else - return FALSE; + INT i; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Ieee802dMode_Proc::(IEEEE0211dMode=%d)\n", pAdapter->StaCfg.IEEE80211dClientMode)); - return TRUE; -} -#endif // EXT_BUILD_CHANNEL_LIST // + sprintf(extra, "\n"); -#ifdef CARRIER_DETECTION_SUPPORT -INT Set_CarrierDetect_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - if (simple_strtol(arg, 0, 10) == 0) - pAd->CommonCfg.CarrierDetect.Enable = FALSE; - else - pAd->CommonCfg.CarrierDetect.Enable = TRUE; + sprintf(extra + strlen(extra), "HT Operating Mode : %d\n", pAd->CommonCfg.AddHTInfo.AddHtInfo2.OperaionMode); + + sprintf(extra + strlen(extra), "\n%-19s%-4s%-4s%-7s%-7s%-7s%-10s%-6s%-6s%-6s%-6s\n", + "MAC", "AID", "BSS", "RSSI0", "RSSI1", "RSSI2", "PhMd", "BW", "MCS", "SGI", "STBC"); + + for (i=1; iMacTab.Content[i]; + + if (strlen(extra) > (IW_PRIV_SIZE_MASK - 30)) + break; + if ((pEntry->ValidAsCLI || pEntry->ValidAsApCli) && (pEntry->Sst == SST_ASSOC)) + { + sprintf(extra + strlen(extra), "%02X:%02X:%02X:%02X:%02X:%02X ", + pEntry->Addr[0], pEntry->Addr[1], pEntry->Addr[2], + pEntry->Addr[3], pEntry->Addr[4], pEntry->Addr[5]); + sprintf(extra + strlen(extra), "%-4d", (int)pEntry->Aid); + sprintf(extra + strlen(extra), "%-4d", (int)pEntry->apidx); + sprintf(extra + strlen(extra), "%-7d", pEntry->RssiSample.AvgRssi0); + sprintf(extra + strlen(extra), "%-7d", pEntry->RssiSample.AvgRssi1); + sprintf(extra + strlen(extra), "%-7d", pEntry->RssiSample.AvgRssi2); + sprintf(extra + strlen(extra), "%-10s", GetPhyMode(pEntry->HTPhyMode.field.MODE)); + sprintf(extra + strlen(extra), "%-6s", GetBW(pEntry->HTPhyMode.field.BW)); + sprintf(extra + strlen(extra), "%-6d", pEntry->HTPhyMode.field.MCS); + sprintf(extra + strlen(extra), "%-6d", pEntry->HTPhyMode.field.ShortGI); + sprintf(extra + strlen(extra), "%-6d", pEntry->HTPhyMode.field.STBC); + sprintf(extra + strlen(extra), "%-10d, %d, %d%%\n", pEntry->DebugFIFOCount, pEntry->DebugTxCount, + (pEntry->DebugTxCount) ? ((pEntry->DebugTxCount-pEntry->DebugFIFOCount)*100/pEntry->DebugTxCount) : 0); + sprintf(extra, "%s\n", extra); + } + } - DBGPRINT(RT_DEBUG_TRACE, ("IF Set_CarrierDetect_Proc::(CarrierDetect.Enable=%d)\n", pAd->CommonCfg.CarrierDetect.Enable)); return TRUE; } -#endif // CARRIER_DETECTION_SUPPORT // - +#endif /* RT2870 */ diff --git a/drivers/staging/rt2860/wpa.h b/drivers/staging/rt2860/wpa.h index 0134ae6097cf..e6716748adfa 100644 --- a/drivers/staging/rt2860/wpa.h +++ b/drivers/staging/rt2860/wpa.h @@ -90,7 +90,9 @@ #define TKIP_AP_RXMICK_OFFSET (TKIP_AP_TXMICK_OFFSET+LEN_TKIP_TXMICK) #define TKIP_GTK_LENGTH ((LEN_TKIP_EK)+(LEN_TKIP_RXMICK)+(LEN_TKIP_TXMICK)) #define LEN_PTK ((LEN_EAP_KEY)+(LEN_TKIP_KEY)) +#ifndef RT30xx #define MIN_LEN_OF_GTK 5 +#endif // RSN IE Length definition #define MAX_LEN_OF_RSNIE 90 @@ -150,19 +152,6 @@ // EAPOL Key Information definition within Key descriptor format typedef struct PACKED _KEY_INFO { -#ifdef RT_BIG_ENDIAN - UCHAR KeyAck:1; - UCHAR Install:1; - UCHAR KeyIndex:2; - UCHAR KeyType:1; - UCHAR KeyDescVer:3; - UCHAR Rsvd:3; - UCHAR EKD_DL:1; // EKD for AP; DL for STA - UCHAR Request:1; - UCHAR Error:1; - UCHAR Secure:1; - UCHAR KeyMic:1; -#else UCHAR KeyMic:1; UCHAR Secure:1; UCHAR Error:1; @@ -174,7 +163,6 @@ typedef struct PACKED _KEY_INFO UCHAR KeyIndex:2; UCHAR Install:1; UCHAR KeyAck:1; -#endif } KEY_INFO, *PKEY_INFO; // EAPOL Key descriptor format @@ -204,17 +192,10 @@ typedef struct PACKED _EAPOL_PACKET //802.11i D10 page 83 typedef struct PACKED _GTK_ENCAP { -#ifndef RT_BIG_ENDIAN UCHAR Kid:2; UCHAR tx:1; UCHAR rsv:5; UCHAR rsv1; -#else - UCHAR rsv:5; - UCHAR tx:1; - UCHAR Kid:2; - UCHAR rsv1; -#endif UCHAR GTK[TKIP_GTK_LENGTH]; } GTK_ENCAP, *PGTK_ENCAP; @@ -258,19 +239,11 @@ typedef struct PACKED _RSNIE_AUTH { typedef union PACKED _RSN_CAPABILITIES { struct PACKED { -#ifdef RT_BIG_ENDIAN - USHORT Rsvd:10; - USHORT GTKSA_R_Counter:2; - USHORT PTKSA_R_Counter:2; - USHORT No_Pairwise:1; - USHORT PreAuth:1; -#else USHORT PreAuth:1; USHORT No_Pairwise:1; USHORT PTKSA_R_Counter:2; USHORT GTKSA_R_Counter:2; USHORT Rsvd:10; -#endif } field; USHORT word; } RSN_CAPABILITIES, *PRSN_CAPABILITIES; diff --git a/drivers/staging/rt2870/2870_main_dev.c b/drivers/staging/rt2870/2870_main_dev.c index 9d59e3167fe4..dd01c64fbf61 100644 --- a/drivers/staging/rt2870/2870_main_dev.c +++ b/drivers/staging/rt2870/2870_main_dev.c @@ -46,17 +46,10 @@ // Otherwise post to forum in ralinktech's web site(www.ralinktech.com) and let all users help you. *** MODULE_AUTHOR("Paul Lin "); MODULE_DESCRIPTION("RT2870 Wireless Lan Linux Driver"); -#ifdef CONFIG_STA_SUPPORT MODULE_LICENSE("GPL"); #ifdef MODULE_VERSION MODULE_VERSION(STA_DRIVER_VERSION); #endif -#endif // CONFIG_STA_SUPPORT // - -#ifdef MULTIPLE_CARD_SUPPORT -// record whether the card in the card list is used in the card file -extern UINT8 MC_CardUsed[]; -#endif // MULTIPLE_CARD_SUPPORT // /* Kernel thread and vars, which handles packets that are completed. Only * packets that have a "complete" function are sent here. This way, the @@ -77,26 +70,6 @@ MODULE_DEVICE_TABLE(usb, rtusb_usb_id); #endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - -/**************************************************************************/ -/**************************************************************************/ -//tested for kernel 2.4 series -/**************************************************************************/ -/**************************************************************************/ -static void *rtusb_probe(struct usb_device *dev, UINT interface, - const struct usb_device_id *id_table); -static void rtusb_disconnect(struct usb_device *dev, void *ptr); - -struct usb_driver rtusb_driver = { - name:"rt2870", - probe:rtusb_probe, - disconnect:rtusb_disconnect, - id_table:rtusb_usb_id, - }; - -#else - #ifdef CONFIG_PM static int rt2870_suspend(struct usb_interface *intf, pm_message_t state); static int rt2870_resume(struct usb_interface *intf); @@ -112,9 +85,6 @@ static int rtusb_probe (struct usb_interface *intf, static void rtusb_disconnect(struct usb_interface *intf); struct usb_driver rtusb_driver = { -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) - .owner = THIS_MODULE, -#endif .name="rt2870", .probe=rtusb_probe, .disconnect=rtusb_disconnect, @@ -176,7 +146,6 @@ static int rt2870_resume( return 0; } #endif // CONFIG_PM // -#endif // LINUX_VERSION_CODE // // Init driver module @@ -265,7 +234,12 @@ INT MlmeThread( */ DBGPRINT(RT_DEBUG_TRACE,( "<---%s\n",__func__)); +#ifndef RT30xx pObj->MLMEThr_task = NULL; +#endif +#ifdef RT30xx + pObj->MLMEThr_pid = NULL; +#endif complete_and_exit (&pAd->mlmeComplete, 0); return 0; @@ -373,7 +347,12 @@ INT RTUSBCmdThread( */ DBGPRINT(RT_DEBUG_TRACE,( "<---RTUSBCmdThread\n")); +#ifndef RT30xx pObj->RTUSBCmdThr_task = NULL; +#endif +#ifdef RT30xx + pObj->RTUSBCmdThr_pid = NULL; +#endif complete_and_exit (&pAd->CmdQComplete, 0); return 0; @@ -467,8 +446,12 @@ INT TimerQThread( */ DBGPRINT(RT_DEBUG_TRACE,( "<---%s\n",__func__)); +#ifndef RT30xx pObj->TimerQThr_task = NULL; - +#endif +#ifdef RT30xx + pObj->TimerQThr_pid = NULL; +#endif complete_and_exit(&pAd->TimerQComplete, 0); return 0; @@ -636,6 +619,7 @@ VOID RT2870_WatchDog(IN RTMP_ADAPTER *pAd) RTMP_IO_WRITE32(pAd, PBF_CFG, 0xf40006); } +//PS packets use HCCA queue when dequeue from PS unicast queue (WiFi WPA2 MA9_DT1 for Marvell B STA) idx = 0; if ((MACValue & 0xff00) !=0 ) { @@ -649,7 +633,6 @@ VOID RT2870_WatchDog(IN RTMP_ADAPTER *pAd) RTMP_IO_WRITE32(pAd, PBF_CFG, 0xf40006); } - if (pAd->watchDogRxOverFlowCnt >= 2) { DBGPRINT(RT_DEBUG_TRACE, ("Maybe the Rx Bulk-In hanged! Cancel the pending Rx bulks request!\n")); @@ -740,7 +723,6 @@ VOID RT2870_WatchDog(IN RTMP_ADAPTER *pAd) } } -#ifdef DOT11_N_SUPPORT // For Sigma debug, dump the ba_reordering sequence. if((needDumpSeq == TRUE) && (pAd->CommonCfg.bDisableReordering == 0)) { @@ -768,7 +750,6 @@ VOID RT2870_WatchDog(IN RTMP_ADAPTER *pAd) NdisReleaseSpinLock(&pBAEntry->RxReRingLock); } } -#endif // DOT11_N_SUPPORT // } /* @@ -795,19 +776,7 @@ static void _rtusb_disconnect(struct usb_device *dev, PRTMP_ADAPTER pAd) dev->bus->bus_name, dev->devpath)); if (!pAd) { -#ifdef MULTIPLE_CARD_SUPPORT - if ((pAd->MC_RowID >= 0) && (pAd->MC_RowID <= MAX_NUM_OF_MULTIPLE_CARD)) - MC_CardUsed[pAd->MC_RowID] = 0; // not clear MAC address -#endif // MULTIPLE_CARD_SUPPORT // - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* kernel 2.4 series */ - while(MOD_IN_USE > 0) - { - MOD_DEC_USE_COUNT; - } -#else usb_put_dev(dev); -#endif // LINUX_VERSION_CODE // printk("rtusb_disconnect: pAd == NULL!\n"); return; @@ -829,31 +798,17 @@ static void _rtusb_disconnect(struct usb_device *dev, PRTMP_ADAPTER pAd) unregister_netdev (pAd->net_dev); } udelay(1); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* kernel 2.4 series */ -#else flush_scheduled_work(); -#endif // LINUX_VERSION_CODE // udelay(1); // free net_device memory -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* kernel 2.4 series */ - kfree(net_dev); -#else free_netdev(net_dev); -#endif // LINUX_VERSION_CODE // // free adapter memory RTMPFreeAdapter(pAd); // release a use of the usb device structure -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* kernel 2.4 series */ - while(MOD_IN_USE > 0) - { - MOD_DEC_USE_COUNT; - } -#else usb_put_dev(dev); -#endif // LINUX_VERSION_CODE // udelay(1); DBGPRINT(RT_DEBUG_ERROR, (" RTUSB disconnect successfully\n")); @@ -876,22 +831,6 @@ Return Value: Note: ======================================================================== */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* kernel 2.4 series */ -static void *rtusb_probe(struct usb_device *dev, UINT interface, - const struct usb_device_id *id) -{ - PRTMP_ADAPTER pAd; - rt28xx_probe((void *)dev, (void *)id, interface, &pAd); - return (void *)pAd; -} - -//Disconnect function is called within exit routine -static void rtusb_disconnect(struct usb_device *dev, void *ptr) -{ - _rtusb_disconnect(dev, ((PRTMP_ADAPTER)ptr)); -} - -#else /* kernel 2.6 series */ static int rtusb_probe (struct usb_interface *intf, const struct usb_device_id *id) { @@ -911,7 +850,6 @@ static void rtusb_disconnect(struct usb_interface *intf) _rtusb_disconnect(dev, pAd); } -#endif // LINUX_VERSION_CODE // /* @@ -944,6 +882,7 @@ VOID RT28xxThreadTerminate( RTUSBCancelPendingIRPs(pAd); // Terminate Threads +#ifndef RT30xx BUG_ON(pObj->TimerQThr_task == NULL); CHECK_PID_LEGALITY(task_pid(pObj->TimerQThr_task)) { @@ -985,7 +924,72 @@ VOID RT28xxThreadTerminate( kthread_stop(pObj->RTUSBCmdThr_task); pObj->RTUSBCmdThr_task = NULL; } +#endif +#ifdef RT30xx + if (pObj->MLMEThr_pid) + { + printk("Terminate the MLMEThr_pid=%d!\n", pid_nr(pObj->MLMEThr_pid)); + mb(); + pAd->mlme_kill = 1; + //RT28XX_MLME_HANDLER(pAd); + mb(); + ret = kill_pid(pObj->MLMEThr_pid, SIGTERM, 1); + if (ret) + { + printk (KERN_WARNING "%s: unable to Mlme thread, pid=%d, ret=%d!\n", + pAd->net_dev->name, pid_nr(pObj->MLMEThr_pid), ret); + } + else + { + //wait_for_completion (&pAd->notify); + wait_for_completion (&pAd->mlmeComplete); + pObj->MLMEThr_pid = NULL; + } + } + if (pObj->RTUSBCmdThr_pid >= 0) + { + printk("Terminate the RTUSBCmdThr_pid=%d!\n", pid_nr(pObj->RTUSBCmdThr_pid)); + mb(); + NdisAcquireSpinLock(&pAd->CmdQLock); + pAd->CmdQ.CmdQState = RT2870_THREAD_STOPED; + NdisReleaseSpinLock(&pAd->CmdQLock); + mb(); + //RTUSBCMDUp(pAd); + ret = kill_pid(pObj->RTUSBCmdThr_pid, SIGTERM, 1); + if (ret) + { + printk(KERN_WARNING "%s: unable to RTUSBCmd thread, pid=%d, ret=%d!\n", + pAd->net_dev->name, pid_nr(pObj->RTUSBCmdThr_pid), ret); + } + else + { + //wait_for_completion (&pAd->notify); + wait_for_completion (&pAd->CmdQComplete); + pObj->RTUSBCmdThr_pid = NULL; + } + } + if (pObj->TimerQThr_pid >= 0) + { + POS_COOKIE pObj = (POS_COOKIE)pAd->OS_Cookie; + printk("Terminate the TimerQThr_pid=%d!\n", pid_nr(pObj->TimerQThr_pid)); + mb(); + pAd->TimerFunc_kill = 1; + mb(); + ret = kill_pid(pObj->TimerQThr_pid, SIGTERM, 1); + if (ret) + { + printk(KERN_WARNING "%s: unable to stop TimerQThread, pid=%d, ret=%d!\n", + pAd->net_dev->name, pid_nr(pObj->TimerQThr_pid), ret); + } + else + { + printk("wait_for_completion TimerQThr\n"); + wait_for_completion(&pAd->TimerQComplete); + pObj->TimerQThr_pid = NULL; + } + } +#endif // Kill tasklets pAd->mlme_kill = 0; @@ -1030,12 +1034,8 @@ Note: BOOLEAN RT28XXChipsetCheck( IN void *_dev_p) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* kernel 2.4 series */ - struct usb_device *dev_p = (struct usb_device *)_dev_p; -#else struct usb_interface *intf = (struct usb_interface *)_dev_p; struct usb_device *dev_p = interface_to_usbdev(intf); -#endif // LINUX_VERSION_CODE // UINT32 i; @@ -1044,7 +1044,12 @@ BOOLEAN RT28XXChipsetCheck( if (dev_p->descriptor.idVendor == rtusb_usb_id[i].idVendor && dev_p->descriptor.idProduct == rtusb_usb_id[i].idProduct) { +#ifndef RT30xx printk(KERN_DEBUG "rt2870: idVendor = 0x%x, idProduct = 0x%x\n", +#endif +#ifdef RT30xx + printk("rt2870: idVendor = 0x%x, idProduct = 0x%x\n", +#endif dev_p->descriptor.idVendor, dev_p->descriptor.idProduct); break; } @@ -1082,19 +1087,11 @@ BOOLEAN RT28XXNetDevInit( IN struct net_device *net_dev, IN RTMP_ADAPTER *pAd) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* kernel 2.4 series */ - struct usb_device *dev_p = (struct usb_device *)_dev_p; -#else struct usb_interface *intf = (struct usb_interface *)_dev_p; struct usb_device *dev_p = interface_to_usbdev(intf); -#endif // LINUX_VERSION_CODE // -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* kernel 2.4 series */ - pAd->config = dev_p->config; -#else pAd->config = &dev_p->config->desc; -#endif // LINUX_VERSION_CODE // return TRUE; } @@ -1115,70 +1112,6 @@ Return Value: Note: ======================================================================== */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) -BOOLEAN RT28XXProbePostConfig( - IN void *_dev_p, - IN RTMP_ADAPTER *pAd, - IN INT32 interface) -{ - struct usb_device *dev_p = (struct usb_device *)_dev_p; - struct usb_interface *intf; - struct usb_interface_descriptor *iface_desc; - struct usb_endpoint_descriptor *endpoint; - ULONG BulkOutIdx; - UINT32 i; - - - /* get the active interface descriptor */ - intf = &dev_p->actconfig->interface[interface]; - iface_desc = &intf->altsetting[0]; - - /* get # of enpoints */ - pAd->NumberOfPipes = iface_desc->bNumEndpoints; - DBGPRINT(RT_DEBUG_TRACE, ("NumEndpoints=%d\n", iface_desc->bNumEndpoints)); - - /* Configure Pipes */ - endpoint = &iface_desc->endpoint[0]; - BulkOutIdx = 0; - - for(i=0; iNumberOfPipes; i++) - { - if ((endpoint[i].bmAttributes == USB_ENDPOINT_XFER_BULK) && - ((endpoint[i].bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)) - { - pAd->BulkInEpAddr = endpoint[i].bEndpointAddress; - pAd->BulkInMaxPacketSize = endpoint[i].wMaxPacketSize; - - DBGPRINT_RAW(RT_DEBUG_TRACE, - ("BULK IN MaximumPacketSize = %d\n", pAd->BulkInMaxPacketSize)); - DBGPRINT_RAW(RT_DEBUG_TRACE, - ("EP address = 0x%2x \n", endpoint[i].bEndpointAddress)); - } - else if ((endpoint[i].bmAttributes == USB_ENDPOINT_XFER_BULK) && - ((endpoint[i].bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT)) - { - // There are 6 bulk out EP. EP6 highest priority. - // EP1-4 is EDCA. EP5 is HCCA. - pAd->BulkOutEpAddr[BulkOutIdx++] = endpoint[i].bEndpointAddress; - pAd->BulkOutMaxPacketSize = endpoint[i].wMaxPacketSize; - - DBGPRINT_RAW(RT_DEBUG_TRACE, - ("BULK OUT MaximumPacketSize = %d\n", pAd->BulkOutMaxPacketSize)); - DBGPRINT_RAW(RT_DEBUG_TRACE, - ("EP address = 0x%2x \n", endpoint[i].bEndpointAddress)); - } - } - - if (!(pAd->BulkInEpAddr && pAd->BulkOutEpAddr[0])) - { - printk("Could not find both bulk-in and bulk-out endpoints\n"); - return FALSE; - } - - return TRUE; -} - -#else BOOLEAN RT28XXProbePostConfig( IN void *_dev_p, IN RTMP_ADAPTER *pAd, @@ -1241,7 +1174,6 @@ BOOLEAN RT28XXProbePostConfig( return TRUE; } -#endif // LINUX_VERSION_CODE // /* @@ -1380,9 +1312,7 @@ VOID RT28xx_UpdateBeaconToAsic( else { ptr = (PUCHAR)&pAd->BeaconTxWI; -#ifdef RT_BIG_ENDIAN - RTMPWIEndianChange(ptr, TYPE_TXWI); -#endif + if (NdisEqualMemory(pBeaconSync->BeaconTxWI[bcn_idx], &pAd->BeaconTxWI, TXWI_SIZE) == FALSE) { // If BeaconTxWI changed, we need to rewrite the TxWI for the Beacon frames. pBeaconSync->BeaconBitMap &= (~(BEACON_BITMAP_MASK & (1 << bcn_idx))); @@ -1417,6 +1347,8 @@ VOID RT28xx_UpdateBeaconToAsic( } pBeaconSync->BeaconBitMap |= (1 << bcn_idx); + + // For AP interface, set the DtimBitOn so that we can send Bcast/Mcast frame out after this beacon frame. } } @@ -1434,13 +1366,7 @@ VOID RT2870_BssBeaconStop( { INT NumOfBcn; - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - NumOfBcn = MAX_MESH_NUM; - } -#endif // CONFIG_STA_SUPPORT // + NumOfBcn = MAX_MESH_NUM; RTMPCancelTimer(&pAd->CommonCfg.BeaconUpdateTimer, &Cancelled); @@ -1473,13 +1399,7 @@ VOID RT2870_BssBeaconStart( { INT NumOfBcn; - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - NumOfBcn = MAX_MESH_NUM; - } -#endif // CONFIG_STA_SUPPORT // + NumOfBcn = MAX_MESH_NUM; for(apidx=0; apidxNumOfCh; i++) - { - channel = pChDesp->FirstChannel + i * increment; - for (l=0; lTxPower[l].Channel) - { - pAd->ChannelList[j].Power = pAd->TxPower[l].Power; - pAd->ChannelList[j].Power2 = pAd->TxPower[l].Power2; - break; - } - } - if (l == MAX_NUM_OF_CHANNELS) - continue; - - pAd->ChannelList[j].Channel = pChDesp->FirstChannel + i * increment; - pAd->ChannelList[j].MaxTxPwr = pChDesp->MaxTxPwr; - pAd->ChannelList[j].DfsReq = pChDesp->DfsReq; - j++; - } - pAd->ChannelListNum = j; - - return j; -} - -static inline VOID CreateChList( - IN PRTMP_ADAPTER pAd, - IN PCH_REGION pChRegion, - IN UCHAR Geography) -{ - INT i; - UCHAR offset = 0; - PCH_DESP pChDesp; - UCHAR ChType; - UCHAR increment; - - if (pChRegion == NULL) - return; - - ChBandCheck(pAd->CommonCfg.PhyMode, &ChType); - - for (i=0; i<10; i++) - { - pChDesp = &pChRegion->ChDesp[i]; - if (pChDesp->FirstChannel == 0) - break; - - if (ChType == BAND_5G) - { - if (pChDesp->FirstChannel <= 14) - continue; - } - else if (ChType == BAND_24G) - { - if (pChDesp->FirstChannel > 14) - continue; - } - - if ((pChDesp->Geography == BOTH) - || (pChDesp->Geography == Geography)) - { - if (pChDesp->FirstChannel > 14) - increment = 4; - else - increment = 1; - offset = FillChList(pAd, pChDesp, offset, increment); - } - } -} - -static inline VOID BuildChannelListEx( - IN PRTMP_ADAPTER pAd) -{ - PCH_REGION pChReg; - - pChReg = GetChRegion(pAd->CommonCfg.CountryCode); - CreateChList(pAd, pChReg, pAd->CommonCfg.Geography); -} - -static inline VOID BuildBeaconChList( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf, - OUT PULONG pBufLen) -{ - INT i; - ULONG TmpLen; - PCH_REGION pChRegion; - PCH_DESP pChDesp; - UCHAR ChType; - - pChRegion = GetChRegion(pAd->CommonCfg.CountryCode); - - if (pChRegion == NULL) - return; - - ChBandCheck(pAd->CommonCfg.PhyMode, &ChType); - *pBufLen = 0; - - for (i=0; i<10; i++) - { - pChDesp = &pChRegion->ChDesp[i]; - if (pChDesp->FirstChannel == 0) - break; - - if (ChType == BAND_5G) - { - if (pChDesp->FirstChannel <= 14) - continue; - } - else if (ChType == BAND_24G) - { - if (pChDesp->FirstChannel > 14) - continue; - } - - if ((pChDesp->Geography == BOTH) - || (pChDesp->Geography == pAd->CommonCfg.Geography)) - { - MakeOutgoingFrame(pBuf + *pBufLen, &TmpLen, - 1, &pChDesp->FirstChannel, - 1, &pChDesp->NumOfCh, - 1, &pChDesp->MaxTxPwr, - END_OF_ARGS); - *pBufLen += TmpLen; - } - } -} - - -#ifdef DOT11_N_SUPPORT -static inline BOOLEAN IsValidChannel( - IN PRTMP_ADAPTER pAd, - IN UCHAR channel) - -{ - INT i; - - for (i = 0; i < pAd->ChannelListNum; i++) - { - if (pAd->ChannelList[i].Channel == channel) - break; - } - - if (i == pAd->ChannelListNum) - return FALSE; - else - return TRUE; -} - - -static inline UCHAR GetExtCh( - IN UCHAR Channel, - IN UCHAR Direction) -{ - CHAR ExtCh; - - if (Direction == EXTCHA_ABOVE) - ExtCh = Channel + 4; - else - ExtCh = (Channel - 4) > 0 ? (Channel - 4) : 0; - - return ExtCh; -} - - -static inline VOID N_ChannelCheck( - IN PRTMP_ADAPTER pAd) -{ - //UCHAR ChannelNum = pAd->ChannelListNum; - UCHAR Channel = pAd->CommonCfg.Channel; - - if ((pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) && (pAd->CommonCfg.RegTransmitSetting.field.BW == BW_40)) - { - if (Channel > 14) - { - if ((Channel == 36) || (Channel == 44) || (Channel == 52) || (Channel == 60) || (Channel == 100) || (Channel == 108) || - (Channel == 116) || (Channel == 124) || (Channel == 132) || (Channel == 149) || (Channel == 157)) - { - pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_ABOVE; - } - else if ((Channel == 40) || (Channel == 48) || (Channel == 56) || (Channel == 64) || (Channel == 104) || (Channel == 112) || - (Channel == 120) || (Channel == 128) || (Channel == 136) || (Channel == 153) || (Channel == 161)) - { - pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_BELOW; - } - else - { - pAd->CommonCfg.RegTransmitSetting.field.BW = BW_20; - } - } - else - { - do - { - UCHAR ExtCh; - UCHAR Dir = pAd->CommonCfg.RegTransmitSetting.field.EXTCHA; - ExtCh = GetExtCh(Channel, Dir); - if (IsValidChannel(pAd, ExtCh)) - break; - - Dir = (Dir == EXTCHA_ABOVE) ? EXTCHA_BELOW : EXTCHA_ABOVE; - ExtCh = GetExtCh(Channel, Dir); - if (IsValidChannel(pAd, ExtCh)) - { - pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = Dir; - break; - } - pAd->CommonCfg.RegTransmitSetting.field.BW = BW_20; - } while(FALSE); - - if (Channel == 14) - { - pAd->CommonCfg.RegTransmitSetting.field.BW = BW_20; - //pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_NONE; // We didn't set the ExtCh as NONE due to it'll set in RTMPSetHT() - } -#if 0 - switch (pAd->CommonCfg.CountryRegion & 0x7f) - { - case REGION_0_BG_BAND: // 1 -11 - case REGION_1_BG_BAND: // 1 - 13 - case REGION_5_BG_BAND: // 1 - 14 - if (Channel <= 4) - { - pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_ABOVE; - } - else if (Channel >= 8) - { - if ((ChannelNum - Channel) < 4) - pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_BELOW; - } - break; - - case REGION_2_BG_BAND: // 10 - 11 - case REGION_3_BG_BAND: // 10 - 13 - case REGION_4_BG_BAND: // 14 - pAd->CommonCfg.RegTransmitSetting.field.BW = BW_20; - break; - - case REGION_6_BG_BAND: // 3 - 9 - if (Channel <= 5) - pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_ABOVE; - else if (Channel == 6) - pAd->CommonCfg.RegTransmitSetting.field.BW = BW_20; - else if (Channel >= 7) - pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_BELOW; - break; - - case REGION_7_BG_BAND: // 5 - 13 - if (Channel <= 8) - pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_ABOVE; - else if (Channel >= 10) - pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_BELOW; - break; - - default: // Error. should never happen - break; - } -#endif - } - } - - -} - - -static inline VOID N_SetCenCh( - IN PRTMP_ADAPTER pAd) -{ - if (pAd->CommonCfg.RegTransmitSetting.field.BW == BW_40) - { - if (pAd->CommonCfg.RegTransmitSetting.field.EXTCHA == EXTCHA_ABOVE) - { - pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel + 2; - } - else - { - if (pAd->CommonCfg.Channel == 14) - pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel - 1; - else - pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel - 2; - } - } - else - { - pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel; - } -} -#endif // DOT11_N_SUPPORT // - - -static inline UINT8 GetCuntryMaxTxPwr( - IN PRTMP_ADAPTER pAd, - IN UINT8 channel) -{ - int i; - for (i = 0; i < pAd->ChannelListNum; i++) - { - if (pAd->ChannelList[i].Channel == channel) - break; - } - - if (i == pAd->ChannelListNum) - return 0xff; - else - return pAd->ChannelList[i].MaxTxPwr; -} -#endif // __CHLIST_H__ - +#include "../rt2860/chlist.h" diff --git a/drivers/staging/rt2870/common/2870_rtmp_init.c b/drivers/staging/rt2870/common/2870_rtmp_init.c index cb16d2fcf60a..0f4c8af97e47 100644 --- a/drivers/staging/rt2870/common/2870_rtmp_init.c +++ b/drivers/staging/rt2870/common/2870_rtmp_init.c @@ -266,27 +266,6 @@ NDIS_STATUS NICInitTransmit( // // MGMT_RING_SIZE // -#if 0 - for(i=0; iMLMEContext[i]); - - - NdisZeroMemory(pMLMEContext, sizeof(TX_CONTEXT)); - - //Allocate URB - LM_USB_ALLOC(pObj, pMLMEContext, PTX_BUFFER, sizeof(TX_BUFFER), Status, - ("<-- ERROR in Alloc TX MLMEContext[%d] urb!! \n", i), - out2, - ("<-- ERROR in Alloc TX MLMEContext[%d] TX_BUFFER !! \n", i), - out2); - - pMLMEContext->pAd = pAd; - pMLMEContext->pIrp = NULL; - pMLMEContext->InUse = FALSE; - pMLMEContext->IRPPending = FALSE; - } -#else // Allocate MGMT ring descriptor's memory pAd->MgmtDescRing.AllocSize = MGMT_RING_SIZE * sizeof(TX_CONTEXT); RTMPAllocateMemory(&pAd->MgmtDescRing.AllocVa, pAd->MgmtDescRing.AllocSize); @@ -336,7 +315,6 @@ NDIS_STATUS NICInitTransmit( pAd->MgmtRing.TxSwFreeIdx = MGMT_RING_SIZE; pAd->MgmtRing.TxCpuIdx = 0; pAd->MgmtRing.TxDmaIdx = 0; -#endif // // BEACON_RING_SIZE @@ -518,10 +496,6 @@ NDIS_STATUS RTMPAllocTxRxRingMemory( NdisAllocateSpinLock(&pAd->TxContextQueueLock[num]); } -#ifdef RALINK_ATE - NdisAllocateSpinLock(&pAd->GenericLock); -#endif // RALINK_ATE // - // NdisAllocateSpinLock(&pAd->MemLock); // Not used in RT28XX // NdisAllocateSpinLock(&pAd->MacTabLock); // init it in UserCfgInit() @@ -665,7 +639,7 @@ VOID RTMPFreeTxRxRingMemory( // Free Tx frame resource - for (acidx = 0; acidx < 4; acidx++) + for(acidx=0; acidx<4; acidx++) { PHT_TX_CONTEXT pHTTXContext = &(pAd->TxContext[acidx]); if (pHTTXContext) @@ -684,9 +658,7 @@ VOID RTMPFreeTxRxRingMemory( NdisFreeSpinLock(&pAd->MLMEBulkOutLock); NdisFreeSpinLock(&pAd->CmdQLock); -#ifdef RALINK_ATE - NdisFreeSpinLock(&pAd->GenericLock); -#endif // RALINK_ATE // + // Clear all pending bulk-out request flags. RTUSB_CLEAR_BULK_FLAG(pAd, 0xffffffff); @@ -727,9 +699,14 @@ NDIS_STATUS AdapterBlockAllocateMemory( usb_dev = pObj->pUsb_Dev; +#ifndef RT30xx pObj->MLMEThr_task = NULL; pObj->RTUSBCmdThr_task = NULL; - +#endif +#ifdef RT30xx + pObj->MLMEThr_pid = NULL; + pObj->RTUSBCmdThr_pid = NULL; +#endif *ppAd = (PVOID)vmalloc(sizeof(RTMP_ADAPTER)); if (*ppAd) @@ -765,7 +742,12 @@ NDIS_STATUS CreateThreads( { PRTMP_ADAPTER pAd = net_dev->ml_priv; POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie; +#ifndef RT30xx struct task_struct *tsk; +#endif +#ifdef RT30xx + pid_t pid_number; +#endif //init_MUTEX(&(pAd->usbdev_semaphore)); @@ -779,39 +761,76 @@ NDIS_STATUS CreateThreads( init_completion (&pAd->TimerQComplete); // Creat MLME Thread +#ifndef RT30xx pObj->MLMEThr_task = NULL; - tsk = kthread_run(MlmeThread, pAd, pAd->net_dev->name); + tsk = kthread_run(MlmeThread, pAd, "%s", pAd->net_dev->name); if (IS_ERR(tsk)) { +#endif +#ifdef RT30xx + pObj->MLMEThr_pid = NULL; + pid_number = kernel_thread(MlmeThread, pAd, CLONE_VM); + if (pid_number < 0) + { +#endif printk (KERN_WARNING "%s: unable to start Mlme thread\n",pAd->net_dev->name); return NDIS_STATUS_FAILURE; } +#ifndef RT30xx pObj->MLMEThr_task = tsk; +#endif +#ifdef RT30xx + pObj->MLMEThr_pid = find_get_pid(pid_number); +#endif // Wait for the thread to start wait_for_completion(&(pAd->mlmeComplete)); // Creat Command Thread +#ifndef RT30xx pObj->RTUSBCmdThr_task = NULL; - tsk = kthread_run(RTUSBCmdThread, pAd, pAd->net_dev->name); + tsk = kthread_run(RTUSBCmdThread, pAd, "%s", pAd->net_dev->name); if (IS_ERR(tsk) < 0) +#endif +#ifdef RT30xx + pObj->RTUSBCmdThr_pid = NULL; + pid_number = kernel_thread(RTUSBCmdThread, pAd, CLONE_VM); + if (pid_number < 0) +#endif { printk (KERN_WARNING "%s: unable to start RTUSBCmd thread\n",pAd->net_dev->name); return NDIS_STATUS_FAILURE; } +#ifndef RT30xx pObj->RTUSBCmdThr_task = tsk; +#endif +#ifdef RT30xx + pObj->RTUSBCmdThr_pid = find_get_pid(pid_number); +#endif wait_for_completion(&(pAd->CmdQComplete)); +#ifndef RT30xx pObj->TimerQThr_task = NULL; - tsk = kthread_run(TimerQThread, pAd, pAd->net_dev->name); + tsk = kthread_run(TimerQThread, pAd, "%s", pAd->net_dev->name); if (IS_ERR(tsk) < 0) +#endif +#ifdef RT30xx + pObj->TimerQThr_pid = NULL; + pid_number = kernel_thread(TimerQThread, pAd, CLONE_VM); + if (pid_number < 0) +#endif { printk (KERN_WARNING "%s: unable to start TimerQThread\n",pAd->net_dev->name); return NDIS_STATUS_FAILURE; } +#ifndef RT30xx pObj->TimerQThr_task = tsk; +#endif +#ifdef RT30xx + pObj->TimerQThr_pid = find_get_pid(pid_number); +#endif // Wait for the thread to start wait_for_completion(&(pAd->TimerQComplete)); @@ -831,8 +850,6 @@ NDIS_STATUS CreateThreads( return NDIS_STATUS_SUCCESS; } - -#ifdef CONFIG_STA_SUPPORT /* ======================================================================== Routine Description: @@ -1013,7 +1030,6 @@ VOID RTMPAddBSSIDCipher( DBGPRINT_RAW(RT_DEBUG_TRACE,(" %x:", pKey->KeyMaterial[i])); DBGPRINT(RT_DEBUG_TRACE,(" \n")); } -#endif // CONFIG_STA_SUPPORT // /* ======================================================================== @@ -1084,18 +1100,13 @@ PNDIS_PACKET GetPacketFromRxRing( // skip USB frame length field pData += RT2870_RXDMALEN_FIELD_SIZE; pRxWI = (PRXWI_STRUC)pData; -#ifdef RT_BIG_ENDIAN - RTMPWIEndianChange(pData, TYPE_RXWI); -#endif // RT_BIG_ENDIAN // + if (pRxWI->MPDUtotalByteCount > ThisFrameLen) { DBGPRINT(RT_DEBUG_ERROR, ("%s():pRxWIMPDUtotalByteCount(%d) large than RxDMALen(%ld)\n", __func__, pRxWI->MPDUtotalByteCount, ThisFrameLen)); goto label_null; } -#ifdef RT_BIG_ENDIAN - RTMPWIEndianChange(pData, TYPE_RXWI); -#endif // RT_BIG_ENDIAN // // allocate a rx packet pSkb = dev_alloc_skb(ThisFrameLen); @@ -1112,9 +1123,6 @@ PNDIS_PACKET GetPacketFromRxRing( // copy RxD *pSaveRxD = *(PRXINFO_STRUC)(pData + ThisFrameLen); -#ifdef RT_BIG_ENDIAN - RTMPDescriptorEndianChange((PUCHAR)pSaveRxD, TYPE_RXINFO); -#endif // RT_BIG_ENDIAN // // update next packet read position. pAd->ReadPosition += (ThisFrameLen + RT2870_RXDMALEN_FIELD_SIZE + RXINFO_SIZE); // 8 for (RT2870_RXDMALEN_FIELD_SIZE + sizeof(RXINFO_STRUC)) @@ -1197,17 +1205,6 @@ static void rx_done_tasklet(unsigned long data) ASSERT((pRxContext->InUse == pRxContext->IRPPending)); -#ifdef RALINK_ATE - if (ATE_ON(pAd)) - { - // If the driver is in ATE mode and Rx frame is set into here. - if (pAd->ContinBulkIn == TRUE) - { - RTUSBBulkReceive(pAd); - } - } - else -#endif // RALINK_ATE // RTUSBBulkReceive(pAd); return; @@ -1310,9 +1307,9 @@ static void rt2870_hcca_dma_done_tasklet(unsigned long data) UCHAR BulkOutPipeId = 4; purbb_t pUrb; - +#ifndef RT30xx DBGPRINT_RAW(RT_DEBUG_ERROR, ("--->hcca_dma_done_tasklet\n")); - +#endif pUrb = (purbb_t)data; pHTTXContext = (PHT_TX_CONTEXT)pUrb->context; @@ -1342,13 +1339,19 @@ static void rt2870_hcca_dma_done_tasklet(unsigned long data) RTMPDeQueuePacket(pAd, FALSE, BulkOutPipeId, MAX_TX_PROCESS); } +#ifndef RT30xx RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NORMAL); +#endif +#ifdef RT30xx + RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NORMAL<<4); +#endif RTUSBKickBulkOut(pAd); } } +#ifndef RT30xx DBGPRINT_RAW(RT_DEBUG_ERROR, ("<---hcca_dma_done_tasklet\n")); - +#endif return; } diff --git a/drivers/staging/rt2870/common/action.c b/drivers/staging/rt2870/common/action.c index 3a48a7f5e2bc..fd806c3871aa 100644 --- a/drivers/staging/rt2870/common/action.c +++ b/drivers/staging/rt2870/common/action.c @@ -1,1046 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - action.c - - Abstract: - Handle association related requests either from WSTA or from local MLME - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Jan Lee 2006 created for rt2860 - */ - -#include "../rt_config.h" -#include "action.h" - - -static VOID ReservedAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -/* - ========================================================================== - Description: - association state machine init, including state transition and timer init - Parameters: - S - pointer to the association state machine - Note: - The state machine looks like the following - - ASSOC_IDLE - MT2_MLME_DISASSOC_REQ mlme_disassoc_req_action - MT2_PEER_DISASSOC_REQ peer_disassoc_action - MT2_PEER_ASSOC_REQ drop - MT2_PEER_REASSOC_REQ drop - MT2_CLS3ERR cls3err_action - ========================================================================== - */ -VOID ActionStateMachineInit( - IN PRTMP_ADAPTER pAd, - IN STATE_MACHINE *S, - OUT STATE_MACHINE_FUNC Trans[]) -{ - StateMachineInit(S, (STATE_MACHINE_FUNC *)Trans, MAX_ACT_STATE, MAX_ACT_MSG, (STATE_MACHINE_FUNC)Drop, ACT_IDLE, ACT_MACHINE_BASE); - - StateMachineSetAction(S, ACT_IDLE, MT2_PEER_SPECTRUM_CATE, (STATE_MACHINE_FUNC)PeerSpectrumAction); - StateMachineSetAction(S, ACT_IDLE, MT2_PEER_QOS_CATE, (STATE_MACHINE_FUNC)PeerQOSAction); - - StateMachineSetAction(S, ACT_IDLE, MT2_PEER_DLS_CATE, (STATE_MACHINE_FUNC)ReservedAction); -#ifdef QOS_DLS_SUPPORT - StateMachineSetAction(S, ACT_IDLE, MT2_PEER_DLS_CATE, (STATE_MACHINE_FUNC)PeerDLSAction); -#endif // QOS_DLS_SUPPORT // - -#ifdef DOT11_N_SUPPORT - StateMachineSetAction(S, ACT_IDLE, MT2_PEER_BA_CATE, (STATE_MACHINE_FUNC)PeerBAAction); - StateMachineSetAction(S, ACT_IDLE, MT2_PEER_HT_CATE, (STATE_MACHINE_FUNC)PeerHTAction); - StateMachineSetAction(S, ACT_IDLE, MT2_MLME_ADD_BA_CATE, (STATE_MACHINE_FUNC)MlmeADDBAAction); - StateMachineSetAction(S, ACT_IDLE, MT2_MLME_ORI_DELBA_CATE, (STATE_MACHINE_FUNC)MlmeDELBAAction); - StateMachineSetAction(S, ACT_IDLE, MT2_MLME_REC_DELBA_CATE, (STATE_MACHINE_FUNC)MlmeDELBAAction); -#endif // DOT11_N_SUPPORT // - - StateMachineSetAction(S, ACT_IDLE, MT2_PEER_PUBLIC_CATE, (STATE_MACHINE_FUNC)PeerPublicAction); - StateMachineSetAction(S, ACT_IDLE, MT2_PEER_RM_CATE, (STATE_MACHINE_FUNC)PeerRMAction); - - StateMachineSetAction(S, ACT_IDLE, MT2_MLME_QOS_CATE, (STATE_MACHINE_FUNC)MlmeQOSAction); - StateMachineSetAction(S, ACT_IDLE, MT2_MLME_DLS_CATE, (STATE_MACHINE_FUNC)MlmeDLSAction); - StateMachineSetAction(S, ACT_IDLE, MT2_ACT_INVALID, (STATE_MACHINE_FUNC)MlmeInvalidAction); -} - -#ifdef DOT11_N_SUPPORT -VOID MlmeADDBAAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) - -{ - MLME_ADDBA_REQ_STRUCT *pInfo; - UCHAR Addr[6]; - PUCHAR pOutBuffer = NULL; - NDIS_STATUS NStatus; - ULONG Idx; - FRAME_ADDBA_REQ Frame; - ULONG FrameLen; - BA_ORI_ENTRY *pBAEntry = NULL; - - pInfo = (MLME_ADDBA_REQ_STRUCT *)Elem->Msg; - NdisZeroMemory(&Frame, sizeof(FRAME_ADDBA_REQ)); - - if(MlmeAddBAReqSanity(pAd, Elem->Msg, Elem->MsgLen, Addr)) - { - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory - if(NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_TRACE,("BA - MlmeADDBAAction() allocate memory failed \n")); - return; - } - // 1. find entry - Idx = pAd->MacTab.Content[pInfo->Wcid].BAOriWcidArray[pInfo->TID]; - if (Idx == 0) - { - MlmeFreeMemory(pAd, pOutBuffer); - DBGPRINT(RT_DEBUG_ERROR,("BA - MlmeADDBAAction() can't find BAOriEntry \n")); - return; - } - else - { - pBAEntry =&pAd->BATable.BAOriEntry[Idx]; - } - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - if (ADHOC_ON(pAd)) - ActHeaderInit(pAd, &Frame.Hdr, pInfo->pAddr, pAd->CurrentAddress, pAd->CommonCfg.Bssid); - else -#ifdef QOS_DLS_SUPPORT - if (pAd->MacTab.Content[pInfo->Wcid].ValidAsDls) - ActHeaderInit(pAd, &Frame.Hdr, pInfo->pAddr, pAd->CurrentAddress, pAd->CommonCfg.Bssid); - else -#endif // QOS_DLS_SUPPORT // - ActHeaderInit(pAd, &Frame.Hdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pInfo->pAddr); - - } -#endif // CONFIG_STA_SUPPORT // - - Frame.Category = CATEGORY_BA; - Frame.Action = ADDBA_REQ; - Frame.BaParm.AMSDUSupported = 0; - Frame.BaParm.BAPolicy = IMMED_BA; - Frame.BaParm.TID = pInfo->TID; - Frame.BaParm.BufSize = pInfo->BaBufSize; - Frame.Token = pInfo->Token; - Frame.TimeOutValue = pInfo->TimeOutValue; - Frame.BaStartSeq.field.FragNum = 0; - Frame.BaStartSeq.field.StartSeq = pAd->MacTab.Content[pInfo->Wcid].TxSeq[pInfo->TID]; - - *(USHORT *)(&Frame.BaParm) = cpu2le16(*(USHORT *)(&Frame.BaParm)); - Frame.TimeOutValue = cpu2le16(Frame.TimeOutValue); - Frame.BaStartSeq.word = cpu2le16(Frame.BaStartSeq.word); - - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(FRAME_ADDBA_REQ), &Frame, - END_OF_ARGS); - MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); - - DBGPRINT(RT_DEBUG_TRACE, ("BA - Send ADDBA request. StartSeq = %x, FrameLen = %ld. BufSize = %d\n", Frame.BaStartSeq.field.StartSeq, FrameLen, Frame.BaParm.BufSize)); - } -} - -/* - ========================================================================== - Description: - send DELBA and delete BaEntry if any - Parametrs: - Elem - MLME message MLME_DELBA_REQ_STRUCT - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID MlmeDELBAAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - MLME_DELBA_REQ_STRUCT *pInfo; - PUCHAR pOutBuffer = NULL; - PUCHAR pOutBuffer2 = NULL; - NDIS_STATUS NStatus; - ULONG Idx; - FRAME_DELBA_REQ Frame; - ULONG FrameLen; - FRAME_BAR FrameBar; - - pInfo = (MLME_DELBA_REQ_STRUCT *)Elem->Msg; - // must send back DELBA - NdisZeroMemory(&Frame, sizeof(FRAME_DELBA_REQ)); - DBGPRINT(RT_DEBUG_TRACE, ("==> MlmeDELBAAction(), Initiator(%d) \n", pInfo->Initiator)); - - if(MlmeDelBAReqSanity(pAd, Elem->Msg, Elem->MsgLen)) - { - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory - if(NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_ERROR,("BA - MlmeDELBAAction() allocate memory failed 1. \n")); - return; - } - - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer2); //Get an unused nonpaged memory - if(NStatus != NDIS_STATUS_SUCCESS) - { - MlmeFreeMemory(pAd, pOutBuffer); - DBGPRINT(RT_DEBUG_ERROR, ("BA - MlmeDELBAAction() allocate memory failed 2. \n")); - return; - } - - // SEND BAR (Send BAR to refresh peer reordering buffer.) - Idx = pAd->MacTab.Content[pInfo->Wcid].BAOriWcidArray[pInfo->TID]; - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - BarHeaderInit(pAd, &FrameBar, pAd->MacTab.Content[pInfo->Wcid].Addr, pAd->CurrentAddress); -#endif // CONFIG_STA_SUPPORT // - - FrameBar.StartingSeq.field.FragNum = 0; // make sure sequence not clear in DEL funciton. - FrameBar.StartingSeq.field.StartSeq = pAd->MacTab.Content[pInfo->Wcid].TxSeq[pInfo->TID]; // make sure sequence not clear in DEL funciton. - FrameBar.BarControl.TID = pInfo->TID; // make sure sequence not clear in DEL funciton. - FrameBar.BarControl.ACKPolicy = IMMED_BA; // make sure sequence not clear in DEL funciton. - FrameBar.BarControl.Compressed = 1; // make sure sequence not clear in DEL funciton. - FrameBar.BarControl.MTID = 0; // make sure sequence not clear in DEL funciton. - - MakeOutgoingFrame(pOutBuffer2, &FrameLen, - sizeof(FRAME_BAR), &FrameBar, - END_OF_ARGS); - MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer2, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer2); - DBGPRINT(RT_DEBUG_TRACE,("BA - MlmeDELBAAction() . Send BAR to refresh peer reordering buffer \n")); - - // SEND DELBA FRAME - FrameLen = 0; -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - if (ADHOC_ON(pAd)) - ActHeaderInit(pAd, &Frame.Hdr, pAd->MacTab.Content[pInfo->Wcid].Addr, pAd->CurrentAddress, pAd->CommonCfg.Bssid); - else -#ifdef QOS_DLS_SUPPORT - if (pAd->MacTab.Content[pInfo->Wcid].ValidAsDls) - ActHeaderInit(pAd, &Frame.Hdr, pAd->MacTab.Content[pInfo->Wcid].Addr, pAd->CurrentAddress, pAd->CommonCfg.Bssid); - else -#endif // QOS_DLS_SUPPORT // - ActHeaderInit(pAd, &Frame.Hdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pAd->MacTab.Content[pInfo->Wcid].Addr); - } -#endif // CONFIG_STA_SUPPORT // - Frame.Category = CATEGORY_BA; - Frame.Action = DELBA; - Frame.DelbaParm.Initiator = pInfo->Initiator; - Frame.DelbaParm.TID = pInfo->TID; - Frame.ReasonCode = 39; // Time Out - *(USHORT *)(&Frame.DelbaParm) = cpu2le16(*(USHORT *)(&Frame.DelbaParm)); - Frame.ReasonCode = cpu2le16(Frame.ReasonCode); - - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(FRAME_DELBA_REQ), &Frame, - END_OF_ARGS); - MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); - DBGPRINT(RT_DEBUG_TRACE, ("BA - MlmeDELBAAction() . 3 DELBA sent. Initiator(%d)\n", pInfo->Initiator)); - } -} -#endif // DOT11_N_SUPPORT // - -VOID MlmeQOSAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ -} - -VOID MlmeDLSAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ -} - -VOID MlmeInvalidAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - //PUCHAR pOutBuffer = NULL; - //Return the receiving frame except the MSB of category filed set to 1. 7.3.1.11 -} - -VOID PeerQOSAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ -} - -#ifdef QOS_DLS_SUPPORT -VOID PeerDLSAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - UCHAR Action = Elem->Msg[LENGTH_802_11+1]; - - switch(Action) - { - case ACTION_DLS_REQUEST: -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - PeerDlsReqAction(pAd, Elem); -#endif // CONFIG_STA_SUPPORT // - break; - - case ACTION_DLS_RESPONSE: -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - PeerDlsRspAction(pAd, Elem); -#endif // CONFIG_STA_SUPPORT // - break; - - case ACTION_DLS_TEARDOWN: -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - PeerDlsTearDownAction(pAd, Elem); -#endif // CONFIG_STA_SUPPORT // - break; - } -} -#endif // QOS_DLS_SUPPORT // - -#ifdef DOT11_N_SUPPORT -VOID PeerBAAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - UCHAR Action = Elem->Msg[LENGTH_802_11+1]; - - switch(Action) - { - case ADDBA_REQ: - PeerAddBAReqAction(pAd,Elem); - break; - case ADDBA_RESP: - PeerAddBARspAction(pAd,Elem); - break; - case DELBA: - PeerDelBAAction(pAd,Elem); - break; - } -} - - -#ifdef DOT11N_DRAFT3 - -#ifdef CONFIG_STA_SUPPORT -VOID StaPublicAction( - IN PRTMP_ADAPTER pAd, - IN UCHAR Bss2040Coexist) -{ - BSS_2040_COEXIST_IE BssCoexist; - MLME_SCAN_REQ_STRUCT ScanReq; - - BssCoexist.word = Bss2040Coexist; - // AP asks Station to return a 20/40 BSS Coexistence mgmt frame. So we first starts a scan, then send back 20/40 BSS Coexistence mgmt frame - if ((BssCoexist.field.InfoReq == 1) && (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_SCAN_2040))) - { - // Clear record first. After scan , will update those bit and send back to transmiter. - pAd->CommonCfg.BSSCoexist2040.field.InfoReq = 1; - pAd->CommonCfg.BSSCoexist2040.field.Intolerant40 = 0; - pAd->CommonCfg.BSSCoexist2040.field.BSS20WidthReq = 0; - // Fill out stuff for scan request - ScanParmFill(pAd, &ScanReq, ZeroSsid, 0, BSS_ANY, SCAN_2040_BSS_COEXIST); - MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq); - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN; - } -} - - -/* -Description : Build Intolerant Channel Rerpot from Trigger event table. -return : how many bytes copied. -*/ -ULONG BuildIntolerantChannelRep( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDest) -{ - ULONG FrameLen = 0; - ULONG ReadOffset = 0; - UCHAR i; - UCHAR LastRegClass = 0xff; - PUCHAR pLen; - - for ( i = 0;i < MAX_TRIGGER_EVENT;i++) - { - if (pAd->CommonCfg.TriggerEventTab.EventA[i].bValid == TRUE) - { - if (pAd->CommonCfg.TriggerEventTab.EventA[i].RegClass == LastRegClass) - { - *(pDest + ReadOffset) = (UCHAR)pAd->CommonCfg.TriggerEventTab.EventA[i].Channel; - *pLen++; - ReadOffset++; - FrameLen++; - } - else - { - *(pDest + ReadOffset) = IE_2040_BSS_INTOLERANT_REPORT; // IE - *(pDest + ReadOffset + 1) = 2; // Len = RegClass byte + channel byte. - pLen = pDest + ReadOffset + 1; - LastRegClass = pAd->CommonCfg.TriggerEventTab.EventA[i].RegClass; - *(pDest + ReadOffset + 2) = LastRegClass; // Len = RegClass byte + channel byte. - *(pDest + ReadOffset + 3) = (UCHAR)pAd->CommonCfg.TriggerEventTab.EventA[i].Channel; - FrameLen += 4; - ReadOffset += 4; - } - - } - } - return FrameLen; -} - - -/* -Description : Send 20/40 BSS Coexistence Action frame If one trigger event is triggered. -*/ -VOID Send2040CoexistAction( - IN PRTMP_ADAPTER pAd, - IN UCHAR Wcid, - IN BOOLEAN bAddIntolerantCha) -{ - PUCHAR pOutBuffer = NULL; - NDIS_STATUS NStatus; - FRAME_ACTION_HDR Frame; - ULONG FrameLen; - ULONG IntolerantChaRepLen; - - IntolerantChaRepLen = 0; - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory - if(NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_ERROR,("ACT - Send2040CoexistAction() allocate memory failed \n")); - return; - } - ActHeaderInit(pAd, &Frame.Hdr, pAd->MacTab.Content[Wcid].Addr, pAd->CommonCfg.Bssid); - Frame.Category = CATEGORY_PUBLIC; - Frame.Action = ACTION_BSS_2040_COEXIST; - - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(FRAME_ACTION_HDR), &Frame, - END_OF_ARGS); - - *(pOutBuffer + FrameLen) = pAd->CommonCfg.BSSCoexist2040.word; - FrameLen++; - - if (bAddIntolerantCha == TRUE) - IntolerantChaRepLen = BuildIntolerantChannelRep(pAd, pOutBuffer + FrameLen); - - MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen + IntolerantChaRepLen); - DBGPRINT(RT_DEBUG_ERROR,("ACT - Send2040CoexistAction( BSSCoexist2040 = 0x%x ) \n", pAd->CommonCfg.BSSCoexist2040.word)); - -} - - -/* - ========================================================================== - Description: - After scan, Update 20/40 BSS Coexistence IE and send out. - According to 802.11n D3.03 11.14.10 - - Parameters: - ========================================================================== - */ -VOID Update2040CoexistFrameAndNotify( - IN PRTMP_ADAPTER pAd, - IN UCHAR Wcid, - IN BOOLEAN bAddIntolerantCha) -{ - BSS_2040_COEXIST_IE OldValue; - - OldValue.word = pAd->CommonCfg.BSSCoexist2040.word; - if ((pAd->CommonCfg.TriggerEventTab.EventANo > 0) || (pAd->CommonCfg.TriggerEventTab.EventBCountDown > 0)) - pAd->CommonCfg.BSSCoexist2040.field.BSS20WidthReq = 1; - - // Need to check !!!! - // How STA will set Intolerant40 if implementation dependent. Now we don't set this bit first.!!!!! - // So Only check BSS20WidthReq change. - if (OldValue.field.BSS20WidthReq != pAd->CommonCfg.BSSCoexist2040.field.BSS20WidthReq) - { - Send2040CoexistAction(pAd, Wcid, bAddIntolerantCha); - } -} -#endif // CONFIG_STA_SUPPORT // - - -BOOLEAN ChannelSwitchSanityCheck( - IN PRTMP_ADAPTER pAd, - IN UCHAR Wcid, - IN UCHAR NewChannel, - IN UCHAR Secondary) -{ - UCHAR i; - - if (Wcid >= MAX_LEN_OF_MAC_TABLE) - return FALSE; - - if ((NewChannel > 7) && (Secondary == 1)) - return FALSE; - - if ((NewChannel < 5) && (Secondary == 3)) - return FALSE; - - // 0. Check if new channel is in the channellist. - for (i = 0;i < pAd->ChannelListNum;i++) - { - if (pAd->ChannelList[i].Channel == NewChannel) - { - break; - } - } - - if (i == pAd->ChannelListNum) - return FALSE; - - return TRUE; -} - - -VOID ChannelSwitchAction( - IN PRTMP_ADAPTER pAd, - IN UCHAR Wcid, - IN UCHAR NewChannel, - IN UCHAR Secondary) -{ - UCHAR BBPValue = 0; - ULONG MACValue; - - DBGPRINT(RT_DEBUG_TRACE,("SPECTRUM - ChannelSwitchAction(NewChannel = %d , Secondary = %d) \n", NewChannel, Secondary)); - - if (ChannelSwitchSanityCheck(pAd, Wcid, NewChannel, Secondary) == FALSE) - return; - - // 1. Switches to BW = 20. - if (Secondary == 0) - { - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); - BBPValue&= (~0x18); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); - if (pAd->MACVersion == 0x28600100) - { - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, 0x16); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, 0x08); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R73, 0x11); - DBGPRINT(RT_DEBUG_TRACE, ("!!!rt2860C !!! \n" )); - } - pAd->CommonCfg.BBPCurrentBW = BW_20; - pAd->CommonCfg.Channel = NewChannel; - pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel; - AsicSwitchChannel(pAd, pAd->CommonCfg.Channel,FALSE); - AsicLockChannel(pAd, pAd->CommonCfg.Channel); - pAd->MacTab.Content[Wcid].HTPhyMode.field.BW = 0; - DBGPRINT(RT_DEBUG_TRACE, ("!!!20MHz !!! \n" )); - } - // 1. Switches to BW = 40 And Station supports BW = 40. - else if (((Secondary == 1) || (Secondary == 3)) && (pAd->CommonCfg.HtCapability.HtCapInfo.ChannelWidth == 1)) - { - pAd->CommonCfg.Channel = NewChannel; - - if (Secondary == 1) - { - // Secondary above. - pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel + 2; - RTMP_IO_READ32(pAd, TX_BAND_CFG, &MACValue); - MACValue &= 0xfe; - RTMP_IO_WRITE32(pAd, TX_BAND_CFG, MACValue); - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); - BBPValue&= (~0x18); - BBPValue|= (0x10); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BBPValue); - BBPValue&= (~0x20); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BBPValue); - DBGPRINT(RT_DEBUG_TRACE, ("!!!40MHz Lower LINK UP !!! Control Channel at Below. Central = %d \n", pAd->CommonCfg.CentralChannel )); - } - else - { - // Secondary below. - pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel - 2; - RTMP_IO_READ32(pAd, TX_BAND_CFG, &MACValue); - MACValue &= 0xfe; - MACValue |= 0x1; - RTMP_IO_WRITE32(pAd, TX_BAND_CFG, MACValue); - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); - BBPValue&= (~0x18); - BBPValue|= (0x10); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BBPValue); - BBPValue&= (~0x20); - BBPValue|= (0x20); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BBPValue); - DBGPRINT(RT_DEBUG_TRACE, ("!!!40MHz Upper LINK UP !!! Control Channel at UpperCentral = %d \n", pAd->CommonCfg.CentralChannel )); - } - pAd->CommonCfg.BBPCurrentBW = BW_40; - AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE); - AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel); - pAd->MacTab.Content[Wcid].HTPhyMode.field.BW = 1; - } -} -#endif // DOT11N_DRAFT3 // -#endif // DOT11_N_SUPPORT // - -VOID PeerPublicAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ -#ifdef DOT11N_DRAFT3 - UCHAR Action = Elem->Msg[LENGTH_802_11+1]; -#endif // DOT11N_DRAFT3 // - - if (Elem->Wcid >= MAX_LEN_OF_MAC_TABLE) - return; - -#ifdef DOT11N_DRAFT3 - switch(Action) - { - case ACTION_BSS_2040_COEXIST: // Format defined in IEEE 7.4.7a.1 in 11n Draf3.03 - { - //UCHAR BssCoexist; - BSS_2040_COEXIST_ELEMENT *pCoexistInfo; - BSS_2040_COEXIST_IE *pBssCoexistIe; - BSS_2040_INTOLERANT_CH_REPORT *pIntolerantReport = NULL; - - if (Elem->MsgLen <= (LENGTH_802_11 + sizeof(BSS_2040_COEXIST_ELEMENT)) ) - { - DBGPRINT(RT_DEBUG_ERROR, ("ACTION - 20/40 BSS Coexistence Management Frame length too short! len = %ld!\n", Elem->MsgLen)); - break; - } - DBGPRINT(RT_DEBUG_TRACE, ("ACTION - 20/40 BSS Coexistence Management action----> \n")); - hex_dump("CoexistenceMgmtFrame", Elem->Msg, Elem->MsgLen); - - - pCoexistInfo = (BSS_2040_COEXIST_ELEMENT *) &Elem->Msg[LENGTH_802_11+2]; - //hex_dump("CoexistInfo", (PUCHAR)pCoexistInfo, sizeof(BSS_2040_COEXIST_ELEMENT)); - if (Elem->MsgLen >= (LENGTH_802_11 + sizeof(BSS_2040_COEXIST_ELEMENT) + sizeof(BSS_2040_INTOLERANT_CH_REPORT))) - { - pIntolerantReport = (BSS_2040_INTOLERANT_CH_REPORT *)((PUCHAR)pCoexistInfo + sizeof(BSS_2040_COEXIST_ELEMENT)); - } - //hex_dump("IntolerantReport ", (PUCHAR)pIntolerantReport, sizeof(BSS_2040_INTOLERANT_CH_REPORT)); - - pBssCoexistIe = (BSS_2040_COEXIST_IE *)(&pCoexistInfo->BssCoexistIe); - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - if (INFRA_ON(pAd)) - { - StaPublicAction(pAd, pCoexistInfo); - } - } -#endif // CONFIG_STA_SUPPORT // - - } - break; - } - -#endif // DOT11N_DRAFT3 // - -} - - -static VOID ReservedAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - UCHAR Category; - - if (Elem->MsgLen <= LENGTH_802_11) - { - return; - } - - Category = Elem->Msg[LENGTH_802_11]; - DBGPRINT(RT_DEBUG_TRACE,("Rcv reserved category(%d) Action Frame\n", Category)); - hex_dump("Reserved Action Frame", &Elem->Msg[0], Elem->MsgLen); -} - -VOID PeerRMAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) - -{ - return; -} - -#ifdef DOT11_N_SUPPORT -static VOID respond_ht_information_exchange_action( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - PUCHAR pOutBuffer = NULL; - NDIS_STATUS NStatus; - ULONG FrameLen; - FRAME_HT_INFO HTINFOframe, *pFrame; - UCHAR *pAddr; - - - // 2. Always send back ADDBA Response - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory - - if (NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_TRACE,("ACTION - respond_ht_information_exchange_action() allocate memory failed \n")); - return; - } - - // get RA - pFrame = (FRAME_HT_INFO *) &Elem->Msg[0]; - pAddr = pFrame->Hdr.Addr2; - - NdisZeroMemory(&HTINFOframe, sizeof(FRAME_HT_INFO)); - // 2-1. Prepare ADDBA Response frame. -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - if (ADHOC_ON(pAd)) - ActHeaderInit(pAd, &HTINFOframe.Hdr, pAddr, pAd->CurrentAddress, pAd->CommonCfg.Bssid); - else - ActHeaderInit(pAd, &HTINFOframe.Hdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pAddr); - } -#endif // CONFIG_STA_SUPPORT // - - HTINFOframe.Category = CATEGORY_HT; - HTINFOframe.Action = HT_INFO_EXCHANGE; - HTINFOframe.HT_Info.Request = 0; - HTINFOframe.HT_Info.Forty_MHz_Intolerant = pAd->CommonCfg.HtCapability.HtCapInfo.Forty_Mhz_Intolerant; - HTINFOframe.HT_Info.STA_Channel_Width = pAd->CommonCfg.AddHTInfo.AddHtInfo.RecomWidth; - - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(FRAME_HT_INFO), &HTINFOframe, - END_OF_ARGS); - - MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); -} - - -#ifdef DOT11N_DRAFT3 -VOID SendNotifyBWActionFrame( - IN PRTMP_ADAPTER pAd, - IN UCHAR Wcid, - IN UCHAR apidx) -{ - PUCHAR pOutBuffer = NULL; - NDIS_STATUS NStatus; - FRAME_ACTION_HDR Frame; - ULONG FrameLen; - PUCHAR pAddr1; - - - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory - if(NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_ERROR,("ACT - SendNotifyBWAction() allocate memory failed \n")); - return; - } - - if (Wcid == MCAST_WCID) - pAddr1 = &BROADCAST_ADDR[0]; - else - pAddr1 = pAd->MacTab.Content[Wcid].Addr; - ActHeaderInit(pAd, &Frame.Hdr, pAddr1, pAd->ApCfg.MBSSID[apidx].Bssid, pAd->ApCfg.MBSSID[apidx].Bssid); - - Frame.Category = CATEGORY_HT; - Frame.Action = NOTIFY_BW_ACTION; - - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(FRAME_ACTION_HDR), &Frame, - END_OF_ARGS); - - *(pOutBuffer + FrameLen) = pAd->CommonCfg.AddHTInfo.AddHtInfo.RecomWidth; - FrameLen++; - - - MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); - DBGPRINT(RT_DEBUG_TRACE,("ACT - SendNotifyBWAction(NotifyBW= %d)!\n", pAd->CommonCfg.AddHTInfo.AddHtInfo.RecomWidth)); - -} -#endif // DOT11N_DRAFT3 // - - -VOID PeerHTAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - UCHAR Action = Elem->Msg[LENGTH_802_11+1]; - - if (Elem->Wcid >= MAX_LEN_OF_MAC_TABLE) - return; - - switch(Action) - { - case NOTIFY_BW_ACTION: - DBGPRINT(RT_DEBUG_TRACE,("ACTION - HT Notify Channel bandwidth action----> \n")); -#ifdef CONFIG_STA_SUPPORT - if(pAd->StaActive.SupportedPhyInfo.bHtEnable == FALSE) - { - // Note, this is to patch DIR-1353 AP. When the AP set to Wep, it will use legacy mode. But AP still keeps - // sending BW_Notify Action frame, and cause us to linkup and linkdown. - // In legacy mode, don't need to parse HT action frame. - DBGPRINT(RT_DEBUG_TRACE,("ACTION -Ignore HT Notify Channel BW when link as legacy mode. BW = %d---> \n", - Elem->Msg[LENGTH_802_11+2] )); - break; - } -#endif // CONFIG_STA_SUPPORT // - - if (Elem->Msg[LENGTH_802_11+2] == 0) // 7.4.8.2. if value is 1, keep the same as supported channel bandwidth. - pAd->MacTab.Content[Elem->Wcid].HTPhyMode.field.BW = 0; - - break; - - case SMPS_ACTION: - // 7.3.1.25 - DBGPRINT(RT_DEBUG_TRACE,("ACTION - SMPS action----> \n")); - if (((Elem->Msg[LENGTH_802_11+2]&0x1) == 0)) - { - pAd->MacTab.Content[Elem->Wcid].MmpsMode = MMPS_ENABLE; - } - else if (((Elem->Msg[LENGTH_802_11+2]&0x2) == 0)) - { - pAd->MacTab.Content[Elem->Wcid].MmpsMode = MMPS_STATIC; - } - else - { - pAd->MacTab.Content[Elem->Wcid].MmpsMode = MMPS_DYNAMIC; - } - - DBGPRINT(RT_DEBUG_TRACE,("Aid(%d) MIMO PS = %d\n", Elem->Wcid, pAd->MacTab.Content[Elem->Wcid].MmpsMode)); - // rt2860c : add something for smps change. - break; - - case SETPCO_ACTION: - break; - - case MIMO_CHA_MEASURE_ACTION: - break; - - case HT_INFO_EXCHANGE: - { - HT_INFORMATION_OCTET *pHT_info; - - pHT_info = (HT_INFORMATION_OCTET *) &Elem->Msg[LENGTH_802_11+2]; - // 7.4.8.10 - DBGPRINT(RT_DEBUG_TRACE,("ACTION - HT Information Exchange action----> \n")); - if (pHT_info->Request) - { - respond_ht_information_exchange_action(pAd, Elem); - } - } - break; - } -} - - -/* - ========================================================================== - Description: - Retry sending ADDBA Reqest. - - IRQL = DISPATCH_LEVEL - - Parametrs: - p8023Header: if this is already 802.3 format, p8023Header is NULL - - Return : TRUE if put into rx reordering buffer, shouldn't indicaterxhere. - FALSE , then continue indicaterx at this moment. - ========================================================================== - */ -VOID ORIBATimerTimeout( - IN PRTMP_ADAPTER pAd) -{ - MAC_TABLE_ENTRY *pEntry; - INT i, total; -// FRAME_BAR FrameBar; -// ULONG FrameLen; -// NDIS_STATUS NStatus; -// PUCHAR pOutBuffer = NULL; -// USHORT Sequence; - UCHAR TID; - -#ifdef RALINK_ATE - if (ATE_ON(pAd)) - return; -#endif // RALINK_ATE // - - total = pAd->MacTab.Size * NUM_OF_TID; - - for (i = 1; ((i 0)) ; i++) - { - if (pAd->BATable.BAOriEntry[i].ORI_BA_Status == Originator_Done) - { - pEntry = &pAd->MacTab.Content[pAd->BATable.BAOriEntry[i].Wcid]; - TID = pAd->BATable.BAOriEntry[i].TID; - - ASSERT(pAd->BATable.BAOriEntry[i].Wcid < MAX_LEN_OF_MAC_TABLE); - } - total --; - } -} - - -VOID SendRefreshBAR( - IN PRTMP_ADAPTER pAd, - IN MAC_TABLE_ENTRY *pEntry) -{ - FRAME_BAR FrameBar; - ULONG FrameLen; - NDIS_STATUS NStatus; - PUCHAR pOutBuffer = NULL; - USHORT Sequence; - UCHAR i, TID; - USHORT idx; - BA_ORI_ENTRY *pBAEntry; - - for (i = 0; i BAOriWcidArray[i]; - if (idx == 0) - { - continue; - } - pBAEntry = &pAd->BATable.BAOriEntry[idx]; - - if (pBAEntry->ORI_BA_Status == Originator_Done) - { - TID = pBAEntry->TID; - - ASSERT(pBAEntry->Wcid < MAX_LEN_OF_MAC_TABLE); - - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory - if(NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_ERROR,("BA - MlmeADDBAAction() allocate memory failed \n")); - return; - } - - Sequence = pEntry->TxSeq[TID]; - - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - BarHeaderInit(pAd, &FrameBar, pEntry->Addr, pAd->CurrentAddress); -#endif // CONFIG_STA_SUPPORT // - - FrameBar.StartingSeq.field.FragNum = 0; // make sure sequence not clear in DEL function. - FrameBar.StartingSeq.field.StartSeq = Sequence; // make sure sequence not clear in DEL funciton. - FrameBar.BarControl.TID = TID; // make sure sequence not clear in DEL funciton. - - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(FRAME_BAR), &FrameBar, - END_OF_ARGS); - //if (!(CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_RALINK_CHIPSET))) - if (1) // Now we always send BAR. - { - //MiniportMMRequestUnlock(pAd, 0, pOutBuffer, FrameLen); - MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); - } - MlmeFreeMemory(pAd, pOutBuffer); - } - } -} -#endif // DOT11_N_SUPPORT // - -VOID ActHeaderInit( - IN PRTMP_ADAPTER pAd, - IN OUT PHEADER_802_11 pHdr80211, - IN PUCHAR Addr1, - IN PUCHAR Addr2, - IN PUCHAR Addr3) -{ - NdisZeroMemory(pHdr80211, sizeof(HEADER_802_11)); - pHdr80211->FC.Type = BTYPE_MGMT; - pHdr80211->FC.SubType = SUBTYPE_ACTION; - - COPY_MAC_ADDR(pHdr80211->Addr1, Addr1); - COPY_MAC_ADDR(pHdr80211->Addr2, Addr2); - COPY_MAC_ADDR(pHdr80211->Addr3, Addr3); -} - -VOID BarHeaderInit( - IN PRTMP_ADAPTER pAd, - IN OUT PFRAME_BAR pCntlBar, - IN PUCHAR pDA, - IN PUCHAR pSA) -{ -// USHORT Duration; - - NdisZeroMemory(pCntlBar, sizeof(FRAME_BAR)); - pCntlBar->FC.Type = BTYPE_CNTL; - pCntlBar->FC.SubType = SUBTYPE_BLOCK_ACK_REQ; - pCntlBar->BarControl.MTID = 0; - pCntlBar->BarControl.Compressed = 1; - pCntlBar->BarControl.ACKPolicy = 0; - - - pCntlBar->Duration = 16 + RTMPCalcDuration(pAd, RATE_1, sizeof(FRAME_BA)); - - COPY_MAC_ADDR(pCntlBar->Addr1, pDA); - COPY_MAC_ADDR(pCntlBar->Addr2, pSA); -} - - -/* - ========================================================================== - Description: - Insert Category and action code into the action frame. - - Parametrs: - 1. frame buffer pointer. - 2. frame length. - 3. category code of the frame. - 4. action code of the frame. - - Return : None. - ========================================================================== - */ -VOID InsertActField( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pFrameBuf, - OUT PULONG pFrameLen, - IN UINT8 Category, - IN UINT8 ActCode) -{ - ULONG TempLen; - - MakeOutgoingFrame( pFrameBuf, &TempLen, - 1, &Category, - 1, &ActCode, - END_OF_ARGS); - - *pFrameLen = *pFrameLen + TempLen; - - return; -} +#include "../../rt2860/common/action.c" diff --git a/drivers/staging/rt2870/common/action.h b/drivers/staging/rt2870/common/action.h index ce3877dce81b..9a1895525f30 100644 --- a/drivers/staging/rt2870/common/action.h +++ b/drivers/staging/rt2870/common/action.h @@ -1,68 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - aironet.h - - Abstract: - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Name Date Modification logs - Paul Lin 04-06-15 Initial -*/ - -#ifndef __ACTION_H__ -#define __ACTION_H__ - -typedef struct PACKED __HT_INFO_OCTET -{ -#ifdef RT_BIG_ENDIAN - UCHAR Reserved:5; - UCHAR STA_Channel_Width:1; - UCHAR Forty_MHz_Intolerant:1; - UCHAR Request:1; -#else - UCHAR Request:1; - UCHAR Forty_MHz_Intolerant:1; - UCHAR STA_Channel_Width:1; - UCHAR Reserved:5; -#endif -} HT_INFORMATION_OCTET; - - -typedef struct PACKED __FRAME_HT_INFO -{ - HEADER_802_11 Hdr; - UCHAR Category; - UCHAR Action; - HT_INFORMATION_OCTET HT_Info; -} FRAME_HT_INFO, *PFRAME_HT_INFO; - -#endif /* __ACTION_H__ */ - - +#include "../../rt2860/common/action.h" diff --git a/drivers/staging/rt2870/common/ba_action.c b/drivers/staging/rt2870/common/ba_action.c index d9f738177e2b..a9e6a09d994f 100644 --- a/drivers/staging/rt2870/common/ba_action.c +++ b/drivers/staging/rt2870/common/ba_action.c @@ -1,1798 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * 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. * - * * - ************************************************************************* - */ - - -#ifdef DOT11_N_SUPPORT - -#include "../rt_config.h" - - - -#define BA_ORI_INIT_SEQ (pEntry->TxSeq[TID]) //1 // inital sequence number of BA session - -#define ORI_SESSION_MAX_RETRY 8 -#define ORI_BA_SESSION_TIMEOUT (2000) // ms -#define REC_BA_SESSION_IDLE_TIMEOUT (1000) // ms - -#define REORDERING_PACKET_TIMEOUT ((100 * HZ)/1000) // system ticks -- 100 ms -#define MAX_REORDERING_PACKET_TIMEOUT ((3000 * HZ)/1000) // system ticks -- 100 ms - -#define RESET_RCV_SEQ (0xFFFF) - -static void ba_mpdu_blk_free(PRTMP_ADAPTER pAd, struct reordering_mpdu *mpdu_blk); - - -BA_ORI_ENTRY *BATableAllocOriEntry( - IN PRTMP_ADAPTER pAd, - OUT USHORT *Idx); - -BA_REC_ENTRY *BATableAllocRecEntry( - IN PRTMP_ADAPTER pAd, - OUT USHORT *Idx); - -VOID BAOriSessionSetupTimeout( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); - -VOID BARecSessionIdleTimeout( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); - - -BUILD_TIMER_FUNCTION(BAOriSessionSetupTimeout); -BUILD_TIMER_FUNCTION(BARecSessionIdleTimeout); - -#define ANNOUNCE_REORDERING_PACKET(_pAd, _mpdu_blk) \ - Announce_Reordering_Packet(_pAd, _mpdu_blk); - -VOID BA_MaxWinSizeReasign( - IN PRTMP_ADAPTER pAd, - IN MAC_TABLE_ENTRY *pEntryPeer, - OUT UCHAR *pWinSize) -{ - UCHAR MaxSize; - - - if (pAd->MACVersion >= RALINK_2883_VERSION) // 3*3 - { - if (pAd->MACVersion >= RALINK_3070_VERSION) - { - if (pEntryPeer->WepStatus != Ndis802_11EncryptionDisabled) - MaxSize = 7; // for non-open mode - else - MaxSize = 13; - } - else - MaxSize = 31; - } - else if (pAd->MACVersion >= RALINK_2880E_VERSION) // 2880 e - { - if (pEntryPeer->WepStatus != Ndis802_11EncryptionDisabled) - MaxSize = 7; // for non-open mode - else - MaxSize = 13; - } - else - MaxSize = 7; - - DBGPRINT(RT_DEBUG_TRACE, ("ba> Win Size = %d, Max Size = %d\n", - *pWinSize, MaxSize)); - - if ((*pWinSize) > MaxSize) - { - DBGPRINT(RT_DEBUG_TRACE, ("ba> reassign max win size from %d to %d\n", - *pWinSize, MaxSize)); - - *pWinSize = MaxSize; - } -} - -void Announce_Reordering_Packet(IN PRTMP_ADAPTER pAd, - IN struct reordering_mpdu *mpdu) -{ - PNDIS_PACKET pPacket; - - pPacket = mpdu->pPacket; - - if (mpdu->bAMSDU) - { - ASSERT(0); - BA_Reorder_AMSDU_Annnounce(pAd, pPacket); - } - else - { - // - // pass this 802.3 packet to upper layer or forward this packet to WM directly - // - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - ANNOUNCE_OR_FORWARD_802_3_PACKET(pAd, pPacket, RTMP_GET_PACKET_IF(pPacket)); -#endif // CONFIG_STA_SUPPORT // - } -} - -/* - * Insert a reordering mpdu into sorted linked list by sequence no. - */ -BOOLEAN ba_reordering_mpdu_insertsorted(struct reordering_list *list, struct reordering_mpdu *mpdu) -{ - - struct reordering_mpdu **ppScan = &list->next; - - while (*ppScan != NULL) - { - if (SEQ_SMALLER((*ppScan)->Sequence, mpdu->Sequence, MAXSEQ)) - { - ppScan = &(*ppScan)->next; - } - else if ((*ppScan)->Sequence == mpdu->Sequence) - { - /* give up this duplicated frame */ - return(FALSE); - } - else - { - /* find position */ - break; - } - } - - mpdu->next = *ppScan; - *ppScan = mpdu; - list->qlen++; - return TRUE; -} - - -/* - * caller lock critical section if necessary - */ -static inline void ba_enqueue(struct reordering_list *list, struct reordering_mpdu *mpdu_blk) -{ - list->qlen++; - mpdu_blk->next = list->next; - list->next = mpdu_blk; -} - -/* - * caller lock critical section if necessary - */ -static inline struct reordering_mpdu * ba_dequeue(struct reordering_list *list) -{ - struct reordering_mpdu *mpdu_blk = NULL; - - ASSERT(list); - - if (list->qlen) - { - list->qlen--; - mpdu_blk = list->next; - if (mpdu_blk) - { - list->next = mpdu_blk->next; - mpdu_blk->next = NULL; - } - } - return mpdu_blk; -} - - -static inline struct reordering_mpdu *ba_reordering_mpdu_dequeue(struct reordering_list *list) -{ - return(ba_dequeue(list)); -} - - -static inline struct reordering_mpdu *ba_reordering_mpdu_probe(struct reordering_list *list) - { - ASSERT(list); - - return(list->next); - } - - -/* - * free all resource for reordering mechanism - */ -void ba_reordering_resource_release(PRTMP_ADAPTER pAd) -{ - BA_TABLE *Tab; - PBA_REC_ENTRY pBAEntry; - struct reordering_mpdu *mpdu_blk; - int i; - - Tab = &pAd->BATable; - - /* I. release all pending reordering packet */ - NdisAcquireSpinLock(&pAd->BATabLock); - for (i = 0; i < MAX_LEN_OF_BA_REC_TABLE; i++) - { - pBAEntry = &Tab->BARecEntry[i]; - if (pBAEntry->REC_BA_Status != Recipient_NONE) - { - while ((mpdu_blk = ba_reordering_mpdu_dequeue(&pBAEntry->list))) - { - ASSERT(mpdu_blk->pPacket); - RELEASE_NDIS_PACKET(pAd, mpdu_blk->pPacket, NDIS_STATUS_FAILURE); - ba_mpdu_blk_free(pAd, mpdu_blk); - } - } - } - NdisReleaseSpinLock(&pAd->BATabLock); - - ASSERT(pBAEntry->list.qlen == 0); - /* II. free memory of reordering mpdu table */ - NdisAcquireSpinLock(&pAd->mpdu_blk_pool.lock); - os_free_mem(pAd, pAd->mpdu_blk_pool.mem); - NdisReleaseSpinLock(&pAd->mpdu_blk_pool.lock); -} - - - -/* - * Allocate all resource for reordering mechanism - */ -BOOLEAN ba_reordering_resource_init(PRTMP_ADAPTER pAd, int num) -{ - int i; - PUCHAR mem; - struct reordering_mpdu *mpdu_blk; - struct reordering_list *freelist; - - /* allocate spinlock */ - NdisAllocateSpinLock(&pAd->mpdu_blk_pool.lock); - - /* initialize freelist */ - freelist = &pAd->mpdu_blk_pool.freelist; - freelist->next = NULL; - freelist->qlen = 0; - - DBGPRINT(RT_DEBUG_TRACE, ("Allocate %d memory for BA reordering\n", (UINT32)(num*sizeof(struct reordering_mpdu)))); - - /* allocate number of mpdu_blk memory */ - os_alloc_mem(pAd, (PUCHAR *)&mem, (num*sizeof(struct reordering_mpdu))); - - pAd->mpdu_blk_pool.mem = mem; - - if (mem == NULL) - { - DBGPRINT(RT_DEBUG_ERROR, ("Can't Allocate Memory for BA Reordering\n")); - return(FALSE); - } - - /* build mpdu_blk free list */ - for (i=0; impdu_blk_pool.lock); - mpdu_blk = ba_dequeue(&pAd->mpdu_blk_pool.freelist); - if (mpdu_blk) - { -// blk_count++; - /* reset mpdu_blk */ - NdisZeroMemory(mpdu_blk, sizeof(struct reordering_mpdu)); - } - NdisReleaseSpinLock(&pAd->mpdu_blk_pool.lock); - return mpdu_blk; -} - -static void ba_mpdu_blk_free(PRTMP_ADAPTER pAd, struct reordering_mpdu *mpdu_blk) -{ - ASSERT(mpdu_blk); - - NdisAcquireSpinLock(&pAd->mpdu_blk_pool.lock); -// blk_count--; - ba_enqueue(&pAd->mpdu_blk_pool.freelist, mpdu_blk); - NdisReleaseSpinLock(&pAd->mpdu_blk_pool.lock); -} - - -static USHORT ba_indicate_reordering_mpdus_in_order( - IN PRTMP_ADAPTER pAd, - IN PBA_REC_ENTRY pBAEntry, - IN USHORT StartSeq) -{ - struct reordering_mpdu *mpdu_blk; - USHORT LastIndSeq = RESET_RCV_SEQ; - - NdisAcquireSpinLock(&pBAEntry->RxReRingLock); - - while ((mpdu_blk = ba_reordering_mpdu_probe(&pBAEntry->list))) - { - /* find in-order frame */ - if (!SEQ_STEPONE(mpdu_blk->Sequence, StartSeq, MAXSEQ)) - { - break; - } - /* dequeue in-order frame from reodering list */ - mpdu_blk = ba_reordering_mpdu_dequeue(&pBAEntry->list); - /* pass this frame up */ - ANNOUNCE_REORDERING_PACKET(pAd, mpdu_blk); - /* move to next sequence */ - StartSeq = mpdu_blk->Sequence; - LastIndSeq = StartSeq; - /* free mpdu_blk */ - ba_mpdu_blk_free(pAd, mpdu_blk); - } - - NdisReleaseSpinLock(&pBAEntry->RxReRingLock); - - /* update last indicated sequence */ - return LastIndSeq; -} - -static void ba_indicate_reordering_mpdus_le_seq( - IN PRTMP_ADAPTER pAd, - IN PBA_REC_ENTRY pBAEntry, - IN USHORT Sequence) -{ - struct reordering_mpdu *mpdu_blk; - - NdisAcquireSpinLock(&pBAEntry->RxReRingLock); - while ((mpdu_blk = ba_reordering_mpdu_probe(&pBAEntry->list))) - { - /* find in-order frame */ - if ((mpdu_blk->Sequence == Sequence) || SEQ_SMALLER(mpdu_blk->Sequence, Sequence, MAXSEQ)) - { - /* dequeue in-order frame from reodering list */ - mpdu_blk = ba_reordering_mpdu_dequeue(&pBAEntry->list); - /* pass this frame up */ - ANNOUNCE_REORDERING_PACKET(pAd, mpdu_blk); - /* free mpdu_blk */ - ba_mpdu_blk_free(pAd, mpdu_blk); - } - else - { - break; - } - } - NdisReleaseSpinLock(&pBAEntry->RxReRingLock); -} - - -static void ba_refresh_reordering_mpdus( - IN PRTMP_ADAPTER pAd, - PBA_REC_ENTRY pBAEntry) -{ - struct reordering_mpdu *mpdu_blk; - - NdisAcquireSpinLock(&pBAEntry->RxReRingLock); - - /* dequeue in-order frame from reodering list */ - while ((mpdu_blk = ba_reordering_mpdu_dequeue(&pBAEntry->list))) - { - /* pass this frame up */ - ANNOUNCE_REORDERING_PACKET(pAd, mpdu_blk); - - pBAEntry->LastIndSeq = mpdu_blk->Sequence; - ba_mpdu_blk_free(pAd, mpdu_blk); - - /* update last indicated sequence */ - } - ASSERT(pBAEntry->list.qlen == 0); - pBAEntry->LastIndSeq = RESET_RCV_SEQ; - NdisReleaseSpinLock(&pBAEntry->RxReRingLock); -} - - -//static -void ba_flush_reordering_timeout_mpdus( - IN PRTMP_ADAPTER pAd, - IN PBA_REC_ENTRY pBAEntry, - IN ULONG Now32) - -{ - USHORT Sequence; - -// if ((RTMP_TIME_AFTER((unsigned long)Now32, (unsigned long)(pBAEntry->LastIndSeqAtTimer+REORDERING_PACKET_TIMEOUT)) && -// (pBAEntry->list.qlen > ((pBAEntry->BAWinSize*7)/8))) //|| -// (RTMP_TIME_AFTER((unsigned long)Now32, (unsigned long)(pBAEntry->LastIndSeqAtTimer+(10*REORDERING_PACKET_TIMEOUT))) && -// (pBAEntry->list.qlen > (pBAEntry->BAWinSize/8))) - if (RTMP_TIME_AFTER((unsigned long)Now32, (unsigned long)(pBAEntry->LastIndSeqAtTimer+(MAX_REORDERING_PACKET_TIMEOUT/6))) - &&(pBAEntry->list.qlen > 1) - ) - { - DBGPRINT(RT_DEBUG_TRACE,("timeout[%d] (%08lx-%08lx = %d > %d): %x, flush all!\n ", pBAEntry->list.qlen, Now32, (pBAEntry->LastIndSeqAtTimer), - (int)((long) Now32 - (long)(pBAEntry->LastIndSeqAtTimer)), MAX_REORDERING_PACKET_TIMEOUT, - pBAEntry->LastIndSeq)); - ba_refresh_reordering_mpdus(pAd, pBAEntry); - pBAEntry->LastIndSeqAtTimer = Now32; - } - else - if (RTMP_TIME_AFTER((unsigned long)Now32, (unsigned long)(pBAEntry->LastIndSeqAtTimer+(REORDERING_PACKET_TIMEOUT))) - && (pBAEntry->list.qlen > 0) - ) - { - // - // force LastIndSeq to shift to LastIndSeq+1 - // - Sequence = (pBAEntry->LastIndSeq+1) & MAXSEQ; - ba_indicate_reordering_mpdus_le_seq(pAd, pBAEntry, Sequence); - pBAEntry->LastIndSeqAtTimer = Now32; - pBAEntry->LastIndSeq = Sequence; - // - // indicate in-order mpdus - // - Sequence = ba_indicate_reordering_mpdus_in_order(pAd, pBAEntry, Sequence); - if (Sequence != RESET_RCV_SEQ) - { - pBAEntry->LastIndSeq = Sequence; - } - - } -#if 0 - else if ( - (RTMP_TIME_AFTER((unsigned long)Now32, (unsigned long)(pBAEntry->LastIndSeqAtTimer+(MAX_REORDERING_PACKET_TIMEOUT))) && - (pBAEntry->list.qlen > 1)) - ) - { - DBGPRINT(RT_DEBUG_TRACE,("timeout[%d] (%lx-%lx = %d > %d): %x\n ", pBAEntry->list.qlen, Now32, (pBAEntry->LastIndSeqAtTimer), - (int)((long) Now32 - (long)(pBAEntry->LastIndSeqAtTimer)), MAX_REORDERING_PACKET_TIMEOUT, - pBAEntry->LastIndSeq)); - ba_refresh_reordering_mpdus(pAd, pBAEntry); - pBAEntry->LastIndSeqAtTimer = Now32; - } -#endif -} - - -/* - * generate ADDBA request to - * set up BA agreement - */ -VOID BAOriSessionSetUp( - IN PRTMP_ADAPTER pAd, - IN MAC_TABLE_ENTRY *pEntry, - IN UCHAR TID, - IN USHORT TimeOut, - IN ULONG DelayTime, - IN BOOLEAN isForced) - -{ - //MLME_ADDBA_REQ_STRUCT AddbaReq; - BA_ORI_ENTRY *pBAEntry = NULL; - USHORT Idx; - BOOLEAN Cancelled; - - if ((pAd->CommonCfg.BACapability.field.AutoBA != TRUE) && (isForced == FALSE)) - return; - - // if this entry is limited to use legacy tx mode, it doesn't generate BA. - if (RTMPStaFixedTxMode(pAd, pEntry) != FIXED_TXMODE_HT) - return; - - if ((pEntry->BADeclineBitmap & (1<BAOriWcidArray[TID]; - if (Idx == 0) - { - // allocate a BA session - pBAEntry = BATableAllocOriEntry(pAd, &Idx); - if (pBAEntry == NULL) - { - DBGPRINT(RT_DEBUG_TRACE,("ADDBA - MlmeADDBAAction() allocate BA session failed \n")); - return; - } - } - else - { - pBAEntry =&pAd->BATable.BAOriEntry[Idx]; - } - - if (pBAEntry->ORI_BA_Status >= Originator_WaitRes) - { - return; - } - - pEntry->BAOriWcidArray[TID] = Idx; - - // Initialize BA session - pBAEntry->ORI_BA_Status = Originator_WaitRes; - pBAEntry->Wcid = pEntry->Aid; - pBAEntry->BAWinSize = pAd->CommonCfg.BACapability.field.RxBAWinLimit; - pBAEntry->Sequence = BA_ORI_INIT_SEQ; - pBAEntry->Token = 1; // (2008-01-21) Jan Lee recommends it - this token can't be 0 - pBAEntry->TID = TID; - pBAEntry->TimeOutValue = TimeOut; - pBAEntry->pAdapter = pAd; - - if (!(pEntry->TXBAbitmap & (1<ORIBATimer, GET_TIMER_FUNCTION(BAOriSessionSetupTimeout), pBAEntry, FALSE); - } - else - RTMPCancelTimer(&pBAEntry->ORIBATimer, &Cancelled); - - // set timer to send ADDBA request - RTMPSetTimer(&pBAEntry->ORIBATimer, DelayTime); -} - -VOID BAOriSessionAdd( - IN PRTMP_ADAPTER pAd, - IN MAC_TABLE_ENTRY *pEntry, - IN PFRAME_ADDBA_RSP pFrame) -{ - BA_ORI_ENTRY *pBAEntry = NULL; - BOOLEAN Cancelled; - UCHAR TID; - USHORT Idx; - PUCHAR pOutBuffer2 = NULL; - NDIS_STATUS NStatus; - ULONG FrameLen; - FRAME_BAR FrameBar; - - TID = pFrame->BaParm.TID; - Idx = pEntry->BAOriWcidArray[TID]; - pBAEntry =&pAd->BATable.BAOriEntry[Idx]; - - // Start fill in parameters. - if ((Idx !=0) && (pBAEntry->TID == TID) && (pBAEntry->ORI_BA_Status == Originator_WaitRes)) - { - pBAEntry->BAWinSize = min(pBAEntry->BAWinSize, ((UCHAR)pFrame->BaParm.BufSize)); - BA_MaxWinSizeReasign(pAd, pEntry, &pBAEntry->BAWinSize); - - pBAEntry->TimeOutValue = pFrame->TimeOutValue; - pBAEntry->ORI_BA_Status = Originator_Done; - // reset sequence number - pBAEntry->Sequence = BA_ORI_INIT_SEQ; - // Set Bitmap flag. - pEntry->TXBAbitmap |= (1<ORIBATimer, &Cancelled); - - pBAEntry->ORIBATimer.TimerValue = 0; //pFrame->TimeOutValue; - - DBGPRINT(RT_DEBUG_TRACE,("%s : TXBAbitmap = %x, BAWinSize = %d, TimeOut = %ld\n", __func__, pEntry->TXBAbitmap, - pBAEntry->BAWinSize, pBAEntry->ORIBATimer.TimerValue)); - - // SEND BAR ; - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer2); //Get an unused nonpaged memory - if (NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_TRACE,("BA - BAOriSessionAdd() allocate memory failed \n")); - return; - } - - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - BarHeaderInit(pAd, &FrameBar, pAd->MacTab.Content[pBAEntry->Wcid].Addr, pAd->CurrentAddress); -#endif // CONFIG_STA_SUPPORT // - - FrameBar.StartingSeq.field.FragNum = 0; // make sure sequence not clear in DEL function. - FrameBar.StartingSeq.field.StartSeq = pBAEntry->Sequence; // make sure sequence not clear in DEL funciton. - FrameBar.BarControl.TID = pBAEntry->TID; // make sure sequence not clear in DEL funciton. - MakeOutgoingFrame(pOutBuffer2, &FrameLen, - sizeof(FRAME_BAR), &FrameBar, - END_OF_ARGS); - MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer2, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer2); - - - if (pBAEntry->ORIBATimer.TimerValue) - RTMPSetTimer(&pBAEntry->ORIBATimer, pBAEntry->ORIBATimer.TimerValue); // in mSec - } -} - -BOOLEAN BARecSessionAdd( - IN PRTMP_ADAPTER pAd, - IN MAC_TABLE_ENTRY *pEntry, - IN PFRAME_ADDBA_REQ pFrame) -{ - BA_REC_ENTRY *pBAEntry = NULL; - BOOLEAN Status = TRUE; - BOOLEAN Cancelled; - USHORT Idx; - UCHAR TID; - UCHAR BAWinSize; - //UINT32 Value; - //UINT offset; - - - ASSERT(pEntry); - - // find TID - TID = pFrame->BaParm.TID; - - BAWinSize = min(((UCHAR)pFrame->BaParm.BufSize), (UCHAR)pAd->CommonCfg.BACapability.field.RxBAWinLimit); - - // Intel patch - if (BAWinSize == 0) - { - BAWinSize = 64; - } - - Idx = pEntry->BARecWcidArray[TID]; - - - if (Idx == 0) - { - pBAEntry = BATableAllocRecEntry(pAd, &Idx); - } - else - { - pBAEntry = &pAd->BATable.BARecEntry[Idx]; - // flush all pending reordering mpdus - ba_refresh_reordering_mpdus(pAd, pBAEntry); - } - - DBGPRINT(RT_DEBUG_TRACE,("%s(%ld): Idx = %d, BAWinSize(req %d) = %d\n", __func__, pAd->BATable.numAsRecipient, Idx, - pFrame->BaParm.BufSize, BAWinSize)); - - // Start fill in parameters. - if (pBAEntry != NULL) - { - ASSERT(pBAEntry->list.qlen == 0); - - pBAEntry->REC_BA_Status = Recipient_HandleRes; - pBAEntry->BAWinSize = BAWinSize; - pBAEntry->Wcid = pEntry->Aid; - pBAEntry->TID = TID; - pBAEntry->TimeOutValue = pFrame->TimeOutValue; - pBAEntry->REC_BA_Status = Recipient_Accept; - // initial sequence number - pBAEntry->LastIndSeq = RESET_RCV_SEQ; //pFrame->BaStartSeq.field.StartSeq; - - printk("Start Seq = %08x\n", pFrame->BaStartSeq.field.StartSeq); - - if (pEntry->RXBAbitmap & (1<RECBATimer, &Cancelled); - } - else - { - RTMPInitTimer(pAd, &pBAEntry->RECBATimer, GET_TIMER_FUNCTION(BARecSessionIdleTimeout), pBAEntry, TRUE); - } - -#if 0 // for debugging - RTMPSetTimer(&pBAEntry->RECBATimer, REC_BA_SESSION_IDLE_TIMEOUT); -#endif - - // Set Bitmap flag. - pEntry->RXBAbitmap |= (1<BARecWcidArray[TID] = Idx; - - pEntry->BADeclineBitmap &= ~(1<Aid, TID); - - DBGPRINT(RT_DEBUG_TRACE,("MACEntry[%d]RXBAbitmap = 0x%x. BARecWcidArray=%d\n", - pEntry->Aid, pEntry->RXBAbitmap, pEntry->BARecWcidArray[TID])); - } - else - { - Status = FALSE; - DBGPRINT(RT_DEBUG_TRACE,("Can't Accept ADDBA for %02x:%02x:%02x:%02x:%02x:%02x TID = %d\n", - PRINT_MAC(pEntry->Addr), TID)); - } - return(Status); -} - - -BA_REC_ENTRY *BATableAllocRecEntry( - IN PRTMP_ADAPTER pAd, - OUT USHORT *Idx) -{ - int i; - BA_REC_ENTRY *pBAEntry = NULL; - - - NdisAcquireSpinLock(&pAd->BATabLock); - - if (pAd->BATable.numAsRecipient >= MAX_BARECI_SESSION) - { - printk("BA Recipeint Session (%ld) > %d\n", pAd->BATable.numAsRecipient, - MAX_BARECI_SESSION); - goto done; - } - - // reserve idx 0 to identify BAWcidArray[TID] as empty - for (i=1; i < MAX_LEN_OF_BA_REC_TABLE; i++) - { - pBAEntry =&pAd->BATable.BARecEntry[i]; - if ((pBAEntry->REC_BA_Status == Recipient_NONE)) - { - // get one - pAd->BATable.numAsRecipient++; - pBAEntry->REC_BA_Status = Recipient_USED; - *Idx = i; - break; - } - } - -done: - NdisReleaseSpinLock(&pAd->BATabLock); - return pBAEntry; -} - -BA_ORI_ENTRY *BATableAllocOriEntry( - IN PRTMP_ADAPTER pAd, - OUT USHORT *Idx) -{ - int i; - BA_ORI_ENTRY *pBAEntry = NULL; - - NdisAcquireSpinLock(&pAd->BATabLock); - - if (pAd->BATable.numAsOriginator >= (MAX_LEN_OF_BA_ORI_TABLE)) - { - goto done; - } - - // reserve idx 0 to identify BAWcidArray[TID] as empty - for (i=1; iBATable.BAOriEntry[i]; - if ((pBAEntry->ORI_BA_Status == Originator_NONE)) - { - // get one - pAd->BATable.numAsOriginator++; - pBAEntry->ORI_BA_Status = Originator_USED; - pBAEntry->pAdapter = pAd; - *Idx = i; - break; - } - } - -done: - NdisReleaseSpinLock(&pAd->BATabLock); - return pBAEntry; -} - - -VOID BATableFreeOriEntry( - IN PRTMP_ADAPTER pAd, - IN ULONG Idx) -{ - BA_ORI_ENTRY *pBAEntry = NULL; - MAC_TABLE_ENTRY *pEntry; - - - if ((Idx == 0) || (Idx >= MAX_LEN_OF_BA_ORI_TABLE)) - return; - - pBAEntry =&pAd->BATable.BAOriEntry[Idx]; - - if (pBAEntry->ORI_BA_Status != Originator_NONE) - { - pEntry = &pAd->MacTab.Content[pBAEntry->Wcid]; - pEntry->BAOriWcidArray[pBAEntry->TID] = 0; - - - NdisAcquireSpinLock(&pAd->BATabLock); - if (pBAEntry->ORI_BA_Status == Originator_Done) - { - pEntry->TXBAbitmap &= (~(1<<(pBAEntry->TID) )); - DBGPRINT(RT_DEBUG_TRACE, ("BATableFreeOriEntry numAsOriginator= %ld\n", pAd->BATable.numAsRecipient)); - // Erase Bitmap flag. - } - - ASSERT(pAd->BATable.numAsOriginator != 0); - - pAd->BATable.numAsOriginator -= 1; - - pBAEntry->ORI_BA_Status = Originator_NONE; - pBAEntry->Token = 0; - NdisReleaseSpinLock(&pAd->BATabLock); - } -} - - -VOID BATableFreeRecEntry( - IN PRTMP_ADAPTER pAd, - IN ULONG Idx) -{ - BA_REC_ENTRY *pBAEntry = NULL; - MAC_TABLE_ENTRY *pEntry; - - - if ((Idx == 0) || (Idx >= MAX_LEN_OF_BA_REC_TABLE)) - return; - - pBAEntry =&pAd->BATable.BARecEntry[Idx]; - - if (pBAEntry->REC_BA_Status != Recipient_NONE) - { - pEntry = &pAd->MacTab.Content[pBAEntry->Wcid]; - pEntry->BARecWcidArray[pBAEntry->TID] = 0; - - NdisAcquireSpinLock(&pAd->BATabLock); - - ASSERT(pAd->BATable.numAsRecipient != 0); - - pAd->BATable.numAsRecipient -= 1; - - pBAEntry->REC_BA_Status = Recipient_NONE; - NdisReleaseSpinLock(&pAd->BATabLock); - } -} - - -VOID BAOriSessionTearDown( - IN OUT PRTMP_ADAPTER pAd, - IN UCHAR Wcid, - IN UCHAR TID, - IN BOOLEAN bPassive, - IN BOOLEAN bForceSend) -{ - ULONG Idx = 0; - BA_ORI_ENTRY *pBAEntry; - BOOLEAN Cancelled; - - if (Wcid >= MAX_LEN_OF_MAC_TABLE) - { - return; - } - - // - // Locate corresponding BA Originator Entry in BA Table with the (pAddr,TID). - // - Idx = pAd->MacTab.Content[Wcid].BAOriWcidArray[TID]; - if ((Idx == 0) || (Idx >= MAX_LEN_OF_BA_ORI_TABLE)) - { - if (bForceSend == TRUE) - { - // force send specified TID DelBA - MLME_DELBA_REQ_STRUCT DelbaReq; - MLME_QUEUE_ELEM *Elem = (MLME_QUEUE_ELEM *) kmalloc(sizeof(MLME_QUEUE_ELEM), MEM_ALLOC_FLAG); - - NdisZeroMemory(&DelbaReq, sizeof(DelbaReq)); - NdisZeroMemory(Elem, sizeof(MLME_QUEUE_ELEM)); - - COPY_MAC_ADDR(DelbaReq.Addr, pAd->MacTab.Content[Wcid].Addr); - DelbaReq.Wcid = Wcid; - DelbaReq.TID = TID; - DelbaReq.Initiator = ORIGINATOR; -#if 1 - Elem->MsgLen = sizeof(DelbaReq); - NdisMoveMemory(Elem->Msg, &DelbaReq, sizeof(DelbaReq)); - MlmeDELBAAction(pAd, Elem); - kfree(Elem); -#else - MlmeEnqueue(pAd, ACTION_STATE_MACHINE, MT2_MLME_ORI_DELBA_CATE, sizeof(MLME_DELBA_REQ_STRUCT), (PVOID)&DelbaReq); - RT28XX_MLME_HANDLER(pAd); -#endif - } - - return; - } - - DBGPRINT(RT_DEBUG_TRACE,("%s===>Wcid=%d.TID=%d \n", __func__, Wcid, TID)); - - pBAEntry = &pAd->BATable.BAOriEntry[Idx]; - DBGPRINT(RT_DEBUG_TRACE,("\t===>Idx = %ld, Wcid=%d.TID=%d, ORI_BA_Status = %d \n", Idx, Wcid, TID, pBAEntry->ORI_BA_Status)); - // - // Prepare DelBA action frame and send to the peer. - // - if ((bPassive == FALSE) && (TID == pBAEntry->TID) && (pBAEntry->ORI_BA_Status == Originator_Done)) - { - MLME_DELBA_REQ_STRUCT DelbaReq; - MLME_QUEUE_ELEM *Elem = (MLME_QUEUE_ELEM *) kmalloc(sizeof(MLME_QUEUE_ELEM), MEM_ALLOC_FLAG); - - NdisZeroMemory(&DelbaReq, sizeof(DelbaReq)); - NdisZeroMemory(Elem, sizeof(MLME_QUEUE_ELEM)); - - COPY_MAC_ADDR(DelbaReq.Addr, pAd->MacTab.Content[Wcid].Addr); - DelbaReq.Wcid = Wcid; - DelbaReq.TID = pBAEntry->TID; - DelbaReq.Initiator = ORIGINATOR; -#if 1 - Elem->MsgLen = sizeof(DelbaReq); - NdisMoveMemory(Elem->Msg, &DelbaReq, sizeof(DelbaReq)); - MlmeDELBAAction(pAd, Elem); - kfree(Elem); -#else - MlmeEnqueue(pAd, ACTION_STATE_MACHINE, MT2_MLME_ORI_DELBA_CATE, sizeof(MLME_DELBA_REQ_STRUCT), (PVOID)&DelbaReq); - RT28XX_MLME_HANDLER(pAd); -#endif - } - RTMPCancelTimer(&pBAEntry->ORIBATimer, &Cancelled); - BATableFreeOriEntry(pAd, Idx); - - if (bPassive) - { - //BAOriSessionSetUp(pAd, &pAd->MacTab.Content[Wcid], TID, 0, 10000, TRUE); - } -} - -VOID BARecSessionTearDown( - IN OUT PRTMP_ADAPTER pAd, - IN UCHAR Wcid, - IN UCHAR TID, - IN BOOLEAN bPassive) -{ - ULONG Idx = 0; - BA_REC_ENTRY *pBAEntry; - - if (Wcid >= MAX_LEN_OF_MAC_TABLE) - { - return; - } - - // - // Locate corresponding BA Originator Entry in BA Table with the (pAddr,TID). - // - Idx = pAd->MacTab.Content[Wcid].BARecWcidArray[TID]; - if (Idx == 0) - return; - - DBGPRINT(RT_DEBUG_TRACE,("%s===>Wcid=%d.TID=%d \n", __func__, Wcid, TID)); - - - pBAEntry = &pAd->BATable.BARecEntry[Idx]; - DBGPRINT(RT_DEBUG_TRACE,("\t===>Idx = %ld, Wcid=%d.TID=%d, REC_BA_Status = %d \n", Idx, Wcid, TID, pBAEntry->REC_BA_Status)); - // - // Prepare DelBA action frame and send to the peer. - // - if ((TID == pBAEntry->TID) && (pBAEntry->REC_BA_Status == Recipient_Accept)) - { - MLME_DELBA_REQ_STRUCT DelbaReq; - BOOLEAN Cancelled; - MLME_QUEUE_ELEM *Elem = (MLME_QUEUE_ELEM *) kmalloc(sizeof(MLME_QUEUE_ELEM), MEM_ALLOC_FLAG); - //ULONG offset; - //UINT32 VALUE; - - RTMPCancelTimer(&pBAEntry->RECBATimer, &Cancelled); - - // - // 1. Send DELBA Action Frame - // - if (bPassive == FALSE) - { - NdisZeroMemory(&DelbaReq, sizeof(DelbaReq)); - NdisZeroMemory(Elem, sizeof(MLME_QUEUE_ELEM)); - - COPY_MAC_ADDR(DelbaReq.Addr, pAd->MacTab.Content[Wcid].Addr); - DelbaReq.Wcid = Wcid; - DelbaReq.TID = TID; - DelbaReq.Initiator = RECIPIENT; -#if 1 - Elem->MsgLen = sizeof(DelbaReq); - NdisMoveMemory(Elem->Msg, &DelbaReq, sizeof(DelbaReq)); - MlmeDELBAAction(pAd, Elem); - kfree(Elem); -#else - MlmeEnqueue(pAd, ACTION_STATE_MACHINE, MT2_MLME_ORI_DELBA_CATE, sizeof(MLME_DELBA_REQ_STRUCT), (PVOID)&DelbaReq); - RT28XX_MLME_HANDLER(pAd); -#endif - } - - - // - // 2. Free resource of BA session - // - // flush all pending reordering mpdus - ba_refresh_reordering_mpdus(pAd, pBAEntry); - - NdisAcquireSpinLock(&pAd->BATabLock); - - // Erase Bitmap flag. - pBAEntry->LastIndSeq = RESET_RCV_SEQ; - pBAEntry->BAWinSize = 0; - // Erase Bitmap flag at software mactable - pAd->MacTab.Content[Wcid].RXBAbitmap &= (~(1<<(pBAEntry->TID))); - pAd->MacTab.Content[Wcid].BARecWcidArray[TID] = 0; - - RT28XX_DEL_BA_SESSION_FROM_ASIC(pAd, Wcid, TID); - - NdisReleaseSpinLock(&pAd->BATabLock); - - } - - BATableFreeRecEntry(pAd, Idx); -} - -VOID BASessionTearDownALL( - IN OUT PRTMP_ADAPTER pAd, - IN UCHAR Wcid) -{ - int i; - - for (i=0; ipAdapter; - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - // Do nothing if monitor mode is on - if (MONITOR_ON(pAd)) - return; - } -#endif // CONFIG_STA_SUPPORT // - -#ifdef RALINK_ATE - // Nothing to do in ATE mode. - if (ATE_ON(pAd)) - return; -#endif // RALINK_ATE // - - pEntry = &pAd->MacTab.Content[pBAEntry->Wcid]; - - if ((pBAEntry->ORI_BA_Status == Originator_WaitRes) && (pBAEntry->Token < ORI_SESSION_MAX_RETRY)) - { - MLME_ADDBA_REQ_STRUCT AddbaReq; - - NdisZeroMemory(&AddbaReq, sizeof(AddbaReq)); - COPY_MAC_ADDR(AddbaReq.pAddr, pEntry->Addr); - AddbaReq.Wcid = (UCHAR)(pEntry->Aid); - AddbaReq.TID = pBAEntry->TID; - AddbaReq.BaBufSize = pAd->CommonCfg.BACapability.field.RxBAWinLimit; - AddbaReq.TimeOutValue = 0; - AddbaReq.Token = pBAEntry->Token; - MlmeEnqueue(pAd, ACTION_STATE_MACHINE, MT2_MLME_ADD_BA_CATE, sizeof(MLME_ADDBA_REQ_STRUCT), (PVOID)&AddbaReq); - RT28XX_MLME_HANDLER(pAd); - DBGPRINT(RT_DEBUG_TRACE,("BA Ori Session Timeout(%d) : Send ADD BA again\n", pBAEntry->Token)); - - pBAEntry->Token++; - RTMPSetTimer(&pBAEntry->ORIBATimer, ORI_BA_SESSION_TIMEOUT); - } - else - { - BATableFreeOriEntry(pAd, pEntry->BAOriWcidArray[pBAEntry->TID]); - } -} - -/* - ========================================================================== - Description: - Retry sending ADDBA Reqest. - - IRQL = DISPATCH_LEVEL - - Parametrs: - p8023Header: if this is already 802.3 format, p8023Header is NULL - - Return : TRUE if put into rx reordering buffer, shouldn't indicaterxhere. - FALSE , then continue indicaterx at this moment. - ========================================================================== - */ -VOID BARecSessionIdleTimeout( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3) -{ - - BA_REC_ENTRY *pBAEntry = (BA_REC_ENTRY *)FunctionContext; - PRTMP_ADAPTER pAd; - ULONG Now32; - - if (pBAEntry == NULL) - return; - - if ((pBAEntry->REC_BA_Status == Recipient_Accept)) - { - NdisGetSystemUpTime(&Now32); - - if (RTMP_TIME_AFTER((unsigned long)Now32, (unsigned long)(pBAEntry->LastIndSeqAtTimer + REC_BA_SESSION_IDLE_TIMEOUT))) - { - pAd = pBAEntry->pAdapter; - // flush all pending reordering mpdus - ba_refresh_reordering_mpdus(pAd, pBAEntry); - printk("%ld: REC BA session Timeout\n", Now32); - } - } -} - - -VOID PeerAddBAReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) - -{ - // 7.4.4.1 - //ULONG Idx; - UCHAR Status = 1; - UCHAR pAddr[6]; - FRAME_ADDBA_RSP ADDframe; - PUCHAR pOutBuffer = NULL; - NDIS_STATUS NStatus; - PFRAME_ADDBA_REQ pAddreqFrame = NULL; - //UCHAR BufSize; - ULONG FrameLen; - PULONG ptemp; - PMAC_TABLE_ENTRY pMacEntry; - - DBGPRINT(RT_DEBUG_TRACE, ("%s ==> (Wcid = %d)\n", __func__, Elem->Wcid)); - - //hex_dump("AddBAReq", Elem->Msg, Elem->MsgLen); - - //ADDBA Request from unknown peer, ignore this. - if (Elem->Wcid >= MAX_LEN_OF_MAC_TABLE) - return; - - pMacEntry = &pAd->MacTab.Content[Elem->Wcid]; - DBGPRINT(RT_DEBUG_TRACE,("BA - PeerAddBAReqAction----> \n")); - ptemp = (PULONG)Elem->Msg; - //DBGPRINT_RAW(RT_DEBUG_EMU, ("%08x:: %08x:: %08x:: %08x:: %08x:: %08x:: %08x:: %08x:: %08x\n", *(ptemp), *(ptemp+1), *(ptemp+2), *(ptemp+3), *(ptemp+4), *(ptemp+5), *(ptemp+6), *(ptemp+7), *(ptemp+8))); - - if (PeerAddBAReqActionSanity(pAd, Elem->Msg, Elem->MsgLen, pAddr)) - { - - if ((pAd->CommonCfg.bBADecline == FALSE) && IS_HT_STA(pMacEntry)) - { - pAddreqFrame = (PFRAME_ADDBA_REQ)(&Elem->Msg[0]); - printk("Rcv Wcid(%d) AddBAReq\n", Elem->Wcid); - if (BARecSessionAdd(pAd, &pAd->MacTab.Content[Elem->Wcid], pAddreqFrame)) - Status = 0; - else - Status = 38; // more parameters have invalid values - } - else - { - Status = 37; // the request has been declined. - } - } - - if (pAd->MacTab.Content[Elem->Wcid].ValidAsCLI) - ASSERT(pAd->MacTab.Content[Elem->Wcid].Sst == SST_ASSOC); - - pAddreqFrame = (PFRAME_ADDBA_REQ)(&Elem->Msg[0]); - // 2. Always send back ADDBA Response - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory - if (NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_TRACE,("ACTION - PeerBAAction() allocate memory failed \n")); - return; - } - - NdisZeroMemory(&ADDframe, sizeof(FRAME_ADDBA_RSP)); - // 2-1. Prepare ADDBA Response frame. -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - if (ADHOC_ON(pAd)) - ActHeaderInit(pAd, &ADDframe.Hdr, pAddr, pAd->CurrentAddress, pAd->CommonCfg.Bssid); - else -#ifdef QOS_DLS_SUPPORT - if (pAd->MacTab.Content[Elem->Wcid].ValidAsDls) - ActHeaderInit(pAd, &ADDframe.Hdr, pAddr, pAd->CurrentAddress, pAd->CommonCfg.Bssid); - else -#endif // QOS_DLS_SUPPORT // - ActHeaderInit(pAd, &ADDframe.Hdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pAddr); - } -#endif // CONFIG_STA_SUPPORT // - ADDframe.Category = CATEGORY_BA; - ADDframe.Action = ADDBA_RESP; - ADDframe.Token = pAddreqFrame->Token; - // What is the Status code?? need to check. - ADDframe.StatusCode = Status; - ADDframe.BaParm.BAPolicy = IMMED_BA; - ADDframe.BaParm.AMSDUSupported = 0; - ADDframe.BaParm.TID = pAddreqFrame->BaParm.TID; - ADDframe.BaParm.BufSize = min(((UCHAR)pAddreqFrame->BaParm.BufSize), (UCHAR)pAd->CommonCfg.BACapability.field.RxBAWinLimit); - if (ADDframe.BaParm.BufSize == 0) - { - ADDframe.BaParm.BufSize = 64; - } - ADDframe.TimeOutValue = 0; //pAddreqFrame->TimeOutValue; - - *(USHORT *)(&ADDframe.BaParm) = cpu2le16(*(USHORT *)(&ADDframe.BaParm)); - ADDframe.StatusCode = cpu2le16(ADDframe.StatusCode); - ADDframe.TimeOutValue = cpu2le16(ADDframe.TimeOutValue); - - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(FRAME_ADDBA_RSP), &ADDframe, - END_OF_ARGS); - MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); - - DBGPRINT(RT_DEBUG_TRACE, ("%s(%d): TID(%d), BufSize(%d) <== \n", __func__, Elem->Wcid, ADDframe.BaParm.TID, - ADDframe.BaParm.BufSize)); -} - - -VOID PeerAddBARspAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) - -{ - //UCHAR Idx, i; - //PUCHAR pOutBuffer = NULL; - PFRAME_ADDBA_RSP pFrame = NULL; - //PBA_ORI_ENTRY pBAEntry; - - //ADDBA Response from unknown peer, ignore this. - if (Elem->Wcid >= MAX_LEN_OF_MAC_TABLE) - return; - - DBGPRINT(RT_DEBUG_TRACE, ("%s ==> Wcid(%d)\n", __func__, Elem->Wcid)); - - //hex_dump("PeerAddBARspAction()", Elem->Msg, Elem->MsgLen); - - if (PeerAddBARspActionSanity(pAd, Elem->Msg, Elem->MsgLen)) - { - pFrame = (PFRAME_ADDBA_RSP)(&Elem->Msg[0]); - - DBGPRINT(RT_DEBUG_TRACE, ("\t\t StatusCode = %d\n", pFrame->StatusCode)); - switch (pFrame->StatusCode) - { - case 0: - // I want a BAsession with this peer as an originator. - BAOriSessionAdd(pAd, &pAd->MacTab.Content[Elem->Wcid], pFrame); - break; - default: - // check status == USED ??? - BAOriSessionTearDown(pAd, Elem->Wcid, pFrame->BaParm.TID, TRUE, FALSE); - break; - } - // Rcv Decline StatusCode - if ((pFrame->StatusCode == 37) -#ifdef CONFIG_STA_SUPPORT - || ((pAd->OpMode == OPMODE_STA) && STA_TGN_WIFI_ON(pAd) && (pFrame->StatusCode != 0)) -#endif // CONFIG_STA_SUPPORT // - ) - { - pAd->MacTab.Content[Elem->Wcid].BADeclineBitmap |= 1<BaParm.TID; - } - } -} - -VOID PeerDelBAAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) - -{ - //UCHAR Idx; - //PUCHAR pOutBuffer = NULL; - PFRAME_DELBA_REQ pDelFrame = NULL; - - DBGPRINT(RT_DEBUG_TRACE,("%s ==>\n", __func__)); - //DELBA Request from unknown peer, ignore this. - if (PeerDelBAActionSanity(pAd, Elem->Wcid, Elem->Msg, Elem->MsgLen)) - { - pDelFrame = (PFRAME_DELBA_REQ)(&Elem->Msg[0]); - if (pDelFrame->DelbaParm.Initiator == ORIGINATOR) - { - DBGPRINT(RT_DEBUG_TRACE,("BA - PeerDelBAAction----> ORIGINATOR\n")); - BARecSessionTearDown(pAd, Elem->Wcid, pDelFrame->DelbaParm.TID, TRUE); - } - else - { - DBGPRINT(RT_DEBUG_TRACE,("BA - PeerDelBAAction----> RECIPIENT, Reason = %d\n", pDelFrame->ReasonCode)); - //hex_dump("DelBA Frame", pDelFrame, Elem->MsgLen); - BAOriSessionTearDown(pAd, Elem->Wcid, pDelFrame->DelbaParm.TID, TRUE, FALSE); - } - } -} - - -BOOLEAN CntlEnqueueForRecv( - IN PRTMP_ADAPTER pAd, - IN ULONG Wcid, - IN ULONG MsgLen, - IN PFRAME_BA_REQ pMsg) -{ - PFRAME_BA_REQ pFrame = pMsg; - //PRTMP_REORDERBUF pBuffer; - //PRTMP_REORDERBUF pDmaBuf; - PBA_REC_ENTRY pBAEntry; - //BOOLEAN Result; - ULONG Idx; - //UCHAR NumRxPkt; - UCHAR TID;//, i; - - TID = (UCHAR)pFrame->BARControl.TID; - - DBGPRINT(RT_DEBUG_TRACE, ("%s(): BAR-Wcid(%ld), Tid (%d)\n", __func__, Wcid, TID)); - //hex_dump("BAR", (PCHAR) pFrame, MsgLen); - // Do nothing if the driver is starting halt state. - // This might happen when timer already been fired before cancel timer with mlmehalt - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) - return FALSE; - - // First check the size, it MUST not exceed the mlme queue size - if (MsgLen > MGMT_DMA_BUFFER_SIZE) - { - DBGPRINT_ERR(("CntlEnqueueForRecv: frame too large, size = %ld \n", MsgLen)); - return FALSE; - } - else if (MsgLen != sizeof(FRAME_BA_REQ)) - { - DBGPRINT_ERR(("CntlEnqueueForRecv: BlockAck Request frame length size = %ld incorrect\n", MsgLen)); - return FALSE; - } - else if (MsgLen != sizeof(FRAME_BA_REQ)) - { - DBGPRINT_ERR(("CntlEnqueueForRecv: BlockAck Request frame length size = %ld incorrect\n", MsgLen)); - return FALSE; - } - - if ((Wcid < MAX_LEN_OF_MAC_TABLE) && (TID < 8)) - { - // if this receiving packet is from SA that is in our OriEntry. Since WCID <9 has direct mapping. no need search. - Idx = pAd->MacTab.Content[Wcid].BARecWcidArray[TID]; - pBAEntry = &pAd->BATable.BARecEntry[Idx]; - } - else - { - return FALSE; - } - - DBGPRINT(RT_DEBUG_TRACE, ("BAR(%ld) : Tid (%d) - %04x:%04x\n", Wcid, TID, pFrame->BAStartingSeq.field.StartSeq, pBAEntry->LastIndSeq )); - - if (SEQ_SMALLER(pBAEntry->LastIndSeq, pFrame->BAStartingSeq.field.StartSeq, MAXSEQ)) - { - //printk("BAR Seq = %x, LastIndSeq = %x\n", pFrame->BAStartingSeq.field.StartSeq, pBAEntry->LastIndSeq); - ba_indicate_reordering_mpdus_le_seq(pAd, pBAEntry, pFrame->BAStartingSeq.field.StartSeq); - pBAEntry->LastIndSeq = (pFrame->BAStartingSeq.field.StartSeq == 0) ? MAXSEQ :(pFrame->BAStartingSeq.field.StartSeq -1); - } - //ba_refresh_reordering_mpdus(pAd, pBAEntry); - return TRUE; -} - -/* -Description : Send PSMP Action frame If PSMP mode switches. -*/ -VOID SendPSMPAction( - IN PRTMP_ADAPTER pAd, - IN UCHAR Wcid, - IN UCHAR Psmp) -{ - PUCHAR pOutBuffer = NULL; - NDIS_STATUS NStatus; - //ULONG Idx; - FRAME_PSMP_ACTION Frame; - ULONG FrameLen; - - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory - if (NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_ERROR,("BA - MlmeADDBAAction() allocate memory failed \n")); - return; - } -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - ActHeaderInit(pAd, &Frame.Hdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pAd->MacTab.Content[Wcid].Addr); -#endif // CONFIG_STA_SUPPORT // - - Frame.Category = CATEGORY_HT; - Frame.Action = SMPS_ACTION; - switch (Psmp) - { - case MMPS_ENABLE: - Frame.Psmp = 0; - break; - case MMPS_DYNAMIC: - Frame.Psmp = 3; - break; - case MMPS_STATIC: - Frame.Psmp = 1; - break; - } - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(FRAME_PSMP_ACTION), &Frame, - END_OF_ARGS); - MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); - DBGPRINT(RT_DEBUG_ERROR,("HT - SendPSMPAction( %d ) \n", Frame.Psmp)); -} - - -#define RADIO_MEASUREMENT_REQUEST_ACTION 0 - -typedef struct PACKED -{ - UCHAR RegulatoryClass; - UCHAR ChannelNumber; - USHORT RandomInterval; - USHORT MeasurementDuration; - UCHAR MeasurementMode; - UCHAR BSSID[MAC_ADDR_LEN]; - UCHAR ReportingCondition; - UCHAR Threshold; - UCHAR SSIDIE[2]; // 2 byte -} BEACON_REQUEST; - -typedef struct PACKED -{ - UCHAR ID; - UCHAR Length; - UCHAR Token; - UCHAR RequestMode; - UCHAR Type; -} MEASUREMENT_REQ; - - - - -void convert_reordering_packet_to_preAMSDU_or_802_3_packet( - IN PRTMP_ADAPTER pAd, - IN RX_BLK *pRxBlk, - IN UCHAR FromWhichBSSID) -{ - PNDIS_PACKET pRxPkt; - UCHAR Header802_3[LENGTH_802_3]; - - // 1. get 802.3 Header - // 2. remove LLC - // a. pointer pRxBlk->pData to payload - // b. modify pRxBlk->DataSize - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - RTMP_802_11_REMOVE_LLC_AND_CONVERT_TO_802_3(pRxBlk, Header802_3); -#endif // CONFIG_STA_SUPPORT // - - ASSERT(pRxBlk->pRxPacket); - pRxPkt = RTPKT_TO_OSPKT(pRxBlk->pRxPacket); - - RTPKT_TO_OSPKT(pRxPkt)->dev = get_netdev_from_bssid(pAd, FromWhichBSSID); - RTPKT_TO_OSPKT(pRxPkt)->data = pRxBlk->pData; - RTPKT_TO_OSPKT(pRxPkt)->len = pRxBlk->DataSize; - RTPKT_TO_OSPKT(pRxPkt)->tail = RTPKT_TO_OSPKT(pRxPkt)->data + RTPKT_TO_OSPKT(pRxPkt)->len; - - // - // copy 802.3 header, if necessary - // - if (!RX_BLK_TEST_FLAG(pRxBlk, fRX_AMSDU)) - { - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { -#ifdef LINUX - NdisMoveMemory(skb_push(pRxPkt, LENGTH_802_3), Header802_3, LENGTH_802_3); -#endif -#ifdef UCOS - NdisMoveMemory(net_pkt_push(pRxPkt, LENGTH_802_3), Header802_3, LENGTH_802_3); -#endif - } -#endif // CONFIG_STA_SUPPORT // - } -} - - -#define INDICATE_LEGACY_OR_AMSDU(_pAd, _pRxBlk, _fromWhichBSSID) \ - do \ - { \ - if (RX_BLK_TEST_FLAG(_pRxBlk, fRX_AMSDU)) \ - { \ - Indicate_AMSDU_Packet(_pAd, _pRxBlk, _fromWhichBSSID); \ - } \ - else if (RX_BLK_TEST_FLAG(_pRxBlk, fRX_EAP)) \ - { \ - Indicate_EAPOL_Packet(_pAd, _pRxBlk, _fromWhichBSSID); \ - } \ - else \ - { \ - Indicate_Legacy_Packet(_pAd, _pRxBlk, _fromWhichBSSID); \ - } \ - } while (0); - - - -static VOID ba_enqueue_reordering_packet( - IN PRTMP_ADAPTER pAd, - IN PBA_REC_ENTRY pBAEntry, - IN RX_BLK *pRxBlk, - IN UCHAR FromWhichBSSID) -{ - struct reordering_mpdu *mpdu_blk; - UINT16 Sequence = (UINT16) pRxBlk->pHeader->Sequence; - - mpdu_blk = ba_mpdu_blk_alloc(pAd); - if (mpdu_blk != NULL) - { - // Write RxD buffer address & allocated buffer length - NdisAcquireSpinLock(&pBAEntry->RxReRingLock); - - mpdu_blk->Sequence = Sequence; - - mpdu_blk->bAMSDU = RX_BLK_TEST_FLAG(pRxBlk, fRX_AMSDU); - - convert_reordering_packet_to_preAMSDU_or_802_3_packet(pAd, pRxBlk, FromWhichBSSID); - - STATS_INC_RX_PACKETS(pAd, FromWhichBSSID); - - // - // it is necessary for reordering packet to record - // which BSS it come from - // - RTMP_SET_PACKET_IF(pRxBlk->pRxPacket, FromWhichBSSID); - - mpdu_blk->pPacket = pRxBlk->pRxPacket; - - if (ba_reordering_mpdu_insertsorted(&pBAEntry->list, mpdu_blk) == FALSE) - { - // had been already within reordering list - // don't indicate - RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_SUCCESS); - ba_mpdu_blk_free(pAd, mpdu_blk); - } - - ASSERT((0<= pBAEntry->list.qlen) && (pBAEntry->list.qlen <= pBAEntry->BAWinSize)); - NdisReleaseSpinLock(&pBAEntry->RxReRingLock); - } - else - { -#if 0 - DBGPRINT(RT_DEBUG_ERROR, ("!!! (%d:%d) Can't allocate reordering mpdu blk\n", - blk_count, pBAEntry->list.qlen)); -#else - DBGPRINT(RT_DEBUG_ERROR, ("!!! (%d) Can't allocate reordering mpdu blk\n", - pBAEntry->list.qlen)); -#endif - /* - * flush all pending reordering mpdus - * and receving mpdu to upper layer - * make tcp/ip to take care reordering mechanism - */ - //ba_refresh_reordering_mpdus(pAd, pBAEntry); - ba_indicate_reordering_mpdus_le_seq(pAd, pBAEntry, Sequence); - - pBAEntry->LastIndSeq = Sequence; - INDICATE_LEGACY_OR_AMSDU(pAd, pRxBlk, FromWhichBSSID); - } -} - - -/* - ========================================================================== - Description: - Indicate this packet to upper layer or put it into reordering buffer - - Parametrs: - pRxBlk : carry necessary packet info 802.11 format - FromWhichBSSID : the packet received from which BSS - - Return : - none - - Note : - the packet queued into reordering buffer need to cover to 802.3 format - or pre_AMSDU format - ========================================================================== - */ - -VOID Indicate_AMPDU_Packet( - IN PRTMP_ADAPTER pAd, - IN RX_BLK *pRxBlk, - IN UCHAR FromWhichBSSID) -{ - USHORT Idx; - PBA_REC_ENTRY pBAEntry = NULL; - UINT16 Sequence = pRxBlk->pHeader->Sequence; - ULONG Now32; - UCHAR Wcid = pRxBlk->pRxWI->WirelessCliID; - UCHAR TID = pRxBlk->pRxWI->TID; - - - if (!RX_BLK_TEST_FLAG(pRxBlk, fRX_AMSDU) && (pRxBlk->DataSize > MAX_RX_PKT_LEN)) - { -#if 0 // sample take off, no use - static int err_size; - - err_size++; - if (err_size > 20) { - printk("AMPDU DataSize = %d\n", pRxBlk->DataSize); - hex_dump("802.11 Header", (UCHAR *)pRxBlk->pHeader, 24); - hex_dump("Payload", pRxBlk->pData, 64); - err_size = 0; - } -#endif - // release packet - RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); - return; - } - - -#if 0 // test - /* Rec BA Session had been torn down */ - INDICATE_LEGACY_OR_AMSDU(pAd, pRxBlk, FromWhichBSSID); - return; -#endif - - if (Wcid < MAX_LEN_OF_MAC_TABLE) - { - Idx = pAd->MacTab.Content[Wcid].BARecWcidArray[TID]; - if (Idx == 0) - { - /* Rec BA Session had been torn down */ - INDICATE_LEGACY_OR_AMSDU(pAd, pRxBlk, FromWhichBSSID); - return; - } - pBAEntry = &pAd->BATable.BARecEntry[Idx]; - } - else - { - // impossible !!! - ASSERT(0); - // release packet - RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); - return; - } - - ASSERT(pBAEntry); - - // update last rx time - NdisGetSystemUpTime(&Now32); - - pBAEntry->rcvSeq = Sequence; - - - ba_flush_reordering_timeout_mpdus(pAd, pBAEntry, Now32); - pBAEntry->LastIndSeqAtTimer = Now32; - - // - // Reset Last Indicate Sequence - // - if (pBAEntry->LastIndSeq == RESET_RCV_SEQ) - { - ASSERT((pBAEntry->list.qlen == 0) && (pBAEntry->list.next == NULL)); - - // reset rcv sequence of BA session - pBAEntry->LastIndSeq = Sequence; - pBAEntry->LastIndSeqAtTimer = Now32; - INDICATE_LEGACY_OR_AMSDU(pAd, pRxBlk, FromWhichBSSID); - return; - } - - - // - // I. Check if in order. - // - if (SEQ_STEPONE(Sequence, pBAEntry->LastIndSeq, MAXSEQ)) - { - USHORT LastIndSeq; - - pBAEntry->LastIndSeq = Sequence; - INDICATE_LEGACY_OR_AMSDU(pAd, pRxBlk, FromWhichBSSID); - LastIndSeq = ba_indicate_reordering_mpdus_in_order(pAd, pBAEntry, pBAEntry->LastIndSeq); - if (LastIndSeq != RESET_RCV_SEQ) - { - pBAEntry->LastIndSeq = LastIndSeq; - } - pBAEntry->LastIndSeqAtTimer = Now32; - } - // - // II. Drop Duplicated Packet - // - else if (Sequence == pBAEntry->LastIndSeq) - { - - // drop and release packet - pBAEntry->nDropPacket++; - RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); - } - // - // III. Drop Old Received Packet - // - else if (SEQ_SMALLER(Sequence, pBAEntry->LastIndSeq, MAXSEQ)) - { - - // drop and release packet - pBAEntry->nDropPacket++; - RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); - } - // - // IV. Receive Sequence within Window Size - // - else if (SEQ_SMALLER(Sequence, (((pBAEntry->LastIndSeq+pBAEntry->BAWinSize+1)) & MAXSEQ), MAXSEQ)) - { - ba_enqueue_reordering_packet(pAd, pBAEntry, pRxBlk, FromWhichBSSID); - } - // - // V. Receive seq surpasses Win(lastseq + nMSDU). So refresh all reorder buffer - // - else - { -#if 0 - ba_refresh_reordering_mpdus(pAd, pBAEntry); - INDICATE_LEGACY_OR_AMSDU(pAd, pRxBlk, FromWhichBSSID); -#else - LONG WinStartSeq, TmpSeq; - - - TmpSeq = Sequence - (pBAEntry->BAWinSize) -1; - if (TmpSeq < 0) - { - TmpSeq = (MAXSEQ+1) + TmpSeq; - } - WinStartSeq = (TmpSeq+1) & MAXSEQ; - ba_indicate_reordering_mpdus_le_seq(pAd, pBAEntry, WinStartSeq); - pBAEntry->LastIndSeq = WinStartSeq; //TmpSeq; - - pBAEntry->LastIndSeqAtTimer = Now32; - - ba_enqueue_reordering_packet(pAd, pBAEntry, pRxBlk, FromWhichBSSID); - - TmpSeq = ba_indicate_reordering_mpdus_in_order(pAd, pBAEntry, pBAEntry->LastIndSeq); - if (TmpSeq != RESET_RCV_SEQ) - { - pBAEntry->LastIndSeq = TmpSeq; - } -#endif - } -} - -#endif // DOT11_N_SUPPORT // - +#include "../../rt2860/common/ba_action.c" diff --git a/drivers/staging/rt2870/common/cmm_data.c b/drivers/staging/rt2870/common/cmm_data.c index f8e0ebd7bca9..df775c3cf691 100644 --- a/drivers/staging/rt2870/common/cmm_data.c +++ b/drivers/staging/rt2870/common/cmm_data.c @@ -1,2731 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * 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 "../rt_config.h" - -#define MAX_TX_IN_TBTT (16) - - -UCHAR SNAP_802_1H[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; -UCHAR SNAP_BRIDGE_TUNNEL[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8}; -// Add Cisco Aironet SNAP heade for CCX2 support -UCHAR SNAP_AIRONET[] = {0xaa, 0xaa, 0x03, 0x00, 0x40, 0x96, 0x00, 0x00}; -UCHAR CKIP_LLC_SNAP[] = {0xaa, 0xaa, 0x03, 0x00, 0x40, 0x96, 0x00, 0x02}; -UCHAR EAPOL_LLC_SNAP[]= {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x88, 0x8e}; -UCHAR EAPOL[] = {0x88, 0x8e}; -UCHAR TPID[] = {0x81, 0x00}; /* VLAN related */ - -UCHAR IPX[] = {0x81, 0x37}; -UCHAR APPLE_TALK[] = {0x80, 0xf3}; -UCHAR RateIdToPlcpSignal[12] = { - 0, /* RATE_1 */ 1, /* RATE_2 */ 2, /* RATE_5_5 */ 3, /* RATE_11 */ // see BBP spec - 11, /* RATE_6 */ 15, /* RATE_9 */ 10, /* RATE_12 */ 14, /* RATE_18 */ // see IEEE802.11a-1999 p.14 - 9, /* RATE_24 */ 13, /* RATE_36 */ 8, /* RATE_48 */ 12 /* RATE_54 */ }; // see IEEE802.11a-1999 p.14 - -UCHAR OfdmSignalToRateId[16] = { - RATE_54, RATE_54, RATE_54, RATE_54, // OFDM PLCP Signal = 0, 1, 2, 3 respectively - RATE_54, RATE_54, RATE_54, RATE_54, // OFDM PLCP Signal = 4, 5, 6, 7 respectively - RATE_48, RATE_24, RATE_12, RATE_6, // OFDM PLCP Signal = 8, 9, 10, 11 respectively - RATE_54, RATE_36, RATE_18, RATE_9, // OFDM PLCP Signal = 12, 13, 14, 15 respectively -}; - -UCHAR OfdmRateToRxwiMCS[12] = { - 0, 0, 0, 0, - 0, 1, 2, 3, // OFDM rate 6,9,12,18 = rxwi mcs 0,1,2,3 - 4, 5, 6, 7, // OFDM rate 24,36,48,54 = rxwi mcs 4,5,6,7 -}; -UCHAR RxwiMCSToOfdmRate[12] = { - RATE_6, RATE_9, RATE_12, RATE_18, - RATE_24, RATE_36, RATE_48, RATE_54, // OFDM rate 6,9,12,18 = rxwi mcs 0,1,2,3 - 4, 5, 6, 7, // OFDM rate 24,36,48,54 = rxwi mcs 4,5,6,7 -}; - -char* MCSToMbps[] = {"1Mbps","2Mbps","5.5Mbps","11Mbps","06Mbps","09Mbps","12Mbps","18Mbps","24Mbps","36Mbps","48Mbps","54Mbps","MM-0","MM-1","MM-2","MM-3","MM-4","MM-5","MM-6","MM-7","MM-8","MM-9","MM-10","MM-11","MM-12","MM-13","MM-14","MM-15","MM-32","ee1","ee2","ee3"}; - -UCHAR default_cwmin[]={CW_MIN_IN_BITS, CW_MIN_IN_BITS, CW_MIN_IN_BITS-1, CW_MIN_IN_BITS-2}; -//UCHAR default_cwmax[]={CW_MAX_IN_BITS, CW_MAX_IN_BITS, CW_MIN_IN_BITS, CW_MIN_IN_BITS-1}; -UCHAR default_sta_aifsn[]={3,7,2,2}; - -UCHAR MapUserPriorityToAccessCategory[8] = {QID_AC_BE, QID_AC_BK, QID_AC_BK, QID_AC_BE, QID_AC_VI, QID_AC_VI, QID_AC_VO, QID_AC_VO}; - - -/* - ======================================================================== - - Routine Description: - API for MLME to transmit management frame to AP (BSS Mode) - or station (IBSS Mode) - - Arguments: - pAd Pointer to our adapter - pData Pointer to the outgoing 802.11 frame - Length Size of outgoing management frame - - Return Value: - NDIS_STATUS_FAILURE - NDIS_STATUS_PENDING - NDIS_STATUS_SUCCESS - - IRQL = PASSIVE_LEVEL - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -NDIS_STATUS MiniportMMRequest( - IN PRTMP_ADAPTER pAd, - IN UCHAR QueIdx, - IN PUCHAR pData, - IN UINT Length) -{ - PNDIS_PACKET pPacket; - NDIS_STATUS Status = NDIS_STATUS_SUCCESS; - ULONG FreeNum; - UCHAR IrqState; - UCHAR rtmpHwHdr[TXINFO_SIZE + TXWI_SIZE]; //RTMP_HW_HDR_LEN]; - - ASSERT(Length <= MGMT_DMA_BUFFER_SIZE); - - QueIdx=3; - - // 2860C use Tx Ring - - IrqState = pAd->irq_disabled; - - do - { - // Reset is in progress, stop immediately - if ( RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS) || - RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)|| - !RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_START_UP)) - { - Status = NDIS_STATUS_FAILURE; - break; - } - - // Check Free priority queue - // Since we use PBF Queue2 for management frame. Its corresponding DMA ring should be using TxRing. - - // 2860C use Tx Ring - if (pAd->MACVersion == 0x28600100) - { - FreeNum = GET_TXRING_FREENO(pAd, QueIdx); - } - else - { - FreeNum = GET_MGMTRING_FREENO(pAd); - } - - if ((FreeNum > 0)) - { - // We need to reserve space for rtmp hardware header. i.e., TxWI for RT2860 and TxInfo+TxWI for RT2870 - NdisZeroMemory(&rtmpHwHdr, (TXINFO_SIZE + TXWI_SIZE)); - Status = RTMPAllocateNdisPacket(pAd, &pPacket, (PUCHAR)&rtmpHwHdr, (TXINFO_SIZE + TXWI_SIZE), pData, Length); - if (Status != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_WARN, ("MiniportMMRequest (error:: can't allocate NDIS PACKET)\n")); - break; - } - - //pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_CCK; - //pAd->CommonCfg.MlmeRate = RATE_2; - - - Status = MlmeHardTransmit(pAd, QueIdx, pPacket); - if (Status != NDIS_STATUS_SUCCESS) - RTMPFreeNdisPacket(pAd, pPacket); - } - else - { - pAd->RalinkCounters.MgmtRingFullCount++; - DBGPRINT(RT_DEBUG_ERROR, ("Qidx(%d), not enough space in MgmtRing, MgmtRingFullCount=%ld!\n", - QueIdx, pAd->RalinkCounters.MgmtRingFullCount)); - } - - } while (FALSE); - - - return Status; -} - - - - -/* - ======================================================================== - - Routine Description: - Copy frame from waiting queue into relative ring buffer and set - appropriate ASIC register to kick hardware transmit function - - Arguments: - pAd Pointer to our adapter - pBuffer Pointer to memory of outgoing frame - Length Size of outgoing management frame - - Return Value: - NDIS_STATUS_FAILURE - NDIS_STATUS_PENDING - NDIS_STATUS_SUCCESS - - IRQL = PASSIVE_LEVEL - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -NDIS_STATUS MlmeHardTransmit( - IN PRTMP_ADAPTER pAd, - IN UCHAR QueIdx, - IN PNDIS_PACKET pPacket) -{ - if ((pAd->CommonCfg.RadarDetect.RDMode != RD_NORMAL_MODE) -#ifdef CARRIER_DETECTION_SUPPORT -#endif // CARRIER_DETECTION_SUPPORT // - ) - { - return NDIS_STATUS_FAILURE; - } - - return MlmeHardTransmitMgmtRing(pAd,QueIdx,pPacket); - -} - - - -NDIS_STATUS MlmeHardTransmitMgmtRing( - IN PRTMP_ADAPTER pAd, - IN UCHAR QueIdx, - IN PNDIS_PACKET pPacket) -{ - PACKET_INFO PacketInfo; - PUCHAR pSrcBufVA; - UINT SrcBufLen; - PHEADER_802_11 pHeader_802_11; - BOOLEAN bAckRequired, bInsertTimestamp; - UCHAR MlmeRate; - PTXWI_STRUC pFirstTxWI; - MAC_TABLE_ENTRY *pMacEntry = NULL; - - RTMP_QueryPacketInfo(pPacket, &PacketInfo, &pSrcBufVA, &SrcBufLen); - - // Make sure MGMT ring resource won't be used by other threads -// sample, for IRQ LOCK -> SEM LOCK -// IrqState = pAd->irq_disabled; -// if (!IrqState) - RTMP_SEM_LOCK(&pAd->MgmtRingLock); - - - if (pSrcBufVA == NULL) - { - // The buffer shouldn't be NULL -// if (!IrqState) - RTMP_SEM_UNLOCK(&pAd->MgmtRingLock); - return NDIS_STATUS_FAILURE; - } - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - // outgoing frame always wakeup PHY to prevent frame lost - if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) - AsicForceWakeup(pAd, TRUE); - } -#endif // CONFIG_STA_SUPPORT // - - pFirstTxWI = (PTXWI_STRUC)(pSrcBufVA + TXINFO_SIZE); - pHeader_802_11 = (PHEADER_802_11) (pSrcBufVA + TXINFO_SIZE + TXWI_SIZE); //TXWI_SIZE); - - if (pHeader_802_11->Addr1[0] & 0x01) - { - MlmeRate = pAd->CommonCfg.BasicMlmeRate; - } - else - { - MlmeRate = pAd->CommonCfg.MlmeRate; - } - - // Verify Mlme rate for a / g bands. - if ((pAd->LatchRfRegs.Channel > 14) && (MlmeRate < RATE_6)) // 11A band - MlmeRate = RATE_6; - - if ((pHeader_802_11->FC.Type == BTYPE_DATA) && - (pHeader_802_11->FC.SubType == SUBTYPE_QOS_NULL)) - { - pMacEntry = MacTableLookup(pAd, pHeader_802_11->Addr1); - } - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - // Fixed W52 with Activity scan issue in ABG_MIXED and ABGN_MIXED mode. - if (pAd->CommonCfg.PhyMode == PHY_11ABG_MIXED -#ifdef DOT11_N_SUPPORT - || pAd->CommonCfg.PhyMode == PHY_11ABGN_MIXED -#endif // DOT11_N_SUPPORT // - ) - { - if (pAd->LatchRfRegs.Channel > 14) - pAd->CommonCfg.MlmeTransmit.field.MODE = 1; - else - pAd->CommonCfg.MlmeTransmit.field.MODE = 0; - } - } -#endif // CONFIG_STA_SUPPORT // - - // - // Should not be hard code to set PwrMgmt to 0 (PWR_ACTIVE) - // Snice it's been set to 0 while on MgtMacHeaderInit - // By the way this will cause frame to be send on PWR_SAVE failed. - // - // pHeader_802_11->FC.PwrMgmt = 0; // (pAd->StaCfg.Psm == PWR_SAVE); - // - // In WMM-UAPSD, mlme frame should be set psm as power saving but probe request frame -#ifdef CONFIG_STA_SUPPORT - // Data-Null packets alse pass through MMRequest in RT2860, however, we hope control the psm bit to pass APSD - if ((pHeader_802_11->FC.Type != BTYPE_DATA) && (pHeader_802_11->FC.Type != BTYPE_CNTL)) - { - if ((pAd->StaCfg.Psm == PWR_SAVE) && - (pHeader_802_11->FC.SubType == SUBTYPE_ACTION)) - pHeader_802_11->FC.PwrMgmt = PWR_SAVE; - else - pHeader_802_11->FC.PwrMgmt = PWR_ACTIVE; - } -#endif // CONFIG_STA_SUPPORT // - - bInsertTimestamp = FALSE; - if (pHeader_802_11->FC.Type == BTYPE_CNTL) // must be PS-POLL - { -#ifdef CONFIG_STA_SUPPORT - //Set PM bit in ps-poll, to fix WLK 1.2 PowerSaveMode_ext failure issue. - if ((pAd->OpMode == OPMODE_STA) && (pHeader_802_11->FC.SubType == SUBTYPE_PS_POLL)) - { - pHeader_802_11->FC.PwrMgmt = PWR_SAVE; - } -#endif // CONFIG_STA_SUPPORT // - bAckRequired = FALSE; - } - else // BTYPE_MGMT or BTYPE_DATA(must be NULL frame) - { - //pAd->Sequence++; - //pHeader_802_11->Sequence = pAd->Sequence; - - if (pHeader_802_11->Addr1[0] & 0x01) // MULTICAST, BROADCAST - { - bAckRequired = FALSE; - pHeader_802_11->Duration = 0; - } - else - { - bAckRequired = TRUE; - pHeader_802_11->Duration = RTMPCalcDuration(pAd, MlmeRate, 14); - if (pHeader_802_11->FC.SubType == SUBTYPE_PROBE_RSP) - { - bInsertTimestamp = TRUE; - } - } - } - - pHeader_802_11->Sequence = pAd->Sequence++; - if (pAd->Sequence >0xfff) - pAd->Sequence = 0; - - // Before radar detection done, mgmt frame can not be sent but probe req - // Because we need to use probe req to trigger driver to send probe req in passive scan - if ((pHeader_802_11->FC.SubType != SUBTYPE_PROBE_REQ) - && (pAd->CommonCfg.bIEEE80211H == 1) - && (pAd->CommonCfg.RadarDetect.RDMode != RD_NORMAL_MODE)) - { - DBGPRINT(RT_DEBUG_ERROR,("MlmeHardTransmit --> radar detect not in normal mode !!!\n")); -// if (!IrqState) - RTMP_SEM_UNLOCK(&pAd->MgmtRingLock); - return (NDIS_STATUS_FAILURE); - } - -#ifdef RT_BIG_ENDIAN - RTMPFrameEndianChange(pAd, (PUCHAR)pHeader_802_11, DIR_WRITE, FALSE); -#endif - - // - // fill scatter-and-gather buffer list into TXD. Internally created NDIS PACKET - // should always has only one ohysical buffer, and the whole frame size equals - // to the first scatter buffer size - // - - // Initialize TX Descriptor - // For inter-frame gap, the number is for this frame and next frame - // For MLME rate, we will fix as 2Mb to match other vendor's implement -// pAd->CommonCfg.MlmeTransmit.field.MODE = 1; - -// management frame doesn't need encryption. so use RESERVED_WCID no matter u are sending to specific wcid or not. - if (pMacEntry == NULL) - { - RTMPWriteTxWI(pAd, pFirstTxWI, FALSE, FALSE, bInsertTimestamp, FALSE, bAckRequired, FALSE, - 0, RESERVED_WCID, (SrcBufLen - TXINFO_SIZE - TXWI_SIZE), PID_MGMT, 0, (UCHAR)pAd->CommonCfg.MlmeTransmit.field.MCS, IFS_BACKOFF, FALSE, &pAd->CommonCfg.MlmeTransmit); - } - else - { - RTMPWriteTxWI(pAd, pFirstTxWI, FALSE, FALSE, - bInsertTimestamp, FALSE, bAckRequired, FALSE, - 0, pMacEntry->Aid, (SrcBufLen - TXINFO_SIZE - TXWI_SIZE), - pMacEntry->MaxHTPhyMode.field.MCS, 0, - (UCHAR)pMacEntry->MaxHTPhyMode.field.MCS, - IFS_BACKOFF, FALSE, &pMacEntry->MaxHTPhyMode); - } - -#ifdef RT_BIG_ENDIAN - RTMPWIEndianChange((PUCHAR)pFirstTxWI, TYPE_TXWI); -#endif - - // Now do hardware-depened kick out. - HAL_KickOutMgmtTx(pAd, QueIdx, pPacket, pSrcBufVA, SrcBufLen); - - // Make sure to release MGMT ring resource -// if (!IrqState) - RTMP_SEM_UNLOCK(&pAd->MgmtRingLock); - return NDIS_STATUS_SUCCESS; -} - - -/******************************************************************************** - - New DeQueue Procedures. - - ********************************************************************************/ - -#define DEQUEUE_LOCK(lock, bIntContext, IrqFlags) \ - do{ \ - if (bIntContext == FALSE) \ - RTMP_IRQ_LOCK((lock), IrqFlags); \ - }while(0) - -#define DEQUEUE_UNLOCK(lock, bIntContext, IrqFlags) \ - do{ \ - if (bIntContext == FALSE) \ - RTMP_IRQ_UNLOCK((lock), IrqFlags); \ - }while(0) - - -#if 0 -static VOID dumpTxBlk(TX_BLK *pTxBlk) -{ - NDIS_PACKET *pPacket; - int i, frameNum; - PQUEUE_ENTRY pQEntry; - - printk("Dump TX_BLK Structure:\n"); - printk("\tTxFrameType=%d!\n", pTxBlk->TxFrameType); - printk("\tTotalFrameLen=%d\n", pTxBlk->TotalFrameLen); - printk("\tTotalFrameNum=%ld!\n", pTxBlk->TxPacketList.Number); - printk("\tTotalFragNum=%d!\n", pTxBlk->TotalFragNum); - printk("\tpPacketList=\n"); - - frameNum = pTxBlk->TxPacketList.Number; - - for(i=0; i < frameNum; i++) - { int j; - UCHAR *pBuf; - - pQEntry = RemoveHeadQueue(&pTxBlk->TxPacketList); - pPacket = QUEUE_ENTRY_TO_PACKET(pQEntry); - if (pPacket) - { - pBuf = GET_OS_PKT_DATAPTR(pPacket); - printk("\t\t[%d]:ptr=0x%x, Len=%d!\n", i, (UINT32)(GET_OS_PKT_DATAPTR(pPacket)), GET_OS_PKT_LEN(pPacket)); - printk("\t\t"); - for (j =0 ; j < GET_OS_PKT_LEN(pPacket); j++) - { - printk("%02x ", (pBuf[j] & 0xff)); - if (j == 16) - break; - } - InsertTailQueue(&pTxBlk->TxPacketList, PACKET_TO_QUEUE_ENTRY(pPacket)); - } - } - printk("\tWcid=%d!\n", pTxBlk->Wcid); - printk("\tapidx=%d!\n", pTxBlk->apidx); - printk("----EndOfDump\n"); - -} -#endif - - -/* - ======================================================================== - Tx Path design algorithm: - Basically, we divide the packets into four types, Broadcast/Multicast, 11N Rate(AMPDU, AMSDU, Normal), B/G Rate(ARALINK, Normal), - Specific Packet Type. Following show the classification rule and policy for each kinds of packets. - Classification Rule=> - Multicast: (*addr1 & 0x01) == 0x01 - Specific : bDHCPFrame, bARPFrame, bEAPOLFrame, etc. - 11N Rate : If peer support HT - (1).AMPDU -- If TXBA is negotiated. - (2).AMSDU -- If AMSDU is capable for both peer and ourself. - *). AMSDU can embedded in a AMPDU, but now we didn't support it. - (3).Normal -- Other packets which send as 11n rate. - - B/G Rate : If peer is b/g only. - (1).ARALINK-- If both of peer/us supprot Ralink proprietary Aggregation and the TxRate is large than RATE_6 - (2).Normal -- Other packets which send as b/g rate. - Fragment: - The packet must be unicast, NOT A-RALINK, NOT A-MSDU, NOT 11n, then can consider about fragment. - - Classified Packet Handle Rule=> - Multicast: - No ACK, //pTxBlk->bAckRequired = FALSE; - No WMM, //pTxBlk->bWMM = FALSE; - No piggyback, //pTxBlk->bPiggyBack = FALSE; - Force LowRate, //pTxBlk->bForceLowRate = TRUE; - Specific : Basically, for specific packet, we should handle it specifically, but now all specific packets are use - the same policy to handle it. - Force LowRate, //pTxBlk->bForceLowRate = TRUE; - - 11N Rate : - No piggyback, //pTxBlk->bPiggyBack = FALSE; - - (1).AMSDU - pTxBlk->bWMM = TRUE; - (2).AMPDU - pTxBlk->bWMM = TRUE; - (3).Normal - - B/G Rate : - (1).ARALINK - - (2).Normal - ======================================================================== -*/ -static UCHAR TxPktClassification( - IN RTMP_ADAPTER *pAd, - IN PNDIS_PACKET pPacket) -{ - UCHAR TxFrameType = TX_UNKOWN_FRAME; - UCHAR Wcid; - MAC_TABLE_ENTRY *pMacEntry = NULL; -#ifdef DOT11_N_SUPPORT - BOOLEAN bHTRate = FALSE; -#endif // DOT11_N_SUPPORT // - - Wcid = RTMP_GET_PACKET_WCID(pPacket); - if (Wcid == MCAST_WCID) - { // Handle for RA is Broadcast/Multicast Address. - return TX_MCAST_FRAME; - } - - // Handle for unicast packets - pMacEntry = &pAd->MacTab.Content[Wcid]; - if (RTMP_GET_PACKET_LOWRATE(pPacket)) - { // It's a specific packet need to force low rate, i.e., bDHCPFrame, bEAPOLFrame, bWAIFrame - TxFrameType = TX_LEGACY_FRAME; - } -#ifdef DOT11_N_SUPPORT - else if (IS_HT_RATE(pMacEntry)) - { // it's a 11n capable packet - - // Depends on HTPhyMode to check if the peer support the HTRate transmission. - // Currently didn't support A-MSDU embedded in A-MPDU - bHTRate = TRUE; - if (RTMP_GET_PACKET_MOREDATA(pPacket) || (pMacEntry->PsMode == PWR_SAVE)) - TxFrameType = TX_LEGACY_FRAME; -#ifdef UAPSD_AP_SUPPORT - else if (RTMP_GET_PACKET_EOSP(pPacket)) - TxFrameType = TX_LEGACY_FRAME; -#endif // UAPSD_AP_SUPPORT // - else if((pMacEntry->TXBAbitmap & (1<<(RTMP_GET_PACKET_UP(pPacket)))) != 0) - return TX_AMPDU_FRAME; - else if(CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_AMSDU_INUSED)) - return TX_AMSDU_FRAME; - else - TxFrameType = TX_LEGACY_FRAME; - } -#endif // DOT11_N_SUPPORT // - else - { // it's a legacy b/g packet. - if ((CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_AGGREGATION_CAPABLE) && pAd->CommonCfg.bAggregationCapable) && - (RTMP_GET_PACKET_TXRATE(pPacket) >= RATE_6) && - (!(OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED) && CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_WMM_CAPABLE)))) - { // if peer support Ralink Aggregation, we use it. - TxFrameType = TX_RALINK_FRAME; - } - else - { - TxFrameType = TX_LEGACY_FRAME; - } - } - - // Currently, our fragment only support when a unicast packet send as NOT-ARALINK, NOT-AMSDU and NOT-AMPDU. - if ((RTMP_GET_PACKET_FRAGMENTS(pPacket) > 1) && (TxFrameType == TX_LEGACY_FRAME)) - TxFrameType = TX_FRAG_FRAME; - - return TxFrameType; -} - - -BOOLEAN RTMP_FillTxBlkInfo( - IN RTMP_ADAPTER *pAd, - IN TX_BLK *pTxBlk) -{ - PACKET_INFO PacketInfo; - PNDIS_PACKET pPacket; - PMAC_TABLE_ENTRY pMacEntry = NULL; - - pPacket = pTxBlk->pPacket; - RTMP_QueryPacketInfo(pPacket, &PacketInfo, &pTxBlk->pSrcBufHeader, &pTxBlk->SrcBufLen); - - pTxBlk->Wcid = RTMP_GET_PACKET_WCID(pPacket); - pTxBlk->apidx = RTMP_GET_PACKET_IF(pPacket); - pTxBlk->UserPriority = RTMP_GET_PACKET_UP(pPacket); - pTxBlk->FrameGap = IFS_HTTXOP; // ASIC determine Frame Gap - - if (RTMP_GET_PACKET_CLEAR_EAP_FRAME(pTxBlk->pPacket)) - TX_BLK_SET_FLAG(pTxBlk, fTX_bClearEAPFrame); - else - TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bClearEAPFrame); - - // Default to clear this flag - TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bForceNonQoS); - - - if (pTxBlk->Wcid == MCAST_WCID) - { - pTxBlk->pMacEntry = NULL; - { -#ifdef MCAST_RATE_SPECIFIC - PUCHAR pDA = GET_OS_PKT_DATAPTR(pPacket); - if (((*pDA & 0x01) == 0x01) && (*pDA != 0xff)) - pTxBlk->pTransmit = &pAd->CommonCfg.MCastPhyMode; - else -#endif // MCAST_RATE_SPECIFIC // - pTxBlk->pTransmit = &pAd->MacTab.Content[MCAST_WCID].HTPhyMode; - } - - TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bAckRequired); // AckRequired = FALSE, when broadcast packet in Adhoc mode. - //TX_BLK_SET_FLAG(pTxBlk, fTX_bForceLowRate); - TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bAllowFrag); - TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bWMM); - if (RTMP_GET_PACKET_MOREDATA(pPacket)) - { - TX_BLK_SET_FLAG(pTxBlk, fTX_bMoreData); - } - - } - else - { - pTxBlk->pMacEntry = &pAd->MacTab.Content[pTxBlk->Wcid]; - pTxBlk->pTransmit = &pTxBlk->pMacEntry->HTPhyMode; - - pMacEntry = pTxBlk->pMacEntry; - - - // For all unicast packets, need Ack unless the Ack Policy is not set as NORMAL_ACK. - if (pAd->CommonCfg.AckPolicy[pTxBlk->QueIdx] != NORMAL_ACK) - TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bAckRequired); - else - TX_BLK_SET_FLAG(pTxBlk, fTX_bAckRequired); - - { - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - - // If support WMM, enable it. - if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED) && - CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_WMM_CAPABLE)) - TX_BLK_SET_FLAG(pTxBlk, fTX_bWMM); - } -#endif // CONFIG_STA_SUPPORT // - } - - if (pTxBlk->TxFrameType == TX_LEGACY_FRAME) - { - if ( (RTMP_GET_PACKET_LOWRATE(pPacket)) || - ((pAd->OpMode == OPMODE_AP) && (pMacEntry->MaxHTPhyMode.field.MODE == MODE_CCK) && (pMacEntry->MaxHTPhyMode.field.MCS == RATE_1))) - { // Specific packet, i.e., bDHCPFrame, bEAPOLFrame, bWAIFrame, need force low rate. - pTxBlk->pTransmit = &pAd->MacTab.Content[MCAST_WCID].HTPhyMode; -#ifdef DOT11_N_SUPPORT - // Modify the WMM bit for ICV issue. If we have a packet with EOSP field need to set as 1, how to handle it??? - if (IS_HT_STA(pTxBlk->pMacEntry) && - (CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_RALINK_CHIPSET)) && - ((pAd->CommonCfg.bRdg == TRUE) && CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_RDG_CAPABLE))) - { - TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bWMM); - TX_BLK_SET_FLAG(pTxBlk, fTX_bForceNonQoS); - } -#endif // DOT11_N_SUPPORT // - } - -#ifdef DOT11_N_SUPPORT - if ( (IS_HT_RATE(pMacEntry) == FALSE) && - (CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_PIGGYBACK_CAPABLE))) - { // Currently piggy-back only support when peer is operate in b/g mode. - TX_BLK_SET_FLAG(pTxBlk, fTX_bPiggyBack); - } -#endif // DOT11_N_SUPPORT // - - if (RTMP_GET_PACKET_MOREDATA(pPacket)) - { - TX_BLK_SET_FLAG(pTxBlk, fTX_bMoreData); - } -#ifdef UAPSD_AP_SUPPORT - if (RTMP_GET_PACKET_EOSP(pPacket)) - { - TX_BLK_SET_FLAG(pTxBlk, fTX_bWMM_UAPSD_EOSP); - } -#endif // UAPSD_AP_SUPPORT // - } - else if (pTxBlk->TxFrameType == TX_FRAG_FRAME) - { - TX_BLK_SET_FLAG(pTxBlk, fTX_bAllowFrag); - } - - pMacEntry->DebugTxCount++; - } - - return TRUE; -} - - -BOOLEAN CanDoAggregateTransmit( - IN RTMP_ADAPTER *pAd, - IN NDIS_PACKET *pPacket, - IN TX_BLK *pTxBlk) -{ - - //printk("Check if can do aggregation! TxFrameType=%d!\n", pTxBlk->TxFrameType); - - if (RTMP_GET_PACKET_WCID(pPacket) == MCAST_WCID) - return FALSE; - - if (RTMP_GET_PACKET_DHCP(pPacket) || - RTMP_GET_PACKET_EAPOL(pPacket) || - RTMP_GET_PACKET_WAI(pPacket)) - return FALSE; - - if ((pTxBlk->TxFrameType == TX_AMSDU_FRAME) && - ((pTxBlk->TotalFrameLen + GET_OS_PKT_LEN(pPacket))> (RX_BUFFER_AGGRESIZE - 100))) - { // For AMSDU, allow the packets with total length < max-amsdu size - return FALSE; - } - - if ((pTxBlk->TxFrameType == TX_RALINK_FRAME) && - (pTxBlk->TxPacketList.Number == 2)) - { // For RALINK-Aggregation, allow two frames in one batch. - return FALSE; - } - -#ifdef CONFIG_STA_SUPPORT - if ((INFRA_ON(pAd)) && (pAd->OpMode == OPMODE_STA)) // must be unicast to AP - return TRUE; - else -#endif // CONFIG_STA_SUPPORT // - return FALSE; - -} - - -/* - ======================================================================== - - Routine Description: - To do the enqueue operation and extract the first item of waiting - list. If a number of available shared memory segments could meet - the request of extracted item, the extracted item will be fragmented - into shared memory segments. - - Arguments: - pAd Pointer to our adapter - pQueue Pointer to Waiting Queue - - Return Value: - None - - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -VOID RTMPDeQueuePacket( - IN PRTMP_ADAPTER pAd, - IN BOOLEAN bIntContext, - IN UCHAR QIdx, /* BulkOutPipeId */ - IN UCHAR Max_Tx_Packets) -{ - PQUEUE_ENTRY pEntry = NULL; - PNDIS_PACKET pPacket; - NDIS_STATUS Status = NDIS_STATUS_SUCCESS; - UCHAR Count=0; - PQUEUE_HEADER pQueue; - ULONG FreeNumber[NUM_OF_TX_RING]; - UCHAR QueIdx, sQIdx, eQIdx; - unsigned long IrqFlags = 0; - BOOLEAN hasTxDesc = FALSE; - TX_BLK TxBlk; - TX_BLK *pTxBlk; - -#ifdef DBG_DIAGNOSE - BOOLEAN firstRound; - RtmpDiagStruct *pDiagStruct = &pAd->DiagStruct; -#endif - - - if (QIdx == NUM_OF_TX_RING) - { - sQIdx = 0; - eQIdx = 3; // 4 ACs, start from 0. - } - else - { - sQIdx = eQIdx = QIdx; - } - - for (QueIdx=sQIdx; QueIdx <= eQIdx; QueIdx++) - { - Count=0; - - RT28XX_START_DEQUEUE(pAd, QueIdx, IrqFlags); - -#ifdef DBG_DIAGNOSE - firstRound = ((QueIdx == 0) ? TRUE : FALSE); -#endif // DBG_DIAGNOSE // - - while (1) - { - if ((RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS | - fRTMP_ADAPTER_RADIO_OFF | - fRTMP_ADAPTER_RESET_IN_PROGRESS | - fRTMP_ADAPTER_HALT_IN_PROGRESS | - fRTMP_ADAPTER_NIC_NOT_EXIST)))) - { - RT28XX_STOP_DEQUEUE(pAd, QueIdx, IrqFlags); - return; - } - - if (Count >= Max_Tx_Packets) - break; - - DEQUEUE_LOCK(&pAd->irq_lock, bIntContext, IrqFlags); - if (&pAd->TxSwQueue[QueIdx] == NULL) - { -#ifdef DBG_DIAGNOSE - if (firstRound == TRUE) - pDiagStruct->TxSWQueCnt[pDiagStruct->ArrayCurIdx][0]++; -#endif // DBG_DIAGNOSE // - DEQUEUE_UNLOCK(&pAd->irq_lock, bIntContext, IrqFlags); - break; - } - - - // probe the Queue Head - pQueue = &pAd->TxSwQueue[QueIdx]; - if ((pEntry = pQueue->Head) == NULL) - { - DEQUEUE_UNLOCK(&pAd->irq_lock, bIntContext, IrqFlags); - break; - } - - pTxBlk = &TxBlk; - NdisZeroMemory((PUCHAR)pTxBlk, sizeof(TX_BLK)); - //InitializeQueueHeader(&pTxBlk->TxPacketList); // Didn't need it because we already memzero it. - pTxBlk->QueIdx = QueIdx; - - pPacket = QUEUE_ENTRY_TO_PKT(pEntry); - - // Early check to make sure we have enoguh Tx Resource. - hasTxDesc = RT28XX_HAS_ENOUGH_FREE_DESC(pAd, pTxBlk, FreeNumber[QueIdx], pPacket); - if (!hasTxDesc) - { - pAd->PrivateInfo.TxRingFullCnt++; - - DEQUEUE_UNLOCK(&pAd->irq_lock, bIntContext, IrqFlags); - - break; - } - - pTxBlk->TxFrameType = TxPktClassification(pAd, pPacket); - pEntry = RemoveHeadQueue(pQueue); - pTxBlk->TotalFrameNum++; - pTxBlk->TotalFragNum += RTMP_GET_PACKET_FRAGMENTS(pPacket); // The real fragment number maybe vary - pTxBlk->TotalFrameLen += GET_OS_PKT_LEN(pPacket); - pTxBlk->pPacket = pPacket; - InsertTailQueue(&pTxBlk->TxPacketList, PACKET_TO_QUEUE_ENTRY(pPacket)); - - if (pTxBlk->TxFrameType == TX_RALINK_FRAME || pTxBlk->TxFrameType == TX_AMSDU_FRAME) - { - // Enhance SW Aggregation Mechanism - if (NEED_QUEUE_BACK_FOR_AGG(pAd, QueIdx, FreeNumber[QueIdx], pTxBlk->TxFrameType)) - { - InsertHeadQueue(pQueue, PACKET_TO_QUEUE_ENTRY(pPacket)); - DEQUEUE_UNLOCK(&pAd->irq_lock, bIntContext, IrqFlags); - break; - } - - do{ - if((pEntry = pQueue->Head) == NULL) - break; - - // For TX_AMSDU_FRAME/TX_RALINK_FRAME, Need to check if next pakcet can do aggregation. - pPacket = QUEUE_ENTRY_TO_PKT(pEntry); - FreeNumber[QueIdx] = GET_TXRING_FREENO(pAd, QueIdx); - hasTxDesc = RT28XX_HAS_ENOUGH_FREE_DESC(pAd, pTxBlk, FreeNumber[QueIdx], pPacket); - if ((hasTxDesc == FALSE) || (CanDoAggregateTransmit(pAd, pPacket, pTxBlk) == FALSE)) - break; - - //Remove the packet from the TxSwQueue and insert into pTxBlk - pEntry = RemoveHeadQueue(pQueue); - ASSERT(pEntry); - pPacket = QUEUE_ENTRY_TO_PKT(pEntry); - pTxBlk->TotalFrameNum++; - pTxBlk->TotalFragNum += RTMP_GET_PACKET_FRAGMENTS(pPacket); // The real fragment number maybe vary - pTxBlk->TotalFrameLen += GET_OS_PKT_LEN(pPacket); - InsertTailQueue(&pTxBlk->TxPacketList, PACKET_TO_QUEUE_ENTRY(pPacket)); - }while(1); - - if (pTxBlk->TxPacketList.Number == 1) - pTxBlk->TxFrameType = TX_LEGACY_FRAME; - } - -#ifdef RT2870 - DEQUEUE_UNLOCK(&pAd->irq_lock, bIntContext, IrqFlags); -#endif // RT2870 // - - Count += pTxBlk->TxPacketList.Number; - - // Do HardTransmit now. -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - Status = STAHardTransmit(pAd, pTxBlk, QueIdx); -#endif // CONFIG_STA_SUPPORT // - - -#if 0 // We should not break if HardTransmit failed. Well, at least now we should not! - if (Status != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_TRACE /*RT_DEBUG_INFO*/,("RTMPHardTransmit return failed!!!\n")); - break; - } -#endif - } - - RT28XX_STOP_DEQUEUE(pAd, QueIdx, IrqFlags); - -#ifdef RT2870 - if (!hasTxDesc) - RTUSBKickBulkOut(pAd); -#endif // RT2870 // - -#ifdef BLOCK_NET_IF - if ((pAd->blockQueueTab[QueIdx].SwTxQueueBlockFlag == TRUE) - && (pAd->TxSwQueue[QueIdx].Number < 1)) - { - releaseNetIf(&pAd->blockQueueTab[QueIdx]); - } -#endif // BLOCK_NET_IF // - - } - -} - - -/* - ======================================================================== - - Routine Description: - Calculates the duration which is required to transmit out frames - with given size and specified rate. - - Arguments: - pAd Pointer to our adapter - Rate Transmit rate - Size Frame size in units of byte - - Return Value: - Duration number in units of usec - - IRQL = PASSIVE_LEVEL - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -USHORT RTMPCalcDuration( - IN PRTMP_ADAPTER pAd, - IN UCHAR Rate, - IN ULONG Size) -{ - ULONG Duration = 0; - - if (Rate < RATE_FIRST_OFDM_RATE) // CCK - { - if ((Rate > RATE_1) && OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED)) - Duration = 96; // 72+24 preamble+plcp - else - Duration = 192; // 144+48 preamble+plcp - - Duration += (USHORT)((Size << 4) / RateIdTo500Kbps[Rate]); - if ((Size << 4) % RateIdTo500Kbps[Rate]) - Duration ++; - } - else if (Rate <= RATE_LAST_OFDM_RATE)// OFDM rates - { - Duration = 20 + 6; // 16+4 preamble+plcp + Signal Extension - Duration += 4 * (USHORT)((11 + Size * 4) / RateIdTo500Kbps[Rate]); - if ((11 + Size * 4) % RateIdTo500Kbps[Rate]) - Duration += 4; - } - else //mimo rate - { - Duration = 20 + 6; // 16+4 preamble+plcp + Signal Extension - } - - return (USHORT)Duration; -} - - -/* - ======================================================================== - - Routine Description: - Calculates the duration which is required to transmit out frames - with given size and specified rate. - - Arguments: - pTxWI Pointer to head of each MPDU to HW. - Ack Setting for Ack requirement bit - Fragment Setting for Fragment bit - RetryMode Setting for retry mode - Ifs Setting for IFS gap - Rate Setting for transmit rate - Service Setting for service - Length Frame length - TxPreamble Short or Long preamble when using CCK rates - QueIdx - 0-3, according to 802.11e/d4.4 June/2003 - - Return Value: - None - - IRQL = PASSIVE_LEVEL - IRQL = DISPATCH_LEVEL - - See also : BASmartHardTransmit() !!! - - ======================================================================== -*/ -VOID RTMPWriteTxWI( - IN PRTMP_ADAPTER pAd, - IN PTXWI_STRUC pOutTxWI, - IN BOOLEAN FRAG, - IN BOOLEAN CFACK, - IN BOOLEAN InsTimestamp, - IN BOOLEAN AMPDU, - IN BOOLEAN Ack, - IN BOOLEAN NSeq, // HW new a sequence. - IN UCHAR BASize, - IN UCHAR WCID, - IN ULONG Length, - IN UCHAR PID, - IN UCHAR TID, - IN UCHAR TxRate, - IN UCHAR Txopmode, - IN BOOLEAN CfAck, - IN HTTRANSMIT_SETTING *pTransmit) -{ - PMAC_TABLE_ENTRY pMac = NULL; - TXWI_STRUC TxWI; - PTXWI_STRUC pTxWI; - - if (WCID < MAX_LEN_OF_MAC_TABLE) - pMac = &pAd->MacTab.Content[WCID]; - - // - // Always use Long preamble before verifiation short preamble functionality works well. - // Todo: remove the following line if short preamble functionality works - // - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED); - NdisZeroMemory(&TxWI, TXWI_SIZE); - pTxWI = &TxWI; - - pTxWI->FRAG= FRAG; - - pTxWI->CFACK = CFACK; - pTxWI->TS= InsTimestamp; - pTxWI->AMPDU = AMPDU; - pTxWI->ACK = Ack; - pTxWI->txop= Txopmode; - - pTxWI->NSEQ = NSeq; - // John tune the performace with Intel Client in 20 MHz performance -#ifdef DOT11_N_SUPPORT - BASize = pAd->CommonCfg.TxBASize; - - if( BASize >7 ) - BASize =7; - pTxWI->BAWinSize = BASize; - pTxWI->ShortGI = pTransmit->field.ShortGI; - pTxWI->STBC = pTransmit->field.STBC; -#endif // DOT11_N_SUPPORT // - - pTxWI->WirelessCliID = WCID; - pTxWI->MPDUtotalByteCount = Length; - pTxWI->PacketId = PID; - - // If CCK or OFDM, BW must be 20 - pTxWI->BW = (pTransmit->field.MODE <= MODE_OFDM) ? (BW_20) : (pTransmit->field.BW); -#ifdef DOT11N_DRAFT3 - if (pTxWI->BW) - pTxWI->BW = (pAd->CommonCfg.AddHTInfo.AddHtInfo.RecomWidth == 0) ? (BW_20) : (pTransmit->field.BW); -#endif // DOT11N_DRAFT3 // - - pTxWI->MCS = pTransmit->field.MCS; - pTxWI->PHYMODE = pTransmit->field.MODE; - pTxWI->CFACK = CfAck; - -#ifdef DOT11_N_SUPPORT - if (pMac) - { - if (pAd->CommonCfg.bMIMOPSEnable) - { - if ((pMac->MmpsMode == MMPS_DYNAMIC) && (pTransmit->field.MCS > 7)) - { - // Dynamic MIMO Power Save Mode - pTxWI->MIMOps = 1; - } - else if (pMac->MmpsMode == MMPS_STATIC) - { - // Static MIMO Power Save Mode - if (pTransmit->field.MODE >= MODE_HTMIX && pTransmit->field.MCS > 7) - { - pTxWI->MCS = 7; - pTxWI->MIMOps = 0; - } - } - } - //pTxWI->MIMOps = (pMac->PsMode == PWR_MMPS)? 1:0; - if (pMac->bIAmBadAtheros && (pMac->WepStatus != Ndis802_11WEPDisabled)) - { - pTxWI->MpduDensity = 7; - } - else - { - pTxWI->MpduDensity = pMac->MpduDensity; - } - } -#endif // DOT11_N_SUPPORT // - - pTxWI->PacketId = pTxWI->MCS; - NdisMoveMemory(pOutTxWI, &TxWI, sizeof(TXWI_STRUC)); -} - - -VOID RTMPWriteTxWI_Data( - IN PRTMP_ADAPTER pAd, - IN OUT PTXWI_STRUC pTxWI, - IN TX_BLK *pTxBlk) -{ - HTTRANSMIT_SETTING *pTransmit; - PMAC_TABLE_ENTRY pMacEntry; -#ifdef DOT11_N_SUPPORT - UCHAR BASize; -#endif // DOT11_N_SUPPORT // - - - ASSERT(pTxWI); - - pTransmit = pTxBlk->pTransmit; - pMacEntry = pTxBlk->pMacEntry; - - - // - // Always use Long preamble before verifiation short preamble functionality works well. - // Todo: remove the following line if short preamble functionality works - // - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED); - NdisZeroMemory(pTxWI, TXWI_SIZE); - - pTxWI->FRAG = TX_BLK_TEST_FLAG(pTxBlk, fTX_bAllowFrag); - pTxWI->ACK = TX_BLK_TEST_FLAG(pTxBlk, fTX_bAckRequired); - pTxWI->txop = pTxBlk->FrameGap; - -#ifdef CONFIG_STA_SUPPORT -#ifdef QOS_DLS_SUPPORT - if (pMacEntry && - (pAd->StaCfg.BssType == BSS_INFRA) && - (pMacEntry->ValidAsDls == TRUE)) - pTxWI->WirelessCliID = BSSID_WCID; - else -#endif // QOS_DLS_SUPPORT // -#endif // CONFIG_STA_SUPPORT // - pTxWI->WirelessCliID = pTxBlk->Wcid; - - pTxWI->MPDUtotalByteCount = pTxBlk->MpduHeaderLen + pTxBlk->SrcBufLen; - pTxWI->CFACK = TX_BLK_TEST_FLAG(pTxBlk, fTX_bPiggyBack); - - // If CCK or OFDM, BW must be 20 - pTxWI->BW = (pTransmit->field.MODE <= MODE_OFDM) ? (BW_20) : (pTransmit->field.BW); -#ifdef DOT11_N_SUPPORT -#ifdef DOT11N_DRAFT3 - if (pTxWI->BW) - pTxWI->BW = (pAd->CommonCfg.AddHTInfo.AddHtInfo.RecomWidth == 0) ? (BW_20) : (pTransmit->field.BW); -#endif // DOT11N_DRAFT3 // - pTxWI->AMPDU = ((pTxBlk->TxFrameType == TX_AMPDU_FRAME) ? TRUE : FALSE); - - // John tune the performace with Intel Client in 20 MHz performance - BASize = pAd->CommonCfg.TxBASize; - if((pTxBlk->TxFrameType == TX_AMPDU_FRAME) && (pMacEntry)) - { - UCHAR RABAOriIdx = 0; //The RA's BA Originator table index. - - RABAOriIdx = pTxBlk->pMacEntry->BAOriWcidArray[pTxBlk->UserPriority]; - BASize = pAd->BATable.BAOriEntry[RABAOriIdx].BAWinSize; - } - -#if 0 // 3*3 - if (BASize > 7) - BASize = 7; -#endif - - pTxWI->TxBF = pTransmit->field.TxBF; - pTxWI->BAWinSize = BASize; - pTxWI->ShortGI = pTransmit->field.ShortGI; - pTxWI->STBC = pTransmit->field.STBC; -#endif // DOT11_N_SUPPORT // - - pTxWI->MCS = pTransmit->field.MCS; - pTxWI->PHYMODE = pTransmit->field.MODE; - -#ifdef DOT11_N_SUPPORT - if (pMacEntry) - { - if ((pMacEntry->MmpsMode == MMPS_DYNAMIC) && (pTransmit->field.MCS > 7)) - { - // Dynamic MIMO Power Save Mode - pTxWI->MIMOps = 1; - } - else if (pMacEntry->MmpsMode == MMPS_STATIC) - { - // Static MIMO Power Save Mode - if (pTransmit->field.MODE >= MODE_HTMIX && pTransmit->field.MCS > 7) - { - pTxWI->MCS = 7; - pTxWI->MIMOps = 0; - } - } - - if (pMacEntry->bIAmBadAtheros && (pMacEntry->WepStatus != Ndis802_11WEPDisabled)) - { - pTxWI->MpduDensity = 7; - } - else - { - pTxWI->MpduDensity = pMacEntry->MpduDensity; - } - } -#endif // DOT11_N_SUPPORT // - -#ifdef DBG_DIAGNOSE - if (pTxBlk->QueIdx== 0) - { - pAd->DiagStruct.TxDataCnt[pAd->DiagStruct.ArrayCurIdx]++; - pAd->DiagStruct.TxMcsCnt[pAd->DiagStruct.ArrayCurIdx][pTxWI->MCS]++; - } -#endif // DBG_DIAGNOSE // - - // for rate adapation - pTxWI->PacketId = pTxWI->MCS; -} - - -VOID RTMPWriteTxWI_Cache( - IN PRTMP_ADAPTER pAd, - IN OUT PTXWI_STRUC pTxWI, - IN TX_BLK *pTxBlk) -{ - PHTTRANSMIT_SETTING /*pTxHTPhyMode,*/ pTransmit; - PMAC_TABLE_ENTRY pMacEntry; - - // - // update TXWI - // - pMacEntry = pTxBlk->pMacEntry; - pTransmit = pTxBlk->pTransmit; - - if (pMacEntry->bAutoTxRateSwitch) - { - pTxWI->txop = IFS_HTTXOP; - - // If CCK or OFDM, BW must be 20 - pTxWI->BW = (pTransmit->field.MODE <= MODE_OFDM) ? (BW_20) : (pTransmit->field.BW); - pTxWI->ShortGI = pTransmit->field.ShortGI; - pTxWI->STBC = pTransmit->field.STBC; - - pTxWI->MCS = pTransmit->field.MCS; - pTxWI->PHYMODE = pTransmit->field.MODE; - - // set PID for TxRateSwitching - pTxWI->PacketId = pTransmit->field.MCS; - } - -#ifdef DOT11_N_SUPPORT - pTxWI->AMPDU = ((pMacEntry->NoBADataCountDown == 0) ? TRUE: FALSE); - pTxWI->MIMOps = 0; - -#ifdef DOT11N_DRAFT3 - if (pTxWI->BW) - pTxWI->BW = (pAd->CommonCfg.AddHTInfo.AddHtInfo.RecomWidth == 0) ? (BW_20) : (pTransmit->field.BW); -#endif // DOT11N_DRAFT3 // - - if (pAd->CommonCfg.bMIMOPSEnable) - { - // MIMO Power Save Mode - if ((pMacEntry->MmpsMode == MMPS_DYNAMIC) && (pTransmit->field.MCS > 7)) - { - // Dynamic MIMO Power Save Mode - pTxWI->MIMOps = 1; - } - else if (pMacEntry->MmpsMode == MMPS_STATIC) - { - // Static MIMO Power Save Mode - if ((pTransmit->field.MODE >= MODE_HTMIX) && (pTransmit->field.MCS > 7)) - { - pTxWI->MCS = 7; - pTxWI->MIMOps = 0; - } - } - } -#endif // DOT11_N_SUPPORT // - -#ifdef DBG_DIAGNOSE - if (pTxBlk->QueIdx== 0) - { - pAd->DiagStruct.TxDataCnt[pAd->DiagStruct.ArrayCurIdx]++; - pAd->DiagStruct.TxMcsCnt[pAd->DiagStruct.ArrayCurIdx][pTxWI->MCS]++; - } -#endif // DBG_DIAGNOSE // - - pTxWI->MPDUtotalByteCount = pTxBlk->MpduHeaderLen + pTxBlk->SrcBufLen; - -} - - -/* - ======================================================================== - - Routine Description: - Calculates the duration which is required to transmit out frames - with given size and specified rate. - - Arguments: - pTxD Pointer to transmit descriptor - Ack Setting for Ack requirement bit - Fragment Setting for Fragment bit - RetryMode Setting for retry mode - Ifs Setting for IFS gap - Rate Setting for transmit rate - Service Setting for service - Length Frame length - TxPreamble Short or Long preamble when using CCK rates - QueIdx - 0-3, according to 802.11e/d4.4 June/2003 - - Return Value: - None - - IRQL = PASSIVE_LEVEL - IRQL = DISPATCH_LEVEL - - ======================================================================== -*/ -VOID RTMPWriteTxDescriptor( - IN PRTMP_ADAPTER pAd, - IN PTXD_STRUC pTxD, - IN BOOLEAN bWIV, - IN UCHAR QueueSEL) -{ - // - // Always use Long preamble before verifiation short preamble functionality works well. - // Todo: remove the following line if short preamble functionality works - // - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED); - - pTxD->WIV = (bWIV) ? 1: 0; - pTxD->QSEL= (QueueSEL); - //RT2860c?? fixed using EDCA queue for test... We doubt Queue1 has problem. 2006-09-26 Jan - //pTxD->QSEL= FIFO_EDCA; - if (pAd->bGenOneHCCA == TRUE) - pTxD->QSEL= FIFO_HCCA; - pTxD->DMADONE = 0; -} - - -// should be called only when - -// 1. MEADIA_CONNECTED -// 2. AGGREGATION_IN_USED -// 3. Fragmentation not in used -// 4. either no previous frame (pPrevAddr1=NULL) .OR. previoud frame is aggregatible -BOOLEAN TxFrameIsAggregatible( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pPrevAddr1, - IN PUCHAR p8023hdr) -{ - - // can't aggregate EAPOL (802.1x) frame - if ((p8023hdr[12] == 0x88) && (p8023hdr[13] == 0x8e)) - return FALSE; - - // can't aggregate multicast/broadcast frame - if (p8023hdr[0] & 0x01) - return FALSE; - - if (INFRA_ON(pAd)) // must be unicast to AP - return TRUE; - else if ((pPrevAddr1 == NULL) || MAC_ADDR_EQUAL(pPrevAddr1, p8023hdr)) // unicast to same STA - return TRUE; - else - return FALSE; -} - - -/* - ======================================================================== - - Routine Description: - Check the MSDU Aggregation policy - 1.HT aggregation is A-MSDU - 2.legaacy rate aggregation is software aggregation by Ralink. - - Arguments: - - Return Value: - - Note: - - ======================================================================== -*/ -BOOLEAN PeerIsAggreOn( - IN PRTMP_ADAPTER pAd, - IN ULONG TxRate, - IN PMAC_TABLE_ENTRY pMacEntry) -{ - ULONG AFlags = (fCLIENT_STATUS_AMSDU_INUSED | fCLIENT_STATUS_AGGREGATION_CAPABLE); - - if (pMacEntry != NULL && CLIENT_STATUS_TEST_FLAG(pMacEntry, AFlags)) - { -#ifdef DOT11_N_SUPPORT - if (pMacEntry->HTPhyMode.field.MODE >= MODE_HTMIX) - { - return TRUE; - } -#endif // DOT11_N_SUPPORT // - -#ifdef AGGREGATION_SUPPORT - if (TxRate >= RATE_6 && pAd->CommonCfg.bAggregationCapable && (!(OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED) && CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_WMM_CAPABLE)))) - { // legacy Ralink Aggregation support - return TRUE; - } -#endif // AGGREGATION_SUPPORT // - } - - return FALSE; - -} - -/* - ======================================================================== - - Routine Description: - Check and fine the packet waiting in SW queue with highest priority - - Arguments: - pAd Pointer to our adapter - - Return Value: - pQueue Pointer to Waiting Queue - - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -PQUEUE_HEADER RTMPCheckTxSwQueue( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pQueIdx) -{ - - ULONG Number; - // 2004-11-15 to be removed. test aggregation only -// if ((OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED)) && (*pNumber < 2)) -// return NULL; - - Number = pAd->TxSwQueue[QID_AC_BK].Number - + pAd->TxSwQueue[QID_AC_BE].Number - + pAd->TxSwQueue[QID_AC_VI].Number - + pAd->TxSwQueue[QID_AC_VO].Number - + pAd->TxSwQueue[QID_HCCA].Number; - - if (pAd->TxSwQueue[QID_AC_VO].Head != NULL) - { - *pQueIdx = QID_AC_VO; - return (&pAd->TxSwQueue[QID_AC_VO]); - } - else if (pAd->TxSwQueue[QID_AC_VI].Head != NULL) - { - *pQueIdx = QID_AC_VI; - return (&pAd->TxSwQueue[QID_AC_VI]); - } - else if (pAd->TxSwQueue[QID_AC_BE].Head != NULL) - { - *pQueIdx = QID_AC_BE; - return (&pAd->TxSwQueue[QID_AC_BE]); - } - else if (pAd->TxSwQueue[QID_AC_BK].Head != NULL) - { - *pQueIdx = QID_AC_BK; - return (&pAd->TxSwQueue[QID_AC_BK]); - } - else if (pAd->TxSwQueue[QID_HCCA].Head != NULL) - { - *pQueIdx = QID_HCCA; - return (&pAd->TxSwQueue[QID_HCCA]); - } - - // No packet pending in Tx Sw queue - *pQueIdx = QID_AC_BK; - - return (NULL); -} - - - -/* - ======================================================================== - - Routine Description: - Suspend MSDU transmission - - Arguments: - pAd Pointer to our adapter - - Return Value: - None - - Note: - - ======================================================================== -*/ -VOID RTMPSuspendMsduTransmission( - IN PRTMP_ADAPTER pAd) -{ - DBGPRINT(RT_DEBUG_TRACE,("SCANNING, suspend MSDU transmission ...\n")); - - - // - // Before BSS_SCAN_IN_PROGRESS, we need to keep Current R66 value and - // use Lowbound as R66 value on ScanNextChannel(...) - // - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R66, &pAd->BbpTuning.R66CurrentValue); - - // set BBP_R66 to 0x30/0x40 when scanning (AsicSwitchChannel will set R66 according to channel when scanning) - //RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, (0x26 + GET_LNA_GAIN(pAd))); - RTMPSetAGCInitValue(pAd, BW_20); - - RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS); - //RTMP_IO_WRITE32(pAd, TX_CNTL_CSR, 0x000f0000); // abort all TX rings -} - - -/* - ======================================================================== - - Routine Description: - Resume MSDU transmission - - Arguments: - pAd Pointer to our adapter - - Return Value: - None - - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -VOID RTMPResumeMsduTransmission( - IN PRTMP_ADAPTER pAd) -{ -// UCHAR IrqState; - - DBGPRINT(RT_DEBUG_TRACE,("SCAN done, resume MSDU transmission ...\n")); - - - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, pAd->BbpTuning.R66CurrentValue); - - RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS); -// sample, for IRQ LOCK to SEM LOCK -// IrqState = pAd->irq_disabled; -// if (IrqState) -// RTMPDeQueuePacket(pAd, TRUE, NUM_OF_TX_RING, MAX_TX_PROCESS); -// else - RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, MAX_TX_PROCESS); -} - - -UINT deaggregate_AMSDU_announce( - IN PRTMP_ADAPTER pAd, - PNDIS_PACKET pPacket, - IN PUCHAR pData, - IN ULONG DataSize) -{ - USHORT PayloadSize; - USHORT SubFrameSize; - PHEADER_802_3 pAMSDUsubheader; - UINT nMSDU; - UCHAR Header802_3[14]; - - PUCHAR pPayload, pDA, pSA, pRemovedLLCSNAP; - PNDIS_PACKET pClonePacket; - - - - nMSDU = 0; - - while (DataSize > LENGTH_802_3) - { - - nMSDU++; - - //hex_dump("subheader", pData, 64); - pAMSDUsubheader = (PHEADER_802_3)pData; - //pData += LENGTH_802_3; - PayloadSize = pAMSDUsubheader->Octet[1] + (pAMSDUsubheader->Octet[0]<<8); - SubFrameSize = PayloadSize + LENGTH_802_3; - - - if ((DataSize < SubFrameSize) || (PayloadSize > 1518 )) - { - break; - } - - //printk("%d subframe: Size = %d\n", nMSDU, PayloadSize); - - pPayload = pData + LENGTH_802_3; - pDA = pData; - pSA = pData + MAC_ADDR_LEN; - - // convert to 802.3 header - CONVERT_TO_802_3(Header802_3, pDA, pSA, pPayload, PayloadSize, pRemovedLLCSNAP); - -#ifdef CONFIG_STA_SUPPORT - if ((Header802_3[12] == 0x88) && (Header802_3[13] == 0x8E) ) - { - // avoid local heap overflow, use dyanamic allocation - MLME_QUEUE_ELEM *Elem = (MLME_QUEUE_ELEM *) kmalloc(sizeof(MLME_QUEUE_ELEM), MEM_ALLOC_FLAG); - memmove(Elem->Msg+(LENGTH_802_11 + LENGTH_802_1_H), pPayload, PayloadSize); - Elem->MsgLen = LENGTH_802_11 + LENGTH_802_1_H + PayloadSize; - WpaEAPOLKeyAction(pAd, Elem); - kfree(Elem); - } -#endif // CONFIG_STA_SUPPORT // - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - if (pRemovedLLCSNAP) - { - pPayload -= LENGTH_802_3; - PayloadSize += LENGTH_802_3; - NdisMoveMemory(pPayload, &Header802_3[0], LENGTH_802_3); - } - } -#endif // CONFIG_STA_SUPPORT // - - pClonePacket = ClonePacket(pAd, pPacket, pPayload, PayloadSize); - if (pClonePacket) - { -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - ANNOUNCE_OR_FORWARD_802_3_PACKET(pAd, pClonePacket, RTMP_GET_PACKET_IF(pPacket)); -#endif // CONFIG_STA_SUPPORT // - } - - - // A-MSDU has padding to multiple of 4 including subframe header. - // align SubFrameSize up to multiple of 4 - SubFrameSize = (SubFrameSize+3)&(~0x3); - - - if (SubFrameSize > 1528 || SubFrameSize < 32) - { - break; - } - - if (DataSize > SubFrameSize) - { - pData += SubFrameSize; - DataSize -= SubFrameSize; - } - else - { - // end of A-MSDU - DataSize = 0; - } - } - - // finally release original rx packet - RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_SUCCESS); - - return nMSDU; -} - - -UINT BA_Reorder_AMSDU_Annnounce( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket) -{ - PUCHAR pData; - USHORT DataSize; - UINT nMSDU = 0; - - pData = (PUCHAR) GET_OS_PKT_DATAPTR(pPacket); - DataSize = (USHORT) GET_OS_PKT_LEN(pPacket); - - nMSDU = deaggregate_AMSDU_announce(pAd, pPacket, pData, DataSize); - - return nMSDU; -} - - -/* - ========================================================================== - Description: - Look up the MAC address in the MAC table. Return NULL if not found. - Return: - pEntry - pointer to the MAC entry; NULL is not found - ========================================================================== -*/ -MAC_TABLE_ENTRY *MacTableLookup( - IN PRTMP_ADAPTER pAd, - PUCHAR pAddr) -{ - ULONG HashIdx; - MAC_TABLE_ENTRY *pEntry = NULL; - - HashIdx = MAC_ADDR_HASH_INDEX(pAddr); - pEntry = pAd->MacTab.Hash[HashIdx]; - - while (pEntry && (pEntry->ValidAsCLI || pEntry->ValidAsWDS || pEntry->ValidAsApCli || pEntry->ValidAsMesh)) - { - if (MAC_ADDR_EQUAL(pEntry->Addr, pAddr)) - { - break; - } - else - pEntry = pEntry->pNext; - } - - return pEntry; -} - -MAC_TABLE_ENTRY *MacTableInsertEntry( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pAddr, - IN UCHAR apidx, - IN BOOLEAN CleanAll) -{ - UCHAR HashIdx; - int i, FirstWcid; - MAC_TABLE_ENTRY *pEntry = NULL, *pCurrEntry; - - // if FULL, return - if (pAd->MacTab.Size >= MAX_LEN_OF_MAC_TABLE) - return NULL; - - FirstWcid = 1; -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - if (pAd->StaCfg.BssType == BSS_INFRA) - FirstWcid = 2; -#endif // CONFIG_STA_SUPPORT // - - // allocate one MAC entry - NdisAcquireSpinLock(&pAd->MacTabLock); - for (i = FirstWcid; i< MAX_LEN_OF_MAC_TABLE; i++) // skip entry#0 so that "entry index == AID" for fast lookup - { - // pick up the first available vacancy - if ((pAd->MacTab.Content[i].ValidAsCLI == FALSE) && - (pAd->MacTab.Content[i].ValidAsWDS == FALSE) && - (pAd->MacTab.Content[i].ValidAsApCli== FALSE) && - (pAd->MacTab.Content[i].ValidAsMesh == FALSE) -#ifdef CONFIG_STA_SUPPORT -#ifdef QOS_DLS_SUPPORT - && (pAd->MacTab.Content[i].ValidAsDls == FALSE) -#endif // QOS_DLS_SUPPORT // -#endif // CONFIG_STA_SUPPORT // - ) - { - pEntry = &pAd->MacTab.Content[i]; - if (CleanAll == TRUE) - { - pEntry->MaxSupportedRate = RATE_11; - pEntry->CurrTxRate = RATE_11; - NdisZeroMemory(pEntry, sizeof(MAC_TABLE_ENTRY)); - pEntry->PairwiseKey.KeyLen = 0; - pEntry->PairwiseKey.CipherAlg = CIPHER_NONE; - } -#ifdef CONFIG_STA_SUPPORT -#ifdef QOS_DLS_SUPPORT - if (apidx >= MIN_NET_DEVICE_FOR_DLS) - { - pEntry->ValidAsCLI = FALSE; - pEntry->ValidAsWDS = FALSE; - pEntry->ValidAsApCli = FALSE; - pEntry->ValidAsMesh = FALSE; - pEntry->ValidAsDls = TRUE; - pEntry->isCached = FALSE; - } - else -#endif // QOS_DLS_SUPPORT // -#endif // CONFIG_STA_SUPPORT // - { - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - pEntry->ValidAsCLI = TRUE; - pEntry->ValidAsWDS = FALSE; - pEntry->ValidAsApCli = FALSE; - pEntry->ValidAsMesh = FALSE; - pEntry->ValidAsDls = FALSE; - } -#endif // CONFIG_STA_SUPPORT // - } - - pEntry->bIAmBadAtheros = FALSE; - pEntry->pAd = pAd; - pEntry->CMTimerRunning = FALSE; - pEntry->EnqueueEapolStartTimerRunning = EAPOL_START_DISABLE; - pEntry->RSNIE_Len = 0; - NdisZeroMemory(pEntry->R_Counter, sizeof(pEntry->R_Counter)); - pEntry->ReTryCounter = PEER_MSG1_RETRY_TIMER_CTR; - - if (pEntry->ValidAsMesh) - pEntry->apidx = (apidx - MIN_NET_DEVICE_FOR_MESH); - else if (pEntry->ValidAsApCli) - pEntry->apidx = (apidx - MIN_NET_DEVICE_FOR_APCLI); - else if (pEntry->ValidAsWDS) - pEntry->apidx = (apidx - MIN_NET_DEVICE_FOR_WDS); -#ifdef CONFIG_STA_SUPPORT -#ifdef QOS_DLS_SUPPORT - else if (pEntry->ValidAsDls) - pEntry->apidx = (apidx - MIN_NET_DEVICE_FOR_DLS); -#endif // QOS_DLS_SUPPORT // -#endif // CONFIG_STA_SUPPORT // - else - pEntry->apidx = apidx; - - { - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - pEntry->AuthMode = pAd->StaCfg.AuthMode; - pEntry->WepStatus = pAd->StaCfg.WepStatus; - pEntry->PrivacyFilter = Ndis802_11PrivFilterAcceptAll; - } -#endif // CONFIG_STA_SUPPORT // - } - - pEntry->GTKState = REKEY_NEGOTIATING; - pEntry->PairwiseKey.KeyLen = 0; - pEntry->PairwiseKey.CipherAlg = CIPHER_NONE; -#ifdef CONFIG_STA_SUPPORT -#ifdef QOS_DLS_SUPPORT - if (pEntry->ValidAsDls == TRUE) - pEntry->PortSecured = WPA_802_1X_PORT_SECURED; -#endif //QOS_DLS_SUPPORT -#endif // CONFIG_STA_SUPPORT // - pEntry->PortSecured = WPA_802_1X_PORT_NOT_SECURED; - pEntry->PMKID_CacheIdx = ENTRY_NOT_FOUND; - COPY_MAC_ADDR(pEntry->Addr, pAddr); - pEntry->Sst = SST_NOT_AUTH; - pEntry->AuthState = AS_NOT_AUTH; - pEntry->Aid = (USHORT)i; //0; - pEntry->CapabilityInfo = 0; - pEntry->PsMode = PWR_ACTIVE; - pEntry->PsQIdleCount = 0; - pEntry->NoDataIdleCount = 0; - pEntry->ContinueTxFailCnt = 0; - InitializeQueueHeader(&pEntry->PsQueue); - - - pAd->MacTab.Size ++; - // Add this entry into ASIC RX WCID search table - RT28XX_STA_ENTRY_ADD(pAd, pEntry); - - DBGPRINT(RT_DEBUG_TRACE, ("MacTableInsertEntry - allocate entry #%d, Total= %d\n",i, pAd->MacTab.Size)); - break; - } - } - - // add this MAC entry into HASH table - if (pEntry) - { - HashIdx = MAC_ADDR_HASH_INDEX(pAddr); - if (pAd->MacTab.Hash[HashIdx] == NULL) - { - pAd->MacTab.Hash[HashIdx] = pEntry; - } - else - { - pCurrEntry = pAd->MacTab.Hash[HashIdx]; - while (pCurrEntry->pNext != NULL) - pCurrEntry = pCurrEntry->pNext; - pCurrEntry->pNext = pEntry; - } - } - - NdisReleaseSpinLock(&pAd->MacTabLock); - return pEntry; -} - -/* - ========================================================================== - Description: - Delete a specified client from MAC table - ========================================================================== - */ -BOOLEAN MacTableDeleteEntry( - IN PRTMP_ADAPTER pAd, - IN USHORT wcid, - IN PUCHAR pAddr) -{ - USHORT HashIdx; - MAC_TABLE_ENTRY *pEntry, *pPrevEntry, *pProbeEntry; - BOOLEAN Cancelled; - //USHORT offset; // unused variable - //UCHAR j; // unused variable - - if (wcid >= MAX_LEN_OF_MAC_TABLE) - return FALSE; - - NdisAcquireSpinLock(&pAd->MacTabLock); - - HashIdx = MAC_ADDR_HASH_INDEX(pAddr); - //pEntry = pAd->MacTab.Hash[HashIdx]; - pEntry = &pAd->MacTab.Content[wcid]; - - if (pEntry && (pEntry->ValidAsCLI || pEntry->ValidAsApCli || pEntry->ValidAsWDS || pEntry->ValidAsMesh -#ifdef CONFIG_STA_SUPPORT -#ifdef QOS_DLS_SUPPORT - || pEntry->ValidAsDls -#endif // QOS_DLS_SUPPORT // -#endif // CONFIG_STA_SUPPORT // - )) - { - if (MAC_ADDR_EQUAL(pEntry->Addr, pAddr)) - { - - // Delete this entry from ASIC on-chip WCID Table - RT28XX_STA_ENTRY_MAC_RESET(pAd, wcid); - -#ifdef DOT11_N_SUPPORT - // free resources of BA - BASessionTearDownALL(pAd, pEntry->Aid); -#endif // DOT11_N_SUPPORT // - - - pPrevEntry = NULL; - pProbeEntry = pAd->MacTab.Hash[HashIdx]; - ASSERT(pProbeEntry); - - // update Hash list - do - { - if (pProbeEntry == pEntry) - { - if (pPrevEntry == NULL) - { - pAd->MacTab.Hash[HashIdx] = pEntry->pNext; - } - else - { - pPrevEntry->pNext = pEntry->pNext; - } - break; - } - - pPrevEntry = pProbeEntry; - pProbeEntry = pProbeEntry->pNext; - } while (pProbeEntry); - - // not found !!! - ASSERT(pProbeEntry != NULL); - - RT28XX_STA_ENTRY_KEY_DEL(pAd, BSS0, wcid); - - - if (pEntry->EnqueueEapolStartTimerRunning != EAPOL_START_DISABLE) - { - RTMPCancelTimer(&pEntry->EnqueueStartForPSKTimer, &Cancelled); - pEntry->EnqueueEapolStartTimerRunning = EAPOL_START_DISABLE; - } - - - NdisZeroMemory(pEntry, sizeof(MAC_TABLE_ENTRY)); - pAd->MacTab.Size --; - DBGPRINT(RT_DEBUG_TRACE, ("MacTableDeleteEntry1 - Total= %d\n", pAd->MacTab.Size)); - } - else - { - printk("\n%s: Impossible Wcid = %d !!!!!\n", __func__, wcid); - } - } - - NdisReleaseSpinLock(&pAd->MacTabLock); - - //Reset operating mode when no Sta. - if (pAd->MacTab.Size == 0) - { -#ifdef DOT11_N_SUPPORT - pAd->CommonCfg.AddHTInfo.AddHtInfo2.OperaionMode = 0; -#endif // DOT11_N_SUPPORT // - AsicUpdateProtect(pAd, 0 /*pAd->CommonCfg.AddHTInfo.AddHtInfo2.OperaionMode*/, (ALLN_SETPROTECT), TRUE, 0 /*pAd->MacTab.fAnyStationNonGF*/); - } - - return TRUE; -} - - -/* - ========================================================================== - Description: - This routine reset the entire MAC table. All packets pending in - the power-saving queues are freed here. - ========================================================================== - */ -VOID MacTableReset( - IN PRTMP_ADAPTER pAd) -{ - int i; - - DBGPRINT(RT_DEBUG_TRACE, ("MacTableReset\n")); - //NdisAcquireSpinLock(&pAd->MacTabLock); - - for (i=1; iMacTab.Content[i].ValidAsCLI == TRUE) - { - -#ifdef DOT11_N_SUPPORT - // free resources of BA - BASessionTearDownALL(pAd, i); -#endif // DOT11_N_SUPPORT // - - pAd->MacTab.Content[i].ValidAsCLI = FALSE; - - - -#ifdef RT2870 - NdisZeroMemory(pAd->MacTab.Content[i].Addr, 6); - RT28XX_STA_ENTRY_MAC_RESET(pAd, i); -#endif // RT2870 // - - //AsicDelWcidTab(pAd, i); - } - } - - return; -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== -*/ -VOID AssocParmFill( - IN PRTMP_ADAPTER pAd, - IN OUT MLME_ASSOC_REQ_STRUCT *AssocReq, - IN PUCHAR pAddr, - IN USHORT CapabilityInfo, - IN ULONG Timeout, - IN USHORT ListenIntv) -{ - COPY_MAC_ADDR(AssocReq->Addr, pAddr); - // Add mask to support 802.11b mode only - AssocReq->CapabilityInfo = CapabilityInfo & SUPPORTED_CAPABILITY_INFO; // not cf-pollable, not cf-poll-request - AssocReq->Timeout = Timeout; - AssocReq->ListenIntv = ListenIntv; -} - - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== -*/ -VOID DisassocParmFill( - IN PRTMP_ADAPTER pAd, - IN OUT MLME_DISASSOC_REQ_STRUCT *DisassocReq, - IN PUCHAR pAddr, - IN USHORT Reason) -{ - COPY_MAC_ADDR(DisassocReq->Addr, pAddr); - DisassocReq->Reason = Reason; -} - - -/* - ======================================================================== - - Routine Description: - Check the out going frame, if this is an DHCP or ARP datagram - will be duplicate another frame at low data rate transmit. - - Arguments: - pAd Pointer to our adapter - pPacket Pointer to outgoing Ndis frame - - Return Value: - TRUE To be duplicate at Low data rate transmit. (1mb) - FALSE Do nothing. - - IRQL = DISPATCH_LEVEL - - Note: - - MAC header + IP Header + UDP Header - 14 Bytes 20 Bytes - - UDP Header - 00|01|02|03|04|05|06|07|08|09|10|11|12|13|14|15| - Source Port - 16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31| - Destination Port - - port 0x43 means Bootstrap Protocol, server. - Port 0x44 means Bootstrap Protocol, client. - - ======================================================================== -*/ - -BOOLEAN RTMPCheckDHCPFrame( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket) -{ - PACKET_INFO PacketInfo; - ULONG NumberOfBytesRead = 0; - ULONG CurrentOffset = 0; - PVOID pVirtualAddress = NULL; - UINT NdisBufferLength; - PUCHAR pSrc; - USHORT Protocol; - UCHAR ByteOffset36 = 0; - UCHAR ByteOffset38 = 0; - BOOLEAN ReadFirstParm = TRUE; - - RTMP_QueryPacketInfo(pPacket, &PacketInfo, (PUCHAR *)&pVirtualAddress, &NdisBufferLength); - - NumberOfBytesRead += NdisBufferLength; - pSrc = (PUCHAR) pVirtualAddress; - Protocol = *(pSrc + 12) * 256 + *(pSrc + 13); - - // - // Check DHCP & BOOTP protocol - // - while (NumberOfBytesRead <= PacketInfo.TotalPacketLength) - { - if ((NumberOfBytesRead >= 35) && (ReadFirstParm == TRUE)) - { - CurrentOffset = 35 - (NumberOfBytesRead - NdisBufferLength); - ByteOffset36 = *(pSrc + CurrentOffset); - ReadFirstParm = FALSE; - } - - if (NumberOfBytesRead >= 37) - { - CurrentOffset = 37 - (NumberOfBytesRead - NdisBufferLength); - ByteOffset38 = *(pSrc + CurrentOffset); - //End of Read - break; - } - return FALSE; - } - - // Check for DHCP & BOOTP protocol - if ((ByteOffset36 != 0x44) || (ByteOffset38 != 0x43)) - { - // - // 2054 (hex 0806) for ARP datagrams - // if this packet is not ARP datagrams, then do nothing - // ARP datagrams will also be duplicate at 1mb broadcast frames - // - if (Protocol != 0x0806 ) - return FALSE; - } - - return TRUE; -} - - -BOOLEAN RTMPCheckEtherType( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket) -{ - USHORT TypeLen; - UCHAR Byte0, Byte1; - PUCHAR pSrcBuf; - UINT32 pktLen; - UINT16 srcPort, dstPort; - BOOLEAN status = TRUE; - - - pSrcBuf = GET_OS_PKT_DATAPTR(pPacket); - pktLen = GET_OS_PKT_LEN(pPacket); - - ASSERT(pSrcBuf); - - RTMP_SET_PACKET_SPECIFIC(pPacket, 0); - - // get Ethernet protocol field - TypeLen = (pSrcBuf[12] << 8) + pSrcBuf[13]; - - pSrcBuf += LENGTH_802_3; // Skip the Ethernet Header. - - if (TypeLen <= 1500) - { // 802.3, 802.3 LLC - /* - DestMAC(6) + SrcMAC(6) + Lenght(2) + - DSAP(1) + SSAP(1) + Control(1) + - if the DSAP = 0xAA, SSAP=0xAA, Contorl = 0x03, it has a 5-bytes SNAP header. - => + SNAP (5, OriginationID(3) + etherType(2)) - */ - if (pSrcBuf[0] == 0xAA && pSrcBuf[1] == 0xAA && pSrcBuf[2] == 0x03) - { - Sniff2BytesFromNdisBuffer(pSrcBuf, 6, &Byte0, &Byte1); - RTMP_SET_PACKET_LLCSNAP(pPacket, 1); - TypeLen = (USHORT)((Byte0 << 8) + Byte1); - pSrcBuf += 8; // Skip this LLC/SNAP header - } - else - { - //It just has 3-byte LLC header, maybe a legacy ether type frame. we didn't handle it. - } - } - - // If it's a VLAN packet, get the real Type/Length field. - if (TypeLen == 0x8100) - { - /* 0x8100 means VLAN packets */ - - /* Dest. MAC Address (6-bytes) + - Source MAC Address (6-bytes) + - Length/Type = 802.1Q Tag Type (2-byte) + - Tag Control Information (2-bytes) + - Length / Type (2-bytes) + - data payload (0-n bytes) + - Pad (0-p bytes) + - Frame Check Sequence (4-bytes) */ - - RTMP_SET_PACKET_VLAN(pPacket, 1); - Sniff2BytesFromNdisBuffer(pSrcBuf, 2, &Byte0, &Byte1); - TypeLen = (USHORT)((Byte0 << 8) + Byte1); - - pSrcBuf += 4; // Skip the VLAN Header. - } - - switch (TypeLen) - { - case 0x0800: - { - ASSERT((pktLen > 34)); - if (*(pSrcBuf + 9) == 0x11) - { // udp packet - ASSERT((pktLen > 34)); // 14 for ethernet header, 20 for IP header - - pSrcBuf += 20; // Skip the IP header - srcPort = OS_NTOHS(*((UINT16 *)pSrcBuf)); - dstPort = OS_NTOHS(*((UINT16 *)(pSrcBuf +2))); - - if ((srcPort==0x44 && dstPort==0x43) || (srcPort==0x43 && dstPort==0x44)) - { //It's a BOOTP/DHCP packet - RTMP_SET_PACKET_DHCP(pPacket, 1); - } - } - } - break; - case 0x0806: - { - //ARP Packet. - RTMP_SET_PACKET_DHCP(pPacket, 1); - } - break; - case 0x888e: - { - // EAPOL Packet. - RTMP_SET_PACKET_EAPOL(pPacket, 1); - } - break; - default: - status = FALSE; - break; - } - - return status; - -} - - - -VOID Update_Rssi_Sample( - IN PRTMP_ADAPTER pAd, - IN RSSI_SAMPLE *pRssi, - IN PRXWI_STRUC pRxWI) - { - CHAR rssi0 = pRxWI->RSSI0; - CHAR rssi1 = pRxWI->RSSI1; - CHAR rssi2 = pRxWI->RSSI2; - - if (rssi0 != 0) - { - pRssi->LastRssi0 = ConvertToRssi(pAd, (CHAR)rssi0, RSSI_0); - pRssi->AvgRssi0X8 = (pRssi->AvgRssi0X8 - pRssi->AvgRssi0) + pRssi->LastRssi0; - pRssi->AvgRssi0 = pRssi->AvgRssi0X8 >> 3; - } - - if (rssi1 != 0) - { - pRssi->LastRssi1 = ConvertToRssi(pAd, (CHAR)rssi1, RSSI_1); - pRssi->AvgRssi1X8 = (pRssi->AvgRssi1X8 - pRssi->AvgRssi1) + pRssi->LastRssi1; - pRssi->AvgRssi1 = pRssi->AvgRssi1X8 >> 3; - } - - if (rssi2 != 0) - { - pRssi->LastRssi2 = ConvertToRssi(pAd, (CHAR)rssi2, RSSI_2); - pRssi->AvgRssi2X8 = (pRssi->AvgRssi2X8 - pRssi->AvgRssi2) + pRssi->LastRssi2; - pRssi->AvgRssi2 = pRssi->AvgRssi2X8 >> 3; - } -} - - - -// Normal legacy Rx packet indication -VOID Indicate_Legacy_Packet( - IN PRTMP_ADAPTER pAd, - IN RX_BLK *pRxBlk, - IN UCHAR FromWhichBSSID) -{ - PNDIS_PACKET pRxPacket = pRxBlk->pRxPacket; - UCHAR Header802_3[LENGTH_802_3]; - - // 1. get 802.3 Header - // 2. remove LLC - // a. pointer pRxBlk->pData to payload - // b. modify pRxBlk->DataSize -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - RTMP_802_11_REMOVE_LLC_AND_CONVERT_TO_802_3(pRxBlk, Header802_3); -#endif // CONFIG_STA_SUPPORT // - - if (pRxBlk->DataSize > MAX_RX_PKT_LEN) - { -#if 0 // sample take off, for multiple card design - static int err_size; - - err_size++; - if (err_size > 20) - { - printk("Legacy DataSize = %d\n", pRxBlk->DataSize); - hex_dump("802.3 Header", Header802_3, LENGTH_802_3); - hex_dump("Payload", pRxBlk->pData, 64); - err_size = 0; - } -#endif - - // release packet - RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); - return; - } - - - STATS_INC_RX_PACKETS(pAd, FromWhichBSSID); - -#ifdef RT2870 -#ifdef DOT11_N_SUPPORT - if (pAd->CommonCfg.bDisableReordering == 0) - { - PBA_REC_ENTRY pBAEntry; - ULONG Now32; - UCHAR Wcid = pRxBlk->pRxWI->WirelessCliID; - UCHAR TID = pRxBlk->pRxWI->TID; - USHORT Idx; - -#define REORDERING_PACKET_TIMEOUT ((100 * HZ)/1000) // system ticks -- 100 ms - - if (Wcid < MAX_LEN_OF_MAC_TABLE) - { - Idx = pAd->MacTab.Content[Wcid].BARecWcidArray[TID]; - if (Idx != 0) - { - pBAEntry = &pAd->BATable.BARecEntry[Idx]; - // update last rx time - NdisGetSystemUpTime(&Now32); - if ((pBAEntry->list.qlen > 0) && - RTMP_TIME_AFTER((unsigned long)Now32, (unsigned long)(pBAEntry->LastIndSeqAtTimer+(REORDERING_PACKET_TIMEOUT))) - ) - { - printk("Indicate_Legacy_Packet():flush reordering_timeout_mpdus! RxWI->Flags=%d, pRxWI.TID=%d, RxD->AMPDU=%d!\n", pRxBlk->Flags, pRxBlk->pRxWI->TID, pRxBlk->RxD.AMPDU); - hex_dump("Dump the legacy Packet:", GET_OS_PKT_DATAPTR(pRxBlk->pRxPacket), 64); - ba_flush_reordering_timeout_mpdus(pAd, pBAEntry, Now32); - } - } - } - } -#endif // DOT11_N_SUPPORT // -#endif // RT2870 // - - wlan_802_11_to_802_3_packet(pAd, pRxBlk, Header802_3, FromWhichBSSID); - - // - // pass this 802.3 packet to upper layer or forward this packet to WM directly - // -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - ANNOUNCE_OR_FORWARD_802_3_PACKET(pAd, pRxPacket, FromWhichBSSID); -#endif // CONFIG_STA_SUPPORT // - -} - - -// Normal, AMPDU or AMSDU -VOID CmmRxnonRalinkFrameIndicate( - IN PRTMP_ADAPTER pAd, - IN RX_BLK *pRxBlk, - IN UCHAR FromWhichBSSID) -{ -#ifdef DOT11_N_SUPPORT - if (RX_BLK_TEST_FLAG(pRxBlk, fRX_AMPDU) && (pAd->CommonCfg.bDisableReordering == 0)) - { - Indicate_AMPDU_Packet(pAd, pRxBlk, FromWhichBSSID); - } - else -#endif // DOT11_N_SUPPORT // - { -#ifdef DOT11_N_SUPPORT - if (RX_BLK_TEST_FLAG(pRxBlk, fRX_AMSDU)) - { - // handle A-MSDU - Indicate_AMSDU_Packet(pAd, pRxBlk, FromWhichBSSID); - } - else -#endif // DOT11_N_SUPPORT // - { - Indicate_Legacy_Packet(pAd, pRxBlk, FromWhichBSSID); - } - } -} - - -VOID CmmRxRalinkFrameIndicate( - IN PRTMP_ADAPTER pAd, - IN MAC_TABLE_ENTRY *pEntry, - IN RX_BLK *pRxBlk, - IN UCHAR FromWhichBSSID) -{ - UCHAR Header802_3[LENGTH_802_3]; - UINT16 Msdu2Size; - UINT16 Payload1Size, Payload2Size; - PUCHAR pData2; - PNDIS_PACKET pPacket2 = NULL; - - - - Msdu2Size = *(pRxBlk->pData) + (*(pRxBlk->pData+1) << 8); - - if ((Msdu2Size <= 1536) && (Msdu2Size < pRxBlk->DataSize)) - { - /* skip two byte MSDU2 len */ - pRxBlk->pData += 2; - pRxBlk->DataSize -= 2; - } - else - { - // release packet - RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); - return; - } - - // get 802.3 Header and remove LLC -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - RTMP_802_11_REMOVE_LLC_AND_CONVERT_TO_802_3(pRxBlk, Header802_3); -#endif // CONFIG_STA_SUPPORT // - - - ASSERT(pRxBlk->pRxPacket); - - // Ralink Aggregation frame - pAd->RalinkCounters.OneSecRxAggregationCount ++; - Payload1Size = pRxBlk->DataSize - Msdu2Size; - Payload2Size = Msdu2Size - LENGTH_802_3; - - pData2 = pRxBlk->pData + Payload1Size + LENGTH_802_3; -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - pPacket2 = duplicate_pkt(pAd, (pData2-LENGTH_802_3), LENGTH_802_3, pData2, Payload2Size, FromWhichBSSID); -#endif // CONFIG_STA_SUPPORT // - - if (!pPacket2) - { - // release packet - RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); - return; - } - - // update payload size of 1st packet - pRxBlk->DataSize = Payload1Size; - wlan_802_11_to_802_3_packet(pAd, pRxBlk, Header802_3, FromWhichBSSID); - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - ANNOUNCE_OR_FORWARD_802_3_PACKET(pAd, pRxBlk->pRxPacket, FromWhichBSSID); -#endif // CONFIG_STA_SUPPORT // - - if (pPacket2) - { -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - ANNOUNCE_OR_FORWARD_802_3_PACKET(pAd, pPacket2, FromWhichBSSID); -#endif // CONFIG_STA_SUPPORT // - } -} - - -#define RESET_FRAGFRAME(_fragFrame) \ - { \ - _fragFrame.RxSize = 0; \ - _fragFrame.Sequence = 0; \ - _fragFrame.LastFrag = 0; \ - _fragFrame.Flags = 0; \ - } - - -PNDIS_PACKET RTMPDeFragmentDataFrame( - IN PRTMP_ADAPTER pAd, - IN RX_BLK *pRxBlk) -{ - PHEADER_802_11 pHeader = pRxBlk->pHeader; - PNDIS_PACKET pRxPacket = pRxBlk->pRxPacket; - UCHAR *pData = pRxBlk->pData; - USHORT DataSize = pRxBlk->DataSize; - PNDIS_PACKET pRetPacket = NULL; - UCHAR *pFragBuffer = NULL; - BOOLEAN bReassDone = FALSE; - UCHAR HeaderRoom = 0; - - - ASSERT(pHeader); - - HeaderRoom = pData - (UCHAR *)pHeader; - - // Re-assemble the fragmented packets - if (pHeader->Frag == 0) // Frag. Number is 0 : First frag or only one pkt - { - // the first pkt of fragment, record it. - if (pHeader->FC.MoreFrag) - { - ASSERT(pAd->FragFrame.pFragPacket); - pFragBuffer = GET_OS_PKT_DATAPTR(pAd->FragFrame.pFragPacket); - pAd->FragFrame.RxSize = DataSize + HeaderRoom; - NdisMoveMemory(pFragBuffer, pHeader, pAd->FragFrame.RxSize); - pAd->FragFrame.Sequence = pHeader->Sequence; - pAd->FragFrame.LastFrag = pHeader->Frag; // Should be 0 - ASSERT(pAd->FragFrame.LastFrag == 0); - goto done; // end of processing this frame - } - } - else //Middle & End of fragment - { - if ((pHeader->Sequence != pAd->FragFrame.Sequence) || - (pHeader->Frag != (pAd->FragFrame.LastFrag + 1))) - { - // Fragment is not the same sequence or out of fragment number order - // Reset Fragment control blk - RESET_FRAGFRAME(pAd->FragFrame); - DBGPRINT(RT_DEBUG_ERROR, ("Fragment is not the same sequence or out of fragment number order.\n")); - goto done; // give up this frame - } - else if ((pAd->FragFrame.RxSize + DataSize) > MAX_FRAME_SIZE) - { - // Fragment frame is too large, it exeeds the maximum frame size. - // Reset Fragment control blk - RESET_FRAGFRAME(pAd->FragFrame); - DBGPRINT(RT_DEBUG_ERROR, ("Fragment frame is too large, it exeeds the maximum frame size.\n")); - goto done; // give up this frame - } - - // - // Broadcom AP(BCM94704AGR) will send out LLC in fragment's packet, LLC only can accpet at first fragment. - // In this case, we will dropt it. - // - if (NdisEqualMemory(pData, SNAP_802_1H, sizeof(SNAP_802_1H))) - { - DBGPRINT(RT_DEBUG_ERROR, ("Find another LLC at Middle or End fragment(SN=%d, Frag=%d)\n", pHeader->Sequence, pHeader->Frag)); - goto done; // give up this frame - } - - pFragBuffer = GET_OS_PKT_DATAPTR(pAd->FragFrame.pFragPacket); - - // concatenate this fragment into the re-assembly buffer - NdisMoveMemory((pFragBuffer + pAd->FragFrame.RxSize), pData, DataSize); - pAd->FragFrame.RxSize += DataSize; - pAd->FragFrame.LastFrag = pHeader->Frag; // Update fragment number - - // Last fragment - if (pHeader->FC.MoreFrag == FALSE) - { - bReassDone = TRUE; - } - } - -done: - // always release rx fragmented packet - RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); - - // return defragmented packet if packet is reassembled completely - // otherwise return NULL - if (bReassDone) - { - PNDIS_PACKET pNewFragPacket; - - // allocate a new packet buffer for fragment - pNewFragPacket = RTMP_AllocateFragPacketBuffer(pAd, RX_BUFFER_NORMSIZE); - if (pNewFragPacket) - { - // update RxBlk - pRetPacket = pAd->FragFrame.pFragPacket; - pAd->FragFrame.pFragPacket = pNewFragPacket; - pRxBlk->pHeader = (PHEADER_802_11) GET_OS_PKT_DATAPTR(pRetPacket); - pRxBlk->pData = (UCHAR *)pRxBlk->pHeader + HeaderRoom; - pRxBlk->DataSize = pAd->FragFrame.RxSize - HeaderRoom; - pRxBlk->pRxPacket = pRetPacket; - } - else - { - RESET_FRAGFRAME(pAd->FragFrame); - } - } - - return pRetPacket; -} - - -VOID Indicate_AMSDU_Packet( - IN PRTMP_ADAPTER pAd, - IN RX_BLK *pRxBlk, - IN UCHAR FromWhichBSSID) -{ - UINT nMSDU; - - update_os_packet_info(pAd, pRxBlk, FromWhichBSSID); - RTMP_SET_PACKET_IF(pRxBlk->pRxPacket, FromWhichBSSID); - nMSDU = deaggregate_AMSDU_announce(pAd, pRxBlk->pRxPacket, pRxBlk->pData, pRxBlk->DataSize); -} - -VOID Indicate_EAPOL_Packet( - IN PRTMP_ADAPTER pAd, - IN RX_BLK *pRxBlk, - IN UCHAR FromWhichBSSID) -{ - MAC_TABLE_ENTRY *pEntry = NULL; - - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - pEntry = &pAd->MacTab.Content[BSSID_WCID]; - STARxEAPOLFrameIndicate(pAd, pEntry, pRxBlk, FromWhichBSSID); - return; - } -#endif // CONFIG_STA_SUPPORT // - - if (pEntry == NULL) - { - DBGPRINT(RT_DEBUG_WARN, ("Indicate_EAPOL_Packet: drop and release the invalid packet.\n")); - // release packet - RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); - return; - } -} - -#define BCN_TBTT_OFFSET 64 //defer 64 us -VOID ReSyncBeaconTime( - IN PRTMP_ADAPTER pAd) -{ - - UINT32 Offset; - - - Offset = (pAd->TbttTickCount) % (BCN_TBTT_OFFSET); - - pAd->TbttTickCount++; - - // - // The updated BeaconInterval Value will affect Beacon Interval after two TBTT - // beacasue the original BeaconInterval had been loaded into next TBTT_TIMER - // - if (Offset == (BCN_TBTT_OFFSET-2)) - { - BCN_TIME_CFG_STRUC csr; - RTMP_IO_READ32(pAd, BCN_TIME_CFG, &csr.word); - csr.field.BeaconInterval = (pAd->CommonCfg.BeaconPeriod << 4) - 1 ; // ASIC register in units of 1/16 TU = 64us - RTMP_IO_WRITE32(pAd, BCN_TIME_CFG, csr.word); - } - else - { - if (Offset == (BCN_TBTT_OFFSET-1)) - { - BCN_TIME_CFG_STRUC csr; - - RTMP_IO_READ32(pAd, BCN_TIME_CFG, &csr.word); - csr.field.BeaconInterval = (pAd->CommonCfg.BeaconPeriod) << 4; // ASIC register in units of 1/16 TU - RTMP_IO_WRITE32(pAd, BCN_TIME_CFG, csr.word); - } - } -} - +#include "../../rt2860/common/cmm_data.c" diff --git a/drivers/staging/rt2870/common/cmm_data_2870.c b/drivers/staging/rt2870/common/cmm_data_2870.c index f77000f336a9..d6fc056f81d9 100644 --- a/drivers/staging/rt2870/common/cmm_data_2870.c +++ b/drivers/staging/rt2870/common/cmm_data_2870.c @@ -189,9 +189,6 @@ USHORT RtmpUSB_WriteFragTxResource( } NdisMoveMemory(pWirelessPacket, pTxBlk->HeaderBuf, TXINFO_SIZE + TXWI_SIZE + hwHdrLen); -#ifdef RT_BIG_ENDIAN - RTMPFrameEndianChange(pAd, (PUCHAR)(pWirelessPacket + TXINFO_SIZE + TXWI_SIZE), DIR_WRITE, FALSE); -#endif // RT_BIG_ENDIAN // pWirelessPacket += (TXINFO_SIZE + TXWI_SIZE + hwHdrLen); pHTTXContext->CurWriteRealPos += (TXINFO_SIZE + TXWI_SIZE + hwHdrLen); @@ -295,6 +292,7 @@ USHORT RtmpUSB_WriteSingleTxResource( pTxBlk->Priv = (TXINFO_SIZE + USBDMApktLen); // For TxInfo, the length of USBDMApktLen = TXWI_SIZE + 802.11 header + payload + //PS packets use HCCA queue when dequeue from PS unicast queue (WiFi WPA2 MA9_DT1 for Marvell B STA) RTMPWriteTxInfo(pAd, pTxInfo, (USHORT)(USBDMApktLen), FALSE, FIFO_EDCA, FALSE /*NextValid*/, FALSE); if ((pHTTXContext->CurWritePosition + 3906 + pTxBlk->Priv) > MAX_TXBULK_LIMIT) @@ -303,9 +301,6 @@ USHORT RtmpUSB_WriteSingleTxResource( bTxQLastRound = TRUE; } NdisMoveMemory(pWirelessPacket, pTxBlk->HeaderBuf, TXINFO_SIZE + TXWI_SIZE + hwHdrLen); -#ifdef RT_BIG_ENDIAN - RTMPFrameEndianChange(pAd, (PUCHAR)(pWirelessPacket + TXINFO_SIZE + TXWI_SIZE), DIR_WRITE, FALSE); -#endif // RT_BIG_ENDIAN // pWirelessPacket += (TXINFO_SIZE + TXWI_SIZE + hwHdrLen); // We unlock it here to prevent the first 8 bytes maybe over-writed issue. @@ -417,9 +412,6 @@ USHORT RtmpUSB_WriteMultiTxResource( // Copy it. NdisMoveMemory(pWirelessPacket, pTxBlk->HeaderBuf, pTxBlk->Priv); -#ifdef RT_BIG_ENDIAN - RTMPFrameEndianChange(pAd, (PUCHAR)(pWirelessPacket+ TXINFO_SIZE + TXWI_SIZE), DIR_WRITE, FALSE); -#endif // RT_BIG_ENDIAN // pHTTXContext->CurWriteRealPos += pTxBlk->Priv; pWirelessPacket += pTxBlk->Priv; } @@ -687,14 +679,7 @@ VOID RtmpUSBNullFrameKickOut( pTxWI = (PTXWI_STRUC)&pWirelessPkt[TXINFO_SIZE]; RTMPWriteTxWI(pAd, pTxWI, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, 0, BSSID_WCID, (sizeof(HEADER_802_11)), 0, 0, (UCHAR)pAd->CommonCfg.MlmeTransmit.field.MCS, IFS_HTTXOP, FALSE, &pAd->CommonCfg.MlmeTransmit); -#ifdef RT_BIG_ENDIAN - RTMPWIEndianChange((PUCHAR)pTxWI, TYPE_TXWI); -#endif // RT_BIG_ENDIAN // - RTMPMoveMemory(&pWirelessPkt[TXWI_SIZE+TXINFO_SIZE], &pAd->NullFrame, sizeof(HEADER_802_11)); -#ifdef RT_BIG_ENDIAN - RTMPFrameEndianChange(pAd, (PUCHAR)&pWirelessPkt[TXINFO_SIZE + TXWI_SIZE], DIR_WRITE, FALSE); -#endif // RT_BIG_ENDIAN // pAd->NullContext.BulkOutSize = TXINFO_SIZE + TXWI_SIZE + sizeof(pAd->NullFrame) + 4; // Fill out frame length information for global Bulk out arbitor @@ -708,7 +693,6 @@ VOID RtmpUSBNullFrameKickOut( } -#ifdef CONFIG_STA_SUPPORT /* ======================================================================== @@ -826,7 +810,12 @@ VOID RT28xxUsbStaAsicForceWakeup( AutoWakeupCfg.word = 0; RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word); +#ifndef RT30xx AsicSendCommandToMcu(pAd, 0x31, 0xff, 0x00, 0x00); +#endif +#ifdef RT30xx + AsicSendCommandToMcu(pAd, 0x31, 0xff, 0x00, 0x02); +#endif OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE); } @@ -854,7 +843,6 @@ VOID RT28xxUsbStaAsicSleepThenAutoWakeup( OPSTATUS_SET_FLAG(pAd, fOP_STATUS_DOZE); } -#endif // CONFIG_STA_SUPPORT // VOID RT28xxUsbMlmeRadioOn( IN PRTMP_ADAPTER pAd) @@ -864,25 +852,30 @@ VOID RT28xxUsbMlmeRadioOn( if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF)) return; -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { +#ifndef RT30xx AsicSendCommandToMcu(pAd, 0x31, 0xff, 0x00, 0x00); +#endif +#ifdef RT30xx + AsicSendCommandToMcu(pAd, 0x31, 0xff, 0x00, 0x02); +#endif RTMPusecDelay(10000); - } -#endif // CONFIG_STA_SUPPORT // + NICResetFromError(pAd); // Enable Tx/Rx RTMPEnableRxTx(pAd); +#ifdef RT3070 + if (IS_RT3071(pAd)) + { + RT30xxReverseRFSleepModeSetup(pAd); + } +#endif // RT3070 // + // Clear Radio off flag RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF); -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - RTUSBBulkReceive(pAd); -#endif // CONFIG_STA_SUPPORT // + RTUSBBulkReceive(pAd); // Set LED RTMPSetLED(pAd, LED_RADIO_ON); @@ -904,8 +897,6 @@ VOID RT28xxUsbMlmeRadioOFF( // Set Radio off flag RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF); -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { // Link down first if any association exists if (INFRA_ON(pAd) || ADHOC_ON(pAd)) @@ -916,9 +907,8 @@ VOID RT28xxUsbMlmeRadioOFF( // Clean up old bss table BssTableInit(&pAd->ScanTab); } -#endif // CONFIG_STA_SUPPORT // - +#ifndef RT30xx // Disable MAC Tx/Rx RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); Value &= (0xfffffff3); @@ -932,6 +922,7 @@ VOID RT28xxUsbMlmeRadioOFF( // TX_PIN_CFG => value = 0x0 => 20mA RTMP_IO_WRITE32(pAd, TX_PIN_CFG, 0); +#endif if (pAd->CommonCfg.BBPCurrentBW == BW_40) { @@ -944,6 +935,14 @@ VOID RT28xxUsbMlmeRadioOFF( AsicTurnOffRFClk(pAd, pAd->CommonCfg.Channel); } +#ifdef RT30xx + // Disable Tx/Rx DMA + RTUSBReadMACRegister(pAd, WPDMA_GLO_CFG, &GloCfg.word); // disable DMA + GloCfg.field.EnableTxDMA = 0; + GloCfg.field.EnableRxDMA = 0; + RTUSBWriteMACRegister(pAd, WPDMA_GLO_CFG, GloCfg.word); // abort all TX rings +#endif + // Waiting for DMA idle i = 0; do @@ -955,9 +954,13 @@ VOID RT28xxUsbMlmeRadioOFF( RTMPusecDelay(1000); }while (i++ < 100); -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - AsicSendCommandToMcu(pAd, 0x30, 0xff, 0xff, 0x02); -#endif // CONFIG_STA_SUPPORT // +#ifdef RT30xx + // Disable MAC Tx/Rx + RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); + Value &= (0xfffffff3); + RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); +#endif + + AsicSendCommandToMcu(pAd, 0x30, 0xff, 0xff, 0x02); } diff --git a/drivers/staging/rt2870/common/cmm_info.c b/drivers/staging/rt2870/common/cmm_info.c index 47a1b1a73f09..226187ee5561 100644 --- a/drivers/staging/rt2870/common/cmm_info.c +++ b/drivers/staging/rt2870/common/cmm_info.c @@ -1,3712 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * 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 "../rt_config.h" - -INT Show_SSID_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -INT Show_WirelessMode_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -INT Show_TxBurst_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -INT Show_TxPreamble_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -INT Show_TxPower_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -INT Show_Channel_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -INT Show_BGProtection_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -INT Show_RTSThreshold_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -INT Show_FragThreshold_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -#ifdef DOT11_N_SUPPORT -INT Show_HtBw_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -INT Show_HtMcs_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -INT Show_HtGi_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -INT Show_HtOpMode_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -INT Show_HtExtcha_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -INT Show_HtMpduDensity_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -INT Show_HtBaWinSize_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -INT Show_HtRdg_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -INT Show_HtAmsdu_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -INT Show_HtAutoBa_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); -#endif // DOT11_N_SUPPORT // - -INT Show_CountryRegion_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -INT Show_CountryRegionABand_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -INT Show_CountryCode_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -#ifdef AGGREGATION_SUPPORT -INT Show_PktAggregate_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); -#endif // AGGREGATION_SUPPORT // - -#ifdef WMM_SUPPORT -INT Show_WmmCapable_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); -#endif // WMM_SUPPORT // - -INT Show_IEEE80211H_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -#ifdef CONFIG_STA_SUPPORT -INT Show_NetworkType_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); -#endif // CONFIG_STA_SUPPORT // - -INT Show_AuthMode_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -INT Show_EncrypType_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -INT Show_DefaultKeyID_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -INT Show_Key1_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -INT Show_Key2_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -INT Show_Key3_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -INT Show_Key4_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -INT Show_WPAPSK_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -static struct { - CHAR *name; - INT (*show_proc)(PRTMP_ADAPTER pAdapter, PUCHAR arg); -} *PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC, RTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC[] = { - {"SSID", Show_SSID_Proc}, - {"WirelessMode", Show_WirelessMode_Proc}, - {"TxBurst", Show_TxBurst_Proc}, - {"TxPreamble", Show_TxPreamble_Proc}, - {"TxPower", Show_TxPower_Proc}, - {"Channel", Show_Channel_Proc}, - {"BGProtection", Show_BGProtection_Proc}, - {"RTSThreshold", Show_RTSThreshold_Proc}, - {"FragThreshold", Show_FragThreshold_Proc}, -#ifdef DOT11_N_SUPPORT - {"HtBw", Show_HtBw_Proc}, - {"HtMcs", Show_HtMcs_Proc}, - {"HtGi", Show_HtGi_Proc}, - {"HtOpMode", Show_HtOpMode_Proc}, - {"HtExtcha", Show_HtExtcha_Proc}, - {"HtMpduDensity", Show_HtMpduDensity_Proc}, - {"HtBaWinSize", Show_HtBaWinSize_Proc}, - {"HtRdg", Show_HtRdg_Proc}, - {"HtAmsdu", Show_HtAmsdu_Proc}, - {"HtAutoBa", Show_HtAutoBa_Proc}, -#endif // DOT11_N_SUPPORT // - {"CountryRegion", Show_CountryRegion_Proc}, - {"CountryRegionABand", Show_CountryRegionABand_Proc}, - {"CountryCode", Show_CountryCode_Proc}, -#ifdef AGGREGATION_SUPPORT - {"PktAggregate", Show_PktAggregate_Proc}, -#endif - -#ifdef WMM_SUPPORT - {"WmmCapable", Show_WmmCapable_Proc}, -#endif - {"IEEE80211H", Show_IEEE80211H_Proc}, -#ifdef CONFIG_STA_SUPPORT - {"NetworkType", Show_NetworkType_Proc}, -#endif // CONFIG_STA_SUPPORT // - {"AuthMode", Show_AuthMode_Proc}, - {"EncrypType", Show_EncrypType_Proc}, - {"DefaultKeyID", Show_DefaultKeyID_Proc}, - {"Key1", Show_Key1_Proc}, - {"Key2", Show_Key2_Proc}, - {"Key3", Show_Key3_Proc}, - {"Key4", Show_Key4_Proc}, - {"WPAPSK", Show_WPAPSK_Proc}, - {NULL, NULL} -}; - -/* - ========================================================================== - Description: - Get Driver version. - - Return: - ========================================================================== -*/ -INT Set_DriverVersion_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - DBGPRINT(RT_DEBUG_TRACE, ("Driver version-%s\n", STA_DRIVER_VERSION)); -#endif // CONFIG_STA_SUPPORT // - - return TRUE; -} - -/* - ========================================================================== - Description: - Set Country Region. - This command will not work, if the field of CountryRegion in eeprom is programmed. - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_CountryRegion_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ULONG region; - - region = simple_strtol(arg, 0, 10); - -#ifdef EXT_BUILD_CHANNEL_LIST - return -EOPNOTSUPP; -#endif // EXT_BUILD_CHANNEL_LIST // - - // Country can be set only when EEPROM not programmed - if (pAd->CommonCfg.CountryRegion & 0x80) - { - DBGPRINT(RT_DEBUG_ERROR, ("Set_CountryRegion_Proc::parameter of CountryRegion in eeprom is programmed \n")); - return FALSE; - } - - if((region >= 0) && (region <= REGION_MAXIMUM_BG_BAND)) - { - pAd->CommonCfg.CountryRegion = (UCHAR) region; - } - else if (region == REGION_31_BG_BAND) - { - pAd->CommonCfg.CountryRegion = (UCHAR) region; - } - else - { - DBGPRINT(RT_DEBUG_ERROR, ("Set_CountryRegion_Proc::parameters out of range\n")); - return FALSE; - } - - // if set country region, driver needs to be reset - BuildChannelList(pAd); - - DBGPRINT(RT_DEBUG_TRACE, ("Set_CountryRegion_Proc::(CountryRegion=%d)\n", pAd->CommonCfg.CountryRegion)); - - return TRUE; -} - -/* - ========================================================================== - Description: - Set Country Region for A band. - This command will not work, if the field of CountryRegion in eeprom is programmed. - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_CountryRegionABand_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ULONG region; - - region = simple_strtol(arg, 0, 10); - -#ifdef EXT_BUILD_CHANNEL_LIST - return -EOPNOTSUPP; -#endif // EXT_BUILD_CHANNEL_LIST // - - // Country can be set only when EEPROM not programmed - if (pAd->CommonCfg.CountryRegionForABand & 0x80) - { - DBGPRINT(RT_DEBUG_ERROR, ("Set_CountryRegionABand_Proc::parameter of CountryRegion in eeprom is programmed \n")); - return FALSE; - } - - if((region >= 0) && (region <= REGION_MAXIMUM_A_BAND)) - { - pAd->CommonCfg.CountryRegionForABand = (UCHAR) region; - } - else - { - DBGPRINT(RT_DEBUG_ERROR, ("Set_CountryRegionABand_Proc::parameters out of range\n")); - return FALSE; - } - - // if set country region, driver needs to be reset - BuildChannelList(pAd); - - DBGPRINT(RT_DEBUG_TRACE, ("Set_CountryRegionABand_Proc::(CountryRegion=%d)\n", pAd->CommonCfg.CountryRegionForABand)); - - return TRUE; -} - -/* - ========================================================================== - Description: - Set Wireless Mode - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_WirelessMode_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ULONG WirelessMode; - INT success = TRUE; - - WirelessMode = simple_strtol(arg, 0, 10); - - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - INT MaxPhyMode = PHY_11G; - -#ifdef DOT11_N_SUPPORT - MaxPhyMode = PHY_11N_5G; -#endif // DOT11_N_SUPPORT // - - if (WirelessMode <= MaxPhyMode) - { - RTMPSetPhyMode(pAd, WirelessMode); -#ifdef DOT11_N_SUPPORT - if (WirelessMode >= PHY_11ABGN_MIXED) - { - pAd->CommonCfg.BACapability.field.AutoBA = TRUE; - pAd->CommonCfg.REGBACapability.field.AutoBA = TRUE; - } - else - { - pAd->CommonCfg.BACapability.field.AutoBA = FALSE; - pAd->CommonCfg.REGBACapability.field.AutoBA = FALSE; - } -#endif // DOT11_N_SUPPORT // - // Set AdhocMode rates - if (pAd->StaCfg.BssType == BSS_ADHOC) - { - MlmeUpdateTxRates(pAd, FALSE, 0); - MakeIbssBeacon(pAd); // re-build BEACON frame - AsicEnableIbssSync(pAd); // copy to on-chip memory - } - } - else - { - success = FALSE; - } - } -#endif // CONFIG_STA_SUPPORT // - - // it is needed to set SSID to take effect - if (success == TRUE) - { -#ifdef DOT11_N_SUPPORT - SetCommonHT(pAd); -#endif // DOT11_N_SUPPORT // - DBGPRINT(RT_DEBUG_TRACE, ("Set_WirelessMode_Proc::(=%ld)\n", WirelessMode)); - } - else - { - DBGPRINT(RT_DEBUG_ERROR, ("Set_WirelessMode_Proc::parameters out of range\n")); - } - - return success; -} - -/* - ========================================================================== - Description: - Set Channel - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_Channel_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - INT success = TRUE; - UCHAR Channel; - - Channel = (UCHAR) simple_strtol(arg, 0, 10); - - // check if this channel is valid - if (ChannelSanity(pAd, Channel) == TRUE) - { -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - pAd->CommonCfg.Channel = Channel; - - if (MONITOR_ON(pAd)) - { -#ifdef DOT11_N_SUPPORT - N_ChannelCheck(pAd); - if (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED && - pAd->CommonCfg.RegTransmitSetting.field.BW == BW_40) - { - N_SetCenCh(pAd); - AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE); - AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel); - DBGPRINT(RT_DEBUG_TRACE, ("BW_40, control_channel(%d), CentralChannel(%d) \n", - pAd->CommonCfg.Channel, pAd->CommonCfg.CentralChannel)); - } - else -#endif // DOT11_N_SUPPORT // - { - AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); - AsicLockChannel(pAd, pAd->CommonCfg.Channel); - DBGPRINT(RT_DEBUG_TRACE, ("BW_20, Channel(%d)\n", pAd->CommonCfg.Channel)); - } - } - } -#endif // CONFIG_STA_SUPPORT // - success = TRUE; - } - else - { - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - success = FALSE; -#endif // CONFIG_STA_SUPPORT // - } - - - if (success == TRUE) - DBGPRINT(RT_DEBUG_TRACE, ("Set_Channel_Proc::(Channel=%d)\n", pAd->CommonCfg.Channel)); - - return success; -} - -/* - ========================================================================== - Description: - Set Short Slot Time Enable or Disable - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_ShortSlot_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ULONG ShortSlot; - - ShortSlot = simple_strtol(arg, 0, 10); - - if (ShortSlot == 1) - pAd->CommonCfg.bUseShortSlotTime = TRUE; - else if (ShortSlot == 0) - pAd->CommonCfg.bUseShortSlotTime = FALSE; - else - return FALSE; //Invalid argument - - DBGPRINT(RT_DEBUG_TRACE, ("Set_ShortSlot_Proc::(ShortSlot=%d)\n", pAd->CommonCfg.bUseShortSlotTime)); - - return TRUE; -} - -/* - ========================================================================== - Description: - Set Tx power - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_TxPower_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ULONG TxPower; - INT success = FALSE; - - TxPower = (ULONG) simple_strtol(arg, 0, 10); - if (TxPower <= 100) - { - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - pAd->CommonCfg.TxPowerDefault = TxPower; - pAd->CommonCfg.TxPowerPercentage = pAd->CommonCfg.TxPowerDefault; - } -#endif // CONFIG_STA_SUPPORT // - success = TRUE; - } - else - success = FALSE; - - DBGPRINT(RT_DEBUG_TRACE, ("Set_TxPower_Proc::(TxPowerPercentage=%ld)\n", pAd->CommonCfg.TxPowerPercentage)); - - return success; -} - -/* - ========================================================================== - Description: - Set 11B/11G Protection - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_BGProtection_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - switch (simple_strtol(arg, 0, 10)) - { - case 0: //AUTO - pAd->CommonCfg.UseBGProtection = 0; - break; - case 1: //Always On - pAd->CommonCfg.UseBGProtection = 1; - break; - case 2: //Always OFF - pAd->CommonCfg.UseBGProtection = 2; - break; - default: //Invalid argument - return FALSE; - } - - - DBGPRINT(RT_DEBUG_TRACE, ("Set_BGProtection_Proc::(BGProtection=%ld)\n", pAd->CommonCfg.UseBGProtection)); - - return TRUE; -} - -/* - ========================================================================== - Description: - Set TxPreamble - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_TxPreamble_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - RT_802_11_PREAMBLE Preamble; - - Preamble = simple_strtol(arg, 0, 10); - - - switch (Preamble) - { - case Rt802_11PreambleShort: - pAd->CommonCfg.TxPreamble = Preamble; -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - MlmeSetTxPreamble(pAd, Rt802_11PreambleShort); -#endif // CONFIG_STA_SUPPORT // - break; - case Rt802_11PreambleLong: -#ifdef CONFIG_STA_SUPPORT - case Rt802_11PreambleAuto: - // if user wants AUTO, initialize to LONG here, then change according to AP's - // capability upon association. -#endif // CONFIG_STA_SUPPORT // - pAd->CommonCfg.TxPreamble = Preamble; -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - MlmeSetTxPreamble(pAd, Rt802_11PreambleLong); -#endif // CONFIG_STA_SUPPORT // - break; - default: //Invalid argument - return FALSE; - } - - DBGPRINT(RT_DEBUG_TRACE, ("Set_TxPreamble_Proc::(TxPreamble=%ld)\n", pAd->CommonCfg.TxPreamble)); - - return TRUE; -} - -/* - ========================================================================== - Description: - Set RTS Threshold - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_RTSThreshold_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - NDIS_802_11_RTS_THRESHOLD RtsThresh; - - RtsThresh = simple_strtol(arg, 0, 10); - - if((RtsThresh > 0) && (RtsThresh <= MAX_RTS_THRESHOLD)) - pAd->CommonCfg.RtsThreshold = (USHORT)RtsThresh; -#ifdef CONFIG_STA_SUPPORT - else if (RtsThresh == 0) - pAd->CommonCfg.RtsThreshold = MAX_RTS_THRESHOLD; -#endif // CONFIG_STA_SUPPORT // - else - return FALSE; //Invalid argument - - DBGPRINT(RT_DEBUG_TRACE, ("Set_RTSThreshold_Proc::(RTSThreshold=%d)\n", pAd->CommonCfg.RtsThreshold)); - - return TRUE; -} - -/* - ========================================================================== - Description: - Set Fragment Threshold - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_FragThreshold_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - NDIS_802_11_FRAGMENTATION_THRESHOLD FragThresh; - - FragThresh = simple_strtol(arg, 0, 10); - - if (FragThresh > MAX_FRAG_THRESHOLD || FragThresh < MIN_FRAG_THRESHOLD) - { - //Illegal FragThresh so we set it to default - pAd->CommonCfg.FragmentThreshold = MAX_FRAG_THRESHOLD; - } - else if (FragThresh % 2 == 1) - { - // The length of each fragment shall always be an even number of octets, except for the last fragment - // of an MSDU or MMPDU, which may be either an even or an odd number of octets. - pAd->CommonCfg.FragmentThreshold = (USHORT)(FragThresh - 1); - } - else - { - pAd->CommonCfg.FragmentThreshold = (USHORT)FragThresh; - } - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - if (pAd->CommonCfg.FragmentThreshold == MAX_FRAG_THRESHOLD) - pAd->CommonCfg.bUseZeroToDisableFragment = TRUE; - else - pAd->CommonCfg.bUseZeroToDisableFragment = FALSE; - } -#endif // CONFIG_STA_SUPPORT // - - DBGPRINT(RT_DEBUG_TRACE, ("Set_FragThreshold_Proc::(FragThreshold=%d)\n", pAd->CommonCfg.FragmentThreshold)); - - return TRUE; -} - -/* - ========================================================================== - Description: - Set TxBurst - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_TxBurst_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ULONG TxBurst; - - TxBurst = simple_strtol(arg, 0, 10); - if (TxBurst == 1) - pAd->CommonCfg.bEnableTxBurst = TRUE; - else if (TxBurst == 0) - pAd->CommonCfg.bEnableTxBurst = FALSE; - else - return FALSE; //Invalid argument - - DBGPRINT(RT_DEBUG_TRACE, ("Set_TxBurst_Proc::(TxBurst=%d)\n", pAd->CommonCfg.bEnableTxBurst)); - - return TRUE; -} - -#ifdef AGGREGATION_SUPPORT -/* - ========================================================================== - Description: - Set TxBurst - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_PktAggregate_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ULONG aggre; - - aggre = simple_strtol(arg, 0, 10); - - if (aggre == 1) - pAd->CommonCfg.bAggregationCapable = TRUE; - else if (aggre == 0) - pAd->CommonCfg.bAggregationCapable = FALSE; - else - return FALSE; //Invalid argument - - - DBGPRINT(RT_DEBUG_TRACE, ("Set_PktAggregate_Proc::(AGGRE=%d)\n", pAd->CommonCfg.bAggregationCapable)); - - return TRUE; -} -#endif - -/* - ========================================================================== - Description: - Set IEEE80211H. - This parameter is 1 when needs radar detection, otherwise 0 - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_IEEE80211H_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ULONG ieee80211h; - - ieee80211h = simple_strtol(arg, 0, 10); - - if (ieee80211h == 1) - pAd->CommonCfg.bIEEE80211H = TRUE; - else if (ieee80211h == 0) - pAd->CommonCfg.bIEEE80211H = FALSE; - else - return FALSE; //Invalid argument - - DBGPRINT(RT_DEBUG_TRACE, ("Set_IEEE80211H_Proc::(IEEE80211H=%d)\n", pAd->CommonCfg.bIEEE80211H)); - - return TRUE; -} - - -#ifdef DBG -/* - ========================================================================== - Description: - For Debug information - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_Debug_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - DBGPRINT(RT_DEBUG_TRACE, ("==> Set_Debug_Proc *******************\n")); - - if(simple_strtol(arg, 0, 10) <= RT_DEBUG_LOUD) - RTDebugLevel = simple_strtol(arg, 0, 10); - - DBGPRINT(RT_DEBUG_TRACE, ("<== Set_Debug_Proc(RTDebugLevel = %ld)\n", RTDebugLevel)); - - return TRUE; -} -#endif - -INT Show_DescInfo_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - - return TRUE; -} - -/* - ========================================================================== - Description: - Reset statistics counter - - Arguments: - pAdapter Pointer to our adapter - arg - - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_ResetStatCounter_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - //UCHAR i; - //MAC_TABLE_ENTRY *pEntry; - - DBGPRINT(RT_DEBUG_TRACE, ("==>Set_ResetStatCounter_Proc\n")); - - // add the most up-to-date h/w raw counters into software counters - NICUpdateRawCounters(pAd); - - NdisZeroMemory(&pAd->WlanCounters, sizeof(COUNTER_802_11)); - NdisZeroMemory(&pAd->Counters8023, sizeof(COUNTER_802_3)); - NdisZeroMemory(&pAd->RalinkCounters, sizeof(COUNTER_RALINK)); - - // Reset HotSpot counter -#if 0 // ToDo. - for (i = 0; i < MAX_LEN_OF_MAC_TABLE; i++) - { - pEntry = &pAd->MacTab.Content[i]; - - if ((pEntry->Valid == FALSE) || (pEntry->Sst != SST_ASSOC)) - continue; - - pEntry->HSCounter.LastDataPacketTime = 0; - pEntry->HSCounter.TotalRxByteCount= 0; - pEntry->HSCounter.TotalTxByteCount= 0; - } -#endif - - - return TRUE; -} - -/* - ======================================================================== - - Routine Description: - Add WPA key process. - In Adhoc WPANONE, bPairwise = 0; KeyIdx = 0; - - Arguments: - pAd Pointer to our adapter - pBuf Pointer to the where the key stored - - Return Value: - NDIS_SUCCESS Add key successfully - - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -#if 0 // remove by AlbertY -NDIS_STATUS RTMPWPAAddKeyProc( - IN PRTMP_ADAPTER pAd, - IN PVOID pBuf) -{ - PNDIS_802_11_KEY pKey; - ULONG KeyIdx; -// NDIS_STATUS Status; -// ULONG offset; // unused variable, snowpin 2006.07.13 - - PUCHAR pTxMic, pRxMic; - BOOLEAN bTxKey; // Set the key as transmit key - BOOLEAN bPairwise; // Indicate the key is pairwise key - BOOLEAN bKeyRSC; // indicate the receive SC set by KeyRSC value. - // Otherwise, it will set by the NIC. - BOOLEAN bAuthenticator; // indicate key is set by authenticator. - UCHAR apidx = BSS0; - - pKey = (PNDIS_802_11_KEY) pBuf; - KeyIdx = pKey->KeyIndex & 0xff; - // Bit 31 of Add-key, Tx Key - bTxKey = (pKey->KeyIndex & 0x80000000) ? TRUE : FALSE; - // Bit 30 of Add-key PairwiseKey - bPairwise = (pKey->KeyIndex & 0x40000000) ? TRUE : FALSE; - // Bit 29 of Add-key KeyRSC - bKeyRSC = (pKey->KeyIndex & 0x20000000) ? TRUE : FALSE; - // Bit 28 of Add-key Authenticator - bAuthenticator = (pKey->KeyIndex & 0x10000000) ? TRUE : FALSE; - - DBGPRINT(RT_DEBUG_TRACE,("RTMPWPAAddKeyProc==>pKey->KeyIndex = %x. bPairwise= %d\n", pKey->KeyIndex, bPairwise)); - // 1. Check Group / Pairwise Key - if (bPairwise) // Pairwise Key - { - // 1. KeyIdx must be 0, otherwise, return NDIS_STATUS_INVALID_DATA - if (KeyIdx != 0) - return(NDIS_STATUS_INVALID_DATA); - - // 2. Check bTx, it must be true, otherwise, return NDIS_STATUS_INVALID_DATA - if (bTxKey == FALSE) - return(NDIS_STATUS_INVALID_DATA); - - // 3. If BSSID is all 0xff, return NDIS_STATUS_INVALID_DATA - if (MAC_ADDR_EQUAL(pKey->BSSID, BROADCAST_ADDR)) - return(NDIS_STATUS_INVALID_DATA); - - // 3.1 Check Pairwise key length for TKIP key. For AES, it's always 128 bits - //if ((pAdapter->PortCfg.WepStatus == Ndis802_11Encryption2Enabled) && (pKey->KeyLength != LEN_TKIP_KEY)) - if ((pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled) && (pKey->KeyLength != LEN_TKIP_KEY)) - return(NDIS_STATUS_INVALID_DATA); - - pAd->SharedKey[apidx][KeyIdx].Type = PAIRWISE_KEY; - - if (pAd->ApCfg.MBSSID[apidx].AuthMode == Ndis802_11AuthModeWPA2) - { - // Send media specific event to start PMKID caching - RTMPIndicateWPA2Status(pAd); - } - } - else - { - // 1. Check BSSID, if not current BSSID or Bcast, return NDIS_STATUS_INVALID_DATA - if ((! MAC_ADDR_EQUAL(pKey->BSSID, BROADCAST_ADDR)) && - (! MAC_ADDR_EQUAL(pKey->BSSID, pAd->ApCfg.MBSSID[apidx].Bssid))) - return(NDIS_STATUS_INVALID_DATA); - - // 2. Check Key index for supported Group Key - if (KeyIdx >= GROUP_KEY_NUM) - return(NDIS_STATUS_INVALID_DATA); - - // 3. Set as default Tx Key if bTxKey is TRUE - if (bTxKey == TRUE) - pAd->ApCfg.MBSSID[apidx].DefaultKeyId = (UCHAR) KeyIdx; - - pAd->SharedKey[apidx][KeyIdx].Type = GROUP_KEY; - } - - // 4. Select RxMic / TxMic based on Supp / Authenticator - if (pAd->ApCfg.MBSSID[apidx].AuthMode == Ndis802_11AuthModeWPANone) - { - // for WPA-None Tx, Rx MIC is the same - pTxMic = (PUCHAR) (&pKey->KeyMaterial) + 16; - pRxMic = pTxMic; - } - else if (bAuthenticator == TRUE) - { - pTxMic = (PUCHAR) (&pKey->KeyMaterial) + 16; - pRxMic = (PUCHAR) (&pKey->KeyMaterial) + 24; - } - else - { - pRxMic = (PUCHAR) (&pKey->KeyMaterial) + 16; - pTxMic = (PUCHAR) (&pKey->KeyMaterial) + 24; - } - - // 6. Check RxTsc - if (bKeyRSC == TRUE) - { - NdisMoveMemory(pAd->SharedKey[apidx][KeyIdx].RxTsc, &pKey->KeyRSC, 6); - NdisMoveMemory(pAd->MacTab.Content[BSSID_WCID].PairwiseKey.RxTsc, &pKey->KeyRSC, 6); - } - else - { - NdisZeroMemory(pAd->SharedKey[apidx][KeyIdx].RxTsc, 6); - } - - // 7. Copy information into Pairwise Key structure. - // pKey->KeyLength will include TxMic and RxMic, therefore, we use 16 bytes hardcoded. - pAd->SharedKey[apidx][KeyIdx].KeyLen = (UCHAR) pKey->KeyLength; - pAd->MacTab.Content[BSSID_WCID].PairwiseKey.KeyLen = (UCHAR)pKey->KeyLength; - NdisMoveMemory(pAd->SharedKey[BSS0][KeyIdx].Key, &pKey->KeyMaterial, 16); - NdisMoveMemory(pAd->MacTab.Content[BSSID_WCID].PairwiseKey.Key, &pKey->KeyMaterial, 16); - if (pKey->KeyLength == LEN_TKIP_KEY) - { - // Only Key lenth equal to TKIP key have these - NdisMoveMemory(pAd->SharedKey[apidx][KeyIdx].RxMic, pRxMic, 8); - NdisMoveMemory(pAd->SharedKey[apidx][KeyIdx].TxMic, pTxMic, 8); - NdisMoveMemory(pAd->MacTab.Content[BSSID_WCID].PairwiseKey.RxMic, pRxMic, 8); - NdisMoveMemory(pAd->MacTab.Content[BSSID_WCID].PairwiseKey.TxMic, pTxMic, 8); - } - - COPY_MAC_ADDR(pAd->SharedKey[BSS0][KeyIdx].BssId, pKey->BSSID); - - // Init TxTsc to one based on WiFi WPA specs - pAd->SharedKey[apidx][KeyIdx].TxTsc[0] = 1; - pAd->SharedKey[apidx][KeyIdx].TxTsc[1] = 0; - pAd->SharedKey[apidx][KeyIdx].TxTsc[2] = 0; - pAd->SharedKey[apidx][KeyIdx].TxTsc[3] = 0; - pAd->SharedKey[apidx][KeyIdx].TxTsc[4] = 0; - pAd->SharedKey[apidx][KeyIdx].TxTsc[5] = 0; - // 4. Init TxTsc to one based on WiFi WPA specs - pAd->MacTab.Content[BSSID_WCID].PairwiseKey.TxTsc[0] = 1; - pAd->MacTab.Content[BSSID_WCID].PairwiseKey.TxTsc[1] = 0; - pAd->MacTab.Content[BSSID_WCID].PairwiseKey.TxTsc[2] = 0; - pAd->MacTab.Content[BSSID_WCID].PairwiseKey.TxTsc[3] = 0; - pAd->MacTab.Content[BSSID_WCID].PairwiseKey.TxTsc[4] = 0; - pAd->MacTab.Content[BSSID_WCID].PairwiseKey.TxTsc[5] = 0; - - if (pAd->ApCfg.MBSSID[apidx].WepStatus == Ndis802_11Encryption3Enabled) - { - pAd->SharedKey[apidx][KeyIdx].CipherAlg = CIPHER_AES; - pAd->MacTab.Content[BSSID_WCID].PairwiseKey.CipherAlg = CIPHER_AES; - } - else if (pAd->ApCfg.MBSSID[apidx].WepStatus == Ndis802_11Encryption2Enabled) - { - pAd->SharedKey[apidx][KeyIdx].CipherAlg = CIPHER_TKIP; - pAd->MacTab.Content[BSSID_WCID].PairwiseKey.CipherAlg = CIPHER_TKIP; - } - else if (pAd->ApCfg.MBSSID[apidx].WepStatus == Ndis802_11Encryption1Enabled) - { - if (pAd->SharedKey[apidx][KeyIdx].KeyLen == 5) - { - pAd->SharedKey[apidx][KeyIdx].CipherAlg = CIPHER_WEP64; - pAd->MacTab.Content[BSSID_WCID].PairwiseKey.CipherAlg = CIPHER_WEP64; - } - else if (pAd->SharedKey[apidx][KeyIdx].KeyLen == 13) - { - pAd->SharedKey[apidx][KeyIdx].CipherAlg = CIPHER_WEP128; - pAd->MacTab.Content[BSSID_WCID].PairwiseKey.CipherAlg = CIPHER_WEP128; - } - else - { - pAd->SharedKey[apidx][KeyIdx].CipherAlg = CIPHER_NONE; - pAd->MacTab.Content[BSSID_WCID].PairwiseKey.CipherAlg = CIPHER_NONE; - } - } - else - { - pAd->SharedKey[apidx][KeyIdx].CipherAlg = CIPHER_NONE; - pAd->MacTab.Content[BSSID_WCID].PairwiseKey.CipherAlg = CIPHER_NONE; - } - - if ((pAd->OpMode == OPMODE_STA)) // Pairwise Key. Add BSSID to WCTable - { - pAd->MacTab.Content[BSSID_WCID].PairwiseKey.CipherAlg = pAd->SharedKey[BSS0][KeyIdx].CipherAlg; - pAd->MacTab.Content[BSSID_WCID].PairwiseKey.KeyLen = pAd->SharedKey[BSS0][KeyIdx].KeyLen; - } - - if ((pAd->ApCfg.MBSSID[apidx].AuthMode == Ndis802_11AuthModeWPA2) || - (pAd->ApCfg.MBSSID[apidx].AuthMode == Ndis802_11AuthModeWPA2PSK)) - { - // - // On WPA2, Update Group Key Cipher. - // - if (!bPairwise) - { - if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption3Enabled) - pAd->SharedKey[apidx][KeyIdx].CipherAlg = CIPHER_AES; - else if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption2Enabled) - pAd->SharedKey[apidx][KeyIdx].CipherAlg = CIPHER_TKIP; - } - } - - DBGPRINT(RT_DEBUG_TRACE, ("pAd->SharedKey[%d][%d].CipherAlg = %d\n", apidx, KeyIdx, pAd->SharedKey[apidx][KeyIdx].CipherAlg)); - -#if 0 - DBGPRINT_RAW(RT_DEBUG_TRACE, ("%s Key #%d", CipherName[pAd->SharedKey[apidx][KeyIdx].CipherAlg],KeyIdx)); - for (i = 0; i < 16; i++) - { - DBGPRINT_RAW(RT_DEBUG_TRACE, ("%02x:", pAd->SharedKey[apidx][KeyIdx].Key[i])); - } - DBGPRINT_RAW(RT_DEBUG_TRACE, ("\n Rx MIC Key = ")); - for (i = 0; i < 8; i++) - { - DBGPRINT_RAW(RT_DEBUG_TRACE, ("%02x:", pAd->SharedKey[apidx][KeyIdx].RxMic[i])); - } - DBGPRINT_RAW(RT_DEBUG_TRACE, ("\n Tx MIC Key = ")); - for (i = 0; i < 8; i++) - { - DBGPRINT_RAW(RT_DEBUG_TRACE, ("%02x:", pAd->SharedKey[apidx][KeyIdx].TxMic[i])); - } - DBGPRINT_RAW(RT_DEBUG_TRACE, ("\n RxTSC = ")); - for (i = 0; i < 6; i++) - { - DBGPRINT_RAW(RT_DEBUG_TRACE, ("%02x:", pAd->SharedKey[apidx][KeyIdx].RxTsc[i])); - } -#endif - DBGPRINT_RAW(RT_DEBUG_TRACE, ("\n pKey-> BSSID:%02x:%02x:%02x:%02x:%02x:%02x \n", - pKey->BSSID[0],pKey->BSSID[1],pKey->BSSID[2],pKey->BSSID[3],pKey->BSSID[4],pKey->BSSID[5])); - - if ((bTxKey) && (pAd->OpMode == OPMODE_STA)) // Pairwise Key. Add BSSID to WCTable - RTMPAddBSSIDCipher(pAd, BSSID_WCID, pKey, pAd->SharedKey[BSS0][KeyIdx].CipherAlg); - - - // No matter pairwise key or what leyidx is, always has a copy at on-chip SharedKeytable. - AsicAddSharedKeyEntry(pAd, - apidx, - (UCHAR)KeyIdx, - pAd->SharedKey[apidx][KeyIdx].CipherAlg, - pAd->SharedKey[apidx][KeyIdx].Key, - pAd->SharedKey[apidx][KeyIdx].TxMic, - pAd->SharedKey[apidx][KeyIdx].RxMic); - - // The WCID key specified in used at Tx. For STA, always use pairwise key. - - // ad-hoc mode need to specify WAP Group key with WCID index=BSS0Mcast_WCID. Let's always set this key here. -/* if (bPairwise == FALSE) - { - offset = MAC_IVEIV_TABLE_BASE + (BSS0Mcast_WCID * HW_IVEIV_ENTRY_SIZE); - NdisZeroMemory(IVEIV, 8); - // 1. IV/EIV - // Specify key index to find shared key. - if ((pAd->SharedKey[BSS0][KeyIdx].CipherAlg==CIPHER_TKIP) || - (pAd->SharedKey[BSS0][KeyIdx].CipherAlg==CIPHER_AES)) - IVEIV[3] = 0x20; // Eiv bit on. keyid always 0 for pairwise key - IVEIV[3] |= (KeyIdx<< 6); // groupkey index is not 0 - for (i=0; i<8; i++) - { - RTMP_IO_WRITE8(pAd, offset+i, IVEIV[i]); - } - - // 2. WCID Attribute UDF:3, BSSIdx:3, Alg:3, Keytable:use share key, BSSIdx is 0 - WCIDAttri = (pAd->SharedKey[BSS0][KeyIdx].CipherAlg<<1)|PAIRWISEKEYTABLE; - offset = MAC_WCID_ATTRIBUTE_BASE + (BSS0Mcast_WCID* HW_WCID_ATTRI_SIZE); - RTMP_IO_WRITE32(pAd, offset, WCIDAttri); - - } - -*/ - - if (pAd->SharedKey[apidx][KeyIdx].Type == GROUP_KEY) - { - // 802.1x port control - pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; - DBGPRINT(RT_DEBUG_TRACE,("!!WPA_802_1X_PORT_SECURED!!\n")); - - } - - return (NDIS_STATUS_SUCCESS); -} -#endif - -BOOLEAN RTMPCheckStrPrintAble( - IN CHAR *pInPutStr, - IN UCHAR strLen) -{ - UCHAR i=0; - - for (i=0; i 0x7E)) - return FALSE; - } - - return TRUE; -} - -/* - ======================================================================== - - Routine Description: - Remove WPA Key process - - Arguments: - pAd Pointer to our adapter - pBuf Pointer to the where the key stored - - Return Value: - NDIS_SUCCESS Add key successfully - - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -#ifdef CONFIG_STA_SUPPORT -VOID RTMPSetDesiredRates( - IN PRTMP_ADAPTER pAdapter, - IN LONG Rates) -{ - NDIS_802_11_RATES aryRates; - - memset(&aryRates, 0x00, sizeof(NDIS_802_11_RATES)); - switch (pAdapter->CommonCfg.PhyMode) - { - case PHY_11A: // A only - switch (Rates) - { - case 6000000: //6M - aryRates[0] = 0x0c; // 6M - pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_0; - break; - case 9000000: //9M - aryRates[0] = 0x12; // 9M - pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_1; - break; - case 12000000: //12M - aryRates[0] = 0x18; // 12M - pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_2; - break; - case 18000000: //18M - aryRates[0] = 0x24; // 18M - pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_3; - break; - case 24000000: //24M - aryRates[0] = 0x30; // 24M - pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_4; - break; - case 36000000: //36M - aryRates[0] = 0x48; // 36M - pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_5; - break; - case 48000000: //48M - aryRates[0] = 0x60; // 48M - pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_6; - break; - case 54000000: //54M - aryRates[0] = 0x6c; // 54M - pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_7; - break; - case -1: //Auto - default: - aryRates[0] = 0x6c; // 54Mbps - aryRates[1] = 0x60; // 48Mbps - aryRates[2] = 0x48; // 36Mbps - aryRates[3] = 0x30; // 24Mbps - aryRates[4] = 0x24; // 18M - aryRates[5] = 0x18; // 12M - aryRates[6] = 0x12; // 9M - aryRates[7] = 0x0c; // 6M - pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_AUTO; - break; - } - break; - case PHY_11BG_MIXED: // B/G Mixed - case PHY_11B: // B only - case PHY_11ABG_MIXED: // A/B/G Mixed - default: - switch (Rates) - { - case 1000000: //1M - aryRates[0] = 0x02; - pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_0; - break; - case 2000000: //2M - aryRates[0] = 0x04; - pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_1; - break; - case 5000000: //5.5M - aryRates[0] = 0x0b; // 5.5M - pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_2; - break; - case 11000000: //11M - aryRates[0] = 0x16; // 11M - pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_3; - break; - case 6000000: //6M - aryRates[0] = 0x0c; // 6M - pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_0; - break; - case 9000000: //9M - aryRates[0] = 0x12; // 9M - pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_1; - break; - case 12000000: //12M - aryRates[0] = 0x18; // 12M - pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_2; - break; - case 18000000: //18M - aryRates[0] = 0x24; // 18M - pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_3; - break; - case 24000000: //24M - aryRates[0] = 0x30; // 24M - pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_4; - break; - case 36000000: //36M - aryRates[0] = 0x48; // 36M - pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_5; - break; - case 48000000: //48M - aryRates[0] = 0x60; // 48M - pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_6; - break; - case 54000000: //54M - aryRates[0] = 0x6c; // 54M - pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_7; - break; - case -1: //Auto - default: - if (pAdapter->CommonCfg.PhyMode == PHY_11B) - { //B Only - aryRates[0] = 0x16; // 11Mbps - aryRates[1] = 0x0b; // 5.5Mbps - aryRates[2] = 0x04; // 2Mbps - aryRates[3] = 0x02; // 1Mbps - } - else - { //(B/G) Mixed or (A/B/G) Mixed - aryRates[0] = 0x6c; // 54Mbps - aryRates[1] = 0x60; // 48Mbps - aryRates[2] = 0x48; // 36Mbps - aryRates[3] = 0x30; // 24Mbps - aryRates[4] = 0x16; // 11Mbps - aryRates[5] = 0x0b; // 5.5Mbps - aryRates[6] = 0x04; // 2Mbps - aryRates[7] = 0x02; // 1Mbps - } - pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_AUTO; - break; - } - break; - } - - NdisZeroMemory(pAdapter->CommonCfg.DesireRate, MAX_LEN_OF_SUPPORTED_RATES); - NdisMoveMemory(pAdapter->CommonCfg.DesireRate, &aryRates, sizeof(NDIS_802_11_RATES)); - DBGPRINT(RT_DEBUG_TRACE, (" RTMPSetDesiredRates (%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x)\n", - pAdapter->CommonCfg.DesireRate[0],pAdapter->CommonCfg.DesireRate[1], - pAdapter->CommonCfg.DesireRate[2],pAdapter->CommonCfg.DesireRate[3], - pAdapter->CommonCfg.DesireRate[4],pAdapter->CommonCfg.DesireRate[5], - pAdapter->CommonCfg.DesireRate[6],pAdapter->CommonCfg.DesireRate[7] )); - // Changing DesiredRate may affect the MAX TX rate we used to TX frames out - MlmeUpdateTxRates(pAdapter, FALSE, 0); -} - -NDIS_STATUS RTMPWPARemoveKeyProc( - IN PRTMP_ADAPTER pAd, - IN PVOID pBuf) -{ - PNDIS_802_11_REMOVE_KEY pKey; - ULONG KeyIdx; - NDIS_STATUS Status = NDIS_STATUS_FAILURE; - BOOLEAN bTxKey; // Set the key as transmit key - BOOLEAN bPairwise; // Indicate the key is pairwise key - BOOLEAN bKeyRSC; // indicate the receive SC set by KeyRSC value. - // Otherwise, it will set by the NIC. - BOOLEAN bAuthenticator; // indicate key is set by authenticator. - INT i; - - DBGPRINT(RT_DEBUG_TRACE,("---> RTMPWPARemoveKeyProc\n")); - - pKey = (PNDIS_802_11_REMOVE_KEY) pBuf; - KeyIdx = pKey->KeyIndex & 0xff; - // Bit 31 of Add-key, Tx Key - bTxKey = (pKey->KeyIndex & 0x80000000) ? TRUE : FALSE; - // Bit 30 of Add-key PairwiseKey - bPairwise = (pKey->KeyIndex & 0x40000000) ? TRUE : FALSE; - // Bit 29 of Add-key KeyRSC - bKeyRSC = (pKey->KeyIndex & 0x20000000) ? TRUE : FALSE; - // Bit 28 of Add-key Authenticator - bAuthenticator = (pKey->KeyIndex & 0x10000000) ? TRUE : FALSE; - - // 1. If bTx is TRUE, return failure information - if (bTxKey == TRUE) - return(NDIS_STATUS_INVALID_DATA); - - // 2. Check Pairwise Key - if (bPairwise) - { - // a. If BSSID is broadcast, remove all pairwise keys. - // b. If not broadcast, remove the pairwise specified by BSSID - for (i = 0; i < SHARE_KEY_NUM; i++) - { - if (MAC_ADDR_EQUAL(pAd->SharedKey[BSS0][i].BssId, pKey->BSSID)) - { - DBGPRINT(RT_DEBUG_TRACE,("RTMPWPARemoveKeyProc(KeyIdx=%d)\n", i)); - pAd->SharedKey[BSS0][i].KeyLen = 0; - pAd->SharedKey[BSS0][i].CipherAlg = CIPHER_NONE; - AsicRemoveSharedKeyEntry(pAd, BSS0, (UCHAR)i); - Status = NDIS_STATUS_SUCCESS; - break; - } - } - } - // 3. Group Key - else - { - // a. If BSSID is broadcast, remove all group keys indexed - // b. If BSSID matched, delete the group key indexed. - DBGPRINT(RT_DEBUG_TRACE,("RTMPWPARemoveKeyProc(KeyIdx=%ld)\n", KeyIdx)); - pAd->SharedKey[BSS0][KeyIdx].KeyLen = 0; - pAd->SharedKey[BSS0][KeyIdx].CipherAlg = CIPHER_NONE; - AsicRemoveSharedKeyEntry(pAd, BSS0, (UCHAR)KeyIdx); - Status = NDIS_STATUS_SUCCESS; - } - - return (Status); -} -#endif // CONFIG_STA_SUPPORT // - - -#ifdef CONFIG_STA_SUPPORT -/* - ======================================================================== - - Routine Description: - Remove All WPA Keys - - Arguments: - pAd Pointer to our adapter - - Return Value: - None - - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -VOID RTMPWPARemoveAllKeys( - IN PRTMP_ADAPTER pAd) -{ - - UCHAR i; - - DBGPRINT(RT_DEBUG_TRACE,("RTMPWPARemoveAllKeys(AuthMode=%d, WepStatus=%d)\n", pAd->StaCfg.AuthMode, pAd->StaCfg.WepStatus)); - - // For WEP/CKIP, there is no need to remove it, since WinXP won't set it again after - // Link up. And it will be replaced if user changed it. - if (pAd->StaCfg.AuthMode < Ndis802_11AuthModeWPA) - return; - - // For WPA-None, there is no need to remove it, since WinXP won't set it again after - // Link up. And it will be replaced if user changed it. - if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) - return; - - // set BSSID wcid entry of the Pair-wise Key table as no-security mode - AsicRemovePairwiseKeyEntry(pAd, BSS0, BSSID_WCID); - - // set all shared key mode as no-security. - for (i = 0; i < SHARE_KEY_NUM; i++) - { - DBGPRINT(RT_DEBUG_TRACE,("remove %s key #%d\n", CipherName[pAd->SharedKey[BSS0][i].CipherAlg], i)); - NdisZeroMemory(&pAd->SharedKey[BSS0][i], sizeof(CIPHER_KEY)); - - AsicRemoveSharedKeyEntry(pAd, BSS0, i); - } - -} -#endif // CONFIG_STA_SUPPORT // - -/* - ======================================================================== - Routine Description: - Change NIC PHY mode. Re-association may be necessary. possible settings - include - PHY_11B, PHY_11BG_MIXED, PHY_11A, and PHY_11ABG_MIXED - - Arguments: - pAd - Pointer to our adapter - phymode - - - IRQL = PASSIVE_LEVEL - IRQL = DISPATCH_LEVEL - - ======================================================================== -*/ -VOID RTMPSetPhyMode( - IN PRTMP_ADAPTER pAd, - IN ULONG phymode) -{ - INT i; - // the selected phymode must be supported by the RF IC encoded in E2PROM - - // if no change, do nothing - /* bug fix - if (pAd->CommonCfg.PhyMode == phymode) - return; - */ - pAd->CommonCfg.PhyMode = (UCHAR)phymode; - - DBGPRINT(RT_DEBUG_TRACE,("RTMPSetPhyMode : PhyMode=%d, channel=%d \n", pAd->CommonCfg.PhyMode, pAd->CommonCfg.Channel)); -#ifdef EXT_BUILD_CHANNEL_LIST - BuildChannelListEx(pAd); -#else - BuildChannelList(pAd); -#endif // EXT_BUILD_CHANNEL_LIST // - - // sanity check user setting - for (i = 0; i < pAd->ChannelListNum; i++) - { - if (pAd->CommonCfg.Channel == pAd->ChannelList[i].Channel) - break; - } - - if (i == pAd->ChannelListNum) - { -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - pAd->CommonCfg.Channel = FirstChannel(pAd); -#endif // CONFIG_STA_SUPPORT // - DBGPRINT(RT_DEBUG_ERROR, ("RTMPSetPhyMode: channel is out of range, use first channel=%d \n", pAd->CommonCfg.Channel)); - } - - NdisZeroMemory(pAd->CommonCfg.SupRate, MAX_LEN_OF_SUPPORTED_RATES); - NdisZeroMemory(pAd->CommonCfg.ExtRate, MAX_LEN_OF_SUPPORTED_RATES); - NdisZeroMemory(pAd->CommonCfg.DesireRate, MAX_LEN_OF_SUPPORTED_RATES); - switch (phymode) { - case PHY_11B: - pAd->CommonCfg.SupRate[0] = 0x82; // 1 mbps, in units of 0.5 Mbps, basic rate - pAd->CommonCfg.SupRate[1] = 0x84; // 2 mbps, in units of 0.5 Mbps, basic rate - pAd->CommonCfg.SupRate[2] = 0x8B; // 5.5 mbps, in units of 0.5 Mbps, basic rate - pAd->CommonCfg.SupRate[3] = 0x96; // 11 mbps, in units of 0.5 Mbps, basic rate - pAd->CommonCfg.SupRateLen = 4; - pAd->CommonCfg.ExtRateLen = 0; - pAd->CommonCfg.DesireRate[0] = 2; // 1 mbps, in units of 0.5 Mbps - pAd->CommonCfg.DesireRate[1] = 4; // 2 mbps, in units of 0.5 Mbps - pAd->CommonCfg.DesireRate[2] = 11; // 5.5 mbps, in units of 0.5 Mbps - pAd->CommonCfg.DesireRate[3] = 22; // 11 mbps, in units of 0.5 Mbps - //pAd->CommonCfg.HTPhyMode.field.MODE = MODE_CCK; // This MODE is only FYI. not use - break; - - case PHY_11G: - case PHY_11BG_MIXED: - case PHY_11ABG_MIXED: -#ifdef DOT11_N_SUPPORT - case PHY_11N_2_4G: - case PHY_11ABGN_MIXED: - case PHY_11BGN_MIXED: - case PHY_11GN_MIXED: -#endif // DOT11_N_SUPPORT // - pAd->CommonCfg.SupRate[0] = 0x82; // 1 mbps, in units of 0.5 Mbps, basic rate - pAd->CommonCfg.SupRate[1] = 0x84; // 2 mbps, in units of 0.5 Mbps, basic rate - pAd->CommonCfg.SupRate[2] = 0x8B; // 5.5 mbps, in units of 0.5 Mbps, basic rate - pAd->CommonCfg.SupRate[3] = 0x96; // 11 mbps, in units of 0.5 Mbps, basic rate - pAd->CommonCfg.SupRate[4] = 0x12; // 9 mbps, in units of 0.5 Mbps - pAd->CommonCfg.SupRate[5] = 0x24; // 18 mbps, in units of 0.5 Mbps - pAd->CommonCfg.SupRate[6] = 0x48; // 36 mbps, in units of 0.5 Mbps - pAd->CommonCfg.SupRate[7] = 0x6c; // 54 mbps, in units of 0.5 Mbps - pAd->CommonCfg.SupRateLen = 8; - pAd->CommonCfg.ExtRate[0] = 0x0C; // 6 mbps, in units of 0.5 Mbps - pAd->CommonCfg.ExtRate[1] = 0x18; // 12 mbps, in units of 0.5 Mbps - pAd->CommonCfg.ExtRate[2] = 0x30; // 24 mbps, in units of 0.5 Mbps - pAd->CommonCfg.ExtRate[3] = 0x60; // 48 mbps, in units of 0.5 Mbps - pAd->CommonCfg.ExtRateLen = 4; - pAd->CommonCfg.DesireRate[0] = 2; // 1 mbps, in units of 0.5 Mbps - pAd->CommonCfg.DesireRate[1] = 4; // 2 mbps, in units of 0.5 Mbps - pAd->CommonCfg.DesireRate[2] = 11; // 5.5 mbps, in units of 0.5 Mbps - pAd->CommonCfg.DesireRate[3] = 22; // 11 mbps, in units of 0.5 Mbps - pAd->CommonCfg.DesireRate[4] = 12; // 6 mbps, in units of 0.5 Mbps - pAd->CommonCfg.DesireRate[5] = 18; // 9 mbps, in units of 0.5 Mbps - pAd->CommonCfg.DesireRate[6] = 24; // 12 mbps, in units of 0.5 Mbps - pAd->CommonCfg.DesireRate[7] = 36; // 18 mbps, in units of 0.5 Mbps - pAd->CommonCfg.DesireRate[8] = 48; // 24 mbps, in units of 0.5 Mbps - pAd->CommonCfg.DesireRate[9] = 72; // 36 mbps, in units of 0.5 Mbps - pAd->CommonCfg.DesireRate[10] = 96; // 48 mbps, in units of 0.5 Mbps - pAd->CommonCfg.DesireRate[11] = 108; // 54 mbps, in units of 0.5 Mbps - break; - - case PHY_11A: -#ifdef DOT11_N_SUPPORT - case PHY_11AN_MIXED: - case PHY_11AGN_MIXED: - case PHY_11N_5G: -#endif // DOT11_N_SUPPORT // - pAd->CommonCfg.SupRate[0] = 0x8C; // 6 mbps, in units of 0.5 Mbps, basic rate - pAd->CommonCfg.SupRate[1] = 0x12; // 9 mbps, in units of 0.5 Mbps - pAd->CommonCfg.SupRate[2] = 0x98; // 12 mbps, in units of 0.5 Mbps, basic rate - pAd->CommonCfg.SupRate[3] = 0x24; // 18 mbps, in units of 0.5 Mbps - pAd->CommonCfg.SupRate[4] = 0xb0; // 24 mbps, in units of 0.5 Mbps, basic rate - pAd->CommonCfg.SupRate[5] = 0x48; // 36 mbps, in units of 0.5 Mbps - pAd->CommonCfg.SupRate[6] = 0x60; // 48 mbps, in units of 0.5 Mbps - pAd->CommonCfg.SupRate[7] = 0x6c; // 54 mbps, in units of 0.5 Mbps - pAd->CommonCfg.SupRateLen = 8; - pAd->CommonCfg.ExtRateLen = 0; - pAd->CommonCfg.DesireRate[0] = 12; // 6 mbps, in units of 0.5 Mbps - pAd->CommonCfg.DesireRate[1] = 18; // 9 mbps, in units of 0.5 Mbps - pAd->CommonCfg.DesireRate[2] = 24; // 12 mbps, in units of 0.5 Mbps - pAd->CommonCfg.DesireRate[3] = 36; // 18 mbps, in units of 0.5 Mbps - pAd->CommonCfg.DesireRate[4] = 48; // 24 mbps, in units of 0.5 Mbps - pAd->CommonCfg.DesireRate[5] = 72; // 36 mbps, in units of 0.5 Mbps - pAd->CommonCfg.DesireRate[6] = 96; // 48 mbps, in units of 0.5 Mbps - pAd->CommonCfg.DesireRate[7] = 108; // 54 mbps, in units of 0.5 Mbps - //pAd->CommonCfg.HTPhyMode.field.MODE = MODE_OFDM; // This MODE is only FYI. not use - break; - - default: - break; - } - - - pAd->CommonCfg.BandState = UNKNOWN_BAND; -} - - -#ifdef DOT11_N_SUPPORT -/* - ======================================================================== - Routine Description: - Caller ensures we has 802.11n support. - Calls at setting HT from AP/STASetinformation - - Arguments: - pAd - Pointer to our adapter - phymode - - - ======================================================================== -*/ -VOID RTMPSetHT( - IN PRTMP_ADAPTER pAd, - IN OID_SET_HT_PHYMODE *pHTPhyMode) -{ - //ULONG *pmcs; - UINT32 Value = 0; - UCHAR BBPValue = 0; - UCHAR BBP3Value = 0; - UCHAR RxStream = pAd->CommonCfg.RxStream; - - DBGPRINT(RT_DEBUG_TRACE, ("RTMPSetHT : HT_mode(%d), ExtOffset(%d), MCS(%d), BW(%d), STBC(%d), SHORTGI(%d)\n", - pHTPhyMode->HtMode, pHTPhyMode->ExtOffset, - pHTPhyMode->MCS, pHTPhyMode->BW, - pHTPhyMode->STBC, pHTPhyMode->SHORTGI)); - - // Don't zero supportedHyPhy structure. - RTMPZeroMemory(&pAd->CommonCfg.HtCapability, sizeof(pAd->CommonCfg.HtCapability)); - RTMPZeroMemory(&pAd->CommonCfg.AddHTInfo, sizeof(pAd->CommonCfg.AddHTInfo)); - RTMPZeroMemory(&pAd->CommonCfg.NewExtChanOffset, sizeof(pAd->CommonCfg.NewExtChanOffset)); - RTMPZeroMemory(&pAd->CommonCfg.DesiredHtPhy, sizeof(pAd->CommonCfg.DesiredHtPhy)); - - if (pAd->CommonCfg.bRdg) - { - pAd->CommonCfg.HtCapability.ExtHtCapInfo.PlusHTC = 1; - pAd->CommonCfg.HtCapability.ExtHtCapInfo.RDGSupport = 1; - } - else - { - pAd->CommonCfg.HtCapability.ExtHtCapInfo.PlusHTC = 0; - pAd->CommonCfg.HtCapability.ExtHtCapInfo.RDGSupport = 0; - } - - pAd->CommonCfg.HtCapability.HtCapParm.MaxRAmpduFactor = 3; - pAd->CommonCfg.DesiredHtPhy.MaxRAmpduFactor = 3; - - DBGPRINT(RT_DEBUG_TRACE, ("RTMPSetHT : RxBAWinLimit = %d\n", pAd->CommonCfg.BACapability.field.RxBAWinLimit)); - - // Mimo power save, A-MSDU size, - pAd->CommonCfg.DesiredHtPhy.AmsduEnable = (USHORT)pAd->CommonCfg.BACapability.field.AmsduEnable; - pAd->CommonCfg.DesiredHtPhy.AmsduSize = (UCHAR)pAd->CommonCfg.BACapability.field.AmsduSize; - pAd->CommonCfg.DesiredHtPhy.MimoPs = (UCHAR)pAd->CommonCfg.BACapability.field.MMPSmode; - pAd->CommonCfg.DesiredHtPhy.MpduDensity = (UCHAR)pAd->CommonCfg.BACapability.field.MpduDensity; - - pAd->CommonCfg.HtCapability.HtCapInfo.AMsduSize = (USHORT)pAd->CommonCfg.BACapability.field.AmsduSize; - pAd->CommonCfg.HtCapability.HtCapInfo.MimoPs = (USHORT)pAd->CommonCfg.BACapability.field.MMPSmode; - pAd->CommonCfg.HtCapability.HtCapParm.MpduDensity = (UCHAR)pAd->CommonCfg.BACapability.field.MpduDensity; - - DBGPRINT(RT_DEBUG_TRACE, ("RTMPSetHT : AMsduSize = %d, MimoPs = %d, MpduDensity = %d, MaxRAmpduFactor = %d\n", - pAd->CommonCfg.DesiredHtPhy.AmsduSize, - pAd->CommonCfg.DesiredHtPhy.MimoPs, - pAd->CommonCfg.DesiredHtPhy.MpduDensity, - pAd->CommonCfg.DesiredHtPhy.MaxRAmpduFactor)); - - if(pHTPhyMode->HtMode == HTMODE_GF) - { - pAd->CommonCfg.HtCapability.HtCapInfo.GF = 1; - pAd->CommonCfg.DesiredHtPhy.GF = 1; - } - else - pAd->CommonCfg.DesiredHtPhy.GF = 0; - - // Decide Rx MCSSet - switch (RxStream) - { - case 1: - pAd->CommonCfg.HtCapability.MCSSet[0] = 0xff; - pAd->CommonCfg.HtCapability.MCSSet[1] = 0x00; - break; - - case 2: - pAd->CommonCfg.HtCapability.MCSSet[0] = 0xff; - pAd->CommonCfg.HtCapability.MCSSet[1] = 0xff; - break; - - case 3: // 3*3 - pAd->CommonCfg.HtCapability.MCSSet[0] = 0xff; - pAd->CommonCfg.HtCapability.MCSSet[1] = 0xff; - pAd->CommonCfg.HtCapability.MCSSet[2] = 0xff; - break; - } - - if (pAd->CommonCfg.bForty_Mhz_Intolerant && (pAd->CommonCfg.Channel <= 14) && (pHTPhyMode->BW == BW_40) ) - { - pHTPhyMode->BW = BW_20; - pAd->CommonCfg.HtCapability.HtCapInfo.Forty_Mhz_Intolerant = 1; - } - - if(pHTPhyMode->BW == BW_40) - { - pAd->CommonCfg.HtCapability.MCSSet[4] = 0x1; // MCS 32 - pAd->CommonCfg.HtCapability.HtCapInfo.ChannelWidth = 1; - if (pAd->CommonCfg.Channel <= 14) - pAd->CommonCfg.HtCapability.HtCapInfo.CCKmodein40 = 1; - - pAd->CommonCfg.DesiredHtPhy.ChannelWidth = 1; - pAd->CommonCfg.AddHTInfo.AddHtInfo.RecomWidth = 1; - pAd->CommonCfg.AddHTInfo.AddHtInfo.ExtChanOffset = (pHTPhyMode->ExtOffset == EXTCHA_BELOW)? (EXTCHA_BELOW): EXTCHA_ABOVE; - // Set Regsiter for extension channel position. - RTMP_IO_READ32(pAd, TX_BAND_CFG, &Value); - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BBP3Value); - if ((pHTPhyMode->ExtOffset == EXTCHA_BELOW)) - { - Value |= 0x1; - BBP3Value |= (0x20); - RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Value); - } - else if ((pHTPhyMode->ExtOffset == EXTCHA_ABOVE)) - { - Value &= 0xfe; - BBP3Value &= (~0x20); - RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Value); - } - - // Turn on BBP 40MHz mode now only as AP . - // Sta can turn on BBP 40MHz after connection with 40MHz AP. Sta only broadcast 40MHz capability before connection. - if ((pAd->OpMode == OPMODE_AP) || INFRA_ON(pAd) || ADHOC_ON(pAd) - ) - { - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); - BBPValue &= (~0x18); - BBPValue |= 0x10; - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); - - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BBP3Value); - pAd->CommonCfg.BBPCurrentBW = BW_40; - } - } - else - { - pAd->CommonCfg.HtCapability.HtCapInfo.ChannelWidth = 0; - pAd->CommonCfg.DesiredHtPhy.ChannelWidth = 0; - pAd->CommonCfg.AddHTInfo.AddHtInfo.RecomWidth = 0; - pAd->CommonCfg.AddHTInfo.AddHtInfo.ExtChanOffset = EXTCHA_NONE; - pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel; - // Turn on BBP 20MHz mode by request here. - { - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); - BBPValue &= (~0x18); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); - pAd->CommonCfg.BBPCurrentBW = BW_20; - } - } - - if(pHTPhyMode->STBC == STBC_USE) - { - pAd->CommonCfg.HtCapability.HtCapInfo.TxSTBC = 1; - pAd->CommonCfg.DesiredHtPhy.TxSTBC = 1; - pAd->CommonCfg.HtCapability.HtCapInfo.RxSTBC = 1; - pAd->CommonCfg.DesiredHtPhy.RxSTBC = 1; - } - else - { - pAd->CommonCfg.DesiredHtPhy.TxSTBC = 0; - pAd->CommonCfg.DesiredHtPhy.RxSTBC = 0; - } - -#ifdef RT2870 - /* Frank recommend ,If not, Tx maybe block in high power. Rx has no problem*/ - if(IS_RT3070(pAd) && ((pAd->RfIcType == RFIC_3020) || (pAd->RfIcType == RFIC_2020))) - { - pAd->CommonCfg.HtCapability.HtCapInfo.TxSTBC = 0; - pAd->CommonCfg.DesiredHtPhy.TxSTBC = 0; - } -#endif // RT2870 // - - if(pHTPhyMode->SHORTGI == GI_400) - { - pAd->CommonCfg.HtCapability.HtCapInfo.ShortGIfor20 = 1; - pAd->CommonCfg.HtCapability.HtCapInfo.ShortGIfor40 = 1; - pAd->CommonCfg.DesiredHtPhy.ShortGIfor20 = 1; - pAd->CommonCfg.DesiredHtPhy.ShortGIfor40 = 1; - } - else - { - pAd->CommonCfg.HtCapability.HtCapInfo.ShortGIfor20 = 0; - pAd->CommonCfg.HtCapability.HtCapInfo.ShortGIfor40 = 0; - pAd->CommonCfg.DesiredHtPhy.ShortGIfor20 = 0; - pAd->CommonCfg.DesiredHtPhy.ShortGIfor40 = 0; - } - - // We support link adaptation for unsolicit MCS feedback, set to 2. - pAd->CommonCfg.HtCapability.ExtHtCapInfo.MCSFeedback = MCSFBK_NONE; //MCSFBK_UNSOLICIT; - pAd->CommonCfg.AddHTInfo.ControlChan = pAd->CommonCfg.Channel; - // 1, the extension channel above the control channel. - - // EDCA parameters used for AP's own transmission - if (pAd->CommonCfg.APEdcaParm.bValid == FALSE) - { - pAd->CommonCfg.APEdcaParm.bValid = TRUE; - pAd->CommonCfg.APEdcaParm.Aifsn[0] = 3; - pAd->CommonCfg.APEdcaParm.Aifsn[1] = 7; - pAd->CommonCfg.APEdcaParm.Aifsn[2] = 1; - pAd->CommonCfg.APEdcaParm.Aifsn[3] = 1; - - pAd->CommonCfg.APEdcaParm.Cwmin[0] = 4; - pAd->CommonCfg.APEdcaParm.Cwmin[1] = 4; - pAd->CommonCfg.APEdcaParm.Cwmin[2] = 3; - pAd->CommonCfg.APEdcaParm.Cwmin[3] = 2; - - pAd->CommonCfg.APEdcaParm.Cwmax[0] = 6; - pAd->CommonCfg.APEdcaParm.Cwmax[1] = 10; - pAd->CommonCfg.APEdcaParm.Cwmax[2] = 4; - pAd->CommonCfg.APEdcaParm.Cwmax[3] = 3; - - pAd->CommonCfg.APEdcaParm.Txop[0] = 0; - pAd->CommonCfg.APEdcaParm.Txop[1] = 0; - pAd->CommonCfg.APEdcaParm.Txop[2] = 94; - pAd->CommonCfg.APEdcaParm.Txop[3] = 47; - } - AsicSetEdcaParm(pAd, &pAd->CommonCfg.APEdcaParm); - - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - RTMPSetIndividualHT(pAd, 0); - } -#endif // CONFIG_STA_SUPPORT // - -} - -/* - ======================================================================== - Routine Description: - Caller ensures we has 802.11n support. - Calls at setting HT from AP/STASetinformation - - Arguments: - pAd - Pointer to our adapter - phymode - - - ======================================================================== -*/ -VOID RTMPSetIndividualHT( - IN PRTMP_ADAPTER pAd, - IN UCHAR apidx) -{ - PRT_HT_PHY_INFO pDesired_ht_phy = NULL; - UCHAR TxStream = pAd->CommonCfg.TxStream; - UCHAR DesiredMcs = MCS_AUTO; - - do - { - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - pDesired_ht_phy = &pAd->StaCfg.DesiredHtPhyInfo; - DesiredMcs = pAd->StaCfg.DesiredTransmitSetting.field.MCS; - //pAd->StaCfg.bAutoTxRateSwitch = (DesiredMcs == MCS_AUTO) ? TRUE : FALSE; - break; - } -#endif // CONFIG_STA_SUPPORT // - } while (FALSE); - - if (pDesired_ht_phy == NULL) - { - DBGPRINT(RT_DEBUG_ERROR, ("RTMPSetIndividualHT: invalid apidx(%d)\n", apidx)); - return; - } - RTMPZeroMemory(pDesired_ht_phy, sizeof(RT_HT_PHY_INFO)); - - DBGPRINT(RT_DEBUG_TRACE, ("RTMPSetIndividualHT : Desired MCS = %d\n", DesiredMcs)); - // Check the validity of MCS - if ((TxStream == 1) && ((DesiredMcs >= MCS_8) && (DesiredMcs <= MCS_15))) - { - DBGPRINT(RT_DEBUG_WARN, ("RTMPSetIndividualHT: MCS(%d) is invalid in 1S, reset it as MCS_7\n", DesiredMcs)); - DesiredMcs = MCS_7; - } - - if ((pAd->CommonCfg.DesiredHtPhy.ChannelWidth == BW_20) && (DesiredMcs == MCS_32)) - { - DBGPRINT(RT_DEBUG_WARN, ("RTMPSetIndividualHT: MCS_32 is only supported in 40-MHz, reset it as MCS_0\n")); - DesiredMcs = MCS_0; - } - - pDesired_ht_phy->bHtEnable = TRUE; - - // Decide desired Tx MCS - switch (TxStream) - { - case 1: - if (DesiredMcs == MCS_AUTO) - { - pDesired_ht_phy->MCSSet[0]= 0xff; - pDesired_ht_phy->MCSSet[1]= 0x00; - } - else if (DesiredMcs <= MCS_7) - { - pDesired_ht_phy->MCSSet[0]= 1<MCSSet[1]= 0x00; - } - break; - - case 2: - if (DesiredMcs == MCS_AUTO) - { - pDesired_ht_phy->MCSSet[0]= 0xff; - pDesired_ht_phy->MCSSet[1]= 0xff; - } - else if (DesiredMcs <= MCS_15) - { - ULONG mode; - - mode = DesiredMcs / 8; - if (mode < 2) - pDesired_ht_phy->MCSSet[mode] = (1 << (DesiredMcs - mode * 8)); - } - break; - - case 3: // 3*3 - if (DesiredMcs == MCS_AUTO) - { - /* MCS0 ~ MCS23, 3 bytes */ - pDesired_ht_phy->MCSSet[0]= 0xff; - pDesired_ht_phy->MCSSet[1]= 0xff; - pDesired_ht_phy->MCSSet[2]= 0xff; - } - else if (DesiredMcs <= MCS_23) - { - ULONG mode; - - mode = DesiredMcs / 8; - if (mode < 3) - pDesired_ht_phy->MCSSet[mode] = (1 << (DesiredMcs - mode * 8)); - } - break; - } - - if(pAd->CommonCfg.DesiredHtPhy.ChannelWidth == BW_40) - { - if (DesiredMcs == MCS_AUTO || DesiredMcs == MCS_32) - pDesired_ht_phy->MCSSet[4] = 0x1; - } - - // update HT Rate setting - if (pAd->OpMode == OPMODE_STA) - MlmeUpdateHtTxRates(pAd, BSS0); - else - MlmeUpdateHtTxRates(pAd, apidx); -} - - -/* - ======================================================================== - Routine Description: - Update HT IE from our capability. - - Arguments: - Send all HT IE in beacon/probe rsp/assoc rsp/action frame. - - - ======================================================================== -*/ -VOID RTMPUpdateHTIE( - IN RT_HT_CAPABILITY *pRtHt, - IN UCHAR *pMcsSet, - OUT HT_CAPABILITY_IE *pHtCapability, - OUT ADD_HT_INFO_IE *pAddHtInfo) -{ - RTMPZeroMemory(pHtCapability, sizeof(HT_CAPABILITY_IE)); - RTMPZeroMemory(pAddHtInfo, sizeof(ADD_HT_INFO_IE)); - - pHtCapability->HtCapInfo.ChannelWidth = pRtHt->ChannelWidth; - pHtCapability->HtCapInfo.MimoPs = pRtHt->MimoPs; - pHtCapability->HtCapInfo.GF = pRtHt->GF; - pHtCapability->HtCapInfo.ShortGIfor20 = pRtHt->ShortGIfor20; - pHtCapability->HtCapInfo.ShortGIfor40 = pRtHt->ShortGIfor40; - pHtCapability->HtCapInfo.TxSTBC = pRtHt->TxSTBC; - pHtCapability->HtCapInfo.RxSTBC = pRtHt->RxSTBC; - pHtCapability->HtCapInfo.AMsduSize = pRtHt->AmsduSize; - pHtCapability->HtCapParm.MaxRAmpduFactor = pRtHt->MaxRAmpduFactor; - pHtCapability->HtCapParm.MpduDensity = pRtHt->MpduDensity; - - pAddHtInfo->AddHtInfo.ExtChanOffset = pRtHt->ExtChanOffset ; - pAddHtInfo->AddHtInfo.RecomWidth = pRtHt->RecomWidth; - pAddHtInfo->AddHtInfo2.OperaionMode = pRtHt->OperaionMode; - pAddHtInfo->AddHtInfo2.NonGfPresent = pRtHt->NonGfPresent; - RTMPMoveMemory(pAddHtInfo->MCSSet, /*pRtHt->MCSSet*/pMcsSet, 4); // rt2860 only support MCS max=32, no need to copy all 16 uchar. - - DBGPRINT(RT_DEBUG_TRACE,("RTMPUpdateHTIE <== \n")); -} -#endif // DOT11_N_SUPPORT // - -/* - ======================================================================== - Description: - Add Client security information into ASIC WCID table and IVEIV table. - Return: - ======================================================================== -*/ -VOID RTMPAddWcidAttributeEntry( - IN PRTMP_ADAPTER pAd, - IN UCHAR BssIdx, - IN UCHAR KeyIdx, - IN UCHAR CipherAlg, - IN MAC_TABLE_ENTRY *pEntry) -{ - UINT32 WCIDAttri = 0; - USHORT offset; - UCHAR IVEIV = 0; - USHORT Wcid = 0; - - { -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - if (BssIdx > BSS0) - { - DBGPRINT(RT_DEBUG_ERROR, ("RTMPAddWcidAttributeEntry: The BSS-index(%d) is out of range for Infra link. \n", BssIdx)); - return; - } - - // 1. In ADHOC mode, the AID is wcid number. And NO mesh link exists. - // 2. In Infra mode, the AID:1 MUST be wcid of infra STA. - // the AID:2~ assign to mesh link entry. - if (pEntry && ADHOC_ON(pAd)) - Wcid = pEntry->Aid; - else if (pEntry && INFRA_ON(pAd)) - { -#ifdef QOS_DLS_SUPPORT - if (pEntry->ValidAsDls == TRUE) - Wcid = pEntry->Aid; - else -#endif // QOS_DLS_SUPPORT // - Wcid = BSSID_WCID; - } - else - Wcid = MCAST_WCID; - } -#endif // CONFIG_STA_SUPPORT // - } - - // Update WCID attribute table - offset = MAC_WCID_ATTRIBUTE_BASE + (Wcid * HW_WCID_ATTRI_SIZE); - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - if (pEntry && pEntry->ValidAsMesh) - WCIDAttri = (CipherAlg<<1) | PAIRWISEKEYTABLE; -#ifdef QOS_DLS_SUPPORT - else if ((pEntry) && (pEntry->ValidAsDls) && - ((CipherAlg == CIPHER_TKIP) || - (CipherAlg == CIPHER_TKIP_NO_MIC) || - (CipherAlg == CIPHER_AES) || - (CipherAlg == CIPHER_NONE))) - WCIDAttri = (CipherAlg<<1) | PAIRWISEKEYTABLE; -#endif // QOS_DLS_SUPPORT // - else - WCIDAttri = (CipherAlg<<1) | SHAREDKEYTABLE; - } -#endif // CONFIG_STA_SUPPORT // - - RTMP_IO_WRITE32(pAd, offset, WCIDAttri); - - - // Update IV/EIV table - offset = MAC_IVEIV_TABLE_BASE + (Wcid * HW_IVEIV_ENTRY_SIZE); - - // WPA mode - if ((CipherAlg == CIPHER_TKIP) || (CipherAlg == CIPHER_TKIP_NO_MIC) || (CipherAlg == CIPHER_AES)) - { - // Eiv bit on. keyid always is 0 for pairwise key - IVEIV = (KeyIdx <<6) | 0x20; - } - else - { - // WEP KeyIdx is default tx key. - IVEIV = (KeyIdx << 6); - } - - // For key index and ext IV bit, so only need to update the position(offset+3). -#ifdef RT2870 - RTUSBMultiWrite_OneByte(pAd, offset+3, &IVEIV); -#endif // RT2870 // - - DBGPRINT(RT_DEBUG_TRACE,("RTMPAddWcidAttributeEntry: WCID #%d, KeyIndex #%d, Alg=%s\n",Wcid, KeyIdx, CipherName[CipherAlg])); - DBGPRINT(RT_DEBUG_TRACE,(" WCIDAttri = 0x%x \n", WCIDAttri)); - -} - -/* - ========================================================================== - Description: - Parse encryption type -Arguments: - pAdapter Pointer to our adapter - wrq Pointer to the ioctl argument - - Return Value: - None - - Note: - ========================================================================== -*/ -CHAR *GetEncryptType(CHAR enc) -{ - if(enc == Ndis802_11WEPDisabled) - return "NONE"; - if(enc == Ndis802_11WEPEnabled) - return "WEP"; - if(enc == Ndis802_11Encryption2Enabled) - return "TKIP"; - if(enc == Ndis802_11Encryption3Enabled) - return "AES"; - if(enc == Ndis802_11Encryption4Enabled) - return "TKIPAES"; - else - return "UNKNOW"; -} - -CHAR *GetAuthMode(CHAR auth) -{ - if(auth == Ndis802_11AuthModeOpen) - return "OPEN"; - if(auth == Ndis802_11AuthModeShared) - return "SHARED"; - if(auth == Ndis802_11AuthModeAutoSwitch) - return "AUTOWEP"; - if(auth == Ndis802_11AuthModeWPA) - return "WPA"; - if(auth == Ndis802_11AuthModeWPAPSK) - return "WPAPSK"; - if(auth == Ndis802_11AuthModeWPANone) - return "WPANONE"; - if(auth == Ndis802_11AuthModeWPA2) - return "WPA2"; - if(auth == Ndis802_11AuthModeWPA2PSK) - return "WPA2PSK"; - if(auth == Ndis802_11AuthModeWPA1WPA2) - return "WPA1WPA2"; - if(auth == Ndis802_11AuthModeWPA1PSKWPA2PSK) - return "WPA1PSKWPA2PSK"; - - return "UNKNOW"; -} - -#if 1 //#ifndef UCOS -/* - ========================================================================== - Description: - Get site survey results - Arguments: - pAdapter Pointer to our adapter - wrq Pointer to the ioctl argument - - Return Value: - None - - Note: - Usage: - 1.) UI needs to wait 4 seconds after issue a site survey command - 2.) iwpriv ra0 get_site_survey - 3.) UI needs to prepare at least 4096bytes to get the results - ========================================================================== -*/ -#define LINE_LEN (4+33+20+8+10+9+7+3) // Channel+SSID+Bssid+WepStatus+AuthMode+Signal+WiressMode+NetworkType -VOID RTMPIoctlGetSiteSurvey( - IN PRTMP_ADAPTER pAdapter, - IN struct iwreq *wrq) -{ - CHAR *msg; - INT i=0; - INT WaitCnt; - INT Status=0; - CHAR Ssid[MAX_LEN_OF_SSID +1]; - INT Rssi = 0, max_len = LINE_LEN; - UINT Rssi_Quality = 0; - NDIS_802_11_NETWORK_TYPE wireless_mode; - - os_alloc_mem(NULL, (PUCHAR *)&msg, sizeof(CHAR)*((MAX_LEN_OF_BSS_TABLE)*max_len)); - - if (msg == NULL) - { - DBGPRINT(RT_DEBUG_TRACE, ("RTMPIoctlGetSiteSurvey - msg memory alloc fail.\n")); - return; - } - - memset(msg, 0 ,(MAX_LEN_OF_BSS_TABLE)*max_len ); - memset(Ssid, 0 ,(MAX_LEN_OF_SSID +1)); - sprintf(msg,"%s","\n"); - sprintf(msg+strlen(msg),"%-4s%-33s%-20s%-8s%-10s%-9s%-7s%-3s\n", - "Ch", "SSID", "BSSID", "Enc", "Auth", "Siganl(%)", "W-Mode", " NT"); - - - WaitCnt = 0; -#ifdef CONFIG_STA_SUPPORT - pAdapter->StaCfg.bScanReqIsFromWebUI = TRUE; - while ((ScanRunning(pAdapter) == TRUE) && (WaitCnt++ < 200)) - OS_WAIT(500); -#endif // CONFIG_STA_SUPPORT // - - for(i=0; iScanTab.BssNr ;i++) - { - if( pAdapter->ScanTab.BssEntry[i].Channel==0) - break; - - if((strlen(msg)+max_len ) >= IW_SCAN_MAX_DATA) - break; - - //Channel - sprintf(msg+strlen(msg),"%-4d", pAdapter->ScanTab.BssEntry[i].Channel); - //SSID - memcpy(Ssid, pAdapter->ScanTab.BssEntry[i].Ssid, pAdapter->ScanTab.BssEntry[i].SsidLen); - Ssid[pAdapter->ScanTab.BssEntry[i].SsidLen] = '\0'; - sprintf(msg+strlen(msg),"%-33s", Ssid); - //BSSID - sprintf(msg+strlen(msg),"%02x:%02x:%02x:%02x:%02x:%02x ", - pAdapter->ScanTab.BssEntry[i].Bssid[0], - pAdapter->ScanTab.BssEntry[i].Bssid[1], - pAdapter->ScanTab.BssEntry[i].Bssid[2], - pAdapter->ScanTab.BssEntry[i].Bssid[3], - pAdapter->ScanTab.BssEntry[i].Bssid[4], - pAdapter->ScanTab.BssEntry[i].Bssid[5]); - //Encryption Type - sprintf(msg+strlen(msg),"%-8s",GetEncryptType(pAdapter->ScanTab.BssEntry[i].WepStatus)); - //Authentication Mode - if (pAdapter->ScanTab.BssEntry[i].WepStatus == Ndis802_11WEPEnabled) - sprintf(msg+strlen(msg),"%-10s", "UNKNOW"); - else - sprintf(msg+strlen(msg),"%-10s",GetAuthMode(pAdapter->ScanTab.BssEntry[i].AuthMode)); - // Rssi - Rssi = (INT)pAdapter->ScanTab.BssEntry[i].Rssi; - if (Rssi >= -50) - Rssi_Quality = 100; - else if (Rssi >= -80) // between -50 ~ -80dbm - Rssi_Quality = (UINT)(24 + ((Rssi + 80) * 26)/10); - else if (Rssi >= -90) // between -80 ~ -90dbm - Rssi_Quality = (UINT)(((Rssi + 90) * 26)/10); - else // < -84 dbm - Rssi_Quality = 0; - sprintf(msg+strlen(msg),"%-9d", Rssi_Quality); - // Wireless Mode - wireless_mode = NetworkTypeInUseSanity(&pAdapter->ScanTab.BssEntry[i]); - if (wireless_mode == Ndis802_11FH || - wireless_mode == Ndis802_11DS) - sprintf(msg+strlen(msg),"%-7s", "11b"); - else if (wireless_mode == Ndis802_11OFDM5) - sprintf(msg+strlen(msg),"%-7s", "11a"); - else if (wireless_mode == Ndis802_11OFDM5_N) - sprintf(msg+strlen(msg),"%-7s", "11a/n"); - else if (wireless_mode == Ndis802_11OFDM24) - sprintf(msg+strlen(msg),"%-7s", "11b/g"); - else if (wireless_mode == Ndis802_11OFDM24_N) - sprintf(msg+strlen(msg),"%-7s", "11b/g/n"); - else - sprintf(msg+strlen(msg),"%-7s", "unknow"); - //Network Type - if (pAdapter->ScanTab.BssEntry[i].BssType == BSS_ADHOC) - sprintf(msg+strlen(msg),"%-3s", " Ad"); - else - sprintf(msg+strlen(msg),"%-3s", " In"); - - sprintf(msg+strlen(msg),"\n"); - } - -#ifdef CONFIG_STA_SUPPORT - pAdapter->StaCfg.bScanReqIsFromWebUI = FALSE; -#endif // CONFIG_STA_SUPPORT // - wrq->u.data.length = strlen(msg); - Status = copy_to_user(wrq->u.data.pointer, msg, wrq->u.data.length); - - DBGPRINT(RT_DEBUG_TRACE, ("RTMPIoctlGetSiteSurvey - wrq->u.data.length = %d\n", wrq->u.data.length)); - os_free_mem(NULL, (PUCHAR)msg); -} - - -#define MAC_LINE_LEN (14+4+4+10+10+10+6+6) // Addr+aid+psm+datatime+rxbyte+txbyte+current tx rate+last tx rate -VOID RTMPIoctlGetMacTable( - IN PRTMP_ADAPTER pAd, - IN struct iwreq *wrq) -{ - INT i; - RT_802_11_MAC_TABLE MacTab; - char *msg; - - MacTab.Num = 0; - for (i=0; iMacTab.Content[i].ValidAsCLI && (pAd->MacTab.Content[i].Sst == SST_ASSOC)) - { - COPY_MAC_ADDR(MacTab.Entry[MacTab.Num].Addr, &pAd->MacTab.Content[i].Addr); - MacTab.Entry[MacTab.Num].Aid = (UCHAR)pAd->MacTab.Content[i].Aid; - MacTab.Entry[MacTab.Num].Psm = pAd->MacTab.Content[i].PsMode; -#ifdef DOT11_N_SUPPORT - MacTab.Entry[MacTab.Num].MimoPs = pAd->MacTab.Content[i].MmpsMode; -#endif // DOT11_N_SUPPORT // - - // Fill in RSSI per entry - MacTab.Entry[MacTab.Num].AvgRssi0 = pAd->MacTab.Content[i].RssiSample.AvgRssi0; - MacTab.Entry[MacTab.Num].AvgRssi1 = pAd->MacTab.Content[i].RssiSample.AvgRssi1; - MacTab.Entry[MacTab.Num].AvgRssi2 = pAd->MacTab.Content[i].RssiSample.AvgRssi2; - - // the connected time per entry - MacTab.Entry[MacTab.Num].ConnectedTime = pAd->MacTab.Content[i].StaConnectTime; -#if 0 // ToDo - MacTab.Entry[MacTab.Num].HSCounter.LastDataPacketTime = pAd->MacTab.Content[i].HSCounter.LastDataPacketTime; - MacTab.Entry[MacTab.Num].HSCounter.TotalRxByteCount = pAd->MacTab.Content[i].HSCounter.TotalRxByteCount; - MacTab.Entry[MacTab.Num].HSCounter.TotalTxByteCount = pAd->MacTab.Content[i].HSCounter.TotalTxByteCount; -#endif - MacTab.Entry[MacTab.Num].TxRate.field.MCS = pAd->MacTab.Content[i].HTPhyMode.field.MCS; - MacTab.Entry[MacTab.Num].TxRate.field.BW = pAd->MacTab.Content[i].HTPhyMode.field.BW; - MacTab.Entry[MacTab.Num].TxRate.field.ShortGI = pAd->MacTab.Content[i].HTPhyMode.field.ShortGI; - MacTab.Entry[MacTab.Num].TxRate.field.STBC = pAd->MacTab.Content[i].HTPhyMode.field.STBC; - MacTab.Entry[MacTab.Num].TxRate.field.rsv = pAd->MacTab.Content[i].HTPhyMode.field.rsv; - MacTab.Entry[MacTab.Num].TxRate.field.MODE = pAd->MacTab.Content[i].HTPhyMode.field.MODE; - MacTab.Entry[MacTab.Num].TxRate.word = pAd->MacTab.Content[i].HTPhyMode.word; - - MacTab.Num += 1; - } - } - wrq->u.data.length = sizeof(RT_802_11_MAC_TABLE); - if (copy_to_user(wrq->u.data.pointer, &MacTab, wrq->u.data.length)) - { - DBGPRINT(RT_DEBUG_TRACE, ("%s: copy_to_user() fail\n", __func__)); - } - - msg = (CHAR *) kmalloc(sizeof(CHAR)*(MAX_LEN_OF_MAC_TABLE*MAC_LINE_LEN), MEM_ALLOC_FLAG); - memset(msg, 0 ,MAX_LEN_OF_MAC_TABLE*MAC_LINE_LEN ); - sprintf(msg,"%s","\n"); - sprintf(msg+strlen(msg),"%-14s%-4s%-4s%-10s%-10s%-10s%-6s%-6s\n", - "MAC", "AID", "PSM", "LDT", "RxB", "TxB","CTxR", "LTxR"); - - for (i=0; iMacTab.Content[i]; - if (pEntry->ValidAsCLI && (pEntry->Sst == SST_ASSOC)) - { - if((strlen(msg)+MAC_LINE_LEN ) >= (MAX_LEN_OF_MAC_TABLE*MAC_LINE_LEN) ) - break; - sprintf(msg+strlen(msg),"%02x%02x%02x%02x%02x%02x ", - pEntry->Addr[0], pEntry->Addr[1], pEntry->Addr[2], - pEntry->Addr[3], pEntry->Addr[4], pEntry->Addr[5]); - sprintf(msg+strlen(msg),"%-4d", (int)pEntry->Aid); - sprintf(msg+strlen(msg),"%-4d", (int)pEntry->PsMode); - sprintf(msg+strlen(msg),"%-10d",0/*pAd->MacTab.Content[i].HSCounter.LastDataPacketTime*/); // ToDo - sprintf(msg+strlen(msg),"%-10d",0/*pAd->MacTab.Content[i].HSCounter.TotalRxByteCount*/); // ToDo - sprintf(msg+strlen(msg),"%-10d",0/*pAd->MacTab.Content[i].HSCounter.TotalTxByteCount*/); // ToDo - sprintf(msg+strlen(msg),"%-6d",RateIdToMbps[pAd->MacTab.Content[i].CurrTxRate]); - sprintf(msg+strlen(msg),"%-6d\n",0/*RateIdToMbps[pAd->MacTab.Content[i].LastTxRate]*/); // ToDo - } - } - // for compatible with old API just do the printk to console - //wrq->u.data.length = strlen(msg); - //if (copy_to_user(wrq->u.data.pointer, msg, wrq->u.data.length)) - { - DBGPRINT(RT_DEBUG_TRACE, ("%s", msg)); - } - - kfree(msg); -} -#endif // UCOS // - -#ifdef DOT11_N_SUPPORT -INT Set_BASetup_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - UCHAR mac[6], tid; - char *token, sepValue[] = ":", DASH = '-'; - INT i; - MAC_TABLE_ENTRY *pEntry; - -/* - The BASetup inupt string format should be xx:xx:xx:xx:xx:xx-d, - =>The six 2 digit hex-decimal number previous are the Mac address, - =>The seventh decimal number is the tid value. -*/ - //printk("\n%s\n", arg); - - if(strlen(arg) < 19) //Mac address acceptable format 01:02:03:04:05:06 length 17 plus the "-" and tid value in decimal format. - return FALSE; - - token = strchr(arg, DASH); - if ((token != NULL) && (strlen(token)>1)) - { - tid = simple_strtol((token+1), 0, 10); - if (tid > 15) - return FALSE; - - *token = '\0'; - for (i = 0, token = rstrtok(arg, &sepValue[0]); token; token = rstrtok(NULL, &sepValue[0]), i++) - { - if((strlen(token) != 2) || (!isxdigit(*token)) || (!isxdigit(*(token+1)))) - return FALSE; - AtoH(token, (PUCHAR)(&mac[i]), 1); - } - if(i != 6) - return FALSE; - - printk("\n%02x:%02x:%02x:%02x:%02x:%02x-%02x\n", mac[0], mac[1], - mac[2], mac[3], mac[4], mac[5], tid); - - pEntry = MacTableLookup(pAd, mac); - - if (pEntry) { - printk("\nSetup BA Session: Tid = %d\n", tid); - BAOriSessionSetUp(pAd, pEntry, tid, 0, 100, TRUE); - } - - return TRUE; - } - - return FALSE; - -} - -INT Set_BADecline_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ULONG bBADecline; - - bBADecline = simple_strtol(arg, 0, 10); - - if (bBADecline == 0) - { - pAd->CommonCfg.bBADecline = FALSE; - } - else if (bBADecline == 1) - { - pAd->CommonCfg.bBADecline = TRUE; - } - else - { - return FALSE; //Invalid argument - } - - DBGPRINT(RT_DEBUG_TRACE, ("Set_BADecline_Proc::(BADecline=%d)\n", pAd->CommonCfg.bBADecline)); - - return TRUE; -} - -INT Set_BAOriTearDown_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - UCHAR mac[6], tid; - char *token, sepValue[] = ":", DASH = '-'; - INT i; - MAC_TABLE_ENTRY *pEntry; - - //printk("\n%s\n", arg); -/* - The BAOriTearDown inupt string format should be xx:xx:xx:xx:xx:xx-d, - =>The six 2 digit hex-decimal number previous are the Mac address, - =>The seventh decimal number is the tid value. -*/ - if(strlen(arg) < 19) //Mac address acceptable format 01:02:03:04:05:06 length 17 plus the "-" and tid value in decimal format. - return FALSE; - - token = strchr(arg, DASH); - if ((token != NULL) && (strlen(token)>1)) - { - tid = simple_strtol((token+1), 0, 10); - if (tid > NUM_OF_TID) - return FALSE; - - *token = '\0'; - for (i = 0, token = rstrtok(arg, &sepValue[0]); token; token = rstrtok(NULL, &sepValue[0]), i++) - { - if((strlen(token) != 2) || (!isxdigit(*token)) || (!isxdigit(*(token+1)))) - return FALSE; - AtoH(token, (PUCHAR)(&mac[i]), 1); - } - if(i != 6) - return FALSE; - - printk("\n%02x:%02x:%02x:%02x:%02x:%02x-%02x", mac[0], mac[1], - mac[2], mac[3], mac[4], mac[5], tid); - - pEntry = MacTableLookup(pAd, mac); - - if (pEntry) { - printk("\nTear down Ori BA Session: Tid = %d\n", tid); - BAOriSessionTearDown(pAd, pEntry->Aid, tid, FALSE, TRUE); - } - - return TRUE; - } - - return FALSE; - -} - -INT Set_BARecTearDown_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - UCHAR mac[6], tid; - char *token, sepValue[] = ":", DASH = '-'; - INT i; - MAC_TABLE_ENTRY *pEntry; - - //printk("\n%s\n", arg); -/* - The BARecTearDown inupt string format should be xx:xx:xx:xx:xx:xx-d, - =>The six 2 digit hex-decimal number previous are the Mac address, - =>The seventh decimal number is the tid value. -*/ - if(strlen(arg) < 19) //Mac address acceptable format 01:02:03:04:05:06 length 17 plus the "-" and tid value in decimal format. - return FALSE; - - token = strchr(arg, DASH); - if ((token != NULL) && (strlen(token)>1)) - { - tid = simple_strtol((token+1), 0, 10); - if (tid > NUM_OF_TID) - return FALSE; - - *token = '\0'; - for (i = 0, token = rstrtok(arg, &sepValue[0]); token; token = rstrtok(NULL, &sepValue[0]), i++) - { - if((strlen(token) != 2) || (!isxdigit(*token)) || (!isxdigit(*(token+1)))) - return FALSE; - AtoH(token, (PUCHAR)(&mac[i]), 1); - } - if(i != 6) - return FALSE; - - printk("\n%02x:%02x:%02x:%02x:%02x:%02x-%02x", mac[0], mac[1], - mac[2], mac[3], mac[4], mac[5], tid); - - pEntry = MacTableLookup(pAd, mac); - - if (pEntry) { - printk("\nTear down Rec BA Session: Tid = %d\n", tid); - BARecSessionTearDown(pAd, pEntry->Aid, tid, FALSE); - } - - return TRUE; - } - - return FALSE; - -} - -INT Set_HtBw_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ULONG HtBw; - - HtBw = simple_strtol(arg, 0, 10); - if (HtBw == BW_40) - pAd->CommonCfg.RegTransmitSetting.field.BW = BW_40; - else if (HtBw == BW_20) - pAd->CommonCfg.RegTransmitSetting.field.BW = BW_20; - else - return FALSE; //Invalid argument - - SetCommonHT(pAd); - - DBGPRINT(RT_DEBUG_TRACE, ("Set_HtBw_Proc::(HtBw=%d)\n", pAd->CommonCfg.RegTransmitSetting.field.BW)); - - return TRUE; -} - -INT Set_HtMcs_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ULONG HtMcs, Mcs_tmp; -#ifdef CONFIG_STA_SUPPORT - BOOLEAN bAutoRate = FALSE; -#endif // CONFIG_STA_SUPPORT // - - Mcs_tmp = simple_strtol(arg, 0, 10); - - if (Mcs_tmp <= 15 || Mcs_tmp == 32) - HtMcs = Mcs_tmp; - else - HtMcs = MCS_AUTO; - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - pAd->StaCfg.DesiredTransmitSetting.field.MCS = HtMcs; - pAd->StaCfg.bAutoTxRateSwitch = (HtMcs == MCS_AUTO) ? TRUE:FALSE; - DBGPRINT(RT_DEBUG_TRACE, ("Set_HtMcs_Proc::(HtMcs=%d, bAutoTxRateSwitch = %d)\n", - pAd->StaCfg.DesiredTransmitSetting.field.MCS, pAd->StaCfg.bAutoTxRateSwitch)); - - if ((pAd->CommonCfg.PhyMode < PHY_11ABGN_MIXED) || - (pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MODE < MODE_HTMIX)) - { - if ((pAd->StaCfg.DesiredTransmitSetting.field.MCS != MCS_AUTO) && - (HtMcs >= 0 && HtMcs <= 3) && - (pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode == FIXED_TXMODE_CCK)) - { - RTMPSetDesiredRates(pAd, (LONG) (RateIdToMbps[HtMcs] * 1000000)); - } - else if ((pAd->StaCfg.DesiredTransmitSetting.field.MCS != MCS_AUTO) && - (HtMcs >= 0 && HtMcs <= 7) && - (pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode == FIXED_TXMODE_OFDM)) - { - RTMPSetDesiredRates(pAd, (LONG) (RateIdToMbps[HtMcs+4] * 1000000)); - } - else - bAutoRate = TRUE; - - if (bAutoRate) - { - pAd->StaCfg.DesiredTransmitSetting.field.MCS = MCS_AUTO; - RTMPSetDesiredRates(pAd, -1); - } - DBGPRINT(RT_DEBUG_TRACE, ("Set_HtMcs_Proc::(FixedTxMode=%d)\n",pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode)); - } - if (ADHOC_ON(pAd)) - return TRUE; - } -#endif // CONFIG_STA_SUPPORT // - - SetCommonHT(pAd); - - return TRUE; -} - -INT Set_HtGi_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ULONG HtGi; - - HtGi = simple_strtol(arg, 0, 10); - - if ( HtGi == GI_400) - pAd->CommonCfg.RegTransmitSetting.field.ShortGI = GI_400; - else if ( HtGi == GI_800 ) - pAd->CommonCfg.RegTransmitSetting.field.ShortGI = GI_800; - else - return FALSE; //Invalid argument - - SetCommonHT(pAd); - - DBGPRINT(RT_DEBUG_TRACE, ("Set_HtGi_Proc::(ShortGI=%d)\n",pAd->CommonCfg.RegTransmitSetting.field.ShortGI)); - - return TRUE; -} - - -INT Set_HtTxBASize_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - UCHAR Size; - - Size = simple_strtol(arg, 0, 10); - - if (Size <=0 || Size >=64) - { - Size = 8; - } - pAd->CommonCfg.TxBASize = Size-1; - DBGPRINT(RT_DEBUG_ERROR, ("Set_HtTxBASize ::(TxBASize= %d)\n", Size)); - - return TRUE; -} - - -INT Set_HtOpMode_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - - ULONG Value; - - Value = simple_strtol(arg, 0, 10); - - if (Value == HTMODE_GF) - pAd->CommonCfg.RegTransmitSetting.field.HTMODE = HTMODE_GF; - else if ( Value == HTMODE_MM ) - pAd->CommonCfg.RegTransmitSetting.field.HTMODE = HTMODE_MM; - else - return FALSE; //Invalid argument - - SetCommonHT(pAd); - - DBGPRINT(RT_DEBUG_TRACE, ("Set_HtOpMode_Proc::(HtOpMode=%d)\n",pAd->CommonCfg.RegTransmitSetting.field.HTMODE)); - - return TRUE; - -} - -INT Set_HtStbc_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - - ULONG Value; - - Value = simple_strtol(arg, 0, 10); - - if (Value == STBC_USE) - pAd->CommonCfg.RegTransmitSetting.field.STBC = STBC_USE; - else if ( Value == STBC_NONE ) - pAd->CommonCfg.RegTransmitSetting.field.STBC = STBC_NONE; - else - return FALSE; //Invalid argument - - SetCommonHT(pAd); - - DBGPRINT(RT_DEBUG_TRACE, ("Set_Stbc_Proc::(HtStbc=%d)\n",pAd->CommonCfg.RegTransmitSetting.field.STBC)); - - return TRUE; -} - -INT Set_HtHtc_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - - ULONG Value; - - Value = simple_strtol(arg, 0, 10); - if (Value == 0) - pAd->HTCEnable = FALSE; - else if ( Value ==1 ) - pAd->HTCEnable = TRUE; - else - return FALSE; //Invalid argument - - DBGPRINT(RT_DEBUG_TRACE, ("Set_HtHtc_Proc::(HtHtc=%d)\n",pAd->HTCEnable)); - - return TRUE; -} - -INT Set_HtExtcha_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - - ULONG Value; - - Value = simple_strtol(arg, 0, 10); - - if (Value == 0) - pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_BELOW; - else if ( Value ==1 ) - pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_ABOVE; - else - return FALSE; //Invalid argument - - SetCommonHT(pAd); - - DBGPRINT(RT_DEBUG_TRACE, ("Set_HtExtcha_Proc::(HtExtcha=%d)\n",pAd->CommonCfg.RegTransmitSetting.field.EXTCHA)); - - return TRUE; -} - -INT Set_HtMpduDensity_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ULONG Value; - - Value = simple_strtol(arg, 0, 10); - - if (Value <=7 && Value >= 0) - pAd->CommonCfg.BACapability.field.MpduDensity = Value; - else - pAd->CommonCfg.BACapability.field.MpduDensity = 4; - - SetCommonHT(pAd); - - DBGPRINT(RT_DEBUG_TRACE, ("Set_HtMpduDensity_Proc::(HtMpduDensity=%d)\n",pAd->CommonCfg.BACapability.field.MpduDensity)); - - return TRUE; -} - -INT Set_HtBaWinSize_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ULONG Value; - - Value = simple_strtol(arg, 0, 10); - - - if (Value >=1 && Value <= 64) - { - pAd->CommonCfg.REGBACapability.field.RxBAWinLimit = Value; - pAd->CommonCfg.BACapability.field.RxBAWinLimit = Value; - } - else - { - pAd->CommonCfg.REGBACapability.field.RxBAWinLimit = 64; - pAd->CommonCfg.BACapability.field.RxBAWinLimit = 64; - } - - SetCommonHT(pAd); - - DBGPRINT(RT_DEBUG_TRACE, ("Set_HtBaWinSize_Proc::(HtBaWinSize=%d)\n",pAd->CommonCfg.BACapability.field.RxBAWinLimit)); - - return TRUE; -} - -INT Set_HtRdg_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ULONG Value; - - Value = simple_strtol(arg, 0, 10); - - if (Value == 0) - pAd->CommonCfg.bRdg = FALSE; - else if ( Value ==1 ) - { - pAd->HTCEnable = TRUE; - pAd->CommonCfg.bRdg = TRUE; - } - else - return FALSE; //Invalid argument - - SetCommonHT(pAd); - - DBGPRINT(RT_DEBUG_TRACE, ("Set_HtRdg_Proc::(HtRdg=%d)\n",pAd->CommonCfg.bRdg)); - - return TRUE; -} - -INT Set_HtLinkAdapt_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ULONG Value; - - Value = simple_strtol(arg, 0, 10); - if (Value == 0) - pAd->bLinkAdapt = FALSE; - else if ( Value ==1 ) - { - pAd->HTCEnable = TRUE; - pAd->bLinkAdapt = TRUE; - } - else - return FALSE; //Invalid argument - - DBGPRINT(RT_DEBUG_TRACE, ("Set_HtLinkAdapt_Proc::(HtLinkAdapt=%d)\n",pAd->bLinkAdapt)); - - return TRUE; -} - -INT Set_HtAmsdu_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ULONG Value; - - Value = simple_strtol(arg, 0, 10); - if (Value == 0) - pAd->CommonCfg.BACapability.field.AmsduEnable = FALSE; - else if ( Value == 1 ) - pAd->CommonCfg.BACapability.field.AmsduEnable = TRUE; - else - return FALSE; //Invalid argument - - SetCommonHT(pAd); - - DBGPRINT(RT_DEBUG_TRACE, ("Set_HtAmsdu_Proc::(HtAmsdu=%d)\n",pAd->CommonCfg.BACapability.field.AmsduEnable)); - - return TRUE; -} - -INT Set_HtAutoBa_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ULONG Value; - - Value = simple_strtol(arg, 0, 10); - if (Value == 0) - pAd->CommonCfg.BACapability.field.AutoBA = FALSE; - else if (Value == 1) - pAd->CommonCfg.BACapability.field.AutoBA = TRUE; - else - return FALSE; //Invalid argument - - pAd->CommonCfg.REGBACapability.field.AutoBA = pAd->CommonCfg.BACapability.field.AutoBA; - SetCommonHT(pAd); - - DBGPRINT(RT_DEBUG_TRACE, ("Set_HtAutoBa_Proc::(HtAutoBa=%d)\n",pAd->CommonCfg.BACapability.field.AutoBA)); - - return TRUE; - -} - -INT Set_HtProtect_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ULONG Value; - - Value = simple_strtol(arg, 0, 10); - if (Value == 0) - pAd->CommonCfg.bHTProtect = FALSE; - else if (Value == 1) - pAd->CommonCfg.bHTProtect = TRUE; - else - return FALSE; //Invalid argument - - DBGPRINT(RT_DEBUG_TRACE, ("Set_HtProtect_Proc::(HtProtect=%d)\n",pAd->CommonCfg.bHTProtect)); - - return TRUE; -} - -INT Set_SendPSMPAction_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - UCHAR mac[6], mode; - char *token, sepValue[] = ":", DASH = '-'; - INT i; - MAC_TABLE_ENTRY *pEntry; - - //printk("\n%s\n", arg); -/* - The BARecTearDown inupt string format should be xx:xx:xx:xx:xx:xx-d, - =>The six 2 digit hex-decimal number previous are the Mac address, - =>The seventh decimal number is the mode value. -*/ - if(strlen(arg) < 19) //Mac address acceptable format 01:02:03:04:05:06 length 17 plus the "-" and mode value in decimal format. - return FALSE; - - token = strchr(arg, DASH); - if ((token != NULL) && (strlen(token)>1)) - { - mode = simple_strtol((token+1), 0, 10); - if (mode > MMPS_ENABLE) - return FALSE; - - *token = '\0'; - for (i = 0, token = rstrtok(arg, &sepValue[0]); token; token = rstrtok(NULL, &sepValue[0]), i++) - { - if((strlen(token) != 2) || (!isxdigit(*token)) || (!isxdigit(*(token+1)))) - return FALSE; - AtoH(token, (PUCHAR)(&mac[i]), 1); - } - if(i != 6) - return FALSE; - - printk("\n%02x:%02x:%02x:%02x:%02x:%02x-%02x", mac[0], mac[1], - mac[2], mac[3], mac[4], mac[5], mode); - - pEntry = MacTableLookup(pAd, mac); - - if (pEntry) { - printk("\nSendPSMPAction MIPS mode = %d\n", mode); - SendPSMPAction(pAd, pEntry->Aid, mode); - } - - return TRUE; - } - - return FALSE; - - -} - -INT Set_HtMIMOPSmode_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ULONG Value; - - Value = simple_strtol(arg, 0, 10); - - if (Value <=3 && Value >= 0) - pAd->CommonCfg.BACapability.field.MMPSmode = Value; - else - pAd->CommonCfg.BACapability.field.MMPSmode = 3; - - SetCommonHT(pAd); - - DBGPRINT(RT_DEBUG_TRACE, ("Set_HtMIMOPSmode_Proc::(MIMOPS mode=%d)\n",pAd->CommonCfg.BACapability.field.MMPSmode)); - - return TRUE; -} - - -INT Set_ForceShortGI_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ULONG Value; - - Value = simple_strtol(arg, 0, 10); - if (Value == 0) - pAd->WIFItestbed.bShortGI = FALSE; - else if (Value == 1) - pAd->WIFItestbed.bShortGI = TRUE; - else - return FALSE; //Invalid argument - - SetCommonHT(pAd); - - DBGPRINT(RT_DEBUG_TRACE, ("Set_ForceShortGI_Proc::(ForceShortGI=%d)\n", pAd->WIFItestbed.bShortGI)); - - return TRUE; -} - - - -INT Set_ForceGF_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ULONG Value; - - Value = simple_strtol(arg, 0, 10); - if (Value == 0) - pAd->WIFItestbed.bGreenField = FALSE; - else if (Value == 1) - pAd->WIFItestbed.bGreenField = TRUE; - else - return FALSE; //Invalid argument - - SetCommonHT(pAd); - - DBGPRINT(RT_DEBUG_TRACE, ("Set_ForceGF_Proc::(ForceGF=%d)\n", pAd->WIFItestbed.bGreenField)); - - return TRUE; -} - -INT Set_HtMimoPs_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ULONG Value; - - Value = simple_strtol(arg, 0, 10); - if (Value == 0) - pAd->CommonCfg.bMIMOPSEnable = FALSE; - else if (Value == 1) - pAd->CommonCfg.bMIMOPSEnable = TRUE; - else - return FALSE; //Invalid argument - - DBGPRINT(RT_DEBUG_TRACE, ("Set_HtMimoPs_Proc::(HtMimoPs=%d)\n",pAd->CommonCfg.bMIMOPSEnable)); - - return TRUE; -} -#endif // DOT11_N_SUPPORT // - - -#ifdef DOT11_N_SUPPORT -INT SetCommonHT( - IN PRTMP_ADAPTER pAd) -{ - OID_SET_HT_PHYMODE SetHT; - - if (pAd->CommonCfg.PhyMode < PHY_11ABGN_MIXED) - return FALSE; - - SetHT.PhyMode = pAd->CommonCfg.PhyMode; - SetHT.TransmitNo = ((UCHAR)pAd->Antenna.field.TxPath); - SetHT.HtMode = (UCHAR)pAd->CommonCfg.RegTransmitSetting.field.HTMODE; - SetHT.ExtOffset = (UCHAR)pAd->CommonCfg.RegTransmitSetting.field.EXTCHA; - SetHT.MCS = MCS_AUTO; - SetHT.BW = (UCHAR)pAd->CommonCfg.RegTransmitSetting.field.BW; - SetHT.STBC = (UCHAR)pAd->CommonCfg.RegTransmitSetting.field.STBC; - SetHT.SHORTGI = (UCHAR)pAd->CommonCfg.RegTransmitSetting.field.ShortGI; - - RTMPSetHT(pAd, &SetHT); - - return TRUE; -} -#endif // DOT11_N_SUPPORT // - -INT Set_FixedTxMode_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - UCHAR fix_tx_mode = FIXED_TXMODE_HT; - - if (strcmp(arg, "OFDM") == 0 || strcmp(arg, "ofdm") == 0) - { - fix_tx_mode = FIXED_TXMODE_OFDM; - } - else if (strcmp(arg, "CCK") == 0 || strcmp(arg, "cck") == 0) - { - fix_tx_mode = FIXED_TXMODE_CCK; - } - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode = fix_tx_mode; -#endif // CONFIG_STA_SUPPORT // - - DBGPRINT(RT_DEBUG_TRACE, ("Set_FixedTxMode_Proc::(FixedTxMode=%d)\n", fix_tx_mode)); - - return TRUE; -} - -#ifdef CONFIG_APSTA_MIXED_SUPPORT -INT Set_OpMode_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ULONG Value; - - Value = simple_strtol(arg, 0, 10); - -#ifdef RT2870 - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_START_UP)) -#endif // RT2870 // - { - DBGPRINT(RT_DEBUG_ERROR, ("Can not switch operate mode on interface up !! \n")); - return FALSE; - } - - if (Value == 0) - pAd->OpMode = OPMODE_STA; - else if (Value == 1) - pAd->OpMode = OPMODE_AP; - else - return FALSE; //Invalid argument - - DBGPRINT(RT_DEBUG_TRACE, ("Set_OpMode_Proc::(OpMode=%s)\n", pAd->OpMode == 1 ? "AP Mode" : "STA Mode")); - - return TRUE; -} -#endif // CONFIG_APSTA_MIXED_SUPPORT // - - -///////////////////////////////////////////////////////////////////////// -PCHAR RTMPGetRalinkAuthModeStr( - IN NDIS_802_11_AUTHENTICATION_MODE authMode) -{ - switch(authMode) - { - case Ndis802_11AuthModeOpen: - return "OPEN"; - case Ndis802_11AuthModeWPAPSK: - return "WPAPSK"; - case Ndis802_11AuthModeShared: - return "SHARED"; - case Ndis802_11AuthModeWPA: - return "WPA"; - case Ndis802_11AuthModeWPA2: - return "WPA2"; - case Ndis802_11AuthModeWPA2PSK: - return "WPA2PSK"; - case Ndis802_11AuthModeWPA1PSKWPA2PSK: - return "WPAPSKWPA2PSK"; - case Ndis802_11AuthModeWPA1WPA2: - return "WPA1WPA2"; - case Ndis802_11AuthModeWPANone: - return "WPANONE"; - default: - return "UNKNOW"; - } -} - -PCHAR RTMPGetRalinkEncryModeStr( - IN USHORT encryMode) -{ - switch(encryMode) - { - case Ndis802_11WEPDisabled: - return "NONE"; - case Ndis802_11WEPEnabled: - return "WEP"; - case Ndis802_11Encryption2Enabled: - return "TKIP"; - case Ndis802_11Encryption3Enabled: - return "AES"; - case Ndis802_11Encryption4Enabled: - return "TKIPAES"; - default: - return "UNKNOW"; - } -} - -INT RTMPShowCfgValue( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pName, - IN PUCHAR pBuf) -{ - INT Status = 0; - - for (PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC = RTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC; PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC->name; PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC++) - { - if (!strcmp(pName, PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC->name)) - { - if(PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC->show_proc(pAd, pBuf)) - Status = -EINVAL; - break; //Exit for loop. - } - } - - if(PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC->name == NULL) - { - sprintf(pBuf, "\n"); - for (PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC = RTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC; PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC->name; PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC++) - sprintf(pBuf, "%s%s\n", pBuf, PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC->name); - } - - return Status; -} - -INT Show_SSID_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - sprintf(pBuf, "\t%s", pAd->CommonCfg.Ssid); -#endif // CONFIG_STA_SUPPORT // - return 0; -} - -INT Show_WirelessMode_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - switch(pAd->CommonCfg.PhyMode) - { - case PHY_11BG_MIXED: - sprintf(pBuf, "\t11B/G"); - break; - case PHY_11B: - sprintf(pBuf, "\t11B"); - break; - case PHY_11A: - sprintf(pBuf, "\t11A"); - break; - case PHY_11ABG_MIXED: - sprintf(pBuf, "\t11A/B/G"); - break; - case PHY_11G: - sprintf(pBuf, "\t11G"); - break; -#ifdef DOT11_N_SUPPORT - case PHY_11ABGN_MIXED: - sprintf(pBuf, "\t11A/B/G/N"); - break; - case PHY_11N_2_4G: - sprintf(pBuf, "\t11N only with 2.4G"); - break; - case PHY_11GN_MIXED: - sprintf(pBuf, "\t11G/N"); - break; - case PHY_11AN_MIXED: - sprintf(pBuf, "\t11A/N"); - break; - case PHY_11BGN_MIXED: - sprintf(pBuf, "\t11B/G/N"); - break; - case PHY_11AGN_MIXED: - sprintf(pBuf, "\t11A/G/N"); - break; - case PHY_11N_5G: - sprintf(pBuf, "\t11N only with 5G"); - break; -#endif // DOT11_N_SUPPORT // - default: - sprintf(pBuf, "\tUnknow Value(%d)", pAd->CommonCfg.PhyMode); - break; - } - return 0; -} - - -INT Show_TxBurst_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - sprintf(pBuf, "\t%s", pAd->CommonCfg.bEnableTxBurst ? "TRUE":"FALSE"); - return 0; -} - -INT Show_TxPreamble_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - switch(pAd->CommonCfg.TxPreamble) - { - case Rt802_11PreambleShort: - sprintf(pBuf, "\tShort"); - break; - case Rt802_11PreambleLong: - sprintf(pBuf, "\tLong"); - break; - case Rt802_11PreambleAuto: - sprintf(pBuf, "\tAuto"); - break; - default: - sprintf(pBuf, "\tUnknow Value(%lu)", pAd->CommonCfg.TxPreamble); - break; - } - - return 0; -} - -INT Show_TxPower_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - sprintf(pBuf, "\t%lu", pAd->CommonCfg.TxPowerPercentage); - return 0; -} - -INT Show_Channel_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - sprintf(pBuf, "\t%d", pAd->CommonCfg.Channel); - return 0; -} - -INT Show_BGProtection_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - switch(pAd->CommonCfg.UseBGProtection) - { - case 1: //Always On - sprintf(pBuf, "\tON"); - break; - case 2: //Always OFF - sprintf(pBuf, "\tOFF"); - break; - case 0: //AUTO - sprintf(pBuf, "\tAuto"); - break; - default: - sprintf(pBuf, "\tUnknow Value(%lu)", pAd->CommonCfg.UseBGProtection); - break; - } - return 0; -} - -INT Show_RTSThreshold_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - sprintf(pBuf, "\t%u", pAd->CommonCfg.RtsThreshold); - return 0; -} - -INT Show_FragThreshold_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - sprintf(pBuf, "\t%u", pAd->CommonCfg.FragmentThreshold); - return 0; -} - -#ifdef DOT11_N_SUPPORT -INT Show_HtBw_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - if (pAd->CommonCfg.RegTransmitSetting.field.BW == BW_40) - { - sprintf(pBuf, "\t40 MHz"); - } - else - { - sprintf(pBuf, "\t20 MHz"); - } - return 0; -} - -INT Show_HtMcs_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - sprintf(pBuf, "\t%u", pAd->StaCfg.DesiredTransmitSetting.field.MCS); -#endif // CONFIG_STA_SUPPORT // - return 0; -} - -INT Show_HtGi_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - switch(pAd->CommonCfg.RegTransmitSetting.field.ShortGI) - { - case GI_400: - sprintf(pBuf, "\tGI_400"); - break; - case GI_800: - sprintf(pBuf, "\tGI_800"); - break; - default: - sprintf(pBuf, "\tUnknow Value(%u)", pAd->CommonCfg.RegTransmitSetting.field.ShortGI); - break; - } - return 0; -} - -INT Show_HtOpMode_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - switch(pAd->CommonCfg.RegTransmitSetting.field.HTMODE) - { - case HTMODE_GF: - sprintf(pBuf, "\tGF"); - break; - case HTMODE_MM: - sprintf(pBuf, "\tMM"); - break; - default: - sprintf(pBuf, "\tUnknow Value(%u)", pAd->CommonCfg.RegTransmitSetting.field.HTMODE); - break; - } - return 0; -} - -INT Show_HtExtcha_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - switch(pAd->CommonCfg.RegTransmitSetting.field.EXTCHA) - { - case EXTCHA_BELOW: - sprintf(pBuf, "\tBelow"); - break; - case EXTCHA_ABOVE: - sprintf(pBuf, "\tAbove"); - break; - default: - sprintf(pBuf, "\tUnknow Value(%u)", pAd->CommonCfg.RegTransmitSetting.field.EXTCHA); - break; - } - return 0; -} - - -INT Show_HtMpduDensity_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - sprintf(pBuf, "\t%u", pAd->CommonCfg.BACapability.field.MpduDensity); - return 0; -} - -INT Show_HtBaWinSize_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - sprintf(pBuf, "\t%u", pAd->CommonCfg.BACapability.field.RxBAWinLimit); - return 0; -} - -INT Show_HtRdg_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - sprintf(pBuf, "\t%s", pAd->CommonCfg.bRdg ? "TRUE":"FALSE"); - return 0; -} - -INT Show_HtAmsdu_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - sprintf(pBuf, "\t%s", pAd->CommonCfg.BACapability.field.AmsduEnable ? "TRUE":"FALSE"); - return 0; -} - -INT Show_HtAutoBa_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - sprintf(pBuf, "\t%s", pAd->CommonCfg.BACapability.field.AutoBA ? "TRUE":"FALSE"); - return 0; -} -#endif // DOT11_N_SUPPORT // - -INT Show_CountryRegion_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - sprintf(pBuf, "\t%d", pAd->CommonCfg.CountryRegion); - return 0; -} - -INT Show_CountryRegionABand_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - sprintf(pBuf, "\t%d", pAd->CommonCfg.CountryRegionForABand); - return 0; -} - -INT Show_CountryCode_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - sprintf(pBuf, "\t%s", pAd->CommonCfg.CountryCode); - return 0; -} - -#ifdef AGGREGATION_SUPPORT -INT Show_PktAggregate_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - sprintf(pBuf, "\t%s", pAd->CommonCfg.bAggregationCapable ? "TRUE":"FALSE"); - return 0; -} -#endif // AGGREGATION_SUPPORT // - -#ifdef WMM_SUPPORT -INT Show_WmmCapable_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - sprintf(pBuf, "\t%s", pAd->CommonCfg.bWmmCapable ? "TRUE":"FALSE"); -#endif // CONFIG_STA_SUPPORT // - - return 0; -} -#endif // WMM_SUPPORT // - -INT Show_IEEE80211H_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - sprintf(pBuf, "\t%s", pAd->CommonCfg.bIEEE80211H ? "TRUE":"FALSE"); - return 0; -} - -#ifdef CONFIG_STA_SUPPORT -INT Show_NetworkType_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - switch(pAd->StaCfg.BssType) - { - case BSS_ADHOC: - sprintf(pBuf, "\tAdhoc"); - break; - case BSS_INFRA: - sprintf(pBuf, "\tInfra"); - break; - case BSS_ANY: - sprintf(pBuf, "\tAny"); - break; - case BSS_MONITOR: - sprintf(pBuf, "\tMonitor"); - break; - default: - sprintf(pBuf, "\tUnknow Value(%d)", pAd->StaCfg.BssType); - break; - } - return 0; -} -#endif // CONFIG_STA_SUPPORT // - -INT Show_AuthMode_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - NDIS_802_11_AUTHENTICATION_MODE AuthMode = Ndis802_11AuthModeOpen; - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - AuthMode = pAd->StaCfg.AuthMode; -#endif // CONFIG_STA_SUPPORT // - - if ((AuthMode >= Ndis802_11AuthModeOpen) && - (AuthMode <= Ndis802_11AuthModeWPA1PSKWPA2PSK)) - sprintf(pBuf, "\t%s", RTMPGetRalinkAuthModeStr(AuthMode)); - else - sprintf(pBuf, "\tUnknow Value(%d)", AuthMode); - - return 0; -} - -INT Show_EncrypType_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - NDIS_802_11_WEP_STATUS WepStatus = Ndis802_11WEPDisabled; - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - WepStatus = pAd->StaCfg.WepStatus; -#endif // CONFIG_STA_SUPPORT // - - if ((WepStatus >= Ndis802_11WEPEnabled) && - (WepStatus <= Ndis802_11Encryption4KeyAbsent)) - sprintf(pBuf, "\t%s", RTMPGetRalinkEncryModeStr(WepStatus)); - else - sprintf(pBuf, "\tUnknow Value(%d)", WepStatus); - - return 0; -} - -INT Show_DefaultKeyID_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - UCHAR DefaultKeyId = 0; - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - DefaultKeyId = pAd->StaCfg.DefaultKeyId; -#endif // CONFIG_STA_SUPPORT // - - sprintf(pBuf, "\t%d", DefaultKeyId); - - return 0; -} - -INT Show_WepKey_Proc( - IN PRTMP_ADAPTER pAd, - IN INT KeyIdx, - OUT PUCHAR pBuf) -{ - UCHAR Key[16] = {0}, KeyLength = 0; - INT index = BSS0; - - KeyLength = pAd->SharedKey[index][KeyIdx].KeyLen; - NdisMoveMemory(Key, pAd->SharedKey[index][KeyIdx].Key, KeyLength); - - //check key string is ASCII or not - if (RTMPCheckStrPrintAble(Key, KeyLength)) - sprintf(pBuf, "\t%s", Key); - else - { - int idx; - sprintf(pBuf, "\t"); - for (idx = 0; idx < KeyLength; idx++) - sprintf(pBuf+strlen(pBuf), "%02X", Key[idx]); - } - return 0; -} - -INT Show_Key1_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - Show_WepKey_Proc(pAd, 0, pBuf); - return 0; -} - -INT Show_Key2_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - Show_WepKey_Proc(pAd, 1, pBuf); - return 0; -} - -INT Show_Key3_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - Show_WepKey_Proc(pAd, 2, pBuf); - return 0; -} - -INT Show_Key4_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - Show_WepKey_Proc(pAd, 3, pBuf); - return 0; -} - -INT Show_WPAPSK_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - INT idx; - UCHAR PMK[32] = {0}; - - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - NdisMoveMemory(PMK, pAd->StaCfg.PMK, 32); -#endif // CONFIG_STA_SUPPORT // - - sprintf(pBuf, "\tPMK = "); - for (idx = 0; idx < 32; idx++) - sprintf(pBuf+strlen(pBuf), "%02X", PMK[idx]); - - return 0; -} - +#include "../../rt2860/common/cmm_info.c" diff --git a/drivers/staging/rt2870/common/cmm_sanity.c b/drivers/staging/rt2870/common/cmm_sanity.c index 1e24320177bc..cb3352118c57 100644 --- a/drivers/staging/rt2870/common/cmm_sanity.c +++ b/drivers/staging/rt2870/common/cmm_sanity.c @@ -1,1663 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - sanity.c - - Abstract: - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - John Chang 2004-09-01 add WMM support -*/ -#include "../rt_config.h" - - -extern UCHAR CISCO_OUI[]; - -extern UCHAR WPA_OUI[]; -extern UCHAR RSN_OUI[]; -extern UCHAR WME_INFO_ELEM[]; -extern UCHAR WME_PARM_ELEM[]; -extern UCHAR Ccx2QosInfo[]; -extern UCHAR RALINK_OUI[]; -extern UCHAR BROADCOM_OUI[]; -extern UCHAR WPS_OUI[]; - -/* - ========================================================================== - Description: - MLME message sanity check - Return: - TRUE if all parameters are OK, FALSE otherwise - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -BOOLEAN MlmeAddBAReqSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PUCHAR pAddr2) -{ - PMLME_ADDBA_REQ_STRUCT pInfo; - - pInfo = (MLME_ADDBA_REQ_STRUCT *)Msg; - - if ((MsgLen != sizeof(MLME_ADDBA_REQ_STRUCT))) - { - DBGPRINT(RT_DEBUG_TRACE, ("MlmeAddBAReqSanity fail - message lenght not correct.\n")); - return FALSE; - } - - if ((pInfo->Wcid >= MAX_LEN_OF_MAC_TABLE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("MlmeAddBAReqSanity fail - The peer Mac is not associated yet.\n")); - return FALSE; - } - - /* - if ((pInfo->BaBufSize > MAX_RX_REORDERBUF) || (pInfo->BaBufSize < 2)) - { - DBGPRINT(RT_DEBUG_TRACE, ("MlmeAddBAReqSanity fail - Rx Reordering buffer too big or too small\n")); - return FALSE; - } - */ - - if ((pInfo->pAddr[0]&0x01) == 0x01) - { - DBGPRINT(RT_DEBUG_TRACE, ("MlmeAddBAReqSanity fail - broadcast address not support BA\n")); - return FALSE; - } - - return TRUE; -} - -/* - ========================================================================== - Description: - MLME message sanity check - Return: - TRUE if all parameters are OK, FALSE otherwise - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -BOOLEAN MlmeDelBAReqSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen) -{ - MLME_DELBA_REQ_STRUCT *pInfo; - pInfo = (MLME_DELBA_REQ_STRUCT *)Msg; - - if ((MsgLen != sizeof(MLME_DELBA_REQ_STRUCT))) - { - DBGPRINT(RT_DEBUG_ERROR, ("MlmeDelBAReqSanity fail - message lenght not correct.\n")); - return FALSE; - } - - if ((pInfo->Wcid >= MAX_LEN_OF_MAC_TABLE)) - { - DBGPRINT(RT_DEBUG_ERROR, ("MlmeDelBAReqSanity fail - The peer Mac is not associated yet.\n")); - return FALSE; - } - - if ((pInfo->TID & 0xf0)) - { - DBGPRINT(RT_DEBUG_ERROR, ("MlmeDelBAReqSanity fail - The peer TID is incorrect.\n")); - return FALSE; - } - - if (NdisEqualMemory(pAd->MacTab.Content[pInfo->Wcid].Addr, pInfo->Addr, MAC_ADDR_LEN) == 0) - { - DBGPRINT(RT_DEBUG_ERROR, ("MlmeDelBAReqSanity fail - the peer addr dosen't exist.\n")); - return FALSE; - } - - return TRUE; -} - -BOOLEAN PeerAddBAReqActionSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *pMsg, - IN ULONG MsgLen, - OUT PUCHAR pAddr2) -{ - PFRAME_802_11 pFrame = (PFRAME_802_11)pMsg; - PFRAME_ADDBA_REQ pAddFrame; - pAddFrame = (PFRAME_ADDBA_REQ)(pMsg); - if (MsgLen < (sizeof(FRAME_ADDBA_REQ))) - { - DBGPRINT(RT_DEBUG_ERROR,("PeerAddBAReqActionSanity: ADDBA Request frame length size = %ld incorrect\n", MsgLen)); - return FALSE; - } - // we support immediate BA. - *(USHORT *)(&pAddFrame->BaParm) = cpu2le16(*(USHORT *)(&pAddFrame->BaParm)); - pAddFrame->TimeOutValue = cpu2le16(pAddFrame->TimeOutValue); - pAddFrame->BaStartSeq.word = cpu2le16(pAddFrame->BaStartSeq.word); - - if (pAddFrame->BaParm.BAPolicy != IMMED_BA) - { - DBGPRINT(RT_DEBUG_ERROR,("PeerAddBAReqActionSanity: ADDBA Request Ba Policy[%d] not support\n", pAddFrame->BaParm.BAPolicy)); - DBGPRINT(RT_DEBUG_ERROR,("ADDBA Request. tid=%x, Bufsize=%x, AMSDUSupported=%x \n", pAddFrame->BaParm.TID, pAddFrame->BaParm.BufSize, pAddFrame->BaParm.AMSDUSupported)); - return FALSE; - } - - // we support immediate BA. - if (pAddFrame->BaParm.TID &0xfff0) - { - DBGPRINT(RT_DEBUG_ERROR,("PeerAddBAReqActionSanity: ADDBA Request incorrect TID = %d\n", pAddFrame->BaParm.TID)); - return FALSE; - } - COPY_MAC_ADDR(pAddr2, pFrame->Hdr.Addr2); - return TRUE; -} - -BOOLEAN PeerAddBARspActionSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *pMsg, - IN ULONG MsgLen) -{ - //PFRAME_802_11 pFrame = (PFRAME_802_11)pMsg; - PFRAME_ADDBA_RSP pAddFrame; - - pAddFrame = (PFRAME_ADDBA_RSP)(pMsg); - if (MsgLen < (sizeof(FRAME_ADDBA_RSP))) - { - DBGPRINT(RT_DEBUG_ERROR,("PeerAddBARspActionSanity: ADDBA Response frame length size = %ld incorrect\n", MsgLen)); - return FALSE; - } - // we support immediate BA. - *(USHORT *)(&pAddFrame->BaParm) = cpu2le16(*(USHORT *)(&pAddFrame->BaParm)); - pAddFrame->StatusCode = cpu2le16(pAddFrame->StatusCode); - pAddFrame->TimeOutValue = cpu2le16(pAddFrame->TimeOutValue); - - if (pAddFrame->BaParm.BAPolicy != IMMED_BA) - { - DBGPRINT(RT_DEBUG_ERROR,("PeerAddBAReqActionSanity: ADDBA Response Ba Policy[%d] not support\n", pAddFrame->BaParm.BAPolicy)); - return FALSE; - } - - // we support immediate BA. - if (pAddFrame->BaParm.TID &0xfff0) - { - DBGPRINT(RT_DEBUG_ERROR,("PeerAddBARspActionSanity: ADDBA Response incorrect TID = %d\n", pAddFrame->BaParm.TID)); - return FALSE; - } - return TRUE; - -} - -BOOLEAN PeerDelBAActionSanity( - IN PRTMP_ADAPTER pAd, - IN UCHAR Wcid, - IN VOID *pMsg, - IN ULONG MsgLen ) -{ - //PFRAME_802_11 pFrame = (PFRAME_802_11)pMsg; - PFRAME_DELBA_REQ pDelFrame; - if (MsgLen != (sizeof(FRAME_DELBA_REQ))) - return FALSE; - - if (Wcid >= MAX_LEN_OF_MAC_TABLE) - return FALSE; - - pDelFrame = (PFRAME_DELBA_REQ)(pMsg); - - *(USHORT *)(&pDelFrame->DelbaParm) = cpu2le16(*(USHORT *)(&pDelFrame->DelbaParm)); - pDelFrame->ReasonCode = cpu2le16(pDelFrame->ReasonCode); - - if (pDelFrame->DelbaParm.TID &0xfff0) - return FALSE; - - return TRUE; -} - -/* - ========================================================================== - Description: - MLME message sanity check - Return: - TRUE if all parameters are OK, FALSE otherwise - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -BOOLEAN PeerBeaconAndProbeRspSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - IN UCHAR MsgChannel, - OUT PUCHAR pAddr2, - OUT PUCHAR pBssid, - OUT CHAR Ssid[], - OUT UCHAR *pSsidLen, - OUT UCHAR *pBssType, - OUT USHORT *pBeaconPeriod, - OUT UCHAR *pChannel, - OUT UCHAR *pNewChannel, - OUT LARGE_INTEGER *pTimestamp, - OUT CF_PARM *pCfParm, - OUT USHORT *pAtimWin, - OUT USHORT *pCapabilityInfo, - OUT UCHAR *pErp, - OUT UCHAR *pDtimCount, - OUT UCHAR *pDtimPeriod, - OUT UCHAR *pBcastFlag, - OUT UCHAR *pMessageToMe, - OUT UCHAR SupRate[], - OUT UCHAR *pSupRateLen, - OUT UCHAR ExtRate[], - OUT UCHAR *pExtRateLen, - OUT UCHAR *pCkipFlag, - OUT UCHAR *pAironetCellPowerLimit, - OUT PEDCA_PARM pEdcaParm, - OUT PQBSS_LOAD_PARM pQbssLoad, - OUT PQOS_CAPABILITY_PARM pQosCapability, - OUT ULONG *pRalinkIe, - OUT UCHAR *pHtCapabilityLen, -#ifdef CONFIG_STA_SUPPORT - OUT UCHAR *pPreNHtCapabilityLen, -#endif // CONFIG_STA_SUPPORT // - OUT HT_CAPABILITY_IE *pHtCapability, - OUT UCHAR *AddHtInfoLen, - OUT ADD_HT_INFO_IE *AddHtInfo, - OUT UCHAR *NewExtChannelOffset, // Ht extension channel offset(above or below) - OUT USHORT *LengthVIE, - OUT PNDIS_802_11_VARIABLE_IEs pVIE) -{ - CHAR *Ptr; -#ifdef CONFIG_STA_SUPPORT - CHAR TimLen; -#endif // CONFIG_STA_SUPPORT // - PFRAME_802_11 pFrame; - PEID_STRUCT pEid; - UCHAR SubType; - UCHAR Sanity; - //UCHAR ECWMin, ECWMax; - //MAC_CSR9_STRUC Csr9; - ULONG Length = 0; - - // For some 11a AP which didn't have DS_IE, we use two conditions to decide the channel - // 1. If the AP is 11n enabled, then check the control channel. - // 2. If the AP didn't have any info about channel, use the channel we received this frame as the channel. (May inaccuracy!!) - UCHAR CtrlChannel = 0; - - // Add for 3 necessary EID field check - Sanity = 0; - - *pAtimWin = 0; - *pErp = 0; - *pDtimCount = 0; - *pDtimPeriod = 0; - *pBcastFlag = 0; - *pMessageToMe = 0; - *pExtRateLen = 0; - *pCkipFlag = 0; // Default of CkipFlag is 0 - *pAironetCellPowerLimit = 0xFF; // Default of AironetCellPowerLimit is 0xFF - *LengthVIE = 0; // Set the length of VIE to init value 0 - *pHtCapabilityLen = 0; // Set the length of VIE to init value 0 -#ifdef CONFIG_STA_SUPPORT - if (pAd->OpMode == OPMODE_STA) - *pPreNHtCapabilityLen = 0; // Set the length of VIE to init value 0 -#endif // CONFIG_STA_SUPPORT // - *AddHtInfoLen = 0; // Set the length of VIE to init value 0 - *pRalinkIe = 0; - *pNewChannel = 0; - *NewExtChannelOffset = 0xff; //Default 0xff means no such IE - pCfParm->bValid = FALSE; // default: no IE_CF found - pQbssLoad->bValid = FALSE; // default: no IE_QBSS_LOAD found - pEdcaParm->bValid = FALSE; // default: no IE_EDCA_PARAMETER found - pQosCapability->bValid = FALSE; // default: no IE_QOS_CAPABILITY found - - pFrame = (PFRAME_802_11)Msg; - - // get subtype from header - SubType = (UCHAR)pFrame->Hdr.FC.SubType; - - // get Addr2 and BSSID from header - COPY_MAC_ADDR(pAddr2, pFrame->Hdr.Addr2); - COPY_MAC_ADDR(pBssid, pFrame->Hdr.Addr3); - -// hex_dump("Beacon", Msg, MsgLen); - - Ptr = pFrame->Octet; - Length += LENGTH_802_11; - - // get timestamp from payload and advance the pointer - NdisMoveMemory(pTimestamp, Ptr, TIMESTAMP_LEN); - - pTimestamp->u.LowPart = cpu2le32(pTimestamp->u.LowPart); - pTimestamp->u.HighPart = cpu2le32(pTimestamp->u.HighPart); - - Ptr += TIMESTAMP_LEN; - Length += TIMESTAMP_LEN; - - // get beacon interval from payload and advance the pointer - NdisMoveMemory(pBeaconPeriod, Ptr, 2); - Ptr += 2; - Length += 2; - - // get capability info from payload and advance the pointer - NdisMoveMemory(pCapabilityInfo, Ptr, 2); - Ptr += 2; - Length += 2; - - if (CAP_IS_ESS_ON(*pCapabilityInfo)) - *pBssType = BSS_INFRA; - else - *pBssType = BSS_ADHOC; - - pEid = (PEID_STRUCT) Ptr; - - // get variable fields from payload and advance the pointer - while ((Length + 2 + pEid->Len) <= MsgLen) - { - // - // Secure copy VIE to VarIE[MAX_VIE_LEN] didn't overflow. - // - if ((*LengthVIE + pEid->Len + 2) >= MAX_VIE_LEN) - { - DBGPRINT(RT_DEBUG_WARN, ("PeerBeaconAndProbeRspSanity - Variable IEs out of resource [len(=%d) > MAX_VIE_LEN(=%d)]\n", - (*LengthVIE + pEid->Len + 2), MAX_VIE_LEN)); - break; - } - - switch(pEid->Eid) - { - case IE_SSID: - // Already has one SSID EID in this beacon, ignore the second one - if (Sanity & 0x1) - break; - if(pEid->Len <= MAX_LEN_OF_SSID) - { - NdisMoveMemory(Ssid, pEid->Octet, pEid->Len); - *pSsidLen = pEid->Len; - Sanity |= 0x1; - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("PeerBeaconAndProbeRspSanity - wrong IE_SSID (len=%d)\n",pEid->Len)); - return FALSE; - } - break; - - case IE_SUPP_RATES: - if(pEid->Len <= MAX_LEN_OF_SUPPORTED_RATES) - { - Sanity |= 0x2; - NdisMoveMemory(SupRate, pEid->Octet, pEid->Len); - *pSupRateLen = pEid->Len; - - // TODO: 2004-09-14 not a good design here, cause it exclude extra rates - // from ScanTab. We should report as is. And filter out unsupported - // rates in MlmeAux. - // Check against the supported rates - // RTMPCheckRates(pAd, SupRate, pSupRateLen); - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("PeerBeaconAndProbeRspSanity - wrong IE_SUPP_RATES (len=%d)\n",pEid->Len)); - return FALSE; - } - break; - - case IE_HT_CAP: - if (pEid->Len >= SIZE_HT_CAP_IE) //Note: allow extension.!! - { - NdisMoveMemory(pHtCapability, pEid->Octet, sizeof(HT_CAPABILITY_IE)); - *pHtCapabilityLen = SIZE_HT_CAP_IE; // Nnow we only support 26 bytes. - - *(USHORT *)(&pHtCapability->HtCapInfo) = cpu2le16(*(USHORT *)(&pHtCapability->HtCapInfo)); - *(USHORT *)(&pHtCapability->ExtHtCapInfo) = cpu2le16(*(USHORT *)(&pHtCapability->ExtHtCapInfo)); - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - *pPreNHtCapabilityLen = 0; // Nnow we only support 26 bytes. - - Ptr = (PUCHAR) pVIE; - NdisMoveMemory(Ptr + *LengthVIE, &pEid->Eid, pEid->Len + 2); - *LengthVIE += (pEid->Len + 2); - } -#endif // CONFIG_STA_SUPPORT // - } - else - { - DBGPRINT(RT_DEBUG_WARN, ("PeerBeaconAndProbeRspSanity - wrong IE_HT_CAP. pEid->Len = %d\n", pEid->Len)); - } - - break; - case IE_ADD_HT: - if (pEid->Len >= sizeof(ADD_HT_INFO_IE)) - { - // This IE allows extension, but we can ignore extra bytes beyond our knowledge , so only - // copy first sizeof(ADD_HT_INFO_IE) - NdisMoveMemory(AddHtInfo, pEid->Octet, sizeof(ADD_HT_INFO_IE)); - *AddHtInfoLen = SIZE_ADD_HT_INFO_IE; - - CtrlChannel = AddHtInfo->ControlChan; - - *(USHORT *)(&AddHtInfo->AddHtInfo2) = cpu2le16(*(USHORT *)(&AddHtInfo->AddHtInfo2)); - *(USHORT *)(&AddHtInfo->AddHtInfo3) = cpu2le16(*(USHORT *)(&AddHtInfo->AddHtInfo3)); - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - Ptr = (PUCHAR) pVIE; - NdisMoveMemory(Ptr + *LengthVIE, &pEid->Eid, pEid->Len + 2); - *LengthVIE += (pEid->Len + 2); - } -#endif // CONFIG_STA_SUPPORT // - } - else - { - DBGPRINT(RT_DEBUG_WARN, ("PeerBeaconAndProbeRspSanity - wrong IE_ADD_HT. \n")); - } - - break; - case IE_SECONDARY_CH_OFFSET: - if (pEid->Len == 1) - { - *NewExtChannelOffset = pEid->Octet[0]; - } - else - { - DBGPRINT(RT_DEBUG_WARN, ("PeerBeaconAndProbeRspSanity - wrong IE_SECONDARY_CH_OFFSET. \n")); - } - - break; - case IE_FH_PARM: - DBGPRINT(RT_DEBUG_TRACE, ("PeerBeaconAndProbeRspSanity(IE_FH_PARM) \n")); - break; - - case IE_DS_PARM: - if(pEid->Len == 1) - { - *pChannel = *pEid->Octet; -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - if (ChannelSanity(pAd, *pChannel) == 0) - { - - return FALSE; - } - } -#endif // CONFIG_STA_SUPPORT // - Sanity |= 0x4; - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("PeerBeaconAndProbeRspSanity - wrong IE_DS_PARM (len=%d)\n",pEid->Len)); - return FALSE; - } - break; - - case IE_CF_PARM: - if(pEid->Len == 6) - { - pCfParm->bValid = TRUE; - pCfParm->CfpCount = pEid->Octet[0]; - pCfParm->CfpPeriod = pEid->Octet[1]; - pCfParm->CfpMaxDuration = pEid->Octet[2] + 256 * pEid->Octet[3]; - pCfParm->CfpDurRemaining = pEid->Octet[4] + 256 * pEid->Octet[5]; - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("PeerBeaconAndProbeRspSanity - wrong IE_CF_PARM\n")); - return FALSE; - } - break; - - case IE_IBSS_PARM: - if(pEid->Len == 2) - { - NdisMoveMemory(pAtimWin, pEid->Octet, pEid->Len); - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("PeerBeaconAndProbeRspSanity - wrong IE_IBSS_PARM\n")); - return FALSE; - } - break; - -#ifdef CONFIG_STA_SUPPORT - case IE_TIM: - if(INFRA_ON(pAd) && SubType == SUBTYPE_BEACON) - { - GetTimBit((PUCHAR)pEid, pAd->StaActive.Aid, &TimLen, pBcastFlag, pDtimCount, pDtimPeriod, pMessageToMe); - } - break; -#endif // CONFIG_STA_SUPPORT // - case IE_CHANNEL_SWITCH_ANNOUNCEMENT: - if(pEid->Len == 3) - { - *pNewChannel = pEid->Octet[1]; //extract new channel number - } - break; - - // New for WPA - // CCX v2 has the same IE, we need to parse that too - // Wifi WMM use the same IE vale, need to parse that too - // case IE_WPA: - case IE_VENDOR_SPECIFIC: - // Check Broadcom/Atheros 802.11n OUI version, for HT Capability IE. - // This HT IE is before IEEE draft set HT IE value.2006-09-28 by Jan. - /*if (NdisEqualMemory(pEid->Octet, BROADCOM_OUI, 3) && (pEid->Len >= 4)) - { - if ((pEid->Octet[3] == OUI_BROADCOM_HT) && (pEid->Len >= 30)) - { - { - NdisMoveMemory(pHtCapability, &pEid->Octet[4], sizeof(HT_CAPABILITY_IE)); - *pHtCapabilityLen = SIZE_HT_CAP_IE; // Nnow we only support 26 bytes. - } - } - if ((pEid->Octet[3] == OUI_BROADCOM_HT) && (pEid->Len >= 26)) - { - { - NdisMoveMemory(AddHtInfo, &pEid->Octet[4], sizeof(ADD_HT_INFO_IE)); - *AddHtInfoLen = SIZE_ADD_HT_INFO_IE; // Nnow we only support 26 bytes. - } - } - } - */ - // Check the OUI version, filter out non-standard usage - if (NdisEqualMemory(pEid->Octet, RALINK_OUI, 3) && (pEid->Len == 7)) - { - //*pRalinkIe = pEid->Octet[3]; - if (pEid->Octet[3] != 0) - *pRalinkIe = pEid->Octet[3]; - else - *pRalinkIe = 0xf0000000; // Set to non-zero value (can't set bit0-2) to represent this is Ralink Chip. So at linkup, we will set ralinkchip flag. - } -#ifdef CONFIG_STA_SUPPORT -#ifdef DOT11_N_SUPPORT - // This HT IE is before IEEE draft set HT IE value.2006-09-28 by Jan. - - // Other vendors had production before IE_HT_CAP value is assigned. To backward support those old-firmware AP, - // Check broadcom-defiend pre-802.11nD1.0 OUI for HT related IE, including HT Capatilities IE and HT Information IE - else if ((*pHtCapabilityLen == 0) && NdisEqualMemory(pEid->Octet, PRE_N_HT_OUI, 3) && (pEid->Len >= 4) && (pAd->OpMode == OPMODE_STA)) - { - if ((pEid->Octet[3] == OUI_PREN_HT_CAP) && (pEid->Len >= 30) && (*pHtCapabilityLen == 0)) - { - NdisMoveMemory(pHtCapability, &pEid->Octet[4], sizeof(HT_CAPABILITY_IE)); - *pPreNHtCapabilityLen = SIZE_HT_CAP_IE; - } - - if ((pEid->Octet[3] == OUI_PREN_ADD_HT) && (pEid->Len >= 26)) - { - NdisMoveMemory(AddHtInfo, &pEid->Octet[4], sizeof(ADD_HT_INFO_IE)); - *AddHtInfoLen = SIZE_ADD_HT_INFO_IE; - } - } -#endif // DOT11_N_SUPPORT // -#endif // CONFIG_STA_SUPPORT // - else if (NdisEqualMemory(pEid->Octet, WPA_OUI, 4)) - { - // Copy to pVIE which will report to microsoft bssid list. - Ptr = (PUCHAR) pVIE; - NdisMoveMemory(Ptr + *LengthVIE, &pEid->Eid, pEid->Len + 2); - *LengthVIE += (pEid->Len + 2); - } - else if (NdisEqualMemory(pEid->Octet, WME_PARM_ELEM, 6) && (pEid->Len == 24)) - { - PUCHAR ptr; - int i; - - // parsing EDCA parameters - pEdcaParm->bValid = TRUE; - pEdcaParm->bQAck = FALSE; // pEid->Octet[0] & 0x10; - pEdcaParm->bQueueRequest = FALSE; // pEid->Octet[0] & 0x20; - pEdcaParm->bTxopRequest = FALSE; // pEid->Octet[0] & 0x40; - pEdcaParm->EdcaUpdateCount = pEid->Octet[6] & 0x0f; - pEdcaParm->bAPSDCapable = (pEid->Octet[6] & 0x80) ? 1 : 0; - ptr = &pEid->Octet[8]; - for (i=0; i<4; i++) - { - UCHAR aci = (*ptr & 0x60) >> 5; // b5~6 is AC INDEX - pEdcaParm->bACM[aci] = (((*ptr) & 0x10) == 0x10); // b5 is ACM - pEdcaParm->Aifsn[aci] = (*ptr) & 0x0f; // b0~3 is AIFSN - pEdcaParm->Cwmin[aci] = *(ptr+1) & 0x0f; // b0~4 is Cwmin - pEdcaParm->Cwmax[aci] = *(ptr+1) >> 4; // b5~8 is Cwmax - pEdcaParm->Txop[aci] = *(ptr+2) + 256 * (*(ptr+3)); // in unit of 32-us - ptr += 4; // point to next AC - } - } - else if (NdisEqualMemory(pEid->Octet, WME_INFO_ELEM, 6) && (pEid->Len == 7)) - { - // parsing EDCA parameters - pEdcaParm->bValid = TRUE; - pEdcaParm->bQAck = FALSE; // pEid->Octet[0] & 0x10; - pEdcaParm->bQueueRequest = FALSE; // pEid->Octet[0] & 0x20; - pEdcaParm->bTxopRequest = FALSE; // pEid->Octet[0] & 0x40; - pEdcaParm->EdcaUpdateCount = pEid->Octet[6] & 0x0f; - pEdcaParm->bAPSDCapable = (pEid->Octet[6] & 0x80) ? 1 : 0; - - // use default EDCA parameter - pEdcaParm->bACM[QID_AC_BE] = 0; - pEdcaParm->Aifsn[QID_AC_BE] = 3; - pEdcaParm->Cwmin[QID_AC_BE] = CW_MIN_IN_BITS; - pEdcaParm->Cwmax[QID_AC_BE] = CW_MAX_IN_BITS; - pEdcaParm->Txop[QID_AC_BE] = 0; - - pEdcaParm->bACM[QID_AC_BK] = 0; - pEdcaParm->Aifsn[QID_AC_BK] = 7; - pEdcaParm->Cwmin[QID_AC_BK] = CW_MIN_IN_BITS; - pEdcaParm->Cwmax[QID_AC_BK] = CW_MAX_IN_BITS; - pEdcaParm->Txop[QID_AC_BK] = 0; - - pEdcaParm->bACM[QID_AC_VI] = 0; - pEdcaParm->Aifsn[QID_AC_VI] = 2; - pEdcaParm->Cwmin[QID_AC_VI] = CW_MIN_IN_BITS-1; - pEdcaParm->Cwmax[QID_AC_VI] = CW_MAX_IN_BITS; - pEdcaParm->Txop[QID_AC_VI] = 96; // AC_VI: 96*32us ~= 3ms - - pEdcaParm->bACM[QID_AC_VO] = 0; - pEdcaParm->Aifsn[QID_AC_VO] = 2; - pEdcaParm->Cwmin[QID_AC_VO] = CW_MIN_IN_BITS-2; - pEdcaParm->Cwmax[QID_AC_VO] = CW_MAX_IN_BITS-1; - pEdcaParm->Txop[QID_AC_VO] = 48; // AC_VO: 48*32us ~= 1.5ms - } - break; - - case IE_EXT_SUPP_RATES: - if (pEid->Len <= MAX_LEN_OF_SUPPORTED_RATES) - { - NdisMoveMemory(ExtRate, pEid->Octet, pEid->Len); - *pExtRateLen = pEid->Len; - - // TODO: 2004-09-14 not a good design here, cause it exclude extra rates - // from ScanTab. We should report as is. And filter out unsupported - // rates in MlmeAux. - // Check against the supported rates - // RTMPCheckRates(pAd, ExtRate, pExtRateLen); - } - break; - - case IE_ERP: - if (pEid->Len == 1) - { - *pErp = (UCHAR)pEid->Octet[0]; - } - break; - - case IE_AIRONET_CKIP: - // 0. Check Aironet IE length, it must be larger or equal to 28 - // Cisco AP350 used length as 28 - // Cisco AP12XX used length as 30 - if (pEid->Len < (CKIP_NEGOTIATION_LENGTH - 2)) - break; - - // 1. Copy CKIP flag byte to buffer for process - *pCkipFlag = *(pEid->Octet + 8); - break; - - case IE_AP_TX_POWER: - // AP Control of Client Transmit Power - //0. Check Aironet IE length, it must be 6 - if (pEid->Len != 0x06) - break; - - // Get cell power limit in dBm - if (NdisEqualMemory(pEid->Octet, CISCO_OUI, 3) == 1) - *pAironetCellPowerLimit = *(pEid->Octet + 4); - break; - - // WPA2 & 802.11i RSN - case IE_RSN: - // There is no OUI for version anymore, check the group cipher OUI before copying - if (RTMPEqualMemory(pEid->Octet + 2, RSN_OUI, 3)) - { - // Copy to pVIE which will report to microsoft bssid list. - Ptr = (PUCHAR) pVIE; - NdisMoveMemory(Ptr + *LengthVIE, &pEid->Eid, pEid->Len + 2); - *LengthVIE += (pEid->Len + 2); - } - break; -#ifdef CONFIG_STA_SUPPORT -#ifdef EXT_BUILD_CHANNEL_LIST - case IE_COUNTRY: - Ptr = (PUCHAR) pVIE; - NdisMoveMemory(Ptr + *LengthVIE, &pEid->Eid, pEid->Len + 2); - *LengthVIE += (pEid->Len + 2); - break; -#endif // EXT_BUILD_CHANNEL_LIST // -#endif // CONFIG_STA_SUPPORT // - default: - break; - } - - Length = Length + 2 + pEid->Len; // Eid[1] + Len[1]+ content[Len] - pEid = (PEID_STRUCT)((UCHAR*)pEid + 2 + pEid->Len); - } - - // For some 11a AP. it did not have the channel EID, patch here -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - UCHAR LatchRfChannel = MsgChannel; - if ((pAd->LatchRfRegs.Channel > 14) && ((Sanity & 0x4) == 0)) - { - if (CtrlChannel != 0) - *pChannel = CtrlChannel; - else - *pChannel = LatchRfChannel; - Sanity |= 0x4; - } - } -#endif // CONFIG_STA_SUPPORT // - - if (Sanity != 0x7) - { - DBGPRINT(RT_DEBUG_WARN, ("PeerBeaconAndProbeRspSanity - missing field, Sanity=0x%02x\n", Sanity)); - return FALSE; - } - else - { - return TRUE; - } - -} - -#ifdef DOT11N_DRAFT3 -/* - ========================================================================== - Description: - MLME message sanity check for some IE addressed in 802.11n d3.03. - Return: - TRUE if all parameters are OK, FALSE otherwise - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -BOOLEAN PeerBeaconAndProbeRspSanity2( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT UCHAR *RegClass) -{ - CHAR *Ptr; - PFRAME_802_11 pFrame; - PEID_STRUCT pEid; - ULONG Length = 0; - - pFrame = (PFRAME_802_11)Msg; - - *RegClass = 0; - Ptr = pFrame->Octet; - Length += LENGTH_802_11; - - // get timestamp from payload and advance the pointer - Ptr += TIMESTAMP_LEN; - Length += TIMESTAMP_LEN; - - // get beacon interval from payload and advance the pointer - Ptr += 2; - Length += 2; - - // get capability info from payload and advance the pointer - Ptr += 2; - Length += 2; - - pEid = (PEID_STRUCT) Ptr; - - // get variable fields from payload and advance the pointer - while ((Length + 2 + pEid->Len) <= MsgLen) - { - switch(pEid->Eid) - { - case IE_SUPP_REG_CLASS: - if(pEid->Len > 0) - { - *RegClass = *pEid->Octet; - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("PeerBeaconAndProbeRspSanity - wrong IE_SSID (len=%d)\n",pEid->Len)); - return FALSE; - } - break; - } - - Length = Length + 2 + pEid->Len; // Eid[1] + Len[1]+ content[Len] - pEid = (PEID_STRUCT)((UCHAR*)pEid + 2 + pEid->Len); - } - - return TRUE; - -} -#endif // DOT11N_DRAFT3 // - -/* - ========================================================================== - Description: - MLME message sanity check - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== - */ -BOOLEAN MlmeScanReqSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT UCHAR *pBssType, - OUT CHAR Ssid[], - OUT UCHAR *pSsidLen, - OUT UCHAR *pScanType) -{ - MLME_SCAN_REQ_STRUCT *Info; - - Info = (MLME_SCAN_REQ_STRUCT *)(Msg); - *pBssType = Info->BssType; - *pSsidLen = Info->SsidLen; - NdisMoveMemory(Ssid, Info->Ssid, *pSsidLen); - *pScanType = Info->ScanType; - - if ((*pBssType == BSS_INFRA || *pBssType == BSS_ADHOC || *pBssType == BSS_ANY) - && (*pScanType == SCAN_ACTIVE || *pScanType == SCAN_PASSIVE -#ifdef CONFIG_STA_SUPPORT - || *pScanType == SCAN_CISCO_PASSIVE || *pScanType == SCAN_CISCO_ACTIVE - || *pScanType == SCAN_CISCO_CHANNEL_LOAD || *pScanType == SCAN_CISCO_NOISE -#endif // CONFIG_STA_SUPPORT // - )) - { - return TRUE; - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("MlmeScanReqSanity fail - wrong BssType or ScanType\n")); - return FALSE; - } -} - -// IRQL = DISPATCH_LEVEL -UCHAR ChannelSanity( - IN PRTMP_ADAPTER pAd, - IN UCHAR channel) -{ - int i; - - for (i = 0; i < pAd->ChannelListNum; i ++) - { - if (channel == pAd->ChannelList[i].Channel) - return 1; - } - return 0; -} - -/* - ========================================================================== - Description: - MLME message sanity check - Return: - TRUE if all parameters are OK, FALSE otherwise - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -BOOLEAN PeerDeauthSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PUCHAR pAddr2, - OUT USHORT *pReason) -{ - PFRAME_802_11 pFrame = (PFRAME_802_11)Msg; - - COPY_MAC_ADDR(pAddr2, pFrame->Hdr.Addr2); - NdisMoveMemory(pReason, &pFrame->Octet[0], 2); - - return TRUE; -} - -/* - ========================================================================== - Description: - MLME message sanity check - Return: - TRUE if all parameters are OK, FALSE otherwise - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -BOOLEAN PeerAuthSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PUCHAR pAddr, - OUT USHORT *pAlg, - OUT USHORT *pSeq, - OUT USHORT *pStatus, - CHAR *pChlgText) -{ - PFRAME_802_11 pFrame = (PFRAME_802_11)Msg; - - COPY_MAC_ADDR(pAddr, pFrame->Hdr.Addr2); - NdisMoveMemory(pAlg, &pFrame->Octet[0], 2); - NdisMoveMemory(pSeq, &pFrame->Octet[2], 2); - NdisMoveMemory(pStatus, &pFrame->Octet[4], 2); - - if ((*pAlg == Ndis802_11AuthModeOpen) -#ifdef LEAP_SUPPORT - || (*pAlg == CISCO_AuthModeLEAP) -#endif // LEAP_SUPPORT // - ) - { - if (*pSeq == 1 || *pSeq == 2) - { - return TRUE; - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("PeerAuthSanity fail - wrong Seg#\n")); - return FALSE; - } - } - else if (*pAlg == Ndis802_11AuthModeShared) - { - if (*pSeq == 1 || *pSeq == 4) - { - return TRUE; - } - else if (*pSeq == 2 || *pSeq == 3) - { - NdisMoveMemory(pChlgText, &pFrame->Octet[8], CIPHER_TEXT_LEN); - return TRUE; - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("PeerAuthSanity fail - wrong Seg#\n")); - return FALSE; - } - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("PeerAuthSanity fail - wrong algorithm\n")); - return FALSE; - } -} - -/* - ========================================================================== - Description: - MLME message sanity check - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== - */ -BOOLEAN MlmeAuthReqSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PUCHAR pAddr, - OUT ULONG *pTimeout, - OUT USHORT *pAlg) -{ - MLME_AUTH_REQ_STRUCT *pInfo; - - pInfo = (MLME_AUTH_REQ_STRUCT *)Msg; - COPY_MAC_ADDR(pAddr, pInfo->Addr); - *pTimeout = pInfo->Timeout; - *pAlg = pInfo->Alg; - - if (((*pAlg == Ndis802_11AuthModeShared) ||(*pAlg == Ndis802_11AuthModeOpen) -#ifdef LEAP_SUPPORT - || (*pAlg == CISCO_AuthModeLEAP) -#endif // LEAP_SUPPORT // - ) && - ((*pAddr & 0x01) == 0)) - { - return TRUE; - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("MlmeAuthReqSanity fail - wrong algorithm\n")); - return FALSE; - } -} - -/* - ========================================================================== - Description: - MLME message sanity check - Return: - TRUE if all parameters are OK, FALSE otherwise - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -BOOLEAN MlmeAssocReqSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PUCHAR pApAddr, - OUT USHORT *pCapabilityInfo, - OUT ULONG *pTimeout, - OUT USHORT *pListenIntv) -{ - MLME_ASSOC_REQ_STRUCT *pInfo; - - pInfo = (MLME_ASSOC_REQ_STRUCT *)Msg; - *pTimeout = pInfo->Timeout; // timeout - COPY_MAC_ADDR(pApAddr, pInfo->Addr); // AP address - *pCapabilityInfo = pInfo->CapabilityInfo; // capability info - *pListenIntv = pInfo->ListenIntv; - - return TRUE; -} - -/* - ========================================================================== - Description: - MLME message sanity check - Return: - TRUE if all parameters are OK, FALSE otherwise - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -BOOLEAN PeerDisassocSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PUCHAR pAddr2, - OUT USHORT *pReason) -{ - PFRAME_802_11 pFrame = (PFRAME_802_11)Msg; - - COPY_MAC_ADDR(pAddr2, pFrame->Hdr.Addr2); - NdisMoveMemory(pReason, &pFrame->Octet[0], 2); - - return TRUE; -} - -/* - ======================================================================== - Routine Description: - Sanity check NetworkType (11b, 11g or 11a) - - Arguments: - pBss - Pointer to BSS table. - - Return Value: - Ndis802_11DS .......(11b) - Ndis802_11OFDM24....(11g) - Ndis802_11OFDM5.....(11a) - - IRQL = DISPATCH_LEVEL - - ======================================================================== -*/ -NDIS_802_11_NETWORK_TYPE NetworkTypeInUseSanity( - IN PBSS_ENTRY pBss) -{ - NDIS_802_11_NETWORK_TYPE NetWorkType; - UCHAR rate, i; - - NetWorkType = Ndis802_11DS; - - if (pBss->Channel <= 14) - { - // - // First check support Rate. - // - for (i = 0; i < pBss->SupRateLen; i++) - { - rate = pBss->SupRate[i] & 0x7f; // Mask out basic rate set bit - if ((rate == 2) || (rate == 4) || (rate == 11) || (rate == 22)) - { - continue; - } - else - { - // - // Otherwise (even rate > 108) means Ndis802_11OFDM24 - // - NetWorkType = Ndis802_11OFDM24; - break; - } - } - - // - // Second check Extend Rate. - // - if (NetWorkType != Ndis802_11OFDM24) - { - for (i = 0; i < pBss->ExtRateLen; i++) - { - rate = pBss->SupRate[i] & 0x7f; // Mask out basic rate set bit - if ((rate == 2) || (rate == 4) || (rate == 11) || (rate == 22)) - { - continue; - } - else - { - // - // Otherwise (even rate > 108) means Ndis802_11OFDM24 - // - NetWorkType = Ndis802_11OFDM24; - break; - } - } - } - } - else - { - NetWorkType = Ndis802_11OFDM5; - } - - if (pBss->HtCapabilityLen != 0) - { - if (NetWorkType == Ndis802_11OFDM5) - NetWorkType = Ndis802_11OFDM5_N; - else - NetWorkType = Ndis802_11OFDM24_N; - } - - return NetWorkType; -} - -/* - ========================================================================== - Description: - WPA message sanity check - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== - */ -BOOLEAN PeerWpaMessageSanity( - IN PRTMP_ADAPTER pAd, - IN PEAPOL_PACKET pMsg, - IN ULONG MsgLen, - IN UCHAR MsgType, - IN MAC_TABLE_ENTRY *pEntry) -{ - UCHAR mic[LEN_KEY_DESC_MIC], digest[80], KEYDATA[MAX_LEN_OF_RSNIE]; - BOOLEAN bReplayDiff = FALSE; - BOOLEAN bWPA2 = FALSE; - KEY_INFO EapolKeyInfo; - UCHAR GroupKeyIndex = 0; - - - NdisZeroMemory(mic, sizeof(mic)); - NdisZeroMemory(digest, sizeof(digest)); - NdisZeroMemory(KEYDATA, sizeof(KEYDATA)); - NdisZeroMemory((PUCHAR)&EapolKeyInfo, sizeof(EapolKeyInfo)); - - NdisMoveMemory((PUCHAR)&EapolKeyInfo, (PUCHAR)&pMsg->KeyDesc.KeyInfo, sizeof(KEY_INFO)); - - *((USHORT *)&EapolKeyInfo) = cpu2le16(*((USHORT *)&EapolKeyInfo)); - - // Choose WPA2 or not - if ((pEntry->AuthMode == Ndis802_11AuthModeWPA2) || (pEntry->AuthMode == Ndis802_11AuthModeWPA2PSK)) - bWPA2 = TRUE; - - // 0. Check MsgType - if ((MsgType > EAPOL_GROUP_MSG_2) || (MsgType < EAPOL_PAIR_MSG_1)) - { - DBGPRINT(RT_DEBUG_ERROR, ("The message type is invalid(%d)! \n", MsgType)); - return FALSE; - } - - // 1. Replay counter check - if (MsgType == EAPOL_PAIR_MSG_1 || MsgType == EAPOL_PAIR_MSG_3 || MsgType == EAPOL_GROUP_MSG_1) // For supplicant - { - // First validate replay counter, only accept message with larger replay counter. - // Let equal pass, some AP start with all zero replay counter - UCHAR ZeroReplay[LEN_KEY_DESC_REPLAY]; - - NdisZeroMemory(ZeroReplay, LEN_KEY_DESC_REPLAY); - if ((RTMPCompareMemory(pMsg->KeyDesc.ReplayCounter, pEntry->R_Counter, LEN_KEY_DESC_REPLAY) != 1) && - (RTMPCompareMemory(pMsg->KeyDesc.ReplayCounter, ZeroReplay, LEN_KEY_DESC_REPLAY) != 0)) - { - bReplayDiff = TRUE; - } - } - else if (MsgType == EAPOL_PAIR_MSG_2 || MsgType == EAPOL_PAIR_MSG_4 || MsgType == EAPOL_GROUP_MSG_2) // For authenticator - { - // check Replay Counter coresponds to MSG from authenticator, otherwise discard - if (!NdisEqualMemory(pMsg->KeyDesc.ReplayCounter, pEntry->R_Counter, LEN_KEY_DESC_REPLAY)) - { - bReplayDiff = TRUE; - } - } - - // Replay Counter different condition - if (bReplayDiff) - { - // send wireless event - for replay counter different - if (pAd->CommonCfg.bWirelessEvent) - RTMPSendWirelessEvent(pAd, IW_REPLAY_COUNTER_DIFF_EVENT_FLAG, pEntry->Addr, pEntry->apidx, 0); - - if (MsgType < EAPOL_GROUP_MSG_1) - { - DBGPRINT(RT_DEBUG_ERROR, ("Replay Counter Different in pairwise msg %d of 4-way handshake!\n", MsgType)); - } - else - { - DBGPRINT(RT_DEBUG_ERROR, ("Replay Counter Different in group msg %d of 2-way handshake!\n", (MsgType - EAPOL_PAIR_MSG_4))); - } - - hex_dump("Receive replay counter ", pMsg->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); - hex_dump("Current replay counter ", pEntry->R_Counter, LEN_KEY_DESC_REPLAY); - return FALSE; - } - - // 2. Verify MIC except Pairwise Msg1 - if (MsgType != EAPOL_PAIR_MSG_1) - { - UCHAR rcvd_mic[LEN_KEY_DESC_MIC]; - - // Record the received MIC for check later - NdisMoveMemory(rcvd_mic, pMsg->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); - NdisZeroMemory(pMsg->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); - - if (pEntry->WepStatus == Ndis802_11Encryption2Enabled) // TKIP - { - hmac_md5(pEntry->PTK, LEN_EAP_MICK, (PUCHAR)pMsg, MsgLen, mic); - } - else if (pEntry->WepStatus == Ndis802_11Encryption3Enabled) // AES - { - HMAC_SHA1((PUCHAR)pMsg, MsgLen, pEntry->PTK, LEN_EAP_MICK, digest); - NdisMoveMemory(mic, digest, LEN_KEY_DESC_MIC); - } - - if (!NdisEqualMemory(rcvd_mic, mic, LEN_KEY_DESC_MIC)) - { - // send wireless event - for MIC different - if (pAd->CommonCfg.bWirelessEvent) - RTMPSendWirelessEvent(pAd, IW_MIC_DIFF_EVENT_FLAG, pEntry->Addr, pEntry->apidx, 0); - - if (MsgType < EAPOL_GROUP_MSG_1) - { - DBGPRINT(RT_DEBUG_ERROR, ("MIC Different in pairwise msg %d of 4-way handshake!\n", MsgType)); - } - else - { - DBGPRINT(RT_DEBUG_ERROR, ("MIC Different in group msg %d of 2-way handshake!\n", (MsgType - EAPOL_PAIR_MSG_4))); - } - - hex_dump("Received MIC", rcvd_mic, LEN_KEY_DESC_MIC); - hex_dump("Desired MIC", mic, LEN_KEY_DESC_MIC); - - return FALSE; - } - } - - // Extract the context of the Key Data field if it exist - // The field in pairwise_msg_2_WPA1(WPA2) & pairwise_msg_3_WPA1 is un-encrypted. - // The field in group_msg_1_WPA1(WPA2) & pairwise_msg_3_WPA2 is encrypted. - if (pMsg->KeyDesc.KeyDataLen[1] > 0) - { - // Decrypt this field - if ((MsgType == EAPOL_PAIR_MSG_3 && bWPA2) || (MsgType == EAPOL_GROUP_MSG_1)) - { - if(pEntry->WepStatus == Ndis802_11Encryption3Enabled) - { - // AES - AES_GTK_KEY_UNWRAP(&pEntry->PTK[16], KEYDATA, pMsg->KeyDesc.KeyDataLen[1],pMsg->KeyDesc.KeyData); - } - else - { - INT i; - UCHAR Key[32]; - // Decrypt TKIP GTK - // Construct 32 bytes RC4 Key - NdisMoveMemory(Key, pMsg->KeyDesc.KeyIv, 16); - NdisMoveMemory(&Key[16], &pEntry->PTK[16], 16); - ARCFOUR_INIT(&pAd->PrivateInfo.WEPCONTEXT, Key, 32); - //discard first 256 bytes - for(i = 0; i < 256; i++) - ARCFOUR_BYTE(&pAd->PrivateInfo.WEPCONTEXT); - // Decrypt GTK. Becareful, there is no ICV to check the result is correct or not - ARCFOUR_DECRYPT(&pAd->PrivateInfo.WEPCONTEXT, KEYDATA, pMsg->KeyDesc.KeyData, pMsg->KeyDesc.KeyDataLen[1]); - } - - if (!bWPA2 && (MsgType == EAPOL_GROUP_MSG_1)) - GroupKeyIndex = EapolKeyInfo.KeyIndex; - - } - else if ((MsgType == EAPOL_PAIR_MSG_2) || (MsgType == EAPOL_PAIR_MSG_3 && !bWPA2)) - { - NdisMoveMemory(KEYDATA, pMsg->KeyDesc.KeyData, pMsg->KeyDesc.KeyDataLen[1]); - } - else - { - - return TRUE; - } - - // Parse Key Data field to - // 1. verify RSN IE for pairwise_msg_2_WPA1(WPA2) ,pairwise_msg_3_WPA1(WPA2) - // 2. verify KDE format for pairwise_msg_3_WPA2, group_msg_1_WPA2 - // 3. update shared key for pairwise_msg_3_WPA2, group_msg_1_WPA1(WPA2) - if (!RTMPParseEapolKeyData(pAd, KEYDATA, pMsg->KeyDesc.KeyDataLen[1], GroupKeyIndex, MsgType, bWPA2, pEntry)) - { - return FALSE; - } - } - - return TRUE; - -} - -#ifdef CONFIG_STA_SUPPORT -#ifdef QOS_DLS_SUPPORT -BOOLEAN MlmeDlsReqSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PRT_802_11_DLS *pDLS, - OUT PUSHORT pReason) -{ - MLME_DLS_REQ_STRUCT *pInfo; - - pInfo = (MLME_DLS_REQ_STRUCT *)Msg; - - *pDLS = pInfo->pDLS; - *pReason = pInfo->Reason; - - return TRUE; -} -#endif // QOS_DLS_SUPPORT // -#endif // CONFIG_STA_SUPPORT // - -#ifdef QOS_DLS_SUPPORT -BOOLEAN PeerDlsReqSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PUCHAR pDA, - OUT PUCHAR pSA, - OUT USHORT *pCapabilityInfo, - OUT USHORT *pDlsTimeout, - OUT UCHAR *pRatesLen, - OUT UCHAR Rates[], - OUT UCHAR *pHtCapabilityLen, - OUT HT_CAPABILITY_IE *pHtCapability) -{ - CHAR *Ptr; - PFRAME_802_11 Fr = (PFRAME_802_11)Msg; - PEID_STRUCT eid_ptr; - - // to prevent caller from using garbage output value - *pCapabilityInfo = 0; - *pDlsTimeout = 0; - *pHtCapabilityLen = 0; - - Ptr = Fr->Octet; - - // offset to destination MAC address (Category and Action field) - Ptr += 2; - - // get DA from payload and advance the pointer - NdisMoveMemory(pDA, Ptr, MAC_ADDR_LEN); - Ptr += MAC_ADDR_LEN; - - // get SA from payload and advance the pointer - NdisMoveMemory(pSA, Ptr, MAC_ADDR_LEN); - Ptr += MAC_ADDR_LEN; - - // get capability info from payload and advance the pointer - NdisMoveMemory(pCapabilityInfo, Ptr, 2); - Ptr += 2; - - // get capability info from payload and advance the pointer - NdisMoveMemory(pDlsTimeout, Ptr, 2); - Ptr += 2; - - // Category and Action field + DA + SA + capability + Timeout - eid_ptr = (PEID_STRUCT) &Fr->Octet[18]; - - while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((UCHAR*)Fr + MsgLen)) - { - switch(eid_ptr->Eid) - { - case IE_SUPP_RATES: - if ((eid_ptr->Len <= MAX_LEN_OF_SUPPORTED_RATES) && (eid_ptr->Len > 0)) - { - NdisMoveMemory(Rates, eid_ptr->Octet, eid_ptr->Len); - DBGPRINT(RT_DEBUG_TRACE, ("PeerDlsReqSanity - IE_SUPP_RATES., Len=%d. Rates[0]=%x\n",eid_ptr->Len, Rates[0])); - DBGPRINT(RT_DEBUG_TRACE, ("Rates[1]=%x %x %x %x %x %x %x\n", Rates[1], Rates[2], Rates[3], Rates[4], Rates[5], Rates[6], Rates[7])); - *pRatesLen = eid_ptr->Len; - } - else - { - *pRatesLen = 8; - Rates[0] = 0x82; - Rates[1] = 0x84; - Rates[2] = 0x8b; - Rates[3] = 0x96; - Rates[4] = 0x12; - Rates[5] = 0x24; - Rates[6] = 0x48; - Rates[7] = 0x6c; - DBGPRINT(RT_DEBUG_TRACE, ("PeerDlsReqSanity - wrong IE_SUPP_RATES., Len=%d\n",eid_ptr->Len)); - } - break; - - case IE_EXT_SUPP_RATES: - if (eid_ptr->Len + *pRatesLen <= MAX_LEN_OF_SUPPORTED_RATES) - { - NdisMoveMemory(&Rates[*pRatesLen], eid_ptr->Octet, eid_ptr->Len); - *pRatesLen = (*pRatesLen) + eid_ptr->Len; - } - else - { - NdisMoveMemory(&Rates[*pRatesLen], eid_ptr->Octet, MAX_LEN_OF_SUPPORTED_RATES - (*pRatesLen)); - *pRatesLen = MAX_LEN_OF_SUPPORTED_RATES; - } - break; - - case IE_HT_CAP: - if (eid_ptr->Len >= sizeof(HT_CAPABILITY_IE)) - { - NdisMoveMemory(pHtCapability, eid_ptr->Octet, sizeof(HT_CAPABILITY_IE)); - - *(USHORT *)(&pHtCapability->HtCapInfo) = cpu2le16(*(USHORT *)(&pHtCapability->HtCapInfo)); - *(USHORT *)(&pHtCapability->ExtHtCapInfo) = cpu2le16(*(USHORT *)(&pHtCapability->ExtHtCapInfo)); - *pHtCapabilityLen = sizeof(HT_CAPABILITY_IE); - - DBGPRINT(RT_DEBUG_TRACE, ("PeerDlsReqSanity - IE_HT_CAP\n")); - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("PeerDlsReqSanity - wrong IE_HT_CAP.eid_ptr->Len = %d\n", eid_ptr->Len)); - } - break; - - default: - break; - } - - eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len); - } - - return TRUE; -} - -BOOLEAN PeerDlsRspSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PUCHAR pDA, - OUT PUCHAR pSA, - OUT USHORT *pCapabilityInfo, - OUT USHORT *pStatus, - OUT UCHAR *pRatesLen, - OUT UCHAR Rates[], - OUT UCHAR *pHtCapabilityLen, - OUT HT_CAPABILITY_IE *pHtCapability) -{ - CHAR *Ptr; - PFRAME_802_11 Fr = (PFRAME_802_11)Msg; - PEID_STRUCT eid_ptr; - - // to prevent caller from using garbage output value - *pStatus = 0; - *pCapabilityInfo = 0; - *pHtCapabilityLen = 0; - - Ptr = Fr->Octet; - - // offset to destination MAC address (Category and Action field) - Ptr += 2; - - // get status code from payload and advance the pointer - NdisMoveMemory(pStatus, Ptr, 2); - Ptr += 2; - - // get DA from payload and advance the pointer - NdisMoveMemory(pDA, Ptr, MAC_ADDR_LEN); - Ptr += MAC_ADDR_LEN; - - // get SA from payload and advance the pointer - NdisMoveMemory(pSA, Ptr, MAC_ADDR_LEN); - Ptr += MAC_ADDR_LEN; - - if (pStatus == 0) - { - // get capability info from payload and advance the pointer - NdisMoveMemory(pCapabilityInfo, Ptr, 2); - Ptr += 2; - } - - // Category and Action field + status code + DA + SA + capability - eid_ptr = (PEID_STRUCT) &Fr->Octet[18]; - - while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((UCHAR*)Fr + MsgLen)) - { - switch(eid_ptr->Eid) - { - case IE_SUPP_RATES: - if ((eid_ptr->Len <= MAX_LEN_OF_SUPPORTED_RATES) && (eid_ptr->Len > 0)) - { - NdisMoveMemory(Rates, eid_ptr->Octet, eid_ptr->Len); - DBGPRINT(RT_DEBUG_TRACE, ("PeerDlsRspSanity - IE_SUPP_RATES., Len=%d. Rates[0]=%x\n",eid_ptr->Len, Rates[0])); - DBGPRINT(RT_DEBUG_TRACE, ("Rates[1]=%x %x %x %x %x %x %x\n", Rates[1], Rates[2], Rates[3], Rates[4], Rates[5], Rates[6], Rates[7])); - *pRatesLen = eid_ptr->Len; - } - else - { - *pRatesLen = 8; - Rates[0] = 0x82; - Rates[1] = 0x84; - Rates[2] = 0x8b; - Rates[3] = 0x96; - Rates[4] = 0x12; - Rates[5] = 0x24; - Rates[6] = 0x48; - Rates[7] = 0x6c; - DBGPRINT(RT_DEBUG_TRACE, ("PeerDlsRspSanity - wrong IE_SUPP_RATES., Len=%d\n",eid_ptr->Len)); - } - break; - - case IE_EXT_SUPP_RATES: - if (eid_ptr->Len + *pRatesLen <= MAX_LEN_OF_SUPPORTED_RATES) - { - NdisMoveMemory(&Rates[*pRatesLen], eid_ptr->Octet, eid_ptr->Len); - *pRatesLen = (*pRatesLen) + eid_ptr->Len; - } - else - { - NdisMoveMemory(&Rates[*pRatesLen], eid_ptr->Octet, MAX_LEN_OF_SUPPORTED_RATES - (*pRatesLen)); - *pRatesLen = MAX_LEN_OF_SUPPORTED_RATES; - } - break; - - case IE_HT_CAP: - if (eid_ptr->Len >= sizeof(HT_CAPABILITY_IE)) - { - NdisMoveMemory(pHtCapability, eid_ptr->Octet, sizeof(HT_CAPABILITY_IE)); - - *(USHORT *)(&pHtCapability->HtCapInfo) = cpu2le16(*(USHORT *)(&pHtCapability->HtCapInfo)); - *(USHORT *)(&pHtCapability->ExtHtCapInfo) = cpu2le16(*(USHORT *)(&pHtCapability->ExtHtCapInfo)); - *pHtCapabilityLen = sizeof(HT_CAPABILITY_IE); - - DBGPRINT(RT_DEBUG_TRACE, ("PeerDlsRspSanity - IE_HT_CAP\n")); - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("PeerDlsRspSanity - wrong IE_HT_CAP.eid_ptr->Len = %d\n", eid_ptr->Len)); - } - break; - - default: - break; - } - - eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len); - } - - return TRUE; -} - -BOOLEAN PeerDlsTearDownSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PUCHAR pDA, - OUT PUCHAR pSA, - OUT USHORT *pReason) -{ - CHAR *Ptr; - PFRAME_802_11 Fr = (PFRAME_802_11)Msg; - - // to prevent caller from using garbage output value - *pReason = 0; - - Ptr = Fr->Octet; - - // offset to destination MAC address (Category and Action field) - Ptr += 2; - - // get DA from payload and advance the pointer - NdisMoveMemory(pDA, Ptr, MAC_ADDR_LEN); - Ptr += MAC_ADDR_LEN; - - // get SA from payload and advance the pointer - NdisMoveMemory(pSA, Ptr, MAC_ADDR_LEN); - Ptr += MAC_ADDR_LEN; - - // get reason code from payload and advance the pointer - NdisMoveMemory(pReason, Ptr, 2); - Ptr += 2; - - return TRUE; -} -#endif // QOS_DLS_SUPPORT // - +#include "../../rt2860/common/cmm_sanity.c" diff --git a/drivers/staging/rt2870/common/cmm_sync.c b/drivers/staging/rt2870/common/cmm_sync.c index 2be7c77a384e..5e7221d7cb27 100644 --- a/drivers/staging/rt2870/common/cmm_sync.c +++ b/drivers/staging/rt2870/common/cmm_sync.c @@ -1,711 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - sync.c - - Abstract: - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - John Chang 2004-09-01 modified for rt2561/2661 -*/ -#include "../rt_config.h" - -// 2.4 Ghz channel plan index in the TxPower arrays. -#define BG_BAND_REGION_0_START 0 // 1,2,3,4,5,6,7,8,9,10,11 -#define BG_BAND_REGION_0_SIZE 11 -#define BG_BAND_REGION_1_START 0 // 1,2,3,4,5,6,7,8,9,10,11,12,13 -#define BG_BAND_REGION_1_SIZE 13 -#define BG_BAND_REGION_2_START 9 // 10,11 -#define BG_BAND_REGION_2_SIZE 2 -#define BG_BAND_REGION_3_START 9 // 10,11,12,13 -#define BG_BAND_REGION_3_SIZE 4 -#define BG_BAND_REGION_4_START 13 // 14 -#define BG_BAND_REGION_4_SIZE 1 -#define BG_BAND_REGION_5_START 0 // 1,2,3,4,5,6,7,8,9,10,11,12,13,14 -#define BG_BAND_REGION_5_SIZE 14 -#define BG_BAND_REGION_6_START 2 // 3,4,5,6,7,8,9 -#define BG_BAND_REGION_6_SIZE 7 -#define BG_BAND_REGION_7_START 4 // 5,6,7,8,9,10,11,12,13 -#define BG_BAND_REGION_7_SIZE 9 -#define BG_BAND_REGION_31_START 0 // 1,2,3,4,5,6,7,8,9,10,11,12,13,14 -#define BG_BAND_REGION_31_SIZE 14 - -// 5 Ghz channel plan index in the TxPower arrays. -UCHAR A_BAND_REGION_0_CHANNEL_LIST[]={36, 40, 44, 48, 52, 56, 60, 64, 149, 153, 157, 161, 165}; -UCHAR A_BAND_REGION_1_CHANNEL_LIST[]={36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140}; -UCHAR A_BAND_REGION_2_CHANNEL_LIST[]={36, 40, 44, 48, 52, 56, 60, 64}; -UCHAR A_BAND_REGION_3_CHANNEL_LIST[]={52, 56, 60, 64, 149, 153, 157, 161}; -UCHAR A_BAND_REGION_4_CHANNEL_LIST[]={149, 153, 157, 161, 165}; -UCHAR A_BAND_REGION_5_CHANNEL_LIST[]={149, 153, 157, 161}; -UCHAR A_BAND_REGION_6_CHANNEL_LIST[]={36, 40, 44, 48}; -UCHAR A_BAND_REGION_7_CHANNEL_LIST[]={36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165}; -UCHAR A_BAND_REGION_8_CHANNEL_LIST[]={52, 56, 60, 64}; -UCHAR A_BAND_REGION_9_CHANNEL_LIST[]={36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 132, 136, 140, 149, 153, 157, 161, 165}; -UCHAR A_BAND_REGION_10_CHANNEL_LIST[]={36, 40, 44, 48, 149, 153, 157, 161, 165}; -UCHAR A_BAND_REGION_11_CHANNEL_LIST[]={36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 149, 153, 157, 161}; - -//BaSizeArray follows the 802.11n definition as MaxRxFactor. 2^(13+factor) bytes. When factor =0, it's about Ba buffer size =8. -UCHAR BaSizeArray[4] = {8,16,32,64}; - -/* - ========================================================================== - Description: - Update StaCfg->ChannelList[] according to 1) Country Region 2) RF IC type, - and 3) PHY-mode user selected. - The outcome is used by driver when doing site survey. - - IRQL = PASSIVE_LEVEL - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID BuildChannelList( - IN PRTMP_ADAPTER pAd) -{ - UCHAR i, j, index=0, num=0; - PUCHAR pChannelList = NULL; - - NdisZeroMemory(pAd->ChannelList, MAX_NUM_OF_CHANNELS * sizeof(CHANNEL_TX_POWER)); - - // if not 11a-only mode, channel list starts from 2.4Ghz band - if ((pAd->CommonCfg.PhyMode != PHY_11A) -#ifdef DOT11_N_SUPPORT - && (pAd->CommonCfg.PhyMode != PHY_11AN_MIXED) && (pAd->CommonCfg.PhyMode != PHY_11N_5G) -#endif // DOT11_N_SUPPORT // - ) - { - switch (pAd->CommonCfg.CountryRegion & 0x7f) - { - case REGION_0_BG_BAND: // 1 -11 - NdisMoveMemory(&pAd->ChannelList[index], &pAd->TxPower[BG_BAND_REGION_0_START], sizeof(CHANNEL_TX_POWER) * BG_BAND_REGION_0_SIZE); - index += BG_BAND_REGION_0_SIZE; - break; - case REGION_1_BG_BAND: // 1 - 13 - NdisMoveMemory(&pAd->ChannelList[index], &pAd->TxPower[BG_BAND_REGION_1_START], sizeof(CHANNEL_TX_POWER) * BG_BAND_REGION_1_SIZE); - index += BG_BAND_REGION_1_SIZE; - break; - case REGION_2_BG_BAND: // 10 - 11 - NdisMoveMemory(&pAd->ChannelList[index], &pAd->TxPower[BG_BAND_REGION_2_START], sizeof(CHANNEL_TX_POWER) * BG_BAND_REGION_2_SIZE); - index += BG_BAND_REGION_2_SIZE; - break; - case REGION_3_BG_BAND: // 10 - 13 - NdisMoveMemory(&pAd->ChannelList[index], &pAd->TxPower[BG_BAND_REGION_3_START], sizeof(CHANNEL_TX_POWER) * BG_BAND_REGION_3_SIZE); - index += BG_BAND_REGION_3_SIZE; - break; - case REGION_4_BG_BAND: // 14 - NdisMoveMemory(&pAd->ChannelList[index], &pAd->TxPower[BG_BAND_REGION_4_START], sizeof(CHANNEL_TX_POWER) * BG_BAND_REGION_4_SIZE); - index += BG_BAND_REGION_4_SIZE; - break; - case REGION_5_BG_BAND: // 1 - 14 - NdisMoveMemory(&pAd->ChannelList[index], &pAd->TxPower[BG_BAND_REGION_5_START], sizeof(CHANNEL_TX_POWER) * BG_BAND_REGION_5_SIZE); - index += BG_BAND_REGION_5_SIZE; - break; - case REGION_6_BG_BAND: // 3 - 9 - NdisMoveMemory(&pAd->ChannelList[index], &pAd->TxPower[BG_BAND_REGION_6_START], sizeof(CHANNEL_TX_POWER) * BG_BAND_REGION_6_SIZE); - index += BG_BAND_REGION_6_SIZE; - break; - case REGION_7_BG_BAND: // 5 - 13 - NdisMoveMemory(&pAd->ChannelList[index], &pAd->TxPower[BG_BAND_REGION_7_START], sizeof(CHANNEL_TX_POWER) * BG_BAND_REGION_7_SIZE); - index += BG_BAND_REGION_7_SIZE; - break; - case REGION_31_BG_BAND: // 1 - 14 - NdisMoveMemory(&pAd->ChannelList[index], &pAd->TxPower[BG_BAND_REGION_31_START], sizeof(CHANNEL_TX_POWER) * BG_BAND_REGION_31_SIZE); - index += BG_BAND_REGION_31_SIZE; - break; - default: // Error. should never happen - break; - } - for (i=0; iChannelList[i].MaxTxPwr = 20; - } - - if ((pAd->CommonCfg.PhyMode == PHY_11A) || (pAd->CommonCfg.PhyMode == PHY_11ABG_MIXED) -#ifdef DOT11_N_SUPPORT - || (pAd->CommonCfg.PhyMode == PHY_11ABGN_MIXED) || (pAd->CommonCfg.PhyMode == PHY_11AN_MIXED) - || (pAd->CommonCfg.PhyMode == PHY_11AGN_MIXED) || (pAd->CommonCfg.PhyMode == PHY_11N_5G) -#endif // DOT11_N_SUPPORT // - ) - { - switch (pAd->CommonCfg.CountryRegionForABand & 0x7f) - { - case REGION_0_A_BAND: - num = sizeof(A_BAND_REGION_0_CHANNEL_LIST)/sizeof(UCHAR); - pChannelList = A_BAND_REGION_0_CHANNEL_LIST; - break; - case REGION_1_A_BAND: - num = sizeof(A_BAND_REGION_1_CHANNEL_LIST)/sizeof(UCHAR); - pChannelList = A_BAND_REGION_1_CHANNEL_LIST; - break; - case REGION_2_A_BAND: - num = sizeof(A_BAND_REGION_2_CHANNEL_LIST)/sizeof(UCHAR); - pChannelList = A_BAND_REGION_2_CHANNEL_LIST; - break; - case REGION_3_A_BAND: - num = sizeof(A_BAND_REGION_3_CHANNEL_LIST)/sizeof(UCHAR); - pChannelList = A_BAND_REGION_3_CHANNEL_LIST; - break; - case REGION_4_A_BAND: - num = sizeof(A_BAND_REGION_4_CHANNEL_LIST)/sizeof(UCHAR); - pChannelList = A_BAND_REGION_4_CHANNEL_LIST; - break; - case REGION_5_A_BAND: - num = sizeof(A_BAND_REGION_5_CHANNEL_LIST)/sizeof(UCHAR); - pChannelList = A_BAND_REGION_5_CHANNEL_LIST; - break; - case REGION_6_A_BAND: - num = sizeof(A_BAND_REGION_6_CHANNEL_LIST)/sizeof(UCHAR); - pChannelList = A_BAND_REGION_6_CHANNEL_LIST; - break; - case REGION_7_A_BAND: - num = sizeof(A_BAND_REGION_7_CHANNEL_LIST)/sizeof(UCHAR); - pChannelList = A_BAND_REGION_7_CHANNEL_LIST; - break; - case REGION_8_A_BAND: - num = sizeof(A_BAND_REGION_8_CHANNEL_LIST)/sizeof(UCHAR); - pChannelList = A_BAND_REGION_8_CHANNEL_LIST; - break; - case REGION_9_A_BAND: - num = sizeof(A_BAND_REGION_9_CHANNEL_LIST)/sizeof(UCHAR); - pChannelList = A_BAND_REGION_9_CHANNEL_LIST; - break; - - case REGION_10_A_BAND: - num = sizeof(A_BAND_REGION_10_CHANNEL_LIST)/sizeof(UCHAR); - pChannelList = A_BAND_REGION_10_CHANNEL_LIST; - break; - - case REGION_11_A_BAND: - num = sizeof(A_BAND_REGION_11_CHANNEL_LIST)/sizeof(UCHAR); - pChannelList = A_BAND_REGION_11_CHANNEL_LIST; - break; - - default: // Error. should never happen - DBGPRINT(RT_DEBUG_WARN,("countryregion=%d not support", pAd->CommonCfg.CountryRegionForABand)); - break; - } - - if (num != 0) - { - UCHAR RadarCh[15]={52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140}; - for (i=0; iTxPower[j].Channel) - NdisMoveMemory(&pAd->ChannelList[index+i], &pAd->TxPower[j], sizeof(CHANNEL_TX_POWER)); - } - for (j=0; j<15; j++) - { - if (pChannelList[i] == RadarCh[j]) - pAd->ChannelList[index+i].DfsReq = TRUE; - } - pAd->ChannelList[index+i].MaxTxPwr = 20; - } - index += num; - } - } - - pAd->ChannelListNum = index; - DBGPRINT(RT_DEBUG_TRACE,("country code=%d/%d, RFIC=%d, PHY mode=%d, support %d channels\n", - pAd->CommonCfg.CountryRegion, pAd->CommonCfg.CountryRegionForABand, pAd->RfIcType, pAd->CommonCfg.PhyMode, pAd->ChannelListNum)); -#ifdef DBG - for (i=0;iChannelListNum;i++) - { - DBGPRINT_RAW(RT_DEBUG_TRACE,("BuildChannel # %d :: Pwr0 = %d, Pwr1 =%d, \n ", pAd->ChannelList[i].Channel, pAd->ChannelList[i].Power, pAd->ChannelList[i].Power2)); - } -#endif -} - -/* - ========================================================================== - Description: - This routine return the first channel number according to the country - code selection and RF IC selection (signal band or dual band). It is called - whenever driver need to start a site survey of all supported channels. - Return: - ch - the first channel number of current country code setting - - IRQL = PASSIVE_LEVEL - - ========================================================================== - */ -UCHAR FirstChannel( - IN PRTMP_ADAPTER pAd) -{ - return pAd->ChannelList[0].Channel; -} - -/* - ========================================================================== - Description: - This routine returns the next channel number. This routine is called - during driver need to start a site survey of all supported channels. - Return: - next_channel - the next channel number valid in current country code setting. - Note: - return 0 if no more next channel - ========================================================================== - */ -UCHAR NextChannel( - IN PRTMP_ADAPTER pAd, - IN UCHAR channel) -{ - int i; - UCHAR next_channel = 0; - - for (i = 0; i < (pAd->ChannelListNum - 1); i++) - if (channel == pAd->ChannelList[i].Channel) - { - next_channel = pAd->ChannelList[i+1].Channel; - break; - } - return next_channel; -} - -/* - ========================================================================== - Description: - This routine is for Cisco Compatible Extensions 2.X - Spec31. AP Control of Client Transmit Power - Return: - None - Note: - Required by Aironet dBm(mW) - 0dBm(1mW), 1dBm(5mW), 13dBm(20mW), 15dBm(30mW), - 17dBm(50mw), 20dBm(100mW) - - We supported - 3dBm(Lowest), 6dBm(10%), 9dBm(25%), 12dBm(50%), - 14dBm(75%), 15dBm(100%) - - The client station's actual transmit power shall be within +/- 5dB of - the minimum value or next lower value. - ========================================================================== - */ -VOID ChangeToCellPowerLimit( - IN PRTMP_ADAPTER pAd, - IN UCHAR AironetCellPowerLimit) -{ - //valud 0xFF means that hasn't found power limit information - //from the AP's Beacon/Probe response. - if (AironetCellPowerLimit == 0xFF) - return; - - if (AironetCellPowerLimit < 6) //Used Lowest Power Percentage. - pAd->CommonCfg.TxPowerPercentage = 6; - else if (AironetCellPowerLimit < 9) - pAd->CommonCfg.TxPowerPercentage = 10; - else if (AironetCellPowerLimit < 12) - pAd->CommonCfg.TxPowerPercentage = 25; - else if (AironetCellPowerLimit < 14) - pAd->CommonCfg.TxPowerPercentage = 50; - else if (AironetCellPowerLimit < 15) - pAd->CommonCfg.TxPowerPercentage = 75; - else - pAd->CommonCfg.TxPowerPercentage = 100; //else used maximum - - if (pAd->CommonCfg.TxPowerPercentage > pAd->CommonCfg.TxPowerDefault) - pAd->CommonCfg.TxPowerPercentage = pAd->CommonCfg.TxPowerDefault; - -} - -CHAR ConvertToRssi( - IN PRTMP_ADAPTER pAd, - IN CHAR Rssi, - IN UCHAR RssiNumber) -{ - UCHAR RssiOffset, LNAGain; - - // Rssi equals to zero should be an invalid value - if (Rssi == 0) - return -99; - - LNAGain = GET_LNA_GAIN(pAd); - if (pAd->LatchRfRegs.Channel > 14) - { - if (RssiNumber == 0) - RssiOffset = pAd->ARssiOffset0; - else if (RssiNumber == 1) - RssiOffset = pAd->ARssiOffset1; - else - RssiOffset = pAd->ARssiOffset2; - } - else - { - if (RssiNumber == 0) - RssiOffset = pAd->BGRssiOffset0; - else if (RssiNumber == 1) - RssiOffset = pAd->BGRssiOffset1; - else - RssiOffset = pAd->BGRssiOffset2; - } - - return (-12 - RssiOffset - LNAGain - Rssi); -} - -/* - ========================================================================== - Description: - Scan next channel - ========================================================================== - */ -VOID ScanNextChannel( - IN PRTMP_ADAPTER pAd) -{ - HEADER_802_11 Hdr80211; - PUCHAR pOutBuffer = NULL; - NDIS_STATUS NStatus; - ULONG FrameLen = 0; - UCHAR SsidLen = 0, ScanType = pAd->MlmeAux.ScanType, BBPValue = 0; -#ifdef CONFIG_STA_SUPPORT - USHORT Status; - PHEADER_802_11 pHdr80211; -#endif // CONFIG_STA_SUPPORT // - UINT ScanTimeIn5gChannel = SHORT_CHANNEL_TIME; - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - if (MONITOR_ON(pAd)) - return; - } -#endif // CONFIG_STA_SUPPORT // - -#ifdef RALINK_ATE - // Nothing to do in ATE mode. - if (ATE_ON(pAd)) - return; -#endif // RALINK_ATE // - - if (pAd->MlmeAux.Channel == 0) - { - if ((pAd->CommonCfg.BBPCurrentBW == BW_40) -#ifdef CONFIG_STA_SUPPORT - && (INFRA_ON(pAd) - || (pAd->OpMode == OPMODE_AP)) -#endif // CONFIG_STA_SUPPORT // - ) - { - AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE); - AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel); - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); - BBPValue &= (~0x18); - BBPValue |= 0x10; - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); - DBGPRINT(RT_DEBUG_TRACE, ("SYNC - End of SCAN, restore to 40MHz channel %d, Total BSS[%02d]\n",pAd->CommonCfg.CentralChannel, pAd->ScanTab.BssNr)); - } - else - { - AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); - AsicLockChannel(pAd, pAd->CommonCfg.Channel); - DBGPRINT(RT_DEBUG_TRACE, ("SYNC - End of SCAN, restore to channel %d, Total BSS[%02d]\n",pAd->CommonCfg.Channel, pAd->ScanTab.BssNr)); - } - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - // - // To prevent data lost. - // Send an NULL data with turned PSM bit on to current associated AP before SCAN progress. - // Now, we need to send an NULL data with turned PSM bit off to AP, when scan progress done - // - if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) && (INFRA_ON(pAd))) - { - NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); - if (NStatus == NDIS_STATUS_SUCCESS) - { - pHdr80211 = (PHEADER_802_11) pOutBuffer; - MgtMacHeaderInit(pAd, pHdr80211, SUBTYPE_NULL_FUNC, 1, pAd->CommonCfg.Bssid, pAd->CommonCfg.Bssid); - pHdr80211->Duration = 0; - pHdr80211->FC.Type = BTYPE_DATA; - pHdr80211->FC.PwrMgmt = (pAd->StaCfg.Psm == PWR_SAVE); - - // Send using priority queue - MiniportMMRequest(pAd, 0, pOutBuffer, sizeof(HEADER_802_11)); - DBGPRINT(RT_DEBUG_TRACE, ("MlmeScanReqAction -- Send PSM Data frame\n")); - MlmeFreeMemory(pAd, pOutBuffer); - RTMPusecDelay(5000); - } - } - - pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; - Status = MLME_SUCCESS; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_SCAN_CONF, 2, &Status); - } -#endif // CONFIG_STA_SUPPORT // - - - RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS); - } -#ifdef RT2870 -#ifdef CONFIG_STA_SUPPORT - else if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST) && (pAd->OpMode == OPMODE_STA)) - { - pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; - MlmeCntlConfirm(pAd, MT2_SCAN_CONF, MLME_FAIL_NO_RESOURCE); - } -#endif // CONFIG_STA_SUPPORT // -#endif // RT2870 // - else - { -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - // BBP and RF are not accessible in PS mode, we has to wake them up first - if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) - AsicForceWakeup(pAd, TRUE); - - // leave PSM during scanning. otherwise we may lost ProbeRsp & BEACON - if (pAd->StaCfg.Psm == PWR_SAVE) - MlmeSetPsmBit(pAd, PWR_ACTIVE); - } -#endif // CONFIG_STA_SUPPORT // - - AsicSwitchChannel(pAd, pAd->MlmeAux.Channel, TRUE); - AsicLockChannel(pAd, pAd->MlmeAux.Channel); - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - if (pAd->MlmeAux.Channel > 14) - { - if ((pAd->CommonCfg.bIEEE80211H == 1) && RadarChannelCheck(pAd, pAd->MlmeAux.Channel)) - { - ScanType = SCAN_PASSIVE; - ScanTimeIn5gChannel = MIN_CHANNEL_TIME; - } - } - -#ifdef CARRIER_DETECTION_SUPPORT // Roger sync Carrier - // carrier detection - if (pAd->CommonCfg.CarrierDetect.Enable == TRUE) - { - ScanType = SCAN_PASSIVE; - ScanTimeIn5gChannel = MIN_CHANNEL_TIME; - } -#endif // CARRIER_DETECTION_SUPPORT // - } - -#endif // CONFIG_STA_SUPPORT // - - //Global country domain(ch1-11:active scan, ch12-14 passive scan) - if ((pAd->MlmeAux.Channel <= 14) && (pAd->MlmeAux.Channel >= 12) && ((pAd->CommonCfg.CountryRegion & 0x7f) == REGION_31_BG_BAND)) - { - ScanType = SCAN_PASSIVE; - } - - // We need to shorten active scan time in order for WZC connect issue - // Chnage the channel scan time for CISCO stuff based on its IAPP announcement - if (ScanType == FAST_SCAN_ACTIVE) - RTMPSetTimer(&pAd->MlmeAux.ScanTimer, FAST_ACTIVE_SCAN_TIME); -#ifdef CONFIG_STA_SUPPORT - else if (((ScanType == SCAN_CISCO_ACTIVE) || - (ScanType == SCAN_CISCO_PASSIVE) || - (ScanType == SCAN_CISCO_CHANNEL_LOAD) || - (ScanType == SCAN_CISCO_NOISE)) && (pAd->OpMode == OPMODE_STA)) - { - if (pAd->StaCfg.CCXScanTime < 25) - RTMPSetTimer(&pAd->MlmeAux.ScanTimer, pAd->StaCfg.CCXScanTime * 2); - else - RTMPSetTimer(&pAd->MlmeAux.ScanTimer, pAd->StaCfg.CCXScanTime); - } -#endif // CONFIG_STA_SUPPORT // - else // must be SCAN_PASSIVE or SCAN_ACTIVE - { - if ((pAd->CommonCfg.PhyMode == PHY_11ABG_MIXED) -#ifdef DOT11_N_SUPPORT - || (pAd->CommonCfg.PhyMode == PHY_11ABGN_MIXED) || (pAd->CommonCfg.PhyMode == PHY_11AGN_MIXED) -#endif // DOT11_N_SUPPORT // - ) - { - if (pAd->MlmeAux.Channel > 14) - RTMPSetTimer(&pAd->MlmeAux.ScanTimer, ScanTimeIn5gChannel); - else - RTMPSetTimer(&pAd->MlmeAux.ScanTimer, MIN_CHANNEL_TIME); - } - else - RTMPSetTimer(&pAd->MlmeAux.ScanTimer, MAX_CHANNEL_TIME); - } - - if ((ScanType == SCAN_ACTIVE) || (ScanType == FAST_SCAN_ACTIVE) || - (ScanType == SCAN_CISCO_ACTIVE)) - { - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory - if (NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_TRACE, ("SYNC - ScanNextChannel() allocate memory fail\n")); -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; - Status = MLME_FAIL_NO_RESOURCE; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_SCAN_CONF, 2, &Status); - } -#endif // CONFIG_STA_SUPPORT // - - return; - } - - // There is no need to send broadcast probe request if active scan is in effect. - if ((ScanType == SCAN_ACTIVE) || (ScanType == FAST_SCAN_ACTIVE) - ) - SsidLen = pAd->MlmeAux.SsidLen; - else - SsidLen = 0; - - MgtMacHeaderInit(pAd, &Hdr80211, SUBTYPE_PROBE_REQ, 0, BROADCAST_ADDR, BROADCAST_ADDR); - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(HEADER_802_11), &Hdr80211, - 1, &SsidIe, - 1, &SsidLen, - SsidLen, pAd->MlmeAux.Ssid, - 1, &SupRateIe, - 1, &pAd->CommonCfg.SupRateLen, - pAd->CommonCfg.SupRateLen, pAd->CommonCfg.SupRate, - END_OF_ARGS); - - if (pAd->CommonCfg.ExtRateLen) - { - ULONG Tmp; - MakeOutgoingFrame(pOutBuffer + FrameLen, &Tmp, - 1, &ExtRateIe, - 1, &pAd->CommonCfg.ExtRateLen, - pAd->CommonCfg.ExtRateLen, pAd->CommonCfg.ExtRate, - END_OF_ARGS); - FrameLen += Tmp; - } - -#ifdef DOT11_N_SUPPORT - if (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) - { - ULONG Tmp; - UCHAR HtLen; - UCHAR BROADCOM[4] = {0x0, 0x90, 0x4c, 0x33}; -#ifdef RT_BIG_ENDIAN - HT_CAPABILITY_IE HtCapabilityTmp; -#endif - if (pAd->bBroadComHT == TRUE) - { - HtLen = pAd->MlmeAux.HtCapabilityLen + 4; -#ifdef RT_BIG_ENDIAN - NdisMoveMemory(&HtCapabilityTmp, &pAd->MlmeAux.HtCapability, SIZE_HT_CAP_IE); - *(USHORT *)(&HtCapabilityTmp.HtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.HtCapInfo)); - *(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo)); - - MakeOutgoingFrame(pOutBuffer + FrameLen, &Tmp, - 1, &WpaIe, - 1, &HtLen, - 4, &BROADCOM[0], - pAd->MlmeAux.HtCapabilityLen, &HtCapabilityTmp, - END_OF_ARGS); -#else - MakeOutgoingFrame(pOutBuffer + FrameLen, &Tmp, - 1, &WpaIe, - 1, &HtLen, - 4, &BROADCOM[0], - pAd->MlmeAux.HtCapabilityLen, &pAd->MlmeAux.HtCapability, - END_OF_ARGS); -#endif // RT_BIG_ENDIAN // - } - else - { - HtLen = pAd->MlmeAux.HtCapabilityLen; -#ifdef RT_BIG_ENDIAN - NdisMoveMemory(&HtCapabilityTmp, &pAd->CommonCfg.HtCapability, SIZE_HT_CAP_IE); - *(USHORT *)(&HtCapabilityTmp.HtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.HtCapInfo)); - *(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo)); - - MakeOutgoingFrame(pOutBuffer + FrameLen, &Tmp, - 1, &HtCapIe, - 1, &HtLen, - HtLen, &HtCapabilityTmp, - END_OF_ARGS); -#else - MakeOutgoingFrame(pOutBuffer + FrameLen, &Tmp, - 1, &HtCapIe, - 1, &HtLen, - HtLen, &pAd->CommonCfg.HtCapability, - END_OF_ARGS); -#endif // RT_BIG_ENDIAN // - } - FrameLen += Tmp; - -#ifdef DOT11N_DRAFT3 - if (pAd->CommonCfg.BACapability.field.b2040CoexistScanSup == 1) - { - ULONG Tmp; - HtLen = 1; - MakeOutgoingFrame(pOutBuffer + FrameLen, &Tmp, - 1, &ExtHtCapIe, - 1, &HtLen, - 1, &pAd->CommonCfg.BSSCoexist2040.word, - END_OF_ARGS); - - FrameLen += Tmp; - } -#endif // DOT11N_DRAFT3 // - } -#endif // DOT11_N_SUPPORT // - - - MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); - } - - // For SCAN_CISCO_PASSIVE, do nothing and silently wait for beacon or other probe reponse - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - pAd->Mlme.SyncMachine.CurrState = SCAN_LISTEN; -#endif // CONFIG_STA_SUPPORT // - - } -} - -VOID MgtProbReqMacHeaderInit( - IN PRTMP_ADAPTER pAd, - IN OUT PHEADER_802_11 pHdr80211, - IN UCHAR SubType, - IN UCHAR ToDs, - IN PUCHAR pDA, - IN PUCHAR pBssid) -{ - NdisZeroMemory(pHdr80211, sizeof(HEADER_802_11)); - - pHdr80211->FC.Type = BTYPE_MGMT; - pHdr80211->FC.SubType = SubType; - if (SubType == SUBTYPE_ACK) - pHdr80211->FC.Type = BTYPE_CNTL; - pHdr80211->FC.ToDs = ToDs; - COPY_MAC_ADDR(pHdr80211->Addr1, pDA); - COPY_MAC_ADDR(pHdr80211->Addr2, pAd->CurrentAddress); - COPY_MAC_ADDR(pHdr80211->Addr3, pBssid); -} - - +#include "../../rt2860/common/cmm_sync.c" diff --git a/drivers/staging/rt2870/common/cmm_wpa.c b/drivers/staging/rt2870/common/cmm_wpa.c index d2c24bd49e75..04a54bb21853 100644 --- a/drivers/staging/rt2870/common/cmm_wpa.c +++ b/drivers/staging/rt2870/common/cmm_wpa.c @@ -1,1654 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - wpa.c - - Abstract: - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Jan Lee 03-07-22 Initial - Paul Lin 03-11-28 Modify for supplicant -*/ -#include "../rt_config.h" -// WPA OUI -UCHAR OUI_WPA_NONE_AKM[4] = {0x00, 0x50, 0xF2, 0x00}; -UCHAR OUI_WPA_VERSION[4] = {0x00, 0x50, 0xF2, 0x01}; -UCHAR OUI_WPA_WEP40[4] = {0x00, 0x50, 0xF2, 0x01}; -UCHAR OUI_WPA_TKIP[4] = {0x00, 0x50, 0xF2, 0x02}; -UCHAR OUI_WPA_CCMP[4] = {0x00, 0x50, 0xF2, 0x04}; -UCHAR OUI_WPA_WEP104[4] = {0x00, 0x50, 0xF2, 0x05}; -UCHAR OUI_WPA_8021X_AKM[4] = {0x00, 0x50, 0xF2, 0x01}; -UCHAR OUI_WPA_PSK_AKM[4] = {0x00, 0x50, 0xF2, 0x02}; -// WPA2 OUI -UCHAR OUI_WPA2_WEP40[4] = {0x00, 0x0F, 0xAC, 0x01}; -UCHAR OUI_WPA2_TKIP[4] = {0x00, 0x0F, 0xAC, 0x02}; -UCHAR OUI_WPA2_CCMP[4] = {0x00, 0x0F, 0xAC, 0x04}; -UCHAR OUI_WPA2_8021X_AKM[4] = {0x00, 0x0F, 0xAC, 0x01}; -UCHAR OUI_WPA2_PSK_AKM[4] = {0x00, 0x0F, 0xAC, 0x02}; -UCHAR OUI_WPA2_WEP104[4] = {0x00, 0x0F, 0xAC, 0x05}; -// MSA OUI -UCHAR OUI_MSA_8021X_AKM[4] = {0x00, 0x0F, 0xAC, 0x05}; // Not yet final - IEEE 802.11s-D1.06 -UCHAR OUI_MSA_PSK_AKM[4] = {0x00, 0x0F, 0xAC, 0x06}; // Not yet final - IEEE 802.11s-D1.06 - -/* - ======================================================================== - - Routine Description: - The pseudo-random function(PRF) that hashes various inputs to - derive a pseudo-random value. To add liveness to the pseudo-random - value, a nonce should be one of the inputs. - - It is used to generate PTK, GTK or some specific random value. - - Arguments: - UCHAR *key, - the key material for HMAC_SHA1 use - INT key_len - the length of key - UCHAR *prefix - a prefix label - INT prefix_len - the length of the label - UCHAR *data - a specific data with variable length - INT data_len - the length of a specific data - INT len - the output lenght - - Return Value: - UCHAR *output - the calculated result - - Note: - 802.11i-2004 Annex H.3 - - ======================================================================== -*/ -VOID PRF( - IN UCHAR *key, - IN INT key_len, - IN UCHAR *prefix, - IN INT prefix_len, - IN UCHAR *data, - IN INT data_len, - OUT UCHAR *output, - IN INT len) -{ - INT i; - UCHAR *input; - INT currentindex = 0; - INT total_len; - - // Allocate memory for input - os_alloc_mem(NULL, (PUCHAR *)&input, 1024); - - if (input == NULL) - { - DBGPRINT(RT_DEBUG_ERROR, ("!!!PRF: no memory!!!\n")); - return; - } - - // Generate concatenation input - NdisMoveMemory(input, prefix, prefix_len); - - // Concatenate a single octet containing 0 - input[prefix_len] = 0; - - // Concatenate specific data - NdisMoveMemory(&input[prefix_len + 1], data, data_len); - total_len = prefix_len + 1 + data_len; - - // Concatenate a single octet containing 0 - // This octet shall be update later - input[total_len] = 0; - total_len++; - - // Iterate to calculate the result by hmac-sha-1 - // Then concatenate to last result - for (i = 0; i < (len + 19) / 20; i++) - { - HMAC_SHA1(input, total_len, key, key_len, &output[currentindex]); - currentindex += 20; - - // update the last octet - input[total_len - 1]++; - } - os_free_mem(NULL, input); -} - -/* - ======================================================================== - - Routine Description: - It utilizes PRF-384 or PRF-512 to derive session-specific keys from a PMK. - It shall be called by 4-way handshake processing. - - Arguments: - pAd - pointer to our pAdapter context - PMK - pointer to PMK - ANonce - pointer to ANonce - AA - pointer to Authenticator Address - SNonce - pointer to SNonce - SA - pointer to Supplicant Address - len - indicate the length of PTK (octet) - - Return Value: - Output pointer to the PTK - - Note: - Refer to IEEE 802.11i-2004 8.5.1.2 - - ======================================================================== -*/ -VOID WpaCountPTK( - IN PRTMP_ADAPTER pAd, - IN UCHAR *PMK, - IN UCHAR *ANonce, - IN UCHAR *AA, - IN UCHAR *SNonce, - IN UCHAR *SA, - OUT UCHAR *output, - IN UINT len) -{ - UCHAR concatenation[76]; - UINT CurrPos = 0; - UCHAR temp[32]; - UCHAR Prefix[] = {'P', 'a', 'i', 'r', 'w', 'i', 's', 'e', ' ', 'k', 'e', 'y', ' ', - 'e', 'x', 'p', 'a', 'n', 's', 'i', 'o', 'n'}; - - // initiate the concatenation input - NdisZeroMemory(temp, sizeof(temp)); - NdisZeroMemory(concatenation, 76); - - // Get smaller address - if (RTMPCompareMemory(SA, AA, 6) == 1) - NdisMoveMemory(concatenation, AA, 6); - else - NdisMoveMemory(concatenation, SA, 6); - CurrPos += 6; - - // Get larger address - if (RTMPCompareMemory(SA, AA, 6) == 1) - NdisMoveMemory(&concatenation[CurrPos], SA, 6); - else - NdisMoveMemory(&concatenation[CurrPos], AA, 6); - - // store the larger mac address for backward compatible of - // ralink proprietary STA-key issue - NdisMoveMemory(temp, &concatenation[CurrPos], MAC_ADDR_LEN); - CurrPos += 6; - - // Get smaller Nonce - if (RTMPCompareMemory(ANonce, SNonce, 32) == 0) - NdisMoveMemory(&concatenation[CurrPos], temp, 32); // patch for ralink proprietary STA-key issue - else if (RTMPCompareMemory(ANonce, SNonce, 32) == 1) - NdisMoveMemory(&concatenation[CurrPos], SNonce, 32); - else - NdisMoveMemory(&concatenation[CurrPos], ANonce, 32); - CurrPos += 32; - - // Get larger Nonce - if (RTMPCompareMemory(ANonce, SNonce, 32) == 0) - NdisMoveMemory(&concatenation[CurrPos], temp, 32); // patch for ralink proprietary STA-key issue - else if (RTMPCompareMemory(ANonce, SNonce, 32) == 1) - NdisMoveMemory(&concatenation[CurrPos], ANonce, 32); - else - NdisMoveMemory(&concatenation[CurrPos], SNonce, 32); - CurrPos += 32; - - hex_dump("concatenation=", concatenation, 76); - - // Use PRF to generate PTK - PRF(PMK, LEN_MASTER_KEY, Prefix, 22, concatenation, 76, output, len); - -} - -/* - ======================================================================== - - Routine Description: - Generate random number by software. - - Arguments: - pAd - pointer to our pAdapter context - macAddr - pointer to local MAC address - - Return Value: - - Note: - 802.1ii-2004 Annex H.5 - - ======================================================================== -*/ -VOID GenRandom( - IN PRTMP_ADAPTER pAd, - IN UCHAR *macAddr, - OUT UCHAR *random) -{ - INT i, curr; - UCHAR local[80], KeyCounter[32]; - UCHAR result[80]; - ULONG CurrentTime; - UCHAR prefix[] = {'I', 'n', 'i', 't', ' ', 'C', 'o', 'u', 'n', 't', 'e', 'r'}; - - // Zero the related information - NdisZeroMemory(result, 80); - NdisZeroMemory(local, 80); - NdisZeroMemory(KeyCounter, 32); - - for (i = 0; i < 32; i++) - { - // copy the local MAC address - COPY_MAC_ADDR(local, macAddr); - curr = MAC_ADDR_LEN; - - // concatenate the current time - NdisGetSystemUpTime(&CurrentTime); - NdisMoveMemory(&local[curr], &CurrentTime, sizeof(CurrentTime)); - curr += sizeof(CurrentTime); - - // concatenate the last result - NdisMoveMemory(&local[curr], result, 32); - curr += 32; - - // concatenate a variable - NdisMoveMemory(&local[curr], &i, 2); - curr += 2; - - // calculate the result - PRF(KeyCounter, 32, prefix,12, local, curr, result, 32); - } - - NdisMoveMemory(random, result, 32); -} - -/* - ======================================================================== - - Routine Description: - Build cipher suite in RSN-IE. - It only shall be called by RTMPMakeRSNIE. - - Arguments: - pAd - pointer to our pAdapter context - ElementID - indicate the WPA1 or WPA2 - WepStatus - indicate the encryption type - bMixCipher - a boolean to indicate the pairwise cipher and group - cipher are the same or not - - Return Value: - - Note: - - ======================================================================== -*/ -static VOID RTMPInsertRsnIeCipher( - IN PRTMP_ADAPTER pAd, - IN UCHAR ElementID, - IN UINT WepStatus, - IN BOOLEAN bMixCipher, - IN UCHAR FlexibleCipher, - OUT PUCHAR pRsnIe, - OUT UCHAR *rsn_len) -{ - UCHAR PairwiseCnt; - - *rsn_len = 0; - - // decide WPA2 or WPA1 - if (ElementID == Wpa2Ie) - { - RSNIE2 *pRsnie_cipher = (RSNIE2*)pRsnIe; - - // Assign the verson as 1 - pRsnie_cipher->version = 1; - - switch (WepStatus) - { - // TKIP mode - case Ndis802_11Encryption2Enabled: - NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA2_TKIP, 4); - pRsnie_cipher->ucount = 1; - NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA2_TKIP, 4); - *rsn_len = sizeof(RSNIE2); - break; - - // AES mode - case Ndis802_11Encryption3Enabled: - if (bMixCipher) - NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA2_TKIP, 4); - else - NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA2_CCMP, 4); - pRsnie_cipher->ucount = 1; - NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA2_CCMP, 4); - *rsn_len = sizeof(RSNIE2); - break; - - // TKIP-AES mix mode - case Ndis802_11Encryption4Enabled: - NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA2_TKIP, 4); - - PairwiseCnt = 1; - // Insert WPA2 TKIP as the first pairwise cipher - if (MIX_CIPHER_WPA2_TKIP_ON(FlexibleCipher)) - { - NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA2_TKIP, 4); - // Insert WPA2 AES as the secondary pairwise cipher - if (MIX_CIPHER_WPA2_AES_ON(FlexibleCipher)) - { - NdisMoveMemory(pRsnie_cipher->ucast[0].oui + 4, OUI_WPA2_CCMP, 4); - PairwiseCnt = 2; - } - } - else - { - // Insert WPA2 AES as the first pairwise cipher - NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA2_CCMP, 4); - } - - pRsnie_cipher->ucount = PairwiseCnt; - *rsn_len = sizeof(RSNIE2) + (4 * (PairwiseCnt - 1)); - break; - } - -#ifdef CONFIG_STA_SUPPORT - if ((pAd->OpMode == OPMODE_STA) && - (pAd->StaCfg.GroupCipher != Ndis802_11Encryption2Enabled) && - (pAd->StaCfg.GroupCipher != Ndis802_11Encryption3Enabled)) - { - UINT GroupCipher = pAd->StaCfg.GroupCipher; - switch(GroupCipher) - { - case Ndis802_11GroupWEP40Enabled: - NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA2_WEP40, 4); - break; - case Ndis802_11GroupWEP104Enabled: - NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA2_WEP104, 4); - break; - } - } -#endif // CONFIG_STA_SUPPORT // - - // swap for big-endian platform - pRsnie_cipher->version = cpu2le16(pRsnie_cipher->version); - pRsnie_cipher->ucount = cpu2le16(pRsnie_cipher->ucount); - } - else - { - RSNIE *pRsnie_cipher = (RSNIE*)pRsnIe; - - // Assign OUI and version - NdisMoveMemory(pRsnie_cipher->oui, OUI_WPA_VERSION, 4); - pRsnie_cipher->version = 1; - - switch (WepStatus) - { - // TKIP mode - case Ndis802_11Encryption2Enabled: - NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA_TKIP, 4); - pRsnie_cipher->ucount = 1; - NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA_TKIP, 4); - *rsn_len = sizeof(RSNIE); - break; - - // AES mode - case Ndis802_11Encryption3Enabled: - if (bMixCipher) - NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA_TKIP, 4); - else - NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA_CCMP, 4); - pRsnie_cipher->ucount = 1; - NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA_CCMP, 4); - *rsn_len = sizeof(RSNIE); - break; - - // TKIP-AES mix mode - case Ndis802_11Encryption4Enabled: - NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA_TKIP, 4); - - PairwiseCnt = 1; - // Insert WPA TKIP as the first pairwise cipher - if (MIX_CIPHER_WPA_TKIP_ON(FlexibleCipher)) - { - NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA_TKIP, 4); - // Insert WPA AES as the secondary pairwise cipher - if (MIX_CIPHER_WPA_AES_ON(FlexibleCipher)) - { - NdisMoveMemory(pRsnie_cipher->ucast[0].oui + 4, OUI_WPA_CCMP, 4); - PairwiseCnt = 2; - } - } - else - { - // Insert WPA AES as the first pairwise cipher - NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA_CCMP, 4); - } - - pRsnie_cipher->ucount = PairwiseCnt; - *rsn_len = sizeof(RSNIE) + (4 * (PairwiseCnt - 1)); - break; - } - -#ifdef CONFIG_STA_SUPPORT - if ((pAd->OpMode == OPMODE_STA) && - (pAd->StaCfg.GroupCipher != Ndis802_11Encryption2Enabled) && - (pAd->StaCfg.GroupCipher != Ndis802_11Encryption3Enabled)) - { - UINT GroupCipher = pAd->StaCfg.GroupCipher; - switch(GroupCipher) - { - case Ndis802_11GroupWEP40Enabled: - NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA_WEP40, 4); - break; - case Ndis802_11GroupWEP104Enabled: - NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA_WEP104, 4); - break; - } - } -#endif // CONFIG_STA_SUPPORT // - - // swap for big-endian platform - pRsnie_cipher->version = cpu2le16(pRsnie_cipher->version); - pRsnie_cipher->ucount = cpu2le16(pRsnie_cipher->ucount); - } -} - -/* - ======================================================================== - - Routine Description: - Build AKM suite in RSN-IE. - It only shall be called by RTMPMakeRSNIE. - - Arguments: - pAd - pointer to our pAdapter context - ElementID - indicate the WPA1 or WPA2 - AuthMode - indicate the authentication mode - apidx - indicate the interface index - - Return Value: - - Note: - - ======================================================================== -*/ -static VOID RTMPInsertRsnIeAKM( - IN PRTMP_ADAPTER pAd, - IN UCHAR ElementID, - IN UINT AuthMode, - IN UCHAR apidx, - OUT PUCHAR pRsnIe, - OUT UCHAR *rsn_len) -{ - RSNIE_AUTH *pRsnie_auth; - - pRsnie_auth = (RSNIE_AUTH*)(pRsnIe + (*rsn_len)); - - // decide WPA2 or WPA1 - if (ElementID == Wpa2Ie) - { - switch (AuthMode) - { - case Ndis802_11AuthModeWPA2: - case Ndis802_11AuthModeWPA1WPA2: - pRsnie_auth->acount = 1; - NdisMoveMemory(pRsnie_auth->auth[0].oui, OUI_WPA2_8021X_AKM, 4); - break; - - case Ndis802_11AuthModeWPA2PSK: - case Ndis802_11AuthModeWPA1PSKWPA2PSK: - pRsnie_auth->acount = 1; - NdisMoveMemory(pRsnie_auth->auth[0].oui, OUI_WPA2_PSK_AKM, 4); - break; - } - } - else - { - switch (AuthMode) - { - case Ndis802_11AuthModeWPA: - case Ndis802_11AuthModeWPA1WPA2: - pRsnie_auth->acount = 1; - NdisMoveMemory(pRsnie_auth->auth[0].oui, OUI_WPA_8021X_AKM, 4); - break; - - case Ndis802_11AuthModeWPAPSK: - case Ndis802_11AuthModeWPA1PSKWPA2PSK: - pRsnie_auth->acount = 1; - NdisMoveMemory(pRsnie_auth->auth[0].oui, OUI_WPA_PSK_AKM, 4); - break; - - case Ndis802_11AuthModeWPANone: - pRsnie_auth->acount = 1; - NdisMoveMemory(pRsnie_auth->auth[0].oui, OUI_WPA_NONE_AKM, 4); - break; - } - } - - pRsnie_auth->acount = cpu2le16(pRsnie_auth->acount); - - (*rsn_len) += sizeof(RSNIE_AUTH); // update current RSNIE length - -} - -/* - ======================================================================== - - Routine Description: - Build capability in RSN-IE. - It only shall be called by RTMPMakeRSNIE. - - Arguments: - pAd - pointer to our pAdapter context - ElementID - indicate the WPA1 or WPA2 - apidx - indicate the interface index - - Return Value: - - Note: - - ======================================================================== -*/ -static VOID RTMPInsertRsnIeCap( - IN PRTMP_ADAPTER pAd, - IN UCHAR ElementID, - IN UCHAR apidx, - OUT PUCHAR pRsnIe, - OUT UCHAR *rsn_len) -{ - RSN_CAPABILITIES *pRSN_Cap; - - // it could be ignored in WPA1 mode - if (ElementID == WpaIe) - return; - - pRSN_Cap = (RSN_CAPABILITIES*)(pRsnIe + (*rsn_len)); - - - pRSN_Cap->word = cpu2le16(pRSN_Cap->word); - - (*rsn_len) += sizeof(RSN_CAPABILITIES); // update current RSNIE length - -} - - -/* - ======================================================================== - - Routine Description: - Build RSN IE context. It is not included element-ID and length. - - Arguments: - pAd - pointer to our pAdapter context - AuthMode - indicate the authentication mode - WepStatus - indicate the encryption type - apidx - indicate the interface index - - Return Value: - - Note: - - ======================================================================== -*/ -VOID RTMPMakeRSNIE( - IN PRTMP_ADAPTER pAd, - IN UINT AuthMode, - IN UINT WepStatus, - IN UCHAR apidx) -{ - PUCHAR pRsnIe = NULL; // primary RSNIE - UCHAR *rsnielen_cur_p = 0; // the length of the primary RSNIE - UCHAR *rsnielen_ex_cur_p = 0; // the length of the secondary RSNIE - UCHAR PrimaryRsnie; - BOOLEAN bMixCipher = FALSE; // indicate the pairwise and group cipher are different - UCHAR p_offset; - WPA_MIX_PAIR_CIPHER FlexibleCipher = MIX_CIPHER_NOTUSE; // it provide the more flexible cipher combination in WPA-WPA2 and TKIPAES mode - - rsnielen_cur_p = NULL; - rsnielen_ex_cur_p = NULL; - - { -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { -#ifdef WPA_SUPPLICANT_SUPPORT - if (pAd->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_DISABLE) - { - if (AuthMode < Ndis802_11AuthModeWPA) - return; - } - else -#endif // WPA_SUPPLICANT_SUPPORT // - { - // Support WPAPSK or WPA2PSK in STA-Infra mode - // Support WPANone in STA-Adhoc mode - if ((AuthMode != Ndis802_11AuthModeWPAPSK) && - (AuthMode != Ndis802_11AuthModeWPA2PSK) && - (AuthMode != Ndis802_11AuthModeWPANone) - ) - return; - } - - DBGPRINT(RT_DEBUG_TRACE,("==> RTMPMakeRSNIE(STA)\n")); - - // Zero RSNIE context - pAd->StaCfg.RSNIE_Len = 0; - NdisZeroMemory(pAd->StaCfg.RSN_IE, MAX_LEN_OF_RSNIE); - - // Pointer to RSNIE - rsnielen_cur_p = &pAd->StaCfg.RSNIE_Len; - pRsnIe = pAd->StaCfg.RSN_IE; - - bMixCipher = pAd->StaCfg.bMixCipher; - } -#endif // CONFIG_STA_SUPPORT // - } - - // indicate primary RSNIE as WPA or WPA2 - if ((AuthMode == Ndis802_11AuthModeWPA) || - (AuthMode == Ndis802_11AuthModeWPAPSK) || - (AuthMode == Ndis802_11AuthModeWPANone) || - (AuthMode == Ndis802_11AuthModeWPA1WPA2) || - (AuthMode == Ndis802_11AuthModeWPA1PSKWPA2PSK)) - PrimaryRsnie = WpaIe; - else - PrimaryRsnie = Wpa2Ie; - - { - // Build the primary RSNIE - // 1. insert cipher suite - RTMPInsertRsnIeCipher(pAd, PrimaryRsnie, WepStatus, bMixCipher, FlexibleCipher, pRsnIe, &p_offset); - - // 2. insert AKM - RTMPInsertRsnIeAKM(pAd, PrimaryRsnie, AuthMode, apidx, pRsnIe, &p_offset); - - // 3. insert capability - RTMPInsertRsnIeCap(pAd, PrimaryRsnie, apidx, pRsnIe, &p_offset); - } - - // 4. update the RSNIE length - *rsnielen_cur_p = p_offset; - - hex_dump("The primary RSNIE", pRsnIe, (*rsnielen_cur_p)); - - -} - -/* - ========================================================================== - Description: - Check whether the received frame is EAP frame. - - Arguments: - pAd - pointer to our pAdapter context - pEntry - pointer to active entry - pData - the received frame - DataByteCount - the received frame's length - FromWhichBSSID - indicate the interface index - - Return: - TRUE - This frame is EAP frame - FALSE - otherwise - ========================================================================== -*/ -BOOLEAN RTMPCheckWPAframe( - IN PRTMP_ADAPTER pAd, - IN PMAC_TABLE_ENTRY pEntry, - IN PUCHAR pData, - IN ULONG DataByteCount, - IN UCHAR FromWhichBSSID) -{ - ULONG Body_len; - BOOLEAN Cancelled; - - - if(DataByteCount < (LENGTH_802_1_H + LENGTH_EAPOL_H)) - return FALSE; - - - // Skip LLC header - if (NdisEqualMemory(SNAP_802_1H, pData, 6) || - // Cisco 1200 AP may send packet with SNAP_BRIDGE_TUNNEL - NdisEqualMemory(SNAP_BRIDGE_TUNNEL, pData, 6)) - { - pData += 6; - } - // Skip 2-bytes EAPoL type - if (NdisEqualMemory(EAPOL, pData, 2)) - { - pData += 2; - } - else - return FALSE; - - switch (*(pData+1)) - { - case EAPPacket: - Body_len = (*(pData+2)<<8) | (*(pData+3)); - DBGPRINT(RT_DEBUG_TRACE, ("Receive EAP-Packet frame, TYPE = 0, Length = %ld\n", Body_len)); - break; - case EAPOLStart: - DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL-Start frame, TYPE = 1 \n")); - if (pEntry->EnqueueEapolStartTimerRunning != EAPOL_START_DISABLE) - { - DBGPRINT(RT_DEBUG_TRACE, ("Cancel the EnqueueEapolStartTimerRunning \n")); - RTMPCancelTimer(&pEntry->EnqueueStartForPSKTimer, &Cancelled); - pEntry->EnqueueEapolStartTimerRunning = EAPOL_START_DISABLE; - } - break; - case EAPOLLogoff: - DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOLLogoff frame, TYPE = 2 \n")); - break; - case EAPOLKey: - Body_len = (*(pData+2)<<8) | (*(pData+3)); - DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL-Key frame, TYPE = 3, Length = %ld\n", Body_len)); - break; - case EAPOLASFAlert: - DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOLASFAlert frame, TYPE = 4 \n")); - break; - default: - return FALSE; - - } - return TRUE; -} - - -/* - ========================================================================== - Description: - ENCRYPT AES GTK before sending in EAPOL frame. - AES GTK length = 128 bit, so fix blocks for aes-key-wrap as 2 in this function. - This function references to RFC 3394 for aes key wrap algorithm. - Return: - ========================================================================== -*/ -VOID AES_GTK_KEY_WRAP( - IN UCHAR *key, - IN UCHAR *plaintext, - IN UCHAR p_len, - OUT UCHAR *ciphertext) -{ - UCHAR A[8], BIN[16], BOUT[16]; - UCHAR R[512]; - INT num_blocks = p_len/8; // unit:64bits - INT i, j; - aes_context aesctx; - UCHAR xor; - - rtmp_aes_set_key(&aesctx, key, 128); - - // Init IA - for (i = 0; i < 8; i++) - A[i] = 0xa6; - - //Input plaintext - for (i = 0; i < num_blocks; i++) - { - for (j = 0 ; j < 8; j++) - R[8 * (i + 1) + j] = plaintext[8 * i + j]; - } - - // Key Mix - for (j = 0; j < 6; j++) - { - for(i = 1; i <= num_blocks; i++) - { - //phase 1 - NdisMoveMemory(BIN, A, 8); - NdisMoveMemory(&BIN[8], &R[8 * i], 8); - rtmp_aes_encrypt(&aesctx, BIN, BOUT); - - NdisMoveMemory(A, &BOUT[0], 8); - xor = num_blocks * j + i; - A[7] = BOUT[7] ^ xor; - NdisMoveMemory(&R[8 * i], &BOUT[8], 8); - } - } - - // Output ciphertext - NdisMoveMemory(ciphertext, A, 8); - - for (i = 1; i <= num_blocks; i++) - { - for (j = 0 ; j < 8; j++) - ciphertext[8 * i + j] = R[8 * i + j]; - } -} - - -/* - ======================================================================== - - Routine Description: - Misc function to decrypt AES body - - Arguments: - - Return Value: - - Note: - This function references to RFC 3394 for aes key unwrap algorithm. - - ======================================================================== -*/ -VOID AES_GTK_KEY_UNWRAP( - IN UCHAR *key, - OUT UCHAR *plaintext, - IN UCHAR c_len, - IN UCHAR *ciphertext) - -{ - UCHAR A[8], BIN[16], BOUT[16]; - UCHAR xor; - INT i, j; - aes_context aesctx; - UCHAR *R; - INT num_blocks = c_len/8; // unit:64bits - - - os_alloc_mem(NULL, (PUCHAR *)&R, 512); - - if (R == NULL) - { - DBGPRINT(RT_DEBUG_ERROR, ("!!!AES_GTK_KEY_UNWRAP: no memory!!!\n")); - return; - } /* End of if */ - - // Initialize - NdisMoveMemory(A, ciphertext, 8); - //Input plaintext - for(i = 0; i < (c_len-8); i++) - { - R[ i] = ciphertext[i + 8]; - } - - rtmp_aes_set_key(&aesctx, key, 128); - - for(j = 5; j >= 0; j--) - { - for(i = (num_blocks-1); i > 0; i--) - { - xor = (num_blocks -1 )* j + i; - NdisMoveMemory(BIN, A, 8); - BIN[7] = A[7] ^ xor; - NdisMoveMemory(&BIN[8], &R[(i-1)*8], 8); - rtmp_aes_decrypt(&aesctx, BIN, BOUT); - NdisMoveMemory(A, &BOUT[0], 8); - NdisMoveMemory(&R[(i-1)*8], &BOUT[8], 8); - } - } - - // OUTPUT - for(i = 0; i < c_len; i++) - { - plaintext[i] = R[i]; - } - - - os_free_mem(NULL, R); -} - -/* - ========================================================================== - Description: - Report the EAP message type - - Arguments: - msg - EAPOL_PAIR_MSG_1 - EAPOL_PAIR_MSG_2 - EAPOL_PAIR_MSG_3 - EAPOL_PAIR_MSG_4 - EAPOL_GROUP_MSG_1 - EAPOL_GROUP_MSG_2 - - Return: - message type string - - ========================================================================== -*/ -CHAR *GetEapolMsgType(CHAR msg) -{ - if(msg == EAPOL_PAIR_MSG_1) - return "Pairwise Message 1"; - else if(msg == EAPOL_PAIR_MSG_2) - return "Pairwise Message 2"; - else if(msg == EAPOL_PAIR_MSG_3) - return "Pairwise Message 3"; - else if(msg == EAPOL_PAIR_MSG_4) - return "Pairwise Message 4"; - else if(msg == EAPOL_GROUP_MSG_1) - return "Group Message 1"; - else if(msg == EAPOL_GROUP_MSG_2) - return "Group Message 2"; - else - return "Invalid Message"; -} - - -/* - ======================================================================== - - Routine Description: - Check Sanity RSN IE of EAPoL message - - Arguments: - - Return Value: - - - ======================================================================== -*/ -BOOLEAN RTMPCheckRSNIE( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pData, - IN UCHAR DataLen, - IN MAC_TABLE_ENTRY *pEntry, - OUT UCHAR *Offset) -{ - PUCHAR pVIE; - UCHAR len; - PEID_STRUCT pEid; - BOOLEAN result = FALSE; - - pVIE = pData; - len = DataLen; - *Offset = 0; - - while (len > sizeof(RSNIE2)) - { - pEid = (PEID_STRUCT) pVIE; - // WPA RSN IE - if ((pEid->Eid == IE_WPA) && (NdisEqualMemory(pEid->Octet, WPA_OUI, 4))) - { - if ((pEntry->AuthMode == Ndis802_11AuthModeWPA || pEntry->AuthMode == Ndis802_11AuthModeWPAPSK) && - (NdisEqualMemory(pVIE, pEntry->RSN_IE, pEntry->RSNIE_Len)) && - (pEntry->RSNIE_Len == (pEid->Len + 2))) - { - result = TRUE; - } - - *Offset += (pEid->Len + 2); - } - // WPA2 RSN IE - else if ((pEid->Eid == IE_RSN) && (NdisEqualMemory(pEid->Octet + 2, RSN_OUI, 3))) - { - if ((pEntry->AuthMode == Ndis802_11AuthModeWPA2 || pEntry->AuthMode == Ndis802_11AuthModeWPA2PSK) && - (NdisEqualMemory(pVIE, pEntry->RSN_IE, pEntry->RSNIE_Len)) && - (pEntry->RSNIE_Len == (pEid->Len + 2))/* ToDo-AlbertY for mesh*/) - { - result = TRUE; - } - - *Offset += (pEid->Len + 2); - } - else - { - break; - } - - pVIE += (pEid->Len + 2); - len -= (pEid->Len + 2); - } - - - return result; - -} - - -/* - ======================================================================== - - Routine Description: - Parse KEYDATA field. KEYDATA[] May contain 2 RSN IE and optionally GTK. - GTK is encaptulated in KDE format at p.83 802.11i D10 - - Arguments: - - Return Value: - - Note: - 802.11i D10 - - ======================================================================== -*/ -BOOLEAN RTMPParseEapolKeyData( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pKeyData, - IN UCHAR KeyDataLen, - IN UCHAR GroupKeyIndex, - IN UCHAR MsgType, - IN BOOLEAN bWPA2, - IN MAC_TABLE_ENTRY *pEntry) -{ - PKDE_ENCAP pKDE = NULL; - PUCHAR pMyKeyData = pKeyData; - UCHAR KeyDataLength = KeyDataLen; - UCHAR GTKLEN = 0; - UCHAR DefaultIdx = 0; - UCHAR skip_offset; - - // Verify The RSN IE contained in pairewise_msg_2 && pairewise_msg_3 and skip it - if (MsgType == EAPOL_PAIR_MSG_2 || MsgType == EAPOL_PAIR_MSG_3) - { - // Check RSN IE whether it is WPA2/WPA2PSK - if (!RTMPCheckRSNIE(pAd, pKeyData, KeyDataLen, pEntry, &skip_offset)) - { - // send wireless event - for RSN IE different - if (pAd->CommonCfg.bWirelessEvent) - RTMPSendWirelessEvent(pAd, IW_RSNIE_DIFF_EVENT_FLAG, pEntry->Addr, pEntry->apidx, 0); - - DBGPRINT(RT_DEBUG_ERROR, ("RSN_IE Different in msg %d of 4-way handshake!\n", MsgType)); - hex_dump("Receive RSN_IE ", pKeyData, KeyDataLen); - hex_dump("Desired RSN_IE ", pEntry->RSN_IE, pEntry->RSNIE_Len); - - return FALSE; - } - else - { - if (bWPA2 && MsgType == EAPOL_PAIR_MSG_3) - { - // skip RSN IE - pMyKeyData += skip_offset; - KeyDataLength -= skip_offset; - DBGPRINT(RT_DEBUG_TRACE, ("RTMPParseEapolKeyData ==> WPA2/WPA2PSK RSN IE matched in Msg 3, Length(%d) \n", skip_offset)); - } - else - return TRUE; - } - } - - DBGPRINT(RT_DEBUG_TRACE,("RTMPParseEapolKeyData ==> KeyDataLength %d without RSN_IE \n", KeyDataLength)); - - // Parse EKD format in pairwise_msg_3_WPA2 && group_msg_1_WPA2 - if (bWPA2 && (MsgType == EAPOL_PAIR_MSG_3 || MsgType == EAPOL_GROUP_MSG_1)) - { - if (KeyDataLength >= 8) // KDE format exclude GTK length - { - pKDE = (PKDE_ENCAP) pMyKeyData; - - - DefaultIdx = pKDE->GTKEncap.Kid; - - // Sanity check - KED length - if (KeyDataLength < (pKDE->Len + 2)) - { - DBGPRINT(RT_DEBUG_ERROR, ("ERROR: The len from KDE is too short \n")); - return FALSE; - } - - // Get GTK length - refer to IEEE 802.11i-2004 p.82 - GTKLEN = pKDE->Len -6; - if (GTKLEN < LEN_AES_KEY) - { - DBGPRINT(RT_DEBUG_ERROR, ("ERROR: GTK Key length is too short (%d) \n", GTKLEN)); - return FALSE; - } - - } - else - { - DBGPRINT(RT_DEBUG_ERROR, ("ERROR: KDE format length is too short \n")); - return FALSE; - } - - DBGPRINT(RT_DEBUG_TRACE, ("GTK in KDE format ,DefaultKeyID=%d, KeyLen=%d \n", DefaultIdx, GTKLEN)); - // skip it - pMyKeyData += 8; - KeyDataLength -= 8; - - } - else if (!bWPA2 && MsgType == EAPOL_GROUP_MSG_1) - { - DefaultIdx = GroupKeyIndex; - DBGPRINT(RT_DEBUG_TRACE, ("GTK DefaultKeyID=%d \n", DefaultIdx)); - } - - // Sanity check - shared key index must be 1 ~ 3 - if (DefaultIdx < 1 || DefaultIdx > 3) - { - DBGPRINT(RT_DEBUG_ERROR, ("ERROR: GTK Key index(%d) is invalid in %s %s \n", DefaultIdx, ((bWPA2) ? "WPA2" : "WPA"), GetEapolMsgType(MsgType))); - return FALSE; - } - - -#ifdef CONFIG_STA_SUPPORT - // Todo -#endif // CONFIG_STA_SUPPORT // - - return TRUE; - -} - - -/* - ======================================================================== - - Routine Description: - Construct EAPoL message for WPA handshaking - Its format is below, - - +--------------------+ - | Protocol Version | 1 octet - +--------------------+ - | Protocol Type | 1 octet - +--------------------+ - | Body Length | 2 octets - +--------------------+ - | Descriptor Type | 1 octet - +--------------------+ - | Key Information | 2 octets - +--------------------+ - | Key Length | 1 octet - +--------------------+ - | Key Repaly Counter | 8 octets - +--------------------+ - | Key Nonce | 32 octets - +--------------------+ - | Key IV | 16 octets - +--------------------+ - | Key RSC | 8 octets - +--------------------+ - | Key ID or Reserved | 8 octets - +--------------------+ - | Key MIC | 16 octets - +--------------------+ - | Key Data Length | 2 octets - +--------------------+ - | Key Data | n octets - +--------------------+ - - - Arguments: - pAd Pointer to our adapter - - Return Value: - None - - Note: - - ======================================================================== -*/ -VOID ConstructEapolMsg( - IN PRTMP_ADAPTER pAd, - IN UCHAR AuthMode, - IN UCHAR WepStatus, - IN UCHAR GroupKeyWepStatus, - IN UCHAR MsgType, - IN UCHAR DefaultKeyIdx, - IN UCHAR *ReplayCounter, - IN UCHAR *KeyNonce, - IN UCHAR *TxRSC, - IN UCHAR *PTK, - IN UCHAR *GTK, - IN UCHAR *RSNIE, - IN UCHAR RSNIE_Len, - OUT PEAPOL_PACKET pMsg) -{ - BOOLEAN bWPA2 = FALSE; - - // Choose WPA2 or not - if ((AuthMode == Ndis802_11AuthModeWPA2) || (AuthMode == Ndis802_11AuthModeWPA2PSK)) - bWPA2 = TRUE; - - // Init Packet and Fill header - pMsg->ProVer = EAPOL_VER; - pMsg->ProType = EAPOLKey; - - // Default 95 bytes, the EAPoL-Key descriptor exclude Key-data field - pMsg->Body_Len[1] = LEN_EAPOL_KEY_MSG; - - // Fill in EAPoL descriptor - if (bWPA2) - pMsg->KeyDesc.Type = WPA2_KEY_DESC; - else - pMsg->KeyDesc.Type = WPA1_KEY_DESC; - - // Fill in Key information, refer to IEEE Std 802.11i-2004 page 78 - // When either the pairwise or the group cipher is AES, the DESC_TYPE_AES(2) shall be used. - pMsg->KeyDesc.KeyInfo.KeyDescVer = - (((WepStatus == Ndis802_11Encryption3Enabled) || (GroupKeyWepStatus == Ndis802_11Encryption3Enabled)) ? (DESC_TYPE_AES) : (DESC_TYPE_TKIP)); - - // Specify Key Type as Group(0) or Pairwise(1) - if (MsgType >= EAPOL_GROUP_MSG_1) - pMsg->KeyDesc.KeyInfo.KeyType = GROUPKEY; - else - pMsg->KeyDesc.KeyInfo.KeyType = PAIRWISEKEY; - - // Specify Key Index, only group_msg1_WPA1 - if (!bWPA2 && (MsgType >= EAPOL_GROUP_MSG_1)) - pMsg->KeyDesc.KeyInfo.KeyIndex = DefaultKeyIdx; - - if (MsgType == EAPOL_PAIR_MSG_3) - pMsg->KeyDesc.KeyInfo.Install = 1; - - if ((MsgType == EAPOL_PAIR_MSG_1) || (MsgType == EAPOL_PAIR_MSG_3) || (MsgType == EAPOL_GROUP_MSG_1)) - pMsg->KeyDesc.KeyInfo.KeyAck = 1; - - if (MsgType != EAPOL_PAIR_MSG_1) - pMsg->KeyDesc.KeyInfo.KeyMic = 1; - - if ((bWPA2 && (MsgType >= EAPOL_PAIR_MSG_3)) || (!bWPA2 && (MsgType >= EAPOL_GROUP_MSG_1))) - { - pMsg->KeyDesc.KeyInfo.Secure = 1; - } - - if (bWPA2 && ((MsgType == EAPOL_PAIR_MSG_3) || (MsgType == EAPOL_GROUP_MSG_1))) - { - pMsg->KeyDesc.KeyInfo.EKD_DL = 1; - } - - // key Information element has done. - *(USHORT *)(&pMsg->KeyDesc.KeyInfo) = cpu2le16(*(USHORT *)(&pMsg->KeyDesc.KeyInfo)); - - // Fill in Key Length -#if 0 - if (bWPA2) - { - // In WPA2 mode, the field indicates the length of pairwise key cipher, - // so only pairwise_msg_1 and pairwise_msg_3 need to fill. - if ((MsgType == EAPOL_PAIR_MSG_1) || (MsgType == EAPOL_PAIR_MSG_3)) - pMsg->KeyDesc.KeyLength[1] = ((WepStatus == Ndis802_11Encryption2Enabled) ? LEN_TKIP_KEY : LEN_AES_KEY); - } - else if (!bWPA2) -#endif - { - if (MsgType >= EAPOL_GROUP_MSG_1) - { - // the length of group key cipher - pMsg->KeyDesc.KeyLength[1] = ((GroupKeyWepStatus == Ndis802_11Encryption2Enabled) ? TKIP_GTK_LENGTH : LEN_AES_KEY); - } - else - { - // the length of pairwise key cipher - pMsg->KeyDesc.KeyLength[1] = ((WepStatus == Ndis802_11Encryption2Enabled) ? LEN_TKIP_KEY : LEN_AES_KEY); - } - } - - // Fill in replay counter - NdisMoveMemory(pMsg->KeyDesc.ReplayCounter, ReplayCounter, LEN_KEY_DESC_REPLAY); - - // Fill Key Nonce field - // ANonce : pairwise_msg1 & pairwise_msg3 - // SNonce : pairwise_msg2 - // GNonce : group_msg1_wpa1 - if ((MsgType <= EAPOL_PAIR_MSG_3) || ((!bWPA2 && (MsgType == EAPOL_GROUP_MSG_1)))) - NdisMoveMemory(pMsg->KeyDesc.KeyNonce, KeyNonce, LEN_KEY_DESC_NONCE); - - // Fill key IV - WPA2 as 0, WPA1 as random - if (!bWPA2 && (MsgType == EAPOL_GROUP_MSG_1)) - { - // Suggest IV be random number plus some number, - NdisMoveMemory(pMsg->KeyDesc.KeyIv, &KeyNonce[16], LEN_KEY_DESC_IV); - pMsg->KeyDesc.KeyIv[15] += 2; - } - - // Fill Key RSC field - // It contains the RSC for the GTK being installed. - if ((MsgType == EAPOL_PAIR_MSG_3 && bWPA2) || (MsgType == EAPOL_GROUP_MSG_1)) - { - NdisMoveMemory(pMsg->KeyDesc.KeyRsc, TxRSC, 6); - } - - // Clear Key MIC field for MIC calculation later - NdisZeroMemory(pMsg->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); - - ConstructEapolKeyData(pAd, - AuthMode, - WepStatus, - GroupKeyWepStatus, - MsgType, - DefaultKeyIdx, - bWPA2, - PTK, - GTK, - RSNIE, - RSNIE_Len, - pMsg); - - // Calculate MIC and fill in KeyMic Field except Pairwise Msg 1. - if (MsgType != EAPOL_PAIR_MSG_1) - { - CalculateMIC(pAd, WepStatus, PTK, pMsg); - } - - DBGPRINT(RT_DEBUG_TRACE, ("===> ConstructEapolMsg for %s %s\n", ((bWPA2) ? "WPA2" : "WPA"), GetEapolMsgType(MsgType))); - DBGPRINT(RT_DEBUG_TRACE, (" Body length = %d \n", pMsg->Body_Len[1])); - DBGPRINT(RT_DEBUG_TRACE, (" Key length = %d \n", pMsg->KeyDesc.KeyLength[1])); - - -} - -/* - ======================================================================== - - Routine Description: - Construct the Key Data field of EAPoL message - - Arguments: - pAd Pointer to our adapter - Elem Message body - - Return Value: - None - - Note: - - ======================================================================== -*/ -VOID ConstructEapolKeyData( - IN PRTMP_ADAPTER pAd, - IN UCHAR AuthMode, - IN UCHAR WepStatus, - IN UCHAR GroupKeyWepStatus, - IN UCHAR MsgType, - IN UCHAR DefaultKeyIdx, - IN BOOLEAN bWPA2Capable, - IN UCHAR *PTK, - IN UCHAR *GTK, - IN UCHAR *RSNIE, - IN UCHAR RSNIE_LEN, - OUT PEAPOL_PACKET pMsg) -{ - UCHAR *mpool, *Key_Data, *Rc4GTK; - UCHAR ekey[(LEN_KEY_DESC_IV+LEN_EAP_EK)]; - UCHAR data_offset; - - - if (MsgType == EAPOL_PAIR_MSG_1 || MsgType == EAPOL_PAIR_MSG_4 || MsgType == EAPOL_GROUP_MSG_2) - return; - - // allocate memory pool - os_alloc_mem(pAd, (PUCHAR *)&mpool, 1500); - - if (mpool == NULL) - return; - - /* Rc4GTK Len = 512 */ - Rc4GTK = (UCHAR *) ROUND_UP(mpool, 4); - /* Key_Data Len = 512 */ - Key_Data = (UCHAR *) ROUND_UP(Rc4GTK + 512, 4); - - NdisZeroMemory(Key_Data, 512); - pMsg->KeyDesc.KeyDataLen[1] = 0; - data_offset = 0; - - // Encapsulate RSNIE in pairwise_msg2 & pairwise_msg3 - if (RSNIE_LEN && ((MsgType == EAPOL_PAIR_MSG_2) || (MsgType == EAPOL_PAIR_MSG_3))) - { - if (bWPA2Capable) - Key_Data[data_offset + 0] = IE_WPA2; - else - Key_Data[data_offset + 0] = IE_WPA; - - Key_Data[data_offset + 1] = RSNIE_LEN; - NdisMoveMemory(&Key_Data[data_offset + 2], RSNIE, RSNIE_LEN); - data_offset += (2 + RSNIE_LEN); - } - - // Encapsulate KDE format in pairwise_msg3_WPA2 & group_msg1_WPA2 - if (bWPA2Capable && ((MsgType == EAPOL_PAIR_MSG_3) || (MsgType == EAPOL_GROUP_MSG_1))) - { - // Key Data Encapsulation (KDE) format - 802.11i-2004 Figure-43w and Table-20h - Key_Data[data_offset + 0] = 0xDD; - - if (GroupKeyWepStatus == Ndis802_11Encryption3Enabled) - { - Key_Data[data_offset + 1] = 0x16;// 4+2+16(OUI+DataType+DataField) - } - else - { - Key_Data[data_offset + 1] = 0x26;// 4+2+32(OUI+DataType+DataField) - } - - Key_Data[data_offset + 2] = 0x00; - Key_Data[data_offset + 3] = 0x0F; - Key_Data[data_offset + 4] = 0xAC; - Key_Data[data_offset + 5] = 0x01; - - // GTK KDE format - 802.11i-2004 Figure-43x - Key_Data[data_offset + 6] = (DefaultKeyIdx & 0x03); - Key_Data[data_offset + 7] = 0x00; // Reserved Byte - - data_offset += 8; - } - - - // Encapsulate GTK and encrypt the key-data field with KEK. - // Only for pairwise_msg3_WPA2 and group_msg1 - if ((MsgType == EAPOL_PAIR_MSG_3 && bWPA2Capable) || (MsgType == EAPOL_GROUP_MSG_1)) - { - // Fill in GTK - if (GroupKeyWepStatus == Ndis802_11Encryption3Enabled) - { - NdisMoveMemory(&Key_Data[data_offset], GTK, LEN_AES_KEY); - data_offset += LEN_AES_KEY; - } - else - { - NdisMoveMemory(&Key_Data[data_offset], GTK, TKIP_GTK_LENGTH); - data_offset += TKIP_GTK_LENGTH; - } - - // Still dont know why, but if not append will occur "GTK not include in MSG3" - // Patch for compatibility between zero config and funk - if (MsgType == EAPOL_PAIR_MSG_3 && bWPA2Capable) - { - if (GroupKeyWepStatus == Ndis802_11Encryption3Enabled) - { - Key_Data[data_offset + 0] = 0xDD; - Key_Data[data_offset + 1] = 0; - data_offset += 2; - } - else - { - Key_Data[data_offset + 0] = 0xDD; - Key_Data[data_offset + 1] = 0; - Key_Data[data_offset + 2] = 0; - Key_Data[data_offset + 3] = 0; - Key_Data[data_offset + 4] = 0; - Key_Data[data_offset + 5] = 0; - data_offset += 6; - } - } - - // Encrypt the data material in key data field - if (WepStatus == Ndis802_11Encryption3Enabled) - { - AES_GTK_KEY_WRAP(&PTK[16], Key_Data, data_offset, Rc4GTK); - // AES wrap function will grow 8 bytes in length - data_offset += 8; - } - else - { - // PREPARE Encrypted "Key DATA" field. (Encrypt GTK with RC4, usinf PTK[16]->[31] as Key, IV-field as IV) - // put TxTsc in Key RSC field - pAd->PrivateInfo.FCSCRC32 = PPPINITFCS32; //Init crc32. - - // ekey is the contanetion of IV-field, and PTK[16]->PTK[31] - NdisMoveMemory(ekey, pMsg->KeyDesc.KeyIv, LEN_KEY_DESC_IV); - NdisMoveMemory(&ekey[LEN_KEY_DESC_IV], &PTK[16], LEN_EAP_EK); - ARCFOUR_INIT(&pAd->PrivateInfo.WEPCONTEXT, ekey, sizeof(ekey)); //INIT SBOX, KEYLEN+3(IV) - pAd->PrivateInfo.FCSCRC32 = RTMP_CALC_FCS32(pAd->PrivateInfo.FCSCRC32, Key_Data, data_offset); - WPAARCFOUR_ENCRYPT(&pAd->PrivateInfo.WEPCONTEXT, Rc4GTK, Key_Data, data_offset); - } - - NdisMoveMemory(pMsg->KeyDesc.KeyData, Rc4GTK, data_offset); - } - else - { - NdisMoveMemory(pMsg->KeyDesc.KeyData, Key_Data, data_offset); - } - - // set key data length field and total length - pMsg->KeyDesc.KeyDataLen[1] = data_offset; - pMsg->Body_Len[1] += data_offset; - - os_free_mem(pAd, mpool); - -} - -/* - ======================================================================== - - Routine Description: - Calcaulate MIC. It is used during 4-ways handsharking. - - Arguments: - pAd - pointer to our pAdapter context - PeerWepStatus - indicate the encryption type - - Return Value: - - Note: - - ======================================================================== -*/ -VOID CalculateMIC( - IN PRTMP_ADAPTER pAd, - IN UCHAR PeerWepStatus, - IN UCHAR *PTK, - OUT PEAPOL_PACKET pMsg) -{ - UCHAR *OutBuffer; - ULONG FrameLen = 0; - UCHAR mic[LEN_KEY_DESC_MIC]; - UCHAR digest[80]; - - // allocate memory for MIC calculation - os_alloc_mem(pAd, (PUCHAR *)&OutBuffer, 512); - - if (OutBuffer == NULL) - { - DBGPRINT(RT_DEBUG_ERROR, ("!!!CalculateMIC: no memory!!!\n")); - return; - } - - // make a frame for calculating MIC. - MakeOutgoingFrame(OutBuffer, &FrameLen, - pMsg->Body_Len[1] + 4, pMsg, - END_OF_ARGS); - - NdisZeroMemory(mic, sizeof(mic)); - - // Calculate MIC - if (PeerWepStatus == Ndis802_11Encryption3Enabled) - { - HMAC_SHA1(OutBuffer, FrameLen, PTK, LEN_EAP_MICK, digest); - NdisMoveMemory(mic, digest, LEN_KEY_DESC_MIC); - } - else - { - hmac_md5(PTK, LEN_EAP_MICK, OutBuffer, FrameLen, mic); - } - - // store the calculated MIC - NdisMoveMemory(pMsg->KeyDesc.KeyMic, mic, LEN_KEY_DESC_MIC); - - os_free_mem(pAd, OutBuffer); -} - -/* - ======================================================================== - - Routine Description: - Some received frames can't decrypt by Asic, so decrypt them by software. - - Arguments: - pAd - pointer to our pAdapter context - PeerWepStatus - indicate the encryption type - - Return Value: - NDIS_STATUS_SUCCESS - decryption successful - NDIS_STATUS_FAILURE - decryption failure - - ======================================================================== -*/ -NDIS_STATUS RTMPSoftDecryptBroadCastData( - IN PRTMP_ADAPTER pAd, - IN RX_BLK *pRxBlk, - IN NDIS_802_11_ENCRYPTION_STATUS GroupCipher, - IN PCIPHER_KEY pShard_key) -{ - PRXWI_STRUC pRxWI = pRxBlk->pRxWI; - - - - // handle WEP decryption - if (GroupCipher == Ndis802_11Encryption1Enabled) - { - if (RTMPSoftDecryptWEP(pAd, pRxBlk->pData, pRxWI->MPDUtotalByteCount, pShard_key)) - { - - //Minus IV[4] & ICV[4] - pRxWI->MPDUtotalByteCount -= 8; - } - else - { - DBGPRINT(RT_DEBUG_ERROR, ("ERROR : Software decrypt WEP data fails.\n")); - // give up this frame - return NDIS_STATUS_FAILURE; - } - } - // handle TKIP decryption - else if (GroupCipher == Ndis802_11Encryption2Enabled) - { - if (RTMPSoftDecryptTKIP(pAd, pRxBlk->pData, pRxWI->MPDUtotalByteCount, 0, pShard_key)) - { - - //Minus 8 bytes MIC, 8 bytes IV/EIV, 4 bytes ICV - pRxWI->MPDUtotalByteCount -= 20; - } - else - { - DBGPRINT(RT_DEBUG_ERROR, ("ERROR : RTMPSoftDecryptTKIP Failed\n")); - // give up this frame - return NDIS_STATUS_FAILURE; - } - } - // handle AES decryption - else if (GroupCipher == Ndis802_11Encryption3Enabled) - { - if (RTMPSoftDecryptAES(pAd, pRxBlk->pData, pRxWI->MPDUtotalByteCount , pShard_key)) - { - - //8 bytes MIC, 8 bytes IV/EIV (CCMP Header) - pRxWI->MPDUtotalByteCount -= 16; - } - else - { - DBGPRINT(RT_DEBUG_ERROR, ("ERROR : RTMPSoftDecryptAES Failed\n")); - // give up this frame - return NDIS_STATUS_FAILURE; - } - } - else - { - // give up this frame - return NDIS_STATUS_FAILURE; - } - - return NDIS_STATUS_SUCCESS; - -} - +#include "../../rt2860/common/cmm_wpa.c" diff --git a/drivers/staging/rt2870/common/dfs.c b/drivers/staging/rt2870/common/dfs.c index b09bba5cb206..ac2da4c0e2ca 100644 --- a/drivers/staging/rt2870/common/dfs.c +++ b/drivers/staging/rt2870/common/dfs.c @@ -1,453 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - ap_dfs.c - - Abstract: - Support DFS function. - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Fonchi 03-12-2007 created -*/ - -#include "../rt_config.h" - -typedef struct _RADAR_DURATION_TABLE -{ - ULONG RDDurRegion; - ULONG RadarSignalDuration; - ULONG Tolerance; -} RADAR_DURATION_TABLE, *PRADAR_DURATION_TABLE; - - -static UCHAR RdIdleTimeTable[MAX_RD_REGION][4] = -{ - {9, 250, 250, 250}, // CE - {4, 250, 250, 250}, // FCC - {4, 250, 250, 250}, // JAP - {15, 250, 250, 250}, // JAP_W53 - {4, 250, 250, 250} // JAP_W56 -}; - -/* - ======================================================================== - - Routine Description: - Bbp Radar detection routine - - Arguments: - pAd Pointer to our adapter - - Return Value: - - ======================================================================== -*/ -VOID BbpRadarDetectionStart( - IN PRTMP_ADAPTER pAd) -{ - UINT8 RadarPeriod; - - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, 114, 0x02); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, 121, 0x20); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, 122, 0x00); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, 123, 0x08/*0x80*/); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, 124, 0x28); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, 125, 0xff); - -#if 0 - // toggle Rx enable bit for radar detection. - // it's Andy's recommand. - { - UINT32 Value; - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value |= (0x1 << 3); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - Value &= ~(0x1 << 3); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - } -#endif - RadarPeriod = ((UINT)RdIdleTimeTable[pAd->CommonCfg.RadarDetect.RDDurRegion][0] + (UINT)pAd->CommonCfg.RadarDetect.DfsSessionTime) < 250 ? - (RdIdleTimeTable[pAd->CommonCfg.RadarDetect.RDDurRegion][0] + pAd->CommonCfg.RadarDetect.DfsSessionTime) : 250; - - RTMP_IO_WRITE8(pAd, 0x7020, 0x1d); - RTMP_IO_WRITE8(pAd, 0x7021, 0x40); - - RadarDetectionStart(pAd, 0, RadarPeriod); - return; -} - -/* - ======================================================================== - - Routine Description: - Bbp Radar detection routine - - Arguments: - pAd Pointer to our adapter - - Return Value: - - ======================================================================== -*/ -VOID BbpRadarDetectionStop( - IN PRTMP_ADAPTER pAd) -{ - RTMP_IO_WRITE8(pAd, 0x7020, 0x1d); - RTMP_IO_WRITE8(pAd, 0x7021, 0x60); - - RadarDetectionStop(pAd); - return; -} - -/* - ======================================================================== - - Routine Description: - Radar detection routine - - Arguments: - pAd Pointer to our adapter - - Return Value: - - ======================================================================== -*/ -VOID RadarDetectionStart( - IN PRTMP_ADAPTER pAd, - IN BOOLEAN CTSProtect, - IN UINT8 CTSPeriod) -{ - UINT8 DfsActiveTime = (pAd->CommonCfg.RadarDetect.DfsSessionTime & 0x1f); - UINT8 CtsProtect = (CTSProtect == 1) ? 0x02 : 0x01; // CTS protect. - - if (CTSProtect != 0) - { - switch(pAd->CommonCfg.RadarDetect.RDDurRegion) - { - case FCC: - case JAP_W56: - CtsProtect = 0x03; - break; - - case CE: - case JAP_W53: - default: - CtsProtect = 0x02; - break; - } - } - else - CtsProtect = 0x01; - - - // send start-RD with CTS protection command to MCU - // highbyte [7] reserve - // highbyte [6:5] 0x: stop Carrier/Radar detection - // highbyte [10]: Start Carrier/Radar detection without CTS protection, 11: Start Carrier/Radar detection with CTS protection - // highbyte [4:0] Radar/carrier detection duration. In 1ms. - - // lowbyte [7:0] Radar/carrier detection period, in 1ms. - AsicSendCommandToMcu(pAd, 0x60, 0xff, CTSPeriod, DfsActiveTime | (CtsProtect << 5)); - //AsicSendCommandToMcu(pAd, 0x63, 0xff, 10, 0); - - return; -} - -/* - ======================================================================== - - Routine Description: - Radar detection routine - - Arguments: - pAd Pointer to our adapter - - Return Value: - TRUE Found radar signal - FALSE Not found radar signal - - ======================================================================== -*/ -VOID RadarDetectionStop( - IN PRTMP_ADAPTER pAd) -{ - DBGPRINT(RT_DEBUG_TRACE,("RadarDetectionStop.\n")); - AsicSendCommandToMcu(pAd, 0x60, 0xff, 0x00, 0x00); // send start-RD with CTS protection command to MCU - - return; -} - -/* - ======================================================================== - - Routine Description: - Radar channel check routine - - Arguments: - pAd Pointer to our adapter - - Return Value: - TRUE need to do radar detect - FALSE need not to do radar detect - - ======================================================================== -*/ -BOOLEAN RadarChannelCheck( - IN PRTMP_ADAPTER pAd, - IN UCHAR Ch) -{ -#if 1 - INT i; - BOOLEAN result = FALSE; - - for (i=0; iChannelListNum; i++) - { - if (Ch == pAd->ChannelList[i].Channel) - { - result = pAd->ChannelList[i].DfsReq; - break; - } - } - - return result; -#else - INT i; - UCHAR Channel[15]={52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140}; - - for (i=0; i<15; i++) - { - if (Ch == Channel[i]) - { - break; - } - } - - if (i != 15) - return TRUE; - else - return FALSE; -#endif -} - -ULONG JapRadarType( - IN PRTMP_ADAPTER pAd) -{ - ULONG i; - const UCHAR Channel[15]={52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140}; - - if (pAd->CommonCfg.RadarDetect.RDDurRegion != JAP) - { - return pAd->CommonCfg.RadarDetect.RDDurRegion; - } - - for (i=0; i<15; i++) - { - if (pAd->CommonCfg.Channel == Channel[i]) - { - break; - } - } - - if (i < 4) - return JAP_W53; - else if (i < 15) - return JAP_W56; - else - return JAP; // W52 - -} - -ULONG RTMPBbpReadRadarDuration( - IN PRTMP_ADAPTER pAd) -{ - UINT8 byteValue = 0; - ULONG result; - - BBP_IO_READ8_BY_REG_ID(pAd, BBP_R115, &byteValue); - - result = 0; - switch (byteValue) - { - case 1: // radar signal detected by pulse mode. - case 2: // radar signal detected by width mode. - result = RTMPReadRadarDuration(pAd); - break; - - case 0: // No radar signal. - default: - - result = 0; - break; - } - - return result; -} - -ULONG RTMPReadRadarDuration( - IN PRTMP_ADAPTER pAd) -{ - ULONG result = 0; - -#ifdef DFS_SUPPORT - UINT8 duration1 = 0, duration2 = 0, duration3 = 0; - - BBP_IO_READ8_BY_REG_ID(pAd, BBP_R116, &duration1); - BBP_IO_READ8_BY_REG_ID(pAd, BBP_R117, &duration2); - BBP_IO_READ8_BY_REG_ID(pAd, BBP_R118, &duration3); - result = (duration1 << 16) + (duration2 << 8) + duration3; -#endif // DFS_SUPPORT // - - return result; - -} - -VOID RTMPCleanRadarDuration( - IN PRTMP_ADAPTER pAd) -{ - return; -} - -/* - ======================================================================== - Routine Description: - Radar wave detection. The API should be invoke each second. - - Arguments: - pAd - Adapter pointer - - Return Value: - None - - ======================================================================== -*/ -VOID ApRadarDetectPeriodic( - IN PRTMP_ADAPTER pAd) -{ - INT i; - - pAd->CommonCfg.RadarDetect.InServiceMonitorCount++; - - for (i=0; iChannelListNum; i++) - { - if (pAd->ChannelList[i].RemainingTimeForUse > 0) - { - pAd->ChannelList[i].RemainingTimeForUse --; - if ((pAd->Mlme.PeriodicRound%5) == 0) - { - DBGPRINT(RT_DEBUG_TRACE, ("RadarDetectPeriodic - ch=%d, RemainingTimeForUse=%d\n", pAd->ChannelList[i].Channel, pAd->ChannelList[i].RemainingTimeForUse)); - } - } - } - - //radar detect - if ((pAd->CommonCfg.Channel > 14) - && (pAd->CommonCfg.bIEEE80211H == 1) - && RadarChannelCheck(pAd, pAd->CommonCfg.Channel)) - { - RadarDetectPeriodic(pAd); - } - - return; -} - -// Periodic Radar detection, switch channel will occur in RTMPHandleTBTTInterrupt() -// Before switch channel, driver needs doing channel switch announcement. -VOID RadarDetectPeriodic( - IN PRTMP_ADAPTER pAd) -{ - // need to check channel availability, after switch channel - if (pAd->CommonCfg.RadarDetect.RDMode != RD_SILENCE_MODE) - return; - - // channel availability check time is 60sec, use 65 for assurance - if (pAd->CommonCfg.RadarDetect.RDCount++ > pAd->CommonCfg.RadarDetect.ChMovingTime) - { - DBGPRINT(RT_DEBUG_TRACE, ("Not found radar signal, start send beacon and radar detection in service monitor\n\n")); - BbpRadarDetectionStop(pAd); - AsicEnableBssSync(pAd); - pAd->CommonCfg.RadarDetect.RDMode = RD_NORMAL_MODE; - - - return; - } - - return; -} - - -/* - ========================================================================== - Description: - change channel moving time for DFS testing. - - Arguments: - pAdapter Pointer to our adapter - wrq Pointer to the ioctl argument - - Return Value: - None - - Note: - Usage: - 1.) iwpriv ra0 set ChMovTime=[value] - ========================================================================== -*/ -INT Set_ChMovingTime_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - UINT8 Value; - - Value = simple_strtol(arg, 0, 10); - - pAd->CommonCfg.RadarDetect.ChMovingTime = Value; - - DBGPRINT(RT_DEBUG_TRACE, ("%s:: %d\n", __func__, - pAd->CommonCfg.RadarDetect.ChMovingTime)); - - return TRUE; -} - -INT Set_LongPulseRadarTh_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - UINT8 Value; - - Value = simple_strtol(arg, 0, 10) > 10 ? 10 : simple_strtol(arg, 0, 10); - - pAd->CommonCfg.RadarDetect.LongPulseRadarTh = Value; - - DBGPRINT(RT_DEBUG_TRACE, ("%s:: %d\n", __func__, - pAd->CommonCfg.RadarDetect.LongPulseRadarTh)); - - return TRUE; -} - - +#include "../../rt2860/common/dfs.c" diff --git a/drivers/staging/rt2870/common/eeprom.c b/drivers/staging/rt2870/common/eeprom.c index 33f16ed9c491..def09658fd81 100644 --- a/drivers/staging/rt2870/common/eeprom.c +++ b/drivers/staging/rt2870/common/eeprom.c @@ -1,254 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - eeprom.c - - Abstract: - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Name Date Modification logs -*/ -#include "../rt_config.h" - -#if 0 -#define EEPROM_SIZE 0x200 -#define NVRAM_OFFSET 0x30000 -#define RF_OFFSET 0x40000 - -static UCHAR init_flag = 0; -static PUCHAR nv_ee_start = 0; - -static UCHAR EeBuffer[EEPROM_SIZE]; -#endif -// IRQL = PASSIVE_LEVEL -VOID RaiseClock( - IN PRTMP_ADAPTER pAd, - IN UINT32 *x) -{ - *x = *x | EESK; - RTMP_IO_WRITE32(pAd, E2PROM_CSR, *x); - RTMPusecDelay(1); // Max frequency = 1MHz in Spec. definition -} - -// IRQL = PASSIVE_LEVEL -VOID LowerClock( - IN PRTMP_ADAPTER pAd, - IN UINT32 *x) -{ - *x = *x & ~EESK; - RTMP_IO_WRITE32(pAd, E2PROM_CSR, *x); - RTMPusecDelay(1); -} - -// IRQL = PASSIVE_LEVEL -USHORT ShiftInBits( - IN PRTMP_ADAPTER pAd) -{ - UINT32 x,i; - USHORT data=0; - - RTMP_IO_READ32(pAd, E2PROM_CSR, &x); - - x &= ~( EEDO | EEDI); - - for(i=0; i<16; i++) - { - data = data << 1; - RaiseClock(pAd, &x); - - RTMP_IO_READ32(pAd, E2PROM_CSR, &x); - - x &= ~(EEDI); - if(x & EEDO) - data |= 1; - - LowerClock(pAd, &x); - } - - return data; -} - -// IRQL = PASSIVE_LEVEL -VOID ShiftOutBits( - IN PRTMP_ADAPTER pAd, - IN USHORT data, - IN USHORT count) -{ - UINT32 x,mask; - - mask = 0x01 << (count - 1); - RTMP_IO_READ32(pAd, E2PROM_CSR, &x); - - x &= ~(EEDO | EEDI); - - do - { - x &= ~EEDI; - if(data & mask) x |= EEDI; - - RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); - - RaiseClock(pAd, &x); - LowerClock(pAd, &x); - - mask = mask >> 1; - } while(mask); - - x &= ~EEDI; - RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); -} - -// IRQL = PASSIVE_LEVEL -VOID EEpromCleanup( - IN PRTMP_ADAPTER pAd) -{ - UINT32 x; - - RTMP_IO_READ32(pAd, E2PROM_CSR, &x); - - x &= ~(EECS | EEDI); - RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); - - RaiseClock(pAd, &x); - LowerClock(pAd, &x); -} - -VOID EWEN( - IN PRTMP_ADAPTER pAd) -{ - UINT32 x; - - // reset bits and set EECS - RTMP_IO_READ32(pAd, E2PROM_CSR, &x); - x &= ~(EEDI | EEDO | EESK); - x |= EECS; - RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); - - // kick a pulse - RaiseClock(pAd, &x); - LowerClock(pAd, &x); - - // output the read_opcode and six pulse in that order - ShiftOutBits(pAd, EEPROM_EWEN_OPCODE, 5); - ShiftOutBits(pAd, 0, 6); - - EEpromCleanup(pAd); -} - -VOID EWDS( - IN PRTMP_ADAPTER pAd) -{ - UINT32 x; - - // reset bits and set EECS - RTMP_IO_READ32(pAd, E2PROM_CSR, &x); - x &= ~(EEDI | EEDO | EESK); - x |= EECS; - RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); - - // kick a pulse - RaiseClock(pAd, &x); - LowerClock(pAd, &x); - - // output the read_opcode and six pulse in that order - ShiftOutBits(pAd, EEPROM_EWDS_OPCODE, 5); - ShiftOutBits(pAd, 0, 6); - - EEpromCleanup(pAd); -} - -// IRQL = PASSIVE_LEVEL -USHORT RTMP_EEPROM_READ16( - IN PRTMP_ADAPTER pAd, - IN USHORT Offset) -{ - UINT32 x; - USHORT data; - - Offset /= 2; - // reset bits and set EECS - RTMP_IO_READ32(pAd, E2PROM_CSR, &x); - x &= ~(EEDI | EEDO | EESK); - x |= EECS; - RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); - - // kick a pulse - RaiseClock(pAd, &x); - LowerClock(pAd, &x); - - // output the read_opcode and register number in that order - ShiftOutBits(pAd, EEPROM_READ_OPCODE, 3); - ShiftOutBits(pAd, Offset, pAd->EEPROMAddressNum); - - // Now read the data (16 bits) in from the selected EEPROM word - data = ShiftInBits(pAd); - - EEpromCleanup(pAd); - - return data; -} //ReadEEprom - -VOID RTMP_EEPROM_WRITE16( - IN PRTMP_ADAPTER pAd, - IN USHORT Offset, - IN USHORT Data) -{ - UINT32 x; - - Offset /= 2; - - EWEN(pAd); - - // reset bits and set EECS - RTMP_IO_READ32(pAd, E2PROM_CSR, &x); - x &= ~(EEDI | EEDO | EESK); - x |= EECS; - RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); - - // kick a pulse - RaiseClock(pAd, &x); - LowerClock(pAd, &x); - - // output the read_opcode ,register number and data in that order - ShiftOutBits(pAd, EEPROM_WRITE_OPCODE, 3); - ShiftOutBits(pAd, Offset, pAd->EEPROMAddressNum); - ShiftOutBits(pAd, Data, 16); // 16-bit access - - // read DO status - RTMP_IO_READ32(pAd, E2PROM_CSR, &x); - - EEpromCleanup(pAd); - - RTMPusecDelay(10000); //delay for twp(MAX)=10ms - - EWDS(pAd); - - EEpromCleanup(pAd); -} - +#include "../../rt2860/common/eeprom.c" diff --git a/drivers/staging/rt2870/common/md5.c b/drivers/staging/rt2870/common/md5.c index 774776b4b8c3..195645c0e1a8 100644 --- a/drivers/staging/rt2870/common/md5.c +++ b/drivers/staging/rt2870/common/md5.c @@ -1,1427 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - md5.c - - Abstract: - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Name Date Modification logs - jan 10-28-03 Initial - Rita 11-23-04 Modify MD5 and SHA-1 - Rita 10-14-05 Modify SHA-1 in big-endian platform - */ -#include "../rt_config.h" - -/** - * md5_mac: - * @key: pointer to the key used for MAC generation - * @key_len: length of the key in bytes - * @data: pointer to the data area for which the MAC is generated - * @data_len: length of the data in bytes - * @mac: pointer to the buffer holding space for the MAC; the buffer should - * have space for 128-bit (16 bytes) MD5 hash value - * - * md5_mac() determines the message authentication code by using secure hash - * MD5(key | data | key). - */ -void md5_mac(u8 *key, size_t key_len, u8 *data, size_t data_len, u8 *mac) -{ - MD5_CTX context; - - MD5Init(&context); - MD5Update(&context, key, key_len); - MD5Update(&context, data, data_len); - MD5Update(&context, key, key_len); - MD5Final(mac, &context); -} - -/** - * hmac_md5: - * @key: pointer to the key used for MAC generation - * @key_len: length of the key in bytes - * @data: pointer to the data area for which the MAC is generated - * @data_len: length of the data in bytes - * @mac: pointer to the buffer holding space for the MAC; the buffer should - * have space for 128-bit (16 bytes) MD5 hash value - * - * hmac_md5() determines the message authentication code using HMAC-MD5. - * This implementation is based on the sample code presented in RFC 2104. - */ -void hmac_md5(u8 *key, size_t key_len, u8 *data, size_t data_len, u8 *mac) -{ - MD5_CTX context; - u8 k_ipad[65]; /* inner padding - key XORd with ipad */ - u8 k_opad[65]; /* outer padding - key XORd with opad */ - u8 tk[16]; - int i; - - //assert(key != NULL && data != NULL && mac != NULL); - - /* if key is longer than 64 bytes reset it to key = MD5(key) */ - if (key_len > 64) { - MD5_CTX ttcontext; - - MD5Init(&ttcontext); - MD5Update(&ttcontext, key, key_len); - MD5Final(tk, &ttcontext); - //key=(PUCHAR)ttcontext.buf; - key = tk; - key_len = 16; - } - - /* the HMAC_MD5 transform looks like: - * - * MD5(K XOR opad, MD5(K XOR ipad, text)) - * - * where K is an n byte key - * ipad is the byte 0x36 repeated 64 times - * opad is the byte 0x5c repeated 64 times - * and text is the data being protected */ - - /* start out by storing key in pads */ - NdisZeroMemory(k_ipad, sizeof(k_ipad)); - NdisZeroMemory(k_opad, sizeof(k_opad)); - //assert(key_len < sizeof(k_ipad)); - NdisMoveMemory(k_ipad, key, key_len); - NdisMoveMemory(k_opad, key, key_len); - - /* XOR key with ipad and opad values */ - for (i = 0; i < 64; i++) { - k_ipad[i] ^= 0x36; - k_opad[i] ^= 0x5c; - } - - /* perform inner MD5 */ - MD5Init(&context); /* init context for 1st pass */ - MD5Update(&context, k_ipad, 64); /* start with inner pad */ - MD5Update(&context, data, data_len); /* then text of datagram */ - MD5Final(mac, &context); /* finish up 1st pass */ - - /* perform outer MD5 */ - MD5Init(&context); /* init context for 2nd pass */ - MD5Update(&context, k_opad, 64); /* start with outer pad */ - MD5Update(&context, mac, 16); /* then results of 1st hash */ - MD5Final(mac, &context); /* finish up 2nd pass */ -} - -#ifndef RT_BIG_ENDIAN -#define byteReverse(buf, len) /* Nothing */ -#else -void byteReverse(unsigned char *buf, unsigned longs); -void byteReverse(unsigned char *buf, unsigned longs) -{ - do { - *(UINT32 *)buf = SWAP32(*(UINT32 *)buf); - buf += 4; - } while (--longs); -} -#endif - - -/* ========================== MD5 implementation =========================== */ -// four base functions for MD5 -#define MD5_F1(x, y, z) (((x) & (y)) | ((~x) & (z))) -#define MD5_F2(x, y, z) (((x) & (z)) | ((y) & (~z))) -#define MD5_F3(x, y, z) ((x) ^ (y) ^ (z)) -#define MD5_F4(x, y, z) ((y) ^ ((x) | (~z))) -#define CYCLIC_LEFT_SHIFT(w, s) (((w) << (s)) | ((w) >> (32-(s)))) - -#define MD5Step(f, w, x, y, z, data, t, s) \ - ( w += f(x, y, z) + data + t, w = (CYCLIC_LEFT_SHIFT(w, s)) & 0xffffffff, w += x ) - - -/* - * Function Description: - * Initiate MD5 Context satisfied in RFC 1321 - * - * Arguments: - * pCtx Pointer to MD5 context - * - * Return Value: - * None - */ -VOID MD5Init(MD5_CTX *pCtx) -{ - pCtx->Buf[0]=0x67452301; - pCtx->Buf[1]=0xefcdab89; - pCtx->Buf[2]=0x98badcfe; - pCtx->Buf[3]=0x10325476; - - pCtx->LenInBitCount[0]=0; - pCtx->LenInBitCount[1]=0; -} - - -/* - * Function Description: - * Update MD5 Context, allow of an arrary of octets as the next portion - * of the message - * - * Arguments: - * pCtx Pointer to MD5 context - * pData Pointer to input data - * LenInBytes The length of input data (unit: byte) - * - * Return Value: - * None - * - * Note: - * Called after MD5Init or MD5Update(itself) - */ -VOID MD5Update(MD5_CTX *pCtx, UCHAR *pData, UINT32 LenInBytes) -{ - - UINT32 TfTimes; - UINT32 temp; - unsigned int i; - - temp = pCtx->LenInBitCount[0]; - - pCtx->LenInBitCount[0] = (UINT32) (pCtx->LenInBitCount[0] + (LenInBytes << 3)); - - if (pCtx->LenInBitCount[0] < temp) - pCtx->LenInBitCount[1]++; //carry in - - pCtx->LenInBitCount[1] += LenInBytes >> 29; - - // mod 64 bytes - temp = (temp >> 3) & 0x3f; - - // process lacks of 64-byte data - if (temp) - { - UCHAR *pAds = (UCHAR *) pCtx->Input + temp; - - if ((temp+LenInBytes) < 64) - { - NdisMoveMemory(pAds, (UCHAR *)pData, LenInBytes); - return; - } - - NdisMoveMemory(pAds, (UCHAR *)pData, 64-temp); - byteReverse(pCtx->Input, 16); - MD5Transform(pCtx->Buf, (UINT32 *)pCtx->Input); - - pData += 64-temp; - LenInBytes -= 64-temp; - } // end of if (temp) - - - TfTimes = (LenInBytes >> 6); - - for (i=TfTimes; i>0; i--) - { - NdisMoveMemory(pCtx->Input, (UCHAR *)pData, 64); - byteReverse(pCtx->Input, 16); - MD5Transform(pCtx->Buf, (UINT32 *)pCtx->Input); - pData += 64; - LenInBytes -= 64; - } // end of for - - // buffering lacks of 64-byte data - if(LenInBytes) - NdisMoveMemory(pCtx->Input, (UCHAR *)pData, LenInBytes); - -} - - -/* - * Function Description: - * Append padding bits and length of original message in the tail - * The message digest has to be completed in the end - * - * Arguments: - * Digest Output of Digest-Message for MD5 - * pCtx Pointer to MD5 context - * - * Return Value: - * None - * - * Note: - * Called after MD5Update - */ -VOID MD5Final(UCHAR Digest[16], MD5_CTX *pCtx) -{ - UCHAR Remainder; - UCHAR PadLenInBytes; - UCHAR *pAppend=0; - unsigned int i; - - Remainder = (UCHAR)((pCtx->LenInBitCount[0] >> 3) & 0x3f); - - PadLenInBytes = (Remainder < 56) ? (56-Remainder) : (120-Remainder); - - pAppend = (UCHAR *)pCtx->Input + Remainder; - - // padding bits without crossing block(64-byte based) boundary - if (Remainder < 56) - { - *pAppend = 0x80; - PadLenInBytes --; - - NdisZeroMemory((UCHAR *)pCtx->Input + Remainder+1, PadLenInBytes); - - // add data-length field, from low to high - for (i=0; i<4; i++) - { - pCtx->Input[56+i] = (UCHAR)((pCtx->LenInBitCount[0] >> (i << 3)) & 0xff); - pCtx->Input[60+i] = (UCHAR)((pCtx->LenInBitCount[1] >> (i << 3)) & 0xff); - } - - byteReverse(pCtx->Input, 16); - MD5Transform(pCtx->Buf, (UINT32 *)pCtx->Input); - } // end of if - - // padding bits with crossing block(64-byte based) boundary - else - { - // the first block === - *pAppend = 0x80; - PadLenInBytes --; - - NdisZeroMemory((UCHAR *)pCtx->Input + Remainder+1, (64-Remainder-1)); - PadLenInBytes -= (64 - Remainder - 1); - - byteReverse(pCtx->Input, 16); - MD5Transform(pCtx->Buf, (UINT32 *)pCtx->Input); - - - // the second block === - NdisZeroMemory((UCHAR *)pCtx->Input, PadLenInBytes); - - // add data-length field - for (i=0; i<4; i++) - { - pCtx->Input[56+i] = (UCHAR)((pCtx->LenInBitCount[0] >> (i << 3)) & 0xff); - pCtx->Input[60+i] = (UCHAR)((pCtx->LenInBitCount[1] >> (i << 3)) & 0xff); - } - - byteReverse(pCtx->Input, 16); - MD5Transform(pCtx->Buf, (UINT32 *)pCtx->Input); - } // end of else - - - NdisMoveMemory((UCHAR *)Digest, (UINT32 *)pCtx->Buf, 16); // output - byteReverse((UCHAR *)Digest, 4); - NdisZeroMemory(pCtx, sizeof(pCtx)); // memory free -} - - -/* - * Function Description: - * The central algorithm of MD5, consists of four rounds and sixteen - * steps per round - * - * Arguments: - * Buf Buffers of four states (output: 16 bytes) - * Mes Input data (input: 64 bytes) - * - * Return Value: - * None - * - * Note: - * Called by MD5Update or MD5Final - */ -VOID MD5Transform(UINT32 Buf[4], UINT32 Mes[16]) -{ - UINT32 Reg[4], Temp; - unsigned int i; - - static UCHAR LShiftVal[16] = - { - 7, 12, 17, 22, - 5, 9 , 14, 20, - 4, 11, 16, 23, - 6, 10, 15, 21, - }; - - - // [equal to 4294967296*abs(sin(index))] - static UINT32 MD5Table[64] = - { - 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, - 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, - 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, - 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, - - 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, - 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, - 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, - 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, - - 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, - 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, - 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, - 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, - - 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, - 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, - 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, - 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 - }; - - - for (i=0; i<4; i++) - Reg[i]=Buf[i]; - - - // 64 steps in MD5 algorithm - for (i=0; i<16; i++) - { - MD5Step(MD5_F1, Reg[0], Reg[1], Reg[2], Reg[3], Mes[i], - MD5Table[i], LShiftVal[i & 0x3]); - - // one-word right shift - Temp = Reg[3]; - Reg[3] = Reg[2]; - Reg[2] = Reg[1]; - Reg[1] = Reg[0]; - Reg[0] = Temp; - } - for (i=16; i<32; i++) - { - MD5Step(MD5_F2, Reg[0], Reg[1], Reg[2], Reg[3], Mes[(5*(i & 0xf)+1) & 0xf], - MD5Table[i], LShiftVal[(0x1 << 2)+(i & 0x3)]); - - // one-word right shift - Temp = Reg[3]; - Reg[3] = Reg[2]; - Reg[2] = Reg[1]; - Reg[1] = Reg[0]; - Reg[0] = Temp; - } - for (i=32; i<48; i++) - { - MD5Step(MD5_F3, Reg[0], Reg[1], Reg[2], Reg[3], Mes[(3*(i & 0xf)+5) & 0xf], - MD5Table[i], LShiftVal[(0x1 << 3)+(i & 0x3)]); - - // one-word right shift - Temp = Reg[3]; - Reg[3] = Reg[2]; - Reg[2] = Reg[1]; - Reg[1] = Reg[0]; - Reg[0] = Temp; - } - for (i=48; i<64; i++) - { - MD5Step(MD5_F4, Reg[0], Reg[1], Reg[2], Reg[3], Mes[(7*(i & 0xf)) & 0xf], - MD5Table[i], LShiftVal[(0x3 << 2)+(i & 0x3)]); - - // one-word right shift - Temp = Reg[3]; - Reg[3] = Reg[2]; - Reg[2] = Reg[1]; - Reg[1] = Reg[0]; - Reg[0] = Temp; - } - - - // (temporary)output - for (i=0; i<4; i++) - Buf[i] += Reg[i]; - -} - - - -/* ========================= SHA-1 implementation ========================== */ -// four base functions for SHA-1 -#define SHA1_F1(b, c, d) (((b) & (c)) | ((~b) & (d))) -#define SHA1_F2(b, c, d) ((b) ^ (c) ^ (d)) -#define SHA1_F3(b, c, d) (((b) & (c)) | ((b) & (d)) | ((c) & (d))) - - -#define SHA1Step(f, a, b, c, d, e, w, k) \ - ( e += ( f(b, c, d) + w + k + CYCLIC_LEFT_SHIFT(a, 5)) & 0xffffffff, \ - b = CYCLIC_LEFT_SHIFT(b, 30) ) - -//Initiate SHA-1 Context satisfied in RFC 3174 -VOID SHAInit(SHA_CTX *pCtx) -{ - pCtx->Buf[0]=0x67452301; - pCtx->Buf[1]=0xefcdab89; - pCtx->Buf[2]=0x98badcfe; - pCtx->Buf[3]=0x10325476; - pCtx->Buf[4]=0xc3d2e1f0; - - pCtx->LenInBitCount[0]=0; - pCtx->LenInBitCount[1]=0; -} - -/* - * Function Description: - * Update SHA-1 Context, allow of an arrary of octets as the next - * portion of the message - * - * Arguments: - * pCtx Pointer to SHA-1 context - * pData Pointer to input data - * LenInBytes The length of input data (unit: byte) - * - * Return Value: - * error indicate more than pow(2,64) bits of data - * - * Note: - * Called after SHAInit or SHAUpdate(itself) - */ -UCHAR SHAUpdate(SHA_CTX *pCtx, UCHAR *pData, UINT32 LenInBytes) -{ - UINT32 TfTimes; - UINT32 temp1,temp2; - unsigned int i; - UCHAR err=1; - - temp1 = pCtx->LenInBitCount[0]; - temp2 = pCtx->LenInBitCount[1]; - - pCtx->LenInBitCount[0] = (UINT32) (pCtx->LenInBitCount[0] + (LenInBytes << 3)); - if (pCtx->LenInBitCount[0] < temp1) - pCtx->LenInBitCount[1]++; //carry in - - - pCtx->LenInBitCount[1] = (UINT32) (pCtx->LenInBitCount[1] +(LenInBytes >> 29)); - if (pCtx->LenInBitCount[1] < temp2) - return (err); //check total length of original data - - - // mod 64 bytes - temp1 = (temp1 >> 3) & 0x3f; - - // process lacks of 64-byte data - if (temp1) - { - UCHAR *pAds = (UCHAR *) pCtx->Input + temp1; - - if ((temp1+LenInBytes) < 64) - { - NdisMoveMemory(pAds, (UCHAR *)pData, LenInBytes); - return (0); - } - - NdisMoveMemory(pAds, (UCHAR *)pData, 64-temp1); - byteReverse((UCHAR *)pCtx->Input, 16); - - NdisZeroMemory((UCHAR *)pCtx->Input + 64, 16); - SHATransform(pCtx->Buf, (UINT32 *)pCtx->Input); - - pData += 64-temp1; - LenInBytes -= 64-temp1; - } // end of if (temp1) - - - TfTimes = (LenInBytes >> 6); - - for (i=TfTimes; i>0; i--) - { - NdisMoveMemory(pCtx->Input, (UCHAR *)pData, 64); - byteReverse((UCHAR *)pCtx->Input, 16); - - NdisZeroMemory((UCHAR *)pCtx->Input + 64, 16); - SHATransform(pCtx->Buf, (UINT32 *)pCtx->Input); - pData += 64; - LenInBytes -= 64; - } // end of for - - // buffering lacks of 64-byte data - if(LenInBytes) - NdisMoveMemory(pCtx->Input, (UCHAR *)pData, LenInBytes); - - return (0); - -} - -// Append padding bits and length of original message in the tail -// The message digest has to be completed in the end -VOID SHAFinal(SHA_CTX *pCtx, UCHAR Digest[20]) -{ - UCHAR Remainder; - UCHAR PadLenInBytes; - UCHAR *pAppend=0; - unsigned int i; - - Remainder = (UCHAR)((pCtx->LenInBitCount[0] >> 3) & 0x3f); - - pAppend = (UCHAR *)pCtx->Input + Remainder; - - PadLenInBytes = (Remainder < 56) ? (56-Remainder) : (120-Remainder); - - // padding bits without crossing block(64-byte based) boundary - if (Remainder < 56) - { - *pAppend = 0x80; - PadLenInBytes --; - - NdisZeroMemory((UCHAR *)pCtx->Input + Remainder+1, PadLenInBytes); - - // add data-length field, from high to low - for (i=0; i<4; i++) - { - pCtx->Input[56+i] = (UCHAR)((pCtx->LenInBitCount[1] >> ((3-i) << 3)) & 0xff); - pCtx->Input[60+i] = (UCHAR)((pCtx->LenInBitCount[0] >> ((3-i) << 3)) & 0xff); - } - - byteReverse((UCHAR *)pCtx->Input, 16); - NdisZeroMemory((UCHAR *)pCtx->Input + 64, 14); - SHATransform(pCtx->Buf, (UINT32 *)pCtx->Input); - } // end of if - - // padding bits with crossing block(64-byte based) boundary - else - { - // the first block === - *pAppend = 0x80; - PadLenInBytes --; - - NdisZeroMemory((UCHAR *)pCtx->Input + Remainder+1, (64-Remainder-1)); - PadLenInBytes -= (64 - Remainder - 1); - - byteReverse((UCHAR *)pCtx->Input, 16); - NdisZeroMemory((UCHAR *)pCtx->Input + 64, 16); - SHATransform(pCtx->Buf, (UINT32 *)pCtx->Input); - - - // the second block === - NdisZeroMemory((UCHAR *)pCtx->Input, PadLenInBytes); - - // add data-length field - for (i=0; i<4; i++) - { - pCtx->Input[56+i] = (UCHAR)((pCtx->LenInBitCount[1] >> ((3-i) << 3)) & 0xff); - pCtx->Input[60+i] = (UCHAR)((pCtx->LenInBitCount[0] >> ((3-i) << 3)) & 0xff); - } - - byteReverse((UCHAR *)pCtx->Input, 16); - NdisZeroMemory((UCHAR *)pCtx->Input + 64, 16); - SHATransform(pCtx->Buf, (UINT32 *)pCtx->Input); - } // end of else - - - //Output, bytereverse - for (i=0; i<20; i++) - { - Digest [i] = (UCHAR)(pCtx->Buf[i>>2] >> 8*(3-(i & 0x3))); - } - - NdisZeroMemory(pCtx, sizeof(pCtx)); // memory free -} - - -// The central algorithm of SHA-1, consists of four rounds and -// twenty steps per round -VOID SHATransform(UINT32 Buf[5], UINT32 Mes[20]) -{ - UINT32 Reg[5],Temp; - unsigned int i; - UINT32 W[80]; - - static UINT32 SHA1Table[4] = { 0x5a827999, 0x6ed9eba1, - 0x8f1bbcdc, 0xca62c1d6 }; - - Reg[0]=Buf[0]; - Reg[1]=Buf[1]; - Reg[2]=Buf[2]; - Reg[3]=Buf[3]; - Reg[4]=Buf[4]; - - //the first octet of a word is stored in the 0th element, bytereverse - for(i = 0; i < 16; i++) - { - W[i] = (Mes[i] >> 24) & 0xff; - W[i] |= (Mes[i] >> 8 ) & 0xff00; - W[i] |= (Mes[i] << 8 ) & 0xff0000; - W[i] |= (Mes[i] << 24) & 0xff000000; - } - - - for (i = 0; i < 64; i++) - W[16+i] = CYCLIC_LEFT_SHIFT(W[i] ^ W[2+i] ^ W[8+i] ^ W[13+i], 1); - - - // 80 steps in SHA-1 algorithm - for (i=0; i<80; i++) - { - if (i<20) - SHA1Step(SHA1_F1, Reg[0], Reg[1], Reg[2], Reg[3], Reg[4], - W[i], SHA1Table[0]); - - else if (i>=20 && i<40) - SHA1Step(SHA1_F2, Reg[0], Reg[1], Reg[2], Reg[3], Reg[4], - W[i], SHA1Table[1]); - - else if (i>=40 && i<60) - SHA1Step(SHA1_F3, Reg[0], Reg[1], Reg[2], Reg[3], Reg[4], - W[i], SHA1Table[2]); - - else - SHA1Step(SHA1_F2, Reg[0], Reg[1], Reg[2], Reg[3], Reg[4], - W[i], SHA1Table[3]); - - - // one-word right shift - Temp = Reg[4]; - Reg[4] = Reg[3]; - Reg[3] = Reg[2]; - Reg[2] = Reg[1]; - Reg[1] = Reg[0]; - Reg[0] = Temp; - - } // end of for-loop - - - // (temporary)output - for (i=0; i<5; i++) - Buf[i] += Reg[i]; - -} - - -/* ========================= AES En/Decryption ========================== */ - -/* forward S-box */ -static uint32 FSb[256] = -{ - 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, - 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, - 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, - 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, - 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, - 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, - 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, - 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, - 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, - 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, - 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, - 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, - 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, - 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, - 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, - 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, - 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, - 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, - 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, - 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, - 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, - 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, - 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, - 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, - 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, - 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, - 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, - 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, - 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, - 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, - 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, - 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 -}; - -/* forward table */ -#define FT \ -\ - V(C6,63,63,A5), V(F8,7C,7C,84), V(EE,77,77,99), V(F6,7B,7B,8D), \ - V(FF,F2,F2,0D), V(D6,6B,6B,BD), V(DE,6F,6F,B1), V(91,C5,C5,54), \ - V(60,30,30,50), V(02,01,01,03), V(CE,67,67,A9), V(56,2B,2B,7D), \ - V(E7,FE,FE,19), V(B5,D7,D7,62), V(4D,AB,AB,E6), V(EC,76,76,9A), \ - V(8F,CA,CA,45), V(1F,82,82,9D), V(89,C9,C9,40), V(FA,7D,7D,87), \ - V(EF,FA,FA,15), V(B2,59,59,EB), V(8E,47,47,C9), V(FB,F0,F0,0B), \ - V(41,AD,AD,EC), V(B3,D4,D4,67), V(5F,A2,A2,FD), V(45,AF,AF,EA), \ - V(23,9C,9C,BF), V(53,A4,A4,F7), V(E4,72,72,96), V(9B,C0,C0,5B), \ - V(75,B7,B7,C2), V(E1,FD,FD,1C), V(3D,93,93,AE), V(4C,26,26,6A), \ - V(6C,36,36,5A), V(7E,3F,3F,41), V(F5,F7,F7,02), V(83,CC,CC,4F), \ - V(68,34,34,5C), V(51,A5,A5,F4), V(D1,E5,E5,34), V(F9,F1,F1,08), \ - V(E2,71,71,93), V(AB,D8,D8,73), V(62,31,31,53), V(2A,15,15,3F), \ - V(08,04,04,0C), V(95,C7,C7,52), V(46,23,23,65), V(9D,C3,C3,5E), \ - V(30,18,18,28), V(37,96,96,A1), V(0A,05,05,0F), V(2F,9A,9A,B5), \ - V(0E,07,07,09), V(24,12,12,36), V(1B,80,80,9B), V(DF,E2,E2,3D), \ - V(CD,EB,EB,26), V(4E,27,27,69), V(7F,B2,B2,CD), V(EA,75,75,9F), \ - V(12,09,09,1B), V(1D,83,83,9E), V(58,2C,2C,74), V(34,1A,1A,2E), \ - V(36,1B,1B,2D), V(DC,6E,6E,B2), V(B4,5A,5A,EE), V(5B,A0,A0,FB), \ - V(A4,52,52,F6), V(76,3B,3B,4D), V(B7,D6,D6,61), V(7D,B3,B3,CE), \ - V(52,29,29,7B), V(DD,E3,E3,3E), V(5E,2F,2F,71), V(13,84,84,97), \ - V(A6,53,53,F5), V(B9,D1,D1,68), V(00,00,00,00), V(C1,ED,ED,2C), \ - V(40,20,20,60), V(E3,FC,FC,1F), V(79,B1,B1,C8), V(B6,5B,5B,ED), \ - V(D4,6A,6A,BE), V(8D,CB,CB,46), V(67,BE,BE,D9), V(72,39,39,4B), \ - V(94,4A,4A,DE), V(98,4C,4C,D4), V(B0,58,58,E8), V(85,CF,CF,4A), \ - V(BB,D0,D0,6B), V(C5,EF,EF,2A), V(4F,AA,AA,E5), V(ED,FB,FB,16), \ - V(86,43,43,C5), V(9A,4D,4D,D7), V(66,33,33,55), V(11,85,85,94), \ - V(8A,45,45,CF), V(E9,F9,F9,10), V(04,02,02,06), V(FE,7F,7F,81), \ - V(A0,50,50,F0), V(78,3C,3C,44), V(25,9F,9F,BA), V(4B,A8,A8,E3), \ - V(A2,51,51,F3), V(5D,A3,A3,FE), V(80,40,40,C0), V(05,8F,8F,8A), \ - V(3F,92,92,AD), V(21,9D,9D,BC), V(70,38,38,48), V(F1,F5,F5,04), \ - V(63,BC,BC,DF), V(77,B6,B6,C1), V(AF,DA,DA,75), V(42,21,21,63), \ - V(20,10,10,30), V(E5,FF,FF,1A), V(FD,F3,F3,0E), V(BF,D2,D2,6D), \ - V(81,CD,CD,4C), V(18,0C,0C,14), V(26,13,13,35), V(C3,EC,EC,2F), \ - V(BE,5F,5F,E1), V(35,97,97,A2), V(88,44,44,CC), V(2E,17,17,39), \ - V(93,C4,C4,57), V(55,A7,A7,F2), V(FC,7E,7E,82), V(7A,3D,3D,47), \ - V(C8,64,64,AC), V(BA,5D,5D,E7), V(32,19,19,2B), V(E6,73,73,95), \ - V(C0,60,60,A0), V(19,81,81,98), V(9E,4F,4F,D1), V(A3,DC,DC,7F), \ - V(44,22,22,66), V(54,2A,2A,7E), V(3B,90,90,AB), V(0B,88,88,83), \ - V(8C,46,46,CA), V(C7,EE,EE,29), V(6B,B8,B8,D3), V(28,14,14,3C), \ - V(A7,DE,DE,79), V(BC,5E,5E,E2), V(16,0B,0B,1D), V(AD,DB,DB,76), \ - V(DB,E0,E0,3B), V(64,32,32,56), V(74,3A,3A,4E), V(14,0A,0A,1E), \ - V(92,49,49,DB), V(0C,06,06,0A), V(48,24,24,6C), V(B8,5C,5C,E4), \ - V(9F,C2,C2,5D), V(BD,D3,D3,6E), V(43,AC,AC,EF), V(C4,62,62,A6), \ - V(39,91,91,A8), V(31,95,95,A4), V(D3,E4,E4,37), V(F2,79,79,8B), \ - V(D5,E7,E7,32), V(8B,C8,C8,43), V(6E,37,37,59), V(DA,6D,6D,B7), \ - V(01,8D,8D,8C), V(B1,D5,D5,64), V(9C,4E,4E,D2), V(49,A9,A9,E0), \ - V(D8,6C,6C,B4), V(AC,56,56,FA), V(F3,F4,F4,07), V(CF,EA,EA,25), \ - V(CA,65,65,AF), V(F4,7A,7A,8E), V(47,AE,AE,E9), V(10,08,08,18), \ - V(6F,BA,BA,D5), V(F0,78,78,88), V(4A,25,25,6F), V(5C,2E,2E,72), \ - V(38,1C,1C,24), V(57,A6,A6,F1), V(73,B4,B4,C7), V(97,C6,C6,51), \ - V(CB,E8,E8,23), V(A1,DD,DD,7C), V(E8,74,74,9C), V(3E,1F,1F,21), \ - V(96,4B,4B,DD), V(61,BD,BD,DC), V(0D,8B,8B,86), V(0F,8A,8A,85), \ - V(E0,70,70,90), V(7C,3E,3E,42), V(71,B5,B5,C4), V(CC,66,66,AA), \ - V(90,48,48,D8), V(06,03,03,05), V(F7,F6,F6,01), V(1C,0E,0E,12), \ - V(C2,61,61,A3), V(6A,35,35,5F), V(AE,57,57,F9), V(69,B9,B9,D0), \ - V(17,86,86,91), V(99,C1,C1,58), V(3A,1D,1D,27), V(27,9E,9E,B9), \ - V(D9,E1,E1,38), V(EB,F8,F8,13), V(2B,98,98,B3), V(22,11,11,33), \ - V(D2,69,69,BB), V(A9,D9,D9,70), V(07,8E,8E,89), V(33,94,94,A7), \ - V(2D,9B,9B,B6), V(3C,1E,1E,22), V(15,87,87,92), V(C9,E9,E9,20), \ - V(87,CE,CE,49), V(AA,55,55,FF), V(50,28,28,78), V(A5,DF,DF,7A), \ - V(03,8C,8C,8F), V(59,A1,A1,F8), V(09,89,89,80), V(1A,0D,0D,17), \ - V(65,BF,BF,DA), V(D7,E6,E6,31), V(84,42,42,C6), V(D0,68,68,B8), \ - V(82,41,41,C3), V(29,99,99,B0), V(5A,2D,2D,77), V(1E,0F,0F,11), \ - V(7B,B0,B0,CB), V(A8,54,54,FC), V(6D,BB,BB,D6), V(2C,16,16,3A) - -#define V(a,b,c,d) 0x##a##b##c##d -static uint32 FT0[256] = { FT }; -#undef V - -#define V(a,b,c,d) 0x##d##a##b##c -static uint32 FT1[256] = { FT }; -#undef V - -#define V(a,b,c,d) 0x##c##d##a##b -static uint32 FT2[256] = { FT }; -#undef V - -#define V(a,b,c,d) 0x##b##c##d##a -static uint32 FT3[256] = { FT }; -#undef V - -#undef FT - -/* reverse S-box */ - -static uint32 RSb[256] = -{ - 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, - 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, - 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, - 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, - 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, - 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, - 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, - 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, - 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, - 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, - 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, - 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, - 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, - 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, - 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, - 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, - 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, - 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, - 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, - 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, - 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, - 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, - 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, - 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, - 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, - 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, - 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, - 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, - 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, - 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, - 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, - 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D -}; - -/* reverse table */ - -#define RT \ -\ - V(51,F4,A7,50), V(7E,41,65,53), V(1A,17,A4,C3), V(3A,27,5E,96), \ - V(3B,AB,6B,CB), V(1F,9D,45,F1), V(AC,FA,58,AB), V(4B,E3,03,93), \ - V(20,30,FA,55), V(AD,76,6D,F6), V(88,CC,76,91), V(F5,02,4C,25), \ - V(4F,E5,D7,FC), V(C5,2A,CB,D7), V(26,35,44,80), V(B5,62,A3,8F), \ - V(DE,B1,5A,49), V(25,BA,1B,67), V(45,EA,0E,98), V(5D,FE,C0,E1), \ - V(C3,2F,75,02), V(81,4C,F0,12), V(8D,46,97,A3), V(6B,D3,F9,C6), \ - V(03,8F,5F,E7), V(15,92,9C,95), V(BF,6D,7A,EB), V(95,52,59,DA), \ - V(D4,BE,83,2D), V(58,74,21,D3), V(49,E0,69,29), V(8E,C9,C8,44), \ - V(75,C2,89,6A), V(F4,8E,79,78), V(99,58,3E,6B), V(27,B9,71,DD), \ - V(BE,E1,4F,B6), V(F0,88,AD,17), V(C9,20,AC,66), V(7D,CE,3A,B4), \ - V(63,DF,4A,18), V(E5,1A,31,82), V(97,51,33,60), V(62,53,7F,45), \ - V(B1,64,77,E0), V(BB,6B,AE,84), V(FE,81,A0,1C), V(F9,08,2B,94), \ - V(70,48,68,58), V(8F,45,FD,19), V(94,DE,6C,87), V(52,7B,F8,B7), \ - V(AB,73,D3,23), V(72,4B,02,E2), V(E3,1F,8F,57), V(66,55,AB,2A), \ - V(B2,EB,28,07), V(2F,B5,C2,03), V(86,C5,7B,9A), V(D3,37,08,A5), \ - V(30,28,87,F2), V(23,BF,A5,B2), V(02,03,6A,BA), V(ED,16,82,5C), \ - V(8A,CF,1C,2B), V(A7,79,B4,92), V(F3,07,F2,F0), V(4E,69,E2,A1), \ - V(65,DA,F4,CD), V(06,05,BE,D5), V(D1,34,62,1F), V(C4,A6,FE,8A), \ - V(34,2E,53,9D), V(A2,F3,55,A0), V(05,8A,E1,32), V(A4,F6,EB,75), \ - V(0B,83,EC,39), V(40,60,EF,AA), V(5E,71,9F,06), V(BD,6E,10,51), \ - V(3E,21,8A,F9), V(96,DD,06,3D), V(DD,3E,05,AE), V(4D,E6,BD,46), \ - V(91,54,8D,B5), V(71,C4,5D,05), V(04,06,D4,6F), V(60,50,15,FF), \ - V(19,98,FB,24), V(D6,BD,E9,97), V(89,40,43,CC), V(67,D9,9E,77), \ - V(B0,E8,42,BD), V(07,89,8B,88), V(E7,19,5B,38), V(79,C8,EE,DB), \ - V(A1,7C,0A,47), V(7C,42,0F,E9), V(F8,84,1E,C9), V(00,00,00,00), \ - V(09,80,86,83), V(32,2B,ED,48), V(1E,11,70,AC), V(6C,5A,72,4E), \ - V(FD,0E,FF,FB), V(0F,85,38,56), V(3D,AE,D5,1E), V(36,2D,39,27), \ - V(0A,0F,D9,64), V(68,5C,A6,21), V(9B,5B,54,D1), V(24,36,2E,3A), \ - V(0C,0A,67,B1), V(93,57,E7,0F), V(B4,EE,96,D2), V(1B,9B,91,9E), \ - V(80,C0,C5,4F), V(61,DC,20,A2), V(5A,77,4B,69), V(1C,12,1A,16), \ - V(E2,93,BA,0A), V(C0,A0,2A,E5), V(3C,22,E0,43), V(12,1B,17,1D), \ - V(0E,09,0D,0B), V(F2,8B,C7,AD), V(2D,B6,A8,B9), V(14,1E,A9,C8), \ - V(57,F1,19,85), V(AF,75,07,4C), V(EE,99,DD,BB), V(A3,7F,60,FD), \ - V(F7,01,26,9F), V(5C,72,F5,BC), V(44,66,3B,C5), V(5B,FB,7E,34), \ - V(8B,43,29,76), V(CB,23,C6,DC), V(B6,ED,FC,68), V(B8,E4,F1,63), \ - V(D7,31,DC,CA), V(42,63,85,10), V(13,97,22,40), V(84,C6,11,20), \ - V(85,4A,24,7D), V(D2,BB,3D,F8), V(AE,F9,32,11), V(C7,29,A1,6D), \ - V(1D,9E,2F,4B), V(DC,B2,30,F3), V(0D,86,52,EC), V(77,C1,E3,D0), \ - V(2B,B3,16,6C), V(A9,70,B9,99), V(11,94,48,FA), V(47,E9,64,22), \ - V(A8,FC,8C,C4), V(A0,F0,3F,1A), V(56,7D,2C,D8), V(22,33,90,EF), \ - V(87,49,4E,C7), V(D9,38,D1,C1), V(8C,CA,A2,FE), V(98,D4,0B,36), \ - V(A6,F5,81,CF), V(A5,7A,DE,28), V(DA,B7,8E,26), V(3F,AD,BF,A4), \ - V(2C,3A,9D,E4), V(50,78,92,0D), V(6A,5F,CC,9B), V(54,7E,46,62), \ - V(F6,8D,13,C2), V(90,D8,B8,E8), V(2E,39,F7,5E), V(82,C3,AF,F5), \ - V(9F,5D,80,BE), V(69,D0,93,7C), V(6F,D5,2D,A9), V(CF,25,12,B3), \ - V(C8,AC,99,3B), V(10,18,7D,A7), V(E8,9C,63,6E), V(DB,3B,BB,7B), \ - V(CD,26,78,09), V(6E,59,18,F4), V(EC,9A,B7,01), V(83,4F,9A,A8), \ - V(E6,95,6E,65), V(AA,FF,E6,7E), V(21,BC,CF,08), V(EF,15,E8,E6), \ - V(BA,E7,9B,D9), V(4A,6F,36,CE), V(EA,9F,09,D4), V(29,B0,7C,D6), \ - V(31,A4,B2,AF), V(2A,3F,23,31), V(C6,A5,94,30), V(35,A2,66,C0), \ - V(74,4E,BC,37), V(FC,82,CA,A6), V(E0,90,D0,B0), V(33,A7,D8,15), \ - V(F1,04,98,4A), V(41,EC,DA,F7), V(7F,CD,50,0E), V(17,91,F6,2F), \ - V(76,4D,D6,8D), V(43,EF,B0,4D), V(CC,AA,4D,54), V(E4,96,04,DF), \ - V(9E,D1,B5,E3), V(4C,6A,88,1B), V(C1,2C,1F,B8), V(46,65,51,7F), \ - V(9D,5E,EA,04), V(01,8C,35,5D), V(FA,87,74,73), V(FB,0B,41,2E), \ - V(B3,67,1D,5A), V(92,DB,D2,52), V(E9,10,56,33), V(6D,D6,47,13), \ - V(9A,D7,61,8C), V(37,A1,0C,7A), V(59,F8,14,8E), V(EB,13,3C,89), \ - V(CE,A9,27,EE), V(B7,61,C9,35), V(E1,1C,E5,ED), V(7A,47,B1,3C), \ - V(9C,D2,DF,59), V(55,F2,73,3F), V(18,14,CE,79), V(73,C7,37,BF), \ - V(53,F7,CD,EA), V(5F,FD,AA,5B), V(DF,3D,6F,14), V(78,44,DB,86), \ - V(CA,AF,F3,81), V(B9,68,C4,3E), V(38,24,34,2C), V(C2,A3,40,5F), \ - V(16,1D,C3,72), V(BC,E2,25,0C), V(28,3C,49,8B), V(FF,0D,95,41), \ - V(39,A8,01,71), V(08,0C,B3,DE), V(D8,B4,E4,9C), V(64,56,C1,90), \ - V(7B,CB,84,61), V(D5,32,B6,70), V(48,6C,5C,74), V(D0,B8,57,42) - -#define V(a,b,c,d) 0x##a##b##c##d -static uint32 RT0[256] = { RT }; -#undef V - -#define V(a,b,c,d) 0x##d##a##b##c -static uint32 RT1[256] = { RT }; -#undef V - -#define V(a,b,c,d) 0x##c##d##a##b -static uint32 RT2[256] = { RT }; -#undef V - -#define V(a,b,c,d) 0x##b##c##d##a -static uint32 RT3[256] = { RT }; -#undef V - -#undef RT - -/* round constants */ - -static uint32 RCON[10] = -{ - 0x01000000, 0x02000000, 0x04000000, 0x08000000, - 0x10000000, 0x20000000, 0x40000000, 0x80000000, - 0x1B000000, 0x36000000 -}; - -/* key schedule tables */ - -static int KT_init = 1; - -static uint32 KT0[256]; -static uint32 KT1[256]; -static uint32 KT2[256]; -static uint32 KT3[256]; - -/* platform-independant 32-bit integer manipulation macros */ - -#define GET_UINT32(n,b,i) \ -{ \ - (n) = ( (uint32) (b)[(i) ] << 24 ) \ - | ( (uint32) (b)[(i) + 1] << 16 ) \ - | ( (uint32) (b)[(i) + 2] << 8 ) \ - | ( (uint32) (b)[(i) + 3] ); \ -} - -#define PUT_UINT32(n,b,i) \ -{ \ - (b)[(i) ] = (uint8) ( (n) >> 24 ); \ - (b)[(i) + 1] = (uint8) ( (n) >> 16 ); \ - (b)[(i) + 2] = (uint8) ( (n) >> 8 ); \ - (b)[(i) + 3] = (uint8) ( (n) ); \ -} - -/* AES key scheduling routine */ - -int rtmp_aes_set_key( aes_context *ctx, uint8 *key, int nbits ) -{ - int i; - uint32 *RK, *SK; - - switch( nbits ) - { - case 128: ctx->nr = 10; break; - case 192: ctx->nr = 12; break; - case 256: ctx->nr = 14; break; - default : return( 1 ); - } - - RK = ctx->erk; - - for( i = 0; i < (nbits >> 5); i++ ) - { - GET_UINT32( RK[i], key, i * 4 ); - } - - /* setup encryption round keys */ - - switch( nbits ) - { - case 128: - - for( i = 0; i < 10; i++, RK += 4 ) - { - RK[4] = RK[0] ^ RCON[i] ^ - ( FSb[ (uint8) ( RK[3] >> 16 ) ] << 24 ) ^ - ( FSb[ (uint8) ( RK[3] >> 8 ) ] << 16 ) ^ - ( FSb[ (uint8) ( RK[3] ) ] << 8 ) ^ - ( FSb[ (uint8) ( RK[3] >> 24 ) ] ); - - RK[5] = RK[1] ^ RK[4]; - RK[6] = RK[2] ^ RK[5]; - RK[7] = RK[3] ^ RK[6]; - } - break; - - case 192: - - for( i = 0; i < 8; i++, RK += 6 ) - { - RK[6] = RK[0] ^ RCON[i] ^ - ( FSb[ (uint8) ( RK[5] >> 16 ) ] << 24 ) ^ - ( FSb[ (uint8) ( RK[5] >> 8 ) ] << 16 ) ^ - ( FSb[ (uint8) ( RK[5] ) ] << 8 ) ^ - ( FSb[ (uint8) ( RK[5] >> 24 ) ] ); - - RK[7] = RK[1] ^ RK[6]; - RK[8] = RK[2] ^ RK[7]; - RK[9] = RK[3] ^ RK[8]; - RK[10] = RK[4] ^ RK[9]; - RK[11] = RK[5] ^ RK[10]; - } - break; - - case 256: - - for( i = 0; i < 7; i++, RK += 8 ) - { - RK[8] = RK[0] ^ RCON[i] ^ - ( FSb[ (uint8) ( RK[7] >> 16 ) ] << 24 ) ^ - ( FSb[ (uint8) ( RK[7] >> 8 ) ] << 16 ) ^ - ( FSb[ (uint8) ( RK[7] ) ] << 8 ) ^ - ( FSb[ (uint8) ( RK[7] >> 24 ) ] ); - - RK[9] = RK[1] ^ RK[8]; - RK[10] = RK[2] ^ RK[9]; - RK[11] = RK[3] ^ RK[10]; - - RK[12] = RK[4] ^ - ( FSb[ (uint8) ( RK[11] >> 24 ) ] << 24 ) ^ - ( FSb[ (uint8) ( RK[11] >> 16 ) ] << 16 ) ^ - ( FSb[ (uint8) ( RK[11] >> 8 ) ] << 8 ) ^ - ( FSb[ (uint8) ( RK[11] ) ] ); - - RK[13] = RK[5] ^ RK[12]; - RK[14] = RK[6] ^ RK[13]; - RK[15] = RK[7] ^ RK[14]; - } - break; - } - - /* setup decryption round keys */ - - if( KT_init ) - { - for( i = 0; i < 256; i++ ) - { - KT0[i] = RT0[ FSb[i] ]; - KT1[i] = RT1[ FSb[i] ]; - KT2[i] = RT2[ FSb[i] ]; - KT3[i] = RT3[ FSb[i] ]; - } - - KT_init = 0; - } - - SK = ctx->drk; - - *SK++ = *RK++; - *SK++ = *RK++; - *SK++ = *RK++; - *SK++ = *RK++; - - for( i = 1; i < ctx->nr; i++ ) - { - RK -= 8; - - *SK++ = KT0[ (uint8) ( *RK >> 24 ) ] ^ - KT1[ (uint8) ( *RK >> 16 ) ] ^ - KT2[ (uint8) ( *RK >> 8 ) ] ^ - KT3[ (uint8) ( *RK ) ]; RK++; - - *SK++ = KT0[ (uint8) ( *RK >> 24 ) ] ^ - KT1[ (uint8) ( *RK >> 16 ) ] ^ - KT2[ (uint8) ( *RK >> 8 ) ] ^ - KT3[ (uint8) ( *RK ) ]; RK++; - - *SK++ = KT0[ (uint8) ( *RK >> 24 ) ] ^ - KT1[ (uint8) ( *RK >> 16 ) ] ^ - KT2[ (uint8) ( *RK >> 8 ) ] ^ - KT3[ (uint8) ( *RK ) ]; RK++; - - *SK++ = KT0[ (uint8) ( *RK >> 24 ) ] ^ - KT1[ (uint8) ( *RK >> 16 ) ] ^ - KT2[ (uint8) ( *RK >> 8 ) ] ^ - KT3[ (uint8) ( *RK ) ]; RK++; - } - - RK -= 8; - - *SK++ = *RK++; - *SK++ = *RK++; - *SK++ = *RK++; - *SK++ = *RK++; - - return( 0 ); -} - -/* AES 128-bit block encryption routine */ - -void rtmp_aes_encrypt(aes_context *ctx, uint8 input[16], uint8 output[16] ) -{ - uint32 *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3; - - RK = ctx->erk; - GET_UINT32( X0, input, 0 ); X0 ^= RK[0]; - GET_UINT32( X1, input, 4 ); X1 ^= RK[1]; - GET_UINT32( X2, input, 8 ); X2 ^= RK[2]; - GET_UINT32( X3, input, 12 ); X3 ^= RK[3]; - -#define AES_FROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \ -{ \ - RK += 4; \ - \ - X0 = RK[0] ^ FT0[ (uint8) ( Y0 >> 24 ) ] ^ \ - FT1[ (uint8) ( Y1 >> 16 ) ] ^ \ - FT2[ (uint8) ( Y2 >> 8 ) ] ^ \ - FT3[ (uint8) ( Y3 ) ]; \ - \ - X1 = RK[1] ^ FT0[ (uint8) ( Y1 >> 24 ) ] ^ \ - FT1[ (uint8) ( Y2 >> 16 ) ] ^ \ - FT2[ (uint8) ( Y3 >> 8 ) ] ^ \ - FT3[ (uint8) ( Y0 ) ]; \ - \ - X2 = RK[2] ^ FT0[ (uint8) ( Y2 >> 24 ) ] ^ \ - FT1[ (uint8) ( Y3 >> 16 ) ] ^ \ - FT2[ (uint8) ( Y0 >> 8 ) ] ^ \ - FT3[ (uint8) ( Y1 ) ]; \ - \ - X3 = RK[3] ^ FT0[ (uint8) ( Y3 >> 24 ) ] ^ \ - FT1[ (uint8) ( Y0 >> 16 ) ] ^ \ - FT2[ (uint8) ( Y1 >> 8 ) ] ^ \ - FT3[ (uint8) ( Y2 ) ]; \ -} - - AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 1 */ - AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 2 */ - AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 3 */ - AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 4 */ - AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 5 */ - AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 6 */ - AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 7 */ - AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 8 */ - AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 9 */ - - if( ctx->nr > 10 ) - { - AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 10 */ - AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 11 */ - } - - if( ctx->nr > 12 ) - { - AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 12 */ - AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 13 */ - } - - /* last round */ - - RK += 4; - - X0 = RK[0] ^ ( FSb[ (uint8) ( Y0 >> 24 ) ] << 24 ) ^ - ( FSb[ (uint8) ( Y1 >> 16 ) ] << 16 ) ^ - ( FSb[ (uint8) ( Y2 >> 8 ) ] << 8 ) ^ - ( FSb[ (uint8) ( Y3 ) ] ); - - X1 = RK[1] ^ ( FSb[ (uint8) ( Y1 >> 24 ) ] << 24 ) ^ - ( FSb[ (uint8) ( Y2 >> 16 ) ] << 16 ) ^ - ( FSb[ (uint8) ( Y3 >> 8 ) ] << 8 ) ^ - ( FSb[ (uint8) ( Y0 ) ] ); - - X2 = RK[2] ^ ( FSb[ (uint8) ( Y2 >> 24 ) ] << 24 ) ^ - ( FSb[ (uint8) ( Y3 >> 16 ) ] << 16 ) ^ - ( FSb[ (uint8) ( Y0 >> 8 ) ] << 8 ) ^ - ( FSb[ (uint8) ( Y1 ) ] ); - - X3 = RK[3] ^ ( FSb[ (uint8) ( Y3 >> 24 ) ] << 24 ) ^ - ( FSb[ (uint8) ( Y0 >> 16 ) ] << 16 ) ^ - ( FSb[ (uint8) ( Y1 >> 8 ) ] << 8 ) ^ - ( FSb[ (uint8) ( Y2 ) ] ); - - PUT_UINT32( X0, output, 0 ); - PUT_UINT32( X1, output, 4 ); - PUT_UINT32( X2, output, 8 ); - PUT_UINT32( X3, output, 12 ); -} - -/* AES 128-bit block decryption routine */ - -void rtmp_aes_decrypt( aes_context *ctx, uint8 input[16], uint8 output[16] ) -{ - uint32 *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3; - - RK = ctx->drk; - - GET_UINT32( X0, input, 0 ); X0 ^= RK[0]; - GET_UINT32( X1, input, 4 ); X1 ^= RK[1]; - GET_UINT32( X2, input, 8 ); X2 ^= RK[2]; - GET_UINT32( X3, input, 12 ); X3 ^= RK[3]; - -#define AES_RROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \ -{ \ - RK += 4; \ - \ - X0 = RK[0] ^ RT0[ (uint8) ( Y0 >> 24 ) ] ^ \ - RT1[ (uint8) ( Y3 >> 16 ) ] ^ \ - RT2[ (uint8) ( Y2 >> 8 ) ] ^ \ - RT3[ (uint8) ( Y1 ) ]; \ - \ - X1 = RK[1] ^ RT0[ (uint8) ( Y1 >> 24 ) ] ^ \ - RT1[ (uint8) ( Y0 >> 16 ) ] ^ \ - RT2[ (uint8) ( Y3 >> 8 ) ] ^ \ - RT3[ (uint8) ( Y2 ) ]; \ - \ - X2 = RK[2] ^ RT0[ (uint8) ( Y2 >> 24 ) ] ^ \ - RT1[ (uint8) ( Y1 >> 16 ) ] ^ \ - RT2[ (uint8) ( Y0 >> 8 ) ] ^ \ - RT3[ (uint8) ( Y3 ) ]; \ - \ - X3 = RK[3] ^ RT0[ (uint8) ( Y3 >> 24 ) ] ^ \ - RT1[ (uint8) ( Y2 >> 16 ) ] ^ \ - RT2[ (uint8) ( Y1 >> 8 ) ] ^ \ - RT3[ (uint8) ( Y0 ) ]; \ -} - - AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 1 */ - AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 2 */ - AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 3 */ - AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 4 */ - AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 5 */ - AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 6 */ - AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 7 */ - AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 8 */ - AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 9 */ - - if( ctx->nr > 10 ) - { - AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 10 */ - AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 11 */ - } - - if( ctx->nr > 12 ) - { - AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 12 */ - AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 13 */ - } - - /* last round */ - - RK += 4; - - X0 = RK[0] ^ ( RSb[ (uint8) ( Y0 >> 24 ) ] << 24 ) ^ - ( RSb[ (uint8) ( Y3 >> 16 ) ] << 16 ) ^ - ( RSb[ (uint8) ( Y2 >> 8 ) ] << 8 ) ^ - ( RSb[ (uint8) ( Y1 ) ] ); - - X1 = RK[1] ^ ( RSb[ (uint8) ( Y1 >> 24 ) ] << 24 ) ^ - ( RSb[ (uint8) ( Y0 >> 16 ) ] << 16 ) ^ - ( RSb[ (uint8) ( Y3 >> 8 ) ] << 8 ) ^ - ( RSb[ (uint8) ( Y2 ) ] ); - - X2 = RK[2] ^ ( RSb[ (uint8) ( Y2 >> 24 ) ] << 24 ) ^ - ( RSb[ (uint8) ( Y1 >> 16 ) ] << 16 ) ^ - ( RSb[ (uint8) ( Y0 >> 8 ) ] << 8 ) ^ - ( RSb[ (uint8) ( Y3 ) ] ); - - X3 = RK[3] ^ ( RSb[ (uint8) ( Y3 >> 24 ) ] << 24 ) ^ - ( RSb[ (uint8) ( Y2 >> 16 ) ] << 16 ) ^ - ( RSb[ (uint8) ( Y1 >> 8 ) ] << 8 ) ^ - ( RSb[ (uint8) ( Y0 ) ] ); - - PUT_UINT32( X0, output, 0 ); - PUT_UINT32( X1, output, 4 ); - PUT_UINT32( X2, output, 8 ); - PUT_UINT32( X3, output, 12 ); -} - -/* - ======================================================================== - - Routine Description: - SHA1 function - - Arguments: - - Return Value: - - Note: - - ======================================================================== -*/ -VOID HMAC_SHA1( - IN UCHAR *text, - IN UINT text_len, - IN UCHAR *key, - IN UINT key_len, - IN UCHAR *digest) -{ - SHA_CTX context; - UCHAR k_ipad[65]; /* inner padding - key XORd with ipad */ - UCHAR k_opad[65]; /* outer padding - key XORd with opad */ - INT i; - - // if key is longer than 64 bytes reset it to key=SHA1(key) - if (key_len > 64) - { - SHA_CTX tctx; - SHAInit(&tctx); - SHAUpdate(&tctx, key, key_len); - SHAFinal(&tctx, key); - key_len = 20; - } - NdisZeroMemory(k_ipad, sizeof(k_ipad)); - NdisZeroMemory(k_opad, sizeof(k_opad)); - NdisMoveMemory(k_ipad, key, key_len); - NdisMoveMemory(k_opad, key, key_len); - - // XOR key with ipad and opad values - for (i = 0; i < 64; i++) - { - k_ipad[i] ^= 0x36; - k_opad[i] ^= 0x5c; - } - - // perform inner SHA1 - SHAInit(&context); /* init context for 1st pass */ - SHAUpdate(&context, k_ipad, 64); /* start with inner pad */ - SHAUpdate(&context, text, text_len); /* then text of datagram */ - SHAFinal(&context, digest); /* finish up 1st pass */ - - //perform outer SHA1 - SHAInit(&context); /* init context for 2nd pass */ - SHAUpdate(&context, k_opad, 64); /* start with outer pad */ - SHAUpdate(&context, digest, 20); /* then results of 1st hash */ - SHAFinal(&context, digest); /* finish up 2nd pass */ - -} - -/* -* F(P, S, c, i) = U1 xor U2 xor ... Uc -* U1 = PRF(P, S || Int(i)) -* U2 = PRF(P, U1) -* Uc = PRF(P, Uc-1) -*/ - -void F(char *password, unsigned char *ssid, int ssidlength, int iterations, int count, unsigned char *output) -{ - unsigned char digest[36], digest1[SHA_DIGEST_LEN]; - int i, j; - - /* U1 = PRF(P, S || int(i)) */ - memcpy(digest, ssid, ssidlength); - digest[ssidlength] = (unsigned char)((count>>24) & 0xff); - digest[ssidlength+1] = (unsigned char)((count>>16) & 0xff); - digest[ssidlength+2] = (unsigned char)((count>>8) & 0xff); - digest[ssidlength+3] = (unsigned char)(count & 0xff); - HMAC_SHA1(digest, ssidlength+4, (unsigned char*) password, (int) strlen(password), digest1); // for WPA update - - /* output = U1 */ - memcpy(output, digest1, SHA_DIGEST_LEN); - - for (i = 1; i < iterations; i++) - { - /* Un = PRF(P, Un-1) */ - HMAC_SHA1(digest1, SHA_DIGEST_LEN, (unsigned char*) password, (int) strlen(password), digest); // for WPA update - memcpy(digest1, digest, SHA_DIGEST_LEN); - - /* output = output xor Un */ - for (j = 0; j < SHA_DIGEST_LEN; j++) - { - output[j] ^= digest[j]; - } - } -} -/* -* password - ascii string up to 63 characters in length -* ssid - octet string up to 32 octets -* ssidlength - length of ssid in octets -* output must be 40 octets in length and outputs 256 bits of key -*/ -int PasswordHash(char *password, unsigned char *ssid, int ssidlength, unsigned char *output) -{ - if ((strlen(password) > 63) || (ssidlength > 32)) - return 0; - - F(password, ssid, ssidlength, 4096, 1, output); - F(password, ssid, ssidlength, 4096, 2, &output[SHA_DIGEST_LEN]); - return 1; -} - - +#include "../../rt2860/common/md5.c" diff --git a/drivers/staging/rt2870/common/mlme.c b/drivers/staging/rt2870/common/mlme.c index 8a82cee8bf26..f88040abd26b 100644 --- a/drivers/staging/rt2870/common/mlme.c +++ b/drivers/staging/rt2870/common/mlme.c @@ -1,8609 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - mlme.c - - Abstract: - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - John Chang 2004-08-25 Modify from RT2500 code base - John Chang 2004-09-06 modified for RT2600 -*/ - -#include "../rt_config.h" -#include - -UCHAR CISCO_OUI[] = {0x00, 0x40, 0x96}; - -UCHAR WPA_OUI[] = {0x00, 0x50, 0xf2, 0x01}; -UCHAR RSN_OUI[] = {0x00, 0x0f, 0xac}; -UCHAR WAPI_OUI[] = {0x00, 0x14, 0x72}; -UCHAR WME_INFO_ELEM[] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01}; -UCHAR WME_PARM_ELEM[] = {0x00, 0x50, 0xf2, 0x02, 0x01, 0x01}; -UCHAR Ccx2QosInfo[] = {0x00, 0x40, 0x96, 0x04}; -UCHAR RALINK_OUI[] = {0x00, 0x0c, 0x43}; -UCHAR BROADCOM_OUI[] = {0x00, 0x90, 0x4c}; -UCHAR WPS_OUI[] = {0x00, 0x50, 0xf2, 0x04}; -#ifdef CONFIG_STA_SUPPORT -#ifdef DOT11_N_SUPPORT -UCHAR PRE_N_HT_OUI[] = {0x00, 0x90, 0x4c}; -#endif // DOT11_N_SUPPORT // -#endif // CONFIG_STA_SUPPORT // - -UCHAR RateSwitchTable[] = { -// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) - 0x11, 0x00, 0, 0, 0, // Initial used item after association - 0x00, 0x00, 0, 40, 101, - 0x01, 0x00, 1, 40, 50, - 0x02, 0x00, 2, 35, 45, - 0x03, 0x00, 3, 20, 45, - 0x04, 0x21, 0, 30, 50, - 0x05, 0x21, 1, 20, 50, - 0x06, 0x21, 2, 20, 50, - 0x07, 0x21, 3, 15, 50, - 0x08, 0x21, 4, 15, 30, - 0x09, 0x21, 5, 10, 25, - 0x0a, 0x21, 6, 8, 25, - 0x0b, 0x21, 7, 8, 25, - 0x0c, 0x20, 12, 15, 30, - 0x0d, 0x20, 13, 8, 20, - 0x0e, 0x20, 14, 8, 20, - 0x0f, 0x20, 15, 8, 25, - 0x10, 0x22, 15, 8, 25, - 0x11, 0x00, 0, 0, 0, - 0x12, 0x00, 0, 0, 0, - 0x13, 0x00, 0, 0, 0, - 0x14, 0x00, 0, 0, 0, - 0x15, 0x00, 0, 0, 0, - 0x16, 0x00, 0, 0, 0, - 0x17, 0x00, 0, 0, 0, - 0x18, 0x00, 0, 0, 0, - 0x19, 0x00, 0, 0, 0, - 0x1a, 0x00, 0, 0, 0, - 0x1b, 0x00, 0, 0, 0, - 0x1c, 0x00, 0, 0, 0, - 0x1d, 0x00, 0, 0, 0, - 0x1e, 0x00, 0, 0, 0, - 0x1f, 0x00, 0, 0, 0, -}; - -UCHAR RateSwitchTable11B[] = { -// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) - 0x04, 0x03, 0, 0, 0, // Initial used item after association - 0x00, 0x00, 0, 40, 101, - 0x01, 0x00, 1, 40, 50, - 0x02, 0x00, 2, 35, 45, - 0x03, 0x00, 3, 20, 45, -}; - -UCHAR RateSwitchTable11BG[] = { -// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) - 0x0a, 0x00, 0, 0, 0, // Initial used item after association - 0x00, 0x00, 0, 40, 101, - 0x01, 0x00, 1, 40, 50, - 0x02, 0x00, 2, 35, 45, - 0x03, 0x00, 3, 20, 45, - 0x04, 0x10, 2, 20, 35, - 0x05, 0x10, 3, 16, 35, - 0x06, 0x10, 4, 10, 25, - 0x07, 0x10, 5, 16, 25, - 0x08, 0x10, 6, 10, 25, - 0x09, 0x10, 7, 10, 13, -}; - -UCHAR RateSwitchTable11G[] = { -// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) - 0x08, 0x00, 0, 0, 0, // Initial used item after association - 0x00, 0x10, 0, 20, 101, - 0x01, 0x10, 1, 20, 35, - 0x02, 0x10, 2, 20, 35, - 0x03, 0x10, 3, 16, 35, - 0x04, 0x10, 4, 10, 25, - 0x05, 0x10, 5, 16, 25, - 0x06, 0x10, 6, 10, 25, - 0x07, 0x10, 7, 10, 13, -}; - -#ifdef DOT11_N_SUPPORT -UCHAR RateSwitchTable11N1S[] = { -// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) - 0x09, 0x00, 0, 0, 0, // Initial used item after association - 0x00, 0x21, 0, 30, 101, - 0x01, 0x21, 1, 20, 50, - 0x02, 0x21, 2, 20, 50, - 0x03, 0x21, 3, 15, 50, - 0x04, 0x21, 4, 15, 30, - 0x05, 0x21, 5, 10, 25, - 0x06, 0x21, 6, 8, 14, - 0x07, 0x21, 7, 8, 14, - 0x08, 0x23, 7, 8, 14, -}; - -UCHAR RateSwitchTable11N2S[] = { -// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) - 0x0a, 0x00, 0, 0, 0, // Initial used item after association - 0x00, 0x21, 0, 30, 101, - 0x01, 0x21, 1, 20, 50, - 0x02, 0x21, 2, 20, 50, - 0x03, 0x21, 3, 15, 50, - 0x04, 0x21, 4, 15, 30, - 0x05, 0x20, 12, 15, 30, - 0x06, 0x20, 13, 8, 20, - 0x07, 0x20, 14, 8, 20, - 0x08, 0x20, 15, 8, 25, - 0x09, 0x22, 15, 8, 25, -}; - -UCHAR RateSwitchTable11N3S[] = { -// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) - 0x0a, 0x00, 0, 0, 0, // Initial used item after association - 0x00, 0x21, 0, 30, 101, - 0x01, 0x21, 1, 20, 50, - 0x02, 0x21, 2, 20, 50, - 0x03, 0x21, 3, 15, 50, - 0x04, 0x21, 4, 15, 30, - 0x05, 0x20, 12, 15, 30, - 0x06, 0x20, 13, 8, 20, - 0x07, 0x20, 14, 8, 20, - 0x08, 0x20, 15, 8, 25, - 0x09, 0x22, 15, 8, 25, -}; - -UCHAR RateSwitchTable11N2SForABand[] = { -// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) - 0x0b, 0x09, 0, 0, 0, // Initial used item after association - 0x00, 0x21, 0, 30, 101, - 0x01, 0x21, 1, 20, 50, - 0x02, 0x21, 2, 20, 50, - 0x03, 0x21, 3, 15, 50, - 0x04, 0x21, 4, 15, 30, - 0x05, 0x21, 5, 15, 30, - 0x06, 0x20, 12, 15, 30, - 0x07, 0x20, 13, 8, 20, - 0x08, 0x20, 14, 8, 20, - 0x09, 0x20, 15, 8, 25, - 0x0a, 0x22, 15, 8, 25, -}; - -UCHAR RateSwitchTable11N3SForABand[] = { // 3*3 -// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) - 0x0b, 0x09, 0, 0, 0, // Initial used item after association - 0x00, 0x21, 0, 30, 101, - 0x01, 0x21, 1, 20, 50, - 0x02, 0x21, 2, 20, 50, - 0x03, 0x21, 3, 15, 50, - 0x04, 0x21, 4, 15, 30, - 0x05, 0x21, 5, 15, 30, - 0x06, 0x20, 12, 15, 30, - 0x07, 0x20, 13, 8, 20, - 0x08, 0x20, 14, 8, 20, - 0x09, 0x20, 15, 8, 25, - 0x0a, 0x22, 15, 8, 25, -}; - -UCHAR RateSwitchTable11BGN1S[] = { -// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) - 0x0d, 0x00, 0, 0, 0, // Initial used item after association - 0x00, 0x00, 0, 40, 101, - 0x01, 0x00, 1, 40, 50, - 0x02, 0x00, 2, 35, 45, - 0x03, 0x00, 3, 20, 45, - 0x04, 0x21, 0, 30,101, //50 - 0x05, 0x21, 1, 20, 50, - 0x06, 0x21, 2, 20, 50, - 0x07, 0x21, 3, 15, 50, - 0x08, 0x21, 4, 15, 30, - 0x09, 0x21, 5, 10, 25, - 0x0a, 0x21, 6, 8, 14, - 0x0b, 0x21, 7, 8, 14, - 0x0c, 0x23, 7, 8, 14, -}; - -UCHAR RateSwitchTable11BGN2S[] = { -// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) - 0x0a, 0x00, 0, 0, 0, // Initial used item after association - 0x00, 0x21, 0, 30,101, //50 - 0x01, 0x21, 1, 20, 50, - 0x02, 0x21, 2, 20, 50, - 0x03, 0x21, 3, 15, 50, - 0x04, 0x21, 4, 15, 30, - 0x05, 0x20, 12, 15, 30, - 0x06, 0x20, 13, 8, 20, - 0x07, 0x20, 14, 8, 20, - 0x08, 0x20, 15, 8, 25, - 0x09, 0x22, 15, 8, 25, -}; - -UCHAR RateSwitchTable11BGN3S[] = { // 3*3 -// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) - 0x0a, 0x00, 0, 0, 0, // Initial used item after association - 0x00, 0x21, 0, 30,101, //50 - 0x01, 0x21, 1, 20, 50, - 0x02, 0x21, 2, 20, 50, - 0x03, 0x21, 3, 20, 50, - 0x04, 0x21, 4, 15, 50, -#if 1 - 0x05, 0x20, 20, 15, 30, - 0x06, 0x20, 21, 8, 20, - 0x07, 0x20, 22, 8, 20, - 0x08, 0x20, 23, 8, 25, - 0x09, 0x22, 23, 8, 25, -#else // for RT2860 2*3 test - 0x05, 0x20, 12, 15, 30, - 0x06, 0x20, 13, 8, 20, - 0x07, 0x20, 14, 8, 20, - 0x08, 0x20, 15, 8, 25, - 0x09, 0x22, 15, 8, 25, -#endif -}; - -UCHAR RateSwitchTable11BGN2SForABand[] = { -// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) - 0x0b, 0x09, 0, 0, 0, // Initial used item after association - 0x00, 0x21, 0, 30,101, //50 - 0x01, 0x21, 1, 20, 50, - 0x02, 0x21, 2, 20, 50, - 0x03, 0x21, 3, 15, 50, - 0x04, 0x21, 4, 15, 30, - 0x05, 0x21, 5, 15, 30, - 0x06, 0x20, 12, 15, 30, - 0x07, 0x20, 13, 8, 20, - 0x08, 0x20, 14, 8, 20, - 0x09, 0x20, 15, 8, 25, - 0x0a, 0x22, 15, 8, 25, -}; - -UCHAR RateSwitchTable11BGN3SForABand[] = { // 3*3 -// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) - 0x0c, 0x09, 0, 0, 0, // Initial used item after association - 0x00, 0x21, 0, 30,101, //50 - 0x01, 0x21, 1, 20, 50, - 0x02, 0x21, 2, 20, 50, - 0x03, 0x21, 3, 15, 50, - 0x04, 0x21, 4, 15, 30, - 0x05, 0x21, 5, 15, 30, - 0x06, 0x21, 12, 15, 30, - 0x07, 0x20, 20, 15, 30, - 0x08, 0x20, 21, 8, 20, - 0x09, 0x20, 22, 8, 20, - 0x0a, 0x20, 23, 8, 25, - 0x0b, 0x22, 23, 8, 25, -}; -#endif // DOT11_N_SUPPORT // - -PUCHAR ReasonString[] = { - /* 0 */ "Reserved", - /* 1 */ "Unspecified Reason", - /* 2 */ "Previous Auth no longer valid", - /* 3 */ "STA is leaving / has left", - /* 4 */ "DIS-ASSOC due to inactivity", - /* 5 */ "AP unable to hanle all associations", - /* 6 */ "class 2 error", - /* 7 */ "class 3 error", - /* 8 */ "STA is leaving / has left", - /* 9 */ "require auth before assoc/re-assoc", - /* 10 */ "Reserved", - /* 11 */ "Reserved", - /* 12 */ "Reserved", - /* 13 */ "invalid IE", - /* 14 */ "MIC error", - /* 15 */ "4-way handshake timeout", - /* 16 */ "2-way (group key) handshake timeout", - /* 17 */ "4-way handshake IE diff among AssosReq/Rsp/Beacon", - /* 18 */ -}; - -extern UCHAR OfdmRateToRxwiMCS[]; -// since RT61 has better RX sensibility, we have to limit TX ACK rate not to exceed our normal data TX rate. -// otherwise the WLAN peer may not be able to receive the ACK thus downgrade its data TX rate -ULONG BasicRateMask[12] = {0xfffff001 /* 1-Mbps */, 0xfffff003 /* 2 Mbps */, 0xfffff007 /* 5.5 */, 0xfffff00f /* 11 */, - 0xfffff01f /* 6 */ , 0xfffff03f /* 9 */ , 0xfffff07f /* 12 */ , 0xfffff0ff /* 18 */, - 0xfffff1ff /* 24 */ , 0xfffff3ff /* 36 */ , 0xfffff7ff /* 48 */ , 0xffffffff /* 54 */}; - -UCHAR MULTICAST_ADDR[MAC_ADDR_LEN] = {0x1, 0x00, 0x00, 0x00, 0x00, 0x00}; -UCHAR BROADCAST_ADDR[MAC_ADDR_LEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; -UCHAR ZERO_MAC_ADDR[MAC_ADDR_LEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - -// e.g. RssiSafeLevelForTxRate[RATE_36]" means if the current RSSI is greater than -// this value, then it's quaranteed capable of operating in 36 mbps TX rate in -// clean environment. -// TxRate: 1 2 5.5 11 6 9 12 18 24 36 48 54 72 100 -CHAR RssiSafeLevelForTxRate[] ={ -92, -91, -90, -87, -88, -86, -85, -83, -81, -78, -72, -71, -40, -40 }; - -UCHAR RateIdToMbps[] = { 1, 2, 5, 11, 6, 9, 12, 18, 24, 36, 48, 54, 72, 100}; -USHORT RateIdTo500Kbps[] = { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108, 144, 200}; - -UCHAR SsidIe = IE_SSID; -UCHAR SupRateIe = IE_SUPP_RATES; -UCHAR ExtRateIe = IE_EXT_SUPP_RATES; -#ifdef DOT11_N_SUPPORT -UCHAR HtCapIe = IE_HT_CAP; -UCHAR AddHtInfoIe = IE_ADD_HT; -UCHAR NewExtChanIe = IE_SECONDARY_CH_OFFSET; -#ifdef DOT11N_DRAFT3 -UCHAR ExtHtCapIe = IE_EXT_CAPABILITY; -#endif // DOT11N_DRAFT3 // -#endif // DOT11_N_SUPPORT // -UCHAR ErpIe = IE_ERP; -UCHAR DsIe = IE_DS_PARM; -UCHAR TimIe = IE_TIM; -UCHAR WpaIe = IE_WPA; -UCHAR Wpa2Ie = IE_WPA2; -UCHAR IbssIe = IE_IBSS_PARM; -UCHAR Ccx2Ie = IE_CCX_V2; -UCHAR WapiIe = IE_WAPI; - -extern UCHAR WPA_OUI[]; - -UCHAR SES_OUI[] = {0x00, 0x90, 0x4c}; - -UCHAR ZeroSsid[32] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; - -// Reset the RFIC setting to new series -RTMP_RF_REGS RF2850RegTable[] = { -// ch R1 R2 R3(TX0~4=0) R4 - {1, 0x98402ecc, 0x984c0786, 0x9816b455, 0x9800510b}, - {2, 0x98402ecc, 0x984c0786, 0x98168a55, 0x9800519f}, - {3, 0x98402ecc, 0x984c078a, 0x98168a55, 0x9800518b}, - {4, 0x98402ecc, 0x984c078a, 0x98168a55, 0x9800519f}, - {5, 0x98402ecc, 0x984c078e, 0x98168a55, 0x9800518b}, - {6, 0x98402ecc, 0x984c078e, 0x98168a55, 0x9800519f}, - {7, 0x98402ecc, 0x984c0792, 0x98168a55, 0x9800518b}, - {8, 0x98402ecc, 0x984c0792, 0x98168a55, 0x9800519f}, - {9, 0x98402ecc, 0x984c0796, 0x98168a55, 0x9800518b}, - {10, 0x98402ecc, 0x984c0796, 0x98168a55, 0x9800519f}, - {11, 0x98402ecc, 0x984c079a, 0x98168a55, 0x9800518b}, - {12, 0x98402ecc, 0x984c079a, 0x98168a55, 0x9800519f}, - {13, 0x98402ecc, 0x984c079e, 0x98168a55, 0x9800518b}, - {14, 0x98402ecc, 0x984c07a2, 0x98168a55, 0x98005193}, - - // 802.11 UNI / HyperLan 2 - {36, 0x98402ecc, 0x984c099a, 0x98158a55, 0x980ed1a3}, - {38, 0x98402ecc, 0x984c099e, 0x98158a55, 0x980ed193}, - {40, 0x98402ec8, 0x984c0682, 0x98158a55, 0x980ed183}, - {44, 0x98402ec8, 0x984c0682, 0x98158a55, 0x980ed1a3}, - {46, 0x98402ec8, 0x984c0686, 0x98158a55, 0x980ed18b}, - {48, 0x98402ec8, 0x984c0686, 0x98158a55, 0x980ed19b}, - {52, 0x98402ec8, 0x984c068a, 0x98158a55, 0x980ed193}, - {54, 0x98402ec8, 0x984c068a, 0x98158a55, 0x980ed1a3}, - {56, 0x98402ec8, 0x984c068e, 0x98158a55, 0x980ed18b}, - {60, 0x98402ec8, 0x984c0692, 0x98158a55, 0x980ed183}, - {62, 0x98402ec8, 0x984c0692, 0x98158a55, 0x980ed193}, - {64, 0x98402ec8, 0x984c0692, 0x98158a55, 0x980ed1a3}, // Plugfest#4, Day4, change RFR3 left4th 9->5. - - // 802.11 HyperLan 2 - {100, 0x98402ec8, 0x984c06b2, 0x98178a55, 0x980ed783}, - - // 2008.04.30 modified - // The system team has AN to improve the EVM value - // for channel 102 to 108 for the RT2850/RT2750 dual band solution. - {102, 0x98402ec8, 0x985c06b2, 0x98578a55, 0x980ed793}, - {104, 0x98402ec8, 0x985c06b2, 0x98578a55, 0x980ed1a3}, - {108, 0x98402ecc, 0x985c0a32, 0x98578a55, 0x980ed193}, - - {110, 0x98402ecc, 0x984c0a36, 0x98178a55, 0x980ed183}, - {112, 0x98402ecc, 0x984c0a36, 0x98178a55, 0x980ed19b}, - {116, 0x98402ecc, 0x984c0a3a, 0x98178a55, 0x980ed1a3}, - {118, 0x98402ecc, 0x984c0a3e, 0x98178a55, 0x980ed193}, - {120, 0x98402ec4, 0x984c0382, 0x98178a55, 0x980ed183}, - {124, 0x98402ec4, 0x984c0382, 0x98178a55, 0x980ed193}, - {126, 0x98402ec4, 0x984c0382, 0x98178a55, 0x980ed15b}, // 0x980ed1bb->0x980ed15b required by Rory 20070927 - {128, 0x98402ec4, 0x984c0382, 0x98178a55, 0x980ed1a3}, - {132, 0x98402ec4, 0x984c0386, 0x98178a55, 0x980ed18b}, - {134, 0x98402ec4, 0x984c0386, 0x98178a55, 0x980ed193}, - {136, 0x98402ec4, 0x984c0386, 0x98178a55, 0x980ed19b}, - {140, 0x98402ec4, 0x984c038a, 0x98178a55, 0x980ed183}, - - // 802.11 UNII - {149, 0x98402ec4, 0x984c038a, 0x98178a55, 0x980ed1a7}, - {151, 0x98402ec4, 0x984c038e, 0x98178a55, 0x980ed187}, - {153, 0x98402ec4, 0x984c038e, 0x98178a55, 0x980ed18f}, - {157, 0x98402ec4, 0x984c038e, 0x98178a55, 0x980ed19f}, - {159, 0x98402ec4, 0x984c038e, 0x98178a55, 0x980ed1a7}, - {161, 0x98402ec4, 0x984c0392, 0x98178a55, 0x980ed187}, - {165, 0x98402ec4, 0x984c0392, 0x98178a55, 0x980ed197}, - - // Japan - {184, 0x95002ccc, 0x9500491e, 0x9509be55, 0x950c0a0b}, - {188, 0x95002ccc, 0x95004922, 0x9509be55, 0x950c0a13}, - {192, 0x95002ccc, 0x95004926, 0x9509be55, 0x950c0a1b}, - {196, 0x95002ccc, 0x9500492a, 0x9509be55, 0x950c0a23}, - {208, 0x95002ccc, 0x9500493a, 0x9509be55, 0x950c0a13}, - {212, 0x95002ccc, 0x9500493e, 0x9509be55, 0x950c0a1b}, - {216, 0x95002ccc, 0x95004982, 0x9509be55, 0x950c0a23}, - - // still lack of MMAC(Japan) ch 34,38,42,46 -}; -UCHAR NUM_OF_2850_CHNL = (sizeof(RF2850RegTable) / sizeof(RTMP_RF_REGS)); - -FREQUENCY_ITEM FreqItems3020[] = -{ - /**************************************************/ - // ISM : 2.4 to 2.483 GHz // - /**************************************************/ - // 11g - /**************************************************/ - //-CH---N-------R---K----------- - {1, 241, 2, 2}, - {2, 241, 2, 7}, - {3, 242, 2, 2}, - {4, 242, 2, 7}, - {5, 243, 2, 2}, - {6, 243, 2, 7}, - {7, 244, 2, 2}, - {8, 244, 2, 7}, - {9, 245, 2, 2}, - {10, 245, 2, 7}, - {11, 246, 2, 2}, - {12, 246, 2, 7}, - {13, 247, 2, 2}, - {14, 248, 2, 4}, -}; -#define NUM_OF_3020_CHNL (sizeof(FreqItems3020) / sizeof(FREQUENCY_ITEM)) - -/* - ========================================================================== - Description: - initialize the MLME task and its data structure (queue, spinlock, - timer, state machines). - - IRQL = PASSIVE_LEVEL - - Return: - always return NDIS_STATUS_SUCCESS - - ========================================================================== -*/ -NDIS_STATUS MlmeInit( - IN PRTMP_ADAPTER pAd) -{ - NDIS_STATUS Status = NDIS_STATUS_SUCCESS; - - DBGPRINT(RT_DEBUG_TRACE, ("--> MLME Initialize\n")); - - do - { - Status = MlmeQueueInit(&pAd->Mlme.Queue); - if(Status != NDIS_STATUS_SUCCESS) - break; - - pAd->Mlme.bRunning = FALSE; - NdisAllocateSpinLock(&pAd->Mlme.TaskLock); - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - BssTableInit(&pAd->ScanTab); - - // init STA state machines - AssocStateMachineInit(pAd, &pAd->Mlme.AssocMachine, pAd->Mlme.AssocFunc); - AuthStateMachineInit(pAd, &pAd->Mlme.AuthMachine, pAd->Mlme.AuthFunc); - AuthRspStateMachineInit(pAd, &pAd->Mlme.AuthRspMachine, pAd->Mlme.AuthRspFunc); - SyncStateMachineInit(pAd, &pAd->Mlme.SyncMachine, pAd->Mlme.SyncFunc); - WpaPskStateMachineInit(pAd, &pAd->Mlme.WpaPskMachine, pAd->Mlme.WpaPskFunc); - AironetStateMachineInit(pAd, &pAd->Mlme.AironetMachine, pAd->Mlme.AironetFunc); - -#ifdef QOS_DLS_SUPPORT - DlsStateMachineInit(pAd, &pAd->Mlme.DlsMachine, pAd->Mlme.DlsFunc); -#endif // QOS_DLS_SUPPORT // - - - // Since we are using switch/case to implement it, the init is different from the above - // state machine init - MlmeCntlInit(pAd, &pAd->Mlme.CntlMachine, NULL); - } -#endif // CONFIG_STA_SUPPORT // - - - - ActionStateMachineInit(pAd, &pAd->Mlme.ActMachine, pAd->Mlme.ActFunc); - - // Init mlme periodic timer - RTMPInitTimer(pAd, &pAd->Mlme.PeriodicTimer, GET_TIMER_FUNCTION(MlmePeriodicExec), pAd, TRUE); - - // Set mlme periodic timer - RTMPSetTimer(&pAd->Mlme.PeriodicTimer, MLME_TASK_EXEC_INTV); - - // software-based RX Antenna diversity - RTMPInitTimer(pAd, &pAd->Mlme.RxAntEvalTimer, GET_TIMER_FUNCTION(AsicRxAntEvalTimeout), pAd, FALSE); - - } while (FALSE); - - DBGPRINT(RT_DEBUG_TRACE, ("<-- MLME Initialize\n")); - - return Status; -} - -/* - ========================================================================== - Description: - main loop of the MLME - Pre: - Mlme has to be initialized, and there are something inside the queue - Note: - This function is invoked from MPSetInformation and MPReceive; - This task guarantee only one MlmeHandler will run. - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID MlmeHandler( - IN PRTMP_ADAPTER pAd) -{ - MLME_QUEUE_ELEM *Elem = NULL; -#ifdef APCLI_SUPPORT - SHORT apcliIfIndex; -#endif - - // Only accept MLME and Frame from peer side, no other (control/data) frame should - // get into this state machine - - NdisAcquireSpinLock(&pAd->Mlme.TaskLock); - if(pAd->Mlme.bRunning) - { - NdisReleaseSpinLock(&pAd->Mlme.TaskLock); - return; - } - else - { - pAd->Mlme.bRunning = TRUE; - } - NdisReleaseSpinLock(&pAd->Mlme.TaskLock); - - while (!MlmeQueueEmpty(&pAd->Mlme.Queue)) - { - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_MLME_RESET_IN_PROGRESS) || - RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS) || - RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) - { - DBGPRINT(RT_DEBUG_TRACE, ("Device Halted or Removed or MlmeRest, exit MlmeHandler! (queue num = %ld)\n", pAd->Mlme.Queue.Num)); - break; - } - -#ifdef RALINK_ATE - if(ATE_ON(pAd)) - { - DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now in MlmeHandler\n")); - break; - } -#endif // RALINK_ATE // - - //From message type, determine which state machine I should drive - if (MlmeDequeue(&pAd->Mlme.Queue, &Elem)) - { -#ifdef RT2870 - if (Elem->MsgType == MT2_RESET_CONF) - { - DBGPRINT_RAW(RT_DEBUG_TRACE, ("!!! reset MLME state machine !!!\n")); - MlmeRestartStateMachine(pAd); - Elem->Occupied = FALSE; - Elem->MsgLen = 0; - continue; - } -#endif // RT2870 // - - // if dequeue success - switch (Elem->Machine) - { - // STA state machines -#ifdef CONFIG_STA_SUPPORT - case ASSOC_STATE_MACHINE: - StateMachinePerformAction(pAd, &pAd->Mlme.AssocMachine, Elem); - break; - case AUTH_STATE_MACHINE: - StateMachinePerformAction(pAd, &pAd->Mlme.AuthMachine, Elem); - break; - case AUTH_RSP_STATE_MACHINE: - StateMachinePerformAction(pAd, &pAd->Mlme.AuthRspMachine, Elem); - break; - case SYNC_STATE_MACHINE: - StateMachinePerformAction(pAd, &pAd->Mlme.SyncMachine, Elem); - break; - case MLME_CNTL_STATE_MACHINE: - MlmeCntlMachinePerformAction(pAd, &pAd->Mlme.CntlMachine, Elem); - break; - case WPA_PSK_STATE_MACHINE: - StateMachinePerformAction(pAd, &pAd->Mlme.WpaPskMachine, Elem); - break; -#ifdef LEAP_SUPPORT - case LEAP_STATE_MACHINE: - LeapMachinePerformAction(pAd, &pAd->Mlme.LeapMachine, Elem); - break; -#endif - case AIRONET_STATE_MACHINE: - StateMachinePerformAction(pAd, &pAd->Mlme.AironetMachine, Elem); - break; - -#ifdef QOS_DLS_SUPPORT - case DLS_STATE_MACHINE: - StateMachinePerformAction(pAd, &pAd->Mlme.DlsMachine, Elem); - break; -#endif // QOS_DLS_SUPPORT // -#endif // CONFIG_STA_SUPPORT // - - case ACTION_STATE_MACHINE: - StateMachinePerformAction(pAd, &pAd->Mlme.ActMachine, Elem); - break; - - - - - default: - DBGPRINT(RT_DEBUG_TRACE, ("ERROR: Illegal machine %ld in MlmeHandler()\n", Elem->Machine)); - break; - } // end of switch - - // free MLME element - Elem->Occupied = FALSE; - Elem->MsgLen = 0; - - } - else { - DBGPRINT_ERR(("MlmeHandler: MlmeQueue empty\n")); - } - } - - NdisAcquireSpinLock(&pAd->Mlme.TaskLock); - pAd->Mlme.bRunning = FALSE; - NdisReleaseSpinLock(&pAd->Mlme.TaskLock); -} - -/* - ========================================================================== - Description: - Destructor of MLME (Destroy queue, state machine, spin lock and timer) - Parameters: - Adapter - NIC Adapter pointer - Post: - The MLME task will no longer work properly - - IRQL = PASSIVE_LEVEL - - ========================================================================== - */ -VOID MlmeHalt( - IN PRTMP_ADAPTER pAd) -{ - BOOLEAN Cancelled; - - DBGPRINT(RT_DEBUG_TRACE, ("==> MlmeHalt\n")); - - if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) - { - // disable BEACON generation and other BEACON related hardware timers - AsicDisableSync(pAd); - } - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { -#ifdef QOS_DLS_SUPPORT - UCHAR i; -#endif // QOS_DLS_SUPPORT // - // Cancel pending timers - RTMPCancelTimer(&pAd->MlmeAux.AssocTimer, &Cancelled); - RTMPCancelTimer(&pAd->MlmeAux.ReassocTimer, &Cancelled); - RTMPCancelTimer(&pAd->MlmeAux.DisassocTimer, &Cancelled); - RTMPCancelTimer(&pAd->MlmeAux.AuthTimer, &Cancelled); - RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer, &Cancelled); - RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &Cancelled); - -#ifdef QOS_DLS_SUPPORT - for (i=0; iStaCfg.DLSEntry[i].Timer, &Cancelled); - } -#endif // QOS_DLS_SUPPORT // - } -#endif // CONFIG_STA_SUPPORT // - - RTMPCancelTimer(&pAd->Mlme.PeriodicTimer, &Cancelled); - RTMPCancelTimer(&pAd->Mlme.RxAntEvalTimer, &Cancelled); - - - - if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) - { - // Set LED - RTMPSetLED(pAd, LED_HALT); - RTMPSetSignalLED(pAd, -100); // Force signal strength Led to be turned off, firmware is not done it. -#ifdef RT2870 - { - LED_CFG_STRUC LedCfg; - RTMP_IO_READ32(pAd, LED_CFG, &LedCfg.word); - LedCfg.field.LedPolar = 0; - LedCfg.field.RLedMode = 0; - LedCfg.field.GLedMode = 0; - LedCfg.field.YLedMode = 0; - RTMP_IO_WRITE32(pAd, LED_CFG, LedCfg.word); - } -#endif // RT2870 // - } - - RTMPusecDelay(5000); // 5 msec to gurantee Ant Diversity timer canceled - - MlmeQueueDestroy(&pAd->Mlme.Queue); - NdisFreeSpinLock(&pAd->Mlme.TaskLock); - - DBGPRINT(RT_DEBUG_TRACE, ("<== MlmeHalt\n")); -} - -VOID MlmeResetRalinkCounters( - IN PRTMP_ADAPTER pAd) -{ - pAd->RalinkCounters.LastOneSecRxOkDataCnt = pAd->RalinkCounters.OneSecRxOkDataCnt; - // clear all OneSecxxx counters. - pAd->RalinkCounters.OneSecBeaconSentCnt = 0; - pAd->RalinkCounters.OneSecFalseCCACnt = 0; - pAd->RalinkCounters.OneSecRxFcsErrCnt = 0; - pAd->RalinkCounters.OneSecRxOkCnt = 0; - pAd->RalinkCounters.OneSecTxFailCount = 0; - pAd->RalinkCounters.OneSecTxNoRetryOkCount = 0; - pAd->RalinkCounters.OneSecTxRetryOkCount = 0; - pAd->RalinkCounters.OneSecRxOkDataCnt = 0; - - // TODO: for debug only. to be removed - pAd->RalinkCounters.OneSecOsTxCount[QID_AC_BE] = 0; - pAd->RalinkCounters.OneSecOsTxCount[QID_AC_BK] = 0; - pAd->RalinkCounters.OneSecOsTxCount[QID_AC_VI] = 0; - pAd->RalinkCounters.OneSecOsTxCount[QID_AC_VO] = 0; - pAd->RalinkCounters.OneSecDmaDoneCount[QID_AC_BE] = 0; - pAd->RalinkCounters.OneSecDmaDoneCount[QID_AC_BK] = 0; - pAd->RalinkCounters.OneSecDmaDoneCount[QID_AC_VI] = 0; - pAd->RalinkCounters.OneSecDmaDoneCount[QID_AC_VO] = 0; - pAd->RalinkCounters.OneSecTxDoneCount = 0; - pAd->RalinkCounters.OneSecRxCount = 0; - pAd->RalinkCounters.OneSecTxAggregationCount = 0; - pAd->RalinkCounters.OneSecRxAggregationCount = 0; - - return; -} - -unsigned long rx_AMSDU; -unsigned long rx_Total; - -/* - ========================================================================== - Description: - This routine is executed periodically to - - 1. Decide if it's a right time to turn on PwrMgmt bit of all - outgoiing frames - 2. Calculate ChannelQuality based on statistics of the last - period, so that TX rate won't toggling very frequently between a - successful TX and a failed TX. - 3. If the calculated ChannelQuality indicated current connection not - healthy, then a ROAMing attempt is tried here. - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -#define ADHOC_BEACON_LOST_TIME (8*OS_HZ) // 8 sec -VOID MlmePeriodicExec( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3) -{ - ULONG TxTotalCnt; - PRTMP_ADAPTER pAd = (RTMP_ADAPTER *)FunctionContext; - - // Do nothing if the driver is starting halt state. - // This might happen when timer already been fired before cancel timer with mlmehalt - if ((RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_HALT_IN_PROGRESS | - fRTMP_ADAPTER_RADIO_OFF | - fRTMP_ADAPTER_RADIO_MEASUREMENT | - fRTMP_ADAPTER_RESET_IN_PROGRESS)))) - return; - - RT28XX_MLME_PRE_SANITY_CHECK(pAd); - -#ifdef RALINK_ATE - /* Do not show RSSI until "Normal 1 second Mlme PeriodicExec". */ - if (ATE_ON(pAd)) - { - if (pAd->Mlme.PeriodicRound % MLME_TASK_EXEC_MULTIPLE != (MLME_TASK_EXEC_MULTIPLE - 1)) - { - pAd->Mlme.PeriodicRound ++; - return; - } - } -#endif // RALINK_ATE // - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - // Do nothing if monitor mode is on - if (MONITOR_ON(pAd)) - return; - - if (pAd->Mlme.PeriodicRound & 0x1) - { - // This is the fix for wifi 11n extension channel overlapping test case. for 2860D - if (((pAd->MACVersion & 0xffff) == 0x0101) && - (STA_TGN_WIFI_ON(pAd)) && - (pAd->CommonCfg.IOTestParm.bToggle == FALSE)) - - { - RTMP_IO_WRITE32(pAd, TXOP_CTRL_CFG, 0x24Bf); - pAd->CommonCfg.IOTestParm.bToggle = TRUE; - } - else if ((STA_TGN_WIFI_ON(pAd)) && - ((pAd->MACVersion & 0xffff) == 0x0101)) - { - RTMP_IO_WRITE32(pAd, TXOP_CTRL_CFG, 0x243f); - pAd->CommonCfg.IOTestParm.bToggle = FALSE; - } - } - } -#endif // CONFIG_STA_SUPPORT // - - pAd->bUpdateBcnCntDone = FALSE; - -// RECBATimerTimeout(SystemSpecific1,FunctionContext,SystemSpecific2,SystemSpecific3); - pAd->Mlme.PeriodicRound ++; - - // execute every 500ms - if ((pAd->Mlme.PeriodicRound % 5 == 0) && RTMPAutoRateSwitchCheck(pAd)/*(OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED))*/) - { -#ifdef CONFIG_STA_SUPPORT - // perform dynamic tx rate switching based on past TX history - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - if ((OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) - ) - && (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE))) - MlmeDynamicTxRateSwitching(pAd); - } -#endif // CONFIG_STA_SUPPORT // - } - - // Normal 1 second Mlme PeriodicExec. - if (pAd->Mlme.PeriodicRound %MLME_TASK_EXEC_MULTIPLE == 0) - { - pAd->Mlme.OneSecPeriodicRound ++; - -#ifdef RALINK_ATE - if (ATE_ON(pAd)) - { - /* request from Baron : move this routine from later to here */ - /* for showing Rx error count in ATE RXFRAME */ - NICUpdateRawCounters(pAd); - if (pAd->ate.bRxFer == 1) - { - pAd->ate.RxTotalCnt += pAd->ate.RxCntPerSec; - ate_print(KERN_EMERG "MlmePeriodicExec: Rx packet cnt = %d/%d\n", pAd->ate.RxCntPerSec, pAd->ate.RxTotalCnt); - pAd->ate.RxCntPerSec = 0; - - if (pAd->ate.RxAntennaSel == 0) - ate_print(KERN_EMERG "MlmePeriodicExec: Rx AvgRssi0=%d, AvgRssi1=%d, AvgRssi2=%d\n\n", - pAd->ate.AvgRssi0, pAd->ate.AvgRssi1, pAd->ate.AvgRssi2); - else - ate_print(KERN_EMERG "MlmePeriodicExec: Rx AvgRssi=%d\n\n", pAd->ate.AvgRssi0); - } - MlmeResetRalinkCounters(pAd); - return; - } -#endif // RALINK_ATE // - - - if (rx_Total) - { - - // reset counters - rx_AMSDU = 0; - rx_Total = 0; - } - - //ORIBATimerTimeout(pAd); - - // Media status changed, report to NDIS - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_MEDIA_STATE_CHANGE)) - { - RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_MEDIA_STATE_CHANGE); - if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) - { - pAd->IndicateMediaState = NdisMediaStateConnected; - RTMP_IndicateMediaState(pAd); - - } - else - { - pAd->IndicateMediaState = NdisMediaStateDisconnected; - RTMP_IndicateMediaState(pAd); - } - } - - NdisGetSystemUpTime(&pAd->Mlme.Now32); - - // add the most up-to-date h/w raw counters into software variable, so that - // the dynamic tuning mechanism below are based on most up-to-date information - NICUpdateRawCounters(pAd); - -#ifdef RT2870 - RT2870_WatchDog(pAd); -#endif // RT2870 // - -#ifdef DOT11_N_SUPPORT - // Need statistics after read counter. So put after NICUpdateRawCounters - ORIBATimerTimeout(pAd); -#endif // DOT11_N_SUPPORT // - - // if MGMT RING is full more than twice within 1 second, we consider there's - // a hardware problem stucking the TX path. In this case, try a hardware reset - // to recover the system - // if (pAd->RalinkCounters.MgmtRingFullCount >= 2) - // RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_HARDWARE_ERROR); - // else - // pAd->RalinkCounters.MgmtRingFullCount = 0; - - // The time period for checking antenna is according to traffic - if (pAd->Mlme.bEnableAutoAntennaCheck) - { - TxTotalCnt = pAd->RalinkCounters.OneSecTxNoRetryOkCount + - pAd->RalinkCounters.OneSecTxRetryOkCount + - pAd->RalinkCounters.OneSecTxFailCount; - - if (TxTotalCnt > 50) - { - if (pAd->Mlme.OneSecPeriodicRound % 10 == 0) - { - AsicEvaluateRxAnt(pAd); - } - } - else - { - if (pAd->Mlme.OneSecPeriodicRound % 3 == 0) - { - AsicEvaluateRxAnt(pAd); - } - } - } - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - STAMlmePeriodicExec(pAd); -#endif // CONFIG_STA_SUPPORT // - - MlmeResetRalinkCounters(pAd); - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - { - // When Adhoc beacon is enabled and RTS/CTS is enabled, there is a chance that hardware MAC FSM will run into a deadlock - // and sending CTS-to-self over and over. - // Software Patch Solution: - // 1. Polling debug state register 0x10F4 every one second. - // 2. If in 0x10F4 the ((bit29==1) && (bit7==1)) OR ((bit29==1) && (bit5==1)), it means the deadlock has occurred. - // 3. If the deadlock occurred, reset MAC/BBP by setting 0x1004 to 0x0001 for a while then setting it back to 0x000C again. - - UINT32 MacReg = 0; - - RTMP_IO_READ32(pAd, 0x10F4, &MacReg); - if (((MacReg & 0x20000000) && (MacReg & 0x80)) || ((MacReg & 0x20000000) && (MacReg & 0x20))) - { - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x1); - RTMPusecDelay(1); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0xC); - - DBGPRINT(RT_DEBUG_WARN,("Warning, MAC specific condition occurs \n")); - } - } - } -#endif // CONFIG_STA_SUPPORT // - - RT28XX_MLME_HANDLER(pAd); - } - - - pAd->bUpdateBcnCntDone = FALSE; -} - -#ifdef CONFIG_STA_SUPPORT -VOID STAMlmePeriodicExec( - PRTMP_ADAPTER pAd) -{ - ULONG TxTotalCnt; - int i; - -// -// We return here in ATE mode, because the statistics -// that ATE needs are not collected via this routine. -// -#ifdef RALINK_ATE - // It is supposed that we will never reach here in ATE mode. - ASSERT(!(ATE_ON(pAd))); - if (ATE_ON(pAd)) - return; -#endif // RALINK_ATE // - -#ifdef WPA_SUPPLICANT_SUPPORT - if (pAd->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_DISABLE) -#endif // WPA_SUPPLICANT_SUPPORT // - { - // WPA MIC error should block association attempt for 60 seconds - if (pAd->StaCfg.bBlockAssoc && (pAd->StaCfg.LastMicErrorTime + (60 * OS_HZ) < pAd->Mlme.Now32)) - pAd->StaCfg.bBlockAssoc = FALSE; - } - - if ((pAd->PreMediaState != pAd->IndicateMediaState) && (pAd->CommonCfg.bWirelessEvent)) - { - if (pAd->IndicateMediaState == NdisMediaStateConnected) - { - RTMPSendWirelessEvent(pAd, IW_STA_LINKUP_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); - } - pAd->PreMediaState = pAd->IndicateMediaState; - } - - - - - AsicStaBbpTuning(pAd); - - TxTotalCnt = pAd->RalinkCounters.OneSecTxNoRetryOkCount + - pAd->RalinkCounters.OneSecTxRetryOkCount + - pAd->RalinkCounters.OneSecTxFailCount; - - if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) - { - // update channel quality for Roaming and UI LinkQuality display - MlmeCalculateChannelQuality(pAd, pAd->Mlme.Now32); - } - - // must be AFTER MlmeDynamicTxRateSwitching() because it needs to know if - // Radio is currently in noisy environment - if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) - AsicAdjustTxPower(pAd); - - if (INFRA_ON(pAd)) - { -#ifdef QOS_DLS_SUPPORT - // Check DLS time out, then tear down those session - RTMPCheckDLSTimeOut(pAd); -#endif // QOS_DLS_SUPPORT // - - // Is PSM bit consistent with user power management policy? - // This is the only place that will set PSM bit ON. - if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) - MlmeCheckPsmChange(pAd, pAd->Mlme.Now32); - - pAd->RalinkCounters.LastOneSecTotalTxCount = TxTotalCnt; - - if ((pAd->StaCfg.LastBeaconRxTime + 1*OS_HZ < pAd->Mlme.Now32) && - (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) && - ((TxTotalCnt + pAd->RalinkCounters.OneSecRxOkCnt < 600))) - { - RTMPSetAGCInitValue(pAd, BW_20); - DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - No BEACON. restore R66 to the low bound(%d) \n", (0x2E + GET_LNA_GAIN(pAd)))); - } - - //if ((pAd->RalinkCounters.OneSecTxNoRetryOkCount == 0) && - // (pAd->RalinkCounters.OneSecTxRetryOkCount == 0)) - { - if (pAd->CommonCfg.bAPSDCapable && pAd->CommonCfg.APEdcaParm.bAPSDCapable) - { - // When APSD is enabled, the period changes as 20 sec - if ((pAd->Mlme.OneSecPeriodicRound % 20) == 8) - RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, TRUE); - } - else - { - // Send out a NULL frame every 10 sec to inform AP that STA is still alive (Avoid being age out) - if ((pAd->Mlme.OneSecPeriodicRound % 10) == 8) - { - if (pAd->CommonCfg.bWmmCapable) - RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, TRUE); - else - RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, FALSE); - } - } - } - - if (CQI_IS_DEAD(pAd->Mlme.ChannelQuality)) - { - DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - No BEACON. Dead CQI. Auto Recovery attempt #%ld\n", pAd->RalinkCounters.BadCQIAutoRecoveryCount)); - pAd->StaCfg.CCXAdjacentAPReportFlag = TRUE; - pAd->StaCfg.CCXAdjacentAPLinkDownTime = pAd->StaCfg.LastBeaconRxTime; - - // Lost AP, send disconnect & link down event - LinkDown(pAd, FALSE); - -#ifdef WPA_SUPPLICANT_SUPPORT -#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT - if (pAd->StaCfg.WpaSupplicantUP) - { - union iwreq_data wrqu; - //send disassociate event to wpa_supplicant - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.flags = RT_DISASSOC_EVENT_FLAG; - wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); - } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // -#endif // WPA_SUPPLICANT_SUPPORT // - -#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT - { - union iwreq_data wrqu; - memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN); - wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); - } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // - - // RTMPPatchMacBbpBug(pAd); - MlmeAutoReconnectLastSSID(pAd); - } - else if (CQI_IS_BAD(pAd->Mlme.ChannelQuality)) - { - pAd->RalinkCounters.BadCQIAutoRecoveryCount ++; - DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - Bad CQI. Auto Recovery attempt #%ld\n", pAd->RalinkCounters.BadCQIAutoRecoveryCount)); - MlmeAutoReconnectLastSSID(pAd); - } - - // Add auto seamless roaming - if (pAd->StaCfg.bFastRoaming) - { - SHORT dBmToRoam = (SHORT)pAd->StaCfg.dBmToRoam; - - DBGPRINT(RT_DEBUG_TRACE, ("Rssi=%d, dBmToRoam=%d\n", RTMPMaxRssi(pAd, pAd->StaCfg.RssiSample.LastRssi0, pAd->StaCfg.RssiSample.LastRssi1, pAd->StaCfg.RssiSample.LastRssi2), (CHAR)dBmToRoam)); - - if (RTMPMaxRssi(pAd, pAd->StaCfg.RssiSample.LastRssi0, pAd->StaCfg.RssiSample.LastRssi1, pAd->StaCfg.RssiSample.LastRssi2) <= (CHAR)dBmToRoam) - { - MlmeCheckForFastRoaming(pAd, pAd->Mlme.Now32); - } - } - } - else if (ADHOC_ON(pAd)) - { - //radar detect - if ((pAd->CommonCfg.Channel > 14) - && (pAd->CommonCfg.bIEEE80211H == 1) - && RadarChannelCheck(pAd, pAd->CommonCfg.Channel)) - { - RadarDetectPeriodic(pAd); - } - - // If all peers leave, and this STA becomes the last one in this IBSS, then change MediaState - // to DISCONNECTED. But still holding this IBSS (i.e. sending BEACON) so that other STAs can - // join later. - if ((pAd->StaCfg.LastBeaconRxTime + ADHOC_BEACON_LOST_TIME < pAd->Mlme.Now32) && - OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) - { - MLME_START_REQ_STRUCT StartReq; - - DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - excessive BEACON lost, last STA in this IBSS, MediaState=Disconnected\n")); - LinkDown(pAd, FALSE); - - StartParmFill(pAd, &StartReq, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen); - MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_START_REQ, sizeof(MLME_START_REQ_STRUCT), &StartReq); - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_START; - } - - for (i = 1; i < MAX_LEN_OF_MAC_TABLE; i++) - { - MAC_TABLE_ENTRY *pEntry = &pAd->MacTab.Content[i]; - - if (pEntry->ValidAsCLI == FALSE) - continue; - - if (pEntry->LastBeaconRxTime + ADHOC_BEACON_LOST_TIME < pAd->Mlme.Now32) - MacTableDeleteEntry(pAd, pEntry->Aid, pEntry->Addr); - } - } - else // no INFRA nor ADHOC connection - { - - if (pAd->StaCfg.bScanReqIsFromWebUI && - ((pAd->StaCfg.LastScanTime + 30 * OS_HZ) > pAd->Mlme.Now32)) - goto SKIP_AUTO_SCAN_CONN; - else - pAd->StaCfg.bScanReqIsFromWebUI = FALSE; - - if ((pAd->StaCfg.bAutoReconnect == TRUE) - && RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_START_UP) - && (MlmeValidateSSID(pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.AutoReconnectSsidLen) == TRUE)) - { - if ((pAd->ScanTab.BssNr==0) && (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE)) - { - MLME_SCAN_REQ_STRUCT ScanReq; - - if ((pAd->StaCfg.LastScanTime + 10 * OS_HZ) < pAd->Mlme.Now32) - { - DBGPRINT(RT_DEBUG_TRACE, ("STAMlmePeriodicExec():CNTL - ScanTab.BssNr==0, start a new ACTIVE scan SSID[%s]\n", pAd->MlmeAux.AutoReconnectSsid)); - ScanParmFill(pAd, &ScanReq, pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.AutoReconnectSsidLen, BSS_ANY, SCAN_ACTIVE); - MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq); - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN; - // Reset Missed scan number - pAd->StaCfg.LastScanTime = pAd->Mlme.Now32; - } - else if (pAd->StaCfg.BssType == BSS_ADHOC) // Quit the forever scan when in a very clean room - MlmeAutoReconnectLastSSID(pAd); - } - else if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) - { - if ((pAd->Mlme.OneSecPeriodicRound % 7) == 0) - { - MlmeAutoScan(pAd); - pAd->StaCfg.LastScanTime = pAd->Mlme.Now32; - } - else - { -#ifdef CARRIER_DETECTION_SUPPORT // Roger sync Carrier - if (pAd->CommonCfg.CarrierDetect.Enable == TRUE) - { - if ((pAd->Mlme.OneSecPeriodicRound % 5) == 1) - MlmeAutoReconnectLastSSID(pAd); - } - else -#endif // CARRIER_DETECTION_SUPPORT // - MlmeAutoReconnectLastSSID(pAd); - } - } - } - } - -SKIP_AUTO_SCAN_CONN: - -#ifdef DOT11_N_SUPPORT - if ((pAd->MacTab.Content[BSSID_WCID].TXBAbitmap !=0) && (pAd->MacTab.fAnyBASession == FALSE)) - { - pAd->MacTab.fAnyBASession = TRUE; - AsicUpdateProtect(pAd, HT_FORCERTSCTS, ALLN_SETPROTECT, FALSE, FALSE); - } - else if ((pAd->MacTab.Content[BSSID_WCID].TXBAbitmap ==0) && (pAd->MacTab.fAnyBASession == TRUE)) - { - pAd->MacTab.fAnyBASession = FALSE; - AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, ALLN_SETPROTECT, FALSE, FALSE); - } -#endif // DOT11_N_SUPPORT // - - -#ifdef DOT11_N_SUPPORT -#ifdef DOT11N_DRAFT3 - if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_SCAN_2040)) - TriEventCounterMaintenance(pAd); -#endif // DOT11N_DRAFT3 // -#endif // DOT11_N_SUPPORT // - - return; -} - -// Link down report -VOID LinkDownExec( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3) -{ - - RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext; - - pAd->IndicateMediaState = NdisMediaStateDisconnected; - RTMP_IndicateMediaState(pAd); - pAd->ExtraInfo = GENERAL_LINK_DOWN; -} - -// IRQL = DISPATCH_LEVEL -VOID MlmeAutoScan( - IN PRTMP_ADAPTER pAd) -{ - // check CntlMachine.CurrState to avoid collision with NDIS SetOID request - if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) - { - DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - Driver auto scan\n")); - MlmeEnqueue(pAd, - MLME_CNTL_STATE_MACHINE, - OID_802_11_BSSID_LIST_SCAN, - 0, - NULL); - RT28XX_MLME_HANDLER(pAd); - } -} - -// IRQL = DISPATCH_LEVEL -VOID MlmeAutoReconnectLastSSID( - IN PRTMP_ADAPTER pAd) -{ - - - // check CntlMachine.CurrState to avoid collision with NDIS SetOID request - if ((pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) && - (MlmeValidateSSID(pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.AutoReconnectSsidLen) == TRUE)) - { - NDIS_802_11_SSID OidSsid; - OidSsid.SsidLength = pAd->MlmeAux.AutoReconnectSsidLen; - NdisMoveMemory(OidSsid.Ssid, pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.AutoReconnectSsidLen); - - DBGPRINT(RT_DEBUG_TRACE, ("Driver auto reconnect to last OID_802_11_SSID setting - %s, len - %d\n", pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.AutoReconnectSsidLen)); - MlmeEnqueue(pAd, - MLME_CNTL_STATE_MACHINE, - OID_802_11_SSID, - sizeof(NDIS_802_11_SSID), - &OidSsid); - RT28XX_MLME_HANDLER(pAd); - } -} -#endif // CONFIG_STA_SUPPORT // - -/* - ========================================================================== - Validate SSID for connection try and rescan purpose - Valid SSID will have visible chars only. - The valid length is from 0 to 32. - IRQL = DISPATCH_LEVEL - ========================================================================== - */ -BOOLEAN MlmeValidateSSID( - IN PUCHAR pSsid, - IN UCHAR SsidLen) -{ - int index; - - if (SsidLen > MAX_LEN_OF_SSID) - return (FALSE); - - // Check each character value - for (index = 0; index < SsidLen; index++) - { - if (pSsid[index] < 0x20) - return (FALSE); - } - - // All checked - return (TRUE); -} - -VOID MlmeSelectTxRateTable( - IN PRTMP_ADAPTER pAd, - IN PMAC_TABLE_ENTRY pEntry, - IN PUCHAR *ppTable, - IN PUCHAR pTableSize, - IN PUCHAR pInitTxRateIdx) -{ - do - { - // decide the rate table for tuning - if (pAd->CommonCfg.TxRateTableSize > 0) - { - *ppTable = RateSwitchTable; - *pTableSize = RateSwitchTable[0]; - *pInitTxRateIdx = RateSwitchTable[1]; - - break; - } - -#ifdef CONFIG_STA_SUPPORT - if ((pAd->OpMode == OPMODE_STA) && ADHOC_ON(pAd)) - { -#ifdef DOT11_N_SUPPORT - if ((pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) && - (pEntry->HTCapability.MCSSet[0] == 0xff) && - ((pEntry->HTCapability.MCSSet[1] == 0x00) || (pAd->Antenna.field.TxPath == 1))) - {// 11N 1S Adhoc - *ppTable = RateSwitchTable11N1S; - *pTableSize = RateSwitchTable11N1S[0]; - *pInitTxRateIdx = RateSwitchTable11N1S[1]; - - } - else if ((pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) && - (pEntry->HTCapability.MCSSet[0] == 0xff) && - (pEntry->HTCapability.MCSSet[1] == 0xff) && - (pAd->Antenna.field.TxPath == 2)) - {// 11N 2S Adhoc - if (pAd->LatchRfRegs.Channel <= 14) - { - *ppTable = RateSwitchTable11N2S; - *pTableSize = RateSwitchTable11N2S[0]; - *pInitTxRateIdx = RateSwitchTable11N2S[1]; - } - else - { - *ppTable = RateSwitchTable11N2SForABand; - *pTableSize = RateSwitchTable11N2SForABand[0]; - *pInitTxRateIdx = RateSwitchTable11N2SForABand[1]; - } - - } - else -#endif // DOT11_N_SUPPORT // - if ((pEntry->RateLen == 4) -#ifdef DOT11_N_SUPPORT - && (pEntry->HTCapability.MCSSet[0] == 0) && (pEntry->HTCapability.MCSSet[1] == 0) -#endif // DOT11_N_SUPPORT // - ) - { - *ppTable = RateSwitchTable11B; - *pTableSize = RateSwitchTable11B[0]; - *pInitTxRateIdx = RateSwitchTable11B[1]; - - } - else if (pAd->LatchRfRegs.Channel <= 14) - { - *ppTable = RateSwitchTable11BG; - *pTableSize = RateSwitchTable11BG[0]; - *pInitTxRateIdx = RateSwitchTable11BG[1]; - - } - else - { - *ppTable = RateSwitchTable11G; - *pTableSize = RateSwitchTable11G[0]; - *pInitTxRateIdx = RateSwitchTable11G[1]; - - } - break; - } -#endif // CONFIG_STA_SUPPORT // - -#ifdef DOT11_N_SUPPORT - //if ((pAd->StaActive.SupRateLen + pAd->StaActive.ExtRateLen == 12) && (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0xff) && - // ((pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0x00) || (pAd->Antenna.field.TxPath == 1))) - if ((pEntry->RateLen == 12) && (pEntry->HTCapability.MCSSet[0] == 0xff) && - ((pEntry->HTCapability.MCSSet[1] == 0x00) || (pAd->CommonCfg.TxStream == 1))) - {// 11BGN 1S AP - *ppTable = RateSwitchTable11BGN1S; - *pTableSize = RateSwitchTable11BGN1S[0]; - *pInitTxRateIdx = RateSwitchTable11BGN1S[1]; - - break; - } - - //else if ((pAd->StaActive.SupRateLen + pAd->StaActive.ExtRateLen == 12) && (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0xff) && - // (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0xff) && (pAd->Antenna.field.TxPath == 2)) - if ((pEntry->RateLen == 12) && (pEntry->HTCapability.MCSSet[0] == 0xff) && - (pEntry->HTCapability.MCSSet[1] == 0xff) && (pAd->CommonCfg.TxStream == 2)) - {// 11BGN 2S AP - if (pAd->LatchRfRegs.Channel <= 14) - { - *ppTable = RateSwitchTable11BGN2S; - *pTableSize = RateSwitchTable11BGN2S[0]; - *pInitTxRateIdx = RateSwitchTable11BGN2S[1]; - - } - else - { - *ppTable = RateSwitchTable11BGN2SForABand; - *pTableSize = RateSwitchTable11BGN2SForABand[0]; - *pInitTxRateIdx = RateSwitchTable11BGN2SForABand[1]; - - } - break; - } - - //else if ((pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0xff) && ((pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0x00) || (pAd->Antenna.field.TxPath == 1))) - if ((pEntry->HTCapability.MCSSet[0] == 0xff) && ((pEntry->HTCapability.MCSSet[1] == 0x00) || (pAd->CommonCfg.TxStream == 1))) - {// 11N 1S AP - *ppTable = RateSwitchTable11N1S; - *pTableSize = RateSwitchTable11N1S[0]; - *pInitTxRateIdx = RateSwitchTable11N1S[1]; - - break; - } - - //else if ((pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0xff) && (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0xff) && (pAd->Antenna.field.TxPath == 2)) - if ((pEntry->HTCapability.MCSSet[0] == 0xff) && (pEntry->HTCapability.MCSSet[1] == 0xff) && (pAd->CommonCfg.TxStream == 2)) - {// 11N 2S AP - if (pAd->LatchRfRegs.Channel <= 14) - { - *ppTable = RateSwitchTable11N2S; - *pTableSize = RateSwitchTable11N2S[0]; - *pInitTxRateIdx = RateSwitchTable11N2S[1]; - } - else - { - *ppTable = RateSwitchTable11N2SForABand; - *pTableSize = RateSwitchTable11N2SForABand[0]; - *pInitTxRateIdx = RateSwitchTable11N2SForABand[1]; - } - - break; - } -#endif // DOT11_N_SUPPORT // - //else if ((pAd->StaActive.SupRateLen == 4) && (pAd->StaActive.ExtRateLen == 0) && (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0) && (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0)) - if ((pEntry->RateLen == 4) -#ifdef DOT11_N_SUPPORT - && (pEntry->HTCapability.MCSSet[0] == 0) && (pEntry->HTCapability.MCSSet[1] == 0) -#endif // DOT11_N_SUPPORT // - ) - {// B only AP - *ppTable = RateSwitchTable11B; - *pTableSize = RateSwitchTable11B[0]; - *pInitTxRateIdx = RateSwitchTable11B[1]; - - break; - } - - //else if ((pAd->StaActive.SupRateLen + pAd->StaActive.ExtRateLen > 8) && (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0) && (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0)) - if ((pEntry->RateLen > 8) -#ifdef DOT11_N_SUPPORT - && (pEntry->HTCapability.MCSSet[0] == 0) && (pEntry->HTCapability.MCSSet[1] == 0) -#endif // DOT11_N_SUPPORT // - ) - {// B/G mixed AP - *ppTable = RateSwitchTable11BG; - *pTableSize = RateSwitchTable11BG[0]; - *pInitTxRateIdx = RateSwitchTable11BG[1]; - - break; - } - - //else if ((pAd->StaActive.SupRateLen + pAd->StaActive.ExtRateLen == 8) && (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0) && (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0)) - if ((pEntry->RateLen == 8) -#ifdef DOT11_N_SUPPORT - && (pEntry->HTCapability.MCSSet[0] == 0) && (pEntry->HTCapability.MCSSet[1] == 0) -#endif // DOT11_N_SUPPORT // - ) - {// G only AP - *ppTable = RateSwitchTable11G; - *pTableSize = RateSwitchTable11G[0]; - *pInitTxRateIdx = RateSwitchTable11G[1]; - - break; - } -#ifdef DOT11_N_SUPPORT -#endif // DOT11_N_SUPPORT // - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { -#ifdef DOT11_N_SUPPORT - //else if ((pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0) && (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0)) - if ((pEntry->HTCapability.MCSSet[0] == 0) && (pEntry->HTCapability.MCSSet[1] == 0)) -#endif // DOT11_N_SUPPORT // - { // Legacy mode - if (pAd->CommonCfg.MaxTxRate <= RATE_11) - { - *ppTable = RateSwitchTable11B; - *pTableSize = RateSwitchTable11B[0]; - *pInitTxRateIdx = RateSwitchTable11B[1]; - } - else if ((pAd->CommonCfg.MaxTxRate > RATE_11) && (pAd->CommonCfg.MinTxRate > RATE_11)) - { - *ppTable = RateSwitchTable11G; - *pTableSize = RateSwitchTable11G[0]; - *pInitTxRateIdx = RateSwitchTable11G[1]; - - } - else - { - *ppTable = RateSwitchTable11BG; - *pTableSize = RateSwitchTable11BG[0]; - *pInitTxRateIdx = RateSwitchTable11BG[1]; - } - break; - } -#ifdef DOT11_N_SUPPORT - if (pAd->LatchRfRegs.Channel <= 14) - { - if (pAd->CommonCfg.TxStream == 1) - { - *ppTable = RateSwitchTable11N1S; - *pTableSize = RateSwitchTable11N1S[0]; - *pInitTxRateIdx = RateSwitchTable11N1S[1]; - DBGPRINT_RAW(RT_DEBUG_ERROR,("DRS: unkown mode,default use 11N 1S AP \n")); - } - else - { - *ppTable = RateSwitchTable11N2S; - *pTableSize = RateSwitchTable11N2S[0]; - *pInitTxRateIdx = RateSwitchTable11N2S[1]; - DBGPRINT_RAW(RT_DEBUG_ERROR,("DRS: unkown mode,default use 11N 2S AP \n")); - } - } - else - { - if (pAd->CommonCfg.TxStream == 1) - { - *ppTable = RateSwitchTable11N1S; - *pTableSize = RateSwitchTable11N1S[0]; - *pInitTxRateIdx = RateSwitchTable11N1S[1]; - DBGPRINT_RAW(RT_DEBUG_ERROR,("DRS: unkown mode,default use 11N 1S AP \n")); - } - else - { - *ppTable = RateSwitchTable11N2SForABand; - *pTableSize = RateSwitchTable11N2SForABand[0]; - *pInitTxRateIdx = RateSwitchTable11N2SForABand[1]; - DBGPRINT_RAW(RT_DEBUG_ERROR,("DRS: unkown mode,default use 11N 2S AP \n")); - } - } -#endif // DOT11_N_SUPPORT // - DBGPRINT_RAW(RT_DEBUG_ERROR,("DRS: unkown mode (SupRateLen=%d, ExtRateLen=%d, MCSSet[0]=0x%x, MCSSet[1]=0x%x)\n", - pAd->StaActive.SupRateLen, pAd->StaActive.ExtRateLen, pAd->StaActive.SupportedPhyInfo.MCSSet[0], pAd->StaActive.SupportedPhyInfo.MCSSet[1])); - } -#endif // CONFIG_STA_SUPPORT // - } while(FALSE); -} - -#ifdef CONFIG_STA_SUPPORT -/* - ========================================================================== - Description: - This routine checks if there're other APs out there capable for - roaming. Caller should call this routine only when Link up in INFRA mode - and channel quality is below CQI_GOOD_THRESHOLD. - - IRQL = DISPATCH_LEVEL - - Output: - ========================================================================== - */ -VOID MlmeCheckForRoaming( - IN PRTMP_ADAPTER pAd, - IN ULONG Now32) -{ - USHORT i; - BSS_TABLE *pRoamTab = &pAd->MlmeAux.RoamTab; - BSS_ENTRY *pBss; - - DBGPRINT(RT_DEBUG_TRACE, ("==> MlmeCheckForRoaming\n")); - // put all roaming candidates into RoamTab, and sort in RSSI order - BssTableInit(pRoamTab); - for (i = 0; i < pAd->ScanTab.BssNr; i++) - { - pBss = &pAd->ScanTab.BssEntry[i]; - - if ((pBss->LastBeaconRxTime + BEACON_LOST_TIME) < Now32) - continue; // AP disappear - if (pBss->Rssi <= RSSI_THRESHOLD_FOR_ROAMING) - continue; // RSSI too weak. forget it. - if (MAC_ADDR_EQUAL(pBss->Bssid, pAd->CommonCfg.Bssid)) - continue; // skip current AP - if (pBss->Rssi < (pAd->StaCfg.RssiSample.LastRssi0 + RSSI_DELTA)) - continue; // only AP with stronger RSSI is eligible for roaming - - // AP passing all above rules is put into roaming candidate table - NdisMoveMemory(&pRoamTab->BssEntry[pRoamTab->BssNr], pBss, sizeof(BSS_ENTRY)); - pRoamTab->BssNr += 1; - } - - if (pRoamTab->BssNr > 0) - { - // check CntlMachine.CurrState to avoid collision with NDIS SetOID request - if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) - { - pAd->RalinkCounters.PoorCQIRoamingCount ++; - DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - Roaming attempt #%ld\n", pAd->RalinkCounters.PoorCQIRoamingCount)); - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_MLME_ROAMING_REQ, 0, NULL); - RT28XX_MLME_HANDLER(pAd); - } - } - DBGPRINT(RT_DEBUG_TRACE, ("<== MlmeCheckForRoaming(# of candidate= %d)\n",pRoamTab->BssNr)); -} - -/* - ========================================================================== - Description: - This routine checks if there're other APs out there capable for - roaming. Caller should call this routine only when link up in INFRA mode - and channel quality is below CQI_GOOD_THRESHOLD. - - IRQL = DISPATCH_LEVEL - - Output: - ========================================================================== - */ -VOID MlmeCheckForFastRoaming( - IN PRTMP_ADAPTER pAd, - IN ULONG Now) -{ - USHORT i; - BSS_TABLE *pRoamTab = &pAd->MlmeAux.RoamTab; - BSS_ENTRY *pBss; - - DBGPRINT(RT_DEBUG_TRACE, ("==> MlmeCheckForFastRoaming\n")); - // put all roaming candidates into RoamTab, and sort in RSSI order - BssTableInit(pRoamTab); - for (i = 0; i < pAd->ScanTab.BssNr; i++) - { - pBss = &pAd->ScanTab.BssEntry[i]; - - if ((pBss->Rssi <= -50) && (pBss->Channel == pAd->CommonCfg.Channel)) - continue; // RSSI too weak. forget it. - if (MAC_ADDR_EQUAL(pBss->Bssid, pAd->CommonCfg.Bssid)) - continue; // skip current AP - if (!SSID_EQUAL(pBss->Ssid, pBss->SsidLen, pAd->CommonCfg.Ssid, pAd->CommonCfg.SsidLen)) - continue; // skip different SSID - if (pBss->Rssi < (RTMPMaxRssi(pAd, pAd->StaCfg.RssiSample.LastRssi0, pAd->StaCfg.RssiSample.LastRssi1, pAd->StaCfg.RssiSample.LastRssi2) + RSSI_DELTA)) - continue; // skip AP without better RSSI - - DBGPRINT(RT_DEBUG_TRACE, ("LastRssi0 = %d, pBss->Rssi = %d\n", RTMPMaxRssi(pAd, pAd->StaCfg.RssiSample.LastRssi0, pAd->StaCfg.RssiSample.LastRssi1, pAd->StaCfg.RssiSample.LastRssi2), pBss->Rssi)); - // AP passing all above rules is put into roaming candidate table - NdisMoveMemory(&pRoamTab->BssEntry[pRoamTab->BssNr], pBss, sizeof(BSS_ENTRY)); - pRoamTab->BssNr += 1; - } - - if (pRoamTab->BssNr > 0) - { - // check CntlMachine.CurrState to avoid collision with NDIS SetOID request - if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) - { - pAd->RalinkCounters.PoorCQIRoamingCount ++; - DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - Roaming attempt #%ld\n", pAd->RalinkCounters.PoorCQIRoamingCount)); - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_MLME_ROAMING_REQ, 0, NULL); - RT28XX_MLME_HANDLER(pAd); - } - } - // Maybe site survey required - else - { - if ((pAd->StaCfg.LastScanTime + 10 * 1000) < Now) - { - // check CntlMachine.CurrState to avoid collision with NDIS SetOID request - DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - Roaming, No eligable entry, try new scan!\n")); - pAd->StaCfg.ScanCnt = 2; - pAd->StaCfg.LastScanTime = Now; - MlmeAutoScan(pAd); - } - } - - DBGPRINT(RT_DEBUG_TRACE, ("<== MlmeCheckForFastRoaming (BssNr=%d)\n", pRoamTab->BssNr)); -} - -/* - ========================================================================== - Description: - This routine calculates TxPER, RxPER of the past N-sec period. And - according to the calculation result, ChannelQuality is calculated here - to decide if current AP is still doing the job. - - If ChannelQuality is not good, a ROAMing attempt may be tried later. - Output: - StaCfg.ChannelQuality - 0..100 - - IRQL = DISPATCH_LEVEL - - NOTE: This routine decide channle quality based on RX CRC error ratio. - Caller should make sure a function call to NICUpdateRawCounters(pAd) - is performed right before this routine, so that this routine can decide - channel quality based on the most up-to-date information - ========================================================================== - */ -VOID MlmeCalculateChannelQuality( - IN PRTMP_ADAPTER pAd, - IN ULONG Now32) -{ - ULONG TxOkCnt, TxCnt, TxPER, TxPRR; - ULONG RxCnt, RxPER; - UCHAR NorRssi; - CHAR MaxRssi; - ULONG BeaconLostTime = BEACON_LOST_TIME; - -#ifdef CARRIER_DETECTION_SUPPORT // Roger sync Carrier - // longer beacon lost time when carrier detection enabled - if (pAd->CommonCfg.CarrierDetect.Enable == TRUE) - { - BeaconLostTime = BEACON_LOST_TIME + BEACON_LOST_TIME/2; - } -#endif // CARRIER_DETECTION_SUPPORT // - - MaxRssi = RTMPMaxRssi(pAd, pAd->StaCfg.RssiSample.LastRssi0, pAd->StaCfg.RssiSample.LastRssi1, pAd->StaCfg.RssiSample.LastRssi2); - - // - // calculate TX packet error ratio and TX retry ratio - if too few TX samples, skip TX related statistics - // - TxOkCnt = pAd->RalinkCounters.OneSecTxNoRetryOkCount + pAd->RalinkCounters.OneSecTxRetryOkCount; - TxCnt = TxOkCnt + pAd->RalinkCounters.OneSecTxFailCount; - if (TxCnt < 5) - { - TxPER = 0; - TxPRR = 0; - } - else - { - TxPER = (pAd->RalinkCounters.OneSecTxFailCount * 100) / TxCnt; - TxPRR = ((TxCnt - pAd->RalinkCounters.OneSecTxNoRetryOkCount) * 100) / TxCnt; - } - - // - // calculate RX PER - don't take RxPER into consideration if too few sample - // - RxCnt = pAd->RalinkCounters.OneSecRxOkCnt + pAd->RalinkCounters.OneSecRxFcsErrCnt; - if (RxCnt < 5) - RxPER = 0; - else - RxPER = (pAd->RalinkCounters.OneSecRxFcsErrCnt * 100) / RxCnt; - - // - // decide ChannelQuality based on: 1)last BEACON received time, 2)last RSSI, 3)TxPER, and 4)RxPER - // - if (INFRA_ON(pAd) && - (pAd->RalinkCounters.OneSecTxNoRetryOkCount < 2) && // no heavy traffic - (pAd->StaCfg.LastBeaconRxTime + BeaconLostTime < Now32)) - { - DBGPRINT(RT_DEBUG_TRACE, ("BEACON lost > %ld msec with TxOkCnt=%ld -> CQI=0\n", BeaconLostTime, TxOkCnt)); - pAd->Mlme.ChannelQuality = 0; - } - else - { - // Normalize Rssi - if (MaxRssi > -40) - NorRssi = 100; - else if (MaxRssi < -90) - NorRssi = 0; - else - NorRssi = (MaxRssi + 90) * 2; - - // ChannelQuality = W1*RSSI + W2*TxPRR + W3*RxPER (RSSI 0..100), (TxPER 100..0), (RxPER 100..0) - pAd->Mlme.ChannelQuality = (RSSI_WEIGHTING * NorRssi + - TX_WEIGHTING * (100 - TxPRR) + - RX_WEIGHTING* (100 - RxPER)) / 100; - if (pAd->Mlme.ChannelQuality >= 100) - pAd->Mlme.ChannelQuality = 100; - } - -} - -VOID MlmeSetTxRate( - IN PRTMP_ADAPTER pAd, - IN PMAC_TABLE_ENTRY pEntry, - IN PRTMP_TX_RATE_SWITCH pTxRate) -{ - UCHAR MaxMode = MODE_OFDM; - -#ifdef DOT11_N_SUPPORT - MaxMode = MODE_HTGREENFIELD; - - if (pTxRate->STBC && (pAd->StaCfg.MaxHTPhyMode.field.STBC) && (pAd->Antenna.field.TxPath == 2)) - pAd->StaCfg.HTPhyMode.field.STBC = STBC_USE; - else -#endif // DOT11_N_SUPPORT // - pAd->StaCfg.HTPhyMode.field.STBC = STBC_NONE; - - if (pTxRate->CurrMCS < MCS_AUTO) - pAd->StaCfg.HTPhyMode.field.MCS = pTxRate->CurrMCS; - - if (pAd->StaCfg.HTPhyMode.field.MCS > 7) - pAd->StaCfg.HTPhyMode.field.STBC = STBC_NONE; - - if (ADHOC_ON(pAd)) - { - // If peer adhoc is b-only mode, we can't send 11g rate. - pAd->StaCfg.HTPhyMode.field.ShortGI = GI_800; - pEntry->HTPhyMode.field.STBC = STBC_NONE; - - // - // For Adhoc MODE_CCK, driver will use AdhocBOnlyJoined flag to roll back to B only if necessary - // - pEntry->HTPhyMode.field.MODE = pTxRate->Mode; - pEntry->HTPhyMode.field.ShortGI = pAd->StaCfg.HTPhyMode.field.ShortGI; - pEntry->HTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; - - // Patch speed error in status page - pAd->StaCfg.HTPhyMode.field.MODE = pEntry->HTPhyMode.field.MODE; - } - else - { - if (pTxRate->Mode <= MaxMode) - pAd->StaCfg.HTPhyMode.field.MODE = pTxRate->Mode; - -#ifdef DOT11_N_SUPPORT - if (pTxRate->ShortGI && (pAd->StaCfg.MaxHTPhyMode.field.ShortGI)) - pAd->StaCfg.HTPhyMode.field.ShortGI = GI_400; - else -#endif // DOT11_N_SUPPORT // - pAd->StaCfg.HTPhyMode.field.ShortGI = GI_800; - -#ifdef DOT11_N_SUPPORT - // Reexam each bandwidth's SGI support. - if (pAd->StaCfg.HTPhyMode.field.ShortGI == GI_400) - { - if ((pEntry->HTPhyMode.field.BW == BW_20) && (!CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_SGI20_CAPABLE))) - pAd->StaCfg.HTPhyMode.field.ShortGI = GI_800; - if ((pEntry->HTPhyMode.field.BW == BW_40) && (!CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_SGI40_CAPABLE))) - pAd->StaCfg.HTPhyMode.field.ShortGI = GI_800; - } - - // Turn RTS/CTS rate to 6Mbps. - if ((pEntry->HTPhyMode.field.MCS == 0) && (pAd->StaCfg.HTPhyMode.field.MCS != 0)) - { - pEntry->HTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; - if (pAd->MacTab.fAnyBASession) - { - AsicUpdateProtect(pAd, HT_FORCERTSCTS, ALLN_SETPROTECT, TRUE, (BOOLEAN)pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent); - } - else - { - AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, ALLN_SETPROTECT, TRUE, (BOOLEAN)pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent); - } - } - else if ((pEntry->HTPhyMode.field.MCS == 8) && (pAd->StaCfg.HTPhyMode.field.MCS != 8)) - { - pEntry->HTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; - if (pAd->MacTab.fAnyBASession) - { - AsicUpdateProtect(pAd, HT_FORCERTSCTS, ALLN_SETPROTECT, TRUE, (BOOLEAN)pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent); - } - else - { - AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, ALLN_SETPROTECT, TRUE, (BOOLEAN)pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent); - } - } - else if ((pEntry->HTPhyMode.field.MCS != 0) && (pAd->StaCfg.HTPhyMode.field.MCS == 0)) - { - AsicUpdateProtect(pAd, HT_RTSCTS_6M, ALLN_SETPROTECT, TRUE, (BOOLEAN)pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent); - - } - else if ((pEntry->HTPhyMode.field.MCS != 8) && (pAd->StaCfg.HTPhyMode.field.MCS == 8)) - { - AsicUpdateProtect(pAd, HT_RTSCTS_6M, ALLN_SETPROTECT, TRUE, (BOOLEAN)pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent); - } -#endif // DOT11_N_SUPPORT // - - pEntry->HTPhyMode.field.STBC = pAd->StaCfg.HTPhyMode.field.STBC; - pEntry->HTPhyMode.field.ShortGI = pAd->StaCfg.HTPhyMode.field.ShortGI; - pEntry->HTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; - pEntry->HTPhyMode.field.MODE = pAd->StaCfg.HTPhyMode.field.MODE; -#ifdef DOT11_N_SUPPORT - if ((pAd->StaCfg.MaxHTPhyMode.field.MODE == MODE_HTGREENFIELD) && - pAd->WIFItestbed.bGreenField) - pEntry->HTPhyMode.field.MODE = MODE_HTGREENFIELD; -#endif // DOT11_N_SUPPORT // - } - - pAd->LastTxRate = (USHORT)(pEntry->HTPhyMode.word); -} - -/* - ========================================================================== - Description: - This routine calculates the acumulated TxPER of eaxh TxRate. And - according to the calculation result, change CommonCfg.TxRate which - is the stable TX Rate we expect the Radio situation could sustained. - - CommonCfg.TxRate will change dynamically within {RATE_1/RATE_6, MaxTxRate} - Output: - CommonCfg.TxRate - - - IRQL = DISPATCH_LEVEL - - NOTE: - call this routine every second - ========================================================================== - */ -VOID MlmeDynamicTxRateSwitching( - IN PRTMP_ADAPTER pAd) -{ - UCHAR UpRateIdx = 0, DownRateIdx = 0, CurrRateIdx; - ULONG i, AccuTxTotalCnt = 0, TxTotalCnt; - ULONG TxErrorRatio = 0; - BOOLEAN bTxRateChanged, bUpgradeQuality = FALSE; - PRTMP_TX_RATE_SWITCH pCurrTxRate, pNextTxRate = NULL; - PUCHAR pTable; - UCHAR TableSize = 0; - UCHAR InitTxRateIdx = 0, TrainUp, TrainDown; - CHAR Rssi, RssiOffset = 0; - TX_STA_CNT1_STRUC StaTx1; - TX_STA_CNT0_STRUC TxStaCnt0; - ULONG TxRetransmit = 0, TxSuccess = 0, TxFailCount = 0; - MAC_TABLE_ENTRY *pEntry; - -#ifdef RALINK_ATE - if (ATE_ON(pAd)) - { - return; - } -#endif // RALINK_ATE // - - // - // walk through MAC table, see if need to change AP's TX rate toward each entry - // - for (i = 1; i < MAX_LEN_OF_MAC_TABLE; i++) - { - pEntry = &pAd->MacTab.Content[i]; - - // check if this entry need to switch rate automatically - if (RTMPCheckEntryEnableAutoRateSwitch(pAd, pEntry) == FALSE) - continue; - - if ((pAd->MacTab.Size == 1) || (pEntry->ValidAsDls)) - { - Rssi = RTMPMaxRssi(pAd, - pAd->StaCfg.RssiSample.AvgRssi0, - pAd->StaCfg.RssiSample.AvgRssi1, - pAd->StaCfg.RssiSample.AvgRssi2); - - // Update statistic counter - RTMP_IO_READ32(pAd, TX_STA_CNT0, &TxStaCnt0.word); - RTMP_IO_READ32(pAd, TX_STA_CNT1, &StaTx1.word); - pAd->bUpdateBcnCntDone = TRUE; - TxRetransmit = StaTx1.field.TxRetransmit; - TxSuccess = StaTx1.field.TxSuccess; - TxFailCount = TxStaCnt0.field.TxFailCount; - TxTotalCnt = TxRetransmit + TxSuccess + TxFailCount; - - pAd->RalinkCounters.OneSecTxRetryOkCount += StaTx1.field.TxRetransmit; - pAd->RalinkCounters.OneSecTxNoRetryOkCount += StaTx1.field.TxSuccess; - pAd->RalinkCounters.OneSecTxFailCount += TxStaCnt0.field.TxFailCount; - pAd->WlanCounters.TransmittedFragmentCount.u.LowPart += StaTx1.field.TxSuccess; - pAd->WlanCounters.RetryCount.u.LowPart += StaTx1.field.TxRetransmit; - pAd->WlanCounters.FailedCount.u.LowPart += TxStaCnt0.field.TxFailCount; - - // if no traffic in the past 1-sec period, don't change TX rate, - // but clear all bad history. because the bad history may affect the next - // Chariot throughput test - AccuTxTotalCnt = pAd->RalinkCounters.OneSecTxNoRetryOkCount + - pAd->RalinkCounters.OneSecTxRetryOkCount + - pAd->RalinkCounters.OneSecTxFailCount; - - if (TxTotalCnt) - TxErrorRatio = ((TxRetransmit + TxFailCount) * 100) / TxTotalCnt; - } - else - { - if (INFRA_ON(pAd) && (i == 1)) - Rssi = RTMPMaxRssi(pAd, - pAd->StaCfg.RssiSample.AvgRssi0, - pAd->StaCfg.RssiSample.AvgRssi1, - pAd->StaCfg.RssiSample.AvgRssi2); - else - Rssi = RTMPMaxRssi(pAd, - pEntry->RssiSample.AvgRssi0, - pEntry->RssiSample.AvgRssi1, - pEntry->RssiSample.AvgRssi2); - - TxTotalCnt = pEntry->OneSecTxNoRetryOkCount + - pEntry->OneSecTxRetryOkCount + - pEntry->OneSecTxFailCount; - - if (TxTotalCnt) - TxErrorRatio = ((pEntry->OneSecTxRetryOkCount + pEntry->OneSecTxFailCount) * 100) / TxTotalCnt; - } - - CurrRateIdx = pEntry->CurrTxRateIndex; - - MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize, &InitTxRateIdx); - - if (CurrRateIdx >= TableSize) - { - CurrRateIdx = TableSize - 1; - } - - // When switch from Fixed rate -> auto rate, the REAL TX rate might be different from pAd->CommonCfg.TxRateIndex. - // So need to sync here. - pCurrTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(CurrRateIdx+1)*5]; - if ((pEntry->HTPhyMode.field.MCS != pCurrTxRate->CurrMCS) - //&& (pAd->StaCfg.bAutoTxRateSwitch == TRUE) - ) - { - - // Need to sync Real Tx rate and our record. - // Then return for next DRS. - pCurrTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(InitTxRateIdx+1)*5]; - pEntry->CurrTxRateIndex = InitTxRateIdx; - MlmeSetTxRate(pAd, pEntry, pCurrTxRate); - - // reset all OneSecTx counters - RESET_ONE_SEC_TX_CNT(pEntry); - continue; - } - - // decide the next upgrade rate and downgrade rate, if any - if ((CurrRateIdx > 0) && (CurrRateIdx < (TableSize - 1))) - { - UpRateIdx = CurrRateIdx + 1; - DownRateIdx = CurrRateIdx -1; - } - else if (CurrRateIdx == 0) - { - UpRateIdx = CurrRateIdx + 1; - DownRateIdx = CurrRateIdx; - } - else if (CurrRateIdx == (TableSize - 1)) - { - UpRateIdx = CurrRateIdx; - DownRateIdx = CurrRateIdx - 1; - } - - pCurrTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(CurrRateIdx+1)*5]; - -#ifdef DOT11_N_SUPPORT - if ((Rssi > -65) && (pCurrTxRate->Mode >= MODE_HTMIX)) - { - TrainUp = (pCurrTxRate->TrainUp + (pCurrTxRate->TrainUp >> 1)); - TrainDown = (pCurrTxRate->TrainDown + (pCurrTxRate->TrainDown >> 1)); - } - else -#endif // DOT11_N_SUPPORT // - { - TrainUp = pCurrTxRate->TrainUp; - TrainDown = pCurrTxRate->TrainDown; - } - - //pAd->DrsCounters.LastTimeTxRateChangeAction = pAd->DrsCounters.LastSecTxRateChangeAction; - - // - // Keep the last time TxRateChangeAction status. - // - pEntry->LastTimeTxRateChangeAction = pEntry->LastSecTxRateChangeAction; - - - - // - // CASE 1. when TX samples are fewer than 15, then decide TX rate solely on RSSI - // (criteria copied from RT2500 for Netopia case) - // - if (TxTotalCnt <= 15) - { - CHAR idx = 0; - UCHAR TxRateIdx; - //UCHAR MCS0 = 0, MCS1 = 0, MCS2 = 0, MCS3 = 0, MCS4 = 0, MCS7 = 0, MCS12 = 0, MCS13 = 0, MCS14 = 0, MCS15 = 0; - UCHAR MCS0 = 0, MCS1 = 0, MCS2 = 0, MCS3 = 0, MCS4 = 0, MCS5 =0, MCS6 = 0, MCS7 = 0; - UCHAR MCS12 = 0, MCS13 = 0, MCS14 = 0, MCS15 = 0; - UCHAR MCS20 = 0, MCS21 = 0, MCS22 = 0, MCS23 = 0; // 3*3 - - // check the existence and index of each needed MCS - while (idx < pTable[0]) - { - pCurrTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(idx+1)*5]; - - if (pCurrTxRate->CurrMCS == MCS_0) - { - MCS0 = idx; - } - else if (pCurrTxRate->CurrMCS == MCS_1) - { - MCS1 = idx; - } - else if (pCurrTxRate->CurrMCS == MCS_2) - { - MCS2 = idx; - } - else if (pCurrTxRate->CurrMCS == MCS_3) - { - MCS3 = idx; - } - else if (pCurrTxRate->CurrMCS == MCS_4) - { - MCS4 = idx; - } - else if (pCurrTxRate->CurrMCS == MCS_5) - { - MCS5 = idx; - } - else if (pCurrTxRate->CurrMCS == MCS_6) - { - MCS6 = idx; - } - //else if (pCurrTxRate->CurrMCS == MCS_7) - else if ((pCurrTxRate->CurrMCS == MCS_7) && (pCurrTxRate->ShortGI == GI_800)) // prevent the highest MCS using short GI when 1T and low throughput - { - MCS7 = idx; - } - else if (pCurrTxRate->CurrMCS == MCS_12) - { - MCS12 = idx; - } - else if (pCurrTxRate->CurrMCS == MCS_13) - { - MCS13 = idx; - } - else if (pCurrTxRate->CurrMCS == MCS_14) - { - MCS14 = idx; - } - //else if ((pCurrTxRate->CurrMCS == MCS_15)/* && (pCurrTxRate->ShortGI == GI_800)*/) //we hope to use ShortGI as initial rate - else if ((pCurrTxRate->CurrMCS == MCS_15) && (pCurrTxRate->ShortGI == GI_800)) //we hope to use ShortGI as initial rate, however Atheros's chip has bugs when short GI - { - MCS15 = idx; - } - else if (pCurrTxRate->CurrMCS == MCS_20) // 3*3 - { - MCS20 = idx; - } - else if (pCurrTxRate->CurrMCS == MCS_21) - { - MCS21 = idx; - } - else if (pCurrTxRate->CurrMCS == MCS_22) - { - MCS22 = idx; - } - else if (pCurrTxRate->CurrMCS == MCS_23) - { - MCS23 = idx; - } - idx ++; - } - - if (pAd->LatchRfRegs.Channel <= 14) - { - if (pAd->NicConfig2.field.ExternalLNAForG) - { - RssiOffset = 2; - } - else - { - RssiOffset = 5; - } - } - else - { - if (pAd->NicConfig2.field.ExternalLNAForA) - { - RssiOffset = 5; - } - else - { - RssiOffset = 8; - } - } -#ifdef DOT11_N_SUPPORT - /*if (MCS15)*/ - if ((pTable == RateSwitchTable11BGN3S) || - (pTable == RateSwitchTable11N3S) || - (pTable == RateSwitchTable)) - {// N mode with 3 stream // 3*3 - if (MCS23 && (Rssi >= -70)) - TxRateIdx = MCS15; - else if (MCS22 && (Rssi >= -72)) - TxRateIdx = MCS14; - else if (MCS21 && (Rssi >= -76)) - TxRateIdx = MCS13; - else if (MCS20 && (Rssi >= -78)) - TxRateIdx = MCS12; - else if (MCS4 && (Rssi >= -82)) - TxRateIdx = MCS4; - else if (MCS3 && (Rssi >= -84)) - TxRateIdx = MCS3; - else if (MCS2 && (Rssi >= -86)) - TxRateIdx = MCS2; - else if (MCS1 && (Rssi >= -88)) - TxRateIdx = MCS1; - else - TxRateIdx = MCS0; - } -// else if ((pTable == RateSwitchTable11BGN2S) || (pTable == RateSwitchTable11BGN2SForABand) ||(pTable == RateSwitchTable11N2S) ||(pTable == RateSwitchTable11N2SForABand) || (pTable == RateSwitchTable)) - else if ((pTable == RateSwitchTable11BGN2S) || (pTable == RateSwitchTable11BGN2SForABand) ||(pTable == RateSwitchTable11N2S) ||(pTable == RateSwitchTable11N2SForABand)) // 3*3 - {// N mode with 2 stream - if (MCS15 && (Rssi >= (-70+RssiOffset))) - TxRateIdx = MCS15; - else if (MCS14 && (Rssi >= (-72+RssiOffset))) - TxRateIdx = MCS14; - else if (MCS13 && (Rssi >= (-76+RssiOffset))) - TxRateIdx = MCS13; - else if (MCS12 && (Rssi >= (-78+RssiOffset))) - TxRateIdx = MCS12; - else if (MCS4 && (Rssi >= (-82+RssiOffset))) - TxRateIdx = MCS4; - else if (MCS3 && (Rssi >= (-84+RssiOffset))) - TxRateIdx = MCS3; - else if (MCS2 && (Rssi >= (-86+RssiOffset))) - TxRateIdx = MCS2; - else if (MCS1 && (Rssi >= (-88+RssiOffset))) - TxRateIdx = MCS1; - else - TxRateIdx = MCS0; - } - else if ((pTable == RateSwitchTable11BGN1S) || (pTable == RateSwitchTable11N1S)) - {// N mode with 1 stream - if (MCS7 && (Rssi > (-72+RssiOffset))) - TxRateIdx = MCS7; - else if (MCS6 && (Rssi > (-74+RssiOffset))) - TxRateIdx = MCS6; - else if (MCS5 && (Rssi > (-77+RssiOffset))) - TxRateIdx = MCS5; - else if (MCS4 && (Rssi > (-79+RssiOffset))) - TxRateIdx = MCS4; - else if (MCS3 && (Rssi > (-81+RssiOffset))) - TxRateIdx = MCS3; - else if (MCS2 && (Rssi > (-83+RssiOffset))) - TxRateIdx = MCS2; - else if (MCS1 && (Rssi > (-86+RssiOffset))) - TxRateIdx = MCS1; - else - TxRateIdx = MCS0; - } - else -#endif // DOT11_N_SUPPORT // - {// Legacy mode - if (MCS7 && (Rssi > -70)) - TxRateIdx = MCS7; - else if (MCS6 && (Rssi > -74)) - TxRateIdx = MCS6; - else if (MCS5 && (Rssi > -78)) - TxRateIdx = MCS5; - else if (MCS4 && (Rssi > -82)) - TxRateIdx = MCS4; - else if (MCS4 == 0) // for B-only mode - TxRateIdx = MCS3; - else if (MCS3 && (Rssi > -85)) - TxRateIdx = MCS3; - else if (MCS2 && (Rssi > -87)) - TxRateIdx = MCS2; - else if (MCS1 && (Rssi > -90)) - TxRateIdx = MCS1; - else - TxRateIdx = MCS0; - } - - // if (TxRateIdx != pAd->CommonCfg.TxRateIndex) - { - pEntry->CurrTxRateIndex = TxRateIdx; - pNextTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(pEntry->CurrTxRateIndex+1)*5]; - MlmeSetTxRate(pAd, pEntry, pNextTxRate); - } - - NdisZeroMemory(pEntry->TxQuality, sizeof(USHORT) * MAX_STEP_OF_TX_RATE_SWITCH); - NdisZeroMemory(pEntry->PER, sizeof(UCHAR) * MAX_STEP_OF_TX_RATE_SWITCH); - pEntry->fLastSecAccordingRSSI = TRUE; - // reset all OneSecTx counters - RESET_ONE_SEC_TX_CNT(pEntry); - - continue; - } - - if (pEntry->fLastSecAccordingRSSI == TRUE) - { - pEntry->fLastSecAccordingRSSI = FALSE; - pEntry->LastSecTxRateChangeAction = 0; - // reset all OneSecTx counters - RESET_ONE_SEC_TX_CNT(pEntry); - - continue; - } - - do - { - BOOLEAN bTrainUpDown = FALSE; - - pEntry->CurrTxRateStableTime ++; - - // downgrade TX quality if PER >= Rate-Down threshold - if (TxErrorRatio >= TrainDown) - { - bTrainUpDown = TRUE; - pEntry->TxQuality[CurrRateIdx] = DRS_TX_QUALITY_WORST_BOUND; - } - // upgrade TX quality if PER <= Rate-Up threshold - else if (TxErrorRatio <= TrainUp) - { - bTrainUpDown = TRUE; - bUpgradeQuality = TRUE; - if (pEntry->TxQuality[CurrRateIdx]) - pEntry->TxQuality[CurrRateIdx] --; // quality very good in CurrRate - - if (pEntry->TxRateUpPenalty) - pEntry->TxRateUpPenalty --; - else if (pEntry->TxQuality[UpRateIdx]) - pEntry->TxQuality[UpRateIdx] --; // may improve next UP rate's quality - } - - pEntry->PER[CurrRateIdx] = (UCHAR)TxErrorRatio; - - if (bTrainUpDown) - { - // perform DRS - consider TxRate Down first, then rate up. - if ((CurrRateIdx != DownRateIdx) && (pEntry->TxQuality[CurrRateIdx] >= DRS_TX_QUALITY_WORST_BOUND)) - { - pEntry->CurrTxRateIndex = DownRateIdx; - } - else if ((CurrRateIdx != UpRateIdx) && (pEntry->TxQuality[UpRateIdx] <= 0)) - { - pEntry->CurrTxRateIndex = UpRateIdx; - } - } - } while (FALSE); - - // if rate-up happen, clear all bad history of all TX rates - if (pEntry->CurrTxRateIndex > CurrRateIdx) - { - pEntry->CurrTxRateStableTime = 0; - pEntry->TxRateUpPenalty = 0; - pEntry->LastSecTxRateChangeAction = 1; // rate UP - NdisZeroMemory(pEntry->TxQuality, sizeof(USHORT) * MAX_STEP_OF_TX_RATE_SWITCH); - NdisZeroMemory(pEntry->PER, sizeof(UCHAR) * MAX_STEP_OF_TX_RATE_SWITCH); - - // - // For TxRate fast train up - // - if (!pAd->StaCfg.StaQuickResponeForRateUpTimerRunning) - { - RTMPSetTimer(&pAd->StaCfg.StaQuickResponeForRateUpTimer, 100); - - pAd->StaCfg.StaQuickResponeForRateUpTimerRunning = TRUE; - } - bTxRateChanged = TRUE; - } - // if rate-down happen, only clear DownRate's bad history - else if (pEntry->CurrTxRateIndex < CurrRateIdx) - { - pEntry->CurrTxRateStableTime = 0; - pEntry->TxRateUpPenalty = 0; // no penalty - pEntry->LastSecTxRateChangeAction = 2; // rate DOWN - pEntry->TxQuality[pEntry->CurrTxRateIndex] = 0; - pEntry->PER[pEntry->CurrTxRateIndex] = 0; - - // - // For TxRate fast train down - // - if (!pAd->StaCfg.StaQuickResponeForRateUpTimerRunning) - { - RTMPSetTimer(&pAd->StaCfg.StaQuickResponeForRateUpTimer, 100); - - pAd->StaCfg.StaQuickResponeForRateUpTimerRunning = TRUE; - } - bTxRateChanged = TRUE; - } - else - { - pEntry->LastSecTxRateChangeAction = 0; // rate no change - bTxRateChanged = FALSE; - } - - pEntry->LastTxOkCount = TxSuccess; - - // reset all OneSecTx counters - RESET_ONE_SEC_TX_CNT(pEntry); - - pNextTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(pEntry->CurrTxRateIndex+1)*5]; - if (bTxRateChanged && pNextTxRate) - { - MlmeSetTxRate(pAd, pEntry, pNextTxRate); - } - } -} - -/* - ======================================================================== - Routine Description: - Station side, Auto TxRate faster train up timer call back function. - - Arguments: - SystemSpecific1 - Not used. - FunctionContext - Pointer to our Adapter context. - SystemSpecific2 - Not used. - SystemSpecific3 - Not used. - - Return Value: - None - - ======================================================================== -*/ -VOID StaQuickResponeForRateUpExec( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3) -{ - PRTMP_ADAPTER pAd = (PRTMP_ADAPTER)FunctionContext; - UCHAR UpRateIdx = 0, DownRateIdx = 0, CurrRateIdx = 0; - ULONG TxTotalCnt; - ULONG TxErrorRatio = 0; - BOOLEAN bTxRateChanged; //, bUpgradeQuality = FALSE; - PRTMP_TX_RATE_SWITCH pCurrTxRate, pNextTxRate = NULL; - PUCHAR pTable; - UCHAR TableSize = 0; - UCHAR InitTxRateIdx = 0, TrainUp, TrainDown; - TX_STA_CNT1_STRUC StaTx1; - TX_STA_CNT0_STRUC TxStaCnt0; - CHAR Rssi, ratio; - ULONG TxRetransmit = 0, TxSuccess = 0, TxFailCount = 0; - MAC_TABLE_ENTRY *pEntry; - ULONG i; - - pAd->StaCfg.StaQuickResponeForRateUpTimerRunning = FALSE; - - // - // walk through MAC table, see if need to change AP's TX rate toward each entry - // - for (i = 1; i < MAX_LEN_OF_MAC_TABLE; i++) - { - pEntry = &pAd->MacTab.Content[i]; - - // check if this entry need to switch rate automatically - if (RTMPCheckEntryEnableAutoRateSwitch(pAd, pEntry) == FALSE) - continue; - - if (INFRA_ON(pAd) && (i == 1)) - Rssi = RTMPMaxRssi(pAd, - pAd->StaCfg.RssiSample.AvgRssi0, - pAd->StaCfg.RssiSample.AvgRssi1, - pAd->StaCfg.RssiSample.AvgRssi2); - else - Rssi = RTMPMaxRssi(pAd, - pEntry->RssiSample.AvgRssi0, - pEntry->RssiSample.AvgRssi1, - pEntry->RssiSample.AvgRssi2); - - CurrRateIdx = pAd->CommonCfg.TxRateIndex; - - MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize, &InitTxRateIdx); - - // decide the next upgrade rate and downgrade rate, if any - if ((CurrRateIdx > 0) && (CurrRateIdx < (TableSize - 1))) - { - UpRateIdx = CurrRateIdx + 1; - DownRateIdx = CurrRateIdx -1; - } - else if (CurrRateIdx == 0) - { - UpRateIdx = CurrRateIdx + 1; - DownRateIdx = CurrRateIdx; - } - else if (CurrRateIdx == (TableSize - 1)) - { - UpRateIdx = CurrRateIdx; - DownRateIdx = CurrRateIdx - 1; - } - - pCurrTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(CurrRateIdx+1)*5]; - -#ifdef DOT11_N_SUPPORT - if ((Rssi > -65) && (pCurrTxRate->Mode >= MODE_HTMIX)) - { - TrainUp = (pCurrTxRate->TrainUp + (pCurrTxRate->TrainUp >> 1)); - TrainDown = (pCurrTxRate->TrainDown + (pCurrTxRate->TrainDown >> 1)); - } - else -#endif // DOT11_N_SUPPORT // - { - TrainUp = pCurrTxRate->TrainUp; - TrainDown = pCurrTxRate->TrainDown; - } - - if (pAd->MacTab.Size == 1) - { - // Update statistic counter - RTMP_IO_READ32(pAd, TX_STA_CNT0, &TxStaCnt0.word); - RTMP_IO_READ32(pAd, TX_STA_CNT1, &StaTx1.word); - - TxRetransmit = StaTx1.field.TxRetransmit; - TxSuccess = StaTx1.field.TxSuccess; - TxFailCount = TxStaCnt0.field.TxFailCount; - TxTotalCnt = TxRetransmit + TxSuccess + TxFailCount; - - pAd->RalinkCounters.OneSecTxRetryOkCount += StaTx1.field.TxRetransmit; - pAd->RalinkCounters.OneSecTxNoRetryOkCount += StaTx1.field.TxSuccess; - pAd->RalinkCounters.OneSecTxFailCount += TxStaCnt0.field.TxFailCount; - pAd->WlanCounters.TransmittedFragmentCount.u.LowPart += StaTx1.field.TxSuccess; - pAd->WlanCounters.RetryCount.u.LowPart += StaTx1.field.TxRetransmit; - pAd->WlanCounters.FailedCount.u.LowPart += TxStaCnt0.field.TxFailCount; - -#if 0 // test by Gary. - // if no traffic in the past 1-sec period, don't change TX rate, - // but clear all bad history. because the bad history may affect the next - // Chariot throughput test - TxTotalCnt = pAd->RalinkCounters.OneSecTxNoRetryOkCount + - pAd->RalinkCounters.OneSecTxRetryOkCount + - pAd->RalinkCounters.OneSecTxFailCount; -#endif - if (TxTotalCnt) - TxErrorRatio = ((TxRetransmit + TxFailCount) * 100) / TxTotalCnt; - } - else - { - TxTotalCnt = pEntry->OneSecTxNoRetryOkCount + - pEntry->OneSecTxRetryOkCount + - pEntry->OneSecTxFailCount; - - if (TxTotalCnt) - TxErrorRatio = ((pEntry->OneSecTxRetryOkCount + pEntry->OneSecTxFailCount) * 100) / TxTotalCnt; - } - - - // - // CASE 1. when TX samples are fewer than 15, then decide TX rate solely on RSSI - // (criteria copied from RT2500 for Netopia case) - // - if (TxTotalCnt <= 12) - { - NdisZeroMemory(pAd->DrsCounters.TxQuality, sizeof(USHORT) * MAX_STEP_OF_TX_RATE_SWITCH); - NdisZeroMemory(pAd->DrsCounters.PER, sizeof(UCHAR) * MAX_STEP_OF_TX_RATE_SWITCH); - - if ((pAd->DrsCounters.LastSecTxRateChangeAction == 1) && (CurrRateIdx != DownRateIdx)) - { - pAd->CommonCfg.TxRateIndex = DownRateIdx; - pAd->DrsCounters.TxQuality[CurrRateIdx] = DRS_TX_QUALITY_WORST_BOUND; - } - else if ((pAd->DrsCounters.LastSecTxRateChangeAction == 2) && (CurrRateIdx != UpRateIdx)) - { - pAd->CommonCfg.TxRateIndex = UpRateIdx; - } - - DBGPRINT_RAW(RT_DEBUG_TRACE,("QuickDRS: TxTotalCnt <= 15, train back to original rate \n")); - return; - } - - do - { - ULONG OneSecTxNoRetryOKRationCount; - - if (pAd->DrsCounters.LastTimeTxRateChangeAction == 0) - ratio = 5; - else - ratio = 4; - - // downgrade TX quality if PER >= Rate-Down threshold - if (TxErrorRatio >= TrainDown) - { - pAd->DrsCounters.TxQuality[CurrRateIdx] = DRS_TX_QUALITY_WORST_BOUND; - } - - pAd->DrsCounters.PER[CurrRateIdx] = (UCHAR)TxErrorRatio; - - OneSecTxNoRetryOKRationCount = (TxSuccess * ratio); - - // perform DRS - consider TxRate Down first, then rate up. - if ((pAd->DrsCounters.LastSecTxRateChangeAction == 1) && (CurrRateIdx != DownRateIdx)) - { - if ((pAd->DrsCounters.LastTxOkCount + 2) >= OneSecTxNoRetryOKRationCount) - { - pAd->CommonCfg.TxRateIndex = DownRateIdx; - pAd->DrsCounters.TxQuality[CurrRateIdx] = DRS_TX_QUALITY_WORST_BOUND; - - } - - } - else if ((pAd->DrsCounters.LastSecTxRateChangeAction == 2) && (CurrRateIdx != UpRateIdx)) - { - if ((TxErrorRatio >= 50) || (TxErrorRatio >= TrainDown)) - { - - } - else if ((pAd->DrsCounters.LastTxOkCount + 2) >= OneSecTxNoRetryOKRationCount) - { - pAd->CommonCfg.TxRateIndex = UpRateIdx; - } - } - }while (FALSE); - - // if rate-up happen, clear all bad history of all TX rates - if (pAd->CommonCfg.TxRateIndex > CurrRateIdx) - { - pAd->DrsCounters.TxRateUpPenalty = 0; - NdisZeroMemory(pAd->DrsCounters.TxQuality, sizeof(USHORT) * MAX_STEP_OF_TX_RATE_SWITCH); - NdisZeroMemory(pAd->DrsCounters.PER, sizeof(UCHAR) * MAX_STEP_OF_TX_RATE_SWITCH); - bTxRateChanged = TRUE; - } - // if rate-down happen, only clear DownRate's bad history - else if (pAd->CommonCfg.TxRateIndex < CurrRateIdx) - { - DBGPRINT_RAW(RT_DEBUG_TRACE,("QuickDRS: --TX rate from %d to %d \n", CurrRateIdx, pAd->CommonCfg.TxRateIndex)); - - pAd->DrsCounters.TxRateUpPenalty = 0; // no penalty - pAd->DrsCounters.TxQuality[pAd->CommonCfg.TxRateIndex] = 0; - pAd->DrsCounters.PER[pAd->CommonCfg.TxRateIndex] = 0; - bTxRateChanged = TRUE; - } - else - { - bTxRateChanged = FALSE; - } - - pNextTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(pAd->CommonCfg.TxRateIndex+1)*5]; - if (bTxRateChanged && pNextTxRate) - { - MlmeSetTxRate(pAd, pEntry, pNextTxRate); - } - } -} - -/* - ========================================================================== - Description: - This routine is executed periodically inside MlmePeriodicExec() after - association with an AP. - It checks if StaCfg.Psm is consistent with user policy (recorded in - StaCfg.WindowsPowerMode). If not, enforce user policy. However, - there're some conditions to consider: - 1. we don't support power-saving in ADHOC mode, so Psm=PWR_ACTIVE all - the time when Mibss==TRUE - 2. When link up in INFRA mode, Psm should not be switch to PWR_SAVE - if outgoing traffic available in TxRing or MgmtRing. - Output: - 1. change pAd->StaCfg.Psm to PWR_SAVE or leave it untouched - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID MlmeCheckPsmChange( - IN PRTMP_ADAPTER pAd, - IN ULONG Now32) -{ - ULONG PowerMode; - - // condition - - // 1. Psm maybe ON only happen in INFRASTRUCTURE mode - // 2. user wants either MAX_PSP or FAST_PSP - // 3. but current psm is not in PWR_SAVE - // 4. CNTL state machine is not doing SCANning - // 5. no TX SUCCESS event for the past 1-sec period -#ifdef NDIS51_MINIPORT - if (pAd->StaCfg.WindowsPowerProfile == NdisPowerProfileBattery) - PowerMode = pAd->StaCfg.WindowsBatteryPowerMode; - else -#endif - PowerMode = pAd->StaCfg.WindowsPowerMode; - - if (INFRA_ON(pAd) && - (PowerMode != Ndis802_11PowerModeCAM) && - (pAd->StaCfg.Psm == PWR_ACTIVE) && -// (! RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) - (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) /*&& - (pAd->RalinkCounters.OneSecTxNoRetryOkCount == 0) && - (pAd->RalinkCounters.OneSecTxRetryOkCount == 0)*/) - { - NdisGetSystemUpTime(&pAd->Mlme.LastSendNULLpsmTime); - pAd->RalinkCounters.RxCountSinceLastNULL = 0; - MlmeSetPsmBit(pAd, PWR_SAVE); - if (!(pAd->CommonCfg.bAPSDCapable && pAd->CommonCfg.APEdcaParm.bAPSDCapable)) - { - RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, FALSE); - } - else - { - RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, TRUE); - } - } -} - -// IRQL = PASSIVE_LEVEL -// IRQL = DISPATCH_LEVEL -VOID MlmeSetPsmBit( - IN PRTMP_ADAPTER pAd, - IN USHORT psm) -{ - AUTO_RSP_CFG_STRUC csr4; - - pAd->StaCfg.Psm = psm; - RTMP_IO_READ32(pAd, AUTO_RSP_CFG, &csr4.word); - csr4.field.AckCtsPsmBit = (psm == PWR_SAVE)? 1:0; - RTMP_IO_WRITE32(pAd, AUTO_RSP_CFG, csr4.word); - DBGPRINT(RT_DEBUG_TRACE, ("MlmeSetPsmBit = %d\n", psm)); -} -#endif // CONFIG_STA_SUPPORT // - - -// IRQL = DISPATCH_LEVEL -VOID MlmeSetTxPreamble( - IN PRTMP_ADAPTER pAd, - IN USHORT TxPreamble) -{ - AUTO_RSP_CFG_STRUC csr4; - - // - // Always use Long preamble before verifiation short preamble functionality works well. - // Todo: remove the following line if short preamble functionality works - // - //TxPreamble = Rt802_11PreambleLong; - - RTMP_IO_READ32(pAd, AUTO_RSP_CFG, &csr4.word); - if (TxPreamble == Rt802_11PreambleLong) - { - DBGPRINT(RT_DEBUG_TRACE, ("MlmeSetTxPreamble (= LONG PREAMBLE)\n")); - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED); - csr4.field.AutoResponderPreamble = 0; - } - else - { - // NOTE: 1Mbps should always use long preamble - DBGPRINT(RT_DEBUG_TRACE, ("MlmeSetTxPreamble (= SHORT PREAMBLE)\n")); - OPSTATUS_SET_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED); - csr4.field.AutoResponderPreamble = 1; - } - - RTMP_IO_WRITE32(pAd, AUTO_RSP_CFG, csr4.word); -} - -/* - ========================================================================== - Description: - Update basic rate bitmap - ========================================================================== - */ - -VOID UpdateBasicRateBitmap( - IN PRTMP_ADAPTER pAdapter) -{ - INT i, j; - /* 1 2 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54 */ - UCHAR rate[] = { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 }; - UCHAR *sup_p = pAdapter->CommonCfg.SupRate; - UCHAR *ext_p = pAdapter->CommonCfg.ExtRate; - ULONG bitmap = pAdapter->CommonCfg.BasicRateBitmap; - - - /* if A mode, always use fix BasicRateBitMap */ - //if (pAdapter->CommonCfg.Channel == PHY_11A) - if (pAdapter->CommonCfg.Channel > 14) - pAdapter->CommonCfg.BasicRateBitmap = 0x150; /* 6, 12, 24M */ - /* End of if */ - - if (pAdapter->CommonCfg.BasicRateBitmap > 4095) - { - /* (2 ^ MAX_LEN_OF_SUPPORTED_RATES) -1 */ - return; - } /* End of if */ - - for(i=0; iCommonCfg.DesireRate[i] & 0x7f) - { - case 2: Rate = RATE_1; num++; break; - case 4: Rate = RATE_2; num++; break; - case 11: Rate = RATE_5_5; num++; break; - case 22: Rate = RATE_11; num++; break; - case 12: Rate = RATE_6; num++; break; - case 18: Rate = RATE_9; num++; break; - case 24: Rate = RATE_12; num++; break; - case 36: Rate = RATE_18; num++; break; - case 48: Rate = RATE_24; num++; break; - case 72: Rate = RATE_36; num++; break; - case 96: Rate = RATE_48; num++; break; - case 108: Rate = RATE_54; num++; break; - //default: Rate = RATE_1; break; - } - if (MaxDesire < Rate) MaxDesire = Rate; - } - -//=========================================================================== -//=========================================================================== - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - pHtPhy = &pAd->StaCfg.HTPhyMode; - pMaxHtPhy = &pAd->StaCfg.MaxHTPhyMode; - pMinHtPhy = &pAd->StaCfg.MinHTPhyMode; - - auto_rate_cur_p = &pAd->StaCfg.bAutoTxRateSwitch; - HtMcs = pAd->StaCfg.DesiredTransmitSetting.field.MCS; - - if ((pAd->StaCfg.BssType == BSS_ADHOC) && - (pAd->CommonCfg.PhyMode == PHY_11B) && - (MaxDesire > RATE_11)) - { - MaxDesire = RATE_11; - } - } -#endif // CONFIG_STA_SUPPORT // - - pAd->CommonCfg.MaxDesiredRate = MaxDesire; - pMinHtPhy->word = 0; - pMaxHtPhy->word = 0; - pHtPhy->word = 0; - - // Auto rate switching is enabled only if more than one DESIRED RATES are - // specified; otherwise disabled - if (num <= 1) - { - //OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED); - //pAd->CommonCfg.bAutoTxRateSwitch = FALSE; - *auto_rate_cur_p = FALSE; - } - else - { - //OPSTATUS_SET_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED); - //pAd->CommonCfg.bAutoTxRateSwitch = TRUE; - *auto_rate_cur_p = TRUE; - } - -#if 1 - if (HtMcs != MCS_AUTO) - { - //OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED); - //pAd->CommonCfg.bAutoTxRateSwitch = FALSE; - *auto_rate_cur_p = FALSE; - } - else - { - //OPSTATUS_SET_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED); - //pAd->CommonCfg.bAutoTxRateSwitch = TRUE; - *auto_rate_cur_p = TRUE; - } -#endif - -#ifdef CONFIG_STA_SUPPORT - if ((ADHOC_ON(pAd) || INFRA_ON(pAd)) && (pAd->OpMode == OPMODE_STA)) - { - pSupRate = &pAd->StaActive.SupRate[0]; - pExtRate = &pAd->StaActive.ExtRate[0]; - SupRateLen = pAd->StaActive.SupRateLen; - ExtRateLen = pAd->StaActive.ExtRateLen; - } - else -#endif // CONFIG_STA_SUPPORT // - { - pSupRate = &pAd->CommonCfg.SupRate[0]; - pExtRate = &pAd->CommonCfg.ExtRate[0]; - SupRateLen = pAd->CommonCfg.SupRateLen; - ExtRateLen = pAd->CommonCfg.ExtRateLen; - } - - // find max supported rate - for (i=0; i Rate) MinSupport = Rate; - } - - for (i=0; i Rate) MinSupport = Rate; - } - - RTMP_IO_WRITE32(pAd, LEGACY_BASIC_RATE, BasicRateBitmap); - - // bug fix - // pAd->CommonCfg.BasicRateBitmap = BasicRateBitmap; - - // calculate the exptected ACK rate for each TX rate. This info is used to caculate - // the DURATION field of outgoing uniicast DATA/MGMT frame - for (i=0; iCommonCfg.ExpectedACKRate[i] = CurrBasicRate; - } - - DBGPRINT(RT_DEBUG_TRACE,("MlmeUpdateTxRates[MaxSupport = %d] = MaxDesire %d Mbps\n", RateIdToMbps[MaxSupport], RateIdToMbps[MaxDesire])); - // max tx rate = min {max desire rate, max supported rate} - if (MaxSupport < MaxDesire) - pAd->CommonCfg.MaxTxRate = MaxSupport; - else - pAd->CommonCfg.MaxTxRate = MaxDesire; - - pAd->CommonCfg.MinTxRate = MinSupport; - // 2003-07-31 john - 2500 doesn't have good sensitivity at high OFDM rates. to increase the success - // ratio of initial DHCP packet exchange, TX rate starts from a lower rate depending - // on average RSSI - // 1. RSSI >= -70db, start at 54 Mbps (short distance) - // 2. -70 > RSSI >= -75, start at 24 Mbps (mid distance) - // 3. -75 > RSSI, start at 11 Mbps (long distance) - //if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED)/* && - // OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)*/) - if (*auto_rate_cur_p) - { - short dbm = 0; -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - dbm = pAd->StaCfg.RssiSample.AvgRssi0 - pAd->BbpRssiToDbmDelta; -#endif // CONFIG_STA_SUPPORT // - if (bLinkUp == TRUE) - pAd->CommonCfg.TxRate = RATE_24; - else - pAd->CommonCfg.TxRate = pAd->CommonCfg.MaxTxRate; - - if (dbm < -75) - pAd->CommonCfg.TxRate = RATE_11; - else if (dbm < -70) - pAd->CommonCfg.TxRate = RATE_24; - - // should never exceed MaxTxRate (consider 11B-only mode) - if (pAd->CommonCfg.TxRate > pAd->CommonCfg.MaxTxRate) - pAd->CommonCfg.TxRate = pAd->CommonCfg.MaxTxRate; - - pAd->CommonCfg.TxRateIndex = 0; - } - else - { - pAd->CommonCfg.TxRate = pAd->CommonCfg.MaxTxRate; - pHtPhy->field.MCS = (pAd->CommonCfg.MaxTxRate > 3) ? (pAd->CommonCfg.MaxTxRate - 4) : pAd->CommonCfg.MaxTxRate; - pHtPhy->field.MODE = (pAd->CommonCfg.MaxTxRate > 3) ? MODE_OFDM : MODE_CCK; - - pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.STBC = pHtPhy->field.STBC; - pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.ShortGI = pHtPhy->field.ShortGI; - pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MCS = pHtPhy->field.MCS; - pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MODE = pHtPhy->field.MODE; - } - - if (pAd->CommonCfg.TxRate <= RATE_11) - { - pMaxHtPhy->field.MODE = MODE_CCK; - pMaxHtPhy->field.MCS = pAd->CommonCfg.TxRate; - pMinHtPhy->field.MCS = pAd->CommonCfg.MinTxRate; - } - else - { - pMaxHtPhy->field.MODE = MODE_OFDM; - pMaxHtPhy->field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.TxRate]; - if (pAd->CommonCfg.MinTxRate >= RATE_6 && (pAd->CommonCfg.MinTxRate <= RATE_54)) - {pMinHtPhy->field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MinTxRate];} - else - {pMinHtPhy->field.MCS = pAd->CommonCfg.MinTxRate;} - } - - pHtPhy->word = (pMaxHtPhy->word); - if (bLinkUp && (pAd->OpMode == OPMODE_STA)) - { - pAd->MacTab.Content[BSSID_WCID].HTPhyMode.word = pHtPhy->word; - pAd->MacTab.Content[BSSID_WCID].MaxHTPhyMode.word = pMaxHtPhy->word; - pAd->MacTab.Content[BSSID_WCID].MinHTPhyMode.word = pMinHtPhy->word; - } - else - { - switch (pAd->CommonCfg.PhyMode) - { - case PHY_11BG_MIXED: - case PHY_11B: -#ifdef DOT11_N_SUPPORT - case PHY_11BGN_MIXED: -#endif // DOT11_N_SUPPORT // - pAd->CommonCfg.MlmeRate = RATE_1; - pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_CCK; - pAd->CommonCfg.MlmeTransmit.field.MCS = RATE_1; - -//#ifdef WIFI_TEST - pAd->CommonCfg.RtsRate = RATE_11; -//#else -// pAd->CommonCfg.RtsRate = RATE_1; -//#endif - break; - case PHY_11G: - case PHY_11A: -#ifdef DOT11_N_SUPPORT - case PHY_11AGN_MIXED: - case PHY_11GN_MIXED: - case PHY_11N_2_4G: - case PHY_11AN_MIXED: - case PHY_11N_5G: -#endif // DOT11_N_SUPPORT // - pAd->CommonCfg.MlmeRate = RATE_6; - pAd->CommonCfg.RtsRate = RATE_6; - pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM; - pAd->CommonCfg.MlmeTransmit.field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate]; - break; - case PHY_11ABG_MIXED: -#ifdef DOT11_N_SUPPORT - case PHY_11ABGN_MIXED: -#endif // DOT11_N_SUPPORT // - if (pAd->CommonCfg.Channel <= 14) - { - pAd->CommonCfg.MlmeRate = RATE_1; - pAd->CommonCfg.RtsRate = RATE_1; - pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_CCK; - pAd->CommonCfg.MlmeTransmit.field.MCS = RATE_1; - } - else - { - pAd->CommonCfg.MlmeRate = RATE_6; - pAd->CommonCfg.RtsRate = RATE_6; - pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM; - pAd->CommonCfg.MlmeTransmit.field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate]; - } - break; - default: // error - pAd->CommonCfg.MlmeRate = RATE_6; - pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM; - pAd->CommonCfg.MlmeTransmit.field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate]; - pAd->CommonCfg.RtsRate = RATE_1; - break; - } - // - // Keep Basic Mlme Rate. - // - pAd->MacTab.Content[MCAST_WCID].HTPhyMode.word = pAd->CommonCfg.MlmeTransmit.word; - if (pAd->CommonCfg.MlmeTransmit.field.MODE == MODE_OFDM) - pAd->MacTab.Content[MCAST_WCID].HTPhyMode.field.MCS = OfdmRateToRxwiMCS[RATE_24]; - else - pAd->MacTab.Content[MCAST_WCID].HTPhyMode.field.MCS = RATE_1; - pAd->CommonCfg.BasicMlmeRate = pAd->CommonCfg.MlmeRate; - } - - DBGPRINT(RT_DEBUG_TRACE, (" MlmeUpdateTxRates (MaxDesire=%d, MaxSupport=%d, MaxTxRate=%d, MinRate=%d, Rate Switching =%d)\n", - RateIdToMbps[MaxDesire], RateIdToMbps[MaxSupport], RateIdToMbps[pAd->CommonCfg.MaxTxRate], RateIdToMbps[pAd->CommonCfg.MinTxRate], - /*OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED)*/*auto_rate_cur_p)); - DBGPRINT(RT_DEBUG_TRACE, (" MlmeUpdateTxRates (TxRate=%d, RtsRate=%d, BasicRateBitmap=0x%04lx)\n", - RateIdToMbps[pAd->CommonCfg.TxRate], RateIdToMbps[pAd->CommonCfg.RtsRate], BasicRateBitmap)); - DBGPRINT(RT_DEBUG_TRACE, ("MlmeUpdateTxRates (MlmeTransmit=0x%x, MinHTPhyMode=%x, MaxHTPhyMode=0x%x, HTPhyMode=0x%x)\n", - pAd->CommonCfg.MlmeTransmit.word, pAd->MacTab.Content[BSSID_WCID].MinHTPhyMode.word ,pAd->MacTab.Content[BSSID_WCID].MaxHTPhyMode.word ,pAd->MacTab.Content[BSSID_WCID].HTPhyMode.word )); -} - -#ifdef DOT11_N_SUPPORT -/* - ========================================================================== - Description: - This function update HT Rate setting. - Input Wcid value is valid for 2 case : - 1. it's used for Station in infra mode that copy AP rate to Mactable. - 2. OR Station in adhoc mode to copy peer's HT rate to Mactable. - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID MlmeUpdateHtTxRates( - IN PRTMP_ADAPTER pAd, - IN UCHAR apidx) -{ - UCHAR StbcMcs; //j, StbcMcs, bitmask; - CHAR i; // 3*3 - RT_HT_CAPABILITY *pRtHtCap = NULL; - RT_HT_PHY_INFO *pActiveHtPhy = NULL; - ULONG BasicMCS; - UCHAR j, bitmask; - PRT_HT_PHY_INFO pDesireHtPhy = NULL; - PHTTRANSMIT_SETTING pHtPhy = NULL; - PHTTRANSMIT_SETTING pMaxHtPhy = NULL; - PHTTRANSMIT_SETTING pMinHtPhy = NULL; - BOOLEAN *auto_rate_cur_p; - - DBGPRINT(RT_DEBUG_TRACE,("MlmeUpdateHtTxRates===> \n")); - - auto_rate_cur_p = NULL; - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - pDesireHtPhy = &pAd->StaCfg.DesiredHtPhyInfo; - pActiveHtPhy = &pAd->StaCfg.DesiredHtPhyInfo; - pHtPhy = &pAd->StaCfg.HTPhyMode; - pMaxHtPhy = &pAd->StaCfg.MaxHTPhyMode; - pMinHtPhy = &pAd->StaCfg.MinHTPhyMode; - - auto_rate_cur_p = &pAd->StaCfg.bAutoTxRateSwitch; - } -#endif // CONFIG_STA_SUPPORT // - -#ifdef CONFIG_STA_SUPPORT - if ((ADHOC_ON(pAd) || INFRA_ON(pAd)) && (pAd->OpMode == OPMODE_STA)) - { - if (pAd->StaActive.SupportedPhyInfo.bHtEnable == FALSE) - return; - - pRtHtCap = &pAd->StaActive.SupportedHtPhy; - pActiveHtPhy = &pAd->StaActive.SupportedPhyInfo; - StbcMcs = (UCHAR)pAd->MlmeAux.AddHtInfo.AddHtInfo3.StbcMcs; - BasicMCS =pAd->MlmeAux.AddHtInfo.MCSSet[0]+(pAd->MlmeAux.AddHtInfo.MCSSet[1]<<8)+(StbcMcs<<16); - if ((pAd->CommonCfg.DesiredHtPhy.TxSTBC) && (pRtHtCap->RxSTBC) && (pAd->Antenna.field.TxPath == 2)) - pMaxHtPhy->field.STBC = STBC_USE; - else - pMaxHtPhy->field.STBC = STBC_NONE; - } - else -#endif // CONFIG_STA_SUPPORT // - { - if (pDesireHtPhy->bHtEnable == FALSE) - return; - - pRtHtCap = &pAd->CommonCfg.DesiredHtPhy; - StbcMcs = (UCHAR)pAd->CommonCfg.AddHTInfo.AddHtInfo3.StbcMcs; - BasicMCS = pAd->CommonCfg.AddHTInfo.MCSSet[0]+(pAd->CommonCfg.AddHTInfo.MCSSet[1]<<8)+(StbcMcs<<16); - if ((pAd->CommonCfg.DesiredHtPhy.TxSTBC) && (pRtHtCap->RxSTBC) && (pAd->Antenna.field.TxPath == 2)) - pMaxHtPhy->field.STBC = STBC_USE; - else - pMaxHtPhy->field.STBC = STBC_NONE; - } - - // Decide MAX ht rate. - if ((pRtHtCap->GF) && (pAd->CommonCfg.DesiredHtPhy.GF)) - pMaxHtPhy->field.MODE = MODE_HTGREENFIELD; - else - pMaxHtPhy->field.MODE = MODE_HTMIX; - - if ((pAd->CommonCfg.DesiredHtPhy.ChannelWidth) && (pRtHtCap->ChannelWidth)) - pMaxHtPhy->field.BW = BW_40; - else - pMaxHtPhy->field.BW = BW_20; - - if (pMaxHtPhy->field.BW == BW_20) - pMaxHtPhy->field.ShortGI = (pAd->CommonCfg.DesiredHtPhy.ShortGIfor20 & pRtHtCap->ShortGIfor20); - else - pMaxHtPhy->field.ShortGI = (pAd->CommonCfg.DesiredHtPhy.ShortGIfor40 & pRtHtCap->ShortGIfor40); - - for (i=23; i>=0; i--) // 3*3 - { - j = i/8; - bitmask = (1<<(i-(j*8))); - - if ((pActiveHtPhy->MCSSet[j] & bitmask) && (pDesireHtPhy->MCSSet[j] & bitmask)) - { - pMaxHtPhy->field.MCS = i; - break; - } - - if (i==0) - break; - } - - // Copy MIN ht rate. rt2860??? - pMinHtPhy->field.BW = BW_20; - pMinHtPhy->field.MCS = 0; - pMinHtPhy->field.STBC = 0; - pMinHtPhy->field.ShortGI = 0; - //If STA assigns fixed rate. update to fixed here. -#ifdef CONFIG_STA_SUPPORT - if ( (pAd->OpMode == OPMODE_STA) && (pDesireHtPhy->MCSSet[0] != 0xff)) - { - if (pDesireHtPhy->MCSSet[4] != 0) - { - pMaxHtPhy->field.MCS = 32; - pMinHtPhy->field.MCS = 32; - DBGPRINT(RT_DEBUG_TRACE,("MlmeUpdateHtTxRates<=== Use Fixed MCS = %d\n",pMinHtPhy->field.MCS)); - } - - for (i=23; (CHAR)i >= 0; i--) // 3*3 - { - j = i/8; - bitmask = (1<<(i-(j*8))); - if ( (pDesireHtPhy->MCSSet[j] & bitmask) && (pActiveHtPhy->MCSSet[j] & bitmask)) - { - pMaxHtPhy->field.MCS = i; - pMinHtPhy->field.MCS = i; - break; - } - if (i==0) - break; - } - } -#endif // CONFIG_STA_SUPPORT // - - - // Decide ht rate - pHtPhy->field.STBC = pMaxHtPhy->field.STBC; - pHtPhy->field.BW = pMaxHtPhy->field.BW; - pHtPhy->field.MODE = pMaxHtPhy->field.MODE; - pHtPhy->field.MCS = pMaxHtPhy->field.MCS; - pHtPhy->field.ShortGI = pMaxHtPhy->field.ShortGI; - - // use default now. rt2860 - if (pDesireHtPhy->MCSSet[0] != 0xff) - *auto_rate_cur_p = FALSE; - else - *auto_rate_cur_p = TRUE; - - DBGPRINT(RT_DEBUG_TRACE, (" MlmeUpdateHtTxRates<---.AMsduSize = %d \n", pAd->CommonCfg.DesiredHtPhy.AmsduSize )); - DBGPRINT(RT_DEBUG_TRACE,("TX: MCS[0] = %x (choose %d), BW = %d, ShortGI = %d, MODE = %d, \n", pActiveHtPhy->MCSSet[0],pHtPhy->field.MCS, - pHtPhy->field.BW, pHtPhy->field.ShortGI, pHtPhy->field.MODE)); - DBGPRINT(RT_DEBUG_TRACE,("MlmeUpdateHtTxRates<=== \n")); -} -#endif // DOT11_N_SUPPORT // - -// IRQL = DISPATCH_LEVEL -VOID MlmeRadioOff( - IN PRTMP_ADAPTER pAd) -{ - RT28XX_MLME_RADIO_OFF(pAd); -} - -// IRQL = DISPATCH_LEVEL -VOID MlmeRadioOn( - IN PRTMP_ADAPTER pAd) -{ - RT28XX_MLME_RADIO_ON(pAd); -} - -// =========================================================================================== -// bss_table.c -// =========================================================================================== - - -/*! \brief initialize BSS table - * \param p_tab pointer to the table - * \return none - * \pre - * \post - - IRQL = PASSIVE_LEVEL - IRQL = DISPATCH_LEVEL - - */ -VOID BssTableInit( - IN BSS_TABLE *Tab) -{ - int i; - - Tab->BssNr = 0; - Tab->BssOverlapNr = 0; - for (i = 0; i < MAX_LEN_OF_BSS_TABLE; i++) - { - NdisZeroMemory(&Tab->BssEntry[i], sizeof(BSS_ENTRY)); - Tab->BssEntry[i].Rssi = -127; // initial the rssi as a minimum value - } -} - -#ifdef DOT11_N_SUPPORT -VOID BATableInit( - IN PRTMP_ADAPTER pAd, - IN BA_TABLE *Tab) -{ - int i; - - Tab->numAsOriginator = 0; - Tab->numAsRecipient = 0; - NdisAllocateSpinLock(&pAd->BATabLock); - for (i = 0; i < MAX_LEN_OF_BA_REC_TABLE; i++) - { - Tab->BARecEntry[i].REC_BA_Status = Recipient_NONE; - NdisAllocateSpinLock(&(Tab->BARecEntry[i].RxReRingLock)); - } - for (i = 0; i < MAX_LEN_OF_BA_ORI_TABLE; i++) - { - Tab->BAOriEntry[i].ORI_BA_Status = Originator_NONE; - } -} -#endif // DOT11_N_SUPPORT // - -/*! \brief search the BSS table by SSID - * \param p_tab pointer to the bss table - * \param ssid SSID string - * \return index of the table, BSS_NOT_FOUND if not in the table - * \pre - * \post - * \note search by sequential search - - IRQL = DISPATCH_LEVEL - - */ -ULONG BssTableSearch( - IN BSS_TABLE *Tab, - IN PUCHAR pBssid, - IN UCHAR Channel) -{ - UCHAR i; - - for (i = 0; i < Tab->BssNr; i++) - { - // - // Some AP that support A/B/G mode that may used the same BSSID on 11A and 11B/G. - // We should distinguish this case. - // - if ((((Tab->BssEntry[i].Channel <= 14) && (Channel <= 14)) || - ((Tab->BssEntry[i].Channel > 14) && (Channel > 14))) && - MAC_ADDR_EQUAL(Tab->BssEntry[i].Bssid, pBssid)) - { - return i; - } - } - return (ULONG)BSS_NOT_FOUND; -} - -ULONG BssSsidTableSearch( - IN BSS_TABLE *Tab, - IN PUCHAR pBssid, - IN PUCHAR pSsid, - IN UCHAR SsidLen, - IN UCHAR Channel) -{ - UCHAR i; - - for (i = 0; i < Tab->BssNr; i++) - { - // - // Some AP that support A/B/G mode that may used the same BSSID on 11A and 11B/G. - // We should distinguish this case. - // - if ((((Tab->BssEntry[i].Channel <= 14) && (Channel <= 14)) || - ((Tab->BssEntry[i].Channel > 14) && (Channel > 14))) && - MAC_ADDR_EQUAL(Tab->BssEntry[i].Bssid, pBssid) && - SSID_EQUAL(pSsid, SsidLen, Tab->BssEntry[i].Ssid, Tab->BssEntry[i].SsidLen)) - { - return i; - } - } - return (ULONG)BSS_NOT_FOUND; -} - -ULONG BssTableSearchWithSSID( - IN BSS_TABLE *Tab, - IN PUCHAR Bssid, - IN PUCHAR pSsid, - IN UCHAR SsidLen, - IN UCHAR Channel) -{ - UCHAR i; - - for (i = 0; i < Tab->BssNr; i++) - { - if ((((Tab->BssEntry[i].Channel <= 14) && (Channel <= 14)) || - ((Tab->BssEntry[i].Channel > 14) && (Channel > 14))) && - MAC_ADDR_EQUAL(&(Tab->BssEntry[i].Bssid), Bssid) && - (SSID_EQUAL(pSsid, SsidLen, Tab->BssEntry[i].Ssid, Tab->BssEntry[i].SsidLen) || - (NdisEqualMemory(pSsid, ZeroSsid, SsidLen)) || - (NdisEqualMemory(Tab->BssEntry[i].Ssid, ZeroSsid, Tab->BssEntry[i].SsidLen)))) - { - return i; - } - } - return (ULONG)BSS_NOT_FOUND; -} - -// IRQL = DISPATCH_LEVEL -VOID BssTableDeleteEntry( - IN OUT BSS_TABLE *Tab, - IN PUCHAR pBssid, - IN UCHAR Channel) -{ - UCHAR i, j; - - for (i = 0; i < Tab->BssNr; i++) - { - if ((Tab->BssEntry[i].Channel == Channel) && - (MAC_ADDR_EQUAL(Tab->BssEntry[i].Bssid, pBssid))) - { - for (j = i; j < Tab->BssNr - 1; j++) - { - NdisMoveMemory(&(Tab->BssEntry[j]), &(Tab->BssEntry[j + 1]), sizeof(BSS_ENTRY)); - } - NdisZeroMemory(&(Tab->BssEntry[Tab->BssNr - 1]), sizeof(BSS_ENTRY)); - Tab->BssNr -= 1; - return; - } - } -} - -#ifdef DOT11_N_SUPPORT -/* - ======================================================================== - Routine Description: - Delete the Originator Entry in BAtable. Or decrease numAs Originator by 1 if needed. - - Arguments: - // IRQL = DISPATCH_LEVEL - ======================================================================== -*/ -VOID BATableDeleteORIEntry( - IN OUT PRTMP_ADAPTER pAd, - IN BA_ORI_ENTRY *pBAORIEntry) -{ - - if (pBAORIEntry->ORI_BA_Status != Originator_NONE) - { - NdisAcquireSpinLock(&pAd->BATabLock); - if (pBAORIEntry->ORI_BA_Status == Originator_Done) - { - pAd->BATable.numAsOriginator -= 1; - DBGPRINT(RT_DEBUG_TRACE, ("BATableDeleteORIEntry numAsOriginator= %ld\n", pAd->BATable.numAsRecipient)); - // Erase Bitmap flag. - } - pAd->MacTab.Content[pBAORIEntry->Wcid].TXBAbitmap &= (~(1<<(pBAORIEntry->TID) )); // If STA mode, erase flag here - pAd->MacTab.Content[pBAORIEntry->Wcid].BAOriWcidArray[pBAORIEntry->TID] = 0; // If STA mode, erase flag here - pBAORIEntry->ORI_BA_Status = Originator_NONE; - pBAORIEntry->Token = 1; - // Not clear Sequence here. - NdisReleaseSpinLock(&pAd->BATabLock); - } -} -#endif // DOT11_N_SUPPORT // - -/*! \brief - * \param - * \return - * \pre - * \post - - IRQL = DISPATCH_LEVEL - - */ -VOID BssEntrySet( - IN PRTMP_ADAPTER pAd, - OUT BSS_ENTRY *pBss, - IN PUCHAR pBssid, - IN CHAR Ssid[], - IN UCHAR SsidLen, - IN UCHAR BssType, - IN USHORT BeaconPeriod, - IN PCF_PARM pCfParm, - IN USHORT AtimWin, - IN USHORT CapabilityInfo, - IN UCHAR SupRate[], - IN UCHAR SupRateLen, - IN UCHAR ExtRate[], - IN UCHAR ExtRateLen, - IN HT_CAPABILITY_IE *pHtCapability, - IN ADD_HT_INFO_IE *pAddHtInfo, // AP might use this additional ht info IE - IN UCHAR HtCapabilityLen, - IN UCHAR AddHtInfoLen, - IN UCHAR NewExtChanOffset, - IN UCHAR Channel, - IN CHAR Rssi, - IN LARGE_INTEGER TimeStamp, - IN UCHAR CkipFlag, - IN PEDCA_PARM pEdcaParm, - IN PQOS_CAPABILITY_PARM pQosCapability, - IN PQBSS_LOAD_PARM pQbssLoad, - IN USHORT LengthVIE, - IN PNDIS_802_11_VARIABLE_IEs pVIE) -{ - COPY_MAC_ADDR(pBss->Bssid, pBssid); - // Default Hidden SSID to be TRUE, it will be turned to FALSE after coping SSID - pBss->Hidden = 1; - if (SsidLen > 0) - { - // For hidden SSID AP, it might send beacon with SSID len equal to 0 - // Or send beacon /probe response with SSID len matching real SSID length, - // but SSID is all zero. such as "00-00-00-00" with length 4. - // We have to prevent this case overwrite correct table - if (NdisEqualMemory(Ssid, ZeroSsid, SsidLen) == 0) - { - NdisZeroMemory(pBss->Ssid, MAX_LEN_OF_SSID); - NdisMoveMemory(pBss->Ssid, Ssid, SsidLen); - pBss->SsidLen = SsidLen; - pBss->Hidden = 0; - } - } - else - pBss->SsidLen = 0; - pBss->BssType = BssType; - pBss->BeaconPeriod = BeaconPeriod; - if (BssType == BSS_INFRA) - { - if (pCfParm->bValid) - { - pBss->CfpCount = pCfParm->CfpCount; - pBss->CfpPeriod = pCfParm->CfpPeriod; - pBss->CfpMaxDuration = pCfParm->CfpMaxDuration; - pBss->CfpDurRemaining = pCfParm->CfpDurRemaining; - } - } - else - { - pBss->AtimWin = AtimWin; - } - - pBss->CapabilityInfo = CapabilityInfo; - // The privacy bit indicate security is ON, it maight be WEP, TKIP or AES - // Combine with AuthMode, they will decide the connection methods. - pBss->Privacy = CAP_IS_PRIVACY_ON(pBss->CapabilityInfo); - ASSERT(SupRateLen <= MAX_LEN_OF_SUPPORTED_RATES); - if (SupRateLen <= MAX_LEN_OF_SUPPORTED_RATES) - NdisMoveMemory(pBss->SupRate, SupRate, SupRateLen); - else - NdisMoveMemory(pBss->SupRate, SupRate, MAX_LEN_OF_SUPPORTED_RATES); - pBss->SupRateLen = SupRateLen; - ASSERT(ExtRateLen <= MAX_LEN_OF_SUPPORTED_RATES); - NdisMoveMemory(pBss->ExtRate, ExtRate, ExtRateLen); - NdisMoveMemory(&pBss->HtCapability, pHtCapability, HtCapabilityLen); - NdisMoveMemory(&pBss->AddHtInfo, pAddHtInfo, AddHtInfoLen); - pBss->NewExtChanOffset = NewExtChanOffset; - pBss->ExtRateLen = ExtRateLen; - pBss->Channel = Channel; - pBss->CentralChannel = Channel; - pBss->Rssi = Rssi; - // Update CkipFlag. if not exists, the value is 0x0 - pBss->CkipFlag = CkipFlag; - - // New for microsoft Fixed IEs - NdisMoveMemory(pBss->FixIEs.Timestamp, &TimeStamp, 8); - pBss->FixIEs.BeaconInterval = BeaconPeriod; - pBss->FixIEs.Capabilities = CapabilityInfo; - - // New for microsoft Variable IEs - if (LengthVIE != 0) - { - pBss->VarIELen = LengthVIE; - NdisMoveMemory(pBss->VarIEs, pVIE, pBss->VarIELen); - } - else - { - pBss->VarIELen = 0; - } - - pBss->AddHtInfoLen = 0; - pBss->HtCapabilityLen = 0; -#ifdef DOT11_N_SUPPORT - if (HtCapabilityLen> 0) - { - pBss->HtCapabilityLen = HtCapabilityLen; - NdisMoveMemory(&pBss->HtCapability, pHtCapability, HtCapabilityLen); - if (AddHtInfoLen > 0) - { - pBss->AddHtInfoLen = AddHtInfoLen; - NdisMoveMemory(&pBss->AddHtInfo, pAddHtInfo, AddHtInfoLen); - - if ((pAddHtInfo->ControlChan > 2)&& (pAddHtInfo->AddHtInfo.ExtChanOffset == EXTCHA_BELOW) && (pHtCapability->HtCapInfo.ChannelWidth == BW_40)) - { - pBss->CentralChannel = pAddHtInfo->ControlChan - 2; - } - else if ((pAddHtInfo->AddHtInfo.ExtChanOffset == EXTCHA_ABOVE) && (pHtCapability->HtCapInfo.ChannelWidth == BW_40)) - { - pBss->CentralChannel = pAddHtInfo->ControlChan + 2; - } - } - } -#endif // DOT11_N_SUPPORT // - - BssCipherParse(pBss); - - // new for QOS - if (pEdcaParm) - NdisMoveMemory(&pBss->EdcaParm, pEdcaParm, sizeof(EDCA_PARM)); - else - pBss->EdcaParm.bValid = FALSE; - if (pQosCapability) - NdisMoveMemory(&pBss->QosCapability, pQosCapability, sizeof(QOS_CAPABILITY_PARM)); - else - pBss->QosCapability.bValid = FALSE; - if (pQbssLoad) - NdisMoveMemory(&pBss->QbssLoad, pQbssLoad, sizeof(QBSS_LOAD_PARM)); - else - pBss->QbssLoad.bValid = FALSE; - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - PEID_STRUCT pEid; - USHORT Length = 0; - - - NdisZeroMemory(&pBss->WpaIE.IE[0], MAX_CUSTOM_LEN); - NdisZeroMemory(&pBss->RsnIE.IE[0], MAX_CUSTOM_LEN); -#ifdef EXT_BUILD_CHANNEL_LIST - NdisZeroMemory(&pBss->CountryString[0], 3); - pBss->bHasCountryIE = FALSE; -#endif // EXT_BUILD_CHANNEL_LIST // - pEid = (PEID_STRUCT) pVIE; - while ((Length + 2 + (USHORT)pEid->Len) <= LengthVIE) - { - switch(pEid->Eid) - { - case IE_WPA: - if (NdisEqualMemory(pEid->Octet, WPA_OUI, 4)) - { - if ((pEid->Len + 2) > MAX_CUSTOM_LEN) - { - pBss->WpaIE.IELen = 0; - break; - } - pBss->WpaIE.IELen = pEid->Len + 2; - NdisMoveMemory(pBss->WpaIE.IE, pEid, pBss->WpaIE.IELen); - } - break; - case IE_RSN: - if (NdisEqualMemory(pEid->Octet + 2, RSN_OUI, 3)) - { - if ((pEid->Len + 2) > MAX_CUSTOM_LEN) - { - pBss->RsnIE.IELen = 0; - break; - } - pBss->RsnIE.IELen = pEid->Len + 2; - NdisMoveMemory(pBss->RsnIE.IE, pEid, pBss->RsnIE.IELen); - } - break; -#ifdef EXT_BUILD_CHANNEL_LIST - case IE_COUNTRY: - NdisMoveMemory(&pBss->CountryString[0], pEid->Octet, 3); - pBss->bHasCountryIE = TRUE; - break; -#endif // EXT_BUILD_CHANNEL_LIST // - } - Length = Length + 2 + (USHORT)pEid->Len; // Eid[1] + Len[1]+ content[Len] - pEid = (PEID_STRUCT)((UCHAR*)pEid + 2 + pEid->Len); - } - } -#endif // CONFIG_STA_SUPPORT // -} - -/*! - * \brief insert an entry into the bss table - * \param p_tab The BSS table - * \param Bssid BSSID - * \param ssid SSID - * \param ssid_len Length of SSID - * \param bss_type - * \param beacon_period - * \param timestamp - * \param p_cf - * \param atim_win - * \param cap - * \param rates - * \param rates_len - * \param channel_idx - * \return none - * \pre - * \post - * \note If SSID is identical, the old entry will be replaced by the new one - - IRQL = DISPATCH_LEVEL - - */ -ULONG BssTableSetEntry( - IN PRTMP_ADAPTER pAd, - OUT BSS_TABLE *Tab, - IN PUCHAR pBssid, - IN CHAR Ssid[], - IN UCHAR SsidLen, - IN UCHAR BssType, - IN USHORT BeaconPeriod, - IN CF_PARM *CfParm, - IN USHORT AtimWin, - IN USHORT CapabilityInfo, - IN UCHAR SupRate[], - IN UCHAR SupRateLen, - IN UCHAR ExtRate[], - IN UCHAR ExtRateLen, - IN HT_CAPABILITY_IE *pHtCapability, - IN ADD_HT_INFO_IE *pAddHtInfo, // AP might use this additional ht info IE - IN UCHAR HtCapabilityLen, - IN UCHAR AddHtInfoLen, - IN UCHAR NewExtChanOffset, - IN UCHAR ChannelNo, - IN CHAR Rssi, - IN LARGE_INTEGER TimeStamp, - IN UCHAR CkipFlag, - IN PEDCA_PARM pEdcaParm, - IN PQOS_CAPABILITY_PARM pQosCapability, - IN PQBSS_LOAD_PARM pQbssLoad, - IN USHORT LengthVIE, - IN PNDIS_802_11_VARIABLE_IEs pVIE) -{ - ULONG Idx; - - Idx = BssTableSearchWithSSID(Tab, pBssid, Ssid, SsidLen, ChannelNo); - if (Idx == BSS_NOT_FOUND) - { - if (Tab->BssNr >= MAX_LEN_OF_BSS_TABLE) - { - // - // It may happen when BSS Table was full. - // The desired AP will not be added into BSS Table - // In this case, if we found the desired AP then overwrite BSS Table. - // - if(!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) - { - if (MAC_ADDR_EQUAL(pAd->MlmeAux.Bssid, pBssid) || - SSID_EQUAL(pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen, Ssid, SsidLen)) - { - Idx = Tab->BssOverlapNr; - BssEntrySet(pAd, &Tab->BssEntry[Idx], pBssid, Ssid, SsidLen, BssType, BeaconPeriod, CfParm, AtimWin, - CapabilityInfo, SupRate, SupRateLen, ExtRate, ExtRateLen,pHtCapability, pAddHtInfo,HtCapabilityLen, AddHtInfoLen, - NewExtChanOffset, ChannelNo, Rssi, TimeStamp, CkipFlag, pEdcaParm, pQosCapability, pQbssLoad, LengthVIE, pVIE); - Tab->BssOverlapNr = (Tab->BssOverlapNr++) % MAX_LEN_OF_BSS_TABLE; - } - return Idx; - } - else - { - return BSS_NOT_FOUND; - } - } - Idx = Tab->BssNr; - BssEntrySet(pAd, &Tab->BssEntry[Idx], pBssid, Ssid, SsidLen, BssType, BeaconPeriod, CfParm, AtimWin, - CapabilityInfo, SupRate, SupRateLen, ExtRate, ExtRateLen,pHtCapability, pAddHtInfo,HtCapabilityLen, AddHtInfoLen, - NewExtChanOffset, ChannelNo, Rssi, TimeStamp, CkipFlag, pEdcaParm, pQosCapability, pQbssLoad, LengthVIE, pVIE); - Tab->BssNr++; - } - else - { - BssEntrySet(pAd, &Tab->BssEntry[Idx], pBssid, Ssid, SsidLen, BssType, BeaconPeriod,CfParm, AtimWin, - CapabilityInfo, SupRate, SupRateLen, ExtRate, ExtRateLen,pHtCapability, pAddHtInfo,HtCapabilityLen, AddHtInfoLen, - NewExtChanOffset, ChannelNo, Rssi, TimeStamp, CkipFlag, pEdcaParm, pQosCapability, pQbssLoad, LengthVIE, pVIE); - } - - return Idx; -} - -#ifdef CONFIG_STA_SUPPORT -#ifdef DOT11_N_SUPPORT -#ifdef DOT11N_DRAFT3 -VOID TriEventInit( - IN PRTMP_ADAPTER pAd) -{ - UCHAR i; - - for (i = 0;i < MAX_TRIGGER_EVENT;i++) - pAd->CommonCfg.TriggerEventTab.EventA[i].bValid = FALSE; - - pAd->CommonCfg.TriggerEventTab.EventANo = 0; - pAd->CommonCfg.TriggerEventTab.EventBCountDown = 0; -} - -ULONG TriEventTableSetEntry( - IN PRTMP_ADAPTER pAd, - OUT TRIGGER_EVENT_TAB *Tab, - IN PUCHAR pBssid, - IN HT_CAPABILITY_IE *pHtCapability, - IN UCHAR HtCapabilityLen, - IN UCHAR RegClass, - IN UCHAR ChannelNo) -{ - // Event A - if (HtCapabilityLen == 0) - { - if (Tab->EventANo < MAX_TRIGGER_EVENT) - { - RTMPMoveMemory(Tab->EventA[Tab->EventANo].BSSID, pBssid, 6); - Tab->EventA[Tab->EventANo].bValid = TRUE; - Tab->EventA[Tab->EventANo].Channel = ChannelNo; - Tab->EventA[Tab->EventANo].CDCounter = pAd->CommonCfg.Dot11BssWidthChanTranDelay; - if (RegClass != 0) - { - // Beacon has Regulatory class IE. So use beacon's - Tab->EventA[Tab->EventANo].RegClass = RegClass; - } - else - { - // Use Station's Regulatory class instead. - if (pAd->StaActive.SupportedHtPhy.bHtEnable == TRUE) - { - if (pAd->CommonCfg.CentralChannel > pAd->CommonCfg.Channel) - { - Tab->EventA[Tab->EventANo].RegClass = 32; - } - else if (pAd->CommonCfg.CentralChannel < pAd->CommonCfg.Channel) - Tab->EventA[Tab->EventANo].RegClass = 33; - } - else - Tab->EventA[Tab->EventANo].RegClass = ??; - - } - - Tab->EventANo ++; - } - } - else if (pHtCapability->HtCapInfo.Intolerant40) - { - Tab->EventBCountDown = pAd->CommonCfg.Dot11BssWidthChanTranDelay; - } - -} - -/* - ======================================================================== - Routine Description: - Trigger Event table Maintainence called once every second. - - Arguments: - // IRQL = DISPATCH_LEVEL - ======================================================================== -*/ -VOID TriEventCounterMaintenance( - IN PRTMP_ADAPTER pAd) -{ - UCHAR i; - BOOLEAN bNotify = FALSE; - for (i = 0;i < MAX_TRIGGER_EVENT;i++) - { - if (pAd->CommonCfg.TriggerEventTab.EventA[i].bValid && (pAd->CommonCfg.TriggerEventTab.EventA[i].CDCounter > 0)) - { - pAd->CommonCfg.TriggerEventTab.EventA[i].CDCounter--; - if (pAd->CommonCfg.TriggerEventTab.EventA[i].CDCounter == 0) - { - pAd->CommonCfg.TriggerEventTab.EventA[i].bValid = FALSE; - pAd->CommonCfg.TriggerEventTab.EventANo --; - // Need to send 20/40 Coexistence Notify frame if has status change. - bNotify = TRUE; - } - } - } - if (pAd->CommonCfg.TriggerEventTab.EventBCountDown > 0) - { - pAd->CommonCfg.TriggerEventTab.EventBCountDown--; - if (pAd->CommonCfg.TriggerEventTab.EventBCountDown == 0) - bNotify = TRUE; - } - - if (bNotify == TRUE) - Update2040CoexistFrameAndNotify(pAd, BSSID_WCID, TRUE); -} -#endif // DOT11N_DRAFT3 // -#endif // DOT11_N_SUPPORT // - -// IRQL = DISPATCH_LEVEL -VOID BssTableSsidSort( - IN PRTMP_ADAPTER pAd, - OUT BSS_TABLE *OutTab, - IN CHAR Ssid[], - IN UCHAR SsidLen) -{ - INT i; - BssTableInit(OutTab); - - for (i = 0; i < pAd->ScanTab.BssNr; i++) - { - BSS_ENTRY *pInBss = &pAd->ScanTab.BssEntry[i]; - BOOLEAN bIsHiddenApIncluded = FALSE; - - if (((pAd->CommonCfg.bIEEE80211H == 1) && - (pAd->MlmeAux.Channel > 14) && - RadarChannelCheck(pAd, pInBss->Channel)) -#ifdef CARRIER_DETECTION_SUPPORT // Roger sync Carrier - || (pAd->CommonCfg.CarrierDetect.Enable == TRUE) -#endif // CARRIER_DETECTION_SUPPORT // - ) - { - if (pInBss->Hidden) - bIsHiddenApIncluded = TRUE; - } - - if ((pInBss->BssType == pAd->StaCfg.BssType) && - (SSID_EQUAL(Ssid, SsidLen, pInBss->Ssid, pInBss->SsidLen) || bIsHiddenApIncluded)) - { - BSS_ENTRY *pOutBss = &OutTab->BssEntry[OutTab->BssNr]; - - -#ifdef EXT_BUILD_CHANNEL_LIST - // If no Country IE exists no Connection will be established when IEEE80211dClientMode is strict. - if ((pAd->StaCfg.IEEE80211dClientMode == Rt802_11_D_Strict) && - (pInBss->bHasCountryIE == FALSE)) - { - DBGPRINT(RT_DEBUG_TRACE,("StaCfg.IEEE80211dClientMode == Rt802_11_D_Strict, but this AP doesn't have country IE.\n")); - continue; - } -#endif // EXT_BUILD_CHANNEL_LIST // - -#ifdef DOT11_N_SUPPORT - // 2.4G/5G N only mode - if ((pInBss->HtCapabilityLen == 0) && - ((pAd->CommonCfg.PhyMode == PHY_11N_2_4G) || (pAd->CommonCfg.PhyMode == PHY_11N_5G))) - { - DBGPRINT(RT_DEBUG_TRACE,("STA is in N-only Mode, this AP don't have Ht capability in Beacon.\n")); - continue; - } -#endif // DOT11_N_SUPPORT // - - // New for WPA2 - // Check the Authmode first - if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - { - // Check AuthMode and AuthModeAux for matching, in case AP support dual-mode - if ((pAd->StaCfg.AuthMode != pInBss->AuthMode) && (pAd->StaCfg.AuthMode != pInBss->AuthModeAux)) - // None matched - continue; - - // Check cipher suite, AP must have more secured cipher than station setting - if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) - { - // If it's not mixed mode, we should only let BSS pass with the same encryption - if (pInBss->WPA.bMixMode == FALSE) - if (pAd->StaCfg.WepStatus != pInBss->WPA.GroupCipher) - continue; - - // check group cipher - if ((pAd->StaCfg.WepStatus < pInBss->WPA.GroupCipher) && - (pInBss->WPA.GroupCipher != Ndis802_11GroupWEP40Enabled) && - (pInBss->WPA.GroupCipher != Ndis802_11GroupWEP104Enabled)) - continue; - - // check pairwise cipher, skip if none matched - // If profile set to AES, let it pass without question. - // If profile set to TKIP, we must find one mateched - if ((pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) && - (pAd->StaCfg.WepStatus != pInBss->WPA.PairCipher) && - (pAd->StaCfg.WepStatus != pInBss->WPA.PairCipherAux)) - continue; - } - else if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)) - { - // If it's not mixed mode, we should only let BSS pass with the same encryption - if (pInBss->WPA2.bMixMode == FALSE) - if (pAd->StaCfg.WepStatus != pInBss->WPA2.GroupCipher) - continue; - - // check group cipher - if ((pAd->StaCfg.WepStatus < pInBss->WPA.GroupCipher) && - (pInBss->WPA2.GroupCipher != Ndis802_11GroupWEP40Enabled) && - (pInBss->WPA2.GroupCipher != Ndis802_11GroupWEP104Enabled)) - continue; - - // check pairwise cipher, skip if none matched - // If profile set to AES, let it pass without question. - // If profile set to TKIP, we must find one mateched - if ((pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) && - (pAd->StaCfg.WepStatus != pInBss->WPA2.PairCipher) && - (pAd->StaCfg.WepStatus != pInBss->WPA2.PairCipherAux)) - continue; - } - } - // Bss Type matched, SSID matched. - // We will check wepstatus for qualification Bss - else if (pAd->StaCfg.WepStatus != pInBss->WepStatus) - { - DBGPRINT(RT_DEBUG_TRACE,("StaCfg.WepStatus=%d, while pInBss->WepStatus=%d\n", pAd->StaCfg.WepStatus, pInBss->WepStatus)); - // - // For the SESv2 case, we will not qualify WepStatus. - // - if (!pInBss->bSES) - continue; - } - - // Since the AP is using hidden SSID, and we are trying to connect to ANY - // It definitely will fail. So, skip it. - // CCX also require not even try to connect it!! - if (SsidLen == 0) - continue; - -#ifdef DOT11_N_SUPPORT - // If both station and AP use 40MHz, still need to check if the 40MHZ band's legality in my country region - // If this 40MHz wideband is not allowed in my country list, use bandwidth 20MHZ instead, - if ((pInBss->CentralChannel != pInBss->Channel) && - (pAd->CommonCfg.RegTransmitSetting.field.BW == BW_40)) - { - if (RTMPCheckChannel(pAd, pInBss->CentralChannel, pInBss->Channel) == FALSE) - { - pAd->CommonCfg.RegTransmitSetting.field.BW = BW_20; - SetCommonHT(pAd); - pAd->CommonCfg.RegTransmitSetting.field.BW = BW_40; - } - else - { - if (pAd->CommonCfg.DesiredHtPhy.ChannelWidth == BAND_WIDTH_20) - { - SetCommonHT(pAd); - } - } - } -#endif // DOT11_N_SUPPORT // - - // copy matching BSS from InTab to OutTab - NdisMoveMemory(pOutBss, pInBss, sizeof(BSS_ENTRY)); - - OutTab->BssNr++; - } - else if ((pInBss->BssType == pAd->StaCfg.BssType) && (SsidLen == 0)) - { - BSS_ENTRY *pOutBss = &OutTab->BssEntry[OutTab->BssNr]; - - -#ifdef DOT11_N_SUPPORT - // 2.4G/5G N only mode - if ((pInBss->HtCapabilityLen == 0) && - ((pAd->CommonCfg.PhyMode == PHY_11N_2_4G) || (pAd->CommonCfg.PhyMode == PHY_11N_5G))) - { - DBGPRINT(RT_DEBUG_TRACE,("STA is in N-only Mode, this AP don't have Ht capability in Beacon.\n")); - continue; - } -#endif // DOT11_N_SUPPORT // - - // New for WPA2 - // Check the Authmode first - if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - { - // Check AuthMode and AuthModeAux for matching, in case AP support dual-mode - if ((pAd->StaCfg.AuthMode != pInBss->AuthMode) && (pAd->StaCfg.AuthMode != pInBss->AuthModeAux)) - // None matched - continue; - - // Check cipher suite, AP must have more secured cipher than station setting - if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) - { - // If it's not mixed mode, we should only let BSS pass with the same encryption - if (pInBss->WPA.bMixMode == FALSE) - if (pAd->StaCfg.WepStatus != pInBss->WPA.GroupCipher) - continue; - - // check group cipher - if (pAd->StaCfg.WepStatus < pInBss->WPA.GroupCipher) - continue; - - // check pairwise cipher, skip if none matched - // If profile set to AES, let it pass without question. - // If profile set to TKIP, we must find one mateched - if ((pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) && - (pAd->StaCfg.WepStatus != pInBss->WPA.PairCipher) && - (pAd->StaCfg.WepStatus != pInBss->WPA.PairCipherAux)) - continue; - } - else if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)) - { - // If it's not mixed mode, we should only let BSS pass with the same encryption - if (pInBss->WPA2.bMixMode == FALSE) - if (pAd->StaCfg.WepStatus != pInBss->WPA2.GroupCipher) - continue; - - // check group cipher - if (pAd->StaCfg.WepStatus < pInBss->WPA2.GroupCipher) - continue; - - // check pairwise cipher, skip if none matched - // If profile set to AES, let it pass without question. - // If profile set to TKIP, we must find one mateched - if ((pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) && - (pAd->StaCfg.WepStatus != pInBss->WPA2.PairCipher) && - (pAd->StaCfg.WepStatus != pInBss->WPA2.PairCipherAux)) - continue; - } - } - // Bss Type matched, SSID matched. - // We will check wepstatus for qualification Bss - else if (pAd->StaCfg.WepStatus != pInBss->WepStatus) - continue; - -#ifdef DOT11_N_SUPPORT - // If both station and AP use 40MHz, still need to check if the 40MHZ band's legality in my country region - // If this 40MHz wideband is not allowed in my country list, use bandwidth 20MHZ instead, - if ((pInBss->CentralChannel != pInBss->Channel) && - (pAd->CommonCfg.RegTransmitSetting.field.BW == BW_40)) - { - if (RTMPCheckChannel(pAd, pInBss->CentralChannel, pInBss->Channel) == FALSE) - { - pAd->CommonCfg.RegTransmitSetting.field.BW = BW_20; - SetCommonHT(pAd); - pAd->CommonCfg.RegTransmitSetting.field.BW = BW_40; - } - } -#endif // DOT11_N_SUPPORT // - - // copy matching BSS from InTab to OutTab - NdisMoveMemory(pOutBss, pInBss, sizeof(BSS_ENTRY)); - - OutTab->BssNr++; - } - - if (OutTab->BssNr >= MAX_LEN_OF_BSS_TABLE) - break; - } - - BssTableSortByRssi(OutTab); -} - - -// IRQL = DISPATCH_LEVEL -VOID BssTableSortByRssi( - IN OUT BSS_TABLE *OutTab) -{ - INT i, j; - BSS_ENTRY TmpBss; - - for (i = 0; i < OutTab->BssNr - 1; i++) - { - for (j = i+1; j < OutTab->BssNr; j++) - { - if (OutTab->BssEntry[j].Rssi > OutTab->BssEntry[i].Rssi) - { - NdisMoveMemory(&TmpBss, &OutTab->BssEntry[j], sizeof(BSS_ENTRY)); - NdisMoveMemory(&OutTab->BssEntry[j], &OutTab->BssEntry[i], sizeof(BSS_ENTRY)); - NdisMoveMemory(&OutTab->BssEntry[i], &TmpBss, sizeof(BSS_ENTRY)); - } - } - } -} -#endif // CONFIG_STA_SUPPORT // - - -VOID BssCipherParse( - IN OUT PBSS_ENTRY pBss) -{ - PEID_STRUCT pEid; - PUCHAR pTmp; - PRSN_IE_HEADER_STRUCT pRsnHeader; - PCIPHER_SUITE_STRUCT pCipher; - PAKM_SUITE_STRUCT pAKM; - USHORT Count; - INT Length; - NDIS_802_11_ENCRYPTION_STATUS TmpCipher; - - // - // WepStatus will be reset later, if AP announce TKIP or AES on the beacon frame. - // - if (pBss->Privacy) - { - pBss->WepStatus = Ndis802_11WEPEnabled; - } - else - { - pBss->WepStatus = Ndis802_11WEPDisabled; - } - // Set default to disable & open authentication before parsing variable IE - pBss->AuthMode = Ndis802_11AuthModeOpen; - pBss->AuthModeAux = Ndis802_11AuthModeOpen; - - // Init WPA setting - pBss->WPA.PairCipher = Ndis802_11WEPDisabled; - pBss->WPA.PairCipherAux = Ndis802_11WEPDisabled; - pBss->WPA.GroupCipher = Ndis802_11WEPDisabled; - pBss->WPA.RsnCapability = 0; - pBss->WPA.bMixMode = FALSE; - - // Init WPA2 setting - pBss->WPA2.PairCipher = Ndis802_11WEPDisabled; - pBss->WPA2.PairCipherAux = Ndis802_11WEPDisabled; - pBss->WPA2.GroupCipher = Ndis802_11WEPDisabled; - pBss->WPA2.RsnCapability = 0; - pBss->WPA2.bMixMode = FALSE; - - - Length = (INT) pBss->VarIELen; - - while (Length > 0) - { - // Parse cipher suite base on WPA1 & WPA2, they should be parsed differently - pTmp = ((PUCHAR) pBss->VarIEs) + pBss->VarIELen - Length; - pEid = (PEID_STRUCT) pTmp; - switch (pEid->Eid) - { - case IE_WPA: - //Parse Cisco IE_WPA (LEAP, CCKM, etc.) - if ( NdisEqualMemory((pTmp+8), CISCO_OUI, 3)) - { - pTmp += 11; - switch (*pTmp) - { - case 1: - case 5: // Although WEP is not allowed in WPA related auth mode, we parse it anyway - pBss->WepStatus = Ndis802_11Encryption1Enabled; - pBss->WPA.PairCipher = Ndis802_11Encryption1Enabled; - pBss->WPA.GroupCipher = Ndis802_11Encryption1Enabled; - break; - case 2: - pBss->WepStatus = Ndis802_11Encryption2Enabled; - pBss->WPA.PairCipher = Ndis802_11Encryption1Enabled; - pBss->WPA.GroupCipher = Ndis802_11Encryption1Enabled; - break; - case 4: - pBss->WepStatus = Ndis802_11Encryption3Enabled; - pBss->WPA.PairCipher = Ndis802_11Encryption1Enabled; - pBss->WPA.GroupCipher = Ndis802_11Encryption1Enabled; - break; - default: - break; - } - - // if Cisco IE_WPA, break - break; - } - else if (NdisEqualMemory(pEid->Octet, SES_OUI, 3) && (pEid->Len == 7)) - { - pBss->bSES = TRUE; - break; - } - else if (NdisEqualMemory(pEid->Octet, WPA_OUI, 4) != 1) - { - // if unsupported vendor specific IE - break; - } - // Skip OUI, version, and multicast suite - // This part should be improved in the future when AP supported multiple cipher suite. - // For now, it's OK since almost all APs have fixed cipher suite supported. - // pTmp = (PUCHAR) pEid->Octet; - pTmp += 11; - - // Cipher Suite Selectors from Spec P802.11i/D3.2 P26. - // Value Meaning - // 0 None - // 1 WEP-40 - // 2 Tkip - // 3 WRAP - // 4 AES - // 5 WEP-104 - // Parse group cipher - switch (*pTmp) - { - case 1: - pBss->WPA.GroupCipher = Ndis802_11GroupWEP40Enabled; - break; - case 5: - pBss->WPA.GroupCipher = Ndis802_11GroupWEP104Enabled; - break; - case 2: - pBss->WPA.GroupCipher = Ndis802_11Encryption2Enabled; - break; - case 4: - pBss->WPA.GroupCipher = Ndis802_11Encryption3Enabled; - break; - default: - break; - } - // number of unicast suite - pTmp += 1; - - // skip all unicast cipher suites - //Count = *(PUSHORT) pTmp; - Count = (pTmp[1]<<8) + pTmp[0]; - pTmp += sizeof(USHORT); - - // Parsing all unicast cipher suite - while (Count > 0) - { - // Skip OUI - pTmp += 3; - TmpCipher = Ndis802_11WEPDisabled; - switch (*pTmp) - { - case 1: - case 5: // Although WEP is not allowed in WPA related auth mode, we parse it anyway - TmpCipher = Ndis802_11Encryption1Enabled; - break; - case 2: - TmpCipher = Ndis802_11Encryption2Enabled; - break; - case 4: - TmpCipher = Ndis802_11Encryption3Enabled; - break; - default: - break; - } - if (TmpCipher > pBss->WPA.PairCipher) - { - // Move the lower cipher suite to PairCipherAux - pBss->WPA.PairCipherAux = pBss->WPA.PairCipher; - pBss->WPA.PairCipher = TmpCipher; - } - else - { - pBss->WPA.PairCipherAux = TmpCipher; - } - pTmp++; - Count--; - } - - // 4. get AKM suite counts - //Count = *(PUSHORT) pTmp; - Count = (pTmp[1]<<8) + pTmp[0]; - pTmp += sizeof(USHORT); - pTmp += 3; - - switch (*pTmp) - { - case 1: - // Set AP support WPA mode - if (pBss->AuthMode == Ndis802_11AuthModeOpen) - pBss->AuthMode = Ndis802_11AuthModeWPA; - else - pBss->AuthModeAux = Ndis802_11AuthModeWPA; - break; - case 2: - // Set AP support WPA mode - if (pBss->AuthMode == Ndis802_11AuthModeOpen) - pBss->AuthMode = Ndis802_11AuthModeWPAPSK; - else - pBss->AuthModeAux = Ndis802_11AuthModeWPAPSK; - break; - default: - break; - } - pTmp += 1; - - // Fixed for WPA-None - if (pBss->BssType == BSS_ADHOC) - { - pBss->AuthMode = Ndis802_11AuthModeWPANone; - pBss->AuthModeAux = Ndis802_11AuthModeWPANone; - pBss->WepStatus = pBss->WPA.GroupCipher; - // Patched bugs for old driver - if (pBss->WPA.PairCipherAux == Ndis802_11WEPDisabled) - pBss->WPA.PairCipherAux = pBss->WPA.GroupCipher; - } - else - pBss->WepStatus = pBss->WPA.PairCipher; - - // Check the Pair & Group, if different, turn on mixed mode flag - if (pBss->WPA.GroupCipher != pBss->WPA.PairCipher) - pBss->WPA.bMixMode = TRUE; - - break; - - case IE_RSN: - pRsnHeader = (PRSN_IE_HEADER_STRUCT) pTmp; - - // 0. Version must be 1 - if (le2cpu16(pRsnHeader->Version) != 1) - break; - pTmp += sizeof(RSN_IE_HEADER_STRUCT); - - // 1. Check group cipher - pCipher = (PCIPHER_SUITE_STRUCT) pTmp; - if (!RTMPEqualMemory(pTmp, RSN_OUI, 3)) - break; - - // Parse group cipher - switch (pCipher->Type) - { - case 1: - pBss->WPA2.GroupCipher = Ndis802_11GroupWEP40Enabled; - break; - case 5: - pBss->WPA2.GroupCipher = Ndis802_11GroupWEP104Enabled; - break; - case 2: - pBss->WPA2.GroupCipher = Ndis802_11Encryption2Enabled; - break; - case 4: - pBss->WPA2.GroupCipher = Ndis802_11Encryption3Enabled; - break; - default: - break; - } - // set to correct offset for next parsing - pTmp += sizeof(CIPHER_SUITE_STRUCT); - - // 2. Get pairwise cipher counts - //Count = *(PUSHORT) pTmp; - Count = (pTmp[1]<<8) + pTmp[0]; - pTmp += sizeof(USHORT); - - // 3. Get pairwise cipher - // Parsing all unicast cipher suite - while (Count > 0) - { - // Skip OUI - pCipher = (PCIPHER_SUITE_STRUCT) pTmp; - TmpCipher = Ndis802_11WEPDisabled; - switch (pCipher->Type) - { - case 1: - case 5: // Although WEP is not allowed in WPA related auth mode, we parse it anyway - TmpCipher = Ndis802_11Encryption1Enabled; - break; - case 2: - TmpCipher = Ndis802_11Encryption2Enabled; - break; - case 4: - TmpCipher = Ndis802_11Encryption3Enabled; - break; - default: - break; - } - if (TmpCipher > pBss->WPA2.PairCipher) - { - // Move the lower cipher suite to PairCipherAux - pBss->WPA2.PairCipherAux = pBss->WPA2.PairCipher; - pBss->WPA2.PairCipher = TmpCipher; - } - else - { - pBss->WPA2.PairCipherAux = TmpCipher; - } - pTmp += sizeof(CIPHER_SUITE_STRUCT); - Count--; - } - - // 4. get AKM suite counts - //Count = *(PUSHORT) pTmp; - Count = (pTmp[1]<<8) + pTmp[0]; - pTmp += sizeof(USHORT); - - // 5. Get AKM ciphers - pAKM = (PAKM_SUITE_STRUCT) pTmp; - if (!RTMPEqualMemory(pTmp, RSN_OUI, 3)) - break; - - switch (pAKM->Type) - { - case 1: - // Set AP support WPA mode - if (pBss->AuthMode == Ndis802_11AuthModeOpen) - pBss->AuthMode = Ndis802_11AuthModeWPA2; - else - pBss->AuthModeAux = Ndis802_11AuthModeWPA2; - break; - case 2: - // Set AP support WPA mode - if (pBss->AuthMode == Ndis802_11AuthModeOpen) - pBss->AuthMode = Ndis802_11AuthModeWPA2PSK; - else - pBss->AuthModeAux = Ndis802_11AuthModeWPA2PSK; - break; - default: - break; - } - pTmp += (Count * sizeof(AKM_SUITE_STRUCT)); - - // Fixed for WPA-None - if (pBss->BssType == BSS_ADHOC) - { - pBss->AuthMode = Ndis802_11AuthModeWPANone; - pBss->AuthModeAux = Ndis802_11AuthModeWPANone; - pBss->WPA.PairCipherAux = pBss->WPA2.PairCipherAux; - pBss->WPA.GroupCipher = pBss->WPA2.GroupCipher; - pBss->WepStatus = pBss->WPA.GroupCipher; - // Patched bugs for old driver - if (pBss->WPA.PairCipherAux == Ndis802_11WEPDisabled) - pBss->WPA.PairCipherAux = pBss->WPA.GroupCipher; - } - pBss->WepStatus = pBss->WPA2.PairCipher; - - // 6. Get RSN capability - //pBss->WPA2.RsnCapability = *(PUSHORT) pTmp; - pBss->WPA2.RsnCapability = (pTmp[1]<<8) + pTmp[0]; - pTmp += sizeof(USHORT); - - // Check the Pair & Group, if different, turn on mixed mode flag - if (pBss->WPA2.GroupCipher != pBss->WPA2.PairCipher) - pBss->WPA2.bMixMode = TRUE; - - break; - default: - break; - } - Length -= (pEid->Len + 2); - } -} - -// =========================================================================================== -// mac_table.c -// =========================================================================================== - -/*! \brief generates a random mac address value for IBSS BSSID - * \param Addr the bssid location - * \return none - * \pre - * \post - */ -VOID MacAddrRandomBssid( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pAddr) -{ - INT i; - - for (i = 0; i < MAC_ADDR_LEN; i++) - { - pAddr[i] = RandomByte(pAd); - } - - pAddr[0] = (pAddr[0] & 0xfe) | 0x02; // the first 2 bits must be 01xxxxxxxx -} - -/*! \brief init the management mac frame header - * \param p_hdr mac header - * \param subtype subtype of the frame - * \param p_ds destination address, don't care if it is a broadcast address - * \return none - * \pre the station has the following information in the pAd->StaCfg - * - bssid - * - station address - * \post - * \note this function initializes the following field - - IRQL = PASSIVE_LEVEL - IRQL = DISPATCH_LEVEL - - */ -VOID MgtMacHeaderInit( - IN PRTMP_ADAPTER pAd, - IN OUT PHEADER_802_11 pHdr80211, - IN UCHAR SubType, - IN UCHAR ToDs, - IN PUCHAR pDA, - IN PUCHAR pBssid) -{ - NdisZeroMemory(pHdr80211, sizeof(HEADER_802_11)); - - pHdr80211->FC.Type = BTYPE_MGMT; - pHdr80211->FC.SubType = SubType; -// if (SubType == SUBTYPE_ACK) // sample, no use, it will conflict with ACTION frame sub type -// pHdr80211->FC.Type = BTYPE_CNTL; - pHdr80211->FC.ToDs = ToDs; - COPY_MAC_ADDR(pHdr80211->Addr1, pDA); -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - COPY_MAC_ADDR(pHdr80211->Addr2, pAd->CurrentAddress); -#endif // CONFIG_STA_SUPPORT // - COPY_MAC_ADDR(pHdr80211->Addr3, pBssid); -} - -// =========================================================================================== -// mem_mgmt.c -// =========================================================================================== - -/*!*************************************************************************** - * This routine build an outgoing frame, and fill all information specified - * in argument list to the frame body. The actual frame size is the summation - * of all arguments. - * input params: - * Buffer - pointer to a pre-allocated memory segment - * args - a list of pairs. - * NOTE NOTE NOTE!!!! the last argument must be NULL, otherwise this - * function will FAIL!!! - * return: - * Size of the buffer - * usage: - * MakeOutgoingFrame(Buffer, output_length, 2, &fc, 2, &dur, 6, p_addr1, 6,p_addr2, END_OF_ARGS); - - IRQL = PASSIVE_LEVEL - IRQL = DISPATCH_LEVEL - - ****************************************************************************/ -ULONG MakeOutgoingFrame( - OUT CHAR *Buffer, - OUT ULONG *FrameLen, ...) -{ - CHAR *p; - int leng; - ULONG TotLeng; - va_list Args; - - // calculates the total length - TotLeng = 0; - va_start(Args, FrameLen); - do - { - leng = va_arg(Args, int); - if (leng == END_OF_ARGS) - { - break; - } - p = va_arg(Args, PVOID); - NdisMoveMemory(&Buffer[TotLeng], p, leng); - TotLeng = TotLeng + leng; - } while(TRUE); - - va_end(Args); /* clean up */ - *FrameLen = TotLeng; - return TotLeng; -} - -// =========================================================================================== -// mlme_queue.c -// =========================================================================================== - -/*! \brief Initialize The MLME Queue, used by MLME Functions - * \param *Queue The MLME Queue - * \return Always Return NDIS_STATE_SUCCESS in this implementation - * \pre - * \post - * \note Because this is done only once (at the init stage), no need to be locked - - IRQL = PASSIVE_LEVEL - - */ -NDIS_STATUS MlmeQueueInit( - IN MLME_QUEUE *Queue) -{ - INT i; - - NdisAllocateSpinLock(&Queue->Lock); - - Queue->Num = 0; - Queue->Head = 0; - Queue->Tail = 0; - - for (i = 0; i < MAX_LEN_OF_MLME_QUEUE; i++) - { - Queue->Entry[i].Occupied = FALSE; - Queue->Entry[i].MsgLen = 0; - NdisZeroMemory(Queue->Entry[i].Msg, MGMT_DMA_BUFFER_SIZE); - } - - return NDIS_STATUS_SUCCESS; -} - -/*! \brief Enqueue a message for other threads, if they want to send messages to MLME thread - * \param *Queue The MLME Queue - * \param Machine The State Machine Id - * \param MsgType The Message Type - * \param MsgLen The Message length - * \param *Msg The message pointer - * \return TRUE if enqueue is successful, FALSE if the queue is full - * \pre - * \post - * \note The message has to be initialized - - IRQL = PASSIVE_LEVEL - IRQL = DISPATCH_LEVEL - - */ -BOOLEAN MlmeEnqueue( - IN PRTMP_ADAPTER pAd, - IN ULONG Machine, - IN ULONG MsgType, - IN ULONG MsgLen, - IN VOID *Msg) -{ - INT Tail; - MLME_QUEUE *Queue = (MLME_QUEUE *)&pAd->Mlme.Queue; - - // Do nothing if the driver is starting halt state. - // This might happen when timer already been fired before cancel timer with mlmehalt - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) - return FALSE; - - // First check the size, it MUST not exceed the mlme queue size - if (MsgLen > MGMT_DMA_BUFFER_SIZE) - { - DBGPRINT_ERR(("MlmeEnqueue: msg too large, size = %ld \n", MsgLen)); - return FALSE; - } - - if (MlmeQueueFull(Queue)) - { - return FALSE; - } - - NdisAcquireSpinLock(&(Queue->Lock)); - Tail = Queue->Tail; - Queue->Tail++; - Queue->Num++; - if (Queue->Tail == MAX_LEN_OF_MLME_QUEUE) - { - Queue->Tail = 0; - } - - Queue->Entry[Tail].Wcid = RESERVED_WCID; - Queue->Entry[Tail].Occupied = TRUE; - Queue->Entry[Tail].Machine = Machine; - Queue->Entry[Tail].MsgType = MsgType; - Queue->Entry[Tail].MsgLen = MsgLen; - - if (Msg != NULL) - { - NdisMoveMemory(Queue->Entry[Tail].Msg, Msg, MsgLen); - } - - NdisReleaseSpinLock(&(Queue->Lock)); - return TRUE; -} - -/*! \brief This function is used when Recv gets a MLME message - * \param *Queue The MLME Queue - * \param TimeStampHigh The upper 32 bit of timestamp - * \param TimeStampLow The lower 32 bit of timestamp - * \param Rssi The receiving RSSI strength - * \param MsgLen The length of the message - * \param *Msg The message pointer - * \return TRUE if everything ok, FALSE otherwise (like Queue Full) - * \pre - * \post - - IRQL = DISPATCH_LEVEL - - */ -BOOLEAN MlmeEnqueueForRecv( - IN PRTMP_ADAPTER pAd, - IN ULONG Wcid, - IN ULONG TimeStampHigh, - IN ULONG TimeStampLow, - IN UCHAR Rssi0, - IN UCHAR Rssi1, - IN UCHAR Rssi2, - IN ULONG MsgLen, - IN VOID *Msg, - IN UCHAR Signal) -{ - INT Tail, Machine; - PFRAME_802_11 pFrame = (PFRAME_802_11)Msg; - INT MsgType; - MLME_QUEUE *Queue = (MLME_QUEUE *)&pAd->Mlme.Queue; - -#ifdef RALINK_ATE - /* Nothing to do in ATE mode */ - if(ATE_ON(pAd)) - return FALSE; -#endif // RALINK_ATE // - - // Do nothing if the driver is starting halt state. - // This might happen when timer already been fired before cancel timer with mlmehalt - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) - { - DBGPRINT_ERR(("MlmeEnqueueForRecv: fRTMP_ADAPTER_HALT_IN_PROGRESS\n")); - return FALSE; - } - - // First check the size, it MUST not exceed the mlme queue size - if (MsgLen > MGMT_DMA_BUFFER_SIZE) - { - DBGPRINT_ERR(("MlmeEnqueueForRecv: frame too large, size = %ld \n", MsgLen)); - return FALSE; - } - - if (MlmeQueueFull(Queue)) - { - return FALSE; - } - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - if (!MsgTypeSubst(pAd, pFrame, &Machine, &MsgType)) - { - DBGPRINT_ERR(("MlmeEnqueueForRecv: un-recongnized mgmt->subtype=%d\n",pFrame->Hdr.FC.SubType)); - return FALSE; - } - } -#endif // CONFIG_STA_SUPPORT // - - // OK, we got all the informations, it is time to put things into queue - NdisAcquireSpinLock(&(Queue->Lock)); - Tail = Queue->Tail; - Queue->Tail++; - Queue->Num++; - if (Queue->Tail == MAX_LEN_OF_MLME_QUEUE) - { - Queue->Tail = 0; - } - Queue->Entry[Tail].Occupied = TRUE; - Queue->Entry[Tail].Machine = Machine; - Queue->Entry[Tail].MsgType = MsgType; - Queue->Entry[Tail].MsgLen = MsgLen; - Queue->Entry[Tail].TimeStamp.u.LowPart = TimeStampLow; - Queue->Entry[Tail].TimeStamp.u.HighPart = TimeStampHigh; - Queue->Entry[Tail].Rssi0 = Rssi0; - Queue->Entry[Tail].Rssi1 = Rssi1; - Queue->Entry[Tail].Rssi2 = Rssi2; - Queue->Entry[Tail].Signal = Signal; - Queue->Entry[Tail].Wcid = (UCHAR)Wcid; - - Queue->Entry[Tail].Channel = pAd->LatchRfRegs.Channel; - - if (Msg != NULL) - { - NdisMoveMemory(Queue->Entry[Tail].Msg, Msg, MsgLen); - } - - NdisReleaseSpinLock(&(Queue->Lock)); - - RT28XX_MLME_HANDLER(pAd); - - return TRUE; -} - - -/*! \brief Dequeue a message from the MLME Queue - * \param *Queue The MLME Queue - * \param *Elem The message dequeued from MLME Queue - * \return TRUE if the Elem contains something, FALSE otherwise - * \pre - * \post - - IRQL = DISPATCH_LEVEL - - */ -BOOLEAN MlmeDequeue( - IN MLME_QUEUE *Queue, - OUT MLME_QUEUE_ELEM **Elem) -{ - NdisAcquireSpinLock(&(Queue->Lock)); - *Elem = &(Queue->Entry[Queue->Head]); - Queue->Num--; - Queue->Head++; - if (Queue->Head == MAX_LEN_OF_MLME_QUEUE) - { - Queue->Head = 0; - } - NdisReleaseSpinLock(&(Queue->Lock)); - return TRUE; -} - -// IRQL = DISPATCH_LEVEL -VOID MlmeRestartStateMachine( - IN PRTMP_ADAPTER pAd) -{ -#ifdef CONFIG_STA_SUPPORT - BOOLEAN Cancelled; -#endif // CONFIG_STA_SUPPORT // - - DBGPRINT(RT_DEBUG_TRACE, ("MlmeRestartStateMachine \n")); - - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { -#ifdef QOS_DLS_SUPPORT - UCHAR i; -#endif // QOS_DLS_SUPPORT // - // Cancel all timer events - // Be careful to cancel new added timer - RTMPCancelTimer(&pAd->MlmeAux.AssocTimer, &Cancelled); - RTMPCancelTimer(&pAd->MlmeAux.ReassocTimer, &Cancelled); - RTMPCancelTimer(&pAd->MlmeAux.DisassocTimer, &Cancelled); - RTMPCancelTimer(&pAd->MlmeAux.AuthTimer, &Cancelled); - RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer, &Cancelled); - RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &Cancelled); - -#ifdef QOS_DLS_SUPPORT - for (i=0; iStaCfg.DLSEntry[i].Timer, &Cancelled); - } -#endif // QOS_DLS_SUPPORT // - } -#endif // CONFIG_STA_SUPPORT // - - // Change back to original channel in case of doing scan - AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); - AsicLockChannel(pAd, pAd->CommonCfg.Channel); - - // Resume MSDU which is turned off durning scan - RTMPResumeMsduTransmission(pAd); - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - // Set all state machines back IDLE - pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; - pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; - pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; - pAd->Mlme.AuthRspMachine.CurrState = AUTH_RSP_IDLE; - pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; - pAd->Mlme.ActMachine.CurrState = ACT_IDLE; -#ifdef QOS_DLS_SUPPORT - pAd->Mlme.DlsMachine.CurrState = DLS_IDLE; -#endif // QOS_DLS_SUPPORT // - } -#endif // CONFIG_STA_SUPPORT // - -} - -/*! \brief test if the MLME Queue is empty - * \param *Queue The MLME Queue - * \return TRUE if the Queue is empty, FALSE otherwise - * \pre - * \post - - IRQL = DISPATCH_LEVEL - - */ -BOOLEAN MlmeQueueEmpty( - IN MLME_QUEUE *Queue) -{ - BOOLEAN Ans; - - NdisAcquireSpinLock(&(Queue->Lock)); - Ans = (Queue->Num == 0); - NdisReleaseSpinLock(&(Queue->Lock)); - - return Ans; -} - -/*! \brief test if the MLME Queue is full - * \param *Queue The MLME Queue - * \return TRUE if the Queue is empty, FALSE otherwise - * \pre - * \post - - IRQL = PASSIVE_LEVEL - IRQL = DISPATCH_LEVEL - - */ -BOOLEAN MlmeQueueFull( - IN MLME_QUEUE *Queue) -{ - BOOLEAN Ans; - - NdisAcquireSpinLock(&(Queue->Lock)); - Ans = (Queue->Num == MAX_LEN_OF_MLME_QUEUE || Queue->Entry[Queue->Tail].Occupied); - NdisReleaseSpinLock(&(Queue->Lock)); - - return Ans; -} - -/*! \brief The destructor of MLME Queue - * \param - * \return - * \pre - * \post - * \note Clear Mlme Queue, Set Queue->Num to Zero. - - IRQL = PASSIVE_LEVEL - - */ -VOID MlmeQueueDestroy( - IN MLME_QUEUE *pQueue) -{ - NdisAcquireSpinLock(&(pQueue->Lock)); - pQueue->Num = 0; - pQueue->Head = 0; - pQueue->Tail = 0; - NdisReleaseSpinLock(&(pQueue->Lock)); - NdisFreeSpinLock(&(pQueue->Lock)); -} - -/*! \brief To substitute the message type if the message is coming from external - * \param pFrame The frame received - * \param *Machine The state machine - * \param *MsgType the message type for the state machine - * \return TRUE if the substitution is successful, FALSE otherwise - * \pre - * \post - - IRQL = DISPATCH_LEVEL - - */ -#ifdef CONFIG_STA_SUPPORT -BOOLEAN MsgTypeSubst( - IN PRTMP_ADAPTER pAd, - IN PFRAME_802_11 pFrame, - OUT INT *Machine, - OUT INT *MsgType) -{ - USHORT Seq; - UCHAR EAPType; - PUCHAR pData; - - // Pointer to start of data frames including SNAP header - pData = (PUCHAR) pFrame + LENGTH_802_11; - - // The only data type will pass to this function is EAPOL frame - if (pFrame->Hdr.FC.Type == BTYPE_DATA) - { - if (NdisEqualMemory(SNAP_AIRONET, pData, LENGTH_802_1_H)) - { - // Cisco Aironet SNAP header - *Machine = AIRONET_STATE_MACHINE; - *MsgType = MT2_AIRONET_MSG; - return (TRUE); - } -#ifdef LEAP_SUPPORT - if ( pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP ) //LEAP - { - // LEAP frames - *Machine = LEAP_STATE_MACHINE; - EAPType = *((UCHAR*)pFrame + LENGTH_802_11 + LENGTH_802_1_H + 1); - return (LeapMsgTypeSubst(EAPType, MsgType)); - } - else -#endif // LEAP_SUPPORT // - { - *Machine = WPA_PSK_STATE_MACHINE; - EAPType = *((UCHAR*)pFrame + LENGTH_802_11 + LENGTH_802_1_H + 1); - return(WpaMsgTypeSubst(EAPType, MsgType)); - } - } - - switch (pFrame->Hdr.FC.SubType) - { - case SUBTYPE_ASSOC_REQ: - *Machine = ASSOC_STATE_MACHINE; - *MsgType = MT2_PEER_ASSOC_REQ; - break; - case SUBTYPE_ASSOC_RSP: - *Machine = ASSOC_STATE_MACHINE; - *MsgType = MT2_PEER_ASSOC_RSP; - break; - case SUBTYPE_REASSOC_REQ: - *Machine = ASSOC_STATE_MACHINE; - *MsgType = MT2_PEER_REASSOC_REQ; - break; - case SUBTYPE_REASSOC_RSP: - *Machine = ASSOC_STATE_MACHINE; - *MsgType = MT2_PEER_REASSOC_RSP; - break; - case SUBTYPE_PROBE_REQ: - *Machine = SYNC_STATE_MACHINE; - *MsgType = MT2_PEER_PROBE_REQ; - break; - case SUBTYPE_PROBE_RSP: - *Machine = SYNC_STATE_MACHINE; - *MsgType = MT2_PEER_PROBE_RSP; - break; - case SUBTYPE_BEACON: - *Machine = SYNC_STATE_MACHINE; - *MsgType = MT2_PEER_BEACON; - break; - case SUBTYPE_ATIM: - *Machine = SYNC_STATE_MACHINE; - *MsgType = MT2_PEER_ATIM; - break; - case SUBTYPE_DISASSOC: - *Machine = ASSOC_STATE_MACHINE; - *MsgType = MT2_PEER_DISASSOC_REQ; - break; - case SUBTYPE_AUTH: - // get the sequence number from payload 24 Mac Header + 2 bytes algorithm - NdisMoveMemory(&Seq, &pFrame->Octet[2], sizeof(USHORT)); - if (Seq == 1 || Seq == 3) - { - *Machine = AUTH_RSP_STATE_MACHINE; - *MsgType = MT2_PEER_AUTH_ODD; - } - else if (Seq == 2 || Seq == 4) - { - *Machine = AUTH_STATE_MACHINE; - *MsgType = MT2_PEER_AUTH_EVEN; - } - else - { - return FALSE; - } - break; - case SUBTYPE_DEAUTH: - *Machine = AUTH_RSP_STATE_MACHINE; - *MsgType = MT2_PEER_DEAUTH; - break; - case SUBTYPE_ACTION: - *Machine = ACTION_STATE_MACHINE; - // Sometimes Sta will return with category bytes with MSB = 1, if they receive catogory out of their support - if ((pFrame->Octet[0]&0x7F) > MAX_PEER_CATE_MSG) - { - *MsgType = MT2_ACT_INVALID; - } - else - { - *MsgType = (pFrame->Octet[0]&0x7F); - } - break; - default: - return FALSE; - break; - } - - return TRUE; -} -#endif // CONFIG_STA_SUPPORT // - -// =========================================================================================== -// state_machine.c -// =========================================================================================== - -/*! \brief Initialize the state machine. - * \param *S pointer to the state machine - * \param Trans State machine transition function - * \param StNr number of states - * \param MsgNr number of messages - * \param DefFunc default function, when there is invalid state/message combination - * \param InitState initial state of the state machine - * \param Base StateMachine base, internal use only - * \pre p_sm should be a legal pointer - * \post - - IRQL = PASSIVE_LEVEL - - */ -VOID StateMachineInit( - IN STATE_MACHINE *S, - IN STATE_MACHINE_FUNC Trans[], - IN ULONG StNr, - IN ULONG MsgNr, - IN STATE_MACHINE_FUNC DefFunc, - IN ULONG InitState, - IN ULONG Base) -{ - ULONG i, j; - - // set number of states and messages - S->NrState = StNr; - S->NrMsg = MsgNr; - S->Base = Base; - - S->TransFunc = Trans; - - // init all state transition to default function - for (i = 0; i < StNr; i++) - { - for (j = 0; j < MsgNr; j++) - { - S->TransFunc[i * MsgNr + j] = DefFunc; - } - } - - // set the starting state - S->CurrState = InitState; -} - -/*! \brief This function fills in the function pointer into the cell in the state machine - * \param *S pointer to the state machine - * \param St state - * \param Msg incoming message - * \param f the function to be executed when (state, message) combination occurs at the state machine - * \pre *S should be a legal pointer to the state machine, st, msg, should be all within the range, Base should be set in the initial state - * \post - - IRQL = PASSIVE_LEVEL - - */ -VOID StateMachineSetAction( - IN STATE_MACHINE *S, - IN ULONG St, - IN ULONG Msg, - IN STATE_MACHINE_FUNC Func) -{ - ULONG MsgIdx; - - MsgIdx = Msg - S->Base; - - if (St < S->NrState && MsgIdx < S->NrMsg) - { - // boundary checking before setting the action - S->TransFunc[St * S->NrMsg + MsgIdx] = Func; - } -} - -/*! \brief This function does the state transition - * \param *Adapter the NIC adapter pointer - * \param *S the state machine - * \param *Elem the message to be executed - * \return None - - IRQL = DISPATCH_LEVEL - - */ -VOID StateMachinePerformAction( - IN PRTMP_ADAPTER pAd, - IN STATE_MACHINE *S, - IN MLME_QUEUE_ELEM *Elem) -{ - (*(S->TransFunc[S->CurrState * S->NrMsg + Elem->MsgType - S->Base]))(pAd, Elem); -} - -/* - ========================================================================== - Description: - The drop function, when machine executes this, the message is simply - ignored. This function does nothing, the message is freed in - StateMachinePerformAction() - ========================================================================== - */ -VOID Drop( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ -} - -// =========================================================================================== -// lfsr.c -// =========================================================================================== - -/* - ========================================================================== - Description: - - IRQL = PASSIVE_LEVEL - - ========================================================================== - */ -VOID LfsrInit( - IN PRTMP_ADAPTER pAd, - IN ULONG Seed) -{ - if (Seed == 0) - pAd->Mlme.ShiftReg = 1; - else - pAd->Mlme.ShiftReg = Seed; -} - -/* - ========================================================================== - Description: - ========================================================================== - */ -UCHAR RandomByte( - IN PRTMP_ADAPTER pAd) -{ - ULONG i; - UCHAR R, Result; - - R = 0; - - if (pAd->Mlme.ShiftReg == 0) - NdisGetSystemUpTime((ULONG *)&pAd->Mlme.ShiftReg); - - for (i = 0; i < 8; i++) - { - if (pAd->Mlme.ShiftReg & 0x00000001) - { - pAd->Mlme.ShiftReg = ((pAd->Mlme.ShiftReg ^ LFSR_MASK) >> 1) | 0x80000000; - Result = 1; - } - else - { - pAd->Mlme.ShiftReg = pAd->Mlme.ShiftReg >> 1; - Result = 0; - } - R = (R << 1) | Result; - } - - return R; -} - -VOID AsicUpdateAutoFallBackTable( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pRateTable) -{ - UCHAR i; - HT_FBK_CFG0_STRUC HtCfg0; - HT_FBK_CFG1_STRUC HtCfg1; - LG_FBK_CFG0_STRUC LgCfg0; - LG_FBK_CFG1_STRUC LgCfg1; - PRTMP_TX_RATE_SWITCH pCurrTxRate, pNextTxRate; - - // set to initial value - HtCfg0.word = 0x65432100; - HtCfg1.word = 0xedcba988; - LgCfg0.word = 0xedcba988; - LgCfg1.word = 0x00002100; - - pNextTxRate = (PRTMP_TX_RATE_SWITCH)pRateTable+1; - for (i = 1; i < *((PUCHAR) pRateTable); i++) - { - pCurrTxRate = (PRTMP_TX_RATE_SWITCH)pRateTable+1+i; - switch (pCurrTxRate->Mode) - { - case 0: //CCK - break; - case 1: //OFDM - { - switch(pCurrTxRate->CurrMCS) - { - case 0: - LgCfg0.field.OFDMMCS0FBK = (pNextTxRate->Mode == MODE_OFDM) ? (pNextTxRate->CurrMCS+8): pNextTxRate->CurrMCS; - break; - case 1: - LgCfg0.field.OFDMMCS1FBK = (pNextTxRate->Mode == MODE_OFDM) ? (pNextTxRate->CurrMCS+8): pNextTxRate->CurrMCS; - break; - case 2: - LgCfg0.field.OFDMMCS2FBK = (pNextTxRate->Mode == MODE_OFDM) ? (pNextTxRate->CurrMCS+8): pNextTxRate->CurrMCS; - break; - case 3: - LgCfg0.field.OFDMMCS3FBK = (pNextTxRate->Mode == MODE_OFDM) ? (pNextTxRate->CurrMCS+8): pNextTxRate->CurrMCS; - break; - case 4: - LgCfg0.field.OFDMMCS4FBK = (pNextTxRate->Mode == MODE_OFDM) ? (pNextTxRate->CurrMCS+8): pNextTxRate->CurrMCS; - break; - case 5: - LgCfg0.field.OFDMMCS5FBK = (pNextTxRate->Mode == MODE_OFDM) ? (pNextTxRate->CurrMCS+8): pNextTxRate->CurrMCS; - break; - case 6: - LgCfg0.field.OFDMMCS6FBK = (pNextTxRate->Mode == MODE_OFDM) ? (pNextTxRate->CurrMCS+8): pNextTxRate->CurrMCS; - break; - case 7: - LgCfg0.field.OFDMMCS7FBK = (pNextTxRate->Mode == MODE_OFDM) ? (pNextTxRate->CurrMCS+8): pNextTxRate->CurrMCS; - break; - } - } - break; -#ifdef DOT11_N_SUPPORT - case 2: //HT-MIX - case 3: //HT-GF - { - if ((pNextTxRate->Mode >= MODE_HTMIX) && (pCurrTxRate->CurrMCS != pNextTxRate->CurrMCS)) - { - switch(pCurrTxRate->CurrMCS) - { - case 0: - HtCfg0.field.HTMCS0FBK = pNextTxRate->CurrMCS; - break; - case 1: - HtCfg0.field.HTMCS1FBK = pNextTxRate->CurrMCS; - break; - case 2: - HtCfg0.field.HTMCS2FBK = pNextTxRate->CurrMCS; - break; - case 3: - HtCfg0.field.HTMCS3FBK = pNextTxRate->CurrMCS; - break; - case 4: - HtCfg0.field.HTMCS4FBK = pNextTxRate->CurrMCS; - break; - case 5: - HtCfg0.field.HTMCS5FBK = pNextTxRate->CurrMCS; - break; - case 6: - HtCfg0.field.HTMCS6FBK = pNextTxRate->CurrMCS; - break; - case 7: - HtCfg0.field.HTMCS7FBK = pNextTxRate->CurrMCS; - break; - case 8: - HtCfg1.field.HTMCS8FBK = pNextTxRate->CurrMCS; - break; - case 9: - HtCfg1.field.HTMCS9FBK = pNextTxRate->CurrMCS; - break; - case 10: - HtCfg1.field.HTMCS10FBK = pNextTxRate->CurrMCS; - break; - case 11: - HtCfg1.field.HTMCS11FBK = pNextTxRate->CurrMCS; - break; - case 12: - HtCfg1.field.HTMCS12FBK = pNextTxRate->CurrMCS; - break; - case 13: - HtCfg1.field.HTMCS13FBK = pNextTxRate->CurrMCS; - break; - case 14: - HtCfg1.field.HTMCS14FBK = pNextTxRate->CurrMCS; - break; - case 15: - HtCfg1.field.HTMCS15FBK = pNextTxRate->CurrMCS; - break; - default: - DBGPRINT(RT_DEBUG_ERROR, ("AsicUpdateAutoFallBackTable: not support CurrMCS=%d\n", pCurrTxRate->CurrMCS)); - } - } - } - break; -#endif // DOT11_N_SUPPORT // - } - - pNextTxRate = pCurrTxRate; - } - - RTMP_IO_WRITE32(pAd, HT_FBK_CFG0, HtCfg0.word); - RTMP_IO_WRITE32(pAd, HT_FBK_CFG1, HtCfg1.word); - RTMP_IO_WRITE32(pAd, LG_FBK_CFG0, LgCfg0.word); - RTMP_IO_WRITE32(pAd, LG_FBK_CFG1, LgCfg1.word); -} - -/* - ======================================================================== - - Routine Description: - Set MAC register value according operation mode. - OperationMode AND bNonGFExist are for MM and GF Proteciton. - If MM or GF mask is not set, those passing argument doesn't not take effect. - - Operation mode meaning: - = 0 : Pure HT, no preotection. - = 0x01; there may be non-HT devices in both the control and extension channel, protection is optional in BSS. - = 0x10: No Transmission in 40M is protected. - = 0x11: Transmission in both 40M and 20M shall be protected - if (bNonGFExist) - we should choose not to use GF. But still set correct ASIC registers. - ======================================================================== -*/ -VOID AsicUpdateProtect( - IN PRTMP_ADAPTER pAd, - IN USHORT OperationMode, - IN UCHAR SetMask, - IN BOOLEAN bDisableBGProtect, - IN BOOLEAN bNonGFExist) -{ - PROT_CFG_STRUC ProtCfg, ProtCfg4; - UINT32 Protect[6]; - USHORT offset; - UCHAR i; - UINT32 MacReg = 0; - -#ifdef RALINK_ATE - if (ATE_ON(pAd)) - return; -#endif // RALINK_ATE // - -#ifdef DOT11_N_SUPPORT - if (!(pAd->CommonCfg.bHTProtect) && (OperationMode != 8)) - { - return; - } - - if (pAd->BATable.numAsOriginator) - { - // - // enable the RTS/CTS to avoid channel collision - // - SetMask = ALLN_SETPROTECT; - OperationMode = 8; - } -#endif // DOT11_N_SUPPORT // - - // Config ASIC RTS threshold register - RTMP_IO_READ32(pAd, TX_RTS_CFG, &MacReg); - MacReg &= 0xFF0000FF; -#if 0 - MacReg |= (pAd->CommonCfg.RtsThreshold << 8); -#else - // If the user want disable RtsThreshold and enbale Amsdu/Ralink-Aggregation, set the RtsThreshold as 4096 - if (( -#ifdef DOT11_N_SUPPORT - (pAd->CommonCfg.BACapability.field.AmsduEnable) || -#endif // DOT11_N_SUPPORT // - (pAd->CommonCfg.bAggregationCapable == TRUE)) - && pAd->CommonCfg.RtsThreshold == MAX_RTS_THRESHOLD) - { - MacReg |= (0x1000 << 8); - } - else - { - MacReg |= (pAd->CommonCfg.RtsThreshold << 8); - } -#endif - - RTMP_IO_WRITE32(pAd, TX_RTS_CFG, MacReg); - - // Initial common protection settings - RTMPZeroMemory(Protect, sizeof(Protect)); - ProtCfg4.word = 0; - ProtCfg.word = 0; - ProtCfg.field.TxopAllowGF40 = 1; - ProtCfg.field.TxopAllowGF20 = 1; - ProtCfg.field.TxopAllowMM40 = 1; - ProtCfg.field.TxopAllowMM20 = 1; - ProtCfg.field.TxopAllowOfdm = 1; - ProtCfg.field.TxopAllowCck = 1; - ProtCfg.field.RTSThEn = 1; - ProtCfg.field.ProtectNav = ASIC_SHORTNAV; - - // update PHY mode and rate - if (pAd->CommonCfg.Channel > 14) - ProtCfg.field.ProtectRate = 0x4000; - ProtCfg.field.ProtectRate |= pAd->CommonCfg.RtsRate; - - // Handle legacy(B/G) protection - if (bDisableBGProtect) - { - //ProtCfg.field.ProtectRate = pAd->CommonCfg.RtsRate; - ProtCfg.field.ProtectCtrl = 0; - Protect[0] = ProtCfg.word; - Protect[1] = ProtCfg.word; - } - else - { - //ProtCfg.field.ProtectRate = pAd->CommonCfg.RtsRate; - ProtCfg.field.ProtectCtrl = 0; // CCK do not need to be protected - Protect[0] = ProtCfg.word; - ProtCfg.field.ProtectCtrl = ASIC_CTS; // OFDM needs using CCK to protect - Protect[1] = ProtCfg.word; - } - -#ifdef DOT11_N_SUPPORT - // Decide HT frame protection. - if ((SetMask & ALLN_SETPROTECT) != 0) - { - switch(OperationMode) - { - case 0x0: - // NO PROTECT - // 1.All STAs in the BSS are 20/40 MHz HT - // 2. in ai 20/40MHz BSS - // 3. all STAs are 20MHz in a 20MHz BSS - // Pure HT. no protection. - - // MM20_PROT_CFG - // Reserved (31:27) - // PROT_TXOP(25:20) -- 010111 - // PROT_NAV(19:18) -- 01 (Short NAV protection) - // PROT_CTRL(17:16) -- 00 (None) - // PROT_RATE(15:0) -- 0x4004 (OFDM 24M) - Protect[2] = 0x01744004; - - // MM40_PROT_CFG - // Reserved (31:27) - // PROT_TXOP(25:20) -- 111111 - // PROT_NAV(19:18) -- 01 (Short NAV protection) - // PROT_CTRL(17:16) -- 00 (None) - // PROT_RATE(15:0) -- 0x4084 (duplicate OFDM 24M) - Protect[3] = 0x03f44084; - - // CF20_PROT_CFG - // Reserved (31:27) - // PROT_TXOP(25:20) -- 010111 - // PROT_NAV(19:18) -- 01 (Short NAV protection) - // PROT_CTRL(17:16) -- 00 (None) - // PROT_RATE(15:0) -- 0x4004 (OFDM 24M) - Protect[4] = 0x01744004; - - // CF40_PROT_CFG - // Reserved (31:27) - // PROT_TXOP(25:20) -- 111111 - // PROT_NAV(19:18) -- 01 (Short NAV protection) - // PROT_CTRL(17:16) -- 00 (None) - // PROT_RATE(15:0) -- 0x4084 (duplicate OFDM 24M) - Protect[5] = 0x03f44084; - - if (bNonGFExist) - { - // PROT_NAV(19:18) -- 01 (Short NAV protectiion) - // PROT_CTRL(17:16) -- 01 (RTS/CTS) - Protect[4] = 0x01754004; - Protect[5] = 0x03f54084; - } - pAd->CommonCfg.IOTestParm.bRTSLongProtOn = FALSE; - break; - - case 1: - // This is "HT non-member protection mode." - // If there may be non-HT STAs my BSS - ProtCfg.word = 0x01744004; // PROT_CTRL(17:16) : 0 (None) - ProtCfg4.word = 0x03f44084; // duplicaet legacy 24M. BW set 1. - if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_BG_PROTECTION_INUSED)) - { - ProtCfg.word = 0x01740003; //ERP use Protection bit is set, use protection rate at Clause 18.. - ProtCfg4.word = 0x03f40003; // Don't duplicate RTS/CTS in CCK mode. 0x03f40083; - } - //Assign Protection method for 20&40 MHz packets - ProtCfg.field.ProtectCtrl = ASIC_RTS; - ProtCfg.field.ProtectNav = ASIC_SHORTNAV; - ProtCfg4.field.ProtectCtrl = ASIC_RTS; - ProtCfg4.field.ProtectNav = ASIC_SHORTNAV; - Protect[2] = ProtCfg.word; - Protect[3] = ProtCfg4.word; - Protect[4] = ProtCfg.word; - Protect[5] = ProtCfg4.word; - pAd->CommonCfg.IOTestParm.bRTSLongProtOn = TRUE; - break; - - case 2: - // If only HT STAs are in BSS. at least one is 20MHz. Only protect 40MHz packets - ProtCfg.word = 0x01744004; // PROT_CTRL(17:16) : 0 (None) - ProtCfg4.word = 0x03f44084; // duplicaet legacy 24M. BW set 1. - - //Assign Protection method for 40MHz packets - ProtCfg4.field.ProtectCtrl = ASIC_RTS; - ProtCfg4.field.ProtectNav = ASIC_SHORTNAV; - Protect[2] = ProtCfg.word; - Protect[3] = ProtCfg4.word; - if (bNonGFExist) - { - ProtCfg.field.ProtectCtrl = ASIC_RTS; - ProtCfg.field.ProtectNav = ASIC_SHORTNAV; - } - Protect[4] = ProtCfg.word; - Protect[5] = ProtCfg4.word; - - pAd->CommonCfg.IOTestParm.bRTSLongProtOn = FALSE; - break; - - case 3: - // HT mixed mode. PROTECT ALL! - // Assign Rate - ProtCfg.word = 0x01744004; //duplicaet legacy 24M. BW set 1. - ProtCfg4.word = 0x03f44084; - // both 20MHz and 40MHz are protected. Whether use RTS or CTS-to-self depends on the - if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_BG_PROTECTION_INUSED)) - { - ProtCfg.word = 0x01740003; //ERP use Protection bit is set, use protection rate at Clause 18.. - ProtCfg4.word = 0x03f40003; // Don't duplicate RTS/CTS in CCK mode. 0x03f40083 - } - //Assign Protection method for 20&40 MHz packets - ProtCfg.field.ProtectCtrl = ASIC_RTS; - ProtCfg.field.ProtectNav = ASIC_SHORTNAV; - ProtCfg4.field.ProtectCtrl = ASIC_RTS; - ProtCfg4.field.ProtectNav = ASIC_SHORTNAV; - Protect[2] = ProtCfg.word; - Protect[3] = ProtCfg4.word; - Protect[4] = ProtCfg.word; - Protect[5] = ProtCfg4.word; - pAd->CommonCfg.IOTestParm.bRTSLongProtOn = TRUE; - break; - - case 8: - // Special on for Atheros problem n chip. - Protect[2] = 0x01754004; - Protect[3] = 0x03f54084; - Protect[4] = 0x01754004; - Protect[5] = 0x03f54084; - pAd->CommonCfg.IOTestParm.bRTSLongProtOn = TRUE; - break; - } - } -#endif // DOT11_N_SUPPORT // - - offset = CCK_PROT_CFG; - for (i = 0;i < 6;i++) - { - if ((SetMask & (1<< i))) - { - RTMP_IO_WRITE32(pAd, offset + i*4, Protect[i]); - } - } -} - -/* - ========================================================================== - Description: - - IRQL = PASSIVE_LEVEL - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID AsicSwitchChannel( - IN PRTMP_ADAPTER pAd, - IN UCHAR Channel, - IN BOOLEAN bScan) -{ - ULONG R2 = 0, R3 = DEFAULT_RF_TX_POWER, R4 = 0; - CHAR TxPwer = 0, TxPwer2 = DEFAULT_RF_TX_POWER; //Bbp94 = BBPR94_DEFAULT, TxPwer2 = DEFAULT_RF_TX_POWER; - UCHAR index; - UINT32 Value = 0; //BbpReg, Value; - RTMP_RF_REGS *RFRegTable; - - // Search Tx power value - for (index = 0; index < pAd->ChannelListNum; index++) - { - if (Channel == pAd->ChannelList[index].Channel) - { - TxPwer = pAd->ChannelList[index].Power; - TxPwer2 = pAd->ChannelList[index].Power2; - break; - } - } - - if (index == MAX_NUM_OF_CHANNELS) - { - DBGPRINT(RT_DEBUG_ERROR, ("AsicSwitchChannel: Cant find the Channel#%d \n", Channel)); - } - -#ifdef RT2870 - // The RF programming sequence is difference between 3xxx and 2xxx - if (IS_RT3070(pAd) && ((pAd->RfIcType == RFIC_3020) || (pAd->RfIcType == RFIC_2020))) - { - /* modify by WY for Read RF Reg. error */ - UCHAR RFValue; - - for (index = 0; index < NUM_OF_3020_CHNL; index++) - { - if (Channel == FreqItems3020[index].Channel) - { - // Programming channel parameters - RT30xxWriteRFRegister(pAd, RF_R02, FreqItems3020[index].N); - RT30xxWriteRFRegister(pAd, RF_R03, FreqItems3020[index].K); - - RT30xxReadRFRegister(pAd, RF_R06, (PUCHAR)&RFValue); - RFValue = (RFValue & 0xFC) | FreqItems3020[index].R; - RT30xxWriteRFRegister(pAd, RF_R06, (UCHAR)RFValue); - - // Set Tx Power - RT30xxReadRFRegister(pAd, RF_R12, (PUCHAR)&RFValue); - RFValue = (RFValue & 0xE0) | TxPwer; - RT30xxWriteRFRegister(pAd, RF_R12, (UCHAR)RFValue); - - // Set RF offset - RT30xxReadRFRegister(pAd, RF_R23, (PUCHAR)&RFValue); - RFValue = (RFValue & 0x80) | pAd->RfFreqOffset; - RT30xxWriteRFRegister(pAd, RF_R23, (UCHAR)RFValue); - - // Set BW - if (!bScan && (pAd->CommonCfg.BBPCurrentBW == BW_40)) - { - RFValue = pAd->Mlme.CaliBW40RfR24; - //DISABLE_11N_CHECK(pAd); - } - else - { - RFValue = pAd->Mlme.CaliBW20RfR24; - } - RT30xxWriteRFRegister(pAd, RF_R24, (UCHAR)RFValue); - - // Enable RF tuning - RT30xxReadRFRegister(pAd, RF_R07, (PUCHAR)&RFValue); - RFValue = RFValue | 0x1; - RT30xxWriteRFRegister(pAd, RF_R07, (UCHAR)RFValue); - - // latch channel for future usage. - pAd->LatchRfRegs.Channel = Channel; - - break; - } - } - - DBGPRINT(RT_DEBUG_TRACE, ("SwitchChannel#%d(RF=%d, Pwr0=%d, Pwr1=%d, %dT), N=0x%02X, K=0x%02X, R=0x%02X\n", - Channel, - pAd->RfIcType, - TxPwer, - TxPwer2, - pAd->Antenna.field.TxPath, - FreqItems3020[index].N, - FreqItems3020[index].K, - FreqItems3020[index].R)); - } - else -#endif // RT2870 // - { - RFRegTable = RF2850RegTable; - - switch (pAd->RfIcType) - { - case RFIC_2820: - case RFIC_2850: - case RFIC_2720: - case RFIC_2750: - - for (index = 0; index < NUM_OF_2850_CHNL; index++) - { - if (Channel == RFRegTable[index].Channel) - { - R2 = RFRegTable[index].R2; - if (pAd->Antenna.field.TxPath == 1) - { - R2 |= 0x4000; // If TXpath is 1, bit 14 = 1; - } - - if (pAd->Antenna.field.RxPath == 2) - { - R2 |= 0x40; // write 1 to off Rxpath. - } - else if (pAd->Antenna.field.RxPath == 1) - { - R2 |= 0x20040; // write 1 to off RxPath - } - - if (Channel > 14) - { - // initialize R3, R4 - R3 = (RFRegTable[index].R3 & 0xffffc1ff); - R4 = (RFRegTable[index].R4 & (~0x001f87c0)) | (pAd->RfFreqOffset << 15); - - // 5G band power range: 0xF9~0X0F, TX0 Reg3 bit9/TX1 Reg4 bit6="0" means the TX power reduce 7dB - // R3 - if ((TxPwer >= -7) && (TxPwer < 0)) - { - TxPwer = (7+TxPwer); - TxPwer = (TxPwer > 0xF) ? (0xF) : (TxPwer); - R3 |= (TxPwer << 10); - DBGPRINT(RT_DEBUG_ERROR, ("AsicSwitchChannel: TxPwer=%d \n", TxPwer)); - } - else - { - TxPwer = (TxPwer > 0xF) ? (0xF) : (TxPwer); - R3 |= (TxPwer << 10) | (1 << 9); - } - - // R4 - if ((TxPwer2 >= -7) && (TxPwer2 < 0)) - { - TxPwer2 = (7+TxPwer2); - TxPwer2 = (TxPwer2 > 0xF) ? (0xF) : (TxPwer2); - R4 |= (TxPwer2 << 7); - DBGPRINT(RT_DEBUG_ERROR, ("AsicSwitchChannel: TxPwer2=%d \n", TxPwer2)); - } - else - { - TxPwer2 = (TxPwer2 > 0xF) ? (0xF) : (TxPwer2); - R4 |= (TxPwer2 << 7) | (1 << 6); - } - } - else - { - R3 = (RFRegTable[index].R3 & 0xffffc1ff) | (TxPwer << 9); // set TX power0 - R4 = (RFRegTable[index].R4 & (~0x001f87c0)) | (pAd->RfFreqOffset << 15) | (TxPwer2 <<6);// Set freq Offset & TxPwr1 - } - - // Based on BBP current mode before changing RF channel. - if (!bScan && (pAd->CommonCfg.BBPCurrentBW == BW_40)) - { - R4 |=0x200000; - } - - // Update variables - pAd->LatchRfRegs.Channel = Channel; - pAd->LatchRfRegs.R1 = RFRegTable[index].R1; - pAd->LatchRfRegs.R2 = R2; - pAd->LatchRfRegs.R3 = R3; - pAd->LatchRfRegs.R4 = R4; - - // Set RF value 1's set R3[bit2] = [0] - RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R1); - RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R2); - RTMP_RF_IO_WRITE32(pAd, (pAd->LatchRfRegs.R3 & (~0x04))); - RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R4); - - RTMPusecDelay(200); - - // Set RF value 2's set R3[bit2] = [1] - RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R1); - RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R2); - RTMP_RF_IO_WRITE32(pAd, (pAd->LatchRfRegs.R3 | 0x04)); - RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R4); - - RTMPusecDelay(200); - - // Set RF value 3's set R3[bit2] = [0] - RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R1); - RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R2); - RTMP_RF_IO_WRITE32(pAd, (pAd->LatchRfRegs.R3 & (~0x04))); - RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R4); - - break; - } - } - break; - - default: - break; - } - } - - // Change BBP setting during siwtch from a->g, g->a - if (Channel <= 14) - { - ULONG TxPinCfg = 0x00050F0A;//Gary 2007/08/09 0x050A0A - - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R62, (0x37 - GET_LNA_GAIN(pAd))); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R63, (0x37 - GET_LNA_GAIN(pAd))); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R64, (0x37 - GET_LNA_GAIN(pAd))); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R86, 0);//(0x44 - GET_LNA_GAIN(pAd))); // According the Rory's suggestion to solve the middle range issue. - //RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R82, 0x62); - - // Rx High power VGA offset for LNA select - if (pAd->NicConfig2.field.ExternalLNAForG) - { - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R82, 0x62); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R75, 0x46); - } - else - { - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R82, 0x84); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R75, 0x50); - } - - // 5G band selection PIN, bit1 and bit2 are complement - RTMP_IO_READ32(pAd, TX_BAND_CFG, &Value); - Value &= (~0x6); - Value |= (0x04); - RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Value); - - // Turn off unused PA or LNA when only 1T or 1R - if (pAd->Antenna.field.TxPath == 1) - { - TxPinCfg &= 0xFFFFFFF3; - } - if (pAd->Antenna.field.RxPath == 1) - { - TxPinCfg &= 0xFFFFF3FF; - } - - RTMP_IO_WRITE32(pAd, TX_PIN_CFG, TxPinCfg); - } - else - { - ULONG TxPinCfg = 0x00050F05;//Gary 2007/8/9 0x050505 - - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R62, (0x37 - GET_LNA_GAIN(pAd))); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R63, (0x37 - GET_LNA_GAIN(pAd))); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R64, (0x37 - GET_LNA_GAIN(pAd))); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R86, 0);//(0x44 - GET_LNA_GAIN(pAd))); // According the Rory's suggestion to solve the middle range issue. - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R82, 0xF2); - - // Rx High power VGA offset for LNA select - if (pAd->NicConfig2.field.ExternalLNAForA) - { - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R75, 0x46); - } - else - { - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R75, 0x50); - } - - // 5G band selection PIN, bit1 and bit2 are complement - RTMP_IO_READ32(pAd, TX_BAND_CFG, &Value); - Value &= (~0x6); - Value |= (0x02); - RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Value); - - // Turn off unused PA or LNA when only 1T or 1R - if (pAd->Antenna.field.TxPath == 1) - { - TxPinCfg &= 0xFFFFFFF3; - } - if (pAd->Antenna.field.RxPath == 1) - { - TxPinCfg &= 0xFFFFF3FF; - } - - RTMP_IO_WRITE32(pAd, TX_PIN_CFG, TxPinCfg); - } - - // R66 should be set according to Channel and use 20MHz when scanning - //RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, (0x2E + GET_LNA_GAIN(pAd))); - if (bScan) - RTMPSetAGCInitValue(pAd, BW_20); - else - RTMPSetAGCInitValue(pAd, pAd->CommonCfg.BBPCurrentBW); - - // - // On 11A, We should delay and wait RF/BBP to be stable - // and the appropriate time should be 1000 micro seconds - // 2005/06/05 - On 11G, We also need this delay time. Otherwise it's difficult to pass the WHQL. - // - RTMPusecDelay(1000); - - DBGPRINT(RT_DEBUG_TRACE, ("SwitchChannel#%d(RF=%d, Pwr0=%lu, Pwr1=%lu, %dT) to , R1=0x%08lx, R2=0x%08lx, R3=0x%08lx, R4=0x%08lx\n", - Channel, - pAd->RfIcType, - (R3 & 0x00003e00) >> 9, - (R4 & 0x000007c0) >> 6, - pAd->Antenna.field.TxPath, - pAd->LatchRfRegs.R1, - pAd->LatchRfRegs.R2, - pAd->LatchRfRegs.R3, - pAd->LatchRfRegs.R4)); -} - -/* - ========================================================================== - Description: - This function is required for 2421 only, and should not be used during - site survey. It's only required after NIC decided to stay at a channel - for a longer period. - When this function is called, it's always after AsicSwitchChannel(). - - IRQL = PASSIVE_LEVEL - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID AsicLockChannel( - IN PRTMP_ADAPTER pAd, - IN UCHAR Channel) -{ -} - -/* - ========================================================================== - Description: - - IRQL = PASSIVE_LEVEL - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID AsicAntennaSelect( - IN PRTMP_ADAPTER pAd, - IN UCHAR Channel) -{ -} - -/* - ======================================================================== - - Routine Description: - Antenna miscellaneous setting. - - Arguments: - pAd Pointer to our adapter - BandState Indicate current Band State. - - Return Value: - None - - IRQL <= DISPATCH_LEVEL - - Note: - 1.) Frame End type control - only valid for G only (RF_2527 & RF_2529) - 0: means DPDT, set BBP R4 bit 5 to 1 - 1: means SPDT, set BBP R4 bit 5 to 0 - - - ======================================================================== -*/ -VOID AsicAntennaSetting( - IN PRTMP_ADAPTER pAd, - IN ABGBAND_STATE BandState) -{ -} - -VOID AsicRfTuningExec( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3) -{ -} - -/* - ========================================================================== - Description: - Gives CCK TX rate 2 more dB TX power. - This routine works only in LINK UP in INFRASTRUCTURE mode. - - calculate desired Tx power in RF R3.Tx0~5, should consider - - 0. if current radio is a noisy environment (pAd->DrsCounters.fNoisyEnvironment) - 1. TxPowerPercentage - 2. auto calibration based on TSSI feedback - 3. extra 2 db for CCK - 4. -10 db upon very-short distance (AvgRSSI >= -40db) to AP - - NOTE: Since this routine requires the value of (pAd->DrsCounters.fNoisyEnvironment), - it should be called AFTER MlmeDynamicTxRatSwitching() - ========================================================================== - */ -VOID AsicAdjustTxPower( - IN PRTMP_ADAPTER pAd) -{ - INT i, j; - CHAR DeltaPwr = 0; - BOOLEAN bAutoTxAgc = FALSE; - UCHAR TssiRef, *pTssiMinusBoundary, *pTssiPlusBoundary, TxAgcStep; - UCHAR BbpR1 = 0, BbpR49 = 0, idx; - PCHAR pTxAgcCompensate; - ULONG TxPwr[5]; - CHAR Value; - - if (pAd->CommonCfg.BBPCurrentBW == BW_40) - { - if (pAd->CommonCfg.CentralChannel > 14) - { - TxPwr[0] = pAd->Tx40MPwrCfgABand[0]; - TxPwr[1] = pAd->Tx40MPwrCfgABand[1]; - TxPwr[2] = pAd->Tx40MPwrCfgABand[2]; - TxPwr[3] = pAd->Tx40MPwrCfgABand[3]; - TxPwr[4] = pAd->Tx40MPwrCfgABand[4]; - } - else - { - TxPwr[0] = pAd->Tx40MPwrCfgGBand[0]; - TxPwr[1] = pAd->Tx40MPwrCfgGBand[1]; - TxPwr[2] = pAd->Tx40MPwrCfgGBand[2]; - TxPwr[3] = pAd->Tx40MPwrCfgGBand[3]; - TxPwr[4] = pAd->Tx40MPwrCfgGBand[4]; - } - } - else - { - if (pAd->CommonCfg.Channel > 14) - { - TxPwr[0] = pAd->Tx20MPwrCfgABand[0]; - TxPwr[1] = pAd->Tx20MPwrCfgABand[1]; - TxPwr[2] = pAd->Tx20MPwrCfgABand[2]; - TxPwr[3] = pAd->Tx20MPwrCfgABand[3]; - TxPwr[4] = pAd->Tx20MPwrCfgABand[4]; - } - else - { - TxPwr[0] = pAd->Tx20MPwrCfgGBand[0]; - TxPwr[1] = pAd->Tx20MPwrCfgGBand[1]; - TxPwr[2] = pAd->Tx20MPwrCfgGBand[2]; - TxPwr[3] = pAd->Tx20MPwrCfgGBand[3]; - TxPwr[4] = pAd->Tx20MPwrCfgGBand[4]; - } - } - - // TX power compensation for temperature variation based on TSSI. try every 4 second - if (pAd->Mlme.OneSecPeriodicRound % 4 == 0) - { - if (pAd->CommonCfg.Channel <= 14) - { - /* bg channel */ - bAutoTxAgc = pAd->bAutoTxAgcG; - TssiRef = pAd->TssiRefG; - pTssiMinusBoundary = &pAd->TssiMinusBoundaryG[0]; - pTssiPlusBoundary = &pAd->TssiPlusBoundaryG[0]; - TxAgcStep = pAd->TxAgcStepG; - pTxAgcCompensate = &pAd->TxAgcCompensateG; - } - else - { - /* a channel */ - bAutoTxAgc = pAd->bAutoTxAgcA; - TssiRef = pAd->TssiRefA; - pTssiMinusBoundary = &pAd->TssiMinusBoundaryA[0]; - pTssiPlusBoundary = &pAd->TssiPlusBoundaryA[0]; - TxAgcStep = pAd->TxAgcStepA; - pTxAgcCompensate = &pAd->TxAgcCompensateA; - } - - if (bAutoTxAgc) - { - /* BbpR1 is unsigned char */ - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R49, &BbpR49); - - /* (p) TssiPlusBoundaryG[0] = 0 = (m) TssiMinusBoundaryG[0] */ - /* compensate: +4 +3 +2 +1 0 -1 -2 -3 -4 * steps */ - /* step value is defined in pAd->TxAgcStepG for tx power value */ - - /* [4]+1+[4] p4 p3 p2 p1 o1 m1 m2 m3 m4 */ - /* ex: 0x00 0x15 0x25 0x45 0x88 0xA0 0xB5 0xD0 0xF0 - above value are examined in mass factory production */ - /* [4] [3] [2] [1] [0] [1] [2] [3] [4] */ - - /* plus (+) is 0x00 ~ 0x45, minus (-) is 0xa0 ~ 0xf0 */ - /* if value is between p1 ~ o1 or o1 ~ s1, no need to adjust tx power */ - /* if value is 0xa5, tx power will be -= TxAgcStep*(2-1) */ - - if (BbpR49 > pTssiMinusBoundary[1]) - { - // Reading is larger than the reference value - // check for how large we need to decrease the Tx power - for (idx = 1; idx < 5; idx++) - { - if (BbpR49 <= pTssiMinusBoundary[idx]) // Found the range - break; - } - // The index is the step we should decrease, idx = 0 means there is nothing to compensate -// if (R3 > (ULONG) (TxAgcStep * (idx-1))) - *pTxAgcCompensate = -(TxAgcStep * (idx-1)); -// else -// *pTxAgcCompensate = -((UCHAR)R3); - - DeltaPwr += (*pTxAgcCompensate); - DBGPRINT(RT_DEBUG_TRACE, ("-- Tx Power, BBP R1=%x, TssiRef=%x, TxAgcStep=%x, step = -%d\n", - BbpR49, TssiRef, TxAgcStep, idx-1)); - } - else if (BbpR49 < pTssiPlusBoundary[1]) - { - // Reading is smaller than the reference value - // check for how large we need to increase the Tx power - for (idx = 1; idx < 5; idx++) - { - if (BbpR49 >= pTssiPlusBoundary[idx]) // Found the range - break; - } - // The index is the step we should increase, idx = 0 means there is nothing to compensate - *pTxAgcCompensate = TxAgcStep * (idx-1); - DeltaPwr += (*pTxAgcCompensate); - DBGPRINT(RT_DEBUG_TRACE, ("++ Tx Power, BBP R1=%x, TssiRef=%x, TxAgcStep=%x, step = +%d\n", - BbpR49, TssiRef, TxAgcStep, idx-1)); - } - else - { - *pTxAgcCompensate = 0; - DBGPRINT(RT_DEBUG_TRACE, (" Tx Power, BBP R49=%x, TssiRef=%x, TxAgcStep=%x, step = +%d\n", - BbpR49, TssiRef, TxAgcStep, 0)); - } - } - } - else - { - if (pAd->CommonCfg.Channel <= 14) - { - bAutoTxAgc = pAd->bAutoTxAgcG; - pTxAgcCompensate = &pAd->TxAgcCompensateG; - } - else - { - bAutoTxAgc = pAd->bAutoTxAgcA; - pTxAgcCompensate = &pAd->TxAgcCompensateA; - } - - if (bAutoTxAgc) - DeltaPwr += (*pTxAgcCompensate); - } - - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R1, &BbpR1); - BbpR1 &= 0xFC; - -#ifdef SINGLE_SKU - // Handle regulatory max tx power constrain - do - { - UCHAR TxPwrInEEPROM = 0xFF, CountryTxPwr = 0xFF, criterion; - UCHAR AdjustMaxTxPwr[40]; - - if (pAd->CommonCfg.Channel > 14) // 5G band - TxPwrInEEPROM = ((pAd->CommonCfg.DefineMaxTxPwr & 0xFF00) >> 8); - else // 2.4G band - TxPwrInEEPROM = (pAd->CommonCfg.DefineMaxTxPwr & 0x00FF); - CountryTxPwr = GetCuntryMaxTxPwr(pAd, pAd->CommonCfg.Channel); - - // error handling, range check - if ((TxPwrInEEPROM > 0x50) || (CountryTxPwr > 0x50)) - { - DBGPRINT(RT_DEBUG_ERROR,("AsicAdjustTxPower - Invalid max tx power (=0x%02x), CountryTxPwr=%d\n", TxPwrInEEPROM, CountryTxPwr)); - break; - } - - criterion = *((PUCHAR)TxPwr + 2) & 0xF; // FAE use OFDM 6M as criterion - - DBGPRINT_RAW(RT_DEBUG_TRACE,("AsicAdjustTxPower (criterion=%d, TxPwrInEEPROM=%d, CountryTxPwr=%d)\n", criterion, TxPwrInEEPROM, CountryTxPwr)); - - // Adjust max tx power according to the relationship of tx power in E2PROM - for (i=0; i<5; i++) - { - // CCK will have 4dBm larger than OFDM - // Therefore, we should separate to parse the tx power field - if (i == 0) - { - for (j=0; j<8; j++) - { - Value = (CHAR)((TxPwr[i] >> j*4) & 0x0F); - - if (j < 4) - { - // CCK will have 4dBm larger than OFDM - AdjustMaxTxPwr[i*8+j] = TxPwrInEEPROM + (Value - criterion) + 4; - } - else - { - AdjustMaxTxPwr[i*8+j] = TxPwrInEEPROM + (Value - criterion); - } - DBGPRINT_RAW(RT_DEBUG_TRACE,("AsicAdjustTxPower (i/j=%d/%d, Value=%d, %d)\n", i, j, Value, AdjustMaxTxPwr[i*8+j])); - } - } - else - { - for (j=0; j<8; j++) - { - Value = (CHAR)((TxPwr[i] >> j*4) & 0x0F); - - AdjustMaxTxPwr[i*8+j] = TxPwrInEEPROM + (Value - criterion); - DBGPRINT_RAW(RT_DEBUG_TRACE,("AsicAdjustTxPower (i/j=%d/%d, Value=%d, %d)\n", i, j, Value, AdjustMaxTxPwr[i*8+j])); - } - } - } - - // Adjust tx power according to the relationship - for (i=0; i<5; i++) - { - if (TxPwr[i] != 0xffffffff) - { - for (j=0; j<8; j++) - { - Value = (CHAR)((TxPwr[i] >> j*4) & 0x0F); - - // The system tx power is larger than the regulatory, the power should be restrain - if (AdjustMaxTxPwr[i*8+j] > CountryTxPwr) - { - // decrease to zero and don't need to take care BBPR1 - if ((Value - (AdjustMaxTxPwr[i*8+j] - CountryTxPwr)) > 0) - Value -= (AdjustMaxTxPwr[i*8+j] - CountryTxPwr); - else - Value = 0; - - DBGPRINT_RAW(RT_DEBUG_TRACE,("AsicAdjustTxPower (i/j=%d/%d, Value=%d, %d)\n", i, j, Value, AdjustMaxTxPwr[i*8+j])); - } - else - DBGPRINT_RAW(RT_DEBUG_TRACE,("AsicAdjustTxPower (i/j=%d/%d, Value=%d, %d, no change)\n", i, j, Value, AdjustMaxTxPwr[i*8+j])); - - TxPwr[i] = (TxPwr[i] & ~(0x0000000F << j*4)) | (Value << j*4); - } - } - } - } while (FALSE); -#endif // SINGLE_SKU // - - /* calculate delta power based on the percentage specified from UI */ - // E2PROM setting is calibrated for maximum TX power (i.e. 100%) - // We lower TX power here according to the percentage specified from UI - if (pAd->CommonCfg.TxPowerPercentage == 0xffffffff) // AUTO TX POWER control - ; - else if (pAd->CommonCfg.TxPowerPercentage > 90) // 91 ~ 100% & AUTO, treat as 100% in terms of mW - ; - else if (pAd->CommonCfg.TxPowerPercentage > 60) // 61 ~ 90%, treat as 75% in terms of mW // DeltaPwr -= 1; - { - DeltaPwr -= 1; - } - else if (pAd->CommonCfg.TxPowerPercentage > 30) // 31 ~ 60%, treat as 50% in terms of mW // DeltaPwr -= 3; - { - DeltaPwr -= 3; - } - else if (pAd->CommonCfg.TxPowerPercentage > 15) // 16 ~ 30%, treat as 25% in terms of mW // DeltaPwr -= 6; - { - BbpR1 |= 0x01; - } - else if (pAd->CommonCfg.TxPowerPercentage > 9) // 10 ~ 15%, treat as 12.5% in terms of mW // DeltaPwr -= 9; - { - BbpR1 |= 0x01; - DeltaPwr -= 3; - } - else // 0 ~ 9 %, treat as MIN(~3%) in terms of mW // DeltaPwr -= 12; - { - BbpR1 |= 0x02; - } - - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R1, BbpR1); - - /* reset different new tx power for different TX rate */ - for(i=0; i<5; i++) - { - if (TxPwr[i] != 0xffffffff) - { - for (j=0; j<8; j++) - { - Value = (CHAR)((TxPwr[i] >> j*4) & 0x0F); /* 0 ~ 15 */ - - if ((Value + DeltaPwr) < 0) - { - Value = 0; /* min */ - } - else if ((Value + DeltaPwr) > 0xF) - { - Value = 0xF; /* max */ - } - else - { - Value += DeltaPwr; /* temperature compensation */ - } - - /* fill new value to CSR offset */ - TxPwr[i] = (TxPwr[i] & ~(0x0000000F << j*4)) | (Value << j*4); - } - - /* write tx power value to CSR */ - /* TX_PWR_CFG_0 (8 tx rate) for TX power for OFDM 12M/18M - TX power for OFDM 6M/9M - TX power for CCK5.5M/11M - TX power for CCK1M/2M */ - /* TX_PWR_CFG_1 ~ TX_PWR_CFG_4 */ - RTMP_IO_WRITE32(pAd, TX_PWR_CFG_0 + i*4, TxPwr[i]); - } - } - -} - -#ifdef CONFIG_STA_SUPPORT -/* - ========================================================================== - Description: - put PHY to sleep here, and set next wakeup timer. PHY doesn't not wakeup - automatically. Instead, MCU will issue a TwakeUpInterrupt to host after - the wakeup timer timeout. Driver has to issue a separate command to wake - PHY up. - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID AsicSleepThenAutoWakeup( - IN PRTMP_ADAPTER pAd, - IN USHORT TbttNumToNextWakeUp) -{ - RT28XX_STA_SLEEP_THEN_AUTO_WAKEUP(pAd, TbttNumToNextWakeUp); -} - -/* - ========================================================================== - Description: - AsicForceWakeup() is used whenever manual wakeup is required - AsicForceSleep() should only be used when not in INFRA BSS. When - in INFRA BSS, we should use AsicSleepThenAutoWakeup() instead. - ========================================================================== - */ -VOID AsicForceSleep( - IN PRTMP_ADAPTER pAd) -{ - -} - -/* - ========================================================================== - Description: - AsicForceWakeup() is used whenever Twakeup timer (set via AsicSleepThenAutoWakeup) - expired. - - IRQL = PASSIVE_LEVEL - IRQL = DISPATCH_LEVEL - ========================================================================== - */ -VOID AsicForceWakeup( - IN PRTMP_ADAPTER pAd, - IN BOOLEAN bFromTx) -{ - DBGPRINT(RT_DEBUG_TRACE, ("--> AsicForceWakeup \n")); - RT28XX_STA_FORCE_WAKEUP(pAd, bFromTx); -} -#endif // CONFIG_STA_SUPPORT // -/* - ========================================================================== - Description: - Set My BSSID - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID AsicSetBssid( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pBssid) -{ - ULONG Addr4; - DBGPRINT(RT_DEBUG_TRACE, ("==============> AsicSetBssid %x:%x:%x:%x:%x:%x\n", - pBssid[0],pBssid[1],pBssid[2],pBssid[3], pBssid[4],pBssid[5])); - - Addr4 = (ULONG)(pBssid[0]) | - (ULONG)(pBssid[1] << 8) | - (ULONG)(pBssid[2] << 16) | - (ULONG)(pBssid[3] << 24); - RTMP_IO_WRITE32(pAd, MAC_BSSID_DW0, Addr4); - - Addr4 = 0; - // always one BSSID in STA mode - Addr4 = (ULONG)(pBssid[4]) | (ULONG)(pBssid[5] << 8); - - RTMP_IO_WRITE32(pAd, MAC_BSSID_DW1, Addr4); -} - -VOID AsicSetMcastWC( - IN PRTMP_ADAPTER pAd) -{ - MAC_TABLE_ENTRY *pEntry = &pAd->MacTab.Content[MCAST_WCID]; - USHORT offset; - - pEntry->Sst = SST_ASSOC; - pEntry->Aid = MCAST_WCID; // Softap supports 1 BSSID and use WCID=0 as multicast Wcid index - pEntry->PsMode = PWR_ACTIVE; - pEntry->CurrTxRate = pAd->CommonCfg.MlmeRate; - offset = MAC_WCID_BASE + BSS0Mcast_WCID * HW_WCID_ENTRY_SIZE; -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID AsicDelWcidTab( - IN PRTMP_ADAPTER pAd, - IN UCHAR Wcid) -{ - ULONG Addr0 = 0x0, Addr1 = 0x0; - ULONG offset; - - DBGPRINT(RT_DEBUG_TRACE, ("AsicDelWcidTab==>Wcid = 0x%x\n",Wcid)); - offset = MAC_WCID_BASE + Wcid * HW_WCID_ENTRY_SIZE; - RTMP_IO_WRITE32(pAd, offset, Addr0); - offset += 4; - RTMP_IO_WRITE32(pAd, offset, Addr1); -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID AsicEnableRDG( - IN PRTMP_ADAPTER pAd) -{ - TX_LINK_CFG_STRUC TxLinkCfg; - UINT32 Data = 0; - - RTMP_IO_READ32(pAd, TX_LINK_CFG, &TxLinkCfg.word); - TxLinkCfg.field.TxRDGEn = 1; - RTMP_IO_WRITE32(pAd, TX_LINK_CFG, TxLinkCfg.word); - - RTMP_IO_READ32(pAd, EDCA_AC0_CFG, &Data); - Data &= 0xFFFFFF00; - Data |= 0x80; - RTMP_IO_WRITE32(pAd, EDCA_AC0_CFG, Data); - - //OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED); -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID AsicDisableRDG( - IN PRTMP_ADAPTER pAd) -{ - TX_LINK_CFG_STRUC TxLinkCfg; - UINT32 Data = 0; - - - RTMP_IO_READ32(pAd, TX_LINK_CFG, &TxLinkCfg.word); - TxLinkCfg.field.TxRDGEn = 0; - RTMP_IO_WRITE32(pAd, TX_LINK_CFG, TxLinkCfg.word); - - RTMP_IO_READ32(pAd, EDCA_AC0_CFG, &Data); - - Data &= 0xFFFFFF00; - //Data |= 0x20; -#ifndef WIFI_TEST - //if ( pAd->CommonCfg.bEnableTxBurst ) - // Data |= 0x60; // for performance issue not set the TXOP to 0 -#endif - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_DYNAMIC_BE_TXOP_ACTIVE) -#ifdef DOT11_N_SUPPORT - && (pAd->MacTab.fAnyStationMIMOPSDynamic == FALSE) -#endif // DOT11_N_SUPPORT // - ) - { - // For CWC test, change txop from 0x30 to 0x20 in TxBurst mode - if (pAd->CommonCfg.bEnableTxBurst) - Data |= 0x20; - } - RTMP_IO_WRITE32(pAd, EDCA_AC0_CFG, Data); -} - -/* - ========================================================================== - Description: - - IRQL = PASSIVE_LEVEL - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID AsicDisableSync( - IN PRTMP_ADAPTER pAd) -{ - BCN_TIME_CFG_STRUC csr; - - DBGPRINT(RT_DEBUG_TRACE, ("--->Disable TSF synchronization\n")); - - // 2003-12-20 disable TSF and TBTT while NIC in power-saving have side effect - // that NIC will never wakes up because TSF stops and no more - // TBTT interrupts - pAd->TbttTickCount = 0; - RTMP_IO_READ32(pAd, BCN_TIME_CFG, &csr.word); - csr.field.bBeaconGen = 0; - csr.field.bTBTTEnable = 0; - csr.field.TsfSyncMode = 0; - csr.field.bTsfTicking = 0; - RTMP_IO_WRITE32(pAd, BCN_TIME_CFG, csr.word); - -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID AsicEnableBssSync( - IN PRTMP_ADAPTER pAd) -{ - BCN_TIME_CFG_STRUC csr; - - DBGPRINT(RT_DEBUG_TRACE, ("--->AsicEnableBssSync(INFRA mode)\n")); - - RTMP_IO_READ32(pAd, BCN_TIME_CFG, &csr.word); -// RTMP_IO_WRITE32(pAd, BCN_TIME_CFG, 0x00000000); -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - csr.field.BeaconInterval = pAd->CommonCfg.BeaconPeriod << 4; // ASIC register in units of 1/16 TU - csr.field.bTsfTicking = 1; - csr.field.TsfSyncMode = 1; // sync TSF in INFRASTRUCTURE mode - csr.field.bBeaconGen = 0; // do NOT generate BEACON - csr.field.bTBTTEnable = 1; - } -#endif // CONFIG_STA_SUPPORT // - RTMP_IO_WRITE32(pAd, BCN_TIME_CFG, csr.word); -} - -/* - ========================================================================== - Description: - Note: - BEACON frame in shared memory should be built ok before this routine - can be called. Otherwise, a garbage frame maybe transmitted out every - Beacon period. - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID AsicEnableIbssSync( - IN PRTMP_ADAPTER pAd) -{ - BCN_TIME_CFG_STRUC csr9; - PUCHAR ptr; - UINT i; - - DBGPRINT(RT_DEBUG_TRACE, ("--->AsicEnableIbssSync(ADHOC mode. MPDUtotalByteCount = %d)\n", pAd->BeaconTxWI.MPDUtotalByteCount)); - - RTMP_IO_READ32(pAd, BCN_TIME_CFG, &csr9.word); - csr9.field.bBeaconGen = 0; - csr9.field.bTBTTEnable = 0; - csr9.field.bTsfTicking = 0; - RTMP_IO_WRITE32(pAd, BCN_TIME_CFG, csr9.word); - - -#ifdef RT2870 - // move BEACON TXD and frame content to on-chip memory - ptr = (PUCHAR)&pAd->BeaconTxWI; - for (i=0; iBeaconBuf; - for (i=0; i< pAd->BeaconTxWI.MPDUtotalByteCount; i+=2) - { - //UINT32 longptr = *ptr + (*(ptr+1)<<8) + (*(ptr+2)<<16) + (*(ptr+3)<<24); - //RTMP_IO_WRITE32(pAd, HW_BEACON_BASE0 + TXWI_SIZE + i, longptr); - RTUSBMultiWrite(pAd, HW_BEACON_BASE0 + TXWI_SIZE + i, ptr, 2); - ptr +=2; - } -#endif // RT2870 // - - // - // For Wi-Fi faily generated beacons between participating stations. - // Set TBTT phase adaptive adjustment step to 8us (default 16us) - // don't change settings 2006-5- by Jerry - //RTMP_IO_WRITE32(pAd, TBTT_SYNC_CFG, 0x00001010); - - // start sending BEACON - csr9.field.BeaconInterval = pAd->CommonCfg.BeaconPeriod << 4; // ASIC register in units of 1/16 TU - csr9.field.bTsfTicking = 1; - csr9.field.TsfSyncMode = 2; // sync TSF in IBSS mode - csr9.field.bTBTTEnable = 1; - csr9.field.bBeaconGen = 1; - RTMP_IO_WRITE32(pAd, BCN_TIME_CFG, csr9.word); -} - -/* - ========================================================================== - Description: - - IRQL = PASSIVE_LEVEL - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID AsicSetEdcaParm( - IN PRTMP_ADAPTER pAd, - IN PEDCA_PARM pEdcaParm) -{ - EDCA_AC_CFG_STRUC Ac0Cfg, Ac1Cfg, Ac2Cfg, Ac3Cfg; - AC_TXOP_CSR0_STRUC csr0; - AC_TXOP_CSR1_STRUC csr1; - AIFSN_CSR_STRUC AifsnCsr; - CWMIN_CSR_STRUC CwminCsr; - CWMAX_CSR_STRUC CwmaxCsr; - int i; - - Ac0Cfg.word = 0; - Ac1Cfg.word = 0; - Ac2Cfg.word = 0; - Ac3Cfg.word = 0; - if ((pEdcaParm == NULL) || (pEdcaParm->bValid == FALSE)) - { - DBGPRINT(RT_DEBUG_TRACE,("AsicSetEdcaParm\n")); - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_WMM_INUSED); - for (i=0; iMacTab.Content[i].ValidAsCLI || pAd->MacTab.Content[i].ValidAsApCli) - CLIENT_STATUS_CLEAR_FLAG(&pAd->MacTab.Content[i], fCLIENT_STATUS_WMM_CAPABLE); - } - - //======================================================== - // MAC Register has a copy . - //======================================================== -//#ifndef WIFI_TEST - if( pAd->CommonCfg.bEnableTxBurst ) - { - // For CWC test, change txop from 0x30 to 0x20 in TxBurst mode - Ac0Cfg.field.AcTxop = 0x20; // Suggest by John for TxBurst in HT Mode - } - else - Ac0Cfg.field.AcTxop = 0; // QID_AC_BE -//#else -// Ac0Cfg.field.AcTxop = 0; // QID_AC_BE -//#endif - Ac0Cfg.field.Cwmin = CW_MIN_IN_BITS; - Ac0Cfg.field.Cwmax = CW_MAX_IN_BITS; - Ac0Cfg.field.Aifsn = 2; - RTMP_IO_WRITE32(pAd, EDCA_AC0_CFG, Ac0Cfg.word); - - Ac1Cfg.field.AcTxop = 0; // QID_AC_BK - Ac1Cfg.field.Cwmin = CW_MIN_IN_BITS; - Ac1Cfg.field.Cwmax = CW_MAX_IN_BITS; - Ac1Cfg.field.Aifsn = 2; - RTMP_IO_WRITE32(pAd, EDCA_AC1_CFG, Ac1Cfg.word); - - if (pAd->CommonCfg.PhyMode == PHY_11B) - { - Ac2Cfg.field.AcTxop = 192; // AC_VI: 192*32us ~= 6ms - Ac3Cfg.field.AcTxop = 96; // AC_VO: 96*32us ~= 3ms - } - else - { - Ac2Cfg.field.AcTxop = 96; // AC_VI: 96*32us ~= 3ms - Ac3Cfg.field.AcTxop = 48; // AC_VO: 48*32us ~= 1.5ms - } - Ac2Cfg.field.Cwmin = CW_MIN_IN_BITS; - Ac2Cfg.field.Cwmax = CW_MAX_IN_BITS; - Ac2Cfg.field.Aifsn = 2; - RTMP_IO_WRITE32(pAd, EDCA_AC2_CFG, Ac2Cfg.word); - Ac3Cfg.field.Cwmin = CW_MIN_IN_BITS; - Ac3Cfg.field.Cwmax = CW_MAX_IN_BITS; - Ac3Cfg.field.Aifsn = 2; - RTMP_IO_WRITE32(pAd, EDCA_AC3_CFG, Ac3Cfg.word); - - //======================================================== - // DMA Register has a copy too. - //======================================================== - csr0.field.Ac0Txop = 0; // QID_AC_BE - csr0.field.Ac1Txop = 0; // QID_AC_BK - RTMP_IO_WRITE32(pAd, WMM_TXOP0_CFG, csr0.word); - if (pAd->CommonCfg.PhyMode == PHY_11B) - { - csr1.field.Ac2Txop = 192; // AC_VI: 192*32us ~= 6ms - csr1.field.Ac3Txop = 96; // AC_VO: 96*32us ~= 3ms - } - else - { - csr1.field.Ac2Txop = 96; // AC_VI: 96*32us ~= 3ms - csr1.field.Ac3Txop = 48; // AC_VO: 48*32us ~= 1.5ms - } - RTMP_IO_WRITE32(pAd, WMM_TXOP1_CFG, csr1.word); - - CwminCsr.word = 0; - CwminCsr.field.Cwmin0 = CW_MIN_IN_BITS; - CwminCsr.field.Cwmin1 = CW_MIN_IN_BITS; - CwminCsr.field.Cwmin2 = CW_MIN_IN_BITS; - CwminCsr.field.Cwmin3 = CW_MIN_IN_BITS; - RTMP_IO_WRITE32(pAd, WMM_CWMIN_CFG, CwminCsr.word); - - CwmaxCsr.word = 0; - CwmaxCsr.field.Cwmax0 = CW_MAX_IN_BITS; - CwmaxCsr.field.Cwmax1 = CW_MAX_IN_BITS; - CwmaxCsr.field.Cwmax2 = CW_MAX_IN_BITS; - CwmaxCsr.field.Cwmax3 = CW_MAX_IN_BITS; - RTMP_IO_WRITE32(pAd, WMM_CWMAX_CFG, CwmaxCsr.word); - - RTMP_IO_WRITE32(pAd, WMM_AIFSN_CFG, 0x00002222); - - NdisZeroMemory(&pAd->CommonCfg.APEdcaParm, sizeof(EDCA_PARM)); - } - else - { - OPSTATUS_SET_FLAG(pAd, fOP_STATUS_WMM_INUSED); - //======================================================== - // MAC Register has a copy. - //======================================================== - // - // Modify Cwmin/Cwmax/Txop on queue[QID_AC_VI], Recommend by Jerry 2005/07/27 - // To degrade our VIDO Queue's throughput for WiFi WMM S3T07 Issue. - // - //pEdcaParm->Txop[QID_AC_VI] = pEdcaParm->Txop[QID_AC_VI] * 7 / 10; // rt2860c need this - - Ac0Cfg.field.AcTxop = pEdcaParm->Txop[QID_AC_BE]; - Ac0Cfg.field.Cwmin= pEdcaParm->Cwmin[QID_AC_BE]; - Ac0Cfg.field.Cwmax = pEdcaParm->Cwmax[QID_AC_BE]; - Ac0Cfg.field.Aifsn = pEdcaParm->Aifsn[QID_AC_BE]; //+1; - - Ac1Cfg.field.AcTxop = pEdcaParm->Txop[QID_AC_BK]; - Ac1Cfg.field.Cwmin = pEdcaParm->Cwmin[QID_AC_BK]; //+2; - Ac1Cfg.field.Cwmax = pEdcaParm->Cwmax[QID_AC_BK]; - Ac1Cfg.field.Aifsn = pEdcaParm->Aifsn[QID_AC_BK]; //+1; - - Ac2Cfg.field.AcTxop = (pEdcaParm->Txop[QID_AC_VI] * 6) / 10; - Ac2Cfg.field.Cwmin = pEdcaParm->Cwmin[QID_AC_VI]; - Ac2Cfg.field.Cwmax = pEdcaParm->Cwmax[QID_AC_VI]; - Ac2Cfg.field.Aifsn = pEdcaParm->Aifsn[QID_AC_VI]; -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - // Tuning for Wi-Fi WMM S06 - if (pAd->CommonCfg.bWiFiTest && - pEdcaParm->Aifsn[QID_AC_VI] == 10) - Ac2Cfg.field.Aifsn -= 1; - - // Tuning for TGn Wi-Fi 5.2.32 - // STA TestBed changes in this item: conexant legacy sta ==> broadcom 11n sta - if (STA_TGN_WIFI_ON(pAd) && - pEdcaParm->Aifsn[QID_AC_VI] == 10) - { - Ac0Cfg.field.Aifsn = 3; - Ac2Cfg.field.AcTxop = 5; - } - } -#endif // CONFIG_STA_SUPPORT // - - Ac3Cfg.field.AcTxop = pEdcaParm->Txop[QID_AC_VO]; - Ac3Cfg.field.Cwmin = pEdcaParm->Cwmin[QID_AC_VO]; - Ac3Cfg.field.Cwmax = pEdcaParm->Cwmax[QID_AC_VO]; - Ac3Cfg.field.Aifsn = pEdcaParm->Aifsn[QID_AC_VO]; - -//#ifdef WIFI_TEST - if (pAd->CommonCfg.bWiFiTest) - { - if (Ac3Cfg.field.AcTxop == 102) - { - Ac0Cfg.field.AcTxop = pEdcaParm->Txop[QID_AC_BE] ? pEdcaParm->Txop[QID_AC_BE] : 10; - Ac0Cfg.field.Aifsn = pEdcaParm->Aifsn[QID_AC_BE]-1; /* AIFSN must >= 1 */ - Ac1Cfg.field.AcTxop = pEdcaParm->Txop[QID_AC_BK]; - Ac1Cfg.field.Aifsn = pEdcaParm->Aifsn[QID_AC_BK]; - Ac2Cfg.field.AcTxop = pEdcaParm->Txop[QID_AC_VI]; - } /* End of if */ - } -//#endif // WIFI_TEST // - - RTMP_IO_WRITE32(pAd, EDCA_AC0_CFG, Ac0Cfg.word); - RTMP_IO_WRITE32(pAd, EDCA_AC1_CFG, Ac1Cfg.word); - RTMP_IO_WRITE32(pAd, EDCA_AC2_CFG, Ac2Cfg.word); - RTMP_IO_WRITE32(pAd, EDCA_AC3_CFG, Ac3Cfg.word); - - - //======================================================== - // DMA Register has a copy too. - //======================================================== - csr0.field.Ac0Txop = Ac0Cfg.field.AcTxop; - csr0.field.Ac1Txop = Ac1Cfg.field.AcTxop; - RTMP_IO_WRITE32(pAd, WMM_TXOP0_CFG, csr0.word); - - csr1.field.Ac2Txop = Ac2Cfg.field.AcTxop; - csr1.field.Ac3Txop = Ac3Cfg.field.AcTxop; - RTMP_IO_WRITE32(pAd, WMM_TXOP1_CFG, csr1.word); - - CwminCsr.word = 0; - CwminCsr.field.Cwmin0 = pEdcaParm->Cwmin[QID_AC_BE]; - CwminCsr.field.Cwmin1 = pEdcaParm->Cwmin[QID_AC_BK]; - CwminCsr.field.Cwmin2 = pEdcaParm->Cwmin[QID_AC_VI]; -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - CwminCsr.field.Cwmin3 = pEdcaParm->Cwmin[QID_AC_VO] - 1; //for TGn wifi test -#endif // CONFIG_STA_SUPPORT // - RTMP_IO_WRITE32(pAd, WMM_CWMIN_CFG, CwminCsr.word); - - CwmaxCsr.word = 0; - CwmaxCsr.field.Cwmax0 = pEdcaParm->Cwmax[QID_AC_BE]; - CwmaxCsr.field.Cwmax1 = pEdcaParm->Cwmax[QID_AC_BK]; - CwmaxCsr.field.Cwmax2 = pEdcaParm->Cwmax[QID_AC_VI]; - CwmaxCsr.field.Cwmax3 = pEdcaParm->Cwmax[QID_AC_VO]; - RTMP_IO_WRITE32(pAd, WMM_CWMAX_CFG, CwmaxCsr.word); - - AifsnCsr.word = 0; - AifsnCsr.field.Aifsn0 = Ac0Cfg.field.Aifsn; //pEdcaParm->Aifsn[QID_AC_BE]; - AifsnCsr.field.Aifsn1 = Ac1Cfg.field.Aifsn; //pEdcaParm->Aifsn[QID_AC_BK]; - AifsnCsr.field.Aifsn2 = Ac2Cfg.field.Aifsn; //pEdcaParm->Aifsn[QID_AC_VI]; -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - // Tuning for Wi-Fi WMM S06 - if (pAd->CommonCfg.bWiFiTest && - pEdcaParm->Aifsn[QID_AC_VI] == 10) - AifsnCsr.field.Aifsn2 = Ac2Cfg.field.Aifsn - 4; - - // Tuning for TGn Wi-Fi 5.2.32 - // STA TestBed changes in this item: conexant legacy sta ==> broadcom 11n sta - if (STA_TGN_WIFI_ON(pAd) && - pEdcaParm->Aifsn[QID_AC_VI] == 10) - { - AifsnCsr.field.Aifsn0 = 3; - AifsnCsr.field.Aifsn2 = 7; - } - - if (INFRA_ON(pAd)) - CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[BSSID_WCID], fCLIENT_STATUS_WMM_CAPABLE); - } -#endif // CONFIG_STA_SUPPORT // - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - AifsnCsr.field.Aifsn3 = Ac3Cfg.field.Aifsn - 1; //pEdcaParm->Aifsn[QID_AC_VO]; //for TGn wifi test -#endif // CONFIG_STA_SUPPORT // - RTMP_IO_WRITE32(pAd, WMM_AIFSN_CFG, AifsnCsr.word); - - NdisMoveMemory(&pAd->CommonCfg.APEdcaParm, pEdcaParm, sizeof(EDCA_PARM)); - if (!ADHOC_ON(pAd)) - { - DBGPRINT(RT_DEBUG_TRACE,("EDCA [#%d]: AIFSN CWmin CWmax TXOP(us) ACM\n", pEdcaParm->EdcaUpdateCount)); - DBGPRINT(RT_DEBUG_TRACE,(" AC_BE %2d %2d %2d %4d %d\n", - pEdcaParm->Aifsn[0], - pEdcaParm->Cwmin[0], - pEdcaParm->Cwmax[0], - pEdcaParm->Txop[0]<<5, - pEdcaParm->bACM[0])); - DBGPRINT(RT_DEBUG_TRACE,(" AC_BK %2d %2d %2d %4d %d\n", - pEdcaParm->Aifsn[1], - pEdcaParm->Cwmin[1], - pEdcaParm->Cwmax[1], - pEdcaParm->Txop[1]<<5, - pEdcaParm->bACM[1])); - DBGPRINT(RT_DEBUG_TRACE,(" AC_VI %2d %2d %2d %4d %d\n", - pEdcaParm->Aifsn[2], - pEdcaParm->Cwmin[2], - pEdcaParm->Cwmax[2], - pEdcaParm->Txop[2]<<5, - pEdcaParm->bACM[2])); - DBGPRINT(RT_DEBUG_TRACE,(" AC_VO %2d %2d %2d %4d %d\n", - pEdcaParm->Aifsn[3], - pEdcaParm->Cwmin[3], - pEdcaParm->Cwmax[3], - pEdcaParm->Txop[3]<<5, - pEdcaParm->bACM[3])); - } - } -} - -/* - ========================================================================== - Description: - - IRQL = PASSIVE_LEVEL - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID AsicSetSlotTime( - IN PRTMP_ADAPTER pAd, - IN BOOLEAN bUseShortSlotTime) -{ - ULONG SlotTime; - UINT32 RegValue = 0; - -#ifdef CONFIG_STA_SUPPORT - if (pAd->CommonCfg.Channel > 14) - bUseShortSlotTime = TRUE; -#endif // CONFIG_STA_SUPPORT // - - if (bUseShortSlotTime) - OPSTATUS_SET_FLAG(pAd, fOP_STATUS_SHORT_SLOT_INUSED); - else - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SHORT_SLOT_INUSED); - - SlotTime = (bUseShortSlotTime)? 9 : 20; - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - // force using short SLOT time for FAE to demo performance when TxBurst is ON - if (((pAd->StaActive.SupportedPhyInfo.bHtEnable == FALSE) && (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED))) -#ifdef DOT11_N_SUPPORT - || ((pAd->StaActive.SupportedPhyInfo.bHtEnable == TRUE) && (pAd->CommonCfg.BACapability.field.Policy == BA_NOTUSE)) -#endif // DOT11_N_SUPPORT // - ) - { - // In this case, we will think it is doing Wi-Fi test - // And we will not set to short slot when bEnableTxBurst is TRUE. - } - else if (pAd->CommonCfg.bEnableTxBurst) - SlotTime = 9; - } -#endif // CONFIG_STA_SUPPORT // - - // - // For some reasons, always set it to short slot time. - // - // ToDo: Should consider capability with 11B - // -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - if (pAd->StaCfg.BssType == BSS_ADHOC) - SlotTime = 20; - } -#endif // CONFIG_STA_SUPPORT // - - RTMP_IO_READ32(pAd, BKOFF_SLOT_CFG, &RegValue); - RegValue = RegValue & 0xFFFFFF00; - - RegValue |= SlotTime; - - RTMP_IO_WRITE32(pAd, BKOFF_SLOT_CFG, RegValue); -} - -/* - ======================================================================== - Description: - Add Shared key information into ASIC. - Update shared key, TxMic and RxMic to Asic Shared key table - Update its cipherAlg to Asic Shared key Mode. - - Return: - ======================================================================== -*/ -VOID AsicAddSharedKeyEntry( - IN PRTMP_ADAPTER pAd, - IN UCHAR BssIndex, - IN UCHAR KeyIdx, - IN UCHAR CipherAlg, - IN PUCHAR pKey, - IN PUCHAR pTxMic, - IN PUCHAR pRxMic) -{ - ULONG offset; //, csr0; - SHAREDKEY_MODE_STRUC csr1; - - DBGPRINT(RT_DEBUG_TRACE, ("AsicAddSharedKeyEntry BssIndex=%d, KeyIdx=%d\n", BssIndex,KeyIdx)); -//============================================================================================ - - DBGPRINT(RT_DEBUG_TRACE,("AsicAddSharedKeyEntry: %s key #%d\n", CipherName[CipherAlg], BssIndex*4 + KeyIdx)); - DBGPRINT_RAW(RT_DEBUG_TRACE, (" Key = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", - pKey[0],pKey[1],pKey[2],pKey[3],pKey[4],pKey[5],pKey[6],pKey[7],pKey[8],pKey[9],pKey[10],pKey[11],pKey[12],pKey[13],pKey[14],pKey[15])); - if (pRxMic) - { - DBGPRINT_RAW(RT_DEBUG_TRACE, (" Rx MIC Key = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", - pRxMic[0],pRxMic[1],pRxMic[2],pRxMic[3],pRxMic[4],pRxMic[5],pRxMic[6],pRxMic[7])); - } - if (pTxMic) - { - DBGPRINT_RAW(RT_DEBUG_TRACE, (" Tx MIC Key = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", - pTxMic[0],pTxMic[1],pTxMic[2],pTxMic[3],pTxMic[4],pTxMic[5],pTxMic[6],pTxMic[7])); - } -//============================================================================================ - // - // fill key material - key + TX MIC + RX MIC - // - -#ifdef RT2870 -{ - offset = SHARED_KEY_TABLE_BASE + (4*BssIndex + KeyIdx)*HW_KEY_ENTRY_SIZE; - RTUSBMultiWrite(pAd, offset, pKey, MAX_LEN_OF_SHARE_KEY); - - offset += MAX_LEN_OF_SHARE_KEY; - if (pTxMic) - { - RTUSBMultiWrite(pAd, offset, pTxMic, 8); - } - - offset += 8; - if (pRxMic) - { - RTUSBMultiWrite(pAd, offset, pRxMic, 8); - } -} -#endif // RT2870 // - - // - // Update cipher algorithm. WSTA always use BSS0 - // - RTMP_IO_READ32(pAd, SHARED_KEY_MODE_BASE+4*(BssIndex/2), &csr1.word); - DBGPRINT(RT_DEBUG_TRACE,("Read: SHARED_KEY_MODE_BASE at this Bss[%d] KeyIdx[%d]= 0x%x \n", BssIndex,KeyIdx, csr1.word)); - if ((BssIndex%2) == 0) - { - if (KeyIdx == 0) - csr1.field.Bss0Key0CipherAlg = CipherAlg; - else if (KeyIdx == 1) - csr1.field.Bss0Key1CipherAlg = CipherAlg; - else if (KeyIdx == 2) - csr1.field.Bss0Key2CipherAlg = CipherAlg; - else - csr1.field.Bss0Key3CipherAlg = CipherAlg; - } - else - { - if (KeyIdx == 0) - csr1.field.Bss1Key0CipherAlg = CipherAlg; - else if (KeyIdx == 1) - csr1.field.Bss1Key1CipherAlg = CipherAlg; - else if (KeyIdx == 2) - csr1.field.Bss1Key2CipherAlg = CipherAlg; - else - csr1.field.Bss1Key3CipherAlg = CipherAlg; - } - DBGPRINT(RT_DEBUG_TRACE,("Write: SHARED_KEY_MODE_BASE at this Bss[%d] = 0x%x \n", BssIndex, csr1.word)); - RTMP_IO_WRITE32(pAd, SHARED_KEY_MODE_BASE+4*(BssIndex/2), csr1.word); - -} - -// IRQL = DISPATCH_LEVEL -VOID AsicRemoveSharedKeyEntry( - IN PRTMP_ADAPTER pAd, - IN UCHAR BssIndex, - IN UCHAR KeyIdx) -{ - //ULONG SecCsr0; - SHAREDKEY_MODE_STRUC csr1; - - DBGPRINT(RT_DEBUG_TRACE,("AsicRemoveSharedKeyEntry: #%d \n", BssIndex*4 + KeyIdx)); - - RTMP_IO_READ32(pAd, SHARED_KEY_MODE_BASE+4*(BssIndex/2), &csr1.word); - if ((BssIndex%2) == 0) - { - if (KeyIdx == 0) - csr1.field.Bss0Key0CipherAlg = 0; - else if (KeyIdx == 1) - csr1.field.Bss0Key1CipherAlg = 0; - else if (KeyIdx == 2) - csr1.field.Bss0Key2CipherAlg = 0; - else - csr1.field.Bss0Key3CipherAlg = 0; - } - else - { - if (KeyIdx == 0) - csr1.field.Bss1Key0CipherAlg = 0; - else if (KeyIdx == 1) - csr1.field.Bss1Key1CipherAlg = 0; - else if (KeyIdx == 2) - csr1.field.Bss1Key2CipherAlg = 0; - else - csr1.field.Bss1Key3CipherAlg = 0; - } - DBGPRINT(RT_DEBUG_TRACE,("Write: SHARED_KEY_MODE_BASE at this Bss[%d] = 0x%x \n", BssIndex, csr1.word)); - RTMP_IO_WRITE32(pAd, SHARED_KEY_MODE_BASE+4*(BssIndex/2), csr1.word); - ASSERT(BssIndex < 4); - ASSERT(KeyIdx < 4); - -} - - -VOID AsicUpdateWCIDAttribute( - IN PRTMP_ADAPTER pAd, - IN USHORT WCID, - IN UCHAR BssIndex, - IN UCHAR CipherAlg, - IN BOOLEAN bUsePairewiseKeyTable) -{ - ULONG WCIDAttri = 0, offset; - - // - // Update WCID attribute. - // Only TxKey could update WCID attribute. - // - offset = MAC_WCID_ATTRIBUTE_BASE + (WCID * HW_WCID_ATTRI_SIZE); - WCIDAttri = (BssIndex << 4) | (CipherAlg << 1) | (bUsePairewiseKeyTable); - RTMP_IO_WRITE32(pAd, offset, WCIDAttri); -} - -VOID AsicUpdateWCIDIVEIV( - IN PRTMP_ADAPTER pAd, - IN USHORT WCID, - IN ULONG uIV, - IN ULONG uEIV) -{ - ULONG offset; - - offset = MAC_IVEIV_TABLE_BASE + (WCID * HW_IVEIV_ENTRY_SIZE); - - RTMP_IO_WRITE32(pAd, offset, uIV); - RTMP_IO_WRITE32(pAd, offset + 4, uEIV); -} - -VOID AsicUpdateRxWCIDTable( - IN PRTMP_ADAPTER pAd, - IN USHORT WCID, - IN PUCHAR pAddr) -{ - ULONG offset; - ULONG Addr; - - offset = MAC_WCID_BASE + (WCID * HW_WCID_ENTRY_SIZE); - Addr = pAddr[0] + (pAddr[1] << 8) +(pAddr[2] << 16) +(pAddr[3] << 24); - RTMP_IO_WRITE32(pAd, offset, Addr); - Addr = pAddr[4] + (pAddr[5] << 8); - RTMP_IO_WRITE32(pAd, offset + 4, Addr); -} - - -/* - ======================================================================== - - Routine Description: - Set Cipher Key, Cipher algorithm, IV/EIV to Asic - - Arguments: - pAd Pointer to our adapter - WCID WCID Entry number. - BssIndex BSSID index, station or none multiple BSSID support - this value should be 0. - KeyIdx This KeyIdx will set to IV's KeyID if bTxKey enabled - pCipherKey Pointer to Cipher Key. - bUsePairewiseKeyTable TRUE means saved the key in SharedKey table, - otherwise PairewiseKey table - bTxKey This is the transmit key if enabled. - - Return Value: - None - - Note: - This routine will set the relative key stuff to Asic including WCID attribute, - Cipher Key, Cipher algorithm and IV/EIV. - - IV/EIV will be update if this CipherKey is the transmission key because - ASIC will base on IV's KeyID value to select Cipher Key. - - If bTxKey sets to FALSE, this is not the TX key, but it could be - RX key - - For AP mode bTxKey must be always set to TRUE. - ======================================================================== -*/ -VOID AsicAddKeyEntry( - IN PRTMP_ADAPTER pAd, - IN USHORT WCID, - IN UCHAR BssIndex, - IN UCHAR KeyIdx, - IN PCIPHER_KEY pCipherKey, - IN BOOLEAN bUsePairewiseKeyTable, - IN BOOLEAN bTxKey) -{ - ULONG offset; -// ULONG WCIDAttri = 0; - UCHAR IV4 = 0; - PUCHAR pKey = pCipherKey->Key; -// ULONG KeyLen = pCipherKey->KeyLen; - PUCHAR pTxMic = pCipherKey->TxMic; - PUCHAR pRxMic = pCipherKey->RxMic; - PUCHAR pTxtsc = pCipherKey->TxTsc; - UCHAR CipherAlg = pCipherKey->CipherAlg; - SHAREDKEY_MODE_STRUC csr1; - -// ASSERT(KeyLen <= MAX_LEN_OF_PEER_KEY); - - DBGPRINT(RT_DEBUG_TRACE, ("==> AsicAddKeyEntry\n")); - // - // 1.) decide key table offset - // - if (bUsePairewiseKeyTable) - offset = PAIRWISE_KEY_TABLE_BASE + (WCID * HW_KEY_ENTRY_SIZE); - else - offset = SHARED_KEY_TABLE_BASE + (4 * BssIndex + KeyIdx) * HW_KEY_ENTRY_SIZE; - - // - // 2.) Set Key to Asic - // - //for (i = 0; i < KeyLen; i++) - -#ifdef RT2870 - RTUSBMultiWrite(pAd, offset, pKey, MAX_LEN_OF_PEER_KEY); - offset += MAX_LEN_OF_PEER_KEY; - - // - // 3.) Set MIC key if available - // - if (pTxMic) - { - RTUSBMultiWrite(pAd, offset, pTxMic, 8); - } - offset += LEN_TKIP_TXMICK; - - if (pRxMic) - { - RTUSBMultiWrite(pAd, offset, pRxMic, 8); - } -#endif // RT2870 // - - // - // 4.) Modify IV/EIV if needs - // This will force Asic to use this key ID by setting IV. - // - if (bTxKey) - { - -#ifdef RT2870 - UINT32 tmpVal; - - // - // Write IV - // - IV4 = (KeyIdx << 6); - if ((CipherAlg == CIPHER_TKIP) || (CipherAlg == CIPHER_TKIP_NO_MIC) ||(CipherAlg == CIPHER_AES)) - IV4 |= 0x20; // turn on extension bit means EIV existence - - tmpVal = pTxtsc[1] + (((pTxtsc[1] | 0x20) & 0x7f) << 8) + (pTxtsc[0] << 16) + (IV4 << 24); - RTMP_IO_WRITE32(pAd, offset, tmpVal); - - // - // Write EIV - // - offset += 4; - RTMP_IO_WRITE32(pAd, offset, *(PUINT32)&pCipherKey->TxTsc[2]); -#endif // RT2870 // - AsicUpdateWCIDAttribute(pAd, WCID, BssIndex, CipherAlg, bUsePairewiseKeyTable); - } - - if (!bUsePairewiseKeyTable) - { - // - // Only update the shared key security mode - // - RTMP_IO_READ32(pAd, SHARED_KEY_MODE_BASE + 4 * (BssIndex / 2), &csr1.word); - if ((BssIndex % 2) == 0) - { - if (KeyIdx == 0) - csr1.field.Bss0Key0CipherAlg = CipherAlg; - else if (KeyIdx == 1) - csr1.field.Bss0Key1CipherAlg = CipherAlg; - else if (KeyIdx == 2) - csr1.field.Bss0Key2CipherAlg = CipherAlg; - else - csr1.field.Bss0Key3CipherAlg = CipherAlg; - } - else - { - if (KeyIdx == 0) - csr1.field.Bss1Key0CipherAlg = CipherAlg; - else if (KeyIdx == 1) - csr1.field.Bss1Key1CipherAlg = CipherAlg; - else if (KeyIdx == 2) - csr1.field.Bss1Key2CipherAlg = CipherAlg; - else - csr1.field.Bss1Key3CipherAlg = CipherAlg; - } - RTMP_IO_WRITE32(pAd, SHARED_KEY_MODE_BASE + 4 * (BssIndex / 2), csr1.word); - } - - DBGPRINT(RT_DEBUG_TRACE, ("<== AsicAddKeyEntry\n")); -} - - -/* - ======================================================================== - Description: - Add Pair-wise key material into ASIC. - Update pairwise key, TxMic and RxMic to Asic Pair-wise key table - - Return: - ======================================================================== -*/ -VOID AsicAddPairwiseKeyEntry( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pAddr, - IN UCHAR WCID, - IN CIPHER_KEY *pCipherKey) -{ - INT i; - ULONG offset; - PUCHAR pKey = pCipherKey->Key; - PUCHAR pTxMic = pCipherKey->TxMic; - PUCHAR pRxMic = pCipherKey->RxMic; -#ifdef DBG - UCHAR CipherAlg = pCipherKey->CipherAlg; -#endif // DBG // - - // EKEY - offset = PAIRWISE_KEY_TABLE_BASE + (WCID * HW_KEY_ENTRY_SIZE); -#ifdef RT2870 - RTUSBMultiWrite(pAd, offset, &pCipherKey->Key[0], MAX_LEN_OF_PEER_KEY); -#endif // RT2870 // - for (i=0; iTxMic[0], 8); -#endif // RT2870 // - } - offset += 8; - if (pRxMic) - { -#ifdef RT2870 - RTUSBMultiWrite(pAd, offset, &pCipherKey->RxMic[0], 8); -#endif // RT2870 // - } - - DBGPRINT(RT_DEBUG_TRACE,("AsicAddPairwiseKeyEntry: WCID #%d Alg=%s\n",WCID, CipherName[CipherAlg])); - DBGPRINT(RT_DEBUG_TRACE,(" Key = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", - pKey[0],pKey[1],pKey[2],pKey[3],pKey[4],pKey[5],pKey[6],pKey[7],pKey[8],pKey[9],pKey[10],pKey[11],pKey[12],pKey[13],pKey[14],pKey[15])); - if (pRxMic) - { - DBGPRINT(RT_DEBUG_TRACE, (" Rx MIC Key = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", - pRxMic[0],pRxMic[1],pRxMic[2],pRxMic[3],pRxMic[4],pRxMic[5],pRxMic[6],pRxMic[7])); - } - if (pTxMic) - { - DBGPRINT(RT_DEBUG_TRACE, (" Tx MIC Key = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", - pTxMic[0],pTxMic[1],pTxMic[2],pTxMic[3],pTxMic[4],pTxMic[5],pTxMic[6],pTxMic[7])); - } -} -/* - ======================================================================== - Description: - Remove Pair-wise key material from ASIC. - - Return: - ======================================================================== -*/ -VOID AsicRemovePairwiseKeyEntry( - IN PRTMP_ADAPTER pAd, - IN UCHAR BssIdx, - IN UCHAR Wcid) -{ - ULONG WCIDAttri; - USHORT offset; - - // re-set the entry's WCID attribute as OPEN-NONE. - offset = MAC_WCID_ATTRIBUTE_BASE + (Wcid * HW_WCID_ATTRI_SIZE); - WCIDAttri = (BssIdx<<4) | PAIRWISEKEYTABLE; - RTMP_IO_WRITE32(pAd, offset, WCIDAttri); -} - -BOOLEAN AsicSendCommandToMcu( - IN PRTMP_ADAPTER pAd, - IN UCHAR Command, - IN UCHAR Token, - IN UCHAR Arg0, - IN UCHAR Arg1) -{ - HOST_CMD_CSR_STRUC H2MCmd; - H2M_MAILBOX_STRUC H2MMailbox; - ULONG i = 0; - do - { - RTMP_IO_READ32(pAd, H2M_MAILBOX_CSR, &H2MMailbox.word); - if (H2MMailbox.field.Owner == 0) - break; - - RTMPusecDelay(2); - } while(i++ < 100); - - if (i >= 100) - { - { - DBGPRINT_ERR(("H2M_MAILBOX still hold by MCU. command fail\n")); - } - return FALSE; - } - - - H2MMailbox.field.Owner = 1; // pass ownership to MCU - H2MMailbox.field.CmdToken = Token; - H2MMailbox.field.HighByte = Arg1; - H2MMailbox.field.LowByte = Arg0; - RTMP_IO_WRITE32(pAd, H2M_MAILBOX_CSR, H2MMailbox.word); - - H2MCmd.word = 0; - H2MCmd.field.HostCommand = Command; - RTMP_IO_WRITE32(pAd, HOST_CMD_CSR, H2MCmd.word); - - if (Command != 0x80) - { - } - - return TRUE; -} - - -/* - ======================================================================== - - Routine Description: - Verify the support rate for different PHY type - - Arguments: - pAd Pointer to our adapter - - Return Value: - None - - IRQL = PASSIVE_LEVEL - - ======================================================================== -*/ -VOID RTMPCheckRates( - IN PRTMP_ADAPTER pAd, - IN OUT UCHAR SupRate[], - IN OUT UCHAR *SupRateLen) -{ - UCHAR RateIdx, i, j; - UCHAR NewRate[12], NewRateLen; - - NewRateLen = 0; - - if (pAd->CommonCfg.PhyMode == PHY_11B) - RateIdx = 4; - else - RateIdx = 12; - - // Check for support rates exclude basic rate bit - for (i = 0; i < *SupRateLen; i++) - for (j = 0; j < RateIdx; j++) - if ((SupRate[i] & 0x7f) == RateIdTo500Kbps[j]) - NewRate[NewRateLen++] = SupRate[i]; - - *SupRateLen = NewRateLen; - NdisMoveMemory(SupRate, NewRate, NewRateLen); -} - -#ifdef CONFIG_STA_SUPPORT -#ifdef DOT11_N_SUPPORT -BOOLEAN RTMPCheckChannel( - IN PRTMP_ADAPTER pAd, - IN UCHAR CentralChannel, - IN UCHAR Channel) -{ - UCHAR k; - UCHAR UpperChannel = 0, LowerChannel = 0; - UCHAR NoEffectChannelinList = 0; - - // Find upper and lower channel according to 40MHz current operation. - if (CentralChannel < Channel) - { - UpperChannel = Channel; - if (CentralChannel > 2) - LowerChannel = CentralChannel - 2; - else - return FALSE; - } - else if (CentralChannel > Channel) - { - UpperChannel = CentralChannel + 2; - LowerChannel = Channel; - } - - for (k = 0;k < pAd->ChannelListNum;k++) - { - if (pAd->ChannelList[k].Channel == UpperChannel) - { - NoEffectChannelinList ++; - } - if (pAd->ChannelList[k].Channel == LowerChannel) - { - NoEffectChannelinList ++; - } - } - - DBGPRINT(RT_DEBUG_TRACE,("Total Channel in Channel List = [%d]\n", NoEffectChannelinList)); - if (NoEffectChannelinList == 2) - return TRUE; - else - return FALSE; -} - -/* - ======================================================================== - - Routine Description: - Verify the support rate for HT phy type - - Arguments: - pAd Pointer to our adapter - - Return Value: - FALSE if pAd->CommonCfg.SupportedHtPhy doesn't accept the pHtCapability. (AP Mode) - - IRQL = PASSIVE_LEVEL - - ======================================================================== -*/ -BOOLEAN RTMPCheckHt( - IN PRTMP_ADAPTER pAd, - IN UCHAR Wcid, - IN HT_CAPABILITY_IE *pHtCapability, - IN ADD_HT_INFO_IE *pAddHtInfo) -{ - if (Wcid >= MAX_LEN_OF_MAC_TABLE) - return FALSE; - - // If use AMSDU, set flag. - if (pAd->CommonCfg.DesiredHtPhy.AmsduEnable) - CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid], fCLIENT_STATUS_AMSDU_INUSED); - // Save Peer Capability - if (pHtCapability->HtCapInfo.ShortGIfor20) - CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid], fCLIENT_STATUS_SGI20_CAPABLE); - if (pHtCapability->HtCapInfo.ShortGIfor40) - CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid], fCLIENT_STATUS_SGI40_CAPABLE); - if (pHtCapability->HtCapInfo.TxSTBC) - CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid], fCLIENT_STATUS_TxSTBC_CAPABLE); - if (pHtCapability->HtCapInfo.RxSTBC) - CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid], fCLIENT_STATUS_RxSTBC_CAPABLE); - if (pAd->CommonCfg.bRdg && pHtCapability->ExtHtCapInfo.RDGSupport) - { - CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid], fCLIENT_STATUS_RDG_CAPABLE); - } - - if (Wcid < MAX_LEN_OF_MAC_TABLE) - { - pAd->MacTab.Content[Wcid].MpduDensity = pHtCapability->HtCapParm.MpduDensity; - } - - // Will check ChannelWidth for MCSSet[4] below - pAd->MlmeAux.HtCapability.MCSSet[4] = 0x1; - switch (pAd->CommonCfg.RxStream) - { - case 1: - pAd->MlmeAux.HtCapability.MCSSet[0] = 0xff; - pAd->MlmeAux.HtCapability.MCSSet[1] = 0x00; - pAd->MlmeAux.HtCapability.MCSSet[2] = 0x00; - pAd->MlmeAux.HtCapability.MCSSet[3] = 0x00; - break; - case 2: - pAd->MlmeAux.HtCapability.MCSSet[0] = 0xff; - pAd->MlmeAux.HtCapability.MCSSet[1] = 0xff; - pAd->MlmeAux.HtCapability.MCSSet[2] = 0x00; - pAd->MlmeAux.HtCapability.MCSSet[3] = 0x00; - break; - case 3: - pAd->MlmeAux.HtCapability.MCSSet[0] = 0xff; - pAd->MlmeAux.HtCapability.MCSSet[1] = 0xff; - pAd->MlmeAux.HtCapability.MCSSet[2] = 0xff; - pAd->MlmeAux.HtCapability.MCSSet[3] = 0x00; - break; - } - - pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth = pAddHtInfo->AddHtInfo.RecomWidth & pAd->CommonCfg.DesiredHtPhy.ChannelWidth; - - DBGPRINT(RT_DEBUG_TRACE, ("RTMPCheckHt:: HtCapInfo.ChannelWidth=%d, RecomWidth=%d, DesiredHtPhy.ChannelWidth=%d, BW40MAvailForA/G=%d/%d, PhyMode=%d \n", - pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth, pAddHtInfo->AddHtInfo.RecomWidth, pAd->CommonCfg.DesiredHtPhy.ChannelWidth, - pAd->NicConfig2.field.BW40MAvailForA, pAd->NicConfig2.field.BW40MAvailForG, pAd->CommonCfg.PhyMode)); - - pAd->MlmeAux.HtCapability.HtCapInfo.GF = pHtCapability->HtCapInfo.GF &pAd->CommonCfg.DesiredHtPhy.GF; - - // Send Assoc Req with my HT capability. - pAd->MlmeAux.HtCapability.HtCapInfo.AMsduSize = pAd->CommonCfg.DesiredHtPhy.AmsduSize; - pAd->MlmeAux.HtCapability.HtCapInfo.MimoPs = pAd->CommonCfg.DesiredHtPhy.MimoPs; - pAd->MlmeAux.HtCapability.HtCapInfo.ShortGIfor20 = (pAd->CommonCfg.DesiredHtPhy.ShortGIfor20) & (pHtCapability->HtCapInfo.ShortGIfor20); - pAd->MlmeAux.HtCapability.HtCapInfo.ShortGIfor40 = (pAd->CommonCfg.DesiredHtPhy.ShortGIfor40) & (pHtCapability->HtCapInfo.ShortGIfor40); - pAd->MlmeAux.HtCapability.HtCapInfo.TxSTBC = (pAd->CommonCfg.DesiredHtPhy.TxSTBC)&(pHtCapability->HtCapInfo.RxSTBC); - pAd->MlmeAux.HtCapability.HtCapInfo.RxSTBC = (pAd->CommonCfg.DesiredHtPhy.RxSTBC)&(pHtCapability->HtCapInfo.TxSTBC); - pAd->MlmeAux.HtCapability.HtCapParm.MaxRAmpduFactor = pAd->CommonCfg.DesiredHtPhy.MaxRAmpduFactor; - pAd->MlmeAux.HtCapability.HtCapParm.MpduDensity = pAd->CommonCfg.HtCapability.HtCapParm.MpduDensity; - pAd->MlmeAux.HtCapability.ExtHtCapInfo.PlusHTC = pHtCapability->ExtHtCapInfo.PlusHTC; - pAd->MacTab.Content[Wcid].HTCapability.ExtHtCapInfo.PlusHTC = pHtCapability->ExtHtCapInfo.PlusHTC; - if (pAd->CommonCfg.bRdg) - { - pAd->MlmeAux.HtCapability.ExtHtCapInfo.RDGSupport = pHtCapability->ExtHtCapInfo.RDGSupport; - pAd->MlmeAux.HtCapability.ExtHtCapInfo.PlusHTC = 1; - } - - if (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_20) - pAd->MlmeAux.HtCapability.MCSSet[4] = 0x0; // BW20 can't transmit MCS32 - - COPY_AP_HTSETTINGS_FROM_BEACON(pAd, pHtCapability); - return TRUE; -} -#endif // DOT11_N_SUPPORT // -#endif // CONFIG_STA_SUPPORT // - -/* - ======================================================================== - - Routine Description: - Verify the support rate for different PHY type - - Arguments: - pAd Pointer to our adapter - - Return Value: - None - - IRQL = PASSIVE_LEVEL - - ======================================================================== -*/ -VOID RTMPUpdateMlmeRate( - IN PRTMP_ADAPTER pAd) -{ - UCHAR MinimumRate; - UCHAR ProperMlmeRate; //= RATE_54; - UCHAR i, j, RateIdx = 12; //1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54 - BOOLEAN bMatch = FALSE; - - switch (pAd->CommonCfg.PhyMode) - { - case PHY_11B: - ProperMlmeRate = RATE_11; - MinimumRate = RATE_1; - break; - case PHY_11BG_MIXED: -#ifdef DOT11_N_SUPPORT - case PHY_11ABGN_MIXED: - case PHY_11BGN_MIXED: -#endif // DOT11_N_SUPPORT // - if ((pAd->MlmeAux.SupRateLen == 4) && - (pAd->MlmeAux.ExtRateLen == 0)) - // B only AP - ProperMlmeRate = RATE_11; - else - ProperMlmeRate = RATE_24; - - if (pAd->MlmeAux.Channel <= 14) - MinimumRate = RATE_1; - else - MinimumRate = RATE_6; - break; - case PHY_11A: -#ifdef DOT11_N_SUPPORT - case PHY_11N_2_4G: // rt2860 need to check mlmerate for 802.11n - case PHY_11GN_MIXED: - case PHY_11AGN_MIXED: - case PHY_11AN_MIXED: - case PHY_11N_5G: -#endif // DOT11_N_SUPPORT // - ProperMlmeRate = RATE_24; - MinimumRate = RATE_6; - break; - case PHY_11ABG_MIXED: - ProperMlmeRate = RATE_24; - if (pAd->MlmeAux.Channel <= 14) - MinimumRate = RATE_1; - else - MinimumRate = RATE_6; - break; - default: // error - ProperMlmeRate = RATE_1; - MinimumRate = RATE_1; - break; - } - - for (i = 0; i < pAd->MlmeAux.SupRateLen; i++) - { - for (j = 0; j < RateIdx; j++) - { - if ((pAd->MlmeAux.SupRate[i] & 0x7f) == RateIdTo500Kbps[j]) - { - if (j == ProperMlmeRate) - { - bMatch = TRUE; - break; - } - } - } - - if (bMatch) - break; - } - - if (bMatch == FALSE) - { - for (i = 0; i < pAd->MlmeAux.ExtRateLen; i++) - { - for (j = 0; j < RateIdx; j++) - { - if ((pAd->MlmeAux.ExtRate[i] & 0x7f) == RateIdTo500Kbps[j]) - { - if (j == ProperMlmeRate) - { - bMatch = TRUE; - break; - } - } - } - - if (bMatch) - break; - } - } - - if (bMatch == FALSE) - { - ProperMlmeRate = MinimumRate; - } - - pAd->CommonCfg.MlmeRate = MinimumRate; - pAd->CommonCfg.RtsRate = ProperMlmeRate; - if (pAd->CommonCfg.MlmeRate >= RATE_6) - { - pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM; - pAd->CommonCfg.MlmeTransmit.field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate]; - pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MODE = MODE_OFDM; - pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate]; - } - else - { - pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_CCK; - pAd->CommonCfg.MlmeTransmit.field.MCS = pAd->CommonCfg.MlmeRate; - pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MODE = MODE_CCK; - pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MCS = pAd->CommonCfg.MlmeRate; - } - - DBGPRINT(RT_DEBUG_TRACE, ("RTMPUpdateMlmeRate ==> MlmeTransmit = 0x%x \n" , pAd->CommonCfg.MlmeTransmit.word)); -} - -CHAR RTMPMaxRssi( - IN PRTMP_ADAPTER pAd, - IN CHAR Rssi0, - IN CHAR Rssi1, - IN CHAR Rssi2) -{ - CHAR larger = -127; - - if ((pAd->Antenna.field.RxPath == 1) && (Rssi0 != 0)) - { - larger = Rssi0; - } - - if ((pAd->Antenna.field.RxPath >= 2) && (Rssi1 != 0)) - { - larger = max(Rssi0, Rssi1); - } - - if ((pAd->Antenna.field.RxPath == 3) && (Rssi2 != 0)) - { - larger = max(larger, Rssi2); - } - - if (larger == -127) - larger = 0; - - return larger; -} - -/* - ======================================================================== - Routine Description: - Periodic evaluate antenna link status - - Arguments: - pAd - Adapter pointer - - Return Value: - None - - ======================================================================== -*/ -VOID AsicEvaluateRxAnt( - IN PRTMP_ADAPTER pAd) -{ - UCHAR BBPR3 = 0; - -#ifdef RALINK_ATE - if (ATE_ON(pAd)) - return; -#endif // RALINK_ATE // - - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS | - fRTMP_ADAPTER_HALT_IN_PROGRESS | - fRTMP_ADAPTER_RADIO_OFF | - fRTMP_ADAPTER_NIC_NOT_EXIST | - fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) - return; - - if (pAd->StaCfg.Psm == PWR_SAVE) - return; - } -#endif // CONFIG_STA_SUPPORT // - - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BBPR3); - BBPR3 &= (~0x18); - if(pAd->Antenna.field.RxPath == 3) - { - BBPR3 |= (0x10); - } - else if(pAd->Antenna.field.RxPath == 2) - { - BBPR3 |= (0x8); - } - else if(pAd->Antenna.field.RxPath == 1) - { - BBPR3 |= (0x0); - } - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BBPR3); -#ifdef CONFIG_STA_SUPPORT -#endif // CONFIG_STA_SUPPORT // - if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) - ) - { - ULONG TxTotalCnt = pAd->RalinkCounters.OneSecTxNoRetryOkCount + - pAd->RalinkCounters.OneSecTxRetryOkCount + - pAd->RalinkCounters.OneSecTxFailCount; - - if (TxTotalCnt > 50) - { - RTMPSetTimer(&pAd->Mlme.RxAntEvalTimer, 20); - pAd->Mlme.bLowThroughput = FALSE; - } - else - { - RTMPSetTimer(&pAd->Mlme.RxAntEvalTimer, 300); - pAd->Mlme.bLowThroughput = TRUE; - } - } -} - -/* - ======================================================================== - Routine Description: - After evaluation, check antenna link status - - Arguments: - pAd - Adapter pointer - - Return Value: - None - - ======================================================================== -*/ -VOID AsicRxAntEvalTimeout( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3) -{ - RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext; -#ifdef CONFIG_STA_SUPPORT - UCHAR BBPR3 = 0; - CHAR larger = -127, rssi0, rssi1, rssi2; -#endif // CONFIG_STA_SUPPORT // - -#ifdef RALINK_ATE - if (ATE_ON(pAd)) - return; -#endif // RALINK_ATE // - - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS) || - RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS) || - RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF) || - RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) - return; - - if (pAd->StaCfg.Psm == PWR_SAVE) - return; - - - // if the traffic is low, use average rssi as the criteria - if (pAd->Mlme.bLowThroughput == TRUE) - { - rssi0 = pAd->StaCfg.RssiSample.LastRssi0; - rssi1 = pAd->StaCfg.RssiSample.LastRssi1; - rssi2 = pAd->StaCfg.RssiSample.LastRssi2; - } - else - { - rssi0 = pAd->StaCfg.RssiSample.AvgRssi0; - rssi1 = pAd->StaCfg.RssiSample.AvgRssi1; - rssi2 = pAd->StaCfg.RssiSample.AvgRssi2; - } - - if(pAd->Antenna.field.RxPath == 3) - { - larger = max(rssi0, rssi1); - - if (larger > (rssi2 + 20)) - pAd->Mlme.RealRxPath = 2; - else - pAd->Mlme.RealRxPath = 3; - } - else if(pAd->Antenna.field.RxPath == 2) - { - if (rssi0 > (rssi1 + 20)) - pAd->Mlme.RealRxPath = 1; - else - pAd->Mlme.RealRxPath = 2; - } - - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BBPR3); - BBPR3 &= (~0x18); - if(pAd->Mlme.RealRxPath == 3) - { - BBPR3 |= (0x10); - } - else if(pAd->Mlme.RealRxPath == 2) - { - BBPR3 |= (0x8); - } - else if(pAd->Mlme.RealRxPath == 1) - { - BBPR3 |= (0x0); - } - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BBPR3); - } - -#endif // CONFIG_STA_SUPPORT // - -} - - - -VOID APSDPeriodicExec( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3) -{ - RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext; - - if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) - return; - - pAd->CommonCfg.TriggerTimerCount++; - -// Driver should not send trigger frame, it should be send by application layer -/* - if (pAd->CommonCfg.bAPSDCapable && pAd->CommonCfg.APEdcaParm.bAPSDCapable - && (pAd->CommonCfg.bNeedSendTriggerFrame || - (((pAd->CommonCfg.TriggerTimerCount%20) == 19) && (!pAd->CommonCfg.bAPSDAC_BE || !pAd->CommonCfg.bAPSDAC_BK || !pAd->CommonCfg.bAPSDAC_VI || !pAd->CommonCfg.bAPSDAC_VO)))) - { - DBGPRINT(RT_DEBUG_TRACE,("Sending trigger frame and enter service period when support APSD\n")); - RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, TRUE); - pAd->CommonCfg.bNeedSendTriggerFrame = FALSE; - pAd->CommonCfg.TriggerTimerCount = 0; - pAd->CommonCfg.bInServicePeriod = TRUE; - }*/ -} - -/* - ======================================================================== - Routine Description: - Set/reset MAC registers according to bPiggyBack parameter - - Arguments: - pAd - Adapter pointer - bPiggyBack - Enable / Disable Piggy-Back - - Return Value: - None - - ======================================================================== -*/ -VOID RTMPSetPiggyBack( - IN PRTMP_ADAPTER pAd, - IN BOOLEAN bPiggyBack) -{ - TX_LINK_CFG_STRUC TxLinkCfg; - - RTMP_IO_READ32(pAd, TX_LINK_CFG, &TxLinkCfg.word); - - TxLinkCfg.field.TxCFAckEn = bPiggyBack; - RTMP_IO_WRITE32(pAd, TX_LINK_CFG, TxLinkCfg.word); -} - -/* - ======================================================================== - Routine Description: - check if this entry need to switch rate automatically - - Arguments: - pAd - pEntry - - Return Value: - TURE - FALSE - - ======================================================================== -*/ -BOOLEAN RTMPCheckEntryEnableAutoRateSwitch( - IN PRTMP_ADAPTER pAd, - IN PMAC_TABLE_ENTRY pEntry) -{ - BOOLEAN result = TRUE; - - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - // only associated STA counts - if (pEntry && (pEntry->ValidAsCLI) && (pEntry->Sst == SST_ASSOC)) - { - result = pAd->StaCfg.bAutoTxRateSwitch; - } - else - result = FALSE; - -#ifdef QOS_DLS_SUPPORT - if (pEntry && (pEntry->ValidAsDls)) - result = pAd->StaCfg.bAutoTxRateSwitch; -#endif // QOS_DLS_SUPPORT // - } -#endif // CONFIG_STA_SUPPORT // - - - - return result; -} - - -BOOLEAN RTMPAutoRateSwitchCheck( - IN PRTMP_ADAPTER pAd) -{ - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - if (pAd->StaCfg.bAutoTxRateSwitch) - return TRUE; - } -#endif // CONFIG_STA_SUPPORT // - return FALSE; -} - - -/* - ======================================================================== - Routine Description: - check if this entry need to fix tx legacy rate - - Arguments: - pAd - pEntry - - Return Value: - TURE - FALSE - - ======================================================================== -*/ -UCHAR RTMPStaFixedTxMode( - IN PRTMP_ADAPTER pAd, - IN PMAC_TABLE_ENTRY pEntry) -{ - UCHAR tx_mode = FIXED_TXMODE_HT; - - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - tx_mode = (UCHAR)pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode; - } -#endif // CONFIG_STA_SUPPORT // - - return tx_mode; -} - -/* - ======================================================================== - Routine Description: - Overwrite HT Tx Mode by Fixed Legency Tx Mode, if specified. - - Arguments: - pAd - pEntry - - Return Value: - TURE - FALSE - - ======================================================================== -*/ -VOID RTMPUpdateLegacyTxSetting( - UCHAR fixed_tx_mode, - PMAC_TABLE_ENTRY pEntry) -{ - HTTRANSMIT_SETTING TransmitSetting; - - if (fixed_tx_mode == FIXED_TXMODE_HT) - return; - - TransmitSetting.word = 0; - - TransmitSetting.field.MODE = pEntry->HTPhyMode.field.MODE; - TransmitSetting.field.MCS = pEntry->HTPhyMode.field.MCS; - - if (fixed_tx_mode == FIXED_TXMODE_CCK) - { - TransmitSetting.field.MODE = MODE_CCK; - // CCK mode allow MCS 0~3 - if (TransmitSetting.field.MCS > MCS_3) - TransmitSetting.field.MCS = MCS_3; - } - else - { - TransmitSetting.field.MODE = MODE_OFDM; - // OFDM mode allow MCS 0~7 - if (TransmitSetting.field.MCS > MCS_7) - TransmitSetting.field.MCS = MCS_7; - } - - if (pEntry->HTPhyMode.field.MODE >= TransmitSetting.field.MODE) - { - pEntry->HTPhyMode.word = TransmitSetting.word; - DBGPRINT(RT_DEBUG_TRACE, ("RTMPUpdateLegacyTxSetting : wcid-%d, MODE=%s, MCS=%d \n", - pEntry->Aid, GetPhyMode(pEntry->HTPhyMode.field.MODE), pEntry->HTPhyMode.field.MCS)); - } -} - -#ifdef CONFIG_STA_SUPPORT -/* - ========================================================================== - Description: - dynamic tune BBP R66 to find a balance between sensibility and - noise isolation - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID AsicStaBbpTuning( - IN PRTMP_ADAPTER pAd) -{ - UCHAR OrigR66Value = 0, R66;//, R66UpperBound = 0x30, R66LowerBound = 0x30; - CHAR Rssi; - - // 2860C did not support Fase CCA, therefore can't tune - if (pAd->MACVersion == 0x28600100) - return; - - // - // work as a STA - // - if (pAd->Mlme.CntlMachine.CurrState != CNTL_IDLE) // no R66 tuning when SCANNING - return; - - if ((pAd->OpMode == OPMODE_STA) - && (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) - ) - && !(OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) - ) - { - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R66, &OrigR66Value); - R66 = OrigR66Value; - - if (pAd->Antenna.field.RxPath > 1) - Rssi = (pAd->StaCfg.RssiSample.AvgRssi0 + pAd->StaCfg.RssiSample.AvgRssi1) >> 1; - else - Rssi = pAd->StaCfg.RssiSample.AvgRssi0; - - if (pAd->LatchRfRegs.Channel <= 14) - { //BG band -#ifdef RT2870 - // RT3070 is a no LNA solution, it should have different control regarding to AGC gain control - // Otherwise, it will have some throughput side effect when low RSSI - if (IS_RT3070(pAd)) - { - if (Rssi > RSSI_FOR_MID_LOW_SENSIBILITY) - { - R66 = 0x1C + 2*GET_LNA_GAIN(pAd) + 0x20; - if (OrigR66Value != R66) - { - RTUSBWriteBBPRegister(pAd, BBP_R66, R66); - } - } - else - { - R66 = 0x1C + 2*GET_LNA_GAIN(pAd); - if (OrigR66Value != R66) - { - RTUSBWriteBBPRegister(pAd, BBP_R66, R66); - } - } - } - else -#endif // RT2870 // - { - if (Rssi > RSSI_FOR_MID_LOW_SENSIBILITY) - { - R66 = (0x2E + GET_LNA_GAIN(pAd)) + 0x10; - if (OrigR66Value != R66) - { - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); - } - } - else - { - R66 = 0x2E + GET_LNA_GAIN(pAd); - if (OrigR66Value != R66) - { - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); - } - } - } - } - else - { //A band - if (pAd->CommonCfg.BBPCurrentBW == BW_20) - { - if (Rssi > RSSI_FOR_MID_LOW_SENSIBILITY) - { - R66 = 0x32 + (GET_LNA_GAIN(pAd)*5)/3 + 0x10; - if (OrigR66Value != R66) - { - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); - } - } - else - { - R66 = 0x32 + (GET_LNA_GAIN(pAd)*5)/3; - if (OrigR66Value != R66) - { - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); - } - } - } - else - { - if (Rssi > RSSI_FOR_MID_LOW_SENSIBILITY) - { - R66 = 0x3A + (GET_LNA_GAIN(pAd)*5)/3 + 0x10; - if (OrigR66Value != R66) - { - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); - } - } - else - { - R66 = 0x3A + (GET_LNA_GAIN(pAd)*5)/3; - if (OrigR66Value != R66) - { - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); - } - } - } - } - - - } -} -#endif // CONFIG_STA_SUPPORT // - -VOID RTMPSetAGCInitValue( - IN PRTMP_ADAPTER pAd, - IN UCHAR BandWidth) -{ - UCHAR R66 = 0x30; - - if (pAd->LatchRfRegs.Channel <= 14) - { // BG band - R66 = 0x2E + GET_LNA_GAIN(pAd); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); - } - else - { //A band - if (BandWidth == BW_20) - { - R66 = (UCHAR)(0x32 + (GET_LNA_GAIN(pAd)*5)/3); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); - } -#ifdef DOT11_N_SUPPORT - else - { - R66 = (UCHAR)(0x3A + (GET_LNA_GAIN(pAd)*5)/3); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); - } -#endif // DOT11_N_SUPPORT // - } - -} - -VOID AsicTurnOffRFClk( - IN PRTMP_ADAPTER pAd, - IN UCHAR Channel) -{ - - // RF R2 bit 18 = 0 - UINT32 R1 = 0, R2 = 0, R3 = 0; - UCHAR index; - RTMP_RF_REGS *RFRegTable; - - RFRegTable = RF2850RegTable; - - switch (pAd->RfIcType) - { - case RFIC_2820: - case RFIC_2850: - case RFIC_2720: - case RFIC_2750: - - for (index = 0; index < NUM_OF_2850_CHNL; index++) - { - if (Channel == RFRegTable[index].Channel) - { - R1 = RFRegTable[index].R1 & 0xffffdfff; - R2 = RFRegTable[index].R2 & 0xfffbffff; - R3 = RFRegTable[index].R3 & 0xfff3ffff; - - RTMP_RF_IO_WRITE32(pAd, R1); - RTMP_RF_IO_WRITE32(pAd, R2); - - // Program R1b13 to 1, R3/b18,19 to 0, R2b18 to 0. - // Set RF R2 bit18=0, R3 bit[18:19]=0 - //if (pAd->StaCfg.bRadio == FALSE) - if (1) - { - RTMP_RF_IO_WRITE32(pAd, R3); - - DBGPRINT(RT_DEBUG_TRACE, ("AsicTurnOffRFClk#%d(RF=%d, ) , R2=0x%08x, R3 = 0x%08x \n", - Channel, pAd->RfIcType, R2, R3)); - } - else - DBGPRINT(RT_DEBUG_TRACE, ("AsicTurnOffRFClk#%d(RF=%d, ) , R2=0x%08x \n", - Channel, pAd->RfIcType, R2)); - break; - } - } - break; - - default: - break; - } -} - - -VOID AsicTurnOnRFClk( - IN PRTMP_ADAPTER pAd, - IN UCHAR Channel) -{ - - // RF R2 bit 18 = 0 - UINT32 R1 = 0, R2 = 0, R3 = 0; - UCHAR index; - RTMP_RF_REGS *RFRegTable; - - RFRegTable = RF2850RegTable; - - switch (pAd->RfIcType) - { - case RFIC_2820: - case RFIC_2850: - case RFIC_2720: - case RFIC_2750: - - for (index = 0; index < NUM_OF_2850_CHNL; index++) - { - if (Channel == RFRegTable[index].Channel) - { - R3 = pAd->LatchRfRegs.R3; - R3 &= 0xfff3ffff; - R3 |= 0x00080000; - RTMP_RF_IO_WRITE32(pAd, R3); - - R1 = RFRegTable[index].R1; - RTMP_RF_IO_WRITE32(pAd, R1); - - R2 = RFRegTable[index].R2; - if (pAd->Antenna.field.TxPath == 1) - { - R2 |= 0x4000; // If TXpath is 1, bit 14 = 1; - } - - if (pAd->Antenna.field.RxPath == 2) - { - R2 |= 0x40; // write 1 to off Rxpath. - } - else if (pAd->Antenna.field.RxPath == 1) - { - R2 |= 0x20040; // write 1 to off RxPath - } - RTMP_RF_IO_WRITE32(pAd, R2); - - break; - } - } - break; - - default: - break; - } - - DBGPRINT(RT_DEBUG_TRACE, ("AsicTurnOnRFClk#%d(RF=%d, ) , R2=0x%08x\n", - Channel, - pAd->RfIcType, - R2)); -} - +#include "../../rt2860/common/mlme.c" diff --git a/drivers/staging/rt2870/common/netif_block.c b/drivers/staging/rt2870/common/netif_block.c deleted file mode 100644 index d3f7d087e7f0..000000000000 --- a/drivers/staging/rt2870/common/netif_block.c +++ /dev/null @@ -1,144 +0,0 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * 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 "../rt_config.h" -#include "netif_block.h" - -static NETIF_ENTRY freeNetIfEntryPool[FREE_NETIF_POOL_SIZE]; -static LIST_HEADER freeNetIfEntryList; - -void initblockQueueTab( - IN PRTMP_ADAPTER pAd) -{ - int i; - - initList(&freeNetIfEntryList); - for (i = 0; i < FREE_NETIF_POOL_SIZE; i++) - insertTailList(&freeNetIfEntryList, (PLIST_ENTRY)&freeNetIfEntryPool[i]); - - for (i=0; i < NUM_OF_TX_RING; i++) - initList(&pAd->blockQueueTab[i].NetIfList); - - return; -} - -BOOLEAN blockNetIf( - IN PBLOCK_QUEUE_ENTRY pBlockQueueEntry, - IN PNET_DEV pNetDev) -{ - PNETIF_ENTRY pNetIfEntry = NULL; - - if ((pNetIfEntry = (PNETIF_ENTRY)removeHeadList(&freeNetIfEntryList)) != NULL) - { - netif_stop_queue(pNetDev); - pNetIfEntry->pNetDev = pNetDev; - insertTailList(&pBlockQueueEntry->NetIfList, (PLIST_ENTRY)pNetIfEntry); - - pBlockQueueEntry->SwTxQueueBlockFlag = TRUE; - DBGPRINT(RT_DEBUG_TRACE, ("netif_stop_queue(%s)\n", pNetDev->name)); - } - else - return FALSE; - - return TRUE; -} - -VOID releaseNetIf( - IN PBLOCK_QUEUE_ENTRY pBlockQueueEntry) -{ - PNETIF_ENTRY pNetIfEntry = NULL; - PLIST_HEADER pNetIfList = &pBlockQueueEntry->NetIfList; - - while((pNetIfEntry = (PNETIF_ENTRY)removeHeadList(pNetIfList)) != NULL) - { - PNET_DEV pNetDev = pNetIfEntry->pNetDev; - netif_wake_queue(pNetDev); - insertTailList(&freeNetIfEntryList, (PLIST_ENTRY)pNetIfEntry); - - DBGPRINT(RT_DEBUG_TRACE, ("netif_wake_queue(%s)\n", pNetDev->name)); - } - pBlockQueueEntry->SwTxQueueBlockFlag = FALSE; - return; -} - - -VOID StopNetIfQueue( - IN PRTMP_ADAPTER pAd, - IN UCHAR QueIdx, - IN PNDIS_PACKET pPacket) -{ - PNET_DEV NetDev = NULL; - UCHAR IfIdx = 0; - BOOLEAN valid = FALSE; - -#ifdef APCLI_SUPPORT - if (RTMP_GET_PACKET_NET_DEVICE(pPacket) >= MIN_NET_DEVICE_FOR_APCLI) - { - IfIdx = (RTMP_GET_PACKET_NET_DEVICE(pPacket) - MIN_NET_DEVICE_FOR_APCLI) % MAX_APCLI_NUM; - NetDev = pAd->ApCfg.ApCliTab[IfIdx].dev; - } - else -#endif // APCLI_SUPPORT // -#ifdef WDS_SUPPORT - if (RTMP_GET_PACKET_NET_DEVICE(pPacket) >= MIN_NET_DEVICE_FOR_WDS) - { - IfIdx = (RTMP_GET_PACKET_NET_DEVICE(pPacket) - MIN_NET_DEVICE_FOR_WDS) % MAX_WDS_ENTRY; - NetDev = pAd->WdsTab.WdsEntry[IfIdx].dev; - } - else -#endif // WDS_SUPPORT // - { -#ifdef MBSS_SUPPORT - if (pAd->OpMode == OPMODE_AP) - { - IfIdx = (RTMP_GET_PACKET_NET_DEVICE(pPacket) - MIN_NET_DEVICE_FOR_MBSSID) % MAX_MBSSID_NUM; - NetDev = pAd->ApCfg.MBSSID[IfIdx].MSSIDDev; - } - else - { - IfIdx = MAIN_MBSSID; - NetDev = pAd->net_dev; - } -#else - IfIdx = MAIN_MBSSID; - NetDev = pAd->net_dev; -#endif - } - - // WMM support 4 software queues. - // One software queue full doesn't mean device have no capbility to transmit packet. - // So disable block Net-If queue function while WMM enable. -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - valid = (pAd->CommonCfg.bWmmCapable == TRUE) ? FALSE : TRUE; -#endif // CONFIG_STA_SUPPORT // - - if (valid) - blockNetIf(&pAd->blockQueueTab[QueIdx], NetDev); - return; -} - diff --git a/drivers/staging/rt2870/common/rtmp_init.c b/drivers/staging/rt2870/common/rtmp_init.c index 099b6a806f86..eef10efda196 100644 --- a/drivers/staging/rt2870/common/rtmp_init.c +++ b/drivers/staging/rt2870/common/rtmp_init.c @@ -1,4132 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - rtmp_init.c - - Abstract: - Miniport generic portion header file - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Paul Lin 2002-08-01 created - John Chang 2004-08-20 RT2561/2661 use scatter-gather scheme - Jan Lee 2006-09-15 RT2860. Change for 802.11n , EEPROM, Led, BA, HT. -*/ -#include "../rt_config.h" -#include "firmware.h" - -//#define BIN_IN_FILE /* use *.bin firmware */ - -UCHAR BIT8[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}; -ULONG BIT32[] = {0x00000001, 0x00000002, 0x00000004, 0x00000008, - 0x00000010, 0x00000020, 0x00000040, 0x00000080, - 0x00000100, 0x00000200, 0x00000400, 0x00000800, - 0x00001000, 0x00002000, 0x00004000, 0x00008000, - 0x00010000, 0x00020000, 0x00040000, 0x00080000, - 0x00100000, 0x00200000, 0x00400000, 0x00800000, - 0x01000000, 0x02000000, 0x04000000, 0x08000000, - 0x10000000, 0x20000000, 0x40000000, 0x80000000}; - -char* CipherName[] = {"none","wep64","wep128","TKIP","AES","CKIP64","CKIP128"}; - -const unsigned short ccitt_16Table[] = { - 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, - 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, - 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, - 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, - 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, - 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, - 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, - 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, - 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, - 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, - 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, - 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, - 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, - 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, - 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, - 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, - 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, - 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, - 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, - 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, - 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, - 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, - 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, - 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, - 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, - 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, - 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, - 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, - 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, - 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, - 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, - 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0 -}; -#define ByteCRC16(v, crc) \ - (unsigned short)((crc << 8) ^ ccitt_16Table[((crc >> 8) ^ (v)) & 255]) - -unsigned char BitReverse(unsigned char x) -{ - int i; - unsigned char Temp=0; - for(i=0; ; i++) - { - if(x & 0x80) Temp |= 0x80; - if(i==7) break; - x <<= 1; - Temp >>= 1; - } - return Temp; -} - -// -// BBP register initialization set -// -REG_PAIR BBPRegTable[] = { - {BBP_R65, 0x2C}, // fix rssi issue - {BBP_R66, 0x38}, // Also set this default value to pAd->BbpTuning.R66CurrentValue at initial - {BBP_R69, 0x12}, - {BBP_R70, 0xa}, // BBP_R70 will change to 0x8 in ApStartUp and LinkUp for rt2860C, otherwise value is 0xa - {BBP_R73, 0x10}, - {BBP_R81, 0x37}, - {BBP_R82, 0x62}, - {BBP_R83, 0x6A}, - {BBP_R84, 0x99}, // 0x19 is for rt2860E and after. This is for extension channel overlapping IOT. 0x99 is for rt2860D and before - {BBP_R86, 0x00}, // middle range issue, Rory @2008-01-28 - {BBP_R91, 0x04}, // middle range issue, Rory @2008-01-28 - {BBP_R92, 0x00}, // middle range issue, Rory @2008-01-28 - {BBP_R103, 0x00}, // near range high-power issue, requested from Gary @2008-0528 - {BBP_R105, 0x05}, // 0x05 is for rt2860E to turn on FEQ control. It is safe for rt2860D and before, because Bit 7:2 are reserved in rt2860D and before. -}; -#define NUM_BBP_REG_PARMS (sizeof(BBPRegTable) / sizeof(REG_PAIR)) - -// -// RF register initialization set -// -#ifdef RT2870 -REG_PAIR RT30xx_RFRegTable[] = { - {RF_R04, 0x40}, - {RF_R05, 0x03}, - {RF_R06, 0x02}, - {RF_R07, 0x70}, - {RF_R09, 0x0F}, - {RF_R10, 0x71}, - {RF_R11, 0x21}, - {RF_R12, 0x7B}, - {RF_R14, 0x90}, - {RF_R15, 0x58}, - {RF_R16, 0xB3}, - {RF_R17, 0x92}, - {RF_R18, 0x2C}, - {RF_R19, 0x02}, - {RF_R20, 0xBA}, - {RF_R21, 0xDB}, - {RF_R24, 0x16}, - {RF_R25, 0x01}, - {RF_R27, 0x03}, - {RF_R29, 0x1F}, -}; -#define NUM_RF_REG_PARMS (sizeof(RT30xx_RFRegTable) / sizeof(REG_PAIR)) -#endif // RT2870 // - -// -// ASIC register initialization sets -// - -RTMP_REG_PAIR MACRegTable[] = { -#if defined(HW_BEACON_OFFSET) && (HW_BEACON_OFFSET == 0x200) - {BCN_OFFSET0, 0xf8f0e8e0}, /* 0x3800(e0), 0x3A00(e8), 0x3C00(f0), 0x3E00(f8), 512B for each beacon */ - {BCN_OFFSET1, 0x6f77d0c8}, /* 0x3200(c8), 0x3400(d0), 0x1DC0(77), 0x1BC0(6f), 512B for each beacon */ -#elif defined(HW_BEACON_OFFSET) && (HW_BEACON_OFFSET == 0x100) - {BCN_OFFSET0, 0xece8e4e0}, /* 0x3800, 0x3A00, 0x3C00, 0x3E00, 512B for each beacon */ - {BCN_OFFSET1, 0xfcf8f4f0}, /* 0x3800, 0x3A00, 0x3C00, 0x3E00, 512B for each beacon */ -#else - #error You must re-calculate new value for BCN_OFFSET0 & BCN_OFFSET1 in MACRegTable[]!!! -#endif // HW_BEACON_OFFSET // - - {LEGACY_BASIC_RATE, 0x0000013f}, // Basic rate set bitmap - {HT_BASIC_RATE, 0x00008003}, // Basic HT rate set , 20M, MCS=3, MM. Format is the same as in TXWI. - {MAC_SYS_CTRL, 0x00}, // 0x1004, , default Disable RX - {RX_FILTR_CFG, 0x17f97}, //0x1400 , RX filter control, - {BKOFF_SLOT_CFG, 0x209}, // default set short slot time, CC_DELAY_TIME should be 2 - {TX_SW_CFG0, 0x0}, // Gary,2008-05-21 for CWC test - {TX_SW_CFG1, 0x80606}, // Gary,2006-08-23 - {TX_LINK_CFG, 0x1020}, // Gary,2006-08-23 - //{TX_TIMEOUT_CFG, 0x00182090}, // CCK has some problem. So increase timieout value. 2006-10-09// MArvek RT - {TX_TIMEOUT_CFG, 0x000a2090}, // CCK has some problem. So increase timieout value. 2006-10-09// MArvek RT , Modify for 2860E ,2007-08-01 - {MAX_LEN_CFG, MAX_AGGREGATION_SIZE | 0x00001000}, // 0x3018, MAX frame length. Max PSDU = 16kbytes. - {LED_CFG, 0x7f031e46}, // Gary, 2006-08-23 - {PBF_MAX_PCNT, 0x1F3FBF9F}, //0x1F3f7f9f}, //Jan, 2006/04/20 - //{TX_RTY_CFG, 0x6bb80408}, // Jan, 2006/11/16 - {TX_RTY_CFG, 0x47d01f0f}, // Jan, 2006/11/16, Set TxWI->ACK =0 in Probe Rsp Modify for 2860E ,2007-08-03 - {AUTO_RSP_CFG, 0x00000013}, // Initial Auto_Responder, because QA will turn off Auto-Responder - {CCK_PROT_CFG, 0x05740003 /*0x01740003*/}, // Initial Auto_Responder, because QA will turn off Auto-Responder. And RTS threshold is enabled. - {OFDM_PROT_CFG, 0x05740003 /*0x01740003*/}, // Initial Auto_Responder, because QA will turn off Auto-Responder. And RTS threshold is enabled. -#ifdef RT2870 - {PBF_CFG, 0xf40006}, // Only enable Queue 2 - {MM40_PROT_CFG, 0x3F44084}, // Initial Auto_Responder, because QA will turn off Auto-Responder - {WPDMA_GLO_CFG, 0x00000030}, -#endif // RT2870 // - {GF20_PROT_CFG, 0x01744004}, // set 19:18 --> Short NAV for MIMO PS - {GF40_PROT_CFG, 0x03F44084}, - {MM20_PROT_CFG, 0x01744004}, - {TXOP_CTRL_CFG, 0x0000583f, /*0x0000243f*/ /*0x000024bf*/}, //Extension channel backoff. - {TX_RTS_CFG, 0x00092b20}, -//#ifdef WIFI_TEST - {EXP_ACK_TIME, 0x002400ca}, // default value -//#else -// {EXP_ACK_TIME, 0x005400ca}, // suggested by Gray @ 20070323 for 11n intel-sta throughput -//#endif // end - WIFI_TEST // - {TXOP_HLDR_ET, 0x00000002}, - - /* Jerry comments 2008/01/16: we use SIFS = 10us in CCK defaultly, but it seems that 10us - is too small for INTEL 2200bg card, so in MBSS mode, the delta time between beacon0 - and beacon1 is SIFS (10us), so if INTEL 2200bg card connects to BSS0, the ping - will always lost. So we change the SIFS of CCK from 10us to 16us. */ - {XIFS_TIME_CFG, 0x33a41010}, - {PWR_PIN_CFG, 0x00000003}, // patch for 2880-E -}; - - -#ifdef CONFIG_STA_SUPPORT -RTMP_REG_PAIR STAMACRegTable[] = { - {WMM_AIFSN_CFG, 0x00002273}, - {WMM_CWMIN_CFG, 0x00002344}, - {WMM_CWMAX_CFG, 0x000034aa}, -}; -#endif // CONFIG_STA_SUPPORT // - -#define NUM_MAC_REG_PARMS (sizeof(MACRegTable) / sizeof(RTMP_REG_PAIR)) -#ifdef CONFIG_STA_SUPPORT -#define NUM_STA_MAC_REG_PARMS (sizeof(STAMACRegTable) / sizeof(RTMP_REG_PAIR)) -#endif // CONFIG_STA_SUPPORT // - -#ifdef RT2870 -// -// RT2870 Firmware Spec only used 1 oct for version expression -// -#define FIRMWARE_MINOR_VERSION 7 - -#endif // RT2870 // - -// New 8k byte firmware size for RT3071/RT3072 -#define FIRMWAREIMAGE_MAX_LENGTH 0x2000 -#define FIRMWAREIMAGE_LENGTH (sizeof (FirmwareImage) / sizeof(UCHAR)) -#define FIRMWARE_MAJOR_VERSION 0 - -#define FIRMWAREIMAGEV1_LENGTH 0x1000 -#define FIRMWAREIMAGEV2_LENGTH 0x1000 - - - -/* - ======================================================================== - - Routine Description: - Allocate RTMP_ADAPTER data block and do some initialization - - Arguments: - Adapter Pointer to our adapter - - Return Value: - NDIS_STATUS_SUCCESS - NDIS_STATUS_FAILURE - - IRQL = PASSIVE_LEVEL - - Note: - - ======================================================================== -*/ -NDIS_STATUS RTMPAllocAdapterBlock( - IN PVOID handle, - OUT PRTMP_ADAPTER *ppAdapter) -{ - PRTMP_ADAPTER pAd; - NDIS_STATUS Status; - INT index; - UCHAR *pBeaconBuf = NULL; - - DBGPRINT(RT_DEBUG_TRACE, ("--> RTMPAllocAdapterBlock\n")); - - *ppAdapter = NULL; - - do - { - // Allocate RTMP_ADAPTER memory block - pBeaconBuf = kmalloc(MAX_BEACON_SIZE, MEM_ALLOC_FLAG); - if (pBeaconBuf == NULL) - { - Status = NDIS_STATUS_FAILURE; - DBGPRINT_ERR(("Failed to allocate memory - BeaconBuf!\n")); - break; - } - - Status = AdapterBlockAllocateMemory(handle, (PVOID *)&pAd); - if (Status != NDIS_STATUS_SUCCESS) - { - DBGPRINT_ERR(("Failed to allocate memory - ADAPTER\n")); - break; - } - pAd->BeaconBuf = pBeaconBuf; - printk("\n\n=== pAd = %p, size = %d ===\n\n", pAd, (UINT32)sizeof(RTMP_ADAPTER)); - - - // Init spin locks - NdisAllocateSpinLock(&pAd->MgmtRingLock); - - for (index =0 ; index < NUM_OF_TX_RING; index++) - { - NdisAllocateSpinLock(&pAd->TxSwQueueLock[index]); - NdisAllocateSpinLock(&pAd->DeQueueLock[index]); - pAd->DeQueueRunning[index] = FALSE; - } - - NdisAllocateSpinLock(&pAd->irq_lock); - - } while (FALSE); - - if ((Status != NDIS_STATUS_SUCCESS) && (pBeaconBuf)) - kfree(pBeaconBuf); - - *ppAdapter = pAd; - - DBGPRINT_S(Status, ("<-- RTMPAllocAdapterBlock, Status=%x\n", Status)); - return Status; -} - -/* - ======================================================================== - - Routine Description: - Read initial Tx power per MCS and BW from EEPROM - - Arguments: - Adapter Pointer to our adapter - - Return Value: - None - - IRQL = PASSIVE_LEVEL - - Note: - - ======================================================================== -*/ -VOID RTMPReadTxPwrPerRate( - IN PRTMP_ADAPTER pAd) -{ - ULONG data, Adata, Gdata; - USHORT i, value, value2; - INT Apwrdelta, Gpwrdelta; - UCHAR t1,t2,t3,t4; - BOOLEAN bValid, bApwrdeltaMinus = TRUE, bGpwrdeltaMinus = TRUE; - - // - // Get power delta for 20MHz and 40MHz. - // - DBGPRINT(RT_DEBUG_TRACE, ("Txpower per Rate\n")); - RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_DELTA, value2); - Apwrdelta = 0; - Gpwrdelta = 0; - - if ((value2 & 0xff) != 0xff) - { - if ((value2 & 0x80)) - Gpwrdelta = (value2&0xf); - - if ((value2 & 0x40)) - bGpwrdeltaMinus = FALSE; - else - bGpwrdeltaMinus = TRUE; - } - if ((value2 & 0xff00) != 0xff00) - { - if ((value2 & 0x8000)) - Apwrdelta = ((value2&0xf00)>>8); - - if ((value2 & 0x4000)) - bApwrdeltaMinus = FALSE; - else - bApwrdeltaMinus = TRUE; - } - DBGPRINT(RT_DEBUG_TRACE, ("Gpwrdelta = %x, Apwrdelta = %x .\n", Gpwrdelta, Apwrdelta)); - - // - // Get Txpower per MCS for 20MHz in 2.4G. - // - for (i=0; i<5; i++) - { - RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_20MHZ_2_4G + i*4, value); - data = value; - if (bApwrdeltaMinus == FALSE) - { - t1 = (value&0xf)+(Apwrdelta); - if (t1 > 0xf) - t1 = 0xf; - t2 = ((value&0xf0)>>4)+(Apwrdelta); - if (t2 > 0xf) - t2 = 0xf; - t3 = ((value&0xf00)>>8)+(Apwrdelta); - if (t3 > 0xf) - t3 = 0xf; - t4 = ((value&0xf000)>>12)+(Apwrdelta); - if (t4 > 0xf) - t4 = 0xf; - } - else - { - if ((value&0xf) > Apwrdelta) - t1 = (value&0xf)-(Apwrdelta); - else - t1 = 0; - if (((value&0xf0)>>4) > Apwrdelta) - t2 = ((value&0xf0)>>4)-(Apwrdelta); - else - t2 = 0; - if (((value&0xf00)>>8) > Apwrdelta) - t3 = ((value&0xf00)>>8)-(Apwrdelta); - else - t3 = 0; - if (((value&0xf000)>>12) > Apwrdelta) - t4 = ((value&0xf000)>>12)-(Apwrdelta); - else - t4 = 0; - } - Adata = t1 + (t2<<4) + (t3<<8) + (t4<<12); - if (bGpwrdeltaMinus == FALSE) - { - t1 = (value&0xf)+(Gpwrdelta); - if (t1 > 0xf) - t1 = 0xf; - t2 = ((value&0xf0)>>4)+(Gpwrdelta); - if (t2 > 0xf) - t2 = 0xf; - t3 = ((value&0xf00)>>8)+(Gpwrdelta); - if (t3 > 0xf) - t3 = 0xf; - t4 = ((value&0xf000)>>12)+(Gpwrdelta); - if (t4 > 0xf) - t4 = 0xf; - } - else - { - if ((value&0xf) > Gpwrdelta) - t1 = (value&0xf)-(Gpwrdelta); - else - t1 = 0; - if (((value&0xf0)>>4) > Gpwrdelta) - t2 = ((value&0xf0)>>4)-(Gpwrdelta); - else - t2 = 0; - if (((value&0xf00)>>8) > Gpwrdelta) - t3 = ((value&0xf00)>>8)-(Gpwrdelta); - else - t3 = 0; - if (((value&0xf000)>>12) > Gpwrdelta) - t4 = ((value&0xf000)>>12)-(Gpwrdelta); - else - t4 = 0; - } - Gdata = t1 + (t2<<4) + (t3<<8) + (t4<<12); - - RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_20MHZ_2_4G + i*4 + 2, value); - if (bApwrdeltaMinus == FALSE) - { - t1 = (value&0xf)+(Apwrdelta); - if (t1 > 0xf) - t1 = 0xf; - t2 = ((value&0xf0)>>4)+(Apwrdelta); - if (t2 > 0xf) - t2 = 0xf; - t3 = ((value&0xf00)>>8)+(Apwrdelta); - if (t3 > 0xf) - t3 = 0xf; - t4 = ((value&0xf000)>>12)+(Apwrdelta); - if (t4 > 0xf) - t4 = 0xf; - } - else - { - if ((value&0xf) > Apwrdelta) - t1 = (value&0xf)-(Apwrdelta); - else - t1 = 0; - if (((value&0xf0)>>4) > Apwrdelta) - t2 = ((value&0xf0)>>4)-(Apwrdelta); - else - t2 = 0; - if (((value&0xf00)>>8) > Apwrdelta) - t3 = ((value&0xf00)>>8)-(Apwrdelta); - else - t3 = 0; - if (((value&0xf000)>>12) > Apwrdelta) - t4 = ((value&0xf000)>>12)-(Apwrdelta); - else - t4 = 0; - } - Adata |= ((t1<<16) + (t2<<20) + (t3<<24) + (t4<<28)); - if (bGpwrdeltaMinus == FALSE) - { - t1 = (value&0xf)+(Gpwrdelta); - if (t1 > 0xf) - t1 = 0xf; - t2 = ((value&0xf0)>>4)+(Gpwrdelta); - if (t2 > 0xf) - t2 = 0xf; - t3 = ((value&0xf00)>>8)+(Gpwrdelta); - if (t3 > 0xf) - t3 = 0xf; - t4 = ((value&0xf000)>>12)+(Gpwrdelta); - if (t4 > 0xf) - t4 = 0xf; - } - else - { - if ((value&0xf) > Gpwrdelta) - t1 = (value&0xf)-(Gpwrdelta); - else - t1 = 0; - if (((value&0xf0)>>4) > Gpwrdelta) - t2 = ((value&0xf0)>>4)-(Gpwrdelta); - else - t2 = 0; - if (((value&0xf00)>>8) > Gpwrdelta) - t3 = ((value&0xf00)>>8)-(Gpwrdelta); - else - t3 = 0; - if (((value&0xf000)>>12) > Gpwrdelta) - t4 = ((value&0xf000)>>12)-(Gpwrdelta); - else - t4 = 0; - } - Gdata |= ((t1<<16) + (t2<<20) + (t3<<24) + (t4<<28)); - data |= (value<<16); - - pAd->Tx20MPwrCfgABand[i] = pAd->Tx40MPwrCfgABand[i] = Adata; - pAd->Tx20MPwrCfgGBand[i] = pAd->Tx40MPwrCfgGBand[i] = Gdata; - - if (data != 0xffffffff) - RTMP_IO_WRITE32(pAd, TX_PWR_CFG_0 + i*4, data); - DBGPRINT_RAW(RT_DEBUG_TRACE, ("20MHz BW, 2.4G band-%lx, Adata = %lx, Gdata = %lx \n", data, Adata, Gdata)); - } - - // - // Check this block is valid for 40MHz in 2.4G. If invalid, use parameter for 20MHz in 2.4G - // - bValid = TRUE; - for (i=0; i<6; i++) - { - RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_40MHZ_2_4G + 2 + i*2, value); - if (((value & 0x00FF) == 0x00FF) || ((value & 0xFF00) == 0xFF00)) - { - bValid = FALSE; - break; - } - } - - // - // Get Txpower per MCS for 40MHz in 2.4G. - // - if (bValid) - { - for (i=0; i<4; i++) - { - RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_40MHZ_2_4G + i*4, value); - if (bGpwrdeltaMinus == FALSE) - { - t1 = (value&0xf)+(Gpwrdelta); - if (t1 > 0xf) - t1 = 0xf; - t2 = ((value&0xf0)>>4)+(Gpwrdelta); - if (t2 > 0xf) - t2 = 0xf; - t3 = ((value&0xf00)>>8)+(Gpwrdelta); - if (t3 > 0xf) - t3 = 0xf; - t4 = ((value&0xf000)>>12)+(Gpwrdelta); - if (t4 > 0xf) - t4 = 0xf; - } - else - { - if ((value&0xf) > Gpwrdelta) - t1 = (value&0xf)-(Gpwrdelta); - else - t1 = 0; - if (((value&0xf0)>>4) > Gpwrdelta) - t2 = ((value&0xf0)>>4)-(Gpwrdelta); - else - t2 = 0; - if (((value&0xf00)>>8) > Gpwrdelta) - t3 = ((value&0xf00)>>8)-(Gpwrdelta); - else - t3 = 0; - if (((value&0xf000)>>12) > Gpwrdelta) - t4 = ((value&0xf000)>>12)-(Gpwrdelta); - else - t4 = 0; - } - Gdata = t1 + (t2<<4) + (t3<<8) + (t4<<12); - - RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_40MHZ_2_4G + i*4 + 2, value); - if (bGpwrdeltaMinus == FALSE) - { - t1 = (value&0xf)+(Gpwrdelta); - if (t1 > 0xf) - t1 = 0xf; - t2 = ((value&0xf0)>>4)+(Gpwrdelta); - if (t2 > 0xf) - t2 = 0xf; - t3 = ((value&0xf00)>>8)+(Gpwrdelta); - if (t3 > 0xf) - t3 = 0xf; - t4 = ((value&0xf000)>>12)+(Gpwrdelta); - if (t4 > 0xf) - t4 = 0xf; - } - else - { - if ((value&0xf) > Gpwrdelta) - t1 = (value&0xf)-(Gpwrdelta); - else - t1 = 0; - if (((value&0xf0)>>4) > Gpwrdelta) - t2 = ((value&0xf0)>>4)-(Gpwrdelta); - else - t2 = 0; - if (((value&0xf00)>>8) > Gpwrdelta) - t3 = ((value&0xf00)>>8)-(Gpwrdelta); - else - t3 = 0; - if (((value&0xf000)>>12) > Gpwrdelta) - t4 = ((value&0xf000)>>12)-(Gpwrdelta); - else - t4 = 0; - } - Gdata |= ((t1<<16) + (t2<<20) + (t3<<24) + (t4<<28)); - - if (i == 0) - pAd->Tx40MPwrCfgGBand[i+1] = (pAd->Tx40MPwrCfgGBand[i+1] & 0x0000FFFF) | (Gdata & 0xFFFF0000); - else - pAd->Tx40MPwrCfgGBand[i+1] = Gdata; - - DBGPRINT_RAW(RT_DEBUG_TRACE, ("40MHz BW, 2.4G band, Gdata = %lx \n", Gdata)); - } - } - - // - // Check this block is valid for 20MHz in 5G. If invalid, use parameter for 20MHz in 2.4G - // - bValid = TRUE; - for (i=0; i<8; i++) - { - RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_20MHZ_5G + 2 + i*2, value); - if (((value & 0x00FF) == 0x00FF) || ((value & 0xFF00) == 0xFF00)) - { - bValid = FALSE; - break; - } - } - - // - // Get Txpower per MCS for 20MHz in 5G. - // - if (bValid) - { - for (i=0; i<5; i++) - { - RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_20MHZ_5G + i*4, value); - if (bApwrdeltaMinus == FALSE) - { - t1 = (value&0xf)+(Apwrdelta); - if (t1 > 0xf) - t1 = 0xf; - t2 = ((value&0xf0)>>4)+(Apwrdelta); - if (t2 > 0xf) - t2 = 0xf; - t3 = ((value&0xf00)>>8)+(Apwrdelta); - if (t3 > 0xf) - t3 = 0xf; - t4 = ((value&0xf000)>>12)+(Apwrdelta); - if (t4 > 0xf) - t4 = 0xf; - } - else - { - if ((value&0xf) > Apwrdelta) - t1 = (value&0xf)-(Apwrdelta); - else - t1 = 0; - if (((value&0xf0)>>4) > Apwrdelta) - t2 = ((value&0xf0)>>4)-(Apwrdelta); - else - t2 = 0; - if (((value&0xf00)>>8) > Apwrdelta) - t3 = ((value&0xf00)>>8)-(Apwrdelta); - else - t3 = 0; - if (((value&0xf000)>>12) > Apwrdelta) - t4 = ((value&0xf000)>>12)-(Apwrdelta); - else - t4 = 0; - } - Adata = t1 + (t2<<4) + (t3<<8) + (t4<<12); - - RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_20MHZ_5G + i*4 + 2, value); - if (bApwrdeltaMinus == FALSE) - { - t1 = (value&0xf)+(Apwrdelta); - if (t1 > 0xf) - t1 = 0xf; - t2 = ((value&0xf0)>>4)+(Apwrdelta); - if (t2 > 0xf) - t2 = 0xf; - t3 = ((value&0xf00)>>8)+(Apwrdelta); - if (t3 > 0xf) - t3 = 0xf; - t4 = ((value&0xf000)>>12)+(Apwrdelta); - if (t4 > 0xf) - t4 = 0xf; - } - else - { - if ((value&0xf) > Apwrdelta) - t1 = (value&0xf)-(Apwrdelta); - else - t1 = 0; - if (((value&0xf0)>>4) > Apwrdelta) - t2 = ((value&0xf0)>>4)-(Apwrdelta); - else - t2 = 0; - if (((value&0xf00)>>8) > Apwrdelta) - t3 = ((value&0xf00)>>8)-(Apwrdelta); - else - t3 = 0; - if (((value&0xf000)>>12) > Apwrdelta) - t4 = ((value&0xf000)>>12)-(Apwrdelta); - else - t4 = 0; - } - Adata |= ((t1<<16) + (t2<<20) + (t3<<24) + (t4<<28)); - - if (i == 0) - pAd->Tx20MPwrCfgABand[i] = (pAd->Tx20MPwrCfgABand[i] & 0x0000FFFF) | (Adata & 0xFFFF0000); - else - pAd->Tx20MPwrCfgABand[i] = Adata; - - DBGPRINT_RAW(RT_DEBUG_TRACE, ("20MHz BW, 5GHz band, Adata = %lx \n", Adata)); - } - } - - // - // Check this block is valid for 40MHz in 5G. If invalid, use parameter for 20MHz in 2.4G - // - bValid = TRUE; - for (i=0; i<6; i++) - { - RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_40MHZ_5G + 2 + i*2, value); - if (((value & 0x00FF) == 0x00FF) || ((value & 0xFF00) == 0xFF00)) - { - bValid = FALSE; - break; - } - } - - // - // Get Txpower per MCS for 40MHz in 5G. - // - if (bValid) - { - for (i=0; i<4; i++) - { - RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_40MHZ_5G + i*4, value); - if (bApwrdeltaMinus == FALSE) - { - t1 = (value&0xf)+(Apwrdelta); - if (t1 > 0xf) - t1 = 0xf; - t2 = ((value&0xf0)>>4)+(Apwrdelta); - if (t2 > 0xf) - t2 = 0xf; - t3 = ((value&0xf00)>>8)+(Apwrdelta); - if (t3 > 0xf) - t3 = 0xf; - t4 = ((value&0xf000)>>12)+(Apwrdelta); - if (t4 > 0xf) - t4 = 0xf; - } - else - { - if ((value&0xf) > Apwrdelta) - t1 = (value&0xf)-(Apwrdelta); - else - t1 = 0; - if (((value&0xf0)>>4) > Apwrdelta) - t2 = ((value&0xf0)>>4)-(Apwrdelta); - else - t2 = 0; - if (((value&0xf00)>>8) > Apwrdelta) - t3 = ((value&0xf00)>>8)-(Apwrdelta); - else - t3 = 0; - if (((value&0xf000)>>12) > Apwrdelta) - t4 = ((value&0xf000)>>12)-(Apwrdelta); - else - t4 = 0; - } - Adata = t1 + (t2<<4) + (t3<<8) + (t4<<12); - - RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_40MHZ_5G + i*4 + 2, value); - if (bApwrdeltaMinus == FALSE) - { - t1 = (value&0xf)+(Apwrdelta); - if (t1 > 0xf) - t1 = 0xf; - t2 = ((value&0xf0)>>4)+(Apwrdelta); - if (t2 > 0xf) - t2 = 0xf; - t3 = ((value&0xf00)>>8)+(Apwrdelta); - if (t3 > 0xf) - t3 = 0xf; - t4 = ((value&0xf000)>>12)+(Apwrdelta); - if (t4 > 0xf) - t4 = 0xf; - } - else - { - if ((value&0xf) > Apwrdelta) - t1 = (value&0xf)-(Apwrdelta); - else - t1 = 0; - if (((value&0xf0)>>4) > Apwrdelta) - t2 = ((value&0xf0)>>4)-(Apwrdelta); - else - t2 = 0; - if (((value&0xf00)>>8) > Apwrdelta) - t3 = ((value&0xf00)>>8)-(Apwrdelta); - else - t3 = 0; - if (((value&0xf000)>>12) > Apwrdelta) - t4 = ((value&0xf000)>>12)-(Apwrdelta); - else - t4 = 0; - } - Adata |= ((t1<<16) + (t2<<20) + (t3<<24) + (t4<<28)); - - if (i == 0) - pAd->Tx40MPwrCfgABand[i+1] = (pAd->Tx40MPwrCfgABand[i+1] & 0x0000FFFF) | (Adata & 0xFFFF0000); - else - pAd->Tx40MPwrCfgABand[i+1] = Adata; - - DBGPRINT_RAW(RT_DEBUG_TRACE, ("40MHz BW, 5GHz band, Adata = %lx \n", Adata)); - } - } -} - - -/* - ======================================================================== - - Routine Description: - Read initial channel power parameters from EEPROM - - Arguments: - Adapter Pointer to our adapter - - Return Value: - None - - IRQL = PASSIVE_LEVEL - - Note: - - ======================================================================== -*/ -VOID RTMPReadChannelPwr( - IN PRTMP_ADAPTER pAd) -{ - UCHAR i, choffset; - EEPROM_TX_PWR_STRUC Power; - EEPROM_TX_PWR_STRUC Power2; - - // Read Tx power value for all channels - // Value from 1 - 0x7f. Default value is 24. - // Power value : 2.4G 0x00 (0) ~ 0x1F (31) - // : 5.5G 0xF9 (-7) ~ 0x0F (15) - - // 0. 11b/g, ch1 - ch 14 - for (i = 0; i < 7; i++) - { -// Power.word = RTMP_EEPROM_READ16(pAd, EEPROM_G_TX_PWR_OFFSET + i * 2); -// Power2.word = RTMP_EEPROM_READ16(pAd, EEPROM_G_TX2_PWR_OFFSET + i * 2); - RT28xx_EEPROM_READ16(pAd, EEPROM_G_TX_PWR_OFFSET + i * 2, Power.word); - RT28xx_EEPROM_READ16(pAd, EEPROM_G_TX2_PWR_OFFSET + i * 2, Power2.word); - pAd->TxPower[i * 2].Channel = i * 2 + 1; - pAd->TxPower[i * 2 + 1].Channel = i * 2 + 2; - - if ((Power.field.Byte0 > 31) || (Power.field.Byte0 < 0)) - pAd->TxPower[i * 2].Power = DEFAULT_RF_TX_POWER; - else - pAd->TxPower[i * 2].Power = Power.field.Byte0; - - if ((Power.field.Byte1 > 31) || (Power.field.Byte1 < 0)) - pAd->TxPower[i * 2 + 1].Power = DEFAULT_RF_TX_POWER; - else - pAd->TxPower[i * 2 + 1].Power = Power.field.Byte1; - - if ((Power2.field.Byte0 > 31) || (Power2.field.Byte0 < 0)) - pAd->TxPower[i * 2].Power2 = DEFAULT_RF_TX_POWER; - else - pAd->TxPower[i * 2].Power2 = Power2.field.Byte0; - - if ((Power2.field.Byte1 > 31) || (Power2.field.Byte1 < 0)) - pAd->TxPower[i * 2 + 1].Power2 = DEFAULT_RF_TX_POWER; - else - pAd->TxPower[i * 2 + 1].Power2 = Power2.field.Byte1; - } - - // 1. U-NII lower/middle band: 36, 38, 40; 44, 46, 48; 52, 54, 56; 60, 62, 64 (including central frequency in BW 40MHz) - // 1.1 Fill up channel - choffset = 14; - for (i = 0; i < 4; i++) - { - pAd->TxPower[3 * i + choffset + 0].Channel = 36 + i * 8 + 0; - pAd->TxPower[3 * i + choffset + 0].Power = DEFAULT_RF_TX_POWER; - pAd->TxPower[3 * i + choffset + 0].Power2 = DEFAULT_RF_TX_POWER; - - pAd->TxPower[3 * i + choffset + 1].Channel = 36 + i * 8 + 2; - pAd->TxPower[3 * i + choffset + 1].Power = DEFAULT_RF_TX_POWER; - pAd->TxPower[3 * i + choffset + 1].Power2 = DEFAULT_RF_TX_POWER; - - pAd->TxPower[3 * i + choffset + 2].Channel = 36 + i * 8 + 4; - pAd->TxPower[3 * i + choffset + 2].Power = DEFAULT_RF_TX_POWER; - pAd->TxPower[3 * i + choffset + 2].Power2 = DEFAULT_RF_TX_POWER; - } - - // 1.2 Fill up power - for (i = 0; i < 6; i++) - { -// Power.word = RTMP_EEPROM_READ16(pAd, EEPROM_A_TX_PWR_OFFSET + i * 2); -// Power2.word = RTMP_EEPROM_READ16(pAd, EEPROM_A_TX2_PWR_OFFSET + i * 2); - RT28xx_EEPROM_READ16(pAd, EEPROM_A_TX_PWR_OFFSET + i * 2, Power.word); - RT28xx_EEPROM_READ16(pAd, EEPROM_A_TX2_PWR_OFFSET + i * 2, Power2.word); - - if ((Power.field.Byte0 < 16) && (Power.field.Byte0 >= -7)) - pAd->TxPower[i * 2 + choffset + 0].Power = Power.field.Byte0; - - if ((Power.field.Byte1 < 16) && (Power.field.Byte1 >= -7)) - pAd->TxPower[i * 2 + choffset + 1].Power = Power.field.Byte1; - - if ((Power2.field.Byte0 < 16) && (Power2.field.Byte0 >= -7)) - pAd->TxPower[i * 2 + choffset + 0].Power2 = Power2.field.Byte0; - - if ((Power2.field.Byte1 < 16) && (Power2.field.Byte1 >= -7)) - pAd->TxPower[i * 2 + choffset + 1].Power2 = Power2.field.Byte1; - } - - // 2. HipperLAN 2 100, 102 ,104; 108, 110, 112; 116, 118, 120; 124, 126, 128; 132, 134, 136; 140 (including central frequency in BW 40MHz) - // 2.1 Fill up channel - choffset = 14 + 12; - for (i = 0; i < 5; i++) - { - pAd->TxPower[3 * i + choffset + 0].Channel = 100 + i * 8 + 0; - pAd->TxPower[3 * i + choffset + 0].Power = DEFAULT_RF_TX_POWER; - pAd->TxPower[3 * i + choffset + 0].Power2 = DEFAULT_RF_TX_POWER; - - pAd->TxPower[3 * i + choffset + 1].Channel = 100 + i * 8 + 2; - pAd->TxPower[3 * i + choffset + 1].Power = DEFAULT_RF_TX_POWER; - pAd->TxPower[3 * i + choffset + 1].Power2 = DEFAULT_RF_TX_POWER; - - pAd->TxPower[3 * i + choffset + 2].Channel = 100 + i * 8 + 4; - pAd->TxPower[3 * i + choffset + 2].Power = DEFAULT_RF_TX_POWER; - pAd->TxPower[3 * i + choffset + 2].Power2 = DEFAULT_RF_TX_POWER; - } - pAd->TxPower[3 * 5 + choffset + 0].Channel = 140; - pAd->TxPower[3 * 5 + choffset + 0].Power = DEFAULT_RF_TX_POWER; - pAd->TxPower[3 * 5 + choffset + 0].Power2 = DEFAULT_RF_TX_POWER; - - // 2.2 Fill up power - for (i = 0; i < 8; i++) - { -// Power.word = RTMP_EEPROM_READ16(pAd, EEPROM_A_TX_PWR_OFFSET + (choffset - 14) + i * 2); -// Power2.word = RTMP_EEPROM_READ16(pAd, EEPROM_A_TX2_PWR_OFFSET + (choffset - 14) + i * 2); - RT28xx_EEPROM_READ16(pAd, EEPROM_A_TX_PWR_OFFSET + (choffset - 14) + i * 2, Power.word); - RT28xx_EEPROM_READ16(pAd, EEPROM_A_TX2_PWR_OFFSET + (choffset - 14) + i * 2, Power2.word); - - if ((Power.field.Byte0 < 16) && (Power.field.Byte0 >= -7)) - pAd->TxPower[i * 2 + choffset + 0].Power = Power.field.Byte0; - - if ((Power.field.Byte1 < 16) && (Power.field.Byte1 >= -7)) - pAd->TxPower[i * 2 + choffset + 1].Power = Power.field.Byte1; - - if ((Power2.field.Byte0 < 16) && (Power2.field.Byte0 >= -7)) - pAd->TxPower[i * 2 + choffset + 0].Power2 = Power2.field.Byte0; - - if ((Power2.field.Byte1 < 16) && (Power2.field.Byte1 >= -7)) - pAd->TxPower[i * 2 + choffset + 1].Power2 = Power2.field.Byte1; - } - - // 3. U-NII upper band: 149, 151, 153; 157, 159, 161; 165 (including central frequency in BW 40MHz) - // 3.1 Fill up channel - choffset = 14 + 12 + 16; - for (i = 0; i < 2; i++) - { - pAd->TxPower[3 * i + choffset + 0].Channel = 149 + i * 8 + 0; - pAd->TxPower[3 * i + choffset + 0].Power = DEFAULT_RF_TX_POWER; - pAd->TxPower[3 * i + choffset + 0].Power2 = DEFAULT_RF_TX_POWER; - - pAd->TxPower[3 * i + choffset + 1].Channel = 149 + i * 8 + 2; - pAd->TxPower[3 * i + choffset + 1].Power = DEFAULT_RF_TX_POWER; - pAd->TxPower[3 * i + choffset + 1].Power2 = DEFAULT_RF_TX_POWER; - - pAd->TxPower[3 * i + choffset + 2].Channel = 149 + i * 8 + 4; - pAd->TxPower[3 * i + choffset + 2].Power = DEFAULT_RF_TX_POWER; - pAd->TxPower[3 * i + choffset + 2].Power2 = DEFAULT_RF_TX_POWER; - } - pAd->TxPower[3 * 2 + choffset + 0].Channel = 165; - pAd->TxPower[3 * 2 + choffset + 0].Power = DEFAULT_RF_TX_POWER; - pAd->TxPower[3 * 2 + choffset + 0].Power2 = DEFAULT_RF_TX_POWER; - - // 3.2 Fill up power - for (i = 0; i < 4; i++) - { -// Power.word = RTMP_EEPROM_READ16(pAd, EEPROM_A_TX_PWR_OFFSET + (choffset - 14) + i * 2); -// Power2.word = RTMP_EEPROM_READ16(pAd, EEPROM_A_TX2_PWR_OFFSET + (choffset - 14) + i * 2); - RT28xx_EEPROM_READ16(pAd, EEPROM_A_TX_PWR_OFFSET + (choffset - 14) + i * 2, Power.word); - RT28xx_EEPROM_READ16(pAd, EEPROM_A_TX2_PWR_OFFSET + (choffset - 14) + i * 2, Power2.word); - - if ((Power.field.Byte0 < 16) && (Power.field.Byte0 >= -7)) - pAd->TxPower[i * 2 + choffset + 0].Power = Power.field.Byte0; - - if ((Power.field.Byte1 < 16) && (Power.field.Byte1 >= -7)) - pAd->TxPower[i * 2 + choffset + 1].Power = Power.field.Byte1; - - if ((Power2.field.Byte0 < 16) && (Power2.field.Byte0 >= -7)) - pAd->TxPower[i * 2 + choffset + 0].Power2 = Power2.field.Byte0; - - if ((Power2.field.Byte1 < 16) && (Power2.field.Byte1 >= -7)) - pAd->TxPower[i * 2 + choffset + 1].Power2 = Power2.field.Byte1; - } - - // 4. Print and Debug - choffset = 14 + 12 + 16 + 7; - -} - -/* - ======================================================================== - - Routine Description: - Read the following from the registry - 1. All the parameters - 2. NetworkAddres - - Arguments: - Adapter Pointer to our adapter - WrapperConfigurationContext For use by NdisOpenConfiguration - - Return Value: - NDIS_STATUS_SUCCESS - NDIS_STATUS_FAILURE - NDIS_STATUS_RESOURCES - - IRQL = PASSIVE_LEVEL - - Note: - - ======================================================================== -*/ -NDIS_STATUS NICReadRegParameters( - IN PRTMP_ADAPTER pAd, - IN NDIS_HANDLE WrapperConfigurationContext - ) -{ - NDIS_STATUS Status = NDIS_STATUS_SUCCESS; - DBGPRINT_S(Status, ("<-- NICReadRegParameters, Status=%x\n", Status)); - return Status; -} - - -#ifdef RT2870 -/* - ======================================================================== - - Routine Description: - For RF filter calibration purpose - - Arguments: - pAd Pointer to our adapter - - Return Value: - None - - IRQL = PASSIVE_LEVEL - - ======================================================================== -*/ -VOID RTUSBFilterCalibration( - IN PRTMP_ADAPTER pAd) -{ - UCHAR R55x = 0, value, FilterTarget = 0x1E, BBPValue; - UINT loop = 0, count = 0, loopcnt = 0, ReTry = 0; - UCHAR RF_R24_Value = 0; - - // Give bbp filter initial value - pAd->Mlme.CaliBW20RfR24 = 0x16; - pAd->Mlme.CaliBW40RfR24 = 0x36; //Bit[5] must be 1 for BW 40 - - do - { - if (loop == 1) //BandWidth = 40 MHz - { - // Write 0x27 to RF_R24 to program filter - RF_R24_Value = 0x27; - RT30xxWriteRFRegister(pAd, RF_R24, RF_R24_Value); - FilterTarget = 0x19; - - // when calibrate BW40, BBP mask must set to BW40. - RTUSBReadBBPRegister(pAd, BBP_R4, &BBPValue); - BBPValue&= (~0x18); - BBPValue|= (0x10); - RTUSBWriteBBPRegister(pAd, BBP_R4, BBPValue); - } - else //BandWidth = 20 MHz - { - // Write 0x07 to RF_R24 to program filter - RF_R24_Value = 0x07; - RT30xxWriteRFRegister(pAd, RF_R24, RF_R24_Value); - FilterTarget = 0x16; - } - - // Write 0x01 to RF_R22 to enable baseband loopback mode - RT30xxReadRFRegister(pAd, RF_R22, &value); - value |= 0x01; - RT30xxWriteRFRegister(pAd, RF_R22, value); - - // Write 0x00 to BBP_R24 to set power & frequency of passband test tone - RTUSBWriteBBPRegister(pAd, BBP_R24, 0); - - do - { - // Write 0x90 to BBP_R25 to transmit test tone - RTUSBWriteBBPRegister(pAd, BBP_R25, 0x90); - - RTMPusecDelay(1000); - // Read BBP_R55[6:0] for received power, set R55x = BBP_R55[6:0] - RTUSBReadBBPRegister(pAd, BBP_R55, &value); - R55x = value & 0xFF; - - } while ((ReTry++ < 100) && (R55x == 0)); - - // Write 0x06 to BBP_R24 to set power & frequency of stopband test tone - RTUSBWriteBBPRegister(pAd, BBP_R24, 0x06); - - while(TRUE) - { - // Write 0x90 to BBP_R25 to transmit test tone - RTUSBWriteBBPRegister(pAd, BBP_R25, 0x90); - - //We need to wait for calibration - RTMPusecDelay(1000); - RTUSBReadBBPRegister(pAd, BBP_R55, &value); - value &= 0xFF; - if ((R55x - value) < FilterTarget) - { - RF_R24_Value ++; - } - else if ((R55x - value) == FilterTarget) - { - RF_R24_Value ++; - count ++; - } - else - { - break; - } - - // prevent infinite loop cause driver hang. - if (loopcnt++ > 100) - { - DBGPRINT(RT_DEBUG_ERROR, ("RTUSBFilterCalibration - can't find a valid value, loopcnt=%d stop calibrating", loopcnt)); - break; - } - - // Write RF_R24 to program filter - RT30xxWriteRFRegister(pAd, RF_R24, RF_R24_Value); - } - - if (count > 0) - { - RF_R24_Value = RF_R24_Value - ((count) ? (1) : (0)); - } - - // Store for future usage - if (loopcnt < 100) - { - if (loop++ == 0) - { - //BandWidth = 20 MHz - pAd->Mlme.CaliBW20RfR24 = (UCHAR)RF_R24_Value; - } - else - { - //BandWidth = 40 MHz - pAd->Mlme.CaliBW40RfR24 = (UCHAR)RF_R24_Value; - break; - } - } - else - break; - - RT30xxWriteRFRegister(pAd, RF_R24, RF_R24_Value); - - // reset count - count = 0; - } while(TRUE); - - // - // Set back to initial state - // - RTUSBWriteBBPRegister(pAd, BBP_R24, 0); - - RT30xxReadRFRegister(pAd, RF_R22, &value); - value &= ~(0x01); - RT30xxWriteRFRegister(pAd, RF_R22, value); - - // set BBP back to BW20 - RTUSBReadBBPRegister(pAd, BBP_R4, &BBPValue); - BBPValue&= (~0x18); - RTUSBWriteBBPRegister(pAd, BBP_R4, BBPValue); - - DBGPRINT(RT_DEBUG_TRACE, ("RTUSBFilterCalibration - CaliBW20RfR24=0x%x, CaliBW40RfR24=0x%x\n", pAd->Mlme.CaliBW20RfR24, pAd->Mlme.CaliBW40RfR24)); -} - - -VOID NICInitRT30xxRFRegisters(IN PRTMP_ADAPTER pAd) -{ - INT i; - // Driver must read EEPROM to get RfIcType before initial RF registers - // Initialize RF register to default value - if (IS_RT3070(pAd) && ((pAd->RfIcType == RFIC_3020) ||(pAd->RfIcType == RFIC_2020))) - { - // Init RF calibration - // Driver should toggle RF R30 bit7 before init RF registers - ULONG RfReg = 0; - RT30xxReadRFRegister(pAd, RF_R30, (PUCHAR)&RfReg); - RfReg |= 0x80; - RT30xxWriteRFRegister(pAd, RF_R30, (UCHAR)RfReg); - RTMPusecDelay(1000); - RfReg &= 0x7F; - RT30xxWriteRFRegister(pAd, RF_R30, (UCHAR)RfReg); - - // Initialize RF register to default value - for (i = 0; i < NUM_RF_REG_PARMS; i++) - { - RT30xxWriteRFRegister(pAd, RT30xx_RFRegTable[i].Register, RT30xx_RFRegTable[i].Value); - } - - //For RF filter Calibration - RTUSBFilterCalibration(pAd); - } - -} -#endif // RT2870 // - - -/* - ======================================================================== - - Routine Description: - Read initial parameters from EEPROM - - Arguments: - Adapter Pointer to our adapter - - Return Value: - None - - IRQL = PASSIVE_LEVEL - - Note: - - ======================================================================== -*/ -VOID NICReadEEPROMParameters( - IN PRTMP_ADAPTER pAd, - IN PUCHAR mac_addr) -{ - UINT32 data = 0; - USHORT i, value, value2; - UCHAR TmpPhy; - EEPROM_TX_PWR_STRUC Power; - EEPROM_VERSION_STRUC Version; - EEPROM_ANTENNA_STRUC Antenna; - EEPROM_NIC_CONFIG2_STRUC NicConfig2; - - DBGPRINT(RT_DEBUG_TRACE, ("--> NICReadEEPROMParameters\n")); - - // Init EEPROM Address Number, before access EEPROM; if 93c46, EEPROMAddressNum=6, else if 93c66, EEPROMAddressNum=8 - RTMP_IO_READ32(pAd, E2PROM_CSR, &data); - DBGPRINT(RT_DEBUG_TRACE, ("--> E2PROM_CSR = 0x%x\n", data)); - - if((data & 0x30) == 0) - pAd->EEPROMAddressNum = 6; // 93C46 - else if((data & 0x30) == 0x10) - pAd->EEPROMAddressNum = 8; // 93C66 - else - pAd->EEPROMAddressNum = 8; // 93C86 - DBGPRINT(RT_DEBUG_TRACE, ("--> EEPROMAddressNum = %d\n", pAd->EEPROMAddressNum )); - - // RT2860 MAC no longer auto load MAC address from E2PROM. Driver has to intialize - // MAC address registers according to E2PROM setting - if (mac_addr == NULL || - strlen(mac_addr) != 17 || - mac_addr[2] != ':' || mac_addr[5] != ':' || mac_addr[8] != ':' || - mac_addr[11] != ':' || mac_addr[14] != ':') - { - USHORT Addr01,Addr23,Addr45 ; - - RT28xx_EEPROM_READ16(pAd, 0x04, Addr01); - RT28xx_EEPROM_READ16(pAd, 0x06, Addr23); - RT28xx_EEPROM_READ16(pAd, 0x08, Addr45); - - pAd->PermanentAddress[0] = (UCHAR)(Addr01 & 0xff); - pAd->PermanentAddress[1] = (UCHAR)(Addr01 >> 8); - pAd->PermanentAddress[2] = (UCHAR)(Addr23 & 0xff); - pAd->PermanentAddress[3] = (UCHAR)(Addr23 >> 8); - pAd->PermanentAddress[4] = (UCHAR)(Addr45 & 0xff); - pAd->PermanentAddress[5] = (UCHAR)(Addr45 >> 8); - - DBGPRINT(RT_DEBUG_TRACE, ("Initialize MAC Address from E2PROM \n")); - } - else - { - INT j; - PUCHAR macptr; - - macptr = mac_addr; - - for (j=0; jPermanentAddress[j], 1); - macptr=macptr+3; - } - - DBGPRINT(RT_DEBUG_TRACE, ("Initialize MAC Address from module parameter \n")); - } - - - { -#if 0 - USHORT Addr01,Addr23,Addr45 ; - - Addr01=RTMP_EEPROM_READ16(pAd, 0x04); - Addr23=RTMP_EEPROM_READ16(pAd, 0x06); - Addr45=RTMP_EEPROM_READ16(pAd, 0x08); - - pAd->PermanentAddress[0] = (UCHAR)(Addr01 & 0xff); - pAd->PermanentAddress[1] = (UCHAR)(Addr01 >> 8); - pAd->PermanentAddress[2] = (UCHAR)(Addr23 & 0xff); - pAd->PermanentAddress[3] = (UCHAR)(Addr23 >> 8); - pAd->PermanentAddress[4] = (UCHAR)(Addr45 & 0xff); - pAd->PermanentAddress[5] = (UCHAR)(Addr45 >> 8); -#endif - //more conveninet to test mbssid, so ap's bssid &0xf1 - if (pAd->PermanentAddress[0] == 0xff) - pAd->PermanentAddress[0] = RandomByte(pAd)&0xf8; - - //if (pAd->PermanentAddress[5] == 0xff) - // pAd->PermanentAddress[5] = RandomByte(pAd)&0xf8; - - DBGPRINT_RAW(RT_DEBUG_TRACE,("E2PROM MAC: =%02x:%02x:%02x:%02x:%02x:%02x\n", - pAd->PermanentAddress[0], pAd->PermanentAddress[1], - pAd->PermanentAddress[2], pAd->PermanentAddress[3], - pAd->PermanentAddress[4], pAd->PermanentAddress[5])); - if (pAd->bLocalAdminMAC == FALSE) - { - MAC_DW0_STRUC csr2; - MAC_DW1_STRUC csr3; - COPY_MAC_ADDR(pAd->CurrentAddress, pAd->PermanentAddress); - csr2.field.Byte0 = pAd->CurrentAddress[0]; - csr2.field.Byte1 = pAd->CurrentAddress[1]; - csr2.field.Byte2 = pAd->CurrentAddress[2]; - csr2.field.Byte3 = pAd->CurrentAddress[3]; - RTMP_IO_WRITE32(pAd, MAC_ADDR_DW0, csr2.word); - csr3.word = 0; - csr3.field.Byte4 = pAd->CurrentAddress[4]; - csr3.field.Byte5 = pAd->CurrentAddress[5]; - csr3.field.U2MeMask = 0xff; - RTMP_IO_WRITE32(pAd, MAC_ADDR_DW1, csr3.word); - DBGPRINT_RAW(RT_DEBUG_TRACE,("E2PROM MAC: =%02x:%02x:%02x:%02x:%02x:%02x\n", - pAd->PermanentAddress[0], pAd->PermanentAddress[1], - pAd->PermanentAddress[2], pAd->PermanentAddress[3], - pAd->PermanentAddress[4], pAd->PermanentAddress[5])); - } - } - - // if not return early. cause fail at emulation. - // Init the channel number for TX channel power - RTMPReadChannelPwr(pAd); - - // if E2PROM version mismatch with driver's expectation, then skip - // all subsequent E2RPOM retieval and set a system error bit to notify GUI - RT28xx_EEPROM_READ16(pAd, EEPROM_VERSION_OFFSET, Version.word); - pAd->EepromVersion = Version.field.Version + Version.field.FaeReleaseNumber * 256; - DBGPRINT(RT_DEBUG_TRACE, ("E2PROM: Version = %d, FAE release #%d\n", Version.field.Version, Version.field.FaeReleaseNumber)); - - if (Version.field.Version > VALID_EEPROM_VERSION) - { - DBGPRINT_ERR(("E2PROM: WRONG VERSION 0x%x, should be %d\n",Version.field.Version, VALID_EEPROM_VERSION)); - /*pAd->SystemErrorBitmap |= 0x00000001; - - // hard-code default value when no proper E2PROM installed - pAd->bAutoTxAgcA = FALSE; - pAd->bAutoTxAgcG = FALSE; - - // Default the channel power - for (i = 0; i < MAX_NUM_OF_CHANNELS; i++) - pAd->TxPower[i].Power = DEFAULT_RF_TX_POWER; - - // Default the channel power - for (i = 0; i < MAX_NUM_OF_11JCHANNELS; i++) - pAd->TxPower11J[i].Power = DEFAULT_RF_TX_POWER; - - for(i = 0; i < NUM_EEPROM_BBP_PARMS; i++) - pAd->EEPROMDefaultValue[i] = 0xffff; - return; */ - } - - // Read BBP default value from EEPROM and store to array(EEPROMDefaultValue) in pAd - RT28xx_EEPROM_READ16(pAd, EEPROM_NIC1_OFFSET, value); - pAd->EEPROMDefaultValue[0] = value; - - RT28xx_EEPROM_READ16(pAd, EEPROM_NIC2_OFFSET, value); - pAd->EEPROMDefaultValue[1] = value; - - RT28xx_EEPROM_READ16(pAd, 0x38, value); // Country Region - pAd->EEPROMDefaultValue[2] = value; - - for(i = 0; i < 8; i++) - { - RT28xx_EEPROM_READ16(pAd, EEPROM_BBP_BASE_OFFSET + i*2, value); - pAd->EEPROMDefaultValue[i+3] = value; - } - - // We have to parse NIC configuration 0 at here. - // If TSSI did not have preloaded value, it should reset the TxAutoAgc to false - // Therefore, we have to read TxAutoAgc control beforehand. - // Read Tx AGC control bit - Antenna.word = pAd->EEPROMDefaultValue[0]; - if (Antenna.word == 0xFFFF) - { - Antenna.word = 0; - Antenna.field.RfIcType = RFIC_2820; - Antenna.field.TxPath = 1; - Antenna.field.RxPath = 2; - DBGPRINT(RT_DEBUG_WARN, ("E2PROM error, hard code as 0x%04x\n", Antenna.word)); - } - - // Choose the desired Tx&Rx stream. - if ((pAd->CommonCfg.TxStream == 0) || (pAd->CommonCfg.TxStream > Antenna.field.TxPath)) - pAd->CommonCfg.TxStream = Antenna.field.TxPath; - - if ((pAd->CommonCfg.RxStream == 0) || (pAd->CommonCfg.RxStream > Antenna.field.RxPath)) - { - pAd->CommonCfg.RxStream = Antenna.field.RxPath; - - if ((pAd->MACVersion < RALINK_2883_VERSION) && - (pAd->CommonCfg.RxStream > 2)) - { - // only 2 Rx streams for RT2860 series - pAd->CommonCfg.RxStream = 2; - } - } - - // 3*3 - // read value from EEPROM and set them to CSR174 ~ 177 in chain0 ~ chain2 - // yet implement - for(i=0; i<3; i++) - { - } - - NicConfig2.word = pAd->EEPROMDefaultValue[1]; - - - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - NicConfig2.word = 0; - if ((NicConfig2.word & 0x00ff) == 0xff) - { - NicConfig2.word &= 0xff00; - } - - if ((NicConfig2.word >> 8) == 0xff) - { - NicConfig2.word &= 0x00ff; - } - } -#endif // CONFIG_STA_SUPPORT // - - if (NicConfig2.field.DynamicTxAgcControl == 1) - pAd->bAutoTxAgcA = pAd->bAutoTxAgcG = TRUE; - else - pAd->bAutoTxAgcA = pAd->bAutoTxAgcG = FALSE; - - DBGPRINT_RAW(RT_DEBUG_TRACE, ("NICReadEEPROMParameters: RxPath = %d, TxPath = %d\n", Antenna.field.RxPath, Antenna.field.TxPath)); - - // Save the antenna for future use - pAd->Antenna.word = Antenna.word; - - // - // Reset PhyMode if we don't support 802.11a - // Only RFIC_2850 & RFIC_2750 support 802.11a - // - if ((Antenna.field.RfIcType != RFIC_2850) && (Antenna.field.RfIcType != RFIC_2750)) - { - if ((pAd->CommonCfg.PhyMode == PHY_11ABG_MIXED) || - (pAd->CommonCfg.PhyMode == PHY_11A)) - pAd->CommonCfg.PhyMode = PHY_11BG_MIXED; -#ifdef DOT11_N_SUPPORT - else if ((pAd->CommonCfg.PhyMode == PHY_11ABGN_MIXED) || - (pAd->CommonCfg.PhyMode == PHY_11AN_MIXED) || - (pAd->CommonCfg.PhyMode == PHY_11AGN_MIXED) || - (pAd->CommonCfg.PhyMode == PHY_11N_5G)) - pAd->CommonCfg.PhyMode = PHY_11BGN_MIXED; -#endif // DOT11_N_SUPPORT // - } - - // Read TSSI reference and TSSI boundary for temperature compensation. This is ugly - // 0. 11b/g - { - /* these are tempature reference value (0x00 ~ 0xFE) - ex: 0x00 0x15 0x25 0x45 0x88 0xA0 0xB5 0xD0 0xF0 - TssiPlusBoundaryG [4] [3] [2] [1] [0] (smaller) + - TssiMinusBoundaryG[0] [1] [2] [3] [4] (larger) */ - RT28xx_EEPROM_READ16(pAd, 0x6E, Power.word); - pAd->TssiMinusBoundaryG[4] = Power.field.Byte0; - pAd->TssiMinusBoundaryG[3] = Power.field.Byte1; - RT28xx_EEPROM_READ16(pAd, 0x70, Power.word); - pAd->TssiMinusBoundaryG[2] = Power.field.Byte0; - pAd->TssiMinusBoundaryG[1] = Power.field.Byte1; - RT28xx_EEPROM_READ16(pAd, 0x72, Power.word); - pAd->TssiRefG = Power.field.Byte0; /* reference value [0] */ - pAd->TssiPlusBoundaryG[1] = Power.field.Byte1; - RT28xx_EEPROM_READ16(pAd, 0x74, Power.word); - pAd->TssiPlusBoundaryG[2] = Power.field.Byte0; - pAd->TssiPlusBoundaryG[3] = Power.field.Byte1; - RT28xx_EEPROM_READ16(pAd, 0x76, Power.word); - pAd->TssiPlusBoundaryG[4] = Power.field.Byte0; - pAd->TxAgcStepG = Power.field.Byte1; - pAd->TxAgcCompensateG = 0; - pAd->TssiMinusBoundaryG[0] = pAd->TssiRefG; - pAd->TssiPlusBoundaryG[0] = pAd->TssiRefG; - - // Disable TxAgc if the based value is not right - if (pAd->TssiRefG == 0xff) - pAd->bAutoTxAgcG = FALSE; - - DBGPRINT(RT_DEBUG_TRACE,("E2PROM: G Tssi[-4 .. +4] = %d %d %d %d - %d -%d %d %d %d, step=%d, tuning=%d\n", - pAd->TssiMinusBoundaryG[4], pAd->TssiMinusBoundaryG[3], pAd->TssiMinusBoundaryG[2], pAd->TssiMinusBoundaryG[1], - pAd->TssiRefG, - pAd->TssiPlusBoundaryG[1], pAd->TssiPlusBoundaryG[2], pAd->TssiPlusBoundaryG[3], pAd->TssiPlusBoundaryG[4], - pAd->TxAgcStepG, pAd->bAutoTxAgcG)); - } - // 1. 11a - { - RT28xx_EEPROM_READ16(pAd, 0xD4, Power.word); - pAd->TssiMinusBoundaryA[4] = Power.field.Byte0; - pAd->TssiMinusBoundaryA[3] = Power.field.Byte1; - RT28xx_EEPROM_READ16(pAd, 0xD6, Power.word); - pAd->TssiMinusBoundaryA[2] = Power.field.Byte0; - pAd->TssiMinusBoundaryA[1] = Power.field.Byte1; - RT28xx_EEPROM_READ16(pAd, 0xD8, Power.word); - pAd->TssiRefA = Power.field.Byte0; - pAd->TssiPlusBoundaryA[1] = Power.field.Byte1; - RT28xx_EEPROM_READ16(pAd, 0xDA, Power.word); - pAd->TssiPlusBoundaryA[2] = Power.field.Byte0; - pAd->TssiPlusBoundaryA[3] = Power.field.Byte1; - RT28xx_EEPROM_READ16(pAd, 0xDC, Power.word); - pAd->TssiPlusBoundaryA[4] = Power.field.Byte0; - pAd->TxAgcStepA = Power.field.Byte1; - pAd->TxAgcCompensateA = 0; - pAd->TssiMinusBoundaryA[0] = pAd->TssiRefA; - pAd->TssiPlusBoundaryA[0] = pAd->TssiRefA; - - // Disable TxAgc if the based value is not right - if (pAd->TssiRefA == 0xff) - pAd->bAutoTxAgcA = FALSE; - - DBGPRINT(RT_DEBUG_TRACE,("E2PROM: A Tssi[-4 .. +4] = %d %d %d %d - %d -%d %d %d %d, step=%d, tuning=%d\n", - pAd->TssiMinusBoundaryA[4], pAd->TssiMinusBoundaryA[3], pAd->TssiMinusBoundaryA[2], pAd->TssiMinusBoundaryA[1], - pAd->TssiRefA, - pAd->TssiPlusBoundaryA[1], pAd->TssiPlusBoundaryA[2], pAd->TssiPlusBoundaryA[3], pAd->TssiPlusBoundaryA[4], - pAd->TxAgcStepA, pAd->bAutoTxAgcA)); - } - pAd->BbpRssiToDbmDelta = 0x0; - - // Read frequency offset setting for RF - RT28xx_EEPROM_READ16(pAd, EEPROM_FREQ_OFFSET, value); - if ((value & 0x00FF) != 0x00FF) - pAd->RfFreqOffset = (ULONG) (value & 0x00FF); - else - pAd->RfFreqOffset = 0; - DBGPRINT(RT_DEBUG_TRACE, ("E2PROM: RF FreqOffset=0x%lx \n", pAd->RfFreqOffset)); - - //CountryRegion byte offset (38h) - value = pAd->EEPROMDefaultValue[2] >> 8; // 2.4G band - value2 = pAd->EEPROMDefaultValue[2] & 0x00FF; // 5G band - - if ((value <= REGION_MAXIMUM_BG_BAND) && (value2 <= REGION_MAXIMUM_A_BAND)) - { - pAd->CommonCfg.CountryRegion = ((UCHAR) value) | 0x80; - pAd->CommonCfg.CountryRegionForABand = ((UCHAR) value2) | 0x80; - TmpPhy = pAd->CommonCfg.PhyMode; - pAd->CommonCfg.PhyMode = 0xff; - RTMPSetPhyMode(pAd, TmpPhy); -#ifdef DOT11_N_SUPPORT - SetCommonHT(pAd); -#endif // DOT11_N_SUPPORT // - } - - // - // Get RSSI Offset on EEPROM 0x9Ah & 0x9Ch. - // The valid value are (-10 ~ 10) - // - RT28xx_EEPROM_READ16(pAd, EEPROM_RSSI_BG_OFFSET, value); - pAd->BGRssiOffset0 = value & 0x00ff; - pAd->BGRssiOffset1 = (value >> 8); - RT28xx_EEPROM_READ16(pAd, EEPROM_RSSI_BG_OFFSET+2, value); - pAd->BGRssiOffset2 = value & 0x00ff; - pAd->ALNAGain1 = (value >> 8); - RT28xx_EEPROM_READ16(pAd, EEPROM_LNA_OFFSET, value); - pAd->BLNAGain = value & 0x00ff; - pAd->ALNAGain0 = (value >> 8); - - // Validate 11b/g RSSI_0 offset. - if ((pAd->BGRssiOffset0 < -10) || (pAd->BGRssiOffset0 > 10)) - pAd->BGRssiOffset0 = 0; - - // Validate 11b/g RSSI_1 offset. - if ((pAd->BGRssiOffset1 < -10) || (pAd->BGRssiOffset1 > 10)) - pAd->BGRssiOffset1 = 0; - - // Validate 11b/g RSSI_2 offset. - if ((pAd->BGRssiOffset2 < -10) || (pAd->BGRssiOffset2 > 10)) - pAd->BGRssiOffset2 = 0; - - RT28xx_EEPROM_READ16(pAd, EEPROM_RSSI_A_OFFSET, value); - pAd->ARssiOffset0 = value & 0x00ff; - pAd->ARssiOffset1 = (value >> 8); - RT28xx_EEPROM_READ16(pAd, (EEPROM_RSSI_A_OFFSET+2), value); - pAd->ARssiOffset2 = value & 0x00ff; - pAd->ALNAGain2 = (value >> 8); - - if (((UCHAR)pAd->ALNAGain1 == 0xFF) || (pAd->ALNAGain1 == 0x00)) - pAd->ALNAGain1 = pAd->ALNAGain0; - if (((UCHAR)pAd->ALNAGain2 == 0xFF) || (pAd->ALNAGain2 == 0x00)) - pAd->ALNAGain2 = pAd->ALNAGain0; - - // Validate 11a RSSI_0 offset. - if ((pAd->ARssiOffset0 < -10) || (pAd->ARssiOffset0 > 10)) - pAd->ARssiOffset0 = 0; - - // Validate 11a RSSI_1 offset. - if ((pAd->ARssiOffset1 < -10) || (pAd->ARssiOffset1 > 10)) - pAd->ARssiOffset1 = 0; - - //Validate 11a RSSI_2 offset. - if ((pAd->ARssiOffset2 < -10) || (pAd->ARssiOffset2 > 10)) - pAd->ARssiOffset2 = 0; - - // - // Get LED Setting. - // - RT28xx_EEPROM_READ16(pAd, 0x3a, value); - pAd->LedCntl.word = (value&0xff00) >> 8; - RT28xx_EEPROM_READ16(pAd, EEPROM_LED1_OFFSET, value); - pAd->Led1 = value; - RT28xx_EEPROM_READ16(pAd, EEPROM_LED2_OFFSET, value); - pAd->Led2 = value; - RT28xx_EEPROM_READ16(pAd, EEPROM_LED3_OFFSET, value); - pAd->Led3 = value; - - RTMPReadTxPwrPerRate(pAd); - -#ifdef SINGLE_SKU - //pAd->CommonCfg.DefineMaxTxPwr = RTMP_EEPROM_READ16(pAd, EEPROM_DEFINE_MAX_TXPWR); - RT28xx_EEPROM_READ16(pAd, EEPROM_DEFINE_MAX_TXPWR, pAd->CommonCfg.DefineMaxTxPwr); -#endif // SINGLE_SKU // - - DBGPRINT(RT_DEBUG_TRACE, ("<-- NICReadEEPROMParameters\n")); -} - -/* - ======================================================================== - - Routine Description: - Set default value from EEPROM - - Arguments: - Adapter Pointer to our adapter - - Return Value: - None - - IRQL = PASSIVE_LEVEL - - Note: - - ======================================================================== -*/ -VOID NICInitAsicFromEEPROM( - IN PRTMP_ADAPTER pAd) -{ -#ifdef CONFIG_STA_SUPPORT - UINT32 data = 0; - UCHAR BBPR1 = 0; -#endif // CONFIG_STA_SUPPORT // - USHORT i; - EEPROM_ANTENNA_STRUC Antenna; - EEPROM_NIC_CONFIG2_STRUC NicConfig2; - UCHAR BBPR3 = 0; - - DBGPRINT(RT_DEBUG_TRACE, ("--> NICInitAsicFromEEPROM\n")); - for(i = 3; i < NUM_EEPROM_BBP_PARMS; i++) - { - UCHAR BbpRegIdx, BbpValue; - - if ((pAd->EEPROMDefaultValue[i] != 0xFFFF) && (pAd->EEPROMDefaultValue[i] != 0)) - { - BbpRegIdx = (UCHAR)(pAd->EEPROMDefaultValue[i] >> 8); - BbpValue = (UCHAR)(pAd->EEPROMDefaultValue[i] & 0xff); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BbpRegIdx, BbpValue); - } - } - - Antenna.word = pAd->Antenna.word; - pAd->Mlme.RealRxPath = (UCHAR) Antenna.field.RxPath; - pAd->RfIcType = (UCHAR) Antenna.field.RfIcType; - - NicConfig2.word = pAd->EEPROMDefaultValue[1]; - - - // Save the antenna for future use - pAd->NicConfig2.word = NicConfig2.word; - - // - // Send LED Setting to MCU. - // - if (pAd->LedCntl.word == 0xFF) - { - pAd->LedCntl.word = 0x01; - pAd->Led1 = 0x5555; - pAd->Led2 = 0x2221; - -#ifdef RT2870 - pAd->Led3 = 0x5627; -#endif // RT2870 // - } - - AsicSendCommandToMcu(pAd, 0x52, 0xff, (UCHAR)pAd->Led1, (UCHAR)(pAd->Led1 >> 8)); - AsicSendCommandToMcu(pAd, 0x53, 0xff, (UCHAR)pAd->Led2, (UCHAR)(pAd->Led2 >> 8)); - AsicSendCommandToMcu(pAd, 0x54, 0xff, (UCHAR)pAd->Led3, (UCHAR)(pAd->Led3 >> 8)); - pAd->LedIndicatorStregth = 0xFF; - RTMPSetSignalLED(pAd, -100); // Force signal strength Led to be turned off, before link up - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - // Read Hardware controlled Radio state enable bit - if (NicConfig2.field.HardwareRadioControl == 1) - { - pAd->StaCfg.bHardwareRadio = TRUE; - - // Read GPIO pin2 as Hardware controlled radio state - RTMP_IO_READ32(pAd, GPIO_CTRL_CFG, &data); - if ((data & 0x04) == 0) - { - pAd->StaCfg.bHwRadio = FALSE; - pAd->StaCfg.bRadio = FALSE; -// RTMP_IO_WRITE32(pAd, PWR_PIN_CFG, 0x00001818); - RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF); - } - } - else - pAd->StaCfg.bHardwareRadio = FALSE; - - if (pAd->StaCfg.bRadio == FALSE) - { - RTMPSetLED(pAd, LED_RADIO_OFF); - } - else - { - RTMPSetLED(pAd, LED_RADIO_ON); - } - } -#endif // CONFIG_STA_SUPPORT // - - // Turn off patching for cardbus controller - if (NicConfig2.field.CardbusAcceleration == 1) - { -// pAd->bTest1 = TRUE; - } - - if (NicConfig2.field.DynamicTxAgcControl == 1) - pAd->bAutoTxAgcA = pAd->bAutoTxAgcG = TRUE; - else - pAd->bAutoTxAgcA = pAd->bAutoTxAgcG = FALSE; - // - // Since BBP has been progamed, to make sure BBP setting will be - // upate inside of AsicAntennaSelect, so reset to UNKNOWN_BAND!! - // - pAd->CommonCfg.BandState = UNKNOWN_BAND; - - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BBPR3); - BBPR3 &= (~0x18); - if(pAd->Antenna.field.RxPath == 3) - { - BBPR3 |= (0x10); - } - else if(pAd->Antenna.field.RxPath == 2) - { - BBPR3 |= (0x8); - } - else if(pAd->Antenna.field.RxPath == 1) - { - BBPR3 |= (0x0); - } - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BBPR3); - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - // Handle the difference when 1T - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R1, &BBPR1); - if(pAd->Antenna.field.TxPath == 1) - { - BBPR1 &= (~0x18); - } - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R1, BBPR1); - - DBGPRINT(RT_DEBUG_TRACE, ("Use Hw Radio Control Pin=%d; if used Pin=%d;\n", pAd->CommonCfg.bHardwareRadio, pAd->CommonCfg.bHardwareRadio)); - } -#endif // CONFIG_STA_SUPPORT // - DBGPRINT(RT_DEBUG_TRACE, ("TxPath = %d, RxPath = %d, RFIC=%d, Polar+LED mode=%x\n", pAd->Antenna.field.TxPath, pAd->Antenna.field.RxPath, pAd->RfIcType, pAd->LedCntl.word)); - DBGPRINT(RT_DEBUG_TRACE, ("<-- NICInitAsicFromEEPROM\n")); -} - -/* - ======================================================================== - - Routine Description: - Initialize NIC hardware - - Arguments: - Adapter Pointer to our adapter - - Return Value: - None - - IRQL = PASSIVE_LEVEL - - Note: - - ======================================================================== -*/ -NDIS_STATUS NICInitializeAdapter( - IN PRTMP_ADAPTER pAd, - IN BOOLEAN bHardReset) -{ - NDIS_STATUS Status = NDIS_STATUS_SUCCESS; - WPDMA_GLO_CFG_STRUC GloCfg; -// INT_MASK_CSR_STRUC IntMask; - ULONG i =0, j=0; - AC_TXOP_CSR0_STRUC csr0; - - DBGPRINT(RT_DEBUG_TRACE, ("--> NICInitializeAdapter\n")); - - // 3. Set DMA global configuration except TX_DMA_EN and RX_DMA_EN bits: -retry: - i = 0; - do - { - RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word); - if ((GloCfg.field.TxDMABusy == 0) && (GloCfg.field.RxDMABusy == 0)) - break; - - RTMPusecDelay(1000); - i++; - }while ( i<100); - DBGPRINT(RT_DEBUG_TRACE, ("<== DMA offset 0x208 = 0x%x\n", GloCfg.word)); - GloCfg.word &= 0xff0; - GloCfg.field.EnTXWriteBackDDONE =1; - RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, GloCfg.word); - - // Record HW Beacon offset - pAd->BeaconOffset[0] = HW_BEACON_BASE0; - pAd->BeaconOffset[1] = HW_BEACON_BASE1; - pAd->BeaconOffset[2] = HW_BEACON_BASE2; - pAd->BeaconOffset[3] = HW_BEACON_BASE3; - pAd->BeaconOffset[4] = HW_BEACON_BASE4; - pAd->BeaconOffset[5] = HW_BEACON_BASE5; - pAd->BeaconOffset[6] = HW_BEACON_BASE6; - pAd->BeaconOffset[7] = HW_BEACON_BASE7; - - // - // write all shared Ring's base address into ASIC - // - - // asic simulation sequence put this ahead before loading firmware. - // pbf hardware reset - - // Initialze ASIC for TX & Rx operation - if (NICInitializeAsic(pAd , bHardReset) != NDIS_STATUS_SUCCESS) - { - if (j++ == 0) - { - NICLoadFirmware(pAd); - goto retry; - } - return NDIS_STATUS_FAILURE; - } - - - - - // WMM parameter - csr0.word = 0; - RTMP_IO_WRITE32(pAd, WMM_TXOP0_CFG, csr0.word); - if (pAd->CommonCfg.PhyMode == PHY_11B) - { - csr0.field.Ac0Txop = 192; // AC_VI: 192*32us ~= 6ms - csr0.field.Ac1Txop = 96; // AC_VO: 96*32us ~= 3ms - } - else - { - csr0.field.Ac0Txop = 96; // AC_VI: 96*32us ~= 3ms - csr0.field.Ac1Txop = 48; // AC_VO: 48*32us ~= 1.5ms - } - RTMP_IO_WRITE32(pAd, WMM_TXOP1_CFG, csr0.word); - - - - - // reset action - // Load firmware - // Status = NICLoadFirmware(pAd); - - DBGPRINT(RT_DEBUG_TRACE, ("<-- NICInitializeAdapter\n")); - return Status; -} - -/* - ======================================================================== - - Routine Description: - Initialize ASIC - - Arguments: - Adapter Pointer to our adapter - - Return Value: - None - - IRQL = PASSIVE_LEVEL - - Note: - - ======================================================================== -*/ -NDIS_STATUS NICInitializeAsic( - IN PRTMP_ADAPTER pAd, - IN BOOLEAN bHardReset) -{ - ULONG Index = 0; - UCHAR R0 = 0xff; - UINT32 MacCsr12 = 0, Counter = 0; -#ifdef RT2870 - UINT32 MacCsr0 = 0; - NTSTATUS Status; - UCHAR Value = 0xff; -#endif // RT2870 // - USHORT KeyIdx; - INT i,apidx; - - DBGPRINT(RT_DEBUG_TRACE, ("--> NICInitializeAsic\n")); - - -#ifdef RT2870 - // - // Make sure MAC gets ready after NICLoadFirmware(). - // - Index = 0; - - //To avoid hang-on issue when interface up in kernel 2.4, - //we use a local variable "MacCsr0" instead of using "pAd->MACVersion" directly. - do - { - RTMP_IO_READ32(pAd, MAC_CSR0, &MacCsr0); - - if ((MacCsr0 != 0x00) && (MacCsr0 != 0xFFFFFFFF)) - break; - - RTMPusecDelay(10); - } while (Index++ < 100); - - pAd->MACVersion = MacCsr0; - DBGPRINT(RT_DEBUG_TRACE, ("MAC_CSR0 [ Ver:Rev=0x%08x]\n", pAd->MACVersion)); - // turn on bit13 (set to zero) after rt2860D. This is to solve high-current issue. - RTMP_IO_READ32(pAd, PBF_SYS_CTRL, &MacCsr12); - MacCsr12 &= (~0x2000); - RTMP_IO_WRITE32(pAd, PBF_SYS_CTRL, MacCsr12); - - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x3); - RTMP_IO_WRITE32(pAd, USB_DMA_CFG, 0x0); - Status = RTUSBVenderReset(pAd); - - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x0); - - // Initialize MAC register to default value - for(Index=0; IndexMACVersion&0xffff) != 0x0101) - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R84, 0x19); - -#ifdef RT2870 - //write RT3070 BBP wchich different with 2870 after write RT2870 BBP - if (IS_RT3070(pAd)) - { - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, 0x0a); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R84, 0x99); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R105, 0x05); - } -#endif // RT2870 // - - if (pAd->MACVersion == 0x28600100) - { - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, 0x16); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R73, 0x12); - } - - if (pAd->MACVersion >= RALINK_2880E_VERSION && pAd->MACVersion < RALINK_3070_VERSION) // 3*3 - { - // enlarge MAX_LEN_CFG - UINT32 csr; - RTMP_IO_READ32(pAd, MAX_LEN_CFG, &csr); - csr &= 0xFFF; - csr |= 0x2000; - RTMP_IO_WRITE32(pAd, MAX_LEN_CFG, csr); - } - -#ifdef RT2870 -{ - UCHAR MAC_Value[]={0xff,0xff,0xff,0xff,0xff,0xff,0xff,0,0}; - - //Initialize WCID table - Value = 0xff; - for(Index =0 ;Index < 254;Index++) - { - RTUSBMultiWrite(pAd, (USHORT)(MAC_WCID_BASE + Index * 8), MAC_Value, 8); - } -} -#endif // RT2870 // - - // Add radio off control -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - if (pAd->StaCfg.bRadio == FALSE) - { -// RTMP_IO_WRITE32(pAd, PWR_PIN_CFG, 0x00001818); - RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF); - DBGPRINT(RT_DEBUG_TRACE, ("Set Radio Off\n")); - } - } -#endif // CONFIG_STA_SUPPORT // - - // Clear raw counters - RTMP_IO_READ32(pAd, RX_STA_CNT0, &Counter); - RTMP_IO_READ32(pAd, RX_STA_CNT1, &Counter); - RTMP_IO_READ32(pAd, RX_STA_CNT2, &Counter); - RTMP_IO_READ32(pAd, TX_STA_CNT0, &Counter); - RTMP_IO_READ32(pAd, TX_STA_CNT1, &Counter); - RTMP_IO_READ32(pAd, TX_STA_CNT2, &Counter); - - // ASIC will keep garbage value after boot - // Clear all seared key table when initial - // This routine can be ignored in radio-ON/OFF operation. - if (bHardReset) - { - for (KeyIdx = 0; KeyIdx < 4; KeyIdx++) - { - RTMP_IO_WRITE32(pAd, SHARED_KEY_MODE_BASE + 4*KeyIdx, 0); - } - - // Clear all pairwise key table when initial - for (KeyIdx = 0; KeyIdx < 256; KeyIdx++) - { - RTMP_IO_WRITE32(pAd, MAC_WCID_ATTRIBUTE_BASE + (KeyIdx * HW_WCID_ATTRI_SIZE), 1); - } - } - - // assert HOST ready bit -// RTMP_IO_WRITE32(pAd, MAC_CSR1, 0x0); // 2004-09-14 asked by Mark -// RTMP_IO_WRITE32(pAd, MAC_CSR1, 0x4); - - // It isn't necessary to clear this space when not hard reset. - if (bHardReset == TRUE) - { - // clear all on-chip BEACON frame space - for (apidx = 0; apidx < HW_BEACON_MAX_COUNT; apidx++) - { - for (i = 0; i < HW_BEACON_OFFSET>>2; i+=4) - RTMP_IO_WRITE32(pAd, pAd->BeaconOffset[apidx] + i, 0x00); - } - } -#ifdef RT2870 - AsicDisableSync(pAd); - // Clear raw counters - RTMP_IO_READ32(pAd, RX_STA_CNT0, &Counter); - RTMP_IO_READ32(pAd, RX_STA_CNT1, &Counter); - RTMP_IO_READ32(pAd, RX_STA_CNT2, &Counter); - RTMP_IO_READ32(pAd, TX_STA_CNT0, &Counter); - RTMP_IO_READ32(pAd, TX_STA_CNT1, &Counter); - RTMP_IO_READ32(pAd, TX_STA_CNT2, &Counter); - // Default PCI clock cycle per ms is different as default setting, which is based on PCI. - RTMP_IO_READ32(pAd, USB_CYC_CFG, &Counter); - Counter&=0xffffff00; - Counter|=0x000001e; - RTMP_IO_WRITE32(pAd, USB_CYC_CFG, Counter); -#endif // RT2870 // - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - // for rt2860E and after, init TXOP_CTRL_CFG with 0x583f. This is for extension channel overlapping IOT. - if ((pAd->MACVersion&0xffff) != 0x0101) - RTMP_IO_WRITE32(pAd, TXOP_CTRL_CFG, 0x583f); - } -#endif // CONFIG_STA_SUPPORT // - - DBGPRINT(RT_DEBUG_TRACE, ("<-- NICInitializeAsic\n")); - return NDIS_STATUS_SUCCESS; -} - -/* - ======================================================================== - - Routine Description: - Reset NIC Asics - - Arguments: - Adapter Pointer to our adapter - - Return Value: - None - - IRQL = PASSIVE_LEVEL - - Note: - Reset NIC to initial state AS IS system boot up time. - - ======================================================================== -*/ -VOID NICIssueReset( - IN PRTMP_ADAPTER pAd) -{ - UINT32 Value = 0; - DBGPRINT(RT_DEBUG_TRACE, ("--> NICIssueReset\n")); - - // Abort Tx, prevent ASIC from writing to Host memory - //RTMP_IO_WRITE32(pAd, TX_CNTL_CSR, 0x001f0000); - - // Disable Rx, register value supposed will remain after reset - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value &= (0xfffffff3); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - - // Issue reset and clear from reset state - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x03); // 2004-09-17 change from 0x01 - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x00); - - DBGPRINT(RT_DEBUG_TRACE, ("<-- NICIssueReset\n")); -} - -/* - ======================================================================== - - Routine Description: - Check ASIC registers and find any reason the system might hang - - Arguments: - Adapter Pointer to our adapter - - Return Value: - None - - IRQL = DISPATCH_LEVEL - - ======================================================================== -*/ -BOOLEAN NICCheckForHang( - IN PRTMP_ADAPTER pAd) -{ - return (FALSE); -} - -VOID NICUpdateFifoStaCounters( - IN PRTMP_ADAPTER pAd) -{ - TX_STA_FIFO_STRUC StaFifo; - MAC_TABLE_ENTRY *pEntry; - UCHAR i = 0; - UCHAR pid = 0, wcid = 0; - CHAR reTry; - UCHAR succMCS; - -#ifdef RALINK_ATE - /* Nothing to do in ATE mode */ - if (ATE_ON(pAd)) - return; -#endif // RALINK_ATE // - - do - { - RTMP_IO_READ32(pAd, TX_STA_FIFO, &StaFifo.word); - - if (StaFifo.field.bValid == 0) - break; - - wcid = (UCHAR)StaFifo.field.wcid; - - - /* ignore NoACK and MGMT frame use 0xFF as WCID */ - if ((StaFifo.field.TxAckRequired == 0) || (wcid >= MAX_LEN_OF_MAC_TABLE)) - { - i++; - continue; - } - - /* PID store Tx MCS Rate */ - pid = (UCHAR)StaFifo.field.PidType; - - pEntry = &pAd->MacTab.Content[wcid]; - - pEntry->DebugFIFOCount++; - -#ifdef DOT11_N_SUPPORT - if (StaFifo.field.TxBF) // 3*3 - pEntry->TxBFCount++; -#endif // DOT11_N_SUPPORT // - -#ifdef UAPSD_AP_SUPPORT - UAPSD_SP_AUE_Handle(pAd, pEntry, StaFifo.field.TxSuccess); -#endif // UAPSD_AP_SUPPORT // - - if (!StaFifo.field.TxSuccess) - { - pEntry->FIFOCount++; - pEntry->OneSecTxFailCount++; - - if (pEntry->FIFOCount >= 1) - { - DBGPRINT(RT_DEBUG_TRACE, ("#")); -#if 0 - SendRefreshBAR(pAd, pEntry); - pEntry->NoBADataCountDown = 64; -#else -#ifdef DOT11_N_SUPPORT - pEntry->NoBADataCountDown = 64; -#endif // DOT11_N_SUPPORT // - - if(pEntry->PsMode == PWR_ACTIVE) - { -#ifdef DOT11_N_SUPPORT - int tid; - for (tid=0; tidAid, tid, FALSE, FALSE); - } -#endif // DOT11_N_SUPPORT // - - // Update the continuous transmission counter except PS mode - pEntry->ContinueTxFailCnt++; - } - else - { - // Clear the FIFOCount when sta in Power Save mode. Basically we assume - // this tx error happened due to sta just go to sleep. - pEntry->FIFOCount = 0; - pEntry->ContinueTxFailCnt = 0; - } -#endif - //pEntry->FIFOCount = 0; - } - //pEntry->bSendBAR = TRUE; - } - else - { -#ifdef DOT11_N_SUPPORT - if ((pEntry->PsMode != PWR_SAVE) && (pEntry->NoBADataCountDown > 0)) - { - pEntry->NoBADataCountDown--; - if (pEntry->NoBADataCountDown==0) - { - DBGPRINT(RT_DEBUG_TRACE, ("@\n")); - } - } -#endif // DOT11_N_SUPPORT // - pEntry->FIFOCount = 0; - pEntry->OneSecTxNoRetryOkCount++; - // update NoDataIdleCount when sucessful send packet to STA. - pEntry->NoDataIdleCount = 0; - pEntry->ContinueTxFailCnt = 0; - } - - succMCS = StaFifo.field.SuccessRate & 0x7F; - - reTry = pid - succMCS; - - if (StaFifo.field.TxSuccess) - { - pEntry->TXMCSExpected[pid]++; - if (pid == succMCS) - { - pEntry->TXMCSSuccessful[pid]++; - } - else - { - pEntry->TXMCSAutoFallBack[pid][succMCS]++; - } - } - else - { - pEntry->TXMCSFailed[pid]++; - } - - if (reTry > 0) - { - if ((pid >= 12) && succMCS <=7) - { - reTry -= 4; - } - pEntry->OneSecTxRetryOkCount += reTry; - } - - i++; - // ASIC store 16 stack - } while ( i < (2*TX_RING_SIZE) ); - -} - -/* - ======================================================================== - - Routine Description: - Read statistical counters from hardware registers and record them - in software variables for later on query - - Arguments: - pAd Pointer to our adapter - - Return Value: - None - - IRQL = DISPATCH_LEVEL - - ======================================================================== -*/ -VOID NICUpdateRawCounters( - IN PRTMP_ADAPTER pAd) -{ - UINT32 OldValue; - RX_STA_CNT0_STRUC RxStaCnt0; - RX_STA_CNT1_STRUC RxStaCnt1; - RX_STA_CNT2_STRUC RxStaCnt2; - TX_STA_CNT0_STRUC TxStaCnt0; - TX_STA_CNT1_STRUC StaTx1; - TX_STA_CNT2_STRUC StaTx2; - TX_AGG_CNT_STRUC TxAggCnt; - TX_AGG_CNT0_STRUC TxAggCnt0; - TX_AGG_CNT1_STRUC TxAggCnt1; - TX_AGG_CNT2_STRUC TxAggCnt2; - TX_AGG_CNT3_STRUC TxAggCnt3; - TX_AGG_CNT4_STRUC TxAggCnt4; - TX_AGG_CNT5_STRUC TxAggCnt5; - TX_AGG_CNT6_STRUC TxAggCnt6; - TX_AGG_CNT7_STRUC TxAggCnt7; - - - RTMP_IO_READ32(pAd, RX_STA_CNT0, &RxStaCnt0.word); - RTMP_IO_READ32(pAd, RX_STA_CNT2, &RxStaCnt2.word); - - { - RTMP_IO_READ32(pAd, RX_STA_CNT1, &RxStaCnt1.word); - // Update RX PLCP error counter - pAd->PrivateInfo.PhyRxErrCnt += RxStaCnt1.field.PlcpErr; - // Update False CCA counter - pAd->RalinkCounters.OneSecFalseCCACnt += RxStaCnt1.field.FalseCca; - } - - // Update FCS counters - OldValue= pAd->WlanCounters.FCSErrorCount.u.LowPart; - pAd->WlanCounters.FCSErrorCount.u.LowPart += (RxStaCnt0.field.CrcErr); // >> 7); - if (pAd->WlanCounters.FCSErrorCount.u.LowPart < OldValue) - pAd->WlanCounters.FCSErrorCount.u.HighPart++; - - // Add FCS error count to private counters - pAd->RalinkCounters.OneSecRxFcsErrCnt += RxStaCnt0.field.CrcErr; - OldValue = pAd->RalinkCounters.RealFcsErrCount.u.LowPart; - pAd->RalinkCounters.RealFcsErrCount.u.LowPart += RxStaCnt0.field.CrcErr; - if (pAd->RalinkCounters.RealFcsErrCount.u.LowPart < OldValue) - pAd->RalinkCounters.RealFcsErrCount.u.HighPart++; - - // Update Duplicate Rcv check - pAd->RalinkCounters.DuplicateRcv += RxStaCnt2.field.RxDupliCount; - pAd->WlanCounters.FrameDuplicateCount.u.LowPart += RxStaCnt2.field.RxDupliCount; - // Update RX Overflow counter - pAd->Counters8023.RxNoBuffer += (RxStaCnt2.field.RxFifoOverflowCount); - - //pAd->RalinkCounters.RxCount = 0; -#ifdef RT2870 - if (pAd->RalinkCounters.RxCount != pAd->watchDogRxCnt) - { - pAd->watchDogRxCnt = pAd->RalinkCounters.RxCount; - pAd->watchDogRxOverFlowCnt = 0; - } - else - { - if (RxStaCnt2.field.RxFifoOverflowCount) - pAd->watchDogRxOverFlowCnt++; - else - pAd->watchDogRxOverFlowCnt = 0; - } -#endif // RT2870 // - - - //if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED) || - // (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED) && (pAd->MacTab.Size != 1))) - if (!pAd->bUpdateBcnCntDone) - { - // Update BEACON sent count - RTMP_IO_READ32(pAd, TX_STA_CNT0, &TxStaCnt0.word); - RTMP_IO_READ32(pAd, TX_STA_CNT1, &StaTx1.word); - RTMP_IO_READ32(pAd, TX_STA_CNT2, &StaTx2.word); - pAd->RalinkCounters.OneSecBeaconSentCnt += TxStaCnt0.field.TxBeaconCount; - pAd->RalinkCounters.OneSecTxRetryOkCount += StaTx1.field.TxRetransmit; - pAd->RalinkCounters.OneSecTxNoRetryOkCount += StaTx1.field.TxSuccess; - pAd->RalinkCounters.OneSecTxFailCount += TxStaCnt0.field.TxFailCount; - pAd->WlanCounters.TransmittedFragmentCount.u.LowPart += StaTx1.field.TxSuccess; - pAd->WlanCounters.RetryCount.u.LowPart += StaTx1.field.TxRetransmit; - pAd->WlanCounters.FailedCount.u.LowPart += TxStaCnt0.field.TxFailCount; - } - -#if 0 - Retry = StaTx1.field.TxRetransmit; - Fail = TxStaCnt0.field.TxFailCount; - TxErrorRatio = 0; - OneSecTransmitCount = pAd->WlanCounters.TransmittedFragmentCount.u.LowPart- pAd->WlanCounters.LastTransmittedFragmentCount.u.LowPart; - if ((OneSecTransmitCount+Retry + Fail) > 0) - TxErrorRatio = (( Retry + Fail) *100) / (OneSecTransmitCount+Retry + Fail); - - if ((OneSecTransmitCount+Retry + Fail) > 0) - TxErrorRatio = (( Retry + Fail) *100) / (OneSecTransmitCount+Retry + Fail); - DBGPRINT(RT_DEBUG_INFO, ("TX ERROR Rate = %ld %%, Retry = %ld, Fail = %ld, Total = %ld \n",TxErrorRatio, Retry, Fail, (OneSecTransmitCount+Retry + Fail))); - pAd->WlanCounters.LastTransmittedFragmentCount.u.LowPart = pAd->WlanCounters.TransmittedFragmentCount.u.LowPart; -#endif - - //if (pAd->bStaFifoTest == TRUE) - { - RTMP_IO_READ32(pAd, TX_AGG_CNT, &TxAggCnt.word); - RTMP_IO_READ32(pAd, TX_AGG_CNT0, &TxAggCnt0.word); - RTMP_IO_READ32(pAd, TX_AGG_CNT1, &TxAggCnt1.word); - RTMP_IO_READ32(pAd, TX_AGG_CNT2, &TxAggCnt2.word); - RTMP_IO_READ32(pAd, TX_AGG_CNT3, &TxAggCnt3.word); - RTMP_IO_READ32(pAd, TX_AGG_CNT4, &TxAggCnt4.word); - RTMP_IO_READ32(pAd, TX_AGG_CNT5, &TxAggCnt5.word); - RTMP_IO_READ32(pAd, TX_AGG_CNT6, &TxAggCnt6.word); - RTMP_IO_READ32(pAd, TX_AGG_CNT7, &TxAggCnt7.word); - pAd->RalinkCounters.TxAggCount += TxAggCnt.field.AggTxCount; - pAd->RalinkCounters.TxNonAggCount += TxAggCnt.field.NonAggTxCount; - pAd->RalinkCounters.TxAgg1MPDUCount += TxAggCnt0.field.AggSize1Count; - pAd->RalinkCounters.TxAgg2MPDUCount += TxAggCnt0.field.AggSize2Count; - - pAd->RalinkCounters.TxAgg3MPDUCount += TxAggCnt1.field.AggSize3Count; - pAd->RalinkCounters.TxAgg4MPDUCount += TxAggCnt1.field.AggSize4Count; - pAd->RalinkCounters.TxAgg5MPDUCount += TxAggCnt2.field.AggSize5Count; - pAd->RalinkCounters.TxAgg6MPDUCount += TxAggCnt2.field.AggSize6Count; - - pAd->RalinkCounters.TxAgg7MPDUCount += TxAggCnt3.field.AggSize7Count; - pAd->RalinkCounters.TxAgg8MPDUCount += TxAggCnt3.field.AggSize8Count; - pAd->RalinkCounters.TxAgg9MPDUCount += TxAggCnt4.field.AggSize9Count; - pAd->RalinkCounters.TxAgg10MPDUCount += TxAggCnt4.field.AggSize10Count; - - pAd->RalinkCounters.TxAgg11MPDUCount += TxAggCnt5.field.AggSize11Count; - pAd->RalinkCounters.TxAgg12MPDUCount += TxAggCnt5.field.AggSize12Count; - pAd->RalinkCounters.TxAgg13MPDUCount += TxAggCnt6.field.AggSize13Count; - pAd->RalinkCounters.TxAgg14MPDUCount += TxAggCnt6.field.AggSize14Count; - - pAd->RalinkCounters.TxAgg15MPDUCount += TxAggCnt7.field.AggSize15Count; - pAd->RalinkCounters.TxAgg16MPDUCount += TxAggCnt7.field.AggSize16Count; - - // Calculate the transmitted A-MPDU count - pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += TxAggCnt0.field.AggSize1Count; - pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt0.field.AggSize2Count / 2); - - pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt1.field.AggSize3Count / 3); - pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt1.field.AggSize4Count / 4); - - pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt2.field.AggSize5Count / 5); - pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt2.field.AggSize6Count / 6); - - pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt3.field.AggSize7Count / 7); - pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt3.field.AggSize8Count / 8); - - pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt4.field.AggSize9Count / 9); - pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt4.field.AggSize10Count / 10); - - pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt5.field.AggSize11Count / 11); - pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt5.field.AggSize12Count / 12); - - pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt6.field.AggSize13Count / 13); - pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt6.field.AggSize14Count / 14); - - pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt7.field.AggSize15Count / 15); - pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt7.field.AggSize16Count / 16); - } - -#ifdef DBG_DIAGNOSE - { - RtmpDiagStruct *pDiag; - COUNTER_RALINK *pRalinkCounters; - UCHAR ArrayCurIdx, i; - - pDiag = &pAd->DiagStruct; - pRalinkCounters = &pAd->RalinkCounters; - ArrayCurIdx = pDiag->ArrayCurIdx; - - if (pDiag->inited == 0) - { - NdisZeroMemory(pDiag, sizeof(struct _RtmpDiagStrcut_)); - pDiag->ArrayStartIdx = pDiag->ArrayCurIdx = 0; - pDiag->inited = 1; - } - else - { - // Tx - pDiag->TxFailCnt[ArrayCurIdx] = TxStaCnt0.field.TxFailCount; - pDiag->TxAggCnt[ArrayCurIdx] = TxAggCnt.field.AggTxCount; - pDiag->TxNonAggCnt[ArrayCurIdx] = TxAggCnt.field.NonAggTxCount; - pDiag->TxAMPDUCnt[ArrayCurIdx][0] = TxAggCnt0.field.AggSize1Count; - pDiag->TxAMPDUCnt[ArrayCurIdx][1] = TxAggCnt0.field.AggSize2Count; - pDiag->TxAMPDUCnt[ArrayCurIdx][2] = TxAggCnt1.field.AggSize3Count; - pDiag->TxAMPDUCnt[ArrayCurIdx][3] = TxAggCnt1.field.AggSize4Count; - pDiag->TxAMPDUCnt[ArrayCurIdx][4] = TxAggCnt2.field.AggSize5Count; - pDiag->TxAMPDUCnt[ArrayCurIdx][5] = TxAggCnt2.field.AggSize6Count; - pDiag->TxAMPDUCnt[ArrayCurIdx][6] = TxAggCnt3.field.AggSize7Count; - pDiag->TxAMPDUCnt[ArrayCurIdx][7] = TxAggCnt3.field.AggSize8Count; - pDiag->TxAMPDUCnt[ArrayCurIdx][8] = TxAggCnt4.field.AggSize9Count; - pDiag->TxAMPDUCnt[ArrayCurIdx][9] = TxAggCnt4.field.AggSize10Count; - pDiag->TxAMPDUCnt[ArrayCurIdx][10] = TxAggCnt5.field.AggSize11Count; - pDiag->TxAMPDUCnt[ArrayCurIdx][11] = TxAggCnt5.field.AggSize12Count; - pDiag->TxAMPDUCnt[ArrayCurIdx][12] = TxAggCnt6.field.AggSize13Count; - pDiag->TxAMPDUCnt[ArrayCurIdx][13] = TxAggCnt6.field.AggSize14Count; - pDiag->TxAMPDUCnt[ArrayCurIdx][14] = TxAggCnt7.field.AggSize15Count; - pDiag->TxAMPDUCnt[ArrayCurIdx][15] = TxAggCnt7.field.AggSize16Count; - - pDiag->RxCrcErrCnt[ArrayCurIdx] = RxStaCnt0.field.CrcErr; - - INC_RING_INDEX(pDiag->ArrayCurIdx, DIAGNOSE_TIME); - ArrayCurIdx = pDiag->ArrayCurIdx; - for (i =0; i < 9; i++) - { - pDiag->TxDescCnt[ArrayCurIdx][i]= 0; - pDiag->TxSWQueCnt[ArrayCurIdx][i] =0; - pDiag->TxMcsCnt[ArrayCurIdx][i] = 0; - pDiag->RxMcsCnt[ArrayCurIdx][i] = 0; - } - pDiag->TxDataCnt[ArrayCurIdx] = 0; - pDiag->TxFailCnt[ArrayCurIdx] = 0; - pDiag->RxDataCnt[ArrayCurIdx] = 0; - pDiag->RxCrcErrCnt[ArrayCurIdx] = 0; -// for (i = 9; i < 16; i++) - for (i = 9; i < 24; i++) // 3*3 - { - pDiag->TxDescCnt[ArrayCurIdx][i] = 0; - pDiag->TxMcsCnt[ArrayCurIdx][i] = 0; - pDiag->RxMcsCnt[ArrayCurIdx][i] = 0; -} - - if (pDiag->ArrayCurIdx == pDiag->ArrayStartIdx) - INC_RING_INDEX(pDiag->ArrayStartIdx, DIAGNOSE_TIME); - } - - } -#endif // DBG_DIAGNOSE // - - -} - - -/* - ======================================================================== - - Routine Description: - Reset NIC from error - - Arguments: - Adapter Pointer to our adapter - - Return Value: - None - - IRQL = PASSIVE_LEVEL - - Note: - Reset NIC from error state - - ======================================================================== -*/ -VOID NICResetFromError( - IN PRTMP_ADAPTER pAd) -{ - // Reset BBP (according to alex, reset ASIC will force reset BBP - // Therefore, skip the reset BBP - // RTMP_IO_WRITE32(pAd, MAC_CSR1, 0x2); - - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x1); - // Remove ASIC from reset state - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x0); - - NICInitializeAdapter(pAd, FALSE); - NICInitAsicFromEEPROM(pAd); - - // Switch to current channel, since during reset process, the connection should remains on. - AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE); - AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel); -} - -/* - ======================================================================== - - Routine Description: - erase 8051 firmware image in MAC ASIC - - Arguments: - Adapter Pointer to our adapter - - IRQL = PASSIVE_LEVEL - - ======================================================================== -*/ -VOID NICEraseFirmware( - IN PRTMP_ADAPTER pAd) -{ - ULONG i; - - for(i=0; i %s\n", __func__)); - - /* init */ - pFirmwareImage = NULL; - src = RTMP_FIRMWARE_FILE_NAME; - - /* save uid and gid used for filesystem access. - set user and group to 0 (root) */ - orgfsuid = current->fsuid; - orgfsgid = current->fsgid; - current->fsuid = current->fsgid = 0; - orgfs = get_fs(); - set_fs(KERNEL_DS); - - pAd->FirmwareVersion = (FIRMWARE_MAJOR_VERSION << 8) + \ - FIRMWARE_MINOR_VERSION; - - - /* allocate firmware buffer */ - pFirmwareImage = kmalloc(MAX_FIRMWARE_IMAGE_SIZE, MEM_ALLOC_FLAG); - if (pFirmwareImage == NULL) - { - /* allocate fail, use default firmware array in firmware.h */ - printk("%s - Allocate memory fail!\n", __func__); - NICLF_DEFAULT_USE(); - } - else - { - /* allocate ok! zero the firmware buffer */ - memset(pFirmwareImage, 0x00, MAX_FIRMWARE_IMAGE_SIZE); - } /* End of if */ - - - /* if ok, read firmware file from *.bin file */ - if (flg_default_firm_use == FALSE) - { - do - { - /* open the bin file */ - srcf = filp_open(src, O_RDONLY, 0); - - if (IS_ERR(srcf)) - { - printk("%s - Error %ld opening %s\n", - __func__, -PTR_ERR(srcf), src); - NICLF_DEFAULT_USE(); - break; - } /* End of if */ - - /* the object must have a read method */ - if ((srcf->f_op == NULL) || (srcf->f_op->read == NULL)) - { - printk("%s - %s does not have a write method\n", __func__, src); - NICLF_DEFAULT_USE(); - break; - } /* End of if */ - - /* read the firmware from the file *.bin */ - FileLength = srcf->f_op->read(srcf, - pFirmwareImage, - MAX_FIRMWARE_IMAGE_SIZE, - &srcf->f_pos); - - if (FileLength != MAX_FIRMWARE_IMAGE_SIZE) - { - printk("%s: error file length (=%d) in RT2860AP.BIN\n", - __func__, FileLength); - NICLF_DEFAULT_USE(); - break; - } - else - { - PUCHAR ptr = pFirmwareImage; - USHORT crc = 0xffff; - - - /* calculate firmware CRC */ - for(i=0; i<(MAX_FIRMWARE_IMAGE_SIZE-2); i++, ptr++) - crc = ByteCRC16(BitReverse(*ptr), crc); - /* End of for */ - - if ((pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-2] != \ - (UCHAR)BitReverse((UCHAR)(crc>>8))) || - (pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-1] != \ - (UCHAR)BitReverse((UCHAR)crc))) - { - /* CRC fail */ - printk("%s: CRC = 0x%02x 0x%02x " - "error, should be 0x%02x 0x%02x\n", - __func__, - pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-2], - pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-1], - (UCHAR)(crc>>8), (UCHAR)(crc)); - NICLF_DEFAULT_USE(); - break; - } - else - { - /* firmware is ok */ - pAd->FirmwareVersion = \ - (pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-4] << 8) + - pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-3]; - - /* check if firmware version of the file is too old */ - if ((pAd->FirmwareVersion) < \ - ((FIRMWARE_MAJOR_VERSION << 8) + - FIRMWARE_MINOR_VERSION)) - { - printk("%s: firmware version too old!\n", __func__); - NICLF_DEFAULT_USE(); - break; - } /* End of if */ - } /* End of if */ - - DBGPRINT(RT_DEBUG_TRACE, - ("NICLoadFirmware: CRC ok, ver=%d.%d\n", - pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-4], - pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-3])); - } /* End of if (FileLength == MAX_FIRMWARE_IMAGE_SIZE) */ - break; - } while(TRUE); - - /* close firmware file */ - if (IS_ERR(srcf)) - ; - else - { - retval = filp_close(srcf, NULL); - if (retval) - { - DBGPRINT(RT_DEBUG_ERROR, - ("--> Error %d closing %s\n", -retval, src)); - } /* End of if */ - } /* End of if */ - } /* End of if */ - - - /* write firmware to ASIC */ - if (flg_default_firm_use == TRUE) - { - /* use default fimeware, free allocated buffer */ - if (pFirmwareImage != NULL) - kfree(pFirmwareImage); - /* End of if */ - - /* use default *.bin array */ - pFirmwareImage = FirmwareImage; - FileLength = sizeof(FirmwareImage); - } /* End of if */ - - /* enable Host program ram write selection */ - RTMP_IO_WRITE32(pAd, PBF_SYS_CTRL, 0x10000); - - for(i=0; ifsuid = orgfsuid; - current->fsgid = orgfsgid; -#else - - NDIS_STATUS Status = NDIS_STATUS_SUCCESS; - PUCHAR pFirmwareImage; - ULONG FileLength, Index; - //ULONG firm; - UINT32 MacReg = 0; -#ifdef RT2870 - UINT32 Version = (pAd->MACVersion >> 16); -#endif // RT2870 // - - pFirmwareImage = FirmwareImage; - FileLength = sizeof(FirmwareImage); -#ifdef RT2870 - // New 8k byte firmware size for RT3071/RT3072 - //printk("Usb Chip\n"); - if (FIRMWAREIMAGE_LENGTH == FIRMWAREIMAGE_MAX_LENGTH) - //The firmware image consists of two parts. One is the origianl and the other is the new. - //Use Second Part - { - if ((Version != 0x2860) && (Version != 0x2872) && (Version != 0x3070)) - { // Use Firmware V2. - //printk("KH:Use New Version,part2\n"); - pFirmwareImage = (PUCHAR)&FirmwareImage[FIRMWAREIMAGEV1_LENGTH]; - FileLength = FIRMWAREIMAGEV2_LENGTH; - } - else - { - //printk("KH:Use New Version,part1\n"); - pFirmwareImage = FirmwareImage; - FileLength = FIRMWAREIMAGEV1_LENGTH; - } - } - else - { - DBGPRINT(RT_DEBUG_ERROR, ("KH: bin file should be 8KB.\n")); - Status = NDIS_STATUS_FAILURE; - } - -#endif // RT2870 // - -#if 0 - /* enable Host program ram write selection */ - RT28XX_FIRMUD_INIT(pAd); - - for(i=0; i= 1000) - { - Status = NDIS_STATUS_FAILURE; - DBGPRINT(RT_DEBUG_ERROR, ("NICLoadFirmware: MCU is not ready\n\n\n")); - } /* End of if */ - -#if 0 - DBGPRINT(RT_DEBUG_TRACE, - ("<=== %s (src=%s, status=%d)\n", __func__, src, Status)); -#else - DBGPRINT(RT_DEBUG_TRACE, - ("<=== %s (status=%d)\n", __func__, Status)); -#endif - return Status; -} /* End of NICLoadFirmware */ - - -/* - ======================================================================== - - Routine Description: - Load Tx rate switching parameters - - Arguments: - Adapter Pointer to our adapter - - Return Value: - NDIS_STATUS_SUCCESS firmware image load ok - NDIS_STATUS_FAILURE image not found - - IRQL = PASSIVE_LEVEL - - Rate Table Format: - 1. (B0: Valid Item number) (B1:Initial item from zero) - 2. Item Number(Dec) Mode(Hex) Current MCS(Dec) TrainUp(Dec) TrainDown(Dec) - - ======================================================================== -*/ -NDIS_STATUS NICLoadRateSwitchingParams( - IN PRTMP_ADAPTER pAd) -{ -#if 0 - NDIS_STATUS Status; - - NDIS_HANDLE FileHandle; - UINT FileLength = 0, i, j; - PUCHAR pFirmwareImage; - NDIS_STRING FileName; - NDIS_PHYSICAL_ADDRESS HighestAcceptableMax = NDIS_PHYSICAL_ADDRESS_CONST(-1, -1); - - DBGPRINT(RT_DEBUG_TRACE,("===> NICLoadRateSwitchingParams \n")); - pAd->CommonCfg.TxRateTableSize = 0; - - if ((pAd->DeviceID == NIC2860_PCI_DEVICE_ID) || (pAd->DeviceID == NIC2860_PCIe_DEVICE_ID)) - { - NdisInitializeString(&FileName,"rate.bin"); - DBGPRINT(RT_DEBUG_TRACE, ("NICLoadRateSwitchingParams: load file - rate.bin for tx rate switch \n")); - } - else - { - DBGPRINT_ERR(("NICLoadRateSwitchingParams: wrong DeviceID = 0x%04x, can't find Tx rate switch parameters file\n", pAd->DeviceID)); - return NDIS_STATUS_SUCCESS; - } - NdisOpenFile(&Status, &FileHandle, &FileLength, &FileName, HighestAcceptableMax); - NdisFreeString(FileName); - - if (Status != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_ERROR, ("NICLoadRateSwitchingParams: NdisOpenFile() failed, used RateSwitchTable instead\n")); - return NDIS_STATUS_SUCCESS; - } - - if ((FileLength == 0) || (FileLength > (MAX_STEP_OF_TX_RATE_SWITCH+1)*16)) - { - DBGPRINT(RT_DEBUG_ERROR, ("NICLoadRateSwitchingParams: file size is not reasonable, used RateSwitchTable instead\n")); - - NdisCloseFile(FileHandle); - return NDIS_STATUS_SUCCESS; - } - else - { - // - // NDIS_STATUS_SUCCESS means - // The handle at FileHandle is valid for a subsequent call to NdisMapFile. - // - NdisMapFile(&Status, &pFirmwareImage, FileHandle); - DBGPRINT(RT_DEBUG_TRACE, ("NdisMapFile FileLength=%d\n", FileLength)); - } - - for (i=0, j=0; i>4) * 10 + (*(pFirmwareImage + i) & 0x0F); - } - - j++; - } - } - - pAd->CommonCfg.TxRateTableSize = RateSwitchTable[0]; // backup table size - - if (Status == NDIS_STATUS_SUCCESS) - { - NdisUnmapFile(FileHandle); - NdisCloseFile(FileHandle); - } - - DBGPRINT(RT_DEBUG_TRACE,("<=== NICLoadRateSwitchingParams(Valid TxRateTable item number=%d)\n", pAd->CommonCfg.TxRateTableSize)); -#endif - return NDIS_STATUS_SUCCESS; -} - -/* - ======================================================================== - - Routine Description: - if pSrc1 all zero with length Length, return 0. - If not all zero, return 1 - - Arguments: - pSrc1 - - Return Value: - 1: not all zero - 0: all zero - - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -ULONG RTMPNotAllZero( - IN PVOID pSrc1, - IN ULONG Length) -{ - PUCHAR pMem1; - ULONG Index = 0; - - pMem1 = (PUCHAR) pSrc1; - - for (Index = 0; Index < Length; Index++) - { - if (pMem1[Index] != 0x0) - { - break; - } - } - - if (Index == Length) - { - return (0); - } - else - { - return (1); - } -} - -/* - ======================================================================== - - Routine Description: - Compare two memory block - - Arguments: - pSrc1 Pointer to first memory address - pSrc2 Pointer to second memory address - - Return Value: - 0: memory is equal - 1: pSrc1 memory is larger - 2: pSrc2 memory is larger - - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -ULONG RTMPCompareMemory( - IN PVOID pSrc1, - IN PVOID pSrc2, - IN ULONG Length) -{ - PUCHAR pMem1; - PUCHAR pMem2; - ULONG Index = 0; - - pMem1 = (PUCHAR) pSrc1; - pMem2 = (PUCHAR) pSrc2; - - for (Index = 0; Index < Length; Index++) - { - if (pMem1[Index] > pMem2[Index]) - return (1); - else if (pMem1[Index] < pMem2[Index]) - return (2); - } - - // Equal - return (0); -} - -/* - ======================================================================== - - Routine Description: - Zero out memory block - - Arguments: - pSrc1 Pointer to memory address - Length Size - - Return Value: - None - - IRQL = PASSIVE_LEVEL - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -VOID RTMPZeroMemory( - IN PVOID pSrc, - IN ULONG Length) -{ - PUCHAR pMem; - ULONG Index = 0; - - pMem = (PUCHAR) pSrc; - - for (Index = 0; Index < Length; Index++) - { - pMem[Index] = 0x00; - } -} - -VOID RTMPFillMemory( - IN PVOID pSrc, - IN ULONG Length, - IN UCHAR Fill) -{ - PUCHAR pMem; - ULONG Index = 0; - - pMem = (PUCHAR) pSrc; - - for (Index = 0; Index < Length; Index++) - { - pMem[Index] = Fill; - } -} - -/* - ======================================================================== - - Routine Description: - Copy data from memory block 1 to memory block 2 - - Arguments: - pDest Pointer to destination memory address - pSrc Pointer to source memory address - Length Copy size - - Return Value: - None - - IRQL = PASSIVE_LEVEL - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -VOID RTMPMoveMemory( - OUT PVOID pDest, - IN PVOID pSrc, - IN ULONG Length) -{ - PUCHAR pMem1; - PUCHAR pMem2; - UINT Index; - - ASSERT((Length==0) || (pDest && pSrc)); - - pMem1 = (PUCHAR) pDest; - pMem2 = (PUCHAR) pSrc; - - for (Index = 0; Index < Length; Index++) - { - pMem1[Index] = pMem2[Index]; - } -} - -/* - ======================================================================== - - Routine Description: - Initialize port configuration structure - - Arguments: - Adapter Pointer to our adapter - - Return Value: - None - - IRQL = PASSIVE_LEVEL - - Note: - - ======================================================================== -*/ -VOID UserCfgInit( - IN PRTMP_ADAPTER pAd) -{ -// EDCA_PARM DefaultEdcaParm; - UINT key_index, bss_index; - - DBGPRINT(RT_DEBUG_TRACE, ("--> UserCfgInit\n")); - - // - // part I. intialize common configuration - // -#ifdef RT2870 - pAd->BulkOutReq = 0; - - pAd->BulkOutComplete = 0; - pAd->BulkOutCompleteOther = 0; - pAd->BulkOutCompleteCancel = 0; - pAd->BulkInReq = 0; - pAd->BulkInComplete = 0; - pAd->BulkInCompleteFail = 0; - - //pAd->QuickTimerP = 100; - //pAd->TurnAggrBulkInCount = 0; - pAd->bUsbTxBulkAggre = 0; - - // init as unsed value to ensure driver will set to MCU once. - pAd->LedIndicatorStregth = 0xFF; - - pAd->CommonCfg.MaxPktOneTxBulk = 2; - pAd->CommonCfg.TxBulkFactor = 1; - pAd->CommonCfg.RxBulkFactor =1; - - pAd->CommonCfg.TxPower = 100; //mW - - NdisZeroMemory(&pAd->CommonCfg.IOTestParm, sizeof(pAd->CommonCfg.IOTestParm)); -#endif // RT2870 // - - for(key_index=0; key_indexSharedKey[bss_index][key_index].KeyLen = 0; - pAd->SharedKey[bss_index][key_index].CipherAlg = CIPHER_NONE; - } - } - - pAd->Antenna.word = 0; - pAd->CommonCfg.BBPCurrentBW = BW_20; - - pAd->LedCntl.word = 0; - - pAd->bAutoTxAgcA = FALSE; // Default is OFF - pAd->bAutoTxAgcG = FALSE; // Default is OFF - pAd->RfIcType = RFIC_2820; - - // Init timer for reset complete event - pAd->CommonCfg.CentralChannel = 1; - pAd->bForcePrintTX = FALSE; - pAd->bForcePrintRX = FALSE; - pAd->bStaFifoTest = FALSE; - pAd->bProtectionTest = FALSE; - pAd->bHCCATest = FALSE; - pAd->bGenOneHCCA = FALSE; - pAd->CommonCfg.Dsifs = 10; // in units of usec - pAd->CommonCfg.TxPower = 100; //mW - pAd->CommonCfg.TxPowerPercentage = 0xffffffff; // AUTO - pAd->CommonCfg.TxPowerDefault = 0xffffffff; // AUTO - pAd->CommonCfg.TxPreamble = Rt802_11PreambleAuto; // use Long preamble on TX by defaut - pAd->CommonCfg.bUseZeroToDisableFragment = FALSE; - pAd->CommonCfg.RtsThreshold = 2347; - pAd->CommonCfg.FragmentThreshold = 2346; - pAd->CommonCfg.UseBGProtection = 0; // 0: AUTO - pAd->CommonCfg.bEnableTxBurst = TRUE; //0; - pAd->CommonCfg.PhyMode = 0xff; // unknown - pAd->CommonCfg.BandState = UNKNOWN_BAND; - pAd->CommonCfg.RadarDetect.CSPeriod = 10; - pAd->CommonCfg.RadarDetect.CSCount = 0; - pAd->CommonCfg.RadarDetect.RDMode = RD_NORMAL_MODE; - pAd->CommonCfg.RadarDetect.ChMovingTime = 65; - pAd->CommonCfg.RadarDetect.LongPulseRadarTh = 3; - pAd->CommonCfg.bAPSDCapable = FALSE; - pAd->CommonCfg.bNeedSendTriggerFrame = FALSE; - pAd->CommonCfg.TriggerTimerCount = 0; - pAd->CommonCfg.bAPSDForcePowerSave = FALSE; - pAd->CommonCfg.bCountryFlag = FALSE; - pAd->CommonCfg.TxStream = 0; - pAd->CommonCfg.RxStream = 0; - - NdisZeroMemory(&pAd->BeaconTxWI, sizeof(pAd->BeaconTxWI)); - -#ifdef DOT11_N_SUPPORT - NdisZeroMemory(&pAd->CommonCfg.HtCapability, sizeof(pAd->CommonCfg.HtCapability)); - pAd->HTCEnable = FALSE; - pAd->bBroadComHT = FALSE; - pAd->CommonCfg.bRdg = FALSE; - -#ifdef DOT11N_DRAFT3 - pAd->CommonCfg.Dot11OBssScanPassiveDwell = dot11OBSSScanPassiveDwell; // Unit : TU. 5~1000 - pAd->CommonCfg.Dot11OBssScanActiveDwell = dot11OBSSScanActiveDwell; // Unit : TU. 10~1000 - pAd->CommonCfg.Dot11BssWidthTriggerScanInt = dot11BSSWidthTriggerScanInterval; // Unit : Second - pAd->CommonCfg.Dot11OBssScanPassiveTotalPerChannel = dot11OBSSScanPassiveTotalPerChannel; // Unit : TU. 200~10000 - pAd->CommonCfg.Dot11OBssScanActiveTotalPerChannel = dot11OBSSScanActiveTotalPerChannel; // Unit : TU. 20~10000 - pAd->CommonCfg.Dot11BssWidthChanTranDelayFactor = dot11BSSWidthChannelTransactionDelayFactor; - pAd->CommonCfg.Dot11OBssScanActivityThre = dot11BSSScanActivityThreshold; // Unit : percentage - pAd->CommonCfg.Dot11BssWidthChanTranDelay = (pAd->CommonCfg.Dot11BssWidthTriggerScanInt * pAd->CommonCfg.Dot11BssWidthChanTranDelayFactor); -#endif // DOT11N_DRAFT3 // - - NdisZeroMemory(&pAd->CommonCfg.AddHTInfo, sizeof(pAd->CommonCfg.AddHTInfo)); - pAd->CommonCfg.BACapability.field.MMPSmode = MMPS_ENABLE; - pAd->CommonCfg.BACapability.field.MpduDensity = 0; - pAd->CommonCfg.BACapability.field.Policy = IMMED_BA; - pAd->CommonCfg.BACapability.field.RxBAWinLimit = 64; //32; - pAd->CommonCfg.BACapability.field.TxBAWinLimit = 64; //32; - DBGPRINT(RT_DEBUG_TRACE, ("--> UserCfgInit. BACapability = 0x%x\n", pAd->CommonCfg.BACapability.word)); - - pAd->CommonCfg.BACapability.field.AutoBA = FALSE; - BATableInit(pAd, &pAd->BATable); - - pAd->CommonCfg.bExtChannelSwitchAnnouncement = 1; - pAd->CommonCfg.bHTProtect = 1; - pAd->CommonCfg.bMIMOPSEnable = TRUE; - pAd->CommonCfg.bBADecline = FALSE; - pAd->CommonCfg.bDisableReordering = FALSE; - - pAd->CommonCfg.TxBASize = 7; - - pAd->CommonCfg.REGBACapability.word = pAd->CommonCfg.BACapability.word; -#endif // DOT11_N_SUPPORT // - - //pAd->CommonCfg.HTPhyMode.field.BW = BW_20; - //pAd->CommonCfg.HTPhyMode.field.MCS = MCS_AUTO; - //pAd->CommonCfg.HTPhyMode.field.ShortGI = GI_800; - //pAd->CommonCfg.HTPhyMode.field.STBC = STBC_NONE; - pAd->CommonCfg.TxRate = RATE_6; - - pAd->CommonCfg.MlmeTransmit.field.MCS = MCS_RATE_6; - pAd->CommonCfg.MlmeTransmit.field.BW = BW_20; - pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM; - - pAd->CommonCfg.BeaconPeriod = 100; // in mSec - - // - // part II. intialize STA specific configuration - // -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - RX_FILTER_SET_FLAG(pAd, fRX_FILTER_ACCEPT_DIRECT); - RX_FILTER_CLEAR_FLAG(pAd, fRX_FILTER_ACCEPT_MULTICAST); - RX_FILTER_SET_FLAG(pAd, fRX_FILTER_ACCEPT_BROADCAST); - RX_FILTER_SET_FLAG(pAd, fRX_FILTER_ACCEPT_ALL_MULTICAST); - - pAd->StaCfg.Psm = PWR_ACTIVE; - - pAd->StaCfg.OrigWepStatus = Ndis802_11EncryptionDisabled; - pAd->StaCfg.PairCipher = Ndis802_11EncryptionDisabled; - pAd->StaCfg.GroupCipher = Ndis802_11EncryptionDisabled; - pAd->StaCfg.bMixCipher = FALSE; - pAd->StaCfg.DefaultKeyId = 0; - - // 802.1x port control - pAd->StaCfg.PrivacyFilter = Ndis802_11PrivFilter8021xWEP; - pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; - pAd->StaCfg.LastMicErrorTime = 0; - pAd->StaCfg.MicErrCnt = 0; - pAd->StaCfg.bBlockAssoc = FALSE; - pAd->StaCfg.WpaState = SS_NOTUSE; - - pAd->CommonCfg.NdisRadioStateOff = FALSE; // New to support microsoft disable radio with OID command - - pAd->StaCfg.RssiTrigger = 0; - NdisZeroMemory(&pAd->StaCfg.RssiSample, sizeof(RSSI_SAMPLE)); - pAd->StaCfg.RssiTriggerMode = RSSI_TRIGGERED_UPON_BELOW_THRESHOLD; - pAd->StaCfg.AtimWin = 0; - pAd->StaCfg.DefaultListenCount = 3;//default listen count; - pAd->StaCfg.BssType = BSS_INFRA; // BSS_INFRA or BSS_ADHOC or BSS_MONITOR - pAd->StaCfg.bScanReqIsFromWebUI = FALSE; - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE); - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_WAKEUP_NOW); - - pAd->StaCfg.bAutoTxRateSwitch = TRUE; - pAd->StaCfg.DesiredTransmitSetting.field.MCS = MCS_AUTO; - } - -#ifdef EXT_BUILD_CHANNEL_LIST - pAd->StaCfg.IEEE80211dClientMode = Rt802_11_D_None; -#endif // EXT_BUILD_CHANNEL_LIST // -#endif // CONFIG_STA_SUPPORT // - - // global variables mXXXX used in MAC protocol state machines - OPSTATUS_SET_FLAG(pAd, fOP_STATUS_RECEIVE_DTIM); - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_ADHOC_ON); - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_INFRA_ON); - - // PHY specification - pAd->CommonCfg.PhyMode = PHY_11BG_MIXED; // default PHY mode - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED); // CCK use LONG preamble - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - // user desired power mode - pAd->StaCfg.WindowsPowerMode = Ndis802_11PowerModeCAM; - pAd->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeCAM; - pAd->StaCfg.bWindowsACCAMEnable = FALSE; - -#ifdef LEAP_SUPPORT - // CCX v1.0 releated init value - RTMPInitTimer(pAd, &pAd->StaCfg.LeapAuthTimer, GET_TIMER_FUNCTION(LeapAuthTimeout), pAd, FALSE); - pAd->StaCfg.LeapAuthMode = CISCO_AuthModeLEAPNone; - pAd->StaCfg.bCkipOn = FALSE; -#endif // LEAP_SUPPORT // - - RTMPInitTimer(pAd, &pAd->StaCfg.StaQuickResponeForRateUpTimer, GET_TIMER_FUNCTION(StaQuickResponeForRateUpExec), pAd, FALSE); - pAd->StaCfg.StaQuickResponeForRateUpTimerRunning = FALSE; - - // Patch for Ndtest - pAd->StaCfg.ScanCnt = 0; - - // CCX 2.0 control flag init - pAd->StaCfg.CCXEnable = FALSE; - pAd->StaCfg.CCXReqType = MSRN_TYPE_UNUSED; - pAd->StaCfg.CCXQosECWMin = 4; - pAd->StaCfg.CCXQosECWMax = 10; - - pAd->StaCfg.bHwRadio = TRUE; // Default Hardware Radio status is On - pAd->StaCfg.bSwRadio = TRUE; // Default Software Radio status is On - pAd->StaCfg.bRadio = TRUE; // bHwRadio && bSwRadio - pAd->StaCfg.bHardwareRadio = FALSE; // Default is OFF - pAd->StaCfg.bShowHiddenSSID = FALSE; // Default no show - - // Nitro mode control - pAd->StaCfg.bAutoReconnect = TRUE; - - // Save the init time as last scan time, the system should do scan after 2 seconds. - // This patch is for driver wake up from standby mode, system will do scan right away. - pAd->StaCfg.LastScanTime = 0; - NdisZeroMemory(pAd->nickname, IW_ESSID_MAX_SIZE+1); - sprintf(pAd->nickname, "%s", STA_NIC_DEVICE_NAME); - RTMPInitTimer(pAd, &pAd->StaCfg.WpaDisassocAndBlockAssocTimer, GET_TIMER_FUNCTION(WpaDisassocApAndBlockAssoc), pAd, FALSE); -#ifdef WPA_SUPPLICANT_SUPPORT - pAd->StaCfg.IEEE8021X = FALSE; - pAd->StaCfg.IEEE8021x_required_keys = FALSE; - pAd->StaCfg.WpaSupplicantUP = WPA_SUPPLICANT_DISABLE; -#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT - pAd->StaCfg.WpaSupplicantUP = WPA_SUPPLICANT_ENABLE; -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // -#endif // WPA_SUPPLICANT_SUPPORT // - - } -#endif // CONFIG_STA_SUPPORT // - - // Default for extra information is not valid - pAd->ExtraInfo = EXTRA_INFO_CLEAR; - - // Default Config change flag - pAd->bConfigChanged = FALSE; - - // - // part III. AP configurations - // - - - // - // part IV. others - // - // dynamic BBP R66:sensibity tuning to overcome background noise - pAd->BbpTuning.bEnable = TRUE; - pAd->BbpTuning.FalseCcaLowerThreshold = 100; - pAd->BbpTuning.FalseCcaUpperThreshold = 512; - pAd->BbpTuning.R66Delta = 4; - pAd->Mlme.bEnableAutoAntennaCheck = TRUE; - - // - // Also initial R66CurrentValue, RTUSBResumeMsduTransmission might use this value. - // if not initial this value, the default value will be 0. - // - pAd->BbpTuning.R66CurrentValue = 0x38; - - pAd->Bbp94 = BBPR94_DEFAULT; - pAd->BbpForCCK = FALSE; - - // Default is FALSE for test bit 1 - //pAd->bTest1 = FALSE; - - // initialize MAC table and allocate spin lock - NdisZeroMemory(&pAd->MacTab, sizeof(MAC_TABLE)); - InitializeQueueHeader(&pAd->MacTab.McastPsQueue); - NdisAllocateSpinLock(&pAd->MacTabLock); - - //RTMPInitTimer(pAd, &pAd->RECBATimer, RECBATimerTimeout, pAd, TRUE); - //RTMPSetTimer(&pAd->RECBATimer, REORDER_EXEC_INTV); - -#ifdef RALINK_ATE - NdisZeroMemory(&pAd->ate, sizeof(ATE_INFO)); - pAd->ate.Mode = ATE_STOP; - pAd->ate.TxCount = 200;/* to exceed TX_RING_SIZE ... */ - pAd->ate.TxLength = 1024; - pAd->ate.TxWI.ShortGI = 0;// LONG GI : 800 ns - pAd->ate.TxWI.PHYMODE = MODE_CCK; - pAd->ate.TxWI.MCS = 3; - pAd->ate.TxWI.BW = BW_20; - pAd->ate.Channel = 1; - pAd->ate.QID = QID_AC_BE; - pAd->ate.Addr1[0] = 0x00; - pAd->ate.Addr1[1] = 0x11; - pAd->ate.Addr1[2] = 0x22; - pAd->ate.Addr1[3] = 0xAA; - pAd->ate.Addr1[4] = 0xBB; - pAd->ate.Addr1[5] = 0xCC; - NdisMoveMemory(pAd->ate.Addr2, pAd->ate.Addr1, ETH_LENGTH_OF_ADDRESS); - NdisMoveMemory(pAd->ate.Addr3, pAd->ate.Addr1, ETH_LENGTH_OF_ADDRESS); - pAd->ate.bRxFer = 0; - pAd->ate.bQATxStart = FALSE; - pAd->ate.bQARxStart = FALSE; -#ifdef RALINK_28xx_QA - //pAd->ate.Repeat = 0; - pAd->ate.TxStatus = 0; - pAd->ate.AtePid = NULL; -#endif // RALINK_28xx_QA // -#endif // RALINK_ATE // - - - pAd->CommonCfg.bWiFiTest = FALSE; - - - DBGPRINT(RT_DEBUG_TRACE, ("<-- UserCfgInit\n")); -} - -// IRQL = PASSIVE_LEVEL -UCHAR BtoH(char ch) -{ - if (ch >= '0' && ch <= '9') return (ch - '0'); // Handle numerals - if (ch >= 'A' && ch <= 'F') return (ch - 'A' + 0xA); // Handle capitol hex digits - if (ch >= 'a' && ch <= 'f') return (ch - 'a' + 0xA); // Handle small hex digits - return(255); -} - -// -// FUNCTION: AtoH(char *, UCHAR *, int) -// -// PURPOSE: Converts ascii string to network order hex -// -// PARAMETERS: -// src - pointer to input ascii string -// dest - pointer to output hex -// destlen - size of dest -// -// COMMENTS: -// -// 2 ascii bytes make a hex byte so must put 1st ascii byte of pair -// into upper nibble and 2nd ascii byte of pair into lower nibble. -// -// IRQL = PASSIVE_LEVEL - -void AtoH(char * src, UCHAR * dest, int destlen) -{ - char * srcptr; - PUCHAR destTemp; - - srcptr = src; - destTemp = (PUCHAR) dest; - - while(destlen--) - { - *destTemp = BtoH(*srcptr++) << 4; // Put 1st ascii byte in upper nibble. - *destTemp += BtoH(*srcptr++); // Add 2nd ascii byte to above. - destTemp++; - } -} - -VOID RTMPPatchMacBbpBug( - IN PRTMP_ADAPTER pAd) -{ - ULONG Index; - - // Initialize BBP register to default value - for (Index = 0; Index < NUM_BBP_REG_PARMS; Index++) - { - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBPRegTable[Index].Register, (UCHAR)BBPRegTable[Index].Value); - } - - // Initialize RF register to default value - AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); - AsicLockChannel(pAd, pAd->CommonCfg.Channel); - - // Re-init BBP register from EEPROM value - NICInitAsicFromEEPROM(pAd); -} - -/* - ======================================================================== - - Routine Description: - Init timer objects - - Arguments: - pAd Pointer to our adapter - pTimer Timer structure - pTimerFunc Function to execute when timer expired - Repeat Ture for period timer - - Return Value: - None - - Note: - - ======================================================================== -*/ -VOID RTMPInitTimer( - IN PRTMP_ADAPTER pAd, - IN PRALINK_TIMER_STRUCT pTimer, - IN PVOID pTimerFunc, - IN PVOID pData, - IN BOOLEAN Repeat) -{ - // - // Set Valid to TRUE for later used. - // It will crash if we cancel a timer or set a timer - // that we haven't initialize before. - // - pTimer->Valid = TRUE; - - pTimer->PeriodicType = Repeat; - pTimer->State = FALSE; - pTimer->cookie = (ULONG) pData; - -#ifdef RT2870 - pTimer->pAd = pAd; -#endif // RT2870 // - - RTMP_OS_Init_Timer(pAd, &pTimer->TimerObj, pTimerFunc, (PVOID) pTimer); -} - -/* - ======================================================================== - - Routine Description: - Init timer objects - - Arguments: - pTimer Timer structure - Value Timer value in milliseconds - - Return Value: - None - - Note: - To use this routine, must call RTMPInitTimer before. - - ======================================================================== -*/ -VOID RTMPSetTimer( - IN PRALINK_TIMER_STRUCT pTimer, - IN ULONG Value) -{ - if (pTimer->Valid) - { - pTimer->TimerValue = Value; - pTimer->State = FALSE; - if (pTimer->PeriodicType == TRUE) - { - pTimer->Repeat = TRUE; - RTMP_SetPeriodicTimer(&pTimer->TimerObj, Value); - } - else - { - pTimer->Repeat = FALSE; - RTMP_OS_Add_Timer(&pTimer->TimerObj, Value); - } - } - else - { - DBGPRINT_ERR(("RTMPSetTimer failed, Timer hasn't been initialize!\n")); - } -} - - -/* - ======================================================================== - - Routine Description: - Init timer objects - - Arguments: - pTimer Timer structure - Value Timer value in milliseconds - - Return Value: - None - - Note: - To use this routine, must call RTMPInitTimer before. - - ======================================================================== -*/ -VOID RTMPModTimer( - IN PRALINK_TIMER_STRUCT pTimer, - IN ULONG Value) -{ - BOOLEAN Cancel; - - if (pTimer->Valid) - { - pTimer->TimerValue = Value; - pTimer->State = FALSE; - if (pTimer->PeriodicType == TRUE) - { - RTMPCancelTimer(pTimer, &Cancel); - RTMPSetTimer(pTimer, Value); - } - else - { - RTMP_OS_Mod_Timer(&pTimer->TimerObj, Value); - } - } - else - { - DBGPRINT_ERR(("RTMPModTimer failed, Timer hasn't been initialize!\n")); - } -} - -/* - ======================================================================== - - Routine Description: - Cancel timer objects - - Arguments: - Adapter Pointer to our adapter - - Return Value: - None - - IRQL = PASSIVE_LEVEL - IRQL = DISPATCH_LEVEL - - Note: - 1.) To use this routine, must call RTMPInitTimer before. - 2.) Reset NIC to initial state AS IS system boot up time. - - ======================================================================== -*/ -VOID RTMPCancelTimer( - IN PRALINK_TIMER_STRUCT pTimer, - OUT BOOLEAN *pCancelled) -{ - if (pTimer->Valid) - { - if (pTimer->State == FALSE) - pTimer->Repeat = FALSE; - RTMP_OS_Del_Timer(&pTimer->TimerObj, pCancelled); - - if (*pCancelled == TRUE) - pTimer->State = TRUE; - -#ifdef RT2870 - // We need to go-through the TimerQ to findout this timer handler and remove it if - // it's still waiting for execution. - - RT2870_TimerQ_Remove(pTimer->pAd, pTimer); -#endif // RT2870 // - } - else - { - // - // NdisMCancelTimer just canced the timer and not mean release the timer. - // And don't set the "Valid" to False. So that we can use this timer again. - // - DBGPRINT_ERR(("RTMPCancelTimer failed, Timer hasn't been initialize!\n")); - } -} - -/* - ======================================================================== - - Routine Description: - Set LED Status - - Arguments: - pAd Pointer to our adapter - Status LED Status - - Return Value: - None - - IRQL = PASSIVE_LEVEL - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -VOID RTMPSetLED( - IN PRTMP_ADAPTER pAd, - IN UCHAR Status) -{ - //ULONG data; - UCHAR HighByte = 0; - UCHAR LowByte; - -// In ATE mode of RT2860 AP/STA, we have erased 8051 firmware. -// So LED mode is not supported when ATE is running. -#ifdef RALINK_ATE - if (ATE_ON(pAd)) - return; -#endif // RALINK_ATE // - - LowByte = pAd->LedCntl.field.LedMode&0x7f; - switch (Status) - { - case LED_LINK_DOWN: - HighByte = 0x20; - AsicSendCommandToMcu(pAd, 0x50, 0xff, LowByte, HighByte); - pAd->LedIndicatorStregth = 0; - break; - case LED_LINK_UP: - if (pAd->CommonCfg.Channel > 14) - HighByte = 0xa0; - else - HighByte = 0x60; - AsicSendCommandToMcu(pAd, 0x50, 0xff, LowByte, HighByte); - break; - case LED_RADIO_ON: - HighByte = 0x20; - AsicSendCommandToMcu(pAd, 0x50, 0xff, LowByte, HighByte); - break; - case LED_HALT: - LowByte = 0; // Driver sets MAC register and MAC controls LED - case LED_RADIO_OFF: - HighByte = 0; - AsicSendCommandToMcu(pAd, 0x50, 0xff, LowByte, HighByte); - break; - case LED_WPS: - HighByte = 0x10; - AsicSendCommandToMcu(pAd, 0x50, 0xff, LowByte, HighByte); - break; - case LED_ON_SITE_SURVEY: - HighByte = 0x08; - AsicSendCommandToMcu(pAd, 0x50, 0xff, LowByte, HighByte); - break; - case LED_POWER_UP: - HighByte = 0x04; - AsicSendCommandToMcu(pAd, 0x50, 0xff, LowByte, HighByte); - break; - default: - DBGPRINT(RT_DEBUG_WARN, ("RTMPSetLED::Unknown Status %d\n", Status)); - break; - } - - // - // Keep LED status for LED SiteSurvey mode. - // After SiteSurvey, we will set the LED mode to previous status. - // - if ((Status != LED_ON_SITE_SURVEY) && (Status != LED_POWER_UP)) - pAd->LedStatus = Status; - - DBGPRINT(RT_DEBUG_TRACE, ("RTMPSetLED::Mode=%d,HighByte=0x%02x,LowByte=0x%02x\n", pAd->LedCntl.field.LedMode, HighByte, LowByte)); -} - -/* - ======================================================================== - - Routine Description: - Set LED Signal Stregth - - Arguments: - pAd Pointer to our adapter - Dbm Signal Stregth - - Return Value: - None - - IRQL = PASSIVE_LEVEL - - Note: - Can be run on any IRQL level. - - According to Microsoft Zero Config Wireless Signal Stregth definition as belows. - <= -90 No Signal - <= -81 Very Low - <= -71 Low - <= -67 Good - <= -57 Very Good - > -57 Excellent - ======================================================================== -*/ -VOID RTMPSetSignalLED( - IN PRTMP_ADAPTER pAd, - IN NDIS_802_11_RSSI Dbm) -{ - UCHAR nLed = 0; - - // - // if not Signal Stregth, then do nothing. - // - if (pAd->LedCntl.field.LedMode != LED_MODE_SIGNAL_STREGTH) - { - return; - } - - if (Dbm <= -90) - nLed = 0; - else if (Dbm <= -81) - nLed = 1; - else if (Dbm <= -71) - nLed = 3; - else if (Dbm <= -67) - nLed = 7; - else if (Dbm <= -57) - nLed = 15; - else - nLed = 31; - - // - // Update Signal Stregth to firmware if changed. - // - if (pAd->LedIndicatorStregth != nLed) - { - AsicSendCommandToMcu(pAd, 0x51, 0xff, nLed, pAd->LedCntl.field.Polarity); - pAd->LedIndicatorStregth = nLed; - } -} - -/* - ======================================================================== - - Routine Description: - Enable RX - - Arguments: - pAd Pointer to our adapter - - Return Value: - None - - IRQL <= DISPATCH_LEVEL - - Note: - Before Enable RX, make sure you have enabled Interrupt. - ======================================================================== -*/ -VOID RTMPEnableRxTx( - IN PRTMP_ADAPTER pAd) -{ -// WPDMA_GLO_CFG_STRUC GloCfg; -// ULONG i = 0; - - DBGPRINT(RT_DEBUG_TRACE, ("==> RTMPEnableRxTx\n")); - -#if 0 - // Enable Rx DMA. - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x4); - do - { - RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word); - if ((GloCfg.field.TxDMABusy == 0) && (GloCfg.field.RxDMABusy == 0)) - break; - - DBGPRINT(RT_DEBUG_TRACE, ("==> DMABusy\n")); - RTMPusecDelay(1000); - i++; - }while ( i <200); - - RTMPusecDelay(50); - RT28XX_DMA_WRITE_INIT(GloCfg); - DBGPRINT(RT_DEBUG_TRACE, ("<== WRITE DMA offset 0x208 = 0x%x\n", GloCfg.word)); - RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, GloCfg.word); - - RT28XX_DMA_POST_WRITE(pAd); -#else - // Enable Rx DMA. - RT28XXDMAEnable(pAd); -#endif - - // enable RX of MAC block - if (pAd->OpMode == OPMODE_AP) - { - UINT32 rx_filter_flag = APNORMAL; - - - RTMP_IO_WRITE32(pAd, RX_FILTR_CFG, rx_filter_flag); // enable RX of DMA block - } - else - { - RTMP_IO_WRITE32(pAd, RX_FILTR_CFG, STANORMAL); // Staion not drop control frame will fail WiFi Certification. - } - - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0xc); - DBGPRINT(RT_DEBUG_TRACE, ("<== RTMPEnableRxTx\n")); -} - - +#include "../../rt2860/common/rtmp_init.c" diff --git a/drivers/staging/rt2870/common/rtmp_tkip.c b/drivers/staging/rt2870/common/rtmp_tkip.c index 2847409ff081..240bf67f521f 100644 --- a/drivers/staging/rt2870/common/rtmp_tkip.c +++ b/drivers/staging/rt2870/common/rtmp_tkip.c @@ -1,1613 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - rtmp_tkip.c - - Abstract: - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Paul Wu 02-25-02 Initial -*/ - -#include "../rt_config.h" - -// Rotation functions on 32 bit values -#define ROL32( A, n ) \ - ( ((A) << (n)) | ( ((A)>>(32-(n))) & ( (1UL << (n)) - 1 ) ) ) -#define ROR32( A, n ) ROL32( (A), 32-(n) ) - -UINT Tkip_Sbox_Lower[256] = -{ - 0xA5,0x84,0x99,0x8D,0x0D,0xBD,0xB1,0x54, - 0x50,0x03,0xA9,0x7D,0x19,0x62,0xE6,0x9A, - 0x45,0x9D,0x40,0x87,0x15,0xEB,0xC9,0x0B, - 0xEC,0x67,0xFD,0xEA,0xBF,0xF7,0x96,0x5B, - 0xC2,0x1C,0xAE,0x6A,0x5A,0x41,0x02,0x4F, - 0x5C,0xF4,0x34,0x08,0x93,0x73,0x53,0x3F, - 0x0C,0x52,0x65,0x5E,0x28,0xA1,0x0F,0xB5, - 0x09,0x36,0x9B,0x3D,0x26,0x69,0xCD,0x9F, - 0x1B,0x9E,0x74,0x2E,0x2D,0xB2,0xEE,0xFB, - 0xF6,0x4D,0x61,0xCE,0x7B,0x3E,0x71,0x97, - 0xF5,0x68,0x00,0x2C,0x60,0x1F,0xC8,0xED, - 0xBE,0x46,0xD9,0x4B,0xDE,0xD4,0xE8,0x4A, - 0x6B,0x2A,0xE5,0x16,0xC5,0xD7,0x55,0x94, - 0xCF,0x10,0x06,0x81,0xF0,0x44,0xBA,0xE3, - 0xF3,0xFE,0xC0,0x8A,0xAD,0xBC,0x48,0x04, - 0xDF,0xC1,0x75,0x63,0x30,0x1A,0x0E,0x6D, - 0x4C,0x14,0x35,0x2F,0xE1,0xA2,0xCC,0x39, - 0x57,0xF2,0x82,0x47,0xAC,0xE7,0x2B,0x95, - 0xA0,0x98,0xD1,0x7F,0x66,0x7E,0xAB,0x83, - 0xCA,0x29,0xD3,0x3C,0x79,0xE2,0x1D,0x76, - 0x3B,0x56,0x4E,0x1E,0xDB,0x0A,0x6C,0xE4, - 0x5D,0x6E,0xEF,0xA6,0xA8,0xA4,0x37,0x8B, - 0x32,0x43,0x59,0xB7,0x8C,0x64,0xD2,0xE0, - 0xB4,0xFA,0x07,0x25,0xAF,0x8E,0xE9,0x18, - 0xD5,0x88,0x6F,0x72,0x24,0xF1,0xC7,0x51, - 0x23,0x7C,0x9C,0x21,0xDD,0xDC,0x86,0x85, - 0x90,0x42,0xC4,0xAA,0xD8,0x05,0x01,0x12, - 0xA3,0x5F,0xF9,0xD0,0x91,0x58,0x27,0xB9, - 0x38,0x13,0xB3,0x33,0xBB,0x70,0x89,0xA7, - 0xB6,0x22,0x92,0x20,0x49,0xFF,0x78,0x7A, - 0x8F,0xF8,0x80,0x17,0xDA,0x31,0xC6,0xB8, - 0xC3,0xB0,0x77,0x11,0xCB,0xFC,0xD6,0x3A -}; - -UINT Tkip_Sbox_Upper[256] = -{ - 0xC6,0xF8,0xEE,0xF6,0xFF,0xD6,0xDE,0x91, - 0x60,0x02,0xCE,0x56,0xE7,0xB5,0x4D,0xEC, - 0x8F,0x1F,0x89,0xFA,0xEF,0xB2,0x8E,0xFB, - 0x41,0xB3,0x5F,0x45,0x23,0x53,0xE4,0x9B, - 0x75,0xE1,0x3D,0x4C,0x6C,0x7E,0xF5,0x83, - 0x68,0x51,0xD1,0xF9,0xE2,0xAB,0x62,0x2A, - 0x08,0x95,0x46,0x9D,0x30,0x37,0x0A,0x2F, - 0x0E,0x24,0x1B,0xDF,0xCD,0x4E,0x7F,0xEA, - 0x12,0x1D,0x58,0x34,0x36,0xDC,0xB4,0x5B, - 0xA4,0x76,0xB7,0x7D,0x52,0xDD,0x5E,0x13, - 0xA6,0xB9,0x00,0xC1,0x40,0xE3,0x79,0xB6, - 0xD4,0x8D,0x67,0x72,0x94,0x98,0xB0,0x85, - 0xBB,0xC5,0x4F,0xED,0x86,0x9A,0x66,0x11, - 0x8A,0xE9,0x04,0xFE,0xA0,0x78,0x25,0x4B, - 0xA2,0x5D,0x80,0x05,0x3F,0x21,0x70,0xF1, - 0x63,0x77,0xAF,0x42,0x20,0xE5,0xFD,0xBF, - 0x81,0x18,0x26,0xC3,0xBE,0x35,0x88,0x2E, - 0x93,0x55,0xFC,0x7A,0xC8,0xBA,0x32,0xE6, - 0xC0,0x19,0x9E,0xA3,0x44,0x54,0x3B,0x0B, - 0x8C,0xC7,0x6B,0x28,0xA7,0xBC,0x16,0xAD, - 0xDB,0x64,0x74,0x14,0x92,0x0C,0x48,0xB8, - 0x9F,0xBD,0x43,0xC4,0x39,0x31,0xD3,0xF2, - 0xD5,0x8B,0x6E,0xDA,0x01,0xB1,0x9C,0x49, - 0xD8,0xAC,0xF3,0xCF,0xCA,0xF4,0x47,0x10, - 0x6F,0xF0,0x4A,0x5C,0x38,0x57,0x73,0x97, - 0xCB,0xA1,0xE8,0x3E,0x96,0x61,0x0D,0x0F, - 0xE0,0x7C,0x71,0xCC,0x90,0x06,0xF7,0x1C, - 0xC2,0x6A,0xAE,0x69,0x17,0x99,0x3A,0x27, - 0xD9,0xEB,0x2B,0x22,0xD2,0xA9,0x07,0x33, - 0x2D,0x3C,0x15,0xC9,0x87,0xAA,0x50,0xA5, - 0x03,0x59,0x09,0x1A,0x65,0xD7,0x84,0xD0, - 0x82,0x29,0x5A,0x1E,0x7B,0xA8,0x6D,0x2C -}; - -/*****************************/ -/******** SBOX Table *********/ -/*****************************/ - -UCHAR SboxTable[256] = -{ - 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, - 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, - 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, - 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, - 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, - 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, - 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, - 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, - 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, - 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, - 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, - 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, - 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, - 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, - 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, - 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, - 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, - 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, - 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, - 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, - 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, - 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, - 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, - 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, - 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, - 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, - 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, - 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, - 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, - 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, - 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, - 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 -}; - -VOID xor_32( - IN PUCHAR a, - IN PUCHAR b, - OUT PUCHAR out); - -VOID xor_128( - IN PUCHAR a, - IN PUCHAR b, - OUT PUCHAR out); - -VOID next_key( - IN PUCHAR key, - IN INT round); - -VOID byte_sub( - IN PUCHAR in, - OUT PUCHAR out); - -VOID shift_row( - IN PUCHAR in, - OUT PUCHAR out); - -VOID mix_column( - IN PUCHAR in, - OUT PUCHAR out); - -UCHAR RTMPCkipSbox( - IN UCHAR a); -// -// Expanded IV for TKIP function. -// -typedef struct PACKED _IV_CONTROL_ -{ - union PACKED - { - struct PACKED - { - UCHAR rc0; - UCHAR rc1; - UCHAR rc2; - - union PACKED - { - struct PACKED - { -#ifdef RT_BIG_ENDIAN - UCHAR KeyID:2; - UCHAR ExtIV:1; - UCHAR Rsvd:5; -#else - UCHAR Rsvd:5; - UCHAR ExtIV:1; - UCHAR KeyID:2; -#endif - } field; - UCHAR Byte; - } CONTROL; - } field; - - ULONG word; - } IV16; - - ULONG IV32; -} TKIP_IV, *PTKIP_IV; - - -/* - ======================================================================== - - Routine Description: - Convert from UCHAR[] to ULONG in a portable way - - Arguments: - pMICKey pointer to MIC Key - - Return Value: - None - - Note: - - ======================================================================== -*/ -ULONG RTMPTkipGetUInt32( - IN PUCHAR pMICKey) -{ - ULONG res = 0; - INT i; - - for (i = 0; i < 4; i++) - { - res |= (*pMICKey++) << (8 * i); - } - - return res; -} - -/* - ======================================================================== - - Routine Description: - Convert from ULONG to UCHAR[] in a portable way - - Arguments: - pDst pointer to destination for convert ULONG to UCHAR[] - val the value for convert - - Return Value: - None - - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -VOID RTMPTkipPutUInt32( - IN OUT PUCHAR pDst, - IN ULONG val) -{ - INT i; - - for(i = 0; i < 4; i++) - { - *pDst++ = (UCHAR) (val & 0xff); - val >>= 8; - } -} - -/* - ======================================================================== - - Routine Description: - Set the MIC Key. - - Arguments: - pAd Pointer to our adapter - pMICKey pointer to MIC Key - - Return Value: - None - - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -VOID RTMPTkipSetMICKey( - IN PTKIP_KEY_INFO pTkip, - IN PUCHAR pMICKey) -{ - // Set the key - pTkip->K0 = RTMPTkipGetUInt32(pMICKey); - pTkip->K1 = RTMPTkipGetUInt32(pMICKey + 4); - // and reset the message - pTkip->L = pTkip->K0; - pTkip->R = pTkip->K1; - pTkip->nBytesInM = 0; - pTkip->M = 0; -} - -/* - ======================================================================== - - Routine Description: - Calculate the MIC Value. - - Arguments: - pAd Pointer to our adapter - uChar Append this uChar - - Return Value: - None - - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -VOID RTMPTkipAppendByte( - IN PTKIP_KEY_INFO pTkip, - IN UCHAR uChar) -{ - // Append the byte to our word-sized buffer - pTkip->M |= (uChar << (8* pTkip->nBytesInM)); - pTkip->nBytesInM++; - // Process the word if it is full. - if( pTkip->nBytesInM >= 4 ) - { - pTkip->L ^= pTkip->M; - pTkip->R ^= ROL32( pTkip->L, 17 ); - pTkip->L += pTkip->R; - pTkip->R ^= ((pTkip->L & 0xff00ff00) >> 8) | ((pTkip->L & 0x00ff00ff) << 8); - pTkip->L += pTkip->R; - pTkip->R ^= ROL32( pTkip->L, 3 ); - pTkip->L += pTkip->R; - pTkip->R ^= ROR32( pTkip->L, 2 ); - pTkip->L += pTkip->R; - // Clear the buffer - pTkip->M = 0; - pTkip->nBytesInM = 0; - } -} - -/* - ======================================================================== - - Routine Description: - Calculate the MIC Value. - - Arguments: - pAd Pointer to our adapter - pSrc Pointer to source data for Calculate MIC Value - Len Indicate the length of the source data - - Return Value: - None - - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -VOID RTMPTkipAppend( - IN PTKIP_KEY_INFO pTkip, - IN PUCHAR pSrc, - IN UINT nBytes) -{ - // This is simple - while(nBytes > 0) - { - RTMPTkipAppendByte(pTkip, *pSrc++); - nBytes--; - } -} - -/* - ======================================================================== - - Routine Description: - Get the MIC Value. - - Arguments: - pAd Pointer to our adapter - - Return Value: - None - - IRQL = DISPATCH_LEVEL - - Note: - the MIC Value is store in pAd->PrivateInfo.MIC - ======================================================================== -*/ -VOID RTMPTkipGetMIC( - IN PTKIP_KEY_INFO pTkip) -{ - // Append the minimum padding - RTMPTkipAppendByte(pTkip, 0x5a ); - RTMPTkipAppendByte(pTkip, 0 ); - RTMPTkipAppendByte(pTkip, 0 ); - RTMPTkipAppendByte(pTkip, 0 ); - RTMPTkipAppendByte(pTkip, 0 ); - // and then zeroes until the length is a multiple of 4 - while( pTkip->nBytesInM != 0 ) - { - RTMPTkipAppendByte(pTkip, 0 ); - } - // The appendByte function has already computed the result. - RTMPTkipPutUInt32(pTkip->MIC, pTkip->L); - RTMPTkipPutUInt32(pTkip->MIC + 4, pTkip->R); -} - -/* - ======================================================================== - - Routine Description: - Init Tkip function. - - Arguments: - pAd Pointer to our adapter - pTKey Pointer to the Temporal Key (TK), TK shall be 128bits. - KeyId TK Key ID - pTA Pointer to transmitter address - pMICKey pointer to MIC Key - - Return Value: - None - - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -VOID RTMPInitTkipEngine( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pKey, - IN UCHAR KeyId, - IN PUCHAR pTA, - IN PUCHAR pMICKey, - IN PUCHAR pTSC, - OUT PULONG pIV16, - OUT PULONG pIV32) -{ - TKIP_IV tkipIv; - - // Prepare 8 bytes TKIP encapsulation for MPDU - NdisZeroMemory(&tkipIv, sizeof(TKIP_IV)); - tkipIv.IV16.field.rc0 = *(pTSC + 1); - tkipIv.IV16.field.rc1 = (tkipIv.IV16.field.rc0 | 0x20) & 0x7f; - tkipIv.IV16.field.rc2 = *pTSC; - tkipIv.IV16.field.CONTROL.field.ExtIV = 1; // 0: non-extended IV, 1: an extended IV - tkipIv.IV16.field.CONTROL.field.KeyID = KeyId; -// tkipIv.IV32 = *(PULONG)(pTSC + 2); - NdisMoveMemory(&tkipIv.IV32, (pTSC + 2), 4); // Copy IV - - *pIV16 = tkipIv.IV16.word; - *pIV32 = tkipIv.IV32; -} - -/* - ======================================================================== - - Routine Description: - Init MIC Value calculation function which include set MIC key & - calculate first 16 bytes (DA + SA + priority + 0) - - Arguments: - pAd Pointer to our adapter - pTKey Pointer to the Temporal Key (TK), TK shall be 128bits. - pDA Pointer to DA address - pSA Pointer to SA address - pMICKey pointer to MIC Key - - Return Value: - None - - Note: - - ======================================================================== -*/ -VOID RTMPInitMICEngine( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pKey, - IN PUCHAR pDA, - IN PUCHAR pSA, - IN UCHAR UserPriority, - IN PUCHAR pMICKey) -{ - ULONG Priority = UserPriority; - - // Init MIC value calculation - RTMPTkipSetMICKey(&pAd->PrivateInfo.Tx, pMICKey); - // DA - RTMPTkipAppend(&pAd->PrivateInfo.Tx, pDA, MAC_ADDR_LEN); - // SA - RTMPTkipAppend(&pAd->PrivateInfo.Tx, pSA, MAC_ADDR_LEN); - // Priority + 3 bytes of 0 - RTMPTkipAppend(&pAd->PrivateInfo.Tx, (PUCHAR)&Priority, 4); -} - -/* - ======================================================================== - - Routine Description: - Compare MIC value of received MSDU - - Arguments: - pAd Pointer to our adapter - pSrc Pointer to the received Plain text data - pDA Pointer to DA address - pSA Pointer to SA address - pMICKey pointer to MIC Key - Len the length of the received plain text data exclude MIC value - - Return Value: - TRUE MIC value matched - FALSE MIC value mismatched - - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -BOOLEAN RTMPTkipCompareMICValue( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pSrc, - IN PUCHAR pDA, - IN PUCHAR pSA, - IN PUCHAR pMICKey, - IN UCHAR UserPriority, - IN UINT Len) -{ - UCHAR OldMic[8]; - ULONG Priority = UserPriority; - - // Init MIC value calculation - RTMPTkipSetMICKey(&pAd->PrivateInfo.Rx, pMICKey); - // DA - RTMPTkipAppend(&pAd->PrivateInfo.Rx, pDA, MAC_ADDR_LEN); - // SA - RTMPTkipAppend(&pAd->PrivateInfo.Rx, pSA, MAC_ADDR_LEN); - // Priority + 3 bytes of 0 - RTMPTkipAppend(&pAd->PrivateInfo.Rx, (PUCHAR)&Priority, 4); - - // Calculate MIC value from plain text data - RTMPTkipAppend(&pAd->PrivateInfo.Rx, pSrc, Len); - - // Get MIC valude from received frame - NdisMoveMemory(OldMic, pSrc + Len, 8); - - // Get MIC value from decrypted plain data - RTMPTkipGetMIC(&pAd->PrivateInfo.Rx); - - // Move MIC value from MSDU, this steps should move to data path. - // Since the MIC value might cross MPDUs. - if(!NdisEqualMemory(pAd->PrivateInfo.Rx.MIC, OldMic, 8)) - { - DBGPRINT_RAW(RT_DEBUG_ERROR, ("RTMPTkipCompareMICValue(): TKIP MIC Error !\n")); //MIC error. - - - return (FALSE); - } - return (TRUE); -} - -/* - ======================================================================== - - Routine Description: - Compare MIC value of received MSDU - - Arguments: - pAd Pointer to our adapter - pLLC LLC header - pSrc Pointer to the received Plain text data - pDA Pointer to DA address - pSA Pointer to SA address - pMICKey pointer to MIC Key - Len the length of the received plain text data exclude MIC value - - Return Value: - TRUE MIC value matched - FALSE MIC value mismatched - - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -BOOLEAN RTMPTkipCompareMICValueWithLLC( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pLLC, - IN PUCHAR pSrc, - IN PUCHAR pDA, - IN PUCHAR pSA, - IN PUCHAR pMICKey, - IN UINT Len) -{ - UCHAR OldMic[8]; - ULONG Priority = 0; - - // Init MIC value calculation - RTMPTkipSetMICKey(&pAd->PrivateInfo.Rx, pMICKey); - // DA - RTMPTkipAppend(&pAd->PrivateInfo.Rx, pDA, MAC_ADDR_LEN); - // SA - RTMPTkipAppend(&pAd->PrivateInfo.Rx, pSA, MAC_ADDR_LEN); - // Priority + 3 bytes of 0 - RTMPTkipAppend(&pAd->PrivateInfo.Rx, (PUCHAR)&Priority, 4); - - // Start with LLC header - RTMPTkipAppend(&pAd->PrivateInfo.Rx, pLLC, 8); - - // Calculate MIC value from plain text data - RTMPTkipAppend(&pAd->PrivateInfo.Rx, pSrc, Len); - - // Get MIC valude from received frame - NdisMoveMemory(OldMic, pSrc + Len, 8); - - // Get MIC value from decrypted plain data - RTMPTkipGetMIC(&pAd->PrivateInfo.Rx); - - // Move MIC value from MSDU, this steps should move to data path. - // Since the MIC value might cross MPDUs. - if(!NdisEqualMemory(pAd->PrivateInfo.Rx.MIC, OldMic, 8)) - { - DBGPRINT_RAW(RT_DEBUG_ERROR, ("RTMPTkipCompareMICValueWithLLC(): TKIP MIC Error !\n")); //MIC error. - - - return (FALSE); - } - return (TRUE); -} -/* - ======================================================================== - - Routine Description: - Copy frame from waiting queue into relative ring buffer and set - appropriate ASIC register to kick hardware transmit function - - Arguments: - pAd Pointer to our adapter - PNDIS_PACKET Pointer to Ndis Packet for MIC calculation - pEncap Pointer to LLC encap data - LenEncap Total encap length, might be 0 which indicates no encap - - Return Value: - None - - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -VOID RTMPCalculateMICValue( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket, - IN PUCHAR pEncap, - IN PCIPHER_KEY pKey, - IN UCHAR apidx) -{ - PACKET_INFO PacketInfo; - PUCHAR pSrcBufVA; - UINT SrcBufLen; - PUCHAR pSrc; - UCHAR UserPriority; - UCHAR vlan_offset = 0; - - RTMP_QueryPacketInfo(pPacket, &PacketInfo, &pSrcBufVA, &SrcBufLen); - - UserPriority = RTMP_GET_PACKET_UP(pPacket); - pSrc = pSrcBufVA; - - // determine if this is a vlan packet - if (((*(pSrc + 12) << 8) + *(pSrc + 13)) == 0x8100) - vlan_offset = 4; - -#ifdef CONFIG_STA_SUPPORT -#endif // CONFIG_STA_SUPPORT // - { - RTMPInitMICEngine( - pAd, - pKey->Key, - pSrc, - pSrc + 6, - UserPriority, - pKey->TxMic); - } - - - if (pEncap != NULL) - { - // LLC encapsulation - RTMPTkipAppend(&pAd->PrivateInfo.Tx, pEncap, 6); - // Protocol Type - RTMPTkipAppend(&pAd->PrivateInfo.Tx, pSrc + 12 + vlan_offset, 2); - } - SrcBufLen -= (14 + vlan_offset); - pSrc += (14 + vlan_offset); - do - { - if (SrcBufLen > 0) - { - RTMPTkipAppend(&pAd->PrivateInfo.Tx, pSrc, SrcBufLen); - } - - break; // No need handle next packet - - } while (TRUE); // End of copying payload - - // Compute the final MIC Value - RTMPTkipGetMIC(&pAd->PrivateInfo.Tx); -} - - -/************************************************************/ -/* tkip_sbox() */ -/* Returns a 16 bit value from a 64K entry table. The Table */ -/* is synthesized from two 256 entry byte wide tables. */ -/************************************************************/ - -UINT tkip_sbox(UINT index) -{ - UINT index_low; - UINT index_high; - UINT left, right; - - index_low = (index % 256); - index_high = ((index >> 8) % 256); - - left = Tkip_Sbox_Lower[index_low] + (Tkip_Sbox_Upper[index_low] * 256); - right = Tkip_Sbox_Upper[index_high] + (Tkip_Sbox_Lower[index_high] * 256); - - return (left ^ right); -} - -UINT rotr1(UINT a) -{ - unsigned int b; - - if ((a & 0x01) == 0x01) - { - b = (a >> 1) | 0x8000; - } - else - { - b = (a >> 1) & 0x7fff; - } - b = b % 65536; - return b; -} - -VOID RTMPTkipMixKey( - UCHAR *key, - UCHAR *ta, - ULONG pnl, /* Least significant 16 bits of PN */ - ULONG pnh, /* Most significant 32 bits of PN */ - UCHAR *rc4key, - UINT *p1k) -{ - - UINT tsc0; - UINT tsc1; - UINT tsc2; - - UINT ppk0; - UINT ppk1; - UINT ppk2; - UINT ppk3; - UINT ppk4; - UINT ppk5; - - INT i; - INT j; - - tsc0 = (unsigned int)((pnh >> 16) % 65536); /* msb */ - tsc1 = (unsigned int)(pnh % 65536); - tsc2 = (unsigned int)(pnl % 65536); /* lsb */ - - /* Phase 1, step 1 */ - p1k[0] = tsc1; - p1k[1] = tsc0; - p1k[2] = (UINT)(ta[0] + (ta[1]*256)); - p1k[3] = (UINT)(ta[2] + (ta[3]*256)); - p1k[4] = (UINT)(ta[4] + (ta[5]*256)); - - /* Phase 1, step 2 */ - for (i=0; i<8; i++) - { - j = 2*(i & 1); - p1k[0] = (p1k[0] + tkip_sbox( (p1k[4] ^ ((256*key[1+j]) + key[j])) % 65536 )) % 65536; - p1k[1] = (p1k[1] + tkip_sbox( (p1k[0] ^ ((256*key[5+j]) + key[4+j])) % 65536 )) % 65536; - p1k[2] = (p1k[2] + tkip_sbox( (p1k[1] ^ ((256*key[9+j]) + key[8+j])) % 65536 )) % 65536; - p1k[3] = (p1k[3] + tkip_sbox( (p1k[2] ^ ((256*key[13+j]) + key[12+j])) % 65536 )) % 65536; - p1k[4] = (p1k[4] + tkip_sbox( (p1k[3] ^ (((256*key[1+j]) + key[j]))) % 65536 )) % 65536; - p1k[4] = (p1k[4] + i) % 65536; - } - - /* Phase 2, Step 1 */ - ppk0 = p1k[0]; - ppk1 = p1k[1]; - ppk2 = p1k[2]; - ppk3 = p1k[3]; - ppk4 = p1k[4]; - ppk5 = (p1k[4] + tsc2) % 65536; - - /* Phase2, Step 2 */ - ppk0 = ppk0 + tkip_sbox( (ppk5 ^ ((256*key[1]) + key[0])) % 65536); - ppk1 = ppk1 + tkip_sbox( (ppk0 ^ ((256*key[3]) + key[2])) % 65536); - ppk2 = ppk2 + tkip_sbox( (ppk1 ^ ((256*key[5]) + key[4])) % 65536); - ppk3 = ppk3 + tkip_sbox( (ppk2 ^ ((256*key[7]) + key[6])) % 65536); - ppk4 = ppk4 + tkip_sbox( (ppk3 ^ ((256*key[9]) + key[8])) % 65536); - ppk5 = ppk5 + tkip_sbox( (ppk4 ^ ((256*key[11]) + key[10])) % 65536); - - ppk0 = ppk0 + rotr1(ppk5 ^ ((256*key[13]) + key[12])); - ppk1 = ppk1 + rotr1(ppk0 ^ ((256*key[15]) + key[14])); - ppk2 = ppk2 + rotr1(ppk1); - ppk3 = ppk3 + rotr1(ppk2); - ppk4 = ppk4 + rotr1(ppk3); - ppk5 = ppk5 + rotr1(ppk4); - - /* Phase 2, Step 3 */ - /* Phase 2, Step 3 */ - - tsc0 = (unsigned int)((pnh >> 16) % 65536); /* msb */ - tsc1 = (unsigned int)(pnh % 65536); - tsc2 = (unsigned int)(pnl % 65536); /* lsb */ - - rc4key[0] = (tsc2 >> 8) % 256; - rc4key[1] = (((tsc2 >> 8) % 256) | 0x20) & 0x7f; - rc4key[2] = tsc2 % 256; - rc4key[3] = ((ppk5 ^ ((256*key[1]) + key[0])) >> 1) % 256; - - rc4key[4] = ppk0 % 256; - rc4key[5] = (ppk0 >> 8) % 256; - - rc4key[6] = ppk1 % 256; - rc4key[7] = (ppk1 >> 8) % 256; - - rc4key[8] = ppk2 % 256; - rc4key[9] = (ppk2 >> 8) % 256; - - rc4key[10] = ppk3 % 256; - rc4key[11] = (ppk3 >> 8) % 256; - - rc4key[12] = ppk4 % 256; - rc4key[13] = (ppk4 >> 8) % 256; - - rc4key[14] = ppk5 % 256; - rc4key[15] = (ppk5 >> 8) % 256; -} - - -/************************************************/ -/* construct_mic_header1() */ -/* Builds the first MIC header block from */ -/* header fields. */ -/************************************************/ - -void construct_mic_header1( - unsigned char *mic_header1, - int header_length, - unsigned char *mpdu) -{ - mic_header1[0] = (unsigned char)((header_length - 2) / 256); - mic_header1[1] = (unsigned char)((header_length - 2) % 256); - mic_header1[2] = mpdu[0] & 0xcf; /* Mute CF poll & CF ack bits */ - mic_header1[3] = mpdu[1] & 0xc7; /* Mute retry, more data and pwr mgt bits */ - mic_header1[4] = mpdu[4]; /* A1 */ - mic_header1[5] = mpdu[5]; - mic_header1[6] = mpdu[6]; - mic_header1[7] = mpdu[7]; - mic_header1[8] = mpdu[8]; - mic_header1[9] = mpdu[9]; - mic_header1[10] = mpdu[10]; /* A2 */ - mic_header1[11] = mpdu[11]; - mic_header1[12] = mpdu[12]; - mic_header1[13] = mpdu[13]; - mic_header1[14] = mpdu[14]; - mic_header1[15] = mpdu[15]; -} - -/************************************************/ -/* construct_mic_header2() */ -/* Builds the last MIC header block from */ -/* header fields. */ -/************************************************/ - -void construct_mic_header2( - unsigned char *mic_header2, - unsigned char *mpdu, - int a4_exists, - int qc_exists) -{ - int i; - - for (i = 0; i<16; i++) mic_header2[i]=0x00; - - mic_header2[0] = mpdu[16]; /* A3 */ - mic_header2[1] = mpdu[17]; - mic_header2[2] = mpdu[18]; - mic_header2[3] = mpdu[19]; - mic_header2[4] = mpdu[20]; - mic_header2[5] = mpdu[21]; - - // In Sequence Control field, mute sequence numer bits (12-bit) - mic_header2[6] = mpdu[22] & 0x0f; /* SC */ - mic_header2[7] = 0x00; /* mpdu[23]; */ - - if ((!qc_exists) & a4_exists) - { - for (i=0;i<6;i++) mic_header2[8+i] = mpdu[24+i]; /* A4 */ - - } - - if (qc_exists && (!a4_exists)) - { - mic_header2[8] = mpdu[24] & 0x0f; /* mute bits 15 - 4 */ - mic_header2[9] = mpdu[25] & 0x00; - } - - if (qc_exists && a4_exists) - { - for (i=0;i<6;i++) mic_header2[8+i] = mpdu[24+i]; /* A4 */ - - mic_header2[14] = mpdu[30] & 0x0f; - mic_header2[15] = mpdu[31] & 0x00; - } -} - - -/************************************************/ -/* construct_mic_iv() */ -/* Builds the MIC IV from header fields and PN */ -/************************************************/ - -void construct_mic_iv( - unsigned char *mic_iv, - int qc_exists, - int a4_exists, - unsigned char *mpdu, - unsigned int payload_length, - unsigned char *pn_vector) -{ - int i; - - mic_iv[0] = 0x59; - if (qc_exists && a4_exists) - mic_iv[1] = mpdu[30] & 0x0f; /* QoS_TC */ - if (qc_exists && !a4_exists) - mic_iv[1] = mpdu[24] & 0x0f; /* mute bits 7-4 */ - if (!qc_exists) - mic_iv[1] = 0x00; - for (i = 2; i < 8; i++) - mic_iv[i] = mpdu[i + 8]; /* mic_iv[2:7] = A2[0:5] = mpdu[10:15] */ -#ifdef CONSISTENT_PN_ORDER - for (i = 8; i < 14; i++) - mic_iv[i] = pn_vector[i - 8]; /* mic_iv[8:13] = PN[0:5] */ -#else - for (i = 8; i < 14; i++) - mic_iv[i] = pn_vector[13 - i]; /* mic_iv[8:13] = PN[5:0] */ -#endif - i = (payload_length / 256); - i = (payload_length % 256); - mic_iv[14] = (unsigned char) (payload_length / 256); - mic_iv[15] = (unsigned char) (payload_length % 256); - -} - - - -/************************************/ -/* bitwise_xor() */ -/* A 128 bit, bitwise exclusive or */ -/************************************/ - -void bitwise_xor(unsigned char *ina, unsigned char *inb, unsigned char *out) -{ - int i; - for (i=0; i<16; i++) - { - out[i] = ina[i] ^ inb[i]; - } -} - - -void aes128k128d(unsigned char *key, unsigned char *data, unsigned char *ciphertext) -{ - int round; - int i; - unsigned char intermediatea[16]; - unsigned char intermediateb[16]; - unsigned char round_key[16]; - - for(i=0; i<16; i++) round_key[i] = key[i]; - - for (round = 0; round < 11; round++) - { - if (round == 0) - { - xor_128(round_key, data, ciphertext); - next_key(round_key, round); - } - else if (round == 10) - { - byte_sub(ciphertext, intermediatea); - shift_row(intermediatea, intermediateb); - xor_128(intermediateb, round_key, ciphertext); - } - else /* 1 - 9 */ - { - byte_sub(ciphertext, intermediatea); - shift_row(intermediatea, intermediateb); - mix_column(&intermediateb[0], &intermediatea[0]); - mix_column(&intermediateb[4], &intermediatea[4]); - mix_column(&intermediateb[8], &intermediatea[8]); - mix_column(&intermediateb[12], &intermediatea[12]); - xor_128(intermediatea, round_key, ciphertext); - next_key(round_key, round); - } - } - -} - -void construct_ctr_preload( - unsigned char *ctr_preload, - int a4_exists, - int qc_exists, - unsigned char *mpdu, - unsigned char *pn_vector, - int c) -{ - - int i = 0; - for (i=0; i<16; i++) ctr_preload[i] = 0x00; - i = 0; - - ctr_preload[0] = 0x01; /* flag */ - if (qc_exists && a4_exists) ctr_preload[1] = mpdu[30] & 0x0f; /* QoC_Control */ - if (qc_exists && !a4_exists) ctr_preload[1] = mpdu[24] & 0x0f; - - for (i = 2; i < 8; i++) - ctr_preload[i] = mpdu[i + 8]; /* ctr_preload[2:7] = A2[0:5] = mpdu[10:15] */ -#ifdef CONSISTENT_PN_ORDER - for (i = 8; i < 14; i++) - ctr_preload[i] = pn_vector[i - 8]; /* ctr_preload[8:13] = PN[0:5] */ -#else - for (i = 8; i < 14; i++) - ctr_preload[i] = pn_vector[13 - i]; /* ctr_preload[8:13] = PN[5:0] */ -#endif - ctr_preload[14] = (unsigned char) (c / 256); // Ctr - ctr_preload[15] = (unsigned char) (c % 256); - -} - - -// -// TRUE: Success! -// FALSE: Decrypt Error! -// -BOOLEAN RTMPSoftDecryptTKIP( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pData, - IN ULONG DataByteCnt, - IN UCHAR UserPriority, - IN PCIPHER_KEY pWpaKey) -{ - UCHAR KeyID; - UINT HeaderLen; - UCHAR fc0; - UCHAR fc1; - USHORT fc; - UINT frame_type; - UINT frame_subtype; - UINT from_ds; - UINT to_ds; - INT a4_exists; - INT qc_exists; - USHORT duration; - USHORT seq_control; - USHORT qos_control; - UCHAR TA[MAC_ADDR_LEN]; - UCHAR DA[MAC_ADDR_LEN]; - UCHAR SA[MAC_ADDR_LEN]; - UCHAR RC4Key[16]; - UINT p1k[5]; //for mix_key; - ULONG pnl;/* Least significant 16 bits of PN */ - ULONG pnh;/* Most significant 32 bits of PN */ - UINT num_blocks; - UINT payload_remainder; - ARCFOURCONTEXT ArcFourContext; - UINT crc32 = 0; - UINT trailfcs = 0; - UCHAR MIC[8]; - UCHAR TrailMIC[8]; - -#ifdef RT_BIG_ENDIAN - RTMPFrameEndianChange(pAd, (PUCHAR)pData, DIR_READ, FALSE); -#endif - - fc0 = *pData; - fc1 = *(pData + 1); - - fc = *((PUSHORT)pData); - - frame_type = ((fc0 >> 2) & 0x03); - frame_subtype = ((fc0 >> 4) & 0x0f); - - from_ds = (fc1 & 0x2) >> 1; - to_ds = (fc1 & 0x1); - - a4_exists = (from_ds & to_ds); - qc_exists = ((frame_subtype == 0x08) || /* Assumed QoS subtypes */ - (frame_subtype == 0x09) || /* Likely to change. */ - (frame_subtype == 0x0a) || - (frame_subtype == 0x0b) - ); - - HeaderLen = 24; - if (a4_exists) - HeaderLen += 6; - - KeyID = *((PUCHAR)(pData+ HeaderLen + 3)); - KeyID = KeyID >> 6; - - if (pWpaKey[KeyID].KeyLen == 0) - { - DBGPRINT(RT_DEBUG_TRACE, ("RTMPSoftDecryptTKIP failed!(KeyID[%d] Length can not be 0)\n", KeyID)); - return FALSE; - } - - duration = *((PUSHORT)(pData+2)); - - seq_control = *((PUSHORT)(pData+22)); - - if (qc_exists) - { - if (a4_exists) - { - qos_control = *((PUSHORT)(pData+30)); - } - else - { - qos_control = *((PUSHORT)(pData+24)); - } - } - - if (to_ds == 0 && from_ds == 1) - { - NdisMoveMemory(DA, pData+4, MAC_ADDR_LEN); - NdisMoveMemory(SA, pData+16, MAC_ADDR_LEN); - NdisMoveMemory(TA, pData+10, MAC_ADDR_LEN); //BSSID - } - else if (to_ds == 0 && from_ds == 0 ) - { - NdisMoveMemory(TA, pData+10, MAC_ADDR_LEN); - NdisMoveMemory(DA, pData+4, MAC_ADDR_LEN); - NdisMoveMemory(SA, pData+10, MAC_ADDR_LEN); - } - else if (to_ds == 1 && from_ds == 0) - { - NdisMoveMemory(SA, pData+10, MAC_ADDR_LEN); - NdisMoveMemory(TA, pData+10, MAC_ADDR_LEN); - NdisMoveMemory(DA, pData+16, MAC_ADDR_LEN); - } - else if (to_ds == 1 && from_ds == 1) - { - NdisMoveMemory(TA, pData+10, MAC_ADDR_LEN); - NdisMoveMemory(DA, pData+16, MAC_ADDR_LEN); - NdisMoveMemory(SA, pData+22, MAC_ADDR_LEN); - } - - num_blocks = (DataByteCnt - 16) / 16; - payload_remainder = (DataByteCnt - 16) % 16; - - pnl = (*(pData + HeaderLen)) * 256 + *(pData + HeaderLen + 2); - pnh = *((PULONG)(pData + HeaderLen + 4)); - pnh = cpu2le32(pnh); - RTMPTkipMixKey(pWpaKey[KeyID].Key, TA, pnl, pnh, RC4Key, p1k); - - ARCFOUR_INIT(&ArcFourContext, RC4Key, 16); - - ARCFOUR_DECRYPT(&ArcFourContext, pData + HeaderLen, pData + HeaderLen + 8, DataByteCnt - HeaderLen - 8); - NdisMoveMemory(&trailfcs, pData + DataByteCnt - 8 - 4, 4); - crc32 = RTMP_CALC_FCS32(PPPINITFCS32, pData + HeaderLen, DataByteCnt - HeaderLen - 8 - 4); //Skip IV+EIV 8 bytes & Skip last 4 bytes(FCS). - crc32 ^= 0xffffffff; /* complement */ - - if(crc32 != cpu2le32(trailfcs)) - { - DBGPRINT(RT_DEBUG_TRACE, ("RTMPSoftDecryptTKIP, WEP Data ICV Error !\n")); //ICV error. - - return (FALSE); - } - - NdisMoveMemory(TrailMIC, pData + DataByteCnt - 8 - 8 - 4, 8); - RTMPInitMICEngine(pAd, pWpaKey[KeyID].Key, DA, SA, UserPriority, pWpaKey[KeyID].RxMic); - RTMPTkipAppend(&pAd->PrivateInfo.Tx, pData + HeaderLen, DataByteCnt - HeaderLen - 8 - 12); - RTMPTkipGetMIC(&pAd->PrivateInfo.Tx); - NdisMoveMemory(MIC, pAd->PrivateInfo.Tx.MIC, 8); - - if (!NdisEqualMemory(MIC, TrailMIC, 8)) - { - DBGPRINT(RT_DEBUG_ERROR, ("RTMPSoftDecryptTKIP, WEP Data MIC Error !\n")); //MIC error. - //RTMPReportMicError(pAd, &pWpaKey[KeyID]); // marked by AlbertY @ 20060630 - return (FALSE); - } - -#ifdef RT_BIG_ENDIAN - RTMPFrameEndianChange(pAd, (PUCHAR)pData, DIR_READ, FALSE); -#endif - //DBGPRINT(RT_DEBUG_TRACE, "RTMPSoftDecryptTKIP Decript done!!\n"); - return TRUE; -} - - - - -BOOLEAN RTMPSoftDecryptAES( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pData, - IN ULONG DataByteCnt, - IN PCIPHER_KEY pWpaKey) -{ - UCHAR KeyID; - UINT HeaderLen; - UCHAR PN[6]; - UINT payload_len; - UINT num_blocks; - UINT payload_remainder; - USHORT fc; - UCHAR fc0; - UCHAR fc1; - UINT frame_type; - UINT frame_subtype; - UINT from_ds; - UINT to_ds; - INT a4_exists; - INT qc_exists; - UCHAR aes_out[16]; - int payload_index; - UINT i; - UCHAR ctr_preload[16]; - UCHAR chain_buffer[16]; - UCHAR padded_buffer[16]; - UCHAR mic_iv[16]; - UCHAR mic_header1[16]; - UCHAR mic_header2[16]; - UCHAR MIC[8]; - UCHAR TrailMIC[8]; - -#ifdef RT_BIG_ENDIAN - RTMPFrameEndianChange(pAd, (PUCHAR)pData, DIR_READ, FALSE); -#endif - - fc0 = *pData; - fc1 = *(pData + 1); - - fc = *((PUSHORT)pData); - - frame_type = ((fc0 >> 2) & 0x03); - frame_subtype = ((fc0 >> 4) & 0x0f); - - from_ds = (fc1 & 0x2) >> 1; - to_ds = (fc1 & 0x1); - - a4_exists = (from_ds & to_ds); - qc_exists = ((frame_subtype == 0x08) || /* Assumed QoS subtypes */ - (frame_subtype == 0x09) || /* Likely to change. */ - (frame_subtype == 0x0a) || - (frame_subtype == 0x0b) - ); - - HeaderLen = 24; - if (a4_exists) - HeaderLen += 6; - - KeyID = *((PUCHAR)(pData+ HeaderLen + 3)); - KeyID = KeyID >> 6; - - if (pWpaKey[KeyID].KeyLen == 0) - { - DBGPRINT(RT_DEBUG_TRACE, ("RTMPSoftDecryptAES failed!(KeyID[%d] Length can not be 0)\n", KeyID)); - return FALSE; - } - - PN[0] = *(pData+ HeaderLen); - PN[1] = *(pData+ HeaderLen + 1); - PN[2] = *(pData+ HeaderLen + 4); - PN[3] = *(pData+ HeaderLen + 5); - PN[4] = *(pData+ HeaderLen + 6); - PN[5] = *(pData+ HeaderLen + 7); - - payload_len = DataByteCnt - HeaderLen - 8 - 8; // 8 bytes for CCMP header , 8 bytes for MIC - payload_remainder = (payload_len) % 16; - num_blocks = (payload_len) / 16; - - - - // Find start of payload - payload_index = HeaderLen + 8; //IV+EIV - - for (i=0; i< num_blocks; i++) - { - construct_ctr_preload(ctr_preload, - a4_exists, - qc_exists, - pData, - PN, - i+1 ); - - aes128k128d(pWpaKey[KeyID].Key, ctr_preload, aes_out); - - bitwise_xor(aes_out, pData + payload_index, chain_buffer); - NdisMoveMemory(pData + payload_index - 8, chain_buffer, 16); - payload_index += 16; - } - - // - // If there is a short final block, then pad it - // encrypt it and copy the unpadded part back - // - if (payload_remainder > 0) - { - construct_ctr_preload(ctr_preload, - a4_exists, - qc_exists, - pData, - PN, - num_blocks + 1); - - NdisZeroMemory(padded_buffer, 16); - NdisMoveMemory(padded_buffer, pData + payload_index, payload_remainder); - - aes128k128d(pWpaKey[KeyID].Key, ctr_preload, aes_out); - - bitwise_xor(aes_out, padded_buffer, chain_buffer); - NdisMoveMemory(pData + payload_index - 8, chain_buffer, payload_remainder); - payload_index += payload_remainder; - } - - // - // Descrypt the MIC - // - construct_ctr_preload(ctr_preload, - a4_exists, - qc_exists, - pData, - PN, - 0); - NdisZeroMemory(padded_buffer, 16); - NdisMoveMemory(padded_buffer, pData + payload_index, 8); - - aes128k128d(pWpaKey[KeyID].Key, ctr_preload, aes_out); - - bitwise_xor(aes_out, padded_buffer, chain_buffer); - - NdisMoveMemory(TrailMIC, chain_buffer, 8); - - // - // Calculate MIC - // - - //Force the protected frame bit on - *(pData + 1) = *(pData + 1) | 0x40; - - // Find start of payload - // Because the CCMP header has been removed - payload_index = HeaderLen; - - construct_mic_iv( - mic_iv, - qc_exists, - a4_exists, - pData, - payload_len, - PN); - - construct_mic_header1( - mic_header1, - HeaderLen, - pData); - - construct_mic_header2( - mic_header2, - pData, - a4_exists, - qc_exists); - - aes128k128d(pWpaKey[KeyID].Key, mic_iv, aes_out); - bitwise_xor(aes_out, mic_header1, chain_buffer); - aes128k128d(pWpaKey[KeyID].Key, chain_buffer, aes_out); - bitwise_xor(aes_out, mic_header2, chain_buffer); - aes128k128d(pWpaKey[KeyID].Key, chain_buffer, aes_out); - - // iterate through each 16 byte payload block - for (i = 0; i < num_blocks; i++) - { - bitwise_xor(aes_out, pData + payload_index, chain_buffer); - payload_index += 16; - aes128k128d(pWpaKey[KeyID].Key, chain_buffer, aes_out); - } - - // Add on the final payload block if it needs padding - if (payload_remainder > 0) - { - NdisZeroMemory(padded_buffer, 16); - NdisMoveMemory(padded_buffer, pData + payload_index, payload_remainder); - - bitwise_xor(aes_out, padded_buffer, chain_buffer); - aes128k128d(pWpaKey[KeyID].Key, chain_buffer, aes_out); - } - - // aes_out contains padded mic, discard most significant - // 8 bytes to generate 64 bit MIC - for (i = 0 ; i < 8; i++) MIC[i] = aes_out[i]; - - if (!NdisEqualMemory(MIC, TrailMIC, 8)) - { - DBGPRINT(RT_DEBUG_ERROR, ("RTMPSoftDecryptAES, MIC Error !\n")); //MIC error. - return FALSE; - } - -#ifdef RT_BIG_ENDIAN - RTMPFrameEndianChange(pAd, (PUCHAR)pData, DIR_READ, FALSE); -#endif - - return TRUE; -} - -/****************************************/ -/* aes128k128d() */ -/* Performs a 128 bit AES encrypt with */ -/* 128 bit data. */ -/****************************************/ -VOID xor_128( - IN PUCHAR a, - IN PUCHAR b, - OUT PUCHAR out) -{ - INT i; - - for (i=0;i<16; i++) - { - out[i] = a[i] ^ b[i]; - } -} - -VOID next_key( - IN PUCHAR key, - IN INT round) -{ - UCHAR rcon; - UCHAR sbox_key[4]; - UCHAR rcon_table[12] = - { - 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, - 0x1b, 0x36, 0x36, 0x36 - }; - - sbox_key[0] = RTMPCkipSbox(key[13]); - sbox_key[1] = RTMPCkipSbox(key[14]); - sbox_key[2] = RTMPCkipSbox(key[15]); - sbox_key[3] = RTMPCkipSbox(key[12]); - - rcon = rcon_table[round]; - - xor_32(&key[0], sbox_key, &key[0]); - key[0] = key[0] ^ rcon; - - xor_32(&key[4], &key[0], &key[4]); - xor_32(&key[8], &key[4], &key[8]); - xor_32(&key[12], &key[8], &key[12]); -} - -VOID xor_32( - IN PUCHAR a, - IN PUCHAR b, - OUT PUCHAR out) -{ - INT i; - - for (i=0;i<4; i++) - { - out[i] = a[i] ^ b[i]; - } -} - -VOID byte_sub( - IN PUCHAR in, - OUT PUCHAR out) -{ - INT i; - - for (i=0; i< 16; i++) - { - out[i] = RTMPCkipSbox(in[i]); - } -} - -UCHAR RTMPCkipSbox( - IN UCHAR a) -{ - return SboxTable[(int)a]; -} - -VOID shift_row( - IN PUCHAR in, - OUT PUCHAR out) -{ - out[0] = in[0]; - out[1] = in[5]; - out[2] = in[10]; - out[3] = in[15]; - out[4] = in[4]; - out[5] = in[9]; - out[6] = in[14]; - out[7] = in[3]; - out[8] = in[8]; - out[9] = in[13]; - out[10] = in[2]; - out[11] = in[7]; - out[12] = in[12]; - out[13] = in[1]; - out[14] = in[6]; - out[15] = in[11]; -} - -VOID mix_column( - IN PUCHAR in, - OUT PUCHAR out) -{ - INT i; - UCHAR add1b[4]; - UCHAR add1bf7[4]; - UCHAR rotl[4]; - UCHAR swap_halfs[4]; - UCHAR andf7[4]; - UCHAR rotr[4]; - UCHAR temp[4]; - UCHAR tempb[4]; - - for (i=0 ; i<4; i++) - { - if ((in[i] & 0x80)== 0x80) - add1b[i] = 0x1b; - else - add1b[i] = 0x00; - } - - swap_halfs[0] = in[2]; /* Swap halfs */ - swap_halfs[1] = in[3]; - swap_halfs[2] = in[0]; - swap_halfs[3] = in[1]; - - rotl[0] = in[3]; /* Rotate left 8 bits */ - rotl[1] = in[0]; - rotl[2] = in[1]; - rotl[3] = in[2]; - - andf7[0] = in[0] & 0x7f; - andf7[1] = in[1] & 0x7f; - andf7[2] = in[2] & 0x7f; - andf7[3] = in[3] & 0x7f; - - for (i = 3; i>0; i--) /* logical shift left 1 bit */ - { - andf7[i] = andf7[i] << 1; - if ((andf7[i-1] & 0x80) == 0x80) - { - andf7[i] = (andf7[i] | 0x01); - } - } - andf7[0] = andf7[0] << 1; - andf7[0] = andf7[0] & 0xfe; - - xor_32(add1b, andf7, add1bf7); - - xor_32(in, add1bf7, rotr); - - temp[0] = rotr[0]; /* Rotate right 8 bits */ - rotr[0] = rotr[1]; - rotr[1] = rotr[2]; - rotr[2] = rotr[3]; - rotr[3] = temp[0]; - - xor_32(add1bf7, rotr, temp); - xor_32(swap_halfs, rotl,tempb); - xor_32(temp, tempb, out); -} - +#include "../../rt2860/common/rtmp_tkip.c" diff --git a/drivers/staging/rt2870/common/rtmp_wep.c b/drivers/staging/rt2870/common/rtmp_wep.c index 62f9e58729d7..ae255adc9f7f 100644 --- a/drivers/staging/rt2870/common/rtmp_wep.c +++ b/drivers/staging/rt2870/common/rtmp_wep.c @@ -1,508 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - rtmp_wep.c - - Abstract: - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Paul Wu 10-28-02 Initial -*/ - -#include "../rt_config.h" - -UINT FCSTAB_32[256] = -{ - 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, - 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, - 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, - 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, - 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, - 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, - 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, - 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, - 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, - 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, - 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, - 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, - 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, - 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, - 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, - 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, - 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, - 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, - 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, - 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, - 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, - 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, - 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, - 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, - 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, - 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, - 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, - 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, - 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, - 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, - 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, - 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, - 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, - 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, - 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, - 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, - 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, - 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, - 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, - 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, - 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, - 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, - 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, - 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, - 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, - 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, - 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, - 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, - 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, - 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, - 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, - 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, - 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, - 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, - 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, - 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, - 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, - 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, - 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, - 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, - 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, - 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, - 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, - 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d -}; - -/* -UCHAR WEPKEY[] = { - //IV - 0x00, 0x11, 0x22, - //WEP KEY - 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC - }; - */ - -/* - ======================================================================== - - Routine Description: - Init WEP function. - - Arguments: - pAd Pointer to our adapter - pKey Pointer to the WEP KEY - KeyId WEP Key ID - KeyLen the length of WEP KEY - pDest Pointer to the destination which Encryption data will store in. - - Return Value: - None - - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -VOID RTMPInitWepEngine( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pKey, - IN UCHAR KeyId, - IN UCHAR KeyLen, - IN OUT PUCHAR pDest) -{ - UINT i; - UCHAR WEPKEY[] = { - //IV - 0x00, 0x11, 0x22, - //WEP KEY - 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC - }; - - pAd->PrivateInfo.FCSCRC32 = PPPINITFCS32; //Init crc32. - -#ifdef CONFIG_STA_SUPPORT - if (pAd->StaCfg.bCkipOn && (pAd->StaCfg.CkipFlag & 0x10) && (pAd->OpMode == OPMODE_STA)) - { - ARCFOUR_INIT(&pAd->PrivateInfo.WEPCONTEXT, pKey, KeyLen); //INIT SBOX, KEYLEN+3(IV) - NdisMoveMemory(pDest, pKey, 3); //Append Init Vector - } - else -#endif // CONFIG_STA_SUPPORT // - { - NdisMoveMemory(WEPKEY + 3, pKey, KeyLen); - - for(i = 0; i < 3; i++) - WEPKEY[i] = RandomByte(pAd); //Call mlme RandomByte() function. - ARCFOUR_INIT(&pAd->PrivateInfo.WEPCONTEXT, WEPKEY, KeyLen + 3); //INIT SBOX, KEYLEN+3(IV) - - NdisMoveMemory(pDest, WEPKEY, 3); //Append Init Vector - } - *(pDest+3) = (KeyId << 6); //Append KEYID - -} - -/* - ======================================================================== - - Routine Description: - Encrypt transimitted data - - Arguments: - pAd Pointer to our adapter - pSrc Pointer to the transimitted source data that will be encrypt - pDest Pointer to the destination where entryption data will be store in. - Len Indicate the length of the source data - - Return Value: - None - - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -VOID RTMPEncryptData( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pSrc, - IN PUCHAR pDest, - IN UINT Len) -{ - pAd->PrivateInfo.FCSCRC32 = RTMP_CALC_FCS32(pAd->PrivateInfo.FCSCRC32, pSrc, Len); - ARCFOUR_ENCRYPT(&pAd->PrivateInfo.WEPCONTEXT, pDest, pSrc, Len); -} - - -/* - ======================================================================== - - Routine Description: - Decrypt received WEP data - - Arguments: - pAdapter Pointer to our adapter - pSrc Pointer to the received data - Len the length of the received data - - Return Value: - TRUE Decrypt WEP data success - FALSE Decrypt WEP data failed - - Note: - - ======================================================================== -*/ -BOOLEAN RTMPSoftDecryptWEP( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pData, - IN ULONG DataByteCnt, - IN PCIPHER_KEY pGroupKey) -{ - UINT trailfcs; - UINT crc32; - UCHAR KeyIdx; - UCHAR WEPKEY[] = { - //IV - 0x00, 0x11, 0x22, - //WEP KEY - 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC - }; - UCHAR *pPayload = (UCHAR *)pData + LENGTH_802_11; - ULONG payload_len = DataByteCnt - LENGTH_802_11; - - NdisMoveMemory(WEPKEY, pPayload, 3); //Get WEP IV - - KeyIdx = (*(pPayload + 3) & 0xc0) >> 6; - if (pGroupKey[KeyIdx].KeyLen == 0) - return (FALSE); - - NdisMoveMemory(WEPKEY + 3, pGroupKey[KeyIdx].Key, pGroupKey[KeyIdx].KeyLen); - ARCFOUR_INIT(&pAd->PrivateInfo.WEPCONTEXT, WEPKEY, pGroupKey[KeyIdx].KeyLen + 3); - ARCFOUR_DECRYPT(&pAd->PrivateInfo.WEPCONTEXT, pPayload, pPayload + 4, payload_len - 4); - NdisMoveMemory(&trailfcs, pPayload + payload_len - 8, 4); - crc32 = RTMP_CALC_FCS32(PPPINITFCS32, pPayload, payload_len - 8); //Skip last 4 bytes(FCS). - crc32 ^= 0xffffffff; /* complement */ - - if(crc32 != cpu2le32(trailfcs)) - { - DBGPRINT(RT_DEBUG_TRACE, ("! WEP Data CRC Error !\n")); //CRC error. - return (FALSE); - } - return (TRUE); -} - -/* - ======================================================================== - - Routine Description: - The Stream Cipher Encryption Algorithm "ARCFOUR" initialize - - Arguments: - Ctx Pointer to ARCFOUR CONTEXT (SBOX) - pKey Pointer to the WEP KEY - KeyLen Indicate the length fo the WEP KEY - - Return Value: - None - - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -VOID ARCFOUR_INIT( - IN PARCFOURCONTEXT Ctx, - IN PUCHAR pKey, - IN UINT KeyLen) -{ - UCHAR t, u; - UINT keyindex; - UINT stateindex; - PUCHAR state; - UINT counter; - - state = Ctx->STATE; - Ctx->X = 0; - Ctx->Y = 0; - for (counter = 0; counter < 256; counter++) - state[counter] = (UCHAR)counter; - keyindex = 0; - stateindex = 0; - for (counter = 0; counter < 256; counter++) - { - t = state[counter]; - stateindex = (stateindex + pKey[keyindex] + t) & 0xff; - u = state[stateindex]; - state[stateindex] = t; - state[counter] = u; - if (++keyindex >= KeyLen) - keyindex = 0; - } -} - -/* - ======================================================================== - - Routine Description: - Get bytes from ARCFOUR CONTEXT (S-BOX) - - Arguments: - Ctx Pointer to ARCFOUR CONTEXT (SBOX) - - Return Value: - UCHAR - the value of the ARCFOUR CONTEXT (S-BOX) - - Note: - - ======================================================================== -*/ -UCHAR ARCFOUR_BYTE( - IN PARCFOURCONTEXT Ctx) -{ - UINT x; - UINT y; - UCHAR sx, sy; - PUCHAR state; - - state = Ctx->STATE; - x = (Ctx->X + 1) & 0xff; - sx = state[x]; - y = (sx + Ctx->Y) & 0xff; - sy = state[y]; - Ctx->X = x; - Ctx->Y = y; - state[y] = sx; - state[x] = sy; - - return(state[(sx + sy) & 0xff]); - -} - -/* - ======================================================================== - - Routine Description: - The Stream Cipher Decryption Algorithm - - Arguments: - Ctx Pointer to ARCFOUR CONTEXT (SBOX) - pDest Pointer to the Destination - pSrc Pointer to the Source data - Len Indicate the length of the Source data - - Return Value: - None - - Note: - - ======================================================================== -*/ -VOID ARCFOUR_DECRYPT( - IN PARCFOURCONTEXT Ctx, - IN PUCHAR pDest, - IN PUCHAR pSrc, - IN UINT Len) -{ - UINT i; - - for (i = 0; i < Len; i++) - pDest[i] = pSrc[i] ^ ARCFOUR_BYTE(Ctx); -} - -/* - ======================================================================== - - Routine Description: - The Stream Cipher Encryption Algorithm - - Arguments: - Ctx Pointer to ARCFOUR CONTEXT (SBOX) - pDest Pointer to the Destination - pSrc Pointer to the Source data - Len Indicate the length of the Source dta - - Return Value: - None - - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -VOID ARCFOUR_ENCRYPT( - IN PARCFOURCONTEXT Ctx, - IN PUCHAR pDest, - IN PUCHAR pSrc, - IN UINT Len) -{ - UINT i; - - for (i = 0; i < Len; i++) - pDest[i] = pSrc[i] ^ ARCFOUR_BYTE(Ctx); -} - -/* - ======================================================================== - - Routine Description: - The Stream Cipher Encryption Algorithm which conform to the special requirement to encrypt GTK. - - Arguments: - Ctx Pointer to ARCFOUR CONTEXT (SBOX) - pDest Pointer to the Destination - pSrc Pointer to the Source data - Len Indicate the length of the Source dta - - - ======================================================================== -*/ - -VOID WPAARCFOUR_ENCRYPT( - IN PARCFOURCONTEXT Ctx, - IN PUCHAR pDest, - IN PUCHAR pSrc, - IN UINT Len) -{ - UINT i; - //discard first 256 bytes - for (i = 0; i < 256; i++) - ARCFOUR_BYTE(Ctx); - - for (i = 0; i < Len; i++) - pDest[i] = pSrc[i] ^ ARCFOUR_BYTE(Ctx); -} - - -/* - ======================================================================== - - Routine Description: - Calculate a new FCS given the current FCS and the new data. - - Arguments: - Fcs the original FCS value - Cp pointer to the data which will be calculate the FCS - Len the length of the data - - Return Value: - UINT - FCS 32 bits - - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -UINT RTMP_CALC_FCS32( - IN UINT Fcs, - IN PUCHAR Cp, - IN INT Len) -{ - while (Len--) - Fcs = (((Fcs) >> 8) ^ FCSTAB_32[((Fcs) ^ (*Cp++)) & 0xff]); - - return (Fcs); -} - - -/* - ======================================================================== - - Routine Description: - Get last FCS and encrypt it to the destination - - Arguments: - pDest Pointer to the Destination - - Return Value: - None - - Note: - - ======================================================================== -*/ -VOID RTMPSetICV( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDest) -{ - pAd->PrivateInfo.FCSCRC32 ^= 0xffffffff; /* complement */ - pAd->PrivateInfo.FCSCRC32 = cpu2le32(pAd->PrivateInfo.FCSCRC32); - - ARCFOUR_ENCRYPT(&pAd->PrivateInfo.WEPCONTEXT, pDest, (PUCHAR) &pAd->PrivateInfo.FCSCRC32, 4); -} - +#include "../../rt2860/common/rtmp_wep.c" diff --git a/drivers/staging/rt2870/common/rtusb_bulk.c b/drivers/staging/rt2870/common/rtusb_bulk.c index c46d9166ccf4..7ae3e9596133 100644 --- a/drivers/staging/rt2870/common/rtusb_bulk.c +++ b/drivers/staging/rt2870/common/rtusb_bulk.c @@ -52,11 +52,7 @@ void RTUSB_FILL_BULK_URB (struct urb *pUrb, void *pContext) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) usb_fill_bulk_urb(pUrb, pUsb_Dev, bulkpipe, pTransferBuf, BufSize, (usb_complete_t)Complete, pContext); -#else - FILL_BULK_URB(pUrb, pUsb_Dev, bulkpipe, pTransferBuf, BufSize, Complete, pContext); -#endif } @@ -95,14 +91,12 @@ VOID RTUSBInitTxDesc( Func, pTxContext); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) if (pTxContext->bAggregatible) pUrb->transfer_dma = (pTxContext->data_dma + TX_BUFFER_NORMSIZE + 2); else pUrb->transfer_dma = pTxContext->data_dma; pUrb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; -#endif } @@ -135,10 +129,8 @@ VOID RTUSBInitHTTxDesc( Func, pTxContext); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) pUrb->transfer_dma = (pTxContext->data_dma + pTxContext->NextBulkOutPosition); pUrb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; -#endif } @@ -168,10 +160,8 @@ VOID RTUSBInitRxDesc( (usb_complete_t)RTUSBBulkRxComplete, (void *)pRxContext); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) pUrb->transfer_dma = pRxContext->data_dma + pAd->NextRxBulkInPosition; pUrb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; -#endif } @@ -327,6 +317,7 @@ VOID RTUSBBulkOutDataPacket( break; } + //PS packets use HCCA queue when dequeue from PS unicast queue (WiFi WPA2 MA9_DT1 for Marvell B STA) if (pTxInfo->QSEL != FIFO_EDCA) { printk("%s(): ====> pTxInfo->QueueSel(%d)!= FIFO_EDCA!!!!\n", __func__, pTxInfo->QSEL); @@ -359,7 +350,7 @@ VOID RTUSBBulkOutDataPacket( pLastTxInfo = pTxInfo; // Make sure we use EDCA QUEUE. - pTxInfo->QSEL = FIFO_EDCA; + pTxInfo->QSEL = FIFO_EDCA; //PS packets use HCCA queue when dequeue from PS unicast queue (WiFi WPA2 MA9_DT1 for Marvell B STA) ThisBulkSize += (pTxInfo->USBDMATxPktLen+4); TmpBulkEndPos += (pTxInfo->USBDMATxPktLen+4); @@ -375,31 +366,14 @@ VOID RTUSBBulkOutDataPacket( bTxQLastRound = TRUE; pHTTXContext->ENextBulkOutPosition = 8; - #ifdef RT_BIG_ENDIAN - RTMPDescriptorEndianChange((PUCHAR)pTxInfo, TYPE_TXINFO); - RTMPWIEndianChange((PUCHAR)pTxWI, TYPE_TXWI); - #endif // RT_BIG_ENDIAN // - break; } - -#ifdef RT_BIG_ENDIAN - RTMPDescriptorEndianChange((PUCHAR)pTxInfo, TYPE_TXINFO); - RTMPWIEndianChange((PUCHAR)pTxWI, TYPE_TXWI); -#endif // RT_BIG_ENDIAN // - }while (TRUE); // adjust the pTxInfo->USBDMANextVLD value of last pTxInfo. if (pLastTxInfo) { -#ifdef RT_BIG_ENDIAN - RTMPDescriptorEndianChange((PUCHAR)pLastTxInfo, TYPE_TXINFO); -#endif // RT_BIG_ENDIAN // pLastTxInfo->USBDMANextVLD = 0; -#ifdef RT_BIG_ENDIAN - RTMPDescriptorEndianChange((PUCHAR)pLastTxInfo, TYPE_TXINFO); -#endif // RT_BIG_ENDIAN // } /* @@ -474,115 +448,6 @@ VOID RTUSBBulkOutDataPacket( VOID RTUSBBulkOutDataPacketComplete(purbb_t pUrb, struct pt_regs *pt_regs) -{ -#if 0 // sample, IRQ LOCK - PRTMP_ADAPTER pAd; - POS_COOKIE pObj; - PHT_TX_CONTEXT pHTTXContext; - UCHAR BulkOutPipeId; - NTSTATUS Status; - unsigned long IrqFlags; - - DBGPRINT_RAW(RT_DEBUG_INFO, ("--->RTUSBBulkOutDataPacketComplete\n")); - - pHTTXContext = (PHT_TX_CONTEXT)pUrb->context; - pAd = pHTTXContext->pAd; - pObj = (POS_COOKIE) pAd->OS_Cookie; - Status = pUrb->status; - - // Store BulkOut PipeId - BulkOutPipeId = pHTTXContext->BulkOutPipeId; - pAd->BulkOutDataOneSecCount++; - - //DBGPRINT(RT_DEBUG_LOUD, ("Done-B(%d):I=0x%lx, CWPos=%ld, NBPos=%ld, ENBPos=%ld, bCopy=%d!\n", BulkOutPipeId, in_interrupt(), pHTTXContext->CurWritePosition, - // pHTTXContext->NextBulkOutPosition, pHTTXContext->ENextBulkOutPosition, pHTTXContext->bCopySavePad)); - - RTMP_IRQ_LOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); - pAd->BulkOutPending[BulkOutPipeId] = FALSE; - pHTTXContext->IRPPending = FALSE; - RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); - - if (Status == USB_ST_NOERROR) - { - pAd->BulkOutComplete++; - - pAd->Counters8023.GoodTransmits++; - //RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags); - FREE_HTTX_RING(pAd, BulkOutPipeId, pHTTXContext); - //RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags); - - - } - else // STATUS_OTHER - { - PUCHAR pBuf; - - pAd->BulkOutCompleteOther++; - - pBuf = &pHTTXContext->TransferBuffer->WirelessPacket[pHTTXContext->NextBulkOutPosition]; - - DBGPRINT_RAW(RT_DEBUG_ERROR, ("BulkOutDataPacket failed: ReasonCode=%d!\n", Status)); - DBGPRINT_RAW(RT_DEBUG_ERROR, (">>BulkOut Req=0x%lx, Complete=0x%lx, Other=0x%lx\n", pAd->BulkOutReq, pAd->BulkOutComplete, pAd->BulkOutCompleteOther)); - DBGPRINT_RAW(RT_DEBUG_ERROR, (">>BulkOut Header:%x %x %x %x %x %x %x %x\n", pBuf[0], pBuf[1], pBuf[2], pBuf[3], pBuf[4], pBuf[5], pBuf[6], pBuf[7])); - //DBGPRINT_RAW(RT_DEBUG_ERROR, (">>BulkOutCompleteCancel=0x%x, BulkOutCompleteOther=0x%x\n", pAd->BulkOutCompleteCancel, pAd->BulkOutCompleteOther)); - - if (!RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_RESET_IN_PROGRESS | - fRTMP_ADAPTER_HALT_IN_PROGRESS | - fRTMP_ADAPTER_NIC_NOT_EXIST | - fRTMP_ADAPTER_BULKOUT_RESET))) - { - RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET); - pAd->bulkResetPipeid = BulkOutPipeId; - } - } - - // - // bInUse = TRUE, means some process are filling TX data, after that must turn on bWaitingBulkOut - // bWaitingBulkOut = TRUE, means the TX data are waiting for bulk out. - // - //RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags); - if ((pHTTXContext->ENextBulkOutPosition != pHTTXContext->CurWritePosition) && - (pHTTXContext->ENextBulkOutPosition != (pHTTXContext->CurWritePosition+8)) && - !RTUSB_TEST_BULK_FLAG(pAd, (fRTUSB_BULK_OUT_DATA_FRAG << BulkOutPipeId))) - { - // Indicate There is data avaliable - RTUSB_SET_BULK_FLAG(pAd, (fRTUSB_BULK_OUT_DATA_NORMAL << BulkOutPipeId)); - } - //RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags); - - // Always call Bulk routine, even reset bulk. - // The protection of rest bulk should be in BulkOut routine - RTUSBKickBulkOut(pAd); - - - //DBGPRINT(RT_DEBUG_LOUD,("Done-A(%d):I=0x%lx, CWPos=%ld, NBPos=%ld, ENBPos=%ld, bCopy=%d\n", BulkOutPipeId, in_interrupt(), - // pHTTXContext->CurWritePosition, pHTTXContext->NextBulkOutPosition, pHTTXContext->ENextBulkOutPosition, pHTTXContext->bCopySavePad)); - - switch (BulkOutPipeId) - { - case 0: - pObj->ac0_dma_done_task.data = (unsigned long)pAd; - tasklet_hi_schedule(&pObj->ac0_dma_done_task); - break; - case 1: - pObj->ac1_dma_done_task.data = (unsigned long)pAd; - tasklet_hi_schedule(&pObj->ac1_dma_done_task); - break; - case 2: - pObj->ac2_dma_done_task.data = (unsigned long)pAd; - tasklet_hi_schedule(&pObj->ac2_dma_done_task); - break; - case 3: - pObj->ac3_dma_done_task.data = (unsigned long)pAd; - tasklet_hi_schedule(&pObj->ac3_dma_done_task); - break; - case 4: - pObj->hcca_dma_done_task.data = (unsigned long)pAd; - tasklet_hi_schedule(&pObj->hcca_dma_done_task); - break; - } -#else - { PHT_TX_CONTEXT pHTTXContext; PRTMP_ADAPTER pAd; @@ -622,10 +487,6 @@ VOID RTUSBBulkOutDataPacketComplete(purbb_t pUrb, struct pt_regs *pt_regs) break; } } -#endif - - -} /* @@ -667,10 +528,6 @@ VOID RTUSBBulkOutNullFrame( // Clear Null frame bulk flag RTUSB_CLEAR_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NULL); -#ifdef RT_BIG_ENDIAN - RTMPDescriptorEndianChange((PUCHAR)pNullContext->TransferBuffer, TYPE_TXINFO); -#endif // RT_BIG_ENDIAN // - // Init Tx context descriptor RTUSBInitTxDesc(pAd, pNullContext, 0, (usb_complete_t)RTUSBBulkOutNullFrameComplete); @@ -695,9 +552,6 @@ VOID RTUSBBulkOutNullFrameComplete(purbb_t pUrb, struct pt_regs *pt_regs) PRTMP_ADAPTER pAd; PTX_CONTEXT pNullContext; NTSTATUS Status; -#if 0 // sample, IRQ LOCK - unsigned long IrqFlags; -#endif POS_COOKIE pObj; @@ -705,174 +559,11 @@ VOID RTUSBBulkOutNullFrameComplete(purbb_t pUrb, struct pt_regs *pt_regs) pAd = pNullContext->pAd; Status = pUrb->status; -#if 0 // sample, IRQ LOCK - // Reset Null frame context flags - pNullContext->IRPPending = FALSE; - pNullContext->InUse = FALSE; - - if (Status == USB_ST_NOERROR) - { - // Don't worry about the queue is empty or not, this function will check itself - //RTMPUSBDeQueuePacket(pAd, 0); - RTMPDeQueuePacket(pAd, TRUE, NUM_OF_TX_RING, MAX_TX_PROCESS); - } - else // STATUS_OTHER - { - if ((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS)) && - (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) && - (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) && - (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET))) - { - DBGPRINT_RAW(RT_DEBUG_ERROR, ("Bulk Out Null Frame Failed\n")); - RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET); - RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_OUT, NULL, 0); - } - } - - RTMP_IRQ_LOCK(&pAd->BulkOutLock[0], IrqFlags); - pAd->BulkOutPending[0] = FALSE; - RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], IrqFlags); - - // Always call Bulk routine, even reset bulk. - // The protectioon of rest bulk should be in BulkOut routine - RTUSBKickBulkOut(pAd); -#else - pObj = (POS_COOKIE) pAd->OS_Cookie; pObj->null_frame_complete_task.data = (unsigned long)pUrb; tasklet_hi_schedule(&pObj->null_frame_complete_task); -#endif - } -#if 0 // For RT2870, RTS frame not used now, but maybe will use it latter. -/* - ======================================================================== - - Routine Description: - - Arguments: - - Return Value: - - Note: RTS frame use BulkOutPipeId = 0 - - ======================================================================== -*/ -VOID RTUSBBulkOutRTSFrame( - IN PRTMP_ADAPTER pAd) -{ - PTX_CONTEXT pRTSContext = &(pAd->RTSContext); - PURB pUrb; - int ret = 0; - unsigned long IrqFlags; - UCHAR PipeID=0; - - if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NORMAL_4)) - PipeID= 3; - else if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NORMAL_3)) - PipeID= 2; - else if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NORMAL_2)) - PipeID= 1; - else if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NORMAL)) - PipeID= 0; - - RTMP_IRQ_LOCK(&pAd->BulkOutLock[PipeID], IrqFlags); - if ((pAd->BulkOutPending[PipeID] == TRUE) || RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NEED_STOP_TX)) - { - RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[PipeID], IrqFlags); - return; - } - pAd->BulkOutPending[PipeID] = TRUE; - RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[PipeID], IrqFlags); - - // Increase Total transmit byte counter - pAd->RalinkCounters.TransmittedByteCount += pRTSContext->BulkOutSize; - - DBGPRINT_RAW(RT_DEBUG_INFO, ("--->RTUSBBulkOutRTSFrame \n")); - - // Clear RTS frame bulk flag - RTUSB_CLEAR_BULK_FLAG(pAd, fRTUSB_BULK_OUT_RTS); - -#ifdef RT_BIG_ENDIAN - RTMPDescriptorEndianChange((PUCHAR)pRTSContext->TransferBuffer, TYPE_TXINFO); -#endif // RT_BIG_ENDIAN // - - // Init Tx context descriptor - RTUSBInitTxDesc(pAd, pRTSContext, PipeID, (usb_complete_t)RTUSBBulkOutRTSFrameComplete); - pRTSContext->IRPPending = TRUE; - - pUrb = pRTSContext->pUrb; - if((ret = RTUSB_SUBMIT_URB(pUrb))!=0) - { - DBGPRINT(RT_DEBUG_ERROR, ("RTUSBBulkOutRTSFrame: Submit Tx URB failed %d\n", ret)); - return; - } - - DBGPRINT_RAW(RT_DEBUG_INFO, ("<---RTUSBBulkOutRTSFrame \n")); - -} - -// RTS frame use BulkOutPipeId = 0 -VOID RTUSBBulkOutRTSFrameComplete(purbb_t pUrb, struct pt_regs *pt_regs) -{ - PRTMP_ADAPTER pAd; - PTX_CONTEXT pRTSContext; - NTSTATUS Status; -#if 0 // sample, IRQ LOCK - unsigned long IrqFlags; -#endif - POS_COOKIE pObj; - - DBGPRINT_RAW(RT_DEBUG_INFO, ("--->RTUSBBulkOutRTSFrameComplete\n")); - - pRTSContext = (PTX_CONTEXT)pUrb->context; - pAd = pRTSContext->pAd; - Status = pUrb->status; - -#if 0 // sample, IRQ LOCK - // Reset RTS frame context flags - pRTSContext->IRPPending = FALSE; - pRTSContext->InUse = FALSE; - - if (Status == USB_ST_NOERROR) - { - // Don't worry about the queue is empty or not, this function will check itself - //RTMPUSBDeQueuePacket(pAd, pRTSContext->BulkOutPipeId); - RTMPDeQueuePacket(pAd, TRUE, NUM_OF_TX_RING, MAX_TX_PROCESS); - } - else // STATUS_OTHER - { - if ((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS)) && - (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) && - (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) && - (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET))) - { - DBGPRINT_RAW(RT_DEBUG_ERROR, ("Bulk Out RTS Frame Failed\n")); - RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET); - RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_OUT, NULL, 0); - } - } - - RTMP_IRQ_LOCK(&pAd->BulkOutLock[pRTSContext->BulkOutPipeId], IrqFlags); - pAd->BulkOutPending[pRTSContext->BulkOutPipeId] = FALSE; - RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[pRTSContext->BulkOutPipeId], IrqFlags); - - // Always call Bulk routine, even reset bulk. - // The protectioon of rest bulk should be in BulkOut routine - RTUSBKickBulkOut(pAd); -#else - - pObj = (POS_COOKIE) pAd->OS_Cookie; - pObj->rts_frame_complete_task.data = (unsigned long)pUrb; - tasklet_hi_schedule(&pObj->rts_frame_complete_task); -#endif - - DBGPRINT_RAW(RT_DEBUG_INFO, ("<---RTUSBBulkOutRTSFrameComplete\n")); - -} -#endif - /* ======================================================================== @@ -930,37 +621,12 @@ VOID RTUSBBulkOutMLMEPacket( // Clear MLME bulk flag RTUSB_CLEAR_BULK_FLAG(pAd, fRTUSB_BULK_OUT_MLME); - - //DBGPRINT_RAW(RT_DEBUG_INFO, ("--->RTUSBBulkOutMLMEPacket\n")); -#if 0 // for debug -{ - printk("MLME-Out, C=%d!, D=%d, F=%d!\n", pAd->MgmtRing.TxCpuIdx, pAd->MgmtRing.TxDmaIdx, pAd->MgmtRing.TxSwFreeIdx); - - //TODO: Need to remove it when formal release - PTXINFO_STRUC pTxInfo; - - pTxInfo = (PTXINFO_STRUC)pMLMEContext->TransferBuffer; - if (pTxInfo->QSEL != FIFO_EDCA) - { - printk("%s(): ====> pTxInfo->QueueSel(%d)!= FIFO_EDCA!!!!\n", __func__, pTxInfo->QSEL); - printk("\tMLME_Index=%d!\n", Index); - hex_dump("Wrong QSel Pkt:", (PUCHAR)pMLMEContext->TransferBuffer, pTxInfo->USBDMATxPktLen); - } -} -#endif - -#ifdef RT_BIG_ENDIAN - RTMPDescriptorEndianChange((PUCHAR)pMLMEContext->TransferBuffer, TYPE_TXINFO); -#endif // RT_BIG_ENDIAN // - // Init Tx context descriptor RTUSBInitTxDesc(pAd, pMLMEContext, MGMTPIPEIDX, (usb_complete_t)RTUSBBulkOutMLMEPacketComplete); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) //For mgmt urb buffer, because we use sk_buff, so we need to notify the USB controller do dma mapping. pUrb->transfer_dma = 0; pUrb->transfer_flags &= (~URB_NO_TRANSFER_DMA_MAP); -#endif pUrb = pMLMEContext->pUrb; if((ret = RTUSB_SUBMIT_URB(pUrb))!=0) @@ -988,11 +654,6 @@ VOID RTUSBBulkOutMLMEPacketComplete(purbb_t pUrb, struct pt_regs *pt_regs) NTSTATUS Status; POS_COOKIE pObj; int index; -#if 0 // sample, IRQ LOCK - unsigned long IrqFlags; - PNDIS_PACKET pPacket; -#endif - //DBGPRINT_RAW(RT_DEBUG_INFO, ("--->RTUSBBulkOutMLMEPacketComplete\n")); pMLMEContext = (PTX_CONTEXT)pUrb->context; @@ -1001,82 +662,8 @@ VOID RTUSBBulkOutMLMEPacketComplete(purbb_t pUrb, struct pt_regs *pt_regs) Status = pUrb->status; index = pMLMEContext->SelfIdx; - -#if 0 // sample, IRQ LOCK - ASSERT((pAd->MgmtRing.TxDmaIdx == index)); - //printk("MLME-Done-B: C=%d, D=%d, F=%d, Self=%d!\n", pAd->MgmtRing.TxCpuIdx, pAd->MgmtRing.TxDmaIdx, pAd->MgmtRing.TxSwFreeIdx, pMLMEContext->SelfIdx); - - RTMP_IRQ_LOCK(&pAd->BulkOutLock[MGMTPIPEIDX], IrqFlags); - - - if (Status != USB_ST_NOERROR) - { - //Bulk-Out fail status handle - if ((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS)) && - (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) && - (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) && - (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET))) - { - DBGPRINT_RAW(RT_DEBUG_ERROR, ("Bulk Out MLME Failed, Status=%d!\n", Status)); - // TODO: How to handle about the MLMEBulkOut failed issue. Need to resend the mgmt pkt? - RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET); - pAd->bulkResetPipeid = (MGMTPIPEIDX | BULKOUT_MGMT_RESET_FLAG); - } - } - pAd->BulkOutPending[MGMTPIPEIDX] = FALSE; - RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[MGMTPIPEIDX], IrqFlags); - - RTMP_IRQ_LOCK(&pAd->MLMEBulkOutLock, IrqFlags); - // Reset MLME context flags - pMLMEContext->IRPPending = FALSE; - pMLMEContext->InUse = FALSE; - pMLMEContext->bWaitingBulkOut = FALSE; - pMLMEContext->BulkOutSize = 0; - - pPacket = pAd->MgmtRing.Cell[index].pNdisPacket; - pAd->MgmtRing.Cell[index].pNdisPacket = NULL; - - // Increase MgmtRing Index - INC_RING_INDEX(pAd->MgmtRing.TxDmaIdx, MGMT_RING_SIZE); - pAd->MgmtRing.TxSwFreeIdx++; - - RTMP_IRQ_UNLOCK(&pAd->MLMEBulkOutLock, IrqFlags); - - // No-matter success or fail, we free the mgmt packet. - if (pPacket) - RTMPFreeNdisPacket(pAd, pPacket); - -#if 0 - //Bulk-Out fail status handle - if (Status != USB_ST_NOERROR) - { - if ((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS)) && - (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) && - (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) && - (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET))) - { - DBGPRINT_RAW(RT_DEBUG_ERROR, ("Bulk Out MLME Failed, Status=%d!\n", Status)); - // TODO: How to handle about the MLMEBulkOut failed issue. Need to reset the endpoint? - RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET); - pAd->bulkResetPipeid = (MGMTPIPEIDX | BULKOUT_MGMT_RESET_FLAG); - } - } -#endif - - //printk("MLME-Done-A: C=%d, D=%d, F=%d!\n", pAd->MgmtRing.TxCpuIdx, pAd->MgmtRing.TxDmaIdx, pAd->MgmtRing.TxSwFreeIdx); - - pObj->mgmt_dma_done_task.data = (unsigned long)pAd; - tasklet_hi_schedule(&pObj->mgmt_dma_done_task); - - //DBGPRINT_RAW(RT_DEBUG_INFO, ("<---RTUSBBulkOutMLMEPacketComplete\n")); -// printk("<---RTUSBBulkOutMLMEPacketComplete, Cpu=%d, Dma=%d, SwIdx=%d!\n", -// pAd->MgmtRing.TxCpuIdx, pAd->MgmtRing.TxDmaIdx, pAd->MgmtRing.TxSwFreeIdx); - -#else - pObj->mgmt_dma_done_task.data = (unsigned long)pUrb; tasklet_hi_schedule(&pObj->mgmt_dma_done_task); -#endif } @@ -1116,10 +703,6 @@ VOID RTUSBBulkOutPsPoll( // Clear PS-Poll bulk flag RTUSB_CLEAR_BULK_FLAG(pAd, fRTUSB_BULK_OUT_PSPOLL); -#ifdef RT_BIG_ENDIAN - RTMPDescriptorEndianChange((PUCHAR)pPsPollContext->TransferBuffer, TYPE_TXINFO); -#endif // RT_BIG_ENDIAN // - // Init Tx context descriptor RTUSBInitTxDesc(pAd, pPsPollContext, MGMTPIPEIDX, (usb_complete_t)RTUSBBulkOutPsPollComplete); @@ -1144,9 +727,6 @@ VOID RTUSBBulkOutPsPollComplete(purbb_t pUrb,struct pt_regs *pt_regs) PRTMP_ADAPTER pAd; PTX_CONTEXT pPsPollContext; NTSTATUS Status; -#if 0 // sample, IRQ LOCK - unsigned long IrqFlags; -#endif POS_COOKIE pObj; @@ -1154,255 +734,11 @@ VOID RTUSBBulkOutPsPollComplete(purbb_t pUrb,struct pt_regs *pt_regs) pAd = pPsPollContext->pAd; Status = pUrb->status; -#if 0 // sample, IRQ LOCK - // Reset PsPoll context flags - pPsPollContext->IRPPending = FALSE; - pPsPollContext->InUse = FALSE; - - if (Status == USB_ST_NOERROR) - { - // Don't worry about the queue is empty or not, this function will check itself - RTMPDeQueuePacket(pAd, TRUE, NUM_OF_TX_RING, MAX_TX_PROCESS); - } - else // STATUS_OTHER - { - if ((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS)) && - (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) && - (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) && - (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET))) - { - DBGPRINT_RAW(RT_DEBUG_ERROR, ("Bulk Out PSPoll Failed\n")); - RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET); - RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_OUT, NULL, 0); - } - } - - RTMP_IRQ_LOCK(&pAd->BulkOutLock[0], IrqFlags); - pAd->BulkOutPending[0] = FALSE; - RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], IrqFlags); - - // Always call Bulk routine, even reset bulk. - // The protectioon of rest bulk should be in BulkOut routine - RTUSBKickBulkOut(pAd); -#else - pObj = (POS_COOKIE) pAd->OS_Cookie; pObj->pspoll_frame_complete_task.data = (unsigned long)pUrb; tasklet_hi_schedule(&pObj->pspoll_frame_complete_task); -#endif } - -#if 0 -/* - ======================================================================== - - Routine Description: - USB_RxPacket initializes a URB and uses the Rx IRP to submit it - to USB. It checks if an Rx Descriptor is available and passes the - the coresponding buffer to be filled. If no descriptor is available - fails the request. When setting the completion routine we pass our - Adapter Object as Context. - - Arguments: - - Return Value: - TRUE found matched tuple cache - FALSE no matched found - - Note: - - ======================================================================== -*/ -VOID RTUSBBulkReceive( - IN PRTMP_ADAPTER pAd) -{ - PRX_CONTEXT pRxContext; - PURB pUrb; - int ret = 0; - unsigned long IrqFlags; - - - /* device had been closed */ - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_REMOVE_IN_PROGRESS)) - return; - - RTMP_IRQ_LOCK(&pAd->BulkInLock, IrqFlags); - - // Last is time point between 2 separate URB. - if (pAd->NextRxBulkInPosition == 0) - { - //pAd->NextRxBulkInIndex = (pAd->NextRxBulkInIndex + 1) % (RX_RING_SIZE); - INC_RING_INDEX(pAd->NextRxBulkInIndex, RX_RING_SIZE); - } - else if ((pAd->NextRxBulkInPosition&0x1ff) != 0) - { - //pAd->NextRxBulkInIndex = (pAd->NextRxBulkInIndex + 1) % (RX_RING_SIZE); - INC_RING_INDEX(pAd->NextRxBulkInIndex, RX_RING_SIZE); - DBGPRINT_RAW(RT_DEBUG_TRACE, ("pAd->NextRxBulkInPosition = 0x%lx. End of URB.\n", pAd->NextRxBulkInPosition )); - pAd->NextRxBulkInPosition = 0; - } - - if (pAd->NextRxBulkInPosition == MAX_RXBULK_SIZE) - pAd->NextRxBulkInPosition = 0; - - pRxContext = &(pAd->RxContext[pAd->NextRxBulkInIndex]); - - // TODO: Why need to check if pRxContext->InUsed == TRUE? - //if ((pRxContext->InUse == TRUE) || (pRxContext->Readable == TRUE)) - if ((pRxContext->InUse == FALSE) && (pRxContext->Readable == TRUE)) - { - DBGPRINT_RAW(RT_DEBUG_TRACE, ("pRxContext[%d] InUse = %d.pRxContext->Readable = %d. Return.\n", pAd->NextRxBulkInIndex,pRxContext->InUse, pRxContext->Readable )); - RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); - - // read RxContext, Since not -#ifdef CONFIG_STA_SUPPORT - STARxDoneInterruptHandle(pAd, TRUE); -#endif // CONFIG_STA_SUPPORT // - - //return; - } - pRxContext->InUse = TRUE; - pRxContext->IRPPending= TRUE; - - RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); - - // Init Rx context descriptor - NdisZeroMemory(pRxContext->TransferBuffer, BUFFER_SIZE); - RTUSBInitRxDesc(pAd, pRxContext); - - pUrb = pRxContext->pUrb; - if ((ret = RTUSB_SUBMIT_URB(pUrb))!=0) - { - DBGPRINT(RT_DEBUG_ERROR, ("RTUSBBulkReceive: Submit Rx URB failed %d\n", ret)); - return; - } - else // success - { - NdisInterlockedIncrement(&pAd->PendingRx); - pAd->BulkInReq++; - } - - // read RxContext, Since not -#ifdef CONFIG_STA_SUPPORT - STARxDoneInterruptHandle(pAd, FALSE); -#endif // CONFIG_STA_SUPPORT // -} - -/* - ======================================================================== - - Routine Description: - This routine process Rx Irp and call rx complete function. - - Arguments: - DeviceObject Pointer to the device object for next lower - device. DeviceObject passed in here belongs to - the next lower driver in the stack because we - were invoked via IoCallDriver in USB_RxPacket - AND it is not OUR device object - Irp Ptr to completed IRP - Context Ptr to our Adapter object (context specified - in IoSetCompletionRoutine - - Return Value: - Always returns STATUS_MORE_PROCESSING_REQUIRED - - Note: - Always returns STATUS_MORE_PROCESSING_REQUIRED - ======================================================================== -*/ -VOID RTUSBBulkRxComplete(purbb_t pUrb, struct pt_regs *pt_regs) -{ -#if 0 - PRX_CONTEXT pRxContext; - PRTMP_ADAPTER pAd; - NTSTATUS Status; -// POS_COOKIE pObj; - - pRxContext = (PRX_CONTEXT)pUrb->context; - pAd = pRxContext->pAd; -// pObj = (POS_COOKIE) pAd->OS_Cookie; - - - Status = pUrb->status; - //pRxContext->pIrp = NULL; - - pRxContext->InUse = FALSE; - pRxContext->IRPPending = FALSE; - - if (Status == USB_ST_NOERROR) - { - pAd->BulkInComplete++; - pRxContext->Readable = TRUE; - pAd->NextRxBulkInPosition = 0; - - } - else // STATUS_OTHER - { - pAd->BulkInCompleteFail++; - // Still read this packet although it may comtain wrong bytes. - pRxContext->Readable = FALSE; - // Parsing all packets. because after reset, the index will reset to all zero. - - if ((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS)) && - (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKIN_RESET)) && - (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) && - (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))) - { - - DBGPRINT_RAW(RT_DEBUG_ERROR, ("Bulk In Failed. Status = %d\n", Status)); - DBGPRINT_RAW(RT_DEBUG_ERROR, ("==>NextRxBulkInIndex=0x%x, NextRxBulkInReadIndex=0x%x, TransferBufferLength= 0x%x\n", - pAd->NextRxBulkInIndex, pAd->NextRxBulkInReadIndex, pRxContext->pUrb->actual_length)); - - RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BULKIN_RESET); - RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_IN, NULL, 0); - } - //pUrb = NULL; - } - - if ((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS)) && - (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKIN_RESET)) && -// (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET)) && - (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF)) && - (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) && - (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))) - { - RTUSBBulkReceive(pAd); -#if 0 -#if 1 - STARxDoneInterruptHandle(pAd, FALSE); -#else - pObj->rx_bh.data = (unsigned long)pUrb; - tasklet_schedule(&pObj->rx_bh); -#endif -#endif - } - - // Call RxPacket to process packet and return the status - NdisInterlockedDecrement(&pAd->PendingRx); -#else - - - // use a receive tasklet to handle received packets; - // or sometimes hardware IRQ will be disabled here, so we can not - // use spin_lock_bh()/spin_unlock_bh() after IRQ is disabled. :< - PRX_CONTEXT pRxContext; - PRTMP_ADAPTER pAd; - POS_COOKIE pObj; - - - pRxContext = (PRX_CONTEXT)pUrb->context; - pAd = pRxContext->pAd; - pObj = (POS_COOKIE) pAd->OS_Cookie; - - pObj->rx_done_task.data = (unsigned long)pUrb; - tasklet_hi_schedule(&pObj->rx_done_task); -#endif -} - -#else - VOID DoBulkIn(IN RTMP_ADAPTER *pAd) { PRX_CONTEXT pRxContext; @@ -1441,14 +777,6 @@ VOID DoBulkIn(IN RTMP_ADAPTER *pAd) } else { // success -#if 0 - RTMP_IRQ_LOCK(&pAd->BulkInLock, IrqFlags); - pRxContext->IRPPending = TRUE; - //NdisInterlockedIncrement(&pAd->PendingRx); - pAd->PendingRx++; - RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); - pAd->BulkInReq++; -#endif ASSERT((pRxContext->InUse == pRxContext->IRPPending)); //printk("BIDone, Pend=%d,BIIdx=%d,BIRIdx=%d!\n", pAd->PendingRx, pAd->NextRxBulkInIndex, pAd->NextRxBulkInReadIndex); } @@ -1508,10 +836,7 @@ VOID RTUSBBulkReceive( RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); // read RxContext, Since not -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - STARxDoneInterruptHandle(pAd, TRUE); -#endif // CONFIG_STA_SUPPORT // + STARxDoneInterruptHandle(pAd, TRUE); // Finish to handle this bulkIn buffer. RTMP_IRQ_LOCK(&pAd->BulkInLock, IrqFlags); @@ -1579,8 +904,6 @@ VOID RTUSBBulkRxComplete(purbb_t pUrb, struct pt_regs *pt_regs) } -#endif - /* @@ -1601,51 +924,8 @@ VOID RTUSBKickBulkOut( { // BulkIn Reset will reset whole USB PHY. So we need to make sure fRTMP_ADAPTER_BULKIN_RESET not flaged. if (!RTMP_TEST_FLAG(pAd ,fRTMP_ADAPTER_NEED_STOP_TX) -#ifdef RALINK_ATE - && !(ATE_ON(pAd)) -#endif // RALINK_ATE // ) { -#if 0 // not used now in RT28xx, but may used latter. - // 1. Data Fragment has highest priority - if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_FRAG)) - { - if (((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) || - (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) - )) - { - RTUSBBulkOutDataPacket(pAd, 0, pAd->NextBulkOutIndex[0]); - } - } - if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_FRAG_2)) - { - if (((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) || - (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) - )) - { - RTUSBBulkOutDataPacket(pAd, 1, pAd->NextBulkOutIndex[1]); - } - } - if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_FRAG_3)) - { - if (((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) || - (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) - )) - { - RTUSBBulkOutDataPacket(pAd, 2, pAd->NextBulkOutIndex[2]); - } - } - if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_FRAG_4)) - { - if (((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) || - (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) - )) - { - RTUSBBulkOutDataPacket(pAd, 3, pAd->NextBulkOutIndex[3]); - } - } -#endif - // 2. PS-Poll frame is next if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_PSPOLL)) { @@ -1696,6 +976,17 @@ VOID RTUSBKickBulkOut( RTUSBBulkOutDataPacket(pAd, 3, pAd->NextBulkOutIndex[3]); } } +#ifdef RT30xx + //PS packets use HCCA queue when dequeue from PS unicast queue (WiFi WPA2 MA9_DT1 for Marvell B STA) + if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NORMAL_5)) + { + if (((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) || + (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) + )) + { + } + } +#endif // 7. Null frame is the last else if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NULL)) @@ -1712,18 +1003,6 @@ VOID RTUSBKickBulkOut( } } -#ifdef RALINK_ATE - /* If the mode is in ATE mode. */ - else if((ATE_ON(pAd)) && - !RTMP_TEST_FLAG(pAd ,fRTMP_ADAPTER_NEED_STOP_TX))// PETER : watch out ! - { - if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_ATE)) - { - ATE_RTUSBBulkOutDataPacket(pAd, 0); - } - } -#endif // RALINK_ATE // - } /* @@ -1778,24 +1057,6 @@ VOID RTUSBCleanUpMLMEBulkOutQueue( IN PRTMP_ADAPTER pAd) { DBGPRINT(RT_DEBUG_TRACE, ("--->CleanUpMLMEBulkOutQueue\n")); - -#if 0 // Do nothing! - NdisAcquireSpinLock(&pAd->MLMEBulkOutLock); - while (pAd->PrioRingTxCnt > 0) - { - pAd->MLMEContext[pAd->PrioRingFirstIndex].InUse = FALSE; - - pAd->PrioRingFirstIndex++; - if (pAd->PrioRingFirstIndex >= MGMT_RING_SIZE) - { - pAd->PrioRingFirstIndex = 0; - } - - pAd->PrioRingTxCnt--; - } - NdisReleaseSpinLock(&pAd->MLMEBulkOutLock); -#endif - DBGPRINT(RT_DEBUG_TRACE, ("<---CleanUpMLMEBulkOutQueue\n")); } @@ -1906,14 +1167,6 @@ VOID RTUSBCancelPendingBulkOutIRP( RTMPusecDelay(200); } -#ifdef RALINK_ATE - pHTTXContext->bCopySavePad = 0; - pHTTXContext->CurWritePosition = 0; - pHTTXContext->CurWriteRealPos = 0; - pHTTXContext->bCurWriting = FALSE; - pHTTXContext->NextBulkOutPosition = 0; - pHTTXContext->ENextBulkOutPosition = 0; -#endif // RALINK_ATE // pAd->BulkOutPending[Idx] = FALSE; } diff --git a/drivers/staging/rt2870/common/rtusb_data.c b/drivers/staging/rt2870/common/rtusb_data.c index 5a0d78389f41..6b003f63372e 100644 --- a/drivers/staging/rt2870/common/rtusb_data.c +++ b/drivers/staging/rt2870/common/rtusb_data.c @@ -135,24 +135,11 @@ BOOLEAN RTUSBNeedQueueBackForAgg( RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags); if ((pHTTXContext->IRPPending == TRUE) /*&& (pAd->TxSwQueue[BulkOutPipeId].Number == 0) */) { -#if 0 - if ((pHTTXContext->CurWritePosition <= 8) && - (pHTTXContext->NextBulkOutPosition > 8 && (pHTTXContext->NextBulkOutPosition+MAX_AGGREGATION_SIZE) < MAX_TXBULK_LIMIT)) - { - needQueBack = TRUE; - } - else if ((pHTTXContext->CurWritePosition < pHTTXContext->NextBulkOutPosition) && - ((pHTTXContext->NextBulkOutPosition + MAX_AGGREGATION_SIZE) < MAX_TXBULK_LIMIT)) - { - needQueBack = TRUE; - } -#else if ((pHTTXContext->CurWritePosition < pHTTXContext->ENextBulkOutPosition) && (((pHTTXContext->ENextBulkOutPosition+MAX_AGGREGATION_SIZE) < MAX_TXBULK_LIMIT) || (pHTTXContext->CurWritePosition > MAX_AGGREGATION_SIZE))) { needQueBack = TRUE; } -#endif else if ((pHTTXContext->CurWritePosition > pHTTXContext->ENextBulkOutPosition) && ((pHTTXContext->ENextBulkOutPosition + MAX_AGGREGATION_SIZE) < pHTTXContext->CurWritePosition)) { diff --git a/drivers/staging/rt2870/common/rtusb_io.c b/drivers/staging/rt2870/common/rtusb_io.c index afde136a9a0c..fd1b0c18f2a0 100644 --- a/drivers/staging/rt2870/common/rtusb_io.c +++ b/drivers/staging/rt2870/common/rtusb_io.c @@ -110,6 +110,12 @@ NTSTATUS RTUSBFirmwareWrite( Status = RTUSBWriteMACRegister(pAd, 0x701c, 0xffffffff); Status = RTUSBFirmwareRun(pAd); +#ifdef RT30xx + RTMPusecDelay(10000); + RTUSBWriteMACRegister(pAd,H2M_MAILBOX_CSR,0); + AsicSendCommandToMcu(pAd, 0x72, 0x00, 0x00, 0x00);//reset rf by MCU supported by new firmware +#endif + return Status; } @@ -665,6 +671,7 @@ NTSTATUS RTUSBWriteRFRegister( return STATUS_SUCCESS; } +#ifndef RT30xx /* ======================================================================== @@ -772,6 +779,7 @@ NTSTATUS RT30xxReadRFRegister( return STATUS_SUCCESS; } +#endif /* RT30xx */ /* ======================================================================== @@ -796,6 +804,14 @@ NTSTATUS RTUSBReadEEPROM( { NTSTATUS Status = STATUS_SUCCESS; +#ifdef RT30xx + if(pAd->bUseEfuse) + { + Status =eFuseRead(pAd, Offset, pData, length); + } + else +#endif // RT30xx // + { Status = RTUSB_VendorRequest( pAd, (USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK), @@ -805,6 +821,7 @@ NTSTATUS RTUSBReadEEPROM( Offset, pData, length); + } return Status; } @@ -832,6 +849,14 @@ NTSTATUS RTUSBWriteEEPROM( { NTSTATUS Status = STATUS_SUCCESS; +#ifdef RT30xx + if(pAd->bUseEfuse) + { + Status = eFuseWrite(pAd, Offset, pData, length); + } + else +#endif // RT30xx // + { Status = RTUSB_VendorRequest( pAd, USBD_TRANSFER_DIRECTION_OUT, @@ -841,6 +866,7 @@ NTSTATUS RTUSBWriteEEPROM( Offset, pData, length); + } return Status; } @@ -957,9 +983,13 @@ NDIS_STATUS RTUSBEnqueueCmdFromNdis( PCmdQElmt cmdqelmt = NULL; POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie; - +#ifndef RT30xx BUG_ON(pObj->RTUSBCmdThr_task == NULL); CHECK_PID_LEGALITY(task_pid(pObj->RTUSBCmdThr_task)) +#endif +#ifdef RT30xx + if (pObj->RTUSBCmdThr_pid < 0) +#endif return (NDIS_STATUS_RESOURCES); status = RTMPAllocateMemory((PVOID *)&cmdqelmt, sizeof(CmdQElmt)); @@ -1194,21 +1224,6 @@ NTSTATUS RTUSB_VendorRequest( void *tmpBuf = TransferBuffer; // Acquire Control token -#ifdef INF_AMAZON_SE - //Semaphore fix INF_AMAZON_SE hang - //pAd->UsbVendorReqBuf is the swap for DEVICE_VENDOR_REQUEST_IN to fix dma bug. - ret = down_interruptible(&(pAd->UsbVendorReq_semaphore)); - if (pAd->UsbVendorReqBuf) - { - ASSERT(TransferBufferLength UsbVendorReqBuf; - NdisZeroMemory(pAd->UsbVendorReqBuf, TransferBufferLength); - - if (RequestType == DEVICE_VENDOR_REQUEST_OUT) - NdisMoveMemory(tmpBuf, TransferBuffer, TransferBufferLength); - } -#endif // INF_AMAZON_SE // do { if( RequestType == DEVICE_VENDOR_REQUEST_OUT) ret=usb_control_msg(pObj->pUsb_Dev, usb_sndctrlpipe( pObj->pUsb_Dev, 0 ), Request, RequestType, Value,Index, tmpBuf, TransferBufferLength, CONTROL_TIMEOUT_JIFFIES); @@ -1227,12 +1242,6 @@ NTSTATUS RTUSB_VendorRequest( } } while((ret < 0) && (retryCount < MAX_RETRY_COUNT)); -#ifdef INF_AMAZON_SE - if ((pAd->UsbVendorReqBuf) && (RequestType == DEVICE_VENDOR_REQUEST_IN)) - NdisMoveMemory(TransferBuffer, tmpBuf, TransferBufferLength); - up(&(pAd->UsbVendorReq_semaphore)); -#endif // INF_AMAZON_SE // - if (ret < 0) { // DBGPRINT(RT_DEBUG_ERROR, ("USBVendorRequest failed ret=%d \n",ret)); DBGPRINT(RT_DEBUG_ERROR, ("RTUSB_VendorRequest failed(%d),TxFlags=0x%x, ReqType=%s, Req=0x%x, Index=0x%x\n", @@ -1243,28 +1252,6 @@ NTSTATUS RTUSB_VendorRequest( if ((TransferBuffer!= NULL) && (TransferBufferLength > 0)) hex_dump("Failed TransferBuffer value", TransferBuffer, TransferBufferLength); } - -#if 0 - // retry - if (ret < 0) { - int temp_i=0; - DBGPRINT(RT_DEBUG_ERROR, ("USBVendorRequest failed ret=%d, \n",ret)); - ret = 0; - do - { - if( RequestType == DEVICE_VENDOR_REQUEST_OUT) - ret=usb_control_msg(pObj->pUsb_Dev, usb_sndctrlpipe( pObj->pUsb_Dev, 0 ), Request, RequestType, Value,Index, TransferBuffer, TransferBufferLength, CONTROL_TIMEOUT_JIFFIES); - else if(RequestType == DEVICE_VENDOR_REQUEST_IN) - ret=usb_control_msg(pObj->pUsb_Dev, usb_rcvctrlpipe( pObj->pUsb_Dev, 0 ), Request, RequestType, Value,Index, TransferBuffer, TransferBufferLength, CONTROL_TIMEOUT_JIFFIES); - temp_i++; - } while( (ret < 0) && (temp_i <= 1) ); - - if( ret >= 0) - return ret; - - } -#endif - } return ret; } @@ -1324,21 +1311,8 @@ VOID CMDHandler( { case CMDTHREAD_CHECK_GPIO: { -#ifdef CONFIG_STA_SUPPORT UINT32 data; -#endif // CONFIG_STA_SUPPORT // -#ifdef RALINK_ATE - if(ATE_ON(pAd)) - { - DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now\n")); - break; - } -#endif // RALINK_ATE // -#ifdef CONFIG_STA_SUPPORT - - - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { // Read GPIO pin2 as Hardware controlled radio state @@ -1374,17 +1348,14 @@ VOID CMDHandler( } } } -#endif // CONFIG_STA_SUPPORT // } break; -#ifdef CONFIG_STA_SUPPORT case CMDTHREAD_QKERIODIC_EXECUT: { StaQuickResponeForRateUpExec(NULL, pAd, NULL, NULL); } break; -#endif // CONFIG_STA_SUPPORT // case CMDTHREAD_RESET_BULK_OUT: { @@ -1394,9 +1365,7 @@ VOID CMDHandler( PHT_TX_CONTEXT pHTTXContext; // RTMP_TX_RING *pTxRing; unsigned long IrqFlags; -#ifdef RALINK_ATE - PTX_CONTEXT pNullContext = &(pAd->NullContext); -#endif // RALINK_ATE // + DBGPRINT_RAW(RT_DEBUG_TRACE, ("CmdThread : CMDTHREAD_RESET_BULK_OUT(ResetPipeid=0x%0x)===>\n", pAd->bulkResetPipeid)); // All transfers must be aborted or cancelled before attempting to reset the pipe. //RTUSBCancelPendingBulkOutIRP(pAd); @@ -1459,32 +1428,6 @@ VOID CMDHandler( //NdisReleaseSpinLock(&pAd->BulkOutLock[pAd->bulkResetPipeid]); RTMP_INT_UNLOCK(&pAd->BulkOutLock[pAd->bulkResetPipeid], IrqFlags); /*-----------------------------------------------------------------------------------------------*/ -#ifdef RALINK_ATE - if(ATE_ON(pAd)) - { - pNullContext->IRPPending = TRUE; - // - // If driver is still in ATE TXFRAME mode, - // keep on transmitting ATE frames. - // - DBGPRINT_RAW(RT_DEBUG_TRACE, ("pAd->ate.Mode == %d\npAd->ContinBulkOut == %d\npAd->BulkOutRemained == %d\n", pAd->ate.Mode, pAd->ContinBulkOut, atomic_read(&pAd->BulkOutRemained))); - if((pAd->ate.Mode == ATE_TXFRAME) && ((pAd->ContinBulkOut == TRUE) || (atomic_read(&pAd->BulkOutRemained) > 0))) - { - DBGPRINT_RAW(RT_DEBUG_TRACE, ("After CMDTHREAD_RESET_BULK_OUT, continue to bulk out frames !\n")); - - // Init Tx context descriptor - RTUSBInitTxDesc(pAd, pNullContext, 0/* pAd->bulkResetPipeid */, (usb_complete_t)ATE_RTUSBBulkOutDataPacketComplete); - - if((ret = RTUSB_SUBMIT_URB(pNullContext->pUrb))!=0) - { - DBGPRINT(RT_DEBUG_ERROR, ("ATE_RTUSBBulkOutDataPacket: Submit Tx URB failed %d\n", ret)); - } - - pAd->BulkOutReq++; - } - } - else -#endif // RALINK_ATE // /*-----------------------------------------------------------------------------------------------*/ { RTUSBInitHTTxDesc(pAd, pHTTXContext, pAd->bulkResetPipeid, pHTTXContext->BulkOutSize, (usb_complete_t)RTUSBBulkOutDataPacketComplete); @@ -1597,19 +1540,6 @@ VOID CMDHandler( { UINT32 MACValue; /*-----------------------------------------------------------------------------------------------*/ -#ifdef RALINK_ATE - if (ATE_ON(pAd)) - { - if((pAd->PendingRx > 0) && (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))) - { - DBGPRINT_RAW(RT_DEBUG_ERROR, ("ATE : BulkIn IRP Pending!!!\n")); - ATE_RTUSBCancelPendingBulkInIRP(pAd); - RTMPusecDelay(100000); - pAd->PendingRx = 0; - } - } - else -#endif // RALINK_ATE // /*-----------------------------------------------------------------------------------------------*/ { //while ((atomic_read(&pAd->PendingRx) > 0) && (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))) @@ -1699,15 +1629,6 @@ VOID CMDHandler( } else { // success -#if 0 - RTMP_IRQ_LOCK(&pAd->BulkInLock, IrqFlags); - pRxContext->IRPPending = TRUE; - //NdisInterlockedIncrement(&pAd->PendingRx); - pAd->PendingRx++; - RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); - pAd->BulkInReq++; -#endif - //printk("BIDone, Pend=%d,BIIdx=%d,BIRIdx=%d!\n", pAd->PendingRx, pAd->NextRxBulkInIndex, pAd->NextRxBulkInReadIndex); DBGPRINT_RAW(RT_DEBUG_TRACE, ("CMDTHREAD_RESET_BULK_IN: Submit Rx URB Done, status=%d!\n", pUrb->status)); ASSERT((pRxContext->InUse == pRxContext->IRPPending)); } @@ -1765,7 +1686,6 @@ VOID CMDHandler( case CMDTHREAD_SET_ASIC_WCID_CIPHER: { -#ifdef CONFIG_STA_SUPPORT RT_SET_ASIC_WCID_ATTRI SetAsicWcidAttri; USHORT offset; UINT32 MACRValue = 0; @@ -1817,46 +1737,46 @@ VOID CMDHandler( RTUSBWriteMACRegister(pAd, SHARED_KEY_MODE_BASE+4*(0/2), csr1.word); } -#endif // CONFIG_STA_SUPPORT // } break; -#ifdef CONFIG_STA_SUPPORT -#ifdef QOS_DLS_SUPPORT - // avoid in interrupt when write key +#ifdef RT30xx +//Benson modified for USB interface, avoid in interrupt when write key, 20080724 --> case RT_CMD_SET_KEY_TABLE: //General call for AsicAddPairwiseKeyEntry() - { - RT_ADD_PAIRWISE_KEY_ENTRY KeyInfo; - KeyInfo = *((PRT_ADD_PAIRWISE_KEY_ENTRY)(pData)); - AsicAddPairwiseKeyEntry(pAd, - KeyInfo.MacAddr, - (UCHAR)KeyInfo.MacTabMatchWCID, - &KeyInfo.CipherKey); - } + { + RT_ADD_PAIRWISE_KEY_ENTRY KeyInfo; + KeyInfo = *((PRT_ADD_PAIRWISE_KEY_ENTRY)(pData)); + AsicAddPairwiseKeyEntry(pAd, + KeyInfo.MacAddr, + (UCHAR)KeyInfo.MacTabMatchWCID, + &KeyInfo.CipherKey); + } break; - case RT_CMD_SET_RX_WCID_TABLE: //General call for RTMPAddWcidAttributeEntry() - { - PMAC_TABLE_ENTRY pEntry ; - pEntry = (PMAC_TABLE_ENTRY)(pData); - RTMPAddWcidAttributeEntry(pAd, - BSS0, - 0, - pEntry->PairwiseKey.CipherAlg, - pEntry); + { + PMAC_TABLE_ENTRY pEntry; + UCHAR KeyIdx; + UCHAR CipherAlg; + UCHAR ApIdx; + + pEntry = (PMAC_TABLE_ENTRY)(pData); + + RTMPAddWcidAttributeEntry( + pAd, + ApIdx, + KeyIdx, + CipherAlg, + pEntry); } - break; -#endif // QOS_DLS_SUPPORT // -#endif // CONFIG_STA_SUPPORT // + break; +//Benson modified for USB interface, avoid in interrupt when write key, 20080724 <-- +#endif case CMDTHREAD_SET_CLIENT_MAC_ENTRY: { MAC_TABLE_ENTRY *pEntry; pEntry = (MAC_TABLE_ENTRY *)pData; - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { AsicRemovePairwiseKeyEntry(pAd, pEntry->apidx, (UCHAR)pEntry->Aid); if ((pEntry->AuthMode <= Ndis802_11AuthModeAutoSwitch) && (pEntry->WepStatus == Ndis802_11Encryption1Enabled)) @@ -1891,7 +1811,6 @@ VOID CMDHandler( RTUSBWriteMACRegister(pAd, offset, 0); } } -#endif // CONFIG_STA_SUPPORT // AsicUpdateRxWCIDTable(pAd, pEntry->Aid, pEntry->Addr); printk("UpdateRxWCIDTable(): Aid=%d, Addr=%02x:%02x:%02x:%02x:%02x:%02x!\n", pEntry->Aid, @@ -1899,9 +1818,18 @@ VOID CMDHandler( } break; +#ifdef RT30xx +// add by johnli, fix "in_interrupt" error when call "MacTableDeleteEntry" in Rx tasklet + case CMDTHREAD_UPDATE_PROTECT: + { + AsicUpdateProtect(pAd, 0, (ALLN_SETPROTECT), TRUE, 0); + } + break; +// end johnli +#endif + case OID_802_11_ADD_WEP: { -#ifdef CONFIG_STA_SUPPORT UINT i; UINT32 KeyIdx; PNDIS_802_11_WEP pWepKey; @@ -1975,7 +1903,6 @@ VOID CMDHandler( AsicAddSharedKeyEntry(pAd, BSS0, (UCHAR)KeyIdx, CipherAlg, pWepKey->KeyMaterial, NULL, NULL); DBGPRINT(RT_DEBUG_TRACE, ("CmdThread::OID_802_11_ADD_WEP (KeyIdx=%d, Len=%d-byte)\n", KeyIdx, pWepKey->KeyLength)); } -#endif // CONFIG_STA_SUPPORT // } break; diff --git a/drivers/staging/rt2870/common/spectrum.c b/drivers/staging/rt2870/common/spectrum.c index 74380958eb70..1cf2c263f452 100644 --- a/drivers/staging/rt2870/common/spectrum.c +++ b/drivers/staging/rt2870/common/spectrum.c @@ -1,1876 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - action.c - - Abstract: - Handle association related requests either from WSTA or from local MLME - - Revision History: - Who When What - --------- ---------- ---------------------------------------------- - Fonchi Wu 2008 created for 802.11h - */ - -#include "../rt_config.h" -#include "action.h" - -VOID MeasureReqTabInit( - IN PRTMP_ADAPTER pAd) -{ - NdisAllocateSpinLock(&pAd->CommonCfg.MeasureReqTabLock); - - pAd->CommonCfg.pMeasureReqTab = kmalloc(sizeof(MEASURE_REQ_TAB), GFP_ATOMIC); - if (pAd->CommonCfg.pMeasureReqTab) - NdisZeroMemory(pAd->CommonCfg.pMeasureReqTab, sizeof(MEASURE_REQ_TAB)); - else - DBGPRINT(RT_DEBUG_ERROR, ("%s Fail to alloc memory for pAd->CommonCfg.pMeasureReqTab.\n", __func__)); - - return; -} - -VOID MeasureReqTabExit( - IN PRTMP_ADAPTER pAd) -{ - NdisFreeSpinLock(pAd->CommonCfg.MeasureReqTabLock); - - if (pAd->CommonCfg.pMeasureReqTab) - kfree(pAd->CommonCfg.pMeasureReqTab); - pAd->CommonCfg.pMeasureReqTab = NULL; - - return; -} - -static PMEASURE_REQ_ENTRY MeasureReqLookUp( - IN PRTMP_ADAPTER pAd, - IN UINT8 DialogToken) -{ - UINT HashIdx; - PMEASURE_REQ_TAB pTab = pAd->CommonCfg.pMeasureReqTab; - PMEASURE_REQ_ENTRY pEntry = NULL; - PMEASURE_REQ_ENTRY pPrevEntry = NULL; - - if (pTab == NULL) - { - DBGPRINT(RT_DEBUG_ERROR, ("%s: pMeasureReqTab doesn't exist.\n", __func__)); - return NULL; - } - - RTMP_SEM_LOCK(&pAd->CommonCfg.MeasureReqTabLock); - - HashIdx = MQ_DIALOGTOKEN_HASH_INDEX(DialogToken); - pEntry = pTab->Hash[HashIdx]; - - while (pEntry) - { - if (pEntry->DialogToken == DialogToken) - break; - else - { - pPrevEntry = pEntry; - pEntry = pEntry->pNext; - } - } - - RTMP_SEM_UNLOCK(&pAd->CommonCfg.MeasureReqTabLock); - - return pEntry; -} - -static PMEASURE_REQ_ENTRY MeasureReqInsert( - IN PRTMP_ADAPTER pAd, - IN UINT8 DialogToken) -{ - INT i; - ULONG HashIdx; - PMEASURE_REQ_TAB pTab = pAd->CommonCfg.pMeasureReqTab; - PMEASURE_REQ_ENTRY pEntry = NULL, pCurrEntry; - ULONG Now; - - if(pTab == NULL) - { - DBGPRINT(RT_DEBUG_ERROR, ("%s: pMeasureReqTab doesn't exist.\n", __func__)); - return NULL; - } - - pEntry = MeasureReqLookUp(pAd, DialogToken); - if (pEntry == NULL) - { - RTMP_SEM_LOCK(&pAd->CommonCfg.MeasureReqTabLock); - for (i = 0; i < MAX_MEASURE_REQ_TAB_SIZE; i++) - { - NdisGetSystemUpTime(&Now); - pEntry = &pTab->Content[i]; - - if ((pEntry->Valid == TRUE) - && RTMP_TIME_AFTER((unsigned long)Now, (unsigned long)(pEntry->lastTime + MQ_REQ_AGE_OUT))) - { - PMEASURE_REQ_ENTRY pPrevEntry = NULL; - ULONG HashIdx = MQ_DIALOGTOKEN_HASH_INDEX(pEntry->DialogToken); - PMEASURE_REQ_ENTRY pProbeEntry = pTab->Hash[HashIdx]; - - // update Hash list - do - { - if (pProbeEntry == pEntry) - { - if (pPrevEntry == NULL) - { - pTab->Hash[HashIdx] = pEntry->pNext; - } - else - { - pPrevEntry->pNext = pEntry->pNext; - } - break; - } - - pPrevEntry = pProbeEntry; - pProbeEntry = pProbeEntry->pNext; - } while (pProbeEntry); - - NdisZeroMemory(pEntry, sizeof(MEASURE_REQ_ENTRY)); - pTab->Size--; - - break; - } - - if (pEntry->Valid == FALSE) - break; - } - - if (i < MAX_MEASURE_REQ_TAB_SIZE) - { - NdisGetSystemUpTime(&Now); - pEntry->lastTime = Now; - pEntry->Valid = TRUE; - pEntry->DialogToken = DialogToken; - pTab->Size++; - } - else - { - pEntry = NULL; - DBGPRINT(RT_DEBUG_ERROR, ("%s: pMeasureReqTab tab full.\n", __func__)); - } - - // add this Neighbor entry into HASH table - if (pEntry) - { - HashIdx = MQ_DIALOGTOKEN_HASH_INDEX(DialogToken); - if (pTab->Hash[HashIdx] == NULL) - { - pTab->Hash[HashIdx] = pEntry; - } - else - { - pCurrEntry = pTab->Hash[HashIdx]; - while (pCurrEntry->pNext != NULL) - pCurrEntry = pCurrEntry->pNext; - pCurrEntry->pNext = pEntry; - } - } - - RTMP_SEM_UNLOCK(&pAd->CommonCfg.MeasureReqTabLock); - } - - return pEntry; -} - -static VOID MeasureReqDelete( - IN PRTMP_ADAPTER pAd, - IN UINT8 DialogToken) -{ - PMEASURE_REQ_TAB pTab = pAd->CommonCfg.pMeasureReqTab; - PMEASURE_REQ_ENTRY pEntry = NULL; - - if(pTab == NULL) - { - DBGPRINT(RT_DEBUG_ERROR, ("%s: pMeasureReqTab doesn't exist.\n", __func__)); - return; - } - - // if empty, return - if (pTab->Size == 0) - { - DBGPRINT(RT_DEBUG_ERROR, ("pMeasureReqTab empty.\n")); - return; - } - - pEntry = MeasureReqLookUp(pAd, DialogToken); - if (pEntry != NULL) - { - PMEASURE_REQ_ENTRY pPrevEntry = NULL; - ULONG HashIdx = MQ_DIALOGTOKEN_HASH_INDEX(pEntry->DialogToken); - PMEASURE_REQ_ENTRY pProbeEntry = pTab->Hash[HashIdx]; - - RTMP_SEM_LOCK(&pAd->CommonCfg.MeasureReqTabLock); - // update Hash list - do - { - if (pProbeEntry == pEntry) - { - if (pPrevEntry == NULL) - { - pTab->Hash[HashIdx] = pEntry->pNext; - } - else - { - pPrevEntry->pNext = pEntry->pNext; - } - break; - } - - pPrevEntry = pProbeEntry; - pProbeEntry = pProbeEntry->pNext; - } while (pProbeEntry); - - NdisZeroMemory(pEntry, sizeof(MEASURE_REQ_ENTRY)); - pTab->Size--; - - RTMP_SEM_UNLOCK(&pAd->CommonCfg.MeasureReqTabLock); - } - - return; -} - -VOID TpcReqTabInit( - IN PRTMP_ADAPTER pAd) -{ - NdisAllocateSpinLock(&pAd->CommonCfg.TpcReqTabLock); - - pAd->CommonCfg.pTpcReqTab = kmalloc(sizeof(TPC_REQ_TAB), GFP_ATOMIC); - if (pAd->CommonCfg.pTpcReqTab) - NdisZeroMemory(pAd->CommonCfg.pTpcReqTab, sizeof(TPC_REQ_TAB)); - else - DBGPRINT(RT_DEBUG_ERROR, ("%s Fail to alloc memory for pAd->CommonCfg.pTpcReqTab.\n", __func__)); - - return; -} - -VOID TpcReqTabExit( - IN PRTMP_ADAPTER pAd) -{ - NdisFreeSpinLock(pAd->CommonCfg.TpcReqTabLock); - - if (pAd->CommonCfg.pTpcReqTab) - kfree(pAd->CommonCfg.pTpcReqTab); - pAd->CommonCfg.pTpcReqTab = NULL; - - return; -} - -static PTPC_REQ_ENTRY TpcReqLookUp( - IN PRTMP_ADAPTER pAd, - IN UINT8 DialogToken) -{ - UINT HashIdx; - PTPC_REQ_TAB pTab = pAd->CommonCfg.pTpcReqTab; - PTPC_REQ_ENTRY pEntry = NULL; - PTPC_REQ_ENTRY pPrevEntry = NULL; - - if (pTab == NULL) - { - DBGPRINT(RT_DEBUG_ERROR, ("%s: pTpcReqTab doesn't exist.\n", __func__)); - return NULL; - } - - RTMP_SEM_LOCK(&pAd->CommonCfg.TpcReqTabLock); - - HashIdx = TPC_DIALOGTOKEN_HASH_INDEX(DialogToken); - pEntry = pTab->Hash[HashIdx]; - - while (pEntry) - { - if (pEntry->DialogToken == DialogToken) - break; - else - { - pPrevEntry = pEntry; - pEntry = pEntry->pNext; - } - } - - RTMP_SEM_UNLOCK(&pAd->CommonCfg.TpcReqTabLock); - - return pEntry; -} - - -static PTPC_REQ_ENTRY TpcReqInsert( - IN PRTMP_ADAPTER pAd, - IN UINT8 DialogToken) -{ - INT i; - ULONG HashIdx; - PTPC_REQ_TAB pTab = pAd->CommonCfg.pTpcReqTab; - PTPC_REQ_ENTRY pEntry = NULL, pCurrEntry; - ULONG Now; - - if(pTab == NULL) - { - DBGPRINT(RT_DEBUG_ERROR, ("%s: pTpcReqTab doesn't exist.\n", __func__)); - return NULL; - } - - pEntry = TpcReqLookUp(pAd, DialogToken); - if (pEntry == NULL) - { - RTMP_SEM_LOCK(&pAd->CommonCfg.TpcReqTabLock); - for (i = 0; i < MAX_TPC_REQ_TAB_SIZE; i++) - { - NdisGetSystemUpTime(&Now); - pEntry = &pTab->Content[i]; - - if ((pEntry->Valid == TRUE) - && RTMP_TIME_AFTER((unsigned long)Now, (unsigned long)(pEntry->lastTime + TPC_REQ_AGE_OUT))) - { - PTPC_REQ_ENTRY pPrevEntry = NULL; - ULONG HashIdx = TPC_DIALOGTOKEN_HASH_INDEX(pEntry->DialogToken); - PTPC_REQ_ENTRY pProbeEntry = pTab->Hash[HashIdx]; - - // update Hash list - do - { - if (pProbeEntry == pEntry) - { - if (pPrevEntry == NULL) - { - pTab->Hash[HashIdx] = pEntry->pNext; - } - else - { - pPrevEntry->pNext = pEntry->pNext; - } - break; - } - - pPrevEntry = pProbeEntry; - pProbeEntry = pProbeEntry->pNext; - } while (pProbeEntry); - - NdisZeroMemory(pEntry, sizeof(TPC_REQ_ENTRY)); - pTab->Size--; - - break; - } - - if (pEntry->Valid == FALSE) - break; - } - - if (i < MAX_TPC_REQ_TAB_SIZE) - { - NdisGetSystemUpTime(&Now); - pEntry->lastTime = Now; - pEntry->Valid = TRUE; - pEntry->DialogToken = DialogToken; - pTab->Size++; - } - else - { - pEntry = NULL; - DBGPRINT(RT_DEBUG_ERROR, ("%s: pTpcReqTab tab full.\n", __func__)); - } - - // add this Neighbor entry into HASH table - if (pEntry) - { - HashIdx = TPC_DIALOGTOKEN_HASH_INDEX(DialogToken); - if (pTab->Hash[HashIdx] == NULL) - { - pTab->Hash[HashIdx] = pEntry; - } - else - { - pCurrEntry = pTab->Hash[HashIdx]; - while (pCurrEntry->pNext != NULL) - pCurrEntry = pCurrEntry->pNext; - pCurrEntry->pNext = pEntry; - } - } - - RTMP_SEM_UNLOCK(&pAd->CommonCfg.TpcReqTabLock); - } - - return pEntry; -} - -static VOID TpcReqDelete( - IN PRTMP_ADAPTER pAd, - IN UINT8 DialogToken) -{ - PTPC_REQ_TAB pTab = pAd->CommonCfg.pTpcReqTab; - PTPC_REQ_ENTRY pEntry = NULL; - - if(pTab == NULL) - { - DBGPRINT(RT_DEBUG_ERROR, ("%s: pTpcReqTab doesn't exist.\n", __func__)); - return; - } - - // if empty, return - if (pTab->Size == 0) - { - DBGPRINT(RT_DEBUG_ERROR, ("pTpcReqTab empty.\n")); - return; - } - - pEntry = TpcReqLookUp(pAd, DialogToken); - if (pEntry != NULL) - { - PTPC_REQ_ENTRY pPrevEntry = NULL; - ULONG HashIdx = TPC_DIALOGTOKEN_HASH_INDEX(pEntry->DialogToken); - PTPC_REQ_ENTRY pProbeEntry = pTab->Hash[HashIdx]; - - RTMP_SEM_LOCK(&pAd->CommonCfg.TpcReqTabLock); - // update Hash list - do - { - if (pProbeEntry == pEntry) - { - if (pPrevEntry == NULL) - { - pTab->Hash[HashIdx] = pEntry->pNext; - } - else - { - pPrevEntry->pNext = pEntry->pNext; - } - break; - } - - pPrevEntry = pProbeEntry; - pProbeEntry = pProbeEntry->pNext; - } while (pProbeEntry); - - NdisZeroMemory(pEntry, sizeof(TPC_REQ_ENTRY)); - pTab->Size--; - - RTMP_SEM_UNLOCK(&pAd->CommonCfg.TpcReqTabLock); - } - - return; -} - -/* - ========================================================================== - Description: - Get Current TimeS tamp. - - Parametrs: - - Return : Current Time Stamp. - ========================================================================== - */ -static UINT64 GetCurrentTimeStamp( - IN PRTMP_ADAPTER pAd) -{ - // get current time stamp. - return 0; -} - -/* - ========================================================================== - Description: - Get Current Transmit Power. - - Parametrs: - - Return : Current Time Stamp. - ========================================================================== - */ -static UINT8 GetCurTxPwr( - IN PRTMP_ADAPTER pAd, - IN UINT8 Wcid) -{ - return 16; /* 16 dBm */ -} - -/* - ========================================================================== - Description: - Insert Dialog Token into frame. - - Parametrs: - 1. frame buffer pointer. - 2. frame length. - 3. Dialog token. - - Return : None. - ========================================================================== - */ -static VOID InsertDialogToken( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pFrameBuf, - OUT PULONG pFrameLen, - IN UINT8 DialogToken) -{ - ULONG TempLen; - MakeOutgoingFrame(pFrameBuf, &TempLen, - 1, &DialogToken, - END_OF_ARGS); - - *pFrameLen = *pFrameLen + TempLen; - - return; -} - -/* - ========================================================================== - Description: - Insert TPC Request IE into frame. - - Parametrs: - 1. frame buffer pointer. - 2. frame length. - - Return : None. - ========================================================================== - */ - static VOID InsertTpcReqIE( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pFrameBuf, - OUT PULONG pFrameLen) -{ - ULONG TempLen; - ULONG Len = 0; - UINT8 ElementID = IE_TPC_REQUEST; - - MakeOutgoingFrame(pFrameBuf, &TempLen, - 1, &ElementID, - 1, &Len, - END_OF_ARGS); - - *pFrameLen = *pFrameLen + TempLen; - - return; -} - -/* - ========================================================================== - Description: - Insert TPC Report IE into frame. - - Parametrs: - 1. frame buffer pointer. - 2. frame length. - 3. Transmit Power. - 4. Link Margin. - - Return : None. - ========================================================================== - */ - static VOID InsertTpcReportIE( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pFrameBuf, - OUT PULONG pFrameLen, - IN UINT8 TxPwr, - IN UINT8 LinkMargin) -{ - ULONG TempLen; - ULONG Len = sizeof(TPC_REPORT_INFO); - UINT8 ElementID = IE_TPC_REPORT; - TPC_REPORT_INFO TpcReportIE; - - TpcReportIE.TxPwr = TxPwr; - TpcReportIE.LinkMargin = LinkMargin; - - MakeOutgoingFrame(pFrameBuf, &TempLen, - 1, &ElementID, - 1, &Len, - Len, &TpcReportIE, - END_OF_ARGS); - - *pFrameLen = *pFrameLen + TempLen; - - - return; -} - -/* - ========================================================================== - Description: - Insert Channel Switch Announcement IE into frame. - - Parametrs: - 1. frame buffer pointer. - 2. frame length. - 3. channel switch announcement mode. - 4. new selected channel. - 5. channel switch announcement count. - - Return : None. - ========================================================================== - */ -static VOID InsertChSwAnnIE( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pFrameBuf, - OUT PULONG pFrameLen, - IN UINT8 ChSwMode, - IN UINT8 NewChannel, - IN UINT8 ChSwCnt) -{ - ULONG TempLen; - ULONG Len = sizeof(CH_SW_ANN_INFO); - UINT8 ElementID = IE_CHANNEL_SWITCH_ANNOUNCEMENT; - CH_SW_ANN_INFO ChSwAnnIE; - - ChSwAnnIE.ChSwMode = ChSwMode; - ChSwAnnIE.Channel = NewChannel; - ChSwAnnIE.ChSwCnt = ChSwCnt; - - MakeOutgoingFrame(pFrameBuf, &TempLen, - 1, &ElementID, - 1, &Len, - Len, &ChSwAnnIE, - END_OF_ARGS); - - *pFrameLen = *pFrameLen + TempLen; - - - return; -} - -/* - ========================================================================== - Description: - Insert Measure Request IE into frame. - - Parametrs: - 1. frame buffer pointer. - 2. frame length. - 3. Measure Token. - 4. Measure Request Mode. - 5. Measure Request Type. - 6. Measure Channel. - 7. Measure Start time. - 8. Measure Duration. - - - Return : None. - ========================================================================== - */ -static VOID InsertMeasureReqIE( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pFrameBuf, - OUT PULONG pFrameLen, - IN PMEASURE_REQ_INFO pMeasureReqIE) -{ - ULONG TempLen; - UINT8 Len = sizeof(MEASURE_REQ_INFO); - UINT8 ElementID = IE_MEASUREMENT_REQUEST; - - MakeOutgoingFrame(pFrameBuf, &TempLen, - 1, &ElementID, - 1, &Len, - Len, pMeasureReqIE, - END_OF_ARGS); - - *pFrameLen = *pFrameLen + TempLen; - - return; -} - -/* - ========================================================================== - Description: - Insert Measure Report IE into frame. - - Parametrs: - 1. frame buffer pointer. - 2. frame length. - 3. Measure Token. - 4. Measure Request Mode. - 5. Measure Request Type. - 6. Length of Report Infomation - 7. Pointer of Report Infomation Buffer. - - Return : None. - ========================================================================== - */ -static VOID InsertMeasureReportIE( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pFrameBuf, - OUT PULONG pFrameLen, - IN PMEASURE_REPORT_INFO pMeasureReportIE, - IN UINT8 ReportLnfoLen, - IN PUINT8 pReportInfo) -{ - ULONG TempLen; - ULONG Len; - UINT8 ElementID = IE_MEASUREMENT_REPORT; - - Len = sizeof(MEASURE_REPORT_INFO) + ReportLnfoLen; - - MakeOutgoingFrame(pFrameBuf, &TempLen, - 1, &ElementID, - 1, &Len, - Len, pMeasureReportIE, - END_OF_ARGS); - - *pFrameLen = *pFrameLen + TempLen; - - if ((ReportLnfoLen > 0) && (pReportInfo != NULL)) - { - MakeOutgoingFrame(pFrameBuf + *pFrameLen, &TempLen, - ReportLnfoLen, pReportInfo, - END_OF_ARGS); - - *pFrameLen = *pFrameLen + TempLen; - } - return; -} - -/* - ========================================================================== - Description: - Prepare Measurement request action frame and enqueue it into - management queue waiting for transmition. - - Parametrs: - 1. the destination mac address of the frame. - - Return : None. - ========================================================================== - */ -VOID EnqueueMeasurementReq( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDA, - IN UINT8 MeasureToken, - IN UINT8 MeasureReqMode, - IN UINT8 MeasureReqType, - IN UINT8 MeasureCh, - IN UINT16 MeasureDuration) -{ - PUCHAR pOutBuffer = NULL; - NDIS_STATUS NStatus; - ULONG FrameLen; - HEADER_802_11 ActHdr; - MEASURE_REQ_INFO MeasureReqIE; - UINT8 RmReqDailogToken = RandomByte(pAd); - UINT64 MeasureStartTime = GetCurrentTimeStamp(pAd); - - // build action frame header. - MgtMacHeaderInit(pAd, &ActHdr, SUBTYPE_ACTION, 0, pDA, - pAd->CurrentAddress); - - NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory - if(NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __func__)); - return; - } - NdisMoveMemory(pOutBuffer, (PCHAR)&ActHdr, sizeof(HEADER_802_11)); - FrameLen = sizeof(HEADER_802_11); - - InsertActField(pAd, (pOutBuffer + FrameLen), &FrameLen, CATEGORY_SPECTRUM, SPEC_MRQ); - - // fill Dialog Token - InsertDialogToken(pAd, (pOutBuffer + FrameLen), &FrameLen, MeasureToken); - - // prepare Measurement IE. - NdisZeroMemory(&MeasureReqIE, sizeof(MEASURE_REQ_INFO)); - MeasureReqIE.Token = RmReqDailogToken; - MeasureReqIE.ReqMode.word = MeasureReqMode; - MeasureReqIE.ReqType = MeasureReqType; - MeasureReqIE.MeasureReq.ChNum = MeasureCh; - MeasureReqIE.MeasureReq.MeasureStartTime = cpu2le64(MeasureStartTime); - MeasureReqIE.MeasureReq.MeasureDuration = cpu2le16(MeasureDuration); - InsertMeasureReqIE(pAd, (pOutBuffer + FrameLen), &FrameLen, &MeasureReqIE); - - MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); - - return; -} - -/* - ========================================================================== - Description: - Prepare Measurement report action frame and enqueue it into - management queue waiting for transmition. - - Parametrs: - 1. the destination mac address of the frame. - - Return : None. - ========================================================================== - */ -VOID EnqueueMeasurementRep( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDA, - IN UINT8 DialogToken, - IN UINT8 MeasureToken, - IN UINT8 MeasureReqMode, - IN UINT8 MeasureReqType, - IN UINT8 ReportInfoLen, - IN PUINT8 pReportInfo) -{ - PUCHAR pOutBuffer = NULL; - NDIS_STATUS NStatus; - ULONG FrameLen; - HEADER_802_11 ActHdr; - MEASURE_REPORT_INFO MeasureRepIE; - - // build action frame header. - MgtMacHeaderInit(pAd, &ActHdr, SUBTYPE_ACTION, 0, pDA, - pAd->CurrentAddress); - - NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory - if(NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __func__)); - return; - } - NdisMoveMemory(pOutBuffer, (PCHAR)&ActHdr, sizeof(HEADER_802_11)); - FrameLen = sizeof(HEADER_802_11); - - InsertActField(pAd, (pOutBuffer + FrameLen), &FrameLen, CATEGORY_SPECTRUM, SPEC_MRP); - - // fill Dialog Token - InsertDialogToken(pAd, (pOutBuffer + FrameLen), &FrameLen, DialogToken); - - // prepare Measurement IE. - NdisZeroMemory(&MeasureRepIE, sizeof(MEASURE_REPORT_INFO)); - MeasureRepIE.Token = MeasureToken; - MeasureRepIE.ReportMode.word = MeasureReqMode; - MeasureRepIE.ReportType = MeasureReqType; - InsertMeasureReportIE(pAd, (pOutBuffer + FrameLen), &FrameLen, &MeasureRepIE, ReportInfoLen, pReportInfo); - - MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); - - return; -} - -/* - ========================================================================== - Description: - Prepare TPC Request action frame and enqueue it into - management queue waiting for transmition. - - Parametrs: - 1. the destination mac address of the frame. - - Return : None. - ========================================================================== - */ -VOID EnqueueTPCReq( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDA, - IN UCHAR DialogToken) -{ - PUCHAR pOutBuffer = NULL; - NDIS_STATUS NStatus; - ULONG FrameLen; - - HEADER_802_11 ActHdr; - - // build action frame header. - MgtMacHeaderInit(pAd, &ActHdr, SUBTYPE_ACTION, 0, pDA, - pAd->CurrentAddress); - - NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory - if(NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __func__)); - return; - } - NdisMoveMemory(pOutBuffer, (PCHAR)&ActHdr, sizeof(HEADER_802_11)); - FrameLen = sizeof(HEADER_802_11); - - InsertActField(pAd, (pOutBuffer + FrameLen), &FrameLen, CATEGORY_SPECTRUM, SPEC_TPCRQ); - - // fill Dialog Token - InsertDialogToken(pAd, (pOutBuffer + FrameLen), &FrameLen, DialogToken); - - // Insert TPC Request IE. - InsertTpcReqIE(pAd, (pOutBuffer + FrameLen), &FrameLen); - - MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); - - return; -} - -/* - ========================================================================== - Description: - Prepare TPC Report action frame and enqueue it into - management queue waiting for transmition. - - Parametrs: - 1. the destination mac address of the frame. - - Return : None. - ========================================================================== - */ -VOID EnqueueTPCRep( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDA, - IN UINT8 DialogToken, - IN UINT8 TxPwr, - IN UINT8 LinkMargin) -{ - PUCHAR pOutBuffer = NULL; - NDIS_STATUS NStatus; - ULONG FrameLen; - - HEADER_802_11 ActHdr; - - // build action frame header. - MgtMacHeaderInit(pAd, &ActHdr, SUBTYPE_ACTION, 0, pDA, - pAd->CurrentAddress); - - NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory - if(NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __func__)); - return; - } - NdisMoveMemory(pOutBuffer, (PCHAR)&ActHdr, sizeof(HEADER_802_11)); - FrameLen = sizeof(HEADER_802_11); - - InsertActField(pAd, (pOutBuffer + FrameLen), &FrameLen, CATEGORY_SPECTRUM, SPEC_TPCRP); - - // fill Dialog Token - InsertDialogToken(pAd, (pOutBuffer + FrameLen), &FrameLen, DialogToken); - - // Insert TPC Request IE. - InsertTpcReportIE(pAd, (pOutBuffer + FrameLen), &FrameLen, TxPwr, LinkMargin); - - MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); - - return; -} - -/* - ========================================================================== - Description: - Prepare Channel Switch Announcement action frame and enqueue it into - management queue waiting for transmition. - - Parametrs: - 1. the destination mac address of the frame. - 2. Channel switch announcement mode. - 2. a New selected channel. - - Return : None. - ========================================================================== - */ -VOID EnqueueChSwAnn( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDA, - IN UINT8 ChSwMode, - IN UINT8 NewCh) -{ - PUCHAR pOutBuffer = NULL; - NDIS_STATUS NStatus; - ULONG FrameLen; - - HEADER_802_11 ActHdr; - - // build action frame header. - MgtMacHeaderInit(pAd, &ActHdr, SUBTYPE_ACTION, 0, pDA, - pAd->CurrentAddress); - - NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory - if(NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __func__)); - return; - } - NdisMoveMemory(pOutBuffer, (PCHAR)&ActHdr, sizeof(HEADER_802_11)); - FrameLen = sizeof(HEADER_802_11); - - InsertActField(pAd, (pOutBuffer + FrameLen), &FrameLen, CATEGORY_SPECTRUM, SPEC_CHANNEL_SWITCH); - - InsertChSwAnnIE(pAd, (pOutBuffer + FrameLen), &FrameLen, ChSwMode, NewCh, 0); - - MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); - - return; -} - -static BOOLEAN DfsRequirementCheck( - IN PRTMP_ADAPTER pAd, - IN UINT8 Channel) -{ - BOOLEAN Result = FALSE; - INT i; - - do - { - // check DFS procedure is running. - // make sure DFS procedure won't start twice. - if (pAd->CommonCfg.RadarDetect.RDMode != RD_NORMAL_MODE) - { - Result = FALSE; - break; - } - - // check the new channel carried from Channel Switch Announcemnet is valid. - for (i=0; iChannelListNum; i++) - { - if ((Channel == pAd->ChannelList[i].Channel) - &&(pAd->ChannelList[i].RemainingTimeForUse == 0)) - { - // found radar signal in the channel. the channel can't use at least for 30 minutes. - pAd->ChannelList[i].RemainingTimeForUse = 1800;//30 min = 1800 sec - Result = TRUE; - break; - } - } - } while(FALSE); - - return Result; -} - -VOID NotifyChSwAnnToPeerAPs( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pRA, - IN PUCHAR pTA, - IN UINT8 ChSwMode, - IN UINT8 Channel) -{ -#ifdef WDS_SUPPORT - if (!((pRA[0] & 0xff) == 0xff)) // is pRA a broadcase address. - { - INT i; - // info neighbor APs that Radar signal found throgh WDS link. - for (i = 0; i < MAX_WDS_ENTRY; i++) - { - if (ValidWdsEntry(pAd, i)) - { - PUCHAR pDA = pAd->WdsTab.WdsEntry[i].PeerWdsAddr; - - // DA equal to SA. have no necessary orignal AP which found Radar signal. - if (MAC_ADDR_EQUAL(pTA, pDA)) - continue; - - // send Channel Switch Action frame to info Neighbro APs. - EnqueueChSwAnn(pAd, pDA, ChSwMode, Channel); - } - } - } -#endif // WDS_SUPPORT // -} - -static VOID StartDFSProcedure( - IN PRTMP_ADAPTER pAd, - IN UCHAR Channel, - IN UINT8 ChSwMode) -{ - // start DFS procedure - pAd->CommonCfg.Channel = Channel; -#ifdef DOT11_N_SUPPORT - N_ChannelCheck(pAd); -#endif // DOT11_N_SUPPORT // - pAd->CommonCfg.RadarDetect.RDMode = RD_SWITCHING_MODE; - pAd->CommonCfg.RadarDetect.CSCount = 0; -} - -/* - ========================================================================== - Description: - Channel Switch Announcement action frame sanity check. - - Parametrs: - 1. MLME message containing the received frame - 2. message length. - 3. Channel switch announcement infomation buffer. - - - Return : None. - ========================================================================== - */ - -/* - Channel Switch Announcement IE. - +----+-----+-----------+------------+-----------+ - | ID | Len |Ch Sw Mode | New Ch Num | Ch Sw Cnt | - +----+-----+-----------+------------+-----------+ - 1 1 1 1 1 -*/ -static BOOLEAN PeerChSwAnnSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *pMsg, - IN ULONG MsgLen, - OUT PCH_SW_ANN_INFO pChSwAnnInfo) -{ - PFRAME_802_11 Fr = (PFRAME_802_11)pMsg; - PUCHAR pFramePtr = Fr->Octet; - BOOLEAN result = FALSE; - PEID_STRUCT eid_ptr; - - // skip 802.11 header. - MsgLen -= sizeof(HEADER_802_11); - - // skip category and action code. - pFramePtr += 2; - MsgLen -= 2; - - if (pChSwAnnInfo == NULL) - return result; - - eid_ptr = (PEID_STRUCT)pFramePtr; - while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((PUCHAR)pFramePtr + MsgLen)) - { - switch(eid_ptr->Eid) - { - case IE_CHANNEL_SWITCH_ANNOUNCEMENT: - NdisMoveMemory(&pChSwAnnInfo->ChSwMode, eid_ptr->Octet, 1); - NdisMoveMemory(&pChSwAnnInfo->Channel, eid_ptr->Octet + 1, 1); - NdisMoveMemory(&pChSwAnnInfo->ChSwCnt, eid_ptr->Octet + 2, 1); - - result = TRUE; - break; - - default: - break; - } - eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len); - } - - return result; -} - -/* - ========================================================================== - Description: - Measurement request action frame sanity check. - - Parametrs: - 1. MLME message containing the received frame - 2. message length. - 3. Measurement request infomation buffer. - - Return : None. - ========================================================================== - */ -static BOOLEAN PeerMeasureReqSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *pMsg, - IN ULONG MsgLen, - OUT PUINT8 pDialogToken, - OUT PMEASURE_REQ_INFO pMeasureReqInfo) -{ - PFRAME_802_11 Fr = (PFRAME_802_11)pMsg; - PUCHAR pFramePtr = Fr->Octet; - BOOLEAN result = FALSE; - PEID_STRUCT eid_ptr; - PUCHAR ptr; - UINT64 MeasureStartTime; - UINT16 MeasureDuration; - - // skip 802.11 header. - MsgLen -= sizeof(HEADER_802_11); - - // skip category and action code. - pFramePtr += 2; - MsgLen -= 2; - - if (pMeasureReqInfo == NULL) - return result; - - NdisMoveMemory(pDialogToken, pFramePtr, 1); - pFramePtr += 1; - MsgLen -= 1; - - eid_ptr = (PEID_STRUCT)pFramePtr; - while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((PUCHAR)pFramePtr + MsgLen)) - { - switch(eid_ptr->Eid) - { - case IE_MEASUREMENT_REQUEST: - NdisMoveMemory(&pMeasureReqInfo->Token, eid_ptr->Octet, 1); - NdisMoveMemory(&pMeasureReqInfo->ReqMode.word, eid_ptr->Octet + 1, 1); - NdisMoveMemory(&pMeasureReqInfo->ReqType, eid_ptr->Octet + 2, 1); - ptr = eid_ptr->Octet + 3; - NdisMoveMemory(&pMeasureReqInfo->MeasureReq.ChNum, ptr, 1); - NdisMoveMemory(&MeasureStartTime, ptr + 1, 8); - pMeasureReqInfo->MeasureReq.MeasureStartTime = SWAP64(MeasureStartTime); - NdisMoveMemory(&MeasureDuration, ptr + 9, 2); - pMeasureReqInfo->MeasureReq.MeasureDuration = SWAP16(MeasureDuration); - - result = TRUE; - break; - - default: - break; - } - eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len); - } - - return result; -} - -/* - ========================================================================== - Description: - Measurement report action frame sanity check. - - Parametrs: - 1. MLME message containing the received frame - 2. message length. - 3. Measurement report infomation buffer. - 4. basic report infomation buffer. - - Return : None. - ========================================================================== - */ - -/* - Measurement Report IE. - +----+-----+-------+-------------+--------------+----------------+ - | ID | Len | Token | Report Mode | Measure Type | Measure Report | - +----+-----+-------+-------------+--------------+----------------+ - 1 1 1 1 1 variable - - Basic Report. - +--------+------------+----------+-----+ - | Ch Num | Start Time | Duration | Map | - +--------+------------+----------+-----+ - 1 8 2 1 - - Map Field Bit Format. - +-----+---------------+---------------------+-------+------------+----------+ - | Bss | OFDM Preamble | Unidentified signal | Radar | Unmeasured | Reserved | - +-----+---------------+---------------------+-------+------------+----------+ - 0 1 2 3 4 5-7 -*/ -static BOOLEAN PeerMeasureReportSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *pMsg, - IN ULONG MsgLen, - OUT PUINT8 pDialogToken, - OUT PMEASURE_REPORT_INFO pMeasureReportInfo, - OUT PUINT8 pReportBuf) -{ - PFRAME_802_11 Fr = (PFRAME_802_11)pMsg; - PUCHAR pFramePtr = Fr->Octet; - BOOLEAN result = FALSE; - PEID_STRUCT eid_ptr; - PUCHAR ptr; - - // skip 802.11 header. - MsgLen -= sizeof(HEADER_802_11); - - // skip category and action code. - pFramePtr += 2; - MsgLen -= 2; - - if (pMeasureReportInfo == NULL) - return result; - - NdisMoveMemory(pDialogToken, pFramePtr, 1); - pFramePtr += 1; - MsgLen -= 1; - - eid_ptr = (PEID_STRUCT)pFramePtr; - while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((PUCHAR)pFramePtr + MsgLen)) - { - switch(eid_ptr->Eid) - { - case IE_MEASUREMENT_REPORT: - NdisMoveMemory(&pMeasureReportInfo->Token, eid_ptr->Octet, 1); - NdisMoveMemory(&pMeasureReportInfo->ReportMode, eid_ptr->Octet + 1, 1); - NdisMoveMemory(&pMeasureReportInfo->ReportType, eid_ptr->Octet + 2, 1); - if (pMeasureReportInfo->ReportType == RM_BASIC) - { - PMEASURE_BASIC_REPORT pReport = (PMEASURE_BASIC_REPORT)pReportBuf; - ptr = eid_ptr->Octet + 3; - NdisMoveMemory(&pReport->ChNum, ptr, 1); - NdisMoveMemory(&pReport->MeasureStartTime, ptr + 1, 8); - NdisMoveMemory(&pReport->MeasureDuration, ptr + 9, 2); - NdisMoveMemory(&pReport->Map, ptr + 11, 1); - - } - else if (pMeasureReportInfo->ReportType == RM_CCA) - { - PMEASURE_CCA_REPORT pReport = (PMEASURE_CCA_REPORT)pReportBuf; - ptr = eid_ptr->Octet + 3; - NdisMoveMemory(&pReport->ChNum, ptr, 1); - NdisMoveMemory(&pReport->MeasureStartTime, ptr + 1, 8); - NdisMoveMemory(&pReport->MeasureDuration, ptr + 9, 2); - NdisMoveMemory(&pReport->CCA_Busy_Fraction, ptr + 11, 1); - - } - else if (pMeasureReportInfo->ReportType == RM_RPI_HISTOGRAM) - { - PMEASURE_RPI_REPORT pReport = (PMEASURE_RPI_REPORT)pReportBuf; - ptr = eid_ptr->Octet + 3; - NdisMoveMemory(&pReport->ChNum, ptr, 1); - NdisMoveMemory(&pReport->MeasureStartTime, ptr + 1, 8); - NdisMoveMemory(&pReport->MeasureDuration, ptr + 9, 2); - NdisMoveMemory(&pReport->RPI_Density, ptr + 11, 8); - } - result = TRUE; - break; - - default: - break; - } - eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len); - } - - return result; -} - -/* - ========================================================================== - Description: - TPC Request action frame sanity check. - - Parametrs: - 1. MLME message containing the received frame - 2. message length. - 3. Dialog Token. - - Return : None. - ========================================================================== - */ -static BOOLEAN PeerTpcReqSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *pMsg, - IN ULONG MsgLen, - OUT PUINT8 pDialogToken) -{ - PFRAME_802_11 Fr = (PFRAME_802_11)pMsg; - PUCHAR pFramePtr = Fr->Octet; - BOOLEAN result = FALSE; - PEID_STRUCT eid_ptr; - - MsgLen -= sizeof(HEADER_802_11); - - // skip category and action code. - pFramePtr += 2; - MsgLen -= 2; - - if (pDialogToken == NULL) - return result; - - NdisMoveMemory(pDialogToken, pFramePtr, 1); - pFramePtr += 1; - MsgLen -= 1; - - eid_ptr = (PEID_STRUCT)pFramePtr; - while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((PUCHAR)pFramePtr + MsgLen)) - { - switch(eid_ptr->Eid) - { - case IE_TPC_REQUEST: - result = TRUE; - break; - - default: - break; - } - eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len); - } - - return result; -} - -/* - ========================================================================== - Description: - TPC Report action frame sanity check. - - Parametrs: - 1. MLME message containing the received frame - 2. message length. - 3. Dialog Token. - 4. TPC Report IE. - - Return : None. - ========================================================================== - */ -static BOOLEAN PeerTpcRepSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *pMsg, - IN ULONG MsgLen, - OUT PUINT8 pDialogToken, - OUT PTPC_REPORT_INFO pTpcRepInfo) -{ - PFRAME_802_11 Fr = (PFRAME_802_11)pMsg; - PUCHAR pFramePtr = Fr->Octet; - BOOLEAN result = FALSE; - PEID_STRUCT eid_ptr; - - MsgLen -= sizeof(HEADER_802_11); - - // skip category and action code. - pFramePtr += 2; - MsgLen -= 2; - - if (pDialogToken == NULL) - return result; - - NdisMoveMemory(pDialogToken, pFramePtr, 1); - pFramePtr += 1; - MsgLen -= 1; - - eid_ptr = (PEID_STRUCT)pFramePtr; - while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((PUCHAR)pFramePtr + MsgLen)) - { - switch(eid_ptr->Eid) - { - case IE_TPC_REPORT: - NdisMoveMemory(&pTpcRepInfo->TxPwr, eid_ptr->Octet, 1); - NdisMoveMemory(&pTpcRepInfo->LinkMargin, eid_ptr->Octet + 1, 1); - result = TRUE; - break; - - default: - break; - } - eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len); - } - - return result; -} - -/* - ========================================================================== - Description: - Channel Switch Announcement action frame handler. - - Parametrs: - Elme - MLME message containing the received frame - - Return : None. - ========================================================================== - */ -static VOID PeerChSwAnnAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - CH_SW_ANN_INFO ChSwAnnInfo; - PFRAME_802_11 pFr = (PFRAME_802_11)Elem->Msg; -#ifdef CONFIG_STA_SUPPORT - UCHAR index = 0, Channel = 0, NewChannel = 0; - ULONG Bssidx = 0; -#endif // CONFIG_STA_SUPPORT // - - NdisZeroMemory(&ChSwAnnInfo, sizeof(CH_SW_ANN_INFO)); - if (! PeerChSwAnnSanity(pAd, Elem->Msg, Elem->MsgLen, &ChSwAnnInfo)) - { - DBGPRINT(RT_DEBUG_TRACE, ("Invalid Channel Switch Action Frame.\n")); - return; - } - - -#ifdef CONFIG_STA_SUPPORT - if (pAd->OpMode == OPMODE_STA) - { - Bssidx = BssTableSearch(&pAd->ScanTab, pFr->Hdr.Addr3, pAd->CommonCfg.Channel); - if (Bssidx == BSS_NOT_FOUND) - { - DBGPRINT(RT_DEBUG_TRACE, ("PeerChSwAnnAction - Bssidx is not found\n")); - return; - } - - DBGPRINT(RT_DEBUG_TRACE, ("\n****Bssidx is %d, Channel = %d\n", index, pAd->ScanTab.BssEntry[Bssidx].Channel)); - hex_dump("SSID",pAd->ScanTab.BssEntry[Bssidx].Bssid ,6); - - Channel = pAd->CommonCfg.Channel; - NewChannel = ChSwAnnInfo.Channel; - - if ((pAd->CommonCfg.bIEEE80211H == 1) && (NewChannel != 0) && (Channel != NewChannel)) - { - // Switching to channel 1 can prevent from rescanning the current channel immediately (by auto reconnection). - // In addition, clear the MLME queue and the scan table to discard the RX packets and previous scanning results. - AsicSwitchChannel(pAd, 1, FALSE); - AsicLockChannel(pAd, 1); - LinkDown(pAd, FALSE); - MlmeQueueInit(&pAd->Mlme.Queue); - BssTableInit(&pAd->ScanTab); - RTMPusecDelay(1000000); // use delay to prevent STA do reassoc - - // channel sanity check - for (index = 0 ; index < pAd->ChannelListNum; index++) - { - if (pAd->ChannelList[index].Channel == NewChannel) - { - pAd->ScanTab.BssEntry[Bssidx].Channel = NewChannel; - pAd->CommonCfg.Channel = NewChannel; - AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); - AsicLockChannel(pAd, pAd->CommonCfg.Channel); - DBGPRINT(RT_DEBUG_TRACE, ("&&&&&&&&&&&&&&&&PeerChSwAnnAction - STA receive channel switch announcement IE (New Channel =%d)\n", NewChannel)); - break; - } - } - - if (index >= pAd->ChannelListNum) - { - DBGPRINT_ERR(("&&&&&&&&&&&&&&&&&&&&&&&&&&PeerChSwAnnAction(can not find New Channel=%d in ChannelList[%d]\n", pAd->CommonCfg.Channel, pAd->ChannelListNum)); - } - } - } -#endif // CONFIG_STA_SUPPORT // - - return; -} - - -/* - ========================================================================== - Description: - Measurement Request action frame handler. - - Parametrs: - Elme - MLME message containing the received frame - - Return : None. - ========================================================================== - */ -static VOID PeerMeasureReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - PFRAME_802_11 pFr = (PFRAME_802_11)Elem->Msg; - UINT8 DialogToken; - MEASURE_REQ_INFO MeasureReqInfo; - MEASURE_REPORT_MODE ReportMode; - - if(PeerMeasureReqSanity(pAd, Elem->Msg, Elem->MsgLen, &DialogToken, &MeasureReqInfo)) - { - ReportMode.word = 0; - ReportMode.field.Incapable = 1; - EnqueueMeasurementRep(pAd, pFr->Hdr.Addr2, DialogToken, MeasureReqInfo.Token, ReportMode.word, MeasureReqInfo.ReqType, 0, NULL); - } - - return; -} - -/* - ========================================================================== - Description: - Measurement Report action frame handler. - - Parametrs: - Elme - MLME message containing the received frame - - Return : None. - ========================================================================== - */ -static VOID PeerMeasureReportAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - MEASURE_REPORT_INFO MeasureReportInfo; - PFRAME_802_11 pFr = (PFRAME_802_11)Elem->Msg; - UINT8 DialogToken; - PUINT8 pMeasureReportInfo; - -// if (pAd->CommonCfg.bIEEE80211H != TRUE) -// return; - - if ((pMeasureReportInfo = kmalloc(sizeof(MEASURE_RPI_REPORT), GFP_ATOMIC)) == NULL) - { - DBGPRINT(RT_DEBUG_ERROR, ("%s unable to alloc memory for measure report buffer (size=%zu).\n", __func__, sizeof(MEASURE_RPI_REPORT))); - return; - } - - NdisZeroMemory(&MeasureReportInfo, sizeof(MEASURE_REPORT_INFO)); - NdisZeroMemory(pMeasureReportInfo, sizeof(MEASURE_RPI_REPORT)); - if (PeerMeasureReportSanity(pAd, Elem->Msg, Elem->MsgLen, &DialogToken, &MeasureReportInfo, pMeasureReportInfo)) - { - do { - PMEASURE_REQ_ENTRY pEntry = NULL; - - // Not a autonomous measure report. - // check the dialog token field. drop it if the dialog token doesn't match. - if ((DialogToken != 0) - && ((pEntry = MeasureReqLookUp(pAd, DialogToken)) == NULL)) - break; - - if (pEntry != NULL) - MeasureReqDelete(pAd, pEntry->DialogToken); - - if (MeasureReportInfo.ReportType == RM_BASIC) - { - PMEASURE_BASIC_REPORT pBasicReport = (PMEASURE_BASIC_REPORT)pMeasureReportInfo; - if ((pBasicReport->Map.field.Radar) - && (DfsRequirementCheck(pAd, pBasicReport->ChNum) == TRUE)) - { - NotifyChSwAnnToPeerAPs(pAd, pFr->Hdr.Addr1, pFr->Hdr.Addr2, 1, pBasicReport->ChNum); - StartDFSProcedure(pAd, pBasicReport->ChNum, 1); - } - } - } while (FALSE); - } - else - DBGPRINT(RT_DEBUG_TRACE, ("Invalid Measurement Report Frame.\n")); - - kfree(pMeasureReportInfo); - - return; -} - -/* - ========================================================================== - Description: - TPC Request action frame handler. - - Parametrs: - Elme - MLME message containing the received frame - - Return : None. - ========================================================================== - */ -static VOID PeerTpcReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - PFRAME_802_11 pFr = (PFRAME_802_11)Elem->Msg; - PUCHAR pFramePtr = pFr->Octet; - UINT8 DialogToken; - UINT8 TxPwr = GetCurTxPwr(pAd, Elem->Wcid); - UINT8 LinkMargin = 0; - CHAR RealRssi; - - // link margin: Ratio of the received signal power to the minimum desired by the station (STA). The - // STA may incorporate rate information and channel conditions, including interference, into its computation - // of link margin. - - RealRssi = RTMPMaxRssi(pAd, ConvertToRssi(pAd, Elem->Rssi0, RSSI_0), - ConvertToRssi(pAd, Elem->Rssi1, RSSI_1), - ConvertToRssi(pAd, Elem->Rssi2, RSSI_2)); - - // skip Category and action code. - pFramePtr += 2; - - // Dialog token. - NdisMoveMemory(&DialogToken, pFramePtr, 1); - - LinkMargin = (RealRssi / MIN_RCV_PWR); - if (PeerTpcReqSanity(pAd, Elem->Msg, Elem->MsgLen, &DialogToken)) - EnqueueTPCRep(pAd, pFr->Hdr.Addr2, DialogToken, TxPwr, LinkMargin); - - return; -} - -/* - ========================================================================== - Description: - TPC Report action frame handler. - - Parametrs: - Elme - MLME message containing the received frame - - Return : None. - ========================================================================== - */ -static VOID PeerTpcRepAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - UINT8 DialogToken; - TPC_REPORT_INFO TpcRepInfo; - PTPC_REQ_ENTRY pEntry = NULL; - - NdisZeroMemory(&TpcRepInfo, sizeof(TPC_REPORT_INFO)); - if (PeerTpcRepSanity(pAd, Elem->Msg, Elem->MsgLen, &DialogToken, &TpcRepInfo)) - { - if ((pEntry = TpcReqLookUp(pAd, DialogToken)) != NULL) - { - TpcReqDelete(pAd, pEntry->DialogToken); - DBGPRINT(RT_DEBUG_TRACE, ("%s: DialogToken=%x, TxPwr=%d, LinkMargin=%d\n", - __func__, DialogToken, TpcRepInfo.TxPwr, TpcRepInfo.LinkMargin)); - } - } - - return; -} - -/* - ========================================================================== - Description: - Spectrun action frames Handler such as channel switch annoucement, - measurement report, measurement request actions frames. - - Parametrs: - Elme - MLME message containing the received frame - - Return : None. - ========================================================================== - */ -VOID PeerSpectrumAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - - UCHAR Action = Elem->Msg[LENGTH_802_11+1]; - - if (pAd->CommonCfg.bIEEE80211H != TRUE) - return; - - switch(Action) - { - case SPEC_MRQ: - // current rt2860 unable do such measure specified in Measurement Request. - // reject all measurement request. - PeerMeasureReqAction(pAd, Elem); - break; - - case SPEC_MRP: - PeerMeasureReportAction(pAd, Elem); - break; - - case SPEC_TPCRQ: - PeerTpcReqAction(pAd, Elem); - break; - - case SPEC_TPCRP: - PeerTpcRepAction(pAd, Elem); - break; - - case SPEC_CHANNEL_SWITCH: -{ -#ifdef DOT11N_DRAFT3 - SEC_CHA_OFFSET_IE Secondary; - CHA_SWITCH_ANNOUNCE_IE ChannelSwitch; - - // 802.11h only has Channel Switch Announcement IE. - RTMPMoveMemory(&ChannelSwitch, &Elem->Msg[LENGTH_802_11+4], sizeof (CHA_SWITCH_ANNOUNCE_IE)); - - // 802.11n D3.03 adds secondary channel offset element in the end. - if (Elem->MsgLen == (LENGTH_802_11 + 2 + sizeof (CHA_SWITCH_ANNOUNCE_IE) + sizeof (SEC_CHA_OFFSET_IE))) - { - RTMPMoveMemory(&Secondary, &Elem->Msg[LENGTH_802_11+9], sizeof (SEC_CHA_OFFSET_IE)); - } - else - { - Secondary.SecondaryChannelOffset = 0; - } - - if ((Elem->Msg[LENGTH_802_11+2] == IE_CHANNEL_SWITCH_ANNOUNCEMENT) && (Elem->Msg[LENGTH_802_11+3] == 3)) - { - ChannelSwitchAction(pAd, Elem->Wcid, ChannelSwitch.NewChannel, Secondary.SecondaryChannelOffset); - } -#endif // DOT11N_DRAFT3 // -} - PeerChSwAnnAction(pAd, Elem); - break; - } - - return; -} - -/* - ========================================================================== - Description: - - Parametrs: - - Return : None. - ========================================================================== - */ -INT Set_MeasureReq_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - UINT Aid = 1; - UINT ArgIdx; - PUCHAR thisChar; - - MEASURE_REQ_MODE MeasureReqMode; - UINT8 MeasureReqToken = RandomByte(pAd); - UINT8 MeasureReqType = RM_BASIC; - UINT8 MeasureCh = 1; - - ArgIdx = 1; - while ((thisChar = strsep((char **)&arg, "-")) != NULL) - { - switch(ArgIdx) - { - case 1: // Aid. - Aid = simple_strtol(thisChar, 0, 16); - break; - - case 2: // Measurement Request Type. - MeasureReqType = simple_strtol(thisChar, 0, 16); - if (MeasureReqType > 3) - { - DBGPRINT(RT_DEBUG_ERROR, ("%s: unknow MeasureReqType(%d)\n", __func__, MeasureReqType)); - return TRUE; - } - break; - - case 3: // Measurement channel. - MeasureCh = simple_strtol(thisChar, 0, 16); - break; - } - ArgIdx++; - } - - DBGPRINT(RT_DEBUG_TRACE, ("%s::Aid = %d, MeasureReqType=%d MeasureCh=%d\n", __func__, Aid, MeasureReqType, MeasureCh)); - if (!VALID_WCID(Aid)) - { - DBGPRINT(RT_DEBUG_ERROR, ("%s: unknow sta of Aid(%d)\n", __func__, Aid)); - return TRUE; - } - - MeasureReqMode.word = 0; - MeasureReqMode.field.Enable = 1; - - MeasureReqInsert(pAd, MeasureReqToken); - - EnqueueMeasurementReq(pAd, pAd->MacTab.Content[Aid].Addr, - MeasureReqToken, MeasureReqMode.word, MeasureReqType, MeasureCh, 2000); - - return TRUE; -} - -INT Set_TpcReq_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - UINT Aid; - - UINT8 TpcReqToken = RandomByte(pAd); - - Aid = simple_strtol(arg, 0, 16); - - DBGPRINT(RT_DEBUG_TRACE, ("%s::Aid = %d\n", __func__, Aid)); - if (!VALID_WCID(Aid)) - { - DBGPRINT(RT_DEBUG_ERROR, ("%s: unknow sta of Aid(%d)\n", __func__, Aid)); - return TRUE; - } - - TpcReqInsert(pAd, TpcReqToken); - - EnqueueTPCReq(pAd, pAd->MacTab.Content[Aid].Addr, TpcReqToken); - - return TRUE; -} - +#include "../../rt2860/common/spectrum.c" diff --git a/drivers/staging/rt2870/dfs.h b/drivers/staging/rt2870/dfs.h index 752a6352d9dd..1fdbd7bc5de5 100644 --- a/drivers/staging/rt2870/dfs.h +++ b/drivers/staging/rt2870/dfs.h @@ -1,100 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - dfs.h - - Abstract: - Support DFS function. - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Fonchi 03-12-2007 created -*/ - -#define RADAR_PULSE 1 -#define RADAR_WIDTH 2 - -#define WIDTH_RD_IDLE 0 -#define WIDTH_RD_CHECK 1 - - -VOID BbpRadarDetectionStart( - IN PRTMP_ADAPTER pAd); - -VOID BbpRadarDetectionStop( - IN PRTMP_ADAPTER pAd); - -VOID RadarDetectionStart( - IN PRTMP_ADAPTER pAd, - IN BOOLEAN CTS_Protect, - IN UINT8 CTSPeriod); - -VOID RadarDetectionStop( - IN PRTMP_ADAPTER pAd); - -VOID RadarDetectPeriodic( - IN PRTMP_ADAPTER pAd); - - -BOOLEAN RadarChannelCheck( - IN PRTMP_ADAPTER pAd, - IN UCHAR Ch); - -ULONG JapRadarType( - IN PRTMP_ADAPTER pAd); - -ULONG RTMPBbpReadRadarDuration( - IN PRTMP_ADAPTER pAd); - -ULONG RTMPReadRadarDuration( - IN PRTMP_ADAPTER pAd); - -VOID RTMPCleanRadarDuration( - IN PRTMP_ADAPTER pAd); - -VOID RTMPPrepareRDCTSFrame( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDA, - IN ULONG Duration, - IN UCHAR RTSRate, - IN ULONG CTSBaseAddr, - IN UCHAR FrameGap); - -VOID RTMPPrepareRadarDetectParams( - IN PRTMP_ADAPTER pAd); - - -INT Set_ChMovingTime_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_LongPulseRadarTh_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - - +#include "../rt2860/dfs.h" diff --git a/drivers/staging/rt2870/leap.h b/drivers/staging/rt2870/leap.h deleted file mode 100644 index 6818c1ff4d73..000000000000 --- a/drivers/staging/rt2870/leap.h +++ /dev/null @@ -1,215 +0,0 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - leap.h - - Abstract: - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Name Date Modification logs -*/ -#ifndef __LEAP_H__ -#define __LEAP_H__ - -// Messages for Associate state machine -#define LEAP_MACHINE_BASE 30 - -#define LEAP_MSG_REQUEST_IDENTITY 31 -#define LEAP_MSG_REQUEST_LEAP 32 -#define LEAP_MSG_SUCCESS 33 -#define LEAP_MSG_FAILED 34 -#define LEAP_MSG_RESPONSE_LEAP 35 -#define LEAP_MSG_EAPOLKEY 36 -#define LEAP_MSG_UNKNOWN 37 -#define LEAP_MSG 38 -//! assoc state-machine states -#define LEAP_IDLE 0 -#define LEAP_WAIT_IDENTITY_REQUEST 1 -#define LEAP_WAIT_CHANLLENGE_REQUEST 2 -#define LEAP_WAIT_SUCCESS 3 -#define LEAP_WAIT_CHANLLENGE_RESPONSE 4 -#define LEAP_WAIT_EAPOLKEY 5 - -#define LEAP_REASON_INVALID_AUTH 0x01 -#define LEAP_REASON_AUTH_TIMEOUT 0x02 -#define LEAP_REASON_CHALLENGE_FROM_AP_FAILED 0x03 -#define LEAP_REASON_CHALLENGE_TO_AP_FAILED 0x04 - -#define CISCO_AuthModeLEAP 0x80 -#define CISCO_AuthModeLEAPNone 0x00 -#define LEAP_AUTH_TIMEOUT 30000 -#define LEAP_CHALLENGE_RESPONSE_LENGTH 24 -#define LEAP_CHALLENGE_REQUEST_LENGTH 8 - -typedef struct _LEAP_EAPOL_HEADER_ { - UCHAR Version; - UCHAR Type; - UCHAR Length[2]; -} LEAP_EAPOL_HEADER, *PLEAP_EAPOL_HEADER; - -typedef struct _LEAP_EAPOL_PACKET_ { - UCHAR Code; - UCHAR Identifier; - UCHAR Length[2]; - UCHAR Type; -} LEAP_EAPOL_PACKET, *PLEAP_EAPOL_PACKET; - -typedef struct _LEAP_EAP_CONTENTS_ { - UCHAR Version; - UCHAR Reserved; - UCHAR Length; -} LEAP_EAP_CONTENTS, *PLEAP_EAP_CONTENTS; - -/*** EAPOL key ***/ -typedef struct _EAPOL_KEY_HEADER_ { - UCHAR Type; - UCHAR Length[2]; - UCHAR Counter[8]; - UCHAR IV[16]; - UCHAR Index; - UCHAR Signature[16]; -} EAPOL_KEY_HEADER, *PEAPOL_KEY_HEADER; - -BOOLEAN LeapMsgTypeSubst( - IN UCHAR EAPType, - OUT ULONG *MsgType); - -VOID LeapMachinePerformAction( - IN PRTMP_ADAPTER pAd, - IN STATE_MACHINE *S, - IN MLME_QUEUE_ELEM *Elem); - -VOID LeapMacHeaderInit( - IN PRTMP_ADAPTER pAd, - IN OUT PHEADER_802_11 pHdr80211, - IN UCHAR wep, - IN PUCHAR pAddr3); - -VOID LeapStartAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID LeapIdentityAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID LeapPeerChallengeAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID HashPwd( - IN PUCHAR pwd, - IN INT pwdlen, - OUT PUCHAR hash); - -VOID PeerChallengeResponse( - IN PUCHAR szChallenge, - IN PUCHAR smbPasswd, - OUT PUCHAR szResponse); - -VOID ParityKey( - OUT PUCHAR szOut, - IN PUCHAR szIn); - -VOID DesKey( - OUT ULONG k[16][2], - IN PUCHAR key, - IN INT decrypt); - -VOID Des( - IN ULONG ks[16][2], - OUT UCHAR block[8]); - -VOID DesEncrypt( - IN PUCHAR szClear, - IN PUCHAR szKey, - OUT PUCHAR szOut); - -VOID LeapNetworkChallengeAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID LeapNetworkChallengeResponse( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID HashpwdHash( - IN PUCHAR hash, - IN PUCHAR hashhash); - -VOID ProcessSessionKey( - OUT PUCHAR SessionKey, - IN PUCHAR hash2, - IN PUCHAR ChallengeToRadius, - IN PUCHAR ChallengeResponseFromRadius, - IN PUCHAR ChallengeFromRadius, - IN PUCHAR ChallengeResponseToRadius); - -VOID LeapEapolKeyAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID RogueApTableInit( - IN ROGUEAP_TABLE *Tab); - -ULONG RogueApTableSearch( - IN ROGUEAP_TABLE *Tab, - IN PUCHAR pAddr); - -VOID RogueApEntrySet( - IN PRTMP_ADAPTER pAd, - OUT ROGUEAP_ENTRY *pRogueAp, - IN PUCHAR pAddr, - IN UCHAR FaileCode); - -ULONG RogueApTableSetEntry( - IN PRTMP_ADAPTER pAd, - OUT ROGUEAP_TABLE *Tab, - IN PUCHAR pAddr, - IN UCHAR FaileCode); - -VOID RogueApTableDeleteEntry( - IN OUT ROGUEAP_TABLE *Tab, - IN PUCHAR pAddr); - -VOID LeapAuthTimeout( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); - -VOID LeapSendRogueAPReport( - IN PRTMP_ADAPTER pAd); - -BOOLEAN CCKMAssocRspSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen); - -#endif // __LEAP_H__ diff --git a/drivers/staging/rt2870/link_list.h b/drivers/staging/rt2870/link_list.h index f6521133fd5e..2589f3470390 100644 --- a/drivers/staging/rt2870/link_list.h +++ b/drivers/staging/rt2870/link_list.h @@ -1,134 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - */ - -#ifndef __LINK_LIST_H__ -#define __LINK_LIST_H__ - -typedef struct _LIST_ENTRY -{ - struct _LIST_ENTRY *pNext; -} LIST_ENTRY, *PLIST_ENTRY; - -typedef struct _LIST_HEADR -{ - PLIST_ENTRY pHead; - PLIST_ENTRY pTail; - UCHAR size; -} LIST_HEADER, *PLIST_HEADER; - -static inline VOID initList( - IN PLIST_HEADER pList) -{ - pList->pHead = pList->pTail = NULL; - pList->size = 0; - return; -} - -static inline VOID insertTailList( - IN PLIST_HEADER pList, - IN PLIST_ENTRY pEntry) -{ - pEntry->pNext = NULL; - if (pList->pTail) - pList->pTail->pNext = pEntry; - else - pList->pHead = pEntry; - pList->pTail = pEntry; - pList->size++; - - return; -} - -static inline PLIST_ENTRY removeHeadList( - IN PLIST_HEADER pList) -{ - PLIST_ENTRY pNext; - PLIST_ENTRY pEntry; - - pEntry = pList->pHead; - if (pList->pHead != NULL) - { - pNext = pList->pHead->pNext; - pList->pHead = pNext; - if (pNext == NULL) - pList->pTail = NULL; - pList->size--; - } - return pEntry; -} - -static inline int getListSize( - IN PLIST_HEADER pList) -{ - return pList->size; -} - -static inline PLIST_ENTRY delEntryList( - IN PLIST_HEADER pList, - IN PLIST_ENTRY pEntry) -{ - PLIST_ENTRY pCurEntry; - PLIST_ENTRY pPrvEntry; - - if(pList->pHead == NULL) - return NULL; - - if(pEntry == pList->pHead) - { - pCurEntry = pList->pHead; - pList->pHead = pCurEntry->pNext; - - if(pList->pHead == NULL) - pList->pTail = NULL; - - pList->size--; - return pCurEntry; - } - - pPrvEntry = pList->pHead; - pCurEntry = pPrvEntry->pNext; - while(pCurEntry != NULL) - { - if (pEntry == pCurEntry) - { - pPrvEntry->pNext = pCurEntry->pNext; - - if(pEntry == pList->pTail) - pList->pTail = pPrvEntry; - - pList->size--; - break; - } - pPrvEntry = pCurEntry; - pCurEntry = pPrvEntry->pNext; - } - - return pCurEntry; -} - -#endif // ___LINK_LIST_H__ // - +#include "../rt2860/link_list.h" diff --git a/drivers/staging/rt2870/md5.h b/drivers/staging/rt2870/md5.h index d85db12170d5..d60cd05b54f7 100644 --- a/drivers/staging/rt2870/md5.h +++ b/drivers/staging/rt2870/md5.h @@ -1,107 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - md5.h - - Abstract: - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Name Date Modification logs - jan 10-28-03 Initial - Rita 11-23-04 Modify MD5 and SHA-1 -*/ - -#ifndef uint8 -#define uint8 unsigned char -#endif - -#ifndef uint32 -#define uint32 unsigned long int -#endif - - -#ifndef __MD5_H__ -#define __MD5_H__ - -#define MD5_MAC_LEN 16 - -typedef struct _MD5_CTX { - UINT32 Buf[4]; // buffers of four states - UCHAR Input[64]; // input message - UINT32 LenInBitCount[2]; // length counter for input message, 0 up to 64 bits -} MD5_CTX; - -VOID MD5Init(MD5_CTX *pCtx); -VOID MD5Update(MD5_CTX *pCtx, UCHAR *pData, UINT32 LenInBytes); -VOID MD5Final(UCHAR Digest[16], MD5_CTX *pCtx); -VOID MD5Transform(UINT32 Buf[4], UINT32 Mes[16]); - -void md5_mac(u8 *key, size_t key_len, u8 *data, size_t data_len, u8 *mac); -void hmac_md5(u8 *key, size_t key_len, u8 *data, size_t data_len, u8 *mac); - -// -// SHA context -// -typedef struct _SHA_CTX -{ - UINT32 Buf[5]; // buffers of five states - UCHAR Input[80]; // input message - UINT32 LenInBitCount[2]; // length counter for input message, 0 up to 64 bits - -} SHA_CTX; - -VOID SHAInit(SHA_CTX *pCtx); -UCHAR SHAUpdate(SHA_CTX *pCtx, UCHAR *pData, UINT32 LenInBytes); -VOID SHAFinal(SHA_CTX *pCtx, UCHAR Digest[20]); -VOID SHATransform(UINT32 Buf[5], UINT32 Mes[20]); - -#define SHA_DIGEST_LEN 20 -#endif // __MD5_H__ - -/******************************************************************************/ -#ifndef _AES_H -#define _AES_H - -typedef struct -{ - uint32 erk[64]; /* encryption round keys */ - uint32 drk[64]; /* decryption round keys */ - int nr; /* number of rounds */ -} -aes_context; - -int rtmp_aes_set_key( aes_context *ctx, uint8 *key, int nbits ); -void rtmp_aes_encrypt( aes_context *ctx, uint8 input[16], uint8 output[16] ); -void rtmp_aes_decrypt( aes_context *ctx, uint8 input[16], uint8 output[16] ); - -void F(char *password, unsigned char *ssid, int ssidlength, int iterations, int count, unsigned char *output); -int PasswordHash(char *password, unsigned char *ssid, int ssidlength, unsigned char *output); - -#endif /* aes.h */ - +#include "../rt2860/md5.h" diff --git a/drivers/staging/rt2870/mlme.h b/drivers/staging/rt2870/mlme.h index 52fb8e1c2906..58753ac441de 100644 --- a/drivers/staging/rt2870/mlme.h +++ b/drivers/staging/rt2870/mlme.h @@ -1,1471 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - mlme.h - - Abstract: - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - John Chang 2003-08-28 Created - John Chang 2004-09-06 modified for RT2600 - -*/ -#ifndef __MLME_H__ -#define __MLME_H__ - -//extern UCHAR BROADCAST_ADDR[]; - -// maximum supported capability information - -// ESS, IBSS, Privacy, Short Preamble, Spectrum mgmt, Short Slot -#define SUPPORTED_CAPABILITY_INFO 0x0533 - -#define END_OF_ARGS -1 -#define LFSR_MASK 0x80000057 -#define MLME_TASK_EXEC_INTV 100/*200*/ // -#define LEAD_TIME 5 -#define MLME_TASK_EXEC_MULTIPLE 10 /*5*/ // MLME_TASK_EXEC_MULTIPLE * MLME_TASK_EXEC_INTV = 1 sec -#define REORDER_EXEC_INTV 100 // 0.1 sec -//#define TBTT_PRELOAD_TIME 384 // usec. LomgPreamble + 24-byte at 1Mbps - -// The definition of Radar detection duration region -#define CE 0 -#define FCC 1 -#define JAP 2 -#define JAP_W53 3 -#define JAP_W56 4 -#define MAX_RD_REGION 5 - -#ifdef NDIS51_MINIPORT -#define BEACON_LOST_TIME 4000 // 2048 msec = 2 sec -#else -#define BEACON_LOST_TIME 4 * OS_HZ // 2048 msec = 2 sec -#endif - -#define DLS_TIMEOUT 1200 // unit: msec -#define AUTH_TIMEOUT 300 // unit: msec -#define ASSOC_TIMEOUT 300 // unit: msec -#define JOIN_TIMEOUT 2 * OS_HZ // unit: msec -#define SHORT_CHANNEL_TIME 90 // unit: msec -#define MIN_CHANNEL_TIME 110 // unit: msec, for dual band scan -#define MAX_CHANNEL_TIME 140 // unit: msec, for single band scan -#define FAST_ACTIVE_SCAN_TIME 30 // Active scan waiting for probe response time -#define CW_MIN_IN_BITS 4 // actual CwMin = 2^CW_MIN_IN_BITS - 1 - - -#ifdef CONFIG_STA_SUPPORT -#ifndef CONFIG_AP_SUPPORT -#define CW_MAX_IN_BITS 10 // actual CwMax = 2^CW_MAX_IN_BITS - 1 -#endif -#endif // CONFIG_STA_SUPPORT // - -#ifdef CONFIG_APSTA_MIXED_SUPPORT -extern UINT32 CW_MAX_IN_BITS; -#endif // CONFIG_APSTA_MIXED_SUPPORT // - -// Note: RSSI_TO_DBM_OFFSET has been changed to variable for new RF (2004-0720). -// SHould not refer to this constant anymore -//#define RSSI_TO_DBM_OFFSET 120 // for RT2530 RSSI-115 = dBm -#define RSSI_FOR_MID_TX_POWER -55 // -55 db is considered mid-distance -#define RSSI_FOR_LOW_TX_POWER -45 // -45 db is considered very short distance and - // eligible to use a lower TX power -#define RSSI_FOR_LOWEST_TX_POWER -30 -//#define MID_TX_POWER_DELTA 0 // 0 db from full TX power upon mid-distance to AP -#define LOW_TX_POWER_DELTA 6 // -3 db from full TX power upon very short distance. 1 grade is 0.5 db -#define LOWEST_TX_POWER_DELTA 16 // -8 db from full TX power upon shortest distance. 1 grade is 0.5 db - -#define RSSI_TRIGGERED_UPON_BELOW_THRESHOLD 0 -#define RSSI_TRIGGERED_UPON_EXCCEED_THRESHOLD 1 -#define RSSI_THRESHOLD_FOR_ROAMING 25 -#define RSSI_DELTA 5 - -// Channel Quality Indication -#define CQI_IS_GOOD(cqi) ((cqi) >= 50) -//#define CQI_IS_FAIR(cqi) (((cqi) >= 20) && ((cqi) < 50)) -#define CQI_IS_POOR(cqi) (cqi < 50) //(((cqi) >= 5) && ((cqi) < 20)) -#define CQI_IS_BAD(cqi) (cqi < 5) -#define CQI_IS_DEAD(cqi) (cqi == 0) - -// weighting factor to calculate Channel quality, total should be 100% -#define RSSI_WEIGHTING 50 -#define TX_WEIGHTING 30 -#define RX_WEIGHTING 20 - -//#define PEER_KEY_NOT_USED 0 -//#define PEER_KEY_64_BIT 64 -//#define PEER_KEY_128_BIT 128 - -//#define PEER_KEY_64BIT_LEN 8 -//#define PEER_KEY_128BIT_LEN 16 - -#define BSS_NOT_FOUND 0xFFFFFFFF - - -#ifdef CONFIG_STA_SUPPORT -#define MAX_LEN_OF_MLME_QUEUE 40 //10 -#endif // CONFIG_STA_SUPPORT // - -#define SCAN_PASSIVE 18 // scan with no probe request, only wait beacon and probe response -#define SCAN_ACTIVE 19 // scan with probe request, and wait beacon and probe response -#define SCAN_CISCO_PASSIVE 20 // Single channel passive scan -#define SCAN_CISCO_ACTIVE 21 // Single channel active scan -#define SCAN_CISCO_NOISE 22 // Single channel passive scan for noise histogram collection -#define SCAN_CISCO_CHANNEL_LOAD 23 // Single channel passive scan for channel load collection -#define FAST_SCAN_ACTIVE 24 // scan with probe request, and wait beacon and probe response - -#ifdef DOT11N_DRAFT3 -#define SCAN_2040_BSS_COEXIST 26 -#endif // DOT11N_DRAFT3 // - -//#define BSS_TABLE_EMPTY(x) ((x).BssNr == 0) -#define MAC_ADDR_IS_GROUP(Addr) (((Addr[0]) & 0x01)) -#define MAC_ADDR_HASH(Addr) (Addr[0] ^ Addr[1] ^ Addr[2] ^ Addr[3] ^ Addr[4] ^ Addr[5]) -#define MAC_ADDR_HASH_INDEX(Addr) (MAC_ADDR_HASH(Addr) % HASH_TABLE_SIZE) -#define TID_MAC_HASH(Addr,TID) (TID^Addr[0] ^ Addr[1] ^ Addr[2] ^ Addr[3] ^ Addr[4] ^ Addr[5]) -#define TID_MAC_HASH_INDEX(Addr,TID) (TID_MAC_HASH(Addr,TID) % HASH_TABLE_SIZE) - -// LED Control -// assoiation ON. one LED ON. another blinking when TX, OFF when idle -// no association, both LED off -#define ASIC_LED_ACT_ON(pAd) RTMP_IO_WRITE32(pAd, MAC_CSR14, 0x00031e46) -#define ASIC_LED_ACT_OFF(pAd) RTMP_IO_WRITE32(pAd, MAC_CSR14, 0x00001e46) - -// bit definition of the 2-byte pBEACON->Capability field -#define CAP_IS_ESS_ON(x) (((x) & 0x0001) != 0) -#define CAP_IS_IBSS_ON(x) (((x) & 0x0002) != 0) -#define CAP_IS_CF_POLLABLE_ON(x) (((x) & 0x0004) != 0) -#define CAP_IS_CF_POLL_REQ_ON(x) (((x) & 0x0008) != 0) -#define CAP_IS_PRIVACY_ON(x) (((x) & 0x0010) != 0) -#define CAP_IS_SHORT_PREAMBLE_ON(x) (((x) & 0x0020) != 0) -#define CAP_IS_PBCC_ON(x) (((x) & 0x0040) != 0) -#define CAP_IS_AGILITY_ON(x) (((x) & 0x0080) != 0) -#define CAP_IS_SPECTRUM_MGMT(x) (((x) & 0x0100) != 0) // 802.11e d9 -#define CAP_IS_QOS(x) (((x) & 0x0200) != 0) // 802.11e d9 -#define CAP_IS_SHORT_SLOT(x) (((x) & 0x0400) != 0) -#define CAP_IS_APSD(x) (((x) & 0x0800) != 0) // 802.11e d9 -#define CAP_IS_IMMED_BA(x) (((x) & 0x1000) != 0) // 802.11e d9 -#define CAP_IS_DSSS_OFDM(x) (((x) & 0x2000) != 0) -#define CAP_IS_DELAY_BA(x) (((x) & 0x4000) != 0) // 802.11e d9 - -#define CAP_GENERATE(ess,ibss,priv,s_pre,s_slot,spectrum) (((ess) ? 0x0001 : 0x0000) | ((ibss) ? 0x0002 : 0x0000) | ((priv) ? 0x0010 : 0x0000) | ((s_pre) ? 0x0020 : 0x0000) | ((s_slot) ? 0x0400 : 0x0000) | ((spectrum) ? 0x0100 : 0x0000)) - -//#define STA_QOS_CAPABILITY 0 // 1-byte. see 802.11e d9.0 for bit definition - -#define ERP_IS_NON_ERP_PRESENT(x) (((x) & 0x01) != 0) // 802.11g -#define ERP_IS_USE_PROTECTION(x) (((x) & 0x02) != 0) // 802.11g -#define ERP_IS_USE_BARKER_PREAMBLE(x) (((x) & 0x04) != 0) // 802.11g - -#define DRS_TX_QUALITY_WORST_BOUND 8// 3 // just test by gary -#define DRS_PENALTY 8 - -#define BA_NOTUSE 2 -//BA Policy subfiled value in ADDBA frame -#define IMMED_BA 1 -#define DELAY_BA 0 - -// BA Initiator subfield in DELBA frame -#define ORIGINATOR 1 -#define RECIPIENT 0 - -// ADDBA Status Code -#define ADDBA_RESULTCODE_SUCCESS 0 -#define ADDBA_RESULTCODE_REFUSED 37 -#define ADDBA_RESULTCODE_INVALID_PARAMETERS 38 - -// DELBA Reason Code -#define DELBA_REASONCODE_QSTA_LEAVING 36 -#define DELBA_REASONCODE_END_BA 37 -#define DELBA_REASONCODE_UNKNOWN_BA 38 -#define DELBA_REASONCODE_TIMEOUT 39 - -// reset all OneSecTx counters -#define RESET_ONE_SEC_TX_CNT(__pEntry) \ -if (((__pEntry)) != NULL) \ -{ \ - (__pEntry)->OneSecTxRetryOkCount = 0; \ - (__pEntry)->OneSecTxFailCount = 0; \ - (__pEntry)->OneSecTxNoRetryOkCount = 0; \ -} - -// -// 802.11 frame formats -// -// HT Capability INFO field in HT Cap IE . -typedef struct PACKED { -#ifdef RT_BIG_ENDIAN - USHORT LSIGTxopProSup:1; - USHORT Forty_Mhz_Intolerant:1; - USHORT PSMP:1; - USHORT CCKmodein40:1; - USHORT AMsduSize:1; - USHORT DelayedBA:1; //rt2860c not support - USHORT RxSTBC:2; - USHORT TxSTBC:1; - USHORT ShortGIfor40:1; //for40MHz - USHORT ShortGIfor20:1; - USHORT GF:1; //green field - USHORT MimoPs:2;//momi power safe - USHORT ChannelWidth:1; - USHORT AdvCoding:1; -#else - USHORT AdvCoding:1; - USHORT ChannelWidth:1; - USHORT MimoPs:2;//momi power safe - USHORT GF:1; //green field - USHORT ShortGIfor20:1; - USHORT ShortGIfor40:1; //for40MHz - USHORT TxSTBC:1; - USHORT RxSTBC:2; - USHORT DelayedBA:1; //rt2860c not support - USHORT AMsduSize:1; // only support as zero - USHORT CCKmodein40:1; - USHORT PSMP:1; - USHORT Forty_Mhz_Intolerant:1; - USHORT LSIGTxopProSup:1; -#endif /* !RT_BIG_ENDIAN */ -} HT_CAP_INFO, *PHT_CAP_INFO; - -// HT Capability INFO field in HT Cap IE . -typedef struct PACKED { -#ifdef RT_BIG_ENDIAN - UCHAR rsv:3;//momi power safe - UCHAR MpduDensity:3; - UCHAR MaxRAmpduFactor:2; -#else - UCHAR MaxRAmpduFactor:2; - UCHAR MpduDensity:3; - UCHAR rsv:3;//momi power safe -#endif /* !RT_BIG_ENDIAN */ -} HT_CAP_PARM, *PHT_CAP_PARM; - -// HT Capability INFO field in HT Cap IE . -typedef struct PACKED { - UCHAR MCSSet[10]; - UCHAR SupRate[2]; // unit : 1Mbps -#ifdef RT_BIG_ENDIAN - UCHAR rsv:3; - UCHAR MpduDensity:1; - UCHAR TxStream:2; - UCHAR TxRxNotEqual:1; - UCHAR TxMCSSetDefined:1; -#else - UCHAR TxMCSSetDefined:1; - UCHAR TxRxNotEqual:1; - UCHAR TxStream:2; - UCHAR MpduDensity:1; - UCHAR rsv:3; -#endif // RT_BIG_ENDIAN // - UCHAR rsv3[3]; -} HT_MCS_SET, *PHT_MCS_SET; - -// HT Capability INFO field in HT Cap IE . -typedef struct PACKED { -#ifdef RT_BIG_ENDIAN - USHORT rsv2:4; - USHORT RDGSupport:1; //reverse Direction Grant support - USHORT PlusHTC:1; //+HTC control field support - USHORT MCSFeedback:2; //0:no MCS feedback, 2:unsolicited MCS feedback, 3:Full MCS feedback, 1:rsv. - USHORT rsv:5;//momi power safe - USHORT TranTime:2; - USHORT Pco:1; -#else - USHORT Pco:1; - USHORT TranTime:2; - USHORT rsv:5;//momi power safe - USHORT MCSFeedback:2; //0:no MCS feedback, 2:unsolicited MCS feedback, 3:Full MCS feedback, 1:rsv. - USHORT PlusHTC:1; //+HTC control field support - USHORT RDGSupport:1; //reverse Direction Grant support - USHORT rsv2:4; -#endif /* RT_BIG_ENDIAN */ -} EXT_HT_CAP_INFO, *PEXT_HT_CAP_INFO; - -// HT Beamforming field in HT Cap IE . -typedef struct PACKED _HT_BF_CAP{ -#ifdef RT_BIG_ENDIAN - ULONG rsv:3; - ULONG ChanEstimation:2; - ULONG CSIRowBFSup:2; - ULONG ComSteerBFAntSup:2; - ULONG NoComSteerBFAntSup:2; - ULONG CSIBFAntSup:2; - ULONG MinGrouping:2; - ULONG ExpComBF:2; - ULONG ExpNoComBF:2; - ULONG ExpCSIFbk:2; - ULONG ExpComSteerCapable:1; - ULONG ExpNoComSteerCapable:1; - ULONG ExpCSICapable:1; - ULONG Calibration:2; - ULONG ImpTxBFCapable:1; - ULONG TxNDPCapable:1; - ULONG RxNDPCapable:1; - ULONG TxSoundCapable:1; - ULONG RxSoundCapable:1; - ULONG TxBFRecCapable:1; -#else - ULONG TxBFRecCapable:1; - ULONG RxSoundCapable:1; - ULONG TxSoundCapable:1; - ULONG RxNDPCapable:1; - ULONG TxNDPCapable:1; - ULONG ImpTxBFCapable:1; - ULONG Calibration:2; - ULONG ExpCSICapable:1; - ULONG ExpNoComSteerCapable:1; - ULONG ExpComSteerCapable:1; - ULONG ExpCSIFbk:2; - ULONG ExpNoComBF:2; - ULONG ExpComBF:2; - ULONG MinGrouping:2; - ULONG CSIBFAntSup:2; - ULONG NoComSteerBFAntSup:2; - ULONG ComSteerBFAntSup:2; - ULONG CSIRowBFSup:2; - ULONG ChanEstimation:2; - ULONG rsv:3; -#endif // RT_BIG_ENDIAN // -} HT_BF_CAP, *PHT_BF_CAP; - -// HT antenna selection field in HT Cap IE . -typedef struct PACKED _HT_AS_CAP{ -#ifdef RT_BIG_ENDIAN - UCHAR rsv:1; - UCHAR TxSoundPPDU:1; - UCHAR RxASel:1; - UCHAR AntIndFbk:1; - UCHAR ExpCSIFbk:1; - UCHAR AntIndFbkTxASEL:1; - UCHAR ExpCSIFbkTxASEL:1; - UCHAR AntSelect:1; -#else - UCHAR AntSelect:1; - UCHAR ExpCSIFbkTxASEL:1; - UCHAR AntIndFbkTxASEL:1; - UCHAR ExpCSIFbk:1; - UCHAR AntIndFbk:1; - UCHAR RxASel:1; - UCHAR TxSoundPPDU:1; - UCHAR rsv:1; -#endif // RT_BIG_ENDIAN // -} HT_AS_CAP, *PHT_AS_CAP; - -// Draft 1.0 set IE length 26, but is extensible.. -#define SIZE_HT_CAP_IE 26 -// The structure for HT Capability IE. -typedef struct PACKED _HT_CAPABILITY_IE{ - HT_CAP_INFO HtCapInfo; - HT_CAP_PARM HtCapParm; -// HT_MCS_SET HtMCSSet; - UCHAR MCSSet[16]; - EXT_HT_CAP_INFO ExtHtCapInfo; - HT_BF_CAP TxBFCap; // beamforming cap. rt2860c not support beamforming. - HT_AS_CAP ASCap; //antenna selection. -} HT_CAPABILITY_IE, *PHT_CAPABILITY_IE; - - -// 802.11n draft3 related structure definitions. -// 7.3.2.60 -#define dot11OBSSScanPassiveDwell 20 // in TU. min amount of time that the STA continously scans each channel when performing an active OBSS scan. -#define dot11OBSSScanActiveDwell 10 // in TU.min amount of time that the STA continously scans each channel when performing an passive OBSS scan. -#define dot11BSSWidthTriggerScanInterval 300 // in sec. max interval between scan operations to be performed to detect BSS channel width trigger events. -#define dot11OBSSScanPassiveTotalPerChannel 200 // in TU. min total amount of time that the STA scans each channel when performing a passive OBSS scan. -#define dot11OBSSScanActiveTotalPerChannel 20 //in TU. min total amount of time that the STA scans each channel when performing a active OBSS scan -#define dot11BSSWidthChannelTransactionDelayFactor 5 // min ratio between the delay time in performing a switch from 20MHz BSS to 20/40 BSS operation and the maxima - // interval between overlapping BSS scan operations. -#define dot11BSSScanActivityThreshold 25 // in %%, max total time that a STA may be active on the medium during a period of - // (dot11BSSWidthChannelTransactionDelayFactor * dot11BSSWidthTriggerScanInterval) seconds without - // being obligated to perform OBSS Scan operations. default is 25(== 0.25%) - -typedef struct PACKED _OVERLAP_BSS_SCAN_IE{ - USHORT ScanPassiveDwell; - USHORT ScanActiveDwell; - USHORT TriggerScanInt; // Trigger scan interval - USHORT PassiveTalPerChannel; // passive total per channel - USHORT ActiveTalPerChannel; // active total per channel - USHORT DelayFactor; // BSS width channel transition delay factor - USHORT ScanActThre; // Scan Activity threshold -}OVERLAP_BSS_SCAN_IE, *POVERLAP_BSS_SCAN_IE; - - -// 7.3.2.56. 20/40 Coexistence element used in Element ID = 72 = IE_2040_BSS_COEXIST -typedef union PACKED _BSS_2040_COEXIST_IE{ - struct PACKED { - #ifdef RT_BIG_ENDIAN - UCHAR rsv:5; - UCHAR BSS20WidthReq:1; - UCHAR Intolerant40:1; - UCHAR InfoReq:1; - #else - UCHAR InfoReq:1; - UCHAR Intolerant40:1; // Inter-BSS. set 1 when prohibits a receiving BSS from operating as a 20/40 Mhz BSS. - UCHAR BSS20WidthReq:1; // Intra-BSS set 1 when prohibits a receiving AP from operating its BSS as a 20/40MHz BSS. - UCHAR rsv:5; -#endif // RT_BIG_ENDIAN // - } field; - UCHAR word; -} BSS_2040_COEXIST_IE, *PBSS_2040_COEXIST_IE; - - -typedef struct _TRIGGER_EVENTA{ - BOOLEAN bValid; - UCHAR BSSID[6]; - UCHAR RegClass; // Regulatory Class - USHORT Channel; - ULONG CDCounter; // Maintain a seperate count down counter for each Event A. -} TRIGGER_EVENTA, *PTRIGGER_EVENTA; - -// 20/40 trigger event table -// If one Event A delete or created, or if Event B is detected or not detected, STA should send 2040BSSCoexistence to AP. -#define MAX_TRIGGER_EVENT 64 -typedef struct _TRIGGER_EVENT_TAB{ - UCHAR EventANo; - TRIGGER_EVENTA EventA[MAX_TRIGGER_EVENT]; - ULONG EventBCountDown; // Count down counter for Event B. -} TRIGGER_EVENT_TAB, *PTRIGGER_EVENT_TAB; - -// 7.3.27 20/40 Bss Coexistence Mgmt capability used in extended capabilities information IE( ID = 127 = IE_EXT_CAPABILITY). -// This is the first octet and was defined in 802.11n D3.03 and 802.11yD9.0 -typedef struct PACKED _EXT_CAP_INFO_ELEMENT{ -#ifdef RT_BIG_ENDIAN - UCHAR rsv2:5; - UCHAR ExtendChannelSwitch:1; - UCHAR rsv:1; - UCHAR BssCoexistMgmtSupport:1; -#else - UCHAR BssCoexistMgmtSupport:1; - UCHAR rsv:1; - UCHAR ExtendChannelSwitch:1; - UCHAR rsv2:5; -#endif // RT_BIG_ENDIAN // -}EXT_CAP_INFO_ELEMENT, *PEXT_CAP_INFO_ELEMENT; - - -// 802.11n 7.3.2.61 -typedef struct PACKED _BSS_2040_COEXIST_ELEMENT{ - UCHAR ElementID; // ID = IE_2040_BSS_COEXIST = 72 - UCHAR Len; - BSS_2040_COEXIST_IE BssCoexistIe; -}BSS_2040_COEXIST_ELEMENT, *PBSS_2040_COEXIST_ELEMENT; - - -//802.11n 7.3.2.59 -typedef struct PACKED _BSS_2040_INTOLERANT_CH_REPORT{ - UCHAR ElementID; // ID = IE_2040_BSS_INTOLERANT_REPORT = 73 - UCHAR Len; - UCHAR RegulatoryClass; - UCHAR ChList[0]; -}BSS_2040_INTOLERANT_CH_REPORT, *PBSS_2040_INTOLERANT_CH_REPORT; - - -// The structure for channel switch annoucement IE. This is in 802.11n D3.03 -typedef struct PACKED _CHA_SWITCH_ANNOUNCE_IE{ - UCHAR SwitchMode; //channel switch mode - UCHAR NewChannel; // - UCHAR SwitchCount; // -} CHA_SWITCH_ANNOUNCE_IE, *PCHA_SWITCH_ANNOUNCE_IE; - - -// The structure for channel switch annoucement IE. This is in 802.11n D3.03 -typedef struct PACKED _SEC_CHA_OFFSET_IE{ - UCHAR SecondaryChannelOffset; // 1: Secondary above, 3: Secondary below, 0: no Secondary -} SEC_CHA_OFFSET_IE, *PSEC_CHA_OFFSET_IE; - - -// This structure is extracted from struct RT_HT_CAPABILITY -typedef struct { - BOOLEAN bHtEnable; // If we should use ht rate. - BOOLEAN bPreNHt; // If we should use ht rate. - //Substract from HT Capability IE - UCHAR MCSSet[16]; //only supoort MCS=0-15,32 , -} RT_HT_PHY_INFO, *PRT_HT_PHY_INFO; - -//This structure substracts ralink supports from all 802.11n-related features. -//Features not listed here but contained in 802.11n spec are not supported in rt2860. -typedef struct { -#if 0 // move to - BOOLEAN bHtEnable; // If we should use ht rate. - BOOLEAN bPreNHt; // If we should use ht rate. - //Substract from HT Capability IE - UCHAR MCSSet[16]; //only supoort MCS=0-15,32 , -#endif -#ifdef RT_BIG_ENDIAN - USHORT rsv:5; - USHORT AmsduSize:1; // Max receiving A-MSDU size - USHORT AmsduEnable:1; // Enable to transmit A-MSDU. Suggest disable. We should use A-MPDU to gain best benifit of 802.11n - USHORT RxSTBC:2; // 2 bits - USHORT TxSTBC:1; - USHORT ShortGIfor40:1; //for40MHz - USHORT ShortGIfor20:1; - USHORT GF:1; //green field - USHORT MimoPs:2;//mimo power safe MMPS_ - USHORT ChannelWidth:1; -#else - USHORT ChannelWidth:1; - USHORT MimoPs:2;//mimo power safe MMPS_ - USHORT GF:1; //green field - USHORT ShortGIfor20:1; - USHORT ShortGIfor40:1; //for40MHz - USHORT TxSTBC:1; - USHORT RxSTBC:2; // 2 bits - USHORT AmsduEnable:1; // Enable to transmit A-MSDU. Suggest disable. We should use A-MPDU to gain best benifit of 802.11n - USHORT AmsduSize:1; // Max receiving A-MSDU size - USHORT rsv:5; -#endif - - //Substract from Addiont HT INFO IE -#ifdef RT_BIG_ENDIAN - UCHAR RecomWidth:1; - UCHAR ExtChanOffset:2; // Please not the difference with following UCHAR NewExtChannelOffset; from 802.11n - UCHAR MpduDensity:3; - UCHAR MaxRAmpduFactor:2; -#else - UCHAR MaxRAmpduFactor:2; - UCHAR MpduDensity:3; - UCHAR ExtChanOffset:2; // Please not the difference with following UCHAR NewExtChannelOffset; from 802.11n - UCHAR RecomWidth:1; -#endif - -#ifdef RT_BIG_ENDIAN - USHORT rsv2:11; - USHORT OBSS_NonHTExist:1; - USHORT rsv3:1; - USHORT NonGfPresent:1; - USHORT OperaionMode:2; -#else - USHORT OperaionMode:2; - USHORT NonGfPresent:1; - USHORT rsv3:1; - USHORT OBSS_NonHTExist:1; - USHORT rsv2:11; -#endif - - // New Extension Channel Offset IE - UCHAR NewExtChannelOffset; - // Extension Capability IE = 127 - UCHAR BSSCoexist2040; -} RT_HT_CAPABILITY, *PRT_HT_CAPABILITY; - -// field in Addtional HT Information IE . -typedef struct PACKED { -#ifdef RT_BIG_ENDIAN - UCHAR SerInterGranu:3; - UCHAR S_PSMPSup:1; - UCHAR RifsMode:1; - UCHAR RecomWidth:1; - UCHAR ExtChanOffset:2; -#else - UCHAR ExtChanOffset:2; - UCHAR RecomWidth:1; - UCHAR RifsMode:1; - UCHAR S_PSMPSup:1; //Indicate support for scheduled PSMP - UCHAR SerInterGranu:3; //service interval granularity -#endif -} ADD_HTINFO, *PADD_HTINFO; - -typedef struct PACKED{ -#ifdef RT_BIG_ENDIAN - USHORT rsv2:11; - USHORT OBSS_NonHTExist:1; - USHORT rsv:1; - USHORT NonGfPresent:1; - USHORT OperaionMode:2; -#else - USHORT OperaionMode:2; - USHORT NonGfPresent:1; - USHORT rsv:1; - USHORT OBSS_NonHTExist:1; - USHORT rsv2:11; -#endif -} ADD_HTINFO2, *PADD_HTINFO2; - - -// TODO: Need sync with spec about the definition of StbcMcs. In Draft 3.03, it's reserved. -typedef struct PACKED{ -#ifdef RT_BIG_ENDIAN - USHORT rsv:4; - USHORT PcoPhase:1; - USHORT PcoActive:1; - USHORT LsigTxopProt:1; - USHORT STBCBeacon:1; - USHORT DualCTSProtect:1; - USHORT DualBeacon:1; - USHORT StbcMcs:6; -#else - USHORT StbcMcs:6; - USHORT DualBeacon:1; - USHORT DualCTSProtect:1; - USHORT STBCBeacon:1; - USHORT LsigTxopProt:1; // L-SIG TXOP protection full support - USHORT PcoActive:1; - USHORT PcoPhase:1; - USHORT rsv:4; -#endif // RT_BIG_ENDIAN // -} ADD_HTINFO3, *PADD_HTINFO3; - -#define SIZE_ADD_HT_INFO_IE 22 -typedef struct PACKED{ - UCHAR ControlChan; - ADD_HTINFO AddHtInfo; - ADD_HTINFO2 AddHtInfo2; - ADD_HTINFO3 AddHtInfo3; - UCHAR MCSSet[16]; // Basic MCS set -} ADD_HT_INFO_IE, *PADD_HT_INFO_IE; - -typedef struct PACKED{ - UCHAR NewExtChanOffset; -} NEW_EXT_CHAN_IE, *PNEW_EXT_CHAN_IE; - - -// 4-byte HTC field. maybe included in any frame except non-QOS data frame. The Order bit must set 1. -typedef struct PACKED { -#ifdef RT_BIG_ENDIAN - UINT32 RDG:1; //RDG / More PPDU - UINT32 ACConstraint:1; //feedback request - UINT32 rsv:5; //calibration sequence - UINT32 ZLFAnnouce:1; // ZLF announcement - UINT32 CSISTEERING:2; //CSI/ STEERING - UINT32 FBKReq:2; //feedback request - UINT32 CalSeq:2; //calibration sequence - UINT32 CalPos:2; // calibration position - UINT32 MFBorASC:7; //Link adaptation feedback containing recommended MCS. 0x7f for no feedback or not available - UINT32 MFS:3; //SET to the received value of MRS. 0x111 for unsolicited MFB. - UINT32 MRSorASI:3; // MRQ Sequence identifier. unchanged during entire procedure. 0x000-0x110. - UINT32 MRQ:1; //MCS feedback. Request for a MCS feedback - UINT32 TRQ:1; //sounding request - UINT32 MA:1; //management action payload exist in (QoS Null+HTC) -#else - UINT32 MA:1; //management action payload exist in (QoS Null+HTC) - UINT32 TRQ:1; //sounding request - UINT32 MRQ:1; //MCS feedback. Request for a MCS feedback - UINT32 MRSorASI:3; // MRQ Sequence identifier. unchanged during entire procedure. 0x000-0x110. - UINT32 MFS:3; //SET to the received value of MRS. 0x111 for unsolicited MFB. - UINT32 MFBorASC:7; //Link adaptation feedback containing recommended MCS. 0x7f for no feedback or not available - UINT32 CalPos:2; // calibration position - UINT32 CalSeq:2; //calibration sequence - UINT32 FBKReq:2; //feedback request - UINT32 CSISTEERING:2; //CSI/ STEERING - UINT32 ZLFAnnouce:1; // ZLF announcement - UINT32 rsv:5; //calibration sequence - UINT32 ACConstraint:1; //feedback request - UINT32 RDG:1; //RDG / More PPDU -#endif /* !RT_BIG_ENDIAN */ -} HT_CONTROL, *PHT_CONTROL; - -// 2-byte QOS CONTROL field -typedef struct PACKED { -#ifdef RT_BIG_ENDIAN - USHORT Txop_QueueSize:8; - USHORT AMsduPresent:1; - USHORT AckPolicy:2; //0: normal ACK 1:No ACK 2:scheduled under MTBA/PSMP 3: BA - USHORT EOSP:1; - USHORT TID:4; -#else - USHORT TID:4; - USHORT EOSP:1; - USHORT AckPolicy:2; //0: normal ACK 1:No ACK 2:scheduled under MTBA/PSMP 3: BA - USHORT AMsduPresent:1; - USHORT Txop_QueueSize:8; -#endif /* !RT_BIG_ENDIAN */ -} QOS_CONTROL, *PQOS_CONTROL; - -// 2-byte Frame control field -typedef struct PACKED { -#ifdef RT_BIG_ENDIAN - USHORT Order:1; // Strict order expected - USHORT Wep:1; // Wep data - USHORT MoreData:1; // More data bit - USHORT PwrMgmt:1; // Power management bit - USHORT Retry:1; // Retry status bit - USHORT MoreFrag:1; // More fragment bit - USHORT FrDs:1; // From DS indication - USHORT ToDs:1; // To DS indication - USHORT SubType:4; // MSDU subtype - USHORT Type:2; // MSDU type - USHORT Ver:2; // Protocol version -#else - USHORT Ver:2; // Protocol version - USHORT Type:2; // MSDU type - USHORT SubType:4; // MSDU subtype - USHORT ToDs:1; // To DS indication - USHORT FrDs:1; // From DS indication - USHORT MoreFrag:1; // More fragment bit - USHORT Retry:1; // Retry status bit - USHORT PwrMgmt:1; // Power management bit - USHORT MoreData:1; // More data bit - USHORT Wep:1; // Wep data - USHORT Order:1; // Strict order expected -#endif /* !RT_BIG_ENDIAN */ -} FRAME_CONTROL, *PFRAME_CONTROL; - -typedef struct PACKED _HEADER_802_11 { - FRAME_CONTROL FC; - USHORT Duration; - UCHAR Addr1[MAC_ADDR_LEN]; - UCHAR Addr2[MAC_ADDR_LEN]; - UCHAR Addr3[MAC_ADDR_LEN]; -#ifdef RT_BIG_ENDIAN - USHORT Sequence:12; - USHORT Frag:4; -#else - USHORT Frag:4; - USHORT Sequence:12; -#endif /* !RT_BIG_ENDIAN */ - UCHAR Octet[0]; -} HEADER_802_11, *PHEADER_802_11; - -typedef struct PACKED _FRAME_802_11 { - HEADER_802_11 Hdr; - UCHAR Octet[1]; -} FRAME_802_11, *PFRAME_802_11; - -// QoSNull embedding of management action. When HT Control MA field set to 1. -typedef struct PACKED _MA_BODY { - UCHAR Category; - UCHAR Action; - UCHAR Octet[1]; -} MA_BODY, *PMA_BODY; - -typedef struct PACKED _HEADER_802_3 { - UCHAR DAAddr1[MAC_ADDR_LEN]; - UCHAR SAAddr2[MAC_ADDR_LEN]; - UCHAR Octet[2]; -} HEADER_802_3, *PHEADER_802_3; -////Block ACK related format -// 2-byte BA Parameter field in DELBA frames to terminate an already set up bA -typedef struct PACKED{ -#ifdef RT_BIG_ENDIAN - USHORT TID:4; // value of TC os TS - USHORT Initiator:1; // 1: originator 0:recipient - USHORT Rsv:11; // always set to 0 -#else - USHORT Rsv:11; // always set to 0 - USHORT Initiator:1; // 1: originator 0:recipient - USHORT TID:4; // value of TC os TS -#endif /* !RT_BIG_ENDIAN */ -} DELBA_PARM, *PDELBA_PARM; - -// 2-byte BA Parameter Set field in ADDBA frames to signal parm for setting up a BA -typedef struct PACKED { -#ifdef RT_BIG_ENDIAN - USHORT BufSize:10; // number of buffe of size 2304 octetsr - USHORT TID:4; // value of TC os TS - USHORT BAPolicy:1; // 1: immediately BA 0:delayed BA - USHORT AMSDUSupported:1; // 0: not permitted 1: permitted -#else - USHORT AMSDUSupported:1; // 0: not permitted 1: permitted - USHORT BAPolicy:1; // 1: immediately BA 0:delayed BA - USHORT TID:4; // value of TC os TS - USHORT BufSize:10; // number of buffe of size 2304 octetsr -#endif /* !RT_BIG_ENDIAN */ -} BA_PARM, *PBA_PARM; - -// 2-byte BA Starting Seq CONTROL field -typedef union PACKED { - struct PACKED { -#ifdef RT_BIG_ENDIAN - USHORT StartSeq:12; // sequence number of the 1st MSDU for which this BAR is sent - USHORT FragNum:4; // always set to 0 -#else - USHORT FragNum:4; // always set to 0 - USHORT StartSeq:12; // sequence number of the 1st MSDU for which this BAR is sent -#endif /* RT_BIG_ENDIAN */ - } field; - USHORT word; -} BASEQ_CONTROL, *PBASEQ_CONTROL; - -//BAControl and BARControl are the same -// 2-byte BA CONTROL field in BA frame -typedef struct PACKED { -#ifdef RT_BIG_ENDIAN - USHORT TID:4; - USHORT Rsv:9; - USHORT Compressed:1; - USHORT MTID:1; //EWC V1.24 - USHORT ACKPolicy:1; // only related to N-Delayed BA. But not support in RT2860b. 0:NormalACK 1:No ACK -#else - USHORT ACKPolicy:1; // only related to N-Delayed BA. But not support in RT2860b. 0:NormalACK 1:No ACK - USHORT MTID:1; //EWC V1.24 - USHORT Compressed:1; - USHORT Rsv:9; - USHORT TID:4; -#endif /* !RT_BIG_ENDIAN */ -} BA_CONTROL, *PBA_CONTROL; - -// 2-byte BAR CONTROL field in BAR frame -typedef struct PACKED { -#ifdef RT_BIG_ENDIAN - USHORT TID:4; - USHORT Rsv1:9; - USHORT Compressed:1; - USHORT MTID:1; //if this bit1, use FRAME_MTBA_REQ, if 0, use FRAME_BA_REQ - USHORT ACKPolicy:1; -#else - USHORT ACKPolicy:1; // 0:normal ack, 1:no ack. - USHORT MTID:1; //if this bit1, use FRAME_MTBA_REQ, if 0, use FRAME_BA_REQ - USHORT Compressed:1; - USHORT Rsv1:9; - USHORT TID:4; -#endif /* !RT_BIG_ENDIAN */ -} BAR_CONTROL, *PBAR_CONTROL; - -// BARControl in MTBAR frame -typedef struct PACKED { -#ifdef RT_BIG_ENDIAN - USHORT NumTID:4; - USHORT Rsv1:9; - USHORT Compressed:1; - USHORT MTID:1; - USHORT ACKPolicy:1; -#else - USHORT ACKPolicy:1; - USHORT MTID:1; - USHORT Compressed:1; - USHORT Rsv1:9; - USHORT NumTID:4; -#endif /* !RT_BIG_ENDIAN */ -} MTBAR_CONTROL, *PMTBAR_CONTROL; - -typedef struct PACKED { -#ifdef RT_BIG_ENDIAN - USHORT TID:4; - USHORT Rsv1:12; -#else - USHORT Rsv1:12; - USHORT TID:4; -#endif /* !RT_BIG_ENDIAN */ -} PER_TID_INFO, *PPER_TID_INFO; - -typedef struct { - PER_TID_INFO PerTID; - BASEQ_CONTROL BAStartingSeq; -} EACH_TID, *PEACH_TID; - - -typedef struct PACKED _PSPOLL_FRAME { - FRAME_CONTROL FC; - USHORT Aid; - UCHAR Bssid[MAC_ADDR_LEN]; - UCHAR Ta[MAC_ADDR_LEN]; -} PSPOLL_FRAME, *PPSPOLL_FRAME; - -typedef struct PACKED _RTS_FRAME { - FRAME_CONTROL FC; - USHORT Duration; - UCHAR Addr1[MAC_ADDR_LEN]; - UCHAR Addr2[MAC_ADDR_LEN]; -}RTS_FRAME, *PRTS_FRAME; - -// BAREQ AND MTBAREQ have the same subtype BAR, 802.11n BAR use compressed bitmap. -typedef struct PACKED _FRAME_BA_REQ { - FRAME_CONTROL FC; - USHORT Duration; - UCHAR Addr1[MAC_ADDR_LEN]; - UCHAR Addr2[MAC_ADDR_LEN]; - BAR_CONTROL BARControl; - BASEQ_CONTROL BAStartingSeq; -} FRAME_BA_REQ, *PFRAME_BA_REQ; - -typedef struct PACKED _FRAME_MTBA_REQ { - FRAME_CONTROL FC; - USHORT Duration; - UCHAR Addr1[MAC_ADDR_LEN]; - UCHAR Addr2[MAC_ADDR_LEN]; - MTBAR_CONTROL MTBARControl; - PER_TID_INFO PerTIDInfo; - BASEQ_CONTROL BAStartingSeq; -} FRAME_MTBA_REQ, *PFRAME_MTBA_REQ; - -// Compressed format is mandantory in HT STA -typedef struct PACKED _FRAME_MTBA { - FRAME_CONTROL FC; - USHORT Duration; - UCHAR Addr1[MAC_ADDR_LEN]; - UCHAR Addr2[MAC_ADDR_LEN]; - BA_CONTROL BAControl; - BASEQ_CONTROL BAStartingSeq; - UCHAR BitMap[8]; -} FRAME_MTBA, *PFRAME_MTBA; - -typedef struct PACKED _FRAME_PSMP_ACTION { - HEADER_802_11 Hdr; - UCHAR Category; - UCHAR Action; - UCHAR Psmp; // 7.3.1.25 -} FRAME_PSMP_ACTION, *PFRAME_PSMP_ACTION; - -typedef struct PACKED _FRAME_ACTION_HDR { - HEADER_802_11 Hdr; - UCHAR Category; - UCHAR Action; -} FRAME_ACTION_HDR, *PFRAME_ACTION_HDR; - -//Action Frame -//Action Frame Category:Spectrum, Action:Channel Switch. 7.3.2.20 -typedef struct PACKED _CHAN_SWITCH_ANNOUNCE { - UCHAR ElementID; // ID = IE_CHANNEL_SWITCH_ANNOUNCEMENT = 37 - UCHAR Len; - CHA_SWITCH_ANNOUNCE_IE CSAnnounceIe; -} CHAN_SWITCH_ANNOUNCE, *PCHAN_SWITCH_ANNOUNCE; - - -//802.11n : 7.3.2.20a -typedef struct PACKED _SECOND_CHAN_OFFSET { - UCHAR ElementID; // ID = IE_SECONDARY_CH_OFFSET = 62 - UCHAR Len; - SEC_CHA_OFFSET_IE SecChOffsetIe; -} SECOND_CHAN_OFFSET, *PSECOND_CHAN_OFFSET; - - -typedef struct PACKED _FRAME_SPETRUM_CS { - HEADER_802_11 Hdr; - UCHAR Category; - UCHAR Action; - CHAN_SWITCH_ANNOUNCE CSAnnounce; - SECOND_CHAN_OFFSET SecondChannel; -} FRAME_SPETRUM_CS, *PFRAME_SPETRUM_CS; - - -typedef struct PACKED _FRAME_ADDBA_REQ { - HEADER_802_11 Hdr; - UCHAR Category; - UCHAR Action; - UCHAR Token; // 1 - BA_PARM BaParm; // 2 - 10 - USHORT TimeOutValue; // 0 - 0 - BASEQ_CONTROL BaStartSeq; // 0-0 -} FRAME_ADDBA_REQ, *PFRAME_ADDBA_REQ; - -typedef struct PACKED _FRAME_ADDBA_RSP { - HEADER_802_11 Hdr; - UCHAR Category; - UCHAR Action; - UCHAR Token; - USHORT StatusCode; - BA_PARM BaParm; //0 - 2 - USHORT TimeOutValue; -} FRAME_ADDBA_RSP, *PFRAME_ADDBA_RSP; - -typedef struct PACKED _FRAME_DELBA_REQ { - HEADER_802_11 Hdr; - UCHAR Category; - UCHAR Action; - DELBA_PARM DelbaParm; - USHORT ReasonCode; -} FRAME_DELBA_REQ, *PFRAME_DELBA_REQ; - - -//7.2.1.7 -typedef struct PACKED _FRAME_BAR { - FRAME_CONTROL FC; - USHORT Duration; - UCHAR Addr1[MAC_ADDR_LEN]; - UCHAR Addr2[MAC_ADDR_LEN]; - BAR_CONTROL BarControl; - BASEQ_CONTROL StartingSeq; -} FRAME_BAR, *PFRAME_BAR; - -//7.2.1.7 -typedef struct PACKED _FRAME_BA { - FRAME_CONTROL FC; - USHORT Duration; - UCHAR Addr1[MAC_ADDR_LEN]; - UCHAR Addr2[MAC_ADDR_LEN]; - BAR_CONTROL BarControl; - BASEQ_CONTROL StartingSeq; - UCHAR bitmask[8]; -} FRAME_BA, *PFRAME_BA; - - -// Radio Measuement Request Frame Format -typedef struct PACKED _FRAME_RM_REQ_ACTION { - HEADER_802_11 Hdr; - UCHAR Category; - UCHAR Action; - UCHAR Token; - USHORT Repetition; - UCHAR data[0]; -} FRAME_RM_REQ_ACTION, *PFRAME_RM_REQ_ACTION; - -typedef struct PACKED { - UCHAR ID; - UCHAR Length; - UCHAR ChannelSwitchMode; - UCHAR NewRegClass; - UCHAR NewChannelNum; - UCHAR ChannelSwitchCount; -} HT_EXT_CHANNEL_SWITCH_ANNOUNCEMENT_IE, *PHT_EXT_CHANNEL_SWITCH_ANNOUNCEMENT_IE; - - -// -// _Limit must be the 2**n - 1 -// _SEQ1 , _SEQ2 must be within 0 ~ _Limit -// -#define SEQ_STEPONE(_SEQ1, _SEQ2, _Limit) ((_SEQ1 == ((_SEQ2+1) & _Limit))) -#define SEQ_SMALLER(_SEQ1, _SEQ2, _Limit) (((_SEQ1-_SEQ2) & ((_Limit+1)>>1))) -#define SEQ_LARGER(_SEQ1, _SEQ2, _Limit) ((_SEQ1 != _SEQ2) && !(((_SEQ1-_SEQ2) & ((_Limit+1)>>1)))) -#define SEQ_WITHIN_WIN(_SEQ1, _SEQ2, _WIN, _Limit) (SEQ_LARGER(_SEQ1, _SEQ2, _Limit) && \ - SEQ_SMALLER(_SEQ1, ((_SEQ2+_WIN+1)&_Limit), _Limit)) - -// -// Contention-free parameter (without ID and Length) -// -typedef struct PACKED { - BOOLEAN bValid; // 1: variable contains valid value - UCHAR CfpCount; - UCHAR CfpPeriod; - USHORT CfpMaxDuration; - USHORT CfpDurRemaining; -} CF_PARM, *PCF_PARM; - -typedef struct _CIPHER_SUITE { - NDIS_802_11_ENCRYPTION_STATUS PairCipher; // Unicast cipher 1, this one has more secured cipher suite - NDIS_802_11_ENCRYPTION_STATUS PairCipherAux; // Unicast cipher 2 if AP announce two unicast cipher suite - NDIS_802_11_ENCRYPTION_STATUS GroupCipher; // Group cipher - USHORT RsnCapability; // RSN capability from beacon - BOOLEAN bMixMode; // Indicate Pair & Group cipher might be different -} CIPHER_SUITE, *PCIPHER_SUITE; - -// EDCA configuration from AP's BEACON/ProbeRsp -typedef struct { - BOOLEAN bValid; // 1: variable contains valid value - BOOLEAN bAdd; // 1: variable contains valid value - BOOLEAN bQAck; - BOOLEAN bQueueRequest; - BOOLEAN bTxopRequest; - BOOLEAN bAPSDCapable; -// BOOLEAN bMoreDataAck; - UCHAR EdcaUpdateCount; - UCHAR Aifsn[4]; // 0:AC_BK, 1:AC_BE, 2:AC_VI, 3:AC_VO - UCHAR Cwmin[4]; - UCHAR Cwmax[4]; - USHORT Txop[4]; // in unit of 32-us - BOOLEAN bACM[4]; // 1: Admission Control of AC_BK is mandattory -} EDCA_PARM, *PEDCA_PARM; - -// QBSS LOAD information from QAP's BEACON/ProbeRsp -typedef struct { - BOOLEAN bValid; // 1: variable contains valid value - USHORT StaNum; - UCHAR ChannelUtilization; - USHORT RemainingAdmissionControl; // in unit of 32-us -} QBSS_LOAD_PARM, *PQBSS_LOAD_PARM; - -// QBSS Info field in QSTA's assoc req -typedef struct PACKED { -#ifdef RT_BIG_ENDIAN - UCHAR Rsv2:1; - UCHAR MaxSPLength:2; - UCHAR Rsv1:1; - UCHAR UAPSD_AC_BE:1; - UCHAR UAPSD_AC_BK:1; - UCHAR UAPSD_AC_VI:1; - UCHAR UAPSD_AC_VO:1; -#else - UCHAR UAPSD_AC_VO:1; - UCHAR UAPSD_AC_VI:1; - UCHAR UAPSD_AC_BK:1; - UCHAR UAPSD_AC_BE:1; - UCHAR Rsv1:1; - UCHAR MaxSPLength:2; - UCHAR Rsv2:1; -#endif /* !RT_BIG_ENDIAN */ -} QBSS_STA_INFO_PARM, *PQBSS_STA_INFO_PARM; - -// QBSS Info field in QAP's Beacon/ProbeRsp -typedef struct PACKED { -#ifdef RT_BIG_ENDIAN - UCHAR UAPSD:1; - UCHAR Rsv:3; - UCHAR ParamSetCount:4; -#else - UCHAR ParamSetCount:4; - UCHAR Rsv:3; - UCHAR UAPSD:1; -#endif /* !RT_BIG_ENDIAN */ -} QBSS_AP_INFO_PARM, *PQBSS_AP_INFO_PARM; - -// QOS Capability reported in QAP's BEACON/ProbeRsp -// QOS Capability sent out in QSTA's AssociateReq/ReAssociateReq -typedef struct { - BOOLEAN bValid; // 1: variable contains valid value - BOOLEAN bQAck; - BOOLEAN bQueueRequest; - BOOLEAN bTxopRequest; -// BOOLEAN bMoreDataAck; - UCHAR EdcaUpdateCount; -} QOS_CAPABILITY_PARM, *PQOS_CAPABILITY_PARM; - -#ifdef CONFIG_STA_SUPPORT -typedef struct { - UCHAR IELen; - UCHAR IE[MAX_CUSTOM_LEN]; -} WPA_IE_; -#endif // CONFIG_STA_SUPPORT // - - -typedef struct { - UCHAR Bssid[MAC_ADDR_LEN]; - UCHAR Channel; - UCHAR CentralChannel; //Store the wide-band central channel for 40MHz. .used in 40MHz AP. Or this is the same as Channel. - UCHAR BssType; - USHORT AtimWin; - USHORT BeaconPeriod; - - UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES]; - UCHAR SupRateLen; - UCHAR ExtRate[MAX_LEN_OF_SUPPORTED_RATES]; - UCHAR ExtRateLen; - HT_CAPABILITY_IE HtCapability; - UCHAR HtCapabilityLen; - ADD_HT_INFO_IE AddHtInfo; // AP might use this additional ht info IE - UCHAR AddHtInfoLen; - UCHAR NewExtChanOffset; - CHAR Rssi; - UCHAR Privacy; // Indicate security function ON/OFF. Don't mess up with auth mode. - UCHAR Hidden; - - USHORT DtimPeriod; - USHORT CapabilityInfo; - - USHORT CfpCount; - USHORT CfpPeriod; - USHORT CfpMaxDuration; - USHORT CfpDurRemaining; - UCHAR SsidLen; - CHAR Ssid[MAX_LEN_OF_SSID]; - - ULONG LastBeaconRxTime; // OS's timestamp - - BOOLEAN bSES; - - // New for WPA2 - CIPHER_SUITE WPA; // AP announced WPA cipher suite - CIPHER_SUITE WPA2; // AP announced WPA2 cipher suite - - // New for microsoft WPA support - NDIS_802_11_FIXED_IEs FixIEs; - NDIS_802_11_AUTHENTICATION_MODE AuthModeAux; // Addition mode for WPA2 / WPA capable AP - NDIS_802_11_AUTHENTICATION_MODE AuthMode; - NDIS_802_11_WEP_STATUS WepStatus; // Unicast Encryption Algorithm extract from VAR_IE - USHORT VarIELen; // Length of next VIE include EID & Length - UCHAR VarIEs[MAX_VIE_LEN]; - - // CCX Ckip information - UCHAR CkipFlag; - - // CCX 2 TSF - UCHAR PTSF[4]; // Parent TSF - UCHAR TTSF[8]; // Target TSF - - // 802.11e d9, and WMM - EDCA_PARM EdcaParm; - QOS_CAPABILITY_PARM QosCapability; - QBSS_LOAD_PARM QbssLoad; -#ifdef CONFIG_STA_SUPPORT - WPA_IE_ WpaIE; - WPA_IE_ RsnIE; -#ifdef EXT_BUILD_CHANNEL_LIST - UCHAR CountryString[3]; - BOOLEAN bHasCountryIE; -#endif // EXT_BUILD_CHANNEL_LIST // -#endif // CONFIG_STA_SUPPORT // -} BSS_ENTRY, *PBSS_ENTRY; - -typedef struct { - UCHAR BssNr; - UCHAR BssOverlapNr; - BSS_ENTRY BssEntry[MAX_LEN_OF_BSS_TABLE]; -} BSS_TABLE, *PBSS_TABLE; - - -typedef struct _MLME_QUEUE_ELEM { - ULONG Machine; - ULONG MsgType; - ULONG MsgLen; - UCHAR Msg[MGMT_DMA_BUFFER_SIZE]; - LARGE_INTEGER TimeStamp; - UCHAR Rssi0; - UCHAR Rssi1; - UCHAR Rssi2; - UCHAR Signal; - UCHAR Channel; - UCHAR Wcid; - BOOLEAN Occupied; -} MLME_QUEUE_ELEM, *PMLME_QUEUE_ELEM; - -typedef struct _MLME_QUEUE { - ULONG Num; - ULONG Head; - ULONG Tail; - NDIS_SPIN_LOCK Lock; - MLME_QUEUE_ELEM Entry[MAX_LEN_OF_MLME_QUEUE]; -} MLME_QUEUE, *PMLME_QUEUE; - -typedef VOID (*STATE_MACHINE_FUNC)(VOID *Adaptor, MLME_QUEUE_ELEM *Elem); - -typedef struct _STATE_MACHINE { - ULONG Base; - ULONG NrState; - ULONG NrMsg; - ULONG CurrState; - STATE_MACHINE_FUNC *TransFunc; -} STATE_MACHINE, *PSTATE_MACHINE; - - -// MLME AUX data structure that hold temporarliy settings during a connection attempt. -// Once this attemp succeeds, all settings will be copy to pAd->StaActive. -// A connection attempt (user set OID, roaming, CCX fast roaming,..) consists of -// several steps (JOIN, AUTH, ASSOC or REASSOC) and may fail at any step. We purposely -// separate this under-trial settings away from pAd->StaActive so that once -// this new attempt failed, driver can auto-recover back to the active settings. -typedef struct _MLME_AUX { - UCHAR BssType; - UCHAR Ssid[MAX_LEN_OF_SSID]; - UCHAR SsidLen; - UCHAR Bssid[MAC_ADDR_LEN]; - UCHAR AutoReconnectSsid[MAX_LEN_OF_SSID]; - UCHAR AutoReconnectSsidLen; - USHORT Alg; - UCHAR ScanType; - UCHAR Channel; - UCHAR CentralChannel; - USHORT Aid; - USHORT CapabilityInfo; - USHORT BeaconPeriod; - USHORT CfpMaxDuration; - USHORT CfpPeriod; - USHORT AtimWin; - - // Copy supported rate from desired AP's beacon. We are trying to match - // AP's supported and extended rate settings. - UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES]; - UCHAR ExtRate[MAX_LEN_OF_SUPPORTED_RATES]; - UCHAR SupRateLen; - UCHAR ExtRateLen; - HT_CAPABILITY_IE HtCapability; - UCHAR HtCapabilityLen; - ADD_HT_INFO_IE AddHtInfo; // AP might use this additional ht info IE - UCHAR NewExtChannelOffset; - //RT_HT_CAPABILITY SupportedHtPhy; - - // new for QOS - QOS_CAPABILITY_PARM APQosCapability; // QOS capability of the current associated AP - EDCA_PARM APEdcaParm; // EDCA parameters of the current associated AP - QBSS_LOAD_PARM APQbssLoad; // QBSS load of the current associated AP - - // new to keep Ralink specific feature - ULONG APRalinkIe; - - BSS_TABLE SsidBssTab; // AP list for the same SSID - BSS_TABLE RoamTab; // AP list eligible for roaming - ULONG BssIdx; - ULONG RoamIdx; - - BOOLEAN CurrReqIsFromNdis; - - RALINK_TIMER_STRUCT BeaconTimer, ScanTimer; - RALINK_TIMER_STRUCT AuthTimer; - RALINK_TIMER_STRUCT AssocTimer, ReassocTimer, DisassocTimer; -} MLME_AUX, *PMLME_AUX; - -typedef struct _MLME_ADDBA_REQ_STRUCT{ - UCHAR Wcid; // - UCHAR pAddr[MAC_ADDR_LEN]; - UCHAR BaBufSize; - USHORT TimeOutValue; - UCHAR TID; - UCHAR Token; - USHORT BaStartSeq; -} MLME_ADDBA_REQ_STRUCT, *PMLME_ADDBA_REQ_STRUCT; - - -typedef struct _MLME_DELBA_REQ_STRUCT{ - UCHAR Wcid; // - UCHAR Addr[MAC_ADDR_LEN]; - UCHAR TID; - UCHAR Initiator; -} MLME_DELBA_REQ_STRUCT, *PMLME_DELBA_REQ_STRUCT; - -// assoc struct is equal to reassoc -typedef struct _MLME_ASSOC_REQ_STRUCT{ - UCHAR Addr[MAC_ADDR_LEN]; - USHORT CapabilityInfo; - USHORT ListenIntv; - ULONG Timeout; -} MLME_ASSOC_REQ_STRUCT, *PMLME_ASSOC_REQ_STRUCT, MLME_REASSOC_REQ_STRUCT, *PMLME_REASSOC_REQ_STRUCT; - -typedef struct _MLME_DISASSOC_REQ_STRUCT{ - UCHAR Addr[MAC_ADDR_LEN]; - USHORT Reason; -} MLME_DISASSOC_REQ_STRUCT, *PMLME_DISASSOC_REQ_STRUCT; - -typedef struct _MLME_AUTH_REQ_STRUCT { - UCHAR Addr[MAC_ADDR_LEN]; - USHORT Alg; - ULONG Timeout; -} MLME_AUTH_REQ_STRUCT, *PMLME_AUTH_REQ_STRUCT; - -typedef struct _MLME_DEAUTH_REQ_STRUCT { - UCHAR Addr[MAC_ADDR_LEN]; - USHORT Reason; -} MLME_DEAUTH_REQ_STRUCT, *PMLME_DEAUTH_REQ_STRUCT; - -typedef struct { - ULONG BssIdx; -} MLME_JOIN_REQ_STRUCT; - -typedef struct _MLME_SCAN_REQ_STRUCT { - UCHAR Bssid[MAC_ADDR_LEN]; - UCHAR BssType; - UCHAR ScanType; - UCHAR SsidLen; - CHAR Ssid[MAX_LEN_OF_SSID]; -} MLME_SCAN_REQ_STRUCT, *PMLME_SCAN_REQ_STRUCT; - -typedef struct _MLME_START_REQ_STRUCT { - CHAR Ssid[MAX_LEN_OF_SSID]; - UCHAR SsidLen; -} MLME_START_REQ_STRUCT, *PMLME_START_REQ_STRUCT; - -#ifdef CONFIG_STA_SUPPORT -#ifdef QOS_DLS_SUPPORT -// structure for DLS -typedef struct _RT_802_11_DLS { - USHORT TimeOut; // Use to time out while slience, unit: second , set by UI - USHORT CountDownTimer; // Use to time out while slience,unit: second , used by driver only - NDIS_802_11_MAC_ADDRESS MacAddr; // set by UI - UCHAR Status; // 0: none , 1: wait STAkey, 2: finish DLS setup , set by driver only - BOOLEAN Valid; // 1: valid , 0: invalid , set by UI, use to setup or tear down DLS link - RALINK_TIMER_STRUCT Timer; // Use to time out while handshake - USHORT Sequence; - USHORT MacTabMatchWCID; // ASIC - BOOLEAN bHTCap; - PVOID pAd; -} RT_802_11_DLS, *PRT_802_11_DLS; - -typedef struct _MLME_DLS_REQ_STRUCT { - PRT_802_11_DLS pDLS; - USHORT Reason; -} MLME_DLS_REQ_STRUCT, *PMLME_DLS_REQ_STRUCT; -#endif // QOS_DLS_SUPPORT // -#endif // CONFIG_STA_SUPPORT // - -typedef struct PACKED { - UCHAR Eid; - UCHAR Len; - CHAR Octet[1]; -} EID_STRUCT,*PEID_STRUCT, BEACON_EID_STRUCT, *PBEACON_EID_STRUCT; - -typedef struct PACKED _RTMP_TX_RATE_SWITCH -{ - UCHAR ItemNo; -#ifdef RT_BIG_ENDIAN - UCHAR Rsv2:2; - UCHAR Mode:2; - UCHAR Rsv1:1; - UCHAR BW:1; - UCHAR ShortGI:1; - UCHAR STBC:1; -#else - UCHAR STBC:1; - UCHAR ShortGI:1; - UCHAR BW:1; - UCHAR Rsv1:1; - UCHAR Mode:2; - UCHAR Rsv2:2; -#endif - UCHAR CurrMCS; - UCHAR TrainUp; - UCHAR TrainDown; -} RRTMP_TX_RATE_SWITCH, *PRTMP_TX_RATE_SWITCH; - -// ========================== AP mlme.h =============================== -#define TBTT_PRELOAD_TIME 384 // usec. LomgPreamble + 24-byte at 1Mbps -#define DEFAULT_DTIM_PERIOD 1 - -// weighting factor to calculate Channel quality, total should be 100% -//#define RSSI_WEIGHTING 0 -//#define TX_WEIGHTING 40 -//#define RX_WEIGHTING 60 - -#define MAC_TABLE_AGEOUT_TIME 300 // unit: sec -#define MAC_TABLE_ASSOC_TIMEOUT 5 // unit: sec -#define MAC_TABLE_FULL(Tab) ((Tab).size == MAX_LEN_OF_MAC_TABLE) - -// AP shall drop the sta if contine Tx fail count reach it. -#define MAC_ENTRY_LIFE_CHECK_CNT 20 // packet cnt. - -// Value domain of pMacEntry->Sst -typedef enum _Sst { - SST_NOT_AUTH, // 0: equivalent to IEEE 802.11/1999 state 1 - SST_AUTH, // 1: equivalent to IEEE 802.11/1999 state 2 - SST_ASSOC // 2: equivalent to IEEE 802.11/1999 state 3 -} SST; - -// value domain of pMacEntry->AuthState -typedef enum _AuthState { - AS_NOT_AUTH, - AS_AUTH_OPEN, // STA has been authenticated using OPEN SYSTEM - AS_AUTH_KEY, // STA has been authenticated using SHARED KEY - AS_AUTHENTICATING // STA is waiting for AUTH seq#3 using SHARED KEY -} AUTH_STATE; - -//for-wpa value domain of pMacEntry->WpaState 802.1i D3 p.114 -typedef enum _ApWpaState { - AS_NOTUSE, // 0 - AS_DISCONNECT, // 1 - AS_DISCONNECTED, // 2 - AS_INITIALIZE, // 3 - AS_AUTHENTICATION, // 4 - AS_AUTHENTICATION2, // 5 - AS_INITPMK, // 6 - AS_INITPSK, // 7 - AS_PTKSTART, // 8 - AS_PTKINIT_NEGOTIATING, // 9 - AS_PTKINITDONE, // 10 - AS_UPDATEKEYS, // 11 - AS_INTEGRITY_FAILURE, // 12 - AS_KEYUPDATE, // 13 -} AP_WPA_STATE; - -// for-wpa value domain of pMacEntry->WpaState 802.1i D3 p.114 -typedef enum _GTKState { - REKEY_NEGOTIATING, - REKEY_ESTABLISHED, - KEYERROR, -} GTK_STATE; - -// for-wpa value domain of pMacEntry->WpaState 802.1i D3 p.114 -typedef enum _WpaGTKState { - SETKEYS, - SETKEYS_DONE, -} WPA_GTK_STATE; -// ====================== end of AP mlme.h ============================ - - -#endif // MLME_H__ +#include "../rt2860/mlme.h" diff --git a/drivers/staging/rt2870/netif_block.h b/drivers/staging/rt2870/netif_block.h deleted file mode 100644 index 6e5151c41095..000000000000 --- a/drivers/staging/rt2870/netif_block.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - */ - -#ifndef __NET_IF_BLOCK_H__ -#define __NET_IF_BLOCK_H__ - -//#include -#include "link_list.h" -#include "rtmp.h" - -#define FREE_NETIF_POOL_SIZE 32 - -typedef struct _NETIF_ENTRY -{ - struct _NETIF_ENTRY *pNext; - PNET_DEV pNetDev; -} NETIF_ENTRY, *PNETIF_ENTRY; - -void initblockQueueTab( - IN PRTMP_ADAPTER pAd); - -BOOLEAN blockNetIf( - IN PBLOCK_QUEUE_ENTRY pBlockQueueEntry, - IN PNET_DEV pNetDev); - -VOID releaseNetIf( - IN PBLOCK_QUEUE_ENTRY pBlockQueueEntry); - -VOID StopNetIfQueue( - IN PRTMP_ADAPTER pAd, - IN UCHAR QueIdx, - IN PNDIS_PACKET pPacket); -#endif // __NET_IF_BLOCK_H__ - diff --git a/drivers/staging/rt2870/oid.h b/drivers/staging/rt2870/oid.h index d788db6b6264..1223d81bfc62 100644 --- a/drivers/staging/rt2870/oid.h +++ b/drivers/staging/rt2870/oid.h @@ -1,1091 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - oid.h - - Abstract: - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Name Date Modification logs -*/ -#ifndef _OID_H_ -#define _OID_H_ - -#define TRUE 1 -#define FALSE 0 -// -// IEEE 802.11 Structures and definitions -// -#define MAX_TX_POWER_LEVEL 100 /* mW */ -#define MAX_RSSI_TRIGGER -10 /* dBm */ -#define MIN_RSSI_TRIGGER -200 /* dBm */ -#define MAX_FRAG_THRESHOLD 2346 /* byte count */ -#define MIN_FRAG_THRESHOLD 256 /* byte count */ -#define MAX_RTS_THRESHOLD 2347 /* byte count */ - -// new types for Media Specific Indications -// Extension channel offset -#define EXTCHA_NONE 0 -#define EXTCHA_ABOVE 0x1 -#define EXTCHA_BELOW 0x3 - -// BW -#define BAND_WIDTH_20 0 -#define BAND_WIDTH_40 1 -#define BAND_WIDTH_BOTH 2 -#define BAND_WIDTH_10 3 // 802.11j has 10MHz. This definition is for internal usage. doesn't fill in the IE or other field. -// SHORTGI -#define GAP_INTERVAL_400 1 // only support in HT mode -#define GAP_INTERVAL_800 0 -#define GAP_INTERVAL_BOTH 2 - -#define NdisMediaStateConnected 1 -#define NdisMediaStateDisconnected 0 - -#define NDIS_802_11_LENGTH_SSID 32 -#define NDIS_802_11_LENGTH_RATES 8 -#define NDIS_802_11_LENGTH_RATES_EX 16 -#define MAC_ADDR_LENGTH 6 -#define MAX_NUM_OF_CHS 49 // 14 channels @2.4G + 12@UNII + 4 @MMAC + 11 @HiperLAN2 + 7 @Japan + 1 as NULL terminationc -#define MAX_NUMBER_OF_EVENT 10 // entry # in EVENT table -#define MAX_NUMBER_OF_MAC 32 // if MAX_MBSSID_NUM is 8, this value can't be larger than 211 -#define MAX_NUMBER_OF_ACL 64 -#define MAX_LENGTH_OF_SUPPORT_RATES 12 // 1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54 -#define MAX_NUMBER_OF_DLS_ENTRY 4 - -#ifndef UNDER_CE -// OID definition, since NDIS 5.0 didn't define these, we need to define for our own -//#if _WIN32_WINNT<=0x0500 - -#define OID_GEN_MACHINE_NAME 0x0001021A - -#ifdef RALINK_ATE -#define RT_QUERY_ATE_TXDONE_COUNT 0x0401 -#endif // RALINK_ATE // -#define RT_QUERY_SIGNAL_CONTEXT 0x0402 -#define RT_SET_IAPP_PID 0x0404 -#define RT_SET_APD_PID 0x0405 -#define RT_SET_DEL_MAC_ENTRY 0x0406 - -// -// IEEE 802.11 OIDs -// -#define OID_GET_SET_TOGGLE 0x8000 - -#define OID_802_11_NETWORK_TYPES_SUPPORTED 0x0103 -#define OID_802_11_NETWORK_TYPE_IN_USE 0x0104 -#define OID_802_11_RSSI_TRIGGER 0x0107 -#define RT_OID_802_11_RSSI 0x0108 //rt2860 only , kathy -#define RT_OID_802_11_RSSI_1 0x0109 //rt2860 only , kathy -#define RT_OID_802_11_RSSI_2 0x010A //rt2860 only , kathy -#define OID_802_11_NUMBER_OF_ANTENNAS 0x010B -#define OID_802_11_RX_ANTENNA_SELECTED 0x010C -#define OID_802_11_TX_ANTENNA_SELECTED 0x010D -#define OID_802_11_SUPPORTED_RATES 0x010E -#define OID_802_11_ADD_WEP 0x0112 -#define OID_802_11_REMOVE_WEP 0x0113 -#define OID_802_11_DISASSOCIATE 0x0114 -#define OID_802_11_PRIVACY_FILTER 0x0118 -#define OID_802_11_ASSOCIATION_INFORMATION 0x011E -#define OID_802_11_TEST 0x011F -#define RT_OID_802_11_COUNTRY_REGION 0x0507 -#define OID_802_11_BSSID_LIST_SCAN 0x0508 -#define OID_802_11_SSID 0x0509 -#define OID_802_11_BSSID 0x050A -#define RT_OID_802_11_RADIO 0x050B -#define RT_OID_802_11_PHY_MODE 0x050C -#define RT_OID_802_11_STA_CONFIG 0x050D -#define OID_802_11_DESIRED_RATES 0x050E -#define RT_OID_802_11_PREAMBLE 0x050F -#define OID_802_11_WEP_STATUS 0x0510 -#define OID_802_11_AUTHENTICATION_MODE 0x0511 -#define OID_802_11_INFRASTRUCTURE_MODE 0x0512 -#define RT_OID_802_11_RESET_COUNTERS 0x0513 -#define OID_802_11_RTS_THRESHOLD 0x0514 -#define OID_802_11_FRAGMENTATION_THRESHOLD 0x0515 -#define OID_802_11_POWER_MODE 0x0516 -#define OID_802_11_TX_POWER_LEVEL 0x0517 -#define RT_OID_802_11_ADD_WPA 0x0518 -#define OID_802_11_REMOVE_KEY 0x0519 -#define OID_802_11_ADD_KEY 0x0520 -#define OID_802_11_CONFIGURATION 0x0521 -#define OID_802_11_TX_PACKET_BURST 0x0522 -#define RT_OID_802_11_QUERY_NOISE_LEVEL 0x0523 -#define RT_OID_802_11_EXTRA_INFO 0x0524 -#ifdef DBG -#define RT_OID_802_11_HARDWARE_REGISTER 0x0525 -#endif -#define OID_802_11_ENCRYPTION_STATUS OID_802_11_WEP_STATUS -#define OID_802_11_DEAUTHENTICATION 0x0526 -#define OID_802_11_DROP_UNENCRYPTED 0x0527 -#define OID_802_11_MIC_FAILURE_REPORT_FRAME 0x0528 - -// For 802.1x daemin using to require current driver configuration -#define OID_802_11_RADIUS_QUERY_SETTING 0x0540 - -#define RT_OID_DEVICE_NAME 0x0607 -#define RT_OID_VERSION_INFO 0x0608 -#define OID_802_11_BSSID_LIST 0x0609 -#define OID_802_3_CURRENT_ADDRESS 0x060A -#define OID_GEN_MEDIA_CONNECT_STATUS 0x060B -#define RT_OID_802_11_QUERY_LINK_STATUS 0x060C -#define OID_802_11_RSSI 0x060D -#define OID_802_11_STATISTICS 0x060E -#define OID_GEN_RCV_OK 0x060F -#define OID_GEN_RCV_NO_BUFFER 0x0610 -#define RT_OID_802_11_QUERY_EEPROM_VERSION 0x0611 -#define RT_OID_802_11_QUERY_FIRMWARE_VERSION 0x0612 -#define RT_OID_802_11_QUERY_LAST_RX_RATE 0x0613 -#define RT_OID_802_11_TX_POWER_LEVEL_1 0x0614 -#define RT_OID_802_11_QUERY_PIDVID 0x0615 -//for WPA_SUPPLICANT_SUPPORT -#define OID_SET_COUNTERMEASURES 0x0616 -#define OID_802_11_SET_IEEE8021X 0x0617 -#define OID_802_11_SET_IEEE8021X_REQUIRE_KEY 0x0618 -#define OID_802_11_PMKID 0x0620 -#define RT_OID_WPA_SUPPLICANT_SUPPORT 0x0621 -#define RT_OID_WE_VERSION_COMPILED 0x0622 -#define RT_OID_NEW_DRIVER 0x0623 - - -//rt2860 , kathy -#define RT_OID_802_11_SNR_0 0x0630 -#define RT_OID_802_11_SNR_1 0x0631 -#define RT_OID_802_11_QUERY_LAST_TX_RATE 0x0632 -#define RT_OID_802_11_QUERY_HT_PHYMODE 0x0633 -#define RT_OID_802_11_SET_HT_PHYMODE 0x0634 -#define OID_802_11_RELOAD_DEFAULTS 0x0635 -#define RT_OID_802_11_QUERY_APSD_SETTING 0x0636 -#define RT_OID_802_11_SET_APSD_SETTING 0x0637 -#define RT_OID_802_11_QUERY_APSD_PSM 0x0638 -#define RT_OID_802_11_SET_APSD_PSM 0x0639 -#define RT_OID_802_11_QUERY_DLS 0x063A -#define RT_OID_802_11_SET_DLS 0x063B -#define RT_OID_802_11_QUERY_DLS_PARAM 0x063C -#define RT_OID_802_11_SET_DLS_PARAM 0x063D -#define RT_OID_802_11_QUERY_WMM 0x063E -#define RT_OID_802_11_SET_WMM 0x063F -#define RT_OID_802_11_QUERY_IMME_BA_CAP 0x0640 -#define RT_OID_802_11_SET_IMME_BA_CAP 0x0641 -#define RT_OID_802_11_QUERY_BATABLE 0x0642 -#define RT_OID_802_11_ADD_IMME_BA 0x0643 -#define RT_OID_802_11_TEAR_IMME_BA 0x0644 -#define RT_OID_DRIVER_DEVICE_NAME 0x0645 -#define RT_OID_802_11_QUERY_DAT_HT_PHYMODE 0x0646 -#define RT_OID_QUERY_MULTIPLE_CARD_SUPPORT 0x0647 - -// Ralink defined OIDs -// Dennis Lee move to platform specific - -#define RT_OID_802_11_BSSID (OID_GET_SET_TOGGLE | OID_802_11_BSSID) -#define RT_OID_802_11_SSID (OID_GET_SET_TOGGLE | OID_802_11_SSID) -#define RT_OID_802_11_INFRASTRUCTURE_MODE (OID_GET_SET_TOGGLE | OID_802_11_INFRASTRUCTURE_MODE) -#define RT_OID_802_11_ADD_WEP (OID_GET_SET_TOGGLE | OID_802_11_ADD_WEP) -#define RT_OID_802_11_ADD_KEY (OID_GET_SET_TOGGLE | OID_802_11_ADD_KEY) -#define RT_OID_802_11_REMOVE_WEP (OID_GET_SET_TOGGLE | OID_802_11_REMOVE_WEP) -#define RT_OID_802_11_REMOVE_KEY (OID_GET_SET_TOGGLE | OID_802_11_REMOVE_KEY) -#define RT_OID_802_11_DISASSOCIATE (OID_GET_SET_TOGGLE | OID_802_11_DISASSOCIATE) -#define RT_OID_802_11_AUTHENTICATION_MODE (OID_GET_SET_TOGGLE | OID_802_11_AUTHENTICATION_MODE) -#define RT_OID_802_11_PRIVACY_FILTER (OID_GET_SET_TOGGLE | OID_802_11_PRIVACY_FILTER) -#define RT_OID_802_11_BSSID_LIST_SCAN (OID_GET_SET_TOGGLE | OID_802_11_BSSID_LIST_SCAN) -#define RT_OID_802_11_WEP_STATUS (OID_GET_SET_TOGGLE | OID_802_11_WEP_STATUS) -#define RT_OID_802_11_RELOAD_DEFAULTS (OID_GET_SET_TOGGLE | OID_802_11_RELOAD_DEFAULTS) -#define RT_OID_802_11_NETWORK_TYPE_IN_USE (OID_GET_SET_TOGGLE | OID_802_11_NETWORK_TYPE_IN_USE) -#define RT_OID_802_11_TX_POWER_LEVEL (OID_GET_SET_TOGGLE | OID_802_11_TX_POWER_LEVEL) -#define RT_OID_802_11_RSSI_TRIGGER (OID_GET_SET_TOGGLE | OID_802_11_RSSI_TRIGGER) -#define RT_OID_802_11_FRAGMENTATION_THRESHOLD (OID_GET_SET_TOGGLE | OID_802_11_FRAGMENTATION_THRESHOLD) -#define RT_OID_802_11_RTS_THRESHOLD (OID_GET_SET_TOGGLE | OID_802_11_RTS_THRESHOLD) -#define RT_OID_802_11_RX_ANTENNA_SELECTED (OID_GET_SET_TOGGLE | OID_802_11_RX_ANTENNA_SELECTED) -#define RT_OID_802_11_TX_ANTENNA_SELECTED (OID_GET_SET_TOGGLE | OID_802_11_TX_ANTENNA_SELECTED) -#define RT_OID_802_11_SUPPORTED_RATES (OID_GET_SET_TOGGLE | OID_802_11_SUPPORTED_RATES) -#define RT_OID_802_11_DESIRED_RATES (OID_GET_SET_TOGGLE | OID_802_11_DESIRED_RATES) -#define RT_OID_802_11_CONFIGURATION (OID_GET_SET_TOGGLE | OID_802_11_CONFIGURATION) -#define RT_OID_802_11_POWER_MODE (OID_GET_SET_TOGGLE | OID_802_11_POWER_MODE) - -typedef enum _NDIS_802_11_STATUS_TYPE -{ - Ndis802_11StatusType_Authentication, - Ndis802_11StatusType_MediaStreamMode, - Ndis802_11StatusType_PMKID_CandidateList, - Ndis802_11StatusTypeMax // not a real type, defined as an upper bound -} NDIS_802_11_STATUS_TYPE, *PNDIS_802_11_STATUS_TYPE; - -typedef UCHAR NDIS_802_11_MAC_ADDRESS[6]; - -typedef struct _NDIS_802_11_STATUS_INDICATION -{ - NDIS_802_11_STATUS_TYPE StatusType; -} NDIS_802_11_STATUS_INDICATION, *PNDIS_802_11_STATUS_INDICATION; - -// mask for authentication/integrity fields -#define NDIS_802_11_AUTH_REQUEST_AUTH_FIELDS 0x0f - -#define NDIS_802_11_AUTH_REQUEST_REAUTH 0x01 -#define NDIS_802_11_AUTH_REQUEST_KEYUPDATE 0x02 -#define NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR 0x06 -#define NDIS_802_11_AUTH_REQUEST_GROUP_ERROR 0x0E - -typedef struct _NDIS_802_11_AUTHENTICATION_REQUEST -{ - ULONG Length; // Length of structure - NDIS_802_11_MAC_ADDRESS Bssid; - ULONG Flags; -} NDIS_802_11_AUTHENTICATION_REQUEST, *PNDIS_802_11_AUTHENTICATION_REQUEST; - -//Added new types for PMKID Candidate lists. -typedef struct _PMKID_CANDIDATE { - NDIS_802_11_MAC_ADDRESS BSSID; - ULONG Flags; -} PMKID_CANDIDATE, *PPMKID_CANDIDATE; - -typedef struct _NDIS_802_11_PMKID_CANDIDATE_LIST -{ - ULONG Version; // Version of the structure - ULONG NumCandidates; // No. of pmkid candidates - PMKID_CANDIDATE CandidateList[1]; -} NDIS_802_11_PMKID_CANDIDATE_LIST, *PNDIS_802_11_PMKID_CANDIDATE_LIST; - -//Flags for PMKID Candidate list structure -#define NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED 0x01 - -// Added new types for OFDM 5G and 2.4G -typedef enum _NDIS_802_11_NETWORK_TYPE -{ - Ndis802_11FH, - Ndis802_11DS, - Ndis802_11OFDM5, - Ndis802_11OFDM5_N, - Ndis802_11OFDM24, - Ndis802_11OFDM24_N, - Ndis802_11Automode, - Ndis802_11NetworkTypeMax // not a real type, defined as an upper bound -} NDIS_802_11_NETWORK_TYPE, *PNDIS_802_11_NETWORK_TYPE; - -typedef struct _NDIS_802_11_NETWORK_TYPE_LIST -{ - UINT NumberOfItems; // in list below, at least 1 - NDIS_802_11_NETWORK_TYPE NetworkType [1]; -} NDIS_802_11_NETWORK_TYPE_LIST, *PNDIS_802_11_NETWORK_TYPE_LIST; - -typedef enum _NDIS_802_11_POWER_MODE -{ - Ndis802_11PowerModeCAM, - Ndis802_11PowerModeMAX_PSP, - Ndis802_11PowerModeFast_PSP, - Ndis802_11PowerModeLegacy_PSP, - Ndis802_11PowerModeMax // not a real mode, defined as an upper bound -} NDIS_802_11_POWER_MODE, *PNDIS_802_11_POWER_MODE; - -typedef ULONG NDIS_802_11_TX_POWER_LEVEL; // in milliwatts - -// -// Received Signal Strength Indication -// -typedef LONG NDIS_802_11_RSSI; // in dBm - -typedef struct _NDIS_802_11_CONFIGURATION_FH -{ - ULONG Length; // Length of structure - ULONG HopPattern; // As defined by 802.11, MSB set - ULONG HopSet; // to one if non-802.11 - ULONG DwellTime; // units are Kusec -} NDIS_802_11_CONFIGURATION_FH, *PNDIS_802_11_CONFIGURATION_FH; - -typedef struct _NDIS_802_11_CONFIGURATION -{ - ULONG Length; // Length of structure - ULONG BeaconPeriod; // units are Kusec - ULONG ATIMWindow; // units are Kusec - ULONG DSConfig; // Frequency, units are kHz - NDIS_802_11_CONFIGURATION_FH FHConfig; -} NDIS_802_11_CONFIGURATION, *PNDIS_802_11_CONFIGURATION; - -typedef struct _NDIS_802_11_STATISTICS -{ - ULONG Length; // Length of structure - LARGE_INTEGER TransmittedFragmentCount; - LARGE_INTEGER MulticastTransmittedFrameCount; - LARGE_INTEGER FailedCount; - LARGE_INTEGER RetryCount; - LARGE_INTEGER MultipleRetryCount; - LARGE_INTEGER RTSSuccessCount; - LARGE_INTEGER RTSFailureCount; - LARGE_INTEGER ACKFailureCount; - LARGE_INTEGER FrameDuplicateCount; - LARGE_INTEGER ReceivedFragmentCount; - LARGE_INTEGER MulticastReceivedFrameCount; - LARGE_INTEGER FCSErrorCount; - LARGE_INTEGER TKIPLocalMICFailures; - LARGE_INTEGER TKIPRemoteMICErrors; - LARGE_INTEGER TKIPICVErrors; - LARGE_INTEGER TKIPCounterMeasuresInvoked; - LARGE_INTEGER TKIPReplays; - LARGE_INTEGER CCMPFormatErrors; - LARGE_INTEGER CCMPReplays; - LARGE_INTEGER CCMPDecryptErrors; - LARGE_INTEGER FourWayHandshakeFailures; -} NDIS_802_11_STATISTICS, *PNDIS_802_11_STATISTICS; - -typedef ULONG NDIS_802_11_KEY_INDEX; -typedef ULONGLONG NDIS_802_11_KEY_RSC; - -#define MAX_RADIUS_SRV_NUM 2 // 802.1x failover number - -typedef struct PACKED _RADIUS_SRV_INFO { - UINT32 radius_ip; - UINT32 radius_port; - UCHAR radius_key[64]; - UCHAR radius_key_len; -} RADIUS_SRV_INFO, *PRADIUS_SRV_INFO; - -typedef struct PACKED _RADIUS_KEY_INFO -{ - UCHAR radius_srv_num; - RADIUS_SRV_INFO radius_srv_info[MAX_RADIUS_SRV_NUM]; - UCHAR ieee8021xWEP; // dynamic WEP - UCHAR key_index; - UCHAR key_length; // length of key in bytes - UCHAR key_material[13]; -} RADIUS_KEY_INFO, *PRADIUS_KEY_INFO; - -// It's used by 802.1x daemon to require relative configuration -typedef struct PACKED _RADIUS_CONF -{ - UINT32 Length; // Length of this structure - UCHAR mbss_num; // indicate multiple BSS number - UINT32 own_ip_addr; - UINT32 retry_interval; - UINT32 session_timeout_interval; - UCHAR EAPifname[IFNAMSIZ]; - UCHAR EAPifname_len; - UCHAR PreAuthifname[IFNAMSIZ]; - UCHAR PreAuthifname_len; - RADIUS_KEY_INFO RadiusInfo[8/*MAX_MBSSID_NUM*/]; -} RADIUS_CONF, *PRADIUS_CONF; - - - -#ifdef CONFIG_STA_SUPPORT -// Key mapping keys require a BSSID -typedef struct _NDIS_802_11_KEY -{ - UINT Length; // Length of this structure - UINT KeyIndex; - UINT KeyLength; // length of key in bytes - NDIS_802_11_MAC_ADDRESS BSSID; - NDIS_802_11_KEY_RSC KeyRSC; - UCHAR KeyMaterial[1]; // variable length depending on above field -} NDIS_802_11_KEY, *PNDIS_802_11_KEY; -#endif // CONFIG_STA_SUPPORT // - -typedef struct _NDIS_802_11_REMOVE_KEY -{ - UINT Length; // Length of this structure - UINT KeyIndex; - NDIS_802_11_MAC_ADDRESS BSSID; -} NDIS_802_11_REMOVE_KEY, *PNDIS_802_11_REMOVE_KEY; - -typedef struct _NDIS_802_11_WEP -{ - UINT Length; // Length of this structure - UINT KeyIndex; // 0 is the per-client key, 1-N are the - // global keys - UINT KeyLength; // length of key in bytes - UCHAR KeyMaterial[1];// variable length depending on above field -} NDIS_802_11_WEP, *PNDIS_802_11_WEP; - - -typedef enum _NDIS_802_11_NETWORK_INFRASTRUCTURE -{ - Ndis802_11IBSS, - Ndis802_11Infrastructure, - Ndis802_11AutoUnknown, - Ndis802_11Monitor, - Ndis802_11InfrastructureMax // Not a real value, defined as upper bound -} NDIS_802_11_NETWORK_INFRASTRUCTURE, *PNDIS_802_11_NETWORK_INFRASTRUCTURE; - -// Add new authentication modes -typedef enum _NDIS_802_11_AUTHENTICATION_MODE -{ - Ndis802_11AuthModeOpen, - Ndis802_11AuthModeShared, - Ndis802_11AuthModeAutoSwitch, - Ndis802_11AuthModeWPA, - Ndis802_11AuthModeWPAPSK, - Ndis802_11AuthModeWPANone, - Ndis802_11AuthModeWPA2, - Ndis802_11AuthModeWPA2PSK, - Ndis802_11AuthModeWPA1WPA2, - Ndis802_11AuthModeWPA1PSKWPA2PSK, - Ndis802_11AuthModeMax // Not a real mode, defined as upper bound -} NDIS_802_11_AUTHENTICATION_MODE, *PNDIS_802_11_AUTHENTICATION_MODE; - -typedef UCHAR NDIS_802_11_RATES[NDIS_802_11_LENGTH_RATES]; // Set of 8 data rates -typedef UCHAR NDIS_802_11_RATES_EX[NDIS_802_11_LENGTH_RATES_EX]; // Set of 16 data rates - -typedef struct PACKED _NDIS_802_11_SSID -{ - UINT SsidLength; // length of SSID field below, in bytes; - // this can be zero. - UCHAR Ssid[NDIS_802_11_LENGTH_SSID]; // SSID information field -} NDIS_802_11_SSID, *PNDIS_802_11_SSID; - - -typedef struct PACKED _NDIS_WLAN_BSSID -{ - ULONG Length; // Length of this structure - NDIS_802_11_MAC_ADDRESS MacAddress; // BSSID - UCHAR Reserved[2]; - NDIS_802_11_SSID Ssid; // SSID - ULONG Privacy; // WEP encryption requirement - NDIS_802_11_RSSI Rssi; // receive signal strength in dBm - NDIS_802_11_NETWORK_TYPE NetworkTypeInUse; - NDIS_802_11_CONFIGURATION Configuration; - NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode; - NDIS_802_11_RATES SupportedRates; -} NDIS_WLAN_BSSID, *PNDIS_WLAN_BSSID; - -typedef struct PACKED _NDIS_802_11_BSSID_LIST -{ - UINT NumberOfItems; // in list below, at least 1 - NDIS_WLAN_BSSID Bssid[1]; -} NDIS_802_11_BSSID_LIST, *PNDIS_802_11_BSSID_LIST; - -// Added Capabilities, IELength and IEs for each BSSID -typedef struct PACKED _NDIS_WLAN_BSSID_EX -{ - ULONG Length; // Length of this structure - NDIS_802_11_MAC_ADDRESS MacAddress; // BSSID - UCHAR Reserved[2]; - NDIS_802_11_SSID Ssid; // SSID - UINT Privacy; // WEP encryption requirement - NDIS_802_11_RSSI Rssi; // receive signal - // strength in dBm - NDIS_802_11_NETWORK_TYPE NetworkTypeInUse; - NDIS_802_11_CONFIGURATION Configuration; - NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode; - NDIS_802_11_RATES_EX SupportedRates; - ULONG IELength; - UCHAR IEs[1]; -} NDIS_WLAN_BSSID_EX, *PNDIS_WLAN_BSSID_EX; - -typedef struct PACKED _NDIS_802_11_BSSID_LIST_EX -{ - UINT NumberOfItems; // in list below, at least 1 - NDIS_WLAN_BSSID_EX Bssid[1]; -} NDIS_802_11_BSSID_LIST_EX, *PNDIS_802_11_BSSID_LIST_EX; - -typedef struct PACKED _NDIS_802_11_FIXED_IEs -{ - UCHAR Timestamp[8]; - USHORT BeaconInterval; - USHORT Capabilities; -} NDIS_802_11_FIXED_IEs, *PNDIS_802_11_FIXED_IEs; - -typedef struct _NDIS_802_11_VARIABLE_IEs -{ - UCHAR ElementID; - UCHAR Length; // Number of bytes in data field - UCHAR data[1]; -} NDIS_802_11_VARIABLE_IEs, *PNDIS_802_11_VARIABLE_IEs; - -typedef ULONG NDIS_802_11_FRAGMENTATION_THRESHOLD; - -typedef ULONG NDIS_802_11_RTS_THRESHOLD; - -typedef ULONG NDIS_802_11_ANTENNA; - -typedef enum _NDIS_802_11_PRIVACY_FILTER -{ - Ndis802_11PrivFilterAcceptAll, - Ndis802_11PrivFilter8021xWEP -} NDIS_802_11_PRIVACY_FILTER, *PNDIS_802_11_PRIVACY_FILTER; - -// Added new encryption types -// Also aliased typedef to new name -typedef enum _NDIS_802_11_WEP_STATUS -{ - Ndis802_11WEPEnabled, - Ndis802_11Encryption1Enabled = Ndis802_11WEPEnabled, - Ndis802_11WEPDisabled, - Ndis802_11EncryptionDisabled = Ndis802_11WEPDisabled, - Ndis802_11WEPKeyAbsent, - Ndis802_11Encryption1KeyAbsent = Ndis802_11WEPKeyAbsent, - Ndis802_11WEPNotSupported, - Ndis802_11EncryptionNotSupported = Ndis802_11WEPNotSupported, - Ndis802_11Encryption2Enabled, - Ndis802_11Encryption2KeyAbsent, - Ndis802_11Encryption3Enabled, - Ndis802_11Encryption3KeyAbsent, - Ndis802_11Encryption4Enabled, // TKIP or AES mix - Ndis802_11Encryption4KeyAbsent, - Ndis802_11GroupWEP40Enabled, - Ndis802_11GroupWEP104Enabled, -} NDIS_802_11_WEP_STATUS, *PNDIS_802_11_WEP_STATUS, - NDIS_802_11_ENCRYPTION_STATUS, *PNDIS_802_11_ENCRYPTION_STATUS; - -typedef enum _NDIS_802_11_RELOAD_DEFAULTS -{ - Ndis802_11ReloadWEPKeys -} NDIS_802_11_RELOAD_DEFAULTS, *PNDIS_802_11_RELOAD_DEFAULTS; - -#define NDIS_802_11_AI_REQFI_CAPABILITIES 1 -#define NDIS_802_11_AI_REQFI_LISTENINTERVAL 2 -#define NDIS_802_11_AI_REQFI_CURRENTAPADDRESS 4 - -#define NDIS_802_11_AI_RESFI_CAPABILITIES 1 -#define NDIS_802_11_AI_RESFI_STATUSCODE 2 -#define NDIS_802_11_AI_RESFI_ASSOCIATIONID 4 - -typedef struct _NDIS_802_11_AI_REQFI -{ - USHORT Capabilities; - USHORT ListenInterval; - NDIS_802_11_MAC_ADDRESS CurrentAPAddress; -} NDIS_802_11_AI_REQFI, *PNDIS_802_11_AI_REQFI; - -typedef struct _NDIS_802_11_AI_RESFI -{ - USHORT Capabilities; - USHORT StatusCode; - USHORT AssociationId; -} NDIS_802_11_AI_RESFI, *PNDIS_802_11_AI_RESFI; - -typedef struct _NDIS_802_11_ASSOCIATION_INFORMATION -{ - ULONG Length; - USHORT AvailableRequestFixedIEs; - NDIS_802_11_AI_REQFI RequestFixedIEs; - ULONG RequestIELength; - ULONG OffsetRequestIEs; - USHORT AvailableResponseFixedIEs; - NDIS_802_11_AI_RESFI ResponseFixedIEs; - ULONG ResponseIELength; - ULONG OffsetResponseIEs; -} NDIS_802_11_ASSOCIATION_INFORMATION, *PNDIS_802_11_ASSOCIATION_INFORMATION; - -typedef struct _NDIS_802_11_AUTHENTICATION_EVENT -{ - NDIS_802_11_STATUS_INDICATION Status; - NDIS_802_11_AUTHENTICATION_REQUEST Request[1]; -} NDIS_802_11_AUTHENTICATION_EVENT, *PNDIS_802_11_AUTHENTICATION_EVENT; - -/* -typedef struct _NDIS_802_11_TEST -{ - ULONG Length; - ULONG Type; - union - { - NDIS_802_11_AUTHENTICATION_EVENT AuthenticationEvent; - NDIS_802_11_RSSI RssiTrigger; - }; -} NDIS_802_11_TEST, *PNDIS_802_11_TEST; - */ - -// 802.11 Media stream constraints, associated with OID_802_11_MEDIA_STREAM_MODE -typedef enum _NDIS_802_11_MEDIA_STREAM_MODE -{ - Ndis802_11MediaStreamOff, - Ndis802_11MediaStreamOn, -} NDIS_802_11_MEDIA_STREAM_MODE, *PNDIS_802_11_MEDIA_STREAM_MODE; - -// PMKID Structures -typedef UCHAR NDIS_802_11_PMKID_VALUE[16]; - -#ifdef CONFIG_STA_SUPPORT -typedef struct _BSSID_INFO -{ - NDIS_802_11_MAC_ADDRESS BSSID; - NDIS_802_11_PMKID_VALUE PMKID; -} BSSID_INFO, *PBSSID_INFO; - -typedef struct _NDIS_802_11_PMKID -{ - UINT Length; - UINT BSSIDInfoCount; - BSSID_INFO BSSIDInfo[1]; -} NDIS_802_11_PMKID, *PNDIS_802_11_PMKID; -#endif // CONFIG_STA_SUPPORT // - - -typedef struct _NDIS_802_11_AUTHENTICATION_ENCRYPTION -{ - NDIS_802_11_AUTHENTICATION_MODE AuthModeSupported; - NDIS_802_11_ENCRYPTION_STATUS EncryptStatusSupported; -} NDIS_802_11_AUTHENTICATION_ENCRYPTION, *PNDIS_802_11_AUTHENTICATION_ENCRYPTION; - -typedef struct _NDIS_802_11_CAPABILITY -{ - ULONG Length; - ULONG Version; - ULONG NoOfPMKIDs; - ULONG NoOfAuthEncryptPairsSupported; - NDIS_802_11_AUTHENTICATION_ENCRYPTION AuthenticationEncryptionSupported[1]; -} NDIS_802_11_CAPABILITY, *PNDIS_802_11_CAPABILITY; - -//#endif //of WIN 2k -#endif //UNDER_CE - -#if WIRELESS_EXT <= 11 -#ifndef SIOCDEVPRIVATE -#define SIOCDEVPRIVATE 0x8BE0 -#endif -#define SIOCIWFIRSTPRIV SIOCDEVPRIVATE -#endif - -#ifdef CONFIG_STA_SUPPORT -#define RTPRIV_IOCTL_SET (SIOCIWFIRSTPRIV + 0x02) - -#ifdef DBG -#define RTPRIV_IOCTL_BBP (SIOCIWFIRSTPRIV + 0x03) -#define RTPRIV_IOCTL_MAC (SIOCIWFIRSTPRIV + 0x05) -#define RTPRIV_IOCTL_E2P (SIOCIWFIRSTPRIV + 0x07) -#endif - -#ifdef RALINK_ATE -#ifdef RALINK_28xx_QA -#define RTPRIV_IOCTL_ATE (SIOCIWFIRSTPRIV + 0x08) -#endif // RALINK_28xx_QA // -#endif // RALINK_ATE // - -#define RTPRIV_IOCTL_STATISTICS (SIOCIWFIRSTPRIV + 0x09) -#define RTPRIV_IOCTL_ADD_PMKID_CACHE (SIOCIWFIRSTPRIV + 0x0A) -#define RTPRIV_IOCTL_RADIUS_DATA (SIOCIWFIRSTPRIV + 0x0C) -#define RTPRIV_IOCTL_GSITESURVEY (SIOCIWFIRSTPRIV + 0x0D) -#define RT_PRIV_IOCTL (SIOCIWFIRSTPRIV + 0x0E) // Sync. with RT61 (for wpa_supplicant) -#define RTPRIV_IOCTL_GET_MAC_TABLE (SIOCIWFIRSTPRIV + 0x0F) - -#define RTPRIV_IOCTL_SHOW (SIOCIWFIRSTPRIV + 0x11) -enum { - SHOW_CONN_STATUS = 4, - SHOW_DRVIER_VERION = 5, - SHOW_BA_INFO = 6, - SHOW_DESC_INFO = 7, -#ifdef RT2870 - SHOW_RXBULK_INFO = 8, - SHOW_TXBULK_INFO = 9, -#endif // RT2870 // - RAIO_OFF = 10, - RAIO_ON = 11, -#ifdef QOS_DLS_SUPPORT - SHOW_DLS_ENTRY_INFO = 19, -#endif // QOS_DLS_SUPPORT // - SHOW_CFG_VALUE = 20, - SHOW_ADHOC_ENTRY_INFO = 21, -}; - - -#endif // CONFIG_STA_SUPPORT // - -#ifdef SNMP_SUPPORT -//SNMP ieee 802dot11, kathy , 2008_0220 -// dot11res(3) -#define RT_OID_802_11_MANUFACTUREROUI 0x0700 -#define RT_OID_802_11_MANUFACTURERNAME 0x0701 -#define RT_OID_802_11_RESOURCETYPEIDNAME 0x0702 - -// dot11smt(1) -#define RT_OID_802_11_PRIVACYOPTIONIMPLEMENTED 0x0703 -#define RT_OID_802_11_POWERMANAGEMENTMODE 0x0704 -#define OID_802_11_WEPDEFAULTKEYVALUE 0x0705 // read , write -#define OID_802_11_WEPDEFAULTKEYID 0x0706 -#define RT_OID_802_11_WEPKEYMAPPINGLENGTH 0x0707 -#define OID_802_11_SHORTRETRYLIMIT 0x0708 -#define OID_802_11_LONGRETRYLIMIT 0x0709 -#define RT_OID_802_11_PRODUCTID 0x0710 -#define RT_OID_802_11_MANUFACTUREID 0x0711 - -// //dot11Phy(4) -#define OID_802_11_CURRENTCHANNEL 0x0712 - -//dot11mac -#define RT_OID_802_11_MAC_ADDRESS 0x0713 -#endif // SNMP_SUPPORT // - -#define OID_802_11_BUILD_CHANNEL_EX 0x0714 -#define OID_802_11_GET_CH_LIST 0x0715 -#define OID_802_11_GET_COUNTRY_CODE 0x0716 -#define OID_802_11_GET_CHANNEL_GEOGRAPHY 0x0717 - -#ifdef LLTD_SUPPORT -// for consistency with RT61 -#define RT_OID_GET_PHY_MODE 0x761 -#endif // LLTD_SUPPORT // - -// MIMO Tx parameter, ShortGI, MCS, STBC, etc. these are fields in TXWI. Don't change this definition!!! -typedef union _HTTRANSMIT_SETTING { -#ifdef RT_BIG_ENDIAN - struct { - USHORT MODE:2; // Use definition MODE_xxx. -// USHORT rsv:3; - USHORT TxBF:1; - USHORT rsv:2; - USHORT STBC:2; //SPACE - USHORT ShortGI:1; - USHORT BW:1; //channel bandwidth 20MHz or 40 MHz - USHORT MCS:7; // MCS - } field; -#else - struct { - USHORT MCS:7; // MCS - USHORT BW:1; //channel bandwidth 20MHz or 40 MHz - USHORT ShortGI:1; - USHORT STBC:2; //SPACE -// USHORT rsv:3; - USHORT rsv:2; - USHORT TxBF:1; - USHORT MODE:2; // Use definition MODE_xxx. - } field; -#endif - USHORT word; - } HTTRANSMIT_SETTING, *PHTTRANSMIT_SETTING; - -typedef enum _RT_802_11_PREAMBLE { - Rt802_11PreambleLong, - Rt802_11PreambleShort, - Rt802_11PreambleAuto -} RT_802_11_PREAMBLE, *PRT_802_11_PREAMBLE; - -// Only for STA, need to sync with AP -typedef enum _RT_802_11_PHY_MODE { - PHY_11BG_MIXED = 0, - PHY_11B, - PHY_11A, - PHY_11ABG_MIXED, - PHY_11G, -#ifdef DOT11_N_SUPPORT - PHY_11ABGN_MIXED, // both band 5 - PHY_11N_2_4G, // 11n-only with 2.4G band 6 - PHY_11GN_MIXED, // 2.4G band 7 - PHY_11AN_MIXED, // 5G band 8 - PHY_11BGN_MIXED, // if check 802.11b. 9 - PHY_11AGN_MIXED, // if check 802.11b. 10 - PHY_11N_5G, // 11n-only with 5G band 11 -#endif // DOT11_N_SUPPORT // -} RT_802_11_PHY_MODE; - -// put all proprietery for-query objects here to reduce # of Query_OID -typedef struct _RT_802_11_LINK_STATUS { - ULONG CurrTxRate; // in units of 0.5Mbps - ULONG ChannelQuality; // 0..100 % - ULONG TxByteCount; // both ok and fail - ULONG RxByteCount; // both ok and fail - ULONG CentralChannel; // 40MHz central channel number -} RT_802_11_LINK_STATUS, *PRT_802_11_LINK_STATUS; - -typedef struct _RT_802_11_EVENT_LOG { - LARGE_INTEGER SystemTime; // timestammp via NdisGetCurrentSystemTime() - UCHAR Addr[MAC_ADDR_LENGTH]; - USHORT Event; // EVENT_xxx -} RT_802_11_EVENT_LOG, *PRT_802_11_EVENT_LOG; - -typedef struct _RT_802_11_EVENT_TABLE { - ULONG Num; - ULONG Rsv; // to align Log[] at LARGE_INEGER boundary - RT_802_11_EVENT_LOG Log[MAX_NUMBER_OF_EVENT]; -} RT_802_11_EVENT_TABLE, PRT_802_11_EVENT_TABLE; - -// MIMO Tx parameter, ShortGI, MCS, STBC, etc. these are fields in TXWI. Don't change this definition!!! -typedef union _MACHTTRANSMIT_SETTING { - struct { - USHORT MCS:7; // MCS - USHORT BW:1; //channel bandwidth 20MHz or 40 MHz - USHORT ShortGI:1; - USHORT STBC:2; //SPACE - USHORT rsv:3; - USHORT MODE:2; // Use definition MODE_xxx. - } field; - USHORT word; - } MACHTTRANSMIT_SETTING, *PMACHTTRANSMIT_SETTING; - -typedef struct _RT_802_11_MAC_ENTRY { - UCHAR Addr[MAC_ADDR_LENGTH]; - UCHAR Aid; - UCHAR Psm; // 0:PWR_ACTIVE, 1:PWR_SAVE - UCHAR MimoPs; // 0:MMPS_STATIC, 1:MMPS_DYNAMIC, 3:MMPS_Enabled - CHAR AvgRssi0; - CHAR AvgRssi1; - CHAR AvgRssi2; - UINT32 ConnectedTime; - MACHTTRANSMIT_SETTING TxRate; -} RT_802_11_MAC_ENTRY, *PRT_802_11_MAC_ENTRY; - -typedef struct _RT_802_11_MAC_TABLE { - ULONG Num; - RT_802_11_MAC_ENTRY Entry[MAX_NUMBER_OF_MAC]; -} RT_802_11_MAC_TABLE, *PRT_802_11_MAC_TABLE; - -// structure for query/set hardware register - MAC, BBP, RF register -typedef struct _RT_802_11_HARDWARE_REGISTER { - ULONG HardwareType; // 0:MAC, 1:BBP, 2:RF register, 3:EEPROM - ULONG Offset; // Q/S register offset addr - ULONG Data; // R/W data buffer -} RT_802_11_HARDWARE_REGISTER, *PRT_802_11_HARDWARE_REGISTER; - -// structure to tune BBP R17 "RX AGC VGC init" -//typedef struct _RT_802_11_RX_AGC_VGC_TUNING { -// UCHAR FalseCcaLowerThreshold; // 0-255, def 10 -// UCHAR FalseCcaUpperThreshold; // 0-255, def 100 -// UCHAR VgcDelta; // R17 +-= VgcDelta whenever flase CCA over UpprThreshold -// // or lower than LowerThresholdupper threshold -// UCHAR VgcUpperBound; // max value of R17 -//} RT_802_11_RX_AGC_VGC_TUNING, *PRT_802_11_RX_AGC_VGC_TUNING; - -typedef struct _RT_802_11_AP_CONFIG { - ULONG EnableTxBurst; // 0-disable, 1-enable - ULONG EnableTurboRate; // 0-disable, 1-enable 72/100mbps turbo rate - ULONG IsolateInterStaTraffic; // 0-disable, 1-enable isolation - ULONG HideSsid; // 0-disable, 1-enable hiding - ULONG UseBGProtection; // 0-AUTO, 1-always ON, 2-always OFF - ULONG UseShortSlotTime; // 0-no use, 1-use 9-us short slot time - ULONG Rsv1; // must be 0 - ULONG SystemErrorBitmap; // ignore upon SET, return system error upon QUERY -} RT_802_11_AP_CONFIG, *PRT_802_11_AP_CONFIG; - -// structure to query/set STA_CONFIG -typedef struct _RT_802_11_STA_CONFIG { - ULONG EnableTxBurst; // 0-disable, 1-enable - ULONG EnableTurboRate; // 0-disable, 1-enable 72/100mbps turbo rate - ULONG UseBGProtection; // 0-AUTO, 1-always ON, 2-always OFF - ULONG UseShortSlotTime; // 0-no use, 1-use 9-us short slot time when applicable - ULONG AdhocMode; // 0-11b rates only (WIFI spec), 1 - b/g mixed, 2 - g only - ULONG HwRadioStatus; // 0-OFF, 1-ON, default is 1, Read-Only - ULONG Rsv1; // must be 0 - ULONG SystemErrorBitmap; // ignore upon SET, return system error upon QUERY -} RT_802_11_STA_CONFIG, *PRT_802_11_STA_CONFIG; - -// -// For OID Query or Set about BA structure -// -typedef struct _OID_BACAP_STRUC { - UCHAR RxBAWinLimit; - UCHAR TxBAWinLimit; - UCHAR Policy; // 0: DELAY_BA 1:IMMED_BA (//BA Policy subfiled value in ADDBA frame) 2:BA-not use. other value invalid - UCHAR MpduDensity; // 0: DELAY_BA 1:IMMED_BA (//BA Policy subfiled value in ADDBA frame) 2:BA-not use. other value invalid - UCHAR AmsduEnable; //Enable AMSDU transmisstion - UCHAR AmsduSize; // 0:3839, 1:7935 bytes. UINT MSDUSizeToBytes[] = { 3839, 7935}; - UCHAR MMPSmode; // MIMO power save more, 0:static, 1:dynamic, 2:rsv, 3:mimo enable - BOOLEAN AutoBA; // Auto BA will automatically -} OID_BACAP_STRUC, *POID_BACAP_STRUC; - -typedef struct _RT_802_11_ACL_ENTRY { - UCHAR Addr[MAC_ADDR_LENGTH]; - USHORT Rsv; -} RT_802_11_ACL_ENTRY, *PRT_802_11_ACL_ENTRY; - -typedef struct PACKED _RT_802_11_ACL { - ULONG Policy; // 0-disable, 1-positive list, 2-negative list - ULONG Num; - RT_802_11_ACL_ENTRY Entry[MAX_NUMBER_OF_ACL]; -} RT_802_11_ACL, *PRT_802_11_ACL; - -typedef struct _RT_802_11_WDS { - ULONG Num; - NDIS_802_11_MAC_ADDRESS Entry[24/*MAX_NUM_OF_WDS_LINK*/]; - ULONG KeyLength; - UCHAR KeyMaterial[32]; -} RT_802_11_WDS, *PRT_802_11_WDS; - -typedef struct _RT_802_11_TX_RATES_ { - UCHAR SupRateLen; - UCHAR SupRate[MAX_LENGTH_OF_SUPPORT_RATES]; - UCHAR ExtRateLen; - UCHAR ExtRate[MAX_LENGTH_OF_SUPPORT_RATES]; -} RT_802_11_TX_RATES, *PRT_802_11_TX_RATES; - - -// Definition of extra information code -#define GENERAL_LINK_UP 0x0 // Link is Up -#define GENERAL_LINK_DOWN 0x1 // Link is Down -#define HW_RADIO_OFF 0x2 // Hardware radio off -#define SW_RADIO_OFF 0x3 // Software radio off -#define AUTH_FAIL 0x4 // Open authentication fail -#define AUTH_FAIL_KEYS 0x5 // Shared authentication fail -#define ASSOC_FAIL 0x6 // Association failed -#define EAP_MIC_FAILURE 0x7 // Deauthencation because MIC failure -#define EAP_4WAY_TIMEOUT 0x8 // Deauthencation on 4-way handshake timeout -#define EAP_GROUP_KEY_TIMEOUT 0x9 // Deauthencation on group key handshake timeout -#define EAP_SUCCESS 0xa // EAP succeed -#define DETECT_RADAR_SIGNAL 0xb // Radar signal occur in current channel -#define EXTRA_INFO_MAX 0xb // Indicate Last OID - -#define EXTRA_INFO_CLEAR 0xffffffff - -// This is OID setting structure. So only GF or MM as Mode. This is valid when our wirelss mode has 802.11n in use. -typedef struct { - RT_802_11_PHY_MODE PhyMode; // - UCHAR TransmitNo; - UCHAR HtMode; //HTMODE_GF or HTMODE_MM - UCHAR ExtOffset; //extension channel above or below - UCHAR MCS; - UCHAR BW; - UCHAR STBC; - UCHAR SHORTGI; - UCHAR rsv; -} OID_SET_HT_PHYMODE, *POID_SET_HT_PHYMODE; - -#ifdef NINTENDO_AP -#define NINTENDO_MAX_ENTRY 16 -#define NINTENDO_SSID_NAME_LN 8 -#define NINTENDO_SSID_NAME "NWCUSBAP" -#define NINTENDO_PROBE_REQ_FLAG_MASK 0x03 -#define NINTENDO_PROBE_REQ_ON 0x01 -#define NINTENDO_PROBE_REQ_SIGNAL 0x02 -#define NINTENDO_PROBE_RSP_ON 0x01 -#define NINTENDO_SSID_NICKNAME_LN 20 - -#define NINTENDO_WEPKEY_LN 13 - -typedef struct _NINTENDO_SSID -{ - UCHAR NINTENDOFixChar[NINTENDO_SSID_NAME_LN]; - UCHAR zero1; - UCHAR registe; - UCHAR ID; - UCHAR zero2; - UCHAR NICKname[NINTENDO_SSID_NICKNAME_LN]; -} RT_NINTENDO_SSID, *PRT_NINTENDO_SSID; - -typedef struct _NINTENDO_ENTRY -{ - UCHAR NICKname[NINTENDO_SSID_NICKNAME_LN]; - UCHAR DS_Addr[ETH_LENGTH_OF_ADDRESS]; - UCHAR registe; - UCHAR UserSpaceAck; -} RT_NINTENDO_ENTRY, *PRT_NINTENDO_ENTRY; - -//RTPRIV_IOCTL_NINTENDO_GET_TABLE -//RTPRIV_IOCTL_NINTENDO_SET_TABLE -typedef struct _NINTENDO_TABLE -{ - UINT number; - RT_NINTENDO_ENTRY entry[NINTENDO_MAX_ENTRY]; -} RT_NINTENDO_TABLE, *PRT_NINTENDO_TABLE; - -//RTPRIV_IOCTL_NINTENDO_SEED_WEPKEY -typedef struct _NINTENDO_SEED_WEPKEY -{ - UCHAR seed[NINTENDO_SSID_NICKNAME_LN]; - UCHAR wepkey[16];//use 13 for 104 bits wep key -} RT_NINTENDO_SEED_WEPKEY, *PRT_NINTENDO_SEED_WEPKEY; -#endif // NINTENDO_AP // - -#ifdef LLTD_SUPPORT -typedef struct _RT_LLTD_ASSOICATION_ENTRY { - UCHAR Addr[ETH_LENGTH_OF_ADDRESS]; - unsigned short MOR; // maximum operational rate - UCHAR phyMode; -} RT_LLTD_ASSOICATION_ENTRY, *PRT_LLTD_ASSOICATION_ENTRY; - -typedef struct _RT_LLTD_ASSOICATION_TABLE { - unsigned int Num; - RT_LLTD_ASSOICATION_ENTRY Entry[MAX_NUMBER_OF_MAC]; -} RT_LLTD_ASSOICATION_TABLE, *PRT_LLTD_ASSOICATION_TABLE; -#endif // LLTD_SUPPORT // - -#ifdef CONFIG_STA_SUPPORT -#ifdef QOS_DLS_SUPPORT -//rt2860, kathy 2007-0118 -// structure for DLS -typedef struct _RT_802_11_DLS_UI { - USHORT TimeOut; // unit: second , set by UI - USHORT CountDownTimer; // unit: second , used by driver only - NDIS_802_11_MAC_ADDRESS MacAddr; // set by UI - UCHAR Status; // 0: none , 1: wait STAkey, 2: finish DLS setup , set by driver only - BOOLEAN Valid; // 1: valid , 0: invalid , set by UI, use to setup or tear down DLS link -} RT_802_11_DLS_UI, *PRT_802_11_DLS_UI; - -typedef struct _RT_802_11_DLS_INFO { - RT_802_11_DLS_UI Entry[MAX_NUMBER_OF_DLS_ENTRY]; - UCHAR num; -} RT_802_11_DLS_INFO, *PRT_802_11_DLS_INFO; - -typedef enum _RT_802_11_DLS_MODE { - DLS_NONE, - DLS_WAIT_KEY, - DLS_FINISH -} RT_802_11_DLS_MODE; -#endif // QOS_DLS_SUPPORT // - -#ifdef WPA_SUPPLICANT_SUPPORT -#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT -#define RT_ASSOC_EVENT_FLAG 0x0101 -#define RT_DISASSOC_EVENT_FLAG 0x0102 -#define RT_REQIE_EVENT_FLAG 0x0103 -#define RT_RESPIE_EVENT_FLAG 0x0104 -#define RT_ASSOCINFO_EVENT_FLAG 0x0105 -#define RT_PMKIDCAND_FLAG 0x0106 -#define RT_INTERFACE_DOWN 0x0107 -#define RT_INTERFACE_UP 0x0108 -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // -#endif // WPA_SUPPLICANT_SUPPORT // -#endif // CONFIG_STA_SUPPORT // - - -#define MAX_CUSTOM_LEN 128 - -#ifdef CONFIG_STA_SUPPORT -typedef enum _RT_802_11_D_CLIENT_MODE -{ - Rt802_11_D_None, - Rt802_11_D_Flexible, - Rt802_11_D_Strict, -} RT_802_11_D_CLIENT_MODE, *PRT_802_11_D_CLIENT_MODE; -#endif // CONFIG_STA_SUPPORT // - -typedef struct _RT_CHANNEL_LIST_INFO -{ - UCHAR ChannelList[MAX_NUM_OF_CHS]; // list all supported channels for site survey - UCHAR ChannelListNum; // number of channel in ChannelList[] -} RT_CHANNEL_LIST_INFO, *PRT_CHANNEL_LIST_INFO; - -// WSC configured credential -typedef struct _WSC_CREDENTIAL -{ - NDIS_802_11_SSID SSID; // mandatory - USHORT AuthType; // mandatory, 1: open, 2: wpa-psk, 4: shared, 8:wpa, 0x10: wpa2, 0x20: wpa2-psk - USHORT EncrType; // mandatory, 1: none, 2: wep, 4: tkip, 8: aes - UCHAR Key[64]; // mandatory, Maximum 64 byte - USHORT KeyLength; - UCHAR MacAddr[6]; // mandatory, AP MAC address - UCHAR KeyIndex; // optional, default is 1 - UCHAR Rsvd[3]; // Make alignment -} WSC_CREDENTIAL, *PWSC_CREDENTIAL; - -// WSC configured profiles -typedef struct _WSC_PROFILE -{ - UINT ProfileCnt; - WSC_CREDENTIAL Profile[8]; // Support up to 8 profiles -} WSC_PROFILE, *PWSC_PROFILE; - - -#endif // _OID_H_ - +#include "../rt2860/oid.h" diff --git a/drivers/staging/rt2870/rt2870.h b/drivers/staging/rt2870/rt2870.h index a69cf338e498..5e5b3f2b7eb1 100644 --- a/drivers/staging/rt2870/rt2870.h +++ b/drivers/staging/rt2870/rt2870.h @@ -33,7 +33,6 @@ /* rtmp_def.h */ // -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) #define BULKAGGRE_ZISE 100 #define RT28XX_DRVDATA_SET(_a) usb_set_intfdata(_a, pAd); #define RT28XX_PUT_DEVICE usb_put_dev @@ -41,22 +40,15 @@ #define RTUSB_SUBMIT_URB(pUrb) usb_submit_urb(pUrb, GFP_ATOMIC) #define RTUSB_URB_ALLOC_BUFFER(pUsb_Dev, BufSize, pDma_addr) usb_buffer_alloc(pUsb_Dev, BufSize, GFP_ATOMIC, pDma_addr) #define RTUSB_URB_FREE_BUFFER(pUsb_Dev, BufSize, pTransferBuf, Dma_addr) usb_buffer_free(pUsb_Dev, BufSize, pTransferBuf, Dma_addr) -#else -#define BULKAGGRE_ZISE 60 -#define RT28XX_DRVDATA_SET(_a) -#define RT28XX_PUT_DEVICE(dev_p) -#define RTUSB_ALLOC_URB(iso) usb_alloc_urb(iso) -#define RTUSB_SUBMIT_URB(pUrb) usb_submit_urb(pUrb) -#define RTUSB_URB_ALLOC_BUFFER(pUsb_Dev, BufSize, pDma_addr) kmalloc(BufSize, GFP_ATOMIC) -#define RTUSB_URB_FREE_BUFFER(pUsb_Dev, BufSize, pTransferBuf, Dma_addr) kfree(pTransferBuf) -#endif #define RXBULKAGGRE_ZISE 12 #define MAX_TXBULK_LIMIT (LOCAL_TXBUF_SIZE*(BULKAGGRE_ZISE-1)) #define MAX_TXBULK_SIZE (LOCAL_TXBUF_SIZE*BULKAGGRE_ZISE) #define MAX_RXBULK_SIZE (LOCAL_TXBUF_SIZE*RXBULKAGGRE_ZISE) #define MAX_MLME_HANDLER_MEMORY 20 +#ifndef RT30xx #define RETRY_LIMIT 10 +#endif #define BUFFER_SIZE 2400 //2048 #define TX_RING 0xa #define PRIO_RING 0xc @@ -72,6 +64,9 @@ #define fRTUSB_BULK_OUT_DATA_NORMAL_2 0x00020000 #define fRTUSB_BULK_OUT_DATA_NORMAL_3 0x00040000 #define fRTUSB_BULK_OUT_DATA_NORMAL_4 0x00080000 +#ifdef RT30xx +#define fRTUSB_BULK_OUT_DATA_NORMAL_5 0x00100000 +#endif #define fRTUSB_BULK_OUT_PSPOLL 0x00000020 #define fRTUSB_BULK_OUT_DATA_FRAG 0x00000040 @@ -79,10 +74,7 @@ #define fRTUSB_BULK_OUT_DATA_FRAG_3 0x00000100 #define fRTUSB_BULK_OUT_DATA_FRAG_4 0x00000200 -#ifdef RALINK_ATE -#define fRTUSB_BULK_OUT_DATA_ATE 0x00100000 -#endif // RALINK_ATE // - +#ifndef RT30xx #define RT2870_USB_DEVICES \ { \ {USB_DEVICE(0x148F,0x2770)}, /* Ralink */ \ @@ -148,6 +140,84 @@ {USB_DEVICE(0x7392,0x7717)}, /* Edimax */ \ { }/* Terminating entry */ \ } +#endif +#ifdef RT30xx +#define RT2870_USB_DEVICES \ +{ \ + {USB_DEVICE(0x148F,0x2770)}, /* Ralink */ \ + {USB_DEVICE(0x148F,0x2870)}, /* Ralink */ \ + {USB_DEVICE(0x148F,0x3070)}, /* Ralink 3070 */ \ + {USB_DEVICE(0x148F,0x3071)}, /* Ralink 3071 */ \ + {USB_DEVICE(0x148F,0x3072)}, /* Ralink 3072 */ \ + {USB_DEVICE(0x0B05,0x1731)}, /* Asus */ \ + {USB_DEVICE(0x0B05,0x1732)}, /* Asus */ \ + {USB_DEVICE(0x0B05,0x1742)}, /* Asus */ \ + {USB_DEVICE(0x0DF6,0x0017)}, /* Sitecom */ \ + {USB_DEVICE(0x0DF6,0x002B)}, /* Sitecom */ \ + {USB_DEVICE(0x0DF6,0x002C)}, /* Sitecom */ \ + {USB_DEVICE(0x0DF6,0x003E)}, /* Sitecom 3070 */ \ + {USB_DEVICE(0x0DF6,0x002D)}, /* Sitecom */ \ + {USB_DEVICE(0x0DF6,0x0039)}, /* Sitecom 2770 */ \ + {USB_DEVICE(0x14B2,0x3C06)}, /* Conceptronic */ \ + {USB_DEVICE(0x14B2,0x3C28)}, /* Conceptronic */ \ + {USB_DEVICE(0x2019,0xED06)}, /* Planex Communications, Inc. */ \ + {USB_DEVICE(0x2019,0xAB25)}, /* Planex Communications, Inc. RT3070 */ \ + {USB_DEVICE(0x07D1,0x3C09)}, /* D-Link */ \ + {USB_DEVICE(0x07D1,0x3C11)}, /* D-Link */ \ + {USB_DEVICE(0x2001,0x3C09)}, /* D-Link */ \ + {USB_DEVICE(0x2001,0x3C0A)}, /* D-Link 3072*/ \ + {USB_DEVICE(0x14B2,0x3C07)}, /* AL */ \ + {USB_DEVICE(0x14B2,0x3C12)}, /* AL 3070 */ \ + {USB_DEVICE(0x050D,0x8053)}, /* Belkin */ \ + {USB_DEVICE(0x14B2,0x3C23)}, /* Airlink */ \ + {USB_DEVICE(0x14B2,0x3C27)}, /* Airlink */ \ + {USB_DEVICE(0x07AA,0x002F)}, /* Corega */ \ + {USB_DEVICE(0x07AA,0x003C)}, /* Corega */ \ + {USB_DEVICE(0x07AA,0x003F)}, /* Corega */ \ + {USB_DEVICE(0x18C5,0x0012)}, /* Corega 3070 */ \ + {USB_DEVICE(0x1044,0x800B)}, /* Gigabyte */ \ + {USB_DEVICE(0x1044,0x800D)}, /* Gigabyte GN-WB32L 3070 */ \ + {USB_DEVICE(0x15A9,0x0006)}, /* Sparklan */ \ + {USB_DEVICE(0x083A,0xB522)}, /* SMC */ \ + {USB_DEVICE(0x083A,0xA618)}, /* SMC */ \ + {USB_DEVICE(0x083A,0x8522)}, /* Arcadyan */ \ + {USB_DEVICE(0x083A,0x7512)}, /* Arcadyan 2770 */ \ + {USB_DEVICE(0x083A,0x7522)}, /* Arcadyan */ \ + {USB_DEVICE(0x083A,0x7511)}, /* Arcadyan 3070 */ \ + {USB_DEVICE(0x0CDE,0x0022)}, /* ZCOM */ \ + {USB_DEVICE(0x0586,0x3416)}, /* Zyxel */ \ + {USB_DEVICE(0x0CDE,0x0025)}, /* Zyxel */ \ + {USB_DEVICE(0x1740,0x9701)}, /* EnGenius */ \ + {USB_DEVICE(0x1740,0x9702)}, /* EnGenius */ \ + {USB_DEVICE(0x1740,0x9703)}, /* EnGenius 3070 */ \ + {USB_DEVICE(0x0471,0x200f)}, /* Philips */ \ + {USB_DEVICE(0x14B2,0x3C25)}, /* Draytek */ \ + {USB_DEVICE(0x13D3,0x3247)}, /* AzureWave */ \ + {USB_DEVICE(0x13D3,0x3273)}, /* AzureWave 3070*/ \ + {USB_DEVICE(0x083A,0x6618)}, /* Accton */ \ + {USB_DEVICE(0x15c5,0x0008)}, /* Amit */ \ + {USB_DEVICE(0x0E66,0x0001)}, /* Hawking */ \ + {USB_DEVICE(0x0E66,0x0003)}, /* Hawking */ \ + {USB_DEVICE(0x129B,0x1828)}, /* Siemens */ \ + {USB_DEVICE(0x157E,0x300E)}, /* U-Media */ \ + {USB_DEVICE(0x050d,0x805c)}, \ + {USB_DEVICE(0x1482,0x3C09)}, /* Abocom*/ \ + {USB_DEVICE(0x14B2,0x3C09)}, /* Alpha */ \ + {USB_DEVICE(0x04E8,0x2018)}, /* samsung */ \ + {USB_DEVICE(0x07B8,0x3070)}, /* AboCom 3070 */ \ + {USB_DEVICE(0x07B8,0x3071)}, /* AboCom 3071 */ \ + {USB_DEVICE(0x07B8,0x3072)}, /* Abocom 3072 */ \ + {USB_DEVICE(0x7392,0x7711)}, /* Edimax 3070 */ \ + {USB_DEVICE(0x5A57,0x0280)}, /* Zinwell */ \ + {USB_DEVICE(0x5A57,0x0282)}, /* Zinwell */ \ + {USB_DEVICE(0x1A32,0x0304)}, /* Quanta 3070 */ \ + {USB_DEVICE(0x0789,0x0162)}, /* Logitec 2870 */ \ + {USB_DEVICE(0x0789,0x0163)}, /* Logitec 2870 */ \ + {USB_DEVICE(0x0789,0x0164)}, /* Logitec 2870 */ \ + {USB_DEVICE(0x1EDA,0x2310)}, /* AirTies 3070 */ \ + { }/* Terminating entry */ \ +} +#endif #define FREE_HTTX_RING(_p, _b, _t) \ { \ @@ -161,30 +231,6 @@ // // RXINFO appends at the end of each rx packet. // -#ifdef RT_BIG_ENDIAN -typedef struct PACKED _RXINFO_STRUC { - UINT32 PlcpSignal:12; - UINT32 LastAMSDU:1; - UINT32 CipherAlg:1; - UINT32 PlcpRssil:1; - UINT32 Decrypted:1; - UINT32 AMPDU:1; // To be moved - UINT32 L2PAD:1; - UINT32 RSSI:1; - UINT32 HTC:1; - UINT32 AMSDU:1; // rx with 802.3 header, not 802.11 header. - UINT32 CipherErr:2; // 0: decryption okay, 1:ICV error, 2:MIC error, 3:KEY not valid - UINT32 Crc:1; // 1: CRC error - UINT32 MyBss:1; // 1: this frame belongs to the same BSSID - UINT32 Bcast:1; // 1: this is a broadcast frame - UINT32 Mcast:1; // 1: this is a multicast frame - UINT32 U2M:1; // 1: this RX frame is unicast to me - UINT32 FRAG:1; - UINT32 NULLDATA:1; - UINT32 DATA:1; - UINT32 BA:1; -} RXINFO_STRUC, *PRXINFO_STRUC, RT28XX_RXD_STRUC, *PRT28XX_RXD_STRUC; -#else typedef struct PACKED _RXINFO_STRUC { UINT32 BA:1; UINT32 DATA:1; @@ -207,25 +253,10 @@ typedef struct PACKED _RXINFO_STRUC { UINT32 LastAMSDU:1; UINT32 PlcpSignal:12; } RXINFO_STRUC, *PRXINFO_STRUC, RT28XX_RXD_STRUC, *PRT28XX_RXD_STRUC; -#endif - // // TXINFO // -#ifdef RT_BIG_ENDIAN -typedef struct _TXINFO_STRUC { - // Word 0 - UINT32 USBDMATxburst:1;//used ONLY in USB bulk Aggre. Force USB DMA transmit frame from current selected endpoint - UINT32 USBDMANextVLD:1; //used ONLY in USB bulk Aggregation, NextValid - UINT32 rsv2:2; // Software use. - UINT32 SwUseLastRound:1; // Software use. - UINT32 QSEL:2; // select on-chip FIFO ID for 2nd-stage output scheduler.0:MGMT, 1:HCCA 2:EDCA - UINT32 WIV:1; // Wireless Info Valid. 1 if Driver already fill WI, o if DMA needs to copy WI to correctposition - UINT32 rsv:8; - UINT32 USBDMATxPktLen:16; //used ONLY in USB bulk Aggregation, Total byte counts of all sub-frame. -} TXINFO_STRUC, *PTXINFO_STRUC; -#else typedef struct _TXINFO_STRUC { // Word 0 UINT32 USBDMATxPktLen:16; //used ONLY in USB bulk Aggregation, Total byte counts of all sub-frame. @@ -237,7 +268,6 @@ typedef struct _TXINFO_STRUC { UINT32 USBDMANextVLD:1; //used ONLY in USB bulk Aggregation, NextValid UINT32 USBDMATxburst:1;//used ONLY in USB bulk Aggre. Force USB DMA transmit frame from current selected endpoint } TXINFO_STRUC, *PTXINFO_STRUC; -#endif #define TXINFO_SIZE 4 #define RXINFO_SIZE 4 @@ -254,6 +284,23 @@ typedef struct _MGMT_STRUC { /* ----------------- EEPROM Related MACRO ----------------- */ +#ifdef RT30xx +#define RT28xx_EEPROM_READ16(pAd, offset, var) \ + do { \ + RTUSBReadEEPROM(pAd, offset, (PUCHAR)&(var), 2); \ + if(!pAd->bUseEfuse) \ + var = le2cpu16(var); \ + }while(0) + +#define RT28xx_EEPROM_WRITE16(pAd, offset, var) \ + do{ \ + USHORT _tmpVar=var; \ + if(!pAd->bUseEfuse) \ + _tmpVar = cpu2le16(var); \ + RTUSBWriteEEPROM(pAd, offset, (PUCHAR)&(_tmpVar), 2); \ + }while(0) +#endif // RT30xx // +#ifndef RT30xx #define RT28xx_EEPROM_READ16(pAd, offset, var) \ do { \ RTUSBReadEEPROM(pAd, offset, (PUCHAR)&(var), 2); \ @@ -266,6 +313,7 @@ typedef struct _MGMT_STRUC { _tmpVar = cpu2le16(var); \ RTUSBWriteEEPROM(pAd, offset, (PUCHAR)&(_tmpVar), 2); \ }while(0) +#endif // RT30xx // /* ----------------- TASK/THREAD Related MACRO ----------------- */ #define RT28XX_TASK_THREAD_INIT(pAd, Status) \ @@ -273,19 +321,8 @@ typedef struct _MGMT_STRUC { /* ----------------- Frimware Related MACRO ----------------- */ -#if 0 -#define RT28XX_FIRMUD_INIT(pAd) \ - { UINT32 MacReg; \ - RTUSBReadMACRegister(pAd, MAC_CSR0, &MacReg); } - -#define RT28XX_FIRMUD_END(pAd) \ - RTUSBWriteMACRegister(pAd, 0x7014, 0xffffffff); \ - RTUSBWriteMACRegister(pAd, 0x701c, 0xffffffff); \ - RTUSBFirmwareRun(pAd); -#else #define RT28XX_WRITE_FIRMWARE(_pAd, _pFwImage, _FwLen) \ RTUSBFirmwareWrite(_pAd, _pFwImage, _FwLen) -#endif /* ----------------- TX Related MACRO ----------------- */ #define RT28XX_START_DEQUEUE(pAd, QueIdx, irqFlags) \ @@ -370,13 +407,6 @@ extern UCHAR EpToQueue[6]; /* ----------------- RX Related MACRO ----------------- */ //#define RT28XX_RX_ERROR_CHECK RTMPCheckRxWI -#if 0 -#define RT28XX_RCV_INIT(pAd) \ - pAd->TransferBufferLength = 0; \ - pAd->ReadPosition = 0; \ - pAd->pCurrRxContext = NULL; -#endif - #define RT28XX_RV_ALL_BUF_END(bBulkReceive) \ /* We return STATUS_MORE_PROCESSING_REQUIRED so that the completion */ \ /* routine (IofCompleteRequest) will stop working on the irp. */ \ @@ -384,27 +414,6 @@ extern UCHAR EpToQueue[6]; /* ----------------- ASIC Related MACRO ----------------- */ -#if 0 -#define RT28XX_DMA_WRITE_INIT(GloCfg) \ - { GloCfg.field.EnTXWriteBackDDONE = 1; \ - GloCfg.field.EnableRxDMA = 1; \ - GloCfg.field.EnableTxDMA = 1; } - -#define RT28XX_DMA_POST_WRITE(_pAd) \ - do{ USB_DMA_CFG_STRUC UsbCfg; \ - UsbCfg.word = 0; \ - /* for last packet, PBF might use more than limited, so minus 2 to prevent from error */ \ - UsbCfg.field.RxBulkAggLmt = (MAX_RXBULK_SIZE /1024)-3; \ - UsbCfg.field.phyclear = 0; \ - /* usb version is 1.1,do not use bulk in aggregation */ \ - if (_pAd->BulkInMaxPacketSize == 512) \ - UsbCfg.field.RxBulkAggEn = 1; \ - UsbCfg.field.RxBulkEn = 1; \ - UsbCfg.field.TxBulkEn = 1; \ - UsbCfg.field.RxBulkAggTOut = 0x80; /* 2006-10-18 */ \ - RTUSBWriteMACRegister(_pAd, USB_DMA_CFG, UsbCfg.word); \ - }while(0) -#endif // reset MAC of a station entry to 0xFFFFFFFFFFFF #define RT28XX_STA_ENTRY_MAC_RESET(pAd, Wcid) \ @@ -420,6 +429,14 @@ extern UCHAR EpToQueue[6]; RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_SET_CLIENT_MAC_ENTRY, \ pEntry, sizeof(MAC_TABLE_ENTRY)); +#ifdef RT30xx +// add by johnli, fix "in_interrupt" error when call "MacTableDeleteEntry" in Rx tasklet +// Set MAC register value according operation mode +#define RT28XX_UPDATE_PROTECT(pAd) \ + RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_UPDATE_PROTECT, NULL, 0); +// end johnli +#endif + // remove Pair-wise key material from ASIC // yet implement #define RT28XX_STA_ENTRY_KEY_DEL(pAd, BssIdx, Wcid) @@ -507,8 +524,10 @@ extern UCHAR EpToQueue[6]; #define RT28xx_CHIP_NAME "RT2870" #define USB_CYC_CFG 0x02a4 +#ifndef RT30xx #define STATUS_SUCCESS 0x00 #define STATUS_UNSUCCESSFUL 0x01 +#endif #define NT_SUCCESS(status) (((status) > 0) ? (1):(0)) #define InterlockedIncrement atomic_inc #define NdisInterlockedIncrement atomic_inc @@ -533,7 +552,9 @@ extern UCHAR EpToQueue[6]; //#undef MlmeAllocateMemory //#undef MlmeFreeMemory +#ifndef RT30xx typedef int NTSTATUS; +#endif typedef struct usb_device * PUSB_DEV; /* MACRO for linux usb */ @@ -551,23 +572,9 @@ typedef struct usb_ctrlrequest devctrlrequest; #define UNLINK_TIMEOUT_MS 3 /* unlink urb */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,7) #define RTUSB_UNLINK_URB(pUrb) usb_kill_urb(pUrb) -#else -#define RTUSB_UNLINK_URB(pUrb) usb_unlink_urb(pUrb) -#endif // Prototypes of completion funuc. -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) -#define RTUSBBulkOutDataPacketComplete(purb, pt_regs) RTUSBBulkOutDataPacketComplete(purb) -#define RTUSBBulkOutMLMEPacketComplete(pUrb, pt_regs) RTUSBBulkOutMLMEPacketComplete(pUrb) -#define RTUSBBulkOutNullFrameComplete(pUrb, pt_regs) RTUSBBulkOutNullFrameComplete(pUrb) -#define RTUSBBulkOutRTSFrameComplete(pUrb, pt_regs) RTUSBBulkOutRTSFrameComplete(pUrb) -#define RTUSBBulkOutPsPollComplete(pUrb, pt_regs) RTUSBBulkOutPsPollComplete(pUrb) -#define RTUSBBulkRxComplete(pUrb, pt_regs) RTUSBBulkRxComplete(pUrb) -#endif - - VOID RTUSBBulkOutDataPacketComplete(purbb_t purb, struct pt_regs *pt_regs); VOID RTUSBBulkOutMLMEPacketComplete(purbb_t pUrb, struct pt_regs *pt_regs); VOID RTUSBBulkOutNullFrameComplete(purbb_t pUrb, struct pt_regs *pt_regs); @@ -575,7 +582,7 @@ VOID RTUSBBulkOutRTSFrameComplete(purbb_t pUrb, struct pt_regs *pt_regs); VOID RTUSBBulkOutPsPollComplete(purbb_t pUrb, struct pt_regs *pt_regs); VOID RTUSBBulkRxComplete(purbb_t pUrb, struct pt_regs *pt_regs); - +#ifndef RT30xx #define RTUSBMlmeUp(pAd) \ { \ POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie; \ @@ -591,7 +598,22 @@ VOID RTUSBBulkRxComplete(purbb_t pUrb, struct pt_regs *pt_regs); CHECK_PID_LEGALITY(task_pid(pObj->RTUSBCmdThr_task)) \ up(&(pAd->RTUSBCmd_semaphore)); \ } +#endif +#ifdef RT30xx +#define RTUSBMlmeUp(pAd) \ +{ \ + POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie; \ + if(pObj->MLMEThr_pid>0) \ + up(&(pAd->mlme_semaphore)); \ +} +#define RTUSBCMDUp(pAd) \ +{ \ + POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie; \ + if(pObj->RTUSBCmdThr_pid>0) \ + up(&(pAd->RTUSBCmd_semaphore)); \ +} +#endif static inline NDIS_STATUS RTMPAllocateMemory( OUT PVOID *ptr, @@ -633,7 +655,9 @@ typedef struct _RT_SET_ASIC_WCID { ULONG WCID; // mechanism for rekeying: 0:disable, 1: time-based, 2: packet-based ULONG SetTid; // time-based: seconds, packet-based: kilo-packets ULONG DeleteTid; // time-based: seconds, packet-based: kilo-packets +#ifndef RT30xx UCHAR Addr[MAC_ADDR_LEN]; // avoid in interrupt when write key +#endif } RT_SET_ASIC_WCID,*PRT_SET_ASIC_WCID; typedef struct _RT_SET_ASIC_WCID_ATTRI { @@ -676,13 +700,6 @@ typedef struct _CmdQ { UINT32 CmdQState; }CmdQ, *PCmdQ; -// -// For WPA SUPPLICANT: WIRELESS EXT support wireless events: v14 or newer -// -#if WIRELESS_EXT >= 14 -//#define WPA_SUPPLICANT_SUPPORT 1 -#endif - /* oid.h */ // Cipher suite type for mixed mode group cipher, P802.11i-2004 typedef enum _RT_802_11_CIPHER_SUITE_TYPE { @@ -742,6 +759,11 @@ typedef struct _CMDHandler_TLV { #define CMDTHREAD_802_11_SET_PREAMBLE 0x0D790101 // cmd #define CMDTHREAD_802_11_COUNTER_MEASURE 0x0D790102 // cmd +#ifdef RT30xx +// add by johnli, fix "in_interrupt" error when call "MacTableDeleteEntry" in Rx tasklet +#define CMDTHREAD_UPDATE_PROTECT 0x0D790103 // cmd +// end johnli +#endif #define WPA1AKMBIT 0x01 #define WPA2AKMBIT 0x02 diff --git a/drivers/staging/rt2870/rt28xx.h b/drivers/staging/rt2870/rt28xx.h index 3927d22f78fb..29bad957de48 100644 --- a/drivers/staging/rt2870/rt28xx.h +++ b/drivers/staging/rt2870/rt28xx.h @@ -1,2689 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - rt28xx.h - - Abstract: - RT28xx ASIC related definition & structures - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Jan Lee Jan-3-2006 created for RT2860c -*/ - -#ifndef __RT28XX_H__ -#define __RT28XX_H__ - - -// -// PCI registers - base address 0x0000 -// -#define PCI_CFG 0x0000 -#define PCI_EECTRL 0x0004 -#define PCI_MCUCTRL 0x0008 - -// -// SCH/DMA registers - base address 0x0200 -// -// INT_SOURCE_CSR: Interrupt source register. Write one to clear corresponding bit -// -#define DMA_CSR0 0x200 -#define INT_SOURCE_CSR 0x200 -#ifdef RT_BIG_ENDIAN -typedef union _INT_SOURCE_CSR_STRUC { - struct { - UINT32 :14; - UINT32 TxCoherent:1; - UINT32 RxCoherent:1; - UINT32 GPTimer:1; - UINT32 AutoWakeup:1;//bit14 - UINT32 TXFifoStatusInt:1;//FIFO Statistics is full, sw should read 0x171c - UINT32 PreTBTT:1; - UINT32 TBTTInt:1; - UINT32 RxTxCoherent:1; - UINT32 MCUCommandINT:1; - UINT32 MgmtDmaDone:1; - UINT32 HccaDmaDone:1; - UINT32 Ac3DmaDone:1; - UINT32 Ac2DmaDone:1; - UINT32 Ac1DmaDone:1; - UINT32 Ac0DmaDone:1; - UINT32 RxDone:1; - UINT32 TxDelayINT:1; //delayed interrupt, not interrupt until several int or time limit hit - UINT32 RxDelayINT:1; //dealyed interrupt - } field; - UINT32 word; -} INT_SOURCE_CSR_STRUC, *PINT_SOURCE_CSR_STRUC; -#else -typedef union _INT_SOURCE_CSR_STRUC { - struct { - UINT32 RxDelayINT:1; - UINT32 TxDelayINT:1; - UINT32 RxDone:1; - UINT32 Ac0DmaDone:1;//4 - UINT32 Ac1DmaDone:1; - UINT32 Ac2DmaDone:1; - UINT32 Ac3DmaDone:1; - UINT32 HccaDmaDone:1; // bit7 - UINT32 MgmtDmaDone:1; - UINT32 MCUCommandINT:1;//bit 9 - UINT32 RxTxCoherent:1; - UINT32 TBTTInt:1; - UINT32 PreTBTT:1; - UINT32 TXFifoStatusInt:1;//FIFO Statistics is full, sw should read 0x171c - UINT32 AutoWakeup:1;//bit14 - UINT32 GPTimer:1; - UINT32 RxCoherent:1;//bit16 - UINT32 TxCoherent:1; - UINT32 :14; - } field; - UINT32 word; -} INT_SOURCE_CSR_STRUC, *PINT_SOURCE_CSR_STRUC; -#endif - -// -// INT_MASK_CSR: Interrupt MASK register. 1: the interrupt is mask OFF -// -#define INT_MASK_CSR 0x204 -#ifdef RT_BIG_ENDIAN -typedef union _INT_MASK_CSR_STRUC { - struct { - UINT32 TxCoherent:1; - UINT32 RxCoherent:1; - UINT32 :20; - UINT32 MCUCommandINT:1; - UINT32 MgmtDmaDone:1; - UINT32 HccaDmaDone:1; - UINT32 Ac3DmaDone:1; - UINT32 Ac2DmaDone:1; - UINT32 Ac1DmaDone:1; - UINT32 Ac0DmaDone:1; - UINT32 RxDone:1; - UINT32 TxDelay:1; - UINT32 RXDelay_INT_MSK:1; - } field; - UINT32 word; -}INT_MASK_CSR_STRUC, *PINT_MASK_CSR_STRUC; -#else -typedef union _INT_MASK_CSR_STRUC { - struct { - UINT32 RXDelay_INT_MSK:1; - UINT32 TxDelay:1; - UINT32 RxDone:1; - UINT32 Ac0DmaDone:1; - UINT32 Ac1DmaDone:1; - UINT32 Ac2DmaDone:1; - UINT32 Ac3DmaDone:1; - UINT32 HccaDmaDone:1; - UINT32 MgmtDmaDone:1; - UINT32 MCUCommandINT:1; - UINT32 :20; - UINT32 RxCoherent:1; - UINT32 TxCoherent:1; - } field; - UINT32 word; -} INT_MASK_CSR_STRUC, *PINT_MASK_CSR_STRUC; -#endif -#define WPDMA_GLO_CFG 0x208 -#ifdef RT_BIG_ENDIAN -typedef union _WPDMA_GLO_CFG_STRUC { - struct { - UINT32 HDR_SEG_LEN:16; - UINT32 RXHdrScater:8; - UINT32 BigEndian:1; - UINT32 EnTXWriteBackDDONE:1; - UINT32 WPDMABurstSIZE:2; - UINT32 RxDMABusy:1; - UINT32 EnableRxDMA:1; - UINT32 TxDMABusy:1; - UINT32 EnableTxDMA:1; - } field; - UINT32 word; -}WPDMA_GLO_CFG_STRUC, *PWPDMA_GLO_CFG_STRUC; -#else -typedef union _WPDMA_GLO_CFG_STRUC { - struct { - UINT32 EnableTxDMA:1; - UINT32 TxDMABusy:1; - UINT32 EnableRxDMA:1; - UINT32 RxDMABusy:1; - UINT32 WPDMABurstSIZE:2; - UINT32 EnTXWriteBackDDONE:1; - UINT32 BigEndian:1; - UINT32 RXHdrScater:8; - UINT32 HDR_SEG_LEN:16; - } field; - UINT32 word; -} WPDMA_GLO_CFG_STRUC, *PWPDMA_GLO_CFG_STRUC; -#endif -#define WPDMA_RST_IDX 0x20c -#ifdef RT_BIG_ENDIAN -typedef union _WPDMA_RST_IDX_STRUC { - struct { - UINT32 :15; - UINT32 RST_DRX_IDX0:1; - UINT32 rsv:10; - UINT32 RST_DTX_IDX5:1; - UINT32 RST_DTX_IDX4:1; - UINT32 RST_DTX_IDX3:1; - UINT32 RST_DTX_IDX2:1; - UINT32 RST_DTX_IDX1:1; - UINT32 RST_DTX_IDX0:1; - } field; - UINT32 word; -}WPDMA_RST_IDX_STRUC, *PWPDMA_RST_IDX_STRUC; -#else -typedef union _WPDMA_RST_IDX_STRUC { - struct { - UINT32 RST_DTX_IDX0:1; - UINT32 RST_DTX_IDX1:1; - UINT32 RST_DTX_IDX2:1; - UINT32 RST_DTX_IDX3:1; - UINT32 RST_DTX_IDX4:1; - UINT32 RST_DTX_IDX5:1; - UINT32 rsv:10; - UINT32 RST_DRX_IDX0:1; - UINT32 :15; - } field; - UINT32 word; -} WPDMA_RST_IDX_STRUC, *PWPDMA_RST_IDX_STRUC; -#endif -#define DELAY_INT_CFG 0x0210 -#ifdef RT_BIG_ENDIAN -typedef union _DELAY_INT_CFG_STRUC { - struct { - UINT32 TXDLY_INT_EN:1; - UINT32 TXMAX_PINT:7; - UINT32 TXMAX_PTIME:8; - UINT32 RXDLY_INT_EN:1; - UINT32 RXMAX_PINT:7; - UINT32 RXMAX_PTIME:8; - } field; - UINT32 word; -}DELAY_INT_CFG_STRUC, *PDELAY_INT_CFG_STRUC; -#else -typedef union _DELAY_INT_CFG_STRUC { - struct { - UINT32 RXMAX_PTIME:8; - UINT32 RXMAX_PINT:7; - UINT32 RXDLY_INT_EN:1; - UINT32 TXMAX_PTIME:8; - UINT32 TXMAX_PINT:7; - UINT32 TXDLY_INT_EN:1; - } field; - UINT32 word; -} DELAY_INT_CFG_STRUC, *PDELAY_INT_CFG_STRUC; -#endif -#define WMM_AIFSN_CFG 0x0214 -#ifdef RT_BIG_ENDIAN -typedef union _AIFSN_CSR_STRUC { - struct { - UINT32 Rsv:16; - UINT32 Aifsn3:4; // for AC_VO - UINT32 Aifsn2:4; // for AC_VI - UINT32 Aifsn1:4; // for AC_BK - UINT32 Aifsn0:4; // for AC_BE - } field; - UINT32 word; -} AIFSN_CSR_STRUC, *PAIFSN_CSR_STRUC; -#else -typedef union _AIFSN_CSR_STRUC { - struct { - UINT32 Aifsn0:4; // for AC_BE - UINT32 Aifsn1:4; // for AC_BK - UINT32 Aifsn2:4; // for AC_VI - UINT32 Aifsn3:4; // for AC_VO - UINT32 Rsv:16; - } field; - UINT32 word; -} AIFSN_CSR_STRUC, *PAIFSN_CSR_STRUC; -#endif -// -// CWMIN_CSR: CWmin for each EDCA AC -// -#define WMM_CWMIN_CFG 0x0218 -#ifdef RT_BIG_ENDIAN -typedef union _CWMIN_CSR_STRUC { - struct { - UINT32 Rsv:16; - UINT32 Cwmin3:4; // for AC_VO - UINT32 Cwmin2:4; // for AC_VI - UINT32 Cwmin1:4; // for AC_BK - UINT32 Cwmin0:4; // for AC_BE - } field; - UINT32 word; -} CWMIN_CSR_STRUC, *PCWMIN_CSR_STRUC; -#else -typedef union _CWMIN_CSR_STRUC { - struct { - UINT32 Cwmin0:4; // for AC_BE - UINT32 Cwmin1:4; // for AC_BK - UINT32 Cwmin2:4; // for AC_VI - UINT32 Cwmin3:4; // for AC_VO - UINT32 Rsv:16; - } field; - UINT32 word; -} CWMIN_CSR_STRUC, *PCWMIN_CSR_STRUC; -#endif - -// -// CWMAX_CSR: CWmin for each EDCA AC -// -#define WMM_CWMAX_CFG 0x021c -#ifdef RT_BIG_ENDIAN -typedef union _CWMAX_CSR_STRUC { - struct { - UINT32 Rsv:16; - UINT32 Cwmax3:4; // for AC_VO - UINT32 Cwmax2:4; // for AC_VI - UINT32 Cwmax1:4; // for AC_BK - UINT32 Cwmax0:4; // for AC_BE - } field; - UINT32 word; -} CWMAX_CSR_STRUC, *PCWMAX_CSR_STRUC; -#else -typedef union _CWMAX_CSR_STRUC { - struct { - UINT32 Cwmax0:4; // for AC_BE - UINT32 Cwmax1:4; // for AC_BK - UINT32 Cwmax2:4; // for AC_VI - UINT32 Cwmax3:4; // for AC_VO - UINT32 Rsv:16; - } field; - UINT32 word; -} CWMAX_CSR_STRUC, *PCWMAX_CSR_STRUC; -#endif - - -// -// AC_TXOP_CSR0: AC_BK/AC_BE TXOP register -// -#define WMM_TXOP0_CFG 0x0220 -#ifdef RT_BIG_ENDIAN -typedef union _AC_TXOP_CSR0_STRUC { - struct { - USHORT Ac1Txop; // for AC_BE, in unit of 32us - USHORT Ac0Txop; // for AC_BK, in unit of 32us - } field; - UINT32 word; -} AC_TXOP_CSR0_STRUC, *PAC_TXOP_CSR0_STRUC; -#else -typedef union _AC_TXOP_CSR0_STRUC { - struct { - USHORT Ac0Txop; // for AC_BK, in unit of 32us - USHORT Ac1Txop; // for AC_BE, in unit of 32us - } field; - UINT32 word; -} AC_TXOP_CSR0_STRUC, *PAC_TXOP_CSR0_STRUC; -#endif - -// -// AC_TXOP_CSR1: AC_VO/AC_VI TXOP register -// -#define WMM_TXOP1_CFG 0x0224 -#ifdef RT_BIG_ENDIAN -typedef union _AC_TXOP_CSR1_STRUC { - struct { - USHORT Ac3Txop; // for AC_VO, in unit of 32us - USHORT Ac2Txop; // for AC_VI, in unit of 32us - } field; - UINT32 word; -} AC_TXOP_CSR1_STRUC, *PAC_TXOP_CSR1_STRUC; -#else -typedef union _AC_TXOP_CSR1_STRUC { - struct { - USHORT Ac2Txop; // for AC_VI, in unit of 32us - USHORT Ac3Txop; // for AC_VO, in unit of 32us - } field; - UINT32 word; -} AC_TXOP_CSR1_STRUC, *PAC_TXOP_CSR1_STRUC; -#endif -#define RINGREG_DIFF 0x10 -#define GPIO_CTRL_CFG 0x0228 //MAC_CSR13 -#define MCU_CMD_CFG 0x022c -#define TX_BASE_PTR0 0x0230 //AC_BK base address -#define TX_MAX_CNT0 0x0234 -#define TX_CTX_IDX0 0x0238 -#define TX_DTX_IDX0 0x023c -#define TX_BASE_PTR1 0x0240 //AC_BE base address -#define TX_MAX_CNT1 0x0244 -#define TX_CTX_IDX1 0x0248 -#define TX_DTX_IDX1 0x024c -#define TX_BASE_PTR2 0x0250 //AC_VI base address -#define TX_MAX_CNT2 0x0254 -#define TX_CTX_IDX2 0x0258 -#define TX_DTX_IDX2 0x025c -#define TX_BASE_PTR3 0x0260 //AC_VO base address -#define TX_MAX_CNT3 0x0264 -#define TX_CTX_IDX3 0x0268 -#define TX_DTX_IDX3 0x026c -#define TX_BASE_PTR4 0x0270 //HCCA base address -#define TX_MAX_CNT4 0x0274 -#define TX_CTX_IDX4 0x0278 -#define TX_DTX_IDX4 0x027c -#define TX_BASE_PTR5 0x0280 //MGMT base address -#define TX_MAX_CNT5 0x0284 -#define TX_CTX_IDX5 0x0288 -#define TX_DTX_IDX5 0x028c -#define TX_MGMTMAX_CNT TX_MAX_CNT5 -#define TX_MGMTCTX_IDX TX_CTX_IDX5 -#define TX_MGMTDTX_IDX TX_DTX_IDX5 -#define RX_BASE_PTR 0x0290 //RX base address -#define RX_MAX_CNT 0x0294 -#define RX_CRX_IDX 0x0298 -#define RX_DRX_IDX 0x029c -#define USB_DMA_CFG 0x02a0 -#ifdef RT_BIG_ENDIAN -typedef union _USB_DMA_CFG_STRUC { - struct { - UINT32 TxBusy:1; //USB DMA TX FSM busy . debug only - UINT32 RxBusy:1; //USB DMA RX FSM busy . debug only - UINT32 EpoutValid:6; //OUT endpoint data valid. debug only - UINT32 TxBulkEn:1; //Enable USB DMA Tx - UINT32 RxBulkEn:1; //Enable USB DMA Rx - UINT32 RxBulkAggEn:1; //Enable Rx Bulk Aggregation - UINT32 TxopHalt:1; //Halt TXOP count down when TX buffer is full. - UINT32 TxClear:1; //Clear USB DMA TX path - UINT32 rsv:2; - UINT32 phyclear:1; //phy watch dog enable. write 1 - UINT32 RxBulkAggLmt:8; //Rx Bulk Aggregation Limit in unit of 1024 bytes - UINT32 RxBulkAggTOut:8; //Rx Bulk Aggregation TimeOut in unit of 33ns - } field; - UINT32 word; -} USB_DMA_CFG_STRUC, *PUSB_DMA_CFG_STRUC; -#else -typedef union _USB_DMA_CFG_STRUC { - struct { - UINT32 RxBulkAggTOut:8; //Rx Bulk Aggregation TimeOut in unit of 33ns - UINT32 RxBulkAggLmt:8; //Rx Bulk Aggregation Limit in unit of 256 bytes - UINT32 phyclear:1; //phy watch dog enable. write 1 - UINT32 rsv:2; - UINT32 TxClear:1; //Clear USB DMA TX path - UINT32 TxopHalt:1; //Halt TXOP count down when TX buffer is full. - UINT32 RxBulkAggEn:1; //Enable Rx Bulk Aggregation - UINT32 RxBulkEn:1; //Enable USB DMA Rx - UINT32 TxBulkEn:1; //Enable USB DMA Tx - UINT32 EpoutValid:6; //OUT endpoint data valid - UINT32 RxBusy:1; //USB DMA RX FSM busy - UINT32 TxBusy:1; //USB DMA TX FSM busy - } field; - UINT32 word; -} USB_DMA_CFG_STRUC, *PUSB_DMA_CFG_STRUC; -#endif - -// -// 3 PBF registers -// -// -// Most are for debug. Driver doesn't touch PBF register. -#define PBF_SYS_CTRL 0x0400 -#define PBF_CFG 0x0408 -#define PBF_MAX_PCNT 0x040C -#define PBF_CTRL 0x0410 -#define PBF_INT_STA 0x0414 -#define PBF_INT_ENA 0x0418 -#define TXRXQ_PCNT 0x0438 -#define PBF_DBG 0x043c -#define PBF_CAP_CTRL 0x0440 - -// -// 4 MAC registers -// -// -// 4.1 MAC SYSTEM configuration registers (offset:0x1000) -// -#define MAC_CSR0 0x1000 -#ifdef RT_BIG_ENDIAN -typedef union _ASIC_VER_ID_STRUC { - struct { - USHORT ASICVer; // version : 2860 - USHORT ASICRev; // reversion : 0 - } field; - UINT32 word; -} ASIC_VER_ID_STRUC, *PASIC_VER_ID_STRUC; -#else -typedef union _ASIC_VER_ID_STRUC { - struct { - USHORT ASICRev; // reversion : 0 - USHORT ASICVer; // version : 2860 - } field; - UINT32 word; -} ASIC_VER_ID_STRUC, *PASIC_VER_ID_STRUC; -#endif -#define MAC_SYS_CTRL 0x1004 //MAC_CSR1 -#define MAC_ADDR_DW0 0x1008 // MAC ADDR DW0 -#define MAC_ADDR_DW1 0x100c // MAC ADDR DW1 -// -// MAC_CSR2: STA MAC register 0 -// -#ifdef RT_BIG_ENDIAN -typedef union _MAC_DW0_STRUC { - struct { - UCHAR Byte3; // MAC address byte 3 - UCHAR Byte2; // MAC address byte 2 - UCHAR Byte1; // MAC address byte 1 - UCHAR Byte0; // MAC address byte 0 - } field; - UINT32 word; -} MAC_DW0_STRUC, *PMAC_DW0_STRUC; -#else -typedef union _MAC_DW0_STRUC { - struct { - UCHAR Byte0; // MAC address byte 0 - UCHAR Byte1; // MAC address byte 1 - UCHAR Byte2; // MAC address byte 2 - UCHAR Byte3; // MAC address byte 3 - } field; - UINT32 word; -} MAC_DW0_STRUC, *PMAC_DW0_STRUC; -#endif - -// -// MAC_CSR3: STA MAC register 1 -// -#ifdef RT_BIG_ENDIAN -typedef union _MAC_DW1_STRUC { - struct { - UCHAR Rsvd1; - UCHAR U2MeMask; - UCHAR Byte5; // MAC address byte 5 - UCHAR Byte4; // MAC address byte 4 - } field; - UINT32 word; -} MAC_DW1_STRUC, *PMAC_DW1_STRUC; -#else -typedef union _MAC_DW1_STRUC { - struct { - UCHAR Byte4; // MAC address byte 4 - UCHAR Byte5; // MAC address byte 5 - UCHAR U2MeMask; - UCHAR Rsvd1; - } field; - UINT32 word; -} MAC_DW1_STRUC, *PMAC_DW1_STRUC; -#endif - -#define MAC_BSSID_DW0 0x1010 // MAC BSSID DW0 -#define MAC_BSSID_DW1 0x1014 // MAC BSSID DW1 - -// -// MAC_CSR5: BSSID register 1 -// -#ifdef RT_BIG_ENDIAN -typedef union _MAC_CSR5_STRUC { - struct { - USHORT Rsvd:11; - USHORT MBssBcnNum:3; - USHORT BssIdMode:2; // 0: one BSSID, 10: 4 BSSID, 01: 2 BSSID , 11: 8BSSID - UCHAR Byte5; // BSSID byte 5 - UCHAR Byte4; // BSSID byte 4 - } field; - UINT32 word; -} MAC_CSR5_STRUC, *PMAC_CSR5_STRUC; -#else -typedef union _MAC_CSR5_STRUC { - struct { - UCHAR Byte4; // BSSID byte 4 - UCHAR Byte5; // BSSID byte 5 - USHORT BssIdMask:2; // 0: one BSSID, 10: 4 BSSID, 01: 2 BSSID , 11: 8BSSID - USHORT MBssBcnNum:3; - USHORT Rsvd:11; - } field; - UINT32 word; -} MAC_CSR5_STRUC, *PMAC_CSR5_STRUC; -#endif - -#define MAX_LEN_CFG 0x1018 // rt2860b max 16k bytes. bit12:13 Maximum PSDU length (power factor) 0:2^13, 1:2^14, 2:2^15, 3:2^16 -#define BBP_CSR_CFG 0x101c // -// -// BBP_CSR_CFG: BBP serial control register -// -#ifdef RT_BIG_ENDIAN -typedef union _BBP_CSR_CFG_STRUC { - struct { - UINT32 :12; - UINT32 BBP_RW_MODE:1; // 0: use serial mode 1:parallel - UINT32 BBP_PAR_DUR:1; // 0: 4 MAC clock cycles 1: 8 MAC clock cycles - UINT32 Busy:1; // 1: ASIC is busy execute BBP programming. - UINT32 fRead:1; // 0: Write BBP, 1: Read BBP - UINT32 RegNum:8; // Selected BBP register - UINT32 Value:8; // Register value to program into BBP - } field; - UINT32 word; -} BBP_CSR_CFG_STRUC, *PBBP_CSR_CFG_STRUC; -#else -typedef union _BBP_CSR_CFG_STRUC { - struct { - UINT32 Value:8; // Register value to program into BBP - UINT32 RegNum:8; // Selected BBP register - UINT32 fRead:1; // 0: Write BBP, 1: Read BBP - UINT32 Busy:1; // 1: ASIC is busy execute BBP programming. - UINT32 BBP_PAR_DUR:1; // 0: 4 MAC clock cycles 1: 8 MAC clock cycles - UINT32 BBP_RW_MODE:1; // 0: use serial mode 1:parallel - UINT32 :12; - } field; - UINT32 word; -} BBP_CSR_CFG_STRUC, *PBBP_CSR_CFG_STRUC; -#endif -#define RF_CSR_CFG0 0x1020 -// -// RF_CSR_CFG: RF control register -// -#ifdef RT_BIG_ENDIAN -typedef union _RF_CSR_CFG0_STRUC { - struct { - UINT32 Busy:1; // 0: idle 1: 8busy - UINT32 Sel:1; // 0:RF_LE0 activate 1:RF_LE1 activate - UINT32 StandbyMode:1; // 0: high when stand by 1: low when standby - UINT32 bitwidth:5; // Selected BBP register - UINT32 RegIdAndContent:24; // Register value to program into BBP - } field; - UINT32 word; -} RF_CSR_CFG0_STRUC, *PRF_CSR_CFG0_STRUC; -#else -typedef union _RF_CSR_CFG0_STRUC { - struct { - UINT32 RegIdAndContent:24; // Register value to program into BBP - UINT32 bitwidth:5; // Selected BBP register - UINT32 StandbyMode:1; // 0: high when stand by 1: low when standby - UINT32 Sel:1; // 0:RF_LE0 activate 1:RF_LE1 activate - UINT32 Busy:1; // 0: idle 1: 8busy - } field; - UINT32 word; -} RF_CSR_CFG0_STRUC, *PRF_CSR_CFG0_STRUC; -#endif -#define RF_CSR_CFG1 0x1024 -#ifdef RT_BIG_ENDIAN -typedef union _RF_CSR_CFG1_STRUC { - struct { - UINT32 rsv:7; // 0: idle 1: 8busy - UINT32 RFGap:5; // Gap between BB_CONTROL_RF and RF_LE. 0: 3 system clock cycle (37.5usec) 1: 5 system clock cycle (62.5usec) - UINT32 RegIdAndContent:24; // Register value to program into BBP - } field; - UINT32 word; -} RF_CSR_CFG1_STRUC, *PRF_CSR_CFG1_STRUC; -#else -typedef union _RF_CSR_CFG1_STRUC { - struct { - UINT32 RegIdAndContent:24; // Register value to program into BBP - UINT32 RFGap:5; // Gap between BB_CONTROL_RF and RF_LE. 0: 3 system clock cycle (37.5usec) 1: 5 system clock cycle (62.5usec) - UINT32 rsv:7; // 0: idle 1: 8busy - } field; - UINT32 word; -} RF_CSR_CFG1_STRUC, *PRF_CSR_CFG1_STRUC; -#endif -#define RF_CSR_CFG2 0x1028 // -#ifdef RT_BIG_ENDIAN -typedef union _RF_CSR_CFG2_STRUC { - struct { - UINT32 rsv:8; // 0: idle 1: 8busy - UINT32 RegIdAndContent:24; // Register value to program into BBP - } field; - UINT32 word; -} RF_CSR_CFG2_STRUC, *PRF_CSR_CFG2_STRUC; -#else -typedef union _RF_CSR_CFG2_STRUC { - struct { - UINT32 RegIdAndContent:24; // Register value to program into BBP - UINT32 rsv:8; // 0: idle 1: 8busy - } field; - UINT32 word; -} RF_CSR_CFG2_STRUC, *PRF_CSR_CFG2_STRUC; -#endif -#define LED_CFG 0x102c // MAC_CSR14 -#ifdef RT_BIG_ENDIAN -typedef union _LED_CFG_STRUC { - struct { - UINT32 :1; - UINT32 LedPolar:1; // Led Polarity. 0: active low1: active high - UINT32 YLedMode:2; // yellow Led Mode - UINT32 GLedMode:2; // green Led Mode - UINT32 RLedMode:2; // red Led Mode 0: off1: blinking upon TX2: periodic slow blinking3: always on - UINT32 rsv:2; - UINT32 SlowBlinkPeriod:6; // slow blinking period. unit:1ms - UINT32 OffPeriod:8; // blinking off period unit 1ms - UINT32 OnPeriod:8; // blinking on period unit 1ms - } field; - UINT32 word; -} LED_CFG_STRUC, *PLED_CFG_STRUC; -#else -typedef union _LED_CFG_STRUC { - struct { - UINT32 OnPeriod:8; // blinking on period unit 1ms - UINT32 OffPeriod:8; // blinking off period unit 1ms - UINT32 SlowBlinkPeriod:6; // slow blinking period. unit:1ms - UINT32 rsv:2; - UINT32 RLedMode:2; // red Led Mode 0: off1: blinking upon TX2: periodic slow blinking3: always on - UINT32 GLedMode:2; // green Led Mode - UINT32 YLedMode:2; // yellow Led Mode - UINT32 LedPolar:1; // Led Polarity. 0: active low1: active high - UINT32 :1; - } field; - UINT32 word; -} LED_CFG_STRUC, *PLED_CFG_STRUC; -#endif -// -// 4.2 MAC TIMING configuration registers (offset:0x1100) -// -#define XIFS_TIME_CFG 0x1100 // MAC_CSR8 MAC_CSR9 -#ifdef RT_BIG_ENDIAN -typedef union _IFS_SLOT_CFG_STRUC { - struct { - UINT32 rsv:2; - UINT32 BBRxendEnable:1; // reference RXEND signal to begin XIFS defer - UINT32 EIFS:9; // unit 1us - UINT32 OfdmXifsTime:4; //OFDM SIFS. unit 1us. Applied after OFDM RX when MAC doesn't reference BBP signal BBRXEND - UINT32 OfdmSifsTime:8; // unit 1us. Applied after OFDM RX/TX - UINT32 CckmSifsTime:8; // unit 1us. Applied after CCK RX/TX - } field; - UINT32 word; -} IFS_SLOT_CFG_STRUC, *PIFS_SLOT_CFG_STRUC; -#else -typedef union _IFS_SLOT_CFG_STRUC { - struct { - UINT32 CckmSifsTime:8; // unit 1us. Applied after CCK RX/TX - UINT32 OfdmSifsTime:8; // unit 1us. Applied after OFDM RX/TX - UINT32 OfdmXifsTime:4; //OFDM SIFS. unit 1us. Applied after OFDM RX when MAC doesn't reference BBP signal BBRXEND - UINT32 EIFS:9; // unit 1us - UINT32 BBRxendEnable:1; // reference RXEND signal to begin XIFS defer - UINT32 rsv:2; - } field; - UINT32 word; -} IFS_SLOT_CFG_STRUC, *PIFS_SLOT_CFG_STRUC; -#endif - -#define BKOFF_SLOT_CFG 0x1104 // mac_csr9 last 8 bits -#define NAV_TIME_CFG 0x1108 // NAV (MAC_CSR15) -#define CH_TIME_CFG 0x110C // Count as channel busy -#define PBF_LIFE_TIMER 0x1110 //TX/RX MPDU timestamp timer (free run)Unit: 1us -#define BCN_TIME_CFG 0x1114 // TXRX_CSR9 - -#define BCN_OFFSET0 0x042C -#define BCN_OFFSET1 0x0430 - -// -// BCN_TIME_CFG : Synchronization control register -// -#ifdef RT_BIG_ENDIAN -typedef union _BCN_TIME_CFG_STRUC { - struct { - UINT32 TxTimestampCompensate:8; - UINT32 :3; - UINT32 bBeaconGen:1; // Enable beacon generator - UINT32 bTBTTEnable:1; - UINT32 TsfSyncMode:2; // Enable TSF sync, 00: disable, 01: infra mode, 10: ad-hoc mode - UINT32 bTsfTicking:1; // Enable TSF auto counting - UINT32 BeaconInterval:16; // in unit of 1/16 TU - } field; - UINT32 word; -} BCN_TIME_CFG_STRUC, *PBCN_TIME_CFG_STRUC; -#else -typedef union _BCN_TIME_CFG_STRUC { - struct { - UINT32 BeaconInterval:16; // in unit of 1/16 TU - UINT32 bTsfTicking:1; // Enable TSF auto counting - UINT32 TsfSyncMode:2; // Enable TSF sync, 00: disable, 01: infra mode, 10: ad-hoc mode - UINT32 bTBTTEnable:1; - UINT32 bBeaconGen:1; // Enable beacon generator - UINT32 :3; - UINT32 TxTimestampCompensate:8; - } field; - UINT32 word; -} BCN_TIME_CFG_STRUC, *PBCN_TIME_CFG_STRUC; -#endif -#define TBTT_SYNC_CFG 0x1118 // txrx_csr10 -#define TSF_TIMER_DW0 0x111C // Local TSF timer lsb 32 bits. Read-only -#define TSF_TIMER_DW1 0x1120 // msb 32 bits. Read-only. -#define TBTT_TIMER 0x1124 // TImer remains till next TBTT. Read-only. TXRX_CSR14 -#define INT_TIMER_CFG 0x1128 // -#define INT_TIMER_EN 0x112c // GP-timer and pre-tbtt Int enable -#define CH_IDLE_STA 0x1130 // channel idle time -#define CH_BUSY_STA 0x1134 // channle busy time -// -// 4.2 MAC POWER configuration registers (offset:0x1200) -// -#define MAC_STATUS_CFG 0x1200 // old MAC_CSR12 -#define PWR_PIN_CFG 0x1204 // old MAC_CSR12 -#define AUTO_WAKEUP_CFG 0x1208 // old MAC_CSR10 -// -// AUTO_WAKEUP_CFG: Manual power control / status register -// -#ifdef RT_BIG_ENDIAN -typedef union _AUTO_WAKEUP_STRUC { - struct { - UINT32 :16; - UINT32 EnableAutoWakeup:1; // 0:sleep, 1:awake - UINT32 NumofSleepingTbtt:7; // ForceWake has high privilege than PutToSleep when both set - UINT32 AutoLeadTime:8; - } field; - UINT32 word; -} AUTO_WAKEUP_STRUC, *PAUTO_WAKEUP_STRUC; -#else -typedef union _AUTO_WAKEUP_STRUC { - struct { - UINT32 AutoLeadTime:8; - UINT32 NumofSleepingTbtt:7; // ForceWake has high privilege than PutToSleep when both set - UINT32 EnableAutoWakeup:1; // 0:sleep, 1:awake - UINT32 :16; - } field; - UINT32 word; -} AUTO_WAKEUP_STRUC, *PAUTO_WAKEUP_STRUC; -#endif -// -// 4.3 MAC TX configuration registers (offset:0x1300) -// - -#define EDCA_AC0_CFG 0x1300 //AC_TXOP_CSR0 0x3474 -#define EDCA_AC1_CFG 0x1304 -#define EDCA_AC2_CFG 0x1308 -#define EDCA_AC3_CFG 0x130c -#ifdef RT_BIG_ENDIAN -typedef union _EDCA_AC_CFG_STRUC { - struct { - UINT32 :12; // - UINT32 Cwmax:4; //unit power of 2 - UINT32 Cwmin:4; // - UINT32 Aifsn:4; // # of slot time - UINT32 AcTxop:8; // in unit of 32us - } field; - UINT32 word; -} EDCA_AC_CFG_STRUC, *PEDCA_AC_CFG_STRUC; -#else -typedef union _EDCA_AC_CFG_STRUC { - struct { - UINT32 AcTxop:8; // in unit of 32us - UINT32 Aifsn:4; // # of slot time - UINT32 Cwmin:4; // - UINT32 Cwmax:4; //unit power of 2 - UINT32 :12; // - } field; - UINT32 word; -} EDCA_AC_CFG_STRUC, *PEDCA_AC_CFG_STRUC; -#endif - -#define EDCA_TID_AC_MAP 0x1310 -#define TX_PWR_CFG_0 0x1314 -#define TX_PWR_CFG_1 0x1318 -#define TX_PWR_CFG_2 0x131C -#define TX_PWR_CFG_3 0x1320 -#define TX_PWR_CFG_4 0x1324 -#define TX_PIN_CFG 0x1328 -#define TX_BAND_CFG 0x132c // 0x1 use upper 20MHz. 0 juse lower 20MHz -#define TX_SW_CFG0 0x1330 -#define TX_SW_CFG1 0x1334 -#define TX_SW_CFG2 0x1338 -#define TXOP_THRES_CFG 0x133c -#define TXOP_CTRL_CFG 0x1340 -#define TX_RTS_CFG 0x1344 - -#ifdef RT_BIG_ENDIAN -typedef union _TX_RTS_CFG_STRUC { - struct { - UINT32 rsv:7; - UINT32 RtsFbkEn:1; // enable rts rate fallback - UINT32 RtsThres:16; // unit:byte - UINT32 AutoRtsRetryLimit:8; - } field; - UINT32 word; -} TX_RTS_CFG_STRUC, *PTX_RTS_CFG_STRUC; -#else -typedef union _TX_RTS_CFG_STRUC { - struct { - UINT32 AutoRtsRetryLimit:8; - UINT32 RtsThres:16; // unit:byte - UINT32 RtsFbkEn:1; // enable rts rate fallback - UINT32 rsv:7; // 1: HT non-STBC control frame enable - } field; - UINT32 word; -} TX_RTS_CFG_STRUC, *PTX_RTS_CFG_STRUC; -#endif -#define TX_TIMEOUT_CFG 0x1348 -#ifdef RT_BIG_ENDIAN -typedef union _TX_TIMEOUT_CFG_STRUC { - struct { - UINT32 rsv2:8; - UINT32 TxopTimeout:8; //TXOP timeout value for TXOP truncation. It is recommended that (SLOT_TIME) > (TX_OP_TIMEOUT) > (RX_ACK_TIMEOUT) - UINT32 RxAckTimeout:8; // unit:slot. Used for TX precedure - UINT32 MpduLifeTime:4; // expiration time = 2^(9+MPDU LIFE TIME) us - UINT32 rsv:4; - } field; - UINT32 word; -} TX_TIMEOUT_CFG_STRUC, *PTX_TIMEOUT_CFG_STRUC; -#else -typedef union _TX_TIMEOUT_CFG_STRUC { - struct { - UINT32 rsv:4; - UINT32 MpduLifeTime:4; // expiration time = 2^(9+MPDU LIFE TIME) us - UINT32 RxAckTimeout:8; // unit:slot. Used for TX precedure - UINT32 TxopTimeout:8; //TXOP timeout value for TXOP truncation. It is recommended that (SLOT_TIME) > (TX_OP_TIMEOUT) > (RX_ACK_TIMEOUT) - UINT32 rsv2:8; // 1: HT non-STBC control frame enable - } field; - UINT32 word; -} TX_TIMEOUT_CFG_STRUC, *PTX_TIMEOUT_CFG_STRUC; -#endif -#define TX_RTY_CFG 0x134c -#ifdef RT_BIG_ENDIAN -typedef union PACKED _TX_RTY_CFG_STRUC { - struct { - UINT32 rsv:1; - UINT32 TxautoFBEnable:1; // Tx retry PHY rate auto fallback enable - UINT32 AggRtyMode:1; // Aggregate MPDU retry mode. 0:expired by retry limit, 1: expired by mpdu life timer - UINT32 NonAggRtyMode:1; // Non-Aggregate MPDU retry mode. 0:expired by retry limit, 1: expired by mpdu life timer - UINT32 LongRtyThre:12; // Long retry threshoold - UINT32 LongRtyLimit:8; //long retry limit - UINT32 ShortRtyLimit:8; // short retry limit - - } field; - UINT32 word; -} TX_RTY_CFG_STRUC, *PTX_RTY_CFG_STRUC; -#else -typedef union PACKED _TX_RTY_CFG_STRUC { - struct { - UINT32 ShortRtyLimit:8; // short retry limit - UINT32 LongRtyLimit:8; //long retry limit - UINT32 LongRtyThre:12; // Long retry threshoold - UINT32 NonAggRtyMode:1; // Non-Aggregate MPDU retry mode. 0:expired by retry limit, 1: expired by mpdu life timer - UINT32 AggRtyMode:1; // Aggregate MPDU retry mode. 0:expired by retry limit, 1: expired by mpdu life timer - UINT32 TxautoFBEnable:1; // Tx retry PHY rate auto fallback enable - UINT32 rsv:1; // 1: HT non-STBC control frame enable - } field; - UINT32 word; -} TX_RTY_CFG_STRUC, *PTX_RTY_CFG_STRUC; -#endif -#define TX_LINK_CFG 0x1350 -#ifdef RT_BIG_ENDIAN -typedef union PACKED _TX_LINK_CFG_STRUC { - struct PACKED { - UINT32 RemotMFS:8; //remote MCS feedback sequence number - UINT32 RemotMFB:8; // remote MCS feedback - UINT32 rsv:3; // - UINT32 TxCFAckEn:1; // Piggyback CF-ACK enable - UINT32 TxRDGEn:1; // RDG TX enable - UINT32 TxMRQEn:1; // MCS request TX enable - UINT32 RemoteUMFSEnable:1; // remote unsolicit MFB enable. 0: not apply remote remote unsolicit (MFS=7) - UINT32 MFBEnable:1; // TX apply remote MFB 1:enable - UINT32 RemoteMFBLifeTime:8; //remote MFB life time. unit : 32us - } field; - UINT32 word; -} TX_LINK_CFG_STRUC, *PTX_LINK_CFG_STRUC; -#else -typedef union PACKED _TX_LINK_CFG_STRUC { - struct PACKED { - UINT32 RemoteMFBLifeTime:8; //remote MFB life time. unit : 32us - UINT32 MFBEnable:1; // TX apply remote MFB 1:enable - UINT32 RemoteUMFSEnable:1; // remote unsolicit MFB enable. 0: not apply remote remote unsolicit (MFS=7) - UINT32 TxMRQEn:1; // MCS request TX enable - UINT32 TxRDGEn:1; // RDG TX enable - UINT32 TxCFAckEn:1; // Piggyback CF-ACK enable - UINT32 rsv:3; // - UINT32 RemotMFB:8; // remote MCS feedback - UINT32 RemotMFS:8; //remote MCS feedback sequence number - } field; - UINT32 word; -} TX_LINK_CFG_STRUC, *PTX_LINK_CFG_STRUC; -#endif -#define HT_FBK_CFG0 0x1354 -#ifdef RT_BIG_ENDIAN -typedef union PACKED _HT_FBK_CFG0_STRUC { - struct { - UINT32 HTMCS7FBK:4; - UINT32 HTMCS6FBK:4; - UINT32 HTMCS5FBK:4; - UINT32 HTMCS4FBK:4; - UINT32 HTMCS3FBK:4; - UINT32 HTMCS2FBK:4; - UINT32 HTMCS1FBK:4; - UINT32 HTMCS0FBK:4; - } field; - UINT32 word; -} HT_FBK_CFG0_STRUC, *PHT_FBK_CFG0_STRUC; -#else -typedef union PACKED _HT_FBK_CFG0_STRUC { - struct { - UINT32 HTMCS0FBK:4; - UINT32 HTMCS1FBK:4; - UINT32 HTMCS2FBK:4; - UINT32 HTMCS3FBK:4; - UINT32 HTMCS4FBK:4; - UINT32 HTMCS5FBK:4; - UINT32 HTMCS6FBK:4; - UINT32 HTMCS7FBK:4; - } field; - UINT32 word; -} HT_FBK_CFG0_STRUC, *PHT_FBK_CFG0_STRUC; -#endif -#define HT_FBK_CFG1 0x1358 -#ifdef RT_BIG_ENDIAN -typedef union _HT_FBK_CFG1_STRUC { - struct { - UINT32 HTMCS15FBK:4; - UINT32 HTMCS14FBK:4; - UINT32 HTMCS13FBK:4; - UINT32 HTMCS12FBK:4; - UINT32 HTMCS11FBK:4; - UINT32 HTMCS10FBK:4; - UINT32 HTMCS9FBK:4; - UINT32 HTMCS8FBK:4; - } field; - UINT32 word; -} HT_FBK_CFG1_STRUC, *PHT_FBK_CFG1_STRUC; -#else -typedef union _HT_FBK_CFG1_STRUC { - struct { - UINT32 HTMCS8FBK:4; - UINT32 HTMCS9FBK:4; - UINT32 HTMCS10FBK:4; - UINT32 HTMCS11FBK:4; - UINT32 HTMCS12FBK:4; - UINT32 HTMCS13FBK:4; - UINT32 HTMCS14FBK:4; - UINT32 HTMCS15FBK:4; - } field; - UINT32 word; -} HT_FBK_CFG1_STRUC, *PHT_FBK_CFG1_STRUC; -#endif -#define LG_FBK_CFG0 0x135c -#ifdef RT_BIG_ENDIAN -typedef union _LG_FBK_CFG0_STRUC { - struct { - UINT32 OFDMMCS7FBK:4; //initial value is 6 - UINT32 OFDMMCS6FBK:4; //initial value is 5 - UINT32 OFDMMCS5FBK:4; //initial value is 4 - UINT32 OFDMMCS4FBK:4; //initial value is 3 - UINT32 OFDMMCS3FBK:4; //initial value is 2 - UINT32 OFDMMCS2FBK:4; //initial value is 1 - UINT32 OFDMMCS1FBK:4; //initial value is 0 - UINT32 OFDMMCS0FBK:4; //initial value is 0 - } field; - UINT32 word; -} LG_FBK_CFG0_STRUC, *PLG_FBK_CFG0_STRUC; -#else -typedef union _LG_FBK_CFG0_STRUC { - struct { - UINT32 OFDMMCS0FBK:4; //initial value is 0 - UINT32 OFDMMCS1FBK:4; //initial value is 0 - UINT32 OFDMMCS2FBK:4; //initial value is 1 - UINT32 OFDMMCS3FBK:4; //initial value is 2 - UINT32 OFDMMCS4FBK:4; //initial value is 3 - UINT32 OFDMMCS5FBK:4; //initial value is 4 - UINT32 OFDMMCS6FBK:4; //initial value is 5 - UINT32 OFDMMCS7FBK:4; //initial value is 6 - } field; - UINT32 word; -} LG_FBK_CFG0_STRUC, *PLG_FBK_CFG0_STRUC; -#endif -#define LG_FBK_CFG1 0x1360 -#ifdef RT_BIG_ENDIAN -typedef union _LG_FBK_CFG1_STRUC { - struct { - UINT32 rsv:16; - UINT32 CCKMCS3FBK:4; //initial value is 2 - UINT32 CCKMCS2FBK:4; //initial value is 1 - UINT32 CCKMCS1FBK:4; //initial value is 0 - UINT32 CCKMCS0FBK:4; //initial value is 0 - } field; - UINT32 word; -} LG_FBK_CFG1_STRUC, *PLG_FBK_CFG1_STRUC; -#else -typedef union _LG_FBK_CFG1_STRUC { - struct { - UINT32 CCKMCS0FBK:4; //initial value is 0 - UINT32 CCKMCS1FBK:4; //initial value is 0 - UINT32 CCKMCS2FBK:4; //initial value is 1 - UINT32 CCKMCS3FBK:4; //initial value is 2 - UINT32 rsv:16; - } field; - UINT32 word; -} LG_FBK_CFG1_STRUC, *PLG_FBK_CFG1_STRUC; -#endif - -//======================================================= -//================ Protection Paramater================================ -//======================================================= -#define CCK_PROT_CFG 0x1364 //CCK Protection -#define ASIC_SHORTNAV 1 -#define ASIC_LONGNAV 2 -#define ASIC_RTS 1 -#define ASIC_CTS 2 -#ifdef RT_BIG_ENDIAN -typedef union _PROT_CFG_STRUC { - struct { - UINT32 rsv:5; - UINT32 RTSThEn:1; //RTS threshold enable on CCK TX - UINT32 TxopAllowGF40:1; //CCK TXOP allowance.0:disallow. - UINT32 TxopAllowGF20:1; //CCK TXOP allowance.0:disallow. - UINT32 TxopAllowMM40:1; //CCK TXOP allowance.0:disallow. - UINT32 TxopAllowMM20:1; //CCK TXOP allowance. 0:disallow. - UINT32 TxopAllowOfdm:1; //CCK TXOP allowance.0:disallow. - UINT32 TxopAllowCck:1; //CCK TXOP allowance.0:disallow. - UINT32 ProtectNav:2; //TXOP protection type for CCK TX. 0:None, 1:ShortNAVprotect, 2:LongNAVProtect, 3:rsv - UINT32 ProtectCtrl:2; //Protection control frame type for CCK TX. 1:RTS/CTS, 2:CTS-to-self, 0:None, 3:rsv - UINT32 ProtectRate:16; //Protection control frame rate for CCK TX(RTS/CTS/CFEnd). - } field; - UINT32 word; -} PROT_CFG_STRUC, *PPROT_CFG_STRUC; -#else -typedef union _PROT_CFG_STRUC { - struct { - UINT32 ProtectRate:16; //Protection control frame rate for CCK TX(RTS/CTS/CFEnd). - UINT32 ProtectCtrl:2; //Protection control frame type for CCK TX. 1:RTS/CTS, 2:CTS-to-self, 0:None, 3:rsv - UINT32 ProtectNav:2; //TXOP protection type for CCK TX. 0:None, 1:ShortNAVprotect, 2:LongNAVProtect, 3:rsv - UINT32 TxopAllowCck:1; //CCK TXOP allowance.0:disallow. - UINT32 TxopAllowOfdm:1; //CCK TXOP allowance.0:disallow. - UINT32 TxopAllowMM20:1; //CCK TXOP allowance. 0:disallow. - UINT32 TxopAllowMM40:1; //CCK TXOP allowance.0:disallow. - UINT32 TxopAllowGF20:1; //CCK TXOP allowance.0:disallow. - UINT32 TxopAllowGF40:1; //CCK TXOP allowance.0:disallow. - UINT32 RTSThEn:1; //RTS threshold enable on CCK TX - UINT32 rsv:5; - } field; - UINT32 word; -} PROT_CFG_STRUC, *PPROT_CFG_STRUC; -#endif - -#define OFDM_PROT_CFG 0x1368 //OFDM Protection -#define MM20_PROT_CFG 0x136C //MM20 Protection -#define MM40_PROT_CFG 0x1370 //MM40 Protection -#define GF20_PROT_CFG 0x1374 //GF20 Protection -#define GF40_PROT_CFG 0x1378 //GR40 Protection -#define EXP_CTS_TIME 0x137C // -#define EXP_ACK_TIME 0x1380 // - -// -// 4.4 MAC RX configuration registers (offset:0x1400) -// -#define RX_FILTR_CFG 0x1400 //TXRX_CSR0 -#define AUTO_RSP_CFG 0x1404 //TXRX_CSR4 -// -// TXRX_CSR4: Auto-Responder/ -// -#ifdef RT_BIG_ENDIAN -typedef union _AUTO_RSP_CFG_STRUC { - struct { - UINT32 :24; - UINT32 AckCtsPsmBit:1; // Power bit value in conrtrol frame - UINT32 DualCTSEn:1; // Power bit value in conrtrol frame - UINT32 rsv:1; // Power bit value in conrtrol frame - UINT32 AutoResponderPreamble:1; // 0:long, 1:short preamble - UINT32 CTS40MRef:1; // Response CTS 40MHz duplicate mode - UINT32 CTS40MMode:1; // Response CTS 40MHz duplicate mode - UINT32 BACAckPolicyEnable:1; // 0:long, 1:short preamble - UINT32 AutoResponderEnable:1; - } field; - UINT32 word; -} AUTO_RSP_CFG_STRUC, *PAUTO_RSP_CFG_STRUC; -#else -typedef union _AUTO_RSP_CFG_STRUC { - struct { - UINT32 AutoResponderEnable:1; - UINT32 BACAckPolicyEnable:1; // 0:long, 1:short preamble - UINT32 CTS40MMode:1; // Response CTS 40MHz duplicate mode - UINT32 CTS40MRef:1; // Response CTS 40MHz duplicate mode - UINT32 AutoResponderPreamble:1; // 0:long, 1:short preamble - UINT32 rsv:1; // Power bit value in conrtrol frame - UINT32 DualCTSEn:1; // Power bit value in conrtrol frame - UINT32 AckCtsPsmBit:1; // Power bit value in conrtrol frame - UINT32 :24; - } field; - UINT32 word; -} AUTO_RSP_CFG_STRUC, *PAUTO_RSP_CFG_STRUC; -#endif - -#define LEGACY_BASIC_RATE 0x1408 // TXRX_CSR5 0x3054 -#define HT_BASIC_RATE 0x140c -#define HT_CTRL_CFG 0x1410 -#define SIFS_COST_CFG 0x1414 -#define RX_PARSER_CFG 0x1418 //Set NAV for all received frames - -// -// 4.5 MAC Security configuration (offset:0x1500) -// -#define TX_SEC_CNT0 0x1500 // -#define RX_SEC_CNT0 0x1504 // -#define CCMP_FC_MUTE 0x1508 // -// -// 4.6 HCCA/PSMP (offset:0x1600) -// -#define TXOP_HLDR_ADDR0 0x1600 -#define TXOP_HLDR_ADDR1 0x1604 -#define TXOP_HLDR_ET 0x1608 -#define QOS_CFPOLL_RA_DW0 0x160c -#define QOS_CFPOLL_A1_DW1 0x1610 -#define QOS_CFPOLL_QC 0x1614 -// -// 4.7 MAC Statistis registers (offset:0x1700) -// -#define RX_STA_CNT0 0x1700 // -#define RX_STA_CNT1 0x1704 // -#define RX_STA_CNT2 0x1708 // - -// -// RX_STA_CNT0_STRUC: RX PLCP error count & RX CRC error count -// -#ifdef RT_BIG_ENDIAN -typedef union _RX_STA_CNT0_STRUC { - struct { - USHORT PhyErr; - USHORT CrcErr; - } field; - UINT32 word; -} RX_STA_CNT0_STRUC, *PRX_STA_CNT0_STRUC; -#else -typedef union _RX_STA_CNT0_STRUC { - struct { - USHORT CrcErr; - USHORT PhyErr; - } field; - UINT32 word; -} RX_STA_CNT0_STRUC, *PRX_STA_CNT0_STRUC; -#endif - -// -// RX_STA_CNT1_STRUC: RX False CCA count & RX LONG frame count -// -#ifdef RT_BIG_ENDIAN -typedef union _RX_STA_CNT1_STRUC { - struct { - USHORT PlcpErr; - USHORT FalseCca; - } field; - UINT32 word; -} RX_STA_CNT1_STRUC, *PRX_STA_CNT1_STRUC; -#else -typedef union _RX_STA_CNT1_STRUC { - struct { - USHORT FalseCca; - USHORT PlcpErr; - } field; - UINT32 word; -} RX_STA_CNT1_STRUC, *PRX_STA_CNT1_STRUC; -#endif - -// -// RX_STA_CNT2_STRUC: -// -#ifdef RT_BIG_ENDIAN -typedef union _RX_STA_CNT2_STRUC { - struct { - USHORT RxFifoOverflowCount; - USHORT RxDupliCount; - } field; - UINT32 word; -} RX_STA_CNT2_STRUC, *PRX_STA_CNT2_STRUC; -#else -typedef union _RX_STA_CNT2_STRUC { - struct { - USHORT RxDupliCount; - USHORT RxFifoOverflowCount; - } field; - UINT32 word; -} RX_STA_CNT2_STRUC, *PRX_STA_CNT2_STRUC; -#endif -#define TX_STA_CNT0 0x170C // -// -// STA_CSR3: TX Beacon count -// -#ifdef RT_BIG_ENDIAN -typedef union _TX_STA_CNT0_STRUC { - struct { - USHORT TxBeaconCount; - USHORT TxFailCount; - } field; - UINT32 word; -} TX_STA_CNT0_STRUC, *PTX_STA_CNT0_STRUC; -#else -typedef union _TX_STA_CNT0_STRUC { - struct { - USHORT TxFailCount; - USHORT TxBeaconCount; - } field; - UINT32 word; -} TX_STA_CNT0_STRUC, *PTX_STA_CNT0_STRUC; -#endif -#define TX_STA_CNT1 0x1710 // -// -// TX_STA_CNT1: TX tx count -// -#ifdef RT_BIG_ENDIAN -typedef union _TX_STA_CNT1_STRUC { - struct { - USHORT TxRetransmit; - USHORT TxSuccess; - } field; - UINT32 word; -} TX_STA_CNT1_STRUC, *PTX_STA_CNT1_STRUC; -#else -typedef union _TX_STA_CNT1_STRUC { - struct { - USHORT TxSuccess; - USHORT TxRetransmit; - } field; - UINT32 word; -} TX_STA_CNT1_STRUC, *PTX_STA_CNT1_STRUC; -#endif -#define TX_STA_CNT2 0x1714 // -// -// TX_STA_CNT2: TX tx count -// -#ifdef RT_BIG_ENDIAN -typedef union _TX_STA_CNT2_STRUC { - struct { - USHORT TxUnderFlowCount; - USHORT TxZeroLenCount; - } field; - UINT32 word; -} TX_STA_CNT2_STRUC, *PTX_STA_CNT2_STRUC; -#else -typedef union _TX_STA_CNT2_STRUC { - struct { - USHORT TxZeroLenCount; - USHORT TxUnderFlowCount; - } field; - UINT32 word; -} TX_STA_CNT2_STRUC, *PTX_STA_CNT2_STRUC; -#endif -#define TX_STA_FIFO 0x1718 // -// -// TX_STA_FIFO_STRUC: TX Result for specific PID status fifo register -// -#ifdef RT_BIG_ENDIAN -typedef union PACKED _TX_STA_FIFO_STRUC { - struct { - UINT32 Reserve:2; - UINT32 TxBF:1; // 3*3 - UINT32 SuccessRate:13; //include MCS, mode ,shortGI, BW settingSame format as TXWI Word 0 Bit 31-16. -// UINT32 SuccessRate:16; //include MCS, mode ,shortGI, BW settingSame format as TXWI Word 0 Bit 31-16. - UINT32 wcid:8; //wireless client index - UINT32 TxAckRequired:1; // ack required - UINT32 TxAggre:1; // Tx is aggregated - UINT32 TxSuccess:1; // Tx success. whether success or not - UINT32 PidType:4; - UINT32 bValid:1; // 1:This register contains a valid TX result - } field; - UINT32 word; -} TX_STA_FIFO_STRUC, *PTX_STA_FIFO_STRUC; -#else -typedef union PACKED _TX_STA_FIFO_STRUC { - struct { - UINT32 bValid:1; // 1:This register contains a valid TX result - UINT32 PidType:4; - UINT32 TxSuccess:1; // Tx No retry success - UINT32 TxAggre:1; // Tx Retry Success - UINT32 TxAckRequired:1; // Tx fail - UINT32 wcid:8; //wireless client index -// UINT32 SuccessRate:16; //include MCS, mode ,shortGI, BW settingSame format as TXWI Word 0 Bit 31-16. - UINT32 SuccessRate:13; //include MCS, mode ,shortGI, BW settingSame format as TXWI Word 0 Bit 31-16. - UINT32 TxBF:1; - UINT32 Reserve:2; - } field; - UINT32 word; -} TX_STA_FIFO_STRUC, *PTX_STA_FIFO_STRUC; -#endif -// Debug counter -#define TX_AGG_CNT 0x171c -#ifdef RT_BIG_ENDIAN -typedef union _TX_AGG_CNT_STRUC { - struct { - USHORT AggTxCount; - USHORT NonAggTxCount; - } field; - UINT32 word; -} TX_AGG_CNT_STRUC, *PTX_AGG_CNT_STRUC; -#else -typedef union _TX_AGG_CNT_STRUC { - struct { - USHORT NonAggTxCount; - USHORT AggTxCount; - } field; - UINT32 word; -} TX_AGG_CNT_STRUC, *PTX_AGG_CNT_STRUC; -#endif -// Debug counter -#define TX_AGG_CNT0 0x1720 -#ifdef RT_BIG_ENDIAN -typedef union _TX_AGG_CNT0_STRUC { - struct { - USHORT AggSize2Count; - USHORT AggSize1Count; - } field; - UINT32 word; -} TX_AGG_CNT0_STRUC, *PTX_AGG_CNT0_STRUC; -#else -typedef union _TX_AGG_CNT0_STRUC { - struct { - USHORT AggSize1Count; - USHORT AggSize2Count; - } field; - UINT32 word; -} TX_AGG_CNT0_STRUC, *PTX_AGG_CNT0_STRUC; -#endif -// Debug counter -#define TX_AGG_CNT1 0x1724 -#ifdef RT_BIG_ENDIAN -typedef union _TX_AGG_CNT1_STRUC { - struct { - USHORT AggSize4Count; - USHORT AggSize3Count; - } field; - UINT32 word; -} TX_AGG_CNT1_STRUC, *PTX_AGG_CNT1_STRUC; -#else -typedef union _TX_AGG_CNT1_STRUC { - struct { - USHORT AggSize3Count; - USHORT AggSize4Count; - } field; - UINT32 word; -} TX_AGG_CNT1_STRUC, *PTX_AGG_CNT1_STRUC; -#endif -#define TX_AGG_CNT2 0x1728 -#ifdef RT_BIG_ENDIAN -typedef union _TX_AGG_CNT2_STRUC { - struct { - USHORT AggSize6Count; - USHORT AggSize5Count; - } field; - UINT32 word; -} TX_AGG_CNT2_STRUC, *PTX_AGG_CNT2_STRUC; -#else -typedef union _TX_AGG_CNT2_STRUC { - struct { - USHORT AggSize5Count; - USHORT AggSize6Count; - } field; - UINT32 word; -} TX_AGG_CNT2_STRUC, *PTX_AGG_CNT2_STRUC; -#endif -// Debug counter -#define TX_AGG_CNT3 0x172c -#ifdef RT_BIG_ENDIAN -typedef union _TX_AGG_CNT3_STRUC { - struct { - USHORT AggSize8Count; - USHORT AggSize7Count; - } field; - UINT32 word; -} TX_AGG_CNT3_STRUC, *PTX_AGG_CNT3_STRUC; -#else -typedef union _TX_AGG_CNT3_STRUC { - struct { - USHORT AggSize7Count; - USHORT AggSize8Count; - } field; - UINT32 word; -} TX_AGG_CNT3_STRUC, *PTX_AGG_CNT3_STRUC; -#endif -// Debug counter -#define TX_AGG_CNT4 0x1730 -#ifdef RT_BIG_ENDIAN -typedef union _TX_AGG_CNT4_STRUC { - struct { - USHORT AggSize10Count; - USHORT AggSize9Count; - } field; - UINT32 word; -} TX_AGG_CNT4_STRUC, *PTX_AGG_CNT4_STRUC; -#else -typedef union _TX_AGG_CNT4_STRUC { - struct { - USHORT AggSize9Count; - USHORT AggSize10Count; - } field; - UINT32 word; -} TX_AGG_CNT4_STRUC, *PTX_AGG_CNT4_STRUC; -#endif -#define TX_AGG_CNT5 0x1734 -#ifdef RT_BIG_ENDIAN -typedef union _TX_AGG_CNT5_STRUC { - struct { - USHORT AggSize12Count; - USHORT AggSize11Count; - } field; - UINT32 word; -} TX_AGG_CNT5_STRUC, *PTX_AGG_CNT5_STRUC; -#else -typedef union _TX_AGG_CNT5_STRUC { - struct { - USHORT AggSize11Count; - USHORT AggSize12Count; - } field; - UINT32 word; -} TX_AGG_CNT5_STRUC, *PTX_AGG_CNT5_STRUC; -#endif -#define TX_AGG_CNT6 0x1738 -#ifdef RT_BIG_ENDIAN -typedef union _TX_AGG_CNT6_STRUC { - struct { - USHORT AggSize14Count; - USHORT AggSize13Count; - } field; - UINT32 word; -} TX_AGG_CNT6_STRUC, *PTX_AGG_CNT6_STRUC; -#else -typedef union _TX_AGG_CNT6_STRUC { - struct { - USHORT AggSize13Count; - USHORT AggSize14Count; - } field; - UINT32 word; -} TX_AGG_CNT6_STRUC, *PTX_AGG_CNT6_STRUC; -#endif -#define TX_AGG_CNT7 0x173c -#ifdef RT_BIG_ENDIAN -typedef union _TX_AGG_CNT7_STRUC { - struct { - USHORT AggSize16Count; - USHORT AggSize15Count; - } field; - UINT32 word; -} TX_AGG_CNT7_STRUC, *PTX_AGG_CNT7_STRUC; -#else -typedef union _TX_AGG_CNT7_STRUC { - struct { - USHORT AggSize15Count; - USHORT AggSize16Count; - } field; - UINT32 word; -} TX_AGG_CNT7_STRUC, *PTX_AGG_CNT7_STRUC; -#endif -#define MPDU_DENSITY_CNT 0x1740 -#ifdef RT_BIG_ENDIAN -typedef union _MPDU_DEN_CNT_STRUC { - struct { - USHORT RXZeroDelCount; //RX zero length delimiter count - USHORT TXZeroDelCount; //TX zero length delimiter count - } field; - UINT32 word; -} MPDU_DEN_CNT_STRUC, *PMPDU_DEN_CNT_STRUC; -#else -typedef union _MPDU_DEN_CNT_STRUC { - struct { - USHORT TXZeroDelCount; //TX zero length delimiter count - USHORT RXZeroDelCount; //RX zero length delimiter count - } field; - UINT32 word; -} MPDU_DEN_CNT_STRUC, *PMPDU_DEN_CNT_STRUC; -#endif -// -// TXRX control registers - base address 0x3000 -// -// rt2860b UNKNOWN reg use R/O Reg Addr 0x77d0 first.. -#define TXRX_CSR1 0x77d0 - -// -// Security key table memory, base address = 0x1000 -// -#define MAC_WCID_BASE 0x1800 //8-bytes(use only 6-bytes) * 256 entry = -#define HW_WCID_ENTRY_SIZE 8 -#define PAIRWISE_KEY_TABLE_BASE 0x4000 // 32-byte * 256-entry = -byte -#define HW_KEY_ENTRY_SIZE 0x20 -#define PAIRWISE_IVEIV_TABLE_BASE 0x6000 // 8-byte * 256-entry = -byte -#define MAC_IVEIV_TABLE_BASE 0x6000 // 8-byte * 256-entry = -byte -#define HW_IVEIV_ENTRY_SIZE 8 -#define MAC_WCID_ATTRIBUTE_BASE 0x6800 // 4-byte * 256-entry = -byte -#define HW_WCID_ATTRI_SIZE 4 -#define WCID_RESERVED 0x6bfc -#define SHARED_KEY_TABLE_BASE 0x6c00 // 32-byte * 16-entry = 512-byte -#define SHARED_KEY_MODE_BASE 0x7000 // 32-byte * 16-entry = 512-byte -#define HW_SHARED_KEY_MODE_SIZE 4 -#define SHAREDKEYTABLE 0 -#define PAIRWISEKEYTABLE 1 - - -#ifdef RT_BIG_ENDIAN -typedef union _SHAREDKEY_MODE_STRUC { - struct { - UINT32 :1; - UINT32 Bss1Key3CipherAlg:3; - UINT32 :1; - UINT32 Bss1Key2CipherAlg:3; - UINT32 :1; - UINT32 Bss1Key1CipherAlg:3; - UINT32 :1; - UINT32 Bss1Key0CipherAlg:3; - UINT32 :1; - UINT32 Bss0Key3CipherAlg:3; - UINT32 :1; - UINT32 Bss0Key2CipherAlg:3; - UINT32 :1; - UINT32 Bss0Key1CipherAlg:3; - UINT32 :1; - UINT32 Bss0Key0CipherAlg:3; - } field; - UINT32 word; -} SHAREDKEY_MODE_STRUC, *PSHAREDKEY_MODE_STRUC; -#else -typedef union _SHAREDKEY_MODE_STRUC { - struct { - UINT32 Bss0Key0CipherAlg:3; - UINT32 :1; - UINT32 Bss0Key1CipherAlg:3; - UINT32 :1; - UINT32 Bss0Key2CipherAlg:3; - UINT32 :1; - UINT32 Bss0Key3CipherAlg:3; - UINT32 :1; - UINT32 Bss1Key0CipherAlg:3; - UINT32 :1; - UINT32 Bss1Key1CipherAlg:3; - UINT32 :1; - UINT32 Bss1Key2CipherAlg:3; - UINT32 :1; - UINT32 Bss1Key3CipherAlg:3; - UINT32 :1; - } field; - UINT32 word; -} SHAREDKEY_MODE_STRUC, *PSHAREDKEY_MODE_STRUC; -#endif -// 64-entry for pairwise key table -typedef struct _HW_WCID_ENTRY { // 8-byte per entry - UCHAR Address[6]; - UCHAR Rsv[2]; -} HW_WCID_ENTRY, PHW_WCID_ENTRY; - - - -// -// Other on-chip shared memory space, base = 0x2000 -// - -// CIS space - base address = 0x2000 -#define HW_CIS_BASE 0x2000 - -// Carrier-sense CTS frame base address. It's where mac stores carrier-sense frame for carrier-sense function. -#define HW_CS_CTS_BASE 0x7700 -// DFS CTS frame base address. It's where mac stores CTS frame for DFS. -#define HW_DFS_CTS_BASE 0x7780 -#define HW_CTS_FRAME_SIZE 0x80 - -// 2004-11-08 john - since NULL frame won't be that long (256 byte). We steal 16 tail bytes -// to save debugging settings -#define HW_DEBUG_SETTING_BASE 0x77f0 // 0x77f0~0x77ff total 16 bytes -#define HW_DEBUG_SETTING_BASE2 0x7770 // 0x77f0~0x77ff total 16 bytes - -#if 0 -// on-chip BEACON frame space - base address = 0x7800 -#define HW_BEACON_MAX_SIZE 0x0800 /* unit: byte */ -#define HW_BEACON_BASE0 0x7800 -#define HW_BEACON_BASE1 0x7900 -#define HW_BEACON_BASE2 0x7a00 -#define HW_BEACON_BASE3 0x7b00 -#define HW_BEACON_BASE4 0x7c00 -#define HW_BEACON_BASE5 0x7d00 -#define HW_BEACON_BASE6 0x7e00 -#define HW_BEACON_BASE7 0x7f00 -/* 1. HW_BEACON_OFFSET/64B must be 0; - 2. BCN_OFFSET0 must also be changed in NICInitializeAsic(); - 3. max 0x0800 for 8 beacon frames; */ -#else -// In order to support maximum 8 MBSS and its maximum length is 512 for each beacon -// Three section discontinue memory segments will be used. -// 1. The original region for BCN 0~3 -// 2. Extract memory from FCE table for BCN 4~5 -// 3. Extract memory from Pair-wise key table for BCN 6~7 -// It occupied those memory of wcid 238~253 for BCN 6 -// and wcid 222~237 for BCN 7 -#define HW_BEACON_MAX_SIZE 0x1000 /* unit: byte */ -#define HW_BEACON_BASE0 0x7800 -#define HW_BEACON_BASE1 0x7A00 -#define HW_BEACON_BASE2 0x7C00 -#define HW_BEACON_BASE3 0x7E00 -#define HW_BEACON_BASE4 0x7200 -#define HW_BEACON_BASE5 0x7400 -#define HW_BEACON_BASE6 0x5DC0 -#define HW_BEACON_BASE7 0x5BC0 -#endif - -#define HW_BEACON_MAX_COUNT 8 -#define HW_BEACON_OFFSET 0x0200 -#define HW_BEACON_CONTENT_LEN (HW_BEACON_OFFSET - TXWI_SIZE) - -// HOST-MCU shared memory - base address = 0x2100 -#define HOST_CMD_CSR 0x404 -#define H2M_MAILBOX_CSR 0x7010 -#define H2M_MAILBOX_CID 0x7014 -#define H2M_MAILBOX_STATUS 0x701c -#define H2M_INT_SRC 0x7024 -#define H2M_BBP_AGENT 0x7028 -#define M2H_CMD_DONE_CSR 0x000c -#define MCU_TXOP_ARRAY_BASE 0x000c // TODO: to be provided by Albert -#define MCU_TXOP_ENTRY_SIZE 32 // TODO: to be provided by Albert -#define MAX_NUM_OF_TXOP_ENTRY 16 // TODO: must be same with 8051 firmware -#define MCU_MBOX_VERSION 0x01 // TODO: to be confirmed by Albert -#define MCU_MBOX_VERSION_OFFSET 5 // TODO: to be provided by Albert - -// -// Host DMA registers - base address 0x200 . TX0-3=EDCAQid0-3, TX4=HCCA, TX5=MGMT, -// -// -// DMA RING DESCRIPTOR -// -#define E2PROM_CSR 0x0004 -#define IO_CNTL_CSR 0x77d0 - -#ifdef RT2870 -// 8051 firmware image for usb - use last-half base address = 0x3000 -#define FIRMWARE_IMAGE_BASE 0x3000 -#define MAX_FIRMWARE_IMAGE_SIZE 0x1000 // 4kbyte -#endif // RT2870 // - -// TODO: ????? old RT2560 registers. to keep them or remove them? -//#define MCAST0 0x0178 // multicast filter register 0 -//#define MCAST1 0x017c // multicast filter register 1 - - -// ================================================================ -// Tx / Rx / Mgmt ring descriptor definition -// ================================================================ - -// the following PID values are used to mark outgoing frame type in TXD->PID so that -// proper TX statistics can be collected based on these categories -// b3-2 of PID field - -#define PID_MGMT 0x05 -#define PID_BEACON 0x0c -#define PID_DATA_NORMALUCAST 0x02 -#define PID_DATA_AMPDU 0x04 -#define PID_DATA_NO_ACK 0x08 -#define PID_DATA_NOT_NORM_ACK 0x03 -#if 0 -#define PTYPE_DATA_REQUIRE_ACK 0x00 // b7-6:00, b5-0: 0~59 is MAC table index (AID?), 60~63 is WDS index -#define PTYPE_NULL_AT_HIGH_RATE 0x04 // b7-6:01, b5-0: 0~59 is MAC table index (AID?), 60~63 is WDS index -#define PTYPE_RESERVED 0x08 // b7-6:10 -#define PTYPE_SPECIAL 0x0c // b7-6:11 - -// when b3-2=11 (PTYPE_SPECIAL), b1-0 coube be ... -#define PSUBTYPE_DATA_NO_ACK 0x00 -#define PSUBTYPE_MGMT 0x01 -#define PSUBTYPE_OTHER_CNTL 0x02 -#define PSUBTYPE_RTS 0x03 -#endif -// value domain of pTxD->HostQId (4-bit: 0~15) -#define QID_AC_BK 1 // meet ACI definition in 802.11e -#define QID_AC_BE 0 // meet ACI definition in 802.11e -#define QID_AC_VI 2 -#define QID_AC_VO 3 -#define QID_HCCA 4 -#define NUM_OF_TX_RING 5 -#define QID_MGMT 13 -#define QID_RX 14 -#define QID_OTHER 15 - - -// ------------------------------------------------------ -// BBP & RF definition -// ------------------------------------------------------ -#define BUSY 1 -#define IDLE 0 - -#define RF_R00 0 -#define RF_R01 1 -#define RF_R02 2 -#define RF_R03 3 -#define RF_R04 4 -#define RF_R05 5 -#define RF_R06 6 -#define RF_R07 7 -#define RF_R08 8 -#define RF_R09 9 -#define RF_R10 10 -#define RF_R11 11 -#define RF_R12 12 -#define RF_R13 13 -#define RF_R14 14 -#define RF_R15 15 -#define RF_R16 16 -#define RF_R17 17 -#define RF_R18 18 -#define RF_R19 19 -#define RF_R20 20 -#define RF_R21 21 -#define RF_R22 22 -#define RF_R23 23 -#define RF_R24 24 -#define RF_R25 25 -#define RF_R26 26 -#define RF_R27 27 -#define RF_R28 28 -#define RF_R29 29 -#define RF_R30 30 -#define RF_R31 31 - -#define BBP_R0 0 // version -#define BBP_R1 1 // TSSI -#define BBP_R2 2 // TX configure -#define BBP_R3 3 -#define BBP_R4 4 -#define BBP_R5 5 -#define BBP_R6 6 -#define BBP_R14 14 // RX configure -#define BBP_R16 16 -#define BBP_R17 17 // RX sensibility -#define BBP_R18 18 -#define BBP_R21 21 -#define BBP_R22 22 -#define BBP_R24 24 -#define BBP_R25 25 -#define BBP_R49 49 //TSSI -#define BBP_R50 50 -#define BBP_R51 51 -#define BBP_R52 52 -#define BBP_R55 55 -#define BBP_R62 62 // Rx SQ0 Threshold HIGH -#define BBP_R63 63 -#define BBP_R64 64 -#define BBP_R65 65 -#define BBP_R66 66 -#define BBP_R67 67 -#define BBP_R68 68 -#define BBP_R69 69 -#define BBP_R70 70 // Rx AGC SQ CCK Xcorr threshold -#define BBP_R73 73 -#define BBP_R75 75 -#define BBP_R77 77 -#define BBP_R81 81 -#define BBP_R82 82 -#define BBP_R83 83 -#define BBP_R84 84 -#define BBP_R86 86 -#define BBP_R91 91 -#define BBP_R92 92 -#define BBP_R94 94 // Tx Gain Control -#define BBP_R103 103 -#define BBP_R105 105 -#define BBP_R113 113 -#define BBP_R114 114 -#define BBP_R115 115 -#define BBP_R116 116 -#define BBP_R117 117 -#define BBP_R118 118 -#define BBP_R119 119 -#define BBP_R120 120 -#define BBP_R121 121 -#define BBP_R122 122 -#define BBP_R123 123 - - -#define BBPR94_DEFAULT 0x06 // Add 1 value will gain 1db - -//#define PHY_TR_SWITCH_TIME 5 // usec - -//#define BBP_R17_LOW_SENSIBILITY 0x50 -//#define BBP_R17_MID_SENSIBILITY 0x41 -//#define BBP_R17_DYNAMIC_UP_BOUND 0x40 -#define RSSI_FOR_VERY_LOW_SENSIBILITY -35 -#define RSSI_FOR_LOW_SENSIBILITY -58 -#define RSSI_FOR_MID_LOW_SENSIBILITY -80 -#define RSSI_FOR_MID_SENSIBILITY -90 - -//------------------------------------------------------------------------- -// EEPROM definition -//------------------------------------------------------------------------- -#define EEDO 0x08 -#define EEDI 0x04 -#define EECS 0x02 -#define EESK 0x01 -#define EERL 0x80 - -#define EEPROM_WRITE_OPCODE 0x05 -#define EEPROM_READ_OPCODE 0x06 -#define EEPROM_EWDS_OPCODE 0x10 -#define EEPROM_EWEN_OPCODE 0x13 - -#define NUM_EEPROM_BBP_PARMS 19 // Include NIC Config 0, 1, CR, TX ALC step, BBPs -#define NUM_EEPROM_TX_G_PARMS 7 -#define EEPROM_NIC1_OFFSET 0x34 // The address is from NIC config 0, not BBP register ID -#define EEPROM_NIC2_OFFSET 0x36 // The address is from NIC config 0, not BBP register ID -#define EEPROM_BBP_BASE_OFFSET 0xf0 // The address is from NIC config 0, not BBP register ID -#define EEPROM_G_TX_PWR_OFFSET 0x52 -#define EEPROM_G_TX2_PWR_OFFSET 0x60 -#define EEPROM_LED1_OFFSET 0x3c -#define EEPROM_LED2_OFFSET 0x3e -#define EEPROM_LED3_OFFSET 0x40 -#define EEPROM_LNA_OFFSET 0x44 -#define EEPROM_RSSI_BG_OFFSET 0x46 -#define EEPROM_RSSI_A_OFFSET 0x4a -#define EEPROM_DEFINE_MAX_TXPWR 0x4e -#define EEPROM_TXPOWER_BYRATE_20MHZ_2_4G 0xde // 20MHZ 2.4G tx power. -#define EEPROM_TXPOWER_BYRATE_40MHZ_2_4G 0xee // 40MHZ 2.4G tx power. -#define EEPROM_TXPOWER_BYRATE_20MHZ_5G 0xfa // 20MHZ 5G tx power. -#define EEPROM_TXPOWER_BYRATE_40MHZ_5G 0x10a // 40MHZ 5G tx power. -#define EEPROM_A_TX_PWR_OFFSET 0x78 -#define EEPROM_A_TX2_PWR_OFFSET 0xa6 -//#define EEPROM_Japan_TX_PWR_OFFSET 0x90 // 802.11j -//#define EEPROM_Japan_TX2_PWR_OFFSET 0xbe -//#define EEPROM_TSSI_REF_OFFSET 0x54 -//#define EEPROM_TSSI_DELTA_OFFSET 0x24 -//#define EEPROM_CCK_TX_PWR_OFFSET 0x62 -//#define EEPROM_CALIBRATE_OFFSET 0x7c -#define EEPROM_VERSION_OFFSET 0x02 -#define EEPROM_FREQ_OFFSET 0x3a -#define EEPROM_TXPOWER_BYRATE 0xde // 20MHZ power. -#define EEPROM_TXPOWER_DELTA 0x50 // 20MHZ AND 40 MHZ use different power. This is delta in 40MHZ. -#define VALID_EEPROM_VERSION 1 - -// PairKeyMode definition -#define PKMODE_NONE 0 -#define PKMODE_WEP64 1 -#define PKMODE_WEP128 2 -#define PKMODE_TKIP 3 -#define PKMODE_AES 4 -#define PKMODE_CKIP64 5 -#define PKMODE_CKIP128 6 -#define PKMODE_TKIP_NO_MIC 7 // MIC appended by driver: not a valid value in hardware key table - -// ================================================================================= -// WCID format -// ================================================================================= -//7.1 WCID ENTRY format : 8bytes -typedef struct _WCID_ENTRY_STRUC { - UCHAR RXBABitmap7; // bit0 for TID8, bit7 for TID 15 - UCHAR RXBABitmap0; // bit0 for TID0, bit7 for TID 7 - UCHAR MAC[6]; // 0 for shared key table. 1 for pairwise key table -} WCID_ENTRY_STRUC, *PWCID_ENTRY_STRUC; - -//8.1.1 SECURITY KEY format : 8DW -// 32-byte per entry, total 16-entry for shared key table, 64-entry for pairwise key table -typedef struct _HW_KEY_ENTRY { // 32-byte per entry - UCHAR Key[16]; - UCHAR TxMic[8]; - UCHAR RxMic[8]; -} HW_KEY_ENTRY, *PHW_KEY_ENTRY; - -//8.1.2 IV/EIV format : 2DW - -//8.1.3 RX attribute entry format : 1DW -#ifdef RT_BIG_ENDIAN -typedef struct _MAC_ATTRIBUTE_STRUC { - UINT32 rsv:22; - UINT32 RXWIUDF:3; - UINT32 BSSIDIdx:3; //multipleBSS index for the WCID - UINT32 PairKeyMode:3; - UINT32 KeyTab:1; // 0 for shared key table. 1 for pairwise key table -} MAC_ATTRIBUTE_STRUC, *PMAC_ATTRIBUTE_STRUC; -#else -typedef struct _MAC_ATTRIBUTE_STRUC { - UINT32 KeyTab:1; // 0 for shared key table. 1 for pairwise key table - UINT32 PairKeyMode:3; - UINT32 BSSIDIdx:3; //multipleBSS index for the WCID - UINT32 RXWIUDF:3; - UINT32 rsv:22; -} MAC_ATTRIBUTE_STRUC, *PMAC_ATTRIBUTE_STRUC; -#endif - - -// ================================================================================= -// TX / RX ring descriptor format -// ================================================================================= - -// the first 24-byte in TXD is called TXINFO and will be DMAed to MAC block through TXFIFO. -// MAC block use this TXINFO to control the transmission behavior of this frame. -#define FIFO_MGMT 0 -#define FIFO_HCCA 1 -#define FIFO_EDCA 2 - -// -// TX descriptor format, Tx ring, Mgmt Ring -// -#ifdef RT_BIG_ENDIAN -typedef struct PACKED _TXD_STRUC { - // Word 0 - UINT32 SDPtr0; - // Word 1 - UINT32 DMADONE:1; - UINT32 LastSec0:1; - UINT32 SDLen0:14; - UINT32 Burst:1; - UINT32 LastSec1:1; - UINT32 SDLen1:14; - // Word 2 - UINT32 SDPtr1; - // Word 3 - UINT32 ICO:1; - UINT32 UCO:1; - UINT32 TCO:1; - UINT32 rsv:2; - UINT32 QSEL:2; // select on-chip FIFO ID for 2nd-stage output scheduler.0:MGMT, 1:HCCA 2:EDCA - UINT32 WIV:1; // Wireless Info Valid. 1 if Driver already fill WI, o if DMA needs to copy WI to correctposition - UINT32 rsv2:24; -} TXD_STRUC, *PTXD_STRUC; -#else -typedef struct PACKED _TXD_STRUC { - // Word 0 - UINT32 SDPtr0; - // Word 1 - UINT32 SDLen1:14; - UINT32 LastSec1:1; - UINT32 Burst:1; - UINT32 SDLen0:14; - UINT32 LastSec0:1; - UINT32 DMADONE:1; - //Word2 - UINT32 SDPtr1; - //Word3 - UINT32 rsv2:24; - UINT32 WIV:1; // Wireless Info Valid. 1 if Driver already fill WI, o if DMA needs to copy WI to correctposition - UINT32 QSEL:2; // select on-chip FIFO ID for 2nd-stage output scheduler.0:MGMT, 1:HCCA 2:EDCA - UINT32 rsv:2; - UINT32 TCO:1; // - UINT32 UCO:1; // - UINT32 ICO:1; // -} TXD_STRUC, *PTXD_STRUC; -#endif - - -// -// TXD Wireless Information format for Tx ring and Mgmt Ring -// -//txop : for txop mode -// 0:txop for the MPDU frame will be handles by ASIC by register -// 1/2/3:the MPDU frame is send after PIFS/backoff/SIFS -#ifdef RT_BIG_ENDIAN -typedef struct PACKED _TXWI_STRUC { - // Word 0 - UINT32 PHYMODE:2; - UINT32 TxBF:1; // 3*3 - UINT32 rsv2:1; -// UINT32 rsv2:2; - UINT32 Ifs:1; // - UINT32 STBC:2; //channel bandwidth 20MHz or 40 MHz - UINT32 ShortGI:1; - UINT32 BW:1; //channel bandwidth 20MHz or 40 MHz - UINT32 MCS:7; - - UINT32 rsv:6; - UINT32 txop:2; //tx back off mode 0:HT TXOP rule , 1:PIFS TX ,2:Backoff, 3:sifs only when previous frame exchange is successful. - UINT32 MpduDensity:3; - UINT32 AMPDU:1; - - UINT32 TS:1; - UINT32 CFACK:1; - UINT32 MIMOps:1; // the remote peer is in dynamic MIMO-PS mode - UINT32 FRAG:1; // 1 to inform TKIP engine this is a fragment. - // Word 1 - UINT32 PacketId:4; - UINT32 MPDUtotalByteCount:12; - UINT32 WirelessCliID:8; - UINT32 BAWinSize:6; - UINT32 NSEQ:1; - UINT32 ACK:1; - // Word 2 - UINT32 IV; - // Word 3 - UINT32 EIV; -} TXWI_STRUC, *PTXWI_STRUC; -#else -typedef struct PACKED _TXWI_STRUC { - // Word 0 - UINT32 FRAG:1; // 1 to inform TKIP engine this is a fragment. - UINT32 MIMOps:1; // the remote peer is in dynamic MIMO-PS mode - UINT32 CFACK:1; - UINT32 TS:1; - - UINT32 AMPDU:1; - UINT32 MpduDensity:3; - UINT32 txop:2; //FOR "THIS" frame. 0:HT TXOP rule , 1:PIFS TX ,2:Backoff, 3:sifs only when previous frame exchange is successful. - UINT32 rsv:6; - - UINT32 MCS:7; - UINT32 BW:1; //channel bandwidth 20MHz or 40 MHz - UINT32 ShortGI:1; - UINT32 STBC:2; // 1: STBC support MCS =0-7, 2,3 : RESERVE - UINT32 Ifs:1; // -// UINT32 rsv2:2; //channel bandwidth 20MHz or 40 MHz - UINT32 rsv2:1; - UINT32 TxBF:1; // 3*3 - UINT32 PHYMODE:2; - // Word 1 - UINT32 ACK:1; - UINT32 NSEQ:1; - UINT32 BAWinSize:6; - UINT32 WirelessCliID:8; - UINT32 MPDUtotalByteCount:12; - UINT32 PacketId:4; - //Word2 - UINT32 IV; - //Word3 - UINT32 EIV; -} TXWI_STRUC, *PTXWI_STRUC; -#endif -// -// Rx descriptor format, Rx Ring -// -// -// RXWI wireless information format, in PBF. invisible in driver. -// -#ifdef RT_BIG_ENDIAN -typedef struct PACKED _RXWI_STRUC { - // Word 0 - UINT32 TID:4; - UINT32 MPDUtotalByteCount:12; - UINT32 UDF:3; - UINT32 BSSID:3; - UINT32 KeyIndex:2; - UINT32 WirelessCliID:8; - // Word 1 - UINT32 PHYMODE:2; // 1: this RX frame is unicast to me - UINT32 rsv:3; - UINT32 STBC:2; - UINT32 ShortGI:1; - UINT32 BW:1; - UINT32 MCS:7; - UINT32 SEQUENCE:12; - UINT32 FRAG:4; - // Word 2 - UINT32 rsv1:8; - UINT32 RSSI2:8; - UINT32 RSSI1:8; - UINT32 RSSI0:8; - // Word 3 - UINT32 rsv2:16; - UINT32 SNR1:8; - UINT32 SNR0:8; -} RXWI_STRUC, *PRXWI_STRUC; -#else -typedef struct PACKED _RXWI_STRUC { - // Word 0 - UINT32 WirelessCliID:8; - UINT32 KeyIndex:2; - UINT32 BSSID:3; - UINT32 UDF:3; - UINT32 MPDUtotalByteCount:12; - UINT32 TID:4; - // Word 1 - UINT32 FRAG:4; - UINT32 SEQUENCE:12; - UINT32 MCS:7; - UINT32 BW:1; - UINT32 ShortGI:1; - UINT32 STBC:2; - UINT32 rsv:3; - UINT32 PHYMODE:2; // 1: this RX frame is unicast to me - //Word2 - UINT32 RSSI0:8; - UINT32 RSSI1:8; - UINT32 RSSI2:8; - UINT32 rsv1:8; - //Word3 - UINT32 SNR0:8; - UINT32 SNR1:8; - UINT32 rsv2:16; -} RXWI_STRUC, *PRXWI_STRUC; -#endif - - -// ================================================================================= -// HOST-MCU communication data structure -// ================================================================================= - -// -// H2M_MAILBOX_CSR: Host-to-MCU Mailbox -// -#ifdef RT_BIG_ENDIAN -typedef union _H2M_MAILBOX_STRUC { - struct { - UINT32 Owner:8; - UINT32 CmdToken:8; // 0xff tells MCU not to report CmdDoneInt after excuting the command - UINT32 HighByte:8; - UINT32 LowByte:8; - } field; - UINT32 word; -} H2M_MAILBOX_STRUC, *PH2M_MAILBOX_STRUC; -#else -typedef union _H2M_MAILBOX_STRUC { - struct { - UINT32 LowByte:8; - UINT32 HighByte:8; - UINT32 CmdToken:8; - UINT32 Owner:8; - } field; - UINT32 word; -} H2M_MAILBOX_STRUC, *PH2M_MAILBOX_STRUC; -#endif - -// -// M2H_CMD_DONE_CSR: MCU-to-Host command complete indication -// -#ifdef RT_BIG_ENDIAN -typedef union _M2H_CMD_DONE_STRUC { - struct { - UINT32 CmdToken3; - UINT32 CmdToken2; - UINT32 CmdToken1; - UINT32 CmdToken0; - } field; - UINT32 word; -} M2H_CMD_DONE_STRUC, *PM2H_CMD_DONE_STRUC; -#else -typedef union _M2H_CMD_DONE_STRUC { - struct { - UINT32 CmdToken0; - UINT32 CmdToken1; - UINT32 CmdToken2; - UINT32 CmdToken3; - } field; - UINT32 word; -} M2H_CMD_DONE_STRUC, *PM2H_CMD_DONE_STRUC; -#endif - - - -// -// MCU_LEDCS: MCU LED Control Setting. -// -#ifdef RT_BIG_ENDIAN -typedef union _MCU_LEDCS_STRUC { - struct { - UCHAR Polarity:1; - UCHAR LedMode:7; - } field; - UCHAR word; -} MCU_LEDCS_STRUC, *PMCU_LEDCS_STRUC; -#else -typedef union _MCU_LEDCS_STRUC { - struct { - UCHAR LedMode:7; - UCHAR Polarity:1; - } field; - UCHAR word; -} MCU_LEDCS_STRUC, *PMCU_LEDCS_STRUC; -#endif -// ================================================================================= -// Register format -// ================================================================================= - - - -//NAV_TIME_CFG :NAV -#ifdef RT_BIG_ENDIAN -typedef union _NAV_TIME_CFG_STRUC { - struct { - USHORT rsv:6; - USHORT ZeroSifs:1; // Applied zero SIFS timer after OFDM RX 0: disable - USHORT Eifs:9; // in unit of 1-us - UCHAR SlotTime; // in unit of 1-us - UCHAR Sifs; // in unit of 1-us - } field; - UINT32 word; -} NAV_TIME_CFG_STRUC, *PNAV_TIME_CFG_STRUC; -#else -typedef union _NAV_TIME_CFG_STRUC { - struct { - UCHAR Sifs; // in unit of 1-us - UCHAR SlotTime; // in unit of 1-us - USHORT Eifs:9; // in unit of 1-us - USHORT ZeroSifs:1; // Applied zero SIFS timer after OFDM RX 0: disable - USHORT rsv:6; - } field; - UINT32 word; -} NAV_TIME_CFG_STRUC, *PNAV_TIME_CFG_STRUC; -#endif - - - - - -// -// RX_FILTR_CFG: /RX configuration register -// -#ifdef RT_BIG_ENDIAN -typedef union RX_FILTR_CFG_STRUC { - struct { - UINT32 :15; - UINT32 DropRsvCntlType:1; - - UINT32 DropBAR:1; // - UINT32 DropBA:1; // - UINT32 DropPsPoll:1; // Drop Ps-Poll - UINT32 DropRts:1; // Drop Ps-Poll - - UINT32 DropCts:1; // Drop Ps-Poll - UINT32 DropAck:1; // Drop Ps-Poll - UINT32 DropCFEnd:1; // Drop Ps-Poll - UINT32 DropCFEndAck:1; // Drop Ps-Poll - - UINT32 DropDuplicate:1; // Drop duplicate frame - UINT32 DropBcast:1; // Drop broadcast frames - UINT32 DropMcast:1; // Drop multicast frames - UINT32 DropVerErr:1; // Drop version error frame - - UINT32 DropNotMyBSSID:1; // Drop fram ToDs bit is true - UINT32 DropNotToMe:1; // Drop not to me unicast frame - UINT32 DropPhyErr:1; // Drop physical error - UINT32 DropCRCErr:1; // Drop CRC error - } field; - UINT32 word; -} RX_FILTR_CFG_STRUC, *PRX_FILTR_CFG_STRUC; -#else -typedef union _RX_FILTR_CFG_STRUC { - struct { - UINT32 DropCRCErr:1; // Drop CRC error - UINT32 DropPhyErr:1; // Drop physical error - UINT32 DropNotToMe:1; // Drop not to me unicast frame - UINT32 DropNotMyBSSID:1; // Drop fram ToDs bit is true - - UINT32 DropVerErr:1; // Drop version error frame - UINT32 DropMcast:1; // Drop multicast frames - UINT32 DropBcast:1; // Drop broadcast frames - UINT32 DropDuplicate:1; // Drop duplicate frame - - UINT32 DropCFEndAck:1; // Drop Ps-Poll - UINT32 DropCFEnd:1; // Drop Ps-Poll - UINT32 DropAck:1; // Drop Ps-Poll - UINT32 DropCts:1; // Drop Ps-Poll - - UINT32 DropRts:1; // Drop Ps-Poll - UINT32 DropPsPoll:1; // Drop Ps-Poll - UINT32 DropBA:1; // - UINT32 DropBAR:1; // - - UINT32 DropRsvCntlType:1; - UINT32 :15; - } field; - UINT32 word; -} RX_FILTR_CFG_STRUC, *PRX_FILTR_CFG_STRUC; -#endif - - - - -// -// PHY_CSR4: RF serial control register -// -#ifdef RT_BIG_ENDIAN -typedef union _PHY_CSR4_STRUC { - struct { - UINT32 Busy:1; // 1: ASIC is busy execute RF programming. - UINT32 PLL_LD:1; // RF PLL_LD status - UINT32 IFSelect:1; // 1: select IF to program, 0: select RF to program - UINT32 NumberOfBits:5; // Number of bits used in RFRegValue (I:20, RFMD:22) - UINT32 RFRegValue:24; // Register value (include register id) serial out to RF/IF chip. - } field; - UINT32 word; -} PHY_CSR4_STRUC, *PPHY_CSR4_STRUC; -#else -typedef union _PHY_CSR4_STRUC { - struct { - UINT32 RFRegValue:24; // Register value (include register id) serial out to RF/IF chip. - UINT32 NumberOfBits:5; // Number of bits used in RFRegValue (I:20, RFMD:22) - UINT32 IFSelect:1; // 1: select IF to program, 0: select RF to program - UINT32 PLL_LD:1; // RF PLL_LD status - UINT32 Busy:1; // 1: ASIC is busy execute RF programming. - } field; - UINT32 word; -} PHY_CSR4_STRUC, *PPHY_CSR4_STRUC; -#endif - - -// -// SEC_CSR5: shared key table security mode register -// -#ifdef RT_BIG_ENDIAN -typedef union _SEC_CSR5_STRUC { - struct { - UINT32 :1; - UINT32 Bss3Key3CipherAlg:3; - UINT32 :1; - UINT32 Bss3Key2CipherAlg:3; - UINT32 :1; - UINT32 Bss3Key1CipherAlg:3; - UINT32 :1; - UINT32 Bss3Key0CipherAlg:3; - UINT32 :1; - UINT32 Bss2Key3CipherAlg:3; - UINT32 :1; - UINT32 Bss2Key2CipherAlg:3; - UINT32 :1; - UINT32 Bss2Key1CipherAlg:3; - UINT32 :1; - UINT32 Bss2Key0CipherAlg:3; - } field; - UINT32 word; -} SEC_CSR5_STRUC, *PSEC_CSR5_STRUC; -#else -typedef union _SEC_CSR5_STRUC { - struct { - UINT32 Bss2Key0CipherAlg:3; - UINT32 :1; - UINT32 Bss2Key1CipherAlg:3; - UINT32 :1; - UINT32 Bss2Key2CipherAlg:3; - UINT32 :1; - UINT32 Bss2Key3CipherAlg:3; - UINT32 :1; - UINT32 Bss3Key0CipherAlg:3; - UINT32 :1; - UINT32 Bss3Key1CipherAlg:3; - UINT32 :1; - UINT32 Bss3Key2CipherAlg:3; - UINT32 :1; - UINT32 Bss3Key3CipherAlg:3; - UINT32 :1; - } field; - UINT32 word; -} SEC_CSR5_STRUC, *PSEC_CSR5_STRUC; -#endif - - -// -// HOST_CMD_CSR: For HOST to interrupt embedded processor -// -#ifdef RT_BIG_ENDIAN -typedef union _HOST_CMD_CSR_STRUC { - struct { - UINT32 Rsv:24; - UINT32 HostCommand:8; - } field; - UINT32 word; -} HOST_CMD_CSR_STRUC, *PHOST_CMD_CSR_STRUC; -#else -typedef union _HOST_CMD_CSR_STRUC { - struct { - UINT32 HostCommand:8; - UINT32 Rsv:24; - } field; - UINT32 word; -} HOST_CMD_CSR_STRUC, *PHOST_CMD_CSR_STRUC; -#endif - - -// -// AIFSN_CSR: AIFSN for each EDCA AC -// - - - -// -// E2PROM_CSR: EEPROM control register -// -#ifdef RT_BIG_ENDIAN -typedef union _E2PROM_CSR_STRUC { - struct { - UINT32 Rsvd:25; - UINT32 LoadStatus:1; // 1:loading, 0:done - UINT32 Type:1; // 1: 93C46, 0:93C66 - UINT32 EepromDO:1; - UINT32 EepromDI:1; - UINT32 EepromCS:1; - UINT32 EepromSK:1; - UINT32 Reload:1; // Reload EEPROM content, write one to reload, self-cleared. - } field; - UINT32 word; -} E2PROM_CSR_STRUC, *PE2PROM_CSR_STRUC; -#else -typedef union _E2PROM_CSR_STRUC { - struct { - UINT32 Reload:1; // Reload EEPROM content, write one to reload, self-cleared. - UINT32 EepromSK:1; - UINT32 EepromCS:1; - UINT32 EepromDI:1; - UINT32 EepromDO:1; - UINT32 Type:1; // 1: 93C46, 0:93C66 - UINT32 LoadStatus:1; // 1:loading, 0:done - UINT32 Rsvd:25; - } field; - UINT32 word; -} E2PROM_CSR_STRUC, *PE2PROM_CSR_STRUC; -#endif - - -// ------------------------------------------------------------------- -// E2PROM data layout -// ------------------------------------------------------------------- - -// -// EEPROM antenna select format -// -#ifdef RT_BIG_ENDIAN -typedef union _EEPROM_ANTENNA_STRUC { - struct { - USHORT Rsv:4; - USHORT RfIcType:4; // see E2PROM document - USHORT TxPath:4; // 1: 1T, 2: 2T - USHORT RxPath:4; // 1: 1R, 2: 2R, 3: 3R - } field; - USHORT word; -} EEPROM_ANTENNA_STRUC, *PEEPROM_ANTENNA_STRUC; -#else -typedef union _EEPROM_ANTENNA_STRUC { - struct { - USHORT RxPath:4; // 1: 1R, 2: 2R, 3: 3R - USHORT TxPath:4; // 1: 1T, 2: 2T - USHORT RfIcType:4; // see E2PROM document - USHORT Rsv:4; - } field; - USHORT word; -} EEPROM_ANTENNA_STRUC, *PEEPROM_ANTENNA_STRUC; -#endif - -#ifdef RT_BIG_ENDIAN -typedef union _EEPROM_NIC_CINFIG2_STRUC { - struct { - USHORT Rsv2:6; // must be 0 - USHORT BW40MAvailForA:1; // 0:enable, 1:disable - USHORT BW40MAvailForG:1; // 0:enable, 1:disable - USHORT EnableWPSPBC:1; // WPS PBC Control bit - USHORT BW40MSidebandForA:1; - USHORT BW40MSidebandForG:1; - USHORT CardbusAcceleration:1; // !!! NOTE: 0 - enable, 1 - disable - USHORT ExternalLNAForA:1; // external LNA enable for 5G - USHORT ExternalLNAForG:1; // external LNA enable for 2.4G - USHORT DynamicTxAgcControl:1; // - USHORT HardwareRadioControl:1; // Whether RF is controlled by driver or HW. 1:enable hw control, 0:disable - } field; - USHORT word; -} EEPROM_NIC_CONFIG2_STRUC, *PEEPROM_NIC_CONFIG2_STRUC; -#else -typedef union _EEPROM_NIC_CINFIG2_STRUC { - struct { - USHORT HardwareRadioControl:1; // 1:enable, 0:disable - USHORT DynamicTxAgcControl:1; // - USHORT ExternalLNAForG:1; // - USHORT ExternalLNAForA:1; // external LNA enable for 2.4G - USHORT CardbusAcceleration:1; // !!! NOTE: 0 - enable, 1 - disable - USHORT BW40MSidebandForG:1; - USHORT BW40MSidebandForA:1; - USHORT EnableWPSPBC:1; // WPS PBC Control bit - USHORT BW40MAvailForG:1; // 0:enable, 1:disable - USHORT BW40MAvailForA:1; // 0:enable, 1:disable - USHORT Rsv2:6; // must be 0 - } field; - USHORT word; -} EEPROM_NIC_CONFIG2_STRUC, *PEEPROM_NIC_CONFIG2_STRUC; -#endif - -// -// TX_PWR Value valid range 0xFA(-6) ~ 0x24(36) -// -#ifdef RT_BIG_ENDIAN -typedef union _EEPROM_TX_PWR_STRUC { - struct { - CHAR Byte1; // High Byte - CHAR Byte0; // Low Byte - } field; - USHORT word; -} EEPROM_TX_PWR_STRUC, *PEEPROM_TX_PWR_STRUC; -#else -typedef union _EEPROM_TX_PWR_STRUC { - struct { - CHAR Byte0; // Low Byte - CHAR Byte1; // High Byte - } field; - USHORT word; -} EEPROM_TX_PWR_STRUC, *PEEPROM_TX_PWR_STRUC; -#endif - -#ifdef RT_BIG_ENDIAN -typedef union _EEPROM_VERSION_STRUC { - struct { - UCHAR Version; // High Byte - UCHAR FaeReleaseNumber; // Low Byte - } field; - USHORT word; -} EEPROM_VERSION_STRUC, *PEEPROM_VERSION_STRUC; -#else -typedef union _EEPROM_VERSION_STRUC { - struct { - UCHAR FaeReleaseNumber; // Low Byte - UCHAR Version; // High Byte - } field; - USHORT word; -} EEPROM_VERSION_STRUC, *PEEPROM_VERSION_STRUC; -#endif - -#ifdef RT_BIG_ENDIAN -typedef union _EEPROM_LED_STRUC { - struct { - USHORT Rsvd:3; // Reserved - USHORT LedMode:5; // Led mode. - USHORT PolarityGPIO_4:1; // Polarity GPIO#4 setting. - USHORT PolarityGPIO_3:1; // Polarity GPIO#3 setting. - USHORT PolarityGPIO_2:1; // Polarity GPIO#2 setting. - USHORT PolarityGPIO_1:1; // Polarity GPIO#1 setting. - USHORT PolarityGPIO_0:1; // Polarity GPIO#0 setting. - USHORT PolarityACT:1; // Polarity ACT setting. - USHORT PolarityRDY_A:1; // Polarity RDY_A setting. - USHORT PolarityRDY_G:1; // Polarity RDY_G setting. - } field; - USHORT word; -} EEPROM_LED_STRUC, *PEEPROM_LED_STRUC; -#else -typedef union _EEPROM_LED_STRUC { - struct { - USHORT PolarityRDY_G:1; // Polarity RDY_G setting. - USHORT PolarityRDY_A:1; // Polarity RDY_A setting. - USHORT PolarityACT:1; // Polarity ACT setting. - USHORT PolarityGPIO_0:1; // Polarity GPIO#0 setting. - USHORT PolarityGPIO_1:1; // Polarity GPIO#1 setting. - USHORT PolarityGPIO_2:1; // Polarity GPIO#2 setting. - USHORT PolarityGPIO_3:1; // Polarity GPIO#3 setting. - USHORT PolarityGPIO_4:1; // Polarity GPIO#4 setting. - USHORT LedMode:5; // Led mode. - USHORT Rsvd:3; // Reserved - } field; - USHORT word; -} EEPROM_LED_STRUC, *PEEPROM_LED_STRUC; -#endif - -#ifdef RT_BIG_ENDIAN -typedef union _EEPROM_TXPOWER_DELTA_STRUC { - struct { - UCHAR TxPowerEnable:1;// Enable - UCHAR Type:1; // 1: plus the delta value, 0: minus the delta value - UCHAR DeltaValue:6; // Tx Power dalta value (MAX=4) - } field; - UCHAR value; -} EEPROM_TXPOWER_DELTA_STRUC, *PEEPROM_TXPOWER_DELTA_STRUC; -#else -typedef union _EEPROM_TXPOWER_DELTA_STRUC { - struct { - UCHAR DeltaValue:6; // Tx Power dalta value (MAX=4) - UCHAR Type:1; // 1: plus the delta value, 0: minus the delta value - UCHAR TxPowerEnable:1;// Enable - } field; - UCHAR value; -} EEPROM_TXPOWER_DELTA_STRUC, *PEEPROM_TXPOWER_DELTA_STRUC; -#endif - -// -// QOS_CSR0: TXOP holder address0 register -// -#ifdef RT_BIG_ENDIAN -typedef union _QOS_CSR0_STRUC { - struct { - UCHAR Byte3; // MAC address byte 3 - UCHAR Byte2; // MAC address byte 2 - UCHAR Byte1; // MAC address byte 1 - UCHAR Byte0; // MAC address byte 0 - } field; - UINT32 word; -} QOS_CSR0_STRUC, *PQOS_CSR0_STRUC; -#else -typedef union _QOS_CSR0_STRUC { - struct { - UCHAR Byte0; // MAC address byte 0 - UCHAR Byte1; // MAC address byte 1 - UCHAR Byte2; // MAC address byte 2 - UCHAR Byte3; // MAC address byte 3 - } field; - UINT32 word; -} QOS_CSR0_STRUC, *PQOS_CSR0_STRUC; -#endif - -// -// QOS_CSR1: TXOP holder address1 register -// -#ifdef RT_BIG_ENDIAN -typedef union _QOS_CSR1_STRUC { - struct { - UCHAR Rsvd1; - UCHAR Rsvd0; - UCHAR Byte5; // MAC address byte 5 - UCHAR Byte4; // MAC address byte 4 - } field; - UINT32 word; -} QOS_CSR1_STRUC, *PQOS_CSR1_STRUC; -#else -typedef union _QOS_CSR1_STRUC { - struct { - UCHAR Byte4; // MAC address byte 4 - UCHAR Byte5; // MAC address byte 5 - UCHAR Rsvd0; - UCHAR Rsvd1; - } field; - UINT32 word; -} QOS_CSR1_STRUC, *PQOS_CSR1_STRUC; -#endif - -#define RF_CSR_CFG 0x500 -#ifdef RT_BIG_ENDIAN -typedef union _RF_CSR_CFG_STRUC { - struct { - UINT Rsvd1:14; // Reserved - UINT RF_CSR_KICK:1; // kick RF register read/write - UINT RF_CSR_WR:1; // 0: read 1: write - UINT Rsvd2:3; // Reserved - UINT TESTCSR_RFACC_REGNUM:5; // RF register ID - UINT RF_CSR_DATA:8; // DATA - } field; - UINT word; -} RF_CSR_CFG_STRUC, *PRF_CSR_CFG_STRUC; -#else -typedef union _RF_CSR_CFG_STRUC { - struct { - UINT RF_CSR_DATA:8; // DATA - UINT TESTCSR_RFACC_REGNUM:5; // RF register ID - UINT Rsvd2:3; // Reserved - UINT RF_CSR_WR:1; // 0: read 1: write - UINT RF_CSR_KICK:1; // kick RF register read/write - UINT Rsvd1:14; // Reserved - } field; - UINT word; -} RF_CSR_CFG_STRUC, *PRF_CSR_CFG_STRUC; -#endif - -#endif // __RT28XX_H__ +#include "../rt2860/rt28xx.h" diff --git a/drivers/staging/rt2870/rt_ate.c b/drivers/staging/rt2870/rt_ate.c deleted file mode 100644 index 27c763ee9276..000000000000 --- a/drivers/staging/rt2870/rt_ate.c +++ /dev/null @@ -1,6452 +0,0 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * 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 "rt_config.h" - -#ifdef UCOS -INT IoctlResponse(PUCHAR payload, PUCHAR msg, INT len); -#endif // UCOS // - -#ifdef RALINK_ATE -UCHAR TemplateFrame[24] = {0x08/* Data type */,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0xAA,0xBB,0x12,0x34,0x56,0x00,0x11,0x22,0xAA,0xBB,0xCC,0x00,0x00}; // 802.11 MAC Header, Type:Data, Length:24bytes -extern RTMP_RF_REGS RF2850RegTable[]; -extern UCHAR NUM_OF_2850_CHNL; - -#ifdef RT2870 -extern UCHAR EpToQueue[]; -extern VOID RTUSBRejectPendingPackets( IN PRTMP_ADAPTER pAd); -#endif // RT2870 // - -#ifdef UCOS -extern INT ConsoleResponse(IN PUCHAR buff); -extern int (*remote_display)(char *); -#endif // UCOS // - -static CHAR CCKRateTable[] = {0, 1, 2, 3, 8, 9, 10, 11, -1}; /* CCK Mode. */ -static CHAR OFDMRateTable[] = {0, 1, 2, 3, 4, 5, 6, 7, -1}; /* OFDM Mode. */ -static CHAR HTMIXRateTable[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, -1}; /* HT Mix Mode. */ - -static INT TxDmaBusy( - IN PRTMP_ADAPTER pAd); - -static INT RxDmaBusy( - IN PRTMP_ADAPTER pAd); - -static VOID RtmpDmaEnable( - IN PRTMP_ADAPTER pAd, - IN INT Enable); - -static VOID BbpSoftReset( - IN PRTMP_ADAPTER pAd); - -static VOID RtmpRfIoWrite( - IN PRTMP_ADAPTER pAd); - -static INT ATESetUpFrame( - IN PRTMP_ADAPTER pAd, - IN UINT32 TxIdx); - -static INT ATETxPwrHandler( - IN PRTMP_ADAPTER pAd, - IN char index); - -static INT ATECmdHandler( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -static int CheckMCSValid( - IN UCHAR Mode, - IN UCHAR Mcs); - - -#ifdef RT2870 -static VOID ATEWriteTxInfo( - IN PRTMP_ADAPTER pAd, - IN PTXINFO_STRUC pTxInfo, - IN USHORT USBDMApktLen, - IN BOOLEAN bWiv, - IN UCHAR QueueSel, - IN UCHAR NextValid, - IN UCHAR TxBurst); - -static VOID ATEWriteTxWI( - IN PRTMP_ADAPTER pAd, - IN PTXWI_STRUC pTxWI, - IN BOOLEAN FRAG, - IN BOOLEAN InsTimestamp, - IN BOOLEAN AMPDU, - IN BOOLEAN Ack, - IN BOOLEAN NSeq, // HW new a sequence. - IN UCHAR BASize, - IN UCHAR WCID, - IN ULONG Length, - IN UCHAR PID, - IN UCHAR MIMOps, - IN UCHAR Txopmode, - IN BOOLEAN CfAck, - IN HTTRANSMIT_SETTING Transmit); - -#endif // RT2870 // - -static VOID SetJapanFilter( - IN PRTMP_ADAPTER pAd); - -/*=========================end of prototype=========================*/ - - -#ifdef RT2870 -static INT TxDmaBusy( - IN PRTMP_ADAPTER pAd) -{ - INT result; - USB_DMA_CFG_STRUC UsbCfg; - - RTMP_IO_READ32(pAd, USB_DMA_CFG, &UsbCfg.word); // disable DMA - if (UsbCfg.field.TxBusy) - result = 1; - else - result = 0; - - return result; -} - -static INT RxDmaBusy( - IN PRTMP_ADAPTER pAd) -{ - INT result; - USB_DMA_CFG_STRUC UsbCfg; - - RTMP_IO_READ32(pAd, USB_DMA_CFG, &UsbCfg.word); // disable DMA - if (UsbCfg.field.RxBusy) - result = 1; - else - result = 0; - - return result; -} - -static VOID RtmpDmaEnable( - IN PRTMP_ADAPTER pAd, - IN INT Enable) -{ - BOOLEAN value; - ULONG WaitCnt; - USB_DMA_CFG_STRUC UsbCfg; - - value = Enable > 0 ? 1 : 0; - - // check DMA is in busy mode. - WaitCnt = 0; - while (TxDmaBusy(pAd) || RxDmaBusy(pAd)) - { - RTMPusecDelay(10); - if (WaitCnt++ > 100) - break; - } - - //Why not to clear USB DMA TX path first ??? - RTMP_IO_READ32(pAd, USB_DMA_CFG, &UsbCfg.word); // disable DMA - UsbCfg.field.TxBulkEn = value; - UsbCfg.field.RxBulkEn = value; - RTMP_IO_WRITE32(pAd, USB_DMA_CFG, UsbCfg.word); // abort all TX rings - RTMPusecDelay(5000); - - return; -} -#endif // RT2870 // - -static VOID BbpSoftReset( - IN PRTMP_ADAPTER pAd) -{ - UCHAR BbpData = 0; - - // Soft reset, set BBP R21 bit0=1->0 - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R21, &BbpData); - BbpData |= 0x00000001; //set bit0=1 - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R21, BbpData); - - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R21, &BbpData); - BbpData &= ~(0x00000001); //set bit0=0 - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R21, BbpData); - - return; -} - -static VOID RtmpRfIoWrite( - IN PRTMP_ADAPTER pAd) -{ - // Set RF value 1's set R3[bit2] = [0] - RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R1); - RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R2); - RTMP_RF_IO_WRITE32(pAd, (pAd->LatchRfRegs.R3 & (~0x04))); - RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R4); - - RTMPusecDelay(200); - - // Set RF value 2's set R3[bit2] = [1] - RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R1); - RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R2); - RTMP_RF_IO_WRITE32(pAd, (pAd->LatchRfRegs.R3 | 0x04)); - RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R4); - - RTMPusecDelay(200); - - // Set RF value 3's set R3[bit2] = [0] - RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R1); - RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R2); - RTMP_RF_IO_WRITE32(pAd, (pAd->LatchRfRegs.R3 & (~0x04))); - RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R4); - - return; -} - -static int CheckMCSValid( - UCHAR Mode, - UCHAR Mcs) -{ - int i; - PCHAR pRateTab; - - switch(Mode) - { - case 0: - pRateTab = CCKRateTable; - break; - case 1: - pRateTab = OFDMRateTable; - break; - case 2: - case 3: - pRateTab = HTMIXRateTable; - break; - default: - ATEDBGPRINT(RT_DEBUG_ERROR, ("unrecognizable Tx Mode %d\n", Mode)); - return -1; - break; - } - - i = 0; - while(pRateTab[i] != -1) - { - if (pRateTab[i] == Mcs) - return 0; - i++; - } - - return -1; -} - -#if 1 -static INT ATETxPwrHandler( - IN PRTMP_ADAPTER pAd, - IN char index) -{ - ULONG R; - CHAR TxPower; - UCHAR Bbp94 = 0; - BOOLEAN bPowerReduce = FALSE; - -#ifdef RALINK_28xx_QA - if ((pAd->ate.bQATxStart == TRUE) || (pAd->ate.bQARxStart == TRUE)) - { - /* When QA is used for Tx, pAd->ate.TxPower0/1 and real tx power - ** are not synchronized. - */ -/* - pAd->ate.TxPower0 = pAd->LatchRfRegs.xxx; - pAd->ate.TxPower1 = pAd->LatchRfRegs.xxx; -*/ - return 0; - } - else -#endif // RALINK_28xx_QA // - { - TxPower = index == 0 ? pAd->ate.TxPower0 : pAd->ate.TxPower1; - - if (pAd->ate.Channel <= 14) - { - if (TxPower > 31) - { - // - // R3, R4 can't large than 31 (0x24), 31 ~ 36 used by BBP 94 - // - R = 31; - if (TxPower <= 36) - Bbp94 = BBPR94_DEFAULT + (UCHAR)(TxPower - 31); - } - else if (TxPower < 0) - { - // - // R3, R4 can't less than 0, -1 ~ -6 used by BBP 94 - // - R = 0; - if (TxPower >= -6) - Bbp94 = BBPR94_DEFAULT + TxPower; - } - else - { - // 0 ~ 31 - R = (ULONG) TxPower; - Bbp94 = BBPR94_DEFAULT; - } - - ATEDBGPRINT(RT_DEBUG_TRACE, ("%s (TxPower=%d, R=%ld, BBP_R94=%d)\n", __func__, TxPower, R, Bbp94)); - } - else// 5.5 GHz - { - if (TxPower > 15) - { - // - // R3, R4 can't large than 15 (0x0F) - // - R = 15; - } - else if (TxPower < 0) - { - // - // R3, R4 can't less than 0 - // - // -1 ~ -7 - ASSERT((TxPower >= -7)); - R = (ULONG)(TxPower + 7); - bPowerReduce = TRUE; - } - else - { - // 0 ~ 15 - R = (ULONG) TxPower; - } - - ATEDBGPRINT(RT_DEBUG_TRACE, ("%s (TxPower=%d, R=%lu)\n", __func__, TxPower, R)); - } - - if (pAd->ate.Channel <= 14) - { - if (index == 0) - { - R = R << 9; // shift TX power control to correct RF(R3) register bit position - R |= (pAd->LatchRfRegs.R3 & 0xffffc1ff); - pAd->LatchRfRegs.R3 = R; - } - else - { - R = R << 6; // shift TX power control to correct RF(R4) register bit position - R |= (pAd->LatchRfRegs.R4 & 0xfffff83f); - pAd->LatchRfRegs.R4 = R; - } - } - else// 5.5GHz - { - if (bPowerReduce == FALSE) - { - if (index == 0) - { - R = (R << 10) | (1 << 9); // shift TX power control to correct RF(R3) register bit position - R |= (pAd->LatchRfRegs.R3 & 0xffffc1ff); - pAd->LatchRfRegs.R3 = R; - } - else - { - R = (R << 7) | (1 << 6); // shift TX power control to correct RF(R4) register bit position - R |= (pAd->LatchRfRegs.R4 & 0xfffff83f); - pAd->LatchRfRegs.R4 = R; - } - } - else - { - if (index == 0) - { - R = (R << 10); // shift TX power control to correct RF(R3) register bit position - R |= (pAd->LatchRfRegs.R3 & 0xffffc1ff); - - /* Clear bit 9 of R3 to reduce 7dB. */ - pAd->LatchRfRegs.R3 = (R & (~(1 << 9))); - } - else - { - R = (R << 7); // shift TX power control to correct RF(R4) register bit position - R |= (pAd->LatchRfRegs.R4 & 0xfffff83f); - - /* Clear bit 6 of R4 to reduce 7dB. */ - pAd->LatchRfRegs.R4 = (R & (~(1 << 6))); - } - } - } - - RtmpRfIoWrite(pAd); - - return 0; - } -} -#else// 1 // -static INT ATETxPwrHandler( - IN PRTMP_ADAPTER pAd, - IN char index) -{ - ULONG R; - CHAR TxPower; - UCHAR Bbp94 = 0; - -#ifdef RALINK_28xx_QA - if ((pAd->ate.bQATxStart == TRUE) || (pAd->ate.bQARxStart == TRUE)) - { - // TODO: how to get current TxPower0/1 from pAd->LatchRfRegs ? - /* When QA is used for Tx, pAd->ate.TxPower0/1 and real tx power - ** are not synchronized. - */ -/* - pAd->ate.TxPower0 = pAd->LatchRfRegs.xxx; - pAd->ate.TxPower1 = pAd->LatchRfRegs.xxx; -*/ - return 0; - } - else -#endif // RALINK_28xx_QA // - { - TxPower = index == 0 ? pAd->ate.TxPower0 : pAd->ate.TxPower1; - - if (TxPower > 31) - { - // - // R3, R4 can't large than 36 (0x24), 31 ~ 36 used by BBP 94 - // - R = 31; - if (TxPower <= 36) - Bbp94 = BBPR94_DEFAULT + (UCHAR)(TxPower - 31); - } - else if (TxPower < 0) - { - // - // R3, R4 can't less than 0, -1 ~ -6 used by BBP 94 - // - R = 0; - if (TxPower >= -6) - Bbp94 = BBPR94_DEFAULT + TxPower; - } - else - { - // 0 ~ 31 - R = (ULONG) TxPower; - Bbp94 = BBPR94_DEFAULT; - } - - ATEDBGPRINT(RT_DEBUG_TRACE, ("%s (TxPower=%d, R3=%ld, BBP_R94=%d)\n", __func__, TxPower, R, Bbp94)); - - if (pAd->ate.Channel <= 14) - { - if (index == 0) - { - R = R << 9; // shift TX power control to correct RF(R3) register bit position - R |= (pAd->LatchRfRegs.R3 & 0xffffc1ff); - pAd->LatchRfRegs.R3 = R; - } - else - { - R = R << 6; // shift TX power control to correct RF(R4) register bit position - R |= (pAd->LatchRfRegs.R4 & 0xfffff83f); - pAd->LatchRfRegs.R4 = R; - } - } - else - { - if (index == 0) - { - R = (R << 10) | (1 << 9); // shift TX power control to correct RF(R3) register bit position - R |= (pAd->LatchRfRegs.R3 & 0xffffc1ff); - pAd->LatchRfRegs.R3 = R; - } - else - { - R = (R << 7) | (1 << 6); // shift TX power control to correct RF(R4) register bit position - R |= (pAd->LatchRfRegs.R4 & 0xfffff83f); - pAd->LatchRfRegs.R4 = R; - } - } - - RtmpRfIoWrite(pAd); - - return 0; - } -} -#endif // 1 // -/* - ========================================================================== - Description: - Set ATE operation mode to - 0. ATESTART = Start ATE Mode - 1. ATESTOP = Stop ATE Mode - 2. TXCONT = Continuous Transmit - 3. TXCARR = Transmit Carrier - 4. TXFRAME = Transmit Frames - 5. RXFRAME = Receive Frames -#ifdef RALINK_28xx_QA - 6. TXSTOP = Stop Any Type of Transmition - 7. RXSTOP = Stop Receiving Frames -#endif // RALINK_28xx_QA // - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -/* */ -/* */ -/*=======================End of RT2860=======================*/ - - -/*======================Start of RT2870======================*/ -/* */ -/* */ - -#ifdef RT2870 -static INT ATECmdHandler( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - UINT32 Value; - UCHAR BbpData; - UINT32 MacData; - UINT i=0, atemode; - //NDIS_STATUS Status = NDIS_STATUS_SUCCESS; - //PUCHAR pDest; - UINT32 temp; - ULONG IrqFlags; - - ATEDBGPRINT(RT_DEBUG_TRACE, ("===> ATECmdHandler()\n")); - ATEAsicSwitchChannel(pAd); - /* AsicLockChannel() is empty function so far in fact */ - AsicLockChannel(pAd, pAd->ate.Channel); - - RTMPusecDelay(5000); - - // Default value in BBP R22 is 0x0. - BbpData = 0; - - /* Enter ATE mode and set Tx/Rx Idle */ - if (!strcmp(arg, "ATESTART")) - { -#ifdef CONFIG_STA_SUPPORT - BOOLEAN Cancelled; -#endif // CONFIG_STA_SUPPORT // - ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE: ATESTART\n")); - - netif_stop_queue(pAd->net_dev); - - atemode = pAd->ate.Mode; - pAd->ate.Mode = ATE_START; -// pAd->ate.TxDoneCount = pAd->ate.TxCount; - // Disable Rx - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value &= ~(1 << 3); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - - // Disable auto responder - RTMP_IO_READ32(pAd, AUTO_RSP_CFG, &temp); - temp = temp & 0xFFFFFFFE; - RTMP_IO_WRITE32(pAd, AUTO_RSP_CFG, temp); - - // read MAC_SYS_CTRL and backup MAC_SYS_CTRL value. - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &MacData); - // clean bit4 to stop continuous Tx production test. - MacData &= 0xFFFFFFEF; - // Stop continuous TX production test. - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, MacData);//disable or cancel pending irp first ??? - - if (atemode & ATE_TXCARR) - { - // No Carrier Test set BBP R22 bit7=0, bit6=0, bit[5~0]=0x0 - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R22, &BbpData); - BbpData &= 0xFFFFFF00; //clear bit7, bit6, bit[5~0] - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); - } - else if (atemode & ATE_TXCARRSUPP) - { - // No Cont. TX set BBP R22 bit7=0 - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R22, &BbpData); - BbpData &= ~(1 << 7); //set bit7=0 - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); - - // No Carrier Suppression set BBP R24 bit0=0 - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R24, &BbpData); - BbpData &= 0xFFFFFFFE; //clear bit0 - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R24, BbpData); - } - // We should free some resource which allocate when ATE_TXFRAME , ATE_STOP, and ATE_TXCONT. - // TODO:Should we free some resource which was allocated when LoopBack and ATE_STOP ? - else if ((atemode & ATE_TXFRAME) || (atemode == ATE_STOP)) - { - if (atemode & ATE_TXCONT) - { - // Not Cont. TX anymore, so set BBP R22 bit7=0 - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R22, &BbpData); - BbpData &= ~(1 << 7); //set bit7=0 - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); - } - // Abort Tx, Rx DMA. - RtmpDmaEnable(pAd, 0); - - { - // It seems nothing to free, - // because we didn't allocate any resource when we entered ATE_TXFRAME mode latestly. - } - - // Start Tx, RX DMA - RtmpDmaEnable(pAd, 1); - } - - RTUSBRejectPendingPackets(pAd); - RTUSBCleanUpDataBulkOutQueue(pAd); - -#ifdef CONFIG_STA_SUPPORT - // - // It will be called in MlmeSuspend(). - // - // Cancel pending timers - RTMPCancelTimer(&pAd->MlmeAux.AssocTimer, &Cancelled); - RTMPCancelTimer(&pAd->MlmeAux.ReassocTimer, &Cancelled); - RTMPCancelTimer(&pAd->MlmeAux.DisassocTimer, &Cancelled); - RTMPCancelTimer(&pAd->MlmeAux.AuthTimer, &Cancelled); - RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer, &Cancelled); - RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &Cancelled); -#endif // CONFIG_STA_SUPPORT // - - //RTUSBCleanUpMLMEWaitQueue(pAd); /* not used in RT28xx */ - RTUSBCleanUpMLMEBulkOutQueue(pAd); - - // Sometimes kernel will hang on, so we avoid calling MlmeSuspend(). -// MlmeSuspend(pAd, TRUE); - //RTMPCancelTimer(&pAd->Mlme.PeriodicTimer, &Cancelled); - - // Disable Rx - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value &= ~(1 << 3); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - - // Abort Tx, RX DMA. - RtmpDmaEnable(pAd, 0); - - // Disable Tx - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value &= ~(1 << 2); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - - // Make sure there are no pending bulk in/out IRPs before we go on. -/*=========================================================================*/ - /* pAd->PendingRx is not of type atomic_t anymore in 28xx */ -// while ((atomic_read(&pAd->PendingRx) > 0)) //pAd->BulkFlags != 0 wait bulk out finish - while ((pAd->PendingRx > 0)) //pAd->BulkFlags != 0 wait bulk out finish - { -#if 1 - ATE_RTUSBCancelPendingBulkInIRP(pAd); -#else - NdisInterlockedDecrement(&pAd->PendingRx); -#endif - /* delay 0.5 seconds */ - RTMPusecDelay(500000); - pAd->PendingRx = 0; - } - /* peter : why don't we have to get BulkOutLock first ? */ - while (((pAd->BulkOutPending[0] == TRUE) || - (pAd->BulkOutPending[1] == TRUE) || - (pAd->BulkOutPending[2] == TRUE) || - (pAd->BulkOutPending[3] == TRUE)) && (pAd->BulkFlags != 0)) //pAd->BulkFlags != 0 wait bulk out finish - { - do - { - /* pAd->BulkOutPending[y] will be set to FALSE in RTUSBCancelPendingBulkOutIRP(pAd) */ - RTUSBCancelPendingBulkOutIRP(pAd); - } while (FALSE); - - /* we have enough time delay in RTUSBCancelPendingBulkOutIRP(pAd) - ** so this is not necessary - */ -// RTMPusecDelay(500000); - } - - /* pAd->PendingRx is not of type atomic_t anymore in 28xx */ -// ASSERT(atomic_read(&pAd->PendingRx) == 0); - ASSERT(pAd->PendingRx == 0); -/*=========================================================================*/ - - // reset Rx statistics. - pAd->ate.LastSNR0 = 0; - pAd->ate.LastSNR1 = 0; - pAd->ate.LastRssi0 = 0; - pAd->ate.LastRssi1 = 0; - pAd->ate.LastRssi2 = 0; - pAd->ate.AvgRssi0 = 0; - pAd->ate.AvgRssi1 = 0; - pAd->ate.AvgRssi2 = 0; - pAd->ate.AvgRssi0X8 = 0; - pAd->ate.AvgRssi1X8 = 0; - pAd->ate.AvgRssi2X8 = 0; - pAd->ate.NumOfAvgRssiSample = 0; - -#ifdef RALINK_28xx_QA - // Tx frame - pAd->ate.bQATxStart = FALSE; - pAd->ate.bQARxStart = FALSE; - pAd->ate.seq = 0; - - // counters - pAd->ate.U2M = 0; - pAd->ate.OtherData = 0; - pAd->ate.Beacon = 0; - pAd->ate.OtherCount = 0; - pAd->ate.TxAc0 = 0; - pAd->ate.TxAc1 = 0; - pAd->ate.TxAc2 = 0; - pAd->ate.TxAc3 = 0; - pAd->ate.TxHCCA = 0; - pAd->ate.TxMgmt = 0; - pAd->ate.RSSI0 = 0; - pAd->ate.RSSI1 = 0; - pAd->ate.RSSI2 = 0; - pAd->ate.SNR0 = 0; - pAd->ate.SNR1 = 0; - - // control - pAd->ate.TxDoneCount = 0; - pAd->ate.TxStatus = 0; // task Tx status // 0 --> task is idle, 1 --> task is running -#endif // RALINK_28xx_QA // - - // Soft reset BBP. - BbpSoftReset(pAd); - - -#ifdef CONFIG_STA_SUPPORT - AsicDisableSync(pAd); - - /* - ** If we skip "LinkDown()", we should disable protection - ** to prevent from sending out RTS or CTS-to-self. - */ - ATEDisableAsicProtect(pAd); - RTMPStationStop(pAd); -#endif // CONFIG_STA_SUPPORT // - - // Default value in BBP R22 is 0x0. - BbpData = 0; - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &MacData); - - // Clean bit4 to stop continuous Tx production test. - MacData &= 0xFFFFFFEF; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, MacData); - //Clean ATE Bulk in/out counter and continue setup - InterlockedExchange(&pAd->BulkOutRemained, 0); - - /* NdisAcquireSpinLock()/NdisReleaseSpinLock() need only one argument in RT28xx */ - NdisAcquireSpinLock(&pAd->GenericLock); - pAd->ContinBulkOut = FALSE; - pAd->ContinBulkIn = FALSE; - NdisReleaseSpinLock(&pAd->GenericLock); - - RTUSB_CLEAR_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_ATE); - } - else if (!strcmp(arg, "ATESTOP")) - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE : ATESTOP ===>\n")); - - // Default value in BBP R22 is 0x0. - BbpData = 0; - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &MacData);//0820 - // Clean bit4 to stop continuous Tx production test. - MacData &= 0xFFFFFFEF; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, MacData); // recover the MAC_SYS_CTRL register back. - - // Disable Rx - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value &= ~(1 << 3); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - - /* - ** Abort Tx, RX DMA. - ** Q : How to do the following I/O if Tx, Rx DMA is aborted ? - ** Ans : Bulk endpoints are aborted, while the control endpoint is not. - */ - RtmpDmaEnable(pAd, 0); - - // Disable Tx - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value &= ~(1 << 2); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - - /* Make sure there are no pending bulk in/out IRPs before we go on. */ -/*=========================================================================*/ -// while ((atomic_read(&pAd->PendingRx) > 0)) //pAd->BulkFlags != 0 wait bulk out finish - while (pAd->PendingRx > 0) - { -#if 1 - ATE_RTUSBCancelPendingBulkInIRP(pAd); -#else -// NdisInterlockedDecrement(&pAd->PendingRx); - pAd->PendingRx--; -#endif - RTMPusecDelay(500000); - } - - while (((pAd->BulkOutPending[0] == TRUE) || - (pAd->BulkOutPending[1] == TRUE) || - (pAd->BulkOutPending[2] == TRUE) || - (pAd->BulkOutPending[3] == TRUE)) && (pAd->BulkFlags != 0)) //pAd->BulkFlags != 0 wait bulk out finish - { - do - { - RTUSBCancelPendingBulkOutIRP(pAd); - } while (FALSE); - - RTMPusecDelay(500000); - } - -// ASSERT(atomic_read(&pAd->PendingRx) == 0); - ASSERT(pAd->PendingRx == 0); -/*=========================================================================*/ -/* Reset Rx RING */ -/*=========================================================================*/ -// InterlockedExchange(&pAd->PendingRx, 0); - pAd->PendingRx = 0; - pAd->NextRxBulkInReadIndex = 0; // Next Rx Read index - pAd->NextRxBulkInIndex = RX_RING_SIZE - 1; // Rx Bulk pointer - pAd->NextRxBulkInPosition = 0; - for (i = 0; i < (RX_RING_SIZE); i++) - { - PRX_CONTEXT pRxContext = &(pAd->RxContext[i]); - NdisZeroMemory(pRxContext->TransferBuffer, MAX_RXBULK_SIZE); - /* peter : why don't we have to get BulkInLock first ? */ - pRxContext->pAd = pAd; - pRxContext->pIrp = NULL; - /* peter debug ++ */ - pRxContext->BulkInOffset = 0; - pRxContext->bRxHandling = FALSE; - /* peter debug -- */ - pRxContext->InUse = FALSE; - pRxContext->IRPPending = FALSE; - pRxContext->Readable = FALSE; -// pRxContext->ReorderInUse = FALSE; -// pRxContext->ReadPosOffset = 0; - } - -/*=========================================================================*/ -/* Reset Tx RING */ -/*=========================================================================*/ - do - { - RTUSBCancelPendingBulkOutIRP(pAd); - } while (FALSE); - -/*=========================================================================*/ - // Enable auto responder. - RTMP_IO_READ32(pAd, AUTO_RSP_CFG, &temp); - temp = temp | (0x01); - RTMP_IO_WRITE32(pAd, AUTO_RSP_CFG, temp); - -/*================================================*/ - AsicEnableBssSync(pAd); - - /* Soft reset BBP.*/ - /* In 2870 chipset, ATE_BBP_IO_READ8_BY_REG_ID() == RTMP_BBP_IO_READ8_BY_REG_ID() */ - /* Both rt2870ap and rt2870sta use BbpSoftReset(pAd) to do BBP soft reset */ - BbpSoftReset(pAd); -/*================================================*/ - { -#ifdef CONFIG_STA_SUPPORT - // Set all state machines back IDLE - pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; - pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; - pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; - pAd->Mlme.AuthRspMachine.CurrState = AUTH_RSP_IDLE; - pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; - pAd->Mlme.ActMachine.CurrState = ACT_IDLE; -#endif // CONFIG_STA_SUPPORT // - - // - // ===> refer to MlmeRestartStateMachine(). - // When we entered ATE_START mode, PeriodicTimer was not cancelled. - // So we don't have to set it here. - // - //RTMPSetTimer(pAd, &pAd->Mlme.PeriodicTimer, MLME_TASK_EXEC_INTV); - - ASSERT(pAd->CommonCfg.Channel != 0); - - AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); - AsicLockChannel(pAd, pAd->CommonCfg.Channel); - - -#ifdef CONFIG_STA_SUPPORT - RTMPStationStart(pAd); -#endif // CONFIG_STA_SUPPORT // - } -// -// These two steps have been done when entering ATE_STOP mode. -// -#if 0 - RTUSBWriteBBPRegister(pAd, BBP_R22, BbpData); - RTUSBWriteMACRegister(pAd, MAC_SYS_CTRL, MacData); -#endif - // Clean ATE Bulk in/out counter and continue setup. - InterlockedExchange(&pAd->BulkOutRemained, 0); - NdisAcquireSpinLock(&pAd->GenericLock); - pAd->ContinBulkOut = FALSE; - pAd->ContinBulkIn = FALSE; - NdisReleaseSpinLock(&pAd->GenericLock); - - /* Wait 50ms to prevent next URB to bulkout during HW reset. */ - /* todo : remove this if not necessary */ - NdisMSleep(50000); - - pAd->ate.Mode = ATE_STOP; - - // Enable Tx - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value |= (1 << 2); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - -/*=========================================================================*/ - /* restore RX_FILTR_CFG */ -#ifdef CONFIG_STA_SUPPORT - /* restore RX_FILTR_CFG in order that QA maybe set it to 0x3 */ - RTMP_IO_WRITE32(pAd, RX_FILTR_CFG, STANORMAL); -#endif // CONFIG_STA_SUPPORT // -/*=========================================================================*/ - - // Enable Tx, RX DMA. - RtmpDmaEnable(pAd, 1); - - // Enable Rx - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value |= (1 << 3); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - - // Wait 10ms to wait all of the bulk-in URBs to complete. - /* todo : remove this if not necessary */ - NdisMSleep(10000); - - // Everything is ready to start normal Tx/Rx. - RTUSBBulkReceive(pAd); - netif_start_queue(pAd->net_dev); - - ATEDBGPRINT(RT_DEBUG_TRACE, ("<=== ATE : ATESTOP \n")); - } - else if (!strcmp(arg, "TXCARR")) // Tx Carrier - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE: TXCARR\n")); - pAd->ate.Mode |= ATE_TXCARR; - - // Disable Rx - // May be we need not to do this, because these have been done in ATE_START mode ??? - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value &= ~(1 << 3); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - - // QA has done the following steps if it is used. - if (pAd->ate.bQATxStart == FALSE) - { - // Soft reset BBP. - BbpSoftReset(pAd); - - // Carrier Test set BBP R22 bit7=1, bit6=1, bit[5~0]=0x01 - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R22, &BbpData); - BbpData &= 0xFFFFFF00; //clear bit7, bit6, bit[5~0] - BbpData |= 0x000000C1; //set bit7=1, bit6=1, bit[5~0]=0x01 - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); - - // set MAC_SYS_CTRL(0x1004) Continuous Tx Production Test (bit4) = 1 - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value = Value | 0x00000010; - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - } - } - else if (!strcmp(arg, "TXCONT")) // Tx Continue - { - if (pAd->ate.bQATxStart == TRUE) - { - /* set MAC_SYS_CTRL(0x1004) bit4(Continuous Tx Production Test) - and bit2(MAC TX enable) back to zero. */ - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &MacData); - MacData &= 0xFFFFFFEB; - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, MacData); - - // set BBP R22 bit7=0 - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R22, &BbpData); - BbpData &= 0xFFFFFF7F; //set bit7=0 - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); - } - - /* for TxCont mode. - ** Step 1: Send 50 packets first then wait for a moment. - ** Step 2: Send more 50 packet then start continue mode. - */ - ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE: TXCONT\n")); - // Step 1: send 50 packets first. - pAd->ate.Mode |= ATE_TXCONT; - pAd->ate.TxCount = 50; - pAd->ate.TxDoneCount = 0; - - // Soft reset BBP. - BbpSoftReset(pAd); - - // Abort Tx, RX DMA. - RtmpDmaEnable(pAd, 0); - - - /* Only needed if we have to send some normal frames. */ - SetJapanFilter(pAd); - - // Setup frame format. - ATESetUpFrame(pAd, 0); - - // Enable Tx - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value |= (1 << 2); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - - // Disable Rx - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value &= ~(1 << 3); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - - // Start Tx, RX DMA. - RtmpDmaEnable(pAd, 1); - - InterlockedExchange(&pAd->BulkOutRemained, pAd->ate.TxCount); - -#ifdef RALINK_28xx_QA - if (pAd->ate.bQATxStart == TRUE) - { - pAd->ate.TxStatus = 1; - //pAd->ate.Repeat = 0; - } -#endif // RALINK_28xx_QA // - - NdisAcquireSpinLock(&pAd->GenericLock);//0820 - pAd->ContinBulkOut = FALSE; - NdisReleaseSpinLock(&pAd->GenericLock); - - RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_ATE); - - // Kick bulk out - RTUSBKickBulkOut(pAd); - - /* To make sure all the 50 frames have been bulk out before executing step 2 */ - while (atomic_read(&pAd->BulkOutRemained) > 0) - { - RTMPusecDelay(5000); - } - - // Step 2: send more 50 packets then start continue mode. - // Abort Tx, RX DMA. - RtmpDmaEnable(pAd, 0); - - // Cont. TX set BBP R22 bit7=1 - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R22, &BbpData); - BbpData |= 0x00000080; //set bit7=1 - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); - - pAd->ate.TxCount = 50; - pAd->ate.TxDoneCount = 0; - - SetJapanFilter(pAd); - - // Setup frame format. - ATESetUpFrame(pAd, 0); - - // Enable Tx - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value |= (1 << 2); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - - // Disable Rx - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value &= ~(1 << 3); - - // Start Tx, RX DMA. - RtmpDmaEnable(pAd, 1); - - InterlockedExchange(&pAd->BulkOutRemained, pAd->ate.TxCount); - -#ifdef RALINK_28xx_QA - if (pAd->ate.bQATxStart == TRUE) - { - pAd->ate.TxStatus = 1; - //pAd->ate.Repeat = 0; - } -#endif // RALINK_28xx_QA // - - NdisAcquireSpinLock(&pAd->GenericLock);//0820 - pAd->ContinBulkOut = FALSE; - NdisReleaseSpinLock(&pAd->GenericLock); - - RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_ATE); - // Kick bulk out - RTUSBKickBulkOut(pAd); - -#if 1 - RTMPusecDelay(500); -#else - while (atomic_read(&pAd->BulkOutRemained) > 0) - { - RTMPusecDelay(5000); - } -#endif // 1 // - - // Set MAC_SYS_CTRL(0x1004) Continuous Tx Production Test (bit4) = 1. - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &MacData); - MacData |= 0x00000010; - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, MacData); - } - else if (!strcmp(arg, "TXFRAME")) // Tx Frames - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE: TXFRAME(Count=0x%08x)\n", pAd->ate.TxCount)); - pAd->ate.Mode |= ATE_TXFRAME; - - // Soft reset BBP. - BbpSoftReset(pAd); - - // Default value in BBP R22 is 0x0. - BbpData = 0; - - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &MacData); - - // Clean bit4 to stop continuous Tx production test. - MacData &= 0xFFFFFFEF; - - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, MacData); - -#ifdef RALINK_28xx_QA - // add this for LoopBack mode - if (pAd->ate.bQARxStart == FALSE) - { - // Disable Rx - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value &= ~(1 << 3); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - } - - if (pAd->ate.bQATxStart == TRUE) - { - pAd->ate.TxStatus = 1; - //pAd->ate.Repeat = 0; - } -#else - // Disable Rx - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value &= ~(1 << 3); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); -#endif // RALINK_28xx_QA // - - // Enable Tx - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value |= (1 << 2); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - - SetJapanFilter(pAd); - - // Abort Tx, RX DMA. - RtmpDmaEnable(pAd, 0); - - pAd->ate.TxDoneCount = 0; - - // Setup frame format - ATESetUpFrame(pAd, 0); - - // Start Tx, RX DMA. - RtmpDmaEnable(pAd, 1); - - // Check count is continuous or not yet. - // - // Due to the type mismatch between "pAd->BulkOutRemained"(atomic_t) and "pAd->ate.TxCount"(UINT32) - // - if (pAd->ate.TxCount == 0) - { - InterlockedExchange(&pAd->BulkOutRemained, 0); - } - else - { - InterlockedExchange(&pAd->BulkOutRemained, pAd->ate.TxCount); - } - ATEDBGPRINT(RT_DEBUG_TRACE, ("bulk out count = %d\n", atomic_read(&pAd->BulkOutRemained))); - ASSERT((atomic_read(&pAd->BulkOutRemained) >= 0)); - - if (atomic_read(&pAd->BulkOutRemained) == 0) - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("Send packet countinuously\n")); - - /* In 28xx, NdisAcquireSpinLock() == spin_lock_bh() */ - /* NdisAcquireSpinLock only need one argument in 28xx. */ - NdisAcquireSpinLock(&pAd->GenericLock); - pAd->ContinBulkOut = TRUE; - NdisReleaseSpinLock(&pAd->GenericLock); - - /* In 28xx, BULK_OUT_LOCK() == spin_lock_irqsave() */ - BULK_OUT_LOCK(&pAd->BulkOutLock[0], IrqFlags);// peter : NdisAcquireSpinLock ==> BULK_OUT_LOCK - pAd->BulkOutPending[0] = FALSE; - BULK_OUT_UNLOCK(&pAd->BulkOutLock[0], IrqFlags);// peter : NdisAcquireSpinLock ==> BULK_OUT_LOCK - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("Send packets depend on counter\n")); - - NdisAcquireSpinLock(&pAd->GenericLock); - pAd->ContinBulkOut = FALSE; - NdisReleaseSpinLock(&pAd->GenericLock); - - BULK_OUT_LOCK(&pAd->BulkOutLock[0], IrqFlags); - pAd->BulkOutPending[0] = FALSE; - BULK_OUT_UNLOCK(&pAd->BulkOutLock[0], IrqFlags); - } - - RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_ATE); - - // Kick bulk out - RTUSBKickBulkOut(pAd); - } -#ifdef RALINK_28xx_QA - else if (!strcmp(arg, "TXSTOP")) //Enter ATE mode and set Tx/Rx Idle - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE: TXSTOP\n")); - - atemode = pAd->ate.Mode; - pAd->ate.Mode &= ATE_TXSTOP; - pAd->ate.bQATxStart = FALSE; -// pAd->ate.TxDoneCount = pAd->ate.TxCount; - -/*=========================================================================*/ - if (atemode & ATE_TXCARR) - { - // No Carrier Test set BBP R22 bit7=0, bit6=0, bit[5~0]=0x0 - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R22, &BbpData); - BbpData &= 0xFFFFFF00; //clear bit7, bit6, bit[5~0] - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); - } - else if (atemode & ATE_TXCARRSUPP) - { - // No Cont. TX set BBP R22 bit7=0 - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R22, &BbpData); - BbpData &= ~(1 << 7); //set bit7=0 - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); - - // No Carrier Suppression set BBP R24 bit0=0 - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R24, &BbpData); - BbpData &= 0xFFFFFFFE; //clear bit0 - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R24, BbpData); - } - else if ((atemode & ATE_TXFRAME) || (atemode == ATE_STOP)) - { - if (atemode & ATE_TXCONT) - { - // No Cont. TX set BBP R22 bit7=0 - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R22, &BbpData); - BbpData &= ~(1 << 7); //set bit7=0 - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); - } - } - -/*=========================================================================*/ - RTUSBRejectPendingPackets(pAd); - RTUSBCleanUpDataBulkOutQueue(pAd); - - /* not used in RT28xx */ - //RTUSBCleanUpMLMEWaitQueue(pAd); - /* empty function so far */ - RTUSBCleanUpMLMEBulkOutQueue(pAd); -/*=========================================================================*/ - // Abort Tx, RX DMA. - RtmpDmaEnable(pAd, 0); -/*=========================================================================*/ - - /* In 28xx, pAd->PendingRx is not of type atomic_t anymore */ -// while ((atomic_read(&pAd->PendingRx) > 0)) //pAd->BulkFlags != 0 wait bulk out finish - /* peter todo : BulkInLock */ - while (pAd->PendingRx > 0) - { -#if 1 - ATE_RTUSBCancelPendingBulkInIRP(pAd); -#else -// NdisInterlockedDecrement(&pAd->PendingRx); - pAd->PendingRx--; -#endif - RTMPusecDelay(500000); - } - - while (((pAd->BulkOutPending[0] == TRUE) || - (pAd->BulkOutPending[1] == TRUE) || - (pAd->BulkOutPending[2] == TRUE) || - (pAd->BulkOutPending[3] == TRUE)) && (pAd->BulkFlags != 0)) //pAd->BulkFlags != 0 wait bulk out finish - { - do - { - RTUSBCancelPendingBulkOutIRP(pAd); - } while (FALSE); - - RTMPusecDelay(500000); - } - - ASSERT(pAd->PendingRx == 0); -/*=========================================================================*/ - // Enable Tx, Rx DMA. - RtmpDmaEnable(pAd, 1); - - /* task Tx status : 0 --> task is idle, 1 --> task is running */ - pAd->ate.TxStatus = 0; - - // Soft reset BBP. - BbpSoftReset(pAd); - - // Disable Tx - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &MacData); - MacData &= (0xfffffffb); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, MacData); - - //Clean ATE Bulk in/out counter and continue setup - InterlockedExchange(&pAd->BulkOutRemained, 0); - - pAd->ContinBulkOut = FALSE; - } - else if (!strcmp(arg, "RXSTOP")) - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE: RXSTOP\n")); - atemode = pAd->ate.Mode; - - // Disable Rx - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value &= ~(1 << 3); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - - pAd->ate.Mode &= ATE_RXSTOP; - pAd->ate.bQARxStart = FALSE; -// pAd->ate.TxDoneCount = pAd->ate.TxCount; - -/*=========================================================================*/ - RTUSBRejectPendingPackets(pAd); - RTUSBCleanUpDataBulkOutQueue(pAd); - - /* not used in RT28xx */ - //RTUSBCleanUpMLMEWaitQueue(pAd); - RTUSBCleanUpMLMEBulkOutQueue(pAd); -/*=========================================================================*/ - - // Abort Tx, RX DMA. - RtmpDmaEnable(pAd, 0); -/*=========================================================================*/ -// while ((atomic_read(&pAd->PendingRx) > 0)) - while (pAd->PendingRx > 0) - { -#if 1 - ATE_RTUSBCancelPendingBulkInIRP(pAd); -#else -// NdisInterlockedDecrement(&pAd->PendingRx); - pAd->PendingRx--; -#endif - RTMPusecDelay(500000); - } - - while (((pAd->BulkOutPending[0] == TRUE) || - (pAd->BulkOutPending[1] == TRUE) || - (pAd->BulkOutPending[2] == TRUE) || - (pAd->BulkOutPending[3] == TRUE)) && (pAd->BulkFlags != 0)) //pAd->BulkFlags != 0 wait bulk out finish - { - do - { - RTUSBCancelPendingBulkOutIRP(pAd); - } while (FALSE); - - RTMPusecDelay(500000); - } - - ASSERT(pAd->PendingRx == 0); -/*=========================================================================*/ - - // Soft reset BBP. - BbpSoftReset(pAd); - pAd->ContinBulkIn = FALSE; - } -#endif // RALINK_28xx_QA // - else if (!strcmp(arg, "RXFRAME")) // Rx Frames - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE: RXFRAME\n")); - - // Disable Rx of MAC block - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value &= ~(1 << 3); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - - // Default value in BBP R22 is 0x0. - BbpData = 0; - - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &MacData); - // Clean bit4 to stop continuous Tx production test. - MacData &= 0xFFFFFFEF; - - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, MacData); - - pAd->ate.Mode |= ATE_RXFRAME; - - // Abort Tx, RX DMA. - RtmpDmaEnable(pAd, 0); - - // Disable TX of MAC block - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value &= ~(1 << 2); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - - // Reset Rx RING. - for ( i = 0; i < (RX_RING_SIZE); i++) - { - PRX_CONTEXT pRxContext = &(pAd->RxContext[i]); - - pRxContext->InUse = FALSE; - pRxContext->IRPPending = FALSE; - pRxContext->Readable = FALSE; - - // - // Get the urb from kernel back to driver. - // - RTUSB_UNLINK_URB(pRxContext->pUrb); - - /* Sleep 200 microsecs to give cancellation time to work. */ - NdisMSleep(200); - pAd->BulkInReq = 0; - -// InterlockedExchange(&pAd->PendingRx, 0); - pAd->PendingRx = 0; - pAd->NextRxBulkInReadIndex = 0; // Next Rx Read index - pAd->NextRxBulkInIndex = RX_RING_SIZE - 1; // Rx Bulk pointer - pAd->NextRxBulkInPosition = 0; - } - - // read to clear counters - RTUSBReadMACRegister(pAd, RX_STA_CNT0, &temp); //RX PHY & RX CRC count - RTUSBReadMACRegister(pAd, RX_STA_CNT1, &temp); //RX PLCP error count & CCA false alarm count - RTUSBReadMACRegister(pAd, RX_STA_CNT2, &temp); //RX FIFO overflow frame count & RX duplicated filtered frame count - - pAd->ContinBulkIn = TRUE; - - // Enable Tx, RX DMA. - RtmpDmaEnable(pAd, 1); - - // Enable RX of MAC block - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value |= (1 << 3); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - - // Kick bulk in - RTUSBBulkReceive(pAd); - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE: Invalid arg!\n")); - return FALSE; - } - RTMPusecDelay(5000); - - ATEDBGPRINT(RT_DEBUG_TRACE, ("<=== ATECmdHandler()\n")); - - return TRUE; -} -#endif // RT2870 // - -INT Set_ATE_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - if (ATECmdHandler(pAd, arg)) - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_Proc Success\n")); - - - return TRUE; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_Proc Failed\n")); - return FALSE; - } -} - -/* - ========================================================================== - Description: - Set ATE ADDR1=DA for TxFrame(AP : To DS = 0 ; From DS = 1) - or - Set ATE ADDR3=DA for TxFrame(STA : To DS = 1 ; From DS = 0) - - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_ATE_DA_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - CHAR *value; - INT i; - - if(strlen(arg) != 17) //Mac address acceptable format 01:02:03:04:05:06 length 17 - return FALSE; - - for (i=0, value = rstrtok(arg, ":"); value; value = rstrtok(NULL, ":")) - { - if((strlen(value) != 2) || (!isxdigit(*value)) || (!isxdigit(*(value+1))) ) - return FALSE; //Invalid - - -#ifdef CONFIG_STA_SUPPORT - AtoH(value, &pAd->ate.Addr3[i++], 1); -#endif // CONFIG_STA_SUPPORT // - } - - if(i != 6) - return FALSE; //Invalid - - -#ifdef CONFIG_STA_SUPPORT - ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_DA_Proc (DA = %2X:%2X:%2X:%2X:%2X:%2X)\n", pAd->ate.Addr3[0], - pAd->ate.Addr3[1], pAd->ate.Addr3[2], pAd->ate.Addr3[3], pAd->ate.Addr3[4], pAd->ate.Addr3[5])); -#endif // CONFIG_STA_SUPPORT // - - ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_DA_Proc Success\n")); - - return TRUE; -} - -/* - ========================================================================== - Description: - Set ATE ADDR3=SA for TxFrame(AP : To DS = 0 ; From DS = 1) - or - Set ATE ADDR2=SA for TxFrame(STA : To DS = 1 ; From DS = 0) - - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_ATE_SA_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - CHAR *value; - INT i; - - if(strlen(arg) != 17) //Mac address acceptable format 01:02:03:04:05:06 length 17 - return FALSE; - - for (i=0, value = rstrtok(arg, ":"); value; value = rstrtok(NULL, ":")) - { - if((strlen(value) != 2) || (!isxdigit(*value)) || (!isxdigit(*(value+1))) ) - return FALSE; //Invalid - - -#ifdef CONFIG_STA_SUPPORT - AtoH(value, &pAd->ate.Addr2[i++], 1); -#endif // CONFIG_STA_SUPPORT // - } - - if(i != 6) - return FALSE; //Invalid - - -#ifdef CONFIG_STA_SUPPORT - ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_SA_Proc (SA = %2X:%2X:%2X:%2X:%2X:%2X)\n", pAd->ate.Addr2[0], - pAd->ate.Addr2[1], pAd->ate.Addr2[2], pAd->ate.Addr2[3], pAd->ate.Addr2[4], pAd->ate.Addr2[5])); -#endif // CONFIG_STA_SUPPORT // - - ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_SA_Proc Success\n")); - - return TRUE; -} - -/* - ========================================================================== - Description: - Set ATE ADDR2=BSSID for TxFrame(AP : To DS = 0 ; From DS = 1) - or - Set ATE ADDR1=BSSID for TxFrame(STA : To DS = 1 ; From DS = 0) - - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_ATE_BSSID_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - CHAR *value; - INT i; - - if(strlen(arg) != 17) //Mac address acceptable format 01:02:03:04:05:06 length 17 - return FALSE; - - for (i=0, value = rstrtok(arg, ":"); value; value = rstrtok(NULL, ":")) - { - if((strlen(value) != 2) || (!isxdigit(*value)) || (!isxdigit(*(value+1))) ) - return FALSE; //Invalid - - -#ifdef CONFIG_STA_SUPPORT - AtoH(value, &pAd->ate.Addr1[i++], 1); -#endif // CONFIG_STA_SUPPORT // - } - - if(i != 6) - return FALSE; //Invalid - - -#ifdef CONFIG_STA_SUPPORT - ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_BSSID_Proc (BSSID = %2X:%2X:%2X:%2X:%2X:%2X)\n", pAd->ate.Addr1[0], - pAd->ate.Addr1[1], pAd->ate.Addr1[2], pAd->ate.Addr1[3], pAd->ate.Addr1[4], pAd->ate.Addr1[5])); -#endif // CONFIG_STA_SUPPORT // - - ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_BSSID_Proc Success\n")); - - return TRUE; -} - -/* - ========================================================================== - Description: - Set ATE Tx Channel - - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_ATE_CHANNEL_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - UCHAR channel; - - channel = simple_strtol(arg, 0, 10); - - if ((channel < 1) || (channel > 216))// to allow A band channel : ((channel < 1) || (channel > 14)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_CHANNEL_Proc::Out of range, it should be in range of 1~14.\n")); - return FALSE; - } - pAd->ate.Channel = channel; - - ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_CHANNEL_Proc (ATE Channel = %d)\n", pAd->ate.Channel)); - ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_CHANNEL_Proc Success\n")); - - - return TRUE; -} - -/* - ========================================================================== - Description: - Set ATE Tx Power0 - - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_ATE_TX_POWER0_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - CHAR TxPower; - - TxPower = simple_strtol(arg, 0, 10); - - if (pAd->ate.Channel <= 14) - { - if ((TxPower > 31) || (TxPower < 0)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_POWER0_Proc::Out of range (Value=%d)\n", TxPower)); - return FALSE; - } - } - else// 5.5GHz - { - if ((TxPower > 15) || (TxPower < -7)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_POWER0_Proc::Out of range (Value=%d)\n", TxPower)); - return FALSE; - } - } - - pAd->ate.TxPower0 = TxPower; - ATETxPwrHandler(pAd, 0); - ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_POWER0_Proc Success\n")); - - - return TRUE; -} - -/* - ========================================================================== - Description: - Set ATE Tx Power1 - - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_ATE_TX_POWER1_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - CHAR TxPower; - - TxPower = simple_strtol(arg, 0, 10); - - if (pAd->ate.Channel <= 14) - { - if ((TxPower > 31) || (TxPower < 0)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_POWER1_Proc::Out of range (Value=%d)\n", TxPower)); - return FALSE; - } - } - else - { - if ((TxPower > 15) || (TxPower < -7)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_POWER1_Proc::Out of range (Value=%d)\n", TxPower)); - return FALSE; - } - } - - pAd->ate.TxPower1 = TxPower; - ATETxPwrHandler(pAd, 1); - ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_POWER1_Proc Success\n")); - - - return TRUE; -} - -/* - ========================================================================== - Description: - Set ATE Tx Antenna - - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_ATE_TX_Antenna_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - CHAR value; - - value = simple_strtol(arg, 0, 10); - - if ((value > 2) || (value < 0)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_Antenna_Proc::Out of range (Value=%d)\n", value)); - return FALSE; - } - - pAd->ate.TxAntennaSel = value; - - ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_TX_Antenna_Proc (Antenna = %d)\n", pAd->ate.TxAntennaSel)); - ATEDBGPRINT(RT_DEBUG_TRACE,("Ralink: Set_ATE_TX_Antenna_Proc Success\n")); - - - return TRUE; -} - -/* - ========================================================================== - Description: - Set ATE Rx Antenna - - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_ATE_RX_Antenna_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - CHAR value; - - value = simple_strtol(arg, 0, 10); - - if ((value > 3) || (value < 0)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_RX_Antenna_Proc::Out of range (Value=%d)\n", value)); - return FALSE; - } - - pAd->ate.RxAntennaSel = value; - - ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_RX_Antenna_Proc (Antenna = %d)\n", pAd->ate.RxAntennaSel)); - ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_RX_Antenna_Proc Success\n")); - - - return TRUE; -} - -/* - ========================================================================== - Description: - Set ATE RF frequence offset - - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_ATE_TX_FREQOFFSET_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - UCHAR RFFreqOffset; - ULONG R4; - - RFFreqOffset = simple_strtol(arg, 0, 10); - - if(RFFreqOffset >= 64) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_FREQOFFSET_Proc::Out of range, it should be in range of 0~63.\n")); - return FALSE; - } - - pAd->ate.RFFreqOffset = RFFreqOffset; - R4 = pAd->ate.RFFreqOffset << 15; // shift TX power control to correct RF register bit position - R4 |= (pAd->LatchRfRegs.R4 & ((~0x001f8000))); - pAd->LatchRfRegs.R4 = R4; - - RtmpRfIoWrite(pAd); - - ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_TX_FREQOFFSET_Proc (RFFreqOffset = %d)\n", pAd->ate.RFFreqOffset)); - ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_FREQOFFSET_Proc Success\n")); - - - return TRUE; -} - -/* - ========================================================================== - Description: - Set ATE RF BW - - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_ATE_TX_BW_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - int i; - UCHAR value = 0; - UCHAR BBPCurrentBW; - - BBPCurrentBW = simple_strtol(arg, 0, 10); - - if(BBPCurrentBW == 0) - pAd->ate.TxWI.BW = BW_20; - else - pAd->ate.TxWI.BW = BW_40; - - if(pAd->ate.TxWI.BW == BW_20) - { - if(pAd->ate.Channel <= 14) - { - for (i=0; i<5; i++) - { - if (pAd->Tx20MPwrCfgGBand[i] != 0xffffffff) - { - RTMP_IO_WRITE32(pAd, TX_PWR_CFG_0 + i*4, pAd->Tx20MPwrCfgGBand[i]); - RTMPusecDelay(5000); - } - } - } - else - { - for (i=0; i<5; i++) - { - if (pAd->Tx20MPwrCfgABand[i] != 0xffffffff) - { - RTMP_IO_WRITE32(pAd, TX_PWR_CFG_0 + i*4, pAd->Tx20MPwrCfgABand[i]); - RTMPusecDelay(5000); - } - } - } - - //Set BBP R4 bit[4:3]=0:0 - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &value); - value &= (~0x18); - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, value); - - //Set BBP R66=0x3C - value = 0x3C; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, value); - //Set BBP R68=0x0B - //to improve Rx sensitivity. - value = 0x0B; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R68, value); - //Set BBP R69=0x16 - value = 0x16; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, value); - //Set BBP R70=0x08 - value = 0x08; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, value); - //Set BBP R73=0x11 - value = 0x11; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R73, value); - - // If Channel=14, Bandwidth=20M and Mode=CCK, Set BBP R4 bit5=1 - // (Japan filter coefficients) - // This segment of code will only works when ATETXMODE and ATECHANNEL - // were set to MODE_CCK and 14 respectively before ATETXBW is set to 0. - //===================================================================== - if (pAd->ate.Channel == 14) - { - int TxMode = pAd->ate.TxWI.PHYMODE; - if (TxMode == MODE_CCK) - { - // when Channel==14 && Mode==CCK && BandWidth==20M, BBP R4 bit5=1 - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &value); - value |= 0x20; //set bit5=1 - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, value); - } - } - - //===================================================================== - // If bandwidth != 40M, RF Reg4 bit 21 = 0. - pAd->LatchRfRegs.R4 &= ~0x00200000; - RtmpRfIoWrite(pAd); - } - else if(pAd->ate.TxWI.BW == BW_40) - { - if(pAd->ate.Channel <= 14) - { - for (i=0; i<5; i++) - { - if (pAd->Tx40MPwrCfgGBand[i] != 0xffffffff) - { - RTMP_IO_WRITE32(pAd, TX_PWR_CFG_0 + i*4, pAd->Tx40MPwrCfgGBand[i]); - RTMPusecDelay(5000); - } - } - } - else - { - for (i=0; i<5; i++) - { - if (pAd->Tx40MPwrCfgABand[i] != 0xffffffff) - { - RTMP_IO_WRITE32(pAd, TX_PWR_CFG_0 + i*4, pAd->Tx40MPwrCfgABand[i]); - RTMPusecDelay(5000); - } - } -#ifdef DOT11_N_SUPPORT - if ((pAd->ate.TxWI.PHYMODE >= MODE_HTMIX) && (pAd->ate.TxWI.MCS == 7)) - { - value = 0x28; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R67, value); - } -#endif // DOT11_N_SUPPORT // - } - - //Set BBP R4 bit[4:3]=1:0 - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &value); - value &= (~0x18); - value |= 0x10; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, value); - - //Set BBP R66=0x3C - value = 0x3C; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, value); - //Set BBP R68=0x0C - //to improve Rx sensitivity. - value = 0x0C; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R68, value); - //Set BBP R69=0x1A - value = 0x1A; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, value); - //Set BBP R70=0x0A - value = 0x0A; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, value); - //Set BBP R73=0x16 - value = 0x16; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R73, value); - - // If bandwidth = 40M, set RF Reg4 bit 21 = 1. - pAd->LatchRfRegs.R4 |= 0x00200000; - RtmpRfIoWrite(pAd); - } - - ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_TX_BW_Proc (BBPCurrentBW = %d)\n", pAd->ate.TxWI.BW)); - ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_BW_Proc Success\n")); - - - return TRUE; -} - -/* - ========================================================================== - Description: - Set ATE Tx frame length - - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_ATE_TX_LENGTH_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - pAd->ate.TxLength = simple_strtol(arg, 0, 10); - - if((pAd->ate.TxLength < 24) || (pAd->ate.TxLength > (MAX_FRAME_SIZE - 34/* == 2312 */))) - { - pAd->ate.TxLength = (MAX_FRAME_SIZE - 34/* == 2312 */); - ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_LENGTH_Proc::Out of range, it should be in range of 24~%d.\n", (MAX_FRAME_SIZE - 34/* == 2312 */))); - return FALSE; - } - - ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_TX_LENGTH_Proc (TxLength = %d)\n", pAd->ate.TxLength)); - ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_LENGTH_Proc Success\n")); - - - return TRUE; -} - -/* - ========================================================================== - Description: - Set ATE Tx frame count - - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_ATE_TX_COUNT_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - pAd->ate.TxCount = simple_strtol(arg, 0, 10); - - ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_TX_COUNT_Proc (TxCount = %d)\n", pAd->ate.TxCount)); - ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_COUNT_Proc Success\n")); - - - return TRUE; -} - -/* - ========================================================================== - Description: - Set ATE Tx frame MCS - - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_ATE_TX_MCS_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - UCHAR MCS; - int result; - - MCS = simple_strtol(arg, 0, 10); - result = CheckMCSValid(pAd->ate.TxWI.PHYMODE, MCS); - - if (result != -1) - { - pAd->ate.TxWI.MCS = (UCHAR)MCS; - } - else - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_MCS_Proc::Out of range, refer to rate table.\n")); - return FALSE; - } - - ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_TX_MCS_Proc (MCS = %d)\n", pAd->ate.TxWI.MCS)); - ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_MCS_Proc Success\n")); - - - return TRUE; -} - -/* - ========================================================================== - Description: - Set ATE Tx frame Mode - 0: MODE_CCK - 1: MODE_OFDM - 2: MODE_HTMIX - 3: MODE_HTGREENFIELD - - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_ATE_TX_MODE_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - pAd->ate.TxWI.PHYMODE = simple_strtol(arg, 0, 10); - - if(pAd->ate.TxWI.PHYMODE > 3) - { - pAd->ate.TxWI.PHYMODE = 0; - ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_MODE_Proc::Out of range. it should be in range of 0~3\n")); - ATEDBGPRINT(RT_DEBUG_ERROR, ("0: CCK, 1: OFDM, 2: HT_MIX, 3: HT_GREEN_FIELD.\n")); - return FALSE; - } - - ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_TX_MODE_Proc (TxMode = %d)\n", pAd->ate.TxWI.PHYMODE)); - ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_MODE_Proc Success\n")); - - - return TRUE; -} - -/* - ========================================================================== - Description: - Set ATE Tx frame GI - - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_ATE_TX_GI_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - pAd->ate.TxWI.ShortGI = simple_strtol(arg, 0, 10); - - if(pAd->ate.TxWI.ShortGI > 1) - { - pAd->ate.TxWI.ShortGI = 0; - ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_GI_Proc::Out of range\n")); - return FALSE; - } - - ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_TX_GI_Proc (GI = %d)\n", pAd->ate.TxWI.ShortGI)); - ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_GI_Proc Success\n")); - - - return TRUE; -} - -/* - ========================================================================== - Description: - ========================================================================== - */ -INT Set_ATE_RX_FER_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - pAd->ate.bRxFer = simple_strtol(arg, 0, 10); - - if (pAd->ate.bRxFer == 1) - { - pAd->ate.RxCntPerSec = 0; - pAd->ate.RxTotalCnt = 0; - } - - ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_RX_FER_Proc (bRxFer = %d)\n", pAd->ate.bRxFer)); - ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_RX_FER_Proc Success\n")); - - - return TRUE; -} - -INT Set_ATE_Read_RF_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ate_print(KERN_EMERG "R1 = %lx\n", pAd->LatchRfRegs.R1); - ate_print(KERN_EMERG "R2 = %lx\n", pAd->LatchRfRegs.R2); - ate_print(KERN_EMERG "R3 = %lx\n", pAd->LatchRfRegs.R3); - ate_print(KERN_EMERG "R4 = %lx\n", pAd->LatchRfRegs.R4); - - return TRUE; -} - -INT Set_ATE_Write_RF1_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - UINT32 value = simple_strtol(arg, 0, 16); - - pAd->LatchRfRegs.R1 = value; - RtmpRfIoWrite(pAd); - - return TRUE; -} - -INT Set_ATE_Write_RF2_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - UINT32 value = simple_strtol(arg, 0, 16); - - pAd->LatchRfRegs.R2 = value; - RtmpRfIoWrite(pAd); - - return TRUE; -} - -INT Set_ATE_Write_RF3_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - UINT32 value = simple_strtol(arg, 0, 16); - - pAd->LatchRfRegs.R3 = value; - RtmpRfIoWrite(pAd); - - return TRUE; -} - -INT Set_ATE_Write_RF4_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - UINT32 value = simple_strtol(arg, 0, 16); - - pAd->LatchRfRegs.R4 = value; - RtmpRfIoWrite(pAd); - - return TRUE; -} - -/* - ========================================================================== - Description: - Load and Write EEPROM from a binary file prepared in advance. - - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -#ifndef UCOS -INT Set_ATE_Load_E2P_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - BOOLEAN ret = FALSE; - PUCHAR src = EEPROM_BIN_FILE_NAME; - struct file *srcf; - INT32 retval, orgfsuid, orgfsgid; - mm_segment_t orgfs; - USHORT WriteEEPROM[(EEPROM_SIZE/2)]; - UINT32 FileLength = 0; - UINT32 value = simple_strtol(arg, 0, 10); - - ATEDBGPRINT(RT_DEBUG_ERROR, ("===> %s (value=%d)\n\n", __func__, value)); - - if (value > 0) - { - /* zero the e2p buffer */ - NdisZeroMemory((PUCHAR)WriteEEPROM, EEPROM_SIZE); - - /* save uid and gid used for filesystem access. - ** set user and group to 0 (root) - */ - orgfsuid = current->fsuid; - orgfsgid = current->fsgid; - /* as root */ - current->fsuid = current->fsgid = 0; - orgfs = get_fs(); - set_fs(KERNEL_DS); - - do - { - /* open the bin file */ - srcf = filp_open(src, O_RDONLY, 0); - - if (IS_ERR(srcf)) - { - ate_print("%s - Error %ld opening %s\n", __func__, -PTR_ERR(srcf), src); - break; - } - - /* the object must have a read method */ - if ((srcf->f_op == NULL) || (srcf->f_op->read == NULL)) - { - ate_print("%s - %s does not have a read method\n", __func__, src); - break; - } - - /* read the firmware from the file *.bin */ - FileLength = srcf->f_op->read(srcf, - (PUCHAR)WriteEEPROM, - EEPROM_SIZE, - &srcf->f_pos); - - if (FileLength != EEPROM_SIZE) - { - ate_print("%s: error file length (=%d) in e2p.bin\n", - __func__, FileLength); - break; - } - else - { - /* write the content of .bin file to EEPROM */ - rt_ee_write_all(pAd, WriteEEPROM); - ret = TRUE; - } - break; - } while(TRUE); - - /* close firmware file */ - if (IS_ERR(srcf)) - { - ; - } - else - { - retval = filp_close(srcf, NULL); - if (retval) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("--> Error %d closing %s\n", -retval, src)); - - } - } - - /* restore */ - set_fs(orgfs); - current->fsuid = orgfsuid; - current->fsgid = orgfsgid; - } - ATEDBGPRINT(RT_DEBUG_ERROR, ("<=== %s (ret=%d)\n", __func__, ret)); - - return ret; - -} -#else -INT Set_ATE_Load_E2P_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - USHORT WriteEEPROM[(EEPROM_SIZE/2)]; - struct iwreq *wrq = (struct iwreq *)arg; - - ATEDBGPRINT(RT_DEBUG_TRACE, ("===> %s (wrq->u.data.length = %d)\n\n", __func__, wrq->u.data.length)); - - if (wrq->u.data.length != EEPROM_SIZE) - { - ate_print("%s: error length (=%d) from host\n", - __func__, wrq->u.data.length); - return FALSE; - } - else/* (wrq->u.data.length == EEPROM_SIZE) */ - { - /* zero the e2p buffer */ - NdisZeroMemory((PUCHAR)WriteEEPROM, EEPROM_SIZE); - - /* fill the local buffer */ - NdisMoveMemory((PUCHAR)WriteEEPROM, wrq->u.data.pointer, wrq->u.data.length); - - do - { - /* write the content of .bin file to EEPROM */ - rt_ee_write_all(pAd, WriteEEPROM); - - } while(FALSE); - } - - ATEDBGPRINT(RT_DEBUG_TRACE, ("<=== %s\n", __func__)); - - return TRUE; - -} -#endif // !UCOS // - -INT Set_ATE_Read_E2P_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - USHORT buffer[EEPROM_SIZE/2]; - USHORT *p; - int i; - - rt_ee_read_all(pAd, (USHORT *)buffer); - p = buffer; - for (i = 0; i < (EEPROM_SIZE/2); i++) - { - ate_print("%4.4x ", *p); - if (((i+1) % 16) == 0) - ate_print("\n"); - p++; - } - return TRUE; -} - -INT Set_ATE_Show_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ate_print("Mode=%d\n", pAd->ate.Mode); - ate_print("TxPower0=%d\n", pAd->ate.TxPower0); - ate_print("TxPower1=%d\n", pAd->ate.TxPower1); - ate_print("TxAntennaSel=%d\n", pAd->ate.TxAntennaSel); - ate_print("RxAntennaSel=%d\n", pAd->ate.RxAntennaSel); - ate_print("BBPCurrentBW=%d\n", pAd->ate.TxWI.BW); - ate_print("GI=%d\n", pAd->ate.TxWI.ShortGI); - ate_print("MCS=%d\n", pAd->ate.TxWI.MCS); - ate_print("TxMode=%d\n", pAd->ate.TxWI.PHYMODE); - ate_print("Addr1=%02x:%02x:%02x:%02x:%02x:%02x\n", - pAd->ate.Addr1[0], pAd->ate.Addr1[1], pAd->ate.Addr1[2], pAd->ate.Addr1[3], pAd->ate.Addr1[4], pAd->ate.Addr1[5]); - ate_print("Addr2=%02x:%02x:%02x:%02x:%02x:%02x\n", - pAd->ate.Addr2[0], pAd->ate.Addr2[1], pAd->ate.Addr2[2], pAd->ate.Addr2[3], pAd->ate.Addr2[4], pAd->ate.Addr2[5]); - ate_print("Addr3=%02x:%02x:%02x:%02x:%02x:%02x\n", - pAd->ate.Addr3[0], pAd->ate.Addr3[1], pAd->ate.Addr3[2], pAd->ate.Addr3[3], pAd->ate.Addr3[4], pAd->ate.Addr3[5]); - ate_print("Channel=%d\n", pAd->ate.Channel); - ate_print("TxLength=%d\n", pAd->ate.TxLength); - ate_print("TxCount=%u\n", pAd->ate.TxCount); - ate_print("RFFreqOffset=%d\n", pAd->ate.RFFreqOffset); - ate_print(KERN_EMERG "Set_ATE_Show_Proc Success\n"); - return TRUE; -} - -INT Set_ATE_Help_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ate_print("ATE=ATESTART, ATESTOP, TXCONT, TXCARR, TXFRAME, RXFRAME\n"); - ate_print("ATEDA\n"); - ate_print("ATESA\n"); - ate_print("ATEBSSID\n"); - ate_print("ATECHANNEL, range:0~14(unless A band !)\n"); - ate_print("ATETXPOW0, set power level of antenna 1.\n"); - ate_print("ATETXPOW1, set power level of antenna 2.\n"); - ate_print("ATETXANT, set TX antenna. 0:all, 1:antenna one, 2:antenna two.\n"); - ate_print("ATERXANT, set RX antenna.0:all, 1:antenna one, 2:antenna two, 3:antenna three.\n"); - ate_print("ATETXFREQOFFSET, set frequency offset, range 0~63\n"); - ate_print("ATETXBW, set BandWidth, 0:20MHz, 1:40MHz.\n"); - ate_print("ATETXLEN, set Frame length, range 24~%d\n", (MAX_FRAME_SIZE - 34/* == 2312 */)); - ate_print("ATETXCNT, set how many frame going to transmit.\n"); - ate_print("ATETXMCS, set MCS, reference to rate table.\n"); - ate_print("ATETXMODE, set Mode 0:CCK, 1:OFDM, 2:HT-Mix, 3:GreenField, reference to rate table.\n"); - ate_print("ATETXGI, set GI interval, 0:Long, 1:Short\n"); - ate_print("ATERXFER, 0:disable Rx Frame error rate. 1:enable Rx Frame error rate.\n"); - ate_print("ATERRF, show all RF registers.\n"); - ate_print("ATEWRF1, set RF1 register.\n"); - ate_print("ATEWRF2, set RF2 register.\n"); - ate_print("ATEWRF3, set RF3 register.\n"); - ate_print("ATEWRF4, set RF4 register.\n"); - ate_print("ATELDE2P, load EEPROM from .bin file.\n"); - ate_print("ATERE2P, display all EEPROM content.\n"); - ate_print("ATESHOW, display all parameters of ATE.\n"); - ate_print("ATEHELP, online help.\n"); - - return TRUE; -} - -/* - ========================================================================== - Description: - - AsicSwitchChannel() dedicated for ATE. - - ========================================================================== -*/ -VOID ATEAsicSwitchChannel( - IN PRTMP_ADAPTER pAd) -{ - UINT32 R2 = 0, R3 = DEFAULT_RF_TX_POWER, R4 = 0, Value = 0; - CHAR TxPwer = 0, TxPwer2 = 0; - UCHAR index, BbpValue = 0, R66 = 0x30; - RTMP_RF_REGS *RFRegTable; - UCHAR Channel; - -#ifdef RALINK_28xx_QA - if ((pAd->ate.bQATxStart == TRUE) || (pAd->ate.bQARxStart == TRUE)) - { - if (pAd->ate.Channel != pAd->LatchRfRegs.Channel) - { - pAd->ate.Channel = pAd->LatchRfRegs.Channel; - } - return; - } - else -#endif // RALINK_28xx_QA // - Channel = pAd->ate.Channel; - - // Select antenna - AsicAntennaSelect(pAd, Channel); - - // fill Tx power value - TxPwer = pAd->ate.TxPower0; - TxPwer2 = pAd->ate.TxPower1; - - RFRegTable = RF2850RegTable; - - switch (pAd->RfIcType) - { - /* But only 2850 and 2750 support 5.5GHz band... */ - case RFIC_2820: - case RFIC_2850: - case RFIC_2720: - case RFIC_2750: - - for (index = 0; index < NUM_OF_2850_CHNL; index++) - { - if (Channel == RFRegTable[index].Channel) - { - R2 = RFRegTable[index].R2; - if (pAd->Antenna.field.TxPath == 1) - { - R2 |= 0x4000; // If TXpath is 1, bit 14 = 1; - } - - if (pAd->Antenna.field.RxPath == 2) - { - switch (pAd->ate.RxAntennaSel) - { - case 1: - R2 |= 0x20040; - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BbpValue); - BbpValue &= 0xE4; - BbpValue |= 0x00; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BbpValue); - break; - case 2: - R2 |= 0x10040; - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BbpValue); - BbpValue &= 0xE4; - BbpValue |= 0x01; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BbpValue); - break; - default: - R2 |= 0x40; - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BbpValue); - BbpValue &= 0xE4; - /* Only enable two Antenna to receive. */ - BbpValue |= 0x08; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BbpValue); - break; - } - } - else if (pAd->Antenna.field.RxPath == 1) - { - R2 |= 0x20040; // write 1 to off RxPath - } - - if (pAd->Antenna.field.TxPath == 2) - { - if (pAd->ate.TxAntennaSel == 1) - { - R2 |= 0x4000; // If TX Antenna select is 1 , bit 14 = 1; Disable Ant 2 - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R1, &BbpValue); - BbpValue &= 0xE7; //11100111B - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R1, BbpValue); - } - else if (pAd->ate.TxAntennaSel == 2) - { - R2 |= 0x8000; // If TX Antenna select is 2 , bit 15 = 1; Disable Ant 1 - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R1, &BbpValue); - BbpValue &= 0xE7; - BbpValue |= 0x08; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R1, BbpValue); - } - else - { - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R1, &BbpValue); - BbpValue &= 0xE7; - BbpValue |= 0x10; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R1, BbpValue); - } - } - if (pAd->Antenna.field.RxPath == 3) - { - switch (pAd->ate.RxAntennaSel) - { - case 1: - R2 |= 0x20040; - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BbpValue); - BbpValue &= 0xE4; - BbpValue |= 0x00; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BbpValue); - break; - case 2: - R2 |= 0x10040; - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BbpValue); - BbpValue &= 0xE4; - BbpValue |= 0x01; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BbpValue); - break; - case 3: - R2 |= 0x30000; - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BbpValue); - BbpValue &= 0xE4; - BbpValue |= 0x02; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BbpValue); - break; - default: - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BbpValue); - BbpValue &= 0xE4; - BbpValue |= 0x10; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BbpValue); - break; - } - } - - if (Channel > 14) - { - // initialize R3, R4 - R3 = (RFRegTable[index].R3 & 0xffffc1ff); - R4 = (RFRegTable[index].R4 & (~0x001f87c0)) | (pAd->ate.RFFreqOffset << 15); - - // According the Rory's suggestion to solve the middle range issue. - // 5.5G band power range: 0xF9~0X0F, TX0 Reg3 bit9/TX1 Reg4 bit6="0" means the TX power reduce 7dB - // R3 - if ((TxPwer >= -7) && (TxPwer < 0)) - { - TxPwer = (7+TxPwer); - TxPwer = (TxPwer > 0xF) ? (0xF) : (TxPwer); - R3 |= (TxPwer << 10); - ATEDBGPRINT(RT_DEBUG_TRACE, ("ATEAsicSwitchChannel: TxPwer=%d \n", TxPwer)); - } - else - { - TxPwer = (TxPwer > 0xF) ? (0xF) : (TxPwer); - R3 |= (TxPwer << 10) | (1 << 9); - } - - // R4 - if ((TxPwer2 >= -7) && (TxPwer2 < 0)) - { - TxPwer2 = (7+TxPwer2); - TxPwer2 = (TxPwer2 > 0xF) ? (0xF) : (TxPwer2); - R4 |= (TxPwer2 << 7); - ATEDBGPRINT(RT_DEBUG_TRACE, ("ATEAsicSwitchChannel: TxPwer2=%d \n", TxPwer2)); - } - else - { - TxPwer2 = (TxPwer2 > 0xF) ? (0xF) : (TxPwer2); - R4 |= (TxPwer2 << 7) | (1 << 6); - } - } - else - { - R3 = (RFRegTable[index].R3 & 0xffffc1ff) | (TxPwer << 9); // set TX power0 - R4 = (RFRegTable[index].R4 & (~0x001f87c0)) | (pAd->ate.RFFreqOffset << 15) | (TxPwer2 <<6);// Set freq offset & TxPwr1 - } - - // Based on BBP current mode before changing RF channel. - if (pAd->ate.TxWI.BW == BW_40) - { - R4 |=0x200000; - } - - // Update variables - pAd->LatchRfRegs.Channel = Channel; - pAd->LatchRfRegs.R1 = RFRegTable[index].R1; - pAd->LatchRfRegs.R2 = R2; - pAd->LatchRfRegs.R3 = R3; - pAd->LatchRfRegs.R4 = R4; - - RtmpRfIoWrite(pAd); - - break; - } - } - break; - - default: - break; - } - - // Change BBP setting during switch from a->g, g->a - if (Channel <= 14) - { - ULONG TxPinCfg = 0x00050F0A;// 2007.10.09 by Brian : 0x0005050A ==> 0x00050F0A - - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R62, (0x37 - GET_LNA_GAIN(pAd))); - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R63, (0x37 - GET_LNA_GAIN(pAd))); - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R64, (0x37 - GET_LNA_GAIN(pAd))); - - /* For 1T/2R chip only... */ - if (pAd->NicConfig2.field.ExternalLNAForG) - { - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R82, 0x62); - } - else - { - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R82, 0x84); - } - - // According the Rory's suggestion to solve the middle range issue. - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R86, &BbpValue); - ASSERT((BbpValue == 0x00)); - if ((BbpValue != 0x00)) - { - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R86, 0x00); - } - - // 5.5GHz band selection PIN, bit1 and bit2 are complement - RTMP_IO_READ32(pAd, TX_BAND_CFG, &Value); - Value &= (~0x6); - Value |= (0x04); - RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Value); - - // Turn off unused PA or LNA when only 1T or 1R. - if (pAd->Antenna.field.TxPath == 1) - { - TxPinCfg &= 0xFFFFFFF3; - } - if (pAd->Antenna.field.RxPath == 1) - { - TxPinCfg &= 0xFFFFF3FF; - } - - RTMP_IO_WRITE32(pAd, TX_PIN_CFG, TxPinCfg); - } - else - { - ULONG TxPinCfg = 0x00050F05;//2007.10.09 by Brian : 0x00050505 ==> 0x00050F05 - - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R62, (0x37 - GET_LNA_GAIN(pAd))); - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R63, (0x37 - GET_LNA_GAIN(pAd))); - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R64, (0x37 - GET_LNA_GAIN(pAd))); - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R82, 0xF2); - - // According the Rory's suggestion to solve the middle range issue. - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R86, &BbpValue); - ASSERT((BbpValue == 0x00)); - if ((BbpValue != 0x00)) - { - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R86, 0x00); - } - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R91, &BbpValue); - ASSERT((BbpValue == 0x04)); - - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R92, &BbpValue); - ASSERT((BbpValue == 0x00)); - - // 5.5GHz band selection PIN, bit1 and bit2 are complement - RTMP_IO_READ32(pAd, TX_BAND_CFG, &Value); - Value &= (~0x6); - Value |= (0x02); - RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Value); - - // Turn off unused PA or LNA when only 1T or 1R. - if (pAd->Antenna.field.TxPath == 1) - { - TxPinCfg &= 0xFFFFFFF3; - } - if (pAd->Antenna.field.RxPath == 1) - { - TxPinCfg &= 0xFFFFF3FF; - } - - RTMP_IO_WRITE32(pAd, TX_PIN_CFG, TxPinCfg); - } - - // R66 should be set according to Channel and use 20MHz when scanning - if (Channel <= 14) - { - // BG band - R66 = 0x2E + GET_LNA_GAIN(pAd); - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); - } - else - { - // 5.5 GHz band - if (pAd->ate.TxWI.BW == BW_20) - { - R66 = (UCHAR)(0x32 + (GET_LNA_GAIN(pAd)*5)/3); - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); - } - else - { - R66 = (UCHAR)(0x3A + (GET_LNA_GAIN(pAd)*5)/3); - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); - } - } - - // - // On 11A, We should delay and wait RF/BBP to be stable - // and the appropriate time should be 1000 micro seconds - // 2005/06/05 - On 11G, We also need this delay time. Otherwise it's difficult to pass the WHQL. - // - RTMPusecDelay(1000); - - if (Channel > 14) - { - // When 5.5GHz band the LSB of TxPwr will be used to reduced 7dB or not. - ATEDBGPRINT(RT_DEBUG_TRACE, ("SwitchChannel#%d(RF=%d, %dT) to , R1=0x%08lx, R2=0x%08lx, R3=0x%08lx, R4=0x%08lx\n", - Channel, - pAd->RfIcType, - pAd->Antenna.field.TxPath, - pAd->LatchRfRegs.R1, - pAd->LatchRfRegs.R2, - pAd->LatchRfRegs.R3, - pAd->LatchRfRegs.R4)); - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("SwitchChannel#%d(RF=%d, Pwr0=%u, Pwr1=%u, %dT) to , R1=0x%08lx, R2=0x%08lx, R3=0x%08lx, R4=0x%08lx\n", - Channel, - pAd->RfIcType, - (R3 & 0x00003e00) >> 9, - (R4 & 0x000007c0) >> 6, - pAd->Antenna.field.TxPath, - pAd->LatchRfRegs.R1, - pAd->LatchRfRegs.R2, - pAd->LatchRfRegs.R3, - pAd->LatchRfRegs.R4)); - } -} - -// -// In fact, no one will call this routine so far ! -// -/* - ========================================================================== - Description: - Gives CCK TX rate 2 more dB TX power. - This routine works only in ATE mode. - - calculate desired Tx power in RF R3.Tx0~5, should consider - - 0. if current radio is a noisy environment (pAd->DrsCounters.fNoisyEnvironment) - 1. TxPowerPercentage - 2. auto calibration based on TSSI feedback - 3. extra 2 db for CCK - 4. -10 db upon very-short distance (AvgRSSI >= -40db) to AP - - NOTE: Since this routine requires the value of (pAd->DrsCounters.fNoisyEnvironment), - it should be called AFTER MlmeDynamicTxRateSwitching() - ========================================================================== - */ -VOID ATEAsicAdjustTxPower( - IN PRTMP_ADAPTER pAd) -{ - INT i, j; - CHAR DeltaPwr = 0; - BOOLEAN bAutoTxAgc = FALSE; - UCHAR TssiRef, *pTssiMinusBoundary, *pTssiPlusBoundary, TxAgcStep; - UCHAR BbpR49 = 0, idx; - PCHAR pTxAgcCompensate; - ULONG TxPwr[5]; - CHAR Value; - - /* no one calls this procedure so far */ - if (pAd->ate.TxWI.BW == BW_40) - { - if (pAd->ate.Channel > 14) - { - TxPwr[0] = pAd->Tx40MPwrCfgABand[0]; - TxPwr[1] = pAd->Tx40MPwrCfgABand[1]; - TxPwr[2] = pAd->Tx40MPwrCfgABand[2]; - TxPwr[3] = pAd->Tx40MPwrCfgABand[3]; - TxPwr[4] = pAd->Tx40MPwrCfgABand[4]; - } - else - { - TxPwr[0] = pAd->Tx40MPwrCfgGBand[0]; - TxPwr[1] = pAd->Tx40MPwrCfgGBand[1]; - TxPwr[2] = pAd->Tx40MPwrCfgGBand[2]; - TxPwr[3] = pAd->Tx40MPwrCfgGBand[3]; - TxPwr[4] = pAd->Tx40MPwrCfgGBand[4]; - } - } - else - { - if (pAd->ate.Channel > 14) - { - TxPwr[0] = pAd->Tx20MPwrCfgABand[0]; - TxPwr[1] = pAd->Tx20MPwrCfgABand[1]; - TxPwr[2] = pAd->Tx20MPwrCfgABand[2]; - TxPwr[3] = pAd->Tx20MPwrCfgABand[3]; - TxPwr[4] = pAd->Tx20MPwrCfgABand[4]; - } - else - { - TxPwr[0] = pAd->Tx20MPwrCfgGBand[0]; - TxPwr[1] = pAd->Tx20MPwrCfgGBand[1]; - TxPwr[2] = pAd->Tx20MPwrCfgGBand[2]; - TxPwr[3] = pAd->Tx20MPwrCfgGBand[3]; - TxPwr[4] = pAd->Tx20MPwrCfgGBand[4]; - } - } - - // TX power compensation for temperature variation based on TSSI. - // Do it per 4 seconds. - if (pAd->Mlme.OneSecPeriodicRound % 4 == 0) - { - if (pAd->ate.Channel <= 14) - { - /* bg channel */ - bAutoTxAgc = pAd->bAutoTxAgcG; - TssiRef = pAd->TssiRefG; - pTssiMinusBoundary = &pAd->TssiMinusBoundaryG[0]; - pTssiPlusBoundary = &pAd->TssiPlusBoundaryG[0]; - TxAgcStep = pAd->TxAgcStepG; - pTxAgcCompensate = &pAd->TxAgcCompensateG; - } - else - { - /* a channel */ - bAutoTxAgc = pAd->bAutoTxAgcA; - TssiRef = pAd->TssiRefA; - pTssiMinusBoundary = &pAd->TssiMinusBoundaryA[0]; - pTssiPlusBoundary = &pAd->TssiPlusBoundaryA[0]; - TxAgcStep = pAd->TxAgcStepA; - pTxAgcCompensate = &pAd->TxAgcCompensateA; - } - - if (bAutoTxAgc) - { - /* BbpR49 is unsigned char */ - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R49, &BbpR49); - - /* (p) TssiPlusBoundaryG[0] = 0 = (m) TssiMinusBoundaryG[0] */ - /* compensate: +4 +3 +2 +1 0 -1 -2 -3 -4 * steps */ - /* step value is defined in pAd->TxAgcStepG for tx power value */ - - /* [4]+1+[4] p4 p3 p2 p1 o1 m1 m2 m3 m4 */ - /* ex: 0x00 0x15 0x25 0x45 0x88 0xA0 0xB5 0xD0 0xF0 - above value are examined in mass factory production */ - /* [4] [3] [2] [1] [0] [1] [2] [3] [4] */ - - /* plus is 0x10 ~ 0x40, minus is 0x60 ~ 0x90 */ - /* if value is between p1 ~ o1 or o1 ~ s1, no need to adjust tx power */ - /* if value is 0x65, tx power will be -= TxAgcStep*(2-1) */ - - if (BbpR49 > pTssiMinusBoundary[1]) - { - // Reading is larger than the reference value. - // Check for how large we need to decrease the Tx power. - for (idx = 1; idx < 5; idx++) - { - if (BbpR49 <= pTssiMinusBoundary[idx]) // Found the range - break; - } - // The index is the step we should decrease, idx = 0 means there is nothing to compensate -// if (R3 > (ULONG) (TxAgcStep * (idx-1))) - *pTxAgcCompensate = -(TxAgcStep * (idx-1)); -// else -// *pTxAgcCompensate = -((UCHAR)R3); - - DeltaPwr += (*pTxAgcCompensate); - ATEDBGPRINT(RT_DEBUG_TRACE, ("-- Tx Power, BBP R1=%x, TssiRef=%x, TxAgcStep=%x, step = -%d\n", - BbpR49, TssiRef, TxAgcStep, idx-1)); - } - else if (BbpR49 < pTssiPlusBoundary[1]) - { - // Reading is smaller than the reference value - // check for how large we need to increase the Tx power - for (idx = 1; idx < 5; idx++) - { - if (BbpR49 >= pTssiPlusBoundary[idx]) // Found the range - break; - } - // The index is the step we should increase, idx = 0 means there is nothing to compensate - *pTxAgcCompensate = TxAgcStep * (idx-1); - DeltaPwr += (*pTxAgcCompensate); - ATEDBGPRINT(RT_DEBUG_TRACE, ("++ Tx Power, BBP R1=%x, TssiRef=%x, TxAgcStep=%x, step = +%d\n", - BbpR49, TssiRef, TxAgcStep, idx-1)); - } - else - { - *pTxAgcCompensate = 0; - ATEDBGPRINT(RT_DEBUG_TRACE, (" Tx Power, BBP R1=%x, TssiRef=%x, TxAgcStep=%x, step = +%d\n", - BbpR49, TssiRef, TxAgcStep, 0)); - } - } - } - else - { - if (pAd->ate.Channel <= 14) - { - bAutoTxAgc = pAd->bAutoTxAgcG; - pTxAgcCompensate = &pAd->TxAgcCompensateG; - } - else - { - bAutoTxAgc = pAd->bAutoTxAgcA; - pTxAgcCompensate = &pAd->TxAgcCompensateA; - } - - if (bAutoTxAgc) - DeltaPwr += (*pTxAgcCompensate); - } - - /* calculate delta power based on the percentage specified from UI */ - // E2PROM setting is calibrated for maximum TX power (i.e. 100%) - // We lower TX power here according to the percentage specified from UI - if (pAd->CommonCfg.TxPowerPercentage == 0xffffffff) // AUTO TX POWER control - ; - else if (pAd->CommonCfg.TxPowerPercentage > 90) // 91 ~ 100% & AUTO, treat as 100% in terms of mW - ; - else if (pAd->CommonCfg.TxPowerPercentage > 60) // 61 ~ 90%, treat as 75% in terms of mW - { - DeltaPwr -= 1; - } - else if (pAd->CommonCfg.TxPowerPercentage > 30) // 31 ~ 60%, treat as 50% in terms of mW - { - DeltaPwr -= 3; - } - else if (pAd->CommonCfg.TxPowerPercentage > 15) // 16 ~ 30%, treat as 25% in terms of mW - { - DeltaPwr -= 6; - } - else if (pAd->CommonCfg.TxPowerPercentage > 9) // 10 ~ 15%, treat as 12.5% in terms of mW - { - DeltaPwr -= 9; - } - else // 0 ~ 9 %, treat as MIN(~3%) in terms of mW - { - DeltaPwr -= 12; - } - - /* reset different new tx power for different TX rate */ - for(i=0; i<5; i++) - { - if (TxPwr[i] != 0xffffffff) - { - for (j=0; j<8; j++) - { - Value = (CHAR)((TxPwr[i] >> j*4) & 0x0F); /* 0 ~ 15 */ - - if ((Value + DeltaPwr) < 0) - { - Value = 0; /* min */ - } - else if ((Value + DeltaPwr) > 0xF) - { - Value = 0xF; /* max */ - } - else - { - Value += DeltaPwr; /* temperature compensation */ - } - - /* fill new value to CSR offset */ - TxPwr[i] = (TxPwr[i] & ~(0x0000000F << j*4)) | (Value << j*4); - } - - /* write tx power value to CSR */ - /* TX_PWR_CFG_0 (8 tx rate) for TX power for OFDM 12M/18M - TX power for OFDM 6M/9M - TX power for CCK5.5M/11M - TX power for CCK1M/2M */ - /* TX_PWR_CFG_1 ~ TX_PWR_CFG_4 */ - RTMP_IO_WRITE32(pAd, TX_PWR_CFG_0 + i*4, TxPwr[i]); - - - } - } - -} - -/* - ======================================================================== - Routine Description: - Write TxWI for ATE mode. - - Return Value: - None - ======================================================================== -*/ - -#ifdef RT2870 -static VOID ATEWriteTxWI( - IN PRTMP_ADAPTER pAd, - IN PTXWI_STRUC pTxWI, - IN BOOLEAN FRAG, - IN BOOLEAN InsTimestamp, - IN BOOLEAN AMPDU, - IN BOOLEAN Ack, - IN BOOLEAN NSeq, // HW new a sequence. - IN UCHAR BASize, - IN UCHAR WCID, - IN ULONG Length, - IN UCHAR PID, - IN UCHAR MIMOps, - IN UCHAR Txopmode, - IN BOOLEAN CfAck, - IN HTTRANSMIT_SETTING Transmit) -{ - // - // Always use Long preamble before verifiation short preamble functionality works well. - // Todo: remove the following line if short preamble functionality works - // - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED); - pTxWI->FRAG= FRAG; - pTxWI->TS= InsTimestamp; - pTxWI->AMPDU = AMPDU; - - pTxWI->MIMOps = PWR_ACTIVE; - pTxWI->MpduDensity = 4; - pTxWI->ACK = Ack; - pTxWI->txop = Txopmode; - pTxWI->NSEQ = NSeq; - pTxWI->BAWinSize = BASize; - - pTxWI->WirelessCliID = WCID; - pTxWI->MPDUtotalByteCount = Length; - pTxWI->PacketId = PID; - - pTxWI->BW = Transmit.field.BW; - pTxWI->ShortGI = Transmit.field.ShortGI; - pTxWI->STBC= Transmit.field.STBC; - - pTxWI->MCS = Transmit.field.MCS; - pTxWI->PHYMODE= Transmit.field.MODE; - -#ifdef DOT11_N_SUPPORT - // - // MMPS is 802.11n features. Because TxWI->MCS > 7 must be HT mode, - // so need not check if it's HT rate. - // - if ((MIMOps == MMPS_STATIC) && (pTxWI->MCS > 7)) - pTxWI->MCS = 7; - - if ((MIMOps == MMPS_DYNAMIC) && (pTxWI->MCS > 7)) // SMPS protect 2 spatial. - pTxWI->MIMOps = 1; -#endif // DOT11_N_SUPPORT // - - pTxWI->CFACK = CfAck; - - return; -} -#endif // RT2870 // -/* - ======================================================================== - - Routine Description: - Disable protection for ATE. - ======================================================================== -*/ -VOID ATEDisableAsicProtect( - IN PRTMP_ADAPTER pAd) -{ - PROT_CFG_STRUC ProtCfg, ProtCfg4; - UINT32 Protect[6]; - USHORT offset; - UCHAR i; - UINT32 MacReg = 0; - - // Config ASIC RTS threshold register - RTMP_IO_READ32(pAd, TX_RTS_CFG, &MacReg); - MacReg &= 0xFF0000FF; - MacReg |= (pAd->CommonCfg.RtsThreshold << 8); - RTMP_IO_WRITE32(pAd, TX_RTS_CFG, MacReg); - - // Initial common protection settings - RTMPZeroMemory(Protect, sizeof(Protect)); - ProtCfg4.word = 0; - ProtCfg.word = 0; - ProtCfg.field.TxopAllowGF40 = 1; - ProtCfg.field.TxopAllowGF20 = 1; - ProtCfg.field.TxopAllowMM40 = 1; - ProtCfg.field.TxopAllowMM20 = 1; - ProtCfg.field.TxopAllowOfdm = 1; - ProtCfg.field.TxopAllowCck = 1; - ProtCfg.field.RTSThEn = 1; - ProtCfg.field.ProtectNav = ASIC_SHORTNAV; - - // Handle legacy(B/G) protection - ProtCfg.field.ProtectRate = pAd->CommonCfg.RtsRate; - ProtCfg.field.ProtectCtrl = 0; - Protect[0] = ProtCfg.word; - Protect[1] = ProtCfg.word; - - // NO PROTECT - // 1.All STAs in the BSS are 20/40 MHz HT - // 2. in ai 20/40MHz BSS - // 3. all STAs are 20MHz in a 20MHz BSS - // Pure HT. no protection. - - // MM20_PROT_CFG - // Reserved (31:27) - // PROT_TXOP(25:20) -- 010111 - // PROT_NAV(19:18) -- 01 (Short NAV protection) - // PROT_CTRL(17:16) -- 00 (None) - // PROT_RATE(15:0) -- 0x4004 (OFDM 24M) - Protect[2] = 0x01744004; - - // MM40_PROT_CFG - // Reserved (31:27) - // PROT_TXOP(25:20) -- 111111 - // PROT_NAV(19:18) -- 01 (Short NAV protection) - // PROT_CTRL(17:16) -- 00 (None) - // PROT_RATE(15:0) -- 0x4084 (duplicate OFDM 24M) - Protect[3] = 0x03f44084; - - // CF20_PROT_CFG - // Reserved (31:27) - // PROT_TXOP(25:20) -- 010111 - // PROT_NAV(19:18) -- 01 (Short NAV protection) - // PROT_CTRL(17:16) -- 00 (None) - // PROT_RATE(15:0) -- 0x4004 (OFDM 24M) - Protect[4] = 0x01744004; - - // CF40_PROT_CFG - // Reserved (31:27) - // PROT_TXOP(25:20) -- 111111 - // PROT_NAV(19:18) -- 01 (Short NAV protection) - // PROT_CTRL(17:16) -- 00 (None) - // PROT_RATE(15:0) -- 0x4084 (duplicate OFDM 24M) - Protect[5] = 0x03f44084; - - pAd->CommonCfg.IOTestParm.bRTSLongProtOn = FALSE; - - offset = CCK_PROT_CFG; - for (i = 0;i < 6;i++) - RTMP_IO_WRITE32(pAd, offset + i*4, Protect[i]); - -} - -#ifdef RT2870 -/* - ======================================================================== - Routine Description: - Write TxInfo for ATE mode. - - Return Value: - None - ======================================================================== -*/ -static VOID ATEWriteTxInfo( - IN PRTMP_ADAPTER pAd, - IN PTXINFO_STRUC pTxInfo, - IN USHORT USBDMApktLen, - IN BOOLEAN bWiv, - IN UCHAR QueueSel, - IN UCHAR NextValid, - IN UCHAR TxBurst) -{ - pTxInfo->USBDMATxPktLen = USBDMApktLen; - pTxInfo->QSEL = QueueSel; - - if (QueueSel != FIFO_EDCA) - ATEDBGPRINT(RT_DEBUG_TRACE, ("=======> QueueSel != FIFO_EDCA<=======\n")); - - pTxInfo->USBDMANextVLD = NextValid; - pTxInfo->USBDMATxburst = TxBurst; - pTxInfo->WIV = bWiv; - pTxInfo->SwUseLastRound = 0; - pTxInfo->rsv = 0; - pTxInfo->rsv2 = 0; - - return; -} -#endif // RT2870 // - -/* There are two ways to convert Rssi */ -#if 1 -// -// The way used with GET_LNA_GAIN(). -// -CHAR ATEConvertToRssi( - IN PRTMP_ADAPTER pAd, - IN CHAR Rssi, - IN UCHAR RssiNumber) -{ - UCHAR RssiOffset, LNAGain; - - // Rssi equals to zero should be an invalid value - if (Rssi == 0) - return -99; - - LNAGain = GET_LNA_GAIN(pAd); - if (pAd->LatchRfRegs.Channel > 14) - { - if (RssiNumber == 0) - RssiOffset = pAd->ARssiOffset0; - else if (RssiNumber == 1) - RssiOffset = pAd->ARssiOffset1; - else - RssiOffset = pAd->ARssiOffset2; - } - else - { - if (RssiNumber == 0) - RssiOffset = pAd->BGRssiOffset0; - else if (RssiNumber == 1) - RssiOffset = pAd->BGRssiOffset1; - else - RssiOffset = pAd->BGRssiOffset2; - } - - return (-12 - RssiOffset - LNAGain - Rssi); -} -#else -// -// The way originally used in ATE of rt2860ap. -// -CHAR ATEConvertToRssi( - IN PRTMP_ADAPTER pAd, - IN CHAR Rssi, - IN UCHAR RssiNumber) -{ - UCHAR RssiOffset, LNAGain; - - // Rssi equals to zero should be an invalid value - if (Rssi == 0) - return -99; - - if (pAd->LatchRfRegs.Channel > 14) - { - LNAGain = pAd->ALNAGain; - if (RssiNumber == 0) - RssiOffset = pAd->ARssiOffset0; - else if (RssiNumber == 1) - RssiOffset = pAd->ARssiOffset1; - else - RssiOffset = pAd->ARssiOffset2; - } - else - { - LNAGain = pAd->BLNAGain; - if (RssiNumber == 0) - RssiOffset = pAd->BGRssiOffset0; - else if (RssiNumber == 1) - RssiOffset = pAd->BGRssiOffset1; - else - RssiOffset = pAd->BGRssiOffset2; - } - - return (-32 - RssiOffset + LNAGain - Rssi); -} -#endif /* end of #if 1 */ - -/* - ======================================================================== - - Routine Description: - Set Japan filter coefficients if needed. - Note: - This routine should only be called when - entering TXFRAME mode or TXCONT mode. - - ======================================================================== -*/ -static VOID SetJapanFilter( - IN PRTMP_ADAPTER pAd) -{ - UCHAR BbpData = 0; - - // - // If Channel=14 and Bandwidth=20M and Mode=CCK, set BBP R4 bit5=1 - // (Japan Tx filter coefficients)when (TXFRAME or TXCONT). - // - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BbpData); - - if ((pAd->ate.TxWI.PHYMODE == MODE_CCK) && (pAd->ate.Channel == 14) && (pAd->ate.TxWI.BW == BW_20)) - { - BbpData |= 0x20; // turn on - ATEDBGPRINT(RT_DEBUG_TRACE, ("SetJapanFilter!!!\n")); - } - else - { - BbpData &= 0xdf; // turn off - ATEDBGPRINT(RT_DEBUG_TRACE, ("ClearJapanFilter!!!\n")); - } - - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BbpData); -} - -VOID ATESampleRssi( - IN PRTMP_ADAPTER pAd, - IN PRXWI_STRUC pRxWI) -{ - /* There are two ways to collect RSSI. */ -#if 1 - //pAd->LastRxRate = (USHORT)((pRxWI->MCS) + (pRxWI->BW <<7) + (pRxWI->ShortGI <<8)+ (pRxWI->PHYMODE <<14)) ; - if (pRxWI->RSSI0 != 0) - { - pAd->ate.LastRssi0 = ATEConvertToRssi(pAd, (CHAR) pRxWI->RSSI0, RSSI_0); - pAd->ate.AvgRssi0X8 = (pAd->ate.AvgRssi0X8 - pAd->ate.AvgRssi0) + pAd->ate.LastRssi0; - pAd->ate.AvgRssi0 = pAd->ate.AvgRssi0X8 >> 3; - } - if (pRxWI->RSSI1 != 0) - { - pAd->ate.LastRssi1 = ATEConvertToRssi(pAd, (CHAR) pRxWI->RSSI1, RSSI_1); - pAd->ate.AvgRssi1X8 = (pAd->ate.AvgRssi1X8 - pAd->ate.AvgRssi1) + pAd->ate.LastRssi1; - pAd->ate.AvgRssi1 = pAd->ate.AvgRssi1X8 >> 3; - } - if (pRxWI->RSSI2 != 0) - { - pAd->ate.LastRssi2 = ATEConvertToRssi(pAd, (CHAR) pRxWI->RSSI2, RSSI_2); - pAd->ate.AvgRssi2X8 = (pAd->ate.AvgRssi2X8 - pAd->ate.AvgRssi2) + pAd->ate.LastRssi2; - pAd->ate.AvgRssi2 = pAd->ate.AvgRssi2X8 >> 3; - } - - pAd->ate.LastSNR0 = (CHAR)(pRxWI->SNR0);// CHAR ==> UCHAR ? - pAd->ate.LastSNR1 = (CHAR)(pRxWI->SNR1);// CHAR ==> UCHAR ? - - pAd->ate.NumOfAvgRssiSample ++; -#else - pAd->ate.LastSNR0 = (CHAR)(pRxWI->SNR0); - pAd->ate.LastSNR1 = (CHAR)(pRxWI->SNR1); - pAd->ate.RxCntPerSec++; - pAd->ate.LastRssi0 = ATEConvertToRssi(pAd, (CHAR) pRxWI->RSSI0, RSSI_0); - pAd->ate.LastRssi1 = ATEConvertToRssi(pAd, (CHAR) pRxWI->RSSI1, RSSI_1); - pAd->ate.LastRssi2 = ATEConvertToRssi(pAd, (CHAR) pRxWI->RSSI2, RSSI_2); - pAd->ate.AvgRssi0X8 = (pAd->ate.AvgRssi0X8 - pAd->ate.AvgRssi0) + pAd->ate.LastRssi0; - pAd->ate.AvgRssi0 = pAd->ate.AvgRssi0X8 >> 3; - pAd->ate.AvgRssi1X8 = (pAd->ate.AvgRssi1X8 - pAd->ate.AvgRssi1) + pAd->ate.LastRssi1; - pAd->ate.AvgRssi1 = pAd->ate.AvgRssi1X8 >> 3; - pAd->ate.AvgRssi2X8 = (pAd->ate.AvgRssi2X8 - pAd->ate.AvgRssi2) + pAd->ate.LastRssi2; - pAd->ate.AvgRssi2 = pAd->ate.AvgRssi2X8 >> 3; - pAd->ate.NumOfAvgRssiSample ++; -#endif -} - -#ifdef CONFIG_STA_SUPPORT -VOID RTMPStationStop( - IN PRTMP_ADAPTER pAd) -{ -// BOOLEAN Cancelled; - - ATEDBGPRINT(RT_DEBUG_TRACE, ("==> RTMPStationStop\n")); - -#if 0 - RTMPCancelTimer(&pAd->MlmeAux.AssocTimer, &Cancelled); - RTMPCancelTimer(&pAd->MlmeAux.ReassocTimer, &Cancelled); - RTMPCancelTimer(&pAd->MlmeAux.DisassocTimer, &Cancelled); - RTMPCancelTimer(&pAd->MlmeAux.AuthTimer, &Cancelled); - RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer, &Cancelled); - RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &Cancelled); -#endif - // For rx statistics, we need to keep this timer running. -// RTMPCancelTimer(&pAd->Mlme.PeriodicTimer, &Cancelled); - - ATEDBGPRINT(RT_DEBUG_TRACE, ("<== RTMPStationStop\n")); -} - -VOID RTMPStationStart( - IN PRTMP_ADAPTER pAd) -{ - ATEDBGPRINT(RT_DEBUG_TRACE, ("==> RTMPStationStart\n")); - ATEDBGPRINT(RT_DEBUG_TRACE, ("<== RTMPStationStart\n")); -} -#endif // CONFIG_STA_SUPPORT // - -/* - ========================================================================== - Description: - Setup Frame format. - NOTE: - This routine should only be used in ATE mode. - ========================================================================== - */ - -#ifdef RT2870 -/*======================Start of RT2870======================*/ -/* */ -/* */ -static INT ATESetUpFrame( - IN PRTMP_ADAPTER pAd, - IN UINT32 TxIdx) -{ - UINT j; - PTX_CONTEXT pNullContext; - PUCHAR pDest; - HTTRANSMIT_SETTING TxHTPhyMode; - PTXWI_STRUC pTxWI; - PTXINFO_STRUC pTxInfo; - UINT32 TransferBufferLength, OrgBufferLength = 0; - UCHAR padLen = 0; -#ifdef RALINK_28xx_QA - PHEADER_802_11 pHeader80211 = NULL; -#endif // RALINK_28xx_QA // - - if ((RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS)) || - (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET)) || - (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) || - (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))) - { - return -1; - } - - /* We always use QID_AC_BE and FIFO_EDCA in ATE mode. */ - - pNullContext = &(pAd->NullContext); - ASSERT(pNullContext != NULL); - - if (pNullContext->InUse == FALSE) - { - // Set the in use bit - pNullContext->InUse = TRUE; - NdisZeroMemory(&(pAd->NullFrame), sizeof(HEADER_802_11)); - - // Fill 802.11 header. -#ifdef RALINK_28xx_QA - if (pAd->ate.bQATxStart == TRUE) - { - pHeader80211 = NdisMoveMemory(&(pAd->NullFrame), pAd->ate.Header, pAd->ate.HLen); -// pDest = NdisMoveMemory(&(pAd->NullFrame), pAd->ate.Header, pAd->ate.HLen); -// pHeader80211 = (PHEADER_802_11)pDest; - } - else -#endif // RALINK_28xx_QA // - { - // Fill 802.11 header. - NdisMoveMemory(&(pAd->NullFrame), TemplateFrame, sizeof(HEADER_802_11)); - } -#ifdef RT_BIG_ENDIAN - RTMPFrameEndianChange(pAd, (PUCHAR)&(pAd->NullFrame), DIR_READ, FALSE); -#endif // RT_BIG_ENDIAN // - -#ifdef RALINK_28xx_QA - if (pAd->ate.bQATxStart == TRUE) - { - /* modify sequence number.... */ - if (pAd->ate.TxDoneCount == 0) - { - pAd->ate.seq = pHeader80211->Sequence; - } - else - { - pHeader80211->Sequence = ++pAd->ate.seq; - } - /* We already got all the addr. fields from QA GUI. */ - } - else -#endif // RALINK_28xx_QA // - { - COPY_MAC_ADDR(pAd->NullFrame.Addr1, pAd->ate.Addr1); - COPY_MAC_ADDR(pAd->NullFrame.Addr2, pAd->ate.Addr2); - COPY_MAC_ADDR(pAd->NullFrame.Addr3, pAd->ate.Addr3); - } - - RTMPZeroMemory(&pAd->NullContext.TransferBuffer->field.WirelessPacket[0], TX_BUFFER_NORMSIZE);//??? - pTxInfo = (PTXINFO_STRUC)&pAd->NullContext.TransferBuffer->field.WirelessPacket[0]; - -#ifdef RALINK_28xx_QA - if (pAd->ate.bQATxStart == TRUE) - { - // Avoid to exceed the range of WirelessPacket[]. - ASSERT(pAd->ate.TxInfo.USBDMATxPktLen <= (MAX_FRAME_SIZE - 34/* == 2312 */)); - NdisMoveMemory(pTxInfo, &(pAd->ate.TxInfo), sizeof(pAd->ate.TxInfo)); - } - else -#endif // RALINK_28xx_QA // - { - // Avoid to exceed the range of WirelessPacket[]. - ASSERT(pAd->ate.TxLength <= (MAX_FRAME_SIZE - 34/* == 2312 */)); - - // pTxInfo->USBDMATxPktLen will be updated to include padding later. - ATEWriteTxInfo(pAd, pTxInfo, (USHORT)(TXWI_SIZE + pAd->ate.TxLength), TRUE, EpToQueue[MGMTPIPEIDX], FALSE, FALSE); - pTxInfo->QSEL = FIFO_EDCA; - } - - pTxWI = (PTXWI_STRUC)&pAd->NullContext.TransferBuffer->field.WirelessPacket[TXINFO_SIZE]; - - // Fill TxWI. - if (pAd->ate.bQATxStart == TRUE) - { - TxHTPhyMode.field.BW = pAd->ate.TxWI.BW; - TxHTPhyMode.field.ShortGI = pAd->ate.TxWI.ShortGI; - TxHTPhyMode.field.STBC = pAd->ate.TxWI.STBC; - TxHTPhyMode.field.MCS = pAd->ate.TxWI.MCS; - TxHTPhyMode.field.MODE = pAd->ate.TxWI.PHYMODE; - ATEWriteTxWI(pAd, pTxWI, pAd->ate.TxWI.FRAG, pAd->ate.TxWI.TS, pAd->ate.TxWI.AMPDU, pAd->ate.TxWI.ACK, pAd->ate.TxWI.NSEQ, - pAd->ate.TxWI.BAWinSize, BSSID_WCID, pAd->ate.TxWI.MPDUtotalByteCount/* include 802.11 header */, pAd->ate.TxWI.PacketId, 0, pAd->ate.TxWI.txop/*IFS_HTTXOP*/, pAd->ate.TxWI.CFACK/*FALSE*/, TxHTPhyMode); - } - else - { - TxHTPhyMode.field.BW = pAd->ate.TxWI.BW; - TxHTPhyMode.field.ShortGI = pAd->ate.TxWI.ShortGI; - TxHTPhyMode.field.STBC = 0; - TxHTPhyMode.field.MCS = pAd->ate.TxWI.MCS; - TxHTPhyMode.field.MODE = pAd->ate.TxWI.PHYMODE; - - ATEWriteTxWI(pAd, pTxWI, FALSE, FALSE, FALSE, FALSE/* No ack required. */, FALSE, 0, BSSID_WCID, pAd->ate.TxLength, - 0, 0, IFS_HTTXOP, FALSE, TxHTPhyMode);// "MMPS_STATIC" instead of "MMPS_DYNAMIC" ??? - } - - RTMPMoveMemory(&pAd->NullContext.TransferBuffer->field.WirelessPacket[TXINFO_SIZE+TXWI_SIZE], &pAd->NullFrame, sizeof(HEADER_802_11)); - - pDest = &(pAd->NullContext.TransferBuffer->field.WirelessPacket[TXINFO_SIZE+TXWI_SIZE+sizeof(HEADER_802_11)]); - - // Prepare frame payload -#ifdef RALINK_28xx_QA - if (pAd->ate.bQATxStart == TRUE) - { - // copy pattern - if ((pAd->ate.PLen != 0)) - { - for (j = 0; j < pAd->ate.DLen; j+=pAd->ate.PLen) - { - RTMPMoveMemory(pDest, pAd->ate.Pattern, pAd->ate.PLen); - pDest += pAd->ate.PLen; - } - } - TransferBufferLength = TXINFO_SIZE + TXWI_SIZE + pAd->ate.TxWI.MPDUtotalByteCount; - } - else -#endif // RALINK_28xx_QA // - { - for (j = 0; j < (pAd->ate.TxLength - sizeof(HEADER_802_11)); j++) - { - *pDest = 0xA5; - pDest += 1; - } - TransferBufferLength = TXINFO_SIZE + TXWI_SIZE + pAd->ate.TxLength; - } - -#if 1 - OrgBufferLength = TransferBufferLength; - TransferBufferLength = (TransferBufferLength + 3) & (~3); - - // Always add 4 extra bytes at every packet. - padLen = TransferBufferLength - OrgBufferLength + 4;/* 4 == last packet padding */ - ASSERT((padLen <= (RTMP_PKT_TAIL_PADDING - 4/* 4 == MaxBulkOutsize alignment padding */))); - - /* Now memzero all extra padding bytes. */ - NdisZeroMemory(pDest, padLen); - pDest += padLen; -#else - if ((TransferBufferLength % 4) == 1) - { - NdisZeroMemory(pDest, 7); - pDest += 7; - TransferBufferLength += 3; - } - else if ((TransferBufferLength % 4) == 2) - { - NdisZeroMemory(pDest, 6); - pDest += 6; - TransferBufferLength += 2; - } - else if ((TransferBufferLength % 4) == 3) - { - NdisZeroMemory(pDest, 5); - pDest += 5; - TransferBufferLength += 1; - } -#endif // 1 // - - // Update pTxInfo->USBDMATxPktLen to include padding. - pTxInfo->USBDMATxPktLen = TransferBufferLength - TXINFO_SIZE; - - TransferBufferLength += 4; - - // If TransferBufferLength is multiple of 64, add extra 4 bytes again. - if ((TransferBufferLength % pAd->BulkOutMaxPacketSize) == 0) - { - NdisZeroMemory(pDest, 4); - TransferBufferLength += 4; - } - - // Fill out frame length information for global Bulk out arbitor - pAd->NullContext.BulkOutSize = TransferBufferLength; - } -#ifdef RT_BIG_ENDIAN - RTMPWIEndianChange((PUCHAR)pTxWI, TYPE_TXWI); - RTMPFrameEndianChange(pAd, (((PUCHAR)pTxInfo)+TXWI_SIZE+TXINFO_SIZE), DIR_WRITE, FALSE); - RTMPDescriptorEndianChange((PUCHAR)pTxInfo, TYPE_TXINFO); -#endif // RT_BIG_ENDIAN // - return 0; -} - -VOID ATE_RTUSBBulkOutDataPacketComplete(purbb_t pUrb, struct pt_regs *pt_regs) -{ - PRTMP_ADAPTER pAd; - PTX_CONTEXT pNullContext; - UCHAR BulkOutPipeId; - NTSTATUS Status; - unsigned long IrqFlags; - ULONG OldValue; - - pNullContext = (PTX_CONTEXT)pUrb->context; - pAd = pNullContext->pAd; - - - // Reset Null frame context flags - pNullContext->IRPPending = FALSE; - pNullContext->InUse = FALSE; - Status = pUrb->status; - - // Store BulkOut PipeId - BulkOutPipeId = pNullContext->BulkOutPipeId; - pAd->BulkOutDataOneSecCount++; - - if (Status == USB_ST_NOERROR) - { -#ifdef RALINK_28xx_QA - if ((ATE_ON(pAd)) && (pAd->ate.bQATxStart == TRUE)) - { - if (pAd->ate.QID == BulkOutPipeId) - { - // Let Rx can have a chance to break in during Tx process, - // especially for loopback mode in QA ATE. - // To trade off between tx performance and loopback mode integrity. - /* Q : Now Rx is handled by tasklet, do we still need this delay ? */ - /* Ans : Even tasklet is used, Rx/Tx < 1 if we do not delay for a while right here. */ - RTMPusecDelay(500); - pAd->ate.TxDoneCount++; - pAd->RalinkCounters.KickTxCount++; - ASSERT(pAd->ate.QID == 0); - pAd->ate.TxAc0++; - } - } -#endif // RALINK_28xx_QA // - pAd->BulkOutComplete++; - - pAd->Counters8023.GoodTransmits++; - - /* Don't worry about the queue is empty or not. This function will check itself. */ - RTMPDeQueuePacket(pAd, TRUE, BulkOutPipeId, MAX_TX_PROCESS); - - /* In 28xx, SendTxWaitQueue ==> TxSwQueue */ -/* - if (pAd->SendTxWaitQueue[BulkOutPipeId].Number > 0) - { - RTMPDeQueuePacket(pAd, BulkOutPipeId); - } -*/ - } - else // STATUS_OTHER - { - pAd->BulkOutCompleteOther++; - - ATEDBGPRINT(RT_DEBUG_ERROR, ("BulkOutDataPacket Failed STATUS_OTHER = 0x%x . \n", Status)); - ATEDBGPRINT(RT_DEBUG_ERROR, (">>BulkOutReq=0x%lx, BulkOutComplete=0x%lx\n", pAd->BulkOutReq, pAd->BulkOutComplete)); - - if ((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS)) && - (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) && - (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) && - (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET))) - { - RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET); - /* In 28xx, RT_OID_USB_RESET_BULK_OUT ==> CMDTHREAD_RESET_BULK_OUT */ - RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_OUT, NULL, 0); - // Check - BULK_OUT_LOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); - pAd->BulkOutPending[BulkOutPipeId] = FALSE; - pAd->bulkResetPipeid = BulkOutPipeId; - BULK_OUT_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); - return; - } - } - - - - if (atomic_read(&pAd->BulkOutRemained) > 0) - { - atomic_dec(&pAd->BulkOutRemained); - } - - // 1st - Transmit Success - OldValue = pAd->WlanCounters.TransmittedFragmentCount.u.LowPart; - pAd->WlanCounters.TransmittedFragmentCount.u.LowPart++; - - if (pAd->WlanCounters.TransmittedFragmentCount.u.LowPart < OldValue) - { - pAd->WlanCounters.TransmittedFragmentCount.u.HighPart++; - } - - if(((pAd->ContinBulkOut == TRUE ) ||(atomic_read(&pAd->BulkOutRemained) > 0)) && (pAd->ate.Mode & ATE_TXFRAME)) - { - RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_ATE); - } - else - { - RTUSB_CLEAR_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_ATE); -#ifdef RALINK_28xx_QA - pAd->ate.TxStatus = 0; -#endif // RALINK_28xx_QA // - } - - BULK_OUT_LOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); - pAd->BulkOutPending[BulkOutPipeId] = FALSE; - BULK_OUT_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); - - // Always call Bulk routine, even reset bulk. - // The protection of rest bulk should be in BulkOut routine. - RTUSBKickBulkOut(pAd); -} - -/* - ======================================================================== - - Routine Description: - - Arguments: - - Return Value: - - Note: - - ======================================================================== -*/ -VOID ATE_RTUSBBulkOutDataPacket( - IN PRTMP_ADAPTER pAd, - IN UCHAR BulkOutPipeId) -{ - PTX_CONTEXT pNullContext = &(pAd->NullContext); - PURB pUrb; - int ret = 0; - unsigned long IrqFlags; - - - ASSERT(BulkOutPipeId == 0); - - /* Build up the frame first. */ -// ATESetUpFrame(pAd, 0); - - BULK_OUT_LOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); - - if (pAd->BulkOutPending[BulkOutPipeId] == TRUE) - { - BULK_OUT_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); - return; - } - - pAd->BulkOutPending[BulkOutPipeId] = TRUE; - BULK_OUT_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); - - // Increase Total transmit byte counter - pAd->RalinkCounters.OneSecTransmittedByteCount += pNullContext->BulkOutSize; - pAd->RalinkCounters.TransmittedByteCount += pNullContext->BulkOutSize; - - // Clear ATE frame bulk out flag - RTUSB_CLEAR_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_ATE); - - // Init Tx context descriptor - pNullContext->IRPPending = TRUE; - RTUSBInitTxDesc(pAd, pNullContext, BulkOutPipeId, (usb_complete_t)ATE_RTUSBBulkOutDataPacketComplete); - pUrb = pNullContext->pUrb; - - if((ret = RTUSB_SUBMIT_URB(pUrb))!=0) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("ATE_RTUSBBulkOutDataPacket: Submit Tx URB failed %d\n", ret)); - return; - } - - pAd->BulkOutReq++; - return; - -} - -/* - ======================================================================== - - Routine Description: - - Arguments: - - Return Value: - - Note: - - ======================================================================== -*/ -VOID ATE_RTUSBCancelPendingBulkInIRP( - IN PRTMP_ADAPTER pAd) -{ - PRX_CONTEXT pRxContext; - UINT i; - - ATEDBGPRINT(RT_DEBUG_TRACE, ("--->ATE_RTUSBCancelPendingBulkInIRP\n")); -#if 1 - for ( i = 0; i < (RX_RING_SIZE); i++) - { - pRxContext = &(pAd->RxContext[i]); - if(pRxContext->IRPPending == TRUE) - { - RTUSB_UNLINK_URB(pRxContext->pUrb); - pRxContext->IRPPending = FALSE; - pRxContext->InUse = FALSE; - //NdisInterlockedDecrement(&pAd->PendingRx); - //pAd->PendingRx--; - } - } -#else - for ( i = 0; i < (RX_RING_SIZE); i++) - { - pRxContext = &(pAd->RxContext[i]); - if(atomic_read(&pRxContext->IrpLock) == IRPLOCK_CANCELABLE) - { - RTUSB_UNLINK_URB(pRxContext->pUrb); - } - InterlockedExchange(&pRxContext->IrpLock, IRPLOCK_CANCE_START); - } -#endif // 1 // - ATEDBGPRINT(RT_DEBUG_TRACE, ("<---ATE_RTUSBCancelPendingBulkInIRP\n")); - return; -} -#endif // RT2870 // - -VOID rt_ee_read_all(PRTMP_ADAPTER pAd, USHORT *Data) -{ - USHORT i; - USHORT value; - - for (i = 0 ; i < EEPROM_SIZE/2 ; ) - { - /* "value" is expecially for some compilers... */ - RT28xx_EEPROM_READ16(pAd, i*2, value); - Data[i] = value; - i++; - } -} - -VOID rt_ee_write_all(PRTMP_ADAPTER pAd, USHORT *Data) -{ - USHORT i; - USHORT value; - - for (i = 0 ; i < EEPROM_SIZE/2 ; ) - { - /* "value" is expecially for some compilers... */ - value = Data[i]; - RT28xx_EEPROM_WRITE16(pAd, i*2, value); - i ++; - } -} -#ifdef RALINK_28xx_QA -VOID ATE_QA_Statistics( - IN PRTMP_ADAPTER pAd, - IN PRXWI_STRUC pRxWI, - IN PRT28XX_RXD_STRUC pRxD, - IN PHEADER_802_11 pHeader) -{ - // update counter first - if (pHeader != NULL) - { - if (pHeader->FC.Type == BTYPE_DATA) - { - if (pRxD->U2M) - pAd->ate.U2M++; - else - pAd->ate.OtherData++; - } - else if (pHeader->FC.Type == BTYPE_MGMT) - { - if (pHeader->FC.SubType == SUBTYPE_BEACON) - pAd->ate.Beacon++; - else - pAd->ate.OtherCount++; - } - else if (pHeader->FC.Type == BTYPE_CNTL) - { - pAd->ate.OtherCount++; - } - } - pAd->ate.RSSI0 = pRxWI->RSSI0; - pAd->ate.RSSI1 = pRxWI->RSSI1; - pAd->ate.RSSI2 = pRxWI->RSSI2; - pAd->ate.SNR0 = pRxWI->SNR0; - pAd->ate.SNR1 = pRxWI->SNR1; -} - -/* command id with Cmd Type == 0x0008(for 28xx)/0x0005(for iNIC) */ -#define RACFG_CMD_RF_WRITE_ALL 0x0000 -#define RACFG_CMD_E2PROM_READ16 0x0001 -#define RACFG_CMD_E2PROM_WRITE16 0x0002 -#define RACFG_CMD_E2PROM_READ_ALL 0x0003 -#define RACFG_CMD_E2PROM_WRITE_ALL 0x0004 -#define RACFG_CMD_IO_READ 0x0005 -#define RACFG_CMD_IO_WRITE 0x0006 -#define RACFG_CMD_IO_READ_BULK 0x0007 -#define RACFG_CMD_BBP_READ8 0x0008 -#define RACFG_CMD_BBP_WRITE8 0x0009 -#define RACFG_CMD_BBP_READ_ALL 0x000a -#define RACFG_CMD_GET_COUNTER 0x000b -#define RACFG_CMD_CLEAR_COUNTER 0x000c - -#define RACFG_CMD_RSV1 0x000d -#define RACFG_CMD_RSV2 0x000e -#define RACFG_CMD_RSV3 0x000f - -#define RACFG_CMD_TX_START 0x0010 -#define RACFG_CMD_GET_TX_STATUS 0x0011 -#define RACFG_CMD_TX_STOP 0x0012 -#define RACFG_CMD_RX_START 0x0013 -#define RACFG_CMD_RX_STOP 0x0014 -#define RACFG_CMD_GET_NOISE_LEVEL 0x0015 - -#define RACFG_CMD_ATE_START 0x0080 -#define RACFG_CMD_ATE_STOP 0x0081 - -#define RACFG_CMD_ATE_START_TX_CARRIER 0x0100 -#define RACFG_CMD_ATE_START_TX_CONT 0x0101 -#define RACFG_CMD_ATE_START_TX_FRAME 0x0102 -#define RACFG_CMD_ATE_SET_BW 0x0103 -#define RACFG_CMD_ATE_SET_TX_POWER0 0x0104 -#define RACFG_CMD_ATE_SET_TX_POWER1 0x0105 -#define RACFG_CMD_ATE_SET_FREQ_OFFSET 0x0106 -#define RACFG_CMD_ATE_GET_STATISTICS 0x0107 -#define RACFG_CMD_ATE_RESET_COUNTER 0x0108 -#define RACFG_CMD_ATE_SEL_TX_ANTENNA 0x0109 -#define RACFG_CMD_ATE_SEL_RX_ANTENNA 0x010a -#define RACFG_CMD_ATE_SET_PREAMBLE 0x010b -#define RACFG_CMD_ATE_SET_CHANNEL 0x010c -#define RACFG_CMD_ATE_SET_ADDR1 0x010d -#define RACFG_CMD_ATE_SET_ADDR2 0x010e -#define RACFG_CMD_ATE_SET_ADDR3 0x010f -#define RACFG_CMD_ATE_SET_RATE 0x0110 -#define RACFG_CMD_ATE_SET_TX_FRAME_LEN 0x0111 -#define RACFG_CMD_ATE_SET_TX_FRAME_COUNT 0x0112 -#define RACFG_CMD_ATE_START_RX_FRAME 0x0113 -#define RACFG_CMD_ATE_E2PROM_READ_BULK 0x0114 -#define RACFG_CMD_ATE_E2PROM_WRITE_BULK 0x0115 -#define RACFG_CMD_ATE_IO_WRITE_BULK 0x0116 -#define RACFG_CMD_ATE_BBP_READ_BULK 0x0117 -#define RACFG_CMD_ATE_BBP_WRITE_BULK 0x0118 -#define RACFG_CMD_ATE_RF_READ_BULK 0x0119 -#define RACFG_CMD_ATE_RF_WRITE_BULK 0x011a - - - -#define A2Hex(_X, _p) \ -{ \ - UCHAR *p; \ - _X = 0; \ - p = _p; \ - while (((*p >= 'a') && (*p <= 'f')) || ((*p >= 'A') && (*p <= 'F')) || ((*p >= '0') && (*p <= '9'))) \ - { \ - if ((*p >= 'a') && (*p <= 'f')) \ - _X = _X * 16 + *p - 87; \ - else if ((*p >= 'A') && (*p <= 'F')) \ - _X = _X * 16 + *p - 55; \ - else if ((*p >= '0') && (*p <= '9')) \ - _X = _X * 16 + *p - 48; \ - p++; \ - } \ -} - - -static VOID memcpy_exl(PRTMP_ADAPTER pAd, UCHAR *dst, UCHAR *src, ULONG len); -static VOID memcpy_exs(PRTMP_ADAPTER pAd, UCHAR *dst, UCHAR *src, ULONG len); -static VOID RTMP_IO_READ_BULK(PRTMP_ADAPTER pAd, UCHAR *dst, UCHAR *src, UINT32 len); - -#ifdef UCOS -int ate_copy_to_user( - IN PUCHAR payload, - IN PUCHAR msg, - IN INT len) -{ - memmove(payload, msg, len); - return 0; -} - -#undef copy_to_user -#define copy_to_user(x,y,z) ate_copy_to_user((PUCHAR)x, (PUCHAR)y, z) -#endif // UCOS // - -#define LEN_OF_ARG 16 - -VOID RtmpDoAte( - IN PRTMP_ADAPTER pAdapter, - IN struct iwreq *wrq) -{ - unsigned short Command_Id; - struct ate_racfghdr *pRaCfg; - INT Status = NDIS_STATUS_SUCCESS; - - - - if((pRaCfg = kmalloc(sizeof(struct ate_racfghdr), GFP_KERNEL)) == NULL) - { - Status = -EINVAL; - return; - } - - NdisZeroMemory(pRaCfg, sizeof(struct ate_racfghdr)); - - if (copy_from_user((PUCHAR)pRaCfg, wrq->u.data.pointer, wrq->u.data.length)) - { - Status = -EFAULT; - kfree(pRaCfg); - return; - } - - - Command_Id = ntohs(pRaCfg->command_id); - - ATEDBGPRINT(RT_DEBUG_TRACE,("\n%s: Command_Id = 0x%04x !\n", __func__, Command_Id)); - - switch (Command_Id) - { - // We will get this command when QA starts. - case RACFG_CMD_ATE_START: - { - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_START\n")); - - // prepare feedback as soon as we can to avoid QA timeout. - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - ATEDBGPRINT(RT_DEBUG_TRACE, ("wrq->u.data.length = %d\n", wrq->u.data.length)); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("copy_to_user() fail in case RACFG_CMD_ATE_START\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_START is done !\n")); - } - Set_ATE_Proc(pAdapter, "ATESTART"); - } - break; - - // We will get this command either QA is closed or ated is killed by user. - case RACFG_CMD_ATE_STOP: - { -#ifndef UCOS - INT32 ret; -#endif // !UCOS // - - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_STOP\n")); - - // Distinguish this command came from QA(via ated) - // or ate daemon according to the existence of pid in payload. - // No need to prepare feedback if this cmd came directly from ate daemon. - pRaCfg->length = ntohs(pRaCfg->length); - - if (pRaCfg->length == sizeof(pAdapter->ate.AtePid)) - { - // This command came from QA. - // Get the pid of ATE daemon. - memcpy((UCHAR *)&pAdapter->ate.AtePid, - (&pRaCfg->data[0]) - 2/* == &(pRaCfg->status) */, - sizeof(pAdapter->ate.AtePid)); - - // prepare feedback as soon as we can to avoid QA timeout. - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - ATEDBGPRINT(RT_DEBUG_TRACE, ("wrq->u.data.length = %d\n", wrq->u.data.length)); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_STOP\n")); - Status = -EFAULT; - } - - // - // kill ATE daemon when leaving ATE mode. - // We must kill ATE daemon first before setting ATESTOP, - // or Microsoft will report sth. wrong. -#ifndef UCOS - ret = KILL_THREAD_PID(pAdapter->ate.AtePid, SIGTERM, 1); - if (ret) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("%s: unable to signal thread\n", pAdapter->net_dev->name)); - } -#endif // !UCOS // - } - - // AP might have in ATE_STOP mode due to cmd from QA. - if (ATE_ON(pAdapter)) - { - // Someone has killed ate daemon while QA GUI is still open. - Set_ATE_Proc(pAdapter, "ATESTOP"); - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_AP_START is done !\n")); - } - } - break; - - case RACFG_CMD_RF_WRITE_ALL: - { - UINT32 R1, R2, R3, R4; - USHORT channel; - - memcpy(&R1, pRaCfg->data-2, 4); - memcpy(&R2, pRaCfg->data+2, 4); - memcpy(&R3, pRaCfg->data+6, 4); - memcpy(&R4, pRaCfg->data+10, 4); - memcpy(&channel, pRaCfg->data+14, 2); - - pAdapter->LatchRfRegs.R1 = ntohl(R1); - pAdapter->LatchRfRegs.R2 = ntohl(R2); - pAdapter->LatchRfRegs.R3 = ntohl(R3); - pAdapter->LatchRfRegs.R4 = ntohl(R4); - pAdapter->LatchRfRegs.Channel = ntohs(channel); - - RTMP_RF_IO_WRITE32(pAdapter, pAdapter->LatchRfRegs.R1); - RTMP_RF_IO_WRITE32(pAdapter, pAdapter->LatchRfRegs.R2); - RTMP_RF_IO_WRITE32(pAdapter, pAdapter->LatchRfRegs.R3); - RTMP_RF_IO_WRITE32(pAdapter, pAdapter->LatchRfRegs.R4); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - ATEDBGPRINT(RT_DEBUG_TRACE, ("wrq->u.data.length = %d\n", wrq->u.data.length)); - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_RF_WRITE_ALL\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_RF_WRITE_ALL is done !\n")); - } - } - break; - - case RACFG_CMD_E2PROM_READ16: - { - USHORT offset, value, tmp; - - offset = ntohs(pRaCfg->status); - /* "tmp" is expecially for some compilers... */ - RT28xx_EEPROM_READ16(pAdapter, offset, tmp); - value = tmp; - value = htons(value); - - ATEDBGPRINT(RT_DEBUG_TRACE,("EEPROM Read offset = 0x%04x, value = 0x%04x\n", offset, value)); - - // prepare feedback - pRaCfg->length = htons(4); - pRaCfg->status = htons(0); - memcpy(pRaCfg->data, &value, 2); - - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - ATEDBGPRINT(RT_DEBUG_TRACE, ("sizeof(struct ate_racfghdr) = %d\n", sizeof(struct ate_racfghdr))); - ATEDBGPRINT(RT_DEBUG_TRACE, ("wrq->u.data.length = %d\n", wrq->u.data.length)); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_E2PROM_READ16\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_E2PROM_READ16 is done !\n")); - } - } - break; - - case RACFG_CMD_E2PROM_WRITE16: - { - USHORT offset, value; - - offset = ntohs(pRaCfg->status); - memcpy(&value, pRaCfg->data, 2); - value = ntohs(value); - RT28xx_EEPROM_WRITE16(pAdapter, offset, value); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_E2PROM_WRITE16\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_E2PROM_WRITE16 is done !\n")); - } - } - break; - - case RACFG_CMD_E2PROM_READ_ALL: - { - USHORT buffer[EEPROM_SIZE/2]; - - rt_ee_read_all(pAdapter,(USHORT *)buffer); - memcpy_exs(pAdapter, pRaCfg->data, (UCHAR *)buffer, EEPROM_SIZE); - - // prepare feedback - pRaCfg->length = htons(2+EEPROM_SIZE); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_E2PROM_READ_ALL\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_E2PROM_READ_ALL is done !\n")); - } - } - break; - - case RACFG_CMD_E2PROM_WRITE_ALL: - { - USHORT buffer[EEPROM_SIZE/2]; - - NdisZeroMemory((UCHAR *)buffer, EEPROM_SIZE); - memcpy_exs(pAdapter, (UCHAR *)buffer, (UCHAR *)&pRaCfg->status, EEPROM_SIZE); - rt_ee_write_all(pAdapter,(USHORT *)buffer); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_E2PROM_WRITE_ALL\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("RACFG_CMD_E2PROM_WRITE_ALL is done !\n")); - } - - } - break; - - case RACFG_CMD_IO_READ: - { - UINT32 offset; - UINT32 value; - - memcpy(&offset, &pRaCfg->status, 4); - offset = ntohl(offset); - - // We do not need the base address. - // So just extract the offset out. - offset &= 0x0000FFFF; - RTMP_IO_READ32(pAdapter, offset, &value); - value = htonl(value); - - // prepare feedback - pRaCfg->length = htons(6); - pRaCfg->status = htons(0); - memcpy(pRaCfg->data, &value, 4); - - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_IO_READ\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_IO_READ is done !\n")); - } - } - break; - - case RACFG_CMD_IO_WRITE: - { - UINT32 offset, value; - - memcpy(&offset, pRaCfg->data-2, 4); - memcpy(&value, pRaCfg->data+2, 4); - - offset = ntohl(offset); - - // We do not need the base address. - // So just extract out the offset. - offset &= 0x0000FFFF; - value = ntohl(value); - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_IO_WRITE: offset = %x, value = %x\n", offset, value)); - RTMP_IO_WRITE32(pAdapter, offset, value); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_IO_WRITE\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_IO_WRITE is done !\n")); - } - } - break; - - case RACFG_CMD_IO_READ_BULK: - { - UINT32 offset; - USHORT len; - - memcpy(&offset, &pRaCfg->status, 4); - offset = ntohl(offset); - - // We do not need the base address. - // So just extract the offset. - offset &= 0x0000FFFF; - memcpy(&len, pRaCfg->data+2, 2); - len = ntohs(len); - - if (len > 371) - { - ATEDBGPRINT(RT_DEBUG_TRACE,("len is too large, make it smaller\n")); - pRaCfg->length = htons(2); - pRaCfg->status = htons(1); - break; - } - - RTMP_IO_READ_BULK(pAdapter, pRaCfg->data, (UCHAR *)offset, len*4);// unit in four bytes - - // prepare feedback - pRaCfg->length = htons(2+len*4);// unit in four bytes - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_IO_READ_BULK\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_IO_READ_BULK is done !\n")); - } - } - break; - - case RACFG_CMD_BBP_READ8: - { - USHORT offset; - UCHAR value; - - value = 0; - offset = ntohs(pRaCfg->status); - - if (ATE_ON(pAdapter)) - { - ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, offset, &value); - } - else - { - RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, offset, &value); - } - // prepare feedback - pRaCfg->length = htons(3); - pRaCfg->status = htons(0); - pRaCfg->data[0] = value; - - ATEDBGPRINT(RT_DEBUG_TRACE,("BBP value = %x\n", value)); - - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_BBP_READ8\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_BBP_READ8 is done !\n")); - } - } - break; - case RACFG_CMD_BBP_WRITE8: - { - USHORT offset; - UCHAR value; - - offset = ntohs(pRaCfg->status); - memcpy(&value, pRaCfg->data, 1); - - if (ATE_ON(pAdapter)) - { - ATE_BBP_IO_WRITE8_BY_REG_ID(pAdapter, offset, value); - } - else - { - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, offset, value); - } - - if ((offset == BBP_R1) || (offset == BBP_R3)) - { - SyncTxRxConfig(pAdapter, offset, value); - } - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_BBP_WRITE8\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_BBP_WRITE8 is done !\n")); - } - } - break; - - case RACFG_CMD_BBP_READ_ALL: - { - USHORT j; - - for (j = 0; j < 137; j++) - { - pRaCfg->data[j] = 0; - - if (ATE_ON(pAdapter)) - { - ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, j, &pRaCfg->data[j]); - } - else - { - RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, j, &pRaCfg->data[j]); - } - } - - // prepare feedback - pRaCfg->length = htons(2+137); - pRaCfg->status = htons(0); - - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_BBP_READ_ALL\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_BBP_READ_ALL is done !\n")); - } - } - - break; - - case RACFG_CMD_ATE_E2PROM_READ_BULK: - { - USHORT offset; - USHORT len; - USHORT buffer[EEPROM_SIZE/2]; - - offset = ntohs(pRaCfg->status); - memcpy(&len, pRaCfg->data, 2); - len = ntohs(len); - - rt_ee_read_all(pAdapter,(USHORT *)buffer); - if (offset + len <= EEPROM_SIZE) - memcpy_exs(pAdapter, pRaCfg->data, (UCHAR *)buffer+offset, len); - else - ATEDBGPRINT(RT_DEBUG_ERROR, ("exceed EEPROM size\n")); - - // prepare feedback - pRaCfg->length = htons(2+len); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_E2PROM_READ_BULK\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_E2PROM_READ_BULK is done !\n")); - } - - } - break; - - case RACFG_CMD_ATE_E2PROM_WRITE_BULK: - { - USHORT offset; - USHORT len; - USHORT buffer[EEPROM_SIZE/2]; - - offset = ntohs(pRaCfg->status); - memcpy(&len, pRaCfg->data, 2); - len = ntohs(len); - - rt_ee_read_all(pAdapter,(USHORT *)buffer); - memcpy_exs(pAdapter, (UCHAR *)buffer + offset, (UCHAR *)pRaCfg->data + 2, len); - rt_ee_write_all(pAdapter,(USHORT *)buffer); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_E2PROM_WRITE_BULK\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("RACFG_CMD_ATE_E2PROM_WRITE_BULK is done !\n")); - } - - } - break; - - case RACFG_CMD_ATE_IO_WRITE_BULK: - { - UINT32 offset, i, value; - USHORT len; - - memcpy(&offset, &pRaCfg->status, 4); - offset = ntohl(offset); - memcpy(&len, pRaCfg->data+2, 2); - len = ntohs(len); - - for (i = 0; i < len; i += 4) - { - memcpy_exl(pAdapter, (UCHAR *)&value, pRaCfg->data+4+i, 4); - printk("Write %x %x\n", offset + i, value); - RTMP_IO_WRITE32(pAdapter, (offset +i) & 0xffff, value); - } - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_IO_WRITE_BULK\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("RACFG_CMD_ATE_IO_WRITE_BULK is done !\n")); - } - - } - break; - - case RACFG_CMD_ATE_BBP_READ_BULK: - { - USHORT offset; - USHORT len; - USHORT j; - - offset = ntohs(pRaCfg->status); - memcpy(&len, pRaCfg->data, 2); - len = ntohs(len); - - - for (j = offset; j < (offset+len); j++) - { - pRaCfg->data[j - offset] = 0; - - if (pAdapter->ate.Mode == ATE_STOP) - { - RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, j, &pRaCfg->data[j - offset]); - } - else - { - ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, j, &pRaCfg->data[j - offset]); - } - } - - // prepare feedback - pRaCfg->length = htons(2+len); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_BBP_READ_BULK\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_BBP_READ_BULK is done !\n")); - } - - } - break; - - case RACFG_CMD_ATE_BBP_WRITE_BULK: - { - USHORT offset; - USHORT len; - USHORT j; - UCHAR *value; - - offset = ntohs(pRaCfg->status); - memcpy(&len, pRaCfg->data, 2); - len = ntohs(len); - - for (j = offset; j < (offset+len); j++) - { - value = pRaCfg->data + 2 + (j - offset); - if (pAdapter->ate.Mode == ATE_STOP) - { - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, j, *value); - } - else - { - ATE_BBP_IO_WRITE8_BY_REG_ID(pAdapter, j, *value); - } - } - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_BBP_WRITE_BULK\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_BBP_WRITE_BULK is done !\n")); - } - } - break; - -#ifdef CONFIG_RALINK_RT3052 - case RACFG_CMD_ATE_RF_READ_BULK: - { - USHORT offset; - USHORT len; - USHORT j; - - offset = ntohs(pRaCfg->status); - memcpy(&len, pRaCfg->data, 2); - len = ntohs(len); - - for (j = offset; j < (offset+len); j++) - { - pRaCfg->data[j - offset] = 0; - RT30xxReadRFRegister(pAdapter, j, &pRaCfg->data[j - offset]); - } - - // prepare feedback - pRaCfg->length = htons(2+len); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_RF_READ_BULK\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_RF_READ_BULK is done !\n")); - } - - } - break; - - case RACFG_CMD_ATE_RF_WRITE_BULK: - { - USHORT offset; - USHORT len; - USHORT j; - UCHAR *value; - - offset = ntohs(pRaCfg->status); - memcpy(&len, pRaCfg->data, 2); - len = ntohs(len); - - for (j = offset; j < (offset+len); j++) - { - value = pRaCfg->data + 2 + (j - offset); - RT30xxWriteRFRegister(pAdapter, j, *value); - } - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_RF_WRITE_BULK\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_RF_WRITE_BULK is done !\n")); - } - - } - break; -#endif - - - case RACFG_CMD_GET_NOISE_LEVEL: - { - UCHAR channel; - INT32 buffer[3][10];/* 3 : RxPath ; 10 : no. of per rssi samples */ - - channel = (ntohs(pRaCfg->status) & 0x00FF); - CalNoiseLevel(pAdapter, channel, buffer); - memcpy_exl(pAdapter, (UCHAR *)pRaCfg->data, (UCHAR *)&(buffer[0][0]), (sizeof(INT32)*3*10)); - - // prepare feedback - pRaCfg->length = htons(2 + (sizeof(INT32)*3*10)); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_GET_NOISE_LEVEL\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_GET_NOISE_LEVEL is done !\n")); - } - } - break; - - case RACFG_CMD_GET_COUNTER: - { - memcpy_exl(pAdapter, &pRaCfg->data[0], (UCHAR *)&pAdapter->ate.U2M, 4); - memcpy_exl(pAdapter, &pRaCfg->data[4], (UCHAR *)&pAdapter->ate.OtherData, 4); - memcpy_exl(pAdapter, &pRaCfg->data[8], (UCHAR *)&pAdapter->ate.Beacon, 4); - memcpy_exl(pAdapter, &pRaCfg->data[12], (UCHAR *)&pAdapter->ate.OtherCount, 4); - memcpy_exl(pAdapter, &pRaCfg->data[16], (UCHAR *)&pAdapter->ate.TxAc0, 4); - memcpy_exl(pAdapter, &pRaCfg->data[20], (UCHAR *)&pAdapter->ate.TxAc1, 4); - memcpy_exl(pAdapter, &pRaCfg->data[24], (UCHAR *)&pAdapter->ate.TxAc2, 4); - memcpy_exl(pAdapter, &pRaCfg->data[28], (UCHAR *)&pAdapter->ate.TxAc3, 4); - memcpy_exl(pAdapter, &pRaCfg->data[32], (UCHAR *)&pAdapter->ate.TxHCCA, 4); - memcpy_exl(pAdapter, &pRaCfg->data[36], (UCHAR *)&pAdapter->ate.TxMgmt, 4); - memcpy_exl(pAdapter, &pRaCfg->data[40], (UCHAR *)&pAdapter->ate.RSSI0, 4); - memcpy_exl(pAdapter, &pRaCfg->data[44], (UCHAR *)&pAdapter->ate.RSSI1, 4); - memcpy_exl(pAdapter, &pRaCfg->data[48], (UCHAR *)&pAdapter->ate.RSSI2, 4); - memcpy_exl(pAdapter, &pRaCfg->data[52], (UCHAR *)&pAdapter->ate.SNR0, 4); - memcpy_exl(pAdapter, &pRaCfg->data[56], (UCHAR *)&pAdapter->ate.SNR1, 4); - - pRaCfg->length = htons(2+60); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_GET_COUNTER\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_GET_COUNTER is done !\n")); - } - } - break; - - case RACFG_CMD_CLEAR_COUNTER: - { - pAdapter->ate.U2M = 0; - pAdapter->ate.OtherData = 0; - pAdapter->ate.Beacon = 0; - pAdapter->ate.OtherCount = 0; - pAdapter->ate.TxAc0 = 0; - pAdapter->ate.TxAc1 = 0; - pAdapter->ate.TxAc2 = 0; - pAdapter->ate.TxAc3 = 0; - pAdapter->ate.TxHCCA = 0; - pAdapter->ate.TxMgmt = 0; - pAdapter->ate.TxDoneCount = 0; - - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_CLEAR_COUNTER\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_CLEAR_COUNTER is done !\n")); - } - } - - break; - - case RACFG_CMD_TX_START: - { - USHORT *p; - USHORT err = 1; - UCHAR Bbp22Value = 0, Bbp24Value = 0; - - if ((pAdapter->ate.TxStatus != 0) && (pAdapter->ate.Mode & ATE_TXFRAME)) - { - ATEDBGPRINT(RT_DEBUG_TRACE,("Ate Tx is already running, to run next Tx, you must stop it first\n")); - err = 2; - goto TX_START_ERROR; - } - else if ((pAdapter->ate.TxStatus != 0) && !(pAdapter->ate.Mode & ATE_TXFRAME)) - { - int i = 0; - - while ((i++ < 10) && (pAdapter->ate.TxStatus != 0)) - { - RTMPusecDelay(5000); - } - - // force it to stop - pAdapter->ate.TxStatus = 0; - pAdapter->ate.TxDoneCount = 0; - //pAdapter->ate.Repeat = 0; - pAdapter->ate.bQATxStart = FALSE; - } - - // If pRaCfg->length == 0, this "RACFG_CMD_TX_START" is for Carrier test or Carrier Suppression. - if (ntohs(pRaCfg->length) != 0) - { - // Get frame info -#ifdef RT2870 - NdisMoveMemory(&pAdapter->ate.TxInfo, pRaCfg->data - 2, 4); -#ifdef RT_BIG_ENDIAN - RTMPDescriptorEndianChange((PUCHAR) &pAdapter->ate.TxInfo, TYPE_TXINFO); -#endif // RT_BIG_ENDIAN // -#endif // RT2870 // - - NdisMoveMemory(&pAdapter->ate.TxWI, pRaCfg->data + 2, 16); -#ifdef RT_BIG_ENDIAN - RTMPWIEndianChange((PUCHAR)&pAdapter->ate.TxWI, TYPE_TXWI); -#endif // RT_BIG_ENDIAN // - - NdisMoveMemory(&pAdapter->ate.TxCount, pRaCfg->data + 18, 4); - pAdapter->ate.TxCount = ntohl(pAdapter->ate.TxCount); - - p = (USHORT *)(&pRaCfg->data[22]); - //p = pRaCfg->data + 22; - // always use QID_AC_BE - pAdapter->ate.QID = 0; - p = (USHORT *)(&pRaCfg->data[24]); - //p = pRaCfg->data + 24; - pAdapter->ate.HLen = ntohs(*p); - - if (pAdapter->ate.HLen > 32) - { - ATEDBGPRINT(RT_DEBUG_ERROR,("pAdapter->ate.HLen > 32\n")); - err = 3; - goto TX_START_ERROR; - } - - NdisMoveMemory(&pAdapter->ate.Header, pRaCfg->data + 26, pAdapter->ate.HLen); - - - pAdapter->ate.PLen = ntohs(pRaCfg->length) - (pAdapter->ate.HLen + 28); - - if (pAdapter->ate.PLen > 32) - { - ATEDBGPRINT(RT_DEBUG_ERROR,("pAdapter->ate.PLen > 32\n")); - err = 4; - goto TX_START_ERROR; - } - - NdisMoveMemory(&pAdapter->ate.Pattern, pRaCfg->data + 26 + pAdapter->ate.HLen, pAdapter->ate.PLen); - pAdapter->ate.DLen = pAdapter->ate.TxWI.MPDUtotalByteCount - pAdapter->ate.HLen; - } - - ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, BBP_R22, &Bbp22Value); - - switch (Bbp22Value) - { - case BBP22_TXFRAME: - { - if (pAdapter->ate.TxCount == 0) - { - } - ATEDBGPRINT(RT_DEBUG_TRACE,("START TXFRAME\n")); - pAdapter->ate.bQATxStart = TRUE; - Set_ATE_Proc(pAdapter, "TXFRAME"); - } - break; - - case BBP22_TXCONT_OR_CARRSUPP: - { - ATEDBGPRINT(RT_DEBUG_TRACE,("BBP22_TXCONT_OR_CARRSUPP\n")); - ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, 24, &Bbp24Value); - - switch (Bbp24Value) - { - case BBP24_TXCONT: - { - ATEDBGPRINT(RT_DEBUG_TRACE,("START TXCONT\n")); - pAdapter->ate.bQATxStart = TRUE; - Set_ATE_Proc(pAdapter, "TXCONT"); - } - break; - - case BBP24_CARRSUPP: - { - ATEDBGPRINT(RT_DEBUG_TRACE,("START TXCARRSUPP\n")); - pAdapter->ate.bQATxStart = TRUE; - pAdapter->ate.Mode |= ATE_TXCARRSUPP; - } - break; - - default: - { - ATEDBGPRINT(RT_DEBUG_ERROR,("Unknown Start TX subtype !")); - } - break; - } - } - break; - - case BBP22_TXCARR: - { - ATEDBGPRINT(RT_DEBUG_TRACE,("START TXCARR\n")); - pAdapter->ate.bQATxStart = TRUE; - Set_ATE_Proc(pAdapter, "TXCARR"); - } - break; - - default: - { - ATEDBGPRINT(RT_DEBUG_ERROR,("Unknown Start TX subtype !")); - } - break; - } - - if (pAdapter->ate.bQATxStart == TRUE) - { - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() was failed in case RACFG_CMD_TX_START\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_TX_START is done !\n")); - } - break; - } - -TX_START_ERROR: - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(err); - - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_TX_START\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("feedback of TX_START_ERROR is done !\n")); - } - } - break; - - case RACFG_CMD_GET_TX_STATUS: - { - UINT32 count; - - // prepare feedback - pRaCfg->length = htons(6); - pRaCfg->status = htons(0); - count = htonl(pAdapter->ate.TxDoneCount); - NdisMoveMemory(pRaCfg->data, &count, 4); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_GET_TX_STATUS\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_GET_TX_STATUS is done !\n")); - } - } - break; - - case RACFG_CMD_TX_STOP: - { - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_TX_STOP\n")); - - Set_ATE_Proc(pAdapter, "TXSTOP"); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("copy_to_user() fail in case RACFG_CMD_TX_STOP\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_TX_STOP is done !\n")); - } - } - break; - - case RACFG_CMD_RX_START: - { - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_RX_START\n")); - - pAdapter->ate.bQARxStart = TRUE; - Set_ATE_Proc(pAdapter, "RXFRAME"); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_RX_START\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_RX_START is done !\n")); - } - } - break; - - case RACFG_CMD_RX_STOP: - { - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_RX_STOP\n")); - - Set_ATE_Proc(pAdapter, "RXSTOP"); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_RX_STOP\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_RX_STOP is done !\n")); - } - } - break; - - /* The following cases are for new ATE GUI(not QA). */ - /*==================================================*/ - case RACFG_CMD_ATE_START_TX_CARRIER: - { - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_START_TX_CARRIER\n")); - - Set_ATE_Proc(pAdapter, "TXCARR"); - - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - ATEDBGPRINT(RT_DEBUG_TRACE, ("wrq->u.data.length = %d\n", wrq->u.data.length)); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_START_TX_CARRIER\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_START_TX_CARRIER is done !\n")); - } - } - break; - - case RACFG_CMD_ATE_START_TX_CONT: - { - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_START_TX_CONT\n")); - - Set_ATE_Proc(pAdapter, "TXCONT"); - - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - ATEDBGPRINT(RT_DEBUG_TRACE, ("wrq->u.data.length = %d\n", wrq->u.data.length)); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_START_TX_CONT\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_START_TX_CONT is done !\n")); - } - } - break; - - case RACFG_CMD_ATE_START_TX_FRAME: - { - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_START_TX_FRAME\n")); - - Set_ATE_Proc(pAdapter, "TXFRAME"); - - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - ATEDBGPRINT(RT_DEBUG_TRACE, ("wrq->u.data.length = %d\n", wrq->u.data.length)); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_START_TX_FRAME\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_START_TX_FRAME is done !\n")); - } - } - break; - - case RACFG_CMD_ATE_SET_BW: - { - SHORT value = 0; - UCHAR str[LEN_OF_ARG]; - - NdisZeroMemory(str, LEN_OF_ARG); - - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_BW\n")); - - memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); - value = ntohs(value); - sprintf((PCHAR)str, "%d", value); - - Set_ATE_TX_BW_Proc(pAdapter, str); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_BW\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_BW is done !\n")); - } - } - break; - - case RACFG_CMD_ATE_SET_TX_POWER0: - { - SHORT value = 0; - UCHAR str[LEN_OF_ARG]; - - NdisZeroMemory(str, LEN_OF_ARG); - - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_TX_POWER0\n")); - - memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); - value = ntohs(value); - sprintf((PCHAR)str, "%d", value); - Set_ATE_TX_POWER0_Proc(pAdapter, str); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_TX_POWER0\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_TX_POWER0 is done !\n")); - } - } - break; - - case RACFG_CMD_ATE_SET_TX_POWER1: - { - SHORT value = 0; - UCHAR str[LEN_OF_ARG]; - - NdisZeroMemory(str, LEN_OF_ARG); - - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_TX_POWER1\n")); - - memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); - value = ntohs(value); - sprintf((PCHAR)str, "%d", value); - Set_ATE_TX_POWER1_Proc(pAdapter, str); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_TX_POWER1\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_TX_POWER1 is done !\n")); - } - } - break; - - case RACFG_CMD_ATE_SET_FREQ_OFFSET: - { - SHORT value = 0; - UCHAR str[LEN_OF_ARG]; - - NdisZeroMemory(str, LEN_OF_ARG); - - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_FREQ_OFFSET\n")); - - memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); - value = ntohs(value); - sprintf((PCHAR)str, "%d", value); - Set_ATE_TX_FREQOFFSET_Proc(pAdapter, str); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_FREQ_OFFSET\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_FREQ_OFFSET is done !\n")); - } - } - break; - - case RACFG_CMD_ATE_GET_STATISTICS: - { - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_GET_STATISTICS\n")); - - memcpy_exl(pAdapter, &pRaCfg->data[0], (UCHAR *)&pAdapter->ate.TxDoneCount, 4); - memcpy_exl(pAdapter, &pRaCfg->data[4], (UCHAR *)&pAdapter->WlanCounters.RetryCount.u.LowPart, 4); - memcpy_exl(pAdapter, &pRaCfg->data[8], (UCHAR *)&pAdapter->WlanCounters.FailedCount.u.LowPart, 4); - memcpy_exl(pAdapter, &pRaCfg->data[12], (UCHAR *)&pAdapter->WlanCounters.RTSSuccessCount.u.LowPart, 4); - memcpy_exl(pAdapter, &pRaCfg->data[16], (UCHAR *)&pAdapter->WlanCounters.RTSFailureCount.u.LowPart, 4); - memcpy_exl(pAdapter, &pRaCfg->data[20], (UCHAR *)&pAdapter->WlanCounters.ReceivedFragmentCount.QuadPart, 4); - memcpy_exl(pAdapter, &pRaCfg->data[24], (UCHAR *)&pAdapter->WlanCounters.FCSErrorCount.u.LowPart, 4); - memcpy_exl(pAdapter, &pRaCfg->data[28], (UCHAR *)&pAdapter->Counters8023.RxNoBuffer, 4); - memcpy_exl(pAdapter, &pRaCfg->data[32], (UCHAR *)&pAdapter->WlanCounters.FrameDuplicateCount.u.LowPart, 4); - memcpy_exl(pAdapter, &pRaCfg->data[36], (UCHAR *)&pAdapter->RalinkCounters.OneSecFalseCCACnt, 4); - - if (pAdapter->ate.RxAntennaSel == 0) - { - INT32 RSSI0 = 0; - INT32 RSSI1 = 0; - INT32 RSSI2 = 0; - - RSSI0 = (INT32)(pAdapter->ate.LastRssi0 - pAdapter->BbpRssiToDbmDelta); - RSSI1 = (INT32)(pAdapter->ate.LastRssi1 - pAdapter->BbpRssiToDbmDelta); - RSSI2 = (INT32)(pAdapter->ate.LastRssi2 - pAdapter->BbpRssiToDbmDelta); - memcpy_exl(pAdapter, &pRaCfg->data[40], (UCHAR *)&RSSI0, 4); - memcpy_exl(pAdapter, &pRaCfg->data[44], (UCHAR *)&RSSI1, 4); - memcpy_exl(pAdapter, &pRaCfg->data[48], (UCHAR *)&RSSI2, 4); - pRaCfg->length = htons(2+52); - } - else - { - INT32 RSSI0 = 0; - - RSSI0 = (INT32)(pAdapter->ate.LastRssi0 - pAdapter->BbpRssiToDbmDelta); - memcpy_exl(pAdapter, &pRaCfg->data[40], (UCHAR *)&RSSI0, 4); - pRaCfg->length = htons(2+44); - } - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_GET_STATISTICS\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_GET_STATISTICS is done !\n")); - } - } - break; - - case RACFG_CMD_ATE_RESET_COUNTER: - { - SHORT value = 1; - UCHAR str[LEN_OF_ARG]; - - NdisZeroMemory(str, LEN_OF_ARG); - - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_RESET_COUNTER\n")); - - sprintf((PCHAR)str, "%d", value); - Set_ResetStatCounter_Proc(pAdapter, str); - - pAdapter->ate.TxDoneCount = 0; - - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_RESET_COUNTER\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_RESET_COUNTER is done !\n")); - } - } - - break; - - case RACFG_CMD_ATE_SEL_TX_ANTENNA: - { - SHORT value = 0; - UCHAR str[LEN_OF_ARG]; - - NdisZeroMemory(str, LEN_OF_ARG); - - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SEL_TX_ANTENNA\n")); - - memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); - value = ntohs(value); - sprintf((PCHAR)str, "%d", value); - Set_ATE_TX_Antenna_Proc(pAdapter, str); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SEL_TX_ANTENNA\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SEL_TX_ANTENNA is done !\n")); - } - } - break; - - case RACFG_CMD_ATE_SEL_RX_ANTENNA: - { - SHORT value = 0; - UCHAR str[LEN_OF_ARG]; - - NdisZeroMemory(str, LEN_OF_ARG); - - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SEL_RX_ANTENNA\n")); - - memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); - value = ntohs(value); - sprintf((PCHAR)str, "%d", value); - Set_ATE_RX_Antenna_Proc(pAdapter, str); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SEL_RX_ANTENNA\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SEL_RX_ANTENNA is done !\n")); - } - } - break; - - case RACFG_CMD_ATE_SET_PREAMBLE: - { - SHORT value = 0; - UCHAR str[LEN_OF_ARG]; - - NdisZeroMemory(str, LEN_OF_ARG); - - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_PREAMBLE\n")); - - memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); - value = ntohs(value); - sprintf((PCHAR)str, "%d", value); - Set_ATE_TX_MODE_Proc(pAdapter, str); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_PREAMBLE\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_PREAMBLE is done !\n")); - } - } - break; - - case RACFG_CMD_ATE_SET_CHANNEL: - { - SHORT value = 0; - UCHAR str[LEN_OF_ARG]; - - NdisZeroMemory(str, LEN_OF_ARG); - - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_CHANNEL\n")); - - memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); - value = ntohs(value); - sprintf((PCHAR)str, "%d", value); - Set_ATE_CHANNEL_Proc(pAdapter, str); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_CHANNEL\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_CHANNEL is done !\n")); - } - } - break; - - case RACFG_CMD_ATE_SET_ADDR1: - { - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_ADDR1\n")); - - // Addr is an array of UCHAR, - // so no need to perform endian swap. - memcpy(pAdapter->ate.Addr1, (PUCHAR)(pRaCfg->data - 2), MAC_ADDR_LEN); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_ADDR1\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_ADDR1 is done !\n (ADDR1 = %2X:%2X:%2X:%2X:%2X:%2X)\n", pAdapter->ate.Addr1[0], - pAdapter->ate.Addr1[1], pAdapter->ate.Addr1[2], pAdapter->ate.Addr1[3], pAdapter->ate.Addr1[4], pAdapter->ate.Addr1[5])); - } - } - break; - - case RACFG_CMD_ATE_SET_ADDR2: - { - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_ADDR2\n")); - - // Addr is an array of UCHAR, - // so no need to perform endian swap. - memcpy(pAdapter->ate.Addr2, (PUCHAR)(pRaCfg->data - 2), MAC_ADDR_LEN); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_ADDR2\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_ADDR2 is done !\n (ADDR2 = %2X:%2X:%2X:%2X:%2X:%2X)\n", pAdapter->ate.Addr2[0], - pAdapter->ate.Addr2[1], pAdapter->ate.Addr2[2], pAdapter->ate.Addr2[3], pAdapter->ate.Addr2[4], pAdapter->ate.Addr2[5])); - } - } - break; - - case RACFG_CMD_ATE_SET_ADDR3: - { - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_ADDR3\n")); - - // Addr is an array of UCHAR, - // so no need to perform endian swap. - memcpy(pAdapter->ate.Addr3, (PUCHAR)(pRaCfg->data - 2), MAC_ADDR_LEN); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_ADDR3\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_ADDR3 is done !\n (ADDR3 = %2X:%2X:%2X:%2X:%2X:%2X)\n", pAdapter->ate.Addr3[0], - pAdapter->ate.Addr3[1], pAdapter->ate.Addr3[2], pAdapter->ate.Addr3[3], pAdapter->ate.Addr3[4], pAdapter->ate.Addr3[5])); - } - } - break; - - case RACFG_CMD_ATE_SET_RATE: - { - SHORT value = 0; - UCHAR str[LEN_OF_ARG]; - - NdisZeroMemory(str, LEN_OF_ARG); - - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_RATE\n")); - - memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); - value = ntohs(value); - sprintf((PCHAR)str, "%d", value); - Set_ATE_TX_MCS_Proc(pAdapter, str); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_RATE\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_RATE is done !\n")); - } - } - break; - - case RACFG_CMD_ATE_SET_TX_FRAME_LEN: - { - SHORT value = 0; - UCHAR str[LEN_OF_ARG]; - - NdisZeroMemory(str, LEN_OF_ARG); - - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_TX_FRAME_LEN\n")); - - memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); - value = ntohs(value); - sprintf((PCHAR)str, "%d", value); - Set_ATE_TX_LENGTH_Proc(pAdapter, str); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_TX_FRAME_LEN\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_TX_FRAME_LEN is done !\n")); - } - } - break; - - case RACFG_CMD_ATE_SET_TX_FRAME_COUNT: - { - USHORT value = 0; - UCHAR str[LEN_OF_ARG]; - - NdisZeroMemory(str, LEN_OF_ARG); - - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_TX_FRAME_COUNT\n")); - - memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); - value = ntohs(value); - { - sprintf((PCHAR)str, "%d", value); - Set_ATE_TX_COUNT_Proc(pAdapter, str); - } - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_TX_FRAME_COUNT\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_TX_FRAME_COUNT is done !\n")); - } - } - break; - - case RACFG_CMD_ATE_START_RX_FRAME: - { - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_RX_START\n")); - - Set_ATE_Proc(pAdapter, "RXFRAME"); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_RX_START\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_RX_START is done !\n")); - } - } - break; - default: - break; - } - ASSERT(pRaCfg != NULL); - if (pRaCfg != NULL) - { - kfree(pRaCfg); - } - return; -} - -VOID BubbleSort(INT32 n, INT32 a[]) -{ - INT32 k, j, temp; - - for (k = n-1; k>0; k--) - { - for (j = 0; j a[j+1]) - { - temp = a[j]; - a[j]=a[j+1]; - a[j+1]=temp; - } - } - } -} - -VOID CalNoiseLevel(PRTMP_ADAPTER pAd, UCHAR channel, INT32 RSSI[3][10]) -{ - INT32 RSSI0, RSSI1, RSSI2; - CHAR Rssi0Offset, Rssi1Offset, Rssi2Offset; - UCHAR BbpR50Rssi0 = 0, BbpR51Rssi1 = 0, BbpR52Rssi2 = 0; - UCHAR Org_BBP66value = 0, Org_BBP69value = 0, Org_BBP70value = 0, data = 0; - USHORT LNA_Gain = 0; - INT32 j = 0; - UCHAR Org_Channel = pAd->ate.Channel; - USHORT GainValue = 0, OffsetValue = 0; - - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R66, &Org_BBP66value); - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R69, &Org_BBP69value); - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R70, &Org_BBP70value); - - //********************************************************************** - // Read the value of LNA gain and Rssi offset - //********************************************************************** - RT28xx_EEPROM_READ16(pAd, EEPROM_LNA_OFFSET, GainValue); - - // for Noise Level - if (channel <= 14) - { - LNA_Gain = GainValue & 0x00FF; - - RT28xx_EEPROM_READ16(pAd, EEPROM_RSSI_BG_OFFSET, OffsetValue); - Rssi0Offset = OffsetValue & 0x00FF; - Rssi1Offset = (OffsetValue & 0xFF00) >> 8; - RT28xx_EEPROM_READ16(pAd, (EEPROM_RSSI_BG_OFFSET + 2)/* 0x48 */, OffsetValue); - Rssi2Offset = OffsetValue & 0x00FF; - } - else - { - LNA_Gain = (GainValue & 0xFF00) >> 8; - - RT28xx_EEPROM_READ16(pAd, EEPROM_RSSI_A_OFFSET, OffsetValue); - Rssi0Offset = OffsetValue & 0x00FF; - Rssi1Offset = (OffsetValue & 0xFF00) >> 8; - RT28xx_EEPROM_READ16(pAd, (EEPROM_RSSI_A_OFFSET + 2)/* 0x4C */, OffsetValue); - Rssi2Offset = OffsetValue & 0x00FF; - } - //********************************************************************** - { - pAd->ate.Channel = channel; - ATEAsicSwitchChannel(pAd); - mdelay(5); - - data = 0x10; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, data); - data = 0x40; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, data); - data = 0x40; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, data); - mdelay(5); - - // Start Rx - pAd->ate.bQARxStart = TRUE; - Set_ATE_Proc(pAd, "RXFRAME"); - - mdelay(5); - - for (j = 0; j < 10; j++) - { - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R50, &BbpR50Rssi0); - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R51, &BbpR51Rssi1); - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R52, &BbpR52Rssi2); - - mdelay(10); - - // Calculate RSSI 0 - if (BbpR50Rssi0 == 0) - { - RSSI0 = -100; - } - else - { - RSSI0 = (INT32)(-12 - BbpR50Rssi0 - LNA_Gain - Rssi0Offset); - } - RSSI[0][j] = RSSI0; - - if ( pAd->Antenna.field.RxPath >= 2 ) // 2R - { - // Calculate RSSI 1 - if (BbpR51Rssi1 == 0) - { - RSSI1 = -100; - } - else - { - RSSI1 = (INT32)(-12 - BbpR51Rssi1 - LNA_Gain - Rssi1Offset); - } - RSSI[1][j] = RSSI1; - } - - if ( pAd->Antenna.field.RxPath >= 3 ) // 3R - { - // Calculate RSSI 2 - if (BbpR52Rssi2 == 0) - RSSI2 = -100; - else - RSSI2 = (INT32)(-12 - BbpR52Rssi2 - LNA_Gain - Rssi2Offset); - - RSSI[2][j] = RSSI2; - } - } - - // Stop Rx - Set_ATE_Proc(pAd, "RXSTOP"); - - mdelay(5); - -#if 0// Debug Message................ - ate_print("\n**********************************************************\n"); - ate_print("Noise Level: Channel %d\n", channel); - ate_print("RSSI0 = %d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n", - RSSI[0][0], RSSI[0][1], RSSI[0][2], - RSSI[0][3], RSSI[0][4], RSSI[0][5], - RSSI[0][6], RSSI[0][7], RSSI[0][8], - RSSI[0][9]); - if ( pAd->Antenna.field.RxPath >= 2 ) // 2R - { - ate_print("RSSI1 = %d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n", - RSSI[1][0], RSSI[1][1], RSSI[1][2], - RSSI[1][3], RSSI[1][4], RSSI[1][5], - RSSI[1][6], RSSI[1][7], RSSI[1][8], - RSSI[1][9]); - } - if ( pAd->Antenna.field.RxPath >= 3 ) // 3R - { - ate_print("RSSI2 = %d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n", - RSSI[2][0], RSSI[2][1], RSSI[2][2], - RSSI[2][3], RSSI[2][4], RSSI[2][5], - RSSI[2][6], RSSI[2][7], RSSI[2][8], - RSSI[2][9]); - } -#endif // 0 // - BubbleSort(10, RSSI[0]); // 1R - - if ( pAd->Antenna.field.RxPath >= 2 ) // 2R - { - BubbleSort(10, RSSI[1]); - } - - if ( pAd->Antenna.field.RxPath >= 3 ) // 3R - { - BubbleSort(10, RSSI[2]); - } - -#if 0// Debug Message................ - ate_print("\nAfter Sorting....Channel %d\n", channel); - ate_print("RSSI0 = %d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n", - RSSI[0][0], RSSI[0][1], RSSI[0][2], - RSSI[0][3], RSSI[0][4], RSSI[0][5], - RSSI[0][6], RSSI[0][7], RSSI[0][8], - RSSI[0][9]); - if ( pAd->Antenna.field.RxPath >= 2 ) // 2R - { - ate_print("RSSI1 = %d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n", - RSSI[1][0], RSSI[1][1], RSSI[1][2], - RSSI[1][3], RSSI[1][4], RSSI[1][5], - RSSI[1][6], RSSI[1][7], RSSI[1][8], - RSSI[1][9]); - } - if ( pAd->Antenna.field.RxPath >= 3 ) // 3R - { - ate_print("RSSI2 = %d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n", - RSSI[2][0], RSSI[2][1], RSSI[2][2], - RSSI[2][3], RSSI[2][4], RSSI[2][5], - RSSI[2][6], RSSI[2][7], RSSI[2][8], - RSSI[2][9]); - } - ate_print("**********************************************************\n"); -#endif // 0 // - } - - pAd->ate.Channel = Org_Channel; - ATEAsicSwitchChannel(pAd); - - // Restore original value - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, Org_BBP66value); - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, Org_BBP69value); - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, Org_BBP70value); - - return; -} - -BOOLEAN SyncTxRxConfig(PRTMP_ADAPTER pAd, USHORT offset, UCHAR value) -{ - UCHAR tmp = 0, bbp_data = 0; - - if (ATE_ON(pAd)) - { - ATE_BBP_IO_READ8_BY_REG_ID(pAd, offset, &bbp_data); - } - else - { - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, offset, &bbp_data); - } - - /* confirm again */ - ASSERT(bbp_data == value); - - switch(offset) - { - case BBP_R1: - /* Need to sync. tx configuration with legacy ATE. */ - tmp = (bbp_data & ((1 << 4) | (1 << 3))/* 0x18 */) >> 3; - switch(tmp) - { - /* The BBP R1 bit[4:3] = 2 :: Both DACs will be used by QA. */ - case 2: - /* All */ - pAd->ate.TxAntennaSel = 0; - break; - /* The BBP R1 bit[4:3] = 0 :: DAC 0 will be used by QA. */ - case 0: - /* Antenna one */ - pAd->ate.TxAntennaSel = 1; - break; - /* The BBP R1 bit[4:3] = 1 :: DAC 1 will be used by QA. */ - case 1: - /* Antenna two */ - pAd->ate.TxAntennaSel = 2; - break; - default: - DBGPRINT(RT_DEBUG_TRACE, ("%s -- Sth. wrong! : return FALSE; \n", __func__)); - return FALSE; - } - break;/* case BBP_R1 */ - - case BBP_R3: - /* Need to sync. rx configuration with legacy ATE. */ - tmp = (bbp_data & ((1 << 1) | (1 << 0))/* 0x03 */); - switch(tmp) - { - /* The BBP R3 bit[1:0] = 3 :: All ADCs will be used by QA. */ - case 3: - /* All */ - pAd->ate.RxAntennaSel = 0; - break; - /* The BBP R3 bit[1:0] = 0 :: ADC 0 will be used by QA, */ - /* unless the BBP R3 bit[4:3] = 2 */ - case 0: - /* Antenna one */ - pAd->ate.RxAntennaSel = 1; - tmp = ((bbp_data & ((1 << 4) | (1 << 3))/* 0x03 */) >> 3); - if (tmp == 2)// 3R - { - /* Default : All ADCs will be used by QA */ - pAd->ate.RxAntennaSel = 0; - } - break; - /* The BBP R3 bit[1:0] = 1 :: ADC 1 will be used by QA. */ - case 1: - /* Antenna two */ - pAd->ate.RxAntennaSel = 2; - break; - /* The BBP R3 bit[1:0] = 2 :: ADC 2 will be used by QA. */ - case 2: - /* Antenna three */ - pAd->ate.RxAntennaSel = 3; - break; - default: - DBGPRINT(RT_DEBUG_ERROR, ("%s -- Impossible! : return FALSE; \n", __func__)); - return FALSE; - } - break;/* case BBP_R3 */ - - default: - DBGPRINT(RT_DEBUG_ERROR, ("%s -- Sth. wrong! : return FALSE; \n", __func__)); - return FALSE; - - } - return TRUE; -} - -static VOID memcpy_exl(PRTMP_ADAPTER pAd, UCHAR *dst, UCHAR *src, ULONG len) -{ - ULONG i, Value = 0; - ULONG *pDst, *pSrc; - UCHAR *p8; - - p8 = src; - pDst = (ULONG *) dst; - pSrc = (ULONG *) src; - - for (i = 0 ; i < (len/4); i++) - { - /* For alignment issue, we need a variable "Value". */ - memmove(&Value, pSrc, 4); - Value = htonl(Value); - memmove(pDst, &Value, 4); - pDst++; - pSrc++; - } - if ((len % 4) != 0) - { - /* wish that it will never reach here */ - memmove(&Value, pSrc, (len % 4)); - Value = htonl(Value); - memmove(pDst, &Value, (len % 4)); - } -} - -static VOID memcpy_exs(PRTMP_ADAPTER pAd, UCHAR *dst, UCHAR *src, ULONG len) -{ - ULONG i; - UCHAR *pDst, *pSrc; - - pDst = dst; - pSrc = src; - - for (i = 0; i < (len/2); i++) - { - memmove(pDst, pSrc, 2); - *((USHORT *)pDst) = htons(*((USHORT *)pDst)); - pDst+=2; - pSrc+=2; - } - - if ((len % 2) != 0) - { - memmove(pDst, pSrc, 1); - } -} - -static VOID RTMP_IO_READ_BULK(PRTMP_ADAPTER pAd, UCHAR *dst, UCHAR *src, UINT32 len) -{ - UINT32 i, Value; - UINT32 *pDst, *pSrc; - - pDst = (UINT32 *) dst; - pSrc = (UINT32 *) src; - - for (i = 0 ; i < (len/4); i++) - { - RTMP_IO_READ32(pAd, (ULONG)pSrc, &Value); - Value = htonl(Value); - memmove(pDst, &Value, 4); - pDst++; - pSrc++; - } - return; -} - -// TODO: -#if 0 -/* These work only when RALINK_ATE is defined */ -INT Set_TxStart_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ULONG value = simple_strtol(arg, 0, 10); - UCHAR buffer[26] = {0x88, 0x02, 0x2c, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x00, 0x55, 0x44, 0x33, 0x22, 0x11, 0xc0, 0x22, 0x00, 0x00}; - POS_COOKIE pObj; - - if (pAd->ate.TxStatus != 0) - return FALSE; - - pAd->ate.TxInfo = 0x04000000; - bzero(&pAd->ate.TxWI, sizeof(TXWI_STRUC)); - pAd->ate.TxWI.PHYMODE = 0;// MODE_CCK - pAd->ate.TxWI.MPDUtotalByteCount = 1226; - pAd->ate.TxWI.MCS = 3; - //pAd->ate.Mode = ATE_START; - pAd->ate.Mode |= ATE_TXFRAME; - pAd->ate.TxCount = value; - pAd->ate.QID = 0; - pAd->ate.HLen = 26; - pAd->ate.PLen = 0; - pAd->ate.DLen = 1200; - memcpy(pAd->ate.Header, buffer, 26); - pAd->ate.bQATxStart = TRUE; - //pObj = (POS_COOKIE) pAd->OS_Cookie; - //tasklet_hi_schedule(&pObj->AteTxTask); - return TRUE; -} -#endif /* end of #if 0 */ - -INT Set_TxStop_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ATEDBGPRINT(RT_DEBUG_TRACE,("Set_TxStop_Proc\n")); - - if (Set_ATE_Proc(pAd, "TXSTOP")) - { - return TRUE; -} - else - { - return FALSE; - } -} - -INT Set_RxStop_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ATEDBGPRINT(RT_DEBUG_TRACE,("Set_RxStop_Proc\n")); - - if (Set_ATE_Proc(pAd, "RXSTOP")) - { - return TRUE; -} - else - { - return FALSE; - } -} - -#if 0 -INT Set_EEWrite_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - USHORT offset = 0, value; - PUCHAR p2 = arg; - - while((*p2 != ':') && (*p2 != '\0')) - { - p2++; - } - - if (*p2 == ':') - { - A2Hex(offset, arg); - A2Hex(value, p2+ 1); - } - else - { - A2Hex(value, arg); - } - - if (offset >= EEPROM_SIZE) - { - ate_print("Offset can not exceed EEPROM_SIZE( == 0x%04x)\n", EEPROM_SIZE); - return FALSE; - } - - RTMP_EEPROM_WRITE16(pAd, offset, value); - - return TRUE; -} - -INT Set_BBPRead_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - UCHAR value = 0, offset; - - A2Hex(offset, arg); - - if (ATE_ON(pAd)) - { - ATE_BBP_IO_READ8_BY_REG_ID(pAd, offset, &value); - } - else - { - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, offset, &value); - } - - ate_print("%x\n", value); - - return TRUE; -} - - -INT Set_BBPWrite_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - USHORT offset = 0; - PUCHAR p2 = arg; - UCHAR value; - - while((*p2 != ':') && (*p2 != '\0')) - { - p2++; - } - - if (*p2 == ':') - { - A2Hex(offset, arg); - A2Hex(value, p2+ 1); - } - else - { - A2Hex(value, arg); - } - - if (ATE_ON(pAd)) - { - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, offset, value); - } - else - { - RTNP_BBP_IO_WRITE8_BY_REG_ID(pAd, offset, value); - } - - return TRUE; -} - -INT Set_RFWrite_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - PUCHAR p2, p3, p4; - ULONG R1, R2, R3, R4; - - p2 = arg; - - while((*p2 != ':') && (*p2 != '\0')) - { - p2++; - } - - if (*p2 != ':') - return FALSE; - - p3 = p2 + 1; - - while((*p3 != ':') && (*p3 != '\0')) - { - p3++; - } - - if (*p3 != ':') - return FALSE; - - p4 = p3 + 1; - - while((*p4 != ':') && (*p4 != '\0')) - { - p4++; - } - - if (*p4 != ':') - return FALSE; - - - A2Hex(R1, arg); - A2Hex(R2, p2 + 1); - A2Hex(R3, p3 + 1); - A2Hex(R4, p4 + 1); - - RTMP_RF_IO_WRITE32(pAd, R1); - RTMP_RF_IO_WRITE32(pAd, R2); - RTMP_RF_IO_WRITE32(pAd, R3); - RTMP_RF_IO_WRITE32(pAd, R4); - - return TRUE; -} -#endif // end of #if 0 // -#endif // RALINK_28xx_QA // - -#endif // RALINK_ATE // - diff --git a/drivers/staging/rt2870/rt_ate.h b/drivers/staging/rt2870/rt_ate.h deleted file mode 100644 index b618ce3599ac..000000000000 --- a/drivers/staging/rt2870/rt_ate.h +++ /dev/null @@ -1,315 +0,0 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - */ - -#ifndef __ATE_H__ -#define __ATE_H__ - -#ifndef UCOS -#define ate_print printk -#define ATEDBGPRINT DBGPRINT - -#ifdef RT2870 -#define EEPROM_SIZE 0x400 -#ifdef CONFIG_STA_SUPPORT -#define EEPROM_BIN_FILE_NAME "/etc/Wireless/RT2870STA/e2p.bin" -#endif // CONFIG_STA_SUPPORT // -#endif // RT2870 // -#else // !UCOS // -#define fATE_LOAD_EEPROM 0x0C43 -#ifdef CONFIG_PRINTK -extern INT ConsoleResponse(IN PUCHAR buff); -extern int (*remote_display)(char *); -extern void puts (const char *s); - -/* specificly defined to redirect and show ate-related messages to host. */ -/* Try to define ate_print as a macro. */ -#define ate_print(fmt, args...) \ -do{ int (*org_remote_display)(char *) = NULL; \ - org_remote_display = remote_display;\ - /* Save original "remote_display" */\ - remote_display = (int (*)(char *))ConsoleResponse; \ - printk(fmt, ## args); \ - /* Restore the remote_display function pointer */ \ - remote_display = org_remote_display; }while(0) - -#define ATEDBGPRINT(Level, Fmt) \ -{ \ - if ((Level) <= RTDebugLevel) \ - { \ - ate_print Fmt; \ - } \ -} -#endif // CONFIG_PRINTK // -#endif // !UCOS // - -#define ATE_ON(_p) (((_p)->ate.Mode) != ATE_STOP) - -/* RT2880_iNIC will define "RT2860". */ - -/* RT2880_iNIC will define RT2860. */ - -#ifdef RT2870 -#define EEPROM_SIZE 0x400 -#ifdef CONFIG_STA_SUPPORT -#define EEPROM_BIN_FILE_NAME "/etc/Wireless/RT2870STA/e2p.bin" -#endif // CONFIG_STA_SUPPORT // -#endif // RT2870 // - -#ifdef RT2870 -#define ATE_BBP_IO_READ8_BY_REG_ID(_A, _I, _pV) RTMP_BBP_IO_READ8_BY_REG_ID(_A, _I, _pV) -#define ATE_BBP_IO_WRITE8_BY_REG_ID(_A, _I, _V) RTMP_BBP_IO_WRITE8_BY_REG_ID(_A, _I, _V) - -#define BULK_OUT_LOCK(pLock, IrqFlags) \ - if(1 /*!(in_interrupt() & 0xffff0000)*/) \ - RTMP_IRQ_LOCK((pLock), IrqFlags); - -#define BULK_OUT_UNLOCK(pLock, IrqFlags) \ - if(1 /*!(in_interrupt() & 0xffff0000)*/) \ - RTMP_IRQ_UNLOCK((pLock), IrqFlags); - -// Prototypes of completion funuc. -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) -#define ATE_RTUSBBulkOutDataPacketComplete(purb, pt_regs) ATE_RTUSBBulkOutDataPacketComplete(purb) -#endif - -VOID ATE_RTUSBBulkOutDataPacketComplete( - IN purbb_t purb, - OUT struct pt_regs *pt_regs); - -VOID ATE_RTUSBBulkOutDataPacket( - IN PRTMP_ADAPTER pAd, - IN UCHAR BulkOutPipeId); - -VOID ATE_RTUSBCancelPendingBulkInIRP( - IN PRTMP_ADAPTER pAd); -#endif // RT2870 // - -VOID rt_ee_read_all( - IN PRTMP_ADAPTER pAd, - OUT USHORT *Data); - - -VOID rt_ee_write_all( - IN PRTMP_ADAPTER pAd, - IN USHORT *Data); - -INT Set_ATE_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_DA_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_SA_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_BSSID_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_CHANNEL_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_TX_POWER0_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_TX_POWER1_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_TX_Antenna_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_RX_Antenna_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_TX_FREQOFFSET_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_TX_BW_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_TX_LENGTH_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_TX_COUNT_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_TX_MCS_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_TX_MODE_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_TX_GI_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - - -INT Set_ATE_RX_FER_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_Read_RF_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_Write_RF1_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_Write_RF2_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_Write_RF3_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_Write_RF4_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_Load_E2P_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_Read_E2P_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_Show_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_Help_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -#ifdef RALINK_ATE -#ifdef RALINK_28xx_QA -VOID ATE_QA_Statistics( - IN PRTMP_ADAPTER pAd, - IN PRXWI_STRUC pRxWI, - IN PRT28XX_RXD_STRUC p28xxRxD, - IN PHEADER_802_11 pHeader); - -VOID RtmpDoAte( - IN PRTMP_ADAPTER pAdapter, - IN struct iwreq *wrq); - -VOID BubbleSort( - IN INT32 n, - IN INT32 a[]); - -VOID CalNoiseLevel( - IN PRTMP_ADAPTER pAdapter, - IN UCHAR channel, - OUT INT32 buffer[3][10]); - -BOOLEAN SyncTxRxConfig( - IN PRTMP_ADAPTER pAdapter, - IN USHORT offset, - IN UCHAR value); - -#if 0 -INT Set_TxStart_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); -#endif // 0 // - -INT Set_TxStop_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_RxStop_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -#if 0 -INT Set_EERead_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_EEWrite_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_BBPRead_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_BBPWrite_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_RFWrite_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); -#endif // end of #if 0 // -#endif // RALINK_28xx_QA // -#endif // RALINK_ATE // - -VOID ATEAsicSwitchChannel( - IN PRTMP_ADAPTER pAd); - -VOID ATEAsicAdjustTxPower( - IN PRTMP_ADAPTER pAd); - -VOID ATEDisableAsicProtect( - IN PRTMP_ADAPTER pAd); - -CHAR ATEConvertToRssi( - IN PRTMP_ADAPTER pAd, - IN CHAR Rssi, - IN UCHAR RssiNumber); - -VOID ATESampleRssi( - IN PRTMP_ADAPTER pAd, - IN PRXWI_STRUC pRxWI); - - -#ifdef CONFIG_STA_SUPPORT -VOID RTMPStationStop( - IN PRTMP_ADAPTER pAd); - -VOID RTMPStationStart( - IN PRTMP_ADAPTER pAd); -#endif // CONFIG_STA_SUPPORT // -#endif // __ATE_H__ // diff --git a/drivers/staging/rt2870/rt_config.h b/drivers/staging/rt2870/rt_config.h index e3fe2642633a..1f6d6ed5630c 100644 --- a/drivers/staging/rt2870/rt_config.h +++ b/drivers/staging/rt2870/rt_config.h @@ -1,104 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - rt_config.h - - Abstract: - Central header file to maintain all include files for all NDIS - miniport driver routines. - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Paul Lin 08-01-2002 created - -*/ -#ifndef __RT_CONFIG_H__ -#define __RT_CONFIG_H__ - -#include "rtmp_type.h" -#ifdef UCOS -#include "includes.h" -#include -#include "rt_ucos.h" -#endif - -#ifdef LINUX -#include "rt_linux.h" -#endif -#include "rtmp_def.h" -#include "rt28xx.h" - - -#ifdef RT2870 -#include "rt2870.h" -#endif // RT2870 // - -#include "oid.h" -#include "mlme.h" -#include "wpa.h" -#include "md5.h" -#include "rtmp.h" -#include "ap.h" -#include "dfs.h" -#include "chlist.h" -#include "spectrum.h" - - -#ifdef LEAP_SUPPORT -#include "leap.h" -#endif // LEAP_SUPPORT // - -#ifdef BLOCK_NET_IF -#include "netif_block.h" -#endif // BLOCK_NET_IF // - -#ifdef IGMP_SNOOP_SUPPORT -#include "igmp_snoop.h" -#endif // IGMP_SNOOP_SUPPORT // - -#ifdef RALINK_ATE -#include "rt_ate.h" -#endif // RALINK_ATE // - - - -#ifdef CONFIG_STA_SUPPORT -#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT -#ifndef WPA_SUPPLICANT_SUPPORT -#error "Build for being controlled by NetworkManager or wext, please set HAS_WPA_SUPPLICANT=y and HAS_NATIVE_WPA_SUPPLICANT_SUPPORT=y" -#endif // WPA_SUPPLICANT_SUPPORT // -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // - -#endif // CONFIG_STA_SUPPORT // - -#ifdef IKANOS_VX_1X0 -#include "vr_ikans.h" -#endif // IKANOS_VX_1X0 // - -#endif // __RT_CONFIG_H__ - +#include "../rt2860/rt_config.h" diff --git a/drivers/staging/rt2870/rt_linux.c b/drivers/staging/rt2870/rt_linux.c index e38552c5ccb1..88c697bf90eb 100644 --- a/drivers/staging/rt2870/rt_linux.c +++ b/drivers/staging/rt2870/rt_linux.c @@ -1,1095 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * 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 "rt_config.h" - -ULONG RTDebugLevel = RT_DEBUG_ERROR; - -BUILD_TIMER_FUNCTION(MlmePeriodicExec); -//BUILD_TIMER_FUNCTION(MlmeRssiReportExec); -BUILD_TIMER_FUNCTION(AsicRxAntEvalTimeout); -BUILD_TIMER_FUNCTION(APSDPeriodicExec); -BUILD_TIMER_FUNCTION(AsicRfTuningExec); -#ifdef RT2870 -BUILD_TIMER_FUNCTION(BeaconUpdateExec); -#endif // RT2870 // - - -#ifdef CONFIG_STA_SUPPORT -BUILD_TIMER_FUNCTION(BeaconTimeout); -BUILD_TIMER_FUNCTION(ScanTimeout); -BUILD_TIMER_FUNCTION(AuthTimeout); -BUILD_TIMER_FUNCTION(AssocTimeout); -BUILD_TIMER_FUNCTION(ReassocTimeout); -BUILD_TIMER_FUNCTION(DisassocTimeout); -BUILD_TIMER_FUNCTION(LinkDownExec); -#ifdef LEAP_SUPPORT -BUILD_TIMER_FUNCTION(LeapAuthTimeout); -#endif -BUILD_TIMER_FUNCTION(StaQuickResponeForRateUpExec); -BUILD_TIMER_FUNCTION(WpaDisassocApAndBlockAssoc); -#ifdef QOS_DLS_SUPPORT -BUILD_TIMER_FUNCTION(DlsTimeoutAction); -#endif // QOS_DLS_SUPPORT // -#endif // CONFIG_STA_SUPPORT // - -// for wireless system event message -char const *pWirelessSysEventText[IW_SYS_EVENT_TYPE_NUM] = { - // system status event - "had associated successfully", /* IW_ASSOC_EVENT_FLAG */ - "had disassociated", /* IW_DISASSOC_EVENT_FLAG */ - "had deauthenticated", /* IW_DEAUTH_EVENT_FLAG */ - "had been aged-out and disassociated", /* IW_AGEOUT_EVENT_FLAG */ - "occurred CounterMeasures attack", /* IW_COUNTER_MEASURES_EVENT_FLAG */ - "occurred replay counter different in Key Handshaking", /* IW_REPLAY_COUNTER_DIFF_EVENT_FLAG */ - "occurred RSNIE different in Key Handshaking", /* IW_RSNIE_DIFF_EVENT_FLAG */ - "occurred MIC different in Key Handshaking", /* IW_MIC_DIFF_EVENT_FLAG */ - "occurred ICV error in RX", /* IW_ICV_ERROR_EVENT_FLAG */ - "occurred MIC error in RX", /* IW_MIC_ERROR_EVENT_FLAG */ - "Group Key Handshaking timeout", /* IW_GROUP_HS_TIMEOUT_EVENT_FLAG */ - "Pairwise Key Handshaking timeout", /* IW_PAIRWISE_HS_TIMEOUT_EVENT_FLAG */ - "RSN IE sanity check failure", /* IW_RSNIE_SANITY_FAIL_EVENT_FLAG */ - "set key done in WPA/WPAPSK", /* IW_SET_KEY_DONE_WPA1_EVENT_FLAG */ - "set key done in WPA2/WPA2PSK", /* IW_SET_KEY_DONE_WPA2_EVENT_FLAG */ - "connects with our wireless client", /* IW_STA_LINKUP_EVENT_FLAG */ - "disconnects with our wireless client", /* IW_STA_LINKDOWN_EVENT_FLAG */ - "scan completed" /* IW_SCAN_COMPLETED_EVENT_FLAG */ - "scan terminate!! Busy!! Enqueue fail!!" /* IW_SCAN_ENQUEUE_FAIL_EVENT_FLAG */ - }; - -// for wireless IDS_spoof_attack event message -char const *pWirelessSpoofEventText[IW_SPOOF_EVENT_TYPE_NUM] = { - "detected conflict SSID", /* IW_CONFLICT_SSID_EVENT_FLAG */ - "detected spoofed association response", /* IW_SPOOF_ASSOC_RESP_EVENT_FLAG */ - "detected spoofed reassociation responses", /* IW_SPOOF_REASSOC_RESP_EVENT_FLAG */ - "detected spoofed probe response", /* IW_SPOOF_PROBE_RESP_EVENT_FLAG */ - "detected spoofed beacon", /* IW_SPOOF_BEACON_EVENT_FLAG */ - "detected spoofed disassociation", /* IW_SPOOF_DISASSOC_EVENT_FLAG */ - "detected spoofed authentication", /* IW_SPOOF_AUTH_EVENT_FLAG */ - "detected spoofed deauthentication", /* IW_SPOOF_DEAUTH_EVENT_FLAG */ - "detected spoofed unknown management frame", /* IW_SPOOF_UNKNOWN_MGMT_EVENT_FLAG */ - "detected replay attack" /* IW_REPLAY_ATTACK_EVENT_FLAG */ - }; - -// for wireless IDS_flooding_attack event message -char const *pWirelessFloodEventText[IW_FLOOD_EVENT_TYPE_NUM] = { - "detected authentication flooding", /* IW_FLOOD_AUTH_EVENT_FLAG */ - "detected association request flooding", /* IW_FLOOD_ASSOC_REQ_EVENT_FLAG */ - "detected reassociation request flooding", /* IW_FLOOD_REASSOC_REQ_EVENT_FLAG */ - "detected probe request flooding", /* IW_FLOOD_PROBE_REQ_EVENT_FLAG */ - "detected disassociation flooding", /* IW_FLOOD_DISASSOC_EVENT_FLAG */ - "detected deauthentication flooding", /* IW_FLOOD_DEAUTH_EVENT_FLAG */ - "detected 802.1x eap-request flooding" /* IW_FLOOD_EAP_REQ_EVENT_FLAG */ - }; - -/* timeout -- ms */ -VOID RTMP_SetPeriodicTimer( - IN NDIS_MINIPORT_TIMER *pTimer, - IN unsigned long timeout) -{ - timeout = ((timeout*HZ) / 1000); - pTimer->expires = jiffies + timeout; - add_timer(pTimer); -} - -/* convert NdisMInitializeTimer --> RTMP_OS_Init_Timer */ -VOID RTMP_OS_Init_Timer( - IN PRTMP_ADAPTER pAd, - IN NDIS_MINIPORT_TIMER *pTimer, - IN TIMER_FUNCTION function, - IN PVOID data) -{ - init_timer(pTimer); - pTimer->data = (unsigned long)data; - pTimer->function = function; -} - - -VOID RTMP_OS_Add_Timer( - IN NDIS_MINIPORT_TIMER *pTimer, - IN unsigned long timeout) -{ - if (timer_pending(pTimer)) - return; - - timeout = ((timeout*HZ) / 1000); - pTimer->expires = jiffies + timeout; - add_timer(pTimer); -} - -VOID RTMP_OS_Mod_Timer( - IN NDIS_MINIPORT_TIMER *pTimer, - IN unsigned long timeout) -{ - timeout = ((timeout*HZ) / 1000); - mod_timer(pTimer, jiffies + timeout); -} - -VOID RTMP_OS_Del_Timer( - IN NDIS_MINIPORT_TIMER *pTimer, - OUT BOOLEAN *pCancelled) -{ - if (timer_pending(pTimer)) - { - *pCancelled = del_timer_sync(pTimer); - } - else - { - *pCancelled = TRUE; - } - -} - -VOID RTMP_OS_Release_Packet( - IN PRTMP_ADAPTER pAd, - IN PQUEUE_ENTRY pEntry) -{ - //RTMPFreeNdisPacket(pAd, (struct sk_buff *)pEntry); -} - -// Unify all delay routine by using udelay -VOID RTMPusecDelay( - IN ULONG usec) -{ - ULONG i; - - for (i = 0; i < (usec / 50); i++) - udelay(50); - - if (usec % 50) - udelay(usec % 50); -} - -void RTMP_GetCurrentSystemTime(LARGE_INTEGER *time) -{ - time->u.LowPart = jiffies; -} - -// pAd MUST allow to be NULL -NDIS_STATUS os_alloc_mem( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR *mem, - IN ULONG size) -{ - *mem = (PUCHAR) kmalloc(size, GFP_ATOMIC); - if (*mem) - return (NDIS_STATUS_SUCCESS); - else - return (NDIS_STATUS_FAILURE); -} - -// pAd MUST allow to be NULL -NDIS_STATUS os_free_mem( - IN PRTMP_ADAPTER pAd, - IN PUCHAR mem) -{ - - ASSERT(mem); - kfree(mem); - return (NDIS_STATUS_SUCCESS); -} - - -PNDIS_PACKET RTMP_AllocateFragPacketBuffer( - IN PRTMP_ADAPTER pAd, - IN ULONG Length) -{ - struct sk_buff *pkt; - - pkt = dev_alloc_skb(Length); - - if (pkt == NULL) - { - DBGPRINT(RT_DEBUG_ERROR, ("can't allocate frag rx %ld size packet\n",Length)); - } - - if (pkt) - { - RTMP_SET_PACKET_SOURCE(OSPKT_TO_RTPKT(pkt), PKTSRC_NDIS); - } - - return (PNDIS_PACKET) pkt; -} - - -PNDIS_PACKET RTMP_AllocateTxPacketBuffer( - IN PRTMP_ADAPTER pAd, - IN ULONG Length, - IN BOOLEAN Cached, - OUT PVOID *VirtualAddress) -{ - struct sk_buff *pkt; - - pkt = dev_alloc_skb(Length); - - if (pkt == NULL) - { - DBGPRINT(RT_DEBUG_ERROR, ("can't allocate tx %ld size packet\n",Length)); - } - - if (pkt) - { - RTMP_SET_PACKET_SOURCE(OSPKT_TO_RTPKT(pkt), PKTSRC_NDIS); - *VirtualAddress = (PVOID) pkt->data; - } - else - { - *VirtualAddress = (PVOID) NULL; - } - - return (PNDIS_PACKET) pkt; -} - - -VOID build_tx_packet( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket, - IN PUCHAR pFrame, - IN ULONG FrameLen) -{ - - struct sk_buff *pTxPkt; - - ASSERT(pPacket); - pTxPkt = RTPKT_TO_OSPKT(pPacket); - - NdisMoveMemory(skb_put(pTxPkt, FrameLen), pFrame, FrameLen); -} - -VOID RTMPFreeAdapter( - IN PRTMP_ADAPTER pAd) -{ - POS_COOKIE os_cookie; - int index; - - os_cookie=(POS_COOKIE)pAd->OS_Cookie; - - kfree(pAd->BeaconBuf); - - - NdisFreeSpinLock(&pAd->MgmtRingLock); - - - for (index =0 ; index < NUM_OF_TX_RING; index++) - { - NdisFreeSpinLock(&pAd->TxSwQueueLock[index]); - NdisFreeSpinLock(&pAd->DeQueueLock[index]); - pAd->DeQueueRunning[index] = FALSE; - } - - NdisFreeSpinLock(&pAd->irq_lock); - - - vfree(pAd); // pci_free_consistent(os_cookie->pci_dev,sizeof(RTMP_ADAPTER),pAd,os_cookie->pAd_pa); - kfree(os_cookie); -} - -BOOLEAN OS_Need_Clone_Packet(void) -{ - return (FALSE); -} - - - -/* - ======================================================================== - - Routine Description: - clone an input NDIS PACKET to another one. The new internally created NDIS PACKET - must have only one NDIS BUFFER - return - byte copied. 0 means can't create NDIS PACKET - NOTE: internally created NDIS_PACKET should be destroyed by RTMPFreeNdisPacket - - Arguments: - pAd Pointer to our adapter - pInsAMSDUHdr EWC A-MSDU format has extra 14-bytes header. if TRUE, insert this 14-byte hdr in front of MSDU. - *pSrcTotalLen return total packet length. This lenght is calculated with 802.3 format packet. - - Return Value: - NDIS_STATUS_SUCCESS - NDIS_STATUS_FAILURE - - Note: - - ======================================================================== -*/ -NDIS_STATUS RTMPCloneNdisPacket( - IN PRTMP_ADAPTER pAd, - IN BOOLEAN pInsAMSDUHdr, - IN PNDIS_PACKET pInPacket, - OUT PNDIS_PACKET *ppOutPacket) -{ - - struct sk_buff *pkt; - - ASSERT(pInPacket); - ASSERT(ppOutPacket); - - // 1. Allocate a packet - pkt = dev_alloc_skb(2048); - - if (pkt == NULL) - { - return NDIS_STATUS_FAILURE; - } - - skb_put(pkt, GET_OS_PKT_LEN(pInPacket)); - NdisMoveMemory(pkt->data, GET_OS_PKT_DATAPTR(pInPacket), GET_OS_PKT_LEN(pInPacket)); - *ppOutPacket = OSPKT_TO_RTPKT(pkt); - - - RTMP_SET_PACKET_SOURCE(OSPKT_TO_RTPKT(pkt), PKTSRC_NDIS); - - printk("###Clone###\n"); - - return NDIS_STATUS_SUCCESS; -} - - -// the allocated NDIS PACKET must be freed via RTMPFreeNdisPacket() -NDIS_STATUS RTMPAllocateNdisPacket( - IN PRTMP_ADAPTER pAd, - OUT PNDIS_PACKET *ppPacket, - IN PUCHAR pHeader, - IN UINT HeaderLen, - IN PUCHAR pData, - IN UINT DataLen) -{ - PNDIS_PACKET pPacket; - ASSERT(pData); - ASSERT(DataLen); - - // 1. Allocate a packet - pPacket = (PNDIS_PACKET *) dev_alloc_skb(HeaderLen + DataLen + TXPADDING_SIZE); - if (pPacket == NULL) - { - *ppPacket = NULL; -#ifdef DEBUG - printk("RTMPAllocateNdisPacket Fail\n\n"); -#endif - return NDIS_STATUS_FAILURE; - } - - // 2. clone the frame content - if (HeaderLen > 0) - NdisMoveMemory(GET_OS_PKT_DATAPTR(pPacket), pHeader, HeaderLen); - if (DataLen > 0) - NdisMoveMemory(GET_OS_PKT_DATAPTR(pPacket) + HeaderLen, pData, DataLen); - - // 3. update length of packet - skb_put(GET_OS_PKT_TYPE(pPacket), HeaderLen+DataLen); - - RTMP_SET_PACKET_SOURCE(pPacket, PKTSRC_NDIS); -// printk("%s : pPacket = %p, len = %d\n", __func__, pPacket, GET_OS_PKT_LEN(pPacket)); - *ppPacket = pPacket; - return NDIS_STATUS_SUCCESS; -} - -/* - ======================================================================== - Description: - This routine frees a miniport internally allocated NDIS_PACKET and its - corresponding NDIS_BUFFER and allocated memory. - ======================================================================== -*/ -VOID RTMPFreeNdisPacket( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket) -{ - dev_kfree_skb_any(RTPKT_TO_OSPKT(pPacket)); -} - - -// IRQL = DISPATCH_LEVEL -// NOTE: we do have an assumption here, that Byte0 and Byte1 always reasid at the same -// scatter gather buffer -NDIS_STATUS Sniff2BytesFromNdisBuffer( - IN PNDIS_BUFFER pFirstBuffer, - IN UCHAR DesiredOffset, - OUT PUCHAR pByte0, - OUT PUCHAR pByte1) -{ - *pByte0 = *(PUCHAR)(pFirstBuffer + DesiredOffset); - *pByte1 = *(PUCHAR)(pFirstBuffer + DesiredOffset + 1); - - return NDIS_STATUS_SUCCESS; -} - - -void RTMP_QueryPacketInfo( - IN PNDIS_PACKET pPacket, - OUT PACKET_INFO *pPacketInfo, - OUT PUCHAR *pSrcBufVA, - OUT UINT *pSrcBufLen) -{ - pPacketInfo->BufferCount = 1; - pPacketInfo->pFirstBuffer = GET_OS_PKT_DATAPTR(pPacket); - pPacketInfo->PhysicalBufferCount = 1; - pPacketInfo->TotalPacketLength = GET_OS_PKT_LEN(pPacket); - - *pSrcBufVA = GET_OS_PKT_DATAPTR(pPacket); - *pSrcBufLen = GET_OS_PKT_LEN(pPacket); -} - -void RTMP_QueryNextPacketInfo( - IN PNDIS_PACKET *ppPacket, - OUT PACKET_INFO *pPacketInfo, - OUT PUCHAR *pSrcBufVA, - OUT UINT *pSrcBufLen) -{ - PNDIS_PACKET pPacket = NULL; - - if (*ppPacket) - pPacket = GET_OS_PKT_NEXT(*ppPacket); - - if (pPacket) - { - pPacketInfo->BufferCount = 1; - pPacketInfo->pFirstBuffer = GET_OS_PKT_DATAPTR(pPacket); - pPacketInfo->PhysicalBufferCount = 1; - pPacketInfo->TotalPacketLength = GET_OS_PKT_LEN(pPacket); - - *pSrcBufVA = GET_OS_PKT_DATAPTR(pPacket); - *pSrcBufLen = GET_OS_PKT_LEN(pPacket); - *ppPacket = GET_OS_PKT_NEXT(pPacket); - } - else - { - pPacketInfo->BufferCount = 0; - pPacketInfo->pFirstBuffer = NULL; - pPacketInfo->PhysicalBufferCount = 0; - pPacketInfo->TotalPacketLength = 0; - - *pSrcBufVA = NULL; - *pSrcBufLen = 0; - *ppPacket = NULL; - } -} - -// not yet support MBSS -PNET_DEV get_netdev_from_bssid( - IN PRTMP_ADAPTER pAd, - IN UCHAR FromWhichBSSID) -{ - PNET_DEV dev_p = NULL; - - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - dev_p = pAd->net_dev; - } -#endif // CONFIG_STA_SUPPORT // - - ASSERT(dev_p); - return dev_p; /* return one of MBSS */ -} - -PNDIS_PACKET DuplicatePacket( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket, - IN UCHAR FromWhichBSSID) -{ - struct sk_buff *skb; - PNDIS_PACKET pRetPacket = NULL; - USHORT DataSize; - UCHAR *pData; - - DataSize = (USHORT) GET_OS_PKT_LEN(pPacket); - pData = (PUCHAR) GET_OS_PKT_DATAPTR(pPacket); - - - skb = skb_clone(RTPKT_TO_OSPKT(pPacket), MEM_ALLOC_FLAG); - if (skb) - { - skb->dev = get_netdev_from_bssid(pAd, FromWhichBSSID); - pRetPacket = OSPKT_TO_RTPKT(skb); - } - -#if 0 - if ((skb = __dev_alloc_skb(DataSize + 2+32, MEM_ALLOC_FLAG)) != NULL) - { - skb_reserve(skb, 2+32); - NdisMoveMemory(skb->tail, pData, DataSize); - skb_put(skb, DataSize); - skb->dev = get_netdev_from_bssid(pAd, FromWhichBSSID); - pRetPacket = OSPKT_TO_RTPKT(skb); - } -#endif - - return pRetPacket; - -} - -PNDIS_PACKET duplicate_pkt( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pHeader802_3, - IN UINT HdrLen, - IN PUCHAR pData, - IN ULONG DataSize, - IN UCHAR FromWhichBSSID) -{ - struct sk_buff *skb; - PNDIS_PACKET pPacket = NULL; - - - if ((skb = __dev_alloc_skb(HdrLen + DataSize + 2, MEM_ALLOC_FLAG)) != NULL) - { - skb_reserve(skb, 2); - NdisMoveMemory(skb->tail, pHeader802_3, HdrLen); - skb_put(skb, HdrLen); - NdisMoveMemory(skb->tail, pData, DataSize); - skb_put(skb, DataSize); - skb->dev = get_netdev_from_bssid(pAd, FromWhichBSSID); - pPacket = OSPKT_TO_RTPKT(skb); - } - - return pPacket; -} - - -#define TKIP_TX_MIC_SIZE 8 -PNDIS_PACKET duplicate_pkt_with_TKIP_MIC( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket) -{ - struct sk_buff *skb, *newskb; - - - skb = RTPKT_TO_OSPKT(pPacket); - if (skb_tailroom(skb) < TKIP_TX_MIC_SIZE) - { - // alloc a new skb and copy the packet - newskb = skb_copy_expand(skb, skb_headroom(skb), TKIP_TX_MIC_SIZE, GFP_ATOMIC); - dev_kfree_skb_any(skb); - if (newskb == NULL) - { - DBGPRINT(RT_DEBUG_ERROR, ("Extend Tx.MIC for packet failed!, dropping packet!\n")); - return NULL; - } - skb = newskb; - } - - return OSPKT_TO_RTPKT(skb); - -#if 0 - if ((data = skb_put(skb, TKIP_TX_MIC_SIZE)) != NULL) - { // If we can extend it, well, copy it first. - NdisMoveMemory(data, pAd->PrivateInfo.Tx.MIC, TKIP_TX_MIC_SIZE); - } - else - { - // Otherwise, copy the packet. - newskb = skb_copy_expand(skb, skb_headroom(skb), TKIP_TX_MIC_SIZE, GFP_ATOMIC); - dev_kfree_skb_any(skb); - if (newskb == NULL) - { - DBGPRINT(RT_DEBUG_ERROR, ("Extend Tx.MIC to packet failed!, dropping packet\n")); - return NULL; - } - skb = newskb; - - NdisMoveMemory(skb->tail, pAd->PrivateInfo.Tx.MIC, TKIP_TX_MIC_SIZE); - skb_put(skb, TKIP_TX_MIC_SIZE); - } - - return OSPKT_TO_RTPKT(skb); -#endif - -} - - - - -PNDIS_PACKET ClonePacket( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket, - IN PUCHAR pData, - IN ULONG DataSize) -{ - struct sk_buff *pRxPkt; - struct sk_buff *pClonedPkt; - - ASSERT(pPacket); - pRxPkt = RTPKT_TO_OSPKT(pPacket); - - // clone the packet - pClonedPkt = skb_clone(pRxPkt, MEM_ALLOC_FLAG); - - if (pClonedPkt) - { - // set the correct dataptr and data len - pClonedPkt->dev = pRxPkt->dev; - pClonedPkt->data = pData; - pClonedPkt->len = DataSize; - pClonedPkt->tail = pClonedPkt->data + pClonedPkt->len; - ASSERT(DataSize < 1530); - } - return pClonedPkt; -} - -// -// change OS packet DataPtr and DataLen -// -void update_os_packet_info( - IN PRTMP_ADAPTER pAd, - IN RX_BLK *pRxBlk, - IN UCHAR FromWhichBSSID) -{ - struct sk_buff *pOSPkt; - - ASSERT(pRxBlk->pRxPacket); - pOSPkt = RTPKT_TO_OSPKT(pRxBlk->pRxPacket); - - pOSPkt->dev = get_netdev_from_bssid(pAd, FromWhichBSSID); - pOSPkt->data = pRxBlk->pData; - pOSPkt->len = pRxBlk->DataSize; - pOSPkt->tail = pOSPkt->data + pOSPkt->len; -} - - -void wlan_802_11_to_802_3_packet( - IN PRTMP_ADAPTER pAd, - IN RX_BLK *pRxBlk, - IN PUCHAR pHeader802_3, - IN UCHAR FromWhichBSSID) -{ - struct sk_buff *pOSPkt; - - ASSERT(pRxBlk->pRxPacket); - ASSERT(pHeader802_3); - - pOSPkt = RTPKT_TO_OSPKT(pRxBlk->pRxPacket); - - pOSPkt->dev = get_netdev_from_bssid(pAd, FromWhichBSSID); - pOSPkt->data = pRxBlk->pData; - pOSPkt->len = pRxBlk->DataSize; - pOSPkt->tail = pOSPkt->data + pOSPkt->len; - - // - // copy 802.3 header - // - // - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - NdisMoveMemory(skb_push(pOSPkt, LENGTH_802_3), pHeader802_3, LENGTH_802_3); -#endif // CONFIG_STA_SUPPORT // - } - - - -void announce_802_3_packet( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket) -{ - - struct sk_buff *pRxPkt; - - ASSERT(pPacket); - - pRxPkt = RTPKT_TO_OSPKT(pPacket); - -#ifdef CONFIG_STA_SUPPORT -#endif // CONFIG_STA_SUPPORT // - - /* Push up the protocol stack */ -#ifdef IKANOS_VX_1X0 - IKANOS_DataFrameRx(pAd, pRxPkt->dev, pRxPkt, pRxPkt->len); -#else - pRxPkt->protocol = eth_type_trans(pRxPkt, pRxPkt->dev); - -//#ifdef CONFIG_5VT_ENHANCE -// *(int*)(pRxPkt->cb) = BRIDGE_TAG; -//#endif - netif_rx(pRxPkt); -#endif // IKANOS_VX_1X0 // -} - - -PRTMP_SCATTER_GATHER_LIST -rt_get_sg_list_from_packet(PNDIS_PACKET pPacket, RTMP_SCATTER_GATHER_LIST *sg) -{ - sg->NumberOfElements = 1; - sg->Elements[0].Address = GET_OS_PKT_DATAPTR(pPacket); - sg->Elements[0].Length = GET_OS_PKT_LEN(pPacket); - return (sg); -} - -void hex_dump(char *str, unsigned char *pSrcBufVA, unsigned int SrcBufLen) -{ - unsigned char *pt; - int x; - - if (RTDebugLevel < RT_DEBUG_TRACE) - return; - - pt = pSrcBufVA; - printk("%s: %p, len = %d\n",str, pSrcBufVA, SrcBufLen); - for (x=0; x= 15 - - union iwreq_data wrqu; - PUCHAR pBuf = NULL, pBufPtr = NULL; - USHORT event, type, BufLen; - UCHAR event_table_len = 0; - - type = Event_flag & 0xFF00; - event = Event_flag & 0x00FF; - - switch (type) - { - case IW_SYS_EVENT_FLAG_START: - event_table_len = IW_SYS_EVENT_TYPE_NUM; - break; - - case IW_SPOOF_EVENT_FLAG_START: - event_table_len = IW_SPOOF_EVENT_TYPE_NUM; - break; - - case IW_FLOOD_EVENT_FLAG_START: - event_table_len = IW_FLOOD_EVENT_TYPE_NUM; - break; - } - - if (event_table_len == 0) - { - DBGPRINT(RT_DEBUG_ERROR, ("%s : The type(%0x02x) is not valid.\n", __func__, type)); - return; - } - - if (event >= event_table_len) - { - DBGPRINT(RT_DEBUG_ERROR, ("%s : The event(%0x02x) is not valid.\n", __func__, event)); - return; - } - - //Allocate memory and copy the msg. - if((pBuf = kmalloc(IW_CUSTOM_MAX_LEN, GFP_ATOMIC)) != NULL) - { - //Prepare the payload - memset(pBuf, 0, IW_CUSTOM_MAX_LEN); - - pBufPtr = pBuf; - - if (pAddr) - pBufPtr += sprintf(pBufPtr, "(RT2860) STA(%02x:%02x:%02x:%02x:%02x:%02x) ", PRINT_MAC(pAddr)); - else if (BssIdx < MAX_MBSSID_NUM) - pBufPtr += sprintf(pBufPtr, "(RT2860) BSS(ra%d) ", BssIdx); - else - pBufPtr += sprintf(pBufPtr, "(RT2860) "); - - if (type == IW_SYS_EVENT_FLAG_START) - pBufPtr += sprintf(pBufPtr, "%s", pWirelessSysEventText[event]); - else if (type == IW_SPOOF_EVENT_FLAG_START) - pBufPtr += sprintf(pBufPtr, "%s (RSSI=%d)", pWirelessSpoofEventText[event], Rssi); - else if (type == IW_FLOOD_EVENT_FLAG_START) - pBufPtr += sprintf(pBufPtr, "%s", pWirelessFloodEventText[event]); - else - pBufPtr += sprintf(pBufPtr, "%s", "unknown event"); - - pBufPtr[pBufPtr - pBuf] = '\0'; - BufLen = pBufPtr - pBuf; - - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.flags = Event_flag; - wrqu.data.length = BufLen; - - //send wireless event - wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, pBuf); - - //DBGPRINT(RT_DEBUG_TRACE, ("%s : %s\n", __func__, pBuf)); - - kfree(pBuf); - } - else - DBGPRINT(RT_DEBUG_ERROR, ("%s : Can't allocate memory for wireless event.\n", __func__)); -#else - DBGPRINT(RT_DEBUG_ERROR, ("%s : The Wireless Extension MUST be v15 or newer.\n", __func__)); -#endif /* WIRELESS_EXT >= 15 */ -} - - -#ifdef CONFIG_STA_SUPPORT -void send_monitor_packets( - IN PRTMP_ADAPTER pAd, - IN RX_BLK *pRxBlk) -{ - struct sk_buff *pOSPkt; - wlan_ng_prism2_header *ph; - int rate_index = 0; - USHORT header_len = 0; - UCHAR temp_header[40] = {0}; - - u_int32_t ralinkrate[256] = {2,4,11,22, 12,18,24,36,48,72,96, 108, 109, 110, 111, 112, 13, 26, 39, 52,78,104, 117, 130, 26, 52, 78,104, 156, 208, 234, 260, 27, 54,81,108,162, 216, 243, 270, // Last 38 - 54, 108, 162, 216, 324, 432, 486, 540, 14, 29, 43, 57, 87, 115, 130, 144, 29, 59,87,115, 173, 230,260, 288, 30, 60,90,120,180,240,270,300,60,120,180,240,360,480,540,600, 0,1,2,3,4,5,6,7,8,9,10, - 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80}; - - - ASSERT(pRxBlk->pRxPacket); - if (pRxBlk->DataSize < 10) - { - DBGPRINT(RT_DEBUG_ERROR, ("%s : Size is too small! (%d)\n", __func__, pRxBlk->DataSize)); - goto err_free_sk_buff; - } - - if (pRxBlk->DataSize + sizeof(wlan_ng_prism2_header) > RX_BUFFER_AGGRESIZE) - { - DBGPRINT(RT_DEBUG_ERROR, ("%s : Size is too large! (%zu)\n", __func__, pRxBlk->DataSize + sizeof(wlan_ng_prism2_header))); - goto err_free_sk_buff; - } - - pOSPkt = RTPKT_TO_OSPKT(pRxBlk->pRxPacket); - pOSPkt->dev = get_netdev_from_bssid(pAd, BSS0); - if (pRxBlk->pHeader->FC.Type == BTYPE_DATA) - { - pRxBlk->DataSize -= LENGTH_802_11; - if ((pRxBlk->pHeader->FC.ToDs == 1) && - (pRxBlk->pHeader->FC.FrDs == 1)) - header_len = LENGTH_802_11_WITH_ADDR4; - else - header_len = LENGTH_802_11; - - // QOS - if (pRxBlk->pHeader->FC.SubType & 0x08) - { - header_len += 2; - // Data skip QOS contorl field - pRxBlk->DataSize -=2; - } - - // Order bit: A-Ralink or HTC+ - if (pRxBlk->pHeader->FC.Order) - { - header_len += 4; - // Data skip HTC contorl field - pRxBlk->DataSize -= 4; - } - - // Copy Header - if (header_len <= 40) - NdisMoveMemory(temp_header, pRxBlk->pData, header_len); - - // skip HW padding - if (pRxBlk->RxD.L2PAD) - pRxBlk->pData += (header_len + 2); - else - pRxBlk->pData += header_len; - } //end if - - - if (pRxBlk->DataSize < pOSPkt->len) { - skb_trim(pOSPkt,pRxBlk->DataSize); - } else { - skb_put(pOSPkt,(pRxBlk->DataSize - pOSPkt->len)); - } //end if - - if ((pRxBlk->pData - pOSPkt->data) > 0) { - skb_put(pOSPkt,(pRxBlk->pData - pOSPkt->data)); - skb_pull(pOSPkt,(pRxBlk->pData - pOSPkt->data)); - } //end if - - if (skb_headroom(pOSPkt) < (sizeof(wlan_ng_prism2_header)+ header_len)) { - if (pskb_expand_head(pOSPkt, (sizeof(wlan_ng_prism2_header) + header_len), 0, GFP_ATOMIC)) { - DBGPRINT(RT_DEBUG_ERROR, ("%s : Reallocate header size of sk_buff fail!\n", __func__)); - goto err_free_sk_buff; - } //end if - } //end if - - if (header_len > 0) - NdisMoveMemory(skb_push(pOSPkt, header_len), temp_header, header_len); - - ph = (wlan_ng_prism2_header *) skb_push(pOSPkt, sizeof(wlan_ng_prism2_header)); - NdisZeroMemory(ph, sizeof(wlan_ng_prism2_header)); - - ph->msgcode = DIDmsg_lnxind_wlansniffrm; - ph->msglen = sizeof(wlan_ng_prism2_header); - strcpy(ph->devname, pAd->net_dev->name); - - ph->hosttime.did = DIDmsg_lnxind_wlansniffrm_hosttime; - ph->hosttime.status = 0; - ph->hosttime.len = 4; - ph->hosttime.data = jiffies; - - ph->mactime.did = DIDmsg_lnxind_wlansniffrm_mactime; - ph->mactime.status = 0; - ph->mactime.len = 0; - ph->mactime.data = 0; - - ph->istx.did = DIDmsg_lnxind_wlansniffrm_istx; - ph->istx.status = 0; - ph->istx.len = 0; - ph->istx.data = 0; - - ph->channel.did = DIDmsg_lnxind_wlansniffrm_channel; - ph->channel.status = 0; - ph->channel.len = 4; - - ph->channel.data = (u_int32_t)pAd->CommonCfg.Channel; - - ph->rssi.did = DIDmsg_lnxind_wlansniffrm_rssi; - ph->rssi.status = 0; - ph->rssi.len = 4; - ph->rssi.data = (u_int32_t)RTMPMaxRssi(pAd, ConvertToRssi(pAd, pRxBlk->pRxWI->RSSI0, RSSI_0), ConvertToRssi(pAd, pRxBlk->pRxWI->RSSI1, RSSI_1), ConvertToRssi(pAd, pRxBlk->pRxWI->RSSI2, RSSI_2));; - - ph->signal.did = DIDmsg_lnxind_wlansniffrm_signal; - ph->signal.status = 0; - ph->signal.len = 4; - ph->signal.data = 0; //rssi + noise; - - ph->noise.did = DIDmsg_lnxind_wlansniffrm_noise; - ph->noise.status = 0; - ph->noise.len = 4; - ph->noise.data = 0; - -#ifdef DOT11_N_SUPPORT - if (pRxBlk->pRxWI->PHYMODE >= MODE_HTMIX) - { - rate_index = 16 + ((UCHAR)pRxBlk->pRxWI->BW *16) + ((UCHAR)pRxBlk->pRxWI->ShortGI *32) + ((UCHAR)pRxBlk->pRxWI->MCS); - } - else -#endif // DOT11_N_SUPPORT // - if (pRxBlk->pRxWI->PHYMODE == MODE_OFDM) - rate_index = (UCHAR)(pRxBlk->pRxWI->MCS) + 4; - else - rate_index = (UCHAR)(pRxBlk->pRxWI->MCS); - if (rate_index < 0) - rate_index = 0; - if (rate_index > 255) - rate_index = 255; - - ph->rate.did = DIDmsg_lnxind_wlansniffrm_rate; - ph->rate.status = 0; - ph->rate.len = 4; - ph->rate.data = ralinkrate[rate_index]; - - ph->frmlen.did = DIDmsg_lnxind_wlansniffrm_frmlen; - ph->frmlen.status = 0; - ph->frmlen.len = 4; - ph->frmlen.data = (u_int32_t)pRxBlk->DataSize; - - - pOSPkt->pkt_type = PACKET_OTHERHOST; - pOSPkt->protocol = eth_type_trans(pOSPkt, pOSPkt->dev); - pOSPkt->ip_summed = CHECKSUM_NONE; - netif_rx(pOSPkt); - - return; - -err_free_sk_buff: - RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); - return; - -} -#endif // CONFIG_STA_SUPPORT // - - -void rtmp_os_thread_init(PUCHAR pThreadName, PVOID pNotify) -{ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) - daemonize(pThreadName /*"%s",pAd->net_dev->name*/); - - allow_signal(SIGTERM); - allow_signal(SIGKILL); - current->flags |= PF_NOFREEZE; -#else - unsigned long flags; - - daemonize(); - reparent_to_init(); - strcpy(current->comm, pThreadName); - - siginitsetinv(¤t->blocked, sigmask(SIGTERM) | sigmask(SIGKILL)); - - /* Allow interception of SIGKILL only - * Don't allow other signals to interrupt the transmission */ -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,22) - spin_lock_irqsave(¤t->sigmask_lock, flags); - flush_signals(current); - recalc_sigpending(current); - spin_unlock_irqrestore(¤t->sigmask_lock, flags); -#endif -#endif - - /* signal that we've started the thread */ - complete(pNotify); - -} - -void RTMP_IndicateMediaState( - IN PRTMP_ADAPTER pAd) -{ - if (pAd->CommonCfg.bWirelessEvent) - { - if (pAd->IndicateMediaState == NdisMediaStateConnected) - { - RTMPSendWirelessEvent(pAd, IW_STA_LINKUP_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); - } - else - { - RTMPSendWirelessEvent(pAd, IW_STA_LINKDOWN_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); - } - } -} - +#include "../rt2860/rt_linux.c" diff --git a/drivers/staging/rt2870/rt_linux.h b/drivers/staging/rt2870/rt_linux.h index 5a6ee6ad0e52..b2aeafbd5189 100644 --- a/drivers/staging/rt2870/rt_linux.h +++ b/drivers/staging/rt2870/rt_linux.h @@ -1,906 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * 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. * - * * - ************************************************************************* - */ - -/***********************************************************************/ -/* */ -/* Program: rt_linux.c */ -/* Created: 4/21/2006 1:17:38 PM */ -/* Author: Wu Xi-Kun */ -/* Comments: `description` */ -/* */ -/*---------------------------------------------------------------------*/ -/* */ -/* History: */ -/* Revision 1.1 4/21/2006 1:17:38 PM xsikun */ -/* Initial revision */ -/* */ -/***********************************************************************/ - -#include "rtmp_type.h" -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#include - -// load firmware -#define __KERNEL_SYSCALLS__ -#include -#include - - -#define MEM_ALLOC_FLAG (GFP_ATOMIC) //(GFP_DMA | GFP_ATOMIC) - -#ifndef IFNAMSIZ -#define IFNAMSIZ 16 -#endif - -//#define CONFIG_CKIP_SUPPORT - -#undef __inline -#define __inline static inline - -typedef int (*HARD_START_XMIT_FUNC)(struct sk_buff *skb, struct net_device *net_dev); - -// add by kathy - -#ifdef CONFIG_STA_SUPPORT - -#ifdef RT2870 -#define STA_PROFILE_PATH "/etc/Wireless/RT2870STA/RT2870STA.dat" -#define STA_RT2870_IMAGE_FILE_NAME "/etc/Wireless/RT2870STA/rt2870.bin" -#define STA_NIC_DEVICE_NAME "RT2870STA" -#define STA_DRIVER_VERSION "1.4.0.0" -#ifdef MULTIPLE_CARD_SUPPORT -#define CARD_INFO_PATH "/etc/Wireless/RT2870STA/RT2870STACard.dat" -#endif // MULTIPLE_CARD_SUPPORT // -#endif // RT2870 // - -#endif // CONFIG_STA_SUPPORT // - - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) - -#define RTMP_TIME_AFTER(a,b) \ - (typecheck(unsigned long, (unsigned long)a) && \ - typecheck(unsigned long, (unsigned long)b) && \ - ((long)(b) - (long)(a) < 0)) - -#define RTMP_TIME_AFTER_EQ(a,b) \ - (typecheck(unsigned long, (unsigned long)a) && \ - typecheck(unsigned long, (unsigned long)b) && \ - ((long)(a) - (long)(b) >= 0)) -#define RTMP_TIME_BEFORE(a,b) RTMP_TIME_AFTER_EQ(b,a) -#else -#define RTMP_TIME_AFTER(a,b) time_after(a, b) -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) -#define RT_MOD_INC_USE_COUNT() \ - if (!try_module_get(THIS_MODULE)) \ - { \ - DBGPRINT(RT_DEBUG_ERROR, ("%s: cannot reserve module\n", __func__)); \ - return -1; \ - } - -#define RT_MOD_DEC_USE_COUNT() module_put(THIS_MODULE); -#else -#define RT_MOD_INC_USE_COUNT() MOD_INC_USE_COUNT; -#define RT_MOD_DEC_USE_COUNT() MOD_DEC_USE_COUNT; -#endif - -#define OS_HZ HZ - -#define ETH_LENGTH_OF_ADDRESS 6 - -#define IN -#define OUT - -#define NDIS_STATUS INT -#define NDIS_STATUS_SUCCESS 0x00 -#define NDIS_STATUS_FAILURE 0x01 -#define NDIS_STATUS_INVALID_DATA 0x02 -#define NDIS_STATUS_RESOURCES 0x03 - -#define MIN_NET_DEVICE_FOR_AID 0x00 //0x00~0x3f -#define MIN_NET_DEVICE_FOR_MBSSID 0x00 //0x00,0x10,0x20,0x30 -#define MIN_NET_DEVICE_FOR_WDS 0x10 //0x40,0x50,0x60,0x70 -#define MIN_NET_DEVICE_FOR_APCLI 0x20 -#define MIN_NET_DEVICE_FOR_MESH 0x30 -#ifdef CONFIG_STA_SUPPORT -#define MIN_NET_DEVICE_FOR_DLS 0x40 -#endif // CONFIG_STA_SUPPORT // - - -#ifdef CONFIG_STA_SUPPORT -#define NDIS_PACKET_TYPE_DIRECTED 0 -#define NDIS_PACKET_TYPE_MULTICAST 1 -#define NDIS_PACKET_TYPE_BROADCAST 2 -#define NDIS_PACKET_TYPE_ALL_MULTICAST 3 -#endif // CONFIG_STA_SUPPORT // - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) -typedef struct pid * THREAD_PID; -#define GET_PID(_v) find_get_pid(_v) -#define GET_PID_NUMBER(_v) pid_nr(_v) -#define CHECK_PID_LEGALITY(_pid) if (pid_nr(_pid) >= 0) -#define KILL_THREAD_PID(_A, _B, _C) kill_pid(_A, _B, _C) -#else -typedef pid_t THREAD_PID; -#define GET_PID(_v) _v -#define GET_PID_NUMBER(_v) _v -#define CHECK_PID_LEGALITY(_pid) if (_pid >= 0) -#define KILL_THREAD_PID(_A, _B, _C) kill_proc(_A, _B, _C) -#endif - -struct os_lock { - spinlock_t lock; - unsigned long flags; -}; - - -struct os_cookie { - -#ifdef RT2870 - struct usb_device *pUsb_Dev; - - struct task_struct *MLMEThr_task; - struct task_struct *RTUSBCmdThr_task; - struct task_struct *TimerQThr_task; -#endif // RT2870 // - - struct tasklet_struct rx_done_task; - struct tasklet_struct mgmt_dma_done_task; - struct tasklet_struct ac0_dma_done_task; - struct tasklet_struct ac1_dma_done_task; - struct tasklet_struct ac2_dma_done_task; - struct tasklet_struct ac3_dma_done_task; - struct tasklet_struct hcca_dma_done_task; - struct tasklet_struct tbtt_task; -#ifdef RT2870 - struct tasklet_struct null_frame_complete_task; - struct tasklet_struct rts_frame_complete_task; - struct tasklet_struct pspoll_frame_complete_task; -#endif // RT2870 // - - - unsigned long apd_pid; //802.1x daemon pid - INT ioctl_if_type; - INT ioctl_if; -}; - -typedef struct _VIRTUAL_ADAPTER -{ - struct net_device *RtmpDev; - struct net_device *VirtualDev; -} VIRTUAL_ADAPTER, PVIRTUAL_ADAPTER; - -#undef ASSERT -#define ASSERT(x) \ -{ \ - if (!(x)) \ - { \ - printk(KERN_WARNING __FILE__ ":%d assert " #x "failed\n", __LINE__); \ - } \ -} - -typedef struct os_cookie * POS_COOKIE; -typedef struct pci_dev * PPCI_DEV; -typedef struct net_device * PNET_DEV; -typedef void * PNDIS_PACKET; -typedef char NDIS_PACKET; -typedef PNDIS_PACKET * PPNDIS_PACKET; -typedef dma_addr_t NDIS_PHYSICAL_ADDRESS; -typedef dma_addr_t * PNDIS_PHYSICAL_ADDRESS; -//typedef struct timer_list RALINK_TIMER_STRUCT; -//typedef struct timer_list * PRALINK_TIMER_STRUCT; -//typedef struct os_lock NDIS_SPIN_LOCK; -typedef spinlock_t NDIS_SPIN_LOCK; -typedef struct timer_list NDIS_MINIPORT_TIMER; -typedef void * NDIS_HANDLE; -typedef char * PNDIS_BUFFER; - - - -void hex_dump(char *str, unsigned char *pSrcBufVA, unsigned int SrcBufLen); - -dma_addr_t linux_pci_map_single(void *handle, void *ptr, size_t size, int sd_idx, int direction); -void linux_pci_unmap_single(void *handle, dma_addr_t dma_addr, size_t size, int direction); - - -//////////////////////////////////////// -// MOVE TO rtmp.h ? -///////////////////////////////////////// -#define PKTSRC_NDIS 0x7f -#define PKTSRC_DRIVER 0x0f -#define PRINT_MAC(addr) \ - addr[0], addr[1], addr[2], addr[3], addr[4], addr[5] - - -#define RT2860_PCI_DEVICE_ID 0x0601 - - -#ifdef RT2870 -#define PCI_MAP_SINGLE(_handle, _ptr, _size, _dir) (ULONG)0 - -#define PCI_UNMAP_SINGLE(_handle, _ptr, _size, _dir) -#endif // RT2870 // - - -#define BEACON_FRAME_DMA_CACHE_WBACK(_ptr, _size) \ - dma_cache_wback(_ptr, _size) - - -////////////////////////////////////////// -// -////////////////////////////////////////// - - -#define NdisMIndicateStatus(_w, _x, _y, _z) - -typedef struct timer_list RTMP_OS_TIMER; - -#ifdef RT2870 -/* ----------------- Timer Related MARCO ---------------*/ -// In RT2870, we have a lot of timer functions and will read/write register, it's -// not allowed in Linux USB sub-system to do it ( because of sleep issue when submit -// to ctrl pipe). So we need a wrapper function to take care it. - -typedef VOID (*RT2870_TIMER_HANDLE)( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); -#endif // RT2870 // - - -typedef struct _RALINK_TIMER_STRUCT { - RTMP_OS_TIMER TimerObj; // Ndis Timer object - BOOLEAN Valid; // Set to True when call RTMPInitTimer - BOOLEAN State; // True if timer cancelled - BOOLEAN PeriodicType; // True if timer is periodic timer - BOOLEAN Repeat; // True if periodic timer - ULONG TimerValue; // Timer value in milliseconds - ULONG cookie; // os specific object -#ifdef RT2870 - RT2870_TIMER_HANDLE handle; - void *pAd; -#endif // RT2870 // -} RALINK_TIMER_STRUCT, *PRALINK_TIMER_STRUCT; - - -#ifdef RT2870 - -typedef enum _RT2870_KERNEL_THREAD_STATUS_ -{ - RT2870_THREAD_UNKNOWN = 0, - RT2870_THREAD_INITED = 1, - RT2870_THREAD_RUNNING = 2, - RT2870_THREAD_STOPED = 4, -}RT2870_KERNEL_THREAD_STATUS; - -#define RT2870_THREAD_CAN_DO_INSERT (RT2870_THREAD_INITED |RT2870_THREAD_RUNNING) - -typedef struct _RT2870_TIMER_ENTRY_ -{ - RALINK_TIMER_STRUCT *pRaTimer; - struct _RT2870_TIMER_ENTRY_ *pNext; -}RT2870_TIMER_ENTRY; - - -#define TIMER_QUEUE_SIZE_MAX 128 -typedef struct _RT2870_TIMER_QUEUE_ -{ - unsigned int status; - //wait_queue_head_t timerWaitQ; - //atomic_t count; - UCHAR *pTimerQPoll; - RT2870_TIMER_ENTRY *pQPollFreeList; - RT2870_TIMER_ENTRY *pQHead; - RT2870_TIMER_ENTRY *pQTail; -}RT2870_TIMER_QUEUE; -#endif // RT2870 // - - -//#define DBG 1 - -// -// MACRO for debugging information -// - -#ifdef DBG -extern ULONG RTDebugLevel; - -#define DBGPRINT_RAW(Level, Fmt) \ -{ \ - if (Level <= RTDebugLevel) \ - { \ - printk Fmt; \ - } \ -} - -#define DBGPRINT(Level, Fmt) DBGPRINT_RAW(Level, Fmt) - - -#define DBGPRINT_ERR(Fmt) \ -{ \ - printk("ERROR!!! "); \ - printk Fmt; \ -} - -#define DBGPRINT_S(Status, Fmt) \ -{ \ - printk Fmt; \ -} - - -#else -#define DBGPRINT(Level, Fmt) -#define DBGPRINT_RAW(Level, Fmt) -#define DBGPRINT_S(Status, Fmt) -#define DBGPRINT_ERR(Fmt) -#endif - - -// -// spin_lock enhanced for Nested spin lock -// -#define NdisAllocateSpinLock(__lock) \ -{ \ - spin_lock_init((spinlock_t *)(__lock)); \ -} - -#define NdisFreeSpinLock(lock) \ -{ \ -} - - -#define RTMP_SEM_LOCK(__lock) \ -{ \ - spin_lock_bh((spinlock_t *)(__lock)); \ -} - -#define RTMP_SEM_UNLOCK(__lock) \ -{ \ - spin_unlock_bh((spinlock_t *)(__lock)); \ -} - -#if 0 // sample, IRQ LOCK -#define RTMP_IRQ_LOCK(__lock, __irqflags) \ -{ \ - spin_lock_irqsave((spinlock_t *)__lock, __irqflags); \ - pAd->irq_disabled |= 1; \ -} - -#define RTMP_IRQ_UNLOCK(__lock, __irqflag) \ -{ \ - pAd->irq_disabled &= 0; \ - spin_unlock_irqrestore((spinlock_t *)(__lock), ((unsigned long)__irqflag)); \ -} -#else - -// sample, use semaphore lock to replace IRQ lock, 2007/11/15 -#define RTMP_IRQ_LOCK(__lock, __irqflags) \ -{ \ - __irqflags = 0; \ - spin_lock_bh((spinlock_t *)(__lock)); \ - pAd->irq_disabled |= 1; \ -} - -#define RTMP_IRQ_UNLOCK(__lock, __irqflag) \ -{ \ - pAd->irq_disabled &= 0; \ - spin_unlock_bh((spinlock_t *)(__lock)); \ -} - -#define RTMP_INT_LOCK(__lock, __irqflags) \ -{ \ - spin_lock_irqsave((spinlock_t *)__lock, __irqflags); \ -} - -#define RTMP_INT_UNLOCK(__lock, __irqflag) \ -{ \ - spin_unlock_irqrestore((spinlock_t *)(__lock), ((unsigned long)__irqflag)); \ -} -#endif - - - -#ifdef RT2870 -//Patch for ASIC turst read/write bug, needs to remove after metel fix -#define RTMP_IO_READ32(_A, _R, _pV) \ - RTUSBReadMACRegister(_A, _R, _pV) - -#define RTMP_IO_READ8(_A, _R, _pV) \ -{ \ -} - -#define RTMP_IO_WRITE32(_A, _R, _V) \ - RTUSBWriteMACRegister(_A, _R, _V) - - -#define RTMP_IO_WRITE8(_A, _R, _V) \ -{ \ - USHORT _Val = _V; \ - RTUSBSingleWrite(_A, _R, _Val); \ -} - - -#define RTMP_IO_WRITE16(_A, _R, _V) \ -{ \ - RTUSBSingleWrite(_A, _R, _V); \ -} -#endif // RT2870 // - -#ifndef wait_event_interruptible_timeout -#define __wait_event_interruptible_timeout(wq, condition, ret) \ -do { \ - wait_queue_t __wait; \ - init_waitqueue_entry(&__wait, current); \ - add_wait_queue(&wq, &__wait); \ - for (;;) { \ - set_current_state(TASK_INTERRUPTIBLE); \ - if (condition) \ - break; \ - if (!signal_pending(current)) { \ - ret = schedule_timeout(ret); \ - if (!ret) \ - break; \ - continue; \ - } \ - ret = -ERESTARTSYS; \ - break; \ - } \ - current->state = TASK_RUNNING; \ - remove_wait_queue(&wq, &__wait); \ -} while (0) - -#define wait_event_interruptible_timeout(wq, condition, timeout) \ -({ \ - long __ret = timeout; \ - if (!(condition)) \ - __wait_event_interruptible_timeout(wq, condition, __ret); \ - __ret; \ -}) -#endif -#define ONE_TICK 1 -#define OS_WAIT(_time) \ -{ int _i; \ - long _loop = ((_time)/(1000/OS_HZ)) > 0 ? ((_time)/(1000/OS_HZ)) : 1;\ - wait_queue_head_t _wait; \ - init_waitqueue_head(&_wait); \ - for (_i=0; _i<(_loop); _i++) \ - wait_event_interruptible_timeout(_wait, 0, ONE_TICK); } - - -typedef void (*TIMER_FUNCTION)(unsigned long); - -#define COPY_MAC_ADDR(Addr1, Addr2) memcpy((Addr1), (Addr2), MAC_ADDR_LEN) - -#define MlmeAllocateMemory(_pAd, _ppVA) os_alloc_mem(_pAd, _ppVA, MGMT_DMA_BUFFER_SIZE) -#define MlmeFreeMemory(_pAd, _pVA) os_free_mem(_pAd, _pVA) - - -#ifdef RT2870 -#define BUILD_TIMER_FUNCTION(_func) \ -void linux_##_func(unsigned long data) \ -{ \ - PRALINK_TIMER_STRUCT _pTimer = (PRALINK_TIMER_STRUCT)data; \ - RT2870_TIMER_ENTRY *_pQNode; \ - RTMP_ADAPTER *_pAd; \ - \ - _pTimer->handle = _func; \ - _pAd = (RTMP_ADAPTER *)_pTimer->pAd; \ - _pQNode = RT2870_TimerQ_Insert(_pAd, _pTimer); \ - if ((_pQNode == NULL) && (_pAd->TimerQ.status & RT2870_THREAD_CAN_DO_INSERT)) \ - RTMP_OS_Add_Timer(&_pTimer->TimerObj, HZ); \ -} -#endif // RT2870 // - - -#define DECLARE_TIMER_FUNCTION(_func) \ -void linux_##_func(unsigned long data) - -#define GET_TIMER_FUNCTION(_func) \ - linux_##_func - -DECLARE_TIMER_FUNCTION(MlmePeriodicExec); -DECLARE_TIMER_FUNCTION(MlmeRssiReportExec); -DECLARE_TIMER_FUNCTION(AsicRxAntEvalTimeout); -DECLARE_TIMER_FUNCTION(APSDPeriodicExec); -DECLARE_TIMER_FUNCTION(AsicRfTuningExec); -#ifdef RT2870 -DECLARE_TIMER_FUNCTION(BeaconUpdateExec); -#endif // RT2870 // - - -#ifdef CONFIG_STA_SUPPORT -DECLARE_TIMER_FUNCTION(BeaconTimeout); -DECLARE_TIMER_FUNCTION(ScanTimeout); -DECLARE_TIMER_FUNCTION(AuthTimeout); -DECLARE_TIMER_FUNCTION(AssocTimeout); -DECLARE_TIMER_FUNCTION(ReassocTimeout); -DECLARE_TIMER_FUNCTION(DisassocTimeout); -DECLARE_TIMER_FUNCTION(LinkDownExec); -#ifdef LEAP_SUPPORT -DECLARE_TIMER_FUNCTION(LeapAuthTimeout); -#endif -DECLARE_TIMER_FUNCTION(StaQuickResponeForRateUpExec); -DECLARE_TIMER_FUNCTION(WpaDisassocApAndBlockAssoc); -DECLARE_TIMER_FUNCTION(PsPollWakeExec); -DECLARE_TIMER_FUNCTION(RadioOnExec); - -#ifdef QOS_DLS_SUPPORT -DECLARE_TIMER_FUNCTION(DlsTimeoutAction); -#endif // QOS_DLS_SUPPORT // -#endif // CONFIG_STA_SUPPORT // - -void RTMP_GetCurrentSystemTime(LARGE_INTEGER *time); - - -/* - * packet helper - * - convert internal rt packet to os packet or - * os packet to rt packet - */ -#define RTPKT_TO_OSPKT(_p) ((struct sk_buff *)(_p)) -#define OSPKT_TO_RTPKT(_p) ((PNDIS_PACKET)(_p)) - -#define GET_OS_PKT_DATAPTR(_pkt) \ - (RTPKT_TO_OSPKT(_pkt)->data) - -#define GET_OS_PKT_LEN(_pkt) \ - (RTPKT_TO_OSPKT(_pkt)->len) - -#define GET_OS_PKT_DATATAIL(_pkt) \ - (RTPKT_TO_OSPKT(_pkt)->tail) - -#define GET_OS_PKT_HEAD(_pkt) \ - (RTPKT_TO_OSPKT(_pkt)->head) - -#define GET_OS_PKT_END(_pkt) \ - (RTPKT_TO_OSPKT(_pkt)->end) - -#define GET_OS_PKT_NETDEV(_pkt) \ - (RTPKT_TO_OSPKT(_pkt)->dev) - -#define GET_OS_PKT_TYPE(_pkt) \ - (RTPKT_TO_OSPKT(_pkt)) - -#define GET_OS_PKT_NEXT(_pkt) \ - (RTPKT_TO_OSPKT(_pkt)->next) - - -#define OS_NTOHS(_Val) \ - (ntohs(_Val)) -#define OS_HTONS(_Val) \ - (htons(_Val)) -#define OS_NTOHL(_Val) \ - (ntohl(_Val)) -#define OS_HTONL(_Val) \ - (htonl(_Val)) - -/* statistics counter */ -#define STATS_INC_RX_PACKETS(_pAd, _dev) -#define STATS_INC_TX_PACKETS(_pAd, _dev) - -#define STATS_INC_RX_BYTESS(_pAd, _dev, len) -#define STATS_INC_TX_BYTESS(_pAd, _dev, len) - -#define STATS_INC_RX_ERRORS(_pAd, _dev) -#define STATS_INC_TX_ERRORS(_pAd, _dev) - -#define STATS_INC_RX_DROPPED(_pAd, _dev) -#define STATS_INC_TX_DROPPED(_pAd, _dev) - - -#define CB_OFF 10 - - -// check DDK NDIS_PACKET data structure and find out only MiniportReservedEx[0..7] can be used by our driver without -// ambiguity. Fields after pPacket->MiniportReservedEx[8] may be used by other wrapper layer thus crashes the driver -// -//#define RTMP_GET_PACKET_MR(_p) (RTPKT_TO_OSPKT(_p)) - -// User Priority -#define RTMP_SET_PACKET_UP(_p, _prio) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+0] = _prio) -#define RTMP_GET_PACKET_UP(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+0]) - -// Fragment # -#define RTMP_SET_PACKET_FRAGMENTS(_p, _num) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+1] = _num) -#define RTMP_GET_PACKET_FRAGMENTS(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+1]) - -// 0x0 ~0x7f: TX to AP's own BSS which has the specified AID. if AID>127, set bit 7 in RTMP_SET_PACKET_EMACTAB too. -//(this value also as MAC(on-chip WCID) table index) -// 0x80~0xff: TX to a WDS link. b0~6: WDS index -#define RTMP_SET_PACKET_WCID(_p, _wdsidx) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+2] = _wdsidx) -#define RTMP_GET_PACKET_WCID(_p) ((UCHAR)(RTPKT_TO_OSPKT(_p)->cb[CB_OFF+2])) - -// 0xff: PKTSRC_NDIS, others: local TX buffer index. This value affects how to a packet -#define RTMP_SET_PACKET_SOURCE(_p, _pktsrc) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+3] = _pktsrc) -#define RTMP_GET_PACKET_SOURCE(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+3]) - -// RTS/CTS-to-self protection method -#define RTMP_SET_PACKET_RTS(_p, _num) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+4] = _num) -#define RTMP_GET_PACKET_RTS(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+4]) -// see RTMP_S(G)ET_PACKET_EMACTAB - -// TX rate index -#define RTMP_SET_PACKET_TXRATE(_p, _rate) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+5] = _rate) -#define RTMP_GET_PACKET_TXRATE(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+5]) - -// From which Interface -#define RTMP_SET_PACKET_IF(_p, _ifdx) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+6] = _ifdx) -#define RTMP_GET_PACKET_IF(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+6]) -#define RTMP_SET_PACKET_NET_DEVICE_MBSSID(_p, _bss) RTMP_SET_PACKET_IF((_p), (_bss)) -#define RTMP_SET_PACKET_NET_DEVICE_WDS(_p, _bss) RTMP_SET_PACKET_IF((_p), ((_bss) + MIN_NET_DEVICE_FOR_WDS)) -#define RTMP_SET_PACKET_NET_DEVICE_APCLI(_p, _idx) RTMP_SET_PACKET_IF((_p), ((_idx) + MIN_NET_DEVICE_FOR_APCLI)) -#define RTMP_SET_PACKET_NET_DEVICE_MESH(_p, _idx) RTMP_SET_PACKET_IF((_p), ((_idx) + MIN_NET_DEVICE_FOR_MESH)) -#define RTMP_GET_PACKET_NET_DEVICE_MBSSID(_p) RTMP_GET_PACKET_IF((_p)) -#define RTMP_GET_PACKET_NET_DEVICE(_p) RTMP_GET_PACKET_IF((_p)) - -#define RTMP_SET_PACKET_MOREDATA(_p, _morebit) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+7] = _morebit) -#define RTMP_GET_PACKET_MOREDATA(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+7]) - -//#define RTMP_SET_PACKET_NET_DEVICE_MBSSID(_p, _bss) (RTPKT_TO_OSPKT(_p)->cb[8] = _bss) -//#define RTMP_GET_PACKET_NET_DEVICE_MBSSID(_p) (RTPKT_TO_OSPKT(_p)->cb[8]) - - - - -#if 0 -//#define RTMP_SET_PACKET_DHCP(_p, _flg) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11] = _flg) -//#define RTMP_GET_PACKET_DHCP(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) -#else -// -// Sepcific Pakcet Type definition -// -#define RTMP_PACKET_SPECIFIC_CB_OFFSET 11 - -#define RTMP_PACKET_SPECIFIC_DHCP 0x01 -#define RTMP_PACKET_SPECIFIC_EAPOL 0x02 -#define RTMP_PACKET_SPECIFIC_IPV4 0x04 -#define RTMP_PACKET_SPECIFIC_WAI 0x08 -#define RTMP_PACKET_SPECIFIC_VLAN 0x10 -#define RTMP_PACKET_SPECIFIC_LLCSNAP 0x20 - -//Specific -#define RTMP_SET_PACKET_SPECIFIC(_p, _flg) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11] = _flg) - -//DHCP -#define RTMP_SET_PACKET_DHCP(_p, _flg) \ - do{ \ - if (_flg) \ - (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) |= (RTMP_PACKET_SPECIFIC_DHCP); \ - else \ - (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) &= (!RTMP_PACKET_SPECIFIC_DHCP); \ - }while(0) -#define RTMP_GET_PACKET_DHCP(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11] & RTMP_PACKET_SPECIFIC_DHCP) - -//EAPOL -#define RTMP_SET_PACKET_EAPOL(_p, _flg) \ - do{ \ - if (_flg) \ - (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) |= (RTMP_PACKET_SPECIFIC_EAPOL); \ - else \ - (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) &= (!RTMP_PACKET_SPECIFIC_EAPOL); \ - }while(0) -#define RTMP_GET_PACKET_EAPOL(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11] & RTMP_PACKET_SPECIFIC_EAPOL) - -//WAI -#define RTMP_SET_PACKET_WAI(_p, _flg) \ - do{ \ - if (_flg) \ - (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) |= (RTMP_PACKET_SPECIFIC_WAI); \ - else \ - (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) &= (!RTMP_PACKET_SPECIFIC_WAI); \ - }while(0) -#define RTMP_GET_PACKET_WAI(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11] & RTMP_PACKET_SPECIFIC_WAI) - -#define RTMP_GET_PACKET_LOWRATE(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11] & (RTMP_PACKET_SPECIFIC_EAPOL | RTMP_PACKET_SPECIFIC_DHCP | RTMP_PACKET_SPECIFIC_WAI)) - -//VLAN -#define RTMP_SET_PACKET_VLAN(_p, _flg) \ - do{ \ - if (_flg) \ - (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) |= (RTMP_PACKET_SPECIFIC_VLAN); \ - else \ - (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) &= (!RTMP_PACKET_SPECIFIC_VLAN); \ - }while(0) -#define RTMP_GET_PACKET_VLAN(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11] & RTMP_PACKET_SPECIFIC_VLAN) - -//LLC/SNAP -#define RTMP_SET_PACKET_LLCSNAP(_p, _flg) \ - do{ \ - if (_flg) \ - (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) |= (RTMP_PACKET_SPECIFIC_LLCSNAP); \ - else \ - (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) &= (!RTMP_PACKET_SPECIFIC_LLCSNAP); \ - }while(0) - -#define RTMP_GET_PACKET_LLCSNAP(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11] & RTMP_PACKET_SPECIFIC_LLCSNAP) - -// IP -#define RTMP_SET_PACKET_IPV4(_p, _flg) \ - do{ \ - if (_flg) \ - (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) |= (RTMP_PACKET_SPECIFIC_IPV4); \ - else \ - (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) &= (!RTMP_PACKET_SPECIFIC_IPV4); \ - }while(0) - -#define RTMP_GET_PACKET_IPV4(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11] & RTMP_PACKET_SPECIFIC_IPV4) - -#endif - - -// If this flag is set, it indicates that this EAPoL frame MUST be clear. -#define RTMP_SET_PACKET_CLEAR_EAP_FRAME(_p, _flg) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+12] = _flg) -#define RTMP_GET_PACKET_CLEAR_EAP_FRAME(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+12]) - -#define RTMP_SET_PACKET_5VT(_p, _flg) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+22] = _flg) -#define RTMP_GET_PACKET_5VT(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+22]) - - -#ifdef CONFIG_5VT_ENHANCE -#define BRIDGE_TAG 0x35564252 // depends on 5VT define in br_input.c -#endif - - -#define NDIS_SET_PACKET_STATUS(_p, _status) - - -#define GET_SG_LIST_FROM_PACKET(_p, _sc) \ - rt_get_sg_list_from_packet(_p, _sc) - - -#define NdisMoveMemory(Destination, Source, Length) memmove(Destination, Source, Length) -#define NdisZeroMemory(Destination, Length) memset(Destination, 0, Length) -#define NdisFillMemory(Destination, Length, Fill) memset(Destination, Fill, Length) -#define NdisEqualMemory(Source1, Source2, Length) (!memcmp(Source1, Source2, Length)) -#define RTMPEqualMemory(Source1, Source2, Length) (!memcmp(Source1, Source2, Length)) - - -#define RTMP_INC_REF(_A) 0 -#define RTMP_DEC_REF(_A) 0 -#define RTMP_GET_REF(_A) 0 - - - -/* - * ULONG - * RTMP_GetPhysicalAddressLow( - * IN NDIS_PHYSICAL_ADDRESS PhysicalAddress); - */ -#define RTMP_GetPhysicalAddressLow(PhysicalAddress) (PhysicalAddress) - -/* - * ULONG - * RTMP_GetPhysicalAddressHigh( - * IN NDIS_PHYSICAL_ADDRESS PhysicalAddress); - */ -#define RTMP_GetPhysicalAddressHigh(PhysicalAddress) (0) - -/* - * VOID - * RTMP_SetPhysicalAddressLow( - * IN NDIS_PHYSICAL_ADDRESS PhysicalAddress, - * IN ULONG Value); - */ -#define RTMP_SetPhysicalAddressLow(PhysicalAddress, Value) \ - PhysicalAddress = Value; - -/* - * VOID - * RTMP_SetPhysicalAddressHigh( - * IN NDIS_PHYSICAL_ADDRESS PhysicalAddress, - * IN ULONG Value); - */ -#define RTMP_SetPhysicalAddressHigh(PhysicalAddress, Value) - - -//CONTAINING_RECORD(pEntry, NDIS_PACKET, MiniportReservedEx); -#define QUEUE_ENTRY_TO_PACKET(pEntry) \ - (PNDIS_PACKET)(pEntry) - -#define PACKET_TO_QUEUE_ENTRY(pPacket) \ - (PQUEUE_ENTRY)(pPacket) - - -#ifndef CONTAINING_RECORD -#define CONTAINING_RECORD(address, type, field) \ -((type *)((PCHAR)(address) - offsetof(type, field))) -#endif - - -#define RELEASE_NDIS_PACKET(_pAd, _pPacket, _Status) \ -{ \ - RTMPFreeNdisPacket(_pAd, _pPacket); \ -} - - -#define SWITCH_PhyAB(_pAA, _pBB) \ -{ \ - ULONG AABasePaHigh; \ - ULONG AABasePaLow; \ - ULONG BBBasePaHigh; \ - ULONG BBBasePaLow; \ - BBBasePaHigh = RTMP_GetPhysicalAddressHigh(_pBB); \ - BBBasePaLow = RTMP_GetPhysicalAddressLow(_pBB); \ - AABasePaHigh = RTMP_GetPhysicalAddressHigh(_pAA); \ - AABasePaLow = RTMP_GetPhysicalAddressLow(_pAA); \ - RTMP_SetPhysicalAddressHigh(_pAA, BBBasePaHigh); \ - RTMP_SetPhysicalAddressLow(_pAA, BBBasePaLow); \ - RTMP_SetPhysicalAddressHigh(_pBB, AABasePaHigh); \ - RTMP_SetPhysicalAddressLow(_pBB, AABasePaLow); \ -} - - -#define NdisWriteErrorLogEntry(_a, _b, _c, _d) -#define NdisMAllocateMapRegisters(_a, _b, _c, _d, _e) NDIS_STATUS_SUCCESS - - -#define NdisAcquireSpinLock RTMP_SEM_LOCK -#define NdisReleaseSpinLock RTMP_SEM_UNLOCK - -static inline void NdisGetSystemUpTime(ULONG *time) -{ - *time = jiffies; -} - -//pPacket = CONTAINING_RECORD(pEntry, NDIS_PACKET, MiniportReservedEx); -#define QUEUE_ENTRY_TO_PKT(pEntry) \ - ((PNDIS_PACKET) (pEntry)) - -int rt28xx_packet_xmit(struct sk_buff *skb); - - - -void rtmp_os_thread_init(PUCHAR pThreadName, PVOID pNotify); - - +#include "../rt2860/rt_linux.h" diff --git a/drivers/staging/rt2870/rt_main_dev.c b/drivers/staging/rt2870/rt_main_dev.c index 48ad41136d0f..121e1636017a 100644 --- a/drivers/staging/rt2870/rt_main_dev.c +++ b/drivers/staging/rt2870/rt_main_dev.c @@ -1,1865 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - rt_main_dev.c - - Abstract: - Create and register network interface. - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Sample Mar/21/07 Merge RT2870 and RT2860 drivers. -*/ - -#include "rt_config.h" - -#define FORTY_MHZ_INTOLERANT_INTERVAL (60*1000) // 1 min - -#ifdef MULTIPLE_CARD_SUPPORT -// record whether the card in the card list is used in the card file -UINT8 MC_CardUsed[MAX_NUM_OF_MULTIPLE_CARD]; -// record used card mac address in the card list -static UINT8 MC_CardMac[MAX_NUM_OF_MULTIPLE_CARD][6]; -#endif // MULTIPLE_CARD_SUPPORT // - -/*---------------------------------------------------------------------*/ -/* Private Variables Used */ -/*---------------------------------------------------------------------*/ -//static RALINK_TIMER_STRUCT PeriodicTimer; - -char *mac = ""; // default 00:00:00:00:00:00 -char *hostname = ""; -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,12) -MODULE_PARM (mac, "s"); -#else -module_param (mac, charp, 0); -#endif -MODULE_PARM_DESC (mac, "rt28xx: wireless mac addr"); - - -/*---------------------------------------------------------------------*/ -/* Prototypes of Functions Used */ -/*---------------------------------------------------------------------*/ -#ifdef DOT11_N_SUPPORT -extern BOOLEAN ba_reordering_resource_init(PRTMP_ADAPTER pAd, int num); -extern void ba_reordering_resource_release(PRTMP_ADAPTER pAd); -#endif // DOT11_N_SUPPORT // -extern NDIS_STATUS NICLoadRateSwitchingParams(IN PRTMP_ADAPTER pAd); - - -// public function prototype -INT __devinit rt28xx_probe(IN void *_dev_p, IN void *_dev_id_p, - IN UINT argc, OUT PRTMP_ADAPTER *ppAd); - -// private function prototype -static int rt28xx_init(IN struct net_device *net_dev); -INT rt28xx_send_packets(IN struct sk_buff *skb_p, IN struct net_device *net_dev); - -#if LINUX_VERSION_CODE <= 0x20402 // Red Hat 7.1 -struct net_device *alloc_netdev( - int sizeof_priv, - const char *mask, - void (*setup)(struct net_device *)); -#endif // LINUX_VERSION_CODE // - -static void CfgInitHook(PRTMP_ADAPTER pAd); -//static BOOLEAN RT28XXAvailRANameAssign(IN CHAR *name_p); - -#ifdef CONFIG_STA_SUPPORT -extern const struct iw_handler_def rt28xx_iw_handler_def; -#endif // CONFIG_STA_SUPPORT // - -#if WIRELESS_EXT >= 12 -// This function will be called when query /proc -struct iw_statistics *rt28xx_get_wireless_stats( - IN struct net_device *net_dev); -#endif - -struct net_device_stats *RT28xx_get_ether_stats( - IN struct net_device *net_dev); - -/* -======================================================================== -Routine Description: - Close raxx interface. - -Arguments: - *net_dev the raxx interface pointer - -Return Value: - 0 Open OK - otherwise Open Fail - -Note: - 1. if open fail, kernel will not call the close function. - 2. Free memory for - (1) Mlme Memory Handler: MlmeHalt() - (2) TX & RX: RTMPFreeTxRxRingMemory() - (3) BA Reordering: ba_reordering_resource_release() -======================================================================== -*/ -int MainVirtualIF_close(IN struct net_device *net_dev) -{ - RTMP_ADAPTER *pAd = net_dev->ml_priv; - - // Sanity check for pAd - if (pAd == NULL) - return 0; // close ok - - netif_carrier_off(pAd->net_dev); - netif_stop_queue(pAd->net_dev); - - - - VIRTUAL_IF_DOWN(pAd); - - RT_MOD_DEC_USE_COUNT(); - - return 0; // close ok -} - -/* -======================================================================== -Routine Description: - Open raxx interface. - -Arguments: - *net_dev the raxx interface pointer - -Return Value: - 0 Open OK - otherwise Open Fail - -Note: - 1. if open fail, kernel will not call the close function. - 2. Free memory for - (1) Mlme Memory Handler: MlmeHalt() - (2) TX & RX: RTMPFreeTxRxRingMemory() - (3) BA Reordering: ba_reordering_resource_release() -======================================================================== -*/ -int MainVirtualIF_open(IN struct net_device *net_dev) -{ - RTMP_ADAPTER *pAd = net_dev->ml_priv; - - // Sanity check for pAd - if (pAd == NULL) - return 0; // close ok - - if (VIRTUAL_IF_UP(pAd) != 0) - return -1; - - // increase MODULE use count - RT_MOD_INC_USE_COUNT(); - - netif_start_queue(net_dev); - netif_carrier_on(net_dev); - netif_wake_queue(net_dev); - - return 0; -} - -/* -======================================================================== -Routine Description: - Close raxx interface. - -Arguments: - *net_dev the raxx interface pointer - -Return Value: - 0 Open OK - otherwise Open Fail - -Note: - 1. if open fail, kernel will not call the close function. - 2. Free memory for - (1) Mlme Memory Handler: MlmeHalt() - (2) TX & RX: RTMPFreeTxRxRingMemory() - (3) BA Reordering: ba_reordering_resource_release() -======================================================================== -*/ -int rt28xx_close(IN PNET_DEV dev) -{ - struct net_device * net_dev = (struct net_device *)dev; - RTMP_ADAPTER *pAd = net_dev->ml_priv; - BOOLEAN Cancelled = FALSE; - UINT32 i = 0; -#ifdef RT2870 - DECLARE_WAIT_QUEUE_HEAD(unlink_wakeup); - DECLARE_WAITQUEUE(wait, current); - - //RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_REMOVE_IN_PROGRESS); -#endif // RT2870 // - - - DBGPRINT(RT_DEBUG_TRACE, ("===> rt28xx_close\n")); - - // Sanity check for pAd - if (pAd == NULL) - return 0; // close ok - - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - - // If dirver doesn't wake up firmware here, - // NICLoadFirmware will hang forever when interface is up again. - if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) - { - AsicForceWakeup(pAd, TRUE); - } - -#ifdef QOS_DLS_SUPPORT - // send DLS-TEAR_DOWN message, - if (pAd->CommonCfg.bDLSCapable) - { - UCHAR i; - - // tear down local dls table entry - for (i=0; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH)) - { - RTMPSendDLSTearDownFrame(pAd, pAd->StaCfg.DLSEntry[i].MacAddr); - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - pAd->StaCfg.DLSEntry[i].Valid = FALSE; - } - } - - // tear down peer dls table entry - for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH)) - { - RTMPSendDLSTearDownFrame(pAd, pAd->StaCfg.DLSEntry[i].MacAddr); - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - pAd->StaCfg.DLSEntry[i].Valid = FALSE; - } - } - RT28XX_MLME_HANDLER(pAd); - } -#endif // QOS_DLS_SUPPORT // - - if (INFRA_ON(pAd) && - (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))) - { - MLME_DISASSOC_REQ_STRUCT DisReq; - MLME_QUEUE_ELEM *MsgElem = (MLME_QUEUE_ELEM *) kmalloc(sizeof(MLME_QUEUE_ELEM), MEM_ALLOC_FLAG); - - COPY_MAC_ADDR(DisReq.Addr, pAd->CommonCfg.Bssid); - DisReq.Reason = REASON_DEAUTH_STA_LEAVING; - - MsgElem->Machine = ASSOC_STATE_MACHINE; - MsgElem->MsgType = MT2_MLME_DISASSOC_REQ; - MsgElem->MsgLen = sizeof(MLME_DISASSOC_REQ_STRUCT); - NdisMoveMemory(MsgElem->Msg, &DisReq, sizeof(MLME_DISASSOC_REQ_STRUCT)); - - // Prevent to connect AP again in STAMlmePeriodicExec - pAd->MlmeAux.AutoReconnectSsidLen= 32; - NdisZeroMemory(pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.AutoReconnectSsidLen); - - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_DISASSOC; - MlmeDisassocReqAction(pAd, MsgElem); - kfree(MsgElem); - - RTMPusecDelay(1000); - } - -#ifdef RT2870 - RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_REMOVE_IN_PROGRESS); -#endif // RT2870 // - -#ifdef CCX_SUPPORT - RTMPCancelTimer(&pAd->StaCfg.LeapAuthTimer, &Cancelled); -#endif - - RTMPCancelTimer(&pAd->StaCfg.StaQuickResponeForRateUpTimer, &Cancelled); - RTMPCancelTimer(&pAd->StaCfg.WpaDisassocAndBlockAssocTimer, &Cancelled); - -#ifdef WPA_SUPPLICANT_SUPPORT -#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT - { - union iwreq_data wrqu; - // send wireless event to wpa_supplicant for infroming interface down. - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.flags = RT_INTERFACE_DOWN; - wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); - } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // -#endif // WPA_SUPPLICANT_SUPPORT // - - MlmeRadioOff(pAd); - } -#endif // CONFIG_STA_SUPPORT // - - RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS); - - for (i = 0 ; i < NUM_OF_TX_RING; i++) - { - while (pAd->DeQueueRunning[i] == TRUE) - { - printk("Waiting for TxQueue[%d] done..........\n", i); - RTMPusecDelay(1000); - } - } - -#ifdef RT2870 - // ensure there are no more active urbs. - add_wait_queue (&unlink_wakeup, &wait); - pAd->wait = &unlink_wakeup; - - // maybe wait for deletions to finish. - i = 0; - //while((i < 25) && atomic_read(&pAd->PendingRx) > 0) - while(i < 25) - { - unsigned long IrqFlags; - - RTMP_IRQ_LOCK(&pAd->BulkInLock, IrqFlags); - if (pAd->PendingRx == 0) - { - RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); - break; - } - RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); - -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) - msleep(UNLINK_TIMEOUT_MS); //Time in millisecond -#else - RTMPusecDelay(UNLINK_TIMEOUT_MS*1000); //Time in microsecond -#endif - i++; - } - pAd->wait = NULL; - remove_wait_queue (&unlink_wakeup, &wait); -#endif // RT2870 // - - //RTUSBCleanUpMLMEWaitQueue(pAd); /*not used in RT28xx*/ - - -#ifdef RT2870 - // We need clear timerQ related structure before exits of the timer thread. - RT2870_TimerQ_Exit(pAd); - // Close kernel threads or tasklets - RT28xxThreadTerminate(pAd); -#endif // RT2870 // - - // Stop Mlme state machine - MlmeHalt(pAd); - - // Close kernel threads or tasklets - kill_thread_task(pAd); - - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - MacTableReset(pAd); - } -#endif // CONFIG_STA_SUPPORT // - - - MeasureReqTabExit(pAd); - TpcReqTabExit(pAd); - - - - - // Free Ring or USB buffers - RTMPFreeTxRxRingMemory(pAd); - - RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS); - -#ifdef DOT11_N_SUPPORT - // Free BA reorder resource - ba_reordering_resource_release(pAd); -#endif // DOT11_N_SUPPORT // - -#ifdef RT2870 -#ifdef INF_AMAZON_SE - if (pAd->UsbVendorReqBuf) - os_free_mem(pAd, pAd->UsbVendorReqBuf); -#endif // INF_AMAZON_SE // -#endif // RT2870 // - - RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_START_UP); - - return 0; // close ok -} /* End of rt28xx_close */ - -static int rt28xx_init(IN struct net_device *net_dev) -{ - PRTMP_ADAPTER pAd = net_dev->ml_priv; - UINT index; - UCHAR TmpPhy; - NDIS_STATUS Status; - UINT32 MacCsr0 = 0; - -#ifdef RT2870 -#ifdef INF_AMAZON_SE - init_MUTEX(&(pAd->UsbVendorReq_semaphore)); - os_alloc_mem(pAd, (PUCHAR)&pAd->UsbVendorReqBuf, MAX_PARAM_BUFFER_SIZE - 1); - if (pAd->UsbVendorReqBuf == NULL) - { - DBGPRINT(RT_DEBUG_ERROR, ("Allocate vendor request temp buffer failed!\n")); - goto err0; - } -#endif // INF_AMAZON_SE // -#endif // RT2870 // - -#ifdef DOT11_N_SUPPORT - // Allocate BA Reordering memory - ba_reordering_resource_init(pAd, MAX_REORDERING_MPDU_NUM); -#endif // DOT11_N_SUPPORT // - - // Make sure MAC gets ready. - index = 0; - do - { - RTMP_IO_READ32(pAd, MAC_CSR0, &MacCsr0); - pAd->MACVersion = MacCsr0; - - if ((pAd->MACVersion != 0x00) && (pAd->MACVersion != 0xFFFFFFFF)) - break; - - RTMPusecDelay(10); - } while (index++ < 100); - - DBGPRINT(RT_DEBUG_TRACE, ("MAC_CSR0 [ Ver:Rev=0x%08x]\n", pAd->MACVersion)); - - // Disable DMA - RT28XXDMADisable(pAd); - - - // Load 8051 firmware - Status = NICLoadFirmware(pAd); - if (Status != NDIS_STATUS_SUCCESS) - { - DBGPRINT_ERR(("NICLoadFirmware failed, Status[=0x%08x]\n", Status)); - goto err1; - } - - NICLoadRateSwitchingParams(pAd); - - // Disable interrupts here which is as soon as possible - // This statement should never be true. We might consider to remove it later - - Status = RTMPAllocTxRxRingMemory(pAd); - if (Status != NDIS_STATUS_SUCCESS) - { - DBGPRINT_ERR(("RTMPAllocDMAMemory failed, Status[=0x%08x]\n", Status)); - goto err1; - } - - RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE); - - // initialize MLME - // - - Status = MlmeInit(pAd); - if (Status != NDIS_STATUS_SUCCESS) - { - DBGPRINT_ERR(("MlmeInit failed, Status[=0x%08x]\n", Status)); - goto err2; - } - - // Initialize pAd->StaCfg, pAd->ApCfg, pAd->CommonCfg to manufacture default - // - UserCfgInit(pAd); - -#ifdef RT2870 - // We need init timerQ related structure before create the timer thread. - RT2870_TimerQ_Init(pAd); -#endif // RT2870 // - - RT28XX_TASK_THREAD_INIT(pAd, Status); - if (Status != NDIS_STATUS_SUCCESS) - goto err1; - -// COPY_MAC_ADDR(pAd->ApCfg.MBSSID[apidx].Bssid, netif->hwaddr); -// pAd->bForcePrintTX = TRUE; - - CfgInitHook(pAd); - - -#ifdef BLOCK_NET_IF - initblockQueueTab(pAd); -#endif // BLOCK_NET_IF // - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - NdisAllocateSpinLock(&pAd->MacTabLock); -#endif // CONFIG_STA_SUPPORT // - - MeasureReqTabInit(pAd); - TpcReqTabInit(pAd); - - // - // Init the hardware, we need to init asic before read registry, otherwise mac register will be reset - // - Status = NICInitializeAdapter(pAd, TRUE); - if (Status != NDIS_STATUS_SUCCESS) - { - DBGPRINT_ERR(("NICInitializeAdapter failed, Status[=0x%08x]\n", Status)); - if (Status != NDIS_STATUS_SUCCESS) - goto err3; - } - - // Read parameters from Config File - Status = RTMPReadParametersHook(pAd); - - printk("1. Phy Mode = %d\n", pAd->CommonCfg.PhyMode); - if (Status != NDIS_STATUS_SUCCESS) - { - DBGPRINT_ERR(("NICReadRegParameters failed, Status[=0x%08x]\n",Status)); - goto err4; - } - -#ifdef RT2870 - pAd->CommonCfg.bMultipleIRP = FALSE; - - if (pAd->CommonCfg.bMultipleIRP) - pAd->CommonCfg.NumOfBulkInIRP = RX_RING_SIZE; - else - pAd->CommonCfg.NumOfBulkInIRP = 1; -#endif // RT2870 // - - - //Init Ba Capability parameters. -// RT28XX_BA_INIT(pAd); -#ifdef DOT11_N_SUPPORT - pAd->CommonCfg.DesiredHtPhy.MpduDensity = (UCHAR)pAd->CommonCfg.BACapability.field.MpduDensity; - pAd->CommonCfg.DesiredHtPhy.AmsduEnable = (USHORT)pAd->CommonCfg.BACapability.field.AmsduEnable; - pAd->CommonCfg.DesiredHtPhy.AmsduSize = (USHORT)pAd->CommonCfg.BACapability.field.AmsduSize; - pAd->CommonCfg.DesiredHtPhy.MimoPs = (USHORT)pAd->CommonCfg.BACapability.field.MMPSmode; - // UPdata to HT IE - pAd->CommonCfg.HtCapability.HtCapInfo.MimoPs = (USHORT)pAd->CommonCfg.BACapability.field.MMPSmode; - pAd->CommonCfg.HtCapability.HtCapInfo.AMsduSize = (USHORT)pAd->CommonCfg.BACapability.field.AmsduSize; - pAd->CommonCfg.HtCapability.HtCapParm.MpduDensity = (UCHAR)pAd->CommonCfg.BACapability.field.MpduDensity; -#endif // DOT11_N_SUPPORT // - - // after reading Registry, we now know if in AP mode or STA mode - - // Load 8051 firmware; crash when FW image not existent - // Status = NICLoadFirmware(pAd); - // if (Status != NDIS_STATUS_SUCCESS) - // break; - - printk("2. Phy Mode = %d\n", pAd->CommonCfg.PhyMode); - - // We should read EEPROM for all cases. rt2860b - NICReadEEPROMParameters(pAd, mac); -#ifdef CONFIG_STA_SUPPORT -#endif // CONFIG_STA_SUPPORT // - - printk("3. Phy Mode = %d\n", pAd->CommonCfg.PhyMode); - - NICInitAsicFromEEPROM(pAd); //rt2860b - - // Set PHY to appropriate mode - TmpPhy = pAd->CommonCfg.PhyMode; - pAd->CommonCfg.PhyMode = 0xff; - RTMPSetPhyMode(pAd, TmpPhy); -#ifdef DOT11_N_SUPPORT - SetCommonHT(pAd); -#endif // DOT11_N_SUPPORT // - - // No valid channels. - if (pAd->ChannelListNum == 0) - { - printk("Wrong configuration. No valid channel found. Check \"ContryCode\" and \"ChannelGeography\" setting.\n"); - goto err4; - } - -#ifdef DOT11_N_SUPPORT - printk("MCS Set = %02x %02x %02x %02x %02x\n", pAd->CommonCfg.HtCapability.MCSSet[0], - pAd->CommonCfg.HtCapability.MCSSet[1], pAd->CommonCfg.HtCapability.MCSSet[2], - pAd->CommonCfg.HtCapability.MCSSet[3], pAd->CommonCfg.HtCapability.MCSSet[4]); -#endif // DOT11_N_SUPPORT // - -#ifdef RT2870 - //Init RT30xx RFRegisters after read RFIC type from EEPROM - NICInitRT30xxRFRegisters(pAd); -#endif // RT2870 // - -#if 0 - // Patch cardbus controller if EEPROM said so. - if (pAd->bTest1 == FALSE) - RTMPPatchCardBus(pAd); -#endif - - -// APInitialize(pAd); - -#ifdef IKANOS_VX_1X0 - VR_IKANOS_FP_Init(pAd->ApCfg.BssidNum, pAd->PermanentAddress); -#endif // IKANOS_VX_1X0 // - - // - // Initialize RF register to default value - // - AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); - AsicLockChannel(pAd, pAd->CommonCfg.Channel); - - // 8051 firmware require the signal during booting time. - AsicSendCommandToMcu(pAd, 0x72, 0xFF, 0x00, 0x00); - - if (pAd && (Status != NDIS_STATUS_SUCCESS)) - { - // - // Undo everything if it failed - // - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { -// NdisMDeregisterInterrupt(&pAd->Interrupt); - RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE); - } -// RTMPFreeAdapter(pAd); // we will free it in disconnect() - } - else if (pAd) - { - // Microsoft HCT require driver send a disconnect event after driver initialization. - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED); -// pAd->IndicateMediaState = NdisMediaStateDisconnected; - RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_MEDIA_STATE_CHANGE); - - DBGPRINT(RT_DEBUG_TRACE, ("NDIS_STATUS_MEDIA_DISCONNECT Event B!\n")); - - -#ifdef RT2870 - RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS); - RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_REMOVE_IN_PROGRESS); - - // - // Support multiple BulkIn IRP, - // the value on pAd->CommonCfg.NumOfBulkInIRP may be large than 1. - // - for(index=0; indexCommonCfg.NumOfBulkInIRP; index++) - { - RTUSBBulkReceive(pAd); - DBGPRINT(RT_DEBUG_TRACE, ("RTUSBBulkReceive!\n" )); - } -#endif // RT2870 // - }// end of else - - - DBGPRINT_S(Status, ("<==== RTMPInitialize, Status=%x\n", Status)); - - return TRUE; - - -err4: -err3: - MlmeHalt(pAd); -err2: - RTMPFreeTxRxRingMemory(pAd); -// RTMPFreeAdapter(pAd); -err1: - -#ifdef DOT11_N_SUPPORT - os_free_mem(pAd, pAd->mpdu_blk_pool.mem); // free BA pool -#endif // DOT11_N_SUPPORT // - RT28XX_IRQ_RELEASE(net_dev); - - // shall not set ml_priv to NULL here because the ml_priv didn't been free yet. - //net_dev->ml_priv = 0; -#ifdef INF_AMAZON_SE -err0: -#endif // INF_AMAZON_SE // - printk("!!! %s Initialized fail !!!\n", RT28xx_CHIP_NAME); - return FALSE; -} /* End of rt28xx_init */ - - -/* -======================================================================== -Routine Description: - Open raxx interface. - -Arguments: - *net_dev the raxx interface pointer - -Return Value: - 0 Open OK - otherwise Open Fail - -Note: -======================================================================== -*/ -int rt28xx_open(IN PNET_DEV dev) -{ - struct net_device * net_dev = (struct net_device *)dev; - PRTMP_ADAPTER pAd = net_dev->ml_priv; - int retval = 0; - POS_COOKIE pObj; - - - // Sanity check for pAd - if (pAd == NULL) - { - /* if 1st open fail, pAd will be free; - So the net_dev->ml_priv will be NULL in 2rd open */ - return -1; - } - -#ifdef CONFIG_APSTA_MIXED_SUPPORT - if (pAd->OpMode == OPMODE_AP) - { - CW_MAX_IN_BITS = 6; - } - else if (pAd->OpMode == OPMODE_STA) - { - CW_MAX_IN_BITS = 10; - } - -#if WIRELESS_EXT >= 12 - if (net_dev->priv_flags == INT_MAIN) - { - if (pAd->OpMode == OPMODE_AP) - net_dev->wireless_handlers = (struct iw_handler_def *) &rt28xx_ap_iw_handler_def; - else if (pAd->OpMode == OPMODE_STA) - net_dev->wireless_handlers = (struct iw_handler_def *) &rt28xx_iw_handler_def; - } -#endif // WIRELESS_EXT >= 12 // -#endif // CONFIG_APSTA_MIXED_SUPPORT // - -#ifdef CONFIG_STA_SUPPORT -#endif // CONFIG_STA_SUPPORT // - - // Init - pObj = (POS_COOKIE)pAd->OS_Cookie; - - // reset Adapter flags - RTMP_CLEAR_FLAGS(pAd); - - // Request interrupt service routine for PCI device - // register the interrupt routine with the os - RT28XX_IRQ_REQUEST(net_dev); - - - // Init BssTab & ChannelInfo tabbles for auto channel select. - - - // Chip & other init - if (rt28xx_init(net_dev) == FALSE) - goto err; - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - NdisZeroMemory(pAd->StaCfg.dev_name, 16); - NdisMoveMemory(pAd->StaCfg.dev_name, net_dev->name, strlen(net_dev->name)); - } -#endif // CONFIG_STA_SUPPORT // - - // Set up the Mac address - NdisMoveMemory(net_dev->dev_addr, (void *) pAd->CurrentAddress, 6); - - // Init IRQ parameters - RT28XX_IRQ_INIT(pAd); - - // Various AP function init - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { -#ifdef WPA_SUPPLICANT_SUPPORT -#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT - { - union iwreq_data wrqu; - // send wireless event to wpa_supplicant for infroming interface down. - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.flags = RT_INTERFACE_UP; - wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); - } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // -#endif // WPA_SUPPLICANT_SUPPORT // - - } -#endif // CONFIG_STA_SUPPORT // - - // Enable Interrupt - RT28XX_IRQ_ENABLE(pAd); - - // Now Enable RxTx - RTMPEnableRxTx(pAd); - RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_START_UP); - - { - UINT32 reg = 0; - RTMP_IO_READ32(pAd, 0x1300, ®); // clear garbage interrupts - printk("0x1300 = %08x\n", reg); - } - - { -// u32 reg; -// u8 byte; -// u16 tmp; - -// RTMP_IO_READ32(pAd, XIFS_TIME_CFG, ®); - -// tmp = 0x0805; -// reg = (reg & 0xffff0000) | tmp; -// RTMP_IO_WRITE32(pAd, XIFS_TIME_CFG, reg); - - } - -#if 0 - /* - * debugging helper - * show the size of main table in Adapter structure - * MacTab -- 185K - * BATable -- 137K - * Total -- 385K !!!!! (5/26/2006) - */ - printk("sizeof(pAd->MacTab) = %ld\n", sizeof(pAd->MacTab)); - printk("sizeof(pAd->AccessControlList) = %ld\n", sizeof(pAd->AccessControlList)); - printk("sizeof(pAd->ApCfg) = %ld\n", sizeof(pAd->ApCfg)); - printk("sizeof(pAd->BATable) = %ld\n", sizeof(pAd->BATable)); - BUG(); -#endif - -#ifdef CONFIG_STA_SUPPORT -#endif // CONFIG_STA_SUPPORT // - - return (retval); - -err: - return (-1); -} /* End of rt28xx_open */ - -static const struct net_device_ops rt2870_netdev_ops = { - .ndo_open = MainVirtualIF_open, - .ndo_stop = MainVirtualIF_close, - .ndo_do_ioctl = rt28xx_ioctl, - .ndo_get_stats = RT28xx_get_ether_stats, - .ndo_validate_addr = NULL, - .ndo_set_mac_address = eth_mac_addr, - .ndo_change_mtu = eth_change_mtu, -#ifdef IKANOS_VX_1X0 - .ndo_start_xmit = IKANOS_DataFramesTx, -#else - .ndo_start_xmit = rt28xx_send_packets, -#endif -}; - -/* Must not be called for mdev and apdev */ -static NDIS_STATUS rt_ieee80211_if_setup(struct net_device *dev, PRTMP_ADAPTER pAd) -{ - NDIS_STATUS Status; - INT i=0; - CHAR slot_name[IFNAMSIZ]; - struct net_device *device; - - - //ether_setup(dev); -// dev->set_multicast_list = ieee80211_set_multicast_list; -// dev->change_mtu = ieee80211_change_mtu; -#ifdef CONFIG_STA_SUPPORT -#if WIRELESS_EXT >= 12 - if (pAd->OpMode == OPMODE_STA) - { - dev->wireless_handlers = &rt28xx_iw_handler_def; - } -#endif //WIRELESS_EXT >= 12 -#endif // CONFIG_STA_SUPPORT // - -#ifdef CONFIG_APSTA_MIXED_SUPPORT -#if WIRELESS_EXT >= 12 - if (pAd->OpMode == OPMODE_AP) - { - dev->wireless_handlers = &rt28xx_ap_iw_handler_def; - } -#endif //WIRELESS_EXT >= 12 -#endif // CONFIG_APSTA_MIXED_SUPPORT // - -#if WIRELESS_EXT < 21 - dev->get_wireless_stats = rt28xx_get_wireless_stats; -#endif -// dev->uninit = ieee80211_if_reinit; -// dev->destructor = ieee80211_if_free; - dev->priv_flags = INT_MAIN; - dev->netdev_ops = &rt2870_netdev_ops; - // find available device name - for (i = 0; i < 8; i++) - { -#ifdef MULTIPLE_CARD_SUPPORT - if (pAd->MC_RowID >= 0) - sprintf(slot_name, "ra%02d_%d", pAd->MC_RowID, i); - else -#endif // MULTIPLE_CARD_SUPPORT // - sprintf(slot_name, "ra%d", i); - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) - device = dev_get_by_name(dev_net(dev), slot_name); -#else - device = dev_get_by_name(dev->nd_net, slot_name); -#endif -#else - device = dev_get_by_name(slot_name); -#endif - if (device != NULL) dev_put(device); -#else - for (device = dev_base; device != NULL; device = device->next) - { - if (strncmp(device->name, slot_name, 4) == 0) - break; - } -#endif - if(device == NULL) - break; - } - - if(i == 8) - { - DBGPRINT(RT_DEBUG_ERROR, ("No available slot name\n")); - Status = NDIS_STATUS_FAILURE; - } - else - { -#ifdef MULTIPLE_CARD_SUPPORT - if (pAd->MC_RowID >= 0) - sprintf(dev->name, "ra%02d_%d", pAd->MC_RowID, i); - else -#endif // MULTIPLE_CARD_SUPPORT // - sprintf(dev->name, "ra%d", i); - Status = NDIS_STATUS_SUCCESS; - } - - return Status; - -} - - -#ifdef MULTIPLE_CARD_SUPPORT -/* -======================================================================== -Routine Description: - Get card profile path. - -Arguments: - pAd - -Return Value: - TRUE - Find a card profile - FALSE - use default profile - -Note: -======================================================================== -*/ -extern INT RTMPGetKeyParameter( - IN PCHAR key, - OUT PCHAR dest, - IN INT destsize, - IN PCHAR buffer); - -BOOLEAN RTMP_CardInfoRead( - IN PRTMP_ADAPTER pAd) -{ -#define MC_SELECT_CARDID 0 /* use CARD ID (0 ~ 31) to identify different cards */ -#define MC_SELECT_MAC 1 /* use CARD MAC to identify different cards */ -#define MC_SELECT_CARDTYPE 2 /* use CARD type (abgn or bgn) to identify different cards */ - -#define LETTER_CASE_TRANSLATE(txt_p, card_id) \ - { UINT32 _len; char _char; \ - for(_len=0; _lenfsuid; - orgfsgid = current->fsgid; - current->fsuid = current->fsgid = 0; - orgfs = get_fs(); - set_fs(KERNEL_DS); - - // get RF IC type - RTMP_IO_READ32(pAd, E2PROM_CSR, &data); - - if ((data & 0x30) == 0) - pAd->EEPROMAddressNum = 6; // 93C46 - else if ((data & 0x30) == 0x10) - pAd->EEPROMAddressNum = 8; // 93C66 - else - pAd->EEPROMAddressNum = 8; // 93C86 - - //antenna.word = RTMP_EEPROM_READ16(pAd, EEPROM_NIC1_OFFSET); - RT28xx_EEPROM_READ16(pAd, EEPROM_NIC1_OFFSET, antenna.word); - - if ((antenna.field.RfIcType == RFIC_2850) || - (antenna.field.RfIcType == RFIC_2750)) - { - /* ABGN card */ - strcpy(RFIC_word, "abgn"); - } - else - { - /* BGN card */ - strcpy(RFIC_word, "bgn"); - } - - // get MAC address - //addr01 = RTMP_EEPROM_READ16(pAd, 0x04); - //addr23 = RTMP_EEPROM_READ16(pAd, 0x06); - //addr45 = RTMP_EEPROM_READ16(pAd, 0x08); - RT28xx_EEPROM_READ16(pAd, 0x04, addr01); - RT28xx_EEPROM_READ16(pAd, 0x06, addr23); - RT28xx_EEPROM_READ16(pAd, 0x08, addr45); - - mac[0] = (UCHAR)(addr01 & 0xff); - mac[1] = (UCHAR)(addr01 >> 8); - mac[2] = (UCHAR)(addr23 & 0xff); - mac[3] = (UCHAR)(addr23 >> 8); - mac[4] = (UCHAR)(addr45 & 0xff); - mac[5] = (UCHAR)(addr45 >> 8); - - // open card information file - srcf = filp_open(CARD_INFO_PATH, O_RDONLY, 0); - if (IS_ERR(srcf)) - { - /* card information file does not exist */ - DBGPRINT(RT_DEBUG_TRACE, - ("--> Error %ld opening %s\n", -PTR_ERR(srcf), CARD_INFO_PATH)); - return FALSE; - } - - if (srcf->f_op && srcf->f_op->read) - { - /* card information file exists so reading the card information */ - memset(buffer, 0x00, MAX_INI_BUFFER_SIZE); - retval = srcf->f_op->read(srcf, buffer, MAX_INI_BUFFER_SIZE, &srcf->f_pos); - if (retval < 0) - { - /* read fail */ - DBGPRINT(RT_DEBUG_TRACE, - ("--> Read %s error %d\n", CARD_INFO_PATH, -retval)); - } - else - { - /* get card selection method */ - memset(tmpbuf, 0x00, MAX_PARAM_BUFFER_SIZE); - card_select_method = MC_SELECT_CARDTYPE; // default - - if (RTMPGetKeyParameter("SELECT", tmpbuf, 256, buffer)) - { - if (strcmp(tmpbuf, "CARDID") == 0) - card_select_method = MC_SELECT_CARDID; - else if (strcmp(tmpbuf, "MAC") == 0) - card_select_method = MC_SELECT_MAC; - else if (strcmp(tmpbuf, "CARDTYPE") == 0) - card_select_method = MC_SELECT_CARDTYPE; - } - - DBGPRINT(RT_DEBUG_TRACE, - ("MC> Card Selection = %d\n", card_select_method)); - - // init - card_free_id = -1; - card_nouse_id = -1; - card_same_mac_id = -1; - card_match_id = -1; - - // search current card information records - for(card_index=0; - card_index Free = %d, Same = %d, NOUSE = %d\n", - card_free_id, card_same_mac_id, card_nouse_id)); - - if ((card_same_mac_id >= 0) && - ((card_select_method == MC_SELECT_CARDID) || - (card_select_method == MC_SELECT_CARDTYPE))) - { - // same MAC entry is found - card_match_id = card_same_mac_id; - - if (card_select_method == MC_SELECT_CARDTYPE) - { - // for CARDTYPE - sprintf(card_id_buf, "%02dCARDTYPE%s", - card_match_id, RFIC_word); - - if ((start_ptr=rtstrstruncasecmp(buffer, card_id_buf)) != NULL) - { - // we found the card ID - LETTER_CASE_TRANSLATE(start_ptr, card_id_buf); - } - } - } - else - { - // the card is 1st plug-in, try to find the match card profile - switch(card_select_method) - { - case MC_SELECT_CARDID: // CARDID - default: - if (card_free_id >= 0) - card_match_id = card_free_id; - else - card_match_id = card_nouse_id; - break; - - case MC_SELECT_MAC: // MAC - sprintf(card_id_buf, "MAC%02x:%02x:%02x:%02x:%02x:%02x", - mac[0], mac[1], mac[2], - mac[3], mac[4], mac[5]); - - /* try to find the key word in the card file */ - if ((start_ptr=rtstrstruncasecmp(buffer, card_id_buf)) != NULL) - { - LETTER_CASE_TRANSLATE(start_ptr, card_id_buf); - - /* get the row ID (2 ASCII characters) */ - start_ptr -= 2; - card_id_buf[0] = *(start_ptr); - card_id_buf[1] = *(start_ptr+1); - card_id_buf[2] = 0x00; - - card_match_id = simple_strtol(card_id_buf, 0, 10); - } - break; - - case MC_SELECT_CARDTYPE: // CARDTYPE - card_nouse_id = -1; - - for(card_index=0; - card_index= 0) - { - // make up search keyword - switch(card_select_method) - { - case MC_SELECT_CARDID: // CARDID - sprintf(card_id_buf, "%02dCARDID", card_match_id); - break; - - case MC_SELECT_MAC: // MAC - sprintf(card_id_buf, - "%02dmac%02x:%02x:%02x:%02x:%02x:%02x", - card_match_id, - mac[0], mac[1], mac[2], - mac[3], mac[4], mac[5]); - break; - - case MC_SELECT_CARDTYPE: // CARDTYPE - default: - sprintf(card_id_buf, "%02dcardtype%s", - card_match_id, RFIC_word); - break; - } - - DBGPRINT(RT_DEBUG_TRACE, ("Search Keyword = %s\n", card_id_buf)); - - // read card file path - if (RTMPGetKeyParameter(card_id_buf, tmpbuf, 256, buffer)) - { - if (strlen(tmpbuf) < sizeof(pAd->MC_FileName)) - { - // backup card information - pAd->MC_RowID = card_match_id; /* base 0 */ - MC_CardUsed[card_match_id] = 1; - memcpy(MC_CardMac[card_match_id], mac, sizeof(mac)); - - // backup card file path - NdisMoveMemory(pAd->MC_FileName, tmpbuf , strlen(tmpbuf)); - pAd->MC_FileName[strlen(tmpbuf)] = '\0'; - flg_match_ok = TRUE; - - DBGPRINT(RT_DEBUG_TRACE, - ("Card Profile Name = %s\n", pAd->MC_FileName)); - } - else - { - DBGPRINT(RT_DEBUG_ERROR, - ("Card Profile Name length too large!\n")); - } - } - else - { - DBGPRINT(RT_DEBUG_ERROR, - ("Can not find search key word in card.dat!\n")); - } - - if ((flg_match_ok != TRUE) && - (card_match_id < MAX_NUM_OF_MULTIPLE_CARD)) - { - MC_CardUsed[card_match_id] = 0; - memset(MC_CardMac[card_match_id], 0, sizeof(mac)); - } - } // if (card_match_id >= 0) - } - } - - // close file - retval = filp_close(srcf, NULL); - set_fs(orgfs); - current->fsuid = orgfsuid; - current->fsgid = orgfsgid; - kfree(buffer); - kfree(tmpbuf); - return flg_match_ok; -} -#endif // MULTIPLE_CARD_SUPPORT // - - -/* -======================================================================== -Routine Description: - Probe RT28XX chipset. - -Arguments: - _dev_p Point to the PCI or USB device - _dev_id_p Point to the PCI or USB device ID - -Return Value: - 0 Probe OK - -ENODEV Probe Fail - -Note: -======================================================================== -*/ -INT __devinit rt28xx_probe( - IN void *_dev_p, - IN void *_dev_id_p, - IN UINT argc, - OUT PRTMP_ADAPTER *ppAd) -{ - struct net_device *net_dev; - PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) NULL; - INT status; - PVOID handle; -#ifdef RT2870 -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* kernel 2.4 series */ - struct usb_device *dev_p = (struct usb_device *)_dev_p; -#else - struct usb_interface *intf = (struct usb_interface *)_dev_p; - struct usb_device *dev_p = interface_to_usbdev(intf); - - dev_p = usb_get_dev(dev_p); -#endif // LINUX_VERSION_CODE // -#endif // RT2870 // - - -#ifdef CONFIG_STA_SUPPORT - DBGPRINT(RT_DEBUG_TRACE, ("STA Driver version-%s\n", STA_DRIVER_VERSION)); -#endif // CONFIG_STA_SUPPORT // - - // Check chipset vendor/product ID -// if (RT28XXChipsetCheck(_dev_p) == FALSE) -// goto err_out; - -#if LINUX_VERSION_CODE <= 0x20402 // Red Hat 7.1 - net_dev = alloc_netdev(sizeof(PRTMP_ADAPTER), "eth%d", ether_setup); -#else - net_dev = alloc_etherdev(sizeof(PRTMP_ADAPTER)); -#endif - if (net_dev == NULL) - { - printk("alloc_netdev failed\n"); - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) - module_put(THIS_MODULE); -#endif //LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) -#else - MOD_DEC_USE_COUNT; -#endif - goto err_out; - } - -// sample -// if (rt_ieee80211_if_setup(net_dev) != NDIS_STATUS_SUCCESS) -// goto err_out; - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) - SET_MODULE_OWNER(net_dev); -#endif - - netif_stop_queue(net_dev); -#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT -/* for supporting Network Manager */ -/* Set the sysfs physical device reference for the network logical device - * if set prior to registration will cause a symlink during initialization. - */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) - SET_NETDEV_DEV(net_dev, &(dev_p->dev)); -#endif -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // - - // Allocate RTMP_ADAPTER miniport adapter structure - handle = kmalloc(sizeof(struct os_cookie), GFP_KERNEL); - RT28XX_HANDLE_DEV_ASSIGN(handle, dev_p); - - status = RTMPAllocAdapterBlock(handle, &pAd); - if (status != NDIS_STATUS_SUCCESS) - goto err_out_free_netdev; - - net_dev->ml_priv = (PVOID)pAd; - pAd->net_dev = net_dev; // must be before RT28XXNetDevInit() - - RT28XXNetDevInit(_dev_p, net_dev, pAd); - -#ifdef CONFIG_STA_SUPPORT - pAd->StaCfg.OriDevType = net_dev->type; -#endif // CONFIG_STA_SUPPORT // - - // Find and assign a free interface name, raxx -// RT28XXAvailRANameAssign(net_dev->name); - - // Post config -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - if (RT28XXProbePostConfig(_dev_p, pAd, argc) == FALSE) - goto err_out_unmap; -#else - if (RT28XXProbePostConfig(_dev_p, pAd, 0) == FALSE) - goto err_out_unmap; -#endif // LINUX_VERSION_CODE // - -#ifdef CONFIG_STA_SUPPORT - pAd->OpMode = OPMODE_STA; -#endif // CONFIG_STA_SUPPORT // - - -#ifdef MULTIPLE_CARD_SUPPORT - // find its profile path - pAd->MC_RowID = -1; // use default profile path - RTMP_CardInfoRead(pAd); - - if (pAd->MC_RowID == -1) -#ifdef CONFIG_STA_SUPPORT - strcpy(pAd->MC_FileName, STA_PROFILE_PATH); -#endif // CONFIG_STA_SUPPORT // - - DBGPRINT(RT_DEBUG_TRACE, - ("MC> ROW = %d, PATH = %s\n", pAd->MC_RowID, pAd->MC_FileName)); -#endif // MULTIPLE_CARD_SUPPORT // - - // sample move - if (rt_ieee80211_if_setup(net_dev, pAd) != NDIS_STATUS_SUCCESS) - goto err_out_unmap; - - // Register this device - status = register_netdev(net_dev); - if (status) - goto err_out_unmap; - - // Set driver data - RT28XX_DRVDATA_SET(_dev_p); - - - - *ppAd = pAd; - return 0; // probe ok - - - /* --------------------------- ERROR HANDLE --------------------------- */ -err_out_unmap: - RTMPFreeAdapter(pAd); - RT28XX_UNMAP(); - -err_out_free_netdev: -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) - free_netdev(net_dev); -#else - kfree(net_dev); -#endif - -err_out: - RT28XX_PUT_DEVICE(dev_p); - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - return (LONG)NULL; -#else - return -ENODEV; /* probe fail */ -#endif // LINUX_VERSION_CODE // -} /* End of rt28xx_probe */ - - -/* -======================================================================== -Routine Description: - The entry point for Linux kernel sent packet to our driver. - -Arguments: - sk_buff *skb the pointer refer to a sk_buffer. - -Return Value: - 0 - -Note: - This function is the entry point of Tx Path for Os delivery packet to - our driver. You only can put OS-depened & STA/AP common handle procedures - in here. -======================================================================== -*/ -int rt28xx_packet_xmit(struct sk_buff *skb) -{ - struct net_device *net_dev = skb->dev; - PRTMP_ADAPTER pAd = net_dev->ml_priv; - int status = 0; - PNDIS_PACKET pPacket = (PNDIS_PACKET) skb; - - /* RT2870STA does this in RTMPSendPackets() */ -#ifdef RALINK_ATE - if (ATE_ON(pAd)) - { - RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_RESOURCES); - return 0; - } -#endif // RALINK_ATE // - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - // Drop send request since we are in monitor mode - if (MONITOR_ON(pAd)) - { - RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); - goto done; - } - } -#endif // CONFIG_STA_SUPPORT // - - // EapolStart size is 18 - if (skb->len < 14) - { - //printk("bad packet size: %d\n", pkt->len); - hex_dump("bad packet", skb->data, skb->len); - RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); - goto done; - } - -#if 0 -// if ((pkt->data[0] & 0x1) == 0) - { - //hex_dump(__func__, pkt->data, pkt->len); - printk("pPacket = %x\n", pPacket); - } -#endif - - RTMP_SET_PACKET_5VT(pPacket, 0); -// MiniportMMRequest(pAd, pkt->data, pkt->len); -#ifdef CONFIG_5VT_ENHANCE - if (*(int*)(skb->cb) == BRIDGE_TAG) { - RTMP_SET_PACKET_5VT(pPacket, 1); - } -#endif - - - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - - STASendPackets((NDIS_HANDLE)pAd, (PPNDIS_PACKET) &pPacket, 1); - } - -#endif // CONFIG_STA_SUPPORT // - - status = 0; -done: - - return status; -} - - -/* -======================================================================== -Routine Description: - Send a packet to WLAN. - -Arguments: - skb_p points to our adapter - dev_p which WLAN network interface - -Return Value: - 0: transmit successfully - otherwise: transmit fail - -Note: -======================================================================== -*/ -INT rt28xx_send_packets( - IN struct sk_buff *skb_p, - IN struct net_device *net_dev) -{ - RTMP_ADAPTER *pAd = net_dev->ml_priv; - - if (!(net_dev->flags & IFF_UP)) - { - RELEASE_NDIS_PACKET(pAd, (PNDIS_PACKET)skb_p, NDIS_STATUS_FAILURE); - return 0; - } - - NdisZeroMemory((PUCHAR)&skb_p->cb[CB_OFF], 15); - RTMP_SET_PACKET_NET_DEVICE_MBSSID(skb_p, MAIN_MBSSID); - - return rt28xx_packet_xmit(skb_p); -} /* End of MBSS_VirtualIF_PacketSend */ - - - - -#if LINUX_VERSION_CODE <= 0x20402 // Red Hat 7.1 -//static struct net_device *alloc_netdev(int sizeof_priv, const char *mask, void (*setup)(struct net_device *)) //sample -struct net_device *alloc_netdev( - int sizeof_priv, - const char *mask, - void (*setup)(struct net_device *)) -{ - struct net_device *dev; - INT alloc_size; - - - /* ensure 32-byte alignment of the private area */ - alloc_size = sizeof (*dev) + sizeof_priv + 31; - - dev = (struct net_device *) kmalloc(alloc_size, GFP_KERNEL); - if (dev == NULL) - { - DBGPRINT(RT_DEBUG_ERROR, - ("alloc_netdev: Unable to allocate device memory.\n")); - return NULL; - } - - memset(dev, 0, alloc_size); - - if (sizeof_priv) - dev->priv = (void *) (((long)(dev + 1) + 31) & ~31); - - setup(dev); - strcpy(dev->name, mask); - - return dev; -} -#endif // LINUX_VERSION_CODE // - - -void CfgInitHook(PRTMP_ADAPTER pAd) -{ - pAd->bBroadComHT = TRUE; -} /* End of CfgInitHook */ - - -#if 0 // Not used now, should keep it in our source tree?? -/* -======================================================================== -Routine Description: - Find and assign a free interface name (raxx). - -Arguments: - *name_p the interface name pointer - -Return Value: - TRUE OK - FALSE FAIL - -Note: -======================================================================== -*/ -static BOOLEAN RT28XXAvailRANameAssign( - IN CHAR *name_p) -{ - CHAR slot_name[IFNAMSIZ]; - struct net_device *device; - UINT32 if_id; - - - for(if_id=0; if_id<8; if_id++) - { - sprintf(slot_name, "ra%d", if_id); - - for(device=dev_base; device!=NULL; device=device->next) - { - if (strncmp(device->name, slot_name, 4) == 0) - break; - } - - if (device == NULL) - break; - } - - if (if_id == 8) - { - DBGPRINT(RT_DEBUG_ERROR, ("No available slot name\n")); - return FALSE; - } - - sprintf(name_p, "ra%d", if_id); - return TRUE; -} /* End of RT28XXAvailRANameAssign */ -#endif - -#if WIRELESS_EXT >= 12 -// This function will be called when query /proc -struct iw_statistics *rt28xx_get_wireless_stats( - IN struct net_device *net_dev) -{ - PRTMP_ADAPTER pAd = net_dev->ml_priv; - - - DBGPRINT(RT_DEBUG_TRACE, ("rt28xx_get_wireless_stats --->\n")); - - pAd->iw_stats.status = 0; // Status - device dependent for now - - // link quality - pAd->iw_stats.qual.qual = ((pAd->Mlme.ChannelQuality * 12)/10 + 10); - if(pAd->iw_stats.qual.qual > 100) - pAd->iw_stats.qual.qual = 100; - -#ifdef CONFIG_STA_SUPPORT - if (pAd->OpMode == OPMODE_STA) - pAd->iw_stats.qual.level = RTMPMaxRssi(pAd, pAd->StaCfg.RssiSample.LastRssi0, pAd->StaCfg.RssiSample.LastRssi1, pAd->StaCfg.RssiSample.LastRssi2); -#endif // CONFIG_STA_SUPPORT // - - pAd->iw_stats.qual.noise = pAd->BbpWriteLatch[66]; // noise level (dBm) - - pAd->iw_stats.qual.noise += 256 - 143; - pAd->iw_stats.qual.updated = 1; // Flags to know if updated -#ifdef IW_QUAL_DBM - pAd->iw_stats.qual.updated |= IW_QUAL_DBM; // Level + Noise are dBm -#endif // IW_QUAL_DBM // - - pAd->iw_stats.discard.nwid = 0; // Rx : Wrong nwid/essid - pAd->iw_stats.miss.beacon = 0; // Missed beacons/superframe - - DBGPRINT(RT_DEBUG_TRACE, ("<--- rt28xx_get_wireless_stats\n")); - return &pAd->iw_stats; -} /* End of rt28xx_get_wireless_stats */ -#endif // WIRELESS_EXT // - - - -void tbtt_tasklet(unsigned long data) -{ -#define MAX_TX_IN_TBTT (16) - -} - -INT rt28xx_ioctl( - IN struct net_device *net_dev, - IN OUT struct ifreq *rq, - IN INT cmd) -{ - VIRTUAL_ADAPTER *pVirtualAd = NULL; - RTMP_ADAPTER *pAd = NULL; - INT ret = 0; - - if (net_dev->priv_flags == INT_MAIN) - { - pAd = net_dev->ml_priv; - } - else - { - pVirtualAd = net_dev->ml_priv; - pAd = pVirtualAd->RtmpDev->ml_priv; - } - - if (pAd == NULL) - { - /* if 1st open fail, pAd will be free; - So the net_dev->ml_priv will be NULL in 2rd open */ - return -ENETDOWN; - } - - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - ret = rt28xx_sta_ioctl(net_dev, rq, cmd); - } -#endif // CONFIG_STA_SUPPORT // - - return ret; -} - -/* - ======================================================================== - - Routine Description: - return ethernet statistics counter - - Arguments: - net_dev Pointer to net_device - - Return Value: - net_device_stats* - - Note: - - ======================================================================== -*/ -struct net_device_stats *RT28xx_get_ether_stats( - IN struct net_device *net_dev) -{ - RTMP_ADAPTER *pAd = NULL; - - if (net_dev) - pAd = net_dev->ml_priv; - - if (pAd) - { - - pAd->stats.rx_packets = pAd->WlanCounters.ReceivedFragmentCount.QuadPart; - pAd->stats.tx_packets = pAd->WlanCounters.TransmittedFragmentCount.QuadPart; - - pAd->stats.rx_bytes = pAd->RalinkCounters.ReceivedByteCount; - pAd->stats.tx_bytes = pAd->RalinkCounters.TransmittedByteCount; - - pAd->stats.rx_errors = pAd->Counters8023.RxErrors; - pAd->stats.tx_errors = pAd->Counters8023.TxErrors; - - pAd->stats.rx_dropped = 0; - pAd->stats.tx_dropped = 0; - - pAd->stats.multicast = pAd->WlanCounters.MulticastReceivedFrameCount.QuadPart; // multicast packets received - pAd->stats.collisions = pAd->Counters8023.OneCollision + pAd->Counters8023.MoreCollisions; // Collision packets - - pAd->stats.rx_length_errors = 0; - pAd->stats.rx_over_errors = pAd->Counters8023.RxNoBuffer; // receiver ring buff overflow - pAd->stats.rx_crc_errors = 0;//pAd->WlanCounters.FCSErrorCount; // recved pkt with crc error - pAd->stats.rx_frame_errors = pAd->Counters8023.RcvAlignmentErrors; // recv'd frame alignment error - pAd->stats.rx_fifo_errors = pAd->Counters8023.RxNoBuffer; // recv'r fifo overrun - pAd->stats.rx_missed_errors = 0; // receiver missed packet - - // detailed tx_errors - pAd->stats.tx_aborted_errors = 0; - pAd->stats.tx_carrier_errors = 0; - pAd->stats.tx_fifo_errors = 0; - pAd->stats.tx_heartbeat_errors = 0; - pAd->stats.tx_window_errors = 0; - - // for cslip etc - pAd->stats.rx_compressed = 0; - pAd->stats.tx_compressed = 0; - - return &pAd->stats; - } - else - return NULL; -} - +#include "../rt2860/rt_main_dev.c" diff --git a/drivers/staging/rt2870/rt_profile.c b/drivers/staging/rt2870/rt_profile.c index 467fea35e4a9..15988c5d9df7 100644 --- a/drivers/staging/rt2870/rt_profile.c +++ b/drivers/staging/rt2870/rt_profile.c @@ -1,2020 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * 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 "rt_config.h" - -#ifdef DOT11_N_SUPPORT -static void HTParametersHook( - IN PRTMP_ADAPTER pAd, - IN CHAR *pValueStr, - IN CHAR *pInput); -#endif // DOT11_N_SUPPORT // - -#define ETH_MAC_ADDR_STR_LEN 17 // in format of xx:xx:xx:xx:xx:xx - -// We assume the s1 is a sting, s2 is a memory space with 6 bytes. and content of s1 will be changed. -BOOLEAN rtstrmactohex(char *s1, char *s2) -{ - int i = 0; - char *ptokS = s1, *ptokE = s1; - - if (strlen(s1) != ETH_MAC_ADDR_STR_LEN) - return FALSE; - - while((*ptokS) != '\0') - { - if((ptokE = strchr(ptokS, ':')) != NULL) - *ptokE++ = '\0'; - if ((strlen(ptokS) != 2) || (!isxdigit(*ptokS)) || (!isxdigit(*(ptokS+1)))) - break; // fail - AtoH(ptokS, &s2[i++], 1); - ptokS = ptokE; - if (i == 6) - break; // parsing finished - } - - return ( i == 6 ? TRUE : FALSE); - -} - - -// we assume the s1 and s2 both are strings. -BOOLEAN rtstrcasecmp(char *s1, char *s2) -{ - char *p1 = s1, *p2 = s2; - - if (strlen(s1) != strlen(s2)) - return FALSE; - - while(*p1 != '\0') - { - if((*p1 != *p2) && ((*p1 ^ *p2) != 0x20)) - return FALSE; - p1++; - p2++; - } - - return TRUE; -} - -// we assume the s1 (buffer) and s2 (key) both are strings. -char * rtstrstruncasecmp(char * s1, char * s2) -{ - INT l1, l2, i; - char temp1, temp2; - - l2 = strlen(s2); - if (!l2) - return (char *) s1; - - l1 = strlen(s1); - - while (l1 >= l2) - { - l1--; - - for(i=0; i= l2) - { - l1--; - if (!memcmp(s1,s2,l2)) - return (char *) s1; - s1++; - } - - return NULL; -} - -/** - * rstrtok - Split a string into tokens - * @s: The string to be searched - * @ct: The characters to search for - * * WARNING: strtok is deprecated, use strsep instead. However strsep is not compatible with old architecture. - */ -char * __rstrtok; -char * rstrtok(char * s,const char * ct) -{ - char *sbegin, *send; - - sbegin = s ? s : __rstrtok; - if (!sbegin) - { - return NULL; - } - - sbegin += strspn(sbegin,ct); - if (*sbegin == '\0') - { - __rstrtok = NULL; - return( NULL ); - } - - send = strpbrk( sbegin, ct); - if (send && *send != '\0') - *send++ = '\0'; - - __rstrtok = send; - - return (sbegin); -} - -/** - * delimitcnt - return the count of a given delimiter in a given string. - * @s: The string to be searched. - * @ct: The delimiter to search for. - * Notice : We suppose the delimiter is a single-char string(for example : ";"). - */ -INT delimitcnt(char * s,const char * ct) -{ - INT count = 0; - /* point to the beginning of the line */ - const char *token = s; - - for ( ;; ) - { - token = strpbrk(token, ct); /* search for delimiters */ - - if ( token == NULL ) - { - /* advanced to the terminating null character */ - break; - } - /* skip the delimiter */ - ++token; - - /* - * Print the found text: use len with %.*s to specify field width. - */ - - /* accumulate delimiter count */ - ++count; - } - return count; -} - -/* - * converts the Internet host address from the standard numbers-and-dots notation - * into binary data. - * returns nonzero if the address is valid, zero if not. - */ -int rtinet_aton(const char *cp, unsigned int *addr) -{ - unsigned int val; - int base, n; - char c; - unsigned int parts[4]; - unsigned int *pp = parts; - - for (;;) - { - /* - * Collect number up to ``.''. - * Values are specified as for C: - * 0x=hex, 0=octal, other=decimal. - */ - val = 0; - base = 10; - if (*cp == '0') - { - if (*++cp == 'x' || *cp == 'X') - base = 16, cp++; - else - base = 8; - } - while ((c = *cp) != '\0') - { - if (isdigit((unsigned char) c)) - { - val = (val * base) + (c - '0'); - cp++; - continue; - } - if (base == 16 && isxdigit((unsigned char) c)) - { - val = (val << 4) + - (c + 10 - (islower((unsigned char) c) ? 'a' : 'A')); - cp++; - continue; - } - break; - } - if (*cp == '.') - { - /* - * Internet format: a.b.c.d a.b.c (with c treated as 16-bits) - * a.b (with b treated as 24 bits) - */ - if (pp >= parts + 3 || val > 0xff) - return 0; - *pp++ = val, cp++; - } - else - break; - } - - /* - * Check for trailing junk. - */ - while (*cp) - if (!isspace((unsigned char) *cp++)) - return 0; - - /* - * Concoct the address according to the number of parts specified. - */ - n = pp - parts + 1; - switch (n) - { - - case 1: /* a -- 32 bits */ - break; - - case 2: /* a.b -- 8.24 bits */ - if (val > 0xffffff) - return 0; - val |= parts[0] << 24; - break; - - case 3: /* a.b.c -- 8.8.16 bits */ - if (val > 0xffff) - return 0; - val |= (parts[0] << 24) | (parts[1] << 16); - break; - - case 4: /* a.b.c.d -- 8.8.8.8 bits */ - if (val > 0xff) - return 0; - val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); - break; - } - - *addr = htonl(val); - return 1; - -} - -/* - ======================================================================== - - Routine Description: - Find key section for Get key parameter. - - Arguments: - buffer Pointer to the buffer to start find the key section - section the key of the secion to be find - - Return Value: - NULL Fail - Others Success - ======================================================================== -*/ -PUCHAR RTMPFindSection( - IN PCHAR buffer) -{ - CHAR temp_buf[32]; - PUCHAR ptr; - - strcpy(temp_buf, "Default"); - - if((ptr = rtstrstr(buffer, temp_buf)) != NULL) - return (ptr+strlen("\n")); - else - return NULL; -} - -/* - ======================================================================== - - Routine Description: - Get key parameter. - - Arguments: - key Pointer to key string - dest Pointer to destination - destsize The datasize of the destination - buffer Pointer to the buffer to start find the key - - Return Value: - TRUE Success - FALSE Fail - - Note: - This routine get the value with the matched key (case case-sensitive) - ======================================================================== -*/ -INT RTMPGetKeyParameter( - IN PCHAR key, - OUT PCHAR dest, - IN INT destsize, - IN PCHAR buffer) -{ - UCHAR *temp_buf1 = NULL; - UCHAR *temp_buf2 = NULL; - CHAR *start_ptr; - CHAR *end_ptr; - CHAR *ptr; - CHAR *offset = 0; - INT len; - - //temp_buf1 = kmalloc(MAX_PARAM_BUFFER_SIZE, MEM_ALLOC_FLAG); - os_alloc_mem(NULL, &temp_buf1, MAX_PARAM_BUFFER_SIZE); - - if(temp_buf1 == NULL) - return (FALSE); - - //temp_buf2 = kmalloc(MAX_PARAM_BUFFER_SIZE, MEM_ALLOC_FLAG); - os_alloc_mem(NULL, &temp_buf2, MAX_PARAM_BUFFER_SIZE); - if(temp_buf2 == NULL) - { - os_free_mem(NULL, temp_buf1); - return (FALSE); - } - - //find section - if((offset = RTMPFindSection(buffer)) == NULL) - { - os_free_mem(NULL, temp_buf1); - os_free_mem(NULL, temp_buf2); - return (FALSE); - } - - strcpy(temp_buf1, "\n"); - strcat(temp_buf1, key); - strcat(temp_buf1, "="); - - //search key - if((start_ptr=rtstrstr(offset, temp_buf1))==NULL) - { - os_free_mem(NULL, temp_buf1); - os_free_mem(NULL, temp_buf2); - return (FALSE); - } - - start_ptr+=strlen("\n"); - if((end_ptr=rtstrstr(start_ptr, "\n"))==NULL) - end_ptr=start_ptr+strlen(start_ptr); - - if (end_ptrSharedKey[i][idx].KeyLen = KeyLen / 2; - AtoH(keybuff, pAd->SharedKey[i][idx].Key, KeyLen / 2); - if (KeyLen == 10) - CipherAlg = CIPHER_WEP64; - else - CipherAlg = CIPHER_WEP128; - pAd->SharedKey[i][idx].CipherAlg = CipherAlg; - - DBGPRINT(RT_DEBUG_TRACE, ("I/F(ra%d) Key%dStr=%s and type=%s\n", i, idx+1, keybuff, (KeyType == 0) ? "Hex":"Ascii")); - return 1; - } - else - {//Invalid key length - DBGPRINT(RT_DEBUG_ERROR, ("I/F(ra%d) Key%dStr is Invalid key length! KeyLen = %ld!\n", i, idx+1, KeyLen)); - return 0; - } - } -} -static void rtmp_read_key_parms_from_file(IN PRTMP_ADAPTER pAd, char *tmpbuf, char *buffer) -{ - char tok_str[16]; - PUCHAR macptr; - INT i = 0, idx; - ULONG KeyType[MAX_MBSSID_NUM]; - ULONG KeyIdx; - - NdisZeroMemory(KeyType, MAX_MBSSID_NUM); - - //DefaultKeyID - if(RTMPGetKeyParameter("DefaultKeyID", tmpbuf, 25, buffer)) - { - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - KeyIdx = simple_strtol(tmpbuf, 0, 10); - if((KeyIdx >= 1 ) && (KeyIdx <= 4)) - pAd->StaCfg.DefaultKeyId = (UCHAR) (KeyIdx - 1); - else - pAd->StaCfg.DefaultKeyId = 0; - - DBGPRINT(RT_DEBUG_TRACE, ("DefaultKeyID(0~3)=%d\n", pAd->StaCfg.DefaultKeyId)); - } -#endif // CONFIG_STA_SUPPORT // - } - - - for (idx = 0; idx < 4; idx++) - { - sprintf(tok_str, "Key%dType", idx + 1); - //Key1Type - if (RTMPGetKeyParameter(tok_str, tmpbuf, 128, buffer)) - { - for (i = 0, macptr = rstrtok(tmpbuf,";"); macptr; macptr = rstrtok(NULL,";"), i++) - { - KeyType[i] = simple_strtol(macptr, 0, 10); - } - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - sprintf(tok_str, "Key%dStr", idx + 1); - if (RTMPGetCriticalParameter(tok_str, tmpbuf, 128, buffer)) - { - rtmp_parse_key_buffer_from_file(pAd, tmpbuf, KeyType[BSS0], BSS0, idx); - } - } -#endif // CONFIG_STA_SUPPORT // - } - } -} - - -#ifdef CONFIG_STA_SUPPORT -static void rtmp_read_sta_wmm_parms_from_file(IN PRTMP_ADAPTER pAd, char *tmpbuf, char *buffer) -{ - PUCHAR macptr; - INT i=0; - BOOLEAN bWmmEnable = FALSE; - - //WmmCapable - if(RTMPGetKeyParameter("WmmCapable", tmpbuf, 32, buffer)) - { - if(simple_strtol(tmpbuf, 0, 10) != 0) //Enable - { - pAd->CommonCfg.bWmmCapable = TRUE; - bWmmEnable = TRUE; - } - else //Disable - { - pAd->CommonCfg.bWmmCapable = FALSE; - } - - DBGPRINT(RT_DEBUG_TRACE, ("WmmCapable=%d\n", pAd->CommonCfg.bWmmCapable)); - } - -#ifdef QOS_DLS_SUPPORT - //DLSCapable - if(RTMPGetKeyParameter("DLSCapable", tmpbuf, 32, buffer)) - { - if(simple_strtol(tmpbuf, 0, 10) != 0) //Enable - { - pAd->CommonCfg.bDLSCapable = TRUE; - } - else //Disable - { - pAd->CommonCfg.bDLSCapable = FALSE; - } - - DBGPRINT(RT_DEBUG_TRACE, ("bDLSCapable=%d\n", pAd->CommonCfg.bDLSCapable)); - } -#endif // QOS_DLS_SUPPORT // - - //AckPolicy for AC_BK, AC_BE, AC_VI, AC_VO - if(RTMPGetKeyParameter("AckPolicy", tmpbuf, 32, buffer)) - { - for (i = 0, macptr = rstrtok(tmpbuf,";"); macptr; macptr = rstrtok(NULL,";"), i++) - { - pAd->CommonCfg.AckPolicy[i] = (UCHAR)simple_strtol(macptr, 0, 10); - - DBGPRINT(RT_DEBUG_TRACE, ("AckPolicy[%d]=%d\n", i, pAd->CommonCfg.AckPolicy[i])); - } - } - - if (bWmmEnable) - { - //APSDCapable - if(RTMPGetKeyParameter("APSDCapable", tmpbuf, 10, buffer)) - { - if(simple_strtol(tmpbuf, 0, 10) != 0) //Enable - pAd->CommonCfg.bAPSDCapable = TRUE; - else - pAd->CommonCfg.bAPSDCapable = FALSE; - - DBGPRINT(RT_DEBUG_TRACE, ("APSDCapable=%d\n", pAd->CommonCfg.bAPSDCapable)); - } - - //APSDAC for AC_BE, AC_BK, AC_VI, AC_VO - if(RTMPGetKeyParameter("APSDAC", tmpbuf, 32, buffer)) - { - BOOLEAN apsd_ac[4]; - - for (i = 0, macptr = rstrtok(tmpbuf,";"); macptr; macptr = rstrtok(NULL,";"), i++) - { - apsd_ac[i] = (BOOLEAN)simple_strtol(macptr, 0, 10); - - DBGPRINT(RT_DEBUG_TRACE, ("APSDAC%d %d\n", i, apsd_ac[i])); - } - - pAd->CommonCfg.bAPSDAC_BE = apsd_ac[0]; - pAd->CommonCfg.bAPSDAC_BK = apsd_ac[1]; - pAd->CommonCfg.bAPSDAC_VI = apsd_ac[2]; - pAd->CommonCfg.bAPSDAC_VO = apsd_ac[3]; - } - } - -} -#endif // CONFIG_STA_SUPPORT // - - -NDIS_STATUS RTMPReadParametersHook( - IN PRTMP_ADAPTER pAd) -{ - PUCHAR src = NULL; - struct file *srcf; - INT retval, orgfsuid, orgfsgid; - mm_segment_t orgfs; - CHAR *buffer; - CHAR *tmpbuf; - ULONG RtsThresh; - ULONG FragThresh; -#ifdef CONFIG_STA_SUPPORT - UCHAR keyMaterial[40]; -#endif // CONFIG_STA_SUPPORT // - - - PUCHAR macptr; - INT i = 0; - - buffer = kmalloc(MAX_INI_BUFFER_SIZE, MEM_ALLOC_FLAG); - if(buffer == NULL) - return NDIS_STATUS_FAILURE; - - tmpbuf = kmalloc(MAX_PARAM_BUFFER_SIZE, MEM_ALLOC_FLAG); - if(tmpbuf == NULL) - { - kfree(buffer); - return NDIS_STATUS_FAILURE; - } - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - src = STA_PROFILE_PATH; -#endif // CONFIG_STA_SUPPORT // -#ifdef MULTIPLE_CARD_SUPPORT - src = pAd->MC_FileName; -#endif // MULTIPLE_CARD_SUPPORT // - - // Save uid and gid used for filesystem access. - // Set user and group to 0 (root) - orgfsuid = current_fsuid(); - orgfsgid = current_fsgid(); - /* Hm, can't really do this nicely anymore, so rely on these files - * being set to the proper permission to read them... */ - /* current->cred->fsuid = current->cred->fsgid = 0; */ - orgfs = get_fs(); - set_fs(KERNEL_DS); - - if (src && *src) - { - srcf = filp_open(src, O_RDONLY, 0); - if (IS_ERR(srcf)) - { - DBGPRINT(RT_DEBUG_ERROR, ("--> Error %ld opening %s\n", -PTR_ERR(srcf),src)); - } - else - { - // The object must have a read method - if (srcf->f_op && srcf->f_op->read) - { - memset(buffer, 0x00, MAX_INI_BUFFER_SIZE); - retval=srcf->f_op->read(srcf, buffer, MAX_INI_BUFFER_SIZE, &srcf->f_pos); - if (retval < 0) - { - DBGPRINT(RT_DEBUG_TRACE, ("--> Read %s error %d\n", src, -retval)); - } - else - { - // set file parameter to portcfg - //CountryRegion - if(RTMPGetKeyParameter("CountryRegion", tmpbuf, 25, buffer)) - { - pAd->CommonCfg.CountryRegion = (UCHAR) simple_strtol(tmpbuf, 0, 10); - DBGPRINT(RT_DEBUG_TRACE, ("CountryRegion=%d\n", pAd->CommonCfg.CountryRegion)); - } - //CountryRegionABand - if(RTMPGetKeyParameter("CountryRegionABand", tmpbuf, 25, buffer)) - { - pAd->CommonCfg.CountryRegionForABand= (UCHAR) simple_strtol(tmpbuf, 0, 10); - DBGPRINT(RT_DEBUG_TRACE, ("CountryRegionABand=%d\n", pAd->CommonCfg.CountryRegionForABand)); - } - //CountryCode - if(RTMPGetKeyParameter("CountryCode", tmpbuf, 25, buffer)) - { - NdisMoveMemory(pAd->CommonCfg.CountryCode, tmpbuf , 2); -#ifdef CONFIG_STA_SUPPORT -#ifdef EXT_BUILD_CHANNEL_LIST - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - NdisMoveMemory(pAd->StaCfg.StaOriCountryCode, tmpbuf , 2); -#endif // EXT_BUILD_CHANNEL_LIST // -#endif // CONFIG_STA_SUPPORT // - if (strlen(pAd->CommonCfg.CountryCode) != 0) - { - pAd->CommonCfg.bCountryFlag = TRUE; - } - DBGPRINT(RT_DEBUG_TRACE, ("CountryCode=%s\n", pAd->CommonCfg.CountryCode)); - } - //ChannelGeography - if(RTMPGetKeyParameter("ChannelGeography", tmpbuf, 25, buffer)) - { - UCHAR Geography = (UCHAR) simple_strtol(tmpbuf, 0, 10); - if (Geography <= BOTH) - { - pAd->CommonCfg.Geography = Geography; - pAd->CommonCfg.CountryCode[2] = - (pAd->CommonCfg.Geography == BOTH) ? ' ' : ((pAd->CommonCfg.Geography == IDOR) ? 'I' : 'O'); -#ifdef CONFIG_STA_SUPPORT -#ifdef EXT_BUILD_CHANNEL_LIST - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - pAd->StaCfg.StaOriGeography = pAd->CommonCfg.Geography; -#endif // EXT_BUILD_CHANNEL_LIST // -#endif // CONFIG_STA_SUPPORT // - DBGPRINT(RT_DEBUG_TRACE, ("ChannelGeography=%d\n", pAd->CommonCfg.Geography)); - } - } - else - { - pAd->CommonCfg.Geography = BOTH; - pAd->CommonCfg.CountryCode[2] = ' '; - } - - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - //SSID - if (RTMPGetCriticalParameter("SSID", tmpbuf, 256, buffer)) - { - if (strlen(tmpbuf) <= 32) - { - pAd->CommonCfg.SsidLen = (UCHAR) strlen(tmpbuf); - NdisZeroMemory(pAd->CommonCfg.Ssid, NDIS_802_11_LENGTH_SSID); - NdisMoveMemory(pAd->CommonCfg.Ssid, tmpbuf, pAd->CommonCfg.SsidLen); - pAd->MlmeAux.AutoReconnectSsidLen = pAd->CommonCfg.SsidLen; - NdisZeroMemory(pAd->MlmeAux.AutoReconnectSsid, NDIS_802_11_LENGTH_SSID); - NdisMoveMemory(pAd->MlmeAux.AutoReconnectSsid, tmpbuf, pAd->MlmeAux.AutoReconnectSsidLen); - pAd->MlmeAux.SsidLen = pAd->CommonCfg.SsidLen; - NdisZeroMemory(pAd->MlmeAux.Ssid, NDIS_802_11_LENGTH_SSID); - NdisMoveMemory(pAd->MlmeAux.Ssid, tmpbuf, pAd->MlmeAux.SsidLen); - DBGPRINT(RT_DEBUG_TRACE, ("%s::(SSID=%s)\n", __func__, tmpbuf)); - } - } - } -#endif // CONFIG_STA_SUPPORT // - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - //NetworkType - if (RTMPGetKeyParameter("NetworkType", tmpbuf, 25, buffer)) - { - pAd->bConfigChanged = TRUE; - if (strcmp(tmpbuf, "Adhoc") == 0) - pAd->StaCfg.BssType = BSS_ADHOC; - else //Default Infrastructure mode - pAd->StaCfg.BssType = BSS_INFRA; - // Reset Ralink supplicant to not use, it will be set to start when UI set PMK key - pAd->StaCfg.WpaState = SS_NOTUSE; - DBGPRINT(RT_DEBUG_TRACE, ("%s::(NetworkType=%d)\n", __func__, pAd->StaCfg.BssType)); - } - } -#endif // CONFIG_STA_SUPPORT // - //Channel - if(RTMPGetKeyParameter("Channel", tmpbuf, 10, buffer)) - { - pAd->CommonCfg.Channel = (UCHAR) simple_strtol(tmpbuf, 0, 10); - DBGPRINT(RT_DEBUG_TRACE, ("Channel=%d\n", pAd->CommonCfg.Channel)); - } - //WirelessMode - if(RTMPGetKeyParameter("WirelessMode", tmpbuf, 10, buffer)) - { - int value = 0, maxPhyMode = PHY_11G; - -#ifdef DOT11_N_SUPPORT - maxPhyMode = PHY_11N_5G; -#endif // DOT11_N_SUPPORT // - - value = simple_strtol(tmpbuf, 0, 10); - - if (value <= maxPhyMode) - { - pAd->CommonCfg.PhyMode = value; - } - DBGPRINT(RT_DEBUG_TRACE, ("PhyMode=%d\n", pAd->CommonCfg.PhyMode)); - } - //BasicRate - if(RTMPGetKeyParameter("BasicRate", tmpbuf, 10, buffer)) - { - pAd->CommonCfg.BasicRateBitmap = (ULONG) simple_strtol(tmpbuf, 0, 10); - DBGPRINT(RT_DEBUG_TRACE, ("BasicRate=%ld\n", pAd->CommonCfg.BasicRateBitmap)); - } - //BeaconPeriod - if(RTMPGetKeyParameter("BeaconPeriod", tmpbuf, 10, buffer)) - { - pAd->CommonCfg.BeaconPeriod = (USHORT) simple_strtol(tmpbuf, 0, 10); - DBGPRINT(RT_DEBUG_TRACE, ("BeaconPeriod=%d\n", pAd->CommonCfg.BeaconPeriod)); - } - //TxPower - if(RTMPGetKeyParameter("TxPower", tmpbuf, 10, buffer)) - { - pAd->CommonCfg.TxPowerPercentage = (ULONG) simple_strtol(tmpbuf, 0, 10); -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - pAd->CommonCfg.TxPowerDefault = pAd->CommonCfg.TxPowerPercentage; -#endif // CONFIG_STA_SUPPORT // - DBGPRINT(RT_DEBUG_TRACE, ("TxPower=%ld\n", pAd->CommonCfg.TxPowerPercentage)); - } - //BGProtection - if(RTMPGetKeyParameter("BGProtection", tmpbuf, 10, buffer)) - { - switch (simple_strtol(tmpbuf, 0, 10)) - { - case 1: //Always On - pAd->CommonCfg.UseBGProtection = 1; - break; - case 2: //Always OFF - pAd->CommonCfg.UseBGProtection = 2; - break; - case 0: //AUTO - default: - pAd->CommonCfg.UseBGProtection = 0; - break; - } - DBGPRINT(RT_DEBUG_TRACE, ("BGProtection=%ld\n", pAd->CommonCfg.UseBGProtection)); - } - //OLBCDetection - if(RTMPGetKeyParameter("DisableOLBC", tmpbuf, 10, buffer)) - { - switch (simple_strtol(tmpbuf, 0, 10)) - { - case 1: //disable OLBC Detection - pAd->CommonCfg.DisableOLBCDetect = 1; - break; - case 0: //enable OLBC Detection - pAd->CommonCfg.DisableOLBCDetect = 0; - break; - default: - pAd->CommonCfg.DisableOLBCDetect= 0; - break; - } - DBGPRINT(RT_DEBUG_TRACE, ("OLBCDetection=%ld\n", pAd->CommonCfg.DisableOLBCDetect)); - } - //TxPreamble - if(RTMPGetKeyParameter("TxPreamble", tmpbuf, 10, buffer)) - { - switch (simple_strtol(tmpbuf, 0, 10)) - { - case Rt802_11PreambleShort: - pAd->CommonCfg.TxPreamble = Rt802_11PreambleShort; - break; - case Rt802_11PreambleLong: - default: - pAd->CommonCfg.TxPreamble = Rt802_11PreambleLong; - break; - } - DBGPRINT(RT_DEBUG_TRACE, ("TxPreamble=%ld\n", pAd->CommonCfg.TxPreamble)); - } - //RTSThreshold - if(RTMPGetKeyParameter("RTSThreshold", tmpbuf, 10, buffer)) - { - RtsThresh = simple_strtol(tmpbuf, 0, 10); - if( (RtsThresh >= 1) && (RtsThresh <= MAX_RTS_THRESHOLD) ) - pAd->CommonCfg.RtsThreshold = (USHORT)RtsThresh; - else - pAd->CommonCfg.RtsThreshold = MAX_RTS_THRESHOLD; - - DBGPRINT(RT_DEBUG_TRACE, ("RTSThreshold=%d\n", pAd->CommonCfg.RtsThreshold)); - } - //FragThreshold - if(RTMPGetKeyParameter("FragThreshold", tmpbuf, 10, buffer)) - { - FragThresh = simple_strtol(tmpbuf, 0, 10); - pAd->CommonCfg.bUseZeroToDisableFragment = FALSE; - - if (FragThresh > MAX_FRAG_THRESHOLD || FragThresh < MIN_FRAG_THRESHOLD) - { //illegal FragThresh so we set it to default - pAd->CommonCfg.FragmentThreshold = MAX_FRAG_THRESHOLD; - pAd->CommonCfg.bUseZeroToDisableFragment = TRUE; - } - else if (FragThresh % 2 == 1) - { - // The length of each fragment shall always be an even number of octets, except for the last fragment - // of an MSDU or MMPDU, which may be either an even or an odd number of octets. - pAd->CommonCfg.FragmentThreshold = (USHORT)(FragThresh - 1); - } - else - { - pAd->CommonCfg.FragmentThreshold = (USHORT)FragThresh; - } - //pAd->CommonCfg.AllowFragSize = (pAd->CommonCfg.FragmentThreshold) - LENGTH_802_11 - LENGTH_CRC; - DBGPRINT(RT_DEBUG_TRACE, ("FragThreshold=%d\n", pAd->CommonCfg.FragmentThreshold)); - } - //TxBurst - if(RTMPGetKeyParameter("TxBurst", tmpbuf, 10, buffer)) - { -//#ifdef WIFI_TEST -// pAd->CommonCfg.bEnableTxBurst = FALSE; -//#else - if(simple_strtol(tmpbuf, 0, 10) != 0) //Enable - pAd->CommonCfg.bEnableTxBurst = TRUE; - else //Disable - pAd->CommonCfg.bEnableTxBurst = FALSE; -//#endif - DBGPRINT(RT_DEBUG_TRACE, ("TxBurst=%d\n", pAd->CommonCfg.bEnableTxBurst)); - } - -#ifdef AGGREGATION_SUPPORT - //PktAggregate - if(RTMPGetKeyParameter("PktAggregate", tmpbuf, 10, buffer)) - { - if(simple_strtol(tmpbuf, 0, 10) != 0) //Enable - pAd->CommonCfg.bAggregationCapable = TRUE; - else //Disable - pAd->CommonCfg.bAggregationCapable = FALSE; -#ifdef PIGGYBACK_SUPPORT - pAd->CommonCfg.bPiggyBackCapable = pAd->CommonCfg.bAggregationCapable; -#endif // PIGGYBACK_SUPPORT // - DBGPRINT(RT_DEBUG_TRACE, ("PktAggregate=%d\n", pAd->CommonCfg.bAggregationCapable)); - } -#else - pAd->CommonCfg.bAggregationCapable = FALSE; - pAd->CommonCfg.bPiggyBackCapable = FALSE; -#endif // AGGREGATION_SUPPORT // - - // WmmCapable - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - rtmp_read_sta_wmm_parms_from_file(pAd, tmpbuf, buffer); -#endif // CONFIG_STA_SUPPORT // - - //ShortSlot - if(RTMPGetKeyParameter("ShortSlot", tmpbuf, 10, buffer)) - { - if(simple_strtol(tmpbuf, 0, 10) != 0) //Enable - pAd->CommonCfg.bUseShortSlotTime = TRUE; - else //Disable - pAd->CommonCfg.bUseShortSlotTime = FALSE; - - DBGPRINT(RT_DEBUG_TRACE, ("ShortSlot=%d\n", pAd->CommonCfg.bUseShortSlotTime)); - } - //IEEE80211H - if(RTMPGetKeyParameter("IEEE80211H", tmpbuf, 10, buffer)) - { - for (i = 0, macptr = rstrtok(tmpbuf,";"); macptr; macptr = rstrtok(NULL,";"), i++) - { - if(simple_strtol(macptr, 0, 10) != 0) //Enable - pAd->CommonCfg.bIEEE80211H = TRUE; - else //Disable - pAd->CommonCfg.bIEEE80211H = FALSE; - - DBGPRINT(RT_DEBUG_TRACE, ("IEEE80211H=%d\n", pAd->CommonCfg.bIEEE80211H)); - } - } - //CSPeriod - if(RTMPGetKeyParameter("CSPeriod", tmpbuf, 10, buffer)) - { - if(simple_strtol(tmpbuf, 0, 10) != 0) - pAd->CommonCfg.RadarDetect.CSPeriod = simple_strtol(tmpbuf, 0, 10); - else - pAd->CommonCfg.RadarDetect.CSPeriod = 0; - - DBGPRINT(RT_DEBUG_TRACE, ("CSPeriod=%d\n", pAd->CommonCfg.RadarDetect.CSPeriod)); - } - - //RDRegion - if(RTMPGetKeyParameter("RDRegion", tmpbuf, 128, buffer)) - { - if ((strncmp(tmpbuf, "JAP_W53", 7) == 0) || (strncmp(tmpbuf, "jap_w53", 7) == 0)) - { - pAd->CommonCfg.RadarDetect.RDDurRegion = JAP_W53; - pAd->CommonCfg.RadarDetect.DfsSessionTime = 15; - } - else if ((strncmp(tmpbuf, "JAP_W56", 7) == 0) || (strncmp(tmpbuf, "jap_w56", 7) == 0)) - { - pAd->CommonCfg.RadarDetect.RDDurRegion = JAP_W56; - pAd->CommonCfg.RadarDetect.DfsSessionTime = 13; - } - else if ((strncmp(tmpbuf, "JAP", 3) == 0) || (strncmp(tmpbuf, "jap", 3) == 0)) - { - pAd->CommonCfg.RadarDetect.RDDurRegion = JAP; - pAd->CommonCfg.RadarDetect.DfsSessionTime = 5; - } - else if ((strncmp(tmpbuf, "FCC", 3) == 0) || (strncmp(tmpbuf, "fcc", 3) == 0)) - { - pAd->CommonCfg.RadarDetect.RDDurRegion = FCC; - pAd->CommonCfg.RadarDetect.DfsSessionTime = 5; - } - else if ((strncmp(tmpbuf, "CE", 2) == 0) || (strncmp(tmpbuf, "ce", 2) == 0)) - { - pAd->CommonCfg.RadarDetect.RDDurRegion = CE; - pAd->CommonCfg.RadarDetect.DfsSessionTime = 13; - } - else - { - pAd->CommonCfg.RadarDetect.RDDurRegion = CE; - pAd->CommonCfg.RadarDetect.DfsSessionTime = 13; - } - - DBGPRINT(RT_DEBUG_TRACE, ("RDRegion=%d\n", pAd->CommonCfg.RadarDetect.RDDurRegion)); - } - else - { - pAd->CommonCfg.RadarDetect.RDDurRegion = CE; - pAd->CommonCfg.RadarDetect.DfsSessionTime = 13; - } - - //WirelessEvent - if(RTMPGetKeyParameter("WirelessEvent", tmpbuf, 10, buffer)) - { -#if WIRELESS_EXT >= 15 - if(simple_strtol(tmpbuf, 0, 10) != 0) - pAd->CommonCfg.bWirelessEvent = simple_strtol(tmpbuf, 0, 10); - else - pAd->CommonCfg.bWirelessEvent = 0; // disable -#else - pAd->CommonCfg.bWirelessEvent = 0; // disable -#endif - DBGPRINT(RT_DEBUG_TRACE, ("WirelessEvent=%d\n", pAd->CommonCfg.bWirelessEvent)); - } - if(RTMPGetKeyParameter("WiFiTest", tmpbuf, 10, buffer)) - { - if(simple_strtol(tmpbuf, 0, 10) != 0) - pAd->CommonCfg.bWiFiTest= simple_strtol(tmpbuf, 0, 10); - else - pAd->CommonCfg.bWiFiTest = 0; // disable - - DBGPRINT(RT_DEBUG_TRACE, ("WiFiTest=%d\n", pAd->CommonCfg.bWiFiTest)); - } - //AuthMode - if(RTMPGetKeyParameter("AuthMode", tmpbuf, 128, buffer)) - { -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - if ((strcmp(tmpbuf, "WEPAUTO") == 0) || (strcmp(tmpbuf, "wepauto") == 0)) - pAd->StaCfg.AuthMode = Ndis802_11AuthModeAutoSwitch; - else if ((strcmp(tmpbuf, "SHARED") == 0) || (strcmp(tmpbuf, "shared") == 0)) - pAd->StaCfg.AuthMode = Ndis802_11AuthModeShared; - else if ((strcmp(tmpbuf, "WPAPSK") == 0) || (strcmp(tmpbuf, "wpapsk") == 0)) - pAd->StaCfg.AuthMode = Ndis802_11AuthModeWPAPSK; - else if ((strcmp(tmpbuf, "WPANONE") == 0) || (strcmp(tmpbuf, "wpanone") == 0)) - pAd->StaCfg.AuthMode = Ndis802_11AuthModeWPANone; - else if ((strcmp(tmpbuf, "WPA2PSK") == 0) || (strcmp(tmpbuf, "wpa2psk") == 0)) - pAd->StaCfg.AuthMode = Ndis802_11AuthModeWPA2PSK; -#ifdef WPA_SUPPLICANT_SUPPORT - else if ((strcmp(tmpbuf, "WPA") == 0) || (strcmp(tmpbuf, "wpa") == 0)) - pAd->StaCfg.AuthMode = Ndis802_11AuthModeWPA; - else if ((strcmp(tmpbuf, "WPA2") == 0) || (strcmp(tmpbuf, "wpa2") == 0)) - pAd->StaCfg.AuthMode = Ndis802_11AuthModeWPA2; -#endif // WPA_SUPPLICANT_SUPPORT // - else - pAd->StaCfg.AuthMode = Ndis802_11AuthModeOpen; - - pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; - - DBGPRINT(RT_DEBUG_TRACE, ("%s::(EncrypType=%d)\n", __func__, pAd->StaCfg.WepStatus)); - } -#endif // CONFIG_STA_SUPPORT // - } - //EncrypType - if(RTMPGetKeyParameter("EncrypType", tmpbuf, 128, buffer)) - { - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - if ((strcmp(tmpbuf, "WEP") == 0) || (strcmp(tmpbuf, "wep") == 0)) - pAd->StaCfg.WepStatus = Ndis802_11WEPEnabled; - else if ((strcmp(tmpbuf, "TKIP") == 0) || (strcmp(tmpbuf, "tkip") == 0)) - pAd->StaCfg.WepStatus = Ndis802_11Encryption2Enabled; - else if ((strcmp(tmpbuf, "AES") == 0) || (strcmp(tmpbuf, "aes") == 0)) - pAd->StaCfg.WepStatus = Ndis802_11Encryption3Enabled; - else - pAd->StaCfg.WepStatus = Ndis802_11WEPDisabled; - - // Update all wepstatus related - pAd->StaCfg.PairCipher = pAd->StaCfg.WepStatus; - pAd->StaCfg.GroupCipher = pAd->StaCfg.WepStatus; - pAd->StaCfg.OrigWepStatus = pAd->StaCfg.WepStatus; - pAd->StaCfg.bMixCipher = FALSE; - - //RTMPMakeRSNIE(pAd, pAd->StaCfg.AuthMode, pAd->StaCfg.WepStatus, 0); - DBGPRINT(RT_DEBUG_TRACE, ("%s::(EncrypType=%d)\n", __func__, pAd->StaCfg.WepStatus)); - } -#endif // CONFIG_STA_SUPPORT // - } - - - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - if(RTMPGetCriticalParameter("WPAPSK", tmpbuf, 512, buffer)) - { - int err=0; - - tmpbuf[strlen(tmpbuf)] = '\0'; // make STA can process .$^& for WPAPSK input - - if ((pAd->StaCfg.AuthMode != Ndis802_11AuthModeWPAPSK) && - (pAd->StaCfg.AuthMode != Ndis802_11AuthModeWPA2PSK) && - (pAd->StaCfg.AuthMode != Ndis802_11AuthModeWPANone) - ) - { - err = 1; - } - else if ((strlen(tmpbuf) >= 8) && (strlen(tmpbuf) < 64)) - { - PasswordHash((char *)tmpbuf, pAd->CommonCfg.Ssid, pAd->CommonCfg.SsidLen, keyMaterial); - NdisMoveMemory(pAd->StaCfg.PMK, keyMaterial, 32); - - } - else if (strlen(tmpbuf) == 64) - { - AtoH(tmpbuf, keyMaterial, 32); - NdisMoveMemory(pAd->StaCfg.PMK, keyMaterial, 32); - } - else - { - err = 1; - DBGPRINT(RT_DEBUG_ERROR, ("%s::(WPAPSK key-string required 8 ~ 64 characters!)\n", __func__)); - } - - if (err == 0) - { - if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) || - (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)) - { - // Start STA supplicant state machine - pAd->StaCfg.WpaState = SS_START; - } - else if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) - { - /* - NdisZeroMemory(&pAd->SharedKey[BSS0][0], sizeof(CIPHER_KEY)); - pAd->SharedKey[BSS0][0].KeyLen = LEN_TKIP_EK; - NdisMoveMemory(pAd->SharedKey[BSS0][0].Key, pAd->StaCfg.PMK, LEN_TKIP_EK); - NdisMoveMemory(pAd->SharedKey[BSS0][0].RxMic, &pAd->StaCfg.PMK[16], LEN_TKIP_RXMICK); - NdisMoveMemory(pAd->SharedKey[BSS0][0].TxMic, &pAd->StaCfg.PMK[16], LEN_TKIP_TXMICK); - - // Decide its ChiperAlg - if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled) - pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_TKIP; - else if (pAd->StaCfg.PairCipher == Ndis802_11Encryption3Enabled) - pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_AES; - else - pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_NONE; - */ - pAd->StaCfg.WpaState = SS_NOTUSE; - } - - DBGPRINT(RT_DEBUG_TRACE, ("%s::(WPAPSK=%s)\n", __func__, tmpbuf)); - } - } - } -#endif // CONFIG_STA_SUPPORT // - - //DefaultKeyID, KeyType, KeyStr - rtmp_read_key_parms_from_file(pAd, tmpbuf, buffer); - - - //HSCounter - /*if(RTMPGetKeyParameter("HSCounter", tmpbuf, 10, buffer)) - { - switch (simple_strtol(tmpbuf, 0, 10)) - { - case 1: //Enable - pAd->CommonCfg.bEnableHSCounter = TRUE; - break; - case 0: //Disable - default: - pAd->CommonCfg.bEnableHSCounter = FALSE; - break; - } - DBGPRINT(RT_DEBUG_TRACE, "HSCounter=%d\n", pAd->CommonCfg.bEnableHSCounter); - }*/ - -#ifdef DOT11_N_SUPPORT - HTParametersHook(pAd, tmpbuf, buffer); -#endif // DOT11_N_SUPPORT // - - -#ifdef CARRIER_DETECTION_SUPPORT - //CarrierDetect - if(RTMPGetKeyParameter("CarrierDetect", tmpbuf, 128, buffer)) - { - if ((strncmp(tmpbuf, "0", 1) == 0)) - pAd->CommonCfg.CarrierDetect.Enable = FALSE; - else if ((strncmp(tmpbuf, "1", 1) == 0)) - pAd->CommonCfg.CarrierDetect.Enable = TRUE; - else - pAd->CommonCfg.CarrierDetect.Enable = FALSE; - - DBGPRINT(RT_DEBUG_TRACE, ("CarrierDetect.Enable=%d\n", pAd->CommonCfg.CarrierDetect.Enable)); - } - else - pAd->CommonCfg.CarrierDetect.Enable = FALSE; -#endif // CARRIER_DETECTION_SUPPORT // - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - //PSMode - if (RTMPGetKeyParameter("PSMode", tmpbuf, 10, buffer)) - { - if (pAd->StaCfg.BssType == BSS_INFRA) - { - if ((strcmp(tmpbuf, "MAX_PSP") == 0) || (strcmp(tmpbuf, "max_psp") == 0)) - { - // do NOT turn on PSM bit here, wait until MlmeCheckForPsmChange() - // to exclude certain situations. - // MlmeSetPsm(pAd, PWR_SAVE); - OPSTATUS_SET_FLAG(pAd, fOP_STATUS_RECEIVE_DTIM); - if (pAd->StaCfg.bWindowsACCAMEnable == FALSE) - pAd->StaCfg.WindowsPowerMode = Ndis802_11PowerModeMAX_PSP; - pAd->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeMAX_PSP; - pAd->StaCfg.DefaultListenCount = 5; - } - else if ((strcmp(tmpbuf, "Fast_PSP") == 0) || (strcmp(tmpbuf, "fast_psp") == 0) - || (strcmp(tmpbuf, "FAST_PSP") == 0)) - { - // do NOT turn on PSM bit here, wait until MlmeCheckForPsmChange() - // to exclude certain situations. - // MlmeSetPsmBit(pAd, PWR_SAVE); - OPSTATUS_SET_FLAG(pAd, fOP_STATUS_RECEIVE_DTIM); - if (pAd->StaCfg.bWindowsACCAMEnable == FALSE) - pAd->StaCfg.WindowsPowerMode = Ndis802_11PowerModeFast_PSP; - pAd->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeFast_PSP; - pAd->StaCfg.DefaultListenCount = 3; - } - else if ((strcmp(tmpbuf, "Legacy_PSP") == 0) || (strcmp(tmpbuf, "legacy_psp") == 0) - || (strcmp(tmpbuf, "LEGACY_PSP") == 0)) - { - // do NOT turn on PSM bit here, wait until MlmeCheckForPsmChange() - // to exclude certain situations. - // MlmeSetPsmBit(pAd, PWR_SAVE); - OPSTATUS_SET_FLAG(pAd, fOP_STATUS_RECEIVE_DTIM); - if (pAd->StaCfg.bWindowsACCAMEnable == FALSE) - pAd->StaCfg.WindowsPowerMode = Ndis802_11PowerModeLegacy_PSP; - pAd->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeLegacy_PSP; - pAd->StaCfg.DefaultListenCount = 3; - } - else - { //Default Ndis802_11PowerModeCAM - // clear PSM bit immediately - MlmeSetPsmBit(pAd, PWR_ACTIVE); - OPSTATUS_SET_FLAG(pAd, fOP_STATUS_RECEIVE_DTIM); - if (pAd->StaCfg.bWindowsACCAMEnable == FALSE) - pAd->StaCfg.WindowsPowerMode = Ndis802_11PowerModeCAM; - pAd->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeCAM; - } - DBGPRINT(RT_DEBUG_TRACE, ("PSMode=%ld\n", pAd->StaCfg.WindowsPowerMode)); - } - } - // FastRoaming - if (RTMPGetKeyParameter("FastRoaming", tmpbuf, 32, buffer)) - { - if (simple_strtol(tmpbuf, 0, 10) == 0) - pAd->StaCfg.bFastRoaming = FALSE; - else - pAd->StaCfg.bFastRoaming = TRUE; - - DBGPRINT(RT_DEBUG_TRACE, ("FastRoaming=%d\n", pAd->StaCfg.bFastRoaming)); - } - // RoamThreshold - if (RTMPGetKeyParameter("RoamThreshold", tmpbuf, 32, buffer)) - { - long lInfo = simple_strtol(tmpbuf, 0, 10); - - if (lInfo > 90 || lInfo < 60) - pAd->StaCfg.dBmToRoam = -70; - else - pAd->StaCfg.dBmToRoam = (CHAR)(-1)*lInfo; - - DBGPRINT(RT_DEBUG_TRACE, ("RoamThreshold=%d dBm\n", pAd->StaCfg.dBmToRoam)); - } - - if(RTMPGetKeyParameter("TGnWifiTest", tmpbuf, 10, buffer)) - { - if(simple_strtol(tmpbuf, 0, 10) == 0) - pAd->StaCfg.bTGnWifiTest = FALSE; - else - pAd->StaCfg.bTGnWifiTest = TRUE; - DBGPRINT(RT_DEBUG_TRACE, ("TGnWifiTest=%d\n", pAd->StaCfg.bTGnWifiTest)); - } - } -#endif // CONFIG_STA_SUPPORT // - - - - } - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("--> %s does not have a write method\n", src)); - } - - retval=filp_close(srcf,NULL); - - if (retval) - { - DBGPRINT(RT_DEBUG_TRACE, ("--> Error %d closing %s\n", -retval, src)); - } - } - } - - set_fs(orgfs); -#if 0 - current->fsuid = orgfsuid; - current->fsgid = orgfsgid; -#endif - - kfree(buffer); - kfree(tmpbuf); - - return (NDIS_STATUS_SUCCESS); -} - -#ifdef DOT11_N_SUPPORT -static void HTParametersHook( - IN PRTMP_ADAPTER pAd, - IN CHAR *pValueStr, - IN CHAR *pInput) -{ - - INT Value; - - if (RTMPGetKeyParameter("HT_PROTECT", pValueStr, 25, pInput)) - { - Value = simple_strtol(pValueStr, 0, 10); - if (Value == 0) - { - pAd->CommonCfg.bHTProtect = FALSE; - } - else - { - pAd->CommonCfg.bHTProtect = TRUE; - } - DBGPRINT(RT_DEBUG_TRACE, ("HT: Protection = %s\n", (Value==0) ? "Disable" : "Enable")); - } - - if (RTMPGetKeyParameter("HT_MIMOPSEnable", pValueStr, 25, pInput)) - { - Value = simple_strtol(pValueStr, 0, 10); - if (Value == 0) - { - pAd->CommonCfg.bMIMOPSEnable = FALSE; - } - else - { - pAd->CommonCfg.bMIMOPSEnable = TRUE; - } - DBGPRINT(RT_DEBUG_TRACE, ("HT: MIMOPSEnable = %s\n", (Value==0) ? "Disable" : "Enable")); - } - - - if (RTMPGetKeyParameter("HT_MIMOPSMode", pValueStr, 25, pInput)) - { - Value = simple_strtol(pValueStr, 0, 10); - if (Value > MMPS_ENABLE) - { - pAd->CommonCfg.BACapability.field.MMPSmode = MMPS_ENABLE; - } - else - { - //TODO: add mimo power saving mechanism - pAd->CommonCfg.BACapability.field.MMPSmode = MMPS_ENABLE; - //pAd->CommonCfg.BACapability.field.MMPSmode = Value; - } - DBGPRINT(RT_DEBUG_TRACE, ("HT: MIMOPS Mode = %d\n", Value)); - } - - if (RTMPGetKeyParameter("HT_BADecline", pValueStr, 25, pInput)) - { - Value = simple_strtol(pValueStr, 0, 10); - if (Value == 0) - { - pAd->CommonCfg.bBADecline = FALSE; - } - else - { - pAd->CommonCfg.bBADecline = TRUE; - } - DBGPRINT(RT_DEBUG_TRACE, ("HT: BA Decline = %s\n", (Value==0) ? "Disable" : "Enable")); - } - - - if (RTMPGetKeyParameter("HT_DisableReordering", pValueStr, 25, pInput)) - { - Value = simple_strtol(pValueStr, 0, 10); - if (Value == 0) - { - pAd->CommonCfg.bDisableReordering = FALSE; - } - else - { - pAd->CommonCfg.bDisableReordering = TRUE; - } - DBGPRINT(RT_DEBUG_TRACE, ("HT: DisableReordering = %s\n", (Value==0) ? "Disable" : "Enable")); - } - - if (RTMPGetKeyParameter("HT_AutoBA", pValueStr, 25, pInput)) - { - Value = simple_strtol(pValueStr, 0, 10); - if (Value == 0) - { - pAd->CommonCfg.BACapability.field.AutoBA = FALSE; - } - else - { - pAd->CommonCfg.BACapability.field.AutoBA = TRUE; - } - pAd->CommonCfg.REGBACapability.field.AutoBA = pAd->CommonCfg.BACapability.field.AutoBA; - DBGPRINT(RT_DEBUG_TRACE, ("HT: Auto BA = %s\n", (Value==0) ? "Disable" : "Enable")); - } - - // Tx_+HTC frame - if (RTMPGetKeyParameter("HT_HTC", pValueStr, 25, pInput)) - { - Value = simple_strtol(pValueStr, 0, 10); - if (Value == 0) - { - pAd->HTCEnable = FALSE; - } - else - { - pAd->HTCEnable = TRUE; - } - DBGPRINT(RT_DEBUG_TRACE, ("HT: Tx +HTC frame = %s\n", (Value==0) ? "Disable" : "Enable")); - } - - // Enable HT Link Adaptation Control - if (RTMPGetKeyParameter("HT_LinkAdapt", pValueStr, 25, pInput)) - { - Value = simple_strtol(pValueStr, 0, 10); - if (Value == 0) - { - pAd->bLinkAdapt = FALSE; - } - else - { - pAd->HTCEnable = TRUE; - pAd->bLinkAdapt = TRUE; - } - DBGPRINT(RT_DEBUG_TRACE, ("HT: Link Adaptation Control = %s\n", (Value==0) ? "Disable" : "Enable(+HTC)")); - } - - // Reverse Direction Mechanism - if (RTMPGetKeyParameter("HT_RDG", pValueStr, 25, pInput)) - { - Value = simple_strtol(pValueStr, 0, 10); - if (Value == 0) - { - pAd->CommonCfg.bRdg = FALSE; - } - else - { - pAd->HTCEnable = TRUE; - pAd->CommonCfg.bRdg = TRUE; - } - DBGPRINT(RT_DEBUG_TRACE, ("HT: RDG = %s\n", (Value==0) ? "Disable" : "Enable(+HTC)")); - } - - - - - // Tx A-MSUD ? - if (RTMPGetKeyParameter("HT_AMSDU", pValueStr, 25, pInput)) - { - Value = simple_strtol(pValueStr, 0, 10); - if (Value == 0) - { - pAd->CommonCfg.BACapability.field.AmsduEnable = FALSE; - } - else - { - pAd->CommonCfg.BACapability.field.AmsduEnable = TRUE; - } - DBGPRINT(RT_DEBUG_TRACE, ("HT: Tx A-MSDU = %s\n", (Value==0) ? "Disable" : "Enable")); - } - - // MPDU Density - if (RTMPGetKeyParameter("HT_MpduDensity", pValueStr, 25, pInput)) - { - Value = simple_strtol(pValueStr, 0, 10); - if (Value <=7 && Value >= 0) - { - pAd->CommonCfg.BACapability.field.MpduDensity = Value; - DBGPRINT(RT_DEBUG_TRACE, ("HT: MPDU Density = %d\n", Value)); - } - else - { - pAd->CommonCfg.BACapability.field.MpduDensity = 4; - DBGPRINT(RT_DEBUG_TRACE, ("HT: MPDU Density = %d (Default)\n", 4)); - } - } - - // Max Rx BA Window Size - if (RTMPGetKeyParameter("HT_BAWinSize", pValueStr, 25, pInput)) - { - Value = simple_strtol(pValueStr, 0, 10); - - if (Value >=1 && Value <= 64) - { - pAd->CommonCfg.REGBACapability.field.RxBAWinLimit = Value; - pAd->CommonCfg.BACapability.field.RxBAWinLimit = Value; - DBGPRINT(RT_DEBUG_TRACE, ("HT: BA Windw Size = %d\n", Value)); - } - else - { - pAd->CommonCfg.REGBACapability.field.RxBAWinLimit = 64; - pAd->CommonCfg.BACapability.field.RxBAWinLimit = 64; - DBGPRINT(RT_DEBUG_TRACE, ("HT: BA Windw Size = 64 (Defualt)\n")); - } - - } - - // Guard Interval - if (RTMPGetKeyParameter("HT_GI", pValueStr, 25, pInput)) - { - Value = simple_strtol(pValueStr, 0, 10); - - if (Value == GI_400) - { - pAd->CommonCfg.RegTransmitSetting.field.ShortGI = GI_400; - } - else - { - pAd->CommonCfg.RegTransmitSetting.field.ShortGI = GI_800; - } - - DBGPRINT(RT_DEBUG_TRACE, ("HT: Guard Interval = %s\n", (Value==GI_400) ? "400" : "800" )); - } - - // HT Operation Mode : Mixed Mode , Green Field - if (RTMPGetKeyParameter("HT_OpMode", pValueStr, 25, pInput)) - { - Value = simple_strtol(pValueStr, 0, 10); - - if (Value == HTMODE_GF) - { - - pAd->CommonCfg.RegTransmitSetting.field.HTMODE = HTMODE_GF; - } - else - { - pAd->CommonCfg.RegTransmitSetting.field.HTMODE = HTMODE_MM; - } - - DBGPRINT(RT_DEBUG_TRACE, ("HT: Operate Mode = %s\n", (Value==HTMODE_GF) ? "Green Field" : "Mixed Mode" )); - } - - // Fixed Tx mode : CCK, OFDM - if (RTMPGetKeyParameter("FixedTxMode", pValueStr, 25, pInput)) - { - UCHAR fix_tx_mode; - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - fix_tx_mode = FIXED_TXMODE_HT; - - if (strcmp(pValueStr, "OFDM") == 0 || strcmp(pValueStr, "ofdm") == 0) - { - fix_tx_mode = FIXED_TXMODE_OFDM; - } - else if (strcmp(pValueStr, "CCK") == 0 || strcmp(pValueStr, "cck") == 0) - { - fix_tx_mode = FIXED_TXMODE_CCK; - } - else if (strcmp(pValueStr, "HT") == 0 || strcmp(pValueStr, "ht") == 0) - { - fix_tx_mode = FIXED_TXMODE_HT; - } - else - { - Value = simple_strtol(pValueStr, 0, 10); - // 1 : CCK - // 2 : OFDM - // otherwise : HT - if (Value == FIXED_TXMODE_CCK || Value == FIXED_TXMODE_OFDM) - fix_tx_mode = Value; - else - fix_tx_mode = FIXED_TXMODE_HT; - } - - pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode = fix_tx_mode; - DBGPRINT(RT_DEBUG_TRACE, ("Fixed Tx Mode = %d\n", fix_tx_mode)); - - } -#endif // CONFIG_STA_SUPPORT // - } - - - // Channel Width - if (RTMPGetKeyParameter("HT_BW", pValueStr, 25, pInput)) - { - Value = simple_strtol(pValueStr, 0, 10); - - if (Value == BW_40) - { - pAd->CommonCfg.RegTransmitSetting.field.BW = BW_40; - } - else - { - pAd->CommonCfg.RegTransmitSetting.field.BW = BW_20; - } - -#ifdef MCAST_RATE_SPECIFIC - pAd->CommonCfg.MCastPhyMode.field.BW = pAd->CommonCfg.RegTransmitSetting.field.BW; -#endif // MCAST_RATE_SPECIFIC // - - DBGPRINT(RT_DEBUG_TRACE, ("HT: Channel Width = %s\n", (Value==BW_40) ? "40 MHz" : "20 MHz" )); - } - - if (RTMPGetKeyParameter("HT_EXTCHA", pValueStr, 25, pInput)) - { - Value = simple_strtol(pValueStr, 0, 10); - - if (Value == 0) - { - - pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_BELOW; - } - else - { - pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_ABOVE; - } - - DBGPRINT(RT_DEBUG_TRACE, ("HT: Ext Channel = %s\n", (Value==0) ? "BELOW" : "ABOVE" )); - } - - // MSC - if (RTMPGetKeyParameter("HT_MCS", pValueStr, 50, pInput)) - { - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - Value = simple_strtol(pValueStr, 0, 10); - -// if ((Value >= 0 && Value <= 15) || (Value == 32)) - if ((Value >= 0 && Value <= 23) || (Value == 32)) // 3*3 - { - pAd->StaCfg.DesiredTransmitSetting.field.MCS = Value; - pAd->StaCfg.bAutoTxRateSwitch = FALSE; - DBGPRINT(RT_DEBUG_TRACE, ("HT: MCS = %d\n", pAd->StaCfg.DesiredTransmitSetting.field.MCS)); - } - else - { - pAd->StaCfg.DesiredTransmitSetting.field.MCS = MCS_AUTO; - pAd->StaCfg.bAutoTxRateSwitch = TRUE; - DBGPRINT(RT_DEBUG_TRACE, ("HT: MCS = AUTO\n")); - } - } -#endif // CONFIG_STA_SUPPORT // - } - - // STBC - if (RTMPGetKeyParameter("HT_STBC", pValueStr, 25, pInput)) - { - Value = simple_strtol(pValueStr, 0, 10); - if (Value == STBC_USE) - { - pAd->CommonCfg.RegTransmitSetting.field.STBC = STBC_USE; - } - else - { - pAd->CommonCfg.RegTransmitSetting.field.STBC = STBC_NONE; - } - DBGPRINT(RT_DEBUG_TRACE, ("HT: STBC = %d\n", pAd->CommonCfg.RegTransmitSetting.field.STBC)); - } - - // 40_Mhz_Intolerant - if (RTMPGetKeyParameter("HT_40MHZ_INTOLERANT", pValueStr, 25, pInput)) - { - Value = simple_strtol(pValueStr, 0, 10); - if (Value == 0) - { - pAd->CommonCfg.bForty_Mhz_Intolerant = FALSE; - } - else - { - pAd->CommonCfg.bForty_Mhz_Intolerant = TRUE; - } - DBGPRINT(RT_DEBUG_TRACE, ("HT: 40MHZ INTOLERANT = %d\n", pAd->CommonCfg.bForty_Mhz_Intolerant)); - } - //HT_TxStream - if(RTMPGetKeyParameter("HT_TxStream", pValueStr, 10, pInput)) - { - switch (simple_strtol(pValueStr, 0, 10)) - { - case 1: - pAd->CommonCfg.TxStream = 1; - break; - case 2: - pAd->CommonCfg.TxStream = 2; - break; - case 3: // 3*3 - default: - pAd->CommonCfg.TxStream = 3; - - if (pAd->MACVersion < RALINK_2883_VERSION) - pAd->CommonCfg.TxStream = 2; // only 2 tx streams for RT2860 series - break; - } - DBGPRINT(RT_DEBUG_TRACE, ("HT: Tx Stream = %d\n", pAd->CommonCfg.TxStream)); - } - //HT_RxStream - if(RTMPGetKeyParameter("HT_RxStream", pValueStr, 10, pInput)) - { - switch (simple_strtol(pValueStr, 0, 10)) - { - case 1: - pAd->CommonCfg.RxStream = 1; - break; - case 2: - pAd->CommonCfg.RxStream = 2; - break; - case 3: - default: - pAd->CommonCfg.RxStream = 3; - - if (pAd->MACVersion < RALINK_2883_VERSION) - pAd->CommonCfg.RxStream = 2; // only 2 rx streams for RT2860 series - break; - } - DBGPRINT(RT_DEBUG_TRACE, ("HT: Rx Stream = %d\n", pAd->CommonCfg.RxStream)); - } - -} -#endif // DOT11_N_SUPPORT // - +#include "../rt2860/rt_profile.c" diff --git a/drivers/staging/rt2870/rtmp.h b/drivers/staging/rt2870/rtmp.h index c2a4784ec338..e5ef89f8bef1 100644 --- a/drivers/staging/rt2870/rtmp.h +++ b/drivers/staging/rt2870/rtmp.h @@ -1,7586 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - rtmp.h - - Abstract: - Miniport generic portion header file - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Paul Lin 2002-08-01 created - James Tan 2002-09-06 modified (Revise NTCRegTable) - John Chang 2004-09-06 modified for RT2600 -*/ -#ifndef __RTMP_H__ -#define __RTMP_H__ - -#include "link_list.h" -#include "spectrum_def.h" - - -#ifdef CONFIG_STA_SUPPORT -#include "aironet.h" -#endif // CONFIG_STA_SUPPORT // - -//#define DBG 1 - -//#define DBG_DIAGNOSE 1 - -#if defined(CONFIG_AP_SUPPORT) && defined(CONFIG_STA_SUPPORT) -#define IF_DEV_CONFIG_OPMODE_ON_AP(_pAd) if(_pAd->OpMode == OPMODE_AP) -#define IF_DEV_CONFIG_OPMODE_ON_STA(_pAd) if(_pAd->OpMode == OPMODE_STA) -#else -#define IF_DEV_CONFIG_OPMODE_ON_AP(_pAd) -#define IF_DEV_CONFIG_OPMODE_ON_STA(_pAd) -#endif - -#define VIRTUAL_IF_INC(__pAd) ((__pAd)->VirtualIfCnt++) -#define VIRTUAL_IF_DEC(__pAd) ((__pAd)->VirtualIfCnt--) -#define VIRTUAL_IF_NUM(__pAd) ((__pAd)->VirtualIfCnt) - -#ifdef RT2870 -//////////////////////////////////////////////////////////////////////////// -// The TX_BUFFER structure forms the transmitted USB packet to the device -//////////////////////////////////////////////////////////////////////////// -typedef struct __TX_BUFFER{ - union { - UCHAR WirelessPacket[TX_BUFFER_NORMSIZE]; - HEADER_802_11 NullFrame; - PSPOLL_FRAME PsPollPacket; - RTS_FRAME RTSFrame; - }field; - UCHAR Aggregation[4]; //Buffer for save Aggregation size. -} TX_BUFFER, *PTX_BUFFER; - -typedef struct __HTTX_BUFFER{ - union { - UCHAR WirelessPacket[MAX_TXBULK_SIZE]; - HEADER_802_11 NullFrame; - PSPOLL_FRAME PsPollPacket; - RTS_FRAME RTSFrame; - }field; - UCHAR Aggregation[4]; //Buffer for save Aggregation size. -} HTTX_BUFFER, *PHTTX_BUFFER; - - -// used to track driver-generated write irps -typedef struct _TX_CONTEXT -{ - PVOID pAd; //Initialized in MiniportInitialize - PURB pUrb; //Initialized in MiniportInitialize - PIRP pIrp; //used to cancel pending bulk out. - //Initialized in MiniportInitialize - PTX_BUFFER TransferBuffer; //Initialized in MiniportInitialize - ULONG BulkOutSize; - UCHAR BulkOutPipeId; - UCHAR SelfIdx; - BOOLEAN InUse; - BOOLEAN bWaitingBulkOut; // at least one packet is in this TxContext, ready for making IRP anytime. - BOOLEAN bFullForBulkOut; // all tx buffer are full , so waiting for tx bulkout. - BOOLEAN IRPPending; - BOOLEAN LastOne; - BOOLEAN bAggregatible; - UCHAR Header_802_3[LENGTH_802_3]; - UCHAR Rsv[2]; - ULONG DataOffset; - UINT TxRate; - dma_addr_t data_dma; // urb dma on linux - -} TX_CONTEXT, *PTX_CONTEXT, **PPTX_CONTEXT; - - -// used to track driver-generated write irps -typedef struct _HT_TX_CONTEXT -{ - PVOID pAd; //Initialized in MiniportInitialize - PURB pUrb; //Initialized in MiniportInitialize - PIRP pIrp; //used to cancel pending bulk out. - //Initialized in MiniportInitialize - PHTTX_BUFFER TransferBuffer; //Initialized in MiniportInitialize - ULONG BulkOutSize; // Indicate the total bulk-out size in bytes in one bulk-transmission - UCHAR BulkOutPipeId; - BOOLEAN IRPPending; - BOOLEAN LastOne; - BOOLEAN bCurWriting; - BOOLEAN bRingEmpty; - BOOLEAN bCopySavePad; - UCHAR SavedPad[8]; - UCHAR Header_802_3[LENGTH_802_3]; - ULONG CurWritePosition; // Indicate the buffer offset which packet will be inserted start from. - ULONG CurWriteRealPos; // Indicate the buffer offset which packet now are writing to. - ULONG NextBulkOutPosition; // Indicate the buffer start offset of a bulk-transmission - ULONG ENextBulkOutPosition; // Indicate the buffer end offset of a bulk-transmission - UINT TxRate; - dma_addr_t data_dma; // urb dma on linux -} HT_TX_CONTEXT, *PHT_TX_CONTEXT, **PPHT_TX_CONTEXT; - - -// -// Structure to keep track of receive packets and buffers to indicate -// receive data to the protocol. -// -typedef struct _RX_CONTEXT -{ - PUCHAR TransferBuffer; - PVOID pAd; - PIRP pIrp;//used to cancel pending bulk in. - PURB pUrb; - //These 2 Boolean shouldn't both be 1 at the same time. - ULONG BulkInOffset; // number of packets waiting for reordering . -// BOOLEAN ReorderInUse; // At least one packet in this buffer are in reordering buffer and wait for receive indication - BOOLEAN bRxHandling; // Notify this packet is being process now. - BOOLEAN InUse; // USB Hardware Occupied. Wait for USB HW to put packet. - BOOLEAN Readable; // Receive Complete back. OK for driver to indicate receiving packet. - BOOLEAN IRPPending; // TODO: To be removed - atomic_t IrpLock; - NDIS_SPIN_LOCK RxContextLock; - dma_addr_t data_dma; // urb dma on linux -} RX_CONTEXT, *PRX_CONTEXT; -#endif // RT2870 // - - -// -// NDIS Version definitions -// -#ifdef NDIS50_MINIPORT -#define RTMP_NDIS_MAJOR_VERSION 5 -#define RTMP_NDIS_MINOR_VERSION 0 -#endif - -#ifdef NDIS51_MINIPORT -#define RTMP_NDIS_MAJOR_VERSION 5 -#define RTMP_NDIS_MINOR_VERSION 1 -#endif - -extern char NIC_VENDOR_DESC[]; -extern int NIC_VENDOR_DESC_LEN; - -extern unsigned char SNAP_AIRONET[]; -extern unsigned char CipherSuiteCiscoCCKM[]; -extern unsigned char CipherSuiteCiscoCCKMLen; -extern unsigned char CipherSuiteCiscoCCKM24[]; -extern unsigned char CipherSuiteCiscoCCKM24Len; -extern unsigned char CipherSuiteCCXTkip[]; -extern unsigned char CipherSuiteCCXTkipLen; -extern unsigned char CISCO_OUI[]; -extern UCHAR BaSizeArray[4]; - -extern UCHAR BROADCAST_ADDR[MAC_ADDR_LEN]; -extern UCHAR MULTICAST_ADDR[MAC_ADDR_LEN]; -extern UCHAR ZERO_MAC_ADDR[MAC_ADDR_LEN]; -extern ULONG BIT32[32]; -extern UCHAR BIT8[8]; -extern char* CipherName[]; -extern char* MCSToMbps[]; -extern UCHAR RxwiMCSToOfdmRate[12]; -extern UCHAR SNAP_802_1H[6]; -extern UCHAR SNAP_BRIDGE_TUNNEL[6]; -extern UCHAR SNAP_AIRONET[8]; -extern UCHAR CKIP_LLC_SNAP[8]; -extern UCHAR EAPOL_LLC_SNAP[8]; -extern UCHAR EAPOL[2]; -extern UCHAR IPX[2]; -extern UCHAR APPLE_TALK[2]; -extern UCHAR RateIdToPlcpSignal[12]; // see IEEE802.11a-1999 p.14 -extern UCHAR OfdmRateToRxwiMCS[]; -extern UCHAR OfdmSignalToRateId[16] ; -extern UCHAR default_cwmin[4]; -extern UCHAR default_cwmax[4]; -extern UCHAR default_sta_aifsn[4]; -extern UCHAR MapUserPriorityToAccessCategory[8]; - -extern USHORT RateUpPER[]; -extern USHORT RateDownPER[]; -extern UCHAR Phy11BNextRateDownward[]; -extern UCHAR Phy11BNextRateUpward[]; -extern UCHAR Phy11BGNextRateDownward[]; -extern UCHAR Phy11BGNextRateUpward[]; -extern UCHAR Phy11ANextRateDownward[]; -extern UCHAR Phy11ANextRateUpward[]; -extern CHAR RssiSafeLevelForTxRate[]; -extern UCHAR RateIdToMbps[]; -extern USHORT RateIdTo500Kbps[]; - -extern UCHAR CipherSuiteWpaNoneTkip[]; -extern UCHAR CipherSuiteWpaNoneTkipLen; - -extern UCHAR CipherSuiteWpaNoneAes[]; -extern UCHAR CipherSuiteWpaNoneAesLen; - -extern UCHAR SsidIe; -extern UCHAR SupRateIe; -extern UCHAR ExtRateIe; - -#ifdef DOT11_N_SUPPORT -extern UCHAR HtCapIe; -extern UCHAR AddHtInfoIe; -extern UCHAR NewExtChanIe; -#ifdef DOT11N_DRAFT3 -extern UCHAR ExtHtCapIe; -#endif // DOT11N_DRAFT3 // -#endif // DOT11_N_SUPPORT // - -extern UCHAR ErpIe; -extern UCHAR DsIe; -extern UCHAR TimIe; -extern UCHAR WpaIe; -extern UCHAR Wpa2Ie; -extern UCHAR IbssIe; -extern UCHAR Ccx2Ie; - -extern UCHAR WPA_OUI[]; -extern UCHAR RSN_OUI[]; -extern UCHAR WME_INFO_ELEM[]; -extern UCHAR WME_PARM_ELEM[]; -extern UCHAR Ccx2QosInfo[]; -extern UCHAR Ccx2IeInfo[]; -extern UCHAR RALINK_OUI[]; -extern UCHAR PowerConstraintIE[]; - - -extern UCHAR RateSwitchTable[]; -extern UCHAR RateSwitchTable11B[]; -extern UCHAR RateSwitchTable11G[]; -extern UCHAR RateSwitchTable11BG[]; - -#ifdef DOT11_N_SUPPORT -extern UCHAR RateSwitchTable11BGN1S[]; -extern UCHAR RateSwitchTable11BGN2S[]; -extern UCHAR RateSwitchTable11BGN2SForABand[]; -extern UCHAR RateSwitchTable11N1S[]; -extern UCHAR RateSwitchTable11N2S[]; -extern UCHAR RateSwitchTable11N2SForABand[]; - -#ifdef CONFIG_STA_SUPPORT -extern UCHAR PRE_N_HT_OUI[]; -#endif // CONFIG_STA_SUPPORT // -#endif // DOT11_N_SUPPORT // - -#define MAXSEQ (0xFFF) - -#ifdef RALINK_ATE -typedef struct _ATE_INFO { - UCHAR Mode; - CHAR TxPower0; - CHAR TxPower1; - CHAR TxAntennaSel; - CHAR RxAntennaSel; - TXWI_STRUC TxWI; // TXWI - USHORT QID; - UCHAR Addr1[MAC_ADDR_LEN]; - UCHAR Addr2[MAC_ADDR_LEN]; - UCHAR Addr3[MAC_ADDR_LEN]; - UCHAR Channel; - UINT32 TxLength; - UINT32 TxCount; - UINT32 TxDoneCount; // Tx DMA Done - UINT32 RFFreqOffset; - BOOLEAN bRxFer; - BOOLEAN bQATxStart; // Have compiled QA in and use it to ATE tx. - BOOLEAN bQARxStart; // Have compiled QA in and use it to ATE rx. - UINT32 RxTotalCnt; - UINT32 RxCntPerSec; - - CHAR LastSNR0; // last received SNR - CHAR LastSNR1; // last received SNR for 2nd antenna - CHAR LastRssi0; // last received RSSI - CHAR LastRssi1; // last received RSSI for 2nd antenna - CHAR LastRssi2; // last received RSSI for 3rd antenna - CHAR AvgRssi0; // last 8 frames' average RSSI - CHAR AvgRssi1; // last 8 frames' average RSSI - CHAR AvgRssi2; // last 8 frames' average RSSI - SHORT AvgRssi0X8; // sum of last 8 frames' RSSI - SHORT AvgRssi1X8; // sum of last 8 frames' RSSI - SHORT AvgRssi2X8; // sum of last 8 frames' RSSI - - UINT32 NumOfAvgRssiSample; - -#ifdef RALINK_28xx_QA - // Tx frame -#ifdef RT2870 - /* not used in RT2860 */ - TXINFO_STRUC TxInfo; // TxInfo -#endif // RT2870 // - USHORT HLen; // Header Length - USHORT PLen; // Pattern Length - UCHAR Header[32]; // Header buffer - UCHAR Pattern[32]; // Pattern buffer - USHORT DLen; // Data Length - USHORT seq; - UINT32 CID; - THREAD_PID AtePid; - // counters - UINT32 U2M; - UINT32 OtherData; - UINT32 Beacon; - UINT32 OtherCount; - UINT32 TxAc0; - UINT32 TxAc1; - UINT32 TxAc2; - UINT32 TxAc3; - UINT32 TxHCCA; - UINT32 TxMgmt; - UINT32 RSSI0; - UINT32 RSSI1; - UINT32 RSSI2; - UINT32 SNR0; - UINT32 SNR1; - // control - //UINT32 Repeat; // Tx Cpu count - UCHAR TxStatus; // task Tx status // 0 --> task is idle, 1 --> task is running -#endif // RALINK_28xx_QA // -} ATE_INFO, *PATE_INFO; - -#ifdef RALINK_28xx_QA -struct ate_racfghdr { - UINT32 magic_no; - USHORT command_type; - USHORT command_id; - USHORT length; - USHORT sequence; - USHORT status; - UCHAR data[2046]; -} __attribute__((packed)); -#endif // RALINK_28xx_QA // -#endif // RALINK_ATE // - -#ifdef DOT11_N_SUPPORT -struct reordering_mpdu -{ - struct reordering_mpdu *next; - PNDIS_PACKET pPacket; /* coverted to 802.3 frame */ - int Sequence; /* sequence number of MPDU */ - BOOLEAN bAMSDU; -}; - -struct reordering_list -{ - struct reordering_mpdu *next; - int qlen; -}; - -struct reordering_mpdu_pool -{ - PVOID mem; - NDIS_SPIN_LOCK lock; - struct reordering_list freelist; -}; -#endif // DOT11_N_SUPPORT // - -typedef struct _RSSI_SAMPLE { - CHAR LastRssi0; // last received RSSI - CHAR LastRssi1; // last received RSSI - CHAR LastRssi2; // last received RSSI - CHAR AvgRssi0; - CHAR AvgRssi1; - CHAR AvgRssi2; - SHORT AvgRssi0X8; - SHORT AvgRssi1X8; - SHORT AvgRssi2X8; -} RSSI_SAMPLE; - -// -// Queue structure and macros -// -typedef struct _QUEUE_ENTRY { - struct _QUEUE_ENTRY *Next; -} QUEUE_ENTRY, *PQUEUE_ENTRY; - -// Queue structure -typedef struct _QUEUE_HEADER { - PQUEUE_ENTRY Head; - PQUEUE_ENTRY Tail; - ULONG Number; -} QUEUE_HEADER, *PQUEUE_HEADER; - -#define InitializeQueueHeader(QueueHeader) \ -{ \ - (QueueHeader)->Head = (QueueHeader)->Tail = NULL; \ - (QueueHeader)->Number = 0; \ -} - -#define RemoveHeadQueue(QueueHeader) \ -(QueueHeader)->Head; \ -{ \ - PQUEUE_ENTRY pNext; \ - if ((QueueHeader)->Head != NULL) \ - { \ - pNext = (QueueHeader)->Head->Next; \ - (QueueHeader)->Head = pNext; \ - if (pNext == NULL) \ - (QueueHeader)->Tail = NULL; \ - (QueueHeader)->Number--; \ - } \ -} - -#define InsertHeadQueue(QueueHeader, QueueEntry) \ -{ \ - ((PQUEUE_ENTRY)QueueEntry)->Next = (QueueHeader)->Head; \ - (QueueHeader)->Head = (PQUEUE_ENTRY)(QueueEntry); \ - if ((QueueHeader)->Tail == NULL) \ - (QueueHeader)->Tail = (PQUEUE_ENTRY)(QueueEntry); \ - (QueueHeader)->Number++; \ -} - -#define InsertTailQueue(QueueHeader, QueueEntry) \ -{ \ - ((PQUEUE_ENTRY)QueueEntry)->Next = NULL; \ - if ((QueueHeader)->Tail) \ - (QueueHeader)->Tail->Next = (PQUEUE_ENTRY)(QueueEntry); \ - else \ - (QueueHeader)->Head = (PQUEUE_ENTRY)(QueueEntry); \ - (QueueHeader)->Tail = (PQUEUE_ENTRY)(QueueEntry); \ - (QueueHeader)->Number++; \ -} - -// -// Macros for flag and ref count operations -// -#define RTMP_SET_FLAG(_M, _F) ((_M)->Flags |= (_F)) -#define RTMP_CLEAR_FLAG(_M, _F) ((_M)->Flags &= ~(_F)) -#define RTMP_CLEAR_FLAGS(_M) ((_M)->Flags = 0) -#define RTMP_TEST_FLAG(_M, _F) (((_M)->Flags & (_F)) != 0) -#define RTMP_TEST_FLAGS(_M, _F) (((_M)->Flags & (_F)) == (_F)) - -#define OPSTATUS_SET_FLAG(_pAd, _F) ((_pAd)->CommonCfg.OpStatusFlags |= (_F)) -#define OPSTATUS_CLEAR_FLAG(_pAd, _F) ((_pAd)->CommonCfg.OpStatusFlags &= ~(_F)) -#define OPSTATUS_TEST_FLAG(_pAd, _F) (((_pAd)->CommonCfg.OpStatusFlags & (_F)) != 0) - -#define CLIENT_STATUS_SET_FLAG(_pEntry,_F) ((_pEntry)->ClientStatusFlags |= (_F)) -#define CLIENT_STATUS_CLEAR_FLAG(_pEntry,_F) ((_pEntry)->ClientStatusFlags &= ~(_F)) -#define CLIENT_STATUS_TEST_FLAG(_pEntry,_F) (((_pEntry)->ClientStatusFlags & (_F)) != 0) - -#define RX_FILTER_SET_FLAG(_pAd, _F) ((_pAd)->CommonCfg.PacketFilter |= (_F)) -#define RX_FILTER_CLEAR_FLAG(_pAd, _F) ((_pAd)->CommonCfg.PacketFilter &= ~(_F)) -#define RX_FILTER_TEST_FLAG(_pAd, _F) (((_pAd)->CommonCfg.PacketFilter & (_F)) != 0) - -#ifdef CONFIG_STA_SUPPORT -#define STA_NO_SECURITY_ON(_p) (_p->StaCfg.WepStatus == Ndis802_11EncryptionDisabled) -#define STA_WEP_ON(_p) (_p->StaCfg.WepStatus == Ndis802_11Encryption1Enabled) -#define STA_TKIP_ON(_p) (_p->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) -#define STA_AES_ON(_p) (_p->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) - -#define STA_TGN_WIFI_ON(_p) (_p->StaCfg.bTGnWifiTest == TRUE) -#endif // CONFIG_STA_SUPPORT // - -#define CKIP_KP_ON(_p) ((((_p)->StaCfg.CkipFlag) & 0x10) && ((_p)->StaCfg.bCkipCmicOn == TRUE)) -#define CKIP_CMIC_ON(_p) ((((_p)->StaCfg.CkipFlag) & 0x08) && ((_p)->StaCfg.bCkipCmicOn == TRUE)) - - -#define INC_RING_INDEX(_idx, _RingSize) \ -{ \ - (_idx) = (_idx+1) % (_RingSize); \ -} - -#define IS_RT3070(_pAd) (((_pAd)->MACVersion & 0xffff0000) == 0x30700000) - -#define RING_PACKET_INIT(_TxRing, _idx) \ -{ \ - _TxRing->Cell[_idx].pNdisPacket = NULL; \ - _TxRing->Cell[_idx].pNextNdisPacket = NULL; \ -} - -#define TXDT_INIT(_TxD) \ -{ \ - NdisZeroMemory(_TxD, TXD_SIZE); \ - _TxD->DMADONE = 1; \ -} - -//Set last data segment -#define RING_SET_LASTDS(_TxD, _IsSD0) \ -{ \ - if (_IsSD0) {_TxD->LastSec0 = 1;} \ - else {_TxD->LastSec1 = 1;} \ -} - -// Increase TxTsc value for next transmission -// TODO: -// When i==6, means TSC has done one full cycle, do re-keying stuff follow specs -// Should send a special event microsoft defined to request re-key -#define INC_TX_TSC(_tsc) \ -{ \ - int i=0; \ - while (++_tsc[i] == 0x0) \ - { \ - i++; \ - if (i == 6) \ - break; \ - } \ -} - -#ifdef DOT11_N_SUPPORT -// StaActive.SupportedHtPhy.MCSSet is copied from AP beacon. Don't need to update here. -#define COPY_HTSETTINGS_FROM_MLME_AUX_TO_ACTIVE_CFG(_pAd) \ -{ \ - _pAd->StaActive.SupportedHtPhy.ChannelWidth = _pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth; \ - _pAd->StaActive.SupportedHtPhy.MimoPs = _pAd->MlmeAux.HtCapability.HtCapInfo.MimoPs; \ - _pAd->StaActive.SupportedHtPhy.GF = _pAd->MlmeAux.HtCapability.HtCapInfo.GF; \ - _pAd->StaActive.SupportedHtPhy.ShortGIfor20 = _pAd->MlmeAux.HtCapability.HtCapInfo.ShortGIfor20; \ - _pAd->StaActive.SupportedHtPhy.ShortGIfor40 = _pAd->MlmeAux.HtCapability.HtCapInfo.ShortGIfor40; \ - _pAd->StaActive.SupportedHtPhy.TxSTBC = _pAd->MlmeAux.HtCapability.HtCapInfo.TxSTBC; \ - _pAd->StaActive.SupportedHtPhy.RxSTBC = _pAd->MlmeAux.HtCapability.HtCapInfo.RxSTBC; \ - _pAd->StaActive.SupportedHtPhy.ExtChanOffset = _pAd->MlmeAux.AddHtInfo.AddHtInfo.ExtChanOffset; \ - _pAd->StaActive.SupportedHtPhy.RecomWidth = _pAd->MlmeAux.AddHtInfo.AddHtInfo.RecomWidth; \ - _pAd->StaActive.SupportedHtPhy.OperaionMode = _pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode; \ - _pAd->StaActive.SupportedHtPhy.NonGfPresent = _pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent; \ - NdisMoveMemory((_pAd)->MacTab.Content[BSSID_WCID].HTCapability.MCSSet, (_pAd)->StaActive.SupportedPhyInfo.MCSSet, sizeof(UCHAR) * 16);\ -} - -#define COPY_AP_HTSETTINGS_FROM_BEACON(_pAd, _pHtCapability) \ -{ \ - _pAd->MacTab.Content[BSSID_WCID].AMsduSize = (UCHAR)(_pHtCapability->HtCapInfo.AMsduSize); \ - _pAd->MacTab.Content[BSSID_WCID].MmpsMode= (UCHAR)(_pHtCapability->HtCapInfo.MimoPs); \ - _pAd->MacTab.Content[BSSID_WCID].MaxRAmpduFactor = (UCHAR)(_pHtCapability->HtCapParm.MaxRAmpduFactor); \ -} -#endif // DOT11_N_SUPPORT // - -// -// BBP & RF are using indirect access. Before write any value into it. -// We have to make sure there is no outstanding command pending via checking busy bit. -// -#define MAX_BUSY_COUNT 100 // Number of retry before failing access BBP & RF indirect register -// - -#ifdef RT2870 -#define RTMP_RF_IO_WRITE32(_A, _V) RTUSBWriteRFRegister(_A, _V) -#define RTMP_BBP_IO_READ8_BY_REG_ID(_A, _I, _pV) RTUSBReadBBPRegister(_A, _I, _pV) -#define RTMP_BBP_IO_WRITE8_BY_REG_ID(_A, _I, _V) RTUSBWriteBBPRegister(_A, _I, _V) - -#define BBP_IO_WRITE8_BY_REG_ID(_A, _I, _V) RTUSBWriteBBPRegister(_A, _I, _V) -#define BBP_IO_READ8_BY_REG_ID(_A, _I, _pV) RTUSBReadBBPRegister(_A, _I, _pV) -#endif // RT2870 // - -#define MAP_CHANNEL_ID_TO_KHZ(ch, khz) { \ - switch (ch) \ - { \ - case 1: khz = 2412000; break; \ - case 2: khz = 2417000; break; \ - case 3: khz = 2422000; break; \ - case 4: khz = 2427000; break; \ - case 5: khz = 2432000; break; \ - case 6: khz = 2437000; break; \ - case 7: khz = 2442000; break; \ - case 8: khz = 2447000; break; \ - case 9: khz = 2452000; break; \ - case 10: khz = 2457000; break; \ - case 11: khz = 2462000; break; \ - case 12: khz = 2467000; break; \ - case 13: khz = 2472000; break; \ - case 14: khz = 2484000; break; \ - case 36: /* UNII */ khz = 5180000; break; \ - case 40: /* UNII */ khz = 5200000; break; \ - case 44: /* UNII */ khz = 5220000; break; \ - case 48: /* UNII */ khz = 5240000; break; \ - case 52: /* UNII */ khz = 5260000; break; \ - case 56: /* UNII */ khz = 5280000; break; \ - case 60: /* UNII */ khz = 5300000; break; \ - case 64: /* UNII */ khz = 5320000; break; \ - case 149: /* UNII */ khz = 5745000; break; \ - case 153: /* UNII */ khz = 5765000; break; \ - case 157: /* UNII */ khz = 5785000; break; \ - case 161: /* UNII */ khz = 5805000; break; \ - case 165: /* UNII */ khz = 5825000; break; \ - case 100: /* HiperLAN2 */ khz = 5500000; break; \ - case 104: /* HiperLAN2 */ khz = 5520000; break; \ - case 108: /* HiperLAN2 */ khz = 5540000; break; \ - case 112: /* HiperLAN2 */ khz = 5560000; break; \ - case 116: /* HiperLAN2 */ khz = 5580000; break; \ - case 120: /* HiperLAN2 */ khz = 5600000; break; \ - case 124: /* HiperLAN2 */ khz = 5620000; break; \ - case 128: /* HiperLAN2 */ khz = 5640000; break; \ - case 132: /* HiperLAN2 */ khz = 5660000; break; \ - case 136: /* HiperLAN2 */ khz = 5680000; break; \ - case 140: /* HiperLAN2 */ khz = 5700000; break; \ - case 34: /* Japan MMAC */ khz = 5170000; break; \ - case 38: /* Japan MMAC */ khz = 5190000; break; \ - case 42: /* Japan MMAC */ khz = 5210000; break; \ - case 46: /* Japan MMAC */ khz = 5230000; break; \ - case 184: /* Japan */ khz = 4920000; break; \ - case 188: /* Japan */ khz = 4940000; break; \ - case 192: /* Japan */ khz = 4960000; break; \ - case 196: /* Japan */ khz = 4980000; break; \ - case 208: /* Japan, means J08 */ khz = 5040000; break; \ - case 212: /* Japan, means J12 */ khz = 5060000; break; \ - case 216: /* Japan, means J16 */ khz = 5080000; break; \ - default: khz = 2412000; break; \ - } \ - } - -#define MAP_KHZ_TO_CHANNEL_ID(khz, ch) { \ - switch (khz) \ - { \ - case 2412000: ch = 1; break; \ - case 2417000: ch = 2; break; \ - case 2422000: ch = 3; break; \ - case 2427000: ch = 4; break; \ - case 2432000: ch = 5; break; \ - case 2437000: ch = 6; break; \ - case 2442000: ch = 7; break; \ - case 2447000: ch = 8; break; \ - case 2452000: ch = 9; break; \ - case 2457000: ch = 10; break; \ - case 2462000: ch = 11; break; \ - case 2467000: ch = 12; break; \ - case 2472000: ch = 13; break; \ - case 2484000: ch = 14; break; \ - case 5180000: ch = 36; /* UNII */ break; \ - case 5200000: ch = 40; /* UNII */ break; \ - case 5220000: ch = 44; /* UNII */ break; \ - case 5240000: ch = 48; /* UNII */ break; \ - case 5260000: ch = 52; /* UNII */ break; \ - case 5280000: ch = 56; /* UNII */ break; \ - case 5300000: ch = 60; /* UNII */ break; \ - case 5320000: ch = 64; /* UNII */ break; \ - case 5745000: ch = 149; /* UNII */ break; \ - case 5765000: ch = 153; /* UNII */ break; \ - case 5785000: ch = 157; /* UNII */ break; \ - case 5805000: ch = 161; /* UNII */ break; \ - case 5825000: ch = 165; /* UNII */ break; \ - case 5500000: ch = 100; /* HiperLAN2 */ break; \ - case 5520000: ch = 104; /* HiperLAN2 */ break; \ - case 5540000: ch = 108; /* HiperLAN2 */ break; \ - case 5560000: ch = 112; /* HiperLAN2 */ break; \ - case 5580000: ch = 116; /* HiperLAN2 */ break; \ - case 5600000: ch = 120; /* HiperLAN2 */ break; \ - case 5620000: ch = 124; /* HiperLAN2 */ break; \ - case 5640000: ch = 128; /* HiperLAN2 */ break; \ - case 5660000: ch = 132; /* HiperLAN2 */ break; \ - case 5680000: ch = 136; /* HiperLAN2 */ break; \ - case 5700000: ch = 140; /* HiperLAN2 */ break; \ - case 5170000: ch = 34; /* Japan MMAC */ break; \ - case 5190000: ch = 38; /* Japan MMAC */ break; \ - case 5210000: ch = 42; /* Japan MMAC */ break; \ - case 5230000: ch = 46; /* Japan MMAC */ break; \ - case 4920000: ch = 184; /* Japan */ break; \ - case 4940000: ch = 188; /* Japan */ break; \ - case 4960000: ch = 192; /* Japan */ break; \ - case 4980000: ch = 196; /* Japan */ break; \ - case 5040000: ch = 208; /* Japan, means J08 */ break; \ - case 5060000: ch = 212; /* Japan, means J12 */ break; \ - case 5080000: ch = 216; /* Japan, means J16 */ break; \ - default: ch = 1; break; \ - } \ - } - -// -// Common fragment list structure - Identical to the scatter gather frag list structure -// -//#define RTMP_SCATTER_GATHER_ELEMENT SCATTER_GATHER_ELEMENT -//#define PRTMP_SCATTER_GATHER_ELEMENT PSCATTER_GATHER_ELEMENT -#define NIC_MAX_PHYS_BUF_COUNT 8 - -typedef struct _RTMP_SCATTER_GATHER_ELEMENT { - PVOID Address; - ULONG Length; - PULONG Reserved; -} RTMP_SCATTER_GATHER_ELEMENT, *PRTMP_SCATTER_GATHER_ELEMENT; - - -typedef struct _RTMP_SCATTER_GATHER_LIST { - ULONG NumberOfElements; - PULONG Reserved; - RTMP_SCATTER_GATHER_ELEMENT Elements[NIC_MAX_PHYS_BUF_COUNT]; -} RTMP_SCATTER_GATHER_LIST, *PRTMP_SCATTER_GATHER_LIST; - -// -// Some utility macros -// -#ifndef min -#define min(_a, _b) (((_a) < (_b)) ? (_a) : (_b)) -#endif - -#ifndef max -#define max(_a, _b) (((_a) > (_b)) ? (_a) : (_b)) -#endif - -#define GET_LNA_GAIN(_pAd) ((_pAd->LatchRfRegs.Channel <= 14) ? (_pAd->BLNAGain) : ((_pAd->LatchRfRegs.Channel <= 64) ? (_pAd->ALNAGain0) : ((_pAd->LatchRfRegs.Channel <= 128) ? (_pAd->ALNAGain1) : (_pAd->ALNAGain2)))) - -#define INC_COUNTER64(Val) (Val.QuadPart++) - -#define INFRA_ON(_p) (OPSTATUS_TEST_FLAG(_p, fOP_STATUS_INFRA_ON)) -#define ADHOC_ON(_p) (OPSTATUS_TEST_FLAG(_p, fOP_STATUS_ADHOC_ON)) -#define MONITOR_ON(_p) (((_p)->StaCfg.BssType) == BSS_MONITOR) -#define IDLE_ON(_p) (!INFRA_ON(_p) && !ADHOC_ON(_p)) - -// Check LEAP & CCKM flags -#define LEAP_ON(_p) (((_p)->StaCfg.LeapAuthMode) == CISCO_AuthModeLEAP) -#define LEAP_CCKM_ON(_p) ((((_p)->StaCfg.LeapAuthMode) == CISCO_AuthModeLEAP) && ((_p)->StaCfg.LeapAuthInfo.CCKM == TRUE)) - -// if orginal Ethernet frame contains no LLC/SNAP, then an extra LLC/SNAP encap is required -#define EXTRA_LLCSNAP_ENCAP_FROM_PKT_START(_pBufVA, _pExtraLlcSnapEncap) \ -{ \ - if (((*(_pBufVA + 12) << 8) + *(_pBufVA + 13)) > 1500) \ - { \ - _pExtraLlcSnapEncap = SNAP_802_1H; \ - if (NdisEqualMemory(IPX, _pBufVA + 12, 2) || \ - NdisEqualMemory(APPLE_TALK, _pBufVA + 12, 2)) \ - { \ - _pExtraLlcSnapEncap = SNAP_BRIDGE_TUNNEL; \ - } \ - } \ - else \ - { \ - _pExtraLlcSnapEncap = NULL; \ - } \ -} - -// New Define for new Tx Path. -#define EXTRA_LLCSNAP_ENCAP_FROM_PKT_OFFSET(_pBufVA, _pExtraLlcSnapEncap) \ -{ \ - if (((*(_pBufVA) << 8) + *(_pBufVA + 1)) > 1500) \ - { \ - _pExtraLlcSnapEncap = SNAP_802_1H; \ - if (NdisEqualMemory(IPX, _pBufVA, 2) || \ - NdisEqualMemory(APPLE_TALK, _pBufVA, 2)) \ - { \ - _pExtraLlcSnapEncap = SNAP_BRIDGE_TUNNEL; \ - } \ - } \ - else \ - { \ - _pExtraLlcSnapEncap = NULL; \ - } \ -} - - -#define MAKE_802_3_HEADER(_p, _pMac1, _pMac2, _pType) \ -{ \ - NdisMoveMemory(_p, _pMac1, MAC_ADDR_LEN); \ - NdisMoveMemory((_p + MAC_ADDR_LEN), _pMac2, MAC_ADDR_LEN); \ - NdisMoveMemory((_p + MAC_ADDR_LEN * 2), _pType, LENGTH_802_3_TYPE); \ -} - -// if pData has no LLC/SNAP (neither RFC1042 nor Bridge tunnel), keep it that way. -// else if the received frame is LLC/SNAP-encaped IPX or APPLETALK, preserve the LLC/SNAP field -// else remove the LLC/SNAP field from the result Ethernet frame -// Patch for WHQL only, which did not turn on Netbios but use IPX within its payload -// Note: -// _pData & _DataSize may be altered (remove 8-byte LLC/SNAP) by this MACRO -// _pRemovedLLCSNAP: pointer to removed LLC/SNAP; NULL is not removed -#define CONVERT_TO_802_3(_p8023hdr, _pDA, _pSA, _pData, _DataSize, _pRemovedLLCSNAP) \ -{ \ - char LLC_Len[2]; \ - \ - _pRemovedLLCSNAP = NULL; \ - if (NdisEqualMemory(SNAP_802_1H, _pData, 6) || \ - NdisEqualMemory(SNAP_BRIDGE_TUNNEL, _pData, 6)) \ - { \ - PUCHAR pProto = _pData + 6; \ - \ - if ((NdisEqualMemory(IPX, pProto, 2) || NdisEqualMemory(APPLE_TALK, pProto, 2)) && \ - NdisEqualMemory(SNAP_802_1H, _pData, 6)) \ - { \ - LLC_Len[0] = (UCHAR)(_DataSize / 256); \ - LLC_Len[1] = (UCHAR)(_DataSize % 256); \ - MAKE_802_3_HEADER(_p8023hdr, _pDA, _pSA, LLC_Len); \ - } \ - else \ - { \ - MAKE_802_3_HEADER(_p8023hdr, _pDA, _pSA, pProto); \ - _pRemovedLLCSNAP = _pData; \ - _DataSize -= LENGTH_802_1_H; \ - _pData += LENGTH_802_1_H; \ - } \ - } \ - else \ - { \ - LLC_Len[0] = (UCHAR)(_DataSize / 256); \ - LLC_Len[1] = (UCHAR)(_DataSize % 256); \ - MAKE_802_3_HEADER(_p8023hdr, _pDA, _pSA, LLC_Len); \ - } \ -} - -#define SWITCH_AB( _pAA, _pBB) \ -{ \ - PVOID pCC; \ - pCC = _pBB; \ - _pBB = _pAA; \ - _pAA = pCC; \ -} - -// Enqueue this frame to MLME engine -// We need to enqueue the whole frame because MLME need to pass data type -// information from 802.11 header -#ifdef RT2870 -#define REPORT_MGMT_FRAME_TO_MLME(_pAd, Wcid, _pFrame, _FrameSize, _Rssi0, _Rssi1, _Rssi2, _PlcpSignal) \ -{ \ - UINT32 High32TSF=0, Low32TSF=0; \ - MlmeEnqueueForRecv(_pAd, Wcid, High32TSF, Low32TSF, (UCHAR)_Rssi0, (UCHAR)_Rssi1,(UCHAR)_Rssi2,_FrameSize, _pFrame, (UCHAR)_PlcpSignal); \ -} -#endif // RT2870 // - -#define NDIS_QUERY_BUFFER(_NdisBuf, _ppVA, _pBufLen) \ - NdisQueryBuffer(_NdisBuf, _ppVA, _pBufLen) - -#define MAC_ADDR_EQUAL(pAddr1,pAddr2) RTMPEqualMemory((PVOID)(pAddr1), (PVOID)(pAddr2), MAC_ADDR_LEN) -#define SSID_EQUAL(ssid1, len1, ssid2, len2) ((len1==len2) && (RTMPEqualMemory(ssid1, ssid2, len1))) - -// -// Check if it is Japan W53(ch52,56,60,64) channel. -// -#define JapanChannelCheck(channel) ((channel == 52) || (channel == 56) || (channel == 60) || (channel == 64)) - -#ifdef CONFIG_STA_SUPPORT -#define STA_PORT_SECURED(_pAd) \ -{ \ - _pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; \ - NdisAcquireSpinLock(&_pAd->MacTabLock); \ - _pAd->MacTab.Content[BSSID_WCID].PortSecured = _pAd->StaCfg.PortSecured; \ - NdisReleaseSpinLock(&_pAd->MacTabLock); \ -} -#endif // CONFIG_STA_SUPPORT // - - -// -// Register set pair for initialzation register set definition -// -typedef struct _RTMP_REG_PAIR -{ - ULONG Register; - ULONG Value; -} RTMP_REG_PAIR, *PRTMP_REG_PAIR; - -typedef struct _REG_PAIR -{ - UCHAR Register; - UCHAR Value; -} REG_PAIR, *PREG_PAIR; - -// -// Register set pair for initialzation register set definition -// -typedef struct _RTMP_RF_REGS -{ - UCHAR Channel; - ULONG R1; - ULONG R2; - ULONG R3; - ULONG R4; -} RTMP_RF_REGS, *PRTMP_RF_REGS; - -typedef struct _FREQUENCY_ITEM { - UCHAR Channel; - UCHAR N; - UCHAR R; - UCHAR K; -} FREQUENCY_ITEM, *PFREQUENCY_ITEM; - -// -// Data buffer for DMA operation, the buffer must be contiguous physical memory -// Both DMA to / from CPU use the same structure. -// -typedef struct _RTMP_DMABUF -{ - ULONG AllocSize; - PVOID AllocVa; // TxBuf virtual address - NDIS_PHYSICAL_ADDRESS AllocPa; // TxBuf physical address -} RTMP_DMABUF, *PRTMP_DMABUF; - - -typedef union _HEADER_802_11_SEQ{ -#ifdef RT_BIG_ENDIAN - struct { - USHORT Sequence:12; - USHORT Frag:4; - } field; -#else - struct { - USHORT Frag:4; - USHORT Sequence:12; - } field; -#endif - USHORT value; -} HEADER_802_11_SEQ, *PHEADER_802_11_SEQ; - -// -// Data buffer for DMA operation, the buffer must be contiguous physical memory -// Both DMA to / from CPU use the same structure. -// -typedef struct _RTMP_REORDERBUF -{ - BOOLEAN IsFull; - PVOID AllocVa; // TxBuf virtual address - UCHAR Header802_3[14]; - HEADER_802_11_SEQ Sequence; //support compressed bitmap BA, so no consider fragment in BA - UCHAR DataOffset; - USHORT Datasize; - ULONG AllocSize; -#ifdef RT2870 - PUCHAR AllocPa; -#endif // RT2870 // -} RTMP_REORDERBUF, *PRTMP_REORDERBUF; - -// -// Control block (Descriptor) for all ring descriptor DMA operation, buffer must be -// contiguous physical memory. NDIS_PACKET stored the binding Rx packet descriptor -// which won't be released, driver has to wait until upper layer return the packet -// before giveing up this rx ring descriptor to ASIC. NDIS_BUFFER is assocaited pair -// to describe the packet buffer. For Tx, NDIS_PACKET stored the tx packet descriptor -// which driver should ACK upper layer when the tx is physically done or failed. -// -typedef struct _RTMP_DMACB -{ - ULONG AllocSize; // Control block size - PVOID AllocVa; // Control block virtual address - NDIS_PHYSICAL_ADDRESS AllocPa; // Control block physical address - PNDIS_PACKET pNdisPacket; - PNDIS_PACKET pNextNdisPacket; - - RTMP_DMABUF DmaBuf; // Associated DMA buffer structure -} RTMP_DMACB, *PRTMP_DMACB; - -typedef struct _RTMP_TX_BUF -{ - PQUEUE_ENTRY Next; - UCHAR Index; - ULONG AllocSize; // Control block size - PVOID AllocVa; // Control block virtual address - NDIS_PHYSICAL_ADDRESS AllocPa; // Control block physical address -} RTMP_TXBUF, *PRTMP_TXBUF; - -typedef struct _RTMP_RX_BUF -{ - BOOLEAN InUse; - ULONG ByBaRecIndex; - RTMP_REORDERBUF MAP_RXBuf[MAX_RX_REORDERBUF]; -} RTMP_RXBUF, *PRTMP_RXBUF; -typedef struct _RTMP_TX_RING -{ - RTMP_DMACB Cell[TX_RING_SIZE]; - UINT32 TxCpuIdx; - UINT32 TxDmaIdx; - UINT32 TxSwFreeIdx; // software next free tx index -} RTMP_TX_RING, *PRTMP_TX_RING; - -typedef struct _RTMP_RX_RING -{ - RTMP_DMACB Cell[RX_RING_SIZE]; - UINT32 RxCpuIdx; - UINT32 RxDmaIdx; - INT32 RxSwReadIdx; // software next read index -} RTMP_RX_RING, *PRTMP_RX_RING; - -typedef struct _RTMP_MGMT_RING -{ - RTMP_DMACB Cell[MGMT_RING_SIZE]; - UINT32 TxCpuIdx; - UINT32 TxDmaIdx; - UINT32 TxSwFreeIdx; // software next free tx index -} RTMP_MGMT_RING, *PRTMP_MGMT_RING; - -// -// Statistic counter structure -// -typedef struct _COUNTER_802_3 -{ - // General Stats - ULONG GoodTransmits; - ULONG GoodReceives; - ULONG TxErrors; - ULONG RxErrors; - ULONG RxNoBuffer; - - // Ethernet Stats - ULONG RcvAlignmentErrors; - ULONG OneCollision; - ULONG MoreCollisions; - -} COUNTER_802_3, *PCOUNTER_802_3; - -typedef struct _COUNTER_802_11 { - ULONG Length; - LARGE_INTEGER LastTransmittedFragmentCount; - LARGE_INTEGER TransmittedFragmentCount; - LARGE_INTEGER MulticastTransmittedFrameCount; - LARGE_INTEGER FailedCount; - LARGE_INTEGER RetryCount; - LARGE_INTEGER MultipleRetryCount; - LARGE_INTEGER RTSSuccessCount; - LARGE_INTEGER RTSFailureCount; - LARGE_INTEGER ACKFailureCount; - LARGE_INTEGER FrameDuplicateCount; - LARGE_INTEGER ReceivedFragmentCount; - LARGE_INTEGER MulticastReceivedFrameCount; - LARGE_INTEGER FCSErrorCount; -} COUNTER_802_11, *PCOUNTER_802_11; - -typedef struct _COUNTER_RALINK { - ULONG TransmittedByteCount; // both successful and failure, used to calculate TX throughput - ULONG ReceivedByteCount; // both CRC okay and CRC error, used to calculate RX throughput - ULONG BeenDisassociatedCount; - ULONG BadCQIAutoRecoveryCount; - ULONG PoorCQIRoamingCount; - ULONG MgmtRingFullCount; - ULONG RxCountSinceLastNULL; - ULONG RxCount; - ULONG RxRingErrCount; - ULONG KickTxCount; - ULONG TxRingErrCount; - LARGE_INTEGER RealFcsErrCount; - ULONG PendingNdisPacketCount; - - ULONG OneSecOsTxCount[NUM_OF_TX_RING]; - ULONG OneSecDmaDoneCount[NUM_OF_TX_RING]; - UINT32 OneSecTxDoneCount; - ULONG OneSecRxCount; - UINT32 OneSecTxAggregationCount; - UINT32 OneSecRxAggregationCount; - - UINT32 OneSecFrameDuplicateCount; - -#ifdef RT2870 - ULONG OneSecTransmittedByteCount; // both successful and failure, used to calculate TX throughput -#endif // RT2870 // - - UINT32 OneSecTxNoRetryOkCount; - UINT32 OneSecTxRetryOkCount; - UINT32 OneSecTxFailCount; - UINT32 OneSecFalseCCACnt; // CCA error count, for debug purpose, might move to global counter - UINT32 OneSecRxOkCnt; // RX without error - UINT32 OneSecRxOkDataCnt; // unicast-to-me DATA frame count - UINT32 OneSecRxFcsErrCnt; // CRC error - UINT32 OneSecBeaconSentCnt; - UINT32 LastOneSecTotalTxCount; // OneSecTxNoRetryOkCount + OneSecTxRetryOkCount + OneSecTxFailCount - UINT32 LastOneSecRxOkDataCnt; // OneSecRxOkDataCnt - ULONG DuplicateRcv; - ULONG TxAggCount; - ULONG TxNonAggCount; - ULONG TxAgg1MPDUCount; - ULONG TxAgg2MPDUCount; - ULONG TxAgg3MPDUCount; - ULONG TxAgg4MPDUCount; - ULONG TxAgg5MPDUCount; - ULONG TxAgg6MPDUCount; - ULONG TxAgg7MPDUCount; - ULONG TxAgg8MPDUCount; - ULONG TxAgg9MPDUCount; - ULONG TxAgg10MPDUCount; - ULONG TxAgg11MPDUCount; - ULONG TxAgg12MPDUCount; - ULONG TxAgg13MPDUCount; - ULONG TxAgg14MPDUCount; - ULONG TxAgg15MPDUCount; - ULONG TxAgg16MPDUCount; - - LARGE_INTEGER TransmittedOctetsInAMSDU; - LARGE_INTEGER TransmittedAMSDUCount; - LARGE_INTEGER ReceivedOctesInAMSDUCount; - LARGE_INTEGER ReceivedAMSDUCount; - LARGE_INTEGER TransmittedAMPDUCount; - LARGE_INTEGER TransmittedMPDUsInAMPDUCount; - LARGE_INTEGER TransmittedOctetsInAMPDUCount; - LARGE_INTEGER MPDUInReceivedAMPDUCount; -} COUNTER_RALINK, *PCOUNTER_RALINK; - -typedef struct _PID_COUNTER { - ULONG TxAckRequiredCount; // CRC error - ULONG TxAggreCount; - ULONG TxSuccessCount; // OneSecTxNoRetryOkCount + OneSecTxRetryOkCount + OneSecTxFailCount - ULONG LastSuccessRate; -} PID_COUNTER, *PPID_COUNTER; - -typedef struct _COUNTER_DRS { - // to record the each TX rate's quality. 0 is best, the bigger the worse. - USHORT TxQuality[MAX_STEP_OF_TX_RATE_SWITCH]; - UCHAR PER[MAX_STEP_OF_TX_RATE_SWITCH]; - UCHAR TxRateUpPenalty; // extra # of second penalty due to last unstable condition - ULONG CurrTxRateStableTime; // # of second in current TX rate - BOOLEAN fNoisyEnvironment; - BOOLEAN fLastSecAccordingRSSI; - UCHAR LastSecTxRateChangeAction; // 0: no change, 1:rate UP, 2:rate down - UCHAR LastTimeTxRateChangeAction; //Keep last time value of LastSecTxRateChangeAction - ULONG LastTxOkCount; -} COUNTER_DRS, *PCOUNTER_DRS; - -// -// Arcfour Structure Added by PaulWu -// -typedef struct _ARCFOUR -{ - UINT X; - UINT Y; - UCHAR STATE[256]; -} ARCFOURCONTEXT, *PARCFOURCONTEXT; - -// MIMO Tx parameter, ShortGI, MCS, STBC, etc. these are fields in TXWI too. just copy to TXWI. -typedef struct _RECEIVE_SETTING { -#ifdef RT_BIG_ENDIAN - USHORT MIMO:1; - USHORT OFDM:1; - USHORT rsv:3; - USHORT STBC:2; //SPACE - USHORT ShortGI:1; - USHORT Mode:2; //channel bandwidth 20MHz or 40 MHz - USHORT NumOfRX:2; // MIMO. WE HAVE 3R -#else - USHORT NumOfRX:2; // MIMO. WE HAVE 3R - USHORT Mode:2; //channel bandwidth 20MHz or 40 MHz - USHORT ShortGI:1; - USHORT STBC:2; //SPACE - USHORT rsv:3; - USHORT OFDM:1; - USHORT MIMO:1; -#endif - } RECEIVE_SETTING, *PRECEIVE_SETTING; - -// Shared key data structure -typedef struct _WEP_KEY { - UCHAR KeyLen; // Key length for each key, 0: entry is invalid - UCHAR Key[MAX_LEN_OF_KEY]; // right now we implement 4 keys, 128 bits max -} WEP_KEY, *PWEP_KEY; - -typedef struct _CIPHER_KEY { - UCHAR Key[16]; // right now we implement 4 keys, 128 bits max - UCHAR RxMic[8]; // make alignment - UCHAR TxMic[8]; - UCHAR TxTsc[6]; // 48bit TSC value - UCHAR RxTsc[6]; // 48bit TSC value - UCHAR CipherAlg; // 0-none, 1:WEP64, 2:WEP128, 3:TKIP, 4:AES, 5:CKIP64, 6:CKIP128 - UCHAR KeyLen; -#ifdef CONFIG_STA_SUPPORT - UCHAR BssId[6]; -#endif // CONFIG_STA_SUPPORT // - // Key length for each key, 0: entry is invalid - UCHAR Type; // Indicate Pairwise/Group when reporting MIC error -} CIPHER_KEY, *PCIPHER_KEY; - -typedef struct _BBP_TUNING_STRUCT { - BOOLEAN Enable; - UCHAR FalseCcaCountUpperBound; // 100 per sec - UCHAR FalseCcaCountLowerBound; // 10 per sec - UCHAR R17LowerBound; // specified in E2PROM - UCHAR R17UpperBound; // 0x68 according to David Tung - UCHAR CurrentR17Value; -} BBP_TUNING, *PBBP_TUNING; - -typedef struct _SOFT_RX_ANT_DIVERSITY_STRUCT { - UCHAR EvaluatePeriod; // 0:not evalute status, 1: evaluate status, 2: switching status - UCHAR Pair1PrimaryRxAnt; // 0:Ant-E1, 1:Ant-E2 - UCHAR Pair1SecondaryRxAnt; // 0:Ant-E1, 1:Ant-E2 - UCHAR Pair2PrimaryRxAnt; // 0:Ant-E3, 1:Ant-E4 - UCHAR Pair2SecondaryRxAnt; // 0:Ant-E3, 1:Ant-E4 - SHORT Pair1AvgRssi[2]; // AvgRssi[0]:E1, AvgRssi[1]:E2 - SHORT Pair2AvgRssi[2]; // AvgRssi[0]:E3, AvgRssi[1]:E4 - SHORT Pair1LastAvgRssi; // - SHORT Pair2LastAvgRssi; // - ULONG RcvPktNumWhenEvaluate; - BOOLEAN FirstPktArrivedWhenEvaluate; - RALINK_TIMER_STRUCT RxAntDiversityTimer; -} SOFT_RX_ANT_DIVERSITY, *PSOFT_RX_ANT_DIVERSITY; - -typedef struct _LEAP_AUTH_INFO { - BOOLEAN Enabled; //Ture: Enable LEAP Authentication - BOOLEAN CCKM; //Ture: Use Fast Reauthentication with CCKM - UCHAR Reserve[2]; - UCHAR UserName[256]; //LEAP, User name - ULONG UserNameLen; - UCHAR Password[256]; //LEAP, User Password - ULONG PasswordLen; -} LEAP_AUTH_INFO, *PLEAP_AUTH_INFO; - -typedef struct { - UCHAR Addr[MAC_ADDR_LEN]; - UCHAR ErrorCode[2]; //00 01-Invalid authentication type - //00 02-Authentication timeout - //00 03-Challenge from AP failed - //00 04-Challenge to AP failed - BOOLEAN Reported; -} ROGUEAP_ENTRY, *PROGUEAP_ENTRY; - -typedef struct { - UCHAR RogueApNr; - ROGUEAP_ENTRY RogueApEntry[MAX_LEN_OF_BSS_TABLE]; -} ROGUEAP_TABLE, *PROGUEAP_TABLE; - -typedef struct { - BOOLEAN Enable; - UCHAR Delta; - BOOLEAN PlusSign; -} CCK_TX_POWER_CALIBRATE, *PCCK_TX_POWER_CALIBRATE; - -// -// Receive Tuple Cache Format -// -typedef struct _TUPLE_CACHE { - BOOLEAN Valid; - UCHAR MacAddress[MAC_ADDR_LEN]; - USHORT Sequence; - USHORT Frag; -} TUPLE_CACHE, *PTUPLE_CACHE; - -// -// Fragment Frame structure -// -typedef struct _FRAGMENT_FRAME { - PNDIS_PACKET pFragPacket; - ULONG RxSize; - USHORT Sequence; - USHORT LastFrag; - ULONG Flags; // Some extra frame information. bit 0: LLC presented -} FRAGMENT_FRAME, *PFRAGMENT_FRAME; - - -// -// Packet information for NdisQueryPacket -// -typedef struct _PACKET_INFO { - UINT PhysicalBufferCount; // Physical breaks of buffer descripor chained - UINT BufferCount ; // Number of Buffer descriptor chained - UINT TotalPacketLength ; // Self explained - PNDIS_BUFFER pFirstBuffer; // Pointer to first buffer descriptor -} PACKET_INFO, *PPACKET_INFO; - -// -// Tkip Key structure which RC4 key & MIC calculation -// -typedef struct _TKIP_KEY_INFO { - UINT nBytesInM; // # bytes in M for MICKEY - ULONG IV16; - ULONG IV32; - ULONG K0; // for MICKEY Low - ULONG K1; // for MICKEY Hig - ULONG L; // Current state for MICKEY - ULONG R; // Current state for MICKEY - ULONG M; // Message accumulator for MICKEY - UCHAR RC4KEY[16]; - UCHAR MIC[8]; -} TKIP_KEY_INFO, *PTKIP_KEY_INFO; - -// -// Private / Misc data, counters for driver internal use -// -typedef struct __PRIVATE_STRUC { - UINT SystemResetCnt; // System reset counter - UINT TxRingFullCnt; // Tx ring full occurrance number - UINT PhyRxErrCnt; // PHY Rx error count, for debug purpose, might move to global counter - // Variables for WEP encryption / decryption in rtmp_wep.c - UINT FCSCRC32; - ARCFOURCONTEXT WEPCONTEXT; - // Tkip stuff - TKIP_KEY_INFO Tx; - TKIP_KEY_INFO Rx; -} PRIVATE_STRUC, *PPRIVATE_STRUC; - -// structure to tune BBP R66 (BBP TUNING) -typedef struct _BBP_R66_TUNING { - BOOLEAN bEnable; - USHORT FalseCcaLowerThreshold; // default 100 - USHORT FalseCcaUpperThreshold; // default 512 - UCHAR R66Delta; - UCHAR R66CurrentValue; - BOOLEAN R66LowerUpperSelect; //Before LinkUp, Used LowerBound or UpperBound as R66 value. -} BBP_R66_TUNING, *PBBP_R66_TUNING; - -// structure to store channel TX power -typedef struct _CHANNEL_TX_POWER { - USHORT RemainingTimeForUse; //unit: sec - UCHAR Channel; -#ifdef DOT11N_DRAFT3 - BOOLEAN bEffectedChannel; // For BW 40 operating in 2.4GHz , the "effected channel" is the channel that is covered in 40Mhz. -#endif // DOT11N_DRAFT3 // - CHAR Power; - CHAR Power2; - UCHAR MaxTxPwr; - UCHAR DfsReq; -} CHANNEL_TX_POWER, *PCHANNEL_TX_POWER; - -// structure to store 802.11j channel TX power -typedef struct _CHANNEL_11J_TX_POWER { - UCHAR Channel; - UCHAR BW; // BW_10 or BW_20 - CHAR Power; - CHAR Power2; - USHORT RemainingTimeForUse; //unit: sec -} CHANNEL_11J_TX_POWER, *PCHANNEL_11J_TX_POWER; - -typedef enum _ABGBAND_STATE_ { - UNKNOWN_BAND, - BG_BAND, - A_BAND, -} ABGBAND_STATE; - -typedef struct _MLME_STRUCT { -#ifdef CONFIG_STA_SUPPORT - // STA state machines - STATE_MACHINE CntlMachine; - STATE_MACHINE AssocMachine; - STATE_MACHINE AuthMachine; - STATE_MACHINE AuthRspMachine; - STATE_MACHINE SyncMachine; - STATE_MACHINE WpaPskMachine; - STATE_MACHINE LeapMachine; - STATE_MACHINE AironetMachine; - STATE_MACHINE_FUNC AssocFunc[ASSOC_FUNC_SIZE]; - STATE_MACHINE_FUNC AuthFunc[AUTH_FUNC_SIZE]; - STATE_MACHINE_FUNC AuthRspFunc[AUTH_RSP_FUNC_SIZE]; - STATE_MACHINE_FUNC SyncFunc[SYNC_FUNC_SIZE]; - STATE_MACHINE_FUNC WpaPskFunc[WPA_PSK_FUNC_SIZE]; - STATE_MACHINE_FUNC AironetFunc[AIRONET_FUNC_SIZE]; -#endif // CONFIG_STA_SUPPORT // - STATE_MACHINE_FUNC ActFunc[ACT_FUNC_SIZE]; - // Action - STATE_MACHINE ActMachine; - - -#ifdef QOS_DLS_SUPPORT - STATE_MACHINE DlsMachine; - STATE_MACHINE_FUNC DlsFunc[DLS_FUNC_SIZE]; -#endif // QOS_DLS_SUPPORT // - - - - - ULONG ChannelQuality; // 0..100, Channel Quality Indication for Roaming - ULONG Now32; // latch the value of NdisGetSystemUpTime() - ULONG LastSendNULLpsmTime; - - BOOLEAN bRunning; - NDIS_SPIN_LOCK TaskLock; - MLME_QUEUE Queue; - - UINT ShiftReg; - - RALINK_TIMER_STRUCT PeriodicTimer; - RALINK_TIMER_STRUCT APSDPeriodicTimer; - RALINK_TIMER_STRUCT LinkDownTimer; - RALINK_TIMER_STRUCT LinkUpTimer; - ULONG PeriodicRound; - ULONG OneSecPeriodicRound; - - UCHAR RealRxPath; - BOOLEAN bLowThroughput; - BOOLEAN bEnableAutoAntennaCheck; - RALINK_TIMER_STRUCT RxAntEvalTimer; - -#ifdef RT2870 - UCHAR CaliBW40RfR24; - UCHAR CaliBW20RfR24; -#endif // RT2870 // - -} MLME_STRUCT, *PMLME_STRUCT; - -// structure for radar detection and channel switch -typedef struct _RADAR_DETECT_STRUCT { - //BOOLEAN IEEE80211H; // 0: disable, 1: enable IEEE802.11h - UCHAR CSCount; //Channel switch counter - UCHAR CSPeriod; //Channel switch period (beacon count) - UCHAR RDCount; //Radar detection counter - UCHAR RDMode; //Radar Detection mode - UCHAR RDDurRegion; //Radar detection duration region - UCHAR BBPR16; - UCHAR BBPR17; - UCHAR BBPR18; - UCHAR BBPR21; - UCHAR BBPR22; - UCHAR BBPR64; - ULONG InServiceMonitorCount; // unit: sec - UINT8 DfsSessionTime; - BOOLEAN bFastDfs; - UINT8 ChMovingTime; - UINT8 LongPulseRadarTh; -} RADAR_DETECT_STRUCT, *PRADAR_DETECT_STRUCT; - -#ifdef CARRIER_DETECTION_SUPPORT -typedef enum CD_STATE_n -{ - CD_NORMAL, - CD_SILENCE, - CD_MAX_STATE -} CD_STATE; - -typedef struct CARRIER_DETECTION_s -{ - BOOLEAN Enable; - UINT8 CDSessionTime; - UINT8 CDPeriod; - CD_STATE CD_State; -} CARRIER_DETECTION, *PCARRIER_DETECTION; -#endif // CARRIER_DETECTION_SUPPORT // - -typedef enum _REC_BLOCKACK_STATUS -{ - Recipient_NONE=0, - Recipient_USED, - Recipient_HandleRes, - Recipient_Accept -} REC_BLOCKACK_STATUS, *PREC_BLOCKACK_STATUS; - -typedef enum _ORI_BLOCKACK_STATUS -{ - Originator_NONE=0, - Originator_USED, - Originator_WaitRes, - Originator_Done -} ORI_BLOCKACK_STATUS, *PORI_BLOCKACK_STATUS; - -#ifdef DOT11_N_SUPPORT -typedef struct _BA_ORI_ENTRY{ - UCHAR Wcid; - UCHAR TID; - UCHAR BAWinSize; - UCHAR Token; -// Sequence is to fill every outgoing QoS DATA frame's sequence field in 802.11 header. - USHORT Sequence; - USHORT TimeOutValue; - ORI_BLOCKACK_STATUS ORI_BA_Status; - RALINK_TIMER_STRUCT ORIBATimer; - PVOID pAdapter; -} BA_ORI_ENTRY, *PBA_ORI_ENTRY; - -typedef struct _BA_REC_ENTRY { - UCHAR Wcid; - UCHAR TID; - UCHAR BAWinSize; // 7.3.1.14. each buffer is capable of holding a max AMSDU or MSDU. - //UCHAR NumOfRxPkt; - //UCHAR Curindidx; // the head in the RX reordering buffer - USHORT LastIndSeq; -// USHORT LastIndSeqAtTimer; - USHORT TimeOutValue; - RALINK_TIMER_STRUCT RECBATimer; - ULONG LastIndSeqAtTimer; - ULONG nDropPacket; - ULONG rcvSeq; - REC_BLOCKACK_STATUS REC_BA_Status; -// UCHAR RxBufIdxUsed; - // corresponding virtual address for RX reordering packet storage. - //RTMP_REORDERDMABUF MAP_RXBuf[MAX_RX_REORDERBUF]; - NDIS_SPIN_LOCK RxReRingLock; // Rx Ring spinlock -// struct _BA_REC_ENTRY *pNext; - PVOID pAdapter; - struct reordering_list list; -} BA_REC_ENTRY, *PBA_REC_ENTRY; - - -typedef struct { - ULONG numAsRecipient; // I am recipient of numAsRecipient clients. These client are in the BARecEntry[] - ULONG numAsOriginator; // I am originator of numAsOriginator clients. These clients are in the BAOriEntry[] - BA_ORI_ENTRY BAOriEntry[MAX_LEN_OF_BA_ORI_TABLE]; - BA_REC_ENTRY BARecEntry[MAX_LEN_OF_BA_REC_TABLE]; -} BA_TABLE, *PBA_TABLE; - -//For QureyBATableOID use; -typedef struct PACKED _OID_BA_REC_ENTRY{ - UCHAR MACAddr[MAC_ADDR_LEN]; - UCHAR BaBitmap; // if (BaBitmap&(1<> 3) + 1) /* /8 + 1 */ -#define WLAN_CT_TIM_BCMC_OFFSET 0 /* unit: 32B */ - -/* clear bcmc TIM bit */ -#define WLAN_MR_TIM_BCMC_CLEAR(apidx) \ - pAd->ApCfg.MBSSID[apidx].TimBitmaps[WLAN_CT_TIM_BCMC_OFFSET] &= ~BIT8[0]; - -/* set bcmc TIM bit */ -#define WLAN_MR_TIM_BCMC_SET(apidx) \ - pAd->ApCfg.MBSSID[apidx].TimBitmaps[WLAN_CT_TIM_BCMC_OFFSET] |= BIT8[0]; - -/* clear a station PS TIM bit */ -#define WLAN_MR_TIM_BIT_CLEAR(ad_p, apidx, wcid) \ - { UCHAR tim_offset = wcid >> 3; \ - UCHAR bit_offset = wcid & 0x7; \ - ad_p->ApCfg.MBSSID[apidx].TimBitmaps[tim_offset] &= (~BIT8[bit_offset]); } - -/* set a station PS TIM bit */ -#define WLAN_MR_TIM_BIT_SET(ad_p, apidx, wcid) \ - { UCHAR tim_offset = wcid >> 3; \ - UCHAR bit_offset = wcid & 0x7; \ - ad_p->ApCfg.MBSSID[apidx].TimBitmaps[tim_offset] |= BIT8[bit_offset]; } - -#ifdef RT2870 -#define BEACON_BITMAP_MASK 0xff -typedef struct _BEACON_SYNC_STRUCT_ -{ - UCHAR BeaconBuf[HW_BEACON_MAX_COUNT][HW_BEACON_OFFSET]; - UCHAR BeaconTxWI[HW_BEACON_MAX_COUNT][TXWI_SIZE]; - ULONG TimIELocationInBeacon[HW_BEACON_MAX_COUNT]; - ULONG CapabilityInfoLocationInBeacon[HW_BEACON_MAX_COUNT]; - BOOLEAN EnableBeacon; // trigger to enable beacon transmission. - UCHAR BeaconBitMap; // NOTE: If the MAX_MBSSID_NUM is larger than 8, this parameter need to change. - UCHAR DtimBitOn; // NOTE: If the MAX_MBSSID_NUM is larger than 8, this parameter need to change. -}BEACON_SYNC_STRUCT; -#endif // RT2870 // - -typedef struct _MULTISSID_STRUCT { - UCHAR Bssid[MAC_ADDR_LEN]; - UCHAR SsidLen; - CHAR Ssid[MAX_LEN_OF_SSID]; - USHORT CapabilityInfo; - - PNET_DEV MSSIDDev; - - NDIS_802_11_AUTHENTICATION_MODE AuthMode; - NDIS_802_11_WEP_STATUS WepStatus; - NDIS_802_11_WEP_STATUS GroupKeyWepStatus; - WPA_MIX_PAIR_CIPHER WpaMixPairCipher; - - ULONG TxCount; - ULONG RxCount; - ULONG ReceivedByteCount; - ULONG TransmittedByteCount; - ULONG RxErrorCount; - ULONG RxDropCount; - - HTTRANSMIT_SETTING HTPhyMode, MaxHTPhyMode, MinHTPhyMode;// For transmit phy setting in TXWI. - RT_HT_PHY_INFO DesiredHtPhyInfo; - DESIRED_TRANSMIT_SETTING DesiredTransmitSetting; // Desired transmit setting. this is for reading registry setting only. not useful. - BOOLEAN bAutoTxRateSwitch; - - //CIPHER_KEY SharedKey[SHARE_KEY_NUM]; // ref pAd->SharedKey[BSS][4] - UCHAR DefaultKeyId; - - UCHAR TxRate; // RATE_1, RATE_2, RATE_5_5, RATE_11, ... - UCHAR DesiredRates[MAX_LEN_OF_SUPPORTED_RATES];// OID_802_11_DESIRED_RATES - UCHAR DesiredRatesIndex; - UCHAR MaxTxRate; // RATE_1, RATE_2, RATE_5_5, RATE_11 - -// ULONG TimBitmap; // bit0 for broadcast, 1 for AID1, 2 for AID2, ...so on -// ULONG TimBitmap2; // b0 for AID32, b1 for AID33, ... and so on - UCHAR TimBitmaps[WLAN_MAX_NUM_OF_TIM]; - - // WPA - UCHAR GMK[32]; - UCHAR PMK[32]; - UCHAR GTK[32]; - BOOLEAN IEEE8021X; - BOOLEAN PreAuth; - UCHAR GNonce[32]; - UCHAR PortSecured; - NDIS_802_11_PRIVACY_FILTER PrivacyFilter; - UCHAR BANClass3Data; - ULONG IsolateInterStaTraffic; - - UCHAR RSNIE_Len[2]; - UCHAR RSN_IE[2][MAX_LEN_OF_RSNIE]; - - - UCHAR TimIELocationInBeacon; - UCHAR CapabilityInfoLocationInBeacon; - // outgoing BEACON frame buffer and corresponding TXWI - // PTXWI_STRUC BeaconTxWI; // - CHAR BeaconBuf[MAX_BEACON_SIZE]; // NOTE: BeaconBuf should be 4-byte aligned - - BOOLEAN bHideSsid; - UINT16 StationKeepAliveTime; // unit: second - - USHORT VLAN_VID; - USHORT VLAN_Priority; - - RT_802_11_ACL AccessControlList; - - // EDCA Qos - BOOLEAN bWmmCapable; // 0:disable WMM, 1:enable WMM - BOOLEAN bDLSCapable; // 0:disable DLS, 1:enable DLS - - UCHAR DlsPTK[64]; // Due to windows dirver count on meetinghouse to handle 4-way shake - - // For 802.1x daemon setting per BSS - UCHAR radius_srv_num; - RADIUS_SRV_INFO radius_srv_info[MAX_RADIUS_SRV_NUM]; - -#ifdef RTL865X_SOC - unsigned int mylinkid; -#endif - - - UINT32 RcvdConflictSsidCount; - UINT32 RcvdSpoofedAssocRespCount; - UINT32 RcvdSpoofedReassocRespCount; - UINT32 RcvdSpoofedProbeRespCount; - UINT32 RcvdSpoofedBeaconCount; - UINT32 RcvdSpoofedDisassocCount; - UINT32 RcvdSpoofedAuthCount; - UINT32 RcvdSpoofedDeauthCount; - UINT32 RcvdSpoofedUnknownMgmtCount; - UINT32 RcvdReplayAttackCount; - - CHAR RssiOfRcvdConflictSsid; - CHAR RssiOfRcvdSpoofedAssocResp; - CHAR RssiOfRcvdSpoofedReassocResp; - CHAR RssiOfRcvdSpoofedProbeResp; - CHAR RssiOfRcvdSpoofedBeacon; - CHAR RssiOfRcvdSpoofedDisassoc; - CHAR RssiOfRcvdSpoofedAuth; - CHAR RssiOfRcvdSpoofedDeauth; - CHAR RssiOfRcvdSpoofedUnknownMgmt; - CHAR RssiOfRcvdReplayAttack; - - BOOLEAN bBcnSntReq; - UCHAR BcnBufIdx; -} MULTISSID_STRUCT, *PMULTISSID_STRUCT; - - - -#ifdef DOT11N_DRAFT3 -typedef enum _BSS2040COEXIST_FLAG{ - BSS_2040_COEXIST_DISABLE = 0, - BSS_2040_COEXIST_TIMER_FIRED = 1, - BSS_2040_COEXIST_INFO_SYNC = 2, - BSS_2040_COEXIST_INFO_NOTIFY = 4, -}BSS2040COEXIST_FLAG; -#endif // DOT11N_DRAFT3 // - -// configuration common to OPMODE_AP as well as OPMODE_STA -typedef struct _COMMON_CONFIG { - - BOOLEAN bCountryFlag; - UCHAR CountryCode[3]; - UCHAR Geography; - UCHAR CountryRegion; // Enum of country region, 0:FCC, 1:IC, 2:ETSI, 3:SPAIN, 4:France, 5:MKK, 6:MKK1, 7:Israel - UCHAR CountryRegionForABand; // Enum of country region for A band - UCHAR PhyMode; // PHY_11A, PHY_11B, PHY_11BG_MIXED, PHY_ABG_MIXED - USHORT Dsifs; // in units of usec - ULONG PacketFilter; // Packet filter for receiving - - CHAR Ssid[MAX_LEN_OF_SSID]; // NOT NULL-terminated - UCHAR SsidLen; // the actual ssid length in used - UCHAR LastSsidLen; // the actual ssid length in used - CHAR LastSsid[MAX_LEN_OF_SSID]; // NOT NULL-terminated - UCHAR LastBssid[MAC_ADDR_LEN]; - - UCHAR Bssid[MAC_ADDR_LEN]; - USHORT BeaconPeriod; - UCHAR Channel; - UCHAR CentralChannel; // Central Channel when using 40MHz is indicating. not real channel. - -#if 0 // move to STA_ADMIN_CONFIG - UCHAR DefaultKeyId; - - NDIS_802_11_PRIVACY_FILTER PrivacyFilter; // PrivacyFilter enum for 802.1X - NDIS_802_11_AUTHENTICATION_MODE AuthMode; // This should match to whatever microsoft defined - NDIS_802_11_WEP_STATUS WepStatus; - NDIS_802_11_WEP_STATUS OrigWepStatus; // Original wep status set from OID - - // Add to support different cipher suite for WPA2/WPA mode - NDIS_802_11_ENCRYPTION_STATUS GroupCipher; // Multicast cipher suite - NDIS_802_11_ENCRYPTION_STATUS PairCipher; // Unicast cipher suite - BOOLEAN bMixCipher; // Indicate current Pair & Group use different cipher suites - USHORT RsnCapability; - - NDIS_802_11_WEP_STATUS GroupKeyWepStatus; -#endif - - UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES]; - UCHAR SupRateLen; - UCHAR ExtRate[MAX_LEN_OF_SUPPORTED_RATES]; - UCHAR ExtRateLen; - UCHAR DesireRate[MAX_LEN_OF_SUPPORTED_RATES]; // OID_802_11_DESIRED_RATES - UCHAR MaxDesiredRate; - UCHAR ExpectedACKRate[MAX_LEN_OF_SUPPORTED_RATES]; - - ULONG BasicRateBitmap; // backup basic ratebitmap - - BOOLEAN bAPSDCapable; - BOOLEAN bInServicePeriod; - BOOLEAN bAPSDAC_BE; - BOOLEAN bAPSDAC_BK; - BOOLEAN bAPSDAC_VI; - BOOLEAN bAPSDAC_VO; - BOOLEAN bNeedSendTriggerFrame; - BOOLEAN bAPSDForcePowerSave; // Force power save mode, should only use in APSD-STAUT - ULONG TriggerTimerCount; - UCHAR MaxSPLength; - UCHAR BBPCurrentBW; // BW_10, BW_20, BW_40 - // move to MULTISSID_STRUCT for MBSS - //HTTRANSMIT_SETTING HTPhyMode, MaxHTPhyMode, MinHTPhyMode;// For transmit phy setting in TXWI. - REG_TRANSMIT_SETTING RegTransmitSetting; //registry transmit setting. this is for reading registry setting only. not useful. - //UCHAR FixedTxMode; // Fixed Tx Mode (CCK, OFDM), for HT fixed tx mode (GF, MIX) , refer to RegTransmitSetting.field.HTMode - UCHAR TxRate; // Same value to fill in TXD. TxRate is 6-bit - UCHAR MaxTxRate; // RATE_1, RATE_2, RATE_5_5, RATE_11 - UCHAR TxRateIndex; // Tx rate index in RateSwitchTable - UCHAR TxRateTableSize; // Valid Tx rate table size in RateSwitchTable - //BOOLEAN bAutoTxRateSwitch; - UCHAR MinTxRate; // RATE_1, RATE_2, RATE_5_5, RATE_11 - UCHAR RtsRate; // RATE_xxx - HTTRANSMIT_SETTING MlmeTransmit; // MGMT frame PHY rate setting when operatin at Ht rate. - UCHAR MlmeRate; // RATE_xxx, used to send MLME frames - UCHAR BasicMlmeRate; // Default Rate for sending MLME frames - - USHORT RtsThreshold; // in unit of BYTE - USHORT FragmentThreshold; // in unit of BYTE - - UCHAR TxPower; // in unit of mW - ULONG TxPowerPercentage; // 0~100 % - ULONG TxPowerDefault; // keep for TxPowerPercentage - -#ifdef DOT11_N_SUPPORT - BACAP_STRUC BACapability; // NO USE = 0XFF ; IMMED_BA =1 ; DELAY_BA=0 - BACAP_STRUC REGBACapability; // NO USE = 0XFF ; IMMED_BA =1 ; DELAY_BA=0 -#endif // DOT11_N_SUPPORT // - IOT_STRUC IOTestParm; // 802.11n InterOpbility Test Parameter; - ULONG TxPreamble; // Rt802_11PreambleLong, Rt802_11PreambleShort, Rt802_11PreambleAuto - BOOLEAN bUseZeroToDisableFragment; // Microsoft use 0 as disable - ULONG UseBGProtection; // 0: auto, 1: always use, 2: always not use - BOOLEAN bUseShortSlotTime; // 0: disable, 1 - use short slot (9us) - BOOLEAN bEnableTxBurst; // 1: enble TX PACKET BURST, 0: disable TX PACKET BURST - BOOLEAN bAggregationCapable; // 1: enable TX aggregation when the peer supports it - BOOLEAN bPiggyBackCapable; // 1: enable TX piggy-back according MAC's version - BOOLEAN bIEEE80211H; // 1: enable IEEE802.11h spec. - ULONG DisableOLBCDetect; // 0: enable OLBC detect; 1 disable OLBC detect - -#ifdef DOT11_N_SUPPORT - BOOLEAN bRdg; -#endif // DOT11_N_SUPPORT // - BOOLEAN bWmmCapable; // 0:disable WMM, 1:enable WMM - QOS_CAPABILITY_PARM APQosCapability; // QOS capability of the current associated AP - EDCA_PARM APEdcaParm; // EDCA parameters of the current associated AP - QBSS_LOAD_PARM APQbssLoad; // QBSS load of the current associated AP - UCHAR AckPolicy[4]; // ACK policy of the specified AC. see ACK_xxx -#ifdef CONFIG_STA_SUPPORT - BOOLEAN bDLSCapable; // 0:disable DLS, 1:enable DLS -#endif // CONFIG_STA_SUPPORT // - // a bitmap of BOOLEAN flags. each bit represent an operation status of a particular - // BOOLEAN control, either ON or OFF. These flags should always be accessed via - // OPSTATUS_TEST_FLAG(), OPSTATUS_SET_FLAG(), OP_STATUS_CLEAR_FLAG() macros. - // see fOP_STATUS_xxx in RTMP_DEF.C for detail bit definition - ULONG OpStatusFlags; - - BOOLEAN NdisRadioStateOff; //For HCT 12.0, set this flag to TRUE instead of called MlmeRadioOff. - ABGBAND_STATE BandState; // For setting BBP used on B/G or A mode. - - // IEEE802.11H--DFS. - RADAR_DETECT_STRUCT RadarDetect; - -#ifdef CARRIER_DETECTION_SUPPORT - CARRIER_DETECTION CarrierDetect; -#endif // CARRIER_DETECTION_SUPPORT // - -#ifdef DOT11_N_SUPPORT - // HT - UCHAR BASize; // USer desired BAWindowSize. Should not exceed our max capability - //RT_HT_CAPABILITY SupportedHtPhy; - RT_HT_CAPABILITY DesiredHtPhy; - HT_CAPABILITY_IE HtCapability; - ADD_HT_INFO_IE AddHTInfo; // Useful as AP. - //This IE is used with channel switch announcement element when changing to a new 40MHz. - //This IE is included in channel switch ammouncement frames 7.4.1.5, beacons, probe Rsp. - NEW_EXT_CHAN_IE NewExtChanOffset; //7.3.2.20A, 1 if extension channel is above the control channel, 3 if below, 0 if not present - -#ifdef DOT11N_DRAFT3 - UCHAR Bss2040CoexistFlag; // bit 0: bBssCoexistTimerRunning, bit 1: NeedSyncAddHtInfo. - RALINK_TIMER_STRUCT Bss2040CoexistTimer; - - //This IE is used for 20/40 BSS Coexistence. - BSS_2040_COEXIST_IE BSS2040CoexistInfo; - // ====== 11n D3.0 =======================> - USHORT Dot11OBssScanPassiveDwell; // Unit : TU. 5~1000 - USHORT Dot11OBssScanActiveDwell; // Unit : TU. 10~1000 - USHORT Dot11BssWidthTriggerScanInt; // Unit : Second - USHORT Dot11OBssScanPassiveTotalPerChannel; // Unit : TU. 200~10000 - USHORT Dot11OBssScanActiveTotalPerChannel; // Unit : TU. 20~10000 - USHORT Dot11BssWidthChanTranDelayFactor; - USHORT Dot11OBssScanActivityThre; // Unit : percentage - - ULONG Dot11BssWidthChanTranDelay; // multiple of (Dot11BssWidthTriggerScanInt * Dot11BssWidthChanTranDelayFactor) - ULONG CountDownCtr; // CountDown Counter from (Dot11BssWidthTriggerScanInt * Dot11BssWidthChanTranDelayFactor) - - NDIS_SPIN_LOCK TriggerEventTabLock; - BSS_2040_COEXIST_IE LastBSSCoexist2040; - BSS_2040_COEXIST_IE BSSCoexist2040; - TRIGGER_EVENT_TAB TriggerEventTab; - UCHAR ChannelListIdx; - // <====== 11n D3.0 ======================= - BOOLEAN bOverlapScanning; -#endif // DOT11N_DRAFT3 // - - BOOLEAN bHTProtect; - BOOLEAN bMIMOPSEnable; - BOOLEAN bBADecline; - BOOLEAN bDisableReordering; - BOOLEAN bForty_Mhz_Intolerant; - BOOLEAN bExtChannelSwitchAnnouncement; - BOOLEAN bRcvBSSWidthTriggerEvents; - ULONG LastRcvBSSWidthTriggerEventsTime; - - UCHAR TxBASize; -#endif // DOT11_N_SUPPORT // - - // Enable wireless event - BOOLEAN bWirelessEvent; - BOOLEAN bWiFiTest; // Enable this parameter for WiFi test - - // Tx & Rx Stream number selection - UCHAR TxStream; - UCHAR RxStream; - - // transmit phy mode, trasmit rate for Multicast. -#ifdef MCAST_RATE_SPECIFIC - UCHAR McastTransmitMcs; - UCHAR McastTransmitPhyMode; -#endif // MCAST_RATE_SPECIFIC // - - BOOLEAN bHardwareRadio; // Hardware controlled Radio enabled - -#ifdef RT2870 - BOOLEAN bMultipleIRP; // Multiple Bulk IN flag - UCHAR NumOfBulkInIRP; // if bMultipleIRP == TRUE, NumOfBulkInIRP will be 4 otherwise be 1 - RT_HT_CAPABILITY SupportedHtPhy; - ULONG MaxPktOneTxBulk; - UCHAR TxBulkFactor; - UCHAR RxBulkFactor; - - BEACON_SYNC_STRUCT *pBeaconSync; - RALINK_TIMER_STRUCT BeaconUpdateTimer; - UINT32 BeaconAdjust; - UINT32 BeaconFactor; - UINT32 BeaconRemain; -#endif // RT2870 // - - - NDIS_SPIN_LOCK MeasureReqTabLock; - PMEASURE_REQ_TAB pMeasureReqTab; - - NDIS_SPIN_LOCK TpcReqTabLock; - PTPC_REQ_TAB pTpcReqTab; - - // transmit phy mode, trasmit rate for Multicast. -#ifdef MCAST_RATE_SPECIFIC - HTTRANSMIT_SETTING MCastPhyMode; -#endif // MCAST_RATE_SPECIFIC // - -#ifdef SINGLE_SKU - UINT16 DefineMaxTxPwr; -#endif // SINGLE_SKU // - - -} COMMON_CONFIG, *PCOMMON_CONFIG; - - -#ifdef CONFIG_STA_SUPPORT -/* Modified by Wu Xi-Kun 4/21/2006 */ -// STA configuration and status -typedef struct _STA_ADMIN_CONFIG { - // GROUP 1 - - // User configuration loaded from Registry, E2PROM or OID_xxx. These settings describe - // the user intended configuration, but not necessary fully equal to the final - // settings in ACTIVE BSS after negotiation/compromize with the BSS holder (either - // AP or IBSS holder). - // Once initialized, user configuration can only be changed via OID_xxx - UCHAR BssType; // BSS_INFRA or BSS_ADHOC - USHORT AtimWin; // used when starting a new IBSS - - // GROUP 2 - - // User configuration loaded from Registry, E2PROM or OID_xxx. These settings describe - // the user intended configuration, and should be always applied to the final - // settings in ACTIVE BSS without compromising with the BSS holder. - // Once initialized, user configuration can only be changed via OID_xxx - UCHAR RssiTrigger; - UCHAR RssiTriggerMode; // RSSI_TRIGGERED_UPON_BELOW_THRESHOLD or RSSI_TRIGGERED_UPON_EXCCEED_THRESHOLD - USHORT DefaultListenCount; // default listen count; - ULONG WindowsPowerMode; // Power mode for AC power - ULONG WindowsBatteryPowerMode; // Power mode for battery if exists - BOOLEAN bWindowsACCAMEnable; // Enable CAM power mode when AC on - BOOLEAN bAutoReconnect; // Set to TRUE when setting OID_802_11_SSID with no matching BSSID - ULONG WindowsPowerProfile; // Windows power profile, for NDIS5.1 PnP - - // MIB:ieee802dot11.dot11smt(1).dot11StationConfigTable(1) - USHORT Psm; // power management mode (PWR_ACTIVE|PWR_SAVE) - USHORT DisassocReason; - UCHAR DisassocSta[MAC_ADDR_LEN]; - USHORT DeauthReason; - UCHAR DeauthSta[MAC_ADDR_LEN]; - USHORT AuthFailReason; - UCHAR AuthFailSta[MAC_ADDR_LEN]; - - NDIS_802_11_PRIVACY_FILTER PrivacyFilter; // PrivacyFilter enum for 802.1X - NDIS_802_11_AUTHENTICATION_MODE AuthMode; // This should match to whatever microsoft defined - NDIS_802_11_WEP_STATUS WepStatus; - NDIS_802_11_WEP_STATUS OrigWepStatus; // Original wep status set from OID - - // Add to support different cipher suite for WPA2/WPA mode - NDIS_802_11_ENCRYPTION_STATUS GroupCipher; // Multicast cipher suite - NDIS_802_11_ENCRYPTION_STATUS PairCipher; // Unicast cipher suite - BOOLEAN bMixCipher; // Indicate current Pair & Group use different cipher suites - USHORT RsnCapability; - - NDIS_802_11_WEP_STATUS GroupKeyWepStatus; - - UCHAR PMK[32]; // WPA PSK mode PMK - UCHAR PTK[64]; // WPA PSK mode PTK - UCHAR GTK[32]; // GTK from authenticator - BSSID_INFO SavedPMK[PMKID_NO]; - UINT SavedPMKNum; // Saved PMKID number - - UCHAR DefaultKeyId; - - - // WPA 802.1x port control, WPA_802_1X_PORT_SECURED, WPA_802_1X_PORT_NOT_SECURED - UCHAR PortSecured; - - // For WPA countermeasures - ULONG LastMicErrorTime; // record last MIC error time - ULONG MicErrCnt; // Should be 0, 1, 2, then reset to zero (after disassoiciation). - BOOLEAN bBlockAssoc; // Block associate attempt for 60 seconds after counter measure occurred. - // For WPA-PSK supplicant state - WPA_STATE WpaState; // Default is SS_NOTUSE and handled by microsoft 802.1x - UCHAR ReplayCounter[8]; - UCHAR ANonce[32]; // ANonce for WPA-PSK from aurhenticator - UCHAR SNonce[32]; // SNonce for WPA-PSK - - UCHAR LastSNR0; // last received BEACON's SNR - UCHAR LastSNR1; // last received BEACON's SNR for 2nd antenna - RSSI_SAMPLE RssiSample; - ULONG NumOfAvgRssiSample; - - ULONG LastBeaconRxTime; // OS's timestamp of the last BEACON RX time - ULONG Last11bBeaconRxTime; // OS's timestamp of the last 11B BEACON RX time - ULONG Last11gBeaconRxTime; // OS's timestamp of the last 11G BEACON RX time - ULONG Last20NBeaconRxTime; // OS's timestamp of the last 20MHz N BEACON RX time - - ULONG LastScanTime; // Record last scan time for issue BSSID_SCAN_LIST - ULONG ScanCnt; // Scan counts since most recent SSID, BSSID, SCAN OID request - BOOLEAN bSwRadio; // Software controlled Radio On/Off, TRUE: On - BOOLEAN bHwRadio; // Hardware controlled Radio On/Off, TRUE: On - BOOLEAN bRadio; // Radio state, And of Sw & Hw radio state - BOOLEAN bHardwareRadio; // Hardware controlled Radio enabled - BOOLEAN bShowHiddenSSID; // Show all known SSID in SSID list get operation - - - // New for WPA, windows want us to to keep association information and - // Fixed IEs from last association response - NDIS_802_11_ASSOCIATION_INFORMATION AssocInfo; - USHORT ReqVarIELen; // Length of next VIE include EID & Length - UCHAR ReqVarIEs[MAX_VIE_LEN]; // The content saved here should be little-endian format. - USHORT ResVarIELen; // Length of next VIE include EID & Length - UCHAR ResVarIEs[MAX_VIE_LEN]; - - UCHAR RSNIE_Len; - UCHAR RSN_IE[MAX_LEN_OF_RSNIE]; // The content saved here should be little-endian format. - - // New variables used for CCX 1.0 - BOOLEAN bCkipOn; - BOOLEAN bCkipCmicOn; - UCHAR CkipFlag; - UCHAR GIV[3]; //for CCX iv - UCHAR RxSEQ[4]; - UCHAR TxSEQ[4]; - UCHAR CKIPMIC[4]; - UCHAR LeapAuthMode; - LEAP_AUTH_INFO LeapAuthInfo; - UCHAR HashPwd[16]; - UCHAR NetworkChallenge[8]; - UCHAR NetworkChallengeResponse[24]; - UCHAR PeerChallenge[8]; - - UCHAR PeerChallengeResponse[24]; - UCHAR SessionKey[16]; //Network session keys (NSK) - RALINK_TIMER_STRUCT LeapAuthTimer; - ROGUEAP_TABLE RogueApTab; //Cisco CCX1 Rogue AP Detection - - // New control flags for CCX - CCX_CONTROL CCXControl; // Master administration state - BOOLEAN CCXEnable; // Actual CCX state - UCHAR CCXScanChannel; // Selected channel for CCX beacon request - USHORT CCXScanTime; // Time out to wait for beacon and probe response - UCHAR CCXReqType; // Current processing CCX request type - BSS_TABLE CCXBssTab; // BSS Table - UCHAR FrameReportBuf[2048]; // Buffer for creating frame report - USHORT FrameReportLen; // Current Frame report length - ULONG CLBusyBytes; // Save the total bytes received durning channel load scan time - USHORT RPIDensity[8]; // Array for RPI density collection - // Start address of each BSS table within FrameReportBuf - // It's important to update the RxPower of the corresponding Bss - USHORT BssReportOffset[MAX_LEN_OF_BSS_TABLE]; - USHORT BeaconToken; // Token for beacon report - ULONG LastBssIndex; // Most current reported Bss index - RM_REQUEST_ACTION MeasurementRequest[16]; // Saved measurement request - UCHAR RMReqCnt; // Number of measurement request saved. - UCHAR CurrentRMReqIdx; // Number of measurement request saved. - BOOLEAN ParallelReq; // Parallel measurement, only one request performed, - // It must be the same channel with maximum duration - USHORT ParallelDuration; // Maximum duration for parallel measurement - UCHAR ParallelChannel; // Only one channel with parallel measurement - USHORT IAPPToken; // IAPP dialog token - UCHAR CCXQosECWMin; // Cisco QOS ECWMin for AC 0 - UCHAR CCXQosECWMax; // Cisco QOS ECWMax for AC 0 - // Hack for channel load and noise histogram parameters - UCHAR NHFactor; // Parameter for Noise histogram - UCHAR CLFactor; // Parameter for channel load - - UCHAR KRK[16]; //Key Refresh Key. - UCHAR BTK[32]; //Base Transient Key - BOOLEAN CCKMLinkUpFlag; - ULONG CCKMRN; //(Re)Association request number. - LARGE_INTEGER CCKMBeaconAtJoinTimeStamp; //TSF timer for Re-assocaite to the new AP - UCHAR AironetCellPowerLimit; //in dBm - UCHAR AironetIPAddress[4]; //eg. 192.168.1.1 - BOOLEAN CCXAdjacentAPReportFlag; //flag for determining report Assoc Lost time - CHAR CCXAdjacentAPSsid[MAX_LEN_OF_SSID]; //Adjacent AP's SSID report - UCHAR CCXAdjacentAPSsidLen; // the actual ssid length in used - UCHAR CCXAdjacentAPBssid[MAC_ADDR_LEN]; //Adjacent AP's BSSID report - USHORT CCXAdjacentAPChannel; - ULONG CCXAdjacentAPLinkDownTime; //for Spec S32. - - RALINK_TIMER_STRUCT StaQuickResponeForRateUpTimer; - BOOLEAN StaQuickResponeForRateUpTimerRunning; - - UCHAR DtimCount; // 0.. DtimPeriod-1 - UCHAR DtimPeriod; // default = 3 - -#ifdef QOS_DLS_SUPPORT - RT_802_11_DLS DLSEntry[MAX_NUM_OF_DLS_ENTRY]; - UCHAR DlsReplayCounter[8]; -#endif // QOS_DLS_SUPPORT // - //////////////////////////////////////////////////////////////////////////////////////// - // This is only for WHQL test. - BOOLEAN WhqlTest; - //////////////////////////////////////////////////////////////////////////////////////// - - RALINK_TIMER_STRUCT WpaDisassocAndBlockAssocTimer; - // Fast Roaming - BOOLEAN bFastRoaming; // 0:disable fast roaming, 1:enable fast roaming - CHAR dBmToRoam; // the condition to roam when receiving Rssi less than this value. It's negative value. - -#ifdef WPA_SUPPLICANT_SUPPORT - BOOLEAN IEEE8021X; - BOOLEAN IEEE8021x_required_keys; - CIPHER_KEY DesireSharedKey[4]; // Record user desired WEP keys - UCHAR DesireSharedKeyId; - - // 0: driver ignores wpa_supplicant - // 1: wpa_supplicant initiates scanning and AP selection - // 2: driver takes care of scanning, AP selection, and IEEE 802.11 association parameters - UCHAR WpaSupplicantUP; - UCHAR WpaSupplicantScanCount; -#endif // WPA_SUPPLICANT_SUPPORT // - - CHAR dev_name[16]; - USHORT OriDevType; - - BOOLEAN bTGnWifiTest; - BOOLEAN bScanReqIsFromWebUI; - - HTTRANSMIT_SETTING HTPhyMode, MaxHTPhyMode, MinHTPhyMode;// For transmit phy setting in TXWI. - DESIRED_TRANSMIT_SETTING DesiredTransmitSetting; - RT_HT_PHY_INFO DesiredHtPhyInfo; - BOOLEAN bAutoTxRateSwitch; - - -#ifdef EXT_BUILD_CHANNEL_LIST - UCHAR IEEE80211dClientMode; - UCHAR StaOriCountryCode[3]; - UCHAR StaOriGeography; -#endif // EXT_BUILD_CHANNEL_LIST // -} STA_ADMIN_CONFIG, *PSTA_ADMIN_CONFIG; - -// This data structure keep the current active BSS/IBSS's configuration that this STA -// had agreed upon joining the network. Which means these parameters are usually decided -// by the BSS/IBSS creator instead of user configuration. Data in this data structurre -// is valid only when either ADHOC_ON(pAd) or INFRA_ON(pAd) is TRUE. -// Normally, after SCAN or failed roaming attempts, we need to recover back to -// the current active settings. -typedef struct _STA_ACTIVE_CONFIG { - USHORT Aid; - USHORT AtimWin; // in kusec; IBSS parameter set element - USHORT CapabilityInfo; - USHORT CfpMaxDuration; - USHORT CfpPeriod; - - // Copy supported rate from desired AP's beacon. We are trying to match - // AP's supported and extended rate settings. - UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES]; - UCHAR ExtRate[MAX_LEN_OF_SUPPORTED_RATES]; - UCHAR SupRateLen; - UCHAR ExtRateLen; - // Copy supported ht from desired AP's beacon. We are trying to match - RT_HT_PHY_INFO SupportedPhyInfo; - RT_HT_CAPABILITY SupportedHtPhy; -} STA_ACTIVE_CONFIG, *PSTA_ACTIVE_CONFIG; - -#ifdef RT2870 -// for USB interface, avoid in interrupt when write key -typedef struct RT_ADD_PAIRWISE_KEY_ENTRY { - NDIS_802_11_MAC_ADDRESS MacAddr; - USHORT MacTabMatchWCID; // ASIC - CIPHER_KEY CipherKey; -} RT_ADD_PAIRWISE_KEY_ENTRY,*PRT_ADD_PAIRWISE_KEY_ENTRY; -#endif // RT2870 // -#endif // CONFIG_STA_SUPPORT // - -// ----------- start of AP -------------------------- -// AUTH-RSP State Machine Aux data structure -typedef struct _AP_MLME_AUX { - UCHAR Addr[MAC_ADDR_LEN]; - USHORT Alg; - CHAR Challenge[CIPHER_TEXT_LEN]; -} AP_MLME_AUX, *PAP_MLME_AUX; - -// structure to define WPA Group Key Rekey Interval -typedef struct PACKED _RT_802_11_WPA_REKEY { - ULONG ReKeyMethod; // mechanism for rekeying: 0:disable, 1: time-based, 2: packet-based - ULONG ReKeyInterval; // time-based: seconds, packet-based: kilo-packets -} RT_WPA_REKEY,*PRT_WPA_REKEY, RT_802_11_WPA_REKEY, *PRT_802_11_WPA_REKEY; - -typedef struct _MAC_TABLE_ENTRY { - //Choose 1 from ValidAsWDS and ValidAsCLI to validize. - BOOLEAN ValidAsCLI; // Sta mode, set this TRUE after Linkup,too. - BOOLEAN ValidAsWDS; // This is WDS Entry. only for AP mode. - BOOLEAN ValidAsApCli; //This is a AP-Client entry, only for AP mode which enable AP-Client functions. - BOOLEAN ValidAsMesh; - BOOLEAN ValidAsDls; // This is DLS Entry. only for STA mode. - BOOLEAN isCached; - BOOLEAN bIAmBadAtheros; // Flag if this is Atheros chip that has IOT problem. We need to turn on RTS/CTS protection. - - UCHAR EnqueueEapolStartTimerRunning; // Enqueue EAPoL-Start for triggering EAP SM - //jan for wpa - // record which entry revoke MIC Failure , if it leaves the BSS itself, AP won't update aMICFailTime MIB - UCHAR CMTimerRunning; - UCHAR apidx; // MBSS number - UCHAR RSNIE_Len; - UCHAR RSN_IE[MAX_LEN_OF_RSNIE]; - UCHAR ANonce[LEN_KEY_DESC_NONCE]; - UCHAR R_Counter[LEN_KEY_DESC_REPLAY]; - UCHAR PTK[64]; - UCHAR ReTryCounter; - RALINK_TIMER_STRUCT RetryTimer; - RALINK_TIMER_STRUCT EnqueueStartForPSKTimer; // A timer which enqueue EAPoL-Start for triggering PSK SM - NDIS_802_11_AUTHENTICATION_MODE AuthMode; // This should match to whatever microsoft defined - NDIS_802_11_WEP_STATUS WepStatus; - AP_WPA_STATE WpaState; - GTK_STATE GTKState; - USHORT PortSecured; - NDIS_802_11_PRIVACY_FILTER PrivacyFilter; // PrivacyFilter enum for 802.1X - CIPHER_KEY PairwiseKey; - PVOID pAd; - INT PMKID_CacheIdx; - UCHAR PMKID[LEN_PMKID]; - - - UCHAR Addr[MAC_ADDR_LEN]; - UCHAR PsMode; - SST Sst; - AUTH_STATE AuthState; // for SHARED KEY authentication state machine used only - BOOLEAN IsReassocSta; // Indicate whether this is a reassociation procedure - USHORT Aid; - USHORT CapabilityInfo; - UCHAR LastRssi; - ULONG NoDataIdleCount; - UINT16 StationKeepAliveCount; // unit: second - ULONG PsQIdleCount; - QUEUE_HEADER PsQueue; - - UINT32 StaConnectTime; // the live time of this station since associated with AP - - -#ifdef DOT11_N_SUPPORT - BOOLEAN bSendBAR; - USHORT NoBADataCountDown; - - UINT32 CachedBuf[16]; // UINT (4 bytes) for alignment - UINT TxBFCount; // 3*3 -#endif // DOT11_N_SUPPORT // - UINT FIFOCount; - UINT DebugFIFOCount; - UINT DebugTxCount; - BOOLEAN bDlsInit; - - -//==================================================== -//WDS entry needs these -// rt2860 add this. if ValidAsWDS==TRUE, MatchWDSTabIdx is the index in WdsTab.MacTab - UINT MatchWDSTabIdx; - UCHAR MaxSupportedRate; - UCHAR CurrTxRate; - UCHAR CurrTxRateIndex; - // to record the each TX rate's quality. 0 is best, the bigger the worse. - USHORT TxQuality[MAX_STEP_OF_TX_RATE_SWITCH]; -// USHORT OneSecTxOkCount; - UINT32 OneSecTxNoRetryOkCount; - UINT32 OneSecTxRetryOkCount; - UINT32 OneSecTxFailCount; - UINT32 ContinueTxFailCnt; - UINT32 CurrTxRateStableTime; // # of second in current TX rate - UCHAR TxRateUpPenalty; // extra # of second penalty due to last unstable condition -//==================================================== - - - -#ifdef CONFIG_STA_SUPPORT -#ifdef QOS_DLS_SUPPORT - UINT MatchDlsEntryIdx; // indicate the index in pAd->StaCfg.DLSEntry -#endif // QOS_DLS_SUPPORT // -#endif // CONFIG_STA_SUPPORT // - - BOOLEAN fNoisyEnvironment; - BOOLEAN fLastSecAccordingRSSI; - UCHAR LastSecTxRateChangeAction; // 0: no change, 1:rate UP, 2:rate down - CHAR LastTimeTxRateChangeAction; //Keep last time value of LastSecTxRateChangeAction - ULONG LastTxOkCount; - UCHAR PER[MAX_STEP_OF_TX_RATE_SWITCH]; - - // a bitmap of BOOLEAN flags. each bit represent an operation status of a particular - // BOOLEAN control, either ON or OFF. These flags should always be accessed via - // CLIENT_STATUS_TEST_FLAG(), CLIENT_STATUS_SET_FLAG(), CLIENT_STATUS_CLEAR_FLAG() macros. - // see fOP_STATUS_xxx in RTMP_DEF.C for detail bit definition. fCLIENT_STATUS_AMSDU_INUSED - ULONG ClientStatusFlags; - - // TODO: Shall we move that to DOT11_N_SUPPORT??? - HTTRANSMIT_SETTING HTPhyMode, MaxHTPhyMode, MinHTPhyMode;// For transmit phy setting in TXWI. - -#ifdef DOT11_N_SUPPORT - // HT EWC MIMO-N used parameters - USHORT RXBAbitmap; // fill to on-chip RXWI_BA_BITMASK in 8.1.3RX attribute entry format - USHORT TXBAbitmap; // This bitmap as originator, only keep in software used to mark AMPDU bit in TXWI - USHORT TXAutoBAbitmap; - USHORT BADeclineBitmap; - USHORT BARecWcidArray[NUM_OF_TID]; // The mapping wcid of recipient session. if RXBAbitmap bit is masked - USHORT BAOriWcidArray[NUM_OF_TID]; // The mapping wcid of originator session. if TXBAbitmap bit is masked - USHORT BAOriSequence[NUM_OF_TID]; // The mapping wcid of originator session. if TXBAbitmap bit is masked - - // 802.11n features. - UCHAR MpduDensity; - UCHAR MaxRAmpduFactor; - UCHAR AMsduSize; - UCHAR MmpsMode; // MIMO power save more. - - HT_CAPABILITY_IE HTCapability; - -#ifdef DOT11N_DRAFT3 - UCHAR BSS2040CoexistenceMgmtSupport; -#endif // DOT11N_DRAFT3 // -#endif // DOT11_N_SUPPORT // - - BOOLEAN bAutoTxRateSwitch; - - UCHAR RateLen; - struct _MAC_TABLE_ENTRY *pNext; - USHORT TxSeq[NUM_OF_TID]; - USHORT NonQosDataSeq; - - RSSI_SAMPLE RssiSample; - - UINT32 TXMCSExpected[16]; - UINT32 TXMCSSuccessful[16]; - UINT32 TXMCSFailed[16]; - UINT32 TXMCSAutoFallBack[16][16]; - -#ifdef CONFIG_STA_SUPPORT - ULONG LastBeaconRxTime; -#endif // CONFIG_STA_SUPPORT // -} MAC_TABLE_ENTRY, *PMAC_TABLE_ENTRY; - -typedef struct _MAC_TABLE { - USHORT Size; - MAC_TABLE_ENTRY *Hash[HASH_TABLE_SIZE]; - MAC_TABLE_ENTRY Content[MAX_LEN_OF_MAC_TABLE]; - QUEUE_HEADER McastPsQueue; - ULONG PsQIdleCount; - BOOLEAN fAnyStationInPsm; - BOOLEAN fAnyStationBadAtheros; // Check if any Station is atheros 802.11n Chip. We need to use RTS/CTS with Atheros 802,.11n chip. - BOOLEAN fAnyTxOPForceDisable; // Check if it is necessary to disable BE TxOP - BOOLEAN fAllStationAsRalink; // Check if all stations are ralink-chipset -#ifdef DOT11_N_SUPPORT - BOOLEAN fAnyStationIsLegacy; // Check if I use legacy rate to transmit to my BSS Station/ - BOOLEAN fAnyStationNonGF; // Check if any Station can't support GF. - BOOLEAN fAnyStation20Only; // Check if any Station can't support GF. - BOOLEAN fAnyStationMIMOPSDynamic; // Check if any Station is MIMO Dynamic - BOOLEAN fAnyBASession; // Check if there is BA session. Force turn on RTS/CTS -#endif // DOT11_N_SUPPORT // -} MAC_TABLE, *PMAC_TABLE; - -#ifdef DOT11_N_SUPPORT -#define IS_HT_STA(_pMacEntry) \ - (_pMacEntry->MaxHTPhyMode.field.MODE >= MODE_HTMIX) - -#define IS_HT_RATE(_pMacEntry) \ - (_pMacEntry->HTPhyMode.field.MODE >= MODE_HTMIX) - -#define PEER_IS_HT_RATE(_pMacEntry) \ - (_pMacEntry->HTPhyMode.field.MODE >= MODE_HTMIX) -#endif // DOT11_N_SUPPORT // - -typedef struct _WDS_ENTRY { - BOOLEAN Valid; - UCHAR Addr[MAC_ADDR_LEN]; - ULONG NoDataIdleCount; - struct _WDS_ENTRY *pNext; -} WDS_ENTRY, *PWDS_ENTRY; - -typedef struct _WDS_TABLE_ENTRY { - USHORT Size; - UCHAR WdsAddr[MAC_ADDR_LEN]; - WDS_ENTRY *Hash[HASH_TABLE_SIZE]; - WDS_ENTRY Content[MAX_LEN_OF_MAC_TABLE]; - UCHAR MaxSupportedRate; - UCHAR CurrTxRate; - USHORT TxQuality[MAX_LEN_OF_SUPPORTED_RATES]; - USHORT OneSecTxOkCount; - USHORT OneSecTxRetryOkCount; - USHORT OneSecTxFailCount; - ULONG CurrTxRateStableTime; // # of second in current TX rate - UCHAR TxRateUpPenalty; // extra # of second penalty due to last unstable condition -} WDS_TABLE_ENTRY, *PWDS_TABLE_ENTRY; - -typedef struct _RT_802_11_WDS_ENTRY { - PNET_DEV dev; - UCHAR Valid; - UCHAR PhyMode; - UCHAR PeerWdsAddr[MAC_ADDR_LEN]; - UCHAR MacTabMatchWCID; // ASIC - NDIS_802_11_WEP_STATUS WepStatus; - UCHAR KeyIdx; - CIPHER_KEY WdsKey; - HTTRANSMIT_SETTING HTPhyMode, MaxHTPhyMode, MinHTPhyMode; - RT_HT_PHY_INFO DesiredHtPhyInfo; - BOOLEAN bAutoTxRateSwitch; - DESIRED_TRANSMIT_SETTING DesiredTransmitSetting; // Desired transmit setting. -} RT_802_11_WDS_ENTRY, *PRT_802_11_WDS_ENTRY; - -typedef struct _WDS_TABLE { - UCHAR Mode; - ULONG Size; - RT_802_11_WDS_ENTRY WdsEntry[MAX_WDS_ENTRY]; -} WDS_TABLE, *PWDS_TABLE; - -typedef struct _APCLI_STRUCT { - PNET_DEV dev; -#ifdef RTL865X_SOC - unsigned int mylinkid; -#endif - BOOLEAN Enable; // Set it as 1 if the apcli interface was configured to "1" or by iwpriv cmd "ApCliEnable" - BOOLEAN Valid; // Set it as 1 if the apcli interface associated success to remote AP. - UCHAR MacTabWCID; //WCID value, which point to the entry of ASIC Mac table. - UCHAR SsidLen; - CHAR Ssid[MAX_LEN_OF_SSID]; - - UCHAR CfgSsidLen; - CHAR CfgSsid[MAX_LEN_OF_SSID]; - UCHAR CfgApCliBssid[ETH_LENGTH_OF_ADDRESS]; - UCHAR CurrentAddress[ETH_LENGTH_OF_ADDRESS]; - - ULONG ApCliRcvBeaconTime; - - ULONG CtrlCurrState; - ULONG SyncCurrState; - ULONG AuthCurrState; - ULONG AssocCurrState; - ULONG WpaPskCurrState; - - USHORT AuthReqCnt; - USHORT AssocReqCnt; - - ULONG ClientStatusFlags; - UCHAR MpduDensity; - - NDIS_802_11_AUTHENTICATION_MODE AuthMode; // This should match to whatever microsoft defined - NDIS_802_11_WEP_STATUS WepStatus; - - // Add to support different cipher suite for WPA2/WPA mode - NDIS_802_11_ENCRYPTION_STATUS GroupCipher; // Multicast cipher suite - NDIS_802_11_ENCRYPTION_STATUS PairCipher; // Unicast cipher suite - BOOLEAN bMixCipher; // Indicate current Pair & Group use different cipher suites - USHORT RsnCapability; - - UCHAR PSK[100]; // reserve PSK key material - UCHAR PSKLen; - UCHAR PMK[32]; // WPA PSK mode PMK - //UCHAR PTK[64]; // WPA PSK mode PTK - UCHAR GTK[32]; // GTK from authenticator - - //CIPHER_KEY PairwiseKey; - CIPHER_KEY SharedKey[SHARE_KEY_NUM]; - UCHAR DefaultKeyId; - - // WPA 802.1x port control, WPA_802_1X_PORT_SECURED, WPA_802_1X_PORT_NOT_SECURED - //UCHAR PortSecured; - - // store RSN_IE built by driver - UCHAR RSN_IE[MAX_LEN_OF_RSNIE]; // The content saved here should be convert to little-endian format. - UCHAR RSNIE_Len; - - // For WPA countermeasures - ULONG LastMicErrorTime; // record last MIC error time - //ULONG MicErrCnt; // Should be 0, 1, 2, then reset to zero (after disassoiciation). - BOOLEAN bBlockAssoc; // Block associate attempt for 60 seconds after counter measure occurred. - - // For WPA-PSK supplicant state - //WPA_STATE WpaState; // Default is SS_NOTUSE - //UCHAR ReplayCounter[8]; - //UCHAR ANonce[32]; // ANonce for WPA-PSK from authenticator - UCHAR SNonce[32]; // SNonce for WPA-PSK - UCHAR GNonce[32]; // GNonce for WPA-PSK from authenticator - - HTTRANSMIT_SETTING HTPhyMode, MaxHTPhyMode, MinHTPhyMode; - RT_HT_PHY_INFO DesiredHtPhyInfo; - BOOLEAN bAutoTxRateSwitch; - DESIRED_TRANSMIT_SETTING DesiredTransmitSetting; // Desired transmit setting. -} APCLI_STRUCT, *PAPCLI_STRUCT; - -// ----------- end of AP ---------------------------- - -#ifdef BLOCK_NET_IF -typedef struct _BLOCK_QUEUE_ENTRY -{ - BOOLEAN SwTxQueueBlockFlag; - LIST_HEADER NetIfList; -} BLOCK_QUEUE_ENTRY, *PBLOCK_QUEUE_ENTRY; -#endif // BLOCK_NET_IF // - -struct wificonf -{ - BOOLEAN bShortGI; - BOOLEAN bGreenField; -}; - - - -typedef struct _INF_PCI_CONFIG -{ - PUCHAR CSRBaseAddress; // PCI MMIO Base Address, all access will use -}INF_PCI_CONFIG; - -typedef struct _INF_USB_CONFIG -{ - UINT BulkInEpAddr; // bulk-in endpoint address - UINT BulkOutEpAddr[6]; // bulk-out endpoint address - -}INF_USB_CONFIG; - -#ifdef IKANOS_VX_1X0 - typedef void (*IkanosWlanTxCbFuncP)(void *, void *); - - struct IKANOS_TX_INFO - { - struct net_device *netdev; - IkanosWlanTxCbFuncP *fp; - }; -#endif // IKANOS_VX_1X0 // - -#ifdef NINTENDO_AP -typedef struct _NINDO_CTRL_BLOCK { - - RT_NINTENDO_TABLE DS_TABLE; - -#ifdef CHIP25XX - spinlock_t NINTENDO_TABLE_Lock; -#else - NDIS_SPIN_LOCK NINTENDO_TABLE_Lock; -#endif // CHIP25XX // - - UCHAR NINTENDO_UP_BUFFER[512]; - UCHAR Local_KeyIdx; - CIPHER_KEY Local_SharedKey; - UCHAR Local_bHideSsid; - UCHAR Local_AuthMode; - UCHAR Local_WepStatus; - USHORT Local_CapabilityInfo; -} NINDO_CTRL_BLOCK; -#endif // NINTENDO_AP // - - -#ifdef DBG_DIAGNOSE -#define DIAGNOSE_TIME 10 // 10 sec -typedef struct _RtmpDiagStrcut_ -{ // Diagnosis Related element - unsigned char inited; - unsigned char qIdx; - unsigned char ArrayStartIdx; - unsigned char ArrayCurIdx; - // Tx Related Count - USHORT TxDataCnt[DIAGNOSE_TIME]; - USHORT TxFailCnt[DIAGNOSE_TIME]; -// USHORT TxDescCnt[DIAGNOSE_TIME][16]; // TxDesc queue length in scale of 0~14, >=15 - USHORT TxDescCnt[DIAGNOSE_TIME][24]; // 3*3 // TxDesc queue length in scale of 0~14, >=15 -// USHORT TxMcsCnt[DIAGNOSE_TIME][16]; // TxDate MCS Count in range from 0 to 15, step in 1. - USHORT TxMcsCnt[DIAGNOSE_TIME][24]; // 3*3 - USHORT TxSWQueCnt[DIAGNOSE_TIME][9]; // TxSwQueue length in scale of 0, 1, 2, 3, 4, 5, 6, 7, >=8 - - USHORT TxAggCnt[DIAGNOSE_TIME]; - USHORT TxNonAggCnt[DIAGNOSE_TIME]; -// USHORT TxAMPDUCnt[DIAGNOSE_TIME][16]; // 10 sec, TxDMA APMDU Aggregation count in range from 0 to 15, in setp of 1. - USHORT TxAMPDUCnt[DIAGNOSE_TIME][24]; // 3*3 // 10 sec, TxDMA APMDU Aggregation count in range from 0 to 15, in setp of 1. - USHORT TxRalinkCnt[DIAGNOSE_TIME]; // TxRalink Aggregation Count in 1 sec scale. - USHORT TxAMSDUCnt[DIAGNOSE_TIME]; // TxAMSUD Aggregation Count in 1 sec scale. - - // Rx Related Count - USHORT RxDataCnt[DIAGNOSE_TIME]; // Rx Total Data count. - USHORT RxCrcErrCnt[DIAGNOSE_TIME]; -// USHORT RxMcsCnt[DIAGNOSE_TIME][16]; // Rx MCS Count in range from 0 to 15, step in 1. - USHORT RxMcsCnt[DIAGNOSE_TIME][24]; // 3*3 -}RtmpDiagStruct; -#endif // DBG_DIAGNOSE // - - -// -// The miniport adapter structure -// -typedef struct _RTMP_ADAPTER -{ - PVOID OS_Cookie; // save specific structure relative to OS - PNET_DEV net_dev; - ULONG VirtualIfCnt; - - - - NDIS_SPIN_LOCK irq_lock; - UCHAR irq_disabled; - -#ifdef RT2870 -/*****************************************************************************************/ -/* USB related parameters */ -/*****************************************************************************************/ - struct usb_config_descriptor *config; - UINT BulkInEpAddr; // bulk-in endpoint address - UINT BulkOutEpAddr[6]; // bulk-out endpoint address - - UINT NumberOfPipes; - USHORT BulkOutMaxPacketSize; - USHORT BulkInMaxPacketSize; - - //======Control Flags - LONG PendingIoCount; - ULONG BulkFlags; - BOOLEAN bUsbTxBulkAggre; // Flags for bulk out data priority - - - //======Timer Thread - RT2870_TIMER_QUEUE TimerQ; - NDIS_SPIN_LOCK TimerQLock; - - - //======Cmd Thread - CmdQ CmdQ; - NDIS_SPIN_LOCK CmdQLock; // CmdQLock spinlock - - BOOLEAN TimerFunc_kill; - BOOLEAN mlme_kill; - - - //======Semaphores (event) - struct semaphore mlme_semaphore; /* to sleep thread on */ - struct semaphore RTUSBCmd_semaphore; /* to sleep thread on */ - struct semaphore RTUSBTimer_semaphore; -#ifdef INF_AMAZON_SE - struct semaphore UsbVendorReq_semaphore; - PVOID UsbVendorReqBuf; -#endif // INF_AMAZON_SE // - struct completion TimerQComplete; - struct completion mlmeComplete; - struct completion CmdQComplete; - wait_queue_head_t *wait; - - //======Lock for 2870 ATE -#ifdef RALINK_ATE - NDIS_SPIN_LOCK GenericLock; // ATE Tx/Rx generic spinlock -#endif // RALINK_ATE // - -#endif // RT2870 // - - -/*****************************************************************************************/ - /* Both PCI/USB related parameters */ -/*****************************************************************************************/ - - -/*****************************************************************************************/ -/* Tx related parameters */ -/*****************************************************************************************/ - BOOLEAN DeQueueRunning[NUM_OF_TX_RING]; // for ensuring RTUSBDeQueuePacket get call once - NDIS_SPIN_LOCK DeQueueLock[NUM_OF_TX_RING]; - -#ifdef RT2870 - // Data related context and AC specified, 4 AC supported - NDIS_SPIN_LOCK BulkOutLock[6]; // BulkOut spinlock for 4 ACs - NDIS_SPIN_LOCK MLMEBulkOutLock; // MLME BulkOut lock - - HT_TX_CONTEXT TxContext[NUM_OF_TX_RING]; - NDIS_SPIN_LOCK TxContextQueueLock[NUM_OF_TX_RING]; // TxContextQueue spinlock - - // 4 sets of Bulk Out index and pending flag - UCHAR NextBulkOutIndex[4]; // only used for 4 EDCA bulkout pipe - - BOOLEAN BulkOutPending[6]; // used for total 6 bulkout pipe - UCHAR bulkResetPipeid; - BOOLEAN MgmtBulkPending; - ULONG bulkResetReq[6]; -#endif // RT2870 // - - // resource for software backlog queues - QUEUE_HEADER TxSwQueue[NUM_OF_TX_RING]; // 4 AC + 1 HCCA - NDIS_SPIN_LOCK TxSwQueueLock[NUM_OF_TX_RING]; // TxSwQueue spinlock - - RTMP_DMABUF MgmtDescRing; // Shared memory for MGMT descriptors - RTMP_MGMT_RING MgmtRing; - NDIS_SPIN_LOCK MgmtRingLock; // Prio Ring spinlock - - -/*****************************************************************************************/ -/* Rx related parameters */ -/*****************************************************************************************/ - - -#ifdef RT2870 - RX_CONTEXT RxContext[RX_RING_SIZE]; // 1 for redundant multiple IRP bulk in. - NDIS_SPIN_LOCK BulkInLock; // BulkIn spinlock for 4 ACs - UCHAR PendingRx; // The Maxima pending Rx value should be RX_RING_SIZE. - UCHAR NextRxBulkInIndex; // Indicate the current RxContext Index which hold by Host controller. - UCHAR NextRxBulkInReadIndex; // Indicate the current RxContext Index which driver can read & process it. - ULONG NextRxBulkInPosition; // Want to contatenate 2 URB buffer while 1st is bulkin failed URB. This Position is 1st URB TransferLength. - ULONG TransferBufferLength; // current length of the packet buffer - ULONG ReadPosition; // current read position in a packet buffer -#endif // RT2870 // - - -/*****************************************************************************************/ -/* ASIC related parameters */ -/*****************************************************************************************/ - UINT32 MACVersion; // MAC version. Record rt2860C(0x28600100) or rt2860D (0x28600101).. - - // --------------------------- - // E2PROM - // --------------------------- - ULONG EepromVersion; // byte 0: version, byte 1: revision, byte 2~3: unused - UCHAR EEPROMAddressNum; // 93c46=6 93c66=8 - USHORT EEPROMDefaultValue[NUM_EEPROM_BBP_PARMS]; - ULONG FirmwareVersion; // byte 0: Minor version, byte 1: Major version, otherwise unused. - - // --------------------------- - // BBP Control - // --------------------------- - UCHAR BbpWriteLatch[140]; // record last BBP register value written via BBP_IO_WRITE/BBP_IO_WRITE_VY_REG_ID - UCHAR BbpRssiToDbmDelta; - BBP_R66_TUNING BbpTuning; - - // ---------------------------- - // RFIC control - // ---------------------------- - UCHAR RfIcType; // RFIC_xxx - ULONG RfFreqOffset; // Frequency offset for channel switching - RTMP_RF_REGS LatchRfRegs; // latch th latest RF programming value since RF IC doesn't support READ - - EEPROM_ANTENNA_STRUC Antenna; // Since ANtenna definition is different for a & g. We need to save it for future reference. - EEPROM_NIC_CONFIG2_STRUC NicConfig2; - - // This soft Rx Antenna Diversity mechanism is used only when user set - // RX Antenna = DIVERSITY ON - SOFT_RX_ANT_DIVERSITY RxAnt; - - UCHAR RFProgSeq; - CHANNEL_TX_POWER TxPower[MAX_NUM_OF_CHANNELS]; // Store Tx power value for all channels. - CHANNEL_TX_POWER ChannelList[MAX_NUM_OF_CHANNELS]; // list all supported channels for site survey - CHANNEL_11J_TX_POWER TxPower11J[MAX_NUM_OF_11JCHANNELS]; // 802.11j channel and bw - CHANNEL_11J_TX_POWER ChannelList11J[MAX_NUM_OF_11JCHANNELS]; // list all supported channels for site survey - - UCHAR ChannelListNum; // number of channel in ChannelList[] - UCHAR Bbp94; - BOOLEAN BbpForCCK; - ULONG Tx20MPwrCfgABand[5]; - ULONG Tx20MPwrCfgGBand[5]; - ULONG Tx40MPwrCfgABand[5]; - ULONG Tx40MPwrCfgGBand[5]; - - BOOLEAN bAutoTxAgcA; // Enable driver auto Tx Agc control - UCHAR TssiRefA; // Store Tssi reference value as 25 temperature. - UCHAR TssiPlusBoundaryA[5]; // Tssi boundary for increase Tx power to compensate. - UCHAR TssiMinusBoundaryA[5]; // Tssi boundary for decrease Tx power to compensate. - UCHAR TxAgcStepA; // Store Tx TSSI delta increment / decrement value - CHAR TxAgcCompensateA; // Store the compensation (TxAgcStep * (idx-1)) - - BOOLEAN bAutoTxAgcG; // Enable driver auto Tx Agc control - UCHAR TssiRefG; // Store Tssi reference value as 25 temperature. - UCHAR TssiPlusBoundaryG[5]; // Tssi boundary for increase Tx power to compensate. - UCHAR TssiMinusBoundaryG[5]; // Tssi boundary for decrease Tx power to compensate. - UCHAR TxAgcStepG; // Store Tx TSSI delta increment / decrement value - CHAR TxAgcCompensateG; // Store the compensation (TxAgcStep * (idx-1)) - - //+++For RT2870, the parameteres is start from BGRssiOffset1 ~ BGRssiOffset3 - CHAR BGRssiOffset0; // Store B/G RSSI#0 Offset value on EEPROM 0x46h - CHAR BGRssiOffset1; // Store B/G RSSI#1 Offset value - CHAR BGRssiOffset2; // Store B/G RSSI#2 Offset value - //--- - - //+++For RT2870, the parameteres is start from ARssiOffset1 ~ ARssiOffset3 - CHAR ARssiOffset0; // Store A RSSI#0 Offset value on EEPROM 0x4Ah - CHAR ARssiOffset1; // Store A RSSI#1 Offset value - CHAR ARssiOffset2; // Store A RSSI#2 Offset value - //--- - - CHAR BLNAGain; // Store B/G external LNA#0 value on EEPROM 0x44h - CHAR ALNAGain0; // Store A external LNA#0 value for ch36~64 - CHAR ALNAGain1; // Store A external LNA#1 value for ch100~128 - CHAR ALNAGain2; // Store A external LNA#2 value for ch132~165 - - // ---------------------------- - // LED control - // ---------------------------- - MCU_LEDCS_STRUC LedCntl; - USHORT Led1; // read from EEPROM 0x3c - USHORT Led2; // EEPROM 0x3e - USHORT Led3; // EEPROM 0x40 - UCHAR LedIndicatorStregth; - UCHAR RssiSingalstrengthOffet; - BOOLEAN bLedOnScanning; - UCHAR LedStatus; - -/*****************************************************************************************/ -/* 802.11 related parameters */ -/*****************************************************************************************/ - // outgoing BEACON frame buffer and corresponding TXD - TXWI_STRUC BeaconTxWI; - PUCHAR BeaconBuf; - USHORT BeaconOffset[HW_BEACON_MAX_COUNT]; - - // pre-build PS-POLL and NULL frame upon link up. for efficiency purpose. - PSPOLL_FRAME PsPollFrame; - HEADER_802_11 NullFrame; - -#ifdef RT2870 - TX_CONTEXT BeaconContext[BEACON_RING_SIZE]; - TX_CONTEXT NullContext; - TX_CONTEXT PsPollContext; - TX_CONTEXT RTSContext; -#endif // RT2870 // - - - -//=========AP=========== - - -//=======STA=========== -#ifdef CONFIG_STA_SUPPORT -/* Modified by Wu Xi-Kun 4/21/2006 */ - // ----------------------------------------------- - // STA specific configuration & operation status - // used only when pAd->OpMode == OPMODE_STA - // ----------------------------------------------- - STA_ADMIN_CONFIG StaCfg; // user desired settings - STA_ACTIVE_CONFIG StaActive; // valid only when ADHOC_ON(pAd) || INFRA_ON(pAd) - CHAR nickname[IW_ESSID_MAX_SIZE+1]; // nickname, only used in the iwconfig i/f - NDIS_MEDIA_STATE PreMediaState; -#endif // CONFIG_STA_SUPPORT // - -//=======Common=========== - // OP mode: either AP or STA - UCHAR OpMode; // OPMODE_STA, OPMODE_AP - - NDIS_MEDIA_STATE IndicateMediaState; // Base on Indication state, default is NdisMediaStateDisConnected - - - // configuration: read from Registry & E2PROM - BOOLEAN bLocalAdminMAC; // Use user changed MAC - UCHAR PermanentAddress[MAC_ADDR_LEN]; // Factory default MAC address - UCHAR CurrentAddress[MAC_ADDR_LEN]; // User changed MAC address - - // ------------------------------------------------------ - // common configuration to both OPMODE_STA and OPMODE_AP - // ------------------------------------------------------ - COMMON_CONFIG CommonCfg; - MLME_STRUCT Mlme; - - // AP needs those vaiables for site survey feature. - MLME_AUX MlmeAux; // temporary settings used during MLME state machine - BSS_TABLE ScanTab; // store the latest SCAN result - - //About MacTab, the sta driver will use #0 and #1 for multicast and AP. - MAC_TABLE MacTab; // ASIC on-chip WCID entry table. At TX, ASIC always use key according to this on-chip table. - NDIS_SPIN_LOCK MacTabLock; - -#ifdef DOT11_N_SUPPORT - BA_TABLE BATable; -#endif // DOT11_N_SUPPORT // - NDIS_SPIN_LOCK BATabLock; - RALINK_TIMER_STRUCT RECBATimer; - - // encryption/decryption KEY tables - CIPHER_KEY SharedKey[MAX_MBSSID_NUM][4]; // STA always use SharedKey[BSS0][0..3] - - // RX re-assembly buffer for fragmentation - FRAGMENT_FRAME FragFrame; // Frame storage for fragment frame - - // various Counters - COUNTER_802_3 Counters8023; // 802.3 counters - COUNTER_802_11 WlanCounters; // 802.11 MIB counters - COUNTER_RALINK RalinkCounters; // Ralink propriety counters - COUNTER_DRS DrsCounters; // counters for Dynamic TX Rate Switching - PRIVATE_STRUC PrivateInfo; // Private information & counters - - // flags, see fRTMP_ADAPTER_xxx flags - ULONG Flags; // Represent current device status - - // current TX sequence # - USHORT Sequence; - - // Control disconnect / connect event generation - //+++Didn't used anymore - ULONG LinkDownTime; - //--- - ULONG LastRxRate; - ULONG LastTxRate; - //+++Used only for Station - BOOLEAN bConfigChanged; // Config Change flag for the same SSID setting - //--- - - ULONG ExtraInfo; // Extra information for displaying status - ULONG SystemErrorBitmap; // b0: E2PROM version error - - //+++Didn't used anymore - ULONG MacIcVersion; // MAC/BBP serial interface issue solved after ver.D - //--- - - // --------------------------- - // System event log - // --------------------------- - RT_802_11_EVENT_TABLE EventTab; - - - BOOLEAN HTCEnable; - - /*****************************************************************************************/ - /* Statistic related parameters */ - /*****************************************************************************************/ -#ifdef RT2870 - ULONG BulkOutDataOneSecCount; - ULONG BulkInDataOneSecCount; - ULONG BulkLastOneSecCount; // BulkOutDataOneSecCount + BulkInDataOneSecCount - ULONG watchDogRxCnt; - ULONG watchDogRxOverFlowCnt; - ULONG watchDogTxPendingCnt[NUM_OF_TX_RING]; -#endif // RT2870 // - - BOOLEAN bUpdateBcnCntDone; - ULONG watchDogMacDeadlock; // prevent MAC/BBP into deadlock condition - // ---------------------------- - // DEBUG paramerts - // ---------------------------- - //ULONG DebugSetting[4]; - BOOLEAN bBanAllBaSetup; - BOOLEAN bPromiscuous; - - // ---------------------------- - // rt2860c emulation-use Parameters - // ---------------------------- - ULONG rtsaccu[30]; - ULONG ctsaccu[30]; - ULONG cfendaccu[30]; - ULONG bacontent[16]; - ULONG rxint[RX_RING_SIZE+1]; - UCHAR rcvba[60]; - BOOLEAN bLinkAdapt; - BOOLEAN bForcePrintTX; - BOOLEAN bForcePrintRX; - BOOLEAN bDisablescanning; //defined in RT2870 USB - BOOLEAN bStaFifoTest; - BOOLEAN bProtectionTest; - BOOLEAN bHCCATest; - BOOLEAN bGenOneHCCA; - BOOLEAN bBroadComHT; - //+++Following add from RT2870 USB. - ULONG BulkOutReq; - ULONG BulkOutComplete; - ULONG BulkOutCompleteOther; - ULONG BulkOutCompleteCancel; // seems not use now? - ULONG BulkInReq; - ULONG BulkInComplete; - ULONG BulkInCompleteFail; - //--- - - struct wificonf WIFItestbed; - -#ifdef RALINK_ATE - ATE_INFO ate; -#ifdef RT2870 - BOOLEAN ContinBulkOut; //ATE bulk out control - BOOLEAN ContinBulkIn; //ATE bulk in control - atomic_t BulkOutRemained; - atomic_t BulkInRemained; -#endif // RT2870 // -#endif // RALINK_ATE // - -#ifdef DOT11_N_SUPPORT - struct reordering_mpdu_pool mpdu_blk_pool; -#endif // DOT11_N_SUPPORT // - - ULONG OneSecondnonBEpackets; // record non BE packets per second - -#if WIRELESS_EXT >= 12 - struct iw_statistics iw_stats; -#endif - - struct net_device_stats stats; - -#ifdef BLOCK_NET_IF - BLOCK_QUEUE_ENTRY blockQueueTab[NUM_OF_TX_RING]; -#endif // BLOCK_NET_IF // - - - -#ifdef MULTIPLE_CARD_SUPPORT - INT32 MC_RowID; - UCHAR MC_FileName[256]; -#endif // MULTIPLE_CARD_SUPPORT // - - ULONG TbttTickCount; -#ifdef PCI_MSI_SUPPORT - BOOLEAN HaveMsi; -#endif // PCI_MSI_SUPPORT // - - - UCHAR is_on; - -#define TIME_BASE (1000000/OS_HZ) -#define TIME_ONE_SECOND (1000000/TIME_BASE) - UCHAR flg_be_adjust; - ULONG be_adjust_last_time; - - -#ifdef IKANOS_VX_1X0 - struct IKANOS_TX_INFO IkanosTxInfo; - struct IKANOS_TX_INFO IkanosRxInfo[MAX_MBSSID_NUM + MAX_WDS_ENTRY + MAX_APCLI_NUM + MAX_MESH_NUM]; -#endif // IKANOS_VX_1X0 // - - -#ifdef DBG_DIAGNOSE - RtmpDiagStruct DiagStruct; -#endif // DBG_DIAGNOSE // - - - UINT8 PM_FlgSuspend; -} RTMP_ADAPTER, *PRTMP_ADAPTER; - -// -// Cisco IAPP format -// -typedef struct _CISCO_IAPP_CONTENT_ -{ - USHORT Length; //IAPP Length - UCHAR MessageType; //IAPP type - UCHAR FunctionCode; //IAPP function type - UCHAR DestinaionMAC[MAC_ADDR_LEN]; - UCHAR SourceMAC[MAC_ADDR_LEN]; - USHORT Tag; //Tag(element IE) - Adjacent AP report - USHORT TagLength; //Length of element not including 4 byte header - UCHAR OUI[4]; //0x00, 0x40, 0x96, 0x00 - UCHAR PreviousAP[MAC_ADDR_LEN]; //MAC Address of access point - USHORT Channel; - USHORT SsidLen; - UCHAR Ssid[MAX_LEN_OF_SSID]; - USHORT Seconds; //Seconds that the client has been disassociated. -} CISCO_IAPP_CONTENT, *PCISCO_IAPP_CONTENT; - -#define DELAYINTMASK 0x0003fffb -#define INTMASK 0x0003fffb -#define IndMask 0x0003fffc -#define RxINT 0x00000005 // Delayed Rx or indivi rx -#define TxDataInt 0x000000fa // Delayed Tx or indivi tx -#define TxMgmtInt 0x00000102 // Delayed Tx or indivi tx -#define TxCoherent 0x00020000 // tx coherent -#define RxCoherent 0x00010000 // rx coherent -#define McuCommand 0x00000200 // mcu -#define PreTBTTInt 0x00001000 // Pre-TBTT interrupt -#define TBTTInt 0x00000800 // TBTT interrupt -#define GPTimeOutInt 0x00008000 // GPtimeout interrupt -#define AutoWakeupInt 0x00004000 // AutoWakeupInt interrupt -#define FifoStaFullInt 0x00002000 // fifo statistics full interrupt - - -typedef struct _RX_BLK_ -{ -// RXD_STRUC RxD; // sample - RT28XX_RXD_STRUC RxD; - PRXWI_STRUC pRxWI; - PHEADER_802_11 pHeader; - PNDIS_PACKET pRxPacket; - UCHAR *pData; - USHORT DataSize; - USHORT Flags; - UCHAR UserPriority; // for calculate TKIP MIC using -} RX_BLK; - - -#define RX_BLK_SET_FLAG(_pRxBlk, _flag) (_pRxBlk->Flags |= _flag) -#define RX_BLK_TEST_FLAG(_pRxBlk, _flag) (_pRxBlk->Flags & _flag) -#define RX_BLK_CLEAR_FLAG(_pRxBlk, _flag) (_pRxBlk->Flags &= ~(_flag)) - - -#define fRX_WDS 0x0001 -#define fRX_AMSDU 0x0002 -#define fRX_ARALINK 0x0004 -#define fRX_HTC 0x0008 -#define fRX_PAD 0x0010 -#define fRX_AMPDU 0x0020 -#define fRX_QOS 0x0040 -#define fRX_INFRA 0x0080 -#define fRX_EAP 0x0100 -#define fRX_MESH 0x0200 -#define fRX_APCLI 0x0400 -#define fRX_DLS 0x0800 -#define fRX_WPI 0x1000 - -#define LENGTH_AMSDU_SUBFRAMEHEAD 14 -#define LENGTH_ARALINK_SUBFRAMEHEAD 14 -#define LENGTH_ARALINK_HEADER_FIELD 2 - -#define TX_UNKOWN_FRAME 0x00 -#define TX_MCAST_FRAME 0x01 -#define TX_LEGACY_FRAME 0x02 -#define TX_AMPDU_FRAME 0x04 -#define TX_AMSDU_FRAME 0x08 -#define TX_RALINK_FRAME 0x10 -#define TX_FRAG_FRAME 0x20 - - -// Currently the sizeof(TX_BLK) is 148 bytes. -typedef struct _TX_BLK_ -{ - UCHAR QueIdx; - UCHAR TxFrameType; // Indicate the Transmission type of the all frames in one batch - UCHAR TotalFrameNum; // Total frame number want to send-out in one batch - USHORT TotalFragNum; // Total frame fragments required in one batch - USHORT TotalFrameLen; // Total length of all frames want to send-out in one batch - - QUEUE_HEADER TxPacketList; - MAC_TABLE_ENTRY *pMacEntry; // NULL: packet with 802.11 RA field is multicast/broadcast address - HTTRANSMIT_SETTING *pTransmit; - - // Following structure used for the characteristics of a specific packet. - PNDIS_PACKET pPacket; - PUCHAR pSrcBufHeader; // Reference to the head of sk_buff->data - PUCHAR pSrcBufData; // Reference to the sk_buff->data, will changed depends on hanlding progresss - UINT SrcBufLen; // Length of packet payload which not including Layer 2 header - PUCHAR pExtraLlcSnapEncap; // NULL means no extra LLC/SNAP is required - UCHAR HeaderBuf[80]; // TempBuffer for TX_INFO + TX_WI + 802.11 Header + padding + AMSDU SubHeader + LLC/SNAP - UCHAR MpduHeaderLen; // 802.11 header length NOT including the padding - UCHAR HdrPadLen; // recording Header Padding Length; - UCHAR apidx; // The interface associated to this packet - UCHAR Wcid; // The MAC entry associated to this packet - UCHAR UserPriority; // priority class of packet - UCHAR FrameGap; // what kind of IFS this packet use - UCHAR MpduReqNum; // number of fragments of this frame - UCHAR TxRate; // TODO: Obsoleted? Should change to MCS? - UCHAR CipherAlg; // cipher alogrithm - PCIPHER_KEY pKey; - - - - USHORT Flags; //See following definitions for detail. - - //YOU SHOULD NOT TOUCH IT! Following parameters are used for hardware-depended layer. - ULONG Priv; // Hardware specific value saved in here. -} TX_BLK, *PTX_BLK; - - -#define fTX_bRtsRequired 0x0001 // Indicate if need send RTS frame for protection. Not used in RT2860/RT2870. -#define fTX_bAckRequired 0x0002 // the packet need ack response -#define fTX_bPiggyBack 0x0004 // Legacy device use Piggback or not -#define fTX_bHTRate 0x0008 // allow to use HT rate -//#define fTX_bForceLowRate 0x0010 // force to use Low Rate -#define fTX_bForceNonQoS 0x0010 // force to transmit frame without WMM-QoS in HT mode -#define fTX_bAllowFrag 0x0020 // allow to fragment the packet, A-MPDU, A-MSDU, A-Ralink is not allowed to fragment -#define fTX_bMoreData 0x0040 // there are more data packets in PowerSave Queue -#define fTX_bWMM 0x0080 // QOS Data - -#define fTX_bClearEAPFrame 0x0100 - - -#ifdef CONFIG_STA_SUPPORT -#endif // CONFIG_STA_SUPPORT // - - - -#define TX_BLK_ASSIGN_FLAG(_pTxBlk, _flag, value) \ - do { \ - if (value) \ - (_pTxBlk->Flags |= _flag) \ - else \ - (_pTxBlk->Flags &= ~(_flag)) \ - }while(0) - -#define TX_BLK_SET_FLAG(_pTxBlk, _flag) (_pTxBlk->Flags |= _flag) -#define TX_BLK_TEST_FLAG(_pTxBlk, _flag) (((_pTxBlk->Flags & _flag) == _flag) ? 1 : 0) -#define TX_BLK_CLEAR_FLAG(_pTxBlk, _flag) (_pTxBlk->Flags &= ~(_flag)) - - - - - -//------------------------------------------------------------------------------------------ - - - -#ifdef RT_BIG_ENDIAN -static inline VOID WriteBackToDescriptor( - IN PUCHAR Dest, - IN PUCHAR Src, - IN BOOLEAN DoEncrypt, - IN ULONG DescriptorType) -{ - UINT32 *p1, *p2; - - p1 = ((UINT32 *)Dest); - p2 = ((UINT32 *)Src); - - *p1 = *p2; - *(p1+2) = *(p2+2); - *(p1+3) = *(p2+3); - *(p1+1) = *(p2+1); // Word 1; this must be written back last -} - -/* - ======================================================================== - - Routine Description: - Endian conversion of Tx/Rx descriptor . - - Arguments: - pAd Pointer to our adapter - pData Pointer to Tx/Rx descriptor - DescriptorType Direction of the frame - - Return Value: - None - - Note: - Call this function when read or update descriptor - ======================================================================== -*/ -static inline VOID RTMPWIEndianChange( - IN PUCHAR pData, - IN ULONG DescriptorType) -{ - int size; - int i; - - size = ((DescriptorType == TYPE_TXWI) ? TXWI_SIZE : RXWI_SIZE); - - if(DescriptorType == TYPE_TXWI) - { - *((UINT32 *)(pData)) = SWAP32(*((UINT32 *)(pData))); // Byte 0~3 - *((UINT32 *)(pData + 4)) = SWAP32(*((UINT32 *)(pData+4))); // Byte 4~7 - } - else - { - for(i=0; i < size/4 ; i++) - *(((UINT32 *)pData) +i) = SWAP32(*(((UINT32 *)pData)+i)); - } -} - -/* - ======================================================================== - - Routine Description: - Endian conversion of Tx/Rx descriptor . - - Arguments: - pAd Pointer to our adapter - pData Pointer to Tx/Rx descriptor - DescriptorType Direction of the frame - - Return Value: - None - - Note: - Call this function when read or update descriptor - ======================================================================== -*/ - -#ifdef RT2870 -static inline VOID RTMPDescriptorEndianChange( - IN PUCHAR pData, - IN ULONG DescriptorType) -{ - *((UINT32 *)(pData)) = SWAP32(*((UINT32 *)(pData))); -} -#endif // RT2870 // -/* - ======================================================================== - - Routine Description: - Endian conversion of all kinds of 802.11 frames . - - Arguments: - pAd Pointer to our adapter - pData Pointer to the 802.11 frame structure - Dir Direction of the frame - FromRxDoneInt Caller is from RxDone interrupt - - Return Value: - None - - Note: - Call this function when read or update buffer data - ======================================================================== -*/ -static inline VOID RTMPFrameEndianChange( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pData, - IN ULONG Dir, - IN BOOLEAN FromRxDoneInt) -{ - PHEADER_802_11 pFrame; - PUCHAR pMacHdr; - - // swab 16 bit fields - Frame Control field - if(Dir == DIR_READ) - { - *(USHORT *)pData = SWAP16(*(USHORT *)pData); - } - - pFrame = (PHEADER_802_11) pData; - pMacHdr = (PUCHAR) pFrame; - - // swab 16 bit fields - Duration/ID field - *(USHORT *)(pMacHdr + 2) = SWAP16(*(USHORT *)(pMacHdr + 2)); - - // swab 16 bit fields - Sequence Control field - *(USHORT *)(pMacHdr + 22) = SWAP16(*(USHORT *)(pMacHdr + 22)); - - if(pFrame->FC.Type == BTYPE_MGMT) - { - switch(pFrame->FC.SubType) - { - case SUBTYPE_ASSOC_REQ: - case SUBTYPE_REASSOC_REQ: - // swab 16 bit fields - CapabilityInfo field - pMacHdr += sizeof(HEADER_802_11); - *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); - - // swab 16 bit fields - Listen Interval field - pMacHdr += 2; - *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); - break; - - case SUBTYPE_ASSOC_RSP: - case SUBTYPE_REASSOC_RSP: - // swab 16 bit fields - CapabilityInfo field - pMacHdr += sizeof(HEADER_802_11); - *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); - - // swab 16 bit fields - Status Code field - pMacHdr += 2; - *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); - - // swab 16 bit fields - AID field - pMacHdr += 2; - *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); - break; - - case SUBTYPE_AUTH: - // If from APHandleRxDoneInterrupt routine, it is still a encrypt format. - // The convertion is delayed to RTMPHandleDecryptionDoneInterrupt. - if(!FromRxDoneInt && pFrame->FC.Wep == 1) - break; - else - { - // swab 16 bit fields - Auth Alg No. field - pMacHdr += sizeof(HEADER_802_11); - *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); - - // swab 16 bit fields - Auth Seq No. field - pMacHdr += 2; - *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); - - // swab 16 bit fields - Status Code field - pMacHdr += 2; - *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); - } - break; - - case SUBTYPE_BEACON: - case SUBTYPE_PROBE_RSP: - // swab 16 bit fields - BeaconInterval field - pMacHdr += (sizeof(HEADER_802_11) + TIMESTAMP_LEN); - *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); - - // swab 16 bit fields - CapabilityInfo field - pMacHdr += sizeof(USHORT); - *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); - break; - - case SUBTYPE_DEAUTH: - case SUBTYPE_DISASSOC: - // swab 16 bit fields - Reason code field - pMacHdr += sizeof(HEADER_802_11); - *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); - break; - } - } - else if( pFrame->FC.Type == BTYPE_DATA ) - { - } - else if(pFrame->FC.Type == BTYPE_CNTL) - { - switch(pFrame->FC.SubType) - { - case SUBTYPE_BLOCK_ACK_REQ: - { - PFRAME_BA_REQ pBAReq = (PFRAME_BA_REQ)pFrame; - *(USHORT *)(&pBAReq->BARControl) = SWAP16(*(USHORT *)(&pBAReq->BARControl)); - pBAReq->BAStartingSeq.word = SWAP16(pBAReq->BAStartingSeq.word); - } - break; - case SUBTYPE_BLOCK_ACK: - // For Block Ack packet, the HT_CONTROL field is in the same offset with Addr3 - *(UINT32 *)(&pFrame->Addr3[0]) = SWAP32(*(UINT32 *)(&pFrame->Addr3[0])); - break; - - case SUBTYPE_ACK: - //For ACK packet, the HT_CONTROL field is in the same offset with Addr2 - *(UINT32 *)(&pFrame->Addr2[0])= SWAP32(*(UINT32 *)(&pFrame->Addr2[0])); - break; - } - } - else - { - DBGPRINT(RT_DEBUG_ERROR,("Invalid Frame Type!!!\n")); - } - - // swab 16 bit fields - Frame Control - if(Dir == DIR_WRITE) - { - *(USHORT *)pData = SWAP16(*(USHORT *)pData); - } -} -#endif // RT_BIG_ENDIAN // - - -static inline VOID ConvertMulticastIP2MAC( - IN PUCHAR pIpAddr, - IN PUCHAR *ppMacAddr, - IN UINT16 ProtoType) -{ - if (pIpAddr == NULL) - return; - - if (ppMacAddr == NULL || *ppMacAddr == NULL) - return; - - switch (ProtoType) - { - case ETH_P_IPV6: -// memset(*ppMacAddr, 0, ETH_LENGTH_OF_ADDRESS); - *(*ppMacAddr) = 0x33; - *(*ppMacAddr + 1) = 0x33; - *(*ppMacAddr + 2) = pIpAddr[12]; - *(*ppMacAddr + 3) = pIpAddr[13]; - *(*ppMacAddr + 4) = pIpAddr[14]; - *(*ppMacAddr + 5) = pIpAddr[15]; - break; - - case ETH_P_IP: - default: -// memset(*ppMacAddr, 0, ETH_LENGTH_OF_ADDRESS); - *(*ppMacAddr) = 0x01; - *(*ppMacAddr + 1) = 0x00; - *(*ppMacAddr + 2) = 0x5e; - *(*ppMacAddr + 3) = pIpAddr[1] & 0x7f; - *(*ppMacAddr + 4) = pIpAddr[2]; - *(*ppMacAddr + 5) = pIpAddr[3]; - break; - } - - return; -} - -BOOLEAN RTMPCheckForHang( - IN NDIS_HANDLE MiniportAdapterContext - ); - -VOID RTMPHalt( - IN NDIS_HANDLE MiniportAdapterContext - ); - -// -// Private routines in rtmp_init.c -// -NDIS_STATUS RTMPAllocAdapterBlock( - IN PVOID handle, - OUT PRTMP_ADAPTER *ppAdapter - ); - -NDIS_STATUS RTMPAllocTxRxRingMemory( - IN PRTMP_ADAPTER pAd - ); - -NDIS_STATUS RTMPFindAdapter( - IN PRTMP_ADAPTER pAd, - IN NDIS_HANDLE WrapperConfigurationContext - ); - -NDIS_STATUS RTMPReadParametersHook( - IN PRTMP_ADAPTER pAd - ); - -VOID RTMPFreeAdapter( - IN PRTMP_ADAPTER pAd - ); - -NDIS_STATUS NICReadRegParameters( - IN PRTMP_ADAPTER pAd, - IN NDIS_HANDLE WrapperConfigurationContext - ); - -#ifdef RT2870 -VOID NICInitRT30xxRFRegisters( - IN PRTMP_ADAPTER pAd); -#endif // RT2870 // - -VOID NICReadEEPROMParameters( - IN PRTMP_ADAPTER pAd, - IN PUCHAR mac_addr); - -VOID NICInitAsicFromEEPROM( - IN PRTMP_ADAPTER pAd); - -VOID NICInitTxRxRingAndBacklogQueue( - IN PRTMP_ADAPTER pAd); - -NDIS_STATUS NICInitializeAdapter( - IN PRTMP_ADAPTER pAd, - IN BOOLEAN bHardReset); - -NDIS_STATUS NICInitializeAsic( - IN PRTMP_ADAPTER pAd, - IN BOOLEAN bHardReset); - -VOID NICIssueReset( - IN PRTMP_ADAPTER pAd); - -VOID RTMPRingCleanUp( - IN PRTMP_ADAPTER pAd, - IN UCHAR RingType); - -VOID RxTest( - IN PRTMP_ADAPTER pAd); - -NDIS_STATUS DbgSendPacket( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket); - -VOID UserCfgInit( - IN PRTMP_ADAPTER pAd); - -VOID NICResetFromError( - IN PRTMP_ADAPTER pAd); - -VOID NICEraseFirmware( - IN PRTMP_ADAPTER pAd); - -NDIS_STATUS NICLoadFirmware( - IN PRTMP_ADAPTER pAd); - -NDIS_STATUS NICLoadRateSwitchingParams( - IN PRTMP_ADAPTER pAd); - -BOOLEAN NICCheckForHang( - IN PRTMP_ADAPTER pAd); - -VOID NICUpdateFifoStaCounters( - IN PRTMP_ADAPTER pAd); - -VOID NICUpdateRawCounters( - IN PRTMP_ADAPTER pAd); - -#if 0 -ULONG RTMPEqualMemory( - IN PVOID pSrc1, - IN PVOID pSrc2, - IN ULONG Length); -#endif - -ULONG RTMPNotAllZero( - IN PVOID pSrc1, - IN ULONG Length); - -VOID RTMPZeroMemory( - IN PVOID pSrc, - IN ULONG Length); - -ULONG RTMPCompareMemory( - IN PVOID pSrc1, - IN PVOID pSrc2, - IN ULONG Length); - -VOID RTMPMoveMemory( - OUT PVOID pDest, - IN PVOID pSrc, - IN ULONG Length); - -VOID AtoH( - char *src, - UCHAR *dest, - int destlen); - -UCHAR BtoH( - char ch); - -VOID RTMPPatchMacBbpBug( - IN PRTMP_ADAPTER pAd); - -VOID RTMPPatchCardBus( - IN PRTMP_ADAPTER pAdapter); - -VOID RTMPPatchRalinkCardBus( - IN PRTMP_ADAPTER pAdapter, - IN ULONG Bus); - -ULONG RTMPReadCBConfig( - IN ULONG Bus, - IN ULONG Slot, - IN ULONG Func, - IN ULONG Offset); - -VOID RTMPWriteCBConfig( - IN ULONG Bus, - IN ULONG Slot, - IN ULONG Func, - IN ULONG Offset, - IN ULONG Value); - -VOID RTMPInitTimer( - IN PRTMP_ADAPTER pAd, - IN PRALINK_TIMER_STRUCT pTimer, - IN PVOID pTimerFunc, - IN PVOID pData, - IN BOOLEAN Repeat); - -VOID RTMPSetTimer( - IN PRALINK_TIMER_STRUCT pTimer, - IN ULONG Value); - - -VOID RTMPModTimer( - IN PRALINK_TIMER_STRUCT pTimer, - IN ULONG Value); - -VOID RTMPCancelTimer( - IN PRALINK_TIMER_STRUCT pTimer, - OUT BOOLEAN *pCancelled); - -VOID RTMPSetLED( - IN PRTMP_ADAPTER pAd, - IN UCHAR Status); - -VOID RTMPSetSignalLED( - IN PRTMP_ADAPTER pAd, - IN NDIS_802_11_RSSI Dbm); - -VOID RTMPEnableRxTx( - IN PRTMP_ADAPTER pAd); - -// -// prototype in action.c -// -VOID ActionStateMachineInit( - IN PRTMP_ADAPTER pAd, - IN STATE_MACHINE *S, - OUT STATE_MACHINE_FUNC Trans[]); - -VOID MlmeADDBAAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID MlmeDELBAAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID MlmeDLSAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID MlmeInvalidAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID MlmeQOSAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -#ifdef DOT11_N_SUPPORT -VOID PeerAddBAReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID PeerAddBARspAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID PeerDelBAAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID PeerBAAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); -#endif // DOT11_N_SUPPORT // - -VOID SendPSMPAction( - IN PRTMP_ADAPTER pAd, - IN UCHAR Wcid, - IN UCHAR Psmp); - - -#ifdef DOT11N_DRAFT3 -VOID SendBSS2040CoexistMgmtAction( - IN PRTMP_ADAPTER pAd, - IN UCHAR Wcid, - IN UCHAR apidx, - IN UCHAR InfoReq); - -VOID SendNotifyBWActionFrame( - IN PRTMP_ADAPTER pAd, - IN UCHAR Wcid, - IN UCHAR apidx); - -BOOLEAN ChannelSwitchSanityCheck( - IN PRTMP_ADAPTER pAd, - IN UCHAR Wcid, - IN UCHAR NewChannel, - IN UCHAR Secondary); - -VOID ChannelSwitchAction( - IN PRTMP_ADAPTER pAd, - IN UCHAR Wcid, - IN UCHAR Channel, - IN UCHAR Secondary); - -ULONG BuildIntolerantChannelRep( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDest); - -VOID Update2040CoexistFrameAndNotify( - IN PRTMP_ADAPTER pAd, - IN UCHAR Wcid, - IN BOOLEAN bAddIntolerantCha); - -VOID Send2040CoexistAction( - IN PRTMP_ADAPTER pAd, - IN UCHAR Wcid, - IN BOOLEAN bAddIntolerantCha); -#endif // DOT11N_DRAFT3 // - -VOID PeerRMAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID PeerPublicAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -#ifdef CONFIG_STA_SUPPORT -VOID StaPublicAction( - IN PRTMP_ADAPTER pAd, - IN UCHAR Bss2040Coexist); -#endif // CONFIG_STA_SUPPORT // - - -VOID PeerBSSTranAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -#ifdef DOT11_N_SUPPORT -VOID PeerHTAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); -#endif // DOT11_N_SUPPORT // - -VOID PeerQOSAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -#ifdef QOS_DLS_SUPPORT -VOID PeerDLSAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); -#endif // QOS_DLS_SUPPORT // - -#ifdef CONFIG_STA_SUPPORT -#ifdef QOS_DLS_SUPPORT -VOID DlsParmFill( - IN PRTMP_ADAPTER pAd, - IN OUT MLME_DLS_REQ_STRUCT *pDlsReq, - IN PRT_802_11_DLS pDls, - IN USHORT reason); -#endif // QOS_DLS_SUPPORT // -#endif // CONFIG_STA_SUPPORT // - -#ifdef DOT11_N_SUPPORT -VOID RECBATimerTimeout( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); - -VOID ORIBATimerTimeout( - IN PRTMP_ADAPTER pAd); - -VOID SendRefreshBAR( - IN PRTMP_ADAPTER pAd, - IN MAC_TABLE_ENTRY *pEntry); -#endif // DOT11_N_SUPPORT // - -VOID ActHeaderInit( - IN PRTMP_ADAPTER pAd, - IN OUT PHEADER_802_11 pHdr80211, - IN PUCHAR Addr1, - IN PUCHAR Addr2, - IN PUCHAR Addr3); - -VOID BarHeaderInit( - IN PRTMP_ADAPTER pAd, - IN OUT PFRAME_BAR pCntlBar, - IN PUCHAR pDA, - IN PUCHAR pSA); - -VOID InsertActField( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pFrameBuf, - OUT PULONG pFrameLen, - IN UINT8 Category, - IN UINT8 ActCode); - -BOOLEAN QosBADataParse( - IN PRTMP_ADAPTER pAd, - IN BOOLEAN bAMSDU, - IN PUCHAR p8023Header, - IN UCHAR WCID, - IN UCHAR TID, - IN USHORT Sequence, - IN UCHAR DataOffset, - IN USHORT Datasize, - IN UINT CurRxIndex); - -#ifdef DOT11_N_SUPPORT -BOOLEAN CntlEnqueueForRecv( - IN PRTMP_ADAPTER pAd, - IN ULONG Wcid, - IN ULONG MsgLen, - IN PFRAME_BA_REQ pMsg); - -VOID BaAutoManSwitch( - IN PRTMP_ADAPTER pAd); -#endif // DOT11_N_SUPPORT // - -VOID HTIOTCheck( - IN PRTMP_ADAPTER pAd, - IN UCHAR BatRecIdx); - -// -// Private routines in rtmp_data.c -// -BOOLEAN RTMPHandleRxDoneInterrupt( - IN PRTMP_ADAPTER pAd); - -VOID RTMPHandleTxDoneInterrupt( - IN PRTMP_ADAPTER pAd); - -BOOLEAN RTMPHandleTxRingDmaDoneInterrupt( - IN PRTMP_ADAPTER pAd, - IN INT_SOURCE_CSR_STRUC TxRingBitmap); - -VOID RTMPHandleMgmtRingDmaDoneInterrupt( - IN PRTMP_ADAPTER pAd); - -VOID RTMPHandleTBTTInterrupt( - IN PRTMP_ADAPTER pAd); - -VOID RTMPHandlePreTBTTInterrupt( - IN PRTMP_ADAPTER pAd); - -void RTMPHandleTwakeupInterrupt( - IN PRTMP_ADAPTER pAd); - -VOID RTMPHandleRxCoherentInterrupt( - IN PRTMP_ADAPTER pAd); - -BOOLEAN TxFrameIsAggregatible( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pPrevAddr1, - IN PUCHAR p8023hdr); - -BOOLEAN PeerIsAggreOn( - IN PRTMP_ADAPTER pAd, - IN ULONG TxRate, - IN PMAC_TABLE_ENTRY pMacEntry); - -#if 0 // It's not be used -HTTRANSMIT_SETTING *GetTxMode( - IN PRTMP_ADAPTER pAd, - IN TX_BLK *pTxBlk); -#endif - -NDIS_STATUS Sniff2BytesFromNdisBuffer( - IN PNDIS_BUFFER pFirstBuffer, - IN UCHAR DesiredOffset, - OUT PUCHAR pByte0, - OUT PUCHAR pByte1); - -NDIS_STATUS STASendPacket( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket); - -VOID STASendPackets( - IN NDIS_HANDLE MiniportAdapterContext, - IN PPNDIS_PACKET ppPacketArray, - IN UINT NumberOfPackets); - -VOID RTMPDeQueuePacket( - IN PRTMP_ADAPTER pAd, - IN BOOLEAN bIntContext, - IN UCHAR QueIdx, - IN UCHAR Max_Tx_Packets); - -NDIS_STATUS RTMPHardTransmit( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket, - IN UCHAR QueIdx, - OUT PULONG pFreeTXDLeft); - -NDIS_STATUS STAHardTransmit( - IN PRTMP_ADAPTER pAd, - IN TX_BLK *pTxBlk, - IN UCHAR QueIdx); - -VOID STARxEAPOLFrameIndicate( - IN PRTMP_ADAPTER pAd, - IN MAC_TABLE_ENTRY *pEntry, - IN RX_BLK *pRxBlk, - IN UCHAR FromWhichBSSID); - -NDIS_STATUS RTMPFreeTXDRequest( - IN PRTMP_ADAPTER pAd, - IN UCHAR RingType, - IN UCHAR NumberRequired, - IN PUCHAR FreeNumberIs); - -NDIS_STATUS MlmeHardTransmit( - IN PRTMP_ADAPTER pAd, - IN UCHAR QueIdx, - IN PNDIS_PACKET pPacket); - -NDIS_STATUS MlmeHardTransmitMgmtRing( - IN PRTMP_ADAPTER pAd, - IN UCHAR QueIdx, - IN PNDIS_PACKET pPacket); - -NDIS_STATUS MlmeHardTransmitTxRing( - IN PRTMP_ADAPTER pAd, - IN UCHAR QueIdx, - IN PNDIS_PACKET pPacket); - -USHORT RTMPCalcDuration( - IN PRTMP_ADAPTER pAd, - IN UCHAR Rate, - IN ULONG Size); - -VOID RTMPWriteTxWI( - IN PRTMP_ADAPTER pAd, - IN PTXWI_STRUC pTxWI, - IN BOOLEAN FRAG, - IN BOOLEAN CFACK, - IN BOOLEAN InsTimestamp, - IN BOOLEAN AMPDU, - IN BOOLEAN Ack, - IN BOOLEAN NSeq, // HW new a sequence. - IN UCHAR BASize, - IN UCHAR WCID, - IN ULONG Length, - IN UCHAR PID, - IN UCHAR TID, - IN UCHAR TxRate, - IN UCHAR Txopmode, - IN BOOLEAN CfAck, - IN HTTRANSMIT_SETTING *pTransmit); - - -VOID RTMPWriteTxWI_Data( - IN PRTMP_ADAPTER pAd, - IN OUT PTXWI_STRUC pTxWI, - IN TX_BLK *pTxBlk); - - -VOID RTMPWriteTxWI_Cache( - IN PRTMP_ADAPTER pAd, - IN OUT PTXWI_STRUC pTxWI, - IN TX_BLK *pTxBlk); - -VOID RTMPWriteTxDescriptor( - IN PRTMP_ADAPTER pAd, - IN PTXD_STRUC pTxD, - IN BOOLEAN bWIV, - IN UCHAR QSEL); - -VOID RTMPSuspendMsduTransmission( - IN PRTMP_ADAPTER pAd); - -VOID RTMPResumeMsduTransmission( - IN PRTMP_ADAPTER pAd); - -NDIS_STATUS MiniportMMRequest( - IN PRTMP_ADAPTER pAd, - IN UCHAR QueIdx, - IN PUCHAR pData, - IN UINT Length); - -NDIS_STATUS MiniportDataMMRequest( - IN PRTMP_ADAPTER pAd, - IN UCHAR QueIdx, - IN PUCHAR pData, - IN UINT Length); - -VOID RTMPSendNullFrame( - IN PRTMP_ADAPTER pAd, - IN UCHAR TxRate, - IN BOOLEAN bQosNull); - -VOID RTMPSendDisassociationFrame( - IN PRTMP_ADAPTER pAd); - -VOID RTMPSendRTSFrame( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDA, - IN unsigned int NextMpduSize, - IN UCHAR TxRate, - IN UCHAR RTSRate, - IN USHORT AckDuration, - IN UCHAR QueIdx, - IN UCHAR FrameGap); - - -NDIS_STATUS RTMPApplyPacketFilter( - IN PRTMP_ADAPTER pAd, - IN PRT28XX_RXD_STRUC pRxD, - IN PHEADER_802_11 pHeader); - -PQUEUE_HEADER RTMPCheckTxSwQueue( - IN PRTMP_ADAPTER pAd, - OUT UCHAR *QueIdx); - -#ifdef CONFIG_STA_SUPPORT -VOID RTMPReportMicError( - IN PRTMP_ADAPTER pAd, - IN PCIPHER_KEY pWpaKey); - -VOID WpaMicFailureReportFrame( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID WpaDisassocApAndBlockAssoc( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); -#endif // CONFIG_STA_SUPPORT // - -NDIS_STATUS RTMPCloneNdisPacket( - IN PRTMP_ADAPTER pAd, - IN BOOLEAN pInsAMSDUHdr, - IN PNDIS_PACKET pInPacket, - OUT PNDIS_PACKET *ppOutPacket); - -NDIS_STATUS RTMPAllocateNdisPacket( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET *pPacket, - IN PUCHAR pHeader, - IN UINT HeaderLen, - IN PUCHAR pData, - IN UINT DataLen); - -VOID RTMPFreeNdisPacket( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket); - -BOOLEAN RTMPFreeTXDUponTxDmaDone( - IN PRTMP_ADAPTER pAd, - IN UCHAR QueIdx); - -BOOLEAN RTMPCheckDHCPFrame( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket); - - -BOOLEAN RTMPCheckEtherType( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket); - - -VOID RTMPCckBbpTuning( - IN PRTMP_ADAPTER pAd, - IN UINT TxRate); - -// -// Private routines in rtmp_wep.c -// -VOID RTMPInitWepEngine( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pKey, - IN UCHAR KeyId, - IN UCHAR KeyLen, - IN PUCHAR pDest); - -VOID RTMPEncryptData( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pSrc, - IN PUCHAR pDest, - IN UINT Len); - -BOOLEAN RTMPDecryptData( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR pSrc, - IN UINT Len, - IN UINT idx); - -BOOLEAN RTMPSoftDecryptWEP( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pData, - IN ULONG DataByteCnt, - IN PCIPHER_KEY pGroupKey); - -VOID RTMPSetICV( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDest); - -VOID ARCFOUR_INIT( - IN PARCFOURCONTEXT Ctx, - IN PUCHAR pKey, - IN UINT KeyLen); - -UCHAR ARCFOUR_BYTE( - IN PARCFOURCONTEXT Ctx); - -VOID ARCFOUR_DECRYPT( - IN PARCFOURCONTEXT Ctx, - IN PUCHAR pDest, - IN PUCHAR pSrc, - IN UINT Len); - -VOID ARCFOUR_ENCRYPT( - IN PARCFOURCONTEXT Ctx, - IN PUCHAR pDest, - IN PUCHAR pSrc, - IN UINT Len); - -VOID WPAARCFOUR_ENCRYPT( - IN PARCFOURCONTEXT Ctx, - IN PUCHAR pDest, - IN PUCHAR pSrc, - IN UINT Len); - -UINT RTMP_CALC_FCS32( - IN UINT Fcs, - IN PUCHAR Cp, - IN INT Len); - -// -// MLME routines -// - -// Asic/RF/BBP related functions - -VOID AsicAdjustTxPower( - IN PRTMP_ADAPTER pAd); - -VOID AsicUpdateProtect( - IN PRTMP_ADAPTER pAd, - IN USHORT OperaionMode, - IN UCHAR SetMask, - IN BOOLEAN bDisableBGProtect, - IN BOOLEAN bNonGFExist); - -VOID AsicSwitchChannel( - IN PRTMP_ADAPTER pAd, - IN UCHAR Channel, - IN BOOLEAN bScan); - -VOID AsicLockChannel( - IN PRTMP_ADAPTER pAd, - IN UCHAR Channel) ; - -VOID AsicAntennaSelect( - IN PRTMP_ADAPTER pAd, - IN UCHAR Channel); - -VOID AsicAntennaSetting( - IN PRTMP_ADAPTER pAd, - IN ABGBAND_STATE BandState); - -VOID AsicRfTuningExec( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); - -#ifdef CONFIG_STA_SUPPORT -VOID AsicSleepThenAutoWakeup( - IN PRTMP_ADAPTER pAd, - IN USHORT TbttNumToNextWakeUp); - -VOID AsicForceSleep( - IN PRTMP_ADAPTER pAd); - -VOID AsicForceWakeup( - IN PRTMP_ADAPTER pAd, - IN BOOLEAN bFromTx); -#endif // CONFIG_STA_SUPPORT // - -VOID AsicSetBssid( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pBssid); - -VOID AsicSetMcastWC( - IN PRTMP_ADAPTER pAd); - -#if 0 // removed by AlbertY -VOID AsicSetBssidWC( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pBssid); -#endif - -VOID AsicDelWcidTab( - IN PRTMP_ADAPTER pAd, - IN UCHAR Wcid); - -VOID AsicEnableRDG( - IN PRTMP_ADAPTER pAd); - -VOID AsicDisableRDG( - IN PRTMP_ADAPTER pAd); - -VOID AsicDisableSync( - IN PRTMP_ADAPTER pAd); - -VOID AsicEnableBssSync( - IN PRTMP_ADAPTER pAd); - -VOID AsicEnableIbssSync( - IN PRTMP_ADAPTER pAd); - -VOID AsicSetEdcaParm( - IN PRTMP_ADAPTER pAd, - IN PEDCA_PARM pEdcaParm); - -VOID AsicSetSlotTime( - IN PRTMP_ADAPTER pAd, - IN BOOLEAN bUseShortSlotTime); - -#if 0 -VOID AsicAddWcidCipherEntry( - IN PRTMP_ADAPTER pAd, - IN UCHAR WCID, - IN UCHAR BssIndex, - IN UCHAR KeyTable, - IN UCHAR CipherAlg, - IN PUCHAR pAddr, - IN CIPHER_KEY *pCipherKey); -#endif - -VOID AsicAddSharedKeyEntry( - IN PRTMP_ADAPTER pAd, - IN UCHAR BssIndex, - IN UCHAR KeyIdx, - IN UCHAR CipherAlg, - IN PUCHAR pKey, - IN PUCHAR pTxMic, - IN PUCHAR pRxMic); - -VOID AsicRemoveSharedKeyEntry( - IN PRTMP_ADAPTER pAd, - IN UCHAR BssIndex, - IN UCHAR KeyIdx); - -VOID AsicUpdateWCIDAttribute( - IN PRTMP_ADAPTER pAd, - IN USHORT WCID, - IN UCHAR BssIndex, - IN UCHAR CipherAlg, - IN BOOLEAN bUsePairewiseKeyTable); - -VOID AsicUpdateWCIDIVEIV( - IN PRTMP_ADAPTER pAd, - IN USHORT WCID, - IN ULONG uIV, - IN ULONG uEIV); - -VOID AsicUpdateRxWCIDTable( - IN PRTMP_ADAPTER pAd, - IN USHORT WCID, - IN PUCHAR pAddr); - -VOID AsicAddKeyEntry( - IN PRTMP_ADAPTER pAd, - IN USHORT WCID, - IN UCHAR BssIndex, - IN UCHAR KeyIdx, - IN PCIPHER_KEY pCipherKey, - IN BOOLEAN bUsePairewiseKeyTable, - IN BOOLEAN bTxKey); - -VOID AsicAddPairwiseKeyEntry( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pAddr, - IN UCHAR WCID, - IN CIPHER_KEY *pCipherKey); - -VOID AsicRemovePairwiseKeyEntry( - IN PRTMP_ADAPTER pAd, - IN UCHAR BssIdx, - IN UCHAR Wcid); - -BOOLEAN AsicSendCommandToMcu( - IN PRTMP_ADAPTER pAd, - IN UCHAR Command, - IN UCHAR Token, - IN UCHAR Arg0, - IN UCHAR Arg1); - - -VOID MacAddrRandomBssid( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pAddr); - -VOID MgtMacHeaderInit( - IN PRTMP_ADAPTER pAd, - IN OUT PHEADER_802_11 pHdr80211, - IN UCHAR SubType, - IN UCHAR ToDs, - IN PUCHAR pDA, - IN PUCHAR pBssid); - -VOID MlmeRadioOff( - IN PRTMP_ADAPTER pAd); - -VOID MlmeRadioOn( - IN PRTMP_ADAPTER pAd); - - -VOID BssTableInit( - IN BSS_TABLE *Tab); - -#ifdef DOT11_N_SUPPORT -VOID BATableInit( - IN PRTMP_ADAPTER pAd, - IN BA_TABLE *Tab); -#endif // DOT11_N_SUPPORT // - -ULONG BssTableSearch( - IN BSS_TABLE *Tab, - IN PUCHAR pBssid, - IN UCHAR Channel); - -ULONG BssSsidTableSearch( - IN BSS_TABLE *Tab, - IN PUCHAR pBssid, - IN PUCHAR pSsid, - IN UCHAR SsidLen, - IN UCHAR Channel); - -ULONG BssTableSearchWithSSID( - IN BSS_TABLE *Tab, - IN PUCHAR Bssid, - IN PUCHAR pSsid, - IN UCHAR SsidLen, - IN UCHAR Channel); - -VOID BssTableDeleteEntry( - IN OUT PBSS_TABLE pTab, - IN PUCHAR pBssid, - IN UCHAR Channel); - -#ifdef DOT11_N_SUPPORT -VOID BATableDeleteORIEntry( - IN OUT PRTMP_ADAPTER pAd, - IN BA_ORI_ENTRY *pBAORIEntry); - -VOID BATableDeleteRECEntry( - IN OUT PRTMP_ADAPTER pAd, - IN BA_REC_ENTRY *pBARECEntry); - -VOID BATableTearORIEntry( - IN OUT PRTMP_ADAPTER pAd, - IN UCHAR TID, - IN UCHAR Wcid, - IN BOOLEAN bForceDelete, - IN BOOLEAN ALL); - -VOID BATableTearRECEntry( - IN OUT PRTMP_ADAPTER pAd, - IN UCHAR TID, - IN UCHAR WCID, - IN BOOLEAN ALL); -#endif // DOT11_N_SUPPORT // - -VOID BssEntrySet( - IN PRTMP_ADAPTER pAd, - OUT PBSS_ENTRY pBss, - IN PUCHAR pBssid, - IN CHAR Ssid[], - IN UCHAR SsidLen, - IN UCHAR BssType, - IN USHORT BeaconPeriod, - IN PCF_PARM CfParm, - IN USHORT AtimWin, - IN USHORT CapabilityInfo, - IN UCHAR SupRate[], - IN UCHAR SupRateLen, - IN UCHAR ExtRate[], - IN UCHAR ExtRateLen, - IN HT_CAPABILITY_IE *pHtCapability, - IN ADD_HT_INFO_IE *pAddHtInfo, // AP might use this additional ht info IE - IN UCHAR HtCapabilityLen, - IN UCHAR AddHtInfoLen, - IN UCHAR NewExtChanOffset, - IN UCHAR Channel, - IN CHAR Rssi, - IN LARGE_INTEGER TimeStamp, - IN UCHAR CkipFlag, - IN PEDCA_PARM pEdcaParm, - IN PQOS_CAPABILITY_PARM pQosCapability, - IN PQBSS_LOAD_PARM pQbssLoad, - IN USHORT LengthVIE, - IN PNDIS_802_11_VARIABLE_IEs pVIE); - -ULONG BssTableSetEntry( - IN PRTMP_ADAPTER pAd, - OUT PBSS_TABLE pTab, - IN PUCHAR pBssid, - IN CHAR Ssid[], - IN UCHAR SsidLen, - IN UCHAR BssType, - IN USHORT BeaconPeriod, - IN CF_PARM *CfParm, - IN USHORT AtimWin, - IN USHORT CapabilityInfo, - IN UCHAR SupRate[], - IN UCHAR SupRateLen, - IN UCHAR ExtRate[], - IN UCHAR ExtRateLen, - IN HT_CAPABILITY_IE *pHtCapability, - IN ADD_HT_INFO_IE *pAddHtInfo, // AP might use this additional ht info IE - IN UCHAR HtCapabilityLen, - IN UCHAR AddHtInfoLen, - IN UCHAR NewExtChanOffset, - IN UCHAR Channel, - IN CHAR Rssi, - IN LARGE_INTEGER TimeStamp, - IN UCHAR CkipFlag, - IN PEDCA_PARM pEdcaParm, - IN PQOS_CAPABILITY_PARM pQosCapability, - IN PQBSS_LOAD_PARM pQbssLoad, - IN USHORT LengthVIE, - IN PNDIS_802_11_VARIABLE_IEs pVIE); - -#ifdef DOT11_N_SUPPORT -VOID BATableInsertEntry( - IN PRTMP_ADAPTER pAd, - IN USHORT Aid, - IN USHORT TimeOutValue, - IN USHORT StartingSeq, - IN UCHAR TID, - IN UCHAR BAWinSize, - IN UCHAR OriginatorStatus, - IN BOOLEAN IsRecipient); - -#ifdef DOT11N_DRAFT3 -VOID Bss2040CoexistTimeOut( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); - - -VOID TriEventInit( - IN PRTMP_ADAPTER pAd); - -ULONG TriEventTableSetEntry( - IN PRTMP_ADAPTER pAd, - OUT TRIGGER_EVENT_TAB *Tab, - IN PUCHAR pBssid, - IN HT_CAPABILITY_IE *pHtCapability, - IN UCHAR HtCapabilityLen, - IN UCHAR RegClass, - IN UCHAR ChannelNo); - -VOID TriEventCounterMaintenance( - IN PRTMP_ADAPTER pAd); -#endif // DOT11N_DRAFT3 // -#endif // DOT11_N_SUPPORT // - -VOID BssTableSsidSort( - IN PRTMP_ADAPTER pAd, - OUT BSS_TABLE *OutTab, - IN CHAR Ssid[], - IN UCHAR SsidLen); - -VOID BssTableSortByRssi( - IN OUT BSS_TABLE *OutTab); - -VOID BssCipherParse( - IN OUT PBSS_ENTRY pBss); - -NDIS_STATUS MlmeQueueInit( - IN MLME_QUEUE *Queue); - -VOID MlmeQueueDestroy( - IN MLME_QUEUE *Queue); - -BOOLEAN MlmeEnqueue( - IN PRTMP_ADAPTER pAd, - IN ULONG Machine, - IN ULONG MsgType, - IN ULONG MsgLen, - IN VOID *Msg); - -BOOLEAN MlmeEnqueueForRecv( - IN PRTMP_ADAPTER pAd, - IN ULONG Wcid, - IN ULONG TimeStampHigh, - IN ULONG TimeStampLow, - IN UCHAR Rssi0, - IN UCHAR Rssi1, - IN UCHAR Rssi2, - IN ULONG MsgLen, - IN PVOID Msg, - IN UCHAR Signal); - - -BOOLEAN MlmeDequeue( - IN MLME_QUEUE *Queue, - OUT MLME_QUEUE_ELEM **Elem); - -VOID MlmeRestartStateMachine( - IN PRTMP_ADAPTER pAd); - -BOOLEAN MlmeQueueEmpty( - IN MLME_QUEUE *Queue); - -BOOLEAN MlmeQueueFull( - IN MLME_QUEUE *Queue); - -BOOLEAN MsgTypeSubst( - IN PRTMP_ADAPTER pAd, - IN PFRAME_802_11 pFrame, - OUT INT *Machine, - OUT INT *MsgType); - -VOID StateMachineInit( - IN STATE_MACHINE *Sm, - IN STATE_MACHINE_FUNC Trans[], - IN ULONG StNr, - IN ULONG MsgNr, - IN STATE_MACHINE_FUNC DefFunc, - IN ULONG InitState, - IN ULONG Base); - -VOID StateMachineSetAction( - IN STATE_MACHINE *S, - IN ULONG St, - ULONG Msg, - IN STATE_MACHINE_FUNC F); - -VOID StateMachinePerformAction( - IN PRTMP_ADAPTER pAd, - IN STATE_MACHINE *S, - IN MLME_QUEUE_ELEM *Elem); - -VOID Drop( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID AssocStateMachineInit( - IN PRTMP_ADAPTER pAd, - IN STATE_MACHINE *Sm, - OUT STATE_MACHINE_FUNC Trans[]); - -VOID ReassocTimeout( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); - -VOID AssocTimeout( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); - -VOID DisassocTimeout( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); - -//---------------------------------------------- -VOID MlmeDisassocReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID MlmeAssocReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID MlmeReassocReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID MlmeDisassocReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID PeerAssocRspAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID PeerReassocRspAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID PeerDisassocAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID DisassocTimeoutAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID AssocTimeoutAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID ReassocTimeoutAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID Cls3errAction( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pAddr); - -VOID SwitchBetweenWepAndCkip( - IN PRTMP_ADAPTER pAd); - -VOID InvalidStateWhenAssoc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID InvalidStateWhenReassoc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID InvalidStateWhenDisassociate( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -#ifdef RT2870 -VOID MlmeCntlConfirm( - IN PRTMP_ADAPTER pAd, - IN ULONG MsgType, - IN USHORT Msg); -#endif // RT2870 // - -VOID ComposePsPoll( - IN PRTMP_ADAPTER pAd); - -VOID ComposeNullFrame( - IN PRTMP_ADAPTER pAd); - -VOID AssocPostProc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pAddr2, - IN USHORT CapabilityInfo, - IN USHORT Aid, - IN UCHAR SupRate[], - IN UCHAR SupRateLen, - IN UCHAR ExtRate[], - IN UCHAR ExtRateLen, - IN PEDCA_PARM pEdcaParm, - IN HT_CAPABILITY_IE *pHtCapability, - IN UCHAR HtCapabilityLen, - IN ADD_HT_INFO_IE *pAddHtInfo); - -VOID AuthStateMachineInit( - IN PRTMP_ADAPTER pAd, - IN PSTATE_MACHINE sm, - OUT STATE_MACHINE_FUNC Trans[]); - -VOID AuthTimeout( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); - -VOID MlmeAuthReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID PeerAuthRspAtSeq2Action( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID PeerAuthRspAtSeq4Action( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID AuthTimeoutAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID Cls2errAction( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pAddr); - -VOID MlmeDeauthReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID InvalidStateWhenAuth( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -//============================================= - -VOID AuthRspStateMachineInit( - IN PRTMP_ADAPTER pAd, - IN PSTATE_MACHINE Sm, - IN STATE_MACHINE_FUNC Trans[]); - -VOID PeerDeauthAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID PeerAuthSimpleRspGenAndSend( - IN PRTMP_ADAPTER pAd, - IN PHEADER_802_11 pHdr80211, - IN USHORT Alg, - IN USHORT Seq, - IN USHORT Reason, - IN USHORT Status); - -// -// Private routines in dls.c -// - -#ifdef CONFIG_STA_SUPPORT -#ifdef QOS_DLS_SUPPORT -void DlsStateMachineInit( - IN PRTMP_ADAPTER pAd, - IN STATE_MACHINE *Sm, - OUT STATE_MACHINE_FUNC Trans[]); - -VOID MlmeDlsReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID PeerDlsReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID PeerDlsRspAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID MlmeDlsTearDownAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID PeerDlsTearDownAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID RTMPCheckDLSTimeOut( - IN PRTMP_ADAPTER pAd); - -BOOLEAN RTMPRcvFrameDLSCheck( - IN PRTMP_ADAPTER pAd, - IN PHEADER_802_11 pHeader, - IN ULONG Len, - IN PRT28XX_RXD_STRUC pRxD); - -INT RTMPCheckDLSFrame( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDA); - -VOID RTMPSendDLSTearDownFrame( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDA); - -NDIS_STATUS RTMPSendSTAKeyRequest( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDA); - -NDIS_STATUS RTMPSendSTAKeyHandShake( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDA); - -VOID DlsTimeoutAction( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); - -BOOLEAN MlmeDlsReqSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PRT_802_11_DLS *pDLS, - OUT PUSHORT pReason); - -INT Set_DlsEntryInfo_Display_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -MAC_TABLE_ENTRY *MacTableInsertDlsEntry( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pAddr, - IN UINT DlsEntryIdx); - -BOOLEAN MacTableDeleteDlsEntry( - IN PRTMP_ADAPTER pAd, - IN USHORT wcid, - IN PUCHAR pAddr); - -MAC_TABLE_ENTRY *DlsEntryTableLookup( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pAddr, - IN BOOLEAN bResetIdelCount); - -MAC_TABLE_ENTRY *DlsEntryTableLookupByWcid( - IN PRTMP_ADAPTER pAd, - IN UCHAR wcid, - IN PUCHAR pAddr, - IN BOOLEAN bResetIdelCount); - -INT Set_DlsAddEntry_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_DlsTearDownEntry_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); -#endif // QOS_DLS_SUPPORT // -#endif // CONFIG_STA_SUPPORT // - -#ifdef QOS_DLS_SUPPORT -BOOLEAN PeerDlsReqSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PUCHAR pDA, - OUT PUCHAR pSA, - OUT USHORT *pCapabilityInfo, - OUT USHORT *pDlsTimeout, - OUT UCHAR *pRatesLen, - OUT UCHAR Rates[], - OUT UCHAR *pHtCapabilityLen, - OUT HT_CAPABILITY_IE *pHtCapability); - -BOOLEAN PeerDlsRspSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PUCHAR pDA, - OUT PUCHAR pSA, - OUT USHORT *pCapabilityInfo, - OUT USHORT *pStatus, - OUT UCHAR *pRatesLen, - OUT UCHAR Rates[], - OUT UCHAR *pHtCapabilityLen, - OUT HT_CAPABILITY_IE *pHtCapability); - -BOOLEAN PeerDlsTearDownSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PUCHAR pDA, - OUT PUCHAR pSA, - OUT USHORT *pReason); -#endif // QOS_DLS_SUPPORT // - -//======================================== - -VOID SyncStateMachineInit( - IN PRTMP_ADAPTER pAd, - IN STATE_MACHINE *Sm, - OUT STATE_MACHINE_FUNC Trans[]); - -VOID BeaconTimeout( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); - -VOID ScanTimeout( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); - -VOID MlmeScanReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID InvalidStateWhenScan( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID InvalidStateWhenJoin( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID InvalidStateWhenStart( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID PeerBeacon( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID EnqueueProbeRequest( - IN PRTMP_ADAPTER pAd); - -BOOLEAN ScanRunning( - IN PRTMP_ADAPTER pAd); -//========================================= - -VOID MlmeCntlInit( - IN PRTMP_ADAPTER pAd, - IN STATE_MACHINE *S, - OUT STATE_MACHINE_FUNC Trans[]); - -VOID MlmeCntlMachinePerformAction( - IN PRTMP_ADAPTER pAd, - IN STATE_MACHINE *S, - IN MLME_QUEUE_ELEM *Elem); - -VOID CntlIdleProc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID CntlOidScanProc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID CntlOidSsidProc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM * Elem); - -VOID CntlOidRTBssidProc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM * Elem); - -VOID CntlMlmeRoamingProc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM * Elem); - -VOID CntlWaitDisassocProc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID CntlWaitJoinProc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID CntlWaitReassocProc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID CntlWaitStartProc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID CntlWaitAuthProc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID CntlWaitAuthProc2( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID CntlWaitAssocProc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -#ifdef QOS_DLS_SUPPORT -VOID CntlOidDLSSetupProc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); -#endif // QOS_DLS_SUPPORT // - -VOID LinkUp( - IN PRTMP_ADAPTER pAd, - IN UCHAR BssType); - -VOID LinkDown( - IN PRTMP_ADAPTER pAd, - IN BOOLEAN IsReqFromAP); - -VOID IterateOnBssTab( - IN PRTMP_ADAPTER pAd); - -VOID IterateOnBssTab2( - IN PRTMP_ADAPTER pAd);; - -VOID JoinParmFill( - IN PRTMP_ADAPTER pAd, - IN OUT MLME_JOIN_REQ_STRUCT *JoinReq, - IN ULONG BssIdx); - -VOID AssocParmFill( - IN PRTMP_ADAPTER pAd, - IN OUT MLME_ASSOC_REQ_STRUCT *AssocReq, - IN PUCHAR pAddr, - IN USHORT CapabilityInfo, - IN ULONG Timeout, - IN USHORT ListenIntv); - -VOID ScanParmFill( - IN PRTMP_ADAPTER pAd, - IN OUT MLME_SCAN_REQ_STRUCT *ScanReq, - IN CHAR Ssid[], - IN UCHAR SsidLen, - IN UCHAR BssType, - IN UCHAR ScanType); - -VOID DisassocParmFill( - IN PRTMP_ADAPTER pAd, - IN OUT MLME_DISASSOC_REQ_STRUCT *DisassocReq, - IN PUCHAR pAddr, - IN USHORT Reason); - -VOID StartParmFill( - IN PRTMP_ADAPTER pAd, - IN OUT MLME_START_REQ_STRUCT *StartReq, - IN CHAR Ssid[], - IN UCHAR SsidLen); - -VOID AuthParmFill( - IN PRTMP_ADAPTER pAd, - IN OUT MLME_AUTH_REQ_STRUCT *AuthReq, - IN PUCHAR pAddr, - IN USHORT Alg); - -VOID EnqueuePsPoll( - IN PRTMP_ADAPTER pAd); - -VOID EnqueueBeaconFrame( - IN PRTMP_ADAPTER pAd); - -VOID MlmeJoinReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID MlmeScanReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID MlmeStartReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID ScanTimeoutAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID BeaconTimeoutAtJoinAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID PeerBeaconAtScanAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID PeerBeaconAtJoinAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID PeerBeacon( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID PeerProbeReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID ScanNextChannel( - IN PRTMP_ADAPTER pAd); - -ULONG MakeIbssBeacon( - IN PRTMP_ADAPTER pAd); - -VOID CCXAdjacentAPReport( - IN PRTMP_ADAPTER pAd); - -BOOLEAN MlmeScanReqSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT UCHAR *BssType, - OUT CHAR ssid[], - OUT UCHAR *SsidLen, - OUT UCHAR *ScanType); - -BOOLEAN PeerBeaconAndProbeRspSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - IN UCHAR MsgChannel, - OUT PUCHAR pAddr2, - OUT PUCHAR pBssid, - OUT CHAR Ssid[], - OUT UCHAR *pSsidLen, - OUT UCHAR *pBssType, - OUT USHORT *pBeaconPeriod, - OUT UCHAR *pChannel, - OUT UCHAR *pNewChannel, - OUT LARGE_INTEGER *pTimestamp, - OUT CF_PARM *pCfParm, - OUT USHORT *pAtimWin, - OUT USHORT *pCapabilityInfo, - OUT UCHAR *pErp, - OUT UCHAR *pDtimCount, - OUT UCHAR *pDtimPeriod, - OUT UCHAR *pBcastFlag, - OUT UCHAR *pMessageToMe, - OUT UCHAR SupRate[], - OUT UCHAR *pSupRateLen, - OUT UCHAR ExtRate[], - OUT UCHAR *pExtRateLen, - OUT UCHAR *pCkipFlag, - OUT UCHAR *pAironetCellPowerLimit, - OUT PEDCA_PARM pEdcaParm, - OUT PQBSS_LOAD_PARM pQbssLoad, - OUT PQOS_CAPABILITY_PARM pQosCapability, - OUT ULONG *pRalinkIe, - OUT UCHAR *pHtCapabilityLen, -#ifdef CONFIG_STA_SUPPORT - OUT UCHAR *pPreNHtCapabilityLen, -#endif // CONFIG_STA_SUPPORT // - OUT HT_CAPABILITY_IE *pHtCapability, - OUT UCHAR *AddHtInfoLen, - OUT ADD_HT_INFO_IE *AddHtInfo, - OUT UCHAR *NewExtChannel, - OUT USHORT *LengthVIE, - OUT PNDIS_802_11_VARIABLE_IEs pVIE); - -BOOLEAN PeerAddBAReqActionSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *pMsg, - IN ULONG MsgLen, - OUT PUCHAR pAddr2); - -BOOLEAN PeerAddBARspActionSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *pMsg, - IN ULONG MsgLen); - -BOOLEAN PeerDelBAActionSanity( - IN PRTMP_ADAPTER pAd, - IN UCHAR Wcid, - IN VOID *pMsg, - IN ULONG MsgLen); - -BOOLEAN MlmeAssocReqSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PUCHAR pApAddr, - OUT USHORT *CapabilityInfo, - OUT ULONG *Timeout, - OUT USHORT *ListenIntv); - -BOOLEAN MlmeAuthReqSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PUCHAR pAddr, - OUT ULONG *Timeout, - OUT USHORT *Alg); - -BOOLEAN MlmeStartReqSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT CHAR Ssid[], - OUT UCHAR *Ssidlen); - -BOOLEAN PeerAuthSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PUCHAR pAddr, - OUT USHORT *Alg, - OUT USHORT *Seq, - OUT USHORT *Status, - OUT CHAR ChlgText[]); - -BOOLEAN PeerAssocRspSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *pMsg, - IN ULONG MsgLen, - OUT PUCHAR pAddr2, - OUT USHORT *pCapabilityInfo, - OUT USHORT *pStatus, - OUT USHORT *pAid, - OUT UCHAR SupRate[], - OUT UCHAR *pSupRateLen, - OUT UCHAR ExtRate[], - OUT UCHAR *pExtRateLen, - OUT HT_CAPABILITY_IE *pHtCapability, - OUT ADD_HT_INFO_IE *pAddHtInfo, // AP might use this additional ht info IE - OUT UCHAR *pHtCapabilityLen, - OUT UCHAR *pAddHtInfoLen, - OUT UCHAR *pNewExtChannelOffset, - OUT PEDCA_PARM pEdcaParm, - OUT UCHAR *pCkipFlag); - -BOOLEAN PeerDisassocSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PUCHAR pAddr2, - OUT USHORT *Reason); - -BOOLEAN PeerWpaMessageSanity( - IN PRTMP_ADAPTER pAd, - IN PEAPOL_PACKET pMsg, - IN ULONG MsgLen, - IN UCHAR MsgType, - IN MAC_TABLE_ENTRY *pEntry); - -BOOLEAN PeerDeauthSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PUCHAR pAddr2, - OUT USHORT *Reason); - -BOOLEAN PeerProbeReqSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PUCHAR pAddr2, - OUT CHAR Ssid[], - OUT UCHAR *pSsidLen); - -BOOLEAN GetTimBit( - IN CHAR *Ptr, - IN USHORT Aid, - OUT UCHAR *TimLen, - OUT UCHAR *BcastFlag, - OUT UCHAR *DtimCount, - OUT UCHAR *DtimPeriod, - OUT UCHAR *MessageToMe); - -UCHAR ChannelSanity( - IN PRTMP_ADAPTER pAd, - IN UCHAR channel); - -NDIS_802_11_NETWORK_TYPE NetworkTypeInUseSanity( - IN PBSS_ENTRY pBss); - -#if 0 // It's omitted -NDIS_STATUS RTMPWepKeySanity( - IN PRTMP_ADAPTER pAdapter, - IN PVOID pBuf); -#endif - -BOOLEAN MlmeDelBAReqSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen); - -BOOLEAN MlmeAddBAReqSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PUCHAR pAddr2); - -ULONG MakeOutgoingFrame( - OUT CHAR *Buffer, - OUT ULONG *Length, ...); - -VOID LfsrInit( - IN PRTMP_ADAPTER pAd, - IN ULONG Seed); - -UCHAR RandomByte( - IN PRTMP_ADAPTER pAd); - -VOID AsicUpdateAutoFallBackTable( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pTxRate); - -VOID MlmePeriodicExec( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); - -VOID LinkDownExec( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); - -VOID LinkUpExec( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); - -VOID STAMlmePeriodicExec( - PRTMP_ADAPTER pAd); - -VOID MlmeAutoScan( - IN PRTMP_ADAPTER pAd); - -VOID MlmeAutoReconnectLastSSID( - IN PRTMP_ADAPTER pAd); - -BOOLEAN MlmeValidateSSID( - IN PUCHAR pSsid, - IN UCHAR SsidLen); - -VOID MlmeCheckForRoaming( - IN PRTMP_ADAPTER pAd, - IN ULONG Now32); - -VOID MlmeCheckForFastRoaming( - IN PRTMP_ADAPTER pAd, - IN ULONG Now); - -VOID MlmeDynamicTxRateSwitching( - IN PRTMP_ADAPTER pAd); - -VOID MlmeSetTxRate( - IN PRTMP_ADAPTER pAd, - IN PMAC_TABLE_ENTRY pEntry, - IN PRTMP_TX_RATE_SWITCH pTxRate); - -VOID MlmeSelectTxRateTable( - IN PRTMP_ADAPTER pAd, - IN PMAC_TABLE_ENTRY pEntry, - IN PUCHAR *ppTable, - IN PUCHAR pTableSize, - IN PUCHAR pInitTxRateIdx); - -VOID MlmeCalculateChannelQuality( - IN PRTMP_ADAPTER pAd, - IN ULONG Now); - -VOID MlmeCheckPsmChange( - IN PRTMP_ADAPTER pAd, - IN ULONG Now32); - -VOID MlmeSetPsmBit( - IN PRTMP_ADAPTER pAd, - IN USHORT psm); - -VOID MlmeSetTxPreamble( - IN PRTMP_ADAPTER pAd, - IN USHORT TxPreamble); - -VOID UpdateBasicRateBitmap( - IN PRTMP_ADAPTER pAd); - -VOID MlmeUpdateTxRates( - IN PRTMP_ADAPTER pAd, - IN BOOLEAN bLinkUp, - IN UCHAR apidx); - -#ifdef DOT11_N_SUPPORT -VOID MlmeUpdateHtTxRates( - IN PRTMP_ADAPTER pAd, - IN UCHAR apidx); -#endif // DOT11_N_SUPPORT // - -VOID RTMPCheckRates( - IN PRTMP_ADAPTER pAd, - IN OUT UCHAR SupRate[], - IN OUT UCHAR *SupRateLen); - -#ifdef CONFIG_STA_SUPPORT -BOOLEAN RTMPCheckChannel( - IN PRTMP_ADAPTER pAd, - IN UCHAR CentralChannel, - IN UCHAR Channel); -#endif // CONFIG_STA_SUPPORT // - -BOOLEAN RTMPCheckHt( - IN PRTMP_ADAPTER pAd, - IN UCHAR Wcid, - IN OUT HT_CAPABILITY_IE *pHtCapability, - IN OUT ADD_HT_INFO_IE *pAddHtInfo); - -VOID StaQuickResponeForRateUpExec( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); - -VOID AsicBbpTuning1( - IN PRTMP_ADAPTER pAd); - -VOID AsicBbpTuning2( - IN PRTMP_ADAPTER pAd); - -VOID RTMPUpdateMlmeRate( - IN PRTMP_ADAPTER pAd); - -CHAR RTMPMaxRssi( - IN PRTMP_ADAPTER pAd, - IN CHAR Rssi0, - IN CHAR Rssi1, - IN CHAR Rssi2); - -VOID AsicEvaluateRxAnt( - IN PRTMP_ADAPTER pAd); - -VOID AsicRxAntEvalTimeout( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); - -VOID APSDPeriodicExec( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); - -BOOLEAN RTMPCheckEntryEnableAutoRateSwitch( - IN PRTMP_ADAPTER pAd, - IN PMAC_TABLE_ENTRY pEntry); - -UCHAR RTMPStaFixedTxMode( - IN PRTMP_ADAPTER pAd, - IN PMAC_TABLE_ENTRY pEntry); - -VOID RTMPUpdateLegacyTxSetting( - UCHAR fixed_tx_mode, - PMAC_TABLE_ENTRY pEntry); - -BOOLEAN RTMPAutoRateSwitchCheck( - IN PRTMP_ADAPTER pAd); - -NDIS_STATUS MlmeInit( - IN PRTMP_ADAPTER pAd); - -VOID MlmeHandler( - IN PRTMP_ADAPTER pAd); - -VOID MlmeHalt( - IN PRTMP_ADAPTER pAd); - -VOID MlmeResetRalinkCounters( - IN PRTMP_ADAPTER pAd); - -VOID BuildChannelList( - IN PRTMP_ADAPTER pAd); - -UCHAR FirstChannel( - IN PRTMP_ADAPTER pAd); - -UCHAR NextChannel( - IN PRTMP_ADAPTER pAd, - IN UCHAR channel); - -VOID ChangeToCellPowerLimit( - IN PRTMP_ADAPTER pAd, - IN UCHAR AironetCellPowerLimit); - -VOID RaiseClock( - IN PRTMP_ADAPTER pAd, - IN UINT32 *x); - -VOID LowerClock( - IN PRTMP_ADAPTER pAd, - IN UINT32 *x); - -USHORT ShiftInBits( - IN PRTMP_ADAPTER pAd); - -VOID ShiftOutBits( - IN PRTMP_ADAPTER pAd, - IN USHORT data, - IN USHORT count); - -VOID EEpromCleanup( - IN PRTMP_ADAPTER pAd); - -VOID EWDS( - IN PRTMP_ADAPTER pAd); - -VOID EWEN( - IN PRTMP_ADAPTER pAd); - -USHORT RTMP_EEPROM_READ16( - IN PRTMP_ADAPTER pAd, - IN USHORT Offset); - -VOID RTMP_EEPROM_WRITE16( - IN PRTMP_ADAPTER pAd, - IN USHORT Offset, - IN USHORT Data); - -// -// Prototypes of function definition in rtmp_tkip.c -// -VOID RTMPInitTkipEngine( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pTKey, - IN UCHAR KeyId, - IN PUCHAR pTA, - IN PUCHAR pMICKey, - IN PUCHAR pTSC, - OUT PULONG pIV16, - OUT PULONG pIV32); - -VOID RTMPInitMICEngine( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pKey, - IN PUCHAR pDA, - IN PUCHAR pSA, - IN UCHAR UserPriority, - IN PUCHAR pMICKey); - -BOOLEAN RTMPTkipCompareMICValue( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pSrc, - IN PUCHAR pDA, - IN PUCHAR pSA, - IN PUCHAR pMICKey, - IN UCHAR UserPriority, - IN UINT Len); - -VOID RTMPCalculateMICValue( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket, - IN PUCHAR pEncap, - IN PCIPHER_KEY pKey, - IN UCHAR apidx); - -BOOLEAN RTMPTkipCompareMICValueWithLLC( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pLLC, - IN PUCHAR pSrc, - IN PUCHAR pDA, - IN PUCHAR pSA, - IN PUCHAR pMICKey, - IN UINT Len); - -VOID RTMPTkipAppendByte( - IN PTKIP_KEY_INFO pTkip, - IN UCHAR uChar); - -VOID RTMPTkipAppend( - IN PTKIP_KEY_INFO pTkip, - IN PUCHAR pSrc, - IN UINT nBytes); - -VOID RTMPTkipGetMIC( - IN PTKIP_KEY_INFO pTkip); - -BOOLEAN RTMPSoftDecryptTKIP( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pData, - IN ULONG DataByteCnt, - IN UCHAR UserPriority, - IN PCIPHER_KEY pWpaKey); - -BOOLEAN RTMPSoftDecryptAES( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pData, - IN ULONG DataByteCnt, - IN PCIPHER_KEY pWpaKey); - -#if 0 // removed by AlbertY -NDIS_STATUS RTMPWPAAddKeyProc( - IN PRTMP_ADAPTER pAd, - IN PVOID pBuf); -#endif - -// -// Prototypes of function definition in cmm_info.c -// -NDIS_STATUS RTMPWPARemoveKeyProc( - IN PRTMP_ADAPTER pAd, - IN PVOID pBuf); - -VOID RTMPWPARemoveAllKeys( - IN PRTMP_ADAPTER pAd); - -BOOLEAN RTMPCheckStrPrintAble( - IN CHAR *pInPutStr, - IN UCHAR strLen); - -VOID RTMPSetPhyMode( - IN PRTMP_ADAPTER pAd, - IN ULONG phymode); - -VOID RTMPUpdateHTIE( - IN RT_HT_CAPABILITY *pRtHt, - IN UCHAR *pMcsSet, - OUT HT_CAPABILITY_IE *pHtCapability, - OUT ADD_HT_INFO_IE *pAddHtInfo); - -VOID RTMPAddWcidAttributeEntry( - IN PRTMP_ADAPTER pAd, - IN UCHAR BssIdx, - IN UCHAR KeyIdx, - IN UCHAR CipherAlg, - IN MAC_TABLE_ENTRY *pEntry); - -CHAR *GetEncryptType( - CHAR enc); - -CHAR *GetAuthMode( - CHAR auth); - -VOID RTMPIoctlGetSiteSurvey( - IN PRTMP_ADAPTER pAdapter, - IN struct iwreq *wrq); - -VOID RTMPIoctlGetMacTable( - IN PRTMP_ADAPTER pAd, - IN struct iwreq *wrq); - -VOID RTMPIndicateWPA2Status( - IN PRTMP_ADAPTER pAdapter); - -VOID RTMPOPModeSwitching( - IN PRTMP_ADAPTER pAd); - -#ifdef CONFIG_STA_SUPPORT -VOID RTMPAddBSSIDCipher( - IN PRTMP_ADAPTER pAd, - IN UCHAR Aid, - IN PNDIS_802_11_KEY pKey, - IN UCHAR CipherAlg); -#endif // CONFIG_STA_SUPPORT // - -#ifdef DOT11_N_SUPPORT -VOID RTMPSetHT( - IN PRTMP_ADAPTER pAd, - IN OID_SET_HT_PHYMODE *pHTPhyMode); - -VOID RTMPSetIndividualHT( - IN PRTMP_ADAPTER pAd, - IN UCHAR apidx); -#endif // DOT11_N_SUPPORT // - -VOID RTMPSendWirelessEvent( - IN PRTMP_ADAPTER pAd, - IN USHORT Event_flag, - IN PUCHAR pAddr, - IN UCHAR BssIdx, - IN CHAR Rssi); - -VOID NICUpdateCntlCounters( - IN PRTMP_ADAPTER pAd, - IN PHEADER_802_11 pHeader, - IN UCHAR SubType, - IN PRXWI_STRUC pRxWI); -// -// prototype in wpa.c -// -BOOLEAN WpaMsgTypeSubst( - IN UCHAR EAPType, - OUT INT *MsgType); - -VOID WpaPskStateMachineInit( - IN PRTMP_ADAPTER pAd, - IN STATE_MACHINE *S, - OUT STATE_MACHINE_FUNC Trans[]); - -VOID WpaEAPOLKeyAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID WpaPairMsg1Action( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID WpaPairMsg3Action( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID WpaGroupMsg1Action( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID WpaMacHeaderInit( - IN PRTMP_ADAPTER pAd, - IN OUT PHEADER_802_11 pHdr80211, - IN UCHAR wep, - IN PUCHAR pAddr1); - -VOID Wpa2PairMsg1Action( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID Wpa2PairMsg3Action( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -BOOLEAN ParseKeyData( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pKeyData, - IN UCHAR KeyDataLen, - IN UCHAR bPairewise); - -VOID RTMPToWirelessSta( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pHeader802_3, - IN UINT HdrLen, - IN PUCHAR pData, - IN UINT DataLen, - IN BOOLEAN is4wayFrame); - -VOID HMAC_SHA1( - IN UCHAR *text, - IN UINT text_len, - IN UCHAR *key, - IN UINT key_len, - IN UCHAR *digest); - -VOID PRF( - IN UCHAR *key, - IN INT key_len, - IN UCHAR *prefix, - IN INT prefix_len, - IN UCHAR *data, - IN INT data_len, - OUT UCHAR *output, - IN INT len); - -VOID CCKMPRF( - IN UCHAR *key, - IN INT key_len, - IN UCHAR *data, - IN INT data_len, - OUT UCHAR *output, - IN INT len); - -VOID WpaCountPTK( - IN PRTMP_ADAPTER pAd, - IN UCHAR *PMK, - IN UCHAR *ANonce, - IN UCHAR *AA, - IN UCHAR *SNonce, - IN UCHAR *SA, - OUT UCHAR *output, - IN UINT len); - -VOID GenRandom( - IN PRTMP_ADAPTER pAd, - IN UCHAR *macAddr, - OUT UCHAR *random); - -// -// prototype in aironet.c -// -VOID AironetStateMachineInit( - IN PRTMP_ADAPTER pAd, - IN STATE_MACHINE *S, - OUT STATE_MACHINE_FUNC Trans[]); - -VOID AironetMsgAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID AironetRequestAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID ChannelLoadRequestAction( - IN PRTMP_ADAPTER pAd, - IN UCHAR Index); - -VOID NoiseHistRequestAction( - IN PRTMP_ADAPTER pAd, - IN UCHAR Index); - -VOID BeaconRequestAction( - IN PRTMP_ADAPTER pAd, - IN UCHAR Index); - -VOID AironetReportAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID ChannelLoadReportAction( - IN PRTMP_ADAPTER pAd, - IN UCHAR Index); - -VOID NoiseHistReportAction( - IN PRTMP_ADAPTER pAd, - IN UCHAR Index); - -VOID AironetFinalReportAction( - IN PRTMP_ADAPTER pAd); - -VOID BeaconReportAction( - IN PRTMP_ADAPTER pAd, - IN UCHAR Index); - -VOID AironetAddBeaconReport( - IN PRTMP_ADAPTER pAd, - IN ULONG Index, - IN PMLME_QUEUE_ELEM pElem); - -VOID AironetCreateBeaconReportFromBssTable( - IN PRTMP_ADAPTER pAd); - -VOID DBGPRINT_TX_RING( - IN PRTMP_ADAPTER pAd, - IN UCHAR QueIdx); - -VOID DBGPRINT_RX_RING( - IN PRTMP_ADAPTER pAd); - -CHAR ConvertToRssi( - IN PRTMP_ADAPTER pAd, - IN CHAR Rssi, - IN UCHAR RssiNumber); - - -#ifdef DOT11N_DRAFT3 -VOID BuildEffectedChannelList( - IN PRTMP_ADAPTER pAd); -#endif // DOT11N_DRAFT3 // - - -VOID APAsicEvaluateRxAnt( - IN PRTMP_ADAPTER pAd); - - -VOID APAsicRxAntEvalTimeout( - IN PRTMP_ADAPTER pAd); - -// -// function prototype in cmm_wpa.c -// -BOOLEAN RTMPCheckWPAframe( - IN PRTMP_ADAPTER pAd, - IN PMAC_TABLE_ENTRY pEntry, - IN PUCHAR pData, - IN ULONG DataByteCount, - IN UCHAR FromWhichBSSID); - -VOID AES_GTK_KEY_UNWRAP( - IN UCHAR *key, - OUT UCHAR *plaintext, - IN UCHAR c_len, - IN UCHAR *ciphertext); - -BOOLEAN RTMPCheckRSNIE( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pData, - IN UCHAR DataLen, - IN MAC_TABLE_ENTRY *pEntry, - OUT UCHAR *Offset); - -BOOLEAN RTMPParseEapolKeyData( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pKeyData, - IN UCHAR KeyDataLen, - IN UCHAR GroupKeyIndex, - IN UCHAR MsgType, - IN BOOLEAN bWPA2, - IN MAC_TABLE_ENTRY *pEntry); - -VOID ConstructEapolMsg( - IN PRTMP_ADAPTER pAd, - IN UCHAR PeerAuthMode, - IN UCHAR PeerWepStatus, - IN UCHAR MyGroupKeyWepStatus, - IN UCHAR MsgType, - IN UCHAR DefaultKeyIdx, - IN UCHAR *ReplayCounter, - IN UCHAR *KeyNonce, - IN UCHAR *TxRSC, - IN UCHAR *PTK, - IN UCHAR *GTK, - IN UCHAR *RSNIE, - IN UCHAR RSNIE_Len, - OUT PEAPOL_PACKET pMsg); - -VOID CalculateMIC( - IN PRTMP_ADAPTER pAd, - IN UCHAR PeerWepStatus, - IN UCHAR *PTK, - OUT PEAPOL_PACKET pMsg); - -NDIS_STATUS RTMPSoftDecryptBroadCastData( - IN PRTMP_ADAPTER pAd, - IN RX_BLK *pRxBlk, - IN NDIS_802_11_ENCRYPTION_STATUS GroupCipher, - IN PCIPHER_KEY pShard_key); - -VOID ConstructEapolKeyData( - IN PRTMP_ADAPTER pAd, - IN UCHAR PeerAuthMode, - IN UCHAR PeerWepStatus, - IN UCHAR GroupKeyWepStatus, - IN UCHAR MsgType, - IN UCHAR DefaultKeyIdx, - IN BOOLEAN bWPA2Capable, - IN UCHAR *PTK, - IN UCHAR *GTK, - IN UCHAR *RSNIE, - IN UCHAR RSNIE_LEN, - OUT PEAPOL_PACKET pMsg); - -VOID RTMPMakeRSNIE( - IN PRTMP_ADAPTER pAd, - IN UINT AuthMode, - IN UINT WepStatus, - IN UCHAR apidx); - -// -// function prototype in ap_wpa.c -// - -BOOLEAN APWpaMsgTypeSubst( - IN UCHAR EAPType, - OUT INT *MsgType) ; - -MAC_TABLE_ENTRY *PACInquiry( - IN PRTMP_ADAPTER pAd, - IN ULONG Wcid); - -BOOLEAN RTMPCheckMcast( - IN PRTMP_ADAPTER pAd, - IN PEID_STRUCT eid_ptr, - IN MAC_TABLE_ENTRY *pEntry); - -BOOLEAN RTMPCheckUcast( - IN PRTMP_ADAPTER pAd, - IN PEID_STRUCT eid_ptr, - IN MAC_TABLE_ENTRY *pEntry); - -BOOLEAN RTMPCheckAUTH( - IN PRTMP_ADAPTER pAd, - IN PEID_STRUCT eid_ptr, - IN MAC_TABLE_ENTRY *pEntry); - -VOID WPAStart4WayHS( - IN PRTMP_ADAPTER pAd, - IN MAC_TABLE_ENTRY *pEntry, - IN ULONG TimeInterval); - -VOID WPAStart2WayGroupHS( - IN PRTMP_ADAPTER pAd, - IN MAC_TABLE_ENTRY *pEntry); - -VOID APWpaEAPPacketAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID APWpaEAPOLStartAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID APWpaEAPOLLogoffAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID APWpaEAPOLKeyAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID APWpaEAPOLASFAlertAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID HandleCounterMeasure( - IN PRTMP_ADAPTER pAd, - IN MAC_TABLE_ENTRY *pEntry); - -VOID PeerPairMsg2Action( - IN PRTMP_ADAPTER pAd, - IN MAC_TABLE_ENTRY *pEntry, - IN MLME_QUEUE_ELEM *Elem); - -VOID PeerPairMsg4Action( - IN PRTMP_ADAPTER pAd, - IN MAC_TABLE_ENTRY *pEntry, - IN MLME_QUEUE_ELEM *Elem); - -VOID CMTimerExec( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); - -VOID WPARetryExec( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); - -VOID EnqueueStartForPSKExec( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); - -VOID RTMPHandleSTAKey( - IN PRTMP_ADAPTER pAdapter, - IN MAC_TABLE_ENTRY *pEntry, - IN MLME_QUEUE_ELEM *Elem); - -#if 0 // merge into PeerPairMsg4Action -VOID Wpa1PeerPairMsg4Action( - IN PRTMP_ADAPTER pAd, - IN MAC_TABLE_ENTRY *pEntry, - IN MLME_QUEUE_ELEM *Elem); - -VOID Wpa2PeerPairMsg4Action( - IN PRTMP_ADAPTER pAd, - IN PMAC_TABLE_ENTRY pEntry, - IN MLME_QUEUE_ELEM *Elem); -#endif // 0 // - -VOID PeerGroupMsg2Action( - IN PRTMP_ADAPTER pAd, - IN PMAC_TABLE_ENTRY pEntry, - IN VOID *Msg, - IN UINT MsgLen); - -#if 0 // replaced by WPAStart2WayGroupHS -NDIS_STATUS APWpaHardTransmit( - IN PRTMP_ADAPTER pAd, - IN PMAC_TABLE_ENTRY pEntry); -#endif // 0 // - -VOID PairDisAssocAction( - IN PRTMP_ADAPTER pAd, - IN PMAC_TABLE_ENTRY pEntry, - IN USHORT Reason); - -VOID MlmeDeAuthAction( - IN PRTMP_ADAPTER pAd, - IN PMAC_TABLE_ENTRY pEntry, - IN USHORT Reason); - -VOID GREKEYPeriodicExec( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); - -VOID CountGTK( - IN UCHAR *PMK, - IN UCHAR *GNonce, - IN UCHAR *AA, - OUT UCHAR *output, - IN UINT len); - -VOID GetSmall( - IN PVOID pSrc1, - IN PVOID pSrc2, - OUT PUCHAR out, - IN ULONG Length); - -VOID GetLarge( - IN PVOID pSrc1, - IN PVOID pSrc2, - OUT PUCHAR out, - IN ULONG Length); - -VOID APGenRandom( - IN PRTMP_ADAPTER pAd, - OUT UCHAR *random); - -VOID AES_GTK_KEY_WRAP( - IN UCHAR *key, - IN UCHAR *plaintext, - IN UCHAR p_len, - OUT UCHAR *ciphertext); - -VOID WpaSend( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR pPacket, - IN ULONG Len); - -VOID APToWirelessSta( - IN PRTMP_ADAPTER pAd, - IN MAC_TABLE_ENTRY *pEntry, - IN PUCHAR pHeader802_3, - IN UINT HdrLen, - IN PUCHAR pData, - IN UINT DataLen, - IN BOOLEAN bClearFrame); - -VOID RTMPAddPMKIDCache( - IN PRTMP_ADAPTER pAd, - IN INT apidx, - IN PUCHAR pAddr, - IN UCHAR *PMKID, - IN UCHAR *PMK); - -INT RTMPSearchPMKIDCache( - IN PRTMP_ADAPTER pAd, - IN INT apidx, - IN PUCHAR pAddr); - -VOID RTMPDeletePMKIDCache( - IN PRTMP_ADAPTER pAd, - IN INT apidx, - IN INT idx); - -VOID RTMPMaintainPMKIDCache( - IN PRTMP_ADAPTER pAd); - -VOID RTMPSendTriggerFrame( - IN PRTMP_ADAPTER pAd, - IN PVOID pBuffer, - IN ULONG Length, - IN UCHAR TxRate, - IN BOOLEAN bQosNull); - - -//typedef void (*TIMER_FUNCTION)(unsigned long); - - -/* timeout -- ms */ -VOID RTMP_SetPeriodicTimer( - IN NDIS_MINIPORT_TIMER *pTimer, - IN unsigned long timeout); - -VOID RTMP_OS_Init_Timer( - IN PRTMP_ADAPTER pAd, - IN NDIS_MINIPORT_TIMER *pTimer, - IN TIMER_FUNCTION function, - IN PVOID data); - -VOID RTMP_OS_Add_Timer( - IN NDIS_MINIPORT_TIMER *pTimer, - IN unsigned long timeout); - -VOID RTMP_OS_Mod_Timer( - IN NDIS_MINIPORT_TIMER *pTimer, - IN unsigned long timeout); - - -VOID RTMP_OS_Del_Timer( - IN NDIS_MINIPORT_TIMER *pTimer, - OUT BOOLEAN *pCancelled); - - -VOID RTMP_OS_Release_Packet( - IN PRTMP_ADAPTER pAd, - IN PQUEUE_ENTRY pEntry); - -VOID RTMPusecDelay( - IN ULONG usec); - -NDIS_STATUS os_alloc_mem( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR *mem, - IN ULONG size); - -NDIS_STATUS os_free_mem( - IN PRTMP_ADAPTER pAd, - IN PUCHAR mem); - - -void RTMP_AllocateSharedMemory( - IN PRTMP_ADAPTER pAd, - IN ULONG Length, - IN BOOLEAN Cached, - OUT PVOID *VirtualAddress, - OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress); - -VOID RTMPFreeTxRxRingMemory( - IN PRTMP_ADAPTER pAd); - -NDIS_STATUS AdapterBlockAllocateMemory( - IN PVOID handle, - OUT PVOID *ppAd); - -void RTMP_AllocateTxDescMemory( - IN PRTMP_ADAPTER pAd, - IN UINT Index, - IN ULONG Length, - IN BOOLEAN Cached, - OUT PVOID *VirtualAddress, - OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress); - -void RTMP_AllocateFirstTxBuffer( - IN PRTMP_ADAPTER pAd, - IN UINT Index, - IN ULONG Length, - IN BOOLEAN Cached, - OUT PVOID *VirtualAddress, - OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress); - -void RTMP_AllocateMgmtDescMemory( - IN PRTMP_ADAPTER pAd, - IN ULONG Length, - IN BOOLEAN Cached, - OUT PVOID *VirtualAddress, - OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress); - -void RTMP_AllocateRxDescMemory( - IN PRTMP_ADAPTER pAd, - IN ULONG Length, - IN BOOLEAN Cached, - OUT PVOID *VirtualAddress, - OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress); - -PNDIS_PACKET RTMP_AllocateRxPacketBuffer( - IN PRTMP_ADAPTER pAd, - IN ULONG Length, - IN BOOLEAN Cached, - OUT PVOID *VirtualAddress, - OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress); - -PNDIS_PACKET RTMP_AllocateTxPacketBuffer( - IN PRTMP_ADAPTER pAd, - IN ULONG Length, - IN BOOLEAN Cached, - OUT PVOID *VirtualAddress); - -PNDIS_PACKET RTMP_AllocateFragPacketBuffer( - IN PRTMP_ADAPTER pAd, - IN ULONG Length); - -void RTMP_QueryPacketInfo( - IN PNDIS_PACKET pPacket, - OUT PACKET_INFO *pPacketInfo, - OUT PUCHAR *pSrcBufVA, - OUT UINT *pSrcBufLen); - -void RTMP_QueryNextPacketInfo( - IN PNDIS_PACKET *ppPacket, - OUT PACKET_INFO *pPacketInfo, - OUT PUCHAR *pSrcBufVA, - OUT UINT *pSrcBufLen); - - -BOOLEAN RTMP_FillTxBlkInfo( - IN RTMP_ADAPTER *pAd, - IN TX_BLK *pTxBlk); - - -PRTMP_SCATTER_GATHER_LIST -rt_get_sg_list_from_packet(PNDIS_PACKET pPacket, RTMP_SCATTER_GATHER_LIST *sg); - - - void announce_802_3_packet( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket); - - -UINT BA_Reorder_AMSDU_Annnounce( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket); - - -UINT Handle_AMSDU_Packet( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pData, - IN ULONG DataSize, - IN UCHAR FromWhichBSSID); - - -void convert_802_11_to_802_3_packet( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket, - IN PUCHAR p8023hdr, - IN PUCHAR pData, - IN ULONG DataSize, - IN UCHAR FromWhichBSSID); - - -PNET_DEV get_netdev_from_bssid( - IN PRTMP_ADAPTER pAd, - IN UCHAR FromWhichBSSID); - - -PNDIS_PACKET duplicate_pkt( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pHeader802_3, - IN UINT HdrLen, - IN PUCHAR pData, - IN ULONG DataSize, - IN UCHAR FromWhichBSSID); - - -PNDIS_PACKET duplicate_pkt_with_TKIP_MIC( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pOldPkt); - -PNDIS_PACKET duplicate_pkt_with_VLAN( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pHeader802_3, - IN UINT HdrLen, - IN PUCHAR pData, - IN ULONG DataSize, - IN UCHAR FromWhichBSSID); - -PNDIS_PACKET duplicate_pkt_with_WPI( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket, - IN UINT32 ext_head_len, - IN UINT32 ext_tail_len); - -UCHAR VLAN_8023_Header_Copy( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pHeader802_3, - IN UINT HdrLen, - OUT PUCHAR pData, - IN UCHAR FromWhichBSSID); - -#ifdef DOT11_N_SUPPORT -void ba_flush_reordering_timeout_mpdus( - IN PRTMP_ADAPTER pAd, - IN PBA_REC_ENTRY pBAEntry, - IN ULONG Now32); - - -VOID BAOriSessionSetUp( - IN PRTMP_ADAPTER pAd, - IN MAC_TABLE_ENTRY *pEntry, - IN UCHAR TID, - IN USHORT TimeOut, - IN ULONG DelayTime, - IN BOOLEAN isForced); - -VOID BASessionTearDownALL( - IN OUT PRTMP_ADAPTER pAd, - IN UCHAR Wcid); -#endif // DOT11_N_SUPPORT // - -BOOLEAN OS_Need_Clone_Packet(void); - - -VOID build_tx_packet( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket, - IN PUCHAR pFrame, - IN ULONG FrameLen); - - -VOID BAOriSessionTearDown( - IN OUT PRTMP_ADAPTER pAd, - IN UCHAR Wcid, - IN UCHAR TID, - IN BOOLEAN bPassive, - IN BOOLEAN bForceSend); - -VOID BARecSessionTearDown( - IN OUT PRTMP_ADAPTER pAd, - IN UCHAR Wcid, - IN UCHAR TID, - IN BOOLEAN bPassive); - -BOOLEAN ba_reordering_resource_init(PRTMP_ADAPTER pAd, int num); -void ba_reordering_resource_release(PRTMP_ADAPTER pAd); - -ULONG AutoChBssInsertEntry( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pBssid, - IN CHAR Ssid[], - IN UCHAR SsidLen, - IN UCHAR ChannelNo, - IN CHAR Rssi); - -void AutoChBssTableInit( - IN PRTMP_ADAPTER pAd); - -void ChannelInfoInit( - IN PRTMP_ADAPTER pAd); - -void AutoChBssTableDestroy( - IN PRTMP_ADAPTER pAd); - -void ChannelInfoDestroy( - IN PRTMP_ADAPTER pAd); - -UCHAR New_ApAutoSelectChannel( - IN PRTMP_ADAPTER pAd); - -BOOLEAN rtstrmactohex( - IN char *s1, - IN char *s2); - -BOOLEAN rtstrcasecmp( - IN char *s1, - IN char *s2); - -char *rtstrstruncasecmp( - IN char *s1, - IN char *s2); - -char *rtstrstr( - IN const char * s1, - IN const char * s2); - -char *rstrtok( - IN char * s, - IN const char * ct); - -int rtinet_aton( - const char *cp, - unsigned int *addr); - -////////// common ioctl functions ////////// -INT Set_DriverVersion_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_CountryRegion_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_CountryRegionABand_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_WirelessMode_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_Channel_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ShortSlot_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_TxPower_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_BGProtection_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_TxPreamble_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_RTSThreshold_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_FragThreshold_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_TxBurst_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -#ifdef AGGREGATION_SUPPORT -INT Set_PktAggregate_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); -#endif - -INT Set_IEEE80211H_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -#ifdef DBG -INT Set_Debug_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); -#endif - -INT Show_DescInfo_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ResetStatCounter_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -#ifdef DOT11_N_SUPPORT -INT Set_BASetup_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_BADecline_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_BAOriTearDown_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_BARecTearDown_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_HtBw_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_HtMcs_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_HtGi_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_HtOpMode_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_HtStbc_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_HtHtc_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_HtExtcha_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_HtMpduDensity_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_HtBaWinSize_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_HtRdg_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_HtLinkAdapt_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_HtAmsdu_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_HtAutoBa_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_HtProtect_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_HtMimoPs_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - - -INT Set_ForceShortGI_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ForceGF_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT SetCommonHT( - IN PRTMP_ADAPTER pAd); - -INT Set_SendPSMPAction_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_HtMIMOPSmode_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - - -INT Set_HtTxBASize_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); -#endif // DOT11_N_SUPPORT // - - - -#ifdef CONFIG_STA_SUPPORT -//Dls , kathy -VOID RTMPSendDLSTearDownFrame( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDA); - -#ifdef DOT11_N_SUPPORT -//Block ACK -VOID QueryBATABLE( - IN PRTMP_ADAPTER pAd, - OUT PQUERYBA_TABLE pBAT); -#endif // DOT11_N_SUPPORT // - -#ifdef WPA_SUPPLICANT_SUPPORT -INT WpaCheckEapCode( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pFrame, - IN USHORT FrameLen, - IN USHORT OffSet); - -VOID WpaSendMicFailureToWpaSupplicant( - IN PRTMP_ADAPTER pAd, - IN BOOLEAN bUnicast); - -VOID SendAssocIEsToWpaSupplicant( - IN PRTMP_ADAPTER pAd); -#endif // WPA_SUPPLICANT_SUPPORT // - -#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT -int wext_notify_event_assoc( - IN RTMP_ADAPTER *pAd); -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // - -#endif // CONFIG_STA_SUPPORT // - - - -#ifdef DOT11_N_SUPPORT -VOID Handle_BSS_Width_Trigger_Events( - IN PRTMP_ADAPTER pAd); - -void build_ext_channel_switch_ie( - IN PRTMP_ADAPTER pAd, - IN HT_EXT_CHANNEL_SWITCH_ANNOUNCEMENT_IE *pIE); -#endif // DOT11_N_SUPPORT // - - -BOOLEAN APRxDoneInterruptHandle( - IN PRTMP_ADAPTER pAd); - -BOOLEAN STARxDoneInterruptHandle( - IN PRTMP_ADAPTER pAd, - IN BOOLEAN argc); - -#ifdef DOT11_N_SUPPORT -// AMPDU packet indication -VOID Indicate_AMPDU_Packet( - IN PRTMP_ADAPTER pAd, - IN RX_BLK *pRxBlk, - IN UCHAR FromWhichBSSID); - -// AMSDU packet indication -VOID Indicate_AMSDU_Packet( - IN PRTMP_ADAPTER pAd, - IN RX_BLK *pRxBlk, - IN UCHAR FromWhichBSSID); -#endif // DOT11_N_SUPPORT // - -// Normal legacy Rx packet indication -VOID Indicate_Legacy_Packet( - IN PRTMP_ADAPTER pAd, - IN RX_BLK *pRxBlk, - IN UCHAR FromWhichBSSID); - -VOID Indicate_EAPOL_Packet( - IN PRTMP_ADAPTER pAd, - IN RX_BLK *pRxBlk, - IN UCHAR FromWhichBSSID); - -void update_os_packet_info( - IN PRTMP_ADAPTER pAd, - IN RX_BLK *pRxBlk, - IN UCHAR FromWhichBSSID); - -void wlan_802_11_to_802_3_packet( - IN PRTMP_ADAPTER pAd, - IN RX_BLK *pRxBlk, - IN PUCHAR pHeader802_3, - IN UCHAR FromWhichBSSID); - -UINT deaggregate_AMSDU_announce( - IN PRTMP_ADAPTER pAd, - PNDIS_PACKET pPacket, - IN PUCHAR pData, - IN ULONG DataSize); - - -#ifdef CONFIG_STA_SUPPORT -// remove LLC and get 802_3 Header -#define RTMP_802_11_REMOVE_LLC_AND_CONVERT_TO_802_3(_pRxBlk, _pHeader802_3) \ -{ \ - PUCHAR _pRemovedLLCSNAP = NULL, _pDA, _pSA; \ - \ - if (RX_BLK_TEST_FLAG(_pRxBlk, fRX_MESH)) \ - { \ - _pDA = _pRxBlk->pHeader->Addr3; \ - _pSA = (PUCHAR)_pRxBlk->pHeader + sizeof(HEADER_802_11); \ - } \ - else \ - { \ - if (RX_BLK_TEST_FLAG(_pRxBlk, fRX_INFRA)) \ - { \ - _pDA = _pRxBlk->pHeader->Addr1; \ - if (RX_BLK_TEST_FLAG(_pRxBlk, fRX_DLS)) \ - _pSA = _pRxBlk->pHeader->Addr2; \ - else \ - _pSA = _pRxBlk->pHeader->Addr3; \ - } \ - else \ - { \ - _pDA = _pRxBlk->pHeader->Addr1; \ - _pSA = _pRxBlk->pHeader->Addr2; \ - } \ - } \ - \ - CONVERT_TO_802_3(_pHeader802_3, _pDA, _pSA, _pRxBlk->pData, \ - _pRxBlk->DataSize, _pRemovedLLCSNAP); \ -} -#endif // CONFIG_STA_SUPPORT // - - -BOOLEAN APFowardWirelessStaToWirelessSta( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket, - IN ULONG FromWhichBSSID); - -VOID Announce_or_Forward_802_3_Packet( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket, - IN UCHAR FromWhichBSSID); - -VOID Sta_Announce_or_Forward_802_3_Packet( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket, - IN UCHAR FromWhichBSSID); - - -#ifdef CONFIG_STA_SUPPORT -#define ANNOUNCE_OR_FORWARD_802_3_PACKET(_pAd, _pPacket, _FromWhichBSS)\ - Sta_Announce_or_Forward_802_3_Packet(_pAd, _pPacket, _FromWhichBSS); - //announce_802_3_packet(_pAd, _pPacket); -#endif // CONFIG_STA_SUPPORT // - - -PNDIS_PACKET DuplicatePacket( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket, - IN UCHAR FromWhichBSSID); - - -PNDIS_PACKET ClonePacket( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket, - IN PUCHAR pData, - IN ULONG DataSize); - - -// Normal, AMPDU or AMSDU -VOID CmmRxnonRalinkFrameIndicate( - IN PRTMP_ADAPTER pAd, - IN RX_BLK *pRxBlk, - IN UCHAR FromWhichBSSID); - -VOID CmmRxRalinkFrameIndicate( - IN PRTMP_ADAPTER pAd, - IN MAC_TABLE_ENTRY *pEntry, - IN RX_BLK *pRxBlk, - IN UCHAR FromWhichBSSID); - -VOID Update_Rssi_Sample( - IN PRTMP_ADAPTER pAd, - IN RSSI_SAMPLE *pRssi, - IN PRXWI_STRUC pRxWI); - -PNDIS_PACKET GetPacketFromRxRing( - IN PRTMP_ADAPTER pAd, - OUT PRT28XX_RXD_STRUC pSaveRxD, - OUT BOOLEAN *pbReschedule, - IN OUT UINT32 *pRxPending); - -PNDIS_PACKET RTMPDeFragmentDataFrame( - IN PRTMP_ADAPTER pAd, - IN RX_BLK *pRxBlk); - -//////////////////////////////////////// - - - - - -#ifdef SNMP_SUPPORT -//for snmp , kathy -typedef struct _DefaultKeyIdxValue -{ - UCHAR KeyIdx; - UCHAR Value[16]; -} DefaultKeyIdxValue, *PDefaultKeyIdxValue; -#endif - - -#ifdef CONFIG_STA_SUPPORT -enum { - DIDmsg_lnxind_wlansniffrm = 0x00000044, - DIDmsg_lnxind_wlansniffrm_hosttime = 0x00010044, - DIDmsg_lnxind_wlansniffrm_mactime = 0x00020044, - DIDmsg_lnxind_wlansniffrm_channel = 0x00030044, - DIDmsg_lnxind_wlansniffrm_rssi = 0x00040044, - DIDmsg_lnxind_wlansniffrm_sq = 0x00050044, - DIDmsg_lnxind_wlansniffrm_signal = 0x00060044, - DIDmsg_lnxind_wlansniffrm_noise = 0x00070044, - DIDmsg_lnxind_wlansniffrm_rate = 0x00080044, - DIDmsg_lnxind_wlansniffrm_istx = 0x00090044, - DIDmsg_lnxind_wlansniffrm_frmlen = 0x000A0044 -}; -enum { - P80211ENUM_msgitem_status_no_value = 0x00 -}; -enum { - P80211ENUM_truth_false = 0x00, - P80211ENUM_truth_true = 0x01 -}; - -/* Definition from madwifi */ -typedef struct { - UINT32 did; - UINT16 status; - UINT16 len; - UINT32 data; -} p80211item_uint32_t; - -typedef struct { - UINT32 msgcode; - UINT32 msglen; -#define WLAN_DEVNAMELEN_MAX 16 - UINT8 devname[WLAN_DEVNAMELEN_MAX]; - p80211item_uint32_t hosttime; - p80211item_uint32_t mactime; - p80211item_uint32_t channel; - p80211item_uint32_t rssi; - p80211item_uint32_t sq; - p80211item_uint32_t signal; - p80211item_uint32_t noise; - p80211item_uint32_t rate; - p80211item_uint32_t istx; - p80211item_uint32_t frmlen; -} wlan_ng_prism2_header; - -/* The radio capture header precedes the 802.11 header. */ -typedef struct PACKED _ieee80211_radiotap_header { - UINT8 it_version; /* Version 0. Only increases - * for drastic changes, - * introduction of compatible - * new fields does not count. - */ - UINT8 it_pad; - UINT16 it_len; /* length of the whole - * header in bytes, including - * it_version, it_pad, - * it_len, and data fields. - */ - UINT32 it_present; /* A bitmap telling which - * fields are present. Set bit 31 - * (0x80000000) to extend the - * bitmap by another 32 bits. - * Additional extensions are made - * by setting bit 31. - */ -}ieee80211_radiotap_header ; - -enum ieee80211_radiotap_type { - IEEE80211_RADIOTAP_TSFT = 0, - IEEE80211_RADIOTAP_FLAGS = 1, - IEEE80211_RADIOTAP_RATE = 2, - IEEE80211_RADIOTAP_CHANNEL = 3, - IEEE80211_RADIOTAP_FHSS = 4, - IEEE80211_RADIOTAP_DBM_ANTSIGNAL = 5, - IEEE80211_RADIOTAP_DBM_ANTNOISE = 6, - IEEE80211_RADIOTAP_LOCK_QUALITY = 7, - IEEE80211_RADIOTAP_TX_ATTENUATION = 8, - IEEE80211_RADIOTAP_DB_TX_ATTENUATION = 9, - IEEE80211_RADIOTAP_DBM_TX_POWER = 10, - IEEE80211_RADIOTAP_ANTENNA = 11, - IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12, - IEEE80211_RADIOTAP_DB_ANTNOISE = 13 -}; - -#define WLAN_RADIOTAP_PRESENT ( \ - (1 << IEEE80211_RADIOTAP_TSFT) | \ - (1 << IEEE80211_RADIOTAP_FLAGS) | \ - (1 << IEEE80211_RADIOTAP_RATE) | \ - 0) - -typedef struct _wlan_radiotap_header { - ieee80211_radiotap_header wt_ihdr; - INT64 wt_tsft; - UINT8 wt_flags; - UINT8 wt_rate; -} wlan_radiotap_header; -/* Definition from madwifi */ - -void send_monitor_packets( - IN PRTMP_ADAPTER pAd, - IN RX_BLK *pRxBlk); - -#if WIRELESS_EXT >= 12 -// This function will be called when query /proc -struct iw_statistics *rt28xx_get_wireless_stats( - IN struct net_device *net_dev); -#endif - -VOID RTMPSetDesiredRates( - IN PRTMP_ADAPTER pAdapter, - IN LONG Rates); -#endif // CONFIG_STA_SUPPORT // - -INT Set_FixedTxMode_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -#ifdef CONFIG_APSTA_MIXED_SUPPORT -INT Set_OpMode_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); -#endif // CONFIG_APSTA_MIXED_SUPPORT // - -static inline char* GetPhyMode( - int Mode) -{ - switch(Mode) - { - case MODE_CCK: - return "CCK"; - - case MODE_OFDM: - return "OFDM"; -#ifdef DOT11_N_SUPPORT - case MODE_HTMIX: - return "HTMIX"; - - case MODE_HTGREENFIELD: - return "GREEN"; -#endif // DOT11_N_SUPPORT // - default: - return "N/A"; - } -} - - -static inline char* GetBW( - int BW) -{ - switch(BW) - { - case BW_10: - return "10M"; - - case BW_20: - return "20M"; -#ifdef DOT11_N_SUPPORT - case BW_40: - return "40M"; -#endif // DOT11_N_SUPPORT // - default: - return "N/A"; - } -} - - -VOID RT28xxThreadTerminate( - IN RTMP_ADAPTER *pAd); - -BOOLEAN RT28XXChipsetCheck( - IN void *_dev_p); - -BOOLEAN RT28XXNetDevInit( - IN void *_dev_p, - IN struct net_device *net_dev, - IN RTMP_ADAPTER *pAd); - -BOOLEAN RT28XXProbePostConfig( - IN void *_dev_p, - IN RTMP_ADAPTER *pAd, - IN INT32 argc); - -VOID RT28XXDMADisable( - IN RTMP_ADAPTER *pAd); - -VOID RT28XXDMAEnable( - IN RTMP_ADAPTER *pAd); - -VOID RT28xx_UpdateBeaconToAsic( - IN RTMP_ADAPTER * pAd, - IN INT apidx, - IN ULONG BeaconLen, - IN ULONG UpdatePos); - -INT rt28xx_ioctl( - IN struct net_device *net_dev, - IN OUT struct ifreq *rq, - IN INT cmd); - - -#ifdef CONFIG_STA_SUPPORT -INT rt28xx_sta_ioctl( - IN struct net_device *net_dev, - IN OUT struct ifreq *rq, - IN INT cmd); -#endif // CONFIG_STA_SUPPORT // - -BOOLEAN RT28XXSecurityKeyAdd( - IN PRTMP_ADAPTER pAd, - IN ULONG apidx, - IN ULONG KeyIdx, - IN MAC_TABLE_ENTRY *pEntry); - -//////////////////////////////////////// -PNDIS_PACKET GetPacketFromRxRing( - IN PRTMP_ADAPTER pAd, - OUT PRT28XX_RXD_STRUC pSaveRxD, - OUT BOOLEAN *pbReschedule, - IN OUT UINT32 *pRxPending); - - -void kill_thread_task(PRTMP_ADAPTER pAd); - -void tbtt_tasklet(unsigned long data); - - -VOID AsicTurnOffRFClk( - IN PRTMP_ADAPTER pAd, - IN UCHAR Channel); - -VOID AsicTurnOnRFClk( - IN PRTMP_ADAPTER pAd, - IN UCHAR Channel); - -#ifdef RT2870 -// -// Function Prototype in rtusb_bulk.c -// -VOID RTUSBInitTxDesc( - IN PRTMP_ADAPTER pAd, - IN PTX_CONTEXT pTxContext, - IN UCHAR BulkOutPipeId, - IN usb_complete_t Func); - -VOID RTUSBInitHTTxDesc( - IN PRTMP_ADAPTER pAd, - IN PHT_TX_CONTEXT pTxContext, - IN UCHAR BulkOutPipeId, - IN ULONG BulkOutSize, - IN usb_complete_t Func); - -VOID RTUSBInitRxDesc( - IN PRTMP_ADAPTER pAd, - IN PRX_CONTEXT pRxContext); - -VOID RTUSBCleanUpDataBulkOutQueue( - IN PRTMP_ADAPTER pAd); - -VOID RTUSBCancelPendingBulkOutIRP( - IN PRTMP_ADAPTER pAd); - -VOID RTUSBBulkOutDataPacket( - IN PRTMP_ADAPTER pAd, - IN UCHAR BulkOutPipeId, - IN UCHAR Index); - -VOID RTUSBBulkOutNullFrame( - IN PRTMP_ADAPTER pAd); - -VOID RTUSBBulkOutRTSFrame( - IN PRTMP_ADAPTER pAd); - -VOID RTUSBCancelPendingBulkInIRP( - IN PRTMP_ADAPTER pAd); - -VOID RTUSBCancelPendingIRPs( - IN PRTMP_ADAPTER pAd); - -VOID RTUSBBulkOutMLMEPacket( - IN PRTMP_ADAPTER pAd, - IN UCHAR Index); - -VOID RTUSBBulkOutPsPoll( - IN PRTMP_ADAPTER pAd); - -VOID RTUSBCleanUpMLMEBulkOutQueue( - IN PRTMP_ADAPTER pAd); - -VOID RTUSBKickBulkOut( - IN PRTMP_ADAPTER pAd); - -VOID RTUSBBulkReceive( - IN PRTMP_ADAPTER pAd); - -VOID DoBulkIn( - IN RTMP_ADAPTER *pAd); - -VOID RTUSBInitRxDesc( - IN PRTMP_ADAPTER pAd, - IN PRX_CONTEXT pRxContext); - -VOID RTUSBBulkRxHandle( - IN unsigned long data); - -// -// Function Prototype in rtusb_io.c -// -NTSTATUS RTUSBMultiRead( - IN PRTMP_ADAPTER pAd, - IN USHORT Offset, - OUT PUCHAR pData, - IN USHORT length); - -NTSTATUS RTUSBMultiWrite( - IN PRTMP_ADAPTER pAd, - IN USHORT Offset, - IN PUCHAR pData, - IN USHORT length); - -NTSTATUS RTUSBMultiWrite_OneByte( - IN PRTMP_ADAPTER pAd, - IN USHORT Offset, - IN PUCHAR pData); - -NTSTATUS RTUSBReadBBPRegister( - IN PRTMP_ADAPTER pAd, - IN UCHAR Id, - IN PUCHAR pValue); - -NTSTATUS RTUSBWriteBBPRegister( - IN PRTMP_ADAPTER pAd, - IN UCHAR Id, - IN UCHAR Value); - -NTSTATUS RTUSBWriteRFRegister( - IN PRTMP_ADAPTER pAd, - IN UINT32 Value); - -NTSTATUS RT30xxWriteRFRegister( - IN PRTMP_ADAPTER pAd, - IN UCHAR RegID, - IN UCHAR Value); - -NTSTATUS RT30xxReadRFRegister( - IN PRTMP_ADAPTER pAd, - IN UCHAR RegID, - IN PUCHAR pValue); - -NTSTATUS RTUSB_VendorRequest( - IN PRTMP_ADAPTER pAd, - IN UINT32 TransferFlags, - IN UCHAR ReservedBits, - IN UCHAR Request, - IN USHORT Value, - IN USHORT Index, - IN PVOID TransferBuffer, - IN UINT32 TransferBufferLength); - -NTSTATUS RTUSBReadEEPROM( - IN PRTMP_ADAPTER pAd, - IN USHORT Offset, - OUT PUCHAR pData, - IN USHORT length); - -NTSTATUS RTUSBWriteEEPROM( - IN PRTMP_ADAPTER pAd, - IN USHORT Offset, - IN PUCHAR pData, - IN USHORT length); - -VOID RTUSBPutToSleep( - IN PRTMP_ADAPTER pAd); - -NTSTATUS RTUSBWakeUp( - IN PRTMP_ADAPTER pAd); - -VOID RTUSBInitializeCmdQ( - IN PCmdQ cmdq); - -NDIS_STATUS RTUSBEnqueueCmdFromNdis( - IN PRTMP_ADAPTER pAd, - IN NDIS_OID Oid, - IN BOOLEAN SetInformation, - IN PVOID pInformationBuffer, - IN UINT32 InformationBufferLength); - -NDIS_STATUS RTUSBEnqueueInternalCmd( - IN PRTMP_ADAPTER pAd, - IN NDIS_OID Oid, - IN PVOID pInformationBuffer, - IN UINT32 InformationBufferLength); - -VOID RTUSBDequeueCmd( - IN PCmdQ cmdq, - OUT PCmdQElmt *pcmdqelmt); - -INT RTUSBCmdThread( - IN OUT PVOID Context); - -INT TimerQThread( - IN OUT PVOID Context); - -RT2870_TIMER_ENTRY *RT2870_TimerQ_Insert( - IN RTMP_ADAPTER *pAd, - IN RALINK_TIMER_STRUCT *pTimer); - -BOOLEAN RT2870_TimerQ_Remove( - IN RTMP_ADAPTER *pAd, - IN RALINK_TIMER_STRUCT *pTimer); - -void RT2870_TimerQ_Exit( - IN RTMP_ADAPTER *pAd); - -void RT2870_TimerQ_Init( - IN RTMP_ADAPTER *pAd); - -VOID RT2870_BssBeaconExit( - IN RTMP_ADAPTER *pAd); - -VOID RT2870_BssBeaconStop( - IN RTMP_ADAPTER *pAd); - -VOID RT2870_BssBeaconStart( - IN RTMP_ADAPTER * pAd); - -VOID RT2870_BssBeaconInit( - IN RTMP_ADAPTER *pAd); - -VOID RT2870_WatchDog( - IN RTMP_ADAPTER *pAd); - -NTSTATUS RTUSBWriteMACRegister( - IN PRTMP_ADAPTER pAd, - IN USHORT Offset, - IN UINT32 Value); - -NTSTATUS RTUSBReadMACRegister( - IN PRTMP_ADAPTER pAd, - IN USHORT Offset, - OUT PUINT32 pValue); - -NTSTATUS RTUSBSingleWrite( - IN RTMP_ADAPTER *pAd, - IN USHORT Offset, - IN USHORT Value); - -NTSTATUS RTUSBFirmwareRun( - IN PRTMP_ADAPTER pAd); - -NTSTATUS RTUSBFirmwareWrite( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pFwImage, - IN ULONG FwLen); - -NTSTATUS RTUSBFirmwareOpmode( - IN PRTMP_ADAPTER pAd, - OUT PUINT32 pValue); - -NTSTATUS RTUSBVenderReset( - IN PRTMP_ADAPTER pAd); - -NDIS_STATUS RTUSBSetHardWareRegister( - IN PRTMP_ADAPTER pAdapter, - IN PVOID pBuf); - -NDIS_STATUS RTUSBQueryHardWareRegister( - IN PRTMP_ADAPTER pAdapter, - IN PVOID pBuf); - -VOID CMDHandler( - IN PRTMP_ADAPTER pAd); - - -NDIS_STATUS CreateThreads( - IN struct net_device *net_dev ); - - -VOID MacTableInitialize( - IN PRTMP_ADAPTER pAd); - -VOID MlmeSetPsm( - IN PRTMP_ADAPTER pAd, - IN USHORT psm); - -NDIS_STATUS RTMPWPAAddKeyProc( - IN PRTMP_ADAPTER pAd, - IN PVOID pBuf); - -VOID AsicRxAntEvalAction( - IN PRTMP_ADAPTER pAd); - -#if 0 // Mark because not used in RT28xx. -NTSTATUS RTUSBRxPacket( - IN PRTMP_ADAPTER pAd, - IN BOOLEAN bBulkReceive); - -VOID RTUSBDequeueMLMEPacket( - IN PRTMP_ADAPTER pAd); - -VOID RTUSBCleanUpMLMEWaitQueue( - IN PRTMP_ADAPTER pAd); -#endif - -void append_pkt( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pHeader802_3, - IN UINT HdrLen, - IN PUCHAR pData, - IN ULONG DataSize, - OUT PNDIS_PACKET *ppPacket); - -UINT deaggregate_AMSDU_announce( - IN PRTMP_ADAPTER pAd, - PNDIS_PACKET pPacket, - IN PUCHAR pData, - IN ULONG DataSize); - -NDIS_STATUS RTMPCheckRxError( - IN PRTMP_ADAPTER pAd, - IN PHEADER_802_11 pHeader, - IN PRXWI_STRUC pRxWI, - IN PRT28XX_RXD_STRUC pRxINFO); - - -VOID RTUSBMlmeHardTransmit( - IN PRTMP_ADAPTER pAd, - IN PMGMT_STRUC pMgmt); - -INT MlmeThread( - IN PVOID Context); - -#if 0 -VOID RTUSBResumeMsduTransmission( - IN PRTMP_ADAPTER pAd); - -VOID RTUSBSuspendMsduTransmission( - IN PRTMP_ADAPTER pAd); -#endif - -// -// Function Prototype in rtusb_data.c -// -NDIS_STATUS RTUSBFreeDescriptorRequest( - IN PRTMP_ADAPTER pAd, - IN UCHAR BulkOutPipeId, - IN UINT32 NumberRequired); - - -BOOLEAN RTUSBNeedQueueBackForAgg( - IN RTMP_ADAPTER *pAd, - IN UCHAR BulkOutPipeId); - - -VOID RTMPWriteTxInfo( - IN PRTMP_ADAPTER pAd, - IN PTXINFO_STRUC pTxInfo, - IN USHORT USBDMApktLen, - IN BOOLEAN bWiv, - IN UCHAR QueueSel, - IN UCHAR NextValid, - IN UCHAR TxBurst); - -// -// Function Prototype in cmm_data_2870.c -// -USHORT RtmpUSB_WriteSubTxResource( - IN PRTMP_ADAPTER pAd, - IN TX_BLK *pTxBlk, - IN BOOLEAN bIsLast, - OUT USHORT *FreeNumber); - -USHORT RtmpUSB_WriteSingleTxResource( - IN PRTMP_ADAPTER pAd, - IN TX_BLK *pTxBlk, - IN BOOLEAN bIsLast, - OUT USHORT *FreeNumber); - -USHORT RtmpUSB_WriteFragTxResource( - IN PRTMP_ADAPTER pAd, - IN TX_BLK *pTxBlk, - IN UCHAR fragNum, - OUT USHORT *FreeNumber); - -USHORT RtmpUSB_WriteMultiTxResource( - IN PRTMP_ADAPTER pAd, - IN TX_BLK *pTxBlk, - IN UCHAR frameNum, - OUT USHORT *FreeNumber); - -VOID RtmpUSB_FinalWriteTxResource( - IN PRTMP_ADAPTER pAd, - IN TX_BLK *pTxBlk, - IN USHORT totalMPDUSize, - IN USHORT TxIdx); - -VOID RtmpUSBDataLastTxIdx( - IN PRTMP_ADAPTER pAd, - IN UCHAR QueIdx, - IN USHORT TxIdx); - -VOID RtmpUSBDataKickOut( - IN PRTMP_ADAPTER pAd, - IN TX_BLK *pTxBlk, - IN UCHAR QueIdx); - - -int RtmpUSBMgmtKickOut( - IN RTMP_ADAPTER *pAd, - IN UCHAR QueIdx, - IN PNDIS_PACKET pPacket, - IN PUCHAR pSrcBufVA, - IN UINT SrcBufLen); - -VOID RtmpUSBNullFrameKickOut( - IN RTMP_ADAPTER *pAd, - IN UCHAR QueIdx, - IN UCHAR *pNullFrame, - IN UINT32 frameLen); - -VOID RT28xxUsbStaAsicForceWakeup( - IN PRTMP_ADAPTER pAd, - IN BOOLEAN bFromTx); - -VOID RT28xxUsbStaAsicSleepThenAutoWakeup( - IN PRTMP_ADAPTER pAd, - IN USHORT TbttNumToNextWakeUp); - -VOID RT28xxUsbMlmeRadioOn( - IN PRTMP_ADAPTER pAd); - -VOID RT28xxUsbMlmeRadioOFF( - IN PRTMP_ADAPTER pAd); -#endif // RT2870 // - -//////////////////////////////////////// - -VOID QBSS_LoadInit( - IN RTMP_ADAPTER *pAd); - -UINT32 QBSS_LoadElementAppend( - IN RTMP_ADAPTER *pAd, - OUT UINT8 *buf_p); - -VOID QBSS_LoadUpdate( - IN RTMP_ADAPTER *pAd); - -/////////////////////////////////////// -INT RTMPShowCfgValue( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pName, - IN PUCHAR pBuf); - -PCHAR RTMPGetRalinkAuthModeStr( - IN NDIS_802_11_AUTHENTICATION_MODE authMode); - -PCHAR RTMPGetRalinkEncryModeStr( - IN USHORT encryMode); -////////////////////////////////////// - -#ifdef CONFIG_STA_SUPPORT -VOID AsicStaBbpTuning( - IN PRTMP_ADAPTER pAd); - -BOOLEAN StaAddMacTableEntry( - IN PRTMP_ADAPTER pAd, - IN PMAC_TABLE_ENTRY pEntry, - IN UCHAR MaxSupportedRateIn500Kbps, - IN HT_CAPABILITY_IE *pHtCapability, - IN UCHAR HtCapabilityLen, - IN USHORT CapabilityInfo); -#endif // CONFIG_STA_SUPPORT // - -void RTMP_IndicateMediaState( - IN PRTMP_ADAPTER pAd); - -VOID ReSyncBeaconTime( - IN PRTMP_ADAPTER pAd); - -VOID RTMPSetAGCInitValue( - IN PRTMP_ADAPTER pAd, - IN UCHAR BandWidth); - -int rt28xx_close(IN PNET_DEV dev); -int rt28xx_open(IN PNET_DEV dev); - -__inline INT VIRTUAL_IF_UP(PRTMP_ADAPTER pAd) -{ -extern VOID MeshMakeBeacon(IN PRTMP_ADAPTER pAd, IN UCHAR idx); -extern VOID MeshUpdateBeaconFrame(IN PRTMP_ADAPTER pAd, IN UCHAR idx); - - if (VIRTUAL_IF_NUM(pAd) == 0) - { - if (rt28xx_open(pAd->net_dev) != 0) - return -1; - } - else - { - } - VIRTUAL_IF_INC(pAd); - return 0; -} - -__inline VOID VIRTUAL_IF_DOWN(PRTMP_ADAPTER pAd) -{ - VIRTUAL_IF_DEC(pAd); - if (VIRTUAL_IF_NUM(pAd) == 0) - rt28xx_close(pAd->net_dev); - return; -} - - -#endif // __RTMP_H__ - +#include "../rt2860/rtmp.h" diff --git a/drivers/staging/rt2870/rtmp_ckipmic.h b/drivers/staging/rt2870/rtmp_ckipmic.h index a3d949a39d39..0e7f1dfd4547 100644 --- a/drivers/staging/rt2870/rtmp_ckipmic.h +++ b/drivers/staging/rt2870/rtmp_ckipmic.h @@ -1,113 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - rtmp_ckipmic.h - - Abstract: - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Name Date Modification logs -*/ -#ifndef __RTMP_CKIPMIC_H__ -#define __RTMP_CKIPMIC_H__ - -typedef struct _MIC_CONTEXT { - /* --- MMH context */ - UCHAR CK[16]; /* the key */ - UCHAR coefficient[16]; /* current aes counter mode coefficients */ - ULONGLONG accum; /* accumulated mic, reduced to u32 in final() */ - UINT position; /* current position (byte offset) in message */ - UCHAR part[4]; /* for conversion of message to u32 for mmh */ -} MIC_CONTEXT, *PMIC_CONTEXT; - -VOID CKIP_key_permute( - OUT UCHAR *PK, /* output permuted key */ - IN UCHAR *CK, /* input CKIP key */ - IN UCHAR toDsFromDs, /* input toDs/FromDs bits */ - IN UCHAR *piv); /* input pointer to IV */ - -VOID RTMPCkipMicInit( - IN PMIC_CONTEXT pContext, - IN PUCHAR CK); - -VOID RTMPMicUpdate( - IN PMIC_CONTEXT pContext, - IN PUCHAR pOctets, - IN INT len); - -ULONG RTMPMicGetCoefficient( - IN PMIC_CONTEXT pContext); - -VOID xor_128( - IN PUCHAR a, - IN PUCHAR b, - OUT PUCHAR out); - -UCHAR RTMPCkipSbox( - IN UCHAR a); - -VOID xor_32( - IN PUCHAR a, - IN PUCHAR b, - OUT PUCHAR out); - -VOID next_key( - IN PUCHAR key, - IN INT round); - -VOID byte_sub( - IN PUCHAR in, - OUT PUCHAR out); - -VOID shift_row( - IN PUCHAR in, - OUT PUCHAR out); - -VOID mix_column( - IN PUCHAR in, - OUT PUCHAR out); - -VOID RTMPAesEncrypt( - IN PUCHAR key, - IN PUCHAR data, - IN PUCHAR ciphertext); - -VOID RTMPMicFinal( - IN PMIC_CONTEXT pContext, - OUT UCHAR digest[4]); - -VOID RTMPCkipInsertCMIC( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pMIC, - IN PUCHAR p80211hdr, - IN PNDIS_PACKET pPacket, - IN PCIPHER_KEY pKey, - IN PUCHAR mic_snap); - -#endif //__RTMP_CKIPMIC_H__ +#include "../rt2860/rtmp_ckipmic.h" diff --git a/drivers/staging/rt2870/rtmp_def.h b/drivers/staging/rt2870/rtmp_def.h index c0f7561a9d9d..839d791b4f62 100644 --- a/drivers/staging/rt2870/rtmp_def.h +++ b/drivers/staging/rt2870/rtmp_def.h @@ -1,1622 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - rtmp_def.h - - Abstract: - Miniport related definition header - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Paul Lin 08-01-2002 created - John Chang 08-05-2003 add definition for 11g & other drafts -*/ -#ifndef __RTMP_DEF_H__ -#define __RTMP_DEF_H__ - -#include "oid.h" - -// -// Debug information verbosity: lower values indicate higher urgency -// -#define RT_DEBUG_OFF 0 -#define RT_DEBUG_ERROR 1 -#define RT_DEBUG_WARN 2 -#define RT_DEBUG_TRACE 3 -#define RT_DEBUG_INFO 4 -#define RT_DEBUG_LOUD 5 - -#define NIC_TAG ((ULONG)'0682') -#define NIC_DBG_STRING ("**RT28xx**") - -#ifdef SNMP_SUPPORT -// for snmp -// to get manufacturer OUI, kathy, 2008_0220 -#define ManufacturerOUI_LEN 3 -#define ManufacturerNAME ("Ralink Technology Company.") -#define ResourceTypeIdName ("Ralink_ID") -#endif - - -//#define PACKED - -#define RALINK_2883_VERSION ((UINT32)0x28830300) -#define RALINK_2880E_VERSION ((UINT32)0x28720200) -#define RALINK_3070_VERSION ((UINT32)0x30700200) - -// -// NDIS version in use by the NIC driver. -// The high byte is the major version. The low byte is the minor version. -// -#ifdef NDIS51_MINIPORT -#define NIC_DRIVER_VERSION 0x0501 -#else -#define NIC_DRIVER_VERSION 0x0500 -#endif - -// -// NDIS media type, current is ethernet, change if native wireless supported -// -#define NIC_MEDIA_TYPE NdisMedium802_3 -#define NIC_PCI_HDR_LENGTH 0xe2 -#define NIC_MAX_PACKET_SIZE 2304 -#define NIC_HEADER_SIZE 14 -#define MAX_MAP_REGISTERS_NEEDED 32 -#define MIN_MAP_REGISTERS_NEEDED 2 //Todo: should consider fragment issue. - -// -// interface type, we use PCI -// -#define NIC_INTERFACE_TYPE NdisInterfacePci -#define NIC_INTERRUPT_MODE NdisInterruptLevelSensitive - -// -// buffer size passed in NdisMQueryAdapterResources -// We should only need three adapter resources (IO, interrupt and memory), -// Some devices get extra resources, so have room for 10 resources -// UF_SIZE (sizeof(NDIS_RESOURCE_LIST) + (10*sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR))) - - -#define NIC_RESOURCE_B// -// IO space length -// -#define NIC_MAP_IOSPACE_LENGTH sizeof(CSR_STRUC) - -#define MAX_RX_PKT_LEN 1520 - -// -// Entry number for each DMA descriptor ring -// - - -#ifdef RT2870 -#define TX_RING_SIZE 8 // 1 -#define PRIO_RING_SIZE 8 -#define MGMT_RING_SIZE 32 // PRIO_RING_SIZE -#define RX_RING_SIZE 8 -#define MAX_TX_PROCESS 4 -#define LOCAL_TXBUF_SIZE 2048 -#endif // RT2870 // - -#ifdef MULTIPLE_CARD_SUPPORT -// MC: Multple Cards -#define MAX_NUM_OF_MULTIPLE_CARD 32 -#endif // MULTIPLE_CARD_SUPPORT // - -#define MAX_RX_PROCESS 128 //64 //32 -#define NUM_OF_LOCAL_TXBUF 2 -#define TXD_SIZE 16 -#define TXWI_SIZE 16 -#define RXD_SIZE 16 -#define RXWI_SIZE 16 -// TXINFO_SIZE + TXWI_SIZE + 802.11 Header Size + AMSDU sub frame header -#define TX_DMA_1ST_BUFFER_SIZE 96 // only the 1st physical buffer is pre-allocated -#define MGMT_DMA_BUFFER_SIZE 1536 //2048 -#define RX_BUFFER_AGGRESIZE 3840 //3904 //3968 //4096 //2048 //4096 -#define RX_BUFFER_NORMSIZE 3840 //3904 //3968 //4096 //2048 //4096 -#define TX_BUFFER_NORMSIZE RX_BUFFER_NORMSIZE -#define MAX_FRAME_SIZE 2346 // Maximum 802.11 frame size -#define MAX_AGGREGATION_SIZE 3840 //3904 //3968 //4096 -#define MAX_NUM_OF_TUPLE_CACHE 2 -#define MAX_MCAST_LIST_SIZE 32 -#define MAX_LEN_OF_VENDOR_DESC 64 -//#define MAX_SIZE_OF_MCAST_PSQ (NUM_OF_LOCAL_TXBUF >> 2) // AP won't spend more than 1/4 of total buffers on M/BCAST PSQ -#define MAX_SIZE_OF_MCAST_PSQ 32 - -#define MAX_RX_PROCESS_CNT (RX_RING_SIZE) - - -#define MAX_PACKETS_IN_QUEUE (512) //(512) // to pass WMM A5-WPAPSK -#define MAX_PACKETS_IN_MCAST_PS_QUEUE 32 -#define MAX_PACKETS_IN_PS_QUEUE 128 //32 -#define WMM_NUM_OF_AC 4 /* AC0, AC1, AC2, and AC3 */ - - - -// RxFilter -#define STANORMAL 0x17f97 -#define APNORMAL 0x15f97 -// -// RTMP_ADAPTER flags -// -#define fRTMP_ADAPTER_MAP_REGISTER 0x00000001 -#define fRTMP_ADAPTER_INTERRUPT_IN_USE 0x00000002 -#define fRTMP_ADAPTER_HARDWARE_ERROR 0x00000004 -#define fRTMP_ADAPTER_SCATTER_GATHER 0x00000008 -#define fRTMP_ADAPTER_SEND_PACKET_ERROR 0x00000010 -#define fRTMP_ADAPTER_MLME_RESET_IN_PROGRESS 0x00000020 -#define fRTMP_ADAPTER_HALT_IN_PROGRESS 0x00000040 -#define fRTMP_ADAPTER_RESET_IN_PROGRESS 0x00000080 -#define fRTMP_ADAPTER_NIC_NOT_EXIST 0x00000100 -#define fRTMP_ADAPTER_TX_RING_ALLOCATED 0x00000200 -#define fRTMP_ADAPTER_REMOVE_IN_PROGRESS 0x00000400 -#define fRTMP_ADAPTER_MIMORATE_INUSED 0x00000800 -#define fRTMP_ADAPTER_RX_RING_ALLOCATED 0x00001000 -#define fRTMP_ADAPTER_INTERRUPT_ACTIVE 0x00002000 -#define fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS 0x00004000 -#define fRTMP_ADAPTER_REASSOC_IN_PROGRESS 0x00008000 -#define fRTMP_ADAPTER_MEDIA_STATE_PENDING 0x00010000 -#define fRTMP_ADAPTER_RADIO_OFF 0x00020000 -#define fRTMP_ADAPTER_BULKOUT_RESET 0x00040000 -#define fRTMP_ADAPTER_BULKIN_RESET 0x00080000 -#define fRTMP_ADAPTER_RDG_ACTIVE 0x00100000 -#define fRTMP_ADAPTER_DYNAMIC_BE_TXOP_ACTIVE 0x00200000 -#define fRTMP_ADAPTER_SCAN_2040 0x04000000 -#define fRTMP_ADAPTER_RADIO_MEASUREMENT 0x08000000 - -#define fRTMP_ADAPTER_START_UP 0x10000000 //Devive already initialized and enabled Tx/Rx. -#define fRTMP_ADAPTER_MEDIA_STATE_CHANGE 0x20000000 -#define fRTMP_ADAPTER_IDLE_RADIO_OFF 0x40000000 - -// Lock bit for accessing different ring buffers -//#define fRTMP_ADAPTER_TX_RING_BUSY 0x80000000 -//#define fRTMP_ADAPTER_MGMT_RING_BUSY 0x40000000 -//#define fRTMP_ADAPTER_ATIM_RING_BUSY 0x20000000 -//#define fRTMP_ADAPTER_RX_RING_BUSY 0x10000000 - -// Lock bit for accessing different queue -//#define fRTMP_ADAPTER_TX_QUEUE_BUSY 0x08000000 -//#define fRTMP_ADAPTER_MGMT_QUEUE_BUSY 0x04000000 - -// -// STA operation status flags -// -#define fOP_STATUS_INFRA_ON 0x00000001 -#define fOP_STATUS_ADHOC_ON 0x00000002 -#define fOP_STATUS_BG_PROTECTION_INUSED 0x00000004 -#define fOP_STATUS_SHORT_SLOT_INUSED 0x00000008 -#define fOP_STATUS_SHORT_PREAMBLE_INUSED 0x00000010 -#define fOP_STATUS_RECEIVE_DTIM 0x00000020 -//#define fOP_STATUS_TX_RATE_SWITCH_ENABLED 0x00000040 -#define fOP_STATUS_MEDIA_STATE_CONNECTED 0x00000080 -#define fOP_STATUS_WMM_INUSED 0x00000100 -#define fOP_STATUS_AGGREGATION_INUSED 0x00000200 -#define fOP_STATUS_DOZE 0x00000400 // debug purpose -#define fOP_STATUS_PIGGYBACK_INUSED 0x00000800 // piggy-back, and aggregation -#define fOP_STATUS_APSD_INUSED 0x00001000 -#define fOP_STATUS_TX_AMSDU_INUSED 0x00002000 -#define fOP_STATUS_MAX_RETRY_ENABLED 0x00004000 -#define fOP_STATUS_WAKEUP_NOW 0x00008000 -#define fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE 0x00020000 - -#ifdef DOT11N_DRAFT3 -#define fOP_STATUS_SCAN_2040 0x00040000 -#endif // DOT11N_DRAFT3 // - -#define CCKSETPROTECT 0x1 -#define OFDMSETPROTECT 0x2 -#define MM20SETPROTECT 0x4 -#define MM40SETPROTECT 0x8 -#define GF20SETPROTECT 0x10 -#define GR40SETPROTECT 0x20 -#define ALLN_SETPROTECT (GR40SETPROTECT | GF20SETPROTECT | MM40SETPROTECT | MM20SETPROTECT) - -// -// AP's client table operation status flags -// -#define fCLIENT_STATUS_WMM_CAPABLE 0x00000001 // CLIENT can parse QOS DATA frame -#define fCLIENT_STATUS_AGGREGATION_CAPABLE 0x00000002 // CLIENT can receive Ralink's proprietary TX aggregation frame -#define fCLIENT_STATUS_PIGGYBACK_CAPABLE 0x00000004 // CLIENT support piggy-back -#define fCLIENT_STATUS_AMSDU_INUSED 0x00000008 -#define fCLIENT_STATUS_SGI20_CAPABLE 0x00000010 -#define fCLIENT_STATUS_SGI40_CAPABLE 0x00000020 -#define fCLIENT_STATUS_TxSTBC_CAPABLE 0x00000040 -#define fCLIENT_STATUS_RxSTBC_CAPABLE 0x00000080 -#define fCLIENT_STATUS_HTC_CAPABLE 0x00000100 -#define fCLIENT_STATUS_RDG_CAPABLE 0x00000200 -#define fCLIENT_STATUS_MCSFEEDBACK_CAPABLE 0x00000400 -#define fCLIENT_STATUS_APSD_CAPABLE 0x00000800 /* UAPSD STATION */ - -#ifdef DOT11N_DRAFT3 -#define fCLIENT_STATUS_BSSCOEXIST_CAPABLE 0x00001000 -#endif // DOT11N_DRAFT3 // - -#define fCLIENT_STATUS_RALINK_CHIPSET 0x00100000 -// -// STA configuration flags -// -//#define fSTA_CFG_ENABLE_TX_BURST 0x00000001 - -// 802.11n Operating Mode Definition. 0-3 also used in ASICUPdateProtect switch case -#define HT_NO_PROTECT 0 -#define HT_LEGACY_PROTECT 1 -#define HT_40_PROTECT 2 -#define HT_2040_PROTECT 3 -#define HT_RTSCTS_6M 7 -//following is our own definition in order to turn on our ASIC protection register in INFRASTRUCTURE. -#define HT_ATHEROS 8 // rt2860c has problem with atheros chip. we need to turn on RTS/CTS . -#define HT_FORCERTSCTS 9 // Force turn on RTS/CTS first. then go to evaluate if this force RTS is necessary. - -// -// RX Packet Filter control flags. Apply on pAd->PacketFilter -// -#define fRX_FILTER_ACCEPT_DIRECT NDIS_PACKET_TYPE_DIRECTED -#define fRX_FILTER_ACCEPT_MULTICAST NDIS_PACKET_TYPE_MULTICAST -#define fRX_FILTER_ACCEPT_BROADCAST NDIS_PACKET_TYPE_BROADCAST -#define fRX_FILTER_ACCEPT_ALL_MULTICAST NDIS_PACKET_TYPE_ALL_MULTICAST - -// -// Error code section -// -// NDIS_ERROR_CODE_ADAPTER_NOT_FOUND -#define ERRLOG_READ_PCI_SLOT_FAILED 0x00000101L -#define ERRLOG_WRITE_PCI_SLOT_FAILED 0x00000102L -#define ERRLOG_VENDOR_DEVICE_NOMATCH 0x00000103L - -// NDIS_ERROR_CODE_ADAPTER_DISABLED -#define ERRLOG_BUS_MASTER_DISABLED 0x00000201L - -// NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION -#define ERRLOG_INVALID_SPEED_DUPLEX 0x00000301L -#define ERRLOG_SET_SECONDARY_FAILED 0x00000302L - -// NDIS_ERROR_CODE_OUT_OF_RESOURCES -#define ERRLOG_OUT_OF_MEMORY 0x00000401L -#define ERRLOG_OUT_OF_SHARED_MEMORY 0x00000402L -#define ERRLOG_OUT_OF_MAP_REGISTERS 0x00000403L -#define ERRLOG_OUT_OF_BUFFER_POOL 0x00000404L -#define ERRLOG_OUT_OF_NDIS_BUFFER 0x00000405L -#define ERRLOG_OUT_OF_PACKET_POOL 0x00000406L -#define ERRLOG_OUT_OF_NDIS_PACKET 0x00000407L -#define ERRLOG_OUT_OF_LOOKASIDE_MEMORY 0x00000408L - -// NDIS_ERROR_CODE_HARDWARE_FAILURE -#define ERRLOG_SELFTEST_FAILED 0x00000501L -#define ERRLOG_INITIALIZE_ADAPTER 0x00000502L -#define ERRLOG_REMOVE_MINIPORT 0x00000503L - -// NDIS_ERROR_CODE_RESOURCE_CONFLICT -#define ERRLOG_MAP_IO_SPACE 0x00000601L -#define ERRLOG_QUERY_ADAPTER_RESOURCES 0x00000602L -#define ERRLOG_NO_IO_RESOURCE 0x00000603L -#define ERRLOG_NO_INTERRUPT_RESOURCE 0x00000604L -#define ERRLOG_NO_MEMORY_RESOURCE 0x00000605L - - -// WDS definition -#define MAX_WDS_ENTRY 4 -#define WDS_PAIRWISE_KEY_OFFSET 60 // WDS links uses pairwise key#60 ~ 63 in ASIC pairwise key table - -#define WDS_DISABLE_MODE 0 -#define WDS_RESTRICT_MODE 1 -#define WDS_BRIDGE_MODE 2 -#define WDS_REPEATER_MODE 3 -#define WDS_LAZY_MODE 4 - - -#define MAX_MESH_NUM 0 - -#define MAX_APCLI_NUM 0 -#ifdef APCLI_SUPPORT -#undef MAX_APCLI_NUM -#define MAX_APCLI_NUM 1 -#endif // APCLI_SUPPORT // - -#define MAX_MBSSID_NUM 1 - -/* sanity check for apidx */ -#define MBSS_MR_APIDX_SANITY_CHECK(apidx) \ - { if (apidx > MAX_MBSSID_NUM) { \ - printk("%s> Error! apidx = %d > MAX_MBSSID_NUM!\n", __func__, apidx); \ - apidx = MAIN_MBSSID; } } - -#define VALID_WCID(_wcid) ((_wcid) > 0 && (_wcid) < MAX_LEN_OF_MAC_TABLE ) - -#define MAIN_MBSSID 0 -#define FIRST_MBSSID 1 - - -#define MAX_BEACON_SIZE 512 -// If the MAX_MBSSID_NUM is larger than 6, -// it shall reserve some WCID space(wcid 222~253) for beacon frames. -// - these wcid 238~253 are reserved for beacon#6(ra6). -// - these wcid 222~237 are reserved for beacon#7(ra7). -#if defined(MAX_MBSSID_NUM) && (MAX_MBSSID_NUM == 8) -#define HW_RESERVED_WCID 222 -#elif defined(MAX_MBSSID_NUM) && (MAX_MBSSID_NUM == 7) -#define HW_RESERVED_WCID 238 -#else -#define HW_RESERVED_WCID 255 -#endif - -// Then dedicate wcid of DFS and Carrier-Sense. -#define DFS_CTS_WCID (HW_RESERVED_WCID - 1) -#define CS_CTS_WCID (HW_RESERVED_WCID - 2) -#define LAST_SPECIFIC_WCID (HW_RESERVED_WCID - 2) - -// If MAX_MBSSID_NUM is 8, the maximum available wcid for the associated STA is 211. -// If MAX_MBSSID_NUM is 7, the maximum available wcid for the associated STA is 228. -#define MAX_AVAILABLE_CLIENT_WCID (LAST_SPECIFIC_WCID - MAX_MBSSID_NUM - 1) - -// TX need WCID to find Cipher Key -// these wcid 212 ~ 219 are reserved for bc/mc packets if MAX_MBSSID_NUM is 8. -#define GET_GroupKey_WCID(__wcid, __bssidx) \ - { \ - __wcid = LAST_SPECIFIC_WCID - (MAX_MBSSID_NUM) + __bssidx; \ - } - -#define IsGroupKeyWCID(__wcid) (((__wcid) < LAST_SPECIFIC_WCID) && ((__wcid) >= (LAST_SPECIFIC_WCID - (MAX_MBSSID_NUM)))) - - -// definition to support multiple BSSID -#define BSS0 0 -#define BSS1 1 -#define BSS2 2 -#define BSS3 3 -#define BSS4 4 -#define BSS5 5 -#define BSS6 6 -#define BSS7 7 - - -//============================================================ -// Length definitions -#define PEER_KEY_NO 2 -#define MAC_ADDR_LEN 6 -#define TIMESTAMP_LEN 8 -#define MAX_LEN_OF_SUPPORTED_RATES MAX_LENGTH_OF_SUPPORT_RATES // 1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54 -#define MAX_LEN_OF_KEY 32 // 32 octets == 256 bits, Redefine for WPA -#define MAX_NUM_OF_CHANNELS MAX_NUM_OF_CHS // 14 channels @2.4G + 12@UNII + 4 @MMAC + 11 @HiperLAN2 + 7 @Japan + 1 as NULL termination -#define MAX_NUM_OF_11JCHANNELS 20 // 14 channels @2.4G + 12@UNII + 4 @MMAC + 11 @HiperLAN2 + 7 @Japan + 1 as NULL termination -#define MAX_LEN_OF_SSID 32 -#define CIPHER_TEXT_LEN 128 -#define HASH_TABLE_SIZE 256 -#define MAX_VIE_LEN 1024 // New for WPA cipher suite variable IE sizes. -#define MAX_SUPPORT_MCS 32 - -//============================================================ -// ASIC WCID Table definition. -//============================================================ -#define BSSID_WCID 1 // in infra mode, always put bssid with this WCID -#define MCAST_WCID 0x0 -#define BSS0Mcast_WCID 0x0 -#define BSS1Mcast_WCID 0xf8 -#define BSS2Mcast_WCID 0xf9 -#define BSS3Mcast_WCID 0xfa -#define BSS4Mcast_WCID 0xfb -#define BSS5Mcast_WCID 0xfc -#define BSS6Mcast_WCID 0xfd -#define BSS7Mcast_WCID 0xfe -#define RESERVED_WCID 0xff - -#define MAX_NUM_OF_ACL_LIST MAX_NUMBER_OF_ACL - -#define MAX_LEN_OF_MAC_TABLE MAX_NUMBER_OF_MAC // if MAX_MBSSID_NUM is 8, this value can't be larger than 211 - -#if MAX_LEN_OF_MAC_TABLE>MAX_AVAILABLE_CLIENT_WCID -#error MAX_LEN_OF_MAC_TABLE can not be larger than MAX_AVAILABLE_CLIENT_WCID!!!! -#endif - -#define MAX_NUM_OF_WDS_LINK_PERBSSID 3 -#define MAX_NUM_OF_WDS_LINK (MAX_NUM_OF_WDS_LINK_PERBSSID*MAX_MBSSID_NUM) -#define MAX_NUM_OF_EVENT MAX_NUMBER_OF_EVENT -#define WDS_LINK_START_WCID (MAX_LEN_OF_MAC_TABLE-1) - -#define NUM_OF_TID 8 -#define MAX_AID_BA 4 -#define MAX_LEN_OF_BA_REC_TABLE ((NUM_OF_TID * MAX_LEN_OF_MAC_TABLE)/2)// (NUM_OF_TID*MAX_AID_BA + 32) //Block ACK recipient -#define MAX_LEN_OF_BA_ORI_TABLE ((NUM_OF_TID * MAX_LEN_OF_MAC_TABLE)/2)// (NUM_OF_TID*MAX_AID_BA + 32) // Block ACK originator -#define MAX_LEN_OF_BSS_TABLE 64 -#define MAX_REORDERING_MPDU_NUM 512 - -// key related definitions -#define SHARE_KEY_NUM 4 -#define MAX_LEN_OF_SHARE_KEY 16 // byte count -#define MAX_LEN_OF_PEER_KEY 16 // byte count -#define PAIRWISE_KEY_NUM 64 // in MAC ASIC pairwise key table -#define GROUP_KEY_NUM 4 -#define PMK_LEN 32 -#define WDS_PAIRWISE_KEY_OFFSET 60 // WDS links uses pairwise key#60 ~ 63 in ASIC pairwise key table -#define PMKID_NO 4 // Number of PMKID saved supported -#define MAX_LEN_OF_MLME_BUFFER 2048 - -// power status related definitions -#define PWR_ACTIVE 0 -#define PWR_SAVE 1 -#define PWR_MMPS 2 //MIMO power save -//#define PWR_UNKNOWN 2 - -// Auth and Assoc mode related definitions -#define AUTH_MODE_OPEN 0x00 -#define AUTH_MODE_KEY 0x01 -//#define AUTH_MODE_AUTO_SWITCH 0x03 -//#define AUTH_MODE_DEAUTH 0x04 -//#define AUTH_MODE_UPLAYER 0x05 // reserved for 802.11i use - -// BSS Type definitions -#define BSS_ADHOC 0 // = Ndis802_11IBSS -#define BSS_INFRA 1 // = Ndis802_11Infrastructure -#define BSS_ANY 2 // = Ndis802_11AutoUnknown -#define BSS_MONITOR 3 // = Ndis802_11Monitor - - -// Reason code definitions -#define REASON_RESERVED 0 -#define REASON_UNSPECIFY 1 -#define REASON_NO_LONGER_VALID 2 -#define REASON_DEAUTH_STA_LEAVING 3 -#define REASON_DISASSOC_INACTIVE 4 -#define REASON_DISASSPC_AP_UNABLE 5 -#define REASON_CLS2ERR 6 -#define REASON_CLS3ERR 7 -#define REASON_DISASSOC_STA_LEAVING 8 -#define REASON_STA_REQ_ASSOC_NOT_AUTH 9 -#define REASON_INVALID_IE 13 -#define REASON_MIC_FAILURE 14 -#define REASON_4_WAY_TIMEOUT 15 -#define REASON_GROUP_KEY_HS_TIMEOUT 16 -#define REASON_IE_DIFFERENT 17 -#define REASON_MCIPHER_NOT_VALID 18 -#define REASON_UCIPHER_NOT_VALID 19 -#define REASON_AKMP_NOT_VALID 20 -#define REASON_UNSUPPORT_RSNE_VER 21 -#define REASON_INVALID_RSNE_CAP 22 -#define REASON_8021X_AUTH_FAIL 23 -#define REASON_CIPHER_SUITE_REJECTED 24 -#define REASON_DECLINED 37 - -#define REASON_QOS_UNSPECIFY 32 -#define REASON_QOS_LACK_BANDWIDTH 33 -#define REASON_POOR_CHANNEL_CONDITION 34 -#define REASON_QOS_OUTSIDE_TXOP_LIMITION 35 -#define REASON_QOS_QSTA_LEAVING_QBSS 36 -#define REASON_QOS_UNWANTED_MECHANISM 37 -#define REASON_QOS_MECH_SETUP_REQUIRED 38 -#define REASON_QOS_REQUEST_TIMEOUT 39 -#define REASON_QOS_CIPHER_NOT_SUPPORT 45 - -// Status code definitions -#define MLME_SUCCESS 0 -#define MLME_UNSPECIFY_FAIL 1 -#define MLME_CANNOT_SUPPORT_CAP 10 -#define MLME_REASSOC_DENY_ASSOC_EXIST 11 -#define MLME_ASSOC_DENY_OUT_SCOPE 12 -#define MLME_ALG_NOT_SUPPORT 13 -#define MLME_SEQ_NR_OUT_OF_SEQUENCE 14 -#define MLME_REJ_CHALLENGE_FAILURE 15 -#define MLME_REJ_TIMEOUT 16 -#define MLME_ASSOC_REJ_UNABLE_HANDLE_STA 17 -#define MLME_ASSOC_REJ_DATA_RATE 18 - -#define MLME_ASSOC_REJ_NO_EXT_RATE 22 -#define MLME_ASSOC_REJ_NO_EXT_RATE_PBCC 23 -#define MLME_ASSOC_REJ_NO_CCK_OFDM 24 - -#define MLME_QOS_UNSPECIFY 32 -#define MLME_REQUEST_DECLINED 37 -#define MLME_REQUEST_WITH_INVALID_PARAM 38 -#define MLME_DLS_NOT_ALLOW_IN_QBSS 48 -#define MLME_DEST_STA_NOT_IN_QBSS 49 -#define MLME_DEST_STA_IS_NOT_A_QSTA 50 - -#define MLME_INVALID_FORMAT 0x51 -#define MLME_FAIL_NO_RESOURCE 0x52 -#define MLME_STATE_MACHINE_REJECT 0x53 -#define MLME_MAC_TABLE_FAIL 0x54 - -// IE code -#define IE_SSID 0 -#define IE_SUPP_RATES 1 -#define IE_FH_PARM 2 -#define IE_DS_PARM 3 -#define IE_CF_PARM 4 -#define IE_TIM 5 -#define IE_IBSS_PARM 6 -#define IE_COUNTRY 7 // 802.11d -#define IE_802_11D_REQUEST 10 // 802.11d -#define IE_QBSS_LOAD 11 // 802.11e d9 -#define IE_EDCA_PARAMETER 12 // 802.11e d9 -#define IE_TSPEC 13 // 802.11e d9 -#define IE_TCLAS 14 // 802.11e d9 -#define IE_SCHEDULE 15 // 802.11e d9 -#define IE_CHALLENGE_TEXT 16 -#define IE_POWER_CONSTRAINT 32 // 802.11h d3.3 -#define IE_POWER_CAPABILITY 33 // 802.11h d3.3 -#define IE_TPC_REQUEST 34 // 802.11h d3.3 -#define IE_TPC_REPORT 35 // 802.11h d3.3 -#define IE_SUPP_CHANNELS 36 // 802.11h d3.3 -#define IE_CHANNEL_SWITCH_ANNOUNCEMENT 37 // 802.11h d3.3 -#define IE_MEASUREMENT_REQUEST 38 // 802.11h d3.3 -#define IE_MEASUREMENT_REPORT 39 // 802.11h d3.3 -#define IE_QUIET 40 // 802.11h d3.3 -#define IE_IBSS_DFS 41 // 802.11h d3.3 -#define IE_ERP 42 // 802.11g -#define IE_TS_DELAY 43 // 802.11e d9 -#define IE_TCLAS_PROCESSING 44 // 802.11e d9 -#define IE_QOS_CAPABILITY 46 // 802.11e d6 -#define IE_HT_CAP 45 // 802.11n d1. HT CAPABILITY. ELEMENT ID TBD -#define IE_AP_CHANNEL_REPORT 51 // 802.11k d6 -#define IE_HT_CAP2 52 // 802.11n d1. HT CAPABILITY. ELEMENT ID TBD -#define IE_RSN 48 // 802.11i d3.0 -#define IE_WPA2 48 // WPA2 -#define IE_EXT_SUPP_RATES 50 // 802.11g -#define IE_SUPP_REG_CLASS 59 // 802.11y. Supported regulatory classes. -#define IE_EXT_CHANNEL_SWITCH_ANNOUNCEMENT 60 // 802.11n -#define IE_ADD_HT 61 // 802.11n d1. ADDITIONAL HT CAPABILITY. ELEMENT ID TBD -#define IE_ADD_HT2 53 // 802.11n d1. ADDITIONAL HT CAPABILITY. ELEMENT ID TBD - - -// For 802.11n D3.03 -//#define IE_NEW_EXT_CHA_OFFSET 62 // 802.11n d1. New extension channel offset elemet -#define IE_SECONDARY_CH_OFFSET 62 // 802.11n D3.03 Secondary Channel Offset element -#define IE_WAPI 68 // WAPI information element -#define IE_2040_BSS_COEXIST 72 // 802.11n D3.0.3 -#define IE_2040_BSS_INTOLERANT_REPORT 73 // 802.11n D3.03 -#define IE_OVERLAPBSS_SCAN_PARM 74 // 802.11n D3.03 -#define IE_EXT_CAPABILITY 127 // 802.11n D3.03 - - -#define IE_WPA 221 // WPA -#define IE_VENDOR_SPECIFIC 221 // Wifi WMM (WME) - -#define OUI_BROADCOM_HT 51 // -#define OUI_BROADCOM_HTADD 52 // -#define OUI_PREN_HT_CAP 51 // -#define OUI_PREN_ADD_HT 52 // - -// CCX information -#define IE_AIRONET_CKIP 133 // CCX1.0 ID 85H for CKIP -#define IE_AP_TX_POWER 150 // CCX 2.0 for AP transmit power -#define IE_MEASUREMENT_CAPABILITY 221 // CCX 2.0 -#define IE_CCX_V2 221 -#define IE_AIRONET_IPADDRESS 149 // CCX ID 95H for IP Address -#define IE_AIRONET_CCKMREASSOC 156 // CCX ID 9CH for CCKM Reassociation Request element -#define CKIP_NEGOTIATION_LENGTH 30 -#define AIRONET_IPADDRESS_LENGTH 10 -#define AIRONET_CCKMREASSOC_LENGTH 24 - -// ======================================================== -// MLME state machine definition -// ======================================================== - -// STA MLME state mahcines -#define ASSOC_STATE_MACHINE 1 -#define AUTH_STATE_MACHINE 2 -#define AUTH_RSP_STATE_MACHINE 3 -#define SYNC_STATE_MACHINE 4 -#define MLME_CNTL_STATE_MACHINE 5 -#define WPA_PSK_STATE_MACHINE 6 -#define LEAP_STATE_MACHINE 7 -#define AIRONET_STATE_MACHINE 8 -#define ACTION_STATE_MACHINE 9 - -// AP MLME state machines -#define AP_ASSOC_STATE_MACHINE 11 -#define AP_AUTH_STATE_MACHINE 12 -#define AP_AUTH_RSP_STATE_MACHINE 13 -#define AP_SYNC_STATE_MACHINE 14 -#define AP_CNTL_STATE_MACHINE 15 -#define AP_WPA_STATE_MACHINE 16 - -#ifdef QOS_DLS_SUPPORT -#define DLS_STATE_MACHINE 26 -#endif // QOS_DLS_SUPPORT // - -// -// STA's CONTROL/CONNECT state machine: states, events, total function # -// -#define CNTL_IDLE 0 -#define CNTL_WAIT_DISASSOC 1 -#define CNTL_WAIT_JOIN 2 -#define CNTL_WAIT_REASSOC 3 -#define CNTL_WAIT_START 4 -#define CNTL_WAIT_AUTH 5 -#define CNTL_WAIT_ASSOC 6 -#define CNTL_WAIT_AUTH2 7 -#define CNTL_WAIT_OID_LIST_SCAN 8 -#define CNTL_WAIT_OID_DISASSOC 9 -#ifdef RT2870 -#define CNTL_WAIT_SCAN_FOR_CONNECT 10 -#endif // RT2870 // - -#define MT2_ASSOC_CONF 34 -#define MT2_AUTH_CONF 35 -#define MT2_DEAUTH_CONF 36 -#define MT2_DISASSOC_CONF 37 -#define MT2_REASSOC_CONF 38 -#define MT2_PWR_MGMT_CONF 39 -#define MT2_JOIN_CONF 40 -#define MT2_SCAN_CONF 41 -#define MT2_START_CONF 42 -#define MT2_GET_CONF 43 -#define MT2_SET_CONF 44 -#define MT2_RESET_CONF 45 -#define MT2_MLME_ROAMING_REQ 52 - -#define CNTL_FUNC_SIZE 1 - -// -// STA's ASSOC state machine: states, events, total function # -// -#define ASSOC_IDLE 0 -#define ASSOC_WAIT_RSP 1 -#define REASSOC_WAIT_RSP 2 -#define DISASSOC_WAIT_RSP 3 -#define MAX_ASSOC_STATE 4 - -#define ASSOC_MACHINE_BASE 0 -#define MT2_MLME_ASSOC_REQ 0 -#define MT2_MLME_REASSOC_REQ 1 -#define MT2_MLME_DISASSOC_REQ 2 -#define MT2_PEER_DISASSOC_REQ 3 -#define MT2_PEER_ASSOC_REQ 4 -#define MT2_PEER_ASSOC_RSP 5 -#define MT2_PEER_REASSOC_REQ 6 -#define MT2_PEER_REASSOC_RSP 7 -#define MT2_DISASSOC_TIMEOUT 8 -#define MT2_ASSOC_TIMEOUT 9 -#define MT2_REASSOC_TIMEOUT 10 -#define MAX_ASSOC_MSG 11 - -#define ASSOC_FUNC_SIZE (MAX_ASSOC_STATE * MAX_ASSOC_MSG) - -// -// ACT state machine: states, events, total function # -// -#define ACT_IDLE 0 -#define MAX_ACT_STATE 1 - -#define ACT_MACHINE_BASE 0 - -//Those PEER_xx_CATE number is based on real Categary value in IEEE spec. Please don'es modify it by your self. -//Category -#define MT2_PEER_SPECTRUM_CATE 0 -#define MT2_PEER_QOS_CATE 1 -#define MT2_PEER_DLS_CATE 2 -#define MT2_PEER_BA_CATE 3 -#define MT2_PEER_PUBLIC_CATE 4 -#define MT2_PEER_RM_CATE 5 -#define MT2_PEER_HT_CATE 7 // 7.4.7 -#define MAX_PEER_CATE_MSG 7 -#define MT2_MLME_ADD_BA_CATE 8 -#define MT2_MLME_ORI_DELBA_CATE 9 -#define MT2_MLME_REC_DELBA_CATE 10 -#define MT2_MLME_QOS_CATE 11 -#define MT2_MLME_DLS_CATE 12 -#define MT2_ACT_INVALID 13 -#define MAX_ACT_MSG 14 - -//Category field -#define CATEGORY_SPECTRUM 0 -#define CATEGORY_QOS 1 -#define CATEGORY_DLS 2 -#define CATEGORY_BA 3 -#define CATEGORY_PUBLIC 4 -#define CATEGORY_RM 5 -#define CATEGORY_HT 7 - - -// DLS Action frame definition -#define ACTION_DLS_REQUEST 0 -#define ACTION_DLS_RESPONSE 1 -#define ACTION_DLS_TEARDOWN 2 - -//Spectrum Action field value 802.11h 7.4.1 -#define SPEC_MRQ 0 // Request -#define SPEC_MRP 1 //Report -#define SPEC_TPCRQ 2 -#define SPEC_TPCRP 3 -#define SPEC_CHANNEL_SWITCH 4 - - -//BA Action field value -#define ADDBA_REQ 0 -#define ADDBA_RESP 1 -#define DELBA 2 - -//Public's Action field value in Public Category. Some in 802.11y and some in 11n -#define ACTION_BSS_2040_COEXIST 0 // 11n -#define ACTION_DSE_ENABLEMENT 1 // 11y D9.0 -#define ACTION_DSE_DEENABLEMENT 2 // 11y D9.0 -#define ACTION_DSE_REG_LOCATION_ANNOUNCE 3 // 11y D9.0 -#define ACTION_EXT_CH_SWITCH_ANNOUNCE 4 // 11y D9.0 -#define ACTION_DSE_MEASUREMENT_REQ 5 // 11y D9.0 -#define ACTION_DSE_MEASUREMENT_REPORT 6 // 11y D9.0 -#define ACTION_MEASUREMENT_PILOT_ACTION 7 // 11y D9.0 -#define ACTION_DSE_POWER_CONSTRAINT 8 // 11y D9.0 - - -//HT Action field value -#define NOTIFY_BW_ACTION 0 -#define SMPS_ACTION 1 -#define PSMP_ACTION 2 -#define SETPCO_ACTION 3 -#define MIMO_CHA_MEASURE_ACTION 4 -#define MIMO_N_BEACONFORM 5 -#define MIMO_BEACONFORM 6 -#define ANTENNA_SELECT 7 -#define HT_INFO_EXCHANGE 8 - -#define ACT_FUNC_SIZE (MAX_ACT_STATE * MAX_ACT_MSG) -// -// STA's AUTHENTICATION state machine: states, evvents, total function # -// -#define AUTH_REQ_IDLE 0 -#define AUTH_WAIT_SEQ2 1 -#define AUTH_WAIT_SEQ4 2 -#define MAX_AUTH_STATE 3 - -#define AUTH_MACHINE_BASE 0 -#define MT2_MLME_AUTH_REQ 0 -#define MT2_PEER_AUTH_EVEN 1 -#define MT2_AUTH_TIMEOUT 2 -#define MAX_AUTH_MSG 3 - -#define AUTH_FUNC_SIZE (MAX_AUTH_STATE * MAX_AUTH_MSG) - -// -// STA's AUTH_RSP state machine: states, events, total function # -// -#define AUTH_RSP_IDLE 0 -#define AUTH_RSP_WAIT_CHAL 1 -#define MAX_AUTH_RSP_STATE 2 - -#define AUTH_RSP_MACHINE_BASE 0 -#define MT2_AUTH_CHALLENGE_TIMEOUT 0 -#define MT2_PEER_AUTH_ODD 1 -#define MT2_PEER_DEAUTH 2 -#define MAX_AUTH_RSP_MSG 3 - -#define AUTH_RSP_FUNC_SIZE (MAX_AUTH_RSP_STATE * MAX_AUTH_RSP_MSG) - -// -// STA's SYNC state machine: states, events, total function # -// -#define SYNC_IDLE 0 // merge NO_BSS,IBSS_IDLE,IBSS_ACTIVE and BSS in to 1 state -#define JOIN_WAIT_BEACON 1 -#define SCAN_LISTEN 2 -#define MAX_SYNC_STATE 3 - -#define SYNC_MACHINE_BASE 0 -#define MT2_MLME_SCAN_REQ 0 -#define MT2_MLME_JOIN_REQ 1 -#define MT2_MLME_START_REQ 2 -#define MT2_PEER_BEACON 3 -#define MT2_PEER_PROBE_RSP 4 -#define MT2_PEER_ATIM 5 -#define MT2_SCAN_TIMEOUT 6 -#define MT2_BEACON_TIMEOUT 7 -#define MT2_ATIM_TIMEOUT 8 -#define MT2_PEER_PROBE_REQ 9 -#define MAX_SYNC_MSG 10 - -#define SYNC_FUNC_SIZE (MAX_SYNC_STATE * MAX_SYNC_MSG) - -//Messages for the DLS state machine -#define DLS_IDLE 0 -#define MAX_DLS_STATE 1 - -#define DLS_MACHINE_BASE 0 -#define MT2_MLME_DLS_REQ 0 -#define MT2_PEER_DLS_REQ 1 -#define MT2_PEER_DLS_RSP 2 -#define MT2_MLME_DLS_TEAR_DOWN 3 -#define MT2_PEER_DLS_TEAR_DOWN 4 -#define MAX_DLS_MSG 5 - -#define DLS_FUNC_SIZE (MAX_DLS_STATE * MAX_DLS_MSG) - -// -// STA's WPA-PSK State machine: states, events, total function # -// -#define WPA_PSK_IDLE 0 -#define MAX_WPA_PSK_STATE 1 - -#define WPA_MACHINE_BASE 0 -#define MT2_EAPPacket 0 -#define MT2_EAPOLStart 1 -#define MT2_EAPOLLogoff 2 -#define MT2_EAPOLKey 3 -#define MT2_EAPOLASFAlert 4 -#define MAX_WPA_PSK_MSG 5 - -#define WPA_PSK_FUNC_SIZE (MAX_WPA_PSK_STATE * MAX_WPA_PSK_MSG) - -// -// STA's CISCO-AIRONET State machine: states, events, total function # -// -#define AIRONET_IDLE 0 -#define AIRONET_SCANNING 1 -#define MAX_AIRONET_STATE 2 - -#define AIRONET_MACHINE_BASE 0 -#define MT2_AIRONET_MSG 0 -#define MT2_AIRONET_SCAN_REQ 1 -#define MT2_AIRONET_SCAN_DONE 2 -#define MAX_AIRONET_MSG 3 - -#define AIRONET_FUNC_SIZE (MAX_AIRONET_STATE * MAX_AIRONET_MSG) - -// -// AP's CONTROL/CONNECT state machine: states, events, total function # -// -#define AP_CNTL_FUNC_SIZE 1 - -// -// AP's ASSOC state machine: states, events, total function # -// -#define AP_ASSOC_IDLE 0 -#define AP_MAX_ASSOC_STATE 1 - -#define AP_ASSOC_MACHINE_BASE 0 -#define APMT2_MLME_DISASSOC_REQ 0 -#define APMT2_PEER_DISASSOC_REQ 1 -#define APMT2_PEER_ASSOC_REQ 2 -#define APMT2_PEER_REASSOC_REQ 3 -#define APMT2_CLS3ERR 4 -#define AP_MAX_ASSOC_MSG 5 - -#define AP_ASSOC_FUNC_SIZE (AP_MAX_ASSOC_STATE * AP_MAX_ASSOC_MSG) - -// -// AP's AUTHENTICATION state machine: states, events, total function # -// -#define AP_AUTH_REQ_IDLE 0 -#define AP_MAX_AUTH_STATE 1 - -#define AP_AUTH_MACHINE_BASE 0 -#define APMT2_MLME_DEAUTH_REQ 0 -#define APMT2_CLS2ERR 1 -#define AP_MAX_AUTH_MSG 2 - -#define AP_AUTH_FUNC_SIZE (AP_MAX_AUTH_STATE * AP_MAX_AUTH_MSG) - -// -// AP's AUTH-RSP state machine: states, events, total function # -// -#define AP_AUTH_RSP_IDLE 0 -#define AP_MAX_AUTH_RSP_STATE 1 - -#define AP_AUTH_RSP_MACHINE_BASE 0 -#define APMT2_AUTH_CHALLENGE_TIMEOUT 0 -#define APMT2_PEER_AUTH_ODD 1 -#define APMT2_PEER_DEAUTH 2 -#define AP_MAX_AUTH_RSP_MSG 3 - -#define AP_AUTH_RSP_FUNC_SIZE (AP_MAX_AUTH_RSP_STATE * AP_MAX_AUTH_RSP_MSG) - -// -// AP's SYNC state machine: states, events, total function # -// -#define AP_SYNC_IDLE 0 -#define AP_SCAN_LISTEN 1 -#define AP_MAX_SYNC_STATE 2 - -#define AP_SYNC_MACHINE_BASE 0 -#define APMT2_PEER_PROBE_REQ 0 -#define APMT2_PEER_BEACON 1 -#define APMT2_MLME_SCAN_REQ 2 -#define APMT2_PEER_PROBE_RSP 3 -#define APMT2_SCAN_TIMEOUT 4 -#define APMT2_MLME_SCAN_CNCL 5 -#define AP_MAX_SYNC_MSG 6 - -#define AP_SYNC_FUNC_SIZE (AP_MAX_SYNC_STATE * AP_MAX_SYNC_MSG) - -// -// AP's WPA state machine: states, events, total function # -// -#define AP_WPA_PTK 0 -#define AP_MAX_WPA_PTK_STATE 1 - -#define AP_WPA_MACHINE_BASE 0 -#define APMT2_EAPPacket 0 -#define APMT2_EAPOLStart 1 -#define APMT2_EAPOLLogoff 2 -#define APMT2_EAPOLKey 3 -#define APMT2_EAPOLASFAlert 4 -#define AP_MAX_WPA_MSG 5 - -#define AP_WPA_FUNC_SIZE (AP_MAX_WPA_PTK_STATE * AP_MAX_WPA_MSG) - -#ifdef APCLI_SUPPORT -//ApCli authentication state machine -#define APCLI_AUTH_REQ_IDLE 0 -#define APCLI_AUTH_WAIT_SEQ2 1 -#define APCLI_AUTH_WAIT_SEQ4 2 -#define APCLI_MAX_AUTH_STATE 3 - -#define APCLI_AUTH_MACHINE_BASE 0 -#define APCLI_MT2_MLME_AUTH_REQ 0 -#define APCLI_MT2_MLME_DEAUTH_REQ 1 -#define APCLI_MT2_PEER_AUTH_EVEN 2 -#define APCLI_MT2_PEER_DEAUTH 3 -#define APCLI_MT2_AUTH_TIMEOUT 4 -#define APCLI_MAX_AUTH_MSG 5 - -#define APCLI_AUTH_FUNC_SIZE (APCLI_MAX_AUTH_STATE * APCLI_MAX_AUTH_MSG) - -//ApCli association state machine -#define APCLI_ASSOC_IDLE 0 -#define APCLI_ASSOC_WAIT_RSP 1 -#define APCLI_MAX_ASSOC_STATE 2 - -#define APCLI_ASSOC_MACHINE_BASE 0 -#define APCLI_MT2_MLME_ASSOC_REQ 0 -#define APCLI_MT2_MLME_DISASSOC_REQ 1 -#define APCLI_MT2_PEER_DISASSOC_REQ 2 -#define APCLI_MT2_PEER_ASSOC_RSP 3 -#define APCLI_MT2_ASSOC_TIMEOUT 4 -#define APCLI_MAX_ASSOC_MSG 5 - -#define APCLI_ASSOC_FUNC_SIZE (APCLI_MAX_ASSOC_STATE * APCLI_MAX_ASSOC_MSG) - -//ApCli sync state machine -#define APCLI_SYNC_IDLE 0 // merge NO_BSS,IBSS_IDLE,IBSS_ACTIVE and BSS in to 1 state -#define APCLI_JOIN_WAIT_PROBE_RSP 1 -#define APCLI_MAX_SYNC_STATE 2 - -#define APCLI_SYNC_MACHINE_BASE 0 -#define APCLI_MT2_MLME_PROBE_REQ 0 -#define APCLI_MT2_PEER_PROBE_RSP 1 -#define APCLI_MT2_PROBE_TIMEOUT 2 -#define APCLI_MAX_SYNC_MSG 3 - -#define APCLI_SYNC_FUNC_SIZE (APCLI_MAX_SYNC_STATE * APCLI_MAX_SYNC_MSG) - -//ApCli ctrl state machine -#define APCLI_CTRL_DISCONNECTED 0 // merge NO_BSS,IBSS_IDLE,IBSS_ACTIVE and BSS in to 1 state -#define APCLI_CTRL_PROBE 1 -#define APCLI_CTRL_AUTH 2 -#define APCLI_CTRL_AUTH_2 3 -#define APCLI_CTRL_ASSOC 4 -#define APCLI_CTRL_DEASSOC 5 -#define APCLI_CTRL_CONNECTED 6 -#define APCLI_MAX_CTRL_STATE 7 - -#define APCLI_CTRL_MACHINE_BASE 0 -#define APCLI_CTRL_JOIN_REQ 0 -#define APCLI_CTRL_PROBE_RSP 1 -#define APCLI_CTRL_AUTH_RSP 2 -#define APCLI_CTRL_DISCONNECT_REQ 3 -#define APCLI_CTRL_PEER_DISCONNECT_REQ 4 -#define APCLI_CTRL_ASSOC_RSP 5 -#define APCLI_CTRL_DEASSOC_RSP 6 -#define APCLI_CTRL_JOIN_REQ_TIMEOUT 7 -#define APCLI_CTRL_AUTH_REQ_TIMEOUT 8 -#define APCLI_CTRL_ASSOC_REQ_TIMEOUT 9 -#define APCLI_MAX_CTRL_MSG 10 - -#define APCLI_CTRL_FUNC_SIZE (APCLI_MAX_CTRL_STATE * APCLI_MAX_CTRL_MSG) - -#if 0 // remove those variables by AlbertY -// ApCli WPA state machine -#define APCLI_WPA_PSK_IDLE 0 -#define APCLI_MAX_WPA_PSK_STATE 1 - -// ApCli WPA MSG Type -#define APCLI_WPA_MACHINE_BASE 0 -#define APCLI_MT2_EAPPacket 0 -#define APCLI_MT2_EAPOLStart 1 -#define APCLI_MT2_EAPOLLogoff 2 -#define APCLI_MT2_EAPOLKey 3 -#define APCLI_MT2_EAPOLASFAlert 4 -#define APCLI_MAX_WPA_PSK_MSG 5 - -#define APCLI_WPA_PSK_FUNC_SIZE (APCLI_MAX_WPA_PSK_STATE * APCLI_MAX_WPA_PSK_MSG) -#endif // end - 0 // - -#endif // APCLI_SUPPORT // - - -// ============================================================================= - -// value domain of 802.11 header FC.Tyte, which is b3..b2 of the 1st-byte of MAC header -#define BTYPE_MGMT 0 -#define BTYPE_CNTL 1 -#define BTYPE_DATA 2 - -// value domain of 802.11 MGMT frame's FC.subtype, which is b7..4 of the 1st-byte of MAC header -#define SUBTYPE_ASSOC_REQ 0 -#define SUBTYPE_ASSOC_RSP 1 -#define SUBTYPE_REASSOC_REQ 2 -#define SUBTYPE_REASSOC_RSP 3 -#define SUBTYPE_PROBE_REQ 4 -#define SUBTYPE_PROBE_RSP 5 -#define SUBTYPE_BEACON 8 -#define SUBTYPE_ATIM 9 -#define SUBTYPE_DISASSOC 10 -#define SUBTYPE_AUTH 11 -#define SUBTYPE_DEAUTH 12 -#define SUBTYPE_ACTION 13 -#define SUBTYPE_ACTION_NO_ACK 14 - -// value domain of 802.11 CNTL frame's FC.subtype, which is b7..4 of the 1st-byte of MAC header -#define SUBTYPE_WRAPPER 7 -#define SUBTYPE_BLOCK_ACK_REQ 8 -#define SUBTYPE_BLOCK_ACK 9 -#define SUBTYPE_PS_POLL 10 -#define SUBTYPE_RTS 11 -#define SUBTYPE_CTS 12 -#define SUBTYPE_ACK 13 -#define SUBTYPE_CFEND 14 -#define SUBTYPE_CFEND_CFACK 15 - -// value domain of 802.11 DATA frame's FC.subtype, which is b7..4 of the 1st-byte of MAC header -#define SUBTYPE_DATA 0 -#define SUBTYPE_DATA_CFACK 1 -#define SUBTYPE_DATA_CFPOLL 2 -#define SUBTYPE_DATA_CFACK_CFPOLL 3 -#define SUBTYPE_NULL_FUNC 4 -#define SUBTYPE_CFACK 5 -#define SUBTYPE_CFPOLL 6 -#define SUBTYPE_CFACK_CFPOLL 7 -#define SUBTYPE_QDATA 8 -#define SUBTYPE_QDATA_CFACK 9 -#define SUBTYPE_QDATA_CFPOLL 10 -#define SUBTYPE_QDATA_CFACK_CFPOLL 11 -#define SUBTYPE_QOS_NULL 12 -#define SUBTYPE_QOS_CFACK 13 -#define SUBTYPE_QOS_CFPOLL 14 -#define SUBTYPE_QOS_CFACK_CFPOLL 15 - -// ACK policy of QOS Control field bit 6:5 -#define NORMAL_ACK 0x00 // b6:5 = 00 -#define NO_ACK 0x20 // b6:5 = 01 -#define NO_EXPLICIT_ACK 0x40 // b6:5 = 10 -#define BLOCK_ACK 0x60 // b6:5 = 11 - -// -// rtmp_data.c use these definition -// -#define LENGTH_802_11 24 -#define LENGTH_802_11_AND_H 30 -#define LENGTH_802_11_CRC_H 34 -#define LENGTH_802_11_CRC 28 -#define LENGTH_802_11_WITH_ADDR4 30 -#define LENGTH_802_3 14 -#define LENGTH_802_3_TYPE 2 -#define LENGTH_802_1_H 8 -#define LENGTH_EAPOL_H 4 -#define LENGTH_WMMQOS_H 2 -#define LENGTH_CRC 4 -#define MAX_SEQ_NUMBER 0x0fff -#define LENGTH_802_3_NO_TYPE 12 -#define LENGTH_802_1Q 4 /* VLAN related */ - -// STA_CSR4.field.TxResult -#define TX_RESULT_SUCCESS 0 -#define TX_RESULT_ZERO_LENGTH 1 -#define TX_RESULT_UNDER_RUN 2 -#define TX_RESULT_OHY_ERROR 4 -#define TX_RESULT_RETRY_FAIL 6 - -// All PHY rate summary in TXD -// Preamble MODE in TxD -#define MODE_CCK 0 -#define MODE_OFDM 1 -#ifdef DOT11_N_SUPPORT -#define MODE_HTMIX 2 -#define MODE_HTGREENFIELD 3 -#endif // DOT11_N_SUPPORT // -// MCS for CCK. BW.SGI.STBC are reserved -#define MCS_LONGP_RATE_1 0 // long preamble CCK 1Mbps -#define MCS_LONGP_RATE_2 1 // long preamble CCK 1Mbps -#define MCS_LONGP_RATE_5_5 2 -#define MCS_LONGP_RATE_11 3 -#define MCS_SHORTP_RATE_1 4 // long preamble CCK 1Mbps. short is forbidden in 1Mbps -#define MCS_SHORTP_RATE_2 5 // short preamble CCK 2Mbps -#define MCS_SHORTP_RATE_5_5 6 -#define MCS_SHORTP_RATE_11 7 -// To send duplicate legacy OFDM. set BW=BW_40. SGI.STBC are reserved -#define MCS_RATE_6 0 // legacy OFDM -#define MCS_RATE_9 1 // OFDM -#define MCS_RATE_12 2 // OFDM -#define MCS_RATE_18 3 // OFDM -#define MCS_RATE_24 4 // OFDM -#define MCS_RATE_36 5 // OFDM -#define MCS_RATE_48 6 // OFDM -#define MCS_RATE_54 7 // OFDM -// HT -#define MCS_0 0 // 1S -#define MCS_1 1 -#define MCS_2 2 -#define MCS_3 3 -#define MCS_4 4 -#define MCS_5 5 -#define MCS_6 6 -#define MCS_7 7 -#define MCS_8 8 // 2S -#define MCS_9 9 -#define MCS_10 10 -#define MCS_11 11 -#define MCS_12 12 -#define MCS_13 13 -#define MCS_14 14 -#define MCS_15 15 -#define MCS_16 16 // 3*3 -#define MCS_17 17 -#define MCS_18 18 -#define MCS_19 19 -#define MCS_20 20 -#define MCS_21 21 -#define MCS_22 22 -#define MCS_23 23 -#define MCS_32 32 -#define MCS_AUTO 33 - -#ifdef DOT11_N_SUPPORT -// OID_HTPHYMODE -// MODE -#define HTMODE_MM 0 -#define HTMODE_GF 1 -#endif // DOT11_N_SUPPORT // - -// Fixed Tx MODE - HT, CCK or OFDM -#define FIXED_TXMODE_HT 0 -#define FIXED_TXMODE_CCK 1 -#define FIXED_TXMODE_OFDM 2 -// BW -#define BW_20 BAND_WIDTH_20 -#define BW_40 BAND_WIDTH_40 -#define BW_BOTH BAND_WIDTH_BOTH -#define BW_10 BAND_WIDTH_10 // 802.11j has 10MHz. This definition is for internal usage. doesn't fill in the IE or other field. - -#ifdef DOT11_N_SUPPORT -// SHORTGI -#define GI_400 GAP_INTERVAL_400 // only support in HT mode -#define GI_BOTH GAP_INTERVAL_BOTH -#endif // DOT11_N_SUPPORT // -#define GI_800 GAP_INTERVAL_800 -// STBC -#define STBC_NONE 0 -#ifdef DOT11_N_SUPPORT -#define STBC_USE 1 // limited use in rt2860b phy -#define RXSTBC_ONE 1 // rx support of one spatial stream -#define RXSTBC_TWO 2 // rx support of 1 and 2 spatial stream -#define RXSTBC_THR 3 // rx support of 1~3 spatial stream -// MCS FEEDBACK -#define MCSFBK_NONE 0 // not support mcs feedback / -#define MCSFBK_RSV 1 // reserved -#define MCSFBK_UNSOLICIT 2 // only support unsolict mcs feedback -#define MCSFBK_MRQ 3 // response to both MRQ and unsolict mcs feedback - -// MIMO power safe -#define MMPS_STATIC 0 -#define MMPS_DYNAMIC 1 -#define MMPS_RSV 2 -#define MMPS_ENABLE 3 - - -// A-MSDU size -#define AMSDU_0 0 -#define AMSDU_1 1 - -#endif // DOT11_N_SUPPORT // - -// MCS use 7 bits -#define TXRATEMIMO 0x80 -#define TXRATEMCS 0x7F -#define TXRATEOFDM 0x7F -#define RATE_1 0 -#define RATE_2 1 -#define RATE_5_5 2 -#define RATE_11 3 -#define RATE_6 4 // OFDM -#define RATE_9 5 // OFDM -#define RATE_12 6 // OFDM -#define RATE_18 7 // OFDM -#define RATE_24 8 // OFDM -#define RATE_36 9 // OFDM -#define RATE_48 10 // OFDM -#define RATE_54 11 // OFDM -#define RATE_FIRST_OFDM_RATE RATE_6 -#define RATE_LAST_OFDM_RATE RATE_54 -#define RATE_6_5 12 // HT mix -#define RATE_13 13 // HT mix -#define RATE_19_5 14 // HT mix -#define RATE_26 15 // HT mix -#define RATE_39 16 // HT mix -#define RATE_52 17 // HT mix -#define RATE_58_5 18 // HT mix -#define RATE_65 19 // HT mix -#define RATE_78 20 // HT mix -#define RATE_104 21 // HT mix -#define RATE_117 22 // HT mix -#define RATE_130 23 // HT mix -//#define RATE_AUTO_SWITCH 255 // for StaCfg.FixedTxRate only -#define HTRATE_0 12 -#define RATE_FIRST_MM_RATE HTRATE_0 -#define RATE_FIRST_HT_RATE HTRATE_0 -#define RATE_LAST_HT_RATE HTRATE_0 - -// pTxWI->txop -#define IFS_HTTXOP 0 // The txop will be handles by ASIC. -#define IFS_PIFS 1 -#define IFS_SIFS 2 -#define IFS_BACKOFF 3 - -// pTxD->RetryMode -#define LONG_RETRY 1 -#define SHORT_RETRY 0 - -// Country Region definition -#define REGION_MINIMUM_BG_BAND 0 -#define REGION_0_BG_BAND 0 // 1-11 -#define REGION_1_BG_BAND 1 // 1-13 -#define REGION_2_BG_BAND 2 // 10-11 -#define REGION_3_BG_BAND 3 // 10-13 -#define REGION_4_BG_BAND 4 // 14 -#define REGION_5_BG_BAND 5 // 1-14 -#define REGION_6_BG_BAND 6 // 3-9 -#define REGION_7_BG_BAND 7 // 5-13 -#define REGION_31_BG_BAND 31 // 5-13 -#define REGION_MAXIMUM_BG_BAND 7 - -#define REGION_MINIMUM_A_BAND 0 -#define REGION_0_A_BAND 0 // 36, 40, 44, 48, 52, 56, 60, 64, 149, 153, 157, 161, 165 -#define REGION_1_A_BAND 1 // 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140 -#define REGION_2_A_BAND 2 // 36, 40, 44, 48, 52, 56, 60, 64 -#define REGION_3_A_BAND 3 // 52, 56, 60, 64, 149, 153, 157, 161 -#define REGION_4_A_BAND 4 // 149, 153, 157, 161, 165 -#define REGION_5_A_BAND 5 // 149, 153, 157, 161 -#define REGION_6_A_BAND 6 // 36, 40, 44, 48 -#define REGION_7_A_BAND 7 // 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165 -#define REGION_8_A_BAND 8 // 52, 56, 60, 64 -#define REGION_9_A_BAND 9 // 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 132, 136, 140, 149, 153, 157, 161, 165 -#define REGION_10_A_BAND 10 // 36, 40, 44, 48, 149, 153, 157, 161, 165 -#define REGION_11_A_BAND 11 // 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 149, 153, 157, 161 -#define REGION_MAXIMUM_A_BAND 11 - -// pTxD->CipherAlg -#define CIPHER_NONE 0 -#define CIPHER_WEP64 1 -#define CIPHER_WEP128 2 -#define CIPHER_TKIP 3 -#define CIPHER_AES 4 -#define CIPHER_CKIP64 5 -#define CIPHER_CKIP128 6 -#define CIPHER_TKIP_NO_MIC 7 // MIC appended by driver: not a valid value in hardware key table -#define CIPHER_SMS4 8 - -// value domain of pAd->RfIcType -#define RFIC_2820 1 // 2.4G 2T3R -#define RFIC_2850 2 // 2.4G/5G 2T3R -#define RFIC_2720 3 // 2.4G 1T2R -#define RFIC_2750 4 // 2.4G/5G 1T2R -#define RFIC_3020 5 // 2.4G 1T1R -#define RFIC_2020 6 // 2.4G B/G - -// LED Status. -#define LED_LINK_DOWN 0 -#define LED_LINK_UP 1 -#define LED_RADIO_OFF 2 -#define LED_RADIO_ON 3 -#define LED_HALT 4 -#define LED_WPS 5 -#define LED_ON_SITE_SURVEY 6 -#define LED_POWER_UP 7 - -// value domain of pAd->LedCntl.LedMode and E2PROM -#define LED_MODE_DEFAULT 0 -#define LED_MODE_TWO_LED 1 -#define LED_MODE_SIGNAL_STREGTH 8 // EEPROM define =8 - -// RC4 init value, used fro WEP & TKIP -#define PPPINITFCS32 0xffffffff /* Initial FCS value */ - -// value domain of pAd->StaCfg.PortSecured. 802.1X controlled port definition -#define WPA_802_1X_PORT_SECURED 1 -#define WPA_802_1X_PORT_NOT_SECURED 2 - -#define PAIRWISE_KEY 1 -#define GROUP_KEY 2 - -//definition of DRS -#define MAX_STEP_OF_TX_RATE_SWITCH 32 - - -// pre-allocated free NDIS PACKET/BUFFER poll for internal usage -#define MAX_NUM_OF_FREE_NDIS_PACKET 128 - -//Block ACK -#define MAX_TX_REORDERBUF 64 -#define MAX_RX_REORDERBUF 64 -#define DEFAULT_TX_TIMEOUT 30 -#define DEFAULT_RX_TIMEOUT 30 - -// definition of Recipient or Originator -#define I_RECIPIENT TRUE -#define I_ORIGINATOR FALSE - -#define DEFAULT_BBP_TX_POWER 0 -#define DEFAULT_RF_TX_POWER 5 - -#define MAX_INI_BUFFER_SIZE 4096 -#define MAX_PARAM_BUFFER_SIZE (2048) // enough for ACL (18*64) - //18 : the length of Mac address acceptable format "01:02:03:04:05:06;") - //64 : MAX_NUM_OF_ACL_LIST -// definition of pAd->OpMode -#define OPMODE_STA 0 -#define OPMODE_AP 1 -//#define OPMODE_L3_BRG 2 // as AP and STA at the same time - -#ifdef RT_BIG_ENDIAN -#define DIR_READ 0 -#define DIR_WRITE 1 -#define TYPE_TXD 0 -#define TYPE_RXD 1 -#define TYPE_TXINFO 0 -#define TYPE_RXINFO 1 -#define TYPE_TXWI 0 -#define TYPE_RXWI 1 -#endif - -// ========================= AP rtmp_def.h =========================== -// value domain for pAd->EventTab.Log[].Event -#define EVENT_RESET_ACCESS_POINT 0 // Log = "hh:mm:ss Restart Access Point" -#define EVENT_ASSOCIATED 1 // Log = "hh:mm:ss STA 00:01:02:03:04:05 associated" -#define EVENT_DISASSOCIATED 2 // Log = "hh:mm:ss STA 00:01:02:03:04:05 left this BSS" -#define EVENT_AGED_OUT 3 // Log = "hh:mm:ss STA 00:01:02:03:04:05 was aged-out and removed from this BSS" -#define EVENT_COUNTER_M 4 -#define EVENT_INVALID_PSK 5 -#define EVENT_MAX_EVENT_TYPE 6 -// ==== end of AP rtmp_def.h ============ - -// definition RSSI Number -#define RSSI_0 0 -#define RSSI_1 1 -#define RSSI_2 2 - -// definition of radar detection -#define RD_NORMAL_MODE 0 // Not found radar signal -#define RD_SWITCHING_MODE 1 // Found radar signal, and doing channel switch -#define RD_SILENCE_MODE 2 // After channel switch, need to be silence a while to ensure radar not found - -//Driver defined cid for mapping status and command. -#define SLEEPCID 0x11 -#define WAKECID 0x22 -#define QUERYPOWERCID 0x33 -#define OWNERMCU 0x1 -#define OWNERCPU 0x0 - -// MBSSID definition -#define ENTRY_NOT_FOUND 0xFF - - -/* After Linux 2.6.9, - * VLAN module use Private (from user) interface flags (netdevice->priv_flags). - * #define IFF_802_1Q_VLAN 0x1 -- 802.1Q VLAN device. in if.h - * ref to ip_sabotage_out() [ out->priv_flags & IFF_802_1Q_VLAN ] in br_netfilter.c - * - * For this reason, we MUST use EVEN value in priv_flags - */ -#define INT_MAIN 0x0100 -#define INT_MBSSID 0x0200 -#define INT_WDS 0x0300 -#define INT_APCLI 0x0400 -#define INT_MESH 0x0500 - -// Use bitmap to allow coexist of ATE_TXFRAME and ATE_RXFRAME(i.e.,to support LoopBack mode) -#ifdef RALINK_ATE -#define ATE_START 0x00 // Start ATE -#define ATE_STOP 0x80 // Stop ATE -#define ATE_TXCONT 0x05 // Continuous Transmit -#define ATE_TXCARR 0x09 // Transmit Carrier -#define ATE_TXCARRSUPP 0x11 // Transmit Carrier Suppression -#define ATE_TXFRAME 0x01 // Transmit Frames -#define ATE_RXFRAME 0x02 // Receive Frames -#ifdef RALINK_28xx_QA -#define ATE_TXSTOP 0xe2 // Stop Transmition(i.e., TXCONT, TXCARR, TXCARRSUPP, and TXFRAME) -#define ATE_RXSTOP 0xfd // Stop receiving Frames -#define BBP22_TXFRAME 0x00 // Transmit Frames -#define BBP22_TXCONT_OR_CARRSUPP 0x80 // Continuous Transmit or Carrier Suppression -#define BBP22_TXCARR 0xc1 // Transmit Carrier -#define BBP24_TXCONT 0x00 // Continuous Transmit -#define BBP24_CARRSUPP 0x01 // Carrier Suppression -#endif // RALINK_28xx_QA // -#endif // RALINK_ATE // - -// WEP Key TYPE -#define WEP_HEXADECIMAL_TYPE 0 -#define WEP_ASCII_TYPE 1 - - - -// WIRELESS EVENTS definition -/* Max number of char in custom event, refer to wireless_tools.28/wireless.20.h */ -#define IW_CUSTOM_MAX_LEN 255 /* In bytes */ - -// For system event - start -#define IW_SYS_EVENT_FLAG_START 0x0200 -#define IW_ASSOC_EVENT_FLAG 0x0200 -#define IW_DISASSOC_EVENT_FLAG 0x0201 -#define IW_DEAUTH_EVENT_FLAG 0x0202 -#define IW_AGEOUT_EVENT_FLAG 0x0203 -#define IW_COUNTER_MEASURES_EVENT_FLAG 0x0204 -#define IW_REPLAY_COUNTER_DIFF_EVENT_FLAG 0x0205 -#define IW_RSNIE_DIFF_EVENT_FLAG 0x0206 -#define IW_MIC_DIFF_EVENT_FLAG 0x0207 -#define IW_ICV_ERROR_EVENT_FLAG 0x0208 -#define IW_MIC_ERROR_EVENT_FLAG 0x0209 -#define IW_GROUP_HS_TIMEOUT_EVENT_FLAG 0x020A -#define IW_PAIRWISE_HS_TIMEOUT_EVENT_FLAG 0x020B -#define IW_RSNIE_SANITY_FAIL_EVENT_FLAG 0x020C -#define IW_SET_KEY_DONE_WPA1_EVENT_FLAG 0x020D -#define IW_SET_KEY_DONE_WPA2_EVENT_FLAG 0x020E -#define IW_STA_LINKUP_EVENT_FLAG 0x020F -#define IW_STA_LINKDOWN_EVENT_FLAG 0x0210 -#define IW_SCAN_COMPLETED_EVENT_FLAG 0x0211 -#define IW_SCAN_ENQUEUE_FAIL_EVENT_FLAG 0x0212 -// if add new system event flag, please upadte the IW_SYS_EVENT_FLAG_END -#define IW_SYS_EVENT_FLAG_END 0x0212 -#define IW_SYS_EVENT_TYPE_NUM (IW_SYS_EVENT_FLAG_END - IW_SYS_EVENT_FLAG_START + 1) -// For system event - end - -// For spoof attack event - start -#define IW_SPOOF_EVENT_FLAG_START 0x0300 -#define IW_CONFLICT_SSID_EVENT_FLAG 0x0300 -#define IW_SPOOF_ASSOC_RESP_EVENT_FLAG 0x0301 -#define IW_SPOOF_REASSOC_RESP_EVENT_FLAG 0x0302 -#define IW_SPOOF_PROBE_RESP_EVENT_FLAG 0x0303 -#define IW_SPOOF_BEACON_EVENT_FLAG 0x0304 -#define IW_SPOOF_DISASSOC_EVENT_FLAG 0x0305 -#define IW_SPOOF_AUTH_EVENT_FLAG 0x0306 -#define IW_SPOOF_DEAUTH_EVENT_FLAG 0x0307 -#define IW_SPOOF_UNKNOWN_MGMT_EVENT_FLAG 0x0308 -#define IW_REPLAY_ATTACK_EVENT_FLAG 0x0309 -// if add new spoof attack event flag, please upadte the IW_SPOOF_EVENT_FLAG_END -#define IW_SPOOF_EVENT_FLAG_END 0x0309 -#define IW_SPOOF_EVENT_TYPE_NUM (IW_SPOOF_EVENT_FLAG_END - IW_SPOOF_EVENT_FLAG_START + 1) -// For spoof attack event - end - -// For flooding attack event - start -#define IW_FLOOD_EVENT_FLAG_START 0x0400 -#define IW_FLOOD_AUTH_EVENT_FLAG 0x0400 -#define IW_FLOOD_ASSOC_REQ_EVENT_FLAG 0x0401 -#define IW_FLOOD_REASSOC_REQ_EVENT_FLAG 0x0402 -#define IW_FLOOD_PROBE_REQ_EVENT_FLAG 0x0403 -#define IW_FLOOD_DISASSOC_EVENT_FLAG 0x0404 -#define IW_FLOOD_DEAUTH_EVENT_FLAG 0x0405 -#define IW_FLOOD_EAP_REQ_EVENT_FLAG 0x0406 -// if add new flooding attack event flag, please upadte the IW_FLOOD_EVENT_FLAG_END -#define IW_FLOOD_EVENT_FLAG_END 0x0406 -#define IW_FLOOD_EVENT_TYPE_NUM (IW_FLOOD_EVENT_FLAG_END - IW_FLOOD_EVENT_FLAG_START + 1) -// For flooding attack - end - -// End - WIRELESS EVENTS definition - -#ifdef CONFIG_STA_SUPPORT -// definition for DLS, kathy -#define MAX_NUM_OF_INIT_DLS_ENTRY 1 -#define MAX_NUM_OF_DLS_ENTRY MAX_NUMBER_OF_DLS_ENTRY - -//Block ACK , rt2860, kathy -#define MAX_TX_REORDERBUF 64 -#define MAX_RX_REORDERBUF 64 -#define DEFAULT_TX_TIMEOUT 30 -#define DEFAULT_RX_TIMEOUT 30 -#ifndef CONFIG_AP_SUPPORT -#define MAX_BARECI_SESSION 8 -#endif - -#ifndef IW_ESSID_MAX_SIZE -/* Maximum size of the ESSID and pAd->nickname strings */ -#define IW_ESSID_MAX_SIZE 32 -#endif -#endif // CONFIG_STA_SUPPORT // - -#ifdef MCAST_RATE_SPECIFIC -#define MCAST_DISABLE 0 -#define MCAST_CCK 1 -#define MCAST_OFDM 2 -#define MCAST_HTMIX 3 -#endif // MCAST_RATE_SPECIFIC // - -// For AsicRadioOff/AsicRadioOn function -#define DOT11POWERSAVE 0 -#define GUIRADIO_OFF 1 -#define RTMP_HALT 2 -#define GUI_IDLE_POWER_SAVE 3 -// -- - - -// definition for WpaSupport flag -#define WPA_SUPPLICANT_DISABLE 0 -#define WPA_SUPPLICANT_ENABLE 1 -#define WPA_SUPPLICANT_ENABLE_WITH_WEB_UI 2 - -// Endian byte swapping codes -#define SWAP16(x) \ - ((UINT16)( \ - (((UINT16)(x) & (UINT16) 0x00ffU) << 8) | \ - (((UINT16)(x) & (UINT16) 0xff00U) >> 8) )) - -#define SWAP32(x) \ - ((UINT32)( \ - (((UINT32)(x) & (UINT32) 0x000000ffUL) << 24) | \ - (((UINT32)(x) & (UINT32) 0x0000ff00UL) << 8) | \ - (((UINT32)(x) & (UINT32) 0x00ff0000UL) >> 8) | \ - (((UINT32)(x) & (UINT32) 0xff000000UL) >> 24) )) - -#define SWAP64(x) \ - ((UINT64)( \ - (UINT64)(((UINT64)(x) & (UINT64) 0x00000000000000ffULL) << 56) | \ - (UINT64)(((UINT64)(x) & (UINT64) 0x000000000000ff00ULL) << 40) | \ - (UINT64)(((UINT64)(x) & (UINT64) 0x0000000000ff0000ULL) << 24) | \ - (UINT64)(((UINT64)(x) & (UINT64) 0x00000000ff000000ULL) << 8) | \ - (UINT64)(((UINT64)(x) & (UINT64) 0x000000ff00000000ULL) >> 8) | \ - (UINT64)(((UINT64)(x) & (UINT64) 0x0000ff0000000000ULL) >> 24) | \ - (UINT64)(((UINT64)(x) & (UINT64) 0x00ff000000000000ULL) >> 40) | \ - (UINT64)(((UINT64)(x) & (UINT64) 0xff00000000000000ULL) >> 56) )) - -#ifdef RT_BIG_ENDIAN - -#define cpu2le64(x) SWAP64((x)) -#define le2cpu64(x) SWAP64((x)) -#define cpu2le32(x) SWAP32((x)) -#define le2cpu32(x) SWAP32((x)) -#define cpu2le16(x) SWAP16((x)) -#define le2cpu16(x) SWAP16((x)) -#define cpu2be64(x) ((UINT64)(x)) -#define be2cpu64(x) ((UINT64)(x)) -#define cpu2be32(x) ((UINT32)(x)) -#define be2cpu32(x) ((UINT32)(x)) -#define cpu2be16(x) ((UINT16)(x)) -#define be2cpu16(x) ((UINT16)(x)) - -#else // Little_Endian - -#define cpu2le64(x) ((UINT64)(x)) -#define le2cpu64(x) ((UINT64)(x)) -#define cpu2le32(x) ((UINT32)(x)) -#define le2cpu32(x) ((UINT32)(x)) -#define cpu2le16(x) ((UINT16)(x)) -#define le2cpu16(x) ((UINT16)(x)) -#define cpu2be64(x) SWAP64((x)) -#define be2cpu64(x) SWAP64((x)) -#define cpu2be32(x) SWAP32((x)) -#define be2cpu32(x) SWAP32((x)) -#define cpu2be16(x) SWAP16((x)) -#define be2cpu16(x) SWAP16((x)) - -#endif // RT_BIG_ENDIAN - -#endif // __RTMP_DEF_H__ - - +#include "../rt2860/rtmp_def.h" diff --git a/drivers/staging/rt2870/rtmp_type.h b/drivers/staging/rt2870/rtmp_type.h index 1fd7df1e1791..fbf97d0fa5d3 100644 --- a/drivers/staging/rt2870/rtmp_type.h +++ b/drivers/staging/rt2870/rtmp_type.h @@ -1,94 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - rtmp_type.h - - Abstract: - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Name Date Modification logs - Paul Lin 1-2-2004 -*/ -#ifndef __RTMP_TYPE_H__ -#define __RTMP_TYPE_H__ - -#define PACKED __attribute__ ((packed)) - -// Put platform dependent declaration here -// For example, linux type definition -typedef unsigned char UINT8; -typedef unsigned short UINT16; -typedef unsigned int UINT32; -typedef unsigned long long UINT64; -typedef int INT32; -typedef long long INT64; - -typedef unsigned char * PUINT8; -typedef unsigned short * PUINT16; -typedef unsigned int * PUINT32; -typedef unsigned long long * PUINT64; -typedef int * PINT32; -typedef long long * PINT64; - -typedef signed char CHAR; -typedef signed short SHORT; -typedef signed int INT; -typedef signed long LONG; -typedef signed long long LONGLONG; - - -typedef unsigned char UCHAR; -typedef unsigned short USHORT; -typedef unsigned int UINT; -typedef unsigned long ULONG; -typedef unsigned long long ULONGLONG; - -typedef unsigned char BOOLEAN; -typedef void VOID; - -typedef VOID * PVOID; -typedef CHAR * PCHAR; -typedef UCHAR * PUCHAR; -typedef USHORT * PUSHORT; -typedef LONG * PLONG; -typedef ULONG * PULONG; -typedef UINT * PUINT; - -typedef unsigned int NDIS_MEDIA_STATE; - -typedef union _LARGE_INTEGER { - struct { - UINT LowPart; - INT32 HighPart; - } u; - INT64 QuadPart; -} LARGE_INTEGER; - -#endif // __RTMP_TYPE_H__ - +#include "../rt2860/rtmp_type.h" diff --git a/drivers/staging/rt2870/spectrum.h b/drivers/staging/rt2870/spectrum.h index 94cfa5b174fc..8aa23a1833b1 100644 --- a/drivers/staging/rt2870/spectrum.h +++ b/drivers/staging/rt2870/spectrum.h @@ -1,322 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - */ - -#ifndef __SPECTRUM_H__ -#define __SPECTRUM_H__ - -#include "rtmp_type.h" -#include "spectrum_def.h" - -typedef struct PACKED _TPC_REPORT_INFO -{ - UINT8 TxPwr; - UINT8 LinkMargin; -} TPC_REPORT_INFO, *PTPC_REPORT_INFO; - -typedef struct PACKED _CH_SW_ANN_INFO -{ - UINT8 ChSwMode; - UINT8 Channel; - UINT8 ChSwCnt; -} CH_SW_ANN_INFO, *PCH_SW_ANN_INFO; - -typedef union PACKED _MEASURE_REQ_MODE -{ -#ifdef RT_BIG_ENDIAN - struct PACKED - { - UINT8 Rev1:4; - UINT8 Report:1; - UINT8 Request:1; - UINT8 Enable:1; - UINT8 Rev0:1; - } field; -#else - struct PACKED - { - UINT8 Rev0:1; - UINT8 Enable:1; - UINT8 Request:1; - UINT8 Report:1; - UINT8 Rev1:4; - } field; -#endif // RT_BIG_ENDIAN // - UINT8 word; -} MEASURE_REQ_MODE, *PMEASURE_REQ_MODE; - -typedef struct PACKED _MEASURE_REQ -{ - UINT8 ChNum; - UINT64 MeasureStartTime; - UINT16 MeasureDuration; -} MEASURE_REQ, *PMEASURE_REQ; - -typedef struct PACKED _MEASURE_REQ_INFO -{ - UINT8 Token; - MEASURE_REQ_MODE ReqMode; - UINT8 ReqType; - MEASURE_REQ MeasureReq; -} MEASURE_REQ_INFO, *PMEASURE_REQ_INFO; - -typedef union PACKED _MEASURE_BASIC_REPORT_MAP -{ -#ifdef RT_BIG_ENDIAN - struct PACKED - { - UINT8 Rev:3; - UINT8 Unmeasure:1; - UINT8 Radar:1; - UINT8 UnidentifiedSignal:1; - UINT8 OfdmPreamble:1; - UINT8 BSS:1; - } field; -#else - struct PACKED - { - UINT8 BSS:1; - UINT8 OfdmPreamble:1; - UINT8 UnidentifiedSignal:1; - UINT8 Radar:1; - UINT8 Unmeasure:1; - UINT8 Rev:3; - } field; -#endif // RT_BIG_ENDIAN // - UINT8 word; -} MEASURE_BASIC_REPORT_MAP, *PMEASURE_BASIC_REPORT_MAP; - -typedef struct PACKED _MEASURE_BASIC_REPORT -{ - UINT8 ChNum; - UINT64 MeasureStartTime; - UINT16 MeasureDuration; - MEASURE_BASIC_REPORT_MAP Map; -} MEASURE_BASIC_REPORT, *PMEASURE_BASIC_REPORT; - -typedef struct PACKED _MEASURE_CCA_REPORT -{ - UINT8 ChNum; - UINT64 MeasureStartTime; - UINT16 MeasureDuration; - UINT8 CCA_Busy_Fraction; -} MEASURE_CCA_REPORT, *PMEASURE_CCA_REPORT; - -typedef struct PACKED _MEASURE_RPI_REPORT -{ - UINT8 ChNum; - UINT64 MeasureStartTime; - UINT16 MeasureDuration; - UINT8 RPI_Density[8]; -} MEASURE_RPI_REPORT, *PMEASURE_RPI_REPORT; - -typedef union PACKED _MEASURE_REPORT_MODE -{ - struct PACKED - { -#ifdef RT_BIG_ENDIAN - UINT8 Rev:5; - UINT8 Refused:1; - UINT8 Incapable:1; - UINT8 Late:1; -#else - UINT8 Late:1; - UINT8 Incapable:1; - UINT8 Refused:1; - UINT8 Rev:5; -#endif // RT_BIG_ENDIAN // - } field; - UINT8 word; -} MEASURE_REPORT_MODE, *PMEASURE_REPORT_MODE; - -typedef struct PACKED _MEASURE_REPORT_INFO -{ - UINT8 Token; - MEASURE_REPORT_MODE ReportMode; - UINT8 ReportType; - UINT8 Octect[0]; -} MEASURE_REPORT_INFO, *PMEASURE_REPORT_INFO; - -typedef struct PACKED _QUIET_INFO -{ - UINT8 QuietCnt; - UINT8 QuietPeriod; - UINT8 QuietDuration; - UINT8 QuietOffset; -} QUIET_INFO, *PQUIET_INFO; - -/* - ========================================================================== - Description: - Prepare Measurement request action frame and enqueue it into - management queue waiting for transmition. - - Parametrs: - 1. the destination mac address of the frame. - - Return : None. - ========================================================================== - */ -VOID EnqueueMeasurementReq( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDA, - IN UINT8 MeasureToken, - IN UINT8 MeasureReqMode, - IN UINT8 MeasureReqType, - IN UINT8 MeasureCh, - IN UINT16 MeasureDuration); - -/* - ========================================================================== - Description: - Prepare Measurement report action frame and enqueue it into - management queue waiting for transmition. - - Parametrs: - 1. the destination mac address of the frame. - - Return : None. - ========================================================================== - */ -VOID EnqueueMeasurementRep( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDA, - IN UINT8 DialogToken, - IN UINT8 MeasureToken, - IN UINT8 MeasureReqMode, - IN UINT8 MeasureReqType, - IN UINT8 ReportInfoLen, - IN PUINT8 pReportInfo); - -/* - ========================================================================== - Description: - Prepare TPC Request action frame and enqueue it into - management queue waiting for transmition. - - Parametrs: - 1. the destination mac address of the frame. - - Return : None. - ========================================================================== - */ -VOID EnqueueTPCReq( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDA, - IN UCHAR DialogToken); - -/* - ========================================================================== - Description: - Prepare TPC Report action frame and enqueue it into - management queue waiting for transmition. - - Parametrs: - 1. the destination mac address of the frame. - - Return : None. - ========================================================================== - */ -VOID EnqueueTPCRep( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDA, - IN UINT8 DialogToken, - IN UINT8 TxPwr, - IN UINT8 LinkMargin); - -/* - ========================================================================== - Description: - Prepare Channel Switch Announcement action frame and enqueue it into - management queue waiting for transmition. - - Parametrs: - 1. the destination mac address of the frame. - 2. Channel switch announcement mode. - 2. a New selected channel. - - Return : None. - ========================================================================== - */ -VOID EnqueueChSwAnn( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDA, - IN UINT8 ChSwMode, - IN UINT8 NewCh); - -/* - ========================================================================== - Description: - Spectrun action frames Handler such as channel switch annoucement, - measurement report, measurement request actions frames. - - Parametrs: - Elme - MLME message containing the received frame - - Return : None. - ========================================================================== - */ -VOID PeerSpectrumAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -/* - ========================================================================== - Description: - - Parametrs: - - Return : None. - ========================================================================== - */ -INT Set_MeasureReq_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_TpcReq_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -VOID MeasureReqTabInit( - IN PRTMP_ADAPTER pAd); - -VOID MeasureReqTabExit( - IN PRTMP_ADAPTER pAd); - -VOID TpcReqTabInit( - IN PRTMP_ADAPTER pAd); - -VOID TpcReqTabExit( - IN PRTMP_ADAPTER pAd); - -VOID NotifyChSwAnnToPeerAPs( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pRA, - IN PUCHAR pTA, - IN UINT8 ChSwMode, - IN UINT8 Channel); -#endif // __SPECTRUM_H__ // - +#include "../rt2860/spectrum.h" diff --git a/drivers/staging/rt2870/spectrum_def.h b/drivers/staging/rt2870/spectrum_def.h index 4ca4817bba05..a65f551e3918 100644 --- a/drivers/staging/rt2870/spectrum_def.h +++ b/drivers/staging/rt2870/spectrum_def.h @@ -1,95 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - spectrum_def.h - - Abstract: - Handle association related requests either from WSTA or from local MLME - - Revision History: - Who When What - --------- ---------- ---------------------------------------------- - Fonchi Wu 2008 created for 802.11h - */ - -#ifndef __SPECTRUM_DEF_H__ -#define __SPECTRUM_DEF_H__ - -#define MAX_MEASURE_REQ_TAB_SIZE 3 -#define MAX_HASH_MEASURE_REQ_TAB_SIZE MAX_MEASURE_REQ_TAB_SIZE - -#define MAX_TPC_REQ_TAB_SIZE 3 -#define MAX_HASH_TPC_REQ_TAB_SIZE MAX_TPC_REQ_TAB_SIZE - -#define MIN_RCV_PWR 100 /* Negative value ((dBm) */ - -#define RM_TPC_REQ 0 -#define RM_MEASURE_REQ 1 - -#define RM_BASIC 0 -#define RM_CCA 1 -#define RM_RPI_HISTOGRAM 2 - -#define TPC_REQ_AGE_OUT 500 /* ms */ -#define MQ_REQ_AGE_OUT 500 /* ms */ - -#define TPC_DIALOGTOKEN_HASH_INDEX(_DialogToken) ((_DialogToken) % MAX_HASH_TPC_REQ_TAB_SIZE) -#define MQ_DIALOGTOKEN_HASH_INDEX(_DialogToken) ((_DialogToken) % MAX_MEASURE_REQ_TAB_SIZE) - -typedef struct _MEASURE_REQ_ENTRY -{ - struct _MEASURE_REQ_ENTRY *pNext; - ULONG lastTime; - BOOLEAN Valid; - UINT8 DialogToken; - UINT8 MeasureDialogToken[3]; // 0:basic measure, 1: CCA measure, 2: RPI_Histogram measure. -} MEASURE_REQ_ENTRY, *PMEASURE_REQ_ENTRY; - -typedef struct _MEASURE_REQ_TAB -{ - UCHAR Size; - PMEASURE_REQ_ENTRY Hash[MAX_HASH_MEASURE_REQ_TAB_SIZE]; - MEASURE_REQ_ENTRY Content[MAX_MEASURE_REQ_TAB_SIZE]; -} MEASURE_REQ_TAB, *PMEASURE_REQ_TAB; - -typedef struct _TPC_REQ_ENTRY -{ - struct _TPC_REQ_ENTRY *pNext; - ULONG lastTime; - BOOLEAN Valid; - UINT8 DialogToken; -} TPC_REQ_ENTRY, *PTPC_REQ_ENTRY; - -typedef struct _TPC_REQ_TAB -{ - UCHAR Size; - PTPC_REQ_ENTRY Hash[MAX_HASH_TPC_REQ_TAB_SIZE]; - TPC_REQ_ENTRY Content[MAX_TPC_REQ_TAB_SIZE]; -} TPC_REQ_TAB, *PTPC_REQ_TAB; - -#endif // __SPECTRUM_DEF_H__ // - +#include "../rt2860/spectrum_def.h" diff --git a/drivers/staging/rt2870/sta/aironet.c b/drivers/staging/rt2870/sta/aironet.c index 4af4a1906181..72b7f2e6bf7f 100644 --- a/drivers/staging/rt2870/sta/aironet.c +++ b/drivers/staging/rt2870/sta/aironet.c @@ -1,1312 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - aironet.c - - Abstract: - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Paul Lin 04-06-15 Initial -*/ -#include "../rt_config.h" - -/* - ========================================================================== - Description: - association state machine init, including state transition and timer init - Parameters: - S - pointer to the association state machine - ========================================================================== - */ -VOID AironetStateMachineInit( - IN PRTMP_ADAPTER pAd, - IN STATE_MACHINE *S, - OUT STATE_MACHINE_FUNC Trans[]) -{ - StateMachineInit(S, Trans, MAX_AIRONET_STATE, MAX_AIRONET_MSG, (STATE_MACHINE_FUNC)Drop, AIRONET_IDLE, AIRONET_MACHINE_BASE); - StateMachineSetAction(S, AIRONET_IDLE, MT2_AIRONET_MSG, (STATE_MACHINE_FUNC)AironetMsgAction); - StateMachineSetAction(S, AIRONET_IDLE, MT2_AIRONET_SCAN_REQ, (STATE_MACHINE_FUNC)AironetRequestAction); - StateMachineSetAction(S, AIRONET_SCANNING, MT2_AIRONET_SCAN_DONE, (STATE_MACHINE_FUNC)AironetReportAction); -} - -/* - ========================================================================== - Description: - This is state machine function. - When receiving EAPOL packets which is for 802.1x key management. - Use both in WPA, and WPAPSK case. - In this function, further dispatch to different functions according to the received packet. 3 categories are : - 1. normal 4-way pairwisekey and 2-way groupkey handshake - 2. MIC error (Countermeasures attack) report packet from STA. - 3. Request for pairwise/group key update from STA - Return: - ========================================================================== -*/ -VOID AironetMsgAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - USHORT Length; - UCHAR Index, i; - PUCHAR pData; - PAIRONET_RM_REQUEST_FRAME pRMReq; - PRM_REQUEST_ACTION pReqElem; - - DBGPRINT(RT_DEBUG_TRACE, ("-----> AironetMsgAction\n")); - - // 0. Get Aironet IAPP header first - pRMReq = (PAIRONET_RM_REQUEST_FRAME) &Elem->Msg[LENGTH_802_11]; - pData = (PUCHAR) &Elem->Msg[LENGTH_802_11]; - - // 1. Change endian format form network to little endian - Length = be2cpu16(pRMReq->IAPP.Length); - - // 2.0 Sanity check, this should only happen when CCX 2.0 support is enabled - if (pAd->StaCfg.CCXEnable != TRUE) - return; - - // 2.1 Radio measurement must be on - if (pAd->StaCfg.CCXControl.field.RMEnable != 1) - return; - - // 2.2. Debug print all bit information - DBGPRINT(RT_DEBUG_TRACE, ("IAPP ID & Length %d\n", Length)); - DBGPRINT(RT_DEBUG_TRACE, ("IAPP Type %x\n", pRMReq->IAPP.Type)); - DBGPRINT(RT_DEBUG_TRACE, ("IAPP SubType %x\n", pRMReq->IAPP.SubType)); - DBGPRINT(RT_DEBUG_TRACE, ("IAPP Dialog Token %x\n", pRMReq->IAPP.Token)); - DBGPRINT(RT_DEBUG_TRACE, ("IAPP Activation Delay %x\n", pRMReq->Delay)); - DBGPRINT(RT_DEBUG_TRACE, ("IAPP Measurement Offset %x\n", pRMReq->Offset)); - - // 3. Check IAPP frame type, it must be 0x32 for Cisco Aironet extension - if (pRMReq->IAPP.Type != AIRONET_IAPP_TYPE) - { - DBGPRINT(RT_DEBUG_ERROR, ("Wrong IAPP type for Cisco Aironet extension\n")); - return; - } - - // 4. Check IAPP frame subtype, it must be 0x01 for Cisco Aironet extension request. - // Since we are acting as client only, we will disregards reply subtype. - if (pRMReq->IAPP.SubType != AIRONET_IAPP_SUBTYPE_REQUEST) - { - DBGPRINT(RT_DEBUG_ERROR, ("Wrong IAPP subtype for Cisco Aironet extension\n")); - return; - } - - // 5. Verify Destination MAC and Source MAC, both should be all zeros. - if (! MAC_ADDR_EQUAL(pRMReq->IAPP.DA, ZERO_MAC_ADDR)) - { - DBGPRINT(RT_DEBUG_ERROR, ("Wrong IAPP DA for Cisco Aironet extension, it's not Zero\n")); - return; - } - - if (! MAC_ADDR_EQUAL(pRMReq->IAPP.SA, ZERO_MAC_ADDR)) - { - DBGPRINT(RT_DEBUG_ERROR, ("Wrong IAPP SA for Cisco Aironet extension, it's not Zero\n")); - return; - } - - // 6. Reinit all report related fields - NdisZeroMemory(pAd->StaCfg.FrameReportBuf, 2048); - NdisZeroMemory(pAd->StaCfg.BssReportOffset, sizeof(USHORT) * MAX_LEN_OF_BSS_TABLE); - NdisZeroMemory(pAd->StaCfg.MeasurementRequest, sizeof(RM_REQUEST_ACTION) * 4); - - // 7. Point to the start of first element report element - pAd->StaCfg.FrameReportLen = LENGTH_802_11 + sizeof(AIRONET_IAPP_HEADER); - DBGPRINT(RT_DEBUG_TRACE, ("FR len = %d\n", pAd->StaCfg.FrameReportLen)); - pAd->StaCfg.LastBssIndex = 0xff; - pAd->StaCfg.RMReqCnt = 0; - pAd->StaCfg.ParallelReq = FALSE; - pAd->StaCfg.ParallelDuration = 0; - pAd->StaCfg.ParallelChannel = 0; - pAd->StaCfg.IAPPToken = pRMReq->IAPP.Token; - pAd->StaCfg.CurrentRMReqIdx = 0; - pAd->StaCfg.CLBusyBytes = 0; - // Reset the statistics - for (i = 0; i < 8; i++) - pAd->StaCfg.RPIDensity[i] = 0; - - Index = 0; - - // 8. Save dialog token for report - pAd->StaCfg.IAPPToken = pRMReq->IAPP.Token; - - // Save Activation delay & measurement offset, Not really needed - - // 9. Point to the first request element - pData += sizeof(AIRONET_RM_REQUEST_FRAME); - // Length should exclude the CISCO Aironet SNAP header - Length -= (sizeof(AIRONET_RM_REQUEST_FRAME) - LENGTH_802_1_H); - - // 10. Start Parsing the Measurement elements. - // Be careful about multiple MR elements within one frames. - while (Length > 0) - { - pReqElem = (PRM_REQUEST_ACTION) pData; - switch (pReqElem->ReqElem.Eid) - { - case IE_MEASUREMENT_REQUEST: - // From the example, it seems we only need to support one request in one frame - // There is no multiple request in one frame. - // Besides, looks like we need to take care the measurement request only. - // The measurement request is always 4 bytes. - - // Start parsing this type of request. - // 0. Eid is IE_MEASUREMENT_REQUEST - // 1. Length didn't include Eid and Length field, it always be 8. - // 2. Measurement Token, we nned to save it for the corresponding report. - // 3. Measurement Mode, Although there are definitions, but we din't see value other than - // 0 from test specs examples. - // 4. Measurement Type, this is what we need to do. - switch (pReqElem->ReqElem.Type) - { - case MSRN_TYPE_CHANNEL_LOAD_REQ: - case MSRN_TYPE_NOISE_HIST_REQ: - case MSRN_TYPE_BEACON_REQ: - // Check the Enable non-serving channel measurement control - if (pAd->StaCfg.CCXControl.field.DCRMEnable == 0) - { - // Check channel before enqueue the action - if (pReqElem->Measurement.Channel != pAd->CommonCfg.Channel) - break; - } - else - { - // If off channel measurement, check the TU duration limit - if (pReqElem->Measurement.Channel != pAd->CommonCfg.Channel) - if (pReqElem->Measurement.Duration > pAd->StaCfg.CCXControl.field.TuLimit) - break; - } - - // Save requests and execute actions later - NdisMoveMemory(&pAd->StaCfg.MeasurementRequest[Index], pReqElem, sizeof(RM_REQUEST_ACTION)); - Index += 1; - break; - - case MSRN_TYPE_FRAME_REQ: - // Since it's option, we will support later - // FrameRequestAction(pAd, pData); - break; - - default: - break; - } - - // Point to next Measurement request - pData += sizeof(RM_REQUEST_ACTION); - Length -= sizeof(RM_REQUEST_ACTION); - break; - - // We accept request only, all others are dropped - case IE_MEASUREMENT_REPORT: - case IE_AP_TX_POWER: - case IE_MEASUREMENT_CAPABILITY: - default: - return; - } - } - - // 11. Update some flags and index - pAd->StaCfg.RMReqCnt = Index; - - if (Index) - { - MlmeEnqueue(pAd, AIRONET_STATE_MACHINE, MT2_AIRONET_SCAN_REQ, 0, NULL); - RT28XX_MLME_HANDLER(pAd); - } - - DBGPRINT(RT_DEBUG_TRACE, ("<----- AironetMsgAction\n")); -} - -/* - ======================================================================== - - Routine Description: - - Arguments: - - Return Value: - None - - Note: - - ======================================================================== -*/ -VOID AironetRequestAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - PRM_REQUEST_ACTION pReq; - - // 1. Point to next request element - pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[pAd->StaCfg.CurrentRMReqIdx]; - - // 2. Parse measurement type and call appropriate functions - if (pReq->ReqElem.Type == MSRN_TYPE_CHANNEL_LOAD_REQ) - // Channel Load measurement request - ChannelLoadRequestAction(pAd, pAd->StaCfg.CurrentRMReqIdx); - else if (pReq->ReqElem.Type == MSRN_TYPE_NOISE_HIST_REQ) - // Noise Histogram measurement request - NoiseHistRequestAction(pAd, pAd->StaCfg.CurrentRMReqIdx); - else if (pReq->ReqElem.Type == MSRN_TYPE_BEACON_REQ) - // Beacon measurement request - BeaconRequestAction(pAd, pAd->StaCfg.CurrentRMReqIdx); - else - // Unknown. Do nothing and return, this should never happen - return; - - // 3. Peek into the next request, if it's parallel, we will update the scan time to the largest one - if ((pAd->StaCfg.CurrentRMReqIdx + 1) < pAd->StaCfg.RMReqCnt) - { - pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[pAd->StaCfg.CurrentRMReqIdx + 1]; - // Check for parallel bit - if ((pReq->ReqElem.Mode & 0x01) && (pReq->Measurement.Channel == pAd->StaCfg.CCXScanChannel)) - { - // Update parallel mode request information - pAd->StaCfg.ParallelReq = TRUE; - pAd->StaCfg.CCXScanTime = ((pReq->Measurement.Duration > pAd->StaCfg.CCXScanTime) ? - (pReq->Measurement.Duration) : (pAd->StaCfg.CCXScanTime)); - } - } - - // 4. Call RT28XX_MLME_HANDLER to execute the request mlme commands, Scan request is the only one used - RT28XX_MLME_HANDLER(pAd); - -} - - -/* - ======================================================================== - - Routine Description: - Prepare channel load report action, special scan operation added - to support - - Arguments: - pAd Pointer to our adapter - pData Start from element ID - - Return Value: - None - - Note: - - ======================================================================== -*/ -VOID ChannelLoadRequestAction( - IN PRTMP_ADAPTER pAd, - IN UCHAR Index) -{ - PRM_REQUEST_ACTION pReq; - MLME_SCAN_REQ_STRUCT ScanReq; - UCHAR ZeroSsid[32]; - NDIS_STATUS NStatus; - PUCHAR pOutBuffer = NULL; - PHEADER_802_11 pNullFrame; - - DBGPRINT(RT_DEBUG_TRACE, ("ChannelLoadRequestAction ----->\n")); - - pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[Index]; - NdisZeroMemory(ZeroSsid, 32); - - // Prepare for special scan request - // The scan definition is different with our Active, Passive scan definition. - // For CCX2, Active means send out probe request with broadcast BSSID. - // Passive means no probe request sent, only listen to the beacons. - // The channel scanned is fixed as specified, no need to scan all channels. - // The scan wait time is specified in the request too. - // Passive scan Mode - - // Control state machine is not idle, reject the request - if ((pAd->Mlme.CntlMachine.CurrState != CNTL_IDLE) && (Index == 0)) - return; - - // Fill out stuff for scan request - ScanParmFill(pAd, &ScanReq, ZeroSsid, 0, BSS_ANY, SCAN_CISCO_CHANNEL_LOAD); - MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq); - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN; - - // Reset some internal control flags to make sure this scan works. - BssTableInit(&pAd->StaCfg.CCXBssTab); - pAd->StaCfg.ScanCnt = 0; - pAd->StaCfg.CCXScanChannel = pReq->Measurement.Channel; - pAd->StaCfg.CCXScanTime = pReq->Measurement.Duration; - - DBGPRINT(RT_DEBUG_TRACE, ("Duration %d, Channel %d!\n", pReq->Measurement.Duration, pReq->Measurement.Channel)); - - // If it's non serving channel scan, send out a null frame with PSM bit on. - if (pAd->StaCfg.CCXScanChannel != pAd->CommonCfg.Channel) - { - // Use MLME enqueue method - NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory - if (NStatus != NDIS_STATUS_SUCCESS) - return; - - pNullFrame = (PHEADER_802_11) pOutBuffer;; - // Make the power save Null frame with PSM bit on - MgtMacHeaderInit(pAd, pNullFrame, SUBTYPE_NULL_FUNC, 1, pAd->CommonCfg.Bssid, pAd->CommonCfg.Bssid); - pNullFrame->Duration = 0; - pNullFrame->FC.Type = BTYPE_DATA; - pNullFrame->FC.PwrMgmt = PWR_SAVE; - - // Send using priority queue - MiniportMMRequest(pAd, 0, pOutBuffer, sizeof(HEADER_802_11)); - MlmeFreeMemory(pAd, pOutBuffer); - DBGPRINT(RT_DEBUG_TRACE, ("Send PSM Data frame for off channel RM\n")); - RTMPusecDelay(5000); - } - - pAd->StaCfg.CCXReqType = MSRN_TYPE_CHANNEL_LOAD_REQ; - pAd->StaCfg.CLBusyBytes = 0; - // Enable Rx with promiscuous reception - RTMP_IO_WRITE32(pAd, RX_FILTR_CFG, 0x1010); - - // Set channel load measurement flag - RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_MEASUREMENT); - - pAd->Mlme.AironetMachine.CurrState = AIRONET_SCANNING; - - DBGPRINT(RT_DEBUG_TRACE, ("ChannelLoadRequestAction <-----\n")); -} - -/* - ======================================================================== - - Routine Description: - Prepare noise histogram report action, special scan operation added - to support - - Arguments: - pAd Pointer to our adapter - pData Start from element ID - - Return Value: - None - - Note: - - ======================================================================== -*/ -VOID NoiseHistRequestAction( - IN PRTMP_ADAPTER pAd, - IN UCHAR Index) -{ - PRM_REQUEST_ACTION pReq; - MLME_SCAN_REQ_STRUCT ScanReq; - UCHAR ZeroSsid[32], i; - NDIS_STATUS NStatus; - PUCHAR pOutBuffer = NULL; - PHEADER_802_11 pNullFrame; - - DBGPRINT(RT_DEBUG_TRACE, ("NoiseHistRequestAction ----->\n")); - - pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[Index]; - NdisZeroMemory(ZeroSsid, 32); - - // Prepare for special scan request - // The scan definition is different with our Active, Passive scan definition. - // For CCX2, Active means send out probe request with broadcast BSSID. - // Passive means no probe request sent, only listen to the beacons. - // The channel scanned is fixed as specified, no need to scan all channels. - // The scan wait time is specified in the request too. - // Passive scan Mode - - // Control state machine is not idle, reject the request - if ((pAd->Mlme.CntlMachine.CurrState != CNTL_IDLE) && (Index == 0)) - return; - - // Fill out stuff for scan request - ScanParmFill(pAd, &ScanReq, ZeroSsid, 0, BSS_ANY, SCAN_CISCO_NOISE); - MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq); - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN; - - // Reset some internal control flags to make sure this scan works. - BssTableInit(&pAd->StaCfg.CCXBssTab); - pAd->StaCfg.ScanCnt = 0; - pAd->StaCfg.CCXScanChannel = pReq->Measurement.Channel; - pAd->StaCfg.CCXScanTime = pReq->Measurement.Duration; - pAd->StaCfg.CCXReqType = MSRN_TYPE_NOISE_HIST_REQ; - - DBGPRINT(RT_DEBUG_TRACE, ("Duration %d, Channel %d!\n", pReq->Measurement.Duration, pReq->Measurement.Channel)); - - // If it's non serving channel scan, send out a null frame with PSM bit on. - if (pAd->StaCfg.CCXScanChannel != pAd->CommonCfg.Channel) - { - // Use MLME enqueue method - NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory - if (NStatus != NDIS_STATUS_SUCCESS) - return; - - pNullFrame = (PHEADER_802_11) pOutBuffer; - // Make the power save Null frame with PSM bit on - MgtMacHeaderInit(pAd, pNullFrame, SUBTYPE_NULL_FUNC, 1, pAd->CommonCfg.Bssid, pAd->CommonCfg.Bssid); - pNullFrame->Duration = 0; - pNullFrame->FC.Type = BTYPE_DATA; - pNullFrame->FC.PwrMgmt = PWR_SAVE; - - // Send using priority queue - MiniportMMRequest(pAd, 0, pOutBuffer, sizeof(HEADER_802_11)); - MlmeFreeMemory(pAd, pOutBuffer); - DBGPRINT(RT_DEBUG_TRACE, ("Send PSM Data frame for off channel RM\n")); - RTMPusecDelay(5000); - } - - // Reset the statistics - for (i = 0; i < 8; i++) - pAd->StaCfg.RPIDensity[i] = 0; - - // Enable Rx with promiscuous reception - RTMP_IO_WRITE32(pAd, RX_FILTR_CFG, 0x1010); - - // Set channel load measurement flag - RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_MEASUREMENT); - - pAd->Mlme.AironetMachine.CurrState = AIRONET_SCANNING; - - DBGPRINT(RT_DEBUG_TRACE, ("NoiseHistRequestAction <-----\n")); -} - -/* - ======================================================================== - - Routine Description: - Prepare Beacon report action, special scan operation added - to support - - Arguments: - pAd Pointer to our adapter - pData Start from element ID - - Return Value: - None - - Note: - - ======================================================================== -*/ -VOID BeaconRequestAction( - IN PRTMP_ADAPTER pAd, - IN UCHAR Index) -{ - PRM_REQUEST_ACTION pReq; - NDIS_STATUS NStatus; - PUCHAR pOutBuffer = NULL; - PHEADER_802_11 pNullFrame; - MLME_SCAN_REQ_STRUCT ScanReq; - UCHAR ZeroSsid[32]; - - DBGPRINT(RT_DEBUG_TRACE, ("BeaconRequestAction ----->\n")); - - pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[Index]; - NdisZeroMemory(ZeroSsid, 32); - - // Prepare for special scan request - // The scan definition is different with our Active, Passive scan definition. - // For CCX2, Active means send out probe request with broadcast BSSID. - // Passive means no probe request sent, only listen to the beacons. - // The channel scanned is fixed as specified, no need to scan all channels. - // The scan wait time is specified in the request too. - if (pReq->Measurement.ScanMode == MSRN_SCAN_MODE_PASSIVE) - { - // Passive scan Mode - DBGPRINT(RT_DEBUG_TRACE, ("Passive Scan Mode!\n")); - - // Control state machine is not idle, reject the request - if ((pAd->Mlme.CntlMachine.CurrState != CNTL_IDLE) && (Index == 0)) - return; - - // Fill out stuff for scan request - ScanParmFill(pAd, &ScanReq, ZeroSsid, 0, BSS_ANY, SCAN_CISCO_PASSIVE); - MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq); - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN; - - // Reset some internal control flags to make sure this scan works. - BssTableInit(&pAd->StaCfg.CCXBssTab); - pAd->StaCfg.ScanCnt = 0; - pAd->StaCfg.CCXScanChannel = pReq->Measurement.Channel; - pAd->StaCfg.CCXScanTime = pReq->Measurement.Duration; - pAd->StaCfg.CCXReqType = MSRN_TYPE_BEACON_REQ; - DBGPRINT(RT_DEBUG_TRACE, ("Duration %d!\n", pReq->Measurement.Duration)); - - // If it's non serving channel scan, send out a null frame with PSM bit on. - if (pAd->StaCfg.CCXScanChannel != pAd->CommonCfg.Channel) - { - // Use MLME enqueue method - NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory - if (NStatus != NDIS_STATUS_SUCCESS) - return; - - pNullFrame = (PHEADER_802_11) pOutBuffer; - // Make the power save Null frame with PSM bit on - MgtMacHeaderInit(pAd, pNullFrame, SUBTYPE_NULL_FUNC, 1, pAd->CommonCfg.Bssid, pAd->CommonCfg.Bssid); - pNullFrame->Duration = 0; - pNullFrame->FC.Type = BTYPE_DATA; - pNullFrame->FC.PwrMgmt = PWR_SAVE; - - // Send using priority queue - MiniportMMRequest(pAd, 0, pOutBuffer, sizeof(HEADER_802_11)); - MlmeFreeMemory(pAd, pOutBuffer); - DBGPRINT(RT_DEBUG_TRACE, ("Send PSM Data frame for off channel RM\n")); - RTMPusecDelay(5000); - } - - pAd->Mlme.AironetMachine.CurrState = AIRONET_SCANNING; - } - else if (pReq->Measurement.ScanMode == MSRN_SCAN_MODE_ACTIVE) - { - // Active scan Mode - DBGPRINT(RT_DEBUG_TRACE, ("Active Scan Mode!\n")); - - // Control state machine is not idle, reject the request - if (pAd->Mlme.CntlMachine.CurrState != CNTL_IDLE) - return; - - // Fill out stuff for scan request - ScanParmFill(pAd, &ScanReq, ZeroSsid, 0, BSS_ANY, SCAN_CISCO_ACTIVE); - MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq); - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN; - - // Reset some internal control flags to make sure this scan works. - BssTableInit(&pAd->StaCfg.CCXBssTab); - pAd->StaCfg.ScanCnt = 0; - pAd->StaCfg.CCXScanChannel = pReq->Measurement.Channel; - pAd->StaCfg.CCXScanTime = pReq->Measurement.Duration; - pAd->StaCfg.CCXReqType = MSRN_TYPE_BEACON_REQ; - DBGPRINT(RT_DEBUG_TRACE, ("Duration %d!\n", pReq->Measurement.Duration)); - - // If it's non serving channel scan, send out a null frame with PSM bit on. - if (pAd->StaCfg.CCXScanChannel != pAd->CommonCfg.Channel) - { - // Use MLME enqueue method - NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory - if (NStatus != NDIS_STATUS_SUCCESS) - return; - - pNullFrame = (PHEADER_802_11) pOutBuffer; - // Make the power save Null frame with PSM bit on - MgtMacHeaderInit(pAd, pNullFrame, SUBTYPE_NULL_FUNC, 1, pAd->CommonCfg.Bssid, pAd->CommonCfg.Bssid); - pNullFrame->Duration = 0; - pNullFrame->FC.Type = BTYPE_DATA; - pNullFrame->FC.PwrMgmt = PWR_SAVE; - - // Send using priority queue - MiniportMMRequest(pAd, 0, pOutBuffer, sizeof(HEADER_802_11)); - MlmeFreeMemory(pAd, pOutBuffer); - DBGPRINT(RT_DEBUG_TRACE, ("Send PSM Data frame for off channel RM\n")); - RTMPusecDelay(5000); - } - - pAd->Mlme.AironetMachine.CurrState = AIRONET_SCANNING; - } - else if (pReq->Measurement.ScanMode == MSRN_SCAN_MODE_BEACON_TABLE) - { - // Beacon report Mode, report all the APS in current bss table - DBGPRINT(RT_DEBUG_TRACE, ("Beacon Report Mode!\n")); - - // Copy current BSS table to CCX table, we can omit this step later on. - NdisMoveMemory(&pAd->StaCfg.CCXBssTab, &pAd->ScanTab, sizeof(BSS_TABLE)); - - // Create beacon report from Bss table - AironetCreateBeaconReportFromBssTable(pAd); - - // Set state to scanning - pAd->Mlme.AironetMachine.CurrState = AIRONET_SCANNING; - - // Enqueue report request - // Cisco scan request is finished, prepare beacon report - MlmeEnqueue(pAd, AIRONET_STATE_MACHINE, MT2_AIRONET_SCAN_DONE, 0, NULL); - } - else - { - // Wrong scan Mode - DBGPRINT(RT_DEBUG_TRACE, ("Wrong Scan Mode!\n")); - } - - DBGPRINT(RT_DEBUG_TRACE, ("BeaconRequestAction <-----\n")); -} - -/* - ======================================================================== - - Routine Description: - - Arguments: - - Return Value: - None - - Note: - - ======================================================================== -*/ -VOID AironetReportAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - PRM_REQUEST_ACTION pReq; - ULONG Now32; - - NdisGetSystemUpTime(&Now32); - pAd->StaCfg.LastBeaconRxTime = Now32; - - pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[pAd->StaCfg.CurrentRMReqIdx]; - - DBGPRINT(RT_DEBUG_TRACE, ("AironetReportAction ----->\n")); - - // 1. Parse measurement type and call appropriate functions - if (pReq->ReqElem.Type == MSRN_TYPE_CHANNEL_LOAD_REQ) - // Channel Load measurement request - ChannelLoadReportAction(pAd, pAd->StaCfg.CurrentRMReqIdx); - else if (pReq->ReqElem.Type == MSRN_TYPE_NOISE_HIST_REQ) - // Noise Histogram measurement request - NoiseHistReportAction(pAd, pAd->StaCfg.CurrentRMReqIdx); - else if (pReq->ReqElem.Type == MSRN_TYPE_BEACON_REQ) - // Beacon measurement request - BeaconReportAction(pAd, pAd->StaCfg.CurrentRMReqIdx); - else - // Unknown. Do nothing and return - ; - - // 2. Point to the correct index of action element, start from 0 - pAd->StaCfg.CurrentRMReqIdx++; - - // 3. Check for parallel actions - if (pAd->StaCfg.ParallelReq == TRUE) - { - pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[pAd->StaCfg.CurrentRMReqIdx]; - - // Process next action right away - if (pReq->ReqElem.Type == MSRN_TYPE_CHANNEL_LOAD_REQ) - // Channel Load measurement request - ChannelLoadReportAction(pAd, pAd->StaCfg.CurrentRMReqIdx); - else if (pReq->ReqElem.Type == MSRN_TYPE_NOISE_HIST_REQ) - // Noise Histogram measurement request - NoiseHistReportAction(pAd, pAd->StaCfg.CurrentRMReqIdx); - - pAd->StaCfg.ParallelReq = FALSE; - pAd->StaCfg.CurrentRMReqIdx++; - } - - if (pAd->StaCfg.CurrentRMReqIdx >= pAd->StaCfg.RMReqCnt) - { - // 4. There is no more unprocessed measurement request, go for transmit this report - AironetFinalReportAction(pAd); - pAd->Mlme.AironetMachine.CurrState = AIRONET_IDLE; - } - else - { - pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[pAd->StaCfg.CurrentRMReqIdx]; - - if (pReq->Measurement.Channel != pAd->CommonCfg.Channel) - { - RTMPusecDelay(100000); - } - - // 5. There are more requests to be measure - MlmeEnqueue(pAd, AIRONET_STATE_MACHINE, MT2_AIRONET_SCAN_REQ, 0, NULL); - RT28XX_MLME_HANDLER(pAd); - } - - DBGPRINT(RT_DEBUG_TRACE, ("AironetReportAction <-----\n")); -} - -/* - ======================================================================== - - Routine Description: - - Arguments: - - Return Value: - None - - Note: - - ======================================================================== -*/ -VOID AironetFinalReportAction( - IN PRTMP_ADAPTER pAd) -{ - PUCHAR pDest; - PAIRONET_IAPP_HEADER pIAPP; - PHEADER_802_11 pHeader; - UCHAR AckRate = RATE_2; - USHORT AckDuration = 0; - NDIS_STATUS NStatus; - PUCHAR pOutBuffer = NULL; - ULONG FrameLen = 0; - - DBGPRINT(RT_DEBUG_TRACE, ("AironetFinalReportAction ----->\n")); - - // 0. Set up the frame pointer, Frame was inited at the end of message action - pDest = &pAd->StaCfg.FrameReportBuf[LENGTH_802_11]; - - // 1. Update report IAPP fields - pIAPP = (PAIRONET_IAPP_HEADER) pDest; - - // 2. Copy Cisco SNAP header - NdisMoveMemory(pIAPP->CiscoSnapHeader, SNAP_AIRONET, LENGTH_802_1_H); - - // 3. network order for this 16bit length - pIAPP->Length = cpu2be16(pAd->StaCfg.FrameReportLen - LENGTH_802_11 - LENGTH_802_1_H); - - // 3.1 sanity check the report length, ignore it if there is nothing to report - if (be2cpu16(pIAPP->Length) <= 18) - return; - - // 4. Type must be 0x32 - pIAPP->Type = AIRONET_IAPP_TYPE; - - // 5. SubType for report must be 0x81 - pIAPP->SubType = AIRONET_IAPP_SUBTYPE_REPORT; - - // 6. DA is not used and must be zero, although the whole frame was cleared at the start of function - // We will do it again here. We can use BSSID instead - COPY_MAC_ADDR(pIAPP->DA, pAd->CommonCfg.Bssid); - - // 7. SA is the client reporting which must be our MAC - COPY_MAC_ADDR(pIAPP->SA, pAd->CurrentAddress); - - // 8. Copy the saved dialog token - pIAPP->Token = pAd->StaCfg.IAPPToken; - - // 9. Make the Report frame 802.11 header - // Reuse function in wpa.c - pHeader = (PHEADER_802_11) pAd->StaCfg.FrameReportBuf; - pAd->Sequence ++; - WpaMacHeaderInit(pAd, pHeader, 0, pAd->CommonCfg.Bssid); - - // ACK size is 14 include CRC, and its rate is based on real time information - AckRate = pAd->CommonCfg.ExpectedACKRate[pAd->CommonCfg.MlmeRate]; - AckDuration = RTMPCalcDuration(pAd, AckRate, 14); - pHeader->Duration = pAd->CommonCfg.Dsifs + AckDuration; - - // Use MLME enqueue method - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory - if (NStatus != NDIS_STATUS_SUCCESS) - return; - - // 10. Prepare report frame with dynamic outbuffer. Just simply copy everything. - MakeOutgoingFrame(pOutBuffer, &FrameLen, - pAd->StaCfg.FrameReportLen, pAd->StaCfg.FrameReportBuf, - END_OF_ARGS); - - // 11. Send using priority queue - MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); - - pAd->StaCfg.CCXReqType = MSRN_TYPE_UNUSED; - - DBGPRINT(RT_DEBUG_TRACE, ("AironetFinalReportAction <-----\n")); -} - -/* - ======================================================================== - - Routine Description: - - Arguments: - - Return Value: - None - - Note: - - ======================================================================== -*/ -VOID ChannelLoadReportAction( - IN PRTMP_ADAPTER pAd, - IN UCHAR Index) -{ - PMEASUREMENT_REPORT_ELEMENT pReport; - PCHANNEL_LOAD_REPORT pLoad; - PUCHAR pDest; - UCHAR CCABusyFraction; - - DBGPRINT(RT_DEBUG_TRACE, ("ChannelLoadReportAction ----->\n")); - - // Disable Rx with promiscuous reception, make it back to normal - RTMP_IO_WRITE32(pAd, RX_FILTR_CFG, STANORMAL); // Staion not drop control frame will fail WiFi Certification. - - // 0. Setup pointer for processing beacon & probe response - pDest = (PUCHAR) &pAd->StaCfg.FrameReportBuf[pAd->StaCfg.FrameReportLen]; - pReport = (PMEASUREMENT_REPORT_ELEMENT) pDest; - - // 1. Fill Measurement report element field. - pReport->Eid = IE_MEASUREMENT_REPORT; - // Fixed Length at 9, not include Eid and length fields - pReport->Length = 9; - pReport->Token = pAd->StaCfg.MeasurementRequest[Index].ReqElem.Token; - pReport->Mode = pAd->StaCfg.MeasurementRequest[Index].ReqElem.Mode; - pReport->Type = MSRN_TYPE_CHANNEL_LOAD_REQ; - - // 2. Fill channel report measurement data - pDest += sizeof(MEASUREMENT_REPORT_ELEMENT); - pLoad = (PCHANNEL_LOAD_REPORT) pDest; - pLoad->Channel = pAd->StaCfg.MeasurementRequest[Index].Measurement.Channel; - pLoad->Spare = 0; - pLoad->Duration = pAd->StaCfg.MeasurementRequest[Index].Measurement.Duration; - - // 3. Calculate the CCA Busy Fraction - // (Bytes + ACK size) * 8 / Tx speed * 255 / 1000 / measurement duration, use 24 us Tx speed - // = (Bytes + ACK) / 12 / duration - // 9 is the good value for pAd->StaCfg.CLFactor - // CCABusyFraction = (UCHAR) (pAd->StaCfg.CLBusyBytes / 9 / pLoad->Duration); - CCABusyFraction = (UCHAR) (pAd->StaCfg.CLBusyBytes / pAd->StaCfg.CLFactor / pLoad->Duration); - if (CCABusyFraction < 10) - CCABusyFraction = (UCHAR) (pAd->StaCfg.CLBusyBytes / 3 / pLoad->Duration) + 1; - - pLoad->CCABusy = CCABusyFraction; - DBGPRINT(RT_DEBUG_TRACE, ("CLBusyByte %ld, Duration %d, Result, %d\n", pAd->StaCfg.CLBusyBytes, pLoad->Duration, CCABusyFraction)); - - DBGPRINT(RT_DEBUG_TRACE, ("FrameReportLen %d\n", pAd->StaCfg.FrameReportLen)); - pAd->StaCfg.FrameReportLen += (sizeof(MEASUREMENT_REPORT_ELEMENT) + sizeof(CHANNEL_LOAD_REPORT)); - DBGPRINT(RT_DEBUG_TRACE, ("FrameReportLen %d\n", pAd->StaCfg.FrameReportLen)); - - // 4. Clear channel load measurement flag - RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_MEASUREMENT); - - // 5. reset to idle state - pAd->Mlme.AironetMachine.CurrState = AIRONET_IDLE; - - DBGPRINT(RT_DEBUG_TRACE, ("ChannelLoadReportAction <-----\n")); -} - -/* - ======================================================================== - - Routine Description: - - Arguments: - - Return Value: - None - - Note: - - ======================================================================== -*/ -VOID NoiseHistReportAction( - IN PRTMP_ADAPTER pAd, - IN UCHAR Index) -{ - PMEASUREMENT_REPORT_ELEMENT pReport; - PNOISE_HIST_REPORT pNoise; - PUCHAR pDest; - UCHAR i,NoiseCnt; - USHORT TotalRPICnt, TotalRPISum; - - DBGPRINT(RT_DEBUG_TRACE, ("NoiseHistReportAction ----->\n")); - - // 0. Disable Rx with promiscuous reception, make it back to normal - RTMP_IO_WRITE32(pAd, RX_FILTR_CFG, STANORMAL); // Staion not drop control frame will fail WiFi Certification. - // 1. Setup pointer for processing beacon & probe response - pDest = (PUCHAR) &pAd->StaCfg.FrameReportBuf[pAd->StaCfg.FrameReportLen]; - pReport = (PMEASUREMENT_REPORT_ELEMENT) pDest; - - // 2. Fill Measurement report element field. - pReport->Eid = IE_MEASUREMENT_REPORT; - // Fixed Length at 16, not include Eid and length fields - pReport->Length = 16; - pReport->Token = pAd->StaCfg.MeasurementRequest[Index].ReqElem.Token; - pReport->Mode = pAd->StaCfg.MeasurementRequest[Index].ReqElem.Mode; - pReport->Type = MSRN_TYPE_NOISE_HIST_REQ; - - // 3. Fill noise histogram report measurement data - pDest += sizeof(MEASUREMENT_REPORT_ELEMENT); - pNoise = (PNOISE_HIST_REPORT) pDest; - pNoise->Channel = pAd->StaCfg.MeasurementRequest[Index].Measurement.Channel; - pNoise->Spare = 0; - pNoise->Duration = pAd->StaCfg.MeasurementRequest[Index].Measurement.Duration; - // 4. Fill Noise histogram, the total RPI counts should be 0.4 * TU - // We estimate 4000 normal packets received durning 10 seconds test. - // Adjust it if required. - // 3 is a good value for pAd->StaCfg.NHFactor - // TotalRPICnt = pNoise->Duration * 3 / 10; - TotalRPICnt = pNoise->Duration * pAd->StaCfg.NHFactor / 10; - TotalRPISum = 0; - - for (i = 0; i < 8; i++) - { - TotalRPISum += pAd->StaCfg.RPIDensity[i]; - DBGPRINT(RT_DEBUG_TRACE, ("RPI %d Conuts %d\n", i, pAd->StaCfg.RPIDensity[i])); - } - - // Double check if the counter is larger than our expectation. - // We will replace it with the total number plus a fraction. - if (TotalRPISum > TotalRPICnt) - TotalRPICnt = TotalRPISum + pNoise->Duration / 20; - - DBGPRINT(RT_DEBUG_TRACE, ("Total RPI Conuts %d\n", TotalRPICnt)); - - // 5. Initialize noise count for the total summation of 0xff - NoiseCnt = 0; - for (i = 1; i < 8; i++) - { - pNoise->Density[i] = (UCHAR) (pAd->StaCfg.RPIDensity[i] * 255 / TotalRPICnt); - if ((pNoise->Density[i] == 0) && (pAd->StaCfg.RPIDensity[i] != 0)) - pNoise->Density[i]++; - NoiseCnt += pNoise->Density[i]; - DBGPRINT(RT_DEBUG_TRACE, ("Reported RPI[%d] = 0x%02x\n", i, pNoise->Density[i])); - } - - // 6. RPI[0] represents the rest of counts - pNoise->Density[0] = 0xff - NoiseCnt; - DBGPRINT(RT_DEBUG_TRACE, ("Reported RPI[0] = 0x%02x\n", pNoise->Density[0])); - - pAd->StaCfg.FrameReportLen += (sizeof(MEASUREMENT_REPORT_ELEMENT) + sizeof(NOISE_HIST_REPORT)); - - // 7. Clear channel load measurement flag - RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_MEASUREMENT); - - // 8. reset to idle state - pAd->Mlme.AironetMachine.CurrState = AIRONET_IDLE; - - DBGPRINT(RT_DEBUG_TRACE, ("NoiseHistReportAction <-----\n")); -} - -/* - ======================================================================== - - Routine Description: - Prepare Beacon report action, - - Arguments: - pAd Pointer to our adapter - - Return Value: - None - - Note: - - ======================================================================== -*/ -VOID BeaconReportAction( - IN PRTMP_ADAPTER pAd, - IN UCHAR Index) -{ - DBGPRINT(RT_DEBUG_TRACE, ("BeaconReportAction ----->\n")); - - // Looks like we don't have anything thing need to do here. - // All measurement report already finished in AddBeaconReport - // The length is in the FrameReportLen - - // reset Beacon index for next beacon request - pAd->StaCfg.LastBssIndex = 0xff; - - // reset to idle state - pAd->Mlme.AironetMachine.CurrState = AIRONET_IDLE; - - DBGPRINT(RT_DEBUG_TRACE, ("BeaconReportAction <-----\n")); -} - -/* - ======================================================================== - - Routine Description: - - Arguments: - Index Current BSSID in CCXBsstab entry index - - Return Value: - - Note: - - ======================================================================== -*/ -VOID AironetAddBeaconReport( - IN PRTMP_ADAPTER pAd, - IN ULONG Index, - IN PMLME_QUEUE_ELEM pElem) -{ - PVOID pMsg; - PUCHAR pSrc, pDest; - UCHAR ReqIdx; - ULONG MsgLen; - USHORT Length; - PFRAME_802_11 pFrame; - PMEASUREMENT_REPORT_ELEMENT pReport; - PEID_STRUCT pEid; - PBEACON_REPORT pBeaconReport; - PBSS_ENTRY pBss; - - // 0. Setup pointer for processing beacon & probe response - pMsg = pElem->Msg; - MsgLen = pElem->MsgLen; - pFrame = (PFRAME_802_11) pMsg; - pSrc = pFrame->Octet; // Start from AP TSF - pBss = (PBSS_ENTRY) &pAd->StaCfg.CCXBssTab.BssEntry[Index]; - ReqIdx = pAd->StaCfg.CurrentRMReqIdx; - - // 1 Check the Index, if we already create this entry, only update the average RSSI - if ((Index <= pAd->StaCfg.LastBssIndex) && (pAd->StaCfg.LastBssIndex != 0xff)) - { - pDest = (PUCHAR) &pAd->StaCfg.FrameReportBuf[pAd->StaCfg.BssReportOffset[Index]]; - // Point to bss report information - pDest += sizeof(MEASUREMENT_REPORT_ELEMENT); - pBeaconReport = (PBEACON_REPORT) pDest; - - // Update Rx power, in dBm - // Get the original RSSI readback from BBP - pBeaconReport->RxPower += pAd->BbpRssiToDbmDelta; - // Average the Rssi reading - pBeaconReport->RxPower = (pBeaconReport->RxPower + pBss->Rssi) / 2; - // Get to dBm format - pBeaconReport->RxPower -= pAd->BbpRssiToDbmDelta; - - DBGPRINT(RT_DEBUG_TRACE, ("Bssid %02x:%02x:%02x:%02x:%02x:%02x ", - pBss->Bssid[0], pBss->Bssid[1], pBss->Bssid[2], - pBss->Bssid[3], pBss->Bssid[4], pBss->Bssid[5])); - DBGPRINT(RT_DEBUG_TRACE, ("RxPower[%ld] Rssi %d, Avg Rssi %d\n", Index, (pBss->Rssi - pAd->BbpRssiToDbmDelta), pBeaconReport->RxPower - 256)); - DBGPRINT(RT_DEBUG_TRACE, ("FrameReportLen = %d\n", pAd->StaCfg.BssReportOffset[Index])); - - // Update other information here - - // Done - return; - } - - // 2. Update reported Index - pAd->StaCfg.LastBssIndex = Index; - - // 3. Setup the buffer address for copying this BSSID into reporting frame - // The offset should start after 802.11 header and report frame header. - pDest = (PUCHAR) &pAd->StaCfg.FrameReportBuf[pAd->StaCfg.FrameReportLen]; - - // 4. Save the start offset of each Bss in report frame - pAd->StaCfg.BssReportOffset[Index] = pAd->StaCfg.FrameReportLen; - - // 5. Fill Measurement report fields - pReport = (PMEASUREMENT_REPORT_ELEMENT) pDest; - pReport->Eid = IE_MEASUREMENT_REPORT; - pReport->Length = 0; - pReport->Token = pAd->StaCfg.MeasurementRequest[ReqIdx].ReqElem.Token; - pReport->Mode = pAd->StaCfg.MeasurementRequest[ReqIdx].ReqElem.Mode; - pReport->Type = MSRN_TYPE_BEACON_REQ; - Length = sizeof(MEASUREMENT_REPORT_ELEMENT); - pDest += sizeof(MEASUREMENT_REPORT_ELEMENT); - - // 6. Start thebeacon report format - pBeaconReport = (PBEACON_REPORT) pDest; - pDest += sizeof(BEACON_REPORT); - Length += sizeof(BEACON_REPORT); - - // 7. Copy Channel number - pBeaconReport->Channel = pBss->Channel; - pBeaconReport->Spare = 0; - pBeaconReport->Duration = pAd->StaCfg.MeasurementRequest[ReqIdx].Measurement.Duration; - pBeaconReport->PhyType = ((pBss->SupRateLen+pBss->ExtRateLen > 4) ? PHY_ERP : PHY_DSS); - // 8. Rx power, in dBm - pBeaconReport->RxPower = pBss->Rssi - pAd->BbpRssiToDbmDelta; - - DBGPRINT(RT_DEBUG_TRACE, ("Bssid %02x:%02x:%02x:%02x:%02x:%02x ", - pBss->Bssid[0], pBss->Bssid[1], pBss->Bssid[2], - pBss->Bssid[3], pBss->Bssid[4], pBss->Bssid[5])); - DBGPRINT(RT_DEBUG_TRACE, ("RxPower[%ld], Rssi %d\n", Index, pBeaconReport->RxPower - 256)); - DBGPRINT(RT_DEBUG_TRACE, ("FrameReportLen = %d\n", pAd->StaCfg.FrameReportLen)); - - pBeaconReport->BeaconInterval = pBss->BeaconPeriod; - COPY_MAC_ADDR(pBeaconReport->BSSID, pFrame->Hdr.Addr3); - NdisMoveMemory(pBeaconReport->ParentTSF, pSrc, 4); - NdisMoveMemory(pBeaconReport->TargetTSF, &pElem->TimeStamp.u.LowPart, 4); - NdisMoveMemory(&pBeaconReport->TargetTSF[4], &pElem->TimeStamp.u.HighPart, 4); - - // 9. Skip the beacon frame and offset to start of capabilityinfo since we already processed capabilityinfo - pSrc += (TIMESTAMP_LEN + 2); - pBeaconReport->CapabilityInfo = *(USHORT *)pSrc; - - // 10. Point to start of element ID - pSrc += 2; - pEid = (PEID_STRUCT) pSrc; - - // 11. Start process all variable Eid oayload and add the appropriate to the frame report - while (((PUCHAR) pEid + pEid->Len + 1) < ((PUCHAR) pFrame + MsgLen)) - { - // Only limited EID are required to report for CCX 2. It includes SSID, Supported rate, - // FH paramenter set, DS parameter set, CF parameter set, IBSS parameter set, - // TIM (report first 4 bytes only, radio measurement capability - switch (pEid->Eid) - { - case IE_SSID: - case IE_SUPP_RATES: - case IE_FH_PARM: - case IE_DS_PARM: - case IE_CF_PARM: - case IE_IBSS_PARM: - NdisMoveMemory(pDest, pEid, pEid->Len + 2); - pDest += (pEid->Len + 2); - Length += (pEid->Len + 2); - break; - - case IE_MEASUREMENT_CAPABILITY: - // Since this IE is duplicated with WPA security IE, we has to do sanity check before - // recognize it. - // 1. It also has fixed 6 bytes IE length. - if (pEid->Len != 6) - break; - // 2. Check the Cisco Aironet OUI - if (NdisEqualMemory(CISCO_OUI, (pSrc + 2), 3)) - { - // Matched, this is what we want - NdisMoveMemory(pDest, pEid, pEid->Len + 2); - pDest += (pEid->Len + 2); - Length += (pEid->Len + 2); - } - break; - - case IE_TIM: - if (pEid->Len > 4) - { - // May truncate and report the first 4 bytes only, with the eid & len, total should be 6 - NdisMoveMemory(pDest, pEid, 6); - pDest += 6; - Length += 6; - } - else - { - NdisMoveMemory(pDest, pEid, pEid->Len + 2); - pDest += (pEid->Len + 2); - Length += (pEid->Len + 2); - } - break; - - default: - break; - } - // 12. Move to next element ID - pSrc += (2 + pEid->Len); - pEid = (PEID_STRUCT) pSrc; - } - - // 13. Update the length in the header, not include EID and length - pReport->Length = Length - 4; - - // 14. Update the frame report buffer data length - pAd->StaCfg.FrameReportLen += Length; - DBGPRINT(RT_DEBUG_TRACE, ("FR len = %d\n", pAd->StaCfg.FrameReportLen)); -} - -/* - ======================================================================== - - Routine Description: - - Arguments: - Index Current BSSID in CCXBsstab entry index - - Return Value: - - Note: - - ======================================================================== -*/ -VOID AironetCreateBeaconReportFromBssTable( - IN PRTMP_ADAPTER pAd) -{ - PMEASUREMENT_REPORT_ELEMENT pReport; - PBEACON_REPORT pBeaconReport; - UCHAR Index, ReqIdx; - USHORT Length; - PUCHAR pDest; - PBSS_ENTRY pBss; - - // 0. setup base pointer - ReqIdx = pAd->StaCfg.CurrentRMReqIdx; - - for (Index = 0; Index < pAd->StaCfg.CCXBssTab.BssNr; Index++) - { - // 1. Setup the buffer address for copying this BSSID into reporting frame - // The offset should start after 802.11 header and report frame header. - pDest = (PUCHAR) &pAd->StaCfg.FrameReportBuf[pAd->StaCfg.FrameReportLen]; - pBss = (PBSS_ENTRY) &pAd->StaCfg.CCXBssTab.BssEntry[Index]; - Length = 0; - - // 2. Fill Measurement report fields - pReport = (PMEASUREMENT_REPORT_ELEMENT) pDest; - pReport->Eid = IE_MEASUREMENT_REPORT; - pReport->Length = 0; - pReport->Token = pAd->StaCfg.MeasurementRequest[ReqIdx].ReqElem.Token; - pReport->Mode = pAd->StaCfg.MeasurementRequest[ReqIdx].ReqElem.Mode; - pReport->Type = MSRN_TYPE_BEACON_REQ; - Length = sizeof(MEASUREMENT_REPORT_ELEMENT); - pDest += sizeof(MEASUREMENT_REPORT_ELEMENT); - - // 3. Start the beacon report format - pBeaconReport = (PBEACON_REPORT) pDest; - pDest += sizeof(BEACON_REPORT); - Length += sizeof(BEACON_REPORT); - - // 4. Copy Channel number - pBeaconReport->Channel = pBss->Channel; - pBeaconReport->Spare = 0; - pBeaconReport->Duration = pAd->StaCfg.MeasurementRequest[ReqIdx].Measurement.Duration; - pBeaconReport->PhyType = ((pBss->SupRateLen+pBss->ExtRateLen > 4) ? PHY_ERP : PHY_DSS); - pBeaconReport->RxPower = pBss->Rssi - pAd->BbpRssiToDbmDelta; - pBeaconReport->BeaconInterval = pBss->BeaconPeriod; - pBeaconReport->CapabilityInfo = pBss->CapabilityInfo; - COPY_MAC_ADDR(pBeaconReport->BSSID, pBss->Bssid); - NdisMoveMemory(pBeaconReport->ParentTSF, pBss->PTSF, 4); - NdisMoveMemory(pBeaconReport->TargetTSF, pBss->TTSF, 8); - - // 5. Create SSID - *pDest++ = 0x00; - *pDest++ = pBss->SsidLen; - NdisMoveMemory(pDest, pBss->Ssid, pBss->SsidLen); - pDest += pBss->SsidLen; - Length += (2 + pBss->SsidLen); - - // 6. Create SupportRates - *pDest++ = 0x01; - *pDest++ = pBss->SupRateLen; - NdisMoveMemory(pDest, pBss->SupRate, pBss->SupRateLen); - pDest += pBss->SupRateLen; - Length += (2 + pBss->SupRateLen); - - // 7. DS Parameter - *pDest++ = 0x03; - *pDest++ = 1; - *pDest++ = pBss->Channel; - Length += 3; - - // 8. IBSS parameter if presents - if (pBss->BssType == BSS_ADHOC) - { - *pDest++ = 0x06; - *pDest++ = 2; - *(PUSHORT) pDest = pBss->AtimWin; - pDest += 2; - Length += 4; - } - - // 9. Update length field, not include EID and length - pReport->Length = Length - 4; - - // 10. Update total frame size - pAd->StaCfg.FrameReportLen += Length; - } -} +#include "../../rt2860/sta/aironet.c" diff --git a/drivers/staging/rt2870/sta/assoc.c b/drivers/staging/rt2870/sta/assoc.c index a76dab500bcb..46564d7a01a9 100644 --- a/drivers/staging/rt2870/sta/assoc.c +++ b/drivers/staging/rt2870/sta/assoc.c @@ -1,2039 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - assoc.c - - Abstract: - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - John 2004-9-3 porting from RT2500 -*/ -#include "../rt_config.h" - -UCHAR CipherWpaTemplate[] = { - 0xdd, // WPA IE - 0x16, // Length - 0x00, 0x50, 0xf2, 0x01, // oui - 0x01, 0x00, // Version - 0x00, 0x50, 0xf2, 0x02, // Multicast - 0x01, 0x00, // Number of unicast - 0x00, 0x50, 0xf2, 0x02, // unicast - 0x01, 0x00, // number of authentication method - 0x00, 0x50, 0xf2, 0x01 // authentication - }; - -UCHAR CipherWpa2Template[] = { - 0x30, // RSN IE - 0x14, // Length - 0x01, 0x00, // Version - 0x00, 0x0f, 0xac, 0x02, // group cipher, TKIP - 0x01, 0x00, // number of pairwise - 0x00, 0x0f, 0xac, 0x02, // unicast - 0x01, 0x00, // number of authentication method - 0x00, 0x0f, 0xac, 0x02, // authentication - 0x00, 0x00, // RSN capability - }; - -UCHAR Ccx2IeInfo[] = { 0x00, 0x40, 0x96, 0x03, 0x02}; - -/* - ========================================================================== - Description: - association state machine init, including state transition and timer init - Parameters: - S - pointer to the association state machine - - IRQL = PASSIVE_LEVEL - - ========================================================================== - */ -VOID AssocStateMachineInit( - IN PRTMP_ADAPTER pAd, - IN STATE_MACHINE *S, - OUT STATE_MACHINE_FUNC Trans[]) -{ - StateMachineInit(S, Trans, MAX_ASSOC_STATE, MAX_ASSOC_MSG, (STATE_MACHINE_FUNC)Drop, ASSOC_IDLE, ASSOC_MACHINE_BASE); - - // first column - StateMachineSetAction(S, ASSOC_IDLE, MT2_MLME_ASSOC_REQ, (STATE_MACHINE_FUNC)MlmeAssocReqAction); - StateMachineSetAction(S, ASSOC_IDLE, MT2_MLME_REASSOC_REQ, (STATE_MACHINE_FUNC)MlmeReassocReqAction); - StateMachineSetAction(S, ASSOC_IDLE, MT2_MLME_DISASSOC_REQ, (STATE_MACHINE_FUNC)MlmeDisassocReqAction); - StateMachineSetAction(S, ASSOC_IDLE, MT2_PEER_DISASSOC_REQ, (STATE_MACHINE_FUNC)PeerDisassocAction); - - // second column - StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_MLME_ASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenAssoc); - StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_MLME_REASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenReassoc); - StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_MLME_DISASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenDisassociate); - StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_PEER_DISASSOC_REQ, (STATE_MACHINE_FUNC)PeerDisassocAction); - StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_PEER_ASSOC_RSP, (STATE_MACHINE_FUNC)PeerAssocRspAction); - // - // Patch 3Com AP MOde:3CRWE454G72 - // We send Assoc request frame to this AP, it always send Reassoc Rsp not Associate Rsp. - // - StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_PEER_REASSOC_RSP, (STATE_MACHINE_FUNC)PeerAssocRspAction); - StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_ASSOC_TIMEOUT, (STATE_MACHINE_FUNC)AssocTimeoutAction); - - // third column - StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_MLME_ASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenAssoc); - StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_MLME_REASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenReassoc); - StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_MLME_DISASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenDisassociate); - StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_PEER_DISASSOC_REQ, (STATE_MACHINE_FUNC)PeerDisassocAction); - StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_PEER_REASSOC_RSP, (STATE_MACHINE_FUNC)PeerReassocRspAction); - // - // Patch, AP doesn't send Reassociate Rsp frame to Station. - // - StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_PEER_ASSOC_RSP, (STATE_MACHINE_FUNC)PeerReassocRspAction); - StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_REASSOC_TIMEOUT, (STATE_MACHINE_FUNC)ReassocTimeoutAction); - - // fourth column - StateMachineSetAction(S, DISASSOC_WAIT_RSP, MT2_MLME_ASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenAssoc); - StateMachineSetAction(S, DISASSOC_WAIT_RSP, MT2_MLME_REASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenReassoc); - StateMachineSetAction(S, DISASSOC_WAIT_RSP, MT2_MLME_DISASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenDisassociate); - StateMachineSetAction(S, DISASSOC_WAIT_RSP, MT2_PEER_DISASSOC_REQ, (STATE_MACHINE_FUNC)PeerDisassocAction); - StateMachineSetAction(S, DISASSOC_WAIT_RSP, MT2_DISASSOC_TIMEOUT, (STATE_MACHINE_FUNC)DisassocTimeoutAction); - - // initialize the timer - RTMPInitTimer(pAd, &pAd->MlmeAux.AssocTimer, GET_TIMER_FUNCTION(AssocTimeout), pAd, FALSE); - RTMPInitTimer(pAd, &pAd->MlmeAux.ReassocTimer, GET_TIMER_FUNCTION(ReassocTimeout), pAd, FALSE); - RTMPInitTimer(pAd, &pAd->MlmeAux.DisassocTimer, GET_TIMER_FUNCTION(DisassocTimeout), pAd, FALSE); -} - -/* - ========================================================================== - Description: - Association timeout procedure. After association timeout, this function - will be called and it will put a message into the MLME queue - Parameters: - Standard timer parameters - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID AssocTimeout(IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3) -{ - RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext; - - // Do nothing if the driver is starting halt state. - // This might happen when timer already been fired before cancel timer with mlmehalt - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) - return; - - MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_ASSOC_TIMEOUT, 0, NULL); - RT28XX_MLME_HANDLER(pAd); -} - -/* - ========================================================================== - Description: - Reassociation timeout procedure. After reassociation timeout, this - function will be called and put a message into the MLME queue - Parameters: - Standard timer parameters - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID ReassocTimeout(IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3) -{ - RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext; - - // Do nothing if the driver is starting halt state. - // This might happen when timer already been fired before cancel timer with mlmehalt - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) - return; - - MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_REASSOC_TIMEOUT, 0, NULL); - RT28XX_MLME_HANDLER(pAd); -} - -/* - ========================================================================== - Description: - Disassociation timeout procedure. After disassociation timeout, this - function will be called and put a message into the MLME queue - Parameters: - Standard timer parameters - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID DisassocTimeout(IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3) -{ - RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext; - - // Do nothing if the driver is starting halt state. - // This might happen when timer already been fired before cancel timer with mlmehalt - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) - return; - - MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_DISASSOC_TIMEOUT, 0, NULL); - RT28XX_MLME_HANDLER(pAd); -} - -/* - ========================================================================== - Description: - mlme assoc req handling procedure - Parameters: - Adapter - Adapter pointer - Elem - MLME Queue Element - Pre: - the station has been authenticated and the following information is stored in the config - -# SSID - -# supported rates and their length - -# listen interval (Adapter->StaCfg.default_listen_count) - -# Transmit power (Adapter->StaCfg.tx_power) - Post : - -# An association request frame is generated and sent to the air - -# Association timer starts - -# Association state -> ASSOC_WAIT_RSP - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID MlmeAssocReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - UCHAR ApAddr[6]; - HEADER_802_11 AssocHdr; - UCHAR Ccx2Len = 5; - UCHAR WmeIe[9] = {IE_VENDOR_SPECIFIC, 0x07, 0x00, 0x50, 0xf2, 0x02, 0x00, 0x01, 0x00}; - USHORT ListenIntv; - ULONG Timeout; - USHORT CapabilityInfo; - BOOLEAN TimerCancelled; - PUCHAR pOutBuffer = NULL; - NDIS_STATUS NStatus; - ULONG FrameLen = 0; - ULONG tmp; - USHORT VarIesOffset; - UCHAR CkipFlag; - UCHAR CkipNegotiationBuffer[CKIP_NEGOTIATION_LENGTH]; - UCHAR AironetCkipIe = IE_AIRONET_CKIP; - UCHAR AironetCkipLen = CKIP_NEGOTIATION_LENGTH; - UCHAR AironetIPAddressIE = IE_AIRONET_IPADDRESS; - UCHAR AironetIPAddressLen = AIRONET_IPADDRESS_LENGTH; - UCHAR AironetIPAddressBuffer[AIRONET_IPADDRESS_LENGTH] = {0x00, 0x40, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00}; - USHORT Status; - - // Block all authentication request durning WPA block period - if (pAd->StaCfg.bBlockAssoc == TRUE) - { - DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - Block Assoc request durning WPA block period!\n")); - pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; - Status = MLME_STATE_MACHINE_REJECT; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_ASSOC_CONF, 2, &Status); - } - // check sanity first - else if (MlmeAssocReqSanity(pAd, Elem->Msg, Elem->MsgLen, ApAddr, &CapabilityInfo, &Timeout, &ListenIntv)) - { - RTMPCancelTimer(&pAd->MlmeAux.AssocTimer, &TimerCancelled); - COPY_MAC_ADDR(pAd->MlmeAux.Bssid, ApAddr); - - // Get an unused nonpaged memory - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); - if (NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_TRACE,("ASSOC - MlmeAssocReqAction() allocate memory failed \n")); - pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; - Status = MLME_FAIL_NO_RESOURCE; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_ASSOC_CONF, 2, &Status); - return; - } - - // Add by James 03/06/27 - pAd->StaCfg.AssocInfo.Length = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION); - // Association don't need to report MAC address - pAd->StaCfg.AssocInfo.AvailableRequestFixedIEs = - NDIS_802_11_AI_REQFI_CAPABILITIES | NDIS_802_11_AI_REQFI_LISTENINTERVAL; - pAd->StaCfg.AssocInfo.RequestFixedIEs.Capabilities = CapabilityInfo; - pAd->StaCfg.AssocInfo.RequestFixedIEs.ListenInterval = ListenIntv; - // Only reassociate need this - //COPY_MAC_ADDR(pAd->StaCfg.AssocInfo.RequestFixedIEs.CurrentAPAddress, ApAddr); - pAd->StaCfg.AssocInfo.OffsetRequestIEs = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION); - - NdisZeroMemory(pAd->StaCfg.ReqVarIEs, MAX_VIE_LEN); - // First add SSID - VarIesOffset = 0; - NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, &SsidIe, 1); - VarIesOffset += 1; - NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, &pAd->MlmeAux.SsidLen, 1); - VarIesOffset += 1; - NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen); - VarIesOffset += pAd->MlmeAux.SsidLen; - - // Second add Supported rates - NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, &SupRateIe, 1); - VarIesOffset += 1; - NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, &pAd->MlmeAux.SupRateLen, 1); - VarIesOffset += 1; - NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, pAd->MlmeAux.SupRate, pAd->MlmeAux.SupRateLen); - VarIesOffset += pAd->MlmeAux.SupRateLen; - // End Add by James - - if ((pAd->CommonCfg.Channel > 14) && - (pAd->CommonCfg.bIEEE80211H == TRUE)) - CapabilityInfo |= 0x0100; - - DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - Send ASSOC request...\n")); - MgtMacHeaderInit(pAd, &AssocHdr, SUBTYPE_ASSOC_REQ, 0, ApAddr, ApAddr); - - // Build basic frame first - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(HEADER_802_11), &AssocHdr, - 2, &CapabilityInfo, - 2, &ListenIntv, - 1, &SsidIe, - 1, &pAd->MlmeAux.SsidLen, - pAd->MlmeAux.SsidLen, pAd->MlmeAux.Ssid, - 1, &SupRateIe, - 1, &pAd->MlmeAux.SupRateLen, - pAd->MlmeAux.SupRateLen, pAd->MlmeAux.SupRate, - END_OF_ARGS); - - if (pAd->MlmeAux.ExtRateLen != 0) - { - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - 1, &ExtRateIe, - 1, &pAd->MlmeAux.ExtRateLen, - pAd->MlmeAux.ExtRateLen, pAd->MlmeAux.ExtRate, - END_OF_ARGS); - FrameLen += tmp; - } - -#ifdef DOT11_N_SUPPORT - // HT - if ((pAd->MlmeAux.HtCapabilityLen > 0) && (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) - { - ULONG TmpLen; - UCHAR HtLen; - UCHAR BROADCOM[4] = {0x0, 0x90, 0x4c, 0x33}; - if (pAd->StaActive.SupportedPhyInfo.bPreNHt == TRUE) - { - HtLen = SIZE_HT_CAP_IE + 4; - MakeOutgoingFrame(pOutBuffer + FrameLen, &TmpLen, - 1, &WpaIe, - 1, &HtLen, - 4, &BROADCOM[0], - pAd->MlmeAux.HtCapabilityLen, &pAd->MlmeAux.HtCapability, - END_OF_ARGS); - } - else - { -#ifdef RT_BIG_ENDIAN - HT_CAPABILITY_IE HtCapabilityTmp; -#endif - -#ifndef RT_BIG_ENDIAN - MakeOutgoingFrame(pOutBuffer + FrameLen, &TmpLen, - 1, &HtCapIe, - 1, &pAd->MlmeAux.HtCapabilityLen, - pAd->MlmeAux.HtCapabilityLen, &pAd->MlmeAux.HtCapability, - END_OF_ARGS); -#else - NdisZeroMemory(&HtCapabilityTmp, sizeof(HT_CAPABILITY_IE)); - NdisMoveMemory(&HtCapabilityTmp, &pAd->MlmeAux.HtCapability, pAd->MlmeAux.HtCapabilityLen); - *(USHORT *)(&HtCapabilityTmp.HtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.HtCapInfo)); - *(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo)); - - MakeOutgoingFrame(pOutBuffer + FrameLen, &TmpLen, - 1, &HtCapIe, - 1, &pAd->MlmeAux.HtCapabilityLen, - pAd->MlmeAux.HtCapabilityLen,&HtCapabilityTmp, - END_OF_ARGS); -#endif - } - FrameLen += TmpLen; - } -#endif // DOT11_N_SUPPORT // - - // add Ralink proprietary IE to inform AP this STA is going to use AGGREGATION or PIGGY-BACK+AGGREGATION - // Case I: (Aggregation + Piggy-Back) - // 1. user enable aggregation, AND - // 2. Mac support piggy-back - // 3. AP annouces it's PIGGY-BACK+AGGREGATION-capable in BEACON - // Case II: (Aggregation) - // 1. user enable aggregation, AND - // 2. AP annouces it's AGGREGATION-capable in BEACON - if (pAd->CommonCfg.bAggregationCapable) - { - if ((pAd->CommonCfg.bPiggyBackCapable) && ((pAd->MlmeAux.APRalinkIe & 0x00000003) == 3)) - { - ULONG TmpLen; - UCHAR RalinkIe[9] = {IE_VENDOR_SPECIFIC, 7, 0x00, 0x0c, 0x43, 0x03, 0x00, 0x00, 0x00}; - MakeOutgoingFrame(pOutBuffer+FrameLen, &TmpLen, - 9, RalinkIe, - END_OF_ARGS); - FrameLen += TmpLen; - } - else if (pAd->MlmeAux.APRalinkIe & 0x00000001) - { - ULONG TmpLen; - UCHAR RalinkIe[9] = {IE_VENDOR_SPECIFIC, 7, 0x00, 0x0c, 0x43, 0x01, 0x00, 0x00, 0x00}; - MakeOutgoingFrame(pOutBuffer+FrameLen, &TmpLen, - 9, RalinkIe, - END_OF_ARGS); - FrameLen += TmpLen; - } - } - else - { - ULONG TmpLen; - UCHAR RalinkIe[9] = {IE_VENDOR_SPECIFIC, 7, 0x00, 0x0c, 0x43, 0x06, 0x00, 0x00, 0x00}; - MakeOutgoingFrame(pOutBuffer+FrameLen, &TmpLen, - 9, RalinkIe, - END_OF_ARGS); - FrameLen += TmpLen; - } - - if (pAd->MlmeAux.APEdcaParm.bValid) - { - if (pAd->CommonCfg.bAPSDCapable && pAd->MlmeAux.APEdcaParm.bAPSDCapable) - { - QBSS_STA_INFO_PARM QosInfo; - - NdisZeroMemory(&QosInfo, sizeof(QBSS_STA_INFO_PARM)); - QosInfo.UAPSD_AC_BE = pAd->CommonCfg.bAPSDAC_BE; - QosInfo.UAPSD_AC_BK = pAd->CommonCfg.bAPSDAC_BK; - QosInfo.UAPSD_AC_VI = pAd->CommonCfg.bAPSDAC_VI; - QosInfo.UAPSD_AC_VO = pAd->CommonCfg.bAPSDAC_VO; - QosInfo.MaxSPLength = pAd->CommonCfg.MaxSPLength; - WmeIe[8] |= *(PUCHAR)&QosInfo; - } - else - { - // The Parameter Set Count is set to ¡§0¡¨ in the association request frames - // WmeIe[8] |= (pAd->MlmeAux.APEdcaParm.EdcaUpdateCount & 0x0f); - } - - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - 9, &WmeIe[0], - END_OF_ARGS); - FrameLen += tmp; - } - - // - // Let WPA(#221) Element ID on the end of this association frame. - // Otherwise some AP will fail on parsing Element ID and set status fail on Assoc Rsp. - // For example: Put Vendor Specific IE on the front of WPA IE. - // This happens on AP (Model No:Linksys WRK54G) - // - if (((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) || - (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) || - (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || - (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) - ) - ) - { - UCHAR RSNIe = IE_WPA; - - if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) || - (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2)) - { - RSNIe = IE_WPA2; - } - - RTMPMakeRSNIE(pAd, pAd->StaCfg.AuthMode, pAd->StaCfg.WepStatus, BSS0); - - // Check for WPA PMK cache list - if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) - { - INT idx; - BOOLEAN FoundPMK = FALSE; - // Search chched PMKID, append it if existed - for (idx = 0; idx < PMKID_NO; idx++) - { - if (NdisEqualMemory(ApAddr, &pAd->StaCfg.SavedPMK[idx].BSSID, 6)) - { - FoundPMK = TRUE; - break; - } - } - - if (FoundPMK) - { - // Set PMK number - *(PUSHORT) &pAd->StaCfg.RSN_IE[pAd->StaCfg.RSNIE_Len] = 1; - NdisMoveMemory(&pAd->StaCfg.RSN_IE[pAd->StaCfg.RSNIE_Len + 2], &pAd->StaCfg.SavedPMK[idx].PMKID, 16); - pAd->StaCfg.RSNIE_Len += 18; - } - } - - { - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - 1, &RSNIe, - 1, &pAd->StaCfg.RSNIE_Len, - pAd->StaCfg.RSNIE_Len, pAd->StaCfg.RSN_IE, - END_OF_ARGS); - } - - FrameLen += tmp; - - { - // Append Variable IE - NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, &RSNIe, 1); - VarIesOffset += 1; - NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, &pAd->StaCfg.RSNIE_Len, 1); - VarIesOffset += 1; - } - NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, pAd->StaCfg.RSN_IE, pAd->StaCfg.RSNIE_Len); - VarIesOffset += pAd->StaCfg.RSNIE_Len; - - // Set Variable IEs Length - pAd->StaCfg.ReqVarIELen = VarIesOffset; - } - - // We have update that at PeerBeaconAtJoinRequest() - CkipFlag = pAd->StaCfg.CkipFlag; - if (CkipFlag != 0) - { - NdisZeroMemory(CkipNegotiationBuffer, CKIP_NEGOTIATION_LENGTH); - CkipNegotiationBuffer[2] = 0x66; - // Make it try KP & MIC, since we have to follow the result from AssocRsp - CkipNegotiationBuffer[8] = 0x18; - CkipNegotiationBuffer[CKIP_NEGOTIATION_LENGTH - 1] = 0x22; - CkipFlag = 0x18; - - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - 1, &AironetCkipIe, - 1, &AironetCkipLen, - AironetCkipLen, CkipNegotiationBuffer, - END_OF_ARGS); - FrameLen += tmp; - } - - // Add CCX v2 request if CCX2 admin state is on - if (pAd->StaCfg.CCXControl.field.Enable == 1) - { - - // - // Add AironetIPAddressIE for Cisco CCX 2.X - // Add CCX Version - // - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - 1, &AironetIPAddressIE, - 1, &AironetIPAddressLen, - AironetIPAddressLen, AironetIPAddressBuffer, - 1, &Ccx2Ie, - 1, &Ccx2Len, - Ccx2Len, Ccx2IeInfo, - END_OF_ARGS); - FrameLen += tmp; - - // - // Add CipherSuite CCKM or LeapTkip if setting. - // -#ifdef LEAP_SUPPORT - if (LEAP_CCKM_ON(pAd)) - { - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - CipherSuiteCiscoCCKMLen, CipherSuiteCiscoCCKM, - END_OF_ARGS); - FrameLen += tmp; - - // Third add RSN - NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, CipherSuiteCiscoCCKM, CipherSuiteCiscoCCKMLen); //Save CipherSuite - VarIesOffset += CipherSuiteCiscoCCKMLen; - } - else if ((pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) && (pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled)) - { - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - CipherSuiteCCXTkipLen, CipherSuiteCCXTkip, - END_OF_ARGS); - FrameLen += tmp; - - // Third add RSN - NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, CipherSuiteCCXTkip, CipherSuiteCCXTkipLen); - VarIesOffset += CipherSuiteCCXTkipLen; - } -#endif // LEAP_SUPPORT // - - // Add by James 03/06/27 - // Set Variable IEs Length - pAd->StaCfg.ReqVarIELen = VarIesOffset; - pAd->StaCfg.AssocInfo.RequestIELength = VarIesOffset; - - // OffsetResponseIEs follow ReqVarIE - pAd->StaCfg.AssocInfo.OffsetResponseIEs = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION) + pAd->StaCfg.ReqVarIELen; - // End Add by James - } - - - MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); - - RTMPSetTimer(&pAd->MlmeAux.AssocTimer, Timeout); - pAd->Mlme.AssocMachine.CurrState = ASSOC_WAIT_RSP; - } - else - { - DBGPRINT(RT_DEBUG_TRACE,("ASSOC - MlmeAssocReqAction() sanity check failed. BUG!!!!!! \n")); - pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; - Status = MLME_INVALID_FORMAT; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_ASSOC_CONF, 2, &Status); - } - -} - -/* - ========================================================================== - Description: - mlme reassoc req handling procedure - Parameters: - Elem - - Pre: - -# SSID (Adapter->StaCfg.ssid[]) - -# BSSID (AP address, Adapter->StaCfg.bssid) - -# Supported rates (Adapter->StaCfg.supported_rates[]) - -# Supported rates length (Adapter->StaCfg.supported_rates_len) - -# Tx power (Adapter->StaCfg.tx_power) - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID MlmeReassocReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - UCHAR ApAddr[6]; - HEADER_802_11 ReassocHdr; - UCHAR Ccx2Len = 5; - UCHAR WmeIe[9] = {IE_VENDOR_SPECIFIC, 0x07, 0x00, 0x50, 0xf2, 0x02, 0x00, 0x01, 0x00}; - USHORT CapabilityInfo, ListenIntv; - ULONG Timeout; - ULONG FrameLen = 0; - BOOLEAN TimerCancelled; - NDIS_STATUS NStatus; - ULONG tmp; - PUCHAR pOutBuffer = NULL; -//CCX 2.X -#ifdef LEAP_SUPPORT - UCHAR CkipFlag; - UCHAR CkipNegotiationBuffer[CKIP_NEGOTIATION_LENGTH]; - UCHAR AironetCkipIe = IE_AIRONET_CKIP; - UCHAR AironetCkipLen = CKIP_NEGOTIATION_LENGTH; - UCHAR AironetIPAddressIE = IE_AIRONET_IPADDRESS; - UCHAR AironetIPAddressLen = AIRONET_IPADDRESS_LENGTH; - UCHAR AironetIPAddressBuffer[AIRONET_IPADDRESS_LENGTH] = {0x00, 0x40, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00}; - UCHAR AironetCCKMReassocIE = IE_AIRONET_CCKMREASSOC; - UCHAR AironetCCKMReassocLen = AIRONET_CCKMREASSOC_LENGTH; - UCHAR AironetCCKMReassocBuffer[AIRONET_CCKMREASSOC_LENGTH]; - UCHAR AironetOUI[] = {0x00, 0x40, 0x96, 0x00}; - UCHAR MICMN[16]; - UCHAR CalcMicBuffer[80]; - ULONG CalcMicBufferLen = 0; -#endif // LEAP_SUPPORT // - USHORT Status; - - // Block all authentication request durning WPA block period - if (pAd->StaCfg.bBlockAssoc == TRUE) - { - DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - Block ReAssoc request durning WPA block period!\n")); - pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; - Status = MLME_STATE_MACHINE_REJECT; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_REASSOC_CONF, 2, &Status); - } - // the parameters are the same as the association - else if(MlmeAssocReqSanity(pAd, Elem->Msg, Elem->MsgLen, ApAddr, &CapabilityInfo, &Timeout, &ListenIntv)) - { - RTMPCancelTimer(&pAd->MlmeAux.ReassocTimer, &TimerCancelled); - - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory - if(NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_TRACE,("ASSOC - MlmeReassocReqAction() allocate memory failed \n")); - pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; - Status = MLME_FAIL_NO_RESOURCE; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_REASSOC_CONF, 2, &Status); - return; - } - - COPY_MAC_ADDR(pAd->MlmeAux.Bssid, ApAddr); - - // make frame, use bssid as the AP address?? - DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - Send RE-ASSOC request...\n")); - MgtMacHeaderInit(pAd, &ReassocHdr, SUBTYPE_REASSOC_REQ, 0, ApAddr, ApAddr); - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(HEADER_802_11), &ReassocHdr, - 2, &CapabilityInfo, - 2, &ListenIntv, - MAC_ADDR_LEN, ApAddr, - 1, &SsidIe, - 1, &pAd->MlmeAux.SsidLen, - pAd->MlmeAux.SsidLen, pAd->MlmeAux.Ssid, - 1, &SupRateIe, - 1, &pAd->MlmeAux.SupRateLen, - pAd->MlmeAux.SupRateLen, pAd->MlmeAux.SupRate, - END_OF_ARGS); - - if (pAd->MlmeAux.ExtRateLen != 0) - { - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - 1, &ExtRateIe, - 1, &pAd->MlmeAux.ExtRateLen, - pAd->MlmeAux.ExtRateLen, pAd->MlmeAux.ExtRate, - END_OF_ARGS); - FrameLen += tmp; - } - - if (pAd->MlmeAux.APEdcaParm.bValid) - { - if (pAd->CommonCfg.bAPSDCapable && pAd->MlmeAux.APEdcaParm.bAPSDCapable) - { - QBSS_STA_INFO_PARM QosInfo; - - NdisZeroMemory(&QosInfo, sizeof(QBSS_STA_INFO_PARM)); - QosInfo.UAPSD_AC_BE = pAd->CommonCfg.bAPSDAC_BE; - QosInfo.UAPSD_AC_BK = pAd->CommonCfg.bAPSDAC_BK; - QosInfo.UAPSD_AC_VI = pAd->CommonCfg.bAPSDAC_VI; - QosInfo.UAPSD_AC_VO = pAd->CommonCfg.bAPSDAC_VO; - QosInfo.MaxSPLength = pAd->CommonCfg.MaxSPLength; - WmeIe[8] |= *(PUCHAR)&QosInfo; - } - - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - 9, &WmeIe[0], - END_OF_ARGS); - FrameLen += tmp; - } - -#ifdef DOT11_N_SUPPORT - // HT - if ((pAd->MlmeAux.HtCapabilityLen > 0) && (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) - { - ULONG TmpLen; - UCHAR HtLen; - UCHAR BROADCOM[4] = {0x0, 0x90, 0x4c, 0x33}; - if (pAd->StaActive.SupportedPhyInfo.bPreNHt == TRUE) - { - HtLen = SIZE_HT_CAP_IE + 4; - MakeOutgoingFrame(pOutBuffer + FrameLen, &TmpLen, - 1, &WpaIe, - 1, &HtLen, - 4, &BROADCOM[0], - pAd->MlmeAux.HtCapabilityLen, &pAd->MlmeAux.HtCapability, - END_OF_ARGS); - } - else - { - MakeOutgoingFrame(pOutBuffer + FrameLen, &TmpLen, - 1, &HtCapIe, - 1, &pAd->MlmeAux.HtCapabilityLen, - pAd->MlmeAux.HtCapabilityLen, &pAd->MlmeAux.HtCapability, - END_OF_ARGS); - } - FrameLen += TmpLen; - } -#endif // DOT11_N_SUPPORT // - - // add Ralink proprietary IE to inform AP this STA is going to use AGGREGATION or PIGGY-BACK+AGGREGATION - // Case I: (Aggregation + Piggy-Back) - // 1. user enable aggregation, AND - // 2. Mac support piggy-back - // 3. AP annouces it's PIGGY-BACK+AGGREGATION-capable in BEACON - // Case II: (Aggregation) - // 1. user enable aggregation, AND - // 2. AP annouces it's AGGREGATION-capable in BEACON - if (pAd->CommonCfg.bAggregationCapable) - { - if ((pAd->CommonCfg.bPiggyBackCapable) && ((pAd->MlmeAux.APRalinkIe & 0x00000003) == 3)) - { - ULONG TmpLen; - UCHAR RalinkIe[9] = {IE_VENDOR_SPECIFIC, 7, 0x00, 0x0c, 0x43, 0x03, 0x00, 0x00, 0x00}; - MakeOutgoingFrame(pOutBuffer+FrameLen, &TmpLen, - 9, RalinkIe, - END_OF_ARGS); - FrameLen += TmpLen; - } - else if (pAd->MlmeAux.APRalinkIe & 0x00000001) - { - ULONG TmpLen; - UCHAR RalinkIe[9] = {IE_VENDOR_SPECIFIC, 7, 0x00, 0x0c, 0x43, 0x01, 0x00, 0x00, 0x00}; - MakeOutgoingFrame(pOutBuffer+FrameLen, &TmpLen, - 9, RalinkIe, - END_OF_ARGS); - FrameLen += TmpLen; - } - } - else - { - ULONG TmpLen; - UCHAR RalinkIe[9] = {IE_VENDOR_SPECIFIC, 7, 0x00, 0x0c, 0x43, 0x04, 0x00, 0x00, 0x00}; - MakeOutgoingFrame(pOutBuffer+FrameLen, &TmpLen, - 9, RalinkIe, - END_OF_ARGS); - FrameLen += TmpLen; - } -#ifdef LEAP_SUPPORT - if (LEAP_CCKM_ON(pAd) && (pAd->StaCfg.CCKMLinkUpFlag == TRUE)) - { - CkipFlag = pAd->StaCfg.CkipFlag; // We have update that at PeerBeaconAtJoinRequest() - if (CkipFlag != 0) - { - NdisZeroMemory(CkipNegotiationBuffer, CKIP_NEGOTIATION_LENGTH); - CkipNegotiationBuffer[2] = 0x66; - // Make it try KP & MIC, since we have to follow the result from AssocRsp - CkipNegotiationBuffer[8] = 0x18; - CkipNegotiationBuffer[CKIP_NEGOTIATION_LENGTH - 1] = 0x22; - - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - 1, &AironetCkipIe, - 1, &AironetCkipLen, - AironetCkipLen, CkipNegotiationBuffer, - END_OF_ARGS); - FrameLen += tmp; - } - - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - 1, &AironetIPAddressIE, - 1, &AironetIPAddressLen, - AironetIPAddressLen, AironetIPAddressBuffer, - END_OF_ARGS); - FrameLen += tmp; - - // - // The RN is incremented before each reassociation request. - // - pAd->StaCfg.CCKMRN++; - // - // Calculate MIC = hmac-md5(krk, STA-ID|BSSID|RSNIE|TSF|RN); - // - COPY_MAC_ADDR(CalcMicBuffer, pAd->CurrentAddress); - CalcMicBufferLen = MAC_ADDR_LEN; - COPY_MAC_ADDR(CalcMicBuffer + CalcMicBufferLen, pAd->MlmeAux.Bssid); - CalcMicBufferLen += MAC_ADDR_LEN; - NdisMoveMemory(CalcMicBuffer + CalcMicBufferLen, CipherSuiteCiscoCCKM, CipherSuiteCiscoCCKMLen); - CalcMicBufferLen += CipherSuiteCiscoCCKMLen; - NdisMoveMemory(CalcMicBuffer + CalcMicBufferLen, (PUCHAR) &pAd->StaCfg.CCKMBeaconAtJoinTimeStamp, sizeof(pAd->StaCfg.CCKMBeaconAtJoinTimeStamp)); - CalcMicBufferLen += sizeof(pAd->StaCfg.CCKMBeaconAtJoinTimeStamp); - NdisMoveMemory(CalcMicBuffer + CalcMicBufferLen, (PUCHAR)&pAd->StaCfg.CCKMRN, sizeof(pAd->StaCfg.CCKMRN)); - CalcMicBufferLen += sizeof(pAd->StaCfg.CCKMRN); - hmac_md5(pAd->StaCfg.KRK, LEN_EAP_MICK, CalcMicBuffer, CalcMicBufferLen, MICMN); - - // - // fill up CCKM reassociation request element - // - NdisMoveMemory(AironetCCKMReassocBuffer, AironetOUI, 4); - NdisMoveMemory(AironetCCKMReassocBuffer + 4, (PUCHAR)&pAd->StaCfg.CCKMBeaconAtJoinTimeStamp, 8); - NdisMoveMemory(AironetCCKMReassocBuffer + 12, (PUCHAR) &pAd->StaCfg.CCKMRN, 4); - NdisMoveMemory(AironetCCKMReassocBuffer +16, MICMN, 8); - - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - 1, &AironetCCKMReassocIE, - 1, &AironetCCKMReassocLen, - AironetCCKMReassocLen, AironetCCKMReassocBuffer, - END_OF_ARGS); - FrameLen += tmp; - - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - CipherSuiteCiscoCCKMLen,CipherSuiteCiscoCCKM, - END_OF_ARGS); - FrameLen += tmp; - } -#endif // LEAP_SUPPORT // - - // Add CCX v2 request if CCX2 admin state is on - if (pAd->StaCfg.CCXControl.field.Enable == 1) - { - // - // Add CCX Version - // - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - 1, &Ccx2Ie, - 1, &Ccx2Len, - Ccx2Len, Ccx2IeInfo, - END_OF_ARGS); - FrameLen += tmp; - } - - MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); - - RTMPSetTimer(&pAd->MlmeAux.ReassocTimer, Timeout); /* in mSec */ - pAd->Mlme.AssocMachine.CurrState = REASSOC_WAIT_RSP; - } - else - { - DBGPRINT(RT_DEBUG_TRACE,("ASSOC - MlmeReassocReqAction() sanity check failed. BUG!!!! \n")); - pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; - Status = MLME_INVALID_FORMAT; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_REASSOC_CONF, 2, &Status); - } -} - -/* - ========================================================================== - Description: - Upper layer issues disassoc request - Parameters: - Elem - - - IRQL = PASSIVE_LEVEL - - ========================================================================== - */ -VOID MlmeDisassocReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - PMLME_DISASSOC_REQ_STRUCT pDisassocReq; - HEADER_802_11 DisassocHdr; - PHEADER_802_11 pDisassocHdr; - PUCHAR pOutBuffer = NULL; - ULONG FrameLen = 0; - NDIS_STATUS NStatus; - BOOLEAN TimerCancelled; - ULONG Timeout = 0; - USHORT Status; - -#ifdef QOS_DLS_SUPPORT - // send DLS-TEAR_DOWN message, - if (pAd->CommonCfg.bDLSCapable) - { - UCHAR i; - - // tear down local dls table entry - for (i=0; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH)) - { - RTMPSendDLSTearDownFrame(pAd, pAd->StaCfg.DLSEntry[i].MacAddr); - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - pAd->StaCfg.DLSEntry[i].Valid = FALSE; - } - } - - // tear down peer dls table entry - for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH)) - { - RTMPSendDLSTearDownFrame(pAd, pAd->StaCfg.DLSEntry[i].MacAddr); - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - pAd->StaCfg.DLSEntry[i].Valid = FALSE; - } - } - } -#endif // QOS_DLS_SUPPORT // - - // skip sanity check - pDisassocReq = (PMLME_DISASSOC_REQ_STRUCT)(Elem->Msg); - - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory - if (NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - MlmeDisassocReqAction() allocate memory failed\n")); - pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; - Status = MLME_FAIL_NO_RESOURCE; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_DISASSOC_CONF, 2, &Status); - return; - } - - - - RTMPCancelTimer(&pAd->MlmeAux.DisassocTimer, &TimerCancelled); - - DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - Send DISASSOC request[BSSID::%02x:%02x:%02x:%02x:%02x:%02x (Reason=%d)\n", - pDisassocReq->Addr[0], pDisassocReq->Addr[1], pDisassocReq->Addr[2], - pDisassocReq->Addr[3], pDisassocReq->Addr[4], pDisassocReq->Addr[5], pDisassocReq->Reason)); - MgtMacHeaderInit(pAd, &DisassocHdr, SUBTYPE_DISASSOC, 0, pDisassocReq->Addr, pDisassocReq->Addr); // patch peap ttls switching issue - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(HEADER_802_11),&DisassocHdr, - 2, &pDisassocReq->Reason, - END_OF_ARGS); - MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); - - // To patch Instance and Buffalo(N) AP - // Driver has to send deauth to Instance AP, but Buffalo(N) needs to send disassoc to reset Authenticator's state machine - // Therefore, we send both of them. - pDisassocHdr = (PHEADER_802_11)pOutBuffer; - pDisassocHdr->FC.SubType = SUBTYPE_DEAUTH; - MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); - - MlmeFreeMemory(pAd, pOutBuffer); - - pAd->StaCfg.DisassocReason = REASON_DISASSOC_STA_LEAVING; - COPY_MAC_ADDR(pAd->StaCfg.DisassocSta, pDisassocReq->Addr); - - RTMPSetTimer(&pAd->MlmeAux.DisassocTimer, Timeout); /* in mSec */ - pAd->Mlme.AssocMachine.CurrState = DISASSOC_WAIT_RSP; - -#ifdef WPA_SUPPLICANT_SUPPORT -#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT - if (pAd->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_DISABLE) - { - union iwreq_data wrqu; - //send disassociate event to wpa_supplicant - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.flags = RT_DISASSOC_EVENT_FLAG; - wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); - } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // -#endif // WPA_SUPPLICANT_SUPPORT // - -#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT - { - union iwreq_data wrqu; - memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN); - wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); - } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // - -} - -/* - ========================================================================== - Description: - peer sends assoc rsp back - Parameters: - Elme - MLME message containing the received frame - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID PeerAssocRspAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - USHORT CapabilityInfo, Status, Aid; - UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES], SupRateLen; - UCHAR ExtRate[MAX_LEN_OF_SUPPORTED_RATES], ExtRateLen; - UCHAR Addr2[MAC_ADDR_LEN]; - BOOLEAN TimerCancelled; - UCHAR CkipFlag; - EDCA_PARM EdcaParm; - HT_CAPABILITY_IE HtCapability; - ADD_HT_INFO_IE AddHtInfo; // AP might use this additional ht info IE - UCHAR HtCapabilityLen; - UCHAR AddHtInfoLen; - UCHAR NewExtChannelOffset = 0xff; - - if (PeerAssocRspSanity(pAd, Elem->Msg, Elem->MsgLen, Addr2, &CapabilityInfo, &Status, &Aid, SupRate, &SupRateLen, ExtRate, &ExtRateLen, - &HtCapability,&AddHtInfo, &HtCapabilityLen,&AddHtInfoLen,&NewExtChannelOffset, &EdcaParm, &CkipFlag)) - { - // The frame is for me ? - if(MAC_ADDR_EQUAL(Addr2, pAd->MlmeAux.Bssid)) - { - DBGPRINT(RT_DEBUG_TRACE, ("PeerAssocRspAction():ASSOC - receive ASSOC_RSP to me (status=%d)\n", Status)); -#ifdef DOT11_N_SUPPORT - DBGPRINT(RT_DEBUG_TRACE, ("PeerAssocRspAction():MacTable [%d].AMsduSize = %d. ClientStatusFlags = 0x%lx \n",Elem->Wcid, pAd->MacTab.Content[BSSID_WCID].AMsduSize, pAd->MacTab.Content[BSSID_WCID].ClientStatusFlags)); -#endif // DOT11_N_SUPPORT // - RTMPCancelTimer(&pAd->MlmeAux.AssocTimer, &TimerCancelled); - if(Status == MLME_SUCCESS) - { - UCHAR MaxSupportedRateIn500Kbps = 0; - UCHAR idx; - - // supported rates array may not be sorted. sort it and find the maximum rate - for (idx=0; idxMacTab.Content[BSSID_WCID], MaxSupportedRateIn500Kbps, &HtCapability, HtCapabilityLen, CapabilityInfo); - - pAd->StaCfg.CkipFlag = CkipFlag; - if (CkipFlag & 0x18) - { - NdisZeroMemory(pAd->StaCfg.TxSEQ, 4); - NdisZeroMemory(pAd->StaCfg.RxSEQ, 4); - NdisZeroMemory(pAd->StaCfg.CKIPMIC, 4); - pAd->StaCfg.GIV[0] = RandomByte(pAd); - pAd->StaCfg.GIV[1] = RandomByte(pAd); - pAd->StaCfg.GIV[2] = RandomByte(pAd); - pAd->StaCfg.bCkipOn = TRUE; - DBGPRINT(RT_DEBUG_TRACE, (" pAd->StaCfg.CkipFlag = 0x%02x\n", pAd->StaCfg.CkipFlag)); - } - } - else - { - // Faile on Association, we need to check the status code - // Is that a Rogue AP? -#ifdef LEAP_SUPPORT - if ((pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) && (Status == MLME_ALG_NOT_SUPPORT)) - { //Possibly Rogue AP - RogueApTableSetEntry(pAd, &pAd->StaCfg.RogueApTab, pAd->MlmeAux.Bssid, LEAP_REASON_INVALID_AUTH); - } -#endif // LEAP_SUPPORT // - } - pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_ASSOC_CONF, 2, &Status); - } - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - PeerAssocRspAction() sanity check fail\n")); - } -} - -/* - ========================================================================== - Description: - peer sends reassoc rsp - Parametrs: - Elem - MLME message cntaining the received frame - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID PeerReassocRspAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - USHORT CapabilityInfo; - USHORT Status; - USHORT Aid; - UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES], SupRateLen; - UCHAR ExtRate[MAX_LEN_OF_SUPPORTED_RATES], ExtRateLen; - UCHAR Addr2[MAC_ADDR_LEN]; - UCHAR CkipFlag; - BOOLEAN TimerCancelled; - EDCA_PARM EdcaParm; - HT_CAPABILITY_IE HtCapability; - ADD_HT_INFO_IE AddHtInfo; // AP might use this additional ht info IE - UCHAR HtCapabilityLen; - UCHAR AddHtInfoLen; - UCHAR NewExtChannelOffset = 0xff; - - if(PeerAssocRspSanity(pAd, Elem->Msg, Elem->MsgLen, Addr2, &CapabilityInfo, &Status, &Aid, SupRate, &SupRateLen, ExtRate, &ExtRateLen, - &HtCapability, &AddHtInfo, &HtCapabilityLen, &AddHtInfoLen,&NewExtChannelOffset, &EdcaParm, &CkipFlag)) - { - if(MAC_ADDR_EQUAL(Addr2, pAd->MlmeAux.Bssid)) // The frame is for me ? - { - DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - receive REASSOC_RSP to me (status=%d)\n", Status)); - RTMPCancelTimer(&pAd->MlmeAux.ReassocTimer, &TimerCancelled); - - if(Status == MLME_SUCCESS) - { - // go to procedure listed on page 376 - AssocPostProc(pAd, Addr2, CapabilityInfo, Aid, SupRate, SupRateLen, ExtRate, ExtRateLen, - &EdcaParm, &HtCapability, HtCapabilityLen, &AddHtInfo); - -#ifdef WPA_SUPPLICANT_SUPPORT -#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT - if (pAd->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_DISABLE) - { - union iwreq_data wrqu; - - SendAssocIEsToWpaSupplicant(pAd); - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.flags = RT_ASSOC_EVENT_FLAG; - wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); - } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // -#endif // WPA_SUPPLICANT_SUPPORT // - -#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT - { - union iwreq_data wrqu; - wext_notify_event_assoc(pAd); - - memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN); - memcpy(wrqu.ap_addr.sa_data, pAd->MlmeAux.Bssid, MAC_ADDR_LEN); - wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); - - } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // - - } - - // - // Cisco Leap CCKM supported Re-association. - // -#ifdef LEAP_SUPPORT - if (LEAP_CCKM_ON(pAd) && (pAd->StaCfg.CCKMLinkUpFlag == TRUE)) - { - if (CCKMAssocRspSanity(pAd, Elem->Msg, Elem->MsgLen) == TRUE) - { - pAd->StaCfg.CkipFlag = CkipFlag; - if (CkipFlag & 0x18) - { - NdisZeroMemory(pAd->StaCfg.TxSEQ, 4); - NdisZeroMemory(pAd->StaCfg.RxSEQ, 4); - NdisZeroMemory(pAd->StaCfg.CKIPMIC, 4); - pAd->StaCfg.GIV[0] = RandomByte(pAd); - pAd->StaCfg.GIV[1] = RandomByte(pAd); - pAd->StaCfg.GIV[2] = RandomByte(pAd); - pAd->StaCfg.bCkipOn = TRUE; - DBGPRINT(RT_DEBUG_TRACE, (" pAd->StaCfg.CkipFlag = 0x%02x\n", pAd->StaCfg.CkipFlag)); - } - - pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_REASSOC_CONF, 2, &Status); - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - CCKMAssocRspSanity() sanity check fail\n")); - } - } - else -#endif // LEAP_SUPPORT // - { - // CkipFlag is no use for reassociate - pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_REASSOC_CONF, 2, &Status); - } - } - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - PeerReassocRspAction() sanity check fail\n")); - } - -} - -/* - ========================================================================== - Description: - procedures on IEEE 802.11/1999 p.376 - Parametrs: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID AssocPostProc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pAddr2, - IN USHORT CapabilityInfo, - IN USHORT Aid, - IN UCHAR SupRate[], - IN UCHAR SupRateLen, - IN UCHAR ExtRate[], - IN UCHAR ExtRateLen, - IN PEDCA_PARM pEdcaParm, - IN HT_CAPABILITY_IE *pHtCapability, - IN UCHAR HtCapabilityLen, - IN ADD_HT_INFO_IE *pAddHtInfo) // AP might use this additional ht info IE -{ - ULONG Idx; - - pAd->MlmeAux.BssType = BSS_INFRA; - COPY_MAC_ADDR(pAd->MlmeAux.Bssid, pAddr2); - pAd->MlmeAux.Aid = Aid; - pAd->MlmeAux.CapabilityInfo = CapabilityInfo & SUPPORTED_CAPABILITY_INFO; -#ifdef DOT11_N_SUPPORT - // Some HT AP might lost WMM IE. We add WMM ourselves. beacuase HT requires QoS on. - if ((HtCapabilityLen > 0) && (pEdcaParm->bValid == FALSE)) - { - pEdcaParm->bValid = TRUE; - pEdcaParm->Aifsn[0] = 3; - pEdcaParm->Aifsn[1] = 7; - pEdcaParm->Aifsn[2] = 2; - pEdcaParm->Aifsn[3] = 2; - - pEdcaParm->Cwmin[0] = 4; - pEdcaParm->Cwmin[1] = 4; - pEdcaParm->Cwmin[2] = 3; - pEdcaParm->Cwmin[3] = 2; - - pEdcaParm->Cwmax[0] = 10; - pEdcaParm->Cwmax[1] = 10; - pEdcaParm->Cwmax[2] = 4; - pEdcaParm->Cwmax[3] = 3; - - pEdcaParm->Txop[0] = 0; - pEdcaParm->Txop[1] = 0; - pEdcaParm->Txop[2] = 96; - pEdcaParm->Txop[3] = 48; - - } -#endif // DOT11_N_SUPPORT // - - NdisMoveMemory(&pAd->MlmeAux.APEdcaParm, pEdcaParm, sizeof(EDCA_PARM)); - - // filter out un-supported rates - pAd->MlmeAux.SupRateLen = SupRateLen; - NdisMoveMemory(pAd->MlmeAux.SupRate, SupRate, SupRateLen); - RTMPCheckRates(pAd, pAd->MlmeAux.SupRate, &pAd->MlmeAux.SupRateLen); - - // filter out un-supported rates - pAd->MlmeAux.ExtRateLen = ExtRateLen; - NdisMoveMemory(pAd->MlmeAux.ExtRate, ExtRate, ExtRateLen); - RTMPCheckRates(pAd, pAd->MlmeAux.ExtRate, &pAd->MlmeAux.ExtRateLen); - -#ifdef DOT11_N_SUPPORT - if (HtCapabilityLen > 0) - { - RTMPCheckHt(pAd, BSSID_WCID, pHtCapability, pAddHtInfo); - } - DBGPRINT(RT_DEBUG_TRACE, ("AssocPostProc===> AP.AMsduSize = %d. ClientStatusFlags = 0x%lx \n", pAd->MacTab.Content[BSSID_WCID].AMsduSize, pAd->MacTab.Content[BSSID_WCID].ClientStatusFlags)); - - DBGPRINT(RT_DEBUG_TRACE, ("AssocPostProc===> (Mmps=%d, AmsduSize=%d, )\n", - pAd->MacTab.Content[BSSID_WCID].MmpsMode, pAd->MacTab.Content[BSSID_WCID].AMsduSize)); -#endif // DOT11_N_SUPPORT // - - // Set New WPA information - Idx = BssTableSearch(&pAd->ScanTab, pAddr2, pAd->MlmeAux.Channel); - if (Idx == BSS_NOT_FOUND) - { - DBGPRINT_ERR(("ASSOC - Can't find BSS after receiving Assoc response\n")); - } - else - { - // Init variable - pAd->MacTab.Content[BSSID_WCID].RSNIE_Len = 0; - NdisZeroMemory(pAd->MacTab.Content[BSSID_WCID].RSN_IE, MAX_LEN_OF_RSNIE); - - // Store appropriate RSN_IE for WPA SM negotiation later - if ((pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) && (pAd->ScanTab.BssEntry[Idx].VarIELen != 0)) - { - PUCHAR pVIE; - USHORT len; - PEID_STRUCT pEid; - - pVIE = pAd->ScanTab.BssEntry[Idx].VarIEs; - len = pAd->ScanTab.BssEntry[Idx].VarIELen; - - while (len > 0) - { - pEid = (PEID_STRUCT) pVIE; - // For WPA/WPAPSK - if ((pEid->Eid == IE_WPA) && (NdisEqualMemory(pEid->Octet, WPA_OUI, 4)) - && (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA || pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) - { - NdisMoveMemory(pAd->MacTab.Content[BSSID_WCID].RSN_IE, pVIE, (pEid->Len + 2)); - pAd->MacTab.Content[BSSID_WCID].RSNIE_Len = (pEid->Len + 2); - DBGPRINT(RT_DEBUG_TRACE, ("AssocPostProc===> Store RSN_IE for WPA SM negotiation \n")); - } - // For WPA2/WPA2PSK - else if ((pEid->Eid == IE_RSN) && (NdisEqualMemory(pEid->Octet + 2, RSN_OUI, 3)) - && (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2 || pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)) - { - NdisMoveMemory(pAd->MacTab.Content[BSSID_WCID].RSN_IE, pVIE, (pEid->Len + 2)); - pAd->MacTab.Content[BSSID_WCID].RSNIE_Len = (pEid->Len + 2); - DBGPRINT(RT_DEBUG_TRACE, ("AssocPostProc===> Store RSN_IE for WPA2 SM negotiation \n")); - } - - pVIE += (pEid->Len + 2); - len -= (pEid->Len + 2); - } - } - - if (pAd->MacTab.Content[BSSID_WCID].RSNIE_Len == 0) - { - DBGPRINT(RT_DEBUG_TRACE, ("AssocPostProc===> no RSN_IE \n")); - } - else - { - hex_dump("RSN_IE", pAd->MacTab.Content[BSSID_WCID].RSN_IE, pAd->MacTab.Content[BSSID_WCID].RSNIE_Len); - } - } -} - -/* - ========================================================================== - Description: - left part of IEEE 802.11/1999 p.374 - Parameters: - Elem - MLME message containing the received frame - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID PeerDisassocAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - UCHAR Addr2[MAC_ADDR_LEN]; - USHORT Reason; - - DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - PeerDisassocAction()\n")); - if(PeerDisassocSanity(pAd, Elem->Msg, Elem->MsgLen, Addr2, &Reason)) - { - DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - PeerDisassocAction() Reason = %d\n", Reason)); - if (INFRA_ON(pAd) && MAC_ADDR_EQUAL(pAd->CommonCfg.Bssid, Addr2)) - { - - if (pAd->CommonCfg.bWirelessEvent) - { - RTMPSendWirelessEvent(pAd, IW_DISASSOC_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); - } - - -#ifdef LEAP_SUPPORT - if (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) - { - // Cisco_LEAP has start a timer - // We should cancel it if using LEAP - RTMPCancelTimer(&pAd->StaCfg.LeapAuthTimer, &TimerCancelled); - //Check is it mach the LEAP Authentication failed as possible a Rogue AP - //on it's PortSecured not equal to WPA_802_1X_PORT_SECURED while process the Association. - if ((pAd->Mlme.LeapMachine.CurrState != LEAP_IDLE) && (pAd->StaCfg.PortSecured != WPA_802_1X_PORT_SECURED)) - { - RogueApTableSetEntry(pAd, &pAd->StaCfg.RogueApTab, Addr2, LEAP_REASON_AUTH_TIMEOUT); - } - } -#endif // LEAP_SUPPORT // - // - // Get Current System time and Turn on AdjacentAPReport - // - NdisGetSystemUpTime(&pAd->StaCfg.CCXAdjacentAPLinkDownTime); - pAd->StaCfg.CCXAdjacentAPReportFlag = TRUE; - LinkDown(pAd, TRUE); - pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; - -#ifdef WPA_SUPPLICANT_SUPPORT -#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT - if (pAd->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_DISABLE) - { - union iwreq_data wrqu; - //send disassociate event to wpa_supplicant - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.flags = RT_DISASSOC_EVENT_FLAG; - wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); - } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // -#endif // WPA_SUPPLICANT_SUPPORT // - -#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT - { - union iwreq_data wrqu; - memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN); - wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); - } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // - } - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - PeerDisassocAction() sanity check fail\n")); - } - -} - -/* - ========================================================================== - Description: - what the state machine will do after assoc timeout - Parameters: - Elme - - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID AssocTimeoutAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - USHORT Status; - DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - AssocTimeoutAction\n")); - pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; - Status = MLME_REJ_TIMEOUT; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_ASSOC_CONF, 2, &Status); -} - -/* - ========================================================================== - Description: - what the state machine will do after reassoc timeout - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID ReassocTimeoutAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - USHORT Status; - DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - ReassocTimeoutAction\n")); - pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; - Status = MLME_REJ_TIMEOUT; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_REASSOC_CONF, 2, &Status); -} - -/* - ========================================================================== - Description: - what the state machine will do after disassoc timeout - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID DisassocTimeoutAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - USHORT Status; - DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - DisassocTimeoutAction\n")); - pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; - Status = MLME_SUCCESS; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_DISASSOC_CONF, 2, &Status); -} - -VOID InvalidStateWhenAssoc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - USHORT Status; - DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - InvalidStateWhenAssoc(state=%ld), reset ASSOC state machine\n", - pAd->Mlme.AssocMachine.CurrState)); - pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; - Status = MLME_STATE_MACHINE_REJECT; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_ASSOC_CONF, 2, &Status); -} - -VOID InvalidStateWhenReassoc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - USHORT Status; - DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - InvalidStateWhenReassoc(state=%ld), reset ASSOC state machine\n", - pAd->Mlme.AssocMachine.CurrState)); - pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; - Status = MLME_STATE_MACHINE_REJECT; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_REASSOC_CONF, 2, &Status); -} - -VOID InvalidStateWhenDisassociate( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - USHORT Status; - DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - InvalidStateWhenDisassoc(state=%ld), reset ASSOC state machine\n", - pAd->Mlme.AssocMachine.CurrState)); - pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; - Status = MLME_STATE_MACHINE_REJECT; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_DISASSOC_CONF, 2, &Status); -} - -/* - ========================================================================== - Description: - right part of IEEE 802.11/1999 page 374 - Note: - This event should never cause ASSOC state machine perform state - transition, and has no relationship with CNTL machine. So we separate - this routine as a service outside of ASSOC state transition table. - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID Cls3errAction( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pAddr) -{ - HEADER_802_11 DisassocHdr; - PHEADER_802_11 pDisassocHdr; - PUCHAR pOutBuffer = NULL; - ULONG FrameLen = 0; - NDIS_STATUS NStatus; - USHORT Reason = REASON_CLS3ERR; - - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory - if (NStatus != NDIS_STATUS_SUCCESS) - return; - - DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - Class 3 Error, Send DISASSOC frame\n")); - MgtMacHeaderInit(pAd, &DisassocHdr, SUBTYPE_DISASSOC, 0, pAddr, pAd->CommonCfg.Bssid); // patch peap ttls switching issue - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(HEADER_802_11),&DisassocHdr, - 2, &Reason, - END_OF_ARGS); - MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); - - // To patch Instance and Buffalo(N) AP - // Driver has to send deauth to Instance AP, but Buffalo(N) needs to send disassoc to reset Authenticator's state machine - // Therefore, we send both of them. - pDisassocHdr = (PHEADER_802_11)pOutBuffer; - pDisassocHdr->FC.SubType = SUBTYPE_DEAUTH; - MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); - - MlmeFreeMemory(pAd, pOutBuffer); - - pAd->StaCfg.DisassocReason = REASON_CLS3ERR; - COPY_MAC_ADDR(pAd->StaCfg.DisassocSta, pAddr); -} - - /* - ========================================================================== - Description: - Switch between WEP and CKIP upon new association up. - Parameters: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID SwitchBetweenWepAndCkip( - IN PRTMP_ADAPTER pAd) -{ - int i; - SHAREDKEY_MODE_STRUC csr1; - - // if KP is required. change the CipherAlg in hardware shard key table from WEP - // to CKIP. else remain as WEP - if (pAd->StaCfg.bCkipOn && (pAd->StaCfg.CkipFlag & 0x10)) - { - // modify hardware key table so that MAC use correct algorithm to decrypt RX - RTMP_IO_READ32(pAd, SHARED_KEY_MODE_BASE, &csr1.word); - if (csr1.field.Bss0Key0CipherAlg == CIPHER_WEP64) - csr1.field.Bss0Key0CipherAlg = CIPHER_CKIP64; - else if (csr1.field.Bss0Key0CipherAlg == CIPHER_WEP128) - csr1.field.Bss0Key0CipherAlg = CIPHER_CKIP128; - - if (csr1.field.Bss0Key1CipherAlg == CIPHER_WEP64) - csr1.field.Bss0Key1CipherAlg = CIPHER_CKIP64; - else if (csr1.field.Bss0Key1CipherAlg == CIPHER_WEP128) - csr1.field.Bss0Key1CipherAlg = CIPHER_CKIP128; - - if (csr1.field.Bss0Key2CipherAlg == CIPHER_WEP64) - csr1.field.Bss0Key2CipherAlg = CIPHER_CKIP64; - else if (csr1.field.Bss0Key2CipherAlg == CIPHER_WEP128) - csr1.field.Bss0Key2CipherAlg = CIPHER_CKIP128; - - if (csr1.field.Bss0Key3CipherAlg == CIPHER_WEP64) - csr1.field.Bss0Key3CipherAlg = CIPHER_CKIP64; - else if (csr1.field.Bss0Key3CipherAlg == CIPHER_WEP128) - csr1.field.Bss0Key3CipherAlg = CIPHER_CKIP128; - RTMP_IO_WRITE32(pAd, SHARED_KEY_MODE_BASE, csr1.word); - DBGPRINT(RT_DEBUG_TRACE, ("SwitchBetweenWepAndCkip: modify BSS0 cipher to %s\n", CipherName[csr1.field.Bss0Key0CipherAlg])); - - // modify software key table so that driver can specify correct algorithm in TXD upon TX - for (i=0; iSharedKey[BSS0][i].CipherAlg == CIPHER_WEP64) - pAd->SharedKey[BSS0][i].CipherAlg = CIPHER_CKIP64; - else if (pAd->SharedKey[BSS0][i].CipherAlg == CIPHER_WEP128) - pAd->SharedKey[BSS0][i].CipherAlg = CIPHER_CKIP128; - } - } - - // else if KP NOT inused. change the CipherAlg in hardware shard key table from CKIP - // to WEP. - else - { - // modify hardware key table so that MAC use correct algorithm to decrypt RX - RTMP_IO_READ32(pAd, SHARED_KEY_MODE_BASE, &csr1.word); - if (csr1.field.Bss0Key0CipherAlg == CIPHER_CKIP64) - csr1.field.Bss0Key0CipherAlg = CIPHER_WEP64; - else if (csr1.field.Bss0Key0CipherAlg == CIPHER_CKIP128) - csr1.field.Bss0Key0CipherAlg = CIPHER_WEP128; - - if (csr1.field.Bss0Key1CipherAlg == CIPHER_CKIP64) - csr1.field.Bss0Key1CipherAlg = CIPHER_WEP64; - else if (csr1.field.Bss0Key1CipherAlg == CIPHER_CKIP128) - csr1.field.Bss0Key1CipherAlg = CIPHER_WEP128; - - if (csr1.field.Bss0Key2CipherAlg == CIPHER_CKIP64) - csr1.field.Bss0Key2CipherAlg = CIPHER_WEP64; - else if (csr1.field.Bss0Key2CipherAlg == CIPHER_CKIP128) - csr1.field.Bss0Key2CipherAlg = CIPHER_WEP128; - - if (csr1.field.Bss0Key3CipherAlg == CIPHER_CKIP64) - csr1.field.Bss0Key3CipherAlg = CIPHER_WEP64; - else if (csr1.field.Bss0Key3CipherAlg == CIPHER_CKIP128) - csr1.field.Bss0Key3CipherAlg = CIPHER_WEP128; - - // modify software key table so that driver can specify correct algorithm in TXD upon TX - for (i=0; iSharedKey[BSS0][i].CipherAlg == CIPHER_CKIP64) - pAd->SharedKey[BSS0][i].CipherAlg = CIPHER_WEP64; - else if (pAd->SharedKey[BSS0][i].CipherAlg == CIPHER_CKIP128) - pAd->SharedKey[BSS0][i].CipherAlg = CIPHER_WEP128; - } - - // - // On WPA-NONE, must update CipherAlg. - // Because the OID_802_11_WEP_STATUS was been set after OID_802_11_ADD_KEY - // and CipherAlg will be CIPHER_NONE by Windows ZeroConfig. - // So we need to update CipherAlg after connect. - // - if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) - { - for (i = 0; i < SHARE_KEY_NUM; i++) - { - if (pAd->SharedKey[BSS0][i].KeyLen != 0) - { - if (pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) - { - pAd->SharedKey[BSS0][i].CipherAlg = CIPHER_TKIP; - } - else if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) - { - pAd->SharedKey[BSS0][i].CipherAlg = CIPHER_AES; - } - } - else - { - pAd->SharedKey[BSS0][i].CipherAlg = CIPHER_NONE; - } - } - - csr1.field.Bss0Key0CipherAlg = pAd->SharedKey[BSS0][0].CipherAlg; - csr1.field.Bss0Key1CipherAlg = pAd->SharedKey[BSS0][1].CipherAlg; - csr1.field.Bss0Key2CipherAlg = pAd->SharedKey[BSS0][2].CipherAlg; - csr1.field.Bss0Key3CipherAlg = pAd->SharedKey[BSS0][3].CipherAlg; - } - RTMP_IO_WRITE32(pAd, SHARED_KEY_MODE_BASE, csr1.word); - DBGPRINT(RT_DEBUG_TRACE, ("SwitchBetweenWepAndCkip: modify BSS0 cipher to %s\n", CipherName[csr1.field.Bss0Key0CipherAlg])); - } -} - -#ifdef WPA_SUPPLICANT_SUPPORT -#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT -VOID SendAssocIEsToWpaSupplicant( - IN PRTMP_ADAPTER pAd) -{ - union iwreq_data wrqu; - unsigned char custom[IW_CUSTOM_MAX] = {0}; - - if ((pAd->StaCfg.ReqVarIELen + 17) <= IW_CUSTOM_MAX) - { - sprintf(custom, "ASSOCINFO_ReqIEs="); - NdisMoveMemory(custom+17, pAd->StaCfg.ReqVarIEs, pAd->StaCfg.ReqVarIELen); - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.length = pAd->StaCfg.ReqVarIELen + 17; - wrqu.data.flags = RT_REQIE_EVENT_FLAG; - wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, custom); - - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.flags = RT_ASSOCINFO_EVENT_FLAG; - wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); - } - else - DBGPRINT(RT_DEBUG_TRACE, ("pAd->StaCfg.ReqVarIELen + 17 > MAX_CUSTOM_LEN\n")); - - return; -} -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // -#endif // WPA_SUPPLICANT_SUPPORT // - -#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT -int wext_notify_event_assoc( - IN RTMP_ADAPTER *pAd) -{ - union iwreq_data wrqu; - char custom[IW_CUSTOM_MAX] = {0}; - -#if WIRELESS_EXT > 17 - if (pAd->StaCfg.ReqVarIELen <= IW_CUSTOM_MAX) - { - wrqu.data.length = pAd->StaCfg.ReqVarIELen; - memcpy(custom, pAd->StaCfg.ReqVarIEs, pAd->StaCfg.ReqVarIELen); - wireless_send_event(pAd->net_dev, IWEVASSOCREQIE, &wrqu, custom); - } - else - DBGPRINT(RT_DEBUG_TRACE, ("pAd->StaCfg.ReqVarIELen > MAX_CUSTOM_LEN\n")); -#else - if (((pAd->StaCfg.ReqVarIELen*2) + 17) <= IW_CUSTOM_MAX) - { - UCHAR idx; - wrqu.data.length = (pAd->StaCfg.ReqVarIELen*2) + 17; - sprintf(custom, "ASSOCINFO(ReqIEs="); - for (idx=0; idxStaCfg.ReqVarIELen; idx++) - sprintf(custom, "%s%02x", custom, pAd->StaCfg.ReqVarIEs[idx]); - wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, custom); - } - else - DBGPRINT(RT_DEBUG_TRACE, ("(pAd->StaCfg.ReqVarIELen*2) + 17 > MAX_CUSTOM_LEN\n")); -#endif - - return 0; - -} -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // - - -BOOLEAN StaAddMacTableEntry( - IN PRTMP_ADAPTER pAd, - IN PMAC_TABLE_ENTRY pEntry, - IN UCHAR MaxSupportedRateIn500Kbps, - IN HT_CAPABILITY_IE *pHtCapability, - IN UCHAR HtCapabilityLen, - IN USHORT CapabilityInfo) -{ - UCHAR MaxSupportedRate = RATE_11; - - if (ADHOC_ON(pAd)) - CLIENT_STATUS_CLEAR_FLAG(pEntry, fCLIENT_STATUS_WMM_CAPABLE); - - switch (MaxSupportedRateIn500Kbps) - { - case 108: MaxSupportedRate = RATE_54; break; - case 96: MaxSupportedRate = RATE_48; break; - case 72: MaxSupportedRate = RATE_36; break; - case 48: MaxSupportedRate = RATE_24; break; - case 36: MaxSupportedRate = RATE_18; break; - case 24: MaxSupportedRate = RATE_12; break; - case 18: MaxSupportedRate = RATE_9; break; - case 12: MaxSupportedRate = RATE_6; break; - case 22: MaxSupportedRate = RATE_11; break; - case 11: MaxSupportedRate = RATE_5_5; break; - case 4: MaxSupportedRate = RATE_2; break; - case 2: MaxSupportedRate = RATE_1; break; - default: MaxSupportedRate = RATE_11; break; - } - - if ((pAd->CommonCfg.PhyMode == PHY_11G) && (MaxSupportedRate < RATE_FIRST_OFDM_RATE)) - return FALSE; - -#ifdef DOT11_N_SUPPORT - // 11n only - if (((pAd->CommonCfg.PhyMode == PHY_11N_2_4G) || (pAd->CommonCfg.PhyMode == PHY_11N_5G))&& (HtCapabilityLen == 0)) - return FALSE; -#endif // DOT11_N_SUPPORT // - - if (!pEntry) - return FALSE; - - NdisAcquireSpinLock(&pAd->MacTabLock); - if (pEntry) - { - pEntry->PortSecured = WPA_802_1X_PORT_SECURED; - if ((MaxSupportedRate < RATE_FIRST_OFDM_RATE) || - (pAd->CommonCfg.PhyMode == PHY_11B)) - { - pEntry->RateLen = 4; - if (MaxSupportedRate >= RATE_FIRST_OFDM_RATE) - MaxSupportedRate = RATE_11; - } - else - pEntry->RateLen = 12; - - pEntry->MaxHTPhyMode.word = 0; - pEntry->MinHTPhyMode.word = 0; - pEntry->HTPhyMode.word = 0; - pEntry->MaxSupportedRate = MaxSupportedRate; - if (pEntry->MaxSupportedRate < RATE_FIRST_OFDM_RATE) - { - pEntry->MaxHTPhyMode.field.MODE = MODE_CCK; - pEntry->MaxHTPhyMode.field.MCS = pEntry->MaxSupportedRate; - pEntry->MinHTPhyMode.field.MODE = MODE_CCK; - pEntry->MinHTPhyMode.field.MCS = pEntry->MaxSupportedRate; - pEntry->HTPhyMode.field.MODE = MODE_CCK; - pEntry->HTPhyMode.field.MCS = pEntry->MaxSupportedRate; - } - else - { - pEntry->MaxHTPhyMode.field.MODE = MODE_OFDM; - pEntry->MaxHTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; - pEntry->MinHTPhyMode.field.MODE = MODE_OFDM; - pEntry->MinHTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; - pEntry->HTPhyMode.field.MODE = MODE_OFDM; - pEntry->HTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; - } - pEntry->CapabilityInfo = CapabilityInfo; - CLIENT_STATUS_CLEAR_FLAG(pEntry, fCLIENT_STATUS_AGGREGATION_CAPABLE); - CLIENT_STATUS_CLEAR_FLAG(pEntry, fCLIENT_STATUS_PIGGYBACK_CAPABLE); - } - -#ifdef DOT11_N_SUPPORT - // If this Entry supports 802.11n, upgrade to HT rate. - if ((HtCapabilityLen != 0) && (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) - { - UCHAR j, bitmask; //k,bitmask; - CHAR i; - - if (ADHOC_ON(pAd)) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_WMM_CAPABLE); - if ((pHtCapability->HtCapInfo.GF) && (pAd->CommonCfg.DesiredHtPhy.GF)) - { - pEntry->MaxHTPhyMode.field.MODE = MODE_HTGREENFIELD; - } - else - { - pEntry->MaxHTPhyMode.field.MODE = MODE_HTMIX; - pAd->MacTab.fAnyStationNonGF = TRUE; - pAd->CommonCfg.AddHTInfo.AddHtInfo2.NonGfPresent = 1; - } - - if ((pHtCapability->HtCapInfo.ChannelWidth) && (pAd->CommonCfg.DesiredHtPhy.ChannelWidth)) - { - pEntry->MaxHTPhyMode.field.BW= BW_40; - pEntry->MaxHTPhyMode.field.ShortGI = ((pAd->CommonCfg.DesiredHtPhy.ShortGIfor40)&(pHtCapability->HtCapInfo.ShortGIfor40)); - } - else - { - pEntry->MaxHTPhyMode.field.BW = BW_20; - pEntry->MaxHTPhyMode.field.ShortGI = ((pAd->CommonCfg.DesiredHtPhy.ShortGIfor20)&(pHtCapability->HtCapInfo.ShortGIfor20)); - pAd->MacTab.fAnyStation20Only = TRUE; - } - - // 3*3 - if (pAd->MACVersion >= RALINK_2883_VERSION && pAd->MACVersion < RALINK_3070_VERSION) - pEntry->MaxHTPhyMode.field.TxBF = pAd->CommonCfg.RegTransmitSetting.field.TxBF; - - // find max fixed rate - for (i=23; i>=0; i--) // 3*3 - { - j = i/8; - bitmask = (1<<(i-(j*8))); - if ((pAd->StaCfg.DesiredHtPhyInfo.MCSSet[j] & bitmask) && (pHtCapability->MCSSet[j] & bitmask)) - { - pEntry->MaxHTPhyMode.field.MCS = i; - break; - } - if (i==0) - break; - } - - - if (pAd->StaCfg.DesiredTransmitSetting.field.MCS != MCS_AUTO) - { - if (pAd->StaCfg.DesiredTransmitSetting.field.MCS == 32) - { - // Fix MCS as HT Duplicated Mode - pEntry->MaxHTPhyMode.field.BW = 1; - pEntry->MaxHTPhyMode.field.MODE = MODE_HTMIX; - pEntry->MaxHTPhyMode.field.STBC = 0; - pEntry->MaxHTPhyMode.field.ShortGI = 0; - pEntry->MaxHTPhyMode.field.MCS = 32; - } - else if (pEntry->MaxHTPhyMode.field.MCS > pAd->StaCfg.HTPhyMode.field.MCS) - { - // STA supports fixed MCS - pEntry->MaxHTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; - } - } - - pEntry->MaxHTPhyMode.field.STBC = (pHtCapability->HtCapInfo.RxSTBC & (pAd->CommonCfg.DesiredHtPhy.TxSTBC)); - pEntry->MpduDensity = pHtCapability->HtCapParm.MpduDensity; - pEntry->MaxRAmpduFactor = pHtCapability->HtCapParm.MaxRAmpduFactor; - pEntry->MmpsMode = (UCHAR)pHtCapability->HtCapInfo.MimoPs; - pEntry->AMsduSize = (UCHAR)pHtCapability->HtCapInfo.AMsduSize; - pEntry->HTPhyMode.word = pEntry->MaxHTPhyMode.word; - - if (pAd->CommonCfg.DesiredHtPhy.AmsduEnable && (pAd->CommonCfg.REGBACapability.field.AutoBA == FALSE)) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_AMSDU_INUSED); - if (pHtCapability->HtCapInfo.ShortGIfor20) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_SGI20_CAPABLE); - if (pHtCapability->HtCapInfo.ShortGIfor40) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_SGI40_CAPABLE); - if (pHtCapability->HtCapInfo.TxSTBC) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_TxSTBC_CAPABLE); - if (pHtCapability->HtCapInfo.RxSTBC) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_RxSTBC_CAPABLE); - if (pHtCapability->ExtHtCapInfo.PlusHTC) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_HTC_CAPABLE); - if (pAd->CommonCfg.bRdg && pHtCapability->ExtHtCapInfo.RDGSupport) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_RDG_CAPABLE); - if (pHtCapability->ExtHtCapInfo.MCSFeedback == 0x03) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_MCSFEEDBACK_CAPABLE); - } - else - { - pAd->MacTab.fAnyStationIsLegacy = TRUE; - } - - NdisMoveMemory(&pEntry->HTCapability, pHtCapability, sizeof(HT_CAPABILITY_IE)); -#endif // DOT11_N_SUPPORT // - - pEntry->HTPhyMode.word = pEntry->MaxHTPhyMode.word; - pEntry->CurrTxRate = pEntry->MaxSupportedRate; - - // Set asic auto fall back - if (pAd->StaCfg.bAutoTxRateSwitch == TRUE) - { - PUCHAR pTable; - UCHAR TableSize = 0; - - MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize, &pEntry->CurrTxRateIndex); - pEntry->bAutoTxRateSwitch = TRUE; - } - else - { - pEntry->HTPhyMode.field.MODE = pAd->StaCfg.HTPhyMode.field.MODE; - pEntry->HTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; - pEntry->bAutoTxRateSwitch = FALSE; - - // If the legacy mode is set, overwrite the transmit setting of this entry. - RTMPUpdateLegacyTxSetting((UCHAR)pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode, pEntry); - } - - pEntry->PortSecured = WPA_802_1X_PORT_SECURED; - pEntry->Sst = SST_ASSOC; - pEntry->AuthState = AS_AUTH_OPEN; - pEntry->AuthMode = pAd->StaCfg.AuthMode; - pEntry->WepStatus = pAd->StaCfg.WepStatus; - - NdisReleaseSpinLock(&pAd->MacTabLock); - -#ifdef WPA_SUPPLICANT_SUPPORT -#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT - if (pAd->StaCfg.WpaSupplicantUP) - { - union iwreq_data wrqu; - - SendAssocIEsToWpaSupplicant(pAd); - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.flags = RT_ASSOC_EVENT_FLAG; - wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); - } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // -#endif // WPA_SUPPLICANT_SUPPORT // - -#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT - { - union iwreq_data wrqu; - wext_notify_event_assoc(pAd); - - memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN); - memcpy(wrqu.ap_addr.sa_data, pAd->MlmeAux.Bssid, MAC_ADDR_LEN); - wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); - - } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // - return TRUE; -} - - +#include "../../rt2860/sta/assoc.c" diff --git a/drivers/staging/rt2870/sta/auth.c b/drivers/staging/rt2870/sta/auth.c index 73fb8d6ea76f..57632f9ec784 100644 --- a/drivers/staging/rt2870/sta/auth.c +++ b/drivers/staging/rt2870/sta/auth.c @@ -1,474 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - auth.c - - Abstract: - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - John 2004-9-3 porting from RT2500 -*/ -#include "../rt_config.h" - -/* - ========================================================================== - Description: - authenticate state machine init, including state transition and timer init - Parameters: - Sm - pointer to the auth state machine - Note: - The state machine looks like this - - AUTH_REQ_IDLE AUTH_WAIT_SEQ2 AUTH_WAIT_SEQ4 - MT2_MLME_AUTH_REQ mlme_auth_req_action invalid_state_when_auth invalid_state_when_auth - MT2_PEER_AUTH_EVEN drop peer_auth_even_at_seq2_action peer_auth_even_at_seq4_action - MT2_AUTH_TIMEOUT Drop auth_timeout_action auth_timeout_action - - IRQL = PASSIVE_LEVEL - - ========================================================================== - */ - -void AuthStateMachineInit( - IN PRTMP_ADAPTER pAd, - IN STATE_MACHINE *Sm, - OUT STATE_MACHINE_FUNC Trans[]) -{ - StateMachineInit(Sm, Trans, MAX_AUTH_STATE, MAX_AUTH_MSG, (STATE_MACHINE_FUNC)Drop, AUTH_REQ_IDLE, AUTH_MACHINE_BASE); - - // the first column - StateMachineSetAction(Sm, AUTH_REQ_IDLE, MT2_MLME_AUTH_REQ, (STATE_MACHINE_FUNC)MlmeAuthReqAction); - - // the second column - StateMachineSetAction(Sm, AUTH_WAIT_SEQ2, MT2_MLME_AUTH_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenAuth); - StateMachineSetAction(Sm, AUTH_WAIT_SEQ2, MT2_PEER_AUTH_EVEN, (STATE_MACHINE_FUNC)PeerAuthRspAtSeq2Action); - StateMachineSetAction(Sm, AUTH_WAIT_SEQ2, MT2_AUTH_TIMEOUT, (STATE_MACHINE_FUNC)AuthTimeoutAction); - - // the third column - StateMachineSetAction(Sm, AUTH_WAIT_SEQ4, MT2_MLME_AUTH_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenAuth); - StateMachineSetAction(Sm, AUTH_WAIT_SEQ4, MT2_PEER_AUTH_EVEN, (STATE_MACHINE_FUNC)PeerAuthRspAtSeq4Action); - StateMachineSetAction(Sm, AUTH_WAIT_SEQ4, MT2_AUTH_TIMEOUT, (STATE_MACHINE_FUNC)AuthTimeoutAction); - - RTMPInitTimer(pAd, &pAd->MlmeAux.AuthTimer, GET_TIMER_FUNCTION(AuthTimeout), pAd, FALSE); -} - -/* - ========================================================================== - Description: - function to be executed at timer thread when auth timer expires - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID AuthTimeout( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3) -{ - RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext; - - DBGPRINT(RT_DEBUG_TRACE,("AUTH - AuthTimeout\n")); - - // Do nothing if the driver is starting halt state. - // This might happen when timer already been fired before cancel timer with mlmehalt - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) - return; - - // send a de-auth to reset AP's state machine (Patch AP-Dir635) - if (pAd->Mlme.AuthMachine.CurrState == AUTH_WAIT_SEQ2) - Cls2errAction(pAd, pAd->MlmeAux.Bssid); - - - MlmeEnqueue(pAd, AUTH_STATE_MACHINE, MT2_AUTH_TIMEOUT, 0, NULL); - RT28XX_MLME_HANDLER(pAd); -} - - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID MlmeAuthReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - UCHAR Addr[6]; - USHORT Alg, Seq, Status; - ULONG Timeout; - HEADER_802_11 AuthHdr; - BOOLEAN TimerCancelled; - NDIS_STATUS NStatus; - PUCHAR pOutBuffer = NULL; - ULONG FrameLen = 0; - - // Block all authentication request durning WPA block period - if (pAd->StaCfg.bBlockAssoc == TRUE) - { - DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Block Auth request durning WPA block period!\n")); - pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; - Status = MLME_STATE_MACHINE_REJECT; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status); - } - else if(MlmeAuthReqSanity(pAd, Elem->Msg, Elem->MsgLen, Addr, &Timeout, &Alg)) - { - // reset timer - RTMPCancelTimer(&pAd->MlmeAux.AuthTimer, &TimerCancelled); - COPY_MAC_ADDR(pAd->MlmeAux.Bssid, Addr); - pAd->MlmeAux.Alg = Alg; - Seq = 1; - Status = MLME_SUCCESS; - - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory - if(NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_TRACE, ("AUTH - MlmeAuthReqAction(Alg:%d) allocate memory failed\n", Alg)); - pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; - Status = MLME_FAIL_NO_RESOURCE; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status); - return; - } - - DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Send AUTH request seq#1 (Alg=%d)...\n", Alg)); - MgtMacHeaderInit(pAd, &AuthHdr, SUBTYPE_AUTH, 0, Addr, pAd->MlmeAux.Bssid); - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(HEADER_802_11),&AuthHdr, - 2, &Alg, - 2, &Seq, - 2, &Status, - END_OF_ARGS); - MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); - - RTMPSetTimer(&pAd->MlmeAux.AuthTimer, Timeout); - pAd->Mlme.AuthMachine.CurrState = AUTH_WAIT_SEQ2; - } - else - { - DBGPRINT_ERR(("AUTH - MlmeAuthReqAction() sanity check failed\n")); - pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; - Status = MLME_INVALID_FORMAT; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status); - } -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID PeerAuthRspAtSeq2Action( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - UCHAR Addr2[MAC_ADDR_LEN]; - USHORT Seq, Status, RemoteStatus, Alg; - UCHAR ChlgText[CIPHER_TEXT_LEN]; - UCHAR CyperChlgText[CIPHER_TEXT_LEN + 8 + 8]; - UCHAR Element[2]; - HEADER_802_11 AuthHdr; - BOOLEAN TimerCancelled; - PUCHAR pOutBuffer = NULL; - NDIS_STATUS NStatus; - ULONG FrameLen = 0; - USHORT Status2; - - if (PeerAuthSanity(pAd, Elem->Msg, Elem->MsgLen, Addr2, &Alg, &Seq, &Status, ChlgText)) - { - if (MAC_ADDR_EQUAL(pAd->MlmeAux.Bssid, Addr2) && Seq == 2) - { - DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Receive AUTH_RSP seq#2 to me (Alg=%d, Status=%d)\n", Alg, Status)); - RTMPCancelTimer(&pAd->MlmeAux.AuthTimer, &TimerCancelled); - - if (Status == MLME_SUCCESS) - { - // Authentication Mode "LEAP" has allow for CCX 1.X - if ((pAd->MlmeAux.Alg == Ndis802_11AuthModeOpen) -#ifdef LEAP_SUPPORT - || (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) -#endif // LEAP_SUPPORT // - ) - { - pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; -#ifdef LEAP_SUPPORT - pAd->Mlme.LeapMachine.CurrState = LEAP_IDLE; -#endif // LEAP_SUPPORT // - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status); - } - else - { - // 2. shared key, need to be challenged - Seq++; - RemoteStatus = MLME_SUCCESS; - - // Get an unused nonpaged memory - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); - if(NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_TRACE, ("AUTH - PeerAuthRspAtSeq2Action() allocate memory fail\n")); - pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; - Status2 = MLME_FAIL_NO_RESOURCE; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status2); - return; - } - - DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Send AUTH request seq#3...\n")); - MgtMacHeaderInit(pAd, &AuthHdr, SUBTYPE_AUTH, 0, Addr2, pAd->MlmeAux.Bssid); - AuthHdr.FC.Wep = 1; - // Encrypt challenge text & auth information - RTMPInitWepEngine( - pAd, - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, - pAd->StaCfg.DefaultKeyId, - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].KeyLen, - CyperChlgText); - - Alg = cpu2le16(*(USHORT *)&Alg); - Seq = cpu2le16(*(USHORT *)&Seq); - RemoteStatus= cpu2le16(*(USHORT *)&RemoteStatus); - - RTMPEncryptData(pAd, (PUCHAR) &Alg, CyperChlgText + 4, 2); - RTMPEncryptData(pAd, (PUCHAR) &Seq, CyperChlgText + 6, 2); - RTMPEncryptData(pAd, (PUCHAR) &RemoteStatus, CyperChlgText + 8, 2); - Element[0] = 16; - Element[1] = 128; - RTMPEncryptData(pAd, Element, CyperChlgText + 10, 2); - RTMPEncryptData(pAd, ChlgText, CyperChlgText + 12, 128); - RTMPSetICV(pAd, CyperChlgText + 140); - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(HEADER_802_11), &AuthHdr, - CIPHER_TEXT_LEN + 16, CyperChlgText, - END_OF_ARGS); - MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); - - RTMPSetTimer(&pAd->MlmeAux.AuthTimer, AUTH_TIMEOUT); - pAd->Mlme.AuthMachine.CurrState = AUTH_WAIT_SEQ4; - } - } - else - { -#ifdef LEAP_SUPPORT - if (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) - { - //Invalid Authentication possible rogue AP - //Add this Ap to Rogue AP. - RogueApTableSetEntry(pAd, &pAd->StaCfg.RogueApTab, Addr2, LEAP_REASON_INVALID_AUTH); - } -#endif // LEAP_SUPPORT // - pAd->StaCfg.AuthFailReason = Status; - COPY_MAC_ADDR(pAd->StaCfg.AuthFailSta, Addr2); - pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status); - } - } - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("AUTH - PeerAuthSanity() sanity check fail\n")); - } -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID PeerAuthRspAtSeq4Action( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - UCHAR Addr2[MAC_ADDR_LEN]; - USHORT Alg, Seq, Status; - CHAR ChlgText[CIPHER_TEXT_LEN]; - BOOLEAN TimerCancelled; - - if(PeerAuthSanity(pAd, Elem->Msg, Elem->MsgLen, Addr2, &Alg, &Seq, &Status, ChlgText)) - { - if(MAC_ADDR_EQUAL(pAd->MlmeAux.Bssid, Addr2) && Seq == 4) - { - DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Receive AUTH_RSP seq#4 to me\n")); - RTMPCancelTimer(&pAd->MlmeAux.AuthTimer, &TimerCancelled); - - if (Status != MLME_SUCCESS) - { - pAd->StaCfg.AuthFailReason = Status; - COPY_MAC_ADDR(pAd->StaCfg.AuthFailSta, Addr2); - } - - pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status); - } - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("AUTH - PeerAuthRspAtSeq4Action() sanity check fail\n")); - } -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID MlmeDeauthReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - MLME_DEAUTH_REQ_STRUCT *pInfo; - HEADER_802_11 DeauthHdr; - PUCHAR pOutBuffer = NULL; - NDIS_STATUS NStatus; - ULONG FrameLen = 0; - USHORT Status; - - pInfo = (MLME_DEAUTH_REQ_STRUCT *)Elem->Msg; - - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory - if (NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_TRACE, ("AUTH - MlmeDeauthReqAction() allocate memory fail\n")); - pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; - Status = MLME_FAIL_NO_RESOURCE; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_DEAUTH_CONF, 2, &Status); - return; - } - - DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Send DE-AUTH request (Reason=%d)...\n", pInfo->Reason)); - MgtMacHeaderInit(pAd, &DeauthHdr, SUBTYPE_DEAUTH, 0, pInfo->Addr, pAd->MlmeAux.Bssid); - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(HEADER_802_11),&DeauthHdr, - 2, &pInfo->Reason, - END_OF_ARGS); - MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); - - pAd->StaCfg.DeauthReason = pInfo->Reason; - COPY_MAC_ADDR(pAd->StaCfg.DeauthSta, pInfo->Addr); - pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; - Status = MLME_SUCCESS; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_DEAUTH_CONF, 2, &Status); - - // send wireless event - for deauthentication - if (pAd->CommonCfg.bWirelessEvent) - RTMPSendWirelessEvent(pAd, IW_DEAUTH_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID AuthTimeoutAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - USHORT Status; - DBGPRINT(RT_DEBUG_TRACE, ("AUTH - AuthTimeoutAction\n")); - pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; - Status = MLME_REJ_TIMEOUT; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status); -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID InvalidStateWhenAuth( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - USHORT Status; - DBGPRINT(RT_DEBUG_TRACE, ("AUTH - InvalidStateWhenAuth (state=%ld), reset AUTH state machine\n", pAd->Mlme.AuthMachine.CurrState)); - pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; - Status = MLME_STATE_MACHINE_REJECT; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status); -} - -/* - ========================================================================== - Description: - Some STA/AP - Note: - This action should never trigger AUTH state transition, therefore we - separate it from AUTH state machine, and make it as a standalone service - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID Cls2errAction( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pAddr) -{ - HEADER_802_11 DeauthHdr; - PUCHAR pOutBuffer = NULL; - NDIS_STATUS NStatus; - ULONG FrameLen = 0; - USHORT Reason = REASON_CLS2ERR; - - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory - if (NStatus != NDIS_STATUS_SUCCESS) - return; - - DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Class 2 error, Send DEAUTH frame...\n")); - MgtMacHeaderInit(pAd, &DeauthHdr, SUBTYPE_DEAUTH, 0, pAddr, pAd->MlmeAux.Bssid); - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(HEADER_802_11),&DeauthHdr, - 2, &Reason, - END_OF_ARGS); - MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); - - pAd->StaCfg.DeauthReason = Reason; - COPY_MAC_ADDR(pAd->StaCfg.DeauthSta, pAddr); -} - - +#include "../../rt2860/sta/auth.c" diff --git a/drivers/staging/rt2870/sta/auth_rsp.c b/drivers/staging/rt2870/sta/auth_rsp.c index 6e3c2d24cdad..783e266d3e8f 100644 --- a/drivers/staging/rt2870/sta/auth_rsp.c +++ b/drivers/staging/rt2870/sta/auth_rsp.c @@ -1,166 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - auth_rsp.c - - Abstract: - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - John 2004-10-1 copy from RT2560 -*/ -#include "../rt_config.h" - -/* - ========================================================================== - Description: - authentication state machine init procedure - Parameters: - Sm - the state machine - - IRQL = PASSIVE_LEVEL - - ========================================================================== - */ -VOID AuthRspStateMachineInit( - IN PRTMP_ADAPTER pAd, - IN PSTATE_MACHINE Sm, - IN STATE_MACHINE_FUNC Trans[]) -{ - StateMachineInit(Sm, Trans, MAX_AUTH_RSP_STATE, MAX_AUTH_RSP_MSG, (STATE_MACHINE_FUNC)Drop, AUTH_RSP_IDLE, AUTH_RSP_MACHINE_BASE); - - // column 1 - StateMachineSetAction(Sm, AUTH_RSP_IDLE, MT2_PEER_DEAUTH, (STATE_MACHINE_FUNC)PeerDeauthAction); - - // column 2 - StateMachineSetAction(Sm, AUTH_RSP_WAIT_CHAL, MT2_PEER_DEAUTH, (STATE_MACHINE_FUNC)PeerDeauthAction); - -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== -*/ -VOID PeerAuthSimpleRspGenAndSend( - IN PRTMP_ADAPTER pAd, - IN PHEADER_802_11 pHdr80211, - IN USHORT Alg, - IN USHORT Seq, - IN USHORT Reason, - IN USHORT Status) -{ - HEADER_802_11 AuthHdr; - ULONG FrameLen = 0; - PUCHAR pOutBuffer = NULL; - NDIS_STATUS NStatus; - - if (Reason != MLME_SUCCESS) - { - DBGPRINT(RT_DEBUG_TRACE, ("Peer AUTH fail...\n")); - return; - } - - //Get an unused nonpaged memory - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); - if (NStatus != NDIS_STATUS_SUCCESS) - return; - - DBGPRINT(RT_DEBUG_TRACE, ("Send AUTH response (seq#2)...\n")); - MgtMacHeaderInit(pAd, &AuthHdr, SUBTYPE_AUTH, 0, pHdr80211->Addr2, pAd->MlmeAux.Bssid); - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(HEADER_802_11), &AuthHdr, - 2, &Alg, - 2, &Seq, - 2, &Reason, - END_OF_ARGS); - MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== -*/ -VOID PeerDeauthAction( - IN PRTMP_ADAPTER pAd, - IN PMLME_QUEUE_ELEM Elem) -{ - UCHAR Addr2[MAC_ADDR_LEN]; - USHORT Reason; - - if (PeerDeauthSanity(pAd, Elem->Msg, Elem->MsgLen, Addr2, &Reason)) - { - if (INFRA_ON(pAd) && MAC_ADDR_EQUAL(Addr2, pAd->CommonCfg.Bssid)) - { - DBGPRINT(RT_DEBUG_TRACE,("AUTH_RSP - receive DE-AUTH from our AP (Reason=%d)\n", Reason)); - -#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT - { - union iwreq_data wrqu; - memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN); - wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); - } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // - - - // send wireless event - for deauthentication - if (pAd->CommonCfg.bWirelessEvent) - RTMPSendWirelessEvent(pAd, IW_DEAUTH_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); - - LinkDown(pAd, TRUE); - - // Authentication Mode Cisco_LEAP has start a timer - // We should cancel it if using LEAP -#ifdef LEAP_SUPPORT - if (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) - { - RTMPCancelTimer(&pAd->StaCfg.LeapAuthTimer, &TimerCancelled); - //Check is it mach the LEAP Authentication failed as possible a Rogue AP - //on it's PortSecured not equal to WPA_802_1X_PORT_SECURED while process the Authenticaton. - if ((pAd->StaCfg.PortSecured != WPA_802_1X_PORT_SECURED) && (pAd->Mlme.LeapMachine.CurrState != LEAP_IDLE)) - { - RogueApTableSetEntry(pAd, &pAd->StaCfg.RogueApTab, Addr2, LEAP_REASON_AUTH_TIMEOUT); - } - } -#endif // LEAP_SUPPORT // - } - } - else - { - DBGPRINT(RT_DEBUG_TRACE,("AUTH_RSP - PeerDeauthAction() sanity check fail\n")); - } -} - +#include "../../rt2860/sta/auth_rsp.c" diff --git a/drivers/staging/rt2870/sta/connect.c b/drivers/staging/rt2870/sta/connect.c index c93140a8caa3..f6c7bbf542dc 100644 --- a/drivers/staging/rt2870/sta/connect.c +++ b/drivers/staging/rt2870/sta/connect.c @@ -1,2822 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - connect.c - - Abstract: - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - John 2004-08-08 Major modification from RT2560 -*/ -#include "../rt_config.h" - -UCHAR CipherSuiteWpaNoneTkip[] = { - 0x00, 0x50, 0xf2, 0x01, // oui - 0x01, 0x00, // Version - 0x00, 0x50, 0xf2, 0x02, // Multicast - 0x01, 0x00, // Number of unicast - 0x00, 0x50, 0xf2, 0x02, // unicast - 0x01, 0x00, // number of authentication method - 0x00, 0x50, 0xf2, 0x00 // authentication - }; -UCHAR CipherSuiteWpaNoneTkipLen = (sizeof(CipherSuiteWpaNoneTkip) / sizeof(UCHAR)); - -UCHAR CipherSuiteWpaNoneAes[] = { - 0x00, 0x50, 0xf2, 0x01, // oui - 0x01, 0x00, // Version - 0x00, 0x50, 0xf2, 0x04, // Multicast - 0x01, 0x00, // Number of unicast - 0x00, 0x50, 0xf2, 0x04, // unicast - 0x01, 0x00, // number of authentication method - 0x00, 0x50, 0xf2, 0x00 // authentication - }; -UCHAR CipherSuiteWpaNoneAesLen = (sizeof(CipherSuiteWpaNoneAes) / sizeof(UCHAR)); - -// The following MACRO is called after 1. starting an new IBSS, 2. succesfully JOIN an IBSS, -// or 3. succesfully ASSOCIATE to a BSS, 4. successfully RE_ASSOCIATE to a BSS -// All settings successfuly negotiated furing MLME state machines become final settings -// and are copied to pAd->StaActive -#define COPY_SETTINGS_FROM_MLME_AUX_TO_ACTIVE_CFG(_pAd) \ -{ \ - (_pAd)->CommonCfg.SsidLen = (_pAd)->MlmeAux.SsidLen; \ - NdisMoveMemory((_pAd)->CommonCfg.Ssid, (_pAd)->MlmeAux.Ssid, (_pAd)->MlmeAux.SsidLen); \ - COPY_MAC_ADDR((_pAd)->CommonCfg.Bssid, (_pAd)->MlmeAux.Bssid); \ - (_pAd)->CommonCfg.Channel = (_pAd)->MlmeAux.Channel; \ - (_pAd)->CommonCfg.CentralChannel = (_pAd)->MlmeAux.CentralChannel; \ - (_pAd)->StaActive.Aid = (_pAd)->MlmeAux.Aid; \ - (_pAd)->StaActive.AtimWin = (_pAd)->MlmeAux.AtimWin; \ - (_pAd)->StaActive.CapabilityInfo = (_pAd)->MlmeAux.CapabilityInfo; \ - (_pAd)->CommonCfg.BeaconPeriod = (_pAd)->MlmeAux.BeaconPeriod; \ - (_pAd)->StaActive.CfpMaxDuration = (_pAd)->MlmeAux.CfpMaxDuration; \ - (_pAd)->StaActive.CfpPeriod = (_pAd)->MlmeAux.CfpPeriod; \ - (_pAd)->StaActive.SupRateLen = (_pAd)->MlmeAux.SupRateLen; \ - NdisMoveMemory((_pAd)->StaActive.SupRate, (_pAd)->MlmeAux.SupRate, (_pAd)->MlmeAux.SupRateLen);\ - (_pAd)->StaActive.ExtRateLen = (_pAd)->MlmeAux.ExtRateLen; \ - NdisMoveMemory((_pAd)->StaActive.ExtRate, (_pAd)->MlmeAux.ExtRate, (_pAd)->MlmeAux.ExtRateLen);\ - NdisMoveMemory(&(_pAd)->CommonCfg.APEdcaParm, &(_pAd)->MlmeAux.APEdcaParm, sizeof(EDCA_PARM));\ - NdisMoveMemory(&(_pAd)->CommonCfg.APQosCapability, &(_pAd)->MlmeAux.APQosCapability, sizeof(QOS_CAPABILITY_PARM));\ - NdisMoveMemory(&(_pAd)->CommonCfg.APQbssLoad, &(_pAd)->MlmeAux.APQbssLoad, sizeof(QBSS_LOAD_PARM));\ - COPY_MAC_ADDR((_pAd)->MacTab.Content[BSSID_WCID].Addr, (_pAd)->MlmeAux.Bssid); \ - (_pAd)->MacTab.Content[BSSID_WCID].Aid = (_pAd)->MlmeAux.Aid; \ - (_pAd)->MacTab.Content[BSSID_WCID].PairwiseKey.CipherAlg = (_pAd)->StaCfg.PairCipher;\ - COPY_MAC_ADDR((_pAd)->MacTab.Content[BSSID_WCID].PairwiseKey.BssId, (_pAd)->MlmeAux.Bssid);\ - (_pAd)->MacTab.Content[BSSID_WCID].RateLen = (_pAd)->StaActive.SupRateLen + (_pAd)->StaActive.ExtRateLen;\ -} - -/* - ========================================================================== - Description: - - IRQL = PASSIVE_LEVEL - - ========================================================================== -*/ -VOID MlmeCntlInit( - IN PRTMP_ADAPTER pAd, - IN STATE_MACHINE *S, - OUT STATE_MACHINE_FUNC Trans[]) -{ - // Control state machine differs from other state machines, the interface - // follows the standard interface - pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== -*/ -VOID MlmeCntlMachinePerformAction( - IN PRTMP_ADAPTER pAd, - IN STATE_MACHINE *S, - IN MLME_QUEUE_ELEM *Elem) -{ - switch(pAd->Mlme.CntlMachine.CurrState) - { - case CNTL_IDLE: - CntlIdleProc(pAd, Elem); - break; - case CNTL_WAIT_DISASSOC: - CntlWaitDisassocProc(pAd, Elem); - break; - case CNTL_WAIT_JOIN: - CntlWaitJoinProc(pAd, Elem); - break; - - // CNTL_WAIT_REASSOC is the only state in CNTL machine that does - // not triggered directly or indirectly by "RTMPSetInformation(OID_xxx)". - // Therefore not protected by NDIS's "only one outstanding OID request" - // rule. Which means NDIS may SET OID in the middle of ROAMing attempts. - // Current approach is to block new SET request at RTMPSetInformation() - // when CntlMachine.CurrState is not CNTL_IDLE - case CNTL_WAIT_REASSOC: - CntlWaitReassocProc(pAd, Elem); - break; - - case CNTL_WAIT_START: - CntlWaitStartProc(pAd, Elem); - break; - case CNTL_WAIT_AUTH: - CntlWaitAuthProc(pAd, Elem); - break; - case CNTL_WAIT_AUTH2: - CntlWaitAuthProc2(pAd, Elem); - break; - case CNTL_WAIT_ASSOC: - CntlWaitAssocProc(pAd, Elem); - break; - - case CNTL_WAIT_OID_LIST_SCAN: - if(Elem->MsgType == MT2_SCAN_CONF) - { - // Resume TxRing after SCANING complete. We hope the out-of-service time - // won't be too long to let upper layer time-out the waiting frames - RTMPResumeMsduTransmission(pAd); - if (pAd->StaCfg.CCXReqType != MSRN_TYPE_UNUSED) - { - // Cisco scan request is finished, prepare beacon report - MlmeEnqueue(pAd, AIRONET_STATE_MACHINE, MT2_AIRONET_SCAN_DONE, 0, NULL); - } - pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; - - // - // Set LED status to previous status. - // - if (pAd->bLedOnScanning) - { - pAd->bLedOnScanning = FALSE; - RTMPSetLED(pAd, pAd->LedStatus); - } -#ifdef DOT11N_DRAFT3 - // AP sent a 2040Coexistence mgmt frame, then station perform a scan, and then send back the respone. - if (pAd->CommonCfg.BSSCoexist2040.field.InfoReq == 1) - { - Update2040CoexistFrameAndNotify(pAd, BSSID_WCID, TRUE); - } -#endif // DOT11N_DRAFT3 // - } - break; - - case CNTL_WAIT_OID_DISASSOC: - if (Elem->MsgType == MT2_DISASSOC_CONF) - { - LinkDown(pAd, FALSE); - pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; - } - break; -#ifdef RT2870 - // - // This state is for that we want to connect to an AP but - // it didn't find on BSS List table. So we need to scan the air first, - // after that we can try to connect to the desired AP if available. - // - case CNTL_WAIT_SCAN_FOR_CONNECT: - if(Elem->MsgType == MT2_SCAN_CONF) - { - // Resume TxRing after SCANING complete. We hope the out-of-service time - // won't be too long to let upper layer time-out the waiting frames - RTMPResumeMsduTransmission(pAd); -#ifdef CCX_SUPPORT - if (pAd->StaCfg.CCXReqType != MSRN_TYPE_UNUSED) - { - // Cisco scan request is finished, prepare beacon report - MlmeEnqueue(pAd, AIRONET_STATE_MACHINE, MT2_AIRONET_SCAN_DONE, 0, NULL); - } -#endif // CCX_SUPPORT // - pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; - - // - // Check if we can connect to. - // - BssTableSsidSort(pAd, &pAd->MlmeAux.SsidBssTab, pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.AutoReconnectSsidLen); - if (pAd->MlmeAux.SsidBssTab.BssNr > 0) - { - MlmeAutoReconnectLastSSID(pAd); - } - } - break; -#endif // RT2870 // - default: - DBGPRINT_ERR(("!ERROR! CNTL - Illegal message type(=%ld)", Elem->MsgType)); - break; - } -} - - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== -*/ -VOID CntlIdleProc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - MLME_DISASSOC_REQ_STRUCT DisassocReq; - - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF)) - return; - - switch(Elem->MsgType) - { - case OID_802_11_SSID: - CntlOidSsidProc(pAd, Elem); - break; - - case OID_802_11_BSSID: - CntlOidRTBssidProc(pAd,Elem); - break; - - case OID_802_11_BSSID_LIST_SCAN: - CntlOidScanProc(pAd,Elem); - break; - - case OID_802_11_DISASSOCIATE: -#ifdef RALINK_ATE - if(ATE_ON(pAd)) - { - DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now\n")); - break; - } -#endif // RALINK_ATE // - DisassocParmFill(pAd, &DisassocReq, pAd->CommonCfg.Bssid, REASON_DISASSOC_STA_LEAVING); - MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ, sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq); - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_DISASSOC; -#ifdef WPA_SUPPLICANT_SUPPORT - if (pAd->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_ENABLE_WITH_WEB_UI) -#endif // WPA_SUPPLICANT_SUPPORT // - { - // Set the AutoReconnectSsid to prevent it reconnect to old SSID - // Since calling this indicate user don't want to connect to that SSID anymore. - pAd->MlmeAux.AutoReconnectSsidLen= 32; - NdisZeroMemory(pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.AutoReconnectSsidLen); - } - break; - - case MT2_MLME_ROAMING_REQ: - CntlMlmeRoamingProc(pAd, Elem); - break; - - case OID_802_11_MIC_FAILURE_REPORT_FRAME: - WpaMicFailureReportFrame(pAd, Elem); - break; - -#ifdef QOS_DLS_SUPPORT - case RT_OID_802_11_SET_DLS_PARAM: - CntlOidDLSSetupProc(pAd, Elem); - break; -#endif // QOS_DLS_SUPPORT // - - default: - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Illegal message in CntlIdleProc(MsgType=%ld)\n",Elem->MsgType)); - break; - } -} - -VOID CntlOidScanProc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - MLME_SCAN_REQ_STRUCT ScanReq; - ULONG BssIdx = BSS_NOT_FOUND; - BSS_ENTRY CurrBss; - -#ifdef RALINK_ATE -/* Disable scanning when ATE is running. */ - if (ATE_ON(pAd)) - return; -#endif // RALINK_ATE // - - - // record current BSS if network is connected. - // 2003-2-13 do not include current IBSS if this is the only STA in this IBSS. - if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) - { - BssIdx = BssSsidTableSearch(&pAd->ScanTab, pAd->CommonCfg.Bssid, pAd->CommonCfg.Ssid, pAd->CommonCfg.SsidLen, pAd->CommonCfg.Channel); - if (BssIdx != BSS_NOT_FOUND) - { - NdisMoveMemory(&CurrBss, &pAd->ScanTab.BssEntry[BssIdx], sizeof(BSS_ENTRY)); - } - } - - // clean up previous SCAN result, add current BSS back to table if any - BssTableInit(&pAd->ScanTab); - if (BssIdx != BSS_NOT_FOUND) - { - // DDK Note: If the NIC is associated with a particular BSSID and SSID - // that are not contained in the list of BSSIDs generated by this scan, the - // BSSID description of the currently associated BSSID and SSID should be - // appended to the list of BSSIDs in the NIC's database. - // To ensure this, we append this BSS as the first entry in SCAN result - NdisMoveMemory(&pAd->ScanTab.BssEntry[0], &CurrBss, sizeof(BSS_ENTRY)); - pAd->ScanTab.BssNr = 1; - } - - ScanParmFill(pAd, &ScanReq, "", 0, BSS_ANY, SCAN_ACTIVE); - MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, - sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq); - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN; -} - -/* - ========================================================================== - Description: - Before calling this routine, user desired SSID should already been - recorded in CommonCfg.Ssid[] - IRQL = DISPATCH_LEVEL - - ========================================================================== -*/ -VOID CntlOidSsidProc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM * Elem) -{ - PNDIS_802_11_SSID pOidSsid = (NDIS_802_11_SSID *)Elem->Msg; - MLME_DISASSOC_REQ_STRUCT DisassocReq; - ULONG Now; - - // Step 1. record the desired user settings to MlmeAux - NdisZeroMemory(pAd->MlmeAux.Ssid, MAX_LEN_OF_SSID); - NdisMoveMemory(pAd->MlmeAux.Ssid, pOidSsid->Ssid, pOidSsid->SsidLength); - pAd->MlmeAux.SsidLen = (UCHAR)pOidSsid->SsidLength; - NdisZeroMemory(pAd->MlmeAux.Bssid, MAC_ADDR_LEN); - pAd->MlmeAux.BssType = pAd->StaCfg.BssType; - - - // - // Update Reconnect Ssid, that user desired to connect. - // - NdisZeroMemory(pAd->MlmeAux.AutoReconnectSsid, MAX_LEN_OF_SSID); - NdisMoveMemory(pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen); - pAd->MlmeAux.AutoReconnectSsidLen = pAd->MlmeAux.SsidLen; - - // step 2. find all matching BSS in the lastest SCAN result (inBssTab) - // & log them into MlmeAux.SsidBssTab for later-on iteration. Sort by RSSI order - BssTableSsidSort(pAd, &pAd->MlmeAux.SsidBssTab, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen); - - DBGPRINT(RT_DEBUG_TRACE, ("CntlOidSsidProc():CNTL - %d BSS of %d BSS match the desire (%d)SSID - %s\n", - pAd->MlmeAux.SsidBssTab.BssNr, pAd->ScanTab.BssNr, pAd->MlmeAux.SsidLen, pAd->MlmeAux.Ssid)); - NdisGetSystemUpTime(&Now); - - if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) && - (pAd->CommonCfg.SsidLen == pAd->MlmeAux.SsidBssTab.BssEntry[0].SsidLen) && - NdisEqualMemory(pAd->CommonCfg.Ssid, pAd->MlmeAux.SsidBssTab.BssEntry[0].Ssid, pAd->CommonCfg.SsidLen) && - MAC_ADDR_EQUAL(pAd->CommonCfg.Bssid, pAd->MlmeAux.SsidBssTab.BssEntry[0].Bssid)) - { - // Case 1. already connected with an AP who has the desired SSID - // with highest RSSI - - // Add checking Mode "LEAP" for CCX 1.0 - if (((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || - (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) || - (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || - (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) -#ifdef LEAP_SUPPORT - || (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) -#endif // LEAP_SUPPORT // - ) && - (pAd->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED)) - { - // case 1.1 For WPA, WPA-PSK, if the 1x port is not secured, we have to redo - // connection process - DBGPRINT(RT_DEBUG_TRACE, ("CntlOidSsidProc():CNTL - disassociate with current AP...\n")); - DisassocParmFill(pAd, &DisassocReq, pAd->CommonCfg.Bssid, REASON_DISASSOC_STA_LEAVING); - MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ, - sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq); - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_DISASSOC; - } - else if (pAd->bConfigChanged == TRUE) - { - // case 1.2 Important Config has changed, we have to reconnect to the same AP - DBGPRINT(RT_DEBUG_TRACE, ("CntlOidSsidProc():CNTL - disassociate with current AP Because config changed...\n")); - DisassocParmFill(pAd, &DisassocReq, pAd->CommonCfg.Bssid, REASON_DISASSOC_STA_LEAVING); - MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ, - sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq); - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_DISASSOC; - } - else - { - // case 1.3. already connected to the SSID with highest RSSI. - DBGPRINT(RT_DEBUG_TRACE, ("CntlOidSsidProc():CNTL - already with this BSSID. ignore this SET_SSID request\n")); - // - // (HCT 12.1) 1c_wlan_mediaevents required - // media connect events are indicated when associating with the same AP - // - if (INFRA_ON(pAd)) - { - // - // Since MediaState already is NdisMediaStateConnected - // We just indicate the connect event again to meet the WHQL required. - // - pAd->IndicateMediaState = NdisMediaStateConnected; - RTMP_IndicateMediaState(pAd); - pAd->ExtraInfo = GENERAL_LINK_UP; // Update extra information to link is up - } - - pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; -#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT - { - union iwreq_data wrqu; - - memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN); - memcpy(wrqu.ap_addr.sa_data, pAd->MlmeAux.Bssid, MAC_ADDR_LEN); - wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); - - } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // - } - } - else if (INFRA_ON(pAd)) - { - // - // For RT61 - // [88888] OID_802_11_SSID should have returned NDTEST_WEP_AP2(Returned: ) - // RT61 may lost SSID, and not connect to NDTEST_WEP_AP2 and will connect to NDTEST_WEP_AP2 by Autoreconnect - // But media status is connected, so the SSID not report correctly. - // - if (!SSID_EQUAL(pAd->CommonCfg.Ssid, pAd->CommonCfg.SsidLen, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen)) - { - // - // Different SSID means not Roaming case, so we let LinkDown() to Indicate a disconnect event. - // - pAd->MlmeAux.CurrReqIsFromNdis = TRUE; - } - // case 2. active INFRA association existent - // roaming is done within miniport driver, nothing to do with configuration - // utility. so upon a new SET(OID_802_11_SSID) is received, we just - // disassociate with the current associated AP, - // then perform a new association with this new SSID, no matter the - // new/old SSID are the same or not. - DBGPRINT(RT_DEBUG_TRACE, ("CntlOidSsidProc():CNTL - disassociate with current AP...\n")); - DisassocParmFill(pAd, &DisassocReq, pAd->CommonCfg.Bssid, REASON_DISASSOC_STA_LEAVING); - MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ, - sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq); - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_DISASSOC; - } - else - { - if (ADHOC_ON(pAd)) - { - DBGPRINT(RT_DEBUG_TRACE, ("CntlOidSsidProc():CNTL - drop current ADHOC\n")); - LinkDown(pAd, FALSE); - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED); - pAd->IndicateMediaState = NdisMediaStateDisconnected; - RTMP_IndicateMediaState(pAd); - pAd->ExtraInfo = GENERAL_LINK_DOWN; - DBGPRINT(RT_DEBUG_TRACE, ("CntlOidSsidProc():NDIS_STATUS_MEDIA_DISCONNECT Event C!\n")); - } - - if ((pAd->MlmeAux.SsidBssTab.BssNr == 0) && - (pAd->StaCfg.bAutoReconnect == TRUE) && - (pAd->MlmeAux.BssType == BSS_INFRA) && - (MlmeValidateSSID(pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen) == TRUE) - ) - { - MLME_SCAN_REQ_STRUCT ScanReq; - - DBGPRINT(RT_DEBUG_TRACE, ("CntlOidSsidProc():CNTL - No matching BSS, start a new scan\n")); - ScanParmFill(pAd, &ScanReq, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen, BSS_ANY, SCAN_ACTIVE); - MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq); - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN; - // Reset Missed scan number - pAd->StaCfg.LastScanTime = Now; - } - else - { - pAd->MlmeAux.BssIdx = 0; - IterateOnBssTab(pAd); - } - } -} - - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== -*/ -VOID CntlOidRTBssidProc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM * Elem) -{ - ULONG BssIdx; - PUCHAR pOidBssid = (PUCHAR)Elem->Msg; - MLME_DISASSOC_REQ_STRUCT DisassocReq; - MLME_JOIN_REQ_STRUCT JoinReq; - -#ifdef RALINK_ATE -/* No need to perform this routine when ATE is running. */ - if (ATE_ON(pAd)) - return; -#endif // RALINK_ATE // - - // record user desired settings - COPY_MAC_ADDR(pAd->MlmeAux.Bssid, pOidBssid); - pAd->MlmeAux.BssType = pAd->StaCfg.BssType; - - // - // Update Reconnect Ssid, that user desired to connect. - // - NdisZeroMemory(pAd->MlmeAux.AutoReconnectSsid, MAX_LEN_OF_SSID); - pAd->MlmeAux.AutoReconnectSsidLen = pAd->MlmeAux.SsidLen; - NdisMoveMemory(pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen); - - // find the desired BSS in the latest SCAN result table - BssIdx = BssTableSearch(&pAd->ScanTab, pOidBssid, pAd->MlmeAux.Channel); - if (BssIdx == BSS_NOT_FOUND) - { - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - BSSID not found. reply NDIS_STATUS_NOT_ACCEPTED\n")); - pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; - return; - } - - // copy the matched BSS entry from ScanTab to MlmeAux.SsidBssTab. Why? - // Because we need this entry to become the JOIN target in later on SYNC state machine - pAd->MlmeAux.BssIdx = 0; - pAd->MlmeAux.SsidBssTab.BssNr = 1; - NdisMoveMemory(&pAd->MlmeAux.SsidBssTab.BssEntry[0], &pAd->ScanTab.BssEntry[BssIdx], sizeof(BSS_ENTRY)); - - //pAd->MlmeAux.AutoReconnectSsidLen = pAd->ScanTab.BssEntry[BssIdx].SsidLen; - //NdisMoveMemory(pAd->MlmeAux.AutoReconnectSsid, pAd->ScanTab.BssEntry[BssIdx].Ssid, pAd->ScanTab.BssEntry[BssIdx].SsidLen); - - // Add SSID into MlmeAux for site surey joining hidden SSID - //pAd->MlmeAux.SsidLen = pAd->ScanTab.BssEntry[BssIdx].SsidLen; - //NdisMoveMemory(pAd->MlmeAux.Ssid, pAd->ScanTab.BssEntry[BssIdx].Ssid, pAd->MlmeAux.SsidLen); - - // 2002-11-26 skip the following checking. i.e. if user wants to re-connect to same AP - // we just follow normal procedure. The reason of user doing this may because he/she changed - // AP to another channel, but we still received BEACON from it thus don't claim Link Down. - // Since user knows he's changed AP channel, he'll re-connect again. By skipping the following - // checking, we'll disassociate then re-do normal association with this AP at the new channel. - // 2003-1-6 Re-enable this feature based on microsoft requirement which prefer not to re-do - // connection when setting the same BSSID. - if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) && - MAC_ADDR_EQUAL(pAd->CommonCfg.Bssid, pOidBssid)) - { - // already connected to the same BSSID, go back to idle state directly - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - already in this BSSID. ignore this SET_BSSID request\n")); - pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; -#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT - { - union iwreq_data wrqu; - - memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN); - memcpy(wrqu.ap_addr.sa_data, pAd->MlmeAux.Bssid, MAC_ADDR_LEN); - wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); - - } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // - } - else - { - if (INFRA_ON(pAd)) - { - // disassoc from current AP first - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - disassociate with current AP ...\n")); - DisassocParmFill(pAd, &DisassocReq, pAd->CommonCfg.Bssid, REASON_DISASSOC_STA_LEAVING); - MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ, - sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq); - - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_DISASSOC; - } - else - { - if (ADHOC_ON(pAd)) - { - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - drop current ADHOC\n")); - LinkDown(pAd, FALSE); - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED); - pAd->IndicateMediaState = NdisMediaStateDisconnected; - RTMP_IndicateMediaState(pAd); - pAd->ExtraInfo = GENERAL_LINK_DOWN; - DBGPRINT(RT_DEBUG_TRACE, ("NDIS_STATUS_MEDIA_DISCONNECT Event C!\n")); - } - - // Change the wepstatus to original wepstatus - pAd->StaCfg.WepStatus = pAd->StaCfg.OrigWepStatus; - pAd->StaCfg.PairCipher = pAd->StaCfg.OrigWepStatus; - pAd->StaCfg.GroupCipher = pAd->StaCfg.OrigWepStatus; - - // Check cipher suite, AP must have more secured cipher than station setting - // Set the Pairwise and Group cipher to match the intended AP setting - // We can only connect to AP with less secured cipher setting - if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) - { - pAd->StaCfg.GroupCipher = pAd->ScanTab.BssEntry[BssIdx].WPA.GroupCipher; - - if (pAd->StaCfg.WepStatus == pAd->ScanTab.BssEntry[BssIdx].WPA.PairCipher) - pAd->StaCfg.PairCipher = pAd->ScanTab.BssEntry[BssIdx].WPA.PairCipher; - else if (pAd->ScanTab.BssEntry[BssIdx].WPA.PairCipherAux != Ndis802_11WEPDisabled) - pAd->StaCfg.PairCipher = pAd->ScanTab.BssEntry[BssIdx].WPA.PairCipherAux; - else // There is no PairCipher Aux, downgrade our capability to TKIP - pAd->StaCfg.PairCipher = Ndis802_11Encryption2Enabled; - } - else if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)) - { - pAd->StaCfg.GroupCipher = pAd->ScanTab.BssEntry[BssIdx].WPA2.GroupCipher; - - if (pAd->StaCfg.WepStatus == pAd->ScanTab.BssEntry[BssIdx].WPA2.PairCipher) - pAd->StaCfg.PairCipher = pAd->ScanTab.BssEntry[BssIdx].WPA2.PairCipher; - else if (pAd->ScanTab.BssEntry[BssIdx].WPA2.PairCipherAux != Ndis802_11WEPDisabled) - pAd->StaCfg.PairCipher = pAd->ScanTab.BssEntry[BssIdx].WPA2.PairCipherAux; - else // There is no PairCipher Aux, downgrade our capability to TKIP - pAd->StaCfg.PairCipher = Ndis802_11Encryption2Enabled; - - // RSN capability - pAd->StaCfg.RsnCapability = pAd->ScanTab.BssEntry[BssIdx].WPA2.RsnCapability; - } - - // Set Mix cipher flag - pAd->StaCfg.bMixCipher = (pAd->StaCfg.PairCipher == pAd->StaCfg.GroupCipher) ? FALSE : TRUE; - if (pAd->StaCfg.bMixCipher == TRUE) - { - // If mix cipher, re-build RSNIE - RTMPMakeRSNIE(pAd, pAd->StaCfg.AuthMode, pAd->StaCfg.WepStatus, 0); - } - // No active association, join the BSS immediately - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - joining %02x:%02x:%02x:%02x:%02x:%02x ...\n", - pOidBssid[0],pOidBssid[1],pOidBssid[2],pOidBssid[3],pOidBssid[4],pOidBssid[5])); - - JoinParmFill(pAd, &JoinReq, pAd->MlmeAux.BssIdx); - MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_JOIN_REQ, sizeof(MLME_JOIN_REQ_STRUCT), &JoinReq); - - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_JOIN; - } - } -} - -// Roaming is the only external request triggering CNTL state machine -// despite of other "SET OID" operation. All "SET OID" related oerations -// happen in sequence, because no other SET OID will be sent to this device -// until the the previous SET operation is complete (successful o failed). -// So, how do we quarantee this ROAMING request won't corrupt other "SET OID"? -// or been corrupted by other "SET OID"? -// -// IRQL = DISPATCH_LEVEL -VOID CntlMlmeRoamingProc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - // TODO: - // AP in different channel may show lower RSSI than actual value?? - // should we add a weighting factor to compensate it? - DBGPRINT(RT_DEBUG_TRACE,("CNTL - Roaming in MlmeAux.RoamTab...\n")); - - NdisMoveMemory(&pAd->MlmeAux.SsidBssTab, &pAd->MlmeAux.RoamTab, sizeof(pAd->MlmeAux.RoamTab)); - pAd->MlmeAux.SsidBssTab.BssNr = pAd->MlmeAux.RoamTab.BssNr; - - BssTableSortByRssi(&pAd->MlmeAux.SsidBssTab); - pAd->MlmeAux.BssIdx = 0; - IterateOnBssTab(pAd); -} - -#ifdef QOS_DLS_SUPPORT -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== -*/ -VOID CntlOidDLSSetupProc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - PRT_802_11_DLS pDLS = (PRT_802_11_DLS)Elem->Msg; - MLME_DLS_REQ_STRUCT MlmeDlsReq; - INT i; - USHORT reason = REASON_UNSPECIFY; - - DBGPRINT(RT_DEBUG_TRACE,("CNTL - (OID set %02x:%02x:%02x:%02x:%02x:%02x with Valid=%d, Status=%d, TimeOut=%d, CountDownTimer=%d)\n", - pDLS->MacAddr[0], pDLS->MacAddr[1], pDLS->MacAddr[2], pDLS->MacAddr[3], pDLS->MacAddr[4], pDLS->MacAddr[5], - pDLS->Valid, pDLS->Status, pDLS->TimeOut, pDLS->CountDownTimer)); - - if (!pAd->CommonCfg.bDLSCapable) - return; - - // DLS will not be supported when Adhoc mode - if (INFRA_ON(pAd)) - { - for (i = 0; i < MAX_NUM_OF_DLS_ENTRY; i++) - { - if (pDLS->Valid && pAd->StaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) && - (pDLS->TimeOut == pAd->StaCfg.DLSEntry[i].TimeOut) && MAC_ADDR_EQUAL(pDLS->MacAddr, pAd->StaCfg.DLSEntry[i].MacAddr)) - { - // 1. Same setting, just drop it - DBGPRINT(RT_DEBUG_TRACE,("CNTL - setting unchanged\n")); - break; - } - else if (!pDLS->Valid && pAd->StaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) && - MAC_ADDR_EQUAL(pDLS->MacAddr, pAd->StaCfg.DLSEntry[i].MacAddr)) - { - // 2. Disable DLS link case, just tear down DLS link - reason = REASON_QOS_UNWANTED_MECHANISM; - pAd->StaCfg.DLSEntry[i].Valid = FALSE; - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); - MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_TEAR_DOWN, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); - DBGPRINT(RT_DEBUG_TRACE,("CNTL - start tear down procedure\n")); - break; - } - else if ((i < MAX_NUM_OF_DLS_ENTRY) && pDLS->Valid && !pAd->StaCfg.DLSEntry[i].Valid) - { - // 3. Enable case, start DLS setup procedure - NdisMoveMemory(&pAd->StaCfg.DLSEntry[i], pDLS, sizeof(RT_802_11_DLS_UI)); - - //Update countdown timer - pAd->StaCfg.DLSEntry[i].CountDownTimer = pAd->StaCfg.DLSEntry[i].TimeOut; - DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); - MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_REQ, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); - DBGPRINT(RT_DEBUG_TRACE,("CNTL - DLS setup case\n")); - break; - } - else if ((i < MAX_NUM_OF_DLS_ENTRY) && pDLS->Valid && pAd->StaCfg.DLSEntry[i].Valid && - (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) && !MAC_ADDR_EQUAL(pDLS->MacAddr, pAd->StaCfg.DLSEntry[i].MacAddr)) - { - // 4. update mac case, tear down old DLS and setup new DLS - reason = REASON_QOS_UNWANTED_MECHANISM; - pAd->StaCfg.DLSEntry[i].Valid = FALSE; - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); - MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_TEAR_DOWN, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); - NdisMoveMemory(&pAd->StaCfg.DLSEntry[i], pDLS, sizeof(RT_802_11_DLS_UI)); - DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); - MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_REQ, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); - DBGPRINT(RT_DEBUG_TRACE,("CNTL - DLS tear down and restart case\n")); - break; - } - else if (pDLS->Valid && pAd->StaCfg.DLSEntry[i].Valid && - MAC_ADDR_EQUAL(pDLS->MacAddr, pAd->StaCfg.DLSEntry[i].MacAddr) && (pAd->StaCfg.DLSEntry[i].TimeOut != pDLS->TimeOut)) - { - // 5. update timeout case, start DLS setup procedure (no tear down) - pAd->StaCfg.DLSEntry[i].TimeOut = pDLS->TimeOut; - //Update countdown timer - pAd->StaCfg.DLSEntry[i].CountDownTimer = pAd->StaCfg.DLSEntry[i].TimeOut; - DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); - MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_REQ, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); - DBGPRINT(RT_DEBUG_TRACE,("CNTL - DLS update timeout case\n")); - break; - } - else if (pDLS->Valid && pAd->StaCfg.DLSEntry[i].Valid && - (pAd->StaCfg.DLSEntry[i].Status != DLS_FINISH) && MAC_ADDR_EQUAL(pDLS->MacAddr, pAd->StaCfg.DLSEntry[i].MacAddr)) - { - // 6. re-setup case, start DLS setup procedure (no tear down) - DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); - MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_REQ, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); - DBGPRINT(RT_DEBUG_TRACE,("CNTL - DLS retry setup procedure\n")); - break; - } - else - { - DBGPRINT(RT_DEBUG_WARN,("CNTL - DLS not changed in entry - %d - Valid=%d, Status=%d, TimeOut=%d\n", - i, pAd->StaCfg.DLSEntry[i].Valid, pAd->StaCfg.DLSEntry[i].Status, pAd->StaCfg.DLSEntry[i].TimeOut)); - } - } - } -} -#endif // QOS_DLS_SUPPORT // - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== -*/ -VOID CntlWaitDisassocProc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - MLME_START_REQ_STRUCT StartReq; - - if (Elem->MsgType == MT2_DISASSOC_CONF) - { - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Dis-associate successful\n")); - - if (pAd->CommonCfg.bWirelessEvent) - { - RTMPSendWirelessEvent(pAd, IW_DISASSOC_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); - } - - LinkDown(pAd, FALSE); - - // case 1. no matching BSS, and user wants ADHOC, so we just start a new one - if ((pAd->MlmeAux.SsidBssTab.BssNr==0) && (pAd->StaCfg.BssType == BSS_ADHOC)) - { - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - No matching BSS, start a new ADHOC (Ssid=%s)...\n",pAd->MlmeAux.Ssid)); - StartParmFill(pAd, &StartReq, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen); - MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_START_REQ, sizeof(MLME_START_REQ_STRUCT), &StartReq); - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_START; - } - // case 2. try each matched BSS - else - { - pAd->MlmeAux.BssIdx = 0; - - IterateOnBssTab(pAd); - } - } -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== -*/ -VOID CntlWaitJoinProc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - USHORT Reason; - MLME_AUTH_REQ_STRUCT AuthReq; - - if (Elem->MsgType == MT2_JOIN_CONF) - { - NdisMoveMemory(&Reason, Elem->Msg, sizeof(USHORT)); - if (Reason == MLME_SUCCESS) - { - // 1. joined an IBSS, we are pretty much done here - if (pAd->MlmeAux.BssType == BSS_ADHOC) - { - // - // 5G bands rules of Japan: - // Ad hoc must be disabled in W53(ch52,56,60,64) channels. - // - if ( (pAd->CommonCfg.bIEEE80211H == 1) && - RadarChannelCheck(pAd, pAd->CommonCfg.Channel) - ) - { - pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Channel=%d, Join adhoc on W53(52,56,60,64) Channels are not accepted\n", pAd->CommonCfg.Channel)); - return; - } - - LinkUp(pAd, BSS_ADHOC); - pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - join the IBSS = %02x:%02x:%02x:%02x:%02x:%02x ...\n", - pAd->CommonCfg.Bssid[0],pAd->CommonCfg.Bssid[1],pAd->CommonCfg.Bssid[2], - pAd->CommonCfg.Bssid[3],pAd->CommonCfg.Bssid[4],pAd->CommonCfg.Bssid[5])); - - pAd->IndicateMediaState = NdisMediaStateConnected; - pAd->ExtraInfo = GENERAL_LINK_UP; - } - // 2. joined a new INFRA network, start from authentication - else - { -#ifdef LEAP_SUPPORT - // Add AuthMode "LEAP" for CCX 1.X - if (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) - { - AuthParmFill(pAd, &AuthReq, pAd->MlmeAux.Bssid, CISCO_AuthModeLEAP); - } - else -#endif // LEAP_SUPPORT // - { - // either Ndis802_11AuthModeShared or Ndis802_11AuthModeAutoSwitch, try shared key first - if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeShared) || - (pAd->StaCfg.AuthMode == Ndis802_11AuthModeAutoSwitch)) - { - AuthParmFill(pAd, &AuthReq, pAd->MlmeAux.Bssid, Ndis802_11AuthModeShared); - } - else - { - AuthParmFill(pAd, &AuthReq, pAd->MlmeAux.Bssid, Ndis802_11AuthModeOpen); - } - } - MlmeEnqueue(pAd, AUTH_STATE_MACHINE, MT2_MLME_AUTH_REQ, - sizeof(MLME_AUTH_REQ_STRUCT), &AuthReq); - - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_AUTH; - } - } - else - { - // 3. failed, try next BSS - pAd->MlmeAux.BssIdx++; - IterateOnBssTab(pAd); - } - } -} - - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== -*/ -VOID CntlWaitStartProc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - USHORT Result; - - if (Elem->MsgType == MT2_START_CONF) - { - NdisMoveMemory(&Result, Elem->Msg, sizeof(USHORT)); - if (Result == MLME_SUCCESS) - { - // - // 5G bands rules of Japan: - // Ad hoc must be disabled in W53(ch52,56,60,64) channels. - // - if ( (pAd->CommonCfg.bIEEE80211H == 1) && - RadarChannelCheck(pAd, pAd->CommonCfg.Channel) - ) - { - pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Channel=%d, Start adhoc on W53(52,56,60,64) Channels are not accepted\n", pAd->CommonCfg.Channel)); - return; - } -#ifdef DOT11_N_SUPPORT - if (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) - { - N_ChannelCheck(pAd); - SetCommonHT(pAd); - NdisMoveMemory(&pAd->MlmeAux.AddHtInfo, &pAd->CommonCfg.AddHTInfo, sizeof(ADD_HT_INFO_IE)); - RTMPCheckHt(pAd, BSSID_WCID, &pAd->CommonCfg.HtCapability, &pAd->CommonCfg.AddHTInfo); - pAd->StaActive.SupportedPhyInfo.bHtEnable = TRUE; - NdisZeroMemory(&pAd->StaActive.SupportedPhyInfo.MCSSet[0], 16); - NdisMoveMemory(&pAd->StaActive.SupportedPhyInfo.MCSSet[0], &pAd->CommonCfg.HtCapability.MCSSet[0], 16); - COPY_HTSETTINGS_FROM_MLME_AUX_TO_ACTIVE_CFG(pAd); - - if ((pAd->CommonCfg.HtCapability.HtCapInfo.ChannelWidth == BW_40) && - (pAd->CommonCfg.AddHTInfo.AddHtInfo.ExtChanOffset == EXTCHA_ABOVE)) - { - pAd->MlmeAux.CentralChannel = pAd->CommonCfg.Channel + 2; - } - else if ((pAd->CommonCfg.HtCapability.HtCapInfo.ChannelWidth == BW_40) && - (pAd->CommonCfg.AddHTInfo.AddHtInfo.ExtChanOffset == EXTCHA_BELOW)) - { - pAd->MlmeAux.CentralChannel = pAd->CommonCfg.Channel - 2; - } - } - else -#endif // DOT11_N_SUPPORT // - { - pAd->StaActive.SupportedPhyInfo.bHtEnable = FALSE; - } - LinkUp(pAd, BSS_ADHOC); - pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; - // Before send beacon, driver need do radar detection - if ((pAd->CommonCfg.Channel > 14 ) - && (pAd->CommonCfg.bIEEE80211H == 1) - && RadarChannelCheck(pAd, pAd->CommonCfg.Channel)) - { - pAd->CommonCfg.RadarDetect.RDMode = RD_SILENCE_MODE; - pAd->CommonCfg.RadarDetect.RDCount = 0; -#ifdef DFS_SUPPORT - BbpRadarDetectionStart(pAd); -#endif // DFS_SUPPORT // - } - - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - start a new IBSS = %02x:%02x:%02x:%02x:%02x:%02x ...\n", - pAd->CommonCfg.Bssid[0],pAd->CommonCfg.Bssid[1],pAd->CommonCfg.Bssid[2], - pAd->CommonCfg.Bssid[3],pAd->CommonCfg.Bssid[4],pAd->CommonCfg.Bssid[5])); - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Start IBSS fail. BUG!!!!!\n")); - pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; - } - } -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== -*/ -VOID CntlWaitAuthProc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - USHORT Reason; - MLME_ASSOC_REQ_STRUCT AssocReq; - MLME_AUTH_REQ_STRUCT AuthReq; - - if (Elem->MsgType == MT2_AUTH_CONF) - { - NdisMoveMemory(&Reason, Elem->Msg, sizeof(USHORT)); - if (Reason == MLME_SUCCESS) - { - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - AUTH OK\n")); - AssocParmFill(pAd, &AssocReq, pAd->MlmeAux.Bssid, pAd->MlmeAux.CapabilityInfo, - ASSOC_TIMEOUT, pAd->StaCfg.DefaultListenCount); - -#ifdef LEAP_SUPPORT - // - // Cisco Leap CCKM supported Re-association. - // - if (LEAP_CCKM_ON(pAd) && (pAd->StaCfg.CCKMLinkUpFlag == TRUE)) - { - //if CCKM is turn on , that's mean Fast Reauthentication - //Use CCKM Reassociation instead of normal association for Fast Roaming. - MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_REASSOC_REQ, - sizeof(MLME_ASSOC_REQ_STRUCT), &AssocReq); - - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_REASSOC; - } - else -#endif // LEAP_SUPPORT // - { - MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_ASSOC_REQ, - sizeof(MLME_ASSOC_REQ_STRUCT), &AssocReq); - - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_ASSOC; - } - } - else - { - // This fail may because of the AP already keep us in its MAC table without - // ageing-out. The previous authentication attempt must have let it remove us. - // so try Authentication again may help. For D-Link DWL-900AP+ compatibility. - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - AUTH FAIL, try again...\n")); -#ifdef LEAP_SUPPORT - //Add AuthMode "LEAP" for CCX 1.X - if (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) - { - AuthParmFill(pAd, &AuthReq, pAd->MlmeAux.Bssid, CISCO_AuthModeLEAP); - } - else -#endif // LEAP_SUPPORT // - { - if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeShared) || - (pAd->StaCfg.AuthMode == Ndis802_11AuthModeAutoSwitch)) - { - // either Ndis802_11AuthModeShared or Ndis802_11AuthModeAutoSwitch, try shared key first - AuthParmFill(pAd, &AuthReq, pAd->MlmeAux.Bssid, Ndis802_11AuthModeShared); - } - else - { - AuthParmFill(pAd, &AuthReq, pAd->MlmeAux.Bssid, Ndis802_11AuthModeOpen); - } - } - MlmeEnqueue(pAd, AUTH_STATE_MACHINE, MT2_MLME_AUTH_REQ, - sizeof(MLME_AUTH_REQ_STRUCT), &AuthReq); - - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_AUTH2; - } - } -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== -*/ -VOID CntlWaitAuthProc2( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - USHORT Reason; - MLME_ASSOC_REQ_STRUCT AssocReq; - MLME_AUTH_REQ_STRUCT AuthReq; - - if (Elem->MsgType == MT2_AUTH_CONF) - { - NdisMoveMemory(&Reason, Elem->Msg, sizeof(USHORT)); - if (Reason == MLME_SUCCESS) - { - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - AUTH OK\n")); - AssocParmFill(pAd, &AssocReq, pAd->MlmeAux.Bssid, pAd->MlmeAux.CapabilityInfo, - ASSOC_TIMEOUT, pAd->StaCfg.DefaultListenCount); - MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_ASSOC_REQ, - sizeof(MLME_ASSOC_REQ_STRUCT), &AssocReq); - - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_ASSOC; - } - else - { -#ifdef LEAP_SUPPORT - // Process LEAP first, since it use different control variable - // We don't want to affect other poven operation - if (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) - { - // LEAP Auth not success, try next BSS - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - *LEAP* AUTH FAIL, give up; try next BSS\n")); - DBGPRINT(RT_DEBUG_TRACE, ("Total match BSSID [=%d]\n", pAd->MlmeAux.SsidBssTab.BssNr)); - pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; - pAd->MlmeAux.BssIdx++; - IterateOnBssTab(pAd); - } - else -#endif // LEAP_SUPPORT // - if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeAutoSwitch) && - (pAd->MlmeAux.Alg == Ndis802_11AuthModeShared)) - { - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - AUTH FAIL, try OPEN system...\n")); - AuthParmFill(pAd, &AuthReq, pAd->MlmeAux.Bssid, Ndis802_11AuthModeOpen); - MlmeEnqueue(pAd, AUTH_STATE_MACHINE, MT2_MLME_AUTH_REQ, - sizeof(MLME_AUTH_REQ_STRUCT), &AuthReq); - - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_AUTH2; - } - else - { - // not success, try next BSS - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - AUTH FAIL, give up; try next BSS\n")); - pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; //??????? - pAd->MlmeAux.BssIdx++; - IterateOnBssTab(pAd); - } - } - } -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== -*/ -VOID CntlWaitAssocProc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - USHORT Reason; - - if (Elem->MsgType == MT2_ASSOC_CONF) - { - NdisMoveMemory(&Reason, Elem->Msg, sizeof(USHORT)); - if (Reason == MLME_SUCCESS) - { - LinkUp(pAd, BSS_INFRA); - pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Association successful on BSS #%ld\n",pAd->MlmeAux.BssIdx)); - - if (pAd->CommonCfg.bWirelessEvent) - { - RTMPSendWirelessEvent(pAd, IW_ASSOC_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); - } - } - else - { - // not success, try next BSS - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Association fails on BSS #%ld\n",pAd->MlmeAux.BssIdx)); - pAd->MlmeAux.BssIdx++; - IterateOnBssTab(pAd); - } - } -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== -*/ -VOID CntlWaitReassocProc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - USHORT Result; - - if (Elem->MsgType == MT2_REASSOC_CONF) - { - NdisMoveMemory(&Result, Elem->Msg, sizeof(USHORT)); - if (Result == MLME_SUCCESS) - { - // - // NDIS requires a new Link UP indication but no Link Down for RE-ASSOC - // - LinkUp(pAd, BSS_INFRA); - - // send wireless event - for association - if (pAd->CommonCfg.bWirelessEvent) - RTMPSendWirelessEvent(pAd, IW_ASSOC_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); - - -#ifdef LEAP_SUPPORT - if (LEAP_CCKM_ON(pAd)) - { - STA_PORT_SECURED(pAd); - pAd->StaCfg.WpaState = SS_FINISH; - } -#endif // LEAP_SUPPORT // - pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Re-assocition successful on BSS #%ld\n", pAd->MlmeAux.RoamIdx)); - } - else - { - // reassoc failed, try to pick next BSS in the BSS Table - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Re-assocition fails on BSS #%ld\n", pAd->MlmeAux.RoamIdx)); - pAd->MlmeAux.RoamIdx++; - IterateOnBssTab2(pAd); - } - } -} - - -VOID AdhocTurnOnQos( - IN PRTMP_ADAPTER pAd) -{ -#define AC0_DEF_TXOP 0 -#define AC1_DEF_TXOP 0 -#define AC2_DEF_TXOP 94 -#define AC3_DEF_TXOP 47 - - // Turn on QOs if use HT rate. - if (pAd->CommonCfg.APEdcaParm.bValid == FALSE) - { - pAd->CommonCfg.APEdcaParm.bValid = TRUE; - pAd->CommonCfg.APEdcaParm.Aifsn[0] = 3; - pAd->CommonCfg.APEdcaParm.Aifsn[1] = 7; - pAd->CommonCfg.APEdcaParm.Aifsn[2] = 1; - pAd->CommonCfg.APEdcaParm.Aifsn[3] = 1; - - pAd->CommonCfg.APEdcaParm.Cwmin[0] = 4; - pAd->CommonCfg.APEdcaParm.Cwmin[1] = 4; - pAd->CommonCfg.APEdcaParm.Cwmin[2] = 3; - pAd->CommonCfg.APEdcaParm.Cwmin[3] = 2; - - pAd->CommonCfg.APEdcaParm.Cwmax[0] = 10; - pAd->CommonCfg.APEdcaParm.Cwmax[1] = 6; - pAd->CommonCfg.APEdcaParm.Cwmax[2] = 4; - pAd->CommonCfg.APEdcaParm.Cwmax[3] = 3; - - pAd->CommonCfg.APEdcaParm.Txop[0] = 0; - pAd->CommonCfg.APEdcaParm.Txop[1] = 0; - pAd->CommonCfg.APEdcaParm.Txop[2] = AC2_DEF_TXOP; - pAd->CommonCfg.APEdcaParm.Txop[3] = AC3_DEF_TXOP; - } - AsicSetEdcaParm(pAd, &pAd->CommonCfg.APEdcaParm); -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== -*/ -VOID LinkUp( - IN PRTMP_ADAPTER pAd, - IN UCHAR BssType) -{ - ULONG Now; - UINT32 Data; - BOOLEAN Cancelled; - UCHAR Value = 0, idx; - MAC_TABLE_ENTRY *pEntry = NULL, *pCurrEntry; - - pEntry = &pAd->MacTab.Content[BSSID_WCID]; - - // - // ASSOC - DisassocTimeoutAction - // CNTL - Dis-associate successful - // !!! LINK DOWN !!! - // [88888] OID_802_11_SSID should have returned NDTEST_WEP_AP2(Returned: ) - // - // To prevent DisassocTimeoutAction to call Link down after we link up, - // cancel the DisassocTimer no matter what it start or not. - // - RTMPCancelTimer(&pAd->MlmeAux.DisassocTimer, &Cancelled); - - COPY_SETTINGS_FROM_MLME_AUX_TO_ACTIVE_CFG(pAd); - -#ifdef DOT11_N_SUPPORT - COPY_HTSETTINGS_FROM_MLME_AUX_TO_ACTIVE_CFG(pAd); -#endif // DOT11_N_SUPPORT // - // It's quite difficult to tell if a newly added KEY is WEP or CKIP until a new BSS - // is formed (either ASSOC/RE-ASSOC done or IBSS started. LinkUP should be a safe place - // to examine if cipher algorithm switching is required. - //rt2860b. Don't know why need this - SwitchBetweenWepAndCkip(pAd); - - - if (BssType == BSS_ADHOC) - { - OPSTATUS_SET_FLAG(pAd, fOP_STATUS_ADHOC_ON); - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_INFRA_ON); - -#ifdef CARRIER_DETECTION_SUPPORT // Roger sync Carrier - // No carrier detection when adhoc - // CarrierDetectionStop(pAd); - pAd->CommonCfg.CarrierDetect.CD_State = CD_NORMAL; -#endif // CARRIER_DETECTION_SUPPORT // - -#ifdef DOT11_N_SUPPORT - if (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) - AdhocTurnOnQos(pAd); -#endif // DOT11_N_SUPPORT // - - DBGPRINT(RT_DEBUG_TRACE, ("!!!Adhoc LINK UP !!! \n" )); - } - else - { - OPSTATUS_SET_FLAG(pAd, fOP_STATUS_INFRA_ON); - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_ADHOC_ON); - - DBGPRINT(RT_DEBUG_TRACE, ("!!!Infra LINK UP !!! \n" )); - } - - // 3*3 - // reset Tx beamforming bit - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &Value); - Value &= (~0x01); - Value |= pAd->CommonCfg.RegTransmitSetting.field.TxBF; - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, Value); - -#ifdef DOT11_N_SUPPORT - // Change to AP channel - if ((pAd->CommonCfg.CentralChannel > pAd->CommonCfg.Channel) && (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40)) - { - // Must using 40MHz. - pAd->CommonCfg.BBPCurrentBW = BW_40; - AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE); - AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel); - - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &Value); - Value &= (~0x18); - Value |= 0x10; - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, Value); - - // RX : control channel at lower - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &Value); - Value &= (~0x20); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, Value); - - RTMP_IO_READ32(pAd, TX_BAND_CFG, &Data); - Data &= 0xfffffffe; - RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Data); - - if (pAd->MACVersion == 0x28600100) - { - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, 0x1A); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, 0x0A); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R73, 0x16); - DBGPRINT(RT_DEBUG_TRACE, ("!!!rt2860C !!! \n" )); - } - - DBGPRINT(RT_DEBUG_TRACE, ("!!!40MHz Lower LINK UP !!! Control Channel at Below. Central = %d \n", pAd->CommonCfg.CentralChannel )); - } - else if ((pAd->CommonCfg.CentralChannel < pAd->CommonCfg.Channel) && (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40)) - { - // Must using 40MHz. - pAd->CommonCfg.BBPCurrentBW = BW_40; - AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE); - AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel); - - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &Value); - Value &= (~0x18); - Value |= 0x10; - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, Value); - - RTMP_IO_READ32(pAd, TX_BAND_CFG, &Data); - Data |= 0x1; - RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Data); - - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &Value); - Value |= (0x20); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, Value); - - if (pAd->MACVersion == 0x28600100) - { - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, 0x1A); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, 0x0A); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R73, 0x16); - DBGPRINT(RT_DEBUG_TRACE, ("!!!rt2860C !!! \n" )); - } - - DBGPRINT(RT_DEBUG_TRACE, ("!!! 40MHz Upper LINK UP !!! Control Channel at UpperCentral = %d \n", pAd->CommonCfg.CentralChannel )); - } - else -#endif // DOT11_N_SUPPORT // - { - pAd->CommonCfg.BBPCurrentBW = BW_20; - pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel; - AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); - AsicLockChannel(pAd, pAd->CommonCfg.Channel); - - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &Value); - Value &= (~0x18); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, Value); - - RTMP_IO_READ32(pAd, TX_BAND_CFG, &Data); - Data &= 0xfffffffe; - RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Data); - - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &Value); - Value &= (~0x20); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, Value); - - if (pAd->MACVersion == 0x28600100) - { - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, 0x16); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, 0x08); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R73, 0x11); - DBGPRINT(RT_DEBUG_TRACE, ("!!!rt2860C !!! \n" )); - } - - DBGPRINT(RT_DEBUG_TRACE, ("!!! 20MHz LINK UP !!! \n" )); - } - - RTMPSetAGCInitValue(pAd, pAd->CommonCfg.BBPCurrentBW); - // - // Save BBP_R66 value, it will be used in RTUSBResumeMsduTransmission - // - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R66, &pAd->BbpTuning.R66CurrentValue); - - DBGPRINT(RT_DEBUG_TRACE, ("!!! LINK UP !!! (BssType=%d, AID=%d, ssid=%s, Channel=%d, CentralChannel = %d)\n", - BssType, pAd->StaActive.Aid, pAd->CommonCfg.Ssid, pAd->CommonCfg.Channel, pAd->CommonCfg.CentralChannel)); - -#ifdef DOT11_N_SUPPORT - DBGPRINT(RT_DEBUG_TRACE, ("!!! LINK UP !!! (Density =%d, )\n", pAd->MacTab.Content[BSSID_WCID].MpduDensity)); -#endif // DOT11_N_SUPPORT // - - AsicSetBssid(pAd, pAd->CommonCfg.Bssid); - - AsicSetSlotTime(pAd, TRUE); - AsicSetEdcaParm(pAd, &pAd->CommonCfg.APEdcaParm); - - // Call this for RTS protectionfor legacy rate, we will always enable RTS threshold, but normally it will not hit - AsicUpdateProtect(pAd, 0, (OFDMSETPROTECT | CCKSETPROTECT), TRUE, FALSE); - -#ifdef DOT11_N_SUPPORT - if ((pAd->StaActive.SupportedPhyInfo.bHtEnable == TRUE)) - { - // Update HT protectionfor based on AP's operating mode. - if (pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent == 1) - { - AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, ALLN_SETPROTECT, FALSE, TRUE); - } - else - AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, ALLN_SETPROTECT, FALSE, FALSE); - } -#endif // DOT11_N_SUPPORT // - - NdisZeroMemory(&pAd->DrsCounters, sizeof(COUNTER_DRS)); - - NdisGetSystemUpTime(&Now); - pAd->StaCfg.LastBeaconRxTime = Now; // last RX timestamp - - if ((pAd->CommonCfg.TxPreamble != Rt802_11PreambleLong) && - CAP_IS_SHORT_PREAMBLE_ON(pAd->StaActive.CapabilityInfo)) - { - MlmeSetTxPreamble(pAd, Rt802_11PreambleShort); - } - - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED); - - if (pAd->CommonCfg.RadarDetect.RDMode == RD_SILENCE_MODE) - { -#ifdef DFS_SUPPORT - RadarDetectionStop(pAd); -#endif // DFS_SUPPORT // - } - pAd->CommonCfg.RadarDetect.RDMode = RD_NORMAL_MODE; - - if (BssType == BSS_ADHOC) - { - MakeIbssBeacon(pAd); - if ((pAd->CommonCfg.Channel > 14) - && (pAd->CommonCfg.bIEEE80211H == 1) - && RadarChannelCheck(pAd, pAd->CommonCfg.Channel)) - { - ; //Do nothing - } - else - { - AsicEnableIbssSync(pAd); - } - - // In ad hoc mode, use MAC table from index 1. - // p.s ASIC use all 0xff as termination of WCID table search.To prevent it's 0xff-ff-ff-ff-ff-ff, Write 0 here. - RTMP_IO_WRITE32(pAd, MAC_WCID_BASE, 0x00); - RTMP_IO_WRITE32(pAd, 0x1808, 0x00); - - // If WEP is enabled, add key material and cipherAlg into Asic - // Fill in Shared Key Table(offset: 0x6c00) and Shared Key Mode(offset: 0x7000) - - if (pAd->StaCfg.WepStatus == Ndis802_11WEPEnabled) - { - PUCHAR Key; - UCHAR CipherAlg; - - for (idx=0; idx < SHARE_KEY_NUM; idx++) - { - CipherAlg = pAd->SharedKey[BSS0][idx].CipherAlg; - Key = pAd->SharedKey[BSS0][idx].Key; - - if (pAd->SharedKey[BSS0][idx].KeyLen > 0) - { - // Set key material and cipherAlg to Asic - AsicAddSharedKeyEntry(pAd, BSS0, idx, CipherAlg, Key, NULL, NULL); - - if (idx == pAd->StaCfg.DefaultKeyId) - { - // Update WCID attribute table and IVEIV table for this group key table - RTMPAddWcidAttributeEntry(pAd, BSS0, idx, CipherAlg, NULL); - } - } - - - } - } - // If WPANone is enabled, add key material and cipherAlg into Asic - // Fill in Shared Key Table(offset: 0x6c00) and Shared Key Mode(offset: 0x7000) - else if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) - { - pAd->StaCfg.DefaultKeyId = 0; // always be zero - - NdisZeroMemory(&pAd->SharedKey[BSS0][0], sizeof(CIPHER_KEY)); - pAd->SharedKey[BSS0][0].KeyLen = LEN_TKIP_EK; - NdisMoveMemory(pAd->SharedKey[BSS0][0].Key, pAd->StaCfg.PMK, LEN_TKIP_EK); - - if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled) - { - NdisMoveMemory(pAd->SharedKey[BSS0][0].RxMic, &pAd->StaCfg.PMK[16], LEN_TKIP_RXMICK); - NdisMoveMemory(pAd->SharedKey[BSS0][0].TxMic, &pAd->StaCfg.PMK[16], LEN_TKIP_TXMICK); - } - - // Decide its ChiperAlg - if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled) - pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_TKIP; - else if (pAd->StaCfg.PairCipher == Ndis802_11Encryption3Enabled) - pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_AES; - else - { - DBGPRINT(RT_DEBUG_TRACE, ("Unknow Cipher (=%d), set Cipher to AES\n", pAd->StaCfg.PairCipher)); - pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_AES; - } - - // Set key material and cipherAlg to Asic - AsicAddSharedKeyEntry(pAd, - BSS0, - 0, - pAd->SharedKey[BSS0][0].CipherAlg, - pAd->SharedKey[BSS0][0].Key, - pAd->SharedKey[BSS0][0].TxMic, - pAd->SharedKey[BSS0][0].RxMic); - - // Update WCID attribute table and IVEIV table for this group key table - RTMPAddWcidAttributeEntry(pAd, BSS0, 0, pAd->SharedKey[BSS0][0].CipherAlg, NULL); - - } - - } - else // BSS_INFRA - { - // Check the new SSID with last SSID - while (Cancelled == TRUE) - { - if (pAd->CommonCfg.LastSsidLen == pAd->CommonCfg.SsidLen) - { - if (RTMPCompareMemory(pAd->CommonCfg.LastSsid, pAd->CommonCfg.Ssid, pAd->CommonCfg.LastSsidLen) == 0) - { - // Link to the old one no linkdown is required. - break; - } - } - // Send link down event before set to link up - pAd->IndicateMediaState = NdisMediaStateDisconnected; - RTMP_IndicateMediaState(pAd); - pAd->ExtraInfo = GENERAL_LINK_DOWN; - DBGPRINT(RT_DEBUG_TRACE, ("NDIS_STATUS_MEDIA_DISCONNECT Event AA!\n")); - break; - } - - // - // On WPA mode, Remove All Keys if not connect to the last BSSID - // Key will be set after 4-way handshake. - // - if ((pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA)) - { - ULONG IV; - - // Remove all WPA keys - RTMPWPARemoveAllKeys(pAd); - pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; - pAd->StaCfg.PrivacyFilter = Ndis802_11PrivFilter8021xWEP; - - // Fixed connection failed with Range Maximizer - 515 AP (Marvell Chip) when security is WPAPSK/TKIP - // If IV related values are too large in GroupMsg2, AP would ignore this message. - IV = 0; - IV |= (pAd->StaCfg.DefaultKeyId << 30); - AsicUpdateWCIDIVEIV(pAd, BSSID_WCID, IV, 0); - } - // NOTE: - // the decision of using "short slot time" or not may change dynamically due to - // new STA association to the AP. so we have to decide that upon parsing BEACON, not here - - // NOTE: - // the decision to use "RTC/CTS" or "CTS-to-self" protection or not may change dynamically - // due to new STA association to the AP. so we have to decide that upon parsing BEACON, not here - - ComposePsPoll(pAd); - ComposeNullFrame(pAd); - - AsicEnableBssSync(pAd); - - // Add BSSID to WCID search table - AsicUpdateRxWCIDTable(pAd, BSSID_WCID, pAd->CommonCfg.Bssid); - - NdisAcquireSpinLock(&pAd->MacTabLock); - // add this BSSID entry into HASH table - { - UCHAR HashIdx; - - //pEntry = &pAd->MacTab.Content[BSSID_WCID]; - HashIdx = MAC_ADDR_HASH_INDEX(pAd->CommonCfg.Bssid); - if (pAd->MacTab.Hash[HashIdx] == NULL) - { - pAd->MacTab.Hash[HashIdx] = pEntry; - } - else - { - pCurrEntry = pAd->MacTab.Hash[HashIdx]; - while (pCurrEntry->pNext != NULL) - pCurrEntry = pCurrEntry->pNext; - pCurrEntry->pNext = pEntry; - } - } - NdisReleaseSpinLock(&pAd->MacTabLock); - - - // If WEP is enabled, add paiewise and shared key -#ifdef WPA_SUPPLICANT_SUPPORT - if (((pAd->StaCfg.WpaSupplicantUP)&& - (pAd->StaCfg.WepStatus == Ndis802_11WEPEnabled)&& - (pAd->StaCfg.PortSecured == WPA_802_1X_PORT_SECURED)) || - ((pAd->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_DISABLE)&& - (pAd->StaCfg.WepStatus == Ndis802_11WEPEnabled))) -#else - if (pAd->StaCfg.WepStatus == Ndis802_11WEPEnabled) -#endif // WPA_SUPPLICANT_SUPPORT // - { - PUCHAR Key; - UCHAR CipherAlg; - - for (idx=0; idx < SHARE_KEY_NUM; idx++) - { - CipherAlg = pAd->SharedKey[BSS0][idx].CipherAlg; - Key = pAd->SharedKey[BSS0][idx].Key; - - if (pAd->SharedKey[BSS0][idx].KeyLen > 0) - { - // Set key material and cipherAlg to Asic - AsicAddSharedKeyEntry(pAd, BSS0, idx, CipherAlg, Key, NULL, NULL); - - if (idx == pAd->StaCfg.DefaultKeyId) - { - // Assign group key info - RTMPAddWcidAttributeEntry(pAd, BSS0, idx, CipherAlg, NULL); - - // Assign pairwise key info - RTMPAddWcidAttributeEntry(pAd, BSS0, idx, CipherAlg, pEntry); - } - } - } - } - - // only INFRASTRUCTURE mode need to indicate connectivity immediately; ADHOC mode - // should wait until at least 2 active nodes in this BSSID. - OPSTATUS_SET_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED); - - // For GUI ++ - if (pAd->StaCfg.AuthMode < Ndis802_11AuthModeWPA) - { - pAd->IndicateMediaState = NdisMediaStateConnected; - pAd->ExtraInfo = GENERAL_LINK_UP; - RTMP_IndicateMediaState(pAd); - } - // -- - - // Add BSSID in my MAC Table. - NdisAcquireSpinLock(&pAd->MacTabLock); - RTMPMoveMemory(pAd->MacTab.Content[BSSID_WCID].Addr, pAd->CommonCfg.Bssid, MAC_ADDR_LEN); - pAd->MacTab.Content[BSSID_WCID].Aid = BSSID_WCID; - pAd->MacTab.Content[BSSID_WCID].pAd = pAd; - pAd->MacTab.Content[BSSID_WCID].ValidAsCLI = TRUE; //Although this is bssid..still set ValidAsCl - pAd->MacTab.Size = 1; // infra mode always set MACtab size =1. - pAd->MacTab.Content[BSSID_WCID].Sst = SST_ASSOC; - pAd->MacTab.Content[BSSID_WCID].AuthState = SST_ASSOC; - pAd->MacTab.Content[BSSID_WCID].WepStatus = pAd->StaCfg.WepStatus; - NdisReleaseSpinLock(&pAd->MacTabLock); - - DBGPRINT(RT_DEBUG_TRACE, ("!!! LINK UP !!! ClientStatusFlags=%lx)\n", - pAd->MacTab.Content[BSSID_WCID].ClientStatusFlags)); - - MlmeUpdateTxRates(pAd, TRUE, BSS0); -#ifdef DOT11_N_SUPPORT - MlmeUpdateHtTxRates(pAd, BSS0); - DBGPRINT(RT_DEBUG_TRACE, ("!!! LINK UP !! (StaActive.bHtEnable =%d, )\n", pAd->StaActive.SupportedPhyInfo.bHtEnable)); -#endif // DOT11_N_SUPPORT // - - // - // Report Adjacent AP report. - // -#ifdef LEAP_SUPPORT - CCXAdjacentAPReport(pAd); -#endif // LEAP_SUPPORT // - - if (pAd->CommonCfg.bAggregationCapable) - { - if ((pAd->CommonCfg.bPiggyBackCapable) && (pAd->MlmeAux.APRalinkIe & 0x00000003) == 3) - { - - OPSTATUS_SET_FLAG(pAd, fOP_STATUS_PIGGYBACK_INUSED); - OPSTATUS_SET_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED); - RTMPSetPiggyBack(pAd, TRUE); - DBGPRINT(RT_DEBUG_TRACE, ("Turn on Piggy-Back\n")); - } - else if (pAd->MlmeAux.APRalinkIe & 0x00000001) - { - OPSTATUS_SET_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED); - } - } - - if (pAd->MlmeAux.APRalinkIe != 0x0) - { -#ifdef DOT11_N_SUPPORT - if (CLIENT_STATUS_TEST_FLAG(&pAd->MacTab.Content[BSSID_WCID], fCLIENT_STATUS_RDG_CAPABLE)) - { - AsicEnableRDG(pAd); - } -#endif // DOT11_N_SUPPORT // - OPSTATUS_SET_FLAG(pAd, fCLIENT_STATUS_RALINK_CHIPSET); - CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[BSSID_WCID], fCLIENT_STATUS_RALINK_CHIPSET); - } - else - { - OPSTATUS_CLEAR_FLAG(pAd, fCLIENT_STATUS_RALINK_CHIPSET); - CLIENT_STATUS_CLEAR_FLAG(&pAd->MacTab.Content[BSSID_WCID], fCLIENT_STATUS_RALINK_CHIPSET); - } - } - -#ifdef DOT11_N_SUPPORT - DBGPRINT(RT_DEBUG_TRACE, ("NDIS_STATUS_MEDIA_CONNECT Event B!.BACapability = %x. ClientStatusFlags = %lx\n", pAd->CommonCfg.BACapability.word, pAd->MacTab.Content[BSSID_WCID].ClientStatusFlags)); -#endif // DOT11_N_SUPPORT // - - // Set LED - RTMPSetLED(pAd, LED_LINK_UP); - - pAd->Mlme.PeriodicRound = 0; - pAd->Mlme.OneSecPeriodicRound = 0; - pAd->bConfigChanged = FALSE; // Reset config flag - pAd->ExtraInfo = GENERAL_LINK_UP; // Update extra information to link is up - - // Set asic auto fall back - { - PUCHAR pTable; - UCHAR TableSize = 0; - - MlmeSelectTxRateTable(pAd, &pAd->MacTab.Content[BSSID_WCID], &pTable, &TableSize, &pAd->CommonCfg.TxRateIndex); - AsicUpdateAutoFallBackTable(pAd, pTable); - } - - NdisAcquireSpinLock(&pAd->MacTabLock); - pEntry->HTPhyMode.word = pAd->StaCfg.HTPhyMode.word; - pEntry->MaxHTPhyMode.word = pAd->StaCfg.HTPhyMode.word; - if (pAd->StaCfg.bAutoTxRateSwitch == FALSE) - { - pEntry->bAutoTxRateSwitch = FALSE; -#ifdef DOT11_N_SUPPORT - if (pEntry->HTPhyMode.field.MCS == 32) - pEntry->HTPhyMode.field.ShortGI = GI_800; - - if ((pEntry->HTPhyMode.field.MCS > MCS_7) || (pEntry->HTPhyMode.field.MCS == 32)) - pEntry->HTPhyMode.field.STBC = STBC_NONE; -#endif // DOT11_N_SUPPORT // - // If the legacy mode is set, overwrite the transmit setting of this entry. - if (pEntry->HTPhyMode.field.MODE <= MODE_OFDM) - RTMPUpdateLegacyTxSetting((UCHAR)pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode, pEntry); - } - else - pEntry->bAutoTxRateSwitch = TRUE; - NdisReleaseSpinLock(&pAd->MacTabLock); - - // Let Link Status Page display first initial rate. - pAd->LastTxRate = (USHORT)(pEntry->HTPhyMode.word); - // Select DAC according to HT or Legacy - if (pAd->StaActive.SupportedPhyInfo.MCSSet[0] != 0x00) - { - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R1, &Value); - Value &= (~0x18); - if (pAd->Antenna.field.TxPath == 2) - { - Value |= 0x10; - } - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R1, Value); - } - else - { - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R1, &Value); - Value &= (~0x18); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R1, Value); - } - -#ifdef DOT11_N_SUPPORT - if (pAd->StaActive.SupportedPhyInfo.bHtEnable == FALSE) - { - } - else if (pEntry->MaxRAmpduFactor == 0) - { - // If HT AP doesn't support MaxRAmpduFactor = 1, we need to set max PSDU to 0. - // Because our Init value is 1 at MACRegTable. - RTMP_IO_WRITE32(pAd, MAX_LEN_CFG, 0x0fff); - } -#endif // DOT11_N_SUPPORT // - - // Patch for Marvel AP to gain high throughput - // Need to set as following, - // 1. Set txop in register-EDCA_AC0_CFG as 0x60 - // 2. Set EnTXWriteBackDDONE in register-WPDMA_GLO_CFG as zero - // 3. PBF_MAX_PCNT as 0x1F3FBF9F - // 4. kick per two packets when dequeue - // - // Txop can only be modified when RDG is off, WMM is disable and TxBurst is enable - // - // if 1. Legacy AP WMM on, or 2. 11n AP, AMPDU disable. Force turn off burst no matter what bEnableTxBurst is. -#ifdef DOT11_N_SUPPORT - if (((pAd->StaActive.SupportedPhyInfo.bHtEnable == FALSE) && (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED))) - || ((pAd->StaActive.SupportedPhyInfo.bHtEnable == TRUE) && (pAd->CommonCfg.BACapability.field.Policy == BA_NOTUSE))) - { - RTMP_IO_READ32(pAd, EDCA_AC0_CFG, &Data); - Data &= 0xFFFFFF00; - RTMP_IO_WRITE32(pAd, EDCA_AC0_CFG, Data); - - RTMP_IO_WRITE32(pAd, PBF_MAX_PCNT, 0x1F3F7F9F); - DBGPRINT(RT_DEBUG_TRACE, ("Txburst 1\n")); - } - else -#endif // DOT11_N_SUPPORT // - if (pAd->CommonCfg.bEnableTxBurst) - { - RTMP_IO_READ32(pAd, EDCA_AC0_CFG, &Data); - Data &= 0xFFFFFF00; - Data |= 0x60; - RTMP_IO_WRITE32(pAd, EDCA_AC0_CFG, Data); - pAd->CommonCfg.IOTestParm.bNowAtherosBurstOn = TRUE; - - RTMP_IO_WRITE32(pAd, PBF_MAX_PCNT, 0x1F3FBF9F); - DBGPRINT(RT_DEBUG_TRACE, ("Txburst 2\n")); - } - else - { - RTMP_IO_READ32(pAd, EDCA_AC0_CFG, &Data); - Data &= 0xFFFFFF00; - RTMP_IO_WRITE32(pAd, EDCA_AC0_CFG, Data); - - RTMP_IO_WRITE32(pAd, PBF_MAX_PCNT, 0x1F3F7F9F); - DBGPRINT(RT_DEBUG_TRACE, ("Txburst 3\n")); - } - -#ifdef DOT11_N_SUPPORT - // Re-check to turn on TX burst or not. - if ((pAd->CommonCfg.IOTestParm.bLastAtheros == TRUE) && ((STA_WEP_ON(pAd))||(STA_TKIP_ON(pAd)))) - { - pAd->CommonCfg.IOTestParm.bNextDisableRxBA = TRUE; - if (pAd->CommonCfg.bEnableTxBurst) - { - UINT32 MACValue = 0; - // Force disable TXOP value in this case. The same action in MLMEUpdateProtect too. - // I didn't change PBF_MAX_PCNT setting. - RTMP_IO_READ32(pAd, EDCA_AC0_CFG, &MACValue); - MACValue &= 0xFFFFFF00; - RTMP_IO_WRITE32(pAd, EDCA_AC0_CFG, MACValue); - pAd->CommonCfg.IOTestParm.bNowAtherosBurstOn = FALSE; - } - } - else - { - pAd->CommonCfg.IOTestParm.bNextDisableRxBA = FALSE; - } -#endif // DOT11_N_SUPPORT // - - pAd->CommonCfg.IOTestParm.bLastAtheros = FALSE; - COPY_MAC_ADDR(pAd->CommonCfg.LastBssid, pAd->CommonCfg.Bssid); - DBGPRINT(RT_DEBUG_TRACE, ("!!!pAd->bNextDisableRxBA= %d \n", pAd->CommonCfg.IOTestParm.bNextDisableRxBA)); - // BSSID add in one MAC entry too. Because in Tx, ASIC need to check Cipher and IV/EIV, BAbitmap - // Pther information in MACTab.Content[BSSID_WCID] is not necessary for driver. - // Note: As STA, The MACTab.Content[BSSID_WCID]. PairwiseKey and Shared Key for BSS0 are the same. - - if (pAd->StaCfg.WepStatus <= Ndis802_11WEPDisabled) - { - pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; - pAd->StaCfg.PrivacyFilter = Ndis802_11PrivFilterAcceptAll; - } - - NdisAcquireSpinLock(&pAd->MacTabLock); - pEntry->PortSecured = pAd->StaCfg.PortSecured; - NdisReleaseSpinLock(&pAd->MacTabLock); - - // - // Patch Atheros AP TX will breakdown issue. - // AP Model: DLink DWL-8200AP - // - if (INFRA_ON(pAd) && OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED) && STA_TKIP_ON(pAd)) - { - RTMP_IO_WRITE32(pAd, RX_PARSER_CFG, 0x01); - } - else - { - RTMP_IO_WRITE32(pAd, RX_PARSER_CFG, 0x00); - } - - RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS); - - -#ifdef DOT11_N_SUPPORT -#ifdef DOT11N_DRAFT3 - if ((pAd->CommonCfg.BACapability.field.b2040CoexistScanSup) && (pAd->CommonCfg.Channel <= 11)) - { - OPSTATUS_SET_FLAG(pAd, fOP_STATUS_SCAN_2040); - BuildEffectedChannelList(pAd); - } -#endif // DOT11N_DRAFT3 // -#endif // DOT11_N_SUPPORT // -} - -/* - ========================================================================== - - Routine Description: - Disconnect current BSSID - - Arguments: - pAd - Pointer to our adapter - IsReqFromAP - Request from AP - - Return Value: - None - - IRQL = DISPATCH_LEVEL - - Note: - We need more information to know it's this requst from AP. - If yes! we need to do extra handling, for example, remove the WPA key. - Otherwise on 4-way handshaking will faied, since the WPA key didn't be - remove while auto reconnect. - Disconnect request from AP, it means we will start afresh 4-way handshaking - on WPA mode. - - ========================================================================== -*/ -VOID LinkDown( - IN PRTMP_ADAPTER pAd, - IN BOOLEAN IsReqFromAP) -{ - UCHAR i, ByteValue = 0; - - // Do nothing if monitor mode is on - if (MONITOR_ON(pAd)) - return; - -#ifdef RALINK_ATE - // Nothing to do in ATE mode. - if (ATE_ON(pAd)) - return; -#endif // RALINK_ATE // - - if (pAd->CommonCfg.bWirelessEvent) - { - RTMPSendWirelessEvent(pAd, IW_STA_LINKDOWN_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); - } - - DBGPRINT(RT_DEBUG_TRACE, ("!!! LINK DOWN !!!\n")); - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED); - - if (ADHOC_ON(pAd)) // Adhoc mode link down - { - DBGPRINT(RT_DEBUG_TRACE, ("!!! LINK DOWN 1!!!\n")); - - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_ADHOC_ON); - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED); - pAd->IndicateMediaState = NdisMediaStateDisconnected; - RTMP_IndicateMediaState(pAd); - pAd->ExtraInfo = GENERAL_LINK_DOWN; - BssTableDeleteEntry(&pAd->ScanTab, pAd->CommonCfg.Bssid, pAd->CommonCfg.Channel); - DBGPRINT(RT_DEBUG_TRACE, ("!!! MacTab.Size=%d !!!\n", pAd->MacTab.Size)); - } - else // Infra structure mode - { - DBGPRINT(RT_DEBUG_TRACE, ("!!! LINK DOWN 2!!!\n")); - -#ifdef QOS_DLS_SUPPORT - // DLS tear down frame must be sent before link down - // send DLS-TEAR_DOWN message - if (pAd->CommonCfg.bDLSCapable) - { - // tear down local dls table entry - for (i=0; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH)) - { - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - RTMPSendDLSTearDownFrame(pAd, pAd->StaCfg.DLSEntry[i].MacAddr); - } - } - - // tear down peer dls table entry - for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH)) - { - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - RTMPSendDLSTearDownFrame(pAd, pAd->StaCfg.DLSEntry[i].MacAddr); - } - } - } -#endif // QOS_DLS_SUPPORT // - - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_INFRA_ON); - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED); - - // Saved last SSID for linkup comparison - pAd->CommonCfg.LastSsidLen = pAd->CommonCfg.SsidLen; - NdisMoveMemory(pAd->CommonCfg.LastSsid, pAd->CommonCfg.Ssid, pAd->CommonCfg.LastSsidLen); - COPY_MAC_ADDR(pAd->CommonCfg.LastBssid, pAd->CommonCfg.Bssid); - if (pAd->MlmeAux.CurrReqIsFromNdis == TRUE) - { - pAd->IndicateMediaState = NdisMediaStateDisconnected; - RTMP_IndicateMediaState(pAd); - pAd->ExtraInfo = GENERAL_LINK_DOWN; - DBGPRINT(RT_DEBUG_TRACE, ("NDIS_STATUS_MEDIA_DISCONNECT Event A!\n")); - pAd->MlmeAux.CurrReqIsFromNdis = FALSE; - } - else - { - // - // If disassociation request is from NDIS, then we don't need to delete BSSID from entry. - // Otherwise lost beacon or receive De-Authentication from AP, - // then we should delete BSSID from BssTable. - // If we don't delete from entry, roaming will fail. - // - BssTableDeleteEntry(&pAd->ScanTab, pAd->CommonCfg.Bssid, pAd->CommonCfg.Channel); - } - - // restore back to - - // 1. long slot (20 us) or short slot (9 us) time - // 2. turn on/off RTS/CTS and/or CTS-to-self protection - // 3. short preamble - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_BG_PROTECTION_INUSED); - - if (pAd->StaCfg.CCXAdjacentAPReportFlag == TRUE) - { - // - // Record current AP's information. - // for later used reporting Adjacent AP report. - // - pAd->StaCfg.CCXAdjacentAPChannel = pAd->CommonCfg.Channel; - pAd->StaCfg.CCXAdjacentAPSsidLen = pAd->CommonCfg.SsidLen; - NdisMoveMemory(pAd->StaCfg.CCXAdjacentAPSsid, pAd->CommonCfg.Ssid, pAd->StaCfg.CCXAdjacentAPSsidLen); - COPY_MAC_ADDR(pAd->StaCfg.CCXAdjacentAPBssid, pAd->CommonCfg.Bssid); - } - -#ifdef EXT_BUILD_CHANNEL_LIST - // Country IE of the AP will be evaluated and will be used. - if (pAd->StaCfg.IEEE80211dClientMode != Rt802_11_D_None) - { - NdisMoveMemory(&pAd->CommonCfg.CountryCode[0], &pAd->StaCfg.StaOriCountryCode[0], 2); - pAd->CommonCfg.Geography = pAd->StaCfg.StaOriGeography; - BuildChannelListEx(pAd); - } -#endif // EXT_BUILD_CHANNEL_LIST // - - } - - for (i=1; iMacTab.Content[i].ValidAsCLI == TRUE) - MacTableDeleteEntry(pAd, pAd->MacTab.Content[i].Aid, pAd->MacTab.Content[i].Addr); - } - - pAd->StaCfg.CCXQosECWMin = 4; - pAd->StaCfg.CCXQosECWMax = 10; - - AsicSetSlotTime(pAd, TRUE); //FALSE); - AsicSetEdcaParm(pAd, NULL); - - // Set LED - RTMPSetLED(pAd, LED_LINK_DOWN); - pAd->LedIndicatorStregth = 0xF0; - RTMPSetSignalLED(pAd, -100); // Force signal strength Led to be turned off, firmware is not done it. - - AsicDisableSync(pAd); - - pAd->Mlme.PeriodicRound = 0; - pAd->Mlme.OneSecPeriodicRound = 0; - - if (pAd->StaCfg.BssType == BSS_INFRA) - { - // Remove StaCfg Information after link down - NdisZeroMemory(pAd->CommonCfg.Bssid, MAC_ADDR_LEN); - NdisZeroMemory(pAd->CommonCfg.Ssid, MAX_LEN_OF_SSID); - pAd->CommonCfg.SsidLen = 0; - } -#ifdef DOT11_N_SUPPORT - NdisZeroMemory(&pAd->MlmeAux.HtCapability, sizeof(HT_CAPABILITY_IE)); - NdisZeroMemory(&pAd->MlmeAux.AddHtInfo, sizeof(ADD_HT_INFO_IE)); - pAd->MlmeAux.HtCapabilityLen = 0; - pAd->MlmeAux.NewExtChannelOffset = 0xff; -#endif // DOT11_N_SUPPORT // - - // Reset WPA-PSK state. Only reset when supplicant enabled - if (pAd->StaCfg.WpaState != SS_NOTUSE) - { - pAd->StaCfg.WpaState = SS_START; - // Clear Replay counter - NdisZeroMemory(pAd->StaCfg.ReplayCounter, 8); - -#ifdef QOS_DLS_SUPPORT - if (pAd->CommonCfg.bDLSCapable) - NdisZeroMemory(pAd->StaCfg.DlsReplayCounter, 8); -#endif // QOS_DLS_SUPPORT // - } - - - // - // if link down come from AP, we need to remove all WPA keys on WPA mode. - // otherwise will cause 4-way handshaking failed, since the WPA key not empty. - // - if ((IsReqFromAP) && (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA)) - { - // Remove all WPA keys - RTMPWPARemoveAllKeys(pAd); - } - - // 802.1x port control -#ifdef WPA_SUPPLICANT_SUPPORT - // Prevent clear PortSecured here with static WEP - // NetworkManger set security policy first then set SSID to connect AP. - if (pAd->StaCfg.WpaSupplicantUP && - (pAd->StaCfg.WepStatus == Ndis802_11WEPEnabled) && - (pAd->StaCfg.IEEE8021X == FALSE)) - { - pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; - } - else -#endif // WPA_SUPPLICANT_SUPPORT // - { - pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; - pAd->StaCfg.PrivacyFilter = Ndis802_11PrivFilter8021xWEP; - } - - NdisAcquireSpinLock(&pAd->MacTabLock); - pAd->MacTab.Content[BSSID_WCID].PortSecured = pAd->StaCfg.PortSecured; - NdisReleaseSpinLock(&pAd->MacTabLock); - - pAd->StaCfg.MicErrCnt = 0; - - // Turn off Ckip control flag - pAd->StaCfg.bCkipOn = FALSE; - pAd->StaCfg.CCXEnable = FALSE; - - pAd->IndicateMediaState = NdisMediaStateDisconnected; - // Update extra information to link is up - pAd->ExtraInfo = GENERAL_LINK_DOWN; - - //pAd->StaCfg.AdhocBOnlyJoined = FALSE; - //pAd->StaCfg.AdhocBGJoined = FALSE; - //pAd->StaCfg.Adhoc20NJoined = FALSE; - pAd->StaActive.SupportedPhyInfo.bHtEnable = FALSE; - - // Reset the Current AP's IP address - NdisZeroMemory(pAd->StaCfg.AironetIPAddress, 4); -#ifdef RT2870 - pAd->bUsbTxBulkAggre = FALSE; -#endif // RT2870 // - - // Clean association information - NdisZeroMemory(&pAd->StaCfg.AssocInfo, sizeof(NDIS_802_11_ASSOCIATION_INFORMATION)); - pAd->StaCfg.AssocInfo.Length = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION); - pAd->StaCfg.ReqVarIELen = 0; - pAd->StaCfg.ResVarIELen = 0; - - // - // Reset RSSI value after link down - // - pAd->StaCfg.RssiSample.AvgRssi0 = 0; - pAd->StaCfg.RssiSample.AvgRssi0X8 = 0; - pAd->StaCfg.RssiSample.AvgRssi1 = 0; - pAd->StaCfg.RssiSample.AvgRssi1X8 = 0; - pAd->StaCfg.RssiSample.AvgRssi2 = 0; - pAd->StaCfg.RssiSample.AvgRssi2X8 = 0; - - // Restore MlmeRate - pAd->CommonCfg.MlmeRate = pAd->CommonCfg.BasicMlmeRate; - pAd->CommonCfg.RtsRate = pAd->CommonCfg.BasicMlmeRate; - -#ifdef DOT11_N_SUPPORT - // - // After Link down, reset piggy-back setting in ASIC. Disable RDG. - // - if (pAd->CommonCfg.BBPCurrentBW == BW_40) - { - pAd->CommonCfg.BBPCurrentBW = BW_20; - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &ByteValue); - ByteValue &= (~0x18); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, ByteValue); - } -#endif // DOT11_N_SUPPORT // - // Reset DAC - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R1, &ByteValue); - ByteValue &= (~0x18); - if (pAd->Antenna.field.TxPath == 2) - { - ByteValue |= 0x10; - } - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R1, ByteValue); - - RTMPSetPiggyBack(pAd,FALSE); - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_PIGGYBACK_INUSED); - -#ifdef DOT11_N_SUPPORT - pAd->CommonCfg.BACapability.word = pAd->CommonCfg.REGBACapability.word; -#endif // DOT11_N_SUPPORT // - - // Restore all settings in the following. - AsicUpdateProtect(pAd, 0, (ALLN_SETPROTECT|CCKSETPROTECT|OFDMSETPROTECT), TRUE, FALSE); - AsicDisableRDG(pAd); - pAd->CommonCfg.IOTestParm.bCurrentAtheros = FALSE; - pAd->CommonCfg.IOTestParm.bNowAtherosBurstOn = FALSE; - -#ifdef DOT11_N_SUPPORT -#ifdef DOT11N_DRAFT3 - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SCAN_2040); - pAd->CommonCfg.BSSCoexist2040.word = 0; - TriEventInit(pAd); - for (i = 0; i < (pAd->ChannelListNum - 1); i++) - { - pAd->ChannelList[i].bEffectedChannel = FALSE; - } -#endif // DOT11N_DRAFT3 // -#endif // DOT11_N_SUPPORT // - - RTMP_IO_WRITE32(pAd, MAX_LEN_CFG, 0x1fff); - RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS); - -#ifdef WPA_SUPPLICANT_SUPPORT -#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT - if (pAd->StaCfg.WpaSupplicantUP) { - union iwreq_data wrqu; - //send disassociate event to wpa_supplicant - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.flags = RT_DISASSOC_EVENT_FLAG; - wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); - } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // -#endif // WPA_SUPPLICANT_SUPPORT // - -#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT - { - union iwreq_data wrqu; - memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN); - wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); - } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== -*/ -VOID IterateOnBssTab( - IN PRTMP_ADAPTER pAd) -{ - MLME_START_REQ_STRUCT StartReq; - MLME_JOIN_REQ_STRUCT JoinReq; - ULONG BssIdx; - - // Change the wepstatus to original wepstatus - pAd->StaCfg.WepStatus = pAd->StaCfg.OrigWepStatus; - pAd->StaCfg.PairCipher = pAd->StaCfg.OrigWepStatus; - pAd->StaCfg.GroupCipher = pAd->StaCfg.OrigWepStatus; - - BssIdx = pAd->MlmeAux.BssIdx; - if (BssIdx < pAd->MlmeAux.SsidBssTab.BssNr) - { - // Check cipher suite, AP must have more secured cipher than station setting - // Set the Pairwise and Group cipher to match the intended AP setting - // We can only connect to AP with less secured cipher setting - if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) - { - pAd->StaCfg.GroupCipher = pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA.GroupCipher; - - if (pAd->StaCfg.WepStatus == pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA.PairCipher) - pAd->StaCfg.PairCipher = pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA.PairCipher; - else if (pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA.PairCipherAux != Ndis802_11WEPDisabled) - pAd->StaCfg.PairCipher = pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA.PairCipherAux; - else // There is no PairCipher Aux, downgrade our capability to TKIP - pAd->StaCfg.PairCipher = Ndis802_11Encryption2Enabled; - } - else if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)) - { - pAd->StaCfg.GroupCipher = pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA2.GroupCipher; - - if (pAd->StaCfg.WepStatus == pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA2.PairCipher) - pAd->StaCfg.PairCipher = pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA2.PairCipher; - else if (pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA2.PairCipherAux != Ndis802_11WEPDisabled) - pAd->StaCfg.PairCipher = pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA2.PairCipherAux; - else // There is no PairCipher Aux, downgrade our capability to TKIP - pAd->StaCfg.PairCipher = Ndis802_11Encryption2Enabled; - - // RSN capability - pAd->StaCfg.RsnCapability = pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA2.RsnCapability; - } - - // Set Mix cipher flag - pAd->StaCfg.bMixCipher = (pAd->StaCfg.PairCipher == pAd->StaCfg.GroupCipher) ? FALSE : TRUE; - if (pAd->StaCfg.bMixCipher == TRUE) - { - // If mix cipher, re-build RSNIE - RTMPMakeRSNIE(pAd, pAd->StaCfg.AuthMode, pAd->StaCfg.WepStatus, 0); - } - - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - iterate BSS %ld of %d\n", BssIdx, pAd->MlmeAux.SsidBssTab.BssNr)); - JoinParmFill(pAd, &JoinReq, BssIdx); - MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_JOIN_REQ, sizeof(MLME_JOIN_REQ_STRUCT), - &JoinReq); - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_JOIN; - } - else if (pAd->StaCfg.BssType == BSS_ADHOC) - { - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - All BSS fail; start a new ADHOC (Ssid=%s)...\n",pAd->MlmeAux.Ssid)); - StartParmFill(pAd, &StartReq, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen); - MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_START_REQ, sizeof(MLME_START_REQ_STRUCT), &StartReq); - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_START; - } - else // no more BSS - { - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - All roaming failed, stay @ ch #%d\n", pAd->CommonCfg.Channel)); - AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); - AsicLockChannel(pAd, pAd->CommonCfg.Channel); - pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; - } -} - -// for re-association only -// IRQL = DISPATCH_LEVEL -VOID IterateOnBssTab2( - IN PRTMP_ADAPTER pAd) -{ - MLME_REASSOC_REQ_STRUCT ReassocReq; - ULONG BssIdx; - BSS_ENTRY *pBss; - - BssIdx = pAd->MlmeAux.RoamIdx; - pBss = &pAd->MlmeAux.RoamTab.BssEntry[BssIdx]; - - if (BssIdx < pAd->MlmeAux.RoamTab.BssNr) - { - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - iterate BSS %ld of %d\n", BssIdx, pAd->MlmeAux.RoamTab.BssNr)); - - AsicSwitchChannel(pAd, pBss->Channel, FALSE); - AsicLockChannel(pAd, pBss->Channel); - - // reassociate message has the same structure as associate message - AssocParmFill(pAd, &ReassocReq, pBss->Bssid, pBss->CapabilityInfo, - ASSOC_TIMEOUT, pAd->StaCfg.DefaultListenCount); - MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_REASSOC_REQ, - sizeof(MLME_REASSOC_REQ_STRUCT), &ReassocReq); - - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_REASSOC; - } - else // no more BSS - { - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - All fast roaming failed, back to ch #%d\n",pAd->CommonCfg.Channel)); - AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); - AsicLockChannel(pAd, pAd->CommonCfg.Channel); - pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; - } -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== -*/ -VOID JoinParmFill( - IN PRTMP_ADAPTER pAd, - IN OUT MLME_JOIN_REQ_STRUCT *JoinReq, - IN ULONG BssIdx) -{ - JoinReq->BssIdx = BssIdx; -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== -*/ -VOID ScanParmFill( - IN PRTMP_ADAPTER pAd, - IN OUT MLME_SCAN_REQ_STRUCT *ScanReq, - IN CHAR Ssid[], - IN UCHAR SsidLen, - IN UCHAR BssType, - IN UCHAR ScanType) -{ - NdisZeroMemory(ScanReq->Ssid, MAX_LEN_OF_SSID); - ScanReq->SsidLen = SsidLen; - NdisMoveMemory(ScanReq->Ssid, Ssid, SsidLen); - ScanReq->BssType = BssType; - ScanReq->ScanType = ScanType; -} - -#ifdef QOS_DLS_SUPPORT -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== -*/ -VOID DlsParmFill( - IN PRTMP_ADAPTER pAd, - IN OUT MLME_DLS_REQ_STRUCT *pDlsReq, - IN PRT_802_11_DLS pDls, - IN USHORT reason) -{ - pDlsReq->pDLS = pDls; - pDlsReq->Reason = reason; -} -#endif // QOS_DLS_SUPPORT // - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== -*/ -VOID StartParmFill( - IN PRTMP_ADAPTER pAd, - IN OUT MLME_START_REQ_STRUCT *StartReq, - IN CHAR Ssid[], - IN UCHAR SsidLen) -{ - ASSERT(SsidLen <= MAX_LEN_OF_SSID); - NdisMoveMemory(StartReq->Ssid, Ssid, SsidLen); - StartReq->SsidLen = SsidLen; -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== -*/ -VOID AuthParmFill( - IN PRTMP_ADAPTER pAd, - IN OUT MLME_AUTH_REQ_STRUCT *AuthReq, - IN PUCHAR pAddr, - IN USHORT Alg) -{ - COPY_MAC_ADDR(AuthReq->Addr, pAddr); - AuthReq->Alg = Alg; - AuthReq->Timeout = AUTH_TIMEOUT; -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ - - -#ifdef RT2870 - -VOID MlmeCntlConfirm( - IN PRTMP_ADAPTER pAd, - IN ULONG MsgType, - IN USHORT Msg) -{ - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MsgType, sizeof(USHORT), &Msg); -} - -VOID ComposePsPoll( - IN PRTMP_ADAPTER pAd) -{ - PTXINFO_STRUC pTxInfo; - PTXWI_STRUC pTxWI; - - DBGPRINT(RT_DEBUG_TRACE, ("ComposePsPoll\n")); - NdisZeroMemory(&pAd->PsPollFrame, sizeof(PSPOLL_FRAME)); - - pAd->PsPollFrame.FC.PwrMgmt = 0; - pAd->PsPollFrame.FC.Type = BTYPE_CNTL; - pAd->PsPollFrame.FC.SubType = SUBTYPE_PS_POLL; - pAd->PsPollFrame.Aid = pAd->StaActive.Aid | 0xC000; - COPY_MAC_ADDR(pAd->PsPollFrame.Bssid, pAd->CommonCfg.Bssid); - COPY_MAC_ADDR(pAd->PsPollFrame.Ta, pAd->CurrentAddress); - - RTMPZeroMemory(&pAd->PsPollContext.TransferBuffer->field.WirelessPacket[0], 100); - pTxInfo = (PTXINFO_STRUC)&pAd->PsPollContext.TransferBuffer->field.WirelessPacket[0]; - RTMPWriteTxInfo(pAd, pTxInfo, (USHORT)(sizeof(PSPOLL_FRAME)+TXWI_SIZE), TRUE, EpToQueue[MGMTPIPEIDX], FALSE, FALSE); - pTxWI = (PTXWI_STRUC)&pAd->PsPollContext.TransferBuffer->field.WirelessPacket[TXINFO_SIZE]; - RTMPWriteTxWI(pAd, pTxWI, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, 0, BSSID_WCID, (sizeof(PSPOLL_FRAME)), - 0, 0, (UCHAR)pAd->CommonCfg.MlmeTransmit.field.MCS, IFS_BACKOFF, FALSE, &pAd->CommonCfg.MlmeTransmit); - RTMPMoveMemory(&pAd->PsPollContext.TransferBuffer->field.WirelessPacket[TXWI_SIZE+TXINFO_SIZE], &pAd->PsPollFrame, sizeof(PSPOLL_FRAME)); - // Append 4 extra zero bytes. - pAd->PsPollContext.BulkOutSize = TXINFO_SIZE + TXWI_SIZE + sizeof(PSPOLL_FRAME) + 4; -} - -// IRQL = DISPATCH_LEVEL -VOID ComposeNullFrame( - IN PRTMP_ADAPTER pAd) -{ - PTXINFO_STRUC pTxInfo; - PTXWI_STRUC pTxWI; - - NdisZeroMemory(&pAd->NullFrame, sizeof(HEADER_802_11)); - pAd->NullFrame.FC.Type = BTYPE_DATA; - pAd->NullFrame.FC.SubType = SUBTYPE_NULL_FUNC; - pAd->NullFrame.FC.ToDs = 1; - COPY_MAC_ADDR(pAd->NullFrame.Addr1, pAd->CommonCfg.Bssid); - COPY_MAC_ADDR(pAd->NullFrame.Addr2, pAd->CurrentAddress); - COPY_MAC_ADDR(pAd->NullFrame.Addr3, pAd->CommonCfg.Bssid); - RTMPZeroMemory(&pAd->NullContext.TransferBuffer->field.WirelessPacket[0], 100); - pTxInfo = (PTXINFO_STRUC)&pAd->NullContext.TransferBuffer->field.WirelessPacket[0]; - RTMPWriteTxInfo(pAd, pTxInfo, (USHORT)(sizeof(HEADER_802_11)+TXWI_SIZE), TRUE, EpToQueue[MGMTPIPEIDX], FALSE, FALSE); - pTxWI = (PTXWI_STRUC)&pAd->NullContext.TransferBuffer->field.WirelessPacket[TXINFO_SIZE]; - RTMPWriteTxWI(pAd, pTxWI, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, 0, BSSID_WCID, (sizeof(HEADER_802_11)), - 0, 0, (UCHAR)pAd->CommonCfg.MlmeTransmit.field.MCS, IFS_BACKOFF, FALSE, &pAd->CommonCfg.MlmeTransmit); - RTMPMoveMemory(&pAd->NullContext.TransferBuffer->field.WirelessPacket[TXWI_SIZE+TXINFO_SIZE], &pAd->NullFrame, sizeof(HEADER_802_11)); - pAd->NullContext.BulkOutSize = TXINFO_SIZE + TXWI_SIZE + sizeof(pAd->NullFrame) + 4; -} -#endif // RT2870 // - - -/* - ========================================================================== - Description: - Pre-build a BEACON frame in the shared memory - - IRQL = PASSIVE_LEVEL - IRQL = DISPATCH_LEVEL - - ========================================================================== -*/ -ULONG MakeIbssBeacon( - IN PRTMP_ADAPTER pAd) -{ - UCHAR DsLen = 1, IbssLen = 2; - UCHAR LocalErpIe[3] = {IE_ERP, 1, 0x04}; - HEADER_802_11 BcnHdr; - USHORT CapabilityInfo; - LARGE_INTEGER FakeTimestamp; - ULONG FrameLen = 0; - PTXWI_STRUC pTxWI = &pAd->BeaconTxWI; - CHAR *pBeaconFrame = pAd->BeaconBuf; - BOOLEAN Privacy; - UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES]; - UCHAR SupRateLen = 0; - UCHAR ExtRate[MAX_LEN_OF_SUPPORTED_RATES]; - UCHAR ExtRateLen = 0; - UCHAR RSNIe = IE_WPA; - - if ((pAd->CommonCfg.PhyMode == PHY_11B) && (pAd->CommonCfg.Channel <= 14)) - { - SupRate[0] = 0x82; // 1 mbps - SupRate[1] = 0x84; // 2 mbps - SupRate[2] = 0x8b; // 5.5 mbps - SupRate[3] = 0x96; // 11 mbps - SupRateLen = 4; - ExtRateLen = 0; - } - else if (pAd->CommonCfg.Channel > 14) - { - SupRate[0] = 0x8C; // 6 mbps, in units of 0.5 Mbps, basic rate - SupRate[1] = 0x12; // 9 mbps, in units of 0.5 Mbps - SupRate[2] = 0x98; // 12 mbps, in units of 0.5 Mbps, basic rate - SupRate[3] = 0x24; // 18 mbps, in units of 0.5 Mbps - SupRate[4] = 0xb0; // 24 mbps, in units of 0.5 Mbps, basic rate - SupRate[5] = 0x48; // 36 mbps, in units of 0.5 Mbps - SupRate[6] = 0x60; // 48 mbps, in units of 0.5 Mbps - SupRate[7] = 0x6c; // 54 mbps, in units of 0.5 Mbps - SupRateLen = 8; - ExtRateLen = 0; - - // - // Also Update MlmeRate & RtsRate for G only & A only - // - pAd->CommonCfg.MlmeRate = RATE_6; - pAd->CommonCfg.RtsRate = RATE_6; - pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM; - pAd->CommonCfg.MlmeTransmit.field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate]; - pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MODE = MODE_OFDM; - pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate]; - } - else - { - SupRate[0] = 0x82; // 1 mbps - SupRate[1] = 0x84; // 2 mbps - SupRate[2] = 0x8b; // 5.5 mbps - SupRate[3] = 0x96; // 11 mbps - SupRateLen = 4; - - ExtRate[0] = 0x0C; // 6 mbps, in units of 0.5 Mbps, - ExtRate[1] = 0x12; // 9 mbps, in units of 0.5 Mbps - ExtRate[2] = 0x18; // 12 mbps, in units of 0.5 Mbps, - ExtRate[3] = 0x24; // 18 mbps, in units of 0.5 Mbps - ExtRate[4] = 0x30; // 24 mbps, in units of 0.5 Mbps, - ExtRate[5] = 0x48; // 36 mbps, in units of 0.5 Mbps - ExtRate[6] = 0x60; // 48 mbps, in units of 0.5 Mbps - ExtRate[7] = 0x6c; // 54 mbps, in units of 0.5 Mbps - ExtRateLen = 8; - } - - pAd->StaActive.SupRateLen = SupRateLen; - NdisMoveMemory(pAd->StaActive.SupRate, SupRate, SupRateLen); - pAd->StaActive.ExtRateLen = ExtRateLen; - NdisMoveMemory(pAd->StaActive.ExtRate, ExtRate, ExtRateLen); - - // compose IBSS beacon frame - MgtMacHeaderInit(pAd, &BcnHdr, SUBTYPE_BEACON, 0, BROADCAST_ADDR, pAd->CommonCfg.Bssid); - Privacy = (pAd->StaCfg.WepStatus == Ndis802_11Encryption1Enabled) || - (pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) || - (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled); - CapabilityInfo = CAP_GENERATE(0, 1, Privacy, (pAd->CommonCfg.TxPreamble == Rt802_11PreambleShort), 0, 0); - - MakeOutgoingFrame(pBeaconFrame, &FrameLen, - sizeof(HEADER_802_11), &BcnHdr, - TIMESTAMP_LEN, &FakeTimestamp, - 2, &pAd->CommonCfg.BeaconPeriod, - 2, &CapabilityInfo, - 1, &SsidIe, - 1, &pAd->CommonCfg.SsidLen, - pAd->CommonCfg.SsidLen, pAd->CommonCfg.Ssid, - 1, &SupRateIe, - 1, &SupRateLen, - SupRateLen, SupRate, - 1, &DsIe, - 1, &DsLen, - 1, &pAd->CommonCfg.Channel, - 1, &IbssIe, - 1, &IbssLen, - 2, &pAd->StaActive.AtimWin, - END_OF_ARGS); - - // add ERP_IE and EXT_RAE IE of in 802.11g - if (ExtRateLen) - { - ULONG tmp; - - MakeOutgoingFrame(pBeaconFrame + FrameLen, &tmp, - 3, LocalErpIe, - 1, &ExtRateIe, - 1, &ExtRateLen, - ExtRateLen, ExtRate, - END_OF_ARGS); - FrameLen += tmp; - } - - // If adhoc secruity is set for WPA-None, append the cipher suite IE - if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) - { - ULONG tmp; - RTMPMakeRSNIE(pAd, pAd->StaCfg.AuthMode, pAd->StaCfg.WepStatus, BSS0); - - MakeOutgoingFrame(pBeaconFrame + FrameLen, &tmp, - 1, &RSNIe, - 1, &pAd->StaCfg.RSNIE_Len, - pAd->StaCfg.RSNIE_Len, pAd->StaCfg.RSN_IE, - END_OF_ARGS); - FrameLen += tmp; - } - -#ifdef DOT11_N_SUPPORT - if ((pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) - { - ULONG TmpLen; - UCHAR HtLen, HtLen1; - -#ifdef RT_BIG_ENDIAN - HT_CAPABILITY_IE HtCapabilityTmp; - ADD_HT_INFO_IE addHTInfoTmp; - USHORT b2lTmp, b2lTmp2; -#endif - - // add HT Capability IE - HtLen = sizeof(pAd->CommonCfg.HtCapability); - HtLen1 = sizeof(pAd->CommonCfg.AddHTInfo); -#ifndef RT_BIG_ENDIAN - MakeOutgoingFrame(pBeaconFrame+FrameLen, &TmpLen, - 1, &HtCapIe, - 1, &HtLen, - HtLen, &pAd->CommonCfg.HtCapability, - 1, &AddHtInfoIe, - 1, &HtLen1, - HtLen1, &pAd->CommonCfg.AddHTInfo, - END_OF_ARGS); -#else - NdisMoveMemory(&HtCapabilityTmp, &pAd->CommonCfg.HtCapability, HtLen); - *(USHORT *)(&HtCapabilityTmp.HtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.HtCapInfo)); - *(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo)); - - NdisMoveMemory(&addHTInfoTmp, &pAd->CommonCfg.AddHTInfo, HtLen1); - *(USHORT *)(&addHTInfoTmp.AddHtInfo2) = SWAP16(*(USHORT *)(&addHTInfoTmp.AddHtInfo2)); - *(USHORT *)(&addHTInfoTmp.AddHtInfo3) = SWAP16(*(USHORT *)(&addHTInfoTmp.AddHtInfo3)); - - MakeOutgoingFrame(pBeaconFrame+FrameLen, &TmpLen, - 1, &HtCapIe, - 1, &HtLen, - HtLen, &HtCapabilityTmp, - 1, &AddHtInfoIe, - 1, &HtLen1, - HtLen1, &addHTInfoTmp, - END_OF_ARGS); -#endif - FrameLen += TmpLen; - } -#endif // DOT11_N_SUPPORT // - - //beacon use reserved WCID 0xff - if (pAd->CommonCfg.Channel > 14) - { - RTMPWriteTxWI(pAd, pTxWI, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, 0, 0xff, FrameLen, - PID_MGMT, PID_BEACON, RATE_1, IFS_HTTXOP, FALSE, &pAd->CommonCfg.MlmeTransmit); - } - else - { - // Set to use 1Mbps for Adhoc beacon. - HTTRANSMIT_SETTING Transmit; - Transmit.word = 0; - RTMPWriteTxWI(pAd, pTxWI, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, 0, 0xff, FrameLen, - PID_MGMT, PID_BEACON, RATE_1, IFS_HTTXOP, FALSE, &Transmit); - } - -#ifdef RT_BIG_ENDIAN - RTMPFrameEndianChange(pAd, pBeaconFrame, DIR_WRITE, FALSE); - RTMPWIEndianChange((PUCHAR)pTxWI, TYPE_TXWI); -#endif - - DBGPRINT(RT_DEBUG_TRACE, ("MakeIbssBeacon (len=%ld), SupRateLen=%d, ExtRateLen=%d, Channel=%d, PhyMode=%d\n", - FrameLen, SupRateLen, ExtRateLen, pAd->CommonCfg.Channel, pAd->CommonCfg.PhyMode)); - return FrameLen; -} - - +#include "../../rt2860/sta/connect.c" diff --git a/drivers/staging/rt2870/sta/dls.c b/drivers/staging/rt2870/sta/dls.c deleted file mode 100644 index 56bfbc33d6f5..000000000000 --- a/drivers/staging/rt2870/sta/dls.c +++ /dev/null @@ -1,2210 +0,0 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - dls.c - - Abstract: - Handle WMM-DLS state machine - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Rory Chen 02-14-2006 - Arvin Tai 06-03-2008 Modified for RT28xx - */ - -#include "../rt_config.h" - -/* - ========================================================================== - Description: - dls state machine init, including state transition and timer init - Parameters: - Sm - pointer to the dls state machine - Note: - The state machine looks like this - - DLS_IDLE - MT2_MLME_DLS_REQUEST MlmeDlsReqAction - MT2_PEER_DLS_REQUEST PeerDlsReqAction - MT2_PEER_DLS_RESPONSE PeerDlsRspAction - MT2_MLME_DLS_TEARDOWN MlmeTearDownAction - MT2_PEER_DLS_TEARDOWN PeerTearDownAction - - IRQL = PASSIVE_LEVEL - - ========================================================================== - */ -void DlsStateMachineInit( - IN PRTMP_ADAPTER pAd, - IN STATE_MACHINE *Sm, - OUT STATE_MACHINE_FUNC Trans[]) -{ - UCHAR i; - - StateMachineInit(Sm, (STATE_MACHINE_FUNC*)Trans, MAX_DLS_STATE, MAX_DLS_MSG, (STATE_MACHINE_FUNC)Drop, DLS_IDLE, DLS_MACHINE_BASE); - - // the first column - StateMachineSetAction(Sm, DLS_IDLE, MT2_MLME_DLS_REQ, (STATE_MACHINE_FUNC)MlmeDlsReqAction); - StateMachineSetAction(Sm, DLS_IDLE, MT2_PEER_DLS_REQ, (STATE_MACHINE_FUNC)PeerDlsReqAction); - StateMachineSetAction(Sm, DLS_IDLE, MT2_PEER_DLS_RSP, (STATE_MACHINE_FUNC)PeerDlsRspAction); - StateMachineSetAction(Sm, DLS_IDLE, MT2_MLME_DLS_TEAR_DOWN, (STATE_MACHINE_FUNC)MlmeDlsTearDownAction); - StateMachineSetAction(Sm, DLS_IDLE, MT2_PEER_DLS_TEAR_DOWN, (STATE_MACHINE_FUNC)PeerDlsTearDownAction); - - for (i=0; iStaCfg.DLSEntry[i].pAd = pAd; - RTMPInitTimer(pAd, &pAd->StaCfg.DLSEntry[i].Timer, GET_TIMER_FUNCTION(DlsTimeoutAction), pAd, FALSE); - } -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID MlmeDlsReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - PUCHAR pOutBuffer = NULL; - NDIS_STATUS NStatus; - ULONG FrameLen = 0; - HEADER_802_11 DlsReqHdr; - PRT_802_11_DLS pDLS = NULL; - UCHAR Category = CATEGORY_DLS; - UCHAR Action = ACTION_DLS_REQUEST; - ULONG tmp; - USHORT reason; - ULONG Timeout; - BOOLEAN TimerCancelled; - - if(!MlmeDlsReqSanity(pAd, Elem->Msg, Elem->MsgLen, &pDLS, &reason)) - return; - - DBGPRINT(RT_DEBUG_TRACE,("DLS - MlmeDlsReqAction() \n")); - - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory - if (NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_ERROR,("DLS - MlmeDlsReqAction() allocate memory failed \n")); - return; - } - - ActHeaderInit(pAd, &DlsReqHdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pAd->CommonCfg.Bssid); - - // Build basic frame first - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(HEADER_802_11), &DlsReqHdr, - 1, &Category, - 1, &Action, - 6, &pDLS->MacAddr, - 6, pAd->CurrentAddress, - 2, &pAd->StaActive.CapabilityInfo, - 2, &pDLS->TimeOut, - 1, &SupRateIe, - 1, &pAd->MlmeAux.SupRateLen, - pAd->MlmeAux.SupRateLen, pAd->MlmeAux.SupRate, - END_OF_ARGS); - - if (pAd->MlmeAux.ExtRateLen != 0) - { - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - 1, &ExtRateIe, - 1, &pAd->MlmeAux.ExtRateLen, - pAd->MlmeAux.ExtRateLen, pAd->MlmeAux.ExtRate, - END_OF_ARGS); - FrameLen += tmp; - } - -#ifdef DOT11_N_SUPPORT - if ((pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) - { - UCHAR HtLen; - -#ifdef RT_BIG_ENDIAN - HT_CAPABILITY_IE HtCapabilityTmp; -#endif - - // add HT Capability IE - HtLen = sizeof(HT_CAPABILITY_IE); -#ifndef RT_BIG_ENDIAN - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - 1, &HtCapIe, - 1, &HtLen, - HtLen, &pAd->CommonCfg.HtCapability, - END_OF_ARGS); -#else - NdisMoveMemory(&HtCapabilityTmp, &pAd->CommonCfg.HtCapability, HtLen); - *(USHORT *)(&HtCapabilityTmp.HtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.HtCapInfo)); - *(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo)); - - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - 1, &HtCapIe, - 1, &HtLen, - HtLen, &HtCapabilityTmp, - END_OF_ARGS); -#endif - FrameLen = FrameLen + tmp; - } -#endif // DOT11_N_SUPPORT // - - RTMPCancelTimer(&pDLS->Timer, &TimerCancelled); - Timeout = DLS_TIMEOUT; - RTMPSetTimer(&pDLS->Timer, Timeout); - - MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID PeerDlsReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - PUCHAR pOutBuffer = NULL; - NDIS_STATUS NStatus; - ULONG FrameLen = 0; - USHORT StatusCode = MLME_SUCCESS; - HEADER_802_11 DlsRspHdr; - UCHAR Category = CATEGORY_DLS; - UCHAR Action = ACTION_DLS_RESPONSE; - ULONG tmp; - USHORT CapabilityInfo; - UCHAR DA[MAC_ADDR_LEN], SA[MAC_ADDR_LEN]; - USHORT DLSTimeOut; - SHORT i; - ULONG Timeout; - BOOLEAN TimerCancelled; - PRT_802_11_DLS pDLS = NULL; - UCHAR MaxSupportedRateIn500Kbps = 0; - UCHAR SupportedRatesLen; - UCHAR SupportedRates[MAX_LEN_OF_SUPPORTED_RATES]; - UCHAR HtCapabilityLen; - HT_CAPABILITY_IE HtCapability; - - if (!PeerDlsReqSanity(pAd, Elem->Msg, Elem->MsgLen, DA, SA, &CapabilityInfo, &DLSTimeOut, - &SupportedRatesLen, &SupportedRates[0], &HtCapabilityLen, &HtCapability)) - return; - - // supported rates array may not be sorted. sort it and find the maximum rate - for (i = 0; i < SupportedRatesLen; i++) - { - if (MaxSupportedRateIn500Kbps < (SupportedRates[i] & 0x7f)) - MaxSupportedRateIn500Kbps = SupportedRates[i] & 0x7f; - } - - DBGPRINT(RT_DEBUG_TRACE,("DLS - PeerDlsReqAction() from %02x:%02x:%02x:%02x:%02x:%02x\n", SA[0], SA[1], SA[2], SA[3], SA[4], SA[5])); - - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory - if (NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_ERROR,("DLS - PeerDlsReqAction() allocate memory failed \n")); - return; - } - - if (!INFRA_ON(pAd)) - { - StatusCode = MLME_REQUEST_DECLINED; - } - else if (!pAd->CommonCfg.bWmmCapable) - { - StatusCode = MLME_DEST_STA_IS_NOT_A_QSTA; - } - else if (!pAd->CommonCfg.bDLSCapable) - { - StatusCode = MLME_REQUEST_DECLINED; - } - else - { - // find table to update parameters - for (i = (MAX_NUM_OF_DLS_ENTRY-1); i >= 0; i--) - { - if (pAd->StaCfg.DLSEntry[i].Valid && MAC_ADDR_EQUAL(SA, pAd->StaCfg.DLSEntry[i].MacAddr)) - { - if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - pAd->StaCfg.DLSEntry[i].Status = DLS_WAIT_KEY; - else - { - RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); - pAd->StaCfg.DLSEntry[i].Status = DLS_FINISH; - } - - pAd->StaCfg.DLSEntry[i].Sequence = 0; - pAd->StaCfg.DLSEntry[i].TimeOut = DLSTimeOut; - pAd->StaCfg.DLSEntry[i].CountDownTimer = DLSTimeOut; - if (HtCapabilityLen != 0) - pAd->StaCfg.DLSEntry[i].bHTCap = TRUE; - else - pAd->StaCfg.DLSEntry[i].bHTCap = FALSE; - pDLS = &pAd->StaCfg.DLSEntry[i]; - break; - } - } - - // can not find in table, create a new one - if (i < 0) - { - DBGPRINT(RT_DEBUG_TRACE,("DLS - PeerDlsReqAction() can not find same entry \n")); - for (i=(MAX_NUM_OF_DLS_ENTRY - 1); i >= MAX_NUM_OF_INIT_DLS_ENTRY; i--) - { - if (!pAd->StaCfg.DLSEntry[i].Valid) - { - MAC_TABLE_ENTRY *pEntry; - UCHAR MaxSupportedRate = RATE_11; - - if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - { - pAd->StaCfg.DLSEntry[i].Status = DLS_WAIT_KEY; - } - else - { - RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); - pAd->StaCfg.DLSEntry[i].Status = DLS_FINISH; - } - - pAd->StaCfg.DLSEntry[i].Sequence = 0; - pAd->StaCfg.DLSEntry[i].Valid = TRUE; - pAd->StaCfg.DLSEntry[i].TimeOut = DLSTimeOut; - pAd->StaCfg.DLSEntry[i].CountDownTimer = DLSTimeOut; - NdisMoveMemory(pAd->StaCfg.DLSEntry[i].MacAddr, SA, MAC_ADDR_LEN); - if (HtCapabilityLen != 0) - pAd->StaCfg.DLSEntry[i].bHTCap = TRUE; - else - pAd->StaCfg.DLSEntry[i].bHTCap = FALSE; - pDLS = &pAd->StaCfg.DLSEntry[i]; - pEntry = MacTableInsertDlsEntry(pAd, SA, i); - - switch (MaxSupportedRateIn500Kbps) - { - case 108: MaxSupportedRate = RATE_54; break; - case 96: MaxSupportedRate = RATE_48; break; - case 72: MaxSupportedRate = RATE_36; break; - case 48: MaxSupportedRate = RATE_24; break; - case 36: MaxSupportedRate = RATE_18; break; - case 24: MaxSupportedRate = RATE_12; break; - case 18: MaxSupportedRate = RATE_9; break; - case 12: MaxSupportedRate = RATE_6; break; - case 22: MaxSupportedRate = RATE_11; break; - case 11: MaxSupportedRate = RATE_5_5; break; - case 4: MaxSupportedRate = RATE_2; break; - case 2: MaxSupportedRate = RATE_1; break; - default: MaxSupportedRate = RATE_11; break; - } - - pEntry->MaxSupportedRate = min(pAd->CommonCfg.MaxTxRate, MaxSupportedRate); - - if (pEntry->MaxSupportedRate < RATE_FIRST_OFDM_RATE) - { - pEntry->MaxHTPhyMode.field.MODE = MODE_CCK; - pEntry->MaxHTPhyMode.field.MCS = pEntry->MaxSupportedRate; - pEntry->MinHTPhyMode.field.MODE = MODE_CCK; - pEntry->MinHTPhyMode.field.MCS = pEntry->MaxSupportedRate; - pEntry->HTPhyMode.field.MODE = MODE_CCK; - pEntry->HTPhyMode.field.MCS = pEntry->MaxSupportedRate; - } - else - { - pEntry->MaxHTPhyMode.field.MODE = MODE_OFDM; - pEntry->MaxHTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; - pEntry->MinHTPhyMode.field.MODE = MODE_OFDM; - pEntry->MinHTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; - pEntry->HTPhyMode.field.MODE = MODE_OFDM; - pEntry->HTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; - } - - pEntry->MaxHTPhyMode.field.BW = BW_20; - pEntry->MinHTPhyMode.field.BW = BW_20; - -#ifdef DOT11_N_SUPPORT - pEntry->HTCapability.MCSSet[0] = 0; - pEntry->HTCapability.MCSSet[1] = 0; - - // If this Entry supports 802.11n, upgrade to HT rate. - if ((HtCapabilityLen != 0) && (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) - { - UCHAR j, bitmask; //k,bitmask; - CHAR ii; - - DBGPRINT(RT_DEBUG_OFF, ("DLS - PeerDlsReqAction() Receive Peer HT Capable STA from %02x:%02x:%02x:%02x:%02x:%02x\n", - SA[0], SA[1], SA[2], SA[3], SA[4], SA[5])); - - if ((HtCapability.HtCapInfo.GF) && (pAd->CommonCfg.DesiredHtPhy.GF)) - { - pEntry->MaxHTPhyMode.field.MODE = MODE_HTGREENFIELD; - } - else - { - pEntry->MaxHTPhyMode.field.MODE = MODE_HTMIX; - pAd->MacTab.fAnyStationNonGF = TRUE; - pAd->CommonCfg.AddHTInfo.AddHtInfo2.NonGfPresent = 1; - } - - if ((HtCapability.HtCapInfo.ChannelWidth) && (pAd->CommonCfg.DesiredHtPhy.ChannelWidth)) - { - pEntry->MaxHTPhyMode.field.BW= BW_40; - pEntry->MaxHTPhyMode.field.ShortGI = ((pAd->CommonCfg.DesiredHtPhy.ShortGIfor40)&(HtCapability.HtCapInfo.ShortGIfor40)); - } - else - { - pEntry->MaxHTPhyMode.field.BW = BW_20; - pEntry->MaxHTPhyMode.field.ShortGI = ((pAd->CommonCfg.DesiredHtPhy.ShortGIfor20)&(HtCapability.HtCapInfo.ShortGIfor20)); - pAd->MacTab.fAnyStation20Only = TRUE; - } - - // find max fixed rate - for (ii=15; ii>=0; ii--) - { - j = ii/8; - bitmask = (1<<(ii-(j*8))); - if ( (pAd->StaCfg.DesiredHtPhyInfo.MCSSet[j]&bitmask) && (HtCapability.MCSSet[j]&bitmask)) - { - pEntry->MaxHTPhyMode.field.MCS = ii; - break; - } - if (ii==0) - break; - } - - - if (pAd->StaCfg.DesiredTransmitSetting.field.MCS != MCS_AUTO) - { - - printk("@@@ pAd->CommonCfg.RegTransmitSetting.field.MCS = %d\n", - pAd->StaCfg.DesiredTransmitSetting.field.MCS); - if (pAd->StaCfg.DesiredTransmitSetting.field.MCS == 32) - { - // Fix MCS as HT Duplicated Mode - pEntry->MaxHTPhyMode.field.BW = 1; - pEntry->MaxHTPhyMode.field.MODE = MODE_HTMIX; - pEntry->MaxHTPhyMode.field.STBC = 0; - pEntry->MaxHTPhyMode.field.ShortGI = 0; - pEntry->MaxHTPhyMode.field.MCS = 32; - } - else if (pEntry->MaxHTPhyMode.field.MCS > pAd->StaCfg.HTPhyMode.field.MCS) - { - // STA supports fixed MCS - pEntry->MaxHTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; - } - } - - pEntry->MaxHTPhyMode.field.STBC = (HtCapability.HtCapInfo.RxSTBC & (pAd->CommonCfg.DesiredHtPhy.TxSTBC)); - pEntry->MpduDensity = HtCapability.HtCapParm.MpduDensity; - pEntry->MaxRAmpduFactor = HtCapability.HtCapParm.MaxRAmpduFactor; - pEntry->MmpsMode = (UCHAR)HtCapability.HtCapInfo.MimoPs; - pEntry->AMsduSize = (UCHAR)HtCapability.HtCapInfo.AMsduSize; - pEntry->HTPhyMode.word = pEntry->MaxHTPhyMode.word; - - if (HtCapability.HtCapInfo.ShortGIfor20) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_SGI20_CAPABLE); - if (HtCapability.HtCapInfo.ShortGIfor40) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_SGI40_CAPABLE); - if (HtCapability.HtCapInfo.TxSTBC) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_TxSTBC_CAPABLE); - if (HtCapability.HtCapInfo.RxSTBC) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_RxSTBC_CAPABLE); - if (HtCapability.ExtHtCapInfo.PlusHTC) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_HTC_CAPABLE); - if (pAd->CommonCfg.bRdg && HtCapability.ExtHtCapInfo.RDGSupport) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_RDG_CAPABLE); - if (HtCapability.ExtHtCapInfo.MCSFeedback == 0x03) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_MCSFEEDBACK_CAPABLE); - - NdisMoveMemory(&pEntry->HTCapability, &HtCapability, sizeof(HT_CAPABILITY_IE)); - } -#endif // DOT11_N_SUPPORT // - - pEntry->HTPhyMode.word = pEntry->MaxHTPhyMode.word; - pEntry->CurrTxRate = pEntry->MaxSupportedRate; - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_WMM_CAPABLE); - - if (pAd->StaCfg.bAutoTxRateSwitch == TRUE) - { - PUCHAR pTable; - UCHAR TableSize = 0; - - MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize, &pEntry->CurrTxRateIndex); - pEntry->bAutoTxRateSwitch = TRUE; - } - else - { - pEntry->HTPhyMode.field.MODE = pAd->StaCfg.HTPhyMode.field.MODE; - pEntry->HTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; - pEntry->bAutoTxRateSwitch = FALSE; - - RTMPUpdateLegacyTxSetting((UCHAR)pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode, pEntry); - } - pEntry->RateLen = SupportedRatesLen; - - break; - } - } - } - StatusCode = MLME_SUCCESS; - - // can not find in table, create a new one - if (i < 0) - { - StatusCode = MLME_QOS_UNSPECIFY; - DBGPRINT(RT_DEBUG_ERROR,("DLS - PeerDlsReqAction() DLSEntry table full(only can support %d DLS session) \n", MAX_NUM_OF_DLS_ENTRY - MAX_NUM_OF_INIT_DLS_ENTRY)); - } - else - { - DBGPRINT(RT_DEBUG_TRACE,("DLS - PeerDlsReqAction() use entry(%d) %02x:%02x:%02x:%02x:%02x:%02x\n", - i, SA[0], SA[1], SA[2], SA[3], SA[4], SA[5])); - } - } - - ActHeaderInit(pAd, &DlsRspHdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pAd->CommonCfg.Bssid); - - // Build basic frame first - if (StatusCode == MLME_SUCCESS) - { - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(HEADER_802_11), &DlsRspHdr, - 1, &Category, - 1, &Action, - 2, &StatusCode, - 6, SA, - 6, pAd->CurrentAddress, - 2, &pAd->StaActive.CapabilityInfo, - 1, &SupRateIe, - 1, &pAd->MlmeAux.SupRateLen, - pAd->MlmeAux.SupRateLen, pAd->MlmeAux.SupRate, - END_OF_ARGS); - - if (pAd->MlmeAux.ExtRateLen != 0) - { - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - 1, &ExtRateIe, - 1, &pAd->MlmeAux.ExtRateLen, - pAd->MlmeAux.ExtRateLen, pAd->MlmeAux.ExtRate, - END_OF_ARGS); - FrameLen += tmp; - } - -#ifdef DOT11_N_SUPPORT - if ((pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) - { - UCHAR HtLen; - -#ifdef RT_BIG_ENDIAN - HT_CAPABILITY_IE HtCapabilityTmp; -#endif - - // add HT Capability IE - HtLen = sizeof(HT_CAPABILITY_IE); -#ifndef RT_BIG_ENDIAN - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - 1, &HtCapIe, - 1, &HtLen, - HtLen, &pAd->CommonCfg.HtCapability, - END_OF_ARGS); -#else - NdisMoveMemory(&HtCapabilityTmp, &pAd->CommonCfg.HtCapability, HtLen); - *(USHORT *)(&HtCapabilityTmp.HtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.HtCapInfo)); - *(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo)); - - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - 1, &HtCapIe, - 1, &HtLen, - HtLen, &HtCapabilityTmp, - END_OF_ARGS); -#endif - FrameLen = FrameLen + tmp; - } -#endif // DOT11_N_SUPPORT // - - if (pDLS && (pDLS->Status != DLS_FINISH)) - { - RTMPCancelTimer(&pDLS->Timer, &TimerCancelled); - Timeout = DLS_TIMEOUT; - RTMPSetTimer(&pDLS->Timer, Timeout); - } - } - else - { - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(HEADER_802_11), &DlsRspHdr, - 1, &Category, - 1, &Action, - 2, &StatusCode, - 6, SA, - 6, pAd->CurrentAddress, - END_OF_ARGS); - } - - MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID PeerDlsRspAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - USHORT CapabilityInfo; - UCHAR DA[MAC_ADDR_LEN], SA[MAC_ADDR_LEN]; - USHORT StatusCode; - SHORT i; - BOOLEAN TimerCancelled; - UCHAR MaxSupportedRateIn500Kbps = 0; - UCHAR SupportedRatesLen; - UCHAR SupportedRates[MAX_LEN_OF_SUPPORTED_RATES]; - UCHAR HtCapabilityLen; - HT_CAPABILITY_IE HtCapability; - - if (!pAd->CommonCfg.bDLSCapable) - return; - - if (!INFRA_ON(pAd)) - return; - - if (!PeerDlsRspSanity(pAd, Elem->Msg, Elem->MsgLen, DA, SA, &CapabilityInfo, &StatusCode, - &SupportedRatesLen, &SupportedRates[0], &HtCapabilityLen, &HtCapability)) - return; - - // supported rates array may not be sorted. sort it and find the maximum rate - for (i=0; iStaCfg.DLSEntry[i].Valid && MAC_ADDR_EQUAL(SA, pAd->StaCfg.DLSEntry[i].MacAddr)) - { - if (StatusCode == MLME_SUCCESS) - { - MAC_TABLE_ENTRY *pEntry; - UCHAR MaxSupportedRate = RATE_11; - - pEntry = MacTableInsertDlsEntry(pAd, SA, i); - - switch (MaxSupportedRateIn500Kbps) - { - case 108: MaxSupportedRate = RATE_54; break; - case 96: MaxSupportedRate = RATE_48; break; - case 72: MaxSupportedRate = RATE_36; break; - case 48: MaxSupportedRate = RATE_24; break; - case 36: MaxSupportedRate = RATE_18; break; - case 24: MaxSupportedRate = RATE_12; break; - case 18: MaxSupportedRate = RATE_9; break; - case 12: MaxSupportedRate = RATE_6; break; - case 22: MaxSupportedRate = RATE_11; break; - case 11: MaxSupportedRate = RATE_5_5; break; - case 4: MaxSupportedRate = RATE_2; break; - case 2: MaxSupportedRate = RATE_1; break; - default: MaxSupportedRate = RATE_11; break; - } - - pEntry->MaxSupportedRate = min(pAd->CommonCfg.MaxTxRate, MaxSupportedRate); - - if (pEntry->MaxSupportedRate < RATE_FIRST_OFDM_RATE) - { - pEntry->MaxHTPhyMode.field.MODE = MODE_CCK; - pEntry->MaxHTPhyMode.field.MCS = pEntry->MaxSupportedRate; - pEntry->MinHTPhyMode.field.MODE = MODE_CCK; - pEntry->MinHTPhyMode.field.MCS = pEntry->MaxSupportedRate; - pEntry->HTPhyMode.field.MODE = MODE_CCK; - pEntry->HTPhyMode.field.MCS = pEntry->MaxSupportedRate; - } - else - { - pEntry->MaxHTPhyMode.field.MODE = MODE_OFDM; - pEntry->MaxHTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; - pEntry->MinHTPhyMode.field.MODE = MODE_OFDM; - pEntry->MinHTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; - pEntry->HTPhyMode.field.MODE = MODE_OFDM; - pEntry->HTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; - } - - pEntry->MaxHTPhyMode.field.BW = BW_20; - pEntry->MinHTPhyMode.field.BW = BW_20; - -#ifdef DOT11_N_SUPPORT - pEntry->HTCapability.MCSSet[0] = 0; - pEntry->HTCapability.MCSSet[1] = 0; - - // If this Entry supports 802.11n, upgrade to HT rate. - if ((HtCapabilityLen != 0) && (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) - { - UCHAR j, bitmask; //k,bitmask; - CHAR ii; - - DBGPRINT(RT_DEBUG_OFF, ("DLS - PeerDlsRspAction Receive Peer HT Capable STA from %02x:%02x:%02x:%02x:%02x:%02x\n", - SA[0], SA[1], SA[2], SA[3], SA[4], SA[5])); - - if ((HtCapability.HtCapInfo.GF) && (pAd->CommonCfg.DesiredHtPhy.GF)) - { - pEntry->MaxHTPhyMode.field.MODE = MODE_HTGREENFIELD; - } - else - { - pEntry->MaxHTPhyMode.field.MODE = MODE_HTMIX; - pAd->MacTab.fAnyStationNonGF = TRUE; - pAd->CommonCfg.AddHTInfo.AddHtInfo2.NonGfPresent = 1; - } - - if ((HtCapability.HtCapInfo.ChannelWidth) && (pAd->CommonCfg.DesiredHtPhy.ChannelWidth)) - { - pEntry->MaxHTPhyMode.field.BW= BW_40; - pEntry->MaxHTPhyMode.field.ShortGI = ((pAd->CommonCfg.DesiredHtPhy.ShortGIfor40)&(HtCapability.HtCapInfo.ShortGIfor40)); - } - else - { - pEntry->MaxHTPhyMode.field.BW = BW_20; - pEntry->MaxHTPhyMode.field.ShortGI = ((pAd->CommonCfg.DesiredHtPhy.ShortGIfor20)&(HtCapability.HtCapInfo.ShortGIfor20)); - pAd->MacTab.fAnyStation20Only = TRUE; - } - - // find max fixed rate - for (ii=15; ii>=0; ii--) - { - j = ii/8; - bitmask = (1<<(ii-(j*8))); - if ( (pAd->StaCfg.DesiredHtPhyInfo.MCSSet[j]&bitmask) && (HtCapability.MCSSet[j]&bitmask)) - { - pEntry->MaxHTPhyMode.field.MCS = ii; - break; - } - if (ii==0) - break; - } - - if (pAd->StaCfg.DesiredTransmitSetting.field.MCS != MCS_AUTO) - { - if (pAd->StaCfg.DesiredTransmitSetting.field.MCS == 32) - { - // Fix MCS as HT Duplicated Mode - pEntry->MaxHTPhyMode.field.BW = 1; - pEntry->MaxHTPhyMode.field.MODE = MODE_HTMIX; - pEntry->MaxHTPhyMode.field.STBC = 0; - pEntry->MaxHTPhyMode.field.ShortGI = 0; - pEntry->MaxHTPhyMode.field.MCS = 32; - } - else if (pEntry->MaxHTPhyMode.field.MCS > pAd->StaCfg.HTPhyMode.field.MCS) - { - // STA supports fixed MCS - pEntry->MaxHTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; - } - } - - pEntry->MaxHTPhyMode.field.STBC = (HtCapability.HtCapInfo.RxSTBC & (pAd->CommonCfg.DesiredHtPhy.TxSTBC)); - pEntry->MpduDensity = HtCapability.HtCapParm.MpduDensity; - pEntry->MaxRAmpduFactor = HtCapability.HtCapParm.MaxRAmpduFactor; - pEntry->MmpsMode = (UCHAR)HtCapability.HtCapInfo.MimoPs; - pEntry->AMsduSize = (UCHAR)HtCapability.HtCapInfo.AMsduSize; - pEntry->HTPhyMode.word = pEntry->MaxHTPhyMode.word; - - if (HtCapability.HtCapInfo.ShortGIfor20) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_SGI20_CAPABLE); - if (HtCapability.HtCapInfo.ShortGIfor40) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_SGI40_CAPABLE); - if (HtCapability.HtCapInfo.TxSTBC) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_TxSTBC_CAPABLE); - if (HtCapability.HtCapInfo.RxSTBC) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_RxSTBC_CAPABLE); - if (HtCapability.ExtHtCapInfo.PlusHTC) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_HTC_CAPABLE); - if (pAd->CommonCfg.bRdg && HtCapability.ExtHtCapInfo.RDGSupport) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_RDG_CAPABLE); - if (HtCapability.ExtHtCapInfo.MCSFeedback == 0x03) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_MCSFEEDBACK_CAPABLE); - - NdisMoveMemory(&pEntry->HTCapability, &HtCapability, sizeof(HT_CAPABILITY_IE)); - } -#endif // DOT11_N_SUPPORT // - pEntry->HTPhyMode.word = pEntry->MaxHTPhyMode.word; - pEntry->CurrTxRate = pEntry->MaxSupportedRate; - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_WMM_CAPABLE); - - if (pAd->StaCfg.bAutoTxRateSwitch == TRUE) - { - PUCHAR pTable; - UCHAR TableSize = 0; - - MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize, &pEntry->CurrTxRateIndex); - pEntry->bAutoTxRateSwitch = TRUE; - } - else - { - pEntry->HTPhyMode.field.MODE = pAd->StaCfg.HTPhyMode.field.MODE; - pEntry->HTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; - pEntry->bAutoTxRateSwitch = FALSE; - - RTMPUpdateLegacyTxSetting((UCHAR)pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode, pEntry); - } - pEntry->RateLen = SupportedRatesLen; - - if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - { - // If support WPA or WPA2, start STAKey hand shake, - // If failed hand shake, just tear down peer DLS - if (RTMPSendSTAKeyRequest(pAd, pAd->StaCfg.DLSEntry[i].MacAddr) != NDIS_STATUS_SUCCESS) - { - MLME_DLS_REQ_STRUCT MlmeDlsReq; - USHORT reason = REASON_QOS_CIPHER_NOT_SUPPORT; - - DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); - MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_TEAR_DOWN, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - pAd->StaCfg.DLSEntry[i].Valid = FALSE; - DBGPRINT(RT_DEBUG_ERROR,("DLS - PeerDlsRspAction failed when call RTMPSendSTAKeyRequest \n")); - } - else - { - pAd->StaCfg.DLSEntry[i].Status = DLS_WAIT_KEY; - DBGPRINT(RT_DEBUG_TRACE,("DLS - waiting for STAKey handshake procedure\n")); - } - } - else - { - RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); - pAd->StaCfg.DLSEntry[i].Status = DLS_FINISH; - DBGPRINT(RT_DEBUG_TRACE,("DLS - PeerDlsRspAction() from %02x:%02x:%02x:%02x:%02x:%02x Succeed with WEP or no security\n", SA[0], SA[1], SA[2], SA[3], SA[4], SA[5])); - } - - //initialize seq no for DLS frames. - pAd->StaCfg.DLSEntry[i].Sequence = 0; - if (HtCapabilityLen != 0) - pAd->StaCfg.DLSEntry[i].bHTCap = TRUE; - else - pAd->StaCfg.DLSEntry[i].bHTCap = FALSE; - } - else - { - // DLS setup procedure failed. - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - pAd->StaCfg.DLSEntry[i].Valid = FALSE; - RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); - DBGPRINT(RT_DEBUG_ERROR,("DLS - PeerDlsRspAction failed with StatusCode=%d \n", StatusCode)); - } - } - } - - if (i >= MAX_NUM_OF_INIT_DLS_ENTRY) - { - DBGPRINT(RT_DEBUG_TRACE,("DLS - PeerDlsRspAction() update timeout value \n")); - for (i=(MAX_NUM_OF_DLS_ENTRY-1); i>=MAX_NUM_OF_INIT_DLS_ENTRY; i--) - { - if (pAd->StaCfg.DLSEntry[i].Valid && MAC_ADDR_EQUAL(SA, pAd->StaCfg.DLSEntry[i].MacAddr)) - { - if (StatusCode == MLME_SUCCESS) - { - MAC_TABLE_ENTRY *pEntry; - UCHAR MaxSupportedRate = RATE_11; - - pEntry = MacTableInsertDlsEntry(pAd, SA, i); - - switch (MaxSupportedRateIn500Kbps) - { - case 108: MaxSupportedRate = RATE_54; break; - case 96: MaxSupportedRate = RATE_48; break; - case 72: MaxSupportedRate = RATE_36; break; - case 48: MaxSupportedRate = RATE_24; break; - case 36: MaxSupportedRate = RATE_18; break; - case 24: MaxSupportedRate = RATE_12; break; - case 18: MaxSupportedRate = RATE_9; break; - case 12: MaxSupportedRate = RATE_6; break; - case 22: MaxSupportedRate = RATE_11; break; - case 11: MaxSupportedRate = RATE_5_5; break; - case 4: MaxSupportedRate = RATE_2; break; - case 2: MaxSupportedRate = RATE_1; break; - default: MaxSupportedRate = RATE_11; break; - } - - pEntry->MaxSupportedRate = min(pAd->CommonCfg.MaxTxRate, MaxSupportedRate); - - if (pEntry->MaxSupportedRate < RATE_FIRST_OFDM_RATE) - { - pEntry->MaxHTPhyMode.field.MODE = MODE_CCK; - pEntry->MaxHTPhyMode.field.MCS = pEntry->MaxSupportedRate; - pEntry->MinHTPhyMode.field.MODE = MODE_CCK; - pEntry->MinHTPhyMode.field.MCS = pEntry->MaxSupportedRate; - pEntry->HTPhyMode.field.MODE = MODE_CCK; - pEntry->HTPhyMode.field.MCS = pEntry->MaxSupportedRate; - } - else - { - pEntry->MaxHTPhyMode.field.MODE = MODE_OFDM; - pEntry->MaxHTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; - pEntry->MinHTPhyMode.field.MODE = MODE_OFDM; - pEntry->MinHTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; - pEntry->HTPhyMode.field.MODE = MODE_OFDM; - pEntry->HTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; - } - - pEntry->MaxHTPhyMode.field.BW = BW_20; - pEntry->MinHTPhyMode.field.BW = BW_20; - -#ifdef DOT11_N_SUPPORT - pEntry->HTCapability.MCSSet[0] = 0; - pEntry->HTCapability.MCSSet[1] = 0; - - // If this Entry supports 802.11n, upgrade to HT rate. - if ((HtCapabilityLen != 0) && (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) - { - UCHAR j, bitmask; //k,bitmask; - CHAR ii; - - DBGPRINT(RT_DEBUG_OFF, ("DLS - PeerDlsRspAction Receive Peer HT Capable STA from %02x:%02x:%02x:%02x:%02x:%02x\n", - SA[0], SA[1], SA[2], SA[3], SA[4], SA[5])); - - if ((HtCapability.HtCapInfo.GF) && (pAd->CommonCfg.DesiredHtPhy.GF)) - { - pEntry->MaxHTPhyMode.field.MODE = MODE_HTGREENFIELD; - } - else - { - pEntry->MaxHTPhyMode.field.MODE = MODE_HTMIX; - pAd->MacTab.fAnyStationNonGF = TRUE; - pAd->CommonCfg.AddHTInfo.AddHtInfo2.NonGfPresent = 1; - } - - if ((HtCapability.HtCapInfo.ChannelWidth) && (pAd->CommonCfg.DesiredHtPhy.ChannelWidth)) - { - pEntry->MaxHTPhyMode.field.BW= BW_40; - pEntry->MaxHTPhyMode.field.ShortGI = ((pAd->CommonCfg.DesiredHtPhy.ShortGIfor40)&(HtCapability.HtCapInfo.ShortGIfor40)); - } - else - { - pEntry->MaxHTPhyMode.field.BW = BW_20; - pEntry->MaxHTPhyMode.field.ShortGI = ((pAd->CommonCfg.DesiredHtPhy.ShortGIfor20)&(HtCapability.HtCapInfo.ShortGIfor20)); - pAd->MacTab.fAnyStation20Only = TRUE; - } - - // find max fixed rate - for (ii=15; ii>=0; ii--) - { - j = ii/8; - bitmask = (1<<(ii-(j*8))); - if ( (pAd->StaCfg.DesiredHtPhyInfo.MCSSet[j]&bitmask) && (HtCapability.MCSSet[j]&bitmask)) - { - pEntry->MaxHTPhyMode.field.MCS = ii; - break; - } - if (ii==0) - break; - } - - if (pAd->StaCfg.DesiredTransmitSetting.field.MCS != MCS_AUTO) - { - printk("@@@ pAd->CommonCfg.RegTransmitSetting.field.MCS = %d\n", - pAd->StaCfg.DesiredTransmitSetting.field.MCS); - if (pAd->StaCfg.DesiredTransmitSetting.field.MCS == 32) - { - // Fix MCS as HT Duplicated Mode - pEntry->MaxHTPhyMode.field.BW = 1; - pEntry->MaxHTPhyMode.field.MODE = MODE_HTMIX; - pEntry->MaxHTPhyMode.field.STBC = 0; - pEntry->MaxHTPhyMode.field.ShortGI = 0; - pEntry->MaxHTPhyMode.field.MCS = 32; - } - else if (pEntry->MaxHTPhyMode.field.MCS > pAd->StaCfg.HTPhyMode.field.MCS) - { - // STA supports fixed MCS - pEntry->MaxHTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; - } - } - - pEntry->MaxHTPhyMode.field.STBC = (HtCapability.HtCapInfo.RxSTBC & (pAd->CommonCfg.DesiredHtPhy.TxSTBC)); - pEntry->MpduDensity = HtCapability.HtCapParm.MpduDensity; - pEntry->MaxRAmpduFactor = HtCapability.HtCapParm.MaxRAmpduFactor; - pEntry->MmpsMode = (UCHAR)HtCapability.HtCapInfo.MimoPs; - pEntry->AMsduSize = (UCHAR)HtCapability.HtCapInfo.AMsduSize; - pEntry->HTPhyMode.word = pEntry->MaxHTPhyMode.word; - - if (HtCapability.HtCapInfo.ShortGIfor20) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_SGI20_CAPABLE); - if (HtCapability.HtCapInfo.ShortGIfor40) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_SGI40_CAPABLE); - if (HtCapability.HtCapInfo.TxSTBC) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_TxSTBC_CAPABLE); - if (HtCapability.HtCapInfo.RxSTBC) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_RxSTBC_CAPABLE); - if (HtCapability.ExtHtCapInfo.PlusHTC) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_HTC_CAPABLE); - if (pAd->CommonCfg.bRdg && HtCapability.ExtHtCapInfo.RDGSupport) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_RDG_CAPABLE); - if (HtCapability.ExtHtCapInfo.MCSFeedback == 0x03) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_MCSFEEDBACK_CAPABLE); - - NdisMoveMemory(&pEntry->HTCapability, &HtCapability, sizeof(HT_CAPABILITY_IE)); - } -#endif // DOT11_N_SUPPORT // - - pEntry->HTPhyMode.word = pEntry->MaxHTPhyMode.word; - pEntry->CurrTxRate = pEntry->MaxSupportedRate; - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_WMM_CAPABLE); - - if (pAd->StaCfg.bAutoTxRateSwitch == TRUE) - { - PUCHAR pTable; - UCHAR TableSize = 0; - - MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize, &pEntry->CurrTxRateIndex); - pEntry->bAutoTxRateSwitch = TRUE; - } - else - { - pEntry->HTPhyMode.field.MODE = pAd->StaCfg.HTPhyMode.field.MODE; - pEntry->HTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; - pEntry->bAutoTxRateSwitch = FALSE; - - RTMPUpdateLegacyTxSetting((UCHAR)pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode, pEntry); - } - pEntry->RateLen = SupportedRatesLen; - - if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - { - // If support WPA or WPA2, start STAKey hand shake, - // If failed hand shake, just tear down peer DLS - if (RTMPSendSTAKeyRequest(pAd, pAd->StaCfg.DLSEntry[i].MacAddr) != NDIS_STATUS_SUCCESS) - { - MLME_DLS_REQ_STRUCT MlmeDlsReq; - USHORT reason = REASON_QOS_CIPHER_NOT_SUPPORT; - - DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); - MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_TEAR_DOWN, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - pAd->StaCfg.DLSEntry[i].Valid = FALSE; - DBGPRINT(RT_DEBUG_ERROR,("DLS - PeerDlsRspAction failed when call RTMPSendSTAKeyRequest \n")); - } - else - { - pAd->StaCfg.DLSEntry[i].Status = DLS_WAIT_KEY; - DBGPRINT(RT_DEBUG_TRACE,("DLS - waiting for STAKey handshake procedure\n")); - } - } - else - { - RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); - pAd->StaCfg.DLSEntry[i].Status = DLS_FINISH; - DBGPRINT(RT_DEBUG_TRACE,("DLS - PeerDlsRspAction() from %02x:%02x:%02x:%02x:%02x:%02x Succeed with WEP or no security\n", SA[0], SA[1], SA[2], SA[3], SA[4], SA[5])); - } - pAd->StaCfg.DLSEntry[i].Sequence = 0; - if (HtCapabilityLen != 0) - pAd->StaCfg.DLSEntry[i].bHTCap = TRUE; - else - pAd->StaCfg.DLSEntry[i].bHTCap = FALSE; - } - else - { - // DLS setup procedure failed. - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - pAd->StaCfg.DLSEntry[i].Valid = FALSE; - RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); - DBGPRINT(RT_DEBUG_ERROR,("DLS - PeerDlsRspAction failed with StatusCode=%d \n", StatusCode)); - } - } - } - } -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID MlmeDlsTearDownAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - PUCHAR pOutBuffer = NULL; - NDIS_STATUS NStatus; - ULONG FrameLen = 0; - UCHAR Category = CATEGORY_DLS; - UCHAR Action = ACTION_DLS_TEARDOWN; - USHORT ReasonCode = REASON_QOS_UNSPECIFY; - HEADER_802_11 DlsTearDownHdr; - PRT_802_11_DLS pDLS; - BOOLEAN TimerCancelled; - UCHAR i; - - if(!MlmeDlsReqSanity(pAd, Elem->Msg, Elem->MsgLen, &pDLS, &ReasonCode)) - return; - - DBGPRINT(RT_DEBUG_TRACE,("DLS - MlmeDlsTearDownAction() with ReasonCode=%d \n", ReasonCode)); - - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory - if (NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_ERROR,("DLS - MlmeDlsTearDownAction() allocate memory failed \n")); - return; - } - - ActHeaderInit(pAd, &DlsTearDownHdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pAd->CommonCfg.Bssid); - - // Build basic frame first - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(HEADER_802_11), &DlsTearDownHdr, - 1, &Category, - 1, &Action, - 6, &pDLS->MacAddr, - 6, pAd->CurrentAddress, - 2, &ReasonCode, - END_OF_ARGS); - - MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); - RTMPCancelTimer(&pDLS->Timer, &TimerCancelled); - - // Remove key in local dls table entry - for (i = 0; i < MAX_NUM_OF_INIT_DLS_ENTRY; i++) - { - if (MAC_ADDR_EQUAL(pDLS->MacAddr, pAd->StaCfg.DLSEntry[i].MacAddr)) - { - MacTableDeleteDlsEntry(pAd, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID, pAd->StaCfg.DLSEntry[i].MacAddr); - } - } - - // clear peer dls table entry - for (i = MAX_NUM_OF_INIT_DLS_ENTRY; i < MAX_NUM_OF_DLS_ENTRY; i++) - { - if (MAC_ADDR_EQUAL(pDLS->MacAddr, pAd->StaCfg.DLSEntry[i].MacAddr)) - { - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - pAd->StaCfg.DLSEntry[i].Valid = FALSE; - RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); - MacTableDeleteDlsEntry(pAd, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID, pAd->StaCfg.DLSEntry[i].MacAddr); - } - } -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID PeerDlsTearDownAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - UCHAR DA[MAC_ADDR_LEN], SA[MAC_ADDR_LEN]; - USHORT ReasonCode; - UINT i; - BOOLEAN TimerCancelled; - - if (!pAd->CommonCfg.bDLSCapable) - return; - - if (!INFRA_ON(pAd)) - return; - - if (!PeerDlsTearDownSanity(pAd, Elem->Msg, Elem->MsgLen, DA, SA, &ReasonCode)) - return; - - DBGPRINT(RT_DEBUG_TRACE,("DLS - PeerDlsTearDownAction() from %02x:%02x:%02x:%02x:%02x:%02x with ReasonCode=%d\n", SA[0], SA[1], SA[2], SA[3], SA[4], SA[5], ReasonCode)); - - // clear local dls table entry - for (i=0; iStaCfg.DLSEntry[i].Valid && MAC_ADDR_EQUAL(SA, pAd->StaCfg.DLSEntry[i].MacAddr)) - { - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - pAd->StaCfg.DLSEntry[i].Valid = FALSE; - RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); - //AsicDelWcidTab(pAd, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID); - //AsicRemovePairwiseKeyEntry(pAd, BSS0, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID); - MacTableDeleteDlsEntry(pAd, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID, pAd->StaCfg.DLSEntry[i].MacAddr); - } - } - - // clear peer dls table entry - for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid && MAC_ADDR_EQUAL(SA, pAd->StaCfg.DLSEntry[i].MacAddr)) - { - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - pAd->StaCfg.DLSEntry[i].Valid = FALSE; - RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); - //AsicDelWcidTab(pAd, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID); - //AsicRemovePairwiseKeyEntry(pAd, BSS0, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID); - MacTableDeleteDlsEntry(pAd, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID, pAd->StaCfg.DLSEntry[i].MacAddr); - } - } -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID RTMPCheckDLSTimeOut( - IN PRTMP_ADAPTER pAd) -{ - ULONG i; - MLME_DLS_REQ_STRUCT MlmeDlsReq; - USHORT reason = REASON_QOS_UNSPECIFY; - - if (! pAd->CommonCfg.bDLSCapable) - return; - - if (! INFRA_ON(pAd)) - return; - - // If timeout value is equaled to zero, it means always not be timeout. - - // update local dls table entry - for (i=0; iStaCfg.DLSEntry[i].Valid) && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) - && (pAd->StaCfg.DLSEntry[i].TimeOut != 0)) - { - pAd->StaCfg.DLSEntry[i].CountDownTimer --; - - if (pAd->StaCfg.DLSEntry[i].CountDownTimer == 0) - { - reason = REASON_QOS_REQUEST_TIMEOUT; - pAd->StaCfg.DLSEntry[i].Valid = FALSE; - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); - MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_TEAR_DOWN, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); - } - } - } - - // update peer dls table entry - for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid) && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) - && (pAd->StaCfg.DLSEntry[i].TimeOut != 0)) - { - pAd->StaCfg.DLSEntry[i].CountDownTimer --; - - if (pAd->StaCfg.DLSEntry[i].CountDownTimer == 0) - { - reason = REASON_QOS_REQUEST_TIMEOUT; - pAd->StaCfg.DLSEntry[i].Valid = FALSE; - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); - MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_TEAR_DOWN, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); - } - } - } -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -BOOLEAN RTMPRcvFrameDLSCheck( - IN PRTMP_ADAPTER pAd, - IN PHEADER_802_11 pHeader, - IN ULONG Len, - IN PRT28XX_RXD_STRUC pRxD) -{ - ULONG i; - BOOLEAN bFindEntry = FALSE; - BOOLEAN bSTAKeyFrame = FALSE; - PEAPOL_PACKET pEap; - PUCHAR pProto, pAddr = NULL; - PUCHAR pSTAKey = NULL; - UCHAR ZeroReplay[LEN_KEY_DESC_REPLAY]; - UCHAR Mic[16], OldMic[16]; - UCHAR digest[80]; - UCHAR DlsPTK[80]; - UCHAR temp[64]; - BOOLEAN TimerCancelled; - CIPHER_KEY PairwiseKey; - - - if (! pAd->CommonCfg.bDLSCapable) - return bSTAKeyFrame; - - if (! INFRA_ON(pAd)) - return bSTAKeyFrame; - - if (! (pHeader->FC.SubType & 0x08)) - return bSTAKeyFrame; - - if (Len < LENGTH_802_11 + 6 + 2 + 2) - return bSTAKeyFrame; - - pProto = (PUCHAR)pHeader + LENGTH_802_11 + 2 + 6; // QOS Control field , 0xAA 0xAA 0xAA 0x00 0x00 0x00 - pAddr = pHeader->Addr2; - - // L2PAD bit on will pad 2 bytes at LLC - if (pRxD->L2PAD) - { - pProto += 2; - } - - if (RTMPEqualMemory(EAPOL, pProto, 2) && (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA)) - { - pEap = (PEAPOL_PACKET) (pProto + 2); - - DBGPRINT(RT_DEBUG_TRACE,("DLS - Sniff Len=%ld, DataLen=%d, KeyMic=%d, Install=%d, KeyAck=%d, Secure=%d, EKD_DL=%d, Error=%d, Request=%d\n", Len, - (LENGTH_802_11 + 6 + 2 + 2 + sizeof(EAPOL_PACKET) - MAX_LEN_OF_RSNIE + 16), - pEap->KeyDesc.KeyInfo.KeyMic, - pEap->KeyDesc.KeyInfo.Install, - pEap->KeyDesc.KeyInfo.KeyAck, - pEap->KeyDesc.KeyInfo.Secure, - pEap->KeyDesc.KeyInfo.EKD_DL, - pEap->KeyDesc.KeyInfo.Error, - pEap->KeyDesc.KeyInfo.Request)); - - if ((Len >= (LENGTH_802_11 + 6 + 2 + 2 + sizeof(EAPOL_PACKET) - MAX_LEN_OF_RSNIE + 16)) && pEap->KeyDesc.KeyInfo.KeyMic - && pEap->KeyDesc.KeyInfo.Install && pEap->KeyDesc.KeyInfo.KeyAck && pEap->KeyDesc.KeyInfo.Secure - && pEap->KeyDesc.KeyInfo.EKD_DL && !pEap->KeyDesc.KeyInfo.Error && !pEap->KeyDesc.KeyInfo.Request) - { - // First validate replay counter, only accept message with larger replay counter - // Let equal pass, some AP start with all zero replay counter - NdisZeroMemory(ZeroReplay, LEN_KEY_DESC_REPLAY); - if ((RTMPCompareMemory(pEap->KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY) != 1) && - (RTMPCompareMemory(pEap->KeyDesc.ReplayCounter, ZeroReplay, LEN_KEY_DESC_REPLAY) != 0)) - return bSTAKeyFrame; - - //RTMPMoveMemory(pAd->StaCfg.ReplayCounter, pEap->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); - RTMPMoveMemory(pAd->StaCfg.DlsReplayCounter, pEap->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); - DBGPRINT(RT_DEBUG_TRACE,("DLS - Sniff replay counter (%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x) Len=%ld, KeyDataLen=%d\n", - pAd->StaCfg.ReplayCounter[0], pAd->StaCfg.ReplayCounter[1], pAd->StaCfg.ReplayCounter[2], - pAd->StaCfg.ReplayCounter[3], pAd->StaCfg.ReplayCounter[4], pAd->StaCfg.ReplayCounter[5], - pAd->StaCfg.ReplayCounter[6], pAd->StaCfg.ReplayCounter[7], Len, pEap->KeyDesc.KeyData[1])); - - // put these code segment to get the replay counter - if (pAd->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED) - return bSTAKeyFrame; - - // Check MIC value - // Save the MIC and replace with zero - // use proprietary PTK - NdisZeroMemory(temp, 64); - NdisMoveMemory(temp, "IEEE802.11 WIRELESS ACCESS POINT", 32); - WpaCountPTK(pAd, temp, temp, pAd->CommonCfg.Bssid, temp, pAd->CurrentAddress, DlsPTK, LEN_PTK); - - NdisMoveMemory(OldMic, pEap->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); - NdisZeroMemory(pEap->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); - if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) - { - // AES - HMAC_SHA1((PUCHAR) pEap, pEap->Body_Len[1] + 4, DlsPTK, LEN_EAP_MICK, digest); - NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); - } - else - { - hmac_md5(DlsPTK, LEN_EAP_MICK, (PUCHAR) pEap, pEap->Body_Len[1] + 4, Mic); - } - - if (!NdisEqualMemory(OldMic, Mic, LEN_KEY_DESC_MIC)) - { - DBGPRINT(RT_DEBUG_ERROR, ("MIC Different in Msg1 of STAKey handshake! \n")); - return bSTAKeyFrame; - } - else - DBGPRINT(RT_DEBUG_TRACE, ("MIC VALID in Msg1 of STAKey handshake! \n")); -#if 1 - if ((pEap->KeyDesc.KeyData[0] == 0xDD) && (pEap->KeyDesc.KeyData[2] == 0x00) && (pEap->KeyDesc.KeyData[3] == 0x0C) - && (pEap->KeyDesc.KeyData[4] == 0x43) && (pEap->KeyDesc.KeyData[5] == 0x02)) - { - pAddr = pEap->KeyDesc.KeyData + 8; // Tpe(1), Len(1), OUI(3), DataType(1), Reserved(2) - pSTAKey = pEap->KeyDesc.KeyData + 14; // Tpe(1), Len(1), OUI(3), DataType(1), Reserved(2), STAKey_Mac_Addr(6) - - DBGPRINT(RT_DEBUG_TRACE,("DLS - Receive STAKey Message-1 from %02x:%02x:%02x:%02x:%02x:%02x Len=%ld, KeyDataLen=%d\n", - pAddr[0], pAddr[1], pAddr[2], pAddr[3], pAddr[4], pAddr[5], Len, pEap->KeyDesc.KeyData[1])); - - bSTAKeyFrame = TRUE; - } -#else - if ((pEap->KeyDesc.KeyData[0] == 0xDD) && (pEap->KeyDesc.KeyData[2] == 0x00) && (pEap->KeyDesc.KeyData[3] == 0x0F) - && (pEap->KeyDesc.KeyData[4] == 0xAC) && (pEap->KeyDesc.KeyData[5] == 0x02)) - { - pAddr = pEap->KeyDesc.KeyData + 8; // Tpe(1), Len(1), OUI(3), DataType(1), Reserved(2) - pSTAKey = pEap->KeyDesc.KeyData + 14; // Tpe(1), Len(1), OUI(3), DataType(1), Reserved(2), STAKey_Mac_Addr(6) - - DBGPRINT(RT_DEBUG_TRACE,("DLS - Receive STAKey Message-1 from %02x:%02x:%02x:%02x:%02x:%02x Len=%d, KeyDataLen=%d\n", - pAddr[0], pAddr[1], pAddr[2], pAddr[3], pAddr[4], pAddr[5], Len, pEap->KeyDesc.KeyData[1])); - - bSTAKeyFrame = TRUE; - } -#endif - - } - else if (Len >= (LENGTH_802_11 + 6 + 2 + 2 + sizeof(EAPOL_PACKET) - MAX_LEN_OF_RSNIE)) - { -#if 0 - RTMPMoveMemory(pAd->StaCfg.ReplayCounter, pEap->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); - -#endif - RTMPMoveMemory(pAd->StaCfg.DlsReplayCounter, pEap->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); - DBGPRINT(RT_DEBUG_TRACE,("DLS - Sniff replay counter 2(%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x) Len=%ld, KeyDataLen=%d\n", - pAd->StaCfg.ReplayCounter[0], pAd->StaCfg.ReplayCounter[1], pAd->StaCfg.ReplayCounter[2], - pAd->StaCfg.ReplayCounter[3], pAd->StaCfg.ReplayCounter[4], pAd->StaCfg.ReplayCounter[5], - pAd->StaCfg.ReplayCounter[6], pAd->StaCfg.ReplayCounter[7], Len, pEap->KeyDesc.KeyData[1])); - - } - } - - // If timeout value is equaled to zero, it means always not be timeout. - // update local dls table entry - for (i= 0; i < MAX_NUM_OF_INIT_DLS_ENTRY; i++) - { - if (pAd->StaCfg.DLSEntry[i].Valid && MAC_ADDR_EQUAL(pAddr, pAd->StaCfg.DLSEntry[i].MacAddr)) - { - if (bSTAKeyFrame) - { - PMAC_TABLE_ENTRY pEntry; - - // STAKey frame, add pairwise key table - pAd->StaCfg.DLSEntry[i].Status = DLS_FINISH; - RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); - - PairwiseKey.KeyLen = LEN_TKIP_EK; - NdisMoveMemory(PairwiseKey.Key, &pSTAKey[0], LEN_TKIP_EK); - NdisMoveMemory(PairwiseKey.TxMic, &pSTAKey[16], LEN_TKIP_RXMICK); - NdisMoveMemory(PairwiseKey.RxMic, &pSTAKey[24], LEN_TKIP_TXMICK); - - PairwiseKey.CipherAlg = pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg; - - pEntry = DlsEntryTableLookup(pAd, pAd->StaCfg.DLSEntry[i].MacAddr, TRUE); - //AsicAddKeyEntry(pAd, (USHORT)(i + 2), BSS0, 0, &PairwiseKey, TRUE, TRUE); // reserve 0 for multicast, 1 for unicast - //AsicUpdateRxWCIDTable(pAd, (USHORT)(i + 2), pAddr); - // Add Pair-wise key to Asic -#ifdef RT2870 - { - RT_ADD_PAIRWISE_KEY_ENTRY KeyInfo; - COPY_MAC_ADDR(KeyInfo.MacAddr,pAd->StaCfg.DLSEntry[i].MacAddr); - KeyInfo.MacTabMatchWCID=pAd->StaCfg.DLSEntry[i].MacTabMatchWCID; - NdisMoveMemory(&KeyInfo.CipherKey, &PairwiseKey,sizeof(CIPHER_KEY)); - RTUSBEnqueueInternalCmd(pAd, RT_CMD_SET_KEY_TABLE, &KeyInfo, sizeof(RT_ADD_PAIRWISE_KEY_ENTRY)); - } - { - PMAC_TABLE_ENTRY pDLSEntry; - pDLSEntry = DlsEntryTableLookup(pAd, pAd->StaCfg.DLSEntry[i].MacAddr, TRUE); - pDLSEntry->PairwiseKey.CipherAlg=PairwiseKey.CipherAlg; - RTUSBEnqueueInternalCmd(pAd, RT_CMD_SET_RX_WCID_TABLE, pDLSEntry, sizeof(MAC_TABLE_ENTRY)); - } -#endif // RT2870 // - NdisMoveMemory(&pEntry->PairwiseKey, &PairwiseKey, sizeof(CIPHER_KEY)); - DBGPRINT(RT_DEBUG_TRACE,("DLS - Receive STAKey Message-1 (Peer STA MAC Address STAKey) \n")); - - RTMPSendSTAKeyHandShake(pAd, pAd->StaCfg.DLSEntry[i].MacAddr); - - DBGPRINT(RT_DEBUG_TRACE,("DLS - Finish STAKey handshake procedure (Initiator side)\n")); - } - else - { - // Data frame, update timeout value - if (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) - { - pAd->StaCfg.DLSEntry[i].CountDownTimer = pAd->StaCfg.DLSEntry[i].TimeOut; - //AsicUpdateRxWCIDTable(pAd, (USHORT)(i + 2), pAddr); - } - } - - bFindEntry = TRUE; - } - } - - // update peer dls table entry - for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid && MAC_ADDR_EQUAL(pAddr, pAd->StaCfg.DLSEntry[i].MacAddr)) - { - if (bSTAKeyFrame) - { - PMAC_TABLE_ENTRY pEntry = NULL; - - // STAKey frame, add pairwise key table, and send STAkey Msg-2 - pAd->StaCfg.DLSEntry[i].Status = DLS_FINISH; - RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); - - PairwiseKey.KeyLen = LEN_TKIP_EK; - NdisMoveMemory(PairwiseKey.Key, &pSTAKey[0], LEN_TKIP_EK); - NdisMoveMemory(PairwiseKey.TxMic, &pSTAKey[16], LEN_TKIP_RXMICK); - NdisMoveMemory(PairwiseKey.RxMic, &pSTAKey[24], LEN_TKIP_TXMICK); - - PairwiseKey.CipherAlg = pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg; - - pEntry = DlsEntryTableLookup(pAd, pAd->StaCfg.DLSEntry[i].MacAddr, TRUE); - //AsicAddKeyEntry(pAd, (USHORT)(i + 2), BSS0, 0, &PairwiseKey, TRUE, TRUE); // reserve 0 for multicast, 1 for unicast - //AsicUpdateRxWCIDTable(pAd, (USHORT)(i + 2), pAddr); - // Add Pair-wise key to Asic -#ifdef RT2870 - { - RT_ADD_PAIRWISE_KEY_ENTRY KeyInfo; - COPY_MAC_ADDR(KeyInfo.MacAddr,pAd->StaCfg.DLSEntry[i].MacAddr); - KeyInfo.MacTabMatchWCID=pAd->StaCfg.DLSEntry[i].MacTabMatchWCID; - NdisMoveMemory(&KeyInfo.CipherKey, &PairwiseKey,sizeof(CIPHER_KEY)); - RTUSBEnqueueInternalCmd(pAd, RT_CMD_SET_KEY_TABLE, &KeyInfo, sizeof(RT_ADD_PAIRWISE_KEY_ENTRY)); - } - { - PMAC_TABLE_ENTRY pDLSEntry; - pDLSEntry = DlsEntryTableLookup(pAd, pAd->StaCfg.DLSEntry[i].MacAddr, TRUE); - pDLSEntry->PairwiseKey.CipherAlg=PairwiseKey.CipherAlg; - RTUSBEnqueueInternalCmd(pAd, RT_CMD_SET_RX_WCID_TABLE, pDLSEntry, sizeof(MAC_TABLE_ENTRY)); - } -#endif // RT2870 // - NdisMoveMemory(&pEntry->PairwiseKey, &PairwiseKey, sizeof(CIPHER_KEY)); - DBGPRINT(RT_DEBUG_TRACE,("DLS - Receive STAKey Message-1 (Initiator STA MAC Address STAKey)\n")); - - // If support WPA or WPA2, start STAKey hand shake, - // If failed hand shake, just tear down peer DLS - if (RTMPSendSTAKeyHandShake(pAd, pAddr) != NDIS_STATUS_SUCCESS) - { - MLME_DLS_REQ_STRUCT MlmeDlsReq; - USHORT reason = REASON_QOS_CIPHER_NOT_SUPPORT; - - pAd->StaCfg.DLSEntry[i].Valid = FALSE; - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); - MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_TEAR_DOWN, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); - } - else - { - DBGPRINT(RT_DEBUG_TRACE,("DLS - Finish STAKey handshake procedure (Peer side)\n")); - } - } - else - { - // Data frame, update timeout value - if (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) - { - pAd->StaCfg.DLSEntry[i].CountDownTimer = pAd->StaCfg.DLSEntry[i].TimeOut; - } - } - - bFindEntry = TRUE; - } - } - - - return bSTAKeyFrame; -} - -/* - ======================================================================== - - Routine Description: - Check if the frame can be sent through DLS direct link interface - - Arguments: - pAd Pointer to adapter - - Return Value: - DLS entry index - - Note: - - ======================================================================== -*/ -INT RTMPCheckDLSFrame( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDA) -{ - INT rval = -1; - INT i; - - if (!pAd->CommonCfg.bDLSCapable) - return rval; - - if (!INFRA_ON(pAd)) - return rval; - - do{ - // check local dls table entry - for (i=0; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) && - MAC_ADDR_EQUAL(pDA, pAd->StaCfg.DLSEntry[i].MacAddr)) - { - rval = i; - break; - } - } - - // check peer dls table entry - for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) && - MAC_ADDR_EQUAL(pDA, pAd->StaCfg.DLSEntry[i].MacAddr)) - { - rval = i; - break; - } - } - } while (FALSE); - - return rval; -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID RTMPSendDLSTearDownFrame( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDA) -{ - PUCHAR pOutBuffer = NULL; - NDIS_STATUS NStatus; - HEADER_802_11 DlsTearDownHdr; - ULONG FrameLen = 0; - USHORT Reason = REASON_QOS_QSTA_LEAVING_QBSS; - UCHAR Category = CATEGORY_DLS; - UCHAR Action = ACTION_DLS_TEARDOWN; - UCHAR i = 0; - - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS) || - RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) - return; - - DBGPRINT(RT_DEBUG_TRACE, ("Send DLS TearDown Frame \n")); - - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory - if (NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_ERROR,("ASSOC - RTMPSendDLSTearDownFrame() allocate memory failed \n")); - return; - } - - ActHeaderInit(pAd, &DlsTearDownHdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pAd->CommonCfg.Bssid); - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(HEADER_802_11), &DlsTearDownHdr, - 1, &Category, - 1, &Action, - 6, pDA, - 6, pAd->CurrentAddress, - 2, &Reason, - END_OF_ARGS); - - MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); - - // Remove key in local dls table entry - for (i = 0; i < MAX_NUM_OF_INIT_DLS_ENTRY; i++) - { - if (pAd->StaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) - && MAC_ADDR_EQUAL(pDA, pAd->StaCfg.DLSEntry[i].MacAddr)) - { - MacTableDeleteDlsEntry(pAd, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID, pAd->StaCfg.DLSEntry[i].MacAddr); - } - } - - // Remove key in peer dls table entry - for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) - && MAC_ADDR_EQUAL(pDA, pAd->StaCfg.DLSEntry[i].MacAddr)) - { - MacTableDeleteDlsEntry(pAd, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID, pAd->StaCfg.DLSEntry[i].MacAddr); - } - } - - DBGPRINT(RT_DEBUG_TRACE, ("Send DLS TearDown Frame and remove key in (i=%d) \n", i)); -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -NDIS_STATUS RTMPSendSTAKeyRequest( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDA) -{ - UCHAR Header802_3[14]; - NDIS_STATUS NStatus; - ULONG FrameLen = 0; - EAPOL_PACKET Packet; - UCHAR Mic[16]; - UCHAR digest[80]; - PUCHAR pOutBuffer = NULL; - PNDIS_PACKET pNdisPacket; - UCHAR temp[64]; - UCHAR DlsPTK[80]; - - DBGPRINT(RT_DEBUG_TRACE,("DLS - RTMPSendSTAKeyRequest() to %02x:%02x:%02x:%02x:%02x:%02x\n", pDA[0], pDA[1], pDA[2], pDA[3], pDA[4], pDA[5])); - - pAd->Sequence ++; - MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL); - - // Zero message body - NdisZeroMemory(&Packet, sizeof(Packet)); - Packet.ProVer = EAPOL_VER; - Packet.ProType = EAPOLKey; - Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE + 6 + MAC_ADDR_LEN; // data field contain KDE andPeer MAC address - - // STAKey Message is as EAPOL-Key(1,1,0,0,G/0,0,0, MIC, 0,Peer MAC KDE) - if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) - { - Packet.KeyDesc.Type = WPA1_KEY_DESC; - } - else if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)) - { - Packet.KeyDesc.Type = WPA2_KEY_DESC; - } - - // Key descriptor version - Packet.KeyDesc.KeyInfo.KeyDescVer = - (((pAd->StaCfg.PairCipher == Ndis802_11Encryption3Enabled) || (pAd->StaCfg.GroupCipher == Ndis802_11Encryption3Enabled)) ? (DESC_TYPE_AES) : (DESC_TYPE_TKIP)); - - Packet.KeyDesc.KeyInfo.KeyMic = 1; - Packet.KeyDesc.KeyInfo.Secure = 1; - Packet.KeyDesc.KeyInfo.Request = 1; - - Packet.KeyDesc.KeyDataLen[1] = 12; - - // use our own OUI to distinguish proprietary with standard. - Packet.KeyDesc.KeyData[0] = 0xDD; - Packet.KeyDesc.KeyData[1] = 0x0A; - Packet.KeyDesc.KeyData[2] = 0x00; - Packet.KeyDesc.KeyData[3] = 0x0C; - Packet.KeyDesc.KeyData[4] = 0x43; - Packet.KeyDesc.KeyData[5] = 0x03; - NdisMoveMemory(&Packet.KeyDesc.KeyData[6], pDA, MAC_ADDR_LEN); - - NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pAd->StaCfg.DlsReplayCounter, LEN_KEY_DESC_REPLAY); - - // Allocate buffer for transmitting message - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); - if (NStatus != NDIS_STATUS_SUCCESS) - return NStatus; - - // Prepare EAPOL frame for MIC calculation - // Be careful, only EAPOL frame is counted for MIC calculation - MakeOutgoingFrame(pOutBuffer, &FrameLen, - Packet.Body_Len[1] + 4, &Packet, - END_OF_ARGS); - - // use proprietary PTK - NdisZeroMemory(temp, 64); - NdisMoveMemory(temp, "IEEE802.11 WIRELESS ACCESS POINT", 32); - WpaCountPTK(pAd, temp, temp, pAd->CommonCfg.Bssid, temp, pAd->CurrentAddress, DlsPTK, LEN_PTK); - - // calculate MIC - if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) - { - // AES - NdisZeroMemory(digest, sizeof(digest)); - HMAC_SHA1(pOutBuffer, FrameLen, DlsPTK, LEN_EAP_MICK, digest); - NdisMoveMemory(Packet.KeyDesc.KeyMic, digest, LEN_KEY_DESC_MIC); - } - else - { - NdisZeroMemory(Mic, sizeof(Mic)); - hmac_md5(DlsPTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic); - NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC); - } - - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(Header802_3), Header802_3, - Packet.Body_Len[1] + 4, &Packet, - END_OF_ARGS); - - NStatus = RTMPAllocateNdisPacket(pAd, &pNdisPacket, NULL, 0, pOutBuffer, FrameLen); - if (NStatus == NDIS_STATUS_SUCCESS) - { - RTMP_SET_PACKET_WCID(pNdisPacket, BSSID_WCID); - STASendPacket(pAd, pNdisPacket); - RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, MAX_TX_PROCESS); - } - - MlmeFreeMemory(pAd, pOutBuffer); - - DBGPRINT(RT_DEBUG_TRACE, ("RTMPSendSTAKeyRequest- Send STAKey request (NStatus=%x, FrameLen=%ld)\n", NStatus, FrameLen)); - - return NStatus; -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -NDIS_STATUS RTMPSendSTAKeyHandShake( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDA) -{ - UCHAR Header802_3[14]; - NDIS_STATUS NStatus; - ULONG FrameLen = 0; - EAPOL_PACKET Packet; - UCHAR Mic[16]; - UCHAR digest[80]; - PUCHAR pOutBuffer = NULL; - PNDIS_PACKET pNdisPacket; - UCHAR temp[64]; - UCHAR DlsPTK[80]; // Due to dirver can not get PTK, use proprietary PTK - - DBGPRINT(RT_DEBUG_TRACE,("DLS - RTMPSendSTAKeyHandShake() to %02x:%02x:%02x:%02x:%02x:%02x\n", pDA[0], pDA[1], pDA[2], pDA[3], pDA[4], pDA[5])); - - pAd->Sequence ++; - MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL); - - // Zero message body - NdisZeroMemory(&Packet, sizeof(Packet)); - Packet.ProVer = EAPOL_VER; - Packet.ProType = EAPOLKey; - Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE + 6 + MAC_ADDR_LEN; // data field contain KDE and Peer MAC address - - // STAKey Message is as EAPOL-Key(1,1,0,0,G/0,0,0, MIC, 0,Peer MAC KDE) - if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) - { - Packet.KeyDesc.Type = WPA1_KEY_DESC; - } - else if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)) - { - Packet.KeyDesc.Type = WPA2_KEY_DESC; - } - - // Key descriptor version - Packet.KeyDesc.KeyInfo.KeyDescVer = - (((pAd->StaCfg.PairCipher == Ndis802_11Encryption3Enabled) || (pAd->StaCfg.GroupCipher == Ndis802_11Encryption3Enabled)) ? (DESC_TYPE_AES) : (DESC_TYPE_TKIP)); - - Packet.KeyDesc.KeyInfo.KeyMic = 1; - Packet.KeyDesc.KeyInfo.Secure = 1; - - Packet.KeyDesc.KeyDataLen[1] = 12; - - // use our own OUI to distinguish proprietary with standard. - Packet.KeyDesc.KeyData[0] = 0xDD; - Packet.KeyDesc.KeyData[1] = 0x0A; - Packet.KeyDesc.KeyData[2] = 0x00; - Packet.KeyDesc.KeyData[3] = 0x0C; - Packet.KeyDesc.KeyData[4] = 0x43; - Packet.KeyDesc.KeyData[5] = 0x03; - NdisMoveMemory(&Packet.KeyDesc.KeyData[6], pDA, MAC_ADDR_LEN); - - NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pAd->StaCfg.DlsReplayCounter, LEN_KEY_DESC_REPLAY); - - // Allocate buffer for transmitting message - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); - if (NStatus != NDIS_STATUS_SUCCESS) - return NStatus; - - // Prepare EAPOL frame for MIC calculation - // Be careful, only EAPOL frame is counted for MIC calculation - MakeOutgoingFrame(pOutBuffer, &FrameLen, - Packet.Body_Len[1] + 4, &Packet, - END_OF_ARGS); - - // use proprietary PTK - NdisZeroMemory(temp, 64); - NdisMoveMemory(temp, "IEEE802.11 WIRELESS ACCESS POINT", 32); - WpaCountPTK(pAd, temp, temp, pAd->CommonCfg.Bssid, temp, pAd->CurrentAddress, DlsPTK, LEN_PTK); - - // calculate MIC - if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) - { - // AES - NdisZeroMemory(digest, sizeof(digest)); - HMAC_SHA1(pOutBuffer, FrameLen, DlsPTK, LEN_EAP_MICK, digest); - NdisMoveMemory(Packet.KeyDesc.KeyMic, digest, LEN_KEY_DESC_MIC); - } - else - { - NdisZeroMemory(Mic, sizeof(Mic)); - hmac_md5(DlsPTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic); - NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC); - } - - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(Header802_3), Header802_3, - Packet.Body_Len[1] + 4, &Packet, - END_OF_ARGS); - - NStatus = RTMPAllocateNdisPacket(pAd, &pNdisPacket, NULL, 0, pOutBuffer, FrameLen); - if (NStatus == NDIS_STATUS_SUCCESS) - { - RTMP_SET_PACKET_WCID(pNdisPacket, BSSID_WCID); - STASendPacket(pAd, pNdisPacket); - RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, MAX_TX_PROCESS); - } - - MlmeFreeMemory(pAd, pOutBuffer); - - DBGPRINT(RT_DEBUG_TRACE, ("RTMPSendSTAKeyHandShake- Send STAKey Message-2 (NStatus=%x, FrameLen=%ld)\n", NStatus, FrameLen)); - - return NStatus; -} - -VOID DlsTimeoutAction( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3) -{ - MLME_DLS_REQ_STRUCT MlmeDlsReq; - USHORT reason; - PRT_802_11_DLS pDLS = (PRT_802_11_DLS)FunctionContext; - PRTMP_ADAPTER pAd = pDLS->pAd; - - DBGPRINT(RT_DEBUG_TRACE, ("DlsTimeout - Tear down DLS links (%02x:%02x:%02x:%02x:%02x:%02x)\n", - pDLS->MacAddr[0], pDLS->MacAddr[1], pDLS->MacAddr[2], pDLS->MacAddr[3], pDLS->MacAddr[4], pDLS->MacAddr[5])); - - if ((pDLS) && (pDLS->Valid)) - { - reason = REASON_QOS_REQUEST_TIMEOUT; - pDLS->Valid = FALSE; - pDLS->Status = DLS_NONE; - DlsParmFill(pAd, &MlmeDlsReq, pDLS, reason); - MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_TEAR_DOWN, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); - RT28XX_MLME_HANDLER(pAd); - } -} - -/* -================================================================ -Description : because DLS and CLI share the same WCID table in ASIC. -Mesh entry also insert to pAd->MacTab.content[]. Such is marked as ValidAsDls = TRUE. -Also fills the pairwise key. -Because front MAX_AID_BA entries have direct mapping to BAEntry, which is only used as CLI. So we insert Dls -from index MAX_AID_BA. -================================================================ -*/ -MAC_TABLE_ENTRY *MacTableInsertDlsEntry( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pAddr, - IN UINT DlsEntryIdx) -{ - PMAC_TABLE_ENTRY pEntry = NULL; - - DBGPRINT(RT_DEBUG_TRACE, ("====> MacTableInsertDlsEntry\n")); - // if FULL, return - if (pAd->MacTab.Size >= MAX_LEN_OF_MAC_TABLE) - return NULL; - - do - { - if((pEntry = DlsEntryTableLookup(pAd, pAddr, TRUE)) != NULL) - break; - - // allocate one MAC entry - pEntry = MacTableInsertEntry(pAd, pAddr, DlsEntryIdx + MIN_NET_DEVICE_FOR_DLS, TRUE); - if (pEntry) - { - pAd->StaCfg.DLSEntry[DlsEntryIdx].MacTabMatchWCID = pEntry->Aid; - pEntry->MatchDlsEntryIdx = DlsEntryIdx; - pEntry->AuthMode = pAd->StaCfg.AuthMode; - pEntry->WepStatus = pAd->StaCfg.WepStatus; - pEntry->PortSecured = WPA_802_1X_PORT_SECURED; - - DBGPRINT(RT_DEBUG_TRACE, ("MacTableInsertDlsEntry - allocate entry #%d, Total= %d\n",pEntry->Aid, pAd->MacTab.Size)); - - // If legacy WEP is used, set pair-wise cipherAlg into WCID attribute table for this entry - if ((pEntry->ValidAsDls) && (pEntry->WepStatus == Ndis802_11WEPEnabled)) - { - UCHAR KeyIdx = 0; - UCHAR CipherAlg = 0; - - KeyIdx = pAd->StaCfg.DefaultKeyId; - - CipherAlg = pAd->SharedKey[BSS0][KeyIdx].CipherAlg; - - RTMPAddWcidAttributeEntry(pAd, - BSS0, - pAd->StaCfg.DefaultKeyId, - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, - pEntry); - } - - break; - } - } while(FALSE); - - DBGPRINT(RT_DEBUG_TRACE, ("<==== MacTableInsertDlsEntry\n")); - - return pEntry; -} - - -/* - ========================================================================== - Description: - Delete all Mesh Entry in pAd->MacTab - ========================================================================== - */ -BOOLEAN MacTableDeleteDlsEntry( - IN PRTMP_ADAPTER pAd, - IN USHORT wcid, - IN PUCHAR pAddr) -{ - DBGPRINT(RT_DEBUG_TRACE, ("====> MacTableDeleteDlsEntry\n")); - - if (!VALID_WCID(wcid)) - return FALSE; - - MacTableDeleteEntry(pAd, wcid, pAddr); - - DBGPRINT(RT_DEBUG_TRACE, ("<==== MacTableDeleteDlsEntry\n")); - - return TRUE; -} - -MAC_TABLE_ENTRY *DlsEntryTableLookup( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pAddr, - IN BOOLEAN bResetIdelCount) -{ - ULONG HashIdx; - MAC_TABLE_ENTRY *pEntry = NULL; - - RTMP_SEM_LOCK(&pAd->MacTabLock); - HashIdx = MAC_ADDR_HASH_INDEX(pAddr); - pEntry = pAd->MacTab.Hash[HashIdx]; - - while (pEntry) - { - if ((pEntry->ValidAsDls == TRUE) - && MAC_ADDR_EQUAL(pEntry->Addr, pAddr)) - { - if(bResetIdelCount) - pEntry->NoDataIdleCount = 0; - break; - } - else - pEntry = pEntry->pNext; - } - - RTMP_SEM_UNLOCK(&pAd->MacTabLock); - return pEntry; -} - -MAC_TABLE_ENTRY *DlsEntryTableLookupByWcid( - IN PRTMP_ADAPTER pAd, - IN UCHAR wcid, - IN PUCHAR pAddr, - IN BOOLEAN bResetIdelCount) -{ - ULONG DLsIndex; - PMAC_TABLE_ENTRY pCurEntry = NULL; - PMAC_TABLE_ENTRY pEntry = NULL; - - if (!VALID_WCID(wcid)) - return NULL; - - RTMP_SEM_LOCK(&pAd->MacTabLock); - - do - { - pCurEntry = &pAd->MacTab.Content[wcid]; - - DLsIndex = 0xff; - if ((pCurEntry) && (pCurEntry->ValidAsDls== TRUE)) - { - DLsIndex = pCurEntry->MatchDlsEntryIdx; - } - - if (DLsIndex == 0xff) - break; - - if (MAC_ADDR_EQUAL(pCurEntry->Addr, pAddr)) - { - if(bResetIdelCount) - pCurEntry->NoDataIdleCount = 0; - pEntry = pCurEntry; - break; - } - } while(FALSE); - - RTMP_SEM_UNLOCK(&pAd->MacTabLock); - - return pEntry; -} - -INT Set_DlsEntryInfo_Display_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - INT i; - - printk("\n%-19s%-8s\n", "MAC", "TIMEOUT\n"); - for (i=0; iStaCfg.DLSEntry[i].Valid) && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH)) - { - PMAC_TABLE_ENTRY pEntry = &pAd->MacTab.Content[pAd->StaCfg.DLSEntry[i].MacTabMatchWCID]; - - printk("%02x:%02x:%02x:%02x:%02x:%02x ", - pAd->StaCfg.DLSEntry[i].MacAddr[0], pAd->StaCfg.DLSEntry[i].MacAddr[1], pAd->StaCfg.DLSEntry[i].MacAddr[2], - pAd->StaCfg.DLSEntry[i].MacAddr[3], pAd->StaCfg.DLSEntry[i].MacAddr[4], pAd->StaCfg.DLSEntry[i].MacAddr[5]); - printk("%-8d\n", pAd->StaCfg.DLSEntry[i].TimeOut); - - printk("\n"); - printk("\n%-19s%-4s%-4s%-4s%-4s%-7s%-7s%-7s","MAC", "AID", "BSS", "PSM", "WMM", "RSSI0", "RSSI1", "RSSI2"); -#ifdef DOT11_N_SUPPORT - printk("%-8s%-10s%-6s%-6s%-6s%-6s", "MIMOPS", "PhMd", "BW", "MCS", "SGI", "STBC"); -#endif // DOT11_N_SUPPORT // - printk("\n%02X:%02X:%02X:%02X:%02X:%02X ", - pEntry->Addr[0], pEntry->Addr[1], pEntry->Addr[2], - pEntry->Addr[3], pEntry->Addr[4], pEntry->Addr[5]); - printk("%-4d", (int)pEntry->Aid); - printk("%-4d", (int)pEntry->apidx); - printk("%-4d", (int)pEntry->PsMode); - printk("%-4d", (int)CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_WMM_CAPABLE)); - printk("%-7d", pEntry->RssiSample.AvgRssi0); - printk("%-7d", pEntry->RssiSample.AvgRssi1); - printk("%-7d", pEntry->RssiSample.AvgRssi2); -#ifdef DOT11_N_SUPPORT - printk("%-8d", (int)pEntry->MmpsMode); - printk("%-10s", GetPhyMode(pEntry->HTPhyMode.field.MODE)); - printk("%-6s", GetBW(pEntry->HTPhyMode.field.BW)); - printk("%-6d", pEntry->HTPhyMode.field.MCS); - printk("%-6d", pEntry->HTPhyMode.field.ShortGI); - printk("%-6d", pEntry->HTPhyMode.field.STBC); -#endif // DOT11_N_SUPPORT // - printk("%-10d, %d, %d%%\n", pEntry->DebugFIFOCount, pEntry->DebugTxCount, - (pEntry->DebugTxCount) ? ((pEntry->DebugTxCount-pEntry->DebugFIFOCount)*100/pEntry->DebugTxCount) : 0); - printk("\n"); - - } - } - - return TRUE; -} - -INT Set_DlsAddEntry_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - UCHAR mac[MAC_ADDR_LEN]; - USHORT Timeout; - char *token, sepValue[] = ":", DASH = '-'; - INT i; - RT_802_11_DLS Dls; - - if(strlen(arg) < 19) //Mac address acceptable format 01:02:03:04:05:06 length 17 plus the "-" and timeout value in decimal format. - return FALSE; - - token = strchr(arg, DASH); - if ((token != NULL) && (strlen(token)>1)) - { - Timeout = simple_strtol((token+1), 0, 10); - - *token = '\0'; - for (i = 0, token = rstrtok(arg, &sepValue[0]); token; token = rstrtok(NULL, &sepValue[0]), i++) - { - if((strlen(token) != 2) || (!isxdigit(*token)) || (!isxdigit(*(token+1)))) - return FALSE; - AtoH(token, (PUCHAR)(&mac[i]), 1); - } - if(i != 6) - return FALSE; - - printk("\n%02x:%02x:%02x:%02x:%02x:%02x-%d", mac[0], mac[1], - mac[2], mac[3], mac[4], mac[5], (int)Timeout); - - NdisZeroMemory(&Dls, sizeof(RT_802_11_DLS)); - Dls.TimeOut = Timeout; - COPY_MAC_ADDR(Dls.MacAddr, mac); - Dls.Valid = 1; - - MlmeEnqueue(pAd, - MLME_CNTL_STATE_MACHINE, - RT_OID_802_11_SET_DLS_PARAM, - sizeof(RT_802_11_DLS), - &Dls); - - return TRUE; - } - - return FALSE; - -} - -INT Set_DlsTearDownEntry_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - UCHAR macAddr[MAC_ADDR_LEN]; - CHAR *value; - INT i; - RT_802_11_DLS Dls; - - if(strlen(arg) != 17) //Mac address acceptable format 01:02:03:04:05:06 length 17 - return FALSE; - - for (i=0, value = rstrtok(arg,":"); value; value = rstrtok(NULL,":")) - { - if((strlen(value) != 2) || (!isxdigit(*value)) || (!isxdigit(*(value+1))) ) - return FALSE; //Invalid - - AtoH(value, &macAddr[i++], 2); - } - - printk("\n%02x:%02x:%02x:%02x:%02x:%02x", macAddr[0], macAddr[1], - macAddr[2], macAddr[3], macAddr[4], macAddr[5]); - - NdisZeroMemory(&Dls, sizeof(RT_802_11_DLS)); - COPY_MAC_ADDR(Dls.MacAddr, macAddr); - Dls.Valid = 0; - - MlmeEnqueue(pAd, - MLME_CNTL_STATE_MACHINE, - RT_OID_802_11_SET_DLS_PARAM, - sizeof(RT_802_11_DLS), - &Dls); - - return TRUE; -} - diff --git a/drivers/staging/rt2870/sta/rtmp_data.c b/drivers/staging/rt2870/sta/rtmp_data.c index 9942ecaf5e2e..b67e06952bcf 100644 --- a/drivers/staging/rt2870/sta/rtmp_data.c +++ b/drivers/staging/rt2870/sta/rtmp_data.c @@ -1,2619 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - rtmp_data.c - - Abstract: - Data path subroutines - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - John Aug/17/04 major modification for RT2561/2661 - Jan Lee Mar/17/06 major modification for RT2860 New Ring Design -*/ -#include "../rt_config.h" - - -VOID STARxEAPOLFrameIndicate( - IN PRTMP_ADAPTER pAd, - IN MAC_TABLE_ENTRY *pEntry, - IN RX_BLK *pRxBlk, - IN UCHAR FromWhichBSSID) -{ - PRT28XX_RXD_STRUC pRxD = &(pRxBlk->RxD); - PRXWI_STRUC pRxWI = pRxBlk->pRxWI; - UCHAR *pTmpBuf; - -#ifdef WPA_SUPPLICANT_SUPPORT - if (pAd->StaCfg.WpaSupplicantUP) - { - // All EAPoL frames have to pass to upper layer (ex. WPA_SUPPLICANT daemon) - // TBD : process fragmented EAPol frames - { - // In 802.1x mode, if the received frame is EAP-SUCCESS packet, turn on the PortSecured variable - if ( pAd->StaCfg.IEEE8021X == TRUE && - (EAP_CODE_SUCCESS == WpaCheckEapCode(pAd, pRxBlk->pData, pRxBlk->DataSize, LENGTH_802_1_H))) - { - PUCHAR Key; - UCHAR CipherAlg; - int idx = 0; - - DBGPRINT_RAW(RT_DEBUG_TRACE, ("Receive EAP-SUCCESS Packet\n")); - //pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; - STA_PORT_SECURED(pAd); - - if (pAd->StaCfg.IEEE8021x_required_keys == FALSE) - { - idx = pAd->StaCfg.DesireSharedKeyId; - CipherAlg = pAd->StaCfg.DesireSharedKey[idx].CipherAlg; - Key = pAd->StaCfg.DesireSharedKey[idx].Key; - - if (pAd->StaCfg.DesireSharedKey[idx].KeyLen > 0) - { -#ifdef RT2870 - union - { - char buf[sizeof(NDIS_802_11_WEP)+MAX_LEN_OF_KEY- 1]; - NDIS_802_11_WEP keyinfo; - } WepKey; - int len; - - - NdisZeroMemory(&WepKey, sizeof(WepKey)); - len =pAd->StaCfg.DesireSharedKey[idx].KeyLen; - - NdisMoveMemory(WepKey.keyinfo.KeyMaterial, - pAd->StaCfg.DesireSharedKey[idx].Key, - pAd->StaCfg.DesireSharedKey[idx].KeyLen); - - WepKey.keyinfo.KeyIndex = 0x80000000 + idx; - WepKey.keyinfo.KeyLength = len; - pAd->SharedKey[BSS0][idx].KeyLen =(UCHAR) (len <= 5 ? 5 : 13); - - pAd->IndicateMediaState = NdisMediaStateConnected; - pAd->ExtraInfo = GENERAL_LINK_UP; - // need to enqueue cmd to thread - RTUSBEnqueueCmdFromNdis(pAd, OID_802_11_ADD_WEP, TRUE, &WepKey, sizeof(WepKey.keyinfo) + len - 1); -#endif // RT2870 // - // For Preventing ShardKey Table is cleared by remove key procedure. - pAd->SharedKey[BSS0][idx].CipherAlg = CipherAlg; - pAd->SharedKey[BSS0][idx].KeyLen = pAd->StaCfg.DesireSharedKey[idx].KeyLen; - NdisMoveMemory(pAd->SharedKey[BSS0][idx].Key, - pAd->StaCfg.DesireSharedKey[idx].Key, - pAd->StaCfg.DesireSharedKey[idx].KeyLen); - } - } - } - - Indicate_Legacy_Packet(pAd, pRxBlk, FromWhichBSSID); - return; - } - } - else -#endif // WPA_SUPPLICANT_SUPPORT // - { - // Special DATA frame that has to pass to MLME - // 1. Cisco Aironet frames for CCX2. We need pass it to MLME for special process - // 2. EAPOL handshaking frames when driver supplicant enabled, pass to MLME for special process - { - pTmpBuf = pRxBlk->pData - LENGTH_802_11; - NdisMoveMemory(pTmpBuf, pRxBlk->pHeader, LENGTH_802_11); - REPORT_MGMT_FRAME_TO_MLME(pAd, pRxWI->WirelessCliID, pTmpBuf, pRxBlk->DataSize + LENGTH_802_11, pRxWI->RSSI0, pRxWI->RSSI1, pRxWI->RSSI2, pRxD->PlcpSignal); - DBGPRINT_RAW(RT_DEBUG_TRACE, ("!!! report EAPOL/AIRONET DATA to MLME (len=%d) !!!\n", pRxBlk->DataSize)); - } - } - - RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); - return; - -} - -VOID STARxDataFrameAnnounce( - IN PRTMP_ADAPTER pAd, - IN MAC_TABLE_ENTRY *pEntry, - IN RX_BLK *pRxBlk, - IN UCHAR FromWhichBSSID) -{ - - // non-EAP frame - if (!RTMPCheckWPAframe(pAd, pEntry, pRxBlk->pData, pRxBlk->DataSize, FromWhichBSSID)) - { - { - // drop all non-EAP DATA frame before - // this client's Port-Access-Control is secured - if (pRxBlk->pHeader->FC.Wep) - { - // unsupported cipher suite - if (pAd->StaCfg.WepStatus == Ndis802_11EncryptionDisabled) - { - // release packet - RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); - return; - } - } - else - { - // encryption in-use but receive a non-EAPOL clear text frame, drop it - if ((pAd->StaCfg.WepStatus != Ndis802_11EncryptionDisabled) && - (pAd->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED)) - { - // release packet - RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); - return; - } - } - } - RX_BLK_CLEAR_FLAG(pRxBlk, fRX_EAP); - if (!RX_BLK_TEST_FLAG(pRxBlk, fRX_ARALINK)) - { - // Normal legacy, AMPDU or AMSDU - CmmRxnonRalinkFrameIndicate(pAd, pRxBlk, FromWhichBSSID); - - } - else - { - // ARALINK - CmmRxRalinkFrameIndicate(pAd, pEntry, pRxBlk, FromWhichBSSID); - } -#ifdef QOS_DLS_SUPPORT - RX_BLK_CLEAR_FLAG(pRxBlk, fRX_DLS); -#endif // QOS_DLS_SUPPORT // - } - else - { - RX_BLK_SET_FLAG(pRxBlk, fRX_EAP); -#ifdef DOT11_N_SUPPORT - if (RX_BLK_TEST_FLAG(pRxBlk, fRX_AMPDU) && (pAd->CommonCfg.bDisableReordering == 0)) - { - Indicate_AMPDU_Packet(pAd, pRxBlk, FromWhichBSSID); - } - else -#endif // DOT11_N_SUPPORT // - { - // Determin the destination of the EAP frame - // to WPA state machine or upper layer - STARxEAPOLFrameIndicate(pAd, pEntry, pRxBlk, FromWhichBSSID); - } - } -} - - -// For TKIP frame, calculate the MIC value -BOOLEAN STACheckTkipMICValue( - IN PRTMP_ADAPTER pAd, - IN MAC_TABLE_ENTRY *pEntry, - IN RX_BLK *pRxBlk) -{ - PHEADER_802_11 pHeader = pRxBlk->pHeader; - UCHAR *pData = pRxBlk->pData; - USHORT DataSize = pRxBlk->DataSize; - UCHAR UserPriority = pRxBlk->UserPriority; - PCIPHER_KEY pWpaKey; - UCHAR *pDA, *pSA; - - pWpaKey = &pAd->SharedKey[BSS0][pRxBlk->pRxWI->KeyIndex]; - - pDA = pHeader->Addr1; - if (RX_BLK_TEST_FLAG(pRxBlk, fRX_INFRA)) - { - pSA = pHeader->Addr3; - } - else - { - pSA = pHeader->Addr2; - } - - if (RTMPTkipCompareMICValue(pAd, - pData, - pDA, - pSA, - pWpaKey->RxMic, - UserPriority, - DataSize) == FALSE) - { - DBGPRINT_RAW(RT_DEBUG_ERROR,("Rx MIC Value error 2\n")); - -#ifdef WPA_SUPPLICANT_SUPPORT - if (pAd->StaCfg.WpaSupplicantUP) - { - WpaSendMicFailureToWpaSupplicant(pAd, (pWpaKey->Type == PAIRWISEKEY) ? TRUE : FALSE); - } - else -#endif // WPA_SUPPLICANT_SUPPORT // - { - RTMPReportMicError(pAd, pWpaKey); - } - - // release packet - RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); - return FALSE; - } - - return TRUE; -} - - -// -// All Rx routines use RX_BLK structure to hande rx events -// It is very important to build pRxBlk attributes -// 1. pHeader pointer to 802.11 Header -// 2. pData pointer to payload including LLC (just skip Header) -// 3. set payload size including LLC to DataSize -// 4. set some flags with RX_BLK_SET_FLAG() -// -VOID STAHandleRxDataFrame( - IN PRTMP_ADAPTER pAd, - IN RX_BLK *pRxBlk) -{ - PRT28XX_RXD_STRUC pRxD = &(pRxBlk->RxD); - PRXWI_STRUC pRxWI = pRxBlk->pRxWI; - PHEADER_802_11 pHeader = pRxBlk->pHeader; - PNDIS_PACKET pRxPacket = pRxBlk->pRxPacket; - BOOLEAN bFragment = FALSE; - MAC_TABLE_ENTRY *pEntry = NULL; - UCHAR FromWhichBSSID = BSS0; - UCHAR UserPriority = 0; - - { - // before LINK UP, all DATA frames are rejected - if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) - { - // release packet - RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); - return; - } - -#ifdef QOS_DLS_SUPPORT - //if ((pHeader->FC.FrDs == 0) && (pHeader->FC.ToDs == 0)) - if (RTMPRcvFrameDLSCheck(pAd, pHeader, pRxWI->MPDUtotalByteCount, pRxD)) - { - return; - } -#endif // QOS_DLS_SUPPORT // - - // Drop not my BSS frames - if (pRxD->MyBss == 0) - { - { - // release packet - RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); - return; - } - } - - pAd->RalinkCounters.RxCountSinceLastNULL++; - if (pAd->CommonCfg.bAPSDCapable && pAd->CommonCfg.APEdcaParm.bAPSDCapable && (pHeader->FC.SubType & 0x08)) - { - UCHAR *pData; - DBGPRINT(RT_DEBUG_TRACE,("bAPSDCapable\n")); - - // Qos bit 4 - pData = (PUCHAR)pHeader + LENGTH_802_11; - if ((*pData >> 4) & 0x01) - { - DBGPRINT(RT_DEBUG_TRACE,("RxDone- Rcv EOSP frame, driver may fall into sleep\n")); - pAd->CommonCfg.bInServicePeriod = FALSE; - - // Force driver to fall into sleep mode when rcv EOSP frame - if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) - { - USHORT TbttNumToNextWakeUp; - USHORT NextDtim = pAd->StaCfg.DtimPeriod; - ULONG Now; - - NdisGetSystemUpTime(&Now); - NextDtim -= (USHORT)(Now - pAd->StaCfg.LastBeaconRxTime)/pAd->CommonCfg.BeaconPeriod; - - TbttNumToNextWakeUp = pAd->StaCfg.DefaultListenCount; - if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_RECEIVE_DTIM) && (TbttNumToNextWakeUp > NextDtim)) - TbttNumToNextWakeUp = NextDtim; - - MlmeSetPsmBit(pAd, PWR_SAVE); - // if WMM-APSD is failed, try to disable following line - AsicSleepThenAutoWakeup(pAd, TbttNumToNextWakeUp); - } - } - - if ((pHeader->FC.MoreData) && (pAd->CommonCfg.bInServicePeriod)) - { - DBGPRINT(RT_DEBUG_TRACE,("Sending another trigger frame when More Data bit is set to 1\n")); - } - } - - // Drop NULL, CF-ACK(no data), CF-POLL(no data), and CF-ACK+CF-POLL(no data) data frame - if ((pHeader->FC.SubType & 0x04)) // bit 2 : no DATA - { - // release packet - RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); - return; - } - - // Drop not my BSS frame (we can not only check the MyBss bit in RxD) -#ifdef QOS_DLS_SUPPORT - if (!pAd->CommonCfg.bDLSCapable) - { -#endif // QOS_DLS_SUPPORT // - if (INFRA_ON(pAd)) - { - // Infrastructure mode, check address 2 for BSSID - if (!RTMPEqualMemory(&pHeader->Addr2, &pAd->CommonCfg.Bssid, 6)) - { - // Receive frame not my BSSID - // release packet - RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); - return; - } - } - else // Ad-Hoc mode or Not associated - { - // Ad-Hoc mode, check address 3 for BSSID - if (!RTMPEqualMemory(&pHeader->Addr3, &pAd->CommonCfg.Bssid, 6)) - { - // Receive frame not my BSSID - // release packet - RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); - return; - } - } -#ifdef QOS_DLS_SUPPORT - } -#endif // QOS_DLS_SUPPORT // - - // - // find pEntry - // - if (pRxWI->WirelessCliID < MAX_LEN_OF_MAC_TABLE) - { - pEntry = &pAd->MacTab.Content[pRxWI->WirelessCliID]; - } - else - { - // 1. release packet if infra mode - // 2. new a pEntry if ad-hoc mode - RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); - return; - } - - // infra or ad-hoc - if (INFRA_ON(pAd)) - { - RX_BLK_SET_FLAG(pRxBlk, fRX_INFRA); -#ifdef QOS_DLS_SUPPORT - if ((pHeader->FC.FrDs == 0) && (pHeader->FC.ToDs == 0)) - RX_BLK_SET_FLAG(pRxBlk, fRX_DLS); - else -#endif // QOS_DLS_SUPPORT // - ASSERT(pRxWI->WirelessCliID == BSSID_WCID); - } - - // check Atheros Client - if ((pEntry->bIAmBadAtheros == FALSE) && (pRxD->AMPDU == 1) && (pHeader->FC.Retry )) - { - pEntry->bIAmBadAtheros = TRUE; - pAd->CommonCfg.IOTestParm.bCurrentAtheros = TRUE; - pAd->CommonCfg.IOTestParm.bLastAtheros = TRUE; - if (!STA_AES_ON(pAd)) - { - AsicUpdateProtect(pAd, 8, ALLN_SETPROTECT, TRUE, FALSE); - } - } - } - - pRxBlk->pData = (UCHAR *)pHeader; - - // - // update RxBlk->pData, DataSize - // 802.11 Header, QOS, HTC, Hw Padding - // - - // 1. skip 802.11 HEADER - { - pRxBlk->pData += LENGTH_802_11; - pRxBlk->DataSize -= LENGTH_802_11; - } - - // 2. QOS - if (pHeader->FC.SubType & 0x08) - { - RX_BLK_SET_FLAG(pRxBlk, fRX_QOS); - UserPriority = *(pRxBlk->pData) & 0x0f; - // bit 7 in QoS Control field signals the HT A-MSDU format - if ((*pRxBlk->pData) & 0x80) - { - RX_BLK_SET_FLAG(pRxBlk, fRX_AMSDU); - } - - // skip QOS contorl field - pRxBlk->pData += 2; - pRxBlk->DataSize -=2; - } - pRxBlk->UserPriority = UserPriority; - - // 3. Order bit: A-Ralink or HTC+ - if (pHeader->FC.Order) - { -#ifdef AGGREGATION_SUPPORT - if ((pRxWI->PHYMODE <= MODE_OFDM) && (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED))) - { - RX_BLK_SET_FLAG(pRxBlk, fRX_ARALINK); - } - else -#endif - { -#ifdef DOT11_N_SUPPORT - RX_BLK_SET_FLAG(pRxBlk, fRX_HTC); - // skip HTC contorl field - pRxBlk->pData += 4; - pRxBlk->DataSize -= 4; -#endif // DOT11_N_SUPPORT // - } - } - - // 4. skip HW padding - if (pRxD->L2PAD) - { - // just move pData pointer - // because DataSize excluding HW padding - RX_BLK_SET_FLAG(pRxBlk, fRX_PAD); - pRxBlk->pData += 2; - } - -#ifdef DOT11_N_SUPPORT - if (pRxD->BA) - { - RX_BLK_SET_FLAG(pRxBlk, fRX_AMPDU); - } -#endif // DOT11_N_SUPPORT // - - - // - // Case I Process Broadcast & Multicast data frame - // - if (pRxD->Bcast || pRxD->Mcast) - { - INC_COUNTER64(pAd->WlanCounters.MulticastReceivedFrameCount); - - // Drop Mcast/Bcast frame with fragment bit on - if (pHeader->FC.MoreFrag) - { - // release packet - RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); - return; - } - - // Filter out Bcast frame which AP relayed for us - if (pHeader->FC.FrDs && MAC_ADDR_EQUAL(pHeader->Addr3, pAd->CurrentAddress)) - { - // release packet - RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); - return; - } - - Indicate_Legacy_Packet(pAd, pRxBlk, FromWhichBSSID); - return; - } - else if (pRxD->U2M) - { - pAd->LastRxRate = (USHORT)((pRxWI->MCS) + (pRxWI->BW <<7) + (pRxWI->ShortGI <<8)+ (pRxWI->PHYMODE <<14)) ; - - -#ifdef QOS_DLS_SUPPORT - if (RX_BLK_TEST_FLAG(pRxBlk, fRX_DLS)) - { - MAC_TABLE_ENTRY *pDlsEntry = NULL; - - pDlsEntry = DlsEntryTableLookupByWcid(pAd, pRxWI->WirelessCliID, pHeader->Addr2, TRUE); - if(pDlsEntry) - Update_Rssi_Sample(pAd, &pDlsEntry->RssiSample, pRxWI); - } - else -#endif // QOS_DLS_SUPPORT // - if (ADHOC_ON(pAd)) - { - pEntry = MacTableLookup(pAd, pHeader->Addr2); - if (pEntry) - Update_Rssi_Sample(pAd, &pEntry->RssiSample, pRxWI); - } - - - Update_Rssi_Sample(pAd, &pAd->StaCfg.RssiSample, pRxWI); - - pAd->StaCfg.LastSNR0 = (UCHAR)(pRxWI->SNR0); - pAd->StaCfg.LastSNR1 = (UCHAR)(pRxWI->SNR1); - - pAd->RalinkCounters.OneSecRxOkDataCnt++; - - - if (!((pHeader->Frag == 0) && (pHeader->FC.MoreFrag == 0))) - { - // re-assemble the fragmented packets - // return complete frame (pRxPacket) or NULL - bFragment = TRUE; - pRxPacket = RTMPDeFragmentDataFrame(pAd, pRxBlk); - } - - if (pRxPacket) - { - pEntry = &pAd->MacTab.Content[pRxWI->WirelessCliID]; - - // process complete frame - if (bFragment && (pRxD->Decrypted) && (pEntry->WepStatus == Ndis802_11Encryption2Enabled)) - { - // Minus MIC length - pRxBlk->DataSize -= 8; - - // For TKIP frame, calculate the MIC value - if (STACheckTkipMICValue(pAd, pEntry, pRxBlk) == FALSE) - { - return; - } - } - - STARxDataFrameAnnounce(pAd, pEntry, pRxBlk, FromWhichBSSID); - return; - } - else - { - // just return - // because RTMPDeFragmentDataFrame() will release rx packet, - // if packet is fragmented - return; - } - } - - ASSERT(0); - // release packet - RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); -} - -VOID STAHandleRxMgmtFrame( - IN PRTMP_ADAPTER pAd, - IN RX_BLK *pRxBlk) -{ - PRT28XX_RXD_STRUC pRxD = &(pRxBlk->RxD); - PRXWI_STRUC pRxWI = pRxBlk->pRxWI; - PHEADER_802_11 pHeader = pRxBlk->pHeader; - PNDIS_PACKET pRxPacket = pRxBlk->pRxPacket; - - do - { - - // We should collect RSSI not only U2M data but also my beacon - if ((pHeader->FC.SubType == SUBTYPE_BEACON) && (MAC_ADDR_EQUAL(&pAd->CommonCfg.Bssid, &pHeader->Addr2))) - { - Update_Rssi_Sample(pAd, &pAd->StaCfg.RssiSample, pRxWI); - - pAd->StaCfg.LastSNR0 = (UCHAR)(pRxWI->SNR0); - pAd->StaCfg.LastSNR1 = (UCHAR)(pRxWI->SNR1); - } - - // First check the size, it MUST not exceed the mlme queue size - if (pRxWI->MPDUtotalByteCount > MGMT_DMA_BUFFER_SIZE) - { - DBGPRINT_ERR(("STAHandleRxMgmtFrame: frame too large, size = %d \n", pRxWI->MPDUtotalByteCount)); - break; - } - - REPORT_MGMT_FRAME_TO_MLME(pAd, pRxWI->WirelessCliID, pHeader, pRxWI->MPDUtotalByteCount, - pRxWI->RSSI0, pRxWI->RSSI1, pRxWI->RSSI2, pRxD->PlcpSignal); - } while (FALSE); - - RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_SUCCESS); -} - -VOID STAHandleRxControlFrame( - IN PRTMP_ADAPTER pAd, - IN RX_BLK *pRxBlk) -{ -#ifdef DOT11_N_SUPPORT - PRXWI_STRUC pRxWI = pRxBlk->pRxWI; -#endif // DOT11_N_SUPPORT // - PHEADER_802_11 pHeader = pRxBlk->pHeader; - PNDIS_PACKET pRxPacket = pRxBlk->pRxPacket; - - switch (pHeader->FC.SubType) - { - case SUBTYPE_BLOCK_ACK_REQ: -#ifdef DOT11_N_SUPPORT - { - CntlEnqueueForRecv(pAd, pRxWI->WirelessCliID, (pRxWI->MPDUtotalByteCount), (PFRAME_BA_REQ)pHeader); - } - break; -#endif // DOT11_N_SUPPORT // - case SUBTYPE_BLOCK_ACK: - case SUBTYPE_ACK: - default: - break; - } - - RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); -} - - -/* - ======================================================================== - - Routine Description: - Process RxDone interrupt, running in DPC level - - Arguments: - pAd Pointer to our adapter - - Return Value: - None - - IRQL = DISPATCH_LEVEL - - Note: - This routine has to maintain Rx ring read pointer. - Need to consider QOS DATA format when converting to 802.3 - ======================================================================== -*/ -BOOLEAN STARxDoneInterruptHandle( - IN PRTMP_ADAPTER pAd, - IN BOOLEAN argc) -{ - NDIS_STATUS Status; - UINT32 RxProcessed, RxPending; - BOOLEAN bReschedule = FALSE; - RT28XX_RXD_STRUC *pRxD; - UCHAR *pData; - PRXWI_STRUC pRxWI; - PNDIS_PACKET pRxPacket; - PHEADER_802_11 pHeader; - RX_BLK RxCell; - - RxProcessed = RxPending = 0; - - // process whole rx ring - while (1) - { - - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF | - fRTMP_ADAPTER_RESET_IN_PROGRESS | - fRTMP_ADAPTER_HALT_IN_PROGRESS | - fRTMP_ADAPTER_NIC_NOT_EXIST) || - !RTMP_TEST_FLAG(pAd,fRTMP_ADAPTER_START_UP)) - { - break; - } - - - RxProcessed ++; // test - - // 1. allocate a new data packet into rx ring to replace received packet - // then processing the received packet - // 2. the callee must take charge of release of packet - // 3. As far as driver is concerned , - // the rx packet must - // a. be indicated to upper layer or - // b. be released if it is discarded - pRxPacket = GetPacketFromRxRing(pAd, &(RxCell.RxD), &bReschedule, &RxPending); - if (pRxPacket == NULL) - { - // no more packet to process - break; - } - - // get rx ring descriptor - pRxD = &(RxCell.RxD); - // get rx data buffer - pData = GET_OS_PKT_DATAPTR(pRxPacket); - pRxWI = (PRXWI_STRUC) pData; - pHeader = (PHEADER_802_11) (pData+RXWI_SIZE) ; - -#ifdef RT_BIG_ENDIAN - RTMPFrameEndianChange(pAd, (PUCHAR)pHeader, DIR_READ, TRUE); - RTMPWIEndianChange((PUCHAR)pRxWI, TYPE_RXWI); -#endif - - // build RxCell - RxCell.pRxWI = pRxWI; - RxCell.pHeader = pHeader; - RxCell.pRxPacket = pRxPacket; - RxCell.pData = (UCHAR *) pHeader; - RxCell.DataSize = pRxWI->MPDUtotalByteCount; - RxCell.Flags = 0; - - // Increase Total receive byte counter after real data received no mater any error or not - pAd->RalinkCounters.ReceivedByteCount += pRxWI->MPDUtotalByteCount; - pAd->RalinkCounters.RxCount ++; - - INC_COUNTER64(pAd->WlanCounters.ReceivedFragmentCount); - - if (pRxWI->MPDUtotalByteCount < 14) - Status = NDIS_STATUS_FAILURE; - - if (MONITOR_ON(pAd)) - { - send_monitor_packets(pAd, &RxCell); - break; - } - /* RT2870 invokes STARxDoneInterruptHandle() in rtusb_bulk.c */ -#ifdef RALINK_ATE - if (ATE_ON(pAd)) - { - pAd->ate.RxCntPerSec++; - ATESampleRssi(pAd, pRxWI); -#ifdef RALINK_28xx_QA - if (pAd->ate.bQARxStart == TRUE) - { - /* (*pRxD) has been swapped in GetPacketFromRxRing() */ - ATE_QA_Statistics(pAd, pRxWI, pRxD, pHeader); - } -#endif // RALINK_28xx_QA // - RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_SUCCESS); - continue; - } -#endif // RALINK_ATE // - - // Check for all RxD errors - Status = RTMPCheckRxError(pAd, pHeader, pRxWI, pRxD); - - // Handle the received frame - if (Status == NDIS_STATUS_SUCCESS) - { - switch (pHeader->FC.Type) - { - // CASE I, receive a DATA frame - case BTYPE_DATA: - { - // process DATA frame - STAHandleRxDataFrame(pAd, &RxCell); - } - break; - // CASE II, receive a MGMT frame - case BTYPE_MGMT: - { - STAHandleRxMgmtFrame(pAd, &RxCell); - } - break; - // CASE III. receive a CNTL frame - case BTYPE_CNTL: - { - STAHandleRxControlFrame(pAd, &RxCell); - } - break; - // discard other type - default: - RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); - break; - } - } - else - { - pAd->Counters8023.RxErrors++; - // discard this frame - RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); - } - } - - return bReschedule; -} - -/* - ======================================================================== - - Routine Description: - Arguments: - pAd Pointer to our adapter - - IRQL = DISPATCH_LEVEL - - ======================================================================== -*/ -VOID RTMPHandleTwakeupInterrupt( - IN PRTMP_ADAPTER pAd) -{ - AsicForceWakeup(pAd, FALSE); -} - -/* -======================================================================== -Routine Description: - Early checking and OS-depened parsing for Tx packet send to our STA driver. - -Arguments: - NDIS_HANDLE MiniportAdapterContext Pointer refer to the device handle, i.e., the pAd. - PPNDIS_PACKET ppPacketArray The packet array need to do transmission. - UINT NumberOfPackets Number of packet in packet array. - -Return Value: - NONE - -Note: - This function do early checking and classification for send-out packet. - You only can put OS-depened & STA related code in here. -======================================================================== -*/ -VOID STASendPackets( - IN NDIS_HANDLE MiniportAdapterContext, - IN PPNDIS_PACKET ppPacketArray, - IN UINT NumberOfPackets) -{ - UINT Index; - PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) MiniportAdapterContext; - PNDIS_PACKET pPacket; - BOOLEAN allowToSend = FALSE; - - - for (Index = 0; Index < NumberOfPackets; Index++) - { - pPacket = ppPacketArray[Index]; - - do - { - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS) || - RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS) || - RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF)) - { - // Drop send request since hardware is in reset state - break; - } - else if (!INFRA_ON(pAd) && !ADHOC_ON(pAd)) - { - // Drop send request since there are no physical connection yet - break; - } - else - { - // Record that orignal packet source is from NDIS layer,so that - // later on driver knows how to release this NDIS PACKET -#ifdef QOS_DLS_SUPPORT - MAC_TABLE_ENTRY *pEntry; - PUCHAR pSrcBufVA = GET_OS_PKT_DATAPTR(pPacket); - - pEntry = MacTableLookup(pAd, pSrcBufVA); - if (pEntry && (pEntry->ValidAsDls == TRUE)) - { - RTMP_SET_PACKET_WCID(pPacket, pEntry->Aid); - } - else -#endif // QOS_DLS_SUPPORT // - RTMP_SET_PACKET_WCID(pPacket, 0); // this field is useless when in STA mode - RTMP_SET_PACKET_SOURCE(pPacket, PKTSRC_NDIS); - NDIS_SET_PACKET_STATUS(pPacket, NDIS_STATUS_PENDING); - pAd->RalinkCounters.PendingNdisPacketCount++; - - allowToSend = TRUE; - } - } while(FALSE); - - if (allowToSend == TRUE) - STASendPacket(pAd, pPacket); - else - RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); - } - - // Dequeue outgoing frames from TxSwQueue[] and process it - RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, MAX_TX_PROCESS); - -} - - -/* -======================================================================== -Routine Description: - This routine is used to do packet parsing and classification for Tx packet - to STA device, and it will en-queue packets to our TxSwQueue depends on AC - class. - -Arguments: - pAd Pointer to our adapter - pPacket Pointer to send packet - -Return Value: - NDIS_STATUS_SUCCESS If succes to queue the packet into TxSwQueue. - NDIS_STATUS_FAILURE If failed to do en-queue. - -Note: - You only can put OS-indepened & STA related code in here. -======================================================================== -*/ -NDIS_STATUS STASendPacket( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket) -{ - PACKET_INFO PacketInfo; - PUCHAR pSrcBufVA; - UINT SrcBufLen; - UINT AllowFragSize; - UCHAR NumberOfFrag; -// UCHAR RTSRequired; - UCHAR QueIdx, UserPriority; - MAC_TABLE_ENTRY *pEntry = NULL; - unsigned int IrqFlags; - UCHAR FlgIsIP = 0; - UCHAR Rate; - - // Prepare packet information structure for buffer descriptor - // chained within a single NDIS packet. - RTMP_QueryPacketInfo(pPacket, &PacketInfo, &pSrcBufVA, &SrcBufLen); - - if (pSrcBufVA == NULL) - { - DBGPRINT(RT_DEBUG_ERROR,("STASendPacket --> pSrcBufVA == NULL !!!SrcBufLen=%x\n",SrcBufLen)); - // Resourece is low, system did not allocate virtual address - // return NDIS_STATUS_FAILURE directly to upper layer - RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); - return NDIS_STATUS_FAILURE; - } - - - if (SrcBufLen < 14) - { - DBGPRINT(RT_DEBUG_ERROR,("STASendPacket --> Ndis Packet buffer error !!!\n")); - RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); - return (NDIS_STATUS_FAILURE); - } - - // In HT rate adhoc mode, A-MPDU is often used. So need to lookup BA Table and MAC Entry. - // Note multicast packets in adhoc also use BSSID_WCID index. - { - if(INFRA_ON(pAd)) - { -#ifdef QOS_DLS_SUPPORT - USHORT tmpWcid; - - tmpWcid = RTMP_GET_PACKET_WCID(pPacket); - if (VALID_WCID(tmpWcid) && - (pAd->MacTab.Content[tmpWcid].ValidAsDls== TRUE)) - { - pEntry = &pAd->MacTab.Content[tmpWcid]; - Rate = pAd->MacTab.Content[tmpWcid].CurrTxRate; - } - else -#endif // QOS_DLS_SUPPORT // - { - pEntry = &pAd->MacTab.Content[BSSID_WCID]; - RTMP_SET_PACKET_WCID(pPacket, BSSID_WCID); - Rate = pAd->CommonCfg.TxRate; - } - } - else if (ADHOC_ON(pAd)) - { - if (*pSrcBufVA & 0x01) - { - RTMP_SET_PACKET_WCID(pPacket, MCAST_WCID); - pEntry = &pAd->MacTab.Content[MCAST_WCID]; - } - else - { - pEntry = MacTableLookup(pAd, pSrcBufVA); - } - Rate = pAd->CommonCfg.TxRate; - } - } - - if (!pEntry) - { - DBGPRINT(RT_DEBUG_ERROR,("STASendPacket->Cannot find pEntry(%2x:%2x:%2x:%2x:%2x:%2x) in MacTab!\n", PRINT_MAC(pSrcBufVA))); - // Resourece is low, system did not allocate virtual address - // return NDIS_STATUS_FAILURE directly to upper layer - RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); - return NDIS_STATUS_FAILURE; - } - - if (ADHOC_ON(pAd) - ) - { - RTMP_SET_PACKET_WCID(pPacket, (UCHAR)pEntry->Aid); - } - - // - // Check the Ethernet Frame type of this packet, and set the RTMP_SET_PACKET_SPECIFIC flags. - // Here we set the PACKET_SPECIFIC flags(LLC, VLAN, DHCP/ARP, EAPOL). - RTMPCheckEtherType(pAd, pPacket); - - - - // - // WPA 802.1x secured port control - drop all non-802.1x frame before port secured - // - if (((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || - (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) || - (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || - (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) -#ifdef WPA_SUPPLICANT_SUPPORT - || (pAd->StaCfg.IEEE8021X == TRUE) -#endif // WPA_SUPPLICANT_SUPPORT // -#ifdef LEAP_SUPPORT - || (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) -#endif // LEAP_SUPPORT // - ) - && ((pAd->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED) || (pAd->StaCfg.MicErrCnt >= 2)) - && (RTMP_GET_PACKET_EAPOL(pPacket)== FALSE) - ) - { - DBGPRINT(RT_DEBUG_TRACE,("STASendPacket --> Drop packet before port secured !!!\n")); - RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); - - return (NDIS_STATUS_FAILURE); - } - - - // STEP 1. Decide number of fragments required to deliver this MSDU. - // The estimation here is not very accurate because difficult to - // take encryption overhead into consideration here. The result - // "NumberOfFrag" is then just used to pre-check if enough free - // TXD are available to hold this MSDU. - - - if (*pSrcBufVA & 0x01) // fragmentation not allowed on multicast & broadcast - NumberOfFrag = 1; - else if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED)) - NumberOfFrag = 1; // Aggregation overwhelms fragmentation - else if (CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_AMSDU_INUSED)) - NumberOfFrag = 1; // Aggregation overwhelms fragmentation -#ifdef DOT11_N_SUPPORT - else if ((pAd->StaCfg.HTPhyMode.field.MODE == MODE_HTMIX) || (pAd->StaCfg.HTPhyMode.field.MODE == MODE_HTGREENFIELD)) - NumberOfFrag = 1; // MIMO RATE overwhelms fragmentation -#endif // DOT11_N_SUPPORT // - else - { - // The calculated "NumberOfFrag" is a rough estimation because of various - // encryption/encapsulation overhead not taken into consideration. This number is just - // used to make sure enough free TXD are available before fragmentation takes place. - // In case the actual required number of fragments of an NDIS packet - // excceeds "NumberOfFrag"caculated here and not enough free TXD available, the - // last fragment (i.e. last MPDU) will be dropped in RTMPHardTransmit() due to out of - // resource, and the NDIS packet will be indicated NDIS_STATUS_FAILURE. This should - // rarely happen and the penalty is just like a TX RETRY fail. Affordable. - - AllowFragSize = (pAd->CommonCfg.FragmentThreshold) - LENGTH_802_11 - LENGTH_CRC; - NumberOfFrag = ((PacketInfo.TotalPacketLength - LENGTH_802_3 + LENGTH_802_1_H) / AllowFragSize) + 1; - // To get accurate number of fragmentation, Minus 1 if the size just match to allowable fragment size - if (((PacketInfo.TotalPacketLength - LENGTH_802_3 + LENGTH_802_1_H) % AllowFragSize) == 0) - { - NumberOfFrag--; - } - } - - // Save fragment number to Ndis packet reserved field - RTMP_SET_PACKET_FRAGMENTS(pPacket, NumberOfFrag); - - - // STEP 2. Check the requirement of RTS: - // If multiple fragment required, RTS is required only for the first fragment - // if the fragment size large than RTS threshold - // For RT28xx, Let ASIC send RTS/CTS - RTMP_SET_PACKET_RTS(pPacket, 0); - RTMP_SET_PACKET_TXRATE(pPacket, pAd->CommonCfg.TxRate); - - // - // STEP 3. Traffic classification. outcome = - // - UserPriority = 0; - QueIdx = QID_AC_BE; - if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED) && - CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_WMM_CAPABLE)) - { - USHORT Protocol; - UCHAR LlcSnapLen = 0, Byte0, Byte1; - do - { - // get Ethernet protocol field - Protocol = (USHORT)((pSrcBufVA[12] << 8) + pSrcBufVA[13]); - if (Protocol <= 1500) - { - // get Ethernet protocol field from LLC/SNAP - if (Sniff2BytesFromNdisBuffer(PacketInfo.pFirstBuffer, LENGTH_802_3 + 6, &Byte0, &Byte1) != NDIS_STATUS_SUCCESS) - break; - - Protocol = (USHORT)((Byte0 << 8) + Byte1); - LlcSnapLen = 8; - } - - // always AC_BE for non-IP packet - if (Protocol != 0x0800) - break; - - // get IP header - if (Sniff2BytesFromNdisBuffer(PacketInfo.pFirstBuffer, LENGTH_802_3 + LlcSnapLen, &Byte0, &Byte1) != NDIS_STATUS_SUCCESS) - break; - - // return AC_BE if packet is not IPv4 - if ((Byte0 & 0xf0) != 0x40) - break; - - FlgIsIP = 1; - UserPriority = (Byte1 & 0xe0) >> 5; - QueIdx = MapUserPriorityToAccessCategory[UserPriority]; - - // TODO: have to check ACM bit. apply TSPEC if ACM is ON - // TODO: downgrade UP & QueIdx before passing ACM - if (pAd->CommonCfg.APEdcaParm.bACM[QueIdx]) - { - UserPriority = 0; - QueIdx = QID_AC_BE; - } - } while (FALSE); - } - - RTMP_SET_PACKET_UP(pPacket, UserPriority); - - - - // Make sure SendTxWait queue resource won't be used by other threads - RTMP_IRQ_LOCK(&pAd->irq_lock, IrqFlags); - if (pAd->TxSwQueue[QueIdx].Number >= MAX_PACKETS_IN_QUEUE) - { - RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags); -#ifdef BLOCK_NET_IF - StopNetIfQueue(pAd, QueIdx, pPacket); -#endif // BLOCK_NET_IF // - RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); - - return NDIS_STATUS_FAILURE; - } - else - { - InsertTailQueue(&pAd->TxSwQueue[QueIdx], PACKET_TO_QUEUE_ENTRY(pPacket)); - } - RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags); - -#ifdef DOT11_N_SUPPORT - if ((pAd->CommonCfg.BACapability.field.AutoBA == TRUE)&& - IS_HT_STA(pEntry)) - { - //PMAC_TABLE_ENTRY pMacEntry = &pAd->MacTab.Content[BSSID_WCID]; - if (((pEntry->TXBAbitmap & (1<BADeclineBitmap & (1<PortSecured == WPA_802_1X_PORT_SECURED) - // For IOT compatibility, if - // 1. It is Ralink chip or - // 2. It is OPEN or AES mode, - // then BA session can be bulit. - && ((pEntry->ValidAsCLI && pAd->MlmeAux.APRalinkIe != 0x0) || - (pEntry->WepStatus == Ndis802_11WEPDisabled || pEntry->WepStatus == Ndis802_11Encryption3Enabled)) - ) - { - BAOriSessionSetUp(pAd, pEntry, 0, 0, 10, FALSE); - } - } -#endif // DOT11_N_SUPPORT // - - pAd->RalinkCounters.OneSecOsTxCount[QueIdx]++; // TODO: for debug only. to be removed - return NDIS_STATUS_SUCCESS; -} - - -/* - ======================================================================== - - Routine Description: - This subroutine will scan through releative ring descriptor to find - out avaliable free ring descriptor and compare with request size. - - Arguments: - pAd Pointer to our adapter - QueIdx Selected TX Ring - - Return Value: - NDIS_STATUS_FAILURE Not enough free descriptor - NDIS_STATUS_SUCCESS Enough free descriptor - - IRQL = PASSIVE_LEVEL - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ - -#ifdef RT2870 -/* - Actually, this function used to check if the TxHardware Queue still has frame need to send. - If no frame need to send, go to sleep, else, still wake up. -*/ -NDIS_STATUS RTMPFreeTXDRequest( - IN PRTMP_ADAPTER pAd, - IN UCHAR QueIdx, - IN UCHAR NumberRequired, - IN PUCHAR FreeNumberIs) -{ - //ULONG FreeNumber = 0; - NDIS_STATUS Status = NDIS_STATUS_FAILURE; - unsigned long IrqFlags; - HT_TX_CONTEXT *pHTTXContext; - - switch (QueIdx) - { - case QID_AC_BK: - case QID_AC_BE: - case QID_AC_VI: - case QID_AC_VO: - case QID_HCCA: - { - pHTTXContext = &pAd->TxContext[QueIdx]; - RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); - if ((pHTTXContext->CurWritePosition != pHTTXContext->ENextBulkOutPosition) || - (pHTTXContext->IRPPending == TRUE)) - { - Status = NDIS_STATUS_FAILURE; - } - else - { - Status = NDIS_STATUS_SUCCESS; - } - RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); - } - break; - - case QID_MGMT: - if (pAd->MgmtRing.TxSwFreeIdx != MGMT_RING_SIZE) - Status = NDIS_STATUS_FAILURE; - else - Status = NDIS_STATUS_SUCCESS; - break; - - default: - DBGPRINT(RT_DEBUG_ERROR,("RTMPFreeTXDRequest::Invalid QueIdx(=%d)\n", QueIdx)); - break; - } - - return (Status); - -} -#endif // RT2870 // - - -VOID RTMPSendDisassociationFrame( - IN PRTMP_ADAPTER pAd) -{ -} - -VOID RTMPSendNullFrame( - IN PRTMP_ADAPTER pAd, - IN UCHAR TxRate, - IN BOOLEAN bQosNull) -{ - UCHAR NullFrame[48]; - ULONG Length; - PHEADER_802_11 pHeader_802_11; - - -#ifdef RALINK_ATE - if(ATE_ON(pAd)) - { - return; - } -#endif // RALINK_ATE // - - // WPA 802.1x secured port control - if (((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || - (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) || - (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || - (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) -#ifdef WPA_SUPPLICANT_SUPPORT - || (pAd->StaCfg.IEEE8021X == TRUE) -#endif - ) && - (pAd->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED)) - { - return; - } - - NdisZeroMemory(NullFrame, 48); - Length = sizeof(HEADER_802_11); - - pHeader_802_11 = (PHEADER_802_11) NullFrame; - - pHeader_802_11->FC.Type = BTYPE_DATA; - pHeader_802_11->FC.SubType = SUBTYPE_NULL_FUNC; - pHeader_802_11->FC.ToDs = 1; - COPY_MAC_ADDR(pHeader_802_11->Addr1, pAd->CommonCfg.Bssid); - COPY_MAC_ADDR(pHeader_802_11->Addr2, pAd->CurrentAddress); - COPY_MAC_ADDR(pHeader_802_11->Addr3, pAd->CommonCfg.Bssid); - - if (pAd->CommonCfg.bAPSDForcePowerSave) - { - pHeader_802_11->FC.PwrMgmt = PWR_SAVE; - } - else - { - pHeader_802_11->FC.PwrMgmt = (pAd->StaCfg.Psm == PWR_SAVE) ? 1: 0; - } - pHeader_802_11->Duration = pAd->CommonCfg.Dsifs + RTMPCalcDuration(pAd, TxRate, 14); - - pAd->Sequence++; - pHeader_802_11->Sequence = pAd->Sequence; - - // Prepare QosNull function frame - if (bQosNull) - { - pHeader_802_11->FC.SubType = SUBTYPE_QOS_NULL; - - // copy QOS control bytes - NullFrame[Length] = 0; - NullFrame[Length+1] = 0; - Length += 2;// if pad with 2 bytes for alignment, APSD will fail - } - - HAL_KickOutNullFrameTx(pAd, 0, NullFrame, Length); - -} - -// IRQL = DISPATCH_LEVEL -VOID RTMPSendRTSFrame( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDA, - IN unsigned int NextMpduSize, - IN UCHAR TxRate, - IN UCHAR RTSRate, - IN USHORT AckDuration, - IN UCHAR QueIdx, - IN UCHAR FrameGap) -{ -} - - - -// -------------------------------------------------------- -// FIND ENCRYPT KEY AND DECIDE CIPHER ALGORITHM -// Find the WPA key, either Group or Pairwise Key -// LEAP + TKIP also use WPA key. -// -------------------------------------------------------- -// Decide WEP bit and cipher suite to be used. Same cipher suite should be used for whole fragment burst -// In Cisco CCX 2.0 Leap Authentication -// WepStatus is Ndis802_11Encryption1Enabled but the key will use PairwiseKey -// Instead of the SharedKey, SharedKey Length may be Zero. -VOID STAFindCipherAlgorithm( - IN PRTMP_ADAPTER pAd, - IN TX_BLK *pTxBlk) -{ - NDIS_802_11_ENCRYPTION_STATUS Cipher; // To indicate cipher used for this packet - UCHAR CipherAlg = CIPHER_NONE; // cipher alogrithm - UCHAR KeyIdx = 0xff; - PUCHAR pSrcBufVA; - PCIPHER_KEY pKey = NULL; - - pSrcBufVA = GET_OS_PKT_DATAPTR(pTxBlk->pPacket); - - { - // Select Cipher - if ((*pSrcBufVA & 0x01) && (ADHOC_ON(pAd))) - Cipher = pAd->StaCfg.GroupCipher; // Cipher for Multicast or Broadcast - else - Cipher = pAd->StaCfg.PairCipher; // Cipher for Unicast - - if (RTMP_GET_PACKET_EAPOL(pTxBlk->pPacket)) - { - ASSERT(pAd->SharedKey[BSS0][0].CipherAlg <= CIPHER_CKIP128); - - // 4-way handshaking frame must be clear - if (!(TX_BLK_TEST_FLAG(pTxBlk, fTX_bClearEAPFrame)) && (pAd->SharedKey[BSS0][0].CipherAlg) && - (pAd->SharedKey[BSS0][0].KeyLen)) - { - CipherAlg = pAd->SharedKey[BSS0][0].CipherAlg; - KeyIdx = 0; - } - } - else if (Cipher == Ndis802_11Encryption1Enabled) - { -#ifdef LEAP_SUPPORT - if (pAd->StaCfg.CkipFlag & 0x10) // Cisco CKIP KP is on - { - if (LEAP_CCKM_ON(pAd)) - { - if (((*pSrcBufVA & 0x01) && (ADHOC_ON(pAd)))) - KeyIdx = 1; - else - KeyIdx = 0; - } - else - KeyIdx = pAd->StaCfg.DefaultKeyId; - } - else if (pAd->StaCfg.CkipFlag & 0x08) // only CKIP CMIC - KeyIdx = pAd->StaCfg.DefaultKeyId; - else if (LEAP_CCKM_ON(pAd)) - { - if ((*pSrcBufVA & 0x01) && (ADHOC_ON(pAd))) - KeyIdx = 1; - else - KeyIdx = 0; - } - else // standard WEP64 or WEP128 -#endif // LEAP_SUPPORT // - KeyIdx = pAd->StaCfg.DefaultKeyId; - } - else if ((Cipher == Ndis802_11Encryption2Enabled) || - (Cipher == Ndis802_11Encryption3Enabled)) - { - if ((*pSrcBufVA & 0x01) && (ADHOC_ON(pAd))) // multicast - KeyIdx = pAd->StaCfg.DefaultKeyId; - else if (pAd->SharedKey[BSS0][0].KeyLen) - KeyIdx = 0; - else - KeyIdx = pAd->StaCfg.DefaultKeyId; - } - - if (KeyIdx == 0xff) - CipherAlg = CIPHER_NONE; - else if ((Cipher == Ndis802_11EncryptionDisabled) || (pAd->SharedKey[BSS0][KeyIdx].KeyLen == 0)) - CipherAlg = CIPHER_NONE; -#ifdef WPA_SUPPLICANT_SUPPORT - else if ( pAd->StaCfg.WpaSupplicantUP && - (Cipher == Ndis802_11Encryption1Enabled) && - (pAd->StaCfg.IEEE8021X == TRUE) && - (pAd->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED)) - CipherAlg = CIPHER_NONE; -#endif // WPA_SUPPLICANT_SUPPORT // - else - { - //Header_802_11.FC.Wep = 1; - CipherAlg = pAd->SharedKey[BSS0][KeyIdx].CipherAlg; - pKey = &pAd->SharedKey[BSS0][KeyIdx]; - } - } - - pTxBlk->CipherAlg = CipherAlg; - pTxBlk->pKey = pKey; -} - - -VOID STABuildCommon802_11Header( - IN PRTMP_ADAPTER pAd, - IN TX_BLK *pTxBlk) -{ - - HEADER_802_11 *pHeader_802_11; -#ifdef QOS_DLS_SUPPORT - BOOLEAN bDLSFrame = FALSE; - INT DlsEntryIndex = 0; -#endif // QOS_DLS_SUPPORT // - - // - // MAKE A COMMON 802.11 HEADER - // - - // normal wlan header size : 24 octets - pTxBlk->MpduHeaderLen = sizeof(HEADER_802_11); - - pHeader_802_11 = (HEADER_802_11 *) &pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE]; - - NdisZeroMemory(pHeader_802_11, sizeof(HEADER_802_11)); - - pHeader_802_11->FC.FrDs = 0; - pHeader_802_11->FC.Type = BTYPE_DATA; - pHeader_802_11->FC.SubType = ((TX_BLK_TEST_FLAG(pTxBlk, fTX_bWMM)) ? SUBTYPE_QDATA : SUBTYPE_DATA); - -#ifdef QOS_DLS_SUPPORT - if (INFRA_ON(pAd)) - { - // Check if the frame can be sent through DLS direct link interface - // If packet can be sent through DLS, then force aggregation disable. (Hard to determine peer STA's capability) - DlsEntryIndex = RTMPCheckDLSFrame(pAd, pTxBlk->pSrcBufHeader); - if (DlsEntryIndex >= 0) - bDLSFrame = TRUE; - else - bDLSFrame = FALSE; - } -#endif // QOS_DLS_SUPPORT // - - if (pTxBlk->pMacEntry) - { - if (TX_BLK_TEST_FLAG(pTxBlk, fTX_bForceNonQoS)) - { - pHeader_802_11->Sequence = pTxBlk->pMacEntry->NonQosDataSeq; - pTxBlk->pMacEntry->NonQosDataSeq = (pTxBlk->pMacEntry->NonQosDataSeq+1) & MAXSEQ; - } - else - { - pHeader_802_11->Sequence = pTxBlk->pMacEntry->TxSeq[pTxBlk->UserPriority]; - pTxBlk->pMacEntry->TxSeq[pTxBlk->UserPriority] = (pTxBlk->pMacEntry->TxSeq[pTxBlk->UserPriority]+1) & MAXSEQ; - } - } - else - { - pHeader_802_11->Sequence = pAd->Sequence; - pAd->Sequence = (pAd->Sequence+1) & MAXSEQ; // next sequence - } - - pHeader_802_11->Frag = 0; - - pHeader_802_11->FC.MoreData = TX_BLK_TEST_FLAG(pTxBlk, fTX_bMoreData); - - { - if (INFRA_ON(pAd)) - { -#ifdef QOS_DLS_SUPPORT - if (bDLSFrame) - { - COPY_MAC_ADDR(pHeader_802_11->Addr1, pTxBlk->pSrcBufHeader); - COPY_MAC_ADDR(pHeader_802_11->Addr2, pAd->CurrentAddress); - COPY_MAC_ADDR(pHeader_802_11->Addr3, pAd->CommonCfg.Bssid); - pHeader_802_11->FC.ToDs = 0; - } - else -#endif // QOS_DLS_SUPPORT // - { - COPY_MAC_ADDR(pHeader_802_11->Addr1, pAd->CommonCfg.Bssid); - COPY_MAC_ADDR(pHeader_802_11->Addr2, pAd->CurrentAddress); - COPY_MAC_ADDR(pHeader_802_11->Addr3, pTxBlk->pSrcBufHeader); - pHeader_802_11->FC.ToDs = 1; - } - } - else if (ADHOC_ON(pAd)) - { - COPY_MAC_ADDR(pHeader_802_11->Addr1, pTxBlk->pSrcBufHeader); - COPY_MAC_ADDR(pHeader_802_11->Addr2, pAd->CurrentAddress); - COPY_MAC_ADDR(pHeader_802_11->Addr3, pAd->CommonCfg.Bssid); - pHeader_802_11->FC.ToDs = 0; - } - } - - if (pTxBlk->CipherAlg != CIPHER_NONE) - pHeader_802_11->FC.Wep = 1; - - // ----------------------------------------------------------------- - // STEP 2. MAKE A COMMON 802.11 HEADER SHARED BY ENTIRE FRAGMENT BURST. Fill sequence later. - // ----------------------------------------------------------------- - if (pAd->CommonCfg.bAPSDForcePowerSave) - pHeader_802_11->FC.PwrMgmt = PWR_SAVE; - else - pHeader_802_11->FC.PwrMgmt = (pAd->StaCfg.Psm == PWR_SAVE); -} - -#ifdef DOT11_N_SUPPORT -VOID STABuildCache802_11Header( - IN RTMP_ADAPTER *pAd, - IN TX_BLK *pTxBlk, - IN UCHAR *pHeader) -{ - MAC_TABLE_ENTRY *pMacEntry; - PHEADER_802_11 pHeader80211; - - pHeader80211 = (PHEADER_802_11)pHeader; - pMacEntry = pTxBlk->pMacEntry; - - // - // Update the cached 802.11 HEADER - // - - // normal wlan header size : 24 octets - pTxBlk->MpduHeaderLen = sizeof(HEADER_802_11); - - // More Bit - pHeader80211->FC.MoreData = TX_BLK_TEST_FLAG(pTxBlk, fTX_bMoreData); - - // Sequence - pHeader80211->Sequence = pMacEntry->TxSeq[pTxBlk->UserPriority]; - pMacEntry->TxSeq[pTxBlk->UserPriority] = (pMacEntry->TxSeq[pTxBlk->UserPriority]+1) & MAXSEQ; - - { - // Check if the frame can be sent through DLS direct link interface - // If packet can be sent through DLS, then force aggregation disable. (Hard to determine peer STA's capability) -#ifdef QOS_DLS_SUPPORT - BOOLEAN bDLSFrame = FALSE; - INT DlsEntryIndex = 0; - - DlsEntryIndex = RTMPCheckDLSFrame(pAd, pTxBlk->pSrcBufHeader); - if (DlsEntryIndex >= 0) - bDLSFrame = TRUE; - else - bDLSFrame = FALSE; -#endif // QOS_DLS_SUPPORT // - - // The addr3 of normal packet send from DS is Dest Mac address. -#ifdef QOS_DLS_SUPPORT - if (bDLSFrame) - { - COPY_MAC_ADDR(pHeader80211->Addr1, pTxBlk->pSrcBufHeader); - COPY_MAC_ADDR(pHeader80211->Addr3, pAd->CommonCfg.Bssid); - pHeader80211->FC.ToDs = 0; - } - else -#endif // QOS_DLS_SUPPORT // - if (ADHOC_ON(pAd)) - COPY_MAC_ADDR(pHeader80211->Addr3, pAd->CommonCfg.Bssid); - else - COPY_MAC_ADDR(pHeader80211->Addr3, pTxBlk->pSrcBufHeader); - } - - // ----------------------------------------------------------------- - // STEP 2. MAKE A COMMON 802.11 HEADER SHARED BY ENTIRE FRAGMENT BURST. Fill sequence later. - // ----------------------------------------------------------------- - if (pAd->CommonCfg.bAPSDForcePowerSave) - pHeader80211->FC.PwrMgmt = PWR_SAVE; - else - pHeader80211->FC.PwrMgmt = (pAd->StaCfg.Psm == PWR_SAVE); -} -#endif // DOT11_N_SUPPORT // - -static inline PUCHAR STA_Build_ARalink_Frame_Header( - IN RTMP_ADAPTER *pAd, - IN TX_BLK *pTxBlk) -{ - PUCHAR pHeaderBufPtr; - HEADER_802_11 *pHeader_802_11; - PNDIS_PACKET pNextPacket; - UINT32 nextBufLen; - PQUEUE_ENTRY pQEntry; - - STAFindCipherAlgorithm(pAd, pTxBlk); - STABuildCommon802_11Header(pAd, pTxBlk); - - - pHeaderBufPtr = &pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE]; - pHeader_802_11 = (HEADER_802_11 *) pHeaderBufPtr; - - // steal "order" bit to mark "aggregation" - pHeader_802_11->FC.Order = 1; - - // skip common header - pHeaderBufPtr += pTxBlk->MpduHeaderLen; - - if (TX_BLK_TEST_FLAG(pTxBlk, fTX_bWMM)) - { - // - // build QOS Control bytes - // - *pHeaderBufPtr = (pTxBlk->UserPriority & 0x0F); - - *(pHeaderBufPtr+1) = 0; - pHeaderBufPtr +=2; - pTxBlk->MpduHeaderLen += 2; - } - - // padding at front of LLC header. LLC header should at 4-bytes aligment. - pTxBlk->HdrPadLen = (ULONG)pHeaderBufPtr; - pHeaderBufPtr = (PCHAR)ROUND_UP(pHeaderBufPtr, 4); - pTxBlk->HdrPadLen = (ULONG)(pHeaderBufPtr - pTxBlk->HdrPadLen); - - // For RA Aggregation, - // put the 2nd MSDU length(extra 2-byte field) after QOS_CONTROL in little endian format - pQEntry = pTxBlk->TxPacketList.Head; - pNextPacket = QUEUE_ENTRY_TO_PKT(pQEntry); - nextBufLen = GET_OS_PKT_LEN(pNextPacket); - if (RTMP_GET_PACKET_VLAN(pNextPacket)) - nextBufLen -= LENGTH_802_1Q; - - *pHeaderBufPtr = (UCHAR)nextBufLen & 0xff; - *(pHeaderBufPtr+1) = (UCHAR)(nextBufLen >> 8); - - pHeaderBufPtr += 2; - pTxBlk->MpduHeaderLen += 2; - - return pHeaderBufPtr; - -} - -#ifdef DOT11_N_SUPPORT -static inline PUCHAR STA_Build_AMSDU_Frame_Header( - IN RTMP_ADAPTER *pAd, - IN TX_BLK *pTxBlk) -{ - PUCHAR pHeaderBufPtr;//, pSaveBufPtr; - HEADER_802_11 *pHeader_802_11; - - - STAFindCipherAlgorithm(pAd, pTxBlk); - STABuildCommon802_11Header(pAd, pTxBlk); - - pHeaderBufPtr = &pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE]; - pHeader_802_11 = (HEADER_802_11 *) pHeaderBufPtr; - - // skip common header - pHeaderBufPtr += pTxBlk->MpduHeaderLen; - - // - // build QOS Control bytes - // - *pHeaderBufPtr = (pTxBlk->UserPriority & 0x0F); - - // - // A-MSDU packet - // - *pHeaderBufPtr |= 0x80; - - *(pHeaderBufPtr+1) = 0; - pHeaderBufPtr +=2; - pTxBlk->MpduHeaderLen += 2; - - //pSaveBufPtr = pHeaderBufPtr; - - // - // padding at front of LLC header - // LLC header should locate at 4-octets aligment - // - // @@@ MpduHeaderLen excluding padding @@@ - // - pTxBlk->HdrPadLen = (ULONG)pHeaderBufPtr; - pHeaderBufPtr = (PCHAR) ROUND_UP(pHeaderBufPtr, 4); - pTxBlk->HdrPadLen = (ULONG)(pHeaderBufPtr - pTxBlk->HdrPadLen); - - return pHeaderBufPtr; - -} - - -VOID STA_AMPDU_Frame_Tx( - IN PRTMP_ADAPTER pAd, - IN TX_BLK *pTxBlk) -{ - HEADER_802_11 *pHeader_802_11; - PUCHAR pHeaderBufPtr; - USHORT FreeNumber; - MAC_TABLE_ENTRY *pMacEntry; - BOOLEAN bVLANPkt; - PQUEUE_ENTRY pQEntry; - - ASSERT(pTxBlk); - - while(pTxBlk->TxPacketList.Head) - { - pQEntry = RemoveHeadQueue(&pTxBlk->TxPacketList); - pTxBlk->pPacket = QUEUE_ENTRY_TO_PACKET(pQEntry); - if ( RTMP_FillTxBlkInfo(pAd, pTxBlk) != TRUE) - { - RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_FAILURE); - continue; - } - - bVLANPkt = (RTMP_GET_PACKET_VLAN(pTxBlk->pPacket) ? TRUE : FALSE); - - pMacEntry = pTxBlk->pMacEntry; - if (pMacEntry->isCached) - { - // NOTE: Please make sure the size of pMacEntry->CachedBuf[] is smaller than pTxBlk->HeaderBuf[]!!!! - NdisMoveMemory((PUCHAR)&pTxBlk->HeaderBuf[TXINFO_SIZE], (PUCHAR)&pMacEntry->CachedBuf[0], TXWI_SIZE + sizeof(HEADER_802_11)); - pHeaderBufPtr = (PUCHAR)(&pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE]); - STABuildCache802_11Header(pAd, pTxBlk, pHeaderBufPtr); - } - else - { - STAFindCipherAlgorithm(pAd, pTxBlk); - STABuildCommon802_11Header(pAd, pTxBlk); - - pHeaderBufPtr = &pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE]; - } - - - pHeader_802_11 = (HEADER_802_11 *) pHeaderBufPtr; - - // skip common header - pHeaderBufPtr += pTxBlk->MpduHeaderLen; - - // - // build QOS Control bytes - // - *pHeaderBufPtr = (pTxBlk->UserPriority & 0x0F); - *(pHeaderBufPtr+1) = 0; - pHeaderBufPtr +=2; - pTxBlk->MpduHeaderLen += 2; - - // - // build HTC+ - // HTC control filed following QoS field - // - if ((pAd->CommonCfg.bRdg == TRUE) && CLIENT_STATUS_TEST_FLAG(pTxBlk->pMacEntry, fCLIENT_STATUS_RDG_CAPABLE)) - { - if (pMacEntry->isCached == FALSE) - { - // mark HTC bit - pHeader_802_11->FC.Order = 1; - - NdisZeroMemory(pHeaderBufPtr, 4); - *(pHeaderBufPtr+3) |= 0x80; - } - pHeaderBufPtr += 4; - pTxBlk->MpduHeaderLen += 4; - } - - //pTxBlk->MpduHeaderLen = pHeaderBufPtr - pTxBlk->HeaderBuf - TXWI_SIZE - TXINFO_SIZE; - ASSERT(pTxBlk->MpduHeaderLen >= 24); - - // skip 802.3 header - pTxBlk->pSrcBufData = pTxBlk->pSrcBufHeader + LENGTH_802_3; - pTxBlk->SrcBufLen -= LENGTH_802_3; - - // skip vlan tag - if (bVLANPkt) - { - pTxBlk->pSrcBufData += LENGTH_802_1Q; - pTxBlk->SrcBufLen -= LENGTH_802_1Q; - } - - // - // padding at front of LLC header - // LLC header should locate at 4-octets aligment - // - // @@@ MpduHeaderLen excluding padding @@@ - // - pTxBlk->HdrPadLen = (ULONG)pHeaderBufPtr; - pHeaderBufPtr = (PCHAR) ROUND_UP(pHeaderBufPtr, 4); - pTxBlk->HdrPadLen = (ULONG)(pHeaderBufPtr - pTxBlk->HdrPadLen); - - { - - // - // Insert LLC-SNAP encapsulation - 8 octets - // - EXTRA_LLCSNAP_ENCAP_FROM_PKT_OFFSET(pTxBlk->pSrcBufData-2, pTxBlk->pExtraLlcSnapEncap); - if (pTxBlk->pExtraLlcSnapEncap) - { - NdisMoveMemory(pHeaderBufPtr, pTxBlk->pExtraLlcSnapEncap, 6); - pHeaderBufPtr += 6; - // get 2 octets (TypeofLen) - NdisMoveMemory(pHeaderBufPtr, pTxBlk->pSrcBufData-2, 2); - pHeaderBufPtr += 2; - pTxBlk->MpduHeaderLen += LENGTH_802_1_H; - } - - } - - if (pMacEntry->isCached) - { - RTMPWriteTxWI_Cache(pAd, (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), pTxBlk); - } - else - { - RTMPWriteTxWI_Data(pAd, (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), pTxBlk); - - NdisZeroMemory((PUCHAR)(&pMacEntry->CachedBuf[0]), sizeof(pMacEntry->CachedBuf)); - NdisMoveMemory((PUCHAR)(&pMacEntry->CachedBuf[0]), (PUCHAR)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), (pHeaderBufPtr - (PUCHAR)(&pTxBlk->HeaderBuf[TXINFO_SIZE]))); - pMacEntry->isCached = TRUE; - } - - // calculate Transmitted AMPDU count and ByteCount - { - pAd->RalinkCounters.TransmittedMPDUsInAMPDUCount.u.LowPart ++; - pAd->RalinkCounters.TransmittedOctetsInAMPDUCount.QuadPart += pTxBlk->SrcBufLen; - } - - //FreeNumber = GET_TXRING_FREENO(pAd, QueIdx); - - HAL_WriteTxResource(pAd, pTxBlk, TRUE, &FreeNumber); - - // - // Kick out Tx - // - HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx); - - pAd->RalinkCounters.KickTxCount++; - pAd->RalinkCounters.OneSecTxDoneCount++; - } - -} - - -VOID STA_AMSDU_Frame_Tx( - IN PRTMP_ADAPTER pAd, - IN TX_BLK *pTxBlk) -{ - PUCHAR pHeaderBufPtr; - USHORT FreeNumber; - USHORT subFramePayloadLen = 0; // AMSDU Subframe length without AMSDU-Header / Padding. - USHORT totalMPDUSize=0; - UCHAR *subFrameHeader; - UCHAR padding = 0; - USHORT FirstTx = 0, LastTxIdx = 0; - BOOLEAN bVLANPkt; - int frameNum = 0; - PQUEUE_ENTRY pQEntry; - - - ASSERT(pTxBlk); - - ASSERT((pTxBlk->TxPacketList.Number > 1)); - - while(pTxBlk->TxPacketList.Head) - { - pQEntry = RemoveHeadQueue(&pTxBlk->TxPacketList); - pTxBlk->pPacket = QUEUE_ENTRY_TO_PACKET(pQEntry); - if (RTMP_FillTxBlkInfo(pAd, pTxBlk) != TRUE) - { - RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_FAILURE); - continue; - } - - bVLANPkt = (RTMP_GET_PACKET_VLAN(pTxBlk->pPacket) ? TRUE : FALSE); - - // skip 802.3 header - pTxBlk->pSrcBufData = pTxBlk->pSrcBufHeader + LENGTH_802_3; - pTxBlk->SrcBufLen -= LENGTH_802_3; - - // skip vlan tag - if (bVLANPkt) - { - pTxBlk->pSrcBufData += LENGTH_802_1Q; - pTxBlk->SrcBufLen -= LENGTH_802_1Q; - } - - if (frameNum == 0) - { - pHeaderBufPtr = STA_Build_AMSDU_Frame_Header(pAd, pTxBlk); - - // NOTE: TxWI->MPDUtotalByteCount will be updated after final frame was handled. - RTMPWriteTxWI_Data(pAd, (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), pTxBlk); - } - else - { - pHeaderBufPtr = &pTxBlk->HeaderBuf[0]; - padding = ROUND_UP(LENGTH_AMSDU_SUBFRAMEHEAD + subFramePayloadLen, 4) - (LENGTH_AMSDU_SUBFRAMEHEAD + subFramePayloadLen); - NdisZeroMemory(pHeaderBufPtr, padding + LENGTH_AMSDU_SUBFRAMEHEAD); - pHeaderBufPtr += padding; - pTxBlk->MpduHeaderLen = padding; - } - - // - // A-MSDU subframe - // DA(6)+SA(6)+Length(2) + LLC/SNAP Encap - // - subFrameHeader = pHeaderBufPtr; - subFramePayloadLen = pTxBlk->SrcBufLen; - - NdisMoveMemory(subFrameHeader, pTxBlk->pSrcBufHeader, 12); - - - pHeaderBufPtr += LENGTH_AMSDU_SUBFRAMEHEAD; - pTxBlk->MpduHeaderLen += LENGTH_AMSDU_SUBFRAMEHEAD; - - - // - // Insert LLC-SNAP encapsulation - 8 octets - // - EXTRA_LLCSNAP_ENCAP_FROM_PKT_OFFSET(pTxBlk->pSrcBufData-2, pTxBlk->pExtraLlcSnapEncap); - - subFramePayloadLen = pTxBlk->SrcBufLen; - - if (pTxBlk->pExtraLlcSnapEncap) - { - NdisMoveMemory(pHeaderBufPtr, pTxBlk->pExtraLlcSnapEncap, 6); - pHeaderBufPtr += 6; - // get 2 octets (TypeofLen) - NdisMoveMemory(pHeaderBufPtr, pTxBlk->pSrcBufData-2, 2); - pHeaderBufPtr += 2; - pTxBlk->MpduHeaderLen += LENGTH_802_1_H; - subFramePayloadLen += LENGTH_802_1_H; - } - - // update subFrame Length field - subFrameHeader[12] = (subFramePayloadLen & 0xFF00) >> 8; - subFrameHeader[13] = subFramePayloadLen & 0xFF; - - totalMPDUSize += pTxBlk->MpduHeaderLen + pTxBlk->SrcBufLen; - - if (frameNum ==0) - FirstTx = HAL_WriteMultiTxResource(pAd, pTxBlk, frameNum, &FreeNumber); - else - LastTxIdx = HAL_WriteMultiTxResource(pAd, pTxBlk, frameNum, &FreeNumber); - - frameNum++; - - pAd->RalinkCounters.KickTxCount++; - pAd->RalinkCounters.OneSecTxDoneCount++; - - // calculate Transmitted AMSDU Count and ByteCount - { - pAd->RalinkCounters.TransmittedAMSDUCount.u.LowPart ++; - pAd->RalinkCounters.TransmittedOctetsInAMSDU.QuadPart += totalMPDUSize; - } - - } - - HAL_FinalWriteTxResource(pAd, pTxBlk, totalMPDUSize, FirstTx); - HAL_LastTxIdx(pAd, pTxBlk->QueIdx, LastTxIdx); - - // - // Kick out Tx - // - HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx); -} -#endif // DOT11_N_SUPPORT // - -VOID STA_Legacy_Frame_Tx( - IN PRTMP_ADAPTER pAd, - IN TX_BLK *pTxBlk) -{ - HEADER_802_11 *pHeader_802_11; - PUCHAR pHeaderBufPtr; - USHORT FreeNumber; - BOOLEAN bVLANPkt; - PQUEUE_ENTRY pQEntry; - - ASSERT(pTxBlk); - - - pQEntry = RemoveHeadQueue(&pTxBlk->TxPacketList); - pTxBlk->pPacket = QUEUE_ENTRY_TO_PACKET(pQEntry); - if (RTMP_FillTxBlkInfo(pAd, pTxBlk) != TRUE) - { - RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_FAILURE); - return; - } - - if (pTxBlk->TxFrameType == TX_MCAST_FRAME) - { - INC_COUNTER64(pAd->WlanCounters.MulticastTransmittedFrameCount); - } - - if (RTMP_GET_PACKET_RTS(pTxBlk->pPacket)) - TX_BLK_SET_FLAG(pTxBlk, fTX_bRtsRequired); - else - TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bRtsRequired); - - bVLANPkt = (RTMP_GET_PACKET_VLAN(pTxBlk->pPacket) ? TRUE : FALSE); - - if (pTxBlk->TxRate < pAd->CommonCfg.MinTxRate) - pTxBlk->TxRate = pAd->CommonCfg.MinTxRate; - - STAFindCipherAlgorithm(pAd, pTxBlk); - STABuildCommon802_11Header(pAd, pTxBlk); - - - // skip 802.3 header - pTxBlk->pSrcBufData = pTxBlk->pSrcBufHeader + LENGTH_802_3; - pTxBlk->SrcBufLen -= LENGTH_802_3; - - // skip vlan tag - if (bVLANPkt) - { - pTxBlk->pSrcBufData += LENGTH_802_1Q; - pTxBlk->SrcBufLen -= LENGTH_802_1Q; - } - - pHeaderBufPtr = &pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE]; - pHeader_802_11 = (HEADER_802_11 *) pHeaderBufPtr; - - // skip common header - pHeaderBufPtr += pTxBlk->MpduHeaderLen; - - if (TX_BLK_TEST_FLAG(pTxBlk, fTX_bWMM)) - { - // - // build QOS Control bytes - // - *pHeaderBufPtr = (pTxBlk->UserPriority & 0x0F); - *(pHeaderBufPtr+1) = 0; - pHeaderBufPtr +=2; - pTxBlk->MpduHeaderLen += 2; - } - - // The remaining content of MPDU header should locate at 4-octets aligment - pTxBlk->HdrPadLen = (ULONG)pHeaderBufPtr; - pHeaderBufPtr = (PCHAR) ROUND_UP(pHeaderBufPtr, 4); - pTxBlk->HdrPadLen = (ULONG)(pHeaderBufPtr - pTxBlk->HdrPadLen); - - { - - // - // Insert LLC-SNAP encapsulation - 8 octets - // - // - // if original Ethernet frame contains no LLC/SNAP, - // then an extra LLC/SNAP encap is required - // - EXTRA_LLCSNAP_ENCAP_FROM_PKT_START(pTxBlk->pSrcBufHeader, pTxBlk->pExtraLlcSnapEncap); - if (pTxBlk->pExtraLlcSnapEncap) - { - UCHAR vlan_size; - - NdisMoveMemory(pHeaderBufPtr, pTxBlk->pExtraLlcSnapEncap, 6); - pHeaderBufPtr += 6; - // skip vlan tag - vlan_size = (bVLANPkt) ? LENGTH_802_1Q : 0; - // get 2 octets (TypeofLen) - NdisMoveMemory(pHeaderBufPtr, pTxBlk->pSrcBufHeader+12+vlan_size, 2); - pHeaderBufPtr += 2; - pTxBlk->MpduHeaderLen += LENGTH_802_1_H; - } - - } - - // - // prepare for TXWI - // use Wcid as Key Index - // - - RTMPWriteTxWI_Data(pAd, (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), pTxBlk); - - //FreeNumber = GET_TXRING_FREENO(pAd, QueIdx); - - HAL_WriteTxResource(pAd, pTxBlk, TRUE, &FreeNumber); - - pAd->RalinkCounters.KickTxCount++; - pAd->RalinkCounters.OneSecTxDoneCount++; - - // - // Kick out Tx - // - HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx); -} - - -VOID STA_ARalink_Frame_Tx( - IN PRTMP_ADAPTER pAd, - IN TX_BLK *pTxBlk) -{ - PUCHAR pHeaderBufPtr; - USHORT FreeNumber; - USHORT totalMPDUSize=0; - USHORT FirstTx, LastTxIdx; - int frameNum = 0; - BOOLEAN bVLANPkt; - PQUEUE_ENTRY pQEntry; - - - ASSERT(pTxBlk); - - ASSERT((pTxBlk->TxPacketList.Number== 2)); - - - FirstTx = LastTxIdx = 0; // Is it ok init they as 0? - while(pTxBlk->TxPacketList.Head) - { - pQEntry = RemoveHeadQueue(&pTxBlk->TxPacketList); - pTxBlk->pPacket = QUEUE_ENTRY_TO_PACKET(pQEntry); - - if (RTMP_FillTxBlkInfo(pAd, pTxBlk) != TRUE) - { - RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_FAILURE); - continue; - } - - bVLANPkt = (RTMP_GET_PACKET_VLAN(pTxBlk->pPacket) ? TRUE : FALSE); - - // skip 802.3 header - pTxBlk->pSrcBufData = pTxBlk->pSrcBufHeader + LENGTH_802_3; - pTxBlk->SrcBufLen -= LENGTH_802_3; - - // skip vlan tag - if (bVLANPkt) - { - pTxBlk->pSrcBufData += LENGTH_802_1Q; - pTxBlk->SrcBufLen -= LENGTH_802_1Q; - } - - if (frameNum == 0) - { // For first frame, we need to create the 802.11 header + padding(optional) + RA-AGG-LEN + SNAP Header - - pHeaderBufPtr = STA_Build_ARalink_Frame_Header(pAd, pTxBlk); - - // It's ok write the TxWI here, because the TxWI->MPDUtotalByteCount - // will be updated after final frame was handled. - RTMPWriteTxWI_Data(pAd, (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), pTxBlk); - - - // - // Insert LLC-SNAP encapsulation - 8 octets - // - EXTRA_LLCSNAP_ENCAP_FROM_PKT_OFFSET(pTxBlk->pSrcBufData-2, pTxBlk->pExtraLlcSnapEncap); - - if (pTxBlk->pExtraLlcSnapEncap) - { - NdisMoveMemory(pHeaderBufPtr, pTxBlk->pExtraLlcSnapEncap, 6); - pHeaderBufPtr += 6; - // get 2 octets (TypeofLen) - NdisMoveMemory(pHeaderBufPtr, pTxBlk->pSrcBufData-2, 2); - pHeaderBufPtr += 2; - pTxBlk->MpduHeaderLen += LENGTH_802_1_H; - } - } - else - { // For second aggregated frame, we need create the 802.3 header to headerBuf, because PCI will copy it to SDPtr0. - - pHeaderBufPtr = &pTxBlk->HeaderBuf[0]; - pTxBlk->MpduHeaderLen = 0; - - // A-Ralink sub-sequent frame header is the same as 802.3 header. - // DA(6)+SA(6)+FrameType(2) - NdisMoveMemory(pHeaderBufPtr, pTxBlk->pSrcBufHeader, 12); - pHeaderBufPtr += 12; - // get 2 octets (TypeofLen) - NdisMoveMemory(pHeaderBufPtr, pTxBlk->pSrcBufData-2, 2); - pHeaderBufPtr += 2; - pTxBlk->MpduHeaderLen = LENGTH_ARALINK_SUBFRAMEHEAD; - } - - totalMPDUSize += pTxBlk->MpduHeaderLen + pTxBlk->SrcBufLen; - - //FreeNumber = GET_TXRING_FREENO(pAd, QueIdx); - if (frameNum ==0) - FirstTx = HAL_WriteMultiTxResource(pAd, pTxBlk, frameNum, &FreeNumber); - else - LastTxIdx = HAL_WriteMultiTxResource(pAd, pTxBlk, frameNum, &FreeNumber); - - frameNum++; - - pAd->RalinkCounters.OneSecTxAggregationCount++; - pAd->RalinkCounters.KickTxCount++; - pAd->RalinkCounters.OneSecTxDoneCount++; - - } - - HAL_FinalWriteTxResource(pAd, pTxBlk, totalMPDUSize, FirstTx); - HAL_LastTxIdx(pAd, pTxBlk->QueIdx, LastTxIdx); - - // - // Kick out Tx - // - HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx); - -} - - -VOID STA_Fragment_Frame_Tx( - IN RTMP_ADAPTER *pAd, - IN TX_BLK *pTxBlk) -{ - HEADER_802_11 *pHeader_802_11; - PUCHAR pHeaderBufPtr; - USHORT FreeNumber; - UCHAR fragNum = 0; - PACKET_INFO PacketInfo; - USHORT EncryptionOverhead = 0; - UINT32 FreeMpduSize, SrcRemainingBytes; - USHORT AckDuration; - UINT NextMpduSize; - BOOLEAN bVLANPkt; - PQUEUE_ENTRY pQEntry; - - - ASSERT(pTxBlk); - - pQEntry = RemoveHeadQueue(&pTxBlk->TxPacketList); - pTxBlk->pPacket = QUEUE_ENTRY_TO_PACKET(pQEntry); - if (RTMP_FillTxBlkInfo(pAd, pTxBlk) != TRUE) - { - RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_FAILURE); - return; - } - - ASSERT(TX_BLK_TEST_FLAG(pTxBlk, fTX_bAllowFrag)); - bVLANPkt = (RTMP_GET_PACKET_VLAN(pTxBlk->pPacket) ? TRUE : FALSE); - - STAFindCipherAlgorithm(pAd, pTxBlk); - STABuildCommon802_11Header(pAd, pTxBlk); - - if (pTxBlk->CipherAlg == CIPHER_TKIP) - { - pTxBlk->pPacket = duplicate_pkt_with_TKIP_MIC(pAd, pTxBlk->pPacket); - if (pTxBlk->pPacket == NULL) - return; - RTMP_QueryPacketInfo(pTxBlk->pPacket, &PacketInfo, &pTxBlk->pSrcBufHeader, &pTxBlk->SrcBufLen); - } - - // skip 802.3 header - pTxBlk->pSrcBufData = pTxBlk->pSrcBufHeader + LENGTH_802_3; - pTxBlk->SrcBufLen -= LENGTH_802_3; - - - // skip vlan tag - if (bVLANPkt) - { - pTxBlk->pSrcBufData += LENGTH_802_1Q; - pTxBlk->SrcBufLen -= LENGTH_802_1Q; - } - - pHeaderBufPtr = &pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE]; - pHeader_802_11 = (HEADER_802_11 *)pHeaderBufPtr; - - - // skip common header - pHeaderBufPtr += pTxBlk->MpduHeaderLen; - - if (TX_BLK_TEST_FLAG(pTxBlk, fTX_bWMM)) - { - // - // build QOS Control bytes - // - *pHeaderBufPtr = (pTxBlk->UserPriority & 0x0F); - - *(pHeaderBufPtr+1) = 0; - pHeaderBufPtr +=2; - pTxBlk->MpduHeaderLen += 2; - } - - // - // padding at front of LLC header - // LLC header should locate at 4-octets aligment - // - pTxBlk->HdrPadLen = (ULONG)pHeaderBufPtr; - pHeaderBufPtr = (PCHAR) ROUND_UP(pHeaderBufPtr, 4); - pTxBlk->HdrPadLen = (ULONG)(pHeaderBufPtr - pTxBlk->HdrPadLen); - - - - // - // Insert LLC-SNAP encapsulation - 8 octets - // - // - // if original Ethernet frame contains no LLC/SNAP, - // then an extra LLC/SNAP encap is required - // - EXTRA_LLCSNAP_ENCAP_FROM_PKT_START(pTxBlk->pSrcBufHeader, pTxBlk->pExtraLlcSnapEncap); - if (pTxBlk->pExtraLlcSnapEncap) - { - UCHAR vlan_size; - - NdisMoveMemory(pHeaderBufPtr, pTxBlk->pExtraLlcSnapEncap, 6); - pHeaderBufPtr += 6; - // skip vlan tag - vlan_size = (bVLANPkt) ? LENGTH_802_1Q : 0; - // get 2 octets (TypeofLen) - NdisMoveMemory(pHeaderBufPtr, pTxBlk->pSrcBufHeader+12+vlan_size, 2); - pHeaderBufPtr += 2; - pTxBlk->MpduHeaderLen += LENGTH_802_1_H; - } - - - // If TKIP is used and fragmentation is required. Driver has to - // append TKIP MIC at tail of the scatter buffer - // MAC ASIC will only perform IV/EIV/ICV insertion but no TKIP MIC - if (pTxBlk->CipherAlg == CIPHER_TKIP) - { - - // NOTE: DON'T refer the skb->len directly after following copy. Becasue the length is not adjust - // to correct lenght, refer to pTxBlk->SrcBufLen for the packet length in following progress. - NdisMoveMemory(pTxBlk->pSrcBufData + pTxBlk->SrcBufLen, &pAd->PrivateInfo.Tx.MIC[0], 8); - //skb_put((RTPKT_TO_OSPKT(pTxBlk->pPacket))->tail, 8); - pTxBlk->SrcBufLen += 8; - pTxBlk->TotalFrameLen += 8; - pTxBlk->CipherAlg = CIPHER_TKIP_NO_MIC; - } - - // - // calcuate the overhead bytes that encryption algorithm may add. This - // affects the calculate of "duration" field - // - if ((pTxBlk->CipherAlg == CIPHER_WEP64) || (pTxBlk->CipherAlg == CIPHER_WEP128)) - EncryptionOverhead = 8; //WEP: IV[4] + ICV[4]; - else if (pTxBlk->CipherAlg == CIPHER_TKIP_NO_MIC) - EncryptionOverhead = 12;//TKIP: IV[4] + EIV[4] + ICV[4], MIC will be added to TotalPacketLength - else if (pTxBlk->CipherAlg == CIPHER_TKIP) - EncryptionOverhead = 20;//TKIP: IV[4] + EIV[4] + ICV[4] + MIC[8] - else if (pTxBlk->CipherAlg == CIPHER_AES) - EncryptionOverhead = 16; // AES: IV[4] + EIV[4] + MIC[8] - else - EncryptionOverhead = 0; - - // decide how much time an ACK/CTS frame will consume in the air - AckDuration = RTMPCalcDuration(pAd, pAd->CommonCfg.ExpectedACKRate[pTxBlk->TxRate], 14); - - // Init the total payload length of this frame. - SrcRemainingBytes = pTxBlk->SrcBufLen; - - pTxBlk->TotalFragNum = 0xff; - - do { - - FreeMpduSize = pAd->CommonCfg.FragmentThreshold - LENGTH_CRC; - - FreeMpduSize -= pTxBlk->MpduHeaderLen; - - if (SrcRemainingBytes <= FreeMpduSize) - { // this is the last or only fragment - - pTxBlk->SrcBufLen = SrcRemainingBytes; - - pHeader_802_11->FC.MoreFrag = 0; - pHeader_802_11->Duration = pAd->CommonCfg.Dsifs + AckDuration; - - // Indicate the lower layer that this's the last fragment. - pTxBlk->TotalFragNum = fragNum; - } - else - { // more fragment is required - - pTxBlk->SrcBufLen = FreeMpduSize; - - NextMpduSize = min(((UINT)SrcRemainingBytes - pTxBlk->SrcBufLen), ((UINT)pAd->CommonCfg.FragmentThreshold)); - pHeader_802_11->FC.MoreFrag = 1; - pHeader_802_11->Duration = (3 * pAd->CommonCfg.Dsifs) + (2 * AckDuration) + RTMPCalcDuration(pAd, pTxBlk->TxRate, NextMpduSize + EncryptionOverhead); - } - - if (fragNum == 0) - pTxBlk->FrameGap = IFS_HTTXOP; - else - pTxBlk->FrameGap = IFS_SIFS; - - RTMPWriteTxWI_Data(pAd, (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), pTxBlk); - - HAL_WriteFragTxResource(pAd, pTxBlk, fragNum, &FreeNumber); - - pAd->RalinkCounters.KickTxCount++; - pAd->RalinkCounters.OneSecTxDoneCount++; - - // Update the frame number, remaining size of the NDIS packet payload. - - // space for 802.11 header. - if (fragNum == 0 && pTxBlk->pExtraLlcSnapEncap) - pTxBlk->MpduHeaderLen -= LENGTH_802_1_H; - - fragNum++; - SrcRemainingBytes -= pTxBlk->SrcBufLen; - pTxBlk->pSrcBufData += pTxBlk->SrcBufLen; - - pHeader_802_11->Frag++; // increase Frag # - - }while(SrcRemainingBytes > 0); - - // - // Kick out Tx - // - HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx); -} - - -#define RELEASE_FRAMES_OF_TXBLK(_pAd, _pTxBlk, _pQEntry, _Status) \ - while(_pTxBlk->TxPacketList.Head) \ - { \ - _pQEntry = RemoveHeadQueue(&_pTxBlk->TxPacketList); \ - RELEASE_NDIS_PACKET(_pAd, QUEUE_ENTRY_TO_PACKET(_pQEntry), _Status); \ - } - - -/* - ======================================================================== - - Routine Description: - Copy frame from waiting queue into relative ring buffer and set - appropriate ASIC register to kick hardware encryption before really - sent out to air. - - Arguments: - pAd Pointer to our adapter - PNDIS_PACKET Pointer to outgoing Ndis frame - NumberOfFrag Number of fragment required - - Return Value: - None - - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -NDIS_STATUS STAHardTransmit( - IN PRTMP_ADAPTER pAd, - IN TX_BLK *pTxBlk, - IN UCHAR QueIdx) -{ - NDIS_PACKET *pPacket; - PQUEUE_ENTRY pQEntry; - - // --------------------------------------------- - // STEP 0. DO SANITY CHECK AND SOME EARLY PREPARATION. - // --------------------------------------------- - // - ASSERT(pTxBlk->TxPacketList.Number); - if (pTxBlk->TxPacketList.Head == NULL) - { - DBGPRINT(RT_DEBUG_ERROR, ("pTxBlk->TotalFrameNum == %ld!\n", pTxBlk->TxPacketList.Number)); - return NDIS_STATUS_FAILURE; - } - - pPacket = QUEUE_ENTRY_TO_PACKET(pTxBlk->TxPacketList.Head); - -#if 0 //def CARRIER_DETECTION_SUPPORT // Roger sync Carrier - if ((pAd->CommonCfg.CarrierDetect.Enable == TRUE) && (isCarrierDetectExist(pAd) == TRUE)) - { - DBGPRINT(RT_DEBUG_INFO,("STAHardTransmit --> radar detect not in normal mode !!!\n")); - RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); - return (NDIS_STATUS_FAILURE); - } -#endif // CARRIER_DETECTION_SUPPORT // - - // ------------------------------------------------------------------ - // STEP 1. WAKE UP PHY - // outgoing frame always wakeup PHY to prevent frame lost and - // turn off PSM bit to improve performance - // ------------------------------------------------------------------ - // not to change PSM bit, just send this frame out? - if ((pAd->StaCfg.Psm == PWR_SAVE) && OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) - { - DBGPRINT_RAW(RT_DEBUG_TRACE, ("AsicForceWakeup At HardTx\n")); - AsicForceWakeup(pAd, TRUE); - } - - // It should not change PSM bit, when APSD turn on. - if ((!(pAd->CommonCfg.bAPSDCapable && pAd->CommonCfg.APEdcaParm.bAPSDCapable) && (pAd->CommonCfg.bAPSDForcePowerSave == FALSE)) - || (RTMP_GET_PACKET_EAPOL(pTxBlk->pPacket)) - || (RTMP_GET_PACKET_WAI(pTxBlk->pPacket))) - { - if ((pAd->StaCfg.Psm == PWR_SAVE) && - (pAd->StaCfg.WindowsPowerMode == Ndis802_11PowerModeFast_PSP)) - MlmeSetPsmBit(pAd, PWR_ACTIVE); - } - - switch (pTxBlk->TxFrameType) - { -#ifdef DOT11_N_SUPPORT - case TX_AMPDU_FRAME: - STA_AMPDU_Frame_Tx(pAd, pTxBlk); - break; - case TX_AMSDU_FRAME: - STA_AMSDU_Frame_Tx(pAd, pTxBlk); - break; -#endif // DOT11_N_SUPPORT // - case TX_LEGACY_FRAME: - STA_Legacy_Frame_Tx(pAd, pTxBlk); - break; - case TX_MCAST_FRAME: - STA_Legacy_Frame_Tx(pAd, pTxBlk); - break; - case TX_RALINK_FRAME: - STA_ARalink_Frame_Tx(pAd, pTxBlk); - break; - case TX_FRAG_FRAME: - STA_Fragment_Frame_Tx(pAd, pTxBlk); - break; - default: - { - // It should not happened! - DBGPRINT(RT_DEBUG_ERROR, ("Send a pacekt was not classified!! It should not happen!\n")); - while(pTxBlk->TxPacketList.Number) - { - pQEntry = RemoveHeadQueue(&pTxBlk->TxPacketList); - pPacket = QUEUE_ENTRY_TO_PACKET(pQEntry); - if (pPacket) - RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); - } - } - break; - } - - return (NDIS_STATUS_SUCCESS); - -} - -ULONG HashBytesPolynomial(UCHAR *value, unsigned int len) -{ - unsigned char *word = value; - unsigned int ret = 0; - unsigned int i; - - for(i=0; i < len; i++) - { - int mod = i % 32; - ret ^=(unsigned int) (word[i]) << mod; - ret ^=(unsigned int) (word[i]) >> (32 - mod); - } - return ret; -} - -VOID Sta_Announce_or_Forward_802_3_Packet( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket, - IN UCHAR FromWhichBSSID) -{ - if (TRUE - ) - { - announce_802_3_packet(pAd, pPacket); - } - else - { - // release packet - RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); - } -} - +#include "../../rt2860/sta/rtmp_data.c" diff --git a/drivers/staging/rt2870/sta/sanity.c b/drivers/staging/rt2870/sta/sanity.c index 239872464bed..f1f2333bb993 100644 --- a/drivers/staging/rt2870/sta/sanity.c +++ b/drivers/staging/rt2870/sta/sanity.c @@ -1,420 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - sanity.c - - Abstract: - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - John Chang 2004-09-01 add WMM support -*/ -#include "../rt_config.h" - -extern UCHAR CISCO_OUI[]; - -extern UCHAR WPA_OUI[]; -extern UCHAR RSN_OUI[]; -extern UCHAR WME_INFO_ELEM[]; -extern UCHAR WME_PARM_ELEM[]; -extern UCHAR Ccx2QosInfo[]; -extern UCHAR RALINK_OUI[]; -extern UCHAR BROADCOM_OUI[]; - -/* - ========================================================================== - Description: - MLME message sanity check - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== - */ -BOOLEAN MlmeStartReqSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT CHAR Ssid[], - OUT UCHAR *pSsidLen) -{ - MLME_START_REQ_STRUCT *Info; - - Info = (MLME_START_REQ_STRUCT *)(Msg); - - if (Info->SsidLen > MAX_LEN_OF_SSID) - { - DBGPRINT(RT_DEBUG_TRACE, ("MlmeStartReqSanity fail - wrong SSID length\n")); - return FALSE; - } - - *pSsidLen = Info->SsidLen; - NdisMoveMemory(Ssid, Info->Ssid, *pSsidLen); - - return TRUE; -} - -/* - ========================================================================== - Description: - MLME message sanity check - Return: - TRUE if all parameters are OK, FALSE otherwise - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -BOOLEAN PeerAssocRspSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *pMsg, - IN ULONG MsgLen, - OUT PUCHAR pAddr2, - OUT USHORT *pCapabilityInfo, - OUT USHORT *pStatus, - OUT USHORT *pAid, - OUT UCHAR SupRate[], - OUT UCHAR *pSupRateLen, - OUT UCHAR ExtRate[], - OUT UCHAR *pExtRateLen, - OUT HT_CAPABILITY_IE *pHtCapability, - OUT ADD_HT_INFO_IE *pAddHtInfo, // AP might use this additional ht info IE - OUT UCHAR *pHtCapabilityLen, - OUT UCHAR *pAddHtInfoLen, - OUT UCHAR *pNewExtChannelOffset, - OUT PEDCA_PARM pEdcaParm, - OUT UCHAR *pCkipFlag) -{ - CHAR IeType, *Ptr; - PFRAME_802_11 pFrame = (PFRAME_802_11)pMsg; - PEID_STRUCT pEid; - ULONG Length = 0; - - *pNewExtChannelOffset = 0xff; - *pHtCapabilityLen = 0; - *pAddHtInfoLen = 0; - COPY_MAC_ADDR(pAddr2, pFrame->Hdr.Addr2); - Ptr = pFrame->Octet; - Length += LENGTH_802_11; - - NdisMoveMemory(pCapabilityInfo, &pFrame->Octet[0], 2); - Length += 2; - NdisMoveMemory(pStatus, &pFrame->Octet[2], 2); - Length += 2; - *pCkipFlag = 0; - *pExtRateLen = 0; - pEdcaParm->bValid = FALSE; - - if (*pStatus != MLME_SUCCESS) - return TRUE; - - NdisMoveMemory(pAid, &pFrame->Octet[4], 2); - Length += 2; - - // Aid already swaped byte order in RTMPFrameEndianChange() for big endian platform - *pAid = (*pAid) & 0x3fff; // AID is low 14-bit - - // -- get supported rates from payload and advance the pointer - IeType = pFrame->Octet[6]; - *pSupRateLen = pFrame->Octet[7]; - if ((IeType != IE_SUPP_RATES) || (*pSupRateLen > MAX_LEN_OF_SUPPORTED_RATES)) - { - DBGPRINT(RT_DEBUG_TRACE, ("PeerAssocRspSanity fail - wrong SupportedRates IE\n")); - return FALSE; - } - else - NdisMoveMemory(SupRate, &pFrame->Octet[8], *pSupRateLen); - - Length = Length + 2 + *pSupRateLen; - - // many AP implement proprietary IEs in non-standard order, we'd better - // tolerate mis-ordered IEs to get best compatibility - pEid = (PEID_STRUCT) &pFrame->Octet[8 + (*pSupRateLen)]; - - // get variable fields from payload and advance the pointer - while ((Length + 2 + pEid->Len) <= MsgLen) - { - switch (pEid->Eid) - { - case IE_EXT_SUPP_RATES: - if (pEid->Len <= MAX_LEN_OF_SUPPORTED_RATES) - { - NdisMoveMemory(ExtRate, pEid->Octet, pEid->Len); - *pExtRateLen = pEid->Len; - } - break; - - case IE_HT_CAP: - case IE_HT_CAP2: - if (pEid->Len >= SIZE_HT_CAP_IE) //Note: allow extension.!! - { - NdisMoveMemory(pHtCapability, pEid->Octet, SIZE_HT_CAP_IE); - - *(USHORT *)(&pHtCapability->HtCapInfo) = cpu2le16(*(USHORT *)(&pHtCapability->HtCapInfo)); - *(USHORT *)(&pHtCapability->ExtHtCapInfo) = cpu2le16(*(USHORT *)(&pHtCapability->ExtHtCapInfo)); - - *pHtCapabilityLen = SIZE_HT_CAP_IE; - } - else - { - DBGPRINT(RT_DEBUG_WARN, ("PeerAssocRspSanity - wrong IE_HT_CAP. \n")); - } - - break; -#ifdef DOT11_N_SUPPORT - case IE_ADD_HT: - case IE_ADD_HT2: - if (pEid->Len >= sizeof(ADD_HT_INFO_IE)) - { - // This IE allows extension, but we can ignore extra bytes beyond our knowledge , so only - // copy first sizeof(ADD_HT_INFO_IE) - NdisMoveMemory(pAddHtInfo, pEid->Octet, sizeof(ADD_HT_INFO_IE)); - - *(USHORT *)(&pAddHtInfo->AddHtInfo2) = cpu2le16(*(USHORT *)(&pAddHtInfo->AddHtInfo2)); - *(USHORT *)(&pAddHtInfo->AddHtInfo3) = cpu2le16(*(USHORT *)(&pAddHtInfo->AddHtInfo3)); - - *pAddHtInfoLen = SIZE_ADD_HT_INFO_IE; - } - else - { - DBGPRINT(RT_DEBUG_WARN, ("PeerAssocRspSanity - wrong IE_ADD_HT. \n")); - } - - break; - case IE_SECONDARY_CH_OFFSET: - if (pEid->Len == 1) - { - *pNewExtChannelOffset = pEid->Octet[0]; - } - else - { - DBGPRINT(RT_DEBUG_WARN, ("PeerAssocRspSanity - wrong IE_SECONDARY_CH_OFFSET. \n")); - } -#endif // DOT11_N_SUPPORT // - break; - case IE_AIRONET_CKIP: - // 0. Check Aironet IE length, it must be larger or equal to 28 - // Cisco's AP VxWork version(will not be supported) used this IE length as 28 - // Cisco's AP IOS version used this IE length as 30 - if (pEid->Len < (CKIP_NEGOTIATION_LENGTH - 2)) - break; - - // 1. Copy CKIP flag byte to buffer for process - *pCkipFlag = *(pEid->Octet + 8); - break; - - case IE_AIRONET_IPADDRESS: - if (pEid->Len != 0x0A) - break; - - // Get Cisco Aironet IP information - if (NdisEqualMemory(pEid->Octet, CISCO_OUI, 3) == 1) - NdisMoveMemory(pAd->StaCfg.AironetIPAddress, pEid->Octet + 4, 4); - break; - - // CCX2, WMM use the same IE value - // case IE_CCX_V2: - case IE_VENDOR_SPECIFIC: - // handle WME PARAMTER ELEMENT - if (NdisEqualMemory(pEid->Octet, WME_PARM_ELEM, 6) && (pEid->Len == 24)) - { - PUCHAR ptr; - int i; - - // parsing EDCA parameters - pEdcaParm->bValid = TRUE; - pEdcaParm->bQAck = FALSE; // pEid->Octet[0] & 0x10; - pEdcaParm->bQueueRequest = FALSE; // pEid->Octet[0] & 0x20; - pEdcaParm->bTxopRequest = FALSE; // pEid->Octet[0] & 0x40; - //pEdcaParm->bMoreDataAck = FALSE; // pEid->Octet[0] & 0x80; - pEdcaParm->EdcaUpdateCount = pEid->Octet[6] & 0x0f; - pEdcaParm->bAPSDCapable = (pEid->Octet[6] & 0x80) ? 1 : 0; - ptr = &pEid->Octet[8]; - for (i=0; i<4; i++) - { - UCHAR aci = (*ptr & 0x60) >> 5; // b5~6 is AC INDEX - pEdcaParm->bACM[aci] = (((*ptr) & 0x10) == 0x10); // b5 is ACM - pEdcaParm->Aifsn[aci] = (*ptr) & 0x0f; // b0~3 is AIFSN - pEdcaParm->Cwmin[aci] = *(ptr+1) & 0x0f; // b0~4 is Cwmin - pEdcaParm->Cwmax[aci] = *(ptr+1) >> 4; // b5~8 is Cwmax - pEdcaParm->Txop[aci] = *(ptr+2) + 256 * (*(ptr+3)); // in unit of 32-us - ptr += 4; // point to next AC - } - } - - // handle CCX IE - else - { - // 0. Check the size and CCX admin control - if (pAd->StaCfg.CCXControl.field.Enable == 0) - break; - if (pEid->Len != 5) - break; - - // Turn CCX2 if matched - if (NdisEqualMemory(pEid->Octet, Ccx2IeInfo, 5) == 1) - pAd->StaCfg.CCXEnable = TRUE; - break; - } - break; - - default: - DBGPRINT(RT_DEBUG_TRACE, ("PeerAssocRspSanity - ignore unrecognized EID = %d\n", pEid->Eid)); - break; - } - - Length = Length + 2 + pEid->Len; - pEid = (PEID_STRUCT)((UCHAR*)pEid + 2 + pEid->Len); - } - - // Force CCX2 enable to TRUE for those AP didn't replay CCX v2 IE, we still force it to be on - if (pAd->StaCfg.CCXControl.field.Enable == 1) - pAd->StaCfg.CCXEnable = TRUE; - - return TRUE; -} - -/* - ========================================================================== - Description: - MLME message sanity check - Return: - TRUE if all parameters are OK, FALSE otherwise - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -BOOLEAN PeerProbeReqSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PUCHAR pAddr2, - OUT CHAR Ssid[], - OUT UCHAR *pSsidLen) -{ - UCHAR Idx; - UCHAR RateLen; - CHAR IeType; - PFRAME_802_11 pFrame = (PFRAME_802_11)Msg; - - COPY_MAC_ADDR(pAddr2, pFrame->Hdr.Addr2); - - if ((pFrame->Octet[0] != IE_SSID) || (pFrame->Octet[1] > MAX_LEN_OF_SSID)) - { - DBGPRINT(RT_DEBUG_TRACE, ("PeerProbeReqSanity fail - wrong SSID IE(Type=%d,Len=%d)\n",pFrame->Octet[0],pFrame->Octet[1])); - return FALSE; - } - - *pSsidLen = pFrame->Octet[1]; - NdisMoveMemory(Ssid, &pFrame->Octet[2], *pSsidLen); - - Idx = *pSsidLen + 2; - - // -- get supported rates from payload and advance the pointer - IeType = pFrame->Octet[Idx]; - RateLen = pFrame->Octet[Idx + 1]; - if (IeType != IE_SUPP_RATES) - { - DBGPRINT(RT_DEBUG_TRACE, ("PeerProbeReqSanity fail - wrong SupportRates IE(Type=%d,Len=%d)\n",pFrame->Octet[Idx],pFrame->Octet[Idx+1])); - return FALSE; - } - else - { - if ((pAd->CommonCfg.PhyMode == PHY_11G) && (RateLen < 8)) - return (FALSE); - } - - return TRUE; -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -BOOLEAN GetTimBit( - IN CHAR *Ptr, - IN USHORT Aid, - OUT UCHAR *TimLen, - OUT UCHAR *BcastFlag, - OUT UCHAR *DtimCount, - OUT UCHAR *DtimPeriod, - OUT UCHAR *MessageToMe) -{ - UCHAR BitCntl, N1, N2, MyByte, MyBit; - CHAR *IdxPtr; - - IdxPtr = Ptr; - - IdxPtr ++; - *TimLen = *IdxPtr; - - // get DTIM Count from TIM element - IdxPtr ++; - *DtimCount = *IdxPtr; - - // get DTIM Period from TIM element - IdxPtr++; - *DtimPeriod = *IdxPtr; - - // get Bitmap Control from TIM element - IdxPtr++; - BitCntl = *IdxPtr; - - if ((*DtimCount == 0) && (BitCntl & 0x01)) - *BcastFlag = TRUE; - else - *BcastFlag = FALSE; - - // Parse Partial Virtual Bitmap from TIM element - N1 = BitCntl & 0xfe; // N1 is the first bitmap byte# - N2 = *TimLen - 4 + N1; // N2 is the last bitmap byte# - - if ((Aid < (N1 << 3)) || (Aid >= ((N2 + 1) << 3))) - *MessageToMe = FALSE; - else - { - MyByte = (Aid >> 3) - N1; // my byte position in the bitmap byte-stream - MyBit = Aid % 16 - ((MyByte & 0x01)? 8:0); - - IdxPtr += (MyByte + 1); - - //if (*IdxPtr) - // DBGPRINT(RT_DEBUG_WARN, ("TIM bitmap = 0x%02x\n", *IdxPtr)); - - if (*IdxPtr & (0x01 << MyBit)) - *MessageToMe = TRUE; - else - *MessageToMe = FALSE; - } - - return TRUE; -} - +#include "../../rt2860/sta/sanity.c" diff --git a/drivers/staging/rt2870/sta/sync.c b/drivers/staging/rt2870/sta/sync.c index a48975566e08..66c8772ad346 100644 --- a/drivers/staging/rt2870/sta/sync.c +++ b/drivers/staging/rt2870/sta/sync.c @@ -1,1753 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - sync.c - - Abstract: - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - John Chang 2004-09-01 modified for rt2561/2661 - Jan Lee 2006-08-01 modified for rt2860 for 802.11n -*/ -#include "../rt_config.h" - -#define ADHOC_ENTRY_BEACON_LOST_TIME (2*OS_HZ) // 2 sec - -/* - ========================================================================== - Description: - The sync state machine, - Parameters: - Sm - pointer to the state machine - Note: - the state machine looks like the following - - ========================================================================== - */ -VOID SyncStateMachineInit( - IN PRTMP_ADAPTER pAd, - IN STATE_MACHINE *Sm, - OUT STATE_MACHINE_FUNC Trans[]) -{ - StateMachineInit(Sm, Trans, MAX_SYNC_STATE, MAX_SYNC_MSG, (STATE_MACHINE_FUNC)Drop, SYNC_IDLE, SYNC_MACHINE_BASE); - - // column 1 - StateMachineSetAction(Sm, SYNC_IDLE, MT2_MLME_SCAN_REQ, (STATE_MACHINE_FUNC)MlmeScanReqAction); - StateMachineSetAction(Sm, SYNC_IDLE, MT2_MLME_JOIN_REQ, (STATE_MACHINE_FUNC)MlmeJoinReqAction); - StateMachineSetAction(Sm, SYNC_IDLE, MT2_MLME_START_REQ, (STATE_MACHINE_FUNC)MlmeStartReqAction); - StateMachineSetAction(Sm, SYNC_IDLE, MT2_PEER_BEACON, (STATE_MACHINE_FUNC)PeerBeacon); - StateMachineSetAction(Sm, SYNC_IDLE, MT2_PEER_PROBE_REQ, (STATE_MACHINE_FUNC)PeerProbeReqAction); - - //column 2 - StateMachineSetAction(Sm, JOIN_WAIT_BEACON, MT2_MLME_SCAN_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenScan); - StateMachineSetAction(Sm, JOIN_WAIT_BEACON, MT2_MLME_JOIN_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenJoin); - StateMachineSetAction(Sm, JOIN_WAIT_BEACON, MT2_MLME_START_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenStart); - StateMachineSetAction(Sm, JOIN_WAIT_BEACON, MT2_PEER_BEACON, (STATE_MACHINE_FUNC)PeerBeaconAtJoinAction); - StateMachineSetAction(Sm, JOIN_WAIT_BEACON, MT2_BEACON_TIMEOUT, (STATE_MACHINE_FUNC)BeaconTimeoutAtJoinAction); - - // column 3 - StateMachineSetAction(Sm, SCAN_LISTEN, MT2_MLME_SCAN_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenScan); - StateMachineSetAction(Sm, SCAN_LISTEN, MT2_MLME_JOIN_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenJoin); - StateMachineSetAction(Sm, SCAN_LISTEN, MT2_MLME_START_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenStart); - StateMachineSetAction(Sm, SCAN_LISTEN, MT2_PEER_BEACON, (STATE_MACHINE_FUNC)PeerBeaconAtScanAction); - StateMachineSetAction(Sm, SCAN_LISTEN, MT2_PEER_PROBE_RSP, (STATE_MACHINE_FUNC)PeerBeaconAtScanAction); - StateMachineSetAction(Sm, SCAN_LISTEN, MT2_SCAN_TIMEOUT, (STATE_MACHINE_FUNC)ScanTimeoutAction); - - // timer init - RTMPInitTimer(pAd, &pAd->MlmeAux.BeaconTimer, GET_TIMER_FUNCTION(BeaconTimeout), pAd, FALSE); - RTMPInitTimer(pAd, &pAd->MlmeAux.ScanTimer, GET_TIMER_FUNCTION(ScanTimeout), pAd, FALSE); -} - -/* - ========================================================================== - Description: - Beacon timeout handler, executed in timer thread - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID BeaconTimeout( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3) -{ - RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext; - - DBGPRINT(RT_DEBUG_TRACE,("SYNC - BeaconTimeout\n")); - - // Do nothing if the driver is starting halt state. - // This might happen when timer already been fired before cancel timer with mlmehalt - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) - return; - -#ifdef DOT11_N_SUPPORT - if ((pAd->CommonCfg.BBPCurrentBW == BW_40) - ) - { - UCHAR BBPValue = 0; - AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE); - AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel); - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); - BBPValue &= (~0x18); - BBPValue |= 0x10; - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); - DBGPRINT(RT_DEBUG_TRACE, ("SYNC - End of SCAN, restore to 40MHz channel %d, Total BSS[%02d]\n",pAd->CommonCfg.CentralChannel, pAd->ScanTab.BssNr)); - } -#endif // DOT11_N_SUPPORT // - - MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_BEACON_TIMEOUT, 0, NULL); - RT28XX_MLME_HANDLER(pAd); -} - -/* - ========================================================================== - Description: - Scan timeout handler, executed in timer thread - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID ScanTimeout( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3) -{ - RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext; - - - // Do nothing if the driver is starting halt state. - // This might happen when timer already been fired before cancel timer with mlmehalt - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) - return; - - if (MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_SCAN_TIMEOUT, 0, NULL)) - { - RT28XX_MLME_HANDLER(pAd); - } - else - { - // To prevent SyncMachine.CurrState is SCAN_LISTEN forever. - pAd->MlmeAux.Channel = 0; - ScanNextChannel(pAd); - if (pAd->CommonCfg.bWirelessEvent) - { - RTMPSendWirelessEvent(pAd, IW_SCAN_ENQUEUE_FAIL_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); - } - } -} - -/* - ========================================================================== - Description: - MLME SCAN req state machine procedure - ========================================================================== - */ -VOID MlmeScanReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - UCHAR Ssid[MAX_LEN_OF_SSID], SsidLen, ScanType, BssType, BBPValue = 0; - BOOLEAN TimerCancelled; - ULONG Now; - USHORT Status; - PHEADER_802_11 pHdr80211; - PUCHAR pOutBuffer = NULL; - NDIS_STATUS NStatus; - - // Check the total scan tries for one single OID command - // If this is the CCX 2.0 Case, skip that! - if ( !RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_START_UP)) - { - DBGPRINT(RT_DEBUG_TRACE, ("SYNC - MlmeScanReqAction before Startup\n")); - return; - } - - // Increase the scan retry counters. - pAd->StaCfg.ScanCnt++; - - - // first check the parameter sanity - if (MlmeScanReqSanity(pAd, - Elem->Msg, - Elem->MsgLen, - &BssType, - Ssid, - &SsidLen, - &ScanType)) - { - - // Check for channel load and noise hist request - // Suspend MSDU only at scan request, not the last two mentioned - if ((ScanType == SCAN_CISCO_NOISE) || (ScanType == SCAN_CISCO_CHANNEL_LOAD)) - { - if (pAd->StaCfg.CCXScanChannel != pAd->CommonCfg.Channel) - RTMPSuspendMsduTransmission(pAd); // Suspend MSDU transmission here - } - else - { - // Suspend MSDU transmission here - RTMPSuspendMsduTransmission(pAd); - } - - // - // To prevent data lost. - // Send an NULL data with turned PSM bit on to current associated AP before SCAN progress. - // And should send an NULL data with turned PSM bit off to AP, when scan progress done - // - if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) && (INFRA_ON(pAd))) - { - NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); - if (NStatus == NDIS_STATUS_SUCCESS) - { - pHdr80211 = (PHEADER_802_11) pOutBuffer; - MgtMacHeaderInit(pAd, pHdr80211, SUBTYPE_NULL_FUNC, 1, pAd->CommonCfg.Bssid, pAd->CommonCfg.Bssid); - pHdr80211->Duration = 0; - pHdr80211->FC.Type = BTYPE_DATA; - pHdr80211->FC.PwrMgmt = PWR_SAVE; - - // Send using priority queue - MiniportMMRequest(pAd, 0, pOutBuffer, sizeof(HEADER_802_11)); - DBGPRINT(RT_DEBUG_TRACE, ("MlmeScanReqAction -- Send PSM Data frame for off channel RM\n")); - MlmeFreeMemory(pAd, pOutBuffer); - RTMPusecDelay(5000); - } - } - - NdisGetSystemUpTime(&Now); - pAd->StaCfg.LastScanTime = Now; - // reset all the timers - RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer, &TimerCancelled); - RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &TimerCancelled); - - // record desired BSS parameters - pAd->MlmeAux.BssType = BssType; - pAd->MlmeAux.ScanType = ScanType; - pAd->MlmeAux.SsidLen = SsidLen; - NdisZeroMemory(pAd->MlmeAux.Ssid, MAX_LEN_OF_SSID); - NdisMoveMemory(pAd->MlmeAux.Ssid, Ssid, SsidLen); - - // start from the first channel - pAd->MlmeAux.Channel = FirstChannel(pAd); - - // Change the scan channel when dealing with CCX beacon report - if ((ScanType == SCAN_CISCO_PASSIVE) || (ScanType == SCAN_CISCO_ACTIVE) || - (ScanType == SCAN_CISCO_CHANNEL_LOAD) || (ScanType == SCAN_CISCO_NOISE)) - pAd->MlmeAux.Channel = pAd->StaCfg.CCXScanChannel; - - // Let BBP register at 20MHz to do scan - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); - BBPValue &= (~0x18); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); - DBGPRINT(RT_DEBUG_TRACE, ("SYNC - BBP R4 to 20MHz.l\n")); - ScanNextChannel(pAd); - } - else - { - DBGPRINT_ERR(("SYNC - MlmeScanReqAction() sanity check fail\n")); - pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; - Status = MLME_INVALID_FORMAT; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_SCAN_CONF, 2, &Status); - } -} - -/* - ========================================================================== - Description: - MLME JOIN req state machine procedure - ========================================================================== - */ -VOID MlmeJoinReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - UCHAR BBPValue = 0; - BSS_ENTRY *pBss; - BOOLEAN TimerCancelled; - HEADER_802_11 Hdr80211; - NDIS_STATUS NStatus; - ULONG FrameLen = 0; - PUCHAR pOutBuffer = NULL; - PUCHAR pSupRate = NULL; - UCHAR SupRateLen; - PUCHAR pExtRate = NULL; - UCHAR ExtRateLen; - UCHAR ASupRate[] = {0x8C, 0x12, 0x98, 0x24, 0xb0, 0x48, 0x60, 0x6C}; - UCHAR ASupRateLen = sizeof(ASupRate)/sizeof(UCHAR); - MLME_JOIN_REQ_STRUCT *pInfo = (MLME_JOIN_REQ_STRUCT *)(Elem->Msg); - - DBGPRINT(RT_DEBUG_TRACE, ("SYNC - MlmeJoinReqAction(BSS #%ld)\n", pInfo->BssIdx)); - - - // reset all the timers - RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &TimerCancelled); - RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer, &TimerCancelled); - - pBss = &pAd->MlmeAux.SsidBssTab.BssEntry[pInfo->BssIdx]; - - // record the desired SSID & BSSID we're waiting for - COPY_MAC_ADDR(pAd->MlmeAux.Bssid, pBss->Bssid); - - // If AP's SSID is not hidden, it is OK for updating ssid to MlmeAux again. - if (pBss->Hidden == 0) - { - NdisMoveMemory(pAd->MlmeAux.Ssid, pBss->Ssid, pBss->SsidLen); - pAd->MlmeAux.SsidLen = pBss->SsidLen; - } - - pAd->MlmeAux.BssType = pBss->BssType; - pAd->MlmeAux.Channel = pBss->Channel; - pAd->MlmeAux.CentralChannel = pBss->CentralChannel; - -#ifdef EXT_BUILD_CHANNEL_LIST - // Country IE of the AP will be evaluated and will be used. - if ((pAd->StaCfg.IEEE80211dClientMode != Rt802_11_D_None) && - (pBss->bHasCountryIE == TRUE)) - { - NdisMoveMemory(&pAd->CommonCfg.CountryCode[0], &pBss->CountryString[0], 2); - if (pBss->CountryString[2] == 'I') - pAd->CommonCfg.Geography = IDOR; - else if (pBss->CountryString[2] == 'O') - pAd->CommonCfg.Geography = ODOR; - else - pAd->CommonCfg.Geography = BOTH; - BuildChannelListEx(pAd); - } -#endif // EXT_BUILD_CHANNEL_LIST // - - // Let BBP register at 20MHz to do scan - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); - BBPValue &= (~0x18); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); - DBGPRINT(RT_DEBUG_TRACE, ("SYNC - BBP R4 to 20MHz.l\n")); - - // switch channel and waiting for beacon timer - AsicSwitchChannel(pAd, pAd->MlmeAux.Channel, FALSE); - AsicLockChannel(pAd, pAd->MlmeAux.Channel); - RTMPSetTimer(&pAd->MlmeAux.BeaconTimer, JOIN_TIMEOUT); - - do - { - if (((pAd->CommonCfg.bIEEE80211H == 1) && - (pAd->MlmeAux.Channel > 14) && - RadarChannelCheck(pAd, pAd->MlmeAux.Channel)) -#ifdef CARRIER_DETECTION_SUPPORT // Roger sync Carrier - || (pAd->CommonCfg.CarrierDetect.Enable == TRUE) -#endif // CARRIER_DETECTION_SUPPORT // - ) - { - // - // We can't send any Probe request frame to meet 802.11h. - // - if (pBss->Hidden == 0) - break; - } - - // - // send probe request - // - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); - if (NStatus == NDIS_STATUS_SUCCESS) - { - if (pAd->MlmeAux.Channel <= 14) - { - pSupRate = pAd->CommonCfg.SupRate; - SupRateLen = pAd->CommonCfg.SupRateLen; - pExtRate = pAd->CommonCfg.ExtRate; - ExtRateLen = pAd->CommonCfg.ExtRateLen; - } - else - { - // - // Overwrite Support Rate, CCK rate are not allowed - // - pSupRate = ASupRate; - SupRateLen = ASupRateLen; - ExtRateLen = 0; - } - - if (pAd->MlmeAux.BssType == BSS_INFRA) - MgtMacHeaderInit(pAd, &Hdr80211, SUBTYPE_PROBE_REQ, 0, pAd->MlmeAux.Bssid, pAd->MlmeAux.Bssid); - else - MgtMacHeaderInit(pAd, &Hdr80211, SUBTYPE_PROBE_REQ, 0, BROADCAST_ADDR, BROADCAST_ADDR); - - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(HEADER_802_11), &Hdr80211, - 1, &SsidIe, - 1, &pAd->MlmeAux.SsidLen, - pAd->MlmeAux.SsidLen, pAd->MlmeAux.Ssid, - 1, &SupRateIe, - 1, &SupRateLen, - SupRateLen, pSupRate, - END_OF_ARGS); - - if (ExtRateLen) - { - ULONG Tmp; - MakeOutgoingFrame(pOutBuffer + FrameLen, &Tmp, - 1, &ExtRateIe, - 1, &ExtRateLen, - ExtRateLen, pExtRate, - END_OF_ARGS); - FrameLen += Tmp; - } - - - MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); - } - } while (FALSE); - - DBGPRINT(RT_DEBUG_TRACE, ("SYNC - Switch to ch %d, Wait BEACON from %02x:%02x:%02x:%02x:%02x:%02x\n", - pBss->Channel, pBss->Bssid[0], pBss->Bssid[1], pBss->Bssid[2], pBss->Bssid[3], pBss->Bssid[4], pBss->Bssid[5])); - - pAd->Mlme.SyncMachine.CurrState = JOIN_WAIT_BEACON; -} - -/* - ========================================================================== - Description: - MLME START Request state machine procedure, starting an IBSS - ========================================================================== - */ -VOID MlmeStartReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - UCHAR Ssid[MAX_LEN_OF_SSID], SsidLen; - BOOLEAN TimerCancelled; - - // New for WPA security suites - UCHAR VarIE[MAX_VIE_LEN]; // Total VIE length = MAX_VIE_LEN - -5 - NDIS_802_11_VARIABLE_IEs *pVIE = NULL; - LARGE_INTEGER TimeStamp; - BOOLEAN Privacy; - USHORT Status; - - // Init Variable IE structure - pVIE = (PNDIS_802_11_VARIABLE_IEs) VarIE; - pVIE->Length = 0; - TimeStamp.u.LowPart = 0; - TimeStamp.u.HighPart = 0; - - if (MlmeStartReqSanity(pAd, Elem->Msg, Elem->MsgLen, Ssid, &SsidLen)) - { - // reset all the timers - RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &TimerCancelled); - RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer, &TimerCancelled); - - // - // Start a new IBSS. All IBSS parameters are decided now.... - // - DBGPRINT(RT_DEBUG_TRACE, ("MlmeStartReqAction - Start a new IBSS. All IBSS parameters are decided now.... \n")); - pAd->MlmeAux.BssType = BSS_ADHOC; - NdisMoveMemory(pAd->MlmeAux.Ssid, Ssid, SsidLen); - pAd->MlmeAux.SsidLen = SsidLen; - - // generate a radom number as BSSID - MacAddrRandomBssid(pAd, pAd->MlmeAux.Bssid); - DBGPRINT(RT_DEBUG_TRACE, ("MlmeStartReqAction - generate a radom number as BSSID \n")); - - Privacy = (pAd->StaCfg.WepStatus == Ndis802_11Encryption1Enabled) || - (pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) || - (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled); - pAd->MlmeAux.CapabilityInfo = CAP_GENERATE(0,1,Privacy, (pAd->CommonCfg.TxPreamble == Rt802_11PreambleShort), 1, 0); - pAd->MlmeAux.BeaconPeriod = pAd->CommonCfg.BeaconPeriod; - pAd->MlmeAux.AtimWin = pAd->StaCfg.AtimWin; - pAd->MlmeAux.Channel = pAd->CommonCfg.Channel; - - pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel; - pAd->MlmeAux.CentralChannel = pAd->CommonCfg.CentralChannel; - - pAd->MlmeAux.SupRateLen= pAd->CommonCfg.SupRateLen; - NdisMoveMemory(pAd->MlmeAux.SupRate, pAd->CommonCfg.SupRate, MAX_LEN_OF_SUPPORTED_RATES); - RTMPCheckRates(pAd, pAd->MlmeAux.SupRate, &pAd->MlmeAux.SupRateLen); - pAd->MlmeAux.ExtRateLen = pAd->CommonCfg.ExtRateLen; - NdisMoveMemory(pAd->MlmeAux.ExtRate, pAd->CommonCfg.ExtRate, MAX_LEN_OF_SUPPORTED_RATES); - RTMPCheckRates(pAd, pAd->MlmeAux.ExtRate, &pAd->MlmeAux.ExtRateLen); -#ifdef DOT11_N_SUPPORT - if (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) - { - RTMPUpdateHTIE(&pAd->CommonCfg.DesiredHtPhy, &pAd->StaCfg.DesiredHtPhyInfo.MCSSet[0], &pAd->MlmeAux.HtCapability, &pAd->MlmeAux.AddHtInfo); - pAd->MlmeAux.HtCapabilityLen = sizeof(HT_CAPABILITY_IE); - // Not turn pAd->StaActive.SupportedHtPhy.bHtEnable = TRUE here. - DBGPRINT(RT_DEBUG_TRACE, ("SYNC -pAd->StaActive.SupportedHtPhy.bHtEnable = TRUE\n")); - } - else -#endif // DOT11_N_SUPPORT // - { - pAd->MlmeAux.HtCapabilityLen = 0; - pAd->StaActive.SupportedPhyInfo.bHtEnable = FALSE; - } - // temporarily not support QOS in IBSS - NdisZeroMemory(&pAd->MlmeAux.APEdcaParm, sizeof(EDCA_PARM)); - NdisZeroMemory(&pAd->MlmeAux.APQbssLoad, sizeof(QBSS_LOAD_PARM)); - NdisZeroMemory(&pAd->MlmeAux.APQosCapability, sizeof(QOS_CAPABILITY_PARM)); - - AsicSwitchChannel(pAd, pAd->MlmeAux.Channel, FALSE); - AsicLockChannel(pAd, pAd->MlmeAux.Channel); - - DBGPRINT(RT_DEBUG_TRACE, ("SYNC - MlmeStartReqAction(ch= %d,sup rates= %d, ext rates=%d)\n", - pAd->MlmeAux.Channel, pAd->MlmeAux.SupRateLen, pAd->MlmeAux.ExtRateLen)); - - pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; - Status = MLME_SUCCESS; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_START_CONF, 2, &Status); - } - else - { - DBGPRINT_ERR(("SYNC - MlmeStartReqAction() sanity check fail.\n")); - pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; - Status = MLME_INVALID_FORMAT; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_START_CONF, 2, &Status); - } -} - -/* - ========================================================================== - Description: - peer sends beacon back when scanning - ========================================================================== - */ -VOID PeerBeaconAtScanAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - UCHAR Bssid[MAC_ADDR_LEN], Addr2[MAC_ADDR_LEN]; - UCHAR Ssid[MAX_LEN_OF_SSID], BssType, Channel, NewChannel, - SsidLen, DtimCount, DtimPeriod, BcastFlag, MessageToMe; - CF_PARM CfParm; - USHORT BeaconPeriod, AtimWin, CapabilityInfo; - PFRAME_802_11 pFrame; - LARGE_INTEGER TimeStamp; - UCHAR Erp; - UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES], ExtRate[MAX_LEN_OF_SUPPORTED_RATES]; - UCHAR SupRateLen, ExtRateLen; - USHORT LenVIE; - UCHAR CkipFlag; - UCHAR AironetCellPowerLimit; - EDCA_PARM EdcaParm; - QBSS_LOAD_PARM QbssLoad; - QOS_CAPABILITY_PARM QosCapability; - ULONG RalinkIe; - UCHAR VarIE[MAX_VIE_LEN]; // Total VIE length = MAX_VIE_LEN - -5 - NDIS_802_11_VARIABLE_IEs *pVIE = NULL; - HT_CAPABILITY_IE HtCapability; - ADD_HT_INFO_IE AddHtInfo; // AP might use this additional ht info IE - UCHAR HtCapabilityLen = 0, PreNHtCapabilityLen = 0; - UCHAR AddHtInfoLen; - UCHAR NewExtChannelOffset = 0xff; - - - // NdisFillMemory(Ssid, MAX_LEN_OF_SSID, 0x00); - pFrame = (PFRAME_802_11) Elem->Msg; - // Init Variable IE structure - pVIE = (PNDIS_802_11_VARIABLE_IEs) VarIE; - pVIE->Length = 0; -#ifdef DOT11_N_SUPPORT - RTMPZeroMemory(&HtCapability, sizeof(HtCapability)); - RTMPZeroMemory(&AddHtInfo, sizeof(ADD_HT_INFO_IE)); -#endif // DOT11_N_SUPPORT // - - if (PeerBeaconAndProbeRspSanity(pAd, - Elem->Msg, - Elem->MsgLen, - Elem->Channel, - Addr2, - Bssid, - Ssid, - &SsidLen, - &BssType, - &BeaconPeriod, - &Channel, - &NewChannel, - &TimeStamp, - &CfParm, - &AtimWin, - &CapabilityInfo, - &Erp, - &DtimCount, - &DtimPeriod, - &BcastFlag, - &MessageToMe, - SupRate, - &SupRateLen, - ExtRate, - &ExtRateLen, - &CkipFlag, - &AironetCellPowerLimit, - &EdcaParm, - &QbssLoad, - &QosCapability, - &RalinkIe, - &HtCapabilityLen, - &PreNHtCapabilityLen, - &HtCapability, - &AddHtInfoLen, - &AddHtInfo, - &NewExtChannelOffset, - &LenVIE, - pVIE)) - { - ULONG Idx; - CHAR Rssi = 0; - - Idx = BssTableSearch(&pAd->ScanTab, Bssid, Channel); - if (Idx != BSS_NOT_FOUND) - Rssi = pAd->ScanTab.BssEntry[Idx].Rssi; - - Rssi = RTMPMaxRssi(pAd, ConvertToRssi(pAd, Elem->Rssi0, RSSI_0), ConvertToRssi(pAd, Elem->Rssi1, RSSI_1), ConvertToRssi(pAd, Elem->Rssi2, RSSI_2)); - - -#ifdef DOT11_N_SUPPORT - if ((HtCapabilityLen > 0) || (PreNHtCapabilityLen > 0)) - HtCapabilityLen = SIZE_HT_CAP_IE; -#endif // DOT11_N_SUPPORT // - if ((pAd->StaCfg.CCXReqType != MSRN_TYPE_UNUSED) && (Channel == pAd->StaCfg.CCXScanChannel)) - { - Idx = BssTableSetEntry(pAd, &pAd->StaCfg.CCXBssTab, Bssid, Ssid, SsidLen, BssType, BeaconPeriod, - &CfParm, AtimWin, CapabilityInfo, SupRate, SupRateLen,ExtRate, ExtRateLen, &HtCapability, - &AddHtInfo, HtCapabilityLen, AddHtInfoLen, NewExtChannelOffset, Channel, Rssi, TimeStamp, CkipFlag, - &EdcaParm, &QosCapability, &QbssLoad, LenVIE, pVIE); - if (Idx != BSS_NOT_FOUND) - { - NdisMoveMemory(pAd->StaCfg.CCXBssTab.BssEntry[Idx].PTSF, &Elem->Msg[24], 4); - NdisMoveMemory(&pAd->StaCfg.CCXBssTab.BssEntry[Idx].TTSF[0], &Elem->TimeStamp.u.LowPart, 4); - NdisMoveMemory(&pAd->StaCfg.CCXBssTab.BssEntry[Idx].TTSF[4], &Elem->TimeStamp.u.LowPart, 4); - if (pAd->StaCfg.CCXReqType == MSRN_TYPE_BEACON_REQ) - AironetAddBeaconReport(pAd, Idx, Elem); - } - } - else - { - Idx = BssTableSetEntry(pAd, &pAd->ScanTab, Bssid, Ssid, SsidLen, BssType, BeaconPeriod, - &CfParm, AtimWin, CapabilityInfo, SupRate, SupRateLen, ExtRate, ExtRateLen, &HtCapability, - &AddHtInfo, HtCapabilityLen, AddHtInfoLen, NewExtChannelOffset, Channel, Rssi, TimeStamp, CkipFlag, - &EdcaParm, &QosCapability, &QbssLoad, LenVIE, pVIE); -#ifdef DOT11_N_SUPPORT -#ifdef DOT11N_DRAFT3 - if (pAd->ChannelList[pAd->CommonCfg.ChannelListIdx].bEffectedChannel == TRUE) - { - UCHAR RegClass; - PeerBeaconAndProbeRspSanity2(pAd, Elem->Msg, Elem->MsgLen, &RegClass); - TriEventTableSetEntry(pAd, &pAd->CommonCfg.TriggerEventTab, Bssid, &HtCapability, HtCapabilityLen, RegClass, Channel); - } -#endif // DOT11N_DRAFT3 // -#endif // DOT11_N_SUPPORT // - if (Idx != BSS_NOT_FOUND) - { - NdisMoveMemory(pAd->ScanTab.BssEntry[Idx].PTSF, &Elem->Msg[24], 4); - NdisMoveMemory(&pAd->ScanTab.BssEntry[Idx].TTSF[0], &Elem->TimeStamp.u.LowPart, 4); - NdisMoveMemory(&pAd->ScanTab.BssEntry[Idx].TTSF[4], &Elem->TimeStamp.u.LowPart, 4); - } - } - } - // sanity check fail, ignored -} - -/* - ========================================================================== - Description: - When waiting joining the (I)BSS, beacon received from external - ========================================================================== - */ -VOID PeerBeaconAtJoinAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - UCHAR Bssid[MAC_ADDR_LEN], Addr2[MAC_ADDR_LEN]; - UCHAR Ssid[MAX_LEN_OF_SSID], SsidLen, BssType, Channel, MessageToMe, - DtimCount, DtimPeriod, BcastFlag, NewChannel; - LARGE_INTEGER TimeStamp; - USHORT BeaconPeriod, AtimWin, CapabilityInfo; - CF_PARM Cf; - BOOLEAN TimerCancelled; - UCHAR Erp; - UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES], ExtRate[MAX_LEN_OF_SUPPORTED_RATES]; - UCHAR SupRateLen, ExtRateLen; - UCHAR CkipFlag; - USHORT LenVIE; - UCHAR AironetCellPowerLimit; - EDCA_PARM EdcaParm; - QBSS_LOAD_PARM QbssLoad; - QOS_CAPABILITY_PARM QosCapability; - USHORT Status; - UCHAR VarIE[MAX_VIE_LEN]; // Total VIE length = MAX_VIE_LEN - -5 - NDIS_802_11_VARIABLE_IEs *pVIE = NULL; - ULONG RalinkIe; - ULONG Idx; - HT_CAPABILITY_IE HtCapability; - ADD_HT_INFO_IE AddHtInfo; // AP might use this additional ht info IE - UCHAR HtCapabilityLen = 0, PreNHtCapabilityLen = 0; - UCHAR AddHtInfoLen; - UCHAR NewExtChannelOffset = 0xff; -#ifdef DOT11_N_SUPPORT - UCHAR CentralChannel; -#endif // DOT11_N_SUPPORT // - - // Init Variable IE structure - pVIE = (PNDIS_802_11_VARIABLE_IEs) VarIE; - pVIE->Length = 0; - RTMPZeroMemory(&HtCapability, sizeof(HtCapability)); - RTMPZeroMemory(&AddHtInfo, sizeof(ADD_HT_INFO_IE)); - - - if (PeerBeaconAndProbeRspSanity(pAd, - Elem->Msg, - Elem->MsgLen, - Elem->Channel, - Addr2, - Bssid, - Ssid, - &SsidLen, - &BssType, - &BeaconPeriod, - &Channel, - &NewChannel, - &TimeStamp, - &Cf, - &AtimWin, - &CapabilityInfo, - &Erp, - &DtimCount, - &DtimPeriod, - &BcastFlag, - &MessageToMe, - SupRate, - &SupRateLen, - ExtRate, - &ExtRateLen, - &CkipFlag, - &AironetCellPowerLimit, - &EdcaParm, - &QbssLoad, - &QosCapability, - &RalinkIe, - &HtCapabilityLen, - &PreNHtCapabilityLen, - &HtCapability, - &AddHtInfoLen, - &AddHtInfo, - &NewExtChannelOffset, - &LenVIE, - pVIE)) - { - // Disqualify 11b only adhoc when we are in 11g only adhoc mode - if ((BssType == BSS_ADHOC) && (pAd->CommonCfg.PhyMode == PHY_11G) && ((SupRateLen+ExtRateLen)< 12)) - return; - - // BEACON from desired BSS/IBSS found. We should be able to decide most - // BSS parameters here. - // Q. But what happen if this JOIN doesn't conclude a successful ASSOCIATEION? - // Do we need to receover back all parameters belonging to previous BSS? - // A. Should be not. There's no back-door recover to previous AP. It still need - // a new JOIN-AUTH-ASSOC sequence. - if (MAC_ADDR_EQUAL(pAd->MlmeAux.Bssid, Bssid)) - { - DBGPRINT(RT_DEBUG_TRACE, ("SYNC - receive desired BEACON at JoinWaitBeacon... Channel = %d\n", Channel)); - RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer, &TimerCancelled); - - // Update RSSI to prevent No signal display when cards first initialized - pAd->StaCfg.RssiSample.LastRssi0 = ConvertToRssi(pAd, Elem->Rssi0, RSSI_0); - pAd->StaCfg.RssiSample.LastRssi1 = ConvertToRssi(pAd, Elem->Rssi1, RSSI_1); - pAd->StaCfg.RssiSample.LastRssi2 = ConvertToRssi(pAd, Elem->Rssi2, RSSI_2); - pAd->StaCfg.RssiSample.AvgRssi0 = pAd->StaCfg.RssiSample.LastRssi0; - pAd->StaCfg.RssiSample.AvgRssi0X8 = pAd->StaCfg.RssiSample.AvgRssi0 << 3; - pAd->StaCfg.RssiSample.AvgRssi1 = pAd->StaCfg.RssiSample.LastRssi1; - pAd->StaCfg.RssiSample.AvgRssi1X8 = pAd->StaCfg.RssiSample.AvgRssi1 << 3; - pAd->StaCfg.RssiSample.AvgRssi2 = pAd->StaCfg.RssiSample.LastRssi2; - pAd->StaCfg.RssiSample.AvgRssi2X8 = pAd->StaCfg.RssiSample.AvgRssi2 << 3; - - // - // We need to check if SSID only set to any, then we can record the current SSID. - // Otherwise will cause hidden SSID association failed. - // - if (pAd->MlmeAux.SsidLen == 0) - { - NdisMoveMemory(pAd->MlmeAux.Ssid, Ssid, SsidLen); - pAd->MlmeAux.SsidLen = SsidLen; - } - else - { - Idx = BssSsidTableSearch(&pAd->ScanTab, Bssid, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen, Channel); - - if (Idx != BSS_NOT_FOUND) - { - // - // Multiple SSID case, used correct CapabilityInfo - // - CapabilityInfo = pAd->ScanTab.BssEntry[Idx].CapabilityInfo; - } - } - NdisMoveMemory(pAd->MlmeAux.Bssid, Bssid, MAC_ADDR_LEN); - pAd->MlmeAux.CapabilityInfo = CapabilityInfo & SUPPORTED_CAPABILITY_INFO; - pAd->MlmeAux.BssType = BssType; - pAd->MlmeAux.BeaconPeriod = BeaconPeriod; - pAd->MlmeAux.Channel = Channel; - pAd->MlmeAux.AtimWin = AtimWin; - pAd->MlmeAux.CfpPeriod = Cf.CfpPeriod; - pAd->MlmeAux.CfpMaxDuration = Cf.CfpMaxDuration; - pAd->MlmeAux.APRalinkIe = RalinkIe; - - // Copy AP's supported rate to MlmeAux for creating assoication request - // Also filter out not supported rate - pAd->MlmeAux.SupRateLen = SupRateLen; - NdisMoveMemory(pAd->MlmeAux.SupRate, SupRate, SupRateLen); - RTMPCheckRates(pAd, pAd->MlmeAux.SupRate, &pAd->MlmeAux.SupRateLen); - pAd->MlmeAux.ExtRateLen = ExtRateLen; - NdisMoveMemory(pAd->MlmeAux.ExtRate, ExtRate, ExtRateLen); - RTMPCheckRates(pAd, pAd->MlmeAux.ExtRate, &pAd->MlmeAux.ExtRateLen); - - NdisZeroMemory(pAd->StaActive.SupportedPhyInfo.MCSSet, 16); -#ifdef DOT11_N_SUPPORT - pAd->MlmeAux.NewExtChannelOffset = NewExtChannelOffset; - pAd->MlmeAux.HtCapabilityLen = HtCapabilityLen; - - // filter out un-supported ht rates - if (((HtCapabilityLen > 0) || (PreNHtCapabilityLen > 0)) && (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) - { - RTMPZeroMemory(&pAd->MlmeAux.HtCapability, SIZE_HT_CAP_IE); - RTMPMoveMemory(&pAd->MlmeAux.AddHtInfo, &AddHtInfo, SIZE_ADD_HT_INFO_IE); - - // StaActive.SupportedHtPhy.MCSSet stores Peer AP's 11n Rx capability - NdisMoveMemory(pAd->StaActive.SupportedPhyInfo.MCSSet, HtCapability.MCSSet, 16); - pAd->MlmeAux.NewExtChannelOffset = NewExtChannelOffset; - pAd->MlmeAux.HtCapabilityLen = SIZE_HT_CAP_IE; - pAd->StaActive.SupportedPhyInfo.bHtEnable = TRUE; - if (PreNHtCapabilityLen > 0) - pAd->StaActive.SupportedPhyInfo.bPreNHt = TRUE; - RTMPCheckHt(pAd, BSSID_WCID, &HtCapability, &AddHtInfo); - // Copy AP Parameter to StaActive. This is also in LinkUp. - DBGPRINT(RT_DEBUG_TRACE, ("PeerBeaconAtJoinAction! (MpduDensity=%d, MaxRAmpduFactor=%d, BW=%d)\n", - pAd->StaActive.SupportedHtPhy.MpduDensity, pAd->StaActive.SupportedHtPhy.MaxRAmpduFactor, HtCapability.HtCapInfo.ChannelWidth)); - - if (AddHtInfoLen > 0) - { - CentralChannel = AddHtInfo.ControlChan; - // Check again the Bandwidth capability of this AP. - if ((AddHtInfo.ControlChan > 2)&& (AddHtInfo.AddHtInfo.ExtChanOffset == EXTCHA_BELOW) && (HtCapability.HtCapInfo.ChannelWidth == BW_40)) - { - CentralChannel = AddHtInfo.ControlChan - 2; - } - else if ((AddHtInfo.AddHtInfo.ExtChanOffset == EXTCHA_ABOVE) && (HtCapability.HtCapInfo.ChannelWidth == BW_40)) - { - CentralChannel = AddHtInfo.ControlChan + 2; - } - - // Check Error . - if (pAd->MlmeAux.CentralChannel != CentralChannel) - DBGPRINT(RT_DEBUG_ERROR, ("PeerBeaconAtJoinAction HT===>Beacon Central Channel = %d, Control Channel = %d. Mlmeaux CentralChannel = %d\n", CentralChannel, AddHtInfo.ControlChan, pAd->MlmeAux.CentralChannel)); - - DBGPRINT(RT_DEBUG_TRACE, ("PeerBeaconAtJoinAction HT===>Central Channel = %d, Control Channel = %d, .\n", CentralChannel, AddHtInfo.ControlChan)); - - } - - } - else -#endif // DOT11_N_SUPPORT // - { - // To prevent error, let legacy AP must have same CentralChannel and Channel. - if ((HtCapabilityLen == 0) && (PreNHtCapabilityLen == 0)) - pAd->MlmeAux.CentralChannel = pAd->MlmeAux.Channel; - - pAd->StaActive.SupportedPhyInfo.bHtEnable = FALSE; - RTMPZeroMemory(&pAd->MlmeAux.HtCapability, SIZE_HT_CAP_IE); - RTMPZeroMemory(&pAd->MlmeAux.AddHtInfo, SIZE_ADD_HT_INFO_IE); - } - - RTMPUpdateMlmeRate(pAd); - - // copy QOS related information - if ((pAd->CommonCfg.bWmmCapable) -#ifdef DOT11_N_SUPPORT - || (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) -#endif // DOT11_N_SUPPORT // - ) - { - NdisMoveMemory(&pAd->MlmeAux.APEdcaParm, &EdcaParm, sizeof(EDCA_PARM)); - NdisMoveMemory(&pAd->MlmeAux.APQbssLoad, &QbssLoad, sizeof(QBSS_LOAD_PARM)); - NdisMoveMemory(&pAd->MlmeAux.APQosCapability, &QosCapability, sizeof(QOS_CAPABILITY_PARM)); - } - else - { - NdisZeroMemory(&pAd->MlmeAux.APEdcaParm, sizeof(EDCA_PARM)); - NdisZeroMemory(&pAd->MlmeAux.APQbssLoad, sizeof(QBSS_LOAD_PARM)); - NdisZeroMemory(&pAd->MlmeAux.APQosCapability, sizeof(QOS_CAPABILITY_PARM)); - } - - DBGPRINT(RT_DEBUG_TRACE, ("SYNC - after JOIN, SupRateLen=%d, ExtRateLen=%d\n", - pAd->MlmeAux.SupRateLen, pAd->MlmeAux.ExtRateLen)); - -#ifdef LEAP_SUPPORT - // Update CkipFlag - pAd->StaCfg.CkipFlag = CkipFlag; - - // Keep TimeStamp for Re-Association used. - if (LEAP_CCKM_ON(pAd) && (pAd->StaCfg.CCKMLinkUpFlag == TRUE)) - pAd->StaCfg.CCKMBeaconAtJoinTimeStamp = TimeStamp; -#endif // LEAP_SUPPORT // - - if (AironetCellPowerLimit != 0xFF) - { - //We need to change our TxPower for CCX 2.0 AP Control of Client Transmit Power - ChangeToCellPowerLimit(pAd, AironetCellPowerLimit); - } - else //Used the default TX Power Percentage. - pAd->CommonCfg.TxPowerPercentage = pAd->CommonCfg.TxPowerDefault; - - pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; - Status = MLME_SUCCESS; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_JOIN_CONF, 2, &Status); - } - // not to me BEACON, ignored - } - // sanity check fail, ignore this frame -} - -/* - ========================================================================== - Description: - receive BEACON from peer - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID PeerBeacon( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - UCHAR Bssid[MAC_ADDR_LEN], Addr2[MAC_ADDR_LEN]; - CHAR Ssid[MAX_LEN_OF_SSID]; - CF_PARM CfParm; - UCHAR SsidLen, MessageToMe=0, BssType, Channel, NewChannel, index=0; - UCHAR DtimCount=0, DtimPeriod=0, BcastFlag=0; - USHORT CapabilityInfo, AtimWin, BeaconPeriod; - LARGE_INTEGER TimeStamp; - USHORT TbttNumToNextWakeUp; - UCHAR Erp; - UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES], ExtRate[MAX_LEN_OF_SUPPORTED_RATES]; - UCHAR SupRateLen, ExtRateLen; - UCHAR CkipFlag; - USHORT LenVIE; - UCHAR AironetCellPowerLimit; - EDCA_PARM EdcaParm; - QBSS_LOAD_PARM QbssLoad; - QOS_CAPABILITY_PARM QosCapability; - ULONG RalinkIe; - // New for WPA security suites - UCHAR VarIE[MAX_VIE_LEN]; // Total VIE length = MAX_VIE_LEN - -5 - NDIS_802_11_VARIABLE_IEs *pVIE = NULL; - HT_CAPABILITY_IE HtCapability; - ADD_HT_INFO_IE AddHtInfo; // AP might use this additional ht info IE - UCHAR HtCapabilityLen, PreNHtCapabilityLen; - UCHAR AddHtInfoLen; - UCHAR NewExtChannelOffset = 0xff; - - -#ifdef RALINK_ATE - if (ATE_ON(pAd)) - { - return; - } -#endif // RALINK_ATE // - - if (!(INFRA_ON(pAd) || ADHOC_ON(pAd) - )) - return; - - // Init Variable IE structure - pVIE = (PNDIS_802_11_VARIABLE_IEs) VarIE; - pVIE->Length = 0; - RTMPZeroMemory(&HtCapability, sizeof(HtCapability)); - RTMPZeroMemory(&AddHtInfo, sizeof(ADD_HT_INFO_IE)); - - if (PeerBeaconAndProbeRspSanity(pAd, - Elem->Msg, - Elem->MsgLen, - Elem->Channel, - Addr2, - Bssid, - Ssid, - &SsidLen, - &BssType, - &BeaconPeriod, - &Channel, - &NewChannel, - &TimeStamp, - &CfParm, - &AtimWin, - &CapabilityInfo, - &Erp, - &DtimCount, - &DtimPeriod, - &BcastFlag, - &MessageToMe, - SupRate, - &SupRateLen, - ExtRate, - &ExtRateLen, - &CkipFlag, - &AironetCellPowerLimit, - &EdcaParm, - &QbssLoad, - &QosCapability, - &RalinkIe, - &HtCapabilityLen, - &PreNHtCapabilityLen, - &HtCapability, - &AddHtInfoLen, - &AddHtInfo, - &NewExtChannelOffset, - &LenVIE, - pVIE)) - { - BOOLEAN is_my_bssid, is_my_ssid; - ULONG Bssidx, Now; - BSS_ENTRY *pBss; - CHAR RealRssi = RTMPMaxRssi(pAd, ConvertToRssi(pAd, Elem->Rssi0, RSSI_0), ConvertToRssi(pAd, Elem->Rssi1, RSSI_1), ConvertToRssi(pAd, Elem->Rssi2, RSSI_2)); - - is_my_bssid = MAC_ADDR_EQUAL(Bssid, pAd->CommonCfg.Bssid)? TRUE : FALSE; - is_my_ssid = SSID_EQUAL(Ssid, SsidLen, pAd->CommonCfg.Ssid, pAd->CommonCfg.SsidLen)? TRUE:FALSE; - - - // ignore BEACON not for my SSID - if ((! is_my_ssid) && (! is_my_bssid)) - return; - - // It means STA waits disassoc completely from this AP, ignores this beacon. - if (pAd->Mlme.CntlMachine.CurrState == CNTL_WAIT_DISASSOC) - return; - -#ifdef DOT11_N_SUPPORT - // Copy Control channel for this BSSID. - if (AddHtInfoLen != 0) - Channel = AddHtInfo.ControlChan; - - if ((HtCapabilityLen > 0) || (PreNHtCapabilityLen > 0)) - HtCapabilityLen = SIZE_HT_CAP_IE; -#endif // DOT11_N_SUPPORT // - - // - // Housekeeping "SsidBssTab" table for later-on ROAMing usage. - // - Bssidx = BssTableSearch(&pAd->ScanTab, Bssid, Channel); - if (Bssidx == BSS_NOT_FOUND) - { - // discover new AP of this network, create BSS entry - Bssidx = BssTableSetEntry(pAd, &pAd->ScanTab, Bssid, Ssid, SsidLen, BssType, BeaconPeriod, - &CfParm, AtimWin, CapabilityInfo, SupRate, SupRateLen, ExtRate, ExtRateLen, - &HtCapability, &AddHtInfo,HtCapabilityLen,AddHtInfoLen,NewExtChannelOffset, Channel, - RealRssi, TimeStamp, CkipFlag, &EdcaParm, &QosCapability, - &QbssLoad, LenVIE, pVIE); - if (Bssidx == BSS_NOT_FOUND) // return if BSS table full - return; - - NdisMoveMemory(pAd->ScanTab.BssEntry[Bssidx].PTSF, &Elem->Msg[24], 4); - NdisMoveMemory(&pAd->ScanTab.BssEntry[Bssidx].TTSF[0], &Elem->TimeStamp.u.LowPart, 4); - NdisMoveMemory(&pAd->ScanTab.BssEntry[Bssidx].TTSF[4], &Elem->TimeStamp.u.LowPart, 4); - - - - } - - if ((pAd->CommonCfg.bIEEE80211H == 1) && (NewChannel != 0) && (Channel != NewChannel)) - { - // Switching to channel 1 can prevent from rescanning the current channel immediately (by auto reconnection). - // In addition, clear the MLME queue and the scan table to discard the RX packets and previous scanning results. - AsicSwitchChannel(pAd, 1, FALSE); - AsicLockChannel(pAd, 1); - LinkDown(pAd, FALSE); - MlmeQueueInit(&pAd->Mlme.Queue); - BssTableInit(&pAd->ScanTab); - RTMPusecDelay(1000000); // use delay to prevent STA do reassoc - - // channel sanity check - for (index = 0 ; index < pAd->ChannelListNum; index++) - { - if (pAd->ChannelList[index].Channel == NewChannel) - { - pAd->ScanTab.BssEntry[Bssidx].Channel = NewChannel; - pAd->CommonCfg.Channel = NewChannel; - AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); - AsicLockChannel(pAd, pAd->CommonCfg.Channel); - DBGPRINT(RT_DEBUG_TRACE, ("PeerBeacon - STA receive channel switch announcement IE (New Channel =%d)\n", NewChannel)); - break; - } - } - - if (index >= pAd->ChannelListNum) - { - DBGPRINT_ERR(("PeerBeacon(can not find New Channel=%d in ChannelList[%d]\n", pAd->CommonCfg.Channel, pAd->ChannelListNum)); - } - } - - // if the ssid matched & bssid unmatched, we should select the bssid with large value. - // This might happened when two STA start at the same time - if ((! is_my_bssid) && ADHOC_ON(pAd)) - { - INT i; - - // Add the safeguard against the mismatch of adhoc wep status - if (pAd->StaCfg.WepStatus != pAd->ScanTab.BssEntry[Bssidx].WepStatus) - { - return; - } - - // collapse into the ADHOC network which has bigger BSSID value. - for (i = 0; i < 6; i++) - { - if (Bssid[i] > pAd->CommonCfg.Bssid[i]) - { - DBGPRINT(RT_DEBUG_TRACE, ("SYNC - merge to the IBSS with bigger BSSID=%02x:%02x:%02x:%02x:%02x:%02x\n", - Bssid[0], Bssid[1], Bssid[2], Bssid[3], Bssid[4], Bssid[5])); - AsicDisableSync(pAd); - COPY_MAC_ADDR(pAd->CommonCfg.Bssid, Bssid); - AsicSetBssid(pAd, pAd->CommonCfg.Bssid); - MakeIbssBeacon(pAd); // re-build BEACON frame - AsicEnableIbssSync(pAd); // copy BEACON frame to on-chip memory - is_my_bssid = TRUE; - break; - } - else if (Bssid[i] < pAd->CommonCfg.Bssid[i]) - break; - } - } - - - NdisGetSystemUpTime(&Now); - pBss = &pAd->ScanTab.BssEntry[Bssidx]; - pBss->Rssi = RealRssi; // lastest RSSI - pBss->LastBeaconRxTime = Now; // last RX timestamp - - // - // BEACON from my BSSID - either IBSS or INFRA network - // - if (is_my_bssid) - { - RXWI_STRUC RxWI; - - pAd->StaCfg.DtimCount = DtimCount; - pAd->StaCfg.DtimPeriod = DtimPeriod; - pAd->StaCfg.LastBeaconRxTime = Now; - - - RxWI.RSSI0 = Elem->Rssi0; - RxWI.RSSI1 = Elem->Rssi1; - RxWI.RSSI2 = Elem->Rssi2; - - Update_Rssi_Sample(pAd, &pAd->StaCfg.RssiSample, &RxWI); - if (AironetCellPowerLimit != 0xFF) - { - // - // We get the Cisco (ccx) "TxPower Limit" required - // Changed to appropriate TxPower Limit for Ciso Compatible Extensions - // - ChangeToCellPowerLimit(pAd, AironetCellPowerLimit); - } - else - { - // - // AironetCellPowerLimit equal to 0xFF means the Cisco (ccx) "TxPower Limit" not exist. - // Used the default TX Power Percentage, that set from UI. - // - pAd->CommonCfg.TxPowerPercentage = pAd->CommonCfg.TxPowerDefault; - } - - if (ADHOC_ON(pAd) && (CAP_IS_IBSS_ON(CapabilityInfo))) - { - UCHAR MaxSupportedRateIn500Kbps = 0; - UCHAR idx; - MAC_TABLE_ENTRY *pEntry; - - // supported rates array may not be sorted. sort it and find the maximum rate - for (idx=0; idxWcid == RESERVED_WCID)) || - (pEntry && ((pEntry->LastBeaconRxTime + ADHOC_ENTRY_BEACON_LOST_TIME) < Now))) - { - if (pEntry == NULL) - // Another adhoc joining, add to our MAC table. - pEntry = MacTableInsertEntry(pAd, Addr2, BSS0, FALSE); - - if (StaAddMacTableEntry(pAd, pEntry, MaxSupportedRateIn500Kbps, &HtCapability, HtCapabilityLen, CapabilityInfo) == FALSE) - { - DBGPRINT(RT_DEBUG_TRACE, ("ADHOC - Add Entry failed.\n")); - return; - } - - if (pEntry && - (Elem->Wcid == RESERVED_WCID)) - { - idx = pAd->StaCfg.DefaultKeyId; - RT28XX_STA_SECURITY_INFO_ADD(pAd, BSS0, idx, pEntry); - } - } - - if (pEntry && pEntry->ValidAsCLI) - pEntry->LastBeaconRxTime = Now; - - // At least another peer in this IBSS, declare MediaState as CONNECTED - if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) - { - OPSTATUS_SET_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED); - - pAd->IndicateMediaState = NdisMediaStateConnected; - RTMP_IndicateMediaState(pAd); - pAd->ExtraInfo = GENERAL_LINK_UP; - AsicSetBssid(pAd, pAd->CommonCfg.Bssid); - - // 2003/03/12 - john - // Make sure this entry in "ScanTab" table, thus complies to Microsoft's policy that - // "site survey" result should always include the current connected network. - // - Bssidx = BssTableSearch(&pAd->ScanTab, Bssid, Channel); - if (Bssidx == BSS_NOT_FOUND) - { - Bssidx = BssTableSetEntry(pAd, &pAd->ScanTab, Bssid, Ssid, SsidLen, BssType, BeaconPeriod, - &CfParm, AtimWin, CapabilityInfo, SupRate, SupRateLen, ExtRate, ExtRateLen, &HtCapability, - &AddHtInfo, HtCapabilityLen, AddHtInfoLen, NewExtChannelOffset, Channel, RealRssi, TimeStamp, 0, - &EdcaParm, &QosCapability, &QbssLoad, LenVIE, pVIE); - } - DBGPRINT(RT_DEBUG_TRACE, ("ADHOC fOP_STATUS_MEDIA_STATE_CONNECTED.\n")); - } - } - - if (INFRA_ON(pAd)) - { - BOOLEAN bUseShortSlot, bUseBGProtection; - - // decide to use/change to - - // 1. long slot (20 us) or short slot (9 us) time - // 2. turn on/off RTS/CTS and/or CTS-to-self protection - // 3. short preamble - - //bUseShortSlot = pAd->CommonCfg.bUseShortSlotTime && CAP_IS_SHORT_SLOT(CapabilityInfo); - bUseShortSlot = CAP_IS_SHORT_SLOT(CapabilityInfo); - if (bUseShortSlot != OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_SHORT_SLOT_INUSED)) - AsicSetSlotTime(pAd, bUseShortSlot); - - bUseBGProtection = (pAd->CommonCfg.UseBGProtection == 1) || // always use - ((pAd->CommonCfg.UseBGProtection == 0) && ERP_IS_USE_PROTECTION(Erp)); - - if (pAd->CommonCfg.Channel > 14) // always no BG protection in A-band. falsely happened when switching A/G band to a dual-band AP - bUseBGProtection = FALSE; - - if (bUseBGProtection != OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_BG_PROTECTION_INUSED)) - { - if (bUseBGProtection) - { - OPSTATUS_SET_FLAG(pAd, fOP_STATUS_BG_PROTECTION_INUSED); - AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, (OFDMSETPROTECT|CCKSETPROTECT|ALLN_SETPROTECT),FALSE,(pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent == 1)); - } - else - { - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_BG_PROTECTION_INUSED); - AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, (OFDMSETPROTECT|CCKSETPROTECT|ALLN_SETPROTECT),TRUE,(pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent == 1)); - } - - DBGPRINT(RT_DEBUG_WARN, ("SYNC - AP changed B/G protection to %d\n", bUseBGProtection)); - } - -#ifdef DOT11_N_SUPPORT - // check Ht protection mode. and adhere to the Non-GF device indication by AP. - if ((AddHtInfoLen != 0) && - ((AddHtInfo.AddHtInfo2.OperaionMode != pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode) || - (AddHtInfo.AddHtInfo2.NonGfPresent != pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent))) - { - pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent = AddHtInfo.AddHtInfo2.NonGfPresent; - pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode = AddHtInfo.AddHtInfo2.OperaionMode; - if (pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent == 1) - { - AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, ALLN_SETPROTECT, FALSE, TRUE); - } - else - AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, ALLN_SETPROTECT, FALSE, FALSE); - - DBGPRINT(RT_DEBUG_TRACE, ("SYNC - AP changed N OperaionMode to %d\n", pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode)); - } -#endif // DOT11_N_SUPPORT // - - if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED) && - ERP_IS_USE_BARKER_PREAMBLE(Erp)) - { - MlmeSetTxPreamble(pAd, Rt802_11PreambleLong); - DBGPRINT(RT_DEBUG_TRACE, ("SYNC - AP forced to use LONG preamble\n")); - } - - if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED) && - (EdcaParm.bValid == TRUE) && - (EdcaParm.EdcaUpdateCount != pAd->CommonCfg.APEdcaParm.EdcaUpdateCount)) - { - DBGPRINT(RT_DEBUG_TRACE, ("SYNC - AP change EDCA parameters(from %d to %d)\n", - pAd->CommonCfg.APEdcaParm.EdcaUpdateCount, - EdcaParm.EdcaUpdateCount)); - AsicSetEdcaParm(pAd, &EdcaParm); - } - - // copy QOS related information - NdisMoveMemory(&pAd->CommonCfg.APQbssLoad, &QbssLoad, sizeof(QBSS_LOAD_PARM)); - NdisMoveMemory(&pAd->CommonCfg.APQosCapability, &QosCapability, sizeof(QOS_CAPABILITY_PARM)); - } - - // only INFRASTRUCTURE mode support power-saving feature - if ((INFRA_ON(pAd) && (pAd->StaCfg.Psm == PWR_SAVE)) || (pAd->CommonCfg.bAPSDForcePowerSave)) - { - UCHAR FreeNumber; - // 1. AP has backlogged unicast-to-me frame, stay AWAKE, send PSPOLL - // 2. AP has backlogged broadcast/multicast frame and we want those frames, stay AWAKE - // 3. we have outgoing frames in TxRing or MgmtRing, better stay AWAKE - // 4. Psm change to PWR_SAVE, but AP not been informed yet, we better stay AWAKE - // 5. otherwise, put PHY back to sleep to save battery. - if (MessageToMe) - { - if (pAd->CommonCfg.bAPSDCapable && pAd->CommonCfg.APEdcaParm.bAPSDCapable && - pAd->CommonCfg.bAPSDAC_BE && pAd->CommonCfg.bAPSDAC_BK && pAd->CommonCfg.bAPSDAC_VI && pAd->CommonCfg.bAPSDAC_VO) - { - pAd->CommonCfg.bNeedSendTriggerFrame = TRUE; - } - else - RT28XX_PS_POLL_ENQUEUE(pAd); - } - else if (BcastFlag && (DtimCount == 0) && OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_RECEIVE_DTIM)) - { - } - else if ((pAd->TxSwQueue[QID_AC_BK].Number != 0) || - (pAd->TxSwQueue[QID_AC_BE].Number != 0) || - (pAd->TxSwQueue[QID_AC_VI].Number != 0) || - (pAd->TxSwQueue[QID_AC_VO].Number != 0) || - (RTMPFreeTXDRequest(pAd, QID_AC_BK, TX_RING_SIZE - 1, &FreeNumber) != NDIS_STATUS_SUCCESS) || - (RTMPFreeTXDRequest(pAd, QID_AC_BE, TX_RING_SIZE - 1, &FreeNumber) != NDIS_STATUS_SUCCESS) || - (RTMPFreeTXDRequest(pAd, QID_AC_VI, TX_RING_SIZE - 1, &FreeNumber) != NDIS_STATUS_SUCCESS) || - (RTMPFreeTXDRequest(pAd, QID_AC_VO, TX_RING_SIZE - 1, &FreeNumber) != NDIS_STATUS_SUCCESS) || - (RTMPFreeTXDRequest(pAd, QID_MGMT, MGMT_RING_SIZE - 1, &FreeNumber) != NDIS_STATUS_SUCCESS)) - { - // TODO: consider scheduled HCCA. might not be proper to use traditional DTIM-based power-saving scheme - // can we cheat here (i.e. just check MGMT & AC_BE) for better performance? - } - else - { - USHORT NextDtim = DtimCount; - - if (NextDtim == 0) - NextDtim = DtimPeriod; - - TbttNumToNextWakeUp = pAd->StaCfg.DefaultListenCount; - if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_RECEIVE_DTIM) && (TbttNumToNextWakeUp > NextDtim)) - TbttNumToNextWakeUp = NextDtim; - - if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) - { - AsicSleepThenAutoWakeup(pAd, TbttNumToNextWakeUp); - } - } - } - } - // not my BSSID, ignore it - } - // sanity check fail, ignore this frame -} - -/* - ========================================================================== - Description: - Receive PROBE REQ from remote peer when operating in IBSS mode - ========================================================================== - */ -VOID PeerProbeReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - UCHAR Addr2[MAC_ADDR_LEN]; - CHAR Ssid[MAX_LEN_OF_SSID]; - UCHAR SsidLen; -#ifdef DOT11_N_SUPPORT - UCHAR HtLen, AddHtLen, NewExtLen; -#endif // DOT11_N_SUPPORT // - HEADER_802_11 ProbeRspHdr; - NDIS_STATUS NStatus; - PUCHAR pOutBuffer = NULL; - ULONG FrameLen = 0; - LARGE_INTEGER FakeTimestamp; - UCHAR DsLen = 1, IbssLen = 2; - UCHAR LocalErpIe[3] = {IE_ERP, 1, 0}; - BOOLEAN Privacy; - USHORT CapabilityInfo; - UCHAR RSNIe = IE_WPA; - - if (! ADHOC_ON(pAd)) - return; - - if (PeerProbeReqSanity(pAd, Elem->Msg, Elem->MsgLen, Addr2, Ssid, &SsidLen)) - { - if ((SsidLen == 0) || SSID_EQUAL(Ssid, SsidLen, pAd->CommonCfg.Ssid, pAd->CommonCfg.SsidLen)) - { - // allocate and send out ProbeRsp frame - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory - if (NStatus != NDIS_STATUS_SUCCESS) - return; - - //pAd->StaCfg.AtimWin = 0; // ?????? - - Privacy = (pAd->StaCfg.WepStatus == Ndis802_11Encryption1Enabled) || - (pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) || - (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled); - CapabilityInfo = CAP_GENERATE(0, 1, Privacy, (pAd->CommonCfg.TxPreamble == Rt802_11PreambleShort), 0, 0); - - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(HEADER_802_11), &ProbeRspHdr, - TIMESTAMP_LEN, &FakeTimestamp, - 2, &pAd->CommonCfg.BeaconPeriod, - 2, &CapabilityInfo, - 1, &SsidIe, - 1, &pAd->CommonCfg.SsidLen, - pAd->CommonCfg.SsidLen, pAd->CommonCfg.Ssid, - 1, &SupRateIe, - 1, &pAd->StaActive.SupRateLen, - pAd->StaActive.SupRateLen, pAd->StaActive.SupRate, - 1, &DsIe, - 1, &DsLen, - 1, &pAd->CommonCfg.Channel, - 1, &IbssIe, - 1, &IbssLen, - 2, &pAd->StaActive.AtimWin, - END_OF_ARGS); - - if (pAd->StaActive.ExtRateLen) - { - ULONG tmp; - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - 3, LocalErpIe, - 1, &ExtRateIe, - 1, &pAd->StaActive.ExtRateLen, - pAd->StaActive.ExtRateLen, &pAd->StaActive.ExtRate, - END_OF_ARGS); - FrameLen += tmp; - } - - // If adhoc secruity is set for WPA-None, append the cipher suite IE - if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) - { - ULONG tmp; - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - 1, &RSNIe, - 1, &pAd->StaCfg.RSNIE_Len, - pAd->StaCfg.RSNIE_Len, pAd->StaCfg.RSN_IE, - END_OF_ARGS); - FrameLen += tmp; - } -#ifdef DOT11_N_SUPPORT - if (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) - { - ULONG TmpLen; - UCHAR BROADCOM[4] = {0x0, 0x90, 0x4c, 0x33}; - HtLen = sizeof(pAd->CommonCfg.HtCapability); - AddHtLen = sizeof(pAd->CommonCfg.AddHTInfo); - NewExtLen = 1; - //New extension channel offset IE is included in Beacon, Probe Rsp or channel Switch Announcement Frame - if (pAd->bBroadComHT == TRUE) - { - MakeOutgoingFrame(pOutBuffer + FrameLen, &TmpLen, - 1, &WpaIe, - 4, &BROADCOM[0], - pAd->MlmeAux.HtCapabilityLen, &pAd->MlmeAux.HtCapability, - END_OF_ARGS); - } - else - { - MakeOutgoingFrame(pOutBuffer + FrameLen, &TmpLen, - 1, &HtCapIe, - 1, &HtLen, - sizeof(HT_CAPABILITY_IE), &pAd->CommonCfg.HtCapability, - 1, &AddHtInfoIe, - 1, &AddHtLen, - sizeof(ADD_HT_INFO_IE), &pAd->CommonCfg.AddHTInfo, - 1, &NewExtChanIe, - 1, &NewExtLen, - sizeof(NEW_EXT_CHAN_IE), &pAd->CommonCfg.NewExtChanOffset, - END_OF_ARGS); - } - FrameLen += TmpLen; - } -#endif // DOT11_N_SUPPORT // - MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); - } - } -} - -VOID BeaconTimeoutAtJoinAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - USHORT Status; - DBGPRINT(RT_DEBUG_TRACE, ("SYNC - BeaconTimeoutAtJoinAction\n")); - pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; - Status = MLME_REJ_TIMEOUT; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_JOIN_CONF, 2, &Status); -} - -/* - ========================================================================== - Description: - Scan timeout procedure. basically add channel index by 1 and rescan - ========================================================================== - */ -VOID ScanTimeoutAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - pAd->MlmeAux.Channel = NextChannel(pAd, pAd->MlmeAux.Channel); - - // Only one channel scanned for CISCO beacon request - if ((pAd->MlmeAux.ScanType == SCAN_CISCO_ACTIVE) || - (pAd->MlmeAux.ScanType == SCAN_CISCO_PASSIVE) || - (pAd->MlmeAux.ScanType == SCAN_CISCO_NOISE) || - (pAd->MlmeAux.ScanType == SCAN_CISCO_CHANNEL_LOAD)) - pAd->MlmeAux.Channel = 0; - - // this routine will stop if pAd->MlmeAux.Channel == 0 - ScanNextChannel(pAd); -} - -/* - ========================================================================== - Description: - ========================================================================== - */ -VOID InvalidStateWhenScan( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - USHORT Status; - DBGPRINT(RT_DEBUG_TRACE, ("AYNC - InvalidStateWhenScan(state=%ld). Reset SYNC machine\n", pAd->Mlme.SyncMachine.CurrState)); - pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; - Status = MLME_STATE_MACHINE_REJECT; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_SCAN_CONF, 2, &Status); -} - -/* - ========================================================================== - Description: - ========================================================================== - */ -VOID InvalidStateWhenJoin( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - USHORT Status; - DBGPRINT(RT_DEBUG_TRACE, ("InvalidStateWhenJoin(state=%ld). Reset SYNC machine\n", pAd->Mlme.SyncMachine.CurrState)); - pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; - Status = MLME_STATE_MACHINE_REJECT; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_JOIN_CONF, 2, &Status); -} - -/* - ========================================================================== - Description: - ========================================================================== - */ -VOID InvalidStateWhenStart( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - USHORT Status; - DBGPRINT(RT_DEBUG_TRACE, ("InvalidStateWhenStart(state=%ld). Reset SYNC machine\n", pAd->Mlme.SyncMachine.CurrState)); - pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; - Status = MLME_STATE_MACHINE_REJECT; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_START_CONF, 2, &Status); -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID EnqueuePsPoll( - IN PRTMP_ADAPTER pAd) -{ -#ifdef RALINK_ATE - if (ATE_ON(pAd)) - { - return; - } -#endif // RALINK_ATE // - - - if (pAd->StaCfg.WindowsPowerMode == Ndis802_11PowerModeLegacy_PSP) - pAd->PsPollFrame.FC.PwrMgmt = PWR_SAVE; - MiniportMMRequest(pAd, 0, (PUCHAR)&pAd->PsPollFrame, sizeof(PSPOLL_FRAME)); -} - - -/* - ========================================================================== - Description: - ========================================================================== - */ -VOID EnqueueProbeRequest( - IN PRTMP_ADAPTER pAd) -{ - NDIS_STATUS NState; - PUCHAR pOutBuffer; - ULONG FrameLen = 0; - HEADER_802_11 Hdr80211; - - DBGPRINT(RT_DEBUG_TRACE, ("force out a ProbeRequest ...\n")); - - NState = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory - if (NState == NDIS_STATUS_SUCCESS) - { - MgtMacHeaderInit(pAd, &Hdr80211, SUBTYPE_PROBE_REQ, 0, BROADCAST_ADDR, BROADCAST_ADDR); - - // this ProbeRequest explicitly specify SSID to reduce unwanted ProbeResponse - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(HEADER_802_11), &Hdr80211, - 1, &SsidIe, - 1, &pAd->CommonCfg.SsidLen, - pAd->CommonCfg.SsidLen, pAd->CommonCfg.Ssid, - 1, &SupRateIe, - 1, &pAd->StaActive.SupRateLen, - pAd->StaActive.SupRateLen, pAd->StaActive.SupRate, - END_OF_ARGS); - MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); - } - -} - -#ifdef DOT11_N_SUPPORT -#ifdef DOT11N_DRAFT3 -VOID BuildEffectedChannelList( - IN PRTMP_ADAPTER pAd) -{ - UCHAR EChannel[11]; - UCHAR i, j, k; - UCHAR UpperChannel = 0, LowerChannel = 0; - - RTMPZeroMemory(EChannel, 11); - i = 0; - // Find upper channel and lower channel. - if (pAd->CommonCfg.CentralChannel < pAd->CommonCfg.Channel) - { - UpperChannel = pAd->CommonCfg.Channel; - LowerChannel = pAd->CommonCfg.CentralChannel; - } - else if (pAd->CommonCfg.CentralChannel > pAd->CommonCfg.Channel) - { - UpperChannel = pAd->CommonCfg.CentralChannel; - LowerChannel = pAd->CommonCfg.Channel; - } - else - { - return; - } - - // Record channels that is below lower channel.. - if (LowerChannel > 1) - { - EChannel[0] = LowerChannel - 1; - i = 1; - if (LowerChannel > 2) - { - EChannel[1] = LowerChannel - 2; - i = 2; - if (LowerChannel > 3) - { - EChannel[2] = LowerChannel - 3; - i = 3; - } - } - } - // Record channels that is between lower channel and upper channel. - for (k = LowerChannel;k < UpperChannel;k++) - { - EChannel[i] = k; - i++; - } - // Record channels that is above upper channel.. - if (LowerChannel < 11) - { - EChannel[i] = UpperChannel + 1; - i++; - if (LowerChannel < 10) - { - EChannel[i] = LowerChannel + 2; - i++; - if (LowerChannel < 9) - { - EChannel[i] = LowerChannel + 3; - i++; - } - } - } - // - for (j = 0;j < i;j++) - { - for (k = 0;k < pAd->ChannelListNum;k++) - { - if (pAd->ChannelList[k].Channel == EChannel[j]) - { - pAd->ChannelList[k].bEffectedChannel = TRUE; - DBGPRINT(RT_DEBUG_TRACE,(" EffectedChannel( =%d)\n", EChannel[j])); - break; - } - } - } -} -#endif // DOT11N_DRAFT3 // -#endif // DOT11_N_SUPPORT // - -BOOLEAN ScanRunning( - IN PRTMP_ADAPTER pAd) -{ - return (pAd->Mlme.SyncMachine.CurrState == SCAN_LISTEN) ? TRUE : FALSE; -} - +#include "../../rt2860/sta/sync.c" diff --git a/drivers/staging/rt2870/sta/wpa.c b/drivers/staging/rt2870/sta/wpa.c index 8626dcde6054..57a2eb2d0896 100644 --- a/drivers/staging/rt2870/sta/wpa.c +++ b/drivers/staging/rt2870/sta/wpa.c @@ -1,2107 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - wpa.c - - Abstract: - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Jan Lee 03-07-22 Initial - Paul Lin 03-11-28 Modify for supplicant -*/ -#include "../rt_config.h" - -#define WPARSNIE 0xdd -#define WPA2RSNIE 0x30 - -//extern UCHAR BIT8[]; -UCHAR CipherWpaPskTkip[] = { - 0xDD, 0x16, // RSN IE - 0x00, 0x50, 0xf2, 0x01, // oui - 0x01, 0x00, // Version - 0x00, 0x50, 0xf2, 0x02, // Multicast - 0x01, 0x00, // Number of unicast - 0x00, 0x50, 0xf2, 0x02, // unicast - 0x01, 0x00, // number of authentication method - 0x00, 0x50, 0xf2, 0x02 // authentication - }; -UCHAR CipherWpaPskTkipLen = (sizeof(CipherWpaPskTkip) / sizeof(UCHAR)); - -UCHAR CipherWpaPskAes[] = { - 0xDD, 0x16, // RSN IE - 0x00, 0x50, 0xf2, 0x01, // oui - 0x01, 0x00, // Version - 0x00, 0x50, 0xf2, 0x04, // Multicast - 0x01, 0x00, // Number of unicast - 0x00, 0x50, 0xf2, 0x04, // unicast - 0x01, 0x00, // number of authentication method - 0x00, 0x50, 0xf2, 0x02 // authentication - }; -UCHAR CipherWpaPskAesLen = (sizeof(CipherWpaPskAes) / sizeof(UCHAR)); - -UCHAR CipherSuiteCiscoCCKM[] = { - 0xDD, 0x16, // RSN IE - 0x00, 0x50, 0xf2, 0x01, // oui - 0x01, 0x00, // Version - 0x00, 0x40, 0x96, 0x01, // Multicast - 0x01, 0x00, // Number of uicast - 0x00, 0x40, 0x96, 0x01, // unicast - 0x01, 0x00, // number of authentication method - 0x00, 0x40, 0x96, 0x00 // Authentication - }; -UCHAR CipherSuiteCiscoCCKMLen = (sizeof(CipherSuiteCiscoCCKM) / sizeof(UCHAR)); - -UCHAR CipherSuiteCiscoCCKM24[] = { - 0xDD, 0x18, // RSN IE - 0x00, 0x50, 0xf2, 0x01, // oui - 0x01, 0x00, // Version - 0x00, 0x40, 0x96, 0x01, // Multicast - 0x01, 0x00, // Number of uicast - 0x00, 0x40, 0x96, 0x01, // unicast - 0x01, 0x00, // number of authentication method - 0x00, 0x40, 0x96, 0x00, - 0x28, 0x00// Authentication - }; - -UCHAR CipherSuiteCiscoCCKM24Len = (sizeof(CipherSuiteCiscoCCKM24) / sizeof(UCHAR)); - -UCHAR CipherSuiteCCXTkip[] = { - 0xDD, 0x16, // RSN IE - 0x00, 0x50, 0xf2, 0x01, // oui - 0x01, 0x00, // Version - 0x00, 0x50, 0xf2, 0x02, // Multicast - 0x01, 0x00, // Number of unicast - 0x00, 0x50, 0xf2, 0x02, // unicast - 0x01, 0x00, // number of authentication method - 0x00, 0x50, 0xf2, 0x01 // authentication - }; -UCHAR CipherSuiteCCXTkipLen = (sizeof(CipherSuiteCCXTkip) / sizeof(UCHAR)); - -UCHAR CCX_LLC_HDR[] = {0xAA, 0xAA, 0x03, 0x00, 0x40, 0x96, 0x00, 0x02}; -UCHAR LLC_NORMAL[] = {0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00}; - -UCHAR EAPOL_FRAME[] = {0x88, 0x8E}; - -BOOLEAN CheckRSNIE( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pData, - IN UCHAR DataLen, - OUT UCHAR *Offset); - -void inc_byte_array(UCHAR *counter, int len); - -/* - ======================================================================== - - Routine Description: - Classify WPA EAP message type - - Arguments: - EAPType Value of EAP message type - MsgType Internal Message definition for MLME state machine - - Return Value: - TRUE Found appropriate message type - FALSE No appropriate message type - - IRQL = DISPATCH_LEVEL - - Note: - All these constants are defined in wpa.h - For supplicant, there is only EAPOL Key message avaliable - - ======================================================================== -*/ -BOOLEAN WpaMsgTypeSubst( - IN UCHAR EAPType, - OUT INT *MsgType) -{ - switch (EAPType) - { - case EAPPacket: - *MsgType = MT2_EAPPacket; - break; - case EAPOLStart: - *MsgType = MT2_EAPOLStart; - break; - case EAPOLLogoff: - *MsgType = MT2_EAPOLLogoff; - break; - case EAPOLKey: - *MsgType = MT2_EAPOLKey; - break; - case EAPOLASFAlert: - *MsgType = MT2_EAPOLASFAlert; - break; - default: - return FALSE; - } - return TRUE; -} - -/* - ========================================================================== - Description: - association state machine init, including state transition and timer init - Parameters: - S - pointer to the association state machine - ========================================================================== - */ -VOID WpaPskStateMachineInit( - IN PRTMP_ADAPTER pAd, - IN STATE_MACHINE *S, - OUT STATE_MACHINE_FUNC Trans[]) -{ - StateMachineInit(S, Trans, MAX_WPA_PSK_STATE, MAX_WPA_PSK_MSG, (STATE_MACHINE_FUNC)Drop, WPA_PSK_IDLE, WPA_MACHINE_BASE); - StateMachineSetAction(S, WPA_PSK_IDLE, MT2_EAPOLKey, (STATE_MACHINE_FUNC)WpaEAPOLKeyAction); -} - -/* - ========================================================================== - Description: - This is state machine function. - When receiving EAPOL packets which is for 802.1x key management. - Use both in WPA, and WPAPSK case. - In this function, further dispatch to different functions according to the received packet. 3 categories are : - 1. normal 4-way pairwisekey and 2-way groupkey handshake - 2. MIC error (Countermeasures attack) report packet from STA. - 3. Request for pairwise/group key update from STA - Return: - ========================================================================== -*/ -VOID WpaEAPOLKeyAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) - -{ - INT MsgType = EAPOL_MSG_INVALID; - PKEY_DESCRIPTER pKeyDesc; - PHEADER_802_11 pHeader; //red - UCHAR ZeroReplay[LEN_KEY_DESC_REPLAY]; - UCHAR EapolVr; - KEY_INFO peerKeyInfo; - - DBGPRINT(RT_DEBUG_TRACE, ("-----> WpaEAPOLKeyAction\n")); - - // Get 802.11 header first - pHeader = (PHEADER_802_11) Elem->Msg; - - // Get EAPoL-Key Descriptor - pKeyDesc = (PKEY_DESCRIPTER) &Elem->Msg[(LENGTH_802_11 + LENGTH_802_1_H + LENGTH_EAPOL_H)]; - - NdisZeroMemory((PUCHAR)&peerKeyInfo, sizeof(peerKeyInfo)); - NdisMoveMemory((PUCHAR)&peerKeyInfo, (PUCHAR)&pKeyDesc->KeyInfo, sizeof(KEY_INFO)); - - *((USHORT *)&peerKeyInfo) = cpu2le16(*((USHORT *)&peerKeyInfo)); - - - // 1. Check EAPOL frame version and type - EapolVr = (UCHAR) Elem->Msg[LENGTH_802_11+LENGTH_802_1_H]; - - if (((EapolVr != EAPOL_VER) && (EapolVr != EAPOL_VER2)) || ((pKeyDesc->Type != WPA1_KEY_DESC) && (pKeyDesc->Type != WPA2_KEY_DESC))) - { - DBGPRINT(RT_DEBUG_ERROR, ("Key descripter does not match with WPA rule\n")); - return; - } - - // First validate replay counter, only accept message with larger replay counter - // Let equal pass, some AP start with all zero replay counter - NdisZeroMemory(ZeroReplay, LEN_KEY_DESC_REPLAY); - - if((RTMPCompareMemory(pKeyDesc->ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY) != 1) && - (RTMPCompareMemory(pKeyDesc->ReplayCounter, ZeroReplay, LEN_KEY_DESC_REPLAY) != 0)) - { - DBGPRINT(RT_DEBUG_ERROR, (" ReplayCounter not match \n")); - return; - } - - // Process WPA2PSK frame - if(pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) - { - if((peerKeyInfo.KeyType == PAIRWISEKEY) && - (peerKeyInfo.EKD_DL == 0) && - (peerKeyInfo.KeyAck == 1) && - (peerKeyInfo.KeyMic == 0) && - (peerKeyInfo.Secure == 0) && - (peerKeyInfo.Error == 0) && - (peerKeyInfo.Request == 0)) - { - MsgType = EAPOL_PAIR_MSG_1; - DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL Key Pairwise Message 1\n")); - } else if((peerKeyInfo.KeyType == PAIRWISEKEY) && - (peerKeyInfo.EKD_DL == 1) && - (peerKeyInfo.KeyAck == 1) && - (peerKeyInfo.KeyMic == 1) && - (peerKeyInfo.Secure == 1) && - (peerKeyInfo.Error == 0) && - (peerKeyInfo.Request == 0)) - { - MsgType = EAPOL_PAIR_MSG_3; - DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL Key Pairwise Message 3\n")); - } else if((peerKeyInfo.KeyType == GROUPKEY) && - (peerKeyInfo.EKD_DL == 1) && - (peerKeyInfo.KeyAck == 1) && - (peerKeyInfo.KeyMic == 1) && - (peerKeyInfo.Secure == 1) && - (peerKeyInfo.Error == 0) && - (peerKeyInfo.Request == 0)) - { - MsgType = EAPOL_GROUP_MSG_1; - DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL Key Group Message 1\n")); - } - - // We will assume link is up (assoc suceess and port not secured). - // All state has to be able to process message from previous state - switch(pAd->StaCfg.WpaState) - { - case SS_START: - if(MsgType == EAPOL_PAIR_MSG_1) - { - Wpa2PairMsg1Action(pAd, Elem); - pAd->StaCfg.WpaState = SS_WAIT_MSG_3; - } - break; - - case SS_WAIT_MSG_3: - if(MsgType == EAPOL_PAIR_MSG_1) - { - Wpa2PairMsg1Action(pAd, Elem); - pAd->StaCfg.WpaState = SS_WAIT_MSG_3; - } - else if(MsgType == EAPOL_PAIR_MSG_3) - { - Wpa2PairMsg3Action(pAd, Elem); - pAd->StaCfg.WpaState = SS_WAIT_GROUP; - } - break; - - case SS_WAIT_GROUP: // When doing group key exchange - case SS_FINISH: // This happened when update group key - if(MsgType == EAPOL_PAIR_MSG_1) - { - // Reset port secured variable - pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; - Wpa2PairMsg1Action(pAd, Elem); - pAd->StaCfg.WpaState = SS_WAIT_MSG_3; - } - else if(MsgType == EAPOL_PAIR_MSG_3) - { - // Reset port secured variable - pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; - Wpa2PairMsg3Action(pAd, Elem); - pAd->StaCfg.WpaState = SS_WAIT_GROUP; - } - else if(MsgType == EAPOL_GROUP_MSG_1) - { - WpaGroupMsg1Action(pAd, Elem); - pAd->StaCfg.WpaState = SS_FINISH; - } - break; - - default: - break; - } - } - // Process WPAPSK Frame - // Classify message Type, either pairwise message 1, 3, or group message 1 for supplicant - else if(pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) - { - if((peerKeyInfo.KeyType == PAIRWISEKEY) && - (peerKeyInfo.KeyIndex == 0) && - (peerKeyInfo.KeyAck == 1) && - (peerKeyInfo.KeyMic == 0) && - (peerKeyInfo.Secure == 0) && - (peerKeyInfo.Error == 0) && - (peerKeyInfo.Request == 0)) - { - MsgType = EAPOL_PAIR_MSG_1; - DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL Key Pairwise Message 1\n")); - } - else if((peerKeyInfo.KeyType == PAIRWISEKEY) && - (peerKeyInfo.KeyIndex == 0) && - (peerKeyInfo.KeyAck == 1) && - (peerKeyInfo.KeyMic == 1) && - (peerKeyInfo.Secure == 0) && - (peerKeyInfo.Error == 0) && - (peerKeyInfo.Request == 0)) - { - MsgType = EAPOL_PAIR_MSG_3; - DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL Key Pairwise Message 3\n")); - } - else if((peerKeyInfo.KeyType == GROUPKEY) && - (peerKeyInfo.KeyIndex != 0) && - (peerKeyInfo.KeyAck == 1) && - (peerKeyInfo.KeyMic == 1) && - (peerKeyInfo.Secure == 1) && - (peerKeyInfo.Error == 0) && - (peerKeyInfo.Request == 0)) - { - MsgType = EAPOL_GROUP_MSG_1; - DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL Key Group Message 1\n")); - } - - // We will assume link is up (assoc suceess and port not secured). - // All state has to be able to process message from previous state - switch(pAd->StaCfg.WpaState) - { - case SS_START: - if(MsgType == EAPOL_PAIR_MSG_1) - { - WpaPairMsg1Action(pAd, Elem); - pAd->StaCfg.WpaState = SS_WAIT_MSG_3; - } - break; - - case SS_WAIT_MSG_3: - if(MsgType == EAPOL_PAIR_MSG_1) - { - WpaPairMsg1Action(pAd, Elem); - pAd->StaCfg.WpaState = SS_WAIT_MSG_3; - } - else if(MsgType == EAPOL_PAIR_MSG_3) - { - WpaPairMsg3Action(pAd, Elem); - pAd->StaCfg.WpaState = SS_WAIT_GROUP; - } - break; - - case SS_WAIT_GROUP: // When doing group key exchange - case SS_FINISH: // This happened when update group key - if(MsgType == EAPOL_PAIR_MSG_1) - { - WpaPairMsg1Action(pAd, Elem); - pAd->StaCfg.WpaState = SS_WAIT_MSG_3; - // Reset port secured variable - pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; - } - else if(MsgType == EAPOL_PAIR_MSG_3) - { - WpaPairMsg3Action(pAd, Elem); - pAd->StaCfg.WpaState = SS_WAIT_GROUP; - // Reset port secured variable - pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; - } - else if(MsgType == EAPOL_GROUP_MSG_1) - { - WpaGroupMsg1Action(pAd, Elem); - pAd->StaCfg.WpaState = SS_FINISH; - } - break; - - default: - break; - } - } - - DBGPRINT(RT_DEBUG_TRACE, ("<----- WpaEAPOLKeyAction\n")); -} - -/* - ======================================================================== - - Routine Description: - Process Pairwise key 4-way handshaking - - Arguments: - pAd Pointer to our adapter - Elem Message body - - Return Value: - None - - Note: - - ======================================================================== -*/ -VOID WpaPairMsg1Action( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - PHEADER_802_11 pHeader; - UCHAR *mpool, *PTK, *digest; - PUCHAR pOutBuffer = NULL; - UCHAR Header802_3[14]; - ULONG FrameLen = 0; - PEAPOL_PACKET pMsg1; - EAPOL_PACKET Packet; - UCHAR Mic[16]; - - DBGPRINT(RT_DEBUG_TRACE, ("WpaPairMsg1Action ----->\n")); - - // allocate memory pool - os_alloc_mem(pAd, (PUCHAR *)&mpool, 256); - - if (mpool == NULL) - return; - - // PTK Len = 80. - PTK = (UCHAR *) ROUND_UP(mpool, 4); - // digest Len = 80. - digest = (UCHAR *) ROUND_UP(PTK + 80, 4); - - pHeader = (PHEADER_802_11) Elem->Msg; - - // Process message 1 from authenticator - pMsg1 = (PEAPOL_PACKET) &Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H]; - - // 1. Save Replay counter, it will use to verify message 3 and construct message 2 - NdisMoveMemory(pAd->StaCfg.ReplayCounter, pMsg1->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); - - // 2. Save ANonce - NdisMoveMemory(pAd->StaCfg.ANonce, pMsg1->KeyDesc.KeyNonce, LEN_KEY_DESC_NONCE); - - // Generate random SNonce - GenRandom(pAd, pAd->CurrentAddress, pAd->StaCfg.SNonce); - - // Calc PTK(ANonce, SNonce) - WpaCountPTK(pAd, - pAd->StaCfg.PMK, - pAd->StaCfg.ANonce, - pAd->CommonCfg.Bssid, - pAd->StaCfg.SNonce, - pAd->CurrentAddress, - PTK, - LEN_PTK); - - // Save key to PTK entry - NdisMoveMemory(pAd->StaCfg.PTK, PTK, LEN_PTK); - - // init 802.3 header and Fill Packet - MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL); - - // Zero Message 2 body - NdisZeroMemory(&Packet, sizeof(Packet)); - Packet.ProVer = EAPOL_VER; - Packet.ProType = EAPOLKey; - // - // Message 2 as EAPOL-Key(0,1,0,0,0,P,0,SNonce,MIC,RSN IE) - // - Packet.KeyDesc.Type = WPA1_KEY_DESC; - // 1. Key descriptor version and appropriate RSN IE - if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) - { - Packet.KeyDesc.KeyInfo.KeyDescVer = 2; - } - else // TKIP - { - Packet.KeyDesc.KeyInfo.KeyDescVer = 1; - } - - // fill in Data Material and its length - Packet.KeyDesc.KeyData[0] = IE_WPA; - Packet.KeyDesc.KeyData[1] = pAd->StaCfg.RSNIE_Len; - Packet.KeyDesc.KeyDataLen[1] = pAd->StaCfg.RSNIE_Len + 2; - NdisMoveMemory(&Packet.KeyDesc.KeyData[2], pAd->StaCfg.RSN_IE, pAd->StaCfg.RSNIE_Len); - - // Update packet length after decide Key data payload - Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE + Packet.KeyDesc.KeyDataLen[1]; - - // Update Key length - Packet.KeyDesc.KeyLength[0] = pMsg1->KeyDesc.KeyLength[0]; - Packet.KeyDesc.KeyLength[1] = pMsg1->KeyDesc.KeyLength[1]; - // 2. Key Type PeerKey - Packet.KeyDesc.KeyInfo.KeyType = PAIRWISEKEY; - - // 3. KeyMic field presented - Packet.KeyDesc.KeyInfo.KeyMic = 1; - - //Convert to little-endian format. - *((USHORT *)&Packet.KeyDesc.KeyInfo) = cpu2le16(*((USHORT *)&Packet.KeyDesc.KeyInfo)); - - - // 4. Fill SNonce - NdisMoveMemory(Packet.KeyDesc.KeyNonce, pAd->StaCfg.SNonce, LEN_KEY_DESC_NONCE); - - // 5. Key Replay Count - NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY); - - // Send EAPOL(0, 1, 0, 0, 0, P, 0, SNonce, MIC, RSN_IE) - // Out buffer for transmitting message 2 - MlmeAllocateMemory(pAd, (PUCHAR *)&pOutBuffer); // allocate memory - if(pOutBuffer == NULL) - { - os_free_mem(pAd, mpool); - return; - } - // Prepare EAPOL frame for MIC calculation - // Be careful, only EAPOL frame is counted for MIC calculation - MakeOutgoingFrame(pOutBuffer, &FrameLen, - Packet.Body_Len[1] + 4, &Packet, - END_OF_ARGS); - - // 6. Prepare and Fill MIC value - NdisZeroMemory(Mic, sizeof(Mic)); - if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) - { // AES - - HMAC_SHA1(pOutBuffer, FrameLen, PTK, LEN_EAP_MICK, digest); - NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); - } - else - { // TKIP - hmac_md5(PTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic); - } - NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC); - - //hex_dump("MIC", Mic, LEN_KEY_DESC_MIC); - - MakeOutgoingFrame(pOutBuffer, &FrameLen, - LENGTH_802_3, &Header802_3, - Packet.Body_Len[1] + 4, &Packet, - END_OF_ARGS); - - - // 5. Copy frame to Tx ring and send Msg 2 to authenticator - RTMPToWirelessSta(pAd, Header802_3, LENGTH_802_3, (PUCHAR)&Packet, Packet.Body_Len[1] + 4, TRUE); - - MlmeFreeMemory(pAd, (PUCHAR)pOutBuffer); - os_free_mem(pAd, (PUCHAR)mpool); - - DBGPRINT(RT_DEBUG_TRACE, ("WpaPairMsg1Action <-----\n")); -} - -VOID Wpa2PairMsg1Action( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - PHEADER_802_11 pHeader; - UCHAR *mpool, *PTK, *digest; - PUCHAR pOutBuffer = NULL; - UCHAR Header802_3[14]; - ULONG FrameLen = 0; - PEAPOL_PACKET pMsg1; - EAPOL_PACKET Packet; - UCHAR Mic[16]; - - DBGPRINT(RT_DEBUG_TRACE, ("Wpa2PairMsg1Action ----->\n")); - - // allocate memory pool - os_alloc_mem(pAd, (PUCHAR *)&mpool, 256); - - if (mpool == NULL) - return; - - // PTK Len = 80. - PTK = (UCHAR *) ROUND_UP(mpool, 4); - // digest Len = 80. - digest = (UCHAR *) ROUND_UP(PTK + 80, 4); - - pHeader = (PHEADER_802_11) Elem->Msg; - - // Process message 1 from authenticator - pMsg1 = (PEAPOL_PACKET) &Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H]; - - // 1. Save Replay counter, it will use to verify message 3 and construct message 2 - NdisMoveMemory(pAd->StaCfg.ReplayCounter, pMsg1->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); - - // 2. Save ANonce - NdisMoveMemory(pAd->StaCfg.ANonce, pMsg1->KeyDesc.KeyNonce, LEN_KEY_DESC_NONCE); - - // Generate random SNonce - GenRandom(pAd, pAd->CurrentAddress, pAd->StaCfg.SNonce); - - if(pMsg1->KeyDesc.KeyDataLen[1] > 0 ) - { - // cached PMKID - } - - // Calc PTK(ANonce, SNonce) - WpaCountPTK(pAd, - pAd->StaCfg.PMK, - pAd->StaCfg.ANonce, - pAd->CommonCfg.Bssid, - pAd->StaCfg.SNonce, - pAd->CurrentAddress, - PTK, - LEN_PTK); - - // Save key to PTK entry - NdisMoveMemory(pAd->StaCfg.PTK, PTK, LEN_PTK); - - // init 802.3 header and Fill Packet - MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL); - - // Zero message 2 body - NdisZeroMemory(&Packet, sizeof(Packet)); - Packet.ProVer = EAPOL_VER; - Packet.ProType = EAPOLKey; - // - // Message 2 as EAPOL-Key(0,1,0,0,0,P,0,SNonce,MIC,RSN IE) - // - Packet.KeyDesc.Type = WPA2_KEY_DESC; - - // 1. Key descriptor version and appropriate RSN IE - if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) - { - Packet.KeyDesc.KeyInfo.KeyDescVer = 2; - } - else // TKIP - { - Packet.KeyDesc.KeyInfo.KeyDescVer = 1; - } - - // fill in Data Material and its length - Packet.KeyDesc.KeyData[0] = IE_WPA2; - Packet.KeyDesc.KeyData[1] = pAd->StaCfg.RSNIE_Len; - Packet.KeyDesc.KeyDataLen[1] = pAd->StaCfg.RSNIE_Len + 2; - NdisMoveMemory(&Packet.KeyDesc.KeyData[2], pAd->StaCfg.RSN_IE, pAd->StaCfg.RSNIE_Len); - - // Update packet length after decide Key data payload - Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE + Packet.KeyDesc.KeyDataLen[1]; - - // 2. Key Type PeerKey - Packet.KeyDesc.KeyInfo.KeyType = PAIRWISEKEY; - - // 3. KeyMic field presented - Packet.KeyDesc.KeyInfo.KeyMic = 1; - - // Update Key Length - Packet.KeyDesc.KeyLength[0] = 0; - Packet.KeyDesc.KeyLength[1] = pMsg1->KeyDesc.KeyLength[1]; - - // 4. Fill SNonce - NdisMoveMemory(Packet.KeyDesc.KeyNonce, pAd->StaCfg.SNonce, LEN_KEY_DESC_NONCE); - - // 5. Key Replay Count - NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY); - - // Convert to little-endian format. - *((USHORT *)&Packet.KeyDesc.KeyInfo) = cpu2le16(*((USHORT *)&Packet.KeyDesc.KeyInfo)); - - // Send EAPOL-Key(0,1,0,0,0,P,0,SNonce,MIC,RSN IE) - // Out buffer for transmitting message 2 - MlmeAllocateMemory(pAd, (PUCHAR *)&pOutBuffer); // allocate memory - if(pOutBuffer == NULL) - { - os_free_mem(pAd, mpool); - return; - } - - // Prepare EAPOL frame for MIC calculation - // Be careful, only EAPOL frame is counted for MIC calculation - MakeOutgoingFrame(pOutBuffer, &FrameLen, - Packet.Body_Len[1] + 4, &Packet, - END_OF_ARGS); - - // 6. Prepare and Fill MIC value - NdisZeroMemory(Mic, sizeof(Mic)); - if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) - { - // AES - HMAC_SHA1(pOutBuffer, FrameLen, PTK, LEN_EAP_MICK, digest); - NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); - } - else - { - hmac_md5(PTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic); - } - NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC); - - - // Make Transmitting frame - MakeOutgoingFrame(pOutBuffer, &FrameLen, - LENGTH_802_3, &Header802_3, - Packet.Body_Len[1] + 4, &Packet, - END_OF_ARGS); - - - // 5. Copy frame to Tx ring - RTMPToWirelessSta(pAd, Header802_3, LENGTH_802_3, (PUCHAR)&Packet, Packet.Body_Len[1] + 4, TRUE); - - MlmeFreeMemory(pAd, pOutBuffer); - os_free_mem(pAd, mpool); - - DBGPRINT(RT_DEBUG_TRACE, ("Wpa2PairMsg1Action <-----\n")); - -} - -/* - ======================================================================== - - Routine Description: - Process Pairwise key 4-way handshaking - - Arguments: - pAd Pointer to our adapter - Elem Message body - - Return Value: - None - - Note: - - ======================================================================== -*/ -VOID WpaPairMsg3Action( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) - -{ - PHEADER_802_11 pHeader; - PUCHAR pOutBuffer = NULL; - UCHAR Header802_3[14]; - ULONG FrameLen = 0; - EAPOL_PACKET Packet; - PEAPOL_PACKET pMsg3; - UCHAR Mic[16], OldMic[16]; - MAC_TABLE_ENTRY *pEntry = NULL; - UCHAR skip_offset; - KEY_INFO peerKeyInfo; - - DBGPRINT(RT_DEBUG_TRACE, ("WpaPairMsg3Action ----->\n")); - - // Record 802.11 header & the received EAPOL packet Msg3 - pHeader = (PHEADER_802_11) Elem->Msg; - pMsg3 = (PEAPOL_PACKET) &Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H]; - - NdisZeroMemory((PUCHAR)&peerKeyInfo, sizeof(peerKeyInfo)); - NdisMoveMemory((PUCHAR)&peerKeyInfo, (PUCHAR)&pMsg3->KeyDesc.KeyInfo, sizeof(KEY_INFO)); - - *((USHORT*)&peerKeyInfo) = cpu2le16(*((USHORT*)&peerKeyInfo)); - - - // 1. Verify cipher type match - if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled && (peerKeyInfo.KeyDescVer != 2)) - { - return; - } - else if(pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled && (peerKeyInfo.KeyDescVer != 1)) - { - return; - } - - // Verify RSN IE - //if (!RTMPEqualMemory(pMsg3->KeyDesc.KeyData, pAd->MacTab.Content[BSSID_WCID].RSN_IE, pAd->MacTab.Content[BSSID_WCID].RSNIE_Len)) - if (!CheckRSNIE(pAd, pMsg3->KeyDesc.KeyData, pMsg3->KeyDesc.KeyDataLen[1], &skip_offset)) - { - DBGPRINT(RT_DEBUG_ERROR, ("RSN_IE Different in Msg 3 of WPA1 4-way handshake!! \n")); - hex_dump("The original RSN_IE", pAd->MacTab.Content[BSSID_WCID].RSN_IE, pAd->MacTab.Content[BSSID_WCID].RSNIE_Len); - hex_dump("The received RSN_IE", pMsg3->KeyDesc.KeyData, pMsg3->KeyDesc.KeyDataLen[1]); - return; - } - else - DBGPRINT(RT_DEBUG_TRACE, ("RSN_IE VALID in Msg 3 of WPA1 4-way handshake!! \n")); - - - // 2. Check MIC value - // Save the MIC and replace with zero - NdisMoveMemory(OldMic, pMsg3->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); - NdisZeroMemory(pMsg3->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); - if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) - { - // AES - UCHAR digest[80]; - - HMAC_SHA1((PUCHAR) pMsg3, pMsg3->Body_Len[1] + 4, pAd->StaCfg.PTK, LEN_EAP_MICK, digest); - NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); - } - else // TKIP - { - hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, (PUCHAR) pMsg3, pMsg3->Body_Len[1] + 4, Mic); - } - - if(!NdisEqualMemory(OldMic, Mic, LEN_KEY_DESC_MIC)) - { - DBGPRINT(RT_DEBUG_ERROR, (" MIC Different in msg 3 of 4-way handshake!!!!!!!!!! \n")); - return; - } - else - DBGPRINT(RT_DEBUG_TRACE, (" MIC VALID in msg 3 of 4-way handshake!!!!!!!!!! \n")); - - // 3. Check Replay Counter, it has to be larger than last one. No need to be exact one larger - if(RTMPCompareMemory(pMsg3->KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY) != 1) - return; - - // Update new replay counter - NdisMoveMemory(pAd->StaCfg.ReplayCounter, pMsg3->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); - - // 4. Double check ANonce - if(!NdisEqualMemory(pAd->StaCfg.ANonce, pMsg3->KeyDesc.KeyNonce, LEN_KEY_DESC_NONCE)) - return; - - // init 802.3 header and Fill Packet - MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL); - - // Zero Message 4 body - NdisZeroMemory(&Packet, sizeof(Packet)); - Packet.ProVer = EAPOL_VER; - Packet.ProType = EAPOLKey; - Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE; // No data field - - // - // Message 4 as EAPOL-Key(0,1,0,0,0,P,0,0,MIC,0) - // - Packet.KeyDesc.Type = WPA1_KEY_DESC; - - // Key descriptor version and appropriate RSN IE - Packet.KeyDesc.KeyInfo.KeyDescVer = peerKeyInfo.KeyDescVer; - - // Update Key Length - Packet.KeyDesc.KeyLength[0] = pMsg3->KeyDesc.KeyLength[0]; - Packet.KeyDesc.KeyLength[1] = pMsg3->KeyDesc.KeyLength[1]; - - // Key Type PeerKey - Packet.KeyDesc.KeyInfo.KeyType = PAIRWISEKEY; - - // KeyMic field presented - Packet.KeyDesc.KeyInfo.KeyMic = 1; - - // In Msg3, KeyInfo.secure =0 if Group Key HS to come. 1 if no group key HS - // Station sends Msg4 KeyInfo.secure should be the same as that in Msg.3 - Packet.KeyDesc.KeyInfo.Secure= peerKeyInfo.Secure; - - // Convert to little-endian format. - *((USHORT *)&Packet.KeyDesc.KeyInfo) = cpu2le16(*((USHORT *)&Packet.KeyDesc.KeyInfo)); - - // Key Replay count - NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pMsg3->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); - - // Out buffer for transmitting message 4 - MlmeAllocateMemory(pAd, (PUCHAR *)&pOutBuffer); // allocate memory - if(pOutBuffer == NULL) - return; - - // Prepare EAPOL frame for MIC calculation - // Be careful, only EAPOL frame is counted for MIC calculation - MakeOutgoingFrame(pOutBuffer, &FrameLen, - Packet.Body_Len[1] + 4, &Packet, - END_OF_ARGS); - - // Prepare and Fill MIC value - NdisZeroMemory(Mic, sizeof(Mic)); - if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) - { - // AES - UCHAR digest[80]; - - HMAC_SHA1(pOutBuffer, FrameLen, pAd->StaCfg.PTK, LEN_EAP_MICK, digest); - NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); - } - else - { - hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic); - } - NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC); - - // Update PTK - // Prepare pair-wise key information into shared key table - NdisZeroMemory(&pAd->SharedKey[BSS0][0], sizeof(CIPHER_KEY)); - pAd->SharedKey[BSS0][0].KeyLen = LEN_TKIP_EK; - NdisMoveMemory(pAd->SharedKey[BSS0][0].Key, &pAd->StaCfg.PTK[32], LEN_TKIP_EK); - NdisMoveMemory(pAd->SharedKey[BSS0][0].RxMic, &pAd->StaCfg.PTK[48], LEN_TKIP_RXMICK); - NdisMoveMemory(pAd->SharedKey[BSS0][0].TxMic, &pAd->StaCfg.PTK[48+LEN_TKIP_RXMICK], LEN_TKIP_TXMICK); - - // Decide its ChiperAlg - if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled) - pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_TKIP; - else if (pAd->StaCfg.PairCipher == Ndis802_11Encryption3Enabled) - pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_AES; - else - pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_NONE; - - // Update these related information to MAC_TABLE_ENTRY - pEntry = &pAd->MacTab.Content[BSSID_WCID]; - NdisMoveMemory(pEntry->PairwiseKey.Key, &pAd->StaCfg.PTK[32], LEN_TKIP_EK); - NdisMoveMemory(pEntry->PairwiseKey.RxMic, &pAd->StaCfg.PTK[48], LEN_TKIP_RXMICK); - NdisMoveMemory(pEntry->PairwiseKey.TxMic, &pAd->StaCfg.PTK[48+LEN_TKIP_RXMICK], LEN_TKIP_TXMICK); - pEntry->PairwiseKey.CipherAlg = pAd->SharedKey[BSS0][0].CipherAlg; - - // Update pairwise key information to ASIC Shared Key Table - AsicAddSharedKeyEntry(pAd, - BSS0, - 0, - pAd->SharedKey[BSS0][0].CipherAlg, - pAd->SharedKey[BSS0][0].Key, - pAd->SharedKey[BSS0][0].TxMic, - pAd->SharedKey[BSS0][0].RxMic); - - // Update ASIC WCID attribute table and IVEIV table - RTMPAddWcidAttributeEntry(pAd, - BSS0, - 0, - pAd->SharedKey[BSS0][0].CipherAlg, - pEntry); - - // Make transmitting frame - MakeOutgoingFrame(pOutBuffer, &FrameLen, - LENGTH_802_3, &Header802_3, - Packet.Body_Len[1] + 4, &Packet, - END_OF_ARGS); - - - // Copy frame to Tx ring and Send Message 4 to authenticator - RTMPToWirelessSta(pAd, Header802_3, LENGTH_802_3, (PUCHAR)&Packet, Packet.Body_Len[1] + 4, TRUE); - - MlmeFreeMemory(pAd, (PUCHAR)pOutBuffer); - - DBGPRINT(RT_DEBUG_TRACE, ("WpaPairMsg3Action <-----\n")); -} - -VOID Wpa2PairMsg3Action( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) - -{ - PHEADER_802_11 pHeader; - PUCHAR pOutBuffer = NULL; - UCHAR Header802_3[14]; - ULONG FrameLen = 0; - EAPOL_PACKET Packet; - PEAPOL_PACKET pMsg3; - UCHAR Mic[16], OldMic[16]; - UCHAR *mpool, *KEYDATA, *digest; - UCHAR Key[32]; - MAC_TABLE_ENTRY *pEntry = NULL; - KEY_INFO peerKeyInfo; - - // allocate memory - os_alloc_mem(pAd, (PUCHAR *)&mpool, 1024); - - if(mpool == NULL) - return; - - // KEYDATA Len = 512. - KEYDATA = (UCHAR *) ROUND_UP(mpool, 4); - // digest Len = 80. - digest = (UCHAR *) ROUND_UP(KEYDATA + 512, 4); - - DBGPRINT(RT_DEBUG_TRACE, ("Wpa2PairMsg3Action ----->\n")); - - pHeader = (PHEADER_802_11) Elem->Msg; - - // Process message 3 frame. - pMsg3 = (PEAPOL_PACKET) &Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H]; - - NdisZeroMemory((PUCHAR)&peerKeyInfo, sizeof(peerKeyInfo)); - NdisMoveMemory((PUCHAR)&peerKeyInfo, (PUCHAR)&pMsg3->KeyDesc.KeyInfo, sizeof(KEY_INFO)); - - *((USHORT*)&peerKeyInfo) = cpu2le16(*((USHORT*)&peerKeyInfo)); - - // 1. Verify cipher type match - if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled && (peerKeyInfo.KeyDescVer!= 2)) - { - os_free_mem(pAd, (PUCHAR)mpool); - return; - } - else if(pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled && (peerKeyInfo.KeyDescVer != 1)) - { - os_free_mem(pAd, (PUCHAR)mpool); - return; - } - - // 2. Check MIC value - // Save the MIC and replace with zero - NdisMoveMemory(OldMic, pMsg3->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); - NdisZeroMemory(pMsg3->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); - if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) - { - // AES - HMAC_SHA1((PUCHAR) pMsg3, pMsg3->Body_Len[1] + 4, pAd->StaCfg.PTK, LEN_EAP_MICK, digest); - NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); - } - else - { - hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, (PUCHAR) pMsg3, pMsg3->Body_Len[1] + 4, Mic); - } - - if(!NdisEqualMemory(OldMic, Mic, LEN_KEY_DESC_MIC)) - { - DBGPRINT(RT_DEBUG_ERROR, (" MIC Different in msg 3 of 4-way handshake!!!!!!!!!! \n")); - os_free_mem(pAd, (PUCHAR)mpool); - return; - } - else - DBGPRINT(RT_DEBUG_TRACE, (" MIC VALID in msg 3 of 4-way handshake!!!!!!!!!! \n")); - - // 3. Check Replay Counter, it has to be larger than last one. No need to be exact one larger - if(RTMPCompareMemory(pMsg3->KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY) != 1) - { - os_free_mem(pAd, (PUCHAR)mpool); - return; - } - - // Update new replay counter - NdisMoveMemory(pAd->StaCfg.ReplayCounter, pMsg3->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); - - // 4. Double check ANonce - if(!NdisEqualMemory(pAd->StaCfg.ANonce, pMsg3->KeyDesc.KeyNonce, LEN_KEY_DESC_NONCE)) - { - os_free_mem(pAd, (PUCHAR)mpool); - return; - } - - // Obtain GTK - // 5. Decrypt GTK from Key Data - DBGPRINT_RAW(RT_DEBUG_TRACE, ("EKD = %d\n", peerKeyInfo.EKD_DL)); - if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) - { - // Decrypt AES GTK - AES_GTK_KEY_UNWRAP(&pAd->StaCfg.PTK[16], KEYDATA, pMsg3->KeyDesc.KeyDataLen[1],pMsg3->KeyDesc.KeyData); - } - else // TKIP - { - INT i; - // Decrypt TKIP GTK - // Construct 32 bytes RC4 Key - NdisMoveMemory(Key, pMsg3->KeyDesc.KeyIv, 16); - NdisMoveMemory(&Key[16], &pAd->StaCfg.PTK[16], 16); - ARCFOUR_INIT(&pAd->PrivateInfo.WEPCONTEXT, Key, 32); - //discard first 256 bytes - for(i = 0; i < 256; i++) - ARCFOUR_BYTE(&pAd->PrivateInfo.WEPCONTEXT); - // Decrypt GTK. Becareful, there is no ICV to check the result is correct or not - ARCFOUR_DECRYPT(&pAd->PrivateInfo.WEPCONTEXT, KEYDATA, pMsg3->KeyDesc.KeyData, pMsg3->KeyDesc.KeyDataLen[1]); - } - - if (!ParseKeyData(pAd, KEYDATA, pMsg3->KeyDesc.KeyDataLen[1], 1)) - { - os_free_mem(pAd, (PUCHAR)mpool); - return; - } - - // Update GTK to ASIC - // Update group key information to ASIC Shared Key Table - AsicAddSharedKeyEntry(pAd, - BSS0, - pAd->StaCfg.DefaultKeyId, - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic); - - // Update ASIC WCID attribute table and IVEIV table - RTMPAddWcidAttributeEntry(pAd, - BSS0, - pAd->StaCfg.DefaultKeyId, - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, - NULL); - - // init 802.3 header and Fill Packet - MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL); - - // Zero message 4 body - NdisZeroMemory(&Packet, sizeof(Packet)); - Packet.ProVer = EAPOL_VER; - Packet.ProType = EAPOLKey; - Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE; // No data field - - // - // Message 4 as EAPOL-Key(0,1,0,0,0,P,0,0,MIC,0) - // - Packet.KeyDesc.Type = WPA2_KEY_DESC; - - // Key descriptor version and appropriate RSN IE - Packet.KeyDesc.KeyInfo.KeyDescVer = peerKeyInfo.KeyDescVer; - - // Update Key Length - Packet.KeyDesc.KeyLength[0] = pMsg3->KeyDesc.KeyLength[0]; - Packet.KeyDesc.KeyLength[1] = pMsg3->KeyDesc.KeyLength[1]; - - // Key Type PeerKey - Packet.KeyDesc.KeyInfo.KeyType = PAIRWISEKEY; - - // KeyMic field presented - Packet.KeyDesc.KeyInfo.KeyMic = 1; - Packet.KeyDesc.KeyInfo.Secure = 1; - - // Convert to little-endian format. - *((USHORT *)&Packet.KeyDesc.KeyInfo) = cpu2le16(*((USHORT *)&Packet.KeyDesc.KeyInfo)); - - // Key Replay count - NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pMsg3->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); - - // Out buffer for transmitting message 4 - MlmeAllocateMemory(pAd, (PUCHAR *)&pOutBuffer); // allocate memory - if(pOutBuffer == NULL) - { - os_free_mem(pAd, (PUCHAR)mpool); - return; - } - - // Prepare EAPOL frame for MIC calculation - // Be careful, only EAPOL frame is counted for MIC calculation - MakeOutgoingFrame(pOutBuffer, &FrameLen, - Packet.Body_Len[1] + 4, &Packet, - END_OF_ARGS); - - // Prepare and Fill MIC value - NdisZeroMemory(Mic, sizeof(Mic)); - if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) - { - // AES - HMAC_SHA1(pOutBuffer, FrameLen, pAd->StaCfg.PTK, LEN_EAP_MICK, digest); - NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); - } - else - { - hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic); - } - NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC); - - // Update PTK - // Prepare pair-wise key information into shared key table - NdisZeroMemory(&pAd->SharedKey[BSS0][0], sizeof(CIPHER_KEY)); - pAd->SharedKey[BSS0][0].KeyLen = LEN_TKIP_EK; - NdisMoveMemory(pAd->SharedKey[BSS0][0].Key, &pAd->StaCfg.PTK[32], LEN_TKIP_EK); - NdisMoveMemory(pAd->SharedKey[BSS0][0].RxMic, &pAd->StaCfg.PTK[48], LEN_TKIP_RXMICK); - NdisMoveMemory(pAd->SharedKey[BSS0][0].TxMic, &pAd->StaCfg.PTK[48+LEN_TKIP_RXMICK], LEN_TKIP_TXMICK); - - // Decide its ChiperAlg - if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled) - pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_TKIP; - else if (pAd->StaCfg.PairCipher == Ndis802_11Encryption3Enabled) - pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_AES; - else - pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_NONE; - - // Update these related information to MAC_TABLE_ENTRY - pEntry = &pAd->MacTab.Content[BSSID_WCID]; - NdisMoveMemory(&pEntry->PairwiseKey.Key, &pAd->StaCfg.PTK[32], LEN_TKIP_EK); - NdisMoveMemory(&pEntry->PairwiseKey.RxMic, &pAd->StaCfg.PTK[48], LEN_TKIP_RXMICK); - NdisMoveMemory(&pEntry->PairwiseKey.TxMic, &pAd->StaCfg.PTK[48+LEN_TKIP_RXMICK], LEN_TKIP_TXMICK); - pEntry->PairwiseKey.CipherAlg = pAd->SharedKey[BSS0][0].CipherAlg; - - // Update pairwise key information to ASIC Shared Key Table - AsicAddSharedKeyEntry(pAd, - BSS0, - 0, - pAd->SharedKey[BSS0][0].CipherAlg, - pAd->SharedKey[BSS0][0].Key, - pAd->SharedKey[BSS0][0].TxMic, - pAd->SharedKey[BSS0][0].RxMic); - - // Update ASIC WCID attribute table and IVEIV table - RTMPAddWcidAttributeEntry(pAd, - BSS0, - 0, - pAd->SharedKey[BSS0][0].CipherAlg, - pEntry); - - // Make Transmitting frame - MakeOutgoingFrame(pOutBuffer, &FrameLen, - LENGTH_802_3, &Header802_3, - Packet.Body_Len[1] + 4, &Packet, - END_OF_ARGS); - - - // Copy frame to Tx ring and Send Message 4 to authenticator - RTMPToWirelessSta(pAd, Header802_3, LENGTH_802_3, (PUCHAR)&Packet, Packet.Body_Len[1] + 4, TRUE); - - // set 802.1x port control - //pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; - STA_PORT_SECURED(pAd); - - // Indicate Connected for GUI - pAd->IndicateMediaState = NdisMediaStateConnected; - - MlmeFreeMemory(pAd, (PUCHAR)pOutBuffer); - os_free_mem(pAd, (PUCHAR)mpool); - - - // send wireless event - for set key done WPA2 - if (pAd->CommonCfg.bWirelessEvent) - RTMPSendWirelessEvent(pAd, IW_SET_KEY_DONE_WPA2_EVENT_FLAG, pEntry->Addr, BSS0, 0); - - DBGPRINT(RT_DEBUG_ERROR, ("Wpa2PairMsg3Action <-----\n")); - -} - -/* - ======================================================================== - - Routine Description: - Process Group key 2-way handshaking - - Arguments: - pAd Pointer to our adapter - Elem Message body - - Return Value: - None - - Note: - - ======================================================================== -*/ -VOID WpaGroupMsg1Action( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) - -{ - PUCHAR pOutBuffer = NULL; - UCHAR Header802_3[14]; - ULONG FrameLen = 0; - EAPOL_PACKET Packet; - PEAPOL_PACKET pGroup; - UCHAR *mpool, *digest, *KEYDATA; - UCHAR Mic[16], OldMic[16]; - UCHAR GTK[32], Key[32]; - KEY_INFO peerKeyInfo; - - // allocate memory - os_alloc_mem(pAd, (PUCHAR *)&mpool, 1024); - - if(mpool == NULL) - return; - - // digest Len = 80. - digest = (UCHAR *) ROUND_UP(mpool, 4); - // KEYDATA Len = 512. - KEYDATA = (UCHAR *) ROUND_UP(digest + 80, 4); - - DBGPRINT(RT_DEBUG_TRACE, ("WpaGroupMsg1Action ----->\n")); - - // Process Group Message 1 frame. skip 802.11 header(24) & LLC_SNAP header(8) - pGroup = (PEAPOL_PACKET) &Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H]; - - NdisZeroMemory((PUCHAR)&peerKeyInfo, sizeof(peerKeyInfo)); - NdisMoveMemory((PUCHAR)&peerKeyInfo, (PUCHAR)&pGroup->KeyDesc.KeyInfo, sizeof(KEY_INFO)); - - *((USHORT*)&peerKeyInfo) = cpu2le16(*((USHORT*)&peerKeyInfo)); - - // 0. Check cipher type match - if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled && (peerKeyInfo.KeyDescVer != 2)) - { - os_free_mem(pAd, (PUCHAR)mpool); - return; - } - else if (pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled && (peerKeyInfo.KeyDescVer != 1)) - { - os_free_mem(pAd, (PUCHAR)mpool); - return; - } - - // 1. Verify Replay counter - // Check Replay Counter, it has to be larger than last one. No need to be exact one larger - if(RTMPCompareMemory(pGroup->KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY) != 1) - { - os_free_mem(pAd, (PUCHAR)mpool); - return; - } - - // Update new replay counter - NdisMoveMemory(pAd->StaCfg.ReplayCounter, pGroup->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); - - // 2. Verify MIC is valid - // Save the MIC and replace with zero - NdisMoveMemory(OldMic, pGroup->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); - NdisZeroMemory(pGroup->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); - - if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) - { // AES - HMAC_SHA1((PUCHAR) pGroup, pGroup->Body_Len[1] + 4, pAd->StaCfg.PTK, LEN_EAP_MICK, digest); - NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); - } - else - { // TKIP - hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, (PUCHAR) pGroup, pGroup->Body_Len[1] + 4, Mic); - } - - if(!NdisEqualMemory(OldMic, Mic, LEN_KEY_DESC_MIC)) - { - DBGPRINT(RT_DEBUG_ERROR, (" MIC Different in group msg 1 of 2-way handshake!!!!!!!!!! \n")); - MlmeFreeMemory(pAd, (PUCHAR)mpool); - return; - } - else - DBGPRINT(RT_DEBUG_TRACE, (" MIC VALID in group msg 1 of 2-way handshake!!!!!!!!!! \n")); - - - // 3. Decrypt GTK from Key Data - if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) - { - // Decrypt AES GTK - AES_GTK_KEY_UNWRAP(&pAd->StaCfg.PTK[16], KEYDATA, pGroup->KeyDesc.KeyDataLen[1], pGroup->KeyDesc.KeyData); - } - else // TKIP - { - INT i; - - // Decrypt TKIP GTK - // Construct 32 bytes RC4 Key - NdisMoveMemory(Key, pGroup->KeyDesc.KeyIv, 16); - NdisMoveMemory(&Key[16], &pAd->StaCfg.PTK[16], 16); - ARCFOUR_INIT(&pAd->PrivateInfo.WEPCONTEXT, Key, 32); - //discard first 256 bytes - for(i = 0; i < 256; i++) - ARCFOUR_BYTE(&pAd->PrivateInfo.WEPCONTEXT); - // Decrypt GTK. Becareful, there is no ICV to check the result is correct or not - ARCFOUR_DECRYPT(&pAd->PrivateInfo.WEPCONTEXT, KEYDATA, pGroup->KeyDesc.KeyData, pGroup->KeyDesc.KeyDataLen[1]); - } - - // Process decrypted key data material - // Parse keyData to handle KDE format for WPA2PSK - if (peerKeyInfo.EKD_DL) - { - if (!ParseKeyData(pAd, KEYDATA, pGroup->KeyDesc.KeyDataLen[1], 0)) - { - os_free_mem(pAd, (PUCHAR)mpool); - return; - } - } - else // WPAPSK - { - // set key material, TxMic and RxMic for WPAPSK - NdisMoveMemory(GTK, KEYDATA, 32); - NdisMoveMemory(pAd->StaCfg.GTK, GTK, 32); - pAd->StaCfg.DefaultKeyId = peerKeyInfo.KeyIndex; - - // Prepare pair-wise key information into shared key table - NdisZeroMemory(&pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId], sizeof(CIPHER_KEY)); - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].KeyLen = LEN_TKIP_EK; - NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, GTK, LEN_TKIP_EK); - NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic, >K[16], LEN_TKIP_RXMICK); - NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, >K[24], LEN_TKIP_TXMICK); - - // Update Shared Key CipherAlg - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_NONE; - if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption2Enabled) - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_TKIP; - else if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption3Enabled) - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_AES; - else if (pAd->StaCfg.GroupCipher == Ndis802_11GroupWEP40Enabled) - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_WEP64; - else if (pAd->StaCfg.GroupCipher == Ndis802_11GroupWEP104Enabled) - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_WEP128; - - //hex_dump("Group Key :", pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, LEN_TKIP_EK); - } - - // Update group key information to ASIC Shared Key Table - AsicAddSharedKeyEntry(pAd, - BSS0, - pAd->StaCfg.DefaultKeyId, - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic); - - // Update ASIC WCID attribute table and IVEIV table - RTMPAddWcidAttributeEntry(pAd, - BSS0, - pAd->StaCfg.DefaultKeyId, - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, - NULL); - - // set 802.1x port control - //pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; - STA_PORT_SECURED(pAd); - - // Indicate Connected for GUI - pAd->IndicateMediaState = NdisMediaStateConnected; - - // init header and Fill Packet - MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL); - - // Zero Group message 1 body - NdisZeroMemory(&Packet, sizeof(Packet)); - Packet.ProVer = EAPOL_VER; - Packet.ProType = EAPOLKey; - Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE; // No data field - - // - // Group Message 2 as EAPOL-Key(1,0,0,0,G,0,0,MIC,0) - // - if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) - { - Packet.KeyDesc.Type = WPA2_KEY_DESC; - } - else - { - Packet.KeyDesc.Type = WPA1_KEY_DESC; - } - - // Key descriptor version and appropriate RSN IE - Packet.KeyDesc.KeyInfo.KeyDescVer = peerKeyInfo.KeyDescVer; - - // Update Key Length - Packet.KeyDesc.KeyLength[0] = pGroup->KeyDesc.KeyLength[0]; - Packet.KeyDesc.KeyLength[1] = pGroup->KeyDesc.KeyLength[1]; - - // Key Index as G-Msg 1 - if(pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) - Packet.KeyDesc.KeyInfo.KeyIndex = peerKeyInfo.KeyIndex; - - // Key Type Group key - Packet.KeyDesc.KeyInfo.KeyType = GROUPKEY; - - // KeyMic field presented - Packet.KeyDesc.KeyInfo.KeyMic = 1; - - // Secure bit - Packet.KeyDesc.KeyInfo.Secure = 1; - - // Convert to little-endian format. - *((USHORT *)&Packet.KeyDesc.KeyInfo) = cpu2le16(*((USHORT *)&Packet.KeyDesc.KeyInfo)); - - // Key Replay count - NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pGroup->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); - - // Out buffer for transmitting group message 2 - MlmeAllocateMemory(pAd, (PUCHAR *)&pOutBuffer); // allocate memory - if(pOutBuffer == NULL) - { - MlmeFreeMemory(pAd, (PUCHAR)mpool); - return; - } - - // Prepare EAPOL frame for MIC calculation - // Be careful, only EAPOL frame is counted for MIC calculation - MakeOutgoingFrame(pOutBuffer, &FrameLen, - Packet.Body_Len[1] + 4, &Packet, - END_OF_ARGS); - - // Prepare and Fill MIC value - NdisZeroMemory(Mic, sizeof(Mic)); - if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) - { - // AES - HMAC_SHA1(pOutBuffer, FrameLen, pAd->StaCfg.PTK, LEN_EAP_MICK, digest); - NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); - } - else - { - hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic); - } - NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC); - - - MakeOutgoingFrame(pOutBuffer, &FrameLen, - LENGTH_802_3, &Header802_3, - Packet.Body_Len[1] + 4, &Packet, - END_OF_ARGS); - - - // 5. Copy frame to Tx ring and prepare for encryption - RTMPToWirelessSta(pAd, Header802_3, LENGTH_802_3, (PUCHAR)&Packet, Packet.Body_Len[1] + 4, FALSE); - - // 6 Free allocated memory - MlmeFreeMemory(pAd, (PUCHAR)pOutBuffer); - os_free_mem(pAd, (PUCHAR)mpool); - - // send wireless event - for set key done WPA2 - if (pAd->CommonCfg.bWirelessEvent) - RTMPSendWirelessEvent(pAd, IW_SET_KEY_DONE_WPA2_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); - - DBGPRINT(RT_DEBUG_TRACE, ("WpaGroupMsg1Action <-----\n")); -} - -/* - ======================================================================== - - Routine Description: - Init WPA MAC header - - Arguments: - pAd Pointer to our adapter - - Return Value: - None - - Note: - - ======================================================================== -*/ -VOID WpaMacHeaderInit( - IN PRTMP_ADAPTER pAd, - IN OUT PHEADER_802_11 pHdr80211, - IN UCHAR wep, - IN PUCHAR pAddr1) -{ - NdisZeroMemory(pHdr80211, sizeof(HEADER_802_11)); - pHdr80211->FC.Type = BTYPE_DATA; - pHdr80211->FC.ToDs = 1; - if (wep == 1) - pHdr80211->FC.Wep = 1; - - // Addr1: BSSID, Addr2: SA, Addr3: DA - COPY_MAC_ADDR(pHdr80211->Addr1, pAddr1); - COPY_MAC_ADDR(pHdr80211->Addr2, pAd->CurrentAddress); - COPY_MAC_ADDR(pHdr80211->Addr3, pAd->CommonCfg.Bssid); - pHdr80211->Sequence = pAd->Sequence; -} - -/* - ======================================================================== - - Routine Description: - Copy frame from waiting queue into relative ring buffer and set - appropriate ASIC register to kick hardware encryption before really - sent out to air. - - Arguments: - pAd Pointer to our adapter - PNDIS_PACKET Pointer to outgoing Ndis frame - NumberOfFrag Number of fragment required - - Return Value: - None - - Note: - - ======================================================================== -*/ -VOID RTMPToWirelessSta( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pHeader802_3, - IN UINT HdrLen, - IN PUCHAR pData, - IN UINT DataLen, - IN BOOLEAN is4wayFrame) - -{ - NDIS_STATUS Status; - PNDIS_PACKET pPacket; - UCHAR Index; - - do - { - // 1. build a NDIS packet and call RTMPSendPacket(); - // be careful about how/when to release this internal allocated NDIS PACKET buffer - Status = RTMPAllocateNdisPacket(pAd, &pPacket, pHeader802_3, HdrLen, pData, DataLen); - if (Status != NDIS_STATUS_SUCCESS) - break; - - if (is4wayFrame) - RTMP_SET_PACKET_CLEAR_EAP_FRAME(pPacket, 1); - else - RTMP_SET_PACKET_CLEAR_EAP_FRAME(pPacket, 0); - - // 2. send out the packet - Status = STASendPacket(pAd, pPacket); - if(Status == NDIS_STATUS_SUCCESS) - { - // Dequeue one frame from TxSwQueue0..3 queue and process it - // There are three place calling dequeue for TX ring. - // 1. Here, right after queueing the frame. - // 2. At the end of TxRingTxDone service routine. - // 3. Upon NDIS call RTMPSendPackets - if((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) && - (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS))) - { - for(Index = 0; Index < 5; Index ++) - if(pAd->TxSwQueue[Index].Number > 0) - RTMPDeQueuePacket(pAd, FALSE, Index, MAX_TX_PROCESS); - } - } - } while(FALSE); - -} - -/* - ======================================================================== - - Routine Description: - Check Sanity RSN IE form AP - - Arguments: - - Return Value: - - - ======================================================================== -*/ -BOOLEAN CheckRSNIE( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pData, - IN UCHAR DataLen, - OUT UCHAR *Offset) -{ - PUCHAR pVIE; - UCHAR len; - PEID_STRUCT pEid; - BOOLEAN result = FALSE; - - pVIE = pData; - len = DataLen; - *Offset = 0; - - while (len > sizeof(RSNIE2)) - { - pEid = (PEID_STRUCT) pVIE; - // WPA RSN IE - if ((pEid->Eid == IE_WPA) && (NdisEqualMemory(pEid->Octet, WPA_OUI, 4))) - { - if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA || pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) && - (NdisEqualMemory(pVIE, pAd->MacTab.Content[BSSID_WCID].RSN_IE, pAd->MacTab.Content[BSSID_WCID].RSNIE_Len)) && - (pAd->MacTab.Content[BSSID_WCID].RSNIE_Len == (pEid->Len + 2))) - { - DBGPRINT(RT_DEBUG_TRACE, ("CheckRSNIE ==> WPA/WPAPSK RSN IE matched in Msg 3, Length(%d) \n", (pEid->Len + 2))); - result = TRUE; - } - - *Offset += (pEid->Len + 2); - } - // WPA2 RSN IE - else if ((pEid->Eid == IE_RSN) && (NdisEqualMemory(pEid->Octet + 2, RSN_OUI, 3))) - { - if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2 || pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) && - (NdisEqualMemory(pVIE, pAd->MacTab.Content[BSSID_WCID].RSN_IE, pAd->MacTab.Content[BSSID_WCID].RSNIE_Len)) && - (pAd->MacTab.Content[BSSID_WCID].RSNIE_Len == (pEid->Len + 2))) - { - DBGPRINT(RT_DEBUG_TRACE, ("CheckRSNIE ==> WPA2/WPA2PSK RSN IE matched in Msg 3, Length(%d) \n", (pEid->Len + 2))); - result = TRUE; - } - - *Offset += (pEid->Len + 2); - } - else - { - break; - } - - pVIE += (pEid->Len + 2); - len -= (pEid->Len + 2); - } - - DBGPRINT(RT_DEBUG_TRACE, ("CheckRSNIE ==> skip_offset(%d) \n", *Offset)); - - return result; - -} - - -/* - ======================================================================== - - Routine Description: - Parse KEYDATA field. KEYDATA[] May contain 2 RSN IE and optionally GTK. - GTK is encaptulated in KDE format at p.83 802.11i D10 - - Arguments: - - Return Value: - - Note: - 802.11i D10 - - ======================================================================== -*/ -BOOLEAN ParseKeyData( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pKeyData, - IN UCHAR KeyDataLen, - IN UCHAR bPairewise) -{ - PKDE_ENCAP pKDE = NULL; - PUCHAR pMyKeyData = pKeyData; - UCHAR KeyDataLength = KeyDataLen; - UCHAR GTKLEN; - UCHAR skip_offset; - - // Verify The RSN IE contained in Pairewise-Msg 3 and skip it - if (bPairewise) - { - // Check RSN IE whether it is WPA2/WPA2PSK - if (!CheckRSNIE(pAd, pKeyData, KeyDataLen, &skip_offset)) - { - DBGPRINT(RT_DEBUG_ERROR, ("ParseKeyData ==> WPA2/WPA2PSK RSN IE mismatched \n")); - hex_dump("Get KEYDATA :", pKeyData, KeyDataLen); - return FALSE; - } - else - { - // skip RSN IE - pMyKeyData += skip_offset; - KeyDataLength -= skip_offset; - - //DBGPRINT(RT_DEBUG_TRACE, ("ParseKeyData ==> WPA2/WPA2PSK RSN IE matched in Msg 3, Length(%d) \n", skip_offset)); - } - } - - DBGPRINT(RT_DEBUG_TRACE,("ParseKeyData ==> KeyDataLength %d without RSN_IE \n", KeyDataLength)); - - // Parse EKD format - if (KeyDataLength >= 8) - { - pKDE = (PKDE_ENCAP) pMyKeyData; - } - else - { - DBGPRINT(RT_DEBUG_ERROR, ("ERROR: KeyDataLength is too short \n")); - return FALSE; - } - - - // Sanity check - shared key index should not be 0 - if (pKDE->GTKEncap.Kid == 0) - { - DBGPRINT(RT_DEBUG_ERROR, ("ERROR: GTK Key index zero \n")); - return FALSE; - } - - // Sanity check - KED length - if (KeyDataLength < (pKDE->Len + 2)) - { - DBGPRINT(RT_DEBUG_ERROR, ("ERROR: The len from KDE is too short \n")); - return FALSE; - } - - // Get GTK length - refer to IEEE 802.11i-2004 p.82 - GTKLEN = pKDE->Len -6; - - if (GTKLEN < MIN_LEN_OF_GTK) - { - DBGPRINT(RT_DEBUG_ERROR, ("ERROR: GTK Key length is too short (%d) \n", GTKLEN)); - return FALSE; - } - else - DBGPRINT(RT_DEBUG_TRACE, ("GTK Key with KDE formet got index=%d, len=%d \n", pKDE->GTKEncap.Kid, GTKLEN)); - - // Update GTK - // set key material, TxMic and RxMic for WPAPSK - NdisMoveMemory(pAd->StaCfg.GTK, pKDE->GTKEncap.GTK, 32); - pAd->StaCfg.DefaultKeyId = pKDE->GTKEncap.Kid; - - // Update shared key table - NdisZeroMemory(&pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId], sizeof(CIPHER_KEY)); - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].KeyLen = LEN_TKIP_EK; - NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, pKDE->GTKEncap.GTK, LEN_TKIP_EK); - NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic, &pKDE->GTKEncap.GTK[16], LEN_TKIP_RXMICK); - NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, &pKDE->GTKEncap.GTK[24], LEN_TKIP_TXMICK); - - // Update Shared Key CipherAlg - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_NONE; - if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption2Enabled) - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_TKIP; - else if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption3Enabled) - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_AES; - else if (pAd->StaCfg.GroupCipher == Ndis802_11GroupWEP40Enabled) - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_WEP64; - else if (pAd->StaCfg.GroupCipher == Ndis802_11GroupWEP104Enabled) - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_WEP128; - - return TRUE; - -} - -/* - ======================================================================== - - Routine Description: - Cisco CCKM PRF function - - Arguments: - key Cisco Base Transient Key (BTK) - key_len The key length of the BTK - data Ruquest Number(RN) + BSSID - data_len The length of the data - output Store for PTK(Pairwise transient keys) - len The length of the output - Return Value: - None - - Note: - 802.1i Annex F.9 - - ======================================================================== -*/ -VOID CCKMPRF( - IN UCHAR *key, - IN INT key_len, - IN UCHAR *data, - IN INT data_len, - OUT UCHAR *output, - IN INT len) -{ - INT i; - UCHAR input[1024]; - INT currentindex = 0; - INT total_len; - - NdisMoveMemory(input, data, data_len); - total_len = data_len; - input[total_len] = 0; - total_len++; - for (i = 0; i < (len + 19) / 20; i++) - { - HMAC_SHA1(input, total_len, key, key_len, &output[currentindex]); - currentindex += 20; - input[total_len - 1]++; - } -} - -/* - ======================================================================== - - Routine Description: - Process MIC error indication and record MIC error timer. - - Arguments: - pAd Pointer to our adapter - pWpaKey Pointer to the WPA key structure - - Return Value: - None - - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -VOID RTMPReportMicError( - IN PRTMP_ADAPTER pAd, - IN PCIPHER_KEY pWpaKey) -{ - ULONG Now; - UCHAR unicastKey = (pWpaKey->Type == PAIRWISE_KEY ? 1:0); - - // Record Last MIC error time and count - Now = jiffies; - if (pAd->StaCfg.MicErrCnt == 0) - { - pAd->StaCfg.MicErrCnt++; - pAd->StaCfg.LastMicErrorTime = Now; - NdisZeroMemory(pAd->StaCfg.ReplayCounter, 8); - } - else if (pAd->StaCfg.MicErrCnt == 1) - { - if ((pAd->StaCfg.LastMicErrorTime + (60 * OS_HZ)) < Now) - { - // Update Last MIC error time, this did not violate two MIC errors within 60 seconds - pAd->StaCfg.LastMicErrorTime = Now; - } - else - { - - if (pAd->CommonCfg.bWirelessEvent) - RTMPSendWirelessEvent(pAd, IW_COUNTER_MEASURES_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); - - pAd->StaCfg.LastMicErrorTime = Now; - // Violate MIC error counts, MIC countermeasures kicks in - pAd->StaCfg.MicErrCnt++; - // We shall block all reception - // We shall clean all Tx ring and disassoicate from AP after next EAPOL frame - // - // No necessary to clean all Tx ring, on RTMPHardTransmit will stop sending non-802.1X EAPOL packets - // if pAd->StaCfg.MicErrCnt greater than 2. - // - // RTMPRingCleanUp(pAd, QID_AC_BK); - // RTMPRingCleanUp(pAd, QID_AC_BE); - // RTMPRingCleanUp(pAd, QID_AC_VI); - // RTMPRingCleanUp(pAd, QID_AC_VO); - // RTMPRingCleanUp(pAd, QID_HCCA); - } - } - else - { - // MIC error count >= 2 - // This should not happen - ; - } - MlmeEnqueue(pAd, - MLME_CNTL_STATE_MACHINE, - OID_802_11_MIC_FAILURE_REPORT_FRAME, - 1, - &unicastKey); - - if (pAd->StaCfg.MicErrCnt == 2) - { - RTMPSetTimer(&pAd->StaCfg.WpaDisassocAndBlockAssocTimer, 100); - } -} - - -#ifdef WPA_SUPPLICANT_SUPPORT -#define LENGTH_EAP_H 4 -// If the received frame is EAP-Packet ,find out its EAP-Code (Request(0x01), Response(0x02), Success(0x03), Failure(0x04)). -INT WpaCheckEapCode( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pFrame, - IN USHORT FrameLen, - IN USHORT OffSet) -{ - - PUCHAR pData; - INT result = 0; - - if( FrameLen < OffSet + LENGTH_EAPOL_H + LENGTH_EAP_H ) - return result; - - pData = pFrame + OffSet; // skip offset bytes - - if(*(pData+1) == EAPPacket) // 802.1x header - Packet Type - { - result = *(pData+4); // EAP header - Code - } - - return result; -} - -VOID WpaSendMicFailureToWpaSupplicant( - IN PRTMP_ADAPTER pAd, - IN BOOLEAN bUnicast) -{ - union iwreq_data wrqu; - char custom[IW_CUSTOM_MAX] = {0}; - - sprintf(custom, "MLME-MICHAELMICFAILURE.indication"); - if (bUnicast) - sprintf(custom, "%s unicast", custom); - wrqu.data.length = strlen(custom); - wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, custom); - - return; -} -#endif // WPA_SUPPLICANT_SUPPORT // - -VOID WpaMicFailureReportFrame( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - PUCHAR pOutBuffer = NULL; - UCHAR Header802_3[14]; - ULONG FrameLen = 0; - EAPOL_PACKET Packet; - UCHAR Mic[16]; - BOOLEAN bUnicast; - - DBGPRINT(RT_DEBUG_TRACE, ("WpaMicFailureReportFrame ----->\n")); - - bUnicast = (Elem->Msg[0] == 1 ? TRUE:FALSE); - pAd->Sequence = ((pAd->Sequence) + 1) & (MAX_SEQ_NUMBER); - - // init 802.3 header and Fill Packet - MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL); - - NdisZeroMemory(&Packet, sizeof(Packet)); - Packet.ProVer = EAPOL_VER; - Packet.ProType = EAPOLKey; - - Packet.KeyDesc.Type = WPA1_KEY_DESC; - - // Request field presented - Packet.KeyDesc.KeyInfo.Request = 1; - - if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) - { - Packet.KeyDesc.KeyInfo.KeyDescVer = 2; - } - else // TKIP - { - Packet.KeyDesc.KeyInfo.KeyDescVer = 1; - } - - Packet.KeyDesc.KeyInfo.KeyType = (bUnicast ? PAIRWISEKEY : GROUPKEY); - - // KeyMic field presented - Packet.KeyDesc.KeyInfo.KeyMic = 1; - - // Error field presented - Packet.KeyDesc.KeyInfo.Error = 1; - - // Update packet length after decide Key data payload - Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE; - - // Key Replay Count - NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY); - inc_byte_array(pAd->StaCfg.ReplayCounter, 8); - - // Convert to little-endian format. - *((USHORT *)&Packet.KeyDesc.KeyInfo) = cpu2le16(*((USHORT *)&Packet.KeyDesc.KeyInfo)); - - - MlmeAllocateMemory(pAd, (PUCHAR *)&pOutBuffer); // allocate memory - if(pOutBuffer == NULL) - { - return; - } - - // Prepare EAPOL frame for MIC calculation - // Be careful, only EAPOL frame is counted for MIC calculation - MakeOutgoingFrame(pOutBuffer, &FrameLen, - Packet.Body_Len[1] + 4, &Packet, - END_OF_ARGS); - - // Prepare and Fill MIC value - NdisZeroMemory(Mic, sizeof(Mic)); - if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) - { // AES - UCHAR digest[20] = {0}; - HMAC_SHA1(pOutBuffer, FrameLen, pAd->StaCfg.PTK, LEN_EAP_MICK, digest); - NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); - } - else - { // TKIP - hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic); - } - NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC); - - MakeOutgoingFrame(pOutBuffer, &FrameLen, - LENGTH_802_3, &Header802_3, - Packet.Body_Len[1] + 4, &Packet, - END_OF_ARGS); - - // opy frame to Tx ring and send MIC failure report frame to authenticator - RTMPToWirelessSta(pAd, Header802_3, LENGTH_802_3, (PUCHAR)&Packet, Packet.Body_Len[1] + 4, FALSE); - - MlmeFreeMemory(pAd, (PUCHAR)pOutBuffer); - - DBGPRINT(RT_DEBUG_TRACE, ("WpaMicFailureReportFrame <-----\n")); -} - -/** from wpa_supplicant - * inc_byte_array - Increment arbitrary length byte array by one - * @counter: Pointer to byte array - * @len: Length of the counter in bytes - * - * This function increments the last byte of the counter by one and continues - * rolling over to more significant bytes if the byte was incremented from - * 0xff to 0x00. - */ -void inc_byte_array(UCHAR *counter, int len) -{ - int pos = len - 1; - while (pos >= 0) { - counter[pos]++; - if (counter[pos] != 0) - break; - pos--; - } -} - -VOID WpaDisassocApAndBlockAssoc( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3) -{ - RTMP_ADAPTER *pAd = (PRTMP_ADAPTER)FunctionContext; - MLME_DISASSOC_REQ_STRUCT DisassocReq; - - // disassoc from current AP first - DBGPRINT(RT_DEBUG_TRACE, ("RTMPReportMicError - disassociate with current AP after sending second continuous EAPOL frame\n")); - DisassocParmFill(pAd, &DisassocReq, pAd->CommonCfg.Bssid, REASON_MIC_FAILURE); - MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ, sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq); - - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_DISASSOC; - pAd->StaCfg.bBlockAssoc = TRUE; -} - +#include "../../rt2860/sta/wpa.c" diff --git a/drivers/staging/rt2870/sta_ioctl.c b/drivers/staging/rt2870/sta_ioctl.c index 4b432ce4442e..3553a6c898b9 100644 --- a/drivers/staging/rt2870/sta_ioctl.c +++ b/drivers/staging/rt2870/sta_ioctl.c @@ -1,7068 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - sta_ioctl.c - - Abstract: - IOCTL related subroutines - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Rory Chen 01-03-2003 created - Rory Chen 02-14-2005 modify to support RT61 -*/ - -#include "rt_config.h" - -#ifdef DBG -extern ULONG RTDebugLevel; -#endif - -#define NR_WEP_KEYS 4 -#define WEP_SMALL_KEY_LEN (40/8) -#define WEP_LARGE_KEY_LEN (104/8) - -#define GROUP_KEY_NO 4 - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) -#define IWE_STREAM_ADD_EVENT(_A, _B, _C, _D, _E) iwe_stream_add_event(_A, _B, _C, _D, _E) -#define IWE_STREAM_ADD_POINT(_A, _B, _C, _D, _E) iwe_stream_add_point(_A, _B, _C, _D, _E) -#define IWE_STREAM_ADD_VALUE(_A, _B, _C, _D, _E, _F) iwe_stream_add_value(_A, _B, _C, _D, _E, _F) -#else -#define IWE_STREAM_ADD_EVENT(_A, _B, _C, _D, _E) iwe_stream_add_event(_B, _C, _D, _E) -#define IWE_STREAM_ADD_POINT(_A, _B, _C, _D, _E) iwe_stream_add_point(_B, _C, _D, _E) -#define IWE_STREAM_ADD_VALUE(_A, _B, _C, _D, _E, _F) iwe_stream_add_value(_B, _C, _D, _E, _F) -#endif - -extern UCHAR CipherWpa2Template[]; -extern UCHAR CipherWpaPskTkip[]; -extern UCHAR CipherWpaPskTkipLen; - -typedef struct PACKED _RT_VERSION_INFO{ - UCHAR DriverVersionW; - UCHAR DriverVersionX; - UCHAR DriverVersionY; - UCHAR DriverVersionZ; - UINT DriverBuildYear; - UINT DriverBuildMonth; - UINT DriverBuildDay; -} RT_VERSION_INFO, *PRT_VERSION_INFO; - -struct iw_priv_args privtab[] = { -{ RTPRIV_IOCTL_SET, - IW_PRIV_TYPE_CHAR | 1024, 0, - "set"}, - -{ RTPRIV_IOCTL_SHOW, 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, - ""}, -{ RTPRIV_IOCTL_SHOW, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, - ""}, -/* --- sub-ioctls definitions --- */ - { SHOW_CONN_STATUS, - 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "connStatus" }, - { SHOW_DRVIER_VERION, - 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "driverVer" }, - { SHOW_BA_INFO, - 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "bainfo" }, - { SHOW_DESC_INFO, - 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "descinfo" }, - { RAIO_OFF, - 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "radio_off" }, - { RAIO_ON, - 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "radio_on" }, -#ifdef QOS_DLS_SUPPORT - { SHOW_DLS_ENTRY_INFO, - 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "dlsentryinfo" }, -#endif // QOS_DLS_SUPPORT // - { SHOW_CFG_VALUE, - IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "show" }, - { SHOW_ADHOC_ENTRY_INFO, - 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "adhocEntry" }, - -/* --- sub-ioctls relations --- */ - -#ifdef DBG -{ RTPRIV_IOCTL_BBP, - IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, - "bbp"}, -{ RTPRIV_IOCTL_MAC, - IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | 1024, - "mac"}, -{ RTPRIV_IOCTL_E2P, - IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | 1024, - "e2p"}, -#endif /* DBG */ - -{ RTPRIV_IOCTL_STATISTICS, - 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, - "stat"}, -{ RTPRIV_IOCTL_GSITESURVEY, - 0, IW_PRIV_TYPE_CHAR | 1024, - "get_site_survey"}, -}; - -INT Set_SSID_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - -#ifdef WMM_SUPPORT -INT Set_WmmCapable_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); -#endif - -INT Set_NetworkType_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - -INT Set_AuthMode_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - -INT Set_EncrypType_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - -INT Set_DefaultKeyID_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - -INT Set_Key1_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - -INT Set_Key2_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - -INT Set_Key3_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - -INT Set_Key4_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - -INT Set_WPAPSK_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - - -INT Set_PSMode_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - -#ifdef WPA_SUPPLICANT_SUPPORT -INT Set_Wpa_Support( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); -#endif // WPA_SUPPLICANT_SUPPORT // - -#ifdef DBG -VOID RTMPIoctlBBP( - IN PRTMP_ADAPTER pAdapter, - IN struct iwreq *wrq); - -VOID RTMPIoctlMAC( - IN PRTMP_ADAPTER pAdapter, - IN struct iwreq *wrq); - -VOID RTMPIoctlE2PROM( - IN PRTMP_ADAPTER pAdapter, - IN struct iwreq *wrq); -#endif // DBG // - - -NDIS_STATUS RTMPWPANoneAddKeyProc( - IN PRTMP_ADAPTER pAd, - IN PVOID pBuf); - -INT Set_FragTest_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - -#ifdef DOT11_N_SUPPORT -INT Set_TGnWifiTest_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); -#endif // DOT11_N_SUPPORT // - -INT Set_LongRetryLimit_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - -INT Set_ShortRetryLimit_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - -#ifdef EXT_BUILD_CHANNEL_LIST -INT Set_Ieee80211dClientMode_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); -#endif // EXT_BUILD_CHANNEL_LIST // - -#ifdef CARRIER_DETECTION_SUPPORT -INT Set_CarrierDetect_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); -#endif // CARRIER_DETECTION_SUPPORT // - -INT Show_Adhoc_MacTable_Proc( - IN PRTMP_ADAPTER pAd, - IN PCHAR extra); - -static struct { - CHAR *name; - INT (*set_proc)(PRTMP_ADAPTER pAdapter, PUCHAR arg); -} *PRTMP_PRIVATE_SET_PROC, RTMP_PRIVATE_SUPPORT_PROC[] = { - {"DriverVersion", Set_DriverVersion_Proc}, - {"CountryRegion", Set_CountryRegion_Proc}, - {"CountryRegionABand", Set_CountryRegionABand_Proc}, - {"SSID", Set_SSID_Proc}, - {"WirelessMode", Set_WirelessMode_Proc}, - {"TxBurst", Set_TxBurst_Proc}, - {"TxPreamble", Set_TxPreamble_Proc}, - {"TxPower", Set_TxPower_Proc}, - {"Channel", Set_Channel_Proc}, - {"BGProtection", Set_BGProtection_Proc}, - {"RTSThreshold", Set_RTSThreshold_Proc}, - {"FragThreshold", Set_FragThreshold_Proc}, -#ifdef DOT11_N_SUPPORT - {"HtBw", Set_HtBw_Proc}, - {"HtMcs", Set_HtMcs_Proc}, - {"HtGi", Set_HtGi_Proc}, - {"HtOpMode", Set_HtOpMode_Proc}, - {"HtExtcha", Set_HtExtcha_Proc}, - {"HtMpduDensity", Set_HtMpduDensity_Proc}, - {"HtBaWinSize", Set_HtBaWinSize_Proc}, - {"HtRdg", Set_HtRdg_Proc}, - {"HtAmsdu", Set_HtAmsdu_Proc}, - {"HtAutoBa", Set_HtAutoBa_Proc}, - {"HtBaDecline", Set_BADecline_Proc}, - {"HtProtect", Set_HtProtect_Proc}, - {"HtMimoPs", Set_HtMimoPs_Proc}, -#endif // DOT11_N_SUPPORT // - -#ifdef AGGREGATION_SUPPORT - {"PktAggregate", Set_PktAggregate_Proc}, -#endif - -#ifdef WMM_SUPPORT - {"WmmCapable", Set_WmmCapable_Proc}, -#endif - {"IEEE80211H", Set_IEEE80211H_Proc}, - {"NetworkType", Set_NetworkType_Proc}, - {"AuthMode", Set_AuthMode_Proc}, - {"EncrypType", Set_EncrypType_Proc}, - {"DefaultKeyID", Set_DefaultKeyID_Proc}, - {"Key1", Set_Key1_Proc}, - {"Key2", Set_Key2_Proc}, - {"Key3", Set_Key3_Proc}, - {"Key4", Set_Key4_Proc}, - {"WPAPSK", Set_WPAPSK_Proc}, - {"ResetCounter", Set_ResetStatCounter_Proc}, - {"PSMode", Set_PSMode_Proc}, -#ifdef DBG - {"Debug", Set_Debug_Proc}, -#endif - -#ifdef RALINK_ATE - {"ATE", Set_ATE_Proc}, - {"ATEDA", Set_ATE_DA_Proc}, - {"ATESA", Set_ATE_SA_Proc}, - {"ATEBSSID", Set_ATE_BSSID_Proc}, - {"ATECHANNEL", Set_ATE_CHANNEL_Proc}, - {"ATETXPOW0", Set_ATE_TX_POWER0_Proc}, - {"ATETXPOW1", Set_ATE_TX_POWER1_Proc}, - {"ATETXANT", Set_ATE_TX_Antenna_Proc}, - {"ATERXANT", Set_ATE_RX_Antenna_Proc}, - {"ATETXFREQOFFSET", Set_ATE_TX_FREQOFFSET_Proc}, - {"ATETXBW", Set_ATE_TX_BW_Proc}, - {"ATETXLEN", Set_ATE_TX_LENGTH_Proc}, - {"ATETXCNT", Set_ATE_TX_COUNT_Proc}, - {"ATETXMCS", Set_ATE_TX_MCS_Proc}, - {"ATETXMODE", Set_ATE_TX_MODE_Proc}, - {"ATETXGI", Set_ATE_TX_GI_Proc}, - {"ATERXFER", Set_ATE_RX_FER_Proc}, - {"ATERRF", Set_ATE_Read_RF_Proc}, - {"ATEWRF1", Set_ATE_Write_RF1_Proc}, - {"ATEWRF2", Set_ATE_Write_RF2_Proc}, - {"ATEWRF3", Set_ATE_Write_RF3_Proc}, - {"ATEWRF4", Set_ATE_Write_RF4_Proc}, - {"ATELDE2P", Set_ATE_Load_E2P_Proc}, - {"ATERE2P", Set_ATE_Read_E2P_Proc}, - {"ATESHOW", Set_ATE_Show_Proc}, - {"ATEHELP", Set_ATE_Help_Proc}, - -#ifdef RALINK_28xx_QA - {"TxStop", Set_TxStop_Proc}, - {"RxStop", Set_RxStop_Proc}, -#endif // RALINK_28xx_QA // -#endif // RALINK_ATE // - -#ifdef WPA_SUPPLICANT_SUPPORT - {"WpaSupport", Set_Wpa_Support}, -#endif // WPA_SUPPLICANT_SUPPORT // - - - - {"FixedTxMode", Set_FixedTxMode_Proc}, -#ifdef CONFIG_APSTA_MIXED_SUPPORT - {"OpMode", Set_OpMode_Proc}, -#endif // CONFIG_APSTA_MIXED_SUPPORT // -#ifdef DOT11_N_SUPPORT - {"TGnWifiTest", Set_TGnWifiTest_Proc}, - {"ForceGF", Set_ForceGF_Proc}, -#endif // DOT11_N_SUPPORT // -#ifdef QOS_DLS_SUPPORT - {"DlsAddEntry", Set_DlsAddEntry_Proc}, - {"DlsTearDownEntry", Set_DlsTearDownEntry_Proc}, -#endif // QOS_DLS_SUPPORT // - {"LongRetry", Set_LongRetryLimit_Proc}, - {"ShortRetry", Set_ShortRetryLimit_Proc}, -#ifdef EXT_BUILD_CHANNEL_LIST - {"11dClientMode", Set_Ieee80211dClientMode_Proc}, -#endif // EXT_BUILD_CHANNEL_LIST // -#ifdef CARRIER_DETECTION_SUPPORT - {"CarrierDetect", Set_CarrierDetect_Proc}, -#endif // CARRIER_DETECTION_SUPPORT // - - {NULL,} -}; - - -VOID RTMPAddKey( - IN PRTMP_ADAPTER pAd, - IN PNDIS_802_11_KEY pKey) -{ - ULONG KeyIdx; - MAC_TABLE_ENTRY *pEntry; - - DBGPRINT(RT_DEBUG_TRACE, ("RTMPAddKey ------>\n")); - - if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - { - if (pKey->KeyIndex & 0x80000000) - { - if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) - { - NdisZeroMemory(pAd->StaCfg.PMK, 32); - NdisMoveMemory(pAd->StaCfg.PMK, pKey->KeyMaterial, pKey->KeyLength); - goto end; - } - // Update PTK - NdisZeroMemory(&pAd->SharedKey[BSS0][0], sizeof(CIPHER_KEY)); - pAd->SharedKey[BSS0][0].KeyLen = LEN_TKIP_EK; - NdisMoveMemory(pAd->SharedKey[BSS0][0].Key, pKey->KeyMaterial, LEN_TKIP_EK); -#ifdef WPA_SUPPLICANT_SUPPORT - if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled) - { - NdisMoveMemory(pAd->SharedKey[BSS0][0].RxMic, pKey->KeyMaterial + LEN_TKIP_EK, LEN_TKIP_TXMICK); - NdisMoveMemory(pAd->SharedKey[BSS0][0].TxMic, pKey->KeyMaterial + LEN_TKIP_EK + LEN_TKIP_TXMICK, LEN_TKIP_RXMICK); - } - else -#endif // WPA_SUPPLICANT_SUPPORT // - { - NdisMoveMemory(pAd->SharedKey[BSS0][0].TxMic, pKey->KeyMaterial + LEN_TKIP_EK, LEN_TKIP_TXMICK); - NdisMoveMemory(pAd->SharedKey[BSS0][0].RxMic, pKey->KeyMaterial + LEN_TKIP_EK + LEN_TKIP_TXMICK, LEN_TKIP_RXMICK); - } - - // Decide its ChiperAlg - if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled) - pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_TKIP; - else if (pAd->StaCfg.PairCipher == Ndis802_11Encryption3Enabled) - pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_AES; - else - pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_NONE; - - // Update these related information to MAC_TABLE_ENTRY - pEntry = &pAd->MacTab.Content[BSSID_WCID]; - NdisMoveMemory(pEntry->PairwiseKey.Key, pAd->SharedKey[BSS0][0].Key, LEN_TKIP_EK); - NdisMoveMemory(pEntry->PairwiseKey.RxMic, pAd->SharedKey[BSS0][0].RxMic, LEN_TKIP_RXMICK); - NdisMoveMemory(pEntry->PairwiseKey.TxMic, pAd->SharedKey[BSS0][0].TxMic, LEN_TKIP_TXMICK); - pEntry->PairwiseKey.CipherAlg = pAd->SharedKey[BSS0][0].CipherAlg; - - // Update pairwise key information to ASIC Shared Key Table - AsicAddSharedKeyEntry(pAd, - BSS0, - 0, - pAd->SharedKey[BSS0][0].CipherAlg, - pAd->SharedKey[BSS0][0].Key, - pAd->SharedKey[BSS0][0].TxMic, - pAd->SharedKey[BSS0][0].RxMic); - - // Update ASIC WCID attribute table and IVEIV table - RTMPAddWcidAttributeEntry(pAd, - BSS0, - 0, - pAd->SharedKey[BSS0][0].CipherAlg, - pEntry); - - if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA2) - { - // set 802.1x port control - //pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; - STA_PORT_SECURED(pAd); - - // Indicate Connected for GUI - pAd->IndicateMediaState = NdisMediaStateConnected; - } - } - else - { - // Update GTK - pAd->StaCfg.DefaultKeyId = (pKey->KeyIndex & 0xFF); - NdisZeroMemory(&pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId], sizeof(CIPHER_KEY)); - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].KeyLen = LEN_TKIP_EK; - NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, pKey->KeyMaterial, LEN_TKIP_EK); -#ifdef WPA_SUPPLICANT_SUPPORT - if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption2Enabled) - { - NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic, pKey->KeyMaterial + LEN_TKIP_EK, LEN_TKIP_TXMICK); - NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, pKey->KeyMaterial + LEN_TKIP_EK + LEN_TKIP_TXMICK, LEN_TKIP_RXMICK); - } - else -#endif // WPA_SUPPLICANT_SUPPORT // - { - NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, pKey->KeyMaterial + LEN_TKIP_EK, LEN_TKIP_TXMICK); - NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic, pKey->KeyMaterial + LEN_TKIP_EK + LEN_TKIP_TXMICK, LEN_TKIP_RXMICK); - } - - // Update Shared Key CipherAlg - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_NONE; - if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption2Enabled) - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_TKIP; - else if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption3Enabled) - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_AES; - - // Update group key information to ASIC Shared Key Table - AsicAddSharedKeyEntry(pAd, - BSS0, - pAd->StaCfg.DefaultKeyId, - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic); - - // Update ASIC WCID attribute table and IVEIV table - RTMPAddWcidAttributeEntry(pAd, - BSS0, - pAd->StaCfg.DefaultKeyId, - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, - NULL); - - // set 802.1x port control - //pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; - STA_PORT_SECURED(pAd); - - // Indicate Connected for GUI - pAd->IndicateMediaState = NdisMediaStateConnected; - } - } - else // dynamic WEP from wpa_supplicant - { - UCHAR CipherAlg; - PUCHAR Key; - - if(pKey->KeyLength == 32) - goto end; - - KeyIdx = pKey->KeyIndex & 0x0fffffff; - - if (KeyIdx < 4) - { - // it is a default shared key, for Pairwise key setting - if (pKey->KeyIndex & 0x80000000) - { - pEntry = MacTableLookup(pAd, pKey->BSSID); - - if (pEntry) - { - DBGPRINT(RT_DEBUG_TRACE, ("RTMPAddKey: Set Pair-wise Key\n")); - - // set key material and key length - pEntry->PairwiseKey.KeyLen = (UCHAR)pKey->KeyLength; - NdisMoveMemory(pEntry->PairwiseKey.Key, &pKey->KeyMaterial, pKey->KeyLength); - - // set Cipher type - if (pKey->KeyLength == 5) - pEntry->PairwiseKey.CipherAlg = CIPHER_WEP64; - else - pEntry->PairwiseKey.CipherAlg = CIPHER_WEP128; - - // Add Pair-wise key to Asic - AsicAddPairwiseKeyEntry( - pAd, - pEntry->Addr, - (UCHAR)pEntry->Aid, - &pEntry->PairwiseKey); - - // update WCID attribute table and IVEIV table for this entry - RTMPAddWcidAttributeEntry( - pAd, - BSS0, - KeyIdx, // The value may be not zero - pEntry->PairwiseKey.CipherAlg, - pEntry); - - } - } - else - { - // Default key for tx (shared key) - pAd->StaCfg.DefaultKeyId = (UCHAR) KeyIdx; - - // set key material and key length - pAd->SharedKey[BSS0][KeyIdx].KeyLen = (UCHAR) pKey->KeyLength; - NdisMoveMemory(pAd->SharedKey[BSS0][KeyIdx].Key, &pKey->KeyMaterial, pKey->KeyLength); - - // Set Ciper type - if (pKey->KeyLength == 5) - pAd->SharedKey[BSS0][KeyIdx].CipherAlg = CIPHER_WEP64; - else - pAd->SharedKey[BSS0][KeyIdx].CipherAlg = CIPHER_WEP128; - - CipherAlg = pAd->SharedKey[BSS0][KeyIdx].CipherAlg; - Key = pAd->SharedKey[BSS0][KeyIdx].Key; - - // Set Group key material to Asic - AsicAddSharedKeyEntry(pAd, BSS0, KeyIdx, CipherAlg, Key, NULL, NULL); - - // Update WCID attribute table and IVEIV table for this group key table - RTMPAddWcidAttributeEntry(pAd, BSS0, KeyIdx, CipherAlg, NULL); - - } - } - } -end: - return; -} - -char * rtstrchr(const char * s, int c) -{ - for(; *s != (char) c; ++s) - if (*s == '\0') - return NULL; - return (char *) s; -} - -/* -This is required for LinEX2004/kernel2.6.7 to provide iwlist scanning function -*/ - -int -rt_ioctl_giwname(struct net_device *dev, - struct iw_request_info *info, - char *name, char *extra) -{ -// PRTMP_ADAPTER pAdapter = dev->ml_priv; - -#ifdef RT2870 - strncpy(name, "RT2870 Wireless", IFNAMSIZ); -#endif // RT2870 // - return 0; -} - -int rt_ioctl_siwfreq(struct net_device *dev, - struct iw_request_info *info, - struct iw_freq *freq, char *extra) -{ - PRTMP_ADAPTER pAdapter = dev->ml_priv; - int chan = -1; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - - if (freq->e > 1) - return -EINVAL; - - if((freq->e == 0) && (freq->m <= 1000)) - chan = freq->m; // Setting by channel number - else - MAP_KHZ_TO_CHANNEL_ID( (freq->m /100) , chan); // Setting by frequency - search the table , like 2.412G, 2.422G, - - if (ChannelSanity(pAdapter, chan) == TRUE) - { - pAdapter->CommonCfg.Channel = chan; - DBGPRINT(RT_DEBUG_ERROR, ("==>rt_ioctl_siwfreq::SIOCSIWFREQ[cmd=0x%x] (Channel=%d)\n", SIOCSIWFREQ, pAdapter->CommonCfg.Channel)); - } - else - return -EINVAL; - - return 0; -} -int rt_ioctl_giwfreq(struct net_device *dev, - struct iw_request_info *info, - struct iw_freq *freq, char *extra) -{ - VIRTUAL_ADAPTER *pVirtualAd = NULL; - PRTMP_ADAPTER pAdapter = NULL; - UCHAR ch; - ULONG m; - - if (dev->priv_flags == INT_MAIN) - { - pAdapter = dev->ml_priv; - } - else - { - pVirtualAd = dev->ml_priv; - if (pVirtualAd && pVirtualAd->RtmpDev) - pAdapter = pVirtualAd->RtmpDev->ml_priv; - } - - if (pAdapter == NULL) - { - /* if 1st open fail, pAd will be free; - So the net_dev->ml_priv will be NULL in 2rd open */ - return -ENETDOWN; - } - - ch = pAdapter->CommonCfg.Channel; - - DBGPRINT(RT_DEBUG_TRACE,("==>rt_ioctl_giwfreq %d\n", ch)); - - MAP_CHANNEL_ID_TO_KHZ(ch, m); - freq->m = m * 100; - freq->e = 1; - return 0; -} - -int rt_ioctl_siwmode(struct net_device *dev, - struct iw_request_info *info, - __u32 *mode, char *extra) -{ - PRTMP_ADAPTER pAdapter = dev->ml_priv; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - switch (*mode) - { - case IW_MODE_ADHOC: - Set_NetworkType_Proc(pAdapter, "Adhoc"); - break; - case IW_MODE_INFRA: - Set_NetworkType_Proc(pAdapter, "Infra"); - break; -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,20)) - case IW_MODE_MONITOR: - Set_NetworkType_Proc(pAdapter, "Monitor"); - break; -#endif - default: - DBGPRINT(RT_DEBUG_TRACE, ("===>rt_ioctl_siwmode::SIOCSIWMODE (unknown %d)\n", *mode)); - return -EINVAL; - } - - // Reset Ralink supplicant to not use, it will be set to start when UI set PMK key - pAdapter->StaCfg.WpaState = SS_NOTUSE; - - return 0; -} - -int rt_ioctl_giwmode(struct net_device *dev, - struct iw_request_info *info, - __u32 *mode, char *extra) -{ - PRTMP_ADAPTER pAdapter = NULL; - VIRTUAL_ADAPTER *pVirtualAd = NULL; - - if (dev->priv_flags == INT_MAIN) - { - pAdapter = dev->ml_priv; - } - else - { - pVirtualAd = dev->ml_priv; - if (pVirtualAd && pVirtualAd->RtmpDev) - pAdapter = pVirtualAd->RtmpDev->ml_priv; - } - - if (pAdapter == NULL) - { - /* if 1st open fail, pAd will be free; - So the net_dev->ml_priv will be NULL in 2rd open */ - return -ENETDOWN; - } - - if (ADHOC_ON(pAdapter)) - *mode = IW_MODE_ADHOC; - else if (INFRA_ON(pAdapter)) - *mode = IW_MODE_INFRA; -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,20)) - else if (MONITOR_ON(pAdapter)) - { - *mode = IW_MODE_MONITOR; - } -#endif - else - *mode = IW_MODE_AUTO; - - DBGPRINT(RT_DEBUG_TRACE, ("==>rt_ioctl_giwmode(mode=%d)\n", *mode)); - return 0; -} - -int rt_ioctl_siwsens(struct net_device *dev, - struct iw_request_info *info, - char *name, char *extra) -{ - PRTMP_ADAPTER pAdapter = dev->ml_priv; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - return 0; -} - -int rt_ioctl_giwsens(struct net_device *dev, - struct iw_request_info *info, - char *name, char *extra) -{ - return 0; -} - -int rt_ioctl_giwrange(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *extra) -{ - PRTMP_ADAPTER pAdapter = NULL; - VIRTUAL_ADAPTER *pVirtualAd = NULL; - struct iw_range *range = (struct iw_range *) extra; - u16 val; - int i; - - if (dev->priv_flags == INT_MAIN) - { - pAdapter = dev->ml_priv; - } - else - { - pVirtualAd = dev->ml_priv; - if (pVirtualAd && pVirtualAd->RtmpDev) - pAdapter = pVirtualAd->RtmpDev->ml_priv; - } - - if (pAdapter == NULL) - { - /* if 1st open fail, pAd will be free; - So the net_dev->ml_priv will be NULL in 2rd open */ - return -ENETDOWN; - } - - DBGPRINT(RT_DEBUG_TRACE ,("===>rt_ioctl_giwrange\n")); - data->length = sizeof(struct iw_range); - memset(range, 0, sizeof(struct iw_range)); - - range->txpower_capa = IW_TXPOW_DBM; - - if (INFRA_ON(pAdapter)||ADHOC_ON(pAdapter)) - { - range->min_pmp = 1 * 1024; - range->max_pmp = 65535 * 1024; - range->min_pmt = 1 * 1024; - range->max_pmt = 1000 * 1024; - range->pmp_flags = IW_POWER_PERIOD; - range->pmt_flags = IW_POWER_TIMEOUT; - range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | - IW_POWER_UNICAST_R | IW_POWER_ALL_R; - } - - range->we_version_compiled = WIRELESS_EXT; - range->we_version_source = 14; - - range->retry_capa = IW_RETRY_LIMIT; - range->retry_flags = IW_RETRY_LIMIT; - range->min_retry = 0; - range->max_retry = 255; - - range->num_channels = pAdapter->ChannelListNum; - - val = 0; - for (i = 1; i <= range->num_channels; i++) - { - u32 m; - range->freq[val].i = pAdapter->ChannelList[i-1].Channel; - MAP_CHANNEL_ID_TO_KHZ(pAdapter->ChannelList[i-1].Channel, m); - range->freq[val].m = m * 100; /* HZ */ - - range->freq[val].e = 1; - val++; - if (val == IW_MAX_FREQUENCIES) - break; - } - range->num_frequency = val; - - range->max_qual.qual = 100; /* what is correct max? This was not - * documented exactly. At least - * 69 has been observed. */ - range->max_qual.level = 0; /* dB */ - range->max_qual.noise = 0; /* dB */ - - /* What would be suitable values for "average/typical" qual? */ - range->avg_qual.qual = 20; - range->avg_qual.level = -60; - range->avg_qual.noise = -95; - range->sensitivity = 3; - - range->max_encoding_tokens = NR_WEP_KEYS; - range->num_encoding_sizes = 2; - range->encoding_size[0] = 5; - range->encoding_size[1] = 13; - - range->min_rts = 0; - range->max_rts = 2347; - range->min_frag = 256; - range->max_frag = 2346; - -#if WIRELESS_EXT > 17 - /* IW_ENC_CAPA_* bit field */ - range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | - IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; -#endif - - return 0; -} - -int rt_ioctl_siwap(struct net_device *dev, - struct iw_request_info *info, - struct sockaddr *ap_addr, char *extra) -{ - PRTMP_ADAPTER pAdapter = dev->ml_priv; - NDIS_802_11_MAC_ADDRESS Bssid; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) - { - RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); - DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); - } - - // tell CNTL state machine to call NdisMSetInformationComplete() after completing - // this request, because this request is initiated by NDIS. - pAdapter->MlmeAux.CurrReqIsFromNdis = FALSE; - // Prevent to connect AP again in STAMlmePeriodicExec - pAdapter->MlmeAux.AutoReconnectSsidLen= 32; - - memset(Bssid, 0, MAC_ADDR_LEN); - memcpy(Bssid, ap_addr->sa_data, MAC_ADDR_LEN); - MlmeEnqueue(pAdapter, - MLME_CNTL_STATE_MACHINE, - OID_802_11_BSSID, - sizeof(NDIS_802_11_MAC_ADDRESS), - (VOID *)&Bssid); - - DBGPRINT(RT_DEBUG_TRACE, ("IOCTL::SIOCSIWAP %02x:%02x:%02x:%02x:%02x:%02x\n", - Bssid[0], Bssid[1], Bssid[2], Bssid[3], Bssid[4], Bssid[5])); - - return 0; -} - -int rt_ioctl_giwap(struct net_device *dev, - struct iw_request_info *info, - struct sockaddr *ap_addr, char *extra) -{ - PRTMP_ADAPTER pAdapter = NULL; - VIRTUAL_ADAPTER *pVirtualAd = NULL; - - if (dev->priv_flags == INT_MAIN) - { - pAdapter = dev->ml_priv; - } - else - { - pVirtualAd = dev->ml_priv; - if (pVirtualAd && pVirtualAd->RtmpDev) - pAdapter = pVirtualAd->RtmpDev->ml_priv; - } - - if (pAdapter == NULL) - { - /* if 1st open fail, pAd will be free; - So the net_dev->ml_priv will be NULL in 2rd open */ - return -ENETDOWN; - } - - if (INFRA_ON(pAdapter) || ADHOC_ON(pAdapter)) - { - ap_addr->sa_family = ARPHRD_ETHER; - memcpy(ap_addr->sa_data, &pAdapter->CommonCfg.Bssid, ETH_ALEN); - } -#ifdef WPA_SUPPLICANT_SUPPORT - // Add for RT2870 - else if (pAdapter->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_DISABLE) - { - ap_addr->sa_family = ARPHRD_ETHER; - memcpy(ap_addr->sa_data, &pAdapter->MlmeAux.Bssid, ETH_ALEN); - } -#endif // WPA_SUPPLICANT_SUPPORT // - else - { - DBGPRINT(RT_DEBUG_TRACE, ("IOCTL::SIOCGIWAP(=EMPTY)\n")); - return -ENOTCONN; - } - - return 0; -} - -/* - * Units are in db above the noise floor. That means the - * rssi values reported in the tx/rx descriptors in the - * driver are the SNR expressed in db. - * - * If you assume that the noise floor is -95, which is an - * excellent assumption 99.5 % of the time, then you can - * derive the absolute signal level (i.e. -95 + rssi). - * There are some other slight factors to take into account - * depending on whether the rssi measurement is from 11b, - * 11g, or 11a. These differences are at most 2db and - * can be documented. - * - * NB: various calculations are based on the orinoco/wavelan - * drivers for compatibility - */ -static void set_quality(PRTMP_ADAPTER pAdapter, - struct iw_quality *iq, - signed char rssi) -{ - __u8 ChannelQuality; - - // Normalize Rssi - if (rssi >= -50) - ChannelQuality = 100; - else if (rssi >= -80) // between -50 ~ -80dbm - ChannelQuality = (__u8)(24 + ((rssi + 80) * 26)/10); - else if (rssi >= -90) // between -80 ~ -90dbm - ChannelQuality = (__u8)((rssi + 90) * 26)/10; - else - ChannelQuality = 0; - - iq->qual = (__u8)ChannelQuality; - - iq->level = (__u8)(rssi); - iq->noise = (pAdapter->BbpWriteLatch[66] > pAdapter->BbpTuning.FalseCcaUpperThreshold) ? ((__u8)pAdapter->BbpTuning.FalseCcaUpperThreshold) : ((__u8) pAdapter->BbpWriteLatch[66]); // noise level (dBm) - iq->noise += 256 - 143; - iq->updated = pAdapter->iw_stats.qual.updated; -} - -int rt_ioctl_iwaplist(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *extra) -{ - PRTMP_ADAPTER pAdapter = dev->ml_priv; - - struct sockaddr addr[IW_MAX_AP]; - struct iw_quality qual[IW_MAX_AP]; - int i; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - data->length = 0; - return 0; - //return -ENETDOWN; - } - - for (i = 0; i = pAdapter->ScanTab.BssNr) - break; - addr[i].sa_family = ARPHRD_ETHER; - memcpy(addr[i].sa_data, &pAdapter->ScanTab.BssEntry[i].Bssid, MAC_ADDR_LEN); - set_quality(pAdapter, &qual[i], pAdapter->ScanTab.BssEntry[i].Rssi); - } - data->length = i; - memcpy(extra, &addr, i*sizeof(addr[0])); - data->flags = 1; /* signal quality present (sort of) */ - memcpy(extra + i*sizeof(addr[0]), &qual, i*sizeof(qual[i])); - - return 0; -} - -#ifdef SIOCGIWSCAN -int rt_ioctl_siwscan(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *extra) -{ - PRTMP_ADAPTER pAdapter = dev->ml_priv; - - ULONG Now; - int Status = NDIS_STATUS_SUCCESS; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - if (MONITOR_ON(pAdapter)) - { - DBGPRINT(RT_DEBUG_TRACE, ("!!! Driver is in Monitor Mode now !!!\n")); - return -EINVAL; - } - - -#ifdef WPA_SUPPLICANT_SUPPORT - if (pAdapter->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_ENABLE) - { - pAdapter->StaCfg.WpaSupplicantScanCount++; - } -#endif // WPA_SUPPLICANT_SUPPORT // - - pAdapter->StaCfg.bScanReqIsFromWebUI = TRUE; - if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) - return 0; - do{ - Now = jiffies; - -#ifdef WPA_SUPPLICANT_SUPPORT - if ((pAdapter->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_ENABLE) && - (pAdapter->StaCfg.WpaSupplicantScanCount > 3)) - { - DBGPRINT(RT_DEBUG_TRACE, ("!!! WpaSupplicantScanCount > 3\n")); - Status = NDIS_STATUS_SUCCESS; - break; - } -#endif // WPA_SUPPLICANT_SUPPORT // - - if ((OPSTATUS_TEST_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED)) && - ((pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || - (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) && - (pAdapter->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED)) - { - DBGPRINT(RT_DEBUG_TRACE, ("!!! Link UP, Port Not Secured! ignore this set::OID_802_11_BSSID_LIST_SCAN\n")); - Status = NDIS_STATUS_SUCCESS; - break; - } - - if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) - { - RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); - DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); - } - - // tell CNTL state machine to call NdisMSetInformationComplete() after completing - // this request, because this request is initiated by NDIS. - pAdapter->MlmeAux.CurrReqIsFromNdis = FALSE; - // Reset allowed scan retries - pAdapter->StaCfg.ScanCnt = 0; - pAdapter->StaCfg.LastScanTime = Now; - - MlmeEnqueue(pAdapter, - MLME_CNTL_STATE_MACHINE, - OID_802_11_BSSID_LIST_SCAN, - 0, - NULL); - - Status = NDIS_STATUS_SUCCESS; - RT28XX_MLME_HANDLER(pAdapter); - }while(0); - return 0; -} - -int rt_ioctl_giwscan(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *extra) -{ - - PRTMP_ADAPTER pAdapter = dev->ml_priv; - int i=0; - char *current_ev = extra, *previous_ev = extra; - char *end_buf; - char *current_val, custom[MAX_CUSTOM_LEN] = {0}; -#ifndef IWEVGENIE - char idx; -#endif // IWEVGENIE // - struct iw_event iwe; - - if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) - { - /* - * Still scanning, indicate the caller should try again. - */ - return -EAGAIN; - } - - -#ifdef WPA_SUPPLICANT_SUPPORT - if (pAdapter->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_ENABLE) - { - pAdapter->StaCfg.WpaSupplicantScanCount = 0; - } -#endif // WPA_SUPPLICANT_SUPPORT // - - if (pAdapter->ScanTab.BssNr == 0) - { - data->length = 0; - return 0; - } - -#if WIRELESS_EXT >= 17 - if (data->length > 0) - end_buf = extra + data->length; - else - end_buf = extra + IW_SCAN_MAX_DATA; -#else - end_buf = extra + IW_SCAN_MAX_DATA; -#endif - - for (i = 0; i < pAdapter->ScanTab.BssNr; i++) - { - if (current_ev >= end_buf) - { -#if WIRELESS_EXT >= 17 - return -E2BIG; -#else - break; -#endif - } - - //MAC address - //================================ - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWAP; - iwe.u.ap_addr.sa_family = ARPHRD_ETHER; - memcpy(iwe.u.ap_addr.sa_data, &pAdapter->ScanTab.BssEntry[i].Bssid, ETH_ALEN); - - previous_ev = current_ev; - current_ev = IWE_STREAM_ADD_EVENT(info, current_ev,end_buf, &iwe, IW_EV_ADDR_LEN); - if (current_ev == previous_ev) -#if WIRELESS_EXT >= 17 - return -E2BIG; -#else - break; -#endif - - //ESSID - //================================ - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWESSID; - iwe.u.data.length = pAdapter->ScanTab.BssEntry[i].SsidLen; - iwe.u.data.flags = 1; - - previous_ev = current_ev; - current_ev = IWE_STREAM_ADD_POINT(info, current_ev,end_buf, &iwe, pAdapter->ScanTab.BssEntry[i].Ssid); - if (current_ev == previous_ev) -#if WIRELESS_EXT >= 17 - return -E2BIG; -#else - break; -#endif - - //Network Type - //================================ - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWMODE; - if (pAdapter->ScanTab.BssEntry[i].BssType == Ndis802_11IBSS) - { - iwe.u.mode = IW_MODE_ADHOC; - } - else if (pAdapter->ScanTab.BssEntry[i].BssType == Ndis802_11Infrastructure) - { - iwe.u.mode = IW_MODE_INFRA; - } - else - { - iwe.u.mode = IW_MODE_AUTO; - } - iwe.len = IW_EV_UINT_LEN; - - previous_ev = current_ev; - current_ev = IWE_STREAM_ADD_EVENT(info, current_ev, end_buf, &iwe, IW_EV_UINT_LEN); - if (current_ev == previous_ev) -#if WIRELESS_EXT >= 17 - return -E2BIG; -#else - break; -#endif - - //Channel and Frequency - //================================ - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWFREQ; - if (INFRA_ON(pAdapter) || ADHOC_ON(pAdapter)) - iwe.u.freq.m = pAdapter->ScanTab.BssEntry[i].Channel; - else - iwe.u.freq.m = pAdapter->ScanTab.BssEntry[i].Channel; - iwe.u.freq.e = 0; - iwe.u.freq.i = 0; - - previous_ev = current_ev; - current_ev = IWE_STREAM_ADD_EVENT(info, current_ev,end_buf, &iwe, IW_EV_FREQ_LEN); - if (current_ev == previous_ev) -#if WIRELESS_EXT >= 17 - return -E2BIG; -#else - break; -#endif - - //Add quality statistics - //================================ - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = IWEVQUAL; - iwe.u.qual.level = 0; - iwe.u.qual.noise = 0; - set_quality(pAdapter, &iwe.u.qual, pAdapter->ScanTab.BssEntry[i].Rssi); - current_ev = IWE_STREAM_ADD_EVENT(info, current_ev, end_buf, &iwe, IW_EV_QUAL_LEN); - if (current_ev == previous_ev) -#if WIRELESS_EXT >= 17 - return -E2BIG; -#else - break; -#endif - - //Encyption key - //================================ - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWENCODE; - if (CAP_IS_PRIVACY_ON (pAdapter->ScanTab.BssEntry[i].CapabilityInfo )) - iwe.u.data.flags =IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; - else - iwe.u.data.flags = IW_ENCODE_DISABLED; - - previous_ev = current_ev; - current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf,&iwe, (char *)pAdapter->SharedKey[BSS0][(iwe.u.data.flags & IW_ENCODE_INDEX)-1].Key); - if (current_ev == previous_ev) -#if WIRELESS_EXT >= 17 - return -E2BIG; -#else - break; -#endif - - //Bit Rate - //================================ - if (pAdapter->ScanTab.BssEntry[i].SupRateLen) - { - UCHAR tmpRate = pAdapter->ScanTab.BssEntry[i].SupRate[pAdapter->ScanTab.BssEntry[i].SupRateLen-1]; - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWRATE; - current_val = current_ev + IW_EV_LCP_LEN; - if (tmpRate == 0x82) - iwe.u.bitrate.value = 1 * 1000000; - else if (tmpRate == 0x84) - iwe.u.bitrate.value = 2 * 1000000; - else if (tmpRate == 0x8B) - iwe.u.bitrate.value = 5.5 * 1000000; - else if (tmpRate == 0x96) - iwe.u.bitrate.value = 11 * 1000000; - else - iwe.u.bitrate.value = (tmpRate/2) * 1000000; - - iwe.u.bitrate.disabled = 0; - current_val = IWE_STREAM_ADD_VALUE(info, current_ev, - current_val, end_buf, &iwe, - IW_EV_PARAM_LEN); - - if((current_val-current_ev)>IW_EV_LCP_LEN) - current_ev = current_val; - else -#if WIRELESS_EXT >= 17 - return -E2BIG; -#else - break; -#endif - } - -#ifdef IWEVGENIE - //WPA IE - if (pAdapter->ScanTab.BssEntry[i].WpaIE.IELen > 0) - { - memset(&iwe, 0, sizeof(iwe)); - memset(&custom[0], 0, MAX_CUSTOM_LEN); - memcpy(custom, &(pAdapter->ScanTab.BssEntry[i].WpaIE.IE[0]), - pAdapter->ScanTab.BssEntry[i].WpaIE.IELen); - iwe.cmd = IWEVGENIE; - iwe.u.data.length = pAdapter->ScanTab.BssEntry[i].WpaIE.IELen; - current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe, custom); - if (current_ev == previous_ev) -#if WIRELESS_EXT >= 17 - return -E2BIG; -#else - break; -#endif - } - - //WPA2 IE - if (pAdapter->ScanTab.BssEntry[i].RsnIE.IELen > 0) - { - memset(&iwe, 0, sizeof(iwe)); - memset(&custom[0], 0, MAX_CUSTOM_LEN); - memcpy(custom, &(pAdapter->ScanTab.BssEntry[i].RsnIE.IE[0]), - pAdapter->ScanTab.BssEntry[i].RsnIE.IELen); - iwe.cmd = IWEVGENIE; - iwe.u.data.length = pAdapter->ScanTab.BssEntry[i].RsnIE.IELen; - current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe, custom); - if (current_ev == previous_ev) -#if WIRELESS_EXT >= 17 - return -E2BIG; -#else - break; -#endif - } -#else - //WPA IE - //================================ - if (pAdapter->ScanTab.BssEntry[i].WpaIE.IELen > 0) - { - NdisZeroMemory(&iwe, sizeof(iwe)); - memset(&custom[0], 0, MAX_CUSTOM_LEN); - iwe.cmd = IWEVCUSTOM; - iwe.u.data.length = (pAdapter->ScanTab.BssEntry[i].WpaIE.IELen * 2) + 7; - NdisMoveMemory(custom, "wpa_ie=", 7); - for (idx = 0; idx < pAdapter->ScanTab.BssEntry[i].WpaIE.IELen; idx++) - sprintf(custom, "%s%02x", custom, pAdapter->ScanTab.BssEntry[i].WpaIE.IE[idx]); - previous_ev = current_ev; - current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe, custom); - if (current_ev == previous_ev) -#if WIRELESS_EXT >= 17 - return -E2BIG; -#else - break; -#endif - } - - //WPA2 IE - if (pAdapter->ScanTab.BssEntry[i].RsnIE.IELen > 0) - { - NdisZeroMemory(&iwe, sizeof(iwe)); - memset(&custom[0], 0, MAX_CUSTOM_LEN); - iwe.cmd = IWEVCUSTOM; - iwe.u.data.length = (pAdapter->ScanTab.BssEntry[i].RsnIE.IELen * 2) + 7; - NdisMoveMemory(custom, "rsn_ie=", 7); - for (idx = 0; idx < pAdapter->ScanTab.BssEntry[i].RsnIE.IELen; idx++) - sprintf(custom, "%s%02x", custom, pAdapter->ScanTab.BssEntry[i].RsnIE.IE[idx]); - previous_ev = current_ev; - current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe, custom); - if (current_ev == previous_ev) -#if WIRELESS_EXT >= 17 - return -E2BIG; -#else - break; -#endif - } -#endif // IWEVGENIE // - } - - data->length = current_ev - extra; - pAdapter->StaCfg.bScanReqIsFromWebUI = FALSE; - DBGPRINT(RT_DEBUG_ERROR ,("===>rt_ioctl_giwscan. %d(%d) BSS returned, data->length = %d\n",i , pAdapter->ScanTab.BssNr, data->length)); - return 0; -} -#endif - -int rt_ioctl_siwessid(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *essid) -{ - PRTMP_ADAPTER pAdapter = dev->ml_priv; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - if (data->flags) - { - PCHAR pSsidString = NULL; - - // Includes null character. - if (data->length > (IW_ESSID_MAX_SIZE + 1)) - return -E2BIG; - - pSsidString = (CHAR *) kmalloc(MAX_LEN_OF_SSID+1, MEM_ALLOC_FLAG); - if (pSsidString) - { - NdisZeroMemory(pSsidString, MAX_LEN_OF_SSID+1); - NdisMoveMemory(pSsidString, essid, data->length); - if (Set_SSID_Proc(pAdapter, pSsidString) == FALSE) - return -EINVAL; - } - else - return -ENOMEM; - } - else - { - // ANY ssid - if (Set_SSID_Proc(pAdapter, "") == FALSE) - return -EINVAL; - } - return 0; -} - -int rt_ioctl_giwessid(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *essid) -{ - PRTMP_ADAPTER pAdapter = NULL; - VIRTUAL_ADAPTER *pVirtualAd = NULL; - - if (dev->priv_flags == INT_MAIN) - { - pAdapter = dev->ml_priv; - } - else - { - pVirtualAd = dev->ml_priv; - if (pVirtualAd && pVirtualAd->RtmpDev) - pAdapter = pVirtualAd->RtmpDev->ml_priv; - } - - if (pAdapter == NULL) - { - /* if 1st open fail, pAd will be free; - So the net_dev->ml_priv will be NULL in 2rd open */ - return -ENETDOWN; - } - - data->flags = 1; - if (MONITOR_ON(pAdapter)) - { - data->length = 0; - return 0; - } - - if (OPSTATUS_TEST_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED)) - { - DBGPRINT(RT_DEBUG_TRACE ,("MediaState is connected\n")); - data->length = pAdapter->CommonCfg.SsidLen; - memcpy(essid, pAdapter->CommonCfg.Ssid, pAdapter->CommonCfg.SsidLen); - } -#ifdef RT2870 -#ifdef WPA_SUPPLICANT_SUPPORT - // Add for RT2870 - else if (pAdapter->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_DISABLE) - { - data->length = pAdapter->CommonCfg.SsidLen; - memcpy(essid, pAdapter->CommonCfg.Ssid, pAdapter->CommonCfg.SsidLen); - } -#endif // WPA_SUPPLICANT_SUPPORT // -#endif // RT2870 // - else - {//the ANY ssid was specified - data->length = 0; - DBGPRINT(RT_DEBUG_TRACE ,("MediaState is not connected, ess\n")); - } - - return 0; - -} - -int rt_ioctl_siwnickn(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *nickname) -{ - PRTMP_ADAPTER pAdapter = dev->ml_priv; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE ,("INFO::Network is down!\n")); - return -ENETDOWN; - } - - if (data->length > IW_ESSID_MAX_SIZE) - return -EINVAL; - - memset(pAdapter->nickname, 0, IW_ESSID_MAX_SIZE + 1); - memcpy(pAdapter->nickname, nickname, data->length); - - - return 0; -} - -int rt_ioctl_giwnickn(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *nickname) -{ - PRTMP_ADAPTER pAdapter = NULL; - VIRTUAL_ADAPTER *pVirtualAd = NULL; - - if (dev->priv_flags == INT_MAIN) - { - pAdapter = dev->ml_priv; - } - else - { - pVirtualAd = dev->ml_priv; - if (pVirtualAd && pVirtualAd->RtmpDev) - pAdapter = pVirtualAd->RtmpDev->ml_priv; - } - - if (pAdapter == NULL) - { - /* if 1st open fail, pAd will be free; - So the net_dev->ml_priv will be NULL in 2rd open */ - return -ENETDOWN; - } - - if (data->length > strlen(pAdapter->nickname) + 1) - data->length = strlen(pAdapter->nickname) + 1; - if (data->length > 0) { - memcpy(nickname, pAdapter->nickname, data->length-1); - nickname[data->length-1] = '\0'; - } - return 0; -} - -int rt_ioctl_siwrts(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *rts, char *extra) -{ - PRTMP_ADAPTER pAdapter = dev->ml_priv; - u16 val; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - if (rts->disabled) - val = MAX_RTS_THRESHOLD; - else if (rts->value < 0 || rts->value > MAX_RTS_THRESHOLD) - return -EINVAL; - else if (rts->value == 0) - val = MAX_RTS_THRESHOLD; - else - val = rts->value; - - if (val != pAdapter->CommonCfg.RtsThreshold) - pAdapter->CommonCfg.RtsThreshold = val; - - return 0; -} - -int rt_ioctl_giwrts(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *rts, char *extra) -{ - PRTMP_ADAPTER pAdapter = NULL; - VIRTUAL_ADAPTER *pVirtualAd = NULL; - - if (dev->priv_flags == INT_MAIN) - { - pAdapter = dev->ml_priv; - } - else - { - pVirtualAd = dev->ml_priv; - if (pVirtualAd && pVirtualAd->RtmpDev) - pAdapter = pVirtualAd->RtmpDev->ml_priv; - } - - if (pAdapter == NULL) - { - /* if 1st open fail, pAd will be free; - So the net_dev->ml_priv will be NULL in 2rd open */ - return -ENETDOWN; - } - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - rts->value = pAdapter->CommonCfg.RtsThreshold; - rts->disabled = (rts->value == MAX_RTS_THRESHOLD); - rts->fixed = 1; - - return 0; -} - -int rt_ioctl_siwfrag(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *frag, char *extra) -{ - PRTMP_ADAPTER pAdapter = dev->ml_priv; - u16 val; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - if (frag->disabled) - val = MAX_FRAG_THRESHOLD; - else if (frag->value >= MIN_FRAG_THRESHOLD || frag->value <= MAX_FRAG_THRESHOLD) - val = __cpu_to_le16(frag->value & ~0x1); /* even numbers only */ - else if (frag->value == 0) - val = MAX_FRAG_THRESHOLD; - else - return -EINVAL; - - pAdapter->CommonCfg.FragmentThreshold = val; - return 0; -} - -int rt_ioctl_giwfrag(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *frag, char *extra) -{ - PRTMP_ADAPTER pAdapter = NULL; - VIRTUAL_ADAPTER *pVirtualAd = NULL; - - if (dev->priv_flags == INT_MAIN) - { - pAdapter = dev->ml_priv; - } - else - { - pVirtualAd = dev->ml_priv; - if (pVirtualAd && pVirtualAd->RtmpDev) - pAdapter = pVirtualAd->RtmpDev->ml_priv; - } - - if (pAdapter == NULL) - { - /* if 1st open fail, pAd will be free; - So the net_dev->ml_priv will be NULL in 2rd open */ - return -ENETDOWN; - } - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - frag->value = pAdapter->CommonCfg.FragmentThreshold; - frag->disabled = (frag->value == MAX_FRAG_THRESHOLD); - frag->fixed = 1; - - return 0; -} - -#define MAX_WEP_KEY_SIZE 13 -#define MIN_WEP_KEY_SIZE 5 -int rt_ioctl_siwencode(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *erq, char *extra) -{ - PRTMP_ADAPTER pAdapter = dev->ml_priv; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - if ((erq->length == 0) && - (erq->flags & IW_ENCODE_DISABLED)) - { - pAdapter->StaCfg.PairCipher = Ndis802_11WEPDisabled; - pAdapter->StaCfg.GroupCipher = Ndis802_11WEPDisabled; - pAdapter->StaCfg.WepStatus = Ndis802_11WEPDisabled; - pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; - goto done; - } - else if ((erq->length == 0) && - (erq->flags & IW_ENCODE_RESTRICTED || erq->flags & IW_ENCODE_OPEN)) - { - //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; - STA_PORT_SECURED(pAdapter); - pAdapter->StaCfg.PairCipher = Ndis802_11WEPEnabled; - pAdapter->StaCfg.GroupCipher = Ndis802_11WEPEnabled; - pAdapter->StaCfg.WepStatus = Ndis802_11WEPEnabled; - pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; - if (erq->flags & IW_ENCODE_RESTRICTED) - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeShared; - else - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; - goto done; - } - - if (erq->length > 0) - { - int keyIdx = (erq->flags & IW_ENCODE_INDEX) - 1; - /* Check the size of the key */ - if (erq->length > MAX_WEP_KEY_SIZE) { - return -EINVAL; - } - /* Check key index */ - if ((keyIdx < 0) || (keyIdx >= NR_WEP_KEYS)) - { - DBGPRINT(RT_DEBUG_TRACE ,("==>rt_ioctl_siwencode::Wrong keyIdx=%d! Using default key instead (%d)\n", - keyIdx, pAdapter->StaCfg.DefaultKeyId)); - - //Using default key - keyIdx = pAdapter->StaCfg.DefaultKeyId; - } - - NdisZeroMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, 16); - - if (erq->length == MAX_WEP_KEY_SIZE) - { - pAdapter->SharedKey[BSS0][keyIdx].KeyLen = MAX_WEP_KEY_SIZE; - pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CIPHER_WEP128; - } - else if (erq->length == MIN_WEP_KEY_SIZE) - { - pAdapter->SharedKey[BSS0][keyIdx].KeyLen = MIN_WEP_KEY_SIZE; - pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CIPHER_WEP64; - } - else - /* Disable the key */ - pAdapter->SharedKey[BSS0][keyIdx].KeyLen = 0; - - /* Check if the key is not marked as invalid */ - if(!(erq->flags & IW_ENCODE_NOKEY)) { - /* Copy the key in the driver */ - NdisMoveMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, extra, erq->length); - } - } - else - { - /* Do we want to just set the transmit key index ? */ - int index = (erq->flags & IW_ENCODE_INDEX) - 1; - if ((index >= 0) && (index < 4)) - { - pAdapter->StaCfg.DefaultKeyId = index; - } - else - /* Don't complain if only change the mode */ - if (!(erq->flags & IW_ENCODE_MODE)) { - return -EINVAL; - } - } - -done: - DBGPRINT(RT_DEBUG_TRACE ,("==>rt_ioctl_siwencode::erq->flags=%x\n",erq->flags)); - DBGPRINT(RT_DEBUG_TRACE ,("==>rt_ioctl_siwencode::AuthMode=%x\n",pAdapter->StaCfg.AuthMode)); - DBGPRINT(RT_DEBUG_TRACE ,("==>rt_ioctl_siwencode::DefaultKeyId=%x, KeyLen = %d\n",pAdapter->StaCfg.DefaultKeyId , pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen)); - DBGPRINT(RT_DEBUG_TRACE ,("==>rt_ioctl_siwencode::WepStatus=%x\n",pAdapter->StaCfg.WepStatus)); - return 0; -} - -int -rt_ioctl_giwencode(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *erq, char *key) -{ - int kid; - PRTMP_ADAPTER pAdapter = NULL; - VIRTUAL_ADAPTER *pVirtualAd = NULL; - - if (dev->priv_flags == INT_MAIN) - { - pAdapter = dev->ml_priv; - } - else - { - pVirtualAd = dev->ml_priv; - if (pVirtualAd && pVirtualAd->RtmpDev) - pAdapter = pVirtualAd->RtmpDev->ml_priv; - } - - if (pAdapter == NULL) - { - /* if 1st open fail, pAd will be free; - So the net_dev->ml_priv will be NULL in 2rd open */ - return -ENETDOWN; - } - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - kid = erq->flags & IW_ENCODE_INDEX; - DBGPRINT(RT_DEBUG_TRACE, ("===>rt_ioctl_giwencode %d\n", erq->flags & IW_ENCODE_INDEX)); - - if (pAdapter->StaCfg.WepStatus == Ndis802_11WEPDisabled) - { - erq->length = 0; - erq->flags = IW_ENCODE_DISABLED; - } - else if ((kid > 0) && (kid <=4)) - { - // copy wep key - erq->flags = kid ; /* NB: base 1 */ - if (erq->length > pAdapter->SharedKey[BSS0][kid-1].KeyLen) - erq->length = pAdapter->SharedKey[BSS0][kid-1].KeyLen; - memcpy(key, pAdapter->SharedKey[BSS0][kid-1].Key, erq->length); - //if ((kid == pAdapter->PortCfg.DefaultKeyId)) - //erq->flags |= IW_ENCODE_ENABLED; /* XXX */ - if (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeShared) - erq->flags |= IW_ENCODE_RESTRICTED; /* XXX */ - else - erq->flags |= IW_ENCODE_OPEN; /* XXX */ - - } - else if (kid == 0) - { - if (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeShared) - erq->flags |= IW_ENCODE_RESTRICTED; /* XXX */ - else - erq->flags |= IW_ENCODE_OPEN; /* XXX */ - erq->length = pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen; - memcpy(key, pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].Key, erq->length); - // copy default key ID - if (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeShared) - erq->flags |= IW_ENCODE_RESTRICTED; /* XXX */ - else - erq->flags |= IW_ENCODE_OPEN; /* XXX */ - erq->flags = pAdapter->StaCfg.DefaultKeyId + 1; /* NB: base 1 */ - erq->flags |= IW_ENCODE_ENABLED; /* XXX */ - } - - return 0; - -} - -static int -rt_ioctl_setparam(struct net_device *dev, struct iw_request_info *info, - void *w, char *extra) -{ - VIRTUAL_ADAPTER *pVirtualAd = NULL; - PRTMP_ADAPTER pAdapter; - POS_COOKIE pObj; - char *this_char = extra; - char *value; - int Status=0; - - if (dev->priv_flags == INT_MAIN) - { - pAdapter = dev->ml_priv; - } - else - { - pVirtualAd = dev->ml_priv; - pAdapter = pVirtualAd->RtmpDev->ml_priv; - } - pObj = (POS_COOKIE) pAdapter->OS_Cookie; - - if (pAdapter == NULL) - { - /* if 1st open fail, pAd will be free; - So the net_dev->ml_priv will be NULL in 2rd open */ - return -ENETDOWN; - } - - { - pObj->ioctl_if_type = INT_MAIN; - pObj->ioctl_if = MAIN_MBSSID; - } - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - if (!*this_char) - return -EINVAL; - - if ((value = rtstrchr(this_char, '=')) != NULL) - *value++ = 0; - - if (!value) - return -EINVAL; - - // reject setting nothing besides ANY ssid(ssidLen=0) - if (!*value && (strcmp(this_char, "SSID") != 0)) - return -EINVAL; - - for (PRTMP_PRIVATE_SET_PROC = RTMP_PRIVATE_SUPPORT_PROC; PRTMP_PRIVATE_SET_PROC->name; PRTMP_PRIVATE_SET_PROC++) - { - if (strcmp(this_char, PRTMP_PRIVATE_SET_PROC->name) == 0) - { - if(!PRTMP_PRIVATE_SET_PROC->set_proc(pAdapter, value)) - { //FALSE:Set private failed then return Invalid argument - Status = -EINVAL; - } - break; //Exit for loop. - } - } - - if(PRTMP_PRIVATE_SET_PROC->name == NULL) - { //Not found argument - Status = -EINVAL; - DBGPRINT(RT_DEBUG_TRACE, ("===>rt_ioctl_setparam:: (iwpriv) Not Support Set Command [%s=%s]\n", this_char, value)); - } - - return Status; -} - - -static int -rt_private_get_statistics(struct net_device *dev, struct iw_request_info *info, - struct iw_point *wrq, char *extra) -{ - INT Status = 0; - PRTMP_ADAPTER pAd = dev->ml_priv; - - if (extra == NULL) - { - wrq->length = 0; - return -EIO; - } - - memset(extra, 0x00, IW_PRIV_SIZE_MASK); - sprintf(extra, "\n\n"); - -#ifdef RALINK_ATE - if (ATE_ON(pAd)) - { - sprintf(extra+strlen(extra), "Tx success = %ld\n", (ULONG)pAd->ate.TxDoneCount); - //sprintf(extra+strlen(extra), "Tx success without retry = %ld\n", (ULONG)pAd->ate.TxDoneCount); - } - else -#endif // RALINK_ATE // - { - sprintf(extra+strlen(extra), "Tx success = %ld\n", (ULONG)pAd->WlanCounters.TransmittedFragmentCount.QuadPart); - sprintf(extra+strlen(extra), "Tx success without retry = %ld\n", (ULONG)pAd->WlanCounters.TransmittedFragmentCount.QuadPart - (ULONG)pAd->WlanCounters.RetryCount.QuadPart); - } - sprintf(extra+strlen(extra), "Tx success after retry = %ld\n", (ULONG)pAd->WlanCounters.RetryCount.QuadPart); - sprintf(extra+strlen(extra), "Tx fail to Rcv ACK after retry = %ld\n", (ULONG)pAd->WlanCounters.FailedCount.QuadPart); - sprintf(extra+strlen(extra), "RTS Success Rcv CTS = %ld\n", (ULONG)pAd->WlanCounters.RTSSuccessCount.QuadPart); - sprintf(extra+strlen(extra), "RTS Fail Rcv CTS = %ld\n", (ULONG)pAd->WlanCounters.RTSFailureCount.QuadPart); - - sprintf(extra+strlen(extra), "Rx success = %ld\n", (ULONG)pAd->WlanCounters.ReceivedFragmentCount.QuadPart); - sprintf(extra+strlen(extra), "Rx with CRC = %ld\n", (ULONG)pAd->WlanCounters.FCSErrorCount.QuadPart); - sprintf(extra+strlen(extra), "Rx drop due to out of resource = %ld\n", (ULONG)pAd->Counters8023.RxNoBuffer); - sprintf(extra+strlen(extra), "Rx duplicate frame = %ld\n", (ULONG)pAd->WlanCounters.FrameDuplicateCount.QuadPart); - - sprintf(extra+strlen(extra), "False CCA (one second) = %ld\n", (ULONG)pAd->RalinkCounters.OneSecFalseCCACnt); -#ifdef RALINK_ATE - if (ATE_ON(pAd)) - { - if (pAd->ate.RxAntennaSel == 0) - { - sprintf(extra+strlen(extra), "RSSI-A = %ld\n", (LONG)(pAd->ate.LastRssi0 - pAd->BbpRssiToDbmDelta)); - sprintf(extra+strlen(extra), "RSSI-B (if available) = %ld\n", (LONG)(pAd->ate.LastRssi1 - pAd->BbpRssiToDbmDelta)); - sprintf(extra+strlen(extra), "RSSI-C (if available) = %ld\n\n", (LONG)(pAd->ate.LastRssi2 - pAd->BbpRssiToDbmDelta)); - } - else - { - sprintf(extra+strlen(extra), "RSSI = %ld\n", (LONG)(pAd->ate.LastRssi0 - pAd->BbpRssiToDbmDelta)); - } - } - else -#endif // RALINK_ATE // - { - sprintf(extra+strlen(extra), "RSSI-A = %ld\n", (LONG)(pAd->StaCfg.RssiSample.LastRssi0 - pAd->BbpRssiToDbmDelta)); - sprintf(extra+strlen(extra), "RSSI-B (if available) = %ld\n", (LONG)(pAd->StaCfg.RssiSample.LastRssi1 - pAd->BbpRssiToDbmDelta)); - sprintf(extra+strlen(extra), "RSSI-C (if available) = %ld\n\n", (LONG)(pAd->StaCfg.RssiSample.LastRssi2 - pAd->BbpRssiToDbmDelta)); - } -#ifdef WPA_SUPPLICANT_SUPPORT - sprintf(extra+strlen(extra), "WpaSupplicantUP = %d\n\n", pAd->StaCfg.WpaSupplicantUP); -#endif // WPA_SUPPLICANT_SUPPORT // - - - wrq->length = strlen(extra) + 1; // 1: size of '\0' - DBGPRINT(RT_DEBUG_TRACE, ("<== rt_private_get_statistics, wrq->length = %d\n", wrq->length)); - - return Status; -} - -#ifdef DOT11_N_SUPPORT -void getBaInfo( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pOutBuf) -{ - INT i, j; - BA_ORI_ENTRY *pOriBAEntry; - BA_REC_ENTRY *pRecBAEntry; - - for (i=0; iMacTab.Content[i]; - if (((pEntry->ValidAsCLI || pEntry->ValidAsApCli) && (pEntry->Sst == SST_ASSOC)) - || (pEntry->ValidAsWDS) || (pEntry->ValidAsMesh)) - { - sprintf(pOutBuf, "%s\n%02X:%02X:%02X:%02X:%02X:%02X (Aid = %d) (AP) -\n", - pOutBuf, - pEntry->Addr[0], pEntry->Addr[1], pEntry->Addr[2], - pEntry->Addr[3], pEntry->Addr[4], pEntry->Addr[5], pEntry->Aid); - - sprintf(pOutBuf, "%s[Recipient]\n", pOutBuf); - for (j=0; j < NUM_OF_TID; j++) - { - if (pEntry->BARecWcidArray[j] != 0) - { - pRecBAEntry =&pAd->BATable.BARecEntry[pEntry->BARecWcidArray[j]]; - sprintf(pOutBuf, "%sTID=%d, BAWinSize=%d, LastIndSeq=%d, ReorderingPkts=%d\n", pOutBuf, j, pRecBAEntry->BAWinSize, pRecBAEntry->LastIndSeq, pRecBAEntry->list.qlen); - } - } - sprintf(pOutBuf, "%s\n", pOutBuf); - - sprintf(pOutBuf, "%s[Originator]\n", pOutBuf); - for (j=0; j < NUM_OF_TID; j++) - { - if (pEntry->BAOriWcidArray[j] != 0) - { - pOriBAEntry =&pAd->BATable.BAOriEntry[pEntry->BAOriWcidArray[j]]; - sprintf(pOutBuf, "%sTID=%d, BAWinSize=%d, StartSeq=%d, CurTxSeq=%d\n", pOutBuf, j, pOriBAEntry->BAWinSize, pOriBAEntry->Sequence, pEntry->TxSeq[j]); - } - } - sprintf(pOutBuf, "%s\n\n", pOutBuf); - } - if (strlen(pOutBuf) > (IW_PRIV_SIZE_MASK - 30)) - break; - } - - return; -} -#endif // DOT11_N_SUPPORT // - -static int -rt_private_show(struct net_device *dev, struct iw_request_info *info, - struct iw_point *wrq, char *extra) -{ - INT Status = 0; - VIRTUAL_ADAPTER *pVirtualAd = NULL; - PRTMP_ADAPTER pAd; - POS_COOKIE pObj; - u32 subcmd = wrq->flags; - - if (dev->priv_flags == INT_MAIN) - pAd = dev->ml_priv; - else - { - pVirtualAd = dev->ml_priv; - pAd = pVirtualAd->RtmpDev->ml_priv; - } - pObj = (POS_COOKIE) pAd->OS_Cookie; - - if (pAd == NULL) - { - /* if 1st open fail, pAd will be free; - So the net_dev->ml_priv will be NULL in 2rd open */ - return -ENETDOWN; - } - - if (extra == NULL) - { - wrq->length = 0; - return -EIO; - } - memset(extra, 0x00, IW_PRIV_SIZE_MASK); - - { - pObj->ioctl_if_type = INT_MAIN; - pObj->ioctl_if = MAIN_MBSSID; - } - - switch(subcmd) - { - - case SHOW_CONN_STATUS: - if (MONITOR_ON(pAd)) - { -#ifdef DOT11_N_SUPPORT - if (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED && - pAd->CommonCfg.RegTransmitSetting.field.BW) - sprintf(extra, "Monitor Mode(CentralChannel %d)\n", pAd->CommonCfg.CentralChannel); - else -#endif // DOT11_N_SUPPORT // - sprintf(extra, "Monitor Mode(Channel %d)\n", pAd->CommonCfg.Channel); - } - else - { - if (pAd->IndicateMediaState == NdisMediaStateConnected) - { - if (INFRA_ON(pAd)) - { - sprintf(extra, "Connected(AP: %s[%02X:%02X:%02X:%02X:%02X:%02X])\n", - pAd->CommonCfg.Ssid, - pAd->CommonCfg.Bssid[0], - pAd->CommonCfg.Bssid[1], - pAd->CommonCfg.Bssid[2], - pAd->CommonCfg.Bssid[3], - pAd->CommonCfg.Bssid[4], - pAd->CommonCfg.Bssid[5]); - DBGPRINT(RT_DEBUG_TRACE ,("Ssid=%s ,Ssidlen = %d\n",pAd->CommonCfg.Ssid, pAd->CommonCfg.SsidLen)); - } - else if (ADHOC_ON(pAd)) - sprintf(extra, "Connected\n"); - } - else - { - sprintf(extra, "Disconnected\n"); - DBGPRINT(RT_DEBUG_TRACE ,("ConnStatus is not connected\n")); - } - } - wrq->length = strlen(extra) + 1; // 1: size of '\0' - break; - case SHOW_DRVIER_VERION: - sprintf(extra, "Driver version-%s, %s %s\n", STA_DRIVER_VERSION, __DATE__, __TIME__ ); - wrq->length = strlen(extra) + 1; // 1: size of '\0' - break; -#ifdef DOT11_N_SUPPORT - case SHOW_BA_INFO: - getBaInfo(pAd, extra); - wrq->length = strlen(extra) + 1; // 1: size of '\0' - break; -#endif // DOT11_N_SUPPORT // - case SHOW_DESC_INFO: - { - Show_DescInfo_Proc(pAd, NULL); - wrq->length = 0; // 1: size of '\0' - } - break; - case RAIO_OFF: - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) - { - sprintf(extra, "Scanning\n"); - wrq->length = strlen(extra) + 1; // 1: size of '\0' - break; - } - pAd->StaCfg.bSwRadio = FALSE; - if (pAd->StaCfg.bRadio != (pAd->StaCfg.bHwRadio && pAd->StaCfg.bSwRadio)) - { - pAd->StaCfg.bRadio = (pAd->StaCfg.bHwRadio && pAd->StaCfg.bSwRadio); - if (pAd->StaCfg.bRadio == FALSE) - { - MlmeRadioOff(pAd); - // Update extra information - pAd->ExtraInfo = SW_RADIO_OFF; - } - } - sprintf(extra, "Radio Off\n"); - wrq->length = strlen(extra) + 1; // 1: size of '\0' - break; - case RAIO_ON: - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) - { - sprintf(extra, "Scanning\n"); - wrq->length = strlen(extra) + 1; // 1: size of '\0' - break; - } - pAd->StaCfg.bSwRadio = TRUE; - //if (pAd->StaCfg.bRadio != (pAd->StaCfg.bHwRadio && pAd->StaCfg.bSwRadio)) - { - pAd->StaCfg.bRadio = (pAd->StaCfg.bHwRadio && pAd->StaCfg.bSwRadio); - if (pAd->StaCfg.bRadio == TRUE) - { - MlmeRadioOn(pAd); - // Update extra information - pAd->ExtraInfo = EXTRA_INFO_CLEAR; - } - } - sprintf(extra, "Radio On\n"); - wrq->length = strlen(extra) + 1; // 1: size of '\0' - break; - - -#ifdef QOS_DLS_SUPPORT - case SHOW_DLS_ENTRY_INFO: - { - Set_DlsEntryInfo_Display_Proc(pAd, NULL); - wrq->length = 0; // 1: size of '\0' - } - break; -#endif // QOS_DLS_SUPPORT // - - case SHOW_CFG_VALUE: - { - Status = RTMPShowCfgValue(pAd, wrq->pointer, extra); - if (Status == 0) - wrq->length = strlen(extra) + 1; // 1: size of '\0' - } - break; - case SHOW_ADHOC_ENTRY_INFO: - Show_Adhoc_MacTable_Proc(pAd, extra); - wrq->length = strlen(extra) + 1; // 1: size of '\0' - break; - default: - DBGPRINT(RT_DEBUG_TRACE, ("%s - unknow subcmd = %d\n", __func__, subcmd)); - break; - } - - return Status; -} - -#ifdef SIOCSIWMLME -int rt_ioctl_siwmlme(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - PRTMP_ADAPTER pAd = dev->ml_priv; - struct iw_mlme *pMlme = (struct iw_mlme *)wrqu->data.pointer; - MLME_QUEUE_ELEM MsgElem; - MLME_DISASSOC_REQ_STRUCT DisAssocReq; - MLME_DEAUTH_REQ_STRUCT DeAuthReq; - - DBGPRINT(RT_DEBUG_TRACE, ("====> %s\n", __func__)); - - if (pMlme == NULL) - return -EINVAL; - - switch(pMlme->cmd) - { -#ifdef IW_MLME_DEAUTH - case IW_MLME_DEAUTH: - DBGPRINT(RT_DEBUG_TRACE, ("====> %s - IW_MLME_DEAUTH\n", __func__)); - COPY_MAC_ADDR(DeAuthReq.Addr, pAd->CommonCfg.Bssid); - DeAuthReq.Reason = pMlme->reason_code; - MsgElem.MsgLen = sizeof(MLME_DEAUTH_REQ_STRUCT); - NdisMoveMemory(MsgElem.Msg, &DeAuthReq, sizeof(MLME_DEAUTH_REQ_STRUCT)); - MlmeDeauthReqAction(pAd, &MsgElem); - if (INFRA_ON(pAd)) - { - LinkDown(pAd, FALSE); - pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; - } - break; -#endif // IW_MLME_DEAUTH // -#ifdef IW_MLME_DISASSOC - case IW_MLME_DISASSOC: - DBGPRINT(RT_DEBUG_TRACE, ("====> %s - IW_MLME_DISASSOC\n", __func__)); - COPY_MAC_ADDR(DisAssocReq.Addr, pAd->CommonCfg.Bssid); - DisAssocReq.Reason = pMlme->reason_code; - - MsgElem.Machine = ASSOC_STATE_MACHINE; - MsgElem.MsgType = MT2_MLME_DISASSOC_REQ; - MsgElem.MsgLen = sizeof(MLME_DISASSOC_REQ_STRUCT); - NdisMoveMemory(MsgElem.Msg, &DisAssocReq, sizeof(MLME_DISASSOC_REQ_STRUCT)); - - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_DISASSOC; - MlmeDisassocReqAction(pAd, &MsgElem); - break; -#endif // IW_MLME_DISASSOC // - default: - DBGPRINT(RT_DEBUG_TRACE, ("====> %s - Unknow Command\n", __func__)); - break; - } - - return 0; -} -#endif // SIOCSIWMLME // - -#if WIRELESS_EXT > 17 -int rt_ioctl_siwauth(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - PRTMP_ADAPTER pAdapter = dev->ml_priv; - struct iw_param *param = &wrqu->param; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - switch (param->flags & IW_AUTH_INDEX) { - case IW_AUTH_WPA_VERSION: - if (param->value == IW_AUTH_WPA_VERSION_WPA) - { - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPAPSK; - if (pAdapter->StaCfg.BssType == BSS_ADHOC) - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPANone; - } - else if (param->value == IW_AUTH_WPA_VERSION_WPA2) - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA2PSK; - - DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_VERSION - param->value = %d!\n", __func__, param->value)); - break; - case IW_AUTH_CIPHER_PAIRWISE: - if (param->value == IW_AUTH_CIPHER_NONE) - { - pAdapter->StaCfg.WepStatus = Ndis802_11WEPDisabled; - pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; - pAdapter->StaCfg.PairCipher = Ndis802_11WEPDisabled; - } - else if (param->value == IW_AUTH_CIPHER_WEP40 || - param->value == IW_AUTH_CIPHER_WEP104) - { - pAdapter->StaCfg.WepStatus = Ndis802_11WEPEnabled; - pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; - pAdapter->StaCfg.PairCipher = Ndis802_11WEPEnabled; -#ifdef WPA_SUPPLICANT_SUPPORT - pAdapter->StaCfg.IEEE8021X = FALSE; -#endif // WPA_SUPPLICANT_SUPPORT // - } - else if (param->value == IW_AUTH_CIPHER_TKIP) - { - pAdapter->StaCfg.WepStatus = Ndis802_11Encryption2Enabled; - pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; - pAdapter->StaCfg.PairCipher = Ndis802_11Encryption2Enabled; - } - else if (param->value == IW_AUTH_CIPHER_CCMP) - { - pAdapter->StaCfg.WepStatus = Ndis802_11Encryption3Enabled; - pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; - pAdapter->StaCfg.PairCipher = Ndis802_11Encryption3Enabled; - } - DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_CIPHER_PAIRWISE - param->value = %d!\n", __func__, param->value)); - break; - case IW_AUTH_CIPHER_GROUP: - if (param->value == IW_AUTH_CIPHER_NONE) - { - pAdapter->StaCfg.GroupCipher = Ndis802_11WEPDisabled; - } - else if (param->value == IW_AUTH_CIPHER_WEP40 || - param->value == IW_AUTH_CIPHER_WEP104) - { - pAdapter->StaCfg.GroupCipher = Ndis802_11WEPEnabled; - } - else if (param->value == IW_AUTH_CIPHER_TKIP) - { - pAdapter->StaCfg.GroupCipher = Ndis802_11Encryption2Enabled; - } - else if (param->value == IW_AUTH_CIPHER_CCMP) - { - pAdapter->StaCfg.GroupCipher = Ndis802_11Encryption3Enabled; - } - DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_CIPHER_GROUP - param->value = %d!\n", __func__, param->value)); - break; - case IW_AUTH_KEY_MGMT: - if (param->value == IW_AUTH_KEY_MGMT_802_1X) - { - if (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) - { - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA; -#ifdef WPA_SUPPLICANT_SUPPORT - pAdapter->StaCfg.IEEE8021X = FALSE; -#endif // WPA_SUPPLICANT_SUPPORT // - } - else if (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) - { - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA2; -#ifdef WPA_SUPPLICANT_SUPPORT - pAdapter->StaCfg.IEEE8021X = FALSE; -#endif // WPA_SUPPLICANT_SUPPORT // - } -#ifdef WPA_SUPPLICANT_SUPPORT - else - // WEP 1x - pAdapter->StaCfg.IEEE8021X = TRUE; -#endif // WPA_SUPPLICANT_SUPPORT // - } - else if (param->value == 0) - { - //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; - STA_PORT_SECURED(pAdapter); - } - DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_KEY_MGMT - param->value = %d!\n", __func__, param->value)); - break; - case IW_AUTH_RX_UNENCRYPTED_EAPOL: - break; - case IW_AUTH_PRIVACY_INVOKED: - /*if (param->value == 0) - { - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; - pAdapter->StaCfg.WepStatus = Ndis802_11WEPDisabled; - pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; - pAdapter->StaCfg.PairCipher = Ndis802_11WEPDisabled; - pAdapter->StaCfg.GroupCipher = Ndis802_11WEPDisabled; - }*/ - DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_PRIVACY_INVOKED - param->value = %d!\n", __func__, param->value)); - break; - case IW_AUTH_DROP_UNENCRYPTED: - if (param->value != 0) - pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; - else - { - //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; - STA_PORT_SECURED(pAdapter); - } - DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_VERSION - param->value = %d!\n", __func__, param->value)); - break; - case IW_AUTH_80211_AUTH_ALG: - if (param->value & IW_AUTH_ALG_SHARED_KEY) - { - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeShared; - } - else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) - { - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; - } - else - return -EINVAL; - DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_80211_AUTH_ALG - param->value = %d!\n", __func__, param->value)); - break; - case IW_AUTH_WPA_ENABLED: - DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_ENABLED - Driver supports WPA!(param->value = %d)\n", __func__, param->value)); - break; - default: - return -EOPNOTSUPP; -} - - return 0; -} - -int rt_ioctl_giwauth(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - PRTMP_ADAPTER pAdapter = dev->ml_priv; - struct iw_param *param = &wrqu->param; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - switch (param->flags & IW_AUTH_INDEX) { - case IW_AUTH_DROP_UNENCRYPTED: - param->value = (pAdapter->StaCfg.WepStatus == Ndis802_11WEPDisabled) ? 0 : 1; - break; - - case IW_AUTH_80211_AUTH_ALG: - param->value = (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeShared) ? IW_AUTH_ALG_SHARED_KEY : IW_AUTH_ALG_OPEN_SYSTEM; - break; - - case IW_AUTH_WPA_ENABLED: - param->value = (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ? 1 : 0; - break; - - default: - return -EOPNOTSUPP; - } - DBGPRINT(RT_DEBUG_TRACE, ("rt_ioctl_giwauth::param->value = %d!\n", param->value)); - return 0; -} - -void fnSetCipherKey( - IN PRTMP_ADAPTER pAdapter, - IN INT keyIdx, - IN UCHAR CipherAlg, - IN BOOLEAN bGTK, - IN struct iw_encode_ext *ext) -{ - NdisZeroMemory(&pAdapter->SharedKey[BSS0][keyIdx], sizeof(CIPHER_KEY)); - pAdapter->SharedKey[BSS0][keyIdx].KeyLen = LEN_TKIP_EK; - NdisMoveMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, ext->key, LEN_TKIP_EK); - NdisMoveMemory(pAdapter->SharedKey[BSS0][keyIdx].TxMic, ext->key + LEN_TKIP_EK, LEN_TKIP_TXMICK); - NdisMoveMemory(pAdapter->SharedKey[BSS0][keyIdx].RxMic, ext->key + LEN_TKIP_EK + LEN_TKIP_TXMICK, LEN_TKIP_RXMICK); - pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CipherAlg; - - // Update group key information to ASIC Shared Key Table - AsicAddSharedKeyEntry(pAdapter, - BSS0, - keyIdx, - pAdapter->SharedKey[BSS0][keyIdx].CipherAlg, - pAdapter->SharedKey[BSS0][keyIdx].Key, - pAdapter->SharedKey[BSS0][keyIdx].TxMic, - pAdapter->SharedKey[BSS0][keyIdx].RxMic); - - if (bGTK) - // Update ASIC WCID attribute table and IVEIV table - RTMPAddWcidAttributeEntry(pAdapter, - BSS0, - keyIdx, - pAdapter->SharedKey[BSS0][keyIdx].CipherAlg, - NULL); - else - // Update ASIC WCID attribute table and IVEIV table - RTMPAddWcidAttributeEntry(pAdapter, - BSS0, - keyIdx, - pAdapter->SharedKey[BSS0][keyIdx].CipherAlg, - &pAdapter->MacTab.Content[BSSID_WCID]); -} - -int rt_ioctl_siwencodeext(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) - { - PRTMP_ADAPTER pAdapter = dev->ml_priv; - struct iw_point *encoding = &wrqu->encoding; - struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; - int keyIdx, alg = ext->alg; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - if (encoding->flags & IW_ENCODE_DISABLED) - { - keyIdx = (encoding->flags & IW_ENCODE_INDEX) - 1; - // set BSSID wcid entry of the Pair-wise Key table as no-security mode - AsicRemovePairwiseKeyEntry(pAdapter, BSS0, BSSID_WCID); - pAdapter->SharedKey[BSS0][keyIdx].KeyLen = 0; - pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CIPHER_NONE; - AsicRemoveSharedKeyEntry(pAdapter, 0, (UCHAR)keyIdx); - NdisZeroMemory(&pAdapter->SharedKey[BSS0][keyIdx], sizeof(CIPHER_KEY)); - DBGPRINT(RT_DEBUG_TRACE, ("%s::Remove all keys!(encoding->flags = %x)\n", __func__, encoding->flags)); - } - else - { - // Get Key Index and convet to our own defined key index - keyIdx = (encoding->flags & IW_ENCODE_INDEX) - 1; - if((keyIdx < 0) || (keyIdx >= NR_WEP_KEYS)) - return -EINVAL; - - if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) - { - pAdapter->StaCfg.DefaultKeyId = keyIdx; - DBGPRINT(RT_DEBUG_TRACE, ("%s::DefaultKeyId = %d\n", __func__, pAdapter->StaCfg.DefaultKeyId)); - } - - switch (alg) { - case IW_ENCODE_ALG_NONE: - DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_NONE\n", __func__)); - break; - case IW_ENCODE_ALG_WEP: - DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_WEP - ext->key_len = %d, keyIdx = %d\n", __func__, ext->key_len, keyIdx)); - if (ext->key_len == MAX_WEP_KEY_SIZE) - { - pAdapter->SharedKey[BSS0][keyIdx].KeyLen = MAX_WEP_KEY_SIZE; - pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CIPHER_WEP128; - } - else if (ext->key_len == MIN_WEP_KEY_SIZE) - { - pAdapter->SharedKey[BSS0][keyIdx].KeyLen = MIN_WEP_KEY_SIZE; - pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CIPHER_WEP64; - } - else - return -EINVAL; - - NdisZeroMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, 16); - NdisMoveMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, ext->key, ext->key_len); - - if (pAdapter->StaCfg.GroupCipher == Ndis802_11GroupWEP40Enabled || - pAdapter->StaCfg.GroupCipher == Ndis802_11GroupWEP104Enabled) - { - // Set Group key material to Asic - AsicAddSharedKeyEntry(pAdapter, BSS0, keyIdx, pAdapter->SharedKey[BSS0][keyIdx].CipherAlg, pAdapter->SharedKey[BSS0][keyIdx].Key, NULL, NULL); - - // Update WCID attribute table and IVEIV table for this group key table - RTMPAddWcidAttributeEntry(pAdapter, BSS0, keyIdx, pAdapter->SharedKey[BSS0][keyIdx].CipherAlg, NULL); - - STA_PORT_SECURED(pAdapter); - - // Indicate Connected for GUI - pAdapter->IndicateMediaState = NdisMediaStateConnected; - } - break; - case IW_ENCODE_ALG_TKIP: - DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_TKIP - keyIdx = %d, ext->key_len = %d\n", __func__, keyIdx, ext->key_len)); - if (ext->key_len == 32) - { - if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) - { - fnSetCipherKey(pAdapter, keyIdx, CIPHER_TKIP, FALSE, ext); - if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA2) - { - //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; - STA_PORT_SECURED(pAdapter); - } - } - else if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) - { - fnSetCipherKey(pAdapter, keyIdx, CIPHER_TKIP, TRUE, ext); - - // set 802.1x port control - //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; - STA_PORT_SECURED(pAdapter); - } - } - else - return -EINVAL; - break; - case IW_ENCODE_ALG_CCMP: - if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) - { - fnSetCipherKey(pAdapter, keyIdx, CIPHER_AES, FALSE, ext); - if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA2) - //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; - STA_PORT_SECURED(pAdapter); - } - else if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) - { - fnSetCipherKey(pAdapter, keyIdx, CIPHER_AES, TRUE, ext); - - // set 802.1x port control - //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; - STA_PORT_SECURED(pAdapter); - } - break; - default: - return -EINVAL; - } - } - - return 0; -} - -int -rt_ioctl_giwencodeext(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - PRTMP_ADAPTER pAd = dev->ml_priv; - PCHAR pKey = NULL; - struct iw_point *encoding = &wrqu->encoding; - struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; - int idx, max_key_len; - - DBGPRINT(RT_DEBUG_TRACE ,("===> rt_ioctl_giwencodeext\n")); - - max_key_len = encoding->length - sizeof(*ext); - if (max_key_len < 0) - return -EINVAL; - - idx = encoding->flags & IW_ENCODE_INDEX; - if (idx) - { - if (idx < 1 || idx > 4) - return -EINVAL; - idx--; - - if ((pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) || - (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled)) - { - if (idx != pAd->StaCfg.DefaultKeyId) - { - ext->key_len = 0; - return 0; - } - } - } - else - idx = pAd->StaCfg.DefaultKeyId; - - encoding->flags = idx + 1; - memset(ext, 0, sizeof(*ext)); - - ext->key_len = 0; - switch(pAd->StaCfg.WepStatus) { - case Ndis802_11WEPDisabled: - ext->alg = IW_ENCODE_ALG_NONE; - encoding->flags |= IW_ENCODE_DISABLED; - break; - case Ndis802_11WEPEnabled: - ext->alg = IW_ENCODE_ALG_WEP; - if (pAd->SharedKey[BSS0][idx].KeyLen > max_key_len) - return -E2BIG; - else - { - ext->key_len = pAd->SharedKey[BSS0][idx].KeyLen; - pKey = &(pAd->SharedKey[BSS0][idx].Key[0]); - } - break; - case Ndis802_11Encryption2Enabled: - case Ndis802_11Encryption3Enabled: - if (pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) - ext->alg = IW_ENCODE_ALG_TKIP; - else - ext->alg = IW_ENCODE_ALG_CCMP; - - if (max_key_len < 32) - return -E2BIG; - else - { - ext->key_len = 32; - pKey = &pAd->StaCfg.PMK[0]; - } - break; - default: - return -EINVAL; - } - - if (ext->key_len && pKey) - { - encoding->flags |= IW_ENCODE_ENABLED; - memcpy(ext->key, pKey, ext->key_len); - } - - return 0; -} - -#ifdef SIOCSIWGENIE -int rt_ioctl_siwgenie(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - PRTMP_ADAPTER pAd = dev->ml_priv; - - if (wrqu->data.length > MAX_LEN_OF_RSNIE || - (wrqu->data.length && extra == NULL)) - return -EINVAL; - - if (wrqu->data.length) - { - pAd->StaCfg.RSNIE_Len = wrqu->data.length; - NdisMoveMemory(&pAd->StaCfg.RSN_IE[0], extra, pAd->StaCfg.RSNIE_Len); - } - else - { - pAd->StaCfg.RSNIE_Len = 0; - NdisZeroMemory(&pAd->StaCfg.RSN_IE[0], MAX_LEN_OF_RSNIE); - } - - return 0; -} -#endif // SIOCSIWGENIE // - -int rt_ioctl_giwgenie(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - PRTMP_ADAPTER pAd = dev->ml_priv; - - if ((pAd->StaCfg.RSNIE_Len == 0) || - (pAd->StaCfg.AuthMode < Ndis802_11AuthModeWPA)) - { - wrqu->data.length = 0; - return 0; - } - -#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT -#ifdef SIOCSIWGENIE - if (pAd->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_ENABLE) - { - if (wrqu->data.length < pAd->StaCfg.RSNIE_Len) - return -E2BIG; - - wrqu->data.length = pAd->StaCfg.RSNIE_Len; - memcpy(extra, &pAd->StaCfg.RSN_IE[0], pAd->StaCfg.RSNIE_Len); - } - else -#endif // SIOCSIWGENIE // -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // - { - UCHAR RSNIe = IE_WPA; - - if (wrqu->data.length < (pAd->StaCfg.RSNIE_Len + 2)) // ID, Len - return -E2BIG; - wrqu->data.length = pAd->StaCfg.RSNIE_Len + 2; - - if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) || - (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2)) - RSNIe = IE_RSN; - - extra[0] = (char)RSNIe; - extra[1] = pAd->StaCfg.RSNIE_Len; - memcpy(extra+2, &pAd->StaCfg.RSN_IE[0], pAd->StaCfg.RSNIE_Len); - } - - return 0; -} - -int rt_ioctl_siwpmksa(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - PRTMP_ADAPTER pAd = dev->ml_priv; - struct iw_pmksa *pPmksa = (struct iw_pmksa *)wrqu->data.pointer; - INT CachedIdx = 0, idx = 0; - - if (pPmksa == NULL) - return -EINVAL; - - DBGPRINT(RT_DEBUG_TRACE ,("===> rt_ioctl_siwpmksa\n")); - switch(pPmksa->cmd) - { - case IW_PMKSA_FLUSH: - NdisZeroMemory(pAd->StaCfg.SavedPMK, sizeof(BSSID_INFO)*PMKID_NO); - DBGPRINT(RT_DEBUG_TRACE ,("rt_ioctl_siwpmksa - IW_PMKSA_FLUSH\n")); - break; - case IW_PMKSA_REMOVE: - for (CachedIdx = 0; CachedIdx < pAd->StaCfg.SavedPMKNum; CachedIdx++) - { - // compare the BSSID - if (NdisEqualMemory(pPmksa->bssid.sa_data, pAd->StaCfg.SavedPMK[CachedIdx].BSSID, MAC_ADDR_LEN)) - { - NdisZeroMemory(pAd->StaCfg.SavedPMK[CachedIdx].BSSID, MAC_ADDR_LEN); - NdisZeroMemory(pAd->StaCfg.SavedPMK[CachedIdx].PMKID, 16); - for (idx = CachedIdx; idx < (pAd->StaCfg.SavedPMKNum - 1); idx++) - { - NdisMoveMemory(&pAd->StaCfg.SavedPMK[idx].BSSID[0], &pAd->StaCfg.SavedPMK[idx+1].BSSID[0], MAC_ADDR_LEN); - NdisMoveMemory(&pAd->StaCfg.SavedPMK[idx].PMKID[0], &pAd->StaCfg.SavedPMK[idx+1].PMKID[0], 16); - } - pAd->StaCfg.SavedPMKNum--; - break; - } - } - - DBGPRINT(RT_DEBUG_TRACE ,("rt_ioctl_siwpmksa - IW_PMKSA_REMOVE\n")); - break; - case IW_PMKSA_ADD: - for (CachedIdx = 0; CachedIdx < pAd->StaCfg.SavedPMKNum; CachedIdx++) - { - // compare the BSSID - if (NdisEqualMemory(pPmksa->bssid.sa_data, pAd->StaCfg.SavedPMK[CachedIdx].BSSID, MAC_ADDR_LEN)) - break; - } - - // Found, replace it - if (CachedIdx < PMKID_NO) - { - DBGPRINT(RT_DEBUG_OFF, ("Update PMKID, idx = %d\n", CachedIdx)); - NdisMoveMemory(&pAd->StaCfg.SavedPMK[CachedIdx].BSSID[0], pPmksa->bssid.sa_data, MAC_ADDR_LEN); - NdisMoveMemory(&pAd->StaCfg.SavedPMK[CachedIdx].PMKID[0], pPmksa->pmkid, 16); - pAd->StaCfg.SavedPMKNum++; - } - // Not found, replace the last one - else - { - // Randomly replace one - CachedIdx = (pPmksa->bssid.sa_data[5] % PMKID_NO); - DBGPRINT(RT_DEBUG_OFF, ("Update PMKID, idx = %d\n", CachedIdx)); - NdisMoveMemory(&pAd->StaCfg.SavedPMK[CachedIdx].BSSID[0], pPmksa->bssid.sa_data, MAC_ADDR_LEN); - NdisMoveMemory(&pAd->StaCfg.SavedPMK[CachedIdx].PMKID[0], pPmksa->pmkid, 16); - } - - DBGPRINT(RT_DEBUG_TRACE ,("rt_ioctl_siwpmksa - IW_PMKSA_ADD\n")); - break; - default: - DBGPRINT(RT_DEBUG_TRACE ,("rt_ioctl_siwpmksa - Unknow Command!!\n")); - break; - } - - return 0; -} -#endif // #if WIRELESS_EXT > 17 - -#ifdef DBG -static int -rt_private_ioctl_bbp(struct net_device *dev, struct iw_request_info *info, - struct iw_point *wrq, char *extra) - { - CHAR *this_char; - CHAR *value = NULL; - UCHAR regBBP = 0; -// CHAR arg[255]={0}; - UINT32 bbpId; - UINT32 bbpValue; - BOOLEAN bIsPrintAllBBP = FALSE; - INT Status = 0; - PRTMP_ADAPTER pAdapter = dev->ml_priv; - - - memset(extra, 0x00, IW_PRIV_SIZE_MASK); - - if (wrq->length > 1) //No parameters. - { - sprintf(extra, "\n"); - - //Parsing Read or Write - this_char = wrq->pointer; - DBGPRINT(RT_DEBUG_TRACE, ("this_char=%s\n", this_char)); - if (!*this_char) - goto next; - - if ((value = rtstrchr(this_char, '=')) != NULL) - *value++ = 0; - - if (!value || !*value) - { //Read - DBGPRINT(RT_DEBUG_TRACE, ("this_char=%s, value=%s\n", this_char, value)); - if (sscanf(this_char, "%d", &(bbpId)) == 1) - { - if (bbpId <= 136) - { -#ifdef RALINK_ATE - if (ATE_ON(pAdapter)) - { - ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); - } - else -#endif // RALINK_ATE // - { - RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); - } - sprintf(extra+strlen(extra), "R%02d[0x%02X]:%02X\n", bbpId, bbpId*2, regBBP); - wrq->length = strlen(extra) + 1; // 1: size of '\0' - DBGPRINT(RT_DEBUG_TRACE, ("msg=%s\n", extra)); - } - else - {//Invalid parametes, so default printk all bbp - bIsPrintAllBBP = TRUE; - goto next; - } - } - else - { //Invalid parametes, so default printk all bbp - bIsPrintAllBBP = TRUE; - goto next; - } - } - else - { //Write - if ((sscanf(this_char, "%d", &(bbpId)) == 1) && (sscanf(value, "%x", &(bbpValue)) == 1)) - { - if (bbpId <= 136) - { -#ifdef RALINK_ATE - if (ATE_ON(pAdapter)) - { - ATE_BBP_IO_WRITE8_BY_REG_ID(pAdapter, bbpId, bbpValue); - //Read it back for showing - ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); - } - else -#endif // RALINK_ATE // - { - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, bbpId, bbpValue); - //Read it back for showing - RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); - } - sprintf(extra+strlen(extra), "R%02d[0x%02X]:%02X\n", bbpId, bbpId*2, regBBP); - wrq->length = strlen(extra) + 1; // 1: size of '\0' - DBGPRINT(RT_DEBUG_TRACE, ("msg=%s\n", extra)); - } - else - {//Invalid parametes, so default printk all bbp - bIsPrintAllBBP = TRUE; - goto next; - } - } - else - { //Invalid parametes, so default printk all bbp - bIsPrintAllBBP = TRUE; - goto next; - } - } - } - else - bIsPrintAllBBP = TRUE; - -next: - if (bIsPrintAllBBP) - { - memset(extra, 0x00, IW_PRIV_SIZE_MASK); - sprintf(extra, "\n"); - for (bbpId = 0; bbpId <= 136; bbpId++) - { - if (strlen(extra) >= (IW_PRIV_SIZE_MASK - 10)) - break; -#ifdef RALINK_ATE - if (ATE_ON(pAdapter)) - { - ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); - } - else -#endif // RALINK_ATE // - RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); - sprintf(extra+strlen(extra), "R%02d[0x%02X]:%02X ", bbpId, bbpId*2, regBBP); - if (bbpId%5 == 4) - sprintf(extra+strlen(extra), "\n"); - } - - wrq->length = strlen(extra) + 1; // 1: size of '\0' - DBGPRINT(RT_DEBUG_TRACE, ("wrq->length = %d\n", wrq->length)); - } - - DBGPRINT(RT_DEBUG_TRACE, ("<==rt_private_ioctl_bbp\n\n")); - - return Status; -} -#endif // DBG // - -int rt_ioctl_siwrate(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - PRTMP_ADAPTER pAd = dev->ml_priv; - UINT32 rate = wrqu->bitrate.value, fixed = wrqu->bitrate.fixed; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("rt_ioctl_siwrate::Network is down!\n")); - return -ENETDOWN; - } - - DBGPRINT(RT_DEBUG_TRACE, ("rt_ioctl_siwrate::(rate = %d, fixed = %d)\n", rate, fixed)); - /* rate = -1 => auto rate - rate = X, fixed = 1 => (fixed rate X) - */ - if (rate == -1) - { - //Auto Rate - pAd->StaCfg.DesiredTransmitSetting.field.MCS = MCS_AUTO; - pAd->StaCfg.bAutoTxRateSwitch = TRUE; - if ((pAd->CommonCfg.PhyMode <= PHY_11G) || - (pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MODE <= MODE_OFDM)) - RTMPSetDesiredRates(pAd, -1); - -#ifdef DOT11_N_SUPPORT - SetCommonHT(pAd); -#endif // DOT11_N_SUPPORT // - } - else - { - if (fixed) - { - pAd->StaCfg.bAutoTxRateSwitch = FALSE; - if ((pAd->CommonCfg.PhyMode <= PHY_11G) || - (pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MODE <= MODE_OFDM)) - RTMPSetDesiredRates(pAd, rate); - else - { - pAd->StaCfg.DesiredTransmitSetting.field.MCS = MCS_AUTO; -#ifdef DOT11_N_SUPPORT - SetCommonHT(pAd); -#endif // DOT11_N_SUPPORT // - } - DBGPRINT(RT_DEBUG_TRACE, ("rt_ioctl_siwrate::(HtMcs=%d)\n",pAd->StaCfg.DesiredTransmitSetting.field.MCS)); - } - else - { - // TODO: rate = X, fixed = 0 => (rates <= X) - return -EOPNOTSUPP; - } - } - - return 0; -} - -int rt_ioctl_giwrate(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - PRTMP_ADAPTER pAd = dev->ml_priv; - int rate_index = 0, rate_count = 0; - HTTRANSMIT_SETTING ht_setting; - __s32 ralinkrate[] = - {2, 4, 11, 22, // CCK - 12, 18, 24, 36, 48, 72, 96, 108, // OFDM - 13, 26, 39, 52, 78, 104, 117, 130, 26, 52, 78, 104, 156, 208, 234, 260, // 20MHz, 800ns GI, MCS: 0 ~ 15 - 39, 78, 117, 156, 234, 312, 351, 390, // 20MHz, 800ns GI, MCS: 16 ~ 23 - 27, 54, 81, 108, 162, 216, 243, 270, 54, 108, 162, 216, 324, 432, 486, 540, // 40MHz, 800ns GI, MCS: 0 ~ 15 - 81, 162, 243, 324, 486, 648, 729, 810, // 40MHz, 800ns GI, MCS: 16 ~ 23 - 14, 29, 43, 57, 87, 115, 130, 144, 29, 59, 87, 115, 173, 230, 260, 288, // 20MHz, 400ns GI, MCS: 0 ~ 15 - 43, 87, 130, 173, 260, 317, 390, 433, // 20MHz, 400ns GI, MCS: 16 ~ 23 - 30, 60, 90, 120, 180, 240, 270, 300, 60, 120, 180, 240, 360, 480, 540, 600, // 40MHz, 400ns GI, MCS: 0 ~ 15 - 90, 180, 270, 360, 540, 720, 810, 900}; // 40MHz, 400ns GI, MCS: 16 ~ 23 - - rate_count = sizeof(ralinkrate)/sizeof(__s32); - //check if the interface is down - if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - if ((pAd->StaCfg.bAutoTxRateSwitch == FALSE) && - (INFRA_ON(pAd)) && - ((pAd->CommonCfg.PhyMode <= PHY_11G) || (pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MODE <= MODE_OFDM))) - ht_setting.word = pAd->StaCfg.HTPhyMode.word; - else - ht_setting.word = pAd->MacTab.Content[BSSID_WCID].HTPhyMode.word; - -#ifdef DOT11_N_SUPPORT - if (ht_setting.field.MODE >= MODE_HTMIX) - { -// rate_index = 12 + ((UCHAR)ht_setting.field.BW *16) + ((UCHAR)ht_setting.field.ShortGI *32) + ((UCHAR)ht_setting.field.MCS); - rate_index = 12 + ((UCHAR)ht_setting.field.BW *24) + ((UCHAR)ht_setting.field.ShortGI *48) + ((UCHAR)ht_setting.field.MCS); - } - else -#endif // DOT11_N_SUPPORT // - if (ht_setting.field.MODE == MODE_OFDM) - rate_index = (UCHAR)(ht_setting.field.MCS) + 4; - else if (ht_setting.field.MODE == MODE_CCK) - rate_index = (UCHAR)(ht_setting.field.MCS); - - if (rate_index < 0) - rate_index = 0; - - if (rate_index > rate_count) - rate_index = rate_count; - - wrqu->bitrate.value = ralinkrate[rate_index] * 500000; - wrqu->bitrate.disabled = 0; - - return 0; -} - -static const iw_handler rt_handler[] = -{ - (iw_handler) NULL, /* SIOCSIWCOMMIT */ - (iw_handler) rt_ioctl_giwname, /* SIOCGIWNAME */ - (iw_handler) NULL, /* SIOCSIWNWID */ - (iw_handler) NULL, /* SIOCGIWNWID */ - (iw_handler) rt_ioctl_siwfreq, /* SIOCSIWFREQ */ - (iw_handler) rt_ioctl_giwfreq, /* SIOCGIWFREQ */ - (iw_handler) rt_ioctl_siwmode, /* SIOCSIWMODE */ - (iw_handler) rt_ioctl_giwmode, /* SIOCGIWMODE */ - (iw_handler) NULL, /* SIOCSIWSENS */ - (iw_handler) NULL, /* SIOCGIWSENS */ - (iw_handler) NULL /* not used */, /* SIOCSIWRANGE */ - (iw_handler) rt_ioctl_giwrange, /* SIOCGIWRANGE */ - (iw_handler) NULL /* not used */, /* SIOCSIWPRIV */ - (iw_handler) NULL /* kernel code */, /* SIOCGIWPRIV */ - (iw_handler) NULL /* not used */, /* SIOCSIWSTATS */ - (iw_handler) rt28xx_get_wireless_stats /* kernel code */, /* SIOCGIWSTATS */ - (iw_handler) NULL, /* SIOCSIWSPY */ - (iw_handler) NULL, /* SIOCGIWSPY */ - (iw_handler) NULL, /* SIOCSIWTHRSPY */ - (iw_handler) NULL, /* SIOCGIWTHRSPY */ - (iw_handler) rt_ioctl_siwap, /* SIOCSIWAP */ - (iw_handler) rt_ioctl_giwap, /* SIOCGIWAP */ -#ifdef SIOCSIWMLME - (iw_handler) rt_ioctl_siwmlme, /* SIOCSIWMLME */ -#else - (iw_handler) NULL, /* SIOCSIWMLME */ -#endif // SIOCSIWMLME // - (iw_handler) rt_ioctl_iwaplist, /* SIOCGIWAPLIST */ -#ifdef SIOCGIWSCAN - (iw_handler) rt_ioctl_siwscan, /* SIOCSIWSCAN */ - (iw_handler) rt_ioctl_giwscan, /* SIOCGIWSCAN */ -#else - (iw_handler) NULL, /* SIOCSIWSCAN */ - (iw_handler) NULL, /* SIOCGIWSCAN */ -#endif /* SIOCGIWSCAN */ - (iw_handler) rt_ioctl_siwessid, /* SIOCSIWESSID */ - (iw_handler) rt_ioctl_giwessid, /* SIOCGIWESSID */ - (iw_handler) rt_ioctl_siwnickn, /* SIOCSIWNICKN */ - (iw_handler) rt_ioctl_giwnickn, /* SIOCGIWNICKN */ - (iw_handler) NULL, /* -- hole -- */ - (iw_handler) NULL, /* -- hole -- */ - (iw_handler) rt_ioctl_siwrate, /* SIOCSIWRATE */ - (iw_handler) rt_ioctl_giwrate, /* SIOCGIWRATE */ - (iw_handler) rt_ioctl_siwrts, /* SIOCSIWRTS */ - (iw_handler) rt_ioctl_giwrts, /* SIOCGIWRTS */ - (iw_handler) rt_ioctl_siwfrag, /* SIOCSIWFRAG */ - (iw_handler) rt_ioctl_giwfrag, /* SIOCGIWFRAG */ - (iw_handler) NULL, /* SIOCSIWTXPOW */ - (iw_handler) NULL, /* SIOCGIWTXPOW */ - (iw_handler) NULL, /* SIOCSIWRETRY */ - (iw_handler) NULL, /* SIOCGIWRETRY */ - (iw_handler) rt_ioctl_siwencode, /* SIOCSIWENCODE */ - (iw_handler) rt_ioctl_giwencode, /* SIOCGIWENCODE */ - (iw_handler) NULL, /* SIOCSIWPOWER */ - (iw_handler) NULL, /* SIOCGIWPOWER */ - (iw_handler) NULL, /* -- hole -- */ - (iw_handler) NULL, /* -- hole -- */ -#if WIRELESS_EXT > 17 - (iw_handler) rt_ioctl_siwgenie, /* SIOCSIWGENIE */ - (iw_handler) rt_ioctl_giwgenie, /* SIOCGIWGENIE */ - (iw_handler) rt_ioctl_siwauth, /* SIOCSIWAUTH */ - (iw_handler) rt_ioctl_giwauth, /* SIOCGIWAUTH */ - (iw_handler) rt_ioctl_siwencodeext, /* SIOCSIWENCODEEXT */ - (iw_handler) rt_ioctl_giwencodeext, /* SIOCGIWENCODEEXT */ - (iw_handler) rt_ioctl_siwpmksa, /* SIOCSIWPMKSA */ -#endif -}; - -static const iw_handler rt_priv_handlers[] = { - (iw_handler) NULL, /* + 0x00 */ - (iw_handler) NULL, /* + 0x01 */ -#ifndef CONFIG_AP_SUPPORT - (iw_handler) rt_ioctl_setparam, /* + 0x02 */ -#else - (iw_handler) NULL, /* + 0x02 */ -#endif // CONFIG_AP_SUPPORT // -#ifdef DBG - (iw_handler) rt_private_ioctl_bbp, /* + 0x03 */ -#else - (iw_handler) NULL, /* + 0x03 */ -#endif - (iw_handler) NULL, /* + 0x04 */ - (iw_handler) NULL, /* + 0x05 */ - (iw_handler) NULL, /* + 0x06 */ - (iw_handler) NULL, /* + 0x07 */ - (iw_handler) NULL, /* + 0x08 */ - (iw_handler) rt_private_get_statistics, /* + 0x09 */ - (iw_handler) NULL, /* + 0x0A */ - (iw_handler) NULL, /* + 0x0B */ - (iw_handler) NULL, /* + 0x0C */ - (iw_handler) NULL, /* + 0x0D */ - (iw_handler) NULL, /* + 0x0E */ - (iw_handler) NULL, /* + 0x0F */ - (iw_handler) NULL, /* + 0x10 */ - (iw_handler) rt_private_show, /* + 0x11 */ - (iw_handler) NULL, /* + 0x12 */ - (iw_handler) NULL, /* + 0x13 */ - (iw_handler) NULL, /* + 0x15 */ - (iw_handler) NULL, /* + 0x17 */ - (iw_handler) NULL, /* + 0x18 */ -}; - -const struct iw_handler_def rt28xx_iw_handler_def = -{ -#define N(a) (sizeof (a) / sizeof (a[0])) - .standard = (iw_handler *) rt_handler, - .num_standard = sizeof(rt_handler) / sizeof(iw_handler), - .private = (iw_handler *) rt_priv_handlers, - .num_private = N(rt_priv_handlers), - .private_args = (struct iw_priv_args *) privtab, - .num_private_args = N(privtab), -#if IW_HANDLER_VERSION >= 7 - .get_wireless_stats = rt28xx_get_wireless_stats, -#endif -}; - -INT RTMPSetInformation( - IN PRTMP_ADAPTER pAdapter, - IN OUT struct ifreq *rq, - IN INT cmd) -{ - struct iwreq *wrq = (struct iwreq *) rq; - NDIS_802_11_SSID Ssid; - NDIS_802_11_MAC_ADDRESS Bssid; - RT_802_11_PHY_MODE PhyMode; - RT_802_11_STA_CONFIG StaConfig; - NDIS_802_11_RATES aryRates; - RT_802_11_PREAMBLE Preamble; - NDIS_802_11_WEP_STATUS WepStatus; - NDIS_802_11_AUTHENTICATION_MODE AuthMode = Ndis802_11AuthModeMax; - NDIS_802_11_NETWORK_INFRASTRUCTURE BssType; - NDIS_802_11_RTS_THRESHOLD RtsThresh; - NDIS_802_11_FRAGMENTATION_THRESHOLD FragThresh; - NDIS_802_11_POWER_MODE PowerMode; - PNDIS_802_11_KEY pKey = NULL; - PNDIS_802_11_WEP pWepKey =NULL; - PNDIS_802_11_REMOVE_KEY pRemoveKey = NULL; - NDIS_802_11_CONFIGURATION Config, *pConfig = NULL; - NDIS_802_11_NETWORK_TYPE NetType; - ULONG Now; - UINT KeyIdx = 0; - INT Status = NDIS_STATUS_SUCCESS, MaxPhyMode = PHY_11G; - ULONG PowerTemp; - BOOLEAN RadioState; - BOOLEAN StateMachineTouched = FALSE; -#ifdef DOT11_N_SUPPORT - OID_SET_HT_PHYMODE HT_PhyMode; //11n ,kathy -#endif // DOT11_N_SUPPORT // -#ifdef WPA_SUPPLICANT_SUPPORT - PNDIS_802_11_PMKID pPmkId = NULL; - BOOLEAN IEEE8021xState = FALSE; - BOOLEAN IEEE8021x_required_keys = FALSE; - UCHAR wpa_supplicant_enable = 0; -#endif // WPA_SUPPLICANT_SUPPORT // - -#ifdef SNMP_SUPPORT - TX_RTY_CFG_STRUC tx_rty_cfg; - ULONG ShortRetryLimit, LongRetryLimit; - UCHAR ctmp; -#endif // SNMP_SUPPORT // - - - -#ifdef DOT11_N_SUPPORT - MaxPhyMode = PHY_11N_5G; -#endif // DOT11_N_SUPPORT // - - - DBGPRINT(RT_DEBUG_TRACE, ("-->RTMPSetInformation(), 0x%08x\n", cmd&0x7FFF)); - switch(cmd & 0x7FFF) { - case RT_OID_802_11_COUNTRY_REGION: - if (wrq->u.data.length < sizeof(UCHAR)) - Status = -EINVAL; - // Only avaliable when EEPROM not programming - else if (!(pAdapter->CommonCfg.CountryRegion & 0x80) && !(pAdapter->CommonCfg.CountryRegionForABand & 0x80)) - { - ULONG Country; - UCHAR TmpPhy; - - Status = copy_from_user(&Country, wrq->u.data.pointer, wrq->u.data.length); - pAdapter->CommonCfg.CountryRegion = (UCHAR)(Country & 0x000000FF); - pAdapter->CommonCfg.CountryRegionForABand = (UCHAR)((Country >> 8) & 0x000000FF); - TmpPhy = pAdapter->CommonCfg.PhyMode; - pAdapter->CommonCfg.PhyMode = 0xff; - // Build all corresponding channel information - RTMPSetPhyMode(pAdapter, TmpPhy); -#ifdef DOT11_N_SUPPORT - SetCommonHT(pAdapter); -#endif // DOT11_N_SUPPORT // - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_COUNTRY_REGION (A:%d B/G:%d)\n", pAdapter->CommonCfg.CountryRegionForABand, - pAdapter->CommonCfg.CountryRegion)); - } - break; - case OID_802_11_BSSID_LIST_SCAN: - #ifdef RALINK_ATE - if (ATE_ON(pAdapter)) - { - DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now\n")); - break; - } -#endif // RALINK_ATE // - Now = jiffies; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_BSSID_LIST_SCAN, TxCnt = %d \n", pAdapter->RalinkCounters.LastOneSecTotalTxCount)); - - if (MONITOR_ON(pAdapter)) - { - DBGPRINT(RT_DEBUG_TRACE, ("!!! Driver is in Monitor Mode now !!!\n")); - break; - } - - //Benson add 20080527, when radio off, sta don't need to scan - if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RADIO_OFF)) - break; - - if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) - { - DBGPRINT(RT_DEBUG_TRACE, ("!!! Driver is scanning now !!!\n")); - pAdapter->StaCfg.bScanReqIsFromWebUI = TRUE; - Status = NDIS_STATUS_SUCCESS; - break; - } - - if (pAdapter->RalinkCounters.LastOneSecTotalTxCount > 100) - { - DBGPRINT(RT_DEBUG_TRACE, ("!!! Link UP, ignore this set::OID_802_11_BSSID_LIST_SCAN\n")); - Status = NDIS_STATUS_SUCCESS; - pAdapter->StaCfg.ScanCnt = 99; // Prevent auto scan triggered by this OID - break; - } - - if ((OPSTATUS_TEST_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED)) && - ((pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || - (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) || - (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || - (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)) && - (pAdapter->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED)) - { - DBGPRINT(RT_DEBUG_TRACE, ("!!! Link UP, Port Not Secured! ignore this set::OID_802_11_BSSID_LIST_SCAN\n")); - Status = NDIS_STATUS_SUCCESS; - pAdapter->StaCfg.ScanCnt = 99; // Prevent auto scan triggered by this OID - break; - } - - - if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) - { - RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); - DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); - } - - // tell CNTL state machine to call NdisMSetInformationComplete() after completing - // this request, because this request is initiated by NDIS. - pAdapter->MlmeAux.CurrReqIsFromNdis = FALSE; - // Reset allowed scan retries - pAdapter->StaCfg.ScanCnt = 0; - pAdapter->StaCfg.LastScanTime = Now; - - pAdapter->StaCfg.bScanReqIsFromWebUI = TRUE; - RTMP_SET_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS); - MlmeEnqueue(pAdapter, - MLME_CNTL_STATE_MACHINE, - OID_802_11_BSSID_LIST_SCAN, - 0, - NULL); - - Status = NDIS_STATUS_SUCCESS; - StateMachineTouched = TRUE; - break; - case OID_802_11_SSID: - if (wrq->u.data.length != sizeof(NDIS_802_11_SSID)) - Status = -EINVAL; - else - { - PCHAR pSsidString = NULL; - Status = copy_from_user(&Ssid, wrq->u.data.pointer, wrq->u.data.length); - - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_SSID (Len=%d,Ssid=%s)\n", Ssid.SsidLength, Ssid.Ssid)); - if (Ssid.SsidLength > MAX_LEN_OF_SSID) - Status = -EINVAL; - else - { - if (Ssid.SsidLength == 0) - { - Set_SSID_Proc(pAdapter, ""); - } - else - { - pSsidString = (CHAR *) kmalloc(MAX_LEN_OF_SSID+1, MEM_ALLOC_FLAG); - if (pSsidString) - { - NdisZeroMemory(pSsidString, MAX_LEN_OF_SSID+1); - NdisMoveMemory(pSsidString, Ssid.Ssid, Ssid.SsidLength); - Set_SSID_Proc(pAdapter, pSsidString); - kfree(pSsidString); - } - else - Status = -ENOMEM; - } - } - } - break; - case OID_802_11_BSSID: -#ifdef RALINK_ATE - if (ATE_ON(pAdapter)) - { - DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now\n")); - break; - } -#endif // RALINK_ATE // - if (wrq->u.data.length != sizeof(NDIS_802_11_MAC_ADDRESS)) - Status = -EINVAL; - else - { - Status = copy_from_user(&Bssid, wrq->u.data.pointer, wrq->u.data.length); - - // tell CNTL state machine to call NdisMSetInformationComplete() after completing - // this request, because this request is initiated by NDIS. - pAdapter->MlmeAux.CurrReqIsFromNdis = FALSE; - - // Prevent to connect AP again in STAMlmePeriodicExec - pAdapter->MlmeAux.AutoReconnectSsidLen= 32; - - // Reset allowed scan retries - pAdapter->StaCfg.ScanCnt = 0; - - if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) - { - RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); - DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); - } - MlmeEnqueue(pAdapter, - MLME_CNTL_STATE_MACHINE, - OID_802_11_BSSID, - sizeof(NDIS_802_11_MAC_ADDRESS), - (VOID *)&Bssid); - Status = NDIS_STATUS_SUCCESS; - StateMachineTouched = TRUE; - - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_BSSID %02x:%02x:%02x:%02x:%02x:%02x\n", - Bssid[0], Bssid[1], Bssid[2], Bssid[3], Bssid[4], Bssid[5])); - } - break; - case RT_OID_802_11_RADIO: - if (wrq->u.data.length != sizeof(BOOLEAN)) - Status = -EINVAL; - else - { - Status = copy_from_user(&RadioState, wrq->u.data.pointer, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_RADIO (=%d)\n", RadioState)); - if (pAdapter->StaCfg.bSwRadio != RadioState) - { - pAdapter->StaCfg.bSwRadio = RadioState; - if (pAdapter->StaCfg.bRadio != (pAdapter->StaCfg.bHwRadio && pAdapter->StaCfg.bSwRadio)) - { - pAdapter->StaCfg.bRadio = (pAdapter->StaCfg.bHwRadio && pAdapter->StaCfg.bSwRadio); - if (pAdapter->StaCfg.bRadio == TRUE) - { - MlmeRadioOn(pAdapter); - // Update extra information - pAdapter->ExtraInfo = EXTRA_INFO_CLEAR; - } - else - { - MlmeRadioOff(pAdapter); - // Update extra information - pAdapter->ExtraInfo = SW_RADIO_OFF; - } - } - } - } - break; - case RT_OID_802_11_PHY_MODE: - if (wrq->u.data.length != sizeof(RT_802_11_PHY_MODE)) - Status = -EINVAL; - else - { - Status = copy_from_user(&PhyMode, wrq->u.data.pointer, wrq->u.data.length); - if (PhyMode <= MaxPhyMode) - { - RTMPSetPhyMode(pAdapter, PhyMode); -#ifdef DOT11_N_SUPPORT - SetCommonHT(pAdapter); -#endif // DOT11_N_SUPPORT // - } - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_PHY_MODE (=%d)\n", PhyMode)); - } - break; - case RT_OID_802_11_STA_CONFIG: - if (wrq->u.data.length != sizeof(RT_802_11_STA_CONFIG)) - Status = -EINVAL; - else - { - Status = copy_from_user(&StaConfig, wrq->u.data.pointer, wrq->u.data.length); - pAdapter->CommonCfg.bEnableTxBurst = StaConfig.EnableTxBurst; - pAdapter->CommonCfg.UseBGProtection = StaConfig.UseBGProtection; - pAdapter->CommonCfg.bUseShortSlotTime = 1; // 2003-10-30 always SHORT SLOT capable - if ((pAdapter->CommonCfg.PhyMode != StaConfig.AdhocMode) && - (StaConfig.AdhocMode <= MaxPhyMode)) - { - // allow dynamic change of "USE OFDM rate or not" in ADHOC mode - // if setting changed, need to reset current TX rate as well as BEACON frame format - if (pAdapter->StaCfg.BssType == BSS_ADHOC) - { - pAdapter->CommonCfg.PhyMode = StaConfig.AdhocMode; - RTMPSetPhyMode(pAdapter, PhyMode); - MlmeUpdateTxRates(pAdapter, FALSE, 0); - MakeIbssBeacon(pAdapter); // re-build BEACON frame - AsicEnableIbssSync(pAdapter); // copy to on-chip memory - } - } - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_SET_STA_CONFIG (Burst=%d, Protection=%ld,ShortSlot=%d\n", - pAdapter->CommonCfg.bEnableTxBurst, - pAdapter->CommonCfg.UseBGProtection, - pAdapter->CommonCfg.bUseShortSlotTime)); - } - break; - case OID_802_11_DESIRED_RATES: - if (wrq->u.data.length != sizeof(NDIS_802_11_RATES)) - Status = -EINVAL; - else - { - Status = copy_from_user(&aryRates, wrq->u.data.pointer, wrq->u.data.length); - NdisZeroMemory(pAdapter->CommonCfg.DesireRate, MAX_LEN_OF_SUPPORTED_RATES); - NdisMoveMemory(pAdapter->CommonCfg.DesireRate, &aryRates, sizeof(NDIS_802_11_RATES)); - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_DESIRED_RATES (%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x)\n", - pAdapter->CommonCfg.DesireRate[0],pAdapter->CommonCfg.DesireRate[1], - pAdapter->CommonCfg.DesireRate[2],pAdapter->CommonCfg.DesireRate[3], - pAdapter->CommonCfg.DesireRate[4],pAdapter->CommonCfg.DesireRate[5], - pAdapter->CommonCfg.DesireRate[6],pAdapter->CommonCfg.DesireRate[7] )); - // Changing DesiredRate may affect the MAX TX rate we used to TX frames out - MlmeUpdateTxRates(pAdapter, FALSE, 0); - } - break; - case RT_OID_802_11_PREAMBLE: - if (wrq->u.data.length != sizeof(RT_802_11_PREAMBLE)) - Status = -EINVAL; - else - { - Status = copy_from_user(&Preamble, wrq->u.data.pointer, wrq->u.data.length); - if (Preamble == Rt802_11PreambleShort) - { - pAdapter->CommonCfg.TxPreamble = Preamble; - MlmeSetTxPreamble(pAdapter, Rt802_11PreambleShort); - } - else if ((Preamble == Rt802_11PreambleLong) || (Preamble == Rt802_11PreambleAuto)) - { - // if user wants AUTO, initialize to LONG here, then change according to AP's - // capability upon association. - pAdapter->CommonCfg.TxPreamble = Preamble; - MlmeSetTxPreamble(pAdapter, Rt802_11PreambleLong); - } - else - { - Status = -EINVAL; - break; - } - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_PREAMBLE (=%d)\n", Preamble)); - } - break; - case OID_802_11_WEP_STATUS: - if (wrq->u.data.length != sizeof(NDIS_802_11_WEP_STATUS)) - Status = -EINVAL; - else - { - Status = copy_from_user(&WepStatus, wrq->u.data.pointer, wrq->u.data.length); - // Since TKIP, AES, WEP are all supported. It should not have any invalid setting - if (WepStatus <= Ndis802_11Encryption3KeyAbsent) - { - if (pAdapter->StaCfg.WepStatus != WepStatus) - { - // Config has changed - pAdapter->bConfigChanged = TRUE; - } - pAdapter->StaCfg.WepStatus = WepStatus; - pAdapter->StaCfg.OrigWepStatus = WepStatus; - pAdapter->StaCfg.PairCipher = WepStatus; - pAdapter->StaCfg.GroupCipher = WepStatus; - } - else - { - Status = -EINVAL; - break; - } - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_WEP_STATUS (=%d)\n",WepStatus)); - } - break; - case OID_802_11_AUTHENTICATION_MODE: - if (wrq->u.data.length != sizeof(NDIS_802_11_AUTHENTICATION_MODE)) - Status = -EINVAL; - else - { - Status = copy_from_user(&AuthMode, wrq->u.data.pointer, wrq->u.data.length); - if (AuthMode > Ndis802_11AuthModeMax) - { - Status = -EINVAL; - break; - } - else - { - if (pAdapter->StaCfg.AuthMode != AuthMode) - { - // Config has changed - pAdapter->bConfigChanged = TRUE; - } - pAdapter->StaCfg.AuthMode = AuthMode; - } - pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_AUTHENTICATION_MODE (=%d) \n",pAdapter->StaCfg.AuthMode)); - } - break; - case OID_802_11_INFRASTRUCTURE_MODE: - if (wrq->u.data.length != sizeof(NDIS_802_11_NETWORK_INFRASTRUCTURE)) - Status = -EINVAL; - else - { - Status = copy_from_user(&BssType, wrq->u.data.pointer, wrq->u.data.length); - - if (BssType == Ndis802_11IBSS) - Set_NetworkType_Proc(pAdapter, "Adhoc"); - else if (BssType == Ndis802_11Infrastructure) - Set_NetworkType_Proc(pAdapter, "Infra"); - else if (BssType == Ndis802_11Monitor) - Set_NetworkType_Proc(pAdapter, "Monitor"); - else - { - Status = -EINVAL; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_INFRASTRUCTURE_MODE (unknown)\n")); - } - } - break; - case OID_802_11_REMOVE_WEP: - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_WEP\n")); - if (wrq->u.data.length != sizeof(NDIS_802_11_KEY_INDEX)) - { - Status = -EINVAL; - } - else - { - KeyIdx = *(NDIS_802_11_KEY_INDEX *) wrq->u.data.pointer; - - if (KeyIdx & 0x80000000) - { - // Should never set default bit when remove key - Status = -EINVAL; - } - else - { - KeyIdx = KeyIdx & 0x0fffffff; - if (KeyIdx >= 4){ - Status = -EINVAL; - } - else - { - pAdapter->SharedKey[BSS0][KeyIdx].KeyLen = 0; - pAdapter->SharedKey[BSS0][KeyIdx].CipherAlg = CIPHER_NONE; - AsicRemoveSharedKeyEntry(pAdapter, 0, (UCHAR)KeyIdx); - } - } - } - break; - case RT_OID_802_11_RESET_COUNTERS: - NdisZeroMemory(&pAdapter->WlanCounters, sizeof(COUNTER_802_11)); - NdisZeroMemory(&pAdapter->Counters8023, sizeof(COUNTER_802_3)); - NdisZeroMemory(&pAdapter->RalinkCounters, sizeof(COUNTER_RALINK)); - pAdapter->Counters8023.RxNoBuffer = 0; - pAdapter->Counters8023.GoodReceives = 0; - pAdapter->Counters8023.RxNoBuffer = 0; -#ifdef RT2870 - pAdapter->BulkOutComplete = 0; - pAdapter->BulkOutCompleteOther= 0; - pAdapter->BulkOutCompleteCancel = 0; - pAdapter->BulkOutReq = 0; - pAdapter->BulkInReq= 0; - pAdapter->BulkInComplete = 0; - pAdapter->BulkInCompleteFail = 0; -#endif // RT2870 // - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_RESET_COUNTERS \n")); - break; - case OID_802_11_RTS_THRESHOLD: - if (wrq->u.data.length != sizeof(NDIS_802_11_RTS_THRESHOLD)) - Status = -EINVAL; - else - { - Status = copy_from_user(&RtsThresh, wrq->u.data.pointer, wrq->u.data.length); - if (RtsThresh > MAX_RTS_THRESHOLD) - Status = -EINVAL; - else - pAdapter->CommonCfg.RtsThreshold = (USHORT)RtsThresh; - } - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_RTS_THRESHOLD (=%ld)\n",RtsThresh)); - break; - case OID_802_11_FRAGMENTATION_THRESHOLD: - if (wrq->u.data.length != sizeof(NDIS_802_11_FRAGMENTATION_THRESHOLD)) - Status = -EINVAL; - else - { - Status = copy_from_user(&FragThresh, wrq->u.data.pointer, wrq->u.data.length); - pAdapter->CommonCfg.bUseZeroToDisableFragment = FALSE; - if (FragThresh > MAX_FRAG_THRESHOLD || FragThresh < MIN_FRAG_THRESHOLD) - { - if (FragThresh == 0) - { - pAdapter->CommonCfg.FragmentThreshold = MAX_FRAG_THRESHOLD; - pAdapter->CommonCfg.bUseZeroToDisableFragment = TRUE; - } - else - Status = -EINVAL; - } - else - pAdapter->CommonCfg.FragmentThreshold = (USHORT)FragThresh; - } - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_FRAGMENTATION_THRESHOLD (=%ld) \n",FragThresh)); - break; - case OID_802_11_POWER_MODE: - if (wrq->u.data.length != sizeof(NDIS_802_11_POWER_MODE)) - Status = -EINVAL; - else - { - Status = copy_from_user(&PowerMode, wrq->u.data.pointer, wrq->u.data.length); - if (PowerMode == Ndis802_11PowerModeCAM) - Set_PSMode_Proc(pAdapter, "CAM"); - else if (PowerMode == Ndis802_11PowerModeMAX_PSP) - Set_PSMode_Proc(pAdapter, "Max_PSP"); - else if (PowerMode == Ndis802_11PowerModeFast_PSP) - Set_PSMode_Proc(pAdapter, "Fast_PSP"); - else if (PowerMode == Ndis802_11PowerModeLegacy_PSP) - Set_PSMode_Proc(pAdapter, "Legacy_PSP"); - else - Status = -EINVAL; - } - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_POWER_MODE (=%d)\n",PowerMode)); - break; - case RT_OID_802_11_TX_POWER_LEVEL_1: - if (wrq->u.data.length < sizeof(ULONG)) - Status = -EINVAL; - else - { - Status = copy_from_user(&PowerTemp, wrq->u.data.pointer, wrq->u.data.length); - if (PowerTemp > 100) - PowerTemp = 0xffffffff; // AUTO - pAdapter->CommonCfg.TxPowerDefault = PowerTemp; //keep current setting. - pAdapter->CommonCfg.TxPowerPercentage = pAdapter->CommonCfg.TxPowerDefault; - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_TX_POWER_LEVEL_1 (=%ld)\n", pAdapter->CommonCfg.TxPowerPercentage)); - } - break; - case OID_802_11_NETWORK_TYPE_IN_USE: - if (wrq->u.data.length != sizeof(NDIS_802_11_NETWORK_TYPE)) - Status = -EINVAL; - else - { - Status = copy_from_user(&NetType, wrq->u.data.pointer, wrq->u.data.length); - - if (NetType == Ndis802_11DS) - RTMPSetPhyMode(pAdapter, PHY_11B); - else if (NetType == Ndis802_11OFDM24) - RTMPSetPhyMode(pAdapter, PHY_11BG_MIXED); - else if (NetType == Ndis802_11OFDM5) - RTMPSetPhyMode(pAdapter, PHY_11A); - else - Status = -EINVAL; -#ifdef DOT11_N_SUPPORT - if (Status == NDIS_STATUS_SUCCESS) - SetCommonHT(pAdapter); -#endif // DOT11_N_SUPPORT // - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_NETWORK_TYPE_IN_USE (=%d)\n",NetType)); - } - break; - // For WPA PSK PMK key - case RT_OID_802_11_ADD_WPA: - pKey = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); - if(pKey == NULL) - { - Status = -ENOMEM; - break; - } - - Status = copy_from_user(pKey, wrq->u.data.pointer, wrq->u.data.length); - if (pKey->Length != wrq->u.data.length) - { - Status = -EINVAL; - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_ADD_WPA, Failed!!\n")); - } - else - { - if ((pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPAPSK) && - (pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPA2PSK) && - (pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPANone) ) - { - Status = -EOPNOTSUPP; - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_ADD_WPA, Failed!! [AuthMode != WPAPSK/WPA2PSK/WPANONE]\n")); - } - else if ((pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) || - (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) || - (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) ) // Only for WPA PSK mode - { - NdisMoveMemory(pAdapter->StaCfg.PMK, &pKey->KeyMaterial, pKey->KeyLength); - // Use RaConfig as PSK agent. - // Start STA supplicant state machine - if (pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPANone) - pAdapter->StaCfg.WpaState = SS_START; - - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_ADD_WPA (id=0x%x, Len=%d-byte)\n", pKey->KeyIndex, pKey->KeyLength)); - } - else - { - pAdapter->StaCfg.WpaState = SS_NOTUSE; - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_ADD_WPA (id=0x%x, Len=%d-byte)\n", pKey->KeyIndex, pKey->KeyLength)); - } - } - kfree(pKey); - break; - case OID_802_11_REMOVE_KEY: - pRemoveKey = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); - if(pRemoveKey == NULL) - { - Status = -ENOMEM; - break; - } - - Status = copy_from_user(pRemoveKey, wrq->u.data.pointer, wrq->u.data.length); - if (pRemoveKey->Length != wrq->u.data.length) - { - Status = -EINVAL; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_KEY, Failed!!\n")); - } - else - { - if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - { - RTMPWPARemoveKeyProc(pAdapter, pRemoveKey); - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_KEY, Remove WPA Key!!\n")); - } - else - { - KeyIdx = pRemoveKey->KeyIndex; - - if (KeyIdx & 0x80000000) - { - // Should never set default bit when remove key - Status = -EINVAL; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_KEY, Failed!!(Should never set default bit when remove key)\n")); - } - else - { - KeyIdx = KeyIdx & 0x0fffffff; - if (KeyIdx > 3) - { - Status = -EINVAL; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_KEY, Failed!!(KeyId[%d] out of range)\n", KeyIdx)); - } - else - { - pAdapter->SharedKey[BSS0][KeyIdx].KeyLen = 0; - pAdapter->SharedKey[BSS0][KeyIdx].CipherAlg = CIPHER_NONE; - AsicRemoveSharedKeyEntry(pAdapter, 0, (UCHAR)KeyIdx); - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_KEY (id=0x%x, Len=%d-byte)\n", pRemoveKey->KeyIndex, pRemoveKey->Length)); - } - } - } - } - kfree(pRemoveKey); - break; - // New for WPA - case OID_802_11_ADD_KEY: - pKey = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); - if(pKey == NULL) - { - Status = -ENOMEM; - break; - } - Status = copy_from_user(pKey, wrq->u.data.pointer, wrq->u.data.length); - if (pKey->Length != wrq->u.data.length) - { - Status = -EINVAL; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_KEY, Failed!!\n")); - } - else - { - RTMPAddKey(pAdapter, pKey); - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_KEY (id=0x%x, Len=%d-byte)\n", pKey->KeyIndex, pKey->KeyLength)); - } - kfree(pKey); - break; - case OID_802_11_CONFIGURATION: - if (wrq->u.data.length != sizeof(NDIS_802_11_CONFIGURATION)) - Status = -EINVAL; - else - { - Status = copy_from_user(&Config, wrq->u.data.pointer, wrq->u.data.length); - pConfig = &Config; - - if ((pConfig->BeaconPeriod >= 20) && (pConfig->BeaconPeriod <=400)) - pAdapter->CommonCfg.BeaconPeriod = (USHORT) pConfig->BeaconPeriod; - - pAdapter->StaActive.AtimWin = (USHORT) pConfig->ATIMWindow; - MAP_KHZ_TO_CHANNEL_ID(pConfig->DSConfig, pAdapter->CommonCfg.Channel); - // - // Save the channel on MlmeAux for CntlOidRTBssidProc used. - // - pAdapter->MlmeAux.Channel = pAdapter->CommonCfg.Channel; - - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_CONFIGURATION (BeacnPeriod=%ld,AtimW=%ld,Ch=%d)\n", - pConfig->BeaconPeriod, pConfig->ATIMWindow, pAdapter->CommonCfg.Channel)); - // Config has changed - pAdapter->bConfigChanged = TRUE; - } - break; -#ifdef DOT11_N_SUPPORT - case RT_OID_802_11_SET_HT_PHYMODE: - if (wrq->u.data.length != sizeof(OID_SET_HT_PHYMODE)) - Status = -EINVAL; - else - { - POID_SET_HT_PHYMODE pHTPhyMode = &HT_PhyMode; - - Status = copy_from_user(&HT_PhyMode, wrq->u.data.pointer, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Set::pHTPhyMode (PhyMode = %d,TransmitNo = %d, HtMode = %d, ExtOffset = %d , MCS = %d, BW = %d, STBC = %d, SHORTGI = %d) \n", - pHTPhyMode->PhyMode, pHTPhyMode->TransmitNo,pHTPhyMode->HtMode,pHTPhyMode->ExtOffset, - pHTPhyMode->MCS, pHTPhyMode->BW, pHTPhyMode->STBC, pHTPhyMode->SHORTGI)); - if (pAdapter->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) - RTMPSetHT(pAdapter, pHTPhyMode); - } - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_SET_HT_PHYMODE(MCS=%d,BW=%d,SGI=%d,STBC=%d)\n", - pAdapter->StaCfg.HTPhyMode.field.MCS, pAdapter->StaCfg.HTPhyMode.field.BW, pAdapter->StaCfg.HTPhyMode.field.ShortGI, - pAdapter->StaCfg.HTPhyMode.field.STBC)); - break; -#endif // DOT11_N_SUPPORT // - case RT_OID_802_11_SET_APSD_SETTING: - if (wrq->u.data.length != sizeof(ULONG)) - Status = -EINVAL; - else - { - ULONG apsd ; - Status = copy_from_user(&apsd, wrq->u.data.pointer, wrq->u.data.length); - - /*------------------------------------------------------------------- - |B31~B7 | B6~B5 | B4 | B3 | B2 | B1 | B0 | - --------------------------------------------------------------------- - | Rsvd | Max SP Len | AC_VO | AC_VI | AC_BK | AC_BE | APSD Capable | - ---------------------------------------------------------------------*/ - pAdapter->CommonCfg.bAPSDCapable = (apsd & 0x00000001) ? TRUE : FALSE; - pAdapter->CommonCfg.bAPSDAC_BE = ((apsd & 0x00000002) >> 1) ? TRUE : FALSE; - pAdapter->CommonCfg.bAPSDAC_BK = ((apsd & 0x00000004) >> 2) ? TRUE : FALSE; - pAdapter->CommonCfg.bAPSDAC_VI = ((apsd & 0x00000008) >> 3) ? TRUE : FALSE; - pAdapter->CommonCfg.bAPSDAC_VO = ((apsd & 0x00000010) >> 4) ? TRUE : FALSE; - pAdapter->CommonCfg.MaxSPLength = (UCHAR)((apsd & 0x00000060) >> 5); - - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_SET_APSD_SETTING (apsd=0x%lx, APSDCap=%d, [BE,BK,VI,VO]=[%d/%d/%d/%d], MaxSPLen=%d)\n", apsd, pAdapter->CommonCfg.bAPSDCapable, - pAdapter->CommonCfg.bAPSDAC_BE, pAdapter->CommonCfg.bAPSDAC_BK, pAdapter->CommonCfg.bAPSDAC_VI, pAdapter->CommonCfg.bAPSDAC_VO, pAdapter->CommonCfg.MaxSPLength)); - } - break; - - case RT_OID_802_11_SET_APSD_PSM: - if (wrq->u.data.length != sizeof(ULONG)) - Status = -EINVAL; - else - { - // Driver needs to notify AP when PSM changes - Status = copy_from_user(&pAdapter->CommonCfg.bAPSDForcePowerSave, wrq->u.data.pointer, wrq->u.data.length); - if (pAdapter->CommonCfg.bAPSDForcePowerSave != pAdapter->StaCfg.Psm) - { - MlmeSetPsmBit(pAdapter, pAdapter->CommonCfg.bAPSDForcePowerSave); - RTMPSendNullFrame(pAdapter, pAdapter->CommonCfg.TxRate, TRUE); - } - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_SET_APSD_PSM (bAPSDForcePowerSave:%d)\n", pAdapter->CommonCfg.bAPSDForcePowerSave)); - } - break; -#ifdef QOS_DLS_SUPPORT - case RT_OID_802_11_SET_DLS: - if (wrq->u.data.length != sizeof(ULONG)) - Status = -EINVAL; - else - { - BOOLEAN oldvalue = pAdapter->CommonCfg.bDLSCapable; - Status = copy_from_user(&pAdapter->CommonCfg.bDLSCapable, wrq->u.data.pointer, wrq->u.data.length); - if (oldvalue && !pAdapter->CommonCfg.bDLSCapable) - { - int i; - // tear down local dls table entry - for (i=0; iStaCfg.DLSEntry[i].Valid && (pAdapter->StaCfg.DLSEntry[i].Status == DLS_FINISH)) - { - pAdapter->StaCfg.DLSEntry[i].Status = DLS_NONE; - pAdapter->StaCfg.DLSEntry[i].Valid = FALSE; - RTMPSendDLSTearDownFrame(pAdapter, pAdapter->StaCfg.DLSEntry[i].MacAddr); - } - } - - // tear down peer dls table entry - for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid && (pAdapter->StaCfg.DLSEntry[i].Status == DLS_FINISH)) - { - pAdapter->StaCfg.DLSEntry[i].Status = DLS_NONE; - pAdapter->StaCfg.DLSEntry[i].Valid = FALSE; - RTMPSendDLSTearDownFrame(pAdapter, pAdapter->StaCfg.DLSEntry[i].MacAddr); - } - } - } - - DBGPRINT(RT_DEBUG_TRACE,("Set::RT_OID_802_11_SET_DLS (=%d)\n", pAdapter->CommonCfg.bDLSCapable)); - } - break; - - case RT_OID_802_11_SET_DLS_PARAM: - if (wrq->u.data.length != sizeof(RT_802_11_DLS_UI)) - Status = -EINVAL; - else - { - RT_802_11_DLS Dls; - - NdisZeroMemory(&Dls, sizeof(RT_802_11_DLS)); - RTMPMoveMemory(&Dls, wrq->u.data.pointer, sizeof(RT_802_11_DLS_UI)); - MlmeEnqueue(pAdapter, - MLME_CNTL_STATE_MACHINE, - RT_OID_802_11_SET_DLS_PARAM, - sizeof(RT_802_11_DLS), - &Dls); - DBGPRINT(RT_DEBUG_TRACE,("Set::RT_OID_802_11_SET_DLS_PARAM \n")); - } - break; -#endif // QOS_DLS_SUPPORT // - case RT_OID_802_11_SET_WMM: - if (wrq->u.data.length != sizeof(BOOLEAN)) - Status = -EINVAL; - else - { - Status = copy_from_user(&pAdapter->CommonCfg.bWmmCapable, wrq->u.data.pointer, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_SET_WMM (=%d) \n", pAdapter->CommonCfg.bWmmCapable)); - } - break; - - case OID_802_11_DISASSOCIATE: -#ifdef RALINK_ATE - if (ATE_ON(pAdapter)) - { - DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now\n")); - break; - } -#endif // RALINK_ATE // - // - // Set NdisRadioStateOff to TRUE, instead of called MlmeRadioOff. - // Later on, NDIS_802_11_BSSID_LIST_EX->NumberOfItems should be 0 - // when query OID_802_11_BSSID_LIST. - // - // TRUE: NumberOfItems will set to 0. - // FALSE: NumberOfItems no change. - // - pAdapter->CommonCfg.NdisRadioStateOff = TRUE; - // Set to immediately send the media disconnect event - pAdapter->MlmeAux.CurrReqIsFromNdis = TRUE; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_DISASSOCIATE \n")); - - if (INFRA_ON(pAdapter)) - { - if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) - { - RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); - DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); - } - - MlmeEnqueue(pAdapter, - MLME_CNTL_STATE_MACHINE, - OID_802_11_DISASSOCIATE, - 0, - NULL); - - StateMachineTouched = TRUE; - } - break; - -#ifdef DOT11_N_SUPPORT - case RT_OID_802_11_SET_IMME_BA_CAP: - if (wrq->u.data.length != sizeof(OID_BACAP_STRUC)) - Status = -EINVAL; - else - { - OID_BACAP_STRUC Orde ; - Status = copy_from_user(&Orde, wrq->u.data.pointer, wrq->u.data.length); - if (Orde.Policy > BA_NOTUSE) - { - Status = NDIS_STATUS_INVALID_DATA; - } - else if (Orde.Policy == BA_NOTUSE) - { - pAdapter->CommonCfg.BACapability.field.Policy = BA_NOTUSE; - pAdapter->CommonCfg.BACapability.field.MpduDensity = Orde.MpduDensity; - pAdapter->CommonCfg.DesiredHtPhy.MpduDensity = Orde.MpduDensity; - pAdapter->CommonCfg.DesiredHtPhy.AmsduEnable = Orde.AmsduEnable; - pAdapter->CommonCfg.DesiredHtPhy.AmsduSize= Orde.AmsduSize; - pAdapter->CommonCfg.DesiredHtPhy.MimoPs= Orde.MMPSmode; - pAdapter->CommonCfg.BACapability.field.MMPSmode = Orde.MMPSmode; - // UPdata to HT IE - pAdapter->CommonCfg.HtCapability.HtCapInfo.MimoPs = Orde.MMPSmode; - pAdapter->CommonCfg.HtCapability.HtCapInfo.AMsduSize = Orde.AmsduSize; - pAdapter->CommonCfg.HtCapability.HtCapParm.MpduDensity = Orde.MpduDensity; - } - else - { - pAdapter->CommonCfg.BACapability.field.AutoBA = Orde.AutoBA; - pAdapter->CommonCfg.BACapability.field.Policy = IMMED_BA; // we only support immediate BA. - pAdapter->CommonCfg.BACapability.field.MpduDensity = Orde.MpduDensity; - pAdapter->CommonCfg.DesiredHtPhy.MpduDensity = Orde.MpduDensity; - pAdapter->CommonCfg.DesiredHtPhy.AmsduEnable = Orde.AmsduEnable; - pAdapter->CommonCfg.DesiredHtPhy.AmsduSize= Orde.AmsduSize; - pAdapter->CommonCfg.DesiredHtPhy.MimoPs = Orde.MMPSmode; - pAdapter->CommonCfg.BACapability.field.MMPSmode = Orde.MMPSmode; - - // UPdata to HT IE - pAdapter->CommonCfg.HtCapability.HtCapInfo.MimoPs = Orde.MMPSmode; - pAdapter->CommonCfg.HtCapability.HtCapInfo.AMsduSize = Orde.AmsduSize; - pAdapter->CommonCfg.HtCapability.HtCapParm.MpduDensity = Orde.MpduDensity; - - if (pAdapter->CommonCfg.BACapability.field.RxBAWinLimit > MAX_RX_REORDERBUF) - pAdapter->CommonCfg.BACapability.field.RxBAWinLimit = MAX_RX_REORDERBUF; - - } - - pAdapter->CommonCfg.REGBACapability.word = pAdapter->CommonCfg.BACapability.word; - DBGPRINT(RT_DEBUG_TRACE, ("Set::(Orde.AutoBA = %d) (Policy=%d)(ReBAWinLimit=%d)(TxBAWinLimit=%d)(AutoMode=%d)\n",Orde.AutoBA, pAdapter->CommonCfg.BACapability.field.Policy, - pAdapter->CommonCfg.BACapability.field.RxBAWinLimit,pAdapter->CommonCfg.BACapability.field.TxBAWinLimit, pAdapter->CommonCfg.BACapability.field.AutoBA)); - DBGPRINT(RT_DEBUG_TRACE, ("Set::(MimoPs = %d)(AmsduEnable = %d) (AmsduSize=%d)(MpduDensity=%d)\n",pAdapter->CommonCfg.DesiredHtPhy.MimoPs, pAdapter->CommonCfg.DesiredHtPhy.AmsduEnable, - pAdapter->CommonCfg.DesiredHtPhy.AmsduSize, pAdapter->CommonCfg.DesiredHtPhy.MpduDensity)); - } - - break; - case RT_OID_802_11_ADD_IMME_BA: - DBGPRINT(RT_DEBUG_TRACE, (" Set :: RT_OID_802_11_ADD_IMME_BA \n")); - if (wrq->u.data.length != sizeof(OID_ADD_BA_ENTRY)) - Status = -EINVAL; - else - { - UCHAR index; - OID_ADD_BA_ENTRY BA; - MAC_TABLE_ENTRY *pEntry; - - Status = copy_from_user(&BA, wrq->u.data.pointer, wrq->u.data.length); - if (BA.TID > 15) - { - Status = NDIS_STATUS_INVALID_DATA; - break; - } - else - { - //BATableInsertEntry - //As ad-hoc mode, BA pair is not limited to only BSSID. so add via OID. - index = BA.TID; - // in ad hoc mode, when adding BA pair, we should insert this entry into MACEntry too - pEntry = MacTableLookup(pAdapter, BA.MACAddr); - if (!pEntry) - { - DBGPRINT(RT_DEBUG_TRACE, ("RT_OID_802_11_ADD_IMME_BA. break on no connection.----:%x:%x\n", BA.MACAddr[4], BA.MACAddr[5])); - break; - } - if (BA.IsRecipient == FALSE) - { - if (pEntry->bIAmBadAtheros == TRUE) - pAdapter->CommonCfg.BACapability.field.RxBAWinLimit = 0x10; - - BAOriSessionSetUp(pAdapter, pEntry, index, 0, 100, TRUE); - } - else - { - //BATableInsertEntry(pAdapter, pEntry->Aid, BA.MACAddr, 0, 0xffff, BA.TID, BA.nMSDU, BA.IsRecipient); - } - - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_ADD_IMME_BA. Rec = %d. Mac = %x:%x:%x:%x:%x:%x . \n", - BA.IsRecipient, BA.MACAddr[0], BA.MACAddr[1], BA.MACAddr[2], BA.MACAddr[2] - , BA.MACAddr[4], BA.MACAddr[5])); - } - } - break; - - case RT_OID_802_11_TEAR_IMME_BA: - DBGPRINT(RT_DEBUG_TRACE, ("Set :: RT_OID_802_11_TEAR_IMME_BA \n")); - if (wrq->u.data.length != sizeof(OID_ADD_BA_ENTRY)) - Status = -EINVAL; - else - { - POID_ADD_BA_ENTRY pBA; - MAC_TABLE_ENTRY *pEntry; - - pBA = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); - - if (pBA == NULL) - { - DBGPRINT(RT_DEBUG_TRACE, ("Set :: RT_OID_802_11_TEAR_IMME_BA kmalloc() can't allocate enough memory\n")); - Status = NDIS_STATUS_FAILURE; - } - else - { - Status = copy_from_user(pBA, wrq->u.data.pointer, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Set :: RT_OID_802_11_TEAR_IMME_BA(TID=%d, bAllTid=%d)\n", pBA->TID, pBA->bAllTid)); - - if (!pBA->bAllTid && (pBA->TID > NUM_OF_TID)) - { - Status = NDIS_STATUS_INVALID_DATA; - break; - } - - if (pBA->IsRecipient == FALSE) - { - pEntry = MacTableLookup(pAdapter, pBA->MACAddr); - DBGPRINT(RT_DEBUG_TRACE, (" pBA->IsRecipient == FALSE\n")); - if (pEntry) - { - DBGPRINT(RT_DEBUG_TRACE, (" pBA->pEntry\n")); - BAOriSessionTearDown(pAdapter, pEntry->Aid, pBA->TID, FALSE, TRUE); - } - else - DBGPRINT(RT_DEBUG_TRACE, ("Set :: Not found pEntry \n")); - } - else - { - pEntry = MacTableLookup(pAdapter, pBA->MACAddr); - if (pEntry) - { - BARecSessionTearDown( pAdapter, (UCHAR)pEntry->Aid, pBA->TID, TRUE); - } - else - DBGPRINT(RT_DEBUG_TRACE, ("Set :: Not found pEntry \n")); - } - kfree(pBA); - } - } - break; -#endif // DOT11_N_SUPPORT // - - // For WPA_SUPPLICANT to set static wep key - case OID_802_11_ADD_WEP: - pWepKey = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); - - if(pWepKey == NULL) - { - Status = -ENOMEM; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_WEP, Failed!!\n")); - break; - } - Status = copy_from_user(pWepKey, wrq->u.data.pointer, wrq->u.data.length); - if (Status) - { - Status = -EINVAL; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_WEP, Failed (length mismatch)!!\n")); - } - else - { - KeyIdx = pWepKey->KeyIndex & 0x0fffffff; - // KeyIdx must be 0 ~ 3 - if (KeyIdx > 4) - { - Status = -EINVAL; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_WEP, Failed (KeyIdx must be smaller than 4)!!\n")); - } - else - { - UCHAR CipherAlg = 0; - PUCHAR Key; - - // set key material and key length - NdisZeroMemory(pAdapter->SharedKey[BSS0][KeyIdx].Key, 16); - pAdapter->SharedKey[BSS0][KeyIdx].KeyLen = (UCHAR) pWepKey->KeyLength; - NdisMoveMemory(pAdapter->SharedKey[BSS0][KeyIdx].Key, &pWepKey->KeyMaterial, pWepKey->KeyLength); - - switch(pWepKey->KeyLength) - { - case 5: - CipherAlg = CIPHER_WEP64; - break; - case 13: - CipherAlg = CIPHER_WEP128; - break; - default: - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_WEP, only support CIPHER_WEP64(len:5) & CIPHER_WEP128(len:13)!!\n")); - Status = -EINVAL; - break; - } - pAdapter->SharedKey[BSS0][KeyIdx].CipherAlg = CipherAlg; - - // Default key for tx (shared key) - if (pWepKey->KeyIndex & 0x80000000) - { -#ifdef WPA_SUPPLICANT_SUPPORT - // set key material and key length - NdisZeroMemory(pAdapter->StaCfg.DesireSharedKey[KeyIdx].Key, 16); - pAdapter->StaCfg.DesireSharedKey[KeyIdx].KeyLen = (UCHAR) pWepKey->KeyLength; - NdisMoveMemory(pAdapter->StaCfg.DesireSharedKey[KeyIdx].Key, &pWepKey->KeyMaterial, pWepKey->KeyLength); - pAdapter->StaCfg.DesireSharedKeyId = KeyIdx; - pAdapter->StaCfg.DesireSharedKey[KeyIdx].CipherAlg = CipherAlg; -#endif // WPA_SUPPLICANT_SUPPORT // - pAdapter->StaCfg.DefaultKeyId = (UCHAR) KeyIdx; - } - -#ifdef WPA_SUPPLICANT_SUPPORT - if ((pAdapter->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_DISABLE) && - (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA)) - { - Key = pWepKey->KeyMaterial; - - // Set Group key material to Asic - AsicAddSharedKeyEntry(pAdapter, BSS0, KeyIdx, CipherAlg, Key, NULL, NULL); - - // Update WCID attribute table and IVEIV table for this group key table - RTMPAddWcidAttributeEntry(pAdapter, BSS0, KeyIdx, CipherAlg, NULL); - - STA_PORT_SECURED(pAdapter); - - // Indicate Connected for GUI - pAdapter->IndicateMediaState = NdisMediaStateConnected; - } - else if (pAdapter->StaCfg.PortSecured == WPA_802_1X_PORT_SECURED) -#endif // WPA_SUPPLICANT_SUPPORT - { - Key = pAdapter->SharedKey[BSS0][KeyIdx].Key; - - // Set key material and cipherAlg to Asic - AsicAddSharedKeyEntry(pAdapter, BSS0, KeyIdx, CipherAlg, Key, NULL, NULL); - - if (pWepKey->KeyIndex & 0x80000000) - { - PMAC_TABLE_ENTRY pEntry = &pAdapter->MacTab.Content[BSSID_WCID]; - // Assign group key info - RTMPAddWcidAttributeEntry(pAdapter, BSS0, KeyIdx, CipherAlg, NULL); - // Assign pairwise key info - RTMPAddWcidAttributeEntry(pAdapter, BSS0, KeyIdx, CipherAlg, pEntry); - } - } - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_WEP (id=0x%x, Len=%d-byte), %s\n", pWepKey->KeyIndex, pWepKey->KeyLength, (pAdapter->StaCfg.PortSecured == WPA_802_1X_PORT_SECURED) ? "Port Secured":"Port NOT Secured")); - } - } - kfree(pWepKey); - break; -#ifdef WPA_SUPPLICANT_SUPPORT - case OID_SET_COUNTERMEASURES: - if (wrq->u.data.length != sizeof(int)) - Status = -EINVAL; - else - { - int enabled = 0; - Status = copy_from_user(&enabled, wrq->u.data.pointer, wrq->u.data.length); - if (enabled == 1) - pAdapter->StaCfg.bBlockAssoc = TRUE; - else - // WPA MIC error should block association attempt for 60 seconds - pAdapter->StaCfg.bBlockAssoc = FALSE; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_SET_COUNTERMEASURES bBlockAssoc=%s\n", pAdapter->StaCfg.bBlockAssoc ? "TRUE":"FALSE")); - } - break; - case RT_OID_WPA_SUPPLICANT_SUPPORT: - if (wrq->u.data.length != sizeof(UCHAR)) - Status = -EINVAL; - else - { - Status = copy_from_user(&wpa_supplicant_enable, wrq->u.data.pointer, wrq->u.data.length); - pAdapter->StaCfg.WpaSupplicantUP = wpa_supplicant_enable; - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_WPA_SUPPLICANT_SUPPORT (=%d)\n", pAdapter->StaCfg.WpaSupplicantUP)); - } - break; - case OID_802_11_DEAUTHENTICATION: - if (wrq->u.data.length != sizeof(MLME_DEAUTH_REQ_STRUCT)) - Status = -EINVAL; - else - { - MLME_DEAUTH_REQ_STRUCT *pInfo; - MLME_QUEUE_ELEM *MsgElem = (MLME_QUEUE_ELEM *) kmalloc(sizeof(MLME_QUEUE_ELEM), MEM_ALLOC_FLAG); - - pInfo = (MLME_DEAUTH_REQ_STRUCT *) MsgElem->Msg; - Status = copy_from_user(pInfo, wrq->u.data.pointer, wrq->u.data.length); - MlmeDeauthReqAction(pAdapter, MsgElem); - kfree(MsgElem); - - if (INFRA_ON(pAdapter)) - { - LinkDown(pAdapter, FALSE); - pAdapter->Mlme.AssocMachine.CurrState = ASSOC_IDLE; - } - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_DEAUTHENTICATION (Reason=%d)\n", pInfo->Reason)); - } - break; - case OID_802_11_DROP_UNENCRYPTED: - if (wrq->u.data.length != sizeof(int)) - Status = -EINVAL; - else - { - int enabled = 0; - Status = copy_from_user(&enabled, wrq->u.data.pointer, wrq->u.data.length); - if (enabled == 1) - pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; - else - pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; - NdisAcquireSpinLock(&pAdapter->MacTabLock); - pAdapter->MacTab.Content[BSSID_WCID].PortSecured = pAdapter->StaCfg.PortSecured; - NdisReleaseSpinLock(&pAdapter->MacTabLock); - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_DROP_UNENCRYPTED (=%d)\n", enabled)); - } - break; - case OID_802_11_SET_IEEE8021X: - if (wrq->u.data.length != sizeof(BOOLEAN)) - Status = -EINVAL; - else - { - Status = copy_from_user(&IEEE8021xState, wrq->u.data.pointer, wrq->u.data.length); - pAdapter->StaCfg.IEEE8021X = IEEE8021xState; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_SET_IEEE8021X (=%d)\n", IEEE8021xState)); - } - break; - case OID_802_11_SET_IEEE8021X_REQUIRE_KEY: - if (wrq->u.data.length != sizeof(BOOLEAN)) - Status = -EINVAL; - else - { - Status = copy_from_user(&IEEE8021x_required_keys, wrq->u.data.pointer, wrq->u.data.length); - pAdapter->StaCfg.IEEE8021x_required_keys = IEEE8021x_required_keys; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_SET_IEEE8021X_REQUIRE_KEY (%d)\n", IEEE8021x_required_keys)); - } - break; - case OID_802_11_PMKID: - pPmkId = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); - - if(pPmkId == NULL) { - Status = -ENOMEM; - break; - } - Status = copy_from_user(pPmkId, wrq->u.data.pointer, wrq->u.data.length); - - // check the PMKID information - if (pPmkId->BSSIDInfoCount == 0) - NdisZeroMemory(pAdapter->StaCfg.SavedPMK, sizeof(BSSID_INFO)*PMKID_NO); - else - { - PBSSID_INFO pBssIdInfo; - UINT BssIdx; - UINT CachedIdx; - - for (BssIdx = 0; BssIdx < pPmkId->BSSIDInfoCount; BssIdx++) - { - // point to the indexed BSSID_INFO structure - pBssIdInfo = (PBSSID_INFO) ((PUCHAR) pPmkId + 2 * sizeof(UINT) + BssIdx * sizeof(BSSID_INFO)); - // Find the entry in the saved data base. - for (CachedIdx = 0; CachedIdx < pAdapter->StaCfg.SavedPMKNum; CachedIdx++) - { - // compare the BSSID - if (NdisEqualMemory(pBssIdInfo->BSSID, pAdapter->StaCfg.SavedPMK[CachedIdx].BSSID, sizeof(NDIS_802_11_MAC_ADDRESS))) - break; - } - - // Found, replace it - if (CachedIdx < PMKID_NO) - { - DBGPRINT(RT_DEBUG_OFF, ("Update OID_802_11_PMKID, idx = %d\n", CachedIdx)); - NdisMoveMemory(&pAdapter->StaCfg.SavedPMK[CachedIdx], pBssIdInfo, sizeof(BSSID_INFO)); - pAdapter->StaCfg.SavedPMKNum++; - } - // Not found, replace the last one - else - { - // Randomly replace one - CachedIdx = (pBssIdInfo->BSSID[5] % PMKID_NO); - DBGPRINT(RT_DEBUG_OFF, ("Update OID_802_11_PMKID, idx = %d\n", CachedIdx)); - NdisMoveMemory(&pAdapter->StaCfg.SavedPMK[CachedIdx], pBssIdInfo, sizeof(BSSID_INFO)); - } - } - } - if(pPmkId) - kfree(pPmkId); - break; -#endif // WPA_SUPPLICANT_SUPPORT // - - - -#ifdef SNMP_SUPPORT - case OID_802_11_SHORTRETRYLIMIT: - if (wrq->u.data.length != sizeof(ULONG)) - Status = -EINVAL; - else - { - Status = copy_from_user(&ShortRetryLimit, wrq->u.data.pointer, wrq->u.data.length); - RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); - tx_rty_cfg.field.ShortRtyLimit = ShortRetryLimit; - RTMP_IO_WRITE32(pAdapter, TX_RTY_CFG, tx_rty_cfg.word); - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_SHORTRETRYLIMIT (tx_rty_cfg.field.ShortRetryLimit=%d, ShortRetryLimit=%ld)\n", tx_rty_cfg.field.ShortRtyLimit, ShortRetryLimit)); - } - break; - - case OID_802_11_LONGRETRYLIMIT: - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_LONGRETRYLIMIT \n")); - if (wrq->u.data.length != sizeof(ULONG)) - Status = -EINVAL; - else - { - Status = copy_from_user(&LongRetryLimit, wrq->u.data.pointer, wrq->u.data.length); - RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); - tx_rty_cfg.field.LongRtyLimit = LongRetryLimit; - RTMP_IO_WRITE32(pAdapter, TX_RTY_CFG, tx_rty_cfg.word); - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_LONGRETRYLIMIT (tx_rty_cfg.field.LongRetryLimit= %d,LongRetryLimit=%ld)\n", tx_rty_cfg.field.LongRtyLimit, LongRetryLimit)); - } - break; - - case OID_802_11_WEPDEFAULTKEYVALUE: - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_WEPDEFAULTKEYVALUE\n")); - pKey = kmalloc(wrq->u.data.length, GFP_KERNEL); - Status = copy_from_user(pKey, wrq->u.data.pointer, wrq->u.data.length); - //pKey = &WepKey; - - if ( pKey->Length != wrq->u.data.length) - { - Status = -EINVAL; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_WEPDEFAULTKEYVALUE, Failed!!\n")); - } - KeyIdx = pKey->KeyIndex & 0x0fffffff; - DBGPRINT(RT_DEBUG_TRACE,("pKey->KeyIndex =%d, pKey->KeyLength=%d\n", pKey->KeyIndex, pKey->KeyLength)); - - // it is a shared key - if (KeyIdx > 4) - Status = -EINVAL; - else - { - pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen = (UCHAR) pKey->KeyLength; - NdisMoveMemory(&pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].Key, &pKey->KeyMaterial, pKey->KeyLength); - if (pKey->KeyIndex & 0x80000000) - { - // Default key for tx (shared key) - pAdapter->StaCfg.DefaultKeyId = (UCHAR) KeyIdx; - } - //RestartAPIsRequired = TRUE; - } - break; - - - case OID_802_11_WEPDEFAULTKEYID: - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_WEPDEFAULTKEYID \n")); - - if (wrq->u.data.length != sizeof(UCHAR)) - Status = -EINVAL; - else - Status = copy_from_user(&pAdapter->StaCfg.DefaultKeyId, wrq->u.data.pointer, wrq->u.data.length); - - break; - - - case OID_802_11_CURRENTCHANNEL: - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_CURRENTCHANNEL \n")); - if (wrq->u.data.length != sizeof(UCHAR)) - Status = -EINVAL; - else - { - Status = copy_from_user(&ctmp, wrq->u.data.pointer, wrq->u.data.length); - sprintf(&ctmp,"%d", ctmp); - Set_Channel_Proc(pAdapter, &ctmp); - } - break; -#endif - - - - default: - DBGPRINT(RT_DEBUG_TRACE, ("Set::unknown IOCTL's subcmd = 0x%08x\n", cmd)); - Status = -EOPNOTSUPP; - break; - } - - - return Status; -} - -INT RTMPQueryInformation( - IN PRTMP_ADAPTER pAdapter, - IN OUT struct ifreq *rq, - IN INT cmd) -{ - struct iwreq *wrq = (struct iwreq *) rq; - NDIS_802_11_BSSID_LIST_EX *pBssidList = NULL; - PNDIS_WLAN_BSSID_EX pBss; - NDIS_802_11_SSID Ssid; - NDIS_802_11_CONFIGURATION *pConfiguration = NULL; - RT_802_11_LINK_STATUS *pLinkStatus = NULL; - RT_802_11_STA_CONFIG *pStaConfig = NULL; - NDIS_802_11_STATISTICS *pStatistics = NULL; - NDIS_802_11_RTS_THRESHOLD RtsThresh; - NDIS_802_11_FRAGMENTATION_THRESHOLD FragThresh; - NDIS_802_11_POWER_MODE PowerMode; - NDIS_802_11_NETWORK_INFRASTRUCTURE BssType; - RT_802_11_PREAMBLE PreamType; - NDIS_802_11_AUTHENTICATION_MODE AuthMode; - NDIS_802_11_WEP_STATUS WepStatus; - NDIS_MEDIA_STATE MediaState; - ULONG BssBufSize, ulInfo=0, NetworkTypeList[4], apsd = 0; - USHORT BssLen = 0; - PUCHAR pBuf = NULL, pPtr; - INT Status = NDIS_STATUS_SUCCESS; - UINT we_version_compiled; - UCHAR i, Padding = 0; - BOOLEAN RadioState; - UCHAR driverVersion[8]; - OID_SET_HT_PHYMODE *pHTPhyMode = NULL; - - -#ifdef SNMP_SUPPORT - //for snmp, kathy - DefaultKeyIdxValue *pKeyIdxValue; - INT valueLen; - TX_RTY_CFG_STRUC tx_rty_cfg; - ULONG ShortRetryLimit, LongRetryLimit; - UCHAR tmp[64]; -#endif //SNMP - - switch(cmd) - { - case RT_OID_DEVICE_NAME: - wrq->u.data.length = sizeof(STA_NIC_DEVICE_NAME); - Status = copy_to_user(wrq->u.data.pointer, STA_NIC_DEVICE_NAME, wrq->u.data.length); - break; - case RT_OID_VERSION_INFO: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_VERSION_INFO \n")); - wrq->u.data.length = 8*sizeof(UCHAR); - sprintf(&driverVersion[0], "%s", STA_DRIVER_VERSION); - driverVersion[7] = '\0'; - if (copy_to_user(wrq->u.data.pointer, &driverVersion, wrq->u.data.length)) - { - Status = -EFAULT; - } - break; -#ifdef RALINK_ATE - case RT_QUERY_ATE_TXDONE_COUNT: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_QUERY_ATE_TXDONE_COUNT \n")); - wrq->u.data.length = sizeof(UINT32); - if (copy_to_user(wrq->u.data.pointer, &pAdapter->ate.TxDoneCount, wrq->u.data.length)) - { - Status = -EFAULT; - } - break; -#endif // RALINK_ATE // - case OID_802_11_BSSID_LIST: - if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) - { - /* - * Still scanning, indicate the caller should try again. - */ - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_BSSID_LIST (Still scanning)\n")); - return -EAGAIN; - } - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_BSSID_LIST (%d BSS returned)\n",pAdapter->ScanTab.BssNr)); - pAdapter->StaCfg.bScanReqIsFromWebUI = FALSE; - // Claculate total buffer size required - BssBufSize = sizeof(ULONG); - - for (i = 0; i < pAdapter->ScanTab.BssNr; i++) - { - // Align pointer to 4 bytes boundary. - //Padding = 4 - (pAdapter->ScanTab.BssEntry[i].VarIELen & 0x0003); - //if (Padding == 4) - // Padding = 0; - BssBufSize += (sizeof(NDIS_WLAN_BSSID_EX) - 1 + sizeof(NDIS_802_11_FIXED_IEs) + pAdapter->ScanTab.BssEntry[i].VarIELen + Padding); - } - - // For safety issue, we add 256 bytes just in case - BssBufSize += 256; - // Allocate the same size as passed from higher layer - pBuf = kmalloc(BssBufSize, MEM_ALLOC_FLAG); - if(pBuf == NULL) - { - Status = -ENOMEM; - break; - } - // Init 802_11_BSSID_LIST_EX structure - NdisZeroMemory(pBuf, BssBufSize); - pBssidList = (PNDIS_802_11_BSSID_LIST_EX) pBuf; - pBssidList->NumberOfItems = pAdapter->ScanTab.BssNr; - - // Calculate total buffer length - BssLen = 4; // Consist of NumberOfItems - // Point to start of NDIS_WLAN_BSSID_EX - // pPtr = pBuf + sizeof(ULONG); - pPtr = (PUCHAR) &pBssidList->Bssid[0]; - for (i = 0; i < pAdapter->ScanTab.BssNr; i++) - { - pBss = (PNDIS_WLAN_BSSID_EX) pPtr; - NdisMoveMemory(&pBss->MacAddress, &pAdapter->ScanTab.BssEntry[i].Bssid, MAC_ADDR_LEN); - if ((pAdapter->ScanTab.BssEntry[i].Hidden == 1) && (pAdapter->StaCfg.bShowHiddenSSID == FALSE)) - { - // - // We must return this SSID during 4way handshaking, otherwise Aegis will failed to parse WPA infomation - // and then failed to send EAPOl farame. - // - if ((pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) && (pAdapter->StaCfg.PortSecured != WPA_802_1X_PORT_SECURED)) - { - pBss->Ssid.SsidLength = pAdapter->ScanTab.BssEntry[i].SsidLen; - NdisMoveMemory(pBss->Ssid.Ssid, pAdapter->ScanTab.BssEntry[i].Ssid, pAdapter->ScanTab.BssEntry[i].SsidLen); - } - else - pBss->Ssid.SsidLength = 0; - } - else - { - pBss->Ssid.SsidLength = pAdapter->ScanTab.BssEntry[i].SsidLen; - NdisMoveMemory(pBss->Ssid.Ssid, pAdapter->ScanTab.BssEntry[i].Ssid, pAdapter->ScanTab.BssEntry[i].SsidLen); - } - pBss->Privacy = pAdapter->ScanTab.BssEntry[i].Privacy; - pBss->Rssi = pAdapter->ScanTab.BssEntry[i].Rssi - pAdapter->BbpRssiToDbmDelta; - pBss->NetworkTypeInUse = NetworkTypeInUseSanity(&pAdapter->ScanTab.BssEntry[i]); - pBss->Configuration.Length = sizeof(NDIS_802_11_CONFIGURATION); - pBss->Configuration.BeaconPeriod = pAdapter->ScanTab.BssEntry[i].BeaconPeriod; - pBss->Configuration.ATIMWindow = pAdapter->ScanTab.BssEntry[i].AtimWin; - - MAP_CHANNEL_ID_TO_KHZ(pAdapter->ScanTab.BssEntry[i].Channel, pBss->Configuration.DSConfig); - - if (pAdapter->ScanTab.BssEntry[i].BssType == BSS_INFRA) - pBss->InfrastructureMode = Ndis802_11Infrastructure; - else - pBss->InfrastructureMode = Ndis802_11IBSS; - - NdisMoveMemory(pBss->SupportedRates, pAdapter->ScanTab.BssEntry[i].SupRate, pAdapter->ScanTab.BssEntry[i].SupRateLen); - NdisMoveMemory(pBss->SupportedRates + pAdapter->ScanTab.BssEntry[i].SupRateLen, - pAdapter->ScanTab.BssEntry[i].ExtRate, - pAdapter->ScanTab.BssEntry[i].ExtRateLen); - - if (pAdapter->ScanTab.BssEntry[i].VarIELen == 0) - { - pBss->IELength = sizeof(NDIS_802_11_FIXED_IEs); - NdisMoveMemory(pBss->IEs, &pAdapter->ScanTab.BssEntry[i].FixIEs, sizeof(NDIS_802_11_FIXED_IEs)); - pPtr = pPtr + sizeof(NDIS_WLAN_BSSID_EX) - 1 + sizeof(NDIS_802_11_FIXED_IEs); - } - else - { - pBss->IELength = (ULONG)(sizeof(NDIS_802_11_FIXED_IEs) + pAdapter->ScanTab.BssEntry[i].VarIELen); - pPtr = pPtr + sizeof(NDIS_WLAN_BSSID_EX) - 1 + sizeof(NDIS_802_11_FIXED_IEs); - NdisMoveMemory(pBss->IEs, &pAdapter->ScanTab.BssEntry[i].FixIEs, sizeof(NDIS_802_11_FIXED_IEs)); - NdisMoveMemory(pBss->IEs + sizeof(NDIS_802_11_FIXED_IEs), pAdapter->ScanTab.BssEntry[i].VarIEs, pAdapter->ScanTab.BssEntry[i].VarIELen); - pPtr += pAdapter->ScanTab.BssEntry[i].VarIELen; - } - pBss->Length = (ULONG)(sizeof(NDIS_WLAN_BSSID_EX) - 1 + sizeof(NDIS_802_11_FIXED_IEs) + pAdapter->ScanTab.BssEntry[i].VarIELen + Padding); - -#if WIRELESS_EXT < 17 - if ((BssLen + pBss->Length) < wrq->u.data.length) - BssLen += pBss->Length; - else - { - pBssidList->NumberOfItems = i; - break; - } -#else - BssLen += pBss->Length; -#endif - } - -#if WIRELESS_EXT < 17 - wrq->u.data.length = BssLen; -#else - if (BssLen > wrq->u.data.length) - { - kfree(pBssidList); - return -E2BIG; - } - else - wrq->u.data.length = BssLen; -#endif - Status = copy_to_user(wrq->u.data.pointer, pBssidList, BssLen); - kfree(pBssidList); - break; - case OID_802_3_CURRENT_ADDRESS: - wrq->u.data.length = MAC_ADDR_LEN; - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CurrentAddress, wrq->u.data.length); - break; - case OID_GEN_MEDIA_CONNECT_STATUS: - if (pAdapter->IndicateMediaState == NdisMediaStateConnected) - MediaState = NdisMediaStateConnected; - else - MediaState = NdisMediaStateDisconnected; - - wrq->u.data.length = sizeof(NDIS_MEDIA_STATE); - Status = copy_to_user(wrq->u.data.pointer, &MediaState, wrq->u.data.length); - break; - case OID_802_11_BSSID: -#ifdef RALINK_ATE - if (ATE_ON(pAdapter)) - { - DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now\n")); - Status = NDIS_STATUS_RESOURCES; - break; - } -#endif // RALINK_ATE // - if (INFRA_ON(pAdapter) || ADHOC_ON(pAdapter)) - { - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.Bssid, sizeof(NDIS_802_11_MAC_ADDRESS)); - - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_BSSID(=EMPTY)\n")); - Status = -ENOTCONN; - } - break; - case OID_802_11_SSID: - NdisZeroMemory(&Ssid, sizeof(NDIS_802_11_SSID)); - NdisZeroMemory(Ssid.Ssid, MAX_LEN_OF_SSID); - Ssid.SsidLength = pAdapter->CommonCfg.SsidLen; - memcpy(Ssid.Ssid, pAdapter->CommonCfg.Ssid, Ssid.SsidLength); - wrq->u.data.length = sizeof(NDIS_802_11_SSID); - Status = copy_to_user(wrq->u.data.pointer, &Ssid, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_SSID (Len=%d, ssid=%s)\n", Ssid.SsidLength,Ssid.Ssid)); - break; - case RT_OID_802_11_QUERY_LINK_STATUS: - pLinkStatus = (RT_802_11_LINK_STATUS *) kmalloc(sizeof(RT_802_11_LINK_STATUS), MEM_ALLOC_FLAG); - if (pLinkStatus) - { - pLinkStatus->CurrTxRate = RateIdTo500Kbps[pAdapter->CommonCfg.TxRate]; // unit : 500 kbps - pLinkStatus->ChannelQuality = pAdapter->Mlme.ChannelQuality; - pLinkStatus->RxByteCount = pAdapter->RalinkCounters.ReceivedByteCount; - pLinkStatus->TxByteCount = pAdapter->RalinkCounters.TransmittedByteCount; - pLinkStatus->CentralChannel = pAdapter->CommonCfg.CentralChannel; - wrq->u.data.length = sizeof(RT_802_11_LINK_STATUS); - Status = copy_to_user(wrq->u.data.pointer, pLinkStatus, wrq->u.data.length); - kfree(pLinkStatus); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_LINK_STATUS\n")); - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_LINK_STATUS(kmalloc failed)\n")); - Status = -EFAULT; - } - break; - case OID_802_11_CONFIGURATION: - pConfiguration = (NDIS_802_11_CONFIGURATION *) kmalloc(sizeof(NDIS_802_11_CONFIGURATION), MEM_ALLOC_FLAG); - if (pConfiguration) - { - pConfiguration->Length = sizeof(NDIS_802_11_CONFIGURATION); - pConfiguration->BeaconPeriod = pAdapter->CommonCfg.BeaconPeriod; - pConfiguration->ATIMWindow = pAdapter->StaActive.AtimWin; - MAP_CHANNEL_ID_TO_KHZ(pAdapter->CommonCfg.Channel, pConfiguration->DSConfig); - wrq->u.data.length = sizeof(NDIS_802_11_CONFIGURATION); - Status = copy_to_user(wrq->u.data.pointer, pConfiguration, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_CONFIGURATION(BeaconPeriod=%ld,AtimW=%ld,Channel=%d) \n", - pConfiguration->BeaconPeriod, pConfiguration->ATIMWindow, pAdapter->CommonCfg.Channel)); - kfree(pConfiguration); - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_CONFIGURATION(kmalloc failed)\n")); - Status = -EFAULT; - } - break; - case RT_OID_802_11_SNR_0: - if ((pAdapter->StaCfg.LastSNR0 > 0)) - { - ulInfo = ((0xeb - pAdapter->StaCfg.LastSNR0) * 3) / 16 ; - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_SNR_0(0x=%lx)\n", ulInfo)); - } - else - Status = -EFAULT; - break; - case RT_OID_802_11_SNR_1: - if ((pAdapter->Antenna.field.RxPath > 1) && - (pAdapter->StaCfg.LastSNR1 > 0)) - { - ulInfo = ((0xeb - pAdapter->StaCfg.LastSNR1) * 3) / 16 ; - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE,("Query::RT_OID_802_11_SNR_1(0x=%lx)\n",ulInfo)); - } - else - Status = -EFAULT; - DBGPRINT(RT_DEBUG_TRACE,("Query::RT_OID_802_11_SNR_1(pAdapter->StaCfg.LastSNR1=%d)\n",pAdapter->StaCfg.LastSNR1)); - break; - case OID_802_11_RSSI_TRIGGER: - ulInfo = pAdapter->StaCfg.RssiSample.LastRssi0 - pAdapter->BbpRssiToDbmDelta; - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_RSSI_TRIGGER(=%ld)\n", ulInfo)); - break; - case OID_802_11_RSSI: - case RT_OID_802_11_RSSI: - ulInfo = pAdapter->StaCfg.RssiSample.LastRssi0; - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - break; - case RT_OID_802_11_RSSI_1: - ulInfo = pAdapter->StaCfg.RssiSample.LastRssi1; - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - break; - case RT_OID_802_11_RSSI_2: - ulInfo = pAdapter->StaCfg.RssiSample.LastRssi2; - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - break; - case OID_802_11_STATISTICS: - pStatistics = (NDIS_802_11_STATISTICS *) kmalloc(sizeof(NDIS_802_11_STATISTICS), MEM_ALLOC_FLAG); - if (pStatistics) - { - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_STATISTICS \n")); - // add the most up-to-date h/w raw counters into software counters - NICUpdateRawCounters(pAdapter); - - // Sanity check for calculation of sucessful count - if (pAdapter->WlanCounters.TransmittedFragmentCount.QuadPart < pAdapter->WlanCounters.RetryCount.QuadPart) - pAdapter->WlanCounters.TransmittedFragmentCount.QuadPart = pAdapter->WlanCounters.RetryCount.QuadPart; - - pStatistics->TransmittedFragmentCount.QuadPart = pAdapter->WlanCounters.TransmittedFragmentCount.QuadPart; - pStatistics->MulticastTransmittedFrameCount.QuadPart = pAdapter->WlanCounters.MulticastTransmittedFrameCount.QuadPart; - pStatistics->FailedCount.QuadPart = pAdapter->WlanCounters.FailedCount.QuadPart; - pStatistics->RetryCount.QuadPart = pAdapter->WlanCounters.RetryCount.QuadPart; - pStatistics->MultipleRetryCount.QuadPart = pAdapter->WlanCounters.MultipleRetryCount.QuadPart; - pStatistics->RTSSuccessCount.QuadPart = pAdapter->WlanCounters.RTSSuccessCount.QuadPart; - pStatistics->RTSFailureCount.QuadPart = pAdapter->WlanCounters.RTSFailureCount.QuadPart; - pStatistics->ACKFailureCount.QuadPart = pAdapter->WlanCounters.ACKFailureCount.QuadPart; - pStatistics->FrameDuplicateCount.QuadPart = pAdapter->WlanCounters.FrameDuplicateCount.QuadPart; - pStatistics->ReceivedFragmentCount.QuadPart = pAdapter->WlanCounters.ReceivedFragmentCount.QuadPart; - pStatistics->MulticastReceivedFrameCount.QuadPart = pAdapter->WlanCounters.MulticastReceivedFrameCount.QuadPart; -#ifdef DBG - pStatistics->FCSErrorCount = pAdapter->RalinkCounters.RealFcsErrCount; -#else - pStatistics->FCSErrorCount.QuadPart = pAdapter->WlanCounters.FCSErrorCount.QuadPart; - pStatistics->FrameDuplicateCount.u.LowPart = pAdapter->WlanCounters.FrameDuplicateCount.u.LowPart / 100; -#endif - wrq->u.data.length = sizeof(NDIS_802_11_STATISTICS); - Status = copy_to_user(wrq->u.data.pointer, pStatistics, wrq->u.data.length); - kfree(pStatistics); - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_STATISTICS(kmalloc failed)\n")); - Status = -EFAULT; - } - break; - case OID_GEN_RCV_OK: - ulInfo = pAdapter->Counters8023.GoodReceives; - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - break; - case OID_GEN_RCV_NO_BUFFER: - ulInfo = pAdapter->Counters8023.RxNoBuffer; - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - break; - case RT_OID_802_11_PHY_MODE: - ulInfo = (ULONG)pAdapter->CommonCfg.PhyMode; - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_PHY_MODE (=%ld)\n", ulInfo)); - break; - case RT_OID_802_11_STA_CONFIG: - pStaConfig = (RT_802_11_STA_CONFIG *) kmalloc(sizeof(RT_802_11_STA_CONFIG), MEM_ALLOC_FLAG); - if (pStaConfig) - { - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_STA_CONFIG\n")); - pStaConfig->EnableTxBurst = pAdapter->CommonCfg.bEnableTxBurst; - pStaConfig->EnableTurboRate = 0; - pStaConfig->UseBGProtection = pAdapter->CommonCfg.UseBGProtection; - pStaConfig->UseShortSlotTime = pAdapter->CommonCfg.bUseShortSlotTime; - //pStaConfig->AdhocMode = pAdapter->StaCfg.AdhocMode; - pStaConfig->HwRadioStatus = (pAdapter->StaCfg.bHwRadio == TRUE) ? 1 : 0; - pStaConfig->Rsv1 = 0; - pStaConfig->SystemErrorBitmap = pAdapter->SystemErrorBitmap; - wrq->u.data.length = sizeof(RT_802_11_STA_CONFIG); - Status = copy_to_user(wrq->u.data.pointer, pStaConfig, wrq->u.data.length); - kfree(pStaConfig); - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_STA_CONFIG(kmalloc failed)\n")); - Status = -EFAULT; - } - break; - case OID_802_11_RTS_THRESHOLD: - RtsThresh = pAdapter->CommonCfg.RtsThreshold; - wrq->u.data.length = sizeof(RtsThresh); - Status = copy_to_user(wrq->u.data.pointer, &RtsThresh, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_RTS_THRESHOLD(=%ld)\n", RtsThresh)); - break; - case OID_802_11_FRAGMENTATION_THRESHOLD: - FragThresh = pAdapter->CommonCfg.FragmentThreshold; - if (pAdapter->CommonCfg.bUseZeroToDisableFragment == TRUE) - FragThresh = 0; - wrq->u.data.length = sizeof(FragThresh); - Status = copy_to_user(wrq->u.data.pointer, &FragThresh, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_FRAGMENTATION_THRESHOLD(=%ld)\n", FragThresh)); - break; - case OID_802_11_POWER_MODE: - PowerMode = pAdapter->StaCfg.WindowsPowerMode; - wrq->u.data.length = sizeof(PowerMode); - Status = copy_to_user(wrq->u.data.pointer, &PowerMode, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_POWER_MODE(=%d)\n", PowerMode)); - break; - case RT_OID_802_11_RADIO: - RadioState = (BOOLEAN) pAdapter->StaCfg.bSwRadio; - wrq->u.data.length = sizeof(RadioState); - Status = copy_to_user(wrq->u.data.pointer, &RadioState, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_RADIO (=%d)\n", RadioState)); - break; - case OID_802_11_INFRASTRUCTURE_MODE: - if (pAdapter->StaCfg.BssType == BSS_ADHOC) - BssType = Ndis802_11IBSS; - else if (pAdapter->StaCfg.BssType == BSS_INFRA) - BssType = Ndis802_11Infrastructure; - else if (pAdapter->StaCfg.BssType == BSS_MONITOR) - BssType = Ndis802_11Monitor; - else - BssType = Ndis802_11AutoUnknown; - - wrq->u.data.length = sizeof(BssType); - Status = copy_to_user(wrq->u.data.pointer, &BssType, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_INFRASTRUCTURE_MODE(=%d)\n", BssType)); - break; - case RT_OID_802_11_PREAMBLE: - PreamType = pAdapter->CommonCfg.TxPreamble; - wrq->u.data.length = sizeof(PreamType); - Status = copy_to_user(wrq->u.data.pointer, &PreamType, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_PREAMBLE(=%d)\n", PreamType)); - break; - case OID_802_11_AUTHENTICATION_MODE: - AuthMode = pAdapter->StaCfg.AuthMode; - wrq->u.data.length = sizeof(AuthMode); - Status = copy_to_user(wrq->u.data.pointer, &AuthMode, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_AUTHENTICATION_MODE(=%d)\n", AuthMode)); - break; - case OID_802_11_WEP_STATUS: - WepStatus = pAdapter->StaCfg.WepStatus; - wrq->u.data.length = sizeof(WepStatus); - Status = copy_to_user(wrq->u.data.pointer, &WepStatus, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_WEP_STATUS(=%d)\n", WepStatus)); - break; - case OID_802_11_TX_POWER_LEVEL: - wrq->u.data.length = sizeof(ULONG); - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.TxPower, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_TX_POWER_LEVEL %x\n",pAdapter->CommonCfg.TxPower)); - break; - case RT_OID_802_11_TX_POWER_LEVEL_1: - wrq->u.data.length = sizeof(ULONG); - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.TxPowerPercentage, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_TX_POWER_LEVEL_1 (=%ld)\n", pAdapter->CommonCfg.TxPowerPercentage)); - break; - case OID_802_11_NETWORK_TYPES_SUPPORTED: - if ((pAdapter->RfIcType == RFIC_2850) || (pAdapter->RfIcType == RFIC_2750)) - { - NetworkTypeList[0] = 3; // NumberOfItems = 3 - NetworkTypeList[1] = Ndis802_11DS; // NetworkType[1] = 11b - NetworkTypeList[2] = Ndis802_11OFDM24; // NetworkType[2] = 11g - NetworkTypeList[3] = Ndis802_11OFDM5; // NetworkType[3] = 11a - wrq->u.data.length = 16; - Status = copy_to_user(wrq->u.data.pointer, &NetworkTypeList[0], wrq->u.data.length); - } - else - { - NetworkTypeList[0] = 2; // NumberOfItems = 2 - NetworkTypeList[1] = Ndis802_11DS; // NetworkType[1] = 11b - NetworkTypeList[2] = Ndis802_11OFDM24; // NetworkType[2] = 11g - wrq->u.data.length = 12; - Status = copy_to_user(wrq->u.data.pointer, &NetworkTypeList[0], wrq->u.data.length); - } - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_NETWORK_TYPES_SUPPORTED\n")); - break; - case OID_802_11_NETWORK_TYPE_IN_USE: - wrq->u.data.length = sizeof(ULONG); - if (pAdapter->CommonCfg.PhyMode == PHY_11A) - ulInfo = Ndis802_11OFDM5; - else if ((pAdapter->CommonCfg.PhyMode == PHY_11BG_MIXED) || (pAdapter->CommonCfg.PhyMode == PHY_11G)) - ulInfo = Ndis802_11OFDM24; - else - ulInfo = Ndis802_11DS; - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - break; - case RT_OID_802_11_QUERY_LAST_RX_RATE: - ulInfo = (ULONG)pAdapter->LastRxRate; - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_LAST_RX_RATE (=%ld)\n", ulInfo)); - break; - case RT_OID_802_11_QUERY_LAST_TX_RATE: - //ulInfo = (ULONG)pAdapter->LastTxRate; - ulInfo = (ULONG)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.word; - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_LAST_TX_RATE (=%lx)\n", ulInfo)); - break; - case RT_OID_802_11_QUERY_EEPROM_VERSION: - wrq->u.data.length = sizeof(ULONG); - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->EepromVersion, wrq->u.data.length); - break; - case RT_OID_802_11_QUERY_FIRMWARE_VERSION: - wrq->u.data.length = sizeof(ULONG); - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->FirmwareVersion, wrq->u.data.length); - break; - case RT_OID_802_11_QUERY_NOISE_LEVEL: - wrq->u.data.length = sizeof(UCHAR); - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->BbpWriteLatch[66], wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_NOISE_LEVEL (=%d)\n", pAdapter->BbpWriteLatch[66])); - break; - case RT_OID_802_11_EXTRA_INFO: - wrq->u.data.length = sizeof(ULONG); - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->ExtraInfo, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_EXTRA_INFO (=%ld)\n", pAdapter->ExtraInfo)); - break; - case RT_OID_WE_VERSION_COMPILED: - wrq->u.data.length = sizeof(UINT); - we_version_compiled = WIRELESS_EXT; - Status = copy_to_user(wrq->u.data.pointer, &we_version_compiled, wrq->u.data.length); - break; - case RT_OID_802_11_QUERY_APSD_SETTING: - apsd = (pAdapter->CommonCfg.bAPSDCapable | (pAdapter->CommonCfg.bAPSDAC_BE << 1) | (pAdapter->CommonCfg.bAPSDAC_BK << 2) - | (pAdapter->CommonCfg.bAPSDAC_VI << 3) | (pAdapter->CommonCfg.bAPSDAC_VO << 4) | (pAdapter->CommonCfg.MaxSPLength << 5)); - - wrq->u.data.length = sizeof(ULONG); - Status = copy_to_user(wrq->u.data.pointer, &apsd, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_APSD_SETTING (=0x%lx,APSDCap=%d,AC_BE=%d,AC_BK=%d,AC_VI=%d,AC_VO=%d,MAXSPLen=%d)\n", - apsd,pAdapter->CommonCfg.bAPSDCapable,pAdapter->CommonCfg.bAPSDAC_BE,pAdapter->CommonCfg.bAPSDAC_BK,pAdapter->CommonCfg.bAPSDAC_VI,pAdapter->CommonCfg.bAPSDAC_VO,pAdapter->CommonCfg.MaxSPLength)); - break; - case RT_OID_802_11_QUERY_APSD_PSM: - wrq->u.data.length = sizeof(ULONG); - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.bAPSDForcePowerSave, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_APSD_PSM (=%d)\n", pAdapter->CommonCfg.bAPSDForcePowerSave)); - break; - case RT_OID_802_11_QUERY_WMM: - wrq->u.data.length = sizeof(BOOLEAN); - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.bWmmCapable, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_WMM (=%d)\n", pAdapter->CommonCfg.bWmmCapable)); - break; -#ifdef WPA_SUPPLICANT_SUPPORT - case RT_OID_NEW_DRIVER: - { - UCHAR enabled = 1; - wrq->u.data.length = sizeof(UCHAR); - Status = copy_to_user(wrq->u.data.pointer, &enabled, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_NEW_DRIVER (=%d)\n", enabled)); - } - break; - case RT_OID_WPA_SUPPLICANT_SUPPORT: - wrq->u.data.length = sizeof(UCHAR); - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->StaCfg.WpaSupplicantUP, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_WPA_SUPPLICANT_SUPPORT (=%d)\n", pAdapter->StaCfg.WpaSupplicantUP)); - break; -#endif // WPA_SUPPLICANT_SUPPORT // - - case RT_OID_DRIVER_DEVICE_NAME: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_DRIVER_DEVICE_NAME \n")); - wrq->u.data.length = 16; - if (copy_to_user(wrq->u.data.pointer, pAdapter->StaCfg.dev_name, wrq->u.data.length)) - { - Status = -EFAULT; - } - break; - case RT_OID_802_11_QUERY_HT_PHYMODE: - pHTPhyMode = (OID_SET_HT_PHYMODE *) kmalloc(sizeof(OID_SET_HT_PHYMODE), MEM_ALLOC_FLAG); - if (pHTPhyMode) - { - pHTPhyMode->PhyMode = pAdapter->CommonCfg.PhyMode; - pHTPhyMode->HtMode = (UCHAR)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.field.MODE; - pHTPhyMode->BW = (UCHAR)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.field.BW; - pHTPhyMode->MCS= (UCHAR)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.field.MCS; - pHTPhyMode->SHORTGI= (UCHAR)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.field.ShortGI; - pHTPhyMode->STBC= (UCHAR)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.field.STBC; - - pHTPhyMode->ExtOffset = ((pAdapter->CommonCfg.CentralChannel < pAdapter->CommonCfg.Channel) ? (EXTCHA_BELOW) : (EXTCHA_ABOVE)); - wrq->u.data.length = sizeof(OID_SET_HT_PHYMODE); - if (copy_to_user(wrq->u.data.pointer, pHTPhyMode, wrq->u.data.length)) - { - Status = -EFAULT; - } - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_HT_PHYMODE (PhyMode = %d, MCS =%d, BW = %d, STBC = %d, ExtOffset=%d)\n", - pHTPhyMode->HtMode, pHTPhyMode->MCS, pHTPhyMode->BW, pHTPhyMode->STBC, pHTPhyMode->ExtOffset)); - DBGPRINT(RT_DEBUG_TRACE, (" MlmeUpdateTxRates (.word = %x )\n", pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.word)); - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_STA_CONFIG(kmalloc failed)\n")); - Status = -EFAULT; - } - break; - case RT_OID_802_11_COUNTRY_REGION: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_COUNTRY_REGION \n")); - wrq->u.data.length = sizeof(ulInfo); - ulInfo = pAdapter->CommonCfg.CountryRegionForABand; - ulInfo = (ulInfo << 8)|(pAdapter->CommonCfg.CountryRegion); - if (copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length)) - { - Status = -EFAULT; - } - break; - case RT_OID_802_11_QUERY_DAT_HT_PHYMODE: - pHTPhyMode = (OID_SET_HT_PHYMODE *) kmalloc(sizeof(OID_SET_HT_PHYMODE), MEM_ALLOC_FLAG); - if (pHTPhyMode) - { - pHTPhyMode->PhyMode = pAdapter->CommonCfg.PhyMode; - pHTPhyMode->HtMode = (UCHAR)pAdapter->CommonCfg.RegTransmitSetting.field.HTMODE; - pHTPhyMode->BW = (UCHAR)pAdapter->CommonCfg.RegTransmitSetting.field.BW; - pHTPhyMode->MCS= (UCHAR)pAdapter->StaCfg.DesiredTransmitSetting.field.MCS; - pHTPhyMode->SHORTGI= (UCHAR)pAdapter->CommonCfg.RegTransmitSetting.field.ShortGI; - pHTPhyMode->STBC= (UCHAR)pAdapter->CommonCfg.RegTransmitSetting.field.STBC; - - wrq->u.data.length = sizeof(OID_SET_HT_PHYMODE); - if (copy_to_user(wrq->u.data.pointer, pHTPhyMode, wrq->u.data.length)) - { - Status = -EFAULT; - } - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_HT_PHYMODE (PhyMode = %d, MCS =%d, BW = %d, STBC = %d, ExtOffset=%d)\n", - pHTPhyMode->HtMode, pHTPhyMode->MCS, pHTPhyMode->BW, pHTPhyMode->STBC, pHTPhyMode->ExtOffset)); - DBGPRINT(RT_DEBUG_TRACE, (" MlmeUpdateTxRates (.word = %x )\n", pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.word)); - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_STA_CONFIG(kmalloc failed)\n")); - Status = -EFAULT; - } - break; - case RT_OID_QUERY_MULTIPLE_CARD_SUPPORT: - wrq->u.data.length = sizeof(UCHAR); - i = 0; -#ifdef MULTIPLE_CARD_SUPPORT - i = 1; -#endif // MULTIPLE_CARD_SUPPORT // - if (copy_to_user(wrq->u.data.pointer, &i, wrq->u.data.length)) - { - Status = -EFAULT; - } - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_QUERY_MULTIPLE_CARD_SUPPORT(=%d) \n", i)); - break; -#ifdef SNMP_SUPPORT - case RT_OID_802_11_MAC_ADDRESS: - wrq->u.data.length = MAC_ADDR_LEN; - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CurrentAddress, wrq->u.data.length); - break; - - case RT_OID_802_11_MANUFACTUREROUI: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_MANUFACTUREROUI \n")); - wrq->u.data.length = ManufacturerOUI_LEN; - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CurrentAddress, wrq->u.data.length); - break; - - case RT_OID_802_11_MANUFACTURERNAME: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_MANUFACTURERNAME \n")); - wrq->u.data.length = strlen(ManufacturerNAME); - Status = copy_to_user(wrq->u.data.pointer, ManufacturerNAME, wrq->u.data.length); - break; - - case RT_OID_802_11_RESOURCETYPEIDNAME: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_RESOURCETYPEIDNAME \n")); - wrq->u.data.length = strlen(ResourceTypeIdName); - Status = copy_to_user(wrq->u.data.pointer, ResourceTypeIdName, wrq->u.data.length); - break; - - case RT_OID_802_11_PRIVACYOPTIONIMPLEMENTED: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_PRIVACYOPTIONIMPLEMENTED \n")); - ulInfo = 1; // 1 is support wep else 2 is not support. - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - break; - - case RT_OID_802_11_POWERMANAGEMENTMODE: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_POWERMANAGEMENTMODE \n")); - if (pAdapter->StaCfg.Psm == PSMP_ACTION) - ulInfo = 1; // 1 is power active else 2 is power save. - else - ulInfo = 2; - - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - break; - - case OID_802_11_WEPDEFAULTKEYVALUE: - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_WEPDEFAULTKEYVALUE \n")); - //KeyIdxValue.KeyIdx = pAd->PortCfg.MBSSID[pAd->IoctlIF].DefaultKeyId; - pKeyIdxValue = wrq->u.data.pointer; - DBGPRINT(RT_DEBUG_TRACE,("KeyIdxValue.KeyIdx = %d, \n",pKeyIdxValue->KeyIdx)); - valueLen = pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen; - NdisMoveMemory(pKeyIdxValue->Value, - &pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].Key, - valueLen); - pKeyIdxValue->Value[valueLen]='\0'; - - wrq->u.data.length = sizeof(DefaultKeyIdxValue); - - Status = copy_to_user(wrq->u.data.pointer, pKeyIdxValue, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE,("DefaultKeyId = %d, total len = %d, str len=%d, KeyValue= %02x %02x %02x %02x \n", pAdapter->StaCfg.DefaultKeyId, wrq->u.data.length, pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen, - pAdapter->SharedKey[BSS0][0].Key[0], - pAdapter->SharedKey[BSS0][1].Key[0], - pAdapter->SharedKey[BSS0][2].Key[0], - pAdapter->SharedKey[BSS0][3].Key[0])); - break; - - case OID_802_11_WEPDEFAULTKEYID: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_WEPDEFAULTKEYID \n")); - wrq->u.data.length = sizeof(UCHAR); - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->StaCfg.DefaultKeyId, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("DefaultKeyId =%d \n", pAdapter->StaCfg.DefaultKeyId)); - break; - - case RT_OID_802_11_WEPKEYMAPPINGLENGTH: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_WEPKEYMAPPINGLENGTH \n")); - wrq->u.data.length = sizeof(UCHAR); - Status = copy_to_user(wrq->u.data.pointer, - &pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen, - wrq->u.data.length); - break; - - case OID_802_11_SHORTRETRYLIMIT: - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_SHORTRETRYLIMIT \n")); - wrq->u.data.length = sizeof(ULONG); - RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); - ShortRetryLimit = tx_rty_cfg.field.ShortRtyLimit; - DBGPRINT(RT_DEBUG_TRACE, ("ShortRetryLimit =%ld, tx_rty_cfg.field.ShortRetryLimit=%d\n", ShortRetryLimit, tx_rty_cfg.field.ShortRtyLimit)); - Status = copy_to_user(wrq->u.data.pointer, &ShortRetryLimit, wrq->u.data.length); - break; - - case OID_802_11_LONGRETRYLIMIT: - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_LONGRETRYLIMIT \n")); - wrq->u.data.length = sizeof(ULONG); - RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); - LongRetryLimit = tx_rty_cfg.field.LongRtyLimit; - DBGPRINT(RT_DEBUG_TRACE, ("LongRetryLimit =%ld, tx_rty_cfg.field.LongRtyLimit=%d\n", LongRetryLimit, tx_rty_cfg.field.LongRtyLimit)); - Status = copy_to_user(wrq->u.data.pointer, &LongRetryLimit, wrq->u.data.length); - break; - - case RT_OID_802_11_PRODUCTID: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_PRODUCTID \n")); - -#ifdef RT2870 - sprintf(tmp, "%04x %04x\n", ((POS_COOKIE)pAdapter->OS_Cookie)->pUsb_Dev->descriptor.idVendor ,((POS_COOKIE)pAdapter->OS_Cookie)->pUsb_Dev->descriptor.idProduct); - -#endif // RT2870 // - wrq->u.data.length = strlen(tmp); - Status = copy_to_user(wrq->u.data.pointer, tmp, wrq->u.data.length); - break; - - case RT_OID_802_11_MANUFACTUREID: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_MANUFACTUREID \n")); - wrq->u.data.length = strlen(ManufacturerNAME); - Status = copy_to_user(wrq->u.data.pointer, ManufacturerNAME, wrq->u.data.length); - break; - - case OID_802_11_CURRENTCHANNEL: - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_CURRENTCHANNEL \n")); - wrq->u.data.length = sizeof(UCHAR); - DBGPRINT(RT_DEBUG_TRACE, ("sizeof UCHAR=%d, channel=%d \n", sizeof(UCHAR), pAdapter->CommonCfg.Channel)); - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.Channel, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Status=%d\n", Status)); - break; -#endif //SNMP_SUPPORT - - case OID_802_11_BUILD_CHANNEL_EX: - { - UCHAR value; - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_BUILD_CHANNEL_EX \n")); - wrq->u.data.length = sizeof(UCHAR); -#ifdef EXT_BUILD_CHANNEL_LIST - DBGPRINT(RT_DEBUG_TRACE, ("Support EXT_BUILD_CHANNEL_LIST.\n")); - value = 1; -#else - DBGPRINT(RT_DEBUG_TRACE, ("Doesn't support EXT_BUILD_CHANNEL_LIST.\n")); - value = 0; -#endif // EXT_BUILD_CHANNEL_LIST // - Status = copy_to_user(wrq->u.data.pointer, &value, 1); - DBGPRINT(RT_DEBUG_TRACE, ("Status=%d\n", Status)); - } - break; - - case OID_802_11_GET_CH_LIST: - { - PRT_CHANNEL_LIST_INFO pChListBuf; - - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_GET_CH_LIST \n")); - if (pAdapter->ChannelListNum == 0) - { - wrq->u.data.length = 0; - break; - } - - pChListBuf = (RT_CHANNEL_LIST_INFO *) kmalloc(sizeof(RT_CHANNEL_LIST_INFO), MEM_ALLOC_FLAG); - if (pChListBuf == NULL) - { - wrq->u.data.length = 0; - break; - } - - pChListBuf->ChannelListNum = pAdapter->ChannelListNum; - for (i = 0; i < pChListBuf->ChannelListNum; i++) - pChListBuf->ChannelList[i] = pAdapter->ChannelList[i].Channel; - - wrq->u.data.length = sizeof(RT_CHANNEL_LIST_INFO); - Status = copy_to_user(wrq->u.data.pointer, pChListBuf, sizeof(RT_CHANNEL_LIST_INFO)); - DBGPRINT(RT_DEBUG_TRACE, ("Status=%d\n", Status)); - - if (pChListBuf) - kfree(pChListBuf); - } - break; - - case OID_802_11_GET_COUNTRY_CODE: - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_GET_COUNTRY_CODE \n")); - wrq->u.data.length = 2; - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.CountryCode, 2); - DBGPRINT(RT_DEBUG_TRACE, ("Status=%d\n", Status)); - break; - - case OID_802_11_GET_CHANNEL_GEOGRAPHY: - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_GET_CHANNEL_GEOGRAPHY \n")); - wrq->u.data.length = 1; - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.Geography, 1); - DBGPRINT(RT_DEBUG_TRACE, ("Status=%d\n", Status)); - break; - - -#ifdef QOS_DLS_SUPPORT - case RT_OID_802_11_QUERY_DLS: - wrq->u.data.length = sizeof(BOOLEAN); - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.bDLSCapable, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_DLS(=%d)\n", pAdapter->CommonCfg.bDLSCapable)); - break; - - case RT_OID_802_11_QUERY_DLS_PARAM: - { - PRT_802_11_DLS_INFO pDlsInfo = kmalloc(sizeof(RT_802_11_DLS_INFO), GFP_ATOMIC); - if (pDlsInfo == NULL) - break; - - for (i=0; iEntry[i], &pAdapter->StaCfg.DLSEntry[i], sizeof(RT_802_11_DLS_UI)); - } - - pDlsInfo->num = MAX_NUM_OF_DLS_ENTRY; - wrq->u.data.length = sizeof(RT_802_11_DLS_INFO); - Status = copy_to_user(wrq->u.data.pointer, pDlsInfo, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_DLS_PARAM\n")); - - if (pDlsInfo) - kfree(pDlsInfo); - } - break; -#endif // QOS_DLS_SUPPORT // - default: - DBGPRINT(RT_DEBUG_TRACE, ("Query::unknown IOCTL's subcmd = 0x%08x\n", cmd)); - Status = -EOPNOTSUPP; - break; - } - return Status; -} - -INT rt28xx_sta_ioctl( - IN struct net_device *net_dev, - IN OUT struct ifreq *rq, - IN INT cmd) -{ - POS_COOKIE pObj; - VIRTUAL_ADAPTER *pVirtualAd = NULL; - RTMP_ADAPTER *pAd = NULL; - struct iwreq *wrq = (struct iwreq *) rq; - BOOLEAN StateMachineTouched = FALSE; - INT Status = NDIS_STATUS_SUCCESS; - USHORT subcmd; - - if (net_dev->priv_flags == INT_MAIN) - { - pAd = net_dev->ml_priv; - } - else - { - pVirtualAd = net_dev->ml_priv; - pAd = pVirtualAd->RtmpDev->ml_priv; - } - pObj = (POS_COOKIE) pAd->OS_Cookie; - - if (pAd == NULL) - { - /* if 1st open fail, pAd will be free; - So the net_dev->ml_priv will be NULL in 2rd open */ - return -ENETDOWN; - } - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { -#ifdef CONFIG_APSTA_MIXED_SUPPORT - if (wrq->u.data.pointer == NULL) - { - return Status; - } - - if (strstr(wrq->u.data.pointer, "OpMode") == NULL) -#endif // CONFIG_APSTA_MIXED_SUPPORT // - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - } - - { // determine this ioctl command is comming from which interface. - pObj->ioctl_if_type = INT_MAIN; - pObj->ioctl_if = MAIN_MBSSID; - } - - switch(cmd) - { -#ifdef RALINK_ATE -#ifdef RALINK_28xx_QA - case RTPRIV_IOCTL_ATE: - { - RtmpDoAte(pAd, wrq); - } - break; -#endif // RALINK_28xx_QA // -#endif // RALINK_ATE // - case SIOCGIFHWADDR: - DBGPRINT(RT_DEBUG_TRACE, ("IOCTL::SIOCGIFHWADDR\n")); - memcpy(wrq->u.name, pAd->CurrentAddress, ETH_ALEN); - break; - case SIOCGIWNAME: - { - char *name=&wrq->u.name[0]; - rt_ioctl_giwname(net_dev, NULL, name, NULL); - break; - } - case SIOCGIWESSID: //Get ESSID - { - struct iw_point *essid=&wrq->u.essid; - rt_ioctl_giwessid(net_dev, NULL, essid, essid->pointer); - break; - } - case SIOCSIWESSID: //Set ESSID - { - struct iw_point *essid=&wrq->u.essid; - rt_ioctl_siwessid(net_dev, NULL, essid, essid->pointer); - break; - } - case SIOCSIWNWID: // set network id (the cell) - case SIOCGIWNWID: // get network id - Status = -EOPNOTSUPP; - break; - case SIOCSIWFREQ: //set channel/frequency (Hz) - { - struct iw_freq *freq=&wrq->u.freq; - rt_ioctl_siwfreq(net_dev, NULL, freq, NULL); - break; - } - case SIOCGIWFREQ: // get channel/frequency (Hz) - { - struct iw_freq *freq=&wrq->u.freq; - rt_ioctl_giwfreq(net_dev, NULL, freq, NULL); - break; - } - case SIOCSIWNICKN: //set node name/nickname - { - struct iw_point *data=&wrq->u.data; - rt_ioctl_siwnickn(net_dev, NULL, data, NULL); - break; - } - case SIOCGIWNICKN: //get node name/nickname - { - struct iw_point *data=&wrq->u.data; - rt_ioctl_giwnickn(net_dev, NULL, data, NULL); - break; - } - case SIOCGIWRATE: //get default bit rate (bps) - rt_ioctl_giwrate(net_dev, NULL, &wrq->u, NULL); - break; - case SIOCSIWRATE: //set default bit rate (bps) - rt_ioctl_siwrate(net_dev, NULL, &wrq->u, NULL); - break; - case SIOCGIWRTS: // get RTS/CTS threshold (bytes) - { - struct iw_param *rts=&wrq->u.rts; - rt_ioctl_giwrts(net_dev, NULL, rts, NULL); - break; - } - case SIOCSIWRTS: //set RTS/CTS threshold (bytes) - { - struct iw_param *rts=&wrq->u.rts; - rt_ioctl_siwrts(net_dev, NULL, rts, NULL); - break; - } - case SIOCGIWFRAG: //get fragmentation thr (bytes) - { - struct iw_param *frag=&wrq->u.frag; - rt_ioctl_giwfrag(net_dev, NULL, frag, NULL); - break; - } - case SIOCSIWFRAG: //set fragmentation thr (bytes) - { - struct iw_param *frag=&wrq->u.frag; - rt_ioctl_siwfrag(net_dev, NULL, frag, NULL); - break; - } - case SIOCGIWENCODE: //get encoding token & mode - { - struct iw_point *erq=&wrq->u.encoding; - if(erq->pointer) - rt_ioctl_giwencode(net_dev, NULL, erq, erq->pointer); - break; - } - case SIOCSIWENCODE: //set encoding token & mode - { - struct iw_point *erq=&wrq->u.encoding; - if(erq->pointer) - rt_ioctl_siwencode(net_dev, NULL, erq, erq->pointer); - break; - } - case SIOCGIWAP: //get access point MAC addresses - { - struct sockaddr *ap_addr=&wrq->u.ap_addr; - rt_ioctl_giwap(net_dev, NULL, ap_addr, ap_addr->sa_data); - break; - } - case SIOCSIWAP: //set access point MAC addresses - { - struct sockaddr *ap_addr=&wrq->u.ap_addr; - rt_ioctl_siwap(net_dev, NULL, ap_addr, ap_addr->sa_data); - break; - } - case SIOCGIWMODE: //get operation mode - { - __u32 *mode=&wrq->u.mode; - rt_ioctl_giwmode(net_dev, NULL, mode, NULL); - break; - } - case SIOCSIWMODE: //set operation mode - { - __u32 *mode=&wrq->u.mode; - rt_ioctl_siwmode(net_dev, NULL, mode, NULL); - break; - } - case SIOCGIWSENS: //get sensitivity (dBm) - case SIOCSIWSENS: //set sensitivity (dBm) - case SIOCGIWPOWER: //get Power Management settings - case SIOCSIWPOWER: //set Power Management settings - case SIOCGIWTXPOW: //get transmit power (dBm) - case SIOCSIWTXPOW: //set transmit power (dBm) - case SIOCGIWRANGE: //Get range of parameters - case SIOCGIWRETRY: //get retry limits and lifetime - case SIOCSIWRETRY: //set retry limits and lifetime - Status = -EOPNOTSUPP; - break; - case RT_PRIV_IOCTL: - subcmd = wrq->u.data.flags; - if( subcmd & OID_GET_SET_TOGGLE) - Status = RTMPSetInformation(pAd, rq, subcmd); - else - Status = RTMPQueryInformation(pAd, rq, subcmd); - break; - case SIOCGIWPRIV: - if (wrq->u.data.pointer) - { - if ( access_ok(VERIFY_WRITE, wrq->u.data.pointer, sizeof(privtab)) != TRUE) - break; - wrq->u.data.length = sizeof(privtab) / sizeof(privtab[0]); - if (copy_to_user(wrq->u.data.pointer, privtab, sizeof(privtab))) - Status = -EFAULT; - } - break; - case RTPRIV_IOCTL_SET: - if(access_ok(VERIFY_READ, wrq->u.data.pointer, wrq->u.data.length) != TRUE) - break; - rt_ioctl_setparam(net_dev, NULL, NULL, wrq->u.data.pointer); - break; - case RTPRIV_IOCTL_GSITESURVEY: - RTMPIoctlGetSiteSurvey(pAd, wrq); - break; -#ifdef DBG - case RTPRIV_IOCTL_MAC: - RTMPIoctlMAC(pAd, wrq); - break; - case RTPRIV_IOCTL_E2P: - RTMPIoctlE2PROM(pAd, wrq); - break; -#endif // DBG // - case SIOCETHTOOL: - break; - default: - DBGPRINT(RT_DEBUG_ERROR, ("IOCTL::unknown IOCTL's cmd = 0x%08x\n", cmd)); - Status = -EOPNOTSUPP; - break; - } - - if(StateMachineTouched) // Upper layer sent a MLME-related operations - RT28XX_MLME_HANDLER(pAd); - - return Status; -} - -/* - ========================================================================== - Description: - Set SSID - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_SSID_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - NDIS_802_11_SSID Ssid, *pSsid=NULL; - BOOLEAN StateMachineTouched = FALSE; - int success = TRUE; - - if( strlen(arg) <= MAX_LEN_OF_SSID) - { - NdisZeroMemory(&Ssid, sizeof(NDIS_802_11_SSID)); - if (strlen(arg) != 0) - { - NdisMoveMemory(Ssid.Ssid, arg, strlen(arg)); - Ssid.SsidLength = strlen(arg); - } - else //ANY ssid - { - Ssid.SsidLength = 0; - memcpy(Ssid.Ssid, "", 0); - pAdapter->StaCfg.BssType = BSS_INFRA; - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; - pAdapter->StaCfg.WepStatus = Ndis802_11EncryptionDisabled; - } - pSsid = &Ssid; - - if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) - { - RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); - DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); - } - - pAdapter->MlmeAux.CurrReqIsFromNdis = TRUE; - pAdapter->StaCfg.bScanReqIsFromWebUI = FALSE; - pAdapter->bConfigChanged = TRUE; - - MlmeEnqueue(pAdapter, - MLME_CNTL_STATE_MACHINE, - OID_802_11_SSID, - sizeof(NDIS_802_11_SSID), - (VOID *)pSsid); - - StateMachineTouched = TRUE; - DBGPRINT(RT_DEBUG_TRACE, ("Set_SSID_Proc::(Len=%d,Ssid=%s)\n", Ssid.SsidLength, Ssid.Ssid)); - } - else - success = FALSE; - - if (StateMachineTouched) // Upper layer sent a MLME-related operations - RT28XX_MLME_HANDLER(pAdapter); - - return success; -} - -#ifdef WMM_SUPPORT -/* - ========================================================================== - Description: - Set WmmCapable Enable or Disable - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_WmmCapable_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - BOOLEAN bWmmCapable; - - bWmmCapable = simple_strtol(arg, 0, 10); - - if ((bWmmCapable == 1) -#ifdef RT2870 - && (pAd->NumberOfPipes >= 5) -#endif // RT2870 // - ) - pAd->CommonCfg.bWmmCapable = TRUE; - else if (bWmmCapable == 0) - pAd->CommonCfg.bWmmCapable = FALSE; - else - return FALSE; //Invalid argument - - DBGPRINT(RT_DEBUG_TRACE, ("Set_WmmCapable_Proc::(bWmmCapable=%d)\n", - pAd->CommonCfg.bWmmCapable)); - - return TRUE; -} -#endif // WMM_SUPPORT // - -/* - ========================================================================== - Description: - Set Network Type(Infrastructure/Adhoc mode) - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_NetworkType_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - UINT32 Value = 0; - - if (strcmp(arg, "Adhoc") == 0) - { - if (pAdapter->StaCfg.BssType != BSS_ADHOC) - { - // Config has changed - pAdapter->bConfigChanged = TRUE; - if (MONITOR_ON(pAdapter)) - { - RTMP_IO_WRITE32(pAdapter, RX_FILTR_CFG, STANORMAL); - RTMP_IO_READ32(pAdapter, MAC_SYS_CTRL, &Value); - Value &= (~0x80); - RTMP_IO_WRITE32(pAdapter, MAC_SYS_CTRL, Value); - OPSTATUS_CLEAR_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED); - pAdapter->StaCfg.bAutoReconnect = TRUE; - LinkDown(pAdapter, FALSE); - } - if (INFRA_ON(pAdapter)) - { - //BOOLEAN Cancelled; - // Set the AutoReconnectSsid to prevent it reconnect to old SSID - // Since calling this indicate user don't want to connect to that SSID anymore. - pAdapter->MlmeAux.AutoReconnectSsidLen= 32; - NdisZeroMemory(pAdapter->MlmeAux.AutoReconnectSsid, pAdapter->MlmeAux.AutoReconnectSsidLen); - - LinkDown(pAdapter, FALSE); - - DBGPRINT(RT_DEBUG_TRACE, ("NDIS_STATUS_MEDIA_DISCONNECT Event BB!\n")); - } - } - pAdapter->StaCfg.BssType = BSS_ADHOC; - pAdapter->net_dev->type = pAdapter->StaCfg.OriDevType; - DBGPRINT(RT_DEBUG_TRACE, ("===>Set_NetworkType_Proc::(AD-HOC)\n")); - } - else if (strcmp(arg, "Infra") == 0) - { - if (pAdapter->StaCfg.BssType != BSS_INFRA) - { - // Config has changed - pAdapter->bConfigChanged = TRUE; - if (MONITOR_ON(pAdapter)) - { - RTMP_IO_WRITE32(pAdapter, RX_FILTR_CFG, STANORMAL); - RTMP_IO_READ32(pAdapter, MAC_SYS_CTRL, &Value); - Value &= (~0x80); - RTMP_IO_WRITE32(pAdapter, MAC_SYS_CTRL, Value); - OPSTATUS_CLEAR_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED); - pAdapter->StaCfg.bAutoReconnect = TRUE; - LinkDown(pAdapter, FALSE); - } - if (ADHOC_ON(pAdapter)) - { - // Set the AutoReconnectSsid to prevent it reconnect to old SSID - // Since calling this indicate user don't want to connect to that SSID anymore. - pAdapter->MlmeAux.AutoReconnectSsidLen= 32; - NdisZeroMemory(pAdapter->MlmeAux.AutoReconnectSsid, pAdapter->MlmeAux.AutoReconnectSsidLen); - - LinkDown(pAdapter, FALSE); - } - } - pAdapter->StaCfg.BssType = BSS_INFRA; - pAdapter->net_dev->type = pAdapter->StaCfg.OriDevType; - DBGPRINT(RT_DEBUG_TRACE, ("===>Set_NetworkType_Proc::(INFRA)\n")); - - pAdapter->StaCfg.BssType = BSS_INFRA; - } - else if (strcmp(arg, "Monitor") == 0) - { - UCHAR bbpValue = 0; - BCN_TIME_CFG_STRUC csr; - OPSTATUS_CLEAR_FLAG(pAdapter, fOP_STATUS_INFRA_ON); - OPSTATUS_CLEAR_FLAG(pAdapter, fOP_STATUS_ADHOC_ON); - OPSTATUS_SET_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED); - // disable all periodic state machine - pAdapter->StaCfg.bAutoReconnect = FALSE; - // reset all mlme state machine - RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); - DBGPRINT(RT_DEBUG_TRACE, ("fOP_STATUS_MEDIA_STATE_CONNECTED \n")); - if (pAdapter->CommonCfg.CentralChannel == 0) - { -#ifdef DOT11_N_SUPPORT - if (pAdapter->CommonCfg.PhyMode == PHY_11AN_MIXED) - pAdapter->CommonCfg.CentralChannel = 36; - else -#endif // DOT11_N_SUPPORT // - pAdapter->CommonCfg.CentralChannel = 6; - } -#ifdef DOT11_N_SUPPORT - else - N_ChannelCheck(pAdapter); -#endif // DOT11_N_SUPPORT // - -#ifdef DOT11_N_SUPPORT - if (pAdapter->CommonCfg.PhyMode >= PHY_11ABGN_MIXED && - pAdapter->CommonCfg.RegTransmitSetting.field.BW == BW_40 && - pAdapter->CommonCfg.RegTransmitSetting.field.EXTCHA == EXTCHA_ABOVE) - { - // 40MHz ,control channel at lower - RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, BBP_R4, &bbpValue); - bbpValue &= (~0x18); - bbpValue |= 0x10; - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R4, bbpValue); - pAdapter->CommonCfg.BBPCurrentBW = BW_40; - // RX : control channel at lower - RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, BBP_R3, &bbpValue); - bbpValue &= (~0x20); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R3, bbpValue); - - RTMP_IO_READ32(pAdapter, TX_BAND_CFG, &Value); - Value &= 0xfffffffe; - RTMP_IO_WRITE32(pAdapter, TX_BAND_CFG, Value); - pAdapter->CommonCfg.CentralChannel = pAdapter->CommonCfg.Channel + 2; - AsicSwitchChannel(pAdapter, pAdapter->CommonCfg.CentralChannel, FALSE); - AsicLockChannel(pAdapter, pAdapter->CommonCfg.CentralChannel); - DBGPRINT(RT_DEBUG_TRACE, ("BW_40 ,control_channel(%d), CentralChannel(%d) \n", - pAdapter->CommonCfg.Channel, - pAdapter->CommonCfg.CentralChannel)); - } - else if (pAdapter->CommonCfg.PhyMode >= PHY_11ABGN_MIXED && - pAdapter->CommonCfg.RegTransmitSetting.field.BW == BW_40 && - pAdapter->CommonCfg.RegTransmitSetting.field.EXTCHA == EXTCHA_BELOW) - { - // 40MHz ,control channel at upper - RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, BBP_R4, &bbpValue); - bbpValue &= (~0x18); - bbpValue |= 0x10; - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R4, bbpValue); - pAdapter->CommonCfg.BBPCurrentBW = BW_40; - RTMP_IO_READ32(pAdapter, TX_BAND_CFG, &Value); - Value |= 0x1; - RTMP_IO_WRITE32(pAdapter, TX_BAND_CFG, Value); - - RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, BBP_R3, &bbpValue); - bbpValue |= (0x20); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R3, bbpValue); - pAdapter->CommonCfg.CentralChannel = pAdapter->CommonCfg.Channel - 2; - AsicSwitchChannel(pAdapter, pAdapter->CommonCfg.CentralChannel, FALSE); - AsicLockChannel(pAdapter, pAdapter->CommonCfg.CentralChannel); - DBGPRINT(RT_DEBUG_TRACE, ("BW_40 ,control_channel(%d), CentralChannel(%d) \n", - pAdapter->CommonCfg.Channel, - pAdapter->CommonCfg.CentralChannel)); - } - else -#endif // DOT11_N_SUPPORT // - { - // 20MHz - RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, BBP_R4, &bbpValue); - bbpValue &= (~0x18); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R4, bbpValue); - pAdapter->CommonCfg.BBPCurrentBW = BW_20; - AsicSwitchChannel(pAdapter, pAdapter->CommonCfg.Channel, FALSE); - AsicLockChannel(pAdapter, pAdapter->CommonCfg.Channel); - DBGPRINT(RT_DEBUG_TRACE, ("BW_20, Channel(%d)\n", pAdapter->CommonCfg.Channel)); - } - // Enable Rx with promiscuous reception - RTMP_IO_WRITE32(pAdapter, RX_FILTR_CFG, 0x3); - // ASIC supporsts sniffer function with replacing RSSI with timestamp. - //RTMP_IO_READ32(pAdapter, MAC_SYS_CTRL, &Value); - //Value |= (0x80); - //RTMP_IO_WRITE32(pAdapter, MAC_SYS_CTRL, Value); - // disable sync - RTMP_IO_READ32(pAdapter, BCN_TIME_CFG, &csr.word); - csr.field.bBeaconGen = 0; - csr.field.bTBTTEnable = 0; - csr.field.TsfSyncMode = 0; - RTMP_IO_WRITE32(pAdapter, BCN_TIME_CFG, csr.word); - - pAdapter->StaCfg.BssType = BSS_MONITOR; - pAdapter->net_dev->type = ARPHRD_IEEE80211_PRISM; //ARPHRD_IEEE80211; // IEEE80211 - DBGPRINT(RT_DEBUG_TRACE, ("===>Set_NetworkType_Proc::(MONITOR)\n")); - } - - // Reset Ralink supplicant to not use, it will be set to start when UI set PMK key - pAdapter->StaCfg.WpaState = SS_NOTUSE; - - DBGPRINT(RT_DEBUG_TRACE, ("Set_NetworkType_Proc::(NetworkType=%d)\n", pAdapter->StaCfg.BssType)); - - return TRUE; -} - -/* - ========================================================================== - Description: - Set Authentication mode - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_AuthMode_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - if ((strcmp(arg, "WEPAUTO") == 0) || (strcmp(arg, "wepauto") == 0)) - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeAutoSwitch; - else if ((strcmp(arg, "OPEN") == 0) || (strcmp(arg, "open") == 0)) - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; - else if ((strcmp(arg, "SHARED") == 0) || (strcmp(arg, "shared") == 0)) - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeShared; - else if ((strcmp(arg, "WPAPSK") == 0) || (strcmp(arg, "wpapsk") == 0)) - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPAPSK; - else if ((strcmp(arg, "WPANONE") == 0) || (strcmp(arg, "wpanone") == 0)) - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPANone; - else if ((strcmp(arg, "WPA2PSK") == 0) || (strcmp(arg, "wpa2psk") == 0)) - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA2PSK; -#ifdef WPA_SUPPLICANT_SUPPORT - else if ((strcmp(arg, "WPA") == 0) || (strcmp(arg, "wpa") == 0)) - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA; - else if ((strcmp(arg, "WPA2") == 0) || (strcmp(arg, "wpa2") == 0)) - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA2; -#endif // WPA_SUPPLICANT_SUPPORT // - else - return FALSE; - - pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; - - DBGPRINT(RT_DEBUG_TRACE, ("Set_AuthMode_Proc::(AuthMode=%d)\n", pAdapter->StaCfg.AuthMode)); - - return TRUE; -} - -/* - ========================================================================== - Description: - Set Encryption Type - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_EncrypType_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - if ((strcmp(arg, "NONE") == 0) || (strcmp(arg, "none") == 0)) - { - if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - return TRUE; // do nothing - - pAdapter->StaCfg.WepStatus = Ndis802_11WEPDisabled; - pAdapter->StaCfg.PairCipher = Ndis802_11WEPDisabled; - pAdapter->StaCfg.GroupCipher = Ndis802_11WEPDisabled; - } - else if ((strcmp(arg, "WEP") == 0) || (strcmp(arg, "wep") == 0)) - { - if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - return TRUE; // do nothing - - pAdapter->StaCfg.WepStatus = Ndis802_11WEPEnabled; - pAdapter->StaCfg.PairCipher = Ndis802_11WEPEnabled; - pAdapter->StaCfg.GroupCipher = Ndis802_11WEPEnabled; - } - else if ((strcmp(arg, "TKIP") == 0) || (strcmp(arg, "tkip") == 0)) - { - if (pAdapter->StaCfg.AuthMode < Ndis802_11AuthModeWPA) - return TRUE; // do nothing - - pAdapter->StaCfg.WepStatus = Ndis802_11Encryption2Enabled; - pAdapter->StaCfg.PairCipher = Ndis802_11Encryption2Enabled; - pAdapter->StaCfg.GroupCipher = Ndis802_11Encryption2Enabled; - } - else if ((strcmp(arg, "AES") == 0) || (strcmp(arg, "aes") == 0)) - { - if (pAdapter->StaCfg.AuthMode < Ndis802_11AuthModeWPA) - return TRUE; // do nothing - - pAdapter->StaCfg.WepStatus = Ndis802_11Encryption3Enabled; - pAdapter->StaCfg.PairCipher = Ndis802_11Encryption3Enabled; - pAdapter->StaCfg.GroupCipher = Ndis802_11Encryption3Enabled; - } - else - return FALSE; - - pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; - - DBGPRINT(RT_DEBUG_TRACE, ("Set_EncrypType_Proc::(EncrypType=%d)\n", pAdapter->StaCfg.WepStatus)); - - return TRUE; -} - -/* - ========================================================================== - Description: - Set Default Key ID - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_DefaultKeyID_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - ULONG KeyIdx; - - KeyIdx = simple_strtol(arg, 0, 10); - if((KeyIdx >= 1 ) && (KeyIdx <= 4)) - pAdapter->StaCfg.DefaultKeyId = (UCHAR) (KeyIdx - 1 ); - else - return FALSE; //Invalid argument - - DBGPRINT(RT_DEBUG_TRACE, ("Set_DefaultKeyID_Proc::(DefaultKeyID=%d)\n", pAdapter->StaCfg.DefaultKeyId)); - - return TRUE; -} - -/* - ========================================================================== - Description: - Set WEP KEY1 - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_Key1_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - int KeyLen; - int i; - UCHAR CipherAlg=CIPHER_WEP64; - - if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - return TRUE; // do nothing - - KeyLen = strlen(arg); - - switch (KeyLen) - { - case 5: //wep 40 Ascii type - pAdapter->SharedKey[BSS0][0].KeyLen = KeyLen; - memcpy(pAdapter->SharedKey[BSS0][0].Key, arg, KeyLen); - CipherAlg = CIPHER_WEP64; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key1_Proc::(Key1=%s and type=%s)\n", arg, "Ascii")); - break; - case 10: //wep 40 Hex type - for(i=0; i < KeyLen; i++) - { - if( !isxdigit(*(arg+i)) ) - return FALSE; //Not Hex value; - } - pAdapter->SharedKey[BSS0][0].KeyLen = KeyLen / 2 ; - AtoH(arg, pAdapter->SharedKey[BSS0][0].Key, KeyLen / 2); - CipherAlg = CIPHER_WEP64; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key1_Proc::(Key1=%s and type=%s)\n", arg, "Hex")); - break; - case 13: //wep 104 Ascii type - pAdapter->SharedKey[BSS0][0].KeyLen = KeyLen; - memcpy(pAdapter->SharedKey[BSS0][0].Key, arg, KeyLen); - CipherAlg = CIPHER_WEP128; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key1_Proc::(Key1=%s and type=%s)\n", arg, "Ascii")); - break; - case 26: //wep 104 Hex type - for(i=0; i < KeyLen; i++) - { - if( !isxdigit(*(arg+i)) ) - return FALSE; //Not Hex value; - } - pAdapter->SharedKey[BSS0][0].KeyLen = KeyLen / 2 ; - AtoH(arg, pAdapter->SharedKey[BSS0][0].Key, KeyLen / 2); - CipherAlg = CIPHER_WEP128; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key1_Proc::(Key1=%s and type=%s)\n", arg, "Hex")); - break; - default: //Invalid argument - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key1_Proc::Invalid argument (=%s)\n", arg)); - return FALSE; - } - - pAdapter->SharedKey[BSS0][0].CipherAlg = CipherAlg; - - // Set keys (into ASIC) - if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - ; // not support - else // Old WEP stuff - { - AsicAddSharedKeyEntry(pAdapter, - 0, - 0, - pAdapter->SharedKey[BSS0][0].CipherAlg, - pAdapter->SharedKey[BSS0][0].Key, - NULL, - NULL); - } - - return TRUE; -} -/* - ========================================================================== - - Description: - Set WEP KEY2 - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_Key2_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - int KeyLen; - int i; - UCHAR CipherAlg=CIPHER_WEP64; - - if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - return TRUE; // do nothing - - KeyLen = strlen(arg); - - switch (KeyLen) - { - case 5: //wep 40 Ascii type - pAdapter->SharedKey[BSS0][1].KeyLen = KeyLen; - memcpy(pAdapter->SharedKey[BSS0][1].Key, arg, KeyLen); - CipherAlg = CIPHER_WEP64; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key2_Proc::(Key2=%s and type=%s)\n", arg, "Ascii")); - break; - case 10: //wep 40 Hex type - for(i=0; i < KeyLen; i++) - { - if( !isxdigit(*(arg+i)) ) - return FALSE; //Not Hex value; - } - pAdapter->SharedKey[BSS0][1].KeyLen = KeyLen / 2 ; - AtoH(arg, pAdapter->SharedKey[BSS0][1].Key, KeyLen / 2); - CipherAlg = CIPHER_WEP64; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key2_Proc::(Key2=%s and type=%s)\n", arg, "Hex")); - break; - case 13: //wep 104 Ascii type - pAdapter->SharedKey[BSS0][1].KeyLen = KeyLen; - memcpy(pAdapter->SharedKey[BSS0][1].Key, arg, KeyLen); - CipherAlg = CIPHER_WEP128; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key2_Proc::(Key2=%s and type=%s)\n", arg, "Ascii")); - break; - case 26: //wep 104 Hex type - for(i=0; i < KeyLen; i++) - { - if( !isxdigit(*(arg+i)) ) - return FALSE; //Not Hex value; - } - pAdapter->SharedKey[BSS0][1].KeyLen = KeyLen / 2 ; - AtoH(arg, pAdapter->SharedKey[BSS0][1].Key, KeyLen / 2); - CipherAlg = CIPHER_WEP128; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key2_Proc::(Key2=%s and type=%s)\n", arg, "Hex")); - break; - default: //Invalid argument - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key2_Proc::Invalid argument (=%s)\n", arg)); - return FALSE; - } - pAdapter->SharedKey[BSS0][1].CipherAlg = CipherAlg; - - // Set keys (into ASIC) - if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - ; // not support - else // Old WEP stuff - { - AsicAddSharedKeyEntry(pAdapter, - 0, - 1, - pAdapter->SharedKey[BSS0][1].CipherAlg, - pAdapter->SharedKey[BSS0][1].Key, - NULL, - NULL); - } - - return TRUE; -} -/* - ========================================================================== - Description: - Set WEP KEY3 - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_Key3_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - int KeyLen; - int i; - UCHAR CipherAlg=CIPHER_WEP64; - - if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - return TRUE; // do nothing - - KeyLen = strlen(arg); - - switch (KeyLen) - { - case 5: //wep 40 Ascii type - pAdapter->SharedKey[BSS0][2].KeyLen = KeyLen; - memcpy(pAdapter->SharedKey[BSS0][2].Key, arg, KeyLen); - CipherAlg = CIPHER_WEP64; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key3_Proc::(Key3=%s and type=Ascii)\n", arg)); - break; - case 10: //wep 40 Hex type - for(i=0; i < KeyLen; i++) - { - if( !isxdigit(*(arg+i)) ) - return FALSE; //Not Hex value; - } - pAdapter->SharedKey[BSS0][2].KeyLen = KeyLen / 2 ; - AtoH(arg, pAdapter->SharedKey[BSS0][2].Key, KeyLen / 2); - CipherAlg = CIPHER_WEP64; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key3_Proc::(Key3=%s and type=Hex)\n", arg)); - break; - case 13: //wep 104 Ascii type - pAdapter->SharedKey[BSS0][2].KeyLen = KeyLen; - memcpy(pAdapter->SharedKey[BSS0][2].Key, arg, KeyLen); - CipherAlg = CIPHER_WEP128; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key3_Proc::(Key3=%s and type=Ascii)\n", arg)); - break; - case 26: //wep 104 Hex type - for(i=0; i < KeyLen; i++) - { - if( !isxdigit(*(arg+i)) ) - return FALSE; //Not Hex value; - } - pAdapter->SharedKey[BSS0][2].KeyLen = KeyLen / 2 ; - AtoH(arg, pAdapter->SharedKey[BSS0][2].Key, KeyLen / 2); - CipherAlg = CIPHER_WEP128; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key3_Proc::(Key3=%s and type=Hex)\n", arg)); - break; - default: //Invalid argument - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key3_Proc::Invalid argument (=%s)\n", arg)); - return FALSE; - } - pAdapter->SharedKey[BSS0][2].CipherAlg = CipherAlg; - - // Set keys (into ASIC) - if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - ; // not support - else // Old WEP stuff - { - AsicAddSharedKeyEntry(pAdapter, - 0, - 2, - pAdapter->SharedKey[BSS0][2].CipherAlg, - pAdapter->SharedKey[BSS0][2].Key, - NULL, - NULL); - } - - return TRUE; -} -/* - ========================================================================== - Description: - Set WEP KEY4 - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_Key4_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - int KeyLen; - int i; - UCHAR CipherAlg=CIPHER_WEP64; - - if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - return TRUE; // do nothing - - KeyLen = strlen(arg); - - switch (KeyLen) - { - case 5: //wep 40 Ascii type - pAdapter->SharedKey[BSS0][3].KeyLen = KeyLen; - memcpy(pAdapter->SharedKey[BSS0][3].Key, arg, KeyLen); - CipherAlg = CIPHER_WEP64; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key4_Proc::(Key4=%s and type=%s)\n", arg, "Ascii")); - break; - case 10: //wep 40 Hex type - for(i=0; i < KeyLen; i++) - { - if( !isxdigit(*(arg+i)) ) - return FALSE; //Not Hex value; - } - pAdapter->SharedKey[BSS0][3].KeyLen = KeyLen / 2 ; - AtoH(arg, pAdapter->SharedKey[BSS0][3].Key, KeyLen / 2); - CipherAlg = CIPHER_WEP64; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key4_Proc::(Key4=%s and type=%s)\n", arg, "Hex")); - break; - case 13: //wep 104 Ascii type - pAdapter->SharedKey[BSS0][3].KeyLen = KeyLen; - memcpy(pAdapter->SharedKey[BSS0][3].Key, arg, KeyLen); - CipherAlg = CIPHER_WEP128; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key4_Proc::(Key4=%s and type=%s)\n", arg, "Ascii")); - break; - case 26: //wep 104 Hex type - for(i=0; i < KeyLen; i++) - { - if( !isxdigit(*(arg+i)) ) - return FALSE; //Not Hex value; - } - pAdapter->SharedKey[BSS0][3].KeyLen = KeyLen / 2 ; - AtoH(arg, pAdapter->SharedKey[BSS0][3].Key, KeyLen / 2); - CipherAlg = CIPHER_WEP128; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key4_Proc::(Key4=%s and type=%s)\n", arg, "Hex")); - break; - default: //Invalid argument - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key4_Proc::Invalid argument (=%s)\n", arg)); - return FALSE; - } - pAdapter->SharedKey[BSS0][3].CipherAlg = CipherAlg; - - // Set keys (into ASIC) - if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - ; // not support - else // Old WEP stuff - { - AsicAddSharedKeyEntry(pAdapter, - 0, - 3, - pAdapter->SharedKey[BSS0][3].CipherAlg, - pAdapter->SharedKey[BSS0][3].Key, - NULL, - NULL); - } - - return TRUE; -} - -/* - ========================================================================== - Description: - Set WPA PSK key - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_WPAPSK_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - UCHAR keyMaterial[40]; - - if ((pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPAPSK) && - (pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPA2PSK) && - (pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPANone) - ) - return TRUE; // do nothing - - DBGPRINT(RT_DEBUG_TRACE, ("Set_WPAPSK_Proc::(WPAPSK=%s)\n", arg)); - - NdisZeroMemory(keyMaterial, 40); - - if ((strlen(arg) < 8) || (strlen(arg) > 64)) - { - DBGPRINT(RT_DEBUG_TRACE, ("Set failed!!(WPAPSK=%s), WPAPSK key-string required 8 ~ 64 characters \n", arg)); - return FALSE; - } - - if (strlen(arg) == 64) - { - AtoH(arg, keyMaterial, 32); - NdisMoveMemory(pAdapter->StaCfg.PMK, keyMaterial, 32); - - } - else - { - PasswordHash((char *)arg, pAdapter->MlmeAux.Ssid, pAdapter->MlmeAux.SsidLen, keyMaterial); - NdisMoveMemory(pAdapter->StaCfg.PMK, keyMaterial, 32); - } - - - - if(pAdapter->StaCfg.BssType == BSS_ADHOC && - pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) - { - pAdapter->StaCfg.WpaState = SS_NOTUSE; - } - else - { - // Start STA supplicant state machine - pAdapter->StaCfg.WpaState = SS_START; - } - - return TRUE; -} - -/* - ========================================================================== - Description: - Set Power Saving mode - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_PSMode_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - if (pAdapter->StaCfg.BssType == BSS_INFRA) - { - if ((strcmp(arg, "Max_PSP") == 0) || - (strcmp(arg, "max_psp") == 0) || - (strcmp(arg, "MAX_PSP") == 0)) - { - // do NOT turn on PSM bit here, wait until MlmeCheckForPsmChange() - // to exclude certain situations. - if (pAdapter->StaCfg.bWindowsACCAMEnable == FALSE) - pAdapter->StaCfg.WindowsPowerMode = Ndis802_11PowerModeMAX_PSP; - pAdapter->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeMAX_PSP; - OPSTATUS_SET_FLAG(pAdapter, fOP_STATUS_RECEIVE_DTIM); - pAdapter->StaCfg.DefaultListenCount = 5; - - } - else if ((strcmp(arg, "Fast_PSP") == 0) || - (strcmp(arg, "fast_psp") == 0) || - (strcmp(arg, "FAST_PSP") == 0)) - { - // do NOT turn on PSM bit here, wait until MlmeCheckForPsmChange() - // to exclude certain situations. - OPSTATUS_SET_FLAG(pAdapter, fOP_STATUS_RECEIVE_DTIM); - if (pAdapter->StaCfg.bWindowsACCAMEnable == FALSE) - pAdapter->StaCfg.WindowsPowerMode = Ndis802_11PowerModeFast_PSP; - pAdapter->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeFast_PSP; - pAdapter->StaCfg.DefaultListenCount = 3; - } - else if ((strcmp(arg, "Legacy_PSP") == 0) || - (strcmp(arg, "legacy_psp") == 0) || - (strcmp(arg, "LEGACY_PSP") == 0)) - { - // do NOT turn on PSM bit here, wait until MlmeCheckForPsmChange() - // to exclude certain situations. - OPSTATUS_SET_FLAG(pAdapter, fOP_STATUS_RECEIVE_DTIM); - if (pAdapter->StaCfg.bWindowsACCAMEnable == FALSE) - pAdapter->StaCfg.WindowsPowerMode = Ndis802_11PowerModeLegacy_PSP; - pAdapter->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeLegacy_PSP; - pAdapter->StaCfg.DefaultListenCount = 3; - } - else - { - //Default Ndis802_11PowerModeCAM - // clear PSM bit immediately - MlmeSetPsmBit(pAdapter, PWR_ACTIVE); - OPSTATUS_SET_FLAG(pAdapter, fOP_STATUS_RECEIVE_DTIM); - if (pAdapter->StaCfg.bWindowsACCAMEnable == FALSE) - pAdapter->StaCfg.WindowsPowerMode = Ndis802_11PowerModeCAM; - pAdapter->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeCAM; - } - - DBGPRINT(RT_DEBUG_TRACE, ("Set_PSMode_Proc::(PSMode=%ld)\n", pAdapter->StaCfg.WindowsPowerMode)); - } - else - return FALSE; - - - return TRUE; -} - -#ifdef WPA_SUPPLICANT_SUPPORT -/* - ========================================================================== - Description: - Set WpaSupport flag. - Value: - 0: Driver ignore wpa_supplicant. - 1: wpa_supplicant initiates scanning and AP selection. - 2: driver takes care of scanning, AP selection, and IEEE 802.11 association parameters. - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_Wpa_Support( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - - if ( simple_strtol(arg, 0, 10) == 0) - pAd->StaCfg.WpaSupplicantUP = WPA_SUPPLICANT_DISABLE; - else if ( simple_strtol(arg, 0, 10) == 1) - pAd->StaCfg.WpaSupplicantUP = WPA_SUPPLICANT_ENABLE; - else if ( simple_strtol(arg, 0, 10) == 2) - pAd->StaCfg.WpaSupplicantUP = WPA_SUPPLICANT_ENABLE_WITH_WEB_UI; - else - pAd->StaCfg.WpaSupplicantUP = WPA_SUPPLICANT_DISABLE; - - DBGPRINT(RT_DEBUG_TRACE, ("Set_Wpa_Support::(WpaSupplicantUP=%d)\n", pAd->StaCfg.WpaSupplicantUP)); - - return TRUE; -} -#endif // WPA_SUPPLICANT_SUPPORT // - -#ifdef DBG -/* - ========================================================================== - Description: - Read / Write MAC - Arguments: - pAdapter Pointer to our adapter - wrq Pointer to the ioctl argument - - Return Value: - None - - Note: - Usage: - 1.) iwpriv ra0 mac 0 ==> read MAC where Addr=0x0 - 2.) iwpriv ra0 mac 0=12 ==> write MAC where Addr=0x0, value=12 - ========================================================================== -*/ -VOID RTMPIoctlMAC( - IN PRTMP_ADAPTER pAdapter, - IN struct iwreq *wrq) -{ - CHAR *this_char; - CHAR *value; - INT j = 0, k = 0; - CHAR msg[1024]; - CHAR arg[255]; - ULONG macAddr = 0; - UCHAR temp[16], temp2[16]; - UINT32 macValue = 0; - INT Status; - - - memset(msg, 0x00, 1024); - if (wrq->u.data.length > 1) //No parameters. - { - Status = copy_from_user(arg, wrq->u.data.pointer, (wrq->u.data.length > 255) ? 255 : wrq->u.data.length); - sprintf(msg, "\n"); - - //Parsing Read or Write - this_char = arg; - if (!*this_char) - goto next; - - if ((value = rtstrchr(this_char, '=')) != NULL) - *value++ = 0; - - if (!value || !*value) - { //Read - // Sanity check - if(strlen(this_char) > 4) - goto next; - - j = strlen(this_char); - while(j-- > 0) - { - if(this_char[j] > 'f' || this_char[j] < '0') - return; - } - - // Mac Addr - k = j = strlen(this_char); - while(j-- > 0) - { - this_char[4-k+j] = this_char[j]; - } - - while(k < 4) - this_char[3-k++]='0'; - this_char[4]='\0'; - - if(strlen(this_char) == 4) - { - AtoH(this_char, temp, 2); - macAddr = *temp*256 + temp[1]; - if (macAddr < 0xFFFF) - { - RTMP_IO_READ32(pAdapter, macAddr, &macValue); - DBGPRINT(RT_DEBUG_TRACE, ("MacAddr=%lx, MacValue=%x\n", macAddr, macValue)); - sprintf(msg+strlen(msg), "[0x%08lX]:%08X ", macAddr , macValue); - } - else - {//Invalid parametes, so default printk all bbp - goto next; - } - } - } - else - { //Write - memcpy(&temp2, value, strlen(value)); - temp2[strlen(value)] = '\0'; - - // Sanity check - if((strlen(this_char) > 4) || strlen(temp2) > 8) - goto next; - - j = strlen(this_char); - while(j-- > 0) - { - if(this_char[j] > 'f' || this_char[j] < '0') - return; - } - - j = strlen(temp2); - while(j-- > 0) - { - if(temp2[j] > 'f' || temp2[j] < '0') - return; - } - - //MAC Addr - k = j = strlen(this_char); - while(j-- > 0) - { - this_char[4-k+j] = this_char[j]; - } - - while(k < 4) - this_char[3-k++]='0'; - this_char[4]='\0'; - - //MAC value - k = j = strlen(temp2); - while(j-- > 0) - { - temp2[8-k+j] = temp2[j]; - } - - while(k < 8) - temp2[7-k++]='0'; - temp2[8]='\0'; - - { - AtoH(this_char, temp, 2); - macAddr = *temp*256 + temp[1]; - - AtoH(temp2, temp, 4); - macValue = *temp*256*256*256 + temp[1]*256*256 + temp[2]*256 + temp[3]; - - // debug mode - if (macAddr == (HW_DEBUG_SETTING_BASE + 4)) - { - // 0x2bf4: byte0 non-zero: enable R17 tuning, 0: disable R17 tuning - if (macValue & 0x000000ff) - { - pAdapter->BbpTuning.bEnable = TRUE; - DBGPRINT(RT_DEBUG_TRACE,("turn on R17 tuning\n")); - } - else - { - UCHAR R66; - pAdapter->BbpTuning.bEnable = FALSE; - R66 = 0x26 + GET_LNA_GAIN(pAdapter); -#ifdef RALINK_ATE - if (ATE_ON(pAdapter)) - { - ATE_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R66, (0x26 + GET_LNA_GAIN(pAdapter))); - } - else -#endif // RALINK_ATE // - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R66, (0x26 + GET_LNA_GAIN(pAdapter))); - DBGPRINT(RT_DEBUG_TRACE,("turn off R17 tuning, restore to 0x%02x\n", R66)); - } - return; - } - - DBGPRINT(RT_DEBUG_TRACE, ("MacAddr=%02lx, MacValue=0x%x\n", macAddr, macValue)); - - RTMP_IO_WRITE32(pAdapter, macAddr, macValue); - sprintf(msg+strlen(msg), "[0x%08lX]:%08X ", macAddr, macValue); - } - } - } -next: - if(strlen(msg) == 1) - sprintf(msg+strlen(msg), "===>Error command format!"); - - // Copy the information into the user buffer - wrq->u.data.length = strlen(msg); - Status = copy_to_user(wrq->u.data.pointer, msg, wrq->u.data.length); - - DBGPRINT(RT_DEBUG_TRACE, ("<==RTMPIoctlMAC\n\n")); -} - -/* - ========================================================================== - Description: - Read / Write E2PROM - Arguments: - pAdapter Pointer to our adapter - wrq Pointer to the ioctl argument - - Return Value: - None - - Note: - Usage: - 1.) iwpriv ra0 e2p 0 ==> read E2PROM where Addr=0x0 - 2.) iwpriv ra0 e2p 0=1234 ==> write E2PROM where Addr=0x0, value=1234 - ========================================================================== -*/ -VOID RTMPIoctlE2PROM( - IN PRTMP_ADAPTER pAdapter, - IN struct iwreq *wrq) -{ - CHAR *this_char; - CHAR *value; - INT j = 0, k = 0; - CHAR msg[1024]; - CHAR arg[255]; - USHORT eepAddr = 0; - UCHAR temp[16], temp2[16]; - USHORT eepValue; - int Status; - - - memset(msg, 0x00, 1024); - if (wrq->u.data.length > 1) //No parameters. - { - Status = copy_from_user(arg, wrq->u.data.pointer, (wrq->u.data.length > 255) ? 255 : wrq->u.data.length); - sprintf(msg, "\n"); - - //Parsing Read or Write - this_char = arg; - - - if (!*this_char) - goto next; - - if ((value = rtstrchr(this_char, '=')) != NULL) - *value++ = 0; - - if (!value || !*value) - { //Read - - // Sanity check - if(strlen(this_char) > 4) - goto next; - - j = strlen(this_char); - while(j-- > 0) - { - if(this_char[j] > 'f' || this_char[j] < '0') - return; - } - - // E2PROM addr - k = j = strlen(this_char); - while(j-- > 0) - { - this_char[4-k+j] = this_char[j]; - } - - while(k < 4) - this_char[3-k++]='0'; - this_char[4]='\0'; - - if(strlen(this_char) == 4) - { - AtoH(this_char, temp, 2); - eepAddr = *temp*256 + temp[1]; - if (eepAddr < 0xFFFF) - { - RT28xx_EEPROM_READ16(pAdapter, eepAddr, eepValue); - sprintf(msg+strlen(msg), "[0x%04X]:0x%04X ", eepAddr , eepValue); - } - else - {//Invalid parametes, so default printk all bbp - goto next; - } - } - } - else - { //Write - memcpy(&temp2, value, strlen(value)); - temp2[strlen(value)] = '\0'; - - // Sanity check - if((strlen(this_char) > 4) || strlen(temp2) > 8) - goto next; - - j = strlen(this_char); - while(j-- > 0) - { - if(this_char[j] > 'f' || this_char[j] < '0') - return; - } - j = strlen(temp2); - while(j-- > 0) - { - if(temp2[j] > 'f' || temp2[j] < '0') - return; - } - - //MAC Addr - k = j = strlen(this_char); - while(j-- > 0) - { - this_char[4-k+j] = this_char[j]; - } - - while(k < 4) - this_char[3-k++]='0'; - this_char[4]='\0'; - - //MAC value - k = j = strlen(temp2); - while(j-- > 0) - { - temp2[4-k+j] = temp2[j]; - } - - while(k < 4) - temp2[3-k++]='0'; - temp2[4]='\0'; - - AtoH(this_char, temp, 2); - eepAddr = *temp*256 + temp[1]; - - AtoH(temp2, temp, 2); - eepValue = *temp*256 + temp[1]; - - RT28xx_EEPROM_WRITE16(pAdapter, eepAddr, eepValue); - sprintf(msg+strlen(msg), "[0x%02X]:%02X ", eepAddr, eepValue); - } - } -next: - if(strlen(msg) == 1) - sprintf(msg+strlen(msg), "===>Error command format!"); - - - // Copy the information into the user buffer - wrq->u.data.length = strlen(msg); - Status = copy_to_user(wrq->u.data.pointer, msg, wrq->u.data.length); - - DBGPRINT(RT_DEBUG_TRACE, ("<==RTMPIoctlE2PROM\n")); -} -#endif // DBG // - - - - -INT Set_TGnWifiTest_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - if (simple_strtol(arg, 0, 10) == 0) - pAd->StaCfg.bTGnWifiTest = FALSE; - else - pAd->StaCfg.bTGnWifiTest = TRUE; - - DBGPRINT(RT_DEBUG_TRACE, ("IF Set_TGnWifiTest_Proc::(bTGnWifiTest=%d)\n", pAd->StaCfg.bTGnWifiTest)); - return TRUE; -} - -INT Set_LongRetryLimit_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - TX_RTY_CFG_STRUC tx_rty_cfg; - UCHAR LongRetryLimit = (UCHAR)simple_strtol(arg, 0, 10); - - RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); - tx_rty_cfg.field.LongRtyLimit = LongRetryLimit; - RTMP_IO_WRITE32(pAdapter, TX_RTY_CFG, tx_rty_cfg.word); - DBGPRINT(RT_DEBUG_TRACE, ("IF Set_LongRetryLimit_Proc::(tx_rty_cfg=0x%x)\n", tx_rty_cfg.word)); - return TRUE; -} - -INT Set_ShortRetryLimit_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - TX_RTY_CFG_STRUC tx_rty_cfg; - UCHAR ShortRetryLimit = (UCHAR)simple_strtol(arg, 0, 10); - - RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); - tx_rty_cfg.field.ShortRtyLimit = ShortRetryLimit; - RTMP_IO_WRITE32(pAdapter, TX_RTY_CFG, tx_rty_cfg.word); - DBGPRINT(RT_DEBUG_TRACE, ("IF Set_ShortRetryLimit_Proc::(tx_rty_cfg=0x%x)\n", tx_rty_cfg.word)); - return TRUE; -} - -#ifdef EXT_BUILD_CHANNEL_LIST -INT Set_Ieee80211dClientMode_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - if (simple_strtol(arg, 0, 10) == 0) - pAdapter->StaCfg.IEEE80211dClientMode = Rt802_11_D_None; - else if (simple_strtol(arg, 0, 10) == 1) - pAdapter->StaCfg.IEEE80211dClientMode = Rt802_11_D_Flexible; - else if (simple_strtol(arg, 0, 10) == 2) - pAdapter->StaCfg.IEEE80211dClientMode = Rt802_11_D_Strict; - else - return FALSE; - - DBGPRINT(RT_DEBUG_TRACE, ("Set_Ieee802dMode_Proc::(IEEEE0211dMode=%d)\n", pAdapter->StaCfg.IEEE80211dClientMode)); - return TRUE; -} -#endif // EXT_BUILD_CHANNEL_LIST // - -#ifdef CARRIER_DETECTION_SUPPORT -INT Set_CarrierDetect_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - if (simple_strtol(arg, 0, 10) == 0) - pAd->CommonCfg.CarrierDetect.Enable = FALSE; - else - pAd->CommonCfg.CarrierDetect.Enable = TRUE; - - DBGPRINT(RT_DEBUG_TRACE, ("IF Set_CarrierDetect_Proc::(CarrierDetect.Enable=%d)\n", pAd->CommonCfg.CarrierDetect.Enable)); - return TRUE; -} -#endif // CARRIER_DETECTION_SUPPORT // - - -INT Show_Adhoc_MacTable_Proc( - IN PRTMP_ADAPTER pAd, - IN PCHAR extra) -{ - INT i; - - sprintf(extra, "\n"); - -#ifdef DOT11_N_SUPPORT - sprintf(extra, "%sHT Operating Mode : %d\n", extra, pAd->CommonCfg.AddHTInfo.AddHtInfo2.OperaionMode); -#endif // DOT11_N_SUPPORT // - - sprintf(extra, "%s\n%-19s%-4s%-4s%-7s%-7s%-7s%-10s%-6s%-6s%-6s%-6s\n", extra, - "MAC", "AID", "BSS", "RSSI0", "RSSI1", "RSSI2", "PhMd", "BW", "MCS", "SGI", "STBC"); - - for (i=1; iMacTab.Content[i]; - - if (strlen(extra) > (IW_PRIV_SIZE_MASK - 30)) - break; - if ((pEntry->ValidAsCLI || pEntry->ValidAsApCli) && (pEntry->Sst == SST_ASSOC)) - { - sprintf(extra, "%s%02X:%02X:%02X:%02X:%02X:%02X ", extra, - pEntry->Addr[0], pEntry->Addr[1], pEntry->Addr[2], - pEntry->Addr[3], pEntry->Addr[4], pEntry->Addr[5]); - sprintf(extra, "%s%-4d", extra, (int)pEntry->Aid); - sprintf(extra, "%s%-4d", extra, (int)pEntry->apidx); - sprintf(extra, "%s%-7d", extra, pEntry->RssiSample.AvgRssi0); - sprintf(extra, "%s%-7d", extra, pEntry->RssiSample.AvgRssi1); - sprintf(extra, "%s%-7d", extra, pEntry->RssiSample.AvgRssi2); - sprintf(extra, "%s%-10s", extra, GetPhyMode(pEntry->HTPhyMode.field.MODE)); - sprintf(extra, "%s%-6s", extra, GetBW(pEntry->HTPhyMode.field.BW)); - sprintf(extra, "%s%-6d", extra, pEntry->HTPhyMode.field.MCS); - sprintf(extra, "%s%-6d", extra, pEntry->HTPhyMode.field.ShortGI); - sprintf(extra, "%s%-6d", extra, pEntry->HTPhyMode.field.STBC); - sprintf(extra, "%s%-10d, %d, %d%%\n", extra, pEntry->DebugFIFOCount, pEntry->DebugTxCount, - (pEntry->DebugTxCount) ? ((pEntry->DebugTxCount-pEntry->DebugFIFOCount)*100/pEntry->DebugTxCount) : 0); - sprintf(extra, "%s\n", extra); - } - } - - return TRUE; -} - - +#include "../rt2860/sta_ioctl.c" diff --git a/drivers/staging/rt2870/sta_ioctl.c.patch b/drivers/staging/rt2870/sta_ioctl.c.patch deleted file mode 100644 index 8672b147a761..000000000000 --- a/drivers/staging/rt2870/sta_ioctl.c.patch +++ /dev/null @@ -1,18 +0,0 @@ ---- sta_ioctl.c 2008-09-19 14:37:52.000000000 +0800 -+++ sta_ioctl.c.fc9 2008-09-19 14:38:20.000000000 +0800 -@@ -49,15 +49,9 @@ - - #define GROUP_KEY_NO 4 - --#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) - #define IWE_STREAM_ADD_EVENT(_A, _B, _C, _D, _E) iwe_stream_add_event(_A, _B, _C, _D, _E) - #define IWE_STREAM_ADD_POINT(_A, _B, _C, _D, _E) iwe_stream_add_point(_A, _B, _C, _D, _E) - #define IWE_STREAM_ADD_VALUE(_A, _B, _C, _D, _E, _F) iwe_stream_add_value(_A, _B, _C, _D, _E, _F) --#else --#define IWE_STREAM_ADD_EVENT(_A, _B, _C, _D, _E) iwe_stream_add_event(_B, _C, _D, _E) --#define IWE_STREAM_ADD_POINT(_A, _B, _C, _D, _E) iwe_stream_add_point(_B, _C, _D, _E) --#define IWE_STREAM_ADD_VALUE(_A, _B, _C, _D, _E, _F) iwe_stream_add_value(_B, _C, _D, _E, _F) --#endif - - extern UCHAR CipherWpa2Template[]; - extern UCHAR CipherWpaPskTkip[]; diff --git a/drivers/staging/rt2870/tmp60 b/drivers/staging/rt2870/tmp60 deleted file mode 100644 index 975e44484379..000000000000 --- a/drivers/staging/rt2870/tmp60 +++ /dev/null @@ -1,7037 +0,0 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - sta_ioctl.c - - Abstract: - IOCTL related subroutines - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Rory Chen 01-03-2003 created - Rory Chen 02-14-2005 modify to support RT61 -*/ - -#include "rt_config.h" - -#ifdef DBG -extern ULONG RTDebugLevel; -#endif - -#define NR_WEP_KEYS 4 -#define WEP_SMALL_KEY_LEN (40/8) -#define WEP_LARGE_KEY_LEN (104/8) - -#define GROUP_KEY_NO 4 - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) -#define IWE_STREAM_ADD_EVENT(_A, _B, _C, _D, _E) iwe_stream_add_event(_A, _B, _C, _D, _E) -#define IWE_STREAM_ADD_POINT(_A, _B, _C, _D, _E) iwe_stream_add_point(_A, _B, _C, _D, _E) -#define IWE_STREAM_ADD_VALUE(_A, _B, _C, _D, _E, _F) iwe_stream_add_value(_A, _B, _C, _D, _E, _F) -#else -#define IWE_STREAM_ADD_EVENT(_A, _B, _C, _D, _E) iwe_stream_add_event(_B, _C, _D, _E) -#define IWE_STREAM_ADD_POINT(_A, _B, _C, _D, _E) iwe_stream_add_point(_B, _C, _D, _E) -#define IWE_STREAM_ADD_VALUE(_A, _B, _C, _D, _E, _F) iwe_stream_add_value(_B, _C, _D, _E, _F) -#endif - -extern UCHAR CipherWpa2Template[]; -extern UCHAR CipherWpaPskTkip[]; -extern UCHAR CipherWpaPskTkipLen; - -typedef struct PACKED _RT_VERSION_INFO{ - UCHAR DriverVersionW; - UCHAR DriverVersionX; - UCHAR DriverVersionY; - UCHAR DriverVersionZ; - UINT DriverBuildYear; - UINT DriverBuildMonth; - UINT DriverBuildDay; -} RT_VERSION_INFO, *PRT_VERSION_INFO; - -struct iw_priv_args privtab[] = { -{ RTPRIV_IOCTL_SET, - IW_PRIV_TYPE_CHAR | 1024, 0, - "set"}, - -{ RTPRIV_IOCTL_SHOW, 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, - ""}, -{ RTPRIV_IOCTL_SHOW, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, - ""}, -/* --- sub-ioctls definitions --- */ - { SHOW_CONN_STATUS, - 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "connStatus" }, - { SHOW_DRVIER_VERION, - 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "driverVer" }, - { SHOW_BA_INFO, - 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "bainfo" }, - { SHOW_DESC_INFO, - 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "descinfo" }, - { RAIO_OFF, - 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "radio_off" }, - { RAIO_ON, - 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "radio_on" }, -#ifdef QOS_DLS_SUPPORT - { SHOW_DLS_ENTRY_INFO, - 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "dlsentryinfo" }, -#endif // QOS_DLS_SUPPORT // - { SHOW_CFG_VALUE, - IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "show" }, - { SHOW_ADHOC_ENTRY_INFO, - 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "adhocEntry" }, - -/* --- sub-ioctls relations --- */ - -#ifdef DBG -{ RTPRIV_IOCTL_BBP, - IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, - "bbp"}, -{ RTPRIV_IOCTL_MAC, - IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | 1024, - "mac"}, -{ RTPRIV_IOCTL_E2P, - IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | 1024, - "e2p"}, -#endif /* DBG */ - -{ RTPRIV_IOCTL_STATISTICS, - 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, - "stat"}, -{ RTPRIV_IOCTL_GSITESURVEY, - 0, IW_PRIV_TYPE_CHAR | 1024, - "get_site_survey"}, -}; - -INT Set_SSID_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - -#ifdef WMM_SUPPORT -INT Set_WmmCapable_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); -#endif - -INT Set_NetworkType_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - -INT Set_AuthMode_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - -INT Set_EncrypType_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - -INT Set_DefaultKeyID_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - -INT Set_Key1_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - -INT Set_Key2_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - -INT Set_Key3_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - -INT Set_Key4_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - -INT Set_WPAPSK_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - - -INT Set_PSMode_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - -#ifdef WPA_SUPPLICANT_SUPPORT -INT Set_Wpa_Support( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); -#endif // WPA_SUPPLICANT_SUPPORT // - -#ifdef DBG -VOID RTMPIoctlBBP( - IN PRTMP_ADAPTER pAdapter, - IN struct iwreq *wrq); - -VOID RTMPIoctlMAC( - IN PRTMP_ADAPTER pAdapter, - IN struct iwreq *wrq); - -VOID RTMPIoctlE2PROM( - IN PRTMP_ADAPTER pAdapter, - IN struct iwreq *wrq); -#endif // DBG // - - -NDIS_STATUS RTMPWPANoneAddKeyProc( - IN PRTMP_ADAPTER pAd, - IN PVOID pBuf); - -INT Set_FragTest_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - -#ifdef DOT11_N_SUPPORT -INT Set_TGnWifiTest_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); -#endif // DOT11_N_SUPPORT // - -INT Set_LongRetryLimit_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - -INT Set_ShortRetryLimit_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - -#ifdef EXT_BUILD_CHANNEL_LIST -INT Set_Ieee80211dClientMode_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); -#endif // EXT_BUILD_CHANNEL_LIST // - -#ifdef CARRIER_DETECTION_SUPPORT -INT Set_CarrierDetect_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); -#endif // CARRIER_DETECTION_SUPPORT // - -INT Show_Adhoc_MacTable_Proc( - IN PRTMP_ADAPTER pAd, - IN PCHAR extra); - -static struct { - CHAR *name; - INT (*set_proc)(PRTMP_ADAPTER pAdapter, PUCHAR arg); -} *PRTMP_PRIVATE_SET_PROC, RTMP_PRIVATE_SUPPORT_PROC[] = { - {"DriverVersion", Set_DriverVersion_Proc}, - {"CountryRegion", Set_CountryRegion_Proc}, - {"CountryRegionABand", Set_CountryRegionABand_Proc}, - {"SSID", Set_SSID_Proc}, - {"WirelessMode", Set_WirelessMode_Proc}, - {"TxBurst", Set_TxBurst_Proc}, - {"TxPreamble", Set_TxPreamble_Proc}, - {"TxPower", Set_TxPower_Proc}, - {"Channel", Set_Channel_Proc}, - {"BGProtection", Set_BGProtection_Proc}, - {"RTSThreshold", Set_RTSThreshold_Proc}, - {"FragThreshold", Set_FragThreshold_Proc}, -#ifdef DOT11_N_SUPPORT - {"HtBw", Set_HtBw_Proc}, - {"HtMcs", Set_HtMcs_Proc}, - {"HtGi", Set_HtGi_Proc}, - {"HtOpMode", Set_HtOpMode_Proc}, - {"HtExtcha", Set_HtExtcha_Proc}, - {"HtMpduDensity", Set_HtMpduDensity_Proc}, - {"HtBaWinSize", Set_HtBaWinSize_Proc}, - {"HtRdg", Set_HtRdg_Proc}, - {"HtAmsdu", Set_HtAmsdu_Proc}, - {"HtAutoBa", Set_HtAutoBa_Proc}, - {"HtBaDecline", Set_BADecline_Proc}, - {"HtProtect", Set_HtProtect_Proc}, - {"HtMimoPs", Set_HtMimoPs_Proc}, -#endif // DOT11_N_SUPPORT // - -#ifdef AGGREGATION_SUPPORT - {"PktAggregate", Set_PktAggregate_Proc}, -#endif - -#ifdef WMM_SUPPORT - {"WmmCapable", Set_WmmCapable_Proc}, -#endif - {"IEEE80211H", Set_IEEE80211H_Proc}, - {"NetworkType", Set_NetworkType_Proc}, - {"AuthMode", Set_AuthMode_Proc}, - {"EncrypType", Set_EncrypType_Proc}, - {"DefaultKeyID", Set_DefaultKeyID_Proc}, - {"Key1", Set_Key1_Proc}, - {"Key2", Set_Key2_Proc}, - {"Key3", Set_Key3_Proc}, - {"Key4", Set_Key4_Proc}, - {"WPAPSK", Set_WPAPSK_Proc}, - {"ResetCounter", Set_ResetStatCounter_Proc}, - {"PSMode", Set_PSMode_Proc}, -#ifdef DBG - {"Debug", Set_Debug_Proc}, -#endif - -#ifdef RALINK_ATE - {"ATE", Set_ATE_Proc}, - {"ATEDA", Set_ATE_DA_Proc}, - {"ATESA", Set_ATE_SA_Proc}, - {"ATEBSSID", Set_ATE_BSSID_Proc}, - {"ATECHANNEL", Set_ATE_CHANNEL_Proc}, - {"ATETXPOW0", Set_ATE_TX_POWER0_Proc}, - {"ATETXPOW1", Set_ATE_TX_POWER1_Proc}, - {"ATETXANT", Set_ATE_TX_Antenna_Proc}, - {"ATERXANT", Set_ATE_RX_Antenna_Proc}, - {"ATETXFREQOFFSET", Set_ATE_TX_FREQOFFSET_Proc}, - {"ATETXBW", Set_ATE_TX_BW_Proc}, - {"ATETXLEN", Set_ATE_TX_LENGTH_Proc}, - {"ATETXCNT", Set_ATE_TX_COUNT_Proc}, - {"ATETXMCS", Set_ATE_TX_MCS_Proc}, - {"ATETXMODE", Set_ATE_TX_MODE_Proc}, - {"ATETXGI", Set_ATE_TX_GI_Proc}, - {"ATERXFER", Set_ATE_RX_FER_Proc}, - {"ATERRF", Set_ATE_Read_RF_Proc}, - {"ATEWRF1", Set_ATE_Write_RF1_Proc}, - {"ATEWRF2", Set_ATE_Write_RF2_Proc}, - {"ATEWRF3", Set_ATE_Write_RF3_Proc}, - {"ATEWRF4", Set_ATE_Write_RF4_Proc}, - {"ATELDE2P", Set_ATE_Load_E2P_Proc}, - {"ATERE2P", Set_ATE_Read_E2P_Proc}, - {"ATESHOW", Set_ATE_Show_Proc}, - {"ATEHELP", Set_ATE_Help_Proc}, - -#ifdef RALINK_28xx_QA - {"TxStop", Set_TxStop_Proc}, - {"RxStop", Set_RxStop_Proc}, -#endif // RALINK_28xx_QA // -#endif // RALINK_ATE // - -#ifdef WPA_SUPPLICANT_SUPPORT - {"WpaSupport", Set_Wpa_Support}, -#endif // WPA_SUPPLICANT_SUPPORT // - - - - {"FixedTxMode", Set_FixedTxMode_Proc}, -#ifdef CONFIG_APSTA_MIXED_SUPPORT - {"OpMode", Set_OpMode_Proc}, -#endif // CONFIG_APSTA_MIXED_SUPPORT // -#ifdef DOT11_N_SUPPORT - {"TGnWifiTest", Set_TGnWifiTest_Proc}, - {"ForceGF", Set_ForceGF_Proc}, -#endif // DOT11_N_SUPPORT // -#ifdef QOS_DLS_SUPPORT - {"DlsAddEntry", Set_DlsAddEntry_Proc}, - {"DlsTearDownEntry", Set_DlsTearDownEntry_Proc}, -#endif // QOS_DLS_SUPPORT // - {"LongRetry", Set_LongRetryLimit_Proc}, - {"ShortRetry", Set_ShortRetryLimit_Proc}, -#ifdef EXT_BUILD_CHANNEL_LIST - {"11dClientMode", Set_Ieee80211dClientMode_Proc}, -#endif // EXT_BUILD_CHANNEL_LIST // -#ifdef CARRIER_DETECTION_SUPPORT - {"CarrierDetect", Set_CarrierDetect_Proc}, -#endif // CARRIER_DETECTION_SUPPORT // - - {NULL,} -}; - - -VOID RTMPAddKey( - IN PRTMP_ADAPTER pAd, - IN PNDIS_802_11_KEY pKey) -{ - ULONG KeyIdx; - MAC_TABLE_ENTRY *pEntry; - - DBGPRINT(RT_DEBUG_TRACE, ("RTMPAddKey ------>\n")); - - if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - { - if (pKey->KeyIndex & 0x80000000) - { - if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) - { - NdisZeroMemory(pAd->StaCfg.PMK, 32); - NdisMoveMemory(pAd->StaCfg.PMK, pKey->KeyMaterial, pKey->KeyLength); - goto end; - } - // Update PTK - NdisZeroMemory(&pAd->SharedKey[BSS0][0], sizeof(CIPHER_KEY)); - pAd->SharedKey[BSS0][0].KeyLen = LEN_TKIP_EK; - NdisMoveMemory(pAd->SharedKey[BSS0][0].Key, pKey->KeyMaterial, LEN_TKIP_EK); -#ifdef WPA_SUPPLICANT_SUPPORT - if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled) - { - NdisMoveMemory(pAd->SharedKey[BSS0][0].RxMic, pKey->KeyMaterial + LEN_TKIP_EK, LEN_TKIP_TXMICK); - NdisMoveMemory(pAd->SharedKey[BSS0][0].TxMic, pKey->KeyMaterial + LEN_TKIP_EK + LEN_TKIP_TXMICK, LEN_TKIP_RXMICK); - } - else -#endif // WPA_SUPPLICANT_SUPPORT // - { - NdisMoveMemory(pAd->SharedKey[BSS0][0].TxMic, pKey->KeyMaterial + LEN_TKIP_EK, LEN_TKIP_TXMICK); - NdisMoveMemory(pAd->SharedKey[BSS0][0].RxMic, pKey->KeyMaterial + LEN_TKIP_EK + LEN_TKIP_TXMICK, LEN_TKIP_RXMICK); - } - - // Decide its ChiperAlg - if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled) - pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_TKIP; - else if (pAd->StaCfg.PairCipher == Ndis802_11Encryption3Enabled) - pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_AES; - else - pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_NONE; - - // Update these related information to MAC_TABLE_ENTRY - pEntry = &pAd->MacTab.Content[BSSID_WCID]; - NdisMoveMemory(pEntry->PairwiseKey.Key, pAd->SharedKey[BSS0][0].Key, LEN_TKIP_EK); - NdisMoveMemory(pEntry->PairwiseKey.RxMic, pAd->SharedKey[BSS0][0].RxMic, LEN_TKIP_RXMICK); - NdisMoveMemory(pEntry->PairwiseKey.TxMic, pAd->SharedKey[BSS0][0].TxMic, LEN_TKIP_TXMICK); - pEntry->PairwiseKey.CipherAlg = pAd->SharedKey[BSS0][0].CipherAlg; - - // Update pairwise key information to ASIC Shared Key Table - AsicAddSharedKeyEntry(pAd, - BSS0, - 0, - pAd->SharedKey[BSS0][0].CipherAlg, - pAd->SharedKey[BSS0][0].Key, - pAd->SharedKey[BSS0][0].TxMic, - pAd->SharedKey[BSS0][0].RxMic); - - // Update ASIC WCID attribute table and IVEIV table - RTMPAddWcidAttributeEntry(pAd, - BSS0, - 0, - pAd->SharedKey[BSS0][0].CipherAlg, - pEntry); - - if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA2) - { - // set 802.1x port control - //pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; - STA_PORT_SECURED(pAd); - - // Indicate Connected for GUI - pAd->IndicateMediaState = NdisMediaStateConnected; - } - } - else - { - // Update GTK - pAd->StaCfg.DefaultKeyId = (pKey->KeyIndex & 0xFF); - NdisZeroMemory(&pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId], sizeof(CIPHER_KEY)); - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].KeyLen = LEN_TKIP_EK; - NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, pKey->KeyMaterial, LEN_TKIP_EK); -#ifdef WPA_SUPPLICANT_SUPPORT - if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption2Enabled) - { - NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic, pKey->KeyMaterial + LEN_TKIP_EK, LEN_TKIP_TXMICK); - NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, pKey->KeyMaterial + LEN_TKIP_EK + LEN_TKIP_TXMICK, LEN_TKIP_RXMICK); - } - else -#endif // WPA_SUPPLICANT_SUPPORT // - { - NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, pKey->KeyMaterial + LEN_TKIP_EK, LEN_TKIP_TXMICK); - NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic, pKey->KeyMaterial + LEN_TKIP_EK + LEN_TKIP_TXMICK, LEN_TKIP_RXMICK); - } - - // Update Shared Key CipherAlg - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_NONE; - if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption2Enabled) - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_TKIP; - else if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption3Enabled) - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_AES; - - // Update group key information to ASIC Shared Key Table - AsicAddSharedKeyEntry(pAd, - BSS0, - pAd->StaCfg.DefaultKeyId, - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic); - - // Update ASIC WCID attribute table and IVEIV table - RTMPAddWcidAttributeEntry(pAd, - BSS0, - pAd->StaCfg.DefaultKeyId, - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, - NULL); - - // set 802.1x port control - //pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; - STA_PORT_SECURED(pAd); - - // Indicate Connected for GUI - pAd->IndicateMediaState = NdisMediaStateConnected; - } - } - else // dynamic WEP from wpa_supplicant - { - UCHAR CipherAlg; - PUCHAR Key; - - if(pKey->KeyLength == 32) - goto end; - - KeyIdx = pKey->KeyIndex & 0x0fffffff; - - if (KeyIdx < 4) - { - // it is a default shared key, for Pairwise key setting - if (pKey->KeyIndex & 0x80000000) - { - pEntry = MacTableLookup(pAd, pKey->BSSID); - - if (pEntry) - { - DBGPRINT(RT_DEBUG_TRACE, ("RTMPAddKey: Set Pair-wise Key\n")); - - // set key material and key length - pEntry->PairwiseKey.KeyLen = (UCHAR)pKey->KeyLength; - NdisMoveMemory(pEntry->PairwiseKey.Key, &pKey->KeyMaterial, pKey->KeyLength); - - // set Cipher type - if (pKey->KeyLength == 5) - pEntry->PairwiseKey.CipherAlg = CIPHER_WEP64; - else - pEntry->PairwiseKey.CipherAlg = CIPHER_WEP128; - - // Add Pair-wise key to Asic - AsicAddPairwiseKeyEntry( - pAd, - pEntry->Addr, - (UCHAR)pEntry->Aid, - &pEntry->PairwiseKey); - - // update WCID attribute table and IVEIV table for this entry - RTMPAddWcidAttributeEntry( - pAd, - BSS0, - KeyIdx, // The value may be not zero - pEntry->PairwiseKey.CipherAlg, - pEntry); - - } - } - else - { - // Default key for tx (shared key) - pAd->StaCfg.DefaultKeyId = (UCHAR) KeyIdx; - - // set key material and key length - pAd->SharedKey[BSS0][KeyIdx].KeyLen = (UCHAR) pKey->KeyLength; - NdisMoveMemory(pAd->SharedKey[BSS0][KeyIdx].Key, &pKey->KeyMaterial, pKey->KeyLength); - - // Set Ciper type - if (pKey->KeyLength == 5) - pAd->SharedKey[BSS0][KeyIdx].CipherAlg = CIPHER_WEP64; - else - pAd->SharedKey[BSS0][KeyIdx].CipherAlg = CIPHER_WEP128; - - CipherAlg = pAd->SharedKey[BSS0][KeyIdx].CipherAlg; - Key = pAd->SharedKey[BSS0][KeyIdx].Key; - - // Set Group key material to Asic - AsicAddSharedKeyEntry(pAd, BSS0, KeyIdx, CipherAlg, Key, NULL, NULL); - - // Update WCID attribute table and IVEIV table for this group key table - RTMPAddWcidAttributeEntry(pAd, BSS0, KeyIdx, CipherAlg, NULL); - - } - } - } -end: - return; -} - -char * rtstrchr(const char * s, int c) -{ - for(; *s != (char) c; ++s) - if (*s == '\0') - return NULL; - return (char *) s; -} - -/* -This is required for LinEX2004/kernel2.6.7 to provide iwlist scanning function -*/ - -int -rt_ioctl_giwname(struct net_device *dev, - struct iw_request_info *info, - char *name, char *extra) -{ -// PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; - -#ifdef RT2870 - strncpy(name, "RT2870 Wireless", IFNAMSIZ); -#endif // RT2870 // - return 0; -} - -int rt_ioctl_siwfreq(struct net_device *dev, - struct iw_request_info *info, - struct iw_freq *freq, char *extra) -{ - PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; - int chan = -1; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - - if (freq->e > 1) - return -EINVAL; - - if((freq->e == 0) && (freq->m <= 1000)) - chan = freq->m; // Setting by channel number - else - MAP_KHZ_TO_CHANNEL_ID( (freq->m /100) , chan); // Setting by frequency - search the table , like 2.412G, 2.422G, - - if (ChannelSanity(pAdapter, chan) == TRUE) - { - pAdapter->CommonCfg.Channel = chan; - DBGPRINT(RT_DEBUG_ERROR, ("==>rt_ioctl_siwfreq::SIOCSIWFREQ[cmd=0x%x] (Channel=%d)\n", SIOCSIWFREQ, pAdapter->CommonCfg.Channel)); - } - else - return -EINVAL; - - return 0; -} -int rt_ioctl_giwfreq(struct net_device *dev, - struct iw_request_info *info, - struct iw_freq *freq, char *extra) -{ - VIRTUAL_ADAPTER *pVirtualAd = NULL; - PRTMP_ADAPTER pAdapter = NULL; - UCHAR ch; - ULONG m; - - if (dev->priv_flags == INT_MAIN) - { - pAdapter = dev->priv; - } - else - { - pVirtualAd = dev->priv; - if (pVirtualAd && pVirtualAd->RtmpDev) - pAdapter = pVirtualAd->RtmpDev->priv; - } - - if (pAdapter == NULL) - { - /* if 1st open fail, pAd will be free; - So the net_dev->priv will be NULL in 2rd open */ - return -ENETDOWN; - } - - ch = pAdapter->CommonCfg.Channel; - - DBGPRINT(RT_DEBUG_TRACE,("==>rt_ioctl_giwfreq %d\n", ch)); - - MAP_CHANNEL_ID_TO_KHZ(ch, m); - freq->m = m * 100; - freq->e = 1; - return 0; -} - -int rt_ioctl_siwmode(struct net_device *dev, - struct iw_request_info *info, - __u32 *mode, char *extra) -{ - PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - switch (*mode) - { - case IW_MODE_ADHOC: - Set_NetworkType_Proc(pAdapter, "Adhoc"); - break; - case IW_MODE_INFRA: - Set_NetworkType_Proc(pAdapter, "Infra"); - break; -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,20)) - case IW_MODE_MONITOR: - Set_NetworkType_Proc(pAdapter, "Monitor"); - break; -#endif - default: - DBGPRINT(RT_DEBUG_TRACE, ("===>rt_ioctl_siwmode::SIOCSIWMODE (unknown %d)\n", *mode)); - return -EINVAL; - } - - // Reset Ralink supplicant to not use, it will be set to start when UI set PMK key - pAdapter->StaCfg.WpaState = SS_NOTUSE; - - return 0; -} - -int rt_ioctl_giwmode(struct net_device *dev, - struct iw_request_info *info, - __u32 *mode, char *extra) -{ - PRTMP_ADAPTER pAdapter = NULL; - VIRTUAL_ADAPTER *pVirtualAd = NULL; - - if (dev->priv_flags == INT_MAIN) - { - pAdapter = dev->priv; - } - else - { - pVirtualAd = dev->priv; - if (pVirtualAd && pVirtualAd->RtmpDev) - pAdapter = pVirtualAd->RtmpDev->priv; - } - - if (pAdapter == NULL) - { - /* if 1st open fail, pAd will be free; - So the net_dev->priv will be NULL in 2rd open */ - return -ENETDOWN; - } - - if (ADHOC_ON(pAdapter)) - *mode = IW_MODE_ADHOC; - else if (INFRA_ON(pAdapter)) - *mode = IW_MODE_INFRA; -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,20)) - else if (MONITOR_ON(pAdapter)) - { - *mode = IW_MODE_MONITOR; - } -#endif - else - *mode = IW_MODE_AUTO; - - DBGPRINT(RT_DEBUG_TRACE, ("==>rt_ioctl_giwmode(mode=%d)\n", *mode)); - return 0; -} - -int rt_ioctl_siwsens(struct net_device *dev, - struct iw_request_info *info, - char *name, char *extra) -{ - PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - return 0; -} - -int rt_ioctl_giwsens(struct net_device *dev, - struct iw_request_info *info, - char *name, char *extra) -{ - return 0; -} - -int rt_ioctl_giwrange(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *extra) -{ - PRTMP_ADAPTER pAdapter = NULL; - VIRTUAL_ADAPTER *pVirtualAd = NULL; - struct iw_range *range = (struct iw_range *) extra; - u16 val; - int i; - - if (dev->priv_flags == INT_MAIN) - { - pAdapter = dev->priv; - } - else - { - pVirtualAd = dev->priv; - if (pVirtualAd && pVirtualAd->RtmpDev) - pAdapter = pVirtualAd->RtmpDev->priv; - } - - if (pAdapter == NULL) - { - /* if 1st open fail, pAd will be free; - So the net_dev->priv will be NULL in 2rd open */ - return -ENETDOWN; - } - - DBGPRINT(RT_DEBUG_TRACE ,("===>rt_ioctl_giwrange\n")); - data->length = sizeof(struct iw_range); - memset(range, 0, sizeof(struct iw_range)); - - range->txpower_capa = IW_TXPOW_DBM; - - if (INFRA_ON(pAdapter)||ADHOC_ON(pAdapter)) - { - range->min_pmp = 1 * 1024; - range->max_pmp = 65535 * 1024; - range->min_pmt = 1 * 1024; - range->max_pmt = 1000 * 1024; - range->pmp_flags = IW_POWER_PERIOD; - range->pmt_flags = IW_POWER_TIMEOUT; - range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | - IW_POWER_UNICAST_R | IW_POWER_ALL_R; - } - - range->we_version_compiled = WIRELESS_EXT; - range->we_version_source = 14; - - range->retry_capa = IW_RETRY_LIMIT; - range->retry_flags = IW_RETRY_LIMIT; - range->min_retry = 0; - range->max_retry = 255; - - range->num_channels = pAdapter->ChannelListNum; - - val = 0; - for (i = 1; i <= range->num_channels; i++) - { - u32 m; - range->freq[val].i = pAdapter->ChannelList[i-1].Channel; - MAP_CHANNEL_ID_TO_KHZ(pAdapter->ChannelList[i-1].Channel, m); - range->freq[val].m = m * 100; /* HZ */ - - range->freq[val].e = 1; - val++; - if (val == IW_MAX_FREQUENCIES) - break; - } - range->num_frequency = val; - - range->max_qual.qual = 100; /* what is correct max? This was not - * documented exactly. At least - * 69 has been observed. */ - range->max_qual.level = 0; /* dB */ - range->max_qual.noise = 0; /* dB */ - - /* What would be suitable values for "average/typical" qual? */ - range->avg_qual.qual = 20; - range->avg_qual.level = -60; - range->avg_qual.noise = -95; - range->sensitivity = 3; - - range->max_encoding_tokens = NR_WEP_KEYS; - range->num_encoding_sizes = 2; - range->encoding_size[0] = 5; - range->encoding_size[1] = 13; - - range->min_rts = 0; - range->max_rts = 2347; - range->min_frag = 256; - range->max_frag = 2346; - -#if WIRELESS_EXT > 17 - /* IW_ENC_CAPA_* bit field */ - range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | - IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; -#endif - - return 0; -} - -int rt_ioctl_siwap(struct net_device *dev, - struct iw_request_info *info, - struct sockaddr *ap_addr, char *extra) -{ - PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; - NDIS_802_11_MAC_ADDRESS Bssid; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) - { - RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); - DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); - } - - // tell CNTL state machine to call NdisMSetInformationComplete() after completing - // this request, because this request is initiated by NDIS. - pAdapter->MlmeAux.CurrReqIsFromNdis = FALSE; - // Prevent to connect AP again in STAMlmePeriodicExec - pAdapter->MlmeAux.AutoReconnectSsidLen= 32; - - memset(Bssid, 0, MAC_ADDR_LEN); - memcpy(Bssid, ap_addr->sa_data, MAC_ADDR_LEN); - MlmeEnqueue(pAdapter, - MLME_CNTL_STATE_MACHINE, - OID_802_11_BSSID, - sizeof(NDIS_802_11_MAC_ADDRESS), - (VOID *)&Bssid); - - DBGPRINT(RT_DEBUG_TRACE, ("IOCTL::SIOCSIWAP %02x:%02x:%02x:%02x:%02x:%02x\n", - Bssid[0], Bssid[1], Bssid[2], Bssid[3], Bssid[4], Bssid[5])); - - return 0; -} - -int rt_ioctl_giwap(struct net_device *dev, - struct iw_request_info *info, - struct sockaddr *ap_addr, char *extra) -{ - PRTMP_ADAPTER pAdapter = NULL; - VIRTUAL_ADAPTER *pVirtualAd = NULL; - - if (dev->priv_flags == INT_MAIN) - { - pAdapter = dev->priv; - } - else - { - pVirtualAd = dev->priv; - if (pVirtualAd && pVirtualAd->RtmpDev) - pAdapter = pVirtualAd->RtmpDev->priv; - } - - if (pAdapter == NULL) - { - /* if 1st open fail, pAd will be free; - So the net_dev->priv will be NULL in 2rd open */ - return -ENETDOWN; - } - - if (INFRA_ON(pAdapter) || ADHOC_ON(pAdapter)) - { - ap_addr->sa_family = ARPHRD_ETHER; - memcpy(ap_addr->sa_data, &pAdapter->CommonCfg.Bssid, ETH_ALEN); - } -#ifdef WPA_SUPPLICANT_SUPPORT - // Add for RT2870 - else if (pAdapter->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_DISABLE) - { - ap_addr->sa_family = ARPHRD_ETHER; - memcpy(ap_addr->sa_data, &pAdapter->MlmeAux.Bssid, ETH_ALEN); - } -#endif // WPA_SUPPLICANT_SUPPORT // - else - { - DBGPRINT(RT_DEBUG_TRACE, ("IOCTL::SIOCGIWAP(=EMPTY)\n")); - return -ENOTCONN; - } - - return 0; -} - -/* - * Units are in db above the noise floor. That means the - * rssi values reported in the tx/rx descriptors in the - * driver are the SNR expressed in db. - * - * If you assume that the noise floor is -95, which is an - * excellent assumption 99.5 % of the time, then you can - * derive the absolute signal level (i.e. -95 + rssi). - * There are some other slight factors to take into account - * depending on whether the rssi measurement is from 11b, - * 11g, or 11a. These differences are at most 2db and - * can be documented. - * - * NB: various calculations are based on the orinoco/wavelan - * drivers for compatibility - */ -static void set_quality(PRTMP_ADAPTER pAdapter, - struct iw_quality *iq, - signed char rssi) -{ - __u8 ChannelQuality; - - // Normalize Rssi - if (rssi >= -50) - ChannelQuality = 100; - else if (rssi >= -80) // between -50 ~ -80dbm - ChannelQuality = (__u8)(24 + ((rssi + 80) * 26)/10); - else if (rssi >= -90) // between -80 ~ -90dbm - ChannelQuality = (__u8)((rssi + 90) * 26)/10; - else - ChannelQuality = 0; - - iq->qual = (__u8)ChannelQuality; - - iq->level = (__u8)(rssi); - iq->noise = (pAdapter->BbpWriteLatch[66] > pAdapter->BbpTuning.FalseCcaUpperThreshold) ? ((__u8)pAdapter->BbpTuning.FalseCcaUpperThreshold) : ((__u8) pAdapter->BbpWriteLatch[66]); // noise level (dBm) - iq->noise += 256 - 143; - iq->updated = pAdapter->iw_stats.qual.updated; -} - -int rt_ioctl_iwaplist(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *extra) -{ - PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; - - struct sockaddr addr[IW_MAX_AP]; - struct iw_quality qual[IW_MAX_AP]; - int i; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - data->length = 0; - return 0; - //return -ENETDOWN; - } - - for (i = 0; i = pAdapter->ScanTab.BssNr) - break; - addr[i].sa_family = ARPHRD_ETHER; - memcpy(addr[i].sa_data, &pAdapter->ScanTab.BssEntry[i].Bssid, MAC_ADDR_LEN); - set_quality(pAdapter, &qual[i], pAdapter->ScanTab.BssEntry[i].Rssi); - } - data->length = i; - memcpy(extra, &addr, i*sizeof(addr[0])); - data->flags = 1; /* signal quality present (sort of) */ - memcpy(extra + i*sizeof(addr[0]), &qual, i*sizeof(qual[i])); - - return 0; -} - -#ifdef SIOCGIWSCAN -int rt_ioctl_siwscan(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *extra) -{ - PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; - - ULONG Now; - int Status = NDIS_STATUS_SUCCESS; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - if (MONITOR_ON(pAdapter)) - { - DBGPRINT(RT_DEBUG_TRACE, ("!!! Driver is in Monitor Mode now !!!\n")); - return -EINVAL; - } - - -#ifdef WPA_SUPPLICANT_SUPPORT - if (pAdapter->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_ENABLE) - { - pAdapter->StaCfg.WpaSupplicantScanCount++; - } -#endif // WPA_SUPPLICANT_SUPPORT // - - pAdapter->StaCfg.bScanReqIsFromWebUI = TRUE; - if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) - return 0; - do{ - Now = jiffies; - -#ifdef WPA_SUPPLICANT_SUPPORT - if ((pAdapter->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_ENABLE) && - (pAdapter->StaCfg.WpaSupplicantScanCount > 3)) - { - DBGPRINT(RT_DEBUG_TRACE, ("!!! WpaSupplicantScanCount > 3\n")); - Status = NDIS_STATUS_SUCCESS; - break; - } -#endif // WPA_SUPPLICANT_SUPPORT // - - if ((OPSTATUS_TEST_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED)) && - ((pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || - (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) && - (pAdapter->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED)) - { - DBGPRINT(RT_DEBUG_TRACE, ("!!! Link UP, Port Not Secured! ignore this set::OID_802_11_BSSID_LIST_SCAN\n")); - Status = NDIS_STATUS_SUCCESS; - break; - } - - if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) - { - RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); - DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); - } - - // tell CNTL state machine to call NdisMSetInformationComplete() after completing - // this request, because this request is initiated by NDIS. - pAdapter->MlmeAux.CurrReqIsFromNdis = FALSE; - // Reset allowed scan retries - pAdapter->StaCfg.ScanCnt = 0; - pAdapter->StaCfg.LastScanTime = Now; - - MlmeEnqueue(pAdapter, - MLME_CNTL_STATE_MACHINE, - OID_802_11_BSSID_LIST_SCAN, - 0, - NULL); - - Status = NDIS_STATUS_SUCCESS; - RT28XX_MLME_HANDLER(pAdapter); - }while(0); - return 0; -} - -int rt_ioctl_giwscan(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *extra) -{ - - PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; - int i=0; - char *current_ev = extra, *previous_ev = extra; - char *end_buf; - char *current_val, custom[MAX_CUSTOM_LEN] = {0}; -#ifndef IWEVGENIE - char idx; -#endif // IWEVGENIE // - struct iw_event iwe; - - if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) - { - /* - * Still scanning, indicate the caller should try again. - */ - return -EAGAIN; - } - - -#ifdef WPA_SUPPLICANT_SUPPORT - if (pAdapter->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_ENABLE) - { - pAdapter->StaCfg.WpaSupplicantScanCount = 0; - } -#endif // WPA_SUPPLICANT_SUPPORT // - - if (pAdapter->ScanTab.BssNr == 0) - { - data->length = 0; - return 0; - } - -#if WIRELESS_EXT >= 17 - if (data->length > 0) - end_buf = extra + data->length; - else - end_buf = extra + IW_SCAN_MAX_DATA; -#else - end_buf = extra + IW_SCAN_MAX_DATA; -#endif - - for (i = 0; i < pAdapter->ScanTab.BssNr; i++) - { - if (current_ev >= end_buf) - { -#if WIRELESS_EXT >= 17 - return -E2BIG; -#else - break; -#endif - } - - //MAC address - //================================ - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWAP; - iwe.u.ap_addr.sa_family = ARPHRD_ETHER; - memcpy(iwe.u.ap_addr.sa_data, &pAdapter->ScanTab.BssEntry[i].Bssid, ETH_ALEN); - - previous_ev = current_ev; - current_ev = IWE_STREAM_ADD_EVENT(info, current_ev,end_buf, &iwe, IW_EV_ADDR_LEN); - if (current_ev == previous_ev) -#if WIRELESS_EXT >= 17 - return -E2BIG; -#else - break; -#endif - - //ESSID - //================================ - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWESSID; - iwe.u.data.length = pAdapter->ScanTab.BssEntry[i].SsidLen; - iwe.u.data.flags = 1; - - previous_ev = current_ev; - current_ev = IWE_STREAM_ADD_POINT(info, current_ev,end_buf, &iwe, pAdapter->ScanTab.BssEntry[i].Ssid); - if (current_ev == previous_ev) -#if WIRELESS_EXT >= 17 - return -E2BIG; -#else - break; -#endif - - //Network Type - //================================ - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWMODE; - if (pAdapter->ScanTab.BssEntry[i].BssType == Ndis802_11IBSS) - { - iwe.u.mode = IW_MODE_ADHOC; - } - else if (pAdapter->ScanTab.BssEntry[i].BssType == Ndis802_11Infrastructure) - { - iwe.u.mode = IW_MODE_INFRA; - } - else - { - iwe.u.mode = IW_MODE_AUTO; - } - iwe.len = IW_EV_UINT_LEN; - - previous_ev = current_ev; - current_ev = IWE_STREAM_ADD_EVENT(info, current_ev, end_buf, &iwe, IW_EV_UINT_LEN); - if (current_ev == previous_ev) -#if WIRELESS_EXT >= 17 - return -E2BIG; -#else - break; -#endif - - //Channel and Frequency - //================================ - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWFREQ; - if (INFRA_ON(pAdapter) || ADHOC_ON(pAdapter)) - iwe.u.freq.m = pAdapter->ScanTab.BssEntry[i].Channel; - else - iwe.u.freq.m = pAdapter->ScanTab.BssEntry[i].Channel; - iwe.u.freq.e = 0; - iwe.u.freq.i = 0; - - previous_ev = current_ev; - current_ev = IWE_STREAM_ADD_EVENT(info, current_ev,end_buf, &iwe, IW_EV_FREQ_LEN); - if (current_ev == previous_ev) -#if WIRELESS_EXT >= 17 - return -E2BIG; -#else - break; -#endif - - //Add quality statistics - //================================ - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = IWEVQUAL; - iwe.u.qual.level = 0; - iwe.u.qual.noise = 0; - set_quality(pAdapter, &iwe.u.qual, pAdapter->ScanTab.BssEntry[i].Rssi); - current_ev = IWE_STREAM_ADD_EVENT(info, current_ev, end_buf, &iwe, IW_EV_QUAL_LEN); - if (current_ev == previous_ev) -#if WIRELESS_EXT >= 17 - return -E2BIG; -#else - break; -#endif - - //Encyption key - //================================ - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWENCODE; - if (CAP_IS_PRIVACY_ON (pAdapter->ScanTab.BssEntry[i].CapabilityInfo )) - iwe.u.data.flags =IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; - else - iwe.u.data.flags = IW_ENCODE_DISABLED; - - previous_ev = current_ev; - current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf,&iwe, (char *)pAdapter->SharedKey[BSS0][(iwe.u.data.flags & IW_ENCODE_INDEX)-1].Key); - if (current_ev == previous_ev) -#if WIRELESS_EXT >= 17 - return -E2BIG; -#else - break; -#endif - - //Bit Rate - //================================ - if (pAdapter->ScanTab.BssEntry[i].SupRateLen) - { - UCHAR tmpRate = pAdapter->ScanTab.BssEntry[i].SupRate[pAdapter->ScanTab.BssEntry[i].SupRateLen-1]; - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWRATE; - current_val = current_ev + IW_EV_LCP_LEN; - if (tmpRate == 0x82) - iwe.u.bitrate.value = 1 * 1000000; - else if (tmpRate == 0x84) - iwe.u.bitrate.value = 2 * 1000000; - else if (tmpRate == 0x8B) - iwe.u.bitrate.value = 5.5 * 1000000; - else if (tmpRate == 0x96) - iwe.u.bitrate.value = 11 * 1000000; - else - iwe.u.bitrate.value = (tmpRate/2) * 1000000; - - iwe.u.bitrate.disabled = 0; - current_val = IWE_STREAM_ADD_VALUE(info, current_ev, - current_val, end_buf, &iwe, - IW_EV_PARAM_LEN); - - if((current_val-current_ev)>IW_EV_LCP_LEN) - current_ev = current_val; - else -#if WIRELESS_EXT >= 17 - return -E2BIG; -#else - break; -#endif - } - -#ifdef IWEVGENIE - //WPA IE - if (pAdapter->ScanTab.BssEntry[i].WpaIE.IELen > 0) - { - memset(&iwe, 0, sizeof(iwe)); - memset(&custom[0], 0, MAX_CUSTOM_LEN); - memcpy(custom, &(pAdapter->ScanTab.BssEntry[i].WpaIE.IE[0]), - pAdapter->ScanTab.BssEntry[i].WpaIE.IELen); - iwe.cmd = IWEVGENIE; - iwe.u.data.length = pAdapter->ScanTab.BssEntry[i].WpaIE.IELen; - current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe, custom); - if (current_ev == previous_ev) -#if WIRELESS_EXT >= 17 - return -E2BIG; -#else - break; -#endif - } - - //WPA2 IE - if (pAdapter->ScanTab.BssEntry[i].RsnIE.IELen > 0) - { - memset(&iwe, 0, sizeof(iwe)); - memset(&custom[0], 0, MAX_CUSTOM_LEN); - memcpy(custom, &(pAdapter->ScanTab.BssEntry[i].RsnIE.IE[0]), - pAdapter->ScanTab.BssEntry[i].RsnIE.IELen); - iwe.cmd = IWEVGENIE; - iwe.u.data.length = pAdapter->ScanTab.BssEntry[i].RsnIE.IELen; - current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe, custom); - if (current_ev == previous_ev) -#if WIRELESS_EXT >= 17 - return -E2BIG; -#else - break; -#endif - } -#else - //WPA IE - //================================ - if (pAdapter->ScanTab.BssEntry[i].WpaIE.IELen > 0) - { - NdisZeroMemory(&iwe, sizeof(iwe)); - memset(&custom[0], 0, MAX_CUSTOM_LEN); - iwe.cmd = IWEVCUSTOM; - iwe.u.data.length = (pAdapter->ScanTab.BssEntry[i].WpaIE.IELen * 2) + 7; - NdisMoveMemory(custom, "wpa_ie=", 7); - for (idx = 0; idx < pAdapter->ScanTab.BssEntry[i].WpaIE.IELen; idx++) - sprintf(custom, "%s%02x", custom, pAdapter->ScanTab.BssEntry[i].WpaIE.IE[idx]); - previous_ev = current_ev; - current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe, custom); - if (current_ev == previous_ev) -#if WIRELESS_EXT >= 17 - return -E2BIG; -#else - break; -#endif - } - - //WPA2 IE - if (pAdapter->ScanTab.BssEntry[i].RsnIE.IELen > 0) - { - NdisZeroMemory(&iwe, sizeof(iwe)); - memset(&custom[0], 0, MAX_CUSTOM_LEN); - iwe.cmd = IWEVCUSTOM; - iwe.u.data.length = (pAdapter->ScanTab.BssEntry[i].RsnIE.IELen * 2) + 7; - NdisMoveMemory(custom, "rsn_ie=", 7); - for (idx = 0; idx < pAdapter->ScanTab.BssEntry[i].RsnIE.IELen; idx++) - sprintf(custom, "%s%02x", custom, pAdapter->ScanTab.BssEntry[i].RsnIE.IE[idx]); - previous_ev = current_ev; - current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe, custom); - if (current_ev == previous_ev) -#if WIRELESS_EXT >= 17 - return -E2BIG; -#else - break; -#endif - } -#endif // IWEVGENIE // - } - - data->length = current_ev - extra; - pAdapter->StaCfg.bScanReqIsFromWebUI = FALSE; - DBGPRINT(RT_DEBUG_ERROR ,("===>rt_ioctl_giwscan. %d(%d) BSS returned, data->length = %d\n",i , pAdapter->ScanTab.BssNr, data->length)); - return 0; -} -#endif - -int rt_ioctl_siwessid(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *essid) -{ - PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - if (data->flags) - { - PCHAR pSsidString = NULL; - - // Includes null character. - if (data->length > (IW_ESSID_MAX_SIZE + 1)) - return -E2BIG; - - pSsidString = (CHAR *) kmalloc(MAX_LEN_OF_SSID+1, MEM_ALLOC_FLAG); - if (pSsidString) - { - NdisZeroMemory(pSsidString, MAX_LEN_OF_SSID+1); - NdisMoveMemory(pSsidString, essid, data->length); - if (Set_SSID_Proc(pAdapter, pSsidString) == FALSE) - return -EINVAL; - } - else - return -ENOMEM; - } - else - { - // ANY ssid - if (Set_SSID_Proc(pAdapter, "") == FALSE) - return -EINVAL; - } - return 0; -} - -int rt_ioctl_giwessid(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *essid) -{ - PRTMP_ADAPTER pAdapter = NULL; - VIRTUAL_ADAPTER *pVirtualAd = NULL; - - if (dev->priv_flags == INT_MAIN) - { - pAdapter = dev->priv; - } - else - { - pVirtualAd = dev->priv; - if (pVirtualAd && pVirtualAd->RtmpDev) - pAdapter = pVirtualAd->RtmpDev->priv; - } - - if (pAdapter == NULL) - { - /* if 1st open fail, pAd will be free; - So the net_dev->priv will be NULL in 2rd open */ - return -ENETDOWN; - } - - data->flags = 1; - if (MONITOR_ON(pAdapter)) - { - data->length = 0; - return 0; - } - - if (OPSTATUS_TEST_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED)) - { - DBGPRINT(RT_DEBUG_TRACE ,("MediaState is connected\n")); - data->length = pAdapter->CommonCfg.SsidLen; - memcpy(essid, pAdapter->CommonCfg.Ssid, pAdapter->CommonCfg.SsidLen); - } -#ifdef RT2870 -#ifdef WPA_SUPPLICANT_SUPPORT - // Add for RT2870 - else if (pAdapter->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_DISABLE) - { - data->length = pAdapter->CommonCfg.SsidLen; - memcpy(essid, pAdapter->CommonCfg.Ssid, pAdapter->CommonCfg.SsidLen); - } -#endif // WPA_SUPPLICANT_SUPPORT // -#endif // RT2870 // - else - {//the ANY ssid was specified - data->length = 0; - DBGPRINT(RT_DEBUG_TRACE ,("MediaState is not connected, ess\n")); - } - - return 0; - -} - -int rt_ioctl_siwnickn(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *nickname) -{ - PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE ,("INFO::Network is down!\n")); - return -ENETDOWN; - } - - if (data->length > IW_ESSID_MAX_SIZE) - return -EINVAL; - - memset(pAdapter->nickname, 0, IW_ESSID_MAX_SIZE + 1); - memcpy(pAdapter->nickname, nickname, data->length); - - - return 0; -} - -int rt_ioctl_giwnickn(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *nickname) -{ - PRTMP_ADAPTER pAdapter = NULL; - VIRTUAL_ADAPTER *pVirtualAd = NULL; - - if (dev->priv_flags == INT_MAIN) - { - pAdapter = dev->priv; - } - else - { - pVirtualAd = dev->priv; - if (pVirtualAd && pVirtualAd->RtmpDev) - pAdapter = pVirtualAd->RtmpDev->priv; - } - - if (pAdapter == NULL) - { - /* if 1st open fail, pAd will be free; - So the net_dev->priv will be NULL in 2rd open */ - return -ENETDOWN; - } - - if (data->length > strlen(pAdapter->nickname) + 1) - data->length = strlen(pAdapter->nickname) + 1; - if (data->length > 0) { - memcpy(nickname, pAdapter->nickname, data->length-1); - nickname[data->length-1] = '\0'; - } - return 0; -} - -int rt_ioctl_siwrts(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *rts, char *extra) -{ - PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; - u16 val; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - if (rts->disabled) - val = MAX_RTS_THRESHOLD; - else if (rts->value < 0 || rts->value > MAX_RTS_THRESHOLD) - return -EINVAL; - else if (rts->value == 0) - val = MAX_RTS_THRESHOLD; - else - val = rts->value; - - if (val != pAdapter->CommonCfg.RtsThreshold) - pAdapter->CommonCfg.RtsThreshold = val; - - return 0; -} - -int rt_ioctl_giwrts(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *rts, char *extra) -{ - PRTMP_ADAPTER pAdapter = NULL; - VIRTUAL_ADAPTER *pVirtualAd = NULL; - - if (dev->priv_flags == INT_MAIN) - { - pAdapter = dev->priv; - } - else - { - pVirtualAd = dev->priv; - if (pVirtualAd && pVirtualAd->RtmpDev) - pAdapter = pVirtualAd->RtmpDev->priv; - } - - if (pAdapter == NULL) - { - /* if 1st open fail, pAd will be free; - So the net_dev->priv will be NULL in 2rd open */ - return -ENETDOWN; - } - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - rts->value = pAdapter->CommonCfg.RtsThreshold; - rts->disabled = (rts->value == MAX_RTS_THRESHOLD); - rts->fixed = 1; - - return 0; -} - -int rt_ioctl_siwfrag(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *frag, char *extra) -{ - PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; - u16 val; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - if (frag->disabled) - val = MAX_FRAG_THRESHOLD; - else if (frag->value >= MIN_FRAG_THRESHOLD || frag->value <= MAX_FRAG_THRESHOLD) - val = __cpu_to_le16(frag->value & ~0x1); /* even numbers only */ - else if (frag->value == 0) - val = MAX_FRAG_THRESHOLD; - else - return -EINVAL; - - pAdapter->CommonCfg.FragmentThreshold = val; - return 0; -} - -int rt_ioctl_giwfrag(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *frag, char *extra) -{ - PRTMP_ADAPTER pAdapter = NULL; - VIRTUAL_ADAPTER *pVirtualAd = NULL; - - if (dev->priv_flags == INT_MAIN) - { - pAdapter = dev->priv; - } - else - { - pVirtualAd = dev->priv; - if (pVirtualAd && pVirtualAd->RtmpDev) - pAdapter = pVirtualAd->RtmpDev->priv; - } - - if (pAdapter == NULL) - { - /* if 1st open fail, pAd will be free; - So the net_dev->priv will be NULL in 2rd open */ - return -ENETDOWN; - } - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - frag->value = pAdapter->CommonCfg.FragmentThreshold; - frag->disabled = (frag->value == MAX_FRAG_THRESHOLD); - frag->fixed = 1; - - return 0; -} - -#define MAX_WEP_KEY_SIZE 13 -#define MIN_WEP_KEY_SIZE 5 -int rt_ioctl_siwencode(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *erq, char *extra) -{ - PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - if ((erq->length == 0) && - (erq->flags & IW_ENCODE_DISABLED)) - { - pAdapter->StaCfg.PairCipher = Ndis802_11WEPDisabled; - pAdapter->StaCfg.GroupCipher = Ndis802_11WEPDisabled; - pAdapter->StaCfg.WepStatus = Ndis802_11WEPDisabled; - pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; - goto done; - } - else if ((erq->length == 0) && - (erq->flags & IW_ENCODE_RESTRICTED || erq->flags & IW_ENCODE_OPEN)) - { - //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; - STA_PORT_SECURED(pAdapter); - pAdapter->StaCfg.PairCipher = Ndis802_11WEPEnabled; - pAdapter->StaCfg.GroupCipher = Ndis802_11WEPEnabled; - pAdapter->StaCfg.WepStatus = Ndis802_11WEPEnabled; - pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; - if (erq->flags & IW_ENCODE_RESTRICTED) - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeShared; - else - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; - goto done; - } - - if (erq->length > 0) - { - int keyIdx = (erq->flags & IW_ENCODE_INDEX) - 1; - /* Check the size of the key */ - if (erq->length > MAX_WEP_KEY_SIZE) { - return -EINVAL; - } - /* Check key index */ - if ((keyIdx < 0) || (keyIdx >= NR_WEP_KEYS)) - { - DBGPRINT(RT_DEBUG_TRACE ,("==>rt_ioctl_siwencode::Wrong keyIdx=%d! Using default key instead (%d)\n", - keyIdx, pAdapter->StaCfg.DefaultKeyId)); - - //Using default key - keyIdx = pAdapter->StaCfg.DefaultKeyId; - } - - NdisZeroMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, 16); - - if (erq->length == MAX_WEP_KEY_SIZE) - { - pAdapter->SharedKey[BSS0][keyIdx].KeyLen = MAX_WEP_KEY_SIZE; - pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CIPHER_WEP128; - } - else if (erq->length == MIN_WEP_KEY_SIZE) - { - pAdapter->SharedKey[BSS0][keyIdx].KeyLen = MIN_WEP_KEY_SIZE; - pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CIPHER_WEP64; - } - else - /* Disable the key */ - pAdapter->SharedKey[BSS0][keyIdx].KeyLen = 0; - - /* Check if the key is not marked as invalid */ - if(!(erq->flags & IW_ENCODE_NOKEY)) { - /* Copy the key in the driver */ - NdisMoveMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, extra, erq->length); - } - } - else - { - /* Do we want to just set the transmit key index ? */ - int index = (erq->flags & IW_ENCODE_INDEX) - 1; - if ((index >= 0) && (index < 4)) - { - pAdapter->StaCfg.DefaultKeyId = index; - } - else - /* Don't complain if only change the mode */ - if(!erq->flags & IW_ENCODE_MODE) { - return -EINVAL; - } - } - -done: - DBGPRINT(RT_DEBUG_TRACE ,("==>rt_ioctl_siwencode::erq->flags=%x\n",erq->flags)); - DBGPRINT(RT_DEBUG_TRACE ,("==>rt_ioctl_siwencode::AuthMode=%x\n",pAdapter->StaCfg.AuthMode)); - DBGPRINT(RT_DEBUG_TRACE ,("==>rt_ioctl_siwencode::DefaultKeyId=%x, KeyLen = %d\n",pAdapter->StaCfg.DefaultKeyId , pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen)); - DBGPRINT(RT_DEBUG_TRACE ,("==>rt_ioctl_siwencode::WepStatus=%x\n",pAdapter->StaCfg.WepStatus)); - return 0; -} - -int -rt_ioctl_giwencode(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *erq, char *key) -{ - int kid; - PRTMP_ADAPTER pAdapter = NULL; - VIRTUAL_ADAPTER *pVirtualAd = NULL; - - if (dev->priv_flags == INT_MAIN) - { - pAdapter = dev->priv; - } - else - { - pVirtualAd = dev->priv; - if (pVirtualAd && pVirtualAd->RtmpDev) - pAdapter = pVirtualAd->RtmpDev->priv; - } - - if (pAdapter == NULL) - { - /* if 1st open fail, pAd will be free; - So the net_dev->priv will be NULL in 2rd open */ - return -ENETDOWN; - } - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - kid = erq->flags & IW_ENCODE_INDEX; - DBGPRINT(RT_DEBUG_TRACE, ("===>rt_ioctl_giwencode %d\n", erq->flags & IW_ENCODE_INDEX)); - - if (pAdapter->StaCfg.WepStatus == Ndis802_11WEPDisabled) - { - erq->length = 0; - erq->flags = IW_ENCODE_DISABLED; - } - else if ((kid > 0) && (kid <=4)) - { - // copy wep key - erq->flags = kid ; /* NB: base 1 */ - if (erq->length > pAdapter->SharedKey[BSS0][kid-1].KeyLen) - erq->length = pAdapter->SharedKey[BSS0][kid-1].KeyLen; - memcpy(key, pAdapter->SharedKey[BSS0][kid-1].Key, erq->length); - //if ((kid == pAdapter->PortCfg.DefaultKeyId)) - //erq->flags |= IW_ENCODE_ENABLED; /* XXX */ - if (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeShared) - erq->flags |= IW_ENCODE_RESTRICTED; /* XXX */ - else - erq->flags |= IW_ENCODE_OPEN; /* XXX */ - - } - else if (kid == 0) - { - if (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeShared) - erq->flags |= IW_ENCODE_RESTRICTED; /* XXX */ - else - erq->flags |= IW_ENCODE_OPEN; /* XXX */ - erq->length = pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen; - memcpy(key, pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].Key, erq->length); - // copy default key ID - if (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeShared) - erq->flags |= IW_ENCODE_RESTRICTED; /* XXX */ - else - erq->flags |= IW_ENCODE_OPEN; /* XXX */ - erq->flags = pAdapter->StaCfg.DefaultKeyId + 1; /* NB: base 1 */ - erq->flags |= IW_ENCODE_ENABLED; /* XXX */ - } - - return 0; - -} - -static int -rt_ioctl_setparam(struct net_device *dev, struct iw_request_info *info, - void *w, char *extra) -{ - VIRTUAL_ADAPTER *pVirtualAd = NULL; - PRTMP_ADAPTER pAdapter; - POS_COOKIE pObj; - char *this_char = extra; - char *value; - int Status=0; - - if (dev->priv_flags == INT_MAIN) - { - pAdapter = dev->priv; - } - else - { - pVirtualAd = dev->priv; - pAdapter = pVirtualAd->RtmpDev->priv; - } - pObj = (POS_COOKIE) pAdapter->OS_Cookie; - - if (pAdapter == NULL) - { - /* if 1st open fail, pAd will be free; - So the net_dev->priv will be NULL in 2rd open */ - return -ENETDOWN; - } - - { - pObj->ioctl_if_type = INT_MAIN; - pObj->ioctl_if = MAIN_MBSSID; - } - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - if (!*this_char) - return -EINVAL; - - if ((value = rtstrchr(this_char, '=')) != NULL) - *value++ = 0; - - if (!value) - return -EINVAL; - - // reject setting nothing besides ANY ssid(ssidLen=0) - if (!*value && (strcmp(this_char, "SSID") != 0)) - return -EINVAL; - - for (PRTMP_PRIVATE_SET_PROC = RTMP_PRIVATE_SUPPORT_PROC; PRTMP_PRIVATE_SET_PROC->name; PRTMP_PRIVATE_SET_PROC++) - { - if (strcmp(this_char, PRTMP_PRIVATE_SET_PROC->name) == 0) - { - if(!PRTMP_PRIVATE_SET_PROC->set_proc(pAdapter, value)) - { //FALSE:Set private failed then return Invalid argument - Status = -EINVAL; - } - break; //Exit for loop. - } - } - - if(PRTMP_PRIVATE_SET_PROC->name == NULL) - { //Not found argument - Status = -EINVAL; - DBGPRINT(RT_DEBUG_TRACE, ("===>rt_ioctl_setparam:: (iwpriv) Not Support Set Command [%s=%s]\n", this_char, value)); - } - - return Status; -} - - -static int -rt_private_get_statistics(struct net_device *dev, struct iw_request_info *info, - struct iw_point *wrq, char *extra) -{ - INT Status = 0; - PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; - - if (extra == NULL) - { - wrq->length = 0; - return -EIO; - } - - memset(extra, 0x00, IW_PRIV_SIZE_MASK); - sprintf(extra, "\n\n"); - -#ifdef RALINK_ATE - if (ATE_ON(pAd)) - { - sprintf(extra+strlen(extra), "Tx success = %ld\n", (ULONG)pAd->ate.TxDoneCount); - //sprintf(extra+strlen(extra), "Tx success without retry = %ld\n", (ULONG)pAd->ate.TxDoneCount); - } - else -#endif // RALINK_ATE // - { - sprintf(extra+strlen(extra), "Tx success = %ld\n", (ULONG)pAd->WlanCounters.TransmittedFragmentCount.QuadPart); - sprintf(extra+strlen(extra), "Tx success without retry = %ld\n", (ULONG)pAd->WlanCounters.TransmittedFragmentCount.QuadPart - (ULONG)pAd->WlanCounters.RetryCount.QuadPart); - } - sprintf(extra+strlen(extra), "Tx success after retry = %ld\n", (ULONG)pAd->WlanCounters.RetryCount.QuadPart); - sprintf(extra+strlen(extra), "Tx fail to Rcv ACK after retry = %ld\n", (ULONG)pAd->WlanCounters.FailedCount.QuadPart); - sprintf(extra+strlen(extra), "RTS Success Rcv CTS = %ld\n", (ULONG)pAd->WlanCounters.RTSSuccessCount.QuadPart); - sprintf(extra+strlen(extra), "RTS Fail Rcv CTS = %ld\n", (ULONG)pAd->WlanCounters.RTSFailureCount.QuadPart); - - sprintf(extra+strlen(extra), "Rx success = %ld\n", (ULONG)pAd->WlanCounters.ReceivedFragmentCount.QuadPart); - sprintf(extra+strlen(extra), "Rx with CRC = %ld\n", (ULONG)pAd->WlanCounters.FCSErrorCount.QuadPart); - sprintf(extra+strlen(extra), "Rx drop due to out of resource = %ld\n", (ULONG)pAd->Counters8023.RxNoBuffer); - sprintf(extra+strlen(extra), "Rx duplicate frame = %ld\n", (ULONG)pAd->WlanCounters.FrameDuplicateCount.QuadPart); - - sprintf(extra+strlen(extra), "False CCA (one second) = %ld\n", (ULONG)pAd->RalinkCounters.OneSecFalseCCACnt); -#ifdef RALINK_ATE - if (ATE_ON(pAd)) - { - if (pAd->ate.RxAntennaSel == 0) - { - sprintf(extra+strlen(extra), "RSSI-A = %ld\n", (LONG)(pAd->ate.LastRssi0 - pAd->BbpRssiToDbmDelta)); - sprintf(extra+strlen(extra), "RSSI-B (if available) = %ld\n", (LONG)(pAd->ate.LastRssi1 - pAd->BbpRssiToDbmDelta)); - sprintf(extra+strlen(extra), "RSSI-C (if available) = %ld\n\n", (LONG)(pAd->ate.LastRssi2 - pAd->BbpRssiToDbmDelta)); - } - else - { - sprintf(extra+strlen(extra), "RSSI = %ld\n", (LONG)(pAd->ate.LastRssi0 - pAd->BbpRssiToDbmDelta)); - } - } - else -#endif // RALINK_ATE // - { - sprintf(extra+strlen(extra), "RSSI-A = %ld\n", (LONG)(pAd->StaCfg.RssiSample.LastRssi0 - pAd->BbpRssiToDbmDelta)); - sprintf(extra+strlen(extra), "RSSI-B (if available) = %ld\n", (LONG)(pAd->StaCfg.RssiSample.LastRssi1 - pAd->BbpRssiToDbmDelta)); - sprintf(extra+strlen(extra), "RSSI-C (if available) = %ld\n\n", (LONG)(pAd->StaCfg.RssiSample.LastRssi2 - pAd->BbpRssiToDbmDelta)); - } -#ifdef WPA_SUPPLICANT_SUPPORT - sprintf(extra+strlen(extra), "WpaSupplicantUP = %d\n\n", pAd->StaCfg.WpaSupplicantUP); -#endif // WPA_SUPPLICANT_SUPPORT // - - - wrq->length = strlen(extra) + 1; // 1: size of '\0' - DBGPRINT(RT_DEBUG_TRACE, ("<== rt_private_get_statistics, wrq->length = %d\n", wrq->length)); - - return Status; -} - -#ifdef DOT11_N_SUPPORT -void getBaInfo( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pOutBuf) -{ - INT i, j; - BA_ORI_ENTRY *pOriBAEntry; - BA_REC_ENTRY *pRecBAEntry; - - for (i=0; iMacTab.Content[i]; - if (((pEntry->ValidAsCLI || pEntry->ValidAsApCli) && (pEntry->Sst == SST_ASSOC)) - || (pEntry->ValidAsWDS) || (pEntry->ValidAsMesh)) - { - sprintf(pOutBuf, "%s\n%02X:%02X:%02X:%02X:%02X:%02X (Aid = %d) (AP) -\n", - pOutBuf, - pEntry->Addr[0], pEntry->Addr[1], pEntry->Addr[2], - pEntry->Addr[3], pEntry->Addr[4], pEntry->Addr[5], pEntry->Aid); - - sprintf(pOutBuf, "%s[Recipient]\n", pOutBuf); - for (j=0; j < NUM_OF_TID; j++) - { - if (pEntry->BARecWcidArray[j] != 0) - { - pRecBAEntry =&pAd->BATable.BARecEntry[pEntry->BARecWcidArray[j]]; - sprintf(pOutBuf, "%sTID=%d, BAWinSize=%d, LastIndSeq=%d, ReorderingPkts=%d\n", pOutBuf, j, pRecBAEntry->BAWinSize, pRecBAEntry->LastIndSeq, pRecBAEntry->list.qlen); - } - } - sprintf(pOutBuf, "%s\n", pOutBuf); - - sprintf(pOutBuf, "%s[Originator]\n", pOutBuf); - for (j=0; j < NUM_OF_TID; j++) - { - if (pEntry->BAOriWcidArray[j] != 0) - { - pOriBAEntry =&pAd->BATable.BAOriEntry[pEntry->BAOriWcidArray[j]]; - sprintf(pOutBuf, "%sTID=%d, BAWinSize=%d, StartSeq=%d, CurTxSeq=%d\n", pOutBuf, j, pOriBAEntry->BAWinSize, pOriBAEntry->Sequence, pEntry->TxSeq[j]); - } - } - sprintf(pOutBuf, "%s\n\n", pOutBuf); - } - if (strlen(pOutBuf) > (IW_PRIV_SIZE_MASK - 30)) - break; - } - - return; -} -#endif // DOT11_N_SUPPORT // - -static int -rt_private_show(struct net_device *dev, struct iw_request_info *info, - struct iw_point *wrq, char *extra) -{ - INT Status = 0; - VIRTUAL_ADAPTER *pVirtualAd = NULL; - PRTMP_ADAPTER pAd; - POS_COOKIE pObj; - u32 subcmd = wrq->flags; - - if (dev->priv_flags == INT_MAIN) - pAd = dev->priv; - else - { - pVirtualAd = dev->priv; - pAd = pVirtualAd->RtmpDev->priv; - } - pObj = (POS_COOKIE) pAd->OS_Cookie; - - if (pAd == NULL) - { - /* if 1st open fail, pAd will be free; - So the net_dev->priv will be NULL in 2rd open */ - return -ENETDOWN; - } - - if (extra == NULL) - { - wrq->length = 0; - return -EIO; - } - memset(extra, 0x00, IW_PRIV_SIZE_MASK); - - { - pObj->ioctl_if_type = INT_MAIN; - pObj->ioctl_if = MAIN_MBSSID; - } - - switch(subcmd) - { - - case SHOW_CONN_STATUS: - if (MONITOR_ON(pAd)) - { -#ifdef DOT11_N_SUPPORT - if (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED && - pAd->CommonCfg.RegTransmitSetting.field.BW) - sprintf(extra, "Monitor Mode(CentralChannel %d)\n", pAd->CommonCfg.CentralChannel); - else -#endif // DOT11_N_SUPPORT // - sprintf(extra, "Monitor Mode(Channel %d)\n", pAd->CommonCfg.Channel); - } - else - { - if (pAd->IndicateMediaState == NdisMediaStateConnected) - { - if (INFRA_ON(pAd)) - { - sprintf(extra, "Connected(AP: %s[%02X:%02X:%02X:%02X:%02X:%02X])\n", - pAd->CommonCfg.Ssid, - pAd->CommonCfg.Bssid[0], - pAd->CommonCfg.Bssid[1], - pAd->CommonCfg.Bssid[2], - pAd->CommonCfg.Bssid[3], - pAd->CommonCfg.Bssid[4], - pAd->CommonCfg.Bssid[5]); - DBGPRINT(RT_DEBUG_TRACE ,("Ssid=%s ,Ssidlen = %d\n",pAd->CommonCfg.Ssid, pAd->CommonCfg.SsidLen)); - } - else if (ADHOC_ON(pAd)) - sprintf(extra, "Connected\n"); - } - else - { - sprintf(extra, "Disconnected\n"); - DBGPRINT(RT_DEBUG_TRACE ,("ConnStatus is not connected\n")); - } - } - wrq->length = strlen(extra) + 1; // 1: size of '\0' - break; - case SHOW_DRVIER_VERION: - sprintf(extra, "Driver version-%s, %s %s\n", STA_DRIVER_VERSION, __DATE__, __TIME__ ); - wrq->length = strlen(extra) + 1; // 1: size of '\0' - break; -#ifdef DOT11_N_SUPPORT - case SHOW_BA_INFO: - getBaInfo(pAd, extra); - wrq->length = strlen(extra) + 1; // 1: size of '\0' - break; -#endif // DOT11_N_SUPPORT // - case SHOW_DESC_INFO: - { - Show_DescInfo_Proc(pAd, NULL); - wrq->length = 0; // 1: size of '\0' - } - break; - case RAIO_OFF: - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) - { - sprintf(extra, "Scanning\n"); - wrq->length = strlen(extra) + 1; // 1: size of '\0' - break; - } - pAd->StaCfg.bSwRadio = FALSE; - if (pAd->StaCfg.bRadio != (pAd->StaCfg.bHwRadio && pAd->StaCfg.bSwRadio)) - { - pAd->StaCfg.bRadio = (pAd->StaCfg.bHwRadio && pAd->StaCfg.bSwRadio); - if (pAd->StaCfg.bRadio == FALSE) - { - MlmeRadioOff(pAd); - // Update extra information - pAd->ExtraInfo = SW_RADIO_OFF; - } - } - sprintf(extra, "Radio Off\n"); - wrq->length = strlen(extra) + 1; // 1: size of '\0' - break; - case RAIO_ON: - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) - { - sprintf(extra, "Scanning\n"); - wrq->length = strlen(extra) + 1; // 1: size of '\0' - break; - } - pAd->StaCfg.bSwRadio = TRUE; - //if (pAd->StaCfg.bRadio != (pAd->StaCfg.bHwRadio && pAd->StaCfg.bSwRadio)) - { - pAd->StaCfg.bRadio = (pAd->StaCfg.bHwRadio && pAd->StaCfg.bSwRadio); - if (pAd->StaCfg.bRadio == TRUE) - { - MlmeRadioOn(pAd); - // Update extra information - pAd->ExtraInfo = EXTRA_INFO_CLEAR; - } - } - sprintf(extra, "Radio On\n"); - wrq->length = strlen(extra) + 1; // 1: size of '\0' - break; - - -#ifdef QOS_DLS_SUPPORT - case SHOW_DLS_ENTRY_INFO: - { - Set_DlsEntryInfo_Display_Proc(pAd, NULL); - wrq->length = 0; // 1: size of '\0' - } - break; -#endif // QOS_DLS_SUPPORT // - - case SHOW_CFG_VALUE: - { - Status = RTMPShowCfgValue(pAd, wrq->pointer, extra); - if (Status == 0) - wrq->length = strlen(extra) + 1; // 1: size of '\0' - } - break; - case SHOW_ADHOC_ENTRY_INFO: - Show_Adhoc_MacTable_Proc(pAd, extra); - wrq->length = strlen(extra) + 1; // 1: size of '\0' - break; - default: - DBGPRINT(RT_DEBUG_TRACE, ("%s - unknow subcmd = %d\n", __func__, subcmd)); - break; - } - - return Status; -} - -#ifdef SIOCSIWMLME -int rt_ioctl_siwmlme(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; - struct iw_mlme *pMlme = (struct iw_mlme *)wrqu->data.pointer; - MLME_QUEUE_ELEM MsgElem; - MLME_DISASSOC_REQ_STRUCT DisAssocReq; - MLME_DEAUTH_REQ_STRUCT DeAuthReq; - - DBGPRINT(RT_DEBUG_TRACE, ("====> %s\n", __func__)); - - if (pMlme == NULL) - return -EINVAL; - - switch(pMlme->cmd) - { -#ifdef IW_MLME_DEAUTH - case IW_MLME_DEAUTH: - DBGPRINT(RT_DEBUG_TRACE, ("====> %s - IW_MLME_DEAUTH\n", __func__)); - COPY_MAC_ADDR(DeAuthReq.Addr, pAd->CommonCfg.Bssid); - DeAuthReq.Reason = pMlme->reason_code; - MsgElem.MsgLen = sizeof(MLME_DEAUTH_REQ_STRUCT); - NdisMoveMemory(MsgElem.Msg, &DeAuthReq, sizeof(MLME_DEAUTH_REQ_STRUCT)); - MlmeDeauthReqAction(pAd, &MsgElem); - if (INFRA_ON(pAd)) - { - LinkDown(pAd, FALSE); - pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; - } - break; -#endif // IW_MLME_DEAUTH // -#ifdef IW_MLME_DISASSOC - case IW_MLME_DISASSOC: - DBGPRINT(RT_DEBUG_TRACE, ("====> %s - IW_MLME_DISASSOC\n", __func__)); - COPY_MAC_ADDR(DisAssocReq.Addr, pAd->CommonCfg.Bssid); - DisAssocReq.Reason = pMlme->reason_code; - - MsgElem.Machine = ASSOC_STATE_MACHINE; - MsgElem.MsgType = MT2_MLME_DISASSOC_REQ; - MsgElem.MsgLen = sizeof(MLME_DISASSOC_REQ_STRUCT); - NdisMoveMemory(MsgElem.Msg, &DisAssocReq, sizeof(MLME_DISASSOC_REQ_STRUCT)); - - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_DISASSOC; - MlmeDisassocReqAction(pAd, &MsgElem); - break; -#endif // IW_MLME_DISASSOC // - default: - DBGPRINT(RT_DEBUG_TRACE, ("====> %s - Unknow Command\n", __func__)); - break; - } - - return 0; -} -#endif // SIOCSIWMLME // - -#if WIRELESS_EXT > 17 -int rt_ioctl_siwauth(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; - struct iw_param *param = &wrqu->param; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - switch (param->flags & IW_AUTH_INDEX) { - case IW_AUTH_WPA_VERSION: - if (param->value == IW_AUTH_WPA_VERSION_WPA) - { - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPAPSK; - if (pAdapter->StaCfg.BssType == BSS_ADHOC) - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPANone; - } - else if (param->value == IW_AUTH_WPA_VERSION_WPA2) - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA2PSK; - - DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_VERSION - param->value = %d!\n", __func__, param->value)); - break; - case IW_AUTH_CIPHER_PAIRWISE: - if (param->value == IW_AUTH_CIPHER_NONE) - { - pAdapter->StaCfg.WepStatus = Ndis802_11WEPDisabled; - pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; - pAdapter->StaCfg.PairCipher = Ndis802_11WEPDisabled; - } - else if (param->value == IW_AUTH_CIPHER_WEP40 || - param->value == IW_AUTH_CIPHER_WEP104) - { - pAdapter->StaCfg.WepStatus = Ndis802_11WEPEnabled; - pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; - pAdapter->StaCfg.PairCipher = Ndis802_11WEPEnabled; -#ifdef WPA_SUPPLICANT_SUPPORT - pAdapter->StaCfg.IEEE8021X = FALSE; -#endif // WPA_SUPPLICANT_SUPPORT // - } - else if (param->value == IW_AUTH_CIPHER_TKIP) - { - pAdapter->StaCfg.WepStatus = Ndis802_11Encryption2Enabled; - pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; - pAdapter->StaCfg.PairCipher = Ndis802_11Encryption2Enabled; - } - else if (param->value == IW_AUTH_CIPHER_CCMP) - { - pAdapter->StaCfg.WepStatus = Ndis802_11Encryption3Enabled; - pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; - pAdapter->StaCfg.PairCipher = Ndis802_11Encryption3Enabled; - } - DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_CIPHER_PAIRWISE - param->value = %d!\n", __func__, param->value)); - break; - case IW_AUTH_CIPHER_GROUP: - if (param->value == IW_AUTH_CIPHER_NONE) - { - pAdapter->StaCfg.GroupCipher = Ndis802_11WEPDisabled; - } - else if (param->value == IW_AUTH_CIPHER_WEP40 || - param->value == IW_AUTH_CIPHER_WEP104) - { - pAdapter->StaCfg.GroupCipher = Ndis802_11WEPEnabled; - } - else if (param->value == IW_AUTH_CIPHER_TKIP) - { - pAdapter->StaCfg.GroupCipher = Ndis802_11Encryption2Enabled; - } - else if (param->value == IW_AUTH_CIPHER_CCMP) - { - pAdapter->StaCfg.GroupCipher = Ndis802_11Encryption3Enabled; - } - DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_CIPHER_GROUP - param->value = %d!\n", __func__, param->value)); - break; - case IW_AUTH_KEY_MGMT: - if (param->value == IW_AUTH_KEY_MGMT_802_1X) - { - if (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) - { - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA; -#ifdef WPA_SUPPLICANT_SUPPORT - pAdapter->StaCfg.IEEE8021X = FALSE; -#endif // WPA_SUPPLICANT_SUPPORT // - } - else if (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) - { - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA2; -#ifdef WPA_SUPPLICANT_SUPPORT - pAdapter->StaCfg.IEEE8021X = FALSE; -#endif // WPA_SUPPLICANT_SUPPORT // - } -#ifdef WPA_SUPPLICANT_SUPPORT - else - // WEP 1x - pAdapter->StaCfg.IEEE8021X = TRUE; -#endif // WPA_SUPPLICANT_SUPPORT // - } - else if (param->value == 0) - { - //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; - STA_PORT_SECURED(pAdapter); - } - DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_KEY_MGMT - param->value = %d!\n", __func__, param->value)); - break; - case IW_AUTH_RX_UNENCRYPTED_EAPOL: - break; - case IW_AUTH_PRIVACY_INVOKED: - /*if (param->value == 0) - { - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; - pAdapter->StaCfg.WepStatus = Ndis802_11WEPDisabled; - pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; - pAdapter->StaCfg.PairCipher = Ndis802_11WEPDisabled; - pAdapter->StaCfg.GroupCipher = Ndis802_11WEPDisabled; - }*/ - DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_PRIVACY_INVOKED - param->value = %d!\n", __func__, param->value)); - break; - case IW_AUTH_DROP_UNENCRYPTED: - if (param->value != 0) - pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; - else - { - //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; - STA_PORT_SECURED(pAdapter); - } - DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_VERSION - param->value = %d!\n", __func__, param->value)); - break; - case IW_AUTH_80211_AUTH_ALG: - if (param->value & IW_AUTH_ALG_SHARED_KEY) - { - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeShared; - } - else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) - { - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; - } - else - return -EINVAL; - DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_80211_AUTH_ALG - param->value = %d!\n", __func__, param->value)); - break; - case IW_AUTH_WPA_ENABLED: - DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_ENABLED - Driver supports WPA!(param->value = %d)\n", __func__, param->value)); - break; - default: - return -EOPNOTSUPP; -} - - return 0; -} - -int rt_ioctl_giwauth(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; - struct iw_param *param = &wrqu->param; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - switch (param->flags & IW_AUTH_INDEX) { - case IW_AUTH_DROP_UNENCRYPTED: - param->value = (pAdapter->StaCfg.WepStatus == Ndis802_11WEPDisabled) ? 0 : 1; - break; - - case IW_AUTH_80211_AUTH_ALG: - param->value = (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeShared) ? IW_AUTH_ALG_SHARED_KEY : IW_AUTH_ALG_OPEN_SYSTEM; - break; - - case IW_AUTH_WPA_ENABLED: - param->value = (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ? 1 : 0; - break; - - default: - return -EOPNOTSUPP; - } - DBGPRINT(RT_DEBUG_TRACE, ("rt_ioctl_giwauth::param->value = %d!\n", param->value)); - return 0; -} - -void fnSetCipherKey( - IN PRTMP_ADAPTER pAdapter, - IN INT keyIdx, - IN UCHAR CipherAlg, - IN BOOLEAN bGTK, - IN struct iw_encode_ext *ext) -{ - NdisZeroMemory(&pAdapter->SharedKey[BSS0][keyIdx], sizeof(CIPHER_KEY)); - pAdapter->SharedKey[BSS0][keyIdx].KeyLen = LEN_TKIP_EK; - NdisMoveMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, ext->key, LEN_TKIP_EK); - NdisMoveMemory(pAdapter->SharedKey[BSS0][keyIdx].TxMic, ext->key + LEN_TKIP_EK, LEN_TKIP_TXMICK); - NdisMoveMemory(pAdapter->SharedKey[BSS0][keyIdx].RxMic, ext->key + LEN_TKIP_EK + LEN_TKIP_TXMICK, LEN_TKIP_RXMICK); - pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CipherAlg; - - // Update group key information to ASIC Shared Key Table - AsicAddSharedKeyEntry(pAdapter, - BSS0, - keyIdx, - pAdapter->SharedKey[BSS0][keyIdx].CipherAlg, - pAdapter->SharedKey[BSS0][keyIdx].Key, - pAdapter->SharedKey[BSS0][keyIdx].TxMic, - pAdapter->SharedKey[BSS0][keyIdx].RxMic); - - if (bGTK) - // Update ASIC WCID attribute table and IVEIV table - RTMPAddWcidAttributeEntry(pAdapter, - BSS0, - keyIdx, - pAdapter->SharedKey[BSS0][keyIdx].CipherAlg, - NULL); - else - // Update ASIC WCID attribute table and IVEIV table - RTMPAddWcidAttributeEntry(pAdapter, - BSS0, - keyIdx, - pAdapter->SharedKey[BSS0][keyIdx].CipherAlg, - &pAdapter->MacTab.Content[BSSID_WCID]); -} - -int rt_ioctl_siwencodeext(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) - { - PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; - struct iw_point *encoding = &wrqu->encoding; - struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; - int keyIdx, alg = ext->alg; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - if (encoding->flags & IW_ENCODE_DISABLED) - { - keyIdx = (encoding->flags & IW_ENCODE_INDEX) - 1; - // set BSSID wcid entry of the Pair-wise Key table as no-security mode - AsicRemovePairwiseKeyEntry(pAdapter, BSS0, BSSID_WCID); - pAdapter->SharedKey[BSS0][keyIdx].KeyLen = 0; - pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CIPHER_NONE; - AsicRemoveSharedKeyEntry(pAdapter, 0, (UCHAR)keyIdx); - NdisZeroMemory(&pAdapter->SharedKey[BSS0][keyIdx], sizeof(CIPHER_KEY)); - DBGPRINT(RT_DEBUG_TRACE, ("%s::Remove all keys!(encoding->flags = %x)\n", __func__, encoding->flags)); - } - else - { - // Get Key Index and convet to our own defined key index - keyIdx = (encoding->flags & IW_ENCODE_INDEX) - 1; - if((keyIdx < 0) || (keyIdx >= NR_WEP_KEYS)) - return -EINVAL; - - if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) - { - pAdapter->StaCfg.DefaultKeyId = keyIdx; - DBGPRINT(RT_DEBUG_TRACE, ("%s::DefaultKeyId = %d\n", __func__, pAdapter->StaCfg.DefaultKeyId)); - } - - switch (alg) { - case IW_ENCODE_ALG_NONE: - DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_NONE\n", __func__)); - break; - case IW_ENCODE_ALG_WEP: - DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_WEP - ext->key_len = %d, keyIdx = %d\n", __func__, ext->key_len, keyIdx)); - if (ext->key_len == MAX_WEP_KEY_SIZE) - { - pAdapter->SharedKey[BSS0][keyIdx].KeyLen = MAX_WEP_KEY_SIZE; - pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CIPHER_WEP128; - } - else if (ext->key_len == MIN_WEP_KEY_SIZE) - { - pAdapter->SharedKey[BSS0][keyIdx].KeyLen = MIN_WEP_KEY_SIZE; - pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CIPHER_WEP64; - } - else - return -EINVAL; - - NdisZeroMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, 16); - NdisMoveMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, ext->key, ext->key_len); - break; - case IW_ENCODE_ALG_TKIP: - DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_TKIP - keyIdx = %d, ext->key_len = %d\n", __func__, keyIdx, ext->key_len)); - if (ext->key_len == 32) - { - if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) - { - fnSetCipherKey(pAdapter, keyIdx, CIPHER_TKIP, FALSE, ext); - if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA2) - { - //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; - STA_PORT_SECURED(pAdapter); - } - } - else if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) - { - fnSetCipherKey(pAdapter, keyIdx, CIPHER_TKIP, TRUE, ext); - - // set 802.1x port control - //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; - STA_PORT_SECURED(pAdapter); - } - } - else - return -EINVAL; - break; - case IW_ENCODE_ALG_CCMP: - if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) - { - fnSetCipherKey(pAdapter, keyIdx, CIPHER_AES, FALSE, ext); - if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA2) - //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; - STA_PORT_SECURED(pAdapter); - } - else if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) - { - fnSetCipherKey(pAdapter, keyIdx, CIPHER_AES, TRUE, ext); - - // set 802.1x port control - //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; - STA_PORT_SECURED(pAdapter); - } - break; - default: - return -EINVAL; - } - } - - return 0; -} - -int -rt_ioctl_giwencodeext(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; - PCHAR pKey = NULL; - struct iw_point *encoding = &wrqu->encoding; - struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; - int idx, max_key_len; - - DBGPRINT(RT_DEBUG_TRACE ,("===> rt_ioctl_giwencodeext\n")); - - max_key_len = encoding->length - sizeof(*ext); - if (max_key_len < 0) - return -EINVAL; - - idx = encoding->flags & IW_ENCODE_INDEX; - if (idx) - { - if (idx < 1 || idx > 4) - return -EINVAL; - idx--; - - if ((pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) || - (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled)) - { - if (idx != pAd->StaCfg.DefaultKeyId) - { - ext->key_len = 0; - return 0; - } - } - } - else - idx = pAd->StaCfg.DefaultKeyId; - - encoding->flags = idx + 1; - memset(ext, 0, sizeof(*ext)); - - ext->key_len = 0; - switch(pAd->StaCfg.WepStatus) { - case Ndis802_11WEPDisabled: - ext->alg = IW_ENCODE_ALG_NONE; - encoding->flags |= IW_ENCODE_DISABLED; - break; - case Ndis802_11WEPEnabled: - ext->alg = IW_ENCODE_ALG_WEP; - if (pAd->SharedKey[BSS0][idx].KeyLen > max_key_len) - return -E2BIG; - else - { - ext->key_len = pAd->SharedKey[BSS0][idx].KeyLen; - pKey = &(pAd->SharedKey[BSS0][idx].Key[0]); - } - break; - case Ndis802_11Encryption2Enabled: - case Ndis802_11Encryption3Enabled: - if (pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) - ext->alg = IW_ENCODE_ALG_TKIP; - else - ext->alg = IW_ENCODE_ALG_CCMP; - - if (max_key_len < 32) - return -E2BIG; - else - { - ext->key_len = 32; - pKey = &pAd->StaCfg.PMK[0]; - } - break; - default: - return -EINVAL; - } - - if (ext->key_len && pKey) - { - encoding->flags |= IW_ENCODE_ENABLED; - memcpy(ext->key, pKey, ext->key_len); - } - - return 0; -} - -#ifdef SIOCSIWGENIE -int rt_ioctl_siwgenie(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; - - if (wrqu->data.length > MAX_LEN_OF_RSNIE || - (wrqu->data.length && extra == NULL)) - return -EINVAL; - - if (wrqu->data.length) - { - pAd->StaCfg.RSNIE_Len = wrqu->data.length; - NdisMoveMemory(&pAd->StaCfg.RSN_IE[0], extra, pAd->StaCfg.RSNIE_Len); - } - else - { - pAd->StaCfg.RSNIE_Len = 0; - NdisZeroMemory(&pAd->StaCfg.RSN_IE[0], MAX_LEN_OF_RSNIE); - } - - return 0; -} -#endif // SIOCSIWGENIE // - -int rt_ioctl_giwgenie(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; - - if ((pAd->StaCfg.RSNIE_Len == 0) || - (pAd->StaCfg.AuthMode < Ndis802_11AuthModeWPA)) - { - wrqu->data.length = 0; - return 0; - } - -#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT -#ifdef SIOCSIWGENIE - if (pAd->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_ENABLE) - { - if (wrqu->data.length < pAd->StaCfg.RSNIE_Len) - return -E2BIG; - - wrqu->data.length = pAd->StaCfg.RSNIE_Len; - memcpy(extra, &pAd->StaCfg.RSN_IE[0], pAd->StaCfg.RSNIE_Len); - } - else -#endif // SIOCSIWGENIE // -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // - { - UCHAR RSNIe = IE_WPA; - - if (wrqu->data.length < (pAd->StaCfg.RSNIE_Len + 2)) // ID, Len - return -E2BIG; - wrqu->data.length = pAd->StaCfg.RSNIE_Len + 2; - - if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) || - (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2)) - RSNIe = IE_RSN; - - extra[0] = (char)RSNIe; - extra[1] = pAd->StaCfg.RSNIE_Len; - memcpy(extra+2, &pAd->StaCfg.RSN_IE[0], pAd->StaCfg.RSNIE_Len); - } - - return 0; -} - -int rt_ioctl_siwpmksa(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; - struct iw_pmksa *pPmksa = (struct iw_pmksa *)wrqu->data.pointer; - INT CachedIdx = 0, idx = 0; - - if (pPmksa == NULL) - return -EINVAL; - - DBGPRINT(RT_DEBUG_TRACE ,("===> rt_ioctl_siwpmksa\n")); - switch(pPmksa->cmd) - { - case IW_PMKSA_FLUSH: - NdisZeroMemory(pAd->StaCfg.SavedPMK, sizeof(BSSID_INFO)*PMKID_NO); - DBGPRINT(RT_DEBUG_TRACE ,("rt_ioctl_siwpmksa - IW_PMKSA_FLUSH\n")); - break; - case IW_PMKSA_REMOVE: - for (CachedIdx = 0; CachedIdx < pAd->StaCfg.SavedPMKNum; CachedIdx++) - { - // compare the BSSID - if (NdisEqualMemory(pPmksa->bssid.sa_data, pAd->StaCfg.SavedPMK[CachedIdx].BSSID, MAC_ADDR_LEN)) - { - NdisZeroMemory(pAd->StaCfg.SavedPMK[CachedIdx].BSSID, MAC_ADDR_LEN); - NdisZeroMemory(pAd->StaCfg.SavedPMK[CachedIdx].PMKID, 16); - for (idx = CachedIdx; idx < (pAd->StaCfg.SavedPMKNum - 1); idx++) - { - NdisMoveMemory(&pAd->StaCfg.SavedPMK[idx].BSSID[0], &pAd->StaCfg.SavedPMK[idx+1].BSSID[0], MAC_ADDR_LEN); - NdisMoveMemory(&pAd->StaCfg.SavedPMK[idx].PMKID[0], &pAd->StaCfg.SavedPMK[idx+1].PMKID[0], 16); - } - pAd->StaCfg.SavedPMKNum--; - break; - } - } - - DBGPRINT(RT_DEBUG_TRACE ,("rt_ioctl_siwpmksa - IW_PMKSA_REMOVE\n")); - break; - case IW_PMKSA_ADD: - for (CachedIdx = 0; CachedIdx < pAd->StaCfg.SavedPMKNum; CachedIdx++) - { - // compare the BSSID - if (NdisEqualMemory(pPmksa->bssid.sa_data, pAd->StaCfg.SavedPMK[CachedIdx].BSSID, MAC_ADDR_LEN)) - break; - } - - // Found, replace it - if (CachedIdx < PMKID_NO) - { - DBGPRINT(RT_DEBUG_OFF, ("Update PMKID, idx = %d\n", CachedIdx)); - NdisMoveMemory(&pAd->StaCfg.SavedPMK[CachedIdx].BSSID[0], pPmksa->bssid.sa_data, MAC_ADDR_LEN); - NdisMoveMemory(&pAd->StaCfg.SavedPMK[CachedIdx].PMKID[0], pPmksa->pmkid, 16); - pAd->StaCfg.SavedPMKNum++; - } - // Not found, replace the last one - else - { - // Randomly replace one - CachedIdx = (pPmksa->bssid.sa_data[5] % PMKID_NO); - DBGPRINT(RT_DEBUG_OFF, ("Update PMKID, idx = %d\n", CachedIdx)); - NdisMoveMemory(&pAd->StaCfg.SavedPMK[CachedIdx].BSSID[0], pPmksa->bssid.sa_data, MAC_ADDR_LEN); - NdisMoveMemory(&pAd->StaCfg.SavedPMK[CachedIdx].PMKID[0], pPmksa->pmkid, 16); - } - - DBGPRINT(RT_DEBUG_TRACE ,("rt_ioctl_siwpmksa - IW_PMKSA_ADD\n")); - break; - default: - DBGPRINT(RT_DEBUG_TRACE ,("rt_ioctl_siwpmksa - Unknow Command!!\n")); - break; - } - - return 0; -} -#endif // #if WIRELESS_EXT > 17 - -#ifdef DBG -static int -rt_private_ioctl_bbp(struct net_device *dev, struct iw_request_info *info, - struct iw_point *wrq, char *extra) - { - CHAR *this_char; - CHAR *value = NULL; - UCHAR regBBP = 0; -// CHAR arg[255]={0}; - UINT32 bbpId; - UINT32 bbpValue; - BOOLEAN bIsPrintAllBBP = FALSE; - INT Status = 0; - PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; - - - memset(extra, 0x00, IW_PRIV_SIZE_MASK); - - if (wrq->length > 1) //No parameters. - { - sprintf(extra, "\n"); - - //Parsing Read or Write - this_char = wrq->pointer; - DBGPRINT(RT_DEBUG_TRACE, ("this_char=%s\n", this_char)); - if (!*this_char) - goto next; - - if ((value = rtstrchr(this_char, '=')) != NULL) - *value++ = 0; - - if (!value || !*value) - { //Read - DBGPRINT(RT_DEBUG_TRACE, ("this_char=%s, value=%s\n", this_char, value)); - if (sscanf(this_char, "%d", &(bbpId)) == 1) - { - if (bbpId <= 136) - { -#ifdef RALINK_ATE - if (ATE_ON(pAdapter)) - { - ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); - } - else -#endif // RALINK_ATE // - { - RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); - } - sprintf(extra+strlen(extra), "R%02d[0x%02X]:%02X\n", bbpId, bbpId*2, regBBP); - wrq->length = strlen(extra) + 1; // 1: size of '\0' - DBGPRINT(RT_DEBUG_TRACE, ("msg=%s\n", extra)); - } - else - {//Invalid parametes, so default printk all bbp - bIsPrintAllBBP = TRUE; - goto next; - } - } - else - { //Invalid parametes, so default printk all bbp - bIsPrintAllBBP = TRUE; - goto next; - } - } - else - { //Write - if ((sscanf(this_char, "%d", &(bbpId)) == 1) && (sscanf(value, "%x", &(bbpValue)) == 1)) - { - if (bbpId <= 136) - { -#ifdef RALINK_ATE - if (ATE_ON(pAdapter)) - { - ATE_BBP_IO_WRITE8_BY_REG_ID(pAdapter, bbpId, bbpValue); - //Read it back for showing - ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); - } - else -#endif // RALINK_ATE // - { - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, bbpId, bbpValue); - //Read it back for showing - RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); - } - sprintf(extra+strlen(extra), "R%02d[0x%02X]:%02X\n", bbpId, bbpId*2, regBBP); - wrq->length = strlen(extra) + 1; // 1: size of '\0' - DBGPRINT(RT_DEBUG_TRACE, ("msg=%s\n", extra)); - } - else - {//Invalid parametes, so default printk all bbp - bIsPrintAllBBP = TRUE; - goto next; - } - } - else - { //Invalid parametes, so default printk all bbp - bIsPrintAllBBP = TRUE; - goto next; - } - } - } - else - bIsPrintAllBBP = TRUE; - -next: - if (bIsPrintAllBBP) - { - memset(extra, 0x00, IW_PRIV_SIZE_MASK); - sprintf(extra, "\n"); - for (bbpId = 0; bbpId <= 136; bbpId++) - { - if (strlen(extra) >= (IW_PRIV_SIZE_MASK - 10)) - break; -#ifdef RALINK_ATE - if (ATE_ON(pAdapter)) - { - ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); - } - else -#endif // RALINK_ATE // - RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); - sprintf(extra+strlen(extra), "R%02d[0x%02X]:%02X ", bbpId, bbpId*2, regBBP); - if (bbpId%5 == 4) - sprintf(extra+strlen(extra), "\n"); - } - - wrq->length = strlen(extra) + 1; // 1: size of '\0' - DBGPRINT(RT_DEBUG_TRACE, ("wrq->length = %d\n", wrq->length)); - } - - DBGPRINT(RT_DEBUG_TRACE, ("<==rt_private_ioctl_bbp\n\n")); - - return Status; -} -#endif // DBG // - -int rt_ioctl_siwrate(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; - UINT32 rate = wrqu->bitrate.value, fixed = wrqu->bitrate.fixed; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("rt_ioctl_siwrate::Network is down!\n")); - return -ENETDOWN; - } - - DBGPRINT(RT_DEBUG_TRACE, ("rt_ioctl_siwrate::(rate = %d, fixed = %d)\n", rate, fixed)); - /* rate = -1 => auto rate - rate = X, fixed = 1 => (fixed rate X) - */ - if (rate == -1) - { - //Auto Rate - pAd->StaCfg.DesiredTransmitSetting.field.MCS = MCS_AUTO; - pAd->StaCfg.bAutoTxRateSwitch = TRUE; - if ((pAd->CommonCfg.PhyMode <= PHY_11G) || - (pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MODE <= MODE_OFDM)) - RTMPSetDesiredRates(pAd, -1); - -#ifdef DOT11_N_SUPPORT - SetCommonHT(pAd); -#endif // DOT11_N_SUPPORT // - } - else - { - if (fixed) - { - pAd->StaCfg.bAutoTxRateSwitch = FALSE; - if ((pAd->CommonCfg.PhyMode <= PHY_11G) || - (pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MODE <= MODE_OFDM)) - RTMPSetDesiredRates(pAd, rate); - else - { - pAd->StaCfg.DesiredTransmitSetting.field.MCS = MCS_AUTO; -#ifdef DOT11_N_SUPPORT - SetCommonHT(pAd); -#endif // DOT11_N_SUPPORT // - } - DBGPRINT(RT_DEBUG_TRACE, ("rt_ioctl_siwrate::(HtMcs=%d)\n",pAd->StaCfg.DesiredTransmitSetting.field.MCS)); - } - else - { - // TODO: rate = X, fixed = 0 => (rates <= X) - return -EOPNOTSUPP; - } - } - - return 0; -} - -int rt_ioctl_giwrate(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; - int rate_index = 0, rate_count = 0; - HTTRANSMIT_SETTING ht_setting; - __s32 ralinkrate[] = - {2, 4, 11, 22, // CCK - 12, 18, 24, 36, 48, 72, 96, 108, // OFDM - 13, 26, 39, 52, 78, 104, 117, 130, 26, 52, 78, 104, 156, 208, 234, 260, // 20MHz, 800ns GI, MCS: 0 ~ 15 - 39, 78, 117, 156, 234, 312, 351, 390, // 20MHz, 800ns GI, MCS: 16 ~ 23 - 27, 54, 81, 108, 162, 216, 243, 270, 54, 108, 162, 216, 324, 432, 486, 540, // 40MHz, 800ns GI, MCS: 0 ~ 15 - 81, 162, 243, 324, 486, 648, 729, 810, // 40MHz, 800ns GI, MCS: 16 ~ 23 - 14, 29, 43, 57, 87, 115, 130, 144, 29, 59, 87, 115, 173, 230, 260, 288, // 20MHz, 400ns GI, MCS: 0 ~ 15 - 43, 87, 130, 173, 260, 317, 390, 433, // 20MHz, 400ns GI, MCS: 16 ~ 23 - 30, 60, 90, 120, 180, 240, 270, 300, 60, 120, 180, 240, 360, 480, 540, 600, // 40MHz, 400ns GI, MCS: 0 ~ 15 - 90, 180, 270, 360, 540, 720, 810, 900}; // 40MHz, 400ns GI, MCS: 16 ~ 23 - - rate_count = sizeof(ralinkrate)/sizeof(__s32); - //check if the interface is down - if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - if ((pAd->StaCfg.bAutoTxRateSwitch == FALSE) && - (INFRA_ON(pAd)) && - ((pAd->CommonCfg.PhyMode <= PHY_11G) || (pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MODE <= MODE_OFDM))) - ht_setting.word = pAd->StaCfg.HTPhyMode.word; - else - ht_setting.word = pAd->MacTab.Content[BSSID_WCID].HTPhyMode.word; - -#ifdef DOT11_N_SUPPORT - if (ht_setting.field.MODE >= MODE_HTMIX) - { -// rate_index = 12 + ((UCHAR)ht_setting.field.BW *16) + ((UCHAR)ht_setting.field.ShortGI *32) + ((UCHAR)ht_setting.field.MCS); - rate_index = 12 + ((UCHAR)ht_setting.field.BW *24) + ((UCHAR)ht_setting.field.ShortGI *48) + ((UCHAR)ht_setting.field.MCS); - } - else -#endif // DOT11_N_SUPPORT // - if (ht_setting.field.MODE == MODE_OFDM) - rate_index = (UCHAR)(ht_setting.field.MCS) + 4; - else if (ht_setting.field.MODE == MODE_CCK) - rate_index = (UCHAR)(ht_setting.field.MCS); - - if (rate_index < 0) - rate_index = 0; - - if (rate_index > rate_count) - rate_index = rate_count; - - wrqu->bitrate.value = ralinkrate[rate_index] * 500000; - wrqu->bitrate.disabled = 0; - - return 0; -} - -static const iw_handler rt_handler[] = -{ - (iw_handler) NULL, /* SIOCSIWCOMMIT */ - (iw_handler) rt_ioctl_giwname, /* SIOCGIWNAME */ - (iw_handler) NULL, /* SIOCSIWNWID */ - (iw_handler) NULL, /* SIOCGIWNWID */ - (iw_handler) rt_ioctl_siwfreq, /* SIOCSIWFREQ */ - (iw_handler) rt_ioctl_giwfreq, /* SIOCGIWFREQ */ - (iw_handler) rt_ioctl_siwmode, /* SIOCSIWMODE */ - (iw_handler) rt_ioctl_giwmode, /* SIOCGIWMODE */ - (iw_handler) NULL, /* SIOCSIWSENS */ - (iw_handler) NULL, /* SIOCGIWSENS */ - (iw_handler) NULL /* not used */, /* SIOCSIWRANGE */ - (iw_handler) rt_ioctl_giwrange, /* SIOCGIWRANGE */ - (iw_handler) NULL /* not used */, /* SIOCSIWPRIV */ - (iw_handler) NULL /* kernel code */, /* SIOCGIWPRIV */ - (iw_handler) NULL /* not used */, /* SIOCSIWSTATS */ - (iw_handler) rt28xx_get_wireless_stats /* kernel code */, /* SIOCGIWSTATS */ - (iw_handler) NULL, /* SIOCSIWSPY */ - (iw_handler) NULL, /* SIOCGIWSPY */ - (iw_handler) NULL, /* SIOCSIWTHRSPY */ - (iw_handler) NULL, /* SIOCGIWTHRSPY */ - (iw_handler) rt_ioctl_siwap, /* SIOCSIWAP */ - (iw_handler) rt_ioctl_giwap, /* SIOCGIWAP */ -#ifdef SIOCSIWMLME - (iw_handler) rt_ioctl_siwmlme, /* SIOCSIWMLME */ -#else - (iw_handler) NULL, /* SIOCSIWMLME */ -#endif // SIOCSIWMLME // - (iw_handler) rt_ioctl_iwaplist, /* SIOCGIWAPLIST */ -#ifdef SIOCGIWSCAN - (iw_handler) rt_ioctl_siwscan, /* SIOCSIWSCAN */ - (iw_handler) rt_ioctl_giwscan, /* SIOCGIWSCAN */ -#else - (iw_handler) NULL, /* SIOCSIWSCAN */ - (iw_handler) NULL, /* SIOCGIWSCAN */ -#endif /* SIOCGIWSCAN */ - (iw_handler) rt_ioctl_siwessid, /* SIOCSIWESSID */ - (iw_handler) rt_ioctl_giwessid, /* SIOCGIWESSID */ - (iw_handler) rt_ioctl_siwnickn, /* SIOCSIWNICKN */ - (iw_handler) rt_ioctl_giwnickn, /* SIOCGIWNICKN */ - (iw_handler) NULL, /* -- hole -- */ - (iw_handler) NULL, /* -- hole -- */ - (iw_handler) rt_ioctl_siwrate, /* SIOCSIWRATE */ - (iw_handler) rt_ioctl_giwrate, /* SIOCGIWRATE */ - (iw_handler) rt_ioctl_siwrts, /* SIOCSIWRTS */ - (iw_handler) rt_ioctl_giwrts, /* SIOCGIWRTS */ - (iw_handler) rt_ioctl_siwfrag, /* SIOCSIWFRAG */ - (iw_handler) rt_ioctl_giwfrag, /* SIOCGIWFRAG */ - (iw_handler) NULL, /* SIOCSIWTXPOW */ - (iw_handler) NULL, /* SIOCGIWTXPOW */ - (iw_handler) NULL, /* SIOCSIWRETRY */ - (iw_handler) NULL, /* SIOCGIWRETRY */ - (iw_handler) rt_ioctl_siwencode, /* SIOCSIWENCODE */ - (iw_handler) rt_ioctl_giwencode, /* SIOCGIWENCODE */ - (iw_handler) NULL, /* SIOCSIWPOWER */ - (iw_handler) NULL, /* SIOCGIWPOWER */ - (iw_handler) NULL, /* -- hole -- */ - (iw_handler) NULL, /* -- hole -- */ -#if WIRELESS_EXT > 17 - (iw_handler) rt_ioctl_siwgenie, /* SIOCSIWGENIE */ - (iw_handler) rt_ioctl_giwgenie, /* SIOCGIWGENIE */ - (iw_handler) rt_ioctl_siwauth, /* SIOCSIWAUTH */ - (iw_handler) rt_ioctl_giwauth, /* SIOCGIWAUTH */ - (iw_handler) rt_ioctl_siwencodeext, /* SIOCSIWENCODEEXT */ - (iw_handler) rt_ioctl_giwencodeext, /* SIOCGIWENCODEEXT */ - (iw_handler) rt_ioctl_siwpmksa, /* SIOCSIWPMKSA */ -#endif -}; - -static const iw_handler rt_priv_handlers[] = { - (iw_handler) NULL, /* + 0x00 */ - (iw_handler) NULL, /* + 0x01 */ -#ifndef CONFIG_AP_SUPPORT - (iw_handler) rt_ioctl_setparam, /* + 0x02 */ -#else - (iw_handler) NULL, /* + 0x02 */ -#endif // CONFIG_AP_SUPPORT // -#ifdef DBG - (iw_handler) rt_private_ioctl_bbp, /* + 0x03 */ -#else - (iw_handler) NULL, /* + 0x03 */ -#endif - (iw_handler) NULL, /* + 0x04 */ - (iw_handler) NULL, /* + 0x05 */ - (iw_handler) NULL, /* + 0x06 */ - (iw_handler) NULL, /* + 0x07 */ - (iw_handler) NULL, /* + 0x08 */ - (iw_handler) rt_private_get_statistics, /* + 0x09 */ - (iw_handler) NULL, /* + 0x0A */ - (iw_handler) NULL, /* + 0x0B */ - (iw_handler) NULL, /* + 0x0C */ - (iw_handler) NULL, /* + 0x0D */ - (iw_handler) NULL, /* + 0x0E */ - (iw_handler) NULL, /* + 0x0F */ - (iw_handler) NULL, /* + 0x10 */ - (iw_handler) rt_private_show, /* + 0x11 */ - (iw_handler) NULL, /* + 0x12 */ - (iw_handler) NULL, /* + 0x13 */ - (iw_handler) NULL, /* + 0x15 */ - (iw_handler) NULL, /* + 0x17 */ - (iw_handler) NULL, /* + 0x18 */ -}; - -const struct iw_handler_def rt28xx_iw_handler_def = -{ -#define N(a) (sizeof (a) / sizeof (a[0])) - .standard = (iw_handler *) rt_handler, - .num_standard = sizeof(rt_handler) / sizeof(iw_handler), - .private = (iw_handler *) rt_priv_handlers, - .num_private = N(rt_priv_handlers), - .private_args = (struct iw_priv_args *) privtab, - .num_private_args = N(privtab), -#if IW_HANDLER_VERSION >= 7 - .get_wireless_stats = rt28xx_get_wireless_stats, -#endif -}; - -INT RTMPSetInformation( - IN PRTMP_ADAPTER pAdapter, - IN OUT struct ifreq *rq, - IN INT cmd) -{ - struct iwreq *wrq = (struct iwreq *) rq; - NDIS_802_11_SSID Ssid; - NDIS_802_11_MAC_ADDRESS Bssid; - RT_802_11_PHY_MODE PhyMode; - RT_802_11_STA_CONFIG StaConfig; - NDIS_802_11_RATES aryRates; - RT_802_11_PREAMBLE Preamble; - NDIS_802_11_WEP_STATUS WepStatus; - NDIS_802_11_AUTHENTICATION_MODE AuthMode = Ndis802_11AuthModeMax; - NDIS_802_11_NETWORK_INFRASTRUCTURE BssType; - NDIS_802_11_RTS_THRESHOLD RtsThresh; - NDIS_802_11_FRAGMENTATION_THRESHOLD FragThresh; - NDIS_802_11_POWER_MODE PowerMode; - PNDIS_802_11_KEY pKey = NULL; - PNDIS_802_11_WEP pWepKey =NULL; - PNDIS_802_11_REMOVE_KEY pRemoveKey = NULL; - NDIS_802_11_CONFIGURATION Config, *pConfig = NULL; - NDIS_802_11_NETWORK_TYPE NetType; - ULONG Now; - UINT KeyIdx = 0; - INT Status = NDIS_STATUS_SUCCESS, MaxPhyMode = PHY_11G; - ULONG PowerTemp; - BOOLEAN RadioState; - BOOLEAN StateMachineTouched = FALSE; -#ifdef DOT11_N_SUPPORT - OID_SET_HT_PHYMODE HT_PhyMode; //11n ,kathy -#endif // DOT11_N_SUPPORT // -#ifdef WPA_SUPPLICANT_SUPPORT - PNDIS_802_11_PMKID pPmkId = NULL; - BOOLEAN IEEE8021xState = FALSE; - BOOLEAN IEEE8021x_required_keys = FALSE; - UCHAR wpa_supplicant_enable = 0; -#endif // WPA_SUPPLICANT_SUPPORT // - -#ifdef SNMP_SUPPORT - TX_RTY_CFG_STRUC tx_rty_cfg; - ULONG ShortRetryLimit, LongRetryLimit; - UCHAR ctmp; -#endif // SNMP_SUPPORT // - - - -#ifdef DOT11_N_SUPPORT - MaxPhyMode = PHY_11N_5G; -#endif // DOT11_N_SUPPORT // - - - DBGPRINT(RT_DEBUG_TRACE, ("-->RTMPSetInformation(), 0x%08x\n", cmd&0x7FFF)); - switch(cmd & 0x7FFF) { - case RT_OID_802_11_COUNTRY_REGION: - if (wrq->u.data.length < sizeof(UCHAR)) - Status = -EINVAL; - // Only avaliable when EEPROM not programming - else if (!(pAdapter->CommonCfg.CountryRegion & 0x80) && !(pAdapter->CommonCfg.CountryRegionForABand & 0x80)) - { - ULONG Country; - UCHAR TmpPhy; - - Status = copy_from_user(&Country, wrq->u.data.pointer, wrq->u.data.length); - pAdapter->CommonCfg.CountryRegion = (UCHAR)(Country & 0x000000FF); - pAdapter->CommonCfg.CountryRegionForABand = (UCHAR)((Country >> 8) & 0x000000FF); - TmpPhy = pAdapter->CommonCfg.PhyMode; - pAdapter->CommonCfg.PhyMode = 0xff; - // Build all corresponding channel information - RTMPSetPhyMode(pAdapter, TmpPhy); -#ifdef DOT11_N_SUPPORT - SetCommonHT(pAdapter); -#endif // DOT11_N_SUPPORT // - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_COUNTRY_REGION (A:%d B/G:%d)\n", pAdapter->CommonCfg.CountryRegionForABand, - pAdapter->CommonCfg.CountryRegion)); - } - break; - case OID_802_11_BSSID_LIST_SCAN: - #ifdef RALINK_ATE - if (ATE_ON(pAdapter)) - { - DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now\n")); - break; - } -#endif // RALINK_ATE // - Now = jiffies; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_BSSID_LIST_SCAN, TxCnt = %d \n", pAdapter->RalinkCounters.LastOneSecTotalTxCount)); - - if (MONITOR_ON(pAdapter)) - { - DBGPRINT(RT_DEBUG_TRACE, ("!!! Driver is in Monitor Mode now !!!\n")); - break; - } - - //Benson add 20080527, when radio off, sta don't need to scan - if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RADIO_OFF)) - break; - - if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) - { - DBGPRINT(RT_DEBUG_TRACE, ("!!! Driver is scanning now !!!\n")); - pAdapter->StaCfg.bScanReqIsFromWebUI = TRUE; - Status = NDIS_STATUS_SUCCESS; - break; - } - - if (pAdapter->RalinkCounters.LastOneSecTotalTxCount > 100) - { - DBGPRINT(RT_DEBUG_TRACE, ("!!! Link UP, ignore this set::OID_802_11_BSSID_LIST_SCAN\n")); - Status = NDIS_STATUS_SUCCESS; - pAdapter->StaCfg.ScanCnt = 99; // Prevent auto scan triggered by this OID - break; - } - - if ((OPSTATUS_TEST_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED)) && - ((pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || - (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) || - (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || - (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)) && - (pAdapter->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED)) - { - DBGPRINT(RT_DEBUG_TRACE, ("!!! Link UP, Port Not Secured! ignore this set::OID_802_11_BSSID_LIST_SCAN\n")); - Status = NDIS_STATUS_SUCCESS; - pAdapter->StaCfg.ScanCnt = 99; // Prevent auto scan triggered by this OID - break; - } - - - if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) - { - RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); - DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); - } - - // tell CNTL state machine to call NdisMSetInformationComplete() after completing - // this request, because this request is initiated by NDIS. - pAdapter->MlmeAux.CurrReqIsFromNdis = FALSE; - // Reset allowed scan retries - pAdapter->StaCfg.ScanCnt = 0; - pAdapter->StaCfg.LastScanTime = Now; - - pAdapter->StaCfg.bScanReqIsFromWebUI = TRUE; - RTMP_SET_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS); - MlmeEnqueue(pAdapter, - MLME_CNTL_STATE_MACHINE, - OID_802_11_BSSID_LIST_SCAN, - 0, - NULL); - - Status = NDIS_STATUS_SUCCESS; - StateMachineTouched = TRUE; - break; - case OID_802_11_SSID: - if (wrq->u.data.length != sizeof(NDIS_802_11_SSID)) - Status = -EINVAL; - else - { - PCHAR pSsidString = NULL; - Status = copy_from_user(&Ssid, wrq->u.data.pointer, wrq->u.data.length); - - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_SSID (Len=%d,Ssid=%s)\n", Ssid.SsidLength, Ssid.Ssid)); - if (Ssid.SsidLength > MAX_LEN_OF_SSID) - Status = -EINVAL; - else - { - if (Ssid.SsidLength == 0) - { - Set_SSID_Proc(pAdapter, ""); - } - else - { - pSsidString = (CHAR *) kmalloc(MAX_LEN_OF_SSID+1, MEM_ALLOC_FLAG); - if (pSsidString) - { - NdisZeroMemory(pSsidString, MAX_LEN_OF_SSID+1); - NdisMoveMemory(pSsidString, Ssid.Ssid, Ssid.SsidLength); - Set_SSID_Proc(pAdapter, pSsidString); - kfree(pSsidString); - } - else - Status = -ENOMEM; - } - } - } - break; - case OID_802_11_BSSID: -#ifdef RALINK_ATE - if (ATE_ON(pAdapter)) - { - DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now\n")); - break; - } -#endif // RALINK_ATE // - if (wrq->u.data.length != sizeof(NDIS_802_11_MAC_ADDRESS)) - Status = -EINVAL; - else - { - Status = copy_from_user(&Bssid, wrq->u.data.pointer, wrq->u.data.length); - - // tell CNTL state machine to call NdisMSetInformationComplete() after completing - // this request, because this request is initiated by NDIS. - pAdapter->MlmeAux.CurrReqIsFromNdis = FALSE; - - // Prevent to connect AP again in STAMlmePeriodicExec - pAdapter->MlmeAux.AutoReconnectSsidLen= 32; - - // Reset allowed scan retries - pAdapter->StaCfg.ScanCnt = 0; - - if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) - { - RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); - DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); - } - MlmeEnqueue(pAdapter, - MLME_CNTL_STATE_MACHINE, - OID_802_11_BSSID, - sizeof(NDIS_802_11_MAC_ADDRESS), - (VOID *)&Bssid); - Status = NDIS_STATUS_SUCCESS; - StateMachineTouched = TRUE; - - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_BSSID %02x:%02x:%02x:%02x:%02x:%02x\n", - Bssid[0], Bssid[1], Bssid[2], Bssid[3], Bssid[4], Bssid[5])); - } - break; - case RT_OID_802_11_RADIO: - if (wrq->u.data.length != sizeof(BOOLEAN)) - Status = -EINVAL; - else - { - Status = copy_from_user(&RadioState, wrq->u.data.pointer, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_RADIO (=%d)\n", RadioState)); - if (pAdapter->StaCfg.bSwRadio != RadioState) - { - pAdapter->StaCfg.bSwRadio = RadioState; - if (pAdapter->StaCfg.bRadio != (pAdapter->StaCfg.bHwRadio && pAdapter->StaCfg.bSwRadio)) - { - pAdapter->StaCfg.bRadio = (pAdapter->StaCfg.bHwRadio && pAdapter->StaCfg.bSwRadio); - if (pAdapter->StaCfg.bRadio == TRUE) - { - MlmeRadioOn(pAdapter); - // Update extra information - pAdapter->ExtraInfo = EXTRA_INFO_CLEAR; - } - else - { - MlmeRadioOff(pAdapter); - // Update extra information - pAdapter->ExtraInfo = SW_RADIO_OFF; - } - } - } - } - break; - case RT_OID_802_11_PHY_MODE: - if (wrq->u.data.length != sizeof(RT_802_11_PHY_MODE)) - Status = -EINVAL; - else - { - Status = copy_from_user(&PhyMode, wrq->u.data.pointer, wrq->u.data.length); - if (PhyMode <= MaxPhyMode) - { - RTMPSetPhyMode(pAdapter, PhyMode); -#ifdef DOT11_N_SUPPORT - SetCommonHT(pAdapter); -#endif // DOT11_N_SUPPORT // - } - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_PHY_MODE (=%d)\n", PhyMode)); - } - break; - case RT_OID_802_11_STA_CONFIG: - if (wrq->u.data.length != sizeof(RT_802_11_STA_CONFIG)) - Status = -EINVAL; - else - { - Status = copy_from_user(&StaConfig, wrq->u.data.pointer, wrq->u.data.length); - pAdapter->CommonCfg.bEnableTxBurst = StaConfig.EnableTxBurst; - pAdapter->CommonCfg.UseBGProtection = StaConfig.UseBGProtection; - pAdapter->CommonCfg.bUseShortSlotTime = 1; // 2003-10-30 always SHORT SLOT capable - if ((pAdapter->CommonCfg.PhyMode != StaConfig.AdhocMode) && - (StaConfig.AdhocMode <= MaxPhyMode)) - { - // allow dynamic change of "USE OFDM rate or not" in ADHOC mode - // if setting changed, need to reset current TX rate as well as BEACON frame format - if (pAdapter->StaCfg.BssType == BSS_ADHOC) - { - pAdapter->CommonCfg.PhyMode = StaConfig.AdhocMode; - RTMPSetPhyMode(pAdapter, PhyMode); - MlmeUpdateTxRates(pAdapter, FALSE, 0); - MakeIbssBeacon(pAdapter); // re-build BEACON frame - AsicEnableIbssSync(pAdapter); // copy to on-chip memory - } - } - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_SET_STA_CONFIG (Burst=%d, Protection=%ld,ShortSlot=%d\n", - pAdapter->CommonCfg.bEnableTxBurst, - pAdapter->CommonCfg.UseBGProtection, - pAdapter->CommonCfg.bUseShortSlotTime)); - } - break; - case OID_802_11_DESIRED_RATES: - if (wrq->u.data.length != sizeof(NDIS_802_11_RATES)) - Status = -EINVAL; - else - { - Status = copy_from_user(&aryRates, wrq->u.data.pointer, wrq->u.data.length); - NdisZeroMemory(pAdapter->CommonCfg.DesireRate, MAX_LEN_OF_SUPPORTED_RATES); - NdisMoveMemory(pAdapter->CommonCfg.DesireRate, &aryRates, sizeof(NDIS_802_11_RATES)); - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_DESIRED_RATES (%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x)\n", - pAdapter->CommonCfg.DesireRate[0],pAdapter->CommonCfg.DesireRate[1], - pAdapter->CommonCfg.DesireRate[2],pAdapter->CommonCfg.DesireRate[3], - pAdapter->CommonCfg.DesireRate[4],pAdapter->CommonCfg.DesireRate[5], - pAdapter->CommonCfg.DesireRate[6],pAdapter->CommonCfg.DesireRate[7] )); - // Changing DesiredRate may affect the MAX TX rate we used to TX frames out - MlmeUpdateTxRates(pAdapter, FALSE, 0); - } - break; - case RT_OID_802_11_PREAMBLE: - if (wrq->u.data.length != sizeof(RT_802_11_PREAMBLE)) - Status = -EINVAL; - else - { - Status = copy_from_user(&Preamble, wrq->u.data.pointer, wrq->u.data.length); - if (Preamble == Rt802_11PreambleShort) - { - pAdapter->CommonCfg.TxPreamble = Preamble; - MlmeSetTxPreamble(pAdapter, Rt802_11PreambleShort); - } - else if ((Preamble == Rt802_11PreambleLong) || (Preamble == Rt802_11PreambleAuto)) - { - // if user wants AUTO, initialize to LONG here, then change according to AP's - // capability upon association. - pAdapter->CommonCfg.TxPreamble = Preamble; - MlmeSetTxPreamble(pAdapter, Rt802_11PreambleLong); - } - else - { - Status = -EINVAL; - break; - } - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_PREAMBLE (=%d)\n", Preamble)); - } - break; - case OID_802_11_WEP_STATUS: - if (wrq->u.data.length != sizeof(NDIS_802_11_WEP_STATUS)) - Status = -EINVAL; - else - { - Status = copy_from_user(&WepStatus, wrq->u.data.pointer, wrq->u.data.length); - // Since TKIP, AES, WEP are all supported. It should not have any invalid setting - if (WepStatus <= Ndis802_11Encryption3KeyAbsent) - { - if (pAdapter->StaCfg.WepStatus != WepStatus) - { - // Config has changed - pAdapter->bConfigChanged = TRUE; - } - pAdapter->StaCfg.WepStatus = WepStatus; - pAdapter->StaCfg.OrigWepStatus = WepStatus; - pAdapter->StaCfg.PairCipher = WepStatus; - pAdapter->StaCfg.GroupCipher = WepStatus; - } - else - { - Status = -EINVAL; - break; - } - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_WEP_STATUS (=%d)\n",WepStatus)); - } - break; - case OID_802_11_AUTHENTICATION_MODE: - if (wrq->u.data.length != sizeof(NDIS_802_11_AUTHENTICATION_MODE)) - Status = -EINVAL; - else - { - Status = copy_from_user(&AuthMode, wrq->u.data.pointer, wrq->u.data.length); - if (AuthMode > Ndis802_11AuthModeMax) - { - Status = -EINVAL; - break; - } - else - { - if (pAdapter->StaCfg.AuthMode != AuthMode) - { - // Config has changed - pAdapter->bConfigChanged = TRUE; - } - pAdapter->StaCfg.AuthMode = AuthMode; - } - pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_AUTHENTICATION_MODE (=%d) \n",pAdapter->StaCfg.AuthMode)); - } - break; - case OID_802_11_INFRASTRUCTURE_MODE: - if (wrq->u.data.length != sizeof(NDIS_802_11_NETWORK_INFRASTRUCTURE)) - Status = -EINVAL; - else - { - Status = copy_from_user(&BssType, wrq->u.data.pointer, wrq->u.data.length); - - if (BssType == Ndis802_11IBSS) - Set_NetworkType_Proc(pAdapter, "Adhoc"); - else if (BssType == Ndis802_11Infrastructure) - Set_NetworkType_Proc(pAdapter, "Infra"); - else if (BssType == Ndis802_11Monitor) - Set_NetworkType_Proc(pAdapter, "Monitor"); - else - { - Status = -EINVAL; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_INFRASTRUCTURE_MODE (unknown)\n")); - } - } - break; - case OID_802_11_REMOVE_WEP: - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_WEP\n")); - if (wrq->u.data.length != sizeof(NDIS_802_11_KEY_INDEX)) - { - Status = -EINVAL; - } - else - { - KeyIdx = *(NDIS_802_11_KEY_INDEX *) wrq->u.data.pointer; - - if (KeyIdx & 0x80000000) - { - // Should never set default bit when remove key - Status = -EINVAL; - } - else - { - KeyIdx = KeyIdx & 0x0fffffff; - if (KeyIdx >= 4){ - Status = -EINVAL; - } - else - { - pAdapter->SharedKey[BSS0][KeyIdx].KeyLen = 0; - pAdapter->SharedKey[BSS0][KeyIdx].CipherAlg = CIPHER_NONE; - AsicRemoveSharedKeyEntry(pAdapter, 0, (UCHAR)KeyIdx); - } - } - } - break; - case RT_OID_802_11_RESET_COUNTERS: - NdisZeroMemory(&pAdapter->WlanCounters, sizeof(COUNTER_802_11)); - NdisZeroMemory(&pAdapter->Counters8023, sizeof(COUNTER_802_3)); - NdisZeroMemory(&pAdapter->RalinkCounters, sizeof(COUNTER_RALINK)); - pAdapter->Counters8023.RxNoBuffer = 0; - pAdapter->Counters8023.GoodReceives = 0; - pAdapter->Counters8023.RxNoBuffer = 0; -#ifdef RT2870 - pAdapter->BulkOutComplete = 0; - pAdapter->BulkOutCompleteOther= 0; - pAdapter->BulkOutCompleteCancel = 0; - pAdapter->BulkOutReq = 0; - pAdapter->BulkInReq= 0; - pAdapter->BulkInComplete = 0; - pAdapter->BulkInCompleteFail = 0; -#endif // RT2870 // - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_RESET_COUNTERS \n")); - break; - case OID_802_11_RTS_THRESHOLD: - if (wrq->u.data.length != sizeof(NDIS_802_11_RTS_THRESHOLD)) - Status = -EINVAL; - else - { - Status = copy_from_user(&RtsThresh, wrq->u.data.pointer, wrq->u.data.length); - if (RtsThresh > MAX_RTS_THRESHOLD) - Status = -EINVAL; - else - pAdapter->CommonCfg.RtsThreshold = (USHORT)RtsThresh; - } - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_RTS_THRESHOLD (=%ld)\n",RtsThresh)); - break; - case OID_802_11_FRAGMENTATION_THRESHOLD: - if (wrq->u.data.length != sizeof(NDIS_802_11_FRAGMENTATION_THRESHOLD)) - Status = -EINVAL; - else - { - Status = copy_from_user(&FragThresh, wrq->u.data.pointer, wrq->u.data.length); - pAdapter->CommonCfg.bUseZeroToDisableFragment = FALSE; - if (FragThresh > MAX_FRAG_THRESHOLD || FragThresh < MIN_FRAG_THRESHOLD) - { - if (FragThresh == 0) - { - pAdapter->CommonCfg.FragmentThreshold = MAX_FRAG_THRESHOLD; - pAdapter->CommonCfg.bUseZeroToDisableFragment = TRUE; - } - else - Status = -EINVAL; - } - else - pAdapter->CommonCfg.FragmentThreshold = (USHORT)FragThresh; - } - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_FRAGMENTATION_THRESHOLD (=%ld) \n",FragThresh)); - break; - case OID_802_11_POWER_MODE: - if (wrq->u.data.length != sizeof(NDIS_802_11_POWER_MODE)) - Status = -EINVAL; - else - { - Status = copy_from_user(&PowerMode, wrq->u.data.pointer, wrq->u.data.length); - if (PowerMode == Ndis802_11PowerModeCAM) - Set_PSMode_Proc(pAdapter, "CAM"); - else if (PowerMode == Ndis802_11PowerModeMAX_PSP) - Set_PSMode_Proc(pAdapter, "Max_PSP"); - else if (PowerMode == Ndis802_11PowerModeFast_PSP) - Set_PSMode_Proc(pAdapter, "Fast_PSP"); - else if (PowerMode == Ndis802_11PowerModeLegacy_PSP) - Set_PSMode_Proc(pAdapter, "Legacy_PSP"); - else - Status = -EINVAL; - } - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_POWER_MODE (=%d)\n",PowerMode)); - break; - case RT_OID_802_11_TX_POWER_LEVEL_1: - if (wrq->u.data.length < sizeof(ULONG)) - Status = -EINVAL; - else - { - Status = copy_from_user(&PowerTemp, wrq->u.data.pointer, wrq->u.data.length); - if (PowerTemp > 100) - PowerTemp = 0xffffffff; // AUTO - pAdapter->CommonCfg.TxPowerDefault = PowerTemp; //keep current setting. - pAdapter->CommonCfg.TxPowerPercentage = pAdapter->CommonCfg.TxPowerDefault; - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_TX_POWER_LEVEL_1 (=%ld)\n", pAdapter->CommonCfg.TxPowerPercentage)); - } - break; - case OID_802_11_NETWORK_TYPE_IN_USE: - if (wrq->u.data.length != sizeof(NDIS_802_11_NETWORK_TYPE)) - Status = -EINVAL; - else - { - Status = copy_from_user(&NetType, wrq->u.data.pointer, wrq->u.data.length); - - if (NetType == Ndis802_11DS) - RTMPSetPhyMode(pAdapter, PHY_11B); - else if (NetType == Ndis802_11OFDM24) - RTMPSetPhyMode(pAdapter, PHY_11BG_MIXED); - else if (NetType == Ndis802_11OFDM5) - RTMPSetPhyMode(pAdapter, PHY_11A); - else - Status = -EINVAL; -#ifdef DOT11_N_SUPPORT - if (Status == NDIS_STATUS_SUCCESS) - SetCommonHT(pAdapter); -#endif // DOT11_N_SUPPORT // - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_NETWORK_TYPE_IN_USE (=%d)\n",NetType)); - } - break; - // For WPA PSK PMK key - case RT_OID_802_11_ADD_WPA: - pKey = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); - if(pKey == NULL) - { - Status = -ENOMEM; - break; - } - - Status = copy_from_user(pKey, wrq->u.data.pointer, wrq->u.data.length); - if (pKey->Length != wrq->u.data.length) - { - Status = -EINVAL; - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_ADD_WPA, Failed!!\n")); - } - else - { - if ((pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPAPSK) && - (pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPA2PSK) && - (pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPANone) ) - { - Status = -EOPNOTSUPP; - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_ADD_WPA, Failed!! [AuthMode != WPAPSK/WPA2PSK/WPANONE]\n")); - } - else if ((pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) || - (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) || - (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) ) // Only for WPA PSK mode - { - NdisMoveMemory(pAdapter->StaCfg.PMK, &pKey->KeyMaterial, pKey->KeyLength); - // Use RaConfig as PSK agent. - // Start STA supplicant state machine - if (pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPANone) - pAdapter->StaCfg.WpaState = SS_START; - - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_ADD_WPA (id=0x%x, Len=%d-byte)\n", pKey->KeyIndex, pKey->KeyLength)); - } - else - { - pAdapter->StaCfg.WpaState = SS_NOTUSE; - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_ADD_WPA (id=0x%x, Len=%d-byte)\n", pKey->KeyIndex, pKey->KeyLength)); - } - } - kfree(pKey); - break; - case OID_802_11_REMOVE_KEY: - pRemoveKey = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); - if(pRemoveKey == NULL) - { - Status = -ENOMEM; - break; - } - - Status = copy_from_user(pRemoveKey, wrq->u.data.pointer, wrq->u.data.length); - if (pRemoveKey->Length != wrq->u.data.length) - { - Status = -EINVAL; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_KEY, Failed!!\n")); - } - else - { - if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - { - RTMPWPARemoveKeyProc(pAdapter, pRemoveKey); - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_KEY, Remove WPA Key!!\n")); - } - else - { - KeyIdx = pRemoveKey->KeyIndex; - - if (KeyIdx & 0x80000000) - { - // Should never set default bit when remove key - Status = -EINVAL; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_KEY, Failed!!(Should never set default bit when remove key)\n")); - } - else - { - KeyIdx = KeyIdx & 0x0fffffff; - if (KeyIdx > 3) - { - Status = -EINVAL; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_KEY, Failed!!(KeyId[%d] out of range)\n", KeyIdx)); - } - else - { - pAdapter->SharedKey[BSS0][KeyIdx].KeyLen = 0; - pAdapter->SharedKey[BSS0][KeyIdx].CipherAlg = CIPHER_NONE; - AsicRemoveSharedKeyEntry(pAdapter, 0, (UCHAR)KeyIdx); - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_KEY (id=0x%x, Len=%d-byte)\n", pRemoveKey->KeyIndex, pRemoveKey->Length)); - } - } - } - } - kfree(pRemoveKey); - break; - // New for WPA - case OID_802_11_ADD_KEY: - pKey = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); - if(pKey == NULL) - { - Status = -ENOMEM; - break; - } - Status = copy_from_user(pKey, wrq->u.data.pointer, wrq->u.data.length); - if (pKey->Length != wrq->u.data.length) - { - Status = -EINVAL; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_KEY, Failed!!\n")); - } - else - { - RTMPAddKey(pAdapter, pKey); - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_KEY (id=0x%x, Len=%d-byte)\n", pKey->KeyIndex, pKey->KeyLength)); - } - kfree(pKey); - break; - case OID_802_11_CONFIGURATION: - if (wrq->u.data.length != sizeof(NDIS_802_11_CONFIGURATION)) - Status = -EINVAL; - else - { - Status = copy_from_user(&Config, wrq->u.data.pointer, wrq->u.data.length); - pConfig = &Config; - - if ((pConfig->BeaconPeriod >= 20) && (pConfig->BeaconPeriod <=400)) - pAdapter->CommonCfg.BeaconPeriod = (USHORT) pConfig->BeaconPeriod; - - pAdapter->StaActive.AtimWin = (USHORT) pConfig->ATIMWindow; - MAP_KHZ_TO_CHANNEL_ID(pConfig->DSConfig, pAdapter->CommonCfg.Channel); - // - // Save the channel on MlmeAux for CntlOidRTBssidProc used. - // - pAdapter->MlmeAux.Channel = pAdapter->CommonCfg.Channel; - - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_CONFIGURATION (BeacnPeriod=%ld,AtimW=%ld,Ch=%d)\n", - pConfig->BeaconPeriod, pConfig->ATIMWindow, pAdapter->CommonCfg.Channel)); - // Config has changed - pAdapter->bConfigChanged = TRUE; - } - break; -#ifdef DOT11_N_SUPPORT - case RT_OID_802_11_SET_HT_PHYMODE: - if (wrq->u.data.length != sizeof(OID_SET_HT_PHYMODE)) - Status = -EINVAL; - else - { - POID_SET_HT_PHYMODE pHTPhyMode = &HT_PhyMode; - - Status = copy_from_user(&HT_PhyMode, wrq->u.data.pointer, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Set::pHTPhyMode (PhyMode = %d,TransmitNo = %d, HtMode = %d, ExtOffset = %d , MCS = %d, BW = %d, STBC = %d, SHORTGI = %d) \n", - pHTPhyMode->PhyMode, pHTPhyMode->TransmitNo,pHTPhyMode->HtMode,pHTPhyMode->ExtOffset, - pHTPhyMode->MCS, pHTPhyMode->BW, pHTPhyMode->STBC, pHTPhyMode->SHORTGI)); - if (pAdapter->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) - RTMPSetHT(pAdapter, pHTPhyMode); - } - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_SET_HT_PHYMODE(MCS=%d,BW=%d,SGI=%d,STBC=%d)\n", - pAdapter->StaCfg.HTPhyMode.field.MCS, pAdapter->StaCfg.HTPhyMode.field.BW, pAdapter->StaCfg.HTPhyMode.field.ShortGI, - pAdapter->StaCfg.HTPhyMode.field.STBC)); - break; -#endif // DOT11_N_SUPPORT // - case RT_OID_802_11_SET_APSD_SETTING: - if (wrq->u.data.length != sizeof(ULONG)) - Status = -EINVAL; - else - { - ULONG apsd ; - Status = copy_from_user(&apsd, wrq->u.data.pointer, wrq->u.data.length); - - /*------------------------------------------------------------------- - |B31~B7 | B6~B5 | B4 | B3 | B2 | B1 | B0 | - --------------------------------------------------------------------- - | Rsvd | Max SP Len | AC_VO | AC_VI | AC_BK | AC_BE | APSD Capable | - ---------------------------------------------------------------------*/ - pAdapter->CommonCfg.bAPSDCapable = (apsd & 0x00000001) ? TRUE : FALSE; - pAdapter->CommonCfg.bAPSDAC_BE = ((apsd & 0x00000002) >> 1) ? TRUE : FALSE; - pAdapter->CommonCfg.bAPSDAC_BK = ((apsd & 0x00000004) >> 2) ? TRUE : FALSE; - pAdapter->CommonCfg.bAPSDAC_VI = ((apsd & 0x00000008) >> 3) ? TRUE : FALSE; - pAdapter->CommonCfg.bAPSDAC_VO = ((apsd & 0x00000010) >> 4) ? TRUE : FALSE; - pAdapter->CommonCfg.MaxSPLength = (UCHAR)((apsd & 0x00000060) >> 5); - - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_SET_APSD_SETTING (apsd=0x%lx, APSDCap=%d, [BE,BK,VI,VO]=[%d/%d/%d/%d], MaxSPLen=%d)\n", apsd, pAdapter->CommonCfg.bAPSDCapable, - pAdapter->CommonCfg.bAPSDAC_BE, pAdapter->CommonCfg.bAPSDAC_BK, pAdapter->CommonCfg.bAPSDAC_VI, pAdapter->CommonCfg.bAPSDAC_VO, pAdapter->CommonCfg.MaxSPLength)); - } - break; - - case RT_OID_802_11_SET_APSD_PSM: - if (wrq->u.data.length != sizeof(ULONG)) - Status = -EINVAL; - else - { - // Driver needs to notify AP when PSM changes - Status = copy_from_user(&pAdapter->CommonCfg.bAPSDForcePowerSave, wrq->u.data.pointer, wrq->u.data.length); - if (pAdapter->CommonCfg.bAPSDForcePowerSave != pAdapter->StaCfg.Psm) - { - MlmeSetPsmBit(pAdapter, pAdapter->CommonCfg.bAPSDForcePowerSave); - RTMPSendNullFrame(pAdapter, pAdapter->CommonCfg.TxRate, TRUE); - } - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_SET_APSD_PSM (bAPSDForcePowerSave:%d)\n", pAdapter->CommonCfg.bAPSDForcePowerSave)); - } - break; -#ifdef QOS_DLS_SUPPORT - case RT_OID_802_11_SET_DLS: - if (wrq->u.data.length != sizeof(ULONG)) - Status = -EINVAL; - else - { - BOOLEAN oldvalue = pAdapter->CommonCfg.bDLSCapable; - Status = copy_from_user(&pAdapter->CommonCfg.bDLSCapable, wrq->u.data.pointer, wrq->u.data.length); - if (oldvalue && !pAdapter->CommonCfg.bDLSCapable) - { - int i; - // tear down local dls table entry - for (i=0; iStaCfg.DLSEntry[i].Valid && (pAdapter->StaCfg.DLSEntry[i].Status == DLS_FINISH)) - { - pAdapter->StaCfg.DLSEntry[i].Status = DLS_NONE; - pAdapter->StaCfg.DLSEntry[i].Valid = FALSE; - RTMPSendDLSTearDownFrame(pAdapter, pAdapter->StaCfg.DLSEntry[i].MacAddr); - } - } - - // tear down peer dls table entry - for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid && (pAdapter->StaCfg.DLSEntry[i].Status == DLS_FINISH)) - { - pAdapter->StaCfg.DLSEntry[i].Status = DLS_NONE; - pAdapter->StaCfg.DLSEntry[i].Valid = FALSE; - RTMPSendDLSTearDownFrame(pAdapter, pAdapter->StaCfg.DLSEntry[i].MacAddr); - } - } - } - - DBGPRINT(RT_DEBUG_TRACE,("Set::RT_OID_802_11_SET_DLS (=%d)\n", pAdapter->CommonCfg.bDLSCapable)); - } - break; - - case RT_OID_802_11_SET_DLS_PARAM: - if (wrq->u.data.length != sizeof(RT_802_11_DLS_UI)) - Status = -EINVAL; - else - { - RT_802_11_DLS Dls; - - NdisZeroMemory(&Dls, sizeof(RT_802_11_DLS)); - RTMPMoveMemory(&Dls, wrq->u.data.pointer, sizeof(RT_802_11_DLS_UI)); - MlmeEnqueue(pAdapter, - MLME_CNTL_STATE_MACHINE, - RT_OID_802_11_SET_DLS_PARAM, - sizeof(RT_802_11_DLS), - &Dls); - DBGPRINT(RT_DEBUG_TRACE,("Set::RT_OID_802_11_SET_DLS_PARAM \n")); - } - break; -#endif // QOS_DLS_SUPPORT // - case RT_OID_802_11_SET_WMM: - if (wrq->u.data.length != sizeof(BOOLEAN)) - Status = -EINVAL; - else - { - Status = copy_from_user(&pAdapter->CommonCfg.bWmmCapable, wrq->u.data.pointer, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_SET_WMM (=%d) \n", pAdapter->CommonCfg.bWmmCapable)); - } - break; - - case OID_802_11_DISASSOCIATE: -#ifdef RALINK_ATE - if (ATE_ON(pAdapter)) - { - DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now\n")); - break; - } -#endif // RALINK_ATE // - // - // Set NdisRadioStateOff to TRUE, instead of called MlmeRadioOff. - // Later on, NDIS_802_11_BSSID_LIST_EX->NumberOfItems should be 0 - // when query OID_802_11_BSSID_LIST. - // - // TRUE: NumberOfItems will set to 0. - // FALSE: NumberOfItems no change. - // - pAdapter->CommonCfg.NdisRadioStateOff = TRUE; - // Set to immediately send the media disconnect event - pAdapter->MlmeAux.CurrReqIsFromNdis = TRUE; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_DISASSOCIATE \n")); - - if (INFRA_ON(pAdapter)) - { - if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) - { - RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); - DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); - } - - MlmeEnqueue(pAdapter, - MLME_CNTL_STATE_MACHINE, - OID_802_11_DISASSOCIATE, - 0, - NULL); - - StateMachineTouched = TRUE; - } - break; - -#ifdef DOT11_N_SUPPORT - case RT_OID_802_11_SET_IMME_BA_CAP: - if (wrq->u.data.length != sizeof(OID_BACAP_STRUC)) - Status = -EINVAL; - else - { - OID_BACAP_STRUC Orde ; - Status = copy_from_user(&Orde, wrq->u.data.pointer, wrq->u.data.length); - if (Orde.Policy > BA_NOTUSE) - { - Status = NDIS_STATUS_INVALID_DATA; - } - else if (Orde.Policy == BA_NOTUSE) - { - pAdapter->CommonCfg.BACapability.field.Policy = BA_NOTUSE; - pAdapter->CommonCfg.BACapability.field.MpduDensity = Orde.MpduDensity; - pAdapter->CommonCfg.DesiredHtPhy.MpduDensity = Orde.MpduDensity; - pAdapter->CommonCfg.DesiredHtPhy.AmsduEnable = Orde.AmsduEnable; - pAdapter->CommonCfg.DesiredHtPhy.AmsduSize= Orde.AmsduSize; - pAdapter->CommonCfg.DesiredHtPhy.MimoPs= Orde.MMPSmode; - pAdapter->CommonCfg.BACapability.field.MMPSmode = Orde.MMPSmode; - // UPdata to HT IE - pAdapter->CommonCfg.HtCapability.HtCapInfo.MimoPs = Orde.MMPSmode; - pAdapter->CommonCfg.HtCapability.HtCapInfo.AMsduSize = Orde.AmsduSize; - pAdapter->CommonCfg.HtCapability.HtCapParm.MpduDensity = Orde.MpduDensity; - } - else - { - pAdapter->CommonCfg.BACapability.field.AutoBA = Orde.AutoBA; - pAdapter->CommonCfg.BACapability.field.Policy = IMMED_BA; // we only support immediate BA. - pAdapter->CommonCfg.BACapability.field.MpduDensity = Orde.MpduDensity; - pAdapter->CommonCfg.DesiredHtPhy.MpduDensity = Orde.MpduDensity; - pAdapter->CommonCfg.DesiredHtPhy.AmsduEnable = Orde.AmsduEnable; - pAdapter->CommonCfg.DesiredHtPhy.AmsduSize= Orde.AmsduSize; - pAdapter->CommonCfg.DesiredHtPhy.MimoPs = Orde.MMPSmode; - pAdapter->CommonCfg.BACapability.field.MMPSmode = Orde.MMPSmode; - - // UPdata to HT IE - pAdapter->CommonCfg.HtCapability.HtCapInfo.MimoPs = Orde.MMPSmode; - pAdapter->CommonCfg.HtCapability.HtCapInfo.AMsduSize = Orde.AmsduSize; - pAdapter->CommonCfg.HtCapability.HtCapParm.MpduDensity = Orde.MpduDensity; - - if (pAdapter->CommonCfg.BACapability.field.RxBAWinLimit > MAX_RX_REORDERBUF) - pAdapter->CommonCfg.BACapability.field.RxBAWinLimit = MAX_RX_REORDERBUF; - - } - - pAdapter->CommonCfg.REGBACapability.word = pAdapter->CommonCfg.BACapability.word; - DBGPRINT(RT_DEBUG_TRACE, ("Set::(Orde.AutoBA = %d) (Policy=%d)(ReBAWinLimit=%d)(TxBAWinLimit=%d)(AutoMode=%d)\n",Orde.AutoBA, pAdapter->CommonCfg.BACapability.field.Policy, - pAdapter->CommonCfg.BACapability.field.RxBAWinLimit,pAdapter->CommonCfg.BACapability.field.TxBAWinLimit, pAdapter->CommonCfg.BACapability.field.AutoBA)); - DBGPRINT(RT_DEBUG_TRACE, ("Set::(MimoPs = %d)(AmsduEnable = %d) (AmsduSize=%d)(MpduDensity=%d)\n",pAdapter->CommonCfg.DesiredHtPhy.MimoPs, pAdapter->CommonCfg.DesiredHtPhy.AmsduEnable, - pAdapter->CommonCfg.DesiredHtPhy.AmsduSize, pAdapter->CommonCfg.DesiredHtPhy.MpduDensity)); - } - - break; - case RT_OID_802_11_ADD_IMME_BA: - DBGPRINT(RT_DEBUG_TRACE, (" Set :: RT_OID_802_11_ADD_IMME_BA \n")); - if (wrq->u.data.length != sizeof(OID_ADD_BA_ENTRY)) - Status = -EINVAL; - else - { - UCHAR index; - OID_ADD_BA_ENTRY BA; - MAC_TABLE_ENTRY *pEntry; - - Status = copy_from_user(&BA, wrq->u.data.pointer, wrq->u.data.length); - if (BA.TID > 15) - { - Status = NDIS_STATUS_INVALID_DATA; - break; - } - else - { - //BATableInsertEntry - //As ad-hoc mode, BA pair is not limited to only BSSID. so add via OID. - index = BA.TID; - // in ad hoc mode, when adding BA pair, we should insert this entry into MACEntry too - pEntry = MacTableLookup(pAdapter, BA.MACAddr); - if (!pEntry) - { - DBGPRINT(RT_DEBUG_TRACE, ("RT_OID_802_11_ADD_IMME_BA. break on no connection.----:%x:%x\n", BA.MACAddr[4], BA.MACAddr[5])); - break; - } - if (BA.IsRecipient == FALSE) - { - if (pEntry->bIAmBadAtheros == TRUE) - pAdapter->CommonCfg.BACapability.field.RxBAWinLimit = 0x10; - - BAOriSessionSetUp(pAdapter, pEntry, index, 0, 100, TRUE); - } - else - { - //BATableInsertEntry(pAdapter, pEntry->Aid, BA.MACAddr, 0, 0xffff, BA.TID, BA.nMSDU, BA.IsRecipient); - } - - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_ADD_IMME_BA. Rec = %d. Mac = %x:%x:%x:%x:%x:%x . \n", - BA.IsRecipient, BA.MACAddr[0], BA.MACAddr[1], BA.MACAddr[2], BA.MACAddr[2] - , BA.MACAddr[4], BA.MACAddr[5])); - } - } - break; - - case RT_OID_802_11_TEAR_IMME_BA: - DBGPRINT(RT_DEBUG_TRACE, ("Set :: RT_OID_802_11_TEAR_IMME_BA \n")); - if (wrq->u.data.length != sizeof(OID_ADD_BA_ENTRY)) - Status = -EINVAL; - else - { - POID_ADD_BA_ENTRY pBA; - MAC_TABLE_ENTRY *pEntry; - - pBA = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); - - if (pBA == NULL) - { - DBGPRINT(RT_DEBUG_TRACE, ("Set :: RT_OID_802_11_TEAR_IMME_BA kmalloc() can't allocate enough memory\n")); - Status = NDIS_STATUS_FAILURE; - } - else - { - Status = copy_from_user(pBA, wrq->u.data.pointer, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Set :: RT_OID_802_11_TEAR_IMME_BA(TID=%d, bAllTid=%d)\n", pBA->TID, pBA->bAllTid)); - - if (!pBA->bAllTid && (pBA->TID > NUM_OF_TID)) - { - Status = NDIS_STATUS_INVALID_DATA; - break; - } - - if (pBA->IsRecipient == FALSE) - { - pEntry = MacTableLookup(pAdapter, pBA->MACAddr); - DBGPRINT(RT_DEBUG_TRACE, (" pBA->IsRecipient == FALSE\n")); - if (pEntry) - { - DBGPRINT(RT_DEBUG_TRACE, (" pBA->pEntry\n")); - BAOriSessionTearDown(pAdapter, pEntry->Aid, pBA->TID, FALSE, TRUE); - } - else - DBGPRINT(RT_DEBUG_TRACE, ("Set :: Not found pEntry \n")); - } - else - { - pEntry = MacTableLookup(pAdapter, pBA->MACAddr); - if (pEntry) - { - BARecSessionTearDown( pAdapter, (UCHAR)pEntry->Aid, pBA->TID, TRUE); - } - else - DBGPRINT(RT_DEBUG_TRACE, ("Set :: Not found pEntry \n")); - } - kfree(pBA); - } - } - break; -#endif // DOT11_N_SUPPORT // - - // For WPA_SUPPLICANT to set static wep key - case OID_802_11_ADD_WEP: - pWepKey = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); - - if(pWepKey == NULL) - { - Status = -ENOMEM; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_WEP, Failed!!\n")); - break; - } - Status = copy_from_user(pWepKey, wrq->u.data.pointer, wrq->u.data.length); - if (Status) - { - Status = -EINVAL; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_WEP, Failed (length mismatch)!!\n")); - } - else - { - KeyIdx = pWepKey->KeyIndex & 0x0fffffff; - // KeyIdx must be 0 ~ 3 - if (KeyIdx > 4) - { - Status = -EINVAL; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_WEP, Failed (KeyIdx must be smaller than 4)!!\n")); - } - else - { - UCHAR CipherAlg = 0; - PUCHAR Key; - - // set key material and key length - NdisZeroMemory(pAdapter->SharedKey[BSS0][KeyIdx].Key, 16); - pAdapter->SharedKey[BSS0][KeyIdx].KeyLen = (UCHAR) pWepKey->KeyLength; - NdisMoveMemory(pAdapter->SharedKey[BSS0][KeyIdx].Key, &pWepKey->KeyMaterial, pWepKey->KeyLength); - - switch(pWepKey->KeyLength) - { - case 5: - CipherAlg = CIPHER_WEP64; - break; - case 13: - CipherAlg = CIPHER_WEP128; - break; - default: - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_WEP, only support CIPHER_WEP64(len:5) & CIPHER_WEP128(len:13)!!\n")); - Status = -EINVAL; - break; - } - pAdapter->SharedKey[BSS0][KeyIdx].CipherAlg = CipherAlg; - - // Default key for tx (shared key) - if (pWepKey->KeyIndex & 0x80000000) - { -#ifdef WPA_SUPPLICANT_SUPPORT - // set key material and key length - NdisZeroMemory(pAdapter->StaCfg.DesireSharedKey[KeyIdx].Key, 16); - pAdapter->StaCfg.DesireSharedKey[KeyIdx].KeyLen = (UCHAR) pWepKey->KeyLength; - NdisMoveMemory(pAdapter->StaCfg.DesireSharedKey[KeyIdx].Key, &pWepKey->KeyMaterial, pWepKey->KeyLength); - pAdapter->StaCfg.DesireSharedKeyId = KeyIdx; - pAdapter->StaCfg.DesireSharedKey[KeyIdx].CipherAlg = CipherAlg; -#endif // WPA_SUPPLICANT_SUPPORT // - pAdapter->StaCfg.DefaultKeyId = (UCHAR) KeyIdx; - } - -#ifdef WPA_SUPPLICANT_SUPPORT - if (pAdapter->StaCfg.PortSecured == WPA_802_1X_PORT_SECURED) -#endif // WPA_SUPPLICANT_SUPPORT - { - Key = pAdapter->SharedKey[BSS0][KeyIdx].Key; - - // Set key material and cipherAlg to Asic - AsicAddSharedKeyEntry(pAdapter, BSS0, KeyIdx, CipherAlg, Key, NULL, NULL); - - if (pWepKey->KeyIndex & 0x80000000) - { - PMAC_TABLE_ENTRY pEntry = &pAdapter->MacTab.Content[BSSID_WCID]; - // Assign group key info - RTMPAddWcidAttributeEntry(pAdapter, BSS0, KeyIdx, CipherAlg, NULL); - // Assign pairwise key info - RTMPAddWcidAttributeEntry(pAdapter, BSS0, KeyIdx, CipherAlg, pEntry); - } - } - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_WEP (id=0x%x, Len=%d-byte), %s\n", pWepKey->KeyIndex, pWepKey->KeyLength, (pAdapter->StaCfg.PortSecured == WPA_802_1X_PORT_SECURED) ? "Port Secured":"Port NOT Secured")); - } - } - kfree(pWepKey); - break; -#ifdef WPA_SUPPLICANT_SUPPORT - case OID_SET_COUNTERMEASURES: - if (wrq->u.data.length != sizeof(int)) - Status = -EINVAL; - else - { - int enabled = 0; - Status = copy_from_user(&enabled, wrq->u.data.pointer, wrq->u.data.length); - if (enabled == 1) - pAdapter->StaCfg.bBlockAssoc = TRUE; - else - // WPA MIC error should block association attempt for 60 seconds - pAdapter->StaCfg.bBlockAssoc = FALSE; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_SET_COUNTERMEASURES bBlockAssoc=%s\n", pAdapter->StaCfg.bBlockAssoc ? "TRUE":"FALSE")); - } - break; - case RT_OID_WPA_SUPPLICANT_SUPPORT: - if (wrq->u.data.length != sizeof(UCHAR)) - Status = -EINVAL; - else - { - Status = copy_from_user(&wpa_supplicant_enable, wrq->u.data.pointer, wrq->u.data.length); - pAdapter->StaCfg.WpaSupplicantUP = wpa_supplicant_enable; - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_WPA_SUPPLICANT_SUPPORT (=%d)\n", pAdapter->StaCfg.WpaSupplicantUP)); - } - break; - case OID_802_11_DEAUTHENTICATION: - if (wrq->u.data.length != sizeof(MLME_DEAUTH_REQ_STRUCT)) - Status = -EINVAL; - else - { - MLME_DEAUTH_REQ_STRUCT *pInfo; - MLME_QUEUE_ELEM *MsgElem = (MLME_QUEUE_ELEM *) kmalloc(sizeof(MLME_QUEUE_ELEM), MEM_ALLOC_FLAG); - - pInfo = (MLME_DEAUTH_REQ_STRUCT *) MsgElem->Msg; - Status = copy_from_user(pInfo, wrq->u.data.pointer, wrq->u.data.length); - MlmeDeauthReqAction(pAdapter, MsgElem); - kfree(MsgElem); - - if (INFRA_ON(pAdapter)) - { - LinkDown(pAdapter, FALSE); - pAdapter->Mlme.AssocMachine.CurrState = ASSOC_IDLE; - } - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_DEAUTHENTICATION (Reason=%d)\n", pInfo->Reason)); - } - break; - case OID_802_11_DROP_UNENCRYPTED: - if (wrq->u.data.length != sizeof(int)) - Status = -EINVAL; - else - { - int enabled = 0; - Status = copy_from_user(&enabled, wrq->u.data.pointer, wrq->u.data.length); - if (enabled == 1) - pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; - else - pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; - NdisAcquireSpinLock(&pAdapter->MacTabLock); - pAdapter->MacTab.Content[BSSID_WCID].PortSecured = pAdapter->StaCfg.PortSecured; - NdisReleaseSpinLock(&pAdapter->MacTabLock); - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_DROP_UNENCRYPTED (=%d)\n", enabled)); - } - break; - case OID_802_11_SET_IEEE8021X: - if (wrq->u.data.length != sizeof(BOOLEAN)) - Status = -EINVAL; - else - { - Status = copy_from_user(&IEEE8021xState, wrq->u.data.pointer, wrq->u.data.length); - pAdapter->StaCfg.IEEE8021X = IEEE8021xState; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_SET_IEEE8021X (=%d)\n", IEEE8021xState)); - } - break; - case OID_802_11_SET_IEEE8021X_REQUIRE_KEY: - if (wrq->u.data.length != sizeof(BOOLEAN)) - Status = -EINVAL; - else - { - Status = copy_from_user(&IEEE8021x_required_keys, wrq->u.data.pointer, wrq->u.data.length); - pAdapter->StaCfg.IEEE8021x_required_keys = IEEE8021x_required_keys; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_SET_IEEE8021X_REQUIRE_KEY (%d)\n", IEEE8021x_required_keys)); - } - break; - case OID_802_11_PMKID: - pPmkId = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); - - if(pPmkId == NULL) { - Status = -ENOMEM; - break; - } - Status = copy_from_user(pPmkId, wrq->u.data.pointer, wrq->u.data.length); - - // check the PMKID information - if (pPmkId->BSSIDInfoCount == 0) - NdisZeroMemory(pAdapter->StaCfg.SavedPMK, sizeof(BSSID_INFO)*PMKID_NO); - else - { - PBSSID_INFO pBssIdInfo; - UINT BssIdx; - UINT CachedIdx; - - for (BssIdx = 0; BssIdx < pPmkId->BSSIDInfoCount; BssIdx++) - { - // point to the indexed BSSID_INFO structure - pBssIdInfo = (PBSSID_INFO) ((PUCHAR) pPmkId + 2 * sizeof(UINT) + BssIdx * sizeof(BSSID_INFO)); - // Find the entry in the saved data base. - for (CachedIdx = 0; CachedIdx < pAdapter->StaCfg.SavedPMKNum; CachedIdx++) - { - // compare the BSSID - if (NdisEqualMemory(pBssIdInfo->BSSID, pAdapter->StaCfg.SavedPMK[CachedIdx].BSSID, sizeof(NDIS_802_11_MAC_ADDRESS))) - break; - } - - // Found, replace it - if (CachedIdx < PMKID_NO) - { - DBGPRINT(RT_DEBUG_OFF, ("Update OID_802_11_PMKID, idx = %d\n", CachedIdx)); - NdisMoveMemory(&pAdapter->StaCfg.SavedPMK[CachedIdx], pBssIdInfo, sizeof(BSSID_INFO)); - pAdapter->StaCfg.SavedPMKNum++; - } - // Not found, replace the last one - else - { - // Randomly replace one - CachedIdx = (pBssIdInfo->BSSID[5] % PMKID_NO); - DBGPRINT(RT_DEBUG_OFF, ("Update OID_802_11_PMKID, idx = %d\n", CachedIdx)); - NdisMoveMemory(&pAdapter->StaCfg.SavedPMK[CachedIdx], pBssIdInfo, sizeof(BSSID_INFO)); - } - } - } - if(pPmkId) - kfree(pPmkId); - break; -#endif // WPA_SUPPLICANT_SUPPORT // - - - -#ifdef SNMP_SUPPORT - case OID_802_11_SHORTRETRYLIMIT: - if (wrq->u.data.length != sizeof(ULONG)) - Status = -EINVAL; - else - { - Status = copy_from_user(&ShortRetryLimit, wrq->u.data.pointer, wrq->u.data.length); - RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); - tx_rty_cfg.field.ShortRtyLimit = ShortRetryLimit; - RTMP_IO_WRITE32(pAdapter, TX_RTY_CFG, tx_rty_cfg.word); - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_SHORTRETRYLIMIT (tx_rty_cfg.field.ShortRetryLimit=%d, ShortRetryLimit=%ld)\n", tx_rty_cfg.field.ShortRtyLimit, ShortRetryLimit)); - } - break; - - case OID_802_11_LONGRETRYLIMIT: - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_LONGRETRYLIMIT \n")); - if (wrq->u.data.length != sizeof(ULONG)) - Status = -EINVAL; - else - { - Status = copy_from_user(&LongRetryLimit, wrq->u.data.pointer, wrq->u.data.length); - RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); - tx_rty_cfg.field.LongRtyLimit = LongRetryLimit; - RTMP_IO_WRITE32(pAdapter, TX_RTY_CFG, tx_rty_cfg.word); - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_LONGRETRYLIMIT (tx_rty_cfg.field.LongRetryLimit= %d,LongRetryLimit=%ld)\n", tx_rty_cfg.field.LongRtyLimit, LongRetryLimit)); - } - break; - - case OID_802_11_WEPDEFAULTKEYVALUE: - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_WEPDEFAULTKEYVALUE\n")); - pKey = kmalloc(wrq->u.data.length, GFP_KERNEL); - Status = copy_from_user(pKey, wrq->u.data.pointer, wrq->u.data.length); - //pKey = &WepKey; - - if ( pKey->Length != wrq->u.data.length) - { - Status = -EINVAL; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_WEPDEFAULTKEYVALUE, Failed!!\n")); - } - KeyIdx = pKey->KeyIndex & 0x0fffffff; - DBGPRINT(RT_DEBUG_TRACE,("pKey->KeyIndex =%d, pKey->KeyLength=%d\n", pKey->KeyIndex, pKey->KeyLength)); - - // it is a shared key - if (KeyIdx > 4) - Status = -EINVAL; - else - { - pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen = (UCHAR) pKey->KeyLength; - NdisMoveMemory(&pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].Key, &pKey->KeyMaterial, pKey->KeyLength); - if (pKey->KeyIndex & 0x80000000) - { - // Default key for tx (shared key) - pAdapter->StaCfg.DefaultKeyId = (UCHAR) KeyIdx; - } - //RestartAPIsRequired = TRUE; - } - break; - - - case OID_802_11_WEPDEFAULTKEYID: - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_WEPDEFAULTKEYID \n")); - - if (wrq->u.data.length != sizeof(UCHAR)) - Status = -EINVAL; - else - Status = copy_from_user(&pAdapter->StaCfg.DefaultKeyId, wrq->u.data.pointer, wrq->u.data.length); - - break; - - - case OID_802_11_CURRENTCHANNEL: - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_CURRENTCHANNEL \n")); - if (wrq->u.data.length != sizeof(UCHAR)) - Status = -EINVAL; - else - { - Status = copy_from_user(&ctmp, wrq->u.data.pointer, wrq->u.data.length); - sprintf(&ctmp,"%d", ctmp); - Set_Channel_Proc(pAdapter, &ctmp); - } - break; -#endif - - - - default: - DBGPRINT(RT_DEBUG_TRACE, ("Set::unknown IOCTL's subcmd = 0x%08x\n", cmd)); - Status = -EOPNOTSUPP; - break; - } - - - return Status; -} - -INT RTMPQueryInformation( - IN PRTMP_ADAPTER pAdapter, - IN OUT struct ifreq *rq, - IN INT cmd) -{ - struct iwreq *wrq = (struct iwreq *) rq; - NDIS_802_11_BSSID_LIST_EX *pBssidList = NULL; - PNDIS_WLAN_BSSID_EX pBss; - NDIS_802_11_SSID Ssid; - NDIS_802_11_CONFIGURATION *pConfiguration = NULL; - RT_802_11_LINK_STATUS *pLinkStatus = NULL; - RT_802_11_STA_CONFIG *pStaConfig = NULL; - NDIS_802_11_STATISTICS *pStatistics = NULL; - NDIS_802_11_RTS_THRESHOLD RtsThresh; - NDIS_802_11_FRAGMENTATION_THRESHOLD FragThresh; - NDIS_802_11_POWER_MODE PowerMode; - NDIS_802_11_NETWORK_INFRASTRUCTURE BssType; - RT_802_11_PREAMBLE PreamType; - NDIS_802_11_AUTHENTICATION_MODE AuthMode; - NDIS_802_11_WEP_STATUS WepStatus; - NDIS_MEDIA_STATE MediaState; - ULONG BssBufSize, ulInfo=0, NetworkTypeList[4], apsd = 0; - USHORT BssLen = 0; - PUCHAR pBuf = NULL, pPtr; - INT Status = NDIS_STATUS_SUCCESS; - UINT we_version_compiled; - UCHAR i, Padding = 0; - BOOLEAN RadioState; - UCHAR driverVersion[8]; - OID_SET_HT_PHYMODE *pHTPhyMode = NULL; - - -#ifdef SNMP_SUPPORT - //for snmp, kathy - DefaultKeyIdxValue *pKeyIdxValue; - INT valueLen; - TX_RTY_CFG_STRUC tx_rty_cfg; - ULONG ShortRetryLimit, LongRetryLimit; - UCHAR tmp[64]; -#endif //SNMP - - switch(cmd) - { - case RT_OID_DEVICE_NAME: - wrq->u.data.length = sizeof(STA_NIC_DEVICE_NAME); - Status = copy_to_user(wrq->u.data.pointer, STA_NIC_DEVICE_NAME, wrq->u.data.length); - break; - case RT_OID_VERSION_INFO: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_VERSION_INFO \n")); - wrq->u.data.length = 8*sizeof(UCHAR); - sprintf(&driverVersion[0], "%s", STA_DRIVER_VERSION); - driverVersion[7] = '\0'; - if (copy_to_user(wrq->u.data.pointer, &driverVersion, wrq->u.data.length)) - { - Status = -EFAULT; - } - break; -#ifdef RALINK_ATE - case RT_QUERY_ATE_TXDONE_COUNT: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_QUERY_ATE_TXDONE_COUNT \n")); - wrq->u.data.length = sizeof(UINT32); - if (copy_to_user(wrq->u.data.pointer, &pAdapter->ate.TxDoneCount, wrq->u.data.length)) - { - Status = -EFAULT; - } - break; -#endif // RALINK_ATE // - case OID_802_11_BSSID_LIST: - if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) - { - /* - * Still scanning, indicate the caller should try again. - */ - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_BSSID_LIST (Still scanning)\n")); - return -EAGAIN; - } - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_BSSID_LIST (%d BSS returned)\n",pAdapter->ScanTab.BssNr)); - pAdapter->StaCfg.bScanReqIsFromWebUI = FALSE; - // Claculate total buffer size required - BssBufSize = sizeof(ULONG); - - for (i = 0; i < pAdapter->ScanTab.BssNr; i++) - { - // Align pointer to 4 bytes boundary. - //Padding = 4 - (pAdapter->ScanTab.BssEntry[i].VarIELen & 0x0003); - //if (Padding == 4) - // Padding = 0; - BssBufSize += (sizeof(NDIS_WLAN_BSSID_EX) - 1 + sizeof(NDIS_802_11_FIXED_IEs) + pAdapter->ScanTab.BssEntry[i].VarIELen + Padding); - } - - // For safety issue, we add 256 bytes just in case - BssBufSize += 256; - // Allocate the same size as passed from higher layer - pBuf = kmalloc(BssBufSize, MEM_ALLOC_FLAG); - if(pBuf == NULL) - { - Status = -ENOMEM; - break; - } - // Init 802_11_BSSID_LIST_EX structure - NdisZeroMemory(pBuf, BssBufSize); - pBssidList = (PNDIS_802_11_BSSID_LIST_EX) pBuf; - pBssidList->NumberOfItems = pAdapter->ScanTab.BssNr; - - // Calculate total buffer length - BssLen = 4; // Consist of NumberOfItems - // Point to start of NDIS_WLAN_BSSID_EX - // pPtr = pBuf + sizeof(ULONG); - pPtr = (PUCHAR) &pBssidList->Bssid[0]; - for (i = 0; i < pAdapter->ScanTab.BssNr; i++) - { - pBss = (PNDIS_WLAN_BSSID_EX) pPtr; - NdisMoveMemory(&pBss->MacAddress, &pAdapter->ScanTab.BssEntry[i].Bssid, MAC_ADDR_LEN); - if ((pAdapter->ScanTab.BssEntry[i].Hidden == 1) && (pAdapter->StaCfg.bShowHiddenSSID == FALSE)) - { - // - // We must return this SSID during 4way handshaking, otherwise Aegis will failed to parse WPA infomation - // and then failed to send EAPOl farame. - // - if ((pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) && (pAdapter->StaCfg.PortSecured != WPA_802_1X_PORT_SECURED)) - { - pBss->Ssid.SsidLength = pAdapter->ScanTab.BssEntry[i].SsidLen; - NdisMoveMemory(pBss->Ssid.Ssid, pAdapter->ScanTab.BssEntry[i].Ssid, pAdapter->ScanTab.BssEntry[i].SsidLen); - } - else - pBss->Ssid.SsidLength = 0; - } - else - { - pBss->Ssid.SsidLength = pAdapter->ScanTab.BssEntry[i].SsidLen; - NdisMoveMemory(pBss->Ssid.Ssid, pAdapter->ScanTab.BssEntry[i].Ssid, pAdapter->ScanTab.BssEntry[i].SsidLen); - } - pBss->Privacy = pAdapter->ScanTab.BssEntry[i].Privacy; - pBss->Rssi = pAdapter->ScanTab.BssEntry[i].Rssi - pAdapter->BbpRssiToDbmDelta; - pBss->NetworkTypeInUse = NetworkTypeInUseSanity(&pAdapter->ScanTab.BssEntry[i]); - pBss->Configuration.Length = sizeof(NDIS_802_11_CONFIGURATION); - pBss->Configuration.BeaconPeriod = pAdapter->ScanTab.BssEntry[i].BeaconPeriod; - pBss->Configuration.ATIMWindow = pAdapter->ScanTab.BssEntry[i].AtimWin; - - MAP_CHANNEL_ID_TO_KHZ(pAdapter->ScanTab.BssEntry[i].Channel, pBss->Configuration.DSConfig); - - if (pAdapter->ScanTab.BssEntry[i].BssType == BSS_INFRA) - pBss->InfrastructureMode = Ndis802_11Infrastructure; - else - pBss->InfrastructureMode = Ndis802_11IBSS; - - NdisMoveMemory(pBss->SupportedRates, pAdapter->ScanTab.BssEntry[i].SupRate, pAdapter->ScanTab.BssEntry[i].SupRateLen); - NdisMoveMemory(pBss->SupportedRates + pAdapter->ScanTab.BssEntry[i].SupRateLen, - pAdapter->ScanTab.BssEntry[i].ExtRate, - pAdapter->ScanTab.BssEntry[i].ExtRateLen); - - if (pAdapter->ScanTab.BssEntry[i].VarIELen == 0) - { - pBss->IELength = sizeof(NDIS_802_11_FIXED_IEs); - NdisMoveMemory(pBss->IEs, &pAdapter->ScanTab.BssEntry[i].FixIEs, sizeof(NDIS_802_11_FIXED_IEs)); - pPtr = pPtr + sizeof(NDIS_WLAN_BSSID_EX) - 1 + sizeof(NDIS_802_11_FIXED_IEs); - } - else - { - pBss->IELength = (ULONG)(sizeof(NDIS_802_11_FIXED_IEs) + pAdapter->ScanTab.BssEntry[i].VarIELen); - pPtr = pPtr + sizeof(NDIS_WLAN_BSSID_EX) - 1 + sizeof(NDIS_802_11_FIXED_IEs); - NdisMoveMemory(pBss->IEs, &pAdapter->ScanTab.BssEntry[i].FixIEs, sizeof(NDIS_802_11_FIXED_IEs)); - NdisMoveMemory(pBss->IEs + sizeof(NDIS_802_11_FIXED_IEs), pAdapter->ScanTab.BssEntry[i].VarIEs, pAdapter->ScanTab.BssEntry[i].VarIELen); - pPtr += pAdapter->ScanTab.BssEntry[i].VarIELen; - } - pBss->Length = (ULONG)(sizeof(NDIS_WLAN_BSSID_EX) - 1 + sizeof(NDIS_802_11_FIXED_IEs) + pAdapter->ScanTab.BssEntry[i].VarIELen + Padding); - -#if WIRELESS_EXT < 17 - if ((BssLen + pBss->Length) < wrq->u.data.length) - BssLen += pBss->Length; - else - { - pBssidList->NumberOfItems = i; - break; - } -#else - BssLen += pBss->Length; -#endif - } - -#if WIRELESS_EXT < 17 - wrq->u.data.length = BssLen; -#else - if (BssLen > wrq->u.data.length) - { - kfree(pBssidList); - return -E2BIG; - } - else - wrq->u.data.length = BssLen; -#endif - Status = copy_to_user(wrq->u.data.pointer, pBssidList, BssLen); - kfree(pBssidList); - break; - case OID_802_3_CURRENT_ADDRESS: - wrq->u.data.length = MAC_ADDR_LEN; - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CurrentAddress, wrq->u.data.length); - break; - case OID_GEN_MEDIA_CONNECT_STATUS: - if (pAdapter->IndicateMediaState == NdisMediaStateConnected) - MediaState = NdisMediaStateConnected; - else - MediaState = NdisMediaStateDisconnected; - - wrq->u.data.length = sizeof(NDIS_MEDIA_STATE); - Status = copy_to_user(wrq->u.data.pointer, &MediaState, wrq->u.data.length); - break; - case OID_802_11_BSSID: -#ifdef RALINK_ATE - if (ATE_ON(pAdapter)) - { - DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now\n")); - Status = NDIS_STATUS_RESOURCES; - break; - } -#endif // RALINK_ATE // - if (INFRA_ON(pAdapter) || ADHOC_ON(pAdapter)) - { - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.Bssid, sizeof(NDIS_802_11_MAC_ADDRESS)); - - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_BSSID(=EMPTY)\n")); - Status = -ENOTCONN; - } - break; - case OID_802_11_SSID: - NdisZeroMemory(&Ssid, sizeof(NDIS_802_11_SSID)); - NdisZeroMemory(Ssid.Ssid, MAX_LEN_OF_SSID); - Ssid.SsidLength = pAdapter->CommonCfg.SsidLen; - memcpy(Ssid.Ssid, pAdapter->CommonCfg.Ssid, Ssid.SsidLength); - wrq->u.data.length = sizeof(NDIS_802_11_SSID); - Status = copy_to_user(wrq->u.data.pointer, &Ssid, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_SSID (Len=%d, ssid=%s)\n", Ssid.SsidLength,Ssid.Ssid)); - break; - case RT_OID_802_11_QUERY_LINK_STATUS: - pLinkStatus = (RT_802_11_LINK_STATUS *) kmalloc(sizeof(RT_802_11_LINK_STATUS), MEM_ALLOC_FLAG); - if (pLinkStatus) - { - pLinkStatus->CurrTxRate = RateIdTo500Kbps[pAdapter->CommonCfg.TxRate]; // unit : 500 kbps - pLinkStatus->ChannelQuality = pAdapter->Mlme.ChannelQuality; - pLinkStatus->RxByteCount = pAdapter->RalinkCounters.ReceivedByteCount; - pLinkStatus->TxByteCount = pAdapter->RalinkCounters.TransmittedByteCount; - pLinkStatus->CentralChannel = pAdapter->CommonCfg.CentralChannel; - wrq->u.data.length = sizeof(RT_802_11_LINK_STATUS); - Status = copy_to_user(wrq->u.data.pointer, pLinkStatus, wrq->u.data.length); - kfree(pLinkStatus); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_LINK_STATUS\n")); - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_LINK_STATUS(kmalloc failed)\n")); - Status = -EFAULT; - } - break; - case OID_802_11_CONFIGURATION: - pConfiguration = (NDIS_802_11_CONFIGURATION *) kmalloc(sizeof(NDIS_802_11_CONFIGURATION), MEM_ALLOC_FLAG); - if (pConfiguration) - { - pConfiguration->Length = sizeof(NDIS_802_11_CONFIGURATION); - pConfiguration->BeaconPeriod = pAdapter->CommonCfg.BeaconPeriod; - pConfiguration->ATIMWindow = pAdapter->StaActive.AtimWin; - MAP_CHANNEL_ID_TO_KHZ(pAdapter->CommonCfg.Channel, pConfiguration->DSConfig); - wrq->u.data.length = sizeof(NDIS_802_11_CONFIGURATION); - Status = copy_to_user(wrq->u.data.pointer, pConfiguration, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_CONFIGURATION(BeaconPeriod=%ld,AtimW=%ld,Channel=%d) \n", - pConfiguration->BeaconPeriod, pConfiguration->ATIMWindow, pAdapter->CommonCfg.Channel)); - kfree(pConfiguration); - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_CONFIGURATION(kmalloc failed)\n")); - Status = -EFAULT; - } - break; - case RT_OID_802_11_SNR_0: - if ((pAdapter->StaCfg.LastSNR0 > 0)) - { - ulInfo = ((0xeb - pAdapter->StaCfg.LastSNR0) * 3) / 16 ; - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_SNR_0(0x=%lx)\n", ulInfo)); - } - else - Status = -EFAULT; - break; - case RT_OID_802_11_SNR_1: - if ((pAdapter->Antenna.field.RxPath > 1) && - (pAdapter->StaCfg.LastSNR1 > 0)) - { - ulInfo = ((0xeb - pAdapter->StaCfg.LastSNR1) * 3) / 16 ; - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE,("Query::RT_OID_802_11_SNR_1(0x=%lx)\n",ulInfo)); - } - else - Status = -EFAULT; - DBGPRINT(RT_DEBUG_TRACE,("Query::RT_OID_802_11_SNR_1(pAdapter->StaCfg.LastSNR1=%d)\n",pAdapter->StaCfg.LastSNR1)); - break; - case OID_802_11_RSSI_TRIGGER: - ulInfo = pAdapter->StaCfg.RssiSample.LastRssi0 - pAdapter->BbpRssiToDbmDelta; - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_RSSI_TRIGGER(=%ld)\n", ulInfo)); - break; - case OID_802_11_RSSI: - case RT_OID_802_11_RSSI: - ulInfo = pAdapter->StaCfg.RssiSample.LastRssi0; - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - break; - case RT_OID_802_11_RSSI_1: - ulInfo = pAdapter->StaCfg.RssiSample.LastRssi1; - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - break; - case RT_OID_802_11_RSSI_2: - ulInfo = pAdapter->StaCfg.RssiSample.LastRssi2; - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - break; - case OID_802_11_STATISTICS: - pStatistics = (NDIS_802_11_STATISTICS *) kmalloc(sizeof(NDIS_802_11_STATISTICS), MEM_ALLOC_FLAG); - if (pStatistics) - { - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_STATISTICS \n")); - // add the most up-to-date h/w raw counters into software counters - NICUpdateRawCounters(pAdapter); - - // Sanity check for calculation of sucessful count - if (pAdapter->WlanCounters.TransmittedFragmentCount.QuadPart < pAdapter->WlanCounters.RetryCount.QuadPart) - pAdapter->WlanCounters.TransmittedFragmentCount.QuadPart = pAdapter->WlanCounters.RetryCount.QuadPart; - - pStatistics->TransmittedFragmentCount.QuadPart = pAdapter->WlanCounters.TransmittedFragmentCount.QuadPart; - pStatistics->MulticastTransmittedFrameCount.QuadPart = pAdapter->WlanCounters.MulticastTransmittedFrameCount.QuadPart; - pStatistics->FailedCount.QuadPart = pAdapter->WlanCounters.FailedCount.QuadPart; - pStatistics->RetryCount.QuadPart = pAdapter->WlanCounters.RetryCount.QuadPart; - pStatistics->MultipleRetryCount.QuadPart = pAdapter->WlanCounters.MultipleRetryCount.QuadPart; - pStatistics->RTSSuccessCount.QuadPart = pAdapter->WlanCounters.RTSSuccessCount.QuadPart; - pStatistics->RTSFailureCount.QuadPart = pAdapter->WlanCounters.RTSFailureCount.QuadPart; - pStatistics->ACKFailureCount.QuadPart = pAdapter->WlanCounters.ACKFailureCount.QuadPart; - pStatistics->FrameDuplicateCount.QuadPart = pAdapter->WlanCounters.FrameDuplicateCount.QuadPart; - pStatistics->ReceivedFragmentCount.QuadPart = pAdapter->WlanCounters.ReceivedFragmentCount.QuadPart; - pStatistics->MulticastReceivedFrameCount.QuadPart = pAdapter->WlanCounters.MulticastReceivedFrameCount.QuadPart; -#ifdef DBG - pStatistics->FCSErrorCount = pAdapter->RalinkCounters.RealFcsErrCount; -#else - pStatistics->FCSErrorCount.QuadPart = pAdapter->WlanCounters.FCSErrorCount.QuadPart; - pStatistics->FrameDuplicateCount.u.LowPart = pAdapter->WlanCounters.FrameDuplicateCount.u.LowPart / 100; -#endif - wrq->u.data.length = sizeof(NDIS_802_11_STATISTICS); - Status = copy_to_user(wrq->u.data.pointer, pStatistics, wrq->u.data.length); - kfree(pStatistics); - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_STATISTICS(kmalloc failed)\n")); - Status = -EFAULT; - } - break; - case OID_GEN_RCV_OK: - ulInfo = pAdapter->Counters8023.GoodReceives; - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - break; - case OID_GEN_RCV_NO_BUFFER: - ulInfo = pAdapter->Counters8023.RxNoBuffer; - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - break; - case RT_OID_802_11_PHY_MODE: - ulInfo = (ULONG)pAdapter->CommonCfg.PhyMode; - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_PHY_MODE (=%ld)\n", ulInfo)); - break; - case RT_OID_802_11_STA_CONFIG: - pStaConfig = (RT_802_11_STA_CONFIG *) kmalloc(sizeof(RT_802_11_STA_CONFIG), MEM_ALLOC_FLAG); - if (pStaConfig) - { - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_STA_CONFIG\n")); - pStaConfig->EnableTxBurst = pAdapter->CommonCfg.bEnableTxBurst; - pStaConfig->EnableTurboRate = 0; - pStaConfig->UseBGProtection = pAdapter->CommonCfg.UseBGProtection; - pStaConfig->UseShortSlotTime = pAdapter->CommonCfg.bUseShortSlotTime; - //pStaConfig->AdhocMode = pAdapter->StaCfg.AdhocMode; - pStaConfig->HwRadioStatus = (pAdapter->StaCfg.bHwRadio == TRUE) ? 1 : 0; - pStaConfig->Rsv1 = 0; - pStaConfig->SystemErrorBitmap = pAdapter->SystemErrorBitmap; - wrq->u.data.length = sizeof(RT_802_11_STA_CONFIG); - Status = copy_to_user(wrq->u.data.pointer, pStaConfig, wrq->u.data.length); - kfree(pStaConfig); - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_STA_CONFIG(kmalloc failed)\n")); - Status = -EFAULT; - } - break; - case OID_802_11_RTS_THRESHOLD: - RtsThresh = pAdapter->CommonCfg.RtsThreshold; - wrq->u.data.length = sizeof(RtsThresh); - Status = copy_to_user(wrq->u.data.pointer, &RtsThresh, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_RTS_THRESHOLD(=%ld)\n", RtsThresh)); - break; - case OID_802_11_FRAGMENTATION_THRESHOLD: - FragThresh = pAdapter->CommonCfg.FragmentThreshold; - if (pAdapter->CommonCfg.bUseZeroToDisableFragment == TRUE) - FragThresh = 0; - wrq->u.data.length = sizeof(FragThresh); - Status = copy_to_user(wrq->u.data.pointer, &FragThresh, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_FRAGMENTATION_THRESHOLD(=%ld)\n", FragThresh)); - break; - case OID_802_11_POWER_MODE: - PowerMode = pAdapter->StaCfg.WindowsPowerMode; - wrq->u.data.length = sizeof(PowerMode); - Status = copy_to_user(wrq->u.data.pointer, &PowerMode, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_POWER_MODE(=%d)\n", PowerMode)); - break; - case RT_OID_802_11_RADIO: - RadioState = (BOOLEAN) pAdapter->StaCfg.bSwRadio; - wrq->u.data.length = sizeof(RadioState); - Status = copy_to_user(wrq->u.data.pointer, &RadioState, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_RADIO (=%d)\n", RadioState)); - break; - case OID_802_11_INFRASTRUCTURE_MODE: - if (pAdapter->StaCfg.BssType == BSS_ADHOC) - BssType = Ndis802_11IBSS; - else if (pAdapter->StaCfg.BssType == BSS_INFRA) - BssType = Ndis802_11Infrastructure; - else if (pAdapter->StaCfg.BssType == BSS_MONITOR) - BssType = Ndis802_11Monitor; - else - BssType = Ndis802_11AutoUnknown; - - wrq->u.data.length = sizeof(BssType); - Status = copy_to_user(wrq->u.data.pointer, &BssType, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_INFRASTRUCTURE_MODE(=%d)\n", BssType)); - break; - case RT_OID_802_11_PREAMBLE: - PreamType = pAdapter->CommonCfg.TxPreamble; - wrq->u.data.length = sizeof(PreamType); - Status = copy_to_user(wrq->u.data.pointer, &PreamType, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_PREAMBLE(=%d)\n", PreamType)); - break; - case OID_802_11_AUTHENTICATION_MODE: - AuthMode = pAdapter->StaCfg.AuthMode; - wrq->u.data.length = sizeof(AuthMode); - Status = copy_to_user(wrq->u.data.pointer, &AuthMode, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_AUTHENTICATION_MODE(=%d)\n", AuthMode)); - break; - case OID_802_11_WEP_STATUS: - WepStatus = pAdapter->StaCfg.WepStatus; - wrq->u.data.length = sizeof(WepStatus); - Status = copy_to_user(wrq->u.data.pointer, &WepStatus, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_WEP_STATUS(=%d)\n", WepStatus)); - break; - case OID_802_11_TX_POWER_LEVEL: - wrq->u.data.length = sizeof(ULONG); - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.TxPower, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_TX_POWER_LEVEL %x\n",pAdapter->CommonCfg.TxPower)); - break; - case RT_OID_802_11_TX_POWER_LEVEL_1: - wrq->u.data.length = sizeof(ULONG); - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.TxPowerPercentage, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_TX_POWER_LEVEL_1 (=%ld)\n", pAdapter->CommonCfg.TxPowerPercentage)); - break; - case OID_802_11_NETWORK_TYPES_SUPPORTED: - if ((pAdapter->RfIcType == RFIC_2850) || (pAdapter->RfIcType == RFIC_2750)) - { - NetworkTypeList[0] = 3; // NumberOfItems = 3 - NetworkTypeList[1] = Ndis802_11DS; // NetworkType[1] = 11b - NetworkTypeList[2] = Ndis802_11OFDM24; // NetworkType[2] = 11g - NetworkTypeList[3] = Ndis802_11OFDM5; // NetworkType[3] = 11a - wrq->u.data.length = 16; - Status = copy_to_user(wrq->u.data.pointer, &NetworkTypeList[0], wrq->u.data.length); - } - else - { - NetworkTypeList[0] = 2; // NumberOfItems = 2 - NetworkTypeList[1] = Ndis802_11DS; // NetworkType[1] = 11b - NetworkTypeList[2] = Ndis802_11OFDM24; // NetworkType[2] = 11g - wrq->u.data.length = 12; - Status = copy_to_user(wrq->u.data.pointer, &NetworkTypeList[0], wrq->u.data.length); - } - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_NETWORK_TYPES_SUPPORTED\n")); - break; - case OID_802_11_NETWORK_TYPE_IN_USE: - wrq->u.data.length = sizeof(ULONG); - if (pAdapter->CommonCfg.PhyMode == PHY_11A) - ulInfo = Ndis802_11OFDM5; - else if ((pAdapter->CommonCfg.PhyMode == PHY_11BG_MIXED) || (pAdapter->CommonCfg.PhyMode == PHY_11G)) - ulInfo = Ndis802_11OFDM24; - else - ulInfo = Ndis802_11DS; - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - break; - case RT_OID_802_11_QUERY_LAST_RX_RATE: - ulInfo = (ULONG)pAdapter->LastRxRate; - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_LAST_RX_RATE (=%ld)\n", ulInfo)); - break; - case RT_OID_802_11_QUERY_LAST_TX_RATE: - //ulInfo = (ULONG)pAdapter->LastTxRate; - ulInfo = (ULONG)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.word; - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_LAST_TX_RATE (=%lx)\n", ulInfo)); - break; - case RT_OID_802_11_QUERY_EEPROM_VERSION: - wrq->u.data.length = sizeof(ULONG); - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->EepromVersion, wrq->u.data.length); - break; - case RT_OID_802_11_QUERY_FIRMWARE_VERSION: - wrq->u.data.length = sizeof(ULONG); - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->FirmwareVersion, wrq->u.data.length); - break; - case RT_OID_802_11_QUERY_NOISE_LEVEL: - wrq->u.data.length = sizeof(UCHAR); - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->BbpWriteLatch[66], wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_NOISE_LEVEL (=%d)\n", pAdapter->BbpWriteLatch[66])); - break; - case RT_OID_802_11_EXTRA_INFO: - wrq->u.data.length = sizeof(ULONG); - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->ExtraInfo, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_EXTRA_INFO (=%ld)\n", pAdapter->ExtraInfo)); - break; - case RT_OID_WE_VERSION_COMPILED: - wrq->u.data.length = sizeof(UINT); - we_version_compiled = WIRELESS_EXT; - Status = copy_to_user(wrq->u.data.pointer, &we_version_compiled, wrq->u.data.length); - break; - case RT_OID_802_11_QUERY_APSD_SETTING: - apsd = (pAdapter->CommonCfg.bAPSDCapable | (pAdapter->CommonCfg.bAPSDAC_BE << 1) | (pAdapter->CommonCfg.bAPSDAC_BK << 2) - | (pAdapter->CommonCfg.bAPSDAC_VI << 3) | (pAdapter->CommonCfg.bAPSDAC_VO << 4) | (pAdapter->CommonCfg.MaxSPLength << 5)); - - wrq->u.data.length = sizeof(ULONG); - Status = copy_to_user(wrq->u.data.pointer, &apsd, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_APSD_SETTING (=0x%lx,APSDCap=%d,AC_BE=%d,AC_BK=%d,AC_VI=%d,AC_VO=%d,MAXSPLen=%d)\n", - apsd,pAdapter->CommonCfg.bAPSDCapable,pAdapter->CommonCfg.bAPSDAC_BE,pAdapter->CommonCfg.bAPSDAC_BK,pAdapter->CommonCfg.bAPSDAC_VI,pAdapter->CommonCfg.bAPSDAC_VO,pAdapter->CommonCfg.MaxSPLength)); - break; - case RT_OID_802_11_QUERY_APSD_PSM: - wrq->u.data.length = sizeof(ULONG); - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.bAPSDForcePowerSave, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_APSD_PSM (=%d)\n", pAdapter->CommonCfg.bAPSDForcePowerSave)); - break; - case RT_OID_802_11_QUERY_WMM: - wrq->u.data.length = sizeof(BOOLEAN); - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.bWmmCapable, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_WMM (=%d)\n", pAdapter->CommonCfg.bWmmCapable)); - break; -#ifdef WPA_SUPPLICANT_SUPPORT - case RT_OID_NEW_DRIVER: - { - UCHAR enabled = 1; - wrq->u.data.length = sizeof(UCHAR); - Status = copy_to_user(wrq->u.data.pointer, &enabled, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_NEW_DRIVER (=%d)\n", enabled)); - } - break; - case RT_OID_WPA_SUPPLICANT_SUPPORT: - wrq->u.data.length = sizeof(UCHAR); - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->StaCfg.WpaSupplicantUP, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_WPA_SUPPLICANT_SUPPORT (=%d)\n", pAdapter->StaCfg.WpaSupplicantUP)); - break; -#endif // WPA_SUPPLICANT_SUPPORT // - - case RT_OID_DRIVER_DEVICE_NAME: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_DRIVER_DEVICE_NAME \n")); - wrq->u.data.length = 16; - if (copy_to_user(wrq->u.data.pointer, pAdapter->StaCfg.dev_name, wrq->u.data.length)) - { - Status = -EFAULT; - } - break; - case RT_OID_802_11_QUERY_HT_PHYMODE: - pHTPhyMode = (OID_SET_HT_PHYMODE *) kmalloc(sizeof(OID_SET_HT_PHYMODE), MEM_ALLOC_FLAG); - if (pHTPhyMode) - { - pHTPhyMode->PhyMode = pAdapter->CommonCfg.PhyMode; - pHTPhyMode->HtMode = (UCHAR)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.field.MODE; - pHTPhyMode->BW = (UCHAR)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.field.BW; - pHTPhyMode->MCS= (UCHAR)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.field.MCS; - pHTPhyMode->SHORTGI= (UCHAR)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.field.ShortGI; - pHTPhyMode->STBC= (UCHAR)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.field.STBC; - - pHTPhyMode->ExtOffset = ((pAdapter->CommonCfg.CentralChannel < pAdapter->CommonCfg.Channel) ? (EXTCHA_BELOW) : (EXTCHA_ABOVE)); - wrq->u.data.length = sizeof(OID_SET_HT_PHYMODE); - if (copy_to_user(wrq->u.data.pointer, pHTPhyMode, wrq->u.data.length)) - { - Status = -EFAULT; - } - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_HT_PHYMODE (PhyMode = %d, MCS =%d, BW = %d, STBC = %d, ExtOffset=%d)\n", - pHTPhyMode->HtMode, pHTPhyMode->MCS, pHTPhyMode->BW, pHTPhyMode->STBC, pHTPhyMode->ExtOffset)); - DBGPRINT(RT_DEBUG_TRACE, (" MlmeUpdateTxRates (.word = %x )\n", pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.word)); - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_STA_CONFIG(kmalloc failed)\n")); - Status = -EFAULT; - } - break; - case RT_OID_802_11_COUNTRY_REGION: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_COUNTRY_REGION \n")); - wrq->u.data.length = sizeof(ulInfo); - ulInfo = pAdapter->CommonCfg.CountryRegionForABand; - ulInfo = (ulInfo << 8)|(pAdapter->CommonCfg.CountryRegion); - if (copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length)) - { - Status = -EFAULT; - } - break; - case RT_OID_802_11_QUERY_DAT_HT_PHYMODE: - pHTPhyMode = (OID_SET_HT_PHYMODE *) kmalloc(sizeof(OID_SET_HT_PHYMODE), MEM_ALLOC_FLAG); - if (pHTPhyMode) - { - pHTPhyMode->PhyMode = pAdapter->CommonCfg.PhyMode; - pHTPhyMode->HtMode = (UCHAR)pAdapter->CommonCfg.RegTransmitSetting.field.HTMODE; - pHTPhyMode->BW = (UCHAR)pAdapter->CommonCfg.RegTransmitSetting.field.BW; - pHTPhyMode->MCS= (UCHAR)pAdapter->StaCfg.DesiredTransmitSetting.field.MCS; - pHTPhyMode->SHORTGI= (UCHAR)pAdapter->CommonCfg.RegTransmitSetting.field.ShortGI; - pHTPhyMode->STBC= (UCHAR)pAdapter->CommonCfg.RegTransmitSetting.field.STBC; - - wrq->u.data.length = sizeof(OID_SET_HT_PHYMODE); - if (copy_to_user(wrq->u.data.pointer, pHTPhyMode, wrq->u.data.length)) - { - Status = -EFAULT; - } - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_HT_PHYMODE (PhyMode = %d, MCS =%d, BW = %d, STBC = %d, ExtOffset=%d)\n", - pHTPhyMode->HtMode, pHTPhyMode->MCS, pHTPhyMode->BW, pHTPhyMode->STBC, pHTPhyMode->ExtOffset)); - DBGPRINT(RT_DEBUG_TRACE, (" MlmeUpdateTxRates (.word = %x )\n", pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.word)); - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_STA_CONFIG(kmalloc failed)\n")); - Status = -EFAULT; - } - break; - case RT_OID_QUERY_MULTIPLE_CARD_SUPPORT: - wrq->u.data.length = sizeof(UCHAR); - i = 0; -#ifdef MULTIPLE_CARD_SUPPORT - i = 1; -#endif // MULTIPLE_CARD_SUPPORT // - if (copy_to_user(wrq->u.data.pointer, &i, wrq->u.data.length)) - { - Status = -EFAULT; - } - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_QUERY_MULTIPLE_CARD_SUPPORT(=%d) \n", i)); - break; -#ifdef SNMP_SUPPORT - case RT_OID_802_11_MAC_ADDRESS: - wrq->u.data.length = MAC_ADDR_LEN; - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CurrentAddress, wrq->u.data.length); - break; - - case RT_OID_802_11_MANUFACTUREROUI: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_MANUFACTUREROUI \n")); - wrq->u.data.length = ManufacturerOUI_LEN; - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CurrentAddress, wrq->u.data.length); - break; - - case RT_OID_802_11_MANUFACTURERNAME: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_MANUFACTURERNAME \n")); - wrq->u.data.length = strlen(ManufacturerNAME); - Status = copy_to_user(wrq->u.data.pointer, ManufacturerNAME, wrq->u.data.length); - break; - - case RT_OID_802_11_RESOURCETYPEIDNAME: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_RESOURCETYPEIDNAME \n")); - wrq->u.data.length = strlen(ResourceTypeIdName); - Status = copy_to_user(wrq->u.data.pointer, ResourceTypeIdName, wrq->u.data.length); - break; - - case RT_OID_802_11_PRIVACYOPTIONIMPLEMENTED: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_PRIVACYOPTIONIMPLEMENTED \n")); - ulInfo = 1; // 1 is support wep else 2 is not support. - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - break; - - case RT_OID_802_11_POWERMANAGEMENTMODE: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_POWERMANAGEMENTMODE \n")); - if (pAdapter->StaCfg.Psm == PSMP_ACTION) - ulInfo = 1; // 1 is power active else 2 is power save. - else - ulInfo = 2; - - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - break; - - case OID_802_11_WEPDEFAULTKEYVALUE: - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_WEPDEFAULTKEYVALUE \n")); - //KeyIdxValue.KeyIdx = pAd->PortCfg.MBSSID[pAd->IoctlIF].DefaultKeyId; - pKeyIdxValue = wrq->u.data.pointer; - DBGPRINT(RT_DEBUG_TRACE,("KeyIdxValue.KeyIdx = %d, \n",pKeyIdxValue->KeyIdx)); - valueLen = pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen; - NdisMoveMemory(pKeyIdxValue->Value, - &pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].Key, - valueLen); - pKeyIdxValue->Value[valueLen]='\0'; - - wrq->u.data.length = sizeof(DefaultKeyIdxValue); - - Status = copy_to_user(wrq->u.data.pointer, pKeyIdxValue, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE,("DefaultKeyId = %d, total len = %d, str len=%d, KeyValue= %02x %02x %02x %02x \n", pAdapter->StaCfg.DefaultKeyId, wrq->u.data.length, pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen, - pAdapter->SharedKey[BSS0][0].Key[0], - pAdapter->SharedKey[BSS0][1].Key[0], - pAdapter->SharedKey[BSS0][2].Key[0], - pAdapter->SharedKey[BSS0][3].Key[0])); - break; - - case OID_802_11_WEPDEFAULTKEYID: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_WEPDEFAULTKEYID \n")); - wrq->u.data.length = sizeof(UCHAR); - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->StaCfg.DefaultKeyId, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("DefaultKeyId =%d \n", pAdapter->StaCfg.DefaultKeyId)); - break; - - case RT_OID_802_11_WEPKEYMAPPINGLENGTH: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_WEPKEYMAPPINGLENGTH \n")); - wrq->u.data.length = sizeof(UCHAR); - Status = copy_to_user(wrq->u.data.pointer, - &pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen, - wrq->u.data.length); - break; - - case OID_802_11_SHORTRETRYLIMIT: - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_SHORTRETRYLIMIT \n")); - wrq->u.data.length = sizeof(ULONG); - RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); - ShortRetryLimit = tx_rty_cfg.field.ShortRtyLimit; - DBGPRINT(RT_DEBUG_TRACE, ("ShortRetryLimit =%ld, tx_rty_cfg.field.ShortRetryLimit=%d\n", ShortRetryLimit, tx_rty_cfg.field.ShortRtyLimit)); - Status = copy_to_user(wrq->u.data.pointer, &ShortRetryLimit, wrq->u.data.length); - break; - - case OID_802_11_LONGRETRYLIMIT: - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_LONGRETRYLIMIT \n")); - wrq->u.data.length = sizeof(ULONG); - RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); - LongRetryLimit = tx_rty_cfg.field.LongRtyLimit; - DBGPRINT(RT_DEBUG_TRACE, ("LongRetryLimit =%ld, tx_rty_cfg.field.LongRtyLimit=%d\n", LongRetryLimit, tx_rty_cfg.field.LongRtyLimit)); - Status = copy_to_user(wrq->u.data.pointer, &LongRetryLimit, wrq->u.data.length); - break; - - case RT_OID_802_11_PRODUCTID: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_PRODUCTID \n")); - -#ifdef RT2870 - sprintf(tmp, "%04x %04x\n", ((POS_COOKIE)pAdapter->OS_Cookie)->pUsb_Dev->descriptor.idVendor ,((POS_COOKIE)pAdapter->OS_Cookie)->pUsb_Dev->descriptor.idProduct); - -#endif // RT2870 // - wrq->u.data.length = strlen(tmp); - Status = copy_to_user(wrq->u.data.pointer, tmp, wrq->u.data.length); - break; - - case RT_OID_802_11_MANUFACTUREID: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_MANUFACTUREID \n")); - wrq->u.data.length = strlen(ManufacturerNAME); - Status = copy_to_user(wrq->u.data.pointer, ManufacturerNAME, wrq->u.data.length); - break; - - case OID_802_11_CURRENTCHANNEL: - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_CURRENTCHANNEL \n")); - wrq->u.data.length = sizeof(UCHAR); - DBGPRINT(RT_DEBUG_TRACE, ("sizeof UCHAR=%d, channel=%d \n", sizeof(UCHAR), pAdapter->CommonCfg.Channel)); - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.Channel, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Status=%d\n", Status)); - break; -#endif //SNMP_SUPPORT - - case OID_802_11_BUILD_CHANNEL_EX: - { - UCHAR value; - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_BUILD_CHANNEL_EX \n")); - wrq->u.data.length = sizeof(UCHAR); -#ifdef EXT_BUILD_CHANNEL_LIST - DBGPRINT(RT_DEBUG_TRACE, ("Support EXT_BUILD_CHANNEL_LIST.\n")); - value = 1; -#else - DBGPRINT(RT_DEBUG_TRACE, ("Doesn't support EXT_BUILD_CHANNEL_LIST.\n")); - value = 0; -#endif // EXT_BUILD_CHANNEL_LIST // - Status = copy_to_user(wrq->u.data.pointer, &value, 1); - DBGPRINT(RT_DEBUG_TRACE, ("Status=%d\n", Status)); - } - break; - - case OID_802_11_GET_CH_LIST: - { - PRT_CHANNEL_LIST_INFO pChListBuf; - - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_GET_CH_LIST \n")); - if (pAdapter->ChannelListNum == 0) - { - wrq->u.data.length = 0; - break; - } - - pChListBuf = (RT_CHANNEL_LIST_INFO *) kmalloc(sizeof(RT_CHANNEL_LIST_INFO), MEM_ALLOC_FLAG); - if (pChListBuf == NULL) - { - wrq->u.data.length = 0; - break; - } - - pChListBuf->ChannelListNum = pAdapter->ChannelListNum; - for (i = 0; i < pChListBuf->ChannelListNum; i++) - pChListBuf->ChannelList[i] = pAdapter->ChannelList[i].Channel; - - wrq->u.data.length = sizeof(RT_CHANNEL_LIST_INFO); - Status = copy_to_user(wrq->u.data.pointer, pChListBuf, sizeof(RT_CHANNEL_LIST_INFO)); - DBGPRINT(RT_DEBUG_TRACE, ("Status=%d\n", Status)); - - if (pChListBuf) - kfree(pChListBuf); - } - break; - - case OID_802_11_GET_COUNTRY_CODE: - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_GET_COUNTRY_CODE \n")); - wrq->u.data.length = 2; - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.CountryCode, 2); - DBGPRINT(RT_DEBUG_TRACE, ("Status=%d\n", Status)); - break; - - case OID_802_11_GET_CHANNEL_GEOGRAPHY: - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_GET_CHANNEL_GEOGRAPHY \n")); - wrq->u.data.length = 1; - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.Geography, 1); - DBGPRINT(RT_DEBUG_TRACE, ("Status=%d\n", Status)); - break; - - -#ifdef QOS_DLS_SUPPORT - case RT_OID_802_11_QUERY_DLS: - wrq->u.data.length = sizeof(BOOLEAN); - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.bDLSCapable, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_DLS(=%d)\n", pAdapter->CommonCfg.bDLSCapable)); - break; - - case RT_OID_802_11_QUERY_DLS_PARAM: - { - PRT_802_11_DLS_INFO pDlsInfo = kmalloc(sizeof(RT_802_11_DLS_INFO), GFP_ATOMIC); - if (pDlsInfo == NULL) - break; - - for (i=0; iEntry[i], &pAdapter->StaCfg.DLSEntry[i], sizeof(RT_802_11_DLS_UI)); - } - - pDlsInfo->num = MAX_NUM_OF_DLS_ENTRY; - wrq->u.data.length = sizeof(RT_802_11_DLS_INFO); - Status = copy_to_user(wrq->u.data.pointer, pDlsInfo, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_DLS_PARAM\n")); - - if (pDlsInfo) - kfree(pDlsInfo); - } - break; -#endif // QOS_DLS_SUPPORT // - default: - DBGPRINT(RT_DEBUG_TRACE, ("Query::unknown IOCTL's subcmd = 0x%08x\n", cmd)); - Status = -EOPNOTSUPP; - break; - } - return Status; -} - -INT rt28xx_sta_ioctl( - IN struct net_device *net_dev, - IN OUT struct ifreq *rq, - IN INT cmd) -{ - POS_COOKIE pObj; - VIRTUAL_ADAPTER *pVirtualAd = NULL; - RTMP_ADAPTER *pAd = NULL; - struct iwreq *wrq = (struct iwreq *) rq; - BOOLEAN StateMachineTouched = FALSE; - INT Status = NDIS_STATUS_SUCCESS; - USHORT subcmd; - - if (net_dev->priv_flags == INT_MAIN) - { - pAd = net_dev->priv; - } - else - { - pVirtualAd = net_dev->priv; - pAd = pVirtualAd->RtmpDev->priv; - } - pObj = (POS_COOKIE) pAd->OS_Cookie; - - if (pAd == NULL) - { - /* if 1st open fail, pAd will be free; - So the net_dev->priv will be NULL in 2rd open */ - return -ENETDOWN; - } - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { -#ifdef CONFIG_APSTA_MIXED_SUPPORT - if (wrq->u.data.pointer == NULL) - { - return Status; - } - - if (strstr(wrq->u.data.pointer, "OpMode") == NULL) -#endif // CONFIG_APSTA_MIXED_SUPPORT // - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - } - - { // determine this ioctl command is comming from which interface. - pObj->ioctl_if_type = INT_MAIN; - pObj->ioctl_if = MAIN_MBSSID; - } - - switch(cmd) - { -#ifdef RALINK_ATE -#ifdef RALINK_28xx_QA - case RTPRIV_IOCTL_ATE: - { - RtmpDoAte(pAd, wrq); - } - break; -#endif // RALINK_28xx_QA // -#endif // RALINK_ATE // - case SIOCGIFHWADDR: - DBGPRINT(RT_DEBUG_TRACE, ("IOCTL::SIOCGIFHWADDR\n")); - memcpy(wrq->u.name, pAd->CurrentAddress, ETH_ALEN); - break; - case SIOCGIWNAME: - { - char *name=&wrq->u.name[0]; - rt_ioctl_giwname(net_dev, NULL, name, NULL); - break; - } - case SIOCGIWESSID: //Get ESSID - { - struct iw_point *essid=&wrq->u.essid; - rt_ioctl_giwessid(net_dev, NULL, essid, essid->pointer); - break; - } - case SIOCSIWESSID: //Set ESSID - { - struct iw_point *essid=&wrq->u.essid; - rt_ioctl_siwessid(net_dev, NULL, essid, essid->pointer); - break; - } - case SIOCSIWNWID: // set network id (the cell) - case SIOCGIWNWID: // get network id - Status = -EOPNOTSUPP; - break; - case SIOCSIWFREQ: //set channel/frequency (Hz) - { - struct iw_freq *freq=&wrq->u.freq; - rt_ioctl_siwfreq(net_dev, NULL, freq, NULL); - break; - } - case SIOCGIWFREQ: // get channel/frequency (Hz) - { - struct iw_freq *freq=&wrq->u.freq; - rt_ioctl_giwfreq(net_dev, NULL, freq, NULL); - break; - } - case SIOCSIWNICKN: //set node name/nickname - { - struct iw_point *data=&wrq->u.data; - rt_ioctl_siwnickn(net_dev, NULL, data, NULL); - break; - } - case SIOCGIWNICKN: //get node name/nickname - { - struct iw_point *data=&wrq->u.data; - rt_ioctl_giwnickn(net_dev, NULL, data, NULL); - break; - } - case SIOCGIWRATE: //get default bit rate (bps) - rt_ioctl_giwrate(net_dev, NULL, &wrq->u, NULL); - break; - case SIOCSIWRATE: //set default bit rate (bps) - rt_ioctl_siwrate(net_dev, NULL, &wrq->u, NULL); - break; - case SIOCGIWRTS: // get RTS/CTS threshold (bytes) - { - struct iw_param *rts=&wrq->u.rts; - rt_ioctl_giwrts(net_dev, NULL, rts, NULL); - break; - } - case SIOCSIWRTS: //set RTS/CTS threshold (bytes) - { - struct iw_param *rts=&wrq->u.rts; - rt_ioctl_siwrts(net_dev, NULL, rts, NULL); - break; - } - case SIOCGIWFRAG: //get fragmentation thr (bytes) - { - struct iw_param *frag=&wrq->u.frag; - rt_ioctl_giwfrag(net_dev, NULL, frag, NULL); - break; - } - case SIOCSIWFRAG: //set fragmentation thr (bytes) - { - struct iw_param *frag=&wrq->u.frag; - rt_ioctl_siwfrag(net_dev, NULL, frag, NULL); - break; - } - case SIOCGIWENCODE: //get encoding token & mode - { - struct iw_point *erq=&wrq->u.encoding; - if(erq->pointer) - rt_ioctl_giwencode(net_dev, NULL, erq, erq->pointer); - break; - } - case SIOCSIWENCODE: //set encoding token & mode - { - struct iw_point *erq=&wrq->u.encoding; - if(erq->pointer) - rt_ioctl_siwencode(net_dev, NULL, erq, erq->pointer); - break; - } - case SIOCGIWAP: //get access point MAC addresses - { - struct sockaddr *ap_addr=&wrq->u.ap_addr; - rt_ioctl_giwap(net_dev, NULL, ap_addr, ap_addr->sa_data); - break; - } - case SIOCSIWAP: //set access point MAC addresses - { - struct sockaddr *ap_addr=&wrq->u.ap_addr; - rt_ioctl_siwap(net_dev, NULL, ap_addr, ap_addr->sa_data); - break; - } - case SIOCGIWMODE: //get operation mode - { - __u32 *mode=&wrq->u.mode; - rt_ioctl_giwmode(net_dev, NULL, mode, NULL); - break; - } - case SIOCSIWMODE: //set operation mode - { - __u32 *mode=&wrq->u.mode; - rt_ioctl_siwmode(net_dev, NULL, mode, NULL); - break; - } - case SIOCGIWSENS: //get sensitivity (dBm) - case SIOCSIWSENS: //set sensitivity (dBm) - case SIOCGIWPOWER: //get Power Management settings - case SIOCSIWPOWER: //set Power Management settings - case SIOCGIWTXPOW: //get transmit power (dBm) - case SIOCSIWTXPOW: //set transmit power (dBm) - case SIOCGIWRANGE: //Get range of parameters - case SIOCGIWRETRY: //get retry limits and lifetime - case SIOCSIWRETRY: //set retry limits and lifetime - Status = -EOPNOTSUPP; - break; - case RT_PRIV_IOCTL: - subcmd = wrq->u.data.flags; - if( subcmd & OID_GET_SET_TOGGLE) - Status = RTMPSetInformation(pAd, rq, subcmd); - else - Status = RTMPQueryInformation(pAd, rq, subcmd); - break; - case SIOCGIWPRIV: - if (wrq->u.data.pointer) - { - if ( access_ok(VERIFY_WRITE, wrq->u.data.pointer, sizeof(privtab)) != TRUE) - break; - wrq->u.data.length = sizeof(privtab) / sizeof(privtab[0]); - if (copy_to_user(wrq->u.data.pointer, privtab, sizeof(privtab))) - Status = -EFAULT; - } - break; - case RTPRIV_IOCTL_SET: - if(access_ok(VERIFY_READ, wrq->u.data.pointer, wrq->u.data.length) != TRUE) - break; - rt_ioctl_setparam(net_dev, NULL, NULL, wrq->u.data.pointer); - break; - case RTPRIV_IOCTL_GSITESURVEY: - RTMPIoctlGetSiteSurvey(pAd, wrq); - break; -#ifdef DBG - case RTPRIV_IOCTL_MAC: - RTMPIoctlMAC(pAd, wrq); - break; - case RTPRIV_IOCTL_E2P: - RTMPIoctlE2PROM(pAd, wrq); - break; -#endif // DBG // - case SIOCETHTOOL: - break; - default: - DBGPRINT(RT_DEBUG_ERROR, ("IOCTL::unknown IOCTL's cmd = 0x%08x\n", cmd)); - Status = -EOPNOTSUPP; - break; - } - - if(StateMachineTouched) // Upper layer sent a MLME-related operations - RT28XX_MLME_HANDLER(pAd); - - return Status; -} - -/* - ========================================================================== - Description: - Set SSID - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_SSID_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - NDIS_802_11_SSID Ssid, *pSsid=NULL; - BOOLEAN StateMachineTouched = FALSE; - int success = TRUE; - - if( strlen(arg) <= MAX_LEN_OF_SSID) - { - NdisZeroMemory(&Ssid, sizeof(NDIS_802_11_SSID)); - if (strlen(arg) != 0) - { - NdisMoveMemory(Ssid.Ssid, arg, strlen(arg)); - Ssid.SsidLength = strlen(arg); - } - else //ANY ssid - { - Ssid.SsidLength = 0; - memcpy(Ssid.Ssid, "", 0); - pAdapter->StaCfg.BssType = BSS_INFRA; - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; - pAdapter->StaCfg.WepStatus = Ndis802_11EncryptionDisabled; - } - pSsid = &Ssid; - - if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) - { - RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); - DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); - } - - pAdapter->MlmeAux.CurrReqIsFromNdis = TRUE; - pAdapter->StaCfg.bScanReqIsFromWebUI = FALSE; - pAdapter->bConfigChanged = TRUE; - - MlmeEnqueue(pAdapter, - MLME_CNTL_STATE_MACHINE, - OID_802_11_SSID, - sizeof(NDIS_802_11_SSID), - (VOID *)pSsid); - - StateMachineTouched = TRUE; - DBGPRINT(RT_DEBUG_TRACE, ("Set_SSID_Proc::(Len=%d,Ssid=%s)\n", Ssid.SsidLength, Ssid.Ssid)); - } - else - success = FALSE; - - if (StateMachineTouched) // Upper layer sent a MLME-related operations - RT28XX_MLME_HANDLER(pAdapter); - - return success; -} - -#ifdef WMM_SUPPORT -/* - ========================================================================== - Description: - Set WmmCapable Enable or Disable - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_WmmCapable_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - BOOLEAN bWmmCapable; - - bWmmCapable = simple_strtol(arg, 0, 10); - - if ((bWmmCapable == 1) -#ifdef RT2870 - && (pAd->NumberOfPipes >= 5) -#endif // RT2870 // - ) - pAd->CommonCfg.bWmmCapable = TRUE; - else if (bWmmCapable == 0) - pAd->CommonCfg.bWmmCapable = FALSE; - else - return FALSE; //Invalid argument - - DBGPRINT(RT_DEBUG_TRACE, ("Set_WmmCapable_Proc::(bWmmCapable=%d)\n", - pAd->CommonCfg.bWmmCapable)); - - return TRUE; -} -#endif // WMM_SUPPORT // - -/* - ========================================================================== - Description: - Set Network Type(Infrastructure/Adhoc mode) - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_NetworkType_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - UINT32 Value = 0; - - if (strcmp(arg, "Adhoc") == 0) - { - if (pAdapter->StaCfg.BssType != BSS_ADHOC) - { - // Config has changed - pAdapter->bConfigChanged = TRUE; - if (MONITOR_ON(pAdapter)) - { - RTMP_IO_WRITE32(pAdapter, RX_FILTR_CFG, STANORMAL); - RTMP_IO_READ32(pAdapter, MAC_SYS_CTRL, &Value); - Value &= (~0x80); - RTMP_IO_WRITE32(pAdapter, MAC_SYS_CTRL, Value); - OPSTATUS_CLEAR_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED); - pAdapter->StaCfg.bAutoReconnect = TRUE; - LinkDown(pAdapter, FALSE); - } - if (INFRA_ON(pAdapter)) - { - //BOOLEAN Cancelled; - // Set the AutoReconnectSsid to prevent it reconnect to old SSID - // Since calling this indicate user don't want to connect to that SSID anymore. - pAdapter->MlmeAux.AutoReconnectSsidLen= 32; - NdisZeroMemory(pAdapter->MlmeAux.AutoReconnectSsid, pAdapter->MlmeAux.AutoReconnectSsidLen); - - LinkDown(pAdapter, FALSE); - - DBGPRINT(RT_DEBUG_TRACE, ("NDIS_STATUS_MEDIA_DISCONNECT Event BB!\n")); - } - } - pAdapter->StaCfg.BssType = BSS_ADHOC; - pAdapter->net_dev->type = pAdapter->StaCfg.OriDevType; - DBGPRINT(RT_DEBUG_TRACE, ("===>Set_NetworkType_Proc::(AD-HOC)\n")); - } - else if (strcmp(arg, "Infra") == 0) - { - if (pAdapter->StaCfg.BssType != BSS_INFRA) - { - // Config has changed - pAdapter->bConfigChanged = TRUE; - if (MONITOR_ON(pAdapter)) - { - RTMP_IO_WRITE32(pAdapter, RX_FILTR_CFG, STANORMAL); - RTMP_IO_READ32(pAdapter, MAC_SYS_CTRL, &Value); - Value &= (~0x80); - RTMP_IO_WRITE32(pAdapter, MAC_SYS_CTRL, Value); - OPSTATUS_CLEAR_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED); - pAdapter->StaCfg.bAutoReconnect = TRUE; - LinkDown(pAdapter, FALSE); - } - if (ADHOC_ON(pAdapter)) - { - // Set the AutoReconnectSsid to prevent it reconnect to old SSID - // Since calling this indicate user don't want to connect to that SSID anymore. - pAdapter->MlmeAux.AutoReconnectSsidLen= 32; - NdisZeroMemory(pAdapter->MlmeAux.AutoReconnectSsid, pAdapter->MlmeAux.AutoReconnectSsidLen); - - LinkDown(pAdapter, FALSE); - } - } - pAdapter->StaCfg.BssType = BSS_INFRA; - pAdapter->net_dev->type = pAdapter->StaCfg.OriDevType; - DBGPRINT(RT_DEBUG_TRACE, ("===>Set_NetworkType_Proc::(INFRA)\n")); - - pAdapter->StaCfg.BssType = BSS_INFRA; - } - else if (strcmp(arg, "Monitor") == 0) - { - UCHAR bbpValue = 0; - BCN_TIME_CFG_STRUC csr; - OPSTATUS_CLEAR_FLAG(pAdapter, fOP_STATUS_INFRA_ON); - OPSTATUS_CLEAR_FLAG(pAdapter, fOP_STATUS_ADHOC_ON); - OPSTATUS_SET_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED); - // disable all periodic state machine - pAdapter->StaCfg.bAutoReconnect = FALSE; - // reset all mlme state machine - RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); - DBGPRINT(RT_DEBUG_TRACE, ("fOP_STATUS_MEDIA_STATE_CONNECTED \n")); - if (pAdapter->CommonCfg.CentralChannel == 0) - { -#ifdef DOT11_N_SUPPORT - if (pAdapter->CommonCfg.PhyMode == PHY_11AN_MIXED) - pAdapter->CommonCfg.CentralChannel = 36; - else -#endif // DOT11_N_SUPPORT // - pAdapter->CommonCfg.CentralChannel = 6; - } -#ifdef DOT11_N_SUPPORT - else - N_ChannelCheck(pAdapter); -#endif // DOT11_N_SUPPORT // - -#ifdef DOT11_N_SUPPORT - if (pAdapter->CommonCfg.PhyMode >= PHY_11ABGN_MIXED && - pAdapter->CommonCfg.RegTransmitSetting.field.BW == BW_40 && - pAdapter->CommonCfg.RegTransmitSetting.field.EXTCHA == EXTCHA_ABOVE) - { - // 40MHz ,control channel at lower - RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, BBP_R4, &bbpValue); - bbpValue &= (~0x18); - bbpValue |= 0x10; - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R4, bbpValue); - pAdapter->CommonCfg.BBPCurrentBW = BW_40; - // RX : control channel at lower - RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, BBP_R3, &bbpValue); - bbpValue &= (~0x20); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R3, bbpValue); - - RTMP_IO_READ32(pAdapter, TX_BAND_CFG, &Value); - Value &= 0xfffffffe; - RTMP_IO_WRITE32(pAdapter, TX_BAND_CFG, Value); - pAdapter->CommonCfg.CentralChannel = pAdapter->CommonCfg.Channel + 2; - AsicSwitchChannel(pAdapter, pAdapter->CommonCfg.CentralChannel, FALSE); - AsicLockChannel(pAdapter, pAdapter->CommonCfg.CentralChannel); - DBGPRINT(RT_DEBUG_TRACE, ("BW_40 ,control_channel(%d), CentralChannel(%d) \n", - pAdapter->CommonCfg.Channel, - pAdapter->CommonCfg.CentralChannel)); - } - else if (pAdapter->CommonCfg.PhyMode >= PHY_11ABGN_MIXED && - pAdapter->CommonCfg.RegTransmitSetting.field.BW == BW_40 && - pAdapter->CommonCfg.RegTransmitSetting.field.EXTCHA == EXTCHA_BELOW) - { - // 40MHz ,control channel at upper - RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, BBP_R4, &bbpValue); - bbpValue &= (~0x18); - bbpValue |= 0x10; - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R4, bbpValue); - pAdapter->CommonCfg.BBPCurrentBW = BW_40; - RTMP_IO_READ32(pAdapter, TX_BAND_CFG, &Value); - Value |= 0x1; - RTMP_IO_WRITE32(pAdapter, TX_BAND_CFG, Value); - - RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, BBP_R3, &bbpValue); - bbpValue |= (0x20); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R3, bbpValue); - pAdapter->CommonCfg.CentralChannel = pAdapter->CommonCfg.Channel - 2; - AsicSwitchChannel(pAdapter, pAdapter->CommonCfg.CentralChannel, FALSE); - AsicLockChannel(pAdapter, pAdapter->CommonCfg.CentralChannel); - DBGPRINT(RT_DEBUG_TRACE, ("BW_40 ,control_channel(%d), CentralChannel(%d) \n", - pAdapter->CommonCfg.Channel, - pAdapter->CommonCfg.CentralChannel)); - } - else -#endif // DOT11_N_SUPPORT // - { - // 20MHz - RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, BBP_R4, &bbpValue); - bbpValue &= (~0x18); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R4, bbpValue); - pAdapter->CommonCfg.BBPCurrentBW = BW_20; - AsicSwitchChannel(pAdapter, pAdapter->CommonCfg.Channel, FALSE); - AsicLockChannel(pAdapter, pAdapter->CommonCfg.Channel); - DBGPRINT(RT_DEBUG_TRACE, ("BW_20, Channel(%d)\n", pAdapter->CommonCfg.Channel)); - } - // Enable Rx with promiscuous reception - RTMP_IO_WRITE32(pAdapter, RX_FILTR_CFG, 0x3); - // ASIC supporsts sniffer function with replacing RSSI with timestamp. - //RTMP_IO_READ32(pAdapter, MAC_SYS_CTRL, &Value); - //Value |= (0x80); - //RTMP_IO_WRITE32(pAdapter, MAC_SYS_CTRL, Value); - // disable sync - RTMP_IO_READ32(pAdapter, BCN_TIME_CFG, &csr.word); - csr.field.bBeaconGen = 0; - csr.field.bTBTTEnable = 0; - csr.field.TsfSyncMode = 0; - RTMP_IO_WRITE32(pAdapter, BCN_TIME_CFG, csr.word); - - pAdapter->StaCfg.BssType = BSS_MONITOR; - pAdapter->net_dev->type = ARPHRD_IEEE80211_PRISM; //ARPHRD_IEEE80211; // IEEE80211 - DBGPRINT(RT_DEBUG_TRACE, ("===>Set_NetworkType_Proc::(MONITOR)\n")); - } - - // Reset Ralink supplicant to not use, it will be set to start when UI set PMK key - pAdapter->StaCfg.WpaState = SS_NOTUSE; - - DBGPRINT(RT_DEBUG_TRACE, ("Set_NetworkType_Proc::(NetworkType=%d)\n", pAdapter->StaCfg.BssType)); - - return TRUE; -} - -/* - ========================================================================== - Description: - Set Authentication mode - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_AuthMode_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - if ((strcmp(arg, "WEPAUTO") == 0) || (strcmp(arg, "wepauto") == 0)) - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeAutoSwitch; - else if ((strcmp(arg, "OPEN") == 0) || (strcmp(arg, "open") == 0)) - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; - else if ((strcmp(arg, "SHARED") == 0) || (strcmp(arg, "shared") == 0)) - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeShared; - else if ((strcmp(arg, "WPAPSK") == 0) || (strcmp(arg, "wpapsk") == 0)) - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPAPSK; - else if ((strcmp(arg, "WPANONE") == 0) || (strcmp(arg, "wpanone") == 0)) - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPANone; - else if ((strcmp(arg, "WPA2PSK") == 0) || (strcmp(arg, "wpa2psk") == 0)) - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA2PSK; -#ifdef WPA_SUPPLICANT_SUPPORT - else if ((strcmp(arg, "WPA") == 0) || (strcmp(arg, "wpa") == 0)) - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA; - else if ((strcmp(arg, "WPA2") == 0) || (strcmp(arg, "wpa2") == 0)) - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA2; -#endif // WPA_SUPPLICANT_SUPPORT // - else - return FALSE; - - pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; - - DBGPRINT(RT_DEBUG_TRACE, ("Set_AuthMode_Proc::(AuthMode=%d)\n", pAdapter->StaCfg.AuthMode)); - - return TRUE; -} - -/* - ========================================================================== - Description: - Set Encryption Type - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_EncrypType_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - if ((strcmp(arg, "NONE") == 0) || (strcmp(arg, "none") == 0)) - { - if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - return TRUE; // do nothing - - pAdapter->StaCfg.WepStatus = Ndis802_11WEPDisabled; - pAdapter->StaCfg.PairCipher = Ndis802_11WEPDisabled; - pAdapter->StaCfg.GroupCipher = Ndis802_11WEPDisabled; - } - else if ((strcmp(arg, "WEP") == 0) || (strcmp(arg, "wep") == 0)) - { - if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - return TRUE; // do nothing - - pAdapter->StaCfg.WepStatus = Ndis802_11WEPEnabled; - pAdapter->StaCfg.PairCipher = Ndis802_11WEPEnabled; - pAdapter->StaCfg.GroupCipher = Ndis802_11WEPEnabled; - } - else if ((strcmp(arg, "TKIP") == 0) || (strcmp(arg, "tkip") == 0)) - { - if (pAdapter->StaCfg.AuthMode < Ndis802_11AuthModeWPA) - return TRUE; // do nothing - - pAdapter->StaCfg.WepStatus = Ndis802_11Encryption2Enabled; - pAdapter->StaCfg.PairCipher = Ndis802_11Encryption2Enabled; - pAdapter->StaCfg.GroupCipher = Ndis802_11Encryption2Enabled; - } - else if ((strcmp(arg, "AES") == 0) || (strcmp(arg, "aes") == 0)) - { - if (pAdapter->StaCfg.AuthMode < Ndis802_11AuthModeWPA) - return TRUE; // do nothing - - pAdapter->StaCfg.WepStatus = Ndis802_11Encryption3Enabled; - pAdapter->StaCfg.PairCipher = Ndis802_11Encryption3Enabled; - pAdapter->StaCfg.GroupCipher = Ndis802_11Encryption3Enabled; - } - else - return FALSE; - - pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; - - DBGPRINT(RT_DEBUG_TRACE, ("Set_EncrypType_Proc::(EncrypType=%d)\n", pAdapter->StaCfg.WepStatus)); - - return TRUE; -} - -/* - ========================================================================== - Description: - Set Default Key ID - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_DefaultKeyID_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - ULONG KeyIdx; - - KeyIdx = simple_strtol(arg, 0, 10); - if((KeyIdx >= 1 ) && (KeyIdx <= 4)) - pAdapter->StaCfg.DefaultKeyId = (UCHAR) (KeyIdx - 1 ); - else - return FALSE; //Invalid argument - - DBGPRINT(RT_DEBUG_TRACE, ("Set_DefaultKeyID_Proc::(DefaultKeyID=%d)\n", pAdapter->StaCfg.DefaultKeyId)); - - return TRUE; -} - -/* - ========================================================================== - Description: - Set WEP KEY1 - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_Key1_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - int KeyLen; - int i; - UCHAR CipherAlg=CIPHER_WEP64; - - if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - return TRUE; // do nothing - - KeyLen = strlen(arg); - - switch (KeyLen) - { - case 5: //wep 40 Ascii type - pAdapter->SharedKey[BSS0][0].KeyLen = KeyLen; - memcpy(pAdapter->SharedKey[BSS0][0].Key, arg, KeyLen); - CipherAlg = CIPHER_WEP64; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key1_Proc::(Key1=%s and type=%s)\n", arg, "Ascii")); - break; - case 10: //wep 40 Hex type - for(i=0; i < KeyLen; i++) - { - if( !isxdigit(*(arg+i)) ) - return FALSE; //Not Hex value; - } - pAdapter->SharedKey[BSS0][0].KeyLen = KeyLen / 2 ; - AtoH(arg, pAdapter->SharedKey[BSS0][0].Key, KeyLen / 2); - CipherAlg = CIPHER_WEP64; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key1_Proc::(Key1=%s and type=%s)\n", arg, "Hex")); - break; - case 13: //wep 104 Ascii type - pAdapter->SharedKey[BSS0][0].KeyLen = KeyLen; - memcpy(pAdapter->SharedKey[BSS0][0].Key, arg, KeyLen); - CipherAlg = CIPHER_WEP128; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key1_Proc::(Key1=%s and type=%s)\n", arg, "Ascii")); - break; - case 26: //wep 104 Hex type - for(i=0; i < KeyLen; i++) - { - if( !isxdigit(*(arg+i)) ) - return FALSE; //Not Hex value; - } - pAdapter->SharedKey[BSS0][0].KeyLen = KeyLen / 2 ; - AtoH(arg, pAdapter->SharedKey[BSS0][0].Key, KeyLen / 2); - CipherAlg = CIPHER_WEP128; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key1_Proc::(Key1=%s and type=%s)\n", arg, "Hex")); - break; - default: //Invalid argument - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key1_Proc::Invalid argument (=%s)\n", arg)); - return FALSE; - } - - pAdapter->SharedKey[BSS0][0].CipherAlg = CipherAlg; - - // Set keys (into ASIC) - if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - ; // not support - else // Old WEP stuff - { - AsicAddSharedKeyEntry(pAdapter, - 0, - 0, - pAdapter->SharedKey[BSS0][0].CipherAlg, - pAdapter->SharedKey[BSS0][0].Key, - NULL, - NULL); - } - - return TRUE; -} -/* - ========================================================================== - - Description: - Set WEP KEY2 - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_Key2_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - int KeyLen; - int i; - UCHAR CipherAlg=CIPHER_WEP64; - - if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - return TRUE; // do nothing - - KeyLen = strlen(arg); - - switch (KeyLen) - { - case 5: //wep 40 Ascii type - pAdapter->SharedKey[BSS0][1].KeyLen = KeyLen; - memcpy(pAdapter->SharedKey[BSS0][1].Key, arg, KeyLen); - CipherAlg = CIPHER_WEP64; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key2_Proc::(Key2=%s and type=%s)\n", arg, "Ascii")); - break; - case 10: //wep 40 Hex type - for(i=0; i < KeyLen; i++) - { - if( !isxdigit(*(arg+i)) ) - return FALSE; //Not Hex value; - } - pAdapter->SharedKey[BSS0][1].KeyLen = KeyLen / 2 ; - AtoH(arg, pAdapter->SharedKey[BSS0][1].Key, KeyLen / 2); - CipherAlg = CIPHER_WEP64; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key2_Proc::(Key2=%s and type=%s)\n", arg, "Hex")); - break; - case 13: //wep 104 Ascii type - pAdapter->SharedKey[BSS0][1].KeyLen = KeyLen; - memcpy(pAdapter->SharedKey[BSS0][1].Key, arg, KeyLen); - CipherAlg = CIPHER_WEP128; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key2_Proc::(Key2=%s and type=%s)\n", arg, "Ascii")); - break; - case 26: //wep 104 Hex type - for(i=0; i < KeyLen; i++) - { - if( !isxdigit(*(arg+i)) ) - return FALSE; //Not Hex value; - } - pAdapter->SharedKey[BSS0][1].KeyLen = KeyLen / 2 ; - AtoH(arg, pAdapter->SharedKey[BSS0][1].Key, KeyLen / 2); - CipherAlg = CIPHER_WEP128; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key2_Proc::(Key2=%s and type=%s)\n", arg, "Hex")); - break; - default: //Invalid argument - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key2_Proc::Invalid argument (=%s)\n", arg)); - return FALSE; - } - pAdapter->SharedKey[BSS0][1].CipherAlg = CipherAlg; - - // Set keys (into ASIC) - if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - ; // not support - else // Old WEP stuff - { - AsicAddSharedKeyEntry(pAdapter, - 0, - 1, - pAdapter->SharedKey[BSS0][1].CipherAlg, - pAdapter->SharedKey[BSS0][1].Key, - NULL, - NULL); - } - - return TRUE; -} -/* - ========================================================================== - Description: - Set WEP KEY3 - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_Key3_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - int KeyLen; - int i; - UCHAR CipherAlg=CIPHER_WEP64; - - if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - return TRUE; // do nothing - - KeyLen = strlen(arg); - - switch (KeyLen) - { - case 5: //wep 40 Ascii type - pAdapter->SharedKey[BSS0][2].KeyLen = KeyLen; - memcpy(pAdapter->SharedKey[BSS0][2].Key, arg, KeyLen); - CipherAlg = CIPHER_WEP64; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key3_Proc::(Key3=%s and type=Ascii)\n", arg)); - break; - case 10: //wep 40 Hex type - for(i=0; i < KeyLen; i++) - { - if( !isxdigit(*(arg+i)) ) - return FALSE; //Not Hex value; - } - pAdapter->SharedKey[BSS0][2].KeyLen = KeyLen / 2 ; - AtoH(arg, pAdapter->SharedKey[BSS0][2].Key, KeyLen / 2); - CipherAlg = CIPHER_WEP64; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key3_Proc::(Key3=%s and type=Hex)\n", arg)); - break; - case 13: //wep 104 Ascii type - pAdapter->SharedKey[BSS0][2].KeyLen = KeyLen; - memcpy(pAdapter->SharedKey[BSS0][2].Key, arg, KeyLen); - CipherAlg = CIPHER_WEP128; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key3_Proc::(Key3=%s and type=Ascii)\n", arg)); - break; - case 26: //wep 104 Hex type - for(i=0; i < KeyLen; i++) - { - if( !isxdigit(*(arg+i)) ) - return FALSE; //Not Hex value; - } - pAdapter->SharedKey[BSS0][2].KeyLen = KeyLen / 2 ; - AtoH(arg, pAdapter->SharedKey[BSS0][2].Key, KeyLen / 2); - CipherAlg = CIPHER_WEP128; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key3_Proc::(Key3=%s and type=Hex)\n", arg)); - break; - default: //Invalid argument - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key3_Proc::Invalid argument (=%s)\n", arg)); - return FALSE; - } - pAdapter->SharedKey[BSS0][2].CipherAlg = CipherAlg; - - // Set keys (into ASIC) - if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - ; // not support - else // Old WEP stuff - { - AsicAddSharedKeyEntry(pAdapter, - 0, - 2, - pAdapter->SharedKey[BSS0][2].CipherAlg, - pAdapter->SharedKey[BSS0][2].Key, - NULL, - NULL); - } - - return TRUE; -} -/* - ========================================================================== - Description: - Set WEP KEY4 - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_Key4_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - int KeyLen; - int i; - UCHAR CipherAlg=CIPHER_WEP64; - - if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - return TRUE; // do nothing - - KeyLen = strlen(arg); - - switch (KeyLen) - { - case 5: //wep 40 Ascii type - pAdapter->SharedKey[BSS0][3].KeyLen = KeyLen; - memcpy(pAdapter->SharedKey[BSS0][3].Key, arg, KeyLen); - CipherAlg = CIPHER_WEP64; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key4_Proc::(Key4=%s and type=%s)\n", arg, "Ascii")); - break; - case 10: //wep 40 Hex type - for(i=0; i < KeyLen; i++) - { - if( !isxdigit(*(arg+i)) ) - return FALSE; //Not Hex value; - } - pAdapter->SharedKey[BSS0][3].KeyLen = KeyLen / 2 ; - AtoH(arg, pAdapter->SharedKey[BSS0][3].Key, KeyLen / 2); - CipherAlg = CIPHER_WEP64; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key4_Proc::(Key4=%s and type=%s)\n", arg, "Hex")); - break; - case 13: //wep 104 Ascii type - pAdapter->SharedKey[BSS0][3].KeyLen = KeyLen; - memcpy(pAdapter->SharedKey[BSS0][3].Key, arg, KeyLen); - CipherAlg = CIPHER_WEP128; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key4_Proc::(Key4=%s and type=%s)\n", arg, "Ascii")); - break; - case 26: //wep 104 Hex type - for(i=0; i < KeyLen; i++) - { - if( !isxdigit(*(arg+i)) ) - return FALSE; //Not Hex value; - } - pAdapter->SharedKey[BSS0][3].KeyLen = KeyLen / 2 ; - AtoH(arg, pAdapter->SharedKey[BSS0][3].Key, KeyLen / 2); - CipherAlg = CIPHER_WEP128; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key4_Proc::(Key4=%s and type=%s)\n", arg, "Hex")); - break; - default: //Invalid argument - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key4_Proc::Invalid argument (=%s)\n", arg)); - return FALSE; - } - pAdapter->SharedKey[BSS0][3].CipherAlg = CipherAlg; - - // Set keys (into ASIC) - if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - ; // not support - else // Old WEP stuff - { - AsicAddSharedKeyEntry(pAdapter, - 0, - 3, - pAdapter->SharedKey[BSS0][3].CipherAlg, - pAdapter->SharedKey[BSS0][3].Key, - NULL, - NULL); - } - - return TRUE; -} - -/* - ========================================================================== - Description: - Set WPA PSK key - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_WPAPSK_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - UCHAR keyMaterial[40]; - - if ((pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPAPSK) && - (pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPA2PSK) && - (pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPANone) - ) - return TRUE; // do nothing - - DBGPRINT(RT_DEBUG_TRACE, ("Set_WPAPSK_Proc::(WPAPSK=%s)\n", arg)); - - NdisZeroMemory(keyMaterial, 40); - - if ((strlen(arg) < 8) || (strlen(arg) > 64)) - { - DBGPRINT(RT_DEBUG_TRACE, ("Set failed!!(WPAPSK=%s), WPAPSK key-string required 8 ~ 64 characters \n", arg)); - return FALSE; - } - - if (strlen(arg) == 64) - { - AtoH(arg, keyMaterial, 32); - NdisMoveMemory(pAdapter->StaCfg.PMK, keyMaterial, 32); - - } - else - { - PasswordHash((char *)arg, pAdapter->MlmeAux.Ssid, pAdapter->MlmeAux.SsidLen, keyMaterial); - NdisMoveMemory(pAdapter->StaCfg.PMK, keyMaterial, 32); - } - - - - if(pAdapter->StaCfg.BssType == BSS_ADHOC && - pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) - { - pAdapter->StaCfg.WpaState = SS_NOTUSE; - } - else - { - // Start STA supplicant state machine - pAdapter->StaCfg.WpaState = SS_START; - } - - return TRUE; -} - -/* - ========================================================================== - Description: - Set Power Saving mode - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_PSMode_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - if (pAdapter->StaCfg.BssType == BSS_INFRA) - { - if ((strcmp(arg, "Max_PSP") == 0) || - (strcmp(arg, "max_psp") == 0) || - (strcmp(arg, "MAX_PSP") == 0)) - { - // do NOT turn on PSM bit here, wait until MlmeCheckForPsmChange() - // to exclude certain situations. - if (pAdapter->StaCfg.bWindowsACCAMEnable == FALSE) - pAdapter->StaCfg.WindowsPowerMode = Ndis802_11PowerModeMAX_PSP; - pAdapter->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeMAX_PSP; - OPSTATUS_SET_FLAG(pAdapter, fOP_STATUS_RECEIVE_DTIM); - pAdapter->StaCfg.DefaultListenCount = 5; - - } - else if ((strcmp(arg, "Fast_PSP") == 0) || - (strcmp(arg, "fast_psp") == 0) || - (strcmp(arg, "FAST_PSP") == 0)) - { - // do NOT turn on PSM bit here, wait until MlmeCheckForPsmChange() - // to exclude certain situations. - OPSTATUS_SET_FLAG(pAdapter, fOP_STATUS_RECEIVE_DTIM); - if (pAdapter->StaCfg.bWindowsACCAMEnable == FALSE) - pAdapter->StaCfg.WindowsPowerMode = Ndis802_11PowerModeFast_PSP; - pAdapter->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeFast_PSP; - pAdapter->StaCfg.DefaultListenCount = 3; - } - else if ((strcmp(arg, "Legacy_PSP") == 0) || - (strcmp(arg, "legacy_psp") == 0) || - (strcmp(arg, "LEGACY_PSP") == 0)) - { - // do NOT turn on PSM bit here, wait until MlmeCheckForPsmChange() - // to exclude certain situations. - OPSTATUS_SET_FLAG(pAdapter, fOP_STATUS_RECEIVE_DTIM); - if (pAdapter->StaCfg.bWindowsACCAMEnable == FALSE) - pAdapter->StaCfg.WindowsPowerMode = Ndis802_11PowerModeLegacy_PSP; - pAdapter->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeLegacy_PSP; - pAdapter->StaCfg.DefaultListenCount = 3; - } - else - { - //Default Ndis802_11PowerModeCAM - // clear PSM bit immediately - MlmeSetPsmBit(pAdapter, PWR_ACTIVE); - OPSTATUS_SET_FLAG(pAdapter, fOP_STATUS_RECEIVE_DTIM); - if (pAdapter->StaCfg.bWindowsACCAMEnable == FALSE) - pAdapter->StaCfg.WindowsPowerMode = Ndis802_11PowerModeCAM; - pAdapter->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeCAM; - } - - DBGPRINT(RT_DEBUG_TRACE, ("Set_PSMode_Proc::(PSMode=%ld)\n", pAdapter->StaCfg.WindowsPowerMode)); - } - else - return FALSE; - - - return TRUE; -} - -#ifdef WPA_SUPPLICANT_SUPPORT -/* - ========================================================================== - Description: - Set WpaSupport flag. - Value: - 0: Driver ignore wpa_supplicant. - 1: wpa_supplicant initiates scanning and AP selection. - 2: driver takes care of scanning, AP selection, and IEEE 802.11 association parameters. - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_Wpa_Support( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - - if ( simple_strtol(arg, 0, 10) == 0) - pAd->StaCfg.WpaSupplicantUP = WPA_SUPPLICANT_DISABLE; - else if ( simple_strtol(arg, 0, 10) == 1) - pAd->StaCfg.WpaSupplicantUP = WPA_SUPPLICANT_ENABLE; - else if ( simple_strtol(arg, 0, 10) == 2) - pAd->StaCfg.WpaSupplicantUP = WPA_SUPPLICANT_ENABLE_WITH_WEB_UI; - else - pAd->StaCfg.WpaSupplicantUP = WPA_SUPPLICANT_DISABLE; - - DBGPRINT(RT_DEBUG_TRACE, ("Set_Wpa_Support::(WpaSupplicantUP=%d)\n", pAd->StaCfg.WpaSupplicantUP)); - - return TRUE; -} -#endif // WPA_SUPPLICANT_SUPPORT // - -#ifdef DBG -/* - ========================================================================== - Description: - Read / Write MAC - Arguments: - pAdapter Pointer to our adapter - wrq Pointer to the ioctl argument - - Return Value: - None - - Note: - Usage: - 1.) iwpriv ra0 mac 0 ==> read MAC where Addr=0x0 - 2.) iwpriv ra0 mac 0=12 ==> write MAC where Addr=0x0, value=12 - ========================================================================== -*/ -VOID RTMPIoctlMAC( - IN PRTMP_ADAPTER pAdapter, - IN struct iwreq *wrq) -{ - CHAR *this_char; - CHAR *value; - INT j = 0, k = 0; - CHAR msg[1024]; - CHAR arg[255]; - ULONG macAddr = 0; - UCHAR temp[16], temp2[16]; - UINT32 macValue = 0; - INT Status; - - - memset(msg, 0x00, 1024); - if (wrq->u.data.length > 1) //No parameters. - { - Status = copy_from_user(arg, wrq->u.data.pointer, (wrq->u.data.length > 255) ? 255 : wrq->u.data.length); - sprintf(msg, "\n"); - - //Parsing Read or Write - this_char = arg; - if (!*this_char) - goto next; - - if ((value = rtstrchr(this_char, '=')) != NULL) - *value++ = 0; - - if (!value || !*value) - { //Read - // Sanity check - if(strlen(this_char) > 4) - goto next; - - j = strlen(this_char); - while(j-- > 0) - { - if(this_char[j] > 'f' || this_char[j] < '0') - return; - } - - // Mac Addr - k = j = strlen(this_char); - while(j-- > 0) - { - this_char[4-k+j] = this_char[j]; - } - - while(k < 4) - this_char[3-k++]='0'; - this_char[4]='\0'; - - if(strlen(this_char) == 4) - { - AtoH(this_char, temp, 2); - macAddr = *temp*256 + temp[1]; - if (macAddr < 0xFFFF) - { - RTMP_IO_READ32(pAdapter, macAddr, &macValue); - DBGPRINT(RT_DEBUG_TRACE, ("MacAddr=%lx, MacValue=%x\n", macAddr, macValue)); - sprintf(msg+strlen(msg), "[0x%08lX]:%08X ", macAddr , macValue); - } - else - {//Invalid parametes, so default printk all bbp - goto next; - } - } - } - else - { //Write - memcpy(&temp2, value, strlen(value)); - temp2[strlen(value)] = '\0'; - - // Sanity check - if((strlen(this_char) > 4) || strlen(temp2) > 8) - goto next; - - j = strlen(this_char); - while(j-- > 0) - { - if(this_char[j] > 'f' || this_char[j] < '0') - return; - } - - j = strlen(temp2); - while(j-- > 0) - { - if(temp2[j] > 'f' || temp2[j] < '0') - return; - } - - //MAC Addr - k = j = strlen(this_char); - while(j-- > 0) - { - this_char[4-k+j] = this_char[j]; - } - - while(k < 4) - this_char[3-k++]='0'; - this_char[4]='\0'; - - //MAC value - k = j = strlen(temp2); - while(j-- > 0) - { - temp2[8-k+j] = temp2[j]; - } - - while(k < 8) - temp2[7-k++]='0'; - temp2[8]='\0'; - - { - AtoH(this_char, temp, 2); - macAddr = *temp*256 + temp[1]; - - AtoH(temp2, temp, 4); - macValue = *temp*256*256*256 + temp[1]*256*256 + temp[2]*256 + temp[3]; - - // debug mode - if (macAddr == (HW_DEBUG_SETTING_BASE + 4)) - { - // 0x2bf4: byte0 non-zero: enable R17 tuning, 0: disable R17 tuning - if (macValue & 0x000000ff) - { - pAdapter->BbpTuning.bEnable = TRUE; - DBGPRINT(RT_DEBUG_TRACE,("turn on R17 tuning\n")); - } - else - { - UCHAR R66; - pAdapter->BbpTuning.bEnable = FALSE; - R66 = 0x26 + GET_LNA_GAIN(pAdapter); -#ifdef RALINK_ATE - if (ATE_ON(pAdapter)) - { - ATE_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R66, (0x26 + GET_LNA_GAIN(pAdapter))); - } - else -#endif // RALINK_ATE // - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R66, (0x26 + GET_LNA_GAIN(pAdapter))); - DBGPRINT(RT_DEBUG_TRACE,("turn off R17 tuning, restore to 0x%02x\n", R66)); - } - return; - } - - DBGPRINT(RT_DEBUG_TRACE, ("MacAddr=%02lx, MacValue=0x%x\n", macAddr, macValue)); - - RTMP_IO_WRITE32(pAdapter, macAddr, macValue); - sprintf(msg+strlen(msg), "[0x%08lX]:%08X ", macAddr, macValue); - } - } - } -next: - if(strlen(msg) == 1) - sprintf(msg+strlen(msg), "===>Error command format!"); - - // Copy the information into the user buffer - wrq->u.data.length = strlen(msg); - Status = copy_to_user(wrq->u.data.pointer, msg, wrq->u.data.length); - - DBGPRINT(RT_DEBUG_TRACE, ("<==RTMPIoctlMAC\n\n")); -} - -/* - ========================================================================== - Description: - Read / Write E2PROM - Arguments: - pAdapter Pointer to our adapter - wrq Pointer to the ioctl argument - - Return Value: - None - - Note: - Usage: - 1.) iwpriv ra0 e2p 0 ==> read E2PROM where Addr=0x0 - 2.) iwpriv ra0 e2p 0=1234 ==> write E2PROM where Addr=0x0, value=1234 - ========================================================================== -*/ -VOID RTMPIoctlE2PROM( - IN PRTMP_ADAPTER pAdapter, - IN struct iwreq *wrq) -{ - CHAR *this_char; - CHAR *value; - INT j = 0, k = 0; - CHAR msg[1024]; - CHAR arg[255]; - USHORT eepAddr = 0; - UCHAR temp[16], temp2[16]; - USHORT eepValue; - int Status; - - - memset(msg, 0x00, 1024); - if (wrq->u.data.length > 1) //No parameters. - { - Status = copy_from_user(arg, wrq->u.data.pointer, (wrq->u.data.length > 255) ? 255 : wrq->u.data.length); - sprintf(msg, "\n"); - - //Parsing Read or Write - this_char = arg; - - - if (!*this_char) - goto next; - - if ((value = rtstrchr(this_char, '=')) != NULL) - *value++ = 0; - - if (!value || !*value) - { //Read - - // Sanity check - if(strlen(this_char) > 4) - goto next; - - j = strlen(this_char); - while(j-- > 0) - { - if(this_char[j] > 'f' || this_char[j] < '0') - return; - } - - // E2PROM addr - k = j = strlen(this_char); - while(j-- > 0) - { - this_char[4-k+j] = this_char[j]; - } - - while(k < 4) - this_char[3-k++]='0'; - this_char[4]='\0'; - - if(strlen(this_char) == 4) - { - AtoH(this_char, temp, 2); - eepAddr = *temp*256 + temp[1]; - if (eepAddr < 0xFFFF) - { - RT28xx_EEPROM_READ16(pAdapter, eepAddr, eepValue); - sprintf(msg+strlen(msg), "[0x%04X]:0x%04X ", eepAddr , eepValue); - } - else - {//Invalid parametes, so default printk all bbp - goto next; - } - } - } - else - { //Write - memcpy(&temp2, value, strlen(value)); - temp2[strlen(value)] = '\0'; - - // Sanity check - if((strlen(this_char) > 4) || strlen(temp2) > 8) - goto next; - - j = strlen(this_char); - while(j-- > 0) - { - if(this_char[j] > 'f' || this_char[j] < '0') - return; - } - j = strlen(temp2); - while(j-- > 0) - { - if(temp2[j] > 'f' || temp2[j] < '0') - return; - } - - //MAC Addr - k = j = strlen(this_char); - while(j-- > 0) - { - this_char[4-k+j] = this_char[j]; - } - - while(k < 4) - this_char[3-k++]='0'; - this_char[4]='\0'; - - //MAC value - k = j = strlen(temp2); - while(j-- > 0) - { - temp2[4-k+j] = temp2[j]; - } - - while(k < 4) - temp2[3-k++]='0'; - temp2[4]='\0'; - - AtoH(this_char, temp, 2); - eepAddr = *temp*256 + temp[1]; - - AtoH(temp2, temp, 2); - eepValue = *temp*256 + temp[1]; - - RT28xx_EEPROM_WRITE16(pAdapter, eepAddr, eepValue); - sprintf(msg+strlen(msg), "[0x%02X]:%02X ", eepAddr, eepValue); - } - } -next: - if(strlen(msg) == 1) - sprintf(msg+strlen(msg), "===>Error command format!"); - - - // Copy the information into the user buffer - wrq->u.data.length = strlen(msg); - Status = copy_to_user(wrq->u.data.pointer, msg, wrq->u.data.length); - - DBGPRINT(RT_DEBUG_TRACE, ("<==RTMPIoctlE2PROM\n")); -} -#endif // DBG // - - - - -INT Set_TGnWifiTest_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - if (simple_strtol(arg, 0, 10) == 0) - pAd->StaCfg.bTGnWifiTest = FALSE; - else - pAd->StaCfg.bTGnWifiTest = TRUE; - - DBGPRINT(RT_DEBUG_TRACE, ("IF Set_TGnWifiTest_Proc::(bTGnWifiTest=%d)\n", pAd->StaCfg.bTGnWifiTest)); - return TRUE; -} - -INT Set_LongRetryLimit_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - TX_RTY_CFG_STRUC tx_rty_cfg; - UCHAR LongRetryLimit = (UCHAR)simple_strtol(arg, 0, 10); - - RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); - tx_rty_cfg.field.LongRtyLimit = LongRetryLimit; - RTMP_IO_WRITE32(pAdapter, TX_RTY_CFG, tx_rty_cfg.word); - DBGPRINT(RT_DEBUG_TRACE, ("IF Set_LongRetryLimit_Proc::(tx_rty_cfg=0x%x)\n", tx_rty_cfg.word)); - return TRUE; -} - -INT Set_ShortRetryLimit_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - TX_RTY_CFG_STRUC tx_rty_cfg; - UCHAR ShortRetryLimit = (UCHAR)simple_strtol(arg, 0, 10); - - RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); - tx_rty_cfg.field.ShortRtyLimit = ShortRetryLimit; - RTMP_IO_WRITE32(pAdapter, TX_RTY_CFG, tx_rty_cfg.word); - DBGPRINT(RT_DEBUG_TRACE, ("IF Set_ShortRetryLimit_Proc::(tx_rty_cfg=0x%x)\n", tx_rty_cfg.word)); - return TRUE; -} - -#ifdef EXT_BUILD_CHANNEL_LIST -INT Set_Ieee80211dClientMode_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - if (simple_strtol(arg, 0, 10) == 0) - pAdapter->StaCfg.IEEE80211dClientMode = Rt802_11_D_None; - else if (simple_strtol(arg, 0, 10) == 1) - pAdapter->StaCfg.IEEE80211dClientMode = Rt802_11_D_Flexible; - else if (simple_strtol(arg, 0, 10) == 2) - pAdapter->StaCfg.IEEE80211dClientMode = Rt802_11_D_Strict; - else - return FALSE; - - DBGPRINT(RT_DEBUG_TRACE, ("Set_Ieee802dMode_Proc::(IEEEE0211dMode=%d)\n", pAdapter->StaCfg.IEEE80211dClientMode)); - return TRUE; -} -#endif // EXT_BUILD_CHANNEL_LIST // - -#ifdef CARRIER_DETECTION_SUPPORT -INT Set_CarrierDetect_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - if (simple_strtol(arg, 0, 10) == 0) - pAd->CommonCfg.CarrierDetect.Enable = FALSE; - else - pAd->CommonCfg.CarrierDetect.Enable = TRUE; - - DBGPRINT(RT_DEBUG_TRACE, ("IF Set_CarrierDetect_Proc::(CarrierDetect.Enable=%d)\n", pAd->CommonCfg.CarrierDetect.Enable)); - return TRUE; -} -#endif // CARRIER_DETECTION_SUPPORT // - - -INT Show_Adhoc_MacTable_Proc( - IN PRTMP_ADAPTER pAd, - IN PCHAR extra) -{ - INT i; - - sprintf(extra, "\n"); - -#ifdef DOT11_N_SUPPORT - sprintf(extra, "%sHT Operating Mode : %d\n", extra, pAd->CommonCfg.AddHTInfo.AddHtInfo2.OperaionMode); -#endif // DOT11_N_SUPPORT // - - sprintf(extra, "%s\n%-19s%-4s%-4s%-7s%-7s%-7s%-10s%-6s%-6s%-6s%-6s\n", extra, - "MAC", "AID", "BSS", "RSSI0", "RSSI1", "RSSI2", "PhMd", "BW", "MCS", "SGI", "STBC"); - - for (i=1; iMacTab.Content[i]; - - if (strlen(extra) > (IW_PRIV_SIZE_MASK - 30)) - break; - if ((pEntry->ValidAsCLI || pEntry->ValidAsApCli) && (pEntry->Sst == SST_ASSOC)) - { - sprintf(extra, "%s%02X:%02X:%02X:%02X:%02X:%02X ", extra, - pEntry->Addr[0], pEntry->Addr[1], pEntry->Addr[2], - pEntry->Addr[3], pEntry->Addr[4], pEntry->Addr[5]); - sprintf(extra, "%s%-4d", extra, (int)pEntry->Aid); - sprintf(extra, "%s%-4d", extra, (int)pEntry->apidx); - sprintf(extra, "%s%-7d", extra, pEntry->RssiSample.AvgRssi0); - sprintf(extra, "%s%-7d", extra, pEntry->RssiSample.AvgRssi1); - sprintf(extra, "%s%-7d", extra, pEntry->RssiSample.AvgRssi2); - sprintf(extra, "%s%-10s", extra, GetPhyMode(pEntry->HTPhyMode.field.MODE)); - sprintf(extra, "%s%-6s", extra, GetBW(pEntry->HTPhyMode.field.BW)); - sprintf(extra, "%s%-6d", extra, pEntry->HTPhyMode.field.MCS); - sprintf(extra, "%s%-6d", extra, pEntry->HTPhyMode.field.ShortGI); - sprintf(extra, "%s%-6d", extra, pEntry->HTPhyMode.field.STBC); - sprintf(extra, "%s%-10d, %d, %d%%\n", extra, pEntry->DebugFIFOCount, pEntry->DebugTxCount, - (pEntry->DebugTxCount) ? ((pEntry->DebugTxCount-pEntry->DebugFIFOCount)*100/pEntry->DebugTxCount) : 0); - sprintf(extra, "%s\n", extra); - } - } - - return TRUE; -} - - diff --git a/drivers/staging/rt2870/tmp61 b/drivers/staging/rt2870/tmp61 deleted file mode 100644 index 975e44484379..000000000000 --- a/drivers/staging/rt2870/tmp61 +++ /dev/null @@ -1,7037 +0,0 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - sta_ioctl.c - - Abstract: - IOCTL related subroutines - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Rory Chen 01-03-2003 created - Rory Chen 02-14-2005 modify to support RT61 -*/ - -#include "rt_config.h" - -#ifdef DBG -extern ULONG RTDebugLevel; -#endif - -#define NR_WEP_KEYS 4 -#define WEP_SMALL_KEY_LEN (40/8) -#define WEP_LARGE_KEY_LEN (104/8) - -#define GROUP_KEY_NO 4 - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) -#define IWE_STREAM_ADD_EVENT(_A, _B, _C, _D, _E) iwe_stream_add_event(_A, _B, _C, _D, _E) -#define IWE_STREAM_ADD_POINT(_A, _B, _C, _D, _E) iwe_stream_add_point(_A, _B, _C, _D, _E) -#define IWE_STREAM_ADD_VALUE(_A, _B, _C, _D, _E, _F) iwe_stream_add_value(_A, _B, _C, _D, _E, _F) -#else -#define IWE_STREAM_ADD_EVENT(_A, _B, _C, _D, _E) iwe_stream_add_event(_B, _C, _D, _E) -#define IWE_STREAM_ADD_POINT(_A, _B, _C, _D, _E) iwe_stream_add_point(_B, _C, _D, _E) -#define IWE_STREAM_ADD_VALUE(_A, _B, _C, _D, _E, _F) iwe_stream_add_value(_B, _C, _D, _E, _F) -#endif - -extern UCHAR CipherWpa2Template[]; -extern UCHAR CipherWpaPskTkip[]; -extern UCHAR CipherWpaPskTkipLen; - -typedef struct PACKED _RT_VERSION_INFO{ - UCHAR DriverVersionW; - UCHAR DriverVersionX; - UCHAR DriverVersionY; - UCHAR DriverVersionZ; - UINT DriverBuildYear; - UINT DriverBuildMonth; - UINT DriverBuildDay; -} RT_VERSION_INFO, *PRT_VERSION_INFO; - -struct iw_priv_args privtab[] = { -{ RTPRIV_IOCTL_SET, - IW_PRIV_TYPE_CHAR | 1024, 0, - "set"}, - -{ RTPRIV_IOCTL_SHOW, 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, - ""}, -{ RTPRIV_IOCTL_SHOW, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, - ""}, -/* --- sub-ioctls definitions --- */ - { SHOW_CONN_STATUS, - 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "connStatus" }, - { SHOW_DRVIER_VERION, - 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "driverVer" }, - { SHOW_BA_INFO, - 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "bainfo" }, - { SHOW_DESC_INFO, - 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "descinfo" }, - { RAIO_OFF, - 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "radio_off" }, - { RAIO_ON, - 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "radio_on" }, -#ifdef QOS_DLS_SUPPORT - { SHOW_DLS_ENTRY_INFO, - 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "dlsentryinfo" }, -#endif // QOS_DLS_SUPPORT // - { SHOW_CFG_VALUE, - IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "show" }, - { SHOW_ADHOC_ENTRY_INFO, - 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "adhocEntry" }, - -/* --- sub-ioctls relations --- */ - -#ifdef DBG -{ RTPRIV_IOCTL_BBP, - IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, - "bbp"}, -{ RTPRIV_IOCTL_MAC, - IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | 1024, - "mac"}, -{ RTPRIV_IOCTL_E2P, - IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | 1024, - "e2p"}, -#endif /* DBG */ - -{ RTPRIV_IOCTL_STATISTICS, - 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, - "stat"}, -{ RTPRIV_IOCTL_GSITESURVEY, - 0, IW_PRIV_TYPE_CHAR | 1024, - "get_site_survey"}, -}; - -INT Set_SSID_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - -#ifdef WMM_SUPPORT -INT Set_WmmCapable_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); -#endif - -INT Set_NetworkType_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - -INT Set_AuthMode_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - -INT Set_EncrypType_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - -INT Set_DefaultKeyID_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - -INT Set_Key1_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - -INT Set_Key2_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - -INT Set_Key3_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - -INT Set_Key4_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - -INT Set_WPAPSK_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - - -INT Set_PSMode_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - -#ifdef WPA_SUPPLICANT_SUPPORT -INT Set_Wpa_Support( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); -#endif // WPA_SUPPLICANT_SUPPORT // - -#ifdef DBG -VOID RTMPIoctlBBP( - IN PRTMP_ADAPTER pAdapter, - IN struct iwreq *wrq); - -VOID RTMPIoctlMAC( - IN PRTMP_ADAPTER pAdapter, - IN struct iwreq *wrq); - -VOID RTMPIoctlE2PROM( - IN PRTMP_ADAPTER pAdapter, - IN struct iwreq *wrq); -#endif // DBG // - - -NDIS_STATUS RTMPWPANoneAddKeyProc( - IN PRTMP_ADAPTER pAd, - IN PVOID pBuf); - -INT Set_FragTest_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - -#ifdef DOT11_N_SUPPORT -INT Set_TGnWifiTest_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); -#endif // DOT11_N_SUPPORT // - -INT Set_LongRetryLimit_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - -INT Set_ShortRetryLimit_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - -#ifdef EXT_BUILD_CHANNEL_LIST -INT Set_Ieee80211dClientMode_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); -#endif // EXT_BUILD_CHANNEL_LIST // - -#ifdef CARRIER_DETECTION_SUPPORT -INT Set_CarrierDetect_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); -#endif // CARRIER_DETECTION_SUPPORT // - -INT Show_Adhoc_MacTable_Proc( - IN PRTMP_ADAPTER pAd, - IN PCHAR extra); - -static struct { - CHAR *name; - INT (*set_proc)(PRTMP_ADAPTER pAdapter, PUCHAR arg); -} *PRTMP_PRIVATE_SET_PROC, RTMP_PRIVATE_SUPPORT_PROC[] = { - {"DriverVersion", Set_DriverVersion_Proc}, - {"CountryRegion", Set_CountryRegion_Proc}, - {"CountryRegionABand", Set_CountryRegionABand_Proc}, - {"SSID", Set_SSID_Proc}, - {"WirelessMode", Set_WirelessMode_Proc}, - {"TxBurst", Set_TxBurst_Proc}, - {"TxPreamble", Set_TxPreamble_Proc}, - {"TxPower", Set_TxPower_Proc}, - {"Channel", Set_Channel_Proc}, - {"BGProtection", Set_BGProtection_Proc}, - {"RTSThreshold", Set_RTSThreshold_Proc}, - {"FragThreshold", Set_FragThreshold_Proc}, -#ifdef DOT11_N_SUPPORT - {"HtBw", Set_HtBw_Proc}, - {"HtMcs", Set_HtMcs_Proc}, - {"HtGi", Set_HtGi_Proc}, - {"HtOpMode", Set_HtOpMode_Proc}, - {"HtExtcha", Set_HtExtcha_Proc}, - {"HtMpduDensity", Set_HtMpduDensity_Proc}, - {"HtBaWinSize", Set_HtBaWinSize_Proc}, - {"HtRdg", Set_HtRdg_Proc}, - {"HtAmsdu", Set_HtAmsdu_Proc}, - {"HtAutoBa", Set_HtAutoBa_Proc}, - {"HtBaDecline", Set_BADecline_Proc}, - {"HtProtect", Set_HtProtect_Proc}, - {"HtMimoPs", Set_HtMimoPs_Proc}, -#endif // DOT11_N_SUPPORT // - -#ifdef AGGREGATION_SUPPORT - {"PktAggregate", Set_PktAggregate_Proc}, -#endif - -#ifdef WMM_SUPPORT - {"WmmCapable", Set_WmmCapable_Proc}, -#endif - {"IEEE80211H", Set_IEEE80211H_Proc}, - {"NetworkType", Set_NetworkType_Proc}, - {"AuthMode", Set_AuthMode_Proc}, - {"EncrypType", Set_EncrypType_Proc}, - {"DefaultKeyID", Set_DefaultKeyID_Proc}, - {"Key1", Set_Key1_Proc}, - {"Key2", Set_Key2_Proc}, - {"Key3", Set_Key3_Proc}, - {"Key4", Set_Key4_Proc}, - {"WPAPSK", Set_WPAPSK_Proc}, - {"ResetCounter", Set_ResetStatCounter_Proc}, - {"PSMode", Set_PSMode_Proc}, -#ifdef DBG - {"Debug", Set_Debug_Proc}, -#endif - -#ifdef RALINK_ATE - {"ATE", Set_ATE_Proc}, - {"ATEDA", Set_ATE_DA_Proc}, - {"ATESA", Set_ATE_SA_Proc}, - {"ATEBSSID", Set_ATE_BSSID_Proc}, - {"ATECHANNEL", Set_ATE_CHANNEL_Proc}, - {"ATETXPOW0", Set_ATE_TX_POWER0_Proc}, - {"ATETXPOW1", Set_ATE_TX_POWER1_Proc}, - {"ATETXANT", Set_ATE_TX_Antenna_Proc}, - {"ATERXANT", Set_ATE_RX_Antenna_Proc}, - {"ATETXFREQOFFSET", Set_ATE_TX_FREQOFFSET_Proc}, - {"ATETXBW", Set_ATE_TX_BW_Proc}, - {"ATETXLEN", Set_ATE_TX_LENGTH_Proc}, - {"ATETXCNT", Set_ATE_TX_COUNT_Proc}, - {"ATETXMCS", Set_ATE_TX_MCS_Proc}, - {"ATETXMODE", Set_ATE_TX_MODE_Proc}, - {"ATETXGI", Set_ATE_TX_GI_Proc}, - {"ATERXFER", Set_ATE_RX_FER_Proc}, - {"ATERRF", Set_ATE_Read_RF_Proc}, - {"ATEWRF1", Set_ATE_Write_RF1_Proc}, - {"ATEWRF2", Set_ATE_Write_RF2_Proc}, - {"ATEWRF3", Set_ATE_Write_RF3_Proc}, - {"ATEWRF4", Set_ATE_Write_RF4_Proc}, - {"ATELDE2P", Set_ATE_Load_E2P_Proc}, - {"ATERE2P", Set_ATE_Read_E2P_Proc}, - {"ATESHOW", Set_ATE_Show_Proc}, - {"ATEHELP", Set_ATE_Help_Proc}, - -#ifdef RALINK_28xx_QA - {"TxStop", Set_TxStop_Proc}, - {"RxStop", Set_RxStop_Proc}, -#endif // RALINK_28xx_QA // -#endif // RALINK_ATE // - -#ifdef WPA_SUPPLICANT_SUPPORT - {"WpaSupport", Set_Wpa_Support}, -#endif // WPA_SUPPLICANT_SUPPORT // - - - - {"FixedTxMode", Set_FixedTxMode_Proc}, -#ifdef CONFIG_APSTA_MIXED_SUPPORT - {"OpMode", Set_OpMode_Proc}, -#endif // CONFIG_APSTA_MIXED_SUPPORT // -#ifdef DOT11_N_SUPPORT - {"TGnWifiTest", Set_TGnWifiTest_Proc}, - {"ForceGF", Set_ForceGF_Proc}, -#endif // DOT11_N_SUPPORT // -#ifdef QOS_DLS_SUPPORT - {"DlsAddEntry", Set_DlsAddEntry_Proc}, - {"DlsTearDownEntry", Set_DlsTearDownEntry_Proc}, -#endif // QOS_DLS_SUPPORT // - {"LongRetry", Set_LongRetryLimit_Proc}, - {"ShortRetry", Set_ShortRetryLimit_Proc}, -#ifdef EXT_BUILD_CHANNEL_LIST - {"11dClientMode", Set_Ieee80211dClientMode_Proc}, -#endif // EXT_BUILD_CHANNEL_LIST // -#ifdef CARRIER_DETECTION_SUPPORT - {"CarrierDetect", Set_CarrierDetect_Proc}, -#endif // CARRIER_DETECTION_SUPPORT // - - {NULL,} -}; - - -VOID RTMPAddKey( - IN PRTMP_ADAPTER pAd, - IN PNDIS_802_11_KEY pKey) -{ - ULONG KeyIdx; - MAC_TABLE_ENTRY *pEntry; - - DBGPRINT(RT_DEBUG_TRACE, ("RTMPAddKey ------>\n")); - - if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - { - if (pKey->KeyIndex & 0x80000000) - { - if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) - { - NdisZeroMemory(pAd->StaCfg.PMK, 32); - NdisMoveMemory(pAd->StaCfg.PMK, pKey->KeyMaterial, pKey->KeyLength); - goto end; - } - // Update PTK - NdisZeroMemory(&pAd->SharedKey[BSS0][0], sizeof(CIPHER_KEY)); - pAd->SharedKey[BSS0][0].KeyLen = LEN_TKIP_EK; - NdisMoveMemory(pAd->SharedKey[BSS0][0].Key, pKey->KeyMaterial, LEN_TKIP_EK); -#ifdef WPA_SUPPLICANT_SUPPORT - if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled) - { - NdisMoveMemory(pAd->SharedKey[BSS0][0].RxMic, pKey->KeyMaterial + LEN_TKIP_EK, LEN_TKIP_TXMICK); - NdisMoveMemory(pAd->SharedKey[BSS0][0].TxMic, pKey->KeyMaterial + LEN_TKIP_EK + LEN_TKIP_TXMICK, LEN_TKIP_RXMICK); - } - else -#endif // WPA_SUPPLICANT_SUPPORT // - { - NdisMoveMemory(pAd->SharedKey[BSS0][0].TxMic, pKey->KeyMaterial + LEN_TKIP_EK, LEN_TKIP_TXMICK); - NdisMoveMemory(pAd->SharedKey[BSS0][0].RxMic, pKey->KeyMaterial + LEN_TKIP_EK + LEN_TKIP_TXMICK, LEN_TKIP_RXMICK); - } - - // Decide its ChiperAlg - if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled) - pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_TKIP; - else if (pAd->StaCfg.PairCipher == Ndis802_11Encryption3Enabled) - pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_AES; - else - pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_NONE; - - // Update these related information to MAC_TABLE_ENTRY - pEntry = &pAd->MacTab.Content[BSSID_WCID]; - NdisMoveMemory(pEntry->PairwiseKey.Key, pAd->SharedKey[BSS0][0].Key, LEN_TKIP_EK); - NdisMoveMemory(pEntry->PairwiseKey.RxMic, pAd->SharedKey[BSS0][0].RxMic, LEN_TKIP_RXMICK); - NdisMoveMemory(pEntry->PairwiseKey.TxMic, pAd->SharedKey[BSS0][0].TxMic, LEN_TKIP_TXMICK); - pEntry->PairwiseKey.CipherAlg = pAd->SharedKey[BSS0][0].CipherAlg; - - // Update pairwise key information to ASIC Shared Key Table - AsicAddSharedKeyEntry(pAd, - BSS0, - 0, - pAd->SharedKey[BSS0][0].CipherAlg, - pAd->SharedKey[BSS0][0].Key, - pAd->SharedKey[BSS0][0].TxMic, - pAd->SharedKey[BSS0][0].RxMic); - - // Update ASIC WCID attribute table and IVEIV table - RTMPAddWcidAttributeEntry(pAd, - BSS0, - 0, - pAd->SharedKey[BSS0][0].CipherAlg, - pEntry); - - if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA2) - { - // set 802.1x port control - //pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; - STA_PORT_SECURED(pAd); - - // Indicate Connected for GUI - pAd->IndicateMediaState = NdisMediaStateConnected; - } - } - else - { - // Update GTK - pAd->StaCfg.DefaultKeyId = (pKey->KeyIndex & 0xFF); - NdisZeroMemory(&pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId], sizeof(CIPHER_KEY)); - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].KeyLen = LEN_TKIP_EK; - NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, pKey->KeyMaterial, LEN_TKIP_EK); -#ifdef WPA_SUPPLICANT_SUPPORT - if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption2Enabled) - { - NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic, pKey->KeyMaterial + LEN_TKIP_EK, LEN_TKIP_TXMICK); - NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, pKey->KeyMaterial + LEN_TKIP_EK + LEN_TKIP_TXMICK, LEN_TKIP_RXMICK); - } - else -#endif // WPA_SUPPLICANT_SUPPORT // - { - NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, pKey->KeyMaterial + LEN_TKIP_EK, LEN_TKIP_TXMICK); - NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic, pKey->KeyMaterial + LEN_TKIP_EK + LEN_TKIP_TXMICK, LEN_TKIP_RXMICK); - } - - // Update Shared Key CipherAlg - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_NONE; - if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption2Enabled) - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_TKIP; - else if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption3Enabled) - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_AES; - - // Update group key information to ASIC Shared Key Table - AsicAddSharedKeyEntry(pAd, - BSS0, - pAd->StaCfg.DefaultKeyId, - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic); - - // Update ASIC WCID attribute table and IVEIV table - RTMPAddWcidAttributeEntry(pAd, - BSS0, - pAd->StaCfg.DefaultKeyId, - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, - NULL); - - // set 802.1x port control - //pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; - STA_PORT_SECURED(pAd); - - // Indicate Connected for GUI - pAd->IndicateMediaState = NdisMediaStateConnected; - } - } - else // dynamic WEP from wpa_supplicant - { - UCHAR CipherAlg; - PUCHAR Key; - - if(pKey->KeyLength == 32) - goto end; - - KeyIdx = pKey->KeyIndex & 0x0fffffff; - - if (KeyIdx < 4) - { - // it is a default shared key, for Pairwise key setting - if (pKey->KeyIndex & 0x80000000) - { - pEntry = MacTableLookup(pAd, pKey->BSSID); - - if (pEntry) - { - DBGPRINT(RT_DEBUG_TRACE, ("RTMPAddKey: Set Pair-wise Key\n")); - - // set key material and key length - pEntry->PairwiseKey.KeyLen = (UCHAR)pKey->KeyLength; - NdisMoveMemory(pEntry->PairwiseKey.Key, &pKey->KeyMaterial, pKey->KeyLength); - - // set Cipher type - if (pKey->KeyLength == 5) - pEntry->PairwiseKey.CipherAlg = CIPHER_WEP64; - else - pEntry->PairwiseKey.CipherAlg = CIPHER_WEP128; - - // Add Pair-wise key to Asic - AsicAddPairwiseKeyEntry( - pAd, - pEntry->Addr, - (UCHAR)pEntry->Aid, - &pEntry->PairwiseKey); - - // update WCID attribute table and IVEIV table for this entry - RTMPAddWcidAttributeEntry( - pAd, - BSS0, - KeyIdx, // The value may be not zero - pEntry->PairwiseKey.CipherAlg, - pEntry); - - } - } - else - { - // Default key for tx (shared key) - pAd->StaCfg.DefaultKeyId = (UCHAR) KeyIdx; - - // set key material and key length - pAd->SharedKey[BSS0][KeyIdx].KeyLen = (UCHAR) pKey->KeyLength; - NdisMoveMemory(pAd->SharedKey[BSS0][KeyIdx].Key, &pKey->KeyMaterial, pKey->KeyLength); - - // Set Ciper type - if (pKey->KeyLength == 5) - pAd->SharedKey[BSS0][KeyIdx].CipherAlg = CIPHER_WEP64; - else - pAd->SharedKey[BSS0][KeyIdx].CipherAlg = CIPHER_WEP128; - - CipherAlg = pAd->SharedKey[BSS0][KeyIdx].CipherAlg; - Key = pAd->SharedKey[BSS0][KeyIdx].Key; - - // Set Group key material to Asic - AsicAddSharedKeyEntry(pAd, BSS0, KeyIdx, CipherAlg, Key, NULL, NULL); - - // Update WCID attribute table and IVEIV table for this group key table - RTMPAddWcidAttributeEntry(pAd, BSS0, KeyIdx, CipherAlg, NULL); - - } - } - } -end: - return; -} - -char * rtstrchr(const char * s, int c) -{ - for(; *s != (char) c; ++s) - if (*s == '\0') - return NULL; - return (char *) s; -} - -/* -This is required for LinEX2004/kernel2.6.7 to provide iwlist scanning function -*/ - -int -rt_ioctl_giwname(struct net_device *dev, - struct iw_request_info *info, - char *name, char *extra) -{ -// PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; - -#ifdef RT2870 - strncpy(name, "RT2870 Wireless", IFNAMSIZ); -#endif // RT2870 // - return 0; -} - -int rt_ioctl_siwfreq(struct net_device *dev, - struct iw_request_info *info, - struct iw_freq *freq, char *extra) -{ - PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; - int chan = -1; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - - if (freq->e > 1) - return -EINVAL; - - if((freq->e == 0) && (freq->m <= 1000)) - chan = freq->m; // Setting by channel number - else - MAP_KHZ_TO_CHANNEL_ID( (freq->m /100) , chan); // Setting by frequency - search the table , like 2.412G, 2.422G, - - if (ChannelSanity(pAdapter, chan) == TRUE) - { - pAdapter->CommonCfg.Channel = chan; - DBGPRINT(RT_DEBUG_ERROR, ("==>rt_ioctl_siwfreq::SIOCSIWFREQ[cmd=0x%x] (Channel=%d)\n", SIOCSIWFREQ, pAdapter->CommonCfg.Channel)); - } - else - return -EINVAL; - - return 0; -} -int rt_ioctl_giwfreq(struct net_device *dev, - struct iw_request_info *info, - struct iw_freq *freq, char *extra) -{ - VIRTUAL_ADAPTER *pVirtualAd = NULL; - PRTMP_ADAPTER pAdapter = NULL; - UCHAR ch; - ULONG m; - - if (dev->priv_flags == INT_MAIN) - { - pAdapter = dev->priv; - } - else - { - pVirtualAd = dev->priv; - if (pVirtualAd && pVirtualAd->RtmpDev) - pAdapter = pVirtualAd->RtmpDev->priv; - } - - if (pAdapter == NULL) - { - /* if 1st open fail, pAd will be free; - So the net_dev->priv will be NULL in 2rd open */ - return -ENETDOWN; - } - - ch = pAdapter->CommonCfg.Channel; - - DBGPRINT(RT_DEBUG_TRACE,("==>rt_ioctl_giwfreq %d\n", ch)); - - MAP_CHANNEL_ID_TO_KHZ(ch, m); - freq->m = m * 100; - freq->e = 1; - return 0; -} - -int rt_ioctl_siwmode(struct net_device *dev, - struct iw_request_info *info, - __u32 *mode, char *extra) -{ - PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - switch (*mode) - { - case IW_MODE_ADHOC: - Set_NetworkType_Proc(pAdapter, "Adhoc"); - break; - case IW_MODE_INFRA: - Set_NetworkType_Proc(pAdapter, "Infra"); - break; -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,20)) - case IW_MODE_MONITOR: - Set_NetworkType_Proc(pAdapter, "Monitor"); - break; -#endif - default: - DBGPRINT(RT_DEBUG_TRACE, ("===>rt_ioctl_siwmode::SIOCSIWMODE (unknown %d)\n", *mode)); - return -EINVAL; - } - - // Reset Ralink supplicant to not use, it will be set to start when UI set PMK key - pAdapter->StaCfg.WpaState = SS_NOTUSE; - - return 0; -} - -int rt_ioctl_giwmode(struct net_device *dev, - struct iw_request_info *info, - __u32 *mode, char *extra) -{ - PRTMP_ADAPTER pAdapter = NULL; - VIRTUAL_ADAPTER *pVirtualAd = NULL; - - if (dev->priv_flags == INT_MAIN) - { - pAdapter = dev->priv; - } - else - { - pVirtualAd = dev->priv; - if (pVirtualAd && pVirtualAd->RtmpDev) - pAdapter = pVirtualAd->RtmpDev->priv; - } - - if (pAdapter == NULL) - { - /* if 1st open fail, pAd will be free; - So the net_dev->priv will be NULL in 2rd open */ - return -ENETDOWN; - } - - if (ADHOC_ON(pAdapter)) - *mode = IW_MODE_ADHOC; - else if (INFRA_ON(pAdapter)) - *mode = IW_MODE_INFRA; -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,20)) - else if (MONITOR_ON(pAdapter)) - { - *mode = IW_MODE_MONITOR; - } -#endif - else - *mode = IW_MODE_AUTO; - - DBGPRINT(RT_DEBUG_TRACE, ("==>rt_ioctl_giwmode(mode=%d)\n", *mode)); - return 0; -} - -int rt_ioctl_siwsens(struct net_device *dev, - struct iw_request_info *info, - char *name, char *extra) -{ - PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - return 0; -} - -int rt_ioctl_giwsens(struct net_device *dev, - struct iw_request_info *info, - char *name, char *extra) -{ - return 0; -} - -int rt_ioctl_giwrange(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *extra) -{ - PRTMP_ADAPTER pAdapter = NULL; - VIRTUAL_ADAPTER *pVirtualAd = NULL; - struct iw_range *range = (struct iw_range *) extra; - u16 val; - int i; - - if (dev->priv_flags == INT_MAIN) - { - pAdapter = dev->priv; - } - else - { - pVirtualAd = dev->priv; - if (pVirtualAd && pVirtualAd->RtmpDev) - pAdapter = pVirtualAd->RtmpDev->priv; - } - - if (pAdapter == NULL) - { - /* if 1st open fail, pAd will be free; - So the net_dev->priv will be NULL in 2rd open */ - return -ENETDOWN; - } - - DBGPRINT(RT_DEBUG_TRACE ,("===>rt_ioctl_giwrange\n")); - data->length = sizeof(struct iw_range); - memset(range, 0, sizeof(struct iw_range)); - - range->txpower_capa = IW_TXPOW_DBM; - - if (INFRA_ON(pAdapter)||ADHOC_ON(pAdapter)) - { - range->min_pmp = 1 * 1024; - range->max_pmp = 65535 * 1024; - range->min_pmt = 1 * 1024; - range->max_pmt = 1000 * 1024; - range->pmp_flags = IW_POWER_PERIOD; - range->pmt_flags = IW_POWER_TIMEOUT; - range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | - IW_POWER_UNICAST_R | IW_POWER_ALL_R; - } - - range->we_version_compiled = WIRELESS_EXT; - range->we_version_source = 14; - - range->retry_capa = IW_RETRY_LIMIT; - range->retry_flags = IW_RETRY_LIMIT; - range->min_retry = 0; - range->max_retry = 255; - - range->num_channels = pAdapter->ChannelListNum; - - val = 0; - for (i = 1; i <= range->num_channels; i++) - { - u32 m; - range->freq[val].i = pAdapter->ChannelList[i-1].Channel; - MAP_CHANNEL_ID_TO_KHZ(pAdapter->ChannelList[i-1].Channel, m); - range->freq[val].m = m * 100; /* HZ */ - - range->freq[val].e = 1; - val++; - if (val == IW_MAX_FREQUENCIES) - break; - } - range->num_frequency = val; - - range->max_qual.qual = 100; /* what is correct max? This was not - * documented exactly. At least - * 69 has been observed. */ - range->max_qual.level = 0; /* dB */ - range->max_qual.noise = 0; /* dB */ - - /* What would be suitable values for "average/typical" qual? */ - range->avg_qual.qual = 20; - range->avg_qual.level = -60; - range->avg_qual.noise = -95; - range->sensitivity = 3; - - range->max_encoding_tokens = NR_WEP_KEYS; - range->num_encoding_sizes = 2; - range->encoding_size[0] = 5; - range->encoding_size[1] = 13; - - range->min_rts = 0; - range->max_rts = 2347; - range->min_frag = 256; - range->max_frag = 2346; - -#if WIRELESS_EXT > 17 - /* IW_ENC_CAPA_* bit field */ - range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | - IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; -#endif - - return 0; -} - -int rt_ioctl_siwap(struct net_device *dev, - struct iw_request_info *info, - struct sockaddr *ap_addr, char *extra) -{ - PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; - NDIS_802_11_MAC_ADDRESS Bssid; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) - { - RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); - DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); - } - - // tell CNTL state machine to call NdisMSetInformationComplete() after completing - // this request, because this request is initiated by NDIS. - pAdapter->MlmeAux.CurrReqIsFromNdis = FALSE; - // Prevent to connect AP again in STAMlmePeriodicExec - pAdapter->MlmeAux.AutoReconnectSsidLen= 32; - - memset(Bssid, 0, MAC_ADDR_LEN); - memcpy(Bssid, ap_addr->sa_data, MAC_ADDR_LEN); - MlmeEnqueue(pAdapter, - MLME_CNTL_STATE_MACHINE, - OID_802_11_BSSID, - sizeof(NDIS_802_11_MAC_ADDRESS), - (VOID *)&Bssid); - - DBGPRINT(RT_DEBUG_TRACE, ("IOCTL::SIOCSIWAP %02x:%02x:%02x:%02x:%02x:%02x\n", - Bssid[0], Bssid[1], Bssid[2], Bssid[3], Bssid[4], Bssid[5])); - - return 0; -} - -int rt_ioctl_giwap(struct net_device *dev, - struct iw_request_info *info, - struct sockaddr *ap_addr, char *extra) -{ - PRTMP_ADAPTER pAdapter = NULL; - VIRTUAL_ADAPTER *pVirtualAd = NULL; - - if (dev->priv_flags == INT_MAIN) - { - pAdapter = dev->priv; - } - else - { - pVirtualAd = dev->priv; - if (pVirtualAd && pVirtualAd->RtmpDev) - pAdapter = pVirtualAd->RtmpDev->priv; - } - - if (pAdapter == NULL) - { - /* if 1st open fail, pAd will be free; - So the net_dev->priv will be NULL in 2rd open */ - return -ENETDOWN; - } - - if (INFRA_ON(pAdapter) || ADHOC_ON(pAdapter)) - { - ap_addr->sa_family = ARPHRD_ETHER; - memcpy(ap_addr->sa_data, &pAdapter->CommonCfg.Bssid, ETH_ALEN); - } -#ifdef WPA_SUPPLICANT_SUPPORT - // Add for RT2870 - else if (pAdapter->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_DISABLE) - { - ap_addr->sa_family = ARPHRD_ETHER; - memcpy(ap_addr->sa_data, &pAdapter->MlmeAux.Bssid, ETH_ALEN); - } -#endif // WPA_SUPPLICANT_SUPPORT // - else - { - DBGPRINT(RT_DEBUG_TRACE, ("IOCTL::SIOCGIWAP(=EMPTY)\n")); - return -ENOTCONN; - } - - return 0; -} - -/* - * Units are in db above the noise floor. That means the - * rssi values reported in the tx/rx descriptors in the - * driver are the SNR expressed in db. - * - * If you assume that the noise floor is -95, which is an - * excellent assumption 99.5 % of the time, then you can - * derive the absolute signal level (i.e. -95 + rssi). - * There are some other slight factors to take into account - * depending on whether the rssi measurement is from 11b, - * 11g, or 11a. These differences are at most 2db and - * can be documented. - * - * NB: various calculations are based on the orinoco/wavelan - * drivers for compatibility - */ -static void set_quality(PRTMP_ADAPTER pAdapter, - struct iw_quality *iq, - signed char rssi) -{ - __u8 ChannelQuality; - - // Normalize Rssi - if (rssi >= -50) - ChannelQuality = 100; - else if (rssi >= -80) // between -50 ~ -80dbm - ChannelQuality = (__u8)(24 + ((rssi + 80) * 26)/10); - else if (rssi >= -90) // between -80 ~ -90dbm - ChannelQuality = (__u8)((rssi + 90) * 26)/10; - else - ChannelQuality = 0; - - iq->qual = (__u8)ChannelQuality; - - iq->level = (__u8)(rssi); - iq->noise = (pAdapter->BbpWriteLatch[66] > pAdapter->BbpTuning.FalseCcaUpperThreshold) ? ((__u8)pAdapter->BbpTuning.FalseCcaUpperThreshold) : ((__u8) pAdapter->BbpWriteLatch[66]); // noise level (dBm) - iq->noise += 256 - 143; - iq->updated = pAdapter->iw_stats.qual.updated; -} - -int rt_ioctl_iwaplist(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *extra) -{ - PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; - - struct sockaddr addr[IW_MAX_AP]; - struct iw_quality qual[IW_MAX_AP]; - int i; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - data->length = 0; - return 0; - //return -ENETDOWN; - } - - for (i = 0; i = pAdapter->ScanTab.BssNr) - break; - addr[i].sa_family = ARPHRD_ETHER; - memcpy(addr[i].sa_data, &pAdapter->ScanTab.BssEntry[i].Bssid, MAC_ADDR_LEN); - set_quality(pAdapter, &qual[i], pAdapter->ScanTab.BssEntry[i].Rssi); - } - data->length = i; - memcpy(extra, &addr, i*sizeof(addr[0])); - data->flags = 1; /* signal quality present (sort of) */ - memcpy(extra + i*sizeof(addr[0]), &qual, i*sizeof(qual[i])); - - return 0; -} - -#ifdef SIOCGIWSCAN -int rt_ioctl_siwscan(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *extra) -{ - PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; - - ULONG Now; - int Status = NDIS_STATUS_SUCCESS; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - if (MONITOR_ON(pAdapter)) - { - DBGPRINT(RT_DEBUG_TRACE, ("!!! Driver is in Monitor Mode now !!!\n")); - return -EINVAL; - } - - -#ifdef WPA_SUPPLICANT_SUPPORT - if (pAdapter->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_ENABLE) - { - pAdapter->StaCfg.WpaSupplicantScanCount++; - } -#endif // WPA_SUPPLICANT_SUPPORT // - - pAdapter->StaCfg.bScanReqIsFromWebUI = TRUE; - if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) - return 0; - do{ - Now = jiffies; - -#ifdef WPA_SUPPLICANT_SUPPORT - if ((pAdapter->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_ENABLE) && - (pAdapter->StaCfg.WpaSupplicantScanCount > 3)) - { - DBGPRINT(RT_DEBUG_TRACE, ("!!! WpaSupplicantScanCount > 3\n")); - Status = NDIS_STATUS_SUCCESS; - break; - } -#endif // WPA_SUPPLICANT_SUPPORT // - - if ((OPSTATUS_TEST_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED)) && - ((pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || - (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) && - (pAdapter->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED)) - { - DBGPRINT(RT_DEBUG_TRACE, ("!!! Link UP, Port Not Secured! ignore this set::OID_802_11_BSSID_LIST_SCAN\n")); - Status = NDIS_STATUS_SUCCESS; - break; - } - - if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) - { - RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); - DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); - } - - // tell CNTL state machine to call NdisMSetInformationComplete() after completing - // this request, because this request is initiated by NDIS. - pAdapter->MlmeAux.CurrReqIsFromNdis = FALSE; - // Reset allowed scan retries - pAdapter->StaCfg.ScanCnt = 0; - pAdapter->StaCfg.LastScanTime = Now; - - MlmeEnqueue(pAdapter, - MLME_CNTL_STATE_MACHINE, - OID_802_11_BSSID_LIST_SCAN, - 0, - NULL); - - Status = NDIS_STATUS_SUCCESS; - RT28XX_MLME_HANDLER(pAdapter); - }while(0); - return 0; -} - -int rt_ioctl_giwscan(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *extra) -{ - - PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; - int i=0; - char *current_ev = extra, *previous_ev = extra; - char *end_buf; - char *current_val, custom[MAX_CUSTOM_LEN] = {0}; -#ifndef IWEVGENIE - char idx; -#endif // IWEVGENIE // - struct iw_event iwe; - - if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) - { - /* - * Still scanning, indicate the caller should try again. - */ - return -EAGAIN; - } - - -#ifdef WPA_SUPPLICANT_SUPPORT - if (pAdapter->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_ENABLE) - { - pAdapter->StaCfg.WpaSupplicantScanCount = 0; - } -#endif // WPA_SUPPLICANT_SUPPORT // - - if (pAdapter->ScanTab.BssNr == 0) - { - data->length = 0; - return 0; - } - -#if WIRELESS_EXT >= 17 - if (data->length > 0) - end_buf = extra + data->length; - else - end_buf = extra + IW_SCAN_MAX_DATA; -#else - end_buf = extra + IW_SCAN_MAX_DATA; -#endif - - for (i = 0; i < pAdapter->ScanTab.BssNr; i++) - { - if (current_ev >= end_buf) - { -#if WIRELESS_EXT >= 17 - return -E2BIG; -#else - break; -#endif - } - - //MAC address - //================================ - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWAP; - iwe.u.ap_addr.sa_family = ARPHRD_ETHER; - memcpy(iwe.u.ap_addr.sa_data, &pAdapter->ScanTab.BssEntry[i].Bssid, ETH_ALEN); - - previous_ev = current_ev; - current_ev = IWE_STREAM_ADD_EVENT(info, current_ev,end_buf, &iwe, IW_EV_ADDR_LEN); - if (current_ev == previous_ev) -#if WIRELESS_EXT >= 17 - return -E2BIG; -#else - break; -#endif - - //ESSID - //================================ - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWESSID; - iwe.u.data.length = pAdapter->ScanTab.BssEntry[i].SsidLen; - iwe.u.data.flags = 1; - - previous_ev = current_ev; - current_ev = IWE_STREAM_ADD_POINT(info, current_ev,end_buf, &iwe, pAdapter->ScanTab.BssEntry[i].Ssid); - if (current_ev == previous_ev) -#if WIRELESS_EXT >= 17 - return -E2BIG; -#else - break; -#endif - - //Network Type - //================================ - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWMODE; - if (pAdapter->ScanTab.BssEntry[i].BssType == Ndis802_11IBSS) - { - iwe.u.mode = IW_MODE_ADHOC; - } - else if (pAdapter->ScanTab.BssEntry[i].BssType == Ndis802_11Infrastructure) - { - iwe.u.mode = IW_MODE_INFRA; - } - else - { - iwe.u.mode = IW_MODE_AUTO; - } - iwe.len = IW_EV_UINT_LEN; - - previous_ev = current_ev; - current_ev = IWE_STREAM_ADD_EVENT(info, current_ev, end_buf, &iwe, IW_EV_UINT_LEN); - if (current_ev == previous_ev) -#if WIRELESS_EXT >= 17 - return -E2BIG; -#else - break; -#endif - - //Channel and Frequency - //================================ - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWFREQ; - if (INFRA_ON(pAdapter) || ADHOC_ON(pAdapter)) - iwe.u.freq.m = pAdapter->ScanTab.BssEntry[i].Channel; - else - iwe.u.freq.m = pAdapter->ScanTab.BssEntry[i].Channel; - iwe.u.freq.e = 0; - iwe.u.freq.i = 0; - - previous_ev = current_ev; - current_ev = IWE_STREAM_ADD_EVENT(info, current_ev,end_buf, &iwe, IW_EV_FREQ_LEN); - if (current_ev == previous_ev) -#if WIRELESS_EXT >= 17 - return -E2BIG; -#else - break; -#endif - - //Add quality statistics - //================================ - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = IWEVQUAL; - iwe.u.qual.level = 0; - iwe.u.qual.noise = 0; - set_quality(pAdapter, &iwe.u.qual, pAdapter->ScanTab.BssEntry[i].Rssi); - current_ev = IWE_STREAM_ADD_EVENT(info, current_ev, end_buf, &iwe, IW_EV_QUAL_LEN); - if (current_ev == previous_ev) -#if WIRELESS_EXT >= 17 - return -E2BIG; -#else - break; -#endif - - //Encyption key - //================================ - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWENCODE; - if (CAP_IS_PRIVACY_ON (pAdapter->ScanTab.BssEntry[i].CapabilityInfo )) - iwe.u.data.flags =IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; - else - iwe.u.data.flags = IW_ENCODE_DISABLED; - - previous_ev = current_ev; - current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf,&iwe, (char *)pAdapter->SharedKey[BSS0][(iwe.u.data.flags & IW_ENCODE_INDEX)-1].Key); - if (current_ev == previous_ev) -#if WIRELESS_EXT >= 17 - return -E2BIG; -#else - break; -#endif - - //Bit Rate - //================================ - if (pAdapter->ScanTab.BssEntry[i].SupRateLen) - { - UCHAR tmpRate = pAdapter->ScanTab.BssEntry[i].SupRate[pAdapter->ScanTab.BssEntry[i].SupRateLen-1]; - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWRATE; - current_val = current_ev + IW_EV_LCP_LEN; - if (tmpRate == 0x82) - iwe.u.bitrate.value = 1 * 1000000; - else if (tmpRate == 0x84) - iwe.u.bitrate.value = 2 * 1000000; - else if (tmpRate == 0x8B) - iwe.u.bitrate.value = 5.5 * 1000000; - else if (tmpRate == 0x96) - iwe.u.bitrate.value = 11 * 1000000; - else - iwe.u.bitrate.value = (tmpRate/2) * 1000000; - - iwe.u.bitrate.disabled = 0; - current_val = IWE_STREAM_ADD_VALUE(info, current_ev, - current_val, end_buf, &iwe, - IW_EV_PARAM_LEN); - - if((current_val-current_ev)>IW_EV_LCP_LEN) - current_ev = current_val; - else -#if WIRELESS_EXT >= 17 - return -E2BIG; -#else - break; -#endif - } - -#ifdef IWEVGENIE - //WPA IE - if (pAdapter->ScanTab.BssEntry[i].WpaIE.IELen > 0) - { - memset(&iwe, 0, sizeof(iwe)); - memset(&custom[0], 0, MAX_CUSTOM_LEN); - memcpy(custom, &(pAdapter->ScanTab.BssEntry[i].WpaIE.IE[0]), - pAdapter->ScanTab.BssEntry[i].WpaIE.IELen); - iwe.cmd = IWEVGENIE; - iwe.u.data.length = pAdapter->ScanTab.BssEntry[i].WpaIE.IELen; - current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe, custom); - if (current_ev == previous_ev) -#if WIRELESS_EXT >= 17 - return -E2BIG; -#else - break; -#endif - } - - //WPA2 IE - if (pAdapter->ScanTab.BssEntry[i].RsnIE.IELen > 0) - { - memset(&iwe, 0, sizeof(iwe)); - memset(&custom[0], 0, MAX_CUSTOM_LEN); - memcpy(custom, &(pAdapter->ScanTab.BssEntry[i].RsnIE.IE[0]), - pAdapter->ScanTab.BssEntry[i].RsnIE.IELen); - iwe.cmd = IWEVGENIE; - iwe.u.data.length = pAdapter->ScanTab.BssEntry[i].RsnIE.IELen; - current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe, custom); - if (current_ev == previous_ev) -#if WIRELESS_EXT >= 17 - return -E2BIG; -#else - break; -#endif - } -#else - //WPA IE - //================================ - if (pAdapter->ScanTab.BssEntry[i].WpaIE.IELen > 0) - { - NdisZeroMemory(&iwe, sizeof(iwe)); - memset(&custom[0], 0, MAX_CUSTOM_LEN); - iwe.cmd = IWEVCUSTOM; - iwe.u.data.length = (pAdapter->ScanTab.BssEntry[i].WpaIE.IELen * 2) + 7; - NdisMoveMemory(custom, "wpa_ie=", 7); - for (idx = 0; idx < pAdapter->ScanTab.BssEntry[i].WpaIE.IELen; idx++) - sprintf(custom, "%s%02x", custom, pAdapter->ScanTab.BssEntry[i].WpaIE.IE[idx]); - previous_ev = current_ev; - current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe, custom); - if (current_ev == previous_ev) -#if WIRELESS_EXT >= 17 - return -E2BIG; -#else - break; -#endif - } - - //WPA2 IE - if (pAdapter->ScanTab.BssEntry[i].RsnIE.IELen > 0) - { - NdisZeroMemory(&iwe, sizeof(iwe)); - memset(&custom[0], 0, MAX_CUSTOM_LEN); - iwe.cmd = IWEVCUSTOM; - iwe.u.data.length = (pAdapter->ScanTab.BssEntry[i].RsnIE.IELen * 2) + 7; - NdisMoveMemory(custom, "rsn_ie=", 7); - for (idx = 0; idx < pAdapter->ScanTab.BssEntry[i].RsnIE.IELen; idx++) - sprintf(custom, "%s%02x", custom, pAdapter->ScanTab.BssEntry[i].RsnIE.IE[idx]); - previous_ev = current_ev; - current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe, custom); - if (current_ev == previous_ev) -#if WIRELESS_EXT >= 17 - return -E2BIG; -#else - break; -#endif - } -#endif // IWEVGENIE // - } - - data->length = current_ev - extra; - pAdapter->StaCfg.bScanReqIsFromWebUI = FALSE; - DBGPRINT(RT_DEBUG_ERROR ,("===>rt_ioctl_giwscan. %d(%d) BSS returned, data->length = %d\n",i , pAdapter->ScanTab.BssNr, data->length)); - return 0; -} -#endif - -int rt_ioctl_siwessid(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *essid) -{ - PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - if (data->flags) - { - PCHAR pSsidString = NULL; - - // Includes null character. - if (data->length > (IW_ESSID_MAX_SIZE + 1)) - return -E2BIG; - - pSsidString = (CHAR *) kmalloc(MAX_LEN_OF_SSID+1, MEM_ALLOC_FLAG); - if (pSsidString) - { - NdisZeroMemory(pSsidString, MAX_LEN_OF_SSID+1); - NdisMoveMemory(pSsidString, essid, data->length); - if (Set_SSID_Proc(pAdapter, pSsidString) == FALSE) - return -EINVAL; - } - else - return -ENOMEM; - } - else - { - // ANY ssid - if (Set_SSID_Proc(pAdapter, "") == FALSE) - return -EINVAL; - } - return 0; -} - -int rt_ioctl_giwessid(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *essid) -{ - PRTMP_ADAPTER pAdapter = NULL; - VIRTUAL_ADAPTER *pVirtualAd = NULL; - - if (dev->priv_flags == INT_MAIN) - { - pAdapter = dev->priv; - } - else - { - pVirtualAd = dev->priv; - if (pVirtualAd && pVirtualAd->RtmpDev) - pAdapter = pVirtualAd->RtmpDev->priv; - } - - if (pAdapter == NULL) - { - /* if 1st open fail, pAd will be free; - So the net_dev->priv will be NULL in 2rd open */ - return -ENETDOWN; - } - - data->flags = 1; - if (MONITOR_ON(pAdapter)) - { - data->length = 0; - return 0; - } - - if (OPSTATUS_TEST_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED)) - { - DBGPRINT(RT_DEBUG_TRACE ,("MediaState is connected\n")); - data->length = pAdapter->CommonCfg.SsidLen; - memcpy(essid, pAdapter->CommonCfg.Ssid, pAdapter->CommonCfg.SsidLen); - } -#ifdef RT2870 -#ifdef WPA_SUPPLICANT_SUPPORT - // Add for RT2870 - else if (pAdapter->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_DISABLE) - { - data->length = pAdapter->CommonCfg.SsidLen; - memcpy(essid, pAdapter->CommonCfg.Ssid, pAdapter->CommonCfg.SsidLen); - } -#endif // WPA_SUPPLICANT_SUPPORT // -#endif // RT2870 // - else - {//the ANY ssid was specified - data->length = 0; - DBGPRINT(RT_DEBUG_TRACE ,("MediaState is not connected, ess\n")); - } - - return 0; - -} - -int rt_ioctl_siwnickn(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *nickname) -{ - PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE ,("INFO::Network is down!\n")); - return -ENETDOWN; - } - - if (data->length > IW_ESSID_MAX_SIZE) - return -EINVAL; - - memset(pAdapter->nickname, 0, IW_ESSID_MAX_SIZE + 1); - memcpy(pAdapter->nickname, nickname, data->length); - - - return 0; -} - -int rt_ioctl_giwnickn(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *nickname) -{ - PRTMP_ADAPTER pAdapter = NULL; - VIRTUAL_ADAPTER *pVirtualAd = NULL; - - if (dev->priv_flags == INT_MAIN) - { - pAdapter = dev->priv; - } - else - { - pVirtualAd = dev->priv; - if (pVirtualAd && pVirtualAd->RtmpDev) - pAdapter = pVirtualAd->RtmpDev->priv; - } - - if (pAdapter == NULL) - { - /* if 1st open fail, pAd will be free; - So the net_dev->priv will be NULL in 2rd open */ - return -ENETDOWN; - } - - if (data->length > strlen(pAdapter->nickname) + 1) - data->length = strlen(pAdapter->nickname) + 1; - if (data->length > 0) { - memcpy(nickname, pAdapter->nickname, data->length-1); - nickname[data->length-1] = '\0'; - } - return 0; -} - -int rt_ioctl_siwrts(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *rts, char *extra) -{ - PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; - u16 val; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - if (rts->disabled) - val = MAX_RTS_THRESHOLD; - else if (rts->value < 0 || rts->value > MAX_RTS_THRESHOLD) - return -EINVAL; - else if (rts->value == 0) - val = MAX_RTS_THRESHOLD; - else - val = rts->value; - - if (val != pAdapter->CommonCfg.RtsThreshold) - pAdapter->CommonCfg.RtsThreshold = val; - - return 0; -} - -int rt_ioctl_giwrts(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *rts, char *extra) -{ - PRTMP_ADAPTER pAdapter = NULL; - VIRTUAL_ADAPTER *pVirtualAd = NULL; - - if (dev->priv_flags == INT_MAIN) - { - pAdapter = dev->priv; - } - else - { - pVirtualAd = dev->priv; - if (pVirtualAd && pVirtualAd->RtmpDev) - pAdapter = pVirtualAd->RtmpDev->priv; - } - - if (pAdapter == NULL) - { - /* if 1st open fail, pAd will be free; - So the net_dev->priv will be NULL in 2rd open */ - return -ENETDOWN; - } - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - rts->value = pAdapter->CommonCfg.RtsThreshold; - rts->disabled = (rts->value == MAX_RTS_THRESHOLD); - rts->fixed = 1; - - return 0; -} - -int rt_ioctl_siwfrag(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *frag, char *extra) -{ - PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; - u16 val; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - if (frag->disabled) - val = MAX_FRAG_THRESHOLD; - else if (frag->value >= MIN_FRAG_THRESHOLD || frag->value <= MAX_FRAG_THRESHOLD) - val = __cpu_to_le16(frag->value & ~0x1); /* even numbers only */ - else if (frag->value == 0) - val = MAX_FRAG_THRESHOLD; - else - return -EINVAL; - - pAdapter->CommonCfg.FragmentThreshold = val; - return 0; -} - -int rt_ioctl_giwfrag(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *frag, char *extra) -{ - PRTMP_ADAPTER pAdapter = NULL; - VIRTUAL_ADAPTER *pVirtualAd = NULL; - - if (dev->priv_flags == INT_MAIN) - { - pAdapter = dev->priv; - } - else - { - pVirtualAd = dev->priv; - if (pVirtualAd && pVirtualAd->RtmpDev) - pAdapter = pVirtualAd->RtmpDev->priv; - } - - if (pAdapter == NULL) - { - /* if 1st open fail, pAd will be free; - So the net_dev->priv will be NULL in 2rd open */ - return -ENETDOWN; - } - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - frag->value = pAdapter->CommonCfg.FragmentThreshold; - frag->disabled = (frag->value == MAX_FRAG_THRESHOLD); - frag->fixed = 1; - - return 0; -} - -#define MAX_WEP_KEY_SIZE 13 -#define MIN_WEP_KEY_SIZE 5 -int rt_ioctl_siwencode(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *erq, char *extra) -{ - PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - if ((erq->length == 0) && - (erq->flags & IW_ENCODE_DISABLED)) - { - pAdapter->StaCfg.PairCipher = Ndis802_11WEPDisabled; - pAdapter->StaCfg.GroupCipher = Ndis802_11WEPDisabled; - pAdapter->StaCfg.WepStatus = Ndis802_11WEPDisabled; - pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; - goto done; - } - else if ((erq->length == 0) && - (erq->flags & IW_ENCODE_RESTRICTED || erq->flags & IW_ENCODE_OPEN)) - { - //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; - STA_PORT_SECURED(pAdapter); - pAdapter->StaCfg.PairCipher = Ndis802_11WEPEnabled; - pAdapter->StaCfg.GroupCipher = Ndis802_11WEPEnabled; - pAdapter->StaCfg.WepStatus = Ndis802_11WEPEnabled; - pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; - if (erq->flags & IW_ENCODE_RESTRICTED) - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeShared; - else - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; - goto done; - } - - if (erq->length > 0) - { - int keyIdx = (erq->flags & IW_ENCODE_INDEX) - 1; - /* Check the size of the key */ - if (erq->length > MAX_WEP_KEY_SIZE) { - return -EINVAL; - } - /* Check key index */ - if ((keyIdx < 0) || (keyIdx >= NR_WEP_KEYS)) - { - DBGPRINT(RT_DEBUG_TRACE ,("==>rt_ioctl_siwencode::Wrong keyIdx=%d! Using default key instead (%d)\n", - keyIdx, pAdapter->StaCfg.DefaultKeyId)); - - //Using default key - keyIdx = pAdapter->StaCfg.DefaultKeyId; - } - - NdisZeroMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, 16); - - if (erq->length == MAX_WEP_KEY_SIZE) - { - pAdapter->SharedKey[BSS0][keyIdx].KeyLen = MAX_WEP_KEY_SIZE; - pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CIPHER_WEP128; - } - else if (erq->length == MIN_WEP_KEY_SIZE) - { - pAdapter->SharedKey[BSS0][keyIdx].KeyLen = MIN_WEP_KEY_SIZE; - pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CIPHER_WEP64; - } - else - /* Disable the key */ - pAdapter->SharedKey[BSS0][keyIdx].KeyLen = 0; - - /* Check if the key is not marked as invalid */ - if(!(erq->flags & IW_ENCODE_NOKEY)) { - /* Copy the key in the driver */ - NdisMoveMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, extra, erq->length); - } - } - else - { - /* Do we want to just set the transmit key index ? */ - int index = (erq->flags & IW_ENCODE_INDEX) - 1; - if ((index >= 0) && (index < 4)) - { - pAdapter->StaCfg.DefaultKeyId = index; - } - else - /* Don't complain if only change the mode */ - if(!erq->flags & IW_ENCODE_MODE) { - return -EINVAL; - } - } - -done: - DBGPRINT(RT_DEBUG_TRACE ,("==>rt_ioctl_siwencode::erq->flags=%x\n",erq->flags)); - DBGPRINT(RT_DEBUG_TRACE ,("==>rt_ioctl_siwencode::AuthMode=%x\n",pAdapter->StaCfg.AuthMode)); - DBGPRINT(RT_DEBUG_TRACE ,("==>rt_ioctl_siwencode::DefaultKeyId=%x, KeyLen = %d\n",pAdapter->StaCfg.DefaultKeyId , pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen)); - DBGPRINT(RT_DEBUG_TRACE ,("==>rt_ioctl_siwencode::WepStatus=%x\n",pAdapter->StaCfg.WepStatus)); - return 0; -} - -int -rt_ioctl_giwencode(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *erq, char *key) -{ - int kid; - PRTMP_ADAPTER pAdapter = NULL; - VIRTUAL_ADAPTER *pVirtualAd = NULL; - - if (dev->priv_flags == INT_MAIN) - { - pAdapter = dev->priv; - } - else - { - pVirtualAd = dev->priv; - if (pVirtualAd && pVirtualAd->RtmpDev) - pAdapter = pVirtualAd->RtmpDev->priv; - } - - if (pAdapter == NULL) - { - /* if 1st open fail, pAd will be free; - So the net_dev->priv will be NULL in 2rd open */ - return -ENETDOWN; - } - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - kid = erq->flags & IW_ENCODE_INDEX; - DBGPRINT(RT_DEBUG_TRACE, ("===>rt_ioctl_giwencode %d\n", erq->flags & IW_ENCODE_INDEX)); - - if (pAdapter->StaCfg.WepStatus == Ndis802_11WEPDisabled) - { - erq->length = 0; - erq->flags = IW_ENCODE_DISABLED; - } - else if ((kid > 0) && (kid <=4)) - { - // copy wep key - erq->flags = kid ; /* NB: base 1 */ - if (erq->length > pAdapter->SharedKey[BSS0][kid-1].KeyLen) - erq->length = pAdapter->SharedKey[BSS0][kid-1].KeyLen; - memcpy(key, pAdapter->SharedKey[BSS0][kid-1].Key, erq->length); - //if ((kid == pAdapter->PortCfg.DefaultKeyId)) - //erq->flags |= IW_ENCODE_ENABLED; /* XXX */ - if (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeShared) - erq->flags |= IW_ENCODE_RESTRICTED; /* XXX */ - else - erq->flags |= IW_ENCODE_OPEN; /* XXX */ - - } - else if (kid == 0) - { - if (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeShared) - erq->flags |= IW_ENCODE_RESTRICTED; /* XXX */ - else - erq->flags |= IW_ENCODE_OPEN; /* XXX */ - erq->length = pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen; - memcpy(key, pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].Key, erq->length); - // copy default key ID - if (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeShared) - erq->flags |= IW_ENCODE_RESTRICTED; /* XXX */ - else - erq->flags |= IW_ENCODE_OPEN; /* XXX */ - erq->flags = pAdapter->StaCfg.DefaultKeyId + 1; /* NB: base 1 */ - erq->flags |= IW_ENCODE_ENABLED; /* XXX */ - } - - return 0; - -} - -static int -rt_ioctl_setparam(struct net_device *dev, struct iw_request_info *info, - void *w, char *extra) -{ - VIRTUAL_ADAPTER *pVirtualAd = NULL; - PRTMP_ADAPTER pAdapter; - POS_COOKIE pObj; - char *this_char = extra; - char *value; - int Status=0; - - if (dev->priv_flags == INT_MAIN) - { - pAdapter = dev->priv; - } - else - { - pVirtualAd = dev->priv; - pAdapter = pVirtualAd->RtmpDev->priv; - } - pObj = (POS_COOKIE) pAdapter->OS_Cookie; - - if (pAdapter == NULL) - { - /* if 1st open fail, pAd will be free; - So the net_dev->priv will be NULL in 2rd open */ - return -ENETDOWN; - } - - { - pObj->ioctl_if_type = INT_MAIN; - pObj->ioctl_if = MAIN_MBSSID; - } - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - if (!*this_char) - return -EINVAL; - - if ((value = rtstrchr(this_char, '=')) != NULL) - *value++ = 0; - - if (!value) - return -EINVAL; - - // reject setting nothing besides ANY ssid(ssidLen=0) - if (!*value && (strcmp(this_char, "SSID") != 0)) - return -EINVAL; - - for (PRTMP_PRIVATE_SET_PROC = RTMP_PRIVATE_SUPPORT_PROC; PRTMP_PRIVATE_SET_PROC->name; PRTMP_PRIVATE_SET_PROC++) - { - if (strcmp(this_char, PRTMP_PRIVATE_SET_PROC->name) == 0) - { - if(!PRTMP_PRIVATE_SET_PROC->set_proc(pAdapter, value)) - { //FALSE:Set private failed then return Invalid argument - Status = -EINVAL; - } - break; //Exit for loop. - } - } - - if(PRTMP_PRIVATE_SET_PROC->name == NULL) - { //Not found argument - Status = -EINVAL; - DBGPRINT(RT_DEBUG_TRACE, ("===>rt_ioctl_setparam:: (iwpriv) Not Support Set Command [%s=%s]\n", this_char, value)); - } - - return Status; -} - - -static int -rt_private_get_statistics(struct net_device *dev, struct iw_request_info *info, - struct iw_point *wrq, char *extra) -{ - INT Status = 0; - PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; - - if (extra == NULL) - { - wrq->length = 0; - return -EIO; - } - - memset(extra, 0x00, IW_PRIV_SIZE_MASK); - sprintf(extra, "\n\n"); - -#ifdef RALINK_ATE - if (ATE_ON(pAd)) - { - sprintf(extra+strlen(extra), "Tx success = %ld\n", (ULONG)pAd->ate.TxDoneCount); - //sprintf(extra+strlen(extra), "Tx success without retry = %ld\n", (ULONG)pAd->ate.TxDoneCount); - } - else -#endif // RALINK_ATE // - { - sprintf(extra+strlen(extra), "Tx success = %ld\n", (ULONG)pAd->WlanCounters.TransmittedFragmentCount.QuadPart); - sprintf(extra+strlen(extra), "Tx success without retry = %ld\n", (ULONG)pAd->WlanCounters.TransmittedFragmentCount.QuadPart - (ULONG)pAd->WlanCounters.RetryCount.QuadPart); - } - sprintf(extra+strlen(extra), "Tx success after retry = %ld\n", (ULONG)pAd->WlanCounters.RetryCount.QuadPart); - sprintf(extra+strlen(extra), "Tx fail to Rcv ACK after retry = %ld\n", (ULONG)pAd->WlanCounters.FailedCount.QuadPart); - sprintf(extra+strlen(extra), "RTS Success Rcv CTS = %ld\n", (ULONG)pAd->WlanCounters.RTSSuccessCount.QuadPart); - sprintf(extra+strlen(extra), "RTS Fail Rcv CTS = %ld\n", (ULONG)pAd->WlanCounters.RTSFailureCount.QuadPart); - - sprintf(extra+strlen(extra), "Rx success = %ld\n", (ULONG)pAd->WlanCounters.ReceivedFragmentCount.QuadPart); - sprintf(extra+strlen(extra), "Rx with CRC = %ld\n", (ULONG)pAd->WlanCounters.FCSErrorCount.QuadPart); - sprintf(extra+strlen(extra), "Rx drop due to out of resource = %ld\n", (ULONG)pAd->Counters8023.RxNoBuffer); - sprintf(extra+strlen(extra), "Rx duplicate frame = %ld\n", (ULONG)pAd->WlanCounters.FrameDuplicateCount.QuadPart); - - sprintf(extra+strlen(extra), "False CCA (one second) = %ld\n", (ULONG)pAd->RalinkCounters.OneSecFalseCCACnt); -#ifdef RALINK_ATE - if (ATE_ON(pAd)) - { - if (pAd->ate.RxAntennaSel == 0) - { - sprintf(extra+strlen(extra), "RSSI-A = %ld\n", (LONG)(pAd->ate.LastRssi0 - pAd->BbpRssiToDbmDelta)); - sprintf(extra+strlen(extra), "RSSI-B (if available) = %ld\n", (LONG)(pAd->ate.LastRssi1 - pAd->BbpRssiToDbmDelta)); - sprintf(extra+strlen(extra), "RSSI-C (if available) = %ld\n\n", (LONG)(pAd->ate.LastRssi2 - pAd->BbpRssiToDbmDelta)); - } - else - { - sprintf(extra+strlen(extra), "RSSI = %ld\n", (LONG)(pAd->ate.LastRssi0 - pAd->BbpRssiToDbmDelta)); - } - } - else -#endif // RALINK_ATE // - { - sprintf(extra+strlen(extra), "RSSI-A = %ld\n", (LONG)(pAd->StaCfg.RssiSample.LastRssi0 - pAd->BbpRssiToDbmDelta)); - sprintf(extra+strlen(extra), "RSSI-B (if available) = %ld\n", (LONG)(pAd->StaCfg.RssiSample.LastRssi1 - pAd->BbpRssiToDbmDelta)); - sprintf(extra+strlen(extra), "RSSI-C (if available) = %ld\n\n", (LONG)(pAd->StaCfg.RssiSample.LastRssi2 - pAd->BbpRssiToDbmDelta)); - } -#ifdef WPA_SUPPLICANT_SUPPORT - sprintf(extra+strlen(extra), "WpaSupplicantUP = %d\n\n", pAd->StaCfg.WpaSupplicantUP); -#endif // WPA_SUPPLICANT_SUPPORT // - - - wrq->length = strlen(extra) + 1; // 1: size of '\0' - DBGPRINT(RT_DEBUG_TRACE, ("<== rt_private_get_statistics, wrq->length = %d\n", wrq->length)); - - return Status; -} - -#ifdef DOT11_N_SUPPORT -void getBaInfo( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pOutBuf) -{ - INT i, j; - BA_ORI_ENTRY *pOriBAEntry; - BA_REC_ENTRY *pRecBAEntry; - - for (i=0; iMacTab.Content[i]; - if (((pEntry->ValidAsCLI || pEntry->ValidAsApCli) && (pEntry->Sst == SST_ASSOC)) - || (pEntry->ValidAsWDS) || (pEntry->ValidAsMesh)) - { - sprintf(pOutBuf, "%s\n%02X:%02X:%02X:%02X:%02X:%02X (Aid = %d) (AP) -\n", - pOutBuf, - pEntry->Addr[0], pEntry->Addr[1], pEntry->Addr[2], - pEntry->Addr[3], pEntry->Addr[4], pEntry->Addr[5], pEntry->Aid); - - sprintf(pOutBuf, "%s[Recipient]\n", pOutBuf); - for (j=0; j < NUM_OF_TID; j++) - { - if (pEntry->BARecWcidArray[j] != 0) - { - pRecBAEntry =&pAd->BATable.BARecEntry[pEntry->BARecWcidArray[j]]; - sprintf(pOutBuf, "%sTID=%d, BAWinSize=%d, LastIndSeq=%d, ReorderingPkts=%d\n", pOutBuf, j, pRecBAEntry->BAWinSize, pRecBAEntry->LastIndSeq, pRecBAEntry->list.qlen); - } - } - sprintf(pOutBuf, "%s\n", pOutBuf); - - sprintf(pOutBuf, "%s[Originator]\n", pOutBuf); - for (j=0; j < NUM_OF_TID; j++) - { - if (pEntry->BAOriWcidArray[j] != 0) - { - pOriBAEntry =&pAd->BATable.BAOriEntry[pEntry->BAOriWcidArray[j]]; - sprintf(pOutBuf, "%sTID=%d, BAWinSize=%d, StartSeq=%d, CurTxSeq=%d\n", pOutBuf, j, pOriBAEntry->BAWinSize, pOriBAEntry->Sequence, pEntry->TxSeq[j]); - } - } - sprintf(pOutBuf, "%s\n\n", pOutBuf); - } - if (strlen(pOutBuf) > (IW_PRIV_SIZE_MASK - 30)) - break; - } - - return; -} -#endif // DOT11_N_SUPPORT // - -static int -rt_private_show(struct net_device *dev, struct iw_request_info *info, - struct iw_point *wrq, char *extra) -{ - INT Status = 0; - VIRTUAL_ADAPTER *pVirtualAd = NULL; - PRTMP_ADAPTER pAd; - POS_COOKIE pObj; - u32 subcmd = wrq->flags; - - if (dev->priv_flags == INT_MAIN) - pAd = dev->priv; - else - { - pVirtualAd = dev->priv; - pAd = pVirtualAd->RtmpDev->priv; - } - pObj = (POS_COOKIE) pAd->OS_Cookie; - - if (pAd == NULL) - { - /* if 1st open fail, pAd will be free; - So the net_dev->priv will be NULL in 2rd open */ - return -ENETDOWN; - } - - if (extra == NULL) - { - wrq->length = 0; - return -EIO; - } - memset(extra, 0x00, IW_PRIV_SIZE_MASK); - - { - pObj->ioctl_if_type = INT_MAIN; - pObj->ioctl_if = MAIN_MBSSID; - } - - switch(subcmd) - { - - case SHOW_CONN_STATUS: - if (MONITOR_ON(pAd)) - { -#ifdef DOT11_N_SUPPORT - if (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED && - pAd->CommonCfg.RegTransmitSetting.field.BW) - sprintf(extra, "Monitor Mode(CentralChannel %d)\n", pAd->CommonCfg.CentralChannel); - else -#endif // DOT11_N_SUPPORT // - sprintf(extra, "Monitor Mode(Channel %d)\n", pAd->CommonCfg.Channel); - } - else - { - if (pAd->IndicateMediaState == NdisMediaStateConnected) - { - if (INFRA_ON(pAd)) - { - sprintf(extra, "Connected(AP: %s[%02X:%02X:%02X:%02X:%02X:%02X])\n", - pAd->CommonCfg.Ssid, - pAd->CommonCfg.Bssid[0], - pAd->CommonCfg.Bssid[1], - pAd->CommonCfg.Bssid[2], - pAd->CommonCfg.Bssid[3], - pAd->CommonCfg.Bssid[4], - pAd->CommonCfg.Bssid[5]); - DBGPRINT(RT_DEBUG_TRACE ,("Ssid=%s ,Ssidlen = %d\n",pAd->CommonCfg.Ssid, pAd->CommonCfg.SsidLen)); - } - else if (ADHOC_ON(pAd)) - sprintf(extra, "Connected\n"); - } - else - { - sprintf(extra, "Disconnected\n"); - DBGPRINT(RT_DEBUG_TRACE ,("ConnStatus is not connected\n")); - } - } - wrq->length = strlen(extra) + 1; // 1: size of '\0' - break; - case SHOW_DRVIER_VERION: - sprintf(extra, "Driver version-%s, %s %s\n", STA_DRIVER_VERSION, __DATE__, __TIME__ ); - wrq->length = strlen(extra) + 1; // 1: size of '\0' - break; -#ifdef DOT11_N_SUPPORT - case SHOW_BA_INFO: - getBaInfo(pAd, extra); - wrq->length = strlen(extra) + 1; // 1: size of '\0' - break; -#endif // DOT11_N_SUPPORT // - case SHOW_DESC_INFO: - { - Show_DescInfo_Proc(pAd, NULL); - wrq->length = 0; // 1: size of '\0' - } - break; - case RAIO_OFF: - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) - { - sprintf(extra, "Scanning\n"); - wrq->length = strlen(extra) + 1; // 1: size of '\0' - break; - } - pAd->StaCfg.bSwRadio = FALSE; - if (pAd->StaCfg.bRadio != (pAd->StaCfg.bHwRadio && pAd->StaCfg.bSwRadio)) - { - pAd->StaCfg.bRadio = (pAd->StaCfg.bHwRadio && pAd->StaCfg.bSwRadio); - if (pAd->StaCfg.bRadio == FALSE) - { - MlmeRadioOff(pAd); - // Update extra information - pAd->ExtraInfo = SW_RADIO_OFF; - } - } - sprintf(extra, "Radio Off\n"); - wrq->length = strlen(extra) + 1; // 1: size of '\0' - break; - case RAIO_ON: - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) - { - sprintf(extra, "Scanning\n"); - wrq->length = strlen(extra) + 1; // 1: size of '\0' - break; - } - pAd->StaCfg.bSwRadio = TRUE; - //if (pAd->StaCfg.bRadio != (pAd->StaCfg.bHwRadio && pAd->StaCfg.bSwRadio)) - { - pAd->StaCfg.bRadio = (pAd->StaCfg.bHwRadio && pAd->StaCfg.bSwRadio); - if (pAd->StaCfg.bRadio == TRUE) - { - MlmeRadioOn(pAd); - // Update extra information - pAd->ExtraInfo = EXTRA_INFO_CLEAR; - } - } - sprintf(extra, "Radio On\n"); - wrq->length = strlen(extra) + 1; // 1: size of '\0' - break; - - -#ifdef QOS_DLS_SUPPORT - case SHOW_DLS_ENTRY_INFO: - { - Set_DlsEntryInfo_Display_Proc(pAd, NULL); - wrq->length = 0; // 1: size of '\0' - } - break; -#endif // QOS_DLS_SUPPORT // - - case SHOW_CFG_VALUE: - { - Status = RTMPShowCfgValue(pAd, wrq->pointer, extra); - if (Status == 0) - wrq->length = strlen(extra) + 1; // 1: size of '\0' - } - break; - case SHOW_ADHOC_ENTRY_INFO: - Show_Adhoc_MacTable_Proc(pAd, extra); - wrq->length = strlen(extra) + 1; // 1: size of '\0' - break; - default: - DBGPRINT(RT_DEBUG_TRACE, ("%s - unknow subcmd = %d\n", __func__, subcmd)); - break; - } - - return Status; -} - -#ifdef SIOCSIWMLME -int rt_ioctl_siwmlme(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; - struct iw_mlme *pMlme = (struct iw_mlme *)wrqu->data.pointer; - MLME_QUEUE_ELEM MsgElem; - MLME_DISASSOC_REQ_STRUCT DisAssocReq; - MLME_DEAUTH_REQ_STRUCT DeAuthReq; - - DBGPRINT(RT_DEBUG_TRACE, ("====> %s\n", __func__)); - - if (pMlme == NULL) - return -EINVAL; - - switch(pMlme->cmd) - { -#ifdef IW_MLME_DEAUTH - case IW_MLME_DEAUTH: - DBGPRINT(RT_DEBUG_TRACE, ("====> %s - IW_MLME_DEAUTH\n", __func__)); - COPY_MAC_ADDR(DeAuthReq.Addr, pAd->CommonCfg.Bssid); - DeAuthReq.Reason = pMlme->reason_code; - MsgElem.MsgLen = sizeof(MLME_DEAUTH_REQ_STRUCT); - NdisMoveMemory(MsgElem.Msg, &DeAuthReq, sizeof(MLME_DEAUTH_REQ_STRUCT)); - MlmeDeauthReqAction(pAd, &MsgElem); - if (INFRA_ON(pAd)) - { - LinkDown(pAd, FALSE); - pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; - } - break; -#endif // IW_MLME_DEAUTH // -#ifdef IW_MLME_DISASSOC - case IW_MLME_DISASSOC: - DBGPRINT(RT_DEBUG_TRACE, ("====> %s - IW_MLME_DISASSOC\n", __func__)); - COPY_MAC_ADDR(DisAssocReq.Addr, pAd->CommonCfg.Bssid); - DisAssocReq.Reason = pMlme->reason_code; - - MsgElem.Machine = ASSOC_STATE_MACHINE; - MsgElem.MsgType = MT2_MLME_DISASSOC_REQ; - MsgElem.MsgLen = sizeof(MLME_DISASSOC_REQ_STRUCT); - NdisMoveMemory(MsgElem.Msg, &DisAssocReq, sizeof(MLME_DISASSOC_REQ_STRUCT)); - - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_DISASSOC; - MlmeDisassocReqAction(pAd, &MsgElem); - break; -#endif // IW_MLME_DISASSOC // - default: - DBGPRINT(RT_DEBUG_TRACE, ("====> %s - Unknow Command\n", __func__)); - break; - } - - return 0; -} -#endif // SIOCSIWMLME // - -#if WIRELESS_EXT > 17 -int rt_ioctl_siwauth(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; - struct iw_param *param = &wrqu->param; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - switch (param->flags & IW_AUTH_INDEX) { - case IW_AUTH_WPA_VERSION: - if (param->value == IW_AUTH_WPA_VERSION_WPA) - { - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPAPSK; - if (pAdapter->StaCfg.BssType == BSS_ADHOC) - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPANone; - } - else if (param->value == IW_AUTH_WPA_VERSION_WPA2) - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA2PSK; - - DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_VERSION - param->value = %d!\n", __func__, param->value)); - break; - case IW_AUTH_CIPHER_PAIRWISE: - if (param->value == IW_AUTH_CIPHER_NONE) - { - pAdapter->StaCfg.WepStatus = Ndis802_11WEPDisabled; - pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; - pAdapter->StaCfg.PairCipher = Ndis802_11WEPDisabled; - } - else if (param->value == IW_AUTH_CIPHER_WEP40 || - param->value == IW_AUTH_CIPHER_WEP104) - { - pAdapter->StaCfg.WepStatus = Ndis802_11WEPEnabled; - pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; - pAdapter->StaCfg.PairCipher = Ndis802_11WEPEnabled; -#ifdef WPA_SUPPLICANT_SUPPORT - pAdapter->StaCfg.IEEE8021X = FALSE; -#endif // WPA_SUPPLICANT_SUPPORT // - } - else if (param->value == IW_AUTH_CIPHER_TKIP) - { - pAdapter->StaCfg.WepStatus = Ndis802_11Encryption2Enabled; - pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; - pAdapter->StaCfg.PairCipher = Ndis802_11Encryption2Enabled; - } - else if (param->value == IW_AUTH_CIPHER_CCMP) - { - pAdapter->StaCfg.WepStatus = Ndis802_11Encryption3Enabled; - pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; - pAdapter->StaCfg.PairCipher = Ndis802_11Encryption3Enabled; - } - DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_CIPHER_PAIRWISE - param->value = %d!\n", __func__, param->value)); - break; - case IW_AUTH_CIPHER_GROUP: - if (param->value == IW_AUTH_CIPHER_NONE) - { - pAdapter->StaCfg.GroupCipher = Ndis802_11WEPDisabled; - } - else if (param->value == IW_AUTH_CIPHER_WEP40 || - param->value == IW_AUTH_CIPHER_WEP104) - { - pAdapter->StaCfg.GroupCipher = Ndis802_11WEPEnabled; - } - else if (param->value == IW_AUTH_CIPHER_TKIP) - { - pAdapter->StaCfg.GroupCipher = Ndis802_11Encryption2Enabled; - } - else if (param->value == IW_AUTH_CIPHER_CCMP) - { - pAdapter->StaCfg.GroupCipher = Ndis802_11Encryption3Enabled; - } - DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_CIPHER_GROUP - param->value = %d!\n", __func__, param->value)); - break; - case IW_AUTH_KEY_MGMT: - if (param->value == IW_AUTH_KEY_MGMT_802_1X) - { - if (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) - { - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA; -#ifdef WPA_SUPPLICANT_SUPPORT - pAdapter->StaCfg.IEEE8021X = FALSE; -#endif // WPA_SUPPLICANT_SUPPORT // - } - else if (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) - { - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA2; -#ifdef WPA_SUPPLICANT_SUPPORT - pAdapter->StaCfg.IEEE8021X = FALSE; -#endif // WPA_SUPPLICANT_SUPPORT // - } -#ifdef WPA_SUPPLICANT_SUPPORT - else - // WEP 1x - pAdapter->StaCfg.IEEE8021X = TRUE; -#endif // WPA_SUPPLICANT_SUPPORT // - } - else if (param->value == 0) - { - //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; - STA_PORT_SECURED(pAdapter); - } - DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_KEY_MGMT - param->value = %d!\n", __func__, param->value)); - break; - case IW_AUTH_RX_UNENCRYPTED_EAPOL: - break; - case IW_AUTH_PRIVACY_INVOKED: - /*if (param->value == 0) - { - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; - pAdapter->StaCfg.WepStatus = Ndis802_11WEPDisabled; - pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; - pAdapter->StaCfg.PairCipher = Ndis802_11WEPDisabled; - pAdapter->StaCfg.GroupCipher = Ndis802_11WEPDisabled; - }*/ - DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_PRIVACY_INVOKED - param->value = %d!\n", __func__, param->value)); - break; - case IW_AUTH_DROP_UNENCRYPTED: - if (param->value != 0) - pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; - else - { - //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; - STA_PORT_SECURED(pAdapter); - } - DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_VERSION - param->value = %d!\n", __func__, param->value)); - break; - case IW_AUTH_80211_AUTH_ALG: - if (param->value & IW_AUTH_ALG_SHARED_KEY) - { - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeShared; - } - else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) - { - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; - } - else - return -EINVAL; - DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_80211_AUTH_ALG - param->value = %d!\n", __func__, param->value)); - break; - case IW_AUTH_WPA_ENABLED: - DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_ENABLED - Driver supports WPA!(param->value = %d)\n", __func__, param->value)); - break; - default: - return -EOPNOTSUPP; -} - - return 0; -} - -int rt_ioctl_giwauth(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; - struct iw_param *param = &wrqu->param; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - switch (param->flags & IW_AUTH_INDEX) { - case IW_AUTH_DROP_UNENCRYPTED: - param->value = (pAdapter->StaCfg.WepStatus == Ndis802_11WEPDisabled) ? 0 : 1; - break; - - case IW_AUTH_80211_AUTH_ALG: - param->value = (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeShared) ? IW_AUTH_ALG_SHARED_KEY : IW_AUTH_ALG_OPEN_SYSTEM; - break; - - case IW_AUTH_WPA_ENABLED: - param->value = (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ? 1 : 0; - break; - - default: - return -EOPNOTSUPP; - } - DBGPRINT(RT_DEBUG_TRACE, ("rt_ioctl_giwauth::param->value = %d!\n", param->value)); - return 0; -} - -void fnSetCipherKey( - IN PRTMP_ADAPTER pAdapter, - IN INT keyIdx, - IN UCHAR CipherAlg, - IN BOOLEAN bGTK, - IN struct iw_encode_ext *ext) -{ - NdisZeroMemory(&pAdapter->SharedKey[BSS0][keyIdx], sizeof(CIPHER_KEY)); - pAdapter->SharedKey[BSS0][keyIdx].KeyLen = LEN_TKIP_EK; - NdisMoveMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, ext->key, LEN_TKIP_EK); - NdisMoveMemory(pAdapter->SharedKey[BSS0][keyIdx].TxMic, ext->key + LEN_TKIP_EK, LEN_TKIP_TXMICK); - NdisMoveMemory(pAdapter->SharedKey[BSS0][keyIdx].RxMic, ext->key + LEN_TKIP_EK + LEN_TKIP_TXMICK, LEN_TKIP_RXMICK); - pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CipherAlg; - - // Update group key information to ASIC Shared Key Table - AsicAddSharedKeyEntry(pAdapter, - BSS0, - keyIdx, - pAdapter->SharedKey[BSS0][keyIdx].CipherAlg, - pAdapter->SharedKey[BSS0][keyIdx].Key, - pAdapter->SharedKey[BSS0][keyIdx].TxMic, - pAdapter->SharedKey[BSS0][keyIdx].RxMic); - - if (bGTK) - // Update ASIC WCID attribute table and IVEIV table - RTMPAddWcidAttributeEntry(pAdapter, - BSS0, - keyIdx, - pAdapter->SharedKey[BSS0][keyIdx].CipherAlg, - NULL); - else - // Update ASIC WCID attribute table and IVEIV table - RTMPAddWcidAttributeEntry(pAdapter, - BSS0, - keyIdx, - pAdapter->SharedKey[BSS0][keyIdx].CipherAlg, - &pAdapter->MacTab.Content[BSSID_WCID]); -} - -int rt_ioctl_siwencodeext(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) - { - PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; - struct iw_point *encoding = &wrqu->encoding; - struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; - int keyIdx, alg = ext->alg; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - if (encoding->flags & IW_ENCODE_DISABLED) - { - keyIdx = (encoding->flags & IW_ENCODE_INDEX) - 1; - // set BSSID wcid entry of the Pair-wise Key table as no-security mode - AsicRemovePairwiseKeyEntry(pAdapter, BSS0, BSSID_WCID); - pAdapter->SharedKey[BSS0][keyIdx].KeyLen = 0; - pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CIPHER_NONE; - AsicRemoveSharedKeyEntry(pAdapter, 0, (UCHAR)keyIdx); - NdisZeroMemory(&pAdapter->SharedKey[BSS0][keyIdx], sizeof(CIPHER_KEY)); - DBGPRINT(RT_DEBUG_TRACE, ("%s::Remove all keys!(encoding->flags = %x)\n", __func__, encoding->flags)); - } - else - { - // Get Key Index and convet to our own defined key index - keyIdx = (encoding->flags & IW_ENCODE_INDEX) - 1; - if((keyIdx < 0) || (keyIdx >= NR_WEP_KEYS)) - return -EINVAL; - - if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) - { - pAdapter->StaCfg.DefaultKeyId = keyIdx; - DBGPRINT(RT_DEBUG_TRACE, ("%s::DefaultKeyId = %d\n", __func__, pAdapter->StaCfg.DefaultKeyId)); - } - - switch (alg) { - case IW_ENCODE_ALG_NONE: - DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_NONE\n", __func__)); - break; - case IW_ENCODE_ALG_WEP: - DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_WEP - ext->key_len = %d, keyIdx = %d\n", __func__, ext->key_len, keyIdx)); - if (ext->key_len == MAX_WEP_KEY_SIZE) - { - pAdapter->SharedKey[BSS0][keyIdx].KeyLen = MAX_WEP_KEY_SIZE; - pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CIPHER_WEP128; - } - else if (ext->key_len == MIN_WEP_KEY_SIZE) - { - pAdapter->SharedKey[BSS0][keyIdx].KeyLen = MIN_WEP_KEY_SIZE; - pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CIPHER_WEP64; - } - else - return -EINVAL; - - NdisZeroMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, 16); - NdisMoveMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, ext->key, ext->key_len); - break; - case IW_ENCODE_ALG_TKIP: - DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_TKIP - keyIdx = %d, ext->key_len = %d\n", __func__, keyIdx, ext->key_len)); - if (ext->key_len == 32) - { - if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) - { - fnSetCipherKey(pAdapter, keyIdx, CIPHER_TKIP, FALSE, ext); - if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA2) - { - //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; - STA_PORT_SECURED(pAdapter); - } - } - else if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) - { - fnSetCipherKey(pAdapter, keyIdx, CIPHER_TKIP, TRUE, ext); - - // set 802.1x port control - //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; - STA_PORT_SECURED(pAdapter); - } - } - else - return -EINVAL; - break; - case IW_ENCODE_ALG_CCMP: - if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) - { - fnSetCipherKey(pAdapter, keyIdx, CIPHER_AES, FALSE, ext); - if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA2) - //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; - STA_PORT_SECURED(pAdapter); - } - else if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) - { - fnSetCipherKey(pAdapter, keyIdx, CIPHER_AES, TRUE, ext); - - // set 802.1x port control - //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; - STA_PORT_SECURED(pAdapter); - } - break; - default: - return -EINVAL; - } - } - - return 0; -} - -int -rt_ioctl_giwencodeext(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; - PCHAR pKey = NULL; - struct iw_point *encoding = &wrqu->encoding; - struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; - int idx, max_key_len; - - DBGPRINT(RT_DEBUG_TRACE ,("===> rt_ioctl_giwencodeext\n")); - - max_key_len = encoding->length - sizeof(*ext); - if (max_key_len < 0) - return -EINVAL; - - idx = encoding->flags & IW_ENCODE_INDEX; - if (idx) - { - if (idx < 1 || idx > 4) - return -EINVAL; - idx--; - - if ((pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) || - (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled)) - { - if (idx != pAd->StaCfg.DefaultKeyId) - { - ext->key_len = 0; - return 0; - } - } - } - else - idx = pAd->StaCfg.DefaultKeyId; - - encoding->flags = idx + 1; - memset(ext, 0, sizeof(*ext)); - - ext->key_len = 0; - switch(pAd->StaCfg.WepStatus) { - case Ndis802_11WEPDisabled: - ext->alg = IW_ENCODE_ALG_NONE; - encoding->flags |= IW_ENCODE_DISABLED; - break; - case Ndis802_11WEPEnabled: - ext->alg = IW_ENCODE_ALG_WEP; - if (pAd->SharedKey[BSS0][idx].KeyLen > max_key_len) - return -E2BIG; - else - { - ext->key_len = pAd->SharedKey[BSS0][idx].KeyLen; - pKey = &(pAd->SharedKey[BSS0][idx].Key[0]); - } - break; - case Ndis802_11Encryption2Enabled: - case Ndis802_11Encryption3Enabled: - if (pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) - ext->alg = IW_ENCODE_ALG_TKIP; - else - ext->alg = IW_ENCODE_ALG_CCMP; - - if (max_key_len < 32) - return -E2BIG; - else - { - ext->key_len = 32; - pKey = &pAd->StaCfg.PMK[0]; - } - break; - default: - return -EINVAL; - } - - if (ext->key_len && pKey) - { - encoding->flags |= IW_ENCODE_ENABLED; - memcpy(ext->key, pKey, ext->key_len); - } - - return 0; -} - -#ifdef SIOCSIWGENIE -int rt_ioctl_siwgenie(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; - - if (wrqu->data.length > MAX_LEN_OF_RSNIE || - (wrqu->data.length && extra == NULL)) - return -EINVAL; - - if (wrqu->data.length) - { - pAd->StaCfg.RSNIE_Len = wrqu->data.length; - NdisMoveMemory(&pAd->StaCfg.RSN_IE[0], extra, pAd->StaCfg.RSNIE_Len); - } - else - { - pAd->StaCfg.RSNIE_Len = 0; - NdisZeroMemory(&pAd->StaCfg.RSN_IE[0], MAX_LEN_OF_RSNIE); - } - - return 0; -} -#endif // SIOCSIWGENIE // - -int rt_ioctl_giwgenie(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; - - if ((pAd->StaCfg.RSNIE_Len == 0) || - (pAd->StaCfg.AuthMode < Ndis802_11AuthModeWPA)) - { - wrqu->data.length = 0; - return 0; - } - -#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT -#ifdef SIOCSIWGENIE - if (pAd->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_ENABLE) - { - if (wrqu->data.length < pAd->StaCfg.RSNIE_Len) - return -E2BIG; - - wrqu->data.length = pAd->StaCfg.RSNIE_Len; - memcpy(extra, &pAd->StaCfg.RSN_IE[0], pAd->StaCfg.RSNIE_Len); - } - else -#endif // SIOCSIWGENIE // -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // - { - UCHAR RSNIe = IE_WPA; - - if (wrqu->data.length < (pAd->StaCfg.RSNIE_Len + 2)) // ID, Len - return -E2BIG; - wrqu->data.length = pAd->StaCfg.RSNIE_Len + 2; - - if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) || - (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2)) - RSNIe = IE_RSN; - - extra[0] = (char)RSNIe; - extra[1] = pAd->StaCfg.RSNIE_Len; - memcpy(extra+2, &pAd->StaCfg.RSN_IE[0], pAd->StaCfg.RSNIE_Len); - } - - return 0; -} - -int rt_ioctl_siwpmksa(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; - struct iw_pmksa *pPmksa = (struct iw_pmksa *)wrqu->data.pointer; - INT CachedIdx = 0, idx = 0; - - if (pPmksa == NULL) - return -EINVAL; - - DBGPRINT(RT_DEBUG_TRACE ,("===> rt_ioctl_siwpmksa\n")); - switch(pPmksa->cmd) - { - case IW_PMKSA_FLUSH: - NdisZeroMemory(pAd->StaCfg.SavedPMK, sizeof(BSSID_INFO)*PMKID_NO); - DBGPRINT(RT_DEBUG_TRACE ,("rt_ioctl_siwpmksa - IW_PMKSA_FLUSH\n")); - break; - case IW_PMKSA_REMOVE: - for (CachedIdx = 0; CachedIdx < pAd->StaCfg.SavedPMKNum; CachedIdx++) - { - // compare the BSSID - if (NdisEqualMemory(pPmksa->bssid.sa_data, pAd->StaCfg.SavedPMK[CachedIdx].BSSID, MAC_ADDR_LEN)) - { - NdisZeroMemory(pAd->StaCfg.SavedPMK[CachedIdx].BSSID, MAC_ADDR_LEN); - NdisZeroMemory(pAd->StaCfg.SavedPMK[CachedIdx].PMKID, 16); - for (idx = CachedIdx; idx < (pAd->StaCfg.SavedPMKNum - 1); idx++) - { - NdisMoveMemory(&pAd->StaCfg.SavedPMK[idx].BSSID[0], &pAd->StaCfg.SavedPMK[idx+1].BSSID[0], MAC_ADDR_LEN); - NdisMoveMemory(&pAd->StaCfg.SavedPMK[idx].PMKID[0], &pAd->StaCfg.SavedPMK[idx+1].PMKID[0], 16); - } - pAd->StaCfg.SavedPMKNum--; - break; - } - } - - DBGPRINT(RT_DEBUG_TRACE ,("rt_ioctl_siwpmksa - IW_PMKSA_REMOVE\n")); - break; - case IW_PMKSA_ADD: - for (CachedIdx = 0; CachedIdx < pAd->StaCfg.SavedPMKNum; CachedIdx++) - { - // compare the BSSID - if (NdisEqualMemory(pPmksa->bssid.sa_data, pAd->StaCfg.SavedPMK[CachedIdx].BSSID, MAC_ADDR_LEN)) - break; - } - - // Found, replace it - if (CachedIdx < PMKID_NO) - { - DBGPRINT(RT_DEBUG_OFF, ("Update PMKID, idx = %d\n", CachedIdx)); - NdisMoveMemory(&pAd->StaCfg.SavedPMK[CachedIdx].BSSID[0], pPmksa->bssid.sa_data, MAC_ADDR_LEN); - NdisMoveMemory(&pAd->StaCfg.SavedPMK[CachedIdx].PMKID[0], pPmksa->pmkid, 16); - pAd->StaCfg.SavedPMKNum++; - } - // Not found, replace the last one - else - { - // Randomly replace one - CachedIdx = (pPmksa->bssid.sa_data[5] % PMKID_NO); - DBGPRINT(RT_DEBUG_OFF, ("Update PMKID, idx = %d\n", CachedIdx)); - NdisMoveMemory(&pAd->StaCfg.SavedPMK[CachedIdx].BSSID[0], pPmksa->bssid.sa_data, MAC_ADDR_LEN); - NdisMoveMemory(&pAd->StaCfg.SavedPMK[CachedIdx].PMKID[0], pPmksa->pmkid, 16); - } - - DBGPRINT(RT_DEBUG_TRACE ,("rt_ioctl_siwpmksa - IW_PMKSA_ADD\n")); - break; - default: - DBGPRINT(RT_DEBUG_TRACE ,("rt_ioctl_siwpmksa - Unknow Command!!\n")); - break; - } - - return 0; -} -#endif // #if WIRELESS_EXT > 17 - -#ifdef DBG -static int -rt_private_ioctl_bbp(struct net_device *dev, struct iw_request_info *info, - struct iw_point *wrq, char *extra) - { - CHAR *this_char; - CHAR *value = NULL; - UCHAR regBBP = 0; -// CHAR arg[255]={0}; - UINT32 bbpId; - UINT32 bbpValue; - BOOLEAN bIsPrintAllBBP = FALSE; - INT Status = 0; - PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; - - - memset(extra, 0x00, IW_PRIV_SIZE_MASK); - - if (wrq->length > 1) //No parameters. - { - sprintf(extra, "\n"); - - //Parsing Read or Write - this_char = wrq->pointer; - DBGPRINT(RT_DEBUG_TRACE, ("this_char=%s\n", this_char)); - if (!*this_char) - goto next; - - if ((value = rtstrchr(this_char, '=')) != NULL) - *value++ = 0; - - if (!value || !*value) - { //Read - DBGPRINT(RT_DEBUG_TRACE, ("this_char=%s, value=%s\n", this_char, value)); - if (sscanf(this_char, "%d", &(bbpId)) == 1) - { - if (bbpId <= 136) - { -#ifdef RALINK_ATE - if (ATE_ON(pAdapter)) - { - ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); - } - else -#endif // RALINK_ATE // - { - RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); - } - sprintf(extra+strlen(extra), "R%02d[0x%02X]:%02X\n", bbpId, bbpId*2, regBBP); - wrq->length = strlen(extra) + 1; // 1: size of '\0' - DBGPRINT(RT_DEBUG_TRACE, ("msg=%s\n", extra)); - } - else - {//Invalid parametes, so default printk all bbp - bIsPrintAllBBP = TRUE; - goto next; - } - } - else - { //Invalid parametes, so default printk all bbp - bIsPrintAllBBP = TRUE; - goto next; - } - } - else - { //Write - if ((sscanf(this_char, "%d", &(bbpId)) == 1) && (sscanf(value, "%x", &(bbpValue)) == 1)) - { - if (bbpId <= 136) - { -#ifdef RALINK_ATE - if (ATE_ON(pAdapter)) - { - ATE_BBP_IO_WRITE8_BY_REG_ID(pAdapter, bbpId, bbpValue); - //Read it back for showing - ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); - } - else -#endif // RALINK_ATE // - { - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, bbpId, bbpValue); - //Read it back for showing - RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); - } - sprintf(extra+strlen(extra), "R%02d[0x%02X]:%02X\n", bbpId, bbpId*2, regBBP); - wrq->length = strlen(extra) + 1; // 1: size of '\0' - DBGPRINT(RT_DEBUG_TRACE, ("msg=%s\n", extra)); - } - else - {//Invalid parametes, so default printk all bbp - bIsPrintAllBBP = TRUE; - goto next; - } - } - else - { //Invalid parametes, so default printk all bbp - bIsPrintAllBBP = TRUE; - goto next; - } - } - } - else - bIsPrintAllBBP = TRUE; - -next: - if (bIsPrintAllBBP) - { - memset(extra, 0x00, IW_PRIV_SIZE_MASK); - sprintf(extra, "\n"); - for (bbpId = 0; bbpId <= 136; bbpId++) - { - if (strlen(extra) >= (IW_PRIV_SIZE_MASK - 10)) - break; -#ifdef RALINK_ATE - if (ATE_ON(pAdapter)) - { - ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); - } - else -#endif // RALINK_ATE // - RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); - sprintf(extra+strlen(extra), "R%02d[0x%02X]:%02X ", bbpId, bbpId*2, regBBP); - if (bbpId%5 == 4) - sprintf(extra+strlen(extra), "\n"); - } - - wrq->length = strlen(extra) + 1; // 1: size of '\0' - DBGPRINT(RT_DEBUG_TRACE, ("wrq->length = %d\n", wrq->length)); - } - - DBGPRINT(RT_DEBUG_TRACE, ("<==rt_private_ioctl_bbp\n\n")); - - return Status; -} -#endif // DBG // - -int rt_ioctl_siwrate(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; - UINT32 rate = wrqu->bitrate.value, fixed = wrqu->bitrate.fixed; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("rt_ioctl_siwrate::Network is down!\n")); - return -ENETDOWN; - } - - DBGPRINT(RT_DEBUG_TRACE, ("rt_ioctl_siwrate::(rate = %d, fixed = %d)\n", rate, fixed)); - /* rate = -1 => auto rate - rate = X, fixed = 1 => (fixed rate X) - */ - if (rate == -1) - { - //Auto Rate - pAd->StaCfg.DesiredTransmitSetting.field.MCS = MCS_AUTO; - pAd->StaCfg.bAutoTxRateSwitch = TRUE; - if ((pAd->CommonCfg.PhyMode <= PHY_11G) || - (pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MODE <= MODE_OFDM)) - RTMPSetDesiredRates(pAd, -1); - -#ifdef DOT11_N_SUPPORT - SetCommonHT(pAd); -#endif // DOT11_N_SUPPORT // - } - else - { - if (fixed) - { - pAd->StaCfg.bAutoTxRateSwitch = FALSE; - if ((pAd->CommonCfg.PhyMode <= PHY_11G) || - (pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MODE <= MODE_OFDM)) - RTMPSetDesiredRates(pAd, rate); - else - { - pAd->StaCfg.DesiredTransmitSetting.field.MCS = MCS_AUTO; -#ifdef DOT11_N_SUPPORT - SetCommonHT(pAd); -#endif // DOT11_N_SUPPORT // - } - DBGPRINT(RT_DEBUG_TRACE, ("rt_ioctl_siwrate::(HtMcs=%d)\n",pAd->StaCfg.DesiredTransmitSetting.field.MCS)); - } - else - { - // TODO: rate = X, fixed = 0 => (rates <= X) - return -EOPNOTSUPP; - } - } - - return 0; -} - -int rt_ioctl_giwrate(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; - int rate_index = 0, rate_count = 0; - HTTRANSMIT_SETTING ht_setting; - __s32 ralinkrate[] = - {2, 4, 11, 22, // CCK - 12, 18, 24, 36, 48, 72, 96, 108, // OFDM - 13, 26, 39, 52, 78, 104, 117, 130, 26, 52, 78, 104, 156, 208, 234, 260, // 20MHz, 800ns GI, MCS: 0 ~ 15 - 39, 78, 117, 156, 234, 312, 351, 390, // 20MHz, 800ns GI, MCS: 16 ~ 23 - 27, 54, 81, 108, 162, 216, 243, 270, 54, 108, 162, 216, 324, 432, 486, 540, // 40MHz, 800ns GI, MCS: 0 ~ 15 - 81, 162, 243, 324, 486, 648, 729, 810, // 40MHz, 800ns GI, MCS: 16 ~ 23 - 14, 29, 43, 57, 87, 115, 130, 144, 29, 59, 87, 115, 173, 230, 260, 288, // 20MHz, 400ns GI, MCS: 0 ~ 15 - 43, 87, 130, 173, 260, 317, 390, 433, // 20MHz, 400ns GI, MCS: 16 ~ 23 - 30, 60, 90, 120, 180, 240, 270, 300, 60, 120, 180, 240, 360, 480, 540, 600, // 40MHz, 400ns GI, MCS: 0 ~ 15 - 90, 180, 270, 360, 540, 720, 810, 900}; // 40MHz, 400ns GI, MCS: 16 ~ 23 - - rate_count = sizeof(ralinkrate)/sizeof(__s32); - //check if the interface is down - if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - if ((pAd->StaCfg.bAutoTxRateSwitch == FALSE) && - (INFRA_ON(pAd)) && - ((pAd->CommonCfg.PhyMode <= PHY_11G) || (pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MODE <= MODE_OFDM))) - ht_setting.word = pAd->StaCfg.HTPhyMode.word; - else - ht_setting.word = pAd->MacTab.Content[BSSID_WCID].HTPhyMode.word; - -#ifdef DOT11_N_SUPPORT - if (ht_setting.field.MODE >= MODE_HTMIX) - { -// rate_index = 12 + ((UCHAR)ht_setting.field.BW *16) + ((UCHAR)ht_setting.field.ShortGI *32) + ((UCHAR)ht_setting.field.MCS); - rate_index = 12 + ((UCHAR)ht_setting.field.BW *24) + ((UCHAR)ht_setting.field.ShortGI *48) + ((UCHAR)ht_setting.field.MCS); - } - else -#endif // DOT11_N_SUPPORT // - if (ht_setting.field.MODE == MODE_OFDM) - rate_index = (UCHAR)(ht_setting.field.MCS) + 4; - else if (ht_setting.field.MODE == MODE_CCK) - rate_index = (UCHAR)(ht_setting.field.MCS); - - if (rate_index < 0) - rate_index = 0; - - if (rate_index > rate_count) - rate_index = rate_count; - - wrqu->bitrate.value = ralinkrate[rate_index] * 500000; - wrqu->bitrate.disabled = 0; - - return 0; -} - -static const iw_handler rt_handler[] = -{ - (iw_handler) NULL, /* SIOCSIWCOMMIT */ - (iw_handler) rt_ioctl_giwname, /* SIOCGIWNAME */ - (iw_handler) NULL, /* SIOCSIWNWID */ - (iw_handler) NULL, /* SIOCGIWNWID */ - (iw_handler) rt_ioctl_siwfreq, /* SIOCSIWFREQ */ - (iw_handler) rt_ioctl_giwfreq, /* SIOCGIWFREQ */ - (iw_handler) rt_ioctl_siwmode, /* SIOCSIWMODE */ - (iw_handler) rt_ioctl_giwmode, /* SIOCGIWMODE */ - (iw_handler) NULL, /* SIOCSIWSENS */ - (iw_handler) NULL, /* SIOCGIWSENS */ - (iw_handler) NULL /* not used */, /* SIOCSIWRANGE */ - (iw_handler) rt_ioctl_giwrange, /* SIOCGIWRANGE */ - (iw_handler) NULL /* not used */, /* SIOCSIWPRIV */ - (iw_handler) NULL /* kernel code */, /* SIOCGIWPRIV */ - (iw_handler) NULL /* not used */, /* SIOCSIWSTATS */ - (iw_handler) rt28xx_get_wireless_stats /* kernel code */, /* SIOCGIWSTATS */ - (iw_handler) NULL, /* SIOCSIWSPY */ - (iw_handler) NULL, /* SIOCGIWSPY */ - (iw_handler) NULL, /* SIOCSIWTHRSPY */ - (iw_handler) NULL, /* SIOCGIWTHRSPY */ - (iw_handler) rt_ioctl_siwap, /* SIOCSIWAP */ - (iw_handler) rt_ioctl_giwap, /* SIOCGIWAP */ -#ifdef SIOCSIWMLME - (iw_handler) rt_ioctl_siwmlme, /* SIOCSIWMLME */ -#else - (iw_handler) NULL, /* SIOCSIWMLME */ -#endif // SIOCSIWMLME // - (iw_handler) rt_ioctl_iwaplist, /* SIOCGIWAPLIST */ -#ifdef SIOCGIWSCAN - (iw_handler) rt_ioctl_siwscan, /* SIOCSIWSCAN */ - (iw_handler) rt_ioctl_giwscan, /* SIOCGIWSCAN */ -#else - (iw_handler) NULL, /* SIOCSIWSCAN */ - (iw_handler) NULL, /* SIOCGIWSCAN */ -#endif /* SIOCGIWSCAN */ - (iw_handler) rt_ioctl_siwessid, /* SIOCSIWESSID */ - (iw_handler) rt_ioctl_giwessid, /* SIOCGIWESSID */ - (iw_handler) rt_ioctl_siwnickn, /* SIOCSIWNICKN */ - (iw_handler) rt_ioctl_giwnickn, /* SIOCGIWNICKN */ - (iw_handler) NULL, /* -- hole -- */ - (iw_handler) NULL, /* -- hole -- */ - (iw_handler) rt_ioctl_siwrate, /* SIOCSIWRATE */ - (iw_handler) rt_ioctl_giwrate, /* SIOCGIWRATE */ - (iw_handler) rt_ioctl_siwrts, /* SIOCSIWRTS */ - (iw_handler) rt_ioctl_giwrts, /* SIOCGIWRTS */ - (iw_handler) rt_ioctl_siwfrag, /* SIOCSIWFRAG */ - (iw_handler) rt_ioctl_giwfrag, /* SIOCGIWFRAG */ - (iw_handler) NULL, /* SIOCSIWTXPOW */ - (iw_handler) NULL, /* SIOCGIWTXPOW */ - (iw_handler) NULL, /* SIOCSIWRETRY */ - (iw_handler) NULL, /* SIOCGIWRETRY */ - (iw_handler) rt_ioctl_siwencode, /* SIOCSIWENCODE */ - (iw_handler) rt_ioctl_giwencode, /* SIOCGIWENCODE */ - (iw_handler) NULL, /* SIOCSIWPOWER */ - (iw_handler) NULL, /* SIOCGIWPOWER */ - (iw_handler) NULL, /* -- hole -- */ - (iw_handler) NULL, /* -- hole -- */ -#if WIRELESS_EXT > 17 - (iw_handler) rt_ioctl_siwgenie, /* SIOCSIWGENIE */ - (iw_handler) rt_ioctl_giwgenie, /* SIOCGIWGENIE */ - (iw_handler) rt_ioctl_siwauth, /* SIOCSIWAUTH */ - (iw_handler) rt_ioctl_giwauth, /* SIOCGIWAUTH */ - (iw_handler) rt_ioctl_siwencodeext, /* SIOCSIWENCODEEXT */ - (iw_handler) rt_ioctl_giwencodeext, /* SIOCGIWENCODEEXT */ - (iw_handler) rt_ioctl_siwpmksa, /* SIOCSIWPMKSA */ -#endif -}; - -static const iw_handler rt_priv_handlers[] = { - (iw_handler) NULL, /* + 0x00 */ - (iw_handler) NULL, /* + 0x01 */ -#ifndef CONFIG_AP_SUPPORT - (iw_handler) rt_ioctl_setparam, /* + 0x02 */ -#else - (iw_handler) NULL, /* + 0x02 */ -#endif // CONFIG_AP_SUPPORT // -#ifdef DBG - (iw_handler) rt_private_ioctl_bbp, /* + 0x03 */ -#else - (iw_handler) NULL, /* + 0x03 */ -#endif - (iw_handler) NULL, /* + 0x04 */ - (iw_handler) NULL, /* + 0x05 */ - (iw_handler) NULL, /* + 0x06 */ - (iw_handler) NULL, /* + 0x07 */ - (iw_handler) NULL, /* + 0x08 */ - (iw_handler) rt_private_get_statistics, /* + 0x09 */ - (iw_handler) NULL, /* + 0x0A */ - (iw_handler) NULL, /* + 0x0B */ - (iw_handler) NULL, /* + 0x0C */ - (iw_handler) NULL, /* + 0x0D */ - (iw_handler) NULL, /* + 0x0E */ - (iw_handler) NULL, /* + 0x0F */ - (iw_handler) NULL, /* + 0x10 */ - (iw_handler) rt_private_show, /* + 0x11 */ - (iw_handler) NULL, /* + 0x12 */ - (iw_handler) NULL, /* + 0x13 */ - (iw_handler) NULL, /* + 0x15 */ - (iw_handler) NULL, /* + 0x17 */ - (iw_handler) NULL, /* + 0x18 */ -}; - -const struct iw_handler_def rt28xx_iw_handler_def = -{ -#define N(a) (sizeof (a) / sizeof (a[0])) - .standard = (iw_handler *) rt_handler, - .num_standard = sizeof(rt_handler) / sizeof(iw_handler), - .private = (iw_handler *) rt_priv_handlers, - .num_private = N(rt_priv_handlers), - .private_args = (struct iw_priv_args *) privtab, - .num_private_args = N(privtab), -#if IW_HANDLER_VERSION >= 7 - .get_wireless_stats = rt28xx_get_wireless_stats, -#endif -}; - -INT RTMPSetInformation( - IN PRTMP_ADAPTER pAdapter, - IN OUT struct ifreq *rq, - IN INT cmd) -{ - struct iwreq *wrq = (struct iwreq *) rq; - NDIS_802_11_SSID Ssid; - NDIS_802_11_MAC_ADDRESS Bssid; - RT_802_11_PHY_MODE PhyMode; - RT_802_11_STA_CONFIG StaConfig; - NDIS_802_11_RATES aryRates; - RT_802_11_PREAMBLE Preamble; - NDIS_802_11_WEP_STATUS WepStatus; - NDIS_802_11_AUTHENTICATION_MODE AuthMode = Ndis802_11AuthModeMax; - NDIS_802_11_NETWORK_INFRASTRUCTURE BssType; - NDIS_802_11_RTS_THRESHOLD RtsThresh; - NDIS_802_11_FRAGMENTATION_THRESHOLD FragThresh; - NDIS_802_11_POWER_MODE PowerMode; - PNDIS_802_11_KEY pKey = NULL; - PNDIS_802_11_WEP pWepKey =NULL; - PNDIS_802_11_REMOVE_KEY pRemoveKey = NULL; - NDIS_802_11_CONFIGURATION Config, *pConfig = NULL; - NDIS_802_11_NETWORK_TYPE NetType; - ULONG Now; - UINT KeyIdx = 0; - INT Status = NDIS_STATUS_SUCCESS, MaxPhyMode = PHY_11G; - ULONG PowerTemp; - BOOLEAN RadioState; - BOOLEAN StateMachineTouched = FALSE; -#ifdef DOT11_N_SUPPORT - OID_SET_HT_PHYMODE HT_PhyMode; //11n ,kathy -#endif // DOT11_N_SUPPORT // -#ifdef WPA_SUPPLICANT_SUPPORT - PNDIS_802_11_PMKID pPmkId = NULL; - BOOLEAN IEEE8021xState = FALSE; - BOOLEAN IEEE8021x_required_keys = FALSE; - UCHAR wpa_supplicant_enable = 0; -#endif // WPA_SUPPLICANT_SUPPORT // - -#ifdef SNMP_SUPPORT - TX_RTY_CFG_STRUC tx_rty_cfg; - ULONG ShortRetryLimit, LongRetryLimit; - UCHAR ctmp; -#endif // SNMP_SUPPORT // - - - -#ifdef DOT11_N_SUPPORT - MaxPhyMode = PHY_11N_5G; -#endif // DOT11_N_SUPPORT // - - - DBGPRINT(RT_DEBUG_TRACE, ("-->RTMPSetInformation(), 0x%08x\n", cmd&0x7FFF)); - switch(cmd & 0x7FFF) { - case RT_OID_802_11_COUNTRY_REGION: - if (wrq->u.data.length < sizeof(UCHAR)) - Status = -EINVAL; - // Only avaliable when EEPROM not programming - else if (!(pAdapter->CommonCfg.CountryRegion & 0x80) && !(pAdapter->CommonCfg.CountryRegionForABand & 0x80)) - { - ULONG Country; - UCHAR TmpPhy; - - Status = copy_from_user(&Country, wrq->u.data.pointer, wrq->u.data.length); - pAdapter->CommonCfg.CountryRegion = (UCHAR)(Country & 0x000000FF); - pAdapter->CommonCfg.CountryRegionForABand = (UCHAR)((Country >> 8) & 0x000000FF); - TmpPhy = pAdapter->CommonCfg.PhyMode; - pAdapter->CommonCfg.PhyMode = 0xff; - // Build all corresponding channel information - RTMPSetPhyMode(pAdapter, TmpPhy); -#ifdef DOT11_N_SUPPORT - SetCommonHT(pAdapter); -#endif // DOT11_N_SUPPORT // - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_COUNTRY_REGION (A:%d B/G:%d)\n", pAdapter->CommonCfg.CountryRegionForABand, - pAdapter->CommonCfg.CountryRegion)); - } - break; - case OID_802_11_BSSID_LIST_SCAN: - #ifdef RALINK_ATE - if (ATE_ON(pAdapter)) - { - DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now\n")); - break; - } -#endif // RALINK_ATE // - Now = jiffies; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_BSSID_LIST_SCAN, TxCnt = %d \n", pAdapter->RalinkCounters.LastOneSecTotalTxCount)); - - if (MONITOR_ON(pAdapter)) - { - DBGPRINT(RT_DEBUG_TRACE, ("!!! Driver is in Monitor Mode now !!!\n")); - break; - } - - //Benson add 20080527, when radio off, sta don't need to scan - if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RADIO_OFF)) - break; - - if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) - { - DBGPRINT(RT_DEBUG_TRACE, ("!!! Driver is scanning now !!!\n")); - pAdapter->StaCfg.bScanReqIsFromWebUI = TRUE; - Status = NDIS_STATUS_SUCCESS; - break; - } - - if (pAdapter->RalinkCounters.LastOneSecTotalTxCount > 100) - { - DBGPRINT(RT_DEBUG_TRACE, ("!!! Link UP, ignore this set::OID_802_11_BSSID_LIST_SCAN\n")); - Status = NDIS_STATUS_SUCCESS; - pAdapter->StaCfg.ScanCnt = 99; // Prevent auto scan triggered by this OID - break; - } - - if ((OPSTATUS_TEST_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED)) && - ((pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || - (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) || - (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || - (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)) && - (pAdapter->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED)) - { - DBGPRINT(RT_DEBUG_TRACE, ("!!! Link UP, Port Not Secured! ignore this set::OID_802_11_BSSID_LIST_SCAN\n")); - Status = NDIS_STATUS_SUCCESS; - pAdapter->StaCfg.ScanCnt = 99; // Prevent auto scan triggered by this OID - break; - } - - - if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) - { - RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); - DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); - } - - // tell CNTL state machine to call NdisMSetInformationComplete() after completing - // this request, because this request is initiated by NDIS. - pAdapter->MlmeAux.CurrReqIsFromNdis = FALSE; - // Reset allowed scan retries - pAdapter->StaCfg.ScanCnt = 0; - pAdapter->StaCfg.LastScanTime = Now; - - pAdapter->StaCfg.bScanReqIsFromWebUI = TRUE; - RTMP_SET_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS); - MlmeEnqueue(pAdapter, - MLME_CNTL_STATE_MACHINE, - OID_802_11_BSSID_LIST_SCAN, - 0, - NULL); - - Status = NDIS_STATUS_SUCCESS; - StateMachineTouched = TRUE; - break; - case OID_802_11_SSID: - if (wrq->u.data.length != sizeof(NDIS_802_11_SSID)) - Status = -EINVAL; - else - { - PCHAR pSsidString = NULL; - Status = copy_from_user(&Ssid, wrq->u.data.pointer, wrq->u.data.length); - - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_SSID (Len=%d,Ssid=%s)\n", Ssid.SsidLength, Ssid.Ssid)); - if (Ssid.SsidLength > MAX_LEN_OF_SSID) - Status = -EINVAL; - else - { - if (Ssid.SsidLength == 0) - { - Set_SSID_Proc(pAdapter, ""); - } - else - { - pSsidString = (CHAR *) kmalloc(MAX_LEN_OF_SSID+1, MEM_ALLOC_FLAG); - if (pSsidString) - { - NdisZeroMemory(pSsidString, MAX_LEN_OF_SSID+1); - NdisMoveMemory(pSsidString, Ssid.Ssid, Ssid.SsidLength); - Set_SSID_Proc(pAdapter, pSsidString); - kfree(pSsidString); - } - else - Status = -ENOMEM; - } - } - } - break; - case OID_802_11_BSSID: -#ifdef RALINK_ATE - if (ATE_ON(pAdapter)) - { - DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now\n")); - break; - } -#endif // RALINK_ATE // - if (wrq->u.data.length != sizeof(NDIS_802_11_MAC_ADDRESS)) - Status = -EINVAL; - else - { - Status = copy_from_user(&Bssid, wrq->u.data.pointer, wrq->u.data.length); - - // tell CNTL state machine to call NdisMSetInformationComplete() after completing - // this request, because this request is initiated by NDIS. - pAdapter->MlmeAux.CurrReqIsFromNdis = FALSE; - - // Prevent to connect AP again in STAMlmePeriodicExec - pAdapter->MlmeAux.AutoReconnectSsidLen= 32; - - // Reset allowed scan retries - pAdapter->StaCfg.ScanCnt = 0; - - if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) - { - RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); - DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); - } - MlmeEnqueue(pAdapter, - MLME_CNTL_STATE_MACHINE, - OID_802_11_BSSID, - sizeof(NDIS_802_11_MAC_ADDRESS), - (VOID *)&Bssid); - Status = NDIS_STATUS_SUCCESS; - StateMachineTouched = TRUE; - - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_BSSID %02x:%02x:%02x:%02x:%02x:%02x\n", - Bssid[0], Bssid[1], Bssid[2], Bssid[3], Bssid[4], Bssid[5])); - } - break; - case RT_OID_802_11_RADIO: - if (wrq->u.data.length != sizeof(BOOLEAN)) - Status = -EINVAL; - else - { - Status = copy_from_user(&RadioState, wrq->u.data.pointer, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_RADIO (=%d)\n", RadioState)); - if (pAdapter->StaCfg.bSwRadio != RadioState) - { - pAdapter->StaCfg.bSwRadio = RadioState; - if (pAdapter->StaCfg.bRadio != (pAdapter->StaCfg.bHwRadio && pAdapter->StaCfg.bSwRadio)) - { - pAdapter->StaCfg.bRadio = (pAdapter->StaCfg.bHwRadio && pAdapter->StaCfg.bSwRadio); - if (pAdapter->StaCfg.bRadio == TRUE) - { - MlmeRadioOn(pAdapter); - // Update extra information - pAdapter->ExtraInfo = EXTRA_INFO_CLEAR; - } - else - { - MlmeRadioOff(pAdapter); - // Update extra information - pAdapter->ExtraInfo = SW_RADIO_OFF; - } - } - } - } - break; - case RT_OID_802_11_PHY_MODE: - if (wrq->u.data.length != sizeof(RT_802_11_PHY_MODE)) - Status = -EINVAL; - else - { - Status = copy_from_user(&PhyMode, wrq->u.data.pointer, wrq->u.data.length); - if (PhyMode <= MaxPhyMode) - { - RTMPSetPhyMode(pAdapter, PhyMode); -#ifdef DOT11_N_SUPPORT - SetCommonHT(pAdapter); -#endif // DOT11_N_SUPPORT // - } - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_PHY_MODE (=%d)\n", PhyMode)); - } - break; - case RT_OID_802_11_STA_CONFIG: - if (wrq->u.data.length != sizeof(RT_802_11_STA_CONFIG)) - Status = -EINVAL; - else - { - Status = copy_from_user(&StaConfig, wrq->u.data.pointer, wrq->u.data.length); - pAdapter->CommonCfg.bEnableTxBurst = StaConfig.EnableTxBurst; - pAdapter->CommonCfg.UseBGProtection = StaConfig.UseBGProtection; - pAdapter->CommonCfg.bUseShortSlotTime = 1; // 2003-10-30 always SHORT SLOT capable - if ((pAdapter->CommonCfg.PhyMode != StaConfig.AdhocMode) && - (StaConfig.AdhocMode <= MaxPhyMode)) - { - // allow dynamic change of "USE OFDM rate or not" in ADHOC mode - // if setting changed, need to reset current TX rate as well as BEACON frame format - if (pAdapter->StaCfg.BssType == BSS_ADHOC) - { - pAdapter->CommonCfg.PhyMode = StaConfig.AdhocMode; - RTMPSetPhyMode(pAdapter, PhyMode); - MlmeUpdateTxRates(pAdapter, FALSE, 0); - MakeIbssBeacon(pAdapter); // re-build BEACON frame - AsicEnableIbssSync(pAdapter); // copy to on-chip memory - } - } - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_SET_STA_CONFIG (Burst=%d, Protection=%ld,ShortSlot=%d\n", - pAdapter->CommonCfg.bEnableTxBurst, - pAdapter->CommonCfg.UseBGProtection, - pAdapter->CommonCfg.bUseShortSlotTime)); - } - break; - case OID_802_11_DESIRED_RATES: - if (wrq->u.data.length != sizeof(NDIS_802_11_RATES)) - Status = -EINVAL; - else - { - Status = copy_from_user(&aryRates, wrq->u.data.pointer, wrq->u.data.length); - NdisZeroMemory(pAdapter->CommonCfg.DesireRate, MAX_LEN_OF_SUPPORTED_RATES); - NdisMoveMemory(pAdapter->CommonCfg.DesireRate, &aryRates, sizeof(NDIS_802_11_RATES)); - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_DESIRED_RATES (%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x)\n", - pAdapter->CommonCfg.DesireRate[0],pAdapter->CommonCfg.DesireRate[1], - pAdapter->CommonCfg.DesireRate[2],pAdapter->CommonCfg.DesireRate[3], - pAdapter->CommonCfg.DesireRate[4],pAdapter->CommonCfg.DesireRate[5], - pAdapter->CommonCfg.DesireRate[6],pAdapter->CommonCfg.DesireRate[7] )); - // Changing DesiredRate may affect the MAX TX rate we used to TX frames out - MlmeUpdateTxRates(pAdapter, FALSE, 0); - } - break; - case RT_OID_802_11_PREAMBLE: - if (wrq->u.data.length != sizeof(RT_802_11_PREAMBLE)) - Status = -EINVAL; - else - { - Status = copy_from_user(&Preamble, wrq->u.data.pointer, wrq->u.data.length); - if (Preamble == Rt802_11PreambleShort) - { - pAdapter->CommonCfg.TxPreamble = Preamble; - MlmeSetTxPreamble(pAdapter, Rt802_11PreambleShort); - } - else if ((Preamble == Rt802_11PreambleLong) || (Preamble == Rt802_11PreambleAuto)) - { - // if user wants AUTO, initialize to LONG here, then change according to AP's - // capability upon association. - pAdapter->CommonCfg.TxPreamble = Preamble; - MlmeSetTxPreamble(pAdapter, Rt802_11PreambleLong); - } - else - { - Status = -EINVAL; - break; - } - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_PREAMBLE (=%d)\n", Preamble)); - } - break; - case OID_802_11_WEP_STATUS: - if (wrq->u.data.length != sizeof(NDIS_802_11_WEP_STATUS)) - Status = -EINVAL; - else - { - Status = copy_from_user(&WepStatus, wrq->u.data.pointer, wrq->u.data.length); - // Since TKIP, AES, WEP are all supported. It should not have any invalid setting - if (WepStatus <= Ndis802_11Encryption3KeyAbsent) - { - if (pAdapter->StaCfg.WepStatus != WepStatus) - { - // Config has changed - pAdapter->bConfigChanged = TRUE; - } - pAdapter->StaCfg.WepStatus = WepStatus; - pAdapter->StaCfg.OrigWepStatus = WepStatus; - pAdapter->StaCfg.PairCipher = WepStatus; - pAdapter->StaCfg.GroupCipher = WepStatus; - } - else - { - Status = -EINVAL; - break; - } - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_WEP_STATUS (=%d)\n",WepStatus)); - } - break; - case OID_802_11_AUTHENTICATION_MODE: - if (wrq->u.data.length != sizeof(NDIS_802_11_AUTHENTICATION_MODE)) - Status = -EINVAL; - else - { - Status = copy_from_user(&AuthMode, wrq->u.data.pointer, wrq->u.data.length); - if (AuthMode > Ndis802_11AuthModeMax) - { - Status = -EINVAL; - break; - } - else - { - if (pAdapter->StaCfg.AuthMode != AuthMode) - { - // Config has changed - pAdapter->bConfigChanged = TRUE; - } - pAdapter->StaCfg.AuthMode = AuthMode; - } - pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_AUTHENTICATION_MODE (=%d) \n",pAdapter->StaCfg.AuthMode)); - } - break; - case OID_802_11_INFRASTRUCTURE_MODE: - if (wrq->u.data.length != sizeof(NDIS_802_11_NETWORK_INFRASTRUCTURE)) - Status = -EINVAL; - else - { - Status = copy_from_user(&BssType, wrq->u.data.pointer, wrq->u.data.length); - - if (BssType == Ndis802_11IBSS) - Set_NetworkType_Proc(pAdapter, "Adhoc"); - else if (BssType == Ndis802_11Infrastructure) - Set_NetworkType_Proc(pAdapter, "Infra"); - else if (BssType == Ndis802_11Monitor) - Set_NetworkType_Proc(pAdapter, "Monitor"); - else - { - Status = -EINVAL; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_INFRASTRUCTURE_MODE (unknown)\n")); - } - } - break; - case OID_802_11_REMOVE_WEP: - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_WEP\n")); - if (wrq->u.data.length != sizeof(NDIS_802_11_KEY_INDEX)) - { - Status = -EINVAL; - } - else - { - KeyIdx = *(NDIS_802_11_KEY_INDEX *) wrq->u.data.pointer; - - if (KeyIdx & 0x80000000) - { - // Should never set default bit when remove key - Status = -EINVAL; - } - else - { - KeyIdx = KeyIdx & 0x0fffffff; - if (KeyIdx >= 4){ - Status = -EINVAL; - } - else - { - pAdapter->SharedKey[BSS0][KeyIdx].KeyLen = 0; - pAdapter->SharedKey[BSS0][KeyIdx].CipherAlg = CIPHER_NONE; - AsicRemoveSharedKeyEntry(pAdapter, 0, (UCHAR)KeyIdx); - } - } - } - break; - case RT_OID_802_11_RESET_COUNTERS: - NdisZeroMemory(&pAdapter->WlanCounters, sizeof(COUNTER_802_11)); - NdisZeroMemory(&pAdapter->Counters8023, sizeof(COUNTER_802_3)); - NdisZeroMemory(&pAdapter->RalinkCounters, sizeof(COUNTER_RALINK)); - pAdapter->Counters8023.RxNoBuffer = 0; - pAdapter->Counters8023.GoodReceives = 0; - pAdapter->Counters8023.RxNoBuffer = 0; -#ifdef RT2870 - pAdapter->BulkOutComplete = 0; - pAdapter->BulkOutCompleteOther= 0; - pAdapter->BulkOutCompleteCancel = 0; - pAdapter->BulkOutReq = 0; - pAdapter->BulkInReq= 0; - pAdapter->BulkInComplete = 0; - pAdapter->BulkInCompleteFail = 0; -#endif // RT2870 // - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_RESET_COUNTERS \n")); - break; - case OID_802_11_RTS_THRESHOLD: - if (wrq->u.data.length != sizeof(NDIS_802_11_RTS_THRESHOLD)) - Status = -EINVAL; - else - { - Status = copy_from_user(&RtsThresh, wrq->u.data.pointer, wrq->u.data.length); - if (RtsThresh > MAX_RTS_THRESHOLD) - Status = -EINVAL; - else - pAdapter->CommonCfg.RtsThreshold = (USHORT)RtsThresh; - } - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_RTS_THRESHOLD (=%ld)\n",RtsThresh)); - break; - case OID_802_11_FRAGMENTATION_THRESHOLD: - if (wrq->u.data.length != sizeof(NDIS_802_11_FRAGMENTATION_THRESHOLD)) - Status = -EINVAL; - else - { - Status = copy_from_user(&FragThresh, wrq->u.data.pointer, wrq->u.data.length); - pAdapter->CommonCfg.bUseZeroToDisableFragment = FALSE; - if (FragThresh > MAX_FRAG_THRESHOLD || FragThresh < MIN_FRAG_THRESHOLD) - { - if (FragThresh == 0) - { - pAdapter->CommonCfg.FragmentThreshold = MAX_FRAG_THRESHOLD; - pAdapter->CommonCfg.bUseZeroToDisableFragment = TRUE; - } - else - Status = -EINVAL; - } - else - pAdapter->CommonCfg.FragmentThreshold = (USHORT)FragThresh; - } - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_FRAGMENTATION_THRESHOLD (=%ld) \n",FragThresh)); - break; - case OID_802_11_POWER_MODE: - if (wrq->u.data.length != sizeof(NDIS_802_11_POWER_MODE)) - Status = -EINVAL; - else - { - Status = copy_from_user(&PowerMode, wrq->u.data.pointer, wrq->u.data.length); - if (PowerMode == Ndis802_11PowerModeCAM) - Set_PSMode_Proc(pAdapter, "CAM"); - else if (PowerMode == Ndis802_11PowerModeMAX_PSP) - Set_PSMode_Proc(pAdapter, "Max_PSP"); - else if (PowerMode == Ndis802_11PowerModeFast_PSP) - Set_PSMode_Proc(pAdapter, "Fast_PSP"); - else if (PowerMode == Ndis802_11PowerModeLegacy_PSP) - Set_PSMode_Proc(pAdapter, "Legacy_PSP"); - else - Status = -EINVAL; - } - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_POWER_MODE (=%d)\n",PowerMode)); - break; - case RT_OID_802_11_TX_POWER_LEVEL_1: - if (wrq->u.data.length < sizeof(ULONG)) - Status = -EINVAL; - else - { - Status = copy_from_user(&PowerTemp, wrq->u.data.pointer, wrq->u.data.length); - if (PowerTemp > 100) - PowerTemp = 0xffffffff; // AUTO - pAdapter->CommonCfg.TxPowerDefault = PowerTemp; //keep current setting. - pAdapter->CommonCfg.TxPowerPercentage = pAdapter->CommonCfg.TxPowerDefault; - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_TX_POWER_LEVEL_1 (=%ld)\n", pAdapter->CommonCfg.TxPowerPercentage)); - } - break; - case OID_802_11_NETWORK_TYPE_IN_USE: - if (wrq->u.data.length != sizeof(NDIS_802_11_NETWORK_TYPE)) - Status = -EINVAL; - else - { - Status = copy_from_user(&NetType, wrq->u.data.pointer, wrq->u.data.length); - - if (NetType == Ndis802_11DS) - RTMPSetPhyMode(pAdapter, PHY_11B); - else if (NetType == Ndis802_11OFDM24) - RTMPSetPhyMode(pAdapter, PHY_11BG_MIXED); - else if (NetType == Ndis802_11OFDM5) - RTMPSetPhyMode(pAdapter, PHY_11A); - else - Status = -EINVAL; -#ifdef DOT11_N_SUPPORT - if (Status == NDIS_STATUS_SUCCESS) - SetCommonHT(pAdapter); -#endif // DOT11_N_SUPPORT // - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_NETWORK_TYPE_IN_USE (=%d)\n",NetType)); - } - break; - // For WPA PSK PMK key - case RT_OID_802_11_ADD_WPA: - pKey = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); - if(pKey == NULL) - { - Status = -ENOMEM; - break; - } - - Status = copy_from_user(pKey, wrq->u.data.pointer, wrq->u.data.length); - if (pKey->Length != wrq->u.data.length) - { - Status = -EINVAL; - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_ADD_WPA, Failed!!\n")); - } - else - { - if ((pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPAPSK) && - (pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPA2PSK) && - (pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPANone) ) - { - Status = -EOPNOTSUPP; - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_ADD_WPA, Failed!! [AuthMode != WPAPSK/WPA2PSK/WPANONE]\n")); - } - else if ((pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) || - (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) || - (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) ) // Only for WPA PSK mode - { - NdisMoveMemory(pAdapter->StaCfg.PMK, &pKey->KeyMaterial, pKey->KeyLength); - // Use RaConfig as PSK agent. - // Start STA supplicant state machine - if (pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPANone) - pAdapter->StaCfg.WpaState = SS_START; - - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_ADD_WPA (id=0x%x, Len=%d-byte)\n", pKey->KeyIndex, pKey->KeyLength)); - } - else - { - pAdapter->StaCfg.WpaState = SS_NOTUSE; - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_ADD_WPA (id=0x%x, Len=%d-byte)\n", pKey->KeyIndex, pKey->KeyLength)); - } - } - kfree(pKey); - break; - case OID_802_11_REMOVE_KEY: - pRemoveKey = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); - if(pRemoveKey == NULL) - { - Status = -ENOMEM; - break; - } - - Status = copy_from_user(pRemoveKey, wrq->u.data.pointer, wrq->u.data.length); - if (pRemoveKey->Length != wrq->u.data.length) - { - Status = -EINVAL; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_KEY, Failed!!\n")); - } - else - { - if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - { - RTMPWPARemoveKeyProc(pAdapter, pRemoveKey); - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_KEY, Remove WPA Key!!\n")); - } - else - { - KeyIdx = pRemoveKey->KeyIndex; - - if (KeyIdx & 0x80000000) - { - // Should never set default bit when remove key - Status = -EINVAL; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_KEY, Failed!!(Should never set default bit when remove key)\n")); - } - else - { - KeyIdx = KeyIdx & 0x0fffffff; - if (KeyIdx > 3) - { - Status = -EINVAL; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_KEY, Failed!!(KeyId[%d] out of range)\n", KeyIdx)); - } - else - { - pAdapter->SharedKey[BSS0][KeyIdx].KeyLen = 0; - pAdapter->SharedKey[BSS0][KeyIdx].CipherAlg = CIPHER_NONE; - AsicRemoveSharedKeyEntry(pAdapter, 0, (UCHAR)KeyIdx); - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_KEY (id=0x%x, Len=%d-byte)\n", pRemoveKey->KeyIndex, pRemoveKey->Length)); - } - } - } - } - kfree(pRemoveKey); - break; - // New for WPA - case OID_802_11_ADD_KEY: - pKey = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); - if(pKey == NULL) - { - Status = -ENOMEM; - break; - } - Status = copy_from_user(pKey, wrq->u.data.pointer, wrq->u.data.length); - if (pKey->Length != wrq->u.data.length) - { - Status = -EINVAL; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_KEY, Failed!!\n")); - } - else - { - RTMPAddKey(pAdapter, pKey); - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_KEY (id=0x%x, Len=%d-byte)\n", pKey->KeyIndex, pKey->KeyLength)); - } - kfree(pKey); - break; - case OID_802_11_CONFIGURATION: - if (wrq->u.data.length != sizeof(NDIS_802_11_CONFIGURATION)) - Status = -EINVAL; - else - { - Status = copy_from_user(&Config, wrq->u.data.pointer, wrq->u.data.length); - pConfig = &Config; - - if ((pConfig->BeaconPeriod >= 20) && (pConfig->BeaconPeriod <=400)) - pAdapter->CommonCfg.BeaconPeriod = (USHORT) pConfig->BeaconPeriod; - - pAdapter->StaActive.AtimWin = (USHORT) pConfig->ATIMWindow; - MAP_KHZ_TO_CHANNEL_ID(pConfig->DSConfig, pAdapter->CommonCfg.Channel); - // - // Save the channel on MlmeAux for CntlOidRTBssidProc used. - // - pAdapter->MlmeAux.Channel = pAdapter->CommonCfg.Channel; - - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_CONFIGURATION (BeacnPeriod=%ld,AtimW=%ld,Ch=%d)\n", - pConfig->BeaconPeriod, pConfig->ATIMWindow, pAdapter->CommonCfg.Channel)); - // Config has changed - pAdapter->bConfigChanged = TRUE; - } - break; -#ifdef DOT11_N_SUPPORT - case RT_OID_802_11_SET_HT_PHYMODE: - if (wrq->u.data.length != sizeof(OID_SET_HT_PHYMODE)) - Status = -EINVAL; - else - { - POID_SET_HT_PHYMODE pHTPhyMode = &HT_PhyMode; - - Status = copy_from_user(&HT_PhyMode, wrq->u.data.pointer, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Set::pHTPhyMode (PhyMode = %d,TransmitNo = %d, HtMode = %d, ExtOffset = %d , MCS = %d, BW = %d, STBC = %d, SHORTGI = %d) \n", - pHTPhyMode->PhyMode, pHTPhyMode->TransmitNo,pHTPhyMode->HtMode,pHTPhyMode->ExtOffset, - pHTPhyMode->MCS, pHTPhyMode->BW, pHTPhyMode->STBC, pHTPhyMode->SHORTGI)); - if (pAdapter->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) - RTMPSetHT(pAdapter, pHTPhyMode); - } - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_SET_HT_PHYMODE(MCS=%d,BW=%d,SGI=%d,STBC=%d)\n", - pAdapter->StaCfg.HTPhyMode.field.MCS, pAdapter->StaCfg.HTPhyMode.field.BW, pAdapter->StaCfg.HTPhyMode.field.ShortGI, - pAdapter->StaCfg.HTPhyMode.field.STBC)); - break; -#endif // DOT11_N_SUPPORT // - case RT_OID_802_11_SET_APSD_SETTING: - if (wrq->u.data.length != sizeof(ULONG)) - Status = -EINVAL; - else - { - ULONG apsd ; - Status = copy_from_user(&apsd, wrq->u.data.pointer, wrq->u.data.length); - - /*------------------------------------------------------------------- - |B31~B7 | B6~B5 | B4 | B3 | B2 | B1 | B0 | - --------------------------------------------------------------------- - | Rsvd | Max SP Len | AC_VO | AC_VI | AC_BK | AC_BE | APSD Capable | - ---------------------------------------------------------------------*/ - pAdapter->CommonCfg.bAPSDCapable = (apsd & 0x00000001) ? TRUE : FALSE; - pAdapter->CommonCfg.bAPSDAC_BE = ((apsd & 0x00000002) >> 1) ? TRUE : FALSE; - pAdapter->CommonCfg.bAPSDAC_BK = ((apsd & 0x00000004) >> 2) ? TRUE : FALSE; - pAdapter->CommonCfg.bAPSDAC_VI = ((apsd & 0x00000008) >> 3) ? TRUE : FALSE; - pAdapter->CommonCfg.bAPSDAC_VO = ((apsd & 0x00000010) >> 4) ? TRUE : FALSE; - pAdapter->CommonCfg.MaxSPLength = (UCHAR)((apsd & 0x00000060) >> 5); - - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_SET_APSD_SETTING (apsd=0x%lx, APSDCap=%d, [BE,BK,VI,VO]=[%d/%d/%d/%d], MaxSPLen=%d)\n", apsd, pAdapter->CommonCfg.bAPSDCapable, - pAdapter->CommonCfg.bAPSDAC_BE, pAdapter->CommonCfg.bAPSDAC_BK, pAdapter->CommonCfg.bAPSDAC_VI, pAdapter->CommonCfg.bAPSDAC_VO, pAdapter->CommonCfg.MaxSPLength)); - } - break; - - case RT_OID_802_11_SET_APSD_PSM: - if (wrq->u.data.length != sizeof(ULONG)) - Status = -EINVAL; - else - { - // Driver needs to notify AP when PSM changes - Status = copy_from_user(&pAdapter->CommonCfg.bAPSDForcePowerSave, wrq->u.data.pointer, wrq->u.data.length); - if (pAdapter->CommonCfg.bAPSDForcePowerSave != pAdapter->StaCfg.Psm) - { - MlmeSetPsmBit(pAdapter, pAdapter->CommonCfg.bAPSDForcePowerSave); - RTMPSendNullFrame(pAdapter, pAdapter->CommonCfg.TxRate, TRUE); - } - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_SET_APSD_PSM (bAPSDForcePowerSave:%d)\n", pAdapter->CommonCfg.bAPSDForcePowerSave)); - } - break; -#ifdef QOS_DLS_SUPPORT - case RT_OID_802_11_SET_DLS: - if (wrq->u.data.length != sizeof(ULONG)) - Status = -EINVAL; - else - { - BOOLEAN oldvalue = pAdapter->CommonCfg.bDLSCapable; - Status = copy_from_user(&pAdapter->CommonCfg.bDLSCapable, wrq->u.data.pointer, wrq->u.data.length); - if (oldvalue && !pAdapter->CommonCfg.bDLSCapable) - { - int i; - // tear down local dls table entry - for (i=0; iStaCfg.DLSEntry[i].Valid && (pAdapter->StaCfg.DLSEntry[i].Status == DLS_FINISH)) - { - pAdapter->StaCfg.DLSEntry[i].Status = DLS_NONE; - pAdapter->StaCfg.DLSEntry[i].Valid = FALSE; - RTMPSendDLSTearDownFrame(pAdapter, pAdapter->StaCfg.DLSEntry[i].MacAddr); - } - } - - // tear down peer dls table entry - for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid && (pAdapter->StaCfg.DLSEntry[i].Status == DLS_FINISH)) - { - pAdapter->StaCfg.DLSEntry[i].Status = DLS_NONE; - pAdapter->StaCfg.DLSEntry[i].Valid = FALSE; - RTMPSendDLSTearDownFrame(pAdapter, pAdapter->StaCfg.DLSEntry[i].MacAddr); - } - } - } - - DBGPRINT(RT_DEBUG_TRACE,("Set::RT_OID_802_11_SET_DLS (=%d)\n", pAdapter->CommonCfg.bDLSCapable)); - } - break; - - case RT_OID_802_11_SET_DLS_PARAM: - if (wrq->u.data.length != sizeof(RT_802_11_DLS_UI)) - Status = -EINVAL; - else - { - RT_802_11_DLS Dls; - - NdisZeroMemory(&Dls, sizeof(RT_802_11_DLS)); - RTMPMoveMemory(&Dls, wrq->u.data.pointer, sizeof(RT_802_11_DLS_UI)); - MlmeEnqueue(pAdapter, - MLME_CNTL_STATE_MACHINE, - RT_OID_802_11_SET_DLS_PARAM, - sizeof(RT_802_11_DLS), - &Dls); - DBGPRINT(RT_DEBUG_TRACE,("Set::RT_OID_802_11_SET_DLS_PARAM \n")); - } - break; -#endif // QOS_DLS_SUPPORT // - case RT_OID_802_11_SET_WMM: - if (wrq->u.data.length != sizeof(BOOLEAN)) - Status = -EINVAL; - else - { - Status = copy_from_user(&pAdapter->CommonCfg.bWmmCapable, wrq->u.data.pointer, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_SET_WMM (=%d) \n", pAdapter->CommonCfg.bWmmCapable)); - } - break; - - case OID_802_11_DISASSOCIATE: -#ifdef RALINK_ATE - if (ATE_ON(pAdapter)) - { - DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now\n")); - break; - } -#endif // RALINK_ATE // - // - // Set NdisRadioStateOff to TRUE, instead of called MlmeRadioOff. - // Later on, NDIS_802_11_BSSID_LIST_EX->NumberOfItems should be 0 - // when query OID_802_11_BSSID_LIST. - // - // TRUE: NumberOfItems will set to 0. - // FALSE: NumberOfItems no change. - // - pAdapter->CommonCfg.NdisRadioStateOff = TRUE; - // Set to immediately send the media disconnect event - pAdapter->MlmeAux.CurrReqIsFromNdis = TRUE; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_DISASSOCIATE \n")); - - if (INFRA_ON(pAdapter)) - { - if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) - { - RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); - DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); - } - - MlmeEnqueue(pAdapter, - MLME_CNTL_STATE_MACHINE, - OID_802_11_DISASSOCIATE, - 0, - NULL); - - StateMachineTouched = TRUE; - } - break; - -#ifdef DOT11_N_SUPPORT - case RT_OID_802_11_SET_IMME_BA_CAP: - if (wrq->u.data.length != sizeof(OID_BACAP_STRUC)) - Status = -EINVAL; - else - { - OID_BACAP_STRUC Orde ; - Status = copy_from_user(&Orde, wrq->u.data.pointer, wrq->u.data.length); - if (Orde.Policy > BA_NOTUSE) - { - Status = NDIS_STATUS_INVALID_DATA; - } - else if (Orde.Policy == BA_NOTUSE) - { - pAdapter->CommonCfg.BACapability.field.Policy = BA_NOTUSE; - pAdapter->CommonCfg.BACapability.field.MpduDensity = Orde.MpduDensity; - pAdapter->CommonCfg.DesiredHtPhy.MpduDensity = Orde.MpduDensity; - pAdapter->CommonCfg.DesiredHtPhy.AmsduEnable = Orde.AmsduEnable; - pAdapter->CommonCfg.DesiredHtPhy.AmsduSize= Orde.AmsduSize; - pAdapter->CommonCfg.DesiredHtPhy.MimoPs= Orde.MMPSmode; - pAdapter->CommonCfg.BACapability.field.MMPSmode = Orde.MMPSmode; - // UPdata to HT IE - pAdapter->CommonCfg.HtCapability.HtCapInfo.MimoPs = Orde.MMPSmode; - pAdapter->CommonCfg.HtCapability.HtCapInfo.AMsduSize = Orde.AmsduSize; - pAdapter->CommonCfg.HtCapability.HtCapParm.MpduDensity = Orde.MpduDensity; - } - else - { - pAdapter->CommonCfg.BACapability.field.AutoBA = Orde.AutoBA; - pAdapter->CommonCfg.BACapability.field.Policy = IMMED_BA; // we only support immediate BA. - pAdapter->CommonCfg.BACapability.field.MpduDensity = Orde.MpduDensity; - pAdapter->CommonCfg.DesiredHtPhy.MpduDensity = Orde.MpduDensity; - pAdapter->CommonCfg.DesiredHtPhy.AmsduEnable = Orde.AmsduEnable; - pAdapter->CommonCfg.DesiredHtPhy.AmsduSize= Orde.AmsduSize; - pAdapter->CommonCfg.DesiredHtPhy.MimoPs = Orde.MMPSmode; - pAdapter->CommonCfg.BACapability.field.MMPSmode = Orde.MMPSmode; - - // UPdata to HT IE - pAdapter->CommonCfg.HtCapability.HtCapInfo.MimoPs = Orde.MMPSmode; - pAdapter->CommonCfg.HtCapability.HtCapInfo.AMsduSize = Orde.AmsduSize; - pAdapter->CommonCfg.HtCapability.HtCapParm.MpduDensity = Orde.MpduDensity; - - if (pAdapter->CommonCfg.BACapability.field.RxBAWinLimit > MAX_RX_REORDERBUF) - pAdapter->CommonCfg.BACapability.field.RxBAWinLimit = MAX_RX_REORDERBUF; - - } - - pAdapter->CommonCfg.REGBACapability.word = pAdapter->CommonCfg.BACapability.word; - DBGPRINT(RT_DEBUG_TRACE, ("Set::(Orde.AutoBA = %d) (Policy=%d)(ReBAWinLimit=%d)(TxBAWinLimit=%d)(AutoMode=%d)\n",Orde.AutoBA, pAdapter->CommonCfg.BACapability.field.Policy, - pAdapter->CommonCfg.BACapability.field.RxBAWinLimit,pAdapter->CommonCfg.BACapability.field.TxBAWinLimit, pAdapter->CommonCfg.BACapability.field.AutoBA)); - DBGPRINT(RT_DEBUG_TRACE, ("Set::(MimoPs = %d)(AmsduEnable = %d) (AmsduSize=%d)(MpduDensity=%d)\n",pAdapter->CommonCfg.DesiredHtPhy.MimoPs, pAdapter->CommonCfg.DesiredHtPhy.AmsduEnable, - pAdapter->CommonCfg.DesiredHtPhy.AmsduSize, pAdapter->CommonCfg.DesiredHtPhy.MpduDensity)); - } - - break; - case RT_OID_802_11_ADD_IMME_BA: - DBGPRINT(RT_DEBUG_TRACE, (" Set :: RT_OID_802_11_ADD_IMME_BA \n")); - if (wrq->u.data.length != sizeof(OID_ADD_BA_ENTRY)) - Status = -EINVAL; - else - { - UCHAR index; - OID_ADD_BA_ENTRY BA; - MAC_TABLE_ENTRY *pEntry; - - Status = copy_from_user(&BA, wrq->u.data.pointer, wrq->u.data.length); - if (BA.TID > 15) - { - Status = NDIS_STATUS_INVALID_DATA; - break; - } - else - { - //BATableInsertEntry - //As ad-hoc mode, BA pair is not limited to only BSSID. so add via OID. - index = BA.TID; - // in ad hoc mode, when adding BA pair, we should insert this entry into MACEntry too - pEntry = MacTableLookup(pAdapter, BA.MACAddr); - if (!pEntry) - { - DBGPRINT(RT_DEBUG_TRACE, ("RT_OID_802_11_ADD_IMME_BA. break on no connection.----:%x:%x\n", BA.MACAddr[4], BA.MACAddr[5])); - break; - } - if (BA.IsRecipient == FALSE) - { - if (pEntry->bIAmBadAtheros == TRUE) - pAdapter->CommonCfg.BACapability.field.RxBAWinLimit = 0x10; - - BAOriSessionSetUp(pAdapter, pEntry, index, 0, 100, TRUE); - } - else - { - //BATableInsertEntry(pAdapter, pEntry->Aid, BA.MACAddr, 0, 0xffff, BA.TID, BA.nMSDU, BA.IsRecipient); - } - - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_ADD_IMME_BA. Rec = %d. Mac = %x:%x:%x:%x:%x:%x . \n", - BA.IsRecipient, BA.MACAddr[0], BA.MACAddr[1], BA.MACAddr[2], BA.MACAddr[2] - , BA.MACAddr[4], BA.MACAddr[5])); - } - } - break; - - case RT_OID_802_11_TEAR_IMME_BA: - DBGPRINT(RT_DEBUG_TRACE, ("Set :: RT_OID_802_11_TEAR_IMME_BA \n")); - if (wrq->u.data.length != sizeof(OID_ADD_BA_ENTRY)) - Status = -EINVAL; - else - { - POID_ADD_BA_ENTRY pBA; - MAC_TABLE_ENTRY *pEntry; - - pBA = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); - - if (pBA == NULL) - { - DBGPRINT(RT_DEBUG_TRACE, ("Set :: RT_OID_802_11_TEAR_IMME_BA kmalloc() can't allocate enough memory\n")); - Status = NDIS_STATUS_FAILURE; - } - else - { - Status = copy_from_user(pBA, wrq->u.data.pointer, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Set :: RT_OID_802_11_TEAR_IMME_BA(TID=%d, bAllTid=%d)\n", pBA->TID, pBA->bAllTid)); - - if (!pBA->bAllTid && (pBA->TID > NUM_OF_TID)) - { - Status = NDIS_STATUS_INVALID_DATA; - break; - } - - if (pBA->IsRecipient == FALSE) - { - pEntry = MacTableLookup(pAdapter, pBA->MACAddr); - DBGPRINT(RT_DEBUG_TRACE, (" pBA->IsRecipient == FALSE\n")); - if (pEntry) - { - DBGPRINT(RT_DEBUG_TRACE, (" pBA->pEntry\n")); - BAOriSessionTearDown(pAdapter, pEntry->Aid, pBA->TID, FALSE, TRUE); - } - else - DBGPRINT(RT_DEBUG_TRACE, ("Set :: Not found pEntry \n")); - } - else - { - pEntry = MacTableLookup(pAdapter, pBA->MACAddr); - if (pEntry) - { - BARecSessionTearDown( pAdapter, (UCHAR)pEntry->Aid, pBA->TID, TRUE); - } - else - DBGPRINT(RT_DEBUG_TRACE, ("Set :: Not found pEntry \n")); - } - kfree(pBA); - } - } - break; -#endif // DOT11_N_SUPPORT // - - // For WPA_SUPPLICANT to set static wep key - case OID_802_11_ADD_WEP: - pWepKey = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); - - if(pWepKey == NULL) - { - Status = -ENOMEM; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_WEP, Failed!!\n")); - break; - } - Status = copy_from_user(pWepKey, wrq->u.data.pointer, wrq->u.data.length); - if (Status) - { - Status = -EINVAL; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_WEP, Failed (length mismatch)!!\n")); - } - else - { - KeyIdx = pWepKey->KeyIndex & 0x0fffffff; - // KeyIdx must be 0 ~ 3 - if (KeyIdx > 4) - { - Status = -EINVAL; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_WEP, Failed (KeyIdx must be smaller than 4)!!\n")); - } - else - { - UCHAR CipherAlg = 0; - PUCHAR Key; - - // set key material and key length - NdisZeroMemory(pAdapter->SharedKey[BSS0][KeyIdx].Key, 16); - pAdapter->SharedKey[BSS0][KeyIdx].KeyLen = (UCHAR) pWepKey->KeyLength; - NdisMoveMemory(pAdapter->SharedKey[BSS0][KeyIdx].Key, &pWepKey->KeyMaterial, pWepKey->KeyLength); - - switch(pWepKey->KeyLength) - { - case 5: - CipherAlg = CIPHER_WEP64; - break; - case 13: - CipherAlg = CIPHER_WEP128; - break; - default: - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_WEP, only support CIPHER_WEP64(len:5) & CIPHER_WEP128(len:13)!!\n")); - Status = -EINVAL; - break; - } - pAdapter->SharedKey[BSS0][KeyIdx].CipherAlg = CipherAlg; - - // Default key for tx (shared key) - if (pWepKey->KeyIndex & 0x80000000) - { -#ifdef WPA_SUPPLICANT_SUPPORT - // set key material and key length - NdisZeroMemory(pAdapter->StaCfg.DesireSharedKey[KeyIdx].Key, 16); - pAdapter->StaCfg.DesireSharedKey[KeyIdx].KeyLen = (UCHAR) pWepKey->KeyLength; - NdisMoveMemory(pAdapter->StaCfg.DesireSharedKey[KeyIdx].Key, &pWepKey->KeyMaterial, pWepKey->KeyLength); - pAdapter->StaCfg.DesireSharedKeyId = KeyIdx; - pAdapter->StaCfg.DesireSharedKey[KeyIdx].CipherAlg = CipherAlg; -#endif // WPA_SUPPLICANT_SUPPORT // - pAdapter->StaCfg.DefaultKeyId = (UCHAR) KeyIdx; - } - -#ifdef WPA_SUPPLICANT_SUPPORT - if (pAdapter->StaCfg.PortSecured == WPA_802_1X_PORT_SECURED) -#endif // WPA_SUPPLICANT_SUPPORT - { - Key = pAdapter->SharedKey[BSS0][KeyIdx].Key; - - // Set key material and cipherAlg to Asic - AsicAddSharedKeyEntry(pAdapter, BSS0, KeyIdx, CipherAlg, Key, NULL, NULL); - - if (pWepKey->KeyIndex & 0x80000000) - { - PMAC_TABLE_ENTRY pEntry = &pAdapter->MacTab.Content[BSSID_WCID]; - // Assign group key info - RTMPAddWcidAttributeEntry(pAdapter, BSS0, KeyIdx, CipherAlg, NULL); - // Assign pairwise key info - RTMPAddWcidAttributeEntry(pAdapter, BSS0, KeyIdx, CipherAlg, pEntry); - } - } - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_WEP (id=0x%x, Len=%d-byte), %s\n", pWepKey->KeyIndex, pWepKey->KeyLength, (pAdapter->StaCfg.PortSecured == WPA_802_1X_PORT_SECURED) ? "Port Secured":"Port NOT Secured")); - } - } - kfree(pWepKey); - break; -#ifdef WPA_SUPPLICANT_SUPPORT - case OID_SET_COUNTERMEASURES: - if (wrq->u.data.length != sizeof(int)) - Status = -EINVAL; - else - { - int enabled = 0; - Status = copy_from_user(&enabled, wrq->u.data.pointer, wrq->u.data.length); - if (enabled == 1) - pAdapter->StaCfg.bBlockAssoc = TRUE; - else - // WPA MIC error should block association attempt for 60 seconds - pAdapter->StaCfg.bBlockAssoc = FALSE; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_SET_COUNTERMEASURES bBlockAssoc=%s\n", pAdapter->StaCfg.bBlockAssoc ? "TRUE":"FALSE")); - } - break; - case RT_OID_WPA_SUPPLICANT_SUPPORT: - if (wrq->u.data.length != sizeof(UCHAR)) - Status = -EINVAL; - else - { - Status = copy_from_user(&wpa_supplicant_enable, wrq->u.data.pointer, wrq->u.data.length); - pAdapter->StaCfg.WpaSupplicantUP = wpa_supplicant_enable; - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_WPA_SUPPLICANT_SUPPORT (=%d)\n", pAdapter->StaCfg.WpaSupplicantUP)); - } - break; - case OID_802_11_DEAUTHENTICATION: - if (wrq->u.data.length != sizeof(MLME_DEAUTH_REQ_STRUCT)) - Status = -EINVAL; - else - { - MLME_DEAUTH_REQ_STRUCT *pInfo; - MLME_QUEUE_ELEM *MsgElem = (MLME_QUEUE_ELEM *) kmalloc(sizeof(MLME_QUEUE_ELEM), MEM_ALLOC_FLAG); - - pInfo = (MLME_DEAUTH_REQ_STRUCT *) MsgElem->Msg; - Status = copy_from_user(pInfo, wrq->u.data.pointer, wrq->u.data.length); - MlmeDeauthReqAction(pAdapter, MsgElem); - kfree(MsgElem); - - if (INFRA_ON(pAdapter)) - { - LinkDown(pAdapter, FALSE); - pAdapter->Mlme.AssocMachine.CurrState = ASSOC_IDLE; - } - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_DEAUTHENTICATION (Reason=%d)\n", pInfo->Reason)); - } - break; - case OID_802_11_DROP_UNENCRYPTED: - if (wrq->u.data.length != sizeof(int)) - Status = -EINVAL; - else - { - int enabled = 0; - Status = copy_from_user(&enabled, wrq->u.data.pointer, wrq->u.data.length); - if (enabled == 1) - pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; - else - pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; - NdisAcquireSpinLock(&pAdapter->MacTabLock); - pAdapter->MacTab.Content[BSSID_WCID].PortSecured = pAdapter->StaCfg.PortSecured; - NdisReleaseSpinLock(&pAdapter->MacTabLock); - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_DROP_UNENCRYPTED (=%d)\n", enabled)); - } - break; - case OID_802_11_SET_IEEE8021X: - if (wrq->u.data.length != sizeof(BOOLEAN)) - Status = -EINVAL; - else - { - Status = copy_from_user(&IEEE8021xState, wrq->u.data.pointer, wrq->u.data.length); - pAdapter->StaCfg.IEEE8021X = IEEE8021xState; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_SET_IEEE8021X (=%d)\n", IEEE8021xState)); - } - break; - case OID_802_11_SET_IEEE8021X_REQUIRE_KEY: - if (wrq->u.data.length != sizeof(BOOLEAN)) - Status = -EINVAL; - else - { - Status = copy_from_user(&IEEE8021x_required_keys, wrq->u.data.pointer, wrq->u.data.length); - pAdapter->StaCfg.IEEE8021x_required_keys = IEEE8021x_required_keys; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_SET_IEEE8021X_REQUIRE_KEY (%d)\n", IEEE8021x_required_keys)); - } - break; - case OID_802_11_PMKID: - pPmkId = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); - - if(pPmkId == NULL) { - Status = -ENOMEM; - break; - } - Status = copy_from_user(pPmkId, wrq->u.data.pointer, wrq->u.data.length); - - // check the PMKID information - if (pPmkId->BSSIDInfoCount == 0) - NdisZeroMemory(pAdapter->StaCfg.SavedPMK, sizeof(BSSID_INFO)*PMKID_NO); - else - { - PBSSID_INFO pBssIdInfo; - UINT BssIdx; - UINT CachedIdx; - - for (BssIdx = 0; BssIdx < pPmkId->BSSIDInfoCount; BssIdx++) - { - // point to the indexed BSSID_INFO structure - pBssIdInfo = (PBSSID_INFO) ((PUCHAR) pPmkId + 2 * sizeof(UINT) + BssIdx * sizeof(BSSID_INFO)); - // Find the entry in the saved data base. - for (CachedIdx = 0; CachedIdx < pAdapter->StaCfg.SavedPMKNum; CachedIdx++) - { - // compare the BSSID - if (NdisEqualMemory(pBssIdInfo->BSSID, pAdapter->StaCfg.SavedPMK[CachedIdx].BSSID, sizeof(NDIS_802_11_MAC_ADDRESS))) - break; - } - - // Found, replace it - if (CachedIdx < PMKID_NO) - { - DBGPRINT(RT_DEBUG_OFF, ("Update OID_802_11_PMKID, idx = %d\n", CachedIdx)); - NdisMoveMemory(&pAdapter->StaCfg.SavedPMK[CachedIdx], pBssIdInfo, sizeof(BSSID_INFO)); - pAdapter->StaCfg.SavedPMKNum++; - } - // Not found, replace the last one - else - { - // Randomly replace one - CachedIdx = (pBssIdInfo->BSSID[5] % PMKID_NO); - DBGPRINT(RT_DEBUG_OFF, ("Update OID_802_11_PMKID, idx = %d\n", CachedIdx)); - NdisMoveMemory(&pAdapter->StaCfg.SavedPMK[CachedIdx], pBssIdInfo, sizeof(BSSID_INFO)); - } - } - } - if(pPmkId) - kfree(pPmkId); - break; -#endif // WPA_SUPPLICANT_SUPPORT // - - - -#ifdef SNMP_SUPPORT - case OID_802_11_SHORTRETRYLIMIT: - if (wrq->u.data.length != sizeof(ULONG)) - Status = -EINVAL; - else - { - Status = copy_from_user(&ShortRetryLimit, wrq->u.data.pointer, wrq->u.data.length); - RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); - tx_rty_cfg.field.ShortRtyLimit = ShortRetryLimit; - RTMP_IO_WRITE32(pAdapter, TX_RTY_CFG, tx_rty_cfg.word); - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_SHORTRETRYLIMIT (tx_rty_cfg.field.ShortRetryLimit=%d, ShortRetryLimit=%ld)\n", tx_rty_cfg.field.ShortRtyLimit, ShortRetryLimit)); - } - break; - - case OID_802_11_LONGRETRYLIMIT: - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_LONGRETRYLIMIT \n")); - if (wrq->u.data.length != sizeof(ULONG)) - Status = -EINVAL; - else - { - Status = copy_from_user(&LongRetryLimit, wrq->u.data.pointer, wrq->u.data.length); - RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); - tx_rty_cfg.field.LongRtyLimit = LongRetryLimit; - RTMP_IO_WRITE32(pAdapter, TX_RTY_CFG, tx_rty_cfg.word); - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_LONGRETRYLIMIT (tx_rty_cfg.field.LongRetryLimit= %d,LongRetryLimit=%ld)\n", tx_rty_cfg.field.LongRtyLimit, LongRetryLimit)); - } - break; - - case OID_802_11_WEPDEFAULTKEYVALUE: - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_WEPDEFAULTKEYVALUE\n")); - pKey = kmalloc(wrq->u.data.length, GFP_KERNEL); - Status = copy_from_user(pKey, wrq->u.data.pointer, wrq->u.data.length); - //pKey = &WepKey; - - if ( pKey->Length != wrq->u.data.length) - { - Status = -EINVAL; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_WEPDEFAULTKEYVALUE, Failed!!\n")); - } - KeyIdx = pKey->KeyIndex & 0x0fffffff; - DBGPRINT(RT_DEBUG_TRACE,("pKey->KeyIndex =%d, pKey->KeyLength=%d\n", pKey->KeyIndex, pKey->KeyLength)); - - // it is a shared key - if (KeyIdx > 4) - Status = -EINVAL; - else - { - pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen = (UCHAR) pKey->KeyLength; - NdisMoveMemory(&pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].Key, &pKey->KeyMaterial, pKey->KeyLength); - if (pKey->KeyIndex & 0x80000000) - { - // Default key for tx (shared key) - pAdapter->StaCfg.DefaultKeyId = (UCHAR) KeyIdx; - } - //RestartAPIsRequired = TRUE; - } - break; - - - case OID_802_11_WEPDEFAULTKEYID: - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_WEPDEFAULTKEYID \n")); - - if (wrq->u.data.length != sizeof(UCHAR)) - Status = -EINVAL; - else - Status = copy_from_user(&pAdapter->StaCfg.DefaultKeyId, wrq->u.data.pointer, wrq->u.data.length); - - break; - - - case OID_802_11_CURRENTCHANNEL: - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_CURRENTCHANNEL \n")); - if (wrq->u.data.length != sizeof(UCHAR)) - Status = -EINVAL; - else - { - Status = copy_from_user(&ctmp, wrq->u.data.pointer, wrq->u.data.length); - sprintf(&ctmp,"%d", ctmp); - Set_Channel_Proc(pAdapter, &ctmp); - } - break; -#endif - - - - default: - DBGPRINT(RT_DEBUG_TRACE, ("Set::unknown IOCTL's subcmd = 0x%08x\n", cmd)); - Status = -EOPNOTSUPP; - break; - } - - - return Status; -} - -INT RTMPQueryInformation( - IN PRTMP_ADAPTER pAdapter, - IN OUT struct ifreq *rq, - IN INT cmd) -{ - struct iwreq *wrq = (struct iwreq *) rq; - NDIS_802_11_BSSID_LIST_EX *pBssidList = NULL; - PNDIS_WLAN_BSSID_EX pBss; - NDIS_802_11_SSID Ssid; - NDIS_802_11_CONFIGURATION *pConfiguration = NULL; - RT_802_11_LINK_STATUS *pLinkStatus = NULL; - RT_802_11_STA_CONFIG *pStaConfig = NULL; - NDIS_802_11_STATISTICS *pStatistics = NULL; - NDIS_802_11_RTS_THRESHOLD RtsThresh; - NDIS_802_11_FRAGMENTATION_THRESHOLD FragThresh; - NDIS_802_11_POWER_MODE PowerMode; - NDIS_802_11_NETWORK_INFRASTRUCTURE BssType; - RT_802_11_PREAMBLE PreamType; - NDIS_802_11_AUTHENTICATION_MODE AuthMode; - NDIS_802_11_WEP_STATUS WepStatus; - NDIS_MEDIA_STATE MediaState; - ULONG BssBufSize, ulInfo=0, NetworkTypeList[4], apsd = 0; - USHORT BssLen = 0; - PUCHAR pBuf = NULL, pPtr; - INT Status = NDIS_STATUS_SUCCESS; - UINT we_version_compiled; - UCHAR i, Padding = 0; - BOOLEAN RadioState; - UCHAR driverVersion[8]; - OID_SET_HT_PHYMODE *pHTPhyMode = NULL; - - -#ifdef SNMP_SUPPORT - //for snmp, kathy - DefaultKeyIdxValue *pKeyIdxValue; - INT valueLen; - TX_RTY_CFG_STRUC tx_rty_cfg; - ULONG ShortRetryLimit, LongRetryLimit; - UCHAR tmp[64]; -#endif //SNMP - - switch(cmd) - { - case RT_OID_DEVICE_NAME: - wrq->u.data.length = sizeof(STA_NIC_DEVICE_NAME); - Status = copy_to_user(wrq->u.data.pointer, STA_NIC_DEVICE_NAME, wrq->u.data.length); - break; - case RT_OID_VERSION_INFO: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_VERSION_INFO \n")); - wrq->u.data.length = 8*sizeof(UCHAR); - sprintf(&driverVersion[0], "%s", STA_DRIVER_VERSION); - driverVersion[7] = '\0'; - if (copy_to_user(wrq->u.data.pointer, &driverVersion, wrq->u.data.length)) - { - Status = -EFAULT; - } - break; -#ifdef RALINK_ATE - case RT_QUERY_ATE_TXDONE_COUNT: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_QUERY_ATE_TXDONE_COUNT \n")); - wrq->u.data.length = sizeof(UINT32); - if (copy_to_user(wrq->u.data.pointer, &pAdapter->ate.TxDoneCount, wrq->u.data.length)) - { - Status = -EFAULT; - } - break; -#endif // RALINK_ATE // - case OID_802_11_BSSID_LIST: - if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) - { - /* - * Still scanning, indicate the caller should try again. - */ - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_BSSID_LIST (Still scanning)\n")); - return -EAGAIN; - } - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_BSSID_LIST (%d BSS returned)\n",pAdapter->ScanTab.BssNr)); - pAdapter->StaCfg.bScanReqIsFromWebUI = FALSE; - // Claculate total buffer size required - BssBufSize = sizeof(ULONG); - - for (i = 0; i < pAdapter->ScanTab.BssNr; i++) - { - // Align pointer to 4 bytes boundary. - //Padding = 4 - (pAdapter->ScanTab.BssEntry[i].VarIELen & 0x0003); - //if (Padding == 4) - // Padding = 0; - BssBufSize += (sizeof(NDIS_WLAN_BSSID_EX) - 1 + sizeof(NDIS_802_11_FIXED_IEs) + pAdapter->ScanTab.BssEntry[i].VarIELen + Padding); - } - - // For safety issue, we add 256 bytes just in case - BssBufSize += 256; - // Allocate the same size as passed from higher layer - pBuf = kmalloc(BssBufSize, MEM_ALLOC_FLAG); - if(pBuf == NULL) - { - Status = -ENOMEM; - break; - } - // Init 802_11_BSSID_LIST_EX structure - NdisZeroMemory(pBuf, BssBufSize); - pBssidList = (PNDIS_802_11_BSSID_LIST_EX) pBuf; - pBssidList->NumberOfItems = pAdapter->ScanTab.BssNr; - - // Calculate total buffer length - BssLen = 4; // Consist of NumberOfItems - // Point to start of NDIS_WLAN_BSSID_EX - // pPtr = pBuf + sizeof(ULONG); - pPtr = (PUCHAR) &pBssidList->Bssid[0]; - for (i = 0; i < pAdapter->ScanTab.BssNr; i++) - { - pBss = (PNDIS_WLAN_BSSID_EX) pPtr; - NdisMoveMemory(&pBss->MacAddress, &pAdapter->ScanTab.BssEntry[i].Bssid, MAC_ADDR_LEN); - if ((pAdapter->ScanTab.BssEntry[i].Hidden == 1) && (pAdapter->StaCfg.bShowHiddenSSID == FALSE)) - { - // - // We must return this SSID during 4way handshaking, otherwise Aegis will failed to parse WPA infomation - // and then failed to send EAPOl farame. - // - if ((pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) && (pAdapter->StaCfg.PortSecured != WPA_802_1X_PORT_SECURED)) - { - pBss->Ssid.SsidLength = pAdapter->ScanTab.BssEntry[i].SsidLen; - NdisMoveMemory(pBss->Ssid.Ssid, pAdapter->ScanTab.BssEntry[i].Ssid, pAdapter->ScanTab.BssEntry[i].SsidLen); - } - else - pBss->Ssid.SsidLength = 0; - } - else - { - pBss->Ssid.SsidLength = pAdapter->ScanTab.BssEntry[i].SsidLen; - NdisMoveMemory(pBss->Ssid.Ssid, pAdapter->ScanTab.BssEntry[i].Ssid, pAdapter->ScanTab.BssEntry[i].SsidLen); - } - pBss->Privacy = pAdapter->ScanTab.BssEntry[i].Privacy; - pBss->Rssi = pAdapter->ScanTab.BssEntry[i].Rssi - pAdapter->BbpRssiToDbmDelta; - pBss->NetworkTypeInUse = NetworkTypeInUseSanity(&pAdapter->ScanTab.BssEntry[i]); - pBss->Configuration.Length = sizeof(NDIS_802_11_CONFIGURATION); - pBss->Configuration.BeaconPeriod = pAdapter->ScanTab.BssEntry[i].BeaconPeriod; - pBss->Configuration.ATIMWindow = pAdapter->ScanTab.BssEntry[i].AtimWin; - - MAP_CHANNEL_ID_TO_KHZ(pAdapter->ScanTab.BssEntry[i].Channel, pBss->Configuration.DSConfig); - - if (pAdapter->ScanTab.BssEntry[i].BssType == BSS_INFRA) - pBss->InfrastructureMode = Ndis802_11Infrastructure; - else - pBss->InfrastructureMode = Ndis802_11IBSS; - - NdisMoveMemory(pBss->SupportedRates, pAdapter->ScanTab.BssEntry[i].SupRate, pAdapter->ScanTab.BssEntry[i].SupRateLen); - NdisMoveMemory(pBss->SupportedRates + pAdapter->ScanTab.BssEntry[i].SupRateLen, - pAdapter->ScanTab.BssEntry[i].ExtRate, - pAdapter->ScanTab.BssEntry[i].ExtRateLen); - - if (pAdapter->ScanTab.BssEntry[i].VarIELen == 0) - { - pBss->IELength = sizeof(NDIS_802_11_FIXED_IEs); - NdisMoveMemory(pBss->IEs, &pAdapter->ScanTab.BssEntry[i].FixIEs, sizeof(NDIS_802_11_FIXED_IEs)); - pPtr = pPtr + sizeof(NDIS_WLAN_BSSID_EX) - 1 + sizeof(NDIS_802_11_FIXED_IEs); - } - else - { - pBss->IELength = (ULONG)(sizeof(NDIS_802_11_FIXED_IEs) + pAdapter->ScanTab.BssEntry[i].VarIELen); - pPtr = pPtr + sizeof(NDIS_WLAN_BSSID_EX) - 1 + sizeof(NDIS_802_11_FIXED_IEs); - NdisMoveMemory(pBss->IEs, &pAdapter->ScanTab.BssEntry[i].FixIEs, sizeof(NDIS_802_11_FIXED_IEs)); - NdisMoveMemory(pBss->IEs + sizeof(NDIS_802_11_FIXED_IEs), pAdapter->ScanTab.BssEntry[i].VarIEs, pAdapter->ScanTab.BssEntry[i].VarIELen); - pPtr += pAdapter->ScanTab.BssEntry[i].VarIELen; - } - pBss->Length = (ULONG)(sizeof(NDIS_WLAN_BSSID_EX) - 1 + sizeof(NDIS_802_11_FIXED_IEs) + pAdapter->ScanTab.BssEntry[i].VarIELen + Padding); - -#if WIRELESS_EXT < 17 - if ((BssLen + pBss->Length) < wrq->u.data.length) - BssLen += pBss->Length; - else - { - pBssidList->NumberOfItems = i; - break; - } -#else - BssLen += pBss->Length; -#endif - } - -#if WIRELESS_EXT < 17 - wrq->u.data.length = BssLen; -#else - if (BssLen > wrq->u.data.length) - { - kfree(pBssidList); - return -E2BIG; - } - else - wrq->u.data.length = BssLen; -#endif - Status = copy_to_user(wrq->u.data.pointer, pBssidList, BssLen); - kfree(pBssidList); - break; - case OID_802_3_CURRENT_ADDRESS: - wrq->u.data.length = MAC_ADDR_LEN; - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CurrentAddress, wrq->u.data.length); - break; - case OID_GEN_MEDIA_CONNECT_STATUS: - if (pAdapter->IndicateMediaState == NdisMediaStateConnected) - MediaState = NdisMediaStateConnected; - else - MediaState = NdisMediaStateDisconnected; - - wrq->u.data.length = sizeof(NDIS_MEDIA_STATE); - Status = copy_to_user(wrq->u.data.pointer, &MediaState, wrq->u.data.length); - break; - case OID_802_11_BSSID: -#ifdef RALINK_ATE - if (ATE_ON(pAdapter)) - { - DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now\n")); - Status = NDIS_STATUS_RESOURCES; - break; - } -#endif // RALINK_ATE // - if (INFRA_ON(pAdapter) || ADHOC_ON(pAdapter)) - { - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.Bssid, sizeof(NDIS_802_11_MAC_ADDRESS)); - - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_BSSID(=EMPTY)\n")); - Status = -ENOTCONN; - } - break; - case OID_802_11_SSID: - NdisZeroMemory(&Ssid, sizeof(NDIS_802_11_SSID)); - NdisZeroMemory(Ssid.Ssid, MAX_LEN_OF_SSID); - Ssid.SsidLength = pAdapter->CommonCfg.SsidLen; - memcpy(Ssid.Ssid, pAdapter->CommonCfg.Ssid, Ssid.SsidLength); - wrq->u.data.length = sizeof(NDIS_802_11_SSID); - Status = copy_to_user(wrq->u.data.pointer, &Ssid, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_SSID (Len=%d, ssid=%s)\n", Ssid.SsidLength,Ssid.Ssid)); - break; - case RT_OID_802_11_QUERY_LINK_STATUS: - pLinkStatus = (RT_802_11_LINK_STATUS *) kmalloc(sizeof(RT_802_11_LINK_STATUS), MEM_ALLOC_FLAG); - if (pLinkStatus) - { - pLinkStatus->CurrTxRate = RateIdTo500Kbps[pAdapter->CommonCfg.TxRate]; // unit : 500 kbps - pLinkStatus->ChannelQuality = pAdapter->Mlme.ChannelQuality; - pLinkStatus->RxByteCount = pAdapter->RalinkCounters.ReceivedByteCount; - pLinkStatus->TxByteCount = pAdapter->RalinkCounters.TransmittedByteCount; - pLinkStatus->CentralChannel = pAdapter->CommonCfg.CentralChannel; - wrq->u.data.length = sizeof(RT_802_11_LINK_STATUS); - Status = copy_to_user(wrq->u.data.pointer, pLinkStatus, wrq->u.data.length); - kfree(pLinkStatus); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_LINK_STATUS\n")); - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_LINK_STATUS(kmalloc failed)\n")); - Status = -EFAULT; - } - break; - case OID_802_11_CONFIGURATION: - pConfiguration = (NDIS_802_11_CONFIGURATION *) kmalloc(sizeof(NDIS_802_11_CONFIGURATION), MEM_ALLOC_FLAG); - if (pConfiguration) - { - pConfiguration->Length = sizeof(NDIS_802_11_CONFIGURATION); - pConfiguration->BeaconPeriod = pAdapter->CommonCfg.BeaconPeriod; - pConfiguration->ATIMWindow = pAdapter->StaActive.AtimWin; - MAP_CHANNEL_ID_TO_KHZ(pAdapter->CommonCfg.Channel, pConfiguration->DSConfig); - wrq->u.data.length = sizeof(NDIS_802_11_CONFIGURATION); - Status = copy_to_user(wrq->u.data.pointer, pConfiguration, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_CONFIGURATION(BeaconPeriod=%ld,AtimW=%ld,Channel=%d) \n", - pConfiguration->BeaconPeriod, pConfiguration->ATIMWindow, pAdapter->CommonCfg.Channel)); - kfree(pConfiguration); - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_CONFIGURATION(kmalloc failed)\n")); - Status = -EFAULT; - } - break; - case RT_OID_802_11_SNR_0: - if ((pAdapter->StaCfg.LastSNR0 > 0)) - { - ulInfo = ((0xeb - pAdapter->StaCfg.LastSNR0) * 3) / 16 ; - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_SNR_0(0x=%lx)\n", ulInfo)); - } - else - Status = -EFAULT; - break; - case RT_OID_802_11_SNR_1: - if ((pAdapter->Antenna.field.RxPath > 1) && - (pAdapter->StaCfg.LastSNR1 > 0)) - { - ulInfo = ((0xeb - pAdapter->StaCfg.LastSNR1) * 3) / 16 ; - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE,("Query::RT_OID_802_11_SNR_1(0x=%lx)\n",ulInfo)); - } - else - Status = -EFAULT; - DBGPRINT(RT_DEBUG_TRACE,("Query::RT_OID_802_11_SNR_1(pAdapter->StaCfg.LastSNR1=%d)\n",pAdapter->StaCfg.LastSNR1)); - break; - case OID_802_11_RSSI_TRIGGER: - ulInfo = pAdapter->StaCfg.RssiSample.LastRssi0 - pAdapter->BbpRssiToDbmDelta; - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_RSSI_TRIGGER(=%ld)\n", ulInfo)); - break; - case OID_802_11_RSSI: - case RT_OID_802_11_RSSI: - ulInfo = pAdapter->StaCfg.RssiSample.LastRssi0; - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - break; - case RT_OID_802_11_RSSI_1: - ulInfo = pAdapter->StaCfg.RssiSample.LastRssi1; - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - break; - case RT_OID_802_11_RSSI_2: - ulInfo = pAdapter->StaCfg.RssiSample.LastRssi2; - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - break; - case OID_802_11_STATISTICS: - pStatistics = (NDIS_802_11_STATISTICS *) kmalloc(sizeof(NDIS_802_11_STATISTICS), MEM_ALLOC_FLAG); - if (pStatistics) - { - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_STATISTICS \n")); - // add the most up-to-date h/w raw counters into software counters - NICUpdateRawCounters(pAdapter); - - // Sanity check for calculation of sucessful count - if (pAdapter->WlanCounters.TransmittedFragmentCount.QuadPart < pAdapter->WlanCounters.RetryCount.QuadPart) - pAdapter->WlanCounters.TransmittedFragmentCount.QuadPart = pAdapter->WlanCounters.RetryCount.QuadPart; - - pStatistics->TransmittedFragmentCount.QuadPart = pAdapter->WlanCounters.TransmittedFragmentCount.QuadPart; - pStatistics->MulticastTransmittedFrameCount.QuadPart = pAdapter->WlanCounters.MulticastTransmittedFrameCount.QuadPart; - pStatistics->FailedCount.QuadPart = pAdapter->WlanCounters.FailedCount.QuadPart; - pStatistics->RetryCount.QuadPart = pAdapter->WlanCounters.RetryCount.QuadPart; - pStatistics->MultipleRetryCount.QuadPart = pAdapter->WlanCounters.MultipleRetryCount.QuadPart; - pStatistics->RTSSuccessCount.QuadPart = pAdapter->WlanCounters.RTSSuccessCount.QuadPart; - pStatistics->RTSFailureCount.QuadPart = pAdapter->WlanCounters.RTSFailureCount.QuadPart; - pStatistics->ACKFailureCount.QuadPart = pAdapter->WlanCounters.ACKFailureCount.QuadPart; - pStatistics->FrameDuplicateCount.QuadPart = pAdapter->WlanCounters.FrameDuplicateCount.QuadPart; - pStatistics->ReceivedFragmentCount.QuadPart = pAdapter->WlanCounters.ReceivedFragmentCount.QuadPart; - pStatistics->MulticastReceivedFrameCount.QuadPart = pAdapter->WlanCounters.MulticastReceivedFrameCount.QuadPart; -#ifdef DBG - pStatistics->FCSErrorCount = pAdapter->RalinkCounters.RealFcsErrCount; -#else - pStatistics->FCSErrorCount.QuadPart = pAdapter->WlanCounters.FCSErrorCount.QuadPart; - pStatistics->FrameDuplicateCount.u.LowPart = pAdapter->WlanCounters.FrameDuplicateCount.u.LowPart / 100; -#endif - wrq->u.data.length = sizeof(NDIS_802_11_STATISTICS); - Status = copy_to_user(wrq->u.data.pointer, pStatistics, wrq->u.data.length); - kfree(pStatistics); - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_STATISTICS(kmalloc failed)\n")); - Status = -EFAULT; - } - break; - case OID_GEN_RCV_OK: - ulInfo = pAdapter->Counters8023.GoodReceives; - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - break; - case OID_GEN_RCV_NO_BUFFER: - ulInfo = pAdapter->Counters8023.RxNoBuffer; - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - break; - case RT_OID_802_11_PHY_MODE: - ulInfo = (ULONG)pAdapter->CommonCfg.PhyMode; - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_PHY_MODE (=%ld)\n", ulInfo)); - break; - case RT_OID_802_11_STA_CONFIG: - pStaConfig = (RT_802_11_STA_CONFIG *) kmalloc(sizeof(RT_802_11_STA_CONFIG), MEM_ALLOC_FLAG); - if (pStaConfig) - { - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_STA_CONFIG\n")); - pStaConfig->EnableTxBurst = pAdapter->CommonCfg.bEnableTxBurst; - pStaConfig->EnableTurboRate = 0; - pStaConfig->UseBGProtection = pAdapter->CommonCfg.UseBGProtection; - pStaConfig->UseShortSlotTime = pAdapter->CommonCfg.bUseShortSlotTime; - //pStaConfig->AdhocMode = pAdapter->StaCfg.AdhocMode; - pStaConfig->HwRadioStatus = (pAdapter->StaCfg.bHwRadio == TRUE) ? 1 : 0; - pStaConfig->Rsv1 = 0; - pStaConfig->SystemErrorBitmap = pAdapter->SystemErrorBitmap; - wrq->u.data.length = sizeof(RT_802_11_STA_CONFIG); - Status = copy_to_user(wrq->u.data.pointer, pStaConfig, wrq->u.data.length); - kfree(pStaConfig); - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_STA_CONFIG(kmalloc failed)\n")); - Status = -EFAULT; - } - break; - case OID_802_11_RTS_THRESHOLD: - RtsThresh = pAdapter->CommonCfg.RtsThreshold; - wrq->u.data.length = sizeof(RtsThresh); - Status = copy_to_user(wrq->u.data.pointer, &RtsThresh, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_RTS_THRESHOLD(=%ld)\n", RtsThresh)); - break; - case OID_802_11_FRAGMENTATION_THRESHOLD: - FragThresh = pAdapter->CommonCfg.FragmentThreshold; - if (pAdapter->CommonCfg.bUseZeroToDisableFragment == TRUE) - FragThresh = 0; - wrq->u.data.length = sizeof(FragThresh); - Status = copy_to_user(wrq->u.data.pointer, &FragThresh, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_FRAGMENTATION_THRESHOLD(=%ld)\n", FragThresh)); - break; - case OID_802_11_POWER_MODE: - PowerMode = pAdapter->StaCfg.WindowsPowerMode; - wrq->u.data.length = sizeof(PowerMode); - Status = copy_to_user(wrq->u.data.pointer, &PowerMode, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_POWER_MODE(=%d)\n", PowerMode)); - break; - case RT_OID_802_11_RADIO: - RadioState = (BOOLEAN) pAdapter->StaCfg.bSwRadio; - wrq->u.data.length = sizeof(RadioState); - Status = copy_to_user(wrq->u.data.pointer, &RadioState, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_RADIO (=%d)\n", RadioState)); - break; - case OID_802_11_INFRASTRUCTURE_MODE: - if (pAdapter->StaCfg.BssType == BSS_ADHOC) - BssType = Ndis802_11IBSS; - else if (pAdapter->StaCfg.BssType == BSS_INFRA) - BssType = Ndis802_11Infrastructure; - else if (pAdapter->StaCfg.BssType == BSS_MONITOR) - BssType = Ndis802_11Monitor; - else - BssType = Ndis802_11AutoUnknown; - - wrq->u.data.length = sizeof(BssType); - Status = copy_to_user(wrq->u.data.pointer, &BssType, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_INFRASTRUCTURE_MODE(=%d)\n", BssType)); - break; - case RT_OID_802_11_PREAMBLE: - PreamType = pAdapter->CommonCfg.TxPreamble; - wrq->u.data.length = sizeof(PreamType); - Status = copy_to_user(wrq->u.data.pointer, &PreamType, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_PREAMBLE(=%d)\n", PreamType)); - break; - case OID_802_11_AUTHENTICATION_MODE: - AuthMode = pAdapter->StaCfg.AuthMode; - wrq->u.data.length = sizeof(AuthMode); - Status = copy_to_user(wrq->u.data.pointer, &AuthMode, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_AUTHENTICATION_MODE(=%d)\n", AuthMode)); - break; - case OID_802_11_WEP_STATUS: - WepStatus = pAdapter->StaCfg.WepStatus; - wrq->u.data.length = sizeof(WepStatus); - Status = copy_to_user(wrq->u.data.pointer, &WepStatus, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_WEP_STATUS(=%d)\n", WepStatus)); - break; - case OID_802_11_TX_POWER_LEVEL: - wrq->u.data.length = sizeof(ULONG); - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.TxPower, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_TX_POWER_LEVEL %x\n",pAdapter->CommonCfg.TxPower)); - break; - case RT_OID_802_11_TX_POWER_LEVEL_1: - wrq->u.data.length = sizeof(ULONG); - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.TxPowerPercentage, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_TX_POWER_LEVEL_1 (=%ld)\n", pAdapter->CommonCfg.TxPowerPercentage)); - break; - case OID_802_11_NETWORK_TYPES_SUPPORTED: - if ((pAdapter->RfIcType == RFIC_2850) || (pAdapter->RfIcType == RFIC_2750)) - { - NetworkTypeList[0] = 3; // NumberOfItems = 3 - NetworkTypeList[1] = Ndis802_11DS; // NetworkType[1] = 11b - NetworkTypeList[2] = Ndis802_11OFDM24; // NetworkType[2] = 11g - NetworkTypeList[3] = Ndis802_11OFDM5; // NetworkType[3] = 11a - wrq->u.data.length = 16; - Status = copy_to_user(wrq->u.data.pointer, &NetworkTypeList[0], wrq->u.data.length); - } - else - { - NetworkTypeList[0] = 2; // NumberOfItems = 2 - NetworkTypeList[1] = Ndis802_11DS; // NetworkType[1] = 11b - NetworkTypeList[2] = Ndis802_11OFDM24; // NetworkType[2] = 11g - wrq->u.data.length = 12; - Status = copy_to_user(wrq->u.data.pointer, &NetworkTypeList[0], wrq->u.data.length); - } - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_NETWORK_TYPES_SUPPORTED\n")); - break; - case OID_802_11_NETWORK_TYPE_IN_USE: - wrq->u.data.length = sizeof(ULONG); - if (pAdapter->CommonCfg.PhyMode == PHY_11A) - ulInfo = Ndis802_11OFDM5; - else if ((pAdapter->CommonCfg.PhyMode == PHY_11BG_MIXED) || (pAdapter->CommonCfg.PhyMode == PHY_11G)) - ulInfo = Ndis802_11OFDM24; - else - ulInfo = Ndis802_11DS; - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - break; - case RT_OID_802_11_QUERY_LAST_RX_RATE: - ulInfo = (ULONG)pAdapter->LastRxRate; - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_LAST_RX_RATE (=%ld)\n", ulInfo)); - break; - case RT_OID_802_11_QUERY_LAST_TX_RATE: - //ulInfo = (ULONG)pAdapter->LastTxRate; - ulInfo = (ULONG)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.word; - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_LAST_TX_RATE (=%lx)\n", ulInfo)); - break; - case RT_OID_802_11_QUERY_EEPROM_VERSION: - wrq->u.data.length = sizeof(ULONG); - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->EepromVersion, wrq->u.data.length); - break; - case RT_OID_802_11_QUERY_FIRMWARE_VERSION: - wrq->u.data.length = sizeof(ULONG); - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->FirmwareVersion, wrq->u.data.length); - break; - case RT_OID_802_11_QUERY_NOISE_LEVEL: - wrq->u.data.length = sizeof(UCHAR); - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->BbpWriteLatch[66], wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_NOISE_LEVEL (=%d)\n", pAdapter->BbpWriteLatch[66])); - break; - case RT_OID_802_11_EXTRA_INFO: - wrq->u.data.length = sizeof(ULONG); - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->ExtraInfo, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_EXTRA_INFO (=%ld)\n", pAdapter->ExtraInfo)); - break; - case RT_OID_WE_VERSION_COMPILED: - wrq->u.data.length = sizeof(UINT); - we_version_compiled = WIRELESS_EXT; - Status = copy_to_user(wrq->u.data.pointer, &we_version_compiled, wrq->u.data.length); - break; - case RT_OID_802_11_QUERY_APSD_SETTING: - apsd = (pAdapter->CommonCfg.bAPSDCapable | (pAdapter->CommonCfg.bAPSDAC_BE << 1) | (pAdapter->CommonCfg.bAPSDAC_BK << 2) - | (pAdapter->CommonCfg.bAPSDAC_VI << 3) | (pAdapter->CommonCfg.bAPSDAC_VO << 4) | (pAdapter->CommonCfg.MaxSPLength << 5)); - - wrq->u.data.length = sizeof(ULONG); - Status = copy_to_user(wrq->u.data.pointer, &apsd, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_APSD_SETTING (=0x%lx,APSDCap=%d,AC_BE=%d,AC_BK=%d,AC_VI=%d,AC_VO=%d,MAXSPLen=%d)\n", - apsd,pAdapter->CommonCfg.bAPSDCapable,pAdapter->CommonCfg.bAPSDAC_BE,pAdapter->CommonCfg.bAPSDAC_BK,pAdapter->CommonCfg.bAPSDAC_VI,pAdapter->CommonCfg.bAPSDAC_VO,pAdapter->CommonCfg.MaxSPLength)); - break; - case RT_OID_802_11_QUERY_APSD_PSM: - wrq->u.data.length = sizeof(ULONG); - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.bAPSDForcePowerSave, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_APSD_PSM (=%d)\n", pAdapter->CommonCfg.bAPSDForcePowerSave)); - break; - case RT_OID_802_11_QUERY_WMM: - wrq->u.data.length = sizeof(BOOLEAN); - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.bWmmCapable, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_WMM (=%d)\n", pAdapter->CommonCfg.bWmmCapable)); - break; -#ifdef WPA_SUPPLICANT_SUPPORT - case RT_OID_NEW_DRIVER: - { - UCHAR enabled = 1; - wrq->u.data.length = sizeof(UCHAR); - Status = copy_to_user(wrq->u.data.pointer, &enabled, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_NEW_DRIVER (=%d)\n", enabled)); - } - break; - case RT_OID_WPA_SUPPLICANT_SUPPORT: - wrq->u.data.length = sizeof(UCHAR); - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->StaCfg.WpaSupplicantUP, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_WPA_SUPPLICANT_SUPPORT (=%d)\n", pAdapter->StaCfg.WpaSupplicantUP)); - break; -#endif // WPA_SUPPLICANT_SUPPORT // - - case RT_OID_DRIVER_DEVICE_NAME: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_DRIVER_DEVICE_NAME \n")); - wrq->u.data.length = 16; - if (copy_to_user(wrq->u.data.pointer, pAdapter->StaCfg.dev_name, wrq->u.data.length)) - { - Status = -EFAULT; - } - break; - case RT_OID_802_11_QUERY_HT_PHYMODE: - pHTPhyMode = (OID_SET_HT_PHYMODE *) kmalloc(sizeof(OID_SET_HT_PHYMODE), MEM_ALLOC_FLAG); - if (pHTPhyMode) - { - pHTPhyMode->PhyMode = pAdapter->CommonCfg.PhyMode; - pHTPhyMode->HtMode = (UCHAR)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.field.MODE; - pHTPhyMode->BW = (UCHAR)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.field.BW; - pHTPhyMode->MCS= (UCHAR)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.field.MCS; - pHTPhyMode->SHORTGI= (UCHAR)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.field.ShortGI; - pHTPhyMode->STBC= (UCHAR)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.field.STBC; - - pHTPhyMode->ExtOffset = ((pAdapter->CommonCfg.CentralChannel < pAdapter->CommonCfg.Channel) ? (EXTCHA_BELOW) : (EXTCHA_ABOVE)); - wrq->u.data.length = sizeof(OID_SET_HT_PHYMODE); - if (copy_to_user(wrq->u.data.pointer, pHTPhyMode, wrq->u.data.length)) - { - Status = -EFAULT; - } - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_HT_PHYMODE (PhyMode = %d, MCS =%d, BW = %d, STBC = %d, ExtOffset=%d)\n", - pHTPhyMode->HtMode, pHTPhyMode->MCS, pHTPhyMode->BW, pHTPhyMode->STBC, pHTPhyMode->ExtOffset)); - DBGPRINT(RT_DEBUG_TRACE, (" MlmeUpdateTxRates (.word = %x )\n", pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.word)); - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_STA_CONFIG(kmalloc failed)\n")); - Status = -EFAULT; - } - break; - case RT_OID_802_11_COUNTRY_REGION: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_COUNTRY_REGION \n")); - wrq->u.data.length = sizeof(ulInfo); - ulInfo = pAdapter->CommonCfg.CountryRegionForABand; - ulInfo = (ulInfo << 8)|(pAdapter->CommonCfg.CountryRegion); - if (copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length)) - { - Status = -EFAULT; - } - break; - case RT_OID_802_11_QUERY_DAT_HT_PHYMODE: - pHTPhyMode = (OID_SET_HT_PHYMODE *) kmalloc(sizeof(OID_SET_HT_PHYMODE), MEM_ALLOC_FLAG); - if (pHTPhyMode) - { - pHTPhyMode->PhyMode = pAdapter->CommonCfg.PhyMode; - pHTPhyMode->HtMode = (UCHAR)pAdapter->CommonCfg.RegTransmitSetting.field.HTMODE; - pHTPhyMode->BW = (UCHAR)pAdapter->CommonCfg.RegTransmitSetting.field.BW; - pHTPhyMode->MCS= (UCHAR)pAdapter->StaCfg.DesiredTransmitSetting.field.MCS; - pHTPhyMode->SHORTGI= (UCHAR)pAdapter->CommonCfg.RegTransmitSetting.field.ShortGI; - pHTPhyMode->STBC= (UCHAR)pAdapter->CommonCfg.RegTransmitSetting.field.STBC; - - wrq->u.data.length = sizeof(OID_SET_HT_PHYMODE); - if (copy_to_user(wrq->u.data.pointer, pHTPhyMode, wrq->u.data.length)) - { - Status = -EFAULT; - } - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_HT_PHYMODE (PhyMode = %d, MCS =%d, BW = %d, STBC = %d, ExtOffset=%d)\n", - pHTPhyMode->HtMode, pHTPhyMode->MCS, pHTPhyMode->BW, pHTPhyMode->STBC, pHTPhyMode->ExtOffset)); - DBGPRINT(RT_DEBUG_TRACE, (" MlmeUpdateTxRates (.word = %x )\n", pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.word)); - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_STA_CONFIG(kmalloc failed)\n")); - Status = -EFAULT; - } - break; - case RT_OID_QUERY_MULTIPLE_CARD_SUPPORT: - wrq->u.data.length = sizeof(UCHAR); - i = 0; -#ifdef MULTIPLE_CARD_SUPPORT - i = 1; -#endif // MULTIPLE_CARD_SUPPORT // - if (copy_to_user(wrq->u.data.pointer, &i, wrq->u.data.length)) - { - Status = -EFAULT; - } - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_QUERY_MULTIPLE_CARD_SUPPORT(=%d) \n", i)); - break; -#ifdef SNMP_SUPPORT - case RT_OID_802_11_MAC_ADDRESS: - wrq->u.data.length = MAC_ADDR_LEN; - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CurrentAddress, wrq->u.data.length); - break; - - case RT_OID_802_11_MANUFACTUREROUI: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_MANUFACTUREROUI \n")); - wrq->u.data.length = ManufacturerOUI_LEN; - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CurrentAddress, wrq->u.data.length); - break; - - case RT_OID_802_11_MANUFACTURERNAME: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_MANUFACTURERNAME \n")); - wrq->u.data.length = strlen(ManufacturerNAME); - Status = copy_to_user(wrq->u.data.pointer, ManufacturerNAME, wrq->u.data.length); - break; - - case RT_OID_802_11_RESOURCETYPEIDNAME: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_RESOURCETYPEIDNAME \n")); - wrq->u.data.length = strlen(ResourceTypeIdName); - Status = copy_to_user(wrq->u.data.pointer, ResourceTypeIdName, wrq->u.data.length); - break; - - case RT_OID_802_11_PRIVACYOPTIONIMPLEMENTED: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_PRIVACYOPTIONIMPLEMENTED \n")); - ulInfo = 1; // 1 is support wep else 2 is not support. - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - break; - - case RT_OID_802_11_POWERMANAGEMENTMODE: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_POWERMANAGEMENTMODE \n")); - if (pAdapter->StaCfg.Psm == PSMP_ACTION) - ulInfo = 1; // 1 is power active else 2 is power save. - else - ulInfo = 2; - - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - break; - - case OID_802_11_WEPDEFAULTKEYVALUE: - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_WEPDEFAULTKEYVALUE \n")); - //KeyIdxValue.KeyIdx = pAd->PortCfg.MBSSID[pAd->IoctlIF].DefaultKeyId; - pKeyIdxValue = wrq->u.data.pointer; - DBGPRINT(RT_DEBUG_TRACE,("KeyIdxValue.KeyIdx = %d, \n",pKeyIdxValue->KeyIdx)); - valueLen = pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen; - NdisMoveMemory(pKeyIdxValue->Value, - &pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].Key, - valueLen); - pKeyIdxValue->Value[valueLen]='\0'; - - wrq->u.data.length = sizeof(DefaultKeyIdxValue); - - Status = copy_to_user(wrq->u.data.pointer, pKeyIdxValue, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE,("DefaultKeyId = %d, total len = %d, str len=%d, KeyValue= %02x %02x %02x %02x \n", pAdapter->StaCfg.DefaultKeyId, wrq->u.data.length, pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen, - pAdapter->SharedKey[BSS0][0].Key[0], - pAdapter->SharedKey[BSS0][1].Key[0], - pAdapter->SharedKey[BSS0][2].Key[0], - pAdapter->SharedKey[BSS0][3].Key[0])); - break; - - case OID_802_11_WEPDEFAULTKEYID: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_WEPDEFAULTKEYID \n")); - wrq->u.data.length = sizeof(UCHAR); - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->StaCfg.DefaultKeyId, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("DefaultKeyId =%d \n", pAdapter->StaCfg.DefaultKeyId)); - break; - - case RT_OID_802_11_WEPKEYMAPPINGLENGTH: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_WEPKEYMAPPINGLENGTH \n")); - wrq->u.data.length = sizeof(UCHAR); - Status = copy_to_user(wrq->u.data.pointer, - &pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen, - wrq->u.data.length); - break; - - case OID_802_11_SHORTRETRYLIMIT: - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_SHORTRETRYLIMIT \n")); - wrq->u.data.length = sizeof(ULONG); - RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); - ShortRetryLimit = tx_rty_cfg.field.ShortRtyLimit; - DBGPRINT(RT_DEBUG_TRACE, ("ShortRetryLimit =%ld, tx_rty_cfg.field.ShortRetryLimit=%d\n", ShortRetryLimit, tx_rty_cfg.field.ShortRtyLimit)); - Status = copy_to_user(wrq->u.data.pointer, &ShortRetryLimit, wrq->u.data.length); - break; - - case OID_802_11_LONGRETRYLIMIT: - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_LONGRETRYLIMIT \n")); - wrq->u.data.length = sizeof(ULONG); - RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); - LongRetryLimit = tx_rty_cfg.field.LongRtyLimit; - DBGPRINT(RT_DEBUG_TRACE, ("LongRetryLimit =%ld, tx_rty_cfg.field.LongRtyLimit=%d\n", LongRetryLimit, tx_rty_cfg.field.LongRtyLimit)); - Status = copy_to_user(wrq->u.data.pointer, &LongRetryLimit, wrq->u.data.length); - break; - - case RT_OID_802_11_PRODUCTID: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_PRODUCTID \n")); - -#ifdef RT2870 - sprintf(tmp, "%04x %04x\n", ((POS_COOKIE)pAdapter->OS_Cookie)->pUsb_Dev->descriptor.idVendor ,((POS_COOKIE)pAdapter->OS_Cookie)->pUsb_Dev->descriptor.idProduct); - -#endif // RT2870 // - wrq->u.data.length = strlen(tmp); - Status = copy_to_user(wrq->u.data.pointer, tmp, wrq->u.data.length); - break; - - case RT_OID_802_11_MANUFACTUREID: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_MANUFACTUREID \n")); - wrq->u.data.length = strlen(ManufacturerNAME); - Status = copy_to_user(wrq->u.data.pointer, ManufacturerNAME, wrq->u.data.length); - break; - - case OID_802_11_CURRENTCHANNEL: - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_CURRENTCHANNEL \n")); - wrq->u.data.length = sizeof(UCHAR); - DBGPRINT(RT_DEBUG_TRACE, ("sizeof UCHAR=%d, channel=%d \n", sizeof(UCHAR), pAdapter->CommonCfg.Channel)); - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.Channel, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Status=%d\n", Status)); - break; -#endif //SNMP_SUPPORT - - case OID_802_11_BUILD_CHANNEL_EX: - { - UCHAR value; - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_BUILD_CHANNEL_EX \n")); - wrq->u.data.length = sizeof(UCHAR); -#ifdef EXT_BUILD_CHANNEL_LIST - DBGPRINT(RT_DEBUG_TRACE, ("Support EXT_BUILD_CHANNEL_LIST.\n")); - value = 1; -#else - DBGPRINT(RT_DEBUG_TRACE, ("Doesn't support EXT_BUILD_CHANNEL_LIST.\n")); - value = 0; -#endif // EXT_BUILD_CHANNEL_LIST // - Status = copy_to_user(wrq->u.data.pointer, &value, 1); - DBGPRINT(RT_DEBUG_TRACE, ("Status=%d\n", Status)); - } - break; - - case OID_802_11_GET_CH_LIST: - { - PRT_CHANNEL_LIST_INFO pChListBuf; - - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_GET_CH_LIST \n")); - if (pAdapter->ChannelListNum == 0) - { - wrq->u.data.length = 0; - break; - } - - pChListBuf = (RT_CHANNEL_LIST_INFO *) kmalloc(sizeof(RT_CHANNEL_LIST_INFO), MEM_ALLOC_FLAG); - if (pChListBuf == NULL) - { - wrq->u.data.length = 0; - break; - } - - pChListBuf->ChannelListNum = pAdapter->ChannelListNum; - for (i = 0; i < pChListBuf->ChannelListNum; i++) - pChListBuf->ChannelList[i] = pAdapter->ChannelList[i].Channel; - - wrq->u.data.length = sizeof(RT_CHANNEL_LIST_INFO); - Status = copy_to_user(wrq->u.data.pointer, pChListBuf, sizeof(RT_CHANNEL_LIST_INFO)); - DBGPRINT(RT_DEBUG_TRACE, ("Status=%d\n", Status)); - - if (pChListBuf) - kfree(pChListBuf); - } - break; - - case OID_802_11_GET_COUNTRY_CODE: - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_GET_COUNTRY_CODE \n")); - wrq->u.data.length = 2; - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.CountryCode, 2); - DBGPRINT(RT_DEBUG_TRACE, ("Status=%d\n", Status)); - break; - - case OID_802_11_GET_CHANNEL_GEOGRAPHY: - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_GET_CHANNEL_GEOGRAPHY \n")); - wrq->u.data.length = 1; - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.Geography, 1); - DBGPRINT(RT_DEBUG_TRACE, ("Status=%d\n", Status)); - break; - - -#ifdef QOS_DLS_SUPPORT - case RT_OID_802_11_QUERY_DLS: - wrq->u.data.length = sizeof(BOOLEAN); - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.bDLSCapable, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_DLS(=%d)\n", pAdapter->CommonCfg.bDLSCapable)); - break; - - case RT_OID_802_11_QUERY_DLS_PARAM: - { - PRT_802_11_DLS_INFO pDlsInfo = kmalloc(sizeof(RT_802_11_DLS_INFO), GFP_ATOMIC); - if (pDlsInfo == NULL) - break; - - for (i=0; iEntry[i], &pAdapter->StaCfg.DLSEntry[i], sizeof(RT_802_11_DLS_UI)); - } - - pDlsInfo->num = MAX_NUM_OF_DLS_ENTRY; - wrq->u.data.length = sizeof(RT_802_11_DLS_INFO); - Status = copy_to_user(wrq->u.data.pointer, pDlsInfo, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_DLS_PARAM\n")); - - if (pDlsInfo) - kfree(pDlsInfo); - } - break; -#endif // QOS_DLS_SUPPORT // - default: - DBGPRINT(RT_DEBUG_TRACE, ("Query::unknown IOCTL's subcmd = 0x%08x\n", cmd)); - Status = -EOPNOTSUPP; - break; - } - return Status; -} - -INT rt28xx_sta_ioctl( - IN struct net_device *net_dev, - IN OUT struct ifreq *rq, - IN INT cmd) -{ - POS_COOKIE pObj; - VIRTUAL_ADAPTER *pVirtualAd = NULL; - RTMP_ADAPTER *pAd = NULL; - struct iwreq *wrq = (struct iwreq *) rq; - BOOLEAN StateMachineTouched = FALSE; - INT Status = NDIS_STATUS_SUCCESS; - USHORT subcmd; - - if (net_dev->priv_flags == INT_MAIN) - { - pAd = net_dev->priv; - } - else - { - pVirtualAd = net_dev->priv; - pAd = pVirtualAd->RtmpDev->priv; - } - pObj = (POS_COOKIE) pAd->OS_Cookie; - - if (pAd == NULL) - { - /* if 1st open fail, pAd will be free; - So the net_dev->priv will be NULL in 2rd open */ - return -ENETDOWN; - } - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { -#ifdef CONFIG_APSTA_MIXED_SUPPORT - if (wrq->u.data.pointer == NULL) - { - return Status; - } - - if (strstr(wrq->u.data.pointer, "OpMode") == NULL) -#endif // CONFIG_APSTA_MIXED_SUPPORT // - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - } - - { // determine this ioctl command is comming from which interface. - pObj->ioctl_if_type = INT_MAIN; - pObj->ioctl_if = MAIN_MBSSID; - } - - switch(cmd) - { -#ifdef RALINK_ATE -#ifdef RALINK_28xx_QA - case RTPRIV_IOCTL_ATE: - { - RtmpDoAte(pAd, wrq); - } - break; -#endif // RALINK_28xx_QA // -#endif // RALINK_ATE // - case SIOCGIFHWADDR: - DBGPRINT(RT_DEBUG_TRACE, ("IOCTL::SIOCGIFHWADDR\n")); - memcpy(wrq->u.name, pAd->CurrentAddress, ETH_ALEN); - break; - case SIOCGIWNAME: - { - char *name=&wrq->u.name[0]; - rt_ioctl_giwname(net_dev, NULL, name, NULL); - break; - } - case SIOCGIWESSID: //Get ESSID - { - struct iw_point *essid=&wrq->u.essid; - rt_ioctl_giwessid(net_dev, NULL, essid, essid->pointer); - break; - } - case SIOCSIWESSID: //Set ESSID - { - struct iw_point *essid=&wrq->u.essid; - rt_ioctl_siwessid(net_dev, NULL, essid, essid->pointer); - break; - } - case SIOCSIWNWID: // set network id (the cell) - case SIOCGIWNWID: // get network id - Status = -EOPNOTSUPP; - break; - case SIOCSIWFREQ: //set channel/frequency (Hz) - { - struct iw_freq *freq=&wrq->u.freq; - rt_ioctl_siwfreq(net_dev, NULL, freq, NULL); - break; - } - case SIOCGIWFREQ: // get channel/frequency (Hz) - { - struct iw_freq *freq=&wrq->u.freq; - rt_ioctl_giwfreq(net_dev, NULL, freq, NULL); - break; - } - case SIOCSIWNICKN: //set node name/nickname - { - struct iw_point *data=&wrq->u.data; - rt_ioctl_siwnickn(net_dev, NULL, data, NULL); - break; - } - case SIOCGIWNICKN: //get node name/nickname - { - struct iw_point *data=&wrq->u.data; - rt_ioctl_giwnickn(net_dev, NULL, data, NULL); - break; - } - case SIOCGIWRATE: //get default bit rate (bps) - rt_ioctl_giwrate(net_dev, NULL, &wrq->u, NULL); - break; - case SIOCSIWRATE: //set default bit rate (bps) - rt_ioctl_siwrate(net_dev, NULL, &wrq->u, NULL); - break; - case SIOCGIWRTS: // get RTS/CTS threshold (bytes) - { - struct iw_param *rts=&wrq->u.rts; - rt_ioctl_giwrts(net_dev, NULL, rts, NULL); - break; - } - case SIOCSIWRTS: //set RTS/CTS threshold (bytes) - { - struct iw_param *rts=&wrq->u.rts; - rt_ioctl_siwrts(net_dev, NULL, rts, NULL); - break; - } - case SIOCGIWFRAG: //get fragmentation thr (bytes) - { - struct iw_param *frag=&wrq->u.frag; - rt_ioctl_giwfrag(net_dev, NULL, frag, NULL); - break; - } - case SIOCSIWFRAG: //set fragmentation thr (bytes) - { - struct iw_param *frag=&wrq->u.frag; - rt_ioctl_siwfrag(net_dev, NULL, frag, NULL); - break; - } - case SIOCGIWENCODE: //get encoding token & mode - { - struct iw_point *erq=&wrq->u.encoding; - if(erq->pointer) - rt_ioctl_giwencode(net_dev, NULL, erq, erq->pointer); - break; - } - case SIOCSIWENCODE: //set encoding token & mode - { - struct iw_point *erq=&wrq->u.encoding; - if(erq->pointer) - rt_ioctl_siwencode(net_dev, NULL, erq, erq->pointer); - break; - } - case SIOCGIWAP: //get access point MAC addresses - { - struct sockaddr *ap_addr=&wrq->u.ap_addr; - rt_ioctl_giwap(net_dev, NULL, ap_addr, ap_addr->sa_data); - break; - } - case SIOCSIWAP: //set access point MAC addresses - { - struct sockaddr *ap_addr=&wrq->u.ap_addr; - rt_ioctl_siwap(net_dev, NULL, ap_addr, ap_addr->sa_data); - break; - } - case SIOCGIWMODE: //get operation mode - { - __u32 *mode=&wrq->u.mode; - rt_ioctl_giwmode(net_dev, NULL, mode, NULL); - break; - } - case SIOCSIWMODE: //set operation mode - { - __u32 *mode=&wrq->u.mode; - rt_ioctl_siwmode(net_dev, NULL, mode, NULL); - break; - } - case SIOCGIWSENS: //get sensitivity (dBm) - case SIOCSIWSENS: //set sensitivity (dBm) - case SIOCGIWPOWER: //get Power Management settings - case SIOCSIWPOWER: //set Power Management settings - case SIOCGIWTXPOW: //get transmit power (dBm) - case SIOCSIWTXPOW: //set transmit power (dBm) - case SIOCGIWRANGE: //Get range of parameters - case SIOCGIWRETRY: //get retry limits and lifetime - case SIOCSIWRETRY: //set retry limits and lifetime - Status = -EOPNOTSUPP; - break; - case RT_PRIV_IOCTL: - subcmd = wrq->u.data.flags; - if( subcmd & OID_GET_SET_TOGGLE) - Status = RTMPSetInformation(pAd, rq, subcmd); - else - Status = RTMPQueryInformation(pAd, rq, subcmd); - break; - case SIOCGIWPRIV: - if (wrq->u.data.pointer) - { - if ( access_ok(VERIFY_WRITE, wrq->u.data.pointer, sizeof(privtab)) != TRUE) - break; - wrq->u.data.length = sizeof(privtab) / sizeof(privtab[0]); - if (copy_to_user(wrq->u.data.pointer, privtab, sizeof(privtab))) - Status = -EFAULT; - } - break; - case RTPRIV_IOCTL_SET: - if(access_ok(VERIFY_READ, wrq->u.data.pointer, wrq->u.data.length) != TRUE) - break; - rt_ioctl_setparam(net_dev, NULL, NULL, wrq->u.data.pointer); - break; - case RTPRIV_IOCTL_GSITESURVEY: - RTMPIoctlGetSiteSurvey(pAd, wrq); - break; -#ifdef DBG - case RTPRIV_IOCTL_MAC: - RTMPIoctlMAC(pAd, wrq); - break; - case RTPRIV_IOCTL_E2P: - RTMPIoctlE2PROM(pAd, wrq); - break; -#endif // DBG // - case SIOCETHTOOL: - break; - default: - DBGPRINT(RT_DEBUG_ERROR, ("IOCTL::unknown IOCTL's cmd = 0x%08x\n", cmd)); - Status = -EOPNOTSUPP; - break; - } - - if(StateMachineTouched) // Upper layer sent a MLME-related operations - RT28XX_MLME_HANDLER(pAd); - - return Status; -} - -/* - ========================================================================== - Description: - Set SSID - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_SSID_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - NDIS_802_11_SSID Ssid, *pSsid=NULL; - BOOLEAN StateMachineTouched = FALSE; - int success = TRUE; - - if( strlen(arg) <= MAX_LEN_OF_SSID) - { - NdisZeroMemory(&Ssid, sizeof(NDIS_802_11_SSID)); - if (strlen(arg) != 0) - { - NdisMoveMemory(Ssid.Ssid, arg, strlen(arg)); - Ssid.SsidLength = strlen(arg); - } - else //ANY ssid - { - Ssid.SsidLength = 0; - memcpy(Ssid.Ssid, "", 0); - pAdapter->StaCfg.BssType = BSS_INFRA; - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; - pAdapter->StaCfg.WepStatus = Ndis802_11EncryptionDisabled; - } - pSsid = &Ssid; - - if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) - { - RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); - DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); - } - - pAdapter->MlmeAux.CurrReqIsFromNdis = TRUE; - pAdapter->StaCfg.bScanReqIsFromWebUI = FALSE; - pAdapter->bConfigChanged = TRUE; - - MlmeEnqueue(pAdapter, - MLME_CNTL_STATE_MACHINE, - OID_802_11_SSID, - sizeof(NDIS_802_11_SSID), - (VOID *)pSsid); - - StateMachineTouched = TRUE; - DBGPRINT(RT_DEBUG_TRACE, ("Set_SSID_Proc::(Len=%d,Ssid=%s)\n", Ssid.SsidLength, Ssid.Ssid)); - } - else - success = FALSE; - - if (StateMachineTouched) // Upper layer sent a MLME-related operations - RT28XX_MLME_HANDLER(pAdapter); - - return success; -} - -#ifdef WMM_SUPPORT -/* - ========================================================================== - Description: - Set WmmCapable Enable or Disable - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_WmmCapable_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - BOOLEAN bWmmCapable; - - bWmmCapable = simple_strtol(arg, 0, 10); - - if ((bWmmCapable == 1) -#ifdef RT2870 - && (pAd->NumberOfPipes >= 5) -#endif // RT2870 // - ) - pAd->CommonCfg.bWmmCapable = TRUE; - else if (bWmmCapable == 0) - pAd->CommonCfg.bWmmCapable = FALSE; - else - return FALSE; //Invalid argument - - DBGPRINT(RT_DEBUG_TRACE, ("Set_WmmCapable_Proc::(bWmmCapable=%d)\n", - pAd->CommonCfg.bWmmCapable)); - - return TRUE; -} -#endif // WMM_SUPPORT // - -/* - ========================================================================== - Description: - Set Network Type(Infrastructure/Adhoc mode) - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_NetworkType_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - UINT32 Value = 0; - - if (strcmp(arg, "Adhoc") == 0) - { - if (pAdapter->StaCfg.BssType != BSS_ADHOC) - { - // Config has changed - pAdapter->bConfigChanged = TRUE; - if (MONITOR_ON(pAdapter)) - { - RTMP_IO_WRITE32(pAdapter, RX_FILTR_CFG, STANORMAL); - RTMP_IO_READ32(pAdapter, MAC_SYS_CTRL, &Value); - Value &= (~0x80); - RTMP_IO_WRITE32(pAdapter, MAC_SYS_CTRL, Value); - OPSTATUS_CLEAR_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED); - pAdapter->StaCfg.bAutoReconnect = TRUE; - LinkDown(pAdapter, FALSE); - } - if (INFRA_ON(pAdapter)) - { - //BOOLEAN Cancelled; - // Set the AutoReconnectSsid to prevent it reconnect to old SSID - // Since calling this indicate user don't want to connect to that SSID anymore. - pAdapter->MlmeAux.AutoReconnectSsidLen= 32; - NdisZeroMemory(pAdapter->MlmeAux.AutoReconnectSsid, pAdapter->MlmeAux.AutoReconnectSsidLen); - - LinkDown(pAdapter, FALSE); - - DBGPRINT(RT_DEBUG_TRACE, ("NDIS_STATUS_MEDIA_DISCONNECT Event BB!\n")); - } - } - pAdapter->StaCfg.BssType = BSS_ADHOC; - pAdapter->net_dev->type = pAdapter->StaCfg.OriDevType; - DBGPRINT(RT_DEBUG_TRACE, ("===>Set_NetworkType_Proc::(AD-HOC)\n")); - } - else if (strcmp(arg, "Infra") == 0) - { - if (pAdapter->StaCfg.BssType != BSS_INFRA) - { - // Config has changed - pAdapter->bConfigChanged = TRUE; - if (MONITOR_ON(pAdapter)) - { - RTMP_IO_WRITE32(pAdapter, RX_FILTR_CFG, STANORMAL); - RTMP_IO_READ32(pAdapter, MAC_SYS_CTRL, &Value); - Value &= (~0x80); - RTMP_IO_WRITE32(pAdapter, MAC_SYS_CTRL, Value); - OPSTATUS_CLEAR_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED); - pAdapter->StaCfg.bAutoReconnect = TRUE; - LinkDown(pAdapter, FALSE); - } - if (ADHOC_ON(pAdapter)) - { - // Set the AutoReconnectSsid to prevent it reconnect to old SSID - // Since calling this indicate user don't want to connect to that SSID anymore. - pAdapter->MlmeAux.AutoReconnectSsidLen= 32; - NdisZeroMemory(pAdapter->MlmeAux.AutoReconnectSsid, pAdapter->MlmeAux.AutoReconnectSsidLen); - - LinkDown(pAdapter, FALSE); - } - } - pAdapter->StaCfg.BssType = BSS_INFRA; - pAdapter->net_dev->type = pAdapter->StaCfg.OriDevType; - DBGPRINT(RT_DEBUG_TRACE, ("===>Set_NetworkType_Proc::(INFRA)\n")); - - pAdapter->StaCfg.BssType = BSS_INFRA; - } - else if (strcmp(arg, "Monitor") == 0) - { - UCHAR bbpValue = 0; - BCN_TIME_CFG_STRUC csr; - OPSTATUS_CLEAR_FLAG(pAdapter, fOP_STATUS_INFRA_ON); - OPSTATUS_CLEAR_FLAG(pAdapter, fOP_STATUS_ADHOC_ON); - OPSTATUS_SET_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED); - // disable all periodic state machine - pAdapter->StaCfg.bAutoReconnect = FALSE; - // reset all mlme state machine - RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); - DBGPRINT(RT_DEBUG_TRACE, ("fOP_STATUS_MEDIA_STATE_CONNECTED \n")); - if (pAdapter->CommonCfg.CentralChannel == 0) - { -#ifdef DOT11_N_SUPPORT - if (pAdapter->CommonCfg.PhyMode == PHY_11AN_MIXED) - pAdapter->CommonCfg.CentralChannel = 36; - else -#endif // DOT11_N_SUPPORT // - pAdapter->CommonCfg.CentralChannel = 6; - } -#ifdef DOT11_N_SUPPORT - else - N_ChannelCheck(pAdapter); -#endif // DOT11_N_SUPPORT // - -#ifdef DOT11_N_SUPPORT - if (pAdapter->CommonCfg.PhyMode >= PHY_11ABGN_MIXED && - pAdapter->CommonCfg.RegTransmitSetting.field.BW == BW_40 && - pAdapter->CommonCfg.RegTransmitSetting.field.EXTCHA == EXTCHA_ABOVE) - { - // 40MHz ,control channel at lower - RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, BBP_R4, &bbpValue); - bbpValue &= (~0x18); - bbpValue |= 0x10; - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R4, bbpValue); - pAdapter->CommonCfg.BBPCurrentBW = BW_40; - // RX : control channel at lower - RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, BBP_R3, &bbpValue); - bbpValue &= (~0x20); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R3, bbpValue); - - RTMP_IO_READ32(pAdapter, TX_BAND_CFG, &Value); - Value &= 0xfffffffe; - RTMP_IO_WRITE32(pAdapter, TX_BAND_CFG, Value); - pAdapter->CommonCfg.CentralChannel = pAdapter->CommonCfg.Channel + 2; - AsicSwitchChannel(pAdapter, pAdapter->CommonCfg.CentralChannel, FALSE); - AsicLockChannel(pAdapter, pAdapter->CommonCfg.CentralChannel); - DBGPRINT(RT_DEBUG_TRACE, ("BW_40 ,control_channel(%d), CentralChannel(%d) \n", - pAdapter->CommonCfg.Channel, - pAdapter->CommonCfg.CentralChannel)); - } - else if (pAdapter->CommonCfg.PhyMode >= PHY_11ABGN_MIXED && - pAdapter->CommonCfg.RegTransmitSetting.field.BW == BW_40 && - pAdapter->CommonCfg.RegTransmitSetting.field.EXTCHA == EXTCHA_BELOW) - { - // 40MHz ,control channel at upper - RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, BBP_R4, &bbpValue); - bbpValue &= (~0x18); - bbpValue |= 0x10; - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R4, bbpValue); - pAdapter->CommonCfg.BBPCurrentBW = BW_40; - RTMP_IO_READ32(pAdapter, TX_BAND_CFG, &Value); - Value |= 0x1; - RTMP_IO_WRITE32(pAdapter, TX_BAND_CFG, Value); - - RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, BBP_R3, &bbpValue); - bbpValue |= (0x20); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R3, bbpValue); - pAdapter->CommonCfg.CentralChannel = pAdapter->CommonCfg.Channel - 2; - AsicSwitchChannel(pAdapter, pAdapter->CommonCfg.CentralChannel, FALSE); - AsicLockChannel(pAdapter, pAdapter->CommonCfg.CentralChannel); - DBGPRINT(RT_DEBUG_TRACE, ("BW_40 ,control_channel(%d), CentralChannel(%d) \n", - pAdapter->CommonCfg.Channel, - pAdapter->CommonCfg.CentralChannel)); - } - else -#endif // DOT11_N_SUPPORT // - { - // 20MHz - RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, BBP_R4, &bbpValue); - bbpValue &= (~0x18); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R4, bbpValue); - pAdapter->CommonCfg.BBPCurrentBW = BW_20; - AsicSwitchChannel(pAdapter, pAdapter->CommonCfg.Channel, FALSE); - AsicLockChannel(pAdapter, pAdapter->CommonCfg.Channel); - DBGPRINT(RT_DEBUG_TRACE, ("BW_20, Channel(%d)\n", pAdapter->CommonCfg.Channel)); - } - // Enable Rx with promiscuous reception - RTMP_IO_WRITE32(pAdapter, RX_FILTR_CFG, 0x3); - // ASIC supporsts sniffer function with replacing RSSI with timestamp. - //RTMP_IO_READ32(pAdapter, MAC_SYS_CTRL, &Value); - //Value |= (0x80); - //RTMP_IO_WRITE32(pAdapter, MAC_SYS_CTRL, Value); - // disable sync - RTMP_IO_READ32(pAdapter, BCN_TIME_CFG, &csr.word); - csr.field.bBeaconGen = 0; - csr.field.bTBTTEnable = 0; - csr.field.TsfSyncMode = 0; - RTMP_IO_WRITE32(pAdapter, BCN_TIME_CFG, csr.word); - - pAdapter->StaCfg.BssType = BSS_MONITOR; - pAdapter->net_dev->type = ARPHRD_IEEE80211_PRISM; //ARPHRD_IEEE80211; // IEEE80211 - DBGPRINT(RT_DEBUG_TRACE, ("===>Set_NetworkType_Proc::(MONITOR)\n")); - } - - // Reset Ralink supplicant to not use, it will be set to start when UI set PMK key - pAdapter->StaCfg.WpaState = SS_NOTUSE; - - DBGPRINT(RT_DEBUG_TRACE, ("Set_NetworkType_Proc::(NetworkType=%d)\n", pAdapter->StaCfg.BssType)); - - return TRUE; -} - -/* - ========================================================================== - Description: - Set Authentication mode - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_AuthMode_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - if ((strcmp(arg, "WEPAUTO") == 0) || (strcmp(arg, "wepauto") == 0)) - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeAutoSwitch; - else if ((strcmp(arg, "OPEN") == 0) || (strcmp(arg, "open") == 0)) - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; - else if ((strcmp(arg, "SHARED") == 0) || (strcmp(arg, "shared") == 0)) - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeShared; - else if ((strcmp(arg, "WPAPSK") == 0) || (strcmp(arg, "wpapsk") == 0)) - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPAPSK; - else if ((strcmp(arg, "WPANONE") == 0) || (strcmp(arg, "wpanone") == 0)) - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPANone; - else if ((strcmp(arg, "WPA2PSK") == 0) || (strcmp(arg, "wpa2psk") == 0)) - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA2PSK; -#ifdef WPA_SUPPLICANT_SUPPORT - else if ((strcmp(arg, "WPA") == 0) || (strcmp(arg, "wpa") == 0)) - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA; - else if ((strcmp(arg, "WPA2") == 0) || (strcmp(arg, "wpa2") == 0)) - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA2; -#endif // WPA_SUPPLICANT_SUPPORT // - else - return FALSE; - - pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; - - DBGPRINT(RT_DEBUG_TRACE, ("Set_AuthMode_Proc::(AuthMode=%d)\n", pAdapter->StaCfg.AuthMode)); - - return TRUE; -} - -/* - ========================================================================== - Description: - Set Encryption Type - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_EncrypType_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - if ((strcmp(arg, "NONE") == 0) || (strcmp(arg, "none") == 0)) - { - if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - return TRUE; // do nothing - - pAdapter->StaCfg.WepStatus = Ndis802_11WEPDisabled; - pAdapter->StaCfg.PairCipher = Ndis802_11WEPDisabled; - pAdapter->StaCfg.GroupCipher = Ndis802_11WEPDisabled; - } - else if ((strcmp(arg, "WEP") == 0) || (strcmp(arg, "wep") == 0)) - { - if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - return TRUE; // do nothing - - pAdapter->StaCfg.WepStatus = Ndis802_11WEPEnabled; - pAdapter->StaCfg.PairCipher = Ndis802_11WEPEnabled; - pAdapter->StaCfg.GroupCipher = Ndis802_11WEPEnabled; - } - else if ((strcmp(arg, "TKIP") == 0) || (strcmp(arg, "tkip") == 0)) - { - if (pAdapter->StaCfg.AuthMode < Ndis802_11AuthModeWPA) - return TRUE; // do nothing - - pAdapter->StaCfg.WepStatus = Ndis802_11Encryption2Enabled; - pAdapter->StaCfg.PairCipher = Ndis802_11Encryption2Enabled; - pAdapter->StaCfg.GroupCipher = Ndis802_11Encryption2Enabled; - } - else if ((strcmp(arg, "AES") == 0) || (strcmp(arg, "aes") == 0)) - { - if (pAdapter->StaCfg.AuthMode < Ndis802_11AuthModeWPA) - return TRUE; // do nothing - - pAdapter->StaCfg.WepStatus = Ndis802_11Encryption3Enabled; - pAdapter->StaCfg.PairCipher = Ndis802_11Encryption3Enabled; - pAdapter->StaCfg.GroupCipher = Ndis802_11Encryption3Enabled; - } - else - return FALSE; - - pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; - - DBGPRINT(RT_DEBUG_TRACE, ("Set_EncrypType_Proc::(EncrypType=%d)\n", pAdapter->StaCfg.WepStatus)); - - return TRUE; -} - -/* - ========================================================================== - Description: - Set Default Key ID - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_DefaultKeyID_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - ULONG KeyIdx; - - KeyIdx = simple_strtol(arg, 0, 10); - if((KeyIdx >= 1 ) && (KeyIdx <= 4)) - pAdapter->StaCfg.DefaultKeyId = (UCHAR) (KeyIdx - 1 ); - else - return FALSE; //Invalid argument - - DBGPRINT(RT_DEBUG_TRACE, ("Set_DefaultKeyID_Proc::(DefaultKeyID=%d)\n", pAdapter->StaCfg.DefaultKeyId)); - - return TRUE; -} - -/* - ========================================================================== - Description: - Set WEP KEY1 - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_Key1_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - int KeyLen; - int i; - UCHAR CipherAlg=CIPHER_WEP64; - - if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - return TRUE; // do nothing - - KeyLen = strlen(arg); - - switch (KeyLen) - { - case 5: //wep 40 Ascii type - pAdapter->SharedKey[BSS0][0].KeyLen = KeyLen; - memcpy(pAdapter->SharedKey[BSS0][0].Key, arg, KeyLen); - CipherAlg = CIPHER_WEP64; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key1_Proc::(Key1=%s and type=%s)\n", arg, "Ascii")); - break; - case 10: //wep 40 Hex type - for(i=0; i < KeyLen; i++) - { - if( !isxdigit(*(arg+i)) ) - return FALSE; //Not Hex value; - } - pAdapter->SharedKey[BSS0][0].KeyLen = KeyLen / 2 ; - AtoH(arg, pAdapter->SharedKey[BSS0][0].Key, KeyLen / 2); - CipherAlg = CIPHER_WEP64; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key1_Proc::(Key1=%s and type=%s)\n", arg, "Hex")); - break; - case 13: //wep 104 Ascii type - pAdapter->SharedKey[BSS0][0].KeyLen = KeyLen; - memcpy(pAdapter->SharedKey[BSS0][0].Key, arg, KeyLen); - CipherAlg = CIPHER_WEP128; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key1_Proc::(Key1=%s and type=%s)\n", arg, "Ascii")); - break; - case 26: //wep 104 Hex type - for(i=0; i < KeyLen; i++) - { - if( !isxdigit(*(arg+i)) ) - return FALSE; //Not Hex value; - } - pAdapter->SharedKey[BSS0][0].KeyLen = KeyLen / 2 ; - AtoH(arg, pAdapter->SharedKey[BSS0][0].Key, KeyLen / 2); - CipherAlg = CIPHER_WEP128; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key1_Proc::(Key1=%s and type=%s)\n", arg, "Hex")); - break; - default: //Invalid argument - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key1_Proc::Invalid argument (=%s)\n", arg)); - return FALSE; - } - - pAdapter->SharedKey[BSS0][0].CipherAlg = CipherAlg; - - // Set keys (into ASIC) - if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - ; // not support - else // Old WEP stuff - { - AsicAddSharedKeyEntry(pAdapter, - 0, - 0, - pAdapter->SharedKey[BSS0][0].CipherAlg, - pAdapter->SharedKey[BSS0][0].Key, - NULL, - NULL); - } - - return TRUE; -} -/* - ========================================================================== - - Description: - Set WEP KEY2 - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_Key2_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - int KeyLen; - int i; - UCHAR CipherAlg=CIPHER_WEP64; - - if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - return TRUE; // do nothing - - KeyLen = strlen(arg); - - switch (KeyLen) - { - case 5: //wep 40 Ascii type - pAdapter->SharedKey[BSS0][1].KeyLen = KeyLen; - memcpy(pAdapter->SharedKey[BSS0][1].Key, arg, KeyLen); - CipherAlg = CIPHER_WEP64; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key2_Proc::(Key2=%s and type=%s)\n", arg, "Ascii")); - break; - case 10: //wep 40 Hex type - for(i=0; i < KeyLen; i++) - { - if( !isxdigit(*(arg+i)) ) - return FALSE; //Not Hex value; - } - pAdapter->SharedKey[BSS0][1].KeyLen = KeyLen / 2 ; - AtoH(arg, pAdapter->SharedKey[BSS0][1].Key, KeyLen / 2); - CipherAlg = CIPHER_WEP64; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key2_Proc::(Key2=%s and type=%s)\n", arg, "Hex")); - break; - case 13: //wep 104 Ascii type - pAdapter->SharedKey[BSS0][1].KeyLen = KeyLen; - memcpy(pAdapter->SharedKey[BSS0][1].Key, arg, KeyLen); - CipherAlg = CIPHER_WEP128; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key2_Proc::(Key2=%s and type=%s)\n", arg, "Ascii")); - break; - case 26: //wep 104 Hex type - for(i=0; i < KeyLen; i++) - { - if( !isxdigit(*(arg+i)) ) - return FALSE; //Not Hex value; - } - pAdapter->SharedKey[BSS0][1].KeyLen = KeyLen / 2 ; - AtoH(arg, pAdapter->SharedKey[BSS0][1].Key, KeyLen / 2); - CipherAlg = CIPHER_WEP128; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key2_Proc::(Key2=%s and type=%s)\n", arg, "Hex")); - break; - default: //Invalid argument - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key2_Proc::Invalid argument (=%s)\n", arg)); - return FALSE; - } - pAdapter->SharedKey[BSS0][1].CipherAlg = CipherAlg; - - // Set keys (into ASIC) - if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - ; // not support - else // Old WEP stuff - { - AsicAddSharedKeyEntry(pAdapter, - 0, - 1, - pAdapter->SharedKey[BSS0][1].CipherAlg, - pAdapter->SharedKey[BSS0][1].Key, - NULL, - NULL); - } - - return TRUE; -} -/* - ========================================================================== - Description: - Set WEP KEY3 - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_Key3_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - int KeyLen; - int i; - UCHAR CipherAlg=CIPHER_WEP64; - - if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - return TRUE; // do nothing - - KeyLen = strlen(arg); - - switch (KeyLen) - { - case 5: //wep 40 Ascii type - pAdapter->SharedKey[BSS0][2].KeyLen = KeyLen; - memcpy(pAdapter->SharedKey[BSS0][2].Key, arg, KeyLen); - CipherAlg = CIPHER_WEP64; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key3_Proc::(Key3=%s and type=Ascii)\n", arg)); - break; - case 10: //wep 40 Hex type - for(i=0; i < KeyLen; i++) - { - if( !isxdigit(*(arg+i)) ) - return FALSE; //Not Hex value; - } - pAdapter->SharedKey[BSS0][2].KeyLen = KeyLen / 2 ; - AtoH(arg, pAdapter->SharedKey[BSS0][2].Key, KeyLen / 2); - CipherAlg = CIPHER_WEP64; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key3_Proc::(Key3=%s and type=Hex)\n", arg)); - break; - case 13: //wep 104 Ascii type - pAdapter->SharedKey[BSS0][2].KeyLen = KeyLen; - memcpy(pAdapter->SharedKey[BSS0][2].Key, arg, KeyLen); - CipherAlg = CIPHER_WEP128; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key3_Proc::(Key3=%s and type=Ascii)\n", arg)); - break; - case 26: //wep 104 Hex type - for(i=0; i < KeyLen; i++) - { - if( !isxdigit(*(arg+i)) ) - return FALSE; //Not Hex value; - } - pAdapter->SharedKey[BSS0][2].KeyLen = KeyLen / 2 ; - AtoH(arg, pAdapter->SharedKey[BSS0][2].Key, KeyLen / 2); - CipherAlg = CIPHER_WEP128; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key3_Proc::(Key3=%s and type=Hex)\n", arg)); - break; - default: //Invalid argument - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key3_Proc::Invalid argument (=%s)\n", arg)); - return FALSE; - } - pAdapter->SharedKey[BSS0][2].CipherAlg = CipherAlg; - - // Set keys (into ASIC) - if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - ; // not support - else // Old WEP stuff - { - AsicAddSharedKeyEntry(pAdapter, - 0, - 2, - pAdapter->SharedKey[BSS0][2].CipherAlg, - pAdapter->SharedKey[BSS0][2].Key, - NULL, - NULL); - } - - return TRUE; -} -/* - ========================================================================== - Description: - Set WEP KEY4 - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_Key4_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - int KeyLen; - int i; - UCHAR CipherAlg=CIPHER_WEP64; - - if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - return TRUE; // do nothing - - KeyLen = strlen(arg); - - switch (KeyLen) - { - case 5: //wep 40 Ascii type - pAdapter->SharedKey[BSS0][3].KeyLen = KeyLen; - memcpy(pAdapter->SharedKey[BSS0][3].Key, arg, KeyLen); - CipherAlg = CIPHER_WEP64; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key4_Proc::(Key4=%s and type=%s)\n", arg, "Ascii")); - break; - case 10: //wep 40 Hex type - for(i=0; i < KeyLen; i++) - { - if( !isxdigit(*(arg+i)) ) - return FALSE; //Not Hex value; - } - pAdapter->SharedKey[BSS0][3].KeyLen = KeyLen / 2 ; - AtoH(arg, pAdapter->SharedKey[BSS0][3].Key, KeyLen / 2); - CipherAlg = CIPHER_WEP64; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key4_Proc::(Key4=%s and type=%s)\n", arg, "Hex")); - break; - case 13: //wep 104 Ascii type - pAdapter->SharedKey[BSS0][3].KeyLen = KeyLen; - memcpy(pAdapter->SharedKey[BSS0][3].Key, arg, KeyLen); - CipherAlg = CIPHER_WEP128; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key4_Proc::(Key4=%s and type=%s)\n", arg, "Ascii")); - break; - case 26: //wep 104 Hex type - for(i=0; i < KeyLen; i++) - { - if( !isxdigit(*(arg+i)) ) - return FALSE; //Not Hex value; - } - pAdapter->SharedKey[BSS0][3].KeyLen = KeyLen / 2 ; - AtoH(arg, pAdapter->SharedKey[BSS0][3].Key, KeyLen / 2); - CipherAlg = CIPHER_WEP128; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key4_Proc::(Key4=%s and type=%s)\n", arg, "Hex")); - break; - default: //Invalid argument - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key4_Proc::Invalid argument (=%s)\n", arg)); - return FALSE; - } - pAdapter->SharedKey[BSS0][3].CipherAlg = CipherAlg; - - // Set keys (into ASIC) - if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - ; // not support - else // Old WEP stuff - { - AsicAddSharedKeyEntry(pAdapter, - 0, - 3, - pAdapter->SharedKey[BSS0][3].CipherAlg, - pAdapter->SharedKey[BSS0][3].Key, - NULL, - NULL); - } - - return TRUE; -} - -/* - ========================================================================== - Description: - Set WPA PSK key - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_WPAPSK_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - UCHAR keyMaterial[40]; - - if ((pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPAPSK) && - (pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPA2PSK) && - (pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPANone) - ) - return TRUE; // do nothing - - DBGPRINT(RT_DEBUG_TRACE, ("Set_WPAPSK_Proc::(WPAPSK=%s)\n", arg)); - - NdisZeroMemory(keyMaterial, 40); - - if ((strlen(arg) < 8) || (strlen(arg) > 64)) - { - DBGPRINT(RT_DEBUG_TRACE, ("Set failed!!(WPAPSK=%s), WPAPSK key-string required 8 ~ 64 characters \n", arg)); - return FALSE; - } - - if (strlen(arg) == 64) - { - AtoH(arg, keyMaterial, 32); - NdisMoveMemory(pAdapter->StaCfg.PMK, keyMaterial, 32); - - } - else - { - PasswordHash((char *)arg, pAdapter->MlmeAux.Ssid, pAdapter->MlmeAux.SsidLen, keyMaterial); - NdisMoveMemory(pAdapter->StaCfg.PMK, keyMaterial, 32); - } - - - - if(pAdapter->StaCfg.BssType == BSS_ADHOC && - pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) - { - pAdapter->StaCfg.WpaState = SS_NOTUSE; - } - else - { - // Start STA supplicant state machine - pAdapter->StaCfg.WpaState = SS_START; - } - - return TRUE; -} - -/* - ========================================================================== - Description: - Set Power Saving mode - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_PSMode_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - if (pAdapter->StaCfg.BssType == BSS_INFRA) - { - if ((strcmp(arg, "Max_PSP") == 0) || - (strcmp(arg, "max_psp") == 0) || - (strcmp(arg, "MAX_PSP") == 0)) - { - // do NOT turn on PSM bit here, wait until MlmeCheckForPsmChange() - // to exclude certain situations. - if (pAdapter->StaCfg.bWindowsACCAMEnable == FALSE) - pAdapter->StaCfg.WindowsPowerMode = Ndis802_11PowerModeMAX_PSP; - pAdapter->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeMAX_PSP; - OPSTATUS_SET_FLAG(pAdapter, fOP_STATUS_RECEIVE_DTIM); - pAdapter->StaCfg.DefaultListenCount = 5; - - } - else if ((strcmp(arg, "Fast_PSP") == 0) || - (strcmp(arg, "fast_psp") == 0) || - (strcmp(arg, "FAST_PSP") == 0)) - { - // do NOT turn on PSM bit here, wait until MlmeCheckForPsmChange() - // to exclude certain situations. - OPSTATUS_SET_FLAG(pAdapter, fOP_STATUS_RECEIVE_DTIM); - if (pAdapter->StaCfg.bWindowsACCAMEnable == FALSE) - pAdapter->StaCfg.WindowsPowerMode = Ndis802_11PowerModeFast_PSP; - pAdapter->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeFast_PSP; - pAdapter->StaCfg.DefaultListenCount = 3; - } - else if ((strcmp(arg, "Legacy_PSP") == 0) || - (strcmp(arg, "legacy_psp") == 0) || - (strcmp(arg, "LEGACY_PSP") == 0)) - { - // do NOT turn on PSM bit here, wait until MlmeCheckForPsmChange() - // to exclude certain situations. - OPSTATUS_SET_FLAG(pAdapter, fOP_STATUS_RECEIVE_DTIM); - if (pAdapter->StaCfg.bWindowsACCAMEnable == FALSE) - pAdapter->StaCfg.WindowsPowerMode = Ndis802_11PowerModeLegacy_PSP; - pAdapter->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeLegacy_PSP; - pAdapter->StaCfg.DefaultListenCount = 3; - } - else - { - //Default Ndis802_11PowerModeCAM - // clear PSM bit immediately - MlmeSetPsmBit(pAdapter, PWR_ACTIVE); - OPSTATUS_SET_FLAG(pAdapter, fOP_STATUS_RECEIVE_DTIM); - if (pAdapter->StaCfg.bWindowsACCAMEnable == FALSE) - pAdapter->StaCfg.WindowsPowerMode = Ndis802_11PowerModeCAM; - pAdapter->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeCAM; - } - - DBGPRINT(RT_DEBUG_TRACE, ("Set_PSMode_Proc::(PSMode=%ld)\n", pAdapter->StaCfg.WindowsPowerMode)); - } - else - return FALSE; - - - return TRUE; -} - -#ifdef WPA_SUPPLICANT_SUPPORT -/* - ========================================================================== - Description: - Set WpaSupport flag. - Value: - 0: Driver ignore wpa_supplicant. - 1: wpa_supplicant initiates scanning and AP selection. - 2: driver takes care of scanning, AP selection, and IEEE 802.11 association parameters. - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_Wpa_Support( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - - if ( simple_strtol(arg, 0, 10) == 0) - pAd->StaCfg.WpaSupplicantUP = WPA_SUPPLICANT_DISABLE; - else if ( simple_strtol(arg, 0, 10) == 1) - pAd->StaCfg.WpaSupplicantUP = WPA_SUPPLICANT_ENABLE; - else if ( simple_strtol(arg, 0, 10) == 2) - pAd->StaCfg.WpaSupplicantUP = WPA_SUPPLICANT_ENABLE_WITH_WEB_UI; - else - pAd->StaCfg.WpaSupplicantUP = WPA_SUPPLICANT_DISABLE; - - DBGPRINT(RT_DEBUG_TRACE, ("Set_Wpa_Support::(WpaSupplicantUP=%d)\n", pAd->StaCfg.WpaSupplicantUP)); - - return TRUE; -} -#endif // WPA_SUPPLICANT_SUPPORT // - -#ifdef DBG -/* - ========================================================================== - Description: - Read / Write MAC - Arguments: - pAdapter Pointer to our adapter - wrq Pointer to the ioctl argument - - Return Value: - None - - Note: - Usage: - 1.) iwpriv ra0 mac 0 ==> read MAC where Addr=0x0 - 2.) iwpriv ra0 mac 0=12 ==> write MAC where Addr=0x0, value=12 - ========================================================================== -*/ -VOID RTMPIoctlMAC( - IN PRTMP_ADAPTER pAdapter, - IN struct iwreq *wrq) -{ - CHAR *this_char; - CHAR *value; - INT j = 0, k = 0; - CHAR msg[1024]; - CHAR arg[255]; - ULONG macAddr = 0; - UCHAR temp[16], temp2[16]; - UINT32 macValue = 0; - INT Status; - - - memset(msg, 0x00, 1024); - if (wrq->u.data.length > 1) //No parameters. - { - Status = copy_from_user(arg, wrq->u.data.pointer, (wrq->u.data.length > 255) ? 255 : wrq->u.data.length); - sprintf(msg, "\n"); - - //Parsing Read or Write - this_char = arg; - if (!*this_char) - goto next; - - if ((value = rtstrchr(this_char, '=')) != NULL) - *value++ = 0; - - if (!value || !*value) - { //Read - // Sanity check - if(strlen(this_char) > 4) - goto next; - - j = strlen(this_char); - while(j-- > 0) - { - if(this_char[j] > 'f' || this_char[j] < '0') - return; - } - - // Mac Addr - k = j = strlen(this_char); - while(j-- > 0) - { - this_char[4-k+j] = this_char[j]; - } - - while(k < 4) - this_char[3-k++]='0'; - this_char[4]='\0'; - - if(strlen(this_char) == 4) - { - AtoH(this_char, temp, 2); - macAddr = *temp*256 + temp[1]; - if (macAddr < 0xFFFF) - { - RTMP_IO_READ32(pAdapter, macAddr, &macValue); - DBGPRINT(RT_DEBUG_TRACE, ("MacAddr=%lx, MacValue=%x\n", macAddr, macValue)); - sprintf(msg+strlen(msg), "[0x%08lX]:%08X ", macAddr , macValue); - } - else - {//Invalid parametes, so default printk all bbp - goto next; - } - } - } - else - { //Write - memcpy(&temp2, value, strlen(value)); - temp2[strlen(value)] = '\0'; - - // Sanity check - if((strlen(this_char) > 4) || strlen(temp2) > 8) - goto next; - - j = strlen(this_char); - while(j-- > 0) - { - if(this_char[j] > 'f' || this_char[j] < '0') - return; - } - - j = strlen(temp2); - while(j-- > 0) - { - if(temp2[j] > 'f' || temp2[j] < '0') - return; - } - - //MAC Addr - k = j = strlen(this_char); - while(j-- > 0) - { - this_char[4-k+j] = this_char[j]; - } - - while(k < 4) - this_char[3-k++]='0'; - this_char[4]='\0'; - - //MAC value - k = j = strlen(temp2); - while(j-- > 0) - { - temp2[8-k+j] = temp2[j]; - } - - while(k < 8) - temp2[7-k++]='0'; - temp2[8]='\0'; - - { - AtoH(this_char, temp, 2); - macAddr = *temp*256 + temp[1]; - - AtoH(temp2, temp, 4); - macValue = *temp*256*256*256 + temp[1]*256*256 + temp[2]*256 + temp[3]; - - // debug mode - if (macAddr == (HW_DEBUG_SETTING_BASE + 4)) - { - // 0x2bf4: byte0 non-zero: enable R17 tuning, 0: disable R17 tuning - if (macValue & 0x000000ff) - { - pAdapter->BbpTuning.bEnable = TRUE; - DBGPRINT(RT_DEBUG_TRACE,("turn on R17 tuning\n")); - } - else - { - UCHAR R66; - pAdapter->BbpTuning.bEnable = FALSE; - R66 = 0x26 + GET_LNA_GAIN(pAdapter); -#ifdef RALINK_ATE - if (ATE_ON(pAdapter)) - { - ATE_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R66, (0x26 + GET_LNA_GAIN(pAdapter))); - } - else -#endif // RALINK_ATE // - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R66, (0x26 + GET_LNA_GAIN(pAdapter))); - DBGPRINT(RT_DEBUG_TRACE,("turn off R17 tuning, restore to 0x%02x\n", R66)); - } - return; - } - - DBGPRINT(RT_DEBUG_TRACE, ("MacAddr=%02lx, MacValue=0x%x\n", macAddr, macValue)); - - RTMP_IO_WRITE32(pAdapter, macAddr, macValue); - sprintf(msg+strlen(msg), "[0x%08lX]:%08X ", macAddr, macValue); - } - } - } -next: - if(strlen(msg) == 1) - sprintf(msg+strlen(msg), "===>Error command format!"); - - // Copy the information into the user buffer - wrq->u.data.length = strlen(msg); - Status = copy_to_user(wrq->u.data.pointer, msg, wrq->u.data.length); - - DBGPRINT(RT_DEBUG_TRACE, ("<==RTMPIoctlMAC\n\n")); -} - -/* - ========================================================================== - Description: - Read / Write E2PROM - Arguments: - pAdapter Pointer to our adapter - wrq Pointer to the ioctl argument - - Return Value: - None - - Note: - Usage: - 1.) iwpriv ra0 e2p 0 ==> read E2PROM where Addr=0x0 - 2.) iwpriv ra0 e2p 0=1234 ==> write E2PROM where Addr=0x0, value=1234 - ========================================================================== -*/ -VOID RTMPIoctlE2PROM( - IN PRTMP_ADAPTER pAdapter, - IN struct iwreq *wrq) -{ - CHAR *this_char; - CHAR *value; - INT j = 0, k = 0; - CHAR msg[1024]; - CHAR arg[255]; - USHORT eepAddr = 0; - UCHAR temp[16], temp2[16]; - USHORT eepValue; - int Status; - - - memset(msg, 0x00, 1024); - if (wrq->u.data.length > 1) //No parameters. - { - Status = copy_from_user(arg, wrq->u.data.pointer, (wrq->u.data.length > 255) ? 255 : wrq->u.data.length); - sprintf(msg, "\n"); - - //Parsing Read or Write - this_char = arg; - - - if (!*this_char) - goto next; - - if ((value = rtstrchr(this_char, '=')) != NULL) - *value++ = 0; - - if (!value || !*value) - { //Read - - // Sanity check - if(strlen(this_char) > 4) - goto next; - - j = strlen(this_char); - while(j-- > 0) - { - if(this_char[j] > 'f' || this_char[j] < '0') - return; - } - - // E2PROM addr - k = j = strlen(this_char); - while(j-- > 0) - { - this_char[4-k+j] = this_char[j]; - } - - while(k < 4) - this_char[3-k++]='0'; - this_char[4]='\0'; - - if(strlen(this_char) == 4) - { - AtoH(this_char, temp, 2); - eepAddr = *temp*256 + temp[1]; - if (eepAddr < 0xFFFF) - { - RT28xx_EEPROM_READ16(pAdapter, eepAddr, eepValue); - sprintf(msg+strlen(msg), "[0x%04X]:0x%04X ", eepAddr , eepValue); - } - else - {//Invalid parametes, so default printk all bbp - goto next; - } - } - } - else - { //Write - memcpy(&temp2, value, strlen(value)); - temp2[strlen(value)] = '\0'; - - // Sanity check - if((strlen(this_char) > 4) || strlen(temp2) > 8) - goto next; - - j = strlen(this_char); - while(j-- > 0) - { - if(this_char[j] > 'f' || this_char[j] < '0') - return; - } - j = strlen(temp2); - while(j-- > 0) - { - if(temp2[j] > 'f' || temp2[j] < '0') - return; - } - - //MAC Addr - k = j = strlen(this_char); - while(j-- > 0) - { - this_char[4-k+j] = this_char[j]; - } - - while(k < 4) - this_char[3-k++]='0'; - this_char[4]='\0'; - - //MAC value - k = j = strlen(temp2); - while(j-- > 0) - { - temp2[4-k+j] = temp2[j]; - } - - while(k < 4) - temp2[3-k++]='0'; - temp2[4]='\0'; - - AtoH(this_char, temp, 2); - eepAddr = *temp*256 + temp[1]; - - AtoH(temp2, temp, 2); - eepValue = *temp*256 + temp[1]; - - RT28xx_EEPROM_WRITE16(pAdapter, eepAddr, eepValue); - sprintf(msg+strlen(msg), "[0x%02X]:%02X ", eepAddr, eepValue); - } - } -next: - if(strlen(msg) == 1) - sprintf(msg+strlen(msg), "===>Error command format!"); - - - // Copy the information into the user buffer - wrq->u.data.length = strlen(msg); - Status = copy_to_user(wrq->u.data.pointer, msg, wrq->u.data.length); - - DBGPRINT(RT_DEBUG_TRACE, ("<==RTMPIoctlE2PROM\n")); -} -#endif // DBG // - - - - -INT Set_TGnWifiTest_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - if (simple_strtol(arg, 0, 10) == 0) - pAd->StaCfg.bTGnWifiTest = FALSE; - else - pAd->StaCfg.bTGnWifiTest = TRUE; - - DBGPRINT(RT_DEBUG_TRACE, ("IF Set_TGnWifiTest_Proc::(bTGnWifiTest=%d)\n", pAd->StaCfg.bTGnWifiTest)); - return TRUE; -} - -INT Set_LongRetryLimit_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - TX_RTY_CFG_STRUC tx_rty_cfg; - UCHAR LongRetryLimit = (UCHAR)simple_strtol(arg, 0, 10); - - RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); - tx_rty_cfg.field.LongRtyLimit = LongRetryLimit; - RTMP_IO_WRITE32(pAdapter, TX_RTY_CFG, tx_rty_cfg.word); - DBGPRINT(RT_DEBUG_TRACE, ("IF Set_LongRetryLimit_Proc::(tx_rty_cfg=0x%x)\n", tx_rty_cfg.word)); - return TRUE; -} - -INT Set_ShortRetryLimit_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - TX_RTY_CFG_STRUC tx_rty_cfg; - UCHAR ShortRetryLimit = (UCHAR)simple_strtol(arg, 0, 10); - - RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); - tx_rty_cfg.field.ShortRtyLimit = ShortRetryLimit; - RTMP_IO_WRITE32(pAdapter, TX_RTY_CFG, tx_rty_cfg.word); - DBGPRINT(RT_DEBUG_TRACE, ("IF Set_ShortRetryLimit_Proc::(tx_rty_cfg=0x%x)\n", tx_rty_cfg.word)); - return TRUE; -} - -#ifdef EXT_BUILD_CHANNEL_LIST -INT Set_Ieee80211dClientMode_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - if (simple_strtol(arg, 0, 10) == 0) - pAdapter->StaCfg.IEEE80211dClientMode = Rt802_11_D_None; - else if (simple_strtol(arg, 0, 10) == 1) - pAdapter->StaCfg.IEEE80211dClientMode = Rt802_11_D_Flexible; - else if (simple_strtol(arg, 0, 10) == 2) - pAdapter->StaCfg.IEEE80211dClientMode = Rt802_11_D_Strict; - else - return FALSE; - - DBGPRINT(RT_DEBUG_TRACE, ("Set_Ieee802dMode_Proc::(IEEEE0211dMode=%d)\n", pAdapter->StaCfg.IEEE80211dClientMode)); - return TRUE; -} -#endif // EXT_BUILD_CHANNEL_LIST // - -#ifdef CARRIER_DETECTION_SUPPORT -INT Set_CarrierDetect_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - if (simple_strtol(arg, 0, 10) == 0) - pAd->CommonCfg.CarrierDetect.Enable = FALSE; - else - pAd->CommonCfg.CarrierDetect.Enable = TRUE; - - DBGPRINT(RT_DEBUG_TRACE, ("IF Set_CarrierDetect_Proc::(CarrierDetect.Enable=%d)\n", pAd->CommonCfg.CarrierDetect.Enable)); - return TRUE; -} -#endif // CARRIER_DETECTION_SUPPORT // - - -INT Show_Adhoc_MacTable_Proc( - IN PRTMP_ADAPTER pAd, - IN PCHAR extra) -{ - INT i; - - sprintf(extra, "\n"); - -#ifdef DOT11_N_SUPPORT - sprintf(extra, "%sHT Operating Mode : %d\n", extra, pAd->CommonCfg.AddHTInfo.AddHtInfo2.OperaionMode); -#endif // DOT11_N_SUPPORT // - - sprintf(extra, "%s\n%-19s%-4s%-4s%-7s%-7s%-7s%-10s%-6s%-6s%-6s%-6s\n", extra, - "MAC", "AID", "BSS", "RSSI0", "RSSI1", "RSSI2", "PhMd", "BW", "MCS", "SGI", "STBC"); - - for (i=1; iMacTab.Content[i]; - - if (strlen(extra) > (IW_PRIV_SIZE_MASK - 30)) - break; - if ((pEntry->ValidAsCLI || pEntry->ValidAsApCli) && (pEntry->Sst == SST_ASSOC)) - { - sprintf(extra, "%s%02X:%02X:%02X:%02X:%02X:%02X ", extra, - pEntry->Addr[0], pEntry->Addr[1], pEntry->Addr[2], - pEntry->Addr[3], pEntry->Addr[4], pEntry->Addr[5]); - sprintf(extra, "%s%-4d", extra, (int)pEntry->Aid); - sprintf(extra, "%s%-4d", extra, (int)pEntry->apidx); - sprintf(extra, "%s%-7d", extra, pEntry->RssiSample.AvgRssi0); - sprintf(extra, "%s%-7d", extra, pEntry->RssiSample.AvgRssi1); - sprintf(extra, "%s%-7d", extra, pEntry->RssiSample.AvgRssi2); - sprintf(extra, "%s%-10s", extra, GetPhyMode(pEntry->HTPhyMode.field.MODE)); - sprintf(extra, "%s%-6s", extra, GetBW(pEntry->HTPhyMode.field.BW)); - sprintf(extra, "%s%-6d", extra, pEntry->HTPhyMode.field.MCS); - sprintf(extra, "%s%-6d", extra, pEntry->HTPhyMode.field.ShortGI); - sprintf(extra, "%s%-6d", extra, pEntry->HTPhyMode.field.STBC); - sprintf(extra, "%s%-10d, %d, %d%%\n", extra, pEntry->DebugFIFOCount, pEntry->DebugTxCount, - (pEntry->DebugTxCount) ? ((pEntry->DebugTxCount-pEntry->DebugFIFOCount)*100/pEntry->DebugTxCount) : 0); - sprintf(extra, "%s\n", extra); - } - } - - return TRUE; -} - - diff --git a/drivers/staging/rt2870/wpa.h b/drivers/staging/rt2870/wpa.h index 0134ae6097cf..712507224146 100644 --- a/drivers/staging/rt2870/wpa.h +++ b/drivers/staging/rt2870/wpa.h @@ -1,357 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - wpa.h - - Abstract: - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Name Date Modification logs -*/ - -#ifndef __WPA_H__ -#define __WPA_H__ - -// EAPOL Key descripter frame format related length -#define LEN_KEY_DESC_NONCE 32 -#define LEN_KEY_DESC_IV 16 -#define LEN_KEY_DESC_RSC 8 -#define LEN_KEY_DESC_ID 8 -#define LEN_KEY_DESC_REPLAY 8 -#define LEN_KEY_DESC_MIC 16 - -// The length is the EAPoL-Key frame except key data field. -// Please refer to 802.11i-2004 ,Figure 43u in p.78 -#define LEN_EAPOL_KEY_MSG (sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE) - -// EAP Code Type. -#define EAP_CODE_REQUEST 1 -#define EAP_CODE_RESPONSE 2 -#define EAP_CODE_SUCCESS 3 -#define EAP_CODE_FAILURE 4 - -// EAPOL frame Protocol Version -#define EAPOL_VER 1 -#define EAPOL_VER2 2 - -// EAPOL-KEY Descriptor Type -#define WPA1_KEY_DESC 0xfe -#define WPA2_KEY_DESC 0x02 - -// Key Descriptor Version of Key Information -#define DESC_TYPE_TKIP 1 -#define DESC_TYPE_AES 2 -#define DESC_TYPE_MESH 3 - -#define LEN_MSG1_2WAY 0x7f -#define MAX_LEN_OF_EAP_HS 256 - -#define LEN_MASTER_KEY 32 - -// EAPOL EK, MK -#define LEN_EAP_EK 16 -#define LEN_EAP_MICK 16 -#define LEN_EAP_KEY ((LEN_EAP_EK)+(LEN_EAP_MICK)) -// TKIP key related -#define LEN_PMKID 16 -#define LEN_TKIP_EK 16 -#define LEN_TKIP_RXMICK 8 -#define LEN_TKIP_TXMICK 8 -#define LEN_AES_EK 16 -#define LEN_AES_KEY LEN_AES_EK -#define LEN_TKIP_KEY ((LEN_TKIP_EK)+(LEN_TKIP_RXMICK)+(LEN_TKIP_TXMICK)) -#define TKIP_AP_TXMICK_OFFSET ((LEN_EAP_KEY)+(LEN_TKIP_EK)) -#define TKIP_AP_RXMICK_OFFSET (TKIP_AP_TXMICK_OFFSET+LEN_TKIP_TXMICK) -#define TKIP_GTK_LENGTH ((LEN_TKIP_EK)+(LEN_TKIP_RXMICK)+(LEN_TKIP_TXMICK)) -#define LEN_PTK ((LEN_EAP_KEY)+(LEN_TKIP_KEY)) -#define MIN_LEN_OF_GTK 5 - -// RSN IE Length definition -#define MAX_LEN_OF_RSNIE 90 -#define MIN_LEN_OF_RSNIE 8 - -//EAP Packet Type -#define EAPPacket 0 -#define EAPOLStart 1 -#define EAPOLLogoff 2 -#define EAPOLKey 3 -#define EAPOLASFAlert 4 -#define EAPTtypeMax 5 - -#define EAPOL_MSG_INVALID 0 -#define EAPOL_PAIR_MSG_1 1 -#define EAPOL_PAIR_MSG_2 2 -#define EAPOL_PAIR_MSG_3 3 -#define EAPOL_PAIR_MSG_4 4 -#define EAPOL_GROUP_MSG_1 5 -#define EAPOL_GROUP_MSG_2 6 - -#define PAIRWISEKEY 1 -#define GROUPKEY 0 - -// Retry timer counter initial value -#define PEER_MSG1_RETRY_TIMER_CTR 0 -#define PEER_MSG3_RETRY_TIMER_CTR 10 -#define GROUP_MSG1_RETRY_TIMER_CTR 20 - - -#define EAPOL_START_DISABLE 0 -#define EAPOL_START_PSK 1 -#define EAPOL_START_1X 2 - -#define MIX_CIPHER_WPA_TKIP_ON(x) (((x) & 0x08) != 0) -#define MIX_CIPHER_WPA_AES_ON(x) (((x) & 0x04) != 0) -#define MIX_CIPHER_WPA2_TKIP_ON(x) (((x) & 0x02) != 0) -#define MIX_CIPHER_WPA2_AES_ON(x) (((x) & 0x01) != 0) - -#define ROUND_UP(__x, __y) \ - (((ULONG)((__x)+((__y)-1))) & ((ULONG)~((__y)-1))) - -#define ADD_ONE_To_64BIT_VAR(_V) \ -{ \ - UCHAR cnt = LEN_KEY_DESC_REPLAY; \ - do \ - { \ - cnt--; \ - _V[cnt]++; \ - if (cnt == 0) \ - break; \ - }while (_V[cnt] == 0); \ -} - -#define IS_WPA_CAPABILITY(a) (((a) >= Ndis802_11AuthModeWPA) && ((a) <= Ndis802_11AuthModeWPA1PSKWPA2PSK)) - -// EAPOL Key Information definition within Key descriptor format -typedef struct PACKED _KEY_INFO -{ -#ifdef RT_BIG_ENDIAN - UCHAR KeyAck:1; - UCHAR Install:1; - UCHAR KeyIndex:2; - UCHAR KeyType:1; - UCHAR KeyDescVer:3; - UCHAR Rsvd:3; - UCHAR EKD_DL:1; // EKD for AP; DL for STA - UCHAR Request:1; - UCHAR Error:1; - UCHAR Secure:1; - UCHAR KeyMic:1; -#else - UCHAR KeyMic:1; - UCHAR Secure:1; - UCHAR Error:1; - UCHAR Request:1; - UCHAR EKD_DL:1; // EKD for AP; DL for STA - UCHAR Rsvd:3; - UCHAR KeyDescVer:3; - UCHAR KeyType:1; - UCHAR KeyIndex:2; - UCHAR Install:1; - UCHAR KeyAck:1; -#endif -} KEY_INFO, *PKEY_INFO; - -// EAPOL Key descriptor format -typedef struct PACKED _KEY_DESCRIPTER -{ - UCHAR Type; - KEY_INFO KeyInfo; - UCHAR KeyLength[2]; - UCHAR ReplayCounter[LEN_KEY_DESC_REPLAY]; - UCHAR KeyNonce[LEN_KEY_DESC_NONCE]; - UCHAR KeyIv[LEN_KEY_DESC_IV]; - UCHAR KeyRsc[LEN_KEY_DESC_RSC]; - UCHAR KeyId[LEN_KEY_DESC_ID]; - UCHAR KeyMic[LEN_KEY_DESC_MIC]; - UCHAR KeyDataLen[2]; - UCHAR KeyData[MAX_LEN_OF_RSNIE]; -} KEY_DESCRIPTER, *PKEY_DESCRIPTER; - -typedef struct PACKED _EAPOL_PACKET -{ - UCHAR ProVer; - UCHAR ProType; - UCHAR Body_Len[2]; - KEY_DESCRIPTER KeyDesc; -} EAPOL_PACKET, *PEAPOL_PACKET; - -//802.11i D10 page 83 -typedef struct PACKED _GTK_ENCAP -{ -#ifndef RT_BIG_ENDIAN - UCHAR Kid:2; - UCHAR tx:1; - UCHAR rsv:5; - UCHAR rsv1; -#else - UCHAR rsv:5; - UCHAR tx:1; - UCHAR Kid:2; - UCHAR rsv1; -#endif - UCHAR GTK[TKIP_GTK_LENGTH]; -} GTK_ENCAP, *PGTK_ENCAP; - -typedef struct PACKED _KDE_ENCAP -{ - UCHAR Type; - UCHAR Len; - UCHAR OUI[3]; - UCHAR DataType; - GTK_ENCAP GTKEncap; -} KDE_ENCAP, *PKDE_ENCAP; - -// For WPA1 -typedef struct PACKED _RSNIE { - UCHAR oui[4]; - USHORT version; - UCHAR mcast[4]; - USHORT ucount; - struct PACKED { - UCHAR oui[4]; - }ucast[1]; -} RSNIE, *PRSNIE; - -// For WPA2 -typedef struct PACKED _RSNIE2 { - USHORT version; - UCHAR mcast[4]; - USHORT ucount; - struct PACKED { - UCHAR oui[4]; - }ucast[1]; -} RSNIE2, *PRSNIE2; - -// AKM Suite -typedef struct PACKED _RSNIE_AUTH { - USHORT acount; - struct PACKED { - UCHAR oui[4]; - }auth[1]; -} RSNIE_AUTH,*PRSNIE_AUTH; - -typedef union PACKED _RSN_CAPABILITIES { - struct PACKED { -#ifdef RT_BIG_ENDIAN - USHORT Rsvd:10; - USHORT GTKSA_R_Counter:2; - USHORT PTKSA_R_Counter:2; - USHORT No_Pairwise:1; - USHORT PreAuth:1; -#else - USHORT PreAuth:1; - USHORT No_Pairwise:1; - USHORT PTKSA_R_Counter:2; - USHORT GTKSA_R_Counter:2; - USHORT Rsvd:10; -#endif - } field; - USHORT word; -} RSN_CAPABILITIES, *PRSN_CAPABILITIES; - -typedef struct PACKED _EAP_HDR { - UCHAR ProVer; - UCHAR ProType; - UCHAR Body_Len[2]; - UCHAR code; - UCHAR identifier; - UCHAR length[2]; // including code and identifier, followed by length-2 octets of data -} EAP_HDR, *PEAP_HDR; - -// For supplicant state machine states. 802.11i Draft 4.1, p. 97 -// We simplified it -typedef enum _WpaState -{ - SS_NOTUSE, // 0 - SS_START, // 1 - SS_WAIT_MSG_3, // 2 - SS_WAIT_GROUP, // 3 - SS_FINISH, // 4 - SS_KEYUPDATE, // 5 -} WPA_STATE; - -// -// The definition of the cipher combination -// -// bit3 bit2 bit1 bit0 -// +------------+------------+ -// | WPA | WPA2 | -// +------+-----+------+-----+ -// | TKIP | AES | TKIP | AES | -// | 0 | 1 | 1 | 0 | -> 0x06 -// | 0 | 1 | 1 | 1 | -> 0x07 -// | 1 | 0 | 0 | 1 | -> 0x09 -// | 1 | 0 | 1 | 1 | -> 0x0B -// | 1 | 1 | 0 | 1 | -> 0x0D -// | 1 | 1 | 1 | 0 | -> 0x0E -// | 1 | 1 | 1 | 1 | -> 0x0F -// +------+-----+------+-----+ -// -typedef enum _WpaMixPairCipher -{ - MIX_CIPHER_NOTUSE = 0x00, - WPA_NONE_WPA2_TKIPAES = 0x03, // WPA2-TKIPAES - WPA_AES_WPA2_TKIP = 0x06, - WPA_AES_WPA2_TKIPAES = 0x07, - WPA_TKIP_WPA2_AES = 0x09, - WPA_TKIP_WPA2_TKIPAES = 0x0B, - WPA_TKIPAES_WPA2_NONE = 0x0C, // WPA-TKIPAES - WPA_TKIPAES_WPA2_AES = 0x0D, - WPA_TKIPAES_WPA2_TKIP = 0x0E, - WPA_TKIPAES_WPA2_TKIPAES = 0x0F, -} WPA_MIX_PAIR_CIPHER; - -typedef struct PACKED _RSN_IE_HEADER_STRUCT { - UCHAR Eid; - UCHAR Length; - USHORT Version; // Little endian format -} RSN_IE_HEADER_STRUCT, *PRSN_IE_HEADER_STRUCT; - -// Cipher suite selector types -typedef struct PACKED _CIPHER_SUITE_STRUCT { - UCHAR Oui[3]; - UCHAR Type; -} CIPHER_SUITE_STRUCT, *PCIPHER_SUITE_STRUCT; - -// Authentication and Key Management suite selector -typedef struct PACKED _AKM_SUITE_STRUCT { - UCHAR Oui[3]; - UCHAR Type; -} AKM_SUITE_STRUCT, *PAKM_SUITE_STRUCT; - -// RSN capability -typedef struct PACKED _RSN_CAPABILITY { - USHORT Rsv:10; - USHORT GTKSAReplayCnt:2; - USHORT PTKSAReplayCnt:2; - USHORT NoPairwise:1; - USHORT PreAuth:1; -} RSN_CAPABILITY, *PRSN_CAPABILITY; - -#endif +#include "../rt2860/wpa.h" diff --git a/drivers/staging/rt3070/2870_main_dev.c b/drivers/staging/rt3070/2870_main_dev.c index 401ddb012131..32427c0bb3b9 100644 --- a/drivers/staging/rt3070/2870_main_dev.c +++ b/drivers/staging/rt3070/2870_main_dev.c @@ -1,1627 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - rtmp_main.c - - Abstract: - main initialization routines - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Name Date Modification logs - Jan Lee 01-10-2005 modified - Sample Jun/01/07 Merge RT2870 and RT2860 drivers. -*/ - -#include "rt_config.h" - - -// Following information will be show when you run 'modinfo' -// *** If you have a solution for the bug in current version of driver, please mail to me. -// Otherwise post to forum in ralinktech's web site(www.ralinktech.com) and let all users help you. *** -MODULE_AUTHOR("Paul Lin "); -MODULE_DESCRIPTION("RT2870 Wireless Lan Linux Driver"); -#ifdef CONFIG_STA_SUPPORT -MODULE_LICENSE("GPL"); -#ifdef MODULE_VERSION -MODULE_VERSION(STA_DRIVER_VERSION); -#endif -#endif // CONFIG_STA_SUPPORT // - -#ifdef MULTIPLE_CARD_SUPPORT -// record whether the card in the card list is used in the card file -extern UINT8 MC_CardUsed[]; -#endif // MULTIPLE_CARD_SUPPORT // - -/* Kernel thread and vars, which handles packets that are completed. Only - * packets that have a "complete" function are sent here. This way, the - * completion is run out of kernel context, and doesn't block the rest of - * the stack. */ -//static int mlme_kill = 0; // Mlme kernel thread -//static int RTUSBCmd_kill = 0; // Command kernel thread -//static int TimerFunc_kill = 0; // TimerQ kernel thread - -//static wait_queue_head_t timerWaitQ; -//static wait_queue_t waitQ; - -extern INT __devinit rt28xx_probe(IN void *_dev_p, IN void *_dev_id_p, - IN UINT argc, OUT PRTMP_ADAPTER *ppAd); - - -/* module table */ -struct usb_device_id rtusb_usb_id[] = RT2870_USB_DEVICES; -INT const rtusb_usb_id_len = sizeof(rtusb_usb_id) / sizeof(struct usb_device_id); -MODULE_DEVICE_TABLE(usb, rtusb_usb_id); - -#ifndef PF_NOFREEZE -#define PF_NOFREEZE 0 -#endif - - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - -/**************************************************************************/ -/**************************************************************************/ -//tested for kernel 2.4 series -/**************************************************************************/ -/**************************************************************************/ -static void *rtusb_probe(struct usb_device *dev, UINT interface, - const struct usb_device_id *id_table); -static void rtusb_disconnect(struct usb_device *dev, void *ptr); - -struct usb_driver rtusb_driver = { - name:"rt2870", - probe:rtusb_probe, - disconnect:rtusb_disconnect, - id_table:rtusb_usb_id, - }; - -#else - -#ifdef CONFIG_PM -static int rt2870_suspend(struct usb_interface *intf, pm_message_t state); -static int rt2870_resume(struct usb_interface *intf); -#endif // CONFIG_PM // - -/**************************************************************************/ -/**************************************************************************/ -//tested for kernel 2.6series -/**************************************************************************/ -/**************************************************************************/ -static int rtusb_probe (struct usb_interface *intf, - const struct usb_device_id *id); -static void rtusb_disconnect(struct usb_interface *intf); - -struct usb_driver rtusb_driver = { -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) - .owner = THIS_MODULE, -#endif - .name="rt2870", - .probe=rtusb_probe, - .disconnect=rtusb_disconnect, - .id_table=rtusb_usb_id, - -#ifdef CONFIG_PM - suspend: rt2870_suspend, - resume: rt2870_resume, -#endif - }; - -#ifdef CONFIG_PM - -VOID RT2860RejectPendingPackets( - IN PRTMP_ADAPTER pAd) -{ - // clear PS packets - // clear TxSw packets -} - -static int rt2870_suspend( - struct usb_interface *intf, - pm_message_t state) -{ - struct net_device *net_dev; - PRTMP_ADAPTER pAd = usb_get_intfdata(intf); - - - DBGPRINT(RT_DEBUG_TRACE, ("===> rt2870_suspend()\n")); - net_dev = pAd->net_dev; - netif_device_detach(net_dev); - - pAd->PM_FlgSuspend = 1; - if (netif_running(net_dev)) { - RTUSBCancelPendingBulkInIRP(pAd); - RTUSBCancelPendingBulkOutIRP(pAd); - } - DBGPRINT(RT_DEBUG_TRACE, ("<=== rt2870_suspend()\n")); - return 0; -} - -static int rt2870_resume( - struct usb_interface *intf) -{ - struct net_device *net_dev; - PRTMP_ADAPTER pAd = usb_get_intfdata(intf); - - - DBGPRINT(RT_DEBUG_TRACE, ("===> rt2870_resume()\n")); - - pAd->PM_FlgSuspend = 0; - net_dev = pAd->net_dev; - netif_device_attach(net_dev); - netif_start_queue(net_dev); - netif_carrier_on(net_dev); - netif_wake_queue(net_dev); - - DBGPRINT(RT_DEBUG_TRACE, ("<=== rt2870_resume()\n")); - return 0; -} -#endif // CONFIG_PM // -#endif // LINUX_VERSION_CODE // - - -// Init driver module -INT __init rtusb_init(void) -{ - printk("rtusb init --->\n"); - return usb_register(&rtusb_driver); -} - -// Deinit driver module -VOID __exit rtusb_exit(void) -{ - usb_deregister(&rtusb_driver); - printk("<--- rtusb exit\n"); -} - -module_init(rtusb_init); -module_exit(rtusb_exit); - - - - -/*--------------------------------------------------------------------- */ -/* function declarations */ -/*--------------------------------------------------------------------- */ - -/* -======================================================================== -Routine Description: - MLME kernel thread. - -Arguments: - *Context the pAd, driver control block pointer - -Return Value: - 0 close the thread - -Note: -======================================================================== -*/ -INT MlmeThread( - IN void *Context) -{ - PRTMP_ADAPTER pAd = (PRTMP_ADAPTER)Context; - POS_COOKIE pObj; - int status; - - pObj = (POS_COOKIE)pAd->OS_Cookie; - - rtmp_os_thread_init("rt2870MlmeThread", (PVOID)&(pAd->mlmeComplete)); - - while (pAd->mlme_kill == 0) - { - /* lock the device pointers */ - //down(&(pAd->mlme_semaphore)); - status = down_interruptible(&(pAd->mlme_semaphore)); - - /* lock the device pointers , need to check if required*/ - //down(&(pAd->usbdev_semaphore)); - - if (!pAd->PM_FlgSuspend) - MlmeHandler(pAd); - - /* unlock the device pointers */ - //up(&(pAd->usbdev_semaphore)); - if (status != 0) - { - RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS); - break; - } - } - - /* notify the exit routine that we're actually exiting now - * - * complete()/wait_for_completion() is similar to up()/down(), - * except that complete() is safe in the case where the structure - * is getting deleted in a parallel mode of execution (i.e. just - * after the down() -- that's necessary for the thread-shutdown - * case. - * - * complete_and_exit() goes even further than this -- it is safe in - * the case that the thread of the caller is going away (not just - * the structure) -- this is necessary for the module-remove case. - * This is important in preemption kernels, which transfer the flow - * of execution immediately upon a complete(). - */ - DBGPRINT(RT_DEBUG_TRACE,( "<---%s\n",__FUNCTION__)); - - pObj->MLMEThr_pid = NULL; - - complete_and_exit (&pAd->mlmeComplete, 0); - return 0; - -} - - -/* -======================================================================== -Routine Description: - USB command kernel thread. - -Arguments: - *Context the pAd, driver control block pointer - -Return Value: - 0 close the thread - -Note: -======================================================================== -*/ -INT RTUSBCmdThread( - IN void * Context) -{ - PRTMP_ADAPTER pAd = (PRTMP_ADAPTER)Context; - POS_COOKIE pObj; - int status; - - pObj = (POS_COOKIE)pAd->OS_Cookie; - - rtmp_os_thread_init("rt2870CmdThread", (PVOID)&(pAd->CmdQComplete)); - - NdisAcquireSpinLock(&pAd->CmdQLock); - pAd->CmdQ.CmdQState = RT2870_THREAD_RUNNING; - NdisReleaseSpinLock(&pAd->CmdQLock); - - while (pAd->CmdQ.CmdQState == RT2870_THREAD_RUNNING) - { - /* lock the device pointers */ - //down(&(pAd->RTUSBCmd_semaphore)); - status = down_interruptible(&(pAd->RTUSBCmd_semaphore)); - - if (pAd->CmdQ.CmdQState == RT2870_THREAD_STOPED) - break; - - if (status != 0) - { - RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS); - break; - } - /* lock the device pointers , need to check if required*/ - //down(&(pAd->usbdev_semaphore)); - - if (!pAd->PM_FlgSuspend) - CMDHandler(pAd); - - /* unlock the device pointers */ - //up(&(pAd->usbdev_semaphore)); - } - - if (!pAd->PM_FlgSuspend) - { // Clear the CmdQElements. - CmdQElmt *pCmdQElmt = NULL; - - NdisAcquireSpinLock(&pAd->CmdQLock); - pAd->CmdQ.CmdQState = RT2870_THREAD_STOPED; - while(pAd->CmdQ.size) - { - RTUSBDequeueCmd(&pAd->CmdQ, &pCmdQElmt); - if (pCmdQElmt) - { - if (pCmdQElmt->CmdFromNdis == TRUE) - { - if (pCmdQElmt->buffer != NULL) - NdisFreeMemory(pCmdQElmt->buffer, pCmdQElmt->bufferlength, 0); - - NdisFreeMemory(pCmdQElmt, sizeof(CmdQElmt), 0); - } - else - { - if ((pCmdQElmt->buffer != NULL) && (pCmdQElmt->bufferlength != 0)) - NdisFreeMemory(pCmdQElmt->buffer, pCmdQElmt->bufferlength, 0); - { - NdisFreeMemory(pCmdQElmt, sizeof(CmdQElmt), 0); - } - } - } - } - - NdisReleaseSpinLock(&pAd->CmdQLock); - } - /* notify the exit routine that we're actually exiting now - * - * complete()/wait_for_completion() is similar to up()/down(), - * except that complete() is safe in the case where the structure - * is getting deleted in a parallel mode of execution (i.e. just - * after the down() -- that's necessary for the thread-shutdown - * case. - * - * complete_and_exit() goes even further than this -- it is safe in - * the case that the thread of the caller is going away (not just - * the structure) -- this is necessary for the module-remove case. - * This is important in preemption kernels, which transfer the flow - * of execution immediately upon a complete(). - */ - DBGPRINT(RT_DEBUG_TRACE,( "<---RTUSBCmdThread\n")); - - pObj->RTUSBCmdThr_pid = NULL; - - complete_and_exit (&pAd->CmdQComplete, 0); - return 0; - -} - - -static void RT2870_TimerQ_Handle(RTMP_ADAPTER *pAd) -{ - int status; - RALINK_TIMER_STRUCT *pTimer; - RT2870_TIMER_ENTRY *pEntry; - unsigned long irqFlag; - - while(!pAd->TimerFunc_kill) - { -// printk("waiting for event!\n"); - pTimer = NULL; - - status = down_interruptible(&(pAd->RTUSBTimer_semaphore)); - - if (pAd->TimerQ.status == RT2870_THREAD_STOPED) - break; - - // event happened. - while(pAd->TimerQ.pQHead) - { - RTMP_IRQ_LOCK(&pAd->TimerQLock, irqFlag); - pEntry = pAd->TimerQ.pQHead; - if (pEntry) - { - pTimer = pEntry->pRaTimer; - - // update pQHead - pAd->TimerQ.pQHead = pEntry->pNext; - if (pEntry == pAd->TimerQ.pQTail) - pAd->TimerQ.pQTail = NULL; - - // return this queue entry to timerQFreeList. - pEntry->pNext = pAd->TimerQ.pQPollFreeList; - pAd->TimerQ.pQPollFreeList = pEntry; - } - RTMP_IRQ_UNLOCK(&pAd->TimerQLock, irqFlag); - - if (pTimer) - { - if (pTimer->handle != NULL) - if (!pAd->PM_FlgSuspend) - pTimer->handle(NULL, (PVOID) pTimer->cookie, NULL, pTimer); - if ((pTimer->Repeat) && (pTimer->State == FALSE)) - RTMP_OS_Add_Timer(&pTimer->TimerObj, pTimer->TimerValue); - } - } - - if (status != 0) - { - pAd->TimerQ.status = RT2870_THREAD_STOPED; - RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS); - break; - } - } -} - - -INT TimerQThread( - IN OUT PVOID Context) -{ - PRTMP_ADAPTER pAd; - POS_COOKIE pObj; - - pAd = (PRTMP_ADAPTER)Context; - pObj = (POS_COOKIE) pAd->OS_Cookie; - - rtmp_os_thread_init("rt2870TimerQHandle", (PVOID)&(pAd->TimerQComplete)); - - RT2870_TimerQ_Handle(pAd); - - /* notify the exit routine that we're actually exiting now - * - * complete()/wait_for_completion() is similar to up()/down(), - * except that complete() is safe in the case where the structure - * is getting deleted in a parallel mode of execution (i.e. just - * after the down() -- that's necessary for the thread-shutdown - * case. - * - * complete_and_exit() goes even further than this -- it is safe in - * the case that the thread of the caller is going away (not just - * the structure) -- this is necessary for the module-remove case. - * This is important in preemption kernels, which transfer the flow - * of execution immediately upon a complete(). - */ - DBGPRINT(RT_DEBUG_TRACE,( "<---%s\n",__FUNCTION__)); - - pObj->TimerQThr_pid = NULL; - - complete_and_exit(&pAd->TimerQComplete, 0); - return 0; - -} - - -RT2870_TIMER_ENTRY *RT2870_TimerQ_Insert( - IN RTMP_ADAPTER *pAd, - IN RALINK_TIMER_STRUCT *pTimer) -{ - RT2870_TIMER_ENTRY *pQNode = NULL, *pQTail; - unsigned long irqFlags; - - - RTMP_IRQ_LOCK(&pAd->TimerQLock, irqFlags); - if (pAd->TimerQ.status & RT2870_THREAD_CAN_DO_INSERT) - { - if(pAd->TimerQ.pQPollFreeList) - { - pQNode = pAd->TimerQ.pQPollFreeList; - pAd->TimerQ.pQPollFreeList = pQNode->pNext; - - pQNode->pRaTimer = pTimer; - pQNode->pNext = NULL; - - pQTail = pAd->TimerQ.pQTail; - if (pAd->TimerQ.pQTail != NULL) - pQTail->pNext = pQNode; - pAd->TimerQ.pQTail = pQNode; - if (pAd->TimerQ.pQHead == NULL) - pAd->TimerQ.pQHead = pQNode; - } - RTMP_IRQ_UNLOCK(&pAd->TimerQLock, irqFlags); - - if (pQNode) - up(&pAd->RTUSBTimer_semaphore); - //wake_up(&timerWaitQ); - } - else - { - RTMP_IRQ_UNLOCK(&pAd->TimerQLock, irqFlags); - } - return pQNode; -} - - -BOOLEAN RT2870_TimerQ_Remove( - IN RTMP_ADAPTER *pAd, - IN RALINK_TIMER_STRUCT *pTimer) -{ - RT2870_TIMER_ENTRY *pNode, *pPrev = NULL; - unsigned long irqFlags; - - RTMP_IRQ_LOCK(&pAd->TimerQLock, irqFlags); - if (pAd->TimerQ.status >= RT2870_THREAD_INITED) - { - pNode = pAd->TimerQ.pQHead; - while (pNode) - { - if (pNode->pRaTimer == pTimer) - break; - pPrev = pNode; - pNode = pNode->pNext; - } - - // Now move it to freeList queue. - if (pNode) - { - if (pNode == pAd->TimerQ.pQHead) - pAd->TimerQ.pQHead = pNode->pNext; - if (pNode == pAd->TimerQ.pQTail) - pAd->TimerQ.pQTail = pPrev; - if (pPrev != NULL) - pPrev->pNext = pNode->pNext; - - // return this queue entry to timerQFreeList. - pNode->pNext = pAd->TimerQ.pQPollFreeList; - pAd->TimerQ.pQPollFreeList = pNode; - } - } - RTMP_IRQ_UNLOCK(&pAd->TimerQLock, irqFlags); - - return TRUE; -} - - -void RT2870_TimerQ_Exit(RTMP_ADAPTER *pAd) -{ - RT2870_TIMER_ENTRY *pTimerQ; - unsigned long irqFlags; - - RTMP_IRQ_LOCK(&pAd->TimerQLock, irqFlags); - while (pAd->TimerQ.pQHead) - { - pTimerQ = pAd->TimerQ.pQHead; - pAd->TimerQ.pQHead = pTimerQ->pNext; - // remove the timeQ - } - pAd->TimerQ.pQPollFreeList = NULL; - os_free_mem(pAd, pAd->TimerQ.pTimerQPoll); - pAd->TimerQ.pQTail = NULL; - pAd->TimerQ.pQHead = NULL; - pAd->TimerQ.status = RT2870_THREAD_STOPED; - RTMP_IRQ_UNLOCK(&pAd->TimerQLock, irqFlags); - -} - - -void RT2870_TimerQ_Init(RTMP_ADAPTER *pAd) -{ - int i; - RT2870_TIMER_ENTRY *pQNode, *pEntry; - unsigned long irqFlags; - - NdisAllocateSpinLock(&pAd->TimerQLock); - - RTMP_IRQ_LOCK(&pAd->TimerQLock, irqFlags); - NdisZeroMemory(&pAd->TimerQ, sizeof(pAd->TimerQ)); - //InterlockedExchange(&pAd->TimerQ.count, 0); - - /* Initialise the wait q head */ - //init_waitqueue_head(&timerWaitQ); - - os_alloc_mem(pAd, &pAd->TimerQ.pTimerQPoll, sizeof(RT2870_TIMER_ENTRY) * TIMER_QUEUE_SIZE_MAX); - if (pAd->TimerQ.pTimerQPoll) - { - pEntry = NULL; - pQNode = (RT2870_TIMER_ENTRY *)pAd->TimerQ.pTimerQPoll; - for (i = 0 ;i pNext = pEntry; - pEntry = pQNode; - pQNode++; - } - pAd->TimerQ.pQPollFreeList = pEntry; - pAd->TimerQ.pQHead = NULL; - pAd->TimerQ.pQTail = NULL; - pAd->TimerQ.status = RT2870_THREAD_INITED; - } - RTMP_IRQ_UNLOCK(&pAd->TimerQLock, irqFlags); -} - - -VOID RT2870_WatchDog(IN RTMP_ADAPTER *pAd) -{ - PHT_TX_CONTEXT pHTTXContext; - int idx; - ULONG irqFlags; - PURB pUrb; - BOOLEAN needDumpSeq = FALSE; - UINT32 MACValue; - - - idx = 0; - RTMP_IO_READ32(pAd, TXRXQ_PCNT, &MACValue); - if ((MACValue & 0xff) !=0 ) - { - DBGPRINT(RT_DEBUG_TRACE, ("TX QUEUE 0 Not EMPTY(Value=0x%0x). !!!!!!!!!!!!!!!\n", MACValue)); - RTMP_IO_WRITE32(pAd, PBF_CFG, 0xf40012); - while((MACValue &0xff) != 0 && (idx++ < 10)) - { - RTMP_IO_READ32(pAd, TXRXQ_PCNT, &MACValue); - NdisMSleep(1); - } - RTMP_IO_WRITE32(pAd, PBF_CFG, 0xf40006); - } - -//PS packets use HCCA queue when dequeue from PS unicast queue (WiFi WPA2 MA9_DT1 for Marvell B STA) -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - idx = 0; - if ((MACValue & 0xff00) !=0 ) - { - DBGPRINT(RT_DEBUG_TRACE, ("TX QUEUE 1 Not EMPTY(Value=0x%0x). !!!!!!!!!!!!!!!\n", MACValue)); - RTMP_IO_WRITE32(pAd, PBF_CFG, 0xf4000a); - while((MACValue &0xff00) != 0 && (idx++ < 10)) - { - RTMP_IO_READ32(pAd, TXRXQ_PCNT, &MACValue); - NdisMSleep(1); - } - RTMP_IO_WRITE32(pAd, PBF_CFG, 0xf40006); - } - } -#endif // CONFIG_STA_SUPPORT // - - if (pAd->watchDogRxOverFlowCnt >= 2) - { - DBGPRINT(RT_DEBUG_TRACE, ("Maybe the Rx Bulk-In hanged! Cancel the pending Rx bulks request!\n")); - if ((!RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_RESET_IN_PROGRESS | - fRTMP_ADAPTER_BULKIN_RESET | - fRTMP_ADAPTER_HALT_IN_PROGRESS | - fRTMP_ADAPTER_NIC_NOT_EXIST)))) - { - DBGPRINT(RT_DEBUG_TRACE, ("Call CMDTHREAD_RESET_BULK_IN to cancel the pending Rx Bulk!\n")); - RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BULKIN_RESET); - RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_IN, NULL, 0); - needDumpSeq = TRUE; - } - pAd->watchDogRxOverFlowCnt = 0; - } - - - for (idx = 0; idx < NUM_OF_TX_RING; idx++) - { - pUrb = NULL; - - RTMP_IRQ_LOCK(&pAd->BulkOutLock[idx], irqFlags); - if ((pAd->BulkOutPending[idx] == TRUE) && pAd->watchDogTxPendingCnt) - { - pAd->watchDogTxPendingCnt[idx]++; - - if ((pAd->watchDogTxPendingCnt[idx] > 2) && - (!RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_RESET_IN_PROGRESS | fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST | fRTMP_ADAPTER_BULKOUT_RESET))) - ) - { - // FIXME: Following code just support single bulk out. If you wanna support multiple bulk out. Modify it! - pHTTXContext = (PHT_TX_CONTEXT)(&pAd->TxContext[idx]); - if (pHTTXContext->IRPPending) - { // Check TxContext. - pUrb = pHTTXContext->pUrb; - } - else if (idx == MGMTPIPEIDX) - { - PTX_CONTEXT pMLMEContext, pNULLContext, pPsPollContext; - - //Check MgmtContext. - pMLMEContext = (PTX_CONTEXT)(pAd->MgmtRing.Cell[pAd->MgmtRing.TxDmaIdx].AllocVa); - pPsPollContext = (PTX_CONTEXT)(&pAd->PsPollContext); - pNULLContext = (PTX_CONTEXT)(&pAd->NullContext); - - if (pMLMEContext->IRPPending) - { - ASSERT(pMLMEContext->IRPPending); - pUrb = pMLMEContext->pUrb; - } - else if (pNULLContext->IRPPending) - { - ASSERT(pNULLContext->IRPPending); - pUrb = pNULLContext->pUrb; - } - else if (pPsPollContext->IRPPending) - { - ASSERT(pPsPollContext->IRPPending); - pUrb = pPsPollContext->pUrb; - } - } - - RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[idx], irqFlags); - - DBGPRINT(RT_DEBUG_TRACE, ("Maybe the Tx Bulk-Out hanged! Cancel the pending Tx bulks request of idx(%d)!\n", idx)); - if (pUrb) - { - DBGPRINT(RT_DEBUG_TRACE, ("Unlink the pending URB!\n")); - // unlink it now - RTUSB_UNLINK_URB(pUrb); - // Sleep 200 microseconds to give cancellation time to work - RTMPusecDelay(200); - needDumpSeq = TRUE; - } - else - { - DBGPRINT(RT_DEBUG_ERROR, ("Unkonw bulkOut URB maybe hanged!!!!!!!!!!!!\n")); - } - } - else - { - RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[idx], irqFlags); - } - } - else - { - RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[idx], irqFlags); - } - } - -#ifdef DOT11_N_SUPPORT - // For Sigma debug, dump the ba_reordering sequence. - if((needDumpSeq == TRUE) && (pAd->CommonCfg.bDisableReordering == 0)) - { - USHORT Idx; - PBA_REC_ENTRY pBAEntry = NULL; - UCHAR count = 0; - struct reordering_mpdu *mpdu_blk; - - Idx = pAd->MacTab.Content[BSSID_WCID].BARecWcidArray[0]; - - pBAEntry = &pAd->BATable.BARecEntry[Idx]; - if((pBAEntry->list.qlen > 0) && (pBAEntry->list.next != NULL)) - { - DBGPRINT(RT_DEBUG_TRACE, ("NICUpdateRawCounters():The Queueing pkt in reordering buffer:\n")); - NdisAcquireSpinLock(&pBAEntry->RxReRingLock); - mpdu_blk = pBAEntry->list.next; - while (mpdu_blk) - { - DBGPRINT(RT_DEBUG_TRACE, ("\t%d:Seq-%d, bAMSDU-%d!\n", count, mpdu_blk->Sequence, mpdu_blk->bAMSDU)); - mpdu_blk = mpdu_blk->next; - count++; - } - - DBGPRINT(RT_DEBUG_TRACE, ("\npBAEntry->LastIndSeq=%d!\n", pBAEntry->LastIndSeq)); - NdisReleaseSpinLock(&pBAEntry->RxReRingLock); - } - } -#endif // DOT11_N_SUPPORT // -} - -/* -======================================================================== -Routine Description: - Release allocated resources. - -Arguments: - *dev Point to the PCI or USB device - pAd driver control block pointer - -Return Value: - None - -Note: -======================================================================== -*/ -static void _rtusb_disconnect(struct usb_device *dev, PRTMP_ADAPTER pAd) -{ - struct net_device *net_dev = NULL; - - - DBGPRINT(RT_DEBUG_ERROR, ("rtusb_disconnect: unregister usbnet usb-%s-%s\n", - dev->bus->bus_name, dev->devpath)); - if (!pAd) - { -#ifdef MULTIPLE_CARD_SUPPORT - if ((pAd->MC_RowID >= 0) && (pAd->MC_RowID <= MAX_NUM_OF_MULTIPLE_CARD)) - MC_CardUsed[pAd->MC_RowID] = 0; // not clear MAC address -#endif // MULTIPLE_CARD_SUPPORT // - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* kernel 2.4 series */ - while(MOD_IN_USE > 0) - { - MOD_DEC_USE_COUNT; - } -#else - usb_put_dev(dev); -#endif // LINUX_VERSION_CODE // - - printk("rtusb_disconnect: pAd == NULL!\n"); - return; - } - RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST); - - - - // for debug, wait to show some messages to /proc system - udelay(1); - - - - - net_dev = pAd->net_dev; - if (pAd->net_dev != NULL) - { - printk("rtusb_disconnect: unregister_netdev(), dev->name=%s!\n", net_dev->name); - unregister_netdev (pAd->net_dev); - } - udelay(1); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* kernel 2.4 series */ -#else - flush_scheduled_work(); -#endif // LINUX_VERSION_CODE // - udelay(1); - - // free net_device memory -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* kernel 2.4 series */ - kfree(net_dev); -#else - free_netdev(net_dev); -#endif // LINUX_VERSION_CODE // - - // free adapter memory - RTMPFreeAdapter(pAd); - - // release a use of the usb device structure -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* kernel 2.4 series */ - while(MOD_IN_USE > 0) - { - MOD_DEC_USE_COUNT; - } -#else - usb_put_dev(dev); -#endif // LINUX_VERSION_CODE // - udelay(1); - - DBGPRINT(RT_DEBUG_ERROR, (" RTUSB disconnect successfully\n")); -} - - -/* -======================================================================== -Routine Description: - Probe RT28XX chipset. - -Arguments: - *dev Point to the PCI or USB device - interface - *id_table Point to the PCI or USB device ID - -Return Value: - None - -Note: -======================================================================== -*/ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* kernel 2.4 series */ -static void *rtusb_probe(struct usb_device *dev, UINT interface, - const struct usb_device_id *id) -{ - PRTMP_ADAPTER pAd; - rt28xx_probe((void *)dev, (void *)id, interface, &pAd); - return (void *)pAd; -} - -//Disconnect function is called within exit routine -static void rtusb_disconnect(struct usb_device *dev, void *ptr) -{ - _rtusb_disconnect(dev, ((PRTMP_ADAPTER)ptr)); -} - -#else /* kernel 2.6 series */ -static int rtusb_probe (struct usb_interface *intf, - const struct usb_device_id *id) -{ - PRTMP_ADAPTER pAd; - return (int)rt28xx_probe((void *)intf, (void *)id, 0, &pAd); -} - - -static void rtusb_disconnect(struct usb_interface *intf) -{ - struct usb_device *dev = interface_to_usbdev(intf); - PRTMP_ADAPTER pAd; - - - pAd = usb_get_intfdata(intf); - usb_set_intfdata(intf, NULL); - - _rtusb_disconnect(dev, pAd); -} -#endif // LINUX_VERSION_CODE // - - -/* -======================================================================== -Routine Description: - Close kernel threads. - -Arguments: - *pAd the raxx interface data pointer - -Return Value: - NONE - -Note: -======================================================================== -*/ -VOID RT28xxThreadTerminate( - IN RTMP_ADAPTER *pAd) -{ - POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie; - INT ret; - - - // Sleep 50 milliseconds so pending io might finish normally - RTMPusecDelay(50000); - - // We want to wait until all pending receives and sends to the - // device object. We cancel any - // irps. Wait until sends and receives have stopped. - RTUSBCancelPendingIRPs(pAd); - - // Terminate Threads - if (pObj->MLMEThr_pid) - { - printk("Terminate the MLMEThr_pid=%d!\n", pid_nr(pObj->MLMEThr_pid)); - mb(); - pAd->mlme_kill = 1; - //RT28XX_MLME_HANDLER(pAd); - mb(); - ret = kill_pid(pObj->MLMEThr_pid, SIGTERM, 1); - if (ret) - { - printk (KERN_WARNING "%s: unable to Mlme thread, pid=%d, ret=%d!\n", - pAd->net_dev->name, pid_nr(pObj->MLMEThr_pid), ret); - } - else - { - //wait_for_completion (&pAd->notify); - wait_for_completion (&pAd->mlmeComplete); - pObj->MLMEThr_pid = NULL; - } - } - - if (pObj->RTUSBCmdThr_pid >= 0) - { - printk("Terminate the RTUSBCmdThr_pid=%d!\n", pid_nr(pObj->RTUSBCmdThr_pid)); - mb(); - NdisAcquireSpinLock(&pAd->CmdQLock); - pAd->CmdQ.CmdQState = RT2870_THREAD_STOPED; - NdisReleaseSpinLock(&pAd->CmdQLock); - mb(); - //RTUSBCMDUp(pAd); - ret = kill_pid(pObj->RTUSBCmdThr_pid, SIGTERM, 1); - if (ret) - { - printk(KERN_WARNING "%s: unable to RTUSBCmd thread, pid=%d, ret=%d!\n", - pAd->net_dev->name, pid_nr(pObj->RTUSBCmdThr_pid), ret); - } - else - { - //wait_for_completion (&pAd->notify); - wait_for_completion (&pAd->CmdQComplete); - pObj->RTUSBCmdThr_pid = NULL; - } - } - if (pObj->TimerQThr_pid >= 0) - { - POS_COOKIE pObj = (POS_COOKIE)pAd->OS_Cookie; - - printk("Terminate the TimerQThr_pid=%d!\n", pid_nr(pObj->TimerQThr_pid)); - mb(); - pAd->TimerFunc_kill = 1; - mb(); - ret = kill_pid(pObj->TimerQThr_pid, SIGTERM, 1); - if (ret) - { - printk(KERN_WARNING "%s: unable to stop TimerQThread, pid=%d, ret=%d!\n", - pAd->net_dev->name, pid_nr(pObj->TimerQThr_pid), ret); - } - else - { - printk("wait_for_completion TimerQThr\n"); - wait_for_completion(&pAd->TimerQComplete); - pObj->TimerQThr_pid = NULL; - } - } - // Kill tasklets - pAd->mlme_kill = 0; - pAd->CmdQ.CmdQState = RT2870_THREAD_UNKNOWN; - pAd->TimerFunc_kill = 0; -} - - -void kill_thread_task(IN PRTMP_ADAPTER pAd) -{ - POS_COOKIE pObj; - - pObj = (POS_COOKIE) pAd->OS_Cookie; - - tasklet_kill(&pObj->rx_done_task); - tasklet_kill(&pObj->mgmt_dma_done_task); - tasklet_kill(&pObj->ac0_dma_done_task); - tasklet_kill(&pObj->ac1_dma_done_task); - tasklet_kill(&pObj->ac2_dma_done_task); - tasklet_kill(&pObj->ac3_dma_done_task); - tasklet_kill(&pObj->hcca_dma_done_task); - tasklet_kill(&pObj->tbtt_task); - -} - - -/* -======================================================================== -Routine Description: - Check the chipset vendor/product ID. - -Arguments: - _dev_p Point to the PCI or USB device - -Return Value: - TRUE Check ok - FALSE Check fail - -Note: -======================================================================== -*/ -BOOLEAN RT28XXChipsetCheck( - IN void *_dev_p) -{ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* kernel 2.4 series */ - struct usb_device *dev_p = (struct usb_device *)_dev_p; -#else - struct usb_interface *intf = (struct usb_interface *)_dev_p; - struct usb_device *dev_p = interface_to_usbdev(intf); -#endif // LINUX_VERSION_CODE // - UINT32 i; - - - for(i=0; idescriptor.idVendor == rtusb_usb_id[i].idVendor && - dev_p->descriptor.idProduct == rtusb_usb_id[i].idProduct) - { - printk("rt2870: idVendor = 0x%x, idProduct = 0x%x\n", - dev_p->descriptor.idVendor, dev_p->descriptor.idProduct); - break; - } - } - - if (i == rtusb_usb_id_len) - { - printk("rt2870: Error! Device Descriptor not matching!\n"); - return FALSE; - } - - return TRUE; -} - - -/* -======================================================================== -Routine Description: - Init net device structure. - -Arguments: - _dev_p Point to the PCI or USB device - *net_dev Point to the net device - *pAd the raxx interface data pointer - -Return Value: - TRUE Init ok - FALSE Init fail - -Note: -======================================================================== -*/ -BOOLEAN RT28XXNetDevInit( - IN void *_dev_p, - IN struct net_device *net_dev, - IN RTMP_ADAPTER *pAd) -{ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* kernel 2.4 series */ - struct usb_device *dev_p = (struct usb_device *)_dev_p; -#else - struct usb_interface *intf = (struct usb_interface *)_dev_p; - struct usb_device *dev_p = interface_to_usbdev(intf); -#endif // LINUX_VERSION_CODE // - - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* kernel 2.4 series */ - pAd->config = dev_p->config; -#else - pAd->config = &dev_p->config->desc; -#endif // LINUX_VERSION_CODE // - return TRUE; -} - - -/* -======================================================================== -Routine Description: - Init net device structure. - -Arguments: - _dev_p Point to the PCI or USB device - *pAd the raxx interface data pointer - -Return Value: - TRUE Config ok - FALSE Config fail - -Note: -======================================================================== -*/ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) -BOOLEAN RT28XXProbePostConfig( - IN void *_dev_p, - IN RTMP_ADAPTER *pAd, - IN INT32 interface) -{ - struct usb_device *dev_p = (struct usb_device *)_dev_p; - struct usb_interface *intf; - struct usb_interface_descriptor *iface_desc; - struct usb_endpoint_descriptor *endpoint; - ULONG BulkOutIdx; - UINT32 i; - - - /* get the active interface descriptor */ - intf = &dev_p->actconfig->interface[interface]; - iface_desc = &intf->altsetting[0]; - - /* get # of enpoints */ - pAd->NumberOfPipes = iface_desc->bNumEndpoints; - DBGPRINT(RT_DEBUG_TRACE, ("NumEndpoints=%d\n", iface_desc->bNumEndpoints)); - - /* Configure Pipes */ - endpoint = &iface_desc->endpoint[0]; - BulkOutIdx = 0; - - for(i=0; iNumberOfPipes; i++) - { - if ((endpoint[i].bmAttributes == USB_ENDPOINT_XFER_BULK) && - ((endpoint[i].bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)) - { - pAd->BulkInEpAddr = endpoint[i].bEndpointAddress; - pAd->BulkInMaxPacketSize = endpoint[i].wMaxPacketSize; - - DBGPRINT_RAW(RT_DEBUG_TRACE, - ("BULK IN MaximumPacketSize = %d\n", pAd->BulkInMaxPacketSize)); - DBGPRINT_RAW(RT_DEBUG_TRACE, - ("EP address = 0x%2x \n", endpoint[i].bEndpointAddress)); - } - else if ((endpoint[i].bmAttributes == USB_ENDPOINT_XFER_BULK) && - ((endpoint[i].bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT)) - { - // There are 6 bulk out EP. EP6 highest priority. - // EP1-4 is EDCA. EP5 is HCCA. - pAd->BulkOutEpAddr[BulkOutIdx++] = endpoint[i].bEndpointAddress; - pAd->BulkOutMaxPacketSize = endpoint[i].wMaxPacketSize; - - DBGPRINT_RAW(RT_DEBUG_TRACE, - ("BULK OUT MaximumPacketSize = %d\n", pAd->BulkOutMaxPacketSize)); - DBGPRINT_RAW(RT_DEBUG_TRACE, - ("EP address = 0x%2x \n", endpoint[i].bEndpointAddress)); - } - } - - if (!(pAd->BulkInEpAddr && pAd->BulkOutEpAddr[0])) - { - printk("Could not find both bulk-in and bulk-out endpoints\n"); - return FALSE; - } - - return TRUE; -} - -#else -BOOLEAN RT28XXProbePostConfig( - IN void *_dev_p, - IN RTMP_ADAPTER *pAd, - IN INT32 interface) -{ - struct usb_interface *intf = (struct usb_interface *)_dev_p; - struct usb_host_interface *iface_desc; - ULONG BulkOutIdx; - UINT32 i; - - - /* get the active interface descriptor */ - iface_desc = intf->cur_altsetting; - - /* get # of enpoints */ - pAd->NumberOfPipes = iface_desc->desc.bNumEndpoints; - DBGPRINT(RT_DEBUG_TRACE, - ("NumEndpoints=%d\n", iface_desc->desc.bNumEndpoints)); - - /* Configure Pipes */ - BulkOutIdx = 0; - - for(i=0; iNumberOfPipes; i++) - { - if ((iface_desc->endpoint[i].desc.bmAttributes == - USB_ENDPOINT_XFER_BULK) && - ((iface_desc->endpoint[i].desc.bEndpointAddress & - USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)) - { - pAd->BulkInEpAddr = iface_desc->endpoint[i].desc.bEndpointAddress; - pAd->BulkInMaxPacketSize = iface_desc->endpoint[i].desc.wMaxPacketSize; - - DBGPRINT_RAW(RT_DEBUG_TRACE, - ("BULK IN MaximumPacketSize = %d\n", pAd->BulkInMaxPacketSize)); - DBGPRINT_RAW(RT_DEBUG_TRACE, - ("EP address = 0x%2x\n", iface_desc->endpoint[i].desc.bEndpointAddress)); - } - else if ((iface_desc->endpoint[i].desc.bmAttributes == - USB_ENDPOINT_XFER_BULK) && - ((iface_desc->endpoint[i].desc.bEndpointAddress & - USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT)) - { - // there are 6 bulk out EP. EP6 highest priority. - // EP1-4 is EDCA. EP5 is HCCA. - pAd->BulkOutEpAddr[BulkOutIdx++] = iface_desc->endpoint[i].desc.bEndpointAddress; - pAd->BulkOutMaxPacketSize = iface_desc->endpoint[i].desc.wMaxPacketSize; - - DBGPRINT_RAW(RT_DEBUG_TRACE, - ("BULK OUT MaximumPacketSize = %d\n", pAd->BulkOutMaxPacketSize)); - DBGPRINT_RAW(RT_DEBUG_TRACE, - ("EP address = 0x%2x \n", iface_desc->endpoint[i].desc.bEndpointAddress)); - } - } - - if (!(pAd->BulkInEpAddr && pAd->BulkOutEpAddr[0])) - { - printk("%s: Could not find both bulk-in and bulk-out endpoints\n", __FUNCTION__); - return FALSE; - } - - return TRUE; -} -#endif // LINUX_VERSION_CODE // - - -/* -======================================================================== -Routine Description: - Disable DMA. - -Arguments: - *pAd the raxx interface data pointer - -Return Value: - None - -Note: -======================================================================== -*/ -VOID RT28XXDMADisable( - IN RTMP_ADAPTER *pAd) -{ - // no use -} - - - -/* -======================================================================== -Routine Description: - Enable DMA. - -Arguments: - *pAd the raxx interface data pointer - -Return Value: - None - -Note: -======================================================================== -*/ -VOID RT28XXDMAEnable( - IN RTMP_ADAPTER *pAd) -{ - WPDMA_GLO_CFG_STRUC GloCfg; - USB_DMA_CFG_STRUC UsbCfg; - int i = 0; - - - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x4); - do - { - RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word); - if ((GloCfg.field.TxDMABusy == 0) && (GloCfg.field.RxDMABusy == 0)) - break; - - DBGPRINT(RT_DEBUG_TRACE, ("==> DMABusy\n")); - RTMPusecDelay(1000); - i++; - }while ( i <200); - - - RTMPusecDelay(50); - GloCfg.field.EnTXWriteBackDDONE = 1; - GloCfg.field.EnableRxDMA = 1; - GloCfg.field.EnableTxDMA = 1; - DBGPRINT(RT_DEBUG_TRACE, ("<== WRITE DMA offset 0x208 = 0x%x\n", GloCfg.word)); - RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, GloCfg.word); - - UsbCfg.word = 0; - UsbCfg.field.phyclear = 0; - /* usb version is 1.1,do not use bulk in aggregation */ - if (pAd->BulkInMaxPacketSize == 512) - UsbCfg.field.RxBulkAggEn = 1; - /* for last packet, PBF might use more than limited, so minus 2 to prevent from error */ - UsbCfg.field.RxBulkAggLmt = (MAX_RXBULK_SIZE /1024)-3; - UsbCfg.field.RxBulkAggTOut = 0x80; /* 2006-10-18 */ - UsbCfg.field.RxBulkEn = 1; - UsbCfg.field.TxBulkEn = 1; - - RTUSBWriteMACRegister(pAd, USB_DMA_CFG, UsbCfg.word); - -} - -/* -======================================================================== -Routine Description: - Write Beacon buffer to Asic. - -Arguments: - *pAd the raxx interface data pointer - -Return Value: - None - -Note: -======================================================================== -*/ -VOID RT28xx_UpdateBeaconToAsic( - IN RTMP_ADAPTER *pAd, - IN INT apidx, - IN ULONG FrameLen, - IN ULONG UpdatePos) -{ - PUCHAR pBeaconFrame = NULL; - UCHAR *ptr; - UINT i, padding; - BEACON_SYNC_STRUCT *pBeaconSync = pAd->CommonCfg.pBeaconSync; - UINT32 longValue; -// USHORT shortValue; - BOOLEAN bBcnReq = FALSE; - UCHAR bcn_idx = 0; - - - if (pBeaconFrame == NULL) - { - DBGPRINT(RT_DEBUG_ERROR,("pBeaconFrame is NULL!\n")); - return; - } - - if (pBeaconSync == NULL) - { - DBGPRINT(RT_DEBUG_ERROR,("pBeaconSync is NULL!\n")); - return; - } - - //if ((pAd->WdsTab.Mode == WDS_BRIDGE_MODE) || - // ((pAd->ApCfg.MBSSID[apidx].MSSIDDev == NULL) || !(pAd->ApCfg.MBSSID[apidx].MSSIDDev->flags & IFF_UP)) - // ) - if (bBcnReq == FALSE) - { - /* when the ra interface is down, do not send its beacon frame */ - /* clear all zero */ - for(i=0; iBeaconOffset[bcn_idx] + i, 0x00); - } - pBeaconSync->BeaconBitMap &= (~(BEACON_BITMAP_MASK & (1 << bcn_idx))); - NdisZeroMemory(pBeaconSync->BeaconTxWI[bcn_idx], TXWI_SIZE); - } - else - { - ptr = (PUCHAR)&pAd->BeaconTxWI; -#ifdef RT_BIG_ENDIAN - RTMPWIEndianChange(ptr, TYPE_TXWI); -#endif - if (NdisEqualMemory(pBeaconSync->BeaconTxWI[bcn_idx], &pAd->BeaconTxWI, TXWI_SIZE) == FALSE) - { // If BeaconTxWI changed, we need to rewrite the TxWI for the Beacon frames. - pBeaconSync->BeaconBitMap &= (~(BEACON_BITMAP_MASK & (1 << bcn_idx))); - NdisMoveMemory(pBeaconSync->BeaconTxWI[bcn_idx], &pAd->BeaconTxWI, TXWI_SIZE); - } - - if ((pBeaconSync->BeaconBitMap & (1 << bcn_idx)) != (1 << bcn_idx)) - { - for (i=0; iBeaconOffset[bcn_idx] + i, longValue); - ptr += 4; - } - } - - ptr = pBeaconSync->BeaconBuf[bcn_idx]; - padding = (FrameLen & 0x01); - NdisZeroMemory((PUCHAR)(pBeaconFrame + FrameLen), padding); - FrameLen += padding; - for (i = 0 ; i < FrameLen /*HW_BEACON_OFFSET*/; i += 2) - { - if (NdisEqualMemory(ptr, pBeaconFrame, 2) == FALSE) - { - NdisMoveMemory(ptr, pBeaconFrame, 2); - //shortValue = *ptr + (*(ptr+1)<<8); - //RTMP_IO_WRITE8(pAd, pAd->BeaconOffset[bcn_idx] + TXWI_SIZE + i, shortValue); - RTUSBMultiWrite(pAd, pAd->BeaconOffset[bcn_idx] + TXWI_SIZE + i, ptr, 2); - } - ptr +=2; - pBeaconFrame += 2; - } - - pBeaconSync->BeaconBitMap |= (1 << bcn_idx); - - // For AP interface, set the DtimBitOn so that we can send Bcast/Mcast frame out after this beacon frame. - } - -} - - -VOID RT2870_BssBeaconStop( - IN RTMP_ADAPTER *pAd) -{ - BEACON_SYNC_STRUCT *pBeaconSync; - int i, offset; - BOOLEAN Cancelled = TRUE; - - pBeaconSync = pAd->CommonCfg.pBeaconSync; - if (pBeaconSync && pBeaconSync->EnableBeacon) - { - INT NumOfBcn; - - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - NumOfBcn = MAX_MESH_NUM; - } -#endif // CONFIG_STA_SUPPORT // - - RTMPCancelTimer(&pAd->CommonCfg.BeaconUpdateTimer, &Cancelled); - - for(i=0; iBeaconBuf[i], HW_BEACON_OFFSET); - NdisZeroMemory(pBeaconSync->BeaconTxWI[i], TXWI_SIZE); - - for (offset=0; offsetBeaconOffset[i] + offset, 0x00); - - pBeaconSync->CapabilityInfoLocationInBeacon[i] = 0; - pBeaconSync->TimIELocationInBeacon[i] = 0; - } - pBeaconSync->BeaconBitMap = 0; - pBeaconSync->DtimBitOn = 0; - } -} - - -VOID RT2870_BssBeaconStart( - IN RTMP_ADAPTER *pAd) -{ - int apidx; - BEACON_SYNC_STRUCT *pBeaconSync; -// LARGE_INTEGER tsfTime, deltaTime; - - pBeaconSync = pAd->CommonCfg.pBeaconSync; - if (pBeaconSync && pBeaconSync->EnableBeacon) - { - INT NumOfBcn; - - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - NumOfBcn = MAX_MESH_NUM; - } -#endif // CONFIG_STA_SUPPORT // - - for(apidx=0; apidxBeaconBuf[apidx], HW_BEACON_OFFSET); - pBeaconSync->CapabilityInfoLocationInBeacon[apidx] = CapabilityInfoLocationInBeacon; - pBeaconSync->TimIELocationInBeacon[apidx] = TimIELocationInBeacon; - NdisZeroMemory(pBeaconSync->BeaconTxWI[apidx], TXWI_SIZE); - } - pBeaconSync->BeaconBitMap = 0; - pBeaconSync->DtimBitOn = 0; - pAd->CommonCfg.BeaconUpdateTimer.Repeat = TRUE; - - pAd->CommonCfg.BeaconAdjust = 0; - pAd->CommonCfg.BeaconFactor = 0xffffffff / (pAd->CommonCfg.BeaconPeriod << 10); - pAd->CommonCfg.BeaconRemain = (0xffffffff % (pAd->CommonCfg.BeaconPeriod << 10)) + 1; - printk("RT2870_BssBeaconStart:BeaconFactor=%d, BeaconRemain=%d!\n", pAd->CommonCfg.BeaconFactor, pAd->CommonCfg.BeaconRemain); - RTMPSetTimer(&pAd->CommonCfg.BeaconUpdateTimer, pAd->CommonCfg.BeaconPeriod); - - } -} - - -VOID RT2870_BssBeaconInit( - IN RTMP_ADAPTER *pAd) -{ - BEACON_SYNC_STRUCT *pBeaconSync; - int i; - - NdisAllocMemory(pAd->CommonCfg.pBeaconSync, sizeof(BEACON_SYNC_STRUCT), MEM_ALLOC_FLAG); - if (pAd->CommonCfg.pBeaconSync) - { - pBeaconSync = pAd->CommonCfg.pBeaconSync; - NdisZeroMemory(pBeaconSync, sizeof(BEACON_SYNC_STRUCT)); - for(i=0; i < HW_BEACON_MAX_COUNT; i++) - { - NdisZeroMemory(pBeaconSync->BeaconBuf[i], HW_BEACON_OFFSET); - pBeaconSync->CapabilityInfoLocationInBeacon[i] = 0; - pBeaconSync->TimIELocationInBeacon[i] = 0; - NdisZeroMemory(pBeaconSync->BeaconTxWI[i], TXWI_SIZE); - } - pBeaconSync->BeaconBitMap = 0; - - //RTMPInitTimer(pAd, &pAd->CommonCfg.BeaconUpdateTimer, GET_TIMER_FUNCTION(BeaconUpdateExec), pAd, TRUE); - pBeaconSync->EnableBeacon = TRUE; - } -} - - -VOID RT2870_BssBeaconExit( - IN RTMP_ADAPTER *pAd) -{ - BEACON_SYNC_STRUCT *pBeaconSync; - BOOLEAN Cancelled = TRUE; - int i; - - if (pAd->CommonCfg.pBeaconSync) - { - pBeaconSync = pAd->CommonCfg.pBeaconSync; - pBeaconSync->EnableBeacon = FALSE; - RTMPCancelTimer(&pAd->CommonCfg.BeaconUpdateTimer, &Cancelled); - pBeaconSync->BeaconBitMap = 0; - - for(i=0; iBeaconBuf[i], HW_BEACON_OFFSET); - pBeaconSync->CapabilityInfoLocationInBeacon[i] = 0; - pBeaconSync->TimIELocationInBeacon[i] = 0; - NdisZeroMemory(pBeaconSync->BeaconTxWI[i], TXWI_SIZE); - } - - NdisFreeMemory(pAd->CommonCfg.pBeaconSync, HW_BEACON_OFFSET * HW_BEACON_MAX_COUNT, 0); - pAd->CommonCfg.pBeaconSync = NULL; - } -} - -VOID BeaconUpdateExec( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3) -{ - PRTMP_ADAPTER pAd = (PRTMP_ADAPTER)FunctionContext; - LARGE_INTEGER tsfTime_a;//, tsfTime_b, deltaTime_exp, deltaTime_ab; - UINT32 delta, remain, remain_low, remain_high; -// BOOLEAN positive; - - ReSyncBeaconTime(pAd); - - - - RTMP_IO_READ32(pAd, TSF_TIMER_DW0, &tsfTime_a.u.LowPart); - RTMP_IO_READ32(pAd, TSF_TIMER_DW1, &tsfTime_a.u.HighPart); - - - //positive=getDeltaTime(tsfTime_a, expectedTime, &deltaTime_exp); - remain_high = pAd->CommonCfg.BeaconRemain * tsfTime_a.u.HighPart; - remain_low = tsfTime_a.u.LowPart % (pAd->CommonCfg.BeaconPeriod << 10); - remain = (remain_high + remain_low)%(pAd->CommonCfg.BeaconPeriod << 10); - delta = (pAd->CommonCfg.BeaconPeriod << 10) - remain; - - pAd->CommonCfg.BeaconUpdateTimer.TimerValue = (delta >> 10) + 10; - -} - +#include "../rt2870/2870_main_dev.c" diff --git a/drivers/staging/rt3070/Makefile b/drivers/staging/rt3070/Makefile index 55980c929254..df7ac19e0883 100644 --- a/drivers/staging/rt3070/Makefile +++ b/drivers/staging/rt3070/Makefile @@ -3,11 +3,7 @@ obj-$(CONFIG_RT3070) += rt3070sta.o # TODO: all of these should be removed EXTRA_CFLAGS += -DLINUX -DAGGREGATION_SUPPORT -DPIGGYBACK_SUPPORT -DWMM_SUPPORT EXTRA_CFLAGS += -DRT2870 -DRT30xx -DRT3070 -EXTRA_CFLAGS += -DCONFIG_STA_SUPPORT EXTRA_CFLAGS += -DDBG -EXTRA_CFLAGS += -DDOT11_N_SUPPORT -EXTRA_CFLAGS += -DWPA_SUPPLICANT_SUPPORT -EXTRA_CFLAGS += -DNATIVE_WPA_SUPPLICANT_SUPPORT rt3070sta-objs := \ common/md5.o \ diff --git a/drivers/staging/rt3070/action.h b/drivers/staging/rt3070/action.h index ce3877dce81b..345fa8922ed3 100644 --- a/drivers/staging/rt3070/action.h +++ b/drivers/staging/rt3070/action.h @@ -1,68 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - aironet.h - - Abstract: - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Name Date Modification logs - Paul Lin 04-06-15 Initial -*/ - -#ifndef __ACTION_H__ -#define __ACTION_H__ - -typedef struct PACKED __HT_INFO_OCTET -{ -#ifdef RT_BIG_ENDIAN - UCHAR Reserved:5; - UCHAR STA_Channel_Width:1; - UCHAR Forty_MHz_Intolerant:1; - UCHAR Request:1; -#else - UCHAR Request:1; - UCHAR Forty_MHz_Intolerant:1; - UCHAR STA_Channel_Width:1; - UCHAR Reserved:5; -#endif -} HT_INFORMATION_OCTET; - - -typedef struct PACKED __FRAME_HT_INFO -{ - HEADER_802_11 Hdr; - UCHAR Category; - UCHAR Action; - HT_INFORMATION_OCTET HT_Info; -} FRAME_HT_INFO, *PFRAME_HT_INFO; - -#endif /* __ACTION_H__ */ - - +#include "../rt2870/common/action.h" diff --git a/drivers/staging/rt3070/aironet.h b/drivers/staging/rt3070/aironet.h index 1e07b19b8cdc..78088f2087ef 100644 --- a/drivers/staging/rt3070/aironet.h +++ b/drivers/staging/rt3070/aironet.h @@ -1,210 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - aironet.h - - Abstract: - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Name Date Modification logs - Paul Lin 04-06-15 Initial -*/ - -#ifndef __AIRONET_H__ -#define __AIRONET_H__ - -// Measurement Type definition -#define MSRN_TYPE_UNUSED 0 -#define MSRN_TYPE_CHANNEL_LOAD_REQ 1 -#define MSRN_TYPE_NOISE_HIST_REQ 2 -#define MSRN_TYPE_BEACON_REQ 3 -#define MSRN_TYPE_FRAME_REQ 4 - -// Scan Mode in Beacon Request -#define MSRN_SCAN_MODE_PASSIVE 0 -#define MSRN_SCAN_MODE_ACTIVE 1 -#define MSRN_SCAN_MODE_BEACON_TABLE 2 - -// PHY type definition for Aironet beacon report, CCX 2 table 36-9 -#define PHY_FH 1 -#define PHY_DSS 2 -#define PHY_UNUSED 3 -#define PHY_OFDM 4 -#define PHY_HR_DSS 5 -#define PHY_ERP 6 - -// RPI table in dBm -#define RPI_0 0 // Power <= -87 -#define RPI_1 1 // -87 < Power <= -82 -#define RPI_2 2 // -82 < Power <= -77 -#define RPI_3 3 // -77 < Power <= -72 -#define RPI_4 4 // -72 < Power <= -67 -#define RPI_5 5 // -67 < Power <= -62 -#define RPI_6 6 // -62 < Power <= -57 -#define RPI_7 7 // -57 < Power - -// Cisco Aironet IAPP definetions -#define AIRONET_IAPP_TYPE 0x32 -#define AIRONET_IAPP_SUBTYPE_REQUEST 0x01 -#define AIRONET_IAPP_SUBTYPE_REPORT 0x81 - -// Measurement Request detail format -typedef struct _MEASUREMENT_REQUEST { - UCHAR Channel; - UCHAR ScanMode; // Use only in beacon request, other requests did not use this field - USHORT Duration; -} MEASUREMENT_REQUEST, *PMEASUREMENT_REQUEST; - -// Beacon Measurement Report -// All these field might change to UCHAR, because we didn't do anything to these report. -// We copy all these beacons and report to CCX 2 AP. -typedef struct _BEACON_REPORT { - UCHAR Channel; - UCHAR Spare; - USHORT Duration; - UCHAR PhyType; // Definiation is listed above table 36-9 - UCHAR RxPower; - UCHAR BSSID[6]; - UCHAR ParentTSF[4]; - UCHAR TargetTSF[8]; - USHORT BeaconInterval; - USHORT CapabilityInfo; -} BEACON_REPORT, *PBEACON_REPORT; - -// Frame Measurement Report (Optional) -typedef struct _FRAME_REPORT { - UCHAR Channel; - UCHAR Spare; - USHORT Duration; - UCHAR TA; - UCHAR BSSID[6]; - UCHAR RSSI; - UCHAR Count; -} FRAME_REPORT, *PFRAME_REPORT; - -#pragma pack(1) -// Channel Load Report -typedef struct _CHANNEL_LOAD_REPORT { - UCHAR Channel; - UCHAR Spare; - USHORT Duration; - UCHAR CCABusy; -} CHANNEL_LOAD_REPORT, *PCHANNEL_LOAD_REPORT; -#pragma pack() - -// Nosie Histogram Report -typedef struct _NOISE_HIST_REPORT { - UCHAR Channel; - UCHAR Spare; - USHORT Duration; - UCHAR Density[8]; -} NOISE_HIST_REPORT, *PNOISE_HIST_REPORT; - -// Radio Management Capability element -typedef struct _RADIO_MANAGEMENT_CAPABILITY { - UCHAR Eid; // TODO: Why the Eid is 1 byte, not normal 2 bytes??? - UCHAR Length; - UCHAR AironetOui[3]; // AIronet OUI (00 40 96) - UCHAR Type; // Type / Version - USHORT Status; // swap16 required -} RADIO_MANAGEMENT_CAPABILITY, *PRADIO_MANAGEMENT_CAPABILITY; - -// Measurement Mode Bit definition -typedef struct _MEASUREMENT_MODE { - UCHAR Rsvd:4; - UCHAR Report:1; - UCHAR NotUsed:1; - UCHAR Enable:1; - UCHAR Parallel:1; -} MEASUREMENT_MODE, *PMEASUREMENT_MODE; - -// Measurement Request element, This is little endian mode -typedef struct _MEASUREMENT_REQUEST_ELEMENT { - USHORT Eid; - USHORT Length; // swap16 required - USHORT Token; // non-zero unique token - UCHAR Mode; // Measurement Mode - UCHAR Type; // Measurement type -} MEASUREMENT_REQUEST_ELEMENT, *PMEASUREMENT_REQUEST_ELEMENT; - -// Measurement Report element, This is little endian mode -typedef struct _MEASUREMENT_REPORT_ELEMENT { - USHORT Eid; - USHORT Length; // swap16 required - USHORT Token; // non-zero unique token - UCHAR Mode; // Measurement Mode - UCHAR Type; // Measurement type -} MEASUREMENT_REPORT_ELEMENT, *PMEASUREMENT_REPORT_ELEMENT; - -// Cisco Aironet IAPP Frame Header, Network byte order used -typedef struct _AIRONET_IAPP_HEADER { - UCHAR CiscoSnapHeader[8]; // 8 bytes Cisco snap header - USHORT Length; // IAPP ID & length, remember to swap16 in LE system - UCHAR Type; // IAPP type - UCHAR SubType; // IAPP subtype - UCHAR DA[6]; // Destination MAC address - UCHAR SA[6]; // Source MAC address - USHORT Token; // Dialog token, no need to swap16 since it is for yoken usage only -} AIRONET_IAPP_HEADER, *PAIRONET_IAPP_HEADER; - -// Radio Measurement Request frame -typedef struct _AIRONET_RM_REQUEST_FRAME { - AIRONET_IAPP_HEADER IAPP; // Common header - UCHAR Delay; // Activation Delay - UCHAR Offset; // Measurement offset -} AIRONET_RM_REQUEST_FRAME, *PAIRONET_RM_REQUEST_FRAME; - -// Radio Measurement Report frame -typedef struct _AIRONET_RM_REPORT_FRAME { - AIRONET_IAPP_HEADER IAPP; // Common header -} AIRONET_RM_REPORT_FRAME, *PAIRONET_RM_REPORT_FRAME; - -// Saved element request actions which will saved in StaCfg. -typedef struct _RM_REQUEST_ACTION { - MEASUREMENT_REQUEST_ELEMENT ReqElem; // Saved request element - MEASUREMENT_REQUEST Measurement; // Saved measurement within the request element -} RM_REQUEST_ACTION, *PRM_REQUEST_ACTION; - -// CCX administration control -typedef union _CCX_CONTROL { - struct { - UINT32 Enable:1; // Enable CCX2 - UINT32 LeapEnable:1; // Enable LEAP at CCX2 - UINT32 RMEnable:1; // Radio Measurement Enable - UINT32 DCRMEnable:1; // Non serving channel Radio Measurement enable - UINT32 QOSEnable:1; // Enable QOS for CCX 2.0 support - UINT32 FastRoamEnable:1; // Enable fast roaming - UINT32 Rsvd:2; // Not used - UINT32 dBmToRoam:8; // the condition to roam when receiving Rssi less than this value. It's negative value. - UINT32 TuLimit:16; // Limit for different channel scan - } field; - UINT32 word; -} CCX_CONTROL, *PCCX_CONTROL; - -#endif // __AIRONET_H__ +#include "../rt2870/aironet.h" diff --git a/drivers/staging/rt3070/ap.h b/drivers/staging/rt3070/ap.h index f5ba042e52ba..ab8de4bbad04 100644 --- a/drivers/staging/rt3070/ap.h +++ b/drivers/staging/rt3070/ap.h @@ -1,557 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - ap.h - - Abstract: - Miniport generic portion header file - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Paul Lin 08-01-2002 created - James Tan 09-06-2002 modified (Revise NTCRegTable) - John Chang 12-22-2004 modified for RT2561/2661. merge with STA driver -*/ -#ifndef __AP_H__ -#define __AP_H__ - - - -// ========================= AP RTMP.h ================================ - - - -// ============================================================= -// Function Prototypes -// ============================================================= - -// ap_data.c - -BOOLEAN APBridgeToWirelessSta( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pHeader, - IN UINT HdrLen, - IN PUCHAR pData, - IN UINT DataLen, - IN ULONG fromwdsidx); - -BOOLEAN APHandleRxDoneInterrupt( - IN PRTMP_ADAPTER pAd); - -VOID APSendPackets( - IN NDIS_HANDLE MiniportAdapterContext, - IN PPNDIS_PACKET ppPacketArray, - IN UINT NumberOfPackets); - -NDIS_STATUS APSendPacket( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket); - - -NDIS_STATUS APHardTransmit( - IN PRTMP_ADAPTER pAd, - IN TX_BLK *pTxBlk, - IN UCHAR QueIdx); - -VOID APRxEAPOLFrameIndicate( - IN PRTMP_ADAPTER pAd, - IN MAC_TABLE_ENTRY *pEntry, - IN RX_BLK *pRxBlk, - IN UCHAR FromWhichBSSID); - -NDIS_STATUS APCheckRxError( - IN PRTMP_ADAPTER pAd, - IN PRT28XX_RXD_STRUC pRxD, - IN UCHAR Wcid); - -BOOLEAN APCheckClass2Class3Error( - IN PRTMP_ADAPTER pAd, - IN ULONG Wcid, - IN PHEADER_802_11 pHeader); - -VOID APHandleRxPsPoll( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pAddr, - IN USHORT Aid, - IN BOOLEAN isActive); - -VOID RTMPDescriptorEndianChange( - IN PUCHAR pData, - IN ULONG DescriptorType); - -VOID RTMPFrameEndianChange( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pData, - IN ULONG Dir, - IN BOOLEAN FromRxDoneInt); - -// ap_assoc.c - -VOID APAssocStateMachineInit( - IN PRTMP_ADAPTER pAd, - IN STATE_MACHINE *S, - OUT STATE_MACHINE_FUNC Trans[]); - -VOID APPeerAssocReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID APPeerReassocReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID APPeerDisassocReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID MbssKickOutStas( - IN PRTMP_ADAPTER pAd, - IN INT apidx, - IN USHORT Reason); - -VOID APMlmeKickOutSta( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pStaAddr, - IN UCHAR Wcid, - IN USHORT Reason); - -VOID APMlmeDisassocReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID APCls3errAction( - IN PRTMP_ADAPTER pAd, - IN ULONG Wcid, - IN PHEADER_802_11 pHeader); - - -USHORT APBuildAssociation( - IN PRTMP_ADAPTER pAd, - IN MAC_TABLE_ENTRY *pEntry, - IN USHORT CapabilityInfo, - IN UCHAR MaxSupportedRateIn500Kbps, - IN UCHAR *RSN, - IN UCHAR *pRSNLen, - IN BOOLEAN bWmmCapable, - IN ULONG RalinkIe, -#ifdef DOT11N_DRAFT3 - IN EXT_CAP_INFO_ELEMENT ExtCapInfo, -#endif // DOT11N_DRAFT3 // - IN HT_CAPABILITY_IE *pHtCapability, - IN UCHAR HtCapabilityLen, - OUT USHORT *pAid); - -/* -VOID RTMPAddClientSec( - IN PRTMP_ADAPTER pAd, - IN UCHAR BssIdx, - IN UCHAR KeyIdx, - IN UCHAR CipherAlg, - IN PUCHAR pKey, - IN PUCHAR pTxMic, - IN PUCHAR pRxMic, - IN MAC_TABLE_ENTRY *pEntry); -*/ - -// ap_auth.c - -void APAuthStateMachineInit( - IN PRTMP_ADAPTER pAd, - IN STATE_MACHINE *Sm, - OUT STATE_MACHINE_FUNC Trans[]); - -VOID APMlmeDeauthReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID APCls2errAction( - IN PRTMP_ADAPTER pAd, - IN ULONG Wcid, - IN PHEADER_802_11 pHeader); - -// ap_authrsp.c - -VOID APAuthRspStateMachineInit( - IN PRTMP_ADAPTER pAd, - IN PSTATE_MACHINE Sm, - IN STATE_MACHINE_FUNC Trans[]); - -VOID APPeerAuthAtAuthRspIdleAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID APPeerDeauthReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID APPeerAuthSimpleRspGenAndSend( - IN PRTMP_ADAPTER pAd, - IN PHEADER_802_11 pHdr80211, - IN USHORT Alg, - IN USHORT Seq, - IN USHORT StatusCode); - -// ap_connect.c - -BOOLEAN BeaconTransmitRequired( - IN PRTMP_ADAPTER pAd, - IN INT apidx); - -VOID APMakeBssBeacon( - IN PRTMP_ADAPTER pAd, - IN INT apidx); - -VOID APUpdateBeaconFrame( - IN PRTMP_ADAPTER pAd, - IN INT apidx); - -VOID APMakeAllBssBeacon( - IN PRTMP_ADAPTER pAd); - -VOID APUpdateAllBeaconFrame( - IN PRTMP_ADAPTER pAd); - - -// ap_sync.c - -VOID APSyncStateMachineInit( - IN PRTMP_ADAPTER pAd, - IN STATE_MACHINE *Sm, - OUT STATE_MACHINE_FUNC Trans[]); - -VOID APScanTimeout( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); - -VOID APInvalidStateWhenScan( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID APScanTimeoutAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID APPeerProbeReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID APPeerBeaconAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID APMlmeScanReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID APPeerBeaconAtScanAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID APScanCnclAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID ApSiteSurvey( - IN PRTMP_ADAPTER pAd); - -VOID SupportRate( - IN PUCHAR SupRate, - IN UCHAR SupRateLen, - IN PUCHAR ExtRate, - IN UCHAR ExtRateLen, - OUT PUCHAR *Rates, - OUT PUCHAR RatesLen, - OUT PUCHAR pMaxSupportRate); - - -BOOLEAN ApScanRunning( - IN PRTMP_ADAPTER pAd); - -#ifdef DOT11N_DRAFT3 -VOID APOverlappingBSSScan( - IN RTMP_ADAPTER *pAd); -#endif // DOT11N_DRAFT3 // - -// ap_wpa.c - -VOID APWpaStateMachineInit( - IN PRTMP_ADAPTER pAd, - IN STATE_MACHINE *Sm, - OUT STATE_MACHINE_FUNC Trans[]); - -// ap_mlme.c - -VOID APMlmePeriodicExec( - IN PRTMP_ADAPTER pAd); - -VOID APMlmeSelectTxRateTable( - IN PRTMP_ADAPTER pAd, - IN PMAC_TABLE_ENTRY pEntry, - IN PUCHAR *ppTable, - IN PUCHAR pTableSize, - IN PUCHAR pInitTxRateIdx); - -VOID APMlmeSetTxRate( - IN PRTMP_ADAPTER pAd, - IN PMAC_TABLE_ENTRY pEntry, - IN PRTMP_TX_RATE_SWITCH pTxRate); - -VOID APMlmeDynamicTxRateSwitching( - IN PRTMP_ADAPTER pAd); - -VOID APQuickResponeForRateUpExec( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); - -BOOLEAN APMsgTypeSubst( - IN PRTMP_ADAPTER pAd, - IN PFRAME_802_11 pFrame, - OUT INT *Machine, - OUT INT *MsgType); - -VOID APQuickResponeForRateUpExec( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); - -#ifdef RT2870 -VOID BeaconUpdateExec( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); -#endif // RT2870 // - -VOID RTMPSetPiggyBack( - IN PRTMP_ADAPTER pAd, - IN BOOLEAN bPiggyBack); - -VOID APAsicEvaluateRxAnt( - IN PRTMP_ADAPTER pAd); - -VOID APAsicRxAntEvalTimeout( - IN PRTMP_ADAPTER pAd); - -// ap.c - -VOID APSwitchChannel( - IN PRTMP_ADAPTER pAd, - IN INT Channel); - -NDIS_STATUS APInitialize( - IN PRTMP_ADAPTER pAd); - -VOID APShutdown( - IN PRTMP_ADAPTER pAd); - -VOID APStartUp( - IN PRTMP_ADAPTER pAd); - -VOID APStop( - IN PRTMP_ADAPTER pAd); - -VOID APCleanupPsQueue( - IN PRTMP_ADAPTER pAd, - IN PQUEUE_HEADER pQueue); - -VOID MacTableReset( - IN PRTMP_ADAPTER pAd); - -MAC_TABLE_ENTRY *MacTableInsertEntry( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pAddr, - IN UCHAR apidx, - IN BOOLEAN CleanAll); - -BOOLEAN MacTableDeleteEntry( - IN PRTMP_ADAPTER pAd, - IN USHORT wcid, - IN PUCHAR pAddr); - -MAC_TABLE_ENTRY *MacTableLookup( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pAddr); - -VOID MacTableMaintenance( - IN PRTMP_ADAPTER pAd); - -UINT32 MacTableAssocStaNumGet( - IN PRTMP_ADAPTER pAd); - -MAC_TABLE_ENTRY *APSsPsInquiry( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pAddr, - OUT SST *Sst, - OUT USHORT *Aid, - OUT UCHAR *PsMode, - OUT UCHAR *Rate); - -BOOLEAN APPsIndicate( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pAddr, - IN ULONG Wcid, - IN UCHAR Psm); - -VOID ApLogEvent( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pAddr, - IN USHORT Event); - -#ifdef DOT11_N_SUPPORT -VOID APUpdateOperationMode( - IN PRTMP_ADAPTER pAd); -#endif // DOT11_N_SUPPORT // - -VOID APUpdateCapabilityAndErpIe( - IN PRTMP_ADAPTER pAd); - -BOOLEAN ApCheckAccessControlList( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pAddr, - IN UCHAR Apidx); - -VOID ApUpdateAccessControlList( - IN PRTMP_ADAPTER pAd, - IN UCHAR Apidx); - -VOID ApEnqueueNullFrame( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pAddr, - IN UCHAR TxRate, - IN UCHAR PID, - IN UCHAR apidx, - IN BOOLEAN bQosNull, - IN BOOLEAN bEOSP, - IN UCHAR OldUP); - -VOID ApSendFrame( - IN PRTMP_ADAPTER pAd, - IN PVOID pBuffer, - IN ULONG Length, - IN UCHAR TxRate, - IN UCHAR PID); - -VOID ApEnqueueAckFrame( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pAddr, - IN UCHAR TxRate, - IN UCHAR apidx); - -UCHAR APAutoSelectChannel( - IN PRTMP_ADAPTER pAd, - IN BOOLEAN Optimal); - -// ap_sanity.c - - -BOOLEAN PeerAssocReqCmmSanity( - IN PRTMP_ADAPTER pAd, - IN BOOLEAN isRessoc, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PUCHAR pAddr2, - OUT USHORT *pCapabilityInfo, - OUT USHORT *pListenInterval, - OUT PUCHAR pApAddr, - OUT UCHAR *pSsidLen, - OUT char *Ssid, - OUT UCHAR *pRatesLen, - OUT UCHAR Rates[], - OUT UCHAR *RSN, - OUT UCHAR *pRSNLen, - OUT BOOLEAN *pbWmmCapable, - OUT ULONG *pRalinkIe, -#ifdef DOT11N_DRAFT3 - OUT EXT_CAP_INFO_ELEMENT *pExtCapInfo, -#endif // DOT11N_DRAFT3 // - OUT UCHAR *pHtCapabilityLen, - OUT HT_CAPABILITY_IE *pHtCapability); - - -BOOLEAN PeerDisassocReqSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PUCHAR pAddr2, - OUT USHORT *Reason); - -BOOLEAN PeerDeauthReqSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PUCHAR pAddr2, - OUT USHORT *Reason); - -BOOLEAN APPeerAuthSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PUCHAR pAddr1, - OUT PUCHAR pAddr2, - OUT USHORT *Alg, - OUT USHORT *Seq, - OUT USHORT *Status, - CHAR *ChlgText); - -BOOLEAN APPeerProbeReqSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PUCHAR pAddr2, - OUT CHAR Ssid[], - OUT UCHAR *SsidLen); - -BOOLEAN APPeerBeaconAndProbeRspSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PUCHAR pAddr2, - OUT PUCHAR pBssid, - OUT CHAR Ssid[], - OUT UCHAR *SsidLen, - OUT UCHAR *BssType, - OUT USHORT *BeaconPeriod, - OUT UCHAR *Channel, - OUT LARGE_INTEGER *Timestamp, - OUT USHORT *CapabilityInfo, - OUT UCHAR Rate[], - OUT UCHAR *RateLen, - OUT BOOLEAN *ExtendedRateIeExist, - OUT UCHAR *Erp); - - -// ================== end of AP RTMP.h ======================== - - -#endif // __AP_H__ - +#include "../rt2870/ap.h" diff --git a/drivers/staging/rt3070/chlist.h b/drivers/staging/rt3070/chlist.h index 7151e8668cb5..8ee1ff527f5d 100644 --- a/drivers/staging/rt3070/chlist.h +++ b/drivers/staging/rt3070/chlist.h @@ -1,1253 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - chlist.c - - Abstract: - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Fonchi Wu 2007-12-19 created -*/ - -#ifndef __CHLIST_H__ -#define __CHLIST_H__ - -#include "rtmp_type.h" -#include "rtmp_def.h" - - -#define ODOR 0 -#define IDOR 1 -#define BOTH 2 - -#define BAND_5G 0 -#define BAND_24G 1 -#define BAND_BOTH 2 - -typedef struct _CH_DESP { - UCHAR FirstChannel; - UCHAR NumOfCh; - CHAR MaxTxPwr; // dBm - UCHAR Geography; // 0:out door, 1:in door, 2:both - BOOLEAN DfsReq; // Dfs require, 0: No, 1: yes. -} CH_DESP, *PCH_DESP; - -typedef struct _CH_REGION { - UCHAR CountReg[3]; - UCHAR DfsType; // 0: CE, 1: FCC, 2: JAP, 3:JAP_W53, JAP_W56 - CH_DESP ChDesp[10]; -} CH_REGION, *PCH_REGION; - -static CH_REGION ChRegion[] = -{ - { // Antigua and Berbuda - "AG", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 - { 52, 4, 23, BOTH, FALSE}, // 5G, ch 52~64 - { 100, 11, 30, BOTH, FALSE}, // 5G, ch 100~140 - { 0}, // end - } - }, - - { // Argentina - "AR", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 - { 149, 4, 30, BOTH, FALSE}, // 5G, ch 149~161 - { 0}, // end - } - }, - - { // Aruba - "AW", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 - { 52, 4, 23, BOTH, FALSE}, // 5G, ch 52~64 - { 100, 11, 30, BOTH, FALSE}, // 5G, ch 100~140 - { 0}, // end - } - }, - - { // Australia - "AU", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 - { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 - { 149, 5, 30, BOTH, FALSE}, // 5G, ch 149~165 - { 0}, // end - } - }, - - { // Austria - "AT", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 36, 4, 23, IDOR, TRUE}, // 5G, ch 36~48 - { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 - { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 - { 0}, // end - } - }, - - { // Bahamas - "BS", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 - { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 - { 149, 5, 30, BOTH, FALSE}, // 5G, ch 149~165 - { 0}, // end - } - }, - - { // Barbados - "BB", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 - { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 - { 100, 11, 30, BOTH, FALSE}, // 5G, ch 100~140 - { 0}, // end - } - }, - - { // Bermuda - "BM", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 - { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 - { 100, 11, 30, BOTH, FALSE}, // 5G, ch 100~140 - { 0}, // end - } - }, - - { // Brazil - "BR", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 - { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 - { 100, 11, 24, BOTH, FALSE}, // 5G, ch 100~140 - { 149, 5, 30, BOTH, FALSE}, // 5G, ch 100~140 - { 0}, // end - } - }, - - { // Belgium - "BE", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 36, 4, 18, IDOR, FALSE}, // 5G, ch 36~48 - { 52, 4, 18, IDOR, FALSE}, // 5G, ch 52~64 - { 0}, // end - } - }, - - { // Bulgaria - "BG", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 - { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 - { 100, 11, 30, ODOR, TRUE}, // 5G, ch 100~140 - { 0}, // end - } - }, - - { // Canada - "CA", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 - { 52, 4, 23, BOTH, FALSE}, // 5G, ch 52~64 - { 149, 5, 30, BOTH, FALSE}, // 5G, ch 149~165 - { 0}, // end - } - }, - - { // Cayman IsLands - "KY", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 - { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 - { 100, 11, 30, BOTH, FALSE}, // 5G, ch 100~140 - { 0}, // end - } - }, - - { // Chile - "CL", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 36, 4, 20, BOTH, FALSE}, // 5G, ch 36~48 - { 52, 4, 20, BOTH, FALSE}, // 5G, ch 52~64 - { 149, 5, 20, BOTH, FALSE}, // 5G, ch 149~165 - { 0}, // end - } - }, - - { // China - "CN", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 149, 4, 27, BOTH, FALSE}, // 5G, ch 149~161 - { 0}, // end - } - }, - - { // Colombia - "CO", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 36, 4, 17, BOTH, FALSE}, // 5G, ch 36~48 - { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 - { 100, 11, 30, BOTH, FALSE}, // 5G, ch 100~140 - { 149, 5, 30, BOTH, FALSE}, // 5G, ch 149~165 - { 0}, // end - } - }, - - { // Costa Rica - "CR", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 36, 4, 17, BOTH, FALSE}, // 5G, ch 36~48 - { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 - { 149, 4, 30, BOTH, FALSE}, // 5G, ch 149~161 - { 0}, // end - } - }, - - { // Cyprus - "CY", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 - { 52, 4, 24, IDOR, TRUE}, // 5G, ch 52~64 - { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 - { 0}, // end - } - }, - - { // Czech_Republic - "CZ", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 - { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 - { 0}, // end - } - }, - - { // Denmark - "DK", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 - { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 - { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 - { 0}, // end - } - }, - - { // Dominican Republic - "DO", - CE, - { - { 1, 0, 20, BOTH, FALSE}, // 2.4 G, ch 0 - { 149, 4, 20, BOTH, FALSE}, // 5G, ch 149~161 - { 0}, // end - } - }, - - { // Equador - "EC", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 100, 11, 27, BOTH, FALSE}, // 5G, ch 100~140 - { 0}, // end - } - }, - - { // El Salvador - "SV", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 - { 52, 4, 30, BOTH, TRUE}, // 5G, ch 52~64 - { 149, 4, 36, BOTH, TRUE}, // 5G, ch 149~165 - { 0}, // end - } - }, - - { // Finland - "FI", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 - { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 - { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 - { 0}, // end - } - }, - - { // France - "FR", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 - { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 - { 0}, // end - } - }, - - { // Germany - "DE", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 - { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 - { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 - { 0}, // end - } - }, - - { // Greece - "GR", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 - { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 - { 100, 11, 30, ODOR, TRUE}, // 5G, ch 100~140 - { 0}, // end - } - }, - - { // Guam - "GU", - CE, - { - { 1, 11, 20, BOTH, FALSE}, // 2.4 G, ch 1~11 - { 36, 4, 17, BOTH, FALSE}, // 5G, ch 36~48 - { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 - { 100, 11, 30, BOTH, FALSE}, // 5G, ch 100~140 - { 149, 5, 30, BOTH, FALSE}, // 5G, ch 149~165 - { 0}, // end - } - }, - - { // Guatemala - "GT", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 36, 4, 17, BOTH, FALSE}, // 5G, ch 36~48 - { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 - { 149, 4, 30, BOTH, FALSE}, // 5G, ch 149~161 - { 0}, // end - } - }, - - { // Haiti - "HT", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 36, 4, 17, BOTH, FALSE}, // 5G, ch 36~48 - { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 - { 149, 4, 30, BOTH, FALSE}, // 5G, ch 149~161 - { 0}, // end - } - }, - - { // Honduras - "HN", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 149, 4, 27, BOTH, FALSE}, // 5G, ch 149~161 - { 0}, // end - } - }, - - { // Hong Kong - "HK", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 - { 52, 4, 23, IDOR, FALSE}, // 5G, ch 52~64 - { 149, 4, 30, BOTH, FALSE}, // 5G, ch 149~161 - { 0}, // end - } - }, - - { // Hungary - "HU", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 - { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 - { 0}, // end - } - }, - - { // Iceland - "IS", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 - { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 - { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 - { 0}, // end - } - }, - - { // India - "IN", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 149, 4, 24, IDOR, FALSE}, // 5G, ch 149~161 - { 0}, // end - } - }, - - { // Indonesia - "ID", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 149, 4, 27, BOTH, FALSE}, // 5G, ch 149~161 - { 0}, // end - } - }, - - { // Ireland - "IE", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 - { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 - { 100, 11, 30, ODOR, TRUE}, // 5G, ch 100~140 - { 0}, // end - } - }, - - { // Israel - "IL", - CE, - { - { 1, 3, 20, IDOR, FALSE}, // 2.4 G, ch 1~3 - { 4, 6, 20, BOTH, FALSE}, // 2.4 G, ch 4~9 - { 10, 4, 20, IDOR, FALSE}, // 2.4 G, ch 10~13 - { 0}, // end - } - }, - - { // Italy - "IT", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 - { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 - { 100, 11, 30, ODOR, TRUE}, // 5G, ch 100~140 - { 0}, // end - } - }, - - { // Japan - "JP", - JAP, - { - { 1, 14, 20, BOTH, FALSE}, // 2.4 G, ch 1~14 - { 34, 4, 23, IDOR, FALSE}, // 5G, ch 34~46 - { 0}, // end - } - }, - - { // Jordan - "JO", - CE, - { - { 1, 13, 20, IDOR, FALSE}, // 2.4 G, ch 1~13 - { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 - { 149, 4, 23, IDOR, FALSE}, // 5G, ch 149~161 - { 0}, // end - } - }, - - { // Latvia - "LV", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 - { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 - { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 - { 0}, // end - } - }, - - { // Liechtenstein - "LI", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 - { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 - { 0}, // end - } - }, - - { // Lithuania - "LT", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 - { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 - { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 - { 0}, // end - } - }, - - { // Luxemburg - "LU", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 - { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 - { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 - { 0}, // end - } - }, - - { // Malaysia - "MY", - CE, - { - { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 - { 52, 4, 23, BOTH, FALSE}, // 5G, ch 52~64 - { 149, 5, 20, BOTH, FALSE}, // 5G, ch 149~165 - { 0}, // end - } - }, - - { // Malta - "MT", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 - { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 - { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 - { 0}, // end - } - }, - - { // Marocco - "MA", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 36, 4, 24, IDOR, FALSE}, // 5G, ch 36~48 - { 0}, // end - } - }, - - { // Mexico - "MX", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 - { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 - { 149, 5, 30, IDOR, FALSE}, // 5G, ch 149~165 - { 0}, // end - } - }, - - { // Netherlands - "NL", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 - { 52, 4, 24, IDOR, TRUE}, // 5G, ch 52~64 - { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 - { 0}, // end - } - }, - - { // New Zealand - "NZ", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 36, 4, 24, BOTH, FALSE}, // 5G, ch 36~48 - { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 - { 149, 4, 30, BOTH, FALSE}, // 5G, ch 149~161 - { 0}, // end - } - }, - - { // Norway - "NO", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 36, 4, 24, IDOR, FALSE}, // 5G, ch 36~48 - { 52, 4, 24, IDOR, TRUE}, // 5G, ch 52~64 - { 100, 11, 30, BOTH, TRUE}, // 5G, ch 149~161 - { 0}, // end - } - }, - - { // Peru - "PE", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 149, 4, 27, BOTH, FALSE}, // 5G, ch 149~161 - { 0}, // end - } - }, - - { // Portugal - "PT", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 - { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 - { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 - { 0}, // end - } - }, - - { // Poland - "PL", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 - { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 - { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 - { 0}, // end - } - }, - - { // Romania - "RO", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 - { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 - { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 - { 0}, // end - } - }, - - { // Russia - "RU", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 149, 4, 20, IDOR, FALSE}, // 5G, ch 149~161 - { 0}, // end - } - }, - - { // Saudi Arabia - "SA", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 - { 52, 4, 23, BOTH, FALSE}, // 5G, ch 52~64 - { 149, 4, 23, BOTH, FALSE}, // 5G, ch 149~161 - { 0}, // end - } - }, - - { // Serbia_and_Montenegro - "CS", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 0}, // end - } - }, - - { // Singapore - "SG", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 - { 52, 4, 23, BOTH, FALSE}, // 5G, ch 52~64 - { 149, 4, 20, BOTH, FALSE}, // 5G, ch 149~161 - { 0}, // end - } - }, - - { // Slovakia - "SK", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 - { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 - { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 - { 0}, // end - } - }, - - { // Slovenia - "SI", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 - { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 - { 0}, // end - } - }, - - { // South Africa - "ZA", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 - { 52, 4, 23, IDOR, FALSE}, // 5G, ch 52~64 - { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 - { 149, 4, 30, BOTH, FALSE}, // 5G, ch 149~161 - { 0}, // end - } - }, - - { // South Korea - "KR", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 36, 4, 20, BOTH, FALSE}, // 5G, ch 36~48 - { 52, 4, 20, BOTH, FALSE}, // 5G, ch 52~64 - { 100, 8, 20, BOTH, FALSE}, // 5G, ch 100~128 - { 149, 4, 20, BOTH, FALSE}, // 5G, ch 149~161 - { 0}, // end - } - }, - - { // Spain - "ES", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 36, 4, 17, IDOR, FALSE}, // 5G, ch 36~48 - { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 - { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 - { 0}, // end - } - }, - - { // Sweden - "SE", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 - { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 - { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 - { 0}, // end - } - }, - - { // Switzerland - "CH", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 - { 36, 4, 23, IDOR, TRUE}, // 5G, ch 36~48 - { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 - { 0}, // end - } - }, - - { // Taiwan - "TW", - CE, - { - { 1, 11, 30, BOTH, FALSE}, // 2.4 G, ch 1~11 - { 52, 4, 23, IDOR, FALSE}, // 5G, ch 52~64 - { 0}, // end - } - }, - - { // Turkey - "TR", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~11 - { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 - { 52, 4, 23, BOTH, FALSE}, // 5G, ch 52~64 - { 0}, // end - } - }, - - { // UK - "GB", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~11 - { 36, 4, 23, IDOR, FALSE}, // 5G, ch 52~64 - { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 - { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 - { 0}, // end - } - }, - - { // Ukraine - "UA", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~11 - { 0}, // end - } - }, - - { // United_Arab_Emirates - "AE", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~11 - { 0}, // end - } - }, - - { // United_States - "US", - CE, - { - { 1, 11, 30, BOTH, FALSE}, // 2.4 G, ch 1~11 - { 36, 4, 17, IDOR, FALSE}, // 5G, ch 52~64 - { 52, 4, 24, BOTH, TRUE}, // 5G, ch 52~64 - { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 - { 149, 5, 30, BOTH, FALSE}, // 5G, ch 149~165 - { 0}, // end - } - }, - - { // Venezuela - "VE", - CE, - { - { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~11 - { 149, 4, 27, BOTH, FALSE}, // 5G, ch 149~161 - { 0}, // end - } - }, - - { // Default - "", - CE, - { - { 1, 11, 20, BOTH, FALSE}, // 2.4 G, ch 1~11 - { 36, 4, 20, BOTH, FALSE}, // 5G, ch 52~64 - { 52, 4, 20, BOTH, FALSE}, // 5G, ch 52~64 - { 100, 11, 20, BOTH, FALSE}, // 5G, ch 100~140 - { 149, 5, 20, BOTH, FALSE}, // 5G, ch 149~165 - { 0}, // end - } - }, -}; - -static inline PCH_REGION GetChRegion( - IN PUCHAR CntryCode) -{ - INT loop = 0; - PCH_REGION pChRegion = NULL; - - while (strcmp(ChRegion[loop].CountReg, "") != 0) - { - if (strncmp(ChRegion[loop].CountReg, CntryCode, 2) == 0) - { - pChRegion = &ChRegion[loop]; - break; - } - loop++; - } - - if (pChRegion == NULL) - pChRegion = &ChRegion[loop]; - return pChRegion; -} - -static inline VOID ChBandCheck( - IN UCHAR PhyMode, - OUT PUCHAR pChType) -{ - switch(PhyMode) - { - case PHY_11A: -#ifdef DOT11_N_SUPPORT - case PHY_11AN_MIXED: -#endif // DOT11_N_SUPPORT // - *pChType = BAND_5G; - break; - case PHY_11ABG_MIXED: -#ifdef DOT11_N_SUPPORT - case PHY_11AGN_MIXED: - case PHY_11ABGN_MIXED: -#endif // DOT11_N_SUPPORT // - *pChType = BAND_BOTH; - break; - - default: - *pChType = BAND_24G; - break; - } -} - -static inline UCHAR FillChList( - IN PRTMP_ADAPTER pAd, - IN PCH_DESP pChDesp, - IN UCHAR Offset, - IN UCHAR increment) -{ - INT i, j, l; - UCHAR channel; - - j = Offset; - for (i = 0; i < pChDesp->NumOfCh; i++) - { - channel = pChDesp->FirstChannel + i * increment; - for (l=0; lTxPower[l].Channel) - { - pAd->ChannelList[j].Power = pAd->TxPower[l].Power; - pAd->ChannelList[j].Power2 = pAd->TxPower[l].Power2; - break; - } - } - if (l == MAX_NUM_OF_CHANNELS) - continue; - - pAd->ChannelList[j].Channel = pChDesp->FirstChannel + i * increment; - pAd->ChannelList[j].MaxTxPwr = pChDesp->MaxTxPwr; - pAd->ChannelList[j].DfsReq = pChDesp->DfsReq; - j++; - } - pAd->ChannelListNum = j; - - return j; -} - -static inline VOID CreateChList( - IN PRTMP_ADAPTER pAd, - IN PCH_REGION pChRegion, - IN UCHAR Geography) -{ - INT i; - UCHAR offset = 0; - PCH_DESP pChDesp; - UCHAR ChType; - UCHAR increment; - - if (pChRegion == NULL) - return; - - ChBandCheck(pAd->CommonCfg.PhyMode, &ChType); - - for (i=0; i<10; i++) - { - pChDesp = &pChRegion->ChDesp[i]; - if (pChDesp->FirstChannel == 0) - break; - - if (ChType == BAND_5G) - { - if (pChDesp->FirstChannel <= 14) - continue; - } - else if (ChType == BAND_24G) - { - if (pChDesp->FirstChannel > 14) - continue; - } - - if ((pChDesp->Geography == BOTH) - || (pChDesp->Geography == Geography)) - { - if (pChDesp->FirstChannel > 14) - increment = 4; - else - increment = 1; - offset = FillChList(pAd, pChDesp, offset, increment); - } - } -} - -static inline VOID BuildChannelListEx( - IN PRTMP_ADAPTER pAd) -{ - PCH_REGION pChReg; - - pChReg = GetChRegion(pAd->CommonCfg.CountryCode); - CreateChList(pAd, pChReg, pAd->CommonCfg.Geography); -} - -static inline VOID BuildBeaconChList( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf, - OUT PULONG pBufLen) -{ - INT i; - ULONG TmpLen; - PCH_REGION pChRegion; - PCH_DESP pChDesp; - UCHAR ChType; - - pChRegion = GetChRegion(pAd->CommonCfg.CountryCode); - - if (pChRegion == NULL) - return; - - ChBandCheck(pAd->CommonCfg.PhyMode, &ChType); - *pBufLen = 0; - - for (i=0; i<10; i++) - { - pChDesp = &pChRegion->ChDesp[i]; - if (pChDesp->FirstChannel == 0) - break; - - if (ChType == BAND_5G) - { - if (pChDesp->FirstChannel <= 14) - continue; - } - else if (ChType == BAND_24G) - { - if (pChDesp->FirstChannel > 14) - continue; - } - - if ((pChDesp->Geography == BOTH) - || (pChDesp->Geography == pAd->CommonCfg.Geography)) - { - MakeOutgoingFrame(pBuf + *pBufLen, &TmpLen, - 1, &pChDesp->FirstChannel, - 1, &pChDesp->NumOfCh, - 1, &pChDesp->MaxTxPwr, - END_OF_ARGS); - *pBufLen += TmpLen; - } - } -} - - -#ifdef DOT11_N_SUPPORT -static inline BOOLEAN IsValidChannel( - IN PRTMP_ADAPTER pAd, - IN UCHAR channel) - -{ - INT i; - - for (i = 0; i < pAd->ChannelListNum; i++) - { - if (pAd->ChannelList[i].Channel == channel) - break; - } - - if (i == pAd->ChannelListNum) - return FALSE; - else - return TRUE; -} - - -static inline UCHAR GetExtCh( - IN UCHAR Channel, - IN UCHAR Direction) -{ - CHAR ExtCh; - - if (Direction == EXTCHA_ABOVE) - ExtCh = Channel + 4; - else - ExtCh = (Channel - 4) > 0 ? (Channel - 4) : 0; - - return ExtCh; -} - - -static inline VOID N_ChannelCheck( - IN PRTMP_ADAPTER pAd) -{ - //UCHAR ChannelNum = pAd->ChannelListNum; - UCHAR Channel = pAd->CommonCfg.Channel; - - if ((pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) && (pAd->CommonCfg.RegTransmitSetting.field.BW == BW_40)) - { - if (Channel > 14) - { - if ((Channel == 36) || (Channel == 44) || (Channel == 52) || (Channel == 60) || (Channel == 100) || (Channel == 108) || - (Channel == 116) || (Channel == 124) || (Channel == 132) || (Channel == 149) || (Channel == 157)) - { - pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_ABOVE; - } - else if ((Channel == 40) || (Channel == 48) || (Channel == 56) || (Channel == 64) || (Channel == 104) || (Channel == 112) || - (Channel == 120) || (Channel == 128) || (Channel == 136) || (Channel == 153) || (Channel == 161)) - { - pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_BELOW; - } - else - { - pAd->CommonCfg.RegTransmitSetting.field.BW = BW_20; - } - } - else - { - do - { - UCHAR ExtCh; - UCHAR Dir = pAd->CommonCfg.RegTransmitSetting.field.EXTCHA; - ExtCh = GetExtCh(Channel, Dir); - if (IsValidChannel(pAd, ExtCh)) - break; - - Dir = (Dir == EXTCHA_ABOVE) ? EXTCHA_BELOW : EXTCHA_ABOVE; - ExtCh = GetExtCh(Channel, Dir); - if (IsValidChannel(pAd, ExtCh)) - { - pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = Dir; - break; - } - pAd->CommonCfg.RegTransmitSetting.field.BW = BW_20; - } while(FALSE); - - if (Channel == 14) - { - pAd->CommonCfg.RegTransmitSetting.field.BW = BW_20; - //pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_NONE; // We didn't set the ExtCh as NONE due to it'll set in RTMPSetHT() - } - } - } - - -} - - -static inline VOID N_SetCenCh( - IN PRTMP_ADAPTER pAd) -{ - if (pAd->CommonCfg.RegTransmitSetting.field.BW == BW_40) - { - if (pAd->CommonCfg.RegTransmitSetting.field.EXTCHA == EXTCHA_ABOVE) - { - pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel + 2; - } - else - { - if (pAd->CommonCfg.Channel == 14) - pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel - 1; - else - pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel - 2; - } - } - else - { - pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel; - } -} -#endif // DOT11_N_SUPPORT // - - -static inline UINT8 GetCuntryMaxTxPwr( - IN PRTMP_ADAPTER pAd, - IN UINT8 channel) -{ - int i; - for (i = 0; i < pAd->ChannelListNum; i++) - { - if (pAd->ChannelList[i].Channel == channel) - break; - } - - if (i == pAd->ChannelListNum) - return 0xff; - else - return pAd->ChannelList[i].MaxTxPwr; -} -#endif // __CHLIST_H__ - +#include "../rt2870/chlist.h" diff --git a/drivers/staging/rt3070/common/2870_rtmp_init.c b/drivers/staging/rt3070/common/2870_rtmp_init.c index fdf8dc176a67..5456454b8d3e 100644 --- a/drivers/staging/rt3070/common/2870_rtmp_init.c +++ b/drivers/staging/rt3070/common/2870_rtmp_init.c @@ -1,1762 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - 2870_rtmp_init.c - - Abstract: - Miniport generic portion header file - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Paul Lin 2002-08-01 created - John Chang 2004-08-20 RT2561/2661 use scatter-gather scheme - Jan Lee 2006-09-15 RT2860. Change for 802.11n , EEPROM, Led, BA, HT. - Sample Lin 2007-05-31 Merge RT2860 and RT2870 drivers. -*/ - -#include "../rt_config.h" - - -static void rx_done_tasklet(unsigned long data); -static void rt2870_hcca_dma_done_tasklet(unsigned long data); -static void rt2870_ac3_dma_done_tasklet(unsigned long data); -static void rt2870_ac2_dma_done_tasklet(unsigned long data); -static void rt2870_ac1_dma_done_tasklet(unsigned long data); -static void rt2870_ac0_dma_done_tasklet(unsigned long data); -static void rt2870_mgmt_dma_done_tasklet(unsigned long data); -static void rt2870_null_frame_complete_tasklet(unsigned long data); -static void rt2870_rts_frame_complete_tasklet(unsigned long data); -static void rt2870_pspoll_frame_complete_tasklet(unsigned long data); -static void rt2870_dataout_complete_tasklet(unsigned long data); - - -/* -======================================================================== -Routine Description: - Initialize receive data structures. - -Arguments: - pAd Pointer to our adapter - -Return Value: - NDIS_STATUS_SUCCESS - NDIS_STATUS_RESOURCES - -Note: - Initialize all receive releated private buffer, include those define - in RTMP_ADAPTER structure and all private data structures. The mahor - work is to allocate buffer for each packet and chain buffer to - NDIS packet descriptor. -======================================================================== -*/ -NDIS_STATUS NICInitRecv( - IN PRTMP_ADAPTER pAd) -{ - UCHAR i; - NDIS_STATUS Status = NDIS_STATUS_SUCCESS; - POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie; - - - DBGPRINT(RT_DEBUG_TRACE, ("--> NICInitRecv\n")); - pObj = pObj; - - //InterlockedExchange(&pAd->PendingRx, 0); - pAd->PendingRx = 0; - pAd->NextRxBulkInReadIndex = 0; // Next Rx Read index - pAd->NextRxBulkInIndex = 0 ; //RX_RING_SIZE -1; // Rx Bulk pointer - pAd->NextRxBulkInPosition = 0; - - for (i = 0; i < (RX_RING_SIZE); i++) - { - PRX_CONTEXT pRxContext = &(pAd->RxContext[i]); - - //Allocate URB - pRxContext->pUrb = RTUSB_ALLOC_URB(0); - if (pRxContext->pUrb == NULL) - { - Status = NDIS_STATUS_RESOURCES; - goto out1; - } - - // Allocate transfer buffer - pRxContext->TransferBuffer = RTUSB_URB_ALLOC_BUFFER(pObj->pUsb_Dev, MAX_RXBULK_SIZE, &pRxContext->data_dma); - if (pRxContext->TransferBuffer == NULL) - { - Status = NDIS_STATUS_RESOURCES; - goto out1; - } - - NdisZeroMemory(pRxContext->TransferBuffer, MAX_RXBULK_SIZE); - - pRxContext->pAd = pAd; - pRxContext->pIrp = NULL; - pRxContext->InUse = FALSE; - pRxContext->IRPPending = FALSE; - pRxContext->Readable = FALSE; - //pRxContext->ReorderInUse = FALSE; - pRxContext->bRxHandling = FALSE; - pRxContext->BulkInOffset = 0; - } - - DBGPRINT(RT_DEBUG_TRACE, ("<-- NICInitRecv\n")); - return Status; - -out1: - for (i = 0; i < (RX_RING_SIZE); i++) - { - PRX_CONTEXT pRxContext = &(pAd->RxContext[i]); - - if (NULL != pRxContext->TransferBuffer) - { - RTUSB_URB_FREE_BUFFER(pObj->pUsb_Dev, MAX_RXBULK_SIZE, - pRxContext->TransferBuffer, pRxContext->data_dma); - pRxContext->TransferBuffer = NULL; - } - - if (NULL != pRxContext->pUrb) - { - RTUSB_UNLINK_URB(pRxContext->pUrb); - RTUSB_FREE_URB(pRxContext->pUrb); - pRxContext->pUrb = NULL; - } - } - - return Status; -} - - -/* -======================================================================== -Routine Description: - Initialize transmit data structures. - -Arguments: - pAd Pointer to our adapter - -Return Value: - NDIS_STATUS_SUCCESS - NDIS_STATUS_RESOURCES - -Note: -======================================================================== -*/ -NDIS_STATUS NICInitTransmit( - IN PRTMP_ADAPTER pAd) -{ -#define LM_USB_ALLOC(pObj, Context, TB_Type, BufferSize, Status, msg1, err1, msg2, err2) \ - Context->pUrb = RTUSB_ALLOC_URB(0); \ - if (Context->pUrb == NULL) { \ - DBGPRINT(RT_DEBUG_ERROR, msg1); \ - Status = NDIS_STATUS_RESOURCES; \ - goto err1; } \ - \ - Context->TransferBuffer = \ - (TB_Type)RTUSB_URB_ALLOC_BUFFER(pObj->pUsb_Dev, BufferSize, &Context->data_dma); \ - if (Context->TransferBuffer == NULL) { \ - DBGPRINT(RT_DEBUG_ERROR, msg2); \ - Status = NDIS_STATUS_RESOURCES; \ - goto err2; } - -#define LM_URB_FREE(pObj, Context, BufferSize) \ - if (NULL != Context->pUrb) { \ - RTUSB_UNLINK_URB(Context->pUrb); \ - RTUSB_FREE_URB(Context->pUrb); \ - Context->pUrb = NULL; } \ - if (NULL != Context->TransferBuffer) { \ - RTUSB_URB_FREE_BUFFER(pObj->pUsb_Dev, BufferSize, \ - Context->TransferBuffer, \ - Context->data_dma); \ - Context->TransferBuffer = NULL; } - - UCHAR i, acidx; - NDIS_STATUS Status = NDIS_STATUS_SUCCESS; - PTX_CONTEXT pNullContext = &(pAd->NullContext); - PTX_CONTEXT pPsPollContext = &(pAd->PsPollContext); - PTX_CONTEXT pRTSContext = &(pAd->RTSContext); - PTX_CONTEXT pMLMEContext = NULL; -// PHT_TX_CONTEXT pHTTXContext = NULL; - POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie; - PVOID RingBaseVa; -// RTMP_TX_RING *pTxRing; - RTMP_MGMT_RING *pMgmtRing; - - DBGPRINT(RT_DEBUG_TRACE, ("--> NICInitTransmit\n")); - pObj = pObj; - - // Init 4 set of Tx parameters - for(acidx = 0; acidx < NUM_OF_TX_RING; acidx++) - { - // Initialize all Transmit releated queues - InitializeQueueHeader(&pAd->TxSwQueue[acidx]); - - // Next Local tx ring pointer waiting for buck out - pAd->NextBulkOutIndex[acidx] = acidx; - pAd->BulkOutPending[acidx] = FALSE; // Buck Out control flag - //pAd->DataBulkDoneIdx[acidx] = 0; - } - - //pAd->NextMLMEIndex = 0; - //pAd->PushMgmtIndex = 0; - //pAd->PopMgmtIndex = 0; - //InterlockedExchange(&pAd->MgmtQueueSize, 0); - //InterlockedExchange(&pAd->TxCount, 0); - - //pAd->PrioRingFirstIndex = 0; - //pAd->PrioRingTxCnt = 0; - - do - { - // - // TX_RING_SIZE, 4 ACs - // -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - for(acidx=0; acidx<4; acidx++) -#endif // CONFIG_STA_SUPPORT // - { -#if 1 //def DOT11_N_SUPPORT - PHT_TX_CONTEXT pHTTXContext = &(pAd->TxContext[acidx]); - - NdisZeroMemory(pHTTXContext, sizeof(HT_TX_CONTEXT)); - //Allocate URB - LM_USB_ALLOC(pObj, pHTTXContext, PHTTX_BUFFER, sizeof(HTTX_BUFFER), Status, - ("<-- ERROR in Alloc TX TxContext[%d] urb!! \n", acidx), - done, - ("<-- ERROR in Alloc TX TxContext[%d] HTTX_BUFFER !! \n", acidx), - out1); - - NdisZeroMemory(pHTTXContext->TransferBuffer->Aggregation, 4); - pHTTXContext->pAd = pAd; - pHTTXContext->pIrp = NULL; - pHTTXContext->IRPPending = FALSE; - pHTTXContext->NextBulkOutPosition = 0; - pHTTXContext->ENextBulkOutPosition = 0; - pHTTXContext->CurWritePosition = 0; - pHTTXContext->CurWriteRealPos = 0; - pHTTXContext->BulkOutSize = 0; - pHTTXContext->BulkOutPipeId = acidx; - pHTTXContext->bRingEmpty = TRUE; - pHTTXContext->bCopySavePad = FALSE; -#endif // DOT11_N_SUPPORT // - pAd->BulkOutPending[acidx] = FALSE; - } - - - // - // MGMT_RING_SIZE - // - // Allocate MGMT ring descriptor's memory - pAd->MgmtDescRing.AllocSize = MGMT_RING_SIZE * sizeof(TX_CONTEXT); - RTMPAllocateMemory(&pAd->MgmtDescRing.AllocVa, pAd->MgmtDescRing.AllocSize); - if (pAd->MgmtDescRing.AllocVa == NULL) - { - DBGPRINT_ERR(("Failed to allocate a big buffer for MgmtDescRing!\n")); - Status = NDIS_STATUS_RESOURCES; - goto out1; - } - NdisZeroMemory(pAd->MgmtDescRing.AllocVa, pAd->MgmtDescRing.AllocSize); - RingBaseVa = pAd->MgmtDescRing.AllocVa; - - // Initialize MGMT Ring and associated buffer memory - pMgmtRing = &pAd->MgmtRing; - for (i = 0; i < MGMT_RING_SIZE; i++) - { - // link the pre-allocated Mgmt buffer to MgmtRing.Cell - pMgmtRing->Cell[i].AllocSize = sizeof(TX_CONTEXT); - pMgmtRing->Cell[i].AllocVa = RingBaseVa; - pMgmtRing->Cell[i].pNdisPacket = NULL; - pMgmtRing->Cell[i].pNextNdisPacket = NULL; - - //Allocate URB for MLMEContext - pMLMEContext = (PTX_CONTEXT) pAd->MgmtRing.Cell[i].AllocVa; - pMLMEContext->pUrb = RTUSB_ALLOC_URB(0); - if (pMLMEContext->pUrb == NULL) - { - DBGPRINT(RT_DEBUG_ERROR, ("<-- ERROR in Alloc TX MLMEContext[%d] urb!! \n", i)); - Status = NDIS_STATUS_RESOURCES; - goto out2; - } - pMLMEContext->pAd = pAd; - pMLMEContext->pIrp = NULL; - pMLMEContext->TransferBuffer = NULL; - pMLMEContext->InUse = FALSE; - pMLMEContext->IRPPending = FALSE; - pMLMEContext->bWaitingBulkOut = FALSE; - pMLMEContext->BulkOutSize = 0; - pMLMEContext->SelfIdx = i; - - // Offset to next ring descriptor address - RingBaseVa = (PUCHAR) RingBaseVa + sizeof(TX_CONTEXT); - } - DBGPRINT(RT_DEBUG_TRACE, ("MGMT Ring: total %d entry allocated\n", i)); - - //pAd->MgmtRing.TxSwFreeIdx = (MGMT_RING_SIZE - 1); - pAd->MgmtRing.TxSwFreeIdx = MGMT_RING_SIZE; - pAd->MgmtRing.TxCpuIdx = 0; - pAd->MgmtRing.TxDmaIdx = 0; - - // - // BEACON_RING_SIZE - // - for(i=0; iBeaconContext[i]); - - - NdisZeroMemory(pBeaconContext, sizeof(TX_CONTEXT)); - - //Allocate URB - LM_USB_ALLOC(pObj, pBeaconContext, PTX_BUFFER, sizeof(TX_BUFFER), Status, - ("<-- ERROR in Alloc TX BeaconContext[%d] urb!! \n", i), - out2, - ("<-- ERROR in Alloc TX BeaconContext[%d] TX_BUFFER !! \n", i), - out3); - - pBeaconContext->pAd = pAd; - pBeaconContext->pIrp = NULL; - pBeaconContext->InUse = FALSE; - pBeaconContext->IRPPending = FALSE; - } - - // - // NullContext - // - NdisZeroMemory(pNullContext, sizeof(TX_CONTEXT)); - - //Allocate URB - LM_USB_ALLOC(pObj, pNullContext, PTX_BUFFER, sizeof(TX_BUFFER), Status, - ("<-- ERROR in Alloc TX NullContext urb!! \n"), - out3, - ("<-- ERROR in Alloc TX NullContext TX_BUFFER !! \n"), - out4); - - pNullContext->pAd = pAd; - pNullContext->pIrp = NULL; - pNullContext->InUse = FALSE; - pNullContext->IRPPending = FALSE; - - // - // RTSContext - // - NdisZeroMemory(pRTSContext, sizeof(TX_CONTEXT)); - - //Allocate URB - LM_USB_ALLOC(pObj, pRTSContext, PTX_BUFFER, sizeof(TX_BUFFER), Status, - ("<-- ERROR in Alloc TX RTSContext urb!! \n"), - out4, - ("<-- ERROR in Alloc TX RTSContext TX_BUFFER !! \n"), - out5); - - pRTSContext->pAd = pAd; - pRTSContext->pIrp = NULL; - pRTSContext->InUse = FALSE; - pRTSContext->IRPPending = FALSE; - - // - // PsPollContext - // - //NdisZeroMemory(pPsPollContext, sizeof(TX_CONTEXT)); - //Allocate URB - LM_USB_ALLOC(pObj, pPsPollContext, PTX_BUFFER, sizeof(TX_BUFFER), Status, - ("<-- ERROR in Alloc TX PsPollContext urb!! \n"), - out5, - ("<-- ERROR in Alloc TX PsPollContext TX_BUFFER !! \n"), - out6); - - pPsPollContext->pAd = pAd; - pPsPollContext->pIrp = NULL; - pPsPollContext->InUse = FALSE; - pPsPollContext->IRPPending = FALSE; - pPsPollContext->bAggregatible = FALSE; - pPsPollContext->LastOne = TRUE; - - } while (FALSE); - - -done: - DBGPRINT(RT_DEBUG_TRACE, ("<-- NICInitTransmit\n")); - - return Status; - - /* --------------------------- ERROR HANDLE --------------------------- */ -out6: - LM_URB_FREE(pObj, pPsPollContext, sizeof(TX_BUFFER)); - -out5: - LM_URB_FREE(pObj, pRTSContext, sizeof(TX_BUFFER)); - -out4: - LM_URB_FREE(pObj, pNullContext, sizeof(TX_BUFFER)); - -out3: - for(i=0; iBeaconContext[i]); - if (pBeaconContext) - LM_URB_FREE(pObj, pBeaconContext, sizeof(TX_BUFFER)); - } - -out2: - if (pAd->MgmtDescRing.AllocVa) - { - pMgmtRing = &pAd->MgmtRing; - for(i=0; iMgmtRing.Cell[i].AllocVa; - if (pMLMEContext) - LM_URB_FREE(pObj, pMLMEContext, sizeof(TX_BUFFER)); - } - NdisFreeMemory(pAd->MgmtDescRing.AllocVa, pAd->MgmtDescRing.AllocSize, 0); - pAd->MgmtDescRing.AllocVa = NULL; - } - -out1: -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - for(acidx=0; acidx<4; acidx++) -#endif // CONFIG_STA_SUPPORT // - { - PHT_TX_CONTEXT pTxContext = &(pAd->TxContext[acidx]); - if (pTxContext) - LM_URB_FREE(pObj, pTxContext, sizeof(HTTX_BUFFER)); - } - - // Here we didn't have any pre-allocated memory need to free. - - return Status; -} - - -/* -======================================================================== -Routine Description: - Allocate DMA memory blocks for send, receive. - -Arguments: - pAd Pointer to our adapter - -Return Value: - NDIS_STATUS_SUCCESS - NDIS_STATUS_FAILURE - NDIS_STATUS_RESOURCES - -Note: -======================================================================== -*/ -NDIS_STATUS RTMPAllocTxRxRingMemory( - IN PRTMP_ADAPTER pAd) -{ -// COUNTER_802_11 pCounter = &pAd->WlanCounters; - NDIS_STATUS Status; - INT num; - - - DBGPRINT(RT_DEBUG_TRACE, ("--> RTMPAllocTxRxRingMemory\n")); - - - do - { - // Init the CmdQ and CmdQLock - NdisAllocateSpinLock(&pAd->CmdQLock); - NdisAcquireSpinLock(&pAd->CmdQLock); - RTUSBInitializeCmdQ(&pAd->CmdQ); - NdisReleaseSpinLock(&pAd->CmdQLock); - - - NdisAllocateSpinLock(&pAd->MLMEBulkOutLock); - //NdisAllocateSpinLock(&pAd->MLMEWaitQueueLock); - NdisAllocateSpinLock(&pAd->BulkOutLock[0]); - NdisAllocateSpinLock(&pAd->BulkOutLock[1]); - NdisAllocateSpinLock(&pAd->BulkOutLock[2]); - NdisAllocateSpinLock(&pAd->BulkOutLock[3]); - NdisAllocateSpinLock(&pAd->BulkOutLock[4]); - NdisAllocateSpinLock(&pAd->BulkOutLock[5]); - NdisAllocateSpinLock(&pAd->BulkInLock); - - for (num = 0; num < NUM_OF_TX_RING; num++) - { - NdisAllocateSpinLock(&pAd->TxContextQueueLock[num]); - } - -#ifdef RALINK_ATE - NdisAllocateSpinLock(&pAd->GenericLock); -#endif // RALINK_ATE // - -// NdisAllocateSpinLock(&pAd->MemLock); // Not used in RT28XX - -// NdisAllocateSpinLock(&pAd->MacTabLock); // init it in UserCfgInit() -// NdisAllocateSpinLock(&pAd->BATabLock); // init it in BATableInit() - -// for(num=0; numBATable.BARecEntry[num].RxReRingLock); -// } - - // - // Init Mac Table - // -// MacTableInitialize(pAd); - - // - // Init send data structures and related parameters - // - Status = NICInitTransmit(pAd); - if (Status != NDIS_STATUS_SUCCESS) - break; - - // - // Init receive data structures and related parameters - // - Status = NICInitRecv(pAd); - if (Status != NDIS_STATUS_SUCCESS) - break; - - pAd->PendingIoCount = 1; - - } while (FALSE); - - NdisZeroMemory(&pAd->FragFrame, sizeof(FRAGMENT_FRAME)); - pAd->FragFrame.pFragPacket = RTMP_AllocateFragPacketBuffer(pAd, RX_BUFFER_NORMSIZE); - - if (pAd->FragFrame.pFragPacket == NULL) - { - Status = NDIS_STATUS_RESOURCES; - } - - DBGPRINT_S(Status, ("<-- RTMPAllocTxRxRingMemory, Status=%x\n", Status)); - return Status; -} - - -/* -======================================================================== -Routine Description: - Calls USB_InterfaceStop and frees memory allocated for the URBs - calls NdisMDeregisterDevice and frees the memory - allocated in VNetInitialize for the Adapter Object - -Arguments: - *pAd the raxx interface data pointer - -Return Value: - None - -Note: -======================================================================== -*/ -VOID RTMPFreeTxRxRingMemory( - IN PRTMP_ADAPTER pAd) -{ -#define LM_URB_FREE(pObj, Context, BufferSize) \ - if (NULL != Context->pUrb) { \ - RTUSB_UNLINK_URB(Context->pUrb); \ - RTUSB_FREE_URB(Context->pUrb); \ - Context->pUrb = NULL; } \ - if (NULL != Context->TransferBuffer) { \ - RTUSB_URB_FREE_BUFFER(pObj->pUsb_Dev, BufferSize, \ - Context->TransferBuffer, \ - Context->data_dma); \ - Context->TransferBuffer = NULL; } - - - UINT i, acidx; - PTX_CONTEXT pNullContext = &pAd->NullContext; - PTX_CONTEXT pPsPollContext = &pAd->PsPollContext; - PTX_CONTEXT pRTSContext = &pAd->RTSContext; -// PHT_TX_CONTEXT pHTTXContext; - //PRTMP_REORDERBUF pReorderBuf; - POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie; -// RTMP_TX_RING *pTxRing; - - DBGPRINT(RT_DEBUG_ERROR, ("---> RTMPFreeTxRxRingMemory\n")); - pObj = pObj; - - // Free all resources for the RECEIVE buffer queue. - for(i=0; i<(RX_RING_SIZE); i++) - { - PRX_CONTEXT pRxContext = &(pAd->RxContext[i]); - if (pRxContext) - LM_URB_FREE(pObj, pRxContext, MAX_RXBULK_SIZE); - } - - // Free PsPoll frame resource - LM_URB_FREE(pObj, pPsPollContext, sizeof(TX_BUFFER)); - - // Free NULL frame resource - LM_URB_FREE(pObj, pNullContext, sizeof(TX_BUFFER)); - - // Free RTS frame resource - LM_URB_FREE(pObj, pRTSContext, sizeof(TX_BUFFER)); - - - // Free beacon frame resource - for(i=0; iBeaconContext[i]); - if (pBeaconContext) - LM_URB_FREE(pObj, pBeaconContext, sizeof(TX_BUFFER)); - } - - - // Free mgmt frame resource - for(i = 0; i < MGMT_RING_SIZE; i++) - { - PTX_CONTEXT pMLMEContext = (PTX_CONTEXT)pAd->MgmtRing.Cell[i].AllocVa; - //LM_URB_FREE(pObj, pMLMEContext, sizeof(TX_BUFFER)); - if (NULL != pAd->MgmtRing.Cell[i].pNdisPacket) - { - RTMPFreeNdisPacket(pAd, pAd->MgmtRing.Cell[i].pNdisPacket); - pAd->MgmtRing.Cell[i].pNdisPacket = NULL; - pMLMEContext->TransferBuffer = NULL; - } - - if (pMLMEContext) - { - if (NULL != pMLMEContext->pUrb) - { - RTUSB_UNLINK_URB(pMLMEContext->pUrb); - RTUSB_FREE_URB(pMLMEContext->pUrb); - pMLMEContext->pUrb = NULL; - } - } - } - if (pAd->MgmtDescRing.AllocVa) - NdisFreeMemory(pAd->MgmtDescRing.AllocVa, pAd->MgmtDescRing.AllocSize, 0); - - - // Free Tx frame resource -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - for(acidx=0; acidx<4; acidx++) -#endif // CONFIG_STA_SUPPORT // - { - PHT_TX_CONTEXT pHTTXContext = &(pAd->TxContext[acidx]); - if (pHTTXContext) - LM_URB_FREE(pObj, pHTTXContext, sizeof(HTTX_BUFFER)); - } - - if (pAd->FragFrame.pFragPacket) - RELEASE_NDIS_PACKET(pAd, pAd->FragFrame.pFragPacket, NDIS_STATUS_SUCCESS); - - for(i=0; i<6; i++) - { - NdisFreeSpinLock(&pAd->BulkOutLock[i]); - } - - NdisFreeSpinLock(&pAd->BulkInLock); - NdisFreeSpinLock(&pAd->MLMEBulkOutLock); - - NdisFreeSpinLock(&pAd->CmdQLock); -#ifdef RALINK_ATE - NdisFreeSpinLock(&pAd->GenericLock); -#endif // RALINK_ATE // - // Clear all pending bulk-out request flags. - RTUSB_CLEAR_BULK_FLAG(pAd, 0xffffffff); - -// NdisFreeSpinLock(&pAd->MacTabLock); - -// for(i=0; iBATable.BARecEntry[i].RxReRingLock); -// } - - DBGPRINT(RT_DEBUG_ERROR, ("<--- ReleaseAdapter\n")); -} - - -/* -======================================================================== -Routine Description: - Allocate memory for adapter control block. - -Arguments: - pAd Pointer to our adapter - -Return Value: - NDIS_STATUS_SUCCESS - NDIS_STATUS_FAILURE - NDIS_STATUS_RESOURCES - -Note: -======================================================================== -*/ -NDIS_STATUS AdapterBlockAllocateMemory( - IN PVOID handle, - OUT PVOID *ppAd) -{ - PUSB_DEV usb_dev; - POS_COOKIE pObj = (POS_COOKIE) handle; - - - usb_dev = pObj->pUsb_Dev; - - pObj->MLMEThr_pid = NULL; - pObj->RTUSBCmdThr_pid = NULL; - - *ppAd = (PVOID)vmalloc(sizeof(RTMP_ADAPTER)); - - if (*ppAd) - { - NdisZeroMemory(*ppAd, sizeof(RTMP_ADAPTER)); - ((PRTMP_ADAPTER)*ppAd)->OS_Cookie = handle; - return (NDIS_STATUS_SUCCESS); - } - else - { - return (NDIS_STATUS_FAILURE); - } -} - - -/* -======================================================================== -Routine Description: - Create kernel threads & tasklets. - -Arguments: - *net_dev Pointer to wireless net device interface - -Return Value: - NDIS_STATUS_SUCCESS - NDIS_STATUS_FAILURE - -Note: -======================================================================== -*/ -NDIS_STATUS CreateThreads( - IN struct net_device *net_dev) -{ - PRTMP_ADAPTER pAd = net_dev->ml_priv; - POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie; - pid_t pid_number; - - //init_MUTEX(&(pAd->usbdev_semaphore)); - - init_MUTEX_LOCKED(&(pAd->mlme_semaphore)); - init_completion (&pAd->mlmeComplete); - - init_MUTEX_LOCKED(&(pAd->RTUSBCmd_semaphore)); - init_completion (&pAd->CmdQComplete); - - init_MUTEX_LOCKED(&(pAd->RTUSBTimer_semaphore)); - init_completion (&pAd->TimerQComplete); - - // Creat MLME Thread - pObj->MLMEThr_pid = NULL; - pid_number = kernel_thread(MlmeThread, pAd, CLONE_VM); - if (pid_number < 0) - { - printk (KERN_WARNING "%s: unable to start Mlme thread\n",pAd->net_dev->name); - return NDIS_STATUS_FAILURE; - } - pObj->MLMEThr_pid = find_get_pid(pid_number); - // Wait for the thread to start - wait_for_completion(&(pAd->mlmeComplete)); - - // Creat Command Thread - pObj->RTUSBCmdThr_pid = NULL; - pid_number = kernel_thread(RTUSBCmdThread, pAd, CLONE_VM); - if (pid_number < 0) - { - printk (KERN_WARNING "%s: unable to start RTUSBCmd thread\n",pAd->net_dev->name); - return NDIS_STATUS_FAILURE; - } - pObj->RTUSBCmdThr_pid = find_get_pid(pid_number); - wait_for_completion(&(pAd->CmdQComplete)); - - pObj->TimerQThr_pid = NULL; - pid_number = kernel_thread(TimerQThread, pAd, CLONE_VM); - if (pid_number < 0) - { - printk (KERN_WARNING "%s: unable to start TimerQThread\n",pAd->net_dev->name); - return NDIS_STATUS_FAILURE; - } - pObj->TimerQThr_pid = find_get_pid(pid_number); - // Wait for the thread to start - wait_for_completion(&(pAd->TimerQComplete)); - - // Create receive tasklet - tasklet_init(&pObj->rx_done_task, rx_done_tasklet, (ULONG)pAd); - tasklet_init(&pObj->mgmt_dma_done_task, rt2870_mgmt_dma_done_tasklet, (unsigned long)pAd); - tasklet_init(&pObj->ac0_dma_done_task, rt2870_ac0_dma_done_tasklet, (unsigned long)pAd); - tasklet_init(&pObj->ac1_dma_done_task, rt2870_ac1_dma_done_tasklet, (unsigned long)pAd); - tasklet_init(&pObj->ac2_dma_done_task, rt2870_ac2_dma_done_tasklet, (unsigned long)pAd); - tasklet_init(&pObj->ac3_dma_done_task, rt2870_ac3_dma_done_tasklet, (unsigned long)pAd); - tasklet_init(&pObj->hcca_dma_done_task, rt2870_hcca_dma_done_tasklet, (unsigned long)pAd); - tasklet_init(&pObj->tbtt_task, tbtt_tasklet, (unsigned long)pAd); - tasklet_init(&pObj->null_frame_complete_task, rt2870_null_frame_complete_tasklet, (unsigned long)pAd); - tasklet_init(&pObj->rts_frame_complete_task, rt2870_rts_frame_complete_tasklet, (unsigned long)pAd); - tasklet_init(&pObj->pspoll_frame_complete_task, rt2870_pspoll_frame_complete_tasklet, (unsigned long)pAd); - - return NDIS_STATUS_SUCCESS; -} - - -#ifdef CONFIG_STA_SUPPORT -/* -======================================================================== -Routine Description: - As STA's BSSID is a WC too, it uses shared key table. - This function write correct unicast TX key to ASIC WCID. - And we still make a copy in our MacTab.Content[BSSID_WCID].PairwiseKey. - Caller guarantee TKIP/AES always has keyidx = 0. (pairwise key) - Caller guarantee WEP calls this function when set Txkey, default key index=0~3. - -Arguments: - pAd Pointer to our adapter - pKey Pointer to the where the key stored - -Return Value: - NDIS_SUCCESS Add key successfully - -Note: -======================================================================== -*/ -VOID RTMPAddBSSIDCipher( - IN PRTMP_ADAPTER pAd, - IN UCHAR Aid, - IN PNDIS_802_11_KEY pKey, - IN UCHAR CipherAlg) -{ - PUCHAR pTxMic, pRxMic; - BOOLEAN bKeyRSC, bAuthenticator; // indicate the receive SC set by KeyRSC value -// UCHAR CipherAlg; - UCHAR i; - ULONG WCIDAttri; - USHORT offset; - UCHAR KeyIdx, IVEIV[8]; - UINT32 Value; - - DBGPRINT(RT_DEBUG_TRACE, ("RTMPAddBSSIDCipher==> Aid = %d\n",Aid)); - - // Bit 29 of Add-key KeyRSC - bKeyRSC = (pKey->KeyIndex & 0x20000000) ? TRUE : FALSE; - - // Bit 28 of Add-key Authenticator - bAuthenticator = (pKey->KeyIndex & 0x10000000) ? TRUE : FALSE; - KeyIdx = (UCHAR)pKey->KeyIndex&0xff; - - if (KeyIdx > 4) - return; - - - if (pAd->MacTab.Content[Aid].PairwiseKey.CipherAlg == CIPHER_TKIP) - { if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) - { - // for WPA-None Tx, Rx MIC is the same - pTxMic = (PUCHAR) (&pKey->KeyMaterial) + 16; - pRxMic = pTxMic; - } - else if (bAuthenticator == TRUE) - { - pTxMic = (PUCHAR) (&pKey->KeyMaterial) + 16; - pRxMic = (PUCHAR) (&pKey->KeyMaterial) + 24; - } - else - { - pRxMic = (PUCHAR) (&pKey->KeyMaterial) + 16; - pTxMic = (PUCHAR) (&pKey->KeyMaterial) + 24; - } - - offset = PAIRWISE_KEY_TABLE_BASE + (Aid * HW_KEY_ENTRY_SIZE) + 0x10; - for (i=0; i<8; ) - { - Value = *(pTxMic+i); - Value += (*(pTxMic+i+1)<<8); - Value += (*(pTxMic+i+2)<<16); - Value += (*(pTxMic+i+3)<<24); - RTUSBWriteMACRegister(pAd, offset+i, Value); - i+=4; - } - - offset = PAIRWISE_KEY_TABLE_BASE + (Aid * HW_KEY_ENTRY_SIZE) + 0x18; - for (i=0; i<8; ) - { - Value = *(pRxMic+i); - Value += (*(pRxMic+i+1)<<8); - Value += (*(pRxMic+i+2)<<16); - Value += (*(pRxMic+i+3)<<24); - RTUSBWriteMACRegister(pAd, offset+i, Value); - i+=4; - } - - // Only Key lenth equal to TKIP key have these - NdisMoveMemory(pAd->MacTab.Content[Aid].PairwiseKey.RxMic, pRxMic, 8); - NdisMoveMemory(pAd->MacTab.Content[Aid].PairwiseKey.TxMic, pTxMic, 8); - - DBGPRINT(RT_DEBUG_TRACE, - (" TxMIC = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x \n", - pTxMic[0],pTxMic[1],pTxMic[2],pTxMic[3], - pTxMic[4],pTxMic[5],pTxMic[6],pTxMic[7])); - DBGPRINT(RT_DEBUG_TRACE, - (" RxMIC = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x \n", - pRxMic[0],pRxMic[1],pRxMic[2],pRxMic[3], - pRxMic[4],pRxMic[5],pRxMic[6],pRxMic[7])); - } - - // 2. Record Security Key. - pAd->MacTab.Content[BSSID_WCID].PairwiseKey.KeyLen= (UCHAR)pKey->KeyLength; - NdisMoveMemory(pAd->MacTab.Content[Aid].PairwiseKey.Key, &pKey->KeyMaterial, pKey->KeyLength); - - // 3. Check RxTsc. And used to init to ASIC IV. - if (bKeyRSC == TRUE) - NdisMoveMemory(pAd->MacTab.Content[Aid].PairwiseKey.RxTsc, &pKey->KeyRSC, 6); - else - NdisZeroMemory(pAd->MacTab.Content[Aid].PairwiseKey.RxTsc, 6); - - // 4. Init TxTsc to one based on WiFi WPA specs - pAd->MacTab.Content[Aid].PairwiseKey.TxTsc[0] = 1; - pAd->MacTab.Content[Aid].PairwiseKey.TxTsc[1] = 0; - pAd->MacTab.Content[Aid].PairwiseKey.TxTsc[2] = 0; - pAd->MacTab.Content[Aid].PairwiseKey.TxTsc[3] = 0; - pAd->MacTab.Content[Aid].PairwiseKey.TxTsc[4] = 0; - pAd->MacTab.Content[Aid].PairwiseKey.TxTsc[5] = 0; - - CipherAlg = pAd->MacTab.Content[Aid].PairwiseKey.CipherAlg; - - offset = PAIRWISE_KEY_TABLE_BASE + (Aid * HW_KEY_ENTRY_SIZE); - RTUSBMultiWrite(pAd, (USHORT) offset, pKey->KeyMaterial, - ((pKey->KeyLength == LEN_TKIP_KEY) ? 16 : (USHORT)pKey->KeyLength)); - - offset = SHARED_KEY_TABLE_BASE + (KeyIdx * HW_KEY_ENTRY_SIZE); - RTUSBMultiWrite(pAd, (USHORT) offset, pKey->KeyMaterial, (USHORT)pKey->KeyLength); - - offset = PAIRWISE_IVEIV_TABLE_BASE + (Aid * HW_IVEIV_ENTRY_SIZE); - NdisZeroMemory(IVEIV, 8); - - // IV/EIV - if ((CipherAlg == CIPHER_TKIP) || - (CipherAlg == CIPHER_TKIP_NO_MIC) || - (CipherAlg == CIPHER_AES)) - { - IVEIV[3] = 0x20; // Eiv bit on. keyid always 0 for pairwise key - } - // default key idx needs to set. - // in TKIP/AES KeyIdx = 0 , WEP KeyIdx is default tx key. - else - { - IVEIV[3] |= (KeyIdx<< 6); - } - RTUSBMultiWrite(pAd, (USHORT) offset, IVEIV, 8); - - // WCID Attribute UDF:3, BSSIdx:3, Alg:3, Keytable:1=PAIRWISE KEY, BSSIdx is 0 - if ((CipherAlg == CIPHER_TKIP) || - (CipherAlg == CIPHER_TKIP_NO_MIC) || - (CipherAlg == CIPHER_AES)) - { - WCIDAttri = (CipherAlg<<1)|SHAREDKEYTABLE; - } - else - WCIDAttri = (CipherAlg<<1)|SHAREDKEYTABLE; - - offset = MAC_WCID_ATTRIBUTE_BASE + (Aid* HW_WCID_ATTRI_SIZE); - RTUSBWriteMACRegister(pAd, offset, WCIDAttri); - RTUSBReadMACRegister(pAd, offset, &Value); - - DBGPRINT(RT_DEBUG_TRACE, ("BSSID_WCID : offset = %x, WCIDAttri = %lx\n", - offset, WCIDAttri)); - - // pAddr - // Add Bssid mac address at linkup. not here. check! - /*offset = MAC_WCID_BASE + (BSSID_WCID * HW_WCID_ENTRY_SIZE); - *for (i=0; iBSSID[i]); - } - */ - - DBGPRINT(RT_DEBUG_ERROR, ("AddBSSIDasWCIDEntry: Alg=%s, KeyLength = %d\n", - CipherName[CipherAlg], pKey->KeyLength)); - DBGPRINT(RT_DEBUG_TRACE, ("Key [idx=%x] [KeyLen = %d]\n", - pKey->KeyIndex, pKey->KeyLength)); - for(i=0; iKeyLength; i++) - DBGPRINT_RAW(RT_DEBUG_TRACE,(" %x:", pKey->KeyMaterial[i])); - DBGPRINT(RT_DEBUG_TRACE,(" \n")); -} -#endif // CONFIG_STA_SUPPORT // - -/* -======================================================================== -Routine Description: - Get a received packet. - -Arguments: - pAd device control block - pSaveRxD receive descriptor information - *pbReschedule need reschedule flag - *pRxPending pending received packet flag - -Return Value: - the recieved packet - -Note: -======================================================================== -*/ -#define RT2870_RXDMALEN_FIELD_SIZE 4 -PNDIS_PACKET GetPacketFromRxRing( - IN PRTMP_ADAPTER pAd, - OUT PRT28XX_RXD_STRUC pSaveRxD, - OUT BOOLEAN *pbReschedule, - IN OUT UINT32 *pRxPending) -{ - PRX_CONTEXT pRxContext; - PNDIS_PACKET pSkb; - PUCHAR pData; - ULONG ThisFrameLen; - ULONG RxBufferLength; - PRXWI_STRUC pRxWI; - - pRxContext = &pAd->RxContext[pAd->NextRxBulkInReadIndex]; - if ((pRxContext->Readable == FALSE) || (pRxContext->InUse == TRUE)) - return NULL; - - RxBufferLength = pRxContext->BulkInOffset - pAd->ReadPosition; - if (RxBufferLength < (RT2870_RXDMALEN_FIELD_SIZE + sizeof(RXWI_STRUC) + sizeof(RXINFO_STRUC))) - { - goto label_null; - } - - pData = &pRxContext->TransferBuffer[pAd->ReadPosition]; /* 4KB */ - // The RXDMA field is 4 bytes, now just use the first 2 bytes. The Length including the (RXWI + MSDU + Padding) - ThisFrameLen = *pData + (*(pData+1)<<8); - if (ThisFrameLen == 0) - { - DBGPRINT(RT_DEBUG_TRACE, ("BIRIdx(%d): RXDMALen is zero.[%ld], BulkInBufLen = %ld)\n", - pAd->NextRxBulkInReadIndex, ThisFrameLen, pRxContext->BulkInOffset)); - goto label_null; - } - if ((ThisFrameLen&0x3) != 0) - { - DBGPRINT(RT_DEBUG_ERROR, ("BIRIdx(%d): RXDMALen not multiple of 4.[%ld], BulkInBufLen = %ld)\n", - pAd->NextRxBulkInReadIndex, ThisFrameLen, pRxContext->BulkInOffset)); - goto label_null; - } - - if ((ThisFrameLen + 8)> RxBufferLength) // 8 for (RT2870_RXDMALEN_FIELD_SIZE + sizeof(RXINFO_STRUC)) - { - DBGPRINT(RT_DEBUG_TRACE,("BIRIdx(%d):FrameLen(0x%lx) outranges. BulkInLen=0x%lx, remaining RxBufLen=0x%lx, ReadPos=0x%lx\n", - pAd->NextRxBulkInReadIndex, ThisFrameLen, pRxContext->BulkInOffset, RxBufferLength, pAd->ReadPosition)); - - // error frame. finish this loop - goto label_null; - } - - // skip USB frame length field - pData += RT2870_RXDMALEN_FIELD_SIZE; - pRxWI = (PRXWI_STRUC)pData; -#ifdef RT_BIG_ENDIAN - RTMPWIEndianChange(pData, TYPE_RXWI); -#endif // RT_BIG_ENDIAN // - if (pRxWI->MPDUtotalByteCount > ThisFrameLen) - { - DBGPRINT(RT_DEBUG_ERROR, ("%s():pRxWIMPDUtotalByteCount(%d) large than RxDMALen(%ld)\n", - __FUNCTION__, pRxWI->MPDUtotalByteCount, ThisFrameLen)); - goto label_null; - } -#ifdef RT_BIG_ENDIAN - RTMPWIEndianChange(pData, TYPE_RXWI); -#endif // RT_BIG_ENDIAN // - - // allocate a rx packet - pSkb = dev_alloc_skb(ThisFrameLen); - if (pSkb == NULL) - { - DBGPRINT(RT_DEBUG_ERROR,("%s():Cannot Allocate sk buffer for this Bulk-In buffer!\n", __FUNCTION__)); - goto label_null; - } - - // copy the rx packet - memcpy(skb_put(pSkb, ThisFrameLen), pData, ThisFrameLen); - RTPKT_TO_OSPKT(pSkb)->dev = get_netdev_from_bssid(pAd, BSS0); - RTMP_SET_PACKET_SOURCE(OSPKT_TO_RTPKT(pSkb), PKTSRC_NDIS); - - // copy RxD - *pSaveRxD = *(PRXINFO_STRUC)(pData + ThisFrameLen); -#ifdef RT_BIG_ENDIAN - RTMPDescriptorEndianChange((PUCHAR)pSaveRxD, TYPE_RXINFO); -#endif // RT_BIG_ENDIAN // - - // update next packet read position. - pAd->ReadPosition += (ThisFrameLen + RT2870_RXDMALEN_FIELD_SIZE + RXINFO_SIZE); // 8 for (RT2870_RXDMALEN_FIELD_SIZE + sizeof(RXINFO_STRUC)) - - return pSkb; - -label_null: - - return NULL; -} - - -/* -======================================================================== -Routine Description: - Handle received packets. - -Arguments: - data - URB information pointer - -Return Value: - None - -Note: -======================================================================== -*/ -static void rx_done_tasklet(unsigned long data) -{ - purbb_t pUrb; - PRX_CONTEXT pRxContext; - PRTMP_ADAPTER pAd; - NTSTATUS Status; - unsigned int IrqFlags; - - pUrb = (purbb_t)data; - pRxContext = (PRX_CONTEXT)pUrb->context; - pAd = pRxContext->pAd; - Status = pUrb->status; - - - RTMP_IRQ_LOCK(&pAd->BulkInLock, IrqFlags); - pRxContext->InUse = FALSE; - pRxContext->IRPPending = FALSE; - pRxContext->BulkInOffset += pUrb->actual_length; - //NdisInterlockedDecrement(&pAd->PendingRx); - pAd->PendingRx--; - - if (Status == USB_ST_NOERROR) - { - pAd->BulkInComplete++; - pAd->NextRxBulkInPosition = 0; - if (pRxContext->BulkInOffset) // As jan's comment, it may bulk-in success but size is zero. - { - pRxContext->Readable = TRUE; - INC_RING_INDEX(pAd->NextRxBulkInIndex, RX_RING_SIZE); - } - RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); - } - else // STATUS_OTHER - { - pAd->BulkInCompleteFail++; - // Still read this packet although it may comtain wrong bytes. - pRxContext->Readable = FALSE; - RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); - - // Parsing all packets. because after reset, the index will reset to all zero. - if ((!RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_RESET_IN_PROGRESS | - fRTMP_ADAPTER_BULKIN_RESET | - fRTMP_ADAPTER_HALT_IN_PROGRESS | - fRTMP_ADAPTER_NIC_NOT_EXIST)))) - { - - DBGPRINT_RAW(RT_DEBUG_ERROR, ("Bulk In Failed. Status=%d, BIIdx=0x%x, BIRIdx=0x%x, actual_length= 0x%x\n", - Status, pAd->NextRxBulkInIndex, pAd->NextRxBulkInReadIndex, pRxContext->pUrb->actual_length)); - - RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BULKIN_RESET); - RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_IN, NULL, 0); - } - } - - ASSERT((pRxContext->InUse == pRxContext->IRPPending)); - -#ifdef RALINK_ATE - if (ATE_ON(pAd)) - { - // If the driver is in ATE mode and Rx frame is set into here. - if (pAd->ContinBulkIn == TRUE) - { - RTUSBBulkReceive(pAd); - } - } - else -#endif // RALINK_ATE // - RTUSBBulkReceive(pAd); - - return; - -} - - -static void rt2870_mgmt_dma_done_tasklet(unsigned long data) -{ - PRTMP_ADAPTER pAd; - PTX_CONTEXT pMLMEContext; - int index; - PNDIS_PACKET pPacket; - purbb_t pUrb; - NTSTATUS Status; - unsigned long IrqFlags; - - - pUrb = (purbb_t)data; - pMLMEContext = (PTX_CONTEXT)pUrb->context; - pAd = pMLMEContext->pAd; - Status = pUrb->status; - index = pMLMEContext->SelfIdx; - - ASSERT((pAd->MgmtRing.TxDmaIdx == index)); - - RTMP_IRQ_LOCK(&pAd->BulkOutLock[MGMTPIPEIDX], IrqFlags); - - - if (Status != USB_ST_NOERROR) - { - //Bulk-Out fail status handle - if ((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS)) && - (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) && - (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) && - (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET))) - { - DBGPRINT_RAW(RT_DEBUG_ERROR, ("Bulk Out MLME Failed, Status=%d!\n", Status)); - // TODO: How to handle about the MLMEBulkOut failed issue. Need to resend the mgmt pkt? - RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET); - pAd->bulkResetPipeid = (MGMTPIPEIDX | BULKOUT_MGMT_RESET_FLAG); - } - } - - pAd->BulkOutPending[MGMTPIPEIDX] = FALSE; - RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[MGMTPIPEIDX], IrqFlags); - - RTMP_IRQ_LOCK(&pAd->MLMEBulkOutLock, IrqFlags); - // Reset MLME context flags - pMLMEContext->IRPPending = FALSE; - pMLMEContext->InUse = FALSE; - pMLMEContext->bWaitingBulkOut = FALSE; - pMLMEContext->BulkOutSize = 0; - - pPacket = pAd->MgmtRing.Cell[index].pNdisPacket; - pAd->MgmtRing.Cell[index].pNdisPacket = NULL; - - // Increase MgmtRing Index - INC_RING_INDEX(pAd->MgmtRing.TxDmaIdx, MGMT_RING_SIZE); - pAd->MgmtRing.TxSwFreeIdx++; - RTMP_IRQ_UNLOCK(&pAd->MLMEBulkOutLock, IrqFlags); - - // No-matter success or fail, we free the mgmt packet. - if (pPacket) - RTMPFreeNdisPacket(pAd, pPacket); - - if ((RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_RESET_IN_PROGRESS | - fRTMP_ADAPTER_HALT_IN_PROGRESS | - fRTMP_ADAPTER_NIC_NOT_EXIST)))) - { - // do nothing and return directly. - } - else - { - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET) && - ((pAd->bulkResetPipeid & BULKOUT_MGMT_RESET_FLAG) == BULKOUT_MGMT_RESET_FLAG)) - { // For Mgmt Bulk-Out failed, ignore it now. - RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_OUT, NULL, 0); - } - else - { - - // Always call Bulk routine, even reset bulk. - // The protectioon of rest bulk should be in BulkOut routine - if (pAd->MgmtRing.TxSwFreeIdx < MGMT_RING_SIZE /* pMLMEContext->bWaitingBulkOut == TRUE */) - { - RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_MLME); - } - RTUSBKickBulkOut(pAd); - } - } - -} - - -static void rt2870_hcca_dma_done_tasklet(unsigned long data) -{ - PRTMP_ADAPTER pAd; - PHT_TX_CONTEXT pHTTXContext; - UCHAR BulkOutPipeId = 4; - purbb_t pUrb; - - - pUrb = (purbb_t)data; - pHTTXContext = (PHT_TX_CONTEXT)pUrb->context; - pAd = pHTTXContext->pAd; - - rt2870_dataout_complete_tasklet((unsigned long)pUrb); - - if ((RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_RESET_IN_PROGRESS | - fRTMP_ADAPTER_HALT_IN_PROGRESS | - fRTMP_ADAPTER_NIC_NOT_EXIST)))) - { - // do nothing and return directly. - } - else - { - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET)) - { - RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_OUT, NULL, 0); - } - else - { pHTTXContext = &pAd->TxContext[BulkOutPipeId]; - if ((pAd->TxSwQueue[BulkOutPipeId].Number > 0) && - /*((pHTTXContext->CurWritePosition > (pHTTXContext->NextBulkOutPosition + 0x6000)) || (pHTTXContext->NextBulkOutPosition > pHTTXContext->CurWritePosition + 0x6000)) && */ - (pAd->DeQueueRunning[BulkOutPipeId] == FALSE) && - (pHTTXContext->bCurWriting == FALSE)) - { - RTMPDeQueuePacket(pAd, FALSE, BulkOutPipeId, MAX_TX_PROCESS); - } - - RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NORMAL<<4); - RTUSBKickBulkOut(pAd); - } - } - - - return; -} - - -static void rt2870_ac3_dma_done_tasklet(unsigned long data) -{ - PRTMP_ADAPTER pAd; - PHT_TX_CONTEXT pHTTXContext; - UCHAR BulkOutPipeId = 3; - purbb_t pUrb; - - - pUrb = (purbb_t)data; - pHTTXContext = (PHT_TX_CONTEXT)pUrb->context; - pAd = pHTTXContext->pAd; - - rt2870_dataout_complete_tasklet((unsigned long)pUrb); - - if ((RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_RESET_IN_PROGRESS | - fRTMP_ADAPTER_HALT_IN_PROGRESS | - fRTMP_ADAPTER_NIC_NOT_EXIST)))) - { - // do nothing and return directly. - } - else - { - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET)) - { - RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_OUT, NULL, 0); - } - else - { pHTTXContext = &pAd->TxContext[BulkOutPipeId]; - if ((pAd->TxSwQueue[BulkOutPipeId].Number > 0) && - /*((pHTTXContext->CurWritePosition > (pHTTXContext->NextBulkOutPosition + 0x6000)) || (pHTTXContext->NextBulkOutPosition > pHTTXContext->CurWritePosition + 0x6000)) && */ - (pAd->DeQueueRunning[BulkOutPipeId] == FALSE) && - (pHTTXContext->bCurWriting == FALSE)) - { - RTMPDeQueuePacket(pAd, FALSE, BulkOutPipeId, MAX_TX_PROCESS); - } - - RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NORMAL<<3); - RTUSBKickBulkOut(pAd); - } - } - - - return; -} - - -static void rt2870_ac2_dma_done_tasklet(unsigned long data) -{ - PRTMP_ADAPTER pAd; - PHT_TX_CONTEXT pHTTXContext; - UCHAR BulkOutPipeId = 2; - purbb_t pUrb; - - - pUrb = (purbb_t)data; - pHTTXContext = (PHT_TX_CONTEXT)pUrb->context; - pAd = pHTTXContext->pAd; - - rt2870_dataout_complete_tasklet((unsigned long)pUrb); - - if ((RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_RESET_IN_PROGRESS | - fRTMP_ADAPTER_HALT_IN_PROGRESS | - fRTMP_ADAPTER_NIC_NOT_EXIST)))) - { - // do nothing and return directly. - } - else - { - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET)) - { - RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_OUT, NULL, 0); - } - else - { pHTTXContext = &pAd->TxContext[BulkOutPipeId]; - if ((pAd->TxSwQueue[BulkOutPipeId].Number > 0) && - /*((pHTTXContext->CurWritePosition > (pHTTXContext->NextBulkOutPosition + 0x6000)) || (pHTTXContext->NextBulkOutPosition > pHTTXContext->CurWritePosition + 0x6000)) && */ - (pAd->DeQueueRunning[BulkOutPipeId] == FALSE) && - (pHTTXContext->bCurWriting == FALSE)) - { - RTMPDeQueuePacket(pAd, FALSE, BulkOutPipeId, MAX_TX_PROCESS); - } - - RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NORMAL<<2); - RTUSBKickBulkOut(pAd); - } - } - - return; -} - - -static void rt2870_ac1_dma_done_tasklet(unsigned long data) -{ - PRTMP_ADAPTER pAd; - PHT_TX_CONTEXT pHTTXContext; - UCHAR BulkOutPipeId = 1; - purbb_t pUrb; - - - pUrb = (purbb_t)data; - pHTTXContext = (PHT_TX_CONTEXT)pUrb->context; - pAd = pHTTXContext->pAd; - - rt2870_dataout_complete_tasklet((unsigned long)pUrb); - - if ((RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_RESET_IN_PROGRESS | - fRTMP_ADAPTER_HALT_IN_PROGRESS | - fRTMP_ADAPTER_NIC_NOT_EXIST)))) - { - // do nothing and return directly. - } - else - { - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET)) - { - RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_OUT, NULL, 0); - } - else - { pHTTXContext = &pAd->TxContext[BulkOutPipeId]; - if ((pAd->TxSwQueue[BulkOutPipeId].Number > 0) && - /*((pHTTXContext->CurWritePosition > (pHTTXContext->NextBulkOutPosition + 0x6000)) || (pHTTXContext->NextBulkOutPosition > pHTTXContext->CurWritePosition + 0x6000)) && */ - (pAd->DeQueueRunning[BulkOutPipeId] == FALSE) && - (pHTTXContext->bCurWriting == FALSE)) - { - RTMPDeQueuePacket(pAd, FALSE, BulkOutPipeId, MAX_TX_PROCESS); - } - - RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NORMAL<<1); - RTUSBKickBulkOut(pAd); - } - } - - - return; -} - - -static void rt2870_ac0_dma_done_tasklet(unsigned long data) -{ - PRTMP_ADAPTER pAd; - PHT_TX_CONTEXT pHTTXContext; - UCHAR BulkOutPipeId = 0; - purbb_t pUrb; - - - pUrb = (purbb_t)data; - pHTTXContext = (PHT_TX_CONTEXT)pUrb->context; - pAd = pHTTXContext->pAd; - - rt2870_dataout_complete_tasklet((unsigned long)pUrb); - - if ((RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_RESET_IN_PROGRESS | - fRTMP_ADAPTER_HALT_IN_PROGRESS | - fRTMP_ADAPTER_NIC_NOT_EXIST)))) - { - // do nothing and return directly. - } - else - { - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET)) - { - RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_OUT, NULL, 0); - } - else - { pHTTXContext = &pAd->TxContext[BulkOutPipeId]; - if ((pAd->TxSwQueue[BulkOutPipeId].Number > 0) && - /* ((pHTTXContext->CurWritePosition > (pHTTXContext->NextBulkOutPosition + 0x6000)) || (pHTTXContext->NextBulkOutPosition > pHTTXContext->CurWritePosition + 0x6000)) && */ - (pAd->DeQueueRunning[BulkOutPipeId] == FALSE) && - (pHTTXContext->bCurWriting == FALSE)) - { - RTMPDeQueuePacket(pAd, FALSE, BulkOutPipeId, MAX_TX_PROCESS); - } - - RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NORMAL); - RTUSBKickBulkOut(pAd); - } - } - - - return; - -} - - -static void rt2870_null_frame_complete_tasklet(unsigned long data) -{ - PRTMP_ADAPTER pAd; - PTX_CONTEXT pNullContext; - purbb_t pUrb; - NTSTATUS Status; - unsigned long irqFlag; - - - pUrb = (purbb_t)data; - pNullContext = (PTX_CONTEXT)pUrb->context; - pAd = pNullContext->pAd; - Status = pUrb->status; - - // Reset Null frame context flags - RTMP_IRQ_LOCK(&pAd->BulkOutLock[0], irqFlag); - pNullContext->IRPPending = FALSE; - pNullContext->InUse = FALSE; - pAd->BulkOutPending[0] = FALSE; - pAd->watchDogTxPendingCnt[0] = 0; - - if (Status == USB_ST_NOERROR) - { - RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], irqFlag); - - RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, MAX_TX_PROCESS); - } - else // STATUS_OTHER - { - if ((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS)) && - (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) && - (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) && - (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET))) - { - DBGPRINT_RAW(RT_DEBUG_ERROR, ("Bulk Out Null Frame Failed, ReasonCode=%d!\n", Status)); - RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET); - pAd->bulkResetPipeid = (MGMTPIPEIDX | BULKOUT_MGMT_RESET_FLAG); - RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], irqFlag); - RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_OUT, NULL, 0); - } - else - { - RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], irqFlag); - } - } - - // Always call Bulk routine, even reset bulk. - // The protectioon of rest bulk should be in BulkOut routine - RTUSBKickBulkOut(pAd); - -} - - -static void rt2870_rts_frame_complete_tasklet(unsigned long data) -{ - PRTMP_ADAPTER pAd; - PTX_CONTEXT pRTSContext; - purbb_t pUrb; - NTSTATUS Status; - unsigned long irqFlag; - - - pUrb = (purbb_t)data; - pRTSContext = (PTX_CONTEXT)pUrb->context; - pAd = pRTSContext->pAd; - Status = pUrb->status; - - // Reset RTS frame context flags - RTMP_IRQ_LOCK(&pAd->BulkOutLock[0], irqFlag); - pRTSContext->IRPPending = FALSE; - pRTSContext->InUse = FALSE; - - if (Status == USB_ST_NOERROR) - { - RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], irqFlag); - RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, MAX_TX_PROCESS); - } - else // STATUS_OTHER - { - if ((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS)) && - (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) && - (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) && - (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET))) - { - DBGPRINT_RAW(RT_DEBUG_ERROR, ("Bulk Out RTS Frame Failed\n")); - RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET); - pAd->bulkResetPipeid = (MGMTPIPEIDX | BULKOUT_MGMT_RESET_FLAG); - RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], irqFlag); - RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_OUT, NULL, 0); - } - else - { - RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], irqFlag); - } - } - - RTMP_SEM_LOCK(&pAd->BulkOutLock[pRTSContext->BulkOutPipeId]); - pAd->BulkOutPending[pRTSContext->BulkOutPipeId] = FALSE; - RTMP_SEM_UNLOCK(&pAd->BulkOutLock[pRTSContext->BulkOutPipeId]); - - // Always call Bulk routine, even reset bulk. - // The protectioon of rest bulk should be in BulkOut routine - RTUSBKickBulkOut(pAd); - -} - - -static void rt2870_pspoll_frame_complete_tasklet(unsigned long data) -{ - PRTMP_ADAPTER pAd; - PTX_CONTEXT pPsPollContext; - purbb_t pUrb; - NTSTATUS Status; - - - pUrb = (purbb_t)data; - pPsPollContext = (PTX_CONTEXT)pUrb->context; - pAd = pPsPollContext->pAd; - Status = pUrb->status; - - // Reset PsPoll context flags - pPsPollContext->IRPPending = FALSE; - pPsPollContext->InUse = FALSE; - pAd->watchDogTxPendingCnt[0] = 0; - - if (Status == USB_ST_NOERROR) - { - RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, MAX_TX_PROCESS); - } - else // STATUS_OTHER - { - if ((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS)) && - (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) && - (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) && - (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET))) - { - DBGPRINT_RAW(RT_DEBUG_ERROR, ("Bulk Out PSPoll Failed\n")); - RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET); - pAd->bulkResetPipeid = (MGMTPIPEIDX | BULKOUT_MGMT_RESET_FLAG); - RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_OUT, NULL, 0); - } - } - - RTMP_SEM_LOCK(&pAd->BulkOutLock[0]); - pAd->BulkOutPending[0] = FALSE; - RTMP_SEM_UNLOCK(&pAd->BulkOutLock[0]); - - // Always call Bulk routine, even reset bulk. - // The protectioon of rest bulk should be in BulkOut routine - RTUSBKickBulkOut(pAd); - -} - - -static void rt2870_dataout_complete_tasklet(unsigned long data) -{ - PRTMP_ADAPTER pAd; - purbb_t pUrb; - POS_COOKIE pObj; - PHT_TX_CONTEXT pHTTXContext; - UCHAR BulkOutPipeId; - NTSTATUS Status; - unsigned long IrqFlags; - - - pUrb = (purbb_t)data; - pHTTXContext = (PHT_TX_CONTEXT)pUrb->context; - pAd = pHTTXContext->pAd; - pObj = (POS_COOKIE) pAd->OS_Cookie; - Status = pUrb->status; - - // Store BulkOut PipeId - BulkOutPipeId = pHTTXContext->BulkOutPipeId; - pAd->BulkOutDataOneSecCount++; - - //DBGPRINT(RT_DEBUG_LOUD, ("Done-B(%d):I=0x%lx, CWPos=%ld, NBPos=%ld, ENBPos=%ld, bCopy=%d!\n", BulkOutPipeId, in_interrupt(), pHTTXContext->CurWritePosition, - // pHTTXContext->NextBulkOutPosition, pHTTXContext->ENextBulkOutPosition, pHTTXContext->bCopySavePad)); - - RTMP_IRQ_LOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); - pAd->BulkOutPending[BulkOutPipeId] = FALSE; - pHTTXContext->IRPPending = FALSE; - pAd->watchDogTxPendingCnt[BulkOutPipeId] = 0; - - if (Status == USB_ST_NOERROR) - { - pAd->BulkOutComplete++; - - RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); - - pAd->Counters8023.GoodTransmits++; - //RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags); - FREE_HTTX_RING(pAd, BulkOutPipeId, pHTTXContext); - //RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags); - - - } - else // STATUS_OTHER - { - PUCHAR pBuf; - - pAd->BulkOutCompleteOther++; - - pBuf = &pHTTXContext->TransferBuffer->field.WirelessPacket[pHTTXContext->NextBulkOutPosition]; - - if (!RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_RESET_IN_PROGRESS | - fRTMP_ADAPTER_HALT_IN_PROGRESS | - fRTMP_ADAPTER_NIC_NOT_EXIST | - fRTMP_ADAPTER_BULKOUT_RESET))) - { - RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET); - pAd->bulkResetPipeid = BulkOutPipeId; - pAd->bulkResetReq[BulkOutPipeId] = pAd->BulkOutReq; - } - RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); - - DBGPRINT_RAW(RT_DEBUG_ERROR, ("BulkOutDataPacket failed: ReasonCode=%d!\n", Status)); - DBGPRINT_RAW(RT_DEBUG_ERROR, ("\t>>BulkOut Req=0x%lx, Complete=0x%lx, Other=0x%lx\n", pAd->BulkOutReq, pAd->BulkOutComplete, pAd->BulkOutCompleteOther)); - DBGPRINT_RAW(RT_DEBUG_ERROR, ("\t>>BulkOut Header:%x %x %x %x %x %x %x %x\n", pBuf[0], pBuf[1], pBuf[2], pBuf[3], pBuf[4], pBuf[5], pBuf[6], pBuf[7])); - //DBGPRINT_RAW(RT_DEBUG_ERROR, (">>BulkOutCompleteCancel=0x%x, BulkOutCompleteOther=0x%x\n", pAd->BulkOutCompleteCancel, pAd->BulkOutCompleteOther)); - - } - - // - // bInUse = TRUE, means some process are filling TX data, after that must turn on bWaitingBulkOut - // bWaitingBulkOut = TRUE, means the TX data are waiting for bulk out. - // - //RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags); - if ((pHTTXContext->ENextBulkOutPosition != pHTTXContext->CurWritePosition) && - (pHTTXContext->ENextBulkOutPosition != (pHTTXContext->CurWritePosition+8)) && - !RTUSB_TEST_BULK_FLAG(pAd, (fRTUSB_BULK_OUT_DATA_FRAG << BulkOutPipeId))) - { - // Indicate There is data avaliable - RTUSB_SET_BULK_FLAG(pAd, (fRTUSB_BULK_OUT_DATA_NORMAL << BulkOutPipeId)); - } - //RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags); - - // Always call Bulk routine, even reset bulk. - // The protection of rest bulk should be in BulkOut routine - RTUSBKickBulkOut(pAd); -} - -/* End of 2870_rtmp_init.c */ +#include "../../rt2870/common/2870_rtmp_init.c" diff --git a/drivers/staging/rt3070/common/action.c b/drivers/staging/rt3070/common/action.c index b8ae53633661..035fd803f613 100644 --- a/drivers/staging/rt3070/common/action.c +++ b/drivers/staging/rt3070/common/action.c @@ -1,1038 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - action.c - - Abstract: - Handle association related requests either from WSTA or from local MLME - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Jan Lee 2006 created for rt2860 - */ - -#include "../rt_config.h" -#include "../action.h" - - -static VOID ReservedAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -/* - ========================================================================== - Description: - association state machine init, including state transition and timer init - Parameters: - S - pointer to the association state machine - Note: - The state machine looks like the following - - ASSOC_IDLE - MT2_MLME_DISASSOC_REQ mlme_disassoc_req_action - MT2_PEER_DISASSOC_REQ peer_disassoc_action - MT2_PEER_ASSOC_REQ drop - MT2_PEER_REASSOC_REQ drop - MT2_CLS3ERR cls3err_action - ========================================================================== - */ -VOID ActionStateMachineInit( - IN PRTMP_ADAPTER pAd, - IN STATE_MACHINE *S, - OUT STATE_MACHINE_FUNC Trans[]) -{ - StateMachineInit(S, (STATE_MACHINE_FUNC *)Trans, MAX_ACT_STATE, MAX_ACT_MSG, (STATE_MACHINE_FUNC)Drop, ACT_IDLE, ACT_MACHINE_BASE); - - StateMachineSetAction(S, ACT_IDLE, MT2_PEER_SPECTRUM_CATE, (STATE_MACHINE_FUNC)PeerSpectrumAction); - StateMachineSetAction(S, ACT_IDLE, MT2_PEER_QOS_CATE, (STATE_MACHINE_FUNC)PeerQOSAction); - - StateMachineSetAction(S, ACT_IDLE, MT2_PEER_DLS_CATE, (STATE_MACHINE_FUNC)ReservedAction); -#ifdef QOS_DLS_SUPPORT - StateMachineSetAction(S, ACT_IDLE, MT2_PEER_DLS_CATE, (STATE_MACHINE_FUNC)PeerDLSAction); -#endif // QOS_DLS_SUPPORT // - -#ifdef DOT11_N_SUPPORT - StateMachineSetAction(S, ACT_IDLE, MT2_PEER_BA_CATE, (STATE_MACHINE_FUNC)PeerBAAction); - StateMachineSetAction(S, ACT_IDLE, MT2_PEER_HT_CATE, (STATE_MACHINE_FUNC)PeerHTAction); - StateMachineSetAction(S, ACT_IDLE, MT2_MLME_ADD_BA_CATE, (STATE_MACHINE_FUNC)MlmeADDBAAction); - StateMachineSetAction(S, ACT_IDLE, MT2_MLME_ORI_DELBA_CATE, (STATE_MACHINE_FUNC)MlmeDELBAAction); - StateMachineSetAction(S, ACT_IDLE, MT2_MLME_REC_DELBA_CATE, (STATE_MACHINE_FUNC)MlmeDELBAAction); -#endif // DOT11_N_SUPPORT // - - StateMachineSetAction(S, ACT_IDLE, MT2_PEER_PUBLIC_CATE, (STATE_MACHINE_FUNC)PeerPublicAction); - StateMachineSetAction(S, ACT_IDLE, MT2_PEER_RM_CATE, (STATE_MACHINE_FUNC)PeerRMAction); - - StateMachineSetAction(S, ACT_IDLE, MT2_MLME_QOS_CATE, (STATE_MACHINE_FUNC)MlmeQOSAction); - StateMachineSetAction(S, ACT_IDLE, MT2_MLME_DLS_CATE, (STATE_MACHINE_FUNC)MlmeDLSAction); - StateMachineSetAction(S, ACT_IDLE, MT2_ACT_INVALID, (STATE_MACHINE_FUNC)MlmeInvalidAction); -} - -#ifdef DOT11_N_SUPPORT -VOID MlmeADDBAAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) - -{ - MLME_ADDBA_REQ_STRUCT *pInfo; - UCHAR Addr[6]; - PUCHAR pOutBuffer = NULL; - NDIS_STATUS NStatus; - ULONG Idx; - FRAME_ADDBA_REQ Frame; - ULONG FrameLen; - BA_ORI_ENTRY *pBAEntry = NULL; - - pInfo = (MLME_ADDBA_REQ_STRUCT *)Elem->Msg; - NdisZeroMemory(&Frame, sizeof(FRAME_ADDBA_REQ)); - - if(MlmeAddBAReqSanity(pAd, Elem->Msg, Elem->MsgLen, Addr)) - { - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory - if(NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_TRACE,("BA - MlmeADDBAAction() allocate memory failed \n")); - return; - } - // 1. find entry - Idx = pAd->MacTab.Content[pInfo->Wcid].BAOriWcidArray[pInfo->TID]; - if (Idx == 0) - { - MlmeFreeMemory(pAd, pOutBuffer); - DBGPRINT(RT_DEBUG_ERROR,("BA - MlmeADDBAAction() can't find BAOriEntry \n")); - return; - } - else - { - pBAEntry =&pAd->BATable.BAOriEntry[Idx]; - } - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - if (ADHOC_ON(pAd)) - ActHeaderInit(pAd, &Frame.Hdr, pInfo->pAddr, pAd->CurrentAddress, pAd->CommonCfg.Bssid); - else - ActHeaderInit(pAd, &Frame.Hdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pInfo->pAddr); - - } -#endif // CONFIG_STA_SUPPORT // - - Frame.Category = CATEGORY_BA; - Frame.Action = ADDBA_REQ; - Frame.BaParm.AMSDUSupported = 0; - Frame.BaParm.BAPolicy = IMMED_BA; - Frame.BaParm.TID = pInfo->TID; - Frame.BaParm.BufSize = pInfo->BaBufSize; - Frame.Token = pInfo->Token; - Frame.TimeOutValue = pInfo->TimeOutValue; - Frame.BaStartSeq.field.FragNum = 0; - Frame.BaStartSeq.field.StartSeq = pAd->MacTab.Content[pInfo->Wcid].TxSeq[pInfo->TID]; - - *(USHORT *)(&Frame.BaParm) = cpu2le16(*(USHORT *)(&Frame.BaParm)); - Frame.TimeOutValue = cpu2le16(Frame.TimeOutValue); - Frame.BaStartSeq.word = cpu2le16(Frame.BaStartSeq.word); - - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(FRAME_ADDBA_REQ), &Frame, - END_OF_ARGS); - MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); - //MiniportDataMMRequest(pAd, MapUserPriorityToAccessCategory[pInfo->TID], pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); - - DBGPRINT(RT_DEBUG_TRACE, ("BA - Send ADDBA request. StartSeq = %x, FrameLen = %ld. BufSize = %d\n", Frame.BaStartSeq.field.StartSeq, FrameLen, Frame.BaParm.BufSize)); - } -} - -/* - ========================================================================== - Description: - send DELBA and delete BaEntry if any - Parametrs: - Elem - MLME message MLME_DELBA_REQ_STRUCT - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID MlmeDELBAAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - MLME_DELBA_REQ_STRUCT *pInfo; - PUCHAR pOutBuffer = NULL; - PUCHAR pOutBuffer2 = NULL; - NDIS_STATUS NStatus; - ULONG Idx; - FRAME_DELBA_REQ Frame; - ULONG FrameLen; - FRAME_BAR FrameBar; - - pInfo = (MLME_DELBA_REQ_STRUCT *)Elem->Msg; - // must send back DELBA - NdisZeroMemory(&Frame, sizeof(FRAME_DELBA_REQ)); - DBGPRINT(RT_DEBUG_TRACE, ("==> MlmeDELBAAction(), Initiator(%d) \n", pInfo->Initiator)); - - if(MlmeDelBAReqSanity(pAd, Elem->Msg, Elem->MsgLen)) - { - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory - if(NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_ERROR,("BA - MlmeDELBAAction() allocate memory failed 1. \n")); - return; - } - - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer2); //Get an unused nonpaged memory - if(NStatus != NDIS_STATUS_SUCCESS) - { - MlmeFreeMemory(pAd, pOutBuffer); - DBGPRINT(RT_DEBUG_ERROR, ("BA - MlmeDELBAAction() allocate memory failed 2. \n")); - return; - } - - // SEND BAR (Send BAR to refresh peer reordering buffer.) - Idx = pAd->MacTab.Content[pInfo->Wcid].BAOriWcidArray[pInfo->TID]; - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - BarHeaderInit(pAd, &FrameBar, pAd->MacTab.Content[pInfo->Wcid].Addr, pAd->CurrentAddress); -#endif // CONFIG_STA_SUPPORT // - - FrameBar.StartingSeq.field.FragNum = 0; // make sure sequence not clear in DEL funciton. - FrameBar.StartingSeq.field.StartSeq = pAd->MacTab.Content[pInfo->Wcid].TxSeq[pInfo->TID]; // make sure sequence not clear in DEL funciton. - FrameBar.BarControl.TID = pInfo->TID; // make sure sequence not clear in DEL funciton. - FrameBar.BarControl.ACKPolicy = IMMED_BA; // make sure sequence not clear in DEL funciton. - FrameBar.BarControl.Compressed = 1; // make sure sequence not clear in DEL funciton. - FrameBar.BarControl.MTID = 0; // make sure sequence not clear in DEL funciton. - - MakeOutgoingFrame(pOutBuffer2, &FrameLen, - sizeof(FRAME_BAR), &FrameBar, - END_OF_ARGS); - MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer2, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer2); - DBGPRINT(RT_DEBUG_TRACE,("BA - MlmeDELBAAction() . Send BAR to refresh peer reordering buffer \n")); - - // SEND DELBA FRAME - FrameLen = 0; -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - if (ADHOC_ON(pAd)) - ActHeaderInit(pAd, &Frame.Hdr, pAd->MacTab.Content[pInfo->Wcid].Addr, pAd->CurrentAddress, pAd->CommonCfg.Bssid); - else - ActHeaderInit(pAd, &Frame.Hdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pAd->MacTab.Content[pInfo->Wcid].Addr); - } -#endif // CONFIG_STA_SUPPORT // - Frame.Category = CATEGORY_BA; - Frame.Action = DELBA; - Frame.DelbaParm.Initiator = pInfo->Initiator; - Frame.DelbaParm.TID = pInfo->TID; - Frame.ReasonCode = 39; // Time Out - *(USHORT *)(&Frame.DelbaParm) = cpu2le16(*(USHORT *)(&Frame.DelbaParm)); - Frame.ReasonCode = cpu2le16(Frame.ReasonCode); - - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(FRAME_DELBA_REQ), &Frame, - END_OF_ARGS); - MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); - DBGPRINT(RT_DEBUG_TRACE, ("BA - MlmeDELBAAction() . 3 DELBA sent. Initiator(%d)\n", pInfo->Initiator)); - } -} -#endif // DOT11_N_SUPPORT // - -VOID MlmeQOSAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ -} - -VOID MlmeDLSAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ -} - -VOID MlmeInvalidAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - //PUCHAR pOutBuffer = NULL; - //Return the receiving frame except the MSB of category filed set to 1. 7.3.1.11 -} - -VOID PeerQOSAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ -} - -#ifdef QOS_DLS_SUPPORT -VOID PeerDLSAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - UCHAR Action = Elem->Msg[LENGTH_802_11+1]; - - switch(Action) - { - case ACTION_DLS_REQUEST: -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - PeerDlsReqAction(pAd, Elem); -#endif // CONFIG_STA_SUPPORT // - break; - - case ACTION_DLS_RESPONSE: -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - PeerDlsRspAction(pAd, Elem); -#endif // CONFIG_STA_SUPPORT // - break; - - case ACTION_DLS_TEARDOWN: -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - PeerDlsTearDownAction(pAd, Elem); -#endif // CONFIG_STA_SUPPORT // - break; - } -} -#endif // QOS_DLS_SUPPORT // - -#ifdef DOT11_N_SUPPORT -VOID PeerBAAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - UCHAR Action = Elem->Msg[LENGTH_802_11+1]; - - switch(Action) - { - case ADDBA_REQ: - PeerAddBAReqAction(pAd,Elem); - break; - case ADDBA_RESP: - PeerAddBARspAction(pAd,Elem); - break; - case DELBA: - PeerDelBAAction(pAd,Elem); - break; - } -} - - -#ifdef DOT11N_DRAFT3 - -#ifdef CONFIG_STA_SUPPORT -VOID StaPublicAction( - IN PRTMP_ADAPTER pAd, - IN UCHAR Bss2040Coexist) -{ - BSS_2040_COEXIST_IE BssCoexist; - MLME_SCAN_REQ_STRUCT ScanReq; - - BssCoexist.word = Bss2040Coexist; - // AP asks Station to return a 20/40 BSS Coexistence mgmt frame. So we first starts a scan, then send back 20/40 BSS Coexistence mgmt frame - if ((BssCoexist.field.InfoReq == 1) && (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_SCAN_2040))) - { - // Clear record first. After scan , will update those bit and send back to transmiter. - pAd->CommonCfg.BSSCoexist2040.field.InfoReq = 1; - pAd->CommonCfg.BSSCoexist2040.field.Intolerant40 = 0; - pAd->CommonCfg.BSSCoexist2040.field.BSS20WidthReq = 0; - // Fill out stuff for scan request - ScanParmFill(pAd, &ScanReq, ZeroSsid, 0, BSS_ANY, SCAN_2040_BSS_COEXIST); - MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq); - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN; - } -} - - -/* -Description : Build Intolerant Channel Rerpot from Trigger event table. -return : how many bytes copied. -*/ -ULONG BuildIntolerantChannelRep( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDest) -{ - ULONG FrameLen = 0; - ULONG ReadOffset = 0; - UCHAR i; - UCHAR LastRegClass = 0xff; - PUCHAR pLen; - - for ( i = 0;i < MAX_TRIGGER_EVENT;i++) - { - if (pAd->CommonCfg.TriggerEventTab.EventA[i].bValid == TRUE) - { - if (pAd->CommonCfg.TriggerEventTab.EventA[i].RegClass == LastRegClass) - { - *(pDest + ReadOffset) = (UCHAR)pAd->CommonCfg.TriggerEventTab.EventA[i].Channel; - *pLen++; - ReadOffset++; - FrameLen++; - } - else - { - *(pDest + ReadOffset) = IE_2040_BSS_INTOLERANT_REPORT; // IE - *(pDest + ReadOffset + 1) = 2; // Len = RegClass byte + channel byte. - pLen = pDest + ReadOffset + 1; - LastRegClass = pAd->CommonCfg.TriggerEventTab.EventA[i].RegClass; - *(pDest + ReadOffset + 2) = LastRegClass; // Len = RegClass byte + channel byte. - *(pDest + ReadOffset + 3) = (UCHAR)pAd->CommonCfg.TriggerEventTab.EventA[i].Channel; - FrameLen += 4; - ReadOffset += 4; - } - - } - } - return FrameLen; -} - - -/* -Description : Send 20/40 BSS Coexistence Action frame If one trigger event is triggered. -*/ -VOID Send2040CoexistAction( - IN PRTMP_ADAPTER pAd, - IN UCHAR Wcid, - IN BOOLEAN bAddIntolerantCha) -{ - PUCHAR pOutBuffer = NULL; - NDIS_STATUS NStatus; - FRAME_ACTION_HDR Frame; - ULONG FrameLen; - ULONG IntolerantChaRepLen; - - IntolerantChaRepLen = 0; - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory - if(NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_ERROR,("ACT - Send2040CoexistAction() allocate memory failed \n")); - return; - } - ActHeaderInit(pAd, &Frame.Hdr, pAd->MacTab.Content[Wcid].Addr, pAd->CommonCfg.Bssid); - Frame.Category = CATEGORY_PUBLIC; - Frame.Action = ACTION_BSS_2040_COEXIST; - - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(FRAME_ACTION_HDR), &Frame, - END_OF_ARGS); - - *(pOutBuffer + FrameLen) = pAd->CommonCfg.BSSCoexist2040.word; - FrameLen++; - - if (bAddIntolerantCha == TRUE) - IntolerantChaRepLen = BuildIntolerantChannelRep(pAd, pOutBuffer + FrameLen); - - MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen + IntolerantChaRepLen); - DBGPRINT(RT_DEBUG_ERROR,("ACT - Send2040CoexistAction( BSSCoexist2040 = 0x%x ) \n", pAd->CommonCfg.BSSCoexist2040.word)); - -} - - -/* - ========================================================================== - Description: - After scan, Update 20/40 BSS Coexistence IE and send out. - According to 802.11n D3.03 11.14.10 - - Parameters: - ========================================================================== - */ -VOID Update2040CoexistFrameAndNotify( - IN PRTMP_ADAPTER pAd, - IN UCHAR Wcid, - IN BOOLEAN bAddIntolerantCha) -{ - BSS_2040_COEXIST_IE OldValue; - - OldValue.word = pAd->CommonCfg.BSSCoexist2040.word; - if ((pAd->CommonCfg.TriggerEventTab.EventANo > 0) || (pAd->CommonCfg.TriggerEventTab.EventBCountDown > 0)) - pAd->CommonCfg.BSSCoexist2040.field.BSS20WidthReq = 1; - - // Need to check !!!! - // How STA will set Intolerant40 if implementation dependent. Now we don't set this bit first.!!!!! - // So Only check BSS20WidthReq change. - if (OldValue.field.BSS20WidthReq != pAd->CommonCfg.BSSCoexist2040.field.BSS20WidthReq) - { - Send2040CoexistAction(pAd, Wcid, bAddIntolerantCha); - } -} -#endif // CONFIG_STA_SUPPORT // - - -BOOLEAN ChannelSwitchSanityCheck( - IN PRTMP_ADAPTER pAd, - IN UCHAR Wcid, - IN UCHAR NewChannel, - IN UCHAR Secondary) -{ - UCHAR i; - - if (Wcid >= MAX_LEN_OF_MAC_TABLE) - return FALSE; - - if ((NewChannel > 7) && (Secondary == 1)) - return FALSE; - - if ((NewChannel < 5) && (Secondary == 3)) - return FALSE; - - // 0. Check if new channel is in the channellist. - for (i = 0;i < pAd->ChannelListNum;i++) - { - if (pAd->ChannelList[i].Channel == NewChannel) - { - break; - } - } - - if (i == pAd->ChannelListNum) - return FALSE; - - return TRUE; -} - - -VOID ChannelSwitchAction( - IN PRTMP_ADAPTER pAd, - IN UCHAR Wcid, - IN UCHAR NewChannel, - IN UCHAR Secondary) -{ - UCHAR BBPValue = 0; - ULONG MACValue; - - DBGPRINT(RT_DEBUG_TRACE,("SPECTRUM - ChannelSwitchAction(NewChannel = %d , Secondary = %d) \n", NewChannel, Secondary)); - - if (ChannelSwitchSanityCheck(pAd, Wcid, NewChannel, Secondary) == FALSE) - return; - - // 1. Switches to BW = 20. - if (Secondary == 0) - { - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); - BBPValue&= (~0x18); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); - if (pAd->MACVersion == 0x28600100) - { - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, 0x16); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, 0x08); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R73, 0x11); - DBGPRINT(RT_DEBUG_TRACE, ("!!!rt2860C !!! \n" )); - } - pAd->CommonCfg.BBPCurrentBW = BW_20; - pAd->CommonCfg.Channel = NewChannel; - pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel; - AsicSwitchChannel(pAd, pAd->CommonCfg.Channel,FALSE); - AsicLockChannel(pAd, pAd->CommonCfg.Channel); - pAd->MacTab.Content[Wcid].HTPhyMode.field.BW = 0; - DBGPRINT(RT_DEBUG_TRACE, ("!!!20MHz !!! \n" )); - } - // 1. Switches to BW = 40 And Station supports BW = 40. - else if (((Secondary == 1) || (Secondary == 3)) && (pAd->CommonCfg.HtCapability.HtCapInfo.ChannelWidth == 1)) - { - pAd->CommonCfg.Channel = NewChannel; - - if (Secondary == 1) - { - // Secondary above. - pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel + 2; - RTMP_IO_READ32(pAd, TX_BAND_CFG, &MACValue); - MACValue &= 0xfe; - RTMP_IO_WRITE32(pAd, TX_BAND_CFG, MACValue); - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); - BBPValue&= (~0x18); - BBPValue|= (0x10); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BBPValue); - BBPValue&= (~0x20); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BBPValue); - DBGPRINT(RT_DEBUG_TRACE, ("!!!40MHz Lower LINK UP !!! Control Channel at Below. Central = %d \n", pAd->CommonCfg.CentralChannel )); - } - else - { - // Secondary below. - pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel - 2; - RTMP_IO_READ32(pAd, TX_BAND_CFG, &MACValue); - MACValue &= 0xfe; - MACValue |= 0x1; - RTMP_IO_WRITE32(pAd, TX_BAND_CFG, MACValue); - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); - BBPValue&= (~0x18); - BBPValue|= (0x10); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BBPValue); - BBPValue&= (~0x20); - BBPValue|= (0x20); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BBPValue); - DBGPRINT(RT_DEBUG_TRACE, ("!!!40MHz Upper LINK UP !!! Control Channel at UpperCentral = %d \n", pAd->CommonCfg.CentralChannel )); - } - pAd->CommonCfg.BBPCurrentBW = BW_40; - AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE); - AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel); - pAd->MacTab.Content[Wcid].HTPhyMode.field.BW = 1; - } -} -#endif // DOT11N_DRAFT3 // -#endif // DOT11_N_SUPPORT // - -VOID PeerPublicAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ -#ifdef DOT11N_DRAFT3 - UCHAR Action = Elem->Msg[LENGTH_802_11+1]; -#endif // DOT11N_DRAFT3 // - - if (Elem->Wcid >= MAX_LEN_OF_MAC_TABLE) - return; - -#ifdef DOT11N_DRAFT3 - switch(Action) - { - case ACTION_BSS_2040_COEXIST: // Format defined in IEEE 7.4.7a.1 in 11n Draf3.03 - { - //UCHAR BssCoexist; - BSS_2040_COEXIST_ELEMENT *pCoexistInfo; - BSS_2040_COEXIST_IE *pBssCoexistIe; - BSS_2040_INTOLERANT_CH_REPORT *pIntolerantReport = NULL; - - if (Elem->MsgLen <= (LENGTH_802_11 + sizeof(BSS_2040_COEXIST_ELEMENT)) ) - { - DBGPRINT(RT_DEBUG_ERROR, ("ACTION - 20/40 BSS Coexistence Management Frame length too short! len = %ld!\n", Elem->MsgLen)); - break; - } - DBGPRINT(RT_DEBUG_TRACE, ("ACTION - 20/40 BSS Coexistence Management action----> \n")); - hex_dump("CoexistenceMgmtFrame", Elem->Msg, Elem->MsgLen); - - - pCoexistInfo = (BSS_2040_COEXIST_ELEMENT *) &Elem->Msg[LENGTH_802_11+2]; - //hex_dump("CoexistInfo", (PUCHAR)pCoexistInfo, sizeof(BSS_2040_COEXIST_ELEMENT)); - if (Elem->MsgLen >= (LENGTH_802_11 + sizeof(BSS_2040_COEXIST_ELEMENT) + sizeof(BSS_2040_INTOLERANT_CH_REPORT))) - { - pIntolerantReport = (BSS_2040_INTOLERANT_CH_REPORT *)((PUCHAR)pCoexistInfo + sizeof(BSS_2040_COEXIST_ELEMENT)); - } - //hex_dump("IntolerantReport ", (PUCHAR)pIntolerantReport, sizeof(BSS_2040_INTOLERANT_CH_REPORT)); - - pBssCoexistIe = (BSS_2040_COEXIST_IE *)(&pCoexistInfo->BssCoexistIe); - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - if (INFRA_ON(pAd)) - { - StaPublicAction(pAd, pCoexistInfo); - } - } -#endif // CONFIG_STA_SUPPORT // - - } - break; - } - -#endif // DOT11N_DRAFT3 // - -} - - -static VOID ReservedAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - UCHAR Category; - - if (Elem->MsgLen <= LENGTH_802_11) - { - return; - } - - Category = Elem->Msg[LENGTH_802_11]; - DBGPRINT(RT_DEBUG_TRACE,("Rcv reserved category(%d) Action Frame\n", Category)); - hex_dump("Reserved Action Frame", &Elem->Msg[0], Elem->MsgLen); -} - -VOID PeerRMAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) - -{ - return; -} - -#ifdef DOT11_N_SUPPORT -static VOID respond_ht_information_exchange_action( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - PUCHAR pOutBuffer = NULL; - NDIS_STATUS NStatus; - ULONG FrameLen; - FRAME_HT_INFO HTINFOframe, *pFrame; - UCHAR *pAddr; - - - // 2. Always send back ADDBA Response - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory - - if (NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_TRACE,("ACTION - respond_ht_information_exchange_action() allocate memory failed \n")); - return; - } - - // get RA - pFrame = (FRAME_HT_INFO *) &Elem->Msg[0]; - pAddr = pFrame->Hdr.Addr2; - - NdisZeroMemory(&HTINFOframe, sizeof(FRAME_HT_INFO)); - // 2-1. Prepare ADDBA Response frame. -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - if (ADHOC_ON(pAd)) - ActHeaderInit(pAd, &HTINFOframe.Hdr, pAddr, pAd->CurrentAddress, pAd->CommonCfg.Bssid); - else - ActHeaderInit(pAd, &HTINFOframe.Hdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pAddr); - } -#endif // CONFIG_STA_SUPPORT // - - HTINFOframe.Category = CATEGORY_HT; - HTINFOframe.Action = HT_INFO_EXCHANGE; - HTINFOframe.HT_Info.Request = 0; - HTINFOframe.HT_Info.Forty_MHz_Intolerant = pAd->CommonCfg.HtCapability.HtCapInfo.Forty_Mhz_Intolerant; - HTINFOframe.HT_Info.STA_Channel_Width = pAd->CommonCfg.AddHTInfo.AddHtInfo.RecomWidth; - - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(FRAME_HT_INFO), &HTINFOframe, - END_OF_ARGS); - - MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); -} - - -#ifdef DOT11N_DRAFT3 -VOID SendNotifyBWActionFrame( - IN PRTMP_ADAPTER pAd, - IN UCHAR Wcid, - IN UCHAR apidx) -{ - PUCHAR pOutBuffer = NULL; - NDIS_STATUS NStatus; - FRAME_ACTION_HDR Frame; - ULONG FrameLen; - PUCHAR pAddr1; - - - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory - if(NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_ERROR,("ACT - SendNotifyBWAction() allocate memory failed \n")); - return; - } - - if (Wcid == MCAST_WCID) - pAddr1 = &BROADCAST_ADDR[0]; - else - pAddr1 = pAd->MacTab.Content[Wcid].Addr; - ActHeaderInit(pAd, &Frame.Hdr, pAddr1, pAd->ApCfg.MBSSID[apidx].Bssid, pAd->ApCfg.MBSSID[apidx].Bssid); - - Frame.Category = CATEGORY_HT; - Frame.Action = NOTIFY_BW_ACTION; - - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(FRAME_ACTION_HDR), &Frame, - END_OF_ARGS); - - *(pOutBuffer + FrameLen) = pAd->CommonCfg.AddHTInfo.AddHtInfo.RecomWidth; - FrameLen++; - - - MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); - DBGPRINT(RT_DEBUG_TRACE,("ACT - SendNotifyBWAction(NotifyBW= %d)!\n", pAd->CommonCfg.AddHTInfo.AddHtInfo.RecomWidth)); - -} -#endif // DOT11N_DRAFT3 // - - -VOID PeerHTAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - UCHAR Action = Elem->Msg[LENGTH_802_11+1]; - - if (Elem->Wcid >= MAX_LEN_OF_MAC_TABLE) - return; - - switch(Action) - { - case NOTIFY_BW_ACTION: - DBGPRINT(RT_DEBUG_TRACE,("ACTION - HT Notify Channel bandwidth action----> \n")); -#ifdef CONFIG_STA_SUPPORT - if(pAd->StaActive.SupportedPhyInfo.bHtEnable == FALSE) - { - // Note, this is to patch DIR-1353 AP. When the AP set to Wep, it will use legacy mode. But AP still keeps - // sending BW_Notify Action frame, and cause us to linkup and linkdown. - // In legacy mode, don't need to parse HT action frame. - DBGPRINT(RT_DEBUG_TRACE,("ACTION -Ignore HT Notify Channel BW when link as legacy mode. BW = %d---> \n", - Elem->Msg[LENGTH_802_11+2] )); - break; - } -#endif // CONFIG_STA_SUPPORT // - - if (Elem->Msg[LENGTH_802_11+2] == 0) // 7.4.8.2. if value is 1, keep the same as supported channel bandwidth. - pAd->MacTab.Content[Elem->Wcid].HTPhyMode.field.BW = 0; - - break; - - case SMPS_ACTION: - // 7.3.1.25 - DBGPRINT(RT_DEBUG_TRACE,("ACTION - SMPS action----> \n")); - if (((Elem->Msg[LENGTH_802_11+2]&0x1) == 0)) - { - pAd->MacTab.Content[Elem->Wcid].MmpsMode = MMPS_ENABLE; - } - else if (((Elem->Msg[LENGTH_802_11+2]&0x2) == 0)) - { - pAd->MacTab.Content[Elem->Wcid].MmpsMode = MMPS_STATIC; - } - else - { - pAd->MacTab.Content[Elem->Wcid].MmpsMode = MMPS_DYNAMIC; - } - - DBGPRINT(RT_DEBUG_TRACE,("Aid(%d) MIMO PS = %d\n", Elem->Wcid, pAd->MacTab.Content[Elem->Wcid].MmpsMode)); - // rt2860c : add something for smps change. - break; - - case SETPCO_ACTION: - break; - - case MIMO_CHA_MEASURE_ACTION: - break; - - case HT_INFO_EXCHANGE: - { - HT_INFORMATION_OCTET *pHT_info; - - pHT_info = (HT_INFORMATION_OCTET *) &Elem->Msg[LENGTH_802_11+2]; - // 7.4.8.10 - DBGPRINT(RT_DEBUG_TRACE,("ACTION - HT Information Exchange action----> \n")); - if (pHT_info->Request) - { - respond_ht_information_exchange_action(pAd, Elem); - } - } - break; - } -} - - -/* - ========================================================================== - Description: - Retry sending ADDBA Reqest. - - IRQL = DISPATCH_LEVEL - - Parametrs: - p8023Header: if this is already 802.3 format, p8023Header is NULL - - Return : TRUE if put into rx reordering buffer, shouldn't indicaterxhere. - FALSE , then continue indicaterx at this moment. - ========================================================================== - */ -VOID ORIBATimerTimeout( - IN PRTMP_ADAPTER pAd) -{ - MAC_TABLE_ENTRY *pEntry; - INT i, total; -// FRAME_BAR FrameBar; -// ULONG FrameLen; -// NDIS_STATUS NStatus; -// PUCHAR pOutBuffer = NULL; -// USHORT Sequence; - UCHAR TID; - -#ifdef RALINK_ATE - if (ATE_ON(pAd)) - return; -#endif // RALINK_ATE // - - total = pAd->MacTab.Size * NUM_OF_TID; - - for (i = 1; ((i 0)) ; i++) - { - if (pAd->BATable.BAOriEntry[i].ORI_BA_Status == Originator_Done) - { - pEntry = &pAd->MacTab.Content[pAd->BATable.BAOriEntry[i].Wcid]; - TID = pAd->BATable.BAOriEntry[i].TID; - - ASSERT(pAd->BATable.BAOriEntry[i].Wcid < MAX_LEN_OF_MAC_TABLE); - } - total --; - } -} - - -VOID SendRefreshBAR( - IN PRTMP_ADAPTER pAd, - IN MAC_TABLE_ENTRY *pEntry) -{ - FRAME_BAR FrameBar; - ULONG FrameLen; - NDIS_STATUS NStatus; - PUCHAR pOutBuffer = NULL; - USHORT Sequence; - UCHAR i, TID; - USHORT idx; - BA_ORI_ENTRY *pBAEntry; - - for (i = 0; i BAOriWcidArray[i]; - if (idx == 0) - { - continue; - } - pBAEntry = &pAd->BATable.BAOriEntry[idx]; - - if (pBAEntry->ORI_BA_Status == Originator_Done) - { - TID = pBAEntry->TID; - - ASSERT(pBAEntry->Wcid < MAX_LEN_OF_MAC_TABLE); - - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory - if(NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_ERROR,("BA - MlmeADDBAAction() allocate memory failed \n")); - return; - } - - Sequence = pEntry->TxSeq[TID]; - - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - BarHeaderInit(pAd, &FrameBar, pEntry->Addr, pAd->CurrentAddress); -#endif // CONFIG_STA_SUPPORT // - - FrameBar.StartingSeq.field.FragNum = 0; // make sure sequence not clear in DEL function. - FrameBar.StartingSeq.field.StartSeq = Sequence; // make sure sequence not clear in DEL funciton. - FrameBar.BarControl.TID = TID; // make sure sequence not clear in DEL funciton. - - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(FRAME_BAR), &FrameBar, - END_OF_ARGS); - //if (!(CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_RALINK_CHIPSET))) - if (1) // Now we always send BAR. - { - //MiniportMMRequestUnlock(pAd, 0, pOutBuffer, FrameLen); - MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); - //MiniportDataMMRequest(pAd, MapUserPriorityToAccessCategory[TID], pOutBuffer, FrameLen); - } - MlmeFreeMemory(pAd, pOutBuffer); - } - } -} -#endif // DOT11_N_SUPPORT // - -VOID ActHeaderInit( - IN PRTMP_ADAPTER pAd, - IN OUT PHEADER_802_11 pHdr80211, - IN PUCHAR Addr1, - IN PUCHAR Addr2, - IN PUCHAR Addr3) -{ - NdisZeroMemory(pHdr80211, sizeof(HEADER_802_11)); - pHdr80211->FC.Type = BTYPE_MGMT; - pHdr80211->FC.SubType = SUBTYPE_ACTION; - - COPY_MAC_ADDR(pHdr80211->Addr1, Addr1); - COPY_MAC_ADDR(pHdr80211->Addr2, Addr2); - COPY_MAC_ADDR(pHdr80211->Addr3, Addr3); -} - -VOID BarHeaderInit( - IN PRTMP_ADAPTER pAd, - IN OUT PFRAME_BAR pCntlBar, - IN PUCHAR pDA, - IN PUCHAR pSA) -{ -// USHORT Duration; - - NdisZeroMemory(pCntlBar, sizeof(FRAME_BAR)); - pCntlBar->FC.Type = BTYPE_CNTL; - pCntlBar->FC.SubType = SUBTYPE_BLOCK_ACK_REQ; - pCntlBar->BarControl.MTID = 0; - pCntlBar->BarControl.Compressed = 1; - pCntlBar->BarControl.ACKPolicy = 0; - - - pCntlBar->Duration = 16 + RTMPCalcDuration(pAd, RATE_1, sizeof(FRAME_BA)); - - COPY_MAC_ADDR(pCntlBar->Addr1, pDA); - COPY_MAC_ADDR(pCntlBar->Addr2, pSA); -} - - -/* - ========================================================================== - Description: - Insert Category and action code into the action frame. - - Parametrs: - 1. frame buffer pointer. - 2. frame length. - 3. category code of the frame. - 4. action code of the frame. - - Return : None. - ========================================================================== - */ -VOID InsertActField( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pFrameBuf, - OUT PULONG pFrameLen, - IN UINT8 Category, - IN UINT8 ActCode) -{ - ULONG TempLen; - - MakeOutgoingFrame( pFrameBuf, &TempLen, - 1, &Category, - 1, &ActCode, - END_OF_ARGS); - - *pFrameLen = *pFrameLen + TempLen; - - return; -} +#include "../../rt2870/common/action.c" diff --git a/drivers/staging/rt3070/common/ba_action.c b/drivers/staging/rt3070/common/ba_action.c index 17e1f87d98db..2d638ea8c87a 100644 --- a/drivers/staging/rt3070/common/ba_action.c +++ b/drivers/staging/rt3070/common/ba_action.c @@ -1,1810 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * 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. * - * * - ************************************************************************* - */ - - -#ifdef DOT11_N_SUPPORT - -#include "../rt_config.h" - - - -#define BA_ORI_INIT_SEQ (pEntry->TxSeq[TID]) //1 // inital sequence number of BA session - -#define ORI_SESSION_MAX_RETRY 8 -#define ORI_BA_SESSION_TIMEOUT (2000) // ms -#define REC_BA_SESSION_IDLE_TIMEOUT (1000) // ms - -#define REORDERING_PACKET_TIMEOUT ((100 * HZ)/1000) // system ticks -- 100 ms -#define MAX_REORDERING_PACKET_TIMEOUT ((3000 * HZ)/1000) // system ticks -- 100 ms - -#define RESET_RCV_SEQ (0xFFFF) - -static void ba_mpdu_blk_free(PRTMP_ADAPTER pAd, struct reordering_mpdu *mpdu_blk); - - -BA_ORI_ENTRY *BATableAllocOriEntry( - IN PRTMP_ADAPTER pAd, - OUT USHORT *Idx); - -BA_REC_ENTRY *BATableAllocRecEntry( - IN PRTMP_ADAPTER pAd, - OUT USHORT *Idx); - -VOID BAOriSessionSetupTimeout( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); - -VOID BARecSessionIdleTimeout( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); - - -BUILD_TIMER_FUNCTION(BAOriSessionSetupTimeout); -BUILD_TIMER_FUNCTION(BARecSessionIdleTimeout); - -#define ANNOUNCE_REORDERING_PACKET(_pAd, _mpdu_blk) \ - Announce_Reordering_Packet(_pAd, _mpdu_blk); - -VOID BA_MaxWinSizeReasign( - IN PRTMP_ADAPTER pAd, - IN MAC_TABLE_ENTRY *pEntryPeer, - OUT UCHAR *pWinSize) -{ - UCHAR MaxSize; - - - if (pAd->MACVersion >= RALINK_2883_VERSION) // 3*3 - { - if (pAd->MACVersion >= RALINK_3070_VERSION) - { - if (pEntryPeer->WepStatus != Ndis802_11EncryptionDisabled) - MaxSize = 7; // for non-open mode - else - MaxSize = 13; - } - else - MaxSize = 31; - } - else if (pAd->MACVersion >= RALINK_2880E_VERSION) // 2880 e - { - if (pEntryPeer->WepStatus != Ndis802_11EncryptionDisabled) - MaxSize = 7; // for non-open mode - else - MaxSize = 13; - } - else - MaxSize = 7; - - DBGPRINT(RT_DEBUG_TRACE, ("ba> Win Size = %d, Max Size = %d\n", - *pWinSize, MaxSize)); - - if ((*pWinSize) > MaxSize) - { - DBGPRINT(RT_DEBUG_TRACE, ("ba> reassign max win size from %d to %d\n", - *pWinSize, MaxSize)); - - *pWinSize = MaxSize; - } -} - -void Announce_Reordering_Packet(IN PRTMP_ADAPTER pAd, - IN struct reordering_mpdu *mpdu) -{ - PNDIS_PACKET pPacket; - - pPacket = mpdu->pPacket; - - if (mpdu->bAMSDU) - { - ASSERT(0); - BA_Reorder_AMSDU_Annnounce(pAd, pPacket); - } - else - { - // - // pass this 802.3 packet to upper layer or forward this packet to WM directly - // - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - ANNOUNCE_OR_FORWARD_802_3_PACKET(pAd, pPacket, RTMP_GET_PACKET_IF(pPacket)); -#endif // CONFIG_STA_SUPPORT // - } -} - -/* - * Insert a reordering mpdu into sorted linked list by sequence no. - */ -BOOLEAN ba_reordering_mpdu_insertsorted(struct reordering_list *list, struct reordering_mpdu *mpdu) -{ - - struct reordering_mpdu **ppScan = &list->next; - - while (*ppScan != NULL) - { - if (SEQ_SMALLER((*ppScan)->Sequence, mpdu->Sequence, MAXSEQ)) - { - ppScan = &(*ppScan)->next; - } - else if ((*ppScan)->Sequence == mpdu->Sequence) - { - /* give up this duplicated frame */ - return(FALSE); - } - else - { - /* find position */ - break; - } - } - - mpdu->next = *ppScan; - *ppScan = mpdu; - list->qlen++; - return TRUE; -} - - -/* - * caller lock critical section if necessary - */ -static inline void ba_enqueue(struct reordering_list *list, struct reordering_mpdu *mpdu_blk) -{ - list->qlen++; - mpdu_blk->next = list->next; - list->next = mpdu_blk; -} - -/* - * caller lock critical section if necessary - */ -static inline struct reordering_mpdu * ba_dequeue(struct reordering_list *list) -{ - struct reordering_mpdu *mpdu_blk = NULL; - - ASSERT(list); - - if (list->qlen) - { - list->qlen--; - mpdu_blk = list->next; - if (mpdu_blk) - { - list->next = mpdu_blk->next; - mpdu_blk->next = NULL; - } - } - return mpdu_blk; -} - - -static inline struct reordering_mpdu *ba_reordering_mpdu_dequeue(struct reordering_list *list) -{ - return(ba_dequeue(list)); -} - - -static inline struct reordering_mpdu *ba_reordering_mpdu_probe(struct reordering_list *list) - { - ASSERT(list); - - return(list->next); - } - - -/* - * free all resource for reordering mechanism - */ -void ba_reordering_resource_release(PRTMP_ADAPTER pAd) -{ - BA_TABLE *Tab; - PBA_REC_ENTRY pBAEntry; - struct reordering_mpdu *mpdu_blk; - int i; - - Tab = &pAd->BATable; - - /* I. release all pending reordering packet */ - NdisAcquireSpinLock(&pAd->BATabLock); - for (i = 0; i < MAX_LEN_OF_BA_REC_TABLE; i++) - { - pBAEntry = &Tab->BARecEntry[i]; - if (pBAEntry->REC_BA_Status != Recipient_NONE) - { - while ((mpdu_blk = ba_reordering_mpdu_dequeue(&pBAEntry->list))) - { - ASSERT(mpdu_blk->pPacket); - RELEASE_NDIS_PACKET(pAd, mpdu_blk->pPacket, NDIS_STATUS_FAILURE); - ba_mpdu_blk_free(pAd, mpdu_blk); - } - } - } - NdisReleaseSpinLock(&pAd->BATabLock); - - ASSERT(pBAEntry->list.qlen == 0); - /* II. free memory of reordering mpdu table */ - NdisAcquireSpinLock(&pAd->mpdu_blk_pool.lock); - os_free_mem(pAd, pAd->mpdu_blk_pool.mem); - NdisReleaseSpinLock(&pAd->mpdu_blk_pool.lock); -} - - - -/* - * Allocate all resource for reordering mechanism - */ -BOOLEAN ba_reordering_resource_init(PRTMP_ADAPTER pAd, int num) -{ - int i; - PUCHAR mem; - struct reordering_mpdu *mpdu_blk; - struct reordering_list *freelist; - - /* allocate spinlock */ - NdisAllocateSpinLock(&pAd->mpdu_blk_pool.lock); - - /* initialize freelist */ - freelist = &pAd->mpdu_blk_pool.freelist; - freelist->next = NULL; - freelist->qlen = 0; - - DBGPRINT(RT_DEBUG_TRACE, ("Allocate %d memory for BA reordering\n", (UINT32)(num*sizeof(struct reordering_mpdu)))); - - /* allocate number of mpdu_blk memory */ - os_alloc_mem(pAd, (PUCHAR *)&mem, (num*sizeof(struct reordering_mpdu))); - - pAd->mpdu_blk_pool.mem = mem; - - if (mem == NULL) - { - DBGPRINT(RT_DEBUG_ERROR, ("Can't Allocate Memory for BA Reordering\n")); - return(FALSE); - } - - /* build mpdu_blk free list */ - for (i=0; impdu_blk_pool.lock); - mpdu_blk = ba_dequeue(&pAd->mpdu_blk_pool.freelist); - if (mpdu_blk) - { -// blk_count++; - /* reset mpdu_blk */ - NdisZeroMemory(mpdu_blk, sizeof(struct reordering_mpdu)); - } - NdisReleaseSpinLock(&pAd->mpdu_blk_pool.lock); - return mpdu_blk; -} - -static void ba_mpdu_blk_free(PRTMP_ADAPTER pAd, struct reordering_mpdu *mpdu_blk) -{ - ASSERT(mpdu_blk); - - NdisAcquireSpinLock(&pAd->mpdu_blk_pool.lock); -// blk_count--; - ba_enqueue(&pAd->mpdu_blk_pool.freelist, mpdu_blk); - NdisReleaseSpinLock(&pAd->mpdu_blk_pool.lock); -} - - -static USHORT ba_indicate_reordering_mpdus_in_order( - IN PRTMP_ADAPTER pAd, - IN PBA_REC_ENTRY pBAEntry, - IN USHORT StartSeq) -{ - struct reordering_mpdu *mpdu_blk; - USHORT LastIndSeq = RESET_RCV_SEQ; - - NdisAcquireSpinLock(&pBAEntry->RxReRingLock); - - while ((mpdu_blk = ba_reordering_mpdu_probe(&pBAEntry->list))) - { - /* find in-order frame */ - if (!SEQ_STEPONE(mpdu_blk->Sequence, StartSeq, MAXSEQ)) - { - break; - } - /* dequeue in-order frame from reodering list */ - mpdu_blk = ba_reordering_mpdu_dequeue(&pBAEntry->list); - /* pass this frame up */ - ANNOUNCE_REORDERING_PACKET(pAd, mpdu_blk); - /* move to next sequence */ - StartSeq = mpdu_blk->Sequence; - LastIndSeq = StartSeq; - /* free mpdu_blk */ - ba_mpdu_blk_free(pAd, mpdu_blk); - } - - NdisReleaseSpinLock(&pBAEntry->RxReRingLock); - - /* update last indicated sequence */ - return LastIndSeq; -} - -static void ba_indicate_reordering_mpdus_le_seq( - IN PRTMP_ADAPTER pAd, - IN PBA_REC_ENTRY pBAEntry, - IN USHORT Sequence) -{ - struct reordering_mpdu *mpdu_blk; - - NdisAcquireSpinLock(&pBAEntry->RxReRingLock); - while ((mpdu_blk = ba_reordering_mpdu_probe(&pBAEntry->list))) - { - /* find in-order frame */ - if ((mpdu_blk->Sequence == Sequence) || SEQ_SMALLER(mpdu_blk->Sequence, Sequence, MAXSEQ)) - { - /* dequeue in-order frame from reodering list */ - mpdu_blk = ba_reordering_mpdu_dequeue(&pBAEntry->list); - /* pass this frame up */ - ANNOUNCE_REORDERING_PACKET(pAd, mpdu_blk); - /* free mpdu_blk */ - ba_mpdu_blk_free(pAd, mpdu_blk); - } - else - { - break; - } - } - NdisReleaseSpinLock(&pBAEntry->RxReRingLock); -} - - -static void ba_refresh_reordering_mpdus( - IN PRTMP_ADAPTER pAd, - PBA_REC_ENTRY pBAEntry) -{ - struct reordering_mpdu *mpdu_blk; - - NdisAcquireSpinLock(&pBAEntry->RxReRingLock); - - /* dequeue in-order frame from reodering list */ - while ((mpdu_blk = ba_reordering_mpdu_dequeue(&pBAEntry->list))) - { - /* pass this frame up */ - ANNOUNCE_REORDERING_PACKET(pAd, mpdu_blk); - - pBAEntry->LastIndSeq = mpdu_blk->Sequence; - ba_mpdu_blk_free(pAd, mpdu_blk); - - /* update last indicated sequence */ - } - ASSERT(pBAEntry->list.qlen == 0); - pBAEntry->LastIndSeq = RESET_RCV_SEQ; - NdisReleaseSpinLock(&pBAEntry->RxReRingLock); -} - - -//static -void ba_flush_reordering_timeout_mpdus( - IN PRTMP_ADAPTER pAd, - IN PBA_REC_ENTRY pBAEntry, - IN ULONG Now32) - -{ - USHORT Sequence; - -// if ((RTMP_TIME_AFTER((unsigned long)Now32, (unsigned long)(pBAEntry->LastIndSeqAtTimer+REORDERING_PACKET_TIMEOUT)) && -// (pBAEntry->list.qlen > ((pBAEntry->BAWinSize*7)/8))) //|| -// (RTMP_TIME_AFTER((unsigned long)Now32, (unsigned long)(pBAEntry->LastIndSeqAtTimer+(10*REORDERING_PACKET_TIMEOUT))) && -// (pBAEntry->list.qlen > (pBAEntry->BAWinSize/8))) - if (RTMP_TIME_AFTER((unsigned long)Now32, (unsigned long)(pBAEntry->LastIndSeqAtTimer+(MAX_REORDERING_PACKET_TIMEOUT/6))) - &&(pBAEntry->list.qlen > 1) - ) - { - DBGPRINT(RT_DEBUG_TRACE,("timeout[%d] (%08lx-%08lx = %d > %d): %x, flush all!\n ", pBAEntry->list.qlen, Now32, (pBAEntry->LastIndSeqAtTimer), - (int)((long) Now32 - (long)(pBAEntry->LastIndSeqAtTimer)), MAX_REORDERING_PACKET_TIMEOUT, - pBAEntry->LastIndSeq)); - ba_refresh_reordering_mpdus(pAd, pBAEntry); - pBAEntry->LastIndSeqAtTimer = Now32; - } - else - if (RTMP_TIME_AFTER((unsigned long)Now32, (unsigned long)(pBAEntry->LastIndSeqAtTimer+(REORDERING_PACKET_TIMEOUT))) - && (pBAEntry->list.qlen > 0) - ) - { -// printk("timeout[%d] (%lx-%lx = %d > %d): %x, ", pBAEntry->list.qlen, Now32, (pBAEntry->LastIndSeqAtTimer), -// (int)((long) Now32 - (long)(pBAEntry->LastIndSeqAtTimer)), REORDERING_PACKET_TIMEOUT, -// pBAEntry->LastIndSeq); - // - // force LastIndSeq to shift to LastIndSeq+1 - // - Sequence = (pBAEntry->LastIndSeq+1) & MAXSEQ; - ba_indicate_reordering_mpdus_le_seq(pAd, pBAEntry, Sequence); - pBAEntry->LastIndSeqAtTimer = Now32; - pBAEntry->LastIndSeq = Sequence; - // - // indicate in-order mpdus - // - Sequence = ba_indicate_reordering_mpdus_in_order(pAd, pBAEntry, Sequence); - if (Sequence != RESET_RCV_SEQ) - { - pBAEntry->LastIndSeq = Sequence; - } - - //printk("%x, flush one!\n", pBAEntry->LastIndSeq); - - } -} - - -/* - * generate ADDBA request to - * set up BA agreement - */ -VOID BAOriSessionSetUp( - IN PRTMP_ADAPTER pAd, - IN MAC_TABLE_ENTRY *pEntry, - IN UCHAR TID, - IN USHORT TimeOut, - IN ULONG DelayTime, - IN BOOLEAN isForced) - -{ - //MLME_ADDBA_REQ_STRUCT AddbaReq; - BA_ORI_ENTRY *pBAEntry = NULL; - USHORT Idx; - BOOLEAN Cancelled; - - if ((pAd->CommonCfg.BACapability.field.AutoBA != TRUE) && (isForced == FALSE)) - return; - - // if this entry is limited to use legacy tx mode, it doesn't generate BA. - if (RTMPStaFixedTxMode(pAd, pEntry) != FIXED_TXMODE_HT) - return; - - if ((pEntry->BADeclineBitmap & (1<BAOriWcidArray[TID]; - if (Idx == 0) - { - // allocate a BA session - pBAEntry = BATableAllocOriEntry(pAd, &Idx); - if (pBAEntry == NULL) - { - DBGPRINT(RT_DEBUG_TRACE,("ADDBA - MlmeADDBAAction() allocate BA session failed \n")); - return; - } - } - else - { - pBAEntry =&pAd->BATable.BAOriEntry[Idx]; - } - - if (pBAEntry->ORI_BA_Status >= Originator_WaitRes) - { - return; - } - - pEntry->BAOriWcidArray[TID] = Idx; - - // Initialize BA session - pBAEntry->ORI_BA_Status = Originator_WaitRes; - pBAEntry->Wcid = pEntry->Aid; - pBAEntry->BAWinSize = pAd->CommonCfg.BACapability.field.RxBAWinLimit; - pBAEntry->Sequence = BA_ORI_INIT_SEQ; - pBAEntry->Token = 1; // (2008-01-21) Jan Lee recommends it - this token can't be 0 - pBAEntry->TID = TID; - pBAEntry->TimeOutValue = TimeOut; - pBAEntry->pAdapter = pAd; - - DBGPRINT(RT_DEBUG_TRACE,("Send AddBA to %02x:%02x:%02x:%02x:%02x:%02x Tid:%d isForced:%d Wcid:%d\n" - ,pEntry->Addr[0],pEntry->Addr[1],pEntry->Addr[2] - ,pEntry->Addr[3],pEntry->Addr[4],pEntry->Addr[5] - ,TID,isForced,pEntry->Aid)); - - if (!(pEntry->TXBAbitmap & (1<ORIBATimer, GET_TIMER_FUNCTION(BAOriSessionSetupTimeout), pBAEntry, FALSE); - } - else - RTMPCancelTimer(&pBAEntry->ORIBATimer, &Cancelled); - - // set timer to send ADDBA request - RTMPSetTimer(&pBAEntry->ORIBATimer, DelayTime); -} - -VOID BAOriSessionAdd( - IN PRTMP_ADAPTER pAd, - IN MAC_TABLE_ENTRY *pEntry, - IN PFRAME_ADDBA_RSP pFrame) -{ - BA_ORI_ENTRY *pBAEntry = NULL; - BOOLEAN Cancelled; - UCHAR TID; - USHORT Idx; - PUCHAR pOutBuffer2 = NULL; - NDIS_STATUS NStatus; - ULONG FrameLen; - FRAME_BAR FrameBar; - - TID = pFrame->BaParm.TID; - Idx = pEntry->BAOriWcidArray[TID]; - pBAEntry =&pAd->BATable.BAOriEntry[Idx]; - - // Start fill in parameters. - if ((Idx !=0) && (pBAEntry->TID == TID) && (pBAEntry->ORI_BA_Status == Originator_WaitRes)) - { - pBAEntry->BAWinSize = min(pBAEntry->BAWinSize, ((UCHAR)pFrame->BaParm.BufSize)); - BA_MaxWinSizeReasign(pAd, pEntry, &pBAEntry->BAWinSize); - - pBAEntry->TimeOutValue = pFrame->TimeOutValue; - pBAEntry->ORI_BA_Status = Originator_Done; - // reset sequence number - pBAEntry->Sequence = BA_ORI_INIT_SEQ; - // Set Bitmap flag. - pEntry->TXBAbitmap |= (1<ORIBATimer, &Cancelled); - - pBAEntry->ORIBATimer.TimerValue = 0; //pFrame->TimeOutValue; - - DBGPRINT(RT_DEBUG_TRACE,("%s : TXBAbitmap = %x, BAWinSize = %d, TimeOut = %ld\n", __FUNCTION__, pEntry->TXBAbitmap, - pBAEntry->BAWinSize, pBAEntry->ORIBATimer.TimerValue)); - - // SEND BAR ; - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer2); //Get an unused nonpaged memory - if (NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_TRACE,("BA - BAOriSessionAdd() allocate memory failed \n")); - return; - } - - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - BarHeaderInit(pAd, &FrameBar, pAd->MacTab.Content[pBAEntry->Wcid].Addr, pAd->CurrentAddress); -#endif // CONFIG_STA_SUPPORT // - - FrameBar.StartingSeq.field.FragNum = 0; // make sure sequence not clear in DEL function. - FrameBar.StartingSeq.field.StartSeq = pBAEntry->Sequence; // make sure sequence not clear in DEL funciton. - FrameBar.BarControl.TID = pBAEntry->TID; // make sure sequence not clear in DEL funciton. - MakeOutgoingFrame(pOutBuffer2, &FrameLen, - sizeof(FRAME_BAR), &FrameBar, - END_OF_ARGS); - MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer2, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer2); - - - if (pBAEntry->ORIBATimer.TimerValue) - RTMPSetTimer(&pBAEntry->ORIBATimer, pBAEntry->ORIBATimer.TimerValue); // in mSec - } -} - -BOOLEAN BARecSessionAdd( - IN PRTMP_ADAPTER pAd, - IN MAC_TABLE_ENTRY *pEntry, - IN PFRAME_ADDBA_REQ pFrame) -{ - BA_REC_ENTRY *pBAEntry = NULL; - BOOLEAN Status = TRUE; - BOOLEAN Cancelled; - USHORT Idx; - UCHAR TID; - UCHAR BAWinSize; - //UINT32 Value; - //UINT offset; - - - ASSERT(pEntry); - - // find TID - TID = pFrame->BaParm.TID; - - BAWinSize = min(((UCHAR)pFrame->BaParm.BufSize), (UCHAR)pAd->CommonCfg.BACapability.field.RxBAWinLimit); - - // Intel patch - if (BAWinSize == 0) - { - BAWinSize = 64; - } - - Idx = pEntry->BARecWcidArray[TID]; - - - if (Idx == 0) - { - pBAEntry = BATableAllocRecEntry(pAd, &Idx); - } - else - { - pBAEntry = &pAd->BATable.BARecEntry[Idx]; - // flush all pending reordering mpdus - ba_refresh_reordering_mpdus(pAd, pBAEntry); - } - - DBGPRINT(RT_DEBUG_TRACE,("%s(%ld): Idx = %d, BAWinSize(req %d) = %d\n", __FUNCTION__, pAd->BATable.numAsRecipient, Idx, - pFrame->BaParm.BufSize, BAWinSize)); - - // Start fill in parameters. - if (pBAEntry != NULL) - { - ASSERT(pBAEntry->list.qlen == 0); - - pBAEntry->REC_BA_Status = Recipient_HandleRes; - pBAEntry->BAWinSize = BAWinSize; - pBAEntry->Wcid = pEntry->Aid; - pBAEntry->TID = TID; - pBAEntry->TimeOutValue = pFrame->TimeOutValue; - pBAEntry->REC_BA_Status = Recipient_Accept; - // initial sequence number - pBAEntry->LastIndSeq = RESET_RCV_SEQ; //pFrame->BaStartSeq.field.StartSeq; - - printk("Start Seq = %08x\n", pFrame->BaStartSeq.field.StartSeq); - - if (pEntry->RXBAbitmap & (1<RECBATimer, &Cancelled); - } - else - { - RTMPInitTimer(pAd, &pBAEntry->RECBATimer, GET_TIMER_FUNCTION(BARecSessionIdleTimeout), pBAEntry, TRUE); - } - - // Set Bitmap flag. - pEntry->RXBAbitmap |= (1<BARecWcidArray[TID] = Idx; - - pEntry->BADeclineBitmap &= ~(1<Aid, TID); - - DBGPRINT(RT_DEBUG_TRACE,("MACEntry[%d]RXBAbitmap = 0x%x. BARecWcidArray=%d\n", - pEntry->Aid, pEntry->RXBAbitmap, pEntry->BARecWcidArray[TID])); - } - else - { - Status = FALSE; - DBGPRINT(RT_DEBUG_TRACE,("Can't Accept ADDBA for %02x:%02x:%02x:%02x:%02x:%02x TID = %d\n", - PRINT_MAC(pEntry->Addr), TID)); - } - return(Status); -} - - -BA_REC_ENTRY *BATableAllocRecEntry( - IN PRTMP_ADAPTER pAd, - OUT USHORT *Idx) -{ - int i; - BA_REC_ENTRY *pBAEntry = NULL; - - - NdisAcquireSpinLock(&pAd->BATabLock); - - if (pAd->BATable.numAsRecipient >= MAX_BARECI_SESSION) - { - printk("BA Recipeint Session (%ld) > %d\n", pAd->BATable.numAsRecipient, - MAX_BARECI_SESSION); - goto done; - } - - // reserve idx 0 to identify BAWcidArray[TID] as empty - for (i=1; i < MAX_LEN_OF_BA_REC_TABLE; i++) - { - pBAEntry =&pAd->BATable.BARecEntry[i]; - if ((pBAEntry->REC_BA_Status == Recipient_NONE)) - { - // get one - pAd->BATable.numAsRecipient++; - pBAEntry->REC_BA_Status = Recipient_USED; - *Idx = i; - break; - } - } - -done: - NdisReleaseSpinLock(&pAd->BATabLock); - return pBAEntry; -} - -BA_ORI_ENTRY *BATableAllocOriEntry( - IN PRTMP_ADAPTER pAd, - OUT USHORT *Idx) -{ - int i; - BA_ORI_ENTRY *pBAEntry = NULL; - - NdisAcquireSpinLock(&pAd->BATabLock); - - if (pAd->BATable.numAsOriginator >= (MAX_LEN_OF_BA_ORI_TABLE)) - { - goto done; - } - - // reserve idx 0 to identify BAWcidArray[TID] as empty - for (i=1; iBATable.BAOriEntry[i]; - if ((pBAEntry->ORI_BA_Status == Originator_NONE)) - { - // get one - pAd->BATable.numAsOriginator++; - pBAEntry->ORI_BA_Status = Originator_USED; - pBAEntry->pAdapter = pAd; - *Idx = i; - break; - } - } - -done: - NdisReleaseSpinLock(&pAd->BATabLock); - return pBAEntry; -} - - -VOID BATableFreeOriEntry( - IN PRTMP_ADAPTER pAd, - IN ULONG Idx) -{ - BA_ORI_ENTRY *pBAEntry = NULL; - MAC_TABLE_ENTRY *pEntry; - - - if ((Idx == 0) || (Idx >= MAX_LEN_OF_BA_ORI_TABLE)) - return; - - pBAEntry =&pAd->BATable.BAOriEntry[Idx]; - - if (pBAEntry->ORI_BA_Status != Originator_NONE) - { - pEntry = &pAd->MacTab.Content[pBAEntry->Wcid]; - pEntry->BAOriWcidArray[pBAEntry->TID] = 0; - - - NdisAcquireSpinLock(&pAd->BATabLock); - if (pBAEntry->ORI_BA_Status == Originator_Done) - { - pEntry->TXBAbitmap &= (~(1<<(pBAEntry->TID) )); - DBGPRINT(RT_DEBUG_TRACE, ("BATableFreeOriEntry numAsOriginator= %ld\n", pAd->BATable.numAsRecipient)); - // Erase Bitmap flag. - } - - ASSERT(pAd->BATable.numAsOriginator != 0); - - pAd->BATable.numAsOriginator -= 1; - - pBAEntry->ORI_BA_Status = Originator_NONE; - pBAEntry->Token = 0; - NdisReleaseSpinLock(&pAd->BATabLock); - } -} - - -VOID BATableFreeRecEntry( - IN PRTMP_ADAPTER pAd, - IN ULONG Idx) -{ - BA_REC_ENTRY *pBAEntry = NULL; - MAC_TABLE_ENTRY *pEntry; - - - if ((Idx == 0) || (Idx >= MAX_LEN_OF_BA_REC_TABLE)) - return; - - pBAEntry =&pAd->BATable.BARecEntry[Idx]; - - if (pBAEntry->REC_BA_Status != Recipient_NONE) - { - pEntry = &pAd->MacTab.Content[pBAEntry->Wcid]; - pEntry->BARecWcidArray[pBAEntry->TID] = 0; - - NdisAcquireSpinLock(&pAd->BATabLock); - - ASSERT(pAd->BATable.numAsRecipient != 0); - - pAd->BATable.numAsRecipient -= 1; - - pBAEntry->REC_BA_Status = Recipient_NONE; - NdisReleaseSpinLock(&pAd->BATabLock); - } -} - - -VOID BAOriSessionTearDown( - IN OUT PRTMP_ADAPTER pAd, - IN UCHAR Wcid, - IN UCHAR TID, - IN BOOLEAN bPassive, - IN BOOLEAN bForceSend) -{ - ULONG Idx = 0; - BA_ORI_ENTRY *pBAEntry; - BOOLEAN Cancelled; - - if (Wcid >= MAX_LEN_OF_MAC_TABLE) - { - return; - } - - // - // Locate corresponding BA Originator Entry in BA Table with the (pAddr,TID). - // - Idx = pAd->MacTab.Content[Wcid].BAOriWcidArray[TID]; - if ((Idx == 0) || (Idx >= MAX_LEN_OF_BA_ORI_TABLE)) - { - if (bForceSend == TRUE) - { - // force send specified TID DelBA - MLME_DELBA_REQ_STRUCT DelbaReq; - MLME_QUEUE_ELEM *Elem = (MLME_QUEUE_ELEM *) kmalloc(sizeof(MLME_QUEUE_ELEM), MEM_ALLOC_FLAG); - - NdisZeroMemory(&DelbaReq, sizeof(DelbaReq)); - NdisZeroMemory(Elem, sizeof(MLME_QUEUE_ELEM)); - - COPY_MAC_ADDR(DelbaReq.Addr, pAd->MacTab.Content[Wcid].Addr); - DelbaReq.Wcid = Wcid; - DelbaReq.TID = TID; - DelbaReq.Initiator = ORIGINATOR; -#if 1 - Elem->MsgLen = sizeof(DelbaReq); - NdisMoveMemory(Elem->Msg, &DelbaReq, sizeof(DelbaReq)); - MlmeDELBAAction(pAd, Elem); - kfree(Elem); -#else - MlmeEnqueue(pAd, ACTION_STATE_MACHINE, MT2_MLME_ORI_DELBA_CATE, sizeof(MLME_DELBA_REQ_STRUCT), (PVOID)&DelbaReq); - RT28XX_MLME_HANDLER(pAd); -#endif - } - - return; - } - - DBGPRINT(RT_DEBUG_TRACE,("%s===>Wcid=%d.TID=%d \n", __FUNCTION__, Wcid, TID)); - - pBAEntry = &pAd->BATable.BAOriEntry[Idx]; - DBGPRINT(RT_DEBUG_TRACE,("\t===>Idx = %ld, Wcid=%d.TID=%d, ORI_BA_Status = %d \n", Idx, Wcid, TID, pBAEntry->ORI_BA_Status)); - // - // Prepare DelBA action frame and send to the peer. - // - if ((bPassive == FALSE) && (TID == pBAEntry->TID) && (pBAEntry->ORI_BA_Status == Originator_Done)) - { - MLME_DELBA_REQ_STRUCT DelbaReq; - MLME_QUEUE_ELEM *Elem = (MLME_QUEUE_ELEM *) kmalloc(sizeof(MLME_QUEUE_ELEM), MEM_ALLOC_FLAG); - - NdisZeroMemory(&DelbaReq, sizeof(DelbaReq)); - NdisZeroMemory(Elem, sizeof(MLME_QUEUE_ELEM)); - - COPY_MAC_ADDR(DelbaReq.Addr, pAd->MacTab.Content[Wcid].Addr); - DelbaReq.Wcid = Wcid; - DelbaReq.TID = pBAEntry->TID; - DelbaReq.Initiator = ORIGINATOR; -#if 1 - Elem->MsgLen = sizeof(DelbaReq); - NdisMoveMemory(Elem->Msg, &DelbaReq, sizeof(DelbaReq)); - MlmeDELBAAction(pAd, Elem); - kfree(Elem); -#else - MlmeEnqueue(pAd, ACTION_STATE_MACHINE, MT2_MLME_ORI_DELBA_CATE, sizeof(MLME_DELBA_REQ_STRUCT), (PVOID)&DelbaReq); - RT28XX_MLME_HANDLER(pAd); -#endif - } - RTMPCancelTimer(&pBAEntry->ORIBATimer, &Cancelled); - BATableFreeOriEntry(pAd, Idx); - - if (bPassive) - { - //BAOriSessionSetUp(pAd, &pAd->MacTab.Content[Wcid], TID, 0, 10000, TRUE); - } -} - -VOID BARecSessionTearDown( - IN OUT PRTMP_ADAPTER pAd, - IN UCHAR Wcid, - IN UCHAR TID, - IN BOOLEAN bPassive) -{ - ULONG Idx = 0; - BA_REC_ENTRY *pBAEntry; - - if (Wcid >= MAX_LEN_OF_MAC_TABLE) - { - return; - } - - // - // Locate corresponding BA Originator Entry in BA Table with the (pAddr,TID). - // - Idx = pAd->MacTab.Content[Wcid].BARecWcidArray[TID]; - if (Idx == 0) - return; - - DBGPRINT(RT_DEBUG_TRACE,("%s===>Wcid=%d.TID=%d \n", __FUNCTION__, Wcid, TID)); - - - pBAEntry = &pAd->BATable.BARecEntry[Idx]; - DBGPRINT(RT_DEBUG_TRACE,("\t===>Idx = %ld, Wcid=%d.TID=%d, REC_BA_Status = %d \n", Idx, Wcid, TID, pBAEntry->REC_BA_Status)); - // - // Prepare DelBA action frame and send to the peer. - // - if ((TID == pBAEntry->TID) && (pBAEntry->REC_BA_Status == Recipient_Accept)) - { - MLME_DELBA_REQ_STRUCT DelbaReq; - BOOLEAN Cancelled; - MLME_QUEUE_ELEM *Elem = (MLME_QUEUE_ELEM *) kmalloc(sizeof(MLME_QUEUE_ELEM), MEM_ALLOC_FLAG); - //ULONG offset; - //UINT32 VALUE; - - RTMPCancelTimer(&pBAEntry->RECBATimer, &Cancelled); - - // - // 1. Send DELBA Action Frame - // - if (bPassive == FALSE) - { - NdisZeroMemory(&DelbaReq, sizeof(DelbaReq)); - NdisZeroMemory(Elem, sizeof(MLME_QUEUE_ELEM)); - - COPY_MAC_ADDR(DelbaReq.Addr, pAd->MacTab.Content[Wcid].Addr); - DelbaReq.Wcid = Wcid; - DelbaReq.TID = TID; - DelbaReq.Initiator = RECIPIENT; -#if 1 - Elem->MsgLen = sizeof(DelbaReq); - NdisMoveMemory(Elem->Msg, &DelbaReq, sizeof(DelbaReq)); - MlmeDELBAAction(pAd, Elem); - kfree(Elem); -#else - MlmeEnqueue(pAd, ACTION_STATE_MACHINE, MT2_MLME_ORI_DELBA_CATE, sizeof(MLME_DELBA_REQ_STRUCT), (PVOID)&DelbaReq); - RT28XX_MLME_HANDLER(pAd); -#endif - } - - - // - // 2. Free resource of BA session - // - // flush all pending reordering mpdus - ba_refresh_reordering_mpdus(pAd, pBAEntry); - - NdisAcquireSpinLock(&pAd->BATabLock); - - // Erase Bitmap flag. - pBAEntry->LastIndSeq = RESET_RCV_SEQ; - pBAEntry->BAWinSize = 0; - // Erase Bitmap flag at software mactable - pAd->MacTab.Content[Wcid].RXBAbitmap &= (~(1<<(pBAEntry->TID))); - pAd->MacTab.Content[Wcid].BARecWcidArray[TID] = 0; - - RT28XX_DEL_BA_SESSION_FROM_ASIC(pAd, Wcid, TID); - - NdisReleaseSpinLock(&pAd->BATabLock); - - } - - BATableFreeRecEntry(pAd, Idx); -} - -VOID BASessionTearDownALL( - IN OUT PRTMP_ADAPTER pAd, - IN UCHAR Wcid) -{ - int i; - - for (i=0; ipAdapter; - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - // Do nothing if monitor mode is on - if (MONITOR_ON(pAd)) - return; - } -#endif // CONFIG_STA_SUPPORT // - -#ifdef RALINK_ATE - // Nothing to do in ATE mode. - if (ATE_ON(pAd)) - return; -#endif // RALINK_ATE // - - pEntry = &pAd->MacTab.Content[pBAEntry->Wcid]; - - if ((pBAEntry->ORI_BA_Status == Originator_WaitRes) && (pBAEntry->Token < ORI_SESSION_MAX_RETRY)) - { - MLME_ADDBA_REQ_STRUCT AddbaReq; - - NdisZeroMemory(&AddbaReq, sizeof(AddbaReq)); - COPY_MAC_ADDR(AddbaReq.pAddr, pEntry->Addr); - AddbaReq.Wcid = (UCHAR)(pEntry->Aid); - AddbaReq.TID = pBAEntry->TID; - AddbaReq.BaBufSize = pAd->CommonCfg.BACapability.field.RxBAWinLimit; - AddbaReq.TimeOutValue = 0; - AddbaReq.Token = pBAEntry->Token; - MlmeEnqueue(pAd, ACTION_STATE_MACHINE, MT2_MLME_ADD_BA_CATE, sizeof(MLME_ADDBA_REQ_STRUCT), (PVOID)&AddbaReq); - RT28XX_MLME_HANDLER(pAd); - //DBGPRINT(RT_DEBUG_TRACE,("BA Ori Session Timeout(%d) : Send ADD BA again\n", pBAEntry->Token)); - - DBGPRINT(RT_DEBUG_TRACE,("BA Ori Session Timeout(%d) to %02x:%02x:%02x:%02x:%02x:%02x Tid:%d Wcid:%d\n" - ,pBAEntry->Token - ,pEntry->Addr[0],pEntry->Addr[1],pEntry->Addr[2] - ,pEntry->Addr[3],pEntry->Addr[4],pEntry->Addr[5] - ,pBAEntry->TID,pEntry->Aid)); - - pBAEntry->Token++; - RTMPSetTimer(&pBAEntry->ORIBATimer, ORI_BA_SESSION_TIMEOUT); - } - else - { - BATableFreeOriEntry(pAd, pEntry->BAOriWcidArray[pBAEntry->TID]); - } -} - -/* - ========================================================================== - Description: - Retry sending ADDBA Reqest. - - IRQL = DISPATCH_LEVEL - - Parametrs: - p8023Header: if this is already 802.3 format, p8023Header is NULL - - Return : TRUE if put into rx reordering buffer, shouldn't indicaterxhere. - FALSE , then continue indicaterx at this moment. - ========================================================================== - */ -VOID BARecSessionIdleTimeout( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3) -{ - - BA_REC_ENTRY *pBAEntry = (BA_REC_ENTRY *)FunctionContext; - PRTMP_ADAPTER pAd; - ULONG Now32; - - if (pBAEntry == NULL) - return; - - if ((pBAEntry->REC_BA_Status == Recipient_Accept)) - { - NdisGetSystemUpTime(&Now32); - - if (RTMP_TIME_AFTER((unsigned long)Now32, (unsigned long)(pBAEntry->LastIndSeqAtTimer + REC_BA_SESSION_IDLE_TIMEOUT))) - { - pAd = pBAEntry->pAdapter; - // flush all pending reordering mpdus - ba_refresh_reordering_mpdus(pAd, pBAEntry); - printk("%ld: REC BA session Timeout\n", Now32); - } - } -} - - -VOID PeerAddBAReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) - -{ - // 7.4.4.1 - //ULONG Idx; - UCHAR Status = 1; - UCHAR pAddr[6]; - FRAME_ADDBA_RSP ADDframe; - PUCHAR pOutBuffer = NULL; - NDIS_STATUS NStatus; - PFRAME_ADDBA_REQ pAddreqFrame = NULL; - //UCHAR BufSize; - ULONG FrameLen; - PULONG ptemp; - PMAC_TABLE_ENTRY pMacEntry; - - DBGPRINT(RT_DEBUG_TRACE, ("%s ==> (Wcid = %d)\n", __FUNCTION__, Elem->Wcid)); - - //hex_dump("AddBAReq", Elem->Msg, Elem->MsgLen); - - //ADDBA Request from unknown peer, ignore this. - if (Elem->Wcid >= MAX_LEN_OF_MAC_TABLE) - return; - - pMacEntry = &pAd->MacTab.Content[Elem->Wcid]; - DBGPRINT(RT_DEBUG_TRACE,("BA - PeerAddBAReqAction----> \n")); - ptemp = (PULONG)Elem->Msg; - //DBGPRINT_RAW(RT_DEBUG_EMU, ("%08x:: %08x:: %08x:: %08x:: %08x:: %08x:: %08x:: %08x:: %08x\n", *(ptemp), *(ptemp+1), *(ptemp+2), *(ptemp+3), *(ptemp+4), *(ptemp+5), *(ptemp+6), *(ptemp+7), *(ptemp+8))); - - if (PeerAddBAReqActionSanity(pAd, Elem->Msg, Elem->MsgLen, pAddr)) - { - - if ((pAd->CommonCfg.bBADecline == FALSE) && IS_HT_STA(pMacEntry)) - { - pAddreqFrame = (PFRAME_ADDBA_REQ)(&Elem->Msg[0]); - printk("Rcv Wcid(%d) AddBAReq\n", Elem->Wcid); - if (BARecSessionAdd(pAd, &pAd->MacTab.Content[Elem->Wcid], pAddreqFrame)) - Status = 0; - else - Status = 38; // more parameters have invalid values - } - else - { - Status = 37; // the request has been declined. - } - } - - if (pAd->MacTab.Content[Elem->Wcid].ValidAsCLI) - ASSERT(pAd->MacTab.Content[Elem->Wcid].Sst == SST_ASSOC); - - pAddreqFrame = (PFRAME_ADDBA_REQ)(&Elem->Msg[0]); - // 2. Always send back ADDBA Response - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory - if (NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_TRACE,("ACTION - PeerBAAction() allocate memory failed \n")); - return; - } - - NdisZeroMemory(&ADDframe, sizeof(FRAME_ADDBA_RSP)); - // 2-1. Prepare ADDBA Response frame. -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - if (ADHOC_ON(pAd)) - ActHeaderInit(pAd, &ADDframe.Hdr, pAddr, pAd->CurrentAddress, pAd->CommonCfg.Bssid); - else - ActHeaderInit(pAd, &ADDframe.Hdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pAddr); - } -#endif // CONFIG_STA_SUPPORT // - ADDframe.Category = CATEGORY_BA; - ADDframe.Action = ADDBA_RESP; - ADDframe.Token = pAddreqFrame->Token; - // What is the Status code?? need to check. - ADDframe.StatusCode = Status; - ADDframe.BaParm.BAPolicy = IMMED_BA; - ADDframe.BaParm.AMSDUSupported = 0; - ADDframe.BaParm.TID = pAddreqFrame->BaParm.TID; - ADDframe.BaParm.BufSize = min(((UCHAR)pAddreqFrame->BaParm.BufSize), (UCHAR)pAd->CommonCfg.BACapability.field.RxBAWinLimit); - if (ADDframe.BaParm.BufSize == 0) - { - ADDframe.BaParm.BufSize = 64; - } - ADDframe.TimeOutValue = 0; //pAddreqFrame->TimeOutValue; - - *(USHORT *)(&ADDframe.BaParm) = cpu2le16(*(USHORT *)(&ADDframe.BaParm)); - ADDframe.StatusCode = cpu2le16(ADDframe.StatusCode); - ADDframe.TimeOutValue = cpu2le16(ADDframe.TimeOutValue); - - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(FRAME_ADDBA_RSP), &ADDframe, - END_OF_ARGS); - MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); - - DBGPRINT(RT_DEBUG_TRACE, ("%s(%d): TID(%d), BufSize(%d) <== \n", __FUNCTION__, Elem->Wcid, ADDframe.BaParm.TID, - ADDframe.BaParm.BufSize)); -} - - -VOID PeerAddBARspAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) - -{ - //UCHAR Idx, i; - //PUCHAR pOutBuffer = NULL; - PFRAME_ADDBA_RSP pFrame = NULL; - //PBA_ORI_ENTRY pBAEntry; - - //ADDBA Response from unknown peer, ignore this. - if (Elem->Wcid >= MAX_LEN_OF_MAC_TABLE) - return; - - DBGPRINT(RT_DEBUG_TRACE, ("%s ==> Wcid(%d)\n", __FUNCTION__, Elem->Wcid)); - - //hex_dump("PeerAddBARspAction()", Elem->Msg, Elem->MsgLen); - - if (PeerAddBARspActionSanity(pAd, Elem->Msg, Elem->MsgLen)) - { - pFrame = (PFRAME_ADDBA_RSP)(&Elem->Msg[0]); - - DBGPRINT(RT_DEBUG_TRACE, ("\t\t StatusCode = %d\n", pFrame->StatusCode)); - switch (pFrame->StatusCode) - { - case 0: - // I want a BAsession with this peer as an originator. - BAOriSessionAdd(pAd, &pAd->MacTab.Content[Elem->Wcid], pFrame); - break; - default: - // check status == USED ??? - BAOriSessionTearDown(pAd, Elem->Wcid, pFrame->BaParm.TID, TRUE, FALSE); - break; - } - // Rcv Decline StatusCode - if ((pFrame->StatusCode == 37) -#ifdef CONFIG_STA_SUPPORT - || ((pAd->OpMode == OPMODE_STA) && STA_TGN_WIFI_ON(pAd) && (pFrame->StatusCode != 0)) -#endif // CONFIG_STA_SUPPORT // - ) - { - pAd->MacTab.Content[Elem->Wcid].BADeclineBitmap |= 1<BaParm.TID; - } - } -} - -VOID PeerDelBAAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) - -{ - //UCHAR Idx; - //PUCHAR pOutBuffer = NULL; - PFRAME_DELBA_REQ pDelFrame = NULL; - - DBGPRINT(RT_DEBUG_TRACE,("%s ==>\n", __FUNCTION__)); - //DELBA Request from unknown peer, ignore this. - if (PeerDelBAActionSanity(pAd, Elem->Wcid, Elem->Msg, Elem->MsgLen)) - { - pDelFrame = (PFRAME_DELBA_REQ)(&Elem->Msg[0]); - if (pDelFrame->DelbaParm.Initiator == ORIGINATOR) - { - DBGPRINT(RT_DEBUG_TRACE,("BA - PeerDelBAAction----> ORIGINATOR\n")); - BARecSessionTearDown(pAd, Elem->Wcid, pDelFrame->DelbaParm.TID, TRUE); - } - else - { - DBGPRINT(RT_DEBUG_TRACE,("BA - PeerDelBAAction----> RECIPIENT, Reason = %d\n", pDelFrame->ReasonCode)); - //hex_dump("DelBA Frame", pDelFrame, Elem->MsgLen); - BAOriSessionTearDown(pAd, Elem->Wcid, pDelFrame->DelbaParm.TID, TRUE, FALSE); - } - } -} - - -BOOLEAN CntlEnqueueForRecv( - IN PRTMP_ADAPTER pAd, - IN ULONG Wcid, - IN ULONG MsgLen, - IN PFRAME_BA_REQ pMsg) -{ - PFRAME_BA_REQ pFrame = pMsg; - //PRTMP_REORDERBUF pBuffer; - //PRTMP_REORDERBUF pDmaBuf; - PBA_REC_ENTRY pBAEntry; - //BOOLEAN Result; - ULONG Idx; - //UCHAR NumRxPkt; - UCHAR TID;//, i; - - TID = (UCHAR)pFrame->BARControl.TID; - - DBGPRINT(RT_DEBUG_TRACE, ("%s(): BAR-Wcid(%ld), Tid (%d)\n", __FUNCTION__, Wcid, TID)); - //hex_dump("BAR", (PCHAR) pFrame, MsgLen); - // Do nothing if the driver is starting halt state. - // This might happen when timer already been fired before cancel timer with mlmehalt - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) - return FALSE; - - // First check the size, it MUST not exceed the mlme queue size - if (MsgLen > MGMT_DMA_BUFFER_SIZE) - { - DBGPRINT_ERR(("CntlEnqueueForRecv: frame too large, size = %ld \n", MsgLen)); - return FALSE; - } - else if (MsgLen != sizeof(FRAME_BA_REQ)) - { - DBGPRINT_ERR(("CntlEnqueueForRecv: BlockAck Request frame length size = %ld incorrect\n", MsgLen)); - return FALSE; - } - else if (MsgLen != sizeof(FRAME_BA_REQ)) - { - DBGPRINT_ERR(("CntlEnqueueForRecv: BlockAck Request frame length size = %ld incorrect\n", MsgLen)); - return FALSE; - } - - if ((Wcid < MAX_LEN_OF_MAC_TABLE) && (TID < 8)) - { - // if this receiving packet is from SA that is in our OriEntry. Since WCID <9 has direct mapping. no need search. - Idx = pAd->MacTab.Content[Wcid].BARecWcidArray[TID]; - pBAEntry = &pAd->BATable.BARecEntry[Idx]; - } - else - { - return FALSE; - } - - DBGPRINT(RT_DEBUG_TRACE, ("BAR(%ld) : Tid (%d) - %04x:%04x\n", Wcid, TID, pFrame->BAStartingSeq.field.StartSeq, pBAEntry->LastIndSeq )); - - if (SEQ_SMALLER(pBAEntry->LastIndSeq, pFrame->BAStartingSeq.field.StartSeq, MAXSEQ)) - { - //printk("BAR Seq = %x, LastIndSeq = %x\n", pFrame->BAStartingSeq.field.StartSeq, pBAEntry->LastIndSeq); - ba_indicate_reordering_mpdus_le_seq(pAd, pBAEntry, pFrame->BAStartingSeq.field.StartSeq); - pBAEntry->LastIndSeq = (pFrame->BAStartingSeq.field.StartSeq == 0) ? MAXSEQ :(pFrame->BAStartingSeq.field.StartSeq -1); - } - //ba_refresh_reordering_mpdus(pAd, pBAEntry); - return TRUE; -} - -/* -Description : Send PSMP Action frame If PSMP mode switches. -*/ -VOID SendPSMPAction( - IN PRTMP_ADAPTER pAd, - IN UCHAR Wcid, - IN UCHAR Psmp) -{ - PUCHAR pOutBuffer = NULL; - NDIS_STATUS NStatus; - //ULONG Idx; - FRAME_PSMP_ACTION Frame; - ULONG FrameLen; -#ifdef RT30xx - UCHAR bbpdata=0; - UINT32 macdata; -#endif // RT30xx // - - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory - if (NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_ERROR,("BA - MlmeADDBAAction() allocate memory failed \n")); - return; - } -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - ActHeaderInit(pAd, &Frame.Hdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pAd->MacTab.Content[Wcid].Addr); -#endif // CONFIG_STA_SUPPORT // - - Frame.Category = CATEGORY_HT; - Frame.Action = SMPS_ACTION; - switch (Psmp) - { - case MMPS_ENABLE: -#ifdef RT30xx - if (IS_RT3090(pAd)) - { - // disable MMPS BBP control register - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &bbpdata); - bbpdata &= ~(0x04); //bit 2 - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, bbpdata); - - // disable MMPS MAC control register - RTMP_IO_READ32(pAd, 0x1210, &macdata); - macdata &= ~(0x09); //bit 0, 3 - RTMP_IO_WRITE32(pAd, 0x1210, macdata); - } -#endif // RT30xx // - Frame.Psmp = 0; - break; - case MMPS_DYNAMIC: -#ifdef RT30xx - if (IS_RT3090(pAd)) - { - // enable MMPS BBP control register - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &bbpdata); - bbpdata |= 0x04; //bit 2 - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, bbpdata); - - // enable MMPS MAC control register - RTMP_IO_READ32(pAd, 0x1210, &macdata); - macdata |= 0x09; //bit 0, 3 - RTMP_IO_WRITE32(pAd, 0x1210, macdata); - } -#endif // RT30xx // - Frame.Psmp = 3; - break; - case MMPS_STATIC: -#ifdef RT30xx - if (IS_RT3090(pAd)) - { - // enable MMPS BBP control register - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &bbpdata); - bbpdata |= 0x04; //bit 2 - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, bbpdata); - - // enable MMPS MAC control register - RTMP_IO_READ32(pAd, 0x1210, &macdata); - macdata |= 0x09; //bit 0, 3 - RTMP_IO_WRITE32(pAd, 0x1210, macdata); - } -#endif // RT30xx // - Frame.Psmp = 1; - break; - } - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(FRAME_PSMP_ACTION), &Frame, - END_OF_ARGS); - MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); - DBGPRINT(RT_DEBUG_ERROR,("HT - SendPSMPAction( %d ) \n", Frame.Psmp)); -} - - -#define RADIO_MEASUREMENT_REQUEST_ACTION 0 - -typedef struct PACKED -{ - UCHAR RegulatoryClass; - UCHAR ChannelNumber; - USHORT RandomInterval; - USHORT MeasurementDuration; - UCHAR MeasurementMode; - UCHAR BSSID[MAC_ADDR_LEN]; - UCHAR ReportingCondition; - UCHAR Threshold; - UCHAR SSIDIE[2]; // 2 byte -} BEACON_REQUEST; - -typedef struct PACKED -{ - UCHAR ID; - UCHAR Length; - UCHAR Token; - UCHAR RequestMode; - UCHAR Type; -} MEASUREMENT_REQ; - - - - -void convert_reordering_packet_to_preAMSDU_or_802_3_packet( - IN PRTMP_ADAPTER pAd, - IN RX_BLK *pRxBlk, - IN UCHAR FromWhichBSSID) -{ - PNDIS_PACKET pRxPkt; - UCHAR Header802_3[LENGTH_802_3]; - - // 1. get 802.3 Header - // 2. remove LLC - // a. pointer pRxBlk->pData to payload - // b. modify pRxBlk->DataSize - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - RTMP_802_11_REMOVE_LLC_AND_CONVERT_TO_802_3(pRxBlk, Header802_3); -#endif // CONFIG_STA_SUPPORT // - - ASSERT(pRxBlk->pRxPacket); - pRxPkt = RTPKT_TO_OSPKT(pRxBlk->pRxPacket); - - RTPKT_TO_OSPKT(pRxPkt)->dev = get_netdev_from_bssid(pAd, FromWhichBSSID); - RTPKT_TO_OSPKT(pRxPkt)->data = pRxBlk->pData; - RTPKT_TO_OSPKT(pRxPkt)->len = pRxBlk->DataSize; - RTPKT_TO_OSPKT(pRxPkt)->tail = RTPKT_TO_OSPKT(pRxPkt)->data + RTPKT_TO_OSPKT(pRxPkt)->len; - - // - // copy 802.3 header, if necessary - // - if (!RX_BLK_TEST_FLAG(pRxBlk, fRX_AMSDU)) - { - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { -#ifdef LINUX - NdisMoveMemory(skb_push(pRxPkt, LENGTH_802_3), Header802_3, LENGTH_802_3); -#endif -#ifdef UCOS - NdisMoveMemory(net_pkt_push(pRxPkt, LENGTH_802_3), Header802_3, LENGTH_802_3); -#endif - } -#endif // CONFIG_STA_SUPPORT // - } -} - - -#define INDICATE_LEGACY_OR_AMSDU(_pAd, _pRxBlk, _fromWhichBSSID) \ - do \ - { \ - if (RX_BLK_TEST_FLAG(_pRxBlk, fRX_AMSDU)) \ - { \ - Indicate_AMSDU_Packet(_pAd, _pRxBlk, _fromWhichBSSID); \ - } \ - else if (RX_BLK_TEST_FLAG(_pRxBlk, fRX_EAP)) \ - { \ - Indicate_EAPOL_Packet(_pAd, _pRxBlk, _fromWhichBSSID); \ - } \ - else \ - { \ - Indicate_Legacy_Packet(_pAd, _pRxBlk, _fromWhichBSSID); \ - } \ - } while (0); - - - -static VOID ba_enqueue_reordering_packet( - IN PRTMP_ADAPTER pAd, - IN PBA_REC_ENTRY pBAEntry, - IN RX_BLK *pRxBlk, - IN UCHAR FromWhichBSSID) -{ - struct reordering_mpdu *mpdu_blk; - UINT16 Sequence = (UINT16) pRxBlk->pHeader->Sequence; - - mpdu_blk = ba_mpdu_blk_alloc(pAd); - if (mpdu_blk != NULL) - { - // Write RxD buffer address & allocated buffer length - NdisAcquireSpinLock(&pBAEntry->RxReRingLock); - - mpdu_blk->Sequence = Sequence; - - mpdu_blk->bAMSDU = RX_BLK_TEST_FLAG(pRxBlk, fRX_AMSDU); - - convert_reordering_packet_to_preAMSDU_or_802_3_packet(pAd, pRxBlk, FromWhichBSSID); - - STATS_INC_RX_PACKETS(pAd, FromWhichBSSID); - - // - // it is necessary for reordering packet to record - // which BSS it come from - // - RTMP_SET_PACKET_IF(pRxBlk->pRxPacket, FromWhichBSSID); - - mpdu_blk->pPacket = pRxBlk->pRxPacket; - - if (ba_reordering_mpdu_insertsorted(&pBAEntry->list, mpdu_blk) == FALSE) - { - // had been already within reordering list - // don't indicate - RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_SUCCESS); - ba_mpdu_blk_free(pAd, mpdu_blk); - } - - ASSERT((0<= pBAEntry->list.qlen) && (pBAEntry->list.qlen <= pBAEntry->BAWinSize)); - NdisReleaseSpinLock(&pBAEntry->RxReRingLock); - } - else - { - DBGPRINT(RT_DEBUG_ERROR, ("!!! (%d) Can't allocate reordering mpdu blk\n", - pBAEntry->list.qlen)); - /* - * flush all pending reordering mpdus - * and receving mpdu to upper layer - * make tcp/ip to take care reordering mechanism - */ - //ba_refresh_reordering_mpdus(pAd, pBAEntry); - ba_indicate_reordering_mpdus_le_seq(pAd, pBAEntry, Sequence); - - pBAEntry->LastIndSeq = Sequence; - INDICATE_LEGACY_OR_AMSDU(pAd, pRxBlk, FromWhichBSSID); - } -} - - -/* - ========================================================================== - Description: - Indicate this packet to upper layer or put it into reordering buffer - - Parametrs: - pRxBlk : carry necessary packet info 802.11 format - FromWhichBSSID : the packet received from which BSS - - Return : - none - - Note : - the packet queued into reordering buffer need to cover to 802.3 format - or pre_AMSDU format - ========================================================================== - */ - -VOID Indicate_AMPDU_Packet( - IN PRTMP_ADAPTER pAd, - IN RX_BLK *pRxBlk, - IN UCHAR FromWhichBSSID) -{ - USHORT Idx; - PBA_REC_ENTRY pBAEntry = NULL; - UINT16 Sequence = pRxBlk->pHeader->Sequence; - ULONG Now32; - UCHAR Wcid = pRxBlk->pRxWI->WirelessCliID; - UCHAR TID = pRxBlk->pRxWI->TID; - - - if (!RX_BLK_TEST_FLAG(pRxBlk, fRX_AMSDU) && (pRxBlk->DataSize > MAX_RX_PKT_LEN)) - { - // release packet - RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); - return; - } - - if (Wcid < MAX_LEN_OF_MAC_TABLE) - { - Idx = pAd->MacTab.Content[Wcid].BARecWcidArray[TID]; - if (Idx == 0) - { - /* Rec BA Session had been torn down */ - INDICATE_LEGACY_OR_AMSDU(pAd, pRxBlk, FromWhichBSSID); - return; - } - pBAEntry = &pAd->BATable.BARecEntry[Idx]; - } - else - { - // impossible !!! - ASSERT(0); - // release packet - RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); - return; - } - - ASSERT(pBAEntry); - - // update last rx time - NdisGetSystemUpTime(&Now32); - - pBAEntry->rcvSeq = Sequence; - - - ba_flush_reordering_timeout_mpdus(pAd, pBAEntry, Now32); - pBAEntry->LastIndSeqAtTimer = Now32; - - // - // Reset Last Indicate Sequence - // - if (pBAEntry->LastIndSeq == RESET_RCV_SEQ) - { - ASSERT((pBAEntry->list.qlen == 0) && (pBAEntry->list.next == NULL)); - - // reset rcv sequence of BA session - pBAEntry->LastIndSeq = Sequence; - pBAEntry->LastIndSeqAtTimer = Now32; - INDICATE_LEGACY_OR_AMSDU(pAd, pRxBlk, FromWhichBSSID); - return; - } - - - // - // I. Check if in order. - // - if (SEQ_STEPONE(Sequence, pBAEntry->LastIndSeq, MAXSEQ)) - { - USHORT LastIndSeq; - - pBAEntry->LastIndSeq = Sequence; - INDICATE_LEGACY_OR_AMSDU(pAd, pRxBlk, FromWhichBSSID); - LastIndSeq = ba_indicate_reordering_mpdus_in_order(pAd, pBAEntry, pBAEntry->LastIndSeq); - if (LastIndSeq != RESET_RCV_SEQ) - { - pBAEntry->LastIndSeq = LastIndSeq; - } - pBAEntry->LastIndSeqAtTimer = Now32; - } - // - // II. Drop Duplicated Packet - // - else if (Sequence == pBAEntry->LastIndSeq) - { - - // drop and release packet - pBAEntry->nDropPacket++; - RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); - } - // - // III. Drop Old Received Packet - // - else if (SEQ_SMALLER(Sequence, pBAEntry->LastIndSeq, MAXSEQ)) - { - - // drop and release packet - pBAEntry->nDropPacket++; - RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); - } - // - // IV. Receive Sequence within Window Size - // - else if (SEQ_SMALLER(Sequence, (((pBAEntry->LastIndSeq+pBAEntry->BAWinSize+1)) & MAXSEQ), MAXSEQ)) - { - ba_enqueue_reordering_packet(pAd, pBAEntry, pRxBlk, FromWhichBSSID); - } - // - // V. Receive seq surpasses Win(lastseq + nMSDU). So refresh all reorder buffer - // - else - { - LONG WinStartSeq, TmpSeq; - - - TmpSeq = Sequence - (pBAEntry->BAWinSize) -1; - if (TmpSeq < 0) - { - TmpSeq = (MAXSEQ+1) + TmpSeq; - } - WinStartSeq = (TmpSeq+1) & MAXSEQ; - ba_indicate_reordering_mpdus_le_seq(pAd, pBAEntry, WinStartSeq); - pBAEntry->LastIndSeq = WinStartSeq; //TmpSeq; - - pBAEntry->LastIndSeqAtTimer = Now32; - - ba_enqueue_reordering_packet(pAd, pBAEntry, pRxBlk, FromWhichBSSID); - - TmpSeq = ba_indicate_reordering_mpdus_in_order(pAd, pBAEntry, pBAEntry->LastIndSeq); - if (TmpSeq != RESET_RCV_SEQ) - { - pBAEntry->LastIndSeq = TmpSeq; - } - } -} - -#endif // DOT11_N_SUPPORT // - +#include "../../rt2870/common/ba_action.c" diff --git a/drivers/staging/rt3070/common/cmm_data.c b/drivers/staging/rt3070/common/cmm_data.c index 85f92b9f83da..02e202db4dad 100644 --- a/drivers/staging/rt3070/common/cmm_data.c +++ b/drivers/staging/rt3070/common/cmm_data.c @@ -1,2827 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * 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 "../rt_config.h" - -#define MAX_TX_IN_TBTT (16) - - -UCHAR SNAP_802_1H[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; -UCHAR SNAP_BRIDGE_TUNNEL[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8}; -// Add Cisco Aironet SNAP heade for CCX2 support -UCHAR SNAP_AIRONET[] = {0xaa, 0xaa, 0x03, 0x00, 0x40, 0x96, 0x00, 0x00}; -UCHAR CKIP_LLC_SNAP[] = {0xaa, 0xaa, 0x03, 0x00, 0x40, 0x96, 0x00, 0x02}; -UCHAR EAPOL_LLC_SNAP[]= {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x88, 0x8e}; -UCHAR EAPOL[] = {0x88, 0x8e}; -UCHAR TPID[] = {0x81, 0x00}; /* VLAN related */ - -UCHAR IPX[] = {0x81, 0x37}; -UCHAR APPLE_TALK[] = {0x80, 0xf3}; -UCHAR RateIdToPlcpSignal[12] = { - 0, /* RATE_1 */ 1, /* RATE_2 */ 2, /* RATE_5_5 */ 3, /* RATE_11 */ // see BBP spec - 11, /* RATE_6 */ 15, /* RATE_9 */ 10, /* RATE_12 */ 14, /* RATE_18 */ // see IEEE802.11a-1999 p.14 - 9, /* RATE_24 */ 13, /* RATE_36 */ 8, /* RATE_48 */ 12 /* RATE_54 */ }; // see IEEE802.11a-1999 p.14 - -UCHAR OfdmSignalToRateId[16] = { - RATE_54, RATE_54, RATE_54, RATE_54, // OFDM PLCP Signal = 0, 1, 2, 3 respectively - RATE_54, RATE_54, RATE_54, RATE_54, // OFDM PLCP Signal = 4, 5, 6, 7 respectively - RATE_48, RATE_24, RATE_12, RATE_6, // OFDM PLCP Signal = 8, 9, 10, 11 respectively - RATE_54, RATE_36, RATE_18, RATE_9, // OFDM PLCP Signal = 12, 13, 14, 15 respectively -}; - -UCHAR OfdmRateToRxwiMCS[12] = { - 0, 0, 0, 0, - 0, 1, 2, 3, // OFDM rate 6,9,12,18 = rxwi mcs 0,1,2,3 - 4, 5, 6, 7, // OFDM rate 24,36,48,54 = rxwi mcs 4,5,6,7 -}; -UCHAR RxwiMCSToOfdmRate[12] = { - RATE_6, RATE_9, RATE_12, RATE_18, - RATE_24, RATE_36, RATE_48, RATE_54, // OFDM rate 6,9,12,18 = rxwi mcs 0,1,2,3 - 4, 5, 6, 7, // OFDM rate 24,36,48,54 = rxwi mcs 4,5,6,7 -}; - -char* MCSToMbps[] = {"1Mbps","2Mbps","5.5Mbps","11Mbps","06Mbps","09Mbps","12Mbps","18Mbps","24Mbps","36Mbps","48Mbps","54Mbps","MM-0","MM-1","MM-2","MM-3","MM-4","MM-5","MM-6","MM-7","MM-8","MM-9","MM-10","MM-11","MM-12","MM-13","MM-14","MM-15","MM-32","ee1","ee2","ee3"}; - -UCHAR default_cwmin[]={CW_MIN_IN_BITS, CW_MIN_IN_BITS, CW_MIN_IN_BITS-1, CW_MIN_IN_BITS-2}; -//UCHAR default_cwmax[]={CW_MAX_IN_BITS, CW_MAX_IN_BITS, CW_MIN_IN_BITS, CW_MIN_IN_BITS-1}; -UCHAR default_sta_aifsn[]={3,7,2,2}; - -UCHAR MapUserPriorityToAccessCategory[8] = {QID_AC_BE, QID_AC_BK, QID_AC_BK, QID_AC_BE, QID_AC_VI, QID_AC_VI, QID_AC_VO, QID_AC_VO}; - - -/* - ======================================================================== - - Routine Description: - API for MLME to transmit management frame to AP (BSS Mode) - or station (IBSS Mode) - - Arguments: - pAd Pointer to our adapter - pData Pointer to the outgoing 802.11 frame - Length Size of outgoing management frame - - Return Value: - NDIS_STATUS_FAILURE - NDIS_STATUS_PENDING - NDIS_STATUS_SUCCESS - - IRQL = PASSIVE_LEVEL - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -NDIS_STATUS MiniportMMRequest( - IN PRTMP_ADAPTER pAd, - IN UCHAR QueIdx, - IN PUCHAR pData, - IN UINT Length) -{ - PNDIS_PACKET pPacket; - NDIS_STATUS Status = NDIS_STATUS_SUCCESS; - ULONG FreeNum; - UCHAR IrqState; - UCHAR rtmpHwHdr[TXINFO_SIZE + TXWI_SIZE]; //RTMP_HW_HDR_LEN]; - - ASSERT(Length <= MGMT_DMA_BUFFER_SIZE); - - QueIdx=3; - - // 2860C use Tx Ring - - IrqState = pAd->irq_disabled; - - do - { - // Reset is in progress, stop immediately - if ( RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS) || - RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)|| - !RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_START_UP)) - { - Status = NDIS_STATUS_FAILURE; - break; - } - - // Check Free priority queue - // Since we use PBF Queue2 for management frame. Its corresponding DMA ring should be using TxRing. - - // 2860C use Tx Ring - if (pAd->MACVersion == 0x28600100) - { - FreeNum = GET_TXRING_FREENO(pAd, QueIdx); - } - else - { - FreeNum = GET_MGMTRING_FREENO(pAd); - } - - if ((FreeNum > 0)) - { - // We need to reserve space for rtmp hardware header. i.e., TxWI for RT2860 and TxInfo+TxWI for RT2870 - NdisZeroMemory(&rtmpHwHdr, (TXINFO_SIZE + TXWI_SIZE)); - Status = RTMPAllocateNdisPacket(pAd, &pPacket, (PUCHAR)&rtmpHwHdr, (TXINFO_SIZE + TXWI_SIZE), pData, Length); - if (Status != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_WARN, ("MiniportMMRequest (error:: can't allocate NDIS PACKET)\n")); - break; - } - - //pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_CCK; - //pAd->CommonCfg.MlmeRate = RATE_2; - - - Status = MlmeHardTransmit(pAd, QueIdx, pPacket); - if (Status != NDIS_STATUS_SUCCESS) - RTMPFreeNdisPacket(pAd, pPacket); - } - else - { - pAd->RalinkCounters.MgmtRingFullCount++; - DBGPRINT(RT_DEBUG_ERROR, ("Qidx(%d), not enough space in MgmtRing, MgmtRingFullCount=%ld!\n", - QueIdx, pAd->RalinkCounters.MgmtRingFullCount)); - } - - } while (FALSE); - - - return Status; -} - - - -NDIS_STATUS MlmeDataHardTransmit( - IN PRTMP_ADAPTER pAd, - IN UCHAR QueIdx, - IN PNDIS_PACKET pPacket); - -#define MAX_DATAMM_RETRY 3 -/* - ======================================================================== - - Routine Description: - API for MLME to transmit management frame to AP (BSS Mode) - or station (IBSS Mode) - - Arguments: - pAd Pointer to our adapter - pData Pointer to the outgoing 802.11 frame - Length Size of outgoing management frame - - Return Value: - NDIS_STATUS_FAILURE - NDIS_STATUS_PENDING - NDIS_STATUS_SUCCESS - - IRQL = PASSIVE_LEVEL - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -NDIS_STATUS MiniportDataMMRequest( - IN PRTMP_ADAPTER pAd, - IN UCHAR QueIdx, - IN PUCHAR pData, - IN UINT Length) -{ - PNDIS_PACKET pPacket; - NDIS_STATUS Status = NDIS_STATUS_SUCCESS; - ULONG FreeNum; - int retry = 0; - UCHAR IrqState; - UCHAR rtmpHwHdr[TXINFO_SIZE + TXWI_SIZE]; //RTMP_HW_HDR_LEN]; - - ASSERT(Length <= MGMT_DMA_BUFFER_SIZE); - - // 2860C use Tx Ring - IrqState = pAd->irq_disabled; - - do - { - // Reset is in progress, stop immediately - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS) || - RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)|| - !RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_START_UP)) - { - Status = NDIS_STATUS_FAILURE; - break; - } - - // Check Free priority queue - // Since we use PBF Queue2 for management frame. Its corresponding DMA ring should be using TxRing. - - // 2860C use Tx Ring - - // free Tx(QueIdx) resources - FreeNum = GET_TXRING_FREENO(pAd, QueIdx); - - if ((FreeNum > 0)) - { - // We need to reserve space for rtmp hardware header. i.e., TxWI for RT2860 and TxInfo+TxWI for RT2870 - NdisZeroMemory(&rtmpHwHdr, (TXINFO_SIZE + TXWI_SIZE)); - Status = RTMPAllocateNdisPacket(pAd, &pPacket, (PUCHAR)&rtmpHwHdr, (TXINFO_SIZE + TXWI_SIZE), pData, Length); - if (Status != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_WARN, ("MiniportMMRequest (error:: can't allocate NDIS PACKET)\n")); - break; - } - - //pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_CCK; - //pAd->CommonCfg.MlmeRate = RATE_2; - - - Status = MlmeDataHardTransmit(pAd, QueIdx, pPacket); - if (Status != NDIS_STATUS_SUCCESS) - RTMPFreeNdisPacket(pAd, pPacket); - retry = MAX_DATAMM_RETRY; - } - else - { - retry ++; - - printk("retry %d\n", retry); - pAd->RalinkCounters.MgmtRingFullCount++; - - if (retry >= MAX_DATAMM_RETRY) - { - DBGPRINT(RT_DEBUG_ERROR, ("Qidx(%d), not enough space in DataRing, MgmtRingFullCount=%ld!\n", - QueIdx, pAd->RalinkCounters.MgmtRingFullCount)); - } - } - - } while (retry < MAX_DATAMM_RETRY); - - - return Status; -} - - - - - - -/* - ======================================================================== - - Routine Description: - Copy frame from waiting queue into relative ring buffer and set - appropriate ASIC register to kick hardware transmit function - - Arguments: - pAd Pointer to our adapter - pBuffer Pointer to memory of outgoing frame - Length Size of outgoing management frame - - Return Value: - NDIS_STATUS_FAILURE - NDIS_STATUS_PENDING - NDIS_STATUS_SUCCESS - - IRQL = PASSIVE_LEVEL - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -NDIS_STATUS MlmeHardTransmit( - IN PRTMP_ADAPTER pAd, - IN UCHAR QueIdx, - IN PNDIS_PACKET pPacket) -{ - if ((pAd->CommonCfg.RadarDetect.RDMode != RD_NORMAL_MODE) -#ifdef CARRIER_DETECTION_SUPPORT -#endif // CARRIER_DETECTION_SUPPORT // - ) - { - return NDIS_STATUS_FAILURE; - } - - return MlmeHardTransmitMgmtRing(pAd,QueIdx,pPacket); - -} - -NDIS_STATUS MlmeDataHardTransmit( - IN PRTMP_ADAPTER pAd, - IN UCHAR QueIdx, - IN PNDIS_PACKET pPacket) -{ - if ((pAd->CommonCfg.RadarDetect.RDMode != RD_NORMAL_MODE) -#ifdef CARRIER_DETECTION_SUPPORT -#endif // CARRIER_DETECTION_SUPPORT // - ) - { - return NDIS_STATUS_FAILURE; - } - -#ifdef RT2870 - return MlmeHardTransmitMgmtRing(pAd,QueIdx,pPacket); -#endif // RT2870 // -} - - - - - -NDIS_STATUS MlmeHardTransmitMgmtRing( - IN PRTMP_ADAPTER pAd, - IN UCHAR QueIdx, - IN PNDIS_PACKET pPacket) -{ - PACKET_INFO PacketInfo; - PUCHAR pSrcBufVA; - UINT SrcBufLen; - PHEADER_802_11 pHeader_802_11; - BOOLEAN bAckRequired, bInsertTimestamp; - UCHAR MlmeRate; - PTXWI_STRUC pFirstTxWI; - MAC_TABLE_ENTRY *pMacEntry = NULL; - - RTMP_QueryPacketInfo(pPacket, &PacketInfo, &pSrcBufVA, &SrcBufLen); - - // Make sure MGMT ring resource won't be used by other threads -// sample, for IRQ LOCK -> SEM LOCK -// IrqState = pAd->irq_disabled; -// if (!IrqState) - RTMP_SEM_LOCK(&pAd->MgmtRingLock); - - - if (pSrcBufVA == NULL) - { - // The buffer shouldn't be NULL -// if (!IrqState) - RTMP_SEM_UNLOCK(&pAd->MgmtRingLock); - return NDIS_STATUS_FAILURE; - } - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - // outgoing frame always wakeup PHY to prevent frame lost - if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) - AsicForceWakeup(pAd, TRUE); - } -#endif // CONFIG_STA_SUPPORT // - - pFirstTxWI = (PTXWI_STRUC)(pSrcBufVA + TXINFO_SIZE); - pHeader_802_11 = (PHEADER_802_11) (pSrcBufVA + TXINFO_SIZE + TXWI_SIZE); //TXWI_SIZE); - - if (pHeader_802_11->Addr1[0] & 0x01) - { - MlmeRate = pAd->CommonCfg.BasicMlmeRate; - } - else - { - MlmeRate = pAd->CommonCfg.MlmeRate; - } - - // Verify Mlme rate for a / g bands. - if ((pAd->LatchRfRegs.Channel > 14) && (MlmeRate < RATE_6)) // 11A band - MlmeRate = RATE_6; - - if ((pHeader_802_11->FC.Type == BTYPE_DATA) && - (pHeader_802_11->FC.SubType == SUBTYPE_QOS_NULL)) - { - pMacEntry = MacTableLookup(pAd, pHeader_802_11->Addr1); - } - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - // Fixed W52 with Activity scan issue in ABG_MIXED and ABGN_MIXED mode. - if (pAd->CommonCfg.PhyMode == PHY_11ABG_MIXED -#ifdef DOT11_N_SUPPORT - || pAd->CommonCfg.PhyMode == PHY_11ABGN_MIXED -#endif // DOT11_N_SUPPORT // - ) - { - if (pAd->LatchRfRegs.Channel > 14) - pAd->CommonCfg.MlmeTransmit.field.MODE = 1; - else - pAd->CommonCfg.MlmeTransmit.field.MODE = 0; - } - } -#endif // CONFIG_STA_SUPPORT // - - // - // Should not be hard code to set PwrMgmt to 0 (PWR_ACTIVE) - // Snice it's been set to 0 while on MgtMacHeaderInit - // By the way this will cause frame to be send on PWR_SAVE failed. - // - // pHeader_802_11->FC.PwrMgmt = 0; // (pAd->StaCfg.Psm == PWR_SAVE); - // - // In WMM-UAPSD, mlme frame should be set psm as power saving but probe request frame -#ifdef CONFIG_STA_SUPPORT - // Data-Null packets alse pass through MMRequest in RT2860, however, we hope control the psm bit to pass APSD - if ((pHeader_802_11->FC.Type != BTYPE_DATA) && (pHeader_802_11->FC.Type != BTYPE_CNTL)) - { - if ((pAd->StaCfg.Psm == PWR_SAVE) && - (pHeader_802_11->FC.SubType == SUBTYPE_ACTION)) - pHeader_802_11->FC.PwrMgmt = PWR_SAVE; - else - pHeader_802_11->FC.PwrMgmt = PWR_ACTIVE; - } -#endif // CONFIG_STA_SUPPORT // - - bInsertTimestamp = FALSE; - if (pHeader_802_11->FC.Type == BTYPE_CNTL) // must be PS-POLL - { -#ifdef CONFIG_STA_SUPPORT - //Set PM bit in ps-poll, to fix WLK 1.2 PowerSaveMode_ext failure issue. - if ((pAd->OpMode == OPMODE_STA) && (pHeader_802_11->FC.SubType == SUBTYPE_PS_POLL)) - { - pHeader_802_11->FC.PwrMgmt = PWR_SAVE; - } -#endif // CONFIG_STA_SUPPORT // - bAckRequired = FALSE; - } - else // BTYPE_MGMT or BTYPE_DATA(must be NULL frame) - { - //pAd->Sequence++; - //pHeader_802_11->Sequence = pAd->Sequence; - - if (pHeader_802_11->Addr1[0] & 0x01) // MULTICAST, BROADCAST - { - bAckRequired = FALSE; - pHeader_802_11->Duration = 0; - } - else - { - bAckRequired = TRUE; - pHeader_802_11->Duration = RTMPCalcDuration(pAd, MlmeRate, 14); - if (pHeader_802_11->FC.SubType == SUBTYPE_PROBE_RSP) - { - bInsertTimestamp = TRUE; - } - } - } - - pHeader_802_11->Sequence = pAd->Sequence++; - if (pAd->Sequence >0xfff) - pAd->Sequence = 0; - - // Before radar detection done, mgmt frame can not be sent but probe req - // Because we need to use probe req to trigger driver to send probe req in passive scan - if ((pHeader_802_11->FC.SubType != SUBTYPE_PROBE_REQ) - && (pAd->CommonCfg.bIEEE80211H == 1) - && (pAd->CommonCfg.RadarDetect.RDMode != RD_NORMAL_MODE)) - { - DBGPRINT(RT_DEBUG_ERROR,("MlmeHardTransmit --> radar detect not in normal mode !!!\n")); -// if (!IrqState) - RTMP_SEM_UNLOCK(&pAd->MgmtRingLock); - return (NDIS_STATUS_FAILURE); - } - -#ifdef RT_BIG_ENDIAN - RTMPFrameEndianChange(pAd, (PUCHAR)pHeader_802_11, DIR_WRITE, FALSE); -#endif - - // - // fill scatter-and-gather buffer list into TXD. Internally created NDIS PACKET - // should always has only one ohysical buffer, and the whole frame size equals - // to the first scatter buffer size - // - - // Initialize TX Descriptor - // For inter-frame gap, the number is for this frame and next frame - // For MLME rate, we will fix as 2Mb to match other vendor's implement -// pAd->CommonCfg.MlmeTransmit.field.MODE = 1; - -// management frame doesn't need encryption. so use RESERVED_WCID no matter u are sending to specific wcid or not. - if (pMacEntry == NULL) - { - RTMPWriteTxWI(pAd, pFirstTxWI, FALSE, FALSE, bInsertTimestamp, FALSE, bAckRequired, FALSE, - 0, RESERVED_WCID, (SrcBufLen - TXINFO_SIZE - TXWI_SIZE), PID_MGMT, 0, (UCHAR)pAd->CommonCfg.MlmeTransmit.field.MCS, IFS_BACKOFF, FALSE, &pAd->CommonCfg.MlmeTransmit); - } - else - { - RTMPWriteTxWI(pAd, pFirstTxWI, FALSE, FALSE, - bInsertTimestamp, FALSE, bAckRequired, FALSE, - 0, pMacEntry->Aid, (SrcBufLen - TXINFO_SIZE - TXWI_SIZE), - pMacEntry->MaxHTPhyMode.field.MCS, 0, - (UCHAR)pMacEntry->MaxHTPhyMode.field.MCS, - IFS_BACKOFF, FALSE, &pMacEntry->MaxHTPhyMode); - } - -#ifdef RT_BIG_ENDIAN - RTMPWIEndianChange((PUCHAR)pFirstTxWI, TYPE_TXWI); -#endif - - // Now do hardware-depened kick out. - HAL_KickOutMgmtTx(pAd, QueIdx, pPacket, pSrcBufVA, SrcBufLen); - - // Make sure to release MGMT ring resource -// if (!IrqState) - RTMP_SEM_UNLOCK(&pAd->MgmtRingLock); - return NDIS_STATUS_SUCCESS; -} - - -/******************************************************************************** - - New DeQueue Procedures. - - ********************************************************************************/ - -#define DEQUEUE_LOCK(lock, bIntContext, IrqFlags) \ - do{ \ - if (bIntContext == FALSE) \ - RTMP_IRQ_LOCK((lock), IrqFlags); \ - }while(0) - -#define DEQUEUE_UNLOCK(lock, bIntContext, IrqFlags) \ - do{ \ - if (bIntContext == FALSE) \ - RTMP_IRQ_UNLOCK((lock), IrqFlags); \ - }while(0) - - -/* - ======================================================================== - Tx Path design algorithm: - Basically, we divide the packets into four types, Broadcast/Multicast, 11N Rate(AMPDU, AMSDU, Normal), B/G Rate(ARALINK, Normal), - Specific Packet Type. Following show the classification rule and policy for each kinds of packets. - Classification Rule=> - Multicast: (*addr1 & 0x01) == 0x01 - Specific : bDHCPFrame, bARPFrame, bEAPOLFrame, etc. - 11N Rate : If peer support HT - (1).AMPDU -- If TXBA is negotiated. - (2).AMSDU -- If AMSDU is capable for both peer and ourself. - *). AMSDU can embedded in a AMPDU, but now we didn't support it. - (3).Normal -- Other packets which send as 11n rate. - - B/G Rate : If peer is b/g only. - (1).ARALINK-- If both of peer/us supprot Ralink proprietary Aggregation and the TxRate is large than RATE_6 - (2).Normal -- Other packets which send as b/g rate. - Fragment: - The packet must be unicast, NOT A-RALINK, NOT A-MSDU, NOT 11n, then can consider about fragment. - - Classified Packet Handle Rule=> - Multicast: - No ACK, //pTxBlk->bAckRequired = FALSE; - No WMM, //pTxBlk->bWMM = FALSE; - No piggyback, //pTxBlk->bPiggyBack = FALSE; - Force LowRate, //pTxBlk->bForceLowRate = TRUE; - Specific : Basically, for specific packet, we should handle it specifically, but now all specific packets are use - the same policy to handle it. - Force LowRate, //pTxBlk->bForceLowRate = TRUE; - - 11N Rate : - No piggyback, //pTxBlk->bPiggyBack = FALSE; - - (1).AMSDU - pTxBlk->bWMM = TRUE; - (2).AMPDU - pTxBlk->bWMM = TRUE; - (3).Normal - - B/G Rate : - (1).ARALINK - - (2).Normal - ======================================================================== -*/ -static UCHAR TxPktClassification( - IN RTMP_ADAPTER *pAd, - IN PNDIS_PACKET pPacket) -{ - UCHAR TxFrameType = TX_UNKOWN_FRAME; - UCHAR Wcid; - MAC_TABLE_ENTRY *pMacEntry = NULL; -#ifdef DOT11_N_SUPPORT - BOOLEAN bHTRate = FALSE; -#endif // DOT11_N_SUPPORT // - - Wcid = RTMP_GET_PACKET_WCID(pPacket); - if (Wcid == MCAST_WCID) - { // Handle for RA is Broadcast/Multicast Address. - return TX_MCAST_FRAME; - } - - // Handle for unicast packets - pMacEntry = &pAd->MacTab.Content[Wcid]; - if (RTMP_GET_PACKET_LOWRATE(pPacket)) - { // It's a specific packet need to force low rate, i.e., bDHCPFrame, bEAPOLFrame, bWAIFrame - TxFrameType = TX_LEGACY_FRAME; - } -#ifdef DOT11_N_SUPPORT - else if (IS_HT_RATE(pMacEntry)) - { // it's a 11n capable packet - - // Depends on HTPhyMode to check if the peer support the HTRate transmission. - // Currently didn't support A-MSDU embedded in A-MPDU - bHTRate = TRUE; - if (RTMP_GET_PACKET_MOREDATA(pPacket) || (pMacEntry->PsMode == PWR_SAVE)) - TxFrameType = TX_LEGACY_FRAME; -#ifdef UAPSD_AP_SUPPORT - else if (RTMP_GET_PACKET_EOSP(pPacket)) - TxFrameType = TX_LEGACY_FRAME; -#endif // UAPSD_AP_SUPPORT // - else if((pMacEntry->TXBAbitmap & (1<<(RTMP_GET_PACKET_UP(pPacket)))) != 0) - return TX_AMPDU_FRAME; - else if(CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_AMSDU_INUSED)) - return TX_AMSDU_FRAME; - else - TxFrameType = TX_LEGACY_FRAME; - } -#endif // DOT11_N_SUPPORT // - else - { // it's a legacy b/g packet. - if ((CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_AGGREGATION_CAPABLE) && pAd->CommonCfg.bAggregationCapable) && - (RTMP_GET_PACKET_TXRATE(pPacket) >= RATE_6) && - (!(OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED) && CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_WMM_CAPABLE)))) - { // if peer support Ralink Aggregation, we use it. - TxFrameType = TX_RALINK_FRAME; - } - else - { - TxFrameType = TX_LEGACY_FRAME; - } - } - - // Currently, our fragment only support when a unicast packet send as NOT-ARALINK, NOT-AMSDU and NOT-AMPDU. - if ((RTMP_GET_PACKET_FRAGMENTS(pPacket) > 1) && (TxFrameType == TX_LEGACY_FRAME)) - TxFrameType = TX_FRAG_FRAME; - - return TxFrameType; -} - - -BOOLEAN RTMP_FillTxBlkInfo( - IN RTMP_ADAPTER *pAd, - IN TX_BLK *pTxBlk) -{ - PACKET_INFO PacketInfo; - PNDIS_PACKET pPacket; - PMAC_TABLE_ENTRY pMacEntry = NULL; - - pPacket = pTxBlk->pPacket; - RTMP_QueryPacketInfo(pPacket, &PacketInfo, &pTxBlk->pSrcBufHeader, &pTxBlk->SrcBufLen); - - pTxBlk->Wcid = RTMP_GET_PACKET_WCID(pPacket); - pTxBlk->apidx = RTMP_GET_PACKET_IF(pPacket); - pTxBlk->UserPriority = RTMP_GET_PACKET_UP(pPacket); - pTxBlk->FrameGap = IFS_HTTXOP; // ASIC determine Frame Gap - - if (RTMP_GET_PACKET_CLEAR_EAP_FRAME(pTxBlk->pPacket)) - TX_BLK_SET_FLAG(pTxBlk, fTX_bClearEAPFrame); - else - TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bClearEAPFrame); - - // Default to clear this flag - TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bForceNonQoS); - - - if (pTxBlk->Wcid == MCAST_WCID) - { - pTxBlk->pMacEntry = NULL; - { -#ifdef MCAST_RATE_SPECIFIC - PUCHAR pDA = GET_OS_PKT_DATAPTR(pPacket); - if (((*pDA & 0x01) == 0x01) && (*pDA != 0xff)) - pTxBlk->pTransmit = &pAd->CommonCfg.MCastPhyMode; - else -#endif // MCAST_RATE_SPECIFIC // - pTxBlk->pTransmit = &pAd->MacTab.Content[MCAST_WCID].HTPhyMode; - } - - TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bAckRequired); // AckRequired = FALSE, when broadcast packet in Adhoc mode. - //TX_BLK_SET_FLAG(pTxBlk, fTX_bForceLowRate); - TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bAllowFrag); - TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bWMM); - if (RTMP_GET_PACKET_MOREDATA(pPacket)) - { - TX_BLK_SET_FLAG(pTxBlk, fTX_bMoreData); - } - - } - else - { - pTxBlk->pMacEntry = &pAd->MacTab.Content[pTxBlk->Wcid]; - pTxBlk->pTransmit = &pTxBlk->pMacEntry->HTPhyMode; - - pMacEntry = pTxBlk->pMacEntry; - - - // For all unicast packets, need Ack unless the Ack Policy is not set as NORMAL_ACK. - if (pAd->CommonCfg.AckPolicy[pTxBlk->QueIdx] != NORMAL_ACK) - TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bAckRequired); - else - TX_BLK_SET_FLAG(pTxBlk, fTX_bAckRequired); - - { - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - - // If support WMM, enable it. - if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED) && - CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_WMM_CAPABLE)) - TX_BLK_SET_FLAG(pTxBlk, fTX_bWMM); - -// if (pAd->StaCfg.bAutoTxRateSwitch) -// TX_BLK_SET_FLAG(pTxBlk, fTX_AutoRateSwitch); - } -#endif // CONFIG_STA_SUPPORT // - } - - if (pTxBlk->TxFrameType == TX_LEGACY_FRAME) - { - if ( (RTMP_GET_PACKET_LOWRATE(pPacket)) || - ((pAd->OpMode == OPMODE_AP) && (pMacEntry->MaxHTPhyMode.field.MODE == MODE_CCK) && (pMacEntry->MaxHTPhyMode.field.MCS == RATE_1))) - { // Specific packet, i.e., bDHCPFrame, bEAPOLFrame, bWAIFrame, need force low rate. - pTxBlk->pTransmit = &pAd->MacTab.Content[MCAST_WCID].HTPhyMode; -#ifdef DOT11_N_SUPPORT - // Modify the WMM bit for ICV issue. If we have a packet with EOSP field need to set as 1, how to handle it??? - if (IS_HT_STA(pTxBlk->pMacEntry) && - (CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_RALINK_CHIPSET)) && - ((pAd->CommonCfg.bRdg == TRUE) && CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_RDG_CAPABLE))) - { - TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bWMM); - TX_BLK_SET_FLAG(pTxBlk, fTX_bForceNonQoS); - } -#endif // DOT11_N_SUPPORT // - } - -#ifdef DOT11_N_SUPPORT - if ( (IS_HT_RATE(pMacEntry) == FALSE) && - (CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_PIGGYBACK_CAPABLE))) - { // Currently piggy-back only support when peer is operate in b/g mode. - TX_BLK_SET_FLAG(pTxBlk, fTX_bPiggyBack); - } -#endif // DOT11_N_SUPPORT // - - if (RTMP_GET_PACKET_MOREDATA(pPacket)) - { - TX_BLK_SET_FLAG(pTxBlk, fTX_bMoreData); - } -#ifdef UAPSD_AP_SUPPORT - if (RTMP_GET_PACKET_EOSP(pPacket)) - { - TX_BLK_SET_FLAG(pTxBlk, fTX_bWMM_UAPSD_EOSP); - } -#endif // UAPSD_AP_SUPPORT // - } - else if (pTxBlk->TxFrameType == TX_FRAG_FRAME) - { - TX_BLK_SET_FLAG(pTxBlk, fTX_bAllowFrag); - } - - pMacEntry->DebugTxCount++; - } - - return TRUE; - -FillTxBlkErr: - return FALSE; -} - - -BOOLEAN CanDoAggregateTransmit( - IN RTMP_ADAPTER *pAd, - IN NDIS_PACKET *pPacket, - IN TX_BLK *pTxBlk) -{ - - //printk("Check if can do aggregation! TxFrameType=%d!\n", pTxBlk->TxFrameType); - - if (RTMP_GET_PACKET_WCID(pPacket) == MCAST_WCID) - return FALSE; - - if (RTMP_GET_PACKET_DHCP(pPacket) || - RTMP_GET_PACKET_EAPOL(pPacket) || - RTMP_GET_PACKET_WAI(pPacket)) - return FALSE; - - if ((pTxBlk->TxFrameType == TX_AMSDU_FRAME) && - ((pTxBlk->TotalFrameLen + GET_OS_PKT_LEN(pPacket))> (RX_BUFFER_AGGRESIZE - 100))) - { // For AMSDU, allow the packets with total length < max-amsdu size - return FALSE; - } - - if ((pTxBlk->TxFrameType == TX_RALINK_FRAME) && - (pTxBlk->TxPacketList.Number == 2)) - { // For RALINK-Aggregation, allow two frames in one batch. - return FALSE; - } - -#ifdef CONFIG_STA_SUPPORT - if ((INFRA_ON(pAd)) && (pAd->OpMode == OPMODE_STA)) // must be unicast to AP - return TRUE; - else -#endif // CONFIG_STA_SUPPORT // - return FALSE; - -} - - -/* - ======================================================================== - - Routine Description: - To do the enqueue operation and extract the first item of waiting - list. If a number of available shared memory segments could meet - the request of extracted item, the extracted item will be fragmented - into shared memory segments. - - Arguments: - pAd Pointer to our adapter - pQueue Pointer to Waiting Queue - - Return Value: - None - - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -VOID RTMPDeQueuePacket( - IN PRTMP_ADAPTER pAd, - IN BOOLEAN bIntContext, - IN UCHAR QIdx, /* BulkOutPipeId */ - IN UCHAR Max_Tx_Packets) -{ - PQUEUE_ENTRY pEntry = NULL; - PNDIS_PACKET pPacket; - NDIS_STATUS Status = NDIS_STATUS_SUCCESS; - UCHAR Count=0; - PQUEUE_HEADER pQueue; - ULONG FreeNumber[NUM_OF_TX_RING]; - UCHAR QueIdx, sQIdx, eQIdx; - unsigned long IrqFlags = 0; - BOOLEAN hasTxDesc = FALSE; - TX_BLK TxBlk; - TX_BLK *pTxBlk; - -#ifdef DBG_DIAGNOSE - BOOLEAN firstRound; - RtmpDiagStruct *pDiagStruct = &pAd->DiagStruct; -#endif - - - if (QIdx == NUM_OF_TX_RING) - { - sQIdx = 0; -//PS packets use HCCA queue when dequeue from PS unicast queue (WiFi WPA2 MA9_DT1 for Marvell B STA) -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - eQIdx = 3; // 4 ACs, start from 0. -#endif // CONFIG_STA_SUPPORT // - } - else - { - sQIdx = eQIdx = QIdx; - } - - for (QueIdx=sQIdx; QueIdx <= eQIdx; QueIdx++) - { - Count=0; - - RT28XX_START_DEQUEUE(pAd, QueIdx, IrqFlags); - -#ifdef DBG_DIAGNOSE - firstRound = ((QueIdx == 0) ? TRUE : FALSE); -#endif // DBG_DIAGNOSE // - - while (1) - { - if ((RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS | - fRTMP_ADAPTER_RADIO_OFF | - fRTMP_ADAPTER_RESET_IN_PROGRESS | - fRTMP_ADAPTER_HALT_IN_PROGRESS | - fRTMP_ADAPTER_NIC_NOT_EXIST)))) - { - RT28XX_STOP_DEQUEUE(pAd, QueIdx, IrqFlags); - return; - } - - if (Count >= Max_Tx_Packets) - break; - - DEQUEUE_LOCK(&pAd->irq_lock, bIntContext, IrqFlags); - if (&pAd->TxSwQueue[QueIdx] == NULL) - { -#ifdef DBG_DIAGNOSE - if (firstRound == TRUE) - pDiagStruct->TxSWQueCnt[pDiagStruct->ArrayCurIdx][0]++; -#endif // DBG_DIAGNOSE // - DEQUEUE_UNLOCK(&pAd->irq_lock, bIntContext, IrqFlags); - break; - } - - - // probe the Queue Head - pQueue = &pAd->TxSwQueue[QueIdx]; - if ((pEntry = pQueue->Head) == NULL) - { - DEQUEUE_UNLOCK(&pAd->irq_lock, bIntContext, IrqFlags); - break; - } - - pTxBlk = &TxBlk; - NdisZeroMemory((PUCHAR)pTxBlk, sizeof(TX_BLK)); - //InitializeQueueHeader(&pTxBlk->TxPacketList); // Didn't need it because we already memzero it. - pTxBlk->QueIdx = QueIdx; - - pPacket = QUEUE_ENTRY_TO_PKT(pEntry); - - // Early check to make sure we have enoguh Tx Resource. - hasTxDesc = RT28XX_HAS_ENOUGH_FREE_DESC(pAd, pTxBlk, FreeNumber[QueIdx], pPacket); - if (!hasTxDesc) - { - pAd->PrivateInfo.TxRingFullCnt++; - - DEQUEUE_UNLOCK(&pAd->irq_lock, bIntContext, IrqFlags); - - break; - } - - pTxBlk->TxFrameType = TxPktClassification(pAd, pPacket); - pEntry = RemoveHeadQueue(pQueue); - pTxBlk->TotalFrameNum++; - pTxBlk->TotalFragNum += RTMP_GET_PACKET_FRAGMENTS(pPacket); // The real fragment number maybe vary - pTxBlk->TotalFrameLen += GET_OS_PKT_LEN(pPacket); - pTxBlk->pPacket = pPacket; - InsertTailQueue(&pTxBlk->TxPacketList, PACKET_TO_QUEUE_ENTRY(pPacket)); - - if (pTxBlk->TxFrameType == TX_RALINK_FRAME || pTxBlk->TxFrameType == TX_AMSDU_FRAME) - { - // Enhance SW Aggregation Mechanism - if (NEED_QUEUE_BACK_FOR_AGG(pAd, QueIdx, FreeNumber[QueIdx], pTxBlk->TxFrameType)) - { - InsertHeadQueue(pQueue, PACKET_TO_QUEUE_ENTRY(pPacket)); - DEQUEUE_UNLOCK(&pAd->irq_lock, bIntContext, IrqFlags); - break; - } - - do{ - if((pEntry = pQueue->Head) == NULL) - break; - - // For TX_AMSDU_FRAME/TX_RALINK_FRAME, Need to check if next pakcet can do aggregation. - pPacket = QUEUE_ENTRY_TO_PKT(pEntry); - FreeNumber[QueIdx] = GET_TXRING_FREENO(pAd, QueIdx); - hasTxDesc = RT28XX_HAS_ENOUGH_FREE_DESC(pAd, pTxBlk, FreeNumber[QueIdx], pPacket); - if ((hasTxDesc == FALSE) || (CanDoAggregateTransmit(pAd, pPacket, pTxBlk) == FALSE)) - break; - - //Remove the packet from the TxSwQueue and insert into pTxBlk - pEntry = RemoveHeadQueue(pQueue); - ASSERT(pEntry); - pPacket = QUEUE_ENTRY_TO_PKT(pEntry); - pTxBlk->TotalFrameNum++; - pTxBlk->TotalFragNum += RTMP_GET_PACKET_FRAGMENTS(pPacket); // The real fragment number maybe vary - pTxBlk->TotalFrameLen += GET_OS_PKT_LEN(pPacket); - InsertTailQueue(&pTxBlk->TxPacketList, PACKET_TO_QUEUE_ENTRY(pPacket)); - }while(1); - - if (pTxBlk->TxPacketList.Number == 1) - pTxBlk->TxFrameType = TX_LEGACY_FRAME; - } - -#ifdef RT2870 - DEQUEUE_UNLOCK(&pAd->irq_lock, bIntContext, IrqFlags); -#endif // RT2870 // - - Count += pTxBlk->TxPacketList.Number; - - // Do HardTransmit now. -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - Status = STAHardTransmit(pAd, pTxBlk, QueIdx); -#endif // CONFIG_STA_SUPPORT // - } - - RT28XX_STOP_DEQUEUE(pAd, QueIdx, IrqFlags); - -#ifdef RT2870 - if (!hasTxDesc) - RTUSBKickBulkOut(pAd); -#endif // RT2870 // - -#ifdef BLOCK_NET_IF - if ((pAd->blockQueueTab[QueIdx].SwTxQueueBlockFlag == TRUE) - && (pAd->TxSwQueue[QueIdx].Number < 1)) - { - releaseNetIf(&pAd->blockQueueTab[QueIdx]); - } -#endif // BLOCK_NET_IF // - - } - -} - - -/* - ======================================================================== - - Routine Description: - Calculates the duration which is required to transmit out frames - with given size and specified rate. - - Arguments: - pAd Pointer to our adapter - Rate Transmit rate - Size Frame size in units of byte - - Return Value: - Duration number in units of usec - - IRQL = PASSIVE_LEVEL - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -USHORT RTMPCalcDuration( - IN PRTMP_ADAPTER pAd, - IN UCHAR Rate, - IN ULONG Size) -{ - ULONG Duration = 0; - - if (Rate < RATE_FIRST_OFDM_RATE) // CCK - { - if ((Rate > RATE_1) && OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED)) - Duration = 96; // 72+24 preamble+plcp - else - Duration = 192; // 144+48 preamble+plcp - - Duration += (USHORT)((Size << 4) / RateIdTo500Kbps[Rate]); - if ((Size << 4) % RateIdTo500Kbps[Rate]) - Duration ++; - } - else if (Rate <= RATE_LAST_OFDM_RATE)// OFDM rates - { - Duration = 20 + 6; // 16+4 preamble+plcp + Signal Extension - Duration += 4 * (USHORT)((11 + Size * 4) / RateIdTo500Kbps[Rate]); - if ((11 + Size * 4) % RateIdTo500Kbps[Rate]) - Duration += 4; - } - else //mimo rate - { - Duration = 20 + 6; // 16+4 preamble+plcp + Signal Extension - } - - return (USHORT)Duration; -} - - -/* - ======================================================================== - - Routine Description: - Calculates the duration which is required to transmit out frames - with given size and specified rate. - - Arguments: - pTxWI Pointer to head of each MPDU to HW. - Ack Setting for Ack requirement bit - Fragment Setting for Fragment bit - RetryMode Setting for retry mode - Ifs Setting for IFS gap - Rate Setting for transmit rate - Service Setting for service - Length Frame length - TxPreamble Short or Long preamble when using CCK rates - QueIdx - 0-3, according to 802.11e/d4.4 June/2003 - - Return Value: - None - - IRQL = PASSIVE_LEVEL - IRQL = DISPATCH_LEVEL - - See also : BASmartHardTransmit() !!! - - ======================================================================== -*/ -VOID RTMPWriteTxWI( - IN PRTMP_ADAPTER pAd, - IN PTXWI_STRUC pOutTxWI, - IN BOOLEAN FRAG, - IN BOOLEAN CFACK, - IN BOOLEAN InsTimestamp, - IN BOOLEAN AMPDU, - IN BOOLEAN Ack, - IN BOOLEAN NSeq, // HW new a sequence. - IN UCHAR BASize, - IN UCHAR WCID, - IN ULONG Length, - IN UCHAR PID, - IN UCHAR TID, - IN UCHAR TxRate, - IN UCHAR Txopmode, - IN BOOLEAN CfAck, - IN HTTRANSMIT_SETTING *pTransmit) -{ - PMAC_TABLE_ENTRY pMac = NULL; - TXWI_STRUC TxWI; - PTXWI_STRUC pTxWI; - - if (WCID < MAX_LEN_OF_MAC_TABLE) - pMac = &pAd->MacTab.Content[WCID]; - - // - // Always use Long preamble before verifiation short preamble functionality works well. - // Todo: remove the following line if short preamble functionality works - // - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED); - NdisZeroMemory(&TxWI, TXWI_SIZE); - pTxWI = &TxWI; - - pTxWI->FRAG= FRAG; - - pTxWI->CFACK = CFACK; - pTxWI->TS= InsTimestamp; - pTxWI->AMPDU = AMPDU; - pTxWI->ACK = Ack; - pTxWI->txop= Txopmode; - - pTxWI->NSEQ = NSeq; - // John tune the performace with Intel Client in 20 MHz performance -#ifdef DOT11_N_SUPPORT - BASize = pAd->CommonCfg.TxBASize; - - if( BASize >7 ) - BASize =7; - pTxWI->BAWinSize = BASize; - pTxWI->ShortGI = pTransmit->field.ShortGI; - pTxWI->STBC = pTransmit->field.STBC; -#endif // DOT11_N_SUPPORT // - - pTxWI->WirelessCliID = WCID; - pTxWI->MPDUtotalByteCount = Length; - pTxWI->PacketId = PID; - - // If CCK or OFDM, BW must be 20 - pTxWI->BW = (pTransmit->field.MODE <= MODE_OFDM) ? (BW_20) : (pTransmit->field.BW); -#ifdef DOT11N_DRAFT3 - if (pTxWI->BW) - pTxWI->BW = (pAd->CommonCfg.AddHTInfo.AddHtInfo.RecomWidth == 0) ? (BW_20) : (pTransmit->field.BW); -#endif // DOT11N_DRAFT3 // - - pTxWI->MCS = pTransmit->field.MCS; - pTxWI->PHYMODE = pTransmit->field.MODE; - pTxWI->CFACK = CfAck; - -#ifdef DOT11_N_SUPPORT - if (pMac) - { - if (pAd->CommonCfg.bMIMOPSEnable) - { - if ((pMac->MmpsMode == MMPS_DYNAMIC) && (pTransmit->field.MCS > 7)) - { - // Dynamic MIMO Power Save Mode - pTxWI->MIMOps = 1; - } - else if (pMac->MmpsMode == MMPS_STATIC) - { - // Static MIMO Power Save Mode - if (pTransmit->field.MODE >= MODE_HTMIX && pTransmit->field.MCS > 7) - { - pTxWI->MCS = 7; - pTxWI->MIMOps = 0; - } - } - } - //pTxWI->MIMOps = (pMac->PsMode == PWR_MMPS)? 1:0; - if (pMac->bIAmBadAtheros && (pMac->WepStatus != Ndis802_11WEPDisabled)) - { - pTxWI->MpduDensity = 7; - } - else - { - pTxWI->MpduDensity = pMac->MpduDensity; - } - } -#endif // DOT11_N_SUPPORT // - - pTxWI->PacketId = pTxWI->MCS; - NdisMoveMemory(pOutTxWI, &TxWI, sizeof(TXWI_STRUC)); -} - - -VOID RTMPWriteTxWI_Data( - IN PRTMP_ADAPTER pAd, - IN OUT PTXWI_STRUC pTxWI, - IN TX_BLK *pTxBlk) -{ - HTTRANSMIT_SETTING *pTransmit; - PMAC_TABLE_ENTRY pMacEntry; -#ifdef DOT11_N_SUPPORT - UCHAR BASize; -#endif // DOT11_N_SUPPORT // - - - ASSERT(pTxWI); - - pTransmit = pTxBlk->pTransmit; - pMacEntry = pTxBlk->pMacEntry; - - - // - // Always use Long preamble before verifiation short preamble functionality works well. - // Todo: remove the following line if short preamble functionality works - // - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED); - NdisZeroMemory(pTxWI, TXWI_SIZE); - - pTxWI->FRAG = TX_BLK_TEST_FLAG(pTxBlk, fTX_bAllowFrag); - pTxWI->ACK = TX_BLK_TEST_FLAG(pTxBlk, fTX_bAckRequired); - pTxWI->txop = pTxBlk->FrameGap; - -#ifdef CONFIG_STA_SUPPORT -#ifdef QOS_DLS_SUPPORT - if (pMacEntry && - (pAd->StaCfg.BssType == BSS_INFRA) && - (pMacEntry->ValidAsDls == TRUE)) - pTxWI->WirelessCliID = BSSID_WCID; - else -#endif // QOS_DLS_SUPPORT // -#endif // CONFIG_STA_SUPPORT // - pTxWI->WirelessCliID = pTxBlk->Wcid; - - pTxWI->MPDUtotalByteCount = pTxBlk->MpduHeaderLen + pTxBlk->SrcBufLen; - pTxWI->CFACK = TX_BLK_TEST_FLAG(pTxBlk, fTX_bPiggyBack); - - // If CCK or OFDM, BW must be 20 - pTxWI->BW = (pTransmit->field.MODE <= MODE_OFDM) ? (BW_20) : (pTransmit->field.BW); -#ifdef DOT11_N_SUPPORT -#ifdef DOT11N_DRAFT3 - if (pTxWI->BW) - pTxWI->BW = (pAd->CommonCfg.AddHTInfo.AddHtInfo.RecomWidth == 0) ? (BW_20) : (pTransmit->field.BW); -#endif // DOT11N_DRAFT3 // - pTxWI->AMPDU = ((pTxBlk->TxFrameType == TX_AMPDU_FRAME) ? TRUE : FALSE); - - // John tune the performace with Intel Client in 20 MHz performance - BASize = pAd->CommonCfg.TxBASize; - if((pTxBlk->TxFrameType == TX_AMPDU_FRAME) && (pMacEntry)) - { - UCHAR RABAOriIdx = 0; //The RA's BA Originator table index. - - RABAOriIdx = pTxBlk->pMacEntry->BAOriWcidArray[pTxBlk->UserPriority]; - BASize = pAd->BATable.BAOriEntry[RABAOriIdx].BAWinSize; - } - - pTxWI->TxBF = pTransmit->field.TxBF; - pTxWI->BAWinSize = BASize; - pTxWI->ShortGI = pTransmit->field.ShortGI; - pTxWI->STBC = pTransmit->field.STBC; -#endif // DOT11_N_SUPPORT // - - pTxWI->MCS = pTransmit->field.MCS; - pTxWI->PHYMODE = pTransmit->field.MODE; - -#ifdef DOT11_N_SUPPORT - if (pMacEntry) - { - if ((pMacEntry->MmpsMode == MMPS_DYNAMIC) && (pTransmit->field.MCS > 7)) - { - // Dynamic MIMO Power Save Mode - pTxWI->MIMOps = 1; - } - else if (pMacEntry->MmpsMode == MMPS_STATIC) - { - // Static MIMO Power Save Mode - if (pTransmit->field.MODE >= MODE_HTMIX && pTransmit->field.MCS > 7) - { - pTxWI->MCS = 7; - pTxWI->MIMOps = 0; - } - } - - if (pMacEntry->bIAmBadAtheros && (pMacEntry->WepStatus != Ndis802_11WEPDisabled)) - { - pTxWI->MpduDensity = 7; - } - else - { - pTxWI->MpduDensity = pMacEntry->MpduDensity; - } - } -#endif // DOT11_N_SUPPORT // - -#ifdef DBG_DIAGNOSE - if (pTxBlk->QueIdx== 0) - { - pAd->DiagStruct.TxDataCnt[pAd->DiagStruct.ArrayCurIdx]++; - pAd->DiagStruct.TxMcsCnt[pAd->DiagStruct.ArrayCurIdx][pTxWI->MCS]++; - } -#endif // DBG_DIAGNOSE // - - // for rate adapation - pTxWI->PacketId = pTxWI->MCS; -#ifdef INF_AMAZON_SE -/*Iverson patch for WMM A5-T07 ,WirelessStaToWirelessSta do not bulk out aggregate */ - if( RTMP_GET_PACKET_NOBULKOUT(pTxBlk->pPacket)) - { - if(pTxWI->PHYMODE == MODE_CCK) - { - pTxWI->PacketId = 6; - } - } -#endif // INF_AMAZON_SE // -} - - -VOID RTMPWriteTxWI_Cache( - IN PRTMP_ADAPTER pAd, - IN OUT PTXWI_STRUC pTxWI, - IN TX_BLK *pTxBlk) -{ - PHTTRANSMIT_SETTING /*pTxHTPhyMode,*/ pTransmit; - PMAC_TABLE_ENTRY pMacEntry; - - // - // update TXWI - // - pMacEntry = pTxBlk->pMacEntry; - pTransmit = pTxBlk->pTransmit; - - //if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED)) - //if (RTMPCheckEntryEnableAutoRateSwitch(pAd, pMacEntry)) - //if (TX_BLK_TEST_FLAG(pTxBlk, fTX_AutoRateSwitch)) - if (pMacEntry->bAutoTxRateSwitch) - { - pTxWI->txop = IFS_HTTXOP; - - // If CCK or OFDM, BW must be 20 - pTxWI->BW = (pTransmit->field.MODE <= MODE_OFDM) ? (BW_20) : (pTransmit->field.BW); - pTxWI->ShortGI = pTransmit->field.ShortGI; - pTxWI->STBC = pTransmit->field.STBC; - - pTxWI->MCS = pTransmit->field.MCS; - pTxWI->PHYMODE = pTransmit->field.MODE; - - // set PID for TxRateSwitching - pTxWI->PacketId = pTransmit->field.MCS; - } - -#ifdef DOT11_N_SUPPORT - pTxWI->AMPDU = ((pMacEntry->NoBADataCountDown == 0) ? TRUE: FALSE); - pTxWI->MIMOps = 0; - -#ifdef DOT11N_DRAFT3 - if (pTxWI->BW) - pTxWI->BW = (pAd->CommonCfg.AddHTInfo.AddHtInfo.RecomWidth == 0) ? (BW_20) : (pTransmit->field.BW); -#endif // DOT11N_DRAFT3 // - - if (pAd->CommonCfg.bMIMOPSEnable) - { - // MIMO Power Save Mode - if ((pMacEntry->MmpsMode == MMPS_DYNAMIC) && (pTransmit->field.MCS > 7)) - { - // Dynamic MIMO Power Save Mode - pTxWI->MIMOps = 1; - } - else if (pMacEntry->MmpsMode == MMPS_STATIC) - { - // Static MIMO Power Save Mode - if ((pTransmit->field.MODE >= MODE_HTMIX) && (pTransmit->field.MCS > 7)) - { - pTxWI->MCS = 7; - pTxWI->MIMOps = 0; - } - } - } -#endif // DOT11_N_SUPPORT // - -#ifdef DBG_DIAGNOSE - if (pTxBlk->QueIdx== 0) - { - pAd->DiagStruct.TxDataCnt[pAd->DiagStruct.ArrayCurIdx]++; - pAd->DiagStruct.TxMcsCnt[pAd->DiagStruct.ArrayCurIdx][pTxWI->MCS]++; - } -#endif // DBG_DIAGNOSE // - - pTxWI->MPDUtotalByteCount = pTxBlk->MpduHeaderLen + pTxBlk->SrcBufLen; - -} - - -/* - ======================================================================== - - Routine Description: - Calculates the duration which is required to transmit out frames - with given size and specified rate. - - Arguments: - pTxD Pointer to transmit descriptor - Ack Setting for Ack requirement bit - Fragment Setting for Fragment bit - RetryMode Setting for retry mode - Ifs Setting for IFS gap - Rate Setting for transmit rate - Service Setting for service - Length Frame length - TxPreamble Short or Long preamble when using CCK rates - QueIdx - 0-3, according to 802.11e/d4.4 June/2003 - - Return Value: - None - - IRQL = PASSIVE_LEVEL - IRQL = DISPATCH_LEVEL - - ======================================================================== -*/ -VOID RTMPWriteTxDescriptor( - IN PRTMP_ADAPTER pAd, - IN PTXD_STRUC pTxD, - IN BOOLEAN bWIV, - IN UCHAR QueueSEL) -{ - // - // Always use Long preamble before verifiation short preamble functionality works well. - // Todo: remove the following line if short preamble functionality works - // - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED); - - pTxD->WIV = (bWIV) ? 1: 0; - pTxD->QSEL= (QueueSEL); - if (pAd->bGenOneHCCA == TRUE) - pTxD->QSEL= FIFO_HCCA; - pTxD->DMADONE = 0; -} - - -// should be called only when - -// 1. MEADIA_CONNECTED -// 2. AGGREGATION_IN_USED -// 3. Fragmentation not in used -// 4. either no previous frame (pPrevAddr1=NULL) .OR. previoud frame is aggregatible -BOOLEAN TxFrameIsAggregatible( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pPrevAddr1, - IN PUCHAR p8023hdr) -{ - - // can't aggregate EAPOL (802.1x) frame - if ((p8023hdr[12] == 0x88) && (p8023hdr[13] == 0x8e)) - return FALSE; - - // can't aggregate multicast/broadcast frame - if (p8023hdr[0] & 0x01) - return FALSE; - - if (INFRA_ON(pAd)) // must be unicast to AP - return TRUE; - else if ((pPrevAddr1 == NULL) || MAC_ADDR_EQUAL(pPrevAddr1, p8023hdr)) // unicast to same STA - return TRUE; - else - return FALSE; -} - - -/* - ======================================================================== - - Routine Description: - Check the MSDU Aggregation policy - 1.HT aggregation is A-MSDU - 2.legaacy rate aggregation is software aggregation by Ralink. - - Arguments: - - Return Value: - - Note: - - ======================================================================== -*/ -BOOLEAN PeerIsAggreOn( - IN PRTMP_ADAPTER pAd, - IN ULONG TxRate, - IN PMAC_TABLE_ENTRY pMacEntry) -{ - ULONG AFlags = (fCLIENT_STATUS_AMSDU_INUSED | fCLIENT_STATUS_AGGREGATION_CAPABLE); - - if (pMacEntry != NULL && CLIENT_STATUS_TEST_FLAG(pMacEntry, AFlags)) - { -#ifdef DOT11_N_SUPPORT - if (pMacEntry->HTPhyMode.field.MODE >= MODE_HTMIX) - { - return TRUE; - } -#endif // DOT11_N_SUPPORT // - -#ifdef AGGREGATION_SUPPORT - if (TxRate >= RATE_6 && pAd->CommonCfg.bAggregationCapable && (!(OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED) && CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_WMM_CAPABLE)))) - { // legacy Ralink Aggregation support - return TRUE; - } -#endif // AGGREGATION_SUPPORT // - } - - return FALSE; - -} - - -/* - ======================================================================== - - Routine Description: - Check and fine the packet waiting in SW queue with highest priority - - Arguments: - pAd Pointer to our adapter - - Return Value: - pQueue Pointer to Waiting Queue - - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -PQUEUE_HEADER RTMPCheckTxSwQueue( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pQueIdx) -{ - - ULONG Number; - // 2004-11-15 to be removed. test aggregation only -// if ((OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED)) && (*pNumber < 2)) -// return NULL; - - Number = pAd->TxSwQueue[QID_AC_BK].Number - + pAd->TxSwQueue[QID_AC_BE].Number - + pAd->TxSwQueue[QID_AC_VI].Number - + pAd->TxSwQueue[QID_AC_VO].Number - + pAd->TxSwQueue[QID_HCCA].Number; - - if (pAd->TxSwQueue[QID_AC_VO].Head != NULL) - { - *pQueIdx = QID_AC_VO; - return (&pAd->TxSwQueue[QID_AC_VO]); - } - else if (pAd->TxSwQueue[QID_AC_VI].Head != NULL) - { - *pQueIdx = QID_AC_VI; - return (&pAd->TxSwQueue[QID_AC_VI]); - } - else if (pAd->TxSwQueue[QID_AC_BE].Head != NULL) - { - *pQueIdx = QID_AC_BE; - return (&pAd->TxSwQueue[QID_AC_BE]); - } - else if (pAd->TxSwQueue[QID_AC_BK].Head != NULL) - { - *pQueIdx = QID_AC_BK; - return (&pAd->TxSwQueue[QID_AC_BK]); - } - else if (pAd->TxSwQueue[QID_HCCA].Head != NULL) - { - *pQueIdx = QID_HCCA; - return (&pAd->TxSwQueue[QID_HCCA]); - } - - // No packet pending in Tx Sw queue - *pQueIdx = QID_AC_BK; - - return (NULL); -} - - - -/* - ======================================================================== - - Routine Description: - Suspend MSDU transmission - - Arguments: - pAd Pointer to our adapter - - Return Value: - None - - Note: - - ======================================================================== -*/ -VOID RTMPSuspendMsduTransmission( - IN PRTMP_ADAPTER pAd) -{ - DBGPRINT(RT_DEBUG_TRACE,("SCANNING, suspend MSDU transmission ...\n")); - - - // - // Before BSS_SCAN_IN_PROGRESS, we need to keep Current R66 value and - // use Lowbound as R66 value on ScanNextChannel(...) - // - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R66, &pAd->BbpTuning.R66CurrentValue); - - // set BBP_R66 to 0x30/0x40 when scanning (AsicSwitchChannel will set R66 according to channel when scanning) - //RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, (0x26 + GET_LNA_GAIN(pAd))); - RTMPSetAGCInitValue(pAd, BW_20); - - RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS); - //RTMP_IO_WRITE32(pAd, TX_CNTL_CSR, 0x000f0000); // abort all TX rings -} - - -/* - ======================================================================== - - Routine Description: - Resume MSDU transmission - - Arguments: - pAd Pointer to our adapter - - Return Value: - None - - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -VOID RTMPResumeMsduTransmission( - IN PRTMP_ADAPTER pAd) -{ -// UCHAR IrqState; - - DBGPRINT(RT_DEBUG_TRACE,("SCAN done, resume MSDU transmission ...\n")); - - - // After finish BSS_SCAN_IN_PROGRESS, we need to restore Current R66 value - // R66 should not be 0 - if (pAd->BbpTuning.R66CurrentValue == 0) - { - pAd->BbpTuning.R66CurrentValue = 0x38; - DBGPRINT_ERR(("RTMPResumeMsduTransmission, R66CurrentValue=0...\n")); - } - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, pAd->BbpTuning.R66CurrentValue); - - RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS); -// sample, for IRQ LOCK to SEM LOCK -// IrqState = pAd->irq_disabled; -// if (IrqState) -// RTMPDeQueuePacket(pAd, TRUE, NUM_OF_TX_RING, MAX_TX_PROCESS); -// else - RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, MAX_TX_PROCESS); -} - - -UINT deaggregate_AMSDU_announce( - IN PRTMP_ADAPTER pAd, - PNDIS_PACKET pPacket, - IN PUCHAR pData, - IN ULONG DataSize) -{ - USHORT PayloadSize; - USHORT SubFrameSize; - PHEADER_802_3 pAMSDUsubheader; - UINT nMSDU; - UCHAR Header802_3[14]; - - PUCHAR pPayload, pDA, pSA, pRemovedLLCSNAP; - PNDIS_PACKET pClonePacket; - - - - nMSDU = 0; - - while (DataSize > LENGTH_802_3) - { - - nMSDU++; - - //hex_dump("subheader", pData, 64); - pAMSDUsubheader = (PHEADER_802_3)pData; - //pData += LENGTH_802_3; - PayloadSize = pAMSDUsubheader->Octet[1] + (pAMSDUsubheader->Octet[0]<<8); - SubFrameSize = PayloadSize + LENGTH_802_3; - - - if ((DataSize < SubFrameSize) || (PayloadSize > 1518 )) - { - break; - } - - //printk("%d subframe: Size = %d\n", nMSDU, PayloadSize); - - pPayload = pData + LENGTH_802_3; - pDA = pData; - pSA = pData + MAC_ADDR_LEN; - - // convert to 802.3 header - CONVERT_TO_802_3(Header802_3, pDA, pSA, pPayload, PayloadSize, pRemovedLLCSNAP); - -#ifdef CONFIG_STA_SUPPORT - if ((Header802_3[12] == 0x88) && (Header802_3[13] == 0x8E) ) - { - // avoid local heap overflow, use dyanamic allocation - MLME_QUEUE_ELEM *Elem = (MLME_QUEUE_ELEM *) kmalloc(sizeof(MLME_QUEUE_ELEM), MEM_ALLOC_FLAG); - memmove(Elem->Msg+(LENGTH_802_11 + LENGTH_802_1_H), pPayload, PayloadSize); - Elem->MsgLen = LENGTH_802_11 + LENGTH_802_1_H + PayloadSize; - WpaEAPOLKeyAction(pAd, Elem); - kfree(Elem); - } -#endif // CONFIG_STA_SUPPORT // - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - if (pRemovedLLCSNAP) - { - pPayload -= LENGTH_802_3; - PayloadSize += LENGTH_802_3; - NdisMoveMemory(pPayload, &Header802_3[0], LENGTH_802_3); - } - } -#endif // CONFIG_STA_SUPPORT // - - pClonePacket = ClonePacket(pAd, pPacket, pPayload, PayloadSize); - if (pClonePacket) - { -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - ANNOUNCE_OR_FORWARD_802_3_PACKET(pAd, pClonePacket, RTMP_GET_PACKET_IF(pPacket)); -#endif // CONFIG_STA_SUPPORT // - } - - - // A-MSDU has padding to multiple of 4 including subframe header. - // align SubFrameSize up to multiple of 4 - SubFrameSize = (SubFrameSize+3)&(~0x3); - - - if (SubFrameSize > 1528 || SubFrameSize < 32) - { - break; - } - - if (DataSize > SubFrameSize) - { - pData += SubFrameSize; - DataSize -= SubFrameSize; - } - else - { - // end of A-MSDU - DataSize = 0; - } - } - - // finally release original rx packet - RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_SUCCESS); - - return nMSDU; -} - - -UINT BA_Reorder_AMSDU_Annnounce( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket) -{ - PUCHAR pData; - USHORT DataSize; - UINT nMSDU = 0; - - pData = (PUCHAR) GET_OS_PKT_DATAPTR(pPacket); - DataSize = (USHORT) GET_OS_PKT_LEN(pPacket); - - nMSDU = deaggregate_AMSDU_announce(pAd, pPacket, pData, DataSize); - - return nMSDU; -} - - -/* - ========================================================================== - Description: - Look up the MAC address in the MAC table. Return NULL if not found. - Return: - pEntry - pointer to the MAC entry; NULL is not found - ========================================================================== -*/ -MAC_TABLE_ENTRY *MacTableLookup( - IN PRTMP_ADAPTER pAd, - PUCHAR pAddr) -{ - ULONG HashIdx; - MAC_TABLE_ENTRY *pEntry = NULL; - - HashIdx = MAC_ADDR_HASH_INDEX(pAddr); - pEntry = pAd->MacTab.Hash[HashIdx]; - - while (pEntry && (pEntry->ValidAsCLI || pEntry->ValidAsWDS || pEntry->ValidAsApCli || pEntry->ValidAsMesh)) - { - if (MAC_ADDR_EQUAL(pEntry->Addr, pAddr)) - { - break; - } - else - pEntry = pEntry->pNext; - } - - return pEntry; -} - -MAC_TABLE_ENTRY *MacTableInsertEntry( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pAddr, - IN UCHAR apidx, - IN BOOLEAN CleanAll) -{ - UCHAR HashIdx; - int i, FirstWcid; - MAC_TABLE_ENTRY *pEntry = NULL, *pCurrEntry; -// USHORT offset; -// ULONG addr; - - // if FULL, return - if (pAd->MacTab.Size >= MAX_LEN_OF_MAC_TABLE) - return NULL; - - FirstWcid = 1; -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - if (pAd->StaCfg.BssType == BSS_INFRA) - FirstWcid = 2; -#endif // CONFIG_STA_SUPPORT // - - // allocate one MAC entry - NdisAcquireSpinLock(&pAd->MacTabLock); - for (i = FirstWcid; i< MAX_LEN_OF_MAC_TABLE; i++) // skip entry#0 so that "entry index == AID" for fast lookup - { - // pick up the first available vacancy - if ((pAd->MacTab.Content[i].ValidAsCLI == FALSE) && - (pAd->MacTab.Content[i].ValidAsWDS == FALSE) && - (pAd->MacTab.Content[i].ValidAsApCli== FALSE) && - (pAd->MacTab.Content[i].ValidAsMesh == FALSE) -#ifdef CONFIG_STA_SUPPORT -#ifdef QOS_DLS_SUPPORT - && (pAd->MacTab.Content[i].ValidAsDls == FALSE) -#endif // QOS_DLS_SUPPORT // -#endif // CONFIG_STA_SUPPORT // - ) - { - pEntry = &pAd->MacTab.Content[i]; - if (CleanAll == TRUE) - { - pEntry->MaxSupportedRate = RATE_11; - pEntry->CurrTxRate = RATE_11; - NdisZeroMemory(pEntry, sizeof(MAC_TABLE_ENTRY)); - pEntry->PairwiseKey.KeyLen = 0; - pEntry->PairwiseKey.CipherAlg = CIPHER_NONE; - } -#ifdef CONFIG_STA_SUPPORT -#ifdef QOS_DLS_SUPPORT - if (apidx >= MIN_NET_DEVICE_FOR_DLS) - { - pEntry->ValidAsCLI = FALSE; - pEntry->ValidAsWDS = FALSE; - pEntry->ValidAsApCli = FALSE; - pEntry->ValidAsMesh = FALSE; - pEntry->ValidAsDls = TRUE; - pEntry->isCached = FALSE; - } - else -#endif // QOS_DLS_SUPPORT // -#endif // CONFIG_STA_SUPPORT // - { - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - pEntry->ValidAsCLI = TRUE; - pEntry->ValidAsWDS = FALSE; - pEntry->ValidAsApCli = FALSE; - pEntry->ValidAsMesh = FALSE; - pEntry->ValidAsDls = FALSE; - } -#endif // CONFIG_STA_SUPPORT // - } - - pEntry->bIAmBadAtheros = FALSE; - pEntry->pAd = pAd; - pEntry->CMTimerRunning = FALSE; - pEntry->EnqueueEapolStartTimerRunning = EAPOL_START_DISABLE; - pEntry->RSNIE_Len = 0; - NdisZeroMemory(pEntry->R_Counter, sizeof(pEntry->R_Counter)); - pEntry->ReTryCounter = PEER_MSG1_RETRY_TIMER_CTR; - - if (pEntry->ValidAsMesh) - pEntry->apidx = (apidx - MIN_NET_DEVICE_FOR_MESH); - else if (pEntry->ValidAsApCli) - pEntry->apidx = (apidx - MIN_NET_DEVICE_FOR_APCLI); - else if (pEntry->ValidAsWDS) - pEntry->apidx = (apidx - MIN_NET_DEVICE_FOR_WDS); -#ifdef CONFIG_STA_SUPPORT -#ifdef QOS_DLS_SUPPORT - else if (pEntry->ValidAsDls) - pEntry->apidx = (apidx - MIN_NET_DEVICE_FOR_DLS); -#endif // QOS_DLS_SUPPORT // -#endif // CONFIG_STA_SUPPORT // - else - pEntry->apidx = apidx; - - { - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - pEntry->AuthMode = pAd->StaCfg.AuthMode; - pEntry->WepStatus = pAd->StaCfg.WepStatus; - pEntry->PrivacyFilter = Ndis802_11PrivFilterAcceptAll; - } -#endif // CONFIG_STA_SUPPORT // - } - - pEntry->GTKState = REKEY_NEGOTIATING; - pEntry->PairwiseKey.KeyLen = 0; - pEntry->PairwiseKey.CipherAlg = CIPHER_NONE; -#ifdef CONFIG_STA_SUPPORT -#ifdef QOS_DLS_SUPPORT - if (pEntry->ValidAsDls == TRUE) - pEntry->PortSecured = WPA_802_1X_PORT_SECURED; - else -#endif //QOS_DLS_SUPPORT -#endif // CONFIG_STA_SUPPORT // - pEntry->PortSecured = WPA_802_1X_PORT_NOT_SECURED; - pEntry->PMKID_CacheIdx = ENTRY_NOT_FOUND; - COPY_MAC_ADDR(pEntry->Addr, pAddr); - pEntry->Sst = SST_NOT_AUTH; - pEntry->AuthState = AS_NOT_AUTH; - pEntry->Aid = (USHORT)i; //0; - pEntry->CapabilityInfo = 0; - pEntry->PsMode = PWR_ACTIVE; - pEntry->PsQIdleCount = 0; - pEntry->NoDataIdleCount = 0; - pEntry->ContinueTxFailCnt = 0; - InitializeQueueHeader(&pEntry->PsQueue); - - - pAd->MacTab.Size ++; - - // Add this entry into ASIC RX WCID search table - RT28XX_STA_ENTRY_ADD(pAd, pEntry); - - - - DBGPRINT(RT_DEBUG_TRACE, ("MacTableInsertEntry - allocate entry #%d, Total= %d\n",i, pAd->MacTab.Size)); - break; - } - } - - // add this MAC entry into HASH table - if (pEntry) - { - HashIdx = MAC_ADDR_HASH_INDEX(pAddr); - if (pAd->MacTab.Hash[HashIdx] == NULL) - { - pAd->MacTab.Hash[HashIdx] = pEntry; - } - else - { - pCurrEntry = pAd->MacTab.Hash[HashIdx]; - while (pCurrEntry->pNext != NULL) - pCurrEntry = pCurrEntry->pNext; - pCurrEntry->pNext = pEntry; - } - } - - NdisReleaseSpinLock(&pAd->MacTabLock); - return pEntry; -} - -/* - ========================================================================== - Description: - Delete a specified client from MAC table - ========================================================================== - */ -BOOLEAN MacTableDeleteEntry( - IN PRTMP_ADAPTER pAd, - IN USHORT wcid, - IN PUCHAR pAddr) -{ - USHORT HashIdx; - MAC_TABLE_ENTRY *pEntry, *pPrevEntry, *pProbeEntry; - BOOLEAN Cancelled; - //USHORT offset; // unused variable - //UCHAR j; // unused variable - - if (wcid >= MAX_LEN_OF_MAC_TABLE) - return FALSE; - - NdisAcquireSpinLock(&pAd->MacTabLock); - - HashIdx = MAC_ADDR_HASH_INDEX(pAddr); - //pEntry = pAd->MacTab.Hash[HashIdx]; - pEntry = &pAd->MacTab.Content[wcid]; - - if (pEntry && (pEntry->ValidAsCLI || pEntry->ValidAsApCli || pEntry->ValidAsWDS || pEntry->ValidAsMesh -#ifdef CONFIG_STA_SUPPORT -#ifdef QOS_DLS_SUPPORT - || pEntry->ValidAsDls -#endif // QOS_DLS_SUPPORT // -#endif // CONFIG_STA_SUPPORT // - )) - { - if (MAC_ADDR_EQUAL(pEntry->Addr, pAddr)) - { - - // Delete this entry from ASIC on-chip WCID Table - RT28XX_STA_ENTRY_MAC_RESET(pAd, wcid); - -#ifdef DOT11_N_SUPPORT - // free resources of BA - BASessionTearDownALL(pAd, pEntry->Aid); -#endif // DOT11_N_SUPPORT // - - - pPrevEntry = NULL; - pProbeEntry = pAd->MacTab.Hash[HashIdx]; - ASSERT(pProbeEntry); - - // update Hash list - do - { - if (pProbeEntry == pEntry) - { - if (pPrevEntry == NULL) - { - pAd->MacTab.Hash[HashIdx] = pEntry->pNext; - } - else - { - pPrevEntry->pNext = pEntry->pNext; - } - break; - } - - pPrevEntry = pProbeEntry; - pProbeEntry = pProbeEntry->pNext; - } while (pProbeEntry); - - // not found !!! - ASSERT(pProbeEntry != NULL); - - RT28XX_STA_ENTRY_KEY_DEL(pAd, BSS0, wcid); - - - if (pEntry->EnqueueEapolStartTimerRunning != EAPOL_START_DISABLE) - { - RTMPCancelTimer(&pEntry->EnqueueStartForPSKTimer, &Cancelled); - pEntry->EnqueueEapolStartTimerRunning = EAPOL_START_DISABLE; - } - - - NdisZeroMemory(pEntry, sizeof(MAC_TABLE_ENTRY)); - pAd->MacTab.Size --; - DBGPRINT(RT_DEBUG_TRACE, ("MacTableDeleteEntry1 - Total= %d\n", pAd->MacTab.Size)); - } - else - { - printk("\n%s: Impossible Wcid = %d !!!!!\n", __FUNCTION__, wcid); - } - } - - NdisReleaseSpinLock(&pAd->MacTabLock); - - //Reset operating mode when no Sta. - if (pAd->MacTab.Size == 0) - { -#ifdef DOT11_N_SUPPORT - pAd->CommonCfg.AddHTInfo.AddHtInfo2.OperaionMode = 0; -#endif // DOT11_N_SUPPORT // - //AsicUpdateProtect(pAd, 0 /*pAd->CommonCfg.AddHTInfo.AddHtInfo2.OperaionMode*/, (ALLN_SETPROTECT), TRUE, 0 /*pAd->MacTab.fAnyStationNonGF*/); - RT28XX_UPDATE_PROTECT(pAd); // edit by johnli, fix "in_interrupt" error when call "MacTableDeleteEntry" in Rx tasklet - } - - return TRUE; -} - - -/* - ========================================================================== - Description: - This routine reset the entire MAC table. All packets pending in - the power-saving queues are freed here. - ========================================================================== - */ -VOID MacTableReset( - IN PRTMP_ADAPTER pAd) -{ - int i; - - DBGPRINT(RT_DEBUG_TRACE, ("MacTableReset\n")); - //NdisAcquireSpinLock(&pAd->MacTabLock); - - for (i=1; iMacTab.Content[i].ValidAsCLI == TRUE) - { - -#ifdef DOT11_N_SUPPORT - // free resources of BA - BASessionTearDownALL(pAd, i); -#endif // DOT11_N_SUPPORT // - - pAd->MacTab.Content[i].ValidAsCLI = FALSE; - - - -#ifdef RT2870 - NdisZeroMemory(pAd->MacTab.Content[i].Addr, 6); - RT28XX_STA_ENTRY_MAC_RESET(pAd, i); -#endif // RT2870 // - - //AsicDelWcidTab(pAd, i); - } - } - - return; -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== -*/ -VOID AssocParmFill( - IN PRTMP_ADAPTER pAd, - IN OUT MLME_ASSOC_REQ_STRUCT *AssocReq, - IN PUCHAR pAddr, - IN USHORT CapabilityInfo, - IN ULONG Timeout, - IN USHORT ListenIntv) -{ - COPY_MAC_ADDR(AssocReq->Addr, pAddr); - // Add mask to support 802.11b mode only - AssocReq->CapabilityInfo = CapabilityInfo & SUPPORTED_CAPABILITY_INFO; // not cf-pollable, not cf-poll-request - AssocReq->Timeout = Timeout; - AssocReq->ListenIntv = ListenIntv; -} - - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== -*/ -VOID DisassocParmFill( - IN PRTMP_ADAPTER pAd, - IN OUT MLME_DISASSOC_REQ_STRUCT *DisassocReq, - IN PUCHAR pAddr, - IN USHORT Reason) -{ - COPY_MAC_ADDR(DisassocReq->Addr, pAddr); - DisassocReq->Reason = Reason; -} - - -/* - ======================================================================== - - Routine Description: - Check the out going frame, if this is an DHCP or ARP datagram - will be duplicate another frame at low data rate transmit. - - Arguments: - pAd Pointer to our adapter - pPacket Pointer to outgoing Ndis frame - - Return Value: - TRUE To be duplicate at Low data rate transmit. (1mb) - FALSE Do nothing. - - IRQL = DISPATCH_LEVEL - - Note: - - MAC header + IP Header + UDP Header - 14 Bytes 20 Bytes - - UDP Header - 00|01|02|03|04|05|06|07|08|09|10|11|12|13|14|15| - Source Port - 16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31| - Destination Port - - port 0x43 means Bootstrap Protocol, server. - Port 0x44 means Bootstrap Protocol, client. - - ======================================================================== -*/ - -BOOLEAN RTMPCheckDHCPFrame( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket) -{ - PACKET_INFO PacketInfo; - ULONG NumberOfBytesRead = 0; - ULONG CurrentOffset = 0; - PVOID pVirtualAddress = NULL; - UINT NdisBufferLength; - PUCHAR pSrc; - USHORT Protocol; - UCHAR ByteOffset36 = 0; - UCHAR ByteOffset38 = 0; - BOOLEAN ReadFirstParm = TRUE; - - RTMP_QueryPacketInfo(pPacket, &PacketInfo, (PUCHAR *)&pVirtualAddress, &NdisBufferLength); - - NumberOfBytesRead += NdisBufferLength; - pSrc = (PUCHAR) pVirtualAddress; - Protocol = *(pSrc + 12) * 256 + *(pSrc + 13); - - // - // Check DHCP & BOOTP protocol - // - while (NumberOfBytesRead <= PacketInfo.TotalPacketLength) - { - if ((NumberOfBytesRead >= 35) && (ReadFirstParm == TRUE)) - { - CurrentOffset = 35 - (NumberOfBytesRead - NdisBufferLength); - ByteOffset36 = *(pSrc + CurrentOffset); - ReadFirstParm = FALSE; - } - - if (NumberOfBytesRead >= 37) - { - CurrentOffset = 37 - (NumberOfBytesRead - NdisBufferLength); - ByteOffset38 = *(pSrc + CurrentOffset); - //End of Read - break; - } - return FALSE; - } - - // Check for DHCP & BOOTP protocol - if ((ByteOffset36 != 0x44) || (ByteOffset38 != 0x43)) - { - // - // 2054 (hex 0806) for ARP datagrams - // if this packet is not ARP datagrams, then do nothing - // ARP datagrams will also be duplicate at 1mb broadcast frames - // - if (Protocol != 0x0806 ) - return FALSE; - } - - return TRUE; -} - - -BOOLEAN RTMPCheckEtherType( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket) -{ - USHORT TypeLen; - UCHAR Byte0, Byte1; - PUCHAR pSrcBuf; - UINT32 pktLen; - UINT16 srcPort, dstPort; - BOOLEAN status = TRUE; - - - pSrcBuf = GET_OS_PKT_DATAPTR(pPacket); - pktLen = GET_OS_PKT_LEN(pPacket); - - ASSERT(pSrcBuf); - - RTMP_SET_PACKET_SPECIFIC(pPacket, 0); - - // get Ethernet protocol field - TypeLen = (pSrcBuf[12] << 8) + pSrcBuf[13]; - - pSrcBuf += LENGTH_802_3; // Skip the Ethernet Header. - - if (TypeLen <= 1500) - { // 802.3, 802.3 LLC - /* - DestMAC(6) + SrcMAC(6) + Lenght(2) + - DSAP(1) + SSAP(1) + Control(1) + - if the DSAP = 0xAA, SSAP=0xAA, Contorl = 0x03, it has a 5-bytes SNAP header. - => + SNAP (5, OriginationID(3) + etherType(2)) - */ - if (pSrcBuf[0] == 0xAA && pSrcBuf[1] == 0xAA && pSrcBuf[2] == 0x03) - { - Sniff2BytesFromNdisBuffer(pSrcBuf, 6, &Byte0, &Byte1); - RTMP_SET_PACKET_LLCSNAP(pPacket, 1); - TypeLen = (USHORT)((Byte0 << 8) + Byte1); - pSrcBuf += 8; // Skip this LLC/SNAP header - } - else - { - //It just has 3-byte LLC header, maybe a legacy ether type frame. we didn't handle it. - } - } - - // If it's a VLAN packet, get the real Type/Length field. - if (TypeLen == 0x8100) - { - /* 0x8100 means VLAN packets */ - - /* Dest. MAC Address (6-bytes) + - Source MAC Address (6-bytes) + - Length/Type = 802.1Q Tag Type (2-byte) + - Tag Control Information (2-bytes) + - Length / Type (2-bytes) + - data payload (0-n bytes) + - Pad (0-p bytes) + - Frame Check Sequence (4-bytes) */ - - RTMP_SET_PACKET_VLAN(pPacket, 1); - Sniff2BytesFromNdisBuffer(pSrcBuf, 2, &Byte0, &Byte1); - TypeLen = (USHORT)((Byte0 << 8) + Byte1); - - pSrcBuf += 4; // Skip the VLAN Header. - } - - switch (TypeLen) - { - case 0x0800: - { - ASSERT((pktLen > 34)); - if (*(pSrcBuf + 9) == 0x11) - { // udp packet - ASSERT((pktLen > 34)); // 14 for ethernet header, 20 for IP header - - pSrcBuf += 20; // Skip the IP header - srcPort = OS_NTOHS(*((UINT16 *)pSrcBuf)); - dstPort = OS_NTOHS(*((UINT16 *)(pSrcBuf +2))); - - if ((srcPort==0x44 && dstPort==0x43) || (srcPort==0x43 && dstPort==0x44)) - { //It's a BOOTP/DHCP packet - RTMP_SET_PACKET_DHCP(pPacket, 1); - } - } - } - break; - case 0x0806: - { - //ARP Packet. - RTMP_SET_PACKET_DHCP(pPacket, 1); - } - break; - case 0x888e: - { - // EAPOL Packet. - RTMP_SET_PACKET_EAPOL(pPacket, 1); - } - break; - default: - status = FALSE; - break; - } - - return status; - -} - - - -VOID Update_Rssi_Sample( - IN PRTMP_ADAPTER pAd, - IN RSSI_SAMPLE *pRssi, - IN PRXWI_STRUC pRxWI) - { - CHAR rssi0 = pRxWI->RSSI0; - CHAR rssi1 = pRxWI->RSSI1; - CHAR rssi2 = pRxWI->RSSI2; - - if (rssi0 != 0) - { - pRssi->LastRssi0 = ConvertToRssi(pAd, (CHAR)rssi0, RSSI_0); - pRssi->AvgRssi0X8 = (pRssi->AvgRssi0X8 - pRssi->AvgRssi0) + pRssi->LastRssi0; - pRssi->AvgRssi0 = pRssi->AvgRssi0X8 >> 3; - } - - if (rssi1 != 0) - { - pRssi->LastRssi1 = ConvertToRssi(pAd, (CHAR)rssi1, RSSI_1); - pRssi->AvgRssi1X8 = (pRssi->AvgRssi1X8 - pRssi->AvgRssi1) + pRssi->LastRssi1; - pRssi->AvgRssi1 = pRssi->AvgRssi1X8 >> 3; - } - - if (rssi2 != 0) - { - pRssi->LastRssi2 = ConvertToRssi(pAd, (CHAR)rssi2, RSSI_2); - pRssi->AvgRssi2X8 = (pRssi->AvgRssi2X8 - pRssi->AvgRssi2) + pRssi->LastRssi2; - pRssi->AvgRssi2 = pRssi->AvgRssi2X8 >> 3; - } -} - - - -// Normal legacy Rx packet indication -VOID Indicate_Legacy_Packet( - IN PRTMP_ADAPTER pAd, - IN RX_BLK *pRxBlk, - IN UCHAR FromWhichBSSID) -{ - PNDIS_PACKET pRxPacket = pRxBlk->pRxPacket; - UCHAR Header802_3[LENGTH_802_3]; - - // 1. get 802.3 Header - // 2. remove LLC - // a. pointer pRxBlk->pData to payload - // b. modify pRxBlk->DataSize -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - RTMP_802_11_REMOVE_LLC_AND_CONVERT_TO_802_3(pRxBlk, Header802_3); -#endif // CONFIG_STA_SUPPORT // - - if (pRxBlk->DataSize > MAX_RX_PKT_LEN) - { - // release packet - RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); - return; - } - - - STATS_INC_RX_PACKETS(pAd, FromWhichBSSID); - -#ifdef RT2870 -#ifdef DOT11_N_SUPPORT - if (pAd->CommonCfg.bDisableReordering == 0) - { - PBA_REC_ENTRY pBAEntry; - ULONG Now32; - UCHAR Wcid = pRxBlk->pRxWI->WirelessCliID; - UCHAR TID = pRxBlk->pRxWI->TID; - USHORT Idx; - -#define REORDERING_PACKET_TIMEOUT ((100 * HZ)/1000) // system ticks -- 100 ms - - if (Wcid < MAX_LEN_OF_MAC_TABLE) - { - Idx = pAd->MacTab.Content[Wcid].BARecWcidArray[TID]; - if (Idx != 0) - { - pBAEntry = &pAd->BATable.BARecEntry[Idx]; - // update last rx time - NdisGetSystemUpTime(&Now32); - if ((pBAEntry->list.qlen > 0) && - RTMP_TIME_AFTER((unsigned long)Now32, (unsigned long)(pBAEntry->LastIndSeqAtTimer+(REORDERING_PACKET_TIMEOUT))) - ) - { - printk("Indicate_Legacy_Packet():flush reordering_timeout_mpdus! RxWI->Flags=%d, pRxWI.TID=%d, RxD->AMPDU=%d!\n", pRxBlk->Flags, pRxBlk->pRxWI->TID, pRxBlk->RxD.AMPDU); - hex_dump("Dump the legacy Packet:", GET_OS_PKT_DATAPTR(pRxBlk->pRxPacket), 64); - ba_flush_reordering_timeout_mpdus(pAd, pBAEntry, Now32); - } - } - } - } -#endif // DOT11_N_SUPPORT // -#endif // RT2870 // - - wlan_802_11_to_802_3_packet(pAd, pRxBlk, Header802_3, FromWhichBSSID); - - // - // pass this 802.3 packet to upper layer or forward this packet to WM directly - // -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - ANNOUNCE_OR_FORWARD_802_3_PACKET(pAd, pRxPacket, FromWhichBSSID); -#endif // CONFIG_STA_SUPPORT // - -} - - -// Normal, AMPDU or AMSDU -VOID CmmRxnonRalinkFrameIndicate( - IN PRTMP_ADAPTER pAd, - IN RX_BLK *pRxBlk, - IN UCHAR FromWhichBSSID) -{ -#ifdef DOT11_N_SUPPORT - if (RX_BLK_TEST_FLAG(pRxBlk, fRX_AMPDU) && (pAd->CommonCfg.bDisableReordering == 0)) - { - Indicate_AMPDU_Packet(pAd, pRxBlk, FromWhichBSSID); - } - else -#endif // DOT11_N_SUPPORT // - { -#ifdef DOT11_N_SUPPORT - if (RX_BLK_TEST_FLAG(pRxBlk, fRX_AMSDU)) - { - // handle A-MSDU - Indicate_AMSDU_Packet(pAd, pRxBlk, FromWhichBSSID); - } - else -#endif // DOT11_N_SUPPORT // - { - Indicate_Legacy_Packet(pAd, pRxBlk, FromWhichBSSID); - } - } -} - - -VOID CmmRxRalinkFrameIndicate( - IN PRTMP_ADAPTER pAd, - IN MAC_TABLE_ENTRY *pEntry, - IN RX_BLK *pRxBlk, - IN UCHAR FromWhichBSSID) -{ - UCHAR Header802_3[LENGTH_802_3]; - UINT16 Msdu2Size; - UINT16 Payload1Size, Payload2Size; - PUCHAR pData2; - PNDIS_PACKET pPacket2 = NULL; - - - - Msdu2Size = *(pRxBlk->pData) + (*(pRxBlk->pData+1) << 8); - - if ((Msdu2Size <= 1536) && (Msdu2Size < pRxBlk->DataSize)) - { - /* skip two byte MSDU2 len */ - pRxBlk->pData += 2; - pRxBlk->DataSize -= 2; - } - else - { - // release packet - RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); - return; - } - - // get 802.3 Header and remove LLC -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - RTMP_802_11_REMOVE_LLC_AND_CONVERT_TO_802_3(pRxBlk, Header802_3); -#endif // CONFIG_STA_SUPPORT // - - - ASSERT(pRxBlk->pRxPacket); - - // Ralink Aggregation frame - pAd->RalinkCounters.OneSecRxAggregationCount ++; - Payload1Size = pRxBlk->DataSize - Msdu2Size; - Payload2Size = Msdu2Size - LENGTH_802_3; - - pData2 = pRxBlk->pData + Payload1Size + LENGTH_802_3; -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - pPacket2 = duplicate_pkt(pAd, (pData2-LENGTH_802_3), LENGTH_802_3, pData2, Payload2Size, FromWhichBSSID); -#endif // CONFIG_STA_SUPPORT // - - if (!pPacket2) - { - // release packet - RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); - return; - } - - // update payload size of 1st packet - pRxBlk->DataSize = Payload1Size; - wlan_802_11_to_802_3_packet(pAd, pRxBlk, Header802_3, FromWhichBSSID); - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - ANNOUNCE_OR_FORWARD_802_3_PACKET(pAd, pRxBlk->pRxPacket, FromWhichBSSID); -#endif // CONFIG_STA_SUPPORT // - - if (pPacket2) - { -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - ANNOUNCE_OR_FORWARD_802_3_PACKET(pAd, pPacket2, FromWhichBSSID); -#endif // CONFIG_STA_SUPPORT // - } -} - - -#define RESET_FRAGFRAME(_fragFrame) \ - { \ - _fragFrame.RxSize = 0; \ - _fragFrame.Sequence = 0; \ - _fragFrame.LastFrag = 0; \ - _fragFrame.Flags = 0; \ - } - - -PNDIS_PACKET RTMPDeFragmentDataFrame( - IN PRTMP_ADAPTER pAd, - IN RX_BLK *pRxBlk) -{ - PHEADER_802_11 pHeader = pRxBlk->pHeader; - PNDIS_PACKET pRxPacket = pRxBlk->pRxPacket; - UCHAR *pData = pRxBlk->pData; - USHORT DataSize = pRxBlk->DataSize; - PNDIS_PACKET pRetPacket = NULL; - UCHAR *pFragBuffer = NULL; - BOOLEAN bReassDone = FALSE; - UCHAR HeaderRoom = 0; - - - ASSERT(pHeader); - - HeaderRoom = pData - (UCHAR *)pHeader; - - // Re-assemble the fragmented packets - if (pHeader->Frag == 0) // Frag. Number is 0 : First frag or only one pkt - { - // the first pkt of fragment, record it. - if (pHeader->FC.MoreFrag) - { - ASSERT(pAd->FragFrame.pFragPacket); - pFragBuffer = GET_OS_PKT_DATAPTR(pAd->FragFrame.pFragPacket); - pAd->FragFrame.RxSize = DataSize + HeaderRoom; - NdisMoveMemory(pFragBuffer, pHeader, pAd->FragFrame.RxSize); - pAd->FragFrame.Sequence = pHeader->Sequence; - pAd->FragFrame.LastFrag = pHeader->Frag; // Should be 0 - ASSERT(pAd->FragFrame.LastFrag == 0); - goto done; // end of processing this frame - } - } - else //Middle & End of fragment - { - if ((pHeader->Sequence != pAd->FragFrame.Sequence) || - (pHeader->Frag != (pAd->FragFrame.LastFrag + 1))) - { - // Fragment is not the same sequence or out of fragment number order - // Reset Fragment control blk - RESET_FRAGFRAME(pAd->FragFrame); - DBGPRINT(RT_DEBUG_ERROR, ("Fragment is not the same sequence or out of fragment number order.\n")); - goto done; // give up this frame - } - else if ((pAd->FragFrame.RxSize + DataSize) > MAX_FRAME_SIZE) - { - // Fragment frame is too large, it exeeds the maximum frame size. - // Reset Fragment control blk - RESET_FRAGFRAME(pAd->FragFrame); - DBGPRINT(RT_DEBUG_ERROR, ("Fragment frame is too large, it exeeds the maximum frame size.\n")); - goto done; // give up this frame - } - - // - // Broadcom AP(BCM94704AGR) will send out LLC in fragment's packet, LLC only can accpet at first fragment. - // In this case, we will dropt it. - // - if (NdisEqualMemory(pData, SNAP_802_1H, sizeof(SNAP_802_1H))) - { - DBGPRINT(RT_DEBUG_ERROR, ("Find another LLC at Middle or End fragment(SN=%d, Frag=%d)\n", pHeader->Sequence, pHeader->Frag)); - goto done; // give up this frame - } - - pFragBuffer = GET_OS_PKT_DATAPTR(pAd->FragFrame.pFragPacket); - - // concatenate this fragment into the re-assembly buffer - NdisMoveMemory((pFragBuffer + pAd->FragFrame.RxSize), pData, DataSize); - pAd->FragFrame.RxSize += DataSize; - pAd->FragFrame.LastFrag = pHeader->Frag; // Update fragment number - - // Last fragment - if (pHeader->FC.MoreFrag == FALSE) - { - bReassDone = TRUE; - } - } - -done: - // always release rx fragmented packet - RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); - - // return defragmented packet if packet is reassembled completely - // otherwise return NULL - if (bReassDone) - { - PNDIS_PACKET pNewFragPacket; - - // allocate a new packet buffer for fragment - pNewFragPacket = RTMP_AllocateFragPacketBuffer(pAd, RX_BUFFER_NORMSIZE); - if (pNewFragPacket) - { - // update RxBlk - pRetPacket = pAd->FragFrame.pFragPacket; - pAd->FragFrame.pFragPacket = pNewFragPacket; - pRxBlk->pHeader = (PHEADER_802_11) GET_OS_PKT_DATAPTR(pRetPacket); - pRxBlk->pData = (UCHAR *)pRxBlk->pHeader + HeaderRoom; - pRxBlk->DataSize = pAd->FragFrame.RxSize - HeaderRoom; - pRxBlk->pRxPacket = pRetPacket; - } - else - { - RESET_FRAGFRAME(pAd->FragFrame); - } - } - - return pRetPacket; -} - - -VOID Indicate_AMSDU_Packet( - IN PRTMP_ADAPTER pAd, - IN RX_BLK *pRxBlk, - IN UCHAR FromWhichBSSID) -{ - UINT nMSDU; - - update_os_packet_info(pAd, pRxBlk, FromWhichBSSID); - RTMP_SET_PACKET_IF(pRxBlk->pRxPacket, FromWhichBSSID); - nMSDU = deaggregate_AMSDU_announce(pAd, pRxBlk->pRxPacket, pRxBlk->pData, pRxBlk->DataSize); -} - -VOID Indicate_EAPOL_Packet( - IN PRTMP_ADAPTER pAd, - IN RX_BLK *pRxBlk, - IN UCHAR FromWhichBSSID) -{ - MAC_TABLE_ENTRY *pEntry = NULL; - - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - pEntry = &pAd->MacTab.Content[BSSID_WCID]; - STARxEAPOLFrameIndicate(pAd, pEntry, pRxBlk, FromWhichBSSID); - return; - } -#endif // CONFIG_STA_SUPPORT // - - if (pEntry == NULL) - { - DBGPRINT(RT_DEBUG_WARN, ("Indicate_EAPOL_Packet: drop and release the invalid packet.\n")); - // release packet - RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); - return; - } -} - -#define BCN_TBTT_OFFSET 64 //defer 64 us -VOID ReSyncBeaconTime( - IN PRTMP_ADAPTER pAd) -{ - - UINT32 Offset; - - - Offset = (pAd->TbttTickCount) % (BCN_TBTT_OFFSET); - - pAd->TbttTickCount++; - - // - // The updated BeaconInterval Value will affect Beacon Interval after two TBTT - // beacasue the original BeaconInterval had been loaded into next TBTT_TIMER - // - if (Offset == (BCN_TBTT_OFFSET-2)) - { - BCN_TIME_CFG_STRUC csr; - RTMP_IO_READ32(pAd, BCN_TIME_CFG, &csr.word); - csr.field.BeaconInterval = (pAd->CommonCfg.BeaconPeriod << 4) - 1 ; // ASIC register in units of 1/16 TU = 64us - RTMP_IO_WRITE32(pAd, BCN_TIME_CFG, csr.word); - } - else - { - if (Offset == (BCN_TBTT_OFFSET-1)) - { - BCN_TIME_CFG_STRUC csr; - - RTMP_IO_READ32(pAd, BCN_TIME_CFG, &csr.word); - csr.field.BeaconInterval = (pAd->CommonCfg.BeaconPeriod) << 4; // ASIC register in units of 1/16 TU - RTMP_IO_WRITE32(pAd, BCN_TIME_CFG, csr.word); - } - } -} - +#include "../../rt2870/common/cmm_data.c" diff --git a/drivers/staging/rt3070/common/cmm_data_2870.c b/drivers/staging/rt3070/common/cmm_data_2870.c index b1066aa2bb23..0e51ee414a2c 100644 --- a/drivers/staging/rt3070/common/cmm_data_2870.c +++ b/drivers/staging/rt3070/common/cmm_data_2870.c @@ -1,980 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * 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. * - * * - ************************************************************************* -*/ -/* - All functions in this file must be USB-depended, or you should out your function - in other files. - -*/ -#include "../rt_config.h" - - -/* - We can do copy the frame into pTxContext when match following conditions. - => - => - => -*/ -static inline NDIS_STATUS RtmpUSBCanDoWrite( - IN RTMP_ADAPTER *pAd, - IN UCHAR QueIdx, - IN HT_TX_CONTEXT *pHTTXContext) -{ - NDIS_STATUS canWrite = NDIS_STATUS_RESOURCES; - - if (((pHTTXContext->CurWritePosition) < pHTTXContext->NextBulkOutPosition) && (pHTTXContext->CurWritePosition + LOCAL_TXBUF_SIZE) > pHTTXContext->NextBulkOutPosition) - { - DBGPRINT(RT_DEBUG_ERROR,("RtmpUSBCanDoWrite c1!\n")); - RTUSB_SET_BULK_FLAG(pAd, (fRTUSB_BULK_OUT_DATA_NORMAL << QueIdx)); - } - else if ((pHTTXContext->CurWritePosition == 8) && (pHTTXContext->NextBulkOutPosition < LOCAL_TXBUF_SIZE)) - { - DBGPRINT(RT_DEBUG_ERROR,("RtmpUSBCanDoWrite c2!\n")); - RTUSB_SET_BULK_FLAG(pAd, (fRTUSB_BULK_OUT_DATA_NORMAL << QueIdx)); - } - else if (pHTTXContext->bCurWriting == TRUE) - { - DBGPRINT(RT_DEBUG_ERROR,("RtmpUSBCanDoWrite c3!\n")); - } - else - { - canWrite = NDIS_STATUS_SUCCESS; - } - - - return canWrite; -} - - -USHORT RtmpUSB_WriteSubTxResource( - IN PRTMP_ADAPTER pAd, - IN TX_BLK *pTxBlk, - IN BOOLEAN bIsLast, - OUT USHORT *FreeNumber) -{ - - // Dummy function. Should be removed in the future. - return 0; - -} - -USHORT RtmpUSB_WriteFragTxResource( - IN PRTMP_ADAPTER pAd, - IN TX_BLK *pTxBlk, - IN UCHAR fragNum, - OUT USHORT *FreeNumber) -{ - HT_TX_CONTEXT *pHTTXContext; - USHORT hwHdrLen; // The hwHdrLen consist of 802.11 header length plus the header padding length. - UINT32 fillOffset; - TXINFO_STRUC *pTxInfo; - TXWI_STRUC *pTxWI; - PUCHAR pWirelessPacket = NULL; - UCHAR QueIdx; - NDIS_STATUS Status; - unsigned long IrqFlags; - UINT32 USBDMApktLen = 0, DMAHdrLen, padding; - BOOLEAN TxQLastRound = FALSE; - - // - // get Tx Ring Resource & Dma Buffer address - // - QueIdx = pTxBlk->QueIdx; - pHTTXContext = &pAd->TxContext[QueIdx]; - - RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); - - pHTTXContext = &pAd->TxContext[QueIdx]; - fillOffset = pHTTXContext->CurWritePosition; - - if(fragNum == 0) - { - // Check if we have enough space for this bulk-out batch. - Status = RtmpUSBCanDoWrite(pAd, QueIdx, pHTTXContext); - if (Status == NDIS_STATUS_SUCCESS) - { - pHTTXContext->bCurWriting = TRUE; - - // Reserve space for 8 bytes padding. - if ((pHTTXContext->ENextBulkOutPosition == pHTTXContext->CurWritePosition)) - { - pHTTXContext->ENextBulkOutPosition += 8; - pHTTXContext->CurWritePosition += 8; - fillOffset += 8; - } - pTxBlk->Priv = 0; - pHTTXContext->CurWriteRealPos = pHTTXContext->CurWritePosition; - } - else - { - RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); - - RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_FAILURE); - return(Status); - } - } - else - { - // For sub-sequent frames of this bulk-out batch. Just copy it to our bulk-out buffer. - Status = ((pHTTXContext->bCurWriting == TRUE) ? NDIS_STATUS_SUCCESS : NDIS_STATUS_FAILURE); - if (Status == NDIS_STATUS_SUCCESS) - { - fillOffset += pTxBlk->Priv; - } - else - { - RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); - - RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_FAILURE); - return(Status); - } - } - - NdisZeroMemory((PUCHAR)(&pTxBlk->HeaderBuf[0]), TXINFO_SIZE); - pTxInfo = (PTXINFO_STRUC)(&pTxBlk->HeaderBuf[0]); - pTxWI= (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]); - - pWirelessPacket = &pHTTXContext->TransferBuffer->field.WirelessPacket[fillOffset]; - - // copy TXWI + WLAN Header + LLC into DMA Header Buffer - //hwHdrLen = ROUND_UP(pTxBlk->MpduHeaderLen, 4); - hwHdrLen = pTxBlk->MpduHeaderLen + pTxBlk->HdrPadLen; - - // Build our URB for USBD - DMAHdrLen = TXWI_SIZE + hwHdrLen; - USBDMApktLen = DMAHdrLen + pTxBlk->SrcBufLen; - padding = (4 - (USBDMApktLen % 4)) & 0x03; // round up to 4 byte alignment - USBDMApktLen += padding; - - pTxBlk->Priv += (TXINFO_SIZE + USBDMApktLen); - - // For TxInfo, the length of USBDMApktLen = TXWI_SIZE + 802.11 header + payload - RTMPWriteTxInfo(pAd, pTxInfo, (USHORT)(USBDMApktLen), FALSE, FIFO_EDCA, FALSE /*NextValid*/, FALSE); - - if (fragNum == pTxBlk->TotalFragNum) - { - pTxInfo->USBDMATxburst = 0; - if ((pHTTXContext->CurWritePosition + pTxBlk->Priv + 3906)> MAX_TXBULK_LIMIT) - { - pTxInfo->SwUseLastRound = 1; - TxQLastRound = TRUE; - } - } - else - { - pTxInfo->USBDMATxburst = 1; - } - - NdisMoveMemory(pWirelessPacket, pTxBlk->HeaderBuf, TXINFO_SIZE + TXWI_SIZE + hwHdrLen); -#ifdef RT_BIG_ENDIAN - RTMPFrameEndianChange(pAd, (PUCHAR)(pWirelessPacket + TXINFO_SIZE + TXWI_SIZE), DIR_WRITE, FALSE); -#endif // RT_BIG_ENDIAN // - pWirelessPacket += (TXINFO_SIZE + TXWI_SIZE + hwHdrLen); - pHTTXContext->CurWriteRealPos += (TXINFO_SIZE + TXWI_SIZE + hwHdrLen); - - RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); - - NdisMoveMemory(pWirelessPacket, pTxBlk->pSrcBufData, pTxBlk->SrcBufLen); - - // Zero the last padding. - pWirelessPacket += pTxBlk->SrcBufLen; - NdisZeroMemory(pWirelessPacket, padding + 8); - - if (fragNum == pTxBlk->TotalFragNum) - { - RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); - - // Update the pHTTXContext->CurWritePosition. 3906 used to prevent the NextBulkOut is a A-RALINK/A-MSDU Frame. - pHTTXContext->CurWritePosition += pTxBlk->Priv; - if (TxQLastRound == TRUE) - pHTTXContext->CurWritePosition = 8; - pHTTXContext->CurWriteRealPos = pHTTXContext->CurWritePosition; - - - // Finally, set bCurWriting as FALSE - pHTTXContext->bCurWriting = FALSE; - - RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); - - // succeed and release the skb buffer - RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_SUCCESS); - } - - - return(Status); - -} - - -USHORT RtmpUSB_WriteSingleTxResource( - IN PRTMP_ADAPTER pAd, - IN TX_BLK *pTxBlk, - IN BOOLEAN bIsLast, - OUT USHORT *FreeNumber) -{ - HT_TX_CONTEXT *pHTTXContext; - USHORT hwHdrLen; - UINT32 fillOffset; - TXINFO_STRUC *pTxInfo; - TXWI_STRUC *pTxWI; - PUCHAR pWirelessPacket; - UCHAR QueIdx; - unsigned long IrqFlags; - NDIS_STATUS Status; - UINT32 USBDMApktLen = 0, DMAHdrLen, padding; - BOOLEAN bTxQLastRound = FALSE; - - // For USB, didn't need PCI_MAP_SINGLE() - //SrcBufPA = PCI_MAP_SINGLE(pAd, (char *) pTxBlk->pSrcBufData, pTxBlk->SrcBufLen, PCI_DMA_TODEVICE); - - - // - // get Tx Ring Resource & Dma Buffer address - // - QueIdx = pTxBlk->QueIdx; - - RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); - pHTTXContext = &pAd->TxContext[QueIdx]; - fillOffset = pHTTXContext->CurWritePosition; - - - - // Check ring full. - Status = RtmpUSBCanDoWrite(pAd, QueIdx, pHTTXContext); - if(Status == NDIS_STATUS_SUCCESS) - { - pHTTXContext->bCurWriting = TRUE; - - pTxInfo = (PTXINFO_STRUC)(&pTxBlk->HeaderBuf[0]); - pTxWI= (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]); - - // Reserve space for 8 bytes padding. - if ((pHTTXContext->ENextBulkOutPosition == pHTTXContext->CurWritePosition)) - { - pHTTXContext->ENextBulkOutPosition += 8; - pHTTXContext->CurWritePosition += 8; - fillOffset += 8; - } - pHTTXContext->CurWriteRealPos = pHTTXContext->CurWritePosition; - - pWirelessPacket = &pHTTXContext->TransferBuffer->field.WirelessPacket[fillOffset]; - - // copy TXWI + WLAN Header + LLC into DMA Header Buffer - //hwHdrLen = ROUND_UP(pTxBlk->MpduHeaderLen, 4); - hwHdrLen = pTxBlk->MpduHeaderLen + pTxBlk->HdrPadLen; - - // Build our URB for USBD - DMAHdrLen = TXWI_SIZE + hwHdrLen; - USBDMApktLen = DMAHdrLen + pTxBlk->SrcBufLen; - padding = (4 - (USBDMApktLen % 4)) & 0x03; // round up to 4 byte alignment - USBDMApktLen += padding; - - pTxBlk->Priv = (TXINFO_SIZE + USBDMApktLen); - - // For TxInfo, the length of USBDMApktLen = TXWI_SIZE + 802.11 header + payload - //PS packets use HCCA queue when dequeue from PS unicast queue (WiFi WPA2 MA9_DT1 for Marvell B STA) -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - RTMPWriteTxInfo(pAd, pTxInfo, (USHORT)(USBDMApktLen), FALSE, FIFO_EDCA, FALSE /*NextValid*/, FALSE); -#endif // CONFIG_STA_SUPPORT // - - if ((pHTTXContext->CurWritePosition + 3906 + pTxBlk->Priv) > MAX_TXBULK_LIMIT) - { - pTxInfo->SwUseLastRound = 1; - bTxQLastRound = TRUE; - } - NdisMoveMemory(pWirelessPacket, pTxBlk->HeaderBuf, TXINFO_SIZE + TXWI_SIZE + hwHdrLen); -#ifdef RT_BIG_ENDIAN - RTMPFrameEndianChange(pAd, (PUCHAR)(pWirelessPacket + TXINFO_SIZE + TXWI_SIZE), DIR_WRITE, FALSE); -#endif // RT_BIG_ENDIAN // - pWirelessPacket += (TXINFO_SIZE + TXWI_SIZE + hwHdrLen); - - // We unlock it here to prevent the first 8 bytes maybe over-writed issue. - // 1. First we got CurWritePosition but the first 8 bytes still not write to the pTxcontext. - // 2. An interrupt break our routine and handle bulk-out complete. - // 3. In the bulk-out compllete, it need to do another bulk-out, - // if the ENextBulkOutPosition is just the same as CurWritePosition, it will save the first 8 bytes from CurWritePosition, - // but the payload still not copyed. the pTxContext->SavedPad[] will save as allzero. and set the bCopyPad = TRUE. - // 4. Interrupt complete. - // 5. Our interrupted routine go back and fill the first 8 bytes to pTxContext. - // 6. Next time when do bulk-out, it found the bCopyPad==TRUE and will copy the SavedPad[] to pTxContext->NextBulkOutPosition. - // and the packet will wrong. - pHTTXContext->CurWriteRealPos += (TXINFO_SIZE + TXWI_SIZE + hwHdrLen); - RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); - - NdisMoveMemory(pWirelessPacket, pTxBlk->pSrcBufData, pTxBlk->SrcBufLen); - pWirelessPacket += pTxBlk->SrcBufLen; - NdisZeroMemory(pWirelessPacket, padding + 8); - - RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); - - pHTTXContext->CurWritePosition += pTxBlk->Priv; - if (bTxQLastRound) - pHTTXContext->CurWritePosition = 8; - pHTTXContext->CurWriteRealPos = pHTTXContext->CurWritePosition; - - pHTTXContext->bCurWriting = FALSE; - } - - - RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); - - - // succeed and release the skb buffer - RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_SUCCESS); - - return(Status); - -} - - -USHORT RtmpUSB_WriteMultiTxResource( - IN PRTMP_ADAPTER pAd, - IN TX_BLK *pTxBlk, - IN UCHAR frameNum, - OUT USHORT *FreeNumber) -{ - HT_TX_CONTEXT *pHTTXContext; - USHORT hwHdrLen; // The hwHdrLen consist of 802.11 header length plus the header padding length. - UINT32 fillOffset; - TXINFO_STRUC *pTxInfo; - TXWI_STRUC *pTxWI; - PUCHAR pWirelessPacket = NULL; - UCHAR QueIdx; - NDIS_STATUS Status; - unsigned long IrqFlags; - //UINT32 USBDMApktLen = 0, DMAHdrLen, padding; - - // - // get Tx Ring Resource & Dma Buffer address - // - QueIdx = pTxBlk->QueIdx; - pHTTXContext = &pAd->TxContext[QueIdx]; - - RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); - - if(frameNum == 0) - { - // Check if we have enough space for this bulk-out batch. - Status = RtmpUSBCanDoWrite(pAd, QueIdx, pHTTXContext); - if (Status == NDIS_STATUS_SUCCESS) - { - pHTTXContext->bCurWriting = TRUE; - - pTxInfo = (PTXINFO_STRUC)(&pTxBlk->HeaderBuf[0]); - pTxWI= (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]); - - - // Reserve space for 8 bytes padding. - if ((pHTTXContext->ENextBulkOutPosition == pHTTXContext->CurWritePosition)) - { - - pHTTXContext->CurWritePosition += 8; - pHTTXContext->ENextBulkOutPosition += 8; - } - fillOffset = pHTTXContext->CurWritePosition; - pHTTXContext->CurWriteRealPos = pHTTXContext->CurWritePosition; - - pWirelessPacket = &pHTTXContext->TransferBuffer->field.WirelessPacket[fillOffset]; - - // - // Copy TXINFO + TXWI + WLAN Header + LLC into DMA Header Buffer - // - if (pTxBlk->TxFrameType == TX_AMSDU_FRAME) - //hwHdrLen = ROUND_UP(pTxBlk->MpduHeaderLen-LENGTH_AMSDU_SUBFRAMEHEAD, 4)+LENGTH_AMSDU_SUBFRAMEHEAD; - hwHdrLen = pTxBlk->MpduHeaderLen-LENGTH_AMSDU_SUBFRAMEHEAD + pTxBlk->HdrPadLen + LENGTH_AMSDU_SUBFRAMEHEAD; - else if (pTxBlk->TxFrameType == TX_RALINK_FRAME) - //hwHdrLen = ROUND_UP(pTxBlk->MpduHeaderLen-LENGTH_ARALINK_HEADER_FIELD, 4)+LENGTH_ARALINK_HEADER_FIELD; - hwHdrLen = pTxBlk->MpduHeaderLen-LENGTH_ARALINK_HEADER_FIELD + pTxBlk->HdrPadLen + LENGTH_ARALINK_HEADER_FIELD; - else - //hwHdrLen = ROUND_UP(pTxBlk->MpduHeaderLen, 4); - hwHdrLen = pTxBlk->MpduHeaderLen + pTxBlk->HdrPadLen; - - // Update the pTxBlk->Priv. - pTxBlk->Priv = TXINFO_SIZE + TXWI_SIZE + hwHdrLen; - - // pTxInfo->USBDMApktLen now just a temp value and will to correct latter. - RTMPWriteTxInfo(pAd, pTxInfo, (USHORT)(pTxBlk->Priv), FALSE, FIFO_EDCA, FALSE /*NextValid*/, FALSE); - - // Copy it. - NdisMoveMemory(pWirelessPacket, pTxBlk->HeaderBuf, pTxBlk->Priv); -#ifdef RT_BIG_ENDIAN - RTMPFrameEndianChange(pAd, (PUCHAR)(pWirelessPacket+ TXINFO_SIZE + TXWI_SIZE), DIR_WRITE, FALSE); -#endif // RT_BIG_ENDIAN // - pHTTXContext->CurWriteRealPos += pTxBlk->Priv; - pWirelessPacket += pTxBlk->Priv; - } - } - else - { // For sub-sequent frames of this bulk-out batch. Just copy it to our bulk-out buffer. - - Status = ((pHTTXContext->bCurWriting == TRUE) ? NDIS_STATUS_SUCCESS : NDIS_STATUS_FAILURE); - if (Status == NDIS_STATUS_SUCCESS) - { - fillOffset = (pHTTXContext->CurWritePosition + pTxBlk->Priv); - pWirelessPacket = &pHTTXContext->TransferBuffer->field.WirelessPacket[fillOffset]; - - //hwHdrLen = pTxBlk->MpduHeaderLen; - NdisMoveMemory(pWirelessPacket, pTxBlk->HeaderBuf, pTxBlk->MpduHeaderLen); - pWirelessPacket += (pTxBlk->MpduHeaderLen); - pTxBlk->Priv += pTxBlk->MpduHeaderLen; - } - else - { // It should not happened now unless we are going to shutdown. - DBGPRINT(RT_DEBUG_ERROR, ("WriteMultiTxResource():bCurWriting is FALSE when handle sub-sequent frames.\n")); - Status = NDIS_STATUS_FAILURE; - } - } - - - // We unlock it here to prevent the first 8 bytes maybe over-write issue. - // 1. First we got CurWritePosition but the first 8 bytes still not write to the pTxContext. - // 2. An interrupt break our routine and handle bulk-out complete. - // 3. In the bulk-out compllete, it need to do another bulk-out, - // if the ENextBulkOutPosition is just the same as CurWritePosition, it will save the first 8 bytes from CurWritePosition, - // but the payload still not copyed. the pTxContext->SavedPad[] will save as allzero. and set the bCopyPad = TRUE. - // 4. Interrupt complete. - // 5. Our interrupted routine go back and fill the first 8 bytes to pTxContext. - // 6. Next time when do bulk-out, it found the bCopyPad==TRUE and will copy the SavedPad[] to pTxContext->NextBulkOutPosition. - // and the packet will wrong. - RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); - - if (Status != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_ERROR,("WriteMultiTxResource: CWPos = %ld, NBOutPos = %ld.\n", pHTTXContext->CurWritePosition, pHTTXContext->NextBulkOutPosition)); - goto done; - } - - // Copy the frame content into DMA buffer and update the pTxBlk->Priv - NdisMoveMemory(pWirelessPacket, pTxBlk->pSrcBufData, pTxBlk->SrcBufLen); - pWirelessPacket += pTxBlk->SrcBufLen; - pTxBlk->Priv += pTxBlk->SrcBufLen; - -done: - // Release the skb buffer here - RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_SUCCESS); - - return(Status); - -} - - -VOID RtmpUSB_FinalWriteTxResource( - IN PRTMP_ADAPTER pAd, - IN TX_BLK *pTxBlk, - IN USHORT totalMPDUSize, - IN USHORT TxIdx) -{ - UCHAR QueIdx; - HT_TX_CONTEXT *pHTTXContext; - UINT32 fillOffset; - TXINFO_STRUC *pTxInfo; - TXWI_STRUC *pTxWI; - UINT32 USBDMApktLen, padding; - unsigned long IrqFlags; - PUCHAR pWirelessPacket; - - QueIdx = pTxBlk->QueIdx; - pHTTXContext = &pAd->TxContext[QueIdx]; - - RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); - - if (pHTTXContext->bCurWriting == TRUE) - { - fillOffset = pHTTXContext->CurWritePosition; - if (((pHTTXContext->ENextBulkOutPosition == pHTTXContext->CurWritePosition) || ((pHTTXContext->ENextBulkOutPosition-8) == pHTTXContext->CurWritePosition)) - && (pHTTXContext->bCopySavePad == TRUE)) - pWirelessPacket = (PUCHAR)(&pHTTXContext->SavedPad[0]); - else - pWirelessPacket = (PUCHAR)(&pHTTXContext->TransferBuffer->field.WirelessPacket[fillOffset]); - - // - // Update TxInfo->USBDMApktLen , - // the length = TXWI_SIZE + 802.11_hdr + 802.11_hdr_pad + payload_of_all_batch_frames + Bulk-Out-padding - // - pTxInfo = (PTXINFO_STRUC)(pWirelessPacket); - - // Calculate the bulk-out padding - USBDMApktLen = pTxBlk->Priv - TXINFO_SIZE; - padding = (4 - (USBDMApktLen % 4)) & 0x03; // round up to 4 byte alignment - USBDMApktLen += padding; - - pTxInfo->USBDMATxPktLen = USBDMApktLen; - - // - // Update TXWI->MPDUtotalByteCount , - // the length = 802.11 header + payload_of_all_batch_frames - pTxWI= (PTXWI_STRUC)(pWirelessPacket + TXINFO_SIZE); - pTxWI->MPDUtotalByteCount = totalMPDUSize; - - // - // Update the pHTTXContext->CurWritePosition - // - pHTTXContext->CurWritePosition += (TXINFO_SIZE + USBDMApktLen); - if ((pHTTXContext->CurWritePosition + 3906)> MAX_TXBULK_LIMIT) - { // Add 3906 for prevent the NextBulkOut packet size is a A-RALINK/A-MSDU Frame. - pHTTXContext->CurWritePosition = 8; - pTxInfo->SwUseLastRound = 1; - } - pHTTXContext->CurWriteRealPos = pHTTXContext->CurWritePosition; - - - // - // Zero the last padding. - // - pWirelessPacket = (&pHTTXContext->TransferBuffer->field.WirelessPacket[fillOffset + pTxBlk->Priv]); - NdisZeroMemory(pWirelessPacket, padding + 8); - - // Finally, set bCurWriting as FALSE - pHTTXContext->bCurWriting = FALSE; - - } - else - { // It should not happened now unless we are going to shutdown. - DBGPRINT(RT_DEBUG_ERROR, ("FinalWriteTxResource():bCurWriting is FALSE when handle last frames.\n")); - } - - RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); - -} - - -VOID RtmpUSBDataLastTxIdx( - IN PRTMP_ADAPTER pAd, - IN UCHAR QueIdx, - IN USHORT TxIdx) -{ - // DO nothing for USB. -} - - -/* - When can do bulk-out: - 1. TxSwFreeIdx < TX_RING_SIZE; - It means has at least one Ring entity is ready for bulk-out, kick it out. - 2. If TxSwFreeIdx == TX_RING_SIZE - Check if the CurWriting flag is FALSE, if it's FALSE, we can do kick out. - -*/ -VOID RtmpUSBDataKickOut( - IN PRTMP_ADAPTER pAd, - IN TX_BLK *pTxBlk, - IN UCHAR QueIdx) -{ - RTUSB_SET_BULK_FLAG(pAd, (fRTUSB_BULK_OUT_DATA_NORMAL << QueIdx)); - RTUSBKickBulkOut(pAd); - -} - - -/* - Must be run in Interrupt context - This function handle RT2870 specific TxDesc and cpu index update and kick the packet out. - */ -int RtmpUSBMgmtKickOut( - IN RTMP_ADAPTER *pAd, - IN UCHAR QueIdx, - IN PNDIS_PACKET pPacket, - IN PUCHAR pSrcBufVA, - IN UINT SrcBufLen) -{ - PTXINFO_STRUC pTxInfo; - ULONG BulkOutSize; - UCHAR padLen; - PUCHAR pDest; - ULONG SwIdx = pAd->MgmtRing.TxCpuIdx; - PTX_CONTEXT pMLMEContext = (PTX_CONTEXT)pAd->MgmtRing.Cell[SwIdx].AllocVa; - unsigned long IrqFlags; - - - pTxInfo = (PTXINFO_STRUC)(pSrcBufVA); - - // Build our URB for USBD - BulkOutSize = SrcBufLen; - BulkOutSize = (BulkOutSize + 3) & (~3); - RTMPWriteTxInfo(pAd, pTxInfo, (USHORT)(BulkOutSize - TXINFO_SIZE), TRUE, EpToQueue[MGMTPIPEIDX], FALSE, FALSE); - - BulkOutSize += 4; // Always add 4 extra bytes at every packet. - - // If BulkOutSize is multiple of BulkOutMaxPacketSize, add extra 4 bytes again. - if ((BulkOutSize % pAd->BulkOutMaxPacketSize) == 0) - BulkOutSize += 4; - - padLen = BulkOutSize - SrcBufLen; - ASSERT((padLen <= RTMP_PKT_TAIL_PADDING)); - - // Now memzero all extra padding bytes. - pDest = (PUCHAR)(pSrcBufVA + SrcBufLen); - skb_put(GET_OS_PKT_TYPE(pPacket), padLen); - NdisZeroMemory(pDest, padLen); - - RTMP_IRQ_LOCK(&pAd->MLMEBulkOutLock, IrqFlags); - - pAd->MgmtRing.Cell[pAd->MgmtRing.TxCpuIdx].pNdisPacket = pPacket; - pMLMEContext->TransferBuffer = (PTX_BUFFER)(GET_OS_PKT_DATAPTR(pPacket)); - - // Length in TxInfo should be 8 less than bulkout size. - pMLMEContext->BulkOutSize = BulkOutSize; - pMLMEContext->InUse = TRUE; - pMLMEContext->bWaitingBulkOut = TRUE; - - - //for debug - //hex_dump("RtmpUSBMgmtKickOut", &pMLMEContext->TransferBuffer->field.WirelessPacket[0], (pMLMEContext->BulkOutSize > 16 ? 16 : pMLMEContext->BulkOutSize)); - - //pAd->RalinkCounters.KickTxCount++; - //pAd->RalinkCounters.OneSecTxDoneCount++; - - //if (pAd->MgmtRing.TxSwFreeIdx == MGMT_RING_SIZE) - // needKickOut = TRUE; - - // Decrease the TxSwFreeIdx and Increase the TX_CTX_IDX - pAd->MgmtRing.TxSwFreeIdx--; - INC_RING_INDEX(pAd->MgmtRing.TxCpuIdx, MGMT_RING_SIZE); - - RTMP_IRQ_UNLOCK(&pAd->MLMEBulkOutLock, IrqFlags); - - RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_MLME); - //if (needKickOut) - RTUSBKickBulkOut(pAd); - - return 0; -} - - -VOID RtmpUSBNullFrameKickOut( - IN RTMP_ADAPTER *pAd, - IN UCHAR QueIdx, - IN UCHAR *pNullFrame, - IN UINT32 frameLen) -{ - if (pAd->NullContext.InUse == FALSE) - { - PTX_CONTEXT pNullContext; - PTXINFO_STRUC pTxInfo; - PTXWI_STRUC pTxWI; - PUCHAR pWirelessPkt; - - pNullContext = &(pAd->NullContext); - - // Set the in use bit - pNullContext->InUse = TRUE; - pWirelessPkt = (PUCHAR)&pNullContext->TransferBuffer->field.WirelessPacket[0]; - - RTMPZeroMemory(&pWirelessPkt[0], 100); - pTxInfo = (PTXINFO_STRUC)&pWirelessPkt[0]; - RTMPWriteTxInfo(pAd, pTxInfo, (USHORT)(sizeof(HEADER_802_11)+TXWI_SIZE), TRUE, EpToQueue[MGMTPIPEIDX], FALSE, FALSE); - pTxInfo->QSEL = FIFO_EDCA; - pTxWI = (PTXWI_STRUC)&pWirelessPkt[TXINFO_SIZE]; - RTMPWriteTxWI(pAd, pTxWI, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, 0, BSSID_WCID, (sizeof(HEADER_802_11)), - 0, 0, (UCHAR)pAd->CommonCfg.MlmeTransmit.field.MCS, IFS_HTTXOP, FALSE, &pAd->CommonCfg.MlmeTransmit); -#ifdef RT_BIG_ENDIAN - RTMPWIEndianChange((PUCHAR)pTxWI, TYPE_TXWI); -#endif // RT_BIG_ENDIAN // - - RTMPMoveMemory(&pWirelessPkt[TXWI_SIZE+TXINFO_SIZE], &pAd->NullFrame, sizeof(HEADER_802_11)); -#ifdef RT_BIG_ENDIAN - RTMPFrameEndianChange(pAd, (PUCHAR)&pWirelessPkt[TXINFO_SIZE + TXWI_SIZE], DIR_WRITE, FALSE); -#endif // RT_BIG_ENDIAN // - pAd->NullContext.BulkOutSize = TXINFO_SIZE + TXWI_SIZE + sizeof(pAd->NullFrame) + 4; - - // Fill out frame length information for global Bulk out arbitor - //pNullContext->BulkOutSize = TransferBufferLength; - DBGPRINT(RT_DEBUG_TRACE, ("SYNC - send NULL Frame @%d Mbps...\n", RateIdToMbps[pAd->CommonCfg.TxRate])); - RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NULL); - - // Kick bulk out - RTUSBKickBulkOut(pAd); - } - -} - -#ifdef CONFIG_STA_SUPPORT -/* - ======================================================================== - - Routine Description: - Check Rx descriptor, return NDIS_STATUS_FAILURE if any error dound - - Arguments: - pRxD Pointer to the Rx descriptor - - Return Value: - NDIS_STATUS_SUCCESS No err - NDIS_STATUS_FAILURE Error - - Note: - - ======================================================================== -*/ -NDIS_STATUS RTMPCheckRxError( - IN PRTMP_ADAPTER pAd, - IN PHEADER_802_11 pHeader, - IN PRXWI_STRUC pRxWI, - IN PRT28XX_RXD_STRUC pRxINFO) -{ - PCIPHER_KEY pWpaKey; - INT dBm; - - if (pAd->bPromiscuous == TRUE) - return(NDIS_STATUS_SUCCESS); - if(pRxINFO == NULL) - return(NDIS_STATUS_FAILURE); - - // Phy errors & CRC errors - if (pRxINFO->Crc) - { - // Check RSSI for Noise Hist statistic collection. - dBm = (INT) (pRxWI->RSSI0) - pAd->BbpRssiToDbmDelta; - if (dBm <= -87) - pAd->StaCfg.RPIDensity[0] += 1; - else if (dBm <= -82) - pAd->StaCfg.RPIDensity[1] += 1; - else if (dBm <= -77) - pAd->StaCfg.RPIDensity[2] += 1; - else if (dBm <= -72) - pAd->StaCfg.RPIDensity[3] += 1; - else if (dBm <= -67) - pAd->StaCfg.RPIDensity[4] += 1; - else if (dBm <= -62) - pAd->StaCfg.RPIDensity[5] += 1; - else if (dBm <= -57) - pAd->StaCfg.RPIDensity[6] += 1; - else if (dBm > -57) - pAd->StaCfg.RPIDensity[7] += 1; - - return(NDIS_STATUS_FAILURE); - } - - // Add Rx size to channel load counter, we should ignore error counts - pAd->StaCfg.CLBusyBytes += (pRxWI->MPDUtotalByteCount+ 14); - - // Drop ToDs promiscous frame, it is opened due to CCX 2 channel load statistics - if (pHeader->FC.ToDs) - { - DBGPRINT_RAW(RT_DEBUG_ERROR, ("Err;FC.ToDs\n")); - return NDIS_STATUS_FAILURE; - } - - // Paul 04-03 for OFDM Rx length issue - if (pRxWI->MPDUtotalByteCount > MAX_AGGREGATION_SIZE) - { - DBGPRINT_RAW(RT_DEBUG_ERROR, ("received packet too long\n")); - return NDIS_STATUS_FAILURE; - } - - // Drop not U2M frames, cant's drop here because we will drop beacon in this case - // I am kind of doubting the U2M bit operation - // if (pRxD->U2M == 0) - // return(NDIS_STATUS_FAILURE); - - // drop decyption fail frame - if (pRxINFO->Decrypted && pRxINFO->CipherErr) - { - - // - // MIC Error - // - if ((pRxINFO->CipherErr == 2) && pRxINFO->MyBss) - { - pWpaKey = &pAd->SharedKey[BSS0][pRxWI->KeyIndex]; - RTMPReportMicError(pAd, pWpaKey); - DBGPRINT_RAW(RT_DEBUG_ERROR,("Rx MIC Value error\n")); - } - - if (pRxINFO->Decrypted && - (pAd->SharedKey[BSS0][pRxWI->KeyIndex].CipherAlg == CIPHER_AES) && - (pHeader->Sequence == pAd->FragFrame.Sequence)) - { - // - // Acceptable since the First FragFrame no CipherErr problem. - // - return(NDIS_STATUS_SUCCESS); - } - - return(NDIS_STATUS_FAILURE); - } - - return(NDIS_STATUS_SUCCESS); -} - -VOID RT28xxUsbStaAsicForceWakeup( - IN PRTMP_ADAPTER pAd, - IN BOOLEAN bFromTx) -{ - AUTO_WAKEUP_STRUC AutoWakeupCfg; - - AutoWakeupCfg.word = 0; - RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word); - - AsicSendCommandToMcu(pAd, 0x31, 0xff, 0x00, 0x02); - - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE); -} - -VOID RT28xxUsbStaAsicSleepThenAutoWakeup( - IN PRTMP_ADAPTER pAd, - IN USHORT TbttNumToNextWakeUp) -{ - AUTO_WAKEUP_STRUC AutoWakeupCfg; - - // we have decided to SLEEP, so at least do it for a BEACON period. - if (TbttNumToNextWakeUp == 0) - TbttNumToNextWakeUp = 1; - - AutoWakeupCfg.word = 0; - RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word); - - AutoWakeupCfg.field.NumofSleepingTbtt = TbttNumToNextWakeUp - 1; - AutoWakeupCfg.field.EnableAutoWakeup = 1; - AutoWakeupCfg.field.AutoLeadTime = 5; - RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word); - - AsicSendCommandToMcu(pAd, 0x30, 0xff, 0xff, 0x02); // send POWER-SAVE command to MCU. Timeout 40us. - - OPSTATUS_SET_FLAG(pAd, fOP_STATUS_DOZE); - -} -#endif // CONFIG_STA_SUPPORT // - -VOID RT28xxUsbMlmeRadioOn( - IN PRTMP_ADAPTER pAd) -{ - DBGPRINT(RT_DEBUG_TRACE,("RT28xxUsbMlmeRadioOn()\n")); - - if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF)) - return; - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - AsicSendCommandToMcu(pAd, 0x31, 0xff, 0x00, 0x02); - RTMPusecDelay(10000); - } -#endif // CONFIG_STA_SUPPORT // - NICResetFromError(pAd); - - // Enable Tx/Rx - RTMPEnableRxTx(pAd); - -#ifdef RT3070 - if (IS_RT3071(pAd)) - { - RT30xxReverseRFSleepModeSetup(pAd); - } -#endif // RT3070 // - - // Clear Radio off flag - RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF); - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - RTUSBBulkReceive(pAd); -#endif // CONFIG_STA_SUPPORT // - - // Set LED - RTMPSetLED(pAd, LED_RADIO_ON); -} - -VOID RT28xxUsbMlmeRadioOFF( - IN PRTMP_ADAPTER pAd) -{ - WPDMA_GLO_CFG_STRUC GloCfg; - UINT32 Value, i; - - DBGPRINT(RT_DEBUG_TRACE,("RT28xxUsbMlmeRadioOFF()\n")); - - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF)) - return; - - // Set LED - RTMPSetLED(pAd, LED_RADIO_OFF); - // Set Radio off flag - RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF); - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - // Link down first if any association exists - if (INFRA_ON(pAd) || ADHOC_ON(pAd)) - LinkDown(pAd, FALSE); - RTMPusecDelay(10000); - - //========================================== - // Clean up old bss table - BssTableInit(&pAd->ScanTab); - } -#endif // CONFIG_STA_SUPPORT // - - - if (pAd->CommonCfg.BBPCurrentBW == BW_40) - { - // Must using 40MHz. - AsicTurnOffRFClk(pAd, pAd->CommonCfg.CentralChannel); - } - else - { - // Must using 20MHz. - AsicTurnOffRFClk(pAd, pAd->CommonCfg.Channel); - } - - // Disable Tx/Rx DMA - RTUSBReadMACRegister(pAd, WPDMA_GLO_CFG, &GloCfg.word); // disable DMA - GloCfg.field.EnableTxDMA = 0; - GloCfg.field.EnableRxDMA = 0; - RTUSBWriteMACRegister(pAd, WPDMA_GLO_CFG, GloCfg.word); // abort all TX rings - - // Waiting for DMA idle - i = 0; - do - { - RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word); - if ((GloCfg.field.TxDMABusy == 0) && (GloCfg.field.RxDMABusy == 0)) - break; - - RTMPusecDelay(1000); - }while (i++ < 100); - - // Disable MAC Tx/Rx - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value &= (0xfffffff3); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - - // MAC_SYS_CTRL => value = 0x0 => 40mA - //RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0); - - // PWR_PIN_CFG => value = 0x0 => 40mA - //RTMP_IO_WRITE32(pAd, PWR_PIN_CFG, 0); - - // TX_PIN_CFG => value = 0x0 => 20mA - //RTMP_IO_WRITE32(pAd, TX_PIN_CFG, 0); - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - AsicSendCommandToMcu(pAd, 0x30, 0xff, 0xff, 0x02); -#endif // CONFIG_STA_SUPPORT // -} - +#include "../../rt2870/common/cmm_data_2870.c" diff --git a/drivers/staging/rt3070/common/cmm_info.c b/drivers/staging/rt3070/common/cmm_info.c index 54cb1a35f7bf..6e981e523fb5 100644 --- a/drivers/staging/rt3070/common/cmm_info.c +++ b/drivers/staging/rt3070/common/cmm_info.c @@ -1,3395 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * 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 "../rt_config.h" - -INT Show_SSID_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -INT Show_WirelessMode_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -INT Show_TxBurst_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -INT Show_TxPreamble_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -INT Show_TxPower_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -INT Show_Channel_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -INT Show_BGProtection_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -INT Show_RTSThreshold_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -INT Show_FragThreshold_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -#ifdef DOT11_N_SUPPORT -INT Show_HtBw_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -INT Show_HtMcs_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -INT Show_HtGi_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -INT Show_HtOpMode_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -INT Show_HtExtcha_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -INT Show_HtMpduDensity_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -INT Show_HtBaWinSize_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -INT Show_HtRdg_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -INT Show_HtAmsdu_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -INT Show_HtAutoBa_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); -#endif // DOT11_N_SUPPORT // - -INT Show_CountryRegion_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -INT Show_CountryRegionABand_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -INT Show_CountryCode_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -#ifdef AGGREGATION_SUPPORT -INT Show_PktAggregate_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); -#endif // AGGREGATION_SUPPORT // - -#ifdef WMM_SUPPORT -INT Show_WmmCapable_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); -#endif // WMM_SUPPORT // - -INT Show_IEEE80211H_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -#ifdef CONFIG_STA_SUPPORT -INT Show_NetworkType_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); -#endif // CONFIG_STA_SUPPORT // - -INT Show_AuthMode_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -INT Show_EncrypType_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -INT Show_DefaultKeyID_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -INT Show_Key1_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -INT Show_Key2_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -INT Show_Key3_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -INT Show_Key4_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -INT Show_WPAPSK_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf); - -static struct { - CHAR *name; - INT (*show_proc)(PRTMP_ADAPTER pAdapter, PUCHAR arg); -} *PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC, RTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC[] = { - {"SSID", Show_SSID_Proc}, - {"WirelessMode", Show_WirelessMode_Proc}, - {"TxBurst", Show_TxBurst_Proc}, - {"TxPreamble", Show_TxPreamble_Proc}, - {"TxPower", Show_TxPower_Proc}, - {"Channel", Show_Channel_Proc}, - {"BGProtection", Show_BGProtection_Proc}, - {"RTSThreshold", Show_RTSThreshold_Proc}, - {"FragThreshold", Show_FragThreshold_Proc}, -#ifdef DOT11_N_SUPPORT - {"HtBw", Show_HtBw_Proc}, - {"HtMcs", Show_HtMcs_Proc}, - {"HtGi", Show_HtGi_Proc}, - {"HtOpMode", Show_HtOpMode_Proc}, - {"HtExtcha", Show_HtExtcha_Proc}, - {"HtMpduDensity", Show_HtMpduDensity_Proc}, - {"HtBaWinSize", Show_HtBaWinSize_Proc}, - {"HtRdg", Show_HtRdg_Proc}, - {"HtAmsdu", Show_HtAmsdu_Proc}, - {"HtAutoBa", Show_HtAutoBa_Proc}, -#endif // DOT11_N_SUPPORT // - {"CountryRegion", Show_CountryRegion_Proc}, - {"CountryRegionABand", Show_CountryRegionABand_Proc}, - {"CountryCode", Show_CountryCode_Proc}, -#ifdef AGGREGATION_SUPPORT - {"PktAggregate", Show_PktAggregate_Proc}, -#endif - -#ifdef WMM_SUPPORT - {"WmmCapable", Show_WmmCapable_Proc}, -#endif - {"IEEE80211H", Show_IEEE80211H_Proc}, -#ifdef CONFIG_STA_SUPPORT - {"NetworkType", Show_NetworkType_Proc}, -#endif // CONFIG_STA_SUPPORT // - {"AuthMode", Show_AuthMode_Proc}, - {"EncrypType", Show_EncrypType_Proc}, - {"DefaultKeyID", Show_DefaultKeyID_Proc}, - {"Key1", Show_Key1_Proc}, - {"Key2", Show_Key2_Proc}, - {"Key3", Show_Key3_Proc}, - {"Key4", Show_Key4_Proc}, - {"WPAPSK", Show_WPAPSK_Proc}, - {NULL, NULL} -}; - -/* - ========================================================================== - Description: - Get Driver version. - - Return: - ========================================================================== -*/ -INT Set_DriverVersion_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - DBGPRINT(RT_DEBUG_TRACE, ("Driver version-%s\n", STA_DRIVER_VERSION)); -#endif // CONFIG_STA_SUPPORT // - - return TRUE; -} - -/* - ========================================================================== - Description: - Set Country Region. - This command will not work, if the field of CountryRegion in eeprom is programmed. - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_CountryRegion_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ULONG region; - - region = simple_strtol(arg, 0, 10); - -#ifdef EXT_BUILD_CHANNEL_LIST - return -EOPNOTSUPP; -#endif // EXT_BUILD_CHANNEL_LIST // - - // Country can be set only when EEPROM not programmed - if (pAd->CommonCfg.CountryRegion & 0x80) - { - DBGPRINT(RT_DEBUG_ERROR, ("Set_CountryRegion_Proc::parameter of CountryRegion in eeprom is programmed \n")); - return FALSE; - } - - if((region >= 0) && (region <= REGION_MAXIMUM_BG_BAND)) - { - pAd->CommonCfg.CountryRegion = (UCHAR) region; - } - else if (region == REGION_31_BG_BAND) - { - pAd->CommonCfg.CountryRegion = (UCHAR) region; - } - else - { - DBGPRINT(RT_DEBUG_ERROR, ("Set_CountryRegion_Proc::parameters out of range\n")); - return FALSE; - } - - // if set country region, driver needs to be reset - BuildChannelList(pAd); - - DBGPRINT(RT_DEBUG_TRACE, ("Set_CountryRegion_Proc::(CountryRegion=%d)\n", pAd->CommonCfg.CountryRegion)); - - return TRUE; -} - -/* - ========================================================================== - Description: - Set Country Region for A band. - This command will not work, if the field of CountryRegion in eeprom is programmed. - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_CountryRegionABand_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ULONG region; - - region = simple_strtol(arg, 0, 10); - -#ifdef EXT_BUILD_CHANNEL_LIST - return -EOPNOTSUPP; -#endif // EXT_BUILD_CHANNEL_LIST // - - // Country can be set only when EEPROM not programmed - if (pAd->CommonCfg.CountryRegionForABand & 0x80) - { - DBGPRINT(RT_DEBUG_ERROR, ("Set_CountryRegionABand_Proc::parameter of CountryRegion in eeprom is programmed \n")); - return FALSE; - } - - if((region >= 0) && (region <= REGION_MAXIMUM_A_BAND)) - { - pAd->CommonCfg.CountryRegionForABand = (UCHAR) region; - } - else - { - DBGPRINT(RT_DEBUG_ERROR, ("Set_CountryRegionABand_Proc::parameters out of range\n")); - return FALSE; - } - - // if set country region, driver needs to be reset - BuildChannelList(pAd); - - DBGPRINT(RT_DEBUG_TRACE, ("Set_CountryRegionABand_Proc::(CountryRegion=%d)\n", pAd->CommonCfg.CountryRegionForABand)); - - return TRUE; -} - -/* - ========================================================================== - Description: - Set Wireless Mode - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_WirelessMode_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ULONG WirelessMode; - INT success = TRUE; - - WirelessMode = simple_strtol(arg, 0, 10); - - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - INT MaxPhyMode = PHY_11G; - -#ifdef DOT11_N_SUPPORT - MaxPhyMode = PHY_11N_5G; -#endif // DOT11_N_SUPPORT // - - if (WirelessMode <= MaxPhyMode) - { - RTMPSetPhyMode(pAd, WirelessMode); -#ifdef DOT11_N_SUPPORT - if (WirelessMode >= PHY_11ABGN_MIXED) - { - pAd->CommonCfg.BACapability.field.AutoBA = TRUE; - pAd->CommonCfg.REGBACapability.field.AutoBA = TRUE; - } - else - { - pAd->CommonCfg.BACapability.field.AutoBA = FALSE; - pAd->CommonCfg.REGBACapability.field.AutoBA = FALSE; - } -#endif // DOT11_N_SUPPORT // - // Set AdhocMode rates - if (pAd->StaCfg.BssType == BSS_ADHOC) - { - MlmeUpdateTxRates(pAd, FALSE, 0); - MakeIbssBeacon(pAd); // re-build BEACON frame - AsicEnableIbssSync(pAd); // copy to on-chip memory - } - } - else - { - success = FALSE; - } - } -#endif // CONFIG_STA_SUPPORT // - - // it is needed to set SSID to take effect - if (success == TRUE) - { -#ifdef DOT11_N_SUPPORT - SetCommonHT(pAd); -#endif // DOT11_N_SUPPORT // - DBGPRINT(RT_DEBUG_TRACE, ("Set_WirelessMode_Proc::(=%ld)\n", WirelessMode)); - } - else - { - DBGPRINT(RT_DEBUG_ERROR, ("Set_WirelessMode_Proc::parameters out of range\n")); - } - - return success; -} - -/* - ========================================================================== - Description: - Set Channel - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_Channel_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - INT success = TRUE; - UCHAR Channel; - - Channel = (UCHAR) simple_strtol(arg, 0, 10); - - // check if this channel is valid - if (ChannelSanity(pAd, Channel) == TRUE) - { -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - pAd->CommonCfg.Channel = Channel; - - if (MONITOR_ON(pAd)) - { -#ifdef DOT11_N_SUPPORT - N_ChannelCheck(pAd); - if (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED && - pAd->CommonCfg.RegTransmitSetting.field.BW == BW_40) - { - N_SetCenCh(pAd); - AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE); - AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel); - DBGPRINT(RT_DEBUG_TRACE, ("BW_40, control_channel(%d), CentralChannel(%d) \n", - pAd->CommonCfg.Channel, pAd->CommonCfg.CentralChannel)); - } - else -#endif // DOT11_N_SUPPORT // - { - AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); - AsicLockChannel(pAd, pAd->CommonCfg.Channel); - DBGPRINT(RT_DEBUG_TRACE, ("BW_20, Channel(%d)\n", pAd->CommonCfg.Channel)); - } - } - } -#endif // CONFIG_STA_SUPPORT // - success = TRUE; - } - else - { - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - success = FALSE; -#endif // CONFIG_STA_SUPPORT // - } - - - if (success == TRUE) - DBGPRINT(RT_DEBUG_TRACE, ("Set_Channel_Proc::(Channel=%d)\n", pAd->CommonCfg.Channel)); - - return success; -} - -/* - ========================================================================== - Description: - Set Short Slot Time Enable or Disable - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_ShortSlot_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ULONG ShortSlot; - - ShortSlot = simple_strtol(arg, 0, 10); - - if (ShortSlot == 1) - pAd->CommonCfg.bUseShortSlotTime = TRUE; - else if (ShortSlot == 0) - pAd->CommonCfg.bUseShortSlotTime = FALSE; - else - return FALSE; //Invalid argument - - DBGPRINT(RT_DEBUG_TRACE, ("Set_ShortSlot_Proc::(ShortSlot=%d)\n", pAd->CommonCfg.bUseShortSlotTime)); - - return TRUE; -} - -/* - ========================================================================== - Description: - Set Tx power - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_TxPower_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ULONG TxPower; - INT success = FALSE; - - TxPower = (ULONG) simple_strtol(arg, 0, 10); - if (TxPower <= 100) - { - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - pAd->CommonCfg.TxPowerDefault = TxPower; - pAd->CommonCfg.TxPowerPercentage = pAd->CommonCfg.TxPowerDefault; - } -#endif // CONFIG_STA_SUPPORT // - success = TRUE; - } - else - success = FALSE; - - DBGPRINT(RT_DEBUG_TRACE, ("Set_TxPower_Proc::(TxPowerPercentage=%ld)\n", pAd->CommonCfg.TxPowerPercentage)); - - return success; -} - -/* - ========================================================================== - Description: - Set 11B/11G Protection - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_BGProtection_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - switch (simple_strtol(arg, 0, 10)) - { - case 0: //AUTO - pAd->CommonCfg.UseBGProtection = 0; - break; - case 1: //Always On - pAd->CommonCfg.UseBGProtection = 1; - break; - case 2: //Always OFF - pAd->CommonCfg.UseBGProtection = 2; - break; - default: //Invalid argument - return FALSE; - } - - - DBGPRINT(RT_DEBUG_TRACE, ("Set_BGProtection_Proc::(BGProtection=%ld)\n", pAd->CommonCfg.UseBGProtection)); - - return TRUE; -} - -/* - ========================================================================== - Description: - Set TxPreamble - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_TxPreamble_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - RT_802_11_PREAMBLE Preamble; - - Preamble = simple_strtol(arg, 0, 10); - - - switch (Preamble) - { - case Rt802_11PreambleShort: - pAd->CommonCfg.TxPreamble = Preamble; -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - MlmeSetTxPreamble(pAd, Rt802_11PreambleShort); -#endif // CONFIG_STA_SUPPORT // - break; - case Rt802_11PreambleLong: -#ifdef CONFIG_STA_SUPPORT - case Rt802_11PreambleAuto: - // if user wants AUTO, initialize to LONG here, then change according to AP's - // capability upon association. -#endif // CONFIG_STA_SUPPORT // - pAd->CommonCfg.TxPreamble = Preamble; -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - MlmeSetTxPreamble(pAd, Rt802_11PreambleLong); -#endif // CONFIG_STA_SUPPORT // - break; - default: //Invalid argument - return FALSE; - } - - DBGPRINT(RT_DEBUG_TRACE, ("Set_TxPreamble_Proc::(TxPreamble=%ld)\n", pAd->CommonCfg.TxPreamble)); - - return TRUE; -} - -/* - ========================================================================== - Description: - Set RTS Threshold - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_RTSThreshold_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - NDIS_802_11_RTS_THRESHOLD RtsThresh; - - RtsThresh = simple_strtol(arg, 0, 10); - - if((RtsThresh > 0) && (RtsThresh <= MAX_RTS_THRESHOLD)) - pAd->CommonCfg.RtsThreshold = (USHORT)RtsThresh; -#ifdef CONFIG_STA_SUPPORT - else if (RtsThresh == 0) - pAd->CommonCfg.RtsThreshold = MAX_RTS_THRESHOLD; -#endif // CONFIG_STA_SUPPORT // - else - return FALSE; //Invalid argument - - DBGPRINT(RT_DEBUG_TRACE, ("Set_RTSThreshold_Proc::(RTSThreshold=%d)\n", pAd->CommonCfg.RtsThreshold)); - - return TRUE; -} - -/* - ========================================================================== - Description: - Set Fragment Threshold - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_FragThreshold_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - NDIS_802_11_FRAGMENTATION_THRESHOLD FragThresh; - - FragThresh = simple_strtol(arg, 0, 10); - - if (FragThresh > MAX_FRAG_THRESHOLD || FragThresh < MIN_FRAG_THRESHOLD) - { - //Illegal FragThresh so we set it to default - pAd->CommonCfg.FragmentThreshold = MAX_FRAG_THRESHOLD; - } - else if (FragThresh % 2 == 1) - { - // The length of each fragment shall always be an even number of octets, except for the last fragment - // of an MSDU or MMPDU, which may be either an even or an odd number of octets. - pAd->CommonCfg.FragmentThreshold = (USHORT)(FragThresh - 1); - } - else - { - pAd->CommonCfg.FragmentThreshold = (USHORT)FragThresh; - } - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - if (pAd->CommonCfg.FragmentThreshold == MAX_FRAG_THRESHOLD) - pAd->CommonCfg.bUseZeroToDisableFragment = TRUE; - else - pAd->CommonCfg.bUseZeroToDisableFragment = FALSE; - } -#endif // CONFIG_STA_SUPPORT // - - DBGPRINT(RT_DEBUG_TRACE, ("Set_FragThreshold_Proc::(FragThreshold=%d)\n", pAd->CommonCfg.FragmentThreshold)); - - return TRUE; -} - -/* - ========================================================================== - Description: - Set TxBurst - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_TxBurst_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ULONG TxBurst; - - TxBurst = simple_strtol(arg, 0, 10); - if (TxBurst == 1) - pAd->CommonCfg.bEnableTxBurst = TRUE; - else if (TxBurst == 0) - pAd->CommonCfg.bEnableTxBurst = FALSE; - else - return FALSE; //Invalid argument - - DBGPRINT(RT_DEBUG_TRACE, ("Set_TxBurst_Proc::(TxBurst=%d)\n", pAd->CommonCfg.bEnableTxBurst)); - - return TRUE; -} - -#ifdef AGGREGATION_SUPPORT -/* - ========================================================================== - Description: - Set TxBurst - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_PktAggregate_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ULONG aggre; - - aggre = simple_strtol(arg, 0, 10); - - if (aggre == 1) - pAd->CommonCfg.bAggregationCapable = TRUE; - else if (aggre == 0) - pAd->CommonCfg.bAggregationCapable = FALSE; - else - return FALSE; //Invalid argument - - - DBGPRINT(RT_DEBUG_TRACE, ("Set_PktAggregate_Proc::(AGGRE=%d)\n", pAd->CommonCfg.bAggregationCapable)); - - return TRUE; -} -#endif - -/* - ========================================================================== - Description: - Set IEEE80211H. - This parameter is 1 when needs radar detection, otherwise 0 - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_IEEE80211H_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ULONG ieee80211h; - - ieee80211h = simple_strtol(arg, 0, 10); - - if (ieee80211h == 1) - pAd->CommonCfg.bIEEE80211H = TRUE; - else if (ieee80211h == 0) - pAd->CommonCfg.bIEEE80211H = FALSE; - else - return FALSE; //Invalid argument - - DBGPRINT(RT_DEBUG_TRACE, ("Set_IEEE80211H_Proc::(IEEE80211H=%d)\n", pAd->CommonCfg.bIEEE80211H)); - - return TRUE; -} - - -#ifdef DBG -/* - ========================================================================== - Description: - For Debug information - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_Debug_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - DBGPRINT(RT_DEBUG_TRACE, ("==> Set_Debug_Proc *******************\n")); - - if(simple_strtol(arg, 0, 10) <= RT_DEBUG_LOUD) - RTDebugLevel = simple_strtol(arg, 0, 10); - - DBGPRINT(RT_DEBUG_TRACE, ("<== Set_Debug_Proc(RTDebugLevel = %ld)\n", RTDebugLevel)); - - return TRUE; -} -#endif - -INT Show_DescInfo_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - - return TRUE; -} - -/* - ========================================================================== - Description: - Reset statistics counter - - Arguments: - pAdapter Pointer to our adapter - arg - - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_ResetStatCounter_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - //UCHAR i; - //MAC_TABLE_ENTRY *pEntry; - - DBGPRINT(RT_DEBUG_TRACE, ("==>Set_ResetStatCounter_Proc\n")); - - // add the most up-to-date h/w raw counters into software counters - NICUpdateRawCounters(pAd); - - NdisZeroMemory(&pAd->WlanCounters, sizeof(COUNTER_802_11)); - NdisZeroMemory(&pAd->Counters8023, sizeof(COUNTER_802_3)); - NdisZeroMemory(&pAd->RalinkCounters, sizeof(COUNTER_RALINK)); - - return TRUE; -} - -BOOLEAN RTMPCheckStrPrintAble( - IN CHAR *pInPutStr, - IN UCHAR strLen) -{ - UCHAR i=0; - - for (i=0; i 0x7E)) - return FALSE; - } - - return TRUE; -} - -/* - ======================================================================== - - Routine Description: - Remove WPA Key process - - Arguments: - pAd Pointer to our adapter - pBuf Pointer to the where the key stored - - Return Value: - NDIS_SUCCESS Add key successfully - - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -#ifdef CONFIG_STA_SUPPORT -VOID RTMPSetDesiredRates( - IN PRTMP_ADAPTER pAdapter, - IN LONG Rates) -{ - NDIS_802_11_RATES aryRates; - - memset(&aryRates, 0x00, sizeof(NDIS_802_11_RATES)); - switch (pAdapter->CommonCfg.PhyMode) - { - case PHY_11A: // A only - switch (Rates) - { - case 6000000: //6M - aryRates[0] = 0x0c; // 6M - pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_0; - break; - case 9000000: //9M - aryRates[0] = 0x12; // 9M - pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_1; - break; - case 12000000: //12M - aryRates[0] = 0x18; // 12M - pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_2; - break; - case 18000000: //18M - aryRates[0] = 0x24; // 18M - pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_3; - break; - case 24000000: //24M - aryRates[0] = 0x30; // 24M - pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_4; - break; - case 36000000: //36M - aryRates[0] = 0x48; // 36M - pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_5; - break; - case 48000000: //48M - aryRates[0] = 0x60; // 48M - pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_6; - break; - case 54000000: //54M - aryRates[0] = 0x6c; // 54M - pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_7; - break; - case -1: //Auto - default: - aryRates[0] = 0x6c; // 54Mbps - aryRates[1] = 0x60; // 48Mbps - aryRates[2] = 0x48; // 36Mbps - aryRates[3] = 0x30; // 24Mbps - aryRates[4] = 0x24; // 18M - aryRates[5] = 0x18; // 12M - aryRates[6] = 0x12; // 9M - aryRates[7] = 0x0c; // 6M - pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_AUTO; - break; - } - break; - case PHY_11BG_MIXED: // B/G Mixed - case PHY_11B: // B only - case PHY_11ABG_MIXED: // A/B/G Mixed - default: - switch (Rates) - { - case 1000000: //1M - aryRates[0] = 0x02; - pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_0; - break; - case 2000000: //2M - aryRates[0] = 0x04; - pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_1; - break; - case 5000000: //5.5M - aryRates[0] = 0x0b; // 5.5M - pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_2; - break; - case 11000000: //11M - aryRates[0] = 0x16; // 11M - pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_3; - break; - case 6000000: //6M - aryRates[0] = 0x0c; // 6M - pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_0; - break; - case 9000000: //9M - aryRates[0] = 0x12; // 9M - pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_1; - break; - case 12000000: //12M - aryRates[0] = 0x18; // 12M - pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_2; - break; - case 18000000: //18M - aryRates[0] = 0x24; // 18M - pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_3; - break; - case 24000000: //24M - aryRates[0] = 0x30; // 24M - pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_4; - break; - case 36000000: //36M - aryRates[0] = 0x48; // 36M - pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_5; - break; - case 48000000: //48M - aryRates[0] = 0x60; // 48M - pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_6; - break; - case 54000000: //54M - aryRates[0] = 0x6c; // 54M - pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_7; - break; - case -1: //Auto - default: - if (pAdapter->CommonCfg.PhyMode == PHY_11B) - { //B Only - aryRates[0] = 0x16; // 11Mbps - aryRates[1] = 0x0b; // 5.5Mbps - aryRates[2] = 0x04; // 2Mbps - aryRates[3] = 0x02; // 1Mbps - } - else - { //(B/G) Mixed or (A/B/G) Mixed - aryRates[0] = 0x6c; // 54Mbps - aryRates[1] = 0x60; // 48Mbps - aryRates[2] = 0x48; // 36Mbps - aryRates[3] = 0x30; // 24Mbps - aryRates[4] = 0x16; // 11Mbps - aryRates[5] = 0x0b; // 5.5Mbps - aryRates[6] = 0x04; // 2Mbps - aryRates[7] = 0x02; // 1Mbps - } - pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_AUTO; - break; - } - break; - } - - NdisZeroMemory(pAdapter->CommonCfg.DesireRate, MAX_LEN_OF_SUPPORTED_RATES); - NdisMoveMemory(pAdapter->CommonCfg.DesireRate, &aryRates, sizeof(NDIS_802_11_RATES)); - DBGPRINT(RT_DEBUG_TRACE, (" RTMPSetDesiredRates (%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x)\n", - pAdapter->CommonCfg.DesireRate[0],pAdapter->CommonCfg.DesireRate[1], - pAdapter->CommonCfg.DesireRate[2],pAdapter->CommonCfg.DesireRate[3], - pAdapter->CommonCfg.DesireRate[4],pAdapter->CommonCfg.DesireRate[5], - pAdapter->CommonCfg.DesireRate[6],pAdapter->CommonCfg.DesireRate[7] )); - // Changing DesiredRate may affect the MAX TX rate we used to TX frames out - MlmeUpdateTxRates(pAdapter, FALSE, 0); -} - -NDIS_STATUS RTMPWPARemoveKeyProc( - IN PRTMP_ADAPTER pAd, - IN PVOID pBuf) -{ - PNDIS_802_11_REMOVE_KEY pKey; - ULONG KeyIdx; - NDIS_STATUS Status = NDIS_STATUS_FAILURE; - BOOLEAN bTxKey; // Set the key as transmit key - BOOLEAN bPairwise; // Indicate the key is pairwise key - BOOLEAN bKeyRSC; // indicate the receive SC set by KeyRSC value. - // Otherwise, it will set by the NIC. - BOOLEAN bAuthenticator; // indicate key is set by authenticator. - INT i; - - DBGPRINT(RT_DEBUG_TRACE,("---> RTMPWPARemoveKeyProc\n")); - - pKey = (PNDIS_802_11_REMOVE_KEY) pBuf; - KeyIdx = pKey->KeyIndex & 0xff; - // Bit 31 of Add-key, Tx Key - bTxKey = (pKey->KeyIndex & 0x80000000) ? TRUE : FALSE; - // Bit 30 of Add-key PairwiseKey - bPairwise = (pKey->KeyIndex & 0x40000000) ? TRUE : FALSE; - // Bit 29 of Add-key KeyRSC - bKeyRSC = (pKey->KeyIndex & 0x20000000) ? TRUE : FALSE; - // Bit 28 of Add-key Authenticator - bAuthenticator = (pKey->KeyIndex & 0x10000000) ? TRUE : FALSE; - - // 1. If bTx is TRUE, return failure information - if (bTxKey == TRUE) - return(NDIS_STATUS_INVALID_DATA); - - // 2. Check Pairwise Key - if (bPairwise) - { - // a. If BSSID is broadcast, remove all pairwise keys. - // b. If not broadcast, remove the pairwise specified by BSSID - for (i = 0; i < SHARE_KEY_NUM; i++) - { - if (MAC_ADDR_EQUAL(pAd->SharedKey[BSS0][i].BssId, pKey->BSSID)) - { - DBGPRINT(RT_DEBUG_TRACE,("RTMPWPARemoveKeyProc(KeyIdx=%d)\n", i)); - pAd->SharedKey[BSS0][i].KeyLen = 0; - pAd->SharedKey[BSS0][i].CipherAlg = CIPHER_NONE; - AsicRemoveSharedKeyEntry(pAd, BSS0, (UCHAR)i); - Status = NDIS_STATUS_SUCCESS; - break; - } - } - } - // 3. Group Key - else - { - // a. If BSSID is broadcast, remove all group keys indexed - // b. If BSSID matched, delete the group key indexed. - DBGPRINT(RT_DEBUG_TRACE,("RTMPWPARemoveKeyProc(KeyIdx=%ld)\n", KeyIdx)); - pAd->SharedKey[BSS0][KeyIdx].KeyLen = 0; - pAd->SharedKey[BSS0][KeyIdx].CipherAlg = CIPHER_NONE; - AsicRemoveSharedKeyEntry(pAd, BSS0, (UCHAR)KeyIdx); - Status = NDIS_STATUS_SUCCESS; - } - - return (Status); -} -#endif // CONFIG_STA_SUPPORT // - - -#ifdef CONFIG_STA_SUPPORT -/* - ======================================================================== - - Routine Description: - Remove All WPA Keys - - Arguments: - pAd Pointer to our adapter - - Return Value: - None - - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -VOID RTMPWPARemoveAllKeys( - IN PRTMP_ADAPTER pAd) -{ - - UCHAR i; - - DBGPRINT(RT_DEBUG_TRACE,("RTMPWPARemoveAllKeys(AuthMode=%d, WepStatus=%d)\n", pAd->StaCfg.AuthMode, pAd->StaCfg.WepStatus)); - - // For WEP/CKIP, there is no need to remove it, since WinXP won't set it again after - // Link up. And it will be replaced if user changed it. - if (pAd->StaCfg.AuthMode < Ndis802_11AuthModeWPA) - return; - - // For WPA-None, there is no need to remove it, since WinXP won't set it again after - // Link up. And it will be replaced if user changed it. - if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) - return; - - // set BSSID wcid entry of the Pair-wise Key table as no-security mode - AsicRemovePairwiseKeyEntry(pAd, BSS0, BSSID_WCID); - - // set all shared key mode as no-security. - for (i = 0; i < SHARE_KEY_NUM; i++) - { - DBGPRINT(RT_DEBUG_TRACE,("remove %s key #%d\n", CipherName[pAd->SharedKey[BSS0][i].CipherAlg], i)); - NdisZeroMemory(&pAd->SharedKey[BSS0][i], sizeof(CIPHER_KEY)); - - AsicRemoveSharedKeyEntry(pAd, BSS0, i); - } - -} -#endif // CONFIG_STA_SUPPORT // - -/* - ======================================================================== - Routine Description: - Change NIC PHY mode. Re-association may be necessary. possible settings - include - PHY_11B, PHY_11BG_MIXED, PHY_11A, and PHY_11ABG_MIXED - - Arguments: - pAd - Pointer to our adapter - phymode - - - IRQL = PASSIVE_LEVEL - IRQL = DISPATCH_LEVEL - - ======================================================================== -*/ -VOID RTMPSetPhyMode( - IN PRTMP_ADAPTER pAd, - IN ULONG phymode) -{ - INT i; - // the selected phymode must be supported by the RF IC encoded in E2PROM - - pAd->CommonCfg.PhyMode = (UCHAR)phymode; - - DBGPRINT(RT_DEBUG_TRACE,("RTMPSetPhyMode : PhyMode=%d, channel=%d \n", pAd->CommonCfg.PhyMode, pAd->CommonCfg.Channel)); -#ifdef EXT_BUILD_CHANNEL_LIST - BuildChannelListEx(pAd); -#else - BuildChannelList(pAd); -#endif // EXT_BUILD_CHANNEL_LIST // - - // sanity check user setting - for (i = 0; i < pAd->ChannelListNum; i++) - { - if (pAd->CommonCfg.Channel == pAd->ChannelList[i].Channel) - break; - } - - if (i == pAd->ChannelListNum) - { -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - pAd->CommonCfg.Channel = FirstChannel(pAd); -#endif // CONFIG_STA_SUPPORT // - DBGPRINT(RT_DEBUG_ERROR, ("RTMPSetPhyMode: channel is out of range, use first channel=%d \n", pAd->CommonCfg.Channel)); - } - - NdisZeroMemory(pAd->CommonCfg.SupRate, MAX_LEN_OF_SUPPORTED_RATES); - NdisZeroMemory(pAd->CommonCfg.ExtRate, MAX_LEN_OF_SUPPORTED_RATES); - NdisZeroMemory(pAd->CommonCfg.DesireRate, MAX_LEN_OF_SUPPORTED_RATES); - switch (phymode) { - case PHY_11B: - pAd->CommonCfg.SupRate[0] = 0x82; // 1 mbps, in units of 0.5 Mbps, basic rate - pAd->CommonCfg.SupRate[1] = 0x84; // 2 mbps, in units of 0.5 Mbps, basic rate - pAd->CommonCfg.SupRate[2] = 0x8B; // 5.5 mbps, in units of 0.5 Mbps, basic rate - pAd->CommonCfg.SupRate[3] = 0x96; // 11 mbps, in units of 0.5 Mbps, basic rate - pAd->CommonCfg.SupRateLen = 4; - pAd->CommonCfg.ExtRateLen = 0; - pAd->CommonCfg.DesireRate[0] = 2; // 1 mbps, in units of 0.5 Mbps - pAd->CommonCfg.DesireRate[1] = 4; // 2 mbps, in units of 0.5 Mbps - pAd->CommonCfg.DesireRate[2] = 11; // 5.5 mbps, in units of 0.5 Mbps - pAd->CommonCfg.DesireRate[3] = 22; // 11 mbps, in units of 0.5 Mbps - //pAd->CommonCfg.HTPhyMode.field.MODE = MODE_CCK; // This MODE is only FYI. not use - break; - - case PHY_11G: - case PHY_11BG_MIXED: - case PHY_11ABG_MIXED: -#ifdef DOT11_N_SUPPORT - case PHY_11N_2_4G: - case PHY_11ABGN_MIXED: - case PHY_11BGN_MIXED: - case PHY_11GN_MIXED: -#endif // DOT11_N_SUPPORT // - pAd->CommonCfg.SupRate[0] = 0x82; // 1 mbps, in units of 0.5 Mbps, basic rate - pAd->CommonCfg.SupRate[1] = 0x84; // 2 mbps, in units of 0.5 Mbps, basic rate - pAd->CommonCfg.SupRate[2] = 0x8B; // 5.5 mbps, in units of 0.5 Mbps, basic rate - pAd->CommonCfg.SupRate[3] = 0x96; // 11 mbps, in units of 0.5 Mbps, basic rate - pAd->CommonCfg.SupRate[4] = 0x12; // 9 mbps, in units of 0.5 Mbps - pAd->CommonCfg.SupRate[5] = 0x24; // 18 mbps, in units of 0.5 Mbps - pAd->CommonCfg.SupRate[6] = 0x48; // 36 mbps, in units of 0.5 Mbps - pAd->CommonCfg.SupRate[7] = 0x6c; // 54 mbps, in units of 0.5 Mbps - pAd->CommonCfg.SupRateLen = 8; - pAd->CommonCfg.ExtRate[0] = 0x0C; // 6 mbps, in units of 0.5 Mbps - pAd->CommonCfg.ExtRate[1] = 0x18; // 12 mbps, in units of 0.5 Mbps - pAd->CommonCfg.ExtRate[2] = 0x30; // 24 mbps, in units of 0.5 Mbps - pAd->CommonCfg.ExtRate[3] = 0x60; // 48 mbps, in units of 0.5 Mbps - pAd->CommonCfg.ExtRateLen = 4; - pAd->CommonCfg.DesireRate[0] = 2; // 1 mbps, in units of 0.5 Mbps - pAd->CommonCfg.DesireRate[1] = 4; // 2 mbps, in units of 0.5 Mbps - pAd->CommonCfg.DesireRate[2] = 11; // 5.5 mbps, in units of 0.5 Mbps - pAd->CommonCfg.DesireRate[3] = 22; // 11 mbps, in units of 0.5 Mbps - pAd->CommonCfg.DesireRate[4] = 12; // 6 mbps, in units of 0.5 Mbps - pAd->CommonCfg.DesireRate[5] = 18; // 9 mbps, in units of 0.5 Mbps - pAd->CommonCfg.DesireRate[6] = 24; // 12 mbps, in units of 0.5 Mbps - pAd->CommonCfg.DesireRate[7] = 36; // 18 mbps, in units of 0.5 Mbps - pAd->CommonCfg.DesireRate[8] = 48; // 24 mbps, in units of 0.5 Mbps - pAd->CommonCfg.DesireRate[9] = 72; // 36 mbps, in units of 0.5 Mbps - pAd->CommonCfg.DesireRate[10] = 96; // 48 mbps, in units of 0.5 Mbps - pAd->CommonCfg.DesireRate[11] = 108; // 54 mbps, in units of 0.5 Mbps - break; - - case PHY_11A: -#ifdef DOT11_N_SUPPORT - case PHY_11AN_MIXED: - case PHY_11AGN_MIXED: - case PHY_11N_5G: -#endif // DOT11_N_SUPPORT // - pAd->CommonCfg.SupRate[0] = 0x8C; // 6 mbps, in units of 0.5 Mbps, basic rate - pAd->CommonCfg.SupRate[1] = 0x12; // 9 mbps, in units of 0.5 Mbps - pAd->CommonCfg.SupRate[2] = 0x98; // 12 mbps, in units of 0.5 Mbps, basic rate - pAd->CommonCfg.SupRate[3] = 0x24; // 18 mbps, in units of 0.5 Mbps - pAd->CommonCfg.SupRate[4] = 0xb0; // 24 mbps, in units of 0.5 Mbps, basic rate - pAd->CommonCfg.SupRate[5] = 0x48; // 36 mbps, in units of 0.5 Mbps - pAd->CommonCfg.SupRate[6] = 0x60; // 48 mbps, in units of 0.5 Mbps - pAd->CommonCfg.SupRate[7] = 0x6c; // 54 mbps, in units of 0.5 Mbps - pAd->CommonCfg.SupRateLen = 8; - pAd->CommonCfg.ExtRateLen = 0; - pAd->CommonCfg.DesireRate[0] = 12; // 6 mbps, in units of 0.5 Mbps - pAd->CommonCfg.DesireRate[1] = 18; // 9 mbps, in units of 0.5 Mbps - pAd->CommonCfg.DesireRate[2] = 24; // 12 mbps, in units of 0.5 Mbps - pAd->CommonCfg.DesireRate[3] = 36; // 18 mbps, in units of 0.5 Mbps - pAd->CommonCfg.DesireRate[4] = 48; // 24 mbps, in units of 0.5 Mbps - pAd->CommonCfg.DesireRate[5] = 72; // 36 mbps, in units of 0.5 Mbps - pAd->CommonCfg.DesireRate[6] = 96; // 48 mbps, in units of 0.5 Mbps - pAd->CommonCfg.DesireRate[7] = 108; // 54 mbps, in units of 0.5 Mbps - //pAd->CommonCfg.HTPhyMode.field.MODE = MODE_OFDM; // This MODE is only FYI. not use - break; - - default: - break; - } - - - pAd->CommonCfg.BandState = UNKNOWN_BAND; -} - - -#ifdef DOT11_N_SUPPORT -/* - ======================================================================== - Routine Description: - Caller ensures we has 802.11n support. - Calls at setting HT from AP/STASetinformation - - Arguments: - pAd - Pointer to our adapter - phymode - - - ======================================================================== -*/ -VOID RTMPSetHT( - IN PRTMP_ADAPTER pAd, - IN OID_SET_HT_PHYMODE *pHTPhyMode) -{ - //ULONG *pmcs; - UINT32 Value = 0; - UCHAR BBPValue = 0; - UCHAR BBP3Value = 0; - UCHAR RxStream = pAd->CommonCfg.RxStream; - - DBGPRINT(RT_DEBUG_TRACE, ("RTMPSetHT : HT_mode(%d), ExtOffset(%d), MCS(%d), BW(%d), STBC(%d), SHORTGI(%d)\n", - pHTPhyMode->HtMode, pHTPhyMode->ExtOffset, - pHTPhyMode->MCS, pHTPhyMode->BW, - pHTPhyMode->STBC, pHTPhyMode->SHORTGI)); - - // Don't zero supportedHyPhy structure. - RTMPZeroMemory(&pAd->CommonCfg.HtCapability, sizeof(pAd->CommonCfg.HtCapability)); - RTMPZeroMemory(&pAd->CommonCfg.AddHTInfo, sizeof(pAd->CommonCfg.AddHTInfo)); - RTMPZeroMemory(&pAd->CommonCfg.NewExtChanOffset, sizeof(pAd->CommonCfg.NewExtChanOffset)); - RTMPZeroMemory(&pAd->CommonCfg.DesiredHtPhy, sizeof(pAd->CommonCfg.DesiredHtPhy)); - - if (pAd->CommonCfg.bRdg) - { - pAd->CommonCfg.HtCapability.ExtHtCapInfo.PlusHTC = 1; - pAd->CommonCfg.HtCapability.ExtHtCapInfo.RDGSupport = 1; - } - else - { - pAd->CommonCfg.HtCapability.ExtHtCapInfo.PlusHTC = 0; - pAd->CommonCfg.HtCapability.ExtHtCapInfo.RDGSupport = 0; - } - - pAd->CommonCfg.HtCapability.HtCapParm.MaxRAmpduFactor = 3; - pAd->CommonCfg.DesiredHtPhy.MaxRAmpduFactor = 3; - - DBGPRINT(RT_DEBUG_TRACE, ("RTMPSetHT : RxBAWinLimit = %d\n", pAd->CommonCfg.BACapability.field.RxBAWinLimit)); - - // Mimo power save, A-MSDU size, - pAd->CommonCfg.DesiredHtPhy.AmsduEnable = (USHORT)pAd->CommonCfg.BACapability.field.AmsduEnable; - pAd->CommonCfg.DesiredHtPhy.AmsduSize = (UCHAR)pAd->CommonCfg.BACapability.field.AmsduSize; - pAd->CommonCfg.DesiredHtPhy.MimoPs = (UCHAR)pAd->CommonCfg.BACapability.field.MMPSmode; - pAd->CommonCfg.DesiredHtPhy.MpduDensity = (UCHAR)pAd->CommonCfg.BACapability.field.MpduDensity; - - pAd->CommonCfg.HtCapability.HtCapInfo.AMsduSize = (USHORT)pAd->CommonCfg.BACapability.field.AmsduSize; - pAd->CommonCfg.HtCapability.HtCapInfo.MimoPs = (USHORT)pAd->CommonCfg.BACapability.field.MMPSmode; - pAd->CommonCfg.HtCapability.HtCapParm.MpduDensity = (UCHAR)pAd->CommonCfg.BACapability.field.MpduDensity; - - DBGPRINT(RT_DEBUG_TRACE, ("RTMPSetHT : AMsduSize = %d, MimoPs = %d, MpduDensity = %d, MaxRAmpduFactor = %d\n", - pAd->CommonCfg.DesiredHtPhy.AmsduSize, - pAd->CommonCfg.DesiredHtPhy.MimoPs, - pAd->CommonCfg.DesiredHtPhy.MpduDensity, - pAd->CommonCfg.DesiredHtPhy.MaxRAmpduFactor)); - - if(pHTPhyMode->HtMode == HTMODE_GF) - { - pAd->CommonCfg.HtCapability.HtCapInfo.GF = 1; - pAd->CommonCfg.DesiredHtPhy.GF = 1; - } - else - pAd->CommonCfg.DesiredHtPhy.GF = 0; - - // Decide Rx MCSSet - switch (RxStream) - { - case 1: - pAd->CommonCfg.HtCapability.MCSSet[0] = 0xff; - pAd->CommonCfg.HtCapability.MCSSet[1] = 0x00; - break; - - case 2: - pAd->CommonCfg.HtCapability.MCSSet[0] = 0xff; - pAd->CommonCfg.HtCapability.MCSSet[1] = 0xff; - break; - - case 3: // 3*3 - pAd->CommonCfg.HtCapability.MCSSet[0] = 0xff; - pAd->CommonCfg.HtCapability.MCSSet[1] = 0xff; - pAd->CommonCfg.HtCapability.MCSSet[2] = 0xff; - break; - } - - if (pAd->CommonCfg.bForty_Mhz_Intolerant && (pAd->CommonCfg.Channel <= 14) && (pHTPhyMode->BW == BW_40) ) - { - pHTPhyMode->BW = BW_20; - pAd->CommonCfg.HtCapability.HtCapInfo.Forty_Mhz_Intolerant = 1; - } - - if(pHTPhyMode->BW == BW_40) - { - pAd->CommonCfg.HtCapability.MCSSet[4] = 0x1; // MCS 32 - pAd->CommonCfg.HtCapability.HtCapInfo.ChannelWidth = 1; - if (pAd->CommonCfg.Channel <= 14) - pAd->CommonCfg.HtCapability.HtCapInfo.CCKmodein40 = 1; - - pAd->CommonCfg.DesiredHtPhy.ChannelWidth = 1; - pAd->CommonCfg.AddHTInfo.AddHtInfo.RecomWidth = 1; - pAd->CommonCfg.AddHTInfo.AddHtInfo.ExtChanOffset = (pHTPhyMode->ExtOffset == EXTCHA_BELOW)? (EXTCHA_BELOW): EXTCHA_ABOVE; - // Set Regsiter for extension channel position. - RTMP_IO_READ32(pAd, TX_BAND_CFG, &Value); - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BBP3Value); - if ((pHTPhyMode->ExtOffset == EXTCHA_BELOW)) - { - Value |= 0x1; - BBP3Value |= (0x20); - RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Value); - } - else if ((pHTPhyMode->ExtOffset == EXTCHA_ABOVE)) - { - Value &= 0xfe; - BBP3Value &= (~0x20); - RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Value); - } - - // Turn on BBP 40MHz mode now only as AP . - // Sta can turn on BBP 40MHz after connection with 40MHz AP. Sta only broadcast 40MHz capability before connection. - if ((pAd->OpMode == OPMODE_AP) || INFRA_ON(pAd) || ADHOC_ON(pAd) - ) - { - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); - BBPValue &= (~0x18); - BBPValue |= 0x10; - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); - - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BBP3Value); - pAd->CommonCfg.BBPCurrentBW = BW_40; - } - } - else - { - pAd->CommonCfg.HtCapability.HtCapInfo.ChannelWidth = 0; - pAd->CommonCfg.DesiredHtPhy.ChannelWidth = 0; - pAd->CommonCfg.AddHTInfo.AddHtInfo.RecomWidth = 0; - pAd->CommonCfg.AddHTInfo.AddHtInfo.ExtChanOffset = EXTCHA_NONE; - pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel; - // Turn on BBP 20MHz mode by request here. - { - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); - BBPValue &= (~0x18); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); - pAd->CommonCfg.BBPCurrentBW = BW_20; - } - } - - if(pHTPhyMode->STBC == STBC_USE) - { - pAd->CommonCfg.HtCapability.HtCapInfo.TxSTBC = 1; - pAd->CommonCfg.DesiredHtPhy.TxSTBC = 1; - pAd->CommonCfg.HtCapability.HtCapInfo.RxSTBC = 1; - pAd->CommonCfg.DesiredHtPhy.RxSTBC = 1; - } - else - { - pAd->CommonCfg.DesiredHtPhy.TxSTBC = 0; - pAd->CommonCfg.DesiredHtPhy.RxSTBC = 0; - } - - if(pHTPhyMode->SHORTGI == GI_400) - { - pAd->CommonCfg.HtCapability.HtCapInfo.ShortGIfor20 = 1; - pAd->CommonCfg.HtCapability.HtCapInfo.ShortGIfor40 = 1; - pAd->CommonCfg.DesiredHtPhy.ShortGIfor20 = 1; - pAd->CommonCfg.DesiredHtPhy.ShortGIfor40 = 1; - } - else - { - pAd->CommonCfg.HtCapability.HtCapInfo.ShortGIfor20 = 0; - pAd->CommonCfg.HtCapability.HtCapInfo.ShortGIfor40 = 0; - pAd->CommonCfg.DesiredHtPhy.ShortGIfor20 = 0; - pAd->CommonCfg.DesiredHtPhy.ShortGIfor40 = 0; - } - - // We support link adaptation for unsolicit MCS feedback, set to 2. - pAd->CommonCfg.HtCapability.ExtHtCapInfo.MCSFeedback = MCSFBK_NONE; //MCSFBK_UNSOLICIT; - pAd->CommonCfg.AddHTInfo.ControlChan = pAd->CommonCfg.Channel; - // 1, the extension channel above the control channel. - - // EDCA parameters used for AP's own transmission - if (pAd->CommonCfg.APEdcaParm.bValid == FALSE) - { - pAd->CommonCfg.APEdcaParm.bValid = TRUE; - pAd->CommonCfg.APEdcaParm.Aifsn[0] = 3; - pAd->CommonCfg.APEdcaParm.Aifsn[1] = 7; - pAd->CommonCfg.APEdcaParm.Aifsn[2] = 1; - pAd->CommonCfg.APEdcaParm.Aifsn[3] = 1; - - pAd->CommonCfg.APEdcaParm.Cwmin[0] = 4; - pAd->CommonCfg.APEdcaParm.Cwmin[1] = 4; - pAd->CommonCfg.APEdcaParm.Cwmin[2] = 3; - pAd->CommonCfg.APEdcaParm.Cwmin[3] = 2; - - pAd->CommonCfg.APEdcaParm.Cwmax[0] = 6; - pAd->CommonCfg.APEdcaParm.Cwmax[1] = 10; - pAd->CommonCfg.APEdcaParm.Cwmax[2] = 4; - pAd->CommonCfg.APEdcaParm.Cwmax[3] = 3; - - pAd->CommonCfg.APEdcaParm.Txop[0] = 0; - pAd->CommonCfg.APEdcaParm.Txop[1] = 0; - pAd->CommonCfg.APEdcaParm.Txop[2] = 94; - pAd->CommonCfg.APEdcaParm.Txop[3] = 47; - } - AsicSetEdcaParm(pAd, &pAd->CommonCfg.APEdcaParm); - - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - RTMPSetIndividualHT(pAd, 0); - } -#endif // CONFIG_STA_SUPPORT // - -} - -/* - ======================================================================== - Routine Description: - Caller ensures we has 802.11n support. - Calls at setting HT from AP/STASetinformation - - Arguments: - pAd - Pointer to our adapter - phymode - - - ======================================================================== -*/ -VOID RTMPSetIndividualHT( - IN PRTMP_ADAPTER pAd, - IN UCHAR apidx) -{ - PRT_HT_PHY_INFO pDesired_ht_phy = NULL; - UCHAR TxStream = pAd->CommonCfg.TxStream; - UCHAR DesiredMcs = MCS_AUTO; - - do - { - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - pDesired_ht_phy = &pAd->StaCfg.DesiredHtPhyInfo; - DesiredMcs = pAd->StaCfg.DesiredTransmitSetting.field.MCS; - //pAd->StaCfg.bAutoTxRateSwitch = (DesiredMcs == MCS_AUTO) ? TRUE : FALSE; - break; - } -#endif // CONFIG_STA_SUPPORT // - } while (FALSE); - - if (pDesired_ht_phy == NULL) - { - DBGPRINT(RT_DEBUG_ERROR, ("RTMPSetIndividualHT: invalid apidx(%d)\n", apidx)); - return; - } - RTMPZeroMemory(pDesired_ht_phy, sizeof(RT_HT_PHY_INFO)); - - DBGPRINT(RT_DEBUG_TRACE, ("RTMPSetIndividualHT : Desired MCS = %d\n", DesiredMcs)); - // Check the validity of MCS - if ((TxStream == 1) && ((DesiredMcs >= MCS_8) && (DesiredMcs <= MCS_15))) - { - DBGPRINT(RT_DEBUG_WARN, ("RTMPSetIndividualHT: MCS(%d) is invalid in 1S, reset it as MCS_7\n", DesiredMcs)); - DesiredMcs = MCS_7; - } - - if ((pAd->CommonCfg.DesiredHtPhy.ChannelWidth == BW_20) && (DesiredMcs == MCS_32)) - { - DBGPRINT(RT_DEBUG_WARN, ("RTMPSetIndividualHT: MCS_32 is only supported in 40-MHz, reset it as MCS_0\n")); - DesiredMcs = MCS_0; - } - - pDesired_ht_phy->bHtEnable = TRUE; - - // Decide desired Tx MCS - switch (TxStream) - { - case 1: - if (DesiredMcs == MCS_AUTO) - { - pDesired_ht_phy->MCSSet[0]= 0xff; - pDesired_ht_phy->MCSSet[1]= 0x00; - } - else if (DesiredMcs <= MCS_7) - { - pDesired_ht_phy->MCSSet[0]= 1<MCSSet[1]= 0x00; - } - break; - - case 2: - if (DesiredMcs == MCS_AUTO) - { - pDesired_ht_phy->MCSSet[0]= 0xff; - pDesired_ht_phy->MCSSet[1]= 0xff; - } - else if (DesiredMcs <= MCS_15) - { - ULONG mode; - - mode = DesiredMcs / 8; - if (mode < 2) - pDesired_ht_phy->MCSSet[mode] = (1 << (DesiredMcs - mode * 8)); - } - break; - - case 3: // 3*3 - if (DesiredMcs == MCS_AUTO) - { - /* MCS0 ~ MCS23, 3 bytes */ - pDesired_ht_phy->MCSSet[0]= 0xff; - pDesired_ht_phy->MCSSet[1]= 0xff; - pDesired_ht_phy->MCSSet[2]= 0xff; - } - else if (DesiredMcs <= MCS_23) - { - ULONG mode; - - mode = DesiredMcs / 8; - if (mode < 3) - pDesired_ht_phy->MCSSet[mode] = (1 << (DesiredMcs - mode * 8)); - } - break; - } - - if(pAd->CommonCfg.DesiredHtPhy.ChannelWidth == BW_40) - { - if (DesiredMcs == MCS_AUTO || DesiredMcs == MCS_32) - pDesired_ht_phy->MCSSet[4] = 0x1; - } - - // update HT Rate setting - if (pAd->OpMode == OPMODE_STA) - MlmeUpdateHtTxRates(pAd, BSS0); - else - MlmeUpdateHtTxRates(pAd, apidx); -} - - -/* - ======================================================================== - Routine Description: - Update HT IE from our capability. - - Arguments: - Send all HT IE in beacon/probe rsp/assoc rsp/action frame. - - - ======================================================================== -*/ -VOID RTMPUpdateHTIE( - IN RT_HT_CAPABILITY *pRtHt, - IN UCHAR *pMcsSet, - OUT HT_CAPABILITY_IE *pHtCapability, - OUT ADD_HT_INFO_IE *pAddHtInfo) -{ - RTMPZeroMemory(pHtCapability, sizeof(HT_CAPABILITY_IE)); - RTMPZeroMemory(pAddHtInfo, sizeof(ADD_HT_INFO_IE)); - - pHtCapability->HtCapInfo.ChannelWidth = pRtHt->ChannelWidth; - pHtCapability->HtCapInfo.MimoPs = pRtHt->MimoPs; - pHtCapability->HtCapInfo.GF = pRtHt->GF; - pHtCapability->HtCapInfo.ShortGIfor20 = pRtHt->ShortGIfor20; - pHtCapability->HtCapInfo.ShortGIfor40 = pRtHt->ShortGIfor40; - pHtCapability->HtCapInfo.TxSTBC = pRtHt->TxSTBC; - pHtCapability->HtCapInfo.RxSTBC = pRtHt->RxSTBC; - pHtCapability->HtCapInfo.AMsduSize = pRtHt->AmsduSize; - pHtCapability->HtCapParm.MaxRAmpduFactor = pRtHt->MaxRAmpduFactor; - pHtCapability->HtCapParm.MpduDensity = pRtHt->MpduDensity; - - pAddHtInfo->AddHtInfo.ExtChanOffset = pRtHt->ExtChanOffset ; - pAddHtInfo->AddHtInfo.RecomWidth = pRtHt->RecomWidth; - pAddHtInfo->AddHtInfo2.OperaionMode = pRtHt->OperaionMode; - pAddHtInfo->AddHtInfo2.NonGfPresent = pRtHt->NonGfPresent; - RTMPMoveMemory(pAddHtInfo->MCSSet, /*pRtHt->MCSSet*/pMcsSet, 4); // rt2860 only support MCS max=32, no need to copy all 16 uchar. - - DBGPRINT(RT_DEBUG_TRACE,("RTMPUpdateHTIE <== \n")); -} -#endif // DOT11_N_SUPPORT // - -/* - ======================================================================== - Description: - Add Client security information into ASIC WCID table and IVEIV table. - Return: - ======================================================================== -*/ -VOID RTMPAddWcidAttributeEntry( - IN PRTMP_ADAPTER pAd, - IN UCHAR BssIdx, - IN UCHAR KeyIdx, - IN UCHAR CipherAlg, - IN MAC_TABLE_ENTRY *pEntry) -{ - UINT32 WCIDAttri = 0; - USHORT offset; - UCHAR IVEIV = 0; - USHORT Wcid = 0; - - { -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - if (BssIdx > BSS0) - { - DBGPRINT(RT_DEBUG_ERROR, ("RTMPAddWcidAttributeEntry: The BSS-index(%d) is out of range for Infra link. \n", BssIdx)); - return; - } - - // 1. In ADHOC mode, the AID is wcid number. And NO mesh link exists. - // 2. In Infra mode, the AID:1 MUST be wcid of infra STA. - // the AID:2~ assign to mesh link entry. - if (pEntry && ADHOC_ON(pAd)) - Wcid = pEntry->Aid; - else if (pEntry && INFRA_ON(pAd)) - { -#ifdef QOS_DLS_SUPPORT - if (pEntry->ValidAsDls == TRUE) - Wcid = pEntry->Aid; - else -#endif // QOS_DLS_SUPPORT // - Wcid = BSSID_WCID; - } - else - Wcid = MCAST_WCID; - } -#endif // CONFIG_STA_SUPPORT // - } - - // Update WCID attribute table - offset = MAC_WCID_ATTRIBUTE_BASE + (Wcid * HW_WCID_ATTRI_SIZE); - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - if (pEntry && pEntry->ValidAsMesh) - WCIDAttri = (CipherAlg<<1) | PAIRWISEKEYTABLE; -#ifdef QOS_DLS_SUPPORT - else if ((pEntry) && (pEntry->ValidAsDls) && - ((CipherAlg == CIPHER_TKIP) || - (CipherAlg == CIPHER_TKIP_NO_MIC) || - (CipherAlg == CIPHER_AES) || - (CipherAlg == CIPHER_NONE))) - WCIDAttri = (CipherAlg<<1) | PAIRWISEKEYTABLE; -#endif // QOS_DLS_SUPPORT // - else - WCIDAttri = (CipherAlg<<1) | SHAREDKEYTABLE; - } -#endif // CONFIG_STA_SUPPORT // - - RTMP_IO_WRITE32(pAd, offset, WCIDAttri); - - - // Update IV/EIV table - offset = MAC_IVEIV_TABLE_BASE + (Wcid * HW_IVEIV_ENTRY_SIZE); - - // WPA mode - if ((CipherAlg == CIPHER_TKIP) || (CipherAlg == CIPHER_TKIP_NO_MIC) || (CipherAlg == CIPHER_AES)) - { - // Eiv bit on. keyid always is 0 for pairwise key - IVEIV = (KeyIdx <<6) | 0x20; - } - else - { - // WEP KeyIdx is default tx key. - IVEIV = (KeyIdx << 6); - } - - // For key index and ext IV bit, so only need to update the position(offset+3). -#ifdef RT2870 - RTUSBMultiWrite_OneByte(pAd, offset+3, &IVEIV); -#endif // RT2870 // - - DBGPRINT(RT_DEBUG_TRACE,("RTMPAddWcidAttributeEntry: WCID #%d, KeyIndex #%d, Alg=%s\n",Wcid, KeyIdx, CipherName[CipherAlg])); - DBGPRINT(RT_DEBUG_TRACE,(" WCIDAttri = 0x%x \n", WCIDAttri)); - -} - -/* - ========================================================================== - Description: - Parse encryption type -Arguments: - pAdapter Pointer to our adapter - wrq Pointer to the ioctl argument - - Return Value: - None - - Note: - ========================================================================== -*/ -CHAR *GetEncryptType(CHAR enc) -{ - if(enc == Ndis802_11WEPDisabled) - return "NONE"; - if(enc == Ndis802_11WEPEnabled) - return "WEP"; - if(enc == Ndis802_11Encryption2Enabled) - return "TKIP"; - if(enc == Ndis802_11Encryption3Enabled) - return "AES"; - if(enc == Ndis802_11Encryption4Enabled) - return "TKIPAES"; - else - return "UNKNOW"; -} - -CHAR *GetAuthMode(CHAR auth) -{ - if(auth == Ndis802_11AuthModeOpen) - return "OPEN"; - if(auth == Ndis802_11AuthModeShared) - return "SHARED"; - if(auth == Ndis802_11AuthModeAutoSwitch) - return "AUTOWEP"; - if(auth == Ndis802_11AuthModeWPA) - return "WPA"; - if(auth == Ndis802_11AuthModeWPAPSK) - return "WPAPSK"; - if(auth == Ndis802_11AuthModeWPANone) - return "WPANONE"; - if(auth == Ndis802_11AuthModeWPA2) - return "WPA2"; - if(auth == Ndis802_11AuthModeWPA2PSK) - return "WPA2PSK"; - if(auth == Ndis802_11AuthModeWPA1WPA2) - return "WPA1WPA2"; - if(auth == Ndis802_11AuthModeWPA1PSKWPA2PSK) - return "WPA1PSKWPA2PSK"; - - return "UNKNOW"; -} - -#if 1 //#ifndef UCOS -/* - ========================================================================== - Description: - Get site survey results - Arguments: - pAdapter Pointer to our adapter - wrq Pointer to the ioctl argument - - Return Value: - None - - Note: - Usage: - 1.) UI needs to wait 4 seconds after issue a site survey command - 2.) iwpriv ra0 get_site_survey - 3.) UI needs to prepare at least 4096bytes to get the results - ========================================================================== -*/ -#define LINE_LEN (4+33+20+8+10+9+7+3) // Channel+SSID+Bssid+WepStatus+AuthMode+Signal+WiressMode+NetworkType -#ifdef CONFIG_STA_SUPPORT -#endif // CONFIG_STA_SUPPORT // -VOID RTMPIoctlGetSiteSurvey( - IN PRTMP_ADAPTER pAdapter, - IN struct iwreq *wrq) -{ - CHAR *msg; - INT i=0; - INT WaitCnt; - INT Status=0; - CHAR Ssid[MAX_LEN_OF_SSID +1]; - INT Rssi = 0, max_len = LINE_LEN; - UINT Rssi_Quality = 0; - NDIS_802_11_NETWORK_TYPE wireless_mode; - - os_alloc_mem(NULL, (PUCHAR *)&msg, sizeof(CHAR)*((MAX_LEN_OF_BSS_TABLE)*max_len)); - - if (msg == NULL) - { - DBGPRINT(RT_DEBUG_TRACE, ("RTMPIoctlGetSiteSurvey - msg memory alloc fail.\n")); - return; - } - - memset(msg, 0 ,(MAX_LEN_OF_BSS_TABLE)*max_len ); - memset(Ssid, 0 ,(MAX_LEN_OF_SSID +1)); - sprintf(msg,"%s","\n"); - sprintf(msg+strlen(msg),"%-4s%-33s%-20s%-8s%-10s%-9s%-7s%-3s\n", - "Ch", "SSID", "BSSID", "Enc", "Auth", "Siganl(%)", "W-Mode", " NT"); - -#ifdef CONFIG_STA_SUPPORT -#endif // CONFIG_STA_SUPPORT // - - WaitCnt = 0; -#ifdef CONFIG_STA_SUPPORT - pAdapter->StaCfg.bScanReqIsFromWebUI = TRUE; - while ((ScanRunning(pAdapter) == TRUE) && (WaitCnt++ < 200)) - OS_WAIT(500); -#endif // CONFIG_STA_SUPPORT // - - for(i=0; iScanTab.BssNr ;i++) - { - if( pAdapter->ScanTab.BssEntry[i].Channel==0) - break; - - if((strlen(msg)+max_len ) >= IW_SCAN_MAX_DATA) - break; - - //Channel - sprintf(msg+strlen(msg),"%-4d", pAdapter->ScanTab.BssEntry[i].Channel); - //SSID - memcpy(Ssid, pAdapter->ScanTab.BssEntry[i].Ssid, pAdapter->ScanTab.BssEntry[i].SsidLen); - Ssid[pAdapter->ScanTab.BssEntry[i].SsidLen] = '\0'; - sprintf(msg+strlen(msg),"%-33s", Ssid); - //BSSID - sprintf(msg+strlen(msg),"%02x:%02x:%02x:%02x:%02x:%02x ", - pAdapter->ScanTab.BssEntry[i].Bssid[0], - pAdapter->ScanTab.BssEntry[i].Bssid[1], - pAdapter->ScanTab.BssEntry[i].Bssid[2], - pAdapter->ScanTab.BssEntry[i].Bssid[3], - pAdapter->ScanTab.BssEntry[i].Bssid[4], - pAdapter->ScanTab.BssEntry[i].Bssid[5]); - //Encryption Type - sprintf(msg+strlen(msg),"%-8s",GetEncryptType(pAdapter->ScanTab.BssEntry[i].WepStatus)); - //Authentication Mode - if (pAdapter->ScanTab.BssEntry[i].WepStatus == Ndis802_11WEPEnabled) - sprintf(msg+strlen(msg),"%-10s", "UNKNOW"); - else - sprintf(msg+strlen(msg),"%-10s",GetAuthMode(pAdapter->ScanTab.BssEntry[i].AuthMode)); - // Rssi - Rssi = (INT)pAdapter->ScanTab.BssEntry[i].Rssi; - if (Rssi >= -50) - Rssi_Quality = 100; - else if (Rssi >= -80) // between -50 ~ -80dbm - Rssi_Quality = (UINT)(24 + ((Rssi + 80) * 26)/10); - else if (Rssi >= -90) // between -80 ~ -90dbm - Rssi_Quality = (UINT)(((Rssi + 90) * 26)/10); - else // < -84 dbm - Rssi_Quality = 0; - sprintf(msg+strlen(msg),"%-9d", Rssi_Quality); - // Wireless Mode - wireless_mode = NetworkTypeInUseSanity(&pAdapter->ScanTab.BssEntry[i]); - if (wireless_mode == Ndis802_11FH || - wireless_mode == Ndis802_11DS) - sprintf(msg+strlen(msg),"%-7s", "11b"); - else if (wireless_mode == Ndis802_11OFDM5) - sprintf(msg+strlen(msg),"%-7s", "11a"); - else if (wireless_mode == Ndis802_11OFDM5_N) - sprintf(msg+strlen(msg),"%-7s", "11a/n"); - else if (wireless_mode == Ndis802_11OFDM24) - sprintf(msg+strlen(msg),"%-7s", "11b/g"); - else if (wireless_mode == Ndis802_11OFDM24_N) - sprintf(msg+strlen(msg),"%-7s", "11b/g/n"); - else - sprintf(msg+strlen(msg),"%-7s", "unknow"); - //Network Type - if (pAdapter->ScanTab.BssEntry[i].BssType == BSS_ADHOC) - sprintf(msg+strlen(msg),"%-3s", " Ad"); - else - sprintf(msg+strlen(msg),"%-3s", " In"); - - sprintf(msg+strlen(msg),"\n"); -#ifdef CONFIG_STA_SUPPORT -#endif // CONFIG_STA_SUPPORT // - } - -#ifdef CONFIG_STA_SUPPORT - pAdapter->StaCfg.bScanReqIsFromWebUI = FALSE; -#endif // CONFIG_STA_SUPPORT // - wrq->u.data.length = strlen(msg); - Status = copy_to_user(wrq->u.data.pointer, msg, wrq->u.data.length); - - DBGPRINT(RT_DEBUG_TRACE, ("RTMPIoctlGetSiteSurvey - wrq->u.data.length = %d\n", wrq->u.data.length)); - os_free_mem(NULL, (PUCHAR)msg); -} - - -#define MAC_LINE_LEN (14+4+4+10+10+10+6+6) // Addr+aid+psm+datatime+rxbyte+txbyte+current tx rate+last tx rate -VOID RTMPIoctlGetMacTable( - IN PRTMP_ADAPTER pAd, - IN struct iwreq *wrq) -{ - INT i; - RT_802_11_MAC_TABLE MacTab; - char *msg; - - MacTab.Num = 0; - for (i=0; iMacTab.Content[i].ValidAsCLI && (pAd->MacTab.Content[i].Sst == SST_ASSOC)) - { - COPY_MAC_ADDR(MacTab.Entry[MacTab.Num].Addr, &pAd->MacTab.Content[i].Addr); - MacTab.Entry[MacTab.Num].Aid = (UCHAR)pAd->MacTab.Content[i].Aid; - MacTab.Entry[MacTab.Num].Psm = pAd->MacTab.Content[i].PsMode; -#ifdef DOT11_N_SUPPORT - MacTab.Entry[MacTab.Num].MimoPs = pAd->MacTab.Content[i].MmpsMode; -#endif // DOT11_N_SUPPORT // - - // Fill in RSSI per entry - MacTab.Entry[MacTab.Num].AvgRssi0 = pAd->MacTab.Content[i].RssiSample.AvgRssi0; - MacTab.Entry[MacTab.Num].AvgRssi1 = pAd->MacTab.Content[i].RssiSample.AvgRssi1; - MacTab.Entry[MacTab.Num].AvgRssi2 = pAd->MacTab.Content[i].RssiSample.AvgRssi2; - - // the connected time per entry - MacTab.Entry[MacTab.Num].ConnectedTime = pAd->MacTab.Content[i].StaConnectTime; - MacTab.Entry[MacTab.Num].TxRate.field.MCS = pAd->MacTab.Content[i].HTPhyMode.field.MCS; - MacTab.Entry[MacTab.Num].TxRate.field.BW = pAd->MacTab.Content[i].HTPhyMode.field.BW; - MacTab.Entry[MacTab.Num].TxRate.field.ShortGI = pAd->MacTab.Content[i].HTPhyMode.field.ShortGI; - MacTab.Entry[MacTab.Num].TxRate.field.STBC = pAd->MacTab.Content[i].HTPhyMode.field.STBC; - MacTab.Entry[MacTab.Num].TxRate.field.rsv = pAd->MacTab.Content[i].HTPhyMode.field.rsv; - MacTab.Entry[MacTab.Num].TxRate.field.MODE = pAd->MacTab.Content[i].HTPhyMode.field.MODE; - MacTab.Entry[MacTab.Num].TxRate.word = pAd->MacTab.Content[i].HTPhyMode.word; - - MacTab.Num += 1; - } - } - wrq->u.data.length = sizeof(RT_802_11_MAC_TABLE); - if (copy_to_user(wrq->u.data.pointer, &MacTab, wrq->u.data.length)) - { - DBGPRINT(RT_DEBUG_TRACE, ("%s: copy_to_user() fail\n", __FUNCTION__)); - } - - msg = (CHAR *) kmalloc(sizeof(CHAR)*(MAX_LEN_OF_MAC_TABLE*MAC_LINE_LEN), MEM_ALLOC_FLAG); - memset(msg, 0 ,MAX_LEN_OF_MAC_TABLE*MAC_LINE_LEN ); - sprintf(msg,"%s","\n"); - sprintf(msg+strlen(msg),"%-14s%-4s%-4s%-10s%-10s%-10s%-6s%-6s\n", - "MAC", "AID", "PSM", "LDT", "RxB", "TxB","CTxR", "LTxR"); - - for (i=0; iMacTab.Content[i]; - if (pEntry->ValidAsCLI && (pEntry->Sst == SST_ASSOC)) - { - if((strlen(msg)+MAC_LINE_LEN ) >= (MAX_LEN_OF_MAC_TABLE*MAC_LINE_LEN) ) - break; - sprintf(msg+strlen(msg),"%02x%02x%02x%02x%02x%02x ", - pEntry->Addr[0], pEntry->Addr[1], pEntry->Addr[2], - pEntry->Addr[3], pEntry->Addr[4], pEntry->Addr[5]); - sprintf(msg+strlen(msg),"%-4d", (int)pEntry->Aid); - sprintf(msg+strlen(msg),"%-4d", (int)pEntry->PsMode); - sprintf(msg+strlen(msg),"%-10d",0/*pAd->MacTab.Content[i].HSCounter.LastDataPacketTime*/); // ToDo - sprintf(msg+strlen(msg),"%-10d",0/*pAd->MacTab.Content[i].HSCounter.TotalRxByteCount*/); // ToDo - sprintf(msg+strlen(msg),"%-10d",0/*pAd->MacTab.Content[i].HSCounter.TotalTxByteCount*/); // ToDo - sprintf(msg+strlen(msg),"%-6d",RateIdToMbps[pAd->MacTab.Content[i].CurrTxRate]); - sprintf(msg+strlen(msg),"%-6d\n",0/*RateIdToMbps[pAd->MacTab.Content[i].LastTxRate]*/); // ToDo - } - } - // for compatible with old API just do the printk to console - //wrq->u.data.length = strlen(msg); - //if (copy_to_user(wrq->u.data.pointer, msg, wrq->u.data.length)) - { - DBGPRINT(RT_DEBUG_TRACE, ("%s", msg)); - } - - kfree(msg); -} -#endif // UCOS // - -#ifdef DOT11_N_SUPPORT -INT Set_BASetup_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - UCHAR mac[6], tid; - char *token, sepValue[] = ":", DASH = '-'; - INT i; - MAC_TABLE_ENTRY *pEntry; - -/* - The BASetup inupt string format should be xx:xx:xx:xx:xx:xx-d, - =>The six 2 digit hex-decimal number previous are the Mac address, - =>The seventh decimal number is the tid value. -*/ - //printk("\n%s\n", arg); - - if(strlen(arg) < 19) //Mac address acceptable format 01:02:03:04:05:06 length 17 plus the "-" and tid value in decimal format. - return FALSE; - - token = strchr(arg, DASH); - if ((token != NULL) && (strlen(token)>1)) - { - tid = simple_strtol((token+1), 0, 10); - if (tid > 15) - return FALSE; - - *token = '\0'; - for (i = 0, token = rstrtok(arg, &sepValue[0]); token; token = rstrtok(NULL, &sepValue[0]), i++) - { - if((strlen(token) != 2) || (!isxdigit(*token)) || (!isxdigit(*(token+1)))) - return FALSE; - AtoH(token, (PUCHAR)(&mac[i]), 1); - } - if(i != 6) - return FALSE; - - printk("\n%02x:%02x:%02x:%02x:%02x:%02x-%02x\n", mac[0], mac[1], - mac[2], mac[3], mac[4], mac[5], tid); - - pEntry = MacTableLookup(pAd, mac); - - if (pEntry) { - printk("\nSetup BA Session: Tid = %d\n", tid); - BAOriSessionSetUp(pAd, pEntry, tid, 0, 100, TRUE); - } - - return TRUE; - } - - return FALSE; - -} - -INT Set_BADecline_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ULONG bBADecline; - - bBADecline = simple_strtol(arg, 0, 10); - - if (bBADecline == 0) - { - pAd->CommonCfg.bBADecline = FALSE; - } - else if (bBADecline == 1) - { - pAd->CommonCfg.bBADecline = TRUE; - } - else - { - return FALSE; //Invalid argument - } - - DBGPRINT(RT_DEBUG_TRACE, ("Set_BADecline_Proc::(BADecline=%d)\n", pAd->CommonCfg.bBADecline)); - - return TRUE; -} - -INT Set_BAOriTearDown_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - UCHAR mac[6], tid; - char *token, sepValue[] = ":", DASH = '-'; - INT i; - MAC_TABLE_ENTRY *pEntry; - - //printk("\n%s\n", arg); -/* - The BAOriTearDown inupt string format should be xx:xx:xx:xx:xx:xx-d, - =>The six 2 digit hex-decimal number previous are the Mac address, - =>The seventh decimal number is the tid value. -*/ - if(strlen(arg) < 19) //Mac address acceptable format 01:02:03:04:05:06 length 17 plus the "-" and tid value in decimal format. - return FALSE; - - token = strchr(arg, DASH); - if ((token != NULL) && (strlen(token)>1)) - { - tid = simple_strtol((token+1), 0, 10); - if (tid > NUM_OF_TID) - return FALSE; - - *token = '\0'; - for (i = 0, token = rstrtok(arg, &sepValue[0]); token; token = rstrtok(NULL, &sepValue[0]), i++) - { - if((strlen(token) != 2) || (!isxdigit(*token)) || (!isxdigit(*(token+1)))) - return FALSE; - AtoH(token, (PUCHAR)(&mac[i]), 1); - } - if(i != 6) - return FALSE; - - printk("\n%02x:%02x:%02x:%02x:%02x:%02x-%02x", mac[0], mac[1], - mac[2], mac[3], mac[4], mac[5], tid); - - pEntry = MacTableLookup(pAd, mac); - - if (pEntry) { - printk("\nTear down Ori BA Session: Tid = %d\n", tid); - BAOriSessionTearDown(pAd, pEntry->Aid, tid, FALSE, TRUE); - } - - return TRUE; - } - - return FALSE; - -} - -INT Set_BARecTearDown_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - UCHAR mac[6], tid; - char *token, sepValue[] = ":", DASH = '-'; - INT i; - MAC_TABLE_ENTRY *pEntry; - - //printk("\n%s\n", arg); -/* - The BARecTearDown inupt string format should be xx:xx:xx:xx:xx:xx-d, - =>The six 2 digit hex-decimal number previous are the Mac address, - =>The seventh decimal number is the tid value. -*/ - if(strlen(arg) < 19) //Mac address acceptable format 01:02:03:04:05:06 length 17 plus the "-" and tid value in decimal format. - return FALSE; - - token = strchr(arg, DASH); - if ((token != NULL) && (strlen(token)>1)) - { - tid = simple_strtol((token+1), 0, 10); - if (tid > NUM_OF_TID) - return FALSE; - - *token = '\0'; - for (i = 0, token = rstrtok(arg, &sepValue[0]); token; token = rstrtok(NULL, &sepValue[0]), i++) - { - if((strlen(token) != 2) || (!isxdigit(*token)) || (!isxdigit(*(token+1)))) - return FALSE; - AtoH(token, (PUCHAR)(&mac[i]), 1); - } - if(i != 6) - return FALSE; - - printk("\n%02x:%02x:%02x:%02x:%02x:%02x-%02x", mac[0], mac[1], - mac[2], mac[3], mac[4], mac[5], tid); - - pEntry = MacTableLookup(pAd, mac); - - if (pEntry) { - printk("\nTear down Rec BA Session: Tid = %d\n", tid); - BARecSessionTearDown(pAd, pEntry->Aid, tid, FALSE); - } - - return TRUE; - } - - return FALSE; - -} - -INT Set_HtBw_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ULONG HtBw; - - HtBw = simple_strtol(arg, 0, 10); - if (HtBw == BW_40) - pAd->CommonCfg.RegTransmitSetting.field.BW = BW_40; - else if (HtBw == BW_20) - pAd->CommonCfg.RegTransmitSetting.field.BW = BW_20; - else - return FALSE; //Invalid argument - - SetCommonHT(pAd); - - DBGPRINT(RT_DEBUG_TRACE, ("Set_HtBw_Proc::(HtBw=%d)\n", pAd->CommonCfg.RegTransmitSetting.field.BW)); - - return TRUE; -} - -INT Set_HtMcs_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ULONG HtMcs, Mcs_tmp; -#ifdef CONFIG_STA_SUPPORT - BOOLEAN bAutoRate = FALSE; -#endif // CONFIG_STA_SUPPORT // - - Mcs_tmp = simple_strtol(arg, 0, 10); - - if (Mcs_tmp <= 15 || Mcs_tmp == 32) - HtMcs = Mcs_tmp; - else - HtMcs = MCS_AUTO; - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - pAd->StaCfg.DesiredTransmitSetting.field.MCS = HtMcs; - pAd->StaCfg.bAutoTxRateSwitch = (HtMcs == MCS_AUTO) ? TRUE:FALSE; - DBGPRINT(RT_DEBUG_TRACE, ("Set_HtMcs_Proc::(HtMcs=%d, bAutoTxRateSwitch = %d)\n", - pAd->StaCfg.DesiredTransmitSetting.field.MCS, pAd->StaCfg.bAutoTxRateSwitch)); - - if ((pAd->CommonCfg.PhyMode < PHY_11ABGN_MIXED) || - (pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MODE < MODE_HTMIX)) - { - if ((pAd->StaCfg.DesiredTransmitSetting.field.MCS != MCS_AUTO) && - (HtMcs >= 0 && HtMcs <= 3) && - (pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode == FIXED_TXMODE_CCK)) - { - RTMPSetDesiredRates(pAd, (LONG) (RateIdToMbps[HtMcs] * 1000000)); - } - else if ((pAd->StaCfg.DesiredTransmitSetting.field.MCS != MCS_AUTO) && - (HtMcs >= 0 && HtMcs <= 7) && - (pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode == FIXED_TXMODE_OFDM)) - { - RTMPSetDesiredRates(pAd, (LONG) (RateIdToMbps[HtMcs+4] * 1000000)); - } - else - bAutoRate = TRUE; - - if (bAutoRate) - { - pAd->StaCfg.DesiredTransmitSetting.field.MCS = MCS_AUTO; - RTMPSetDesiredRates(pAd, -1); - } - DBGPRINT(RT_DEBUG_TRACE, ("Set_HtMcs_Proc::(FixedTxMode=%d)\n",pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode)); - } - if (ADHOC_ON(pAd)) - return TRUE; - } -#endif // CONFIG_STA_SUPPORT // - - SetCommonHT(pAd); - - return TRUE; -} - -INT Set_HtGi_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ULONG HtGi; - - HtGi = simple_strtol(arg, 0, 10); - - if ( HtGi == GI_400) - pAd->CommonCfg.RegTransmitSetting.field.ShortGI = GI_400; - else if ( HtGi == GI_800 ) - pAd->CommonCfg.RegTransmitSetting.field.ShortGI = GI_800; - else - return FALSE; //Invalid argument - - SetCommonHT(pAd); - - DBGPRINT(RT_DEBUG_TRACE, ("Set_HtGi_Proc::(ShortGI=%d)\n",pAd->CommonCfg.RegTransmitSetting.field.ShortGI)); - - return TRUE; -} - - -INT Set_HtTxBASize_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - UCHAR Size; - - Size = simple_strtol(arg, 0, 10); - - if (Size <=0 || Size >=64) - { - Size = 8; - } - pAd->CommonCfg.TxBASize = Size-1; - DBGPRINT(RT_DEBUG_ERROR, ("Set_HtTxBASize ::(TxBASize= %d)\n", Size)); - - return TRUE; -} - - -INT Set_HtOpMode_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - - ULONG Value; - - Value = simple_strtol(arg, 0, 10); - - if (Value == HTMODE_GF) - pAd->CommonCfg.RegTransmitSetting.field.HTMODE = HTMODE_GF; - else if ( Value == HTMODE_MM ) - pAd->CommonCfg.RegTransmitSetting.field.HTMODE = HTMODE_MM; - else - return FALSE; //Invalid argument - - SetCommonHT(pAd); - - DBGPRINT(RT_DEBUG_TRACE, ("Set_HtOpMode_Proc::(HtOpMode=%d)\n",pAd->CommonCfg.RegTransmitSetting.field.HTMODE)); - - return TRUE; - -} - -INT Set_HtStbc_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - - ULONG Value; - - Value = simple_strtol(arg, 0, 10); - - if (Value == STBC_USE) - pAd->CommonCfg.RegTransmitSetting.field.STBC = STBC_USE; - else if ( Value == STBC_NONE ) - pAd->CommonCfg.RegTransmitSetting.field.STBC = STBC_NONE; - else - return FALSE; //Invalid argument - - SetCommonHT(pAd); - - DBGPRINT(RT_DEBUG_TRACE, ("Set_Stbc_Proc::(HtStbc=%d)\n",pAd->CommonCfg.RegTransmitSetting.field.STBC)); - - return TRUE; -} - -INT Set_HtHtc_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - - ULONG Value; - - Value = simple_strtol(arg, 0, 10); - if (Value == 0) - pAd->HTCEnable = FALSE; - else if ( Value ==1 ) - pAd->HTCEnable = TRUE; - else - return FALSE; //Invalid argument - - DBGPRINT(RT_DEBUG_TRACE, ("Set_HtHtc_Proc::(HtHtc=%d)\n",pAd->HTCEnable)); - - return TRUE; -} - -INT Set_HtExtcha_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - - ULONG Value; - - Value = simple_strtol(arg, 0, 10); - - if (Value == 0) - pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_BELOW; - else if ( Value ==1 ) - pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_ABOVE; - else - return FALSE; //Invalid argument - - SetCommonHT(pAd); - - DBGPRINT(RT_DEBUG_TRACE, ("Set_HtExtcha_Proc::(HtExtcha=%d)\n",pAd->CommonCfg.RegTransmitSetting.field.EXTCHA)); - - return TRUE; -} - -INT Set_HtMpduDensity_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ULONG Value; - - Value = simple_strtol(arg, 0, 10); - - if (Value <=7 && Value >= 0) - pAd->CommonCfg.BACapability.field.MpduDensity = Value; - else - pAd->CommonCfg.BACapability.field.MpduDensity = 4; - - SetCommonHT(pAd); - - DBGPRINT(RT_DEBUG_TRACE, ("Set_HtMpduDensity_Proc::(HtMpduDensity=%d)\n",pAd->CommonCfg.BACapability.field.MpduDensity)); - - return TRUE; -} - -INT Set_HtBaWinSize_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ULONG Value; - - Value = simple_strtol(arg, 0, 10); - - - if (Value >=1 && Value <= 64) - { - pAd->CommonCfg.REGBACapability.field.RxBAWinLimit = Value; - pAd->CommonCfg.BACapability.field.RxBAWinLimit = Value; - } - else - { - pAd->CommonCfg.REGBACapability.field.RxBAWinLimit = 64; - pAd->CommonCfg.BACapability.field.RxBAWinLimit = 64; - } - - SetCommonHT(pAd); - - DBGPRINT(RT_DEBUG_TRACE, ("Set_HtBaWinSize_Proc::(HtBaWinSize=%d)\n",pAd->CommonCfg.BACapability.field.RxBAWinLimit)); - - return TRUE; -} - -INT Set_HtRdg_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ULONG Value; - - Value = simple_strtol(arg, 0, 10); - - if (Value == 0) - pAd->CommonCfg.bRdg = FALSE; - else if ( Value ==1 ) - { - pAd->HTCEnable = TRUE; - pAd->CommonCfg.bRdg = TRUE; - } - else - return FALSE; //Invalid argument - - SetCommonHT(pAd); - - DBGPRINT(RT_DEBUG_TRACE, ("Set_HtRdg_Proc::(HtRdg=%d)\n",pAd->CommonCfg.bRdg)); - - return TRUE; -} - -INT Set_HtLinkAdapt_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ULONG Value; - - Value = simple_strtol(arg, 0, 10); - if (Value == 0) - pAd->bLinkAdapt = FALSE; - else if ( Value ==1 ) - { - pAd->HTCEnable = TRUE; - pAd->bLinkAdapt = TRUE; - } - else - return FALSE; //Invalid argument - - DBGPRINT(RT_DEBUG_TRACE, ("Set_HtLinkAdapt_Proc::(HtLinkAdapt=%d)\n",pAd->bLinkAdapt)); - - return TRUE; -} - -INT Set_HtAmsdu_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ULONG Value; - - Value = simple_strtol(arg, 0, 10); - if (Value == 0) - pAd->CommonCfg.BACapability.field.AmsduEnable = FALSE; - else if ( Value == 1 ) - pAd->CommonCfg.BACapability.field.AmsduEnable = TRUE; - else - return FALSE; //Invalid argument - - SetCommonHT(pAd); - - DBGPRINT(RT_DEBUG_TRACE, ("Set_HtAmsdu_Proc::(HtAmsdu=%d)\n",pAd->CommonCfg.BACapability.field.AmsduEnable)); - - return TRUE; -} - -INT Set_HtAutoBa_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ULONG Value; - - Value = simple_strtol(arg, 0, 10); - if (Value == 0) - { - pAd->CommonCfg.BACapability.field.AutoBA = FALSE; - pAd->CommonCfg.BACapability.field.Policy = BA_NOTUSE; - } - else if (Value == 1) - { - pAd->CommonCfg.BACapability.field.AutoBA = TRUE; - pAd->CommonCfg.BACapability.field.Policy = IMMED_BA; - } - else - return FALSE; //Invalid argument - - pAd->CommonCfg.REGBACapability.field.AutoBA = pAd->CommonCfg.BACapability.field.AutoBA; - pAd->CommonCfg.REGBACapability.field.Policy = pAd->CommonCfg.BACapability.field.Policy; - SetCommonHT(pAd); - - DBGPRINT(RT_DEBUG_TRACE, ("Set_HtAutoBa_Proc::(HtAutoBa=%d)\n",pAd->CommonCfg.BACapability.field.AutoBA)); - - return TRUE; - -} - -INT Set_HtProtect_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ULONG Value; - - Value = simple_strtol(arg, 0, 10); - if (Value == 0) - pAd->CommonCfg.bHTProtect = FALSE; - else if (Value == 1) - pAd->CommonCfg.bHTProtect = TRUE; - else - return FALSE; //Invalid argument - - DBGPRINT(RT_DEBUG_TRACE, ("Set_HtProtect_Proc::(HtProtect=%d)\n",pAd->CommonCfg.bHTProtect)); - - return TRUE; -} - -INT Set_SendPSMPAction_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - UCHAR mac[6], mode; - char *token, sepValue[] = ":", DASH = '-'; - INT i; - MAC_TABLE_ENTRY *pEntry; - - //printk("\n%s\n", arg); -/* - The BARecTearDown inupt string format should be xx:xx:xx:xx:xx:xx-d, - =>The six 2 digit hex-decimal number previous are the Mac address, - =>The seventh decimal number is the mode value. -*/ - if(strlen(arg) < 19) //Mac address acceptable format 01:02:03:04:05:06 length 17 plus the "-" and mode value in decimal format. - return FALSE; - - token = strchr(arg, DASH); - if ((token != NULL) && (strlen(token)>1)) - { - mode = simple_strtol((token+1), 0, 10); - if (mode > MMPS_ENABLE) - return FALSE; - - *token = '\0'; - for (i = 0, token = rstrtok(arg, &sepValue[0]); token; token = rstrtok(NULL, &sepValue[0]), i++) - { - if((strlen(token) != 2) || (!isxdigit(*token)) || (!isxdigit(*(token+1)))) - return FALSE; - AtoH(token, (PUCHAR)(&mac[i]), 1); - } - if(i != 6) - return FALSE; - - printk("\n%02x:%02x:%02x:%02x:%02x:%02x-%02x", mac[0], mac[1], - mac[2], mac[3], mac[4], mac[5], mode); - - pEntry = MacTableLookup(pAd, mac); - - if (pEntry) { - printk("\nSendPSMPAction MIPS mode = %d\n", mode); - SendPSMPAction(pAd, pEntry->Aid, mode); - } - - return TRUE; - } - - return FALSE; - - -} - -INT Set_HtMIMOPSmode_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ULONG Value; - - Value = simple_strtol(arg, 0, 10); - - if (Value <=3 && Value >= 0) - pAd->CommonCfg.BACapability.field.MMPSmode = Value; - else - pAd->CommonCfg.BACapability.field.MMPSmode = 3; - - SetCommonHT(pAd); - - DBGPRINT(RT_DEBUG_TRACE, ("Set_HtMIMOPSmode_Proc::(MIMOPS mode=%d)\n",pAd->CommonCfg.BACapability.field.MMPSmode)); - - return TRUE; -} - - -INT Set_ForceShortGI_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ULONG Value; - - Value = simple_strtol(arg, 0, 10); - if (Value == 0) - pAd->WIFItestbed.bShortGI = FALSE; - else if (Value == 1) - pAd->WIFItestbed.bShortGI = TRUE; - else - return FALSE; //Invalid argument - - SetCommonHT(pAd); - - DBGPRINT(RT_DEBUG_TRACE, ("Set_ForceShortGI_Proc::(ForceShortGI=%d)\n", pAd->WIFItestbed.bShortGI)); - - return TRUE; -} - - - -INT Set_ForceGF_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ULONG Value; - - Value = simple_strtol(arg, 0, 10); - if (Value == 0) - pAd->WIFItestbed.bGreenField = FALSE; - else if (Value == 1) - pAd->WIFItestbed.bGreenField = TRUE; - else - return FALSE; //Invalid argument - - SetCommonHT(pAd); - - DBGPRINT(RT_DEBUG_TRACE, ("Set_ForceGF_Proc::(ForceGF=%d)\n", pAd->WIFItestbed.bGreenField)); - - return TRUE; -} - -INT Set_HtMimoPs_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ULONG Value; - - Value = simple_strtol(arg, 0, 10); - if (Value == 0) - pAd->CommonCfg.bMIMOPSEnable = FALSE; - else if (Value == 1) - pAd->CommonCfg.bMIMOPSEnable = TRUE; - else - return FALSE; //Invalid argument - - DBGPRINT(RT_DEBUG_TRACE, ("Set_HtMimoPs_Proc::(HtMimoPs=%d)\n",pAd->CommonCfg.bMIMOPSEnable)); - - return TRUE; -} -#endif // DOT11_N_SUPPORT // - - -#ifdef DOT11_N_SUPPORT -INT SetCommonHT( - IN PRTMP_ADAPTER pAd) -{ - OID_SET_HT_PHYMODE SetHT; - - if (pAd->CommonCfg.PhyMode < PHY_11ABGN_MIXED) - return FALSE; - - SetHT.PhyMode = pAd->CommonCfg.PhyMode; - SetHT.TransmitNo = ((UCHAR)pAd->Antenna.field.TxPath); - SetHT.HtMode = (UCHAR)pAd->CommonCfg.RegTransmitSetting.field.HTMODE; - SetHT.ExtOffset = (UCHAR)pAd->CommonCfg.RegTransmitSetting.field.EXTCHA; - SetHT.MCS = MCS_AUTO; - SetHT.BW = (UCHAR)pAd->CommonCfg.RegTransmitSetting.field.BW; - SetHT.STBC = (UCHAR)pAd->CommonCfg.RegTransmitSetting.field.STBC; - SetHT.SHORTGI = (UCHAR)pAd->CommonCfg.RegTransmitSetting.field.ShortGI; - - RTMPSetHT(pAd, &SetHT); - - return TRUE; -} -#endif // DOT11_N_SUPPORT // - -INT Set_FixedTxMode_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - UCHAR fix_tx_mode = FIXED_TXMODE_HT; - - if (strcmp(arg, "OFDM") == 0 || strcmp(arg, "ofdm") == 0) - { - fix_tx_mode = FIXED_TXMODE_OFDM; - } - else if (strcmp(arg, "CCK") == 0 || strcmp(arg, "cck") == 0) - { - fix_tx_mode = FIXED_TXMODE_CCK; - } - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode = fix_tx_mode; -#endif // CONFIG_STA_SUPPORT // - - DBGPRINT(RT_DEBUG_TRACE, ("Set_FixedTxMode_Proc::(FixedTxMode=%d)\n", fix_tx_mode)); - - return TRUE; -} - -#ifdef CONFIG_APSTA_MIXED_SUPPORT -INT Set_OpMode_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ULONG Value; - - Value = simple_strtol(arg, 0, 10); - -#ifdef RT2870 - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_START_UP)) -#endif // RT2870 // - { - DBGPRINT(RT_DEBUG_ERROR, ("Can not switch operate mode on interface up !! \n")); - return FALSE; - } - - if (Value == 0) - pAd->OpMode = OPMODE_STA; - else if (Value == 1) - pAd->OpMode = OPMODE_AP; - else - return FALSE; //Invalid argument - - DBGPRINT(RT_DEBUG_TRACE, ("Set_OpMode_Proc::(OpMode=%s)\n", pAd->OpMode == 1 ? "AP Mode" : "STA Mode")); - - return TRUE; -} -#endif // CONFIG_APSTA_MIXED_SUPPORT // - - -///////////////////////////////////////////////////////////////////////// -PCHAR RTMPGetRalinkAuthModeStr( - IN NDIS_802_11_AUTHENTICATION_MODE authMode) -{ - switch(authMode) - { - case Ndis802_11AuthModeOpen: - return "OPEN"; - default: - case Ndis802_11AuthModeWPAPSK: - return "WPAPSK"; - case Ndis802_11AuthModeShared: - return "SHARED"; - case Ndis802_11AuthModeWPA: - return "WPA"; - case Ndis802_11AuthModeWPA2: - return "WPA2"; - case Ndis802_11AuthModeWPA2PSK: - return "WPA2PSK"; - case Ndis802_11AuthModeWPA1PSKWPA2PSK: - return "WPAPSKWPA2PSK"; - case Ndis802_11AuthModeWPA1WPA2: - return "WPA1WPA2"; - } -} - -PCHAR RTMPGetRalinkEncryModeStr( - IN USHORT encryMode) -{ - switch(encryMode) - { - default: - case Ndis802_11WEPDisabled: - return "NONE"; - case Ndis802_11WEPEnabled: - return "WEP"; - case Ndis802_11Encryption2Enabled: - return "TKIP"; - case Ndis802_11Encryption3Enabled: - return "AES"; - case Ndis802_11Encryption4Enabled: - return "TKIPAES"; - } -} - -INT RTMPShowCfgValue( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pName, - IN PUCHAR pBuf) -{ - INT Status = 0; - - for (PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC = RTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC; PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC->name; PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC++) - { - if (!strcmp(pName, PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC->name)) - { - if(PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC->show_proc(pAd, pBuf)) - Status = -EINVAL; - break; //Exit for loop. - } - } - - if(PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC->name == NULL) - { - sprintf(pBuf, "\n"); - for (PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC = RTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC; PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC->name; PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC++) - sprintf(pBuf, "%s%s\n", pBuf, PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC->name); - } - - return Status; -} - -INT Show_SSID_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - sprintf(pBuf, "\t%s", pAd->CommonCfg.Ssid); -#endif // CONFIG_STA_SUPPORT // - return 0; -} - -INT Show_WirelessMode_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - switch(pAd->CommonCfg.PhyMode) - { - case PHY_11BG_MIXED: - sprintf(pBuf, "\t11B/G"); - break; - case PHY_11B: - sprintf(pBuf, "\t11B"); - break; - case PHY_11A: - sprintf(pBuf, "\t11A"); - break; - case PHY_11ABG_MIXED: - sprintf(pBuf, "\t11A/B/G"); - break; - case PHY_11G: - sprintf(pBuf, "\t11G"); - break; -#ifdef DOT11_N_SUPPORT - case PHY_11ABGN_MIXED: - sprintf(pBuf, "\t11A/B/G/N"); - break; - case PHY_11N_2_4G: - sprintf(pBuf, "\t11N only with 2.4G"); - break; - case PHY_11GN_MIXED: - sprintf(pBuf, "\t11G/N"); - break; - case PHY_11AN_MIXED: - sprintf(pBuf, "\t11A/N"); - break; - case PHY_11BGN_MIXED: - sprintf(pBuf, "\t11B/G/N"); - break; - case PHY_11AGN_MIXED: - sprintf(pBuf, "\t11A/G/N"); - break; - case PHY_11N_5G: - sprintf(pBuf, "\t11N only with 5G"); - break; -#endif // DOT11_N_SUPPORT // - default: - sprintf(pBuf, "\tUnknow Value(%d)", pAd->CommonCfg.PhyMode); - break; - } - return 0; -} - - -INT Show_TxBurst_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - sprintf(pBuf, "\t%s", pAd->CommonCfg.bEnableTxBurst ? "TRUE":"FALSE"); - return 0; -} - -INT Show_TxPreamble_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - switch(pAd->CommonCfg.TxPreamble) - { - case Rt802_11PreambleShort: - sprintf(pBuf, "\tShort"); - break; - case Rt802_11PreambleLong: - sprintf(pBuf, "\tLong"); - break; - case Rt802_11PreambleAuto: - sprintf(pBuf, "\tAuto"); - break; - default: - sprintf(pBuf, "\tUnknow Value(%lu)", pAd->CommonCfg.TxPreamble); - break; - } - - return 0; -} - -INT Show_TxPower_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - sprintf(pBuf, "\t%lu", pAd->CommonCfg.TxPowerPercentage); - return 0; -} - -INT Show_Channel_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - sprintf(pBuf, "\t%d", pAd->CommonCfg.Channel); - return 0; -} - -INT Show_BGProtection_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - switch(pAd->CommonCfg.UseBGProtection) - { - case 1: //Always On - sprintf(pBuf, "\tON"); - break; - case 2: //Always OFF - sprintf(pBuf, "\tOFF"); - break; - case 0: //AUTO - sprintf(pBuf, "\tAuto"); - break; - default: - sprintf(pBuf, "\tUnknow Value(%lu)", pAd->CommonCfg.UseBGProtection); - break; - } - return 0; -} - -INT Show_RTSThreshold_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - sprintf(pBuf, "\t%u", pAd->CommonCfg.RtsThreshold); - return 0; -} - -INT Show_FragThreshold_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - sprintf(pBuf, "\t%u", pAd->CommonCfg.FragmentThreshold); - return 0; -} - -#ifdef DOT11_N_SUPPORT -INT Show_HtBw_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - if (pAd->CommonCfg.RegTransmitSetting.field.BW == BW_40) - { - sprintf(pBuf, "\t40 MHz"); - } - else - { - sprintf(pBuf, "\t20 MHz"); - } - return 0; -} - -INT Show_HtMcs_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - sprintf(pBuf, "\t%u", pAd->StaCfg.DesiredTransmitSetting.field.MCS); -#endif // CONFIG_STA_SUPPORT // - return 0; -} - -INT Show_HtGi_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - switch(pAd->CommonCfg.RegTransmitSetting.field.ShortGI) - { - case GI_400: - sprintf(pBuf, "\tGI_400"); - break; - case GI_800: - sprintf(pBuf, "\tGI_800"); - break; - default: - sprintf(pBuf, "\tUnknow Value(%u)", pAd->CommonCfg.RegTransmitSetting.field.ShortGI); - break; - } - return 0; -} - -INT Show_HtOpMode_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - switch(pAd->CommonCfg.RegTransmitSetting.field.HTMODE) - { - case HTMODE_GF: - sprintf(pBuf, "\tGF"); - break; - case HTMODE_MM: - sprintf(pBuf, "\tMM"); - break; - default: - sprintf(pBuf, "\tUnknow Value(%u)", pAd->CommonCfg.RegTransmitSetting.field.HTMODE); - break; - } - return 0; -} - -INT Show_HtExtcha_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - switch(pAd->CommonCfg.RegTransmitSetting.field.EXTCHA) - { - case EXTCHA_BELOW: - sprintf(pBuf, "\tBelow"); - break; - case EXTCHA_ABOVE: - sprintf(pBuf, "\tAbove"); - break; - default: - sprintf(pBuf, "\tUnknow Value(%u)", pAd->CommonCfg.RegTransmitSetting.field.EXTCHA); - break; - } - return 0; -} - - -INT Show_HtMpduDensity_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - sprintf(pBuf, "\t%u", pAd->CommonCfg.BACapability.field.MpduDensity); - return 0; -} - -INT Show_HtBaWinSize_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - sprintf(pBuf, "\t%u", pAd->CommonCfg.BACapability.field.RxBAWinLimit); - return 0; -} - -INT Show_HtRdg_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - sprintf(pBuf, "\t%s", pAd->CommonCfg.bRdg ? "TRUE":"FALSE"); - return 0; -} - -INT Show_HtAmsdu_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - sprintf(pBuf, "\t%s", pAd->CommonCfg.BACapability.field.AmsduEnable ? "TRUE":"FALSE"); - return 0; -} - -INT Show_HtAutoBa_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - sprintf(pBuf, "\t%s", pAd->CommonCfg.BACapability.field.AutoBA ? "TRUE":"FALSE"); - return 0; -} -#endif // DOT11_N_SUPPORT // - -INT Show_CountryRegion_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - sprintf(pBuf, "\t%d", pAd->CommonCfg.CountryRegion); - return 0; -} - -INT Show_CountryRegionABand_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - sprintf(pBuf, "\t%d", pAd->CommonCfg.CountryRegionForABand); - return 0; -} - -INT Show_CountryCode_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - sprintf(pBuf, "\t%s", pAd->CommonCfg.CountryCode); - return 0; -} - -#ifdef AGGREGATION_SUPPORT -INT Show_PktAggregate_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - sprintf(pBuf, "\t%s", pAd->CommonCfg.bAggregationCapable ? "TRUE":"FALSE"); - return 0; -} -#endif // AGGREGATION_SUPPORT // - -#ifdef WMM_SUPPORT -INT Show_WmmCapable_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - sprintf(pBuf, "\t%s", pAd->CommonCfg.bWmmCapable ? "TRUE":"FALSE"); -#endif // CONFIG_STA_SUPPORT // - - return 0; -} -#endif // WMM_SUPPORT // - -INT Show_IEEE80211H_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - sprintf(pBuf, "\t%s", pAd->CommonCfg.bIEEE80211H ? "TRUE":"FALSE"); - return 0; -} - -#ifdef CONFIG_STA_SUPPORT -INT Show_NetworkType_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - switch(pAd->StaCfg.BssType) - { - case BSS_ADHOC: - sprintf(pBuf, "\tAdhoc"); - break; - case BSS_INFRA: - sprintf(pBuf, "\tInfra"); - break; - case BSS_ANY: - sprintf(pBuf, "\tAny"); - break; - case BSS_MONITOR: - sprintf(pBuf, "\tMonitor"); - break; - default: - sprintf(pBuf, "\tUnknow Value(%d)", pAd->StaCfg.BssType); - break; - } - return 0; -} -#endif // CONFIG_STA_SUPPORT // - -INT Show_AuthMode_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - NDIS_802_11_AUTHENTICATION_MODE AuthMode = Ndis802_11AuthModeOpen; - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - AuthMode = pAd->StaCfg.AuthMode; -#endif // CONFIG_STA_SUPPORT // - - if ((AuthMode >= Ndis802_11AuthModeOpen) && - (AuthMode <= Ndis802_11AuthModeWPA1PSKWPA2PSK)) - sprintf(pBuf, "\t%s", RTMPGetRalinkAuthModeStr(AuthMode)); - else - sprintf(pBuf, "\tUnknow Value(%d)", AuthMode); - - return 0; -} - -INT Show_EncrypType_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - NDIS_802_11_WEP_STATUS WepStatus = Ndis802_11WEPDisabled; - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - WepStatus = pAd->StaCfg.WepStatus; -#endif // CONFIG_STA_SUPPORT // - - if ((WepStatus >= Ndis802_11WEPEnabled) && - (WepStatus <= Ndis802_11Encryption4KeyAbsent)) - sprintf(pBuf, "\t%s", RTMPGetRalinkEncryModeStr(WepStatus)); - else - sprintf(pBuf, "\tUnknow Value(%d)", WepStatus); - - return 0; -} - -INT Show_DefaultKeyID_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - UCHAR DefaultKeyId = 0; - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - DefaultKeyId = pAd->StaCfg.DefaultKeyId; -#endif // CONFIG_STA_SUPPORT // - - sprintf(pBuf, "\t%d", DefaultKeyId); - - return 0; -} - -INT Show_WepKey_Proc( - IN PRTMP_ADAPTER pAd, - IN INT KeyIdx, - OUT PUCHAR pBuf) -{ - UCHAR Key[16] = {0}, KeyLength = 0; - INT index = BSS0; - - KeyLength = pAd->SharedKey[index][KeyIdx].KeyLen; - NdisMoveMemory(Key, pAd->SharedKey[index][KeyIdx].Key, KeyLength); - - //check key string is ASCII or not - if (RTMPCheckStrPrintAble(Key, KeyLength)) - sprintf(pBuf, "\t%s", Key); - else - { - int idx; - sprintf(pBuf, "\t"); - for (idx = 0; idx < KeyLength; idx++) - sprintf(pBuf+strlen(pBuf), "%02X", Key[idx]); - } - return 0; -} - -INT Show_Key1_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - Show_WepKey_Proc(pAd, 0, pBuf); - return 0; -} - -INT Show_Key2_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - Show_WepKey_Proc(pAd, 1, pBuf); - return 0; -} - -INT Show_Key3_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - Show_WepKey_Proc(pAd, 2, pBuf); - return 0; -} - -INT Show_Key4_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - Show_WepKey_Proc(pAd, 3, pBuf); - return 0; -} - -INT Show_WPAPSK_Proc( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pBuf) -{ - INT idx; - UCHAR PMK[32] = {0}; - - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - NdisMoveMemory(PMK, pAd->StaCfg.PMK, 32); -#endif // CONFIG_STA_SUPPORT // - - sprintf(pBuf, "\tPMK = "); - for (idx = 0; idx < 32; idx++) - sprintf(pBuf+strlen(pBuf), "%02X", PMK[idx]); - - return 0; -} - +#include "../../rt2870/common/cmm_info.c" diff --git a/drivers/staging/rt3070/common/cmm_sanity.c b/drivers/staging/rt3070/common/cmm_sanity.c index 6118df8de7bb..82ccf9e85f32 100644 --- a/drivers/staging/rt3070/common/cmm_sanity.c +++ b/drivers/staging/rt3070/common/cmm_sanity.c @@ -1,1669 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - sanity.c - - Abstract: - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - John Chang 2004-09-01 add WMM support -*/ -#include "../rt_config.h" - - -extern UCHAR CISCO_OUI[]; - -extern UCHAR WPA_OUI[]; -extern UCHAR RSN_OUI[]; -extern UCHAR WME_INFO_ELEM[]; -extern UCHAR WME_PARM_ELEM[]; -extern UCHAR Ccx2QosInfo[]; -extern UCHAR RALINK_OUI[]; -extern UCHAR BROADCOM_OUI[]; -extern UCHAR WPS_OUI[]; - -/* - ========================================================================== - Description: - MLME message sanity check - Return: - TRUE if all parameters are OK, FALSE otherwise - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -BOOLEAN MlmeAddBAReqSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PUCHAR pAddr2) -{ - PMLME_ADDBA_REQ_STRUCT pInfo; - - pInfo = (MLME_ADDBA_REQ_STRUCT *)Msg; - - if ((MsgLen != sizeof(MLME_ADDBA_REQ_STRUCT))) - { - DBGPRINT(RT_DEBUG_TRACE, ("MlmeAddBAReqSanity fail - message lenght not correct.\n")); - return FALSE; - } - - if ((pInfo->Wcid >= MAX_LEN_OF_MAC_TABLE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("MlmeAddBAReqSanity fail - The peer Mac is not associated yet.\n")); - return FALSE; - } - - /* - if ((pInfo->BaBufSize > MAX_RX_REORDERBUF) || (pInfo->BaBufSize < 2)) - { - DBGPRINT(RT_DEBUG_TRACE, ("MlmeAddBAReqSanity fail - Rx Reordering buffer too big or too small\n")); - return FALSE; - } - */ - - if ((pInfo->pAddr[0]&0x01) == 0x01) - { - DBGPRINT(RT_DEBUG_TRACE, ("MlmeAddBAReqSanity fail - broadcast address not support BA\n")); - return FALSE; - } - - return TRUE; -} - -/* - ========================================================================== - Description: - MLME message sanity check - Return: - TRUE if all parameters are OK, FALSE otherwise - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -BOOLEAN MlmeDelBAReqSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen) -{ - MLME_DELBA_REQ_STRUCT *pInfo; - pInfo = (MLME_DELBA_REQ_STRUCT *)Msg; - - if ((MsgLen != sizeof(MLME_DELBA_REQ_STRUCT))) - { - DBGPRINT(RT_DEBUG_ERROR, ("MlmeDelBAReqSanity fail - message lenght not correct.\n")); - return FALSE; - } - - if ((pInfo->Wcid >= MAX_LEN_OF_MAC_TABLE)) - { - DBGPRINT(RT_DEBUG_ERROR, ("MlmeDelBAReqSanity fail - The peer Mac is not associated yet.\n")); - return FALSE; - } - - if ((pInfo->TID & 0xf0)) - { - DBGPRINT(RT_DEBUG_ERROR, ("MlmeDelBAReqSanity fail - The peer TID is incorrect.\n")); - return FALSE; - } - - if (NdisEqualMemory(pAd->MacTab.Content[pInfo->Wcid].Addr, pInfo->Addr, MAC_ADDR_LEN) == 0) - { - DBGPRINT(RT_DEBUG_ERROR, ("MlmeDelBAReqSanity fail - the peer addr dosen't exist.\n")); - return FALSE; - } - - return TRUE; -} - -BOOLEAN PeerAddBAReqActionSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *pMsg, - IN ULONG MsgLen, - OUT PUCHAR pAddr2) -{ - PFRAME_802_11 pFrame = (PFRAME_802_11)pMsg; - PFRAME_ADDBA_REQ pAddFrame; - pAddFrame = (PFRAME_ADDBA_REQ)(pMsg); - if (MsgLen < (sizeof(FRAME_ADDBA_REQ))) - { - DBGPRINT(RT_DEBUG_ERROR,("PeerAddBAReqActionSanity: ADDBA Request frame length size = %ld incorrect\n", MsgLen)); - return FALSE; - } - // we support immediate BA. - *(USHORT *)(&pAddFrame->BaParm) = cpu2le16(*(USHORT *)(&pAddFrame->BaParm)); - pAddFrame->TimeOutValue = cpu2le16(pAddFrame->TimeOutValue); - pAddFrame->BaStartSeq.word = cpu2le16(pAddFrame->BaStartSeq.word); - - if (pAddFrame->BaParm.BAPolicy != IMMED_BA) - { - DBGPRINT(RT_DEBUG_ERROR,("PeerAddBAReqActionSanity: ADDBA Request Ba Policy[%d] not support\n", pAddFrame->BaParm.BAPolicy)); - DBGPRINT(RT_DEBUG_ERROR,("ADDBA Request. tid=%x, Bufsize=%x, AMSDUSupported=%x \n", pAddFrame->BaParm.TID, pAddFrame->BaParm.BufSize, pAddFrame->BaParm.AMSDUSupported)); - return FALSE; - } - - // we support immediate BA. - if (pAddFrame->BaParm.TID &0xfff0) - { - DBGPRINT(RT_DEBUG_ERROR,("PeerAddBAReqActionSanity: ADDBA Request incorrect TID = %d\n", pAddFrame->BaParm.TID)); - return FALSE; - } - COPY_MAC_ADDR(pAddr2, pFrame->Hdr.Addr2); - return TRUE; -} - -BOOLEAN PeerAddBARspActionSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *pMsg, - IN ULONG MsgLen) -{ - //PFRAME_802_11 pFrame = (PFRAME_802_11)pMsg; - PFRAME_ADDBA_RSP pAddFrame; - - pAddFrame = (PFRAME_ADDBA_RSP)(pMsg); - if (MsgLen < (sizeof(FRAME_ADDBA_RSP))) - { - DBGPRINT(RT_DEBUG_ERROR,("PeerAddBARspActionSanity: ADDBA Response frame length size = %ld incorrect\n", MsgLen)); - return FALSE; - } - // we support immediate BA. - *(USHORT *)(&pAddFrame->BaParm) = cpu2le16(*(USHORT *)(&pAddFrame->BaParm)); - pAddFrame->StatusCode = cpu2le16(pAddFrame->StatusCode); - pAddFrame->TimeOutValue = cpu2le16(pAddFrame->TimeOutValue); - - if (pAddFrame->BaParm.BAPolicy != IMMED_BA) - { - DBGPRINT(RT_DEBUG_ERROR,("PeerAddBAReqActionSanity: ADDBA Response Ba Policy[%d] not support\n", pAddFrame->BaParm.BAPolicy)); - return FALSE; - } - - // we support immediate BA. - if (pAddFrame->BaParm.TID &0xfff0) - { - DBGPRINT(RT_DEBUG_ERROR,("PeerAddBARspActionSanity: ADDBA Response incorrect TID = %d\n", pAddFrame->BaParm.TID)); - return FALSE; - } - return TRUE; - -} - -BOOLEAN PeerDelBAActionSanity( - IN PRTMP_ADAPTER pAd, - IN UCHAR Wcid, - IN VOID *pMsg, - IN ULONG MsgLen ) -{ - //PFRAME_802_11 pFrame = (PFRAME_802_11)pMsg; - PFRAME_DELBA_REQ pDelFrame; - if (MsgLen != (sizeof(FRAME_DELBA_REQ))) - return FALSE; - - if (Wcid >= MAX_LEN_OF_MAC_TABLE) - return FALSE; - - pDelFrame = (PFRAME_DELBA_REQ)(pMsg); - - *(USHORT *)(&pDelFrame->DelbaParm) = cpu2le16(*(USHORT *)(&pDelFrame->DelbaParm)); - pDelFrame->ReasonCode = cpu2le16(pDelFrame->ReasonCode); - - if (pDelFrame->DelbaParm.TID &0xfff0) - return FALSE; - - return TRUE; -} - -/* - ========================================================================== - Description: - MLME message sanity check - Return: - TRUE if all parameters are OK, FALSE otherwise - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -BOOLEAN PeerBeaconAndProbeRspSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - IN UCHAR MsgChannel, - OUT PUCHAR pAddr2, - OUT PUCHAR pBssid, - OUT CHAR Ssid[], - OUT UCHAR *pSsidLen, - OUT UCHAR *pBssType, - OUT USHORT *pBeaconPeriod, - OUT UCHAR *pChannel, - OUT UCHAR *pNewChannel, - OUT LARGE_INTEGER *pTimestamp, - OUT CF_PARM *pCfParm, - OUT USHORT *pAtimWin, - OUT USHORT *pCapabilityInfo, - OUT UCHAR *pErp, - OUT UCHAR *pDtimCount, - OUT UCHAR *pDtimPeriod, - OUT UCHAR *pBcastFlag, - OUT UCHAR *pMessageToMe, - OUT UCHAR SupRate[], - OUT UCHAR *pSupRateLen, - OUT UCHAR ExtRate[], - OUT UCHAR *pExtRateLen, - OUT UCHAR *pCkipFlag, - OUT UCHAR *pAironetCellPowerLimit, - OUT PEDCA_PARM pEdcaParm, - OUT PQBSS_LOAD_PARM pQbssLoad, - OUT PQOS_CAPABILITY_PARM pQosCapability, - OUT ULONG *pRalinkIe, - OUT UCHAR *pHtCapabilityLen, -#ifdef CONFIG_STA_SUPPORT - OUT UCHAR *pPreNHtCapabilityLen, -#endif // CONFIG_STA_SUPPORT // - OUT HT_CAPABILITY_IE *pHtCapability, - OUT UCHAR *AddHtInfoLen, - OUT ADD_HT_INFO_IE *AddHtInfo, - OUT UCHAR *NewExtChannelOffset, // Ht extension channel offset(above or below) - OUT USHORT *LengthVIE, - OUT PNDIS_802_11_VARIABLE_IEs pVIE) -{ - CHAR *Ptr; -#ifdef CONFIG_STA_SUPPORT - CHAR TimLen; -#endif // CONFIG_STA_SUPPORT // - PFRAME_802_11 pFrame; - PEID_STRUCT pEid; - UCHAR SubType; - UCHAR Sanity; - //UCHAR ECWMin, ECWMax; - //MAC_CSR9_STRUC Csr9; - ULONG Length = 0; - - // For some 11a AP which didn't have DS_IE, we use two conditions to decide the channel - // 1. If the AP is 11n enabled, then check the control channel. - // 2. If the AP didn't have any info about channel, use the channel we received this frame as the channel. (May inaccuracy!!) - UCHAR CtrlChannel = 0; - - // Add for 3 necessary EID field check - Sanity = 0; - - *pAtimWin = 0; - *pErp = 0; - *pDtimCount = 0; - *pDtimPeriod = 0; - *pBcastFlag = 0; - *pMessageToMe = 0; - *pExtRateLen = 0; - *pCkipFlag = 0; // Default of CkipFlag is 0 - *pAironetCellPowerLimit = 0xFF; // Default of AironetCellPowerLimit is 0xFF - *LengthVIE = 0; // Set the length of VIE to init value 0 - *pHtCapabilityLen = 0; // Set the length of VIE to init value 0 -#ifdef CONFIG_STA_SUPPORT - if (pAd->OpMode == OPMODE_STA) - *pPreNHtCapabilityLen = 0; // Set the length of VIE to init value 0 -#endif // CONFIG_STA_SUPPORT // - *AddHtInfoLen = 0; // Set the length of VIE to init value 0 - *pRalinkIe = 0; - *pNewChannel = 0; - *NewExtChannelOffset = 0xff; //Default 0xff means no such IE - pCfParm->bValid = FALSE; // default: no IE_CF found - pQbssLoad->bValid = FALSE; // default: no IE_QBSS_LOAD found - pEdcaParm->bValid = FALSE; // default: no IE_EDCA_PARAMETER found - pQosCapability->bValid = FALSE; // default: no IE_QOS_CAPABILITY found - - pFrame = (PFRAME_802_11)Msg; - - // get subtype from header - SubType = (UCHAR)pFrame->Hdr.FC.SubType; - - // get Addr2 and BSSID from header - COPY_MAC_ADDR(pAddr2, pFrame->Hdr.Addr2); - COPY_MAC_ADDR(pBssid, pFrame->Hdr.Addr3); - -// hex_dump("Beacon", Msg, MsgLen); - - Ptr = pFrame->Octet; - Length += LENGTH_802_11; - - // get timestamp from payload and advance the pointer - NdisMoveMemory(pTimestamp, Ptr, TIMESTAMP_LEN); - - pTimestamp->u.LowPart = cpu2le32(pTimestamp->u.LowPart); - pTimestamp->u.HighPart = cpu2le32(pTimestamp->u.HighPart); - - Ptr += TIMESTAMP_LEN; - Length += TIMESTAMP_LEN; - - // get beacon interval from payload and advance the pointer - NdisMoveMemory(pBeaconPeriod, Ptr, 2); - Ptr += 2; - Length += 2; - - // get capability info from payload and advance the pointer - NdisMoveMemory(pCapabilityInfo, Ptr, 2); - Ptr += 2; - Length += 2; - - if (CAP_IS_ESS_ON(*pCapabilityInfo)) - *pBssType = BSS_INFRA; - else - *pBssType = BSS_ADHOC; - - pEid = (PEID_STRUCT) Ptr; - - // get variable fields from payload and advance the pointer - while ((Length + 2 + pEid->Len) <= MsgLen) - { - // - // Secure copy VIE to VarIE[MAX_VIE_LEN] didn't overflow. - // - if ((*LengthVIE + pEid->Len + 2) >= MAX_VIE_LEN) - { - DBGPRINT(RT_DEBUG_WARN, ("PeerBeaconAndProbeRspSanity - Variable IEs out of resource [len(=%d) > MAX_VIE_LEN(=%d)]\n", - (*LengthVIE + pEid->Len + 2), MAX_VIE_LEN)); - break; - } - - switch(pEid->Eid) - { - case IE_SSID: - // Already has one SSID EID in this beacon, ignore the second one - if (Sanity & 0x1) - break; - if(pEid->Len <= MAX_LEN_OF_SSID) - { - NdisMoveMemory(Ssid, pEid->Octet, pEid->Len); - *pSsidLen = pEid->Len; - Sanity |= 0x1; - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("PeerBeaconAndProbeRspSanity - wrong IE_SSID (len=%d)\n",pEid->Len)); - return FALSE; - } - break; - - case IE_SUPP_RATES: - if(pEid->Len <= MAX_LEN_OF_SUPPORTED_RATES) - { - Sanity |= 0x2; - NdisMoveMemory(SupRate, pEid->Octet, pEid->Len); - *pSupRateLen = pEid->Len; - - // TODO: 2004-09-14 not a good design here, cause it exclude extra rates - // from ScanTab. We should report as is. And filter out unsupported - // rates in MlmeAux. - // Check against the supported rates - // RTMPCheckRates(pAd, SupRate, pSupRateLen); - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("PeerBeaconAndProbeRspSanity - wrong IE_SUPP_RATES (len=%d)\n",pEid->Len)); - return FALSE; - } - break; - - case IE_HT_CAP: - if (pEid->Len >= SIZE_HT_CAP_IE) //Note: allow extension.!! - { - NdisMoveMemory(pHtCapability, pEid->Octet, sizeof(HT_CAPABILITY_IE)); - *pHtCapabilityLen = SIZE_HT_CAP_IE; // Nnow we only support 26 bytes. - - *(USHORT *)(&pHtCapability->HtCapInfo) = cpu2le16(*(USHORT *)(&pHtCapability->HtCapInfo)); - *(USHORT *)(&pHtCapability->ExtHtCapInfo) = cpu2le16(*(USHORT *)(&pHtCapability->ExtHtCapInfo)); - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - *pPreNHtCapabilityLen = 0; // Nnow we only support 26 bytes. - - Ptr = (PUCHAR) pVIE; - NdisMoveMemory(Ptr + *LengthVIE, &pEid->Eid, pEid->Len + 2); - *LengthVIE += (pEid->Len + 2); - } -#endif // CONFIG_STA_SUPPORT // - } - else - { - DBGPRINT(RT_DEBUG_WARN, ("PeerBeaconAndProbeRspSanity - wrong IE_HT_CAP. pEid->Len = %d\n", pEid->Len)); - } - - break; - case IE_ADD_HT: - if (pEid->Len >= sizeof(ADD_HT_INFO_IE)) - { - // This IE allows extension, but we can ignore extra bytes beyond our knowledge , so only - // copy first sizeof(ADD_HT_INFO_IE) - NdisMoveMemory(AddHtInfo, pEid->Octet, sizeof(ADD_HT_INFO_IE)); - *AddHtInfoLen = SIZE_ADD_HT_INFO_IE; - - CtrlChannel = AddHtInfo->ControlChan; - - *(USHORT *)(&AddHtInfo->AddHtInfo2) = cpu2le16(*(USHORT *)(&AddHtInfo->AddHtInfo2)); - *(USHORT *)(&AddHtInfo->AddHtInfo3) = cpu2le16(*(USHORT *)(&AddHtInfo->AddHtInfo3)); - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - Ptr = (PUCHAR) pVIE; - NdisMoveMemory(Ptr + *LengthVIE, &pEid->Eid, pEid->Len + 2); - *LengthVIE += (pEid->Len + 2); - } -#endif // CONFIG_STA_SUPPORT // - } - else - { - DBGPRINT(RT_DEBUG_WARN, ("PeerBeaconAndProbeRspSanity - wrong IE_ADD_HT. \n")); - } - - break; - case IE_SECONDARY_CH_OFFSET: - if (pEid->Len == 1) - { - *NewExtChannelOffset = pEid->Octet[0]; - } - else - { - DBGPRINT(RT_DEBUG_WARN, ("PeerBeaconAndProbeRspSanity - wrong IE_SECONDARY_CH_OFFSET. \n")); - } - - break; - case IE_FH_PARM: - DBGPRINT(RT_DEBUG_TRACE, ("PeerBeaconAndProbeRspSanity(IE_FH_PARM) \n")); - break; - - case IE_DS_PARM: - if(pEid->Len == 1) - { - *pChannel = *pEid->Octet; -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - if (ChannelSanity(pAd, *pChannel) == 0) - { - - return FALSE; - } - } -#endif // CONFIG_STA_SUPPORT // - Sanity |= 0x4; - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("PeerBeaconAndProbeRspSanity - wrong IE_DS_PARM (len=%d)\n",pEid->Len)); - return FALSE; - } - break; - - case IE_CF_PARM: - if(pEid->Len == 6) - { - pCfParm->bValid = TRUE; - pCfParm->CfpCount = pEid->Octet[0]; - pCfParm->CfpPeriod = pEid->Octet[1]; - pCfParm->CfpMaxDuration = pEid->Octet[2] + 256 * pEid->Octet[3]; - pCfParm->CfpDurRemaining = pEid->Octet[4] + 256 * pEid->Octet[5]; - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("PeerBeaconAndProbeRspSanity - wrong IE_CF_PARM\n")); - return FALSE; - } - break; - - case IE_IBSS_PARM: - if(pEid->Len == 2) - { - NdisMoveMemory(pAtimWin, pEid->Octet, pEid->Len); - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("PeerBeaconAndProbeRspSanity - wrong IE_IBSS_PARM\n")); - return FALSE; - } - break; - -#ifdef CONFIG_STA_SUPPORT - case IE_TIM: - if(INFRA_ON(pAd) && SubType == SUBTYPE_BEACON) - { - GetTimBit((PUCHAR)pEid, pAd->StaActive.Aid, &TimLen, pBcastFlag, pDtimCount, pDtimPeriod, pMessageToMe); - } - break; -#endif // CONFIG_STA_SUPPORT // - case IE_CHANNEL_SWITCH_ANNOUNCEMENT: - if(pEid->Len == 3) - { - *pNewChannel = pEid->Octet[1]; //extract new channel number - } - break; - - // New for WPA - // CCX v2 has the same IE, we need to parse that too - // Wifi WMM use the same IE vale, need to parse that too - // case IE_WPA: - case IE_VENDOR_SPECIFIC: - // Check Broadcom/Atheros 802.11n OUI version, for HT Capability IE. - // This HT IE is before IEEE draft set HT IE value.2006-09-28 by Jan. - /*if (NdisEqualMemory(pEid->Octet, BROADCOM_OUI, 3) && (pEid->Len >= 4)) - { - if ((pEid->Octet[3] == OUI_BROADCOM_HT) && (pEid->Len >= 30)) - { - { - NdisMoveMemory(pHtCapability, &pEid->Octet[4], sizeof(HT_CAPABILITY_IE)); - *pHtCapabilityLen = SIZE_HT_CAP_IE; // Nnow we only support 26 bytes. - } - } - if ((pEid->Octet[3] == OUI_BROADCOM_HT) && (pEid->Len >= 26)) - { - { - NdisMoveMemory(AddHtInfo, &pEid->Octet[4], sizeof(ADD_HT_INFO_IE)); - *AddHtInfoLen = SIZE_ADD_HT_INFO_IE; // Nnow we only support 26 bytes. - } - } - } - */ - // Check the OUI version, filter out non-standard usage - if (NdisEqualMemory(pEid->Octet, RALINK_OUI, 3) && (pEid->Len == 7)) - { - //*pRalinkIe = pEid->Octet[3]; - if (pEid->Octet[3] != 0) - *pRalinkIe = pEid->Octet[3]; - else - *pRalinkIe = 0xf0000000; // Set to non-zero value (can't set bit0-2) to represent this is Ralink Chip. So at linkup, we will set ralinkchip flag. - } -#ifdef CONFIG_STA_SUPPORT -#ifdef DOT11_N_SUPPORT - // This HT IE is before IEEE draft set HT IE value.2006-09-28 by Jan. - - // Other vendors had production before IE_HT_CAP value is assigned. To backward support those old-firmware AP, - // Check broadcom-defiend pre-802.11nD1.0 OUI for HT related IE, including HT Capatilities IE and HT Information IE - else if ((*pHtCapabilityLen == 0) && NdisEqualMemory(pEid->Octet, PRE_N_HT_OUI, 3) && (pEid->Len >= 4) && (pAd->OpMode == OPMODE_STA)) - { - if ((pEid->Octet[3] == OUI_PREN_HT_CAP) && (pEid->Len >= 30) && (*pHtCapabilityLen == 0)) - { - NdisMoveMemory(pHtCapability, &pEid->Octet[4], sizeof(HT_CAPABILITY_IE)); - *pPreNHtCapabilityLen = SIZE_HT_CAP_IE; - } - - if ((pEid->Octet[3] == OUI_PREN_ADD_HT) && (pEid->Len >= 26)) - { - NdisMoveMemory(AddHtInfo, &pEid->Octet[4], sizeof(ADD_HT_INFO_IE)); - *AddHtInfoLen = SIZE_ADD_HT_INFO_IE; - } - } -#endif // DOT11_N_SUPPORT // -#endif // CONFIG_STA_SUPPORT // - else if (NdisEqualMemory(pEid->Octet, WPA_OUI, 4)) - { - // Copy to pVIE which will report to microsoft bssid list. - Ptr = (PUCHAR) pVIE; - NdisMoveMemory(Ptr + *LengthVIE, &pEid->Eid, pEid->Len + 2); - *LengthVIE += (pEid->Len + 2); - } - else if (NdisEqualMemory(pEid->Octet, WME_PARM_ELEM, 6) && (pEid->Len == 24)) - { - PUCHAR ptr; - int i; - - // parsing EDCA parameters - pEdcaParm->bValid = TRUE; - pEdcaParm->bQAck = FALSE; // pEid->Octet[0] & 0x10; - pEdcaParm->bQueueRequest = FALSE; // pEid->Octet[0] & 0x20; - pEdcaParm->bTxopRequest = FALSE; // pEid->Octet[0] & 0x40; - pEdcaParm->EdcaUpdateCount = pEid->Octet[6] & 0x0f; - pEdcaParm->bAPSDCapable = (pEid->Octet[6] & 0x80) ? 1 : 0; - ptr = &pEid->Octet[8]; - for (i=0; i<4; i++) - { - UCHAR aci = (*ptr & 0x60) >> 5; // b5~6 is AC INDEX - pEdcaParm->bACM[aci] = (((*ptr) & 0x10) == 0x10); // b5 is ACM - pEdcaParm->Aifsn[aci] = (*ptr) & 0x0f; // b0~3 is AIFSN - pEdcaParm->Cwmin[aci] = *(ptr+1) & 0x0f; // b0~4 is Cwmin - pEdcaParm->Cwmax[aci] = *(ptr+1) >> 4; // b5~8 is Cwmax - pEdcaParm->Txop[aci] = *(ptr+2) + 256 * (*(ptr+3)); // in unit of 32-us - ptr += 4; // point to next AC - } - } - else if (NdisEqualMemory(pEid->Octet, WME_INFO_ELEM, 6) && (pEid->Len == 7)) - { - // parsing EDCA parameters - pEdcaParm->bValid = TRUE; - pEdcaParm->bQAck = FALSE; // pEid->Octet[0] & 0x10; - pEdcaParm->bQueueRequest = FALSE; // pEid->Octet[0] & 0x20; - pEdcaParm->bTxopRequest = FALSE; // pEid->Octet[0] & 0x40; - pEdcaParm->EdcaUpdateCount = pEid->Octet[6] & 0x0f; - pEdcaParm->bAPSDCapable = (pEid->Octet[6] & 0x80) ? 1 : 0; - - // use default EDCA parameter - pEdcaParm->bACM[QID_AC_BE] = 0; - pEdcaParm->Aifsn[QID_AC_BE] = 3; - pEdcaParm->Cwmin[QID_AC_BE] = CW_MIN_IN_BITS; - pEdcaParm->Cwmax[QID_AC_BE] = CW_MAX_IN_BITS; - pEdcaParm->Txop[QID_AC_BE] = 0; - - pEdcaParm->bACM[QID_AC_BK] = 0; - pEdcaParm->Aifsn[QID_AC_BK] = 7; - pEdcaParm->Cwmin[QID_AC_BK] = CW_MIN_IN_BITS; - pEdcaParm->Cwmax[QID_AC_BK] = CW_MAX_IN_BITS; - pEdcaParm->Txop[QID_AC_BK] = 0; - - pEdcaParm->bACM[QID_AC_VI] = 0; - pEdcaParm->Aifsn[QID_AC_VI] = 2; - pEdcaParm->Cwmin[QID_AC_VI] = CW_MIN_IN_BITS-1; - pEdcaParm->Cwmax[QID_AC_VI] = CW_MAX_IN_BITS; - pEdcaParm->Txop[QID_AC_VI] = 96; // AC_VI: 96*32us ~= 3ms - - pEdcaParm->bACM[QID_AC_VO] = 0; - pEdcaParm->Aifsn[QID_AC_VO] = 2; - pEdcaParm->Cwmin[QID_AC_VO] = CW_MIN_IN_BITS-2; - pEdcaParm->Cwmax[QID_AC_VO] = CW_MAX_IN_BITS-1; - pEdcaParm->Txop[QID_AC_VO] = 48; // AC_VO: 48*32us ~= 1.5ms - } -#ifdef CONFIG_STA_SUPPORT -#endif // CONFIG_STA_SUPPORT // - else - { - } - - break; - - case IE_EXT_SUPP_RATES: - if (pEid->Len <= MAX_LEN_OF_SUPPORTED_RATES) - { - NdisMoveMemory(ExtRate, pEid->Octet, pEid->Len); - *pExtRateLen = pEid->Len; - - // TODO: 2004-09-14 not a good design here, cause it exclude extra rates - // from ScanTab. We should report as is. And filter out unsupported - // rates in MlmeAux. - // Check against the supported rates - // RTMPCheckRates(pAd, ExtRate, pExtRateLen); - } - break; - - case IE_ERP: - if (pEid->Len == 1) - { - *pErp = (UCHAR)pEid->Octet[0]; - } - break; - - case IE_AIRONET_CKIP: - // 0. Check Aironet IE length, it must be larger or equal to 28 - // Cisco AP350 used length as 28 - // Cisco AP12XX used length as 30 - if (pEid->Len < (CKIP_NEGOTIATION_LENGTH - 2)) - break; - - // 1. Copy CKIP flag byte to buffer for process - *pCkipFlag = *(pEid->Octet + 8); - break; - - case IE_AP_TX_POWER: - // AP Control of Client Transmit Power - //0. Check Aironet IE length, it must be 6 - if (pEid->Len != 0x06) - break; - - // Get cell power limit in dBm - if (NdisEqualMemory(pEid->Octet, CISCO_OUI, 3) == 1) - *pAironetCellPowerLimit = *(pEid->Octet + 4); - break; - - // WPA2 & 802.11i RSN - case IE_RSN: - // There is no OUI for version anymore, check the group cipher OUI before copying - if (RTMPEqualMemory(pEid->Octet + 2, RSN_OUI, 3)) - { - // Copy to pVIE which will report to microsoft bssid list. - Ptr = (PUCHAR) pVIE; - NdisMoveMemory(Ptr + *LengthVIE, &pEid->Eid, pEid->Len + 2); - *LengthVIE += (pEid->Len + 2); - } - break; -#ifdef CONFIG_STA_SUPPORT -#ifdef EXT_BUILD_CHANNEL_LIST - case IE_COUNTRY: - Ptr = (PUCHAR) pVIE; - NdisMoveMemory(Ptr + *LengthVIE, &pEid->Eid, pEid->Len + 2); - *LengthVIE += (pEid->Len + 2); - break; -#endif // EXT_BUILD_CHANNEL_LIST // -#endif // CONFIG_STA_SUPPORT // - default: - break; - } - - Length = Length + 2 + pEid->Len; // Eid[1] + Len[1]+ content[Len] - pEid = (PEID_STRUCT)((UCHAR*)pEid + 2 + pEid->Len); - } - - // For some 11a AP. it did not have the channel EID, patch here -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - UCHAR LatchRfChannel = MsgChannel; - if ((pAd->LatchRfRegs.Channel > 14) && ((Sanity & 0x4) == 0)) - { - if (CtrlChannel != 0) - *pChannel = CtrlChannel; - else - *pChannel = LatchRfChannel; - Sanity |= 0x4; - } - } -#endif // CONFIG_STA_SUPPORT // - - if (Sanity != 0x7) - { - DBGPRINT(RT_DEBUG_WARN, ("PeerBeaconAndProbeRspSanity - missing field, Sanity=0x%02x\n", Sanity)); - return FALSE; - } - else - { - return TRUE; - } - -} - -#ifdef DOT11N_DRAFT3 -/* - ========================================================================== - Description: - MLME message sanity check for some IE addressed in 802.11n d3.03. - Return: - TRUE if all parameters are OK, FALSE otherwise - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -BOOLEAN PeerBeaconAndProbeRspSanity2( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT UCHAR *RegClass) -{ - CHAR *Ptr; - PFRAME_802_11 pFrame; - PEID_STRUCT pEid; - ULONG Length = 0; - - pFrame = (PFRAME_802_11)Msg; - - *RegClass = 0; - Ptr = pFrame->Octet; - Length += LENGTH_802_11; - - // get timestamp from payload and advance the pointer - Ptr += TIMESTAMP_LEN; - Length += TIMESTAMP_LEN; - - // get beacon interval from payload and advance the pointer - Ptr += 2; - Length += 2; - - // get capability info from payload and advance the pointer - Ptr += 2; - Length += 2; - - pEid = (PEID_STRUCT) Ptr; - - // get variable fields from payload and advance the pointer - while ((Length + 2 + pEid->Len) <= MsgLen) - { - switch(pEid->Eid) - { - case IE_SUPP_REG_CLASS: - if(pEid->Len > 0) - { - *RegClass = *pEid->Octet; - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("PeerBeaconAndProbeRspSanity - wrong IE_SSID (len=%d)\n",pEid->Len)); - return FALSE; - } - break; - } - - Length = Length + 2 + pEid->Len; // Eid[1] + Len[1]+ content[Len] - pEid = (PEID_STRUCT)((UCHAR*)pEid + 2 + pEid->Len); - } - - return TRUE; - -} -#endif // DOT11N_DRAFT3 // - -/* - ========================================================================== - Description: - MLME message sanity check - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== - */ -BOOLEAN MlmeScanReqSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT UCHAR *pBssType, - OUT CHAR Ssid[], - OUT UCHAR *pSsidLen, - OUT UCHAR *pScanType) -{ - MLME_SCAN_REQ_STRUCT *Info; - - Info = (MLME_SCAN_REQ_STRUCT *)(Msg); - *pBssType = Info->BssType; - *pSsidLen = Info->SsidLen; - NdisMoveMemory(Ssid, Info->Ssid, *pSsidLen); - *pScanType = Info->ScanType; - - if ((*pBssType == BSS_INFRA || *pBssType == BSS_ADHOC || *pBssType == BSS_ANY) - && (*pScanType == SCAN_ACTIVE || *pScanType == SCAN_PASSIVE -#ifdef CONFIG_STA_SUPPORT - || *pScanType == SCAN_CISCO_PASSIVE || *pScanType == SCAN_CISCO_ACTIVE - || *pScanType == SCAN_CISCO_CHANNEL_LOAD || *pScanType == SCAN_CISCO_NOISE -#endif // CONFIG_STA_SUPPORT // - )) - { - return TRUE; - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("MlmeScanReqSanity fail - wrong BssType or ScanType\n")); - return FALSE; - } -} - -// IRQL = DISPATCH_LEVEL -UCHAR ChannelSanity( - IN PRTMP_ADAPTER pAd, - IN UCHAR channel) -{ - int i; - - for (i = 0; i < pAd->ChannelListNum; i ++) - { - if (channel == pAd->ChannelList[i].Channel) - return 1; - } - return 0; -} - -/* - ========================================================================== - Description: - MLME message sanity check - Return: - TRUE if all parameters are OK, FALSE otherwise - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -BOOLEAN PeerDeauthSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PUCHAR pAddr2, - OUT USHORT *pReason) -{ - PFRAME_802_11 pFrame = (PFRAME_802_11)Msg; - - COPY_MAC_ADDR(pAddr2, pFrame->Hdr.Addr2); - NdisMoveMemory(pReason, &pFrame->Octet[0], 2); - - return TRUE; -} - -/* - ========================================================================== - Description: - MLME message sanity check - Return: - TRUE if all parameters are OK, FALSE otherwise - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -BOOLEAN PeerAuthSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PUCHAR pAddr, - OUT USHORT *pAlg, - OUT USHORT *pSeq, - OUT USHORT *pStatus, - CHAR *pChlgText) -{ - PFRAME_802_11 pFrame = (PFRAME_802_11)Msg; - - COPY_MAC_ADDR(pAddr, pFrame->Hdr.Addr2); - NdisMoveMemory(pAlg, &pFrame->Octet[0], 2); - NdisMoveMemory(pSeq, &pFrame->Octet[2], 2); - NdisMoveMemory(pStatus, &pFrame->Octet[4], 2); - - if ((*pAlg == Ndis802_11AuthModeOpen) -#ifdef LEAP_SUPPORT - || (*pAlg == CISCO_AuthModeLEAP) -#endif // LEAP_SUPPORT // - ) - { - if (*pSeq == 1 || *pSeq == 2) - { - return TRUE; - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("PeerAuthSanity fail - wrong Seg#\n")); - return FALSE; - } - } - else if (*pAlg == Ndis802_11AuthModeShared) - { - if (*pSeq == 1 || *pSeq == 4) - { - return TRUE; - } - else if (*pSeq == 2 || *pSeq == 3) - { - NdisMoveMemory(pChlgText, &pFrame->Octet[8], CIPHER_TEXT_LEN); - return TRUE; - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("PeerAuthSanity fail - wrong Seg#\n")); - return FALSE; - } - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("PeerAuthSanity fail - wrong algorithm\n")); - return FALSE; - } -} - -/* - ========================================================================== - Description: - MLME message sanity check - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== - */ -BOOLEAN MlmeAuthReqSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PUCHAR pAddr, - OUT ULONG *pTimeout, - OUT USHORT *pAlg) -{ - MLME_AUTH_REQ_STRUCT *pInfo; - - pInfo = (MLME_AUTH_REQ_STRUCT *)Msg; - COPY_MAC_ADDR(pAddr, pInfo->Addr); - *pTimeout = pInfo->Timeout; - *pAlg = pInfo->Alg; - - if (((*pAlg == Ndis802_11AuthModeShared) ||(*pAlg == Ndis802_11AuthModeOpen) -#ifdef LEAP_SUPPORT - || (*pAlg == CISCO_AuthModeLEAP) -#endif // LEAP_SUPPORT // - ) && - ((*pAddr & 0x01) == 0)) - { - return TRUE; - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("MlmeAuthReqSanity fail - wrong algorithm\n")); - return FALSE; - } -} - -/* - ========================================================================== - Description: - MLME message sanity check - Return: - TRUE if all parameters are OK, FALSE otherwise - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -BOOLEAN MlmeAssocReqSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PUCHAR pApAddr, - OUT USHORT *pCapabilityInfo, - OUT ULONG *pTimeout, - OUT USHORT *pListenIntv) -{ - MLME_ASSOC_REQ_STRUCT *pInfo; - - pInfo = (MLME_ASSOC_REQ_STRUCT *)Msg; - *pTimeout = pInfo->Timeout; // timeout - COPY_MAC_ADDR(pApAddr, pInfo->Addr); // AP address - *pCapabilityInfo = pInfo->CapabilityInfo; // capability info - *pListenIntv = pInfo->ListenIntv; - - return TRUE; -} - -/* - ========================================================================== - Description: - MLME message sanity check - Return: - TRUE if all parameters are OK, FALSE otherwise - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -BOOLEAN PeerDisassocSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PUCHAR pAddr2, - OUT USHORT *pReason) -{ - PFRAME_802_11 pFrame = (PFRAME_802_11)Msg; - - COPY_MAC_ADDR(pAddr2, pFrame->Hdr.Addr2); - NdisMoveMemory(pReason, &pFrame->Octet[0], 2); - - return TRUE; -} - -/* - ======================================================================== - Routine Description: - Sanity check NetworkType (11b, 11g or 11a) - - Arguments: - pBss - Pointer to BSS table. - - Return Value: - Ndis802_11DS .......(11b) - Ndis802_11OFDM24....(11g) - Ndis802_11OFDM5.....(11a) - - IRQL = DISPATCH_LEVEL - - ======================================================================== -*/ -NDIS_802_11_NETWORK_TYPE NetworkTypeInUseSanity( - IN PBSS_ENTRY pBss) -{ - NDIS_802_11_NETWORK_TYPE NetWorkType; - UCHAR rate, i; - - NetWorkType = Ndis802_11DS; - - if (pBss->Channel <= 14) - { - // - // First check support Rate. - // - for (i = 0; i < pBss->SupRateLen; i++) - { - rate = pBss->SupRate[i] & 0x7f; // Mask out basic rate set bit - if ((rate == 2) || (rate == 4) || (rate == 11) || (rate == 22)) - { - continue; - } - else - { - // - // Otherwise (even rate > 108) means Ndis802_11OFDM24 - // - NetWorkType = Ndis802_11OFDM24; - break; - } - } - - // - // Second check Extend Rate. - // - if (NetWorkType != Ndis802_11OFDM24) - { - for (i = 0; i < pBss->ExtRateLen; i++) - { - rate = pBss->SupRate[i] & 0x7f; // Mask out basic rate set bit - if ((rate == 2) || (rate == 4) || (rate == 11) || (rate == 22)) - { - continue; - } - else - { - // - // Otherwise (even rate > 108) means Ndis802_11OFDM24 - // - NetWorkType = Ndis802_11OFDM24; - break; - } - } - } - } - else - { - NetWorkType = Ndis802_11OFDM5; - } - - if (pBss->HtCapabilityLen != 0) - { - if (NetWorkType == Ndis802_11OFDM5) - NetWorkType = Ndis802_11OFDM5_N; - else - NetWorkType = Ndis802_11OFDM24_N; - } - - return NetWorkType; -} - -/* - ========================================================================== - Description: - WPA message sanity check - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== - */ -BOOLEAN PeerWpaMessageSanity( - IN PRTMP_ADAPTER pAd, - IN PEAPOL_PACKET pMsg, - IN ULONG MsgLen, - IN UCHAR MsgType, - IN MAC_TABLE_ENTRY *pEntry) -{ - UCHAR mic[LEN_KEY_DESC_MIC], digest[80], KEYDATA[MAX_LEN_OF_RSNIE]; - BOOLEAN bReplayDiff = FALSE; - BOOLEAN bWPA2 = FALSE; - KEY_INFO EapolKeyInfo; - UCHAR GroupKeyIndex = 0; - - - NdisZeroMemory(mic, sizeof(mic)); - NdisZeroMemory(digest, sizeof(digest)); - NdisZeroMemory(KEYDATA, sizeof(KEYDATA)); - NdisZeroMemory((PUCHAR)&EapolKeyInfo, sizeof(EapolKeyInfo)); - - NdisMoveMemory((PUCHAR)&EapolKeyInfo, (PUCHAR)&pMsg->KeyDesc.KeyInfo, sizeof(KEY_INFO)); - - *((USHORT *)&EapolKeyInfo) = cpu2le16(*((USHORT *)&EapolKeyInfo)); - - // Choose WPA2 or not - if ((pEntry->AuthMode == Ndis802_11AuthModeWPA2) || (pEntry->AuthMode == Ndis802_11AuthModeWPA2PSK)) - bWPA2 = TRUE; - - // 0. Check MsgType - if ((MsgType > EAPOL_GROUP_MSG_2) || (MsgType < EAPOL_PAIR_MSG_1)) - { - DBGPRINT(RT_DEBUG_ERROR, ("The message type is invalid(%d)! \n", MsgType)); - return FALSE; - } - - // 1. Replay counter check - if (MsgType == EAPOL_PAIR_MSG_1 || MsgType == EAPOL_PAIR_MSG_3 || MsgType == EAPOL_GROUP_MSG_1) // For supplicant - { - // First validate replay counter, only accept message with larger replay counter. - // Let equal pass, some AP start with all zero replay counter - UCHAR ZeroReplay[LEN_KEY_DESC_REPLAY]; - - NdisZeroMemory(ZeroReplay, LEN_KEY_DESC_REPLAY); - if ((RTMPCompareMemory(pMsg->KeyDesc.ReplayCounter, pEntry->R_Counter, LEN_KEY_DESC_REPLAY) != 1) && - (RTMPCompareMemory(pMsg->KeyDesc.ReplayCounter, ZeroReplay, LEN_KEY_DESC_REPLAY) != 0)) - { - bReplayDiff = TRUE; - } - } - else if (MsgType == EAPOL_PAIR_MSG_2 || MsgType == EAPOL_PAIR_MSG_4 || MsgType == EAPOL_GROUP_MSG_2) // For authenticator - { - // check Replay Counter coresponds to MSG from authenticator, otherwise discard - if (!NdisEqualMemory(pMsg->KeyDesc.ReplayCounter, pEntry->R_Counter, LEN_KEY_DESC_REPLAY)) - { - bReplayDiff = TRUE; - } - } - - // Replay Counter different condition - if (bReplayDiff) - { - // send wireless event - for replay counter different - if (pAd->CommonCfg.bWirelessEvent) - RTMPSendWirelessEvent(pAd, IW_REPLAY_COUNTER_DIFF_EVENT_FLAG, pEntry->Addr, pEntry->apidx, 0); - - if (MsgType < EAPOL_GROUP_MSG_1) - { - DBGPRINT(RT_DEBUG_ERROR, ("Replay Counter Different in pairwise msg %d of 4-way handshake!\n", MsgType)); - } - else - { - DBGPRINT(RT_DEBUG_ERROR, ("Replay Counter Different in group msg %d of 2-way handshake!\n", (MsgType - EAPOL_PAIR_MSG_4))); - } - - hex_dump("Receive replay counter ", pMsg->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); - hex_dump("Current replay counter ", pEntry->R_Counter, LEN_KEY_DESC_REPLAY); - return FALSE; - } - - // 2. Verify MIC except Pairwise Msg1 - if (MsgType != EAPOL_PAIR_MSG_1) - { - UCHAR rcvd_mic[LEN_KEY_DESC_MIC]; - - // Record the received MIC for check later - NdisMoveMemory(rcvd_mic, pMsg->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); - NdisZeroMemory(pMsg->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); - - if (pEntry->WepStatus == Ndis802_11Encryption2Enabled) // TKIP - { - hmac_md5(pEntry->PTK, LEN_EAP_MICK, (PUCHAR)pMsg, MsgLen, mic); - } - else if (pEntry->WepStatus == Ndis802_11Encryption3Enabled) // AES - { - HMAC_SHA1((PUCHAR)pMsg, MsgLen, pEntry->PTK, LEN_EAP_MICK, digest); - NdisMoveMemory(mic, digest, LEN_KEY_DESC_MIC); - } - - if (!NdisEqualMemory(rcvd_mic, mic, LEN_KEY_DESC_MIC)) - { - // send wireless event - for MIC different - if (pAd->CommonCfg.bWirelessEvent) - RTMPSendWirelessEvent(pAd, IW_MIC_DIFF_EVENT_FLAG, pEntry->Addr, pEntry->apidx, 0); - - if (MsgType < EAPOL_GROUP_MSG_1) - { - DBGPRINT(RT_DEBUG_ERROR, ("MIC Different in pairwise msg %d of 4-way handshake!\n", MsgType)); - } - else - { - DBGPRINT(RT_DEBUG_ERROR, ("MIC Different in group msg %d of 2-way handshake!\n", (MsgType - EAPOL_PAIR_MSG_4))); - } - - hex_dump("Received MIC", rcvd_mic, LEN_KEY_DESC_MIC); - hex_dump("Desired MIC", mic, LEN_KEY_DESC_MIC); - - return FALSE; - } - } - - // Extract the context of the Key Data field if it exist - // The field in pairwise_msg_2_WPA1(WPA2) & pairwise_msg_3_WPA1 is un-encrypted. - // The field in group_msg_1_WPA1(WPA2) & pairwise_msg_3_WPA2 is encrypted. - if (pMsg->KeyDesc.KeyDataLen[1] > 0) - { - // Decrypt this field - if ((MsgType == EAPOL_PAIR_MSG_3 && bWPA2) || (MsgType == EAPOL_GROUP_MSG_1)) - { - if(pEntry->WepStatus == Ndis802_11Encryption3Enabled) - { - // AES - AES_GTK_KEY_UNWRAP(&pEntry->PTK[16], KEYDATA, pMsg->KeyDesc.KeyDataLen[1],pMsg->KeyDesc.KeyData); - } - else - { - INT i; - UCHAR Key[32]; - // Decrypt TKIP GTK - // Construct 32 bytes RC4 Key - NdisMoveMemory(Key, pMsg->KeyDesc.KeyIv, 16); - NdisMoveMemory(&Key[16], &pEntry->PTK[16], 16); - ARCFOUR_INIT(&pAd->PrivateInfo.WEPCONTEXT, Key, 32); - //discard first 256 bytes - for(i = 0; i < 256; i++) - ARCFOUR_BYTE(&pAd->PrivateInfo.WEPCONTEXT); - // Decrypt GTK. Becareful, there is no ICV to check the result is correct or not - ARCFOUR_DECRYPT(&pAd->PrivateInfo.WEPCONTEXT, KEYDATA, pMsg->KeyDesc.KeyData, pMsg->KeyDesc.KeyDataLen[1]); - } - - if (!bWPA2 && (MsgType == EAPOL_GROUP_MSG_1)) - GroupKeyIndex = EapolKeyInfo.KeyIndex; - - } - else if ((MsgType == EAPOL_PAIR_MSG_2) || (MsgType == EAPOL_PAIR_MSG_3 && !bWPA2)) - { - NdisMoveMemory(KEYDATA, pMsg->KeyDesc.KeyData, pMsg->KeyDesc.KeyDataLen[1]); - } - else - { - - return TRUE; - } - - // Parse Key Data field to - // 1. verify RSN IE for pairwise_msg_2_WPA1(WPA2) ,pairwise_msg_3_WPA1(WPA2) - // 2. verify KDE format for pairwise_msg_3_WPA2, group_msg_1_WPA2 - // 3. update shared key for pairwise_msg_3_WPA2, group_msg_1_WPA1(WPA2) - if (!RTMPParseEapolKeyData(pAd, KEYDATA, pMsg->KeyDesc.KeyDataLen[1], GroupKeyIndex, MsgType, bWPA2, pEntry)) - { - return FALSE; - } - } - - return TRUE; - -} - -#ifdef CONFIG_STA_SUPPORT -#ifdef QOS_DLS_SUPPORT -BOOLEAN MlmeDlsReqSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PRT_802_11_DLS *pDLS, - OUT PUSHORT pReason) -{ - MLME_DLS_REQ_STRUCT *pInfo; - - pInfo = (MLME_DLS_REQ_STRUCT *)Msg; - - *pDLS = pInfo->pDLS; - *pReason = pInfo->Reason; - - return TRUE; -} -#endif // QOS_DLS_SUPPORT // -#endif // CONFIG_STA_SUPPORT // - -#ifdef QOS_DLS_SUPPORT -BOOLEAN PeerDlsReqSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PUCHAR pDA, - OUT PUCHAR pSA, - OUT USHORT *pCapabilityInfo, - OUT USHORT *pDlsTimeout, - OUT UCHAR *pRatesLen, - OUT UCHAR Rates[], - OUT UCHAR *pHtCapabilityLen, - OUT HT_CAPABILITY_IE *pHtCapability) -{ - CHAR *Ptr; - PFRAME_802_11 Fr = (PFRAME_802_11)Msg; - PEID_STRUCT eid_ptr; - - // to prevent caller from using garbage output value - *pCapabilityInfo = 0; - *pDlsTimeout = 0; - *pHtCapabilityLen = 0; - - Ptr = Fr->Octet; - - // offset to destination MAC address (Category and Action field) - Ptr += 2; - - // get DA from payload and advance the pointer - NdisMoveMemory(pDA, Ptr, MAC_ADDR_LEN); - Ptr += MAC_ADDR_LEN; - - // get SA from payload and advance the pointer - NdisMoveMemory(pSA, Ptr, MAC_ADDR_LEN); - Ptr += MAC_ADDR_LEN; - - // get capability info from payload and advance the pointer - NdisMoveMemory(pCapabilityInfo, Ptr, 2); - Ptr += 2; - - // get capability info from payload and advance the pointer - NdisMoveMemory(pDlsTimeout, Ptr, 2); - Ptr += 2; - - // Category and Action field + DA + SA + capability + Timeout - eid_ptr = (PEID_STRUCT) &Fr->Octet[18]; - - while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((UCHAR*)Fr + MsgLen)) - { - switch(eid_ptr->Eid) - { - case IE_SUPP_RATES: - if ((eid_ptr->Len <= MAX_LEN_OF_SUPPORTED_RATES) && (eid_ptr->Len > 0)) - { - NdisMoveMemory(Rates, eid_ptr->Octet, eid_ptr->Len); - DBGPRINT(RT_DEBUG_TRACE, ("PeerDlsReqSanity - IE_SUPP_RATES., Len=%d. Rates[0]=%x\n",eid_ptr->Len, Rates[0])); - DBGPRINT(RT_DEBUG_TRACE, ("Rates[1]=%x %x %x %x %x %x %x\n", Rates[1], Rates[2], Rates[3], Rates[4], Rates[5], Rates[6], Rates[7])); - *pRatesLen = eid_ptr->Len; - } - else - { - *pRatesLen = 8; - Rates[0] = 0x82; - Rates[1] = 0x84; - Rates[2] = 0x8b; - Rates[3] = 0x96; - Rates[4] = 0x12; - Rates[5] = 0x24; - Rates[6] = 0x48; - Rates[7] = 0x6c; - DBGPRINT(RT_DEBUG_TRACE, ("PeerDlsReqSanity - wrong IE_SUPP_RATES., Len=%d\n",eid_ptr->Len)); - } - break; - - case IE_EXT_SUPP_RATES: - if (eid_ptr->Len + *pRatesLen <= MAX_LEN_OF_SUPPORTED_RATES) - { - NdisMoveMemory(&Rates[*pRatesLen], eid_ptr->Octet, eid_ptr->Len); - *pRatesLen = (*pRatesLen) + eid_ptr->Len; - } - else - { - NdisMoveMemory(&Rates[*pRatesLen], eid_ptr->Octet, MAX_LEN_OF_SUPPORTED_RATES - (*pRatesLen)); - *pRatesLen = MAX_LEN_OF_SUPPORTED_RATES; - } - break; - - case IE_HT_CAP: - if (eid_ptr->Len >= sizeof(HT_CAPABILITY_IE)) - { - NdisMoveMemory(pHtCapability, eid_ptr->Octet, sizeof(HT_CAPABILITY_IE)); - - *(USHORT *)(&pHtCapability->HtCapInfo) = cpu2le16(*(USHORT *)(&pHtCapability->HtCapInfo)); - *(USHORT *)(&pHtCapability->ExtHtCapInfo) = cpu2le16(*(USHORT *)(&pHtCapability->ExtHtCapInfo)); - *pHtCapabilityLen = sizeof(HT_CAPABILITY_IE); - - DBGPRINT(RT_DEBUG_TRACE, ("PeerDlsReqSanity - IE_HT_CAP\n")); - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("PeerDlsReqSanity - wrong IE_HT_CAP.eid_ptr->Len = %d\n", eid_ptr->Len)); - } - break; - - default: - break; - } - - eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len); - } - - return TRUE; -} - -BOOLEAN PeerDlsRspSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PUCHAR pDA, - OUT PUCHAR pSA, - OUT USHORT *pCapabilityInfo, - OUT USHORT *pStatus, - OUT UCHAR *pRatesLen, - OUT UCHAR Rates[], - OUT UCHAR *pHtCapabilityLen, - OUT HT_CAPABILITY_IE *pHtCapability) -{ - CHAR *Ptr; - PFRAME_802_11 Fr = (PFRAME_802_11)Msg; - PEID_STRUCT eid_ptr; - - // to prevent caller from using garbage output value - *pStatus = 0; - *pCapabilityInfo = 0; - *pHtCapabilityLen = 0; - - Ptr = Fr->Octet; - - // offset to destination MAC address (Category and Action field) - Ptr += 2; - - // get status code from payload and advance the pointer - NdisMoveMemory(pStatus, Ptr, 2); - Ptr += 2; - - // get DA from payload and advance the pointer - NdisMoveMemory(pDA, Ptr, MAC_ADDR_LEN); - Ptr += MAC_ADDR_LEN; - - // get SA from payload and advance the pointer - NdisMoveMemory(pSA, Ptr, MAC_ADDR_LEN); - Ptr += MAC_ADDR_LEN; - - if (pStatus == 0) - { - // get capability info from payload and advance the pointer - NdisMoveMemory(pCapabilityInfo, Ptr, 2); - Ptr += 2; - } - - // Category and Action field + status code + DA + SA + capability - eid_ptr = (PEID_STRUCT) &Fr->Octet[18]; - - while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((UCHAR*)Fr + MsgLen)) - { - switch(eid_ptr->Eid) - { - case IE_SUPP_RATES: - if ((eid_ptr->Len <= MAX_LEN_OF_SUPPORTED_RATES) && (eid_ptr->Len > 0)) - { - NdisMoveMemory(Rates, eid_ptr->Octet, eid_ptr->Len); - DBGPRINT(RT_DEBUG_TRACE, ("PeerDlsRspSanity - IE_SUPP_RATES., Len=%d. Rates[0]=%x\n",eid_ptr->Len, Rates[0])); - DBGPRINT(RT_DEBUG_TRACE, ("Rates[1]=%x %x %x %x %x %x %x\n", Rates[1], Rates[2], Rates[3], Rates[4], Rates[5], Rates[6], Rates[7])); - *pRatesLen = eid_ptr->Len; - } - else - { - *pRatesLen = 8; - Rates[0] = 0x82; - Rates[1] = 0x84; - Rates[2] = 0x8b; - Rates[3] = 0x96; - Rates[4] = 0x12; - Rates[5] = 0x24; - Rates[6] = 0x48; - Rates[7] = 0x6c; - DBGPRINT(RT_DEBUG_TRACE, ("PeerDlsRspSanity - wrong IE_SUPP_RATES., Len=%d\n",eid_ptr->Len)); - } - break; - - case IE_EXT_SUPP_RATES: - if (eid_ptr->Len + *pRatesLen <= MAX_LEN_OF_SUPPORTED_RATES) - { - NdisMoveMemory(&Rates[*pRatesLen], eid_ptr->Octet, eid_ptr->Len); - *pRatesLen = (*pRatesLen) + eid_ptr->Len; - } - else - { - NdisMoveMemory(&Rates[*pRatesLen], eid_ptr->Octet, MAX_LEN_OF_SUPPORTED_RATES - (*pRatesLen)); - *pRatesLen = MAX_LEN_OF_SUPPORTED_RATES; - } - break; - - case IE_HT_CAP: - if (eid_ptr->Len >= sizeof(HT_CAPABILITY_IE)) - { - NdisMoveMemory(pHtCapability, eid_ptr->Octet, sizeof(HT_CAPABILITY_IE)); - - *(USHORT *)(&pHtCapability->HtCapInfo) = cpu2le16(*(USHORT *)(&pHtCapability->HtCapInfo)); - *(USHORT *)(&pHtCapability->ExtHtCapInfo) = cpu2le16(*(USHORT *)(&pHtCapability->ExtHtCapInfo)); - *pHtCapabilityLen = sizeof(HT_CAPABILITY_IE); - - DBGPRINT(RT_DEBUG_TRACE, ("PeerDlsRspSanity - IE_HT_CAP\n")); - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("PeerDlsRspSanity - wrong IE_HT_CAP.eid_ptr->Len = %d\n", eid_ptr->Len)); - } - break; - - default: - break; - } - - eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len); - } - - return TRUE; -} - -BOOLEAN PeerDlsTearDownSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PUCHAR pDA, - OUT PUCHAR pSA, - OUT USHORT *pReason) -{ - CHAR *Ptr; - PFRAME_802_11 Fr = (PFRAME_802_11)Msg; - - // to prevent caller from using garbage output value - *pReason = 0; - - Ptr = Fr->Octet; - - // offset to destination MAC address (Category and Action field) - Ptr += 2; - - // get DA from payload and advance the pointer - NdisMoveMemory(pDA, Ptr, MAC_ADDR_LEN); - Ptr += MAC_ADDR_LEN; - - // get SA from payload and advance the pointer - NdisMoveMemory(pSA, Ptr, MAC_ADDR_LEN); - Ptr += MAC_ADDR_LEN; - - // get reason code from payload and advance the pointer - NdisMoveMemory(pReason, Ptr, 2); - Ptr += 2; - - return TRUE; -} -#endif // QOS_DLS_SUPPORT // - +#include "../../rt2870/common/cmm_sanity.c" diff --git a/drivers/staging/rt3070/common/cmm_sync.c b/drivers/staging/rt3070/common/cmm_sync.c index 2be7c77a384e..3b517420f48d 100644 --- a/drivers/staging/rt3070/common/cmm_sync.c +++ b/drivers/staging/rt3070/common/cmm_sync.c @@ -1,711 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - sync.c - - Abstract: - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - John Chang 2004-09-01 modified for rt2561/2661 -*/ -#include "../rt_config.h" - -// 2.4 Ghz channel plan index in the TxPower arrays. -#define BG_BAND_REGION_0_START 0 // 1,2,3,4,5,6,7,8,9,10,11 -#define BG_BAND_REGION_0_SIZE 11 -#define BG_BAND_REGION_1_START 0 // 1,2,3,4,5,6,7,8,9,10,11,12,13 -#define BG_BAND_REGION_1_SIZE 13 -#define BG_BAND_REGION_2_START 9 // 10,11 -#define BG_BAND_REGION_2_SIZE 2 -#define BG_BAND_REGION_3_START 9 // 10,11,12,13 -#define BG_BAND_REGION_3_SIZE 4 -#define BG_BAND_REGION_4_START 13 // 14 -#define BG_BAND_REGION_4_SIZE 1 -#define BG_BAND_REGION_5_START 0 // 1,2,3,4,5,6,7,8,9,10,11,12,13,14 -#define BG_BAND_REGION_5_SIZE 14 -#define BG_BAND_REGION_6_START 2 // 3,4,5,6,7,8,9 -#define BG_BAND_REGION_6_SIZE 7 -#define BG_BAND_REGION_7_START 4 // 5,6,7,8,9,10,11,12,13 -#define BG_BAND_REGION_7_SIZE 9 -#define BG_BAND_REGION_31_START 0 // 1,2,3,4,5,6,7,8,9,10,11,12,13,14 -#define BG_BAND_REGION_31_SIZE 14 - -// 5 Ghz channel plan index in the TxPower arrays. -UCHAR A_BAND_REGION_0_CHANNEL_LIST[]={36, 40, 44, 48, 52, 56, 60, 64, 149, 153, 157, 161, 165}; -UCHAR A_BAND_REGION_1_CHANNEL_LIST[]={36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140}; -UCHAR A_BAND_REGION_2_CHANNEL_LIST[]={36, 40, 44, 48, 52, 56, 60, 64}; -UCHAR A_BAND_REGION_3_CHANNEL_LIST[]={52, 56, 60, 64, 149, 153, 157, 161}; -UCHAR A_BAND_REGION_4_CHANNEL_LIST[]={149, 153, 157, 161, 165}; -UCHAR A_BAND_REGION_5_CHANNEL_LIST[]={149, 153, 157, 161}; -UCHAR A_BAND_REGION_6_CHANNEL_LIST[]={36, 40, 44, 48}; -UCHAR A_BAND_REGION_7_CHANNEL_LIST[]={36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165}; -UCHAR A_BAND_REGION_8_CHANNEL_LIST[]={52, 56, 60, 64}; -UCHAR A_BAND_REGION_9_CHANNEL_LIST[]={36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 132, 136, 140, 149, 153, 157, 161, 165}; -UCHAR A_BAND_REGION_10_CHANNEL_LIST[]={36, 40, 44, 48, 149, 153, 157, 161, 165}; -UCHAR A_BAND_REGION_11_CHANNEL_LIST[]={36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 149, 153, 157, 161}; - -//BaSizeArray follows the 802.11n definition as MaxRxFactor. 2^(13+factor) bytes. When factor =0, it's about Ba buffer size =8. -UCHAR BaSizeArray[4] = {8,16,32,64}; - -/* - ========================================================================== - Description: - Update StaCfg->ChannelList[] according to 1) Country Region 2) RF IC type, - and 3) PHY-mode user selected. - The outcome is used by driver when doing site survey. - - IRQL = PASSIVE_LEVEL - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID BuildChannelList( - IN PRTMP_ADAPTER pAd) -{ - UCHAR i, j, index=0, num=0; - PUCHAR pChannelList = NULL; - - NdisZeroMemory(pAd->ChannelList, MAX_NUM_OF_CHANNELS * sizeof(CHANNEL_TX_POWER)); - - // if not 11a-only mode, channel list starts from 2.4Ghz band - if ((pAd->CommonCfg.PhyMode != PHY_11A) -#ifdef DOT11_N_SUPPORT - && (pAd->CommonCfg.PhyMode != PHY_11AN_MIXED) && (pAd->CommonCfg.PhyMode != PHY_11N_5G) -#endif // DOT11_N_SUPPORT // - ) - { - switch (pAd->CommonCfg.CountryRegion & 0x7f) - { - case REGION_0_BG_BAND: // 1 -11 - NdisMoveMemory(&pAd->ChannelList[index], &pAd->TxPower[BG_BAND_REGION_0_START], sizeof(CHANNEL_TX_POWER) * BG_BAND_REGION_0_SIZE); - index += BG_BAND_REGION_0_SIZE; - break; - case REGION_1_BG_BAND: // 1 - 13 - NdisMoveMemory(&pAd->ChannelList[index], &pAd->TxPower[BG_BAND_REGION_1_START], sizeof(CHANNEL_TX_POWER) * BG_BAND_REGION_1_SIZE); - index += BG_BAND_REGION_1_SIZE; - break; - case REGION_2_BG_BAND: // 10 - 11 - NdisMoveMemory(&pAd->ChannelList[index], &pAd->TxPower[BG_BAND_REGION_2_START], sizeof(CHANNEL_TX_POWER) * BG_BAND_REGION_2_SIZE); - index += BG_BAND_REGION_2_SIZE; - break; - case REGION_3_BG_BAND: // 10 - 13 - NdisMoveMemory(&pAd->ChannelList[index], &pAd->TxPower[BG_BAND_REGION_3_START], sizeof(CHANNEL_TX_POWER) * BG_BAND_REGION_3_SIZE); - index += BG_BAND_REGION_3_SIZE; - break; - case REGION_4_BG_BAND: // 14 - NdisMoveMemory(&pAd->ChannelList[index], &pAd->TxPower[BG_BAND_REGION_4_START], sizeof(CHANNEL_TX_POWER) * BG_BAND_REGION_4_SIZE); - index += BG_BAND_REGION_4_SIZE; - break; - case REGION_5_BG_BAND: // 1 - 14 - NdisMoveMemory(&pAd->ChannelList[index], &pAd->TxPower[BG_BAND_REGION_5_START], sizeof(CHANNEL_TX_POWER) * BG_BAND_REGION_5_SIZE); - index += BG_BAND_REGION_5_SIZE; - break; - case REGION_6_BG_BAND: // 3 - 9 - NdisMoveMemory(&pAd->ChannelList[index], &pAd->TxPower[BG_BAND_REGION_6_START], sizeof(CHANNEL_TX_POWER) * BG_BAND_REGION_6_SIZE); - index += BG_BAND_REGION_6_SIZE; - break; - case REGION_7_BG_BAND: // 5 - 13 - NdisMoveMemory(&pAd->ChannelList[index], &pAd->TxPower[BG_BAND_REGION_7_START], sizeof(CHANNEL_TX_POWER) * BG_BAND_REGION_7_SIZE); - index += BG_BAND_REGION_7_SIZE; - break; - case REGION_31_BG_BAND: // 1 - 14 - NdisMoveMemory(&pAd->ChannelList[index], &pAd->TxPower[BG_BAND_REGION_31_START], sizeof(CHANNEL_TX_POWER) * BG_BAND_REGION_31_SIZE); - index += BG_BAND_REGION_31_SIZE; - break; - default: // Error. should never happen - break; - } - for (i=0; iChannelList[i].MaxTxPwr = 20; - } - - if ((pAd->CommonCfg.PhyMode == PHY_11A) || (pAd->CommonCfg.PhyMode == PHY_11ABG_MIXED) -#ifdef DOT11_N_SUPPORT - || (pAd->CommonCfg.PhyMode == PHY_11ABGN_MIXED) || (pAd->CommonCfg.PhyMode == PHY_11AN_MIXED) - || (pAd->CommonCfg.PhyMode == PHY_11AGN_MIXED) || (pAd->CommonCfg.PhyMode == PHY_11N_5G) -#endif // DOT11_N_SUPPORT // - ) - { - switch (pAd->CommonCfg.CountryRegionForABand & 0x7f) - { - case REGION_0_A_BAND: - num = sizeof(A_BAND_REGION_0_CHANNEL_LIST)/sizeof(UCHAR); - pChannelList = A_BAND_REGION_0_CHANNEL_LIST; - break; - case REGION_1_A_BAND: - num = sizeof(A_BAND_REGION_1_CHANNEL_LIST)/sizeof(UCHAR); - pChannelList = A_BAND_REGION_1_CHANNEL_LIST; - break; - case REGION_2_A_BAND: - num = sizeof(A_BAND_REGION_2_CHANNEL_LIST)/sizeof(UCHAR); - pChannelList = A_BAND_REGION_2_CHANNEL_LIST; - break; - case REGION_3_A_BAND: - num = sizeof(A_BAND_REGION_3_CHANNEL_LIST)/sizeof(UCHAR); - pChannelList = A_BAND_REGION_3_CHANNEL_LIST; - break; - case REGION_4_A_BAND: - num = sizeof(A_BAND_REGION_4_CHANNEL_LIST)/sizeof(UCHAR); - pChannelList = A_BAND_REGION_4_CHANNEL_LIST; - break; - case REGION_5_A_BAND: - num = sizeof(A_BAND_REGION_5_CHANNEL_LIST)/sizeof(UCHAR); - pChannelList = A_BAND_REGION_5_CHANNEL_LIST; - break; - case REGION_6_A_BAND: - num = sizeof(A_BAND_REGION_6_CHANNEL_LIST)/sizeof(UCHAR); - pChannelList = A_BAND_REGION_6_CHANNEL_LIST; - break; - case REGION_7_A_BAND: - num = sizeof(A_BAND_REGION_7_CHANNEL_LIST)/sizeof(UCHAR); - pChannelList = A_BAND_REGION_7_CHANNEL_LIST; - break; - case REGION_8_A_BAND: - num = sizeof(A_BAND_REGION_8_CHANNEL_LIST)/sizeof(UCHAR); - pChannelList = A_BAND_REGION_8_CHANNEL_LIST; - break; - case REGION_9_A_BAND: - num = sizeof(A_BAND_REGION_9_CHANNEL_LIST)/sizeof(UCHAR); - pChannelList = A_BAND_REGION_9_CHANNEL_LIST; - break; - - case REGION_10_A_BAND: - num = sizeof(A_BAND_REGION_10_CHANNEL_LIST)/sizeof(UCHAR); - pChannelList = A_BAND_REGION_10_CHANNEL_LIST; - break; - - case REGION_11_A_BAND: - num = sizeof(A_BAND_REGION_11_CHANNEL_LIST)/sizeof(UCHAR); - pChannelList = A_BAND_REGION_11_CHANNEL_LIST; - break; - - default: // Error. should never happen - DBGPRINT(RT_DEBUG_WARN,("countryregion=%d not support", pAd->CommonCfg.CountryRegionForABand)); - break; - } - - if (num != 0) - { - UCHAR RadarCh[15]={52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140}; - for (i=0; iTxPower[j].Channel) - NdisMoveMemory(&pAd->ChannelList[index+i], &pAd->TxPower[j], sizeof(CHANNEL_TX_POWER)); - } - for (j=0; j<15; j++) - { - if (pChannelList[i] == RadarCh[j]) - pAd->ChannelList[index+i].DfsReq = TRUE; - } - pAd->ChannelList[index+i].MaxTxPwr = 20; - } - index += num; - } - } - - pAd->ChannelListNum = index; - DBGPRINT(RT_DEBUG_TRACE,("country code=%d/%d, RFIC=%d, PHY mode=%d, support %d channels\n", - pAd->CommonCfg.CountryRegion, pAd->CommonCfg.CountryRegionForABand, pAd->RfIcType, pAd->CommonCfg.PhyMode, pAd->ChannelListNum)); -#ifdef DBG - for (i=0;iChannelListNum;i++) - { - DBGPRINT_RAW(RT_DEBUG_TRACE,("BuildChannel # %d :: Pwr0 = %d, Pwr1 =%d, \n ", pAd->ChannelList[i].Channel, pAd->ChannelList[i].Power, pAd->ChannelList[i].Power2)); - } -#endif -} - -/* - ========================================================================== - Description: - This routine return the first channel number according to the country - code selection and RF IC selection (signal band or dual band). It is called - whenever driver need to start a site survey of all supported channels. - Return: - ch - the first channel number of current country code setting - - IRQL = PASSIVE_LEVEL - - ========================================================================== - */ -UCHAR FirstChannel( - IN PRTMP_ADAPTER pAd) -{ - return pAd->ChannelList[0].Channel; -} - -/* - ========================================================================== - Description: - This routine returns the next channel number. This routine is called - during driver need to start a site survey of all supported channels. - Return: - next_channel - the next channel number valid in current country code setting. - Note: - return 0 if no more next channel - ========================================================================== - */ -UCHAR NextChannel( - IN PRTMP_ADAPTER pAd, - IN UCHAR channel) -{ - int i; - UCHAR next_channel = 0; - - for (i = 0; i < (pAd->ChannelListNum - 1); i++) - if (channel == pAd->ChannelList[i].Channel) - { - next_channel = pAd->ChannelList[i+1].Channel; - break; - } - return next_channel; -} - -/* - ========================================================================== - Description: - This routine is for Cisco Compatible Extensions 2.X - Spec31. AP Control of Client Transmit Power - Return: - None - Note: - Required by Aironet dBm(mW) - 0dBm(1mW), 1dBm(5mW), 13dBm(20mW), 15dBm(30mW), - 17dBm(50mw), 20dBm(100mW) - - We supported - 3dBm(Lowest), 6dBm(10%), 9dBm(25%), 12dBm(50%), - 14dBm(75%), 15dBm(100%) - - The client station's actual transmit power shall be within +/- 5dB of - the minimum value or next lower value. - ========================================================================== - */ -VOID ChangeToCellPowerLimit( - IN PRTMP_ADAPTER pAd, - IN UCHAR AironetCellPowerLimit) -{ - //valud 0xFF means that hasn't found power limit information - //from the AP's Beacon/Probe response. - if (AironetCellPowerLimit == 0xFF) - return; - - if (AironetCellPowerLimit < 6) //Used Lowest Power Percentage. - pAd->CommonCfg.TxPowerPercentage = 6; - else if (AironetCellPowerLimit < 9) - pAd->CommonCfg.TxPowerPercentage = 10; - else if (AironetCellPowerLimit < 12) - pAd->CommonCfg.TxPowerPercentage = 25; - else if (AironetCellPowerLimit < 14) - pAd->CommonCfg.TxPowerPercentage = 50; - else if (AironetCellPowerLimit < 15) - pAd->CommonCfg.TxPowerPercentage = 75; - else - pAd->CommonCfg.TxPowerPercentage = 100; //else used maximum - - if (pAd->CommonCfg.TxPowerPercentage > pAd->CommonCfg.TxPowerDefault) - pAd->CommonCfg.TxPowerPercentage = pAd->CommonCfg.TxPowerDefault; - -} - -CHAR ConvertToRssi( - IN PRTMP_ADAPTER pAd, - IN CHAR Rssi, - IN UCHAR RssiNumber) -{ - UCHAR RssiOffset, LNAGain; - - // Rssi equals to zero should be an invalid value - if (Rssi == 0) - return -99; - - LNAGain = GET_LNA_GAIN(pAd); - if (pAd->LatchRfRegs.Channel > 14) - { - if (RssiNumber == 0) - RssiOffset = pAd->ARssiOffset0; - else if (RssiNumber == 1) - RssiOffset = pAd->ARssiOffset1; - else - RssiOffset = pAd->ARssiOffset2; - } - else - { - if (RssiNumber == 0) - RssiOffset = pAd->BGRssiOffset0; - else if (RssiNumber == 1) - RssiOffset = pAd->BGRssiOffset1; - else - RssiOffset = pAd->BGRssiOffset2; - } - - return (-12 - RssiOffset - LNAGain - Rssi); -} - -/* - ========================================================================== - Description: - Scan next channel - ========================================================================== - */ -VOID ScanNextChannel( - IN PRTMP_ADAPTER pAd) -{ - HEADER_802_11 Hdr80211; - PUCHAR pOutBuffer = NULL; - NDIS_STATUS NStatus; - ULONG FrameLen = 0; - UCHAR SsidLen = 0, ScanType = pAd->MlmeAux.ScanType, BBPValue = 0; -#ifdef CONFIG_STA_SUPPORT - USHORT Status; - PHEADER_802_11 pHdr80211; -#endif // CONFIG_STA_SUPPORT // - UINT ScanTimeIn5gChannel = SHORT_CHANNEL_TIME; - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - if (MONITOR_ON(pAd)) - return; - } -#endif // CONFIG_STA_SUPPORT // - -#ifdef RALINK_ATE - // Nothing to do in ATE mode. - if (ATE_ON(pAd)) - return; -#endif // RALINK_ATE // - - if (pAd->MlmeAux.Channel == 0) - { - if ((pAd->CommonCfg.BBPCurrentBW == BW_40) -#ifdef CONFIG_STA_SUPPORT - && (INFRA_ON(pAd) - || (pAd->OpMode == OPMODE_AP)) -#endif // CONFIG_STA_SUPPORT // - ) - { - AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE); - AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel); - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); - BBPValue &= (~0x18); - BBPValue |= 0x10; - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); - DBGPRINT(RT_DEBUG_TRACE, ("SYNC - End of SCAN, restore to 40MHz channel %d, Total BSS[%02d]\n",pAd->CommonCfg.CentralChannel, pAd->ScanTab.BssNr)); - } - else - { - AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); - AsicLockChannel(pAd, pAd->CommonCfg.Channel); - DBGPRINT(RT_DEBUG_TRACE, ("SYNC - End of SCAN, restore to channel %d, Total BSS[%02d]\n",pAd->CommonCfg.Channel, pAd->ScanTab.BssNr)); - } - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - // - // To prevent data lost. - // Send an NULL data with turned PSM bit on to current associated AP before SCAN progress. - // Now, we need to send an NULL data with turned PSM bit off to AP, when scan progress done - // - if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) && (INFRA_ON(pAd))) - { - NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); - if (NStatus == NDIS_STATUS_SUCCESS) - { - pHdr80211 = (PHEADER_802_11) pOutBuffer; - MgtMacHeaderInit(pAd, pHdr80211, SUBTYPE_NULL_FUNC, 1, pAd->CommonCfg.Bssid, pAd->CommonCfg.Bssid); - pHdr80211->Duration = 0; - pHdr80211->FC.Type = BTYPE_DATA; - pHdr80211->FC.PwrMgmt = (pAd->StaCfg.Psm == PWR_SAVE); - - // Send using priority queue - MiniportMMRequest(pAd, 0, pOutBuffer, sizeof(HEADER_802_11)); - DBGPRINT(RT_DEBUG_TRACE, ("MlmeScanReqAction -- Send PSM Data frame\n")); - MlmeFreeMemory(pAd, pOutBuffer); - RTMPusecDelay(5000); - } - } - - pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; - Status = MLME_SUCCESS; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_SCAN_CONF, 2, &Status); - } -#endif // CONFIG_STA_SUPPORT // - - - RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS); - } -#ifdef RT2870 -#ifdef CONFIG_STA_SUPPORT - else if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST) && (pAd->OpMode == OPMODE_STA)) - { - pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; - MlmeCntlConfirm(pAd, MT2_SCAN_CONF, MLME_FAIL_NO_RESOURCE); - } -#endif // CONFIG_STA_SUPPORT // -#endif // RT2870 // - else - { -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - // BBP and RF are not accessible in PS mode, we has to wake them up first - if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) - AsicForceWakeup(pAd, TRUE); - - // leave PSM during scanning. otherwise we may lost ProbeRsp & BEACON - if (pAd->StaCfg.Psm == PWR_SAVE) - MlmeSetPsmBit(pAd, PWR_ACTIVE); - } -#endif // CONFIG_STA_SUPPORT // - - AsicSwitchChannel(pAd, pAd->MlmeAux.Channel, TRUE); - AsicLockChannel(pAd, pAd->MlmeAux.Channel); - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - if (pAd->MlmeAux.Channel > 14) - { - if ((pAd->CommonCfg.bIEEE80211H == 1) && RadarChannelCheck(pAd, pAd->MlmeAux.Channel)) - { - ScanType = SCAN_PASSIVE; - ScanTimeIn5gChannel = MIN_CHANNEL_TIME; - } - } - -#ifdef CARRIER_DETECTION_SUPPORT // Roger sync Carrier - // carrier detection - if (pAd->CommonCfg.CarrierDetect.Enable == TRUE) - { - ScanType = SCAN_PASSIVE; - ScanTimeIn5gChannel = MIN_CHANNEL_TIME; - } -#endif // CARRIER_DETECTION_SUPPORT // - } - -#endif // CONFIG_STA_SUPPORT // - - //Global country domain(ch1-11:active scan, ch12-14 passive scan) - if ((pAd->MlmeAux.Channel <= 14) && (pAd->MlmeAux.Channel >= 12) && ((pAd->CommonCfg.CountryRegion & 0x7f) == REGION_31_BG_BAND)) - { - ScanType = SCAN_PASSIVE; - } - - // We need to shorten active scan time in order for WZC connect issue - // Chnage the channel scan time for CISCO stuff based on its IAPP announcement - if (ScanType == FAST_SCAN_ACTIVE) - RTMPSetTimer(&pAd->MlmeAux.ScanTimer, FAST_ACTIVE_SCAN_TIME); -#ifdef CONFIG_STA_SUPPORT - else if (((ScanType == SCAN_CISCO_ACTIVE) || - (ScanType == SCAN_CISCO_PASSIVE) || - (ScanType == SCAN_CISCO_CHANNEL_LOAD) || - (ScanType == SCAN_CISCO_NOISE)) && (pAd->OpMode == OPMODE_STA)) - { - if (pAd->StaCfg.CCXScanTime < 25) - RTMPSetTimer(&pAd->MlmeAux.ScanTimer, pAd->StaCfg.CCXScanTime * 2); - else - RTMPSetTimer(&pAd->MlmeAux.ScanTimer, pAd->StaCfg.CCXScanTime); - } -#endif // CONFIG_STA_SUPPORT // - else // must be SCAN_PASSIVE or SCAN_ACTIVE - { - if ((pAd->CommonCfg.PhyMode == PHY_11ABG_MIXED) -#ifdef DOT11_N_SUPPORT - || (pAd->CommonCfg.PhyMode == PHY_11ABGN_MIXED) || (pAd->CommonCfg.PhyMode == PHY_11AGN_MIXED) -#endif // DOT11_N_SUPPORT // - ) - { - if (pAd->MlmeAux.Channel > 14) - RTMPSetTimer(&pAd->MlmeAux.ScanTimer, ScanTimeIn5gChannel); - else - RTMPSetTimer(&pAd->MlmeAux.ScanTimer, MIN_CHANNEL_TIME); - } - else - RTMPSetTimer(&pAd->MlmeAux.ScanTimer, MAX_CHANNEL_TIME); - } - - if ((ScanType == SCAN_ACTIVE) || (ScanType == FAST_SCAN_ACTIVE) || - (ScanType == SCAN_CISCO_ACTIVE)) - { - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory - if (NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_TRACE, ("SYNC - ScanNextChannel() allocate memory fail\n")); -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; - Status = MLME_FAIL_NO_RESOURCE; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_SCAN_CONF, 2, &Status); - } -#endif // CONFIG_STA_SUPPORT // - - return; - } - - // There is no need to send broadcast probe request if active scan is in effect. - if ((ScanType == SCAN_ACTIVE) || (ScanType == FAST_SCAN_ACTIVE) - ) - SsidLen = pAd->MlmeAux.SsidLen; - else - SsidLen = 0; - - MgtMacHeaderInit(pAd, &Hdr80211, SUBTYPE_PROBE_REQ, 0, BROADCAST_ADDR, BROADCAST_ADDR); - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(HEADER_802_11), &Hdr80211, - 1, &SsidIe, - 1, &SsidLen, - SsidLen, pAd->MlmeAux.Ssid, - 1, &SupRateIe, - 1, &pAd->CommonCfg.SupRateLen, - pAd->CommonCfg.SupRateLen, pAd->CommonCfg.SupRate, - END_OF_ARGS); - - if (pAd->CommonCfg.ExtRateLen) - { - ULONG Tmp; - MakeOutgoingFrame(pOutBuffer + FrameLen, &Tmp, - 1, &ExtRateIe, - 1, &pAd->CommonCfg.ExtRateLen, - pAd->CommonCfg.ExtRateLen, pAd->CommonCfg.ExtRate, - END_OF_ARGS); - FrameLen += Tmp; - } - -#ifdef DOT11_N_SUPPORT - if (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) - { - ULONG Tmp; - UCHAR HtLen; - UCHAR BROADCOM[4] = {0x0, 0x90, 0x4c, 0x33}; -#ifdef RT_BIG_ENDIAN - HT_CAPABILITY_IE HtCapabilityTmp; -#endif - if (pAd->bBroadComHT == TRUE) - { - HtLen = pAd->MlmeAux.HtCapabilityLen + 4; -#ifdef RT_BIG_ENDIAN - NdisMoveMemory(&HtCapabilityTmp, &pAd->MlmeAux.HtCapability, SIZE_HT_CAP_IE); - *(USHORT *)(&HtCapabilityTmp.HtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.HtCapInfo)); - *(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo)); - - MakeOutgoingFrame(pOutBuffer + FrameLen, &Tmp, - 1, &WpaIe, - 1, &HtLen, - 4, &BROADCOM[0], - pAd->MlmeAux.HtCapabilityLen, &HtCapabilityTmp, - END_OF_ARGS); -#else - MakeOutgoingFrame(pOutBuffer + FrameLen, &Tmp, - 1, &WpaIe, - 1, &HtLen, - 4, &BROADCOM[0], - pAd->MlmeAux.HtCapabilityLen, &pAd->MlmeAux.HtCapability, - END_OF_ARGS); -#endif // RT_BIG_ENDIAN // - } - else - { - HtLen = pAd->MlmeAux.HtCapabilityLen; -#ifdef RT_BIG_ENDIAN - NdisMoveMemory(&HtCapabilityTmp, &pAd->CommonCfg.HtCapability, SIZE_HT_CAP_IE); - *(USHORT *)(&HtCapabilityTmp.HtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.HtCapInfo)); - *(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo)); - - MakeOutgoingFrame(pOutBuffer + FrameLen, &Tmp, - 1, &HtCapIe, - 1, &HtLen, - HtLen, &HtCapabilityTmp, - END_OF_ARGS); -#else - MakeOutgoingFrame(pOutBuffer + FrameLen, &Tmp, - 1, &HtCapIe, - 1, &HtLen, - HtLen, &pAd->CommonCfg.HtCapability, - END_OF_ARGS); -#endif // RT_BIG_ENDIAN // - } - FrameLen += Tmp; - -#ifdef DOT11N_DRAFT3 - if (pAd->CommonCfg.BACapability.field.b2040CoexistScanSup == 1) - { - ULONG Tmp; - HtLen = 1; - MakeOutgoingFrame(pOutBuffer + FrameLen, &Tmp, - 1, &ExtHtCapIe, - 1, &HtLen, - 1, &pAd->CommonCfg.BSSCoexist2040.word, - END_OF_ARGS); - - FrameLen += Tmp; - } -#endif // DOT11N_DRAFT3 // - } -#endif // DOT11_N_SUPPORT // - - - MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); - } - - // For SCAN_CISCO_PASSIVE, do nothing and silently wait for beacon or other probe reponse - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - pAd->Mlme.SyncMachine.CurrState = SCAN_LISTEN; -#endif // CONFIG_STA_SUPPORT // - - } -} - -VOID MgtProbReqMacHeaderInit( - IN PRTMP_ADAPTER pAd, - IN OUT PHEADER_802_11 pHdr80211, - IN UCHAR SubType, - IN UCHAR ToDs, - IN PUCHAR pDA, - IN PUCHAR pBssid) -{ - NdisZeroMemory(pHdr80211, sizeof(HEADER_802_11)); - - pHdr80211->FC.Type = BTYPE_MGMT; - pHdr80211->FC.SubType = SubType; - if (SubType == SUBTYPE_ACK) - pHdr80211->FC.Type = BTYPE_CNTL; - pHdr80211->FC.ToDs = ToDs; - COPY_MAC_ADDR(pHdr80211->Addr1, pDA); - COPY_MAC_ADDR(pHdr80211->Addr2, pAd->CurrentAddress); - COPY_MAC_ADDR(pHdr80211->Addr3, pBssid); -} - - +#include "../../rt2870/common/cmm_sync.c" diff --git a/drivers/staging/rt3070/common/cmm_wpa.c b/drivers/staging/rt3070/common/cmm_wpa.c index 81c332ac2524..6483d329286d 100644 --- a/drivers/staging/rt3070/common/cmm_wpa.c +++ b/drivers/staging/rt3070/common/cmm_wpa.c @@ -1,1606 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - wpa.c - - Abstract: - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Jan Lee 03-07-22 Initial - Paul Lin 03-11-28 Modify for supplicant -*/ -#include "../rt_config.h" -// WPA OUI -UCHAR OUI_WPA_NONE_AKM[4] = {0x00, 0x50, 0xF2, 0x00}; -UCHAR OUI_WPA_VERSION[4] = {0x00, 0x50, 0xF2, 0x01}; -UCHAR OUI_WPA_TKIP[4] = {0x00, 0x50, 0xF2, 0x02}; -UCHAR OUI_WPA_CCMP[4] = {0x00, 0x50, 0xF2, 0x04}; -UCHAR OUI_WPA_8021X_AKM[4] = {0x00, 0x50, 0xF2, 0x01}; -UCHAR OUI_WPA_PSK_AKM[4] = {0x00, 0x50, 0xF2, 0x02}; -// WPA2 OUI -UCHAR OUI_WPA2_WEP40[4] = {0x00, 0x0F, 0xAC, 0x01}; -UCHAR OUI_WPA2_TKIP[4] = {0x00, 0x0F, 0xAC, 0x02}; -UCHAR OUI_WPA2_CCMP[4] = {0x00, 0x0F, 0xAC, 0x04}; -UCHAR OUI_WPA2_8021X_AKM[4] = {0x00, 0x0F, 0xAC, 0x01}; -UCHAR OUI_WPA2_PSK_AKM[4] = {0x00, 0x0F, 0xAC, 0x02}; -// MSA OUI -UCHAR OUI_MSA_8021X_AKM[4] = {0x00, 0x0F, 0xAC, 0x05}; // Not yet final - IEEE 802.11s-D1.06 -UCHAR OUI_MSA_PSK_AKM[4] = {0x00, 0x0F, 0xAC, 0x06}; // Not yet final - IEEE 802.11s-D1.06 - -/* - ======================================================================== - - Routine Description: - The pseudo-random function(PRF) that hashes various inputs to - derive a pseudo-random value. To add liveness to the pseudo-random - value, a nonce should be one of the inputs. - - It is used to generate PTK, GTK or some specific random value. - - Arguments: - UCHAR *key, - the key material for HMAC_SHA1 use - INT key_len - the length of key - UCHAR *prefix - a prefix label - INT prefix_len - the length of the label - UCHAR *data - a specific data with variable length - INT data_len - the length of a specific data - INT len - the output lenght - - Return Value: - UCHAR *output - the calculated result - - Note: - 802.11i-2004 Annex H.3 - - ======================================================================== -*/ -VOID PRF( - IN UCHAR *key, - IN INT key_len, - IN UCHAR *prefix, - IN INT prefix_len, - IN UCHAR *data, - IN INT data_len, - OUT UCHAR *output, - IN INT len) -{ - INT i; - UCHAR *input; - INT currentindex = 0; - INT total_len; - - // Allocate memory for input - os_alloc_mem(NULL, (PUCHAR *)&input, 1024); - - if (input == NULL) - { - DBGPRINT(RT_DEBUG_ERROR, ("!!!PRF: no memory!!!\n")); - return; - } - - // Generate concatenation input - NdisMoveMemory(input, prefix, prefix_len); - - // Concatenate a single octet containing 0 - input[prefix_len] = 0; - - // Concatenate specific data - NdisMoveMemory(&input[prefix_len + 1], data, data_len); - total_len = prefix_len + 1 + data_len; - - // Concatenate a single octet containing 0 - // This octet shall be update later - input[total_len] = 0; - total_len++; - - // Iterate to calculate the result by hmac-sha-1 - // Then concatenate to last result - for (i = 0; i < (len + 19) / 20; i++) - { - HMAC_SHA1(input, total_len, key, key_len, &output[currentindex]); - currentindex += 20; - - // update the last octet - input[total_len - 1]++; - } - os_free_mem(NULL, input); -} - -/* - ======================================================================== - - Routine Description: - It utilizes PRF-384 or PRF-512 to derive session-specific keys from a PMK. - It shall be called by 4-way handshake processing. - - Arguments: - pAd - pointer to our pAdapter context - PMK - pointer to PMK - ANonce - pointer to ANonce - AA - pointer to Authenticator Address - SNonce - pointer to SNonce - SA - pointer to Supplicant Address - len - indicate the length of PTK (octet) - - Return Value: - Output pointer to the PTK - - Note: - Refer to IEEE 802.11i-2004 8.5.1.2 - - ======================================================================== -*/ -VOID WpaCountPTK( - IN PRTMP_ADAPTER pAd, - IN UCHAR *PMK, - IN UCHAR *ANonce, - IN UCHAR *AA, - IN UCHAR *SNonce, - IN UCHAR *SA, - OUT UCHAR *output, - IN UINT len) -{ - UCHAR concatenation[76]; - UINT CurrPos = 0; - UCHAR temp[32]; - UCHAR Prefix[] = {'P', 'a', 'i', 'r', 'w', 'i', 's', 'e', ' ', 'k', 'e', 'y', ' ', - 'e', 'x', 'p', 'a', 'n', 's', 'i', 'o', 'n'}; - - // initiate the concatenation input - NdisZeroMemory(temp, sizeof(temp)); - NdisZeroMemory(concatenation, 76); - - // Get smaller address - if (RTMPCompareMemory(SA, AA, 6) == 1) - NdisMoveMemory(concatenation, AA, 6); - else - NdisMoveMemory(concatenation, SA, 6); - CurrPos += 6; - - // Get larger address - if (RTMPCompareMemory(SA, AA, 6) == 1) - NdisMoveMemory(&concatenation[CurrPos], SA, 6); - else - NdisMoveMemory(&concatenation[CurrPos], AA, 6); - - // store the larger mac address for backward compatible of - // ralink proprietary STA-key issue - NdisMoveMemory(temp, &concatenation[CurrPos], MAC_ADDR_LEN); - CurrPos += 6; - - // Get smaller Nonce - if (RTMPCompareMemory(ANonce, SNonce, 32) == 0) - NdisMoveMemory(&concatenation[CurrPos], temp, 32); // patch for ralink proprietary STA-key issue - else if (RTMPCompareMemory(ANonce, SNonce, 32) == 1) - NdisMoveMemory(&concatenation[CurrPos], SNonce, 32); - else - NdisMoveMemory(&concatenation[CurrPos], ANonce, 32); - CurrPos += 32; - - // Get larger Nonce - if (RTMPCompareMemory(ANonce, SNonce, 32) == 0) - NdisMoveMemory(&concatenation[CurrPos], temp, 32); // patch for ralink proprietary STA-key issue - else if (RTMPCompareMemory(ANonce, SNonce, 32) == 1) - NdisMoveMemory(&concatenation[CurrPos], ANonce, 32); - else - NdisMoveMemory(&concatenation[CurrPos], SNonce, 32); - CurrPos += 32; - - hex_dump("concatenation=", concatenation, 76); - - // Use PRF to generate PTK - PRF(PMK, LEN_MASTER_KEY, Prefix, 22, concatenation, 76, output, len); - -} - -/* - ======================================================================== - - Routine Description: - Generate random number by software. - - Arguments: - pAd - pointer to our pAdapter context - macAddr - pointer to local MAC address - - Return Value: - - Note: - 802.1ii-2004 Annex H.5 - - ======================================================================== -*/ -VOID GenRandom( - IN PRTMP_ADAPTER pAd, - IN UCHAR *macAddr, - OUT UCHAR *random) -{ - INT i, curr; - UCHAR local[80], KeyCounter[32]; - UCHAR result[80]; - ULONG CurrentTime; - UCHAR prefix[] = {'I', 'n', 'i', 't', ' ', 'C', 'o', 'u', 'n', 't', 'e', 'r'}; - - // Zero the related information - NdisZeroMemory(result, 80); - NdisZeroMemory(local, 80); - NdisZeroMemory(KeyCounter, 32); - - for (i = 0; i < 32; i++) - { - // copy the local MAC address - COPY_MAC_ADDR(local, macAddr); - curr = MAC_ADDR_LEN; - - // concatenate the current time - NdisGetSystemUpTime(&CurrentTime); - NdisMoveMemory(&local[curr], &CurrentTime, sizeof(CurrentTime)); - curr += sizeof(CurrentTime); - - // concatenate the last result - NdisMoveMemory(&local[curr], result, 32); - curr += 32; - - // concatenate a variable - NdisMoveMemory(&local[curr], &i, 2); - curr += 2; - - // calculate the result - PRF(KeyCounter, 32, prefix,12, local, curr, result, 32); - } - - NdisMoveMemory(random, result, 32); -} - -/* - ======================================================================== - - Routine Description: - Build cipher suite in RSN-IE. - It only shall be called by RTMPMakeRSNIE. - - Arguments: - pAd - pointer to our pAdapter context - ElementID - indicate the WPA1 or WPA2 - WepStatus - indicate the encryption type - bMixCipher - a boolean to indicate the pairwise cipher and group - cipher are the same or not - - Return Value: - - Note: - - ======================================================================== -*/ -static VOID RTMPInsertRsnIeCipher( - IN PRTMP_ADAPTER pAd, - IN UCHAR ElementID, - IN UINT WepStatus, - IN BOOLEAN bMixCipher, - IN UCHAR FlexibleCipher, - OUT PUCHAR pRsnIe, - OUT UCHAR *rsn_len) -{ - UCHAR PairwiseCnt; - - *rsn_len = 0; - - // decide WPA2 or WPA1 - if (ElementID == Wpa2Ie) - { - RSNIE2 *pRsnie_cipher = (RSNIE2*)pRsnIe; - - // Assign the verson as 1 - pRsnie_cipher->version = 1; - - switch (WepStatus) - { - // TKIP mode - case Ndis802_11Encryption2Enabled: - NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA2_TKIP, 4); - pRsnie_cipher->ucount = 1; - NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA2_TKIP, 4); - *rsn_len = sizeof(RSNIE2); - break; - - // AES mode - case Ndis802_11Encryption3Enabled: - if (bMixCipher) - NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA2_TKIP, 4); - else - NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA2_CCMP, 4); - pRsnie_cipher->ucount = 1; - NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA2_CCMP, 4); - *rsn_len = sizeof(RSNIE2); - break; - - // TKIP-AES mix mode - case Ndis802_11Encryption4Enabled: - NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA2_TKIP, 4); - - PairwiseCnt = 1; - // Insert WPA2 TKIP as the first pairwise cipher - if (MIX_CIPHER_WPA2_TKIP_ON(FlexibleCipher)) - { - NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA2_TKIP, 4); - // Insert WPA2 AES as the secondary pairwise cipher - if (MIX_CIPHER_WPA2_AES_ON(FlexibleCipher)) - { - NdisMoveMemory(pRsnie_cipher->ucast[0].oui + 4, OUI_WPA2_CCMP, 4); - PairwiseCnt = 2; - } - } - else - { - // Insert WPA2 AES as the first pairwise cipher - NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA2_CCMP, 4); - } - - pRsnie_cipher->ucount = PairwiseCnt; - *rsn_len = sizeof(RSNIE2) + (4 * (PairwiseCnt - 1)); - break; - } - - // swap for big-endian platform - pRsnie_cipher->version = cpu2le16(pRsnie_cipher->version); - pRsnie_cipher->ucount = cpu2le16(pRsnie_cipher->ucount); - } - else - { - RSNIE *pRsnie_cipher = (RSNIE*)pRsnIe; - - // Assign OUI and version - NdisMoveMemory(pRsnie_cipher->oui, OUI_WPA_VERSION, 4); - pRsnie_cipher->version = 1; - - switch (WepStatus) - { - // TKIP mode - case Ndis802_11Encryption2Enabled: - NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA_TKIP, 4); - pRsnie_cipher->ucount = 1; - NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA_TKIP, 4); - *rsn_len = sizeof(RSNIE); - break; - - // AES mode - case Ndis802_11Encryption3Enabled: - if (bMixCipher) - NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA_TKIP, 4); - else - NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA_CCMP, 4); - pRsnie_cipher->ucount = 1; - NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA_CCMP, 4); - *rsn_len = sizeof(RSNIE); - break; - - // TKIP-AES mix mode - case Ndis802_11Encryption4Enabled: - NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA_TKIP, 4); - - PairwiseCnt = 1; - // Insert WPA TKIP as the first pairwise cipher - if (MIX_CIPHER_WPA_TKIP_ON(FlexibleCipher)) - { - NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA_TKIP, 4); - // Insert WPA AES as the secondary pairwise cipher - if (MIX_CIPHER_WPA_AES_ON(FlexibleCipher)) - { - NdisMoveMemory(pRsnie_cipher->ucast[0].oui + 4, OUI_WPA_CCMP, 4); - PairwiseCnt = 2; - } - } - else - { - // Insert WPA AES as the first pairwise cipher - NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA_CCMP, 4); - } - - pRsnie_cipher->ucount = PairwiseCnt; - *rsn_len = sizeof(RSNIE) + (4 * (PairwiseCnt - 1)); - break; - } - - // swap for big-endian platform - pRsnie_cipher->version = cpu2le16(pRsnie_cipher->version); - pRsnie_cipher->ucount = cpu2le16(pRsnie_cipher->ucount); - } - -} - -/* - ======================================================================== - - Routine Description: - Build AKM suite in RSN-IE. - It only shall be called by RTMPMakeRSNIE. - - Arguments: - pAd - pointer to our pAdapter context - ElementID - indicate the WPA1 or WPA2 - AuthMode - indicate the authentication mode - apidx - indicate the interface index - - Return Value: - - Note: - - ======================================================================== -*/ -static VOID RTMPInsertRsnIeAKM( - IN PRTMP_ADAPTER pAd, - IN UCHAR ElementID, - IN UINT AuthMode, - IN UCHAR apidx, - OUT PUCHAR pRsnIe, - OUT UCHAR *rsn_len) -{ - RSNIE_AUTH *pRsnie_auth; - - pRsnie_auth = (RSNIE_AUTH*)(pRsnIe + (*rsn_len)); - - // decide WPA2 or WPA1 - if (ElementID == Wpa2Ie) - { - switch (AuthMode) - { - case Ndis802_11AuthModeWPA2: - case Ndis802_11AuthModeWPA1WPA2: - pRsnie_auth->acount = 1; - NdisMoveMemory(pRsnie_auth->auth[0].oui, OUI_WPA2_8021X_AKM, 4); - break; - - case Ndis802_11AuthModeWPA2PSK: - case Ndis802_11AuthModeWPA1PSKWPA2PSK: - pRsnie_auth->acount = 1; - NdisMoveMemory(pRsnie_auth->auth[0].oui, OUI_WPA2_PSK_AKM, 4); - break; - } - } - else - { - switch (AuthMode) - { - case Ndis802_11AuthModeWPA: - case Ndis802_11AuthModeWPA1WPA2: - pRsnie_auth->acount = 1; - NdisMoveMemory(pRsnie_auth->auth[0].oui, OUI_WPA_8021X_AKM, 4); - break; - - case Ndis802_11AuthModeWPAPSK: - case Ndis802_11AuthModeWPA1PSKWPA2PSK: - pRsnie_auth->acount = 1; - NdisMoveMemory(pRsnie_auth->auth[0].oui, OUI_WPA_PSK_AKM, 4); - break; - - case Ndis802_11AuthModeWPANone: - pRsnie_auth->acount = 1; - NdisMoveMemory(pRsnie_auth->auth[0].oui, OUI_WPA_NONE_AKM, 4); - break; - } - } - - pRsnie_auth->acount = cpu2le16(pRsnie_auth->acount); - - (*rsn_len) += sizeof(RSNIE_AUTH); // update current RSNIE length - -} - -/* - ======================================================================== - - Routine Description: - Build capability in RSN-IE. - It only shall be called by RTMPMakeRSNIE. - - Arguments: - pAd - pointer to our pAdapter context - ElementID - indicate the WPA1 or WPA2 - apidx - indicate the interface index - - Return Value: - - Note: - - ======================================================================== -*/ -static VOID RTMPInsertRsnIeCap( - IN PRTMP_ADAPTER pAd, - IN UCHAR ElementID, - IN UCHAR apidx, - OUT PUCHAR pRsnIe, - OUT UCHAR *rsn_len) -{ - RSN_CAPABILITIES *pRSN_Cap; - - // it could be ignored in WPA1 mode - if (ElementID == WpaIe) - return; - - pRSN_Cap = (RSN_CAPABILITIES*)(pRsnIe + (*rsn_len)); - - - pRSN_Cap->word = cpu2le16(pRSN_Cap->word); - - (*rsn_len) += sizeof(RSN_CAPABILITIES); // update current RSNIE length - -} - - -/* - ======================================================================== - - Routine Description: - Build RSN IE context. It is not included element-ID and length. - - Arguments: - pAd - pointer to our pAdapter context - AuthMode - indicate the authentication mode - WepStatus - indicate the encryption type - apidx - indicate the interface index - - Return Value: - - Note: - - ======================================================================== -*/ -VOID RTMPMakeRSNIE( - IN PRTMP_ADAPTER pAd, - IN UINT AuthMode, - IN UINT WepStatus, - IN UCHAR apidx) -{ - PUCHAR pRsnIe = NULL; // primary RSNIE - UCHAR *rsnielen_cur_p = 0; // the length of the primary RSNIE - UCHAR *rsnielen_ex_cur_p = 0; // the length of the secondary RSNIE - UCHAR PrimaryRsnie; - BOOLEAN bMixCipher = FALSE; // indicate the pairwise and group cipher are different - UCHAR p_offset; - WPA_MIX_PAIR_CIPHER FlexibleCipher = MIX_CIPHER_NOTUSE; // it provide the more flexible cipher combination in WPA-WPA2 and TKIPAES mode - - rsnielen_cur_p = NULL; - rsnielen_ex_cur_p = NULL; - - { -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { -#ifdef WPA_SUPPLICANT_SUPPORT - if (pAd->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_DISABLE) - { - if (AuthMode < Ndis802_11AuthModeWPA) - return; - } - else -#endif // WPA_SUPPLICANT_SUPPORT // - { - // Support WPAPSK or WPA2PSK in STA-Infra mode - // Support WPANone in STA-Adhoc mode - if ((AuthMode != Ndis802_11AuthModeWPAPSK) && - (AuthMode != Ndis802_11AuthModeWPA2PSK) && - (AuthMode != Ndis802_11AuthModeWPANone) - ) - return; - } - - DBGPRINT(RT_DEBUG_TRACE,("==> RTMPMakeRSNIE(STA)\n")); - - // Zero RSNIE context - pAd->StaCfg.RSNIE_Len = 0; - NdisZeroMemory(pAd->StaCfg.RSN_IE, MAX_LEN_OF_RSNIE); - - // Pointer to RSNIE - rsnielen_cur_p = &pAd->StaCfg.RSNIE_Len; - pRsnIe = pAd->StaCfg.RSN_IE; - - bMixCipher = pAd->StaCfg.bMixCipher; - } -#endif // CONFIG_STA_SUPPORT // - } - - // indicate primary RSNIE as WPA or WPA2 - if ((AuthMode == Ndis802_11AuthModeWPA) || - (AuthMode == Ndis802_11AuthModeWPAPSK) || - (AuthMode == Ndis802_11AuthModeWPANone) || - (AuthMode == Ndis802_11AuthModeWPA1WPA2) || - (AuthMode == Ndis802_11AuthModeWPA1PSKWPA2PSK)) - PrimaryRsnie = WpaIe; - else - PrimaryRsnie = Wpa2Ie; - - { - // Build the primary RSNIE - // 1. insert cipher suite - RTMPInsertRsnIeCipher(pAd, PrimaryRsnie, WepStatus, bMixCipher, FlexibleCipher, pRsnIe, &p_offset); - - // 2. insert AKM - RTMPInsertRsnIeAKM(pAd, PrimaryRsnie, AuthMode, apidx, pRsnIe, &p_offset); - - // 3. insert capability - RTMPInsertRsnIeCap(pAd, PrimaryRsnie, apidx, pRsnIe, &p_offset); - } - - // 4. update the RSNIE length - *rsnielen_cur_p = p_offset; - - hex_dump("The primary RSNIE", pRsnIe, (*rsnielen_cur_p)); - - -} - -/* - ========================================================================== - Description: - Check whether the received frame is EAP frame. - - Arguments: - pAd - pointer to our pAdapter context - pEntry - pointer to active entry - pData - the received frame - DataByteCount - the received frame's length - FromWhichBSSID - indicate the interface index - - Return: - TRUE - This frame is EAP frame - FALSE - otherwise - ========================================================================== -*/ -BOOLEAN RTMPCheckWPAframe( - IN PRTMP_ADAPTER pAd, - IN PMAC_TABLE_ENTRY pEntry, - IN PUCHAR pData, - IN ULONG DataByteCount, - IN UCHAR FromWhichBSSID) -{ - ULONG Body_len; - BOOLEAN Cancelled; - - - if(DataByteCount < (LENGTH_802_1_H + LENGTH_EAPOL_H)) - return FALSE; - - - // Skip LLC header - if (NdisEqualMemory(SNAP_802_1H, pData, 6) || - // Cisco 1200 AP may send packet with SNAP_BRIDGE_TUNNEL - NdisEqualMemory(SNAP_BRIDGE_TUNNEL, pData, 6)) - { - pData += 6; - } - // Skip 2-bytes EAPoL type - if (NdisEqualMemory(EAPOL, pData, 2)) - { - pData += 2; - } - else - return FALSE; - - switch (*(pData+1)) - { - case EAPPacket: - Body_len = (*(pData+2)<<8) | (*(pData+3)); - DBGPRINT(RT_DEBUG_TRACE, ("Receive EAP-Packet frame, TYPE = 0, Length = %ld\n", Body_len)); - break; - case EAPOLStart: - DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL-Start frame, TYPE = 1 \n")); - if (pEntry->EnqueueEapolStartTimerRunning != EAPOL_START_DISABLE) - { - DBGPRINT(RT_DEBUG_TRACE, ("Cancel the EnqueueEapolStartTimerRunning \n")); - RTMPCancelTimer(&pEntry->EnqueueStartForPSKTimer, &Cancelled); - pEntry->EnqueueEapolStartTimerRunning = EAPOL_START_DISABLE; - } - break; - case EAPOLLogoff: - DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOLLogoff frame, TYPE = 2 \n")); - break; - case EAPOLKey: - Body_len = (*(pData+2)<<8) | (*(pData+3)); - DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL-Key frame, TYPE = 3, Length = %ld\n", Body_len)); - break; - case EAPOLASFAlert: - DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOLASFAlert frame, TYPE = 4 \n")); - break; - default: - return FALSE; - - } - return TRUE; -} - - -/* - ========================================================================== - Description: - ENCRYPT AES GTK before sending in EAPOL frame. - AES GTK length = 128 bit, so fix blocks for aes-key-wrap as 2 in this function. - This function references to RFC 3394 for aes key wrap algorithm. - Return: - ========================================================================== -*/ -VOID AES_GTK_KEY_WRAP( - IN UCHAR *key, - IN UCHAR *plaintext, - IN UCHAR p_len, - OUT UCHAR *ciphertext) -{ - UCHAR A[8], BIN[16], BOUT[16]; - UCHAR R[512]; - INT num_blocks = p_len/8; // unit:64bits - INT i, j; - aes_context aesctx; - UCHAR xor; - - rtmp_aes_set_key(&aesctx, key, 128); - - // Init IA - for (i = 0; i < 8; i++) - A[i] = 0xa6; - - //Input plaintext - for (i = 0; i < num_blocks; i++) - { - for (j = 0 ; j < 8; j++) - R[8 * (i + 1) + j] = plaintext[8 * i + j]; - } - - // Key Mix - for (j = 0; j < 6; j++) - { - for(i = 1; i <= num_blocks; i++) - { - //phase 1 - NdisMoveMemory(BIN, A, 8); - NdisMoveMemory(&BIN[8], &R[8 * i], 8); - rtmp_aes_encrypt(&aesctx, BIN, BOUT); - - NdisMoveMemory(A, &BOUT[0], 8); - xor = num_blocks * j + i; - A[7] = BOUT[7] ^ xor; - NdisMoveMemory(&R[8 * i], &BOUT[8], 8); - } - } - - // Output ciphertext - NdisMoveMemory(ciphertext, A, 8); - - for (i = 1; i <= num_blocks; i++) - { - for (j = 0 ; j < 8; j++) - ciphertext[8 * i + j] = R[8 * i + j]; - } -} - - -/* - ======================================================================== - - Routine Description: - Misc function to decrypt AES body - - Arguments: - - Return Value: - - Note: - This function references to RFC 3394 for aes key unwrap algorithm. - - ======================================================================== -*/ -VOID AES_GTK_KEY_UNWRAP( - IN UCHAR *key, - OUT UCHAR *plaintext, - IN UCHAR c_len, - IN UCHAR *ciphertext) - -{ - UCHAR A[8], BIN[16], BOUT[16]; - UCHAR xor; - INT i, j; - aes_context aesctx; - UCHAR *R; - INT num_blocks = c_len/8; // unit:64bits - - - os_alloc_mem(NULL, (PUCHAR *)&R, 512); - - if (R == NULL) - { - DBGPRINT(RT_DEBUG_ERROR, ("!!!AES_GTK_KEY_UNWRAP: no memory!!!\n")); - return; - } /* End of if */ - - // Initialize - NdisMoveMemory(A, ciphertext, 8); - //Input plaintext - for(i = 0; i < (c_len-8); i++) - { - R[ i] = ciphertext[i + 8]; - } - - rtmp_aes_set_key(&aesctx, key, 128); - - for(j = 5; j >= 0; j--) - { - for(i = (num_blocks-1); i > 0; i--) - { - xor = (num_blocks -1 )* j + i; - NdisMoveMemory(BIN, A, 8); - BIN[7] = A[7] ^ xor; - NdisMoveMemory(&BIN[8], &R[(i-1)*8], 8); - rtmp_aes_decrypt(&aesctx, BIN, BOUT); - NdisMoveMemory(A, &BOUT[0], 8); - NdisMoveMemory(&R[(i-1)*8], &BOUT[8], 8); - } - } - - // OUTPUT - for(i = 0; i < c_len; i++) - { - plaintext[i] = R[i]; - } - - - os_free_mem(NULL, R); -} - -/* - ========================================================================== - Description: - Report the EAP message type - - Arguments: - msg - EAPOL_PAIR_MSG_1 - EAPOL_PAIR_MSG_2 - EAPOL_PAIR_MSG_3 - EAPOL_PAIR_MSG_4 - EAPOL_GROUP_MSG_1 - EAPOL_GROUP_MSG_2 - - Return: - message type string - - ========================================================================== -*/ -CHAR *GetEapolMsgType(CHAR msg) -{ - if(msg == EAPOL_PAIR_MSG_1) - return "Pairwise Message 1"; - else if(msg == EAPOL_PAIR_MSG_2) - return "Pairwise Message 2"; - else if(msg == EAPOL_PAIR_MSG_3) - return "Pairwise Message 3"; - else if(msg == EAPOL_PAIR_MSG_4) - return "Pairwise Message 4"; - else if(msg == EAPOL_GROUP_MSG_1) - return "Group Message 1"; - else if(msg == EAPOL_GROUP_MSG_2) - return "Group Message 2"; - else - return "Invalid Message"; -} - - -/* - ======================================================================== - - Routine Description: - Check Sanity RSN IE of EAPoL message - - Arguments: - - Return Value: - - - ======================================================================== -*/ -BOOLEAN RTMPCheckRSNIE( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pData, - IN UCHAR DataLen, - IN MAC_TABLE_ENTRY *pEntry, - OUT UCHAR *Offset) -{ - PUCHAR pVIE; - UCHAR len; - PEID_STRUCT pEid; - BOOLEAN result = FALSE; - - pVIE = pData; - len = DataLen; - *Offset = 0; - - while (len > sizeof(RSNIE2)) - { - pEid = (PEID_STRUCT) pVIE; - // WPA RSN IE - if ((pEid->Eid == IE_WPA) && (NdisEqualMemory(pEid->Octet, WPA_OUI, 4))) - { - if ((pEntry->AuthMode == Ndis802_11AuthModeWPA || pEntry->AuthMode == Ndis802_11AuthModeWPAPSK) && - (NdisEqualMemory(pVIE, pEntry->RSN_IE, pEntry->RSNIE_Len)) && - (pEntry->RSNIE_Len == (pEid->Len + 2))) - { - result = TRUE; - } - - *Offset += (pEid->Len + 2); - } - // WPA2 RSN IE - else if ((pEid->Eid == IE_RSN) && (NdisEqualMemory(pEid->Octet + 2, RSN_OUI, 3))) - { - if ((pEntry->AuthMode == Ndis802_11AuthModeWPA2 || pEntry->AuthMode == Ndis802_11AuthModeWPA2PSK) && - (NdisEqualMemory(pVIE, pEntry->RSN_IE, pEntry->RSNIE_Len)) && - (pEntry->RSNIE_Len == (pEid->Len + 2))/* ToDo-AlbertY for mesh*/) - { - result = TRUE; - } - - *Offset += (pEid->Len + 2); - } - else - { - break; - } - - pVIE += (pEid->Len + 2); - len -= (pEid->Len + 2); - } - - - return result; - -} - - -/* - ======================================================================== - - Routine Description: - Parse KEYDATA field. KEYDATA[] May contain 2 RSN IE and optionally GTK. - GTK is encaptulated in KDE format at p.83 802.11i D10 - - Arguments: - - Return Value: - - Note: - 802.11i D10 - - ======================================================================== -*/ -BOOLEAN RTMPParseEapolKeyData( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pKeyData, - IN UCHAR KeyDataLen, - IN UCHAR GroupKeyIndex, - IN UCHAR MsgType, - IN BOOLEAN bWPA2, - IN MAC_TABLE_ENTRY *pEntry) -{ - PKDE_ENCAP pKDE = NULL; - PUCHAR pMyKeyData = pKeyData; - UCHAR KeyDataLength = KeyDataLen; - UCHAR GTKLEN = 0; - UCHAR DefaultIdx = 0; - UCHAR skip_offset; - - // Verify The RSN IE contained in pairewise_msg_2 && pairewise_msg_3 and skip it - if (MsgType == EAPOL_PAIR_MSG_2 || MsgType == EAPOL_PAIR_MSG_3) - { - // Check RSN IE whether it is WPA2/WPA2PSK - if (!RTMPCheckRSNIE(pAd, pKeyData, KeyDataLen, pEntry, &skip_offset)) - { - // send wireless event - for RSN IE different - if (pAd->CommonCfg.bWirelessEvent) - RTMPSendWirelessEvent(pAd, IW_RSNIE_DIFF_EVENT_FLAG, pEntry->Addr, pEntry->apidx, 0); - - DBGPRINT(RT_DEBUG_ERROR, ("RSN_IE Different in msg %d of 4-way handshake!\n", MsgType)); - hex_dump("Receive RSN_IE ", pKeyData, KeyDataLen); - hex_dump("Desired RSN_IE ", pEntry->RSN_IE, pEntry->RSNIE_Len); - - return FALSE; - } - else - { - if (bWPA2 && MsgType == EAPOL_PAIR_MSG_3) - { - // skip RSN IE - pMyKeyData += skip_offset; - KeyDataLength -= skip_offset; - DBGPRINT(RT_DEBUG_TRACE, ("RTMPParseEapolKeyData ==> WPA2/WPA2PSK RSN IE matched in Msg 3, Length(%d) \n", skip_offset)); - } - else - return TRUE; - } - } - - DBGPRINT(RT_DEBUG_TRACE,("RTMPParseEapolKeyData ==> KeyDataLength %d without RSN_IE \n", KeyDataLength)); - - // Parse EKD format in pairwise_msg_3_WPA2 && group_msg_1_WPA2 - if (bWPA2 && (MsgType == EAPOL_PAIR_MSG_3 || MsgType == EAPOL_GROUP_MSG_1)) - { - if (KeyDataLength >= 8) // KDE format exclude GTK length - { - pKDE = (PKDE_ENCAP) pMyKeyData; - - - DefaultIdx = pKDE->GTKEncap.Kid; - - // Sanity check - KED length - if (KeyDataLength < (pKDE->Len + 2)) - { - DBGPRINT(RT_DEBUG_ERROR, ("ERROR: The len from KDE is too short \n")); - return FALSE; - } - - // Get GTK length - refer to IEEE 802.11i-2004 p.82 - GTKLEN = pKDE->Len -6; - if (GTKLEN < LEN_AES_KEY) - { - DBGPRINT(RT_DEBUG_ERROR, ("ERROR: GTK Key length is too short (%d) \n", GTKLEN)); - return FALSE; - } - - } - else - { - DBGPRINT(RT_DEBUG_ERROR, ("ERROR: KDE format length is too short \n")); - return FALSE; - } - - DBGPRINT(RT_DEBUG_TRACE, ("GTK in KDE format ,DefaultKeyID=%d, KeyLen=%d \n", DefaultIdx, GTKLEN)); - // skip it - pMyKeyData += 8; - KeyDataLength -= 8; - - } - else if (!bWPA2 && MsgType == EAPOL_GROUP_MSG_1) - { - DefaultIdx = GroupKeyIndex; - DBGPRINT(RT_DEBUG_TRACE, ("GTK DefaultKeyID=%d \n", DefaultIdx)); - } - - // Sanity check - shared key index must be 1 ~ 3 - if (DefaultIdx < 1 || DefaultIdx > 3) - { - DBGPRINT(RT_DEBUG_ERROR, ("ERROR: GTK Key index(%d) is invalid in %s %s \n", DefaultIdx, ((bWPA2) ? "WPA2" : "WPA"), GetEapolMsgType(MsgType))); - return FALSE; - } - - -#ifdef CONFIG_STA_SUPPORT - // Todo -#endif // CONFIG_STA_SUPPORT // - - return TRUE; - -} - - -/* - ======================================================================== - - Routine Description: - Construct EAPoL message for WPA handshaking - Its format is below, - - +--------------------+ - | Protocol Version | 1 octet - +--------------------+ - | Protocol Type | 1 octet - +--------------------+ - | Body Length | 2 octets - +--------------------+ - | Descriptor Type | 1 octet - +--------------------+ - | Key Information | 2 octets - +--------------------+ - | Key Length | 1 octet - +--------------------+ - | Key Repaly Counter | 8 octets - +--------------------+ - | Key Nonce | 32 octets - +--------------------+ - | Key IV | 16 octets - +--------------------+ - | Key RSC | 8 octets - +--------------------+ - | Key ID or Reserved | 8 octets - +--------------------+ - | Key MIC | 16 octets - +--------------------+ - | Key Data Length | 2 octets - +--------------------+ - | Key Data | n octets - +--------------------+ - - - Arguments: - pAd Pointer to our adapter - - Return Value: - None - - Note: - - ======================================================================== -*/ -VOID ConstructEapolMsg( - IN PRTMP_ADAPTER pAd, - IN UCHAR AuthMode, - IN UCHAR WepStatus, - IN UCHAR GroupKeyWepStatus, - IN UCHAR MsgType, - IN UCHAR DefaultKeyIdx, - IN UCHAR *ReplayCounter, - IN UCHAR *KeyNonce, - IN UCHAR *TxRSC, - IN UCHAR *PTK, - IN UCHAR *GTK, - IN UCHAR *RSNIE, - IN UCHAR RSNIE_Len, - OUT PEAPOL_PACKET pMsg) -{ - BOOLEAN bWPA2 = FALSE; - - // Choose WPA2 or not - if ((AuthMode == Ndis802_11AuthModeWPA2) || (AuthMode == Ndis802_11AuthModeWPA2PSK)) - bWPA2 = TRUE; - - // Init Packet and Fill header - pMsg->ProVer = EAPOL_VER; - pMsg->ProType = EAPOLKey; - - // Default 95 bytes, the EAPoL-Key descriptor exclude Key-data field - pMsg->Body_Len[1] = LEN_EAPOL_KEY_MSG; - - // Fill in EAPoL descriptor - if (bWPA2) - pMsg->KeyDesc.Type = WPA2_KEY_DESC; - else - pMsg->KeyDesc.Type = WPA1_KEY_DESC; - - // Fill in Key information, refer to IEEE Std 802.11i-2004 page 78 - // When either the pairwise or the group cipher is AES, the DESC_TYPE_AES(2) shall be used. - pMsg->KeyDesc.KeyInfo.KeyDescVer = - (((WepStatus == Ndis802_11Encryption3Enabled) || (GroupKeyWepStatus == Ndis802_11Encryption3Enabled)) ? (DESC_TYPE_AES) : (DESC_TYPE_TKIP)); - - // Specify Key Type as Group(0) or Pairwise(1) - if (MsgType >= EAPOL_GROUP_MSG_1) - pMsg->KeyDesc.KeyInfo.KeyType = GROUPKEY; - else - pMsg->KeyDesc.KeyInfo.KeyType = PAIRWISEKEY; - - // Specify Key Index, only group_msg1_WPA1 - if (!bWPA2 && (MsgType >= EAPOL_GROUP_MSG_1)) - pMsg->KeyDesc.KeyInfo.KeyIndex = DefaultKeyIdx; - - if (MsgType == EAPOL_PAIR_MSG_3) - pMsg->KeyDesc.KeyInfo.Install = 1; - - if ((MsgType == EAPOL_PAIR_MSG_1) || (MsgType == EAPOL_PAIR_MSG_3) || (MsgType == EAPOL_GROUP_MSG_1)) - pMsg->KeyDesc.KeyInfo.KeyAck = 1; - - if (MsgType != EAPOL_PAIR_MSG_1) - pMsg->KeyDesc.KeyInfo.KeyMic = 1; - - if ((bWPA2 && (MsgType >= EAPOL_PAIR_MSG_3)) || (!bWPA2 && (MsgType >= EAPOL_GROUP_MSG_1))) - { - pMsg->KeyDesc.KeyInfo.Secure = 1; - } - - if (bWPA2 && ((MsgType == EAPOL_PAIR_MSG_3) || (MsgType == EAPOL_GROUP_MSG_1))) - { - pMsg->KeyDesc.KeyInfo.EKD_DL = 1; - } - - // key Information element has done. - *(USHORT *)(&pMsg->KeyDesc.KeyInfo) = cpu2le16(*(USHORT *)(&pMsg->KeyDesc.KeyInfo)); - - // Fill in Key Length - { - if (MsgType >= EAPOL_GROUP_MSG_1) - { - // the length of group key cipher - pMsg->KeyDesc.KeyLength[1] = ((GroupKeyWepStatus == Ndis802_11Encryption2Enabled) ? TKIP_GTK_LENGTH : LEN_AES_KEY); - } - else - { - // the length of pairwise key cipher - pMsg->KeyDesc.KeyLength[1] = ((WepStatus == Ndis802_11Encryption2Enabled) ? LEN_TKIP_KEY : LEN_AES_KEY); - } - } - - // Fill in replay counter - NdisMoveMemory(pMsg->KeyDesc.ReplayCounter, ReplayCounter, LEN_KEY_DESC_REPLAY); - - // Fill Key Nonce field - // ANonce : pairwise_msg1 & pairwise_msg3 - // SNonce : pairwise_msg2 - // GNonce : group_msg1_wpa1 - if ((MsgType <= EAPOL_PAIR_MSG_3) || ((!bWPA2 && (MsgType == EAPOL_GROUP_MSG_1)))) - NdisMoveMemory(pMsg->KeyDesc.KeyNonce, KeyNonce, LEN_KEY_DESC_NONCE); - - // Fill key IV - WPA2 as 0, WPA1 as random - if (!bWPA2 && (MsgType == EAPOL_GROUP_MSG_1)) - { - // Suggest IV be random number plus some number, - NdisMoveMemory(pMsg->KeyDesc.KeyIv, &KeyNonce[16], LEN_KEY_DESC_IV); - pMsg->KeyDesc.KeyIv[15] += 2; - } - - // Fill Key RSC field - // It contains the RSC for the GTK being installed. - if ((MsgType == EAPOL_PAIR_MSG_3 && bWPA2) || (MsgType == EAPOL_GROUP_MSG_1)) - { - NdisMoveMemory(pMsg->KeyDesc.KeyRsc, TxRSC, 6); - } - - // Clear Key MIC field for MIC calculation later - NdisZeroMemory(pMsg->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); - - ConstructEapolKeyData(pAd, - AuthMode, - WepStatus, - GroupKeyWepStatus, - MsgType, - DefaultKeyIdx, - bWPA2, - PTK, - GTK, - RSNIE, - RSNIE_Len, - pMsg); - - // Calculate MIC and fill in KeyMic Field except Pairwise Msg 1. - if (MsgType != EAPOL_PAIR_MSG_1) - { - CalculateMIC(pAd, WepStatus, PTK, pMsg); - } - - DBGPRINT(RT_DEBUG_TRACE, ("===> ConstructEapolMsg for %s %s\n", ((bWPA2) ? "WPA2" : "WPA"), GetEapolMsgType(MsgType))); - DBGPRINT(RT_DEBUG_TRACE, (" Body length = %d \n", pMsg->Body_Len[1])); - DBGPRINT(RT_DEBUG_TRACE, (" Key length = %d \n", pMsg->KeyDesc.KeyLength[1])); - - -} - -/* - ======================================================================== - - Routine Description: - Construct the Key Data field of EAPoL message - - Arguments: - pAd Pointer to our adapter - Elem Message body - - Return Value: - None - - Note: - - ======================================================================== -*/ -VOID ConstructEapolKeyData( - IN PRTMP_ADAPTER pAd, - IN UCHAR AuthMode, - IN UCHAR WepStatus, - IN UCHAR GroupKeyWepStatus, - IN UCHAR MsgType, - IN UCHAR DefaultKeyIdx, - IN BOOLEAN bWPA2Capable, - IN UCHAR *PTK, - IN UCHAR *GTK, - IN UCHAR *RSNIE, - IN UCHAR RSNIE_LEN, - OUT PEAPOL_PACKET pMsg) -{ - UCHAR *mpool, *Key_Data, *Rc4GTK; - UCHAR ekey[(LEN_KEY_DESC_IV+LEN_EAP_EK)]; - UCHAR data_offset; - - - if (MsgType == EAPOL_PAIR_MSG_1 || MsgType == EAPOL_PAIR_MSG_4 || MsgType == EAPOL_GROUP_MSG_2) - return; - - // allocate memory pool - os_alloc_mem(pAd, (PUCHAR *)&mpool, 1500); - - if (mpool == NULL) - return; - - /* Rc4GTK Len = 512 */ - Rc4GTK = (UCHAR *) ROUND_UP(mpool, 4); - /* Key_Data Len = 512 */ - Key_Data = (UCHAR *) ROUND_UP(Rc4GTK + 512, 4); - - NdisZeroMemory(Key_Data, 512); - pMsg->KeyDesc.KeyDataLen[1] = 0; - data_offset = 0; - - // Encapsulate RSNIE in pairwise_msg2 & pairwise_msg3 - if (RSNIE_LEN && ((MsgType == EAPOL_PAIR_MSG_2) || (MsgType == EAPOL_PAIR_MSG_3))) - { - if (bWPA2Capable) - Key_Data[data_offset + 0] = IE_WPA2; - else - Key_Data[data_offset + 0] = IE_WPA; - - Key_Data[data_offset + 1] = RSNIE_LEN; - NdisMoveMemory(&Key_Data[data_offset + 2], RSNIE, RSNIE_LEN); - data_offset += (2 + RSNIE_LEN); - } - - // Encapsulate KDE format in pairwise_msg3_WPA2 & group_msg1_WPA2 - if (bWPA2Capable && ((MsgType == EAPOL_PAIR_MSG_3) || (MsgType == EAPOL_GROUP_MSG_1))) - { - // Key Data Encapsulation (KDE) format - 802.11i-2004 Figure-43w and Table-20h - Key_Data[data_offset + 0] = 0xDD; - - if (GroupKeyWepStatus == Ndis802_11Encryption3Enabled) - { - Key_Data[data_offset + 1] = 0x16;// 4+2+16(OUI+DataType+DataField) - } - else - { - Key_Data[data_offset + 1] = 0x26;// 4+2+32(OUI+DataType+DataField) - } - - Key_Data[data_offset + 2] = 0x00; - Key_Data[data_offset + 3] = 0x0F; - Key_Data[data_offset + 4] = 0xAC; - Key_Data[data_offset + 5] = 0x01; - - // GTK KDE format - 802.11i-2004 Figure-43x - Key_Data[data_offset + 6] = (DefaultKeyIdx & 0x03); - Key_Data[data_offset + 7] = 0x00; // Reserved Byte - - data_offset += 8; - } - - - // Encapsulate GTK and encrypt the key-data field with KEK. - // Only for pairwise_msg3_WPA2 and group_msg1 - if ((MsgType == EAPOL_PAIR_MSG_3 && bWPA2Capable) || (MsgType == EAPOL_GROUP_MSG_1)) - { - // Fill in GTK - if (GroupKeyWepStatus == Ndis802_11Encryption3Enabled) - { - NdisMoveMemory(&Key_Data[data_offset], GTK, LEN_AES_KEY); - data_offset += LEN_AES_KEY; - } - else - { - NdisMoveMemory(&Key_Data[data_offset], GTK, TKIP_GTK_LENGTH); - data_offset += TKIP_GTK_LENGTH; - } - - // Still dont know why, but if not append will occur "GTK not include in MSG3" - // Patch for compatibility between zero config and funk - if (MsgType == EAPOL_PAIR_MSG_3 && bWPA2Capable) - { - if (GroupKeyWepStatus == Ndis802_11Encryption3Enabled) - { - Key_Data[data_offset + 0] = 0xDD; - Key_Data[data_offset + 1] = 0; - data_offset += 2; - } - else - { - Key_Data[data_offset + 0] = 0xDD; - Key_Data[data_offset + 1] = 0; - Key_Data[data_offset + 2] = 0; - Key_Data[data_offset + 3] = 0; - Key_Data[data_offset + 4] = 0; - Key_Data[data_offset + 5] = 0; - data_offset += 6; - } - } - - // Encrypt the data material in key data field - if (WepStatus == Ndis802_11Encryption3Enabled) - { - AES_GTK_KEY_WRAP(&PTK[16], Key_Data, data_offset, Rc4GTK); - // AES wrap function will grow 8 bytes in length - data_offset += 8; - } - else - { - // PREPARE Encrypted "Key DATA" field. (Encrypt GTK with RC4, usinf PTK[16]->[31] as Key, IV-field as IV) - // put TxTsc in Key RSC field - pAd->PrivateInfo.FCSCRC32 = PPPINITFCS32; //Init crc32. - - // ekey is the contanetion of IV-field, and PTK[16]->PTK[31] - NdisMoveMemory(ekey, pMsg->KeyDesc.KeyIv, LEN_KEY_DESC_IV); - NdisMoveMemory(&ekey[LEN_KEY_DESC_IV], &PTK[16], LEN_EAP_EK); - ARCFOUR_INIT(&pAd->PrivateInfo.WEPCONTEXT, ekey, sizeof(ekey)); //INIT SBOX, KEYLEN+3(IV) - pAd->PrivateInfo.FCSCRC32 = RTMP_CALC_FCS32(pAd->PrivateInfo.FCSCRC32, Key_Data, data_offset); - WPAARCFOUR_ENCRYPT(&pAd->PrivateInfo.WEPCONTEXT, Rc4GTK, Key_Data, data_offset); - } - - NdisMoveMemory(pMsg->KeyDesc.KeyData, Rc4GTK, data_offset); - } - else - { - NdisMoveMemory(pMsg->KeyDesc.KeyData, Key_Data, data_offset); - } - - // set key data length field and total length - pMsg->KeyDesc.KeyDataLen[1] = data_offset; - pMsg->Body_Len[1] += data_offset; - - os_free_mem(pAd, mpool); - -} - -/* - ======================================================================== - - Routine Description: - Calcaulate MIC. It is used during 4-ways handsharking. - - Arguments: - pAd - pointer to our pAdapter context - PeerWepStatus - indicate the encryption type - - Return Value: - - Note: - - ======================================================================== -*/ -VOID CalculateMIC( - IN PRTMP_ADAPTER pAd, - IN UCHAR PeerWepStatus, - IN UCHAR *PTK, - OUT PEAPOL_PACKET pMsg) -{ - UCHAR *OutBuffer; - ULONG FrameLen = 0; - UCHAR mic[LEN_KEY_DESC_MIC]; - UCHAR digest[80]; - - // allocate memory for MIC calculation - os_alloc_mem(pAd, (PUCHAR *)&OutBuffer, 512); - - if (OutBuffer == NULL) - { - DBGPRINT(RT_DEBUG_ERROR, ("!!!CalculateMIC: no memory!!!\n")); - return; - } - - // make a frame for calculating MIC. - MakeOutgoingFrame(OutBuffer, &FrameLen, - pMsg->Body_Len[1] + 4, pMsg, - END_OF_ARGS); - - NdisZeroMemory(mic, sizeof(mic)); - - // Calculate MIC - if (PeerWepStatus == Ndis802_11Encryption3Enabled) - { - HMAC_SHA1(OutBuffer, FrameLen, PTK, LEN_EAP_MICK, digest); - NdisMoveMemory(mic, digest, LEN_KEY_DESC_MIC); - } - else - { - hmac_md5(PTK, LEN_EAP_MICK, OutBuffer, FrameLen, mic); - } - - // store the calculated MIC - NdisMoveMemory(pMsg->KeyDesc.KeyMic, mic, LEN_KEY_DESC_MIC); - - os_free_mem(pAd, OutBuffer); -} - -/* - ======================================================================== - - Routine Description: - Some received frames can't decrypt by Asic, so decrypt them by software. - - Arguments: - pAd - pointer to our pAdapter context - PeerWepStatus - indicate the encryption type - - Return Value: - NDIS_STATUS_SUCCESS - decryption successful - NDIS_STATUS_FAILURE - decryption failure - - ======================================================================== -*/ -NDIS_STATUS RTMPSoftDecryptBroadCastData( - IN PRTMP_ADAPTER pAd, - IN RX_BLK *pRxBlk, - IN NDIS_802_11_ENCRYPTION_STATUS GroupCipher, - IN PCIPHER_KEY pShard_key) -{ - PRXWI_STRUC pRxWI = pRxBlk->pRxWI; - - - - // handle WEP decryption - if (GroupCipher == Ndis802_11Encryption1Enabled) - { - if (RTMPSoftDecryptWEP(pAd, pRxBlk->pData, pRxWI->MPDUtotalByteCount, pShard_key)) - { - - //Minus IV[4] & ICV[4] - pRxWI->MPDUtotalByteCount -= 8; - } - else - { - DBGPRINT(RT_DEBUG_ERROR, ("ERROR : Software decrypt WEP data fails.\n")); - // give up this frame - return NDIS_STATUS_FAILURE; - } - } - // handle TKIP decryption - else if (GroupCipher == Ndis802_11Encryption2Enabled) - { - if (RTMPSoftDecryptTKIP(pAd, pRxBlk->pData, pRxWI->MPDUtotalByteCount, 0, pShard_key)) - { - - //Minus 8 bytes MIC, 8 bytes IV/EIV, 4 bytes ICV - pRxWI->MPDUtotalByteCount -= 20; - } - else - { - DBGPRINT(RT_DEBUG_ERROR, ("ERROR : RTMPSoftDecryptTKIP Failed\n")); - // give up this frame - return NDIS_STATUS_FAILURE; - } - } - // handle AES decryption - else if (GroupCipher == Ndis802_11Encryption3Enabled) - { - if (RTMPSoftDecryptAES(pAd, pRxBlk->pData, pRxWI->MPDUtotalByteCount , pShard_key)) - { - - //8 bytes MIC, 8 bytes IV/EIV (CCMP Header) - pRxWI->MPDUtotalByteCount -= 16; - } - else - { - DBGPRINT(RT_DEBUG_ERROR, ("ERROR : RTMPSoftDecryptAES Failed\n")); - // give up this frame - return NDIS_STATUS_FAILURE; - } - } - else - { - // give up this frame - return NDIS_STATUS_FAILURE; - } - - return NDIS_STATUS_SUCCESS; - -} - +#include "../../rt2870/common/cmm_wpa.c" diff --git a/drivers/staging/rt3070/common/dfs.c b/drivers/staging/rt3070/common/dfs.c index 28d60145791c..c584a6924c3c 100644 --- a/drivers/staging/rt3070/common/dfs.c +++ b/drivers/staging/rt3070/common/dfs.c @@ -1,441 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - ap_dfs.c - - Abstract: - Support DFS function. - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Fonchi 03-12-2007 created -*/ - -#include "../rt_config.h" - -typedef struct _RADAR_DURATION_TABLE -{ - ULONG RDDurRegion; - ULONG RadarSignalDuration; - ULONG Tolerance; -} RADAR_DURATION_TABLE, *PRADAR_DURATION_TABLE; - - -static UCHAR RdIdleTimeTable[MAX_RD_REGION][4] = -{ - {9, 250, 250, 250}, // CE - {4, 250, 250, 250}, // FCC - {4, 250, 250, 250}, // JAP - {15, 250, 250, 250}, // JAP_W53 - {4, 250, 250, 250} // JAP_W56 -}; - -/* - ======================================================================== - - Routine Description: - Bbp Radar detection routine - - Arguments: - pAd Pointer to our adapter - - Return Value: - - ======================================================================== -*/ -VOID BbpRadarDetectionStart( - IN PRTMP_ADAPTER pAd) -{ - UINT8 RadarPeriod; - - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, 114, 0x02); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, 121, 0x20); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, 122, 0x00); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, 123, 0x08/*0x80*/); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, 124, 0x28); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, 125, 0xff); - - RadarPeriod = ((UINT)RdIdleTimeTable[pAd->CommonCfg.RadarDetect.RDDurRegion][0] + (UINT)pAd->CommonCfg.RadarDetect.DfsSessionTime) < 250 ? - (RdIdleTimeTable[pAd->CommonCfg.RadarDetect.RDDurRegion][0] + pAd->CommonCfg.RadarDetect.DfsSessionTime) : 250; - - RTMP_IO_WRITE8(pAd, 0x7020, 0x1d); - RTMP_IO_WRITE8(pAd, 0x7021, 0x40); - - RadarDetectionStart(pAd, 0, RadarPeriod); - return; -} - -/* - ======================================================================== - - Routine Description: - Bbp Radar detection routine - - Arguments: - pAd Pointer to our adapter - - Return Value: - - ======================================================================== -*/ -VOID BbpRadarDetectionStop( - IN PRTMP_ADAPTER pAd) -{ - RTMP_IO_WRITE8(pAd, 0x7020, 0x1d); - RTMP_IO_WRITE8(pAd, 0x7021, 0x60); - - RadarDetectionStop(pAd); - return; -} - -/* - ======================================================================== - - Routine Description: - Radar detection routine - - Arguments: - pAd Pointer to our adapter - - Return Value: - - ======================================================================== -*/ -VOID RadarDetectionStart( - IN PRTMP_ADAPTER pAd, - IN BOOLEAN CTSProtect, - IN UINT8 CTSPeriod) -{ - UINT8 DfsActiveTime = (pAd->CommonCfg.RadarDetect.DfsSessionTime & 0x1f); - UINT8 CtsProtect = (CTSProtect == 1) ? 0x02 : 0x01; // CTS protect. - - if (CTSProtect != 0) - { - switch(pAd->CommonCfg.RadarDetect.RDDurRegion) - { - case FCC: - case JAP_W56: - CtsProtect = 0x03; - break; - - case CE: - case JAP_W53: - default: - CtsProtect = 0x02; - break; - } - } - else - CtsProtect = 0x01; - - - // send start-RD with CTS protection command to MCU - // highbyte [7] reserve - // highbyte [6:5] 0x: stop Carrier/Radar detection - // highbyte [10]: Start Carrier/Radar detection without CTS protection, 11: Start Carrier/Radar detection with CTS protection - // highbyte [4:0] Radar/carrier detection duration. In 1ms. - - // lowbyte [7:0] Radar/carrier detection period, in 1ms. - AsicSendCommandToMcu(pAd, 0x60, 0xff, CTSPeriod, DfsActiveTime | (CtsProtect << 5)); - //AsicSendCommandToMcu(pAd, 0x63, 0xff, 10, 0); - - return; -} - -/* - ======================================================================== - - Routine Description: - Radar detection routine - - Arguments: - pAd Pointer to our adapter - - Return Value: - TRUE Found radar signal - FALSE Not found radar signal - - ======================================================================== -*/ -VOID RadarDetectionStop( - IN PRTMP_ADAPTER pAd) -{ - DBGPRINT(RT_DEBUG_TRACE,("RadarDetectionStop.\n")); - AsicSendCommandToMcu(pAd, 0x60, 0xff, 0x00, 0x00); // send start-RD with CTS protection command to MCU - - return; -} - -/* - ======================================================================== - - Routine Description: - Radar channel check routine - - Arguments: - pAd Pointer to our adapter - - Return Value: - TRUE need to do radar detect - FALSE need not to do radar detect - - ======================================================================== -*/ -BOOLEAN RadarChannelCheck( - IN PRTMP_ADAPTER pAd, - IN UCHAR Ch) -{ -#if 1 - INT i; - BOOLEAN result = FALSE; - - for (i=0; iChannelListNum; i++) - { - if (Ch == pAd->ChannelList[i].Channel) - { - result = pAd->ChannelList[i].DfsReq; - break; - } - } - - return result; -#else - INT i; - UCHAR Channel[15]={52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140}; - - for (i=0; i<15; i++) - { - if (Ch == Channel[i]) - { - break; - } - } - - if (i != 15) - return TRUE; - else - return FALSE; -#endif -} - -ULONG JapRadarType( - IN PRTMP_ADAPTER pAd) -{ - ULONG i; - const UCHAR Channel[15]={52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140}; - - if (pAd->CommonCfg.RadarDetect.RDDurRegion != JAP) - { - return pAd->CommonCfg.RadarDetect.RDDurRegion; - } - - for (i=0; i<15; i++) - { - if (pAd->CommonCfg.Channel == Channel[i]) - { - break; - } - } - - if (i < 4) - return JAP_W53; - else if (i < 15) - return JAP_W56; - else - return JAP; // W52 - -} - -ULONG RTMPBbpReadRadarDuration( - IN PRTMP_ADAPTER pAd) -{ - UINT8 byteValue = 0; - ULONG result; - - BBP_IO_READ8_BY_REG_ID(pAd, BBP_R115, &byteValue); - - result = 0; - switch (byteValue) - { - case 1: // radar signal detected by pulse mode. - case 2: // radar signal detected by width mode. - result = RTMPReadRadarDuration(pAd); - break; - - case 0: // No radar signal. - default: - - result = 0; - break; - } - - return result; -} - -ULONG RTMPReadRadarDuration( - IN PRTMP_ADAPTER pAd) -{ - ULONG result = 0; - -#ifdef DFS_SUPPORT - UINT8 duration1 = 0, duration2 = 0, duration3 = 0; - - BBP_IO_READ8_BY_REG_ID(pAd, BBP_R116, &duration1); - BBP_IO_READ8_BY_REG_ID(pAd, BBP_R117, &duration2); - BBP_IO_READ8_BY_REG_ID(pAd, BBP_R118, &duration3); - result = (duration1 << 16) + (duration2 << 8) + duration3; -#endif // DFS_SUPPORT // - - return result; - -} - -VOID RTMPCleanRadarDuration( - IN PRTMP_ADAPTER pAd) -{ - return; -} - -/* - ======================================================================== - Routine Description: - Radar wave detection. The API should be invoke each second. - - Arguments: - pAd - Adapter pointer - - Return Value: - None - - ======================================================================== -*/ -VOID ApRadarDetectPeriodic( - IN PRTMP_ADAPTER pAd) -{ - INT i; - - pAd->CommonCfg.RadarDetect.InServiceMonitorCount++; - - for (i=0; iChannelListNum; i++) - { - if (pAd->ChannelList[i].RemainingTimeForUse > 0) - { - pAd->ChannelList[i].RemainingTimeForUse --; - if ((pAd->Mlme.PeriodicRound%5) == 0) - { - DBGPRINT(RT_DEBUG_TRACE, ("RadarDetectPeriodic - ch=%d, RemainingTimeForUse=%d\n", pAd->ChannelList[i].Channel, pAd->ChannelList[i].RemainingTimeForUse)); - } - } - } - - //radar detect - if ((pAd->CommonCfg.Channel > 14) - && (pAd->CommonCfg.bIEEE80211H == 1) - && RadarChannelCheck(pAd, pAd->CommonCfg.Channel)) - { - RadarDetectPeriodic(pAd); - } - - return; -} - -// Periodic Radar detection, switch channel will occur in RTMPHandleTBTTInterrupt() -// Before switch channel, driver needs doing channel switch announcement. -VOID RadarDetectPeriodic( - IN PRTMP_ADAPTER pAd) -{ - // need to check channel availability, after switch channel - if (pAd->CommonCfg.RadarDetect.RDMode != RD_SILENCE_MODE) - return; - - // channel availability check time is 60sec, use 65 for assurance - if (pAd->CommonCfg.RadarDetect.RDCount++ > pAd->CommonCfg.RadarDetect.ChMovingTime) - { - DBGPRINT(RT_DEBUG_TRACE, ("Not found radar signal, start send beacon and radar detection in service monitor\n\n")); - BbpRadarDetectionStop(pAd); - AsicEnableBssSync(pAd); - pAd->CommonCfg.RadarDetect.RDMode = RD_NORMAL_MODE; - - - return; - } - - return; -} - - -/* - ========================================================================== - Description: - change channel moving time for DFS testing. - - Arguments: - pAdapter Pointer to our adapter - wrq Pointer to the ioctl argument - - Return Value: - None - - Note: - Usage: - 1.) iwpriv ra0 set ChMovTime=[value] - ========================================================================== -*/ -INT Set_ChMovingTime_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - UINT8 Value; - - Value = simple_strtol(arg, 0, 10); - - pAd->CommonCfg.RadarDetect.ChMovingTime = Value; - - DBGPRINT(RT_DEBUG_TRACE, ("%s:: %d\n", __FUNCTION__, - pAd->CommonCfg.RadarDetect.ChMovingTime)); - - return TRUE; -} - -INT Set_LongPulseRadarTh_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - UINT8 Value; - - Value = simple_strtol(arg, 0, 10) > 10 ? 10 : simple_strtol(arg, 0, 10); - - pAd->CommonCfg.RadarDetect.LongPulseRadarTh = Value; - - DBGPRINT(RT_DEBUG_TRACE, ("%s:: %d\n", __FUNCTION__, - pAd->CommonCfg.RadarDetect.LongPulseRadarTh)); - - return TRUE; -} - - +#include "../../rt2870/common/dfs.c" diff --git a/drivers/staging/rt3070/common/eeprom.c b/drivers/staging/rt3070/common/eeprom.c index 63e1dc14d151..0c567d3dad0f 100644 --- a/drivers/staging/rt3070/common/eeprom.c +++ b/drivers/staging/rt3070/common/eeprom.c @@ -1,1498 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - eeprom.c - - Abstract: - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Name Date Modification logs -*/ -#include "../rt_config.h" - -// IRQL = PASSIVE_LEVEL -VOID RaiseClock( - IN PRTMP_ADAPTER pAd, - IN UINT32 *x) -{ - *x = *x | EESK; - RTMP_IO_WRITE32(pAd, E2PROM_CSR, *x); - RTMPusecDelay(1); // Max frequency = 1MHz in Spec. definition -} - -// IRQL = PASSIVE_LEVEL -VOID LowerClock( - IN PRTMP_ADAPTER pAd, - IN UINT32 *x) -{ - *x = *x & ~EESK; - RTMP_IO_WRITE32(pAd, E2PROM_CSR, *x); - RTMPusecDelay(1); -} - -// IRQL = PASSIVE_LEVEL -USHORT ShiftInBits( - IN PRTMP_ADAPTER pAd) -{ - UINT32 x,i; - USHORT data=0; - - RTMP_IO_READ32(pAd, E2PROM_CSR, &x); - - x &= ~( EEDO | EEDI); - - for(i=0; i<16; i++) - { - data = data << 1; - RaiseClock(pAd, &x); - - RTMP_IO_READ32(pAd, E2PROM_CSR, &x); - LowerClock(pAd, &x); //prevent read failed - - x &= ~(EEDI); - if(x & EEDO) - data |= 1; - } - - return data; -} - -// IRQL = PASSIVE_LEVEL -VOID ShiftOutBits( - IN PRTMP_ADAPTER pAd, - IN USHORT data, - IN USHORT count) -{ - UINT32 x,mask; - - mask = 0x01 << (count - 1); - RTMP_IO_READ32(pAd, E2PROM_CSR, &x); - - x &= ~(EEDO | EEDI); - - do - { - x &= ~EEDI; - if(data & mask) x |= EEDI; - - RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); - - RaiseClock(pAd, &x); - LowerClock(pAd, &x); - - mask = mask >> 1; - } while(mask); - - x &= ~EEDI; - RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); -} - -// IRQL = PASSIVE_LEVEL -VOID EEpromCleanup( - IN PRTMP_ADAPTER pAd) -{ - UINT32 x; - - RTMP_IO_READ32(pAd, E2PROM_CSR, &x); - - x &= ~(EECS | EEDI); - RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); - - RaiseClock(pAd, &x); - LowerClock(pAd, &x); -} - -VOID EWEN( - IN PRTMP_ADAPTER pAd) -{ - UINT32 x; - - // reset bits and set EECS - RTMP_IO_READ32(pAd, E2PROM_CSR, &x); - x &= ~(EEDI | EEDO | EESK); - x |= EECS; - RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); - - // kick a pulse - RaiseClock(pAd, &x); - LowerClock(pAd, &x); - - // output the read_opcode and six pulse in that order - ShiftOutBits(pAd, EEPROM_EWEN_OPCODE, 5); - ShiftOutBits(pAd, 0, 6); - - EEpromCleanup(pAd); -} - -VOID EWDS( - IN PRTMP_ADAPTER pAd) -{ - UINT32 x; - - // reset bits and set EECS - RTMP_IO_READ32(pAd, E2PROM_CSR, &x); - x &= ~(EEDI | EEDO | EESK); - x |= EECS; - RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); - - // kick a pulse - RaiseClock(pAd, &x); - LowerClock(pAd, &x); - - // output the read_opcode and six pulse in that order - ShiftOutBits(pAd, EEPROM_EWDS_OPCODE, 5); - ShiftOutBits(pAd, 0, 6); - - EEpromCleanup(pAd); -} - -// IRQL = PASSIVE_LEVEL -USHORT RTMP_EEPROM_READ16( - IN PRTMP_ADAPTER pAd, - IN USHORT Offset) -{ - UINT32 x; - USHORT data; - - if (pAd->NicConfig2.field.AntDiversity) - { - pAd->EepromAccess = TRUE; - } -//2008/09/11:KH add to support efuse<-- -//2008/09/11:KH add to support efuse--> -{ - Offset /= 2; - // reset bits and set EECS - RTMP_IO_READ32(pAd, E2PROM_CSR, &x); - x &= ~(EEDI | EEDO | EESK); - x |= EECS; - RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); - - // patch can not access e-Fuse issue - if (!IS_RT3090(pAd)) - { - // kick a pulse - RaiseClock(pAd, &x); - LowerClock(pAd, &x); - } - - // output the read_opcode and register number in that order - ShiftOutBits(pAd, EEPROM_READ_OPCODE, 3); - ShiftOutBits(pAd, Offset, pAd->EEPROMAddressNum); - - // Now read the data (16 bits) in from the selected EEPROM word - data = ShiftInBits(pAd); - - EEpromCleanup(pAd); - - // Antenna and EEPROM access are both using EESK pin, - // Therefor we should avoid accessing EESK at the same time - // Then restore antenna after EEPROM access - if ((pAd->NicConfig2.field.AntDiversity) || (pAd->RfIcType == RFIC_3020)) - { - pAd->EepromAccess = FALSE; - AsicSetRxAnt(pAd, pAd->RxAnt.Pair1PrimaryRxAnt); - } -} - return data; -} //ReadEEprom - -VOID RTMP_EEPROM_WRITE16( - IN PRTMP_ADAPTER pAd, - IN USHORT Offset, - IN USHORT Data) -{ - UINT32 x; - - if (pAd->NicConfig2.field.AntDiversity) - { - pAd->EepromAccess = TRUE; - } - //2008/09/11:KH add to support efuse<-- -//2008/09/11:KH add to support efuse--> - { - Offset /= 2; - - EWEN(pAd); - - // reset bits and set EECS - RTMP_IO_READ32(pAd, E2PROM_CSR, &x); - x &= ~(EEDI | EEDO | EESK); - x |= EECS; - RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); - - // patch can not access e-Fuse issue - if (!IS_RT3090(pAd)) - { - // kick a pulse - RaiseClock(pAd, &x); - LowerClock(pAd, &x); - } - - // output the read_opcode ,register number and data in that order - ShiftOutBits(pAd, EEPROM_WRITE_OPCODE, 3); - ShiftOutBits(pAd, Offset, pAd->EEPROMAddressNum); - ShiftOutBits(pAd, Data, 16); // 16-bit access - - // read DO status - RTMP_IO_READ32(pAd, E2PROM_CSR, &x); - - EEpromCleanup(pAd); - - RTMPusecDelay(10000); //delay for twp(MAX)=10ms - - EWDS(pAd); - - EEpromCleanup(pAd); - - // Antenna and EEPROM access are both using EESK pin, - // Therefor we should avoid accessing EESK at the same time - // Then restore antenna after EEPROM access - if ((pAd->NicConfig2.field.AntDiversity) || (pAd->RfIcType == RFIC_3020)) - { - pAd->EepromAccess = FALSE; - AsicSetRxAnt(pAd, pAd->RxAnt.Pair1PrimaryRxAnt); - } -} -} - -//2008/09/11:KH add to support efuse<-- -#ifdef RT30xx -/* - ======================================================================== - - Routine Description: - - Arguments: - - Return Value: - - IRQL = - - Note: - - ======================================================================== -*/ -UCHAR eFuseReadRegisters( - IN PRTMP_ADAPTER pAd, - IN USHORT Offset, - IN USHORT Length, - OUT USHORT* pData) -{ - EFUSE_CTRL_STRUC eFuseCtrlStruc; - int i; - USHORT efuseDataOffset; - UINT32 data; - - RTMP_IO_READ32(pAd, EFUSE_CTRL, (PUINT32) &eFuseCtrlStruc); - - //Step0. Write 10-bit of address to EFSROM_AIN (0x580, bit25:bit16). The address must be 16-byte alignment. - //Use the eeprom logical address and covert to address to block number - eFuseCtrlStruc.field.EFSROM_AIN = Offset & 0xfff0; - - //Step1. Write EFSROM_MODE (0x580, bit7:bit6) to 0. - eFuseCtrlStruc.field.EFSROM_MODE = 0; - - //Step2. Write EFSROM_KICK (0x580, bit30) to 1 to kick-off physical read procedure. - eFuseCtrlStruc.field.EFSROM_KICK = 1; - - NdisMoveMemory(&data, &eFuseCtrlStruc, 4); - RTMP_IO_WRITE32(pAd, EFUSE_CTRL, data); - - //Step3. Polling EFSROM_KICK(0x580, bit30) until it become 0 again. - i = 0; - while(i < 100) - { - //rtmp.HwMemoryReadDword(EFUSE_CTRL, (DWORD *) &eFuseCtrlStruc, 4); - RTMP_IO_READ32(pAd, EFUSE_CTRL, (PUINT32) &eFuseCtrlStruc); - if(eFuseCtrlStruc.field.EFSROM_KICK == 0) - { - break; - } - RTMPusecDelay(2); - i++; - } - - //if EFSROM_AOUT is not found in physical address, write 0xffff - if (eFuseCtrlStruc.field.EFSROM_AOUT == 0x3f) - { - for(i=0; i> (8*(Offset & 0x3)); -#endif - - NdisMoveMemory(pData, &data, Length); - } - - return (UCHAR) eFuseCtrlStruc.field.EFSROM_AOUT; - -} - -/* - ======================================================================== - - Routine Description: - - Arguments: - - Return Value: - - IRQL = - - Note: - - ======================================================================== -*/ -VOID eFusePhysicalReadRegisters( - IN PRTMP_ADAPTER pAd, - IN USHORT Offset, - IN USHORT Length, - OUT USHORT* pData) -{ - EFUSE_CTRL_STRUC eFuseCtrlStruc; - int i; - USHORT efuseDataOffset; - UINT32 data; - - RTMP_IO_READ32(pAd, EFUSE_CTRL, (PUINT32) &eFuseCtrlStruc); - - //Step0. Write 10-bit of address to EFSROM_AIN (0x580, bit25:bit16). The address must be 16-byte alignment. - eFuseCtrlStruc.field.EFSROM_AIN = Offset & 0xfff0; - - //Step1. Write EFSROM_MODE (0x580, bit7:bit6) to 1. - //Read in physical view - eFuseCtrlStruc.field.EFSROM_MODE = 1; - - //Step2. Write EFSROM_KICK (0x580, bit30) to 1 to kick-off physical read procedure. - eFuseCtrlStruc.field.EFSROM_KICK = 1; - - NdisMoveMemory(&data, &eFuseCtrlStruc, 4); - RTMP_IO_WRITE32(pAd, EFUSE_CTRL, data); - - //Step3. Polling EFSROM_KICK(0x580, bit30) until it become 0 again. - i = 0; - while(i < 100) - { - RTMP_IO_READ32(pAd, EFUSE_CTRL, (PUINT32) &eFuseCtrlStruc); - if(eFuseCtrlStruc.field.EFSROM_KICK == 0) - break; - RTMPusecDelay(2); - i++; - } - - //Step4. Read 16-byte of data from EFUSE_DATA0-3 (0x59C-0x590) - //Because the size of each EFUSE_DATA is 4 Bytes, the size of address of each is 2 bits. - //The previous 2 bits is the EFUSE_DATA number, the last 2 bits is used to decide which bytes - //Decide which EFUSE_DATA to read - //590:F E D C - //594:B A 9 8 - //598:7 6 5 4 - //59C:3 2 1 0 - efuseDataOffset = EFUSE_DATA3 - (Offset & 0xC) ; - - RTMP_IO_READ32(pAd, efuseDataOffset, &data); - -#ifdef RT_BIG_ENDIAN - data = data << (8*((Offset & 0x3)^0x2)); -#else - data = data >> (8*(Offset & 0x3)); -#endif - - NdisMoveMemory(pData, &data, Length); - -} - -/* - ======================================================================== - - Routine Description: - - Arguments: - - Return Value: - - IRQL = - - Note: - - ======================================================================== -*/ -VOID eFuseReadPhysical( - IN PRTMP_ADAPTER pAd, - IN PUSHORT lpInBuffer, - IN ULONG nInBufferSize, - OUT PUSHORT lpOutBuffer, - IN ULONG nOutBufferSize -) -{ - USHORT* pInBuf = (USHORT*)lpInBuffer; - USHORT* pOutBuf = (USHORT*)lpOutBuffer; - - USHORT Offset = pInBuf[0]; //addr - USHORT Length = pInBuf[1]; //length - int i; - - for(i=0; i> 2; - data = pData[0] & 0xffff; - //The offset should be 0x***10 or 0x***00 - if((Offset % 4) != 0) - { - eFuseDataBuffer[efuseDataOffset] = (eFuseDataBuffer[efuseDataOffset] & 0xffff) | (data << 16); - } - else - { - eFuseDataBuffer[efuseDataOffset] = (eFuseDataBuffer[efuseDataOffset] & 0xffff0000) | data; - } - - efuseDataOffset = EFUSE_DATA3; - for(i=0; i< 4; i++) - { - RTMP_IO_WRITE32(pAd, efuseDataOffset, eFuseDataBuffer[i]); - efuseDataOffset -= 4; - } - ///////////////////////////////////////////////////////////////// - - //Step1. Write 10-bit of address to EFSROM_AIN (0x580, bit25:bit16). The address must be 16-byte alignment. - eFuseCtrlStruc.field.EFSROM_AIN = Offset & 0xfff0; - - //Step2. Write EFSROM_MODE (0x580, bit7:bit6) to 3. - eFuseCtrlStruc.field.EFSROM_MODE = 3; - - //Step3. Write EFSROM_KICK (0x580, bit30) to 1 to kick-off physical write procedure. - eFuseCtrlStruc.field.EFSROM_KICK = 1; - - NdisMoveMemory(&data, &eFuseCtrlStruc, 4); - RTMP_IO_WRITE32(pAd, EFUSE_CTRL, data); - - //Step4. Polling EFSROM_KICK(0x580, bit30) until it become 0 again. It¡¦s done. - i = 0; - while(i < 100) - { - RTMP_IO_READ32(pAd, EFUSE_CTRL, (PUINT32) &eFuseCtrlStruc); - - if(eFuseCtrlStruc.field.EFSROM_KICK == 0) - break; - - RTMPusecDelay(2); - i++; - } -} - -/* - ======================================================================== - - Routine Description: - - Arguments: - - Return Value: - - IRQL = - - Note: - - ======================================================================== -*/ -NTSTATUS eFuseWriteRegisters( - IN PRTMP_ADAPTER pAd, - IN USHORT Offset, - IN USHORT Length, - IN USHORT* pData) -{ - USHORT i; - USHORT eFuseData; - USHORT LogicalAddress, BlkNum = 0xffff; - UCHAR EFSROM_AOUT; - - USHORT addr,tmpaddr, InBuf[3], tmpOffset; - USHORT buffer[8]; - BOOLEAN bWriteSuccess = TRUE; - - DBGPRINT(RT_DEBUG_TRACE, ("eFuseWriteRegisters Offset=%x, pData=%x\n", Offset, *pData)); - - //Step 0. find the entry in the mapping table - //The address of EEPROM is 2-bytes alignment. - //The last bit is used for alignment, so it must be 0. - tmpOffset = Offset & 0xfffe; - EFSROM_AOUT = eFuseReadRegisters(pAd, tmpOffset, 2, &eFuseData); - - if( EFSROM_AOUT == 0x3f) - { //find available logical address pointer - //the logical address does not exist, find an empty one - //from the first address of block 45=16*45=0x2d0 to the last address of block 47 - //==>48*16-3(reserved)=2FC - for (i=EFUSE_USAGE_MAP_START; i<=EFUSE_USAGE_MAP_END; i+=2) - { - //Retrive the logical block nubmer form each logical address pointer - //It will access two logical address pointer each time. - eFusePhysicalReadRegisters(pAd, i, 2, &LogicalAddress); - if( (LogicalAddress & 0xff) == 0) - {//Not used logical address pointer - BlkNum = i-EFUSE_USAGE_MAP_START; - break; - } - else if(( (LogicalAddress >> 8) & 0xff) == 0) - {//Not used logical address pointer - if (i != EFUSE_USAGE_MAP_END) - { - BlkNum = i-EFUSE_USAGE_MAP_START+1; - } - break; - } - } - } - else - { - BlkNum = EFSROM_AOUT; - } - - DBGPRINT(RT_DEBUG_TRACE, ("eFuseWriteRegisters BlkNum = %d \n", BlkNum)); - - if(BlkNum == 0xffff) - { - DBGPRINT(RT_DEBUG_TRACE, ("eFuseWriteRegisters: out of free E-fuse space!!!\n")); - return FALSE; - } - - //Step 1. Save data of this block which is pointed by the avaible logical address pointer - // read and save the original block data - for(i =0; i<8; i++) - { - addr = BlkNum * 0x10 ; - - InBuf[0] = addr+2*i; - InBuf[1] = 2; - InBuf[2] = 0x0; - - eFuseReadPhysical(pAd, &InBuf[0], 4, &InBuf[2], 2); - - buffer[i] = InBuf[2]; - } - - //Step 2. Update the data in buffer, and write the data to Efuse - buffer[ (Offset >> 1) % 8] = pData[0]; - - do - { - //Step 3. Write the data to Efuse - if(!bWriteSuccess) - { - for(i =0; i<8; i++) - { - addr = BlkNum * 0x10 ; - - InBuf[0] = addr+2*i; - InBuf[1] = 2; - InBuf[2] = buffer[i]; - - eFuseWritePhysical(pAd, &InBuf[0], 6, NULL, 2); - } - } - else - { - addr = BlkNum * 0x10 ; - - InBuf[0] = addr+(Offset % 16); - InBuf[1] = 2; - InBuf[2] = pData[0]; - - eFuseWritePhysical(pAd, &InBuf[0], 6, NULL, 2); - } - - //Step 4. Write mapping table - addr = EFUSE_USAGE_MAP_START+BlkNum; - - tmpaddr = addr; - - if(addr % 2 != 0) - addr = addr -1; - InBuf[0] = addr; - InBuf[1] = 2; - - //convert the address from 10 to 8 bit ( bit7, 6 = parity and bit5 ~ 0 = bit9~4), and write to logical map entry - tmpOffset = Offset; - tmpOffset >>= 4; - tmpOffset |= ((~((tmpOffset & 0x01) ^ ( tmpOffset >> 1 & 0x01) ^ (tmpOffset >> 2 & 0x01) ^ (tmpOffset >> 3 & 0x01))) << 6) & 0x40; - tmpOffset |= ((~( (tmpOffset >> 2 & 0x01) ^ (tmpOffset >> 3 & 0x01) ^ (tmpOffset >> 4 & 0x01) ^ ( tmpOffset >> 5 & 0x01))) << 7) & 0x80; - - // write the logical address - if(tmpaddr%2 != 0) - InBuf[2] = tmpOffset<<8; - else - InBuf[2] = tmpOffset; - - eFuseWritePhysical(pAd,&InBuf[0], 6, NULL, 0); - - //Step 5. Compare data if not the same, invalidate the mapping entry, then re-write the data until E-fuse is exhausted - bWriteSuccess = TRUE; - for(i =0; i<8; i++) - { - addr = BlkNum * 0x10 ; - - InBuf[0] = addr+2*i; - InBuf[1] = 2; - InBuf[2] = 0x0; - - eFuseReadPhysical(pAd, &InBuf[0], 4, &InBuf[2], 2); - - if(buffer[i] != InBuf[2]) - { - bWriteSuccess = FALSE; - break; - } - } - - //Step 6. invlidate mapping entry and find a free mapping entry if not succeed - if (!bWriteSuccess) - { - DBGPRINT(RT_DEBUG_TRACE, ("Not bWriteSuccess BlkNum = %d\n", BlkNum)); - - // the offset of current mapping entry - addr = EFUSE_USAGE_MAP_START+BlkNum; - - //find a new mapping entry - BlkNum = 0xffff; - for (i=EFUSE_USAGE_MAP_START; i<=EFUSE_USAGE_MAP_END; i+=2) - { - eFusePhysicalReadRegisters(pAd, i, 2, &LogicalAddress); - if( (LogicalAddress & 0xff) == 0) - { - BlkNum = i-EFUSE_USAGE_MAP_START; - break; - } - else if(( (LogicalAddress >> 8) & 0xff) == 0) - { - if (i != EFUSE_USAGE_MAP_END) - { - BlkNum = i+1-EFUSE_USAGE_MAP_START; - } - break; - } - } - DBGPRINT(RT_DEBUG_TRACE, ("Not bWriteSuccess new BlkNum = %d\n", BlkNum)); - if(BlkNum == 0xffff) - { - DBGPRINT(RT_DEBUG_TRACE, ("eFuseWriteRegisters: out of free E-fuse space!!!\n")); - return FALSE; - } - - //invalidate the original mapping entry if new entry is not found - tmpaddr = addr; - - if(addr % 2 != 0) - addr = addr -1; - InBuf[0] = addr; - InBuf[1] = 2; - - eFuseReadPhysical(pAd, &InBuf[0], 4, &InBuf[2], 2); - - // write the logical address - if(tmpaddr%2 != 0) - { - // Invalidate the high byte - for (i=8; i<15; i++) - { - if( ( (InBuf[2] >> i) & 0x01) == 0) - { - InBuf[2] |= (0x1 <> i) & 0x01) == 0) - { - InBuf[2] |= (0x1 <bUseEfuse) - return FALSE; - for (i = EFUSE_USAGE_MAP_START; i <= EFUSE_USAGE_MAP_END; i+=2) - { - eFusePhysicalReadRegisters(pAd, i, 2, &LogicalAddress); - if( (LogicalAddress & 0xff) == 0) - { - efusefreenum= (UCHAR) (EFUSE_USAGE_MAP_END-i+1); - break; - } - else if(( (LogicalAddress >> 8) & 0xff) == 0) - { - efusefreenum = (UCHAR) (EFUSE_USAGE_MAP_END-i); - break; - } - - if(i == EFUSE_USAGE_MAP_END) - efusefreenum = 0; - } - printk("efuseFreeNumber is %d\n",efusefreenum); - return TRUE; -} -INT set_eFusedump_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ -USHORT InBuf[3]; - INT i=0; - if(!pAd->bUseEfuse) - return FALSE; - for(i =0; i0) - { - - NdisMoveMemory(src, arg, strlen(arg)); - } - - else - { - - NdisMoveMemory(src, "RT30xxEEPROM.bin", BinFileSize); - } - - DBGPRINT(RT_DEBUG_TRACE, ("FileName=%s\n",src)); - buffer = kmalloc(MAX_EEPROM_BIN_FILE_SIZE, MEM_ALLOC_FLAG); - - if(buffer == NULL) - { - kfree(src); - return FALSE; -} - PDATA=kmalloc(sizeof(USHORT)*8,MEM_ALLOC_FLAG); - - if(PDATA==NULL) - { - kfree(src); - - kfree(buffer); - return FALSE; - } - /* Don't change to uid 0, let the file be opened as the "normal" user */ -#if 0 - orgfsuid = current->fsuid; - orgfsgid = current->fsgid; - current->fsuid=current->fsgid = 0; -#endif - orgfs = get_fs(); - set_fs(KERNEL_DS); - - if (src && *src) - { - srcf = filp_open(src, O_RDONLY, 0); - if (IS_ERR(srcf)) - { - DBGPRINT(RT_DEBUG_ERROR, ("--> Error %ld opening %s\n", -PTR_ERR(srcf),src)); - return FALSE; - } - else - { - // The object must have a read method - if (srcf->f_op && srcf->f_op->read) - { - memset(buffer, 0x00, MAX_EEPROM_BIN_FILE_SIZE); - while(srcf->f_op->read(srcf, &buffer[i], 1, &srcf->f_pos)==1) - { - DBGPRINT(RT_DEBUG_TRACE, ("%02X ",buffer[i])); - if((i+1)%8==0) - DBGPRINT(RT_DEBUG_TRACE, ("\n")); - i++; - if(i>=MAX_EEPROM_BIN_FILE_SIZE) - { - DBGPRINT(RT_DEBUG_ERROR, ("--> Error %ld reading %s, The file is too large[1024]\n", -PTR_ERR(srcf),src)); - kfree(PDATA); - kfree(buffer); - kfree(src); - return FALSE; - } - } - } - else - { - DBGPRINT(RT_DEBUG_ERROR, ("--> Error!! System doest not support read function\n")); - kfree(PDATA); - kfree(buffer); - kfree(src); - return FALSE; - } - } - - - } - else - { - DBGPRINT(RT_DEBUG_ERROR, ("--> Error src or srcf is null\n")); - kfree(PDATA); - kfree(buffer); - return FALSE; - - } - - - retval=filp_close(srcf,NULL); - - if (retval) - { - DBGPRINT(RT_DEBUG_TRACE, ("--> Error %d closing %s\n", -retval, src)); - } - set_fs(orgfs); -#if 0 - current->fsuid = orgfsuid; - current->fsgid = orgfsgid; -#endif - for(j=0;j48*16-3(reserved)=2FC - bAllocateNewBlk=TRUE; - for (i=EFUSE_USAGE_MAP_START; i<=EFUSE_USAGE_MAP_END; i+=2) - { - //Retrive the logical block nubmer form each logical address pointer - //It will access two logical address pointer each time. - eFusePhysicalReadRegisters(pAd, i, 2, &LogicalAddress); - if( (LogicalAddress & 0xff) == 0) - {//Not used logical address pointer - BlkNum = i-EFUSE_USAGE_MAP_START; - break; - } - else if(( (LogicalAddress >> 8) & 0xff) == 0) - {//Not used logical address pointer - if (i != EFUSE_USAGE_MAP_END) - { - BlkNum = i-EFUSE_USAGE_MAP_START+1; - } - break; - } - } - } - else - { - bAllocateNewBlk=FALSE; - BlkNum = EFSROM_AOUT; - } - - DBGPRINT(RT_DEBUG_TRACE, ("eFuseWriteRegisters BlkNum = %d \n", BlkNum)); - - if(BlkNum == 0xffff) - { - DBGPRINT(RT_DEBUG_TRACE, ("eFuseWriteRegisters: out of free E-fuse space!!!\n")); - return FALSE; - } - //Step 1.1.0 - //If the block is not existing in mapping table, create one - //and write down the 16-bytes data to the new block - if(bAllocateNewBlk) - { - DBGPRINT(RT_DEBUG_TRACE, ("Allocate New Blk\n")); - efuseDataOffset = EFUSE_DATA3; - for(i=0; i< 4; i++) - { - DBGPRINT(RT_DEBUG_TRACE, ("Allocate New Blk, Data%d=%04x%04x\n",3-i,pData[2*i+1],pData[2*i])); - tempbuffer=((pData[2*i+1]<<16)&0xffff0000)|pData[2*i]; - - - RTMP_IO_WRITE32(pAd, efuseDataOffset,tempbuffer); - efuseDataOffset -= 4; - - } - ///////////////////////////////////////////////////////////////// - - //Step1.1.1. Write 10-bit of address to EFSROM_AIN (0x580, bit25:bit16). The address must be 16-byte alignment. - eFuseCtrlStruc.field.EFSROM_AIN = BlkNum* 0x10 ; - - //Step1.1.2. Write EFSROM_MODE (0x580, bit7:bit6) to 3. - eFuseCtrlStruc.field.EFSROM_MODE = 3; - - //Step1.1.3. Write EFSROM_KICK (0x580, bit30) to 1 to kick-off physical write procedure. - eFuseCtrlStruc.field.EFSROM_KICK = 1; - - NdisMoveMemory(&data, &eFuseCtrlStruc, 4); - - RTMP_IO_WRITE32(pAd, EFUSE_CTRL, data); - - //Step1.1.4. Polling EFSROM_KICK(0x580, bit30) until it become 0 again. It¡¦s done. - i = 0; - while(i < 100) - { - RTMP_IO_READ32(pAd, EFUSE_CTRL, (PUINT32) &eFuseCtrlStruc); - - if(eFuseCtrlStruc.field.EFSROM_KICK == 0) - break; - - RTMPusecDelay(2); - i++; - } - - } - else - { //Step1.2. - //If the same logical number is existing, check if the writting data and the data - //saving in this block are the same. - ///////////////////////////////////////////////////////////////// - //read current values of 16-byte block - RTMP_IO_READ32(pAd, EFUSE_CTRL, (PUINT32) &eFuseCtrlStruc); - - //Step1.2.0. Write 10-bit of address to EFSROM_AIN (0x580, bit25:bit16). The address must be 16-byte alignment. - eFuseCtrlStruc.field.EFSROM_AIN = Offset & 0xfff0; - - //Step1.2.1. Write EFSROM_MODE (0x580, bit7:bit6) to 1. - eFuseCtrlStruc.field.EFSROM_MODE = 0; - - //Step1.2.2. Write EFSROM_KICK (0x580, bit30) to 1 to kick-off physical read procedure. - eFuseCtrlStruc.field.EFSROM_KICK = 1; - - NdisMoveMemory(&data, &eFuseCtrlStruc, 4); - RTMP_IO_WRITE32(pAd, EFUSE_CTRL, data); - - //Step1.2.3. Polling EFSROM_KICK(0x580, bit30) until it become 0 again. - i = 0; - while(i < 100) - { - RTMP_IO_READ32(pAd, EFUSE_CTRL, (PUINT32) &eFuseCtrlStruc); - - if(eFuseCtrlStruc.field.EFSROM_KICK == 0) - break; - RTMPusecDelay(2); - i++; - } - - //Step1.2.4. Read 16-byte of data from EFUSE_DATA0-3 (0x59C-0x590) - efuseDataOffset = EFUSE_DATA3; - for(i=0; i< 4; i++) - { - RTMP_IO_READ32(pAd, efuseDataOffset, (PUINT32) &buffer[i]); - efuseDataOffset -= 4; - } - //Step1.2.5. Check if the data of efuse and the writing data are the same. - for(i =0; i<4; i++) - { - tempbuffer=((pData[2*i+1]<<16)&0xffff0000)|pData[2*i]; - DBGPRINT(RT_DEBUG_TRACE, ("buffer[%d]=%x,pData[%d]=%x,pData[%d]=%x,tempbuffer=%x\n",i,buffer[i],2*i,pData[2*i],2*i+1,pData[2*i+1],tempbuffer)); - - if(((buffer[i]&0xffff0000)==(pData[2*i+1]<<16))&&((buffer[i]&0xffff)==pData[2*i])) - bNotWrite&=TRUE; - else - { - bNotWrite&=FALSE; - break; - } - } - if(!bNotWrite) - { - printk("The data is not the same\n"); - - for(i =0; i<8; i++) - { - addr = BlkNum * 0x10 ; - - InBuf[0] = addr+2*i; - InBuf[1] = 2; - InBuf[2] = pData[i]; - - eFuseWritePhysical(pAd, &InBuf[0], 6, NULL, 2); - } - - } - else - return TRUE; - } - - - - //Step 2. Write mapping table - addr = EFUSE_USAGE_MAP_START+BlkNum; - - tmpaddr = addr; - - if(addr % 2 != 0) - addr = addr -1; - InBuf[0] = addr; - InBuf[1] = 2; - - //convert the address from 10 to 8 bit ( bit7, 6 = parity and bit5 ~ 0 = bit9~4), and write to logical map entry - tmpOffset = Offset; - tmpOffset >>= 4; - tmpOffset |= ((~((tmpOffset & 0x01) ^ ( tmpOffset >> 1 & 0x01) ^ (tmpOffset >> 2 & 0x01) ^ (tmpOffset >> 3 & 0x01))) << 6) & 0x40; - tmpOffset |= ((~( (tmpOffset >> 2 & 0x01) ^ (tmpOffset >> 3 & 0x01) ^ (tmpOffset >> 4 & 0x01) ^ ( tmpOffset >> 5 & 0x01))) << 7) & 0x80; - - // write the logical address - if(tmpaddr%2 != 0) - InBuf[2] = tmpOffset<<8; - else - InBuf[2] = tmpOffset; - - eFuseWritePhysical(pAd,&InBuf[0], 6, NULL, 0); - - //Step 3. Compare data if not the same, invalidate the mapping entry, then re-write the data until E-fuse is exhausted - bWriteSuccess = TRUE; - for(i =0; i<8; i++) - { - addr = BlkNum * 0x10 ; - - InBuf[0] = addr+2*i; - InBuf[1] = 2; - InBuf[2] = 0x0; - - eFuseReadPhysical(pAd, &InBuf[0], 4, &InBuf[2], 2); - DBGPRINT(RT_DEBUG_TRACE, ("addr=%x, buffer[i]=%x,InBuf[2]=%x\n",InBuf[0],pData[i],InBuf[2])); - if(pData[i] != InBuf[2]) - { - bWriteSuccess = FALSE; - break; - } - } - - //Step 4. invlidate mapping entry and find a free mapping entry if not succeed - - if (!bWriteSuccess&&Loop<2) - { - DBGPRINT(RT_DEBUG_TRACE, ("eFuseWriteRegistersFromBin::Not bWriteSuccess BlkNum = %d\n", BlkNum)); - - // the offset of current mapping entry - addr = EFUSE_USAGE_MAP_START+BlkNum; - - //find a new mapping entry - BlkNum = 0xffff; - for (i=EFUSE_USAGE_MAP_START; i<=EFUSE_USAGE_MAP_END; i+=2) - { - eFusePhysicalReadRegisters(pAd, i, 2, &LogicalAddress); - if( (LogicalAddress & 0xff) == 0) - { - BlkNum = i-EFUSE_USAGE_MAP_START; - break; - } - else if(( (LogicalAddress >> 8) & 0xff) == 0) - { - if (i != EFUSE_USAGE_MAP_END) - { - BlkNum = i+1-EFUSE_USAGE_MAP_START; - } - break; - } - } - DBGPRINT(RT_DEBUG_TRACE, ("eFuseWriteRegistersFromBin::Not bWriteSuccess new BlkNum = %d\n", BlkNum)); - if(BlkNum == 0xffff) - { - DBGPRINT(RT_DEBUG_TRACE, ("eFuseWriteRegistersFromBin: out of free E-fuse space!!!\n")); - return FALSE; - } - - //invalidate the original mapping entry if new entry is not found - tmpaddr = addr; - - if(addr % 2 != 0) - addr = addr -1; - InBuf[0] = addr; - InBuf[1] = 2; - - eFuseReadPhysical(pAd, &InBuf[0], 4, &InBuf[2], 2); - - // write the logical address - if(tmpaddr%2 != 0) - { - // Invalidate the high byte - for (i=8; i<15; i++) - { - if( ( (InBuf[2] >> i) & 0x01) == 0) - { - InBuf[2] |= (0x1 <> i) & 0x01) == 0) - { - InBuf[2] |= (0x1 < - +#include "../../rt2870/common/eeprom.c" diff --git a/drivers/staging/rt3070/common/md5.c b/drivers/staging/rt3070/common/md5.c index 774776b4b8c3..07528842267a 100644 --- a/drivers/staging/rt3070/common/md5.c +++ b/drivers/staging/rt3070/common/md5.c @@ -1,1427 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - md5.c - - Abstract: - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Name Date Modification logs - jan 10-28-03 Initial - Rita 11-23-04 Modify MD5 and SHA-1 - Rita 10-14-05 Modify SHA-1 in big-endian platform - */ -#include "../rt_config.h" - -/** - * md5_mac: - * @key: pointer to the key used for MAC generation - * @key_len: length of the key in bytes - * @data: pointer to the data area for which the MAC is generated - * @data_len: length of the data in bytes - * @mac: pointer to the buffer holding space for the MAC; the buffer should - * have space for 128-bit (16 bytes) MD5 hash value - * - * md5_mac() determines the message authentication code by using secure hash - * MD5(key | data | key). - */ -void md5_mac(u8 *key, size_t key_len, u8 *data, size_t data_len, u8 *mac) -{ - MD5_CTX context; - - MD5Init(&context); - MD5Update(&context, key, key_len); - MD5Update(&context, data, data_len); - MD5Update(&context, key, key_len); - MD5Final(mac, &context); -} - -/** - * hmac_md5: - * @key: pointer to the key used for MAC generation - * @key_len: length of the key in bytes - * @data: pointer to the data area for which the MAC is generated - * @data_len: length of the data in bytes - * @mac: pointer to the buffer holding space for the MAC; the buffer should - * have space for 128-bit (16 bytes) MD5 hash value - * - * hmac_md5() determines the message authentication code using HMAC-MD5. - * This implementation is based on the sample code presented in RFC 2104. - */ -void hmac_md5(u8 *key, size_t key_len, u8 *data, size_t data_len, u8 *mac) -{ - MD5_CTX context; - u8 k_ipad[65]; /* inner padding - key XORd with ipad */ - u8 k_opad[65]; /* outer padding - key XORd with opad */ - u8 tk[16]; - int i; - - //assert(key != NULL && data != NULL && mac != NULL); - - /* if key is longer than 64 bytes reset it to key = MD5(key) */ - if (key_len > 64) { - MD5_CTX ttcontext; - - MD5Init(&ttcontext); - MD5Update(&ttcontext, key, key_len); - MD5Final(tk, &ttcontext); - //key=(PUCHAR)ttcontext.buf; - key = tk; - key_len = 16; - } - - /* the HMAC_MD5 transform looks like: - * - * MD5(K XOR opad, MD5(K XOR ipad, text)) - * - * where K is an n byte key - * ipad is the byte 0x36 repeated 64 times - * opad is the byte 0x5c repeated 64 times - * and text is the data being protected */ - - /* start out by storing key in pads */ - NdisZeroMemory(k_ipad, sizeof(k_ipad)); - NdisZeroMemory(k_opad, sizeof(k_opad)); - //assert(key_len < sizeof(k_ipad)); - NdisMoveMemory(k_ipad, key, key_len); - NdisMoveMemory(k_opad, key, key_len); - - /* XOR key with ipad and opad values */ - for (i = 0; i < 64; i++) { - k_ipad[i] ^= 0x36; - k_opad[i] ^= 0x5c; - } - - /* perform inner MD5 */ - MD5Init(&context); /* init context for 1st pass */ - MD5Update(&context, k_ipad, 64); /* start with inner pad */ - MD5Update(&context, data, data_len); /* then text of datagram */ - MD5Final(mac, &context); /* finish up 1st pass */ - - /* perform outer MD5 */ - MD5Init(&context); /* init context for 2nd pass */ - MD5Update(&context, k_opad, 64); /* start with outer pad */ - MD5Update(&context, mac, 16); /* then results of 1st hash */ - MD5Final(mac, &context); /* finish up 2nd pass */ -} - -#ifndef RT_BIG_ENDIAN -#define byteReverse(buf, len) /* Nothing */ -#else -void byteReverse(unsigned char *buf, unsigned longs); -void byteReverse(unsigned char *buf, unsigned longs) -{ - do { - *(UINT32 *)buf = SWAP32(*(UINT32 *)buf); - buf += 4; - } while (--longs); -} -#endif - - -/* ========================== MD5 implementation =========================== */ -// four base functions for MD5 -#define MD5_F1(x, y, z) (((x) & (y)) | ((~x) & (z))) -#define MD5_F2(x, y, z) (((x) & (z)) | ((y) & (~z))) -#define MD5_F3(x, y, z) ((x) ^ (y) ^ (z)) -#define MD5_F4(x, y, z) ((y) ^ ((x) | (~z))) -#define CYCLIC_LEFT_SHIFT(w, s) (((w) << (s)) | ((w) >> (32-(s)))) - -#define MD5Step(f, w, x, y, z, data, t, s) \ - ( w += f(x, y, z) + data + t, w = (CYCLIC_LEFT_SHIFT(w, s)) & 0xffffffff, w += x ) - - -/* - * Function Description: - * Initiate MD5 Context satisfied in RFC 1321 - * - * Arguments: - * pCtx Pointer to MD5 context - * - * Return Value: - * None - */ -VOID MD5Init(MD5_CTX *pCtx) -{ - pCtx->Buf[0]=0x67452301; - pCtx->Buf[1]=0xefcdab89; - pCtx->Buf[2]=0x98badcfe; - pCtx->Buf[3]=0x10325476; - - pCtx->LenInBitCount[0]=0; - pCtx->LenInBitCount[1]=0; -} - - -/* - * Function Description: - * Update MD5 Context, allow of an arrary of octets as the next portion - * of the message - * - * Arguments: - * pCtx Pointer to MD5 context - * pData Pointer to input data - * LenInBytes The length of input data (unit: byte) - * - * Return Value: - * None - * - * Note: - * Called after MD5Init or MD5Update(itself) - */ -VOID MD5Update(MD5_CTX *pCtx, UCHAR *pData, UINT32 LenInBytes) -{ - - UINT32 TfTimes; - UINT32 temp; - unsigned int i; - - temp = pCtx->LenInBitCount[0]; - - pCtx->LenInBitCount[0] = (UINT32) (pCtx->LenInBitCount[0] + (LenInBytes << 3)); - - if (pCtx->LenInBitCount[0] < temp) - pCtx->LenInBitCount[1]++; //carry in - - pCtx->LenInBitCount[1] += LenInBytes >> 29; - - // mod 64 bytes - temp = (temp >> 3) & 0x3f; - - // process lacks of 64-byte data - if (temp) - { - UCHAR *pAds = (UCHAR *) pCtx->Input + temp; - - if ((temp+LenInBytes) < 64) - { - NdisMoveMemory(pAds, (UCHAR *)pData, LenInBytes); - return; - } - - NdisMoveMemory(pAds, (UCHAR *)pData, 64-temp); - byteReverse(pCtx->Input, 16); - MD5Transform(pCtx->Buf, (UINT32 *)pCtx->Input); - - pData += 64-temp; - LenInBytes -= 64-temp; - } // end of if (temp) - - - TfTimes = (LenInBytes >> 6); - - for (i=TfTimes; i>0; i--) - { - NdisMoveMemory(pCtx->Input, (UCHAR *)pData, 64); - byteReverse(pCtx->Input, 16); - MD5Transform(pCtx->Buf, (UINT32 *)pCtx->Input); - pData += 64; - LenInBytes -= 64; - } // end of for - - // buffering lacks of 64-byte data - if(LenInBytes) - NdisMoveMemory(pCtx->Input, (UCHAR *)pData, LenInBytes); - -} - - -/* - * Function Description: - * Append padding bits and length of original message in the tail - * The message digest has to be completed in the end - * - * Arguments: - * Digest Output of Digest-Message for MD5 - * pCtx Pointer to MD5 context - * - * Return Value: - * None - * - * Note: - * Called after MD5Update - */ -VOID MD5Final(UCHAR Digest[16], MD5_CTX *pCtx) -{ - UCHAR Remainder; - UCHAR PadLenInBytes; - UCHAR *pAppend=0; - unsigned int i; - - Remainder = (UCHAR)((pCtx->LenInBitCount[0] >> 3) & 0x3f); - - PadLenInBytes = (Remainder < 56) ? (56-Remainder) : (120-Remainder); - - pAppend = (UCHAR *)pCtx->Input + Remainder; - - // padding bits without crossing block(64-byte based) boundary - if (Remainder < 56) - { - *pAppend = 0x80; - PadLenInBytes --; - - NdisZeroMemory((UCHAR *)pCtx->Input + Remainder+1, PadLenInBytes); - - // add data-length field, from low to high - for (i=0; i<4; i++) - { - pCtx->Input[56+i] = (UCHAR)((pCtx->LenInBitCount[0] >> (i << 3)) & 0xff); - pCtx->Input[60+i] = (UCHAR)((pCtx->LenInBitCount[1] >> (i << 3)) & 0xff); - } - - byteReverse(pCtx->Input, 16); - MD5Transform(pCtx->Buf, (UINT32 *)pCtx->Input); - } // end of if - - // padding bits with crossing block(64-byte based) boundary - else - { - // the first block === - *pAppend = 0x80; - PadLenInBytes --; - - NdisZeroMemory((UCHAR *)pCtx->Input + Remainder+1, (64-Remainder-1)); - PadLenInBytes -= (64 - Remainder - 1); - - byteReverse(pCtx->Input, 16); - MD5Transform(pCtx->Buf, (UINT32 *)pCtx->Input); - - - // the second block === - NdisZeroMemory((UCHAR *)pCtx->Input, PadLenInBytes); - - // add data-length field - for (i=0; i<4; i++) - { - pCtx->Input[56+i] = (UCHAR)((pCtx->LenInBitCount[0] >> (i << 3)) & 0xff); - pCtx->Input[60+i] = (UCHAR)((pCtx->LenInBitCount[1] >> (i << 3)) & 0xff); - } - - byteReverse(pCtx->Input, 16); - MD5Transform(pCtx->Buf, (UINT32 *)pCtx->Input); - } // end of else - - - NdisMoveMemory((UCHAR *)Digest, (UINT32 *)pCtx->Buf, 16); // output - byteReverse((UCHAR *)Digest, 4); - NdisZeroMemory(pCtx, sizeof(pCtx)); // memory free -} - - -/* - * Function Description: - * The central algorithm of MD5, consists of four rounds and sixteen - * steps per round - * - * Arguments: - * Buf Buffers of four states (output: 16 bytes) - * Mes Input data (input: 64 bytes) - * - * Return Value: - * None - * - * Note: - * Called by MD5Update or MD5Final - */ -VOID MD5Transform(UINT32 Buf[4], UINT32 Mes[16]) -{ - UINT32 Reg[4], Temp; - unsigned int i; - - static UCHAR LShiftVal[16] = - { - 7, 12, 17, 22, - 5, 9 , 14, 20, - 4, 11, 16, 23, - 6, 10, 15, 21, - }; - - - // [equal to 4294967296*abs(sin(index))] - static UINT32 MD5Table[64] = - { - 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, - 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, - 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, - 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, - - 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, - 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, - 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, - 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, - - 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, - 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, - 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, - 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, - - 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, - 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, - 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, - 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 - }; - - - for (i=0; i<4; i++) - Reg[i]=Buf[i]; - - - // 64 steps in MD5 algorithm - for (i=0; i<16; i++) - { - MD5Step(MD5_F1, Reg[0], Reg[1], Reg[2], Reg[3], Mes[i], - MD5Table[i], LShiftVal[i & 0x3]); - - // one-word right shift - Temp = Reg[3]; - Reg[3] = Reg[2]; - Reg[2] = Reg[1]; - Reg[1] = Reg[0]; - Reg[0] = Temp; - } - for (i=16; i<32; i++) - { - MD5Step(MD5_F2, Reg[0], Reg[1], Reg[2], Reg[3], Mes[(5*(i & 0xf)+1) & 0xf], - MD5Table[i], LShiftVal[(0x1 << 2)+(i & 0x3)]); - - // one-word right shift - Temp = Reg[3]; - Reg[3] = Reg[2]; - Reg[2] = Reg[1]; - Reg[1] = Reg[0]; - Reg[0] = Temp; - } - for (i=32; i<48; i++) - { - MD5Step(MD5_F3, Reg[0], Reg[1], Reg[2], Reg[3], Mes[(3*(i & 0xf)+5) & 0xf], - MD5Table[i], LShiftVal[(0x1 << 3)+(i & 0x3)]); - - // one-word right shift - Temp = Reg[3]; - Reg[3] = Reg[2]; - Reg[2] = Reg[1]; - Reg[1] = Reg[0]; - Reg[0] = Temp; - } - for (i=48; i<64; i++) - { - MD5Step(MD5_F4, Reg[0], Reg[1], Reg[2], Reg[3], Mes[(7*(i & 0xf)) & 0xf], - MD5Table[i], LShiftVal[(0x3 << 2)+(i & 0x3)]); - - // one-word right shift - Temp = Reg[3]; - Reg[3] = Reg[2]; - Reg[2] = Reg[1]; - Reg[1] = Reg[0]; - Reg[0] = Temp; - } - - - // (temporary)output - for (i=0; i<4; i++) - Buf[i] += Reg[i]; - -} - - - -/* ========================= SHA-1 implementation ========================== */ -// four base functions for SHA-1 -#define SHA1_F1(b, c, d) (((b) & (c)) | ((~b) & (d))) -#define SHA1_F2(b, c, d) ((b) ^ (c) ^ (d)) -#define SHA1_F3(b, c, d) (((b) & (c)) | ((b) & (d)) | ((c) & (d))) - - -#define SHA1Step(f, a, b, c, d, e, w, k) \ - ( e += ( f(b, c, d) + w + k + CYCLIC_LEFT_SHIFT(a, 5)) & 0xffffffff, \ - b = CYCLIC_LEFT_SHIFT(b, 30) ) - -//Initiate SHA-1 Context satisfied in RFC 3174 -VOID SHAInit(SHA_CTX *pCtx) -{ - pCtx->Buf[0]=0x67452301; - pCtx->Buf[1]=0xefcdab89; - pCtx->Buf[2]=0x98badcfe; - pCtx->Buf[3]=0x10325476; - pCtx->Buf[4]=0xc3d2e1f0; - - pCtx->LenInBitCount[0]=0; - pCtx->LenInBitCount[1]=0; -} - -/* - * Function Description: - * Update SHA-1 Context, allow of an arrary of octets as the next - * portion of the message - * - * Arguments: - * pCtx Pointer to SHA-1 context - * pData Pointer to input data - * LenInBytes The length of input data (unit: byte) - * - * Return Value: - * error indicate more than pow(2,64) bits of data - * - * Note: - * Called after SHAInit or SHAUpdate(itself) - */ -UCHAR SHAUpdate(SHA_CTX *pCtx, UCHAR *pData, UINT32 LenInBytes) -{ - UINT32 TfTimes; - UINT32 temp1,temp2; - unsigned int i; - UCHAR err=1; - - temp1 = pCtx->LenInBitCount[0]; - temp2 = pCtx->LenInBitCount[1]; - - pCtx->LenInBitCount[0] = (UINT32) (pCtx->LenInBitCount[0] + (LenInBytes << 3)); - if (pCtx->LenInBitCount[0] < temp1) - pCtx->LenInBitCount[1]++; //carry in - - - pCtx->LenInBitCount[1] = (UINT32) (pCtx->LenInBitCount[1] +(LenInBytes >> 29)); - if (pCtx->LenInBitCount[1] < temp2) - return (err); //check total length of original data - - - // mod 64 bytes - temp1 = (temp1 >> 3) & 0x3f; - - // process lacks of 64-byte data - if (temp1) - { - UCHAR *pAds = (UCHAR *) pCtx->Input + temp1; - - if ((temp1+LenInBytes) < 64) - { - NdisMoveMemory(pAds, (UCHAR *)pData, LenInBytes); - return (0); - } - - NdisMoveMemory(pAds, (UCHAR *)pData, 64-temp1); - byteReverse((UCHAR *)pCtx->Input, 16); - - NdisZeroMemory((UCHAR *)pCtx->Input + 64, 16); - SHATransform(pCtx->Buf, (UINT32 *)pCtx->Input); - - pData += 64-temp1; - LenInBytes -= 64-temp1; - } // end of if (temp1) - - - TfTimes = (LenInBytes >> 6); - - for (i=TfTimes; i>0; i--) - { - NdisMoveMemory(pCtx->Input, (UCHAR *)pData, 64); - byteReverse((UCHAR *)pCtx->Input, 16); - - NdisZeroMemory((UCHAR *)pCtx->Input + 64, 16); - SHATransform(pCtx->Buf, (UINT32 *)pCtx->Input); - pData += 64; - LenInBytes -= 64; - } // end of for - - // buffering lacks of 64-byte data - if(LenInBytes) - NdisMoveMemory(pCtx->Input, (UCHAR *)pData, LenInBytes); - - return (0); - -} - -// Append padding bits and length of original message in the tail -// The message digest has to be completed in the end -VOID SHAFinal(SHA_CTX *pCtx, UCHAR Digest[20]) -{ - UCHAR Remainder; - UCHAR PadLenInBytes; - UCHAR *pAppend=0; - unsigned int i; - - Remainder = (UCHAR)((pCtx->LenInBitCount[0] >> 3) & 0x3f); - - pAppend = (UCHAR *)pCtx->Input + Remainder; - - PadLenInBytes = (Remainder < 56) ? (56-Remainder) : (120-Remainder); - - // padding bits without crossing block(64-byte based) boundary - if (Remainder < 56) - { - *pAppend = 0x80; - PadLenInBytes --; - - NdisZeroMemory((UCHAR *)pCtx->Input + Remainder+1, PadLenInBytes); - - // add data-length field, from high to low - for (i=0; i<4; i++) - { - pCtx->Input[56+i] = (UCHAR)((pCtx->LenInBitCount[1] >> ((3-i) << 3)) & 0xff); - pCtx->Input[60+i] = (UCHAR)((pCtx->LenInBitCount[0] >> ((3-i) << 3)) & 0xff); - } - - byteReverse((UCHAR *)pCtx->Input, 16); - NdisZeroMemory((UCHAR *)pCtx->Input + 64, 14); - SHATransform(pCtx->Buf, (UINT32 *)pCtx->Input); - } // end of if - - // padding bits with crossing block(64-byte based) boundary - else - { - // the first block === - *pAppend = 0x80; - PadLenInBytes --; - - NdisZeroMemory((UCHAR *)pCtx->Input + Remainder+1, (64-Remainder-1)); - PadLenInBytes -= (64 - Remainder - 1); - - byteReverse((UCHAR *)pCtx->Input, 16); - NdisZeroMemory((UCHAR *)pCtx->Input + 64, 16); - SHATransform(pCtx->Buf, (UINT32 *)pCtx->Input); - - - // the second block === - NdisZeroMemory((UCHAR *)pCtx->Input, PadLenInBytes); - - // add data-length field - for (i=0; i<4; i++) - { - pCtx->Input[56+i] = (UCHAR)((pCtx->LenInBitCount[1] >> ((3-i) << 3)) & 0xff); - pCtx->Input[60+i] = (UCHAR)((pCtx->LenInBitCount[0] >> ((3-i) << 3)) & 0xff); - } - - byteReverse((UCHAR *)pCtx->Input, 16); - NdisZeroMemory((UCHAR *)pCtx->Input + 64, 16); - SHATransform(pCtx->Buf, (UINT32 *)pCtx->Input); - } // end of else - - - //Output, bytereverse - for (i=0; i<20; i++) - { - Digest [i] = (UCHAR)(pCtx->Buf[i>>2] >> 8*(3-(i & 0x3))); - } - - NdisZeroMemory(pCtx, sizeof(pCtx)); // memory free -} - - -// The central algorithm of SHA-1, consists of four rounds and -// twenty steps per round -VOID SHATransform(UINT32 Buf[5], UINT32 Mes[20]) -{ - UINT32 Reg[5],Temp; - unsigned int i; - UINT32 W[80]; - - static UINT32 SHA1Table[4] = { 0x5a827999, 0x6ed9eba1, - 0x8f1bbcdc, 0xca62c1d6 }; - - Reg[0]=Buf[0]; - Reg[1]=Buf[1]; - Reg[2]=Buf[2]; - Reg[3]=Buf[3]; - Reg[4]=Buf[4]; - - //the first octet of a word is stored in the 0th element, bytereverse - for(i = 0; i < 16; i++) - { - W[i] = (Mes[i] >> 24) & 0xff; - W[i] |= (Mes[i] >> 8 ) & 0xff00; - W[i] |= (Mes[i] << 8 ) & 0xff0000; - W[i] |= (Mes[i] << 24) & 0xff000000; - } - - - for (i = 0; i < 64; i++) - W[16+i] = CYCLIC_LEFT_SHIFT(W[i] ^ W[2+i] ^ W[8+i] ^ W[13+i], 1); - - - // 80 steps in SHA-1 algorithm - for (i=0; i<80; i++) - { - if (i<20) - SHA1Step(SHA1_F1, Reg[0], Reg[1], Reg[2], Reg[3], Reg[4], - W[i], SHA1Table[0]); - - else if (i>=20 && i<40) - SHA1Step(SHA1_F2, Reg[0], Reg[1], Reg[2], Reg[3], Reg[4], - W[i], SHA1Table[1]); - - else if (i>=40 && i<60) - SHA1Step(SHA1_F3, Reg[0], Reg[1], Reg[2], Reg[3], Reg[4], - W[i], SHA1Table[2]); - - else - SHA1Step(SHA1_F2, Reg[0], Reg[1], Reg[2], Reg[3], Reg[4], - W[i], SHA1Table[3]); - - - // one-word right shift - Temp = Reg[4]; - Reg[4] = Reg[3]; - Reg[3] = Reg[2]; - Reg[2] = Reg[1]; - Reg[1] = Reg[0]; - Reg[0] = Temp; - - } // end of for-loop - - - // (temporary)output - for (i=0; i<5; i++) - Buf[i] += Reg[i]; - -} - - -/* ========================= AES En/Decryption ========================== */ - -/* forward S-box */ -static uint32 FSb[256] = -{ - 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, - 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, - 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, - 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, - 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, - 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, - 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, - 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, - 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, - 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, - 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, - 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, - 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, - 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, - 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, - 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, - 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, - 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, - 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, - 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, - 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, - 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, - 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, - 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, - 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, - 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, - 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, - 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, - 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, - 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, - 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, - 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 -}; - -/* forward table */ -#define FT \ -\ - V(C6,63,63,A5), V(F8,7C,7C,84), V(EE,77,77,99), V(F6,7B,7B,8D), \ - V(FF,F2,F2,0D), V(D6,6B,6B,BD), V(DE,6F,6F,B1), V(91,C5,C5,54), \ - V(60,30,30,50), V(02,01,01,03), V(CE,67,67,A9), V(56,2B,2B,7D), \ - V(E7,FE,FE,19), V(B5,D7,D7,62), V(4D,AB,AB,E6), V(EC,76,76,9A), \ - V(8F,CA,CA,45), V(1F,82,82,9D), V(89,C9,C9,40), V(FA,7D,7D,87), \ - V(EF,FA,FA,15), V(B2,59,59,EB), V(8E,47,47,C9), V(FB,F0,F0,0B), \ - V(41,AD,AD,EC), V(B3,D4,D4,67), V(5F,A2,A2,FD), V(45,AF,AF,EA), \ - V(23,9C,9C,BF), V(53,A4,A4,F7), V(E4,72,72,96), V(9B,C0,C0,5B), \ - V(75,B7,B7,C2), V(E1,FD,FD,1C), V(3D,93,93,AE), V(4C,26,26,6A), \ - V(6C,36,36,5A), V(7E,3F,3F,41), V(F5,F7,F7,02), V(83,CC,CC,4F), \ - V(68,34,34,5C), V(51,A5,A5,F4), V(D1,E5,E5,34), V(F9,F1,F1,08), \ - V(E2,71,71,93), V(AB,D8,D8,73), V(62,31,31,53), V(2A,15,15,3F), \ - V(08,04,04,0C), V(95,C7,C7,52), V(46,23,23,65), V(9D,C3,C3,5E), \ - V(30,18,18,28), V(37,96,96,A1), V(0A,05,05,0F), V(2F,9A,9A,B5), \ - V(0E,07,07,09), V(24,12,12,36), V(1B,80,80,9B), V(DF,E2,E2,3D), \ - V(CD,EB,EB,26), V(4E,27,27,69), V(7F,B2,B2,CD), V(EA,75,75,9F), \ - V(12,09,09,1B), V(1D,83,83,9E), V(58,2C,2C,74), V(34,1A,1A,2E), \ - V(36,1B,1B,2D), V(DC,6E,6E,B2), V(B4,5A,5A,EE), V(5B,A0,A0,FB), \ - V(A4,52,52,F6), V(76,3B,3B,4D), V(B7,D6,D6,61), V(7D,B3,B3,CE), \ - V(52,29,29,7B), V(DD,E3,E3,3E), V(5E,2F,2F,71), V(13,84,84,97), \ - V(A6,53,53,F5), V(B9,D1,D1,68), V(00,00,00,00), V(C1,ED,ED,2C), \ - V(40,20,20,60), V(E3,FC,FC,1F), V(79,B1,B1,C8), V(B6,5B,5B,ED), \ - V(D4,6A,6A,BE), V(8D,CB,CB,46), V(67,BE,BE,D9), V(72,39,39,4B), \ - V(94,4A,4A,DE), V(98,4C,4C,D4), V(B0,58,58,E8), V(85,CF,CF,4A), \ - V(BB,D0,D0,6B), V(C5,EF,EF,2A), V(4F,AA,AA,E5), V(ED,FB,FB,16), \ - V(86,43,43,C5), V(9A,4D,4D,D7), V(66,33,33,55), V(11,85,85,94), \ - V(8A,45,45,CF), V(E9,F9,F9,10), V(04,02,02,06), V(FE,7F,7F,81), \ - V(A0,50,50,F0), V(78,3C,3C,44), V(25,9F,9F,BA), V(4B,A8,A8,E3), \ - V(A2,51,51,F3), V(5D,A3,A3,FE), V(80,40,40,C0), V(05,8F,8F,8A), \ - V(3F,92,92,AD), V(21,9D,9D,BC), V(70,38,38,48), V(F1,F5,F5,04), \ - V(63,BC,BC,DF), V(77,B6,B6,C1), V(AF,DA,DA,75), V(42,21,21,63), \ - V(20,10,10,30), V(E5,FF,FF,1A), V(FD,F3,F3,0E), V(BF,D2,D2,6D), \ - V(81,CD,CD,4C), V(18,0C,0C,14), V(26,13,13,35), V(C3,EC,EC,2F), \ - V(BE,5F,5F,E1), V(35,97,97,A2), V(88,44,44,CC), V(2E,17,17,39), \ - V(93,C4,C4,57), V(55,A7,A7,F2), V(FC,7E,7E,82), V(7A,3D,3D,47), \ - V(C8,64,64,AC), V(BA,5D,5D,E7), V(32,19,19,2B), V(E6,73,73,95), \ - V(C0,60,60,A0), V(19,81,81,98), V(9E,4F,4F,D1), V(A3,DC,DC,7F), \ - V(44,22,22,66), V(54,2A,2A,7E), V(3B,90,90,AB), V(0B,88,88,83), \ - V(8C,46,46,CA), V(C7,EE,EE,29), V(6B,B8,B8,D3), V(28,14,14,3C), \ - V(A7,DE,DE,79), V(BC,5E,5E,E2), V(16,0B,0B,1D), V(AD,DB,DB,76), \ - V(DB,E0,E0,3B), V(64,32,32,56), V(74,3A,3A,4E), V(14,0A,0A,1E), \ - V(92,49,49,DB), V(0C,06,06,0A), V(48,24,24,6C), V(B8,5C,5C,E4), \ - V(9F,C2,C2,5D), V(BD,D3,D3,6E), V(43,AC,AC,EF), V(C4,62,62,A6), \ - V(39,91,91,A8), V(31,95,95,A4), V(D3,E4,E4,37), V(F2,79,79,8B), \ - V(D5,E7,E7,32), V(8B,C8,C8,43), V(6E,37,37,59), V(DA,6D,6D,B7), \ - V(01,8D,8D,8C), V(B1,D5,D5,64), V(9C,4E,4E,D2), V(49,A9,A9,E0), \ - V(D8,6C,6C,B4), V(AC,56,56,FA), V(F3,F4,F4,07), V(CF,EA,EA,25), \ - V(CA,65,65,AF), V(F4,7A,7A,8E), V(47,AE,AE,E9), V(10,08,08,18), \ - V(6F,BA,BA,D5), V(F0,78,78,88), V(4A,25,25,6F), V(5C,2E,2E,72), \ - V(38,1C,1C,24), V(57,A6,A6,F1), V(73,B4,B4,C7), V(97,C6,C6,51), \ - V(CB,E8,E8,23), V(A1,DD,DD,7C), V(E8,74,74,9C), V(3E,1F,1F,21), \ - V(96,4B,4B,DD), V(61,BD,BD,DC), V(0D,8B,8B,86), V(0F,8A,8A,85), \ - V(E0,70,70,90), V(7C,3E,3E,42), V(71,B5,B5,C4), V(CC,66,66,AA), \ - V(90,48,48,D8), V(06,03,03,05), V(F7,F6,F6,01), V(1C,0E,0E,12), \ - V(C2,61,61,A3), V(6A,35,35,5F), V(AE,57,57,F9), V(69,B9,B9,D0), \ - V(17,86,86,91), V(99,C1,C1,58), V(3A,1D,1D,27), V(27,9E,9E,B9), \ - V(D9,E1,E1,38), V(EB,F8,F8,13), V(2B,98,98,B3), V(22,11,11,33), \ - V(D2,69,69,BB), V(A9,D9,D9,70), V(07,8E,8E,89), V(33,94,94,A7), \ - V(2D,9B,9B,B6), V(3C,1E,1E,22), V(15,87,87,92), V(C9,E9,E9,20), \ - V(87,CE,CE,49), V(AA,55,55,FF), V(50,28,28,78), V(A5,DF,DF,7A), \ - V(03,8C,8C,8F), V(59,A1,A1,F8), V(09,89,89,80), V(1A,0D,0D,17), \ - V(65,BF,BF,DA), V(D7,E6,E6,31), V(84,42,42,C6), V(D0,68,68,B8), \ - V(82,41,41,C3), V(29,99,99,B0), V(5A,2D,2D,77), V(1E,0F,0F,11), \ - V(7B,B0,B0,CB), V(A8,54,54,FC), V(6D,BB,BB,D6), V(2C,16,16,3A) - -#define V(a,b,c,d) 0x##a##b##c##d -static uint32 FT0[256] = { FT }; -#undef V - -#define V(a,b,c,d) 0x##d##a##b##c -static uint32 FT1[256] = { FT }; -#undef V - -#define V(a,b,c,d) 0x##c##d##a##b -static uint32 FT2[256] = { FT }; -#undef V - -#define V(a,b,c,d) 0x##b##c##d##a -static uint32 FT3[256] = { FT }; -#undef V - -#undef FT - -/* reverse S-box */ - -static uint32 RSb[256] = -{ - 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, - 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, - 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, - 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, - 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, - 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, - 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, - 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, - 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, - 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, - 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, - 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, - 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, - 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, - 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, - 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, - 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, - 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, - 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, - 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, - 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, - 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, - 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, - 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, - 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, - 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, - 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, - 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, - 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, - 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, - 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, - 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D -}; - -/* reverse table */ - -#define RT \ -\ - V(51,F4,A7,50), V(7E,41,65,53), V(1A,17,A4,C3), V(3A,27,5E,96), \ - V(3B,AB,6B,CB), V(1F,9D,45,F1), V(AC,FA,58,AB), V(4B,E3,03,93), \ - V(20,30,FA,55), V(AD,76,6D,F6), V(88,CC,76,91), V(F5,02,4C,25), \ - V(4F,E5,D7,FC), V(C5,2A,CB,D7), V(26,35,44,80), V(B5,62,A3,8F), \ - V(DE,B1,5A,49), V(25,BA,1B,67), V(45,EA,0E,98), V(5D,FE,C0,E1), \ - V(C3,2F,75,02), V(81,4C,F0,12), V(8D,46,97,A3), V(6B,D3,F9,C6), \ - V(03,8F,5F,E7), V(15,92,9C,95), V(BF,6D,7A,EB), V(95,52,59,DA), \ - V(D4,BE,83,2D), V(58,74,21,D3), V(49,E0,69,29), V(8E,C9,C8,44), \ - V(75,C2,89,6A), V(F4,8E,79,78), V(99,58,3E,6B), V(27,B9,71,DD), \ - V(BE,E1,4F,B6), V(F0,88,AD,17), V(C9,20,AC,66), V(7D,CE,3A,B4), \ - V(63,DF,4A,18), V(E5,1A,31,82), V(97,51,33,60), V(62,53,7F,45), \ - V(B1,64,77,E0), V(BB,6B,AE,84), V(FE,81,A0,1C), V(F9,08,2B,94), \ - V(70,48,68,58), V(8F,45,FD,19), V(94,DE,6C,87), V(52,7B,F8,B7), \ - V(AB,73,D3,23), V(72,4B,02,E2), V(E3,1F,8F,57), V(66,55,AB,2A), \ - V(B2,EB,28,07), V(2F,B5,C2,03), V(86,C5,7B,9A), V(D3,37,08,A5), \ - V(30,28,87,F2), V(23,BF,A5,B2), V(02,03,6A,BA), V(ED,16,82,5C), \ - V(8A,CF,1C,2B), V(A7,79,B4,92), V(F3,07,F2,F0), V(4E,69,E2,A1), \ - V(65,DA,F4,CD), V(06,05,BE,D5), V(D1,34,62,1F), V(C4,A6,FE,8A), \ - V(34,2E,53,9D), V(A2,F3,55,A0), V(05,8A,E1,32), V(A4,F6,EB,75), \ - V(0B,83,EC,39), V(40,60,EF,AA), V(5E,71,9F,06), V(BD,6E,10,51), \ - V(3E,21,8A,F9), V(96,DD,06,3D), V(DD,3E,05,AE), V(4D,E6,BD,46), \ - V(91,54,8D,B5), V(71,C4,5D,05), V(04,06,D4,6F), V(60,50,15,FF), \ - V(19,98,FB,24), V(D6,BD,E9,97), V(89,40,43,CC), V(67,D9,9E,77), \ - V(B0,E8,42,BD), V(07,89,8B,88), V(E7,19,5B,38), V(79,C8,EE,DB), \ - V(A1,7C,0A,47), V(7C,42,0F,E9), V(F8,84,1E,C9), V(00,00,00,00), \ - V(09,80,86,83), V(32,2B,ED,48), V(1E,11,70,AC), V(6C,5A,72,4E), \ - V(FD,0E,FF,FB), V(0F,85,38,56), V(3D,AE,D5,1E), V(36,2D,39,27), \ - V(0A,0F,D9,64), V(68,5C,A6,21), V(9B,5B,54,D1), V(24,36,2E,3A), \ - V(0C,0A,67,B1), V(93,57,E7,0F), V(B4,EE,96,D2), V(1B,9B,91,9E), \ - V(80,C0,C5,4F), V(61,DC,20,A2), V(5A,77,4B,69), V(1C,12,1A,16), \ - V(E2,93,BA,0A), V(C0,A0,2A,E5), V(3C,22,E0,43), V(12,1B,17,1D), \ - V(0E,09,0D,0B), V(F2,8B,C7,AD), V(2D,B6,A8,B9), V(14,1E,A9,C8), \ - V(57,F1,19,85), V(AF,75,07,4C), V(EE,99,DD,BB), V(A3,7F,60,FD), \ - V(F7,01,26,9F), V(5C,72,F5,BC), V(44,66,3B,C5), V(5B,FB,7E,34), \ - V(8B,43,29,76), V(CB,23,C6,DC), V(B6,ED,FC,68), V(B8,E4,F1,63), \ - V(D7,31,DC,CA), V(42,63,85,10), V(13,97,22,40), V(84,C6,11,20), \ - V(85,4A,24,7D), V(D2,BB,3D,F8), V(AE,F9,32,11), V(C7,29,A1,6D), \ - V(1D,9E,2F,4B), V(DC,B2,30,F3), V(0D,86,52,EC), V(77,C1,E3,D0), \ - V(2B,B3,16,6C), V(A9,70,B9,99), V(11,94,48,FA), V(47,E9,64,22), \ - V(A8,FC,8C,C4), V(A0,F0,3F,1A), V(56,7D,2C,D8), V(22,33,90,EF), \ - V(87,49,4E,C7), V(D9,38,D1,C1), V(8C,CA,A2,FE), V(98,D4,0B,36), \ - V(A6,F5,81,CF), V(A5,7A,DE,28), V(DA,B7,8E,26), V(3F,AD,BF,A4), \ - V(2C,3A,9D,E4), V(50,78,92,0D), V(6A,5F,CC,9B), V(54,7E,46,62), \ - V(F6,8D,13,C2), V(90,D8,B8,E8), V(2E,39,F7,5E), V(82,C3,AF,F5), \ - V(9F,5D,80,BE), V(69,D0,93,7C), V(6F,D5,2D,A9), V(CF,25,12,B3), \ - V(C8,AC,99,3B), V(10,18,7D,A7), V(E8,9C,63,6E), V(DB,3B,BB,7B), \ - V(CD,26,78,09), V(6E,59,18,F4), V(EC,9A,B7,01), V(83,4F,9A,A8), \ - V(E6,95,6E,65), V(AA,FF,E6,7E), V(21,BC,CF,08), V(EF,15,E8,E6), \ - V(BA,E7,9B,D9), V(4A,6F,36,CE), V(EA,9F,09,D4), V(29,B0,7C,D6), \ - V(31,A4,B2,AF), V(2A,3F,23,31), V(C6,A5,94,30), V(35,A2,66,C0), \ - V(74,4E,BC,37), V(FC,82,CA,A6), V(E0,90,D0,B0), V(33,A7,D8,15), \ - V(F1,04,98,4A), V(41,EC,DA,F7), V(7F,CD,50,0E), V(17,91,F6,2F), \ - V(76,4D,D6,8D), V(43,EF,B0,4D), V(CC,AA,4D,54), V(E4,96,04,DF), \ - V(9E,D1,B5,E3), V(4C,6A,88,1B), V(C1,2C,1F,B8), V(46,65,51,7F), \ - V(9D,5E,EA,04), V(01,8C,35,5D), V(FA,87,74,73), V(FB,0B,41,2E), \ - V(B3,67,1D,5A), V(92,DB,D2,52), V(E9,10,56,33), V(6D,D6,47,13), \ - V(9A,D7,61,8C), V(37,A1,0C,7A), V(59,F8,14,8E), V(EB,13,3C,89), \ - V(CE,A9,27,EE), V(B7,61,C9,35), V(E1,1C,E5,ED), V(7A,47,B1,3C), \ - V(9C,D2,DF,59), V(55,F2,73,3F), V(18,14,CE,79), V(73,C7,37,BF), \ - V(53,F7,CD,EA), V(5F,FD,AA,5B), V(DF,3D,6F,14), V(78,44,DB,86), \ - V(CA,AF,F3,81), V(B9,68,C4,3E), V(38,24,34,2C), V(C2,A3,40,5F), \ - V(16,1D,C3,72), V(BC,E2,25,0C), V(28,3C,49,8B), V(FF,0D,95,41), \ - V(39,A8,01,71), V(08,0C,B3,DE), V(D8,B4,E4,9C), V(64,56,C1,90), \ - V(7B,CB,84,61), V(D5,32,B6,70), V(48,6C,5C,74), V(D0,B8,57,42) - -#define V(a,b,c,d) 0x##a##b##c##d -static uint32 RT0[256] = { RT }; -#undef V - -#define V(a,b,c,d) 0x##d##a##b##c -static uint32 RT1[256] = { RT }; -#undef V - -#define V(a,b,c,d) 0x##c##d##a##b -static uint32 RT2[256] = { RT }; -#undef V - -#define V(a,b,c,d) 0x##b##c##d##a -static uint32 RT3[256] = { RT }; -#undef V - -#undef RT - -/* round constants */ - -static uint32 RCON[10] = -{ - 0x01000000, 0x02000000, 0x04000000, 0x08000000, - 0x10000000, 0x20000000, 0x40000000, 0x80000000, - 0x1B000000, 0x36000000 -}; - -/* key schedule tables */ - -static int KT_init = 1; - -static uint32 KT0[256]; -static uint32 KT1[256]; -static uint32 KT2[256]; -static uint32 KT3[256]; - -/* platform-independant 32-bit integer manipulation macros */ - -#define GET_UINT32(n,b,i) \ -{ \ - (n) = ( (uint32) (b)[(i) ] << 24 ) \ - | ( (uint32) (b)[(i) + 1] << 16 ) \ - | ( (uint32) (b)[(i) + 2] << 8 ) \ - | ( (uint32) (b)[(i) + 3] ); \ -} - -#define PUT_UINT32(n,b,i) \ -{ \ - (b)[(i) ] = (uint8) ( (n) >> 24 ); \ - (b)[(i) + 1] = (uint8) ( (n) >> 16 ); \ - (b)[(i) + 2] = (uint8) ( (n) >> 8 ); \ - (b)[(i) + 3] = (uint8) ( (n) ); \ -} - -/* AES key scheduling routine */ - -int rtmp_aes_set_key( aes_context *ctx, uint8 *key, int nbits ) -{ - int i; - uint32 *RK, *SK; - - switch( nbits ) - { - case 128: ctx->nr = 10; break; - case 192: ctx->nr = 12; break; - case 256: ctx->nr = 14; break; - default : return( 1 ); - } - - RK = ctx->erk; - - for( i = 0; i < (nbits >> 5); i++ ) - { - GET_UINT32( RK[i], key, i * 4 ); - } - - /* setup encryption round keys */ - - switch( nbits ) - { - case 128: - - for( i = 0; i < 10; i++, RK += 4 ) - { - RK[4] = RK[0] ^ RCON[i] ^ - ( FSb[ (uint8) ( RK[3] >> 16 ) ] << 24 ) ^ - ( FSb[ (uint8) ( RK[3] >> 8 ) ] << 16 ) ^ - ( FSb[ (uint8) ( RK[3] ) ] << 8 ) ^ - ( FSb[ (uint8) ( RK[3] >> 24 ) ] ); - - RK[5] = RK[1] ^ RK[4]; - RK[6] = RK[2] ^ RK[5]; - RK[7] = RK[3] ^ RK[6]; - } - break; - - case 192: - - for( i = 0; i < 8; i++, RK += 6 ) - { - RK[6] = RK[0] ^ RCON[i] ^ - ( FSb[ (uint8) ( RK[5] >> 16 ) ] << 24 ) ^ - ( FSb[ (uint8) ( RK[5] >> 8 ) ] << 16 ) ^ - ( FSb[ (uint8) ( RK[5] ) ] << 8 ) ^ - ( FSb[ (uint8) ( RK[5] >> 24 ) ] ); - - RK[7] = RK[1] ^ RK[6]; - RK[8] = RK[2] ^ RK[7]; - RK[9] = RK[3] ^ RK[8]; - RK[10] = RK[4] ^ RK[9]; - RK[11] = RK[5] ^ RK[10]; - } - break; - - case 256: - - for( i = 0; i < 7; i++, RK += 8 ) - { - RK[8] = RK[0] ^ RCON[i] ^ - ( FSb[ (uint8) ( RK[7] >> 16 ) ] << 24 ) ^ - ( FSb[ (uint8) ( RK[7] >> 8 ) ] << 16 ) ^ - ( FSb[ (uint8) ( RK[7] ) ] << 8 ) ^ - ( FSb[ (uint8) ( RK[7] >> 24 ) ] ); - - RK[9] = RK[1] ^ RK[8]; - RK[10] = RK[2] ^ RK[9]; - RK[11] = RK[3] ^ RK[10]; - - RK[12] = RK[4] ^ - ( FSb[ (uint8) ( RK[11] >> 24 ) ] << 24 ) ^ - ( FSb[ (uint8) ( RK[11] >> 16 ) ] << 16 ) ^ - ( FSb[ (uint8) ( RK[11] >> 8 ) ] << 8 ) ^ - ( FSb[ (uint8) ( RK[11] ) ] ); - - RK[13] = RK[5] ^ RK[12]; - RK[14] = RK[6] ^ RK[13]; - RK[15] = RK[7] ^ RK[14]; - } - break; - } - - /* setup decryption round keys */ - - if( KT_init ) - { - for( i = 0; i < 256; i++ ) - { - KT0[i] = RT0[ FSb[i] ]; - KT1[i] = RT1[ FSb[i] ]; - KT2[i] = RT2[ FSb[i] ]; - KT3[i] = RT3[ FSb[i] ]; - } - - KT_init = 0; - } - - SK = ctx->drk; - - *SK++ = *RK++; - *SK++ = *RK++; - *SK++ = *RK++; - *SK++ = *RK++; - - for( i = 1; i < ctx->nr; i++ ) - { - RK -= 8; - - *SK++ = KT0[ (uint8) ( *RK >> 24 ) ] ^ - KT1[ (uint8) ( *RK >> 16 ) ] ^ - KT2[ (uint8) ( *RK >> 8 ) ] ^ - KT3[ (uint8) ( *RK ) ]; RK++; - - *SK++ = KT0[ (uint8) ( *RK >> 24 ) ] ^ - KT1[ (uint8) ( *RK >> 16 ) ] ^ - KT2[ (uint8) ( *RK >> 8 ) ] ^ - KT3[ (uint8) ( *RK ) ]; RK++; - - *SK++ = KT0[ (uint8) ( *RK >> 24 ) ] ^ - KT1[ (uint8) ( *RK >> 16 ) ] ^ - KT2[ (uint8) ( *RK >> 8 ) ] ^ - KT3[ (uint8) ( *RK ) ]; RK++; - - *SK++ = KT0[ (uint8) ( *RK >> 24 ) ] ^ - KT1[ (uint8) ( *RK >> 16 ) ] ^ - KT2[ (uint8) ( *RK >> 8 ) ] ^ - KT3[ (uint8) ( *RK ) ]; RK++; - } - - RK -= 8; - - *SK++ = *RK++; - *SK++ = *RK++; - *SK++ = *RK++; - *SK++ = *RK++; - - return( 0 ); -} - -/* AES 128-bit block encryption routine */ - -void rtmp_aes_encrypt(aes_context *ctx, uint8 input[16], uint8 output[16] ) -{ - uint32 *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3; - - RK = ctx->erk; - GET_UINT32( X0, input, 0 ); X0 ^= RK[0]; - GET_UINT32( X1, input, 4 ); X1 ^= RK[1]; - GET_UINT32( X2, input, 8 ); X2 ^= RK[2]; - GET_UINT32( X3, input, 12 ); X3 ^= RK[3]; - -#define AES_FROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \ -{ \ - RK += 4; \ - \ - X0 = RK[0] ^ FT0[ (uint8) ( Y0 >> 24 ) ] ^ \ - FT1[ (uint8) ( Y1 >> 16 ) ] ^ \ - FT2[ (uint8) ( Y2 >> 8 ) ] ^ \ - FT3[ (uint8) ( Y3 ) ]; \ - \ - X1 = RK[1] ^ FT0[ (uint8) ( Y1 >> 24 ) ] ^ \ - FT1[ (uint8) ( Y2 >> 16 ) ] ^ \ - FT2[ (uint8) ( Y3 >> 8 ) ] ^ \ - FT3[ (uint8) ( Y0 ) ]; \ - \ - X2 = RK[2] ^ FT0[ (uint8) ( Y2 >> 24 ) ] ^ \ - FT1[ (uint8) ( Y3 >> 16 ) ] ^ \ - FT2[ (uint8) ( Y0 >> 8 ) ] ^ \ - FT3[ (uint8) ( Y1 ) ]; \ - \ - X3 = RK[3] ^ FT0[ (uint8) ( Y3 >> 24 ) ] ^ \ - FT1[ (uint8) ( Y0 >> 16 ) ] ^ \ - FT2[ (uint8) ( Y1 >> 8 ) ] ^ \ - FT3[ (uint8) ( Y2 ) ]; \ -} - - AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 1 */ - AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 2 */ - AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 3 */ - AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 4 */ - AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 5 */ - AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 6 */ - AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 7 */ - AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 8 */ - AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 9 */ - - if( ctx->nr > 10 ) - { - AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 10 */ - AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 11 */ - } - - if( ctx->nr > 12 ) - { - AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 12 */ - AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 13 */ - } - - /* last round */ - - RK += 4; - - X0 = RK[0] ^ ( FSb[ (uint8) ( Y0 >> 24 ) ] << 24 ) ^ - ( FSb[ (uint8) ( Y1 >> 16 ) ] << 16 ) ^ - ( FSb[ (uint8) ( Y2 >> 8 ) ] << 8 ) ^ - ( FSb[ (uint8) ( Y3 ) ] ); - - X1 = RK[1] ^ ( FSb[ (uint8) ( Y1 >> 24 ) ] << 24 ) ^ - ( FSb[ (uint8) ( Y2 >> 16 ) ] << 16 ) ^ - ( FSb[ (uint8) ( Y3 >> 8 ) ] << 8 ) ^ - ( FSb[ (uint8) ( Y0 ) ] ); - - X2 = RK[2] ^ ( FSb[ (uint8) ( Y2 >> 24 ) ] << 24 ) ^ - ( FSb[ (uint8) ( Y3 >> 16 ) ] << 16 ) ^ - ( FSb[ (uint8) ( Y0 >> 8 ) ] << 8 ) ^ - ( FSb[ (uint8) ( Y1 ) ] ); - - X3 = RK[3] ^ ( FSb[ (uint8) ( Y3 >> 24 ) ] << 24 ) ^ - ( FSb[ (uint8) ( Y0 >> 16 ) ] << 16 ) ^ - ( FSb[ (uint8) ( Y1 >> 8 ) ] << 8 ) ^ - ( FSb[ (uint8) ( Y2 ) ] ); - - PUT_UINT32( X0, output, 0 ); - PUT_UINT32( X1, output, 4 ); - PUT_UINT32( X2, output, 8 ); - PUT_UINT32( X3, output, 12 ); -} - -/* AES 128-bit block decryption routine */ - -void rtmp_aes_decrypt( aes_context *ctx, uint8 input[16], uint8 output[16] ) -{ - uint32 *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3; - - RK = ctx->drk; - - GET_UINT32( X0, input, 0 ); X0 ^= RK[0]; - GET_UINT32( X1, input, 4 ); X1 ^= RK[1]; - GET_UINT32( X2, input, 8 ); X2 ^= RK[2]; - GET_UINT32( X3, input, 12 ); X3 ^= RK[3]; - -#define AES_RROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \ -{ \ - RK += 4; \ - \ - X0 = RK[0] ^ RT0[ (uint8) ( Y0 >> 24 ) ] ^ \ - RT1[ (uint8) ( Y3 >> 16 ) ] ^ \ - RT2[ (uint8) ( Y2 >> 8 ) ] ^ \ - RT3[ (uint8) ( Y1 ) ]; \ - \ - X1 = RK[1] ^ RT0[ (uint8) ( Y1 >> 24 ) ] ^ \ - RT1[ (uint8) ( Y0 >> 16 ) ] ^ \ - RT2[ (uint8) ( Y3 >> 8 ) ] ^ \ - RT3[ (uint8) ( Y2 ) ]; \ - \ - X2 = RK[2] ^ RT0[ (uint8) ( Y2 >> 24 ) ] ^ \ - RT1[ (uint8) ( Y1 >> 16 ) ] ^ \ - RT2[ (uint8) ( Y0 >> 8 ) ] ^ \ - RT3[ (uint8) ( Y3 ) ]; \ - \ - X3 = RK[3] ^ RT0[ (uint8) ( Y3 >> 24 ) ] ^ \ - RT1[ (uint8) ( Y2 >> 16 ) ] ^ \ - RT2[ (uint8) ( Y1 >> 8 ) ] ^ \ - RT3[ (uint8) ( Y0 ) ]; \ -} - - AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 1 */ - AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 2 */ - AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 3 */ - AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 4 */ - AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 5 */ - AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 6 */ - AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 7 */ - AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 8 */ - AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 9 */ - - if( ctx->nr > 10 ) - { - AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 10 */ - AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 11 */ - } - - if( ctx->nr > 12 ) - { - AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 12 */ - AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 13 */ - } - - /* last round */ - - RK += 4; - - X0 = RK[0] ^ ( RSb[ (uint8) ( Y0 >> 24 ) ] << 24 ) ^ - ( RSb[ (uint8) ( Y3 >> 16 ) ] << 16 ) ^ - ( RSb[ (uint8) ( Y2 >> 8 ) ] << 8 ) ^ - ( RSb[ (uint8) ( Y1 ) ] ); - - X1 = RK[1] ^ ( RSb[ (uint8) ( Y1 >> 24 ) ] << 24 ) ^ - ( RSb[ (uint8) ( Y0 >> 16 ) ] << 16 ) ^ - ( RSb[ (uint8) ( Y3 >> 8 ) ] << 8 ) ^ - ( RSb[ (uint8) ( Y2 ) ] ); - - X2 = RK[2] ^ ( RSb[ (uint8) ( Y2 >> 24 ) ] << 24 ) ^ - ( RSb[ (uint8) ( Y1 >> 16 ) ] << 16 ) ^ - ( RSb[ (uint8) ( Y0 >> 8 ) ] << 8 ) ^ - ( RSb[ (uint8) ( Y3 ) ] ); - - X3 = RK[3] ^ ( RSb[ (uint8) ( Y3 >> 24 ) ] << 24 ) ^ - ( RSb[ (uint8) ( Y2 >> 16 ) ] << 16 ) ^ - ( RSb[ (uint8) ( Y1 >> 8 ) ] << 8 ) ^ - ( RSb[ (uint8) ( Y0 ) ] ); - - PUT_UINT32( X0, output, 0 ); - PUT_UINT32( X1, output, 4 ); - PUT_UINT32( X2, output, 8 ); - PUT_UINT32( X3, output, 12 ); -} - -/* - ======================================================================== - - Routine Description: - SHA1 function - - Arguments: - - Return Value: - - Note: - - ======================================================================== -*/ -VOID HMAC_SHA1( - IN UCHAR *text, - IN UINT text_len, - IN UCHAR *key, - IN UINT key_len, - IN UCHAR *digest) -{ - SHA_CTX context; - UCHAR k_ipad[65]; /* inner padding - key XORd with ipad */ - UCHAR k_opad[65]; /* outer padding - key XORd with opad */ - INT i; - - // if key is longer than 64 bytes reset it to key=SHA1(key) - if (key_len > 64) - { - SHA_CTX tctx; - SHAInit(&tctx); - SHAUpdate(&tctx, key, key_len); - SHAFinal(&tctx, key); - key_len = 20; - } - NdisZeroMemory(k_ipad, sizeof(k_ipad)); - NdisZeroMemory(k_opad, sizeof(k_opad)); - NdisMoveMemory(k_ipad, key, key_len); - NdisMoveMemory(k_opad, key, key_len); - - // XOR key with ipad and opad values - for (i = 0; i < 64; i++) - { - k_ipad[i] ^= 0x36; - k_opad[i] ^= 0x5c; - } - - // perform inner SHA1 - SHAInit(&context); /* init context for 1st pass */ - SHAUpdate(&context, k_ipad, 64); /* start with inner pad */ - SHAUpdate(&context, text, text_len); /* then text of datagram */ - SHAFinal(&context, digest); /* finish up 1st pass */ - - //perform outer SHA1 - SHAInit(&context); /* init context for 2nd pass */ - SHAUpdate(&context, k_opad, 64); /* start with outer pad */ - SHAUpdate(&context, digest, 20); /* then results of 1st hash */ - SHAFinal(&context, digest); /* finish up 2nd pass */ - -} - -/* -* F(P, S, c, i) = U1 xor U2 xor ... Uc -* U1 = PRF(P, S || Int(i)) -* U2 = PRF(P, U1) -* Uc = PRF(P, Uc-1) -*/ - -void F(char *password, unsigned char *ssid, int ssidlength, int iterations, int count, unsigned char *output) -{ - unsigned char digest[36], digest1[SHA_DIGEST_LEN]; - int i, j; - - /* U1 = PRF(P, S || int(i)) */ - memcpy(digest, ssid, ssidlength); - digest[ssidlength] = (unsigned char)((count>>24) & 0xff); - digest[ssidlength+1] = (unsigned char)((count>>16) & 0xff); - digest[ssidlength+2] = (unsigned char)((count>>8) & 0xff); - digest[ssidlength+3] = (unsigned char)(count & 0xff); - HMAC_SHA1(digest, ssidlength+4, (unsigned char*) password, (int) strlen(password), digest1); // for WPA update - - /* output = U1 */ - memcpy(output, digest1, SHA_DIGEST_LEN); - - for (i = 1; i < iterations; i++) - { - /* Un = PRF(P, Un-1) */ - HMAC_SHA1(digest1, SHA_DIGEST_LEN, (unsigned char*) password, (int) strlen(password), digest); // for WPA update - memcpy(digest1, digest, SHA_DIGEST_LEN); - - /* output = output xor Un */ - for (j = 0; j < SHA_DIGEST_LEN; j++) - { - output[j] ^= digest[j]; - } - } -} -/* -* password - ascii string up to 63 characters in length -* ssid - octet string up to 32 octets -* ssidlength - length of ssid in octets -* output must be 40 octets in length and outputs 256 bits of key -*/ -int PasswordHash(char *password, unsigned char *ssid, int ssidlength, unsigned char *output) -{ - if ((strlen(password) > 63) || (ssidlength > 32)) - return 0; - - F(password, ssid, ssidlength, 4096, 1, output); - F(password, ssid, ssidlength, 4096, 2, &output[SHA_DIGEST_LEN]); - return 1; -} - - +#include "../../rt2870/common/md5.c" diff --git a/drivers/staging/rt3070/common/mlme.c b/drivers/staging/rt3070/common/mlme.c index 0ffbfa36699e..c2d0d4e10cb7 100644 --- a/drivers/staging/rt3070/common/mlme.c +++ b/drivers/staging/rt3070/common/mlme.c @@ -1,9136 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - mlme.c - - Abstract: - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - John Chang 2004-08-25 Modify from RT2500 code base - John Chang 2004-09-06 modified for RT2600 -*/ - -#include "../rt_config.h" -#include - -UCHAR CISCO_OUI[] = {0x00, 0x40, 0x96}; - -UCHAR WPA_OUI[] = {0x00, 0x50, 0xf2, 0x01}; -UCHAR RSN_OUI[] = {0x00, 0x0f, 0xac}; -UCHAR WAPI_OUI[] = {0x00, 0x14, 0x72}; -UCHAR WME_INFO_ELEM[] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01}; -UCHAR WME_PARM_ELEM[] = {0x00, 0x50, 0xf2, 0x02, 0x01, 0x01}; -UCHAR Ccx2QosInfo[] = {0x00, 0x40, 0x96, 0x04}; -UCHAR RALINK_OUI[] = {0x00, 0x0c, 0x43}; -UCHAR BROADCOM_OUI[] = {0x00, 0x90, 0x4c}; -UCHAR WPS_OUI[] = {0x00, 0x50, 0xf2, 0x04}; -#ifdef CONFIG_STA_SUPPORT -#ifdef DOT11_N_SUPPORT -UCHAR PRE_N_HT_OUI[] = {0x00, 0x90, 0x4c}; -#endif // DOT11_N_SUPPORT // -#endif // CONFIG_STA_SUPPORT // - -UCHAR RateSwitchTable[] = { -// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) - 0x11, 0x00, 0, 0, 0, // Initial used item after association - 0x00, 0x00, 0, 40, 101, - 0x01, 0x00, 1, 40, 50, - 0x02, 0x00, 2, 35, 45, - 0x03, 0x00, 3, 20, 45, - 0x04, 0x21, 0, 30, 50, - 0x05, 0x21, 1, 20, 50, - 0x06, 0x21, 2, 20, 50, - 0x07, 0x21, 3, 15, 50, - 0x08, 0x21, 4, 15, 30, - 0x09, 0x21, 5, 10, 25, - 0x0a, 0x21, 6, 8, 25, - 0x0b, 0x21, 7, 8, 25, - 0x0c, 0x20, 12, 15, 30, - 0x0d, 0x20, 13, 8, 20, - 0x0e, 0x20, 14, 8, 20, - 0x0f, 0x20, 15, 8, 25, - 0x10, 0x22, 15, 8, 25, - 0x11, 0x00, 0, 0, 0, - 0x12, 0x00, 0, 0, 0, - 0x13, 0x00, 0, 0, 0, - 0x14, 0x00, 0, 0, 0, - 0x15, 0x00, 0, 0, 0, - 0x16, 0x00, 0, 0, 0, - 0x17, 0x00, 0, 0, 0, - 0x18, 0x00, 0, 0, 0, - 0x19, 0x00, 0, 0, 0, - 0x1a, 0x00, 0, 0, 0, - 0x1b, 0x00, 0, 0, 0, - 0x1c, 0x00, 0, 0, 0, - 0x1d, 0x00, 0, 0, 0, - 0x1e, 0x00, 0, 0, 0, - 0x1f, 0x00, 0, 0, 0, -}; - -UCHAR RateSwitchTable11B[] = { -// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) - 0x04, 0x03, 0, 0, 0, // Initial used item after association - 0x00, 0x00, 0, 40, 101, - 0x01, 0x00, 1, 40, 50, - 0x02, 0x00, 2, 35, 45, - 0x03, 0x00, 3, 20, 45, -}; - -UCHAR RateSwitchTable11BG[] = { -// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) - 0x0a, 0x00, 0, 0, 0, // Initial used item after association - 0x00, 0x00, 0, 40, 101, - 0x01, 0x00, 1, 40, 50, - 0x02, 0x00, 2, 35, 45, - 0x03, 0x00, 3, 20, 45, - 0x04, 0x10, 2, 20, 35, - 0x05, 0x10, 3, 16, 35, - 0x06, 0x10, 4, 10, 25, - 0x07, 0x10, 5, 16, 25, - 0x08, 0x10, 6, 10, 25, - 0x09, 0x10, 7, 10, 13, -}; - -UCHAR RateSwitchTable11G[] = { -// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) - 0x08, 0x00, 0, 0, 0, // Initial used item after association - 0x00, 0x10, 0, 20, 101, - 0x01, 0x10, 1, 20, 35, - 0x02, 0x10, 2, 20, 35, - 0x03, 0x10, 3, 16, 35, - 0x04, 0x10, 4, 10, 25, - 0x05, 0x10, 5, 16, 25, - 0x06, 0x10, 6, 10, 25, - 0x07, 0x10, 7, 10, 13, -}; - -#ifdef DOT11_N_SUPPORT -UCHAR RateSwitchTable11N1S[] = { -// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) - 0x09, 0x00, 0, 0, 0, // Initial used item after association - 0x00, 0x21, 0, 30, 101, - 0x01, 0x21, 1, 20, 50, - 0x02, 0x21, 2, 20, 50, - 0x03, 0x21, 3, 15, 50, - 0x04, 0x21, 4, 15, 30, - 0x05, 0x21, 5, 10, 25, - 0x06, 0x21, 6, 8, 14, - 0x07, 0x21, 7, 8, 14, - 0x08, 0x23, 7, 8, 14, -}; - -UCHAR RateSwitchTable11N2S[] = { -// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) - 0x0a, 0x00, 0, 0, 0, // Initial used item after association - 0x00, 0x21, 0, 30, 101, - 0x01, 0x21, 1, 20, 50, - 0x02, 0x21, 2, 20, 50, - 0x03, 0x21, 3, 15, 50, - 0x04, 0x21, 4, 15, 30, - 0x05, 0x20, 12, 15, 30, - 0x06, 0x20, 13, 8, 20, - 0x07, 0x20, 14, 8, 20, - 0x08, 0x20, 15, 8, 25, - 0x09, 0x22, 15, 8, 25, -}; - -UCHAR RateSwitchTable11N3S[] = { -// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) - 0x0a, 0x00, 0, 0, 0, // Initial used item after association - 0x00, 0x21, 0, 30, 101, - 0x01, 0x21, 1, 20, 50, - 0x02, 0x21, 2, 20, 50, - 0x03, 0x21, 3, 15, 50, - 0x04, 0x21, 4, 15, 30, - 0x05, 0x20, 12, 15, 30, - 0x06, 0x20, 13, 8, 20, - 0x07, 0x20, 14, 8, 20, - 0x08, 0x20, 15, 8, 25, - 0x09, 0x22, 15, 8, 25, -}; - -UCHAR RateSwitchTable11N2SForABand[] = { -// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) - 0x0b, 0x09, 0, 0, 0, // Initial used item after association - 0x00, 0x21, 0, 30, 101, - 0x01, 0x21, 1, 20, 50, - 0x02, 0x21, 2, 20, 50, - 0x03, 0x21, 3, 15, 50, - 0x04, 0x21, 4, 15, 30, - 0x05, 0x21, 5, 15, 30, - 0x06, 0x20, 12, 15, 30, - 0x07, 0x20, 13, 8, 20, - 0x08, 0x20, 14, 8, 20, - 0x09, 0x20, 15, 8, 25, - 0x0a, 0x22, 15, 8, 25, -}; - -UCHAR RateSwitchTable11N3SForABand[] = { // 3*3 -// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) - 0x0b, 0x09, 0, 0, 0, // Initial used item after association - 0x00, 0x21, 0, 30, 101, - 0x01, 0x21, 1, 20, 50, - 0x02, 0x21, 2, 20, 50, - 0x03, 0x21, 3, 15, 50, - 0x04, 0x21, 4, 15, 30, - 0x05, 0x21, 5, 15, 30, - 0x06, 0x20, 12, 15, 30, - 0x07, 0x20, 13, 8, 20, - 0x08, 0x20, 14, 8, 20, - 0x09, 0x20, 15, 8, 25, - 0x0a, 0x22, 15, 8, 25, -}; - -UCHAR RateSwitchTable11BGN1S[] = { -// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) - 0x0d, 0x00, 0, 0, 0, // Initial used item after association - 0x00, 0x00, 0, 40, 101, - 0x01, 0x00, 1, 40, 50, - 0x02, 0x00, 2, 35, 45, - 0x03, 0x00, 3, 20, 45, - 0x04, 0x21, 0, 30,101, //50 - 0x05, 0x21, 1, 20, 50, - 0x06, 0x21, 2, 20, 50, - 0x07, 0x21, 3, 15, 50, - 0x08, 0x21, 4, 15, 30, - 0x09, 0x21, 5, 10, 25, - 0x0a, 0x21, 6, 8, 14, - 0x0b, 0x21, 7, 8, 14, - 0x0c, 0x23, 7, 8, 14, -}; - -UCHAR RateSwitchTable11BGN2S[] = { -// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) - 0x0a, 0x00, 0, 0, 0, // Initial used item after association - 0x00, 0x21, 0, 30,101, //50 - 0x01, 0x21, 1, 20, 50, - 0x02, 0x21, 2, 20, 50, - 0x03, 0x21, 3, 15, 50, - 0x04, 0x21, 4, 15, 30, - 0x05, 0x20, 12, 15, 30, - 0x06, 0x20, 13, 8, 20, - 0x07, 0x20, 14, 8, 20, - 0x08, 0x20, 15, 8, 25, - 0x09, 0x22, 15, 8, 25, -}; - -UCHAR RateSwitchTable11BGN3S[] = { // 3*3 -// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) - 0x0a, 0x00, 0, 0, 0, // Initial used item after association - 0x00, 0x21, 0, 30,101, //50 - 0x01, 0x21, 1, 20, 50, - 0x02, 0x21, 2, 20, 50, - 0x03, 0x21, 3, 20, 50, - 0x04, 0x21, 4, 15, 50, -#if 1 - 0x05, 0x20, 20, 15, 30, - 0x06, 0x20, 21, 8, 20, - 0x07, 0x20, 22, 8, 20, - 0x08, 0x20, 23, 8, 25, - 0x09, 0x22, 23, 8, 25, -#else // for RT2860 2*3 test - 0x05, 0x20, 12, 15, 30, - 0x06, 0x20, 13, 8, 20, - 0x07, 0x20, 14, 8, 20, - 0x08, 0x20, 15, 8, 25, - 0x09, 0x22, 15, 8, 25, -#endif -}; - -UCHAR RateSwitchTable11BGN2SForABand[] = { -// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) - 0x0b, 0x09, 0, 0, 0, // Initial used item after association - 0x00, 0x21, 0, 30,101, //50 - 0x01, 0x21, 1, 20, 50, - 0x02, 0x21, 2, 20, 50, - 0x03, 0x21, 3, 15, 50, - 0x04, 0x21, 4, 15, 30, - 0x05, 0x21, 5, 15, 30, - 0x06, 0x20, 12, 15, 30, - 0x07, 0x20, 13, 8, 20, - 0x08, 0x20, 14, 8, 20, - 0x09, 0x20, 15, 8, 25, - 0x0a, 0x22, 15, 8, 25, -}; - -UCHAR RateSwitchTable11BGN3SForABand[] = { // 3*3 -// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) - 0x0c, 0x09, 0, 0, 0, // Initial used item after association - 0x00, 0x21, 0, 30,101, //50 - 0x01, 0x21, 1, 20, 50, - 0x02, 0x21, 2, 20, 50, - 0x03, 0x21, 3, 15, 50, - 0x04, 0x21, 4, 15, 30, - 0x05, 0x21, 5, 15, 30, - 0x06, 0x21, 12, 15, 30, - 0x07, 0x20, 20, 15, 30, - 0x08, 0x20, 21, 8, 20, - 0x09, 0x20, 22, 8, 20, - 0x0a, 0x20, 23, 8, 25, - 0x0b, 0x22, 23, 8, 25, -}; -#endif // DOT11_N_SUPPORT // - -PUCHAR ReasonString[] = { - /* 0 */ "Reserved", - /* 1 */ "Unspecified Reason", - /* 2 */ "Previous Auth no longer valid", - /* 3 */ "STA is leaving / has left", - /* 4 */ "DIS-ASSOC due to inactivity", - /* 5 */ "AP unable to hanle all associations", - /* 6 */ "class 2 error", - /* 7 */ "class 3 error", - /* 8 */ "STA is leaving / has left", - /* 9 */ "require auth before assoc/re-assoc", - /* 10 */ "Reserved", - /* 11 */ "Reserved", - /* 12 */ "Reserved", - /* 13 */ "invalid IE", - /* 14 */ "MIC error", - /* 15 */ "4-way handshake timeout", - /* 16 */ "2-way (group key) handshake timeout", - /* 17 */ "4-way handshake IE diff among AssosReq/Rsp/Beacon", - /* 18 */ -}; - -extern UCHAR OfdmRateToRxwiMCS[]; -// since RT61 has better RX sensibility, we have to limit TX ACK rate not to exceed our normal data TX rate. -// otherwise the WLAN peer may not be able to receive the ACK thus downgrade its data TX rate -ULONG BasicRateMask[12] = {0xfffff001 /* 1-Mbps */, 0xfffff003 /* 2 Mbps */, 0xfffff007 /* 5.5 */, 0xfffff00f /* 11 */, - 0xfffff01f /* 6 */ , 0xfffff03f /* 9 */ , 0xfffff07f /* 12 */ , 0xfffff0ff /* 18 */, - 0xfffff1ff /* 24 */ , 0xfffff3ff /* 36 */ , 0xfffff7ff /* 48 */ , 0xffffffff /* 54 */}; - -UCHAR MULTICAST_ADDR[MAC_ADDR_LEN] = {0x1, 0x00, 0x00, 0x00, 0x00, 0x00}; -UCHAR BROADCAST_ADDR[MAC_ADDR_LEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; -UCHAR ZERO_MAC_ADDR[MAC_ADDR_LEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - -// e.g. RssiSafeLevelForTxRate[RATE_36]" means if the current RSSI is greater than -// this value, then it's quaranteed capable of operating in 36 mbps TX rate in -// clean environment. -// TxRate: 1 2 5.5 11 6 9 12 18 24 36 48 54 72 100 -CHAR RssiSafeLevelForTxRate[] ={ -92, -91, -90, -87, -88, -86, -85, -83, -81, -78, -72, -71, -40, -40 }; - -UCHAR RateIdToMbps[] = { 1, 2, 5, 11, 6, 9, 12, 18, 24, 36, 48, 54, 72, 100}; -USHORT RateIdTo500Kbps[] = { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108, 144, 200}; - -UCHAR SsidIe = IE_SSID; -UCHAR SupRateIe = IE_SUPP_RATES; -UCHAR ExtRateIe = IE_EXT_SUPP_RATES; -#ifdef DOT11_N_SUPPORT -UCHAR HtCapIe = IE_HT_CAP; -UCHAR AddHtInfoIe = IE_ADD_HT; -UCHAR NewExtChanIe = IE_SECONDARY_CH_OFFSET; -#ifdef DOT11N_DRAFT3 -UCHAR ExtHtCapIe = IE_EXT_CAPABILITY; -#endif // DOT11N_DRAFT3 // -#endif // DOT11_N_SUPPORT // -UCHAR ErpIe = IE_ERP; -UCHAR DsIe = IE_DS_PARM; -UCHAR TimIe = IE_TIM; -UCHAR WpaIe = IE_WPA; -UCHAR Wpa2Ie = IE_WPA2; -UCHAR IbssIe = IE_IBSS_PARM; -UCHAR Ccx2Ie = IE_CCX_V2; -UCHAR WapiIe = IE_WAPI; - -extern UCHAR WPA_OUI[]; - -UCHAR SES_OUI[] = {0x00, 0x90, 0x4c}; - -UCHAR ZeroSsid[32] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; - -// Reset the RFIC setting to new series -RTMP_RF_REGS RF2850RegTable[] = { -// ch R1 R2 R3(TX0~4=0) R4 - {1, 0x98402ecc, 0x984c0786, 0x9816b455, 0x9800510b}, - {2, 0x98402ecc, 0x984c0786, 0x98168a55, 0x9800519f}, - {3, 0x98402ecc, 0x984c078a, 0x98168a55, 0x9800518b}, - {4, 0x98402ecc, 0x984c078a, 0x98168a55, 0x9800519f}, - {5, 0x98402ecc, 0x984c078e, 0x98168a55, 0x9800518b}, - {6, 0x98402ecc, 0x984c078e, 0x98168a55, 0x9800519f}, - {7, 0x98402ecc, 0x984c0792, 0x98168a55, 0x9800518b}, - {8, 0x98402ecc, 0x984c0792, 0x98168a55, 0x9800519f}, - {9, 0x98402ecc, 0x984c0796, 0x98168a55, 0x9800518b}, - {10, 0x98402ecc, 0x984c0796, 0x98168a55, 0x9800519f}, - {11, 0x98402ecc, 0x984c079a, 0x98168a55, 0x9800518b}, - {12, 0x98402ecc, 0x984c079a, 0x98168a55, 0x9800519f}, - {13, 0x98402ecc, 0x984c079e, 0x98168a55, 0x9800518b}, - {14, 0x98402ecc, 0x984c07a2, 0x98168a55, 0x98005193}, - - // 802.11 UNI / HyperLan 2 - {36, 0x98402ecc, 0x984c099a, 0x98158a55, 0x980ed1a3}, - {38, 0x98402ecc, 0x984c099e, 0x98158a55, 0x980ed193}, - {40, 0x98402ec8, 0x984c0682, 0x98158a55, 0x980ed183}, - {44, 0x98402ec8, 0x984c0682, 0x98158a55, 0x980ed1a3}, - {46, 0x98402ec8, 0x984c0686, 0x98158a55, 0x980ed18b}, - {48, 0x98402ec8, 0x984c0686, 0x98158a55, 0x980ed19b}, - {52, 0x98402ec8, 0x984c068a, 0x98158a55, 0x980ed193}, - {54, 0x98402ec8, 0x984c068a, 0x98158a55, 0x980ed1a3}, - {56, 0x98402ec8, 0x984c068e, 0x98158a55, 0x980ed18b}, - {60, 0x98402ec8, 0x984c0692, 0x98158a55, 0x980ed183}, - {62, 0x98402ec8, 0x984c0692, 0x98158a55, 0x980ed193}, - {64, 0x98402ec8, 0x984c0692, 0x98158a55, 0x980ed1a3}, // Plugfest#4, Day4, change RFR3 left4th 9->5. - - // 802.11 HyperLan 2 - {100, 0x98402ec8, 0x984c06b2, 0x98178a55, 0x980ed783}, - - // 2008.04.30 modified - // The system team has AN to improve the EVM value - // for channel 102 to 108 for the RT2850/RT2750 dual band solution. - {102, 0x98402ec8, 0x985c06b2, 0x98578a55, 0x980ed793}, - {104, 0x98402ec8, 0x985c06b2, 0x98578a55, 0x980ed1a3}, - {108, 0x98402ecc, 0x985c0a32, 0x98578a55, 0x980ed193}, - - {110, 0x98402ecc, 0x984c0a36, 0x98178a55, 0x980ed183}, - {112, 0x98402ecc, 0x984c0a36, 0x98178a55, 0x980ed19b}, - {116, 0x98402ecc, 0x984c0a3a, 0x98178a55, 0x980ed1a3}, - {118, 0x98402ecc, 0x984c0a3e, 0x98178a55, 0x980ed193}, - {120, 0x98402ec4, 0x984c0382, 0x98178a55, 0x980ed183}, - {124, 0x98402ec4, 0x984c0382, 0x98178a55, 0x980ed193}, - {126, 0x98402ec4, 0x984c0382, 0x98178a55, 0x980ed15b}, // 0x980ed1bb->0x980ed15b required by Rory 20070927 - {128, 0x98402ec4, 0x984c0382, 0x98178a55, 0x980ed1a3}, - {132, 0x98402ec4, 0x984c0386, 0x98178a55, 0x980ed18b}, - {134, 0x98402ec4, 0x984c0386, 0x98178a55, 0x980ed193}, - {136, 0x98402ec4, 0x984c0386, 0x98178a55, 0x980ed19b}, - {140, 0x98402ec4, 0x984c038a, 0x98178a55, 0x980ed183}, - - // 802.11 UNII - {149, 0x98402ec4, 0x984c038a, 0x98178a55, 0x980ed1a7}, - {151, 0x98402ec4, 0x984c038e, 0x98178a55, 0x980ed187}, - {153, 0x98402ec4, 0x984c038e, 0x98178a55, 0x980ed18f}, - {157, 0x98402ec4, 0x984c038e, 0x98178a55, 0x980ed19f}, - {159, 0x98402ec4, 0x984c038e, 0x98178a55, 0x980ed1a7}, - {161, 0x98402ec4, 0x984c0392, 0x98178a55, 0x980ed187}, - {165, 0x98402ec4, 0x984c0392, 0x98178a55, 0x980ed197}, - - // Japan - {184, 0x95002ccc, 0x9500491e, 0x9509be55, 0x950c0a0b}, - {188, 0x95002ccc, 0x95004922, 0x9509be55, 0x950c0a13}, - {192, 0x95002ccc, 0x95004926, 0x9509be55, 0x950c0a1b}, - {196, 0x95002ccc, 0x9500492a, 0x9509be55, 0x950c0a23}, - {208, 0x95002ccc, 0x9500493a, 0x9509be55, 0x950c0a13}, - {212, 0x95002ccc, 0x9500493e, 0x9509be55, 0x950c0a1b}, - {216, 0x95002ccc, 0x95004982, 0x9509be55, 0x950c0a23}, - - // still lack of MMAC(Japan) ch 34,38,42,46 -}; -UCHAR NUM_OF_2850_CHNL = (sizeof(RF2850RegTable) / sizeof(RTMP_RF_REGS)); - -FREQUENCY_ITEM FreqItems3020[] = -{ - /**************************************************/ - // ISM : 2.4 to 2.483 GHz // - /**************************************************/ - // 11g - /**************************************************/ - //-CH---N-------R---K----------- - {1, 241, 2, 2}, - {2, 241, 2, 7}, - {3, 242, 2, 2}, - {4, 242, 2, 7}, - {5, 243, 2, 2}, - {6, 243, 2, 7}, - {7, 244, 2, 2}, - {8, 244, 2, 7}, - {9, 245, 2, 2}, - {10, 245, 2, 7}, - {11, 246, 2, 2}, - {12, 246, 2, 7}, - {13, 247, 2, 2}, - {14, 248, 2, 4}, -}; -//2008/07/10:KH Modified to share this variable -UCHAR NUM_OF_3020_CHNL=(sizeof(FreqItems3020) / sizeof(FREQUENCY_ITEM)); - -/* - ========================================================================== - Description: - initialize the MLME task and its data structure (queue, spinlock, - timer, state machines). - - IRQL = PASSIVE_LEVEL - - Return: - always return NDIS_STATUS_SUCCESS - - ========================================================================== -*/ -NDIS_STATUS MlmeInit( - IN PRTMP_ADAPTER pAd) -{ - NDIS_STATUS Status = NDIS_STATUS_SUCCESS; - - DBGPRINT(RT_DEBUG_TRACE, ("--> MLME Initialize\n")); - - do - { - Status = MlmeQueueInit(&pAd->Mlme.Queue); - if(Status != NDIS_STATUS_SUCCESS) - break; - - pAd->Mlme.bRunning = FALSE; - NdisAllocateSpinLock(&pAd->Mlme.TaskLock); - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - BssTableInit(&pAd->ScanTab); - - // init STA state machines - AssocStateMachineInit(pAd, &pAd->Mlme.AssocMachine, pAd->Mlme.AssocFunc); - AuthStateMachineInit(pAd, &pAd->Mlme.AuthMachine, pAd->Mlme.AuthFunc); - AuthRspStateMachineInit(pAd, &pAd->Mlme.AuthRspMachine, pAd->Mlme.AuthRspFunc); - SyncStateMachineInit(pAd, &pAd->Mlme.SyncMachine, pAd->Mlme.SyncFunc); - WpaPskStateMachineInit(pAd, &pAd->Mlme.WpaPskMachine, pAd->Mlme.WpaPskFunc); - AironetStateMachineInit(pAd, &pAd->Mlme.AironetMachine, pAd->Mlme.AironetFunc); - -#ifdef QOS_DLS_SUPPORT - DlsStateMachineInit(pAd, &pAd->Mlme.DlsMachine, pAd->Mlme.DlsFunc); -#endif // QOS_DLS_SUPPORT // - - - // Since we are using switch/case to implement it, the init is different from the above - // state machine init - MlmeCntlInit(pAd, &pAd->Mlme.CntlMachine, NULL); - } -#endif // CONFIG_STA_SUPPORT // - - - - ActionStateMachineInit(pAd, &pAd->Mlme.ActMachine, pAd->Mlme.ActFunc); - - // Init mlme periodic timer - RTMPInitTimer(pAd, &pAd->Mlme.PeriodicTimer, GET_TIMER_FUNCTION(MlmePeriodicExec), pAd, TRUE); - - // Set mlme periodic timer - RTMPSetTimer(&pAd->Mlme.PeriodicTimer, MLME_TASK_EXEC_INTV); - - // software-based RX Antenna diversity - RTMPInitTimer(pAd, &pAd->Mlme.RxAntEvalTimer, GET_TIMER_FUNCTION(AsicRxAntEvalTimeout), pAd, FALSE); - - -#ifdef CONFIG_STA_SUPPORT -#endif // CONFIG_STA_SUPPORT // - - } while (FALSE); - - DBGPRINT(RT_DEBUG_TRACE, ("<-- MLME Initialize\n")); - - return Status; -} - -/* - ========================================================================== - Description: - main loop of the MLME - Pre: - Mlme has to be initialized, and there are something inside the queue - Note: - This function is invoked from MPSetInformation and MPReceive; - This task guarantee only one MlmeHandler will run. - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID MlmeHandler( - IN PRTMP_ADAPTER pAd) -{ - MLME_QUEUE_ELEM *Elem = NULL; - - // Only accept MLME and Frame from peer side, no other (control/data) frame should - // get into this state machine - - NdisAcquireSpinLock(&pAd->Mlme.TaskLock); - if(pAd->Mlme.bRunning) - { - NdisReleaseSpinLock(&pAd->Mlme.TaskLock); - return; - } - else - { - pAd->Mlme.bRunning = TRUE; - } - NdisReleaseSpinLock(&pAd->Mlme.TaskLock); - - while (!MlmeQueueEmpty(&pAd->Mlme.Queue)) - { - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_MLME_RESET_IN_PROGRESS) || - RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS) || - RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) - { - DBGPRINT(RT_DEBUG_TRACE, ("Device Halted or Removed or MlmeRest, exit MlmeHandler! (queue num = %ld)\n", pAd->Mlme.Queue.Num)); - break; - } - -#ifdef RALINK_ATE - if(ATE_ON(pAd)) - { - DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now in MlmeHandler\n")); - break; - } -#endif // RALINK_ATE // - - //From message type, determine which state machine I should drive - if (MlmeDequeue(&pAd->Mlme.Queue, &Elem)) - { -#ifdef RT2870 - if (Elem->MsgType == MT2_RESET_CONF) - { - DBGPRINT_RAW(RT_DEBUG_TRACE, ("!!! reset MLME state machine !!!\n")); - MlmeRestartStateMachine(pAd); - Elem->Occupied = FALSE; - Elem->MsgLen = 0; - continue; - } -#endif // RT2870 // - - // if dequeue success - switch (Elem->Machine) - { - // STA state machines -#ifdef CONFIG_STA_SUPPORT - case ASSOC_STATE_MACHINE: - StateMachinePerformAction(pAd, &pAd->Mlme.AssocMachine, Elem); - break; - case AUTH_STATE_MACHINE: - StateMachinePerformAction(pAd, &pAd->Mlme.AuthMachine, Elem); - break; - case AUTH_RSP_STATE_MACHINE: - StateMachinePerformAction(pAd, &pAd->Mlme.AuthRspMachine, Elem); - break; - case SYNC_STATE_MACHINE: - StateMachinePerformAction(pAd, &pAd->Mlme.SyncMachine, Elem); - break; - case MLME_CNTL_STATE_MACHINE: - MlmeCntlMachinePerformAction(pAd, &pAd->Mlme.CntlMachine, Elem); - break; - case WPA_PSK_STATE_MACHINE: - StateMachinePerformAction(pAd, &pAd->Mlme.WpaPskMachine, Elem); - break; -#ifdef LEAP_SUPPORT - case LEAP_STATE_MACHINE: - LeapMachinePerformAction(pAd, &pAd->Mlme.LeapMachine, Elem); - break; -#endif - case AIRONET_STATE_MACHINE: - StateMachinePerformAction(pAd, &pAd->Mlme.AironetMachine, Elem); - break; - -#ifdef QOS_DLS_SUPPORT - case DLS_STATE_MACHINE: - StateMachinePerformAction(pAd, &pAd->Mlme.DlsMachine, Elem); - break; -#endif // QOS_DLS_SUPPORT // -#endif // CONFIG_STA_SUPPORT // - - case ACTION_STATE_MACHINE: - StateMachinePerformAction(pAd, &pAd->Mlme.ActMachine, Elem); - break; - - - - - default: - DBGPRINT(RT_DEBUG_TRACE, ("ERROR: Illegal machine %ld in MlmeHandler()\n", Elem->Machine)); - break; - } // end of switch - - // free MLME element - Elem->Occupied = FALSE; - Elem->MsgLen = 0; - - } - else { - DBGPRINT_ERR(("MlmeHandler: MlmeQueue empty\n")); - } - } - - NdisAcquireSpinLock(&pAd->Mlme.TaskLock); - pAd->Mlme.bRunning = FALSE; - NdisReleaseSpinLock(&pAd->Mlme.TaskLock); -} - -/* - ========================================================================== - Description: - Destructor of MLME (Destroy queue, state machine, spin lock and timer) - Parameters: - Adapter - NIC Adapter pointer - Post: - The MLME task will no longer work properly - - IRQL = PASSIVE_LEVEL - - ========================================================================== - */ -VOID MlmeHalt( - IN PRTMP_ADAPTER pAd) -{ - BOOLEAN Cancelled; -#ifdef RT3070 - UINT32 TxPinCfg = 0x00050F0F; -#endif // RT3070 // - - DBGPRINT(RT_DEBUG_TRACE, ("==> MlmeHalt\n")); - - if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) - { - // disable BEACON generation and other BEACON related hardware timers - AsicDisableSync(pAd); - } - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { -#ifdef QOS_DLS_SUPPORT - UCHAR i; -#endif // QOS_DLS_SUPPORT // - // Cancel pending timers - RTMPCancelTimer(&pAd->MlmeAux.AssocTimer, &Cancelled); - RTMPCancelTimer(&pAd->MlmeAux.ReassocTimer, &Cancelled); - RTMPCancelTimer(&pAd->MlmeAux.DisassocTimer, &Cancelled); - RTMPCancelTimer(&pAd->MlmeAux.AuthTimer, &Cancelled); - RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer, &Cancelled); - RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &Cancelled); - -#ifdef QOS_DLS_SUPPORT - for (i=0; iStaCfg.DLSEntry[i].Timer, &Cancelled); - } -#endif // QOS_DLS_SUPPORT // - } -#endif // CONFIG_STA_SUPPORT // - - RTMPCancelTimer(&pAd->Mlme.PeriodicTimer, &Cancelled); - RTMPCancelTimer(&pAd->Mlme.RxAntEvalTimer, &Cancelled); - - - - if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) - { - // Set LED - RTMPSetLED(pAd, LED_HALT); - RTMPSetSignalLED(pAd, -100); // Force signal strength Led to be turned off, firmware is not done it. -#ifdef RT2870 - { - LED_CFG_STRUC LedCfg; - RTMP_IO_READ32(pAd, LED_CFG, &LedCfg.word); - LedCfg.field.LedPolar = 0; - LedCfg.field.RLedMode = 0; - LedCfg.field.GLedMode = 0; - LedCfg.field.YLedMode = 0; - RTMP_IO_WRITE32(pAd, LED_CFG, LedCfg.word); - } -#endif // RT2870 // -#ifdef RT3070 - // - // Turn off LNA_PE - // - if (IS_RT3070(pAd) || IS_RT3071(pAd)) - { - TxPinCfg &= 0xFFFFF0F0; - RTUSBWriteMACRegister(pAd, TX_PIN_CFG, TxPinCfg); - } -#endif // RT3070 // - } - - RTMPusecDelay(5000); // 5 msec to gurantee Ant Diversity timer canceled - - MlmeQueueDestroy(&pAd->Mlme.Queue); - NdisFreeSpinLock(&pAd->Mlme.TaskLock); - - DBGPRINT(RT_DEBUG_TRACE, ("<== MlmeHalt\n")); -} - -VOID MlmeResetRalinkCounters( - IN PRTMP_ADAPTER pAd) -{ - pAd->RalinkCounters.LastOneSecRxOkDataCnt = pAd->RalinkCounters.OneSecRxOkDataCnt; - // clear all OneSecxxx counters. - pAd->RalinkCounters.OneSecBeaconSentCnt = 0; - pAd->RalinkCounters.OneSecFalseCCACnt = 0; - pAd->RalinkCounters.OneSecRxFcsErrCnt = 0; - pAd->RalinkCounters.OneSecRxOkCnt = 0; - pAd->RalinkCounters.OneSecTxFailCount = 0; - pAd->RalinkCounters.OneSecTxNoRetryOkCount = 0; - pAd->RalinkCounters.OneSecTxRetryOkCount = 0; - pAd->RalinkCounters.OneSecRxOkDataCnt = 0; - - // TODO: for debug only. to be removed - pAd->RalinkCounters.OneSecOsTxCount[QID_AC_BE] = 0; - pAd->RalinkCounters.OneSecOsTxCount[QID_AC_BK] = 0; - pAd->RalinkCounters.OneSecOsTxCount[QID_AC_VI] = 0; - pAd->RalinkCounters.OneSecOsTxCount[QID_AC_VO] = 0; - pAd->RalinkCounters.OneSecDmaDoneCount[QID_AC_BE] = 0; - pAd->RalinkCounters.OneSecDmaDoneCount[QID_AC_BK] = 0; - pAd->RalinkCounters.OneSecDmaDoneCount[QID_AC_VI] = 0; - pAd->RalinkCounters.OneSecDmaDoneCount[QID_AC_VO] = 0; - pAd->RalinkCounters.OneSecTxDoneCount = 0; - pAd->RalinkCounters.OneSecRxCount = 0; - pAd->RalinkCounters.OneSecTxAggregationCount = 0; - pAd->RalinkCounters.OneSecRxAggregationCount = 0; - - return; -} - -unsigned long rx_AMSDU; -unsigned long rx_Total; - -/* - ========================================================================== - Description: - This routine is executed periodically to - - 1. Decide if it's a right time to turn on PwrMgmt bit of all - outgoiing frames - 2. Calculate ChannelQuality based on statistics of the last - period, so that TX rate won't toggling very frequently between a - successful TX and a failed TX. - 3. If the calculated ChannelQuality indicated current connection not - healthy, then a ROAMing attempt is tried here. - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -#define ADHOC_BEACON_LOST_TIME (8*OS_HZ) // 8 sec -VOID MlmePeriodicExec( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3) -{ - ULONG TxTotalCnt; - PRTMP_ADAPTER pAd = (RTMP_ADAPTER *)FunctionContext; - -#ifdef CONFIG_STA_SUPPORT -#endif // CONFIG_STA_SUPPORT // - - // Do nothing if the driver is starting halt state. - // This might happen when timer already been fired before cancel timer with mlmehalt - if ((RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_HALT_IN_PROGRESS | - fRTMP_ADAPTER_RADIO_OFF | - fRTMP_ADAPTER_RADIO_MEASUREMENT | - fRTMP_ADAPTER_RESET_IN_PROGRESS)))) - return; - - RT28XX_MLME_PRE_SANITY_CHECK(pAd); - -#ifdef RALINK_ATE - /* Do not show RSSI until "Normal 1 second Mlme PeriodicExec". */ - if (ATE_ON(pAd)) - { - if (pAd->Mlme.PeriodicRound % MLME_TASK_EXEC_MULTIPLE != (MLME_TASK_EXEC_MULTIPLE - 1)) - { - pAd->Mlme.PeriodicRound ++; - return; - } - } -#endif // RALINK_ATE // - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - // Do nothing if monitor mode is on - if (MONITOR_ON(pAd)) - return; - - if (pAd->Mlme.PeriodicRound & 0x1) - { - // This is the fix for wifi 11n extension channel overlapping test case. for 2860D - if (((pAd->MACVersion & 0xffff) == 0x0101) && - (STA_TGN_WIFI_ON(pAd)) && - (pAd->CommonCfg.IOTestParm.bToggle == FALSE)) - - { - RTMP_IO_WRITE32(pAd, TXOP_CTRL_CFG, 0x24Bf); - pAd->CommonCfg.IOTestParm.bToggle = TRUE; - } - else if ((STA_TGN_WIFI_ON(pAd)) && - ((pAd->MACVersion & 0xffff) == 0x0101)) - { - RTMP_IO_WRITE32(pAd, TXOP_CTRL_CFG, 0x243f); - pAd->CommonCfg.IOTestParm.bToggle = FALSE; - } - } - } -#endif // CONFIG_STA_SUPPORT // - - pAd->bUpdateBcnCntDone = FALSE; - -// RECBATimerTimeout(SystemSpecific1,FunctionContext,SystemSpecific2,SystemSpecific3); - pAd->Mlme.PeriodicRound ++; - -#ifdef RT2870 - // execute every 100ms, update the Tx FIFO Cnt for update Tx Rate. - NICUpdateFifoStaCounters(pAd); -#endif // RT2870 // - // execute every 500ms - if ((pAd->Mlme.PeriodicRound % 5 == 0) && RTMPAutoRateSwitchCheck(pAd)/*(OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED))*/) - { -#ifdef CONFIG_STA_SUPPORT - // perform dynamic tx rate switching based on past TX history - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - if ((OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) - ) - && (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE))) - MlmeDynamicTxRateSwitching(pAd); - } -#endif // CONFIG_STA_SUPPORT // - } - - // Normal 1 second Mlme PeriodicExec. - if (pAd->Mlme.PeriodicRound %MLME_TASK_EXEC_MULTIPLE == 0) - { - pAd->Mlme.OneSecPeriodicRound ++; - -#ifdef RALINK_ATE - if (ATE_ON(pAd)) - { - /* request from Baron : move this routine from later to here */ - /* for showing Rx error count in ATE RXFRAME */ - NICUpdateRawCounters(pAd); - if (pAd->ate.bRxFer == 1) - { - pAd->ate.RxTotalCnt += pAd->ate.RxCntPerSec; - ate_print(KERN_EMERG "MlmePeriodicExec: Rx packet cnt = %d/%d\n", pAd->ate.RxCntPerSec, pAd->ate.RxTotalCnt); - pAd->ate.RxCntPerSec = 0; - - if (pAd->ate.RxAntennaSel == 0) - ate_print(KERN_EMERG "MlmePeriodicExec: Rx AvgRssi0=%d, AvgRssi1=%d, AvgRssi2=%d\n\n", - pAd->ate.AvgRssi0, pAd->ate.AvgRssi1, pAd->ate.AvgRssi2); - else - ate_print(KERN_EMERG "MlmePeriodicExec: Rx AvgRssi=%d\n\n", pAd->ate.AvgRssi0); - } - MlmeResetRalinkCounters(pAd); - return; - } -#endif // RALINK_ATE // - - - if (rx_Total) - { - - // reset counters - rx_AMSDU = 0; - rx_Total = 0; - } - - //ORIBATimerTimeout(pAd); - - // Media status changed, report to NDIS - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_MEDIA_STATE_CHANGE)) - { - RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_MEDIA_STATE_CHANGE); - if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) - { - pAd->IndicateMediaState = NdisMediaStateConnected; - RTMP_IndicateMediaState(pAd); - - } - else - { - pAd->IndicateMediaState = NdisMediaStateDisconnected; - RTMP_IndicateMediaState(pAd); - } - } - - NdisGetSystemUpTime(&pAd->Mlme.Now32); - - // add the most up-to-date h/w raw counters into software variable, so that - // the dynamic tuning mechanism below are based on most up-to-date information - NICUpdateRawCounters(pAd); - -#ifdef RT2870 - RT2870_WatchDog(pAd); -#endif // RT2870 // - -#ifdef DOT11_N_SUPPORT - // Need statistics after read counter. So put after NICUpdateRawCounters - ORIBATimerTimeout(pAd); -#endif // DOT11_N_SUPPORT // - - // The time period for checking antenna is according to traffic - { - if (pAd->Mlme.bEnableAutoAntennaCheck) - { - TxTotalCnt = pAd->RalinkCounters.OneSecTxNoRetryOkCount + - pAd->RalinkCounters.OneSecTxRetryOkCount + - pAd->RalinkCounters.OneSecTxFailCount; - - // dynamic adjust antenna evaluation period according to the traffic - if (TxTotalCnt > 50) - { - if (pAd->Mlme.OneSecPeriodicRound % 10 == 0) - { - AsicEvaluateRxAnt(pAd); - } - } - else - { - if (pAd->Mlme.OneSecPeriodicRound % 3 == 0) - { - AsicEvaluateRxAnt(pAd); - } - } - } - } - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - STAMlmePeriodicExec(pAd); -#endif // CONFIG_STA_SUPPORT // - - MlmeResetRalinkCounters(pAd); - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - { - // When Adhoc beacon is enabled and RTS/CTS is enabled, there is a chance that hardware MAC FSM will run into a deadlock - // and sending CTS-to-self over and over. - // Software Patch Solution: - // 1. Polling debug state register 0x10F4 every one second. - // 2. If in 0x10F4 the ((bit29==1) && (bit7==1)) OR ((bit29==1) && (bit5==1)), it means the deadlock has occurred. - // 3. If the deadlock occurred, reset MAC/BBP by setting 0x1004 to 0x0001 for a while then setting it back to 0x000C again. - - UINT32 MacReg = 0; - - RTMP_IO_READ32(pAd, 0x10F4, &MacReg); - if (((MacReg & 0x20000000) && (MacReg & 0x80)) || ((MacReg & 0x20000000) && (MacReg & 0x20))) - { - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x1); - RTMPusecDelay(1); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0xC); - - DBGPRINT(RT_DEBUG_WARN,("Warning, MAC specific condition occurs \n")); - } - } - } -#endif // CONFIG_STA_SUPPORT // - - RT28XX_MLME_HANDLER(pAd); - } - - - pAd->bUpdateBcnCntDone = FALSE; -} - -#ifdef CONFIG_STA_SUPPORT -VOID STAMlmePeriodicExec( - PRTMP_ADAPTER pAd) -{ - ULONG TxTotalCnt; - int i; - -// -// We return here in ATE mode, because the statistics -// that ATE needs are not collected via this routine. -// -#ifdef RALINK_ATE - // It is supposed that we will never reach here in ATE mode. - ASSERT(!(ATE_ON(pAd))); - if (ATE_ON(pAd)) - return; -#endif // RALINK_ATE // - -#ifdef WPA_SUPPLICANT_SUPPORT - if (pAd->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_DISABLE) -#endif // WPA_SUPPLICANT_SUPPORT // - { - // WPA MIC error should block association attempt for 60 seconds - if (pAd->StaCfg.bBlockAssoc && (pAd->StaCfg.LastMicErrorTime + (60 * OS_HZ) < pAd->Mlme.Now32)) - pAd->StaCfg.bBlockAssoc = FALSE; - } - - if ((pAd->PreMediaState != pAd->IndicateMediaState) && (pAd->CommonCfg.bWirelessEvent)) - { - if (pAd->IndicateMediaState == NdisMediaStateConnected) - { - RTMPSendWirelessEvent(pAd, IW_STA_LINKUP_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); - } - pAd->PreMediaState = pAd->IndicateMediaState; - } - - - - - AsicStaBbpTuning(pAd); - - TxTotalCnt = pAd->RalinkCounters.OneSecTxNoRetryOkCount + - pAd->RalinkCounters.OneSecTxRetryOkCount + - pAd->RalinkCounters.OneSecTxFailCount; - - if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) - { - // update channel quality for Roaming and UI LinkQuality display - MlmeCalculateChannelQuality(pAd, pAd->Mlme.Now32); - } - - // must be AFTER MlmeDynamicTxRateSwitching() because it needs to know if - // Radio is currently in noisy environment - if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) - AsicAdjustTxPower(pAd); - - if (INFRA_ON(pAd)) - { -#ifdef QOS_DLS_SUPPORT - // Check DLS time out, then tear down those session - RTMPCheckDLSTimeOut(pAd); -#endif // QOS_DLS_SUPPORT // - - // Is PSM bit consistent with user power management policy? - // This is the only place that will set PSM bit ON. - if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) - MlmeCheckPsmChange(pAd, pAd->Mlme.Now32); - - pAd->RalinkCounters.LastOneSecTotalTxCount = TxTotalCnt; - - if ((pAd->StaCfg.LastBeaconRxTime + 1*OS_HZ < pAd->Mlme.Now32) && - (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) && - ((TxTotalCnt + pAd->RalinkCounters.OneSecRxOkCnt < 600))) - { - RTMPSetAGCInitValue(pAd, BW_20); - DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - No BEACON. restore R66 to the low bound(%d) \n", (0x2E + GET_LNA_GAIN(pAd)))); - } - - //if ((pAd->RalinkCounters.OneSecTxNoRetryOkCount == 0) && - // (pAd->RalinkCounters.OneSecTxRetryOkCount == 0)) - { - if (pAd->CommonCfg.bAPSDCapable && pAd->CommonCfg.APEdcaParm.bAPSDCapable) - { - // When APSD is enabled, the period changes as 20 sec - if ((pAd->Mlme.OneSecPeriodicRound % 20) == 8) - RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, TRUE); - } - else - { - // Send out a NULL frame every 10 sec to inform AP that STA is still alive (Avoid being age out) - if ((pAd->Mlme.OneSecPeriodicRound % 10) == 8) - { - if (pAd->CommonCfg.bWmmCapable) - RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, TRUE); - else - RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, FALSE); - } - } - } - - if (CQI_IS_DEAD(pAd->Mlme.ChannelQuality)) - { - DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - No BEACON. Dead CQI. Auto Recovery attempt #%ld\n", pAd->RalinkCounters.BadCQIAutoRecoveryCount)); - pAd->StaCfg.CCXAdjacentAPReportFlag = TRUE; - pAd->StaCfg.CCXAdjacentAPLinkDownTime = pAd->StaCfg.LastBeaconRxTime; - - // Lost AP, send disconnect & link down event - LinkDown(pAd, FALSE); - -#ifdef WPA_SUPPLICANT_SUPPORT -#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT - if (pAd->StaCfg.WpaSupplicantUP) - { - union iwreq_data wrqu; - //send disassociate event to wpa_supplicant - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.flags = RT_DISASSOC_EVENT_FLAG; - wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); - } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // -#endif // WPA_SUPPLICANT_SUPPORT // - -#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT - { - union iwreq_data wrqu; - memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN); - wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); - } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // - - // RTMPPatchMacBbpBug(pAd); - MlmeAutoReconnectLastSSID(pAd); - } - else if (CQI_IS_BAD(pAd->Mlme.ChannelQuality)) - { - pAd->RalinkCounters.BadCQIAutoRecoveryCount ++; - DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - Bad CQI. Auto Recovery attempt #%ld\n", pAd->RalinkCounters.BadCQIAutoRecoveryCount)); - MlmeAutoReconnectLastSSID(pAd); - } - - // Add auto seamless roaming - if (pAd->StaCfg.bFastRoaming) - { - SHORT dBmToRoam = (SHORT)pAd->StaCfg.dBmToRoam; - - DBGPRINT(RT_DEBUG_TRACE, ("Rssi=%d, dBmToRoam=%d\n", RTMPMaxRssi(pAd, pAd->StaCfg.RssiSample.LastRssi0, pAd->StaCfg.RssiSample.LastRssi1, pAd->StaCfg.RssiSample.LastRssi2), (CHAR)dBmToRoam)); - - if (RTMPMaxRssi(pAd, pAd->StaCfg.RssiSample.LastRssi0, pAd->StaCfg.RssiSample.LastRssi1, pAd->StaCfg.RssiSample.LastRssi2) <= (CHAR)dBmToRoam) - { - MlmeCheckForFastRoaming(pAd, pAd->Mlme.Now32); - } - } - } - else if (ADHOC_ON(pAd)) - { - //radar detect - if ((pAd->CommonCfg.Channel > 14) - && (pAd->CommonCfg.bIEEE80211H == 1) - && RadarChannelCheck(pAd, pAd->CommonCfg.Channel)) - { - RadarDetectPeriodic(pAd); - } - - // If all peers leave, and this STA becomes the last one in this IBSS, then change MediaState - // to DISCONNECTED. But still holding this IBSS (i.e. sending BEACON) so that other STAs can - // join later. - if ((pAd->StaCfg.LastBeaconRxTime + ADHOC_BEACON_LOST_TIME < pAd->Mlme.Now32) && - OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) - { - MLME_START_REQ_STRUCT StartReq; - - DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - excessive BEACON lost, last STA in this IBSS, MediaState=Disconnected\n")); - LinkDown(pAd, FALSE); - - StartParmFill(pAd, &StartReq, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen); - MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_START_REQ, sizeof(MLME_START_REQ_STRUCT), &StartReq); - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_START; - } - - for (i = 1; i < MAX_LEN_OF_MAC_TABLE; i++) - { - MAC_TABLE_ENTRY *pEntry = &pAd->MacTab.Content[i]; - - if (pEntry->ValidAsCLI == FALSE) - continue; - - if (pEntry->LastBeaconRxTime + ADHOC_BEACON_LOST_TIME < pAd->Mlme.Now32) - MacTableDeleteEntry(pAd, pEntry->Aid, pEntry->Addr); - } - } - else // no INFRA nor ADHOC connection - { - - if (pAd->StaCfg.bScanReqIsFromWebUI && - ((pAd->StaCfg.LastScanTime + 30 * OS_HZ) > pAd->Mlme.Now32)) - goto SKIP_AUTO_SCAN_CONN; - else - pAd->StaCfg.bScanReqIsFromWebUI = FALSE; - - if ((pAd->StaCfg.bAutoReconnect == TRUE) - && RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_START_UP) - && (MlmeValidateSSID(pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.AutoReconnectSsidLen) == TRUE)) - { - if ((pAd->ScanTab.BssNr==0) && (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE)) - { - MLME_SCAN_REQ_STRUCT ScanReq; - - if ((pAd->StaCfg.LastScanTime + 10 * OS_HZ) < pAd->Mlme.Now32) - { - DBGPRINT(RT_DEBUG_TRACE, ("STAMlmePeriodicExec():CNTL - ScanTab.BssNr==0, start a new ACTIVE scan SSID[%s]\n", pAd->MlmeAux.AutoReconnectSsid)); - ScanParmFill(pAd, &ScanReq, pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.AutoReconnectSsidLen, BSS_ANY, SCAN_ACTIVE); - MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq); - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN; - // Reset Missed scan number - pAd->StaCfg.LastScanTime = pAd->Mlme.Now32; - } - else if (pAd->StaCfg.BssType == BSS_ADHOC) // Quit the forever scan when in a very clean room - MlmeAutoReconnectLastSSID(pAd); - } - else if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) - { - if ((pAd->Mlme.OneSecPeriodicRound % 7) == 0) - { - MlmeAutoScan(pAd); - pAd->StaCfg.LastScanTime = pAd->Mlme.Now32; - } - else - { -#ifdef CARRIER_DETECTION_SUPPORT // Roger sync Carrier - if (pAd->CommonCfg.CarrierDetect.Enable == TRUE) - { - if ((pAd->Mlme.OneSecPeriodicRound % 5) == 1) - MlmeAutoReconnectLastSSID(pAd); - } - else -#endif // CARRIER_DETECTION_SUPPORT // - MlmeAutoReconnectLastSSID(pAd); - } - } - } - } - -SKIP_AUTO_SCAN_CONN: - -#ifdef DOT11_N_SUPPORT - if ((pAd->MacTab.Content[BSSID_WCID].TXBAbitmap !=0) && (pAd->MacTab.fAnyBASession == FALSE)) - { - pAd->MacTab.fAnyBASession = TRUE; - AsicUpdateProtect(pAd, HT_FORCERTSCTS, ALLN_SETPROTECT, FALSE, FALSE); - } - else if ((pAd->MacTab.Content[BSSID_WCID].TXBAbitmap ==0) && (pAd->MacTab.fAnyBASession == TRUE)) - { - pAd->MacTab.fAnyBASession = FALSE; - AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, ALLN_SETPROTECT, FALSE, FALSE); - } -#endif // DOT11_N_SUPPORT // - - -#ifdef DOT11_N_SUPPORT -#ifdef DOT11N_DRAFT3 - if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_SCAN_2040)) - TriEventCounterMaintenance(pAd); -#endif // DOT11N_DRAFT3 // -#endif // DOT11_N_SUPPORT // - - return; -} - -// Link down report -VOID LinkDownExec( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3) -{ - - RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext; - - pAd->IndicateMediaState = NdisMediaStateDisconnected; - RTMP_IndicateMediaState(pAd); - pAd->ExtraInfo = GENERAL_LINK_DOWN; -} - -// IRQL = DISPATCH_LEVEL -VOID MlmeAutoScan( - IN PRTMP_ADAPTER pAd) -{ - // check CntlMachine.CurrState to avoid collision with NDIS SetOID request - if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) - { - DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - Driver auto scan\n")); - MlmeEnqueue(pAd, - MLME_CNTL_STATE_MACHINE, - OID_802_11_BSSID_LIST_SCAN, - 0, - NULL); - RT28XX_MLME_HANDLER(pAd); - } -} - -// IRQL = DISPATCH_LEVEL -VOID MlmeAutoReconnectLastSSID( - IN PRTMP_ADAPTER pAd) -{ - - - // check CntlMachine.CurrState to avoid collision with NDIS SetOID request - if ((pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) && - (MlmeValidateSSID(pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.AutoReconnectSsidLen) == TRUE)) - { - NDIS_802_11_SSID OidSsid; - OidSsid.SsidLength = pAd->MlmeAux.AutoReconnectSsidLen; - NdisMoveMemory(OidSsid.Ssid, pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.AutoReconnectSsidLen); - - DBGPRINT(RT_DEBUG_TRACE, ("Driver auto reconnect to last OID_802_11_SSID setting - %s, len - %d\n", pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.AutoReconnectSsidLen)); - MlmeEnqueue(pAd, - MLME_CNTL_STATE_MACHINE, - OID_802_11_SSID, - sizeof(NDIS_802_11_SSID), - &OidSsid); - RT28XX_MLME_HANDLER(pAd); - } -} -#endif // CONFIG_STA_SUPPORT // - -/* - ========================================================================== - Validate SSID for connection try and rescan purpose - Valid SSID will have visible chars only. - The valid length is from 0 to 32. - IRQL = DISPATCH_LEVEL - ========================================================================== - */ -BOOLEAN MlmeValidateSSID( - IN PUCHAR pSsid, - IN UCHAR SsidLen) -{ - int index; - - if (SsidLen > MAX_LEN_OF_SSID) - return (FALSE); - - // Check each character value - for (index = 0; index < SsidLen; index++) - { - if (pSsid[index] < 0x20) - return (FALSE); - } - - // All checked - return (TRUE); -} - -VOID MlmeSelectTxRateTable( - IN PRTMP_ADAPTER pAd, - IN PMAC_TABLE_ENTRY pEntry, - IN PUCHAR *ppTable, - IN PUCHAR pTableSize, - IN PUCHAR pInitTxRateIdx) -{ - do - { - // decide the rate table for tuning - if (pAd->CommonCfg.TxRateTableSize > 0) - { - *ppTable = RateSwitchTable; - *pTableSize = RateSwitchTable[0]; - *pInitTxRateIdx = RateSwitchTable[1]; - - break; - } - -#ifdef CONFIG_STA_SUPPORT - if ((pAd->OpMode == OPMODE_STA) && ADHOC_ON(pAd)) - { -#ifdef DOT11_N_SUPPORT - if ((pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) && - (pEntry->HTCapability.MCSSet[0] == 0xff) && - ((pEntry->HTCapability.MCSSet[1] == 0x00) || (pAd->Antenna.field.TxPath == 1))) - {// 11N 1S Adhoc - *ppTable = RateSwitchTable11N1S; - *pTableSize = RateSwitchTable11N1S[0]; - *pInitTxRateIdx = RateSwitchTable11N1S[1]; - - } - else if ((pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) && - (pEntry->HTCapability.MCSSet[0] == 0xff) && - (pEntry->HTCapability.MCSSet[1] == 0xff) && - (pAd->Antenna.field.TxPath == 2)) - {// 11N 2S Adhoc - if (pAd->LatchRfRegs.Channel <= 14) - { - *ppTable = RateSwitchTable11N2S; - *pTableSize = RateSwitchTable11N2S[0]; - *pInitTxRateIdx = RateSwitchTable11N2S[1]; - } - else - { - *ppTable = RateSwitchTable11N2SForABand; - *pTableSize = RateSwitchTable11N2SForABand[0]; - *pInitTxRateIdx = RateSwitchTable11N2SForABand[1]; - } - - } - else -#endif // DOT11_N_SUPPORT // - if ((pEntry->RateLen == 4) -#ifdef DOT11_N_SUPPORT - && (pEntry->HTCapability.MCSSet[0] == 0) && (pEntry->HTCapability.MCSSet[1] == 0) -#endif // DOT11_N_SUPPORT // - ) - { - *ppTable = RateSwitchTable11B; - *pTableSize = RateSwitchTable11B[0]; - *pInitTxRateIdx = RateSwitchTable11B[1]; - - } - else if (pAd->LatchRfRegs.Channel <= 14) - { - *ppTable = RateSwitchTable11BG; - *pTableSize = RateSwitchTable11BG[0]; - *pInitTxRateIdx = RateSwitchTable11BG[1]; - - } - else - { - *ppTable = RateSwitchTable11G; - *pTableSize = RateSwitchTable11G[0]; - *pInitTxRateIdx = RateSwitchTable11G[1]; - - } - break; - } -#endif // CONFIG_STA_SUPPORT // - -#ifdef DOT11_N_SUPPORT - //if ((pAd->StaActive.SupRateLen + pAd->StaActive.ExtRateLen == 12) && (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0xff) && - // ((pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0x00) || (pAd->Antenna.field.TxPath == 1))) - if ((pEntry->RateLen == 12) && (pEntry->HTCapability.MCSSet[0] == 0xff) && - ((pEntry->HTCapability.MCSSet[1] == 0x00) || (pAd->CommonCfg.TxStream == 1))) - {// 11BGN 1S AP - *ppTable = RateSwitchTable11BGN1S; - *pTableSize = RateSwitchTable11BGN1S[0]; - *pInitTxRateIdx = RateSwitchTable11BGN1S[1]; - - break; - } - - //else if ((pAd->StaActive.SupRateLen + pAd->StaActive.ExtRateLen == 12) && (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0xff) && - // (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0xff) && (pAd->Antenna.field.TxPath == 2)) - if ((pEntry->RateLen == 12) && (pEntry->HTCapability.MCSSet[0] == 0xff) && - (pEntry->HTCapability.MCSSet[1] == 0xff) && (pAd->CommonCfg.TxStream == 2)) - {// 11BGN 2S AP - if (pAd->LatchRfRegs.Channel <= 14) - { - *ppTable = RateSwitchTable11BGN2S; - *pTableSize = RateSwitchTable11BGN2S[0]; - *pInitTxRateIdx = RateSwitchTable11BGN2S[1]; - - } - else - { - *ppTable = RateSwitchTable11BGN2SForABand; - *pTableSize = RateSwitchTable11BGN2SForABand[0]; - *pInitTxRateIdx = RateSwitchTable11BGN2SForABand[1]; - - } - break; - } - - //else if ((pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0xff) && ((pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0x00) || (pAd->Antenna.field.TxPath == 1))) - if ((pEntry->HTCapability.MCSSet[0] == 0xff) && ((pEntry->HTCapability.MCSSet[1] == 0x00) || (pAd->CommonCfg.TxStream == 1))) - {// 11N 1S AP - *ppTable = RateSwitchTable11N1S; - *pTableSize = RateSwitchTable11N1S[0]; - *pInitTxRateIdx = RateSwitchTable11N1S[1]; - - break; - } - - //else if ((pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0xff) && (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0xff) && (pAd->Antenna.field.TxPath == 2)) - if ((pEntry->HTCapability.MCSSet[0] == 0xff) && (pEntry->HTCapability.MCSSet[1] == 0xff) && (pAd->CommonCfg.TxStream == 2)) - {// 11N 2S AP - if (pAd->LatchRfRegs.Channel <= 14) - { - *ppTable = RateSwitchTable11N2S; - *pTableSize = RateSwitchTable11N2S[0]; - *pInitTxRateIdx = RateSwitchTable11N2S[1]; - } - else - { - *ppTable = RateSwitchTable11N2SForABand; - *pTableSize = RateSwitchTable11N2SForABand[0]; - *pInitTxRateIdx = RateSwitchTable11N2SForABand[1]; - } - - break; - } -#endif // DOT11_N_SUPPORT // - //else if ((pAd->StaActive.SupRateLen == 4) && (pAd->StaActive.ExtRateLen == 0) && (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0) && (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0)) - if ((pEntry->RateLen == 4) -#ifdef DOT11_N_SUPPORT -//Iverson mark for Adhoc b mode,sta will use rate 54 Mbps when connect with sta b/g/n mode -// && (pEntry->HTCapability.MCSSet[0] == 0) && (pEntry->HTCapability.MCSSet[1] == 0) -#endif // DOT11_N_SUPPORT // - ) - {// B only AP - *ppTable = RateSwitchTable11B; - *pTableSize = RateSwitchTable11B[0]; - *pInitTxRateIdx = RateSwitchTable11B[1]; - - break; - } - - //else if ((pAd->StaActive.SupRateLen + pAd->StaActive.ExtRateLen > 8) && (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0) && (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0)) - if ((pEntry->RateLen > 8) -#ifdef DOT11_N_SUPPORT - && (pEntry->HTCapability.MCSSet[0] == 0) && (pEntry->HTCapability.MCSSet[1] == 0) -#endif // DOT11_N_SUPPORT // - ) - {// B/G mixed AP - *ppTable = RateSwitchTable11BG; - *pTableSize = RateSwitchTable11BG[0]; - *pInitTxRateIdx = RateSwitchTable11BG[1]; - - break; - } - - //else if ((pAd->StaActive.SupRateLen + pAd->StaActive.ExtRateLen == 8) && (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0) && (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0)) - if ((pEntry->RateLen == 8) -#ifdef DOT11_N_SUPPORT - && (pEntry->HTCapability.MCSSet[0] == 0) && (pEntry->HTCapability.MCSSet[1] == 0) -#endif // DOT11_N_SUPPORT // - ) - {// G only AP - *ppTable = RateSwitchTable11G; - *pTableSize = RateSwitchTable11G[0]; - *pInitTxRateIdx = RateSwitchTable11G[1]; - - break; - } -#ifdef DOT11_N_SUPPORT -#endif // DOT11_N_SUPPORT // - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { -#ifdef DOT11_N_SUPPORT - //else if ((pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0) && (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0)) - if ((pEntry->HTCapability.MCSSet[0] == 0) && (pEntry->HTCapability.MCSSet[1] == 0)) -#endif // DOT11_N_SUPPORT // - { // Legacy mode - if (pAd->CommonCfg.MaxTxRate <= RATE_11) - { - *ppTable = RateSwitchTable11B; - *pTableSize = RateSwitchTable11B[0]; - *pInitTxRateIdx = RateSwitchTable11B[1]; - } - else if ((pAd->CommonCfg.MaxTxRate > RATE_11) && (pAd->CommonCfg.MinTxRate > RATE_11)) - { - *ppTable = RateSwitchTable11G; - *pTableSize = RateSwitchTable11G[0]; - *pInitTxRateIdx = RateSwitchTable11G[1]; - - } - else - { - *ppTable = RateSwitchTable11BG; - *pTableSize = RateSwitchTable11BG[0]; - *pInitTxRateIdx = RateSwitchTable11BG[1]; - } - break; - } -#ifdef DOT11_N_SUPPORT - if (pAd->LatchRfRegs.Channel <= 14) - { - if (pAd->CommonCfg.TxStream == 1) - { - *ppTable = RateSwitchTable11N1S; - *pTableSize = RateSwitchTable11N1S[0]; - *pInitTxRateIdx = RateSwitchTable11N1S[1]; - DBGPRINT_RAW(RT_DEBUG_ERROR,("DRS: unkown mode,default use 11N 1S AP \n")); - } - else - { - *ppTable = RateSwitchTable11N2S; - *pTableSize = RateSwitchTable11N2S[0]; - *pInitTxRateIdx = RateSwitchTable11N2S[1]; - DBGPRINT_RAW(RT_DEBUG_ERROR,("DRS: unkown mode,default use 11N 2S AP \n")); - } - } - else - { - if (pAd->CommonCfg.TxStream == 1) - { - *ppTable = RateSwitchTable11N1S; - *pTableSize = RateSwitchTable11N1S[0]; - *pInitTxRateIdx = RateSwitchTable11N1S[1]; - DBGPRINT_RAW(RT_DEBUG_ERROR,("DRS: unkown mode,default use 11N 1S AP \n")); - } - else - { - *ppTable = RateSwitchTable11N2SForABand; - *pTableSize = RateSwitchTable11N2SForABand[0]; - *pInitTxRateIdx = RateSwitchTable11N2SForABand[1]; - DBGPRINT_RAW(RT_DEBUG_ERROR,("DRS: unkown mode,default use 11N 2S AP \n")); - } - } -#endif // DOT11_N_SUPPORT // - DBGPRINT_RAW(RT_DEBUG_ERROR,("DRS: unkown mode (SupRateLen=%d, ExtRateLen=%d, MCSSet[0]=0x%x, MCSSet[1]=0x%x)\n", - pAd->StaActive.SupRateLen, pAd->StaActive.ExtRateLen, pAd->StaActive.SupportedPhyInfo.MCSSet[0], pAd->StaActive.SupportedPhyInfo.MCSSet[1])); - } -#endif // CONFIG_STA_SUPPORT // - } while(FALSE); -} - -#ifdef CONFIG_STA_SUPPORT -/* - ========================================================================== - Description: - This routine checks if there're other APs out there capable for - roaming. Caller should call this routine only when Link up in INFRA mode - and channel quality is below CQI_GOOD_THRESHOLD. - - IRQL = DISPATCH_LEVEL - - Output: - ========================================================================== - */ -VOID MlmeCheckForRoaming( - IN PRTMP_ADAPTER pAd, - IN ULONG Now32) -{ - USHORT i; - BSS_TABLE *pRoamTab = &pAd->MlmeAux.RoamTab; - BSS_ENTRY *pBss; - - DBGPRINT(RT_DEBUG_TRACE, ("==> MlmeCheckForRoaming\n")); - // put all roaming candidates into RoamTab, and sort in RSSI order - BssTableInit(pRoamTab); - for (i = 0; i < pAd->ScanTab.BssNr; i++) - { - pBss = &pAd->ScanTab.BssEntry[i]; - - if ((pBss->LastBeaconRxTime + BEACON_LOST_TIME) < Now32) - continue; // AP disappear - if (pBss->Rssi <= RSSI_THRESHOLD_FOR_ROAMING) - continue; // RSSI too weak. forget it. - if (MAC_ADDR_EQUAL(pBss->Bssid, pAd->CommonCfg.Bssid)) - continue; // skip current AP - if (pBss->Rssi < (pAd->StaCfg.RssiSample.LastRssi0 + RSSI_DELTA)) - continue; // only AP with stronger RSSI is eligible for roaming - - // AP passing all above rules is put into roaming candidate table - NdisMoveMemory(&pRoamTab->BssEntry[pRoamTab->BssNr], pBss, sizeof(BSS_ENTRY)); - pRoamTab->BssNr += 1; - } - - if (pRoamTab->BssNr > 0) - { - // check CntlMachine.CurrState to avoid collision with NDIS SetOID request - if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) - { - pAd->RalinkCounters.PoorCQIRoamingCount ++; - DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - Roaming attempt #%ld\n", pAd->RalinkCounters.PoorCQIRoamingCount)); - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_MLME_ROAMING_REQ, 0, NULL); - RT28XX_MLME_HANDLER(pAd); - } - } - DBGPRINT(RT_DEBUG_TRACE, ("<== MlmeCheckForRoaming(# of candidate= %d)\n",pRoamTab->BssNr)); -} - -/* - ========================================================================== - Description: - This routine checks if there're other APs out there capable for - roaming. Caller should call this routine only when link up in INFRA mode - and channel quality is below CQI_GOOD_THRESHOLD. - - IRQL = DISPATCH_LEVEL - - Output: - ========================================================================== - */ -VOID MlmeCheckForFastRoaming( - IN PRTMP_ADAPTER pAd, - IN ULONG Now) -{ - USHORT i; - BSS_TABLE *pRoamTab = &pAd->MlmeAux.RoamTab; - BSS_ENTRY *pBss; - - DBGPRINT(RT_DEBUG_TRACE, ("==> MlmeCheckForFastRoaming\n")); - // put all roaming candidates into RoamTab, and sort in RSSI order - BssTableInit(pRoamTab); - for (i = 0; i < pAd->ScanTab.BssNr; i++) - { - pBss = &pAd->ScanTab.BssEntry[i]; - - if ((pBss->Rssi <= -50) && (pBss->Channel == pAd->CommonCfg.Channel)) - continue; // RSSI too weak. forget it. - if (MAC_ADDR_EQUAL(pBss->Bssid, pAd->CommonCfg.Bssid)) - continue; // skip current AP - if (!SSID_EQUAL(pBss->Ssid, pBss->SsidLen, pAd->CommonCfg.Ssid, pAd->CommonCfg.SsidLen)) - continue; // skip different SSID - if (pBss->Rssi < (RTMPMaxRssi(pAd, pAd->StaCfg.RssiSample.LastRssi0, pAd->StaCfg.RssiSample.LastRssi1, pAd->StaCfg.RssiSample.LastRssi2) + RSSI_DELTA)) - continue; // skip AP without better RSSI - - DBGPRINT(RT_DEBUG_TRACE, ("LastRssi0 = %d, pBss->Rssi = %d\n", RTMPMaxRssi(pAd, pAd->StaCfg.RssiSample.LastRssi0, pAd->StaCfg.RssiSample.LastRssi1, pAd->StaCfg.RssiSample.LastRssi2), pBss->Rssi)); - // AP passing all above rules is put into roaming candidate table - NdisMoveMemory(&pRoamTab->BssEntry[pRoamTab->BssNr], pBss, sizeof(BSS_ENTRY)); - pRoamTab->BssNr += 1; - } - - if (pRoamTab->BssNr > 0) - { - // check CntlMachine.CurrState to avoid collision with NDIS SetOID request - if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) - { - pAd->RalinkCounters.PoorCQIRoamingCount ++; - DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - Roaming attempt #%ld\n", pAd->RalinkCounters.PoorCQIRoamingCount)); - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_MLME_ROAMING_REQ, 0, NULL); - RT28XX_MLME_HANDLER(pAd); - } - } - // Maybe site survey required - else - { - if ((pAd->StaCfg.LastScanTime + 10 * 1000) < Now) - { - // check CntlMachine.CurrState to avoid collision with NDIS SetOID request - DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - Roaming, No eligable entry, try new scan!\n")); - pAd->StaCfg.ScanCnt = 2; - pAd->StaCfg.LastScanTime = Now; - MlmeAutoScan(pAd); - } - } - - DBGPRINT(RT_DEBUG_TRACE, ("<== MlmeCheckForFastRoaming (BssNr=%d)\n", pRoamTab->BssNr)); -} - -/* - ========================================================================== - Description: - This routine calculates TxPER, RxPER of the past N-sec period. And - according to the calculation result, ChannelQuality is calculated here - to decide if current AP is still doing the job. - - If ChannelQuality is not good, a ROAMing attempt may be tried later. - Output: - StaCfg.ChannelQuality - 0..100 - - IRQL = DISPATCH_LEVEL - - NOTE: This routine decide channle quality based on RX CRC error ratio. - Caller should make sure a function call to NICUpdateRawCounters(pAd) - is performed right before this routine, so that this routine can decide - channel quality based on the most up-to-date information - ========================================================================== - */ -VOID MlmeCalculateChannelQuality( - IN PRTMP_ADAPTER pAd, - IN ULONG Now32) -{ - ULONG TxOkCnt, TxCnt, TxPER, TxPRR; - ULONG RxCnt, RxPER; - UCHAR NorRssi; - CHAR MaxRssi; - ULONG BeaconLostTime = BEACON_LOST_TIME; - -#ifdef CARRIER_DETECTION_SUPPORT // Roger sync Carrier - // longer beacon lost time when carrier detection enabled - if (pAd->CommonCfg.CarrierDetect.Enable == TRUE) - { - BeaconLostTime = BEACON_LOST_TIME + BEACON_LOST_TIME/2; - } -#endif // CARRIER_DETECTION_SUPPORT // - - MaxRssi = RTMPMaxRssi(pAd, pAd->StaCfg.RssiSample.LastRssi0, pAd->StaCfg.RssiSample.LastRssi1, pAd->StaCfg.RssiSample.LastRssi2); - - // - // calculate TX packet error ratio and TX retry ratio - if too few TX samples, skip TX related statistics - // - TxOkCnt = pAd->RalinkCounters.OneSecTxNoRetryOkCount + pAd->RalinkCounters.OneSecTxRetryOkCount; - TxCnt = TxOkCnt + pAd->RalinkCounters.OneSecTxFailCount; - if (TxCnt < 5) - { - TxPER = 0; - TxPRR = 0; - } - else - { - TxPER = (pAd->RalinkCounters.OneSecTxFailCount * 100) / TxCnt; - TxPRR = ((TxCnt - pAd->RalinkCounters.OneSecTxNoRetryOkCount) * 100) / TxCnt; - } - - // - // calculate RX PER - don't take RxPER into consideration if too few sample - // - RxCnt = pAd->RalinkCounters.OneSecRxOkCnt + pAd->RalinkCounters.OneSecRxFcsErrCnt; - if (RxCnt < 5) - RxPER = 0; - else - RxPER = (pAd->RalinkCounters.OneSecRxFcsErrCnt * 100) / RxCnt; - - // - // decide ChannelQuality based on: 1)last BEACON received time, 2)last RSSI, 3)TxPER, and 4)RxPER - // - if (INFRA_ON(pAd) && - (pAd->RalinkCounters.OneSecTxNoRetryOkCount < 2) && // no heavy traffic - (pAd->StaCfg.LastBeaconRxTime + BeaconLostTime < Now32)) - { - DBGPRINT(RT_DEBUG_TRACE, ("BEACON lost > %ld msec with TxOkCnt=%ld -> CQI=0\n", BeaconLostTime, TxOkCnt)); - pAd->Mlme.ChannelQuality = 0; - } - else - { - // Normalize Rssi - if (MaxRssi > -40) - NorRssi = 100; - else if (MaxRssi < -90) - NorRssi = 0; - else - NorRssi = (MaxRssi + 90) * 2; - - // ChannelQuality = W1*RSSI + W2*TxPRR + W3*RxPER (RSSI 0..100), (TxPER 100..0), (RxPER 100..0) - pAd->Mlme.ChannelQuality = (RSSI_WEIGHTING * NorRssi + - TX_WEIGHTING * (100 - TxPRR) + - RX_WEIGHTING* (100 - RxPER)) / 100; - if (pAd->Mlme.ChannelQuality >= 100) - pAd->Mlme.ChannelQuality = 100; - } - -} - -VOID MlmeSetTxRate( - IN PRTMP_ADAPTER pAd, - IN PMAC_TABLE_ENTRY pEntry, - IN PRTMP_TX_RATE_SWITCH pTxRate) -{ - UCHAR MaxMode = MODE_OFDM; - -#ifdef DOT11_N_SUPPORT - MaxMode = MODE_HTGREENFIELD; - - if (pTxRate->STBC && (pAd->StaCfg.MaxHTPhyMode.field.STBC) && (pAd->Antenna.field.TxPath == 2)) - pAd->StaCfg.HTPhyMode.field.STBC = STBC_USE; - else -#endif // DOT11_N_SUPPORT // - pAd->StaCfg.HTPhyMode.field.STBC = STBC_NONE; - - if (pTxRate->CurrMCS < MCS_AUTO) - pAd->StaCfg.HTPhyMode.field.MCS = pTxRate->CurrMCS; - - if (pAd->StaCfg.HTPhyMode.field.MCS > 7) - pAd->StaCfg.HTPhyMode.field.STBC = STBC_NONE; - - if (ADHOC_ON(pAd)) - { - // If peer adhoc is b-only mode, we can't send 11g rate. - pAd->StaCfg.HTPhyMode.field.ShortGI = GI_800; - pEntry->HTPhyMode.field.STBC = STBC_NONE; - - // - // For Adhoc MODE_CCK, driver will use AdhocBOnlyJoined flag to roll back to B only if necessary - // - pEntry->HTPhyMode.field.MODE = pTxRate->Mode; - pEntry->HTPhyMode.field.ShortGI = pAd->StaCfg.HTPhyMode.field.ShortGI; - pEntry->HTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; - - // Patch speed error in status page - pAd->StaCfg.HTPhyMode.field.MODE = pEntry->HTPhyMode.field.MODE; - } - else - { - if (pTxRate->Mode <= MaxMode) - pAd->StaCfg.HTPhyMode.field.MODE = pTxRate->Mode; - -#ifdef DOT11_N_SUPPORT - if (pTxRate->ShortGI && (pAd->StaCfg.MaxHTPhyMode.field.ShortGI)) - pAd->StaCfg.HTPhyMode.field.ShortGI = GI_400; - else -#endif // DOT11_N_SUPPORT // - pAd->StaCfg.HTPhyMode.field.ShortGI = GI_800; - -#ifdef DOT11_N_SUPPORT - // Reexam each bandwidth's SGI support. - if (pAd->StaCfg.HTPhyMode.field.ShortGI == GI_400) - { - if ((pEntry->HTPhyMode.field.BW == BW_20) && (!CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_SGI20_CAPABLE))) - pAd->StaCfg.HTPhyMode.field.ShortGI = GI_800; - if ((pEntry->HTPhyMode.field.BW == BW_40) && (!CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_SGI40_CAPABLE))) - pAd->StaCfg.HTPhyMode.field.ShortGI = GI_800; - } - - // Turn RTS/CTS rate to 6Mbps. - if ((pEntry->HTPhyMode.field.MCS == 0) && (pAd->StaCfg.HTPhyMode.field.MCS != 0)) - { - pEntry->HTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; - if (pAd->MacTab.fAnyBASession) - { - AsicUpdateProtect(pAd, HT_FORCERTSCTS, ALLN_SETPROTECT, TRUE, (BOOLEAN)pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent); - } - else - { - AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, ALLN_SETPROTECT, TRUE, (BOOLEAN)pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent); - } - } - else if ((pEntry->HTPhyMode.field.MCS == 8) && (pAd->StaCfg.HTPhyMode.field.MCS != 8)) - { - pEntry->HTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; - if (pAd->MacTab.fAnyBASession) - { - AsicUpdateProtect(pAd, HT_FORCERTSCTS, ALLN_SETPROTECT, TRUE, (BOOLEAN)pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent); - } - else - { - AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, ALLN_SETPROTECT, TRUE, (BOOLEAN)pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent); - } - } - else if ((pEntry->HTPhyMode.field.MCS != 0) && (pAd->StaCfg.HTPhyMode.field.MCS == 0)) - { - AsicUpdateProtect(pAd, HT_RTSCTS_6M, ALLN_SETPROTECT, TRUE, (BOOLEAN)pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent); - - } - else if ((pEntry->HTPhyMode.field.MCS != 8) && (pAd->StaCfg.HTPhyMode.field.MCS == 8)) - { - AsicUpdateProtect(pAd, HT_RTSCTS_6M, ALLN_SETPROTECT, TRUE, (BOOLEAN)pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent); - } -#endif // DOT11_N_SUPPORT // - - pEntry->HTPhyMode.field.STBC = pAd->StaCfg.HTPhyMode.field.STBC; - pEntry->HTPhyMode.field.ShortGI = pAd->StaCfg.HTPhyMode.field.ShortGI; - pEntry->HTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; - pEntry->HTPhyMode.field.MODE = pAd->StaCfg.HTPhyMode.field.MODE; -#ifdef DOT11_N_SUPPORT - if ((pAd->StaCfg.MaxHTPhyMode.field.MODE == MODE_HTGREENFIELD) && - pAd->WIFItestbed.bGreenField) - pEntry->HTPhyMode.field.MODE = MODE_HTGREENFIELD; -#endif // DOT11_N_SUPPORT // - } - - pAd->LastTxRate = (USHORT)(pEntry->HTPhyMode.word); -} - -/* - ========================================================================== - Description: - This routine calculates the acumulated TxPER of eaxh TxRate. And - according to the calculation result, change CommonCfg.TxRate which - is the stable TX Rate we expect the Radio situation could sustained. - - CommonCfg.TxRate will change dynamically within {RATE_1/RATE_6, MaxTxRate} - Output: - CommonCfg.TxRate - - - IRQL = DISPATCH_LEVEL - - NOTE: - call this routine every second - ========================================================================== - */ -VOID MlmeDynamicTxRateSwitching( - IN PRTMP_ADAPTER pAd) -{ - UCHAR UpRateIdx = 0, DownRateIdx = 0, CurrRateIdx; - ULONG i, AccuTxTotalCnt = 0, TxTotalCnt; - ULONG TxErrorRatio = 0; - BOOLEAN bTxRateChanged, bUpgradeQuality = FALSE; - PRTMP_TX_RATE_SWITCH pCurrTxRate, pNextTxRate = NULL; - PUCHAR pTable; - UCHAR TableSize = 0; - UCHAR InitTxRateIdx = 0, TrainUp, TrainDown; - CHAR Rssi, RssiOffset = 0; - TX_STA_CNT1_STRUC StaTx1; - TX_STA_CNT0_STRUC TxStaCnt0; - ULONG TxRetransmit = 0, TxSuccess = 0, TxFailCount = 0; - MAC_TABLE_ENTRY *pEntry; - -#ifdef RALINK_ATE - if (ATE_ON(pAd)) - { - return; - } -#endif // RALINK_ATE // - - // - // walk through MAC table, see if need to change AP's TX rate toward each entry - // - for (i = 1; i < MAX_LEN_OF_MAC_TABLE; i++) - { - pEntry = &pAd->MacTab.Content[i]; - - // check if this entry need to switch rate automatically - if (RTMPCheckEntryEnableAutoRateSwitch(pAd, pEntry) == FALSE) - continue; - - if ((pAd->MacTab.Size == 1) || (pEntry->ValidAsDls)) - { - Rssi = RTMPMaxRssi(pAd, - pAd->StaCfg.RssiSample.AvgRssi0, - pAd->StaCfg.RssiSample.AvgRssi1, - pAd->StaCfg.RssiSample.AvgRssi2); - - // Update statistic counter - RTMP_IO_READ32(pAd, TX_STA_CNT0, &TxStaCnt0.word); - RTMP_IO_READ32(pAd, TX_STA_CNT1, &StaTx1.word); - pAd->bUpdateBcnCntDone = TRUE; - TxRetransmit = StaTx1.field.TxRetransmit; - TxSuccess = StaTx1.field.TxSuccess; - TxFailCount = TxStaCnt0.field.TxFailCount; - TxTotalCnt = TxRetransmit + TxSuccess + TxFailCount; - - pAd->RalinkCounters.OneSecTxRetryOkCount += StaTx1.field.TxRetransmit; - pAd->RalinkCounters.OneSecTxNoRetryOkCount += StaTx1.field.TxSuccess; - pAd->RalinkCounters.OneSecTxFailCount += TxStaCnt0.field.TxFailCount; - pAd->WlanCounters.TransmittedFragmentCount.u.LowPart += StaTx1.field.TxSuccess; - pAd->WlanCounters.RetryCount.u.LowPart += StaTx1.field.TxRetransmit; - pAd->WlanCounters.FailedCount.u.LowPart += TxStaCnt0.field.TxFailCount; - - // if no traffic in the past 1-sec period, don't change TX rate, - // but clear all bad history. because the bad history may affect the next - // Chariot throughput test - AccuTxTotalCnt = pAd->RalinkCounters.OneSecTxNoRetryOkCount + - pAd->RalinkCounters.OneSecTxRetryOkCount + - pAd->RalinkCounters.OneSecTxFailCount; - - if (TxTotalCnt) - TxErrorRatio = ((TxRetransmit + TxFailCount) * 100) / TxTotalCnt; - } - else - { - if (INFRA_ON(pAd) && (i == 1)) - Rssi = RTMPMaxRssi(pAd, - pAd->StaCfg.RssiSample.AvgRssi0, - pAd->StaCfg.RssiSample.AvgRssi1, - pAd->StaCfg.RssiSample.AvgRssi2); - else - Rssi = RTMPMaxRssi(pAd, - pEntry->RssiSample.AvgRssi0, - pEntry->RssiSample.AvgRssi1, - pEntry->RssiSample.AvgRssi2); - - TxTotalCnt = pEntry->OneSecTxNoRetryOkCount + - pEntry->OneSecTxRetryOkCount + - pEntry->OneSecTxFailCount; - - if (TxTotalCnt) - TxErrorRatio = ((pEntry->OneSecTxRetryOkCount + pEntry->OneSecTxFailCount) * 100) / TxTotalCnt; - } - - CurrRateIdx = pEntry->CurrTxRateIndex; - - MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize, &InitTxRateIdx); - - if (CurrRateIdx >= TableSize) - { - CurrRateIdx = TableSize - 1; - } - - // When switch from Fixed rate -> auto rate, the REAL TX rate might be different from pAd->CommonCfg.TxRateIndex. - // So need to sync here. - pCurrTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(CurrRateIdx+1)*5]; - if ((pEntry->HTPhyMode.field.MCS != pCurrTxRate->CurrMCS) - //&& (pAd->StaCfg.bAutoTxRateSwitch == TRUE) - ) - { - - // Need to sync Real Tx rate and our record. - // Then return for next DRS. - pCurrTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(InitTxRateIdx+1)*5]; - pEntry->CurrTxRateIndex = InitTxRateIdx; - MlmeSetTxRate(pAd, pEntry, pCurrTxRate); - - // reset all OneSecTx counters - RESET_ONE_SEC_TX_CNT(pEntry); - continue; - } - - // decide the next upgrade rate and downgrade rate, if any - if ((CurrRateIdx > 0) && (CurrRateIdx < (TableSize - 1))) - { - UpRateIdx = CurrRateIdx + 1; - DownRateIdx = CurrRateIdx -1; - } - else if (CurrRateIdx == 0) - { - UpRateIdx = CurrRateIdx + 1; - DownRateIdx = CurrRateIdx; - } - else if (CurrRateIdx == (TableSize - 1)) - { - UpRateIdx = CurrRateIdx; - DownRateIdx = CurrRateIdx - 1; - } - - pCurrTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(CurrRateIdx+1)*5]; - -#ifdef DOT11_N_SUPPORT - if ((Rssi > -65) && (pCurrTxRate->Mode >= MODE_HTMIX)) - { - TrainUp = (pCurrTxRate->TrainUp + (pCurrTxRate->TrainUp >> 1)); - TrainDown = (pCurrTxRate->TrainDown + (pCurrTxRate->TrainDown >> 1)); - } - else -#endif // DOT11_N_SUPPORT // - { - TrainUp = pCurrTxRate->TrainUp; - TrainDown = pCurrTxRate->TrainDown; - } - - //pAd->DrsCounters.LastTimeTxRateChangeAction = pAd->DrsCounters.LastSecTxRateChangeAction; - - // - // Keep the last time TxRateChangeAction status. - // - pEntry->LastTimeTxRateChangeAction = pEntry->LastSecTxRateChangeAction; - - - - // - // CASE 1. when TX samples are fewer than 15, then decide TX rate solely on RSSI - // (criteria copied from RT2500 for Netopia case) - // - if (TxTotalCnt <= 15) - { - CHAR idx = 0; - UCHAR TxRateIdx; - //UCHAR MCS0 = 0, MCS1 = 0, MCS2 = 0, MCS3 = 0, MCS4 = 0, MCS7 = 0, MCS12 = 0, MCS13 = 0, MCS14 = 0, MCS15 = 0; - UCHAR MCS0 = 0, MCS1 = 0, MCS2 = 0, MCS3 = 0, MCS4 = 0, MCS5 =0, MCS6 = 0, MCS7 = 0; - UCHAR MCS12 = 0, MCS13 = 0, MCS14 = 0, MCS15 = 0; - UCHAR MCS20 = 0, MCS21 = 0, MCS22 = 0, MCS23 = 0; // 3*3 - - // check the existence and index of each needed MCS - while (idx < pTable[0]) - { - pCurrTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(idx+1)*5]; - - if (pCurrTxRate->CurrMCS == MCS_0) - { - MCS0 = idx; - } - else if (pCurrTxRate->CurrMCS == MCS_1) - { - MCS1 = idx; - } - else if (pCurrTxRate->CurrMCS == MCS_2) - { - MCS2 = idx; - } - else if (pCurrTxRate->CurrMCS == MCS_3) - { - MCS3 = idx; - } - else if (pCurrTxRate->CurrMCS == MCS_4) - { - MCS4 = idx; - } - else if (pCurrTxRate->CurrMCS == MCS_5) - { - MCS5 = idx; - } - else if (pCurrTxRate->CurrMCS == MCS_6) - { - MCS6 = idx; - } - //else if (pCurrTxRate->CurrMCS == MCS_7) - else if ((pCurrTxRate->CurrMCS == MCS_7) && (pCurrTxRate->ShortGI == GI_800)) // prevent the highest MCS using short GI when 1T and low throughput - { - MCS7 = idx; - } - else if (pCurrTxRate->CurrMCS == MCS_12) - { - MCS12 = idx; - } - else if (pCurrTxRate->CurrMCS == MCS_13) - { - MCS13 = idx; - } - else if (pCurrTxRate->CurrMCS == MCS_14) - { - MCS14 = idx; - } - else if ((pCurrTxRate->CurrMCS == MCS_15) && (pCurrTxRate->ShortGI == GI_800)) - { - MCS15 = idx; - } - else if (pCurrTxRate->CurrMCS == MCS_20) // 3*3 - { - MCS20 = idx; - } - else if (pCurrTxRate->CurrMCS == MCS_21) - { - MCS21 = idx; - } - else if (pCurrTxRate->CurrMCS == MCS_22) - { - MCS22 = idx; - } - else if (pCurrTxRate->CurrMCS == MCS_23) - { - MCS23 = idx; - } - idx ++; - } - - if (pAd->LatchRfRegs.Channel <= 14) - { - if (pAd->NicConfig2.field.ExternalLNAForG) - { - RssiOffset = 2; - } - else - { - RssiOffset = 5; - } - } - else - { - if (pAd->NicConfig2.field.ExternalLNAForA) - { - RssiOffset = 5; - } - else - { - RssiOffset = 8; - } - } -#ifdef DOT11_N_SUPPORT - /*if (MCS15)*/ - if ((pTable == RateSwitchTable11BGN3S) || - (pTable == RateSwitchTable11N3S) || - (pTable == RateSwitchTable)) - {// N mode with 3 stream // 3*3 - if (MCS23 && (Rssi >= -70)) - TxRateIdx = MCS15; - else if (MCS22 && (Rssi >= -72)) - TxRateIdx = MCS14; - else if (MCS21 && (Rssi >= -76)) - TxRateIdx = MCS13; - else if (MCS20 && (Rssi >= -78)) - TxRateIdx = MCS12; - else if (MCS4 && (Rssi >= -82)) - TxRateIdx = MCS4; - else if (MCS3 && (Rssi >= -84)) - TxRateIdx = MCS3; - else if (MCS2 && (Rssi >= -86)) - TxRateIdx = MCS2; - else if (MCS1 && (Rssi >= -88)) - TxRateIdx = MCS1; - else - TxRateIdx = MCS0; - } -// else if ((pTable == RateSwitchTable11BGN2S) || (pTable == RateSwitchTable11BGN2SForABand) ||(pTable == RateSwitchTable11N2S) ||(pTable == RateSwitchTable11N2SForABand) || (pTable == RateSwitchTable)) - else if ((pTable == RateSwitchTable11BGN2S) || (pTable == RateSwitchTable11BGN2SForABand) ||(pTable == RateSwitchTable11N2S) ||(pTable == RateSwitchTable11N2SForABand)) // 3*3 - {// N mode with 2 stream - if (MCS15 && (Rssi >= (-70+RssiOffset))) - TxRateIdx = MCS15; - else if (MCS14 && (Rssi >= (-72+RssiOffset))) - TxRateIdx = MCS14; - else if (MCS13 && (Rssi >= (-76+RssiOffset))) - TxRateIdx = MCS13; - else if (MCS12 && (Rssi >= (-78+RssiOffset))) - TxRateIdx = MCS12; - else if (MCS4 && (Rssi >= (-82+RssiOffset))) - TxRateIdx = MCS4; - else if (MCS3 && (Rssi >= (-84+RssiOffset))) - TxRateIdx = MCS3; - else if (MCS2 && (Rssi >= (-86+RssiOffset))) - TxRateIdx = MCS2; - else if (MCS1 && (Rssi >= (-88+RssiOffset))) - TxRateIdx = MCS1; - else - TxRateIdx = MCS0; - } - else if ((pTable == RateSwitchTable11BGN1S) || (pTable == RateSwitchTable11N1S)) - {// N mode with 1 stream - if (MCS7 && (Rssi > (-72+RssiOffset))) - TxRateIdx = MCS7; - else if (MCS6 && (Rssi > (-74+RssiOffset))) - TxRateIdx = MCS6; - else if (MCS5 && (Rssi > (-77+RssiOffset))) - TxRateIdx = MCS5; - else if (MCS4 && (Rssi > (-79+RssiOffset))) - TxRateIdx = MCS4; - else if (MCS3 && (Rssi > (-81+RssiOffset))) - TxRateIdx = MCS3; - else if (MCS2 && (Rssi > (-83+RssiOffset))) - TxRateIdx = MCS2; - else if (MCS1 && (Rssi > (-86+RssiOffset))) - TxRateIdx = MCS1; - else - TxRateIdx = MCS0; - } - else -#endif // DOT11_N_SUPPORT // - {// Legacy mode - if (MCS7 && (Rssi > -70)) - TxRateIdx = MCS7; - else if (MCS6 && (Rssi > -74)) - TxRateIdx = MCS6; - else if (MCS5 && (Rssi > -78)) - TxRateIdx = MCS5; - else if (MCS4 && (Rssi > -82)) - TxRateIdx = MCS4; - else if (MCS4 == 0) // for B-only mode - TxRateIdx = MCS3; - else if (MCS3 && (Rssi > -85)) - TxRateIdx = MCS3; - else if (MCS2 && (Rssi > -87)) - TxRateIdx = MCS2; - else if (MCS1 && (Rssi > -90)) - TxRateIdx = MCS1; - else - TxRateIdx = MCS0; - } - - // if (TxRateIdx != pAd->CommonCfg.TxRateIndex) - { - pEntry->CurrTxRateIndex = TxRateIdx; - pNextTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(pEntry->CurrTxRateIndex+1)*5]; - MlmeSetTxRate(pAd, pEntry, pNextTxRate); - } - - NdisZeroMemory(pEntry->TxQuality, sizeof(USHORT) * MAX_STEP_OF_TX_RATE_SWITCH); - NdisZeroMemory(pEntry->PER, sizeof(UCHAR) * MAX_STEP_OF_TX_RATE_SWITCH); - pEntry->fLastSecAccordingRSSI = TRUE; - // reset all OneSecTx counters - RESET_ONE_SEC_TX_CNT(pEntry); - - continue; - } - - if (pEntry->fLastSecAccordingRSSI == TRUE) - { - pEntry->fLastSecAccordingRSSI = FALSE; - pEntry->LastSecTxRateChangeAction = 0; - // reset all OneSecTx counters - RESET_ONE_SEC_TX_CNT(pEntry); - - continue; - } - - do - { - BOOLEAN bTrainUpDown = FALSE; - - pEntry->CurrTxRateStableTime ++; - - // downgrade TX quality if PER >= Rate-Down threshold - if (TxErrorRatio >= TrainDown) - { - bTrainUpDown = TRUE; - pEntry->TxQuality[CurrRateIdx] = DRS_TX_QUALITY_WORST_BOUND; - } - // upgrade TX quality if PER <= Rate-Up threshold - else if (TxErrorRatio <= TrainUp) - { - bTrainUpDown = TRUE; - bUpgradeQuality = TRUE; - if (pEntry->TxQuality[CurrRateIdx]) - pEntry->TxQuality[CurrRateIdx] --; // quality very good in CurrRate - - if (pEntry->TxRateUpPenalty) - pEntry->TxRateUpPenalty --; - else if (pEntry->TxQuality[UpRateIdx]) - pEntry->TxQuality[UpRateIdx] --; // may improve next UP rate's quality - } - - pEntry->PER[CurrRateIdx] = (UCHAR)TxErrorRatio; - - if (bTrainUpDown) - { - // perform DRS - consider TxRate Down first, then rate up. - if ((CurrRateIdx != DownRateIdx) && (pEntry->TxQuality[CurrRateIdx] >= DRS_TX_QUALITY_WORST_BOUND)) - { - pEntry->CurrTxRateIndex = DownRateIdx; - } - else if ((CurrRateIdx != UpRateIdx) && (pEntry->TxQuality[UpRateIdx] <= 0)) - { - pEntry->CurrTxRateIndex = UpRateIdx; - } - } - } while (FALSE); - - // if rate-up happen, clear all bad history of all TX rates - if (pEntry->CurrTxRateIndex > CurrRateIdx) - { - pEntry->CurrTxRateStableTime = 0; - pEntry->TxRateUpPenalty = 0; - pEntry->LastSecTxRateChangeAction = 1; // rate UP - NdisZeroMemory(pEntry->TxQuality, sizeof(USHORT) * MAX_STEP_OF_TX_RATE_SWITCH); - NdisZeroMemory(pEntry->PER, sizeof(UCHAR) * MAX_STEP_OF_TX_RATE_SWITCH); - - // - // For TxRate fast train up - // - if (!pAd->StaCfg.StaQuickResponeForRateUpTimerRunning) - { - RTMPSetTimer(&pAd->StaCfg.StaQuickResponeForRateUpTimer, 100); - - pAd->StaCfg.StaQuickResponeForRateUpTimerRunning = TRUE; - } - bTxRateChanged = TRUE; - } - // if rate-down happen, only clear DownRate's bad history - else if (pEntry->CurrTxRateIndex < CurrRateIdx) - { - pEntry->CurrTxRateStableTime = 0; - pEntry->TxRateUpPenalty = 0; // no penalty - pEntry->LastSecTxRateChangeAction = 2; // rate DOWN - pEntry->TxQuality[pEntry->CurrTxRateIndex] = 0; - pEntry->PER[pEntry->CurrTxRateIndex] = 0; - - // - // For TxRate fast train down - // - if (!pAd->StaCfg.StaQuickResponeForRateUpTimerRunning) - { - RTMPSetTimer(&pAd->StaCfg.StaQuickResponeForRateUpTimer, 100); - - pAd->StaCfg.StaQuickResponeForRateUpTimerRunning = TRUE; - } - bTxRateChanged = TRUE; - } - else - { - pEntry->LastSecTxRateChangeAction = 0; // rate no change - bTxRateChanged = FALSE; - } - - pEntry->LastTxOkCount = TxSuccess; - - // reset all OneSecTx counters - RESET_ONE_SEC_TX_CNT(pEntry); - - pNextTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(pEntry->CurrTxRateIndex+1)*5]; - if (bTxRateChanged && pNextTxRate) - { - MlmeSetTxRate(pAd, pEntry, pNextTxRate); - } - } -} - -/* - ======================================================================== - Routine Description: - Station side, Auto TxRate faster train up timer call back function. - - Arguments: - SystemSpecific1 - Not used. - FunctionContext - Pointer to our Adapter context. - SystemSpecific2 - Not used. - SystemSpecific3 - Not used. - - Return Value: - None - - ======================================================================== -*/ -VOID StaQuickResponeForRateUpExec( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3) -{ - PRTMP_ADAPTER pAd = (PRTMP_ADAPTER)FunctionContext; - UCHAR UpRateIdx = 0, DownRateIdx = 0, CurrRateIdx = 0; - ULONG TxTotalCnt; - ULONG TxErrorRatio = 0; - BOOLEAN bTxRateChanged; //, bUpgradeQuality = FALSE; - PRTMP_TX_RATE_SWITCH pCurrTxRate, pNextTxRate = NULL; - PUCHAR pTable; - UCHAR TableSize = 0; - UCHAR InitTxRateIdx = 0, TrainUp, TrainDown; - TX_STA_CNT1_STRUC StaTx1; - TX_STA_CNT0_STRUC TxStaCnt0; - CHAR Rssi, ratio; - ULONG TxRetransmit = 0, TxSuccess = 0, TxFailCount = 0; - MAC_TABLE_ENTRY *pEntry; - ULONG i; - - pAd->StaCfg.StaQuickResponeForRateUpTimerRunning = FALSE; - - // - // walk through MAC table, see if need to change AP's TX rate toward each entry - // - for (i = 1; i < MAX_LEN_OF_MAC_TABLE; i++) - { - pEntry = &pAd->MacTab.Content[i]; - - // check if this entry need to switch rate automatically - if (RTMPCheckEntryEnableAutoRateSwitch(pAd, pEntry) == FALSE) - continue; - - if (INFRA_ON(pAd) && (i == 1)) - Rssi = RTMPMaxRssi(pAd, - pAd->StaCfg.RssiSample.AvgRssi0, - pAd->StaCfg.RssiSample.AvgRssi1, - pAd->StaCfg.RssiSample.AvgRssi2); - else - Rssi = RTMPMaxRssi(pAd, - pEntry->RssiSample.AvgRssi0, - pEntry->RssiSample.AvgRssi1, - pEntry->RssiSample.AvgRssi2); - - CurrRateIdx = pAd->CommonCfg.TxRateIndex; - - MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize, &InitTxRateIdx); - - // decide the next upgrade rate and downgrade rate, if any - if ((CurrRateIdx > 0) && (CurrRateIdx < (TableSize - 1))) - { - UpRateIdx = CurrRateIdx + 1; - DownRateIdx = CurrRateIdx -1; - } - else if (CurrRateIdx == 0) - { - UpRateIdx = CurrRateIdx + 1; - DownRateIdx = CurrRateIdx; - } - else if (CurrRateIdx == (TableSize - 1)) - { - UpRateIdx = CurrRateIdx; - DownRateIdx = CurrRateIdx - 1; - } - - pCurrTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(CurrRateIdx+1)*5]; - -#ifdef DOT11_N_SUPPORT - if ((Rssi > -65) && (pCurrTxRate->Mode >= MODE_HTMIX)) - { - TrainUp = (pCurrTxRate->TrainUp + (pCurrTxRate->TrainUp >> 1)); - TrainDown = (pCurrTxRate->TrainDown + (pCurrTxRate->TrainDown >> 1)); - } - else -#endif // DOT11_N_SUPPORT // - { - TrainUp = pCurrTxRate->TrainUp; - TrainDown = pCurrTxRate->TrainDown; - } - - if (pAd->MacTab.Size == 1) - { - // Update statistic counter - RTMP_IO_READ32(pAd, TX_STA_CNT0, &TxStaCnt0.word); - RTMP_IO_READ32(pAd, TX_STA_CNT1, &StaTx1.word); - - TxRetransmit = StaTx1.field.TxRetransmit; - TxSuccess = StaTx1.field.TxSuccess; - TxFailCount = TxStaCnt0.field.TxFailCount; - TxTotalCnt = TxRetransmit + TxSuccess + TxFailCount; - - pAd->RalinkCounters.OneSecTxRetryOkCount += StaTx1.field.TxRetransmit; - pAd->RalinkCounters.OneSecTxNoRetryOkCount += StaTx1.field.TxSuccess; - pAd->RalinkCounters.OneSecTxFailCount += TxStaCnt0.field.TxFailCount; - pAd->WlanCounters.TransmittedFragmentCount.u.LowPart += StaTx1.field.TxSuccess; - pAd->WlanCounters.RetryCount.u.LowPart += StaTx1.field.TxRetransmit; - pAd->WlanCounters.FailedCount.u.LowPart += TxStaCnt0.field.TxFailCount; - - if (TxTotalCnt) - TxErrorRatio = ((TxRetransmit + TxFailCount) * 100) / TxTotalCnt; - } - else - { - TxTotalCnt = pEntry->OneSecTxNoRetryOkCount + - pEntry->OneSecTxRetryOkCount + - pEntry->OneSecTxFailCount; - - if (TxTotalCnt) - TxErrorRatio = ((pEntry->OneSecTxRetryOkCount + pEntry->OneSecTxFailCount) * 100) / TxTotalCnt; - } - - - // - // CASE 1. when TX samples are fewer than 15, then decide TX rate solely on RSSI - // (criteria copied from RT2500 for Netopia case) - // - if (TxTotalCnt <= 12) - { - NdisZeroMemory(pAd->DrsCounters.TxQuality, sizeof(USHORT) * MAX_STEP_OF_TX_RATE_SWITCH); - NdisZeroMemory(pAd->DrsCounters.PER, sizeof(UCHAR) * MAX_STEP_OF_TX_RATE_SWITCH); - - if ((pAd->DrsCounters.LastSecTxRateChangeAction == 1) && (CurrRateIdx != DownRateIdx)) - { - pAd->CommonCfg.TxRateIndex = DownRateIdx; - pAd->DrsCounters.TxQuality[CurrRateIdx] = DRS_TX_QUALITY_WORST_BOUND; - } - else if ((pAd->DrsCounters.LastSecTxRateChangeAction == 2) && (CurrRateIdx != UpRateIdx)) - { - pAd->CommonCfg.TxRateIndex = UpRateIdx; - } - - DBGPRINT_RAW(RT_DEBUG_TRACE,("QuickDRS: TxTotalCnt <= 15, train back to original rate \n")); - return; - } - - do - { - ULONG OneSecTxNoRetryOKRationCount; - - if (pAd->DrsCounters.LastTimeTxRateChangeAction == 0) - ratio = 5; - else - ratio = 4; - - // downgrade TX quality if PER >= Rate-Down threshold - if (TxErrorRatio >= TrainDown) - { - pAd->DrsCounters.TxQuality[CurrRateIdx] = DRS_TX_QUALITY_WORST_BOUND; - } - - pAd->DrsCounters.PER[CurrRateIdx] = (UCHAR)TxErrorRatio; - - OneSecTxNoRetryOKRationCount = (TxSuccess * ratio); - - // perform DRS - consider TxRate Down first, then rate up. - if ((pAd->DrsCounters.LastSecTxRateChangeAction == 1) && (CurrRateIdx != DownRateIdx)) - { - if ((pAd->DrsCounters.LastTxOkCount + 2) >= OneSecTxNoRetryOKRationCount) - { - pAd->CommonCfg.TxRateIndex = DownRateIdx; - pAd->DrsCounters.TxQuality[CurrRateIdx] = DRS_TX_QUALITY_WORST_BOUND; - - } - - } - else if ((pAd->DrsCounters.LastSecTxRateChangeAction == 2) && (CurrRateIdx != UpRateIdx)) - { - if ((TxErrorRatio >= 50) || (TxErrorRatio >= TrainDown)) - { - - } - else if ((pAd->DrsCounters.LastTxOkCount + 2) >= OneSecTxNoRetryOKRationCount) - { - pAd->CommonCfg.TxRateIndex = UpRateIdx; - } - } - }while (FALSE); - - // if rate-up happen, clear all bad history of all TX rates - if (pAd->CommonCfg.TxRateIndex > CurrRateIdx) - { - pAd->DrsCounters.TxRateUpPenalty = 0; - NdisZeroMemory(pAd->DrsCounters.TxQuality, sizeof(USHORT) * MAX_STEP_OF_TX_RATE_SWITCH); - NdisZeroMemory(pAd->DrsCounters.PER, sizeof(UCHAR) * MAX_STEP_OF_TX_RATE_SWITCH); - bTxRateChanged = TRUE; - } - // if rate-down happen, only clear DownRate's bad history - else if (pAd->CommonCfg.TxRateIndex < CurrRateIdx) - { - DBGPRINT_RAW(RT_DEBUG_TRACE,("QuickDRS: --TX rate from %d to %d \n", CurrRateIdx, pAd->CommonCfg.TxRateIndex)); - - pAd->DrsCounters.TxRateUpPenalty = 0; // no penalty - pAd->DrsCounters.TxQuality[pAd->CommonCfg.TxRateIndex] = 0; - pAd->DrsCounters.PER[pAd->CommonCfg.TxRateIndex] = 0; - bTxRateChanged = TRUE; - } - else - { - bTxRateChanged = FALSE; - } - - pNextTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(pAd->CommonCfg.TxRateIndex+1)*5]; - if (bTxRateChanged && pNextTxRate) - { - MlmeSetTxRate(pAd, pEntry, pNextTxRate); - } - } -} - -/* - ========================================================================== - Description: - This routine is executed periodically inside MlmePeriodicExec() after - association with an AP. - It checks if StaCfg.Psm is consistent with user policy (recorded in - StaCfg.WindowsPowerMode). If not, enforce user policy. However, - there're some conditions to consider: - 1. we don't support power-saving in ADHOC mode, so Psm=PWR_ACTIVE all - the time when Mibss==TRUE - 2. When link up in INFRA mode, Psm should not be switch to PWR_SAVE - if outgoing traffic available in TxRing or MgmtRing. - Output: - 1. change pAd->StaCfg.Psm to PWR_SAVE or leave it untouched - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID MlmeCheckPsmChange( - IN PRTMP_ADAPTER pAd, - IN ULONG Now32) -{ - ULONG PowerMode; - - // condition - - // 1. Psm maybe ON only happen in INFRASTRUCTURE mode - // 2. user wants either MAX_PSP or FAST_PSP - // 3. but current psm is not in PWR_SAVE - // 4. CNTL state machine is not doing SCANning - // 5. no TX SUCCESS event for the past 1-sec period -#ifdef NDIS51_MINIPORT - if (pAd->StaCfg.WindowsPowerProfile == NdisPowerProfileBattery) - PowerMode = pAd->StaCfg.WindowsBatteryPowerMode; - else -#endif - PowerMode = pAd->StaCfg.WindowsPowerMode; - - if (INFRA_ON(pAd) && - (PowerMode != Ndis802_11PowerModeCAM) && - (pAd->StaCfg.Psm == PWR_ACTIVE) && -// (! RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) - (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) /*&& - (pAd->RalinkCounters.OneSecTxNoRetryOkCount == 0) && - (pAd->RalinkCounters.OneSecTxRetryOkCount == 0)*/) - { - // add by johnli, use Rx OK data count per second to calculate throughput - // If Ttraffic is too high ( > 400 Rx per second), don't go to sleep mode. If tx rate is low, use low criteria - // Mode=CCK/MCS=3 => 11 Mbps, Mode=OFDM/MCS=3 => 18 Mbps - if (((pAd->StaCfg.HTPhyMode.field.MCS <= 3) && -/* Iverson mark - (pAd->StaCfg.HTPhyMode.field.MODE <= MODE_OFDM) && -*/ - (pAd->RalinkCounters.OneSecRxOkDataCnt < (ULONG)100)) || - ((pAd->StaCfg.HTPhyMode.field.MCS > 3) && -/* Iverson mark - (pAd->StaCfg.HTPhyMode.field.MODE > MODE_OFDM) && -*/ - (pAd->RalinkCounters.OneSecRxOkDataCnt < (ULONG)400))) - { - // Get this time - NdisGetSystemUpTime(&pAd->Mlme.LastSendNULLpsmTime); - pAd->RalinkCounters.RxCountSinceLastNULL = 0; - MlmeSetPsmBit(pAd, PWR_SAVE); - if (!(pAd->CommonCfg.bAPSDCapable && pAd->CommonCfg.APEdcaParm.bAPSDCapable)) - { - RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, FALSE); - } - else - { - RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, TRUE); - } - } - } -} - -// IRQL = PASSIVE_LEVEL -// IRQL = DISPATCH_LEVEL -VOID MlmeSetPsmBit( - IN PRTMP_ADAPTER pAd, - IN USHORT psm) -{ - AUTO_RSP_CFG_STRUC csr4; - - pAd->StaCfg.Psm = psm; - RTMP_IO_READ32(pAd, AUTO_RSP_CFG, &csr4.word); - csr4.field.AckCtsPsmBit = (psm == PWR_SAVE)? 1:0; - RTMP_IO_WRITE32(pAd, AUTO_RSP_CFG, csr4.word); -} -#endif // CONFIG_STA_SUPPORT // - - -// IRQL = DISPATCH_LEVEL -VOID MlmeSetTxPreamble( - IN PRTMP_ADAPTER pAd, - IN USHORT TxPreamble) -{ - AUTO_RSP_CFG_STRUC csr4; - - // - // Always use Long preamble before verifiation short preamble functionality works well. - // Todo: remove the following line if short preamble functionality works - // - //TxPreamble = Rt802_11PreambleLong; - - RTMP_IO_READ32(pAd, AUTO_RSP_CFG, &csr4.word); - if (TxPreamble == Rt802_11PreambleLong) - { - DBGPRINT(RT_DEBUG_TRACE, ("MlmeSetTxPreamble (= LONG PREAMBLE)\n")); - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED); - csr4.field.AutoResponderPreamble = 0; - } - else - { - // NOTE: 1Mbps should always use long preamble - DBGPRINT(RT_DEBUG_TRACE, ("MlmeSetTxPreamble (= SHORT PREAMBLE)\n")); - OPSTATUS_SET_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED); - csr4.field.AutoResponderPreamble = 1; - } - - RTMP_IO_WRITE32(pAd, AUTO_RSP_CFG, csr4.word); -} - -/* - ========================================================================== - Description: - Update basic rate bitmap - ========================================================================== - */ - -VOID UpdateBasicRateBitmap( - IN PRTMP_ADAPTER pAdapter) -{ - INT i, j; - /* 1 2 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54 */ - UCHAR rate[] = { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 }; - UCHAR *sup_p = pAdapter->CommonCfg.SupRate; - UCHAR *ext_p = pAdapter->CommonCfg.ExtRate; - ULONG bitmap = pAdapter->CommonCfg.BasicRateBitmap; - - - /* if A mode, always use fix BasicRateBitMap */ - //if (pAdapter->CommonCfg.Channel == PHY_11A) - if (pAdapter->CommonCfg.Channel > 14) - pAdapter->CommonCfg.BasicRateBitmap = 0x150; /* 6, 12, 24M */ - /* End of if */ - - if (pAdapter->CommonCfg.BasicRateBitmap > 4095) - { - /* (2 ^ MAX_LEN_OF_SUPPORTED_RATES) -1 */ - return; - } /* End of if */ - - for(i=0; iCommonCfg.DesireRate[i] & 0x7f) - { - case 2: Rate = RATE_1; num++; break; - case 4: Rate = RATE_2; num++; break; - case 11: Rate = RATE_5_5; num++; break; - case 22: Rate = RATE_11; num++; break; - case 12: Rate = RATE_6; num++; break; - case 18: Rate = RATE_9; num++; break; - case 24: Rate = RATE_12; num++; break; - case 36: Rate = RATE_18; num++; break; - case 48: Rate = RATE_24; num++; break; - case 72: Rate = RATE_36; num++; break; - case 96: Rate = RATE_48; num++; break; - case 108: Rate = RATE_54; num++; break; - //default: Rate = RATE_1; break; - } - if (MaxDesire < Rate) MaxDesire = Rate; - } - -//=========================================================================== -//=========================================================================== - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - pHtPhy = &pAd->StaCfg.HTPhyMode; - pMaxHtPhy = &pAd->StaCfg.MaxHTPhyMode; - pMinHtPhy = &pAd->StaCfg.MinHTPhyMode; - - auto_rate_cur_p = &pAd->StaCfg.bAutoTxRateSwitch; - HtMcs = pAd->StaCfg.DesiredTransmitSetting.field.MCS; - - if ((pAd->StaCfg.BssType == BSS_ADHOC) && - (pAd->CommonCfg.PhyMode == PHY_11B) && - (MaxDesire > RATE_11)) - { - MaxDesire = RATE_11; - } - } -#endif // CONFIG_STA_SUPPORT // - - pAd->CommonCfg.MaxDesiredRate = MaxDesire; - pMinHtPhy->word = 0; - pMaxHtPhy->word = 0; - pHtPhy->word = 0; - - // Auto rate switching is enabled only if more than one DESIRED RATES are - // specified; otherwise disabled - if (num <= 1) - { - //OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED); - //pAd->CommonCfg.bAutoTxRateSwitch = FALSE; - *auto_rate_cur_p = FALSE; - } - else - { - //OPSTATUS_SET_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED); - //pAd->CommonCfg.bAutoTxRateSwitch = TRUE; - *auto_rate_cur_p = TRUE; - } - -#if 1 - if (HtMcs != MCS_AUTO) - { - //OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED); - //pAd->CommonCfg.bAutoTxRateSwitch = FALSE; - *auto_rate_cur_p = FALSE; - } - else - { - //OPSTATUS_SET_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED); - //pAd->CommonCfg.bAutoTxRateSwitch = TRUE; - *auto_rate_cur_p = TRUE; - } -#endif - -#ifdef CONFIG_STA_SUPPORT - if ((ADHOC_ON(pAd) || INFRA_ON(pAd)) && (pAd->OpMode == OPMODE_STA)) - { - pSupRate = &pAd->StaActive.SupRate[0]; - pExtRate = &pAd->StaActive.ExtRate[0]; - SupRateLen = pAd->StaActive.SupRateLen; - ExtRateLen = pAd->StaActive.ExtRateLen; - } - else -#endif // CONFIG_STA_SUPPORT // - { - pSupRate = &pAd->CommonCfg.SupRate[0]; - pExtRate = &pAd->CommonCfg.ExtRate[0]; - SupRateLen = pAd->CommonCfg.SupRateLen; - ExtRateLen = pAd->CommonCfg.ExtRateLen; - } - - // find max supported rate - for (i=0; i Rate) MinSupport = Rate; - } - - for (i=0; i Rate) MinSupport = Rate; - } - - RTMP_IO_WRITE32(pAd, LEGACY_BASIC_RATE, BasicRateBitmap); - - // calculate the exptected ACK rate for each TX rate. This info is used to caculate - // the DURATION field of outgoing uniicast DATA/MGMT frame - for (i=0; iCommonCfg.ExpectedACKRate[i] = CurrBasicRate; - } - - DBGPRINT(RT_DEBUG_TRACE,("MlmeUpdateTxRates[MaxSupport = %d] = MaxDesire %d Mbps\n", RateIdToMbps[MaxSupport], RateIdToMbps[MaxDesire])); - // max tx rate = min {max desire rate, max supported rate} - if (MaxSupport < MaxDesire) - pAd->CommonCfg.MaxTxRate = MaxSupport; - else - pAd->CommonCfg.MaxTxRate = MaxDesire; - - pAd->CommonCfg.MinTxRate = MinSupport; - // 2003-07-31 john - 2500 doesn't have good sensitivity at high OFDM rates. to increase the success - // ratio of initial DHCP packet exchange, TX rate starts from a lower rate depending - // on average RSSI - // 1. RSSI >= -70db, start at 54 Mbps (short distance) - // 2. -70 > RSSI >= -75, start at 24 Mbps (mid distance) - // 3. -75 > RSSI, start at 11 Mbps (long distance) - //if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED)/* && - // OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)*/) - if (*auto_rate_cur_p) - { - short dbm = 0; -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - dbm = pAd->StaCfg.RssiSample.AvgRssi0 - pAd->BbpRssiToDbmDelta; -#endif // CONFIG_STA_SUPPORT // - if (bLinkUp == TRUE) - pAd->CommonCfg.TxRate = RATE_24; - else - pAd->CommonCfg.TxRate = pAd->CommonCfg.MaxTxRate; - - if (dbm < -75) - pAd->CommonCfg.TxRate = RATE_11; - else if (dbm < -70) - pAd->CommonCfg.TxRate = RATE_24; - - // should never exceed MaxTxRate (consider 11B-only mode) - if (pAd->CommonCfg.TxRate > pAd->CommonCfg.MaxTxRate) - pAd->CommonCfg.TxRate = pAd->CommonCfg.MaxTxRate; - - pAd->CommonCfg.TxRateIndex = 0; - } - else - { - pAd->CommonCfg.TxRate = pAd->CommonCfg.MaxTxRate; - pHtPhy->field.MCS = (pAd->CommonCfg.MaxTxRate > 3) ? (pAd->CommonCfg.MaxTxRate - 4) : pAd->CommonCfg.MaxTxRate; - pHtPhy->field.MODE = (pAd->CommonCfg.MaxTxRate > 3) ? MODE_OFDM : MODE_CCK; - - pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.STBC = pHtPhy->field.STBC; - pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.ShortGI = pHtPhy->field.ShortGI; - pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MCS = pHtPhy->field.MCS; - pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MODE = pHtPhy->field.MODE; - } - - if (pAd->CommonCfg.TxRate <= RATE_11) - { - pMaxHtPhy->field.MODE = MODE_CCK; - pMaxHtPhy->field.MCS = pAd->CommonCfg.TxRate; - pMinHtPhy->field.MCS = pAd->CommonCfg.MinTxRate; - } - else - { - pMaxHtPhy->field.MODE = MODE_OFDM; - pMaxHtPhy->field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.TxRate]; - if (pAd->CommonCfg.MinTxRate >= RATE_6 && (pAd->CommonCfg.MinTxRate <= RATE_54)) - {pMinHtPhy->field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MinTxRate];} - else - {pMinHtPhy->field.MCS = pAd->CommonCfg.MinTxRate;} - } - - pHtPhy->word = (pMaxHtPhy->word); - if (bLinkUp && (pAd->OpMode == OPMODE_STA)) - { - pAd->MacTab.Content[BSSID_WCID].HTPhyMode.word = pHtPhy->word; - pAd->MacTab.Content[BSSID_WCID].MaxHTPhyMode.word = pMaxHtPhy->word; - pAd->MacTab.Content[BSSID_WCID].MinHTPhyMode.word = pMinHtPhy->word; - } - else - { - switch (pAd->CommonCfg.PhyMode) - { - case PHY_11BG_MIXED: - case PHY_11B: -#ifdef DOT11_N_SUPPORT - case PHY_11BGN_MIXED: -#endif // DOT11_N_SUPPORT // - pAd->CommonCfg.MlmeRate = RATE_1; - pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_CCK; - pAd->CommonCfg.MlmeTransmit.field.MCS = RATE_1; - -//#ifdef WIFI_TEST - pAd->CommonCfg.RtsRate = RATE_11; -//#else -// pAd->CommonCfg.RtsRate = RATE_1; -//#endif - break; - case PHY_11G: - case PHY_11A: -#ifdef DOT11_N_SUPPORT - case PHY_11AGN_MIXED: - case PHY_11GN_MIXED: - case PHY_11N_2_4G: - case PHY_11AN_MIXED: - case PHY_11N_5G: -#endif // DOT11_N_SUPPORT // - pAd->CommonCfg.MlmeRate = RATE_6; - pAd->CommonCfg.RtsRate = RATE_6; - pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM; - pAd->CommonCfg.MlmeTransmit.field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate]; - break; - case PHY_11ABG_MIXED: -#ifdef DOT11_N_SUPPORT - case PHY_11ABGN_MIXED: -#endif // DOT11_N_SUPPORT // - if (pAd->CommonCfg.Channel <= 14) - { - pAd->CommonCfg.MlmeRate = RATE_1; - pAd->CommonCfg.RtsRate = RATE_1; - pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_CCK; - pAd->CommonCfg.MlmeTransmit.field.MCS = RATE_1; - } - else - { - pAd->CommonCfg.MlmeRate = RATE_6; - pAd->CommonCfg.RtsRate = RATE_6; - pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM; - pAd->CommonCfg.MlmeTransmit.field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate]; - } - break; - default: // error - pAd->CommonCfg.MlmeRate = RATE_6; - pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM; - pAd->CommonCfg.MlmeTransmit.field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate]; - pAd->CommonCfg.RtsRate = RATE_1; - break; - } - // - // Keep Basic Mlme Rate. - // - pAd->MacTab.Content[MCAST_WCID].HTPhyMode.word = pAd->CommonCfg.MlmeTransmit.word; - if (pAd->CommonCfg.MlmeTransmit.field.MODE == MODE_OFDM) - pAd->MacTab.Content[MCAST_WCID].HTPhyMode.field.MCS = OfdmRateToRxwiMCS[RATE_24]; - else - pAd->MacTab.Content[MCAST_WCID].HTPhyMode.field.MCS = RATE_1; - pAd->CommonCfg.BasicMlmeRate = pAd->CommonCfg.MlmeRate; - } - - DBGPRINT(RT_DEBUG_TRACE, (" MlmeUpdateTxRates (MaxDesire=%d, MaxSupport=%d, MaxTxRate=%d, MinRate=%d, Rate Switching =%d)\n", - RateIdToMbps[MaxDesire], RateIdToMbps[MaxSupport], RateIdToMbps[pAd->CommonCfg.MaxTxRate], RateIdToMbps[pAd->CommonCfg.MinTxRate], - /*OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED)*/*auto_rate_cur_p)); - DBGPRINT(RT_DEBUG_TRACE, (" MlmeUpdateTxRates (TxRate=%d, RtsRate=%d, BasicRateBitmap=0x%04lx)\n", - RateIdToMbps[pAd->CommonCfg.TxRate], RateIdToMbps[pAd->CommonCfg.RtsRate], BasicRateBitmap)); - DBGPRINT(RT_DEBUG_TRACE, ("MlmeUpdateTxRates (MlmeTransmit=0x%x, MinHTPhyMode=%x, MaxHTPhyMode=0x%x, HTPhyMode=0x%x)\n", - pAd->CommonCfg.MlmeTransmit.word, pAd->MacTab.Content[BSSID_WCID].MinHTPhyMode.word ,pAd->MacTab.Content[BSSID_WCID].MaxHTPhyMode.word ,pAd->MacTab.Content[BSSID_WCID].HTPhyMode.word )); -} - -#ifdef DOT11_N_SUPPORT -/* - ========================================================================== - Description: - This function update HT Rate setting. - Input Wcid value is valid for 2 case : - 1. it's used for Station in infra mode that copy AP rate to Mactable. - 2. OR Station in adhoc mode to copy peer's HT rate to Mactable. - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID MlmeUpdateHtTxRates( - IN PRTMP_ADAPTER pAd, - IN UCHAR apidx) -{ - UCHAR StbcMcs; //j, StbcMcs, bitmask; - CHAR i; // 3*3 - RT_HT_CAPABILITY *pRtHtCap = NULL; - RT_HT_PHY_INFO *pActiveHtPhy = NULL; - ULONG BasicMCS; - UCHAR j, bitmask; - PRT_HT_PHY_INFO pDesireHtPhy = NULL; - PHTTRANSMIT_SETTING pHtPhy = NULL; - PHTTRANSMIT_SETTING pMaxHtPhy = NULL; - PHTTRANSMIT_SETTING pMinHtPhy = NULL; - BOOLEAN *auto_rate_cur_p; - - DBGPRINT(RT_DEBUG_TRACE,("MlmeUpdateHtTxRates===> \n")); - - auto_rate_cur_p = NULL; - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - pDesireHtPhy = &pAd->StaCfg.DesiredHtPhyInfo; - pActiveHtPhy = &pAd->StaCfg.DesiredHtPhyInfo; - pHtPhy = &pAd->StaCfg.HTPhyMode; - pMaxHtPhy = &pAd->StaCfg.MaxHTPhyMode; - pMinHtPhy = &pAd->StaCfg.MinHTPhyMode; - - auto_rate_cur_p = &pAd->StaCfg.bAutoTxRateSwitch; - } -#endif // CONFIG_STA_SUPPORT // - -#ifdef CONFIG_STA_SUPPORT - if ((ADHOC_ON(pAd) || INFRA_ON(pAd)) && (pAd->OpMode == OPMODE_STA)) - { - if (pAd->StaActive.SupportedPhyInfo.bHtEnable == FALSE) - return; - - pRtHtCap = &pAd->StaActive.SupportedHtPhy; - pActiveHtPhy = &pAd->StaActive.SupportedPhyInfo; - StbcMcs = (UCHAR)pAd->MlmeAux.AddHtInfo.AddHtInfo3.StbcMcs; - BasicMCS =pAd->MlmeAux.AddHtInfo.MCSSet[0]+(pAd->MlmeAux.AddHtInfo.MCSSet[1]<<8)+(StbcMcs<<16); - if ((pAd->CommonCfg.DesiredHtPhy.TxSTBC) && (pRtHtCap->RxSTBC) && (pAd->Antenna.field.TxPath == 2)) - pMaxHtPhy->field.STBC = STBC_USE; - else - pMaxHtPhy->field.STBC = STBC_NONE; - } - else -#endif // CONFIG_STA_SUPPORT // - { - if (pDesireHtPhy->bHtEnable == FALSE) - return; - - pRtHtCap = &pAd->CommonCfg.DesiredHtPhy; - StbcMcs = (UCHAR)pAd->CommonCfg.AddHTInfo.AddHtInfo3.StbcMcs; - BasicMCS = pAd->CommonCfg.AddHTInfo.MCSSet[0]+(pAd->CommonCfg.AddHTInfo.MCSSet[1]<<8)+(StbcMcs<<16); - if ((pAd->CommonCfg.DesiredHtPhy.TxSTBC) && (pRtHtCap->RxSTBC) && (pAd->Antenna.field.TxPath == 2)) - pMaxHtPhy->field.STBC = STBC_USE; - else - pMaxHtPhy->field.STBC = STBC_NONE; - } - - // Decide MAX ht rate. - if ((pRtHtCap->GF) && (pAd->CommonCfg.DesiredHtPhy.GF)) - pMaxHtPhy->field.MODE = MODE_HTGREENFIELD; - else - pMaxHtPhy->field.MODE = MODE_HTMIX; - - if ((pAd->CommonCfg.DesiredHtPhy.ChannelWidth) && (pRtHtCap->ChannelWidth)) - pMaxHtPhy->field.BW = BW_40; - else - pMaxHtPhy->field.BW = BW_20; - - if (pMaxHtPhy->field.BW == BW_20) - pMaxHtPhy->field.ShortGI = (pAd->CommonCfg.DesiredHtPhy.ShortGIfor20 & pRtHtCap->ShortGIfor20); - else - pMaxHtPhy->field.ShortGI = (pAd->CommonCfg.DesiredHtPhy.ShortGIfor40 & pRtHtCap->ShortGIfor40); - - for (i=23; i>=0; i--) // 3*3 - { - j = i/8; - bitmask = (1<<(i-(j*8))); - - if ((pActiveHtPhy->MCSSet[j] & bitmask) && (pDesireHtPhy->MCSSet[j] & bitmask)) - { - pMaxHtPhy->field.MCS = i; - break; - } - - if (i==0) - break; - } - - // Copy MIN ht rate. rt2860??? - pMinHtPhy->field.BW = BW_20; - pMinHtPhy->field.MCS = 0; - pMinHtPhy->field.STBC = 0; - pMinHtPhy->field.ShortGI = 0; - //If STA assigns fixed rate. update to fixed here. -#ifdef CONFIG_STA_SUPPORT - if ( (pAd->OpMode == OPMODE_STA) && (pDesireHtPhy->MCSSet[0] != 0xff)) - { - if (pDesireHtPhy->MCSSet[4] != 0) - { - pMaxHtPhy->field.MCS = 32; - pMinHtPhy->field.MCS = 32; - DBGPRINT(RT_DEBUG_TRACE,("MlmeUpdateHtTxRates<=== Use Fixed MCS = %d\n",pMinHtPhy->field.MCS)); - } - - for (i=23; (CHAR)i >= 0; i--) // 3*3 - { - j = i/8; - bitmask = (1<<(i-(j*8))); - if ( (pDesireHtPhy->MCSSet[j] & bitmask) && (pActiveHtPhy->MCSSet[j] & bitmask)) - { - pMaxHtPhy->field.MCS = i; - pMinHtPhy->field.MCS = i; - break; - } - if (i==0) - break; - } - } -#endif // CONFIG_STA_SUPPORT // - - - // Decide ht rate - pHtPhy->field.STBC = pMaxHtPhy->field.STBC; - pHtPhy->field.BW = pMaxHtPhy->field.BW; - pHtPhy->field.MODE = pMaxHtPhy->field.MODE; - pHtPhy->field.MCS = pMaxHtPhy->field.MCS; - pHtPhy->field.ShortGI = pMaxHtPhy->field.ShortGI; - - // use default now. rt2860 - if (pDesireHtPhy->MCSSet[0] != 0xff) - *auto_rate_cur_p = FALSE; - else - *auto_rate_cur_p = TRUE; - - DBGPRINT(RT_DEBUG_TRACE, (" MlmeUpdateHtTxRates<---.AMsduSize = %d \n", pAd->CommonCfg.DesiredHtPhy.AmsduSize )); - DBGPRINT(RT_DEBUG_TRACE,("TX: MCS[0] = %x (choose %d), BW = %d, ShortGI = %d, MODE = %d, \n", pActiveHtPhy->MCSSet[0],pHtPhy->field.MCS, - pHtPhy->field.BW, pHtPhy->field.ShortGI, pHtPhy->field.MODE)); - DBGPRINT(RT_DEBUG_TRACE,("MlmeUpdateHtTxRates<=== \n")); -} -#endif // DOT11_N_SUPPORT // - -// IRQL = DISPATCH_LEVEL -VOID MlmeRadioOff( - IN PRTMP_ADAPTER pAd) -{ - RT28XX_MLME_RADIO_OFF(pAd); -} - -// IRQL = DISPATCH_LEVEL -VOID MlmeRadioOn( - IN PRTMP_ADAPTER pAd) -{ - RT28XX_MLME_RADIO_ON(pAd); -} - -// =========================================================================================== -// bss_table.c -// =========================================================================================== - - -/*! \brief initialize BSS table - * \param p_tab pointer to the table - * \return none - * \pre - * \post - - IRQL = PASSIVE_LEVEL - IRQL = DISPATCH_LEVEL - - */ -VOID BssTableInit( - IN BSS_TABLE *Tab) -{ - int i; - - Tab->BssNr = 0; - Tab->BssOverlapNr = 0; - for (i = 0; i < MAX_LEN_OF_BSS_TABLE; i++) - { - NdisZeroMemory(&Tab->BssEntry[i], sizeof(BSS_ENTRY)); - Tab->BssEntry[i].Rssi = -127; // initial the rssi as a minimum value - } -} - -#ifdef DOT11_N_SUPPORT -VOID BATableInit( - IN PRTMP_ADAPTER pAd, - IN BA_TABLE *Tab) -{ - int i; - - Tab->numAsOriginator = 0; - Tab->numAsRecipient = 0; - NdisAllocateSpinLock(&pAd->BATabLock); - for (i = 0; i < MAX_LEN_OF_BA_REC_TABLE; i++) - { - Tab->BARecEntry[i].REC_BA_Status = Recipient_NONE; - NdisAllocateSpinLock(&(Tab->BARecEntry[i].RxReRingLock)); - } - for (i = 0; i < MAX_LEN_OF_BA_ORI_TABLE; i++) - { - Tab->BAOriEntry[i].ORI_BA_Status = Originator_NONE; - } -} -#endif // DOT11_N_SUPPORT // - -/*! \brief search the BSS table by SSID - * \param p_tab pointer to the bss table - * \param ssid SSID string - * \return index of the table, BSS_NOT_FOUND if not in the table - * \pre - * \post - * \note search by sequential search - - IRQL = DISPATCH_LEVEL - - */ -ULONG BssTableSearch( - IN BSS_TABLE *Tab, - IN PUCHAR pBssid, - IN UCHAR Channel) -{ - UCHAR i; - - for (i = 0; i < Tab->BssNr; i++) - { - // - // Some AP that support A/B/G mode that may used the same BSSID on 11A and 11B/G. - // We should distinguish this case. - // - if ((((Tab->BssEntry[i].Channel <= 14) && (Channel <= 14)) || - ((Tab->BssEntry[i].Channel > 14) && (Channel > 14))) && - MAC_ADDR_EQUAL(Tab->BssEntry[i].Bssid, pBssid)) - { - return i; - } - } - return (ULONG)BSS_NOT_FOUND; -} - -ULONG BssSsidTableSearch( - IN BSS_TABLE *Tab, - IN PUCHAR pBssid, - IN PUCHAR pSsid, - IN UCHAR SsidLen, - IN UCHAR Channel) -{ - UCHAR i; - - for (i = 0; i < Tab->BssNr; i++) - { - // - // Some AP that support A/B/G mode that may used the same BSSID on 11A and 11B/G. - // We should distinguish this case. - // - if ((((Tab->BssEntry[i].Channel <= 14) && (Channel <= 14)) || - ((Tab->BssEntry[i].Channel > 14) && (Channel > 14))) && - MAC_ADDR_EQUAL(Tab->BssEntry[i].Bssid, pBssid) && - SSID_EQUAL(pSsid, SsidLen, Tab->BssEntry[i].Ssid, Tab->BssEntry[i].SsidLen)) - { - return i; - } - } - return (ULONG)BSS_NOT_FOUND; -} - -ULONG BssTableSearchWithSSID( - IN BSS_TABLE *Tab, - IN PUCHAR Bssid, - IN PUCHAR pSsid, - IN UCHAR SsidLen, - IN UCHAR Channel) -{ - UCHAR i; - - for (i = 0; i < Tab->BssNr; i++) - { - if ((((Tab->BssEntry[i].Channel <= 14) && (Channel <= 14)) || - ((Tab->BssEntry[i].Channel > 14) && (Channel > 14))) && - MAC_ADDR_EQUAL(&(Tab->BssEntry[i].Bssid), Bssid) && - (SSID_EQUAL(pSsid, SsidLen, Tab->BssEntry[i].Ssid, Tab->BssEntry[i].SsidLen) || - (NdisEqualMemory(pSsid, ZeroSsid, SsidLen)) || - (NdisEqualMemory(Tab->BssEntry[i].Ssid, ZeroSsid, Tab->BssEntry[i].SsidLen)))) - { - return i; - } - } - return (ULONG)BSS_NOT_FOUND; -} - -// IRQL = DISPATCH_LEVEL -VOID BssTableDeleteEntry( - IN OUT BSS_TABLE *Tab, - IN PUCHAR pBssid, - IN UCHAR Channel) -{ - UCHAR i, j; - - for (i = 0; i < Tab->BssNr; i++) - { - if ((Tab->BssEntry[i].Channel == Channel) && - (MAC_ADDR_EQUAL(Tab->BssEntry[i].Bssid, pBssid))) - { - for (j = i; j < Tab->BssNr - 1; j++) - { - NdisMoveMemory(&(Tab->BssEntry[j]), &(Tab->BssEntry[j + 1]), sizeof(BSS_ENTRY)); - } - NdisZeroMemory(&(Tab->BssEntry[Tab->BssNr - 1]), sizeof(BSS_ENTRY)); - Tab->BssNr -= 1; - return; - } - } -} - -#ifdef DOT11_N_SUPPORT -/* - ======================================================================== - Routine Description: - Delete the Originator Entry in BAtable. Or decrease numAs Originator by 1 if needed. - - Arguments: - // IRQL = DISPATCH_LEVEL - ======================================================================== -*/ -VOID BATableDeleteORIEntry( - IN OUT PRTMP_ADAPTER pAd, - IN BA_ORI_ENTRY *pBAORIEntry) -{ - - if (pBAORIEntry->ORI_BA_Status != Originator_NONE) - { - NdisAcquireSpinLock(&pAd->BATabLock); - if (pBAORIEntry->ORI_BA_Status == Originator_Done) - { - pAd->BATable.numAsOriginator -= 1; - DBGPRINT(RT_DEBUG_TRACE, ("BATableDeleteORIEntry numAsOriginator= %ld\n", pAd->BATable.numAsRecipient)); - // Erase Bitmap flag. - } - pAd->MacTab.Content[pBAORIEntry->Wcid].TXBAbitmap &= (~(1<<(pBAORIEntry->TID) )); // If STA mode, erase flag here - pAd->MacTab.Content[pBAORIEntry->Wcid].BAOriWcidArray[pBAORIEntry->TID] = 0; // If STA mode, erase flag here - pBAORIEntry->ORI_BA_Status = Originator_NONE; - pBAORIEntry->Token = 1; - // Not clear Sequence here. - NdisReleaseSpinLock(&pAd->BATabLock); - } -} -#endif // DOT11_N_SUPPORT // - -/*! \brief - * \param - * \return - * \pre - * \post - - IRQL = DISPATCH_LEVEL - - */ -VOID BssEntrySet( - IN PRTMP_ADAPTER pAd, - OUT BSS_ENTRY *pBss, - IN PUCHAR pBssid, - IN CHAR Ssid[], - IN UCHAR SsidLen, - IN UCHAR BssType, - IN USHORT BeaconPeriod, - IN PCF_PARM pCfParm, - IN USHORT AtimWin, - IN USHORT CapabilityInfo, - IN UCHAR SupRate[], - IN UCHAR SupRateLen, - IN UCHAR ExtRate[], - IN UCHAR ExtRateLen, - IN HT_CAPABILITY_IE *pHtCapability, - IN ADD_HT_INFO_IE *pAddHtInfo, // AP might use this additional ht info IE - IN UCHAR HtCapabilityLen, - IN UCHAR AddHtInfoLen, - IN UCHAR NewExtChanOffset, - IN UCHAR Channel, - IN CHAR Rssi, - IN LARGE_INTEGER TimeStamp, - IN UCHAR CkipFlag, - IN PEDCA_PARM pEdcaParm, - IN PQOS_CAPABILITY_PARM pQosCapability, - IN PQBSS_LOAD_PARM pQbssLoad, - IN USHORT LengthVIE, - IN PNDIS_802_11_VARIABLE_IEs pVIE) -{ - COPY_MAC_ADDR(pBss->Bssid, pBssid); - // Default Hidden SSID to be TRUE, it will be turned to FALSE after coping SSID - pBss->Hidden = 1; - if (SsidLen > 0) - { - // For hidden SSID AP, it might send beacon with SSID len equal to 0 - // Or send beacon /probe response with SSID len matching real SSID length, - // but SSID is all zero. such as "00-00-00-00" with length 4. - // We have to prevent this case overwrite correct table - if (NdisEqualMemory(Ssid, ZeroSsid, SsidLen) == 0) - { - NdisZeroMemory(pBss->Ssid, MAX_LEN_OF_SSID); - NdisMoveMemory(pBss->Ssid, Ssid, SsidLen); - pBss->SsidLen = SsidLen; - pBss->Hidden = 0; - } - } - else - pBss->SsidLen = 0; - pBss->BssType = BssType; - pBss->BeaconPeriod = BeaconPeriod; - if (BssType == BSS_INFRA) - { - if (pCfParm->bValid) - { - pBss->CfpCount = pCfParm->CfpCount; - pBss->CfpPeriod = pCfParm->CfpPeriod; - pBss->CfpMaxDuration = pCfParm->CfpMaxDuration; - pBss->CfpDurRemaining = pCfParm->CfpDurRemaining; - } - } - else - { - pBss->AtimWin = AtimWin; - } - - pBss->CapabilityInfo = CapabilityInfo; - // The privacy bit indicate security is ON, it maight be WEP, TKIP or AES - // Combine with AuthMode, they will decide the connection methods. - pBss->Privacy = CAP_IS_PRIVACY_ON(pBss->CapabilityInfo); - ASSERT(SupRateLen <= MAX_LEN_OF_SUPPORTED_RATES); - if (SupRateLen <= MAX_LEN_OF_SUPPORTED_RATES) - NdisMoveMemory(pBss->SupRate, SupRate, SupRateLen); - else - NdisMoveMemory(pBss->SupRate, SupRate, MAX_LEN_OF_SUPPORTED_RATES); - pBss->SupRateLen = SupRateLen; - ASSERT(ExtRateLen <= MAX_LEN_OF_SUPPORTED_RATES); - NdisMoveMemory(pBss->ExtRate, ExtRate, ExtRateLen); - NdisMoveMemory(&pBss->HtCapability, pHtCapability, HtCapabilityLen); - NdisMoveMemory(&pBss->AddHtInfo, pAddHtInfo, AddHtInfoLen); - pBss->NewExtChanOffset = NewExtChanOffset; - pBss->ExtRateLen = ExtRateLen; - pBss->Channel = Channel; - pBss->CentralChannel = Channel; - pBss->Rssi = Rssi; - // Update CkipFlag. if not exists, the value is 0x0 - pBss->CkipFlag = CkipFlag; - - // New for microsoft Fixed IEs - NdisMoveMemory(pBss->FixIEs.Timestamp, &TimeStamp, 8); - pBss->FixIEs.BeaconInterval = BeaconPeriod; - pBss->FixIEs.Capabilities = CapabilityInfo; - - // New for microsoft Variable IEs - if (LengthVIE != 0) - { - pBss->VarIELen = LengthVIE; - NdisMoveMemory(pBss->VarIEs, pVIE, pBss->VarIELen); - } - else - { - pBss->VarIELen = 0; - } - - pBss->AddHtInfoLen = 0; - pBss->HtCapabilityLen = 0; -#ifdef DOT11_N_SUPPORT - if (HtCapabilityLen> 0) - { - pBss->HtCapabilityLen = HtCapabilityLen; - NdisMoveMemory(&pBss->HtCapability, pHtCapability, HtCapabilityLen); - if (AddHtInfoLen > 0) - { - pBss->AddHtInfoLen = AddHtInfoLen; - NdisMoveMemory(&pBss->AddHtInfo, pAddHtInfo, AddHtInfoLen); - - if ((pAddHtInfo->ControlChan > 2)&& (pAddHtInfo->AddHtInfo.ExtChanOffset == EXTCHA_BELOW) && (pHtCapability->HtCapInfo.ChannelWidth == BW_40)) - { - pBss->CentralChannel = pAddHtInfo->ControlChan - 2; - } - else if ((pAddHtInfo->AddHtInfo.ExtChanOffset == EXTCHA_ABOVE) && (pHtCapability->HtCapInfo.ChannelWidth == BW_40)) - { - pBss->CentralChannel = pAddHtInfo->ControlChan + 2; - } - } - } -#endif // DOT11_N_SUPPORT // - - BssCipherParse(pBss); - - // new for QOS - if (pEdcaParm) - NdisMoveMemory(&pBss->EdcaParm, pEdcaParm, sizeof(EDCA_PARM)); - else - pBss->EdcaParm.bValid = FALSE; - if (pQosCapability) - NdisMoveMemory(&pBss->QosCapability, pQosCapability, sizeof(QOS_CAPABILITY_PARM)); - else - pBss->QosCapability.bValid = FALSE; - if (pQbssLoad) - NdisMoveMemory(&pBss->QbssLoad, pQbssLoad, sizeof(QBSS_LOAD_PARM)); - else - pBss->QbssLoad.bValid = FALSE; - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - PEID_STRUCT pEid; - USHORT Length = 0; - - - NdisZeroMemory(&pBss->WpaIE.IE[0], MAX_CUSTOM_LEN); - NdisZeroMemory(&pBss->RsnIE.IE[0], MAX_CUSTOM_LEN); -#ifdef EXT_BUILD_CHANNEL_LIST - NdisZeroMemory(&pBss->CountryString[0], 3); - pBss->bHasCountryIE = FALSE; -#endif // EXT_BUILD_CHANNEL_LIST // - pEid = (PEID_STRUCT) pVIE; - while ((Length + 2 + (USHORT)pEid->Len) <= LengthVIE) - { - switch(pEid->Eid) - { - case IE_WPA: - if (NdisEqualMemory(pEid->Octet, WPA_OUI, 4)) - { - if ((pEid->Len + 2) > MAX_CUSTOM_LEN) - { - pBss->WpaIE.IELen = 0; - break; - } - pBss->WpaIE.IELen = pEid->Len + 2; - NdisMoveMemory(pBss->WpaIE.IE, pEid, pBss->WpaIE.IELen); - } - break; - case IE_RSN: - if (NdisEqualMemory(pEid->Octet + 2, RSN_OUI, 3)) - { - if ((pEid->Len + 2) > MAX_CUSTOM_LEN) - { - pBss->RsnIE.IELen = 0; - break; - } - pBss->RsnIE.IELen = pEid->Len + 2; - NdisMoveMemory(pBss->RsnIE.IE, pEid, pBss->RsnIE.IELen); - } - break; -#ifdef EXT_BUILD_CHANNEL_LIST - case IE_COUNTRY: - NdisMoveMemory(&pBss->CountryString[0], pEid->Octet, 3); - pBss->bHasCountryIE = TRUE; - break; -#endif // EXT_BUILD_CHANNEL_LIST // - } - Length = Length + 2 + (USHORT)pEid->Len; // Eid[1] + Len[1]+ content[Len] - pEid = (PEID_STRUCT)((UCHAR*)pEid + 2 + pEid->Len); - } - } -#endif // CONFIG_STA_SUPPORT // -} - -/*! - * \brief insert an entry into the bss table - * \param p_tab The BSS table - * \param Bssid BSSID - * \param ssid SSID - * \param ssid_len Length of SSID - * \param bss_type - * \param beacon_period - * \param timestamp - * \param p_cf - * \param atim_win - * \param cap - * \param rates - * \param rates_len - * \param channel_idx - * \return none - * \pre - * \post - * \note If SSID is identical, the old entry will be replaced by the new one - - IRQL = DISPATCH_LEVEL - - */ -ULONG BssTableSetEntry( - IN PRTMP_ADAPTER pAd, - OUT BSS_TABLE *Tab, - IN PUCHAR pBssid, - IN CHAR Ssid[], - IN UCHAR SsidLen, - IN UCHAR BssType, - IN USHORT BeaconPeriod, - IN CF_PARM *CfParm, - IN USHORT AtimWin, - IN USHORT CapabilityInfo, - IN UCHAR SupRate[], - IN UCHAR SupRateLen, - IN UCHAR ExtRate[], - IN UCHAR ExtRateLen, - IN HT_CAPABILITY_IE *pHtCapability, - IN ADD_HT_INFO_IE *pAddHtInfo, // AP might use this additional ht info IE - IN UCHAR HtCapabilityLen, - IN UCHAR AddHtInfoLen, - IN UCHAR NewExtChanOffset, - IN UCHAR ChannelNo, - IN CHAR Rssi, - IN LARGE_INTEGER TimeStamp, - IN UCHAR CkipFlag, - IN PEDCA_PARM pEdcaParm, - IN PQOS_CAPABILITY_PARM pQosCapability, - IN PQBSS_LOAD_PARM pQbssLoad, - IN USHORT LengthVIE, - IN PNDIS_802_11_VARIABLE_IEs pVIE) -{ - ULONG Idx; - - Idx = BssTableSearchWithSSID(Tab, pBssid, Ssid, SsidLen, ChannelNo); - if (Idx == BSS_NOT_FOUND) - { - if (Tab->BssNr >= MAX_LEN_OF_BSS_TABLE) - { - // - // It may happen when BSS Table was full. - // The desired AP will not be added into BSS Table - // In this case, if we found the desired AP then overwrite BSS Table. - // - if(!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) - { - if (MAC_ADDR_EQUAL(pAd->MlmeAux.Bssid, pBssid) || - SSID_EQUAL(pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen, Ssid, SsidLen)) - { - Idx = Tab->BssOverlapNr; - BssEntrySet(pAd, &Tab->BssEntry[Idx], pBssid, Ssid, SsidLen, BssType, BeaconPeriod, CfParm, AtimWin, - CapabilityInfo, SupRate, SupRateLen, ExtRate, ExtRateLen,pHtCapability, pAddHtInfo,HtCapabilityLen, AddHtInfoLen, - NewExtChanOffset, ChannelNo, Rssi, TimeStamp, CkipFlag, pEdcaParm, pQosCapability, pQbssLoad, LengthVIE, pVIE); - Tab->BssOverlapNr = (Tab->BssOverlapNr++) % MAX_LEN_OF_BSS_TABLE; - } - return Idx; - } - else - { - return BSS_NOT_FOUND; - } - } - Idx = Tab->BssNr; - BssEntrySet(pAd, &Tab->BssEntry[Idx], pBssid, Ssid, SsidLen, BssType, BeaconPeriod, CfParm, AtimWin, - CapabilityInfo, SupRate, SupRateLen, ExtRate, ExtRateLen,pHtCapability, pAddHtInfo,HtCapabilityLen, AddHtInfoLen, - NewExtChanOffset, ChannelNo, Rssi, TimeStamp, CkipFlag, pEdcaParm, pQosCapability, pQbssLoad, LengthVIE, pVIE); - Tab->BssNr++; - } - else - { - /* avoid Hidden SSID form beacon to overwirite correct SSID from probe response */ - if ((SSID_EQUAL(Ssid, SsidLen, Tab->BssEntry[Idx].Ssid, Tab->BssEntry[Idx].SsidLen)) || - (NdisEqualMemory(Tab->BssEntry[Idx].Ssid, ZeroSsid, Tab->BssEntry[Idx].SsidLen))) - { - BssEntrySet(pAd, &Tab->BssEntry[Idx], pBssid, Ssid, SsidLen, BssType, BeaconPeriod,CfParm, AtimWin, - CapabilityInfo, SupRate, SupRateLen, ExtRate, ExtRateLen,pHtCapability, pAddHtInfo,HtCapabilityLen, AddHtInfoLen, - NewExtChanOffset, ChannelNo, Rssi, TimeStamp, CkipFlag, pEdcaParm, pQosCapability, pQbssLoad, LengthVIE, pVIE); - } - } - - return Idx; -} - -#ifdef CONFIG_STA_SUPPORT -#ifdef DOT11_N_SUPPORT -#ifdef DOT11N_DRAFT3 -VOID TriEventInit( - IN PRTMP_ADAPTER pAd) -{ - UCHAR i; - - for (i = 0;i < MAX_TRIGGER_EVENT;i++) - pAd->CommonCfg.TriggerEventTab.EventA[i].bValid = FALSE; - - pAd->CommonCfg.TriggerEventTab.EventANo = 0; - pAd->CommonCfg.TriggerEventTab.EventBCountDown = 0; -} - -ULONG TriEventTableSetEntry( - IN PRTMP_ADAPTER pAd, - OUT TRIGGER_EVENT_TAB *Tab, - IN PUCHAR pBssid, - IN HT_CAPABILITY_IE *pHtCapability, - IN UCHAR HtCapabilityLen, - IN UCHAR RegClass, - IN UCHAR ChannelNo) -{ - // Event A - if (HtCapabilityLen == 0) - { - if (Tab->EventANo < MAX_TRIGGER_EVENT) - { - RTMPMoveMemory(Tab->EventA[Tab->EventANo].BSSID, pBssid, 6); - Tab->EventA[Tab->EventANo].bValid = TRUE; - Tab->EventA[Tab->EventANo].Channel = ChannelNo; - Tab->EventA[Tab->EventANo].CDCounter = pAd->CommonCfg.Dot11BssWidthChanTranDelay; - if (RegClass != 0) - { - // Beacon has Regulatory class IE. So use beacon's - Tab->EventA[Tab->EventANo].RegClass = RegClass; - } - else - { - // Use Station's Regulatory class instead. - if (pAd->StaActive.SupportedHtPhy.bHtEnable == TRUE) - { - if (pAd->CommonCfg.CentralChannel > pAd->CommonCfg.Channel) - { - Tab->EventA[Tab->EventANo].RegClass = 32; - } - else if (pAd->CommonCfg.CentralChannel < pAd->CommonCfg.Channel) - Tab->EventA[Tab->EventANo].RegClass = 33; - } - else - Tab->EventA[Tab->EventANo].RegClass = ??; - - } - - Tab->EventANo ++; - } - } - else if (pHtCapability->HtCapInfo.Intolerant40) - { - Tab->EventBCountDown = pAd->CommonCfg.Dot11BssWidthChanTranDelay; - } - -} - -/* - ======================================================================== - Routine Description: - Trigger Event table Maintainence called once every second. - - Arguments: - // IRQL = DISPATCH_LEVEL - ======================================================================== -*/ -VOID TriEventCounterMaintenance( - IN PRTMP_ADAPTER pAd) -{ - UCHAR i; - BOOLEAN bNotify = FALSE; - for (i = 0;i < MAX_TRIGGER_EVENT;i++) - { - if (pAd->CommonCfg.TriggerEventTab.EventA[i].bValid && (pAd->CommonCfg.TriggerEventTab.EventA[i].CDCounter > 0)) - { - pAd->CommonCfg.TriggerEventTab.EventA[i].CDCounter--; - if (pAd->CommonCfg.TriggerEventTab.EventA[i].CDCounter == 0) - { - pAd->CommonCfg.TriggerEventTab.EventA[i].bValid = FALSE; - pAd->CommonCfg.TriggerEventTab.EventANo --; - // Need to send 20/40 Coexistence Notify frame if has status change. - bNotify = TRUE; - } - } - } - if (pAd->CommonCfg.TriggerEventTab.EventBCountDown > 0) - { - pAd->CommonCfg.TriggerEventTab.EventBCountDown--; - if (pAd->CommonCfg.TriggerEventTab.EventBCountDown == 0) - bNotify = TRUE; - } - - if (bNotify == TRUE) - Update2040CoexistFrameAndNotify(pAd, BSSID_WCID, TRUE); -} -#endif // DOT11N_DRAFT3 // -#endif // DOT11_N_SUPPORT // - -// IRQL = DISPATCH_LEVEL -VOID BssTableSsidSort( - IN PRTMP_ADAPTER pAd, - OUT BSS_TABLE *OutTab, - IN CHAR Ssid[], - IN UCHAR SsidLen) -{ - INT i; - BssTableInit(OutTab); - - for (i = 0; i < pAd->ScanTab.BssNr; i++) - { - BSS_ENTRY *pInBss = &pAd->ScanTab.BssEntry[i]; - BOOLEAN bIsHiddenApIncluded = FALSE; - - if (((pAd->CommonCfg.bIEEE80211H == 1) && - (pAd->MlmeAux.Channel > 14) && - RadarChannelCheck(pAd, pInBss->Channel)) -#ifdef CARRIER_DETECTION_SUPPORT // Roger sync Carrier - || (pAd->CommonCfg.CarrierDetect.Enable == TRUE) -#endif // CARRIER_DETECTION_SUPPORT // - ) - { - if (pInBss->Hidden) - bIsHiddenApIncluded = TRUE; - } - - if ((pInBss->BssType == pAd->StaCfg.BssType) && - (SSID_EQUAL(Ssid, SsidLen, pInBss->Ssid, pInBss->SsidLen) || bIsHiddenApIncluded)) - { - BSS_ENTRY *pOutBss = &OutTab->BssEntry[OutTab->BssNr]; - - -#ifdef EXT_BUILD_CHANNEL_LIST - // If no Country IE exists no Connection will be established when IEEE80211dClientMode is strict. - if ((pAd->StaCfg.IEEE80211dClientMode == Rt802_11_D_Strict) && - (pInBss->bHasCountryIE == FALSE)) - { - DBGPRINT(RT_DEBUG_TRACE,("StaCfg.IEEE80211dClientMode == Rt802_11_D_Strict, but this AP doesn't have country IE.\n")); - continue; - } -#endif // EXT_BUILD_CHANNEL_LIST // - -#ifdef DOT11_N_SUPPORT - // 2.4G/5G N only mode - if ((pInBss->HtCapabilityLen == 0) && - ((pAd->CommonCfg.PhyMode == PHY_11N_2_4G) || (pAd->CommonCfg.PhyMode == PHY_11N_5G))) - { - DBGPRINT(RT_DEBUG_TRACE,("STA is in N-only Mode, this AP don't have Ht capability in Beacon.\n")); - continue; - } -#endif // DOT11_N_SUPPORT // - - // New for WPA2 - // Check the Authmode first - if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - { - // Check AuthMode and AuthModeAux for matching, in case AP support dual-mode - if ((pAd->StaCfg.AuthMode != pInBss->AuthMode) && (pAd->StaCfg.AuthMode != pInBss->AuthModeAux)) - // None matched - continue; - - // Check cipher suite, AP must have more secured cipher than station setting - if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) - { - // If it's not mixed mode, we should only let BSS pass with the same encryption - if (pInBss->WPA.bMixMode == FALSE) - if (pAd->StaCfg.WepStatus != pInBss->WPA.GroupCipher) - continue; - - // check group cipher - if (pAd->StaCfg.WepStatus < pInBss->WPA.GroupCipher) - continue; - - // check pairwise cipher, skip if none matched - // If profile set to AES, let it pass without question. - // If profile set to TKIP, we must find one mateched - if ((pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) && - (pAd->StaCfg.WepStatus != pInBss->WPA.PairCipher) && - (pAd->StaCfg.WepStatus != pInBss->WPA.PairCipherAux)) - continue; - } - else if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)) - { - // If it's not mixed mode, we should only let BSS pass with the same encryption - if (pInBss->WPA2.bMixMode == FALSE) - if (pAd->StaCfg.WepStatus != pInBss->WPA2.GroupCipher) - continue; - - // check group cipher - if (pAd->StaCfg.WepStatus < pInBss->WPA2.GroupCipher) - continue; - - // check pairwise cipher, skip if none matched - // If profile set to AES, let it pass without question. - // If profile set to TKIP, we must find one mateched - if ((pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) && - (pAd->StaCfg.WepStatus != pInBss->WPA2.PairCipher) && - (pAd->StaCfg.WepStatus != pInBss->WPA2.PairCipherAux)) - continue; - } - } - // Bss Type matched, SSID matched. - // We will check wepstatus for qualification Bss - else if (pAd->StaCfg.WepStatus != pInBss->WepStatus) - { - DBGPRINT(RT_DEBUG_TRACE,("StaCfg.WepStatus=%d, while pInBss->WepStatus=%d\n", pAd->StaCfg.WepStatus, pInBss->WepStatus)); - // - // For the SESv2 case, we will not qualify WepStatus. - // - if (!pInBss->bSES) - continue; - } - - // Since the AP is using hidden SSID, and we are trying to connect to ANY - // It definitely will fail. So, skip it. - // CCX also require not even try to connect it!! - if (SsidLen == 0) - continue; - -#ifdef DOT11_N_SUPPORT - // If both station and AP use 40MHz, still need to check if the 40MHZ band's legality in my country region - // If this 40MHz wideband is not allowed in my country list, use bandwidth 20MHZ instead, - if ((pInBss->CentralChannel != pInBss->Channel) && - (pAd->CommonCfg.RegTransmitSetting.field.BW == BW_40)) - { - if (RTMPCheckChannel(pAd, pInBss->CentralChannel, pInBss->Channel) == FALSE) - { - pAd->CommonCfg.RegTransmitSetting.field.BW = BW_20; - SetCommonHT(pAd); - pAd->CommonCfg.RegTransmitSetting.field.BW = BW_40; - } - else - { - if (pAd->CommonCfg.DesiredHtPhy.ChannelWidth == BAND_WIDTH_20) - { - SetCommonHT(pAd); - } - } - } -#endif // DOT11_N_SUPPORT // - - // copy matching BSS from InTab to OutTab - NdisMoveMemory(pOutBss, pInBss, sizeof(BSS_ENTRY)); - - OutTab->BssNr++; - } - else if ((pInBss->BssType == pAd->StaCfg.BssType) && (SsidLen == 0)) - { - BSS_ENTRY *pOutBss = &OutTab->BssEntry[OutTab->BssNr]; - - -#ifdef DOT11_N_SUPPORT - // 2.4G/5G N only mode - if ((pInBss->HtCapabilityLen == 0) && - ((pAd->CommonCfg.PhyMode == PHY_11N_2_4G) || (pAd->CommonCfg.PhyMode == PHY_11N_5G))) - { - DBGPRINT(RT_DEBUG_TRACE,("STA is in N-only Mode, this AP don't have Ht capability in Beacon.\n")); - continue; - } -#endif // DOT11_N_SUPPORT // - - // New for WPA2 - // Check the Authmode first - if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - { - // Check AuthMode and AuthModeAux for matching, in case AP support dual-mode - if ((pAd->StaCfg.AuthMode != pInBss->AuthMode) && (pAd->StaCfg.AuthMode != pInBss->AuthModeAux)) - // None matched - continue; - - // Check cipher suite, AP must have more secured cipher than station setting - if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) - { - // If it's not mixed mode, we should only let BSS pass with the same encryption - if (pInBss->WPA.bMixMode == FALSE) - if (pAd->StaCfg.WepStatus != pInBss->WPA.GroupCipher) - continue; - - // check group cipher - if (pAd->StaCfg.WepStatus < pInBss->WPA.GroupCipher) - continue; - - // check pairwise cipher, skip if none matched - // If profile set to AES, let it pass without question. - // If profile set to TKIP, we must find one mateched - if ((pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) && - (pAd->StaCfg.WepStatus != pInBss->WPA.PairCipher) && - (pAd->StaCfg.WepStatus != pInBss->WPA.PairCipherAux)) - continue; - } - else if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)) - { - // If it's not mixed mode, we should only let BSS pass with the same encryption - if (pInBss->WPA2.bMixMode == FALSE) - if (pAd->StaCfg.WepStatus != pInBss->WPA2.GroupCipher) - continue; - - // check group cipher - if (pAd->StaCfg.WepStatus < pInBss->WPA2.GroupCipher) - continue; - - // check pairwise cipher, skip if none matched - // If profile set to AES, let it pass without question. - // If profile set to TKIP, we must find one mateched - if ((pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) && - (pAd->StaCfg.WepStatus != pInBss->WPA2.PairCipher) && - (pAd->StaCfg.WepStatus != pInBss->WPA2.PairCipherAux)) - continue; - } - } - // Bss Type matched, SSID matched. - // We will check wepstatus for qualification Bss - else if (pAd->StaCfg.WepStatus != pInBss->WepStatus) - continue; - -#ifdef DOT11_N_SUPPORT - // If both station and AP use 40MHz, still need to check if the 40MHZ band's legality in my country region - // If this 40MHz wideband is not allowed in my country list, use bandwidth 20MHZ instead, - if ((pInBss->CentralChannel != pInBss->Channel) && - (pAd->CommonCfg.RegTransmitSetting.field.BW == BW_40)) - { - if (RTMPCheckChannel(pAd, pInBss->CentralChannel, pInBss->Channel) == FALSE) - { - pAd->CommonCfg.RegTransmitSetting.field.BW = BW_20; - SetCommonHT(pAd); - pAd->CommonCfg.RegTransmitSetting.field.BW = BW_40; - } - } -#endif // DOT11_N_SUPPORT // - - // copy matching BSS from InTab to OutTab - NdisMoveMemory(pOutBss, pInBss, sizeof(BSS_ENTRY)); - - OutTab->BssNr++; - } - - if (OutTab->BssNr >= MAX_LEN_OF_BSS_TABLE) - break; - } - - BssTableSortByRssi(OutTab); -} - - -// IRQL = DISPATCH_LEVEL -VOID BssTableSortByRssi( - IN OUT BSS_TABLE *OutTab) -{ - INT i, j; - BSS_ENTRY TmpBss; - - for (i = 0; i < OutTab->BssNr - 1; i++) - { - for (j = i+1; j < OutTab->BssNr; j++) - { - if (OutTab->BssEntry[j].Rssi > OutTab->BssEntry[i].Rssi) - { - NdisMoveMemory(&TmpBss, &OutTab->BssEntry[j], sizeof(BSS_ENTRY)); - NdisMoveMemory(&OutTab->BssEntry[j], &OutTab->BssEntry[i], sizeof(BSS_ENTRY)); - NdisMoveMemory(&OutTab->BssEntry[i], &TmpBss, sizeof(BSS_ENTRY)); - } - } - } -} -#endif // CONFIG_STA_SUPPORT // - - -VOID BssCipherParse( - IN OUT PBSS_ENTRY pBss) -{ - PEID_STRUCT pEid; - PUCHAR pTmp; - PRSN_IE_HEADER_STRUCT pRsnHeader; - PCIPHER_SUITE_STRUCT pCipher; - PAKM_SUITE_STRUCT pAKM; - USHORT Count; - INT Length; - NDIS_802_11_ENCRYPTION_STATUS TmpCipher; - - // - // WepStatus will be reset later, if AP announce TKIP or AES on the beacon frame. - // - if (pBss->Privacy) - { - pBss->WepStatus = Ndis802_11WEPEnabled; - } - else - { - pBss->WepStatus = Ndis802_11WEPDisabled; - } - // Set default to disable & open authentication before parsing variable IE - pBss->AuthMode = Ndis802_11AuthModeOpen; - pBss->AuthModeAux = Ndis802_11AuthModeOpen; - - // Init WPA setting - pBss->WPA.PairCipher = Ndis802_11WEPDisabled; - pBss->WPA.PairCipherAux = Ndis802_11WEPDisabled; - pBss->WPA.GroupCipher = Ndis802_11WEPDisabled; - pBss->WPA.RsnCapability = 0; - pBss->WPA.bMixMode = FALSE; - - // Init WPA2 setting - pBss->WPA2.PairCipher = Ndis802_11WEPDisabled; - pBss->WPA2.PairCipherAux = Ndis802_11WEPDisabled; - pBss->WPA2.GroupCipher = Ndis802_11WEPDisabled; - pBss->WPA2.RsnCapability = 0; - pBss->WPA2.bMixMode = FALSE; - - - Length = (INT) pBss->VarIELen; - - while (Length > 0) - { - // Parse cipher suite base on WPA1 & WPA2, they should be parsed differently - pTmp = ((PUCHAR) pBss->VarIEs) + pBss->VarIELen - Length; - pEid = (PEID_STRUCT) pTmp; - switch (pEid->Eid) - { - case IE_WPA: - //Parse Cisco IE_WPA (LEAP, CCKM, etc.) - if ( NdisEqualMemory((pTmp+8), CISCO_OUI, 3)) - { - pTmp += 11; - switch (*pTmp) - { - case 1: - case 5: // Although WEP is not allowed in WPA related auth mode, we parse it anyway - pBss->WepStatus = Ndis802_11Encryption1Enabled; - pBss->WPA.PairCipher = Ndis802_11Encryption1Enabled; - pBss->WPA.GroupCipher = Ndis802_11Encryption1Enabled; - break; - case 2: - pBss->WepStatus = Ndis802_11Encryption2Enabled; - pBss->WPA.PairCipher = Ndis802_11Encryption1Enabled; - pBss->WPA.GroupCipher = Ndis802_11Encryption1Enabled; - break; - case 4: - pBss->WepStatus = Ndis802_11Encryption3Enabled; - pBss->WPA.PairCipher = Ndis802_11Encryption1Enabled; - pBss->WPA.GroupCipher = Ndis802_11Encryption1Enabled; - break; - default: - break; - } - - // if Cisco IE_WPA, break - break; - } - else if (NdisEqualMemory(pEid->Octet, SES_OUI, 3) && (pEid->Len == 7)) - { - pBss->bSES = TRUE; - break; - } - else if (NdisEqualMemory(pEid->Octet, WPA_OUI, 4) != 1) - { - // if unsupported vendor specific IE - break; - } - // Skip OUI, version, and multicast suite - // This part should be improved in the future when AP supported multiple cipher suite. - // For now, it's OK since almost all APs have fixed cipher suite supported. - // pTmp = (PUCHAR) pEid->Octet; - pTmp += 11; - - // Cipher Suite Selectors from Spec P802.11i/D3.2 P26. - // Value Meaning - // 0 None - // 1 WEP-40 - // 2 Tkip - // 3 WRAP - // 4 AES - // 5 WEP-104 - // Parse group cipher - switch (*pTmp) - { - case 1: - case 5: // Although WEP is not allowed in WPA related auth mode, we parse it anyway - pBss->WPA.GroupCipher = Ndis802_11Encryption1Enabled; - break; - case 2: - pBss->WPA.GroupCipher = Ndis802_11Encryption2Enabled; - break; - case 4: - pBss->WPA.GroupCipher = Ndis802_11Encryption3Enabled; - break; - default: - break; - } - // number of unicast suite - pTmp += 1; - - // skip all unicast cipher suites - //Count = *(PUSHORT) pTmp; - Count = (pTmp[1]<<8) + pTmp[0]; - pTmp += sizeof(USHORT); - - // Parsing all unicast cipher suite - while (Count > 0) - { - // Skip OUI - pTmp += 3; - TmpCipher = Ndis802_11WEPDisabled; - switch (*pTmp) - { - case 1: - case 5: // Although WEP is not allowed in WPA related auth mode, we parse it anyway - TmpCipher = Ndis802_11Encryption1Enabled; - break; - case 2: - TmpCipher = Ndis802_11Encryption2Enabled; - break; - case 4: - TmpCipher = Ndis802_11Encryption3Enabled; - break; - default: - break; - } - if (TmpCipher > pBss->WPA.PairCipher) - { - // Move the lower cipher suite to PairCipherAux - pBss->WPA.PairCipherAux = pBss->WPA.PairCipher; - pBss->WPA.PairCipher = TmpCipher; - } - else - { - pBss->WPA.PairCipherAux = TmpCipher; - } - pTmp++; - Count--; - } - - // 4. get AKM suite counts - //Count = *(PUSHORT) pTmp; - Count = (pTmp[1]<<8) + pTmp[0]; - pTmp += sizeof(USHORT); - pTmp += 3; - - switch (*pTmp) - { - case 1: - // Set AP support WPA mode - if (pBss->AuthMode == Ndis802_11AuthModeOpen) - pBss->AuthMode = Ndis802_11AuthModeWPA; - else - pBss->AuthModeAux = Ndis802_11AuthModeWPA; - break; - case 2: - // Set AP support WPA mode - if (pBss->AuthMode == Ndis802_11AuthModeOpen) - pBss->AuthMode = Ndis802_11AuthModeWPAPSK; - else - pBss->AuthModeAux = Ndis802_11AuthModeWPAPSK; - break; - default: - break; - } - pTmp += 1; - - // Fixed for WPA-None - if (pBss->BssType == BSS_ADHOC) - { - pBss->AuthMode = Ndis802_11AuthModeWPANone; - pBss->AuthModeAux = Ndis802_11AuthModeWPANone; - pBss->WepStatus = pBss->WPA.GroupCipher; - if (pBss->WPA.PairCipherAux == Ndis802_11WEPDisabled) - pBss->WPA.PairCipherAux = pBss->WPA.GroupCipher; - } - else - pBss->WepStatus = pBss->WPA.PairCipher; - - // Check the Pair & Group, if different, turn on mixed mode flag - if (pBss->WPA.GroupCipher != pBss->WPA.PairCipher) - pBss->WPA.bMixMode = TRUE; - - break; - - case IE_RSN: - pRsnHeader = (PRSN_IE_HEADER_STRUCT) pTmp; - - // 0. Version must be 1 - if (le2cpu16(pRsnHeader->Version) != 1) - break; - pTmp += sizeof(RSN_IE_HEADER_STRUCT); - - // 1. Check group cipher - pCipher = (PCIPHER_SUITE_STRUCT) pTmp; - if (!RTMPEqualMemory(pTmp, RSN_OUI, 3)) - break; - - // Parse group cipher - switch (pCipher->Type) - { - case 1: - case 5: // Although WEP is not allowed in WPA related auth mode, we parse it anyway - pBss->WPA2.GroupCipher = Ndis802_11Encryption1Enabled; - break; - case 2: - pBss->WPA2.GroupCipher = Ndis802_11Encryption2Enabled; - break; - case 4: - pBss->WPA2.GroupCipher = Ndis802_11Encryption3Enabled; - break; - default: - break; - } - // set to correct offset for next parsing - pTmp += sizeof(CIPHER_SUITE_STRUCT); - - // 2. Get pairwise cipher counts - //Count = *(PUSHORT) pTmp; - Count = (pTmp[1]<<8) + pTmp[0]; - pTmp += sizeof(USHORT); - - // 3. Get pairwise cipher - // Parsing all unicast cipher suite - while (Count > 0) - { - // Skip OUI - pCipher = (PCIPHER_SUITE_STRUCT) pTmp; - TmpCipher = Ndis802_11WEPDisabled; - switch (pCipher->Type) - { - case 1: - case 5: // Although WEP is not allowed in WPA related auth mode, we parse it anyway - TmpCipher = Ndis802_11Encryption1Enabled; - break; - case 2: - TmpCipher = Ndis802_11Encryption2Enabled; - break; - case 4: - TmpCipher = Ndis802_11Encryption3Enabled; - break; - default: - break; - } - if (TmpCipher > pBss->WPA2.PairCipher) - { - // Move the lower cipher suite to PairCipherAux - pBss->WPA2.PairCipherAux = pBss->WPA2.PairCipher; - pBss->WPA2.PairCipher = TmpCipher; - } - else - { - pBss->WPA2.PairCipherAux = TmpCipher; - } - pTmp += sizeof(CIPHER_SUITE_STRUCT); - Count--; - } - - // 4. get AKM suite counts - //Count = *(PUSHORT) pTmp; - Count = (pTmp[1]<<8) + pTmp[0]; - pTmp += sizeof(USHORT); - - // 5. Get AKM ciphers - pAKM = (PAKM_SUITE_STRUCT) pTmp; - if (!RTMPEqualMemory(pTmp, RSN_OUI, 3)) - break; - - switch (pAKM->Type) - { - case 1: - // Set AP support WPA mode - if (pBss->AuthMode == Ndis802_11AuthModeOpen) - pBss->AuthMode = Ndis802_11AuthModeWPA2; - else - pBss->AuthModeAux = Ndis802_11AuthModeWPA2; - break; - case 2: - // Set AP support WPA mode - if (pBss->AuthMode == Ndis802_11AuthModeOpen) - pBss->AuthMode = Ndis802_11AuthModeWPA2PSK; - else - pBss->AuthModeAux = Ndis802_11AuthModeWPA2PSK; - break; - default: - break; - } - pTmp += (Count * sizeof(AKM_SUITE_STRUCT)); - - // Fixed for WPA-None - if (pBss->BssType == BSS_ADHOC) - { - pBss->AuthMode = Ndis802_11AuthModeWPANone; - pBss->AuthModeAux = Ndis802_11AuthModeWPANone; - pBss->WPA.PairCipherAux = pBss->WPA2.PairCipherAux; - pBss->WPA.GroupCipher = pBss->WPA2.GroupCipher; - pBss->WepStatus = pBss->WPA.GroupCipher; - if (pBss->WPA.PairCipherAux == Ndis802_11WEPDisabled) - pBss->WPA.PairCipherAux = pBss->WPA.GroupCipher; - } - pBss->WepStatus = pBss->WPA2.PairCipher; - - // 6. Get RSN capability - //pBss->WPA2.RsnCapability = *(PUSHORT) pTmp; - pBss->WPA2.RsnCapability = (pTmp[1]<<8) + pTmp[0]; - pTmp += sizeof(USHORT); - - // Check the Pair & Group, if different, turn on mixed mode flag - if (pBss->WPA2.GroupCipher != pBss->WPA2.PairCipher) - pBss->WPA2.bMixMode = TRUE; - - break; - default: - break; - } - Length -= (pEid->Len + 2); - } -} - -// =========================================================================================== -// mac_table.c -// =========================================================================================== - -/*! \brief generates a random mac address value for IBSS BSSID - * \param Addr the bssid location - * \return none - * \pre - * \post - */ -VOID MacAddrRandomBssid( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pAddr) -{ - INT i; - - for (i = 0; i < MAC_ADDR_LEN; i++) - { - pAddr[i] = RandomByte(pAd); - } - - pAddr[0] = (pAddr[0] & 0xfe) | 0x02; // the first 2 bits must be 01xxxxxxxx -} - -/*! \brief init the management mac frame header - * \param p_hdr mac header - * \param subtype subtype of the frame - * \param p_ds destination address, don't care if it is a broadcast address - * \return none - * \pre the station has the following information in the pAd->StaCfg - * - bssid - * - station address - * \post - * \note this function initializes the following field - - IRQL = PASSIVE_LEVEL - IRQL = DISPATCH_LEVEL - - */ -VOID MgtMacHeaderInit( - IN PRTMP_ADAPTER pAd, - IN OUT PHEADER_802_11 pHdr80211, - IN UCHAR SubType, - IN UCHAR ToDs, - IN PUCHAR pDA, - IN PUCHAR pBssid) -{ - NdisZeroMemory(pHdr80211, sizeof(HEADER_802_11)); - - pHdr80211->FC.Type = BTYPE_MGMT; - pHdr80211->FC.SubType = SubType; -// if (SubType == SUBTYPE_ACK) // sample, no use, it will conflict with ACTION frame sub type -// pHdr80211->FC.Type = BTYPE_CNTL; - pHdr80211->FC.ToDs = ToDs; - COPY_MAC_ADDR(pHdr80211->Addr1, pDA); -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - COPY_MAC_ADDR(pHdr80211->Addr2, pAd->CurrentAddress); -#endif // CONFIG_STA_SUPPORT // - COPY_MAC_ADDR(pHdr80211->Addr3, pBssid); -} - -// =========================================================================================== -// mem_mgmt.c -// =========================================================================================== - -/*!*************************************************************************** - * This routine build an outgoing frame, and fill all information specified - * in argument list to the frame body. The actual frame size is the summation - * of all arguments. - * input params: - * Buffer - pointer to a pre-allocated memory segment - * args - a list of pairs. - * NOTE NOTE NOTE!!!! the last argument must be NULL, otherwise this - * function will FAIL!!! - * return: - * Size of the buffer - * usage: - * MakeOutgoingFrame(Buffer, output_length, 2, &fc, 2, &dur, 6, p_addr1, 6,p_addr2, END_OF_ARGS); - - IRQL = PASSIVE_LEVEL - IRQL = DISPATCH_LEVEL - - ****************************************************************************/ -ULONG MakeOutgoingFrame( - OUT CHAR *Buffer, - OUT ULONG *FrameLen, ...) -{ - CHAR *p; - int leng; - ULONG TotLeng; - va_list Args; - - // calculates the total length - TotLeng = 0; - va_start(Args, FrameLen); - do - { - leng = va_arg(Args, int); - if (leng == END_OF_ARGS) - { - break; - } - p = va_arg(Args, PVOID); - NdisMoveMemory(&Buffer[TotLeng], p, leng); - TotLeng = TotLeng + leng; - } while(TRUE); - - va_end(Args); /* clean up */ - *FrameLen = TotLeng; - return TotLeng; -} - -// =========================================================================================== -// mlme_queue.c -// =========================================================================================== - -/*! \brief Initialize The MLME Queue, used by MLME Functions - * \param *Queue The MLME Queue - * \return Always Return NDIS_STATE_SUCCESS in this implementation - * \pre - * \post - * \note Because this is done only once (at the init stage), no need to be locked - - IRQL = PASSIVE_LEVEL - - */ -NDIS_STATUS MlmeQueueInit( - IN MLME_QUEUE *Queue) -{ - INT i; - - NdisAllocateSpinLock(&Queue->Lock); - - Queue->Num = 0; - Queue->Head = 0; - Queue->Tail = 0; - - for (i = 0; i < MAX_LEN_OF_MLME_QUEUE; i++) - { - Queue->Entry[i].Occupied = FALSE; - Queue->Entry[i].MsgLen = 0; - NdisZeroMemory(Queue->Entry[i].Msg, MGMT_DMA_BUFFER_SIZE); - } - - return NDIS_STATUS_SUCCESS; -} - -/*! \brief Enqueue a message for other threads, if they want to send messages to MLME thread - * \param *Queue The MLME Queue - * \param Machine The State Machine Id - * \param MsgType The Message Type - * \param MsgLen The Message length - * \param *Msg The message pointer - * \return TRUE if enqueue is successful, FALSE if the queue is full - * \pre - * \post - * \note The message has to be initialized - - IRQL = PASSIVE_LEVEL - IRQL = DISPATCH_LEVEL - - */ -BOOLEAN MlmeEnqueue( - IN PRTMP_ADAPTER pAd, - IN ULONG Machine, - IN ULONG MsgType, - IN ULONG MsgLen, - IN VOID *Msg) -{ - INT Tail; - MLME_QUEUE *Queue = (MLME_QUEUE *)&pAd->Mlme.Queue; - - // Do nothing if the driver is starting halt state. - // This might happen when timer already been fired before cancel timer with mlmehalt - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) - return FALSE; - - // First check the size, it MUST not exceed the mlme queue size - if (MsgLen > MGMT_DMA_BUFFER_SIZE) - { - DBGPRINT_ERR(("MlmeEnqueue: msg too large, size = %ld \n", MsgLen)); - return FALSE; - } - - if (MlmeQueueFull(Queue)) - { - return FALSE; - } - - NdisAcquireSpinLock(&(Queue->Lock)); - Tail = Queue->Tail; - Queue->Tail++; - Queue->Num++; - if (Queue->Tail == MAX_LEN_OF_MLME_QUEUE) - { - Queue->Tail = 0; - } - - Queue->Entry[Tail].Wcid = RESERVED_WCID; - Queue->Entry[Tail].Occupied = TRUE; - Queue->Entry[Tail].Machine = Machine; - Queue->Entry[Tail].MsgType = MsgType; - Queue->Entry[Tail].MsgLen = MsgLen; - - if (Msg != NULL) - { - NdisMoveMemory(Queue->Entry[Tail].Msg, Msg, MsgLen); - } - - NdisReleaseSpinLock(&(Queue->Lock)); - return TRUE; -} - -/*! \brief This function is used when Recv gets a MLME message - * \param *Queue The MLME Queue - * \param TimeStampHigh The upper 32 bit of timestamp - * \param TimeStampLow The lower 32 bit of timestamp - * \param Rssi The receiving RSSI strength - * \param MsgLen The length of the message - * \param *Msg The message pointer - * \return TRUE if everything ok, FALSE otherwise (like Queue Full) - * \pre - * \post - - IRQL = DISPATCH_LEVEL - - */ -BOOLEAN MlmeEnqueueForRecv( - IN PRTMP_ADAPTER pAd, - IN ULONG Wcid, - IN ULONG TimeStampHigh, - IN ULONG TimeStampLow, - IN UCHAR Rssi0, - IN UCHAR Rssi1, - IN UCHAR Rssi2, - IN ULONG MsgLen, - IN VOID *Msg, - IN UCHAR Signal) -{ - INT Tail, Machine; - PFRAME_802_11 pFrame = (PFRAME_802_11)Msg; - INT MsgType; - MLME_QUEUE *Queue = (MLME_QUEUE *)&pAd->Mlme.Queue; - -#ifdef RALINK_ATE - /* Nothing to do in ATE mode */ - if(ATE_ON(pAd)) - return FALSE; -#endif // RALINK_ATE // - - // Do nothing if the driver is starting halt state. - // This might happen when timer already been fired before cancel timer with mlmehalt - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) - { - DBGPRINT_ERR(("MlmeEnqueueForRecv: fRTMP_ADAPTER_HALT_IN_PROGRESS\n")); - return FALSE; - } - - // First check the size, it MUST not exceed the mlme queue size - if (MsgLen > MGMT_DMA_BUFFER_SIZE) - { - DBGPRINT_ERR(("MlmeEnqueueForRecv: frame too large, size = %ld \n", MsgLen)); - return FALSE; - } - - if (MlmeQueueFull(Queue)) - { - return FALSE; - } - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - if (!MsgTypeSubst(pAd, pFrame, &Machine, &MsgType)) - { - DBGPRINT_ERR(("MlmeEnqueueForRecv: un-recongnized mgmt->subtype=%d\n",pFrame->Hdr.FC.SubType)); - return FALSE; - } - } -#endif // CONFIG_STA_SUPPORT // - - // OK, we got all the informations, it is time to put things into queue - NdisAcquireSpinLock(&(Queue->Lock)); - Tail = Queue->Tail; - Queue->Tail++; - Queue->Num++; - if (Queue->Tail == MAX_LEN_OF_MLME_QUEUE) - { - Queue->Tail = 0; - } - Queue->Entry[Tail].Occupied = TRUE; - Queue->Entry[Tail].Machine = Machine; - Queue->Entry[Tail].MsgType = MsgType; - Queue->Entry[Tail].MsgLen = MsgLen; - Queue->Entry[Tail].TimeStamp.u.LowPart = TimeStampLow; - Queue->Entry[Tail].TimeStamp.u.HighPart = TimeStampHigh; - Queue->Entry[Tail].Rssi0 = Rssi0; - Queue->Entry[Tail].Rssi1 = Rssi1; - Queue->Entry[Tail].Rssi2 = Rssi2; - Queue->Entry[Tail].Signal = Signal; - Queue->Entry[Tail].Wcid = (UCHAR)Wcid; - - Queue->Entry[Tail].Channel = pAd->LatchRfRegs.Channel; - - if (Msg != NULL) - { - NdisMoveMemory(Queue->Entry[Tail].Msg, Msg, MsgLen); - } - - NdisReleaseSpinLock(&(Queue->Lock)); - - RT28XX_MLME_HANDLER(pAd); - - return TRUE; -} - - -/*! \brief Dequeue a message from the MLME Queue - * \param *Queue The MLME Queue - * \param *Elem The message dequeued from MLME Queue - * \return TRUE if the Elem contains something, FALSE otherwise - * \pre - * \post - - IRQL = DISPATCH_LEVEL - - */ -BOOLEAN MlmeDequeue( - IN MLME_QUEUE *Queue, - OUT MLME_QUEUE_ELEM **Elem) -{ - NdisAcquireSpinLock(&(Queue->Lock)); - *Elem = &(Queue->Entry[Queue->Head]); - Queue->Num--; - Queue->Head++; - if (Queue->Head == MAX_LEN_OF_MLME_QUEUE) - { - Queue->Head = 0; - } - NdisReleaseSpinLock(&(Queue->Lock)); - return TRUE; -} - -// IRQL = DISPATCH_LEVEL -VOID MlmeRestartStateMachine( - IN PRTMP_ADAPTER pAd) -{ -#ifdef CONFIG_STA_SUPPORT - BOOLEAN Cancelled; -#endif // CONFIG_STA_SUPPORT // - - DBGPRINT(RT_DEBUG_TRACE, ("MlmeRestartStateMachine \n")); - - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { -#ifdef QOS_DLS_SUPPORT - UCHAR i; -#endif // QOS_DLS_SUPPORT // - // Cancel all timer events - // Be careful to cancel new added timer - RTMPCancelTimer(&pAd->MlmeAux.AssocTimer, &Cancelled); - RTMPCancelTimer(&pAd->MlmeAux.ReassocTimer, &Cancelled); - RTMPCancelTimer(&pAd->MlmeAux.DisassocTimer, &Cancelled); - RTMPCancelTimer(&pAd->MlmeAux.AuthTimer, &Cancelled); - RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer, &Cancelled); - RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &Cancelled); - -#ifdef QOS_DLS_SUPPORT - for (i=0; iStaCfg.DLSEntry[i].Timer, &Cancelled); - } -#endif // QOS_DLS_SUPPORT // - } -#endif // CONFIG_STA_SUPPORT // - - // Change back to original channel in case of doing scan - AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); - AsicLockChannel(pAd, pAd->CommonCfg.Channel); - - // Resume MSDU which is turned off durning scan - RTMPResumeMsduTransmission(pAd); - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - // Set all state machines back IDLE - pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; - pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; - pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; - pAd->Mlme.AuthRspMachine.CurrState = AUTH_RSP_IDLE; - pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; - pAd->Mlme.ActMachine.CurrState = ACT_IDLE; -#ifdef QOS_DLS_SUPPORT - pAd->Mlme.DlsMachine.CurrState = DLS_IDLE; -#endif // QOS_DLS_SUPPORT // - } -#endif // CONFIG_STA_SUPPORT // - -} - -/*! \brief test if the MLME Queue is empty - * \param *Queue The MLME Queue - * \return TRUE if the Queue is empty, FALSE otherwise - * \pre - * \post - - IRQL = DISPATCH_LEVEL - - */ -BOOLEAN MlmeQueueEmpty( - IN MLME_QUEUE *Queue) -{ - BOOLEAN Ans; - - NdisAcquireSpinLock(&(Queue->Lock)); - Ans = (Queue->Num == 0); - NdisReleaseSpinLock(&(Queue->Lock)); - - return Ans; -} - -/*! \brief test if the MLME Queue is full - * \param *Queue The MLME Queue - * \return TRUE if the Queue is empty, FALSE otherwise - * \pre - * \post - - IRQL = PASSIVE_LEVEL - IRQL = DISPATCH_LEVEL - - */ -BOOLEAN MlmeQueueFull( - IN MLME_QUEUE *Queue) -{ - BOOLEAN Ans; - - NdisAcquireSpinLock(&(Queue->Lock)); - Ans = (Queue->Num == MAX_LEN_OF_MLME_QUEUE || Queue->Entry[Queue->Tail].Occupied); - NdisReleaseSpinLock(&(Queue->Lock)); - - return Ans; -} - -/*! \brief The destructor of MLME Queue - * \param - * \return - * \pre - * \post - * \note Clear Mlme Queue, Set Queue->Num to Zero. - - IRQL = PASSIVE_LEVEL - - */ -VOID MlmeQueueDestroy( - IN MLME_QUEUE *pQueue) -{ - NdisAcquireSpinLock(&(pQueue->Lock)); - pQueue->Num = 0; - pQueue->Head = 0; - pQueue->Tail = 0; - NdisReleaseSpinLock(&(pQueue->Lock)); - NdisFreeSpinLock(&(pQueue->Lock)); -} - -/*! \brief To substitute the message type if the message is coming from external - * \param pFrame The frame received - * \param *Machine The state machine - * \param *MsgType the message type for the state machine - * \return TRUE if the substitution is successful, FALSE otherwise - * \pre - * \post - - IRQL = DISPATCH_LEVEL - - */ -#ifdef CONFIG_STA_SUPPORT -BOOLEAN MsgTypeSubst( - IN PRTMP_ADAPTER pAd, - IN PFRAME_802_11 pFrame, - OUT INT *Machine, - OUT INT *MsgType) -{ - USHORT Seq; - UCHAR EAPType; - PUCHAR pData; - - // Pointer to start of data frames including SNAP header - pData = (PUCHAR) pFrame + LENGTH_802_11; - - // The only data type will pass to this function is EAPOL frame - if (pFrame->Hdr.FC.Type == BTYPE_DATA) - { - if (NdisEqualMemory(SNAP_AIRONET, pData, LENGTH_802_1_H)) - { - // Cisco Aironet SNAP header - *Machine = AIRONET_STATE_MACHINE; - *MsgType = MT2_AIRONET_MSG; - return (TRUE); - } -#ifdef LEAP_SUPPORT - if ( pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP ) //LEAP - { - // LEAP frames - *Machine = LEAP_STATE_MACHINE; - EAPType = *((UCHAR*)pFrame + LENGTH_802_11 + LENGTH_802_1_H + 1); - return (LeapMsgTypeSubst(EAPType, MsgType)); - } - else -#endif // LEAP_SUPPORT // - { - *Machine = WPA_PSK_STATE_MACHINE; - EAPType = *((UCHAR*)pFrame + LENGTH_802_11 + LENGTH_802_1_H + 1); - return(WpaMsgTypeSubst(EAPType, MsgType)); - } - } - - switch (pFrame->Hdr.FC.SubType) - { - case SUBTYPE_ASSOC_REQ: - *Machine = ASSOC_STATE_MACHINE; - *MsgType = MT2_PEER_ASSOC_REQ; - break; - case SUBTYPE_ASSOC_RSP: - *Machine = ASSOC_STATE_MACHINE; - *MsgType = MT2_PEER_ASSOC_RSP; - break; - case SUBTYPE_REASSOC_REQ: - *Machine = ASSOC_STATE_MACHINE; - *MsgType = MT2_PEER_REASSOC_REQ; - break; - case SUBTYPE_REASSOC_RSP: - *Machine = ASSOC_STATE_MACHINE; - *MsgType = MT2_PEER_REASSOC_RSP; - break; - case SUBTYPE_PROBE_REQ: - *Machine = SYNC_STATE_MACHINE; - *MsgType = MT2_PEER_PROBE_REQ; - break; - case SUBTYPE_PROBE_RSP: - *Machine = SYNC_STATE_MACHINE; - *MsgType = MT2_PEER_PROBE_RSP; - break; - case SUBTYPE_BEACON: - *Machine = SYNC_STATE_MACHINE; - *MsgType = MT2_PEER_BEACON; - break; - case SUBTYPE_ATIM: - *Machine = SYNC_STATE_MACHINE; - *MsgType = MT2_PEER_ATIM; - break; - case SUBTYPE_DISASSOC: - *Machine = ASSOC_STATE_MACHINE; - *MsgType = MT2_PEER_DISASSOC_REQ; - break; - case SUBTYPE_AUTH: - // get the sequence number from payload 24 Mac Header + 2 bytes algorithm - NdisMoveMemory(&Seq, &pFrame->Octet[2], sizeof(USHORT)); - if (Seq == 1 || Seq == 3) - { - *Machine = AUTH_RSP_STATE_MACHINE; - *MsgType = MT2_PEER_AUTH_ODD; - } - else if (Seq == 2 || Seq == 4) - { - *Machine = AUTH_STATE_MACHINE; - *MsgType = MT2_PEER_AUTH_EVEN; - } - else - { - return FALSE; - } - break; - case SUBTYPE_DEAUTH: - *Machine = AUTH_RSP_STATE_MACHINE; - *MsgType = MT2_PEER_DEAUTH; - break; - case SUBTYPE_ACTION: - *Machine = ACTION_STATE_MACHINE; - // Sometimes Sta will return with category bytes with MSB = 1, if they receive catogory out of their support - if ((pFrame->Octet[0]&0x7F) > MAX_PEER_CATE_MSG) - { - *MsgType = MT2_ACT_INVALID; - } - else - { - *MsgType = (pFrame->Octet[0]&0x7F); - } - break; - default: - return FALSE; - break; - } - - return TRUE; -} -#endif // CONFIG_STA_SUPPORT // - -// =========================================================================================== -// state_machine.c -// =========================================================================================== - -/*! \brief Initialize the state machine. - * \param *S pointer to the state machine - * \param Trans State machine transition function - * \param StNr number of states - * \param MsgNr number of messages - * \param DefFunc default function, when there is invalid state/message combination - * \param InitState initial state of the state machine - * \param Base StateMachine base, internal use only - * \pre p_sm should be a legal pointer - * \post - - IRQL = PASSIVE_LEVEL - - */ -VOID StateMachineInit( - IN STATE_MACHINE *S, - IN STATE_MACHINE_FUNC Trans[], - IN ULONG StNr, - IN ULONG MsgNr, - IN STATE_MACHINE_FUNC DefFunc, - IN ULONG InitState, - IN ULONG Base) -{ - ULONG i, j; - - // set number of states and messages - S->NrState = StNr; - S->NrMsg = MsgNr; - S->Base = Base; - - S->TransFunc = Trans; - - // init all state transition to default function - for (i = 0; i < StNr; i++) - { - for (j = 0; j < MsgNr; j++) - { - S->TransFunc[i * MsgNr + j] = DefFunc; - } - } - - // set the starting state - S->CurrState = InitState; -} - -/*! \brief This function fills in the function pointer into the cell in the state machine - * \param *S pointer to the state machine - * \param St state - * \param Msg incoming message - * \param f the function to be executed when (state, message) combination occurs at the state machine - * \pre *S should be a legal pointer to the state machine, st, msg, should be all within the range, Base should be set in the initial state - * \post - - IRQL = PASSIVE_LEVEL - - */ -VOID StateMachineSetAction( - IN STATE_MACHINE *S, - IN ULONG St, - IN ULONG Msg, - IN STATE_MACHINE_FUNC Func) -{ - ULONG MsgIdx; - - MsgIdx = Msg - S->Base; - - if (St < S->NrState && MsgIdx < S->NrMsg) - { - // boundary checking before setting the action - S->TransFunc[St * S->NrMsg + MsgIdx] = Func; - } -} - -/*! \brief This function does the state transition - * \param *Adapter the NIC adapter pointer - * \param *S the state machine - * \param *Elem the message to be executed - * \return None - - IRQL = DISPATCH_LEVEL - - */ -VOID StateMachinePerformAction( - IN PRTMP_ADAPTER pAd, - IN STATE_MACHINE *S, - IN MLME_QUEUE_ELEM *Elem) -{ - (*(S->TransFunc[S->CurrState * S->NrMsg + Elem->MsgType - S->Base]))(pAd, Elem); -} - -/* - ========================================================================== - Description: - The drop function, when machine executes this, the message is simply - ignored. This function does nothing, the message is freed in - StateMachinePerformAction() - ========================================================================== - */ -VOID Drop( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ -} - -// =========================================================================================== -// lfsr.c -// =========================================================================================== - -/* - ========================================================================== - Description: - - IRQL = PASSIVE_LEVEL - - ========================================================================== - */ -VOID LfsrInit( - IN PRTMP_ADAPTER pAd, - IN ULONG Seed) -{ - if (Seed == 0) - pAd->Mlme.ShiftReg = 1; - else - pAd->Mlme.ShiftReg = Seed; -} - -/* - ========================================================================== - Description: - ========================================================================== - */ -UCHAR RandomByte( - IN PRTMP_ADAPTER pAd) -{ - ULONG i; - UCHAR R, Result; - - R = 0; - - if (pAd->Mlme.ShiftReg == 0) - NdisGetSystemUpTime((ULONG *)&pAd->Mlme.ShiftReg); - - for (i = 0; i < 8; i++) - { - if (pAd->Mlme.ShiftReg & 0x00000001) - { - pAd->Mlme.ShiftReg = ((pAd->Mlme.ShiftReg ^ LFSR_MASK) >> 1) | 0x80000000; - Result = 1; - } - else - { - pAd->Mlme.ShiftReg = pAd->Mlme.ShiftReg >> 1; - Result = 0; - } - R = (R << 1) | Result; - } - - return R; -} - -VOID AsicUpdateAutoFallBackTable( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pRateTable) -{ - UCHAR i; - HT_FBK_CFG0_STRUC HtCfg0; - HT_FBK_CFG1_STRUC HtCfg1; - LG_FBK_CFG0_STRUC LgCfg0; - LG_FBK_CFG1_STRUC LgCfg1; - PRTMP_TX_RATE_SWITCH pCurrTxRate, pNextTxRate; - - // set to initial value - HtCfg0.word = 0x65432100; - HtCfg1.word = 0xedcba988; - LgCfg0.word = 0xedcba988; - LgCfg1.word = 0x00002100; - - pNextTxRate = (PRTMP_TX_RATE_SWITCH)pRateTable+1; - for (i = 1; i < *((PUCHAR) pRateTable); i++) - { - pCurrTxRate = (PRTMP_TX_RATE_SWITCH)pRateTable+1+i; - switch (pCurrTxRate->Mode) - { - case 0: //CCK - break; - case 1: //OFDM - { - switch(pCurrTxRate->CurrMCS) - { - case 0: - LgCfg0.field.OFDMMCS0FBK = (pNextTxRate->Mode == MODE_OFDM) ? (pNextTxRate->CurrMCS+8): pNextTxRate->CurrMCS; - break; - case 1: - LgCfg0.field.OFDMMCS1FBK = (pNextTxRate->Mode == MODE_OFDM) ? (pNextTxRate->CurrMCS+8): pNextTxRate->CurrMCS; - break; - case 2: - LgCfg0.field.OFDMMCS2FBK = (pNextTxRate->Mode == MODE_OFDM) ? (pNextTxRate->CurrMCS+8): pNextTxRate->CurrMCS; - break; - case 3: - LgCfg0.field.OFDMMCS3FBK = (pNextTxRate->Mode == MODE_OFDM) ? (pNextTxRate->CurrMCS+8): pNextTxRate->CurrMCS; - break; - case 4: - LgCfg0.field.OFDMMCS4FBK = (pNextTxRate->Mode == MODE_OFDM) ? (pNextTxRate->CurrMCS+8): pNextTxRate->CurrMCS; - break; - case 5: - LgCfg0.field.OFDMMCS5FBK = (pNextTxRate->Mode == MODE_OFDM) ? (pNextTxRate->CurrMCS+8): pNextTxRate->CurrMCS; - break; - case 6: - LgCfg0.field.OFDMMCS6FBK = (pNextTxRate->Mode == MODE_OFDM) ? (pNextTxRate->CurrMCS+8): pNextTxRate->CurrMCS; - break; - case 7: - LgCfg0.field.OFDMMCS7FBK = (pNextTxRate->Mode == MODE_OFDM) ? (pNextTxRate->CurrMCS+8): pNextTxRate->CurrMCS; - break; - } - } - break; -#ifdef DOT11_N_SUPPORT - case 2: //HT-MIX - case 3: //HT-GF - { - if ((pNextTxRate->Mode >= MODE_HTMIX) && (pCurrTxRate->CurrMCS != pNextTxRate->CurrMCS)) - { - switch(pCurrTxRate->CurrMCS) - { - case 0: - HtCfg0.field.HTMCS0FBK = pNextTxRate->CurrMCS; - break; - case 1: - HtCfg0.field.HTMCS1FBK = pNextTxRate->CurrMCS; - break; - case 2: - HtCfg0.field.HTMCS2FBK = pNextTxRate->CurrMCS; - break; - case 3: - HtCfg0.field.HTMCS3FBK = pNextTxRate->CurrMCS; - break; - case 4: - HtCfg0.field.HTMCS4FBK = pNextTxRate->CurrMCS; - break; - case 5: - HtCfg0.field.HTMCS5FBK = pNextTxRate->CurrMCS; - break; - case 6: - HtCfg0.field.HTMCS6FBK = pNextTxRate->CurrMCS; - break; - case 7: - HtCfg0.field.HTMCS7FBK = pNextTxRate->CurrMCS; - break; - case 8: - HtCfg1.field.HTMCS8FBK = pNextTxRate->CurrMCS; - break; - case 9: - HtCfg1.field.HTMCS9FBK = pNextTxRate->CurrMCS; - break; - case 10: - HtCfg1.field.HTMCS10FBK = pNextTxRate->CurrMCS; - break; - case 11: - HtCfg1.field.HTMCS11FBK = pNextTxRate->CurrMCS; - break; - case 12: - HtCfg1.field.HTMCS12FBK = pNextTxRate->CurrMCS; - break; - case 13: - HtCfg1.field.HTMCS13FBK = pNextTxRate->CurrMCS; - break; - case 14: - HtCfg1.field.HTMCS14FBK = pNextTxRate->CurrMCS; - break; - case 15: - HtCfg1.field.HTMCS15FBK = pNextTxRate->CurrMCS; - break; - default: - DBGPRINT(RT_DEBUG_ERROR, ("AsicUpdateAutoFallBackTable: not support CurrMCS=%d\n", pCurrTxRate->CurrMCS)); - } - } - } - break; -#endif // DOT11_N_SUPPORT // - } - - pNextTxRate = pCurrTxRate; - } - - RTMP_IO_WRITE32(pAd, HT_FBK_CFG0, HtCfg0.word); - RTMP_IO_WRITE32(pAd, HT_FBK_CFG1, HtCfg1.word); - RTMP_IO_WRITE32(pAd, LG_FBK_CFG0, LgCfg0.word); - RTMP_IO_WRITE32(pAd, LG_FBK_CFG1, LgCfg1.word); -} - -/* - ======================================================================== - - Routine Description: - Set MAC register value according operation mode. - OperationMode AND bNonGFExist are for MM and GF Proteciton. - If MM or GF mask is not set, those passing argument doesn't not take effect. - - Operation mode meaning: - = 0 : Pure HT, no preotection. - = 0x01; there may be non-HT devices in both the control and extension channel, protection is optional in BSS. - = 0x10: No Transmission in 40M is protected. - = 0x11: Transmission in both 40M and 20M shall be protected - if (bNonGFExist) - we should choose not to use GF. But still set correct ASIC registers. - ======================================================================== -*/ -VOID AsicUpdateProtect( - IN PRTMP_ADAPTER pAd, - IN USHORT OperationMode, - IN UCHAR SetMask, - IN BOOLEAN bDisableBGProtect, - IN BOOLEAN bNonGFExist) -{ - PROT_CFG_STRUC ProtCfg, ProtCfg4; - UINT32 Protect[6]; - USHORT offset; - UCHAR i; - UINT32 MacReg = 0; - -#ifdef RALINK_ATE - if (ATE_ON(pAd)) - return; -#endif // RALINK_ATE // - -#ifdef DOT11_N_SUPPORT - if (!(pAd->CommonCfg.bHTProtect) && (OperationMode != 8)) - { - return; - } - - if (pAd->BATable.numAsOriginator) - { - // - // enable the RTS/CTS to avoid channel collision - // - SetMask = ALLN_SETPROTECT; - OperationMode = 8; - } -#endif // DOT11_N_SUPPORT // - - // Config ASIC RTS threshold register - RTMP_IO_READ32(pAd, TX_RTS_CFG, &MacReg); - MacReg &= 0xFF0000FF; - - // If the user want disable RtsThreshold and enbale Amsdu/Ralink-Aggregation, set the RtsThreshold as 4096 - if (( -#ifdef DOT11_N_SUPPORT - (pAd->CommonCfg.BACapability.field.AmsduEnable) || -#endif // DOT11_N_SUPPORT // - (pAd->CommonCfg.bAggregationCapable == TRUE)) - && pAd->CommonCfg.RtsThreshold == MAX_RTS_THRESHOLD) - { - MacReg |= (0x1000 << 8); - } - else - { - MacReg |= (pAd->CommonCfg.RtsThreshold << 8); - } - - RTMP_IO_WRITE32(pAd, TX_RTS_CFG, MacReg); - - // Initial common protection settings - RTMPZeroMemory(Protect, sizeof(Protect)); - ProtCfg4.word = 0; - ProtCfg.word = 0; - ProtCfg.field.TxopAllowGF40 = 1; - ProtCfg.field.TxopAllowGF20 = 1; - ProtCfg.field.TxopAllowMM40 = 1; - ProtCfg.field.TxopAllowMM20 = 1; - ProtCfg.field.TxopAllowOfdm = 1; - ProtCfg.field.TxopAllowCck = 1; - ProtCfg.field.RTSThEn = 1; - ProtCfg.field.ProtectNav = ASIC_SHORTNAV; - - // update PHY mode and rate - if (pAd->CommonCfg.Channel > 14) - ProtCfg.field.ProtectRate = 0x4000; - ProtCfg.field.ProtectRate |= pAd->CommonCfg.RtsRate; - - // Handle legacy(B/G) protection - if (bDisableBGProtect) - { - //ProtCfg.field.ProtectRate = pAd->CommonCfg.RtsRate; - ProtCfg.field.ProtectCtrl = 0; - Protect[0] = ProtCfg.word; - Protect[1] = ProtCfg.word; - } - else - { - //ProtCfg.field.ProtectRate = pAd->CommonCfg.RtsRate; - ProtCfg.field.ProtectCtrl = 0; // CCK do not need to be protected - Protect[0] = ProtCfg.word; - ProtCfg.field.ProtectCtrl = ASIC_CTS; // OFDM needs using CCK to protect - Protect[1] = ProtCfg.word; - } - -#ifdef DOT11_N_SUPPORT - // Decide HT frame protection. - if ((SetMask & ALLN_SETPROTECT) != 0) - { - switch(OperationMode) - { - case 0x0: - // NO PROTECT - // 1.All STAs in the BSS are 20/40 MHz HT - // 2. in ai 20/40MHz BSS - // 3. all STAs are 20MHz in a 20MHz BSS - // Pure HT. no protection. - - // MM20_PROT_CFG - // Reserved (31:27) - // PROT_TXOP(25:20) -- 010111 - // PROT_NAV(19:18) -- 01 (Short NAV protection) - // PROT_CTRL(17:16) -- 00 (None) - // PROT_RATE(15:0) -- 0x4004 (OFDM 24M) - Protect[2] = 0x01744004; - - // MM40_PROT_CFG - // Reserved (31:27) - // PROT_TXOP(25:20) -- 111111 - // PROT_NAV(19:18) -- 01 (Short NAV protection) - // PROT_CTRL(17:16) -- 00 (None) - // PROT_RATE(15:0) -- 0x4084 (duplicate OFDM 24M) - Protect[3] = 0x03f44084; - - // CF20_PROT_CFG - // Reserved (31:27) - // PROT_TXOP(25:20) -- 010111 - // PROT_NAV(19:18) -- 01 (Short NAV protection) - // PROT_CTRL(17:16) -- 00 (None) - // PROT_RATE(15:0) -- 0x4004 (OFDM 24M) - Protect[4] = 0x01744004; - - // CF40_PROT_CFG - // Reserved (31:27) - // PROT_TXOP(25:20) -- 111111 - // PROT_NAV(19:18) -- 01 (Short NAV protection) - // PROT_CTRL(17:16) -- 00 (None) - // PROT_RATE(15:0) -- 0x4084 (duplicate OFDM 24M) - Protect[5] = 0x03f44084; - - if (bNonGFExist) - { - // PROT_NAV(19:18) -- 01 (Short NAV protectiion) - // PROT_CTRL(17:16) -- 01 (RTS/CTS) - Protect[4] = 0x01754004; - Protect[5] = 0x03f54084; - } - pAd->CommonCfg.IOTestParm.bRTSLongProtOn = FALSE; - break; - - case 1: - // This is "HT non-member protection mode." - // If there may be non-HT STAs my BSS - ProtCfg.word = 0x01744004; // PROT_CTRL(17:16) : 0 (None) - ProtCfg4.word = 0x03f44084; // duplicaet legacy 24M. BW set 1. - if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_BG_PROTECTION_INUSED)) - { - ProtCfg.word = 0x01740003; //ERP use Protection bit is set, use protection rate at Clause 18.. - ProtCfg4.word = 0x03f40003; // Don't duplicate RTS/CTS in CCK mode. 0x03f40083; - } - //Assign Protection method for 20&40 MHz packets - ProtCfg.field.ProtectCtrl = ASIC_RTS; - ProtCfg.field.ProtectNav = ASIC_SHORTNAV; - ProtCfg4.field.ProtectCtrl = ASIC_RTS; - ProtCfg4.field.ProtectNav = ASIC_SHORTNAV; - Protect[2] = ProtCfg.word; - Protect[3] = ProtCfg4.word; - Protect[4] = ProtCfg.word; - Protect[5] = ProtCfg4.word; - pAd->CommonCfg.IOTestParm.bRTSLongProtOn = TRUE; - break; - - case 2: - // If only HT STAs are in BSS. at least one is 20MHz. Only protect 40MHz packets - ProtCfg.word = 0x01744004; // PROT_CTRL(17:16) : 0 (None) - ProtCfg4.word = 0x03f44084; // duplicaet legacy 24M. BW set 1. - - //Assign Protection method for 40MHz packets - ProtCfg4.field.ProtectCtrl = ASIC_RTS; - ProtCfg4.field.ProtectNav = ASIC_SHORTNAV; - Protect[2] = ProtCfg.word; - Protect[3] = ProtCfg4.word; - if (bNonGFExist) - { - ProtCfg.field.ProtectCtrl = ASIC_RTS; - ProtCfg.field.ProtectNav = ASIC_SHORTNAV; - } - Protect[4] = ProtCfg.word; - Protect[5] = ProtCfg4.word; - - pAd->CommonCfg.IOTestParm.bRTSLongProtOn = FALSE; - break; - - case 3: - // HT mixed mode. PROTECT ALL! - // Assign Rate - ProtCfg.word = 0x01744004; //duplicaet legacy 24M. BW set 1. - ProtCfg4.word = 0x03f44084; - // both 20MHz and 40MHz are protected. Whether use RTS or CTS-to-self depends on the - if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_BG_PROTECTION_INUSED)) - { - ProtCfg.word = 0x01740003; //ERP use Protection bit is set, use protection rate at Clause 18.. - ProtCfg4.word = 0x03f40003; // Don't duplicate RTS/CTS in CCK mode. 0x03f40083 - } - //Assign Protection method for 20&40 MHz packets - ProtCfg.field.ProtectCtrl = ASIC_RTS; - ProtCfg.field.ProtectNav = ASIC_SHORTNAV; - ProtCfg4.field.ProtectCtrl = ASIC_RTS; - ProtCfg4.field.ProtectNav = ASIC_SHORTNAV; - Protect[2] = ProtCfg.word; - Protect[3] = ProtCfg4.word; - Protect[4] = ProtCfg.word; - Protect[5] = ProtCfg4.word; - pAd->CommonCfg.IOTestParm.bRTSLongProtOn = TRUE; - break; - - case 8: - Protect[2] = 0x01754004; - Protect[3] = 0x03f54084; - Protect[4] = 0x01754004; - Protect[5] = 0x03f54084; - pAd->CommonCfg.IOTestParm.bRTSLongProtOn = TRUE; - break; - } - } -#endif // DOT11_N_SUPPORT // - - offset = CCK_PROT_CFG; - for (i = 0;i < 6;i++) - { - if ((SetMask & (1<< i))) - { - RTMP_IO_WRITE32(pAd, offset + i*4, Protect[i]); - } - } -} - - -#ifdef RT30xx -/* - ======================================================================== - - Routine Description: Write RT30xx RF register through MAC - - Arguments: - - Return Value: - - IRQL = - - Note: - - ======================================================================== -*/ -NTSTATUS RT30xxWriteRFRegister( - IN PRTMP_ADAPTER pAd, - IN UCHAR RegID, - IN UCHAR Value) -{ - RF_CSR_CFG_STRUC rfcsr; - UINT i = 0; - - do - { - RTMP_IO_READ32(pAd, RF_CSR_CFG, &rfcsr.word); - - if (!rfcsr.field.RF_CSR_KICK) - break; - i++; - } - while ((i < RETRY_LIMIT) && (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))); - - if ((i == RETRY_LIMIT) || (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))) - { - DBGPRINT_RAW(RT_DEBUG_ERROR, ("Retry count exhausted or device removed!!!\n")); - return STATUS_UNSUCCESSFUL; - } - - rfcsr.field.RF_CSR_WR = 1; - rfcsr.field.RF_CSR_KICK = 1; - rfcsr.field.TESTCSR_RFACC_REGNUM = RegID; - rfcsr.field.RF_CSR_DATA = Value; - - RTMP_IO_WRITE32(pAd, RF_CSR_CFG, rfcsr.word); - - return STATUS_SUCCESS; -} - - -/* - ======================================================================== - - Routine Description: Read RT30xx RF register through MAC - - Arguments: - - Return Value: - - IRQL = - - Note: - - ======================================================================== -*/ -NTSTATUS RT30xxReadRFRegister( - IN PRTMP_ADAPTER pAd, - IN UCHAR RegID, - IN PUCHAR pValue) -{ - RF_CSR_CFG_STRUC rfcsr; - UINT i=0, k=0; - - for (i=0; iMACVersion & 0xffff) >= 0x0211) && (pAd->NicConfig2.field.ExternalLNAForG == 0)) - { - RFValue |= 0x20; - } - RT30xxWriteRFRegister(pAd, RF_R17, RFValue); - - // RX_LO1_en, RF R20 register Bit 3 to 0 - RT30xxReadRFRegister(pAd, RF_R20, &RFValue); - RFValue &= (~0x08); - RT30xxWriteRFRegister(pAd, RF_R20, RFValue); - - // RX_LO2_en, RF R21 register Bit 3 to 0 - RT30xxReadRFRegister(pAd, RF_R21, &RFValue); - RFValue &= (~0x08); - RT30xxWriteRFRegister(pAd, RF_R21, RFValue); - - // LDORF_VC, RF R27 register Bit 2 to 0 - RT30xxReadRFRegister(pAd, RF_R27, &RFValue); - if ((pAd->MACVersion & 0xffff) < 0x0211) - RFValue = (RFValue & (~0x77)) | 0x3; - else - RFValue = (RFValue & (~0x77)); - RT30xxWriteRFRegister(pAd, RF_R27, RFValue); - /* end johnli */ -} - -/* - ========================================================================== - Description: - - Load RF sleep-mode setup - - ========================================================================== - */ -VOID RT30xxLoadRFSleepModeSetup( - IN PRTMP_ADAPTER pAd) -{ - UCHAR RFValue; - UINT32 MACValue; - - // RF_BLOCK_en. RF R1 register Bit 0 to 0 - RT30xxReadRFRegister(pAd, RF_R01, &RFValue); - RFValue &= (~0x01); - RT30xxWriteRFRegister(pAd, RF_R01, RFValue); - - // VCO_IC, RF R7 register Bit 4 & Bit 5 to 0 - RT30xxReadRFRegister(pAd, RF_R07, &RFValue); - RFValue &= (~0x30); - RT30xxWriteRFRegister(pAd, RF_R07, RFValue); - - // Idoh, RF R9 register Bit 1, Bit 2 & Bit 3 to 0 - RT30xxReadRFRegister(pAd, RF_R09, &RFValue); - RFValue &= (~0x0E); - RT30xxWriteRFRegister(pAd, RF_R09, RFValue); - - // RX_CTB_en, RF R21 register Bit 7 to 0 - RT30xxReadRFRegister(pAd, RF_R21, &RFValue); - RFValue &= (~0x80); - RT30xxWriteRFRegister(pAd, RF_R21, RFValue); - - // LDORF_VC, RF R27 register Bit 0, Bit 1 & Bit 2 to 1 - RT30xxReadRFRegister(pAd, RF_R27, &RFValue); - RFValue |= 0x77; - RT30xxWriteRFRegister(pAd, RF_R27, RFValue); - - RTMP_IO_READ32(pAd, LDO_CFG0, &MACValue); - MACValue |= 0x1D000000; - RTMP_IO_WRITE32(pAd, LDO_CFG0, MACValue); -} - -/* - ========================================================================== - Description: - - Reverse RF sleep-mode setup - - ========================================================================== - */ -VOID RT30xxReverseRFSleepModeSetup( - IN PRTMP_ADAPTER pAd) -{ - UCHAR RFValue; - UINT32 MACValue; - - // RF_BLOCK_en, RF R1 register Bit 0 to 1 - RT30xxReadRFRegister(pAd, RF_R01, &RFValue); - RFValue |= 0x01; - RT30xxWriteRFRegister(pAd, RF_R01, RFValue); - - // VCO_IC, RF R7 register Bit 4 & Bit 5 to 1 - RT30xxReadRFRegister(pAd, RF_R07, &RFValue); - RFValue |= 0x30; - RT30xxWriteRFRegister(pAd, RF_R07, RFValue); - - // Idoh, RF R9 register Bit 1, Bit 2 & Bit 3 to 1 - RT30xxReadRFRegister(pAd, RF_R09, &RFValue); - RFValue |= 0x0E; - RT30xxWriteRFRegister(pAd, RF_R09, RFValue); - - // RX_CTB_en, RF R21 register Bit 7 to 1 - RT30xxReadRFRegister(pAd, RF_R21, &RFValue); - RFValue |= 0x80; - RT30xxWriteRFRegister(pAd, RF_R21, RFValue); - - // LDORF_VC, RF R27 register Bit 2 to 0 - RT30xxReadRFRegister(pAd, RF_R27, &RFValue); - if ((pAd->MACVersion & 0xffff) < 0x0211) - RFValue = (RFValue & (~0x77)) | 0x3; - else - RFValue = (RFValue & (~0x77)); - RT30xxWriteRFRegister(pAd, RF_R27, RFValue); - - // RT3071 version E has fixed this issue - if ((pAd->NicConfig2.field.DACTestBit == 1) && ((pAd->MACVersion & 0xffff) < 0x0211)) - { - // patch tx EVM issue temporarily - RTMP_IO_READ32(pAd, LDO_CFG0, &MACValue); - MACValue = ((MACValue & 0xE0FFFFFF) | 0x0D000000); - RTMP_IO_WRITE32(pAd, LDO_CFG0, MACValue); - } - else - { - RTMP_IO_READ32(pAd, LDO_CFG0, &MACValue); - MACValue = ((MACValue & 0xE0FFFFFF) | 0x01000000); - RTMP_IO_WRITE32(pAd, LDO_CFG0, MACValue); - } -} -// end johnli -#endif // RT30xx // - -/* - ========================================================================== - Description: - - IRQL = PASSIVE_LEVEL - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID AsicSwitchChannel( - IN PRTMP_ADAPTER pAd, - IN UCHAR Channel, - IN BOOLEAN bScan) -{ - ULONG R2 = 0, R3 = DEFAULT_RF_TX_POWER, R4 = 0; - CHAR TxPwer = 0, TxPwer2 = DEFAULT_RF_TX_POWER; //Bbp94 = BBPR94_DEFAULT, TxPwer2 = DEFAULT_RF_TX_POWER; - UCHAR index; - UINT32 Value = 0; //BbpReg, Value; - RTMP_RF_REGS *RFRegTable; - - // Search Tx power value -#if 1 - // We can't use ChannelList to search channel, since some central channl's txpowr doesn't list - // in ChannelList, so use TxPower array instead. - // - for (index = 0; index < MAX_NUM_OF_CHANNELS; index++) - { - if (Channel == pAd->TxPower[index].Channel) - { - TxPwer = pAd->TxPower[index].Power; - TxPwer2 = pAd->TxPower[index].Power2; - break; - } - } -#else - for (index = 0; index < pAd->ChannelListNum; index++) - { - if (Channel == pAd->ChannelList[index].Channel) - { - TxPwer = pAd->ChannelList[index].Power; - TxPwer2 = pAd->ChannelList[index].Power2; - break; - } - } -#endif - - if (index == MAX_NUM_OF_CHANNELS) - { - DBGPRINT(RT_DEBUG_ERROR, ("AsicSwitchChannel: Can't find the Channel#%d \n", Channel)); - } - -#ifdef RT30xx - // The RF programming sequence is difference between 3xxx and 2xxx - if ((IS_RT3070(pAd) || IS_RT3090(pAd)) && ((pAd->RfIcType == RFIC_3020) || (pAd->RfIcType == RFIC_2020) || - (pAd->RfIcType == RFIC_3021) || (pAd->RfIcType == RFIC_3022))) - { - /* modify by WY for Read RF Reg. error */ - UCHAR RFValue; - - for (index = 0; index < NUM_OF_3020_CHNL; index++) - { - if (Channel == FreqItems3020[index].Channel) - { - // Programming channel parameters - RT30xxWriteRFRegister(pAd, RF_R02, FreqItems3020[index].N); - RT30xxWriteRFRegister(pAd, RF_R03, FreqItems3020[index].K); - RT30xxReadRFRegister(pAd, RF_R06, &RFValue); - RFValue = (RFValue & 0xFC) | FreqItems3020[index].R; - RT30xxWriteRFRegister(pAd, RF_R06, RFValue); - - // Set Tx0 Power - RT30xxReadRFRegister(pAd, RF_R12, &RFValue); - RFValue = (RFValue & 0xE0) | TxPwer; - RT30xxWriteRFRegister(pAd, RF_R12, RFValue); - - // Set Tx1 Power - RT30xxReadRFRegister(pAd, RF_R13, &RFValue); - RFValue = (RFValue & 0xE0) | TxPwer2; - RT30xxWriteRFRegister(pAd, RF_R13, RFValue); - - // Tx/Rx Stream setting - RT30xxReadRFRegister(pAd, RF_R01, &RFValue); - //if (IS_RT3090(pAd)) - // RFValue |= 0x01; // Enable RF block. - RFValue &= 0x03; //clear bit[7~2] - if (pAd->Antenna.field.TxPath == 1) - RFValue |= 0xA0; - else if (pAd->Antenna.field.TxPath == 2) - RFValue |= 0x80; - if (pAd->Antenna.field.RxPath == 1) - RFValue |= 0x50; - else if (pAd->Antenna.field.RxPath == 2) - RFValue |= 0x40; - RT30xxWriteRFRegister(pAd, RF_R01, RFValue); - - // Set RF offset - RT30xxReadRFRegister(pAd, RF_R23, &RFValue); - RFValue = (RFValue & 0x80) | pAd->RfFreqOffset; - RT30xxWriteRFRegister(pAd, RF_R23, RFValue); - - // Set BW - if (!bScan && (pAd->CommonCfg.BBPCurrentBW == BW_40)) - { - RFValue = pAd->Mlme.CaliBW40RfR24; - //DISABLE_11N_CHECK(pAd); - } - else - { - RFValue = pAd->Mlme.CaliBW20RfR24; - } - RT30xxWriteRFRegister(pAd, RF_R24, RFValue); - RT30xxWriteRFRegister(pAd, RF_R31, RFValue); - - // Enable RF tuning - RT30xxReadRFRegister(pAd, RF_R07, &RFValue); - RFValue = RFValue | 0x1; - RT30xxWriteRFRegister(pAd, RF_R07, RFValue); - - // latch channel for future usage. - pAd->LatchRfRegs.Channel = Channel; - - DBGPRINT(RT_DEBUG_TRACE, ("SwitchChannel#%d(RF=%d, Pwr0=%d, Pwr1=%d, %dT), N=0x%02X, K=0x%02X, R=0x%02X\n", - Channel, - pAd->RfIcType, - TxPwer, - TxPwer2, - pAd->Antenna.field.TxPath, - FreqItems3020[index].N, - FreqItems3020[index].K, - FreqItems3020[index].R)); - - break; - } - } - } - else -#endif // RT30xx // - - { - RFRegTable = RF2850RegTable; - - switch (pAd->RfIcType) - { - case RFIC_2820: - case RFIC_2850: - case RFIC_2720: - case RFIC_2750: - - for (index = 0; index < NUM_OF_2850_CHNL; index++) - { - if (Channel == RFRegTable[index].Channel) - { - R2 = RFRegTable[index].R2; - if (pAd->Antenna.field.TxPath == 1) - { - R2 |= 0x4000; // If TXpath is 1, bit 14 = 1; - } - - if (pAd->Antenna.field.RxPath == 2) - { - R2 |= 0x40; // write 1 to off Rxpath. - } - else if (pAd->Antenna.field.RxPath == 1) - { - R2 |= 0x20040; // write 1 to off RxPath - } - - if (Channel > 14) - { - // initialize R3, R4 - R3 = (RFRegTable[index].R3 & 0xffffc1ff); - R4 = (RFRegTable[index].R4 & (~0x001f87c0)) | (pAd->RfFreqOffset << 15); - - // 5G band power range: 0xF9~0X0F, TX0 Reg3 bit9/TX1 Reg4 bit6="0" means the TX power reduce 7dB - // R3 - if ((TxPwer >= -7) && (TxPwer < 0)) - { - TxPwer = (7+TxPwer); - TxPwer = (TxPwer > 0xF) ? (0xF) : (TxPwer); - R3 |= (TxPwer << 10); - DBGPRINT(RT_DEBUG_ERROR, ("AsicSwitchChannel: TxPwer=%d \n", TxPwer)); - } - else - { - TxPwer = (TxPwer > 0xF) ? (0xF) : (TxPwer); - R3 |= (TxPwer << 10) | (1 << 9); - } - - // R4 - if ((TxPwer2 >= -7) && (TxPwer2 < 0)) - { - TxPwer2 = (7+TxPwer2); - TxPwer2 = (TxPwer2 > 0xF) ? (0xF) : (TxPwer2); - R4 |= (TxPwer2 << 7); - DBGPRINT(RT_DEBUG_ERROR, ("AsicSwitchChannel: TxPwer2=%d \n", TxPwer2)); - } - else - { - TxPwer2 = (TxPwer2 > 0xF) ? (0xF) : (TxPwer2); - R4 |= (TxPwer2 << 7) | (1 << 6); - } - } - else - { - R3 = (RFRegTable[index].R3 & 0xffffc1ff) | (TxPwer << 9); // set TX power0 - R4 = (RFRegTable[index].R4 & (~0x001f87c0)) | (pAd->RfFreqOffset << 15) | (TxPwer2 <<6);// Set freq Offset & TxPwr1 - } - - // Based on BBP current mode before changing RF channel. - if (!bScan && (pAd->CommonCfg.BBPCurrentBW == BW_40)) - { - R4 |=0x200000; - } - - // Update variables - pAd->LatchRfRegs.Channel = Channel; - pAd->LatchRfRegs.R1 = RFRegTable[index].R1; - pAd->LatchRfRegs.R2 = R2; - pAd->LatchRfRegs.R3 = R3; - pAd->LatchRfRegs.R4 = R4; - - // Set RF value 1's set R3[bit2] = [0] - RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R1); - RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R2); - RTMP_RF_IO_WRITE32(pAd, (pAd->LatchRfRegs.R3 & (~0x04))); - RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R4); - - RTMPusecDelay(200); - - // Set RF value 2's set R3[bit2] = [1] - RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R1); - RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R2); - RTMP_RF_IO_WRITE32(pAd, (pAd->LatchRfRegs.R3 | 0x04)); - RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R4); - - RTMPusecDelay(200); - - // Set RF value 3's set R3[bit2] = [0] - RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R1); - RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R2); - RTMP_RF_IO_WRITE32(pAd, (pAd->LatchRfRegs.R3 & (~0x04))); - RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R4); - - break; - } - } - break; - - default: - break; - } - } - - // Change BBP setting during siwtch from a->g, g->a - if (Channel <= 14) - { - ULONG TxPinCfg = 0x00050F0A;//Gary 2007/08/09 0x050A0A - - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R62, (0x37 - GET_LNA_GAIN(pAd))); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R63, (0x37 - GET_LNA_GAIN(pAd))); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R64, (0x37 - GET_LNA_GAIN(pAd))); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R86, 0);//(0x44 - GET_LNA_GAIN(pAd))); // According the Rory's suggestion to solve the middle range issue. - //RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R82, 0x62); - - // Rx High power VGA offset for LNA select - if (pAd->NicConfig2.field.ExternalLNAForG) - { - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R82, 0x62); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R75, 0x46); - } - else - { - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R82, 0x84); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R75, 0x50); - } - - // 5G band selection PIN, bit1 and bit2 are complement - RTMP_IO_READ32(pAd, TX_BAND_CFG, &Value); - Value &= (~0x6); - Value |= (0x04); - RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Value); - - // Turn off unused PA or LNA when only 1T or 1R - if (pAd->Antenna.field.TxPath == 1) - { - TxPinCfg &= 0xFFFFFFF3; - } - if (pAd->Antenna.field.RxPath == 1) - { - TxPinCfg &= 0xFFFFF3FF; - } - - RTMP_IO_WRITE32(pAd, TX_PIN_CFG, TxPinCfg); - } - else - { - ULONG TxPinCfg = 0x00050F05;//Gary 2007/8/9 0x050505 - - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R62, (0x37 - GET_LNA_GAIN(pAd))); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R63, (0x37 - GET_LNA_GAIN(pAd))); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R64, (0x37 - GET_LNA_GAIN(pAd))); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R86, 0);//(0x44 - GET_LNA_GAIN(pAd))); // According the Rory's suggestion to solve the middle range issue. - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R82, 0xF2); - - // Rx High power VGA offset for LNA select - if (pAd->NicConfig2.field.ExternalLNAForA) - { - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R75, 0x46); - } - else - { - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R75, 0x50); - } - - // 5G band selection PIN, bit1 and bit2 are complement - RTMP_IO_READ32(pAd, TX_BAND_CFG, &Value); - Value &= (~0x6); - Value |= (0x02); - RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Value); - - // Turn off unused PA or LNA when only 1T or 1R - if (pAd->Antenna.field.TxPath == 1) - { - TxPinCfg &= 0xFFFFFFF3; - } - if (pAd->Antenna.field.RxPath == 1) - { - TxPinCfg &= 0xFFFFF3FF; - } - - RTMP_IO_WRITE32(pAd, TX_PIN_CFG, TxPinCfg); - } - - // R66 should be set according to Channel and use 20MHz when scanning - //RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, (0x2E + GET_LNA_GAIN(pAd))); - if (bScan) - RTMPSetAGCInitValue(pAd, BW_20); - else - RTMPSetAGCInitValue(pAd, pAd->CommonCfg.BBPCurrentBW); - - // - // On 11A, We should delay and wait RF/BBP to be stable - // and the appropriate time should be 1000 micro seconds - // 2005/06/05 - On 11G, We also need this delay time. Otherwise it's difficult to pass the WHQL. - // - RTMPusecDelay(1000); - - DBGPRINT(RT_DEBUG_TRACE, ("SwitchChannel#%d(RF=%d, Pwr0=%lu, Pwr1=%lu, %dT) to , R1=0x%08lx, R2=0x%08lx, R3=0x%08lx, R4=0x%08lx\n", - Channel, - pAd->RfIcType, - (R3 & 0x00003e00) >> 9, - (R4 & 0x000007c0) >> 6, - pAd->Antenna.field.TxPath, - pAd->LatchRfRegs.R1, - pAd->LatchRfRegs.R2, - pAd->LatchRfRegs.R3, - pAd->LatchRfRegs.R4)); -} - -/* - ========================================================================== - Description: - This function is required for 2421 only, and should not be used during - site survey. It's only required after NIC decided to stay at a channel - for a longer period. - When this function is called, it's always after AsicSwitchChannel(). - - IRQL = PASSIVE_LEVEL - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID AsicLockChannel( - IN PRTMP_ADAPTER pAd, - IN UCHAR Channel) -{ -} - -/* - ========================================================================== - Description: - - IRQL = PASSIVE_LEVEL - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID AsicAntennaSelect( - IN PRTMP_ADAPTER pAd, - IN UCHAR Channel) -{ - if (pAd->Mlme.OneSecPeriodicRound % 2 == 1) - { - // patch for AsicSetRxAnt failed - pAd->RxAnt.EvaluatePeriod = 0; - - // check every 2 second. If rcv-beacon less than 5 in the past 2 second, then AvgRSSI is no longer a - // valid indication of the distance between this AP and its clients. - if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) - { - SHORT realavgrssi1; - - // if no traffic then reset average rssi to trigger evaluation -#ifdef CONFIG_STA_SUPPORT - if (pAd->StaCfg.NumOfAvgRssiSample < 5) - { - pAd->RxAnt.Pair1LastAvgRssi = (-99); - pAd->RxAnt.Pair2LastAvgRssi = (-99); - DBGPRINT(RT_DEBUG_TRACE, ("MlmePeriodicExec: no traffic/beacon, reset RSSI\n")); - } - - pAd->StaCfg.NumOfAvgRssiSample = 0; -#endif // CONFIG_STA_SUPPORT // - realavgrssi1 = (pAd->RxAnt.Pair1AvgRssi[pAd->RxAnt.Pair1PrimaryRxAnt] >> 3); - - DBGPRINT(RT_DEBUG_TRACE,("Ant-realrssi0(%d), Lastrssi0(%d), EvaluateStableCnt=%d\n", realavgrssi1, pAd->RxAnt.Pair1LastAvgRssi, pAd->RxAnt.EvaluateStableCnt)); - - // if the difference between two rssi is larger or less than 5, then evaluate the other antenna - if ((pAd->RxAnt.EvaluateStableCnt < 2) || (realavgrssi1 > (pAd->RxAnt.Pair1LastAvgRssi + 5)) || (realavgrssi1 < (pAd->RxAnt.Pair1LastAvgRssi - 5))) - { - pAd->RxAnt.Pair1LastAvgRssi = realavgrssi1; - AsicEvaluateRxAnt(pAd); - } - } - else - { - // if not connected, always switch antenna to try to connect - UCHAR temp; - - temp = pAd->RxAnt.Pair1PrimaryRxAnt; - pAd->RxAnt.Pair1PrimaryRxAnt = pAd->RxAnt.Pair1SecondaryRxAnt; - pAd->RxAnt.Pair1SecondaryRxAnt = temp; - - DBGPRINT(RT_DEBUG_TRACE, ("MlmePeriodicExec: no connect, switch to another one to try connection\n")); - - AsicSetRxAnt(pAd, pAd->RxAnt.Pair1PrimaryRxAnt); - } - } -} - -/* - ======================================================================== - - Routine Description: - Antenna miscellaneous setting. - - Arguments: - pAd Pointer to our adapter - BandState Indicate current Band State. - - Return Value: - None - - IRQL <= DISPATCH_LEVEL - - Note: - 1.) Frame End type control - only valid for G only (RF_2527 & RF_2529) - 0: means DPDT, set BBP R4 bit 5 to 1 - 1: means SPDT, set BBP R4 bit 5 to 0 - - - ======================================================================== -*/ -VOID AsicAntennaSetting( - IN PRTMP_ADAPTER pAd, - IN ABGBAND_STATE BandState) -{ -} - -VOID AsicRfTuningExec( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3) -{ -} - -/* - ========================================================================== - Description: - Gives CCK TX rate 2 more dB TX power. - This routine works only in LINK UP in INFRASTRUCTURE mode. - - calculate desired Tx power in RF R3.Tx0~5, should consider - - 0. if current radio is a noisy environment (pAd->DrsCounters.fNoisyEnvironment) - 1. TxPowerPercentage - 2. auto calibration based on TSSI feedback - 3. extra 2 db for CCK - 4. -10 db upon very-short distance (AvgRSSI >= -40db) to AP - - NOTE: Since this routine requires the value of (pAd->DrsCounters.fNoisyEnvironment), - it should be called AFTER MlmeDynamicTxRatSwitching() - ========================================================================== - */ -VOID AsicAdjustTxPower( - IN PRTMP_ADAPTER pAd) -{ - INT i, j; - CHAR DeltaPwr = 0; - BOOLEAN bAutoTxAgc = FALSE; - UCHAR TssiRef, *pTssiMinusBoundary, *pTssiPlusBoundary, TxAgcStep; - UCHAR BbpR1 = 0, BbpR49 = 0, idx; - PCHAR pTxAgcCompensate; - ULONG TxPwr[5]; - CHAR Value; - - - - if (pAd->CommonCfg.BBPCurrentBW == BW_40) - { - if (pAd->CommonCfg.CentralChannel > 14) - { - TxPwr[0] = pAd->Tx40MPwrCfgABand[0]; - TxPwr[1] = pAd->Tx40MPwrCfgABand[1]; - TxPwr[2] = pAd->Tx40MPwrCfgABand[2]; - TxPwr[3] = pAd->Tx40MPwrCfgABand[3]; - TxPwr[4] = pAd->Tx40MPwrCfgABand[4]; - } - else - { - TxPwr[0] = pAd->Tx40MPwrCfgGBand[0]; - TxPwr[1] = pAd->Tx40MPwrCfgGBand[1]; - TxPwr[2] = pAd->Tx40MPwrCfgGBand[2]; - TxPwr[3] = pAd->Tx40MPwrCfgGBand[3]; - TxPwr[4] = pAd->Tx40MPwrCfgGBand[4]; - } - } - else - { - if (pAd->CommonCfg.Channel > 14) - { - TxPwr[0] = pAd->Tx20MPwrCfgABand[0]; - TxPwr[1] = pAd->Tx20MPwrCfgABand[1]; - TxPwr[2] = pAd->Tx20MPwrCfgABand[2]; - TxPwr[3] = pAd->Tx20MPwrCfgABand[3]; - TxPwr[4] = pAd->Tx20MPwrCfgABand[4]; - } - else - { - TxPwr[0] = pAd->Tx20MPwrCfgGBand[0]; - TxPwr[1] = pAd->Tx20MPwrCfgGBand[1]; - TxPwr[2] = pAd->Tx20MPwrCfgGBand[2]; - TxPwr[3] = pAd->Tx20MPwrCfgGBand[3]; - TxPwr[4] = pAd->Tx20MPwrCfgGBand[4]; - } - } - - // TX power compensation for temperature variation based on TSSI. try every 4 second - if (pAd->Mlme.OneSecPeriodicRound % 4 == 0) - { - if (pAd->CommonCfg.Channel <= 14) - { - /* bg channel */ - bAutoTxAgc = pAd->bAutoTxAgcG; - TssiRef = pAd->TssiRefG; - pTssiMinusBoundary = &pAd->TssiMinusBoundaryG[0]; - pTssiPlusBoundary = &pAd->TssiPlusBoundaryG[0]; - TxAgcStep = pAd->TxAgcStepG; - pTxAgcCompensate = &pAd->TxAgcCompensateG; - } - else - { - /* a channel */ - bAutoTxAgc = pAd->bAutoTxAgcA; - TssiRef = pAd->TssiRefA; - pTssiMinusBoundary = &pAd->TssiMinusBoundaryA[0]; - pTssiPlusBoundary = &pAd->TssiPlusBoundaryA[0]; - TxAgcStep = pAd->TxAgcStepA; - pTxAgcCompensate = &pAd->TxAgcCompensateA; - } - - if (bAutoTxAgc) - { - /* BbpR1 is unsigned char */ - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R49, &BbpR49); - - /* (p) TssiPlusBoundaryG[0] = 0 = (m) TssiMinusBoundaryG[0] */ - /* compensate: +4 +3 +2 +1 0 -1 -2 -3 -4 * steps */ - /* step value is defined in pAd->TxAgcStepG for tx power value */ - - /* [4]+1+[4] p4 p3 p2 p1 o1 m1 m2 m3 m4 */ - /* ex: 0x00 0x15 0x25 0x45 0x88 0xA0 0xB5 0xD0 0xF0 - above value are examined in mass factory production */ - /* [4] [3] [2] [1] [0] [1] [2] [3] [4] */ - - /* plus (+) is 0x00 ~ 0x45, minus (-) is 0xa0 ~ 0xf0 */ - /* if value is between p1 ~ o1 or o1 ~ s1, no need to adjust tx power */ - /* if value is 0xa5, tx power will be -= TxAgcStep*(2-1) */ - - if (BbpR49 > pTssiMinusBoundary[1]) - { - // Reading is larger than the reference value - // check for how large we need to decrease the Tx power - for (idx = 1; idx < 5; idx++) - { - if (BbpR49 <= pTssiMinusBoundary[idx]) // Found the range - break; - } - // The index is the step we should decrease, idx = 0 means there is nothing to compensate -// if (R3 > (ULONG) (TxAgcStep * (idx-1))) - *pTxAgcCompensate = -(TxAgcStep * (idx-1)); -// else -// *pTxAgcCompensate = -((UCHAR)R3); - - DeltaPwr += (*pTxAgcCompensate); - DBGPRINT(RT_DEBUG_TRACE, ("-- Tx Power, BBP R1=%x, TssiRef=%x, TxAgcStep=%x, step = -%d\n", - BbpR49, TssiRef, TxAgcStep, idx-1)); - } - else if (BbpR49 < pTssiPlusBoundary[1]) - { - // Reading is smaller than the reference value - // check for how large we need to increase the Tx power - for (idx = 1; idx < 5; idx++) - { - if (BbpR49 >= pTssiPlusBoundary[idx]) // Found the range - break; - } - // The index is the step we should increase, idx = 0 means there is nothing to compensate - *pTxAgcCompensate = TxAgcStep * (idx-1); - DeltaPwr += (*pTxAgcCompensate); - DBGPRINT(RT_DEBUG_TRACE, ("++ Tx Power, BBP R1=%x, TssiRef=%x, TxAgcStep=%x, step = +%d\n", - BbpR49, TssiRef, TxAgcStep, idx-1)); - } - else - { - *pTxAgcCompensate = 0; - DBGPRINT(RT_DEBUG_TRACE, (" Tx Power, BBP R49=%x, TssiRef=%x, TxAgcStep=%x, step = +%d\n", - BbpR49, TssiRef, TxAgcStep, 0)); - } - } - } - else - { - if (pAd->CommonCfg.Channel <= 14) - { - bAutoTxAgc = pAd->bAutoTxAgcG; - pTxAgcCompensate = &pAd->TxAgcCompensateG; - } - else - { - bAutoTxAgc = pAd->bAutoTxAgcA; - pTxAgcCompensate = &pAd->TxAgcCompensateA; - } - - if (bAutoTxAgc) - DeltaPwr += (*pTxAgcCompensate); - } - - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R1, &BbpR1); - BbpR1 &= 0xFC; - -#ifdef SINGLE_SKU - // Handle regulatory max tx power constrain - do - { - UCHAR TxPwrInEEPROM = 0xFF, CountryTxPwr = 0xFF, criterion; - UCHAR AdjustMaxTxPwr[40]; - - if (pAd->CommonCfg.Channel > 14) // 5G band - TxPwrInEEPROM = ((pAd->CommonCfg.DefineMaxTxPwr & 0xFF00) >> 8); - else // 2.4G band - TxPwrInEEPROM = (pAd->CommonCfg.DefineMaxTxPwr & 0x00FF); - CountryTxPwr = GetCuntryMaxTxPwr(pAd, pAd->CommonCfg.Channel); - - // error handling, range check - if ((TxPwrInEEPROM > 0x50) || (CountryTxPwr > 0x50)) - { - DBGPRINT(RT_DEBUG_ERROR,("AsicAdjustTxPower - Invalid max tx power (=0x%02x), CountryTxPwr=%d\n", TxPwrInEEPROM, CountryTxPwr)); - break; - } - - criterion = *((PUCHAR)TxPwr + 2) & 0xF; // FAE use OFDM 6M as criterion - - DBGPRINT_RAW(RT_DEBUG_TRACE,("AsicAdjustTxPower (criterion=%d, TxPwrInEEPROM=%d, CountryTxPwr=%d)\n", criterion, TxPwrInEEPROM, CountryTxPwr)); - - // Adjust max tx power according to the relationship of tx power in E2PROM - for (i=0; i<5; i++) - { - // CCK will have 4dBm larger than OFDM - // Therefore, we should separate to parse the tx power field - if (i == 0) - { - for (j=0; j<8; j++) - { - Value = (CHAR)((TxPwr[i] >> j*4) & 0x0F); - - if (j < 4) - { - // CCK will have 4dBm larger than OFDM - AdjustMaxTxPwr[i*8+j] = TxPwrInEEPROM + (Value - criterion) + 4; - } - else - { - AdjustMaxTxPwr[i*8+j] = TxPwrInEEPROM + (Value - criterion); - } - DBGPRINT_RAW(RT_DEBUG_TRACE,("AsicAdjustTxPower (i/j=%d/%d, Value=%d, %d)\n", i, j, Value, AdjustMaxTxPwr[i*8+j])); - } - } - else - { - for (j=0; j<8; j++) - { - Value = (CHAR)((TxPwr[i] >> j*4) & 0x0F); - - AdjustMaxTxPwr[i*8+j] = TxPwrInEEPROM + (Value - criterion); - DBGPRINT_RAW(RT_DEBUG_TRACE,("AsicAdjustTxPower (i/j=%d/%d, Value=%d, %d)\n", i, j, Value, AdjustMaxTxPwr[i*8+j])); - } - } - } - - // Adjust tx power according to the relationship - for (i=0; i<5; i++) - { - if (TxPwr[i] != 0xffffffff) - { - for (j=0; j<8; j++) - { - Value = (CHAR)((TxPwr[i] >> j*4) & 0x0F); - - // The system tx power is larger than the regulatory, the power should be restrain - if (AdjustMaxTxPwr[i*8+j] > CountryTxPwr) - { - // decrease to zero and don't need to take care BBPR1 - if ((Value - (AdjustMaxTxPwr[i*8+j] - CountryTxPwr)) > 0) - Value -= (AdjustMaxTxPwr[i*8+j] - CountryTxPwr); - else - Value = 0; - - DBGPRINT_RAW(RT_DEBUG_TRACE,("AsicAdjustTxPower (i/j=%d/%d, Value=%d, %d)\n", i, j, Value, AdjustMaxTxPwr[i*8+j])); - } - else - DBGPRINT_RAW(RT_DEBUG_TRACE,("AsicAdjustTxPower (i/j=%d/%d, Value=%d, %d, no change)\n", i, j, Value, AdjustMaxTxPwr[i*8+j])); - - TxPwr[i] = (TxPwr[i] & ~(0x0000000F << j*4)) | (Value << j*4); - } - } - } - } while (FALSE); -#endif // SINGLE_SKU // - - /* calculate delta power based on the percentage specified from UI */ - // E2PROM setting is calibrated for maximum TX power (i.e. 100%) - // We lower TX power here according to the percentage specified from UI - if (pAd->CommonCfg.TxPowerPercentage == 0xffffffff) // AUTO TX POWER control - ; - else if (pAd->CommonCfg.TxPowerPercentage > 90) // 91 ~ 100% & AUTO, treat as 100% in terms of mW - ; - else if (pAd->CommonCfg.TxPowerPercentage > 60) // 61 ~ 90%, treat as 75% in terms of mW // DeltaPwr -= 1; - { - DeltaPwr -= 1; - } - else if (pAd->CommonCfg.TxPowerPercentage > 30) // 31 ~ 60%, treat as 50% in terms of mW // DeltaPwr -= 3; - { - DeltaPwr -= 3; - } - else if (pAd->CommonCfg.TxPowerPercentage > 15) // 16 ~ 30%, treat as 25% in terms of mW // DeltaPwr -= 6; - { - BbpR1 |= 0x01; - } - else if (pAd->CommonCfg.TxPowerPercentage > 9) // 10 ~ 15%, treat as 12.5% in terms of mW // DeltaPwr -= 9; - { - BbpR1 |= 0x01; - DeltaPwr -= 3; - } - else // 0 ~ 9 %, treat as MIN(~3%) in terms of mW // DeltaPwr -= 12; - { - BbpR1 |= 0x02; - } - - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R1, BbpR1); - - /* reset different new tx power for different TX rate */ - for(i=0; i<5; i++) - { - if (TxPwr[i] != 0xffffffff) - { - for (j=0; j<8; j++) - { - Value = (CHAR)((TxPwr[i] >> j*4) & 0x0F); /* 0 ~ 15 */ - - if ((Value + DeltaPwr) < 0) - { - Value = 0; /* min */ - } - else if ((Value + DeltaPwr) > 0xF) - { - Value = 0xF; /* max */ - } - else - { - Value += DeltaPwr; /* temperature compensation */ - } - - /* fill new value to CSR offset */ - TxPwr[i] = (TxPwr[i] & ~(0x0000000F << j*4)) | (Value << j*4); - } - - /* write tx power value to CSR */ - /* TX_PWR_CFG_0 (8 tx rate) for TX power for OFDM 12M/18M - TX power for OFDM 6M/9M - TX power for CCK5.5M/11M - TX power for CCK1M/2M */ - /* TX_PWR_CFG_1 ~ TX_PWR_CFG_4 */ - RTMP_IO_WRITE32(pAd, TX_PWR_CFG_0 + i*4, TxPwr[i]); - } - } - - -} - -#ifdef CONFIG_STA_SUPPORT -/* - ========================================================================== - Description: - put PHY to sleep here, and set next wakeup timer. PHY doesn't not wakeup - automatically. Instead, MCU will issue a TwakeUpInterrupt to host after - the wakeup timer timeout. Driver has to issue a separate command to wake - PHY up. - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID AsicSleepThenAutoWakeup( - IN PRTMP_ADAPTER pAd, - IN USHORT TbttNumToNextWakeUp) -{ - RT28XX_STA_SLEEP_THEN_AUTO_WAKEUP(pAd, TbttNumToNextWakeUp); -} - -/* - ========================================================================== - Description: - AsicForceWakeup() is used whenever manual wakeup is required - AsicForceSleep() should only be used when not in INFRA BSS. When - in INFRA BSS, we should use AsicSleepThenAutoWakeup() instead. - ========================================================================== - */ -VOID AsicForceSleep( - IN PRTMP_ADAPTER pAd) -{ - -} - -/* - ========================================================================== - Description: - AsicForceWakeup() is used whenever Twakeup timer (set via AsicSleepThenAutoWakeup) - expired. - - IRQL = PASSIVE_LEVEL - IRQL = DISPATCH_LEVEL - ========================================================================== - */ -VOID AsicForceWakeup( - IN PRTMP_ADAPTER pAd, - IN BOOLEAN bFromTx) -{ - DBGPRINT(RT_DEBUG_TRACE, ("--> AsicForceWakeup \n")); - RT28XX_STA_FORCE_WAKEUP(pAd, bFromTx); -} -#endif // CONFIG_STA_SUPPORT // -/* - ========================================================================== - Description: - Set My BSSID - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID AsicSetBssid( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pBssid) -{ - ULONG Addr4; - DBGPRINT(RT_DEBUG_TRACE, ("==============> AsicSetBssid %x:%x:%x:%x:%x:%x\n", - pBssid[0],pBssid[1],pBssid[2],pBssid[3], pBssid[4],pBssid[5])); - - Addr4 = (ULONG)(pBssid[0]) | - (ULONG)(pBssid[1] << 8) | - (ULONG)(pBssid[2] << 16) | - (ULONG)(pBssid[3] << 24); - RTMP_IO_WRITE32(pAd, MAC_BSSID_DW0, Addr4); - - Addr4 = 0; - // always one BSSID in STA mode - Addr4 = (ULONG)(pBssid[4]) | (ULONG)(pBssid[5] << 8); - - RTMP_IO_WRITE32(pAd, MAC_BSSID_DW1, Addr4); -} - -VOID AsicSetMcastWC( - IN PRTMP_ADAPTER pAd) -{ - MAC_TABLE_ENTRY *pEntry = &pAd->MacTab.Content[MCAST_WCID]; - USHORT offset; - - pEntry->Sst = SST_ASSOC; - pEntry->Aid = MCAST_WCID; // Softap supports 1 BSSID and use WCID=0 as multicast Wcid index - pEntry->PsMode = PWR_ACTIVE; - pEntry->CurrTxRate = pAd->CommonCfg.MlmeRate; - offset = MAC_WCID_BASE + BSS0Mcast_WCID * HW_WCID_ENTRY_SIZE; -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID AsicDelWcidTab( - IN PRTMP_ADAPTER pAd, - IN UCHAR Wcid) -{ - ULONG Addr0 = 0x0, Addr1 = 0x0; - ULONG offset; - - DBGPRINT(RT_DEBUG_TRACE, ("AsicDelWcidTab==>Wcid = 0x%x\n",Wcid)); - offset = MAC_WCID_BASE + Wcid * HW_WCID_ENTRY_SIZE; - RTMP_IO_WRITE32(pAd, offset, Addr0); - offset += 4; - RTMP_IO_WRITE32(pAd, offset, Addr1); -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID AsicEnableRDG( - IN PRTMP_ADAPTER pAd) -{ - TX_LINK_CFG_STRUC TxLinkCfg; - UINT32 Data = 0; - - RTMP_IO_READ32(pAd, TX_LINK_CFG, &TxLinkCfg.word); - TxLinkCfg.field.TxRDGEn = 1; - RTMP_IO_WRITE32(pAd, TX_LINK_CFG, TxLinkCfg.word); - - RTMP_IO_READ32(pAd, EDCA_AC0_CFG, &Data); - Data &= 0xFFFFFF00; - Data |= 0x80; - RTMP_IO_WRITE32(pAd, EDCA_AC0_CFG, Data); - - //OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED); -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID AsicDisableRDG( - IN PRTMP_ADAPTER pAd) -{ - TX_LINK_CFG_STRUC TxLinkCfg; - UINT32 Data = 0; - - - RTMP_IO_READ32(pAd, TX_LINK_CFG, &TxLinkCfg.word); - TxLinkCfg.field.TxRDGEn = 0; - RTMP_IO_WRITE32(pAd, TX_LINK_CFG, TxLinkCfg.word); - - RTMP_IO_READ32(pAd, EDCA_AC0_CFG, &Data); - - Data &= 0xFFFFFF00; - //Data |= 0x20; -#ifndef WIFI_TEST - //if ( pAd->CommonCfg.bEnableTxBurst ) - // Data |= 0x60; // for performance issue not set the TXOP to 0 -#endif - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_DYNAMIC_BE_TXOP_ACTIVE) -#ifdef DOT11_N_SUPPORT - && (pAd->MacTab.fAnyStationMIMOPSDynamic == FALSE) -#endif // DOT11_N_SUPPORT // - ) - { - // For CWC test, change txop from 0x30 to 0x20 in TxBurst mode - if (pAd->CommonCfg.bEnableTxBurst) - Data |= 0x20; - } - RTMP_IO_WRITE32(pAd, EDCA_AC0_CFG, Data); -} - -/* - ========================================================================== - Description: - - IRQL = PASSIVE_LEVEL - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID AsicDisableSync( - IN PRTMP_ADAPTER pAd) -{ - BCN_TIME_CFG_STRUC csr; - - DBGPRINT(RT_DEBUG_TRACE, ("--->Disable TSF synchronization\n")); - - // 2003-12-20 disable TSF and TBTT while NIC in power-saving have side effect - // that NIC will never wakes up because TSF stops and no more - // TBTT interrupts - pAd->TbttTickCount = 0; - RTMP_IO_READ32(pAd, BCN_TIME_CFG, &csr.word); - csr.field.bBeaconGen = 0; - csr.field.bTBTTEnable = 0; - csr.field.TsfSyncMode = 0; - csr.field.bTsfTicking = 0; - RTMP_IO_WRITE32(pAd, BCN_TIME_CFG, csr.word); - -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID AsicEnableBssSync( - IN PRTMP_ADAPTER pAd) -{ - BCN_TIME_CFG_STRUC csr; - - DBGPRINT(RT_DEBUG_TRACE, ("--->AsicEnableBssSync(INFRA mode)\n")); - - RTMP_IO_READ32(pAd, BCN_TIME_CFG, &csr.word); -// RTMP_IO_WRITE32(pAd, BCN_TIME_CFG, 0x00000000); -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - csr.field.BeaconInterval = pAd->CommonCfg.BeaconPeriod << 4; // ASIC register in units of 1/16 TU - csr.field.bTsfTicking = 1; - csr.field.TsfSyncMode = 1; // sync TSF in INFRASTRUCTURE mode - csr.field.bBeaconGen = 0; // do NOT generate BEACON - csr.field.bTBTTEnable = 1; - } -#endif // CONFIG_STA_SUPPORT // - RTMP_IO_WRITE32(pAd, BCN_TIME_CFG, csr.word); -} - -/* - ========================================================================== - Description: - Note: - BEACON frame in shared memory should be built ok before this routine - can be called. Otherwise, a garbage frame maybe transmitted out every - Beacon period. - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID AsicEnableIbssSync( - IN PRTMP_ADAPTER pAd) -{ - BCN_TIME_CFG_STRUC csr9; - PUCHAR ptr; - UINT i; - - DBGPRINT(RT_DEBUG_TRACE, ("--->AsicEnableIbssSync(ADHOC mode. MPDUtotalByteCount = %d)\n", pAd->BeaconTxWI.MPDUtotalByteCount)); - - RTMP_IO_READ32(pAd, BCN_TIME_CFG, &csr9.word); - csr9.field.bBeaconGen = 0; - csr9.field.bTBTTEnable = 0; - csr9.field.bTsfTicking = 0; - RTMP_IO_WRITE32(pAd, BCN_TIME_CFG, csr9.word); - - -#ifdef RT2870 - // move BEACON TXD and frame content to on-chip memory - ptr = (PUCHAR)&pAd->BeaconTxWI; - for (i=0; iBeaconBuf; - for (i=0; i< pAd->BeaconTxWI.MPDUtotalByteCount; i+=2) - { - //UINT32 longptr = *ptr + (*(ptr+1)<<8) + (*(ptr+2)<<16) + (*(ptr+3)<<24); - //RTMP_IO_WRITE32(pAd, HW_BEACON_BASE0 + TXWI_SIZE + i, longptr); - RTUSBMultiWrite(pAd, HW_BEACON_BASE0 + TXWI_SIZE + i, ptr, 2); - ptr +=2; - } -#endif // RT2870 // - - // - // For Wi-Fi faily generated beacons between participating stations. - // Set TBTT phase adaptive adjustment step to 8us (default 16us) - // don't change settings 2006-5- by Jerry - //RTMP_IO_WRITE32(pAd, TBTT_SYNC_CFG, 0x00001010); - - // start sending BEACON - csr9.field.BeaconInterval = pAd->CommonCfg.BeaconPeriod << 4; // ASIC register in units of 1/16 TU - csr9.field.bTsfTicking = 1; - csr9.field.TsfSyncMode = 2; // sync TSF in IBSS mode - csr9.field.bTBTTEnable = 1; - csr9.field.bBeaconGen = 1; - RTMP_IO_WRITE32(pAd, BCN_TIME_CFG, csr9.word); -} - -/* - ========================================================================== - Description: - - IRQL = PASSIVE_LEVEL - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID AsicSetEdcaParm( - IN PRTMP_ADAPTER pAd, - IN PEDCA_PARM pEdcaParm) -{ - EDCA_AC_CFG_STRUC Ac0Cfg, Ac1Cfg, Ac2Cfg, Ac3Cfg; - AC_TXOP_CSR0_STRUC csr0; - AC_TXOP_CSR1_STRUC csr1; - AIFSN_CSR_STRUC AifsnCsr; - CWMIN_CSR_STRUC CwminCsr; - CWMAX_CSR_STRUC CwmaxCsr; - int i; - - Ac0Cfg.word = 0; - Ac1Cfg.word = 0; - Ac2Cfg.word = 0; - Ac3Cfg.word = 0; - if ((pEdcaParm == NULL) || (pEdcaParm->bValid == FALSE)) - { - DBGPRINT(RT_DEBUG_TRACE,("AsicSetEdcaParm\n")); - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_WMM_INUSED); - for (i=0; iMacTab.Content[i].ValidAsCLI || pAd->MacTab.Content[i].ValidAsApCli) - CLIENT_STATUS_CLEAR_FLAG(&pAd->MacTab.Content[i], fCLIENT_STATUS_WMM_CAPABLE); - } - - //======================================================== - // MAC Register has a copy . - //======================================================== -//#ifndef WIFI_TEST - if( pAd->CommonCfg.bEnableTxBurst ) - { - // For CWC test, change txop from 0x30 to 0x20 in TxBurst mode - Ac0Cfg.field.AcTxop = 0x20; // Suggest by John for TxBurst in HT Mode - } - else - Ac0Cfg.field.AcTxop = 0; // QID_AC_BE -//#else -// Ac0Cfg.field.AcTxop = 0; // QID_AC_BE -//#endif - Ac0Cfg.field.Cwmin = CW_MIN_IN_BITS; - Ac0Cfg.field.Cwmax = CW_MAX_IN_BITS; - Ac0Cfg.field.Aifsn = 2; - RTMP_IO_WRITE32(pAd, EDCA_AC0_CFG, Ac0Cfg.word); - - Ac1Cfg.field.AcTxop = 0; // QID_AC_BK - Ac1Cfg.field.Cwmin = CW_MIN_IN_BITS; - Ac1Cfg.field.Cwmax = CW_MAX_IN_BITS; - Ac1Cfg.field.Aifsn = 2; - RTMP_IO_WRITE32(pAd, EDCA_AC1_CFG, Ac1Cfg.word); - - if (pAd->CommonCfg.PhyMode == PHY_11B) - { - Ac2Cfg.field.AcTxop = 192; // AC_VI: 192*32us ~= 6ms - Ac3Cfg.field.AcTxop = 96; // AC_VO: 96*32us ~= 3ms - } - else - { - Ac2Cfg.field.AcTxop = 96; // AC_VI: 96*32us ~= 3ms - Ac3Cfg.field.AcTxop = 48; // AC_VO: 48*32us ~= 1.5ms - } - Ac2Cfg.field.Cwmin = CW_MIN_IN_BITS; - Ac2Cfg.field.Cwmax = CW_MAX_IN_BITS; - Ac2Cfg.field.Aifsn = 2; - RTMP_IO_WRITE32(pAd, EDCA_AC2_CFG, Ac2Cfg.word); - Ac3Cfg.field.Cwmin = CW_MIN_IN_BITS; - Ac3Cfg.field.Cwmax = CW_MAX_IN_BITS; - Ac3Cfg.field.Aifsn = 2; - RTMP_IO_WRITE32(pAd, EDCA_AC3_CFG, Ac3Cfg.word); - - //======================================================== - // DMA Register has a copy too. - //======================================================== - csr0.field.Ac0Txop = 0; // QID_AC_BE - csr0.field.Ac1Txop = 0; // QID_AC_BK - RTMP_IO_WRITE32(pAd, WMM_TXOP0_CFG, csr0.word); - if (pAd->CommonCfg.PhyMode == PHY_11B) - { - csr1.field.Ac2Txop = 192; // AC_VI: 192*32us ~= 6ms - csr1.field.Ac3Txop = 96; // AC_VO: 96*32us ~= 3ms - } - else - { - csr1.field.Ac2Txop = 96; // AC_VI: 96*32us ~= 3ms - csr1.field.Ac3Txop = 48; // AC_VO: 48*32us ~= 1.5ms - } - RTMP_IO_WRITE32(pAd, WMM_TXOP1_CFG, csr1.word); - - CwminCsr.word = 0; - CwminCsr.field.Cwmin0 = CW_MIN_IN_BITS; - CwminCsr.field.Cwmin1 = CW_MIN_IN_BITS; - CwminCsr.field.Cwmin2 = CW_MIN_IN_BITS; - CwminCsr.field.Cwmin3 = CW_MIN_IN_BITS; - RTMP_IO_WRITE32(pAd, WMM_CWMIN_CFG, CwminCsr.word); - - CwmaxCsr.word = 0; - CwmaxCsr.field.Cwmax0 = CW_MAX_IN_BITS; - CwmaxCsr.field.Cwmax1 = CW_MAX_IN_BITS; - CwmaxCsr.field.Cwmax2 = CW_MAX_IN_BITS; - CwmaxCsr.field.Cwmax3 = CW_MAX_IN_BITS; - RTMP_IO_WRITE32(pAd, WMM_CWMAX_CFG, CwmaxCsr.word); - - RTMP_IO_WRITE32(pAd, WMM_AIFSN_CFG, 0x00002222); - - NdisZeroMemory(&pAd->CommonCfg.APEdcaParm, sizeof(EDCA_PARM)); - } - else - { - OPSTATUS_SET_FLAG(pAd, fOP_STATUS_WMM_INUSED); - //======================================================== - // MAC Register has a copy. - //======================================================== - // - // Modify Cwmin/Cwmax/Txop on queue[QID_AC_VI], Recommend by Jerry 2005/07/27 - // To degrade our VIDO Queue's throughput for WiFi WMM S3T07 Issue. - // - //pEdcaParm->Txop[QID_AC_VI] = pEdcaParm->Txop[QID_AC_VI] * 7 / 10; // rt2860c need this - - Ac0Cfg.field.AcTxop = pEdcaParm->Txop[QID_AC_BE]; - Ac0Cfg.field.Cwmin= pEdcaParm->Cwmin[QID_AC_BE]; - Ac0Cfg.field.Cwmax = pEdcaParm->Cwmax[QID_AC_BE]; - Ac0Cfg.field.Aifsn = pEdcaParm->Aifsn[QID_AC_BE]; //+1; - - Ac1Cfg.field.AcTxop = pEdcaParm->Txop[QID_AC_BK]; - Ac1Cfg.field.Cwmin = pEdcaParm->Cwmin[QID_AC_BK]; //+2; - Ac1Cfg.field.Cwmax = pEdcaParm->Cwmax[QID_AC_BK]; - Ac1Cfg.field.Aifsn = pEdcaParm->Aifsn[QID_AC_BK]; //+1; - - Ac2Cfg.field.AcTxop = (pEdcaParm->Txop[QID_AC_VI] * 6) / 10; - Ac2Cfg.field.Cwmin = pEdcaParm->Cwmin[QID_AC_VI]; - Ac2Cfg.field.Cwmax = pEdcaParm->Cwmax[QID_AC_VI]; - Ac2Cfg.field.Aifsn = pEdcaParm->Aifsn[QID_AC_VI]; -#ifdef INF_AMAZON_SE -#endif // INF_AMAZON_SE // - - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - // Tuning for Wi-Fi WMM S06 - if (pAd->CommonCfg.bWiFiTest && - pEdcaParm->Aifsn[QID_AC_VI] == 10) - Ac2Cfg.field.Aifsn -= 1; - - // Tuning for TGn Wi-Fi 5.2.32 - // STA TestBed changes in this item: conexant legacy sta ==> broadcom 11n sta - if (STA_TGN_WIFI_ON(pAd) && - pEdcaParm->Aifsn[QID_AC_VI] == 10) - { - Ac0Cfg.field.Aifsn = 3; - Ac2Cfg.field.AcTxop = 5; - } - -#ifdef RT30xx - if (pAd->RfIcType == RFIC_3020 || pAd->RfIcType == RFIC_2020) - { - // Tuning for WiFi WMM S3-T07: connexant legacy sta ==> broadcom 11n sta. - Ac2Cfg.field.Aifsn = 5; - } -#endif // RT30xx // - } -#endif // CONFIG_STA_SUPPORT // - - Ac3Cfg.field.AcTxop = pEdcaParm->Txop[QID_AC_VO]; - Ac3Cfg.field.Cwmin = pEdcaParm->Cwmin[QID_AC_VO]; - Ac3Cfg.field.Cwmax = pEdcaParm->Cwmax[QID_AC_VO]; - Ac3Cfg.field.Aifsn = pEdcaParm->Aifsn[QID_AC_VO]; - -//#ifdef WIFI_TEST - if (pAd->CommonCfg.bWiFiTest) - { - if (Ac3Cfg.field.AcTxop == 102) - { - Ac0Cfg.field.AcTxop = pEdcaParm->Txop[QID_AC_BE] ? pEdcaParm->Txop[QID_AC_BE] : 10; - Ac0Cfg.field.Aifsn = pEdcaParm->Aifsn[QID_AC_BE]-1; /* AIFSN must >= 1 */ - Ac1Cfg.field.AcTxop = pEdcaParm->Txop[QID_AC_BK]; - Ac1Cfg.field.Aifsn = pEdcaParm->Aifsn[QID_AC_BK]; - Ac2Cfg.field.AcTxop = pEdcaParm->Txop[QID_AC_VI]; - } /* End of if */ - } -//#endif // WIFI_TEST // - - RTMP_IO_WRITE32(pAd, EDCA_AC0_CFG, Ac0Cfg.word); - RTMP_IO_WRITE32(pAd, EDCA_AC1_CFG, Ac1Cfg.word); - RTMP_IO_WRITE32(pAd, EDCA_AC2_CFG, Ac2Cfg.word); - RTMP_IO_WRITE32(pAd, EDCA_AC3_CFG, Ac3Cfg.word); - - - //======================================================== - // DMA Register has a copy too. - //======================================================== - csr0.field.Ac0Txop = Ac0Cfg.field.AcTxop; - csr0.field.Ac1Txop = Ac1Cfg.field.AcTxop; - RTMP_IO_WRITE32(pAd, WMM_TXOP0_CFG, csr0.word); - - csr1.field.Ac2Txop = Ac2Cfg.field.AcTxop; - csr1.field.Ac3Txop = Ac3Cfg.field.AcTxop; - RTMP_IO_WRITE32(pAd, WMM_TXOP1_CFG, csr1.word); - - CwminCsr.word = 0; - CwminCsr.field.Cwmin0 = pEdcaParm->Cwmin[QID_AC_BE]; - CwminCsr.field.Cwmin1 = pEdcaParm->Cwmin[QID_AC_BK]; - CwminCsr.field.Cwmin2 = pEdcaParm->Cwmin[QID_AC_VI]; -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - CwminCsr.field.Cwmin3 = pEdcaParm->Cwmin[QID_AC_VO] - 1; //for TGn wifi test -#endif // CONFIG_STA_SUPPORT // - RTMP_IO_WRITE32(pAd, WMM_CWMIN_CFG, CwminCsr.word); - - CwmaxCsr.word = 0; - CwmaxCsr.field.Cwmax0 = pEdcaParm->Cwmax[QID_AC_BE]; - CwmaxCsr.field.Cwmax1 = pEdcaParm->Cwmax[QID_AC_BK]; - CwmaxCsr.field.Cwmax2 = pEdcaParm->Cwmax[QID_AC_VI]; - CwmaxCsr.field.Cwmax3 = pEdcaParm->Cwmax[QID_AC_VO]; - RTMP_IO_WRITE32(pAd, WMM_CWMAX_CFG, CwmaxCsr.word); - - AifsnCsr.word = 0; - AifsnCsr.field.Aifsn0 = Ac0Cfg.field.Aifsn; //pEdcaParm->Aifsn[QID_AC_BE]; - AifsnCsr.field.Aifsn1 = Ac1Cfg.field.Aifsn; //pEdcaParm->Aifsn[QID_AC_BK]; - AifsnCsr.field.Aifsn2 = Ac2Cfg.field.Aifsn; //pEdcaParm->Aifsn[QID_AC_VI]; -#ifdef INF_AMAZON_SE -#endif // INF_AMAZON_SE // - - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - // Tuning for Wi-Fi WMM S06 - if (pAd->CommonCfg.bWiFiTest && - pEdcaParm->Aifsn[QID_AC_VI] == 10) - AifsnCsr.field.Aifsn2 = Ac2Cfg.field.Aifsn - 4; - - // Tuning for TGn Wi-Fi 5.2.32 - // STA TestBed changes in this item: connexant legacy sta ==> broadcom 11n sta - if (STA_TGN_WIFI_ON(pAd) && - pEdcaParm->Aifsn[QID_AC_VI] == 10) - { - AifsnCsr.field.Aifsn0 = 3; - AifsnCsr.field.Aifsn2 = 7; - } - - if (INFRA_ON(pAd)) - CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[BSSID_WCID], fCLIENT_STATUS_WMM_CAPABLE); - } -#endif // CONFIG_STA_SUPPORT // - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - AifsnCsr.field.Aifsn3 = Ac3Cfg.field.Aifsn - 1; //pEdcaParm->Aifsn[QID_AC_VO]; //for TGn wifi test -#ifdef RT30xx - if (pAd->RfIcType == RFIC_3020 || pAd->RfIcType == RFIC_2020) - { - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - AifsnCsr.field.Aifsn2 = 0x2; //pEdcaParm->Aifsn[QID_AC_VI]; //for WiFi WMM S4-T04. - } -#endif // RT30xx // -#endif // CONFIG_STA_SUPPORT // - RTMP_IO_WRITE32(pAd, WMM_AIFSN_CFG, AifsnCsr.word); - - NdisMoveMemory(&pAd->CommonCfg.APEdcaParm, pEdcaParm, sizeof(EDCA_PARM)); - if (!ADHOC_ON(pAd)) - { - DBGPRINT(RT_DEBUG_TRACE,("EDCA [#%d]: AIFSN CWmin CWmax TXOP(us) ACM\n", pEdcaParm->EdcaUpdateCount)); - DBGPRINT(RT_DEBUG_TRACE,(" AC_BE %2d %2d %2d %4d %d\n", - pEdcaParm->Aifsn[0], - pEdcaParm->Cwmin[0], - pEdcaParm->Cwmax[0], - pEdcaParm->Txop[0]<<5, - pEdcaParm->bACM[0])); - DBGPRINT(RT_DEBUG_TRACE,(" AC_BK %2d %2d %2d %4d %d\n", - pEdcaParm->Aifsn[1], - pEdcaParm->Cwmin[1], - pEdcaParm->Cwmax[1], - pEdcaParm->Txop[1]<<5, - pEdcaParm->bACM[1])); - DBGPRINT(RT_DEBUG_TRACE,(" AC_VI %2d %2d %2d %4d %d\n", - pEdcaParm->Aifsn[2], - pEdcaParm->Cwmin[2], - pEdcaParm->Cwmax[2], - pEdcaParm->Txop[2]<<5, - pEdcaParm->bACM[2])); - DBGPRINT(RT_DEBUG_TRACE,(" AC_VO %2d %2d %2d %4d %d\n", - pEdcaParm->Aifsn[3], - pEdcaParm->Cwmin[3], - pEdcaParm->Cwmax[3], - pEdcaParm->Txop[3]<<5, - pEdcaParm->bACM[3])); - } - } -} - -/* - ========================================================================== - Description: - - IRQL = PASSIVE_LEVEL - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID AsicSetSlotTime( - IN PRTMP_ADAPTER pAd, - IN BOOLEAN bUseShortSlotTime) -{ - ULONG SlotTime; - UINT32 RegValue = 0; - -#ifdef CONFIG_STA_SUPPORT - if (pAd->CommonCfg.Channel > 14) - bUseShortSlotTime = TRUE; -#endif // CONFIG_STA_SUPPORT // - - if (bUseShortSlotTime) - OPSTATUS_SET_FLAG(pAd, fOP_STATUS_SHORT_SLOT_INUSED); - else - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SHORT_SLOT_INUSED); - - SlotTime = (bUseShortSlotTime)? 9 : 20; - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - // force using short SLOT time for FAE to demo performance when TxBurst is ON - if (pAd->CommonCfg.bEnableTxBurst) - SlotTime = 9; - } -#endif // CONFIG_STA_SUPPORT // - - // - // For some reasons, always set it to short slot time. - // - // ToDo: Should consider capability with 11B - // -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - if (pAd->StaCfg.BssType == BSS_ADHOC) - SlotTime = 20; - } -#endif // CONFIG_STA_SUPPORT // - - RTMP_IO_READ32(pAd, BKOFF_SLOT_CFG, &RegValue); - RegValue = RegValue & 0xFFFFFF00; - - RegValue |= SlotTime; - - RTMP_IO_WRITE32(pAd, BKOFF_SLOT_CFG, RegValue); -} - -/* - ======================================================================== - Description: - Add Shared key information into ASIC. - Update shared key, TxMic and RxMic to Asic Shared key table - Update its cipherAlg to Asic Shared key Mode. - - Return: - ======================================================================== -*/ -VOID AsicAddSharedKeyEntry( - IN PRTMP_ADAPTER pAd, - IN UCHAR BssIndex, - IN UCHAR KeyIdx, - IN UCHAR CipherAlg, - IN PUCHAR pKey, - IN PUCHAR pTxMic, - IN PUCHAR pRxMic) -{ - ULONG offset; //, csr0; - SHAREDKEY_MODE_STRUC csr1; - - DBGPRINT(RT_DEBUG_TRACE, ("AsicAddSharedKeyEntry BssIndex=%d, KeyIdx=%d\n", BssIndex,KeyIdx)); -//============================================================================================ - - DBGPRINT(RT_DEBUG_TRACE,("AsicAddSharedKeyEntry: %s key #%d\n", CipherName[CipherAlg], BssIndex*4 + KeyIdx)); - DBGPRINT_RAW(RT_DEBUG_TRACE, (" Key = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", - pKey[0],pKey[1],pKey[2],pKey[3],pKey[4],pKey[5],pKey[6],pKey[7],pKey[8],pKey[9],pKey[10],pKey[11],pKey[12],pKey[13],pKey[14],pKey[15])); - if (pRxMic) - { - DBGPRINT_RAW(RT_DEBUG_TRACE, (" Rx MIC Key = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", - pRxMic[0],pRxMic[1],pRxMic[2],pRxMic[3],pRxMic[4],pRxMic[5],pRxMic[6],pRxMic[7])); - } - if (pTxMic) - { - DBGPRINT_RAW(RT_DEBUG_TRACE, (" Tx MIC Key = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", - pTxMic[0],pTxMic[1],pTxMic[2],pTxMic[3],pTxMic[4],pTxMic[5],pTxMic[6],pTxMic[7])); - } -//============================================================================================ - // - // fill key material - key + TX MIC + RX MIC - // - -#ifdef RT2870 -{ - offset = SHARED_KEY_TABLE_BASE + (4*BssIndex + KeyIdx)*HW_KEY_ENTRY_SIZE; - RTUSBMultiWrite(pAd, offset, pKey, MAX_LEN_OF_SHARE_KEY); - - offset += MAX_LEN_OF_SHARE_KEY; - if (pTxMic) - { - RTUSBMultiWrite(pAd, offset, pTxMic, 8); - } - - offset += 8; - if (pRxMic) - { - RTUSBMultiWrite(pAd, offset, pRxMic, 8); - } -} -#endif // RT2870 // - - // - // Update cipher algorithm. WSTA always use BSS0 - // - RTMP_IO_READ32(pAd, SHARED_KEY_MODE_BASE+4*(BssIndex/2), &csr1.word); - DBGPRINT(RT_DEBUG_TRACE,("Read: SHARED_KEY_MODE_BASE at this Bss[%d] KeyIdx[%d]= 0x%x \n", BssIndex,KeyIdx, csr1.word)); - if ((BssIndex%2) == 0) - { - if (KeyIdx == 0) - csr1.field.Bss0Key0CipherAlg = CipherAlg; - else if (KeyIdx == 1) - csr1.field.Bss0Key1CipherAlg = CipherAlg; - else if (KeyIdx == 2) - csr1.field.Bss0Key2CipherAlg = CipherAlg; - else - csr1.field.Bss0Key3CipherAlg = CipherAlg; - } - else - { - if (KeyIdx == 0) - csr1.field.Bss1Key0CipherAlg = CipherAlg; - else if (KeyIdx == 1) - csr1.field.Bss1Key1CipherAlg = CipherAlg; - else if (KeyIdx == 2) - csr1.field.Bss1Key2CipherAlg = CipherAlg; - else - csr1.field.Bss1Key3CipherAlg = CipherAlg; - } - DBGPRINT(RT_DEBUG_TRACE,("Write: SHARED_KEY_MODE_BASE at this Bss[%d] = 0x%x \n", BssIndex, csr1.word)); - RTMP_IO_WRITE32(pAd, SHARED_KEY_MODE_BASE+4*(BssIndex/2), csr1.word); - -} - -// IRQL = DISPATCH_LEVEL -VOID AsicRemoveSharedKeyEntry( - IN PRTMP_ADAPTER pAd, - IN UCHAR BssIndex, - IN UCHAR KeyIdx) -{ - //ULONG SecCsr0; - SHAREDKEY_MODE_STRUC csr1; - - DBGPRINT(RT_DEBUG_TRACE,("AsicRemoveSharedKeyEntry: #%d \n", BssIndex*4 + KeyIdx)); - - RTMP_IO_READ32(pAd, SHARED_KEY_MODE_BASE+4*(BssIndex/2), &csr1.word); - if ((BssIndex%2) == 0) - { - if (KeyIdx == 0) - csr1.field.Bss0Key0CipherAlg = 0; - else if (KeyIdx == 1) - csr1.field.Bss0Key1CipherAlg = 0; - else if (KeyIdx == 2) - csr1.field.Bss0Key2CipherAlg = 0; - else - csr1.field.Bss0Key3CipherAlg = 0; - } - else - { - if (KeyIdx == 0) - csr1.field.Bss1Key0CipherAlg = 0; - else if (KeyIdx == 1) - csr1.field.Bss1Key1CipherAlg = 0; - else if (KeyIdx == 2) - csr1.field.Bss1Key2CipherAlg = 0; - else - csr1.field.Bss1Key3CipherAlg = 0; - } - DBGPRINT(RT_DEBUG_TRACE,("Write: SHARED_KEY_MODE_BASE at this Bss[%d] = 0x%x \n", BssIndex, csr1.word)); - RTMP_IO_WRITE32(pAd, SHARED_KEY_MODE_BASE+4*(BssIndex/2), csr1.word); - ASSERT(BssIndex < 4); - ASSERT(KeyIdx < 4); - -} - - -VOID AsicUpdateWCIDAttribute( - IN PRTMP_ADAPTER pAd, - IN USHORT WCID, - IN UCHAR BssIndex, - IN UCHAR CipherAlg, - IN BOOLEAN bUsePairewiseKeyTable) -{ - ULONG WCIDAttri = 0, offset; - - // - // Update WCID attribute. - // Only TxKey could update WCID attribute. - // - offset = MAC_WCID_ATTRIBUTE_BASE + (WCID * HW_WCID_ATTRI_SIZE); - WCIDAttri = (BssIndex << 4) | (CipherAlg << 1) | (bUsePairewiseKeyTable); - RTMP_IO_WRITE32(pAd, offset, WCIDAttri); -} - -VOID AsicUpdateWCIDIVEIV( - IN PRTMP_ADAPTER pAd, - IN USHORT WCID, - IN ULONG uIV, - IN ULONG uEIV) -{ - ULONG offset; - - offset = MAC_IVEIV_TABLE_BASE + (WCID * HW_IVEIV_ENTRY_SIZE); - - RTMP_IO_WRITE32(pAd, offset, uIV); - RTMP_IO_WRITE32(pAd, offset + 4, uEIV); -} - -VOID AsicUpdateRxWCIDTable( - IN PRTMP_ADAPTER pAd, - IN USHORT WCID, - IN PUCHAR pAddr) -{ - ULONG offset; - ULONG Addr; - - offset = MAC_WCID_BASE + (WCID * HW_WCID_ENTRY_SIZE); - Addr = pAddr[0] + (pAddr[1] << 8) +(pAddr[2] << 16) +(pAddr[3] << 24); - RTMP_IO_WRITE32(pAd, offset, Addr); - Addr = pAddr[4] + (pAddr[5] << 8); - RTMP_IO_WRITE32(pAd, offset + 4, Addr); -} - - -/* - ======================================================================== - - Routine Description: - Set Cipher Key, Cipher algorithm, IV/EIV to Asic - - Arguments: - pAd Pointer to our adapter - WCID WCID Entry number. - BssIndex BSSID index, station or none multiple BSSID support - this value should be 0. - KeyIdx This KeyIdx will set to IV's KeyID if bTxKey enabled - pCipherKey Pointer to Cipher Key. - bUsePairewiseKeyTable TRUE means saved the key in SharedKey table, - otherwise PairewiseKey table - bTxKey This is the transmit key if enabled. - - Return Value: - None - - Note: - This routine will set the relative key stuff to Asic including WCID attribute, - Cipher Key, Cipher algorithm and IV/EIV. - - IV/EIV will be update if this CipherKey is the transmission key because - ASIC will base on IV's KeyID value to select Cipher Key. - - If bTxKey sets to FALSE, this is not the TX key, but it could be - RX key - - For AP mode bTxKey must be always set to TRUE. - ======================================================================== -*/ -VOID AsicAddKeyEntry( - IN PRTMP_ADAPTER pAd, - IN USHORT WCID, - IN UCHAR BssIndex, - IN UCHAR KeyIdx, - IN PCIPHER_KEY pCipherKey, - IN BOOLEAN bUsePairewiseKeyTable, - IN BOOLEAN bTxKey) -{ - ULONG offset; -// ULONG WCIDAttri = 0; - UCHAR IV4 = 0; - PUCHAR pKey = pCipherKey->Key; -// ULONG KeyLen = pCipherKey->KeyLen; - PUCHAR pTxMic = pCipherKey->TxMic; - PUCHAR pRxMic = pCipherKey->RxMic; - PUCHAR pTxtsc = pCipherKey->TxTsc; - UCHAR CipherAlg = pCipherKey->CipherAlg; - SHAREDKEY_MODE_STRUC csr1; - -// ASSERT(KeyLen <= MAX_LEN_OF_PEER_KEY); - - DBGPRINT(RT_DEBUG_TRACE, ("==> AsicAddKeyEntry\n")); - // - // 1.) decide key table offset - // - if (bUsePairewiseKeyTable) - offset = PAIRWISE_KEY_TABLE_BASE + (WCID * HW_KEY_ENTRY_SIZE); - else - offset = SHARED_KEY_TABLE_BASE + (4 * BssIndex + KeyIdx) * HW_KEY_ENTRY_SIZE; - - // - // 2.) Set Key to Asic - // - //for (i = 0; i < KeyLen; i++) - -#ifdef RT2870 - RTUSBMultiWrite(pAd, offset, pKey, MAX_LEN_OF_PEER_KEY); - offset += MAX_LEN_OF_PEER_KEY; - - // - // 3.) Set MIC key if available - // - if (pTxMic) - { - RTUSBMultiWrite(pAd, offset, pTxMic, 8); - } - offset += LEN_TKIP_TXMICK; - - if (pRxMic) - { - RTUSBMultiWrite(pAd, offset, pRxMic, 8); - } -#endif // RT2870 // - - // - // 4.) Modify IV/EIV if needs - // This will force Asic to use this key ID by setting IV. - // - if (bTxKey) - { - -#ifdef RT2870 - UINT32 tmpVal; - - // - // Write IV - // - IV4 = (KeyIdx << 6); - if ((CipherAlg == CIPHER_TKIP) || (CipherAlg == CIPHER_TKIP_NO_MIC) ||(CipherAlg == CIPHER_AES)) - IV4 |= 0x20; // turn on extension bit means EIV existence - - tmpVal = pTxtsc[1] + (((pTxtsc[1] | 0x20) & 0x7f) << 8) + (pTxtsc[0] << 16) + (IV4 << 24); - RTMP_IO_WRITE32(pAd, offset, tmpVal); - - // - // Write EIV - // - offset += 4; - RTMP_IO_WRITE32(pAd, offset, *(PUINT32)&pCipherKey->TxTsc[2]); -#endif // RT2870 // - AsicUpdateWCIDAttribute(pAd, WCID, BssIndex, CipherAlg, bUsePairewiseKeyTable); - } - - if (!bUsePairewiseKeyTable) - { - // - // Only update the shared key security mode - // - RTMP_IO_READ32(pAd, SHARED_KEY_MODE_BASE + 4 * (BssIndex / 2), &csr1.word); - if ((BssIndex % 2) == 0) - { - if (KeyIdx == 0) - csr1.field.Bss0Key0CipherAlg = CipherAlg; - else if (KeyIdx == 1) - csr1.field.Bss0Key1CipherAlg = CipherAlg; - else if (KeyIdx == 2) - csr1.field.Bss0Key2CipherAlg = CipherAlg; - else - csr1.field.Bss0Key3CipherAlg = CipherAlg; - } - else - { - if (KeyIdx == 0) - csr1.field.Bss1Key0CipherAlg = CipherAlg; - else if (KeyIdx == 1) - csr1.field.Bss1Key1CipherAlg = CipherAlg; - else if (KeyIdx == 2) - csr1.field.Bss1Key2CipherAlg = CipherAlg; - else - csr1.field.Bss1Key3CipherAlg = CipherAlg; - } - RTMP_IO_WRITE32(pAd, SHARED_KEY_MODE_BASE + 4 * (BssIndex / 2), csr1.word); - } - - DBGPRINT(RT_DEBUG_TRACE, ("<== AsicAddKeyEntry\n")); -} - - -/* - ======================================================================== - Description: - Add Pair-wise key material into ASIC. - Update pairwise key, TxMic and RxMic to Asic Pair-wise key table - - Return: - ======================================================================== -*/ -VOID AsicAddPairwiseKeyEntry( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pAddr, - IN UCHAR WCID, - IN CIPHER_KEY *pCipherKey) -{ - INT i; - ULONG offset; - PUCHAR pKey = pCipherKey->Key; - PUCHAR pTxMic = pCipherKey->TxMic; - PUCHAR pRxMic = pCipherKey->RxMic; -#ifdef DBG - UCHAR CipherAlg = pCipherKey->CipherAlg; -#endif // DBG // - - // EKEY - offset = PAIRWISE_KEY_TABLE_BASE + (WCID * HW_KEY_ENTRY_SIZE); -#ifdef RT2870 - RTUSBMultiWrite(pAd, offset, &pCipherKey->Key[0], MAX_LEN_OF_PEER_KEY); -#endif // RT2870 // - for (i=0; iTxMic[0], 8); -#endif // RT2870 // - } - offset += 8; - if (pRxMic) - { -#ifdef RT2870 - RTUSBMultiWrite(pAd, offset, &pCipherKey->RxMic[0], 8); -#endif // RT2870 // - } - - DBGPRINT(RT_DEBUG_TRACE,("AsicAddPairwiseKeyEntry: WCID #%d Alg=%s\n",WCID, CipherName[CipherAlg])); - DBGPRINT(RT_DEBUG_TRACE,(" Key = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", - pKey[0],pKey[1],pKey[2],pKey[3],pKey[4],pKey[5],pKey[6],pKey[7],pKey[8],pKey[9],pKey[10],pKey[11],pKey[12],pKey[13],pKey[14],pKey[15])); - if (pRxMic) - { - DBGPRINT(RT_DEBUG_TRACE, (" Rx MIC Key = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", - pRxMic[0],pRxMic[1],pRxMic[2],pRxMic[3],pRxMic[4],pRxMic[5],pRxMic[6],pRxMic[7])); - } - if (pTxMic) - { - DBGPRINT(RT_DEBUG_TRACE, (" Tx MIC Key = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", - pTxMic[0],pTxMic[1],pTxMic[2],pTxMic[3],pTxMic[4],pTxMic[5],pTxMic[6],pTxMic[7])); - } -} -/* - ======================================================================== - Description: - Remove Pair-wise key material from ASIC. - - Return: - ======================================================================== -*/ -VOID AsicRemovePairwiseKeyEntry( - IN PRTMP_ADAPTER pAd, - IN UCHAR BssIdx, - IN UCHAR Wcid) -{ - ULONG WCIDAttri; - USHORT offset; - - // re-set the entry's WCID attribute as OPEN-NONE. - offset = MAC_WCID_ATTRIBUTE_BASE + (Wcid * HW_WCID_ATTRI_SIZE); - WCIDAttri = (BssIdx<<4) | PAIRWISEKEYTABLE; - RTMP_IO_WRITE32(pAd, offset, WCIDAttri); -} - -BOOLEAN AsicSendCommandToMcu( - IN PRTMP_ADAPTER pAd, - IN UCHAR Command, - IN UCHAR Token, - IN UCHAR Arg0, - IN UCHAR Arg1) -{ - HOST_CMD_CSR_STRUC H2MCmd; - H2M_MAILBOX_STRUC H2MMailbox; - ULONG i = 0; - do - { - RTMP_IO_READ32(pAd, H2M_MAILBOX_CSR, &H2MMailbox.word); - if (H2MMailbox.field.Owner == 0) - break; - - RTMPusecDelay(2); - } while(i++ < 100); - - if (i >= 100) - { - { - DBGPRINT_ERR(("H2M_MAILBOX still hold by MCU. command fail\n")); - } - return FALSE; - } - - - H2MMailbox.field.Owner = 1; // pass ownership to MCU - H2MMailbox.field.CmdToken = Token; - H2MMailbox.field.HighByte = Arg1; - H2MMailbox.field.LowByte = Arg0; - RTMP_IO_WRITE32(pAd, H2M_MAILBOX_CSR, H2MMailbox.word); - - H2MCmd.word = 0; - H2MCmd.field.HostCommand = Command; - RTMP_IO_WRITE32(pAd, HOST_CMD_CSR, H2MCmd.word); - - if (Command != 0x80) - { - } - - return TRUE; -} - - -/* - ======================================================================== - - Routine Description: - Verify the support rate for different PHY type - - Arguments: - pAd Pointer to our adapter - - Return Value: - None - - IRQL = PASSIVE_LEVEL - - ======================================================================== -*/ -VOID RTMPCheckRates( - IN PRTMP_ADAPTER pAd, - IN OUT UCHAR SupRate[], - IN OUT UCHAR *SupRateLen) -{ - UCHAR RateIdx, i, j; - UCHAR NewRate[12], NewRateLen; - - NewRateLen = 0; - - if (pAd->CommonCfg.PhyMode == PHY_11B) - RateIdx = 4; - else - RateIdx = 12; - - // Check for support rates exclude basic rate bit - for (i = 0; i < *SupRateLen; i++) - for (j = 0; j < RateIdx; j++) - if ((SupRate[i] & 0x7f) == RateIdTo500Kbps[j]) - NewRate[NewRateLen++] = SupRate[i]; - - *SupRateLen = NewRateLen; - NdisMoveMemory(SupRate, NewRate, NewRateLen); -} - -#ifdef CONFIG_STA_SUPPORT -#ifdef DOT11_N_SUPPORT -BOOLEAN RTMPCheckChannel( - IN PRTMP_ADAPTER pAd, - IN UCHAR CentralChannel, - IN UCHAR Channel) -{ - UCHAR k; - UCHAR UpperChannel = 0, LowerChannel = 0; - UCHAR NoEffectChannelinList = 0; - - // Find upper and lower channel according to 40MHz current operation. - if (CentralChannel < Channel) - { - UpperChannel = Channel; - if (CentralChannel > 2) - LowerChannel = CentralChannel - 2; - else - return FALSE; - } - else if (CentralChannel > Channel) - { - UpperChannel = CentralChannel + 2; - LowerChannel = Channel; - } - - for (k = 0;k < pAd->ChannelListNum;k++) - { - if (pAd->ChannelList[k].Channel == UpperChannel) - { - NoEffectChannelinList ++; - } - if (pAd->ChannelList[k].Channel == LowerChannel) - { - NoEffectChannelinList ++; - } - } - - DBGPRINT(RT_DEBUG_TRACE,("Total Channel in Channel List = [%d]\n", NoEffectChannelinList)); - if (NoEffectChannelinList == 2) - return TRUE; - else - return FALSE; -} - -/* - ======================================================================== - - Routine Description: - Verify the support rate for HT phy type - - Arguments: - pAd Pointer to our adapter - - Return Value: - FALSE if pAd->CommonCfg.SupportedHtPhy doesn't accept the pHtCapability. (AP Mode) - - IRQL = PASSIVE_LEVEL - - ======================================================================== -*/ -BOOLEAN RTMPCheckHt( - IN PRTMP_ADAPTER pAd, - IN UCHAR Wcid, - IN HT_CAPABILITY_IE *pHtCapability, - IN ADD_HT_INFO_IE *pAddHtInfo) -{ - if (Wcid >= MAX_LEN_OF_MAC_TABLE) - return FALSE; - - // If use AMSDU, set flag. - if (pAd->CommonCfg.DesiredHtPhy.AmsduEnable) - CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid], fCLIENT_STATUS_AMSDU_INUSED); - // Save Peer Capability - if (pHtCapability->HtCapInfo.ShortGIfor20) - CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid], fCLIENT_STATUS_SGI20_CAPABLE); - if (pHtCapability->HtCapInfo.ShortGIfor40) - CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid], fCLIENT_STATUS_SGI40_CAPABLE); - if (pHtCapability->HtCapInfo.TxSTBC) - CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid], fCLIENT_STATUS_TxSTBC_CAPABLE); - if (pHtCapability->HtCapInfo.RxSTBC) - CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid], fCLIENT_STATUS_RxSTBC_CAPABLE); - if (pAd->CommonCfg.bRdg && pHtCapability->ExtHtCapInfo.RDGSupport) - { - CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid], fCLIENT_STATUS_RDG_CAPABLE); - } - - if (Wcid < MAX_LEN_OF_MAC_TABLE) - { - pAd->MacTab.Content[Wcid].MpduDensity = pHtCapability->HtCapParm.MpduDensity; - } - - // Will check ChannelWidth for MCSSet[4] below - pAd->MlmeAux.HtCapability.MCSSet[4] = 0x1; - switch (pAd->CommonCfg.RxStream) - { - case 1: - pAd->MlmeAux.HtCapability.MCSSet[0] = 0xff; - pAd->MlmeAux.HtCapability.MCSSet[1] = 0x00; - pAd->MlmeAux.HtCapability.MCSSet[2] = 0x00; - pAd->MlmeAux.HtCapability.MCSSet[3] = 0x00; - break; - case 2: - pAd->MlmeAux.HtCapability.MCSSet[0] = 0xff; - pAd->MlmeAux.HtCapability.MCSSet[1] = 0xff; - pAd->MlmeAux.HtCapability.MCSSet[2] = 0x00; - pAd->MlmeAux.HtCapability.MCSSet[3] = 0x00; - break; - case 3: - pAd->MlmeAux.HtCapability.MCSSet[0] = 0xff; - pAd->MlmeAux.HtCapability.MCSSet[1] = 0xff; - pAd->MlmeAux.HtCapability.MCSSet[2] = 0xff; - pAd->MlmeAux.HtCapability.MCSSet[3] = 0x00; - break; - } - - pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth = pAddHtInfo->AddHtInfo.RecomWidth & pAd->CommonCfg.DesiredHtPhy.ChannelWidth; - - DBGPRINT(RT_DEBUG_TRACE, ("RTMPCheckHt:: HtCapInfo.ChannelWidth=%d, RecomWidth=%d, DesiredHtPhy.ChannelWidth=%d, BW40MAvailForA/G=%d/%d, PhyMode=%d \n", - pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth, pAddHtInfo->AddHtInfo.RecomWidth, pAd->CommonCfg.DesiredHtPhy.ChannelWidth, - pAd->NicConfig2.field.BW40MAvailForA, pAd->NicConfig2.field.BW40MAvailForG, pAd->CommonCfg.PhyMode)); - - pAd->MlmeAux.HtCapability.HtCapInfo.GF = pHtCapability->HtCapInfo.GF &pAd->CommonCfg.DesiredHtPhy.GF; - - // Send Assoc Req with my HT capability. - pAd->MlmeAux.HtCapability.HtCapInfo.AMsduSize = pAd->CommonCfg.DesiredHtPhy.AmsduSize; - pAd->MlmeAux.HtCapability.HtCapInfo.MimoPs = pAd->CommonCfg.DesiredHtPhy.MimoPs; - pAd->MlmeAux.HtCapability.HtCapInfo.ShortGIfor20 = (pAd->CommonCfg.DesiredHtPhy.ShortGIfor20) & (pHtCapability->HtCapInfo.ShortGIfor20); - pAd->MlmeAux.HtCapability.HtCapInfo.ShortGIfor40 = (pAd->CommonCfg.DesiredHtPhy.ShortGIfor40) & (pHtCapability->HtCapInfo.ShortGIfor40); - pAd->MlmeAux.HtCapability.HtCapInfo.TxSTBC = (pAd->CommonCfg.DesiredHtPhy.TxSTBC)&(pHtCapability->HtCapInfo.RxSTBC); - pAd->MlmeAux.HtCapability.HtCapInfo.RxSTBC = (pAd->CommonCfg.DesiredHtPhy.RxSTBC)&(pHtCapability->HtCapInfo.TxSTBC); - pAd->MlmeAux.HtCapability.HtCapParm.MaxRAmpduFactor = pAd->CommonCfg.DesiredHtPhy.MaxRAmpduFactor; - pAd->MlmeAux.HtCapability.HtCapParm.MpduDensity = pAd->CommonCfg.HtCapability.HtCapParm.MpduDensity; - pAd->MlmeAux.HtCapability.ExtHtCapInfo.PlusHTC = pHtCapability->ExtHtCapInfo.PlusHTC; - pAd->MacTab.Content[Wcid].HTCapability.ExtHtCapInfo.PlusHTC = pHtCapability->ExtHtCapInfo.PlusHTC; - if (pAd->CommonCfg.bRdg) - { - pAd->MlmeAux.HtCapability.ExtHtCapInfo.RDGSupport = pHtCapability->ExtHtCapInfo.RDGSupport; - pAd->MlmeAux.HtCapability.ExtHtCapInfo.PlusHTC = 1; - } - - if (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_20) - pAd->MlmeAux.HtCapability.MCSSet[4] = 0x0; // BW20 can't transmit MCS32 - - COPY_AP_HTSETTINGS_FROM_BEACON(pAd, pHtCapability); - return TRUE; -} -#endif // DOT11_N_SUPPORT // -#endif // CONFIG_STA_SUPPORT // - -/* - ======================================================================== - - Routine Description: - Verify the support rate for different PHY type - - Arguments: - pAd Pointer to our adapter - - Return Value: - None - - IRQL = PASSIVE_LEVEL - - ======================================================================== -*/ -VOID RTMPUpdateMlmeRate( - IN PRTMP_ADAPTER pAd) -{ - UCHAR MinimumRate; - UCHAR ProperMlmeRate; //= RATE_54; - UCHAR i, j, RateIdx = 12; //1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54 - BOOLEAN bMatch = FALSE; - - switch (pAd->CommonCfg.PhyMode) - { - case PHY_11B: - ProperMlmeRate = RATE_11; - MinimumRate = RATE_1; - break; - case PHY_11BG_MIXED: -#ifdef DOT11_N_SUPPORT - case PHY_11ABGN_MIXED: - case PHY_11BGN_MIXED: -#endif // DOT11_N_SUPPORT // - if ((pAd->MlmeAux.SupRateLen == 4) && - (pAd->MlmeAux.ExtRateLen == 0)) - // B only AP - ProperMlmeRate = RATE_11; - else - ProperMlmeRate = RATE_24; - - if (pAd->MlmeAux.Channel <= 14) - MinimumRate = RATE_1; - else - MinimumRate = RATE_6; - break; - case PHY_11A: -#ifdef DOT11_N_SUPPORT - case PHY_11N_2_4G: // rt2860 need to check mlmerate for 802.11n - case PHY_11GN_MIXED: - case PHY_11AGN_MIXED: - case PHY_11AN_MIXED: - case PHY_11N_5G: -#endif // DOT11_N_SUPPORT // - ProperMlmeRate = RATE_24; - MinimumRate = RATE_6; - break; - case PHY_11ABG_MIXED: - ProperMlmeRate = RATE_24; - if (pAd->MlmeAux.Channel <= 14) - MinimumRate = RATE_1; - else - MinimumRate = RATE_6; - break; - default: // error - ProperMlmeRate = RATE_1; - MinimumRate = RATE_1; - break; - } - - for (i = 0; i < pAd->MlmeAux.SupRateLen; i++) - { - for (j = 0; j < RateIdx; j++) - { - if ((pAd->MlmeAux.SupRate[i] & 0x7f) == RateIdTo500Kbps[j]) - { - if (j == ProperMlmeRate) - { - bMatch = TRUE; - break; - } - } - } - - if (bMatch) - break; - } - - if (bMatch == FALSE) - { - for (i = 0; i < pAd->MlmeAux.ExtRateLen; i++) - { - for (j = 0; j < RateIdx; j++) - { - if ((pAd->MlmeAux.ExtRate[i] & 0x7f) == RateIdTo500Kbps[j]) - { - if (j == ProperMlmeRate) - { - bMatch = TRUE; - break; - } - } - } - - if (bMatch) - break; - } - } - - if (bMatch == FALSE) - { - ProperMlmeRate = MinimumRate; - } - - pAd->CommonCfg.MlmeRate = MinimumRate; - pAd->CommonCfg.RtsRate = ProperMlmeRate; - if (pAd->CommonCfg.MlmeRate >= RATE_6) - { - pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM; - pAd->CommonCfg.MlmeTransmit.field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate]; - pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MODE = MODE_OFDM; - pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate]; - } - else - { - pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_CCK; - pAd->CommonCfg.MlmeTransmit.field.MCS = pAd->CommonCfg.MlmeRate; - pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MODE = MODE_CCK; - pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MCS = pAd->CommonCfg.MlmeRate; - } - - DBGPRINT(RT_DEBUG_TRACE, ("RTMPUpdateMlmeRate ==> MlmeTransmit = 0x%x \n" , pAd->CommonCfg.MlmeTransmit.word)); -} - -CHAR RTMPMaxRssi( - IN PRTMP_ADAPTER pAd, - IN CHAR Rssi0, - IN CHAR Rssi1, - IN CHAR Rssi2) -{ - CHAR larger = -127; - - if ((pAd->Antenna.field.RxPath == 1) && (Rssi0 != 0)) - { - larger = Rssi0; - } - - if ((pAd->Antenna.field.RxPath >= 2) && (Rssi1 != 0)) - { - larger = max(Rssi0, Rssi1); - } - - if ((pAd->Antenna.field.RxPath == 3) && (Rssi2 != 0)) - { - larger = max(larger, Rssi2); - } - - if (larger == -127) - larger = 0; - - return larger; -} - - -// Antenna divesity use GPIO3 and EESK pin for control -// Antenna and EEPROM access are both using EESK pin, -// Therefor we should avoid accessing EESK at the same time -// Then restore antenna after EEPROM access -VOID AsicSetRxAnt( - IN PRTMP_ADAPTER pAd, - IN UCHAR Ant) -{ -#ifdef RT30xx - UINT32 Value; - UINT32 x; - - if ((pAd->EepromAccess) || - (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS)) || - (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) || - (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF)) || - (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))) - { - return; - } - - // the antenna selection is through firmware and MAC register(GPIO3) - if (Ant == 0) - { - // Main antenna - RTMP_IO_READ32(pAd, E2PROM_CSR, &x); - x |= (EESK); - RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); - - RTMP_IO_READ32(pAd, GPIO_CTRL_CFG, &Value); - Value &= ~(0x0808); - RTMP_IO_WRITE32(pAd, GPIO_CTRL_CFG, Value); - DBGPRINT_RAW(RT_DEBUG_TRACE, ("AsicSetRxAnt, switch to main antenna\n")); - } - else - { - // Aux antenna - RTMP_IO_READ32(pAd, E2PROM_CSR, &x); - x &= ~(EESK); - RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); - - RTMP_IO_READ32(pAd, GPIO_CTRL_CFG, &Value); - Value &= ~(0x0808); - Value |= 0x08; - RTMP_IO_WRITE32(pAd, GPIO_CTRL_CFG, Value); - DBGPRINT_RAW(RT_DEBUG_TRACE, ("AsicSetRxAnt, switch to aux antenna\n")); - } -#endif // RT30xx // -} - - -/* - ======================================================================== - Routine Description: - Periodic evaluate antenna link status - - Arguments: - pAd - Adapter pointer - - Return Value: - None - - ======================================================================== -*/ -VOID AsicEvaluateRxAnt( - IN PRTMP_ADAPTER pAd) -{ - UCHAR BBPR3 = 0; - -#ifdef RALINK_ATE - if (ATE_ON(pAd)) - return; -#endif // RALINK_ATE // - - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS | - fRTMP_ADAPTER_HALT_IN_PROGRESS | - fRTMP_ADAPTER_RADIO_OFF | - fRTMP_ADAPTER_NIC_NOT_EXIST | - fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS) || - OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE) -#ifdef RT30xx - || (pAd->EepromAccess) -#endif // RT30xx // - ) - return; - - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - //if (pAd->StaCfg.Psm == PWR_SAVE) - // return; - } -#endif // CONFIG_STA_SUPPORT // - - // two antenna selection mechanism- one is antenna diversity, the other is failed antenna remove - // one is antenna diversity:there is only one antenna can rx and tx - // the other is failed antenna remove:two physical antenna can rx and tx - if (pAd->NicConfig2.field.AntDiversity) - { - DBGPRINT(RT_DEBUG_TRACE,("AntDiv - before evaluate Pair1-Ant (%d,%d)\n", - pAd->RxAnt.Pair1PrimaryRxAnt, pAd->RxAnt.Pair1SecondaryRxAnt)); - - AsicSetRxAnt(pAd, pAd->RxAnt.Pair1SecondaryRxAnt); - - pAd->RxAnt.EvaluatePeriod = 1; // 1:Means switch to SecondaryRxAnt, 0:Means switch to Pair1PrimaryRxAnt - pAd->RxAnt.FirstPktArrivedWhenEvaluate = FALSE; - pAd->RxAnt.RcvPktNumWhenEvaluate = 0; - - // a one-shot timer to end the evalution - // dynamic adjust antenna evaluation period according to the traffic - if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) - RTMPSetTimer(&pAd->Mlme.RxAntEvalTimer, 100); - else - RTMPSetTimer(&pAd->Mlme.RxAntEvalTimer, 300); - } - else - { - -#ifdef CONFIG_STA_SUPPORT - if (pAd->StaCfg.Psm == PWR_SAVE) - return; -#endif // CONFIG_STA_SUPPORT // - - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BBPR3); - BBPR3 &= (~0x18); - if(pAd->Antenna.field.RxPath == 3) - { - BBPR3 |= (0x10); - } - else if(pAd->Antenna.field.RxPath == 2) - { - BBPR3 |= (0x8); - } - else if(pAd->Antenna.field.RxPath == 1) - { - BBPR3 |= (0x0); - } - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BBPR3); -#ifdef CONFIG_STA_SUPPORT -#endif // CONFIG_STA_SUPPORT // - if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) - ) - { - ULONG TxTotalCnt = pAd->RalinkCounters.OneSecTxNoRetryOkCount + - pAd->RalinkCounters.OneSecTxRetryOkCount + - pAd->RalinkCounters.OneSecTxFailCount; - - // dynamic adjust antenna evaluation period according to the traffic - if (TxTotalCnt > 50) - { - RTMPSetTimer(&pAd->Mlme.RxAntEvalTimer, 20); - pAd->Mlme.bLowThroughput = FALSE; - } - else - { - RTMPSetTimer(&pAd->Mlme.RxAntEvalTimer, 300); - pAd->Mlme.bLowThroughput = TRUE; - } - } - } -} - -/* - ======================================================================== - Routine Description: - After evaluation, check antenna link status - - Arguments: - pAd - Adapter pointer - - Return Value: - None - - ======================================================================== -*/ -VOID AsicRxAntEvalTimeout( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3) -{ - RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext; -#ifdef CONFIG_STA_SUPPORT - UCHAR BBPR3 = 0; - CHAR larger = -127, rssi0, rssi1, rssi2; -#endif // CONFIG_STA_SUPPORT // - -#ifdef RALINK_ATE - if (ATE_ON(pAd)) - return; -#endif // RALINK_ATE // - - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS | - fRTMP_ADAPTER_HALT_IN_PROGRESS | - fRTMP_ADAPTER_RADIO_OFF | - fRTMP_ADAPTER_NIC_NOT_EXIST) || - OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE) -#ifdef RT30xx - || (pAd->EepromAccess) -#endif // RT30xx // - ) - return; - - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - //if (pAd->StaCfg.Psm == PWR_SAVE) - // return; - - if (pAd->NicConfig2.field.AntDiversity) - { - if ((pAd->RxAnt.RcvPktNumWhenEvaluate != 0) && (pAd->RxAnt.Pair1AvgRssi[pAd->RxAnt.Pair1SecondaryRxAnt] >= pAd->RxAnt.Pair1AvgRssi[pAd->RxAnt.Pair1PrimaryRxAnt])) - { - UCHAR temp; - - // - // select PrimaryRxAntPair - // Role change, Used Pair1SecondaryRxAnt as PrimaryRxAntPair. - // Since Pair1SecondaryRxAnt Quality good than Pair1PrimaryRxAnt - // - temp = pAd->RxAnt.Pair1PrimaryRxAnt; - pAd->RxAnt.Pair1PrimaryRxAnt = pAd->RxAnt.Pair1SecondaryRxAnt; - pAd->RxAnt.Pair1SecondaryRxAnt = temp; - - pAd->RxAnt.Pair1LastAvgRssi = (pAd->RxAnt.Pair1AvgRssi[pAd->RxAnt.Pair1SecondaryRxAnt] >> 3); - pAd->RxAnt.EvaluateStableCnt = 0; - } - else - { - // if the evaluated antenna is not better than original, switch back to original antenna - AsicSetRxAnt(pAd, pAd->RxAnt.Pair1PrimaryRxAnt); - pAd->RxAnt.EvaluateStableCnt ++; - } - - pAd->RxAnt.EvaluatePeriod = 0; // 1:Means switch to SecondaryRxAnt, 0:Means switch to Pair1PrimaryRxAnt - - DBGPRINT(RT_DEBUG_TRACE,("AsicRxAntEvalAction::After Eval(fix in #%d), <%d, %d>, RcvPktNumWhenEvaluate=%ld\n", - pAd->RxAnt.Pair1PrimaryRxAnt, (pAd->RxAnt.Pair1AvgRssi[0] >> 3), (pAd->RxAnt.Pair1AvgRssi[1] >> 3), pAd->RxAnt.RcvPktNumWhenEvaluate)); - } - else - { - if (pAd->StaCfg.Psm == PWR_SAVE) - return; - - // if the traffic is low, use average rssi as the criteria - if (pAd->Mlme.bLowThroughput == TRUE) - { - rssi0 = pAd->StaCfg.RssiSample.LastRssi0; - rssi1 = pAd->StaCfg.RssiSample.LastRssi1; - rssi2 = pAd->StaCfg.RssiSample.LastRssi2; - } - else - { - rssi0 = pAd->StaCfg.RssiSample.AvgRssi0; - rssi1 = pAd->StaCfg.RssiSample.AvgRssi1; - rssi2 = pAd->StaCfg.RssiSample.AvgRssi2; - } - - if(pAd->Antenna.field.RxPath == 3) - { - larger = max(rssi0, rssi1); - - if (larger > (rssi2 + 20)) - pAd->Mlme.RealRxPath = 2; - else - pAd->Mlme.RealRxPath = 3; - } - else if(pAd->Antenna.field.RxPath == 2) - { - if (rssi0 > (rssi1 + 20)) - pAd->Mlme.RealRxPath = 1; - else - pAd->Mlme.RealRxPath = 2; - } - - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BBPR3); - BBPR3 &= (~0x18); - if(pAd->Mlme.RealRxPath == 3) - { - BBPR3 |= (0x10); - } - else if(pAd->Mlme.RealRxPath == 2) - { - BBPR3 |= (0x8); - } - else if(pAd->Mlme.RealRxPath == 1) - { - BBPR3 |= (0x0); - } - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BBPR3); - } - } - -#endif // CONFIG_STA_SUPPORT // - -} - - - -VOID APSDPeriodicExec( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3) -{ - RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext; - - if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) - return; - - pAd->CommonCfg.TriggerTimerCount++; - -// Driver should not send trigger frame, it should be send by application layer -/* - if (pAd->CommonCfg.bAPSDCapable && pAd->CommonCfg.APEdcaParm.bAPSDCapable - && (pAd->CommonCfg.bNeedSendTriggerFrame || - (((pAd->CommonCfg.TriggerTimerCount%20) == 19) && (!pAd->CommonCfg.bAPSDAC_BE || !pAd->CommonCfg.bAPSDAC_BK || !pAd->CommonCfg.bAPSDAC_VI || !pAd->CommonCfg.bAPSDAC_VO)))) - { - DBGPRINT(RT_DEBUG_TRACE,("Sending trigger frame and enter service period when support APSD\n")); - RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, TRUE); - pAd->CommonCfg.bNeedSendTriggerFrame = FALSE; - pAd->CommonCfg.TriggerTimerCount = 0; - pAd->CommonCfg.bInServicePeriod = TRUE; - }*/ -} - -/* - ======================================================================== - Routine Description: - Set/reset MAC registers according to bPiggyBack parameter - - Arguments: - pAd - Adapter pointer - bPiggyBack - Enable / Disable Piggy-Back - - Return Value: - None - - ======================================================================== -*/ -VOID RTMPSetPiggyBack( - IN PRTMP_ADAPTER pAd, - IN BOOLEAN bPiggyBack) -{ - TX_LINK_CFG_STRUC TxLinkCfg; - - RTMP_IO_READ32(pAd, TX_LINK_CFG, &TxLinkCfg.word); - - TxLinkCfg.field.TxCFAckEn = bPiggyBack; - RTMP_IO_WRITE32(pAd, TX_LINK_CFG, TxLinkCfg.word); -} - -/* - ======================================================================== - Routine Description: - check if this entry need to switch rate automatically - - Arguments: - pAd - pEntry - - Return Value: - TURE - FALSE - - ======================================================================== -*/ -BOOLEAN RTMPCheckEntryEnableAutoRateSwitch( - IN PRTMP_ADAPTER pAd, - IN PMAC_TABLE_ENTRY pEntry) -{ - BOOLEAN result = TRUE; - - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - // only associated STA counts - if (pEntry && (pEntry->ValidAsCLI) && (pEntry->Sst == SST_ASSOC)) - { - result = pAd->StaCfg.bAutoTxRateSwitch; - } - else - result = FALSE; - } -#endif // CONFIG_STA_SUPPORT // - - - - return result; -} - - -BOOLEAN RTMPAutoRateSwitchCheck( - IN PRTMP_ADAPTER pAd) -{ - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - if (pAd->StaCfg.bAutoTxRateSwitch) - return TRUE; - } -#endif // CONFIG_STA_SUPPORT // - return FALSE; -} - - -/* - ======================================================================== - Routine Description: - check if this entry need to fix tx legacy rate - - Arguments: - pAd - pEntry - - Return Value: - TURE - FALSE - - ======================================================================== -*/ -UCHAR RTMPStaFixedTxMode( - IN PRTMP_ADAPTER pAd, - IN PMAC_TABLE_ENTRY pEntry) -{ - UCHAR tx_mode = FIXED_TXMODE_HT; - - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - tx_mode = (UCHAR)pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode; - } -#endif // CONFIG_STA_SUPPORT // - - return tx_mode; -} - -/* - ======================================================================== - Routine Description: - Overwrite HT Tx Mode by Fixed Legency Tx Mode, if specified. - - Arguments: - pAd - pEntry - - Return Value: - TURE - FALSE - - ======================================================================== -*/ -VOID RTMPUpdateLegacyTxSetting( - UCHAR fixed_tx_mode, - PMAC_TABLE_ENTRY pEntry) -{ - HTTRANSMIT_SETTING TransmitSetting; - - if (fixed_tx_mode == FIXED_TXMODE_HT) - return; - - TransmitSetting.word = 0; - - TransmitSetting.field.MODE = pEntry->HTPhyMode.field.MODE; - TransmitSetting.field.MCS = pEntry->HTPhyMode.field.MCS; - - if (fixed_tx_mode == FIXED_TXMODE_CCK) - { - TransmitSetting.field.MODE = MODE_CCK; - // CCK mode allow MCS 0~3 - if (TransmitSetting.field.MCS > MCS_3) - TransmitSetting.field.MCS = MCS_3; - } - else - { - TransmitSetting.field.MODE = MODE_OFDM; - // OFDM mode allow MCS 0~7 - if (TransmitSetting.field.MCS > MCS_7) - TransmitSetting.field.MCS = MCS_7; - } - - if (pEntry->HTPhyMode.field.MODE >= TransmitSetting.field.MODE) - { - pEntry->HTPhyMode.word = TransmitSetting.word; - DBGPRINT(RT_DEBUG_TRACE, ("RTMPUpdateLegacyTxSetting : wcid-%d, MODE=%s, MCS=%d \n", - pEntry->Aid, GetPhyMode(pEntry->HTPhyMode.field.MODE), pEntry->HTPhyMode.field.MCS)); - } -} - -#ifdef CONFIG_STA_SUPPORT -/* - ========================================================================== - Description: - dynamic tune BBP R66 to find a balance between sensibility and - noise isolation - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID AsicStaBbpTuning( - IN PRTMP_ADAPTER pAd) -{ - UCHAR OrigR66Value = 0, R66;//, R66UpperBound = 0x30, R66LowerBound = 0x30; - CHAR Rssi; - - // 2860C did not support Fase CCA, therefore can't tune - if (pAd->MACVersion == 0x28600100) - return; - - // - // work as a STA - // - if (pAd->Mlme.CntlMachine.CurrState != CNTL_IDLE) // no R66 tuning when SCANNING - return; - - if ((pAd->OpMode == OPMODE_STA) - && (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) - ) - && !(OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) - ) - { - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R66, &OrigR66Value); - R66 = OrigR66Value; - - if (pAd->Antenna.field.RxPath > 1) - Rssi = (pAd->StaCfg.RssiSample.AvgRssi0 + pAd->StaCfg.RssiSample.AvgRssi1) >> 1; - else - Rssi = pAd->StaCfg.RssiSample.AvgRssi0; - - if (pAd->LatchRfRegs.Channel <= 14) - { //BG band -#ifdef RT30xx - // RT3070 is a no LNA solution, it should have different control regarding to AGC gain control - // Otherwise, it will have some throughput side effect when low RSSI - if (IS_RT30xx(pAd)) - { - if (Rssi > RSSI_FOR_MID_LOW_SENSIBILITY) - { - R66 = 0x1C + 2*GET_LNA_GAIN(pAd) + 0x20; - if (OrigR66Value != R66) - { - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); - } - } - else - { - R66 = 0x1C + 2*GET_LNA_GAIN(pAd); - if (OrigR66Value != R66) - { - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); - } - } - } - else -#endif // RT30xx // - { - if (Rssi > RSSI_FOR_MID_LOW_SENSIBILITY) - { - R66 = (0x2E + GET_LNA_GAIN(pAd)) + 0x10; - if (OrigR66Value != R66) - { - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); - } - } - else - { - R66 = 0x2E + GET_LNA_GAIN(pAd); - if (OrigR66Value != R66) - { - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); - } - } - } - - } - else - { //A band - if (pAd->CommonCfg.BBPCurrentBW == BW_20) - { - if (Rssi > RSSI_FOR_MID_LOW_SENSIBILITY) - { - R66 = 0x32 + (GET_LNA_GAIN(pAd)*5)/3 + 0x10; - if (OrigR66Value != R66) - { - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); - } - } - else - { - R66 = 0x32 + (GET_LNA_GAIN(pAd)*5)/3; - if (OrigR66Value != R66) - { - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); - } - } - } - else - { - if (Rssi > RSSI_FOR_MID_LOW_SENSIBILITY) - { - R66 = 0x3A + (GET_LNA_GAIN(pAd)*5)/3 + 0x10; - if (OrigR66Value != R66) - { - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); - } - } - else - { - R66 = 0x3A + (GET_LNA_GAIN(pAd)*5)/3; - if (OrigR66Value != R66) - { - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); - } - } - } - } - - - } -} -#endif // CONFIG_STA_SUPPORT // - -VOID RTMPSetAGCInitValue( - IN PRTMP_ADAPTER pAd, - IN UCHAR BandWidth) -{ - UCHAR R66 = 0x30; - - if (pAd->LatchRfRegs.Channel <= 14) - { // BG band - R66 = 0x2E + GET_LNA_GAIN(pAd); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); - } - else - { //A band - if (BandWidth == BW_20) - { - R66 = (UCHAR)(0x32 + (GET_LNA_GAIN(pAd)*5)/3); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); - } -#ifdef DOT11_N_SUPPORT - else - { - R66 = (UCHAR)(0x3A + (GET_LNA_GAIN(pAd)*5)/3); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); - } -#endif // DOT11_N_SUPPORT // - } - -} - -VOID AsicTurnOffRFClk( - IN PRTMP_ADAPTER pAd, - IN UCHAR Channel) -{ - // RF R2 bit 18 = 0 - UINT32 R1 = 0, R2 = 0, R3 = 0; - UCHAR index; - RTMP_RF_REGS *RFRegTable; - -#ifdef RT30xx - // The RF programming sequence is difference between 3xxx and 2xxx - if (IS_RT3090(pAd)) - { - RT30xxLoadRFSleepModeSetup(pAd); // add by johnli, RF power sequence setup, load RF sleep-mode setup - } - else - { -#endif // RT30xx // - RFRegTable = RF2850RegTable; - - switch (pAd->RfIcType) - { - case RFIC_2820: - case RFIC_2850: - case RFIC_2720: - case RFIC_2750: - - for (index = 0; index < NUM_OF_2850_CHNL; index++) - { - if (Channel == RFRegTable[index].Channel) - { - R1 = RFRegTable[index].R1 & 0xffffdfff; - R2 = RFRegTable[index].R2 & 0xfffbffff; - R3 = RFRegTable[index].R3 & 0xfff3ffff; - - RTMP_RF_IO_WRITE32(pAd, R1); - RTMP_RF_IO_WRITE32(pAd, R2); - - // Program R1b13 to 1, R3/b18,19 to 0, R2b18 to 0. - // Set RF R2 bit18=0, R3 bit[18:19]=0 - //if (pAd->StaCfg.bRadio == FALSE) - if (1) - { - RTMP_RF_IO_WRITE32(pAd, R3); - - DBGPRINT(RT_DEBUG_TRACE, ("AsicTurnOffRFClk#%d(RF=%d, ) , R2=0x%08x, R3 = 0x%08x \n", - Channel, pAd->RfIcType, R2, R3)); - } - else - DBGPRINT(RT_DEBUG_TRACE, ("AsicTurnOffRFClk#%d(RF=%d, ) , R2=0x%08x \n", - Channel, pAd->RfIcType, R2)); - break; - } - } - break; - - default: - break; - } -#ifdef RT30xx - } -#endif // RT30xx // - -} - - -VOID AsicTurnOnRFClk( - IN PRTMP_ADAPTER pAd, - IN UCHAR Channel) -{ - // RF R2 bit 18 = 0 - UINT32 R1 = 0, R2 = 0, R3 = 0; - UCHAR index; - RTMP_RF_REGS *RFRegTable; - -#ifdef RT30xx - // The RF programming sequence is difference between 3xxx and 2xxx - if (IS_RT3090(pAd)) - { - } - else - { -#endif // RT30xx // - RFRegTable = RF2850RegTable; - - switch (pAd->RfIcType) - { - case RFIC_2820: - case RFIC_2850: - case RFIC_2720: - case RFIC_2750: - - for (index = 0; index < NUM_OF_2850_CHNL; index++) - { - if (Channel == RFRegTable[index].Channel) - { - R3 = pAd->LatchRfRegs.R3; - R3 &= 0xfff3ffff; - R3 |= 0x00080000; - RTMP_RF_IO_WRITE32(pAd, R3); - - R1 = RFRegTable[index].R1; - RTMP_RF_IO_WRITE32(pAd, R1); - - R2 = RFRegTable[index].R2; - if (pAd->Antenna.field.TxPath == 1) - { - R2 |= 0x4000; // If TXpath is 1, bit 14 = 1; - } - - if (pAd->Antenna.field.RxPath == 2) - { - R2 |= 0x40; // write 1 to off Rxpath. - } - else if (pAd->Antenna.field.RxPath == 1) - { - R2 |= 0x20040; // write 1 to off RxPath - } - RTMP_RF_IO_WRITE32(pAd, R2); - - break; - } - } - break; - - default: - break; - } - -#ifdef RT30xx - } -#endif // RT30xx // - -} - +#include "../../rt2870/common/mlme.c" diff --git a/drivers/staging/rt3070/common/netif_block.c b/drivers/staging/rt3070/common/netif_block.c deleted file mode 100644 index 4773c11bedd0..000000000000 --- a/drivers/staging/rt3070/common/netif_block.c +++ /dev/null @@ -1,136 +0,0 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * 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 "../rt_config.h" -#include "netif_block.h" - -static NETIF_ENTRY freeNetIfEntryPool[FREE_NETIF_POOL_SIZE]; -static LIST_HEADER freeNetIfEntryList; - -void initblockQueueTab( - IN PRTMP_ADAPTER pAd) -{ - int i; - - initList(&freeNetIfEntryList); - for (i = 0; i < FREE_NETIF_POOL_SIZE; i++) - insertTailList(&freeNetIfEntryList, (PLIST_ENTRY)&freeNetIfEntryPool[i]); - - for (i=0; i < NUM_OF_TX_RING; i++) - initList(&pAd->blockQueueTab[i].NetIfList); - - return; -} - -BOOLEAN blockNetIf( - IN PBLOCK_QUEUE_ENTRY pBlockQueueEntry, - IN PNET_DEV pNetDev) -{ - PNETIF_ENTRY pNetIfEntry = NULL; - - if ((pNetIfEntry = (PNETIF_ENTRY)removeHeadList(&freeNetIfEntryList)) != NULL) - { - netif_stop_queue(pNetDev); - pNetIfEntry->pNetDev = pNetDev; - insertTailList(&pBlockQueueEntry->NetIfList, (PLIST_ENTRY)pNetIfEntry); - - pBlockQueueEntry->SwTxQueueBlockFlag = TRUE; - DBGPRINT(RT_DEBUG_TRACE, ("netif_stop_queue(%s)\n", pNetDev->name)); - } - else - return FALSE; - - return TRUE; -} - -VOID releaseNetIf( - IN PBLOCK_QUEUE_ENTRY pBlockQueueEntry) -{ - PNETIF_ENTRY pNetIfEntry = NULL; - PLIST_HEADER pNetIfList = &pBlockQueueEntry->NetIfList; - - while((pNetIfEntry = (PNETIF_ENTRY)removeHeadList(pNetIfList)) != NULL) - { - PNET_DEV pNetDev = pNetIfEntry->pNetDev; - netif_wake_queue(pNetDev); - insertTailList(&freeNetIfEntryList, (PLIST_ENTRY)pNetIfEntry); - - DBGPRINT(RT_DEBUG_TRACE, ("netif_wake_queue(%s)\n", pNetDev->name)); - } - pBlockQueueEntry->SwTxQueueBlockFlag = FALSE; - return; -} - - -VOID StopNetIfQueue( - IN PRTMP_ADAPTER pAd, - IN UCHAR QueIdx, - IN PNDIS_PACKET pPacket) -{ - PNET_DEV NetDev = NULL; - UCHAR IfIdx = 0; - BOOLEAN valid = FALSE; - -#ifdef WDS_SUPPORT - if (RTMP_GET_PACKET_NET_DEVICE(pPacket) >= MIN_NET_DEVICE_FOR_WDS) - { - IfIdx = (RTMP_GET_PACKET_NET_DEVICE(pPacket) - MIN_NET_DEVICE_FOR_WDS) % MAX_WDS_ENTRY; - NetDev = pAd->WdsTab.WdsEntry[IfIdx].dev; - } - else -#endif // WDS_SUPPORT // - { -#ifdef MBSS_SUPPORT - if (pAd->OpMode == OPMODE_AP) - { - IfIdx = (RTMP_GET_PACKET_NET_DEVICE(pPacket) - MIN_NET_DEVICE_FOR_MBSSID) % MAX_MBSSID_NUM; - NetDev = pAd->ApCfg.MBSSID[IfIdx].MSSIDDev; - } - else - { - IfIdx = MAIN_MBSSID; - NetDev = pAd->net_dev; - } -#else - IfIdx = MAIN_MBSSID; - NetDev = pAd->net_dev; -#endif - } - - // WMM support 4 software queues. - // One software queue full doesn't mean device have no capbility to transmit packet. - // So disable block Net-If queue function while WMM enable. -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - valid = (pAd->CommonCfg.bWmmCapable == TRUE) ? FALSE : TRUE; -#endif // CONFIG_STA_SUPPORT // - - if (valid) - blockNetIf(&pAd->blockQueueTab[QueIdx], NetDev); - return; -} - diff --git a/drivers/staging/rt3070/common/rtmp_init.c b/drivers/staging/rt3070/common/rtmp_init.c index 4503f6c6d954..4709e5f28a8a 100644 --- a/drivers/staging/rt3070/common/rtmp_init.c +++ b/drivers/staging/rt3070/common/rtmp_init.c @@ -1,4197 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - rtmp_init.c - - Abstract: - Miniport generic portion header file - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Paul Lin 2002-08-01 created - John Chang 2004-08-20 RT2561/2661 use scatter-gather scheme - Jan Lee 2006-09-15 RT2860. Change for 802.11n , EEPROM, Led, BA, HT. -*/ -#include "../rt_config.h" -#include "../firmware.h" - -//#define BIN_IN_FILE /* use *.bin firmware */ - -UCHAR BIT8[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}; -ULONG BIT32[] = {0x00000001, 0x00000002, 0x00000004, 0x00000008, - 0x00000010, 0x00000020, 0x00000040, 0x00000080, - 0x00000100, 0x00000200, 0x00000400, 0x00000800, - 0x00001000, 0x00002000, 0x00004000, 0x00008000, - 0x00010000, 0x00020000, 0x00040000, 0x00080000, - 0x00100000, 0x00200000, 0x00400000, 0x00800000, - 0x01000000, 0x02000000, 0x04000000, 0x08000000, - 0x10000000, 0x20000000, 0x40000000, 0x80000000}; - -char* CipherName[] = {"none","wep64","wep128","TKIP","AES","CKIP64","CKIP128"}; - -const unsigned short ccitt_16Table[] = { - 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, - 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, - 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, - 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, - 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, - 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, - 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, - 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, - 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, - 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, - 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, - 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, - 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, - 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, - 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, - 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, - 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, - 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, - 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, - 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, - 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, - 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, - 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, - 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, - 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, - 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, - 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, - 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, - 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, - 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, - 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, - 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0 -}; -#define ByteCRC16(v, crc) \ - (unsigned short)((crc << 8) ^ ccitt_16Table[((crc >> 8) ^ (v)) & 255]) - -unsigned char BitReverse(unsigned char x) -{ - int i; - unsigned char Temp=0; - for(i=0; ; i++) - { - if(x & 0x80) Temp |= 0x80; - if(i==7) break; - x <<= 1; - Temp >>= 1; - } - return Temp; -} - -// -// BBP register initialization set -// -REG_PAIR BBPRegTable[] = { - {BBP_R65, 0x2C}, // fix rssi issue - {BBP_R66, 0x38}, // Also set this default value to pAd->BbpTuning.R66CurrentValue at initial - {BBP_R69, 0x12}, - {BBP_R70, 0xa}, // BBP_R70 will change to 0x8 in ApStartUp and LinkUp for rt2860C, otherwise value is 0xa - {BBP_R73, 0x10}, - {BBP_R81, 0x37}, - {BBP_R82, 0x62}, - {BBP_R83, 0x6A}, - {BBP_R84, 0x99}, // 0x19 is for rt2860E and after. This is for extension channel overlapping IOT. 0x99 is for rt2860D and before - {BBP_R86, 0x00}, // middle range issue, Rory @2008-01-28 - {BBP_R91, 0x04}, // middle range issue, Rory @2008-01-28 - {BBP_R92, 0x00}, // middle range issue, Rory @2008-01-28 - {BBP_R103, 0x00}, // near range high-power issue, requested from Gary @2008-0528 - {BBP_R105, 0x05}, // 0x05 is for rt2860E to turn on FEQ control. It is safe for rt2860D and before, because Bit 7:2 are reserved in rt2860D and before. -}; -#define NUM_BBP_REG_PARMS (sizeof(BBPRegTable) / sizeof(REG_PAIR)) - -// -// RF register initialization set -// -#ifdef RT30xx -REG_PAIR RT30xx_RFRegTable[] = { - {RF_R04, 0x40}, - {RF_R05, 0x03}, - {RF_R06, 0x02}, - {RF_R07, 0x70}, - {RF_R09, 0x0F}, - {RF_R10, 0x41}, - {RF_R11, 0x21}, - {RF_R12, 0x7B}, - {RF_R14, 0x90}, - {RF_R15, 0x58}, - {RF_R16, 0xB3}, - {RF_R17, 0x92}, - {RF_R18, 0x2C}, - {RF_R19, 0x02}, - {RF_R20, 0xBA}, - {RF_R21, 0xDB}, - {RF_R24, 0x16}, - {RF_R25, 0x01}, - {RF_R29, 0x1F}, -}; -#define NUM_RF_REG_PARMS (sizeof(RT30xx_RFRegTable) / sizeof(REG_PAIR)) -#endif // RT30xx // - -// -// ASIC register initialization sets -// - -RTMP_REG_PAIR MACRegTable[] = { -#if defined(HW_BEACON_OFFSET) && (HW_BEACON_OFFSET == 0x200) - {BCN_OFFSET0, 0xf8f0e8e0}, /* 0x3800(e0), 0x3A00(e8), 0x3C00(f0), 0x3E00(f8), 512B for each beacon */ - {BCN_OFFSET1, 0x6f77d0c8}, /* 0x3200(c8), 0x3400(d0), 0x1DC0(77), 0x1BC0(6f), 512B for each beacon */ -#elif defined(HW_BEACON_OFFSET) && (HW_BEACON_OFFSET == 0x100) - {BCN_OFFSET0, 0xece8e4e0}, /* 0x3800, 0x3A00, 0x3C00, 0x3E00, 512B for each beacon */ - {BCN_OFFSET1, 0xfcf8f4f0}, /* 0x3800, 0x3A00, 0x3C00, 0x3E00, 512B for each beacon */ -#else - #error You must re-calculate new value for BCN_OFFSET0 & BCN_OFFSET1 in MACRegTable[]!!! -#endif // HW_BEACON_OFFSET // - - {LEGACY_BASIC_RATE, 0x0000013f}, // Basic rate set bitmap - {HT_BASIC_RATE, 0x00008003}, // Basic HT rate set , 20M, MCS=3, MM. Format is the same as in TXWI. - {MAC_SYS_CTRL, 0x00}, // 0x1004, , default Disable RX - {RX_FILTR_CFG, 0x17f97}, //0x1400 , RX filter control, - {BKOFF_SLOT_CFG, 0x209}, // default set short slot time, CC_DELAY_TIME should be 2 - //{TX_SW_CFG0, 0x40a06}, // Gary,2006-08-23 - {TX_SW_CFG0, 0x0}, // Gary,2008-05-21 for CWC test - {TX_SW_CFG1, 0x80606}, // Gary,2006-08-23 - {TX_LINK_CFG, 0x1020}, // Gary,2006-08-23 - {TX_TIMEOUT_CFG, 0x000a2090}, - {MAX_LEN_CFG, MAX_AGGREGATION_SIZE | 0x00001000}, // 0x3018, MAX frame length. Max PSDU = 16kbytes. - {LED_CFG, 0x7f031e46}, // Gary, 2006-08-23 - -//#ifdef CONFIG_STA_SUPPORT -// {WMM_AIFSN_CFG, 0x00002273}, -// {WMM_CWMIN_CFG, 0x00002344}, -// {WMM_CWMAX_CFG, 0x000034aa}, -//#endif // CONFIG_STA_SUPPORT // -#ifdef INF_AMAZON_SE - {PBF_MAX_PCNT, 0x1F3F6F6F}, //iverson modify for usb issue, 2008/09/19 - // 6F + 6F < total page count FE - // so that RX doesn't occupy TX's buffer space when WMM congestion. -#else - {PBF_MAX_PCNT, 0x1F3FBF9F}, //0x1F3f7f9f}, //Jan, 2006/04/20 -#endif // INF_AMAZON_SE // - //{TX_RTY_CFG, 0x6bb80408}, // Jan, 2006/11/16 - {TX_RTY_CFG, 0x47d01f0f}, // Jan, 2006/11/16, Set TxWI->ACK =0 in Probe Rsp Modify for 2860E ,2007-08-03 - {AUTO_RSP_CFG, 0x00000013}, // Initial Auto_Responder, because QA will turn off Auto-Responder - {CCK_PROT_CFG, 0x05740003 /*0x01740003*/}, // Initial Auto_Responder, because QA will turn off Auto-Responder. And RTS threshold is enabled. - {OFDM_PROT_CFG, 0x05740003 /*0x01740003*/}, // Initial Auto_Responder, because QA will turn off Auto-Responder. And RTS threshold is enabled. -//PS packets use Tx1Q (for HCCA) when dequeue from PS unicast queue (WiFi WPA2 MA9_DT1 for Marvell B STA) -#ifdef RT2870 -#ifdef CONFIG_STA_SUPPORT - {PBF_CFG, 0xf40006}, // Only enable Queue 2 -#endif // CONFIG_STA_SUPPORT // - {MM40_PROT_CFG, 0x3F44084}, // Initial Auto_Responder, because QA will turn off Auto-Responder - {WPDMA_GLO_CFG, 0x00000030}, -#endif // RT2870 // - {GF20_PROT_CFG, 0x01744004}, // set 19:18 --> Short NAV for MIMO PS - {GF40_PROT_CFG, 0x03F44084}, - {MM20_PROT_CFG, 0x01744004}, - {TXOP_CTRL_CFG, 0x0000583f, /*0x0000243f*/ /*0x000024bf*/}, //Extension channel backoff. - {TX_RTS_CFG, 0x00092b20}, -//#ifdef WIFI_TEST - {EXP_ACK_TIME, 0x002400ca}, // default value -//#else -// {EXP_ACK_TIME, 0x005400ca}, // suggested by Gray @ 20070323 for 11n intel-sta throughput -//#endif // end - WIFI_TEST // - {TXOP_HLDR_ET, 0x00000002}, - - /* Jerry comments 2008/01/16: we use SIFS = 10us in CCK defaultly, but it seems that 10us - is too small for INTEL 2200bg card, so in MBSS mode, the delta time between beacon0 - and beacon1 is SIFS (10us), so if INTEL 2200bg card connects to BSS0, the ping - will always lost. So we change the SIFS of CCK from 10us to 16us. */ - {XIFS_TIME_CFG, 0x33a41010}, - {PWR_PIN_CFG, 0x00000003}, // patch for 2880-E -}; - - -#ifdef CONFIG_STA_SUPPORT -RTMP_REG_PAIR STAMACRegTable[] = { - {WMM_AIFSN_CFG, 0x00002273}, - {WMM_CWMIN_CFG, 0x00002344}, - {WMM_CWMAX_CFG, 0x000034aa}, -}; -#endif // CONFIG_STA_SUPPORT // - -#define NUM_MAC_REG_PARMS (sizeof(MACRegTable) / sizeof(RTMP_REG_PAIR)) -#ifdef CONFIG_STA_SUPPORT -#define NUM_STA_MAC_REG_PARMS (sizeof(STAMACRegTable) / sizeof(RTMP_REG_PAIR)) -#endif // CONFIG_STA_SUPPORT // - -#ifdef RT2870 -// -// RT2870 Firmware Spec only used 1 oct for version expression -// -#define FIRMWARE_MINOR_VERSION 7 - -#endif // RT2870 // - -// New 8k byte firmware size for RT3071/RT3072 -#define FIRMWAREIMAGE_MAX_LENGTH 0x2000 -#define FIRMWAREIMAGE_LENGTH (sizeof (FirmwareImage) / sizeof(UCHAR)) -#define FIRMWARE_MAJOR_VERSION 0 - -#define FIRMWAREIMAGEV1_LENGTH 0x1000 -#define FIRMWAREIMAGEV2_LENGTH 0x1000 - - - -/* - ======================================================================== - - Routine Description: - Allocate RTMP_ADAPTER data block and do some initialization - - Arguments: - Adapter Pointer to our adapter - - Return Value: - NDIS_STATUS_SUCCESS - NDIS_STATUS_FAILURE - - IRQL = PASSIVE_LEVEL - - Note: - - ======================================================================== -*/ -NDIS_STATUS RTMPAllocAdapterBlock( - IN PVOID handle, - OUT PRTMP_ADAPTER *ppAdapter) -{ - PRTMP_ADAPTER pAd; - NDIS_STATUS Status; - INT index; - UCHAR *pBeaconBuf = NULL; - - DBGPRINT(RT_DEBUG_TRACE, ("--> RTMPAllocAdapterBlock\n")); - - *ppAdapter = NULL; - - do - { - // Allocate RTMP_ADAPTER memory block - pBeaconBuf = kmalloc(MAX_BEACON_SIZE, MEM_ALLOC_FLAG); - if (pBeaconBuf == NULL) - { - Status = NDIS_STATUS_FAILURE; - DBGPRINT_ERR(("Failed to allocate memory - BeaconBuf!\n")); - break; - } - - Status = AdapterBlockAllocateMemory(handle, (PVOID *)&pAd); - if (Status != NDIS_STATUS_SUCCESS) - { - DBGPRINT_ERR(("Failed to allocate memory - ADAPTER\n")); - break; - } - pAd->BeaconBuf = pBeaconBuf; - printk("\n\n=== pAd = %p, size = %d ===\n\n", pAd, (UINT32)sizeof(RTMP_ADAPTER)); - - - // Init spin locks - NdisAllocateSpinLock(&pAd->MgmtRingLock); - - for (index =0 ; index < NUM_OF_TX_RING; index++) - { - NdisAllocateSpinLock(&pAd->TxSwQueueLock[index]); - NdisAllocateSpinLock(&pAd->DeQueueLock[index]); - pAd->DeQueueRunning[index] = FALSE; - } - - NdisAllocateSpinLock(&pAd->irq_lock); - - } while (FALSE); - - if ((Status != NDIS_STATUS_SUCCESS) && (pBeaconBuf)) - kfree(pBeaconBuf); - - *ppAdapter = pAd; - - DBGPRINT_S(Status, ("<-- RTMPAllocAdapterBlock, Status=%x\n", Status)); - return Status; -} - -/* - ======================================================================== - - Routine Description: - Read initial Tx power per MCS and BW from EEPROM - - Arguments: - Adapter Pointer to our adapter - - Return Value: - None - - IRQL = PASSIVE_LEVEL - - Note: - - ======================================================================== -*/ -VOID RTMPReadTxPwrPerRate( - IN PRTMP_ADAPTER pAd) -{ - ULONG data, Adata, Gdata; - USHORT i, value, value2; - INT Apwrdelta, Gpwrdelta; - UCHAR t1,t2,t3,t4; - BOOLEAN bValid, bApwrdeltaMinus = TRUE, bGpwrdeltaMinus = TRUE; - - // - // Get power delta for 20MHz and 40MHz. - // - DBGPRINT(RT_DEBUG_TRACE, ("Txpower per Rate\n")); - RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_DELTA, value2); - Apwrdelta = 0; - Gpwrdelta = 0; - - if ((value2 & 0xff) != 0xff) - { - if ((value2 & 0x80)) - Gpwrdelta = (value2&0xf); - - if ((value2 & 0x40)) - bGpwrdeltaMinus = FALSE; - else - bGpwrdeltaMinus = TRUE; - } - if ((value2 & 0xff00) != 0xff00) - { - if ((value2 & 0x8000)) - Apwrdelta = ((value2&0xf00)>>8); - - if ((value2 & 0x4000)) - bApwrdeltaMinus = FALSE; - else - bApwrdeltaMinus = TRUE; - } - DBGPRINT(RT_DEBUG_TRACE, ("Gpwrdelta = %x, Apwrdelta = %x .\n", Gpwrdelta, Apwrdelta)); - - // - // Get Txpower per MCS for 20MHz in 2.4G. - // - for (i=0; i<5; i++) - { - RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_20MHZ_2_4G + i*4, value); - data = value; - if (bApwrdeltaMinus == FALSE) - { - t1 = (value&0xf)+(Apwrdelta); - if (t1 > 0xf) - t1 = 0xf; - t2 = ((value&0xf0)>>4)+(Apwrdelta); - if (t2 > 0xf) - t2 = 0xf; - t3 = ((value&0xf00)>>8)+(Apwrdelta); - if (t3 > 0xf) - t3 = 0xf; - t4 = ((value&0xf000)>>12)+(Apwrdelta); - if (t4 > 0xf) - t4 = 0xf; - } - else - { - if ((value&0xf) > Apwrdelta) - t1 = (value&0xf)-(Apwrdelta); - else - t1 = 0; - if (((value&0xf0)>>4) > Apwrdelta) - t2 = ((value&0xf0)>>4)-(Apwrdelta); - else - t2 = 0; - if (((value&0xf00)>>8) > Apwrdelta) - t3 = ((value&0xf00)>>8)-(Apwrdelta); - else - t3 = 0; - if (((value&0xf000)>>12) > Apwrdelta) - t4 = ((value&0xf000)>>12)-(Apwrdelta); - else - t4 = 0; - } - Adata = t1 + (t2<<4) + (t3<<8) + (t4<<12); - if (bGpwrdeltaMinus == FALSE) - { - t1 = (value&0xf)+(Gpwrdelta); - if (t1 > 0xf) - t1 = 0xf; - t2 = ((value&0xf0)>>4)+(Gpwrdelta); - if (t2 > 0xf) - t2 = 0xf; - t3 = ((value&0xf00)>>8)+(Gpwrdelta); - if (t3 > 0xf) - t3 = 0xf; - t4 = ((value&0xf000)>>12)+(Gpwrdelta); - if (t4 > 0xf) - t4 = 0xf; - } - else - { - if ((value&0xf) > Gpwrdelta) - t1 = (value&0xf)-(Gpwrdelta); - else - t1 = 0; - if (((value&0xf0)>>4) > Gpwrdelta) - t2 = ((value&0xf0)>>4)-(Gpwrdelta); - else - t2 = 0; - if (((value&0xf00)>>8) > Gpwrdelta) - t3 = ((value&0xf00)>>8)-(Gpwrdelta); - else - t3 = 0; - if (((value&0xf000)>>12) > Gpwrdelta) - t4 = ((value&0xf000)>>12)-(Gpwrdelta); - else - t4 = 0; - } - Gdata = t1 + (t2<<4) + (t3<<8) + (t4<<12); - - RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_20MHZ_2_4G + i*4 + 2, value); - if (bApwrdeltaMinus == FALSE) - { - t1 = (value&0xf)+(Apwrdelta); - if (t1 > 0xf) - t1 = 0xf; - t2 = ((value&0xf0)>>4)+(Apwrdelta); - if (t2 > 0xf) - t2 = 0xf; - t3 = ((value&0xf00)>>8)+(Apwrdelta); - if (t3 > 0xf) - t3 = 0xf; - t4 = ((value&0xf000)>>12)+(Apwrdelta); - if (t4 > 0xf) - t4 = 0xf; - } - else - { - if ((value&0xf) > Apwrdelta) - t1 = (value&0xf)-(Apwrdelta); - else - t1 = 0; - if (((value&0xf0)>>4) > Apwrdelta) - t2 = ((value&0xf0)>>4)-(Apwrdelta); - else - t2 = 0; - if (((value&0xf00)>>8) > Apwrdelta) - t3 = ((value&0xf00)>>8)-(Apwrdelta); - else - t3 = 0; - if (((value&0xf000)>>12) > Apwrdelta) - t4 = ((value&0xf000)>>12)-(Apwrdelta); - else - t4 = 0; - } - Adata |= ((t1<<16) + (t2<<20) + (t3<<24) + (t4<<28)); - if (bGpwrdeltaMinus == FALSE) - { - t1 = (value&0xf)+(Gpwrdelta); - if (t1 > 0xf) - t1 = 0xf; - t2 = ((value&0xf0)>>4)+(Gpwrdelta); - if (t2 > 0xf) - t2 = 0xf; - t3 = ((value&0xf00)>>8)+(Gpwrdelta); - if (t3 > 0xf) - t3 = 0xf; - t4 = ((value&0xf000)>>12)+(Gpwrdelta); - if (t4 > 0xf) - t4 = 0xf; - } - else - { - if ((value&0xf) > Gpwrdelta) - t1 = (value&0xf)-(Gpwrdelta); - else - t1 = 0; - if (((value&0xf0)>>4) > Gpwrdelta) - t2 = ((value&0xf0)>>4)-(Gpwrdelta); - else - t2 = 0; - if (((value&0xf00)>>8) > Gpwrdelta) - t3 = ((value&0xf00)>>8)-(Gpwrdelta); - else - t3 = 0; - if (((value&0xf000)>>12) > Gpwrdelta) - t4 = ((value&0xf000)>>12)-(Gpwrdelta); - else - t4 = 0; - } - Gdata |= ((t1<<16) + (t2<<20) + (t3<<24) + (t4<<28)); - data |= (value<<16); - - pAd->Tx20MPwrCfgABand[i] = pAd->Tx40MPwrCfgABand[i] = Adata; - pAd->Tx20MPwrCfgGBand[i] = pAd->Tx40MPwrCfgGBand[i] = Gdata; - - if (data != 0xffffffff) - RTMP_IO_WRITE32(pAd, TX_PWR_CFG_0 + i*4, data); - DBGPRINT_RAW(RT_DEBUG_TRACE, ("20MHz BW, 2.4G band-%lx, Adata = %lx, Gdata = %lx \n", data, Adata, Gdata)); - } - - // - // Check this block is valid for 40MHz in 2.4G. If invalid, use parameter for 20MHz in 2.4G - // - bValid = TRUE; - for (i=0; i<6; i++) - { - RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_40MHZ_2_4G + 2 + i*2, value); - if (((value & 0x00FF) == 0x00FF) || ((value & 0xFF00) == 0xFF00)) - { - bValid = FALSE; - break; - } - } - - // - // Get Txpower per MCS for 40MHz in 2.4G. - // - if (bValid) - { - for (i=0; i<4; i++) - { - RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_40MHZ_2_4G + i*4, value); - if (bGpwrdeltaMinus == FALSE) - { - t1 = (value&0xf)+(Gpwrdelta); - if (t1 > 0xf) - t1 = 0xf; - t2 = ((value&0xf0)>>4)+(Gpwrdelta); - if (t2 > 0xf) - t2 = 0xf; - t3 = ((value&0xf00)>>8)+(Gpwrdelta); - if (t3 > 0xf) - t3 = 0xf; - t4 = ((value&0xf000)>>12)+(Gpwrdelta); - if (t4 > 0xf) - t4 = 0xf; - } - else - { - if ((value&0xf) > Gpwrdelta) - t1 = (value&0xf)-(Gpwrdelta); - else - t1 = 0; - if (((value&0xf0)>>4) > Gpwrdelta) - t2 = ((value&0xf0)>>4)-(Gpwrdelta); - else - t2 = 0; - if (((value&0xf00)>>8) > Gpwrdelta) - t3 = ((value&0xf00)>>8)-(Gpwrdelta); - else - t3 = 0; - if (((value&0xf000)>>12) > Gpwrdelta) - t4 = ((value&0xf000)>>12)-(Gpwrdelta); - else - t4 = 0; - } - Gdata = t1 + (t2<<4) + (t3<<8) + (t4<<12); - - RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_40MHZ_2_4G + i*4 + 2, value); - if (bGpwrdeltaMinus == FALSE) - { - t1 = (value&0xf)+(Gpwrdelta); - if (t1 > 0xf) - t1 = 0xf; - t2 = ((value&0xf0)>>4)+(Gpwrdelta); - if (t2 > 0xf) - t2 = 0xf; - t3 = ((value&0xf00)>>8)+(Gpwrdelta); - if (t3 > 0xf) - t3 = 0xf; - t4 = ((value&0xf000)>>12)+(Gpwrdelta); - if (t4 > 0xf) - t4 = 0xf; - } - else - { - if ((value&0xf) > Gpwrdelta) - t1 = (value&0xf)-(Gpwrdelta); - else - t1 = 0; - if (((value&0xf0)>>4) > Gpwrdelta) - t2 = ((value&0xf0)>>4)-(Gpwrdelta); - else - t2 = 0; - if (((value&0xf00)>>8) > Gpwrdelta) - t3 = ((value&0xf00)>>8)-(Gpwrdelta); - else - t3 = 0; - if (((value&0xf000)>>12) > Gpwrdelta) - t4 = ((value&0xf000)>>12)-(Gpwrdelta); - else - t4 = 0; - } - Gdata |= ((t1<<16) + (t2<<20) + (t3<<24) + (t4<<28)); - - if (i == 0) - pAd->Tx40MPwrCfgGBand[i+1] = (pAd->Tx40MPwrCfgGBand[i+1] & 0x0000FFFF) | (Gdata & 0xFFFF0000); - else - pAd->Tx40MPwrCfgGBand[i+1] = Gdata; - - DBGPRINT_RAW(RT_DEBUG_TRACE, ("40MHz BW, 2.4G band, Gdata = %lx \n", Gdata)); - } - } - - // - // Check this block is valid for 20MHz in 5G. If invalid, use parameter for 20MHz in 2.4G - // - bValid = TRUE; - for (i=0; i<8; i++) - { - RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_20MHZ_5G + 2 + i*2, value); - if (((value & 0x00FF) == 0x00FF) || ((value & 0xFF00) == 0xFF00)) - { - bValid = FALSE; - break; - } - } - - // - // Get Txpower per MCS for 20MHz in 5G. - // - if (bValid) - { - for (i=0; i<5; i++) - { - RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_20MHZ_5G + i*4, value); - if (bApwrdeltaMinus == FALSE) - { - t1 = (value&0xf)+(Apwrdelta); - if (t1 > 0xf) - t1 = 0xf; - t2 = ((value&0xf0)>>4)+(Apwrdelta); - if (t2 > 0xf) - t2 = 0xf; - t3 = ((value&0xf00)>>8)+(Apwrdelta); - if (t3 > 0xf) - t3 = 0xf; - t4 = ((value&0xf000)>>12)+(Apwrdelta); - if (t4 > 0xf) - t4 = 0xf; - } - else - { - if ((value&0xf) > Apwrdelta) - t1 = (value&0xf)-(Apwrdelta); - else - t1 = 0; - if (((value&0xf0)>>4) > Apwrdelta) - t2 = ((value&0xf0)>>4)-(Apwrdelta); - else - t2 = 0; - if (((value&0xf00)>>8) > Apwrdelta) - t3 = ((value&0xf00)>>8)-(Apwrdelta); - else - t3 = 0; - if (((value&0xf000)>>12) > Apwrdelta) - t4 = ((value&0xf000)>>12)-(Apwrdelta); - else - t4 = 0; - } - Adata = t1 + (t2<<4) + (t3<<8) + (t4<<12); - - RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_20MHZ_5G + i*4 + 2, value); - if (bApwrdeltaMinus == FALSE) - { - t1 = (value&0xf)+(Apwrdelta); - if (t1 > 0xf) - t1 = 0xf; - t2 = ((value&0xf0)>>4)+(Apwrdelta); - if (t2 > 0xf) - t2 = 0xf; - t3 = ((value&0xf00)>>8)+(Apwrdelta); - if (t3 > 0xf) - t3 = 0xf; - t4 = ((value&0xf000)>>12)+(Apwrdelta); - if (t4 > 0xf) - t4 = 0xf; - } - else - { - if ((value&0xf) > Apwrdelta) - t1 = (value&0xf)-(Apwrdelta); - else - t1 = 0; - if (((value&0xf0)>>4) > Apwrdelta) - t2 = ((value&0xf0)>>4)-(Apwrdelta); - else - t2 = 0; - if (((value&0xf00)>>8) > Apwrdelta) - t3 = ((value&0xf00)>>8)-(Apwrdelta); - else - t3 = 0; - if (((value&0xf000)>>12) > Apwrdelta) - t4 = ((value&0xf000)>>12)-(Apwrdelta); - else - t4 = 0; - } - Adata |= ((t1<<16) + (t2<<20) + (t3<<24) + (t4<<28)); - - if (i == 0) - pAd->Tx20MPwrCfgABand[i] = (pAd->Tx20MPwrCfgABand[i] & 0x0000FFFF) | (Adata & 0xFFFF0000); - else - pAd->Tx20MPwrCfgABand[i] = Adata; - - DBGPRINT_RAW(RT_DEBUG_TRACE, ("20MHz BW, 5GHz band, Adata = %lx \n", Adata)); - } - } - - // - // Check this block is valid for 40MHz in 5G. If invalid, use parameter for 20MHz in 2.4G - // - bValid = TRUE; - for (i=0; i<6; i++) - { - RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_40MHZ_5G + 2 + i*2, value); - if (((value & 0x00FF) == 0x00FF) || ((value & 0xFF00) == 0xFF00)) - { - bValid = FALSE; - break; - } - } - - // - // Get Txpower per MCS for 40MHz in 5G. - // - if (bValid) - { - for (i=0; i<4; i++) - { - RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_40MHZ_5G + i*4, value); - if (bApwrdeltaMinus == FALSE) - { - t1 = (value&0xf)+(Apwrdelta); - if (t1 > 0xf) - t1 = 0xf; - t2 = ((value&0xf0)>>4)+(Apwrdelta); - if (t2 > 0xf) - t2 = 0xf; - t3 = ((value&0xf00)>>8)+(Apwrdelta); - if (t3 > 0xf) - t3 = 0xf; - t4 = ((value&0xf000)>>12)+(Apwrdelta); - if (t4 > 0xf) - t4 = 0xf; - } - else - { - if ((value&0xf) > Apwrdelta) - t1 = (value&0xf)-(Apwrdelta); - else - t1 = 0; - if (((value&0xf0)>>4) > Apwrdelta) - t2 = ((value&0xf0)>>4)-(Apwrdelta); - else - t2 = 0; - if (((value&0xf00)>>8) > Apwrdelta) - t3 = ((value&0xf00)>>8)-(Apwrdelta); - else - t3 = 0; - if (((value&0xf000)>>12) > Apwrdelta) - t4 = ((value&0xf000)>>12)-(Apwrdelta); - else - t4 = 0; - } - Adata = t1 + (t2<<4) + (t3<<8) + (t4<<12); - - RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_40MHZ_5G + i*4 + 2, value); - if (bApwrdeltaMinus == FALSE) - { - t1 = (value&0xf)+(Apwrdelta); - if (t1 > 0xf) - t1 = 0xf; - t2 = ((value&0xf0)>>4)+(Apwrdelta); - if (t2 > 0xf) - t2 = 0xf; - t3 = ((value&0xf00)>>8)+(Apwrdelta); - if (t3 > 0xf) - t3 = 0xf; - t4 = ((value&0xf000)>>12)+(Apwrdelta); - if (t4 > 0xf) - t4 = 0xf; - } - else - { - if ((value&0xf) > Apwrdelta) - t1 = (value&0xf)-(Apwrdelta); - else - t1 = 0; - if (((value&0xf0)>>4) > Apwrdelta) - t2 = ((value&0xf0)>>4)-(Apwrdelta); - else - t2 = 0; - if (((value&0xf00)>>8) > Apwrdelta) - t3 = ((value&0xf00)>>8)-(Apwrdelta); - else - t3 = 0; - if (((value&0xf000)>>12) > Apwrdelta) - t4 = ((value&0xf000)>>12)-(Apwrdelta); - else - t4 = 0; - } - Adata |= ((t1<<16) + (t2<<20) + (t3<<24) + (t4<<28)); - - if (i == 0) - pAd->Tx40MPwrCfgABand[i+1] = (pAd->Tx40MPwrCfgABand[i+1] & 0x0000FFFF) | (Adata & 0xFFFF0000); - else - pAd->Tx40MPwrCfgABand[i+1] = Adata; - - DBGPRINT_RAW(RT_DEBUG_TRACE, ("40MHz BW, 5GHz band, Adata = %lx \n", Adata)); - } - } -} - - -/* - ======================================================================== - - Routine Description: - Read initial channel power parameters from EEPROM - - Arguments: - Adapter Pointer to our adapter - - Return Value: - None - - IRQL = PASSIVE_LEVEL - - Note: - - ======================================================================== -*/ -VOID RTMPReadChannelPwr( - IN PRTMP_ADAPTER pAd) -{ - UCHAR i, choffset; - EEPROM_TX_PWR_STRUC Power; - EEPROM_TX_PWR_STRUC Power2; - - // Read Tx power value for all channels - // Value from 1 - 0x7f. Default value is 24. - // Power value : 2.4G 0x00 (0) ~ 0x1F (31) - // : 5.5G 0xF9 (-7) ~ 0x0F (15) - - // 0. 11b/g, ch1 - ch 14 - for (i = 0; i < 7; i++) - { -// Power.word = RTMP_EEPROM_READ16(pAd, EEPROM_G_TX_PWR_OFFSET + i * 2); -// Power2.word = RTMP_EEPROM_READ16(pAd, EEPROM_G_TX2_PWR_OFFSET + i * 2); - RT28xx_EEPROM_READ16(pAd, EEPROM_G_TX_PWR_OFFSET + i * 2, Power.word); - RT28xx_EEPROM_READ16(pAd, EEPROM_G_TX2_PWR_OFFSET + i * 2, Power2.word); - pAd->TxPower[i * 2].Channel = i * 2 + 1; - pAd->TxPower[i * 2 + 1].Channel = i * 2 + 2; - - if ((Power.field.Byte0 > 31) || (Power.field.Byte0 < 0)) - pAd->TxPower[i * 2].Power = DEFAULT_RF_TX_POWER; - else - pAd->TxPower[i * 2].Power = Power.field.Byte0; - - if ((Power.field.Byte1 > 31) || (Power.field.Byte1 < 0)) - pAd->TxPower[i * 2 + 1].Power = DEFAULT_RF_TX_POWER; - else - pAd->TxPower[i * 2 + 1].Power = Power.field.Byte1; - - if ((Power2.field.Byte0 > 31) || (Power2.field.Byte0 < 0)) - pAd->TxPower[i * 2].Power2 = DEFAULT_RF_TX_POWER; - else - pAd->TxPower[i * 2].Power2 = Power2.field.Byte0; - - if ((Power2.field.Byte1 > 31) || (Power2.field.Byte1 < 0)) - pAd->TxPower[i * 2 + 1].Power2 = DEFAULT_RF_TX_POWER; - else - pAd->TxPower[i * 2 + 1].Power2 = Power2.field.Byte1; - } - - // 1. U-NII lower/middle band: 36, 38, 40; 44, 46, 48; 52, 54, 56; 60, 62, 64 (including central frequency in BW 40MHz) - // 1.1 Fill up channel - choffset = 14; - for (i = 0; i < 4; i++) - { - pAd->TxPower[3 * i + choffset + 0].Channel = 36 + i * 8 + 0; - pAd->TxPower[3 * i + choffset + 0].Power = DEFAULT_RF_TX_POWER; - pAd->TxPower[3 * i + choffset + 0].Power2 = DEFAULT_RF_TX_POWER; - - pAd->TxPower[3 * i + choffset + 1].Channel = 36 + i * 8 + 2; - pAd->TxPower[3 * i + choffset + 1].Power = DEFAULT_RF_TX_POWER; - pAd->TxPower[3 * i + choffset + 1].Power2 = DEFAULT_RF_TX_POWER; - - pAd->TxPower[3 * i + choffset + 2].Channel = 36 + i * 8 + 4; - pAd->TxPower[3 * i + choffset + 2].Power = DEFAULT_RF_TX_POWER; - pAd->TxPower[3 * i + choffset + 2].Power2 = DEFAULT_RF_TX_POWER; - } - - // 1.2 Fill up power - for (i = 0; i < 6; i++) - { -// Power.word = RTMP_EEPROM_READ16(pAd, EEPROM_A_TX_PWR_OFFSET + i * 2); -// Power2.word = RTMP_EEPROM_READ16(pAd, EEPROM_A_TX2_PWR_OFFSET + i * 2); - RT28xx_EEPROM_READ16(pAd, EEPROM_A_TX_PWR_OFFSET + i * 2, Power.word); - RT28xx_EEPROM_READ16(pAd, EEPROM_A_TX2_PWR_OFFSET + i * 2, Power2.word); - - if ((Power.field.Byte0 < 16) && (Power.field.Byte0 >= -7)) - pAd->TxPower[i * 2 + choffset + 0].Power = Power.field.Byte0; - - if ((Power.field.Byte1 < 16) && (Power.field.Byte1 >= -7)) - pAd->TxPower[i * 2 + choffset + 1].Power = Power.field.Byte1; - - if ((Power2.field.Byte0 < 16) && (Power2.field.Byte0 >= -7)) - pAd->TxPower[i * 2 + choffset + 0].Power2 = Power2.field.Byte0; - - if ((Power2.field.Byte1 < 16) && (Power2.field.Byte1 >= -7)) - pAd->TxPower[i * 2 + choffset + 1].Power2 = Power2.field.Byte1; - } - - // 2. HipperLAN 2 100, 102 ,104; 108, 110, 112; 116, 118, 120; 124, 126, 128; 132, 134, 136; 140 (including central frequency in BW 40MHz) - // 2.1 Fill up channel - choffset = 14 + 12; - for (i = 0; i < 5; i++) - { - pAd->TxPower[3 * i + choffset + 0].Channel = 100 + i * 8 + 0; - pAd->TxPower[3 * i + choffset + 0].Power = DEFAULT_RF_TX_POWER; - pAd->TxPower[3 * i + choffset + 0].Power2 = DEFAULT_RF_TX_POWER; - - pAd->TxPower[3 * i + choffset + 1].Channel = 100 + i * 8 + 2; - pAd->TxPower[3 * i + choffset + 1].Power = DEFAULT_RF_TX_POWER; - pAd->TxPower[3 * i + choffset + 1].Power2 = DEFAULT_RF_TX_POWER; - - pAd->TxPower[3 * i + choffset + 2].Channel = 100 + i * 8 + 4; - pAd->TxPower[3 * i + choffset + 2].Power = DEFAULT_RF_TX_POWER; - pAd->TxPower[3 * i + choffset + 2].Power2 = DEFAULT_RF_TX_POWER; - } - pAd->TxPower[3 * 5 + choffset + 0].Channel = 140; - pAd->TxPower[3 * 5 + choffset + 0].Power = DEFAULT_RF_TX_POWER; - pAd->TxPower[3 * 5 + choffset + 0].Power2 = DEFAULT_RF_TX_POWER; - - // 2.2 Fill up power - for (i = 0; i < 8; i++) - { -// Power.word = RTMP_EEPROM_READ16(pAd, EEPROM_A_TX_PWR_OFFSET + (choffset - 14) + i * 2); -// Power2.word = RTMP_EEPROM_READ16(pAd, EEPROM_A_TX2_PWR_OFFSET + (choffset - 14) + i * 2); - RT28xx_EEPROM_READ16(pAd, EEPROM_A_TX_PWR_OFFSET + (choffset - 14) + i * 2, Power.word); - RT28xx_EEPROM_READ16(pAd, EEPROM_A_TX2_PWR_OFFSET + (choffset - 14) + i * 2, Power2.word); - - if ((Power.field.Byte0 < 16) && (Power.field.Byte0 >= -7)) - pAd->TxPower[i * 2 + choffset + 0].Power = Power.field.Byte0; - - if ((Power.field.Byte1 < 16) && (Power.field.Byte1 >= -7)) - pAd->TxPower[i * 2 + choffset + 1].Power = Power.field.Byte1; - - if ((Power2.field.Byte0 < 16) && (Power2.field.Byte0 >= -7)) - pAd->TxPower[i * 2 + choffset + 0].Power2 = Power2.field.Byte0; - - if ((Power2.field.Byte1 < 16) && (Power2.field.Byte1 >= -7)) - pAd->TxPower[i * 2 + choffset + 1].Power2 = Power2.field.Byte1; - } - - // 3. U-NII upper band: 149, 151, 153; 157, 159, 161; 165 (including central frequency in BW 40MHz) - // 3.1 Fill up channel - choffset = 14 + 12 + 16; - for (i = 0; i < 2; i++) - { - pAd->TxPower[3 * i + choffset + 0].Channel = 149 + i * 8 + 0; - pAd->TxPower[3 * i + choffset + 0].Power = DEFAULT_RF_TX_POWER; - pAd->TxPower[3 * i + choffset + 0].Power2 = DEFAULT_RF_TX_POWER; - - pAd->TxPower[3 * i + choffset + 1].Channel = 149 + i * 8 + 2; - pAd->TxPower[3 * i + choffset + 1].Power = DEFAULT_RF_TX_POWER; - pAd->TxPower[3 * i + choffset + 1].Power2 = DEFAULT_RF_TX_POWER; - - pAd->TxPower[3 * i + choffset + 2].Channel = 149 + i * 8 + 4; - pAd->TxPower[3 * i + choffset + 2].Power = DEFAULT_RF_TX_POWER; - pAd->TxPower[3 * i + choffset + 2].Power2 = DEFAULT_RF_TX_POWER; - } - pAd->TxPower[3 * 2 + choffset + 0].Channel = 165; - pAd->TxPower[3 * 2 + choffset + 0].Power = DEFAULT_RF_TX_POWER; - pAd->TxPower[3 * 2 + choffset + 0].Power2 = DEFAULT_RF_TX_POWER; - - // 3.2 Fill up power - for (i = 0; i < 4; i++) - { -// Power.word = RTMP_EEPROM_READ16(pAd, EEPROM_A_TX_PWR_OFFSET + (choffset - 14) + i * 2); -// Power2.word = RTMP_EEPROM_READ16(pAd, EEPROM_A_TX2_PWR_OFFSET + (choffset - 14) + i * 2); - RT28xx_EEPROM_READ16(pAd, EEPROM_A_TX_PWR_OFFSET + (choffset - 14) + i * 2, Power.word); - RT28xx_EEPROM_READ16(pAd, EEPROM_A_TX2_PWR_OFFSET + (choffset - 14) + i * 2, Power2.word); - - if ((Power.field.Byte0 < 16) && (Power.field.Byte0 >= -7)) - pAd->TxPower[i * 2 + choffset + 0].Power = Power.field.Byte0; - - if ((Power.field.Byte1 < 16) && (Power.field.Byte1 >= -7)) - pAd->TxPower[i * 2 + choffset + 1].Power = Power.field.Byte1; - - if ((Power2.field.Byte0 < 16) && (Power2.field.Byte0 >= -7)) - pAd->TxPower[i * 2 + choffset + 0].Power2 = Power2.field.Byte0; - - if ((Power2.field.Byte1 < 16) && (Power2.field.Byte1 >= -7)) - pAd->TxPower[i * 2 + choffset + 1].Power2 = Power2.field.Byte1; - } - - // 4. Print and Debug - choffset = 14 + 12 + 16 + 7; - -} - -/* - ======================================================================== - - Routine Description: - Read the following from the registry - 1. All the parameters - 2. NetworkAddres - - Arguments: - Adapter Pointer to our adapter - WrapperConfigurationContext For use by NdisOpenConfiguration - - Return Value: - NDIS_STATUS_SUCCESS - NDIS_STATUS_FAILURE - NDIS_STATUS_RESOURCES - - IRQL = PASSIVE_LEVEL - - Note: - - ======================================================================== -*/ -NDIS_STATUS NICReadRegParameters( - IN PRTMP_ADAPTER pAd, - IN NDIS_HANDLE WrapperConfigurationContext - ) -{ - NDIS_STATUS Status = NDIS_STATUS_SUCCESS; - DBGPRINT_S(Status, ("<-- NICReadRegParameters, Status=%x\n", Status)); - return Status; -} - - -#ifdef RT30xx -/* - ======================================================================== - - Routine Description: - For RF filter calibration purpose - - Arguments: - pAd Pointer to our adapter - - Return Value: - None - - IRQL = PASSIVE_LEVEL - - ======================================================================== -*/ -VOID RTMPFilterCalibration( - IN PRTMP_ADAPTER pAd) -{ - UCHAR R55x = 0, value, FilterTarget = 0x1E, BBPValue=0; - UINT loop = 0, count = 0, loopcnt = 0, ReTry = 0; - UCHAR RF_R24_Value = 0; - - // Give bbp filter initial value - pAd->Mlme.CaliBW20RfR24 = 0x1F; - pAd->Mlme.CaliBW40RfR24 = 0x2F; //Bit[5] must be 1 for BW 40 - - do - { - if (loop == 1) //BandWidth = 40 MHz - { - // Write 0x27 to RF_R24 to program filter - RF_R24_Value = 0x27; - RT30xxWriteRFRegister(pAd, RF_R24, RF_R24_Value); - if (IS_RT3090(pAd)) - FilterTarget = 0x15; - else - FilterTarget = 0x19; - - // when calibrate BW40, BBP mask must set to BW40. - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); - BBPValue&= (~0x18); - BBPValue|= (0x10); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); - - // set to BW40 - RT30xxReadRFRegister(pAd, RF_R31, &value); - value |= 0x20; - RT30xxWriteRFRegister(pAd, RF_R31, value); - } - else //BandWidth = 20 MHz - { - // Write 0x07 to RF_R24 to program filter - RF_R24_Value = 0x07; - RT30xxWriteRFRegister(pAd, RF_R24, RF_R24_Value); - if (IS_RT3090(pAd)) - FilterTarget = 0x13; - else - FilterTarget = 0x16; - - // set to BW20 - RT30xxReadRFRegister(pAd, RF_R31, &value); - value &= (~0x20); - RT30xxWriteRFRegister(pAd, RF_R31, value); - } - - // Write 0x01 to RF_R22 to enable baseband loopback mode - RT30xxReadRFRegister(pAd, RF_R22, &value); - value |= 0x01; - RT30xxWriteRFRegister(pAd, RF_R22, value); - - // Write 0x00 to BBP_R24 to set power & frequency of passband test tone - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R24, 0); - - do - { - // Write 0x90 to BBP_R25 to transmit test tone - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R25, 0x90); - - RTMPusecDelay(1000); - // Read BBP_R55[6:0] for received power, set R55x = BBP_R55[6:0] - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R55, &value); - R55x = value & 0xFF; - - } while ((ReTry++ < 100) && (R55x == 0)); - - // Write 0x06 to BBP_R24 to set power & frequency of stopband test tone - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R24, 0x06); - - while(TRUE) - { - // Write 0x90 to BBP_R25 to transmit test tone - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R25, 0x90); - - //We need to wait for calibration - RTMPusecDelay(1000); - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R55, &value); - value &= 0xFF; - if ((R55x - value) < FilterTarget) - { - RF_R24_Value ++; - } - else if ((R55x - value) == FilterTarget) - { - RF_R24_Value ++; - count ++; - } - else - { - break; - } - - // prevent infinite loop cause driver hang. - if (loopcnt++ > 100) - { - DBGPRINT(RT_DEBUG_ERROR, ("RTMPFilterCalibration - can't find a valid value, loopcnt=%d stop calibrating", loopcnt)); - break; - } - - // Write RF_R24 to program filter - RT30xxWriteRFRegister(pAd, RF_R24, RF_R24_Value); - } - - if (count > 0) - { - RF_R24_Value = RF_R24_Value - ((count) ? (1) : (0)); - } - - // Store for future usage - if (loopcnt < 100) - { - if (loop++ == 0) - { - //BandWidth = 20 MHz - pAd->Mlme.CaliBW20RfR24 = (UCHAR)RF_R24_Value; - } - else - { - //BandWidth = 40 MHz - pAd->Mlme.CaliBW40RfR24 = (UCHAR)RF_R24_Value; - break; - } - } - else - break; - - RT30xxWriteRFRegister(pAd, RF_R24, RF_R24_Value); - - // reset count - count = 0; - } while(TRUE); - - // - // Set back to initial state - // - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R24, 0); - - RT30xxReadRFRegister(pAd, RF_R22, &value); - value &= ~(0x01); - RT30xxWriteRFRegister(pAd, RF_R22, value); - - // set BBP back to BW20 - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); - BBPValue&= (~0x18); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); - - DBGPRINT(RT_DEBUG_TRACE, ("RTMPFilterCalibration - CaliBW20RfR24=0x%x, CaliBW40RfR24=0x%x\n", pAd->Mlme.CaliBW20RfR24, pAd->Mlme.CaliBW40RfR24)); -} -#endif // RT30xx // - - -#ifdef RT3070 -VOID NICInitRT30xxRFRegisters(IN PRTMP_ADAPTER pAd) -{ - INT i; - // Driver must read EEPROM to get RfIcType before initial RF registers - // Initialize RF register to default value - if (IS_RT3070(pAd) || IS_RT3071(pAd)) - { - // Init RF calibration - // Driver should toggle RF R30 bit7 before init RF registers - UINT32 RfReg = 0; - UINT32 data; - - RT30xxReadRFRegister(pAd, RF_R30, (PUCHAR)&RfReg); - RfReg |= 0x80; - RT30xxWriteRFRegister(pAd, RF_R30, (UCHAR)RfReg); - RTMPusecDelay(1000); - RfReg &= 0x7F; - RT30xxWriteRFRegister(pAd, RF_R30, (UCHAR)RfReg); - - // Initialize RF register to default value - for (i = 0; i < NUM_RF_REG_PARMS; i++) - { - RT30xxWriteRFRegister(pAd, RT30xx_RFRegTable[i].Register, RT30xx_RFRegTable[i].Value); - } - - // add by johnli - if (IS_RT3070(pAd)) - { - // Update MAC 0x05D4 from 01xxxxxx to 0Dxxxxxx (voltage 1.2V to 1.35V) for RT3070 to improve yield rate - RTUSBReadMACRegister(pAd, LDO_CFG0, &data); - data = ((data & 0xF0FFFFFF) | 0x0D000000); - RTUSBWriteMACRegister(pAd, LDO_CFG0, data); - } - else if (IS_RT3071(pAd)) - { - // Driver should set RF R6 bit6 on before init RF registers - RT30xxReadRFRegister(pAd, RF_R06, (PUCHAR)&RfReg); - RfReg |= 0x40; - RT30xxWriteRFRegister(pAd, RF_R06, (UCHAR)RfReg); - - // init R31 - RT30xxWriteRFRegister(pAd, RF_R31, 0x14); - - // RT3071 version E has fixed this issue - if ((pAd->NicConfig2.field.DACTestBit == 1) && ((pAd->MACVersion & 0xffff) < 0x0211)) - { - // patch tx EVM issue temporarily - RTUSBReadMACRegister(pAd, LDO_CFG0, &data); - data = ((data & 0xE0FFFFFF) | 0x0D000000); - RTUSBWriteMACRegister(pAd, LDO_CFG0, data); - } - else - { - RTMP_IO_READ32(pAd, LDO_CFG0, &data); - data = ((data & 0xE0FFFFFF) | 0x01000000); - RTMP_IO_WRITE32(pAd, LDO_CFG0, data); - } - - // patch LNA_PE_G1 failed issue - RTUSBReadMACRegister(pAd, GPIO_SWITCH, &data); - data &= ~(0x20); - RTUSBWriteMACRegister(pAd, GPIO_SWITCH, data); - } - - //For RF filter Calibration - RTMPFilterCalibration(pAd); - - // Initialize RF R27 register, set RF R27 must be behind RTMPFilterCalibration() - if ((pAd->MACVersion & 0xffff) < 0x0211) - RT30xxWriteRFRegister(pAd, RF_R27, 0x3); - - // set led open drain enable - RTUSBReadMACRegister(pAd, OPT_14, &data); - data |= 0x01; - RTUSBWriteMACRegister(pAd, OPT_14, data); - - if (IS_RT3071(pAd)) - { - // add by johnli, RF power sequence setup, load RF normal operation-mode setup - RT30xxLoadRFNormalModeSetup(pAd); - } - } - -} -#endif // RT3070 // - - -/* - ======================================================================== - - Routine Description: - Read initial parameters from EEPROM - - Arguments: - Adapter Pointer to our adapter - - Return Value: - None - - IRQL = PASSIVE_LEVEL - - Note: - - ======================================================================== -*/ -VOID NICReadEEPROMParameters( - IN PRTMP_ADAPTER pAd, - IN PUCHAR mac_addr) -{ - UINT32 data = 0; - USHORT i, value, value2; - UCHAR TmpPhy; - EEPROM_TX_PWR_STRUC Power; - EEPROM_VERSION_STRUC Version; - EEPROM_ANTENNA_STRUC Antenna; - EEPROM_NIC_CONFIG2_STRUC NicConfig2; - - DBGPRINT(RT_DEBUG_TRACE, ("--> NICReadEEPROMParameters\n")); - - // Init EEPROM Address Number, before access EEPROM; if 93c46, EEPROMAddressNum=6, else if 93c66, EEPROMAddressNum=8 - RTMP_IO_READ32(pAd, E2PROM_CSR, &data); - DBGPRINT(RT_DEBUG_TRACE, ("--> E2PROM_CSR = 0x%x\n", data)); - - if((data & 0x30) == 0) - pAd->EEPROMAddressNum = 6; // 93C46 - else if((data & 0x30) == 0x10) - pAd->EEPROMAddressNum = 8; // 93C66 - else - pAd->EEPROMAddressNum = 8; // 93C86 - DBGPRINT(RT_DEBUG_TRACE, ("--> EEPROMAddressNum = %d\n", pAd->EEPROMAddressNum )); - - // RT2860 MAC no longer auto load MAC address from E2PROM. Driver has to intialize - // MAC address registers according to E2PROM setting - if (mac_addr == NULL || - strlen(mac_addr) != 17 || - mac_addr[2] != ':' || mac_addr[5] != ':' || mac_addr[8] != ':' || - mac_addr[11] != ':' || mac_addr[14] != ':') - { - USHORT Addr01,Addr23,Addr45 ; - - RT28xx_EEPROM_READ16(pAd, 0x04, Addr01); - RT28xx_EEPROM_READ16(pAd, 0x06, Addr23); - RT28xx_EEPROM_READ16(pAd, 0x08, Addr45); - - pAd->PermanentAddress[0] = (UCHAR)(Addr01 & 0xff); - pAd->PermanentAddress[1] = (UCHAR)(Addr01 >> 8); - pAd->PermanentAddress[2] = (UCHAR)(Addr23 & 0xff); - pAd->PermanentAddress[3] = (UCHAR)(Addr23 >> 8); - pAd->PermanentAddress[4] = (UCHAR)(Addr45 & 0xff); - pAd->PermanentAddress[5] = (UCHAR)(Addr45 >> 8); - - DBGPRINT(RT_DEBUG_TRACE, ("Initialize MAC Address from E2PROM \n")); - } - else - { - INT j; - PUCHAR macptr; - - macptr = mac_addr; - - for (j=0; jPermanentAddress[j], 1); - macptr=macptr+3; - } - - DBGPRINT(RT_DEBUG_TRACE, ("Initialize MAC Address from module parameter \n")); - } - - - { - //more conveninet to test mbssid, so ap's bssid &0xf1 - if (pAd->PermanentAddress[0] == 0xff) - pAd->PermanentAddress[0] = RandomByte(pAd)&0xf8; - - //if (pAd->PermanentAddress[5] == 0xff) - // pAd->PermanentAddress[5] = RandomByte(pAd)&0xf8; - - DBGPRINT_RAW(RT_DEBUG_TRACE,("E2PROM MAC: =%02x:%02x:%02x:%02x:%02x:%02x\n", - pAd->PermanentAddress[0], pAd->PermanentAddress[1], - pAd->PermanentAddress[2], pAd->PermanentAddress[3], - pAd->PermanentAddress[4], pAd->PermanentAddress[5])); - if (pAd->bLocalAdminMAC == FALSE) - { - MAC_DW0_STRUC csr2; - MAC_DW1_STRUC csr3; - COPY_MAC_ADDR(pAd->CurrentAddress, pAd->PermanentAddress); - csr2.field.Byte0 = pAd->CurrentAddress[0]; - csr2.field.Byte1 = pAd->CurrentAddress[1]; - csr2.field.Byte2 = pAd->CurrentAddress[2]; - csr2.field.Byte3 = pAd->CurrentAddress[3]; - RTMP_IO_WRITE32(pAd, MAC_ADDR_DW0, csr2.word); - csr3.word = 0; - csr3.field.Byte4 = pAd->CurrentAddress[4]; - csr3.field.Byte5 = pAd->CurrentAddress[5]; - csr3.field.U2MeMask = 0xff; - RTMP_IO_WRITE32(pAd, MAC_ADDR_DW1, csr3.word); - DBGPRINT_RAW(RT_DEBUG_TRACE,("E2PROM MAC: =%02x:%02x:%02x:%02x:%02x:%02x\n", - pAd->PermanentAddress[0], pAd->PermanentAddress[1], - pAd->PermanentAddress[2], pAd->PermanentAddress[3], - pAd->PermanentAddress[4], pAd->PermanentAddress[5])); - } - } - - // if not return early. cause fail at emulation. - // Init the channel number for TX channel power - RTMPReadChannelPwr(pAd); - - // if E2PROM version mismatch with driver's expectation, then skip - // all subsequent E2RPOM retieval and set a system error bit to notify GUI - RT28xx_EEPROM_READ16(pAd, EEPROM_VERSION_OFFSET, Version.word); - pAd->EepromVersion = Version.field.Version + Version.field.FaeReleaseNumber * 256; - DBGPRINT(RT_DEBUG_TRACE, ("E2PROM: Version = %d, FAE release #%d\n", Version.field.Version, Version.field.FaeReleaseNumber)); - - if (Version.field.Version > VALID_EEPROM_VERSION) - { - DBGPRINT_ERR(("E2PROM: WRONG VERSION 0x%x, should be %d\n",Version.field.Version, VALID_EEPROM_VERSION)); - /*pAd->SystemErrorBitmap |= 0x00000001; - - // hard-code default value when no proper E2PROM installed - pAd->bAutoTxAgcA = FALSE; - pAd->bAutoTxAgcG = FALSE; - - // Default the channel power - for (i = 0; i < MAX_NUM_OF_CHANNELS; i++) - pAd->TxPower[i].Power = DEFAULT_RF_TX_POWER; - - // Default the channel power - for (i = 0; i < MAX_NUM_OF_11JCHANNELS; i++) - pAd->TxPower11J[i].Power = DEFAULT_RF_TX_POWER; - - for(i = 0; i < NUM_EEPROM_BBP_PARMS; i++) - pAd->EEPROMDefaultValue[i] = 0xffff; - return; */ - } - - // Read BBP default value from EEPROM and store to array(EEPROMDefaultValue) in pAd - RT28xx_EEPROM_READ16(pAd, EEPROM_NIC1_OFFSET, value); - pAd->EEPROMDefaultValue[0] = value; - - RT28xx_EEPROM_READ16(pAd, EEPROM_NIC2_OFFSET, value); - pAd->EEPROMDefaultValue[1] = value; - - RT28xx_EEPROM_READ16(pAd, 0x38, value); // Country Region - pAd->EEPROMDefaultValue[2] = value; - - for(i = 0; i < 8; i++) - { - RT28xx_EEPROM_READ16(pAd, EEPROM_BBP_BASE_OFFSET + i*2, value); - pAd->EEPROMDefaultValue[i+3] = value; - } - - // We have to parse NIC configuration 0 at here. - // If TSSI did not have preloaded value, it should reset the TxAutoAgc to false - // Therefore, we have to read TxAutoAgc control beforehand. - // Read Tx AGC control bit - Antenna.word = pAd->EEPROMDefaultValue[0]; - if (Antenna.word == 0xFFFF) - { -#ifdef RT30xx - if(IS_RT3090(pAd)) - { - Antenna.word = 0; - Antenna.field.RfIcType = RFIC_3020; - Antenna.field.TxPath = 1; - Antenna.field.RxPath = 1; - } - else - { -#endif // RT30xx // - Antenna.word = 0; - Antenna.field.RfIcType = RFIC_2820; - Antenna.field.TxPath = 1; - Antenna.field.RxPath = 2; - DBGPRINT(RT_DEBUG_WARN, ("E2PROM error, hard code as 0x%04x\n", Antenna.word)); -#ifdef RT30xx - } -#endif // RT30xx // - } - - // Choose the desired Tx&Rx stream. - if ((pAd->CommonCfg.TxStream == 0) || (pAd->CommonCfg.TxStream > Antenna.field.TxPath)) - pAd->CommonCfg.TxStream = Antenna.field.TxPath; - - if ((pAd->CommonCfg.RxStream == 0) || (pAd->CommonCfg.RxStream > Antenna.field.RxPath)) - { - pAd->CommonCfg.RxStream = Antenna.field.RxPath; - - if ((pAd->MACVersion < RALINK_2883_VERSION) && - (pAd->CommonCfg.RxStream > 2)) - { - // only 2 Rx streams for RT2860 series - pAd->CommonCfg.RxStream = 2; - } - } - - // 3*3 - // read value from EEPROM and set them to CSR174 ~ 177 in chain0 ~ chain2 - // yet implement - for(i=0; i<3; i++) - { - } - - NicConfig2.word = pAd->EEPROMDefaultValue[1]; - - - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - if ((NicConfig2.word & 0x00ff) == 0xff) - { - NicConfig2.word &= 0xff00; - } - - if ((NicConfig2.word >> 8) == 0xff) - { - NicConfig2.word &= 0x00ff; - } - } -#endif // CONFIG_STA_SUPPORT // - - if (NicConfig2.field.DynamicTxAgcControl == 1) - pAd->bAutoTxAgcA = pAd->bAutoTxAgcG = TRUE; - else - pAd->bAutoTxAgcA = pAd->bAutoTxAgcG = FALSE; - - DBGPRINT_RAW(RT_DEBUG_TRACE, ("NICReadEEPROMParameters: RxPath = %d, TxPath = %d\n", Antenna.field.RxPath, Antenna.field.TxPath)); - - // Save the antenna for future use - pAd->Antenna.word = Antenna.word; - - // - // Reset PhyMode if we don't support 802.11a - // Only RFIC_2850 & RFIC_2750 support 802.11a - // - if ((Antenna.field.RfIcType != RFIC_2850) && (Antenna.field.RfIcType != RFIC_2750)) - { - if ((pAd->CommonCfg.PhyMode == PHY_11ABG_MIXED) || - (pAd->CommonCfg.PhyMode == PHY_11A)) - pAd->CommonCfg.PhyMode = PHY_11BG_MIXED; -#ifdef DOT11_N_SUPPORT - else if ((pAd->CommonCfg.PhyMode == PHY_11ABGN_MIXED) || - (pAd->CommonCfg.PhyMode == PHY_11AN_MIXED) || - (pAd->CommonCfg.PhyMode == PHY_11AGN_MIXED) || - (pAd->CommonCfg.PhyMode == PHY_11N_5G)) - pAd->CommonCfg.PhyMode = PHY_11BGN_MIXED; -#endif // DOT11_N_SUPPORT // - } - - // Read TSSI reference and TSSI boundary for temperature compensation. This is ugly - // 0. 11b/g - { - /* these are tempature reference value (0x00 ~ 0xFE) - ex: 0x00 0x15 0x25 0x45 0x88 0xA0 0xB5 0xD0 0xF0 - TssiPlusBoundaryG [4] [3] [2] [1] [0] (smaller) + - TssiMinusBoundaryG[0] [1] [2] [3] [4] (larger) */ - RT28xx_EEPROM_READ16(pAd, 0x6E, Power.word); - pAd->TssiMinusBoundaryG[4] = Power.field.Byte0; - pAd->TssiMinusBoundaryG[3] = Power.field.Byte1; - RT28xx_EEPROM_READ16(pAd, 0x70, Power.word); - pAd->TssiMinusBoundaryG[2] = Power.field.Byte0; - pAd->TssiMinusBoundaryG[1] = Power.field.Byte1; - RT28xx_EEPROM_READ16(pAd, 0x72, Power.word); - pAd->TssiRefG = Power.field.Byte0; /* reference value [0] */ - pAd->TssiPlusBoundaryG[1] = Power.field.Byte1; - RT28xx_EEPROM_READ16(pAd, 0x74, Power.word); - pAd->TssiPlusBoundaryG[2] = Power.field.Byte0; - pAd->TssiPlusBoundaryG[3] = Power.field.Byte1; - RT28xx_EEPROM_READ16(pAd, 0x76, Power.word); - pAd->TssiPlusBoundaryG[4] = Power.field.Byte0; - pAd->TxAgcStepG = Power.field.Byte1; - pAd->TxAgcCompensateG = 0; - pAd->TssiMinusBoundaryG[0] = pAd->TssiRefG; - pAd->TssiPlusBoundaryG[0] = pAd->TssiRefG; - - // Disable TxAgc if the based value is not right - if (pAd->TssiRefG == 0xff) - pAd->bAutoTxAgcG = FALSE; - - DBGPRINT(RT_DEBUG_TRACE,("E2PROM: G Tssi[-4 .. +4] = %d %d %d %d - %d -%d %d %d %d, step=%d, tuning=%d\n", - pAd->TssiMinusBoundaryG[4], pAd->TssiMinusBoundaryG[3], pAd->TssiMinusBoundaryG[2], pAd->TssiMinusBoundaryG[1], - pAd->TssiRefG, - pAd->TssiPlusBoundaryG[1], pAd->TssiPlusBoundaryG[2], pAd->TssiPlusBoundaryG[3], pAd->TssiPlusBoundaryG[4], - pAd->TxAgcStepG, pAd->bAutoTxAgcG)); - } - // 1. 11a - { - RT28xx_EEPROM_READ16(pAd, 0xD4, Power.word); - pAd->TssiMinusBoundaryA[4] = Power.field.Byte0; - pAd->TssiMinusBoundaryA[3] = Power.field.Byte1; - RT28xx_EEPROM_READ16(pAd, 0xD6, Power.word); - pAd->TssiMinusBoundaryA[2] = Power.field.Byte0; - pAd->TssiMinusBoundaryA[1] = Power.field.Byte1; - RT28xx_EEPROM_READ16(pAd, 0xD8, Power.word); - pAd->TssiRefA = Power.field.Byte0; - pAd->TssiPlusBoundaryA[1] = Power.field.Byte1; - RT28xx_EEPROM_READ16(pAd, 0xDA, Power.word); - pAd->TssiPlusBoundaryA[2] = Power.field.Byte0; - pAd->TssiPlusBoundaryA[3] = Power.field.Byte1; - RT28xx_EEPROM_READ16(pAd, 0xDC, Power.word); - pAd->TssiPlusBoundaryA[4] = Power.field.Byte0; - pAd->TxAgcStepA = Power.field.Byte1; - pAd->TxAgcCompensateA = 0; - pAd->TssiMinusBoundaryA[0] = pAd->TssiRefA; - pAd->TssiPlusBoundaryA[0] = pAd->TssiRefA; - - // Disable TxAgc if the based value is not right - if (pAd->TssiRefA == 0xff) - pAd->bAutoTxAgcA = FALSE; - - DBGPRINT(RT_DEBUG_TRACE,("E2PROM: A Tssi[-4 .. +4] = %d %d %d %d - %d -%d %d %d %d, step=%d, tuning=%d\n", - pAd->TssiMinusBoundaryA[4], pAd->TssiMinusBoundaryA[3], pAd->TssiMinusBoundaryA[2], pAd->TssiMinusBoundaryA[1], - pAd->TssiRefA, - pAd->TssiPlusBoundaryA[1], pAd->TssiPlusBoundaryA[2], pAd->TssiPlusBoundaryA[3], pAd->TssiPlusBoundaryA[4], - pAd->TxAgcStepA, pAd->bAutoTxAgcA)); - } - pAd->BbpRssiToDbmDelta = 0x0; - - // Read frequency offset setting for RF - RT28xx_EEPROM_READ16(pAd, EEPROM_FREQ_OFFSET, value); - if ((value & 0x00FF) != 0x00FF) - pAd->RfFreqOffset = (ULONG) (value & 0x00FF); - else - pAd->RfFreqOffset = 0; - DBGPRINT(RT_DEBUG_TRACE, ("E2PROM: RF FreqOffset=0x%lx \n", pAd->RfFreqOffset)); - - //CountryRegion byte offset (38h) - value = pAd->EEPROMDefaultValue[2] >> 8; // 2.4G band - value2 = pAd->EEPROMDefaultValue[2] & 0x00FF; // 5G band - - if ((value <= REGION_MAXIMUM_BG_BAND) && (value2 <= REGION_MAXIMUM_A_BAND)) - { - pAd->CommonCfg.CountryRegion = ((UCHAR) value) | 0x80; - pAd->CommonCfg.CountryRegionForABand = ((UCHAR) value2) | 0x80; - TmpPhy = pAd->CommonCfg.PhyMode; - pAd->CommonCfg.PhyMode = 0xff; - RTMPSetPhyMode(pAd, TmpPhy); -#ifdef DOT11_N_SUPPORT - SetCommonHT(pAd); -#endif // DOT11_N_SUPPORT // - } - - // - // Get RSSI Offset on EEPROM 0x9Ah & 0x9Ch. - // The valid value are (-10 ~ 10) - // - RT28xx_EEPROM_READ16(pAd, EEPROM_RSSI_BG_OFFSET, value); - pAd->BGRssiOffset0 = value & 0x00ff; - pAd->BGRssiOffset1 = (value >> 8); - RT28xx_EEPROM_READ16(pAd, EEPROM_RSSI_BG_OFFSET+2, value); - pAd->BGRssiOffset2 = value & 0x00ff; - pAd->ALNAGain1 = (value >> 8); - RT28xx_EEPROM_READ16(pAd, EEPROM_LNA_OFFSET, value); - pAd->BLNAGain = value & 0x00ff; - pAd->ALNAGain0 = (value >> 8); - - // Validate 11b/g RSSI_0 offset. - if ((pAd->BGRssiOffset0 < -10) || (pAd->BGRssiOffset0 > 10)) - pAd->BGRssiOffset0 = 0; - - // Validate 11b/g RSSI_1 offset. - if ((pAd->BGRssiOffset1 < -10) || (pAd->BGRssiOffset1 > 10)) - pAd->BGRssiOffset1 = 0; - - // Validate 11b/g RSSI_2 offset. - if ((pAd->BGRssiOffset2 < -10) || (pAd->BGRssiOffset2 > 10)) - pAd->BGRssiOffset2 = 0; - - RT28xx_EEPROM_READ16(pAd, EEPROM_RSSI_A_OFFSET, value); - pAd->ARssiOffset0 = value & 0x00ff; - pAd->ARssiOffset1 = (value >> 8); - RT28xx_EEPROM_READ16(pAd, (EEPROM_RSSI_A_OFFSET+2), value); - pAd->ARssiOffset2 = value & 0x00ff; - pAd->ALNAGain2 = (value >> 8); - - if (((UCHAR)pAd->ALNAGain1 == 0xFF) || (pAd->ALNAGain1 == 0x00)) - pAd->ALNAGain1 = pAd->ALNAGain0; - if (((UCHAR)pAd->ALNAGain2 == 0xFF) || (pAd->ALNAGain2 == 0x00)) - pAd->ALNAGain2 = pAd->ALNAGain0; - - // Validate 11a RSSI_0 offset. - if ((pAd->ARssiOffset0 < -10) || (pAd->ARssiOffset0 > 10)) - pAd->ARssiOffset0 = 0; - - // Validate 11a RSSI_1 offset. - if ((pAd->ARssiOffset1 < -10) || (pAd->ARssiOffset1 > 10)) - pAd->ARssiOffset1 = 0; - - //Validate 11a RSSI_2 offset. - if ((pAd->ARssiOffset2 < -10) || (pAd->ARssiOffset2 > 10)) - pAd->ARssiOffset2 = 0; - - // - // Get LED Setting. - // - RT28xx_EEPROM_READ16(pAd, 0x3a, value); - pAd->LedCntl.word = (value&0xff00) >> 8; - RT28xx_EEPROM_READ16(pAd, EEPROM_LED1_OFFSET, value); - pAd->Led1 = value; - RT28xx_EEPROM_READ16(pAd, EEPROM_LED2_OFFSET, value); - pAd->Led2 = value; - RT28xx_EEPROM_READ16(pAd, EEPROM_LED3_OFFSET, value); - pAd->Led3 = value; - - RTMPReadTxPwrPerRate(pAd); - -#ifdef SINGLE_SKU - //pAd->CommonCfg.DefineMaxTxPwr = RTMP_EEPROM_READ16(pAd, EEPROM_DEFINE_MAX_TXPWR); - RT28xx_EEPROM_READ16(pAd, EEPROM_DEFINE_MAX_TXPWR, pAd->CommonCfg.DefineMaxTxPwr); -#endif // SINGLE_SKU // -#ifdef RT30xx - if (IS_RT30xx(pAd)) - { - eFusePhysicalReadRegisters(pAd, EFUSE_TAG, 2, &value); - pAd->EFuseTag = (value & 0xff); - } -#endif // RT30xx // - - DBGPRINT(RT_DEBUG_TRACE, ("<-- NICReadEEPROMParameters\n")); -} - -/* - ======================================================================== - - Routine Description: - Set default value from EEPROM - - Arguments: - Adapter Pointer to our adapter - - Return Value: - None - - IRQL = PASSIVE_LEVEL - - Note: - - ======================================================================== -*/ -VOID NICInitAsicFromEEPROM( - IN PRTMP_ADAPTER pAd) -{ -#ifdef CONFIG_STA_SUPPORT - UINT32 data = 0; - UCHAR BBPR1 = 0; -#endif // CONFIG_STA_SUPPORT // - USHORT i; - EEPROM_ANTENNA_STRUC Antenna; - EEPROM_NIC_CONFIG2_STRUC NicConfig2; - UCHAR BBPR3 = 0; - - DBGPRINT(RT_DEBUG_TRACE, ("--> NICInitAsicFromEEPROM\n")); - for(i = 3; i < NUM_EEPROM_BBP_PARMS; i++) - { - UCHAR BbpRegIdx, BbpValue; - - if ((pAd->EEPROMDefaultValue[i] != 0xFFFF) && (pAd->EEPROMDefaultValue[i] != 0)) - { - BbpRegIdx = (UCHAR)(pAd->EEPROMDefaultValue[i] >> 8); - BbpValue = (UCHAR)(pAd->EEPROMDefaultValue[i] & 0xff); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BbpRegIdx, BbpValue); - } - } - - Antenna.word = pAd->EEPROMDefaultValue[0]; - if (Antenna.word == 0xFFFF) - { - DBGPRINT(RT_DEBUG_ERROR, ("E2PROM error, hard code as 0x%04x\n", Antenna.word)); - BUG_ON(Antenna.word == 0xFFFF); - } - pAd->Mlme.RealRxPath = (UCHAR) Antenna.field.RxPath; - pAd->RfIcType = (UCHAR) Antenna.field.RfIcType; - - DBGPRINT(RT_DEBUG_WARN, ("pAd->RfIcType = %d, RealRxPath=%d, TxPath = %d\n", pAd->RfIcType, pAd->Mlme.RealRxPath,Antenna.field.TxPath)); - - // Save the antenna for future use - pAd->Antenna.word = Antenna.word; - - NicConfig2.word = pAd->EEPROMDefaultValue[1]; - - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - if ((NicConfig2.word & 0x00ff) == 0xff) - { - NicConfig2.word &= 0xff00; - } - - if ((NicConfig2.word >> 8) == 0xff) - { - NicConfig2.word &= 0x00ff; - } - } -#endif // CONFIG_STA_SUPPORT // - - // Save the antenna for future use - pAd->NicConfig2.word = NicConfig2.word; - - // set default antenna as main - if (pAd->RfIcType == RFIC_3020) - AsicSetRxAnt(pAd, pAd->RxAnt.Pair1PrimaryRxAnt); - - // - // Send LED Setting to MCU. - // - if (pAd->LedCntl.word == 0xFF) - { - pAd->LedCntl.word = 0x01; - pAd->Led1 = 0x5555; - pAd->Led2 = 0x2221; - -#ifdef RT2870 - pAd->Led3 = 0x5627; -#endif // RT2870 // - } - - AsicSendCommandToMcu(pAd, 0x52, 0xff, (UCHAR)pAd->Led1, (UCHAR)(pAd->Led1 >> 8)); - AsicSendCommandToMcu(pAd, 0x53, 0xff, (UCHAR)pAd->Led2, (UCHAR)(pAd->Led2 >> 8)); - AsicSendCommandToMcu(pAd, 0x54, 0xff, (UCHAR)pAd->Led3, (UCHAR)(pAd->Led3 >> 8)); - pAd->LedIndicatorStregth = 0xFF; - RTMPSetSignalLED(pAd, -100); // Force signal strength Led to be turned off, before link up - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - // Read Hardware controlled Radio state enable bit - if (NicConfig2.field.HardwareRadioControl == 1) - { - pAd->StaCfg.bHardwareRadio = TRUE; - - // Read GPIO pin2 as Hardware controlled radio state - RTMP_IO_READ32(pAd, GPIO_CTRL_CFG, &data); - if ((data & 0x04) == 0) - { - pAd->StaCfg.bHwRadio = FALSE; - pAd->StaCfg.bRadio = FALSE; -// RTMP_IO_WRITE32(pAd, PWR_PIN_CFG, 0x00001818); - RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF); - } - } - else - pAd->StaCfg.bHardwareRadio = FALSE; - - if (pAd->StaCfg.bRadio == FALSE) - { - RTMPSetLED(pAd, LED_RADIO_OFF); - } - else - { - RTMPSetLED(pAd, LED_RADIO_ON); - } - } -#endif // CONFIG_STA_SUPPORT // - - // Turn off patching for cardbus controller - if (NicConfig2.field.CardbusAcceleration == 1) - { -// pAd->bTest1 = TRUE; - } - - if (NicConfig2.field.DynamicTxAgcControl == 1) - pAd->bAutoTxAgcA = pAd->bAutoTxAgcG = TRUE; - else - pAd->bAutoTxAgcA = pAd->bAutoTxAgcG = FALSE; - // - // Since BBP has been progamed, to make sure BBP setting will be - // upate inside of AsicAntennaSelect, so reset to UNKNOWN_BAND!! - // - pAd->CommonCfg.BandState = UNKNOWN_BAND; - - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BBPR3); - BBPR3 &= (~0x18); - if(pAd->Antenna.field.RxPath == 3) - { - BBPR3 |= (0x10); - } - else if(pAd->Antenna.field.RxPath == 2) - { - BBPR3 |= (0x8); - } - else if(pAd->Antenna.field.RxPath == 1) - { - BBPR3 |= (0x0); - } - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BBPR3); - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - // Handle the difference when 1T - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R1, &BBPR1); - if(pAd->Antenna.field.TxPath == 1) - { - BBPR1 &= (~0x18); - } - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R1, BBPR1); - - DBGPRINT(RT_DEBUG_TRACE, ("Use Hw Radio Control Pin=%d; if used Pin=%d;\n", pAd->CommonCfg.bHardwareRadio, pAd->CommonCfg.bHardwareRadio)); - } -#endif // CONFIG_STA_SUPPORT // - DBGPRINT(RT_DEBUG_TRACE, ("TxPath = %d, RxPath = %d, RFIC=%d, Polar+LED mode=%x\n", pAd->Antenna.field.TxPath, pAd->Antenna.field.RxPath, pAd->RfIcType, pAd->LedCntl.word)); - DBGPRINT(RT_DEBUG_TRACE, ("<-- NICInitAsicFromEEPROM\n")); -} - -/* - ======================================================================== - - Routine Description: - Initialize NIC hardware - - Arguments: - Adapter Pointer to our adapter - - Return Value: - None - - IRQL = PASSIVE_LEVEL - - Note: - - ======================================================================== -*/ -NDIS_STATUS NICInitializeAdapter( - IN PRTMP_ADAPTER pAd, - IN BOOLEAN bHardReset) -{ - NDIS_STATUS Status = NDIS_STATUS_SUCCESS; - WPDMA_GLO_CFG_STRUC GloCfg; -// INT_MASK_CSR_STRUC IntMask; - ULONG i =0, j=0; - AC_TXOP_CSR0_STRUC csr0; - - DBGPRINT(RT_DEBUG_TRACE, ("--> NICInitializeAdapter\n")); - - // 3. Set DMA global configuration except TX_DMA_EN and RX_DMA_EN bits: -retry: - i = 0; - do - { - RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word); - if ((GloCfg.field.TxDMABusy == 0) && (GloCfg.field.RxDMABusy == 0)) - break; - - RTMPusecDelay(1000); - i++; - }while ( i<100); - DBGPRINT(RT_DEBUG_TRACE, ("<== DMA offset 0x208 = 0x%x\n", GloCfg.word)); - GloCfg.word &= 0xff0; - GloCfg.field.EnTXWriteBackDDONE =1; - RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, GloCfg.word); - - // Record HW Beacon offset - pAd->BeaconOffset[0] = HW_BEACON_BASE0; - pAd->BeaconOffset[1] = HW_BEACON_BASE1; - pAd->BeaconOffset[2] = HW_BEACON_BASE2; - pAd->BeaconOffset[3] = HW_BEACON_BASE3; - pAd->BeaconOffset[4] = HW_BEACON_BASE4; - pAd->BeaconOffset[5] = HW_BEACON_BASE5; - pAd->BeaconOffset[6] = HW_BEACON_BASE6; - pAd->BeaconOffset[7] = HW_BEACON_BASE7; - - // - // write all shared Ring's base address into ASIC - // - - // asic simulation sequence put this ahead before loading firmware. - // pbf hardware reset - - // Initialze ASIC for TX & Rx operation - if (NICInitializeAsic(pAd , bHardReset) != NDIS_STATUS_SUCCESS) - { - if (j++ == 0) - { - NICLoadFirmware(pAd); - goto retry; - } - return NDIS_STATUS_FAILURE; - } - - - - - // WMM parameter - csr0.word = 0; - RTMP_IO_WRITE32(pAd, WMM_TXOP0_CFG, csr0.word); - if (pAd->CommonCfg.PhyMode == PHY_11B) - { - csr0.field.Ac0Txop = 192; // AC_VI: 192*32us ~= 6ms - csr0.field.Ac1Txop = 96; // AC_VO: 96*32us ~= 3ms - } - else - { - csr0.field.Ac0Txop = 96; // AC_VI: 96*32us ~= 3ms - csr0.field.Ac1Txop = 48; // AC_VO: 48*32us ~= 1.5ms - } - RTMP_IO_WRITE32(pAd, WMM_TXOP1_CFG, csr0.word); - - - - - // reset action - // Load firmware - // Status = NICLoadFirmware(pAd); - - DBGPRINT(RT_DEBUG_TRACE, ("<-- NICInitializeAdapter\n")); - return Status; -} - -/* - ======================================================================== - - Routine Description: - Initialize ASIC - - Arguments: - Adapter Pointer to our adapter - - Return Value: - None - - IRQL = PASSIVE_LEVEL - - Note: - - ======================================================================== -*/ -NDIS_STATUS NICInitializeAsic( - IN PRTMP_ADAPTER pAd, - IN BOOLEAN bHardReset) -{ - ULONG Index = 0; - UCHAR R0 = 0xff; - UINT32 MacCsr12 = 0, Counter = 0; -#ifdef RT2870 - UINT32 MacCsr0 = 0; - NTSTATUS Status; - UCHAR Value = 0xff; -#endif // RT2870 // -#ifdef RT30xx - UINT32 eFuseCtrl; -#endif // RT30xx // - USHORT KeyIdx; - INT i,apidx; - - DBGPRINT(RT_DEBUG_TRACE, ("--> NICInitializeAsic\n")); - - -#ifdef RT2870 - // - // Make sure MAC gets ready after NICLoadFirmware(). - // - Index = 0; - - //To avoid hang-on issue when interface up in kernel 2.4, - //we use a local variable "MacCsr0" instead of using "pAd->MACVersion" directly. - do - { - RTMP_IO_READ32(pAd, MAC_CSR0, &MacCsr0); - - if ((MacCsr0 != 0x00) && (MacCsr0 != 0xFFFFFFFF)) - break; - - RTMPusecDelay(10); - } while (Index++ < 100); - - pAd->MACVersion = MacCsr0; - DBGPRINT(RT_DEBUG_TRACE, ("MAC_CSR0 [ Ver:Rev=0x%08x]\n", pAd->MACVersion)); - // turn on bit13 (set to zero) after rt2860D. This is to solve high-current issue. - RTMP_IO_READ32(pAd, PBF_SYS_CTRL, &MacCsr12); - MacCsr12 &= (~0x2000); - RTMP_IO_WRITE32(pAd, PBF_SYS_CTRL, MacCsr12); - - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x3); - RTMP_IO_WRITE32(pAd, USB_DMA_CFG, 0x0); - Status = RTUSBVenderReset(pAd); - - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x0); - - // Initialize MAC register to default value - for(Index=0; IndexMACVersion & 0xffff) < 0x0211) - { - if (pAd->NicConfig2.field.DACTestBit == 1) - { - RTMP_IO_WRITE32(pAd, TX_SW_CFG2, 0x1F); // To fix throughput drop drastically - } - else - { - RTMP_IO_WRITE32(pAd, TX_SW_CFG2, 0x0F); // To fix throughput drop drastically - } - } - else - { - RTMP_IO_WRITE32(pAd, TX_SW_CFG2, 0x0); - } - } - else if (IS_RT3070(pAd)) - { - RTMP_IO_WRITE32(pAd, TX_SW_CFG1, 0); - RTMP_IO_WRITE32(pAd, TX_SW_CFG2, 0x1F); // To fix throughput drop drastically - } -#endif // RT30xx // - - // - // Before program BBP, we need to wait BBP/RF get wake up. - // - Index = 0; - do - { - RTMP_IO_READ32(pAd, MAC_STATUS_CFG, &MacCsr12); - - if ((MacCsr12 & 0x03) == 0) // if BB.RF is stable - break; - - DBGPRINT(RT_DEBUG_TRACE, ("Check MAC_STATUS_CFG = Busy = %x\n", MacCsr12)); - RTMPusecDelay(1000); - } while (Index++ < 100); - - // The commands to firmware should be after these commands, these commands will init firmware - // PCI and USB are not the same because PCI driver needs to wait for PCI bus ready - RTMP_IO_WRITE32(pAd, H2M_BBP_AGENT, 0); // initialize BBP R/W access agent - RTMP_IO_WRITE32(pAd, H2M_MAILBOX_CSR, 0); - RTMPusecDelay(1000); - - // Read BBP register, make sure BBP is up and running before write new data - Index = 0; - do - { - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R0, &R0); - DBGPRINT(RT_DEBUG_TRACE, ("BBP version = %x\n", R0)); - } while ((++Index < 20) && ((R0 == 0xff) || (R0 == 0x00))); - //ASSERT(Index < 20); //this will cause BSOD on Check-build driver - - if ((R0 == 0xff) || (R0 == 0x00)) - return NDIS_STATUS_FAILURE; - - // Initialize BBP register to default value - for (Index = 0; Index < NUM_BBP_REG_PARMS; Index++) - { - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBPRegTable[Index].Register, BBPRegTable[Index].Value); - } - - // for rt2860E and after, init BBP_R84 with 0x19. This is for extension channel overlapping IOT. - // RT3090 should not program BBP R84 to 0x19, otherwise TX will block. - if (((pAd->MACVersion&0xffff) != 0x0101) && (!IS_RT30xx(pAd))) - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R84, 0x19); - -// add by johnli, RF power sequence setup -#ifdef RT30xx - if (IS_RT30xx(pAd)) - { //update for RT3070/71/72/90/91/92. - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R79, 0x13); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R80, 0x05); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R81, 0x33); - } - - if (IS_RT3090(pAd)) - { - UCHAR bbpreg=0; - - // enable DC filter - if ((pAd->MACVersion & 0xffff) >= 0x0211) - { - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R103, 0xc0); - } - - // improve power consumption - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R138, &bbpreg); - if (pAd->Antenna.field.TxPath == 1) - { - // turn off tx DAC_1 - bbpreg = (bbpreg | 0x20); - } - - if (pAd->Antenna.field.RxPath == 1) - { - // turn off tx ADC_1 - bbpreg &= (~0x2); - } - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R138, bbpreg); - - // improve power consumption in RT3071 Ver.E - if ((pAd->MACVersion & 0xffff) >= 0x0211) - { - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R31, &bbpreg); - bbpreg &= (~0x3); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R31, bbpreg); - } - } -#endif // RT30xx // -// end johnli - - if (pAd->MACVersion == 0x28600100) - { - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, 0x16); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R73, 0x12); - } - - if (pAd->MACVersion >= RALINK_2880E_VERSION && pAd->MACVersion < RALINK_3070_VERSION) // 3*3 - { - // enlarge MAX_LEN_CFG - UINT32 csr; - RTMP_IO_READ32(pAd, MAX_LEN_CFG, &csr); - csr &= 0xFFF; - csr |= 0x2000; - RTMP_IO_WRITE32(pAd, MAX_LEN_CFG, csr); - } - -#ifdef RT2870 -{ - UCHAR MAC_Value[]={0xff,0xff,0xff,0xff,0xff,0xff,0xff,0,0}; - - //Initialize WCID table - Value = 0xff; - for(Index =0 ;Index < 254;Index++) - { - RTUSBMultiWrite(pAd, (USHORT)(MAC_WCID_BASE + Index * 8), MAC_Value, 8); - } -} -#endif // RT2870 // - - // Add radio off control -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - if (pAd->StaCfg.bRadio == FALSE) - { -// RTMP_IO_WRITE32(pAd, PWR_PIN_CFG, 0x00001818); - RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF); - DBGPRINT(RT_DEBUG_TRACE, ("Set Radio Off\n")); - } - } -#endif // CONFIG_STA_SUPPORT // - - // Clear raw counters - RTMP_IO_READ32(pAd, RX_STA_CNT0, &Counter); - RTMP_IO_READ32(pAd, RX_STA_CNT1, &Counter); - RTMP_IO_READ32(pAd, RX_STA_CNT2, &Counter); - RTMP_IO_READ32(pAd, TX_STA_CNT0, &Counter); - RTMP_IO_READ32(pAd, TX_STA_CNT1, &Counter); - RTMP_IO_READ32(pAd, TX_STA_CNT2, &Counter); - - // ASIC will keep garbage value after boot - // Clear all seared key table when initial - // This routine can be ignored in radio-ON/OFF operation. - if (bHardReset) - { - for (KeyIdx = 0; KeyIdx < 4; KeyIdx++) - { - RTMP_IO_WRITE32(pAd, SHARED_KEY_MODE_BASE + 4*KeyIdx, 0); - } - - // Clear all pairwise key table when initial - for (KeyIdx = 0; KeyIdx < 256; KeyIdx++) - { - RTMP_IO_WRITE32(pAd, MAC_WCID_ATTRIBUTE_BASE + (KeyIdx * HW_WCID_ATTRI_SIZE), 1); - } - } - - // assert HOST ready bit -// RTMP_IO_WRITE32(pAd, MAC_CSR1, 0x0); // 2004-09-14 asked by Mark -// RTMP_IO_WRITE32(pAd, MAC_CSR1, 0x4); - - // It isn't necessary to clear this space when not hard reset. - if (bHardReset == TRUE) - { - // clear all on-chip BEACON frame space - for (apidx = 0; apidx < HW_BEACON_MAX_COUNT; apidx++) - { - for (i = 0; i < HW_BEACON_OFFSET>>2; i+=4) - RTMP_IO_WRITE32(pAd, pAd->BeaconOffset[apidx] + i, 0x00); - } - } -#ifdef RT2870 - AsicDisableSync(pAd); - // Clear raw counters - RTMP_IO_READ32(pAd, RX_STA_CNT0, &Counter); - RTMP_IO_READ32(pAd, RX_STA_CNT1, &Counter); - RTMP_IO_READ32(pAd, RX_STA_CNT2, &Counter); - RTMP_IO_READ32(pAd, TX_STA_CNT0, &Counter); - RTMP_IO_READ32(pAd, TX_STA_CNT1, &Counter); - RTMP_IO_READ32(pAd, TX_STA_CNT2, &Counter); - // Default PCI clock cycle per ms is different as default setting, which is based on PCI. - RTMP_IO_READ32(pAd, USB_CYC_CFG, &Counter); - Counter&=0xffffff00; - Counter|=0x000001e; - RTMP_IO_WRITE32(pAd, USB_CYC_CFG, Counter); -#endif // RT2870 // -#ifdef RT30xx - pAd->bUseEfuse=FALSE; - RTMP_IO_READ32(pAd, EFUSE_CTRL, &eFuseCtrl); - pAd->bUseEfuse = ( (eFuseCtrl & 0x80000000) == 0x80000000) ? 1 : 0; - if(pAd->bUseEfuse) - { - DBGPRINT(RT_DEBUG_TRACE, ("NVM is Efuse\n")); - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("NVM is EEPROM\n")); - - } -#endif // RT30xx // - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - // for rt2860E and after, init TXOP_CTRL_CFG with 0x583f. This is for extension channel overlapping IOT. - if ((pAd->MACVersion&0xffff) != 0x0101) - RTMP_IO_WRITE32(pAd, TXOP_CTRL_CFG, 0x583f); - } -#endif // CONFIG_STA_SUPPORT // - - DBGPRINT(RT_DEBUG_TRACE, ("<-- NICInitializeAsic\n")); - return NDIS_STATUS_SUCCESS; -} - -/* - ======================================================================== - - Routine Description: - Reset NIC Asics - - Arguments: - Adapter Pointer to our adapter - - Return Value: - None - - IRQL = PASSIVE_LEVEL - - Note: - Reset NIC to initial state AS IS system boot up time. - - ======================================================================== -*/ -VOID NICIssueReset( - IN PRTMP_ADAPTER pAd) -{ - UINT32 Value = 0; - DBGPRINT(RT_DEBUG_TRACE, ("--> NICIssueReset\n")); - - // Abort Tx, prevent ASIC from writing to Host memory - //RTMP_IO_WRITE32(pAd, TX_CNTL_CSR, 0x001f0000); - - // Disable Rx, register value supposed will remain after reset - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value &= (0xfffffff3); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - - // Issue reset and clear from reset state - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x03); // 2004-09-17 change from 0x01 - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x00); - - DBGPRINT(RT_DEBUG_TRACE, ("<-- NICIssueReset\n")); -} - -/* - ======================================================================== - - Routine Description: - Check ASIC registers and find any reason the system might hang - - Arguments: - Adapter Pointer to our adapter - - Return Value: - None - - IRQL = DISPATCH_LEVEL - - ======================================================================== -*/ -BOOLEAN NICCheckForHang( - IN PRTMP_ADAPTER pAd) -{ - return (FALSE); -} - -VOID NICUpdateFifoStaCounters( - IN PRTMP_ADAPTER pAd) -{ - TX_STA_FIFO_STRUC StaFifo; - MAC_TABLE_ENTRY *pEntry; - UCHAR i = 0; - UCHAR pid = 0, wcid = 0; - CHAR reTry; - UCHAR succMCS; - -#ifdef RALINK_ATE - /* Nothing to do in ATE mode */ - if (ATE_ON(pAd)) - return; -#endif // RALINK_ATE // - - do - { - RTMP_IO_READ32(pAd, TX_STA_FIFO, &StaFifo.word); - - if (StaFifo.field.bValid == 0) - break; - - wcid = (UCHAR)StaFifo.field.wcid; - - - /* ignore NoACK and MGMT frame use 0xFF as WCID */ - if ((StaFifo.field.TxAckRequired == 0) || (wcid >= MAX_LEN_OF_MAC_TABLE)) - { - i++; - continue; - } - - /* PID store Tx MCS Rate */ - pid = (UCHAR)StaFifo.field.PidType; - - pEntry = &pAd->MacTab.Content[wcid]; - - pEntry->DebugFIFOCount++; - -#ifdef DOT11_N_SUPPORT - if (StaFifo.field.TxBF) // 3*3 - pEntry->TxBFCount++; -#endif // DOT11_N_SUPPORT // - -#ifdef UAPSD_AP_SUPPORT - UAPSD_SP_AUE_Handle(pAd, pEntry, StaFifo.field.TxSuccess); -#endif // UAPSD_AP_SUPPORT // - - if (!StaFifo.field.TxSuccess) - { - pEntry->FIFOCount++; - pEntry->OneSecTxFailCount++; - - if (pEntry->FIFOCount >= 1) - { - DBGPRINT(RT_DEBUG_TRACE, ("#")); -#ifdef DOT11_N_SUPPORT - pEntry->NoBADataCountDown = 64; -#endif // DOT11_N_SUPPORT // - - if(pEntry->PsMode == PWR_ACTIVE) - { -#ifdef DOT11_N_SUPPORT - int tid; - for (tid=0; tidAid, tid, FALSE, FALSE); - } -#endif // DOT11_N_SUPPORT // - - // Update the continuous transmission counter except PS mode - pEntry->ContinueTxFailCnt++; - } - else - { - // Clear the FIFOCount when sta in Power Save mode. Basically we assume - // this tx error happened due to sta just go to sleep. - pEntry->FIFOCount = 0; - pEntry->ContinueTxFailCnt = 0; - } - //pEntry->FIFOCount = 0; - } - //pEntry->bSendBAR = TRUE; - } - else - { -#ifdef DOT11_N_SUPPORT - if ((pEntry->PsMode != PWR_SAVE) && (pEntry->NoBADataCountDown > 0)) - { - pEntry->NoBADataCountDown--; - if (pEntry->NoBADataCountDown==0) - { - DBGPRINT(RT_DEBUG_TRACE, ("@\n")); - } - } -#endif // DOT11_N_SUPPORT // - pEntry->FIFOCount = 0; - pEntry->OneSecTxNoRetryOkCount++; - // update NoDataIdleCount when sucessful send packet to STA. - pEntry->NoDataIdleCount = 0; - pEntry->ContinueTxFailCnt = 0; - } - - succMCS = StaFifo.field.SuccessRate & 0x7F; - - reTry = pid - succMCS; - - if (StaFifo.field.TxSuccess) - { - pEntry->TXMCSExpected[pid]++; - if (pid == succMCS) - { - pEntry->TXMCSSuccessful[pid]++; - } - else - { - pEntry->TXMCSAutoFallBack[pid][succMCS]++; - } - } - else - { - pEntry->TXMCSFailed[pid]++; - } - - if (reTry > 0) - { - if ((pid >= 12) && succMCS <=7) - { - reTry -= 4; - } - pEntry->OneSecTxRetryOkCount += reTry; - } - - i++; - // ASIC store 16 stack - } while ( i < (2*TX_RING_SIZE) ); - -} - -/* - ======================================================================== - - Routine Description: - Read statistical counters from hardware registers and record them - in software variables for later on query - - Arguments: - pAd Pointer to our adapter - - Return Value: - None - - IRQL = DISPATCH_LEVEL - - ======================================================================== -*/ -VOID NICUpdateRawCounters( - IN PRTMP_ADAPTER pAd) -{ - UINT32 OldValue;//, Value2; - //ULONG PageSum, OneSecTransmitCount; - //ULONG TxErrorRatio, Retry, Fail; - RX_STA_CNT0_STRUC RxStaCnt0; - RX_STA_CNT1_STRUC RxStaCnt1; - RX_STA_CNT2_STRUC RxStaCnt2; - TX_STA_CNT0_STRUC TxStaCnt0; - TX_STA_CNT1_STRUC StaTx1; - TX_STA_CNT2_STRUC StaTx2; - TX_AGG_CNT_STRUC TxAggCnt; - TX_AGG_CNT0_STRUC TxAggCnt0; - TX_AGG_CNT1_STRUC TxAggCnt1; - TX_AGG_CNT2_STRUC TxAggCnt2; - TX_AGG_CNT3_STRUC TxAggCnt3; - TX_AGG_CNT4_STRUC TxAggCnt4; - TX_AGG_CNT5_STRUC TxAggCnt5; - TX_AGG_CNT6_STRUC TxAggCnt6; - TX_AGG_CNT7_STRUC TxAggCnt7; - - RTMP_IO_READ32(pAd, RX_STA_CNT0, &RxStaCnt0.word); - RTMP_IO_READ32(pAd, RX_STA_CNT2, &RxStaCnt2.word); - - { - RTMP_IO_READ32(pAd, RX_STA_CNT1, &RxStaCnt1.word); - // Update RX PLCP error counter - pAd->PrivateInfo.PhyRxErrCnt += RxStaCnt1.field.PlcpErr; - // Update False CCA counter - pAd->RalinkCounters.OneSecFalseCCACnt += RxStaCnt1.field.FalseCca; - } - - // Update FCS counters - OldValue= pAd->WlanCounters.FCSErrorCount.u.LowPart; - pAd->WlanCounters.FCSErrorCount.u.LowPart += (RxStaCnt0.field.CrcErr); // >> 7); - if (pAd->WlanCounters.FCSErrorCount.u.LowPart < OldValue) - pAd->WlanCounters.FCSErrorCount.u.HighPart++; - - // Add FCS error count to private counters - pAd->RalinkCounters.OneSecRxFcsErrCnt += RxStaCnt0.field.CrcErr; - OldValue = pAd->RalinkCounters.RealFcsErrCount.u.LowPart; - pAd->RalinkCounters.RealFcsErrCount.u.LowPart += RxStaCnt0.field.CrcErr; - if (pAd->RalinkCounters.RealFcsErrCount.u.LowPart < OldValue) - pAd->RalinkCounters.RealFcsErrCount.u.HighPart++; - - // Update Duplicate Rcv check - pAd->RalinkCounters.DuplicateRcv += RxStaCnt2.field.RxDupliCount; - pAd->WlanCounters.FrameDuplicateCount.u.LowPart += RxStaCnt2.field.RxDupliCount; - // Update RX Overflow counter - pAd->Counters8023.RxNoBuffer += (RxStaCnt2.field.RxFifoOverflowCount); - - //pAd->RalinkCounters.RxCount = 0; -#ifdef RT2870 - if (pAd->RalinkCounters.RxCount != pAd->watchDogRxCnt) - { - pAd->watchDogRxCnt = pAd->RalinkCounters.RxCount; - pAd->watchDogRxOverFlowCnt = 0; - } - else - { - if (RxStaCnt2.field.RxFifoOverflowCount) - pAd->watchDogRxOverFlowCnt++; - else - pAd->watchDogRxOverFlowCnt = 0; - } -#endif // RT2870 // - - - //if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED) || - // (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED) && (pAd->MacTab.Size != 1))) - if (!pAd->bUpdateBcnCntDone) - { - // Update BEACON sent count - RTMP_IO_READ32(pAd, TX_STA_CNT0, &TxStaCnt0.word); - RTMP_IO_READ32(pAd, TX_STA_CNT1, &StaTx1.word); - RTMP_IO_READ32(pAd, TX_STA_CNT2, &StaTx2.word); - pAd->RalinkCounters.OneSecBeaconSentCnt += TxStaCnt0.field.TxBeaconCount; - pAd->RalinkCounters.OneSecTxRetryOkCount += StaTx1.field.TxRetransmit; - pAd->RalinkCounters.OneSecTxNoRetryOkCount += StaTx1.field.TxSuccess; - pAd->RalinkCounters.OneSecTxFailCount += TxStaCnt0.field.TxFailCount; - pAd->WlanCounters.TransmittedFragmentCount.u.LowPart += StaTx1.field.TxSuccess; - pAd->WlanCounters.RetryCount.u.LowPart += StaTx1.field.TxRetransmit; - pAd->WlanCounters.FailedCount.u.LowPart += TxStaCnt0.field.TxFailCount; - } - - //if (pAd->bStaFifoTest == TRUE) - { - RTMP_IO_READ32(pAd, TX_AGG_CNT, &TxAggCnt.word); - RTMP_IO_READ32(pAd, TX_AGG_CNT0, &TxAggCnt0.word); - RTMP_IO_READ32(pAd, TX_AGG_CNT1, &TxAggCnt1.word); - RTMP_IO_READ32(pAd, TX_AGG_CNT2, &TxAggCnt2.word); - RTMP_IO_READ32(pAd, TX_AGG_CNT3, &TxAggCnt3.word); - RTMP_IO_READ32(pAd, TX_AGG_CNT4, &TxAggCnt4.word); - RTMP_IO_READ32(pAd, TX_AGG_CNT5, &TxAggCnt5.word); - RTMP_IO_READ32(pAd, TX_AGG_CNT6, &TxAggCnt6.word); - RTMP_IO_READ32(pAd, TX_AGG_CNT7, &TxAggCnt7.word); - pAd->RalinkCounters.TxAggCount += TxAggCnt.field.AggTxCount; - pAd->RalinkCounters.TxNonAggCount += TxAggCnt.field.NonAggTxCount; - pAd->RalinkCounters.TxAgg1MPDUCount += TxAggCnt0.field.AggSize1Count; - pAd->RalinkCounters.TxAgg2MPDUCount += TxAggCnt0.field.AggSize2Count; - - pAd->RalinkCounters.TxAgg3MPDUCount += TxAggCnt1.field.AggSize3Count; - pAd->RalinkCounters.TxAgg4MPDUCount += TxAggCnt1.field.AggSize4Count; - pAd->RalinkCounters.TxAgg5MPDUCount += TxAggCnt2.field.AggSize5Count; - pAd->RalinkCounters.TxAgg6MPDUCount += TxAggCnt2.field.AggSize6Count; - - pAd->RalinkCounters.TxAgg7MPDUCount += TxAggCnt3.field.AggSize7Count; - pAd->RalinkCounters.TxAgg8MPDUCount += TxAggCnt3.field.AggSize8Count; - pAd->RalinkCounters.TxAgg9MPDUCount += TxAggCnt4.field.AggSize9Count; - pAd->RalinkCounters.TxAgg10MPDUCount += TxAggCnt4.field.AggSize10Count; - - pAd->RalinkCounters.TxAgg11MPDUCount += TxAggCnt5.field.AggSize11Count; - pAd->RalinkCounters.TxAgg12MPDUCount += TxAggCnt5.field.AggSize12Count; - pAd->RalinkCounters.TxAgg13MPDUCount += TxAggCnt6.field.AggSize13Count; - pAd->RalinkCounters.TxAgg14MPDUCount += TxAggCnt6.field.AggSize14Count; - - pAd->RalinkCounters.TxAgg15MPDUCount += TxAggCnt7.field.AggSize15Count; - pAd->RalinkCounters.TxAgg16MPDUCount += TxAggCnt7.field.AggSize16Count; - - // Calculate the transmitted A-MPDU count - pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += TxAggCnt0.field.AggSize1Count; - pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt0.field.AggSize2Count / 2); - - pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt1.field.AggSize3Count / 3); - pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt1.field.AggSize4Count / 4); - - pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt2.field.AggSize5Count / 5); - pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt2.field.AggSize6Count / 6); - - pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt3.field.AggSize7Count / 7); - pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt3.field.AggSize8Count / 8); - - pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt4.field.AggSize9Count / 9); - pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt4.field.AggSize10Count / 10); - - pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt5.field.AggSize11Count / 11); - pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt5.field.AggSize12Count / 12); - - pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt6.field.AggSize13Count / 13); - pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt6.field.AggSize14Count / 14); - - pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt7.field.AggSize15Count / 15); - pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt7.field.AggSize16Count / 16); - } - -#ifdef DBG_DIAGNOSE - { - RtmpDiagStruct *pDiag; - COUNTER_RALINK *pRalinkCounters; - UCHAR ArrayCurIdx, i; - - pDiag = &pAd->DiagStruct; - pRalinkCounters = &pAd->RalinkCounters; - ArrayCurIdx = pDiag->ArrayCurIdx; - - if (pDiag->inited == 0) - { - NdisZeroMemory(pDiag, sizeof(struct _RtmpDiagStrcut_)); - pDiag->ArrayStartIdx = pDiag->ArrayCurIdx = 0; - pDiag->inited = 1; - } - else - { - // Tx - pDiag->TxFailCnt[ArrayCurIdx] = TxStaCnt0.field.TxFailCount; - pDiag->TxAggCnt[ArrayCurIdx] = TxAggCnt.field.AggTxCount; - pDiag->TxNonAggCnt[ArrayCurIdx] = TxAggCnt.field.NonAggTxCount; - pDiag->TxAMPDUCnt[ArrayCurIdx][0] = TxAggCnt0.field.AggSize1Count; - pDiag->TxAMPDUCnt[ArrayCurIdx][1] = TxAggCnt0.field.AggSize2Count; - pDiag->TxAMPDUCnt[ArrayCurIdx][2] = TxAggCnt1.field.AggSize3Count; - pDiag->TxAMPDUCnt[ArrayCurIdx][3] = TxAggCnt1.field.AggSize4Count; - pDiag->TxAMPDUCnt[ArrayCurIdx][4] = TxAggCnt2.field.AggSize5Count; - pDiag->TxAMPDUCnt[ArrayCurIdx][5] = TxAggCnt2.field.AggSize6Count; - pDiag->TxAMPDUCnt[ArrayCurIdx][6] = TxAggCnt3.field.AggSize7Count; - pDiag->TxAMPDUCnt[ArrayCurIdx][7] = TxAggCnt3.field.AggSize8Count; - pDiag->TxAMPDUCnt[ArrayCurIdx][8] = TxAggCnt4.field.AggSize9Count; - pDiag->TxAMPDUCnt[ArrayCurIdx][9] = TxAggCnt4.field.AggSize10Count; - pDiag->TxAMPDUCnt[ArrayCurIdx][10] = TxAggCnt5.field.AggSize11Count; - pDiag->TxAMPDUCnt[ArrayCurIdx][11] = TxAggCnt5.field.AggSize12Count; - pDiag->TxAMPDUCnt[ArrayCurIdx][12] = TxAggCnt6.field.AggSize13Count; - pDiag->TxAMPDUCnt[ArrayCurIdx][13] = TxAggCnt6.field.AggSize14Count; - pDiag->TxAMPDUCnt[ArrayCurIdx][14] = TxAggCnt7.field.AggSize15Count; - pDiag->TxAMPDUCnt[ArrayCurIdx][15] = TxAggCnt7.field.AggSize16Count; - - pDiag->RxCrcErrCnt[ArrayCurIdx] = RxStaCnt0.field.CrcErr; - - INC_RING_INDEX(pDiag->ArrayCurIdx, DIAGNOSE_TIME); - ArrayCurIdx = pDiag->ArrayCurIdx; - for (i =0; i < 9; i++) - { - pDiag->TxDescCnt[ArrayCurIdx][i]= 0; - pDiag->TxSWQueCnt[ArrayCurIdx][i] =0; - pDiag->TxMcsCnt[ArrayCurIdx][i] = 0; - pDiag->RxMcsCnt[ArrayCurIdx][i] = 0; - } - pDiag->TxDataCnt[ArrayCurIdx] = 0; - pDiag->TxFailCnt[ArrayCurIdx] = 0; - pDiag->RxDataCnt[ArrayCurIdx] = 0; - pDiag->RxCrcErrCnt[ArrayCurIdx] = 0; -// for (i = 9; i < 16; i++) - for (i = 9; i < 24; i++) // 3*3 - { - pDiag->TxDescCnt[ArrayCurIdx][i] = 0; - pDiag->TxMcsCnt[ArrayCurIdx][i] = 0; - pDiag->RxMcsCnt[ArrayCurIdx][i] = 0; -} - - if (pDiag->ArrayCurIdx == pDiag->ArrayStartIdx) - INC_RING_INDEX(pDiag->ArrayStartIdx, DIAGNOSE_TIME); - } - - } -#endif // DBG_DIAGNOSE // - - -} - - -/* - ======================================================================== - - Routine Description: - Reset NIC from error - - Arguments: - Adapter Pointer to our adapter - - Return Value: - None - - IRQL = PASSIVE_LEVEL - - Note: - Reset NIC from error state - - ======================================================================== -*/ -VOID NICResetFromError( - IN PRTMP_ADAPTER pAd) -{ - // Reset BBP (according to alex, reset ASIC will force reset BBP - // Therefore, skip the reset BBP - // RTMP_IO_WRITE32(pAd, MAC_CSR1, 0x2); - - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x1); - // Remove ASIC from reset state - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x0); - - NICInitializeAdapter(pAd, FALSE); - NICInitAsicFromEEPROM(pAd); - - // Switch to current channel, since during reset process, the connection should remains on. - AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE); - AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel); -} - -/* - ======================================================================== - - Routine Description: - erase 8051 firmware image in MAC ASIC - - Arguments: - Adapter Pointer to our adapter - - IRQL = PASSIVE_LEVEL - - ======================================================================== -*/ -VOID NICEraseFirmware( - IN PRTMP_ADAPTER pAd) -{ - ULONG i; - - for(i=0; i %s\n", __FUNCTION__)); - - /* init */ - pFirmwareImage = NULL; - src = RTMP_FIRMWARE_FILE_NAME; - - /* save uid and gid used for filesystem access. - set user and group to 0 (root) */ - orgfsuid = current->fsuid; - orgfsgid = current->fsgid; - current->fsuid = current->fsgid = 0; - orgfs = get_fs(); - set_fs(KERNEL_DS); - - pAd->FirmwareVersion = (FIRMWARE_MAJOR_VERSION << 8) + \ - FIRMWARE_MINOR_VERSION; - - - /* allocate firmware buffer */ - pFirmwareImage = kmalloc(MAX_FIRMWARE_IMAGE_SIZE, MEM_ALLOC_FLAG); - if (pFirmwareImage == NULL) - { - /* allocate fail, use default firmware array in firmware.h */ - printk("%s - Allocate memory fail!\n", __FUNCTION__); - NICLF_DEFAULT_USE(); - } - else - { - /* allocate ok! zero the firmware buffer */ - memset(pFirmwareImage, 0x00, MAX_FIRMWARE_IMAGE_SIZE); - } /* End of if */ - - - /* if ok, read firmware file from *.bin file */ - if (flg_default_firm_use == FALSE) - { - do - { - /* open the bin file */ - srcf = filp_open(src, O_RDONLY, 0); - - if (IS_ERR(srcf)) - { - printk("%s - Error %ld opening %s\n", - __FUNCTION__, -PTR_ERR(srcf), src); - NICLF_DEFAULT_USE(); - break; - } /* End of if */ - - /* the object must have a read method */ - if ((srcf->f_op == NULL) || (srcf->f_op->read == NULL)) - { - printk("%s - %s does not have a write method\n", __FUNCTION__, src); - NICLF_DEFAULT_USE(); - break; - } /* End of if */ - - /* read the firmware from the file *.bin */ - FileLength = srcf->f_op->read(srcf, - pFirmwareImage, - MAX_FIRMWARE_IMAGE_SIZE, - &srcf->f_pos); - - if (FileLength != MAX_FIRMWARE_IMAGE_SIZE) - { - printk("%s: error file length (=%d) in RT2860AP.BIN\n", - __FUNCTION__, FileLength); - NICLF_DEFAULT_USE(); - break; - } - else - { - PUCHAR ptr = pFirmwareImage; - USHORT crc = 0xffff; - - - /* calculate firmware CRC */ - for(i=0; i<(MAX_FIRMWARE_IMAGE_SIZE-2); i++, ptr++) - crc = ByteCRC16(BitReverse(*ptr), crc); - /* End of for */ - - if ((pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-2] != \ - (UCHAR)BitReverse((UCHAR)(crc>>8))) || - (pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-1] != \ - (UCHAR)BitReverse((UCHAR)crc))) - { - /* CRC fail */ - printk("%s: CRC = 0x%02x 0x%02x " - "error, should be 0x%02x 0x%02x\n", - __FUNCTION__, - pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-2], - pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-1], - (UCHAR)(crc>>8), (UCHAR)(crc)); - NICLF_DEFAULT_USE(); - break; - } - else - { - /* firmware is ok */ - pAd->FirmwareVersion = \ - (pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-4] << 8) + - pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-3]; - - /* check if firmware version of the file is too old */ - if ((pAd->FirmwareVersion) < \ - ((FIRMWARE_MAJOR_VERSION << 8) + - FIRMWARE_MINOR_VERSION)) - { - printk("%s: firmware version too old!\n", __FUNCTION__); - NICLF_DEFAULT_USE(); - break; - } /* End of if */ - } /* End of if */ - - DBGPRINT(RT_DEBUG_TRACE, - ("NICLoadFirmware: CRC ok, ver=%d.%d\n", - pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-4], - pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-3])); - } /* End of if (FileLength == MAX_FIRMWARE_IMAGE_SIZE) */ - break; - } while(TRUE); - - /* close firmware file */ - if (IS_ERR(srcf)) - ; - else - { - retval = filp_close(srcf, NULL); - if (retval) - { - DBGPRINT(RT_DEBUG_ERROR, - ("--> Error %d closing %s\n", -retval, src)); - } /* End of if */ - } /* End of if */ - } /* End of if */ - - - /* write firmware to ASIC */ - if (flg_default_firm_use == TRUE) - { - /* use default fimeware, free allocated buffer */ - if (pFirmwareImage != NULL) - kfree(pFirmwareImage); - /* End of if */ - - /* use default *.bin array */ - pFirmwareImage = FirmwareImage; - FileLength = sizeof(FirmwareImage); - } /* End of if */ - - /* enable Host program ram write selection */ - RTMP_IO_WRITE32(pAd, PBF_SYS_CTRL, 0x10000); - - for(i=0; ifsuid = orgfsuid; - current->fsgid = orgfsgid; -#else - - NDIS_STATUS Status = NDIS_STATUS_SUCCESS; - PUCHAR pFirmwareImage; - ULONG FileLength, Index; - //ULONG firm; - UINT32 MacReg = 0; - UINT32 Version = (pAd->MACVersion >> 16); - - pFirmwareImage = FirmwareImage; - FileLength = sizeof(FirmwareImage); - - // New 8k byte firmware size for RT3071/RT3072 - //printk("Usb Chip\n"); - if (FIRMWAREIMAGE_LENGTH == FIRMWAREIMAGE_MAX_LENGTH) - //The firmware image consists of two parts. One is the origianl and the other is the new. - //Use Second Part - { -#ifdef RT2870 - if ((Version != 0x2860) && (Version != 0x2872) && (Version != 0x3070)) - { // Use Firmware V2. - //printk("KH:Use New Version,part2\n"); - pFirmwareImage = (PUCHAR)&FirmwareImage[FIRMWAREIMAGEV1_LENGTH]; - FileLength = FIRMWAREIMAGEV2_LENGTH; - } - else - { - //printk("KH:Use New Version,part1\n"); - pFirmwareImage = FirmwareImage; - FileLength = FIRMWAREIMAGEV1_LENGTH; - } -#endif // RT2870 // - } - else - { - DBGPRINT(RT_DEBUG_ERROR, ("KH: bin file should be 8KB.\n")); - Status = NDIS_STATUS_FAILURE; - } - - RT28XX_WRITE_FIRMWARE(pAd, pFirmwareImage, FileLength); - -#endif - - /* check if MCU is ready */ - Index = 0; - do - { - RTMP_IO_READ32(pAd, PBF_SYS_CTRL, &MacReg); - - if (MacReg & 0x80) - break; - - RTMPusecDelay(1000); - } while (Index++ < 1000); - - if (Index >= 1000) - { - Status = NDIS_STATUS_FAILURE; - DBGPRINT(RT_DEBUG_ERROR, ("NICLoadFirmware: MCU is not ready\n\n\n")); - } /* End of if */ - - DBGPRINT(RT_DEBUG_TRACE, - ("<=== %s (status=%d)\n", __FUNCTION__, Status)); - return Status; -} /* End of NICLoadFirmware */ - - -/* - ======================================================================== - - Routine Description: - Load Tx rate switching parameters - - Arguments: - Adapter Pointer to our adapter - - Return Value: - NDIS_STATUS_SUCCESS firmware image load ok - NDIS_STATUS_FAILURE image not found - - IRQL = PASSIVE_LEVEL - - Rate Table Format: - 1. (B0: Valid Item number) (B1:Initial item from zero) - 2. Item Number(Dec) Mode(Hex) Current MCS(Dec) TrainUp(Dec) TrainDown(Dec) - - ======================================================================== -*/ -NDIS_STATUS NICLoadRateSwitchingParams( - IN PRTMP_ADAPTER pAd) -{ - return NDIS_STATUS_SUCCESS; -} - -/* - ======================================================================== - - Routine Description: - if pSrc1 all zero with length Length, return 0. - If not all zero, return 1 - - Arguments: - pSrc1 - - Return Value: - 1: not all zero - 0: all zero - - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -ULONG RTMPNotAllZero( - IN PVOID pSrc1, - IN ULONG Length) -{ - PUCHAR pMem1; - ULONG Index = 0; - - pMem1 = (PUCHAR) pSrc1; - - for (Index = 0; Index < Length; Index++) - { - if (pMem1[Index] != 0x0) - { - break; - } - } - - if (Index == Length) - { - return (0); - } - else - { - return (1); - } -} - -/* - ======================================================================== - - Routine Description: - Compare two memory block - - Arguments: - pSrc1 Pointer to first memory address - pSrc2 Pointer to second memory address - - Return Value: - 0: memory is equal - 1: pSrc1 memory is larger - 2: pSrc2 memory is larger - - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -ULONG RTMPCompareMemory( - IN PVOID pSrc1, - IN PVOID pSrc2, - IN ULONG Length) -{ - PUCHAR pMem1; - PUCHAR pMem2; - ULONG Index = 0; - - pMem1 = (PUCHAR) pSrc1; - pMem2 = (PUCHAR) pSrc2; - - for (Index = 0; Index < Length; Index++) - { - if (pMem1[Index] > pMem2[Index]) - return (1); - else if (pMem1[Index] < pMem2[Index]) - return (2); - } - - // Equal - return (0); -} - -/* - ======================================================================== - - Routine Description: - Zero out memory block - - Arguments: - pSrc1 Pointer to memory address - Length Size - - Return Value: - None - - IRQL = PASSIVE_LEVEL - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -VOID RTMPZeroMemory( - IN PVOID pSrc, - IN ULONG Length) -{ - PUCHAR pMem; - ULONG Index = 0; - - pMem = (PUCHAR) pSrc; - - for (Index = 0; Index < Length; Index++) - { - pMem[Index] = 0x00; - } -} - -VOID RTMPFillMemory( - IN PVOID pSrc, - IN ULONG Length, - IN UCHAR Fill) -{ - PUCHAR pMem; - ULONG Index = 0; - - pMem = (PUCHAR) pSrc; - - for (Index = 0; Index < Length; Index++) - { - pMem[Index] = Fill; - } -} - -/* - ======================================================================== - - Routine Description: - Copy data from memory block 1 to memory block 2 - - Arguments: - pDest Pointer to destination memory address - pSrc Pointer to source memory address - Length Copy size - - Return Value: - None - - IRQL = PASSIVE_LEVEL - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -VOID RTMPMoveMemory( - OUT PVOID pDest, - IN PVOID pSrc, - IN ULONG Length) -{ - PUCHAR pMem1; - PUCHAR pMem2; - UINT Index; - - ASSERT((Length==0) || (pDest && pSrc)); - - pMem1 = (PUCHAR) pDest; - pMem2 = (PUCHAR) pSrc; - - for (Index = 0; Index < Length; Index++) - { - pMem1[Index] = pMem2[Index]; - } -} - -/* - ======================================================================== - - Routine Description: - Initialize port configuration structure - - Arguments: - Adapter Pointer to our adapter - - Return Value: - None - - IRQL = PASSIVE_LEVEL - - Note: - - ======================================================================== -*/ -VOID UserCfgInit( - IN PRTMP_ADAPTER pAd) -{ -// EDCA_PARM DefaultEdcaParm; - UINT key_index, bss_index; - - DBGPRINT(RT_DEBUG_TRACE, ("--> UserCfgInit\n")); - - // - // part I. intialize common configuration - // -#ifdef RT2870 - pAd->BulkOutReq = 0; - - pAd->BulkOutComplete = 0; - pAd->BulkOutCompleteOther = 0; - pAd->BulkOutCompleteCancel = 0; - pAd->BulkInReq = 0; - pAd->BulkInComplete = 0; - pAd->BulkInCompleteFail = 0; - - //pAd->QuickTimerP = 100; - //pAd->TurnAggrBulkInCount = 0; - pAd->bUsbTxBulkAggre = 0; - - // init as unsed value to ensure driver will set to MCU once. - pAd->LedIndicatorStregth = 0xFF; - - pAd->CommonCfg.MaxPktOneTxBulk = 2; - pAd->CommonCfg.TxBulkFactor = 1; - pAd->CommonCfg.RxBulkFactor =1; - - pAd->CommonCfg.TxPower = 100; //mW - - NdisZeroMemory(&pAd->CommonCfg.IOTestParm, sizeof(pAd->CommonCfg.IOTestParm)); -#endif // RT2870 // - - for(key_index=0; key_indexSharedKey[bss_index][key_index].KeyLen = 0; - pAd->SharedKey[bss_index][key_index].CipherAlg = CIPHER_NONE; - } /* End of for */ - } /* End of for */ - - pAd->EepromAccess = FALSE; - - pAd->Antenna.word = 0; - pAd->CommonCfg.BBPCurrentBW = BW_20; - - pAd->LedCntl.word = 0; - - pAd->bAutoTxAgcA = FALSE; // Default is OFF - pAd->bAutoTxAgcG = FALSE; // Default is OFF - pAd->RfIcType = RFIC_2820; - - // Init timer for reset complete event - pAd->CommonCfg.CentralChannel = 1; - pAd->bForcePrintTX = FALSE; - pAd->bForcePrintRX = FALSE; - pAd->bStaFifoTest = FALSE; - pAd->bProtectionTest = FALSE; - pAd->bHCCATest = FALSE; - pAd->bGenOneHCCA = FALSE; - pAd->CommonCfg.Dsifs = 10; // in units of usec - pAd->CommonCfg.TxPower = 100; //mW - pAd->CommonCfg.TxPowerPercentage = 0xffffffff; // AUTO - pAd->CommonCfg.TxPowerDefault = 0xffffffff; // AUTO - pAd->CommonCfg.TxPreamble = Rt802_11PreambleAuto; // use Long preamble on TX by defaut - pAd->CommonCfg.bUseZeroToDisableFragment = FALSE; - pAd->CommonCfg.RtsThreshold = 2347; - pAd->CommonCfg.FragmentThreshold = 2346; - pAd->CommonCfg.UseBGProtection = 0; // 0: AUTO - pAd->CommonCfg.bEnableTxBurst = TRUE; //0; - pAd->CommonCfg.PhyMode = 0xff; // unknown - pAd->CommonCfg.BandState = UNKNOWN_BAND; - pAd->CommonCfg.RadarDetect.CSPeriod = 10; - pAd->CommonCfg.RadarDetect.CSCount = 0; - pAd->CommonCfg.RadarDetect.RDMode = RD_NORMAL_MODE; - pAd->CommonCfg.RadarDetect.ChMovingTime = 65; - pAd->CommonCfg.RadarDetect.LongPulseRadarTh = 3; - pAd->CommonCfg.bAPSDCapable = FALSE; - pAd->CommonCfg.bNeedSendTriggerFrame = FALSE; - pAd->CommonCfg.TriggerTimerCount = 0; - pAd->CommonCfg.bAPSDForcePowerSave = FALSE; - pAd->CommonCfg.bCountryFlag = FALSE; - pAd->CommonCfg.TxStream = 0; - pAd->CommonCfg.RxStream = 0; - - NdisZeroMemory(&pAd->BeaconTxWI, sizeof(pAd->BeaconTxWI)); - -#ifdef DOT11_N_SUPPORT - NdisZeroMemory(&pAd->CommonCfg.HtCapability, sizeof(pAd->CommonCfg.HtCapability)); - pAd->HTCEnable = FALSE; - pAd->bBroadComHT = FALSE; - pAd->CommonCfg.bRdg = FALSE; - -#ifdef DOT11N_DRAFT3 - pAd->CommonCfg.Dot11OBssScanPassiveDwell = dot11OBSSScanPassiveDwell; // Unit : TU. 5~1000 - pAd->CommonCfg.Dot11OBssScanActiveDwell = dot11OBSSScanActiveDwell; // Unit : TU. 10~1000 - pAd->CommonCfg.Dot11BssWidthTriggerScanInt = dot11BSSWidthTriggerScanInterval; // Unit : Second - pAd->CommonCfg.Dot11OBssScanPassiveTotalPerChannel = dot11OBSSScanPassiveTotalPerChannel; // Unit : TU. 200~10000 - pAd->CommonCfg.Dot11OBssScanActiveTotalPerChannel = dot11OBSSScanActiveTotalPerChannel; // Unit : TU. 20~10000 - pAd->CommonCfg.Dot11BssWidthChanTranDelayFactor = dot11BSSWidthChannelTransactionDelayFactor; - pAd->CommonCfg.Dot11OBssScanActivityThre = dot11BSSScanActivityThreshold; // Unit : percentage - pAd->CommonCfg.Dot11BssWidthChanTranDelay = (pAd->CommonCfg.Dot11BssWidthTriggerScanInt * pAd->CommonCfg.Dot11BssWidthChanTranDelayFactor); -#endif // DOT11N_DRAFT3 // - - NdisZeroMemory(&pAd->CommonCfg.AddHTInfo, sizeof(pAd->CommonCfg.AddHTInfo)); - pAd->CommonCfg.BACapability.field.MMPSmode = MMPS_ENABLE; - pAd->CommonCfg.BACapability.field.MpduDensity = 0; - pAd->CommonCfg.BACapability.field.Policy = IMMED_BA; - pAd->CommonCfg.BACapability.field.RxBAWinLimit = 64; //32; - pAd->CommonCfg.BACapability.field.TxBAWinLimit = 64; //32; - DBGPRINT(RT_DEBUG_TRACE, ("--> UserCfgInit. BACapability = 0x%x\n", pAd->CommonCfg.BACapability.word)); - - pAd->CommonCfg.BACapability.field.AutoBA = FALSE; - BATableInit(pAd, &pAd->BATable); - - pAd->CommonCfg.bExtChannelSwitchAnnouncement = 1; - pAd->CommonCfg.bHTProtect = 1; - pAd->CommonCfg.bMIMOPSEnable = TRUE; - pAd->CommonCfg.bBADecline = FALSE; - pAd->CommonCfg.bDisableReordering = FALSE; - - pAd->CommonCfg.TxBASize = 7; - - pAd->CommonCfg.REGBACapability.word = pAd->CommonCfg.BACapability.word; -#endif // DOT11_N_SUPPORT // - - //pAd->CommonCfg.HTPhyMode.field.BW = BW_20; - //pAd->CommonCfg.HTPhyMode.field.MCS = MCS_AUTO; - //pAd->CommonCfg.HTPhyMode.field.ShortGI = GI_800; - //pAd->CommonCfg.HTPhyMode.field.STBC = STBC_NONE; - pAd->CommonCfg.TxRate = RATE_6; - - pAd->CommonCfg.MlmeTransmit.field.MCS = MCS_RATE_6; - pAd->CommonCfg.MlmeTransmit.field.BW = BW_20; - pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM; - - pAd->CommonCfg.BeaconPeriod = 100; // in mSec - - // - // part II. intialize STA specific configuration - // -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - RX_FILTER_SET_FLAG(pAd, fRX_FILTER_ACCEPT_DIRECT); - RX_FILTER_CLEAR_FLAG(pAd, fRX_FILTER_ACCEPT_MULTICAST); - RX_FILTER_SET_FLAG(pAd, fRX_FILTER_ACCEPT_BROADCAST); - RX_FILTER_SET_FLAG(pAd, fRX_FILTER_ACCEPT_ALL_MULTICAST); - - pAd->StaCfg.Psm = PWR_ACTIVE; - - pAd->StaCfg.OrigWepStatus = Ndis802_11EncryptionDisabled; - pAd->StaCfg.PairCipher = Ndis802_11EncryptionDisabled; - pAd->StaCfg.GroupCipher = Ndis802_11EncryptionDisabled; - pAd->StaCfg.bMixCipher = FALSE; - pAd->StaCfg.DefaultKeyId = 0; - - // 802.1x port control - pAd->StaCfg.PrivacyFilter = Ndis802_11PrivFilter8021xWEP; - pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; - pAd->StaCfg.LastMicErrorTime = 0; - pAd->StaCfg.MicErrCnt = 0; - pAd->StaCfg.bBlockAssoc = FALSE; - pAd->StaCfg.WpaState = SS_NOTUSE; - - pAd->CommonCfg.NdisRadioStateOff = FALSE; // New to support microsoft disable radio with OID command - - pAd->StaCfg.RssiTrigger = 0; - NdisZeroMemory(&pAd->StaCfg.RssiSample, sizeof(RSSI_SAMPLE)); - pAd->StaCfg.RssiTriggerMode = RSSI_TRIGGERED_UPON_BELOW_THRESHOLD; - pAd->StaCfg.AtimWin = 0; - pAd->StaCfg.DefaultListenCount = 3;//default listen count; - pAd->StaCfg.BssType = BSS_INFRA; // BSS_INFRA or BSS_ADHOC or BSS_MONITOR - pAd->StaCfg.bScanReqIsFromWebUI = FALSE; - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE); - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_WAKEUP_NOW); - - pAd->StaCfg.bAutoTxRateSwitch = TRUE; - pAd->StaCfg.DesiredTransmitSetting.field.MCS = MCS_AUTO; - } - -#ifdef EXT_BUILD_CHANNEL_LIST - pAd->StaCfg.IEEE80211dClientMode = Rt802_11_D_None; -#endif // EXT_BUILD_CHANNEL_LIST // -#endif // CONFIG_STA_SUPPORT // - - // global variables mXXXX used in MAC protocol state machines - OPSTATUS_SET_FLAG(pAd, fOP_STATUS_RECEIVE_DTIM); - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_ADHOC_ON); - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_INFRA_ON); - - // PHY specification - pAd->CommonCfg.PhyMode = PHY_11BG_MIXED; // default PHY mode - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED); // CCK use LONG preamble - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - // user desired power mode - pAd->StaCfg.WindowsPowerMode = Ndis802_11PowerModeCAM; - pAd->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeCAM; - pAd->StaCfg.bWindowsACCAMEnable = FALSE; - -#ifdef LEAP_SUPPORT - // CCX v1.0 releated init value - RTMPInitTimer(pAd, &pAd->StaCfg.LeapAuthTimer, GET_TIMER_FUNCTION(LeapAuthTimeout), pAd, FALSE); - pAd->StaCfg.LeapAuthMode = CISCO_AuthModeLEAPNone; - pAd->StaCfg.bCkipOn = FALSE; -#endif // LEAP_SUPPORT // - - RTMPInitTimer(pAd, &pAd->StaCfg.StaQuickResponeForRateUpTimer, GET_TIMER_FUNCTION(StaQuickResponeForRateUpExec), pAd, FALSE); - pAd->StaCfg.StaQuickResponeForRateUpTimerRunning = FALSE; - - // Patch for Ndtest - pAd->StaCfg.ScanCnt = 0; - - // CCX 2.0 control flag init - pAd->StaCfg.CCXEnable = FALSE; - pAd->StaCfg.CCXReqType = MSRN_TYPE_UNUSED; - pAd->StaCfg.CCXQosECWMin = 4; - pAd->StaCfg.CCXQosECWMax = 10; - - pAd->StaCfg.bHwRadio = TRUE; // Default Hardware Radio status is On - pAd->StaCfg.bSwRadio = TRUE; // Default Software Radio status is On - pAd->StaCfg.bRadio = TRUE; // bHwRadio && bSwRadio - pAd->StaCfg.bHardwareRadio = FALSE; // Default is OFF - pAd->StaCfg.bShowHiddenSSID = FALSE; // Default no show - - // Nitro mode control - pAd->StaCfg.bAutoReconnect = TRUE; - - // Save the init time as last scan time, the system should do scan after 2 seconds. - // This patch is for driver wake up from standby mode, system will do scan right away. - pAd->StaCfg.LastScanTime = 0; - NdisZeroMemory(pAd->nickname, IW_ESSID_MAX_SIZE+1); - sprintf(pAd->nickname, "%s", STA_NIC_DEVICE_NAME); - RTMPInitTimer(pAd, &pAd->StaCfg.WpaDisassocAndBlockAssocTimer, GET_TIMER_FUNCTION(WpaDisassocApAndBlockAssoc), pAd, FALSE); -#ifdef WPA_SUPPLICANT_SUPPORT - pAd->StaCfg.IEEE8021X = FALSE; - pAd->StaCfg.IEEE8021x_required_keys = FALSE; - pAd->StaCfg.WpaSupplicantUP = WPA_SUPPLICANT_DISABLE; -#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT - pAd->StaCfg.WpaSupplicantUP = WPA_SUPPLICANT_ENABLE; -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // -#endif // WPA_SUPPLICANT_SUPPORT // - - } -#endif // CONFIG_STA_SUPPORT // - - // Default for extra information is not valid - pAd->ExtraInfo = EXTRA_INFO_CLEAR; - - // Default Config change flag - pAd->bConfigChanged = FALSE; - - // - // part III. AP configurations - // - - - // - // part IV. others - // - // dynamic BBP R66:sensibity tuning to overcome background noise - pAd->BbpTuning.bEnable = TRUE; - pAd->BbpTuning.FalseCcaLowerThreshold = 100; - pAd->BbpTuning.FalseCcaUpperThreshold = 512; - pAd->BbpTuning.R66Delta = 4; - pAd->Mlme.bEnableAutoAntennaCheck = TRUE; - - // - // Also initial R66CurrentValue, RTUSBResumeMsduTransmission might use this value. - // if not initial this value, the default value will be 0. - // - pAd->BbpTuning.R66CurrentValue = 0x38; - - pAd->Bbp94 = BBPR94_DEFAULT; - pAd->BbpForCCK = FALSE; - - // Default is FALSE for test bit 1 - //pAd->bTest1 = FALSE; - - // initialize MAC table and allocate spin lock - NdisZeroMemory(&pAd->MacTab, sizeof(MAC_TABLE)); - InitializeQueueHeader(&pAd->MacTab.McastPsQueue); - NdisAllocateSpinLock(&pAd->MacTabLock); - - //RTMPInitTimer(pAd, &pAd->RECBATimer, RECBATimerTimeout, pAd, TRUE); - //RTMPSetTimer(&pAd->RECBATimer, REORDER_EXEC_INTV); - -#ifdef RALINK_ATE - NdisZeroMemory(&pAd->ate, sizeof(ATE_INFO)); - pAd->ate.Mode = ATE_STOP; - pAd->ate.TxCount = 200;/* to exceed TX_RING_SIZE ... */ - pAd->ate.TxLength = 1024; - pAd->ate.TxWI.ShortGI = 0;// LONG GI : 800 ns - pAd->ate.TxWI.PHYMODE = MODE_CCK; - pAd->ate.TxWI.MCS = 3; - pAd->ate.TxWI.BW = BW_20; - pAd->ate.Channel = 1; - pAd->ate.QID = QID_AC_BE; - pAd->ate.Addr1[0] = 0x00; - pAd->ate.Addr1[1] = 0x11; - pAd->ate.Addr1[2] = 0x22; - pAd->ate.Addr1[3] = 0xAA; - pAd->ate.Addr1[4] = 0xBB; - pAd->ate.Addr1[5] = 0xCC; - NdisMoveMemory(pAd->ate.Addr2, pAd->ate.Addr1, ETH_LENGTH_OF_ADDRESS); - NdisMoveMemory(pAd->ate.Addr3, pAd->ate.Addr1, ETH_LENGTH_OF_ADDRESS); - pAd->ate.bRxFer = 0; - pAd->ate.bQATxStart = FALSE; - pAd->ate.bQARxStart = FALSE; -#ifdef RALINK_28xx_QA - //pAd->ate.Repeat = 0; - pAd->ate.TxStatus = 0; - pAd->ate.AtePid = 0; -#endif // RALINK_28xx_QA // -#endif // RALINK_ATE // - - - pAd->CommonCfg.bWiFiTest = FALSE; - - - DBGPRINT(RT_DEBUG_TRACE, ("<-- UserCfgInit\n")); -} - -// IRQL = PASSIVE_LEVEL -UCHAR BtoH(char ch) -{ - if (ch >= '0' && ch <= '9') return (ch - '0'); // Handle numerals - if (ch >= 'A' && ch <= 'F') return (ch - 'A' + 0xA); // Handle capitol hex digits - if (ch >= 'a' && ch <= 'f') return (ch - 'a' + 0xA); // Handle small hex digits - return(255); -} - -// -// FUNCTION: AtoH(char *, UCHAR *, int) -// -// PURPOSE: Converts ascii string to network order hex -// -// PARAMETERS: -// src - pointer to input ascii string -// dest - pointer to output hex -// destlen - size of dest -// -// COMMENTS: -// -// 2 ascii bytes make a hex byte so must put 1st ascii byte of pair -// into upper nibble and 2nd ascii byte of pair into lower nibble. -// -// IRQL = PASSIVE_LEVEL - -void AtoH(char * src, UCHAR * dest, int destlen) -{ - char * srcptr; - PUCHAR destTemp; - - srcptr = src; - destTemp = (PUCHAR) dest; - - while(destlen--) - { - *destTemp = BtoH(*srcptr++) << 4; // Put 1st ascii byte in upper nibble. - *destTemp += BtoH(*srcptr++); // Add 2nd ascii byte to above. - destTemp++; - } -} - -VOID RTMPPatchMacBbpBug( - IN PRTMP_ADAPTER pAd) -{ - ULONG Index; - - // Initialize BBP register to default value - for (Index = 0; Index < NUM_BBP_REG_PARMS; Index++) - { - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBPRegTable[Index].Register, (UCHAR)BBPRegTable[Index].Value); - } - - // Initialize RF register to default value - AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); - AsicLockChannel(pAd, pAd->CommonCfg.Channel); - - // Re-init BBP register from EEPROM value - NICInitAsicFromEEPROM(pAd); -} - -/* - ======================================================================== - - Routine Description: - Init timer objects - - Arguments: - pAd Pointer to our adapter - pTimer Timer structure - pTimerFunc Function to execute when timer expired - Repeat Ture for period timer - - Return Value: - None - - Note: - - ======================================================================== -*/ -VOID RTMPInitTimer( - IN PRTMP_ADAPTER pAd, - IN PRALINK_TIMER_STRUCT pTimer, - IN PVOID pTimerFunc, - IN PVOID pData, - IN BOOLEAN Repeat) -{ - // - // Set Valid to TRUE for later used. - // It will crash if we cancel a timer or set a timer - // that we haven't initialize before. - // - pTimer->Valid = TRUE; - - pTimer->PeriodicType = Repeat; - pTimer->State = FALSE; - pTimer->cookie = (ULONG) pData; - -#ifdef RT2870 - pTimer->pAd = pAd; -#endif // RT2870 // - - RTMP_OS_Init_Timer(pAd, &pTimer->TimerObj, pTimerFunc, (PVOID) pTimer); -} - -/* - ======================================================================== - - Routine Description: - Init timer objects - - Arguments: - pTimer Timer structure - Value Timer value in milliseconds - - Return Value: - None - - Note: - To use this routine, must call RTMPInitTimer before. - - ======================================================================== -*/ -VOID RTMPSetTimer( - IN PRALINK_TIMER_STRUCT pTimer, - IN ULONG Value) -{ - if (pTimer->Valid) - { - pTimer->TimerValue = Value; - pTimer->State = FALSE; - if (pTimer->PeriodicType == TRUE) - { - pTimer->Repeat = TRUE; - RTMP_SetPeriodicTimer(&pTimer->TimerObj, Value); - } - else - { - pTimer->Repeat = FALSE; - RTMP_OS_Add_Timer(&pTimer->TimerObj, Value); - } - } - else - { - DBGPRINT_ERR(("RTMPSetTimer failed, Timer hasn't been initialize!\n")); - } -} - - -/* - ======================================================================== - - Routine Description: - Init timer objects - - Arguments: - pTimer Timer structure - Value Timer value in milliseconds - - Return Value: - None - - Note: - To use this routine, must call RTMPInitTimer before. - - ======================================================================== -*/ -VOID RTMPModTimer( - IN PRALINK_TIMER_STRUCT pTimer, - IN ULONG Value) -{ - BOOLEAN Cancel; - - if (pTimer->Valid) - { - pTimer->TimerValue = Value; - pTimer->State = FALSE; - if (pTimer->PeriodicType == TRUE) - { - RTMPCancelTimer(pTimer, &Cancel); - RTMPSetTimer(pTimer, Value); - } - else - { - RTMP_OS_Mod_Timer(&pTimer->TimerObj, Value); - } - } - else - { - DBGPRINT_ERR(("RTMPModTimer failed, Timer hasn't been initialize!\n")); - } -} - -/* - ======================================================================== - - Routine Description: - Cancel timer objects - - Arguments: - Adapter Pointer to our adapter - - Return Value: - None - - IRQL = PASSIVE_LEVEL - IRQL = DISPATCH_LEVEL - - Note: - 1.) To use this routine, must call RTMPInitTimer before. - 2.) Reset NIC to initial state AS IS system boot up time. - - ======================================================================== -*/ -VOID RTMPCancelTimer( - IN PRALINK_TIMER_STRUCT pTimer, - OUT BOOLEAN *pCancelled) -{ - if (pTimer->Valid) - { - if (pTimer->State == FALSE) - pTimer->Repeat = FALSE; - RTMP_OS_Del_Timer(&pTimer->TimerObj, pCancelled); - - if (*pCancelled == TRUE) - pTimer->State = TRUE; - -#ifdef RT2870 - // We need to go-through the TimerQ to findout this timer handler and remove it if - // it's still waiting for execution. - - RT2870_TimerQ_Remove(pTimer->pAd, pTimer); -#endif // RT2870 // - } - else - { - // - // NdisMCancelTimer just canced the timer and not mean release the timer. - // And don't set the "Valid" to False. So that we can use this timer again. - // - DBGPRINT_ERR(("RTMPCancelTimer failed, Timer hasn't been initialize!\n")); - } -} - -/* - ======================================================================== - - Routine Description: - Set LED Status - - Arguments: - pAd Pointer to our adapter - Status LED Status - - Return Value: - None - - IRQL = PASSIVE_LEVEL - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -VOID RTMPSetLED( - IN PRTMP_ADAPTER pAd, - IN UCHAR Status) -{ - //ULONG data; - UCHAR HighByte = 0; - UCHAR LowByte; - -// In ATE mode of RT2860 AP/STA, we have erased 8051 firmware. -// So LED mode is not supported when ATE is running. -#ifdef RALINK_ATE - if (ATE_ON(pAd)) - return; -#endif // RALINK_ATE // - - LowByte = pAd->LedCntl.field.LedMode&0x7f; - switch (Status) - { - case LED_LINK_DOWN: - HighByte = 0x20; - AsicSendCommandToMcu(pAd, 0x50, 0xff, LowByte, HighByte); - pAd->LedIndicatorStregth = 0; - break; - case LED_LINK_UP: - if (pAd->CommonCfg.Channel > 14) - HighByte = 0xa0; - else - HighByte = 0x60; - AsicSendCommandToMcu(pAd, 0x50, 0xff, LowByte, HighByte); - break; - case LED_RADIO_ON: - HighByte = 0x20; - AsicSendCommandToMcu(pAd, 0x50, 0xff, LowByte, HighByte); - break; - case LED_HALT: - LowByte = 0; // Driver sets MAC register and MAC controls LED - case LED_RADIO_OFF: - HighByte = 0; - AsicSendCommandToMcu(pAd, 0x50, 0xff, LowByte, HighByte); - break; - case LED_WPS: - HighByte = 0x10; - AsicSendCommandToMcu(pAd, 0x50, 0xff, LowByte, HighByte); - break; - case LED_ON_SITE_SURVEY: - HighByte = 0x08; - AsicSendCommandToMcu(pAd, 0x50, 0xff, LowByte, HighByte); - break; - case LED_POWER_UP: - HighByte = 0x04; - AsicSendCommandToMcu(pAd, 0x50, 0xff, LowByte, HighByte); - break; - default: - DBGPRINT(RT_DEBUG_WARN, ("RTMPSetLED::Unknown Status %d\n", Status)); - break; - } - - // - // Keep LED status for LED SiteSurvey mode. - // After SiteSurvey, we will set the LED mode to previous status. - // - if ((Status != LED_ON_SITE_SURVEY) && (Status != LED_POWER_UP)) - pAd->LedStatus = Status; - - DBGPRINT(RT_DEBUG_TRACE, ("RTMPSetLED::Mode=%d,HighByte=0x%02x,LowByte=0x%02x\n", pAd->LedCntl.field.LedMode, HighByte, LowByte)); -} - -/* - ======================================================================== - - Routine Description: - Set LED Signal Stregth - - Arguments: - pAd Pointer to our adapter - Dbm Signal Stregth - - Return Value: - None - - IRQL = PASSIVE_LEVEL - - Note: - Can be run on any IRQL level. - - According to Microsoft Zero Config Wireless Signal Stregth definition as belows. - <= -90 No Signal - <= -81 Very Low - <= -71 Low - <= -67 Good - <= -57 Very Good - > -57 Excellent - ======================================================================== -*/ -VOID RTMPSetSignalLED( - IN PRTMP_ADAPTER pAd, - IN NDIS_802_11_RSSI Dbm) -{ - UCHAR nLed = 0; - - // - // if not Signal Stregth, then do nothing. - // - if (pAd->LedCntl.field.LedMode != LED_MODE_SIGNAL_STREGTH) - { - return; - } - - if (Dbm <= -90) - nLed = 0; - else if (Dbm <= -81) - nLed = 1; - else if (Dbm <= -71) - nLed = 3; - else if (Dbm <= -67) - nLed = 7; - else if (Dbm <= -57) - nLed = 15; - else - nLed = 31; - - // - // Update Signal Stregth to firmware if changed. - // - if (pAd->LedIndicatorStregth != nLed) - { - AsicSendCommandToMcu(pAd, 0x51, 0xff, nLed, pAd->LedCntl.field.Polarity); - pAd->LedIndicatorStregth = nLed; - } -} - -/* - ======================================================================== - - Routine Description: - Enable RX - - Arguments: - pAd Pointer to our adapter - - Return Value: - None - - IRQL <= DISPATCH_LEVEL - - Note: - Before Enable RX, make sure you have enabled Interrupt. - ======================================================================== -*/ -VOID RTMPEnableRxTx( - IN PRTMP_ADAPTER pAd) -{ -// WPDMA_GLO_CFG_STRUC GloCfg; -// ULONG i = 0; - - DBGPRINT(RT_DEBUG_TRACE, ("==> RTMPEnableRxTx\n")); - - // Enable Rx DMA. - RT28XXDMAEnable(pAd); - - // enable RX of MAC block - if (pAd->OpMode == OPMODE_AP) - { - UINT32 rx_filter_flag = APNORMAL; - - - RTMP_IO_WRITE32(pAd, RX_FILTR_CFG, rx_filter_flag); // enable RX of DMA block - } - else - { - RTMP_IO_WRITE32(pAd, RX_FILTR_CFG, STANORMAL); // Staion not drop control frame will fail WiFi Certification. - } - - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0xc); - DBGPRINT(RT_DEBUG_TRACE, ("<== RTMPEnableRxTx\n")); -} - - +#include "../../rt2870/common/rtmp_init.c" diff --git a/drivers/staging/rt3070/common/rtmp_tkip.c b/drivers/staging/rt3070/common/rtmp_tkip.c index bf8986e83679..57a5ee96f311 100644 --- a/drivers/staging/rt3070/common/rtmp_tkip.c +++ b/drivers/staging/rt3070/common/rtmp_tkip.c @@ -1,1613 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - rtmp_tkip.c - - Abstract: - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Paul Wu 02-25-02 Initial -*/ - -#include "../rt_config.h" - -// Rotation functions on 32 bit values -#define ROL32( A, n ) \ - ( ((A) << (n)) | ( ((A)>>(32-(n))) & ( (1UL << (n)) - 1 ) ) ) -#define ROR32( A, n ) ROL32( (A), 32-(n) ) - -UINT Tkip_Sbox_Lower[256] = -{ - 0xA5,0x84,0x99,0x8D,0x0D,0xBD,0xB1,0x54, - 0x50,0x03,0xA9,0x7D,0x19,0x62,0xE6,0x9A, - 0x45,0x9D,0x40,0x87,0x15,0xEB,0xC9,0x0B, - 0xEC,0x67,0xFD,0xEA,0xBF,0xF7,0x96,0x5B, - 0xC2,0x1C,0xAE,0x6A,0x5A,0x41,0x02,0x4F, - 0x5C,0xF4,0x34,0x08,0x93,0x73,0x53,0x3F, - 0x0C,0x52,0x65,0x5E,0x28,0xA1,0x0F,0xB5, - 0x09,0x36,0x9B,0x3D,0x26,0x69,0xCD,0x9F, - 0x1B,0x9E,0x74,0x2E,0x2D,0xB2,0xEE,0xFB, - 0xF6,0x4D,0x61,0xCE,0x7B,0x3E,0x71,0x97, - 0xF5,0x68,0x00,0x2C,0x60,0x1F,0xC8,0xED, - 0xBE,0x46,0xD9,0x4B,0xDE,0xD4,0xE8,0x4A, - 0x6B,0x2A,0xE5,0x16,0xC5,0xD7,0x55,0x94, - 0xCF,0x10,0x06,0x81,0xF0,0x44,0xBA,0xE3, - 0xF3,0xFE,0xC0,0x8A,0xAD,0xBC,0x48,0x04, - 0xDF,0xC1,0x75,0x63,0x30,0x1A,0x0E,0x6D, - 0x4C,0x14,0x35,0x2F,0xE1,0xA2,0xCC,0x39, - 0x57,0xF2,0x82,0x47,0xAC,0xE7,0x2B,0x95, - 0xA0,0x98,0xD1,0x7F,0x66,0x7E,0xAB,0x83, - 0xCA,0x29,0xD3,0x3C,0x79,0xE2,0x1D,0x76, - 0x3B,0x56,0x4E,0x1E,0xDB,0x0A,0x6C,0xE4, - 0x5D,0x6E,0xEF,0xA6,0xA8,0xA4,0x37,0x8B, - 0x32,0x43,0x59,0xB7,0x8C,0x64,0xD2,0xE0, - 0xB4,0xFA,0x07,0x25,0xAF,0x8E,0xE9,0x18, - 0xD5,0x88,0x6F,0x72,0x24,0xF1,0xC7,0x51, - 0x23,0x7C,0x9C,0x21,0xDD,0xDC,0x86,0x85, - 0x90,0x42,0xC4,0xAA,0xD8,0x05,0x01,0x12, - 0xA3,0x5F,0xF9,0xD0,0x91,0x58,0x27,0xB9, - 0x38,0x13,0xB3,0x33,0xBB,0x70,0x89,0xA7, - 0xB6,0x22,0x92,0x20,0x49,0xFF,0x78,0x7A, - 0x8F,0xF8,0x80,0x17,0xDA,0x31,0xC6,0xB8, - 0xC3,0xB0,0x77,0x11,0xCB,0xFC,0xD6,0x3A -}; - -UINT Tkip_Sbox_Upper[256] = -{ - 0xC6,0xF8,0xEE,0xF6,0xFF,0xD6,0xDE,0x91, - 0x60,0x02,0xCE,0x56,0xE7,0xB5,0x4D,0xEC, - 0x8F,0x1F,0x89,0xFA,0xEF,0xB2,0x8E,0xFB, - 0x41,0xB3,0x5F,0x45,0x23,0x53,0xE4,0x9B, - 0x75,0xE1,0x3D,0x4C,0x6C,0x7E,0xF5,0x83, - 0x68,0x51,0xD1,0xF9,0xE2,0xAB,0x62,0x2A, - 0x08,0x95,0x46,0x9D,0x30,0x37,0x0A,0x2F, - 0x0E,0x24,0x1B,0xDF,0xCD,0x4E,0x7F,0xEA, - 0x12,0x1D,0x58,0x34,0x36,0xDC,0xB4,0x5B, - 0xA4,0x76,0xB7,0x7D,0x52,0xDD,0x5E,0x13, - 0xA6,0xB9,0x00,0xC1,0x40,0xE3,0x79,0xB6, - 0xD4,0x8D,0x67,0x72,0x94,0x98,0xB0,0x85, - 0xBB,0xC5,0x4F,0xED,0x86,0x9A,0x66,0x11, - 0x8A,0xE9,0x04,0xFE,0xA0,0x78,0x25,0x4B, - 0xA2,0x5D,0x80,0x05,0x3F,0x21,0x70,0xF1, - 0x63,0x77,0xAF,0x42,0x20,0xE5,0xFD,0xBF, - 0x81,0x18,0x26,0xC3,0xBE,0x35,0x88,0x2E, - 0x93,0x55,0xFC,0x7A,0xC8,0xBA,0x32,0xE6, - 0xC0,0x19,0x9E,0xA3,0x44,0x54,0x3B,0x0B, - 0x8C,0xC7,0x6B,0x28,0xA7,0xBC,0x16,0xAD, - 0xDB,0x64,0x74,0x14,0x92,0x0C,0x48,0xB8, - 0x9F,0xBD,0x43,0xC4,0x39,0x31,0xD3,0xF2, - 0xD5,0x8B,0x6E,0xDA,0x01,0xB1,0x9C,0x49, - 0xD8,0xAC,0xF3,0xCF,0xCA,0xF4,0x47,0x10, - 0x6F,0xF0,0x4A,0x5C,0x38,0x57,0x73,0x97, - 0xCB,0xA1,0xE8,0x3E,0x96,0x61,0x0D,0x0F, - 0xE0,0x7C,0x71,0xCC,0x90,0x06,0xF7,0x1C, - 0xC2,0x6A,0xAE,0x69,0x17,0x99,0x3A,0x27, - 0xD9,0xEB,0x2B,0x22,0xD2,0xA9,0x07,0x33, - 0x2D,0x3C,0x15,0xC9,0x87,0xAA,0x50,0xA5, - 0x03,0x59,0x09,0x1A,0x65,0xD7,0x84,0xD0, - 0x82,0x29,0x5A,0x1E,0x7B,0xA8,0x6D,0x2C -}; - -/*****************************/ -/******** SBOX Table *********/ -/*****************************/ - -UCHAR SboxTable[256] = -{ - 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, - 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, - 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, - 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, - 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, - 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, - 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, - 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, - 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, - 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, - 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, - 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, - 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, - 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, - 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, - 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, - 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, - 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, - 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, - 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, - 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, - 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, - 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, - 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, - 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, - 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, - 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, - 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, - 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, - 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, - 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, - 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 -}; - -VOID xor_32( - IN PUCHAR a, - IN PUCHAR b, - OUT PUCHAR out); - -VOID xor_128( - IN PUCHAR a, - IN PUCHAR b, - OUT PUCHAR out); - -VOID next_key( - IN PUCHAR key, - IN INT round); - -VOID byte_sub( - IN PUCHAR in, - OUT PUCHAR out); - -VOID shift_row( - IN PUCHAR in, - OUT PUCHAR out); - -VOID mix_column( - IN PUCHAR in, - OUT PUCHAR out); - -UCHAR RTMPCkipSbox( - IN UCHAR a); -// -// Expanded IV for TKIP function. -// -typedef struct PACKED _IV_CONTROL_ -{ - union PACKED - { - struct PACKED - { - UCHAR rc0; - UCHAR rc1; - UCHAR rc2; - - union PACKED - { - struct PACKED - { -#ifdef RT_BIG_ENDIAN - UCHAR KeyID:2; - UCHAR ExtIV:1; - UCHAR Rsvd:5; -#else - UCHAR Rsvd:5; - UCHAR ExtIV:1; - UCHAR KeyID:2; -#endif - } field; - UCHAR Byte; - } CONTROL; - } field; - - ULONG word; - } IV16; - - ULONG IV32; -} TKIP_IV, *PTKIP_IV; - - -/* - ======================================================================== - - Routine Description: - Convert from UCHAR[] to ULONG in a portable way - - Arguments: - pMICKey pointer to MIC Key - - Return Value: - None - - Note: - - ======================================================================== -*/ -ULONG RTMPTkipGetUInt32( - IN PUCHAR pMICKey) -{ - ULONG res = 0; - INT i; - - for (i = 0; i < 4; i++) - { - res |= (*pMICKey++) << (8 * i); - } - - return res; -} - -/* - ======================================================================== - - Routine Description: - Convert from ULONG to UCHAR[] in a portable way - - Arguments: - pDst pointer to destination for convert ULONG to UCHAR[] - val the value for convert - - Return Value: - None - - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -VOID RTMPTkipPutUInt32( - IN OUT PUCHAR pDst, - IN ULONG val) -{ - INT i; - - for(i = 0; i < 4; i++) - { - *pDst++ = (UCHAR) (val & 0xff); - val >>= 8; - } -} - -/* - ======================================================================== - - Routine Description: - Set the MIC Key. - - Arguments: - pAd Pointer to our adapter - pMICKey pointer to MIC Key - - Return Value: - None - - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -VOID RTMPTkipSetMICKey( - IN PTKIP_KEY_INFO pTkip, - IN PUCHAR pMICKey) -{ - // Set the key - pTkip->K0 = RTMPTkipGetUInt32(pMICKey); - pTkip->K1 = RTMPTkipGetUInt32(pMICKey + 4); - // and reset the message - pTkip->L = pTkip->K0; - pTkip->R = pTkip->K1; - pTkip->nBytesInM = 0; - pTkip->M = 0; -} - -/* - ======================================================================== - - Routine Description: - Calculate the MIC Value. - - Arguments: - pAd Pointer to our adapter - uChar Append this uChar - - Return Value: - None - - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -VOID RTMPTkipAppendByte( - IN PTKIP_KEY_INFO pTkip, - IN UCHAR uChar) -{ - // Append the byte to our word-sized buffer - pTkip->M |= (uChar << (8* pTkip->nBytesInM)); - pTkip->nBytesInM++; - // Process the word if it is full. - if( pTkip->nBytesInM >= 4 ) - { - pTkip->L ^= pTkip->M; - pTkip->R ^= ROL32( pTkip->L, 17 ); - pTkip->L += pTkip->R; - pTkip->R ^= ((pTkip->L & 0xff00ff00) >> 8) | ((pTkip->L & 0x00ff00ff) << 8); - pTkip->L += pTkip->R; - pTkip->R ^= ROL32( pTkip->L, 3 ); - pTkip->L += pTkip->R; - pTkip->R ^= ROR32( pTkip->L, 2 ); - pTkip->L += pTkip->R; - // Clear the buffer - pTkip->M = 0; - pTkip->nBytesInM = 0; - } -} - -/* - ======================================================================== - - Routine Description: - Calculate the MIC Value. - - Arguments: - pAd Pointer to our adapter - pSrc Pointer to source data for Calculate MIC Value - Len Indicate the length of the source data - - Return Value: - None - - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -VOID RTMPTkipAppend( - IN PTKIP_KEY_INFO pTkip, - IN PUCHAR pSrc, - IN UINT nBytes) -{ - // This is simple - while(nBytes > 0) - { - RTMPTkipAppendByte(pTkip, *pSrc++); - nBytes--; - } -} - -/* - ======================================================================== - - Routine Description: - Get the MIC Value. - - Arguments: - pAd Pointer to our adapter - - Return Value: - None - - IRQL = DISPATCH_LEVEL - - Note: - the MIC Value is store in pAd->PrivateInfo.MIC - ======================================================================== -*/ -VOID RTMPTkipGetMIC( - IN PTKIP_KEY_INFO pTkip) -{ - // Append the minimum padding - RTMPTkipAppendByte(pTkip, 0x5a ); - RTMPTkipAppendByte(pTkip, 0 ); - RTMPTkipAppendByte(pTkip, 0 ); - RTMPTkipAppendByte(pTkip, 0 ); - RTMPTkipAppendByte(pTkip, 0 ); - // and then zeroes until the length is a multiple of 4 - while( pTkip->nBytesInM != 0 ) - { - RTMPTkipAppendByte(pTkip, 0 ); - } - // The appendByte function has already computed the result. - RTMPTkipPutUInt32(pTkip->MIC, pTkip->L); - RTMPTkipPutUInt32(pTkip->MIC + 4, pTkip->R); -} - -/* - ======================================================================== - - Routine Description: - Init Tkip function. - - Arguments: - pAd Pointer to our adapter - pTKey Pointer to the Temporal Key (TK), TK shall be 128bits. - KeyId TK Key ID - pTA Pointer to transmitter address - pMICKey pointer to MIC Key - - Return Value: - None - - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -VOID RTMPInitTkipEngine( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pKey, - IN UCHAR KeyId, - IN PUCHAR pTA, - IN PUCHAR pMICKey, - IN PUCHAR pTSC, - OUT PULONG pIV16, - OUT PULONG pIV32) -{ - TKIP_IV tkipIv; - - // Prepare 8 bytes TKIP encapsulation for MPDU - NdisZeroMemory(&tkipIv, sizeof(TKIP_IV)); - tkipIv.IV16.field.rc0 = *(pTSC + 1); - tkipIv.IV16.field.rc1 = (tkipIv.IV16.field.rc0 | 0x20) & 0x7f; - tkipIv.IV16.field.rc2 = *pTSC; - tkipIv.IV16.field.CONTROL.field.ExtIV = 1; // 0: non-extended IV, 1: an extended IV - tkipIv.IV16.field.CONTROL.field.KeyID = KeyId; -// tkipIv.IV32 = *(PULONG)(pTSC + 2); - NdisMoveMemory(&tkipIv.IV32, (pTSC + 2), 4); // Copy IV - - *pIV16 = tkipIv.IV16.word; - *pIV32 = tkipIv.IV32; -} - -/* - ======================================================================== - - Routine Description: - Init MIC Value calculation function which include set MIC key & - calculate first 16 bytes (DA + SA + priority + 0) - - Arguments: - pAd Pointer to our adapter - pTKey Pointer to the Temporal Key (TK), TK shall be 128bits. - pDA Pointer to DA address - pSA Pointer to SA address - pMICKey pointer to MIC Key - - Return Value: - None - - Note: - - ======================================================================== -*/ -VOID RTMPInitMICEngine( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pKey, - IN PUCHAR pDA, - IN PUCHAR pSA, - IN UCHAR UserPriority, - IN PUCHAR pMICKey) -{ - ULONG Priority = UserPriority; - - // Init MIC value calculation - RTMPTkipSetMICKey(&pAd->PrivateInfo.Tx, pMICKey); - // DA - RTMPTkipAppend(&pAd->PrivateInfo.Tx, pDA, MAC_ADDR_LEN); - // SA - RTMPTkipAppend(&pAd->PrivateInfo.Tx, pSA, MAC_ADDR_LEN); - // Priority + 3 bytes of 0 - RTMPTkipAppend(&pAd->PrivateInfo.Tx, (PUCHAR)&Priority, 4); -} - -/* - ======================================================================== - - Routine Description: - Compare MIC value of received MSDU - - Arguments: - pAd Pointer to our adapter - pSrc Pointer to the received Plain text data - pDA Pointer to DA address - pSA Pointer to SA address - pMICKey pointer to MIC Key - Len the length of the received plain text data exclude MIC value - - Return Value: - TRUE MIC value matched - FALSE MIC value mismatched - - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -BOOLEAN RTMPTkipCompareMICValue( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pSrc, - IN PUCHAR pDA, - IN PUCHAR pSA, - IN PUCHAR pMICKey, - IN UCHAR UserPriority, - IN UINT Len) -{ - UCHAR OldMic[8]; - ULONG Priority = UserPriority; - - // Init MIC value calculation - RTMPTkipSetMICKey(&pAd->PrivateInfo.Rx, pMICKey); - // DA - RTMPTkipAppend(&pAd->PrivateInfo.Rx, pDA, MAC_ADDR_LEN); - // SA - RTMPTkipAppend(&pAd->PrivateInfo.Rx, pSA, MAC_ADDR_LEN); - // Priority + 3 bytes of 0 - RTMPTkipAppend(&pAd->PrivateInfo.Rx, (PUCHAR)&Priority, 4); - - // Calculate MIC value from plain text data - RTMPTkipAppend(&pAd->PrivateInfo.Rx, pSrc, Len); - - // Get MIC valude from received frame - NdisMoveMemory(OldMic, pSrc + Len, 8); - - // Get MIC value from decrypted plain data - RTMPTkipGetMIC(&pAd->PrivateInfo.Rx); - - // Move MIC value from MSDU, this steps should move to data path. - // Since the MIC value might cross MPDUs. - if(!NdisEqualMemory(pAd->PrivateInfo.Rx.MIC, OldMic, 8)) - { - DBGPRINT_RAW(RT_DEBUG_ERROR, ("RTMPTkipCompareMICValue(): TKIP MIC Error !\n")); //MIC error. - - - return (FALSE); - } - return (TRUE); -} - -/* - ======================================================================== - - Routine Description: - Compare MIC value of received MSDU - - Arguments: - pAd Pointer to our adapter - pLLC LLC header - pSrc Pointer to the received Plain text data - pDA Pointer to DA address - pSA Pointer to SA address - pMICKey pointer to MIC Key - Len the length of the received plain text data exclude MIC value - - Return Value: - TRUE MIC value matched - FALSE MIC value mismatched - - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -BOOLEAN RTMPTkipCompareMICValueWithLLC( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pLLC, - IN PUCHAR pSrc, - IN PUCHAR pDA, - IN PUCHAR pSA, - IN PUCHAR pMICKey, - IN UINT Len) -{ - UCHAR OldMic[8]; - ULONG Priority = 0; - - // Init MIC value calculation - RTMPTkipSetMICKey(&pAd->PrivateInfo.Rx, pMICKey); - // DA - RTMPTkipAppend(&pAd->PrivateInfo.Rx, pDA, MAC_ADDR_LEN); - // SA - RTMPTkipAppend(&pAd->PrivateInfo.Rx, pSA, MAC_ADDR_LEN); - // Priority + 3 bytes of 0 - RTMPTkipAppend(&pAd->PrivateInfo.Rx, (PUCHAR)&Priority, 4); - - // Start with LLC header - RTMPTkipAppend(&pAd->PrivateInfo.Rx, pLLC, 8); - - // Calculate MIC value from plain text data - RTMPTkipAppend(&pAd->PrivateInfo.Rx, pSrc, Len); - - // Get MIC valude from received frame - NdisMoveMemory(OldMic, pSrc + Len, 8); - - // Get MIC value from decrypted plain data - RTMPTkipGetMIC(&pAd->PrivateInfo.Rx); - - // Move MIC value from MSDU, this steps should move to data path. - // Since the MIC value might cross MPDUs. - if(!NdisEqualMemory(pAd->PrivateInfo.Rx.MIC, OldMic, 8)) - { - DBGPRINT_RAW(RT_DEBUG_ERROR, ("RTMPTkipCompareMICValueWithLLC(): TKIP MIC Error !\n")); //MIC error. - - - return (FALSE); - } - return (TRUE); -} -/* - ======================================================================== - - Routine Description: - Copy frame from waiting queue into relative ring buffer and set - appropriate ASIC register to kick hardware transmit function - - Arguments: - pAd Pointer to our adapter - PNDIS_PACKET Pointer to Ndis Packet for MIC calculation - pEncap Pointer to LLC encap data - LenEncap Total encap length, might be 0 which indicates no encap - - Return Value: - None - - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -VOID RTMPCalculateMICValue( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket, - IN PUCHAR pEncap, - IN PCIPHER_KEY pKey, - IN UCHAR apidx) -{ - PACKET_INFO PacketInfo; - PUCHAR pSrcBufVA; - UINT SrcBufLen; - PUCHAR pSrc; - UCHAR UserPriority; - UCHAR vlan_offset = 0; - - RTMP_QueryPacketInfo(pPacket, &PacketInfo, &pSrcBufVA, &SrcBufLen); - - UserPriority = RTMP_GET_PACKET_UP(pPacket); - pSrc = pSrcBufVA; - - // determine if this is a vlan packet - if (((*(pSrc + 12) << 8) + *(pSrc + 13)) == 0x8100) - vlan_offset = 4; - -#ifdef CONFIG_STA_SUPPORT -#endif // CONFIG_STA_SUPPORT // - { - RTMPInitMICEngine( - pAd, - pKey->Key, - pSrc, - pSrc + 6, - UserPriority, - pKey->TxMic); - } - - - if (pEncap != NULL) - { - // LLC encapsulation - RTMPTkipAppend(&pAd->PrivateInfo.Tx, pEncap, 6); - // Protocol Type - RTMPTkipAppend(&pAd->PrivateInfo.Tx, pSrc + 12 + vlan_offset, 2); - } - SrcBufLen -= (14 + vlan_offset); - pSrc += (14 + vlan_offset); - do - { - if (SrcBufLen > 0) - { - RTMPTkipAppend(&pAd->PrivateInfo.Tx, pSrc, SrcBufLen); - } - - break; // No need handle next packet - - } while (TRUE); // End of copying payload - - // Compute the final MIC Value - RTMPTkipGetMIC(&pAd->PrivateInfo.Tx); -} - - -/************************************************************/ -/* tkip_sbox() */ -/* Returns a 16 bit value from a 64K entry table. The Table */ -/* is synthesized from two 256 entry byte wide tables. */ -/************************************************************/ - -UINT tkip_sbox(UINT index) -{ - UINT index_low; - UINT index_high; - UINT left, right; - - index_low = (index % 256); - index_high = ((index >> 8) % 256); - - left = Tkip_Sbox_Lower[index_low] + (Tkip_Sbox_Upper[index_low] * 256); - right = Tkip_Sbox_Upper[index_high] + (Tkip_Sbox_Lower[index_high] * 256); - - return (left ^ right); -} - -UINT rotr1(UINT a) -{ - unsigned int b; - - if ((a & 0x01) == 0x01) - { - b = (a >> 1) | 0x8000; - } - else - { - b = (a >> 1) & 0x7fff; - } - b = b % 65536; - return b; -} - -VOID RTMPTkipMixKey( - UCHAR *key, - UCHAR *ta, - ULONG pnl, /* Least significant 16 bits of PN */ - ULONG pnh, /* Most significant 32 bits of PN */ - UCHAR *rc4key, - UINT *p1k) -{ - - UINT tsc0; - UINT tsc1; - UINT tsc2; - - UINT ppk0; - UINT ppk1; - UINT ppk2; - UINT ppk3; - UINT ppk4; - UINT ppk5; - - INT i; - INT j; - - tsc0 = (unsigned int)((pnh >> 16) % 65536); /* msb */ - tsc1 = (unsigned int)(pnh % 65536); - tsc2 = (unsigned int)(pnl % 65536); /* lsb */ - - /* Phase 1, step 1 */ - p1k[0] = tsc1; - p1k[1] = tsc0; - p1k[2] = (UINT)(ta[0] + (ta[1]*256)); - p1k[3] = (UINT)(ta[2] + (ta[3]*256)); - p1k[4] = (UINT)(ta[4] + (ta[5]*256)); - - /* Phase 1, step 2 */ - for (i=0; i<8; i++) - { - j = 2*(i & 1); - p1k[0] = (p1k[0] + tkip_sbox( (p1k[4] ^ ((256*key[1+j]) + key[j])) % 65536 )) % 65536; - p1k[1] = (p1k[1] + tkip_sbox( (p1k[0] ^ ((256*key[5+j]) + key[4+j])) % 65536 )) % 65536; - p1k[2] = (p1k[2] + tkip_sbox( (p1k[1] ^ ((256*key[9+j]) + key[8+j])) % 65536 )) % 65536; - p1k[3] = (p1k[3] + tkip_sbox( (p1k[2] ^ ((256*key[13+j]) + key[12+j])) % 65536 )) % 65536; - p1k[4] = (p1k[4] + tkip_sbox( (p1k[3] ^ (((256*key[1+j]) + key[j]))) % 65536 )) % 65536; - p1k[4] = (p1k[4] + i) % 65536; - } - - /* Phase 2, Step 1 */ - ppk0 = p1k[0]; - ppk1 = p1k[1]; - ppk2 = p1k[2]; - ppk3 = p1k[3]; - ppk4 = p1k[4]; - ppk5 = (p1k[4] + tsc2) % 65536; - - /* Phase2, Step 2 */ - ppk0 = ppk0 + tkip_sbox( (ppk5 ^ ((256*key[1]) + key[0])) % 65536); - ppk1 = ppk1 + tkip_sbox( (ppk0 ^ ((256*key[3]) + key[2])) % 65536); - ppk2 = ppk2 + tkip_sbox( (ppk1 ^ ((256*key[5]) + key[4])) % 65536); - ppk3 = ppk3 + tkip_sbox( (ppk2 ^ ((256*key[7]) + key[6])) % 65536); - ppk4 = ppk4 + tkip_sbox( (ppk3 ^ ((256*key[9]) + key[8])) % 65536); - ppk5 = ppk5 + tkip_sbox( (ppk4 ^ ((256*key[11]) + key[10])) % 65536); - - ppk0 = ppk0 + rotr1(ppk5 ^ ((256*key[13]) + key[12])); - ppk1 = ppk1 + rotr1(ppk0 ^ ((256*key[15]) + key[14])); - ppk2 = ppk2 + rotr1(ppk1); - ppk3 = ppk3 + rotr1(ppk2); - ppk4 = ppk4 + rotr1(ppk3); - ppk5 = ppk5 + rotr1(ppk4); - - /* Phase 2, Step 3 */ - /* Phase 2, Step 3 */ - - tsc0 = (unsigned int)((pnh >> 16) % 65536); /* msb */ - tsc1 = (unsigned int)(pnh % 65536); - tsc2 = (unsigned int)(pnl % 65536); /* lsb */ - - rc4key[0] = (tsc2 >> 8) % 256; - rc4key[1] = (((tsc2 >> 8) % 256) | 0x20) & 0x7f; - rc4key[2] = tsc2 % 256; - rc4key[3] = ((ppk5 ^ ((256*key[1]) + key[0])) >> 1) % 256; - - rc4key[4] = ppk0 % 256; - rc4key[5] = (ppk0 >> 8) % 256; - - rc4key[6] = ppk1 % 256; - rc4key[7] = (ppk1 >> 8) % 256; - - rc4key[8] = ppk2 % 256; - rc4key[9] = (ppk2 >> 8) % 256; - - rc4key[10] = ppk3 % 256; - rc4key[11] = (ppk3 >> 8) % 256; - - rc4key[12] = ppk4 % 256; - rc4key[13] = (ppk4 >> 8) % 256; - - rc4key[14] = ppk5 % 256; - rc4key[15] = (ppk5 >> 8) % 256; -} - - -/************************************************/ -/* construct_mic_header1() */ -/* Builds the first MIC header block from */ -/* header fields. */ -/************************************************/ - -void construct_mic_header1( - unsigned char *mic_header1, - int header_length, - unsigned char *mpdu) -{ - mic_header1[0] = (unsigned char)((header_length - 2) / 256); - mic_header1[1] = (unsigned char)((header_length - 2) % 256); - mic_header1[2] = mpdu[0] & 0xcf; /* Mute CF poll & CF ack bits */ - mic_header1[3] = mpdu[1] & 0xc7; /* Mute retry, more data and pwr mgt bits */ - mic_header1[4] = mpdu[4]; /* A1 */ - mic_header1[5] = mpdu[5]; - mic_header1[6] = mpdu[6]; - mic_header1[7] = mpdu[7]; - mic_header1[8] = mpdu[8]; - mic_header1[9] = mpdu[9]; - mic_header1[10] = mpdu[10]; /* A2 */ - mic_header1[11] = mpdu[11]; - mic_header1[12] = mpdu[12]; - mic_header1[13] = mpdu[13]; - mic_header1[14] = mpdu[14]; - mic_header1[15] = mpdu[15]; -} - -/************************************************/ -/* construct_mic_header2() */ -/* Builds the last MIC header block from */ -/* header fields. */ -/************************************************/ - -void construct_mic_header2( - unsigned char *mic_header2, - unsigned char *mpdu, - int a4_exists, - int qc_exists) -{ - int i; - - for (i = 0; i<16; i++) mic_header2[i]=0x00; - - mic_header2[0] = mpdu[16]; /* A3 */ - mic_header2[1] = mpdu[17]; - mic_header2[2] = mpdu[18]; - mic_header2[3] = mpdu[19]; - mic_header2[4] = mpdu[20]; - mic_header2[5] = mpdu[21]; - - // In Sequence Control field, mute sequence numer bits (12-bit) - mic_header2[6] = mpdu[22] & 0x0f; /* SC */ - mic_header2[7] = 0x00; /* mpdu[23]; */ - - if ((!qc_exists) & a4_exists) - { - for (i=0;i<6;i++) mic_header2[8+i] = mpdu[24+i]; /* A4 */ - - } - - if (qc_exists && (!a4_exists)) - { - mic_header2[8] = mpdu[24] & 0x0f; /* mute bits 15 - 4 */ - mic_header2[9] = mpdu[25] & 0x00; - } - - if (qc_exists && a4_exists) - { - for (i=0;i<6;i++) mic_header2[8+i] = mpdu[24+i]; /* A4 */ - - mic_header2[14] = mpdu[30] & 0x0f; - mic_header2[15] = mpdu[31] & 0x00; - } -} - - -/************************************************/ -/* construct_mic_iv() */ -/* Builds the MIC IV from header fields and PN */ -/************************************************/ - -void construct_mic_iv( - unsigned char *mic_iv, - int qc_exists, - int a4_exists, - unsigned char *mpdu, - unsigned int payload_length, - unsigned char *pn_vector) -{ - int i; - - mic_iv[0] = 0x59; - if (qc_exists && a4_exists) - mic_iv[1] = mpdu[30] & 0x0f; /* QoS_TC */ - if (qc_exists && !a4_exists) - mic_iv[1] = mpdu[24] & 0x0f; /* mute bits 7-4 */ - if (!qc_exists) - mic_iv[1] = 0x00; - for (i = 2; i < 8; i++) - mic_iv[i] = mpdu[i + 8]; /* mic_iv[2:7] = A2[0:5] = mpdu[10:15] */ -#ifdef CONSISTENT_PN_ORDER - for (i = 8; i < 14; i++) - mic_iv[i] = pn_vector[i - 8]; /* mic_iv[8:13] = PN[0:5] */ -#else - for (i = 8; i < 14; i++) - mic_iv[i] = pn_vector[13 - i]; /* mic_iv[8:13] = PN[5:0] */ -#endif - i = (payload_length / 256); - i = (payload_length % 256); - mic_iv[14] = (unsigned char) (payload_length / 256); - mic_iv[15] = (unsigned char) (payload_length % 256); - -} - - - -/************************************/ -/* bitwise_xor() */ -/* A 128 bit, bitwise exclusive or */ -/************************************/ - -void bitwise_xor(unsigned char *ina, unsigned char *inb, unsigned char *out) -{ - int i; - for (i=0; i<16; i++) - { - out[i] = ina[i] ^ inb[i]; - } -} - - -void aes128k128d(unsigned char *key, unsigned char *data, unsigned char *ciphertext) -{ - int round; - int i; - unsigned char intermediatea[16]; - unsigned char intermediateb[16]; - unsigned char round_key[16]; - - for(i=0; i<16; i++) round_key[i] = key[i]; - - for (round = 0; round < 11; round++) - { - if (round == 0) - { - xor_128(round_key, data, ciphertext); - next_key(round_key, round); - } - else if (round == 10) - { - byte_sub(ciphertext, intermediatea); - shift_row(intermediatea, intermediateb); - xor_128(intermediateb, round_key, ciphertext); - } - else /* 1 - 9 */ - { - byte_sub(ciphertext, intermediatea); - shift_row(intermediatea, intermediateb); - mix_column(&intermediateb[0], &intermediatea[0]); - mix_column(&intermediateb[4], &intermediatea[4]); - mix_column(&intermediateb[8], &intermediatea[8]); - mix_column(&intermediateb[12], &intermediatea[12]); - xor_128(intermediatea, round_key, ciphertext); - next_key(round_key, round); - } - } - -} - -void construct_ctr_preload( - unsigned char *ctr_preload, - int a4_exists, - int qc_exists, - unsigned char *mpdu, - unsigned char *pn_vector, - int c) -{ - - int i = 0; - for (i=0; i<16; i++) ctr_preload[i] = 0x00; - i = 0; - - ctr_preload[0] = 0x01; /* flag */ - if (qc_exists && a4_exists) ctr_preload[1] = mpdu[30] & 0x0f; /* QoC_Control */ - if (qc_exists && !a4_exists) ctr_preload[1] = mpdu[24] & 0x0f; - - for (i = 2; i < 8; i++) - ctr_preload[i] = mpdu[i + 8]; /* ctr_preload[2:7] = A2[0:5] = mpdu[10:15] */ -#ifdef CONSISTENT_PN_ORDER - for (i = 8; i < 14; i++) - ctr_preload[i] = pn_vector[i - 8]; /* ctr_preload[8:13] = PN[0:5] */ -#else - for (i = 8; i < 14; i++) - ctr_preload[i] = pn_vector[13 - i]; /* ctr_preload[8:13] = PN[5:0] */ -#endif - ctr_preload[14] = (unsigned char) (c / 256); // Ctr - ctr_preload[15] = (unsigned char) (c % 256); - -} - - -// -// TRUE: Success! -// FALSE: Decrypt Error! -// -BOOLEAN RTMPSoftDecryptTKIP( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pData, - IN ULONG DataByteCnt, - IN UCHAR UserPriority, - IN PCIPHER_KEY pWpaKey) -{ - UCHAR KeyID; - UINT HeaderLen; - UCHAR fc0; - UCHAR fc1; - USHORT fc; - UINT frame_type; - UINT frame_subtype; - UINT from_ds; - UINT to_ds; - INT a4_exists; - INT qc_exists; - USHORT duration; - USHORT seq_control; - USHORT qos_control; - UCHAR TA[MAC_ADDR_LEN]; - UCHAR DA[MAC_ADDR_LEN]; - UCHAR SA[MAC_ADDR_LEN]; - UCHAR RC4Key[16]; - UINT p1k[5]; //for mix_key; - ULONG pnl;/* Least significant 16 bits of PN */ - ULONG pnh;/* Most significant 32 bits of PN */ - UINT num_blocks; - UINT payload_remainder; - ARCFOURCONTEXT ArcFourContext; - UINT crc32 = 0; - UINT trailfcs = 0; - UCHAR MIC[8]; - UCHAR TrailMIC[8]; - -#ifdef RT_BIG_ENDIAN - RTMPFrameEndianChange(pAd, (PUCHAR)pData, DIR_READ, FALSE); -#endif - - fc0 = *pData; - fc1 = *(pData + 1); - - fc = *((PUSHORT)pData); - - frame_type = ((fc0 >> 2) & 0x03); - frame_subtype = ((fc0 >> 4) & 0x0f); - - from_ds = (fc1 & 0x2) >> 1; - to_ds = (fc1 & 0x1); - - a4_exists = (from_ds & to_ds); - qc_exists = ((frame_subtype == 0x08) || /* Assumed QoS subtypes */ - (frame_subtype == 0x09) || /* Likely to change. */ - (frame_subtype == 0x0a) || - (frame_subtype == 0x0b) - ); - - HeaderLen = 24; - if (a4_exists) - HeaderLen += 6; - - KeyID = *((PUCHAR)(pData+ HeaderLen + 3)); - KeyID = KeyID >> 6; - - if (pWpaKey[KeyID].KeyLen == 0) - { - DBGPRINT(RT_DEBUG_TRACE, ("RTMPSoftDecryptTKIP failed!(KeyID[%d] Length can not be 0)\n", KeyID)); - return FALSE; - } - - duration = *((PUSHORT)(pData+2)); - - seq_control = *((PUSHORT)(pData+22)); - - if (qc_exists) - { - if (a4_exists) - { - qos_control = *((PUSHORT)(pData+30)); - } - else - { - qos_control = *((PUSHORT)(pData+24)); - } - } - - if (to_ds == 0 && from_ds == 1) - { - NdisMoveMemory(DA, pData+4, MAC_ADDR_LEN); - NdisMoveMemory(SA, pData+16, MAC_ADDR_LEN); - NdisMoveMemory(TA, pData+10, MAC_ADDR_LEN); //BSSID - } - else if (to_ds == 0 && from_ds == 0 ) - { - NdisMoveMemory(TA, pData+10, MAC_ADDR_LEN); - NdisMoveMemory(DA, pData+4, MAC_ADDR_LEN); - NdisMoveMemory(SA, pData+10, MAC_ADDR_LEN); - } - else if (to_ds == 1 && from_ds == 0) - { - NdisMoveMemory(SA, pData+10, MAC_ADDR_LEN); - NdisMoveMemory(TA, pData+10, MAC_ADDR_LEN); - NdisMoveMemory(DA, pData+16, MAC_ADDR_LEN); - } - else if (to_ds == 1 && from_ds == 1) - { - NdisMoveMemory(TA, pData+10, MAC_ADDR_LEN); - NdisMoveMemory(DA, pData+16, MAC_ADDR_LEN); - NdisMoveMemory(SA, pData+22, MAC_ADDR_LEN); - } - - num_blocks = (DataByteCnt - 16) / 16; - payload_remainder = (DataByteCnt - 16) % 16; - - pnl = (*(pData + HeaderLen)) * 256 + *(pData + HeaderLen + 2); - pnh = *((PULONG)(pData + HeaderLen + 4)); - pnh = cpu2le32(pnh); - RTMPTkipMixKey(pWpaKey[KeyID].Key, TA, pnl, pnh, RC4Key, p1k); - - ARCFOUR_INIT(&ArcFourContext, RC4Key, 16); - - ARCFOUR_DECRYPT(&ArcFourContext, pData + HeaderLen, pData + HeaderLen + 8, DataByteCnt - HeaderLen - 8); - NdisMoveMemory(&trailfcs, pData + DataByteCnt - 8 - 4, 4); - crc32 = RTMP_CALC_FCS32(PPPINITFCS32, pData + HeaderLen, DataByteCnt - HeaderLen - 8 - 4); //Skip IV+EIV 8 bytes & Skip last 4 bytes(FCS). - crc32 ^= 0xffffffff; /* complement */ - - if(crc32 != cpu2le32(trailfcs)) - { - DBGPRINT(RT_DEBUG_TRACE, ("RTMPSoftDecryptTKIP, WEP Data ICV Error !\n")); //ICV error. - - return (FALSE); - } - - NdisMoveMemory(TrailMIC, pData + DataByteCnt - 8 - 8 - 4, 8); - RTMPInitMICEngine(pAd, pWpaKey[KeyID].Key, DA, SA, UserPriority, pWpaKey[KeyID].RxMic); - RTMPTkipAppend(&pAd->PrivateInfo.Tx, pData + HeaderLen, DataByteCnt - HeaderLen - 8 - 12); - RTMPTkipGetMIC(&pAd->PrivateInfo.Tx); - NdisMoveMemory(MIC, pAd->PrivateInfo.Tx.MIC, 8); - - if (!NdisEqualMemory(MIC, TrailMIC, 8)) - { - DBGPRINT(RT_DEBUG_ERROR, ("RTMPSoftDecryptTKIP, WEP Data MIC Error !\n")); //MIC error. - //RTMPReportMicError(pAd, &pWpaKey[KeyID]); // marked by AlbertY @ 20060630 - return (FALSE); - } - -#ifdef RT_BIG_ENDIAN - RTMPFrameEndianChange(pAd, (PUCHAR)pData, DIR_READ, FALSE); -#endif - //DBGPRINT(RT_DEBUG_TRACE, "RTMPSoftDecryptTKIP Decript done!!\n"); - return TRUE; -} - - - - -BOOLEAN RTMPSoftDecryptAES( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pData, - IN ULONG DataByteCnt, - IN PCIPHER_KEY pWpaKey) -{ - UCHAR KeyID; - UINT HeaderLen; - UCHAR PN[6]; - UINT payload_len; - UINT num_blocks; - UINT payload_remainder; - USHORT fc; - UCHAR fc0; - UCHAR fc1; - UINT frame_type; - UINT frame_subtype; - UINT from_ds; - UINT to_ds; - INT a4_exists; - INT qc_exists; - UCHAR aes_out[16]; - int payload_index; - UINT i; - UCHAR ctr_preload[16]; - UCHAR chain_buffer[16]; - UCHAR padded_buffer[16]; - UCHAR mic_iv[16]; - UCHAR mic_header1[16]; - UCHAR mic_header2[16]; - UCHAR MIC[8]; - UCHAR TrailMIC[8]; - -#ifdef RT_BIG_ENDIAN - RTMPFrameEndianChange(pAd, (PUCHAR)pData, DIR_READ, FALSE); -#endif - - fc0 = *pData; - fc1 = *(pData + 1); - - fc = *((PUSHORT)pData); - - frame_type = ((fc0 >> 2) & 0x03); - frame_subtype = ((fc0 >> 4) & 0x0f); - - from_ds = (fc1 & 0x2) >> 1; - to_ds = (fc1 & 0x1); - - a4_exists = (from_ds & to_ds); - qc_exists = ((frame_subtype == 0x08) || /* Assumed QoS subtypes */ - (frame_subtype == 0x09) || /* Likely to change. */ - (frame_subtype == 0x0a) || - (frame_subtype == 0x0b) - ); - - HeaderLen = 24; - if (a4_exists) - HeaderLen += 6; - - KeyID = *((PUCHAR)(pData+ HeaderLen + 3)); - KeyID = KeyID >> 6; - - if (pWpaKey[KeyID].KeyLen == 0) - { - DBGPRINT(RT_DEBUG_TRACE, ("RTMPSoftDecryptAES failed!(KeyID[%d] Length can not be 0)\n", KeyID)); - return FALSE; - } - - PN[0] = *(pData+ HeaderLen); - PN[1] = *(pData+ HeaderLen + 1); - PN[2] = *(pData+ HeaderLen + 4); - PN[3] = *(pData+ HeaderLen + 5); - PN[4] = *(pData+ HeaderLen + 6); - PN[5] = *(pData+ HeaderLen + 7); - - payload_len = DataByteCnt - HeaderLen - 8 - 8; // 8 bytes for CCMP header , 8 bytes for MIC - payload_remainder = (payload_len) % 16; - num_blocks = (payload_len) / 16; - - - - // Find start of payload - payload_index = HeaderLen + 8; //IV+EIV - - for (i=0; i< num_blocks; i++) - { - construct_ctr_preload(ctr_preload, - a4_exists, - qc_exists, - pData, - PN, - i+1 ); - - aes128k128d(pWpaKey[KeyID].Key, ctr_preload, aes_out); - - bitwise_xor(aes_out, pData + payload_index, chain_buffer); - NdisMoveMemory(pData + payload_index - 8, chain_buffer, 16); - payload_index += 16; - } - - // - // If there is a short final block, then pad it - // encrypt it and copy the unpadded part back - // - if (payload_remainder > 0) - { - construct_ctr_preload(ctr_preload, - a4_exists, - qc_exists, - pData, - PN, - num_blocks + 1); - - NdisZeroMemory(padded_buffer, 16); - NdisMoveMemory(padded_buffer, pData + payload_index, payload_remainder); - - aes128k128d(pWpaKey[KeyID].Key, ctr_preload, aes_out); - - bitwise_xor(aes_out, padded_buffer, chain_buffer); - NdisMoveMemory(pData + payload_index - 8, chain_buffer, payload_remainder); - payload_index += payload_remainder; - } - - // - // Descrypt the MIC - // - construct_ctr_preload(ctr_preload, - a4_exists, - qc_exists, - pData, - PN, - 0); - NdisZeroMemory(padded_buffer, 16); - NdisMoveMemory(padded_buffer, pData + payload_index, 8); - - aes128k128d(pWpaKey[KeyID].Key, ctr_preload, aes_out); - - bitwise_xor(aes_out, padded_buffer, chain_buffer); - - NdisMoveMemory(TrailMIC, chain_buffer, 8); - - // - // Calculate MIC - // - - //Force the protected frame bit on - *(pData + 1) = *(pData + 1) | 0x40; - - // Find start of payload - // Because the CCMP header has been removed - payload_index = HeaderLen; - - construct_mic_iv( - mic_iv, - qc_exists, - a4_exists, - pData, - payload_len, - PN); - - construct_mic_header1( - mic_header1, - HeaderLen, - pData); - - construct_mic_header2( - mic_header2, - pData, - a4_exists, - qc_exists); - - aes128k128d(pWpaKey[KeyID].Key, mic_iv, aes_out); - bitwise_xor(aes_out, mic_header1, chain_buffer); - aes128k128d(pWpaKey[KeyID].Key, chain_buffer, aes_out); - bitwise_xor(aes_out, mic_header2, chain_buffer); - aes128k128d(pWpaKey[KeyID].Key, chain_buffer, aes_out); - - // iterate through each 16 byte payload block - for (i = 0; i < num_blocks; i++) - { - bitwise_xor(aes_out, pData + payload_index, chain_buffer); - payload_index += 16; - aes128k128d(pWpaKey[KeyID].Key, chain_buffer, aes_out); - } - - // Add on the final payload block if it needs padding - if (payload_remainder > 0) - { - NdisZeroMemory(padded_buffer, 16); - NdisMoveMemory(padded_buffer, pData + payload_index, payload_remainder); - - bitwise_xor(aes_out, padded_buffer, chain_buffer); - aes128k128d(pWpaKey[KeyID].Key, chain_buffer, aes_out); - } - - // aes_out contains padded mic, discard most significant - // 8 bytes to generate 64 bit MIC - for (i = 0 ; i < 8; i++) MIC[i] = aes_out[i]; - - if (!NdisEqualMemory(MIC, TrailMIC, 8)) - { - DBGPRINT(RT_DEBUG_ERROR, ("RTMPSoftDecryptAES, MIC Error !\n")); //MIC error. - return FALSE; - } - -#ifdef RT_BIG_ENDIAN - RTMPFrameEndianChange(pAd, (PUCHAR)pData, DIR_READ, FALSE); -#endif - - return TRUE; -} - -/****************************************/ -/* aes128k128d() */ -/* Performs a 128 bit AES encrypt with */ -/* 128 bit data. */ -/****************************************/ -VOID xor_128( - IN PUCHAR a, - IN PUCHAR b, - OUT PUCHAR out) -{ - INT i; - - for (i=0;i<16; i++) - { - out[i] = a[i] ^ b[i]; - } -} - -VOID next_key( - IN PUCHAR key, - IN INT round) -{ - UCHAR rcon; - UCHAR sbox_key[4]; - UCHAR rcon_table[12] = - { - 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, - 0x1b, 0x36, 0x36, 0x36 - }; - - sbox_key[0] = RTMPCkipSbox(key[13]); - sbox_key[1] = RTMPCkipSbox(key[14]); - sbox_key[2] = RTMPCkipSbox(key[15]); - sbox_key[3] = RTMPCkipSbox(key[12]); - - rcon = rcon_table[round]; - - xor_32(&key[0], sbox_key, &key[0]); - key[0] = key[0] ^ rcon; - - xor_32(&key[4], &key[0], &key[4]); - xor_32(&key[8], &key[4], &key[8]); - xor_32(&key[12], &key[8], &key[12]); -} - -VOID xor_32( - IN PUCHAR a, - IN PUCHAR b, - OUT PUCHAR out) -{ - INT i; - - for (i=0;i<4; i++) - { - out[i] = a[i] ^ b[i]; - } -} - -VOID byte_sub( - IN PUCHAR in, - OUT PUCHAR out) -{ - INT i; - - for (i=0; i< 16; i++) - { - out[i] = RTMPCkipSbox(in[i]); - } -} - -UCHAR RTMPCkipSbox( - IN UCHAR a) -{ - return SboxTable[(int)a]; -} - -VOID shift_row( - IN PUCHAR in, - OUT PUCHAR out) -{ - out[0] = in[0]; - out[1] = in[5]; - out[2] = in[10]; - out[3] = in[15]; - out[4] = in[4]; - out[5] = in[9]; - out[6] = in[14]; - out[7] = in[3]; - out[8] = in[8]; - out[9] = in[13]; - out[10] = in[2]; - out[11] = in[7]; - out[12] = in[12]; - out[13] = in[1]; - out[14] = in[6]; - out[15] = in[11]; -} - -VOID mix_column( - IN PUCHAR in, - OUT PUCHAR out) -{ - INT i; - UCHAR add1b[4]; - UCHAR add1bf7[4]; - UCHAR rotl[4]; - UCHAR swap_halfs[4]; - UCHAR andf7[4]; - UCHAR rotr[4]; - UCHAR temp[4]; - UCHAR tempb[4]; - - for (i=0 ; i<4; i++) - { - if ((in[i] & 0x80)== 0x80) - add1b[i] = 0x1b; - else - add1b[i] = 0x00; - } - - swap_halfs[0] = in[2]; /* Swap halfs */ - swap_halfs[1] = in[3]; - swap_halfs[2] = in[0]; - swap_halfs[3] = in[1]; - - rotl[0] = in[3]; /* Rotate left 8 bits */ - rotl[1] = in[0]; - rotl[2] = in[1]; - rotl[3] = in[2]; - - andf7[0] = in[0] & 0x7f; - andf7[1] = in[1] & 0x7f; - andf7[2] = in[2] & 0x7f; - andf7[3] = in[3] & 0x7f; - - for (i = 3; i>0; i--) /* logical shift left 1 bit */ - { - andf7[i] = andf7[i] << 1; - if ((andf7[i-1] & 0x80) == 0x80) - { - andf7[i] = (andf7[i] | 0x01); - } - } - andf7[0] = andf7[0] << 1; - andf7[0] = andf7[0] & 0xfe; - - xor_32(add1b, andf7, add1bf7); - - xor_32(in, add1bf7, rotr); - - temp[0] = rotr[0]; /* Rotate right 8 bits */ - rotr[0] = rotr[1]; - rotr[1] = rotr[2]; - rotr[2] = rotr[3]; - rotr[3] = temp[0]; - - xor_32(add1bf7, rotr, temp); - xor_32(swap_halfs, rotl,tempb); - xor_32(temp, tempb, out); -} - +#include "../../rt2870/common/rtmp_tkip.c" diff --git a/drivers/staging/rt3070/common/rtmp_wep.c b/drivers/staging/rt3070/common/rtmp_wep.c index f5f0a3bb17eb..71979856e11a 100644 --- a/drivers/staging/rt3070/common/rtmp_wep.c +++ b/drivers/staging/rt3070/common/rtmp_wep.c @@ -1,508 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - rtmp_wep.c - - Abstract: - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Paul Wu 10-28-02 Initial -*/ - -#include "../rt_config.h" - -UINT FCSTAB_32[256] = -{ - 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, - 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, - 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, - 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, - 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, - 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, - 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, - 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, - 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, - 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, - 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, - 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, - 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, - 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, - 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, - 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, - 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, - 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, - 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, - 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, - 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, - 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, - 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, - 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, - 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, - 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, - 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, - 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, - 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, - 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, - 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, - 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, - 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, - 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, - 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, - 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, - 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, - 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, - 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, - 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, - 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, - 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, - 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, - 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, - 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, - 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, - 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, - 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, - 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, - 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, - 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, - 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, - 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, - 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, - 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, - 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, - 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, - 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, - 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, - 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, - 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, - 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, - 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, - 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d -}; - -/* -UCHAR WEPKEY[] = { - //IV - 0x00, 0x11, 0x22, - //WEP KEY - 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC - }; - */ - -/* - ======================================================================== - - Routine Description: - Init WEP function. - - Arguments: - pAd Pointer to our adapter - pKey Pointer to the WEP KEY - KeyId WEP Key ID - KeyLen the length of WEP KEY - pDest Pointer to the destination which Encryption data will store in. - - Return Value: - None - - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -VOID RTMPInitWepEngine( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pKey, - IN UCHAR KeyId, - IN UCHAR KeyLen, - IN OUT PUCHAR pDest) -{ - UINT i; - UCHAR WEPKEY[] = { - //IV - 0x00, 0x11, 0x22, - //WEP KEY - 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC - }; - - pAd->PrivateInfo.FCSCRC32 = PPPINITFCS32; //Init crc32. - -#ifdef CONFIG_STA_SUPPORT - if (pAd->StaCfg.bCkipOn && (pAd->StaCfg.CkipFlag & 0x10) && (pAd->OpMode == OPMODE_STA)) - { - ARCFOUR_INIT(&pAd->PrivateInfo.WEPCONTEXT, pKey, KeyLen); //INIT SBOX, KEYLEN+3(IV) - NdisMoveMemory(pDest, pKey, 3); //Append Init Vector - } - else -#endif // CONFIG_STA_SUPPORT // - { - NdisMoveMemory(WEPKEY + 3, pKey, KeyLen); - - for(i = 0; i < 3; i++) - WEPKEY[i] = RandomByte(pAd); //Call mlme RandomByte() function. - ARCFOUR_INIT(&pAd->PrivateInfo.WEPCONTEXT, WEPKEY, KeyLen + 3); //INIT SBOX, KEYLEN+3(IV) - - NdisMoveMemory(pDest, WEPKEY, 3); //Append Init Vector - } - *(pDest+3) = (KeyId << 6); //Append KEYID - -} - -/* - ======================================================================== - - Routine Description: - Encrypt transimitted data - - Arguments: - pAd Pointer to our adapter - pSrc Pointer to the transimitted source data that will be encrypt - pDest Pointer to the destination where entryption data will be store in. - Len Indicate the length of the source data - - Return Value: - None - - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -VOID RTMPEncryptData( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pSrc, - IN PUCHAR pDest, - IN UINT Len) -{ - pAd->PrivateInfo.FCSCRC32 = RTMP_CALC_FCS32(pAd->PrivateInfo.FCSCRC32, pSrc, Len); - ARCFOUR_ENCRYPT(&pAd->PrivateInfo.WEPCONTEXT, pDest, pSrc, Len); -} - - -/* - ======================================================================== - - Routine Description: - Decrypt received WEP data - - Arguments: - pAdapter Pointer to our adapter - pSrc Pointer to the received data - Len the length of the received data - - Return Value: - TRUE Decrypt WEP data success - FALSE Decrypt WEP data failed - - Note: - - ======================================================================== -*/ -BOOLEAN RTMPSoftDecryptWEP( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pData, - IN ULONG DataByteCnt, - IN PCIPHER_KEY pGroupKey) -{ - UINT trailfcs; - UINT crc32; - UCHAR KeyIdx; - UCHAR WEPKEY[] = { - //IV - 0x00, 0x11, 0x22, - //WEP KEY - 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC - }; - UCHAR *pPayload = (UCHAR *)pData + LENGTH_802_11; - ULONG payload_len = DataByteCnt - LENGTH_802_11; - - NdisMoveMemory(WEPKEY, pPayload, 3); //Get WEP IV - - KeyIdx = (*(pPayload + 3) & 0xc0) >> 6; - if (pGroupKey[KeyIdx].KeyLen == 0) - return (FALSE); - - NdisMoveMemory(WEPKEY + 3, pGroupKey[KeyIdx].Key, pGroupKey[KeyIdx].KeyLen); - ARCFOUR_INIT(&pAd->PrivateInfo.WEPCONTEXT, WEPKEY, pGroupKey[KeyIdx].KeyLen + 3); - ARCFOUR_DECRYPT(&pAd->PrivateInfo.WEPCONTEXT, pPayload, pPayload + 4, payload_len - 4); - NdisMoveMemory(&trailfcs, pPayload + payload_len - 8, 4); - crc32 = RTMP_CALC_FCS32(PPPINITFCS32, pPayload, payload_len - 8); //Skip last 4 bytes(FCS). - crc32 ^= 0xffffffff; /* complement */ - - if(crc32 != cpu2le32(trailfcs)) - { - DBGPRINT(RT_DEBUG_TRACE, ("! WEP Data CRC Error !\n")); //CRC error. - return (FALSE); - } - return (TRUE); -} - -/* - ======================================================================== - - Routine Description: - The Stream Cipher Encryption Algorithm "ARCFOUR" initialize - - Arguments: - Ctx Pointer to ARCFOUR CONTEXT (SBOX) - pKey Pointer to the WEP KEY - KeyLen Indicate the length fo the WEP KEY - - Return Value: - None - - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -VOID ARCFOUR_INIT( - IN PARCFOURCONTEXT Ctx, - IN PUCHAR pKey, - IN UINT KeyLen) -{ - UCHAR t, u; - UINT keyindex; - UINT stateindex; - PUCHAR state; - UINT counter; - - state = Ctx->STATE; - Ctx->X = 0; - Ctx->Y = 0; - for (counter = 0; counter < 256; counter++) - state[counter] = (UCHAR)counter; - keyindex = 0; - stateindex = 0; - for (counter = 0; counter < 256; counter++) - { - t = state[counter]; - stateindex = (stateindex + pKey[keyindex] + t) & 0xff; - u = state[stateindex]; - state[stateindex] = t; - state[counter] = u; - if (++keyindex >= KeyLen) - keyindex = 0; - } -} - -/* - ======================================================================== - - Routine Description: - Get bytes from ARCFOUR CONTEXT (S-BOX) - - Arguments: - Ctx Pointer to ARCFOUR CONTEXT (SBOX) - - Return Value: - UCHAR - the value of the ARCFOUR CONTEXT (S-BOX) - - Note: - - ======================================================================== -*/ -UCHAR ARCFOUR_BYTE( - IN PARCFOURCONTEXT Ctx) -{ - UINT x; - UINT y; - UCHAR sx, sy; - PUCHAR state; - - state = Ctx->STATE; - x = (Ctx->X + 1) & 0xff; - sx = state[x]; - y = (sx + Ctx->Y) & 0xff; - sy = state[y]; - Ctx->X = x; - Ctx->Y = y; - state[y] = sx; - state[x] = sy; - - return(state[(sx + sy) & 0xff]); - -} - -/* - ======================================================================== - - Routine Description: - The Stream Cipher Decryption Algorithm - - Arguments: - Ctx Pointer to ARCFOUR CONTEXT (SBOX) - pDest Pointer to the Destination - pSrc Pointer to the Source data - Len Indicate the length of the Source data - - Return Value: - None - - Note: - - ======================================================================== -*/ -VOID ARCFOUR_DECRYPT( - IN PARCFOURCONTEXT Ctx, - IN PUCHAR pDest, - IN PUCHAR pSrc, - IN UINT Len) -{ - UINT i; - - for (i = 0; i < Len; i++) - pDest[i] = pSrc[i] ^ ARCFOUR_BYTE(Ctx); -} - -/* - ======================================================================== - - Routine Description: - The Stream Cipher Encryption Algorithm - - Arguments: - Ctx Pointer to ARCFOUR CONTEXT (SBOX) - pDest Pointer to the Destination - pSrc Pointer to the Source data - Len Indicate the length of the Source dta - - Return Value: - None - - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -VOID ARCFOUR_ENCRYPT( - IN PARCFOURCONTEXT Ctx, - IN PUCHAR pDest, - IN PUCHAR pSrc, - IN UINT Len) -{ - UINT i; - - for (i = 0; i < Len; i++) - pDest[i] = pSrc[i] ^ ARCFOUR_BYTE(Ctx); -} - -/* - ======================================================================== - - Routine Description: - The Stream Cipher Encryption Algorithm which conform to the special requirement to encrypt GTK. - - Arguments: - Ctx Pointer to ARCFOUR CONTEXT (SBOX) - pDest Pointer to the Destination - pSrc Pointer to the Source data - Len Indicate the length of the Source dta - - - ======================================================================== -*/ - -VOID WPAARCFOUR_ENCRYPT( - IN PARCFOURCONTEXT Ctx, - IN PUCHAR pDest, - IN PUCHAR pSrc, - IN UINT Len) -{ - UINT i; - //discard first 256 bytes - for (i = 0; i < 256; i++) - ARCFOUR_BYTE(Ctx); - - for (i = 0; i < Len; i++) - pDest[i] = pSrc[i] ^ ARCFOUR_BYTE(Ctx); -} - - -/* - ======================================================================== - - Routine Description: - Calculate a new FCS given the current FCS and the new data. - - Arguments: - Fcs the original FCS value - Cp pointer to the data which will be calculate the FCS - Len the length of the data - - Return Value: - UINT - FCS 32 bits - - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -UINT RTMP_CALC_FCS32( - IN UINT Fcs, - IN PUCHAR Cp, - IN INT Len) -{ - while (Len--) - Fcs = (((Fcs) >> 8) ^ FCSTAB_32[((Fcs) ^ (*Cp++)) & 0xff]); - - return (Fcs); -} - - -/* - ======================================================================== - - Routine Description: - Get last FCS and encrypt it to the destination - - Arguments: - pDest Pointer to the Destination - - Return Value: - None - - Note: - - ======================================================================== -*/ -VOID RTMPSetICV( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDest) -{ - pAd->PrivateInfo.FCSCRC32 ^= 0xffffffff; /* complement */ - pAd->PrivateInfo.FCSCRC32 = cpu2le32(pAd->PrivateInfo.FCSCRC32); - - ARCFOUR_ENCRYPT(&pAd->PrivateInfo.WEPCONTEXT, pDest, (PUCHAR) &pAd->PrivateInfo.FCSCRC32, 4); -} - +#include "../../rt2870/common/rtmp_wep.c" diff --git a/drivers/staging/rt3070/common/rtusb_bulk.c b/drivers/staging/rt3070/common/rtusb_bulk.c index 1a05703520fc..762ecfe6044f 100644 --- a/drivers/staging/rt3070/common/rtusb_bulk.c +++ b/drivers/staging/rt3070/common/rtusb_bulk.c @@ -1,1382 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - rtusb_bulk.c - - Abstract: - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Name Date Modification logs - Paul Lin 06-25-2004 created - -*/ - -#include "../rt_config.h" -// Match total 6 bulkout endpoint to corresponding queue. -UCHAR EpToQueue[6]={FIFO_EDCA, FIFO_EDCA, FIFO_EDCA, FIFO_EDCA, FIFO_EDCA, FIFO_MGMT}; - -//static BOOLEAN SingleBulkOut = FALSE; - -void RTUSB_FILL_BULK_URB (struct urb *pUrb, - struct usb_device *pUsb_Dev, - unsigned int bulkpipe, - void *pTransferBuf, - int BufSize, - usb_complete_t Complete, - void *pContext) -{ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) - usb_fill_bulk_urb(pUrb, pUsb_Dev, bulkpipe, pTransferBuf, BufSize, (usb_complete_t)Complete, pContext); -#else - FILL_BULK_URB(pUrb, pUsb_Dev, bulkpipe, pTransferBuf, BufSize, Complete, pContext); -#endif - -} - -VOID RTUSBInitTxDesc( - IN PRTMP_ADAPTER pAd, - IN PTX_CONTEXT pTxContext, - IN UCHAR BulkOutPipeId, - IN usb_complete_t Func) -{ - PURB pUrb; - PUCHAR pSrc = NULL; - POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie; - - pUrb = pTxContext->pUrb; - ASSERT(pUrb); - - // Store BulkOut PipeId - pTxContext->BulkOutPipeId = BulkOutPipeId; - - if (pTxContext->bAggregatible) - { - pSrc = &pTxContext->TransferBuffer->Aggregation[2]; - } - else - { - pSrc = (PUCHAR) pTxContext->TransferBuffer->field.WirelessPacket; - } - - - //Initialize a tx bulk urb - RTUSB_FILL_BULK_URB(pUrb, - pObj->pUsb_Dev, - usb_sndbulkpipe(pObj->pUsb_Dev, pAd->BulkOutEpAddr[BulkOutPipeId]), - pSrc, - pTxContext->BulkOutSize, - Func, - pTxContext); - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) - if (pTxContext->bAggregatible) - pUrb->transfer_dma = (pTxContext->data_dma + TX_BUFFER_NORMSIZE + 2); - else - pUrb->transfer_dma = pTxContext->data_dma; - - pUrb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; -#endif - -} - -VOID RTUSBInitHTTxDesc( - IN PRTMP_ADAPTER pAd, - IN PHT_TX_CONTEXT pTxContext, - IN UCHAR BulkOutPipeId, - IN ULONG BulkOutSize, - IN usb_complete_t Func) -{ - PURB pUrb; - PUCHAR pSrc = NULL; - POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie; - - pUrb = pTxContext->pUrb; - ASSERT(pUrb); - - // Store BulkOut PipeId - pTxContext->BulkOutPipeId = BulkOutPipeId; - - pSrc = &pTxContext->TransferBuffer->field.WirelessPacket[pTxContext->NextBulkOutPosition]; - - - //Initialize a tx bulk urb - RTUSB_FILL_BULK_URB(pUrb, - pObj->pUsb_Dev, - usb_sndbulkpipe(pObj->pUsb_Dev, pAd->BulkOutEpAddr[BulkOutPipeId]), - pSrc, - BulkOutSize, - Func, - pTxContext); - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) - pUrb->transfer_dma = (pTxContext->data_dma + pTxContext->NextBulkOutPosition); - pUrb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; -#endif - -} - -VOID RTUSBInitRxDesc( - IN PRTMP_ADAPTER pAd, - IN PRX_CONTEXT pRxContext) -{ - PURB pUrb; - POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie; - ULONG RX_bulk_size; - - - pUrb = pRxContext->pUrb; - ASSERT(pUrb); - - if ( pAd->BulkInMaxPacketSize == 64) - RX_bulk_size = 4096; - else - RX_bulk_size = MAX_RXBULK_SIZE; - - //Initialize a rx bulk urb - RTUSB_FILL_BULK_URB(pUrb, - pObj->pUsb_Dev, - usb_rcvbulkpipe(pObj->pUsb_Dev, pAd->BulkInEpAddr), - &(pRxContext->TransferBuffer[pAd->NextRxBulkInPosition]), - RX_bulk_size - (pAd->NextRxBulkInPosition), - (usb_complete_t)RTUSBBulkRxComplete, - (void *)pRxContext); - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) - pUrb->transfer_dma = pRxContext->data_dma + pAd->NextRxBulkInPosition; - pUrb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; -#endif - - -} - -/* - ======================================================================== - - Routine Description: - - Arguments: - - Return Value: - - Note: - - ======================================================================== -*/ - -#define BULK_OUT_LOCK(pLock, IrqFlags) \ - if(1 /*!(in_interrupt() & 0xffff0000)*/) \ - RTMP_IRQ_LOCK((pLock), IrqFlags); - -#define BULK_OUT_UNLOCK(pLock, IrqFlags) \ - if(1 /*!(in_interrupt() & 0xffff0000)*/) \ - RTMP_IRQ_UNLOCK((pLock), IrqFlags); - - -VOID RTUSBBulkOutDataPacket( - IN PRTMP_ADAPTER pAd, - IN UCHAR BulkOutPipeId, - IN UCHAR Index) -{ - - PHT_TX_CONTEXT pHTTXContext; - PURB pUrb; - int ret = 0; - PTXINFO_STRUC pTxInfo, pLastTxInfo = NULL; - PTXWI_STRUC pTxWI; - ULONG TmpBulkEndPos, ThisBulkSize; - unsigned long IrqFlags = 0, IrqFlags2 = 0; - PUCHAR pWirelessPkt, pAppendant; - BOOLEAN bTxQLastRound = FALSE; - UCHAR allzero[4]= {0x0,0x0,0x0,0x0}; - - BULK_OUT_LOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); - if ((pAd->BulkOutPending[BulkOutPipeId] == TRUE) || RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NEED_STOP_TX)) - { - BULK_OUT_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); - return; - } - pAd->BulkOutPending[BulkOutPipeId] = TRUE; - - if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) - ) - { - pAd->BulkOutPending[BulkOutPipeId] = FALSE; - BULK_OUT_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); - return; - } - BULK_OUT_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); - - - pHTTXContext = &(pAd->TxContext[BulkOutPipeId]); - - BULK_OUT_LOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags2); - if ((pHTTXContext->ENextBulkOutPosition == pHTTXContext->CurWritePosition) - || ((pHTTXContext->ENextBulkOutPosition-8) == pHTTXContext->CurWritePosition)) - { - BULK_OUT_UNLOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags2); - - BULK_OUT_LOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); - pAd->BulkOutPending[BulkOutPipeId] = FALSE; - - // Clear Data flag - RTUSB_CLEAR_BULK_FLAG(pAd, (fRTUSB_BULK_OUT_DATA_FRAG << BulkOutPipeId)); - RTUSB_CLEAR_BULK_FLAG(pAd, (fRTUSB_BULK_OUT_DATA_NORMAL << BulkOutPipeId)); - - BULK_OUT_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); - return; - } - - // Clear Data flag - RTUSB_CLEAR_BULK_FLAG(pAd, (fRTUSB_BULK_OUT_DATA_FRAG << BulkOutPipeId)); - RTUSB_CLEAR_BULK_FLAG(pAd, (fRTUSB_BULK_OUT_DATA_NORMAL << BulkOutPipeId)); - - //DBGPRINT(RT_DEBUG_TRACE,("BulkOut-B:I=0x%lx, CWPos=%ld, CWRPos=%ld, NBPos=%ld, ENBPos=%ld, bCopy=%d!\n", in_interrupt(), - // pHTTXContext->CurWritePosition, pHTTXContext->CurWriteRealPos, pHTTXContext->NextBulkOutPosition, - // pHTTXContext->ENextBulkOutPosition, pHTTXContext->bCopySavePad)); - pHTTXContext->NextBulkOutPosition = pHTTXContext->ENextBulkOutPosition; - ThisBulkSize = 0; - TmpBulkEndPos = pHTTXContext->NextBulkOutPosition; - pWirelessPkt = &pHTTXContext->TransferBuffer->field.WirelessPacket[0]; - - if ((pHTTXContext->bCopySavePad == TRUE)) - { - if (RTMPEqualMemory(pHTTXContext->SavedPad, allzero,4)) - { - DBGPRINT_RAW(RT_DEBUG_ERROR,("e1, allzero : %x %x %x %x %x %x %x %x \n", - pHTTXContext->SavedPad[0], pHTTXContext->SavedPad[1], pHTTXContext->SavedPad[2],pHTTXContext->SavedPad[3] - ,pHTTXContext->SavedPad[4], pHTTXContext->SavedPad[5], pHTTXContext->SavedPad[6],pHTTXContext->SavedPad[7])); - } - NdisMoveMemory(&pWirelessPkt[TmpBulkEndPos], pHTTXContext->SavedPad, 8); - pHTTXContext->bCopySavePad = FALSE; - if (pAd->bForcePrintTX == TRUE) - DBGPRINT(RT_DEBUG_TRACE,("RTUSBBulkOutDataPacket --> COPY PAD. CurWrite = %ld, NextBulk = %ld. ENextBulk = %ld.\n", pHTTXContext->CurWritePosition, pHTTXContext->NextBulkOutPosition, pHTTXContext->ENextBulkOutPosition)); - } - - do - { - pTxInfo = (PTXINFO_STRUC)&pWirelessPkt[TmpBulkEndPos]; - pTxWI = (PTXWI_STRUC)&pWirelessPkt[TmpBulkEndPos + TXINFO_SIZE]; - - if (pAd->bForcePrintTX == TRUE) - DBGPRINT(RT_DEBUG_TRACE, ("RTUSBBulkOutDataPacket AMPDU = %d.\n", pTxWI->AMPDU)); - - // add by Iverson, limit BulkOut size to 4k to pass WMM b mode 2T1R test items - //if ((ThisBulkSize != 0) && (pTxWI->AMPDU == 0)) - if ((ThisBulkSize != 0) && (pTxWI->PHYMODE == MODE_CCK)) - { -#ifdef INF_AMAZON_SE - /*Iverson Add for AMAZON USB (RT2070 && RT3070) to pass WMM A2-T4 ~ A2-T10*/ - if(OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED)) - { - /*Iverson patch for WMM A5-T07 ,WirelessStaToWirelessSta do not bulk out aggregate*/ - if(pTxWI->PacketId == 6) - { - pHTTXContext->ENextBulkOutPosition = TmpBulkEndPos; - break; - } - else if (BulkOutPipeId == 1) - { - /*BK No Limit BulkOut size .*/ - pHTTXContext->ENextBulkOutPosition = TmpBulkEndPos; - break; - } - else if (((ThisBulkSize&0xffff8000) != 0) || (((ThisBulkSize&0x1000) == 0x1000) && (BulkOutPipeId == 0) )) - { - /*BE Limit BulkOut size to about 4k bytes.*/ - pHTTXContext->ENextBulkOutPosition = TmpBulkEndPos; - break; - } - else if (((ThisBulkSize&0xffff8000) != 0) || (((ThisBulkSize&0x1c00) == 0x1c00) && (BulkOutPipeId == 2) )) - { - /*VI Limit BulkOut size to about 7k bytes.*/ - pHTTXContext->ENextBulkOutPosition = TmpBulkEndPos; - break; - } - else if (((ThisBulkSize&0xffff8000) != 0) || (((ThisBulkSize&0x2500) == 0x2500) && (BulkOutPipeId == 3) )) - { - /*VO Limit BulkOut size to about 9k bytes.*/ - pHTTXContext->ENextBulkOutPosition = TmpBulkEndPos; - break; - } - } - else if (((ThisBulkSize&0xffff8000) != 0) || ((ThisBulkSize&0x1000) == 0x1000)) - { - /* Limit BulkOut size to about 4k bytes.*/ - pHTTXContext->ENextBulkOutPosition = TmpBulkEndPos; - break; - } -#else - if (((ThisBulkSize&0xffff8000) != 0) || ((ThisBulkSize&0x1000) == 0x1000)) - { - // Limit BulkOut size to about 4k bytes. - pHTTXContext->ENextBulkOutPosition = TmpBulkEndPos; - break; - } -#endif // INF_AMAZON_SE // - - else if (((pAd->BulkOutMaxPacketSize < 512) && ((ThisBulkSize&0xfffff800) != 0) ) /*|| ( (ThisBulkSize != 0) && (pTxWI->AMPDU == 0))*/) - { - // For USB 1.1 or peer which didn't support AMPDU, limit the BulkOut size. - // For performence in b/g mode, now just check for USB 1.1 and didn't care about the APMDU or not! 2008/06/04. - pHTTXContext->ENextBulkOutPosition = TmpBulkEndPos; - break; - } - } - // end Iverson - else - { -#ifdef INF_AMAZON_SE -//#ifdef DOT11_N_SUPPORT -// if(((ThisBulkSize&0xffff8000) != 0) || ((ThisBulkSize&0x6000) == 0x6000) || ( (ThisBulkSize != 0) && (pTxWI->AMPDU == 0))) -// { -// /* AMAZON_SE: BG mode Disable BulkOut Aggregate, N mode BulkOut Aggregaet size 24K */ -// pHTTXContext->ENextBulkOutPosition = TmpBulkEndPos; -// break; -// } -// else -//#endif // DOT11_N_SUPPORT // -// { - if(OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED) && (pTxWI->AMPDU == 0)) - { - if (((pAd->BulkOutMaxPacketSize < 512) && ((ThisBulkSize&0xfffff800) != 0)) || - (ThisBulkSize != 0)) - { - /* AMAZON_SE: RT2070 Disable BulkOut Aggregate when WMM for USB issue */ - pHTTXContext->ENextBulkOutPosition = TmpBulkEndPos; - break; - } - } -/* - else if (((ThisBulkSize&0xffff8000) != 0) || ((ThisBulkSize&0x6000) == 0x6000)) - { - // Limit BulkOut size to about 24k bytes. - pHTTXContext->ENextBulkOutPosition = TmpBulkEndPos; - break; - } - } -*/ -#endif // INF_AMAZON_SE // - - if (((ThisBulkSize&0xffff8000) != 0) || ((ThisBulkSize&0x6000) == 0x6000)) - { // Limit BulkOut size to about 24k bytes. - pHTTXContext->ENextBulkOutPosition = TmpBulkEndPos; - break; - } - - else if (((pAd->BulkOutMaxPacketSize < 512) && ((ThisBulkSize&0xfffff800) != 0) ) /*|| ( (ThisBulkSize != 0) && (pTxWI->AMPDU == 0))*/) - { // For USB 1.1 or peer which didn't support AMPDU, limit the BulkOut size. - // For performence in b/g mode, now just check for USB 1.1 and didn't care about the APMDU or not! 2008/06/04. - pHTTXContext->ENextBulkOutPosition = TmpBulkEndPos; - break; - } - } - - if (TmpBulkEndPos == pHTTXContext->CurWritePosition) - { - pHTTXContext->ENextBulkOutPosition = TmpBulkEndPos; - break; - } - //PS packets use HCCA queue when dequeue from PS unicast queue (WiFi WPA2 MA9_DT1 for Marvell B STA) -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - if (pTxInfo->QSEL != FIFO_EDCA) - { - printk("%s(): ====> pTxInfo->QueueSel(%d)!= FIFO_EDCA!!!!\n", __FUNCTION__, pTxInfo->QSEL); - printk("\tCWPos=%ld, NBPos=%ld, ENBPos=%ld, bCopy=%d!\n", pHTTXContext->CurWritePosition, pHTTXContext->NextBulkOutPosition, pHTTXContext->ENextBulkOutPosition, pHTTXContext->bCopySavePad); - hex_dump("Wrong QSel Pkt:", (PUCHAR)&pWirelessPkt[TmpBulkEndPos], (pHTTXContext->CurWritePosition - pHTTXContext->NextBulkOutPosition)); - } - } -#endif // CONFIG_STA_SUPPORT // - - if (pTxInfo->USBDMATxPktLen <= 8) - { - BULK_OUT_UNLOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags2); - DBGPRINT(RT_DEBUG_ERROR /*RT_DEBUG_TRACE*/,("e2, USBDMATxPktLen==0, Size=%ld, bCSPad=%d, CWPos=%ld, NBPos=%ld, CWRPos=%ld!\n", - pHTTXContext->BulkOutSize, pHTTXContext->bCopySavePad, pHTTXContext->CurWritePosition, pHTTXContext->NextBulkOutPosition, pHTTXContext->CurWriteRealPos)); - { - DBGPRINT_RAW(RT_DEBUG_ERROR /*RT_DEBUG_TRACE*/,("%x %x %x %x %x %x %x %x \n", - pHTTXContext->SavedPad[0], pHTTXContext->SavedPad[1], pHTTXContext->SavedPad[2],pHTTXContext->SavedPad[3] - ,pHTTXContext->SavedPad[4], pHTTXContext->SavedPad[5], pHTTXContext->SavedPad[6],pHTTXContext->SavedPad[7])); - } - pAd->bForcePrintTX = TRUE; - BULK_OUT_LOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); - pAd->BulkOutPending[BulkOutPipeId] = FALSE; - BULK_OUT_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); - //DBGPRINT(RT_DEBUG_LOUD,("Out:pTxInfo->USBDMATxPktLen=%d!\n", pTxInfo->USBDMATxPktLen)); - return; - } - - // Increase Total transmit byte counter - pAd->RalinkCounters.OneSecTransmittedByteCount += pTxWI->MPDUtotalByteCount; - pAd->RalinkCounters.TransmittedByteCount += pTxWI->MPDUtotalByteCount; - - pLastTxInfo = pTxInfo; - - // Make sure we use EDCA QUEUE. -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - pTxInfo->QSEL = FIFO_EDCA; //PS packets use HCCA queue when dequeue from PS unicast queue (WiFi WPA2 MA9_DT1 for Marvell B STA) -#endif // CONFIG_STA_SUPPORT // - ThisBulkSize += (pTxInfo->USBDMATxPktLen+4); - TmpBulkEndPos += (pTxInfo->USBDMATxPktLen+4); - - if (TmpBulkEndPos != pHTTXContext->CurWritePosition) - pTxInfo->USBDMANextVLD = 1; - - if (pTxInfo->SwUseLastRound == 1) - { - if (pHTTXContext->CurWritePosition == 8) - pTxInfo->USBDMANextVLD = 0; - pTxInfo->SwUseLastRound = 0; - - bTxQLastRound = TRUE; - pHTTXContext->ENextBulkOutPosition = 8; - - #ifdef RT_BIG_ENDIAN - RTMPDescriptorEndianChange((PUCHAR)pTxInfo, TYPE_TXINFO); - RTMPWIEndianChange((PUCHAR)pTxWI, TYPE_TXWI); - #endif // RT_BIG_ENDIAN // - - break; - } - -#ifdef RT_BIG_ENDIAN - RTMPDescriptorEndianChange((PUCHAR)pTxInfo, TYPE_TXINFO); - RTMPWIEndianChange((PUCHAR)pTxWI, TYPE_TXWI); -#endif // RT_BIG_ENDIAN // - - }while (TRUE); - - // adjust the pTxInfo->USBDMANextVLD value of last pTxInfo. - if (pLastTxInfo) - { -#ifdef RT_BIG_ENDIAN - RTMPDescriptorEndianChange((PUCHAR)pLastTxInfo, TYPE_TXINFO); -#endif // RT_BIG_ENDIAN // - pLastTxInfo->USBDMANextVLD = 0; -#ifdef RT_BIG_ENDIAN - RTMPDescriptorEndianChange((PUCHAR)pLastTxInfo, TYPE_TXINFO); -#endif // RT_BIG_ENDIAN // - } - - /* - We need to copy SavedPad when following condition matched! - 1. Not the last round of the TxQueue and - 2. any match of following cases: - (1). The End Position of this bulk out is reach to the Currenct Write position and - the TxInfo and related header already write to the CurWritePosition. - =>(ENextBulkOutPosition == CurWritePosition) && (CurWriteRealPos > CurWritePosition) - - (2). The EndPosition of the bulk out is not reach to the Current Write Position. - =>(ENextBulkOutPosition != CurWritePosition) - */ - if ((bTxQLastRound == FALSE) && - (((pHTTXContext->ENextBulkOutPosition == pHTTXContext->CurWritePosition) && (pHTTXContext->CurWriteRealPos > pHTTXContext->CurWritePosition)) || - (pHTTXContext->ENextBulkOutPosition != pHTTXContext->CurWritePosition)) - ) - { - NdisMoveMemory(pHTTXContext->SavedPad, &pWirelessPkt[pHTTXContext->ENextBulkOutPosition], 8); - pHTTXContext->bCopySavePad = TRUE; - if (RTMPEqualMemory(pHTTXContext->SavedPad, allzero,4)) - { - PUCHAR pBuf = &pHTTXContext->SavedPad[0]; - DBGPRINT_RAW(RT_DEBUG_ERROR,("WARNING-Zero-3:%02x%02x%02x%02x%02x%02x%02x%02x,CWPos=%ld, CWRPos=%ld, bCW=%d, NBPos=%ld, TBPos=%ld, TBSize=%ld\n", - pBuf[0], pBuf[1], pBuf[2],pBuf[3],pBuf[4], pBuf[5], pBuf[6],pBuf[7], pHTTXContext->CurWritePosition, pHTTXContext->CurWriteRealPos, - pHTTXContext->bCurWriting, pHTTXContext->NextBulkOutPosition, TmpBulkEndPos, ThisBulkSize)); - - pBuf = &pWirelessPkt[pHTTXContext->CurWritePosition]; - DBGPRINT_RAW(RT_DEBUG_ERROR,("\tCWPos=%02x%02x%02x%02x%02x%02x%02x%02x\n", pBuf[0], pBuf[1], pBuf[2],pBuf[3],pBuf[4], pBuf[5], pBuf[6],pBuf[7])); - } - //DBGPRINT(RT_DEBUG_LOUD,("ENPos==CWPos=%ld, CWRPos=%ld, bCSPad=%d!\n", pHTTXContext->CurWritePosition, pHTTXContext->CurWriteRealPos, pHTTXContext->bCopySavePad)); - } - - if (pAd->bForcePrintTX == TRUE) - DBGPRINT(RT_DEBUG_TRACE,("BulkOut-A:Size=%ld, CWPos=%ld, NBPos=%ld, ENBPos=%ld, bCopy=%d!\n", ThisBulkSize, pHTTXContext->CurWritePosition, pHTTXContext->NextBulkOutPosition, pHTTXContext->ENextBulkOutPosition, pHTTXContext->bCopySavePad)); - //DBGPRINT(RT_DEBUG_LOUD,("BulkOut-A:Size=%ld, CWPos=%ld, CWRPos=%ld, NBPos=%ld, ENBPos=%ld, bCopy=%d, bLRound=%d!\n", ThisBulkSize, pHTTXContext->CurWritePosition, pHTTXContext->CurWriteRealPos, pHTTXContext->NextBulkOutPosition, pHTTXContext->ENextBulkOutPosition, pHTTXContext->bCopySavePad, bTxQLastRound)); - - // USB DMA engine requires to pad extra 4 bytes. This pad doesn't count into real bulkoutsize. - pAppendant = &pWirelessPkt[TmpBulkEndPos]; - NdisZeroMemory(pAppendant, 8); - ThisBulkSize += 4; - pHTTXContext->LastOne = TRUE; - if ((ThisBulkSize % pAd->BulkOutMaxPacketSize) == 0) - ThisBulkSize += 4; - pHTTXContext->BulkOutSize = ThisBulkSize; - - pAd->watchDogTxPendingCnt[BulkOutPipeId] = 1; - BULK_OUT_UNLOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags2); - - // Init Tx context descriptor - RTUSBInitHTTxDesc(pAd, pHTTXContext, BulkOutPipeId, ThisBulkSize, (usb_complete_t)RTUSBBulkOutDataPacketComplete); - - pUrb = pHTTXContext->pUrb; - if((ret = RTUSB_SUBMIT_URB(pUrb))!=0) - { - DBGPRINT(RT_DEBUG_ERROR, ("RTUSBBulkOutDataPacket: Submit Tx URB failed %d\n", ret)); - - BULK_OUT_LOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); - pAd->BulkOutPending[BulkOutPipeId] = FALSE; - pAd->watchDogTxPendingCnt[BulkOutPipeId] = 0; - BULK_OUT_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); - - return; - } - - BULK_OUT_LOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); - pHTTXContext->IRPPending = TRUE; - BULK_OUT_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); - pAd->BulkOutReq++; - -} - - -VOID RTUSBBulkOutDataPacketComplete(purbb_t pUrb, struct pt_regs *pt_regs) -{ - PHT_TX_CONTEXT pHTTXContext; - PRTMP_ADAPTER pAd; - POS_COOKIE pObj; - UCHAR BulkOutPipeId; - - - pHTTXContext = (PHT_TX_CONTEXT)pUrb->context; - pAd = pHTTXContext->pAd; - pObj = (POS_COOKIE) pAd->OS_Cookie; - - // Store BulkOut PipeId - BulkOutPipeId = pHTTXContext->BulkOutPipeId; - pAd->BulkOutDataOneSecCount++; - - switch (BulkOutPipeId) - { - case 0: - pObj->ac0_dma_done_task.data = (unsigned long)pUrb; - tasklet_hi_schedule(&pObj->ac0_dma_done_task); - break; - case 1: - pObj->ac1_dma_done_task.data = (unsigned long)pUrb; - tasklet_hi_schedule(&pObj->ac1_dma_done_task); - break; - case 2: - pObj->ac2_dma_done_task.data = (unsigned long)pUrb; - tasklet_hi_schedule(&pObj->ac2_dma_done_task); - break; - case 3: - pObj->ac3_dma_done_task.data = (unsigned long)pUrb; - tasklet_hi_schedule(&pObj->ac3_dma_done_task); - break; - case 4: - pObj->hcca_dma_done_task.data = (unsigned long)pUrb; - tasklet_hi_schedule(&pObj->hcca_dma_done_task); - break; - } -} - - -/* - ======================================================================== - - Routine Description: - - Arguments: - - Return Value: - - Note: NULL frame use BulkOutPipeId = 0 - - ======================================================================== -*/ -VOID RTUSBBulkOutNullFrame( - IN PRTMP_ADAPTER pAd) -{ - PTX_CONTEXT pNullContext = &(pAd->NullContext); - PURB pUrb; - int ret = 0; - unsigned long IrqFlags; - - RTMP_IRQ_LOCK(&pAd->BulkOutLock[0], IrqFlags); - if ((pAd->BulkOutPending[0] == TRUE) || RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NEED_STOP_TX)) - { - RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], IrqFlags); - return; - } - pAd->BulkOutPending[0] = TRUE; - pAd->watchDogTxPendingCnt[0] = 1; - pNullContext->IRPPending = TRUE; - RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], IrqFlags); - - // Increase Total transmit byte counter - pAd->RalinkCounters.TransmittedByteCount += pNullContext->BulkOutSize; - - - // Clear Null frame bulk flag - RTUSB_CLEAR_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NULL); - -#ifdef RT_BIG_ENDIAN - RTMPDescriptorEndianChange((PUCHAR)pNullContext->TransferBuffer, TYPE_TXINFO); -#endif // RT_BIG_ENDIAN // - - // Init Tx context descriptor - RTUSBInitTxDesc(pAd, pNullContext, 0, (usb_complete_t)RTUSBBulkOutNullFrameComplete); - - pUrb = pNullContext->pUrb; - if((ret = RTUSB_SUBMIT_URB(pUrb))!=0) - { - RTMP_IRQ_LOCK(&pAd->BulkOutLock[0], IrqFlags); - pAd->BulkOutPending[0] = FALSE; - pAd->watchDogTxPendingCnt[0] = 0; - pNullContext->IRPPending = FALSE; - RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], IrqFlags); - - DBGPRINT(RT_DEBUG_ERROR, ("RTUSBBulkOutNullFrame: Submit Tx URB failed %d\n", ret)); - return; - } - -} - -// NULL frame use BulkOutPipeId = 0 -VOID RTUSBBulkOutNullFrameComplete(purbb_t pUrb, struct pt_regs *pt_regs) -{ - PRTMP_ADAPTER pAd; - PTX_CONTEXT pNullContext; - NTSTATUS Status; - POS_COOKIE pObj; - - - pNullContext = (PTX_CONTEXT)pUrb->context; - pAd = pNullContext->pAd; - Status = pUrb->status; - - pObj = (POS_COOKIE) pAd->OS_Cookie; - pObj->null_frame_complete_task.data = (unsigned long)pUrb; - tasklet_hi_schedule(&pObj->null_frame_complete_task); - -} - -/* - ======================================================================== - - Routine Description: - - Arguments: - - Return Value: - - Note: MLME use BulkOutPipeId = 0 - - ======================================================================== -*/ -VOID RTUSBBulkOutMLMEPacket( - IN PRTMP_ADAPTER pAd, - IN UCHAR Index) -{ - PTX_CONTEXT pMLMEContext; - PURB pUrb; - int ret = 0; - unsigned long IrqFlags; - - pMLMEContext = (PTX_CONTEXT)pAd->MgmtRing.Cell[pAd->MgmtRing.TxDmaIdx].AllocVa; - pUrb = pMLMEContext->pUrb; - - if ((pAd->MgmtRing.TxSwFreeIdx >= MGMT_RING_SIZE) || - (pMLMEContext->InUse == FALSE) || - (pMLMEContext->bWaitingBulkOut == FALSE)) - { - - - // Clear MLME bulk flag - RTUSB_CLEAR_BULK_FLAG(pAd, fRTUSB_BULK_OUT_MLME); - - return; - } - - - RTMP_IRQ_LOCK(&pAd->BulkOutLock[MGMTPIPEIDX], IrqFlags); - if ((pAd->BulkOutPending[MGMTPIPEIDX] == TRUE) || RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NEED_STOP_TX)) - { - RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[MGMTPIPEIDX], IrqFlags); - return; - } - - pAd->BulkOutPending[MGMTPIPEIDX] = TRUE; - pAd->watchDogTxPendingCnt[MGMTPIPEIDX] = 1; - pMLMEContext->IRPPending = TRUE; - pMLMEContext->bWaitingBulkOut = FALSE; - RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[MGMTPIPEIDX], IrqFlags); - - // Increase Total transmit byte counter - pAd->RalinkCounters.TransmittedByteCount += pMLMEContext->BulkOutSize; - - // Clear MLME bulk flag - RTUSB_CLEAR_BULK_FLAG(pAd, fRTUSB_BULK_OUT_MLME); - -#ifdef RT_BIG_ENDIAN - RTMPDescriptorEndianChange((PUCHAR)pMLMEContext->TransferBuffer, TYPE_TXINFO); -#endif // RT_BIG_ENDIAN // - - // Init Tx context descriptor - RTUSBInitTxDesc(pAd, pMLMEContext, MGMTPIPEIDX, (usb_complete_t)RTUSBBulkOutMLMEPacketComplete); - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) - //For mgmt urb buffer, because we use sk_buff, so we need to notify the USB controller do dma mapping. - pUrb->transfer_dma = 0; - pUrb->transfer_flags &= (~URB_NO_TRANSFER_DMA_MAP); -#endif - - pUrb = pMLMEContext->pUrb; - if((ret = RTUSB_SUBMIT_URB(pUrb))!=0) - { - DBGPRINT(RT_DEBUG_ERROR, ("RTUSBBulkOutMLMEPacket: Submit MLME URB failed %d\n", ret)); - RTMP_IRQ_LOCK(&pAd->BulkOutLock[MGMTPIPEIDX], IrqFlags); - pAd->BulkOutPending[MGMTPIPEIDX] = FALSE; - pAd->watchDogTxPendingCnt[MGMTPIPEIDX] = 0; - pMLMEContext->IRPPending = FALSE; - pMLMEContext->bWaitingBulkOut = TRUE; - RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[MGMTPIPEIDX], IrqFlags); - - return; - } - - //DBGPRINT_RAW(RT_DEBUG_INFO, ("<---RTUSBBulkOutMLMEPacket \n")); -// printk("<---RTUSBBulkOutMLMEPacket,Cpu=%d!, Dma=%d, SwIdx=%d!\n", pAd->MgmtRing.TxCpuIdx, pAd->MgmtRing.TxDmaIdx, pAd->MgmtRing.TxSwFreeIdx); -} - - -VOID RTUSBBulkOutMLMEPacketComplete(purbb_t pUrb, struct pt_regs *pt_regs) -{ - PTX_CONTEXT pMLMEContext; - PRTMP_ADAPTER pAd; - NTSTATUS Status; - POS_COOKIE pObj; - int index; - - //DBGPRINT_RAW(RT_DEBUG_INFO, ("--->RTUSBBulkOutMLMEPacketComplete\n")); - pMLMEContext = (PTX_CONTEXT)pUrb->context; - pAd = pMLMEContext->pAd; - pObj = (POS_COOKIE)pAd->OS_Cookie; - Status = pUrb->status; - index = pMLMEContext->SelfIdx; - - pObj->mgmt_dma_done_task.data = (unsigned long)pUrb; - tasklet_hi_schedule(&pObj->mgmt_dma_done_task); -} - - -/* - ======================================================================== - - Routine Description: - - Arguments: - - Return Value: - - Note: PsPoll use BulkOutPipeId = 0 - - ======================================================================== -*/ -VOID RTUSBBulkOutPsPoll( - IN PRTMP_ADAPTER pAd) -{ - PTX_CONTEXT pPsPollContext = &(pAd->PsPollContext); - PURB pUrb; - int ret = 0; - unsigned long IrqFlags; - - RTMP_IRQ_LOCK(&pAd->BulkOutLock[0], IrqFlags); - if ((pAd->BulkOutPending[0] == TRUE) || RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NEED_STOP_TX)) - { - RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], IrqFlags); - return; - } - pAd->BulkOutPending[0] = TRUE; - pAd->watchDogTxPendingCnt[0] = 1; - pPsPollContext->IRPPending = TRUE; - RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], IrqFlags); - - - // Clear PS-Poll bulk flag - RTUSB_CLEAR_BULK_FLAG(pAd, fRTUSB_BULK_OUT_PSPOLL); - -#ifdef RT_BIG_ENDIAN - RTMPDescriptorEndianChange((PUCHAR)pPsPollContext->TransferBuffer, TYPE_TXINFO); -#endif // RT_BIG_ENDIAN // - - // Init Tx context descriptor - RTUSBInitTxDesc(pAd, pPsPollContext, MGMTPIPEIDX, (usb_complete_t)RTUSBBulkOutPsPollComplete); - - pUrb = pPsPollContext->pUrb; - if((ret = RTUSB_SUBMIT_URB(pUrb))!=0) - { - RTMP_IRQ_LOCK(&pAd->BulkOutLock[0], IrqFlags); - pAd->BulkOutPending[0] = FALSE; - pAd->watchDogTxPendingCnt[0] = 0; - pPsPollContext->IRPPending = FALSE; - RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], IrqFlags); - - DBGPRINT(RT_DEBUG_ERROR, ("RTUSBBulkOutPsPoll: Submit Tx URB failed %d\n", ret)); - return; - } - -} - -// PS-Poll frame use BulkOutPipeId = 0 -VOID RTUSBBulkOutPsPollComplete(purbb_t pUrb,struct pt_regs *pt_regs) -{ - PRTMP_ADAPTER pAd; - PTX_CONTEXT pPsPollContext; - NTSTATUS Status; - POS_COOKIE pObj; - - - pPsPollContext= (PTX_CONTEXT)pUrb->context; - pAd = pPsPollContext->pAd; - Status = pUrb->status; - pObj = (POS_COOKIE) pAd->OS_Cookie; - pObj->pspoll_frame_complete_task.data = (unsigned long)pUrb; - tasklet_hi_schedule(&pObj->pspoll_frame_complete_task); - -} - -VOID DoBulkIn(IN RTMP_ADAPTER *pAd) -{ - PRX_CONTEXT pRxContext; - PURB pUrb; - int ret = 0; - unsigned long IrqFlags; - - RTMP_IRQ_LOCK(&pAd->BulkInLock, IrqFlags); - pRxContext = &(pAd->RxContext[pAd->NextRxBulkInIndex]); - if ((pAd->PendingRx > 0) || (pRxContext->Readable == TRUE) || (pRxContext->InUse == TRUE)) - { - RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); - return; - } - pRxContext->InUse = TRUE; - pRxContext->IRPPending = TRUE; - pAd->PendingRx++; - pAd->BulkInReq++; - RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); - - // Init Rx context descriptor - NdisZeroMemory(pRxContext->TransferBuffer, pRxContext->BulkInOffset); - RTUSBInitRxDesc(pAd, pRxContext); - - pUrb = pRxContext->pUrb; - if ((ret = RTUSB_SUBMIT_URB(pUrb))!=0) - { // fail - - RTMP_IRQ_LOCK(&pAd->BulkInLock, IrqFlags); - pRxContext->InUse = FALSE; - pRxContext->IRPPending = FALSE; - pAd->PendingRx--; - pAd->BulkInReq--; - RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); - DBGPRINT(RT_DEBUG_ERROR, ("RTUSBBulkReceive: Submit Rx URB failed %d\n", ret)); - } - else - { // success - ASSERT((pRxContext->InUse == pRxContext->IRPPending)); - //printk("BIDone, Pend=%d,BIIdx=%d,BIRIdx=%d!\n", pAd->PendingRx, pAd->NextRxBulkInIndex, pAd->NextRxBulkInReadIndex); - } -} - - -/* - ======================================================================== - - Routine Description: - USB_RxPacket initializes a URB and uses the Rx IRP to submit it - to USB. It checks if an Rx Descriptor is available and passes the - the coresponding buffer to be filled. If no descriptor is available - fails the request. When setting the completion routine we pass our - Adapter Object as Context. - - Arguments: - - Return Value: - TRUE found matched tuple cache - FALSE no matched found - - Note: - - ======================================================================== -*/ -#define fRTMP_ADAPTER_NEED_STOP_RX \ - (fRTMP_ADAPTER_NIC_NOT_EXIST | fRTMP_ADAPTER_HALT_IN_PROGRESS | \ - fRTMP_ADAPTER_RADIO_OFF | fRTMP_ADAPTER_RESET_IN_PROGRESS | \ - fRTMP_ADAPTER_REMOVE_IN_PROGRESS | fRTMP_ADAPTER_BULKIN_RESET) - -#define fRTMP_ADAPTER_NEED_STOP_HANDLE_RX \ - (fRTMP_ADAPTER_NIC_NOT_EXIST | fRTMP_ADAPTER_HALT_IN_PROGRESS | \ - fRTMP_ADAPTER_RADIO_OFF | fRTMP_ADAPTER_RESET_IN_PROGRESS | \ - fRTMP_ADAPTER_REMOVE_IN_PROGRESS) - -VOID RTUSBBulkReceive( - IN PRTMP_ADAPTER pAd) -{ - PRX_CONTEXT pRxContext; - unsigned long IrqFlags; - - - /* sanity check */ - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NEED_STOP_HANDLE_RX)) - return; - - while(1) - { - - RTMP_IRQ_LOCK(&pAd->BulkInLock, IrqFlags); - pRxContext = &(pAd->RxContext[pAd->NextRxBulkInReadIndex]); - if (((pRxContext->InUse == FALSE) && (pRxContext->Readable == TRUE)) && - (pRxContext->bRxHandling == FALSE)) - { - pRxContext->bRxHandling = TRUE; - RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); - - // read RxContext, Since not -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - STARxDoneInterruptHandle(pAd, TRUE); -#endif // CONFIG_STA_SUPPORT // - - // Finish to handle this bulkIn buffer. - RTMP_IRQ_LOCK(&pAd->BulkInLock, IrqFlags); - pRxContext->BulkInOffset = 0; - pRxContext->Readable = FALSE; - pRxContext->bRxHandling = FALSE; - pAd->ReadPosition = 0; - pAd->TransferBufferLength = 0; - INC_RING_INDEX(pAd->NextRxBulkInReadIndex, RX_RING_SIZE); - RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); - - } - else - { - RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); - break; - } - } - - if (!(RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NEED_STOP_RX))) - DoBulkIn(pAd); - -} - - -/* - ======================================================================== - - Routine Description: - This routine process Rx Irp and call rx complete function. - - Arguments: - DeviceObject Pointer to the device object for next lower - device. DeviceObject passed in here belongs to - the next lower driver in the stack because we - were invoked via IoCallDriver in USB_RxPacket - AND it is not OUR device object - Irp Ptr to completed IRP - Context Ptr to our Adapter object (context specified - in IoSetCompletionRoutine - - Return Value: - Always returns STATUS_MORE_PROCESSING_REQUIRED - - Note: - Always returns STATUS_MORE_PROCESSING_REQUIRED - ======================================================================== -*/ -VOID RTUSBBulkRxComplete(purbb_t pUrb, struct pt_regs *pt_regs) -{ - // use a receive tasklet to handle received packets; - // or sometimes hardware IRQ will be disabled here, so we can not - // use spin_lock_bh()/spin_unlock_bh() after IRQ is disabled. :< - PRX_CONTEXT pRxContext; - PRTMP_ADAPTER pAd; - POS_COOKIE pObj; - - - pRxContext = (PRX_CONTEXT)pUrb->context; - pAd = pRxContext->pAd; - pObj = (POS_COOKIE) pAd->OS_Cookie; - - pObj->rx_done_task.data = (unsigned long)pUrb; - tasklet_hi_schedule(&pObj->rx_done_task); - -} - -/* - ======================================================================== - - Routine Description: - - Arguments: - - Return Value: - - Note: - - ======================================================================== -*/ -VOID RTUSBKickBulkOut( - IN PRTMP_ADAPTER pAd) -{ - // BulkIn Reset will reset whole USB PHY. So we need to make sure fRTMP_ADAPTER_BULKIN_RESET not flaged. - if (!RTMP_TEST_FLAG(pAd ,fRTMP_ADAPTER_NEED_STOP_TX) -#ifdef RALINK_ATE - && !(ATE_ON(pAd)) -#endif // RALINK_ATE // - ) - { - // 2. PS-Poll frame is next - if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_PSPOLL)) - { - RTUSBBulkOutPsPoll(pAd); - } - - // 5. Mlme frame is next - else if ((RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_MLME)) && - (pAd->MgmtRing.TxSwFreeIdx < MGMT_RING_SIZE)) - { - RTUSBBulkOutMLMEPacket(pAd, pAd->MgmtRing.TxDmaIdx); - } - - // 6. Data frame normal is next - if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NORMAL)) - { - if (((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) || - (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) - )) - { - RTUSBBulkOutDataPacket(pAd, 0, pAd->NextBulkOutIndex[0]); - } - } - if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NORMAL_2)) - { - if (((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) || - (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) - )) - { - RTUSBBulkOutDataPacket(pAd, 1, pAd->NextBulkOutIndex[1]); - } - } - if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NORMAL_3)) - { - if (((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) || - (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) - )) - { - RTUSBBulkOutDataPacket(pAd, 2, pAd->NextBulkOutIndex[2]); - } - } - if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NORMAL_4)) - { - if (((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) || - (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) - )) - { - RTUSBBulkOutDataPacket(pAd, 3, pAd->NextBulkOutIndex[3]); - } - } - //PS packets use HCCA queue when dequeue from PS unicast queue (WiFi WPA2 MA9_DT1 for Marvell B STA) - if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NORMAL_5)) - { - if (((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) || - (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) - )) - { - } - } - - // 7. Null frame is the last - else if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NULL)) - { - if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) - { - RTUSBBulkOutNullFrame(pAd); - } - } - - // 8. No data avaliable - else - { - - } - } -#ifdef RALINK_ATE - /* If the mode is in ATE mode. */ - else if((ATE_ON(pAd)) && - !RTMP_TEST_FLAG(pAd ,fRTMP_ADAPTER_NEED_STOP_TX))// PETER : watch out ! - { - if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_ATE)) - { - ATE_RTUSBBulkOutDataPacket(pAd, 0); - } - } -#endif // RALINK_ATE // - -} - -/* - ======================================================================== - - Routine Description: - Call from Reset action after BulkOut failed. - Arguments: - - Return Value: - - Note: - - ======================================================================== -*/ -VOID RTUSBCleanUpDataBulkOutQueue( - IN PRTMP_ADAPTER pAd) -{ - UCHAR Idx; - PHT_TX_CONTEXT pTxContext; - - DBGPRINT(RT_DEBUG_TRACE, ("--->CleanUpDataBulkOutQueue\n")); - - for (Idx = 0; Idx < 4; Idx++) - { - pTxContext = &pAd->TxContext[Idx]; - - pTxContext->CurWritePosition = pTxContext->NextBulkOutPosition; - pTxContext->LastOne = FALSE; - NdisAcquireSpinLock(&pAd->BulkOutLock[Idx]); - pAd->BulkOutPending[Idx] = FALSE; - NdisReleaseSpinLock(&pAd->BulkOutLock[Idx]); - } - - DBGPRINT(RT_DEBUG_TRACE, ("<---CleanUpDataBulkOutQueue\n")); -} - -/* - ======================================================================== - - Routine Description: - - Arguments: - - Return Value: - - Note: - - ======================================================================== -*/ -VOID RTUSBCleanUpMLMEBulkOutQueue( - IN PRTMP_ADAPTER pAd) -{ - DBGPRINT(RT_DEBUG_TRACE, ("--->CleanUpMLMEBulkOutQueue\n")); - DBGPRINT(RT_DEBUG_TRACE, ("<---CleanUpMLMEBulkOutQueue\n")); -} - - -/* - ======================================================================== - - Routine Description: - - Arguments: - - Return Value: - - - Note: - - ======================================================================== -*/ -VOID RTUSBCancelPendingIRPs( - IN PRTMP_ADAPTER pAd) -{ - RTUSBCancelPendingBulkInIRP(pAd); - RTUSBCancelPendingBulkOutIRP(pAd); -} - -/* - ======================================================================== - - Routine Description: - - Arguments: - - Return Value: - - Note: - - ======================================================================== -*/ -VOID RTUSBCancelPendingBulkInIRP( - IN PRTMP_ADAPTER pAd) -{ - PRX_CONTEXT pRxContext; - UINT i; - - DBGPRINT_RAW(RT_DEBUG_TRACE, ("--->RTUSBCancelPendingBulkInIRP\n")); - for ( i = 0; i < (RX_RING_SIZE); i++) - { - pRxContext = &(pAd->RxContext[i]); - if(pRxContext->IRPPending == TRUE) - { - RTUSB_UNLINK_URB(pRxContext->pUrb); - pRxContext->IRPPending = FALSE; - pRxContext->InUse = FALSE; - //NdisInterlockedDecrement(&pAd->PendingRx); - //pAd->PendingRx--; - } - } - DBGPRINT_RAW(RT_DEBUG_TRACE, ("<---RTUSBCancelPendingBulkInIRP\n")); -} - - -/* - ======================================================================== - - Routine Description: - - Arguments: - - Return Value: - - Note: - - ======================================================================== -*/ -VOID RTUSBCancelPendingBulkOutIRP( - IN PRTMP_ADAPTER pAd) -{ - PHT_TX_CONTEXT pHTTXContext; - PTX_CONTEXT pMLMEContext; - PTX_CONTEXT pBeaconContext; - PTX_CONTEXT pNullContext; - PTX_CONTEXT pPsPollContext; - PTX_CONTEXT pRTSContext; - UINT i, Idx; -// unsigned int IrqFlags; -// NDIS_SPIN_LOCK *pLock; -// BOOLEAN *pPending; - - -// pLock = &pAd->BulkOutLock[MGMTPIPEIDX]; -// pPending = &pAd->BulkOutPending[MGMTPIPEIDX]; - - for (Idx = 0; Idx < 4; Idx++) - { - pHTTXContext = &(pAd->TxContext[Idx]); - - if (pHTTXContext->IRPPending == TRUE) - { - - // Get the USB_CONTEXT and cancel it's IRP; the completion routine will itself - // remove it from the HeadPendingSendList and NULL out HeadPendingSendList - // when the last IRP on the list has been cancelled; that's how we exit this loop - // - - RTUSB_UNLINK_URB(pHTTXContext->pUrb); - - // Sleep 200 microseconds to give cancellation time to work - RTMPusecDelay(200); - } - -#ifdef RALINK_ATE - pHTTXContext->bCopySavePad = 0; - pHTTXContext->CurWritePosition = 0; - pHTTXContext->CurWriteRealPos = 0; - pHTTXContext->bCurWriting = FALSE; - pHTTXContext->NextBulkOutPosition = 0; - pHTTXContext->ENextBulkOutPosition = 0; -#endif // RALINK_ATE // - pAd->BulkOutPending[Idx] = FALSE; - } - - //RTMP_IRQ_LOCK(pLock, IrqFlags); - for (i = 0; i < MGMT_RING_SIZE; i++) - { - pMLMEContext = (PTX_CONTEXT)pAd->MgmtRing.Cell[i].AllocVa; - if(pMLMEContext && (pMLMEContext->IRPPending == TRUE)) - { - - // Get the USB_CONTEXT and cancel it's IRP; the completion routine will itself - // remove it from the HeadPendingSendList and NULL out HeadPendingSendList - // when the last IRP on the list has been cancelled; that's how we exit this loop - // - - RTUSB_UNLINK_URB(pMLMEContext->pUrb); - pMLMEContext->IRPPending = FALSE; - - // Sleep 200 microsecs to give cancellation time to work - RTMPusecDelay(200); - } - } - pAd->BulkOutPending[MGMTPIPEIDX] = FALSE; - //RTMP_IRQ_UNLOCK(pLock, IrqFlags); - - - for (i = 0; i < BEACON_RING_SIZE; i++) - { - pBeaconContext = &(pAd->BeaconContext[i]); - - if(pBeaconContext->IRPPending == TRUE) - { - - // Get the USB_CONTEXT and cancel it's IRP; the completion routine will itself - // remove it from the HeadPendingSendList and NULL out HeadPendingSendList - // when the last IRP on the list has been cancelled; that's how we exit this loop - // - - RTUSB_UNLINK_URB(pBeaconContext->pUrb); - - // Sleep 200 microsecs to give cancellation time to work - RTMPusecDelay(200); - } - } - - pNullContext = &(pAd->NullContext); - if (pNullContext->IRPPending == TRUE) - RTUSB_UNLINK_URB(pNullContext->pUrb); - - pRTSContext = &(pAd->RTSContext); - if (pRTSContext->IRPPending == TRUE) - RTUSB_UNLINK_URB(pRTSContext->pUrb); - - pPsPollContext = &(pAd->PsPollContext); - if (pPsPollContext->IRPPending == TRUE) - RTUSB_UNLINK_URB(pPsPollContext->pUrb); - - for (Idx = 0; Idx < 4; Idx++) - { - NdisAcquireSpinLock(&pAd->BulkOutLock[Idx]); - pAd->BulkOutPending[Idx] = FALSE; - NdisReleaseSpinLock(&pAd->BulkOutLock[Idx]); - } -} - +#include "../../rt2870/common/rtusb_bulk.c" diff --git a/drivers/staging/rt3070/common/rtusb_data.c b/drivers/staging/rt3070/common/rtusb_data.c index 521309a2ae53..d05deb870f46 100644 --- a/drivers/staging/rt3070/common/rtusb_data.c +++ b/drivers/staging/rt3070/common/rtusb_data.c @@ -1,218 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - rtusb_data.c - - Abstract: - Ralink USB driver Tx/Rx functions. - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Jan 03-25-2006 created - -*/ -#include "../rt_config.h" - -extern UCHAR Phy11BGNextRateUpward[]; // defined in mlme.c -extern UCHAR EpToQueue[]; - - -VOID REPORT_AMSDU_FRAMES_TO_LLC( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pData, - IN ULONG DataSize) -{ - PNDIS_PACKET pPacket; - UINT nMSDU; - struct sk_buff *pSkb; - - nMSDU = 0; - /* allocate a rx packet */ - pSkb = dev_alloc_skb(RX_BUFFER_AGGRESIZE); - pPacket = (PNDIS_PACKET)OSPKT_TO_RTPKT(pSkb); - if (pSkb) - { - - /* convert 802.11 to 802.3 packet */ - pSkb->dev = get_netdev_from_bssid(pAd, BSS0); - RTMP_SET_PACKET_SOURCE(pPacket, PKTSRC_NDIS); - deaggregate_AMSDU_announce(pAd, pPacket, pData, DataSize); - } - else - { - DBGPRINT(RT_DEBUG_ERROR,("Can't allocate skb\n")); - } -} - -NDIS_STATUS RTUSBFreeDescriptorRequest( - IN PRTMP_ADAPTER pAd, - IN UCHAR BulkOutPipeId, - IN UINT32 NumberRequired) -{ -// UCHAR FreeNumber = 0; -// UINT Index; - NDIS_STATUS Status = NDIS_STATUS_FAILURE; - unsigned long IrqFlags; - HT_TX_CONTEXT *pHTTXContext; - - - pHTTXContext = &pAd->TxContext[BulkOutPipeId]; - RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags); - if ((pHTTXContext->CurWritePosition < pHTTXContext->NextBulkOutPosition) && ((pHTTXContext->CurWritePosition + NumberRequired + LOCAL_TXBUF_SIZE) > pHTTXContext->NextBulkOutPosition)) - { - - RTUSB_SET_BULK_FLAG(pAd, (fRTUSB_BULK_OUT_DATA_NORMAL << BulkOutPipeId)); - } - else if ((pHTTXContext->CurWritePosition == 8) && (pHTTXContext->NextBulkOutPosition < (NumberRequired + LOCAL_TXBUF_SIZE))) - { - RTUSB_SET_BULK_FLAG(pAd, (fRTUSB_BULK_OUT_DATA_NORMAL << BulkOutPipeId)); - } - else if (pHTTXContext->bCurWriting == TRUE) - { - DBGPRINT(RT_DEBUG_TRACE,("RTUSBFreeD c3 --> QueIdx=%d, CWPos=%ld, NBOutPos=%ld!\n", BulkOutPipeId, pHTTXContext->CurWritePosition, pHTTXContext->NextBulkOutPosition)); - RTUSB_SET_BULK_FLAG(pAd, (fRTUSB_BULK_OUT_DATA_NORMAL << BulkOutPipeId)); - } - else - { - Status = NDIS_STATUS_SUCCESS; - } - RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags); - - - return (Status); -} - - -NDIS_STATUS RTUSBFreeDescriptorRelease( - IN RTMP_ADAPTER *pAd, - IN UCHAR BulkOutPipeId) -{ - unsigned long IrqFlags; - HT_TX_CONTEXT *pHTTXContext; - - pHTTXContext = &pAd->TxContext[BulkOutPipeId]; - RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags); - pHTTXContext->bCurWriting = FALSE; - RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags); - - return (NDIS_STATUS_SUCCESS); -} - - -BOOLEAN RTUSBNeedQueueBackForAgg( - IN RTMP_ADAPTER *pAd, - IN UCHAR BulkOutPipeId) -{ - unsigned long IrqFlags; - HT_TX_CONTEXT *pHTTXContext; - BOOLEAN needQueBack = FALSE; - - pHTTXContext = &pAd->TxContext[BulkOutPipeId]; - - RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags); - if ((pHTTXContext->IRPPending == TRUE) /*&& (pAd->TxSwQueue[BulkOutPipeId].Number == 0) */) - { - if ((pHTTXContext->CurWritePosition < pHTTXContext->ENextBulkOutPosition) && - (((pHTTXContext->ENextBulkOutPosition+MAX_AGGREGATION_SIZE) < MAX_TXBULK_LIMIT) || (pHTTXContext->CurWritePosition > MAX_AGGREGATION_SIZE))) - { - needQueBack = TRUE; - } - else if ((pHTTXContext->CurWritePosition > pHTTXContext->ENextBulkOutPosition) && - ((pHTTXContext->ENextBulkOutPosition + MAX_AGGREGATION_SIZE) < pHTTXContext->CurWritePosition)) - { - needQueBack = TRUE; - } - } - RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags); - - return needQueBack; - -} - - -/* - ======================================================================== - - Routine Description: - - Arguments: - - Return Value: - - IRQL = - - Note: - - ======================================================================== -*/ -VOID RTUSBRejectPendingPackets( - IN PRTMP_ADAPTER pAd) -{ - UCHAR Index; - PQUEUE_ENTRY pEntry; - PNDIS_PACKET pPacket; - PQUEUE_HEADER pQueue; - - - for (Index = 0; Index < 4; Index++) - { - NdisAcquireSpinLock(&pAd->TxSwQueueLock[Index]); - while (pAd->TxSwQueue[Index].Head != NULL) - { - pQueue = (PQUEUE_HEADER) &(pAd->TxSwQueue[Index]); - pEntry = RemoveHeadQueue(pQueue); - pPacket = QUEUE_ENTRY_TO_PACKET(pEntry); - RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); - } - NdisReleaseSpinLock(&pAd->TxSwQueueLock[Index]); - - } - -} - -VOID RTMPWriteTxInfo( - IN PRTMP_ADAPTER pAd, - IN PTXINFO_STRUC pTxInfo, - IN USHORT USBDMApktLen, - IN BOOLEAN bWiv, - IN UCHAR QueueSel, - IN UCHAR NextValid, - IN UCHAR TxBurst) -{ - pTxInfo->USBDMATxPktLen = USBDMApktLen; - pTxInfo->QSEL = QueueSel; - if (QueueSel != FIFO_EDCA) - DBGPRINT(RT_DEBUG_TRACE, ("====> QueueSel != FIFO_EDCA<============\n")); - pTxInfo->USBDMANextVLD = FALSE; //NextValid; // Need to check with Jan about this. - pTxInfo->USBDMATxburst = TxBurst; - pTxInfo->WIV = bWiv; - pTxInfo->SwUseLastRound = 0; - pTxInfo->rsv = 0; - pTxInfo->rsv2 = 0; -} - +#include "../../rt2870/common/rtusb_data.c" diff --git a/drivers/staging/rt3070/common/rtusb_io.c b/drivers/staging/rt3070/common/rtusb_io.c index a6a52e3445f9..20a0b56e58b0 100644 --- a/drivers/staging/rt3070/common/rtusb_io.c +++ b/drivers/staging/rt3070/common/rtusb_io.c @@ -1,1908 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - rtusb_io.c - - Abstract: - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Name Date Modification logs - Paul Lin 06-25-2004 created -*/ - -#include "../rt_config.h" - - -/* - ======================================================================== - - Routine Description: NIC initialization complete - - Arguments: - - Return Value: - - IRQL = - - Note: - - ======================================================================== -*/ - -NTSTATUS RTUSBFirmwareRun( - IN PRTMP_ADAPTER pAd) -{ - NTSTATUS Status; - - Status = RTUSB_VendorRequest( - pAd, - USBD_TRANSFER_DIRECTION_OUT, - DEVICE_VENDOR_REQUEST_OUT, - 0x01, - 0x8, - 0, - NULL, - 0); - - return Status; -} - - - -/* - ======================================================================== - - Routine Description: Write Firmware to NIC. - - Arguments: - - Return Value: - - IRQL = - - Note: - - ======================================================================== -*/ -NTSTATUS RTUSBFirmwareWrite( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pFwImage, - IN ULONG FwLen) -{ - UINT32 MacReg; - NTSTATUS Status; -// ULONG i; - USHORT writeLen; - - Status = RTUSBReadMACRegister(pAd, MAC_CSR0, &MacReg); - - - writeLen = FwLen; - RTUSBMultiWrite(pAd, FIRMWARE_IMAGE_BASE, pFwImage, writeLen); - - Status = RTUSBWriteMACRegister(pAd, 0x7014, 0xffffffff); - Status = RTUSBWriteMACRegister(pAd, 0x701c, 0xffffffff); - Status = RTUSBFirmwareRun(pAd); - - RTMPusecDelay(10000); - RTUSBWriteMACRegister(pAd,H2M_MAILBOX_CSR,0); - AsicSendCommandToMcu(pAd, 0x72, 0x00, 0x00, 0x00);//reset rf by MCU supported by new firmware - - return Status; -} - - -/* - ======================================================================== - - Routine Description: Get current firmware operation mode (Return Value) - - Arguments: - - Return Value: - 0 or 1 = Downloaded by host driver - others = Driver doesn't download firmware - - IRQL = - - Note: - - ======================================================================== -*/ -NTSTATUS RTUSBFirmwareOpmode( - IN PRTMP_ADAPTER pAd, - OUT PUINT32 pValue) -{ - NTSTATUS Status; - - Status = RTUSB_VendorRequest( - pAd, - (USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK), - DEVICE_VENDOR_REQUEST_IN, - 0x1, - 0x11, - 0, - pValue, - 4); - return Status; -} -NTSTATUS RTUSBVenderReset( - IN PRTMP_ADAPTER pAd) -{ - NTSTATUS Status; - DBGPRINT_RAW(RT_DEBUG_ERROR, ("-->RTUSBVenderReset\n")); - Status = RTUSB_VendorRequest( - pAd, - USBD_TRANSFER_DIRECTION_OUT, - DEVICE_VENDOR_REQUEST_OUT, - 0x01, - 0x1, - 0, - NULL, - 0); - - DBGPRINT_RAW(RT_DEBUG_ERROR, ("<--RTUSBVenderReset\n")); - return Status; -} -/* - ======================================================================== - - Routine Description: Read various length data from RT2573 - - Arguments: - - Return Value: - - IRQL = - - Note: - - ======================================================================== -*/ -NTSTATUS RTUSBMultiRead( - IN PRTMP_ADAPTER pAd, - IN USHORT Offset, - OUT PUCHAR pData, - IN USHORT length) -{ - NTSTATUS Status; - - Status = RTUSB_VendorRequest( - pAd, - (USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK), - DEVICE_VENDOR_REQUEST_IN, - 0x7, - 0, - Offset, - pData, - length); - - return Status; -} - -/* - ======================================================================== - - Routine Description: Write various length data to RT2573 - - Arguments: - - Return Value: - - IRQL = - - Note: - - ======================================================================== -*/ -NTSTATUS RTUSBMultiWrite_OneByte( - IN PRTMP_ADAPTER pAd, - IN USHORT Offset, - IN PUCHAR pData) -{ - NTSTATUS Status; - - // TODO: In 2870, use this funciton carefully cause it's not stable. - Status = RTUSB_VendorRequest( - pAd, - USBD_TRANSFER_DIRECTION_OUT, - DEVICE_VENDOR_REQUEST_OUT, - 0x6, - 0, - Offset, - pData, - 1); - - return Status; -} - -NTSTATUS RTUSBMultiWrite( - IN PRTMP_ADAPTER pAd, - IN USHORT Offset, - IN PUCHAR pData, - IN USHORT length) -{ - NTSTATUS Status; - - - USHORT index = 0,Value; - PUCHAR pSrc = pData; - USHORT resude = 0; - - resude = length % 2; - length += resude; - do - { - Value =(USHORT)( *pSrc | (*(pSrc + 1) << 8)); - Status = RTUSBSingleWrite(pAd,Offset + index,Value); - index +=2; - length -= 2; - pSrc = pSrc + 2; - }while(length > 0); - - return Status; -} - - -NTSTATUS RTUSBSingleWrite( - IN RTMP_ADAPTER *pAd, - IN USHORT Offset, - IN USHORT Value) -{ - NTSTATUS Status; - - Status = RTUSB_VendorRequest( - pAd, - USBD_TRANSFER_DIRECTION_OUT, - DEVICE_VENDOR_REQUEST_OUT, - 0x2, - Value, - Offset, - NULL, - 0); - - return Status; - -} - - -/* - ======================================================================== - - Routine Description: Read 32-bit MAC register - - Arguments: - - Return Value: - - IRQL = - - Note: - - ======================================================================== -*/ -NTSTATUS RTUSBReadMACRegister( - IN PRTMP_ADAPTER pAd, - IN USHORT Offset, - OUT PUINT32 pValue) -{ - NTSTATUS Status; - UINT32 localVal; - - Status = RTUSB_VendorRequest( - pAd, - (USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK), - DEVICE_VENDOR_REQUEST_IN, - 0x7, - 0, - Offset, - &localVal, - 4); - - *pValue = le2cpu32(localVal); - - - if (Status < 0) - *pValue = 0xffffffff; - - return Status; -} - - -/* - ======================================================================== - - Routine Description: Write 32-bit MAC register - - Arguments: - - Return Value: - - IRQL = - - Note: - - ======================================================================== -*/ -NTSTATUS RTUSBWriteMACRegister( - IN PRTMP_ADAPTER pAd, - IN USHORT Offset, - IN UINT32 Value) -{ - NTSTATUS Status; - UINT32 localVal; - - localVal = Value; - - Status = RTUSBSingleWrite(pAd, Offset, (USHORT)(localVal & 0xffff)); - Status = RTUSBSingleWrite(pAd, Offset + 2, (USHORT)((localVal & 0xffff0000) >> 16)); - - return Status; -} - - - -#if 1 -/* - ======================================================================== - - Routine Description: Read 8-bit BBP register - - Arguments: - - Return Value: - - IRQL = - - Note: - - ======================================================================== -*/ -NTSTATUS RTUSBReadBBPRegister( - IN PRTMP_ADAPTER pAd, - IN UCHAR Id, - IN PUCHAR pValue) -{ - BBP_CSR_CFG_STRUC BbpCsr; - UINT i = 0; - NTSTATUS status; - - // Verify the busy condition - do - { - status = RTUSBReadMACRegister(pAd, BBP_CSR_CFG, &BbpCsr.word); - if(status >= 0) - { - if (!(BbpCsr.field.Busy == BUSY)) - break; - } - printk("RTUSBReadBBPRegister(BBP_CSR_CFG_1):retry count=%d!\n", i); - i++; - } - while ((i < RETRY_LIMIT) && (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))); - - if ((i == RETRY_LIMIT) || (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))) - { - // - // Read failed then Return Default value. - // - *pValue = pAd->BbpWriteLatch[Id]; - - DBGPRINT_RAW(RT_DEBUG_ERROR, ("Retry count exhausted or device removed!!!\n")); - return STATUS_UNSUCCESSFUL; - } - - // Prepare for write material - BbpCsr.word = 0; - BbpCsr.field.fRead = 1; - BbpCsr.field.Busy = 1; - BbpCsr.field.RegNum = Id; - RTUSBWriteMACRegister(pAd, BBP_CSR_CFG, BbpCsr.word); - - i = 0; - // Verify the busy condition - do - { - status = RTUSBReadMACRegister(pAd, BBP_CSR_CFG, &BbpCsr.word); - if (status >= 0) - { - if (!(BbpCsr.field.Busy == BUSY)) - { - *pValue = (UCHAR)BbpCsr.field.Value; - break; - } - } - printk("RTUSBReadBBPRegister(BBP_CSR_CFG_2):retry count=%d!\n", i); - i++; - } - while ((i < RETRY_LIMIT) && (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))); - - if ((i == RETRY_LIMIT) || (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))) - { - // - // Read failed then Return Default value. - // - *pValue = pAd->BbpWriteLatch[Id]; - - DBGPRINT_RAW(RT_DEBUG_ERROR, ("Retry count exhausted or device removed!!!\n")); - return STATUS_UNSUCCESSFUL; - } - - return STATUS_SUCCESS; -} -#else -/* - ======================================================================== - - Routine Description: Read 8-bit BBP register via firmware - - Arguments: - - Return Value: - - IRQL = - - Note: - - ======================================================================== -*/ -NTSTATUS RTUSBReadBBPRegister( - IN PRTMP_ADAPTER pAd, - IN UCHAR Id, - IN PUCHAR pValue) -{ - BBP_CSR_CFG_STRUC BbpCsr; - int i, k; - for (i=0; iBbpWriteLatch[Id]; - return STATUS_UNSUCCESSFUL; - } - return STATUS_SUCCESS; -} -#endif - -#if 1 -/* - ======================================================================== - - Routine Description: Write 8-bit BBP register - - Arguments: - - Return Value: - - IRQL = - - Note: - - ======================================================================== -*/ -NTSTATUS RTUSBWriteBBPRegister( - IN PRTMP_ADAPTER pAd, - IN UCHAR Id, - IN UCHAR Value) -{ - BBP_CSR_CFG_STRUC BbpCsr; - UINT i = 0; - NTSTATUS status; - // Verify the busy condition - do - { - status = RTUSBReadMACRegister(pAd, BBP_CSR_CFG, &BbpCsr.word); - if (status >= 0) - { - if (!(BbpCsr.field.Busy == BUSY)) - break; - } - printk("RTUSBWriteBBPRegister(BBP_CSR_CFG):retry count=%d!\n", i); - i++; - } - while ((i < RETRY_LIMIT) && (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))); - - if ((i == RETRY_LIMIT) || (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))) - { - DBGPRINT_RAW(RT_DEBUG_ERROR, ("Retry count exhausted or device removed!!!\n")); - return STATUS_UNSUCCESSFUL; - } - - // Prepare for write material - BbpCsr.word = 0; - BbpCsr.field.fRead = 0; - BbpCsr.field.Value = Value; - BbpCsr.field.Busy = 1; - BbpCsr.field.RegNum = Id; - RTUSBWriteMACRegister(pAd, BBP_CSR_CFG, BbpCsr.word); - - pAd->BbpWriteLatch[Id] = Value; - - return STATUS_SUCCESS; -} -#else -/* - ======================================================================== - - Routine Description: Write 8-bit BBP register via firmware - - Arguments: - - Return Value: - - IRQL = - - Note: - - ======================================================================== -*/ - -NTSTATUS RTUSBWriteBBPRegister( - IN PRTMP_ADAPTER pAd, - IN UCHAR Id, - IN UCHAR Value) - -{ - BBP_CSR_CFG_STRUC BbpCsr; - int BusyCnt; - for (BusyCnt=0; BusyCntBbpWriteLatch[Id] = Value; - break; - } - if (BusyCnt == MAX_BUSY_COUNT) - { - DBGPRINT_ERR(("BBP write R%d=0x%x fail\n", Id, BbpCsr.word)); - return STATUS_UNSUCCESSFUL; - } - return STATUS_SUCCESS; -} -#endif -/* - ======================================================================== - - Routine Description: Write RF register through MAC - - Arguments: - - Return Value: - - IRQL = - - Note: - - ======================================================================== -*/ -NTSTATUS RTUSBWriteRFRegister( - IN PRTMP_ADAPTER pAd, - IN UINT32 Value) -{ - PHY_CSR4_STRUC PhyCsr4; - UINT i = 0; - NTSTATUS status; - - NdisZeroMemory(&PhyCsr4, sizeof(PHY_CSR4_STRUC)); - do - { - status = RTUSBReadMACRegister(pAd, RF_CSR_CFG0, &PhyCsr4.word); - if (status >= 0) - { - if (!(PhyCsr4.field.Busy)) - break; - } - printk("RTUSBWriteRFRegister(RF_CSR_CFG0):retry count=%d!\n", i); - i++; - } - while ((i < RETRY_LIMIT) && (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))); - - if ((i == RETRY_LIMIT) || (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))) - { - DBGPRINT_RAW(RT_DEBUG_ERROR, ("Retry count exhausted or device removed!!!\n")); - return STATUS_UNSUCCESSFUL; - } - - RTUSBWriteMACRegister(pAd, RF_CSR_CFG0, Value); - - return STATUS_SUCCESS; -} - - -/* - ======================================================================== - - Routine Description: - - Arguments: - - Return Value: - - IRQL = - - Note: - - ======================================================================== -*/ -NTSTATUS RTUSBReadEEPROM( - IN PRTMP_ADAPTER pAd, - IN USHORT Offset, - OUT PUCHAR pData, - IN USHORT length) -{ - NTSTATUS Status = STATUS_SUCCESS; - -#ifdef RT30xx - if(pAd->bUseEfuse) - { - Status =eFuseRead(pAd, Offset, pData, length); - } - else -#endif // RT30xx // - { - Status = RTUSB_VendorRequest( - pAd, - (USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK), - DEVICE_VENDOR_REQUEST_IN, - 0x9, - 0, - Offset, - pData, - length); - } - - return Status; -} - -/* - ======================================================================== - - Routine Description: - - Arguments: - - Return Value: - - IRQL = - - Note: - - ======================================================================== -*/ -NTSTATUS RTUSBWriteEEPROM( - IN PRTMP_ADAPTER pAd, - IN USHORT Offset, - IN PUCHAR pData, - IN USHORT length) -{ - NTSTATUS Status = STATUS_SUCCESS; - -#ifdef RT30xx - if(pAd->bUseEfuse) - { - Status = eFuseWrite(pAd, Offset, pData, length); - } - else -#endif // RT30xx // - { - Status = RTUSB_VendorRequest( - pAd, - USBD_TRANSFER_DIRECTION_OUT, - DEVICE_VENDOR_REQUEST_OUT, - 0x8, - 0, - Offset, - pData, - length); - } - - return Status; -} - -/* - ======================================================================== - - Routine Description: - - Arguments: - - Return Value: - - IRQL = - - Note: - - ======================================================================== -*/ -VOID RTUSBPutToSleep( - IN PRTMP_ADAPTER pAd) -{ - UINT32 value; - - // Timeout 0x40 x 50us - value = (SLEEPCID<<16)+(OWNERMCU<<24)+ (0x40<<8)+1; - RTUSBWriteMACRegister(pAd, 0x7010, value); - RTUSBWriteMACRegister(pAd, 0x404, 0x30); - //RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS); - DBGPRINT_RAW(RT_DEBUG_ERROR, ("Sleep Mailbox testvalue %x\n", value)); - -} - -/* - ======================================================================== - - Routine Description: - - Arguments: - - Return Value: - - IRQL = - - Note: - - ======================================================================== -*/ -NTSTATUS RTUSBWakeUp( - IN PRTMP_ADAPTER pAd) -{ - NTSTATUS Status; - - Status = RTUSB_VendorRequest( - pAd, - USBD_TRANSFER_DIRECTION_OUT, - DEVICE_VENDOR_REQUEST_OUT, - 0x01, - 0x09, - 0, - NULL, - 0); - - return Status; -} - -/* - ======================================================================== - - Routine Description: - - Arguments: - - Return Value: - - IRQL = - - Note: - - ======================================================================== -*/ -VOID RTUSBInitializeCmdQ( - IN PCmdQ cmdq) -{ - cmdq->head = NULL; - cmdq->tail = NULL; - cmdq->size = 0; - cmdq->CmdQState = RT2870_THREAD_INITED; -} - -/* - ======================================================================== - - Routine Description: - - Arguments: - - Return Value: - - IRQL = - - Note: - - ======================================================================== -*/ -NDIS_STATUS RTUSBEnqueueCmdFromNdis( - IN PRTMP_ADAPTER pAd, - IN NDIS_OID Oid, - IN BOOLEAN SetInformation, - IN PVOID pInformationBuffer, - IN UINT32 InformationBufferLength) -{ - NDIS_STATUS status; - PCmdQElmt cmdqelmt = NULL; - POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie; - - - if (pObj->RTUSBCmdThr_pid < 0) - return (NDIS_STATUS_RESOURCES); - - status = RTMPAllocateMemory((PVOID *)&cmdqelmt, sizeof(CmdQElmt)); - if ((status != NDIS_STATUS_SUCCESS) || (cmdqelmt == NULL)) - return (NDIS_STATUS_RESOURCES); - - cmdqelmt->buffer = NULL; - if (pInformationBuffer != NULL) - { - status = RTMPAllocateMemory((PVOID *)&cmdqelmt->buffer, InformationBufferLength); - if ((status != NDIS_STATUS_SUCCESS) || (cmdqelmt->buffer == NULL)) - { - kfree(cmdqelmt); - return (NDIS_STATUS_RESOURCES); - } - else - { - NdisMoveMemory(cmdqelmt->buffer, pInformationBuffer, InformationBufferLength); - cmdqelmt->bufferlength = InformationBufferLength; - } - } - else - cmdqelmt->bufferlength = 0; - - cmdqelmt->command = Oid; - cmdqelmt->CmdFromNdis = TRUE; - if (SetInformation == TRUE) - cmdqelmt->SetOperation = TRUE; - else - cmdqelmt->SetOperation = FALSE; - - NdisAcquireSpinLock(&pAd->CmdQLock); - if (pAd->CmdQ.CmdQState & RT2870_THREAD_CAN_DO_INSERT) - { - EnqueueCmd((&pAd->CmdQ), cmdqelmt); - status = NDIS_STATUS_SUCCESS; - } - else - { - status = NDIS_STATUS_FAILURE; - } - NdisReleaseSpinLock(&pAd->CmdQLock); - - if (status == NDIS_STATUS_FAILURE) - { - if (cmdqelmt->buffer) - NdisFreeMemory(cmdqelmt->buffer, cmdqelmt->bufferlength, 0); - NdisFreeMemory(cmdqelmt, sizeof(CmdQElmt), 0); - } - else - RTUSBCMDUp(pAd); - - - return(NDIS_STATUS_SUCCESS); -} - -/* - ======================================================================== - - Routine Description: - - Arguments: - - Return Value: - - IRQL = - - Note: - - ======================================================================== -*/ -NDIS_STATUS RTUSBEnqueueInternalCmd( - IN PRTMP_ADAPTER pAd, - IN NDIS_OID Oid, - IN PVOID pInformationBuffer, - IN UINT32 InformationBufferLength) -{ - NDIS_STATUS status; - PCmdQElmt cmdqelmt = NULL; - - - status = RTMPAllocateMemory((PVOID *)&cmdqelmt, sizeof(CmdQElmt)); - if ((status != NDIS_STATUS_SUCCESS) || (cmdqelmt == NULL)) - return (NDIS_STATUS_RESOURCES); - NdisZeroMemory(cmdqelmt, sizeof(CmdQElmt)); - - if(InformationBufferLength > 0) - { - status = RTMPAllocateMemory((PVOID *)&cmdqelmt->buffer, InformationBufferLength); - if ((status != NDIS_STATUS_SUCCESS) || (cmdqelmt->buffer == NULL)) - { - NdisFreeMemory(cmdqelmt, sizeof(CmdQElmt), 0); - return (NDIS_STATUS_RESOURCES); - } - else - { - NdisMoveMemory(cmdqelmt->buffer, pInformationBuffer, InformationBufferLength); - cmdqelmt->bufferlength = InformationBufferLength; - } - } - else - { - cmdqelmt->buffer = NULL; - cmdqelmt->bufferlength = 0; - } - - cmdqelmt->command = Oid; - cmdqelmt->CmdFromNdis = FALSE; - - if (cmdqelmt != NULL) - { - NdisAcquireSpinLock(&pAd->CmdQLock); - if (pAd->CmdQ.CmdQState & RT2870_THREAD_CAN_DO_INSERT) - { - EnqueueCmd((&pAd->CmdQ), cmdqelmt); - status = NDIS_STATUS_SUCCESS; - } - else - { - status = NDIS_STATUS_FAILURE; - } - NdisReleaseSpinLock(&pAd->CmdQLock); - - if (status == NDIS_STATUS_FAILURE) - { - if (cmdqelmt->buffer) - NdisFreeMemory(cmdqelmt->buffer, cmdqelmt->bufferlength, 0); - NdisFreeMemory(cmdqelmt, sizeof(CmdQElmt), 0); - } - else - RTUSBCMDUp(pAd); - } - return(NDIS_STATUS_SUCCESS); -} - -/* - ======================================================================== - - Routine Description: - - Arguments: - - Return Value: - - IRQL = - - Note: - - ======================================================================== -*/ -VOID RTUSBDequeueCmd( - IN PCmdQ cmdq, - OUT PCmdQElmt *pcmdqelmt) -{ - *pcmdqelmt = cmdq->head; - - if (*pcmdqelmt != NULL) - { - cmdq->head = cmdq->head->next; - cmdq->size--; - if (cmdq->size == 0) - cmdq->tail = NULL; - } -} - -/* - ======================================================================== - usb_control_msg - Builds a control urb, sends it off and waits for completion - @dev: pointer to the usb device to send the message to - @pipe: endpoint "pipe" to send the message to - @request: USB message request value - @requesttype: USB message request type value - @value: USB message value - @index: USB message index value - @data: pointer to the data to send - @size: length in bytes of the data to send - @timeout: time in jiffies to wait for the message to complete before - timing out (if 0 the wait is forever) - Context: !in_interrupt () - - This function sends a simple control message to a specified endpoint - and waits for the message to complete, or timeout. - If successful, it returns the number of bytes transferred, otherwise a negative error number. - - Don't use this function from within an interrupt context, like a - bottom half handler. If you need an asynchronous message, or need to send - a message from within interrupt context, use usb_submit_urb() - If a thread in your driver uses this call, make sure your disconnect() - method can wait for it to complete. Since you don't have a handle on - the URB used, you can't cancel the request. - - - Routine Description: - - Arguments: - - Return Value: - - Note: - - ======================================================================== -*/ -NTSTATUS RTUSB_VendorRequest( - IN PRTMP_ADAPTER pAd, - IN UINT32 TransferFlags, - IN UCHAR RequestType, - IN UCHAR Request, - IN USHORT Value, - IN USHORT Index, - IN PVOID TransferBuffer, - IN UINT32 TransferBufferLength) -{ - int ret; - POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie; - - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) - { - DBGPRINT(RT_DEBUG_ERROR, ("device disconnected\n")); - return -1; - } - else if (in_interrupt()) - { - DBGPRINT(RT_DEBUG_ERROR, ("in_interrupt, RTUSB_VendorRequest Request%02x Value%04x Offset%04x\n",Request,Value,Index)); - - return -1; - } - else - { -#define MAX_RETRY_COUNT 10 - - int retryCount = 0; - void *tmpBuf = TransferBuffer; - - // Acquire Control token -#ifdef INF_AMAZON_SE - ret = down_interruptible(&(pAd->UsbVendorReq_semaphore)); - if (pAd->UsbVendorReqBuf) - { - ASSERT(TransferBufferLength UsbVendorReqBuf; - NdisZeroMemory(pAd->UsbVendorReqBuf, TransferBufferLength); - - if (RequestType == DEVICE_VENDOR_REQUEST_OUT) - NdisMoveMemory(tmpBuf, TransferBuffer, TransferBufferLength); - } -#endif // INF_AMAZON_SE // - do { - if( RequestType == DEVICE_VENDOR_REQUEST_OUT) - ret=usb_control_msg(pObj->pUsb_Dev, usb_sndctrlpipe( pObj->pUsb_Dev, 0 ), Request, RequestType, Value,Index, tmpBuf, TransferBufferLength, CONTROL_TIMEOUT_JIFFIES); - else if(RequestType == DEVICE_VENDOR_REQUEST_IN) - ret=usb_control_msg(pObj->pUsb_Dev, usb_rcvctrlpipe( pObj->pUsb_Dev, 0 ), Request, RequestType, Value,Index, tmpBuf, TransferBufferLength, CONTROL_TIMEOUT_JIFFIES); - else - { - DBGPRINT(RT_DEBUG_ERROR, ("vendor request direction is failed\n")); - ret = -1; - } - - retryCount++; - if (ret < 0) { - printk("#\n"); - RTMPusecDelay(5000); - } - } while((ret < 0) && (retryCount < MAX_RETRY_COUNT)); - -#ifdef INF_AMAZON_SE - if ((pAd->UsbVendorReqBuf) && (RequestType == DEVICE_VENDOR_REQUEST_IN)) - NdisMoveMemory(TransferBuffer, tmpBuf, TransferBufferLength); - up(&(pAd->UsbVendorReq_semaphore)); -#endif // INF_AMAZON_SE // - - if (ret < 0) { -// DBGPRINT(RT_DEBUG_ERROR, ("USBVendorRequest failed ret=%d \n",ret)); - DBGPRINT(RT_DEBUG_ERROR, ("RTUSB_VendorRequest failed(%d),TxFlags=0x%x, ReqType=%s, Req=0x%x, Index=0x%x\n", - ret, TransferFlags, (RequestType == DEVICE_VENDOR_REQUEST_OUT ? "OUT" : "IN"), Request, Index)); - if (Request == 0x2) - DBGPRINT(RT_DEBUG_ERROR, ("\tRequest Value=0x%04x!\n", Value)); - - if ((TransferBuffer!= NULL) && (TransferBufferLength > 0)) - hex_dump("Failed TransferBuffer value", TransferBuffer, TransferBufferLength); - } - } - return ret; -} - -/* - ======================================================================== - - Routine Description: - Creates an IRP to submite an IOCTL_INTERNAL_USB_RESET_PORT - synchronously. Callers of this function must be running at - PASSIVE LEVEL. - - Arguments: - - Return Value: - - Note: - - ======================================================================== -*/ -NTSTATUS RTUSB_ResetDevice( - IN PRTMP_ADAPTER pAd) -{ - NTSTATUS Status = TRUE; - - DBGPRINT_RAW(RT_DEBUG_TRACE, ("--->USB_ResetDevice\n")); - //RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS); - return Status; -} - -VOID CMDHandler( - IN PRTMP_ADAPTER pAd) -{ - PCmdQElmt cmdqelmt; - PUCHAR pData; - NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS; -// ULONG Now = 0; - NTSTATUS ntStatus; -// unsigned long IrqFlags; - - while (pAd->CmdQ.size > 0) - { - NdisStatus = NDIS_STATUS_SUCCESS; - - NdisAcquireSpinLock(&pAd->CmdQLock); - RTUSBDequeueCmd(&pAd->CmdQ, &cmdqelmt); - NdisReleaseSpinLock(&pAd->CmdQLock); - - if (cmdqelmt == NULL) - break; - - pData = cmdqelmt->buffer; - - if(!(RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST) || RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS))) - { - switch (cmdqelmt->command) - { - case CMDTHREAD_CHECK_GPIO: - { -#ifdef CONFIG_STA_SUPPORT - UINT32 data; -#endif // CONFIG_STA_SUPPORT // -#ifdef RALINK_ATE - if(ATE_ON(pAd)) - { - DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now\n")); - break; - } -#endif // RALINK_ATE // - -#ifdef CONFIG_STA_SUPPORT - - - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - // Read GPIO pin2 as Hardware controlled radio state - - RTUSBReadMACRegister( pAd, GPIO_CTRL_CFG, &data); - - if (data & 0x04) - { - pAd->StaCfg.bHwRadio = TRUE; - } - else - { - pAd->StaCfg.bHwRadio = FALSE; - } - - if(pAd->StaCfg.bRadio != (pAd->StaCfg.bHwRadio && pAd->StaCfg.bSwRadio)) - { - pAd->StaCfg.bRadio = (pAd->StaCfg.bHwRadio && pAd->StaCfg.bSwRadio); - if(pAd->StaCfg.bRadio == TRUE) - { - DBGPRINT_RAW(RT_DEBUG_ERROR, ("!!! Radio On !!!\n")); - - MlmeRadioOn(pAd); - // Update extra information - pAd->ExtraInfo = EXTRA_INFO_CLEAR; - } - else - { - DBGPRINT_RAW(RT_DEBUG_ERROR, ("!!! Radio Off !!!\n")); - - MlmeRadioOff(pAd); - // Update extra information - pAd->ExtraInfo = HW_RADIO_OFF; - } - } - } -#endif // CONFIG_STA_SUPPORT // - } - break; - -#ifdef CONFIG_STA_SUPPORT - case CMDTHREAD_QKERIODIC_EXECUT: - { - StaQuickResponeForRateUpExec(NULL, pAd, NULL, NULL); - } - break; -#endif // CONFIG_STA_SUPPORT // - - case CMDTHREAD_RESET_BULK_OUT: - { - UINT32 MACValue; - UCHAR Index; - int ret=0; - PHT_TX_CONTEXT pHTTXContext; -// RTMP_TX_RING *pTxRing; - unsigned long IrqFlags; -#ifdef RALINK_ATE - PTX_CONTEXT pNullContext = &(pAd->NullContext); -#endif // RALINK_ATE // - DBGPRINT_RAW(RT_DEBUG_TRACE, ("CmdThread : CMDTHREAD_RESET_BULK_OUT(ResetPipeid=0x%0x)===>\n", pAd->bulkResetPipeid)); - // All transfers must be aborted or cancelled before attempting to reset the pipe. - //RTUSBCancelPendingBulkOutIRP(pAd); - // Wait 10ms to let previous packet that are already in HW FIFO to clear. by MAXLEE 12-25-2007 - Index = 0; - do - { - RTUSBReadMACRegister(pAd, TXRXQ_PCNT, &MACValue); - if ((MACValue & 0xf00000/*0x800000*/) == 0) - break; - Index++; - RTMPusecDelay(10000); - }while(Index < 100); - MACValue = 0; - RTUSBReadMACRegister(pAd, USB_DMA_CFG, &MACValue); - // To prevent Read Register error, we 2nd check the validity. - if ((MACValue & 0xc00000) == 0) - RTUSBReadMACRegister(pAd, USB_DMA_CFG, &MACValue); - // To prevent Read Register error, we 3rd check the validity. - if ((MACValue & 0xc00000) == 0) - RTUSBReadMACRegister(pAd, USB_DMA_CFG, &MACValue); - MACValue |= 0x80000; - RTUSBWriteMACRegister(pAd, USB_DMA_CFG, MACValue); - - // Wait 1ms to prevent next URB to bulkout before HW reset. by MAXLEE 12-25-2007 - RTMPusecDelay(1000); - - MACValue &= (~0x80000); - RTUSBWriteMACRegister(pAd, USB_DMA_CFG, MACValue); - DBGPRINT_RAW(RT_DEBUG_TRACE, ("\tSet 0x2a0 bit19. Clear USB DMA TX path\n")); - - // Wait 5ms to prevent next URB to bulkout before HW reset. by MAXLEE 12-25-2007 - //RTMPusecDelay(5000); - - if ((pAd->bulkResetPipeid & BULKOUT_MGMT_RESET_FLAG) == BULKOUT_MGMT_RESET_FLAG) - { - RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET); - if (pAd->MgmtRing.TxSwFreeIdx < MGMT_RING_SIZE /* pMLMEContext->bWaitingBulkOut == TRUE */) - { - RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_MLME); - } - RTUSBKickBulkOut(pAd); - - DBGPRINT_RAW(RT_DEBUG_TRACE, ("\tTX MGMT RECOVER Done!\n")); - } - else - { - pHTTXContext = &(pAd->TxContext[pAd->bulkResetPipeid]); - //NdisAcquireSpinLock(&pAd->BulkOutLock[pAd->bulkResetPipeid]); - RTMP_INT_LOCK(&pAd->BulkOutLock[pAd->bulkResetPipeid], IrqFlags); - if ( pAd->BulkOutPending[pAd->bulkResetPipeid] == FALSE) - { - pAd->BulkOutPending[pAd->bulkResetPipeid] = TRUE; - pHTTXContext->IRPPending = TRUE; - pAd->watchDogTxPendingCnt[pAd->bulkResetPipeid] = 1; - - // no matter what, clean the flag - RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET); - - //NdisReleaseSpinLock(&pAd->BulkOutLock[pAd->bulkResetPipeid]); - RTMP_INT_UNLOCK(&pAd->BulkOutLock[pAd->bulkResetPipeid], IrqFlags); -/*-----------------------------------------------------------------------------------------------*/ -#ifdef RALINK_ATE - if(ATE_ON(pAd)) - { - pNullContext->IRPPending = TRUE; - // - // If driver is still in ATE TXFRAME mode, - // keep on transmitting ATE frames. - // - DBGPRINT_RAW(RT_DEBUG_TRACE, ("pAd->ate.Mode == %d\npAd->ContinBulkOut == %d\npAd->BulkOutRemained == %d\n", pAd->ate.Mode, pAd->ContinBulkOut, atomic_read(&pAd->BulkOutRemained))); - if((pAd->ate.Mode == ATE_TXFRAME) && ((pAd->ContinBulkOut == TRUE) || (atomic_read(&pAd->BulkOutRemained) > 0))) - { - DBGPRINT_RAW(RT_DEBUG_TRACE, ("After CMDTHREAD_RESET_BULK_OUT, continue to bulk out frames !\n")); - - // Init Tx context descriptor - RTUSBInitTxDesc(pAd, pNullContext, 0/* pAd->bulkResetPipeid */, (usb_complete_t)ATE_RTUSBBulkOutDataPacketComplete); - - if((ret = RTUSB_SUBMIT_URB(pNullContext->pUrb))!=0) - { - DBGPRINT(RT_DEBUG_ERROR, ("ATE_RTUSBBulkOutDataPacket: Submit Tx URB failed %d\n", ret)); - } - - pAd->BulkOutReq++; - } - } - else -#endif // RALINK_ATE // -/*-----------------------------------------------------------------------------------------------*/ - { - RTUSBInitHTTxDesc(pAd, pHTTXContext, pAd->bulkResetPipeid, pHTTXContext->BulkOutSize, (usb_complete_t)RTUSBBulkOutDataPacketComplete); - - if((ret = RTUSB_SUBMIT_URB(pHTTXContext->pUrb))!=0) - { - RTMP_INT_LOCK(&pAd->BulkOutLock[pAd->bulkResetPipeid], IrqFlags); - pAd->BulkOutPending[pAd->bulkResetPipeid] = FALSE; - pHTTXContext->IRPPending = FALSE; - pAd->watchDogTxPendingCnt[pAd->bulkResetPipeid] = 0; - RTMP_INT_UNLOCK(&pAd->BulkOutLock[pAd->bulkResetPipeid], IrqFlags); - - DBGPRINT(RT_DEBUG_ERROR, ("CmdThread : CMDTHREAD_RESET_BULK_OUT: Submit Tx URB failed %d\n", ret)); - } - else - { - RTMP_IRQ_LOCK(&pAd->BulkOutLock[pAd->bulkResetPipeid], IrqFlags); - DBGPRINT_RAW(RT_DEBUG_TRACE,("\tCMDTHREAD_RESET_BULK_OUT: TxContext[%d]:CWPos=%ld, NBPos=%ld, ENBPos=%ld, bCopy=%d, pending=%d!\n", - pAd->bulkResetPipeid, pHTTXContext->CurWritePosition, pHTTXContext->NextBulkOutPosition, - pHTTXContext->ENextBulkOutPosition, pHTTXContext->bCopySavePad, pAd->BulkOutPending[pAd->bulkResetPipeid])); - DBGPRINT_RAW(RT_DEBUG_TRACE,("\t\tBulkOut Req=0x%lx, Complete=0x%lx, Other=0x%lx\n", - pAd->BulkOutReq, pAd->BulkOutComplete, pAd->BulkOutCompleteOther)); - RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[pAd->bulkResetPipeid], IrqFlags); - DBGPRINT_RAW(RT_DEBUG_TRACE, ("\tCMDTHREAD_RESET_BULK_OUT: Submit Tx DATA URB for failed BulkReq(0x%lx) Done, status=%d!\n", pAd->bulkResetReq[pAd->bulkResetPipeid], pHTTXContext->pUrb->status)); - - } - } - } - else - { - //NdisReleaseSpinLock(&pAd->BulkOutLock[pAd->bulkResetPipeid]); - //RTMP_INT_UNLOCK(&pAd->BulkOutLock[pAd->bulkResetPipeid], IrqFlags); - - DBGPRINT_RAW(RT_DEBUG_ERROR, ("CmdThread : TX DATA RECOVER FAIL for BulkReq(0x%lx) because BulkOutPending[%d] is TRUE!\n", pAd->bulkResetReq[pAd->bulkResetPipeid], pAd->bulkResetPipeid)); - if (pAd->bulkResetPipeid == 0) - { - UCHAR pendingContext = 0; - PHT_TX_CONTEXT pHTTXContext = (PHT_TX_CONTEXT)(&pAd->TxContext[pAd->bulkResetPipeid ]); - PTX_CONTEXT pMLMEContext = (PTX_CONTEXT)(pAd->MgmtRing.Cell[pAd->MgmtRing.TxDmaIdx].AllocVa); - PTX_CONTEXT pNULLContext = (PTX_CONTEXT)(&pAd->PsPollContext); - PTX_CONTEXT pPsPollContext = (PTX_CONTEXT)(&pAd->NullContext); - - if (pHTTXContext->IRPPending) - pendingContext |= 1; - else if (pMLMEContext->IRPPending) - pendingContext |= 2; - else if (pNULLContext->IRPPending) - pendingContext |= 4; - else if (pPsPollContext->IRPPending) - pendingContext |= 8; - else - pendingContext = 0; - - DBGPRINT_RAW(RT_DEBUG_ERROR, ("\tTX Occupied by %d!\n", pendingContext)); - } - - // no matter what, clean the flag - RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET); - - RTMP_INT_UNLOCK(&pAd->BulkOutLock[pAd->bulkResetPipeid], IrqFlags); - - RTUSB_SET_BULK_FLAG(pAd, (fRTUSB_BULK_OUT_DATA_NORMAL << pAd->bulkResetPipeid)); - } - - RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, MAX_TX_PROCESS); - //RTUSBKickBulkOut(pAd); - } - - } - /* - // Don't cancel BULKIN. - while ((atomic_read(&pAd->PendingRx) > 0) && - (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))) - { - if (atomic_read(&pAd->PendingRx) > 0) - { - DBGPRINT_RAW(RT_DEBUG_ERROR, ("BulkIn IRP Pending!!cancel it!\n")); - RTUSBCancelPendingBulkInIRP(pAd); - } - RTMPusecDelay(100000); - } - - if ((atomic_read(&pAd->PendingRx) == 0) && (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS))) - { - UCHAR i; - RTUSBRxPacket(pAd); - pAd->NextRxBulkInReadIndex = 0; // Next Rx Read index - pAd->NextRxBulkInIndex = 0; // Rx Bulk pointer - for (i = 0; i < (RX_RING_SIZE); i++) - { - PRX_CONTEXT pRxContext = &(pAd->RxContext[i]); - - pRxContext->pAd = pAd; - pRxContext->InUse = FALSE; - pRxContext->IRPPending = FALSE; - pRxContext->Readable = FALSE; - pRxContext->ReorderInUse = FALSE; - - } - RTUSBBulkReceive(pAd); - DBGPRINT_RAW(RT_DEBUG_ERROR, ("RTUSBBulkReceive\n")); - }*/ - DBGPRINT_RAW(RT_DEBUG_TRACE, ("CmdThread : CMDTHREAD_RESET_BULK_OUT<===\n")); - break; - - case CMDTHREAD_RESET_BULK_IN: - DBGPRINT_RAW(RT_DEBUG_TRACE, ("CmdThread : CMDTHREAD_RESET_BULK_IN === >\n")); - - // All transfers must be aborted or cancelled before attempting to reset the pipe. - { - UINT32 MACValue; -/*-----------------------------------------------------------------------------------------------*/ -#ifdef RALINK_ATE - if (ATE_ON(pAd)) - { - if((pAd->PendingRx > 0) && (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))) - { - DBGPRINT_RAW(RT_DEBUG_ERROR, ("ATE : BulkIn IRP Pending!!!\n")); - ATE_RTUSBCancelPendingBulkInIRP(pAd); - RTMPusecDelay(100000); - pAd->PendingRx = 0; - } - } - else -#endif // RALINK_ATE // -/*-----------------------------------------------------------------------------------------------*/ - { - //while ((atomic_read(&pAd->PendingRx) > 0) && (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))) - if((pAd->PendingRx > 0) && (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))) - { - DBGPRINT_RAW(RT_DEBUG_ERROR, ("BulkIn IRP Pending!!!\n")); - RTUSBCancelPendingBulkInIRP(pAd); - RTMPusecDelay(100000); - pAd->PendingRx = 0; - } - } - - // Wait 10ms before reading register. - RTMPusecDelay(10000); - ntStatus = RTUSBReadMACRegister(pAd, MAC_CSR0, &MACValue); - - if ((NT_SUCCESS(ntStatus) == TRUE) && - (!(RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_RESET_IN_PROGRESS | fRTMP_ADAPTER_RADIO_OFF | - fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST))))) - { - UCHAR i; - - if (RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_RESET_IN_PROGRESS | fRTMP_ADAPTER_RADIO_OFF | - fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST))) - break; - pAd->NextRxBulkInPosition = pAd->RxContext[pAd->NextRxBulkInIndex].BulkInOffset; - DBGPRINT(RT_DEBUG_TRACE, ("BULK_IN_RESET: NBIIdx=0x%x,NBIRIdx=0x%x, BIRPos=0x%lx. BIReq=x%lx, BIComplete=0x%lx, BICFail0x%lx\n", - pAd->NextRxBulkInIndex, pAd->NextRxBulkInReadIndex, pAd->NextRxBulkInPosition, pAd->BulkInReq, pAd->BulkInComplete, pAd->BulkInCompleteFail)); - for (i = 0; i < RX_RING_SIZE; i++) - { - DBGPRINT(RT_DEBUG_TRACE, ("\tRxContext[%d]: IRPPending=%d, InUse=%d, Readable=%d!\n" - , i, pAd->RxContext[i].IRPPending, pAd->RxContext[i].InUse, pAd->RxContext[i].Readable)); - } - /* - - DBGPRINT_RAW(RT_DEBUG_ERROR, ("==========================================\n")); - - pAd->NextRxBulkInReadIndex = 0; // Next Rx Read index - pAd->NextRxBulkInIndex = 0; // Rx Bulk pointer - for (i = 0; i < (RX_RING_SIZE); i++) - { - PRX_CONTEXT pRxContext = &(pAd->RxContext[i]); - - pRxContext->pAd = pAd; - pRxContext->InUse = FALSE; - pRxContext->IRPPending = FALSE; - pRxContext->Readable = FALSE; - pRxContext->ReorderInUse = FALSE; - - }*/ - RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BULKIN_RESET); - for (i = 0; i < pAd->CommonCfg.NumOfBulkInIRP; i++) - { - //RTUSBBulkReceive(pAd); - PRX_CONTEXT pRxContext; - PURB pUrb; - int ret = 0; - unsigned long IrqFlags; - - - RTMP_IRQ_LOCK(&pAd->BulkInLock, IrqFlags); - pRxContext = &(pAd->RxContext[pAd->NextRxBulkInIndex]); - if ((pAd->PendingRx > 0) || (pRxContext->Readable == TRUE) || (pRxContext->InUse == TRUE)) - { - RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); - break; - } - pRxContext->InUse = TRUE; - pRxContext->IRPPending = TRUE; - pAd->PendingRx++; - pAd->BulkInReq++; - RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); - - // Init Rx context descriptor - RTUSBInitRxDesc(pAd, pRxContext); - pUrb = pRxContext->pUrb; - if ((ret = RTUSB_SUBMIT_URB(pUrb))!=0) - { // fail - - RTMP_IRQ_LOCK(&pAd->BulkInLock, IrqFlags); - pRxContext->InUse = FALSE; - pRxContext->IRPPending = FALSE; - pAd->PendingRx--; - pAd->BulkInReq--; - RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); - DBGPRINT(RT_DEBUG_ERROR, ("CMDTHREAD_RESET_BULK_IN: Submit Rx URB failed(%d), status=%d\n", ret, pUrb->status)); - } - else - { // success - DBGPRINT_RAW(RT_DEBUG_TRACE, ("CMDTHREAD_RESET_BULK_IN: Submit Rx URB Done, status=%d!\n", pUrb->status)); - ASSERT((pRxContext->InUse == pRxContext->IRPPending)); - } - } - - } - else - { - // Card must be removed - if (NT_SUCCESS(ntStatus) != TRUE) - { - RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST); - DBGPRINT_RAW(RT_DEBUG_ERROR, ("CMDTHREAD_RESET_BULK_IN: Read Register Failed!Card must be removed!!\n\n")); - } - else - { - DBGPRINT_RAW(RT_DEBUG_ERROR, ("CMDTHREAD_RESET_BULK_IN: Cannot do bulk in because flags(0x%lx) on !\n", pAd->Flags)); - } - } - } - DBGPRINT_RAW(RT_DEBUG_TRACE, ("CmdThread : CMDTHREAD_RESET_BULK_IN <===\n")); - break; - - case CMDTHREAD_SET_ASIC_WCID: - { - RT_SET_ASIC_WCID SetAsicWcid; - USHORT offset; - UINT32 MACValue, MACRValue = 0; - SetAsicWcid = *((PRT_SET_ASIC_WCID)(pData)); - - if (SetAsicWcid.WCID >= MAX_LEN_OF_MAC_TABLE) - return; - - offset = MAC_WCID_BASE + ((UCHAR)SetAsicWcid.WCID)*HW_WCID_ENTRY_SIZE; - - DBGPRINT_RAW(RT_DEBUG_TRACE, ("CmdThread : CMDTHREAD_SET_ASIC_WCID : WCID = %ld, SetTid = %lx, DeleteTid = %lx.\n", SetAsicWcid.WCID, SetAsicWcid.SetTid, SetAsicWcid.DeleteTid)); - MACValue = (pAd->MacTab.Content[SetAsicWcid.WCID].Addr[3]<<24)+(pAd->MacTab.Content[SetAsicWcid.WCID].Addr[2]<<16)+(pAd->MacTab.Content[SetAsicWcid.WCID].Addr[1]<<8)+(pAd->MacTab.Content[SetAsicWcid.WCID].Addr[0]); - DBGPRINT_RAW(RT_DEBUG_TRACE, ("1-MACValue= %x,\n", MACValue)); - RTUSBWriteMACRegister(pAd, offset, MACValue); - // Read bitmask - RTUSBReadMACRegister(pAd, offset+4, &MACRValue); - if ( SetAsicWcid.DeleteTid != 0xffffffff) - MACRValue &= (~SetAsicWcid.DeleteTid); - if (SetAsicWcid.SetTid != 0xffffffff) - MACRValue |= (SetAsicWcid.SetTid); - MACRValue &= 0xffff0000; - - MACValue = (pAd->MacTab.Content[SetAsicWcid.WCID].Addr[5]<<8)+pAd->MacTab.Content[SetAsicWcid.WCID].Addr[4]; - MACValue |= MACRValue; - RTUSBWriteMACRegister(pAd, offset+4, MACValue); - - DBGPRINT_RAW(RT_DEBUG_TRACE, ("2-MACValue= %x,\n", MACValue)); - } - break; - - case CMDTHREAD_SET_ASIC_WCID_CIPHER: - { -#ifdef CONFIG_STA_SUPPORT - RT_SET_ASIC_WCID_ATTRI SetAsicWcidAttri; - USHORT offset; - UINT32 MACRValue = 0; - SHAREDKEY_MODE_STRUC csr1; - SetAsicWcidAttri = *((PRT_SET_ASIC_WCID_ATTRI)(pData)); - - if (SetAsicWcidAttri.WCID >= MAX_LEN_OF_MAC_TABLE) - return; - - offset = MAC_WCID_ATTRIBUTE_BASE + ((UCHAR)SetAsicWcidAttri.WCID)*HW_WCID_ATTRI_SIZE; - - DBGPRINT_RAW(RT_DEBUG_TRACE, ("Cmd : CMDTHREAD_SET_ASIC_WCID_CIPHER : WCID = %ld, Cipher = %lx.\n", SetAsicWcidAttri.WCID, SetAsicWcidAttri.Cipher)); - // Read bitmask - RTUSBReadMACRegister(pAd, offset, &MACRValue); - MACRValue = 0; - MACRValue |= (((UCHAR)SetAsicWcidAttri.Cipher) << 1); - - RTUSBWriteMACRegister(pAd, offset, MACRValue); - DBGPRINT_RAW(RT_DEBUG_TRACE, ("2-offset = %x , MACValue= %x,\n", offset, MACRValue)); - - offset = PAIRWISE_IVEIV_TABLE_BASE + ((UCHAR)SetAsicWcidAttri.WCID)*HW_IVEIV_ENTRY_SIZE; - MACRValue = 0; - if ( (SetAsicWcidAttri.Cipher <= CIPHER_WEP128)) - MACRValue |= ( pAd->StaCfg.DefaultKeyId << 30); - else - MACRValue |= (0x20000000); - RTUSBWriteMACRegister(pAd, offset, MACRValue); - DBGPRINT_RAW(RT_DEBUG_TRACE, ("2-offset = %x , MACValue= %x,\n", offset, MACRValue)); - - // - // Update cipher algorithm. WSTA always use BSS0 - // - // for adhoc mode only ,because wep status slow than add key, when use zero config - if (pAd->StaCfg.BssType == BSS_ADHOC ) - { - offset = MAC_WCID_ATTRIBUTE_BASE; - - RTUSBReadMACRegister(pAd, offset, &MACRValue); - MACRValue &= (~0xe); - MACRValue |= (((UCHAR)SetAsicWcidAttri.Cipher) << 1); - - RTUSBWriteMACRegister(pAd, offset, MACRValue); - - //Update group key cipher,,because wep status slow than add key, when use zero config - RTUSBReadMACRegister(pAd, SHARED_KEY_MODE_BASE+4*(0/2), &csr1.word); - - csr1.field.Bss0Key0CipherAlg = SetAsicWcidAttri.Cipher; - csr1.field.Bss0Key1CipherAlg = SetAsicWcidAttri.Cipher; - - RTUSBWriteMACRegister(pAd, SHARED_KEY_MODE_BASE+4*(0/2), csr1.word); - } -#endif // CONFIG_STA_SUPPORT // - } - break; - -//Benson modified for USB interface, avoid in interrupt when write key, 20080724 --> - case RT_CMD_SET_KEY_TABLE: //General call for AsicAddPairwiseKeyEntry() - { - RT_ADD_PAIRWISE_KEY_ENTRY KeyInfo; - KeyInfo = *((PRT_ADD_PAIRWISE_KEY_ENTRY)(pData)); - AsicAddPairwiseKeyEntry(pAd, - KeyInfo.MacAddr, - (UCHAR)KeyInfo.MacTabMatchWCID, - &KeyInfo.CipherKey); - } - break; - case RT_CMD_SET_RX_WCID_TABLE: //General call for RTMPAddWcidAttributeEntry() - { - PMAC_TABLE_ENTRY pEntry; - UCHAR KeyIdx; - UCHAR CipherAlg; - UCHAR ApIdx; - - pEntry = (PMAC_TABLE_ENTRY)(pData); - -#ifdef CONFIG_STA_SUPPORT -#ifdef QOS_DLS_SUPPORT - KeyIdx = 0; - CipherAlg = pEntry->PairwiseKey.CipherAlg; - ApIdx = BSS0; -#endif // QOS_DLS_SUPPORT // -#endif // CONFIG_STA_SUPPORT // - - - RTMPAddWcidAttributeEntry( - pAd, - ApIdx, - KeyIdx, - CipherAlg, - pEntry); - } - break; -//Benson modified for USB interface, avoid in interrupt when write key, 20080724 <-- - - case CMDTHREAD_SET_CLIENT_MAC_ENTRY: - { - MAC_TABLE_ENTRY *pEntry; - pEntry = (MAC_TABLE_ENTRY *)pData; - - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - AsicRemovePairwiseKeyEntry(pAd, pEntry->apidx, (UCHAR)pEntry->Aid); - if ((pEntry->AuthMode <= Ndis802_11AuthModeAutoSwitch) && (pEntry->WepStatus == Ndis802_11Encryption1Enabled)) - { - UINT32 uIV = 0; - PUCHAR ptr; - - ptr = (PUCHAR) &uIV; - *(ptr + 3) = (pAd->StaCfg.DefaultKeyId << 6); - AsicUpdateWCIDIVEIV(pAd, pEntry->Aid, uIV, 0); - AsicUpdateWCIDAttribute(pAd, pEntry->Aid, BSS0, pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, FALSE); - } - else if (pEntry->AuthMode == Ndis802_11AuthModeWPANone) - { - UINT32 uIV = 0; - PUCHAR ptr; - - ptr = (PUCHAR) &uIV; - *(ptr + 3) = (pAd->StaCfg.DefaultKeyId << 6); - AsicUpdateWCIDIVEIV(pAd, pEntry->Aid, uIV, 0); - AsicUpdateWCIDAttribute(pAd, pEntry->Aid, BSS0, pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, FALSE); - } - else - { - // - // Other case, disable engine. - // Don't worry WPA key, we will add WPA Key after 4-Way handshaking. - // - USHORT offset; - offset = MAC_WCID_ATTRIBUTE_BASE + (pEntry->Aid * HW_WCID_ATTRI_SIZE); - // RX_PKEY_MODE:0 for no security; RX_KEY_TAB:0 for shared key table; BSS_IDX:0 - RTUSBWriteMACRegister(pAd, offset, 0); - } - } -#endif // CONFIG_STA_SUPPORT // - - AsicUpdateRxWCIDTable(pAd, pEntry->Aid, pEntry->Addr); - printk("UpdateRxWCIDTable(): Aid=%d, Addr=%02x:%02x:%02x:%02x:%02x:%02x!\n", pEntry->Aid, - pEntry->Addr[0], pEntry->Addr[1], pEntry->Addr[2], pEntry->Addr[3], pEntry->Addr[4], pEntry->Addr[5]); - } - break; - -// add by johnli, fix "in_interrupt" error when call "MacTableDeleteEntry" in Rx tasklet - case CMDTHREAD_UPDATE_PROTECT: - { - AsicUpdateProtect(pAd, 0, (ALLN_SETPROTECT), TRUE, 0); - } - break; -// end johnli - - case OID_802_11_ADD_WEP: - { -#ifdef CONFIG_STA_SUPPORT - UINT i; - UINT32 KeyIdx; - PNDIS_802_11_WEP pWepKey; - - DBGPRINT(RT_DEBUG_TRACE, ("CmdThread::OID_802_11_ADD_WEP \n")); - - pWepKey = (PNDIS_802_11_WEP)pData; - KeyIdx = pWepKey->KeyIndex & 0x0fffffff; - - // it is a shared key - if ((KeyIdx >= 4) || ((pWepKey->KeyLength != 5) && (pWepKey->KeyLength != 13))) - { - NdisStatus = NDIS_STATUS_INVALID_DATA; - DBGPRINT(RT_DEBUG_ERROR, ("CmdThread::OID_802_11_ADD_WEP, INVALID_DATA!!\n")); - } - else - { - UCHAR CipherAlg; - pAd->SharedKey[BSS0][KeyIdx].KeyLen = (UCHAR) pWepKey->KeyLength; - NdisMoveMemory(pAd->SharedKey[BSS0][KeyIdx].Key, &pWepKey->KeyMaterial, pWepKey->KeyLength); - CipherAlg = (pAd->SharedKey[BSS0][KeyIdx].KeyLen == 5)? CIPHER_WEP64 : CIPHER_WEP128; - - // - // Change the WEP cipher to CKIP cipher if CKIP KP on. - // Funk UI or Meetinghouse UI will add ckip key from this path. - // - - if (pAd->OpMode == OPMODE_STA) - { - pAd->MacTab.Content[BSSID_WCID].PairwiseKey.CipherAlg = pAd->SharedKey[BSS0][KeyIdx].CipherAlg; - pAd->MacTab.Content[BSSID_WCID].PairwiseKey.KeyLen = pAd->SharedKey[BSS0][KeyIdx].KeyLen; - } - pAd->SharedKey[BSS0][KeyIdx].CipherAlg = CipherAlg; - if (pWepKey->KeyIndex & 0x80000000) - { - // Default key for tx (shared key) - UCHAR IVEIV[8]; - UINT32 WCIDAttri, Value; - USHORT offset, offset2; - NdisZeroMemory(IVEIV, 8); - pAd->StaCfg.DefaultKeyId = (UCHAR) KeyIdx; - // Add BSSID to WCTable. because this is Tx wep key. - // WCID Attribute UDF:3, BSSIdx:3, Alg:3, Keytable:1=PAIRWISE KEY, BSSIdx is 0 - WCIDAttri = (CipherAlg<<1)|SHAREDKEYTABLE; - - offset = MAC_WCID_ATTRIBUTE_BASE + (BSSID_WCID* HW_WCID_ATTRI_SIZE); - RTUSBWriteMACRegister(pAd, offset, WCIDAttri); - // 1. IV/EIV - // Specify key index to find shared key. - IVEIV[3] = (UCHAR)(KeyIdx<< 6); //WEP Eiv bit off. groupkey index is not 0 - offset = PAIRWISE_IVEIV_TABLE_BASE + (BSS0Mcast_WCID * HW_IVEIV_ENTRY_SIZE); - offset2 = PAIRWISE_IVEIV_TABLE_BASE + (BSSID_WCID* HW_IVEIV_ENTRY_SIZE); - for (i=0; i<8;) - { - Value = IVEIV[i]; - Value += (IVEIV[i+1]<<8); - Value += (IVEIV[i+2]<<16); - Value += (IVEIV[i+3]<<24); - RTUSBWriteMACRegister(pAd, offset+i, Value); - RTUSBWriteMACRegister(pAd, offset2+i, Value); - i+=4; - } - - // 2. WCID Attribute UDF:3, BSSIdx:3, Alg:3, Keytable:use share key, BSSIdx is 0 - WCIDAttri = (pAd->SharedKey[BSS0][KeyIdx].CipherAlg<<1)|SHAREDKEYTABLE; - offset = MAC_WCID_ATTRIBUTE_BASE + (BSS0Mcast_WCID* HW_WCID_ATTRI_SIZE); - DBGPRINT(RT_DEBUG_TRACE, ("BSS0Mcast_WCID : offset = %x, WCIDAttri = %x\n", offset, WCIDAttri)); - RTUSBWriteMACRegister(pAd, offset, WCIDAttri); - - } - AsicAddSharedKeyEntry(pAd, BSS0, (UCHAR)KeyIdx, CipherAlg, pWepKey->KeyMaterial, NULL, NULL); - DBGPRINT(RT_DEBUG_TRACE, ("CmdThread::OID_802_11_ADD_WEP (KeyIdx=%d, Len=%d-byte)\n", KeyIdx, pWepKey->KeyLength)); - } -#endif // CONFIG_STA_SUPPORT // - } - break; - - case CMDTHREAD_802_11_COUNTER_MEASURE: - break; - - default: - DBGPRINT(RT_DEBUG_ERROR, ("--> Control Thread !! ERROR !! Unknown(cmdqelmt->command=0x%x) !! \n", cmdqelmt->command)); - break; - } - } - - if (cmdqelmt->CmdFromNdis == TRUE) - { - if (cmdqelmt->buffer != NULL) - NdisFreeMemory(cmdqelmt->buffer, cmdqelmt->bufferlength, 0); - - NdisFreeMemory(cmdqelmt, sizeof(CmdQElmt), 0); - } - else - { - if ((cmdqelmt->buffer != NULL) && (cmdqelmt->bufferlength != 0)) - NdisFreeMemory(cmdqelmt->buffer, cmdqelmt->bufferlength, 0); - { - NdisFreeMemory(cmdqelmt, sizeof(CmdQElmt), 0); - } - } - } /* end of while */ -} - +#include "../../rt2870/common/rtusb_io.c" diff --git a/drivers/staging/rt3070/common/spectrum.c b/drivers/staging/rt3070/common/spectrum.c index da57b1202d64..de3b949e52fb 100644 --- a/drivers/staging/rt3070/common/spectrum.c +++ b/drivers/staging/rt3070/common/spectrum.c @@ -1,1876 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - action.c - - Abstract: - Handle association related requests either from WSTA or from local MLME - - Revision History: - Who When What - --------- ---------- ---------------------------------------------- - Fonchi Wu 2008 created for 802.11h - */ - -#include "../rt_config.h" -#include "../action.h" - -VOID MeasureReqTabInit( - IN PRTMP_ADAPTER pAd) -{ - NdisAllocateSpinLock(&pAd->CommonCfg.MeasureReqTabLock); - - pAd->CommonCfg.pMeasureReqTab = kmalloc(sizeof(MEASURE_REQ_TAB), GFP_ATOMIC); - if (pAd->CommonCfg.pMeasureReqTab) - NdisZeroMemory(pAd->CommonCfg.pMeasureReqTab, sizeof(MEASURE_REQ_TAB)); - else - DBGPRINT(RT_DEBUG_ERROR, ("%s Fail to alloc memory for pAd->CommonCfg.pMeasureReqTab.\n", __FUNCTION__)); - - return; -} - -VOID MeasureReqTabExit( - IN PRTMP_ADAPTER pAd) -{ - NdisFreeSpinLock(pAd->CommonCfg.MeasureReqTabLock); - - if (pAd->CommonCfg.pMeasureReqTab) - kfree(pAd->CommonCfg.pMeasureReqTab); - pAd->CommonCfg.pMeasureReqTab = NULL; - - return; -} - -static PMEASURE_REQ_ENTRY MeasureReqLookUp( - IN PRTMP_ADAPTER pAd, - IN UINT8 DialogToken) -{ - UINT HashIdx; - PMEASURE_REQ_TAB pTab = pAd->CommonCfg.pMeasureReqTab; - PMEASURE_REQ_ENTRY pEntry = NULL; - PMEASURE_REQ_ENTRY pPrevEntry = NULL; - - if (pTab == NULL) - { - DBGPRINT(RT_DEBUG_ERROR, ("%s: pMeasureReqTab doesn't exist.\n", __FUNCTION__)); - return NULL; - } - - RTMP_SEM_LOCK(&pAd->CommonCfg.MeasureReqTabLock); - - HashIdx = MQ_DIALOGTOKEN_HASH_INDEX(DialogToken); - pEntry = pTab->Hash[HashIdx]; - - while (pEntry) - { - if (pEntry->DialogToken == DialogToken) - break; - else - { - pPrevEntry = pEntry; - pEntry = pEntry->pNext; - } - } - - RTMP_SEM_UNLOCK(&pAd->CommonCfg.MeasureReqTabLock); - - return pEntry; -} - -static PMEASURE_REQ_ENTRY MeasureReqInsert( - IN PRTMP_ADAPTER pAd, - IN UINT8 DialogToken) -{ - INT i; - ULONG HashIdx; - PMEASURE_REQ_TAB pTab = pAd->CommonCfg.pMeasureReqTab; - PMEASURE_REQ_ENTRY pEntry = NULL, pCurrEntry; - ULONG Now; - - if(pTab == NULL) - { - DBGPRINT(RT_DEBUG_ERROR, ("%s: pMeasureReqTab doesn't exist.\n", __FUNCTION__)); - return NULL; - } - - pEntry = MeasureReqLookUp(pAd, DialogToken); - if (pEntry == NULL) - { - RTMP_SEM_LOCK(&pAd->CommonCfg.MeasureReqTabLock); - for (i = 0; i < MAX_MEASURE_REQ_TAB_SIZE; i++) - { - NdisGetSystemUpTime(&Now); - pEntry = &pTab->Content[i]; - - if ((pEntry->Valid == TRUE) - && RTMP_TIME_AFTER((unsigned long)Now, (unsigned long)(pEntry->lastTime + MQ_REQ_AGE_OUT))) - { - PMEASURE_REQ_ENTRY pPrevEntry = NULL; - ULONG HashIdx = MQ_DIALOGTOKEN_HASH_INDEX(pEntry->DialogToken); - PMEASURE_REQ_ENTRY pProbeEntry = pTab->Hash[HashIdx]; - - // update Hash list - do - { - if (pProbeEntry == pEntry) - { - if (pPrevEntry == NULL) - { - pTab->Hash[HashIdx] = pEntry->pNext; - } - else - { - pPrevEntry->pNext = pEntry->pNext; - } - break; - } - - pPrevEntry = pProbeEntry; - pProbeEntry = pProbeEntry->pNext; - } while (pProbeEntry); - - NdisZeroMemory(pEntry, sizeof(MEASURE_REQ_ENTRY)); - pTab->Size--; - - break; - } - - if (pEntry->Valid == FALSE) - break; - } - - if (i < MAX_MEASURE_REQ_TAB_SIZE) - { - NdisGetSystemUpTime(&Now); - pEntry->lastTime = Now; - pEntry->Valid = TRUE; - pEntry->DialogToken = DialogToken; - pTab->Size++; - } - else - { - pEntry = NULL; - DBGPRINT(RT_DEBUG_ERROR, ("%s: pMeasureReqTab tab full.\n", __FUNCTION__)); - } - - // add this Neighbor entry into HASH table - if (pEntry) - { - HashIdx = MQ_DIALOGTOKEN_HASH_INDEX(DialogToken); - if (pTab->Hash[HashIdx] == NULL) - { - pTab->Hash[HashIdx] = pEntry; - } - else - { - pCurrEntry = pTab->Hash[HashIdx]; - while (pCurrEntry->pNext != NULL) - pCurrEntry = pCurrEntry->pNext; - pCurrEntry->pNext = pEntry; - } - } - - RTMP_SEM_UNLOCK(&pAd->CommonCfg.MeasureReqTabLock); - } - - return pEntry; -} - -static VOID MeasureReqDelete( - IN PRTMP_ADAPTER pAd, - IN UINT8 DialogToken) -{ - PMEASURE_REQ_TAB pTab = pAd->CommonCfg.pMeasureReqTab; - PMEASURE_REQ_ENTRY pEntry = NULL; - - if(pTab == NULL) - { - DBGPRINT(RT_DEBUG_ERROR, ("%s: pMeasureReqTab doesn't exist.\n", __FUNCTION__)); - return; - } - - // if empty, return - if (pTab->Size == 0) - { - DBGPRINT(RT_DEBUG_ERROR, ("pMeasureReqTab empty.\n")); - return; - } - - pEntry = MeasureReqLookUp(pAd, DialogToken); - if (pEntry != NULL) - { - PMEASURE_REQ_ENTRY pPrevEntry = NULL; - ULONG HashIdx = MQ_DIALOGTOKEN_HASH_INDEX(pEntry->DialogToken); - PMEASURE_REQ_ENTRY pProbeEntry = pTab->Hash[HashIdx]; - - RTMP_SEM_LOCK(&pAd->CommonCfg.MeasureReqTabLock); - // update Hash list - do - { - if (pProbeEntry == pEntry) - { - if (pPrevEntry == NULL) - { - pTab->Hash[HashIdx] = pEntry->pNext; - } - else - { - pPrevEntry->pNext = pEntry->pNext; - } - break; - } - - pPrevEntry = pProbeEntry; - pProbeEntry = pProbeEntry->pNext; - } while (pProbeEntry); - - NdisZeroMemory(pEntry, sizeof(MEASURE_REQ_ENTRY)); - pTab->Size--; - - RTMP_SEM_UNLOCK(&pAd->CommonCfg.MeasureReqTabLock); - } - - return; -} - -VOID TpcReqTabInit( - IN PRTMP_ADAPTER pAd) -{ - NdisAllocateSpinLock(&pAd->CommonCfg.TpcReqTabLock); - - pAd->CommonCfg.pTpcReqTab = kmalloc(sizeof(TPC_REQ_TAB), GFP_ATOMIC); - if (pAd->CommonCfg.pTpcReqTab) - NdisZeroMemory(pAd->CommonCfg.pTpcReqTab, sizeof(TPC_REQ_TAB)); - else - DBGPRINT(RT_DEBUG_ERROR, ("%s Fail to alloc memory for pAd->CommonCfg.pTpcReqTab.\n", __FUNCTION__)); - - return; -} - -VOID TpcReqTabExit( - IN PRTMP_ADAPTER pAd) -{ - NdisFreeSpinLock(pAd->CommonCfg.TpcReqTabLock); - - if (pAd->CommonCfg.pTpcReqTab) - kfree(pAd->CommonCfg.pTpcReqTab); - pAd->CommonCfg.pTpcReqTab = NULL; - - return; -} - -static PTPC_REQ_ENTRY TpcReqLookUp( - IN PRTMP_ADAPTER pAd, - IN UINT8 DialogToken) -{ - UINT HashIdx; - PTPC_REQ_TAB pTab = pAd->CommonCfg.pTpcReqTab; - PTPC_REQ_ENTRY pEntry = NULL; - PTPC_REQ_ENTRY pPrevEntry = NULL; - - if (pTab == NULL) - { - DBGPRINT(RT_DEBUG_ERROR, ("%s: pTpcReqTab doesn't exist.\n", __FUNCTION__)); - return NULL; - } - - RTMP_SEM_LOCK(&pAd->CommonCfg.TpcReqTabLock); - - HashIdx = TPC_DIALOGTOKEN_HASH_INDEX(DialogToken); - pEntry = pTab->Hash[HashIdx]; - - while (pEntry) - { - if (pEntry->DialogToken == DialogToken) - break; - else - { - pPrevEntry = pEntry; - pEntry = pEntry->pNext; - } - } - - RTMP_SEM_UNLOCK(&pAd->CommonCfg.TpcReqTabLock); - - return pEntry; -} - - -static PTPC_REQ_ENTRY TpcReqInsert( - IN PRTMP_ADAPTER pAd, - IN UINT8 DialogToken) -{ - INT i; - ULONG HashIdx; - PTPC_REQ_TAB pTab = pAd->CommonCfg.pTpcReqTab; - PTPC_REQ_ENTRY pEntry = NULL, pCurrEntry; - ULONG Now; - - if(pTab == NULL) - { - DBGPRINT(RT_DEBUG_ERROR, ("%s: pTpcReqTab doesn't exist.\n", __FUNCTION__)); - return NULL; - } - - pEntry = TpcReqLookUp(pAd, DialogToken); - if (pEntry == NULL) - { - RTMP_SEM_LOCK(&pAd->CommonCfg.TpcReqTabLock); - for (i = 0; i < MAX_TPC_REQ_TAB_SIZE; i++) - { - NdisGetSystemUpTime(&Now); - pEntry = &pTab->Content[i]; - - if ((pEntry->Valid == TRUE) - && RTMP_TIME_AFTER((unsigned long)Now, (unsigned long)(pEntry->lastTime + TPC_REQ_AGE_OUT))) - { - PTPC_REQ_ENTRY pPrevEntry = NULL; - ULONG HashIdx = TPC_DIALOGTOKEN_HASH_INDEX(pEntry->DialogToken); - PTPC_REQ_ENTRY pProbeEntry = pTab->Hash[HashIdx]; - - // update Hash list - do - { - if (pProbeEntry == pEntry) - { - if (pPrevEntry == NULL) - { - pTab->Hash[HashIdx] = pEntry->pNext; - } - else - { - pPrevEntry->pNext = pEntry->pNext; - } - break; - } - - pPrevEntry = pProbeEntry; - pProbeEntry = pProbeEntry->pNext; - } while (pProbeEntry); - - NdisZeroMemory(pEntry, sizeof(TPC_REQ_ENTRY)); - pTab->Size--; - - break; - } - - if (pEntry->Valid == FALSE) - break; - } - - if (i < MAX_TPC_REQ_TAB_SIZE) - { - NdisGetSystemUpTime(&Now); - pEntry->lastTime = Now; - pEntry->Valid = TRUE; - pEntry->DialogToken = DialogToken; - pTab->Size++; - } - else - { - pEntry = NULL; - DBGPRINT(RT_DEBUG_ERROR, ("%s: pTpcReqTab tab full.\n", __FUNCTION__)); - } - - // add this Neighbor entry into HASH table - if (pEntry) - { - HashIdx = TPC_DIALOGTOKEN_HASH_INDEX(DialogToken); - if (pTab->Hash[HashIdx] == NULL) - { - pTab->Hash[HashIdx] = pEntry; - } - else - { - pCurrEntry = pTab->Hash[HashIdx]; - while (pCurrEntry->pNext != NULL) - pCurrEntry = pCurrEntry->pNext; - pCurrEntry->pNext = pEntry; - } - } - - RTMP_SEM_UNLOCK(&pAd->CommonCfg.TpcReqTabLock); - } - - return pEntry; -} - -static VOID TpcReqDelete( - IN PRTMP_ADAPTER pAd, - IN UINT8 DialogToken) -{ - PTPC_REQ_TAB pTab = pAd->CommonCfg.pTpcReqTab; - PTPC_REQ_ENTRY pEntry = NULL; - - if(pTab == NULL) - { - DBGPRINT(RT_DEBUG_ERROR, ("%s: pTpcReqTab doesn't exist.\n", __FUNCTION__)); - return; - } - - // if empty, return - if (pTab->Size == 0) - { - DBGPRINT(RT_DEBUG_ERROR, ("pTpcReqTab empty.\n")); - return; - } - - pEntry = TpcReqLookUp(pAd, DialogToken); - if (pEntry != NULL) - { - PTPC_REQ_ENTRY pPrevEntry = NULL; - ULONG HashIdx = TPC_DIALOGTOKEN_HASH_INDEX(pEntry->DialogToken); - PTPC_REQ_ENTRY pProbeEntry = pTab->Hash[HashIdx]; - - RTMP_SEM_LOCK(&pAd->CommonCfg.TpcReqTabLock); - // update Hash list - do - { - if (pProbeEntry == pEntry) - { - if (pPrevEntry == NULL) - { - pTab->Hash[HashIdx] = pEntry->pNext; - } - else - { - pPrevEntry->pNext = pEntry->pNext; - } - break; - } - - pPrevEntry = pProbeEntry; - pProbeEntry = pProbeEntry->pNext; - } while (pProbeEntry); - - NdisZeroMemory(pEntry, sizeof(TPC_REQ_ENTRY)); - pTab->Size--; - - RTMP_SEM_UNLOCK(&pAd->CommonCfg.TpcReqTabLock); - } - - return; -} - -/* - ========================================================================== - Description: - Get Current TimeS tamp. - - Parametrs: - - Return : Current Time Stamp. - ========================================================================== - */ -static UINT64 GetCurrentTimeStamp( - IN PRTMP_ADAPTER pAd) -{ - // get current time stamp. - return 0; -} - -/* - ========================================================================== - Description: - Get Current Transmit Power. - - Parametrs: - - Return : Current Time Stamp. - ========================================================================== - */ -static UINT8 GetCurTxPwr( - IN PRTMP_ADAPTER pAd, - IN UINT8 Wcid) -{ - return 16; /* 16 dBm */ -} - -/* - ========================================================================== - Description: - Insert Dialog Token into frame. - - Parametrs: - 1. frame buffer pointer. - 2. frame length. - 3. Dialog token. - - Return : None. - ========================================================================== - */ -static VOID InsertDialogToken( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pFrameBuf, - OUT PULONG pFrameLen, - IN UINT8 DialogToken) -{ - ULONG TempLen; - MakeOutgoingFrame(pFrameBuf, &TempLen, - 1, &DialogToken, - END_OF_ARGS); - - *pFrameLen = *pFrameLen + TempLen; - - return; -} - -/* - ========================================================================== - Description: - Insert TPC Request IE into frame. - - Parametrs: - 1. frame buffer pointer. - 2. frame length. - - Return : None. - ========================================================================== - */ - static VOID InsertTpcReqIE( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pFrameBuf, - OUT PULONG pFrameLen) -{ - ULONG TempLen; - ULONG Len = 0; - UINT8 ElementID = IE_TPC_REQUEST; - - MakeOutgoingFrame(pFrameBuf, &TempLen, - 1, &ElementID, - 1, &Len, - END_OF_ARGS); - - *pFrameLen = *pFrameLen + TempLen; - - return; -} - -/* - ========================================================================== - Description: - Insert TPC Report IE into frame. - - Parametrs: - 1. frame buffer pointer. - 2. frame length. - 3. Transmit Power. - 4. Link Margin. - - Return : None. - ========================================================================== - */ - static VOID InsertTpcReportIE( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pFrameBuf, - OUT PULONG pFrameLen, - IN UINT8 TxPwr, - IN UINT8 LinkMargin) -{ - ULONG TempLen; - ULONG Len = sizeof(TPC_REPORT_INFO); - UINT8 ElementID = IE_TPC_REPORT; - TPC_REPORT_INFO TpcReportIE; - - TpcReportIE.TxPwr = TxPwr; - TpcReportIE.LinkMargin = LinkMargin; - - MakeOutgoingFrame(pFrameBuf, &TempLen, - 1, &ElementID, - 1, &Len, - Len, &TpcReportIE, - END_OF_ARGS); - - *pFrameLen = *pFrameLen + TempLen; - - - return; -} - -/* - ========================================================================== - Description: - Insert Channel Switch Announcement IE into frame. - - Parametrs: - 1. frame buffer pointer. - 2. frame length. - 3. channel switch announcement mode. - 4. new selected channel. - 5. channel switch announcement count. - - Return : None. - ========================================================================== - */ -static VOID InsertChSwAnnIE( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pFrameBuf, - OUT PULONG pFrameLen, - IN UINT8 ChSwMode, - IN UINT8 NewChannel, - IN UINT8 ChSwCnt) -{ - ULONG TempLen; - ULONG Len = sizeof(CH_SW_ANN_INFO); - UINT8 ElementID = IE_CHANNEL_SWITCH_ANNOUNCEMENT; - CH_SW_ANN_INFO ChSwAnnIE; - - ChSwAnnIE.ChSwMode = ChSwMode; - ChSwAnnIE.Channel = NewChannel; - ChSwAnnIE.ChSwCnt = ChSwCnt; - - MakeOutgoingFrame(pFrameBuf, &TempLen, - 1, &ElementID, - 1, &Len, - Len, &ChSwAnnIE, - END_OF_ARGS); - - *pFrameLen = *pFrameLen + TempLen; - - - return; -} - -/* - ========================================================================== - Description: - Insert Measure Request IE into frame. - - Parametrs: - 1. frame buffer pointer. - 2. frame length. - 3. Measure Token. - 4. Measure Request Mode. - 5. Measure Request Type. - 6. Measure Channel. - 7. Measure Start time. - 8. Measure Duration. - - - Return : None. - ========================================================================== - */ -static VOID InsertMeasureReqIE( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pFrameBuf, - OUT PULONG pFrameLen, - IN PMEASURE_REQ_INFO pMeasureReqIE) -{ - ULONG TempLen; - UINT8 Len = sizeof(MEASURE_REQ_INFO); - UINT8 ElementID = IE_MEASUREMENT_REQUEST; - - MakeOutgoingFrame(pFrameBuf, &TempLen, - 1, &ElementID, - 1, &Len, - Len, pMeasureReqIE, - END_OF_ARGS); - - *pFrameLen = *pFrameLen + TempLen; - - return; -} - -/* - ========================================================================== - Description: - Insert Measure Report IE into frame. - - Parametrs: - 1. frame buffer pointer. - 2. frame length. - 3. Measure Token. - 4. Measure Request Mode. - 5. Measure Request Type. - 6. Length of Report Infomation - 7. Pointer of Report Infomation Buffer. - - Return : None. - ========================================================================== - */ -static VOID InsertMeasureReportIE( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pFrameBuf, - OUT PULONG pFrameLen, - IN PMEASURE_REPORT_INFO pMeasureReportIE, - IN UINT8 ReportLnfoLen, - IN PUINT8 pReportInfo) -{ - ULONG TempLen; - ULONG Len; - UINT8 ElementID = IE_MEASUREMENT_REPORT; - - Len = sizeof(MEASURE_REPORT_INFO) + ReportLnfoLen; - - MakeOutgoingFrame(pFrameBuf, &TempLen, - 1, &ElementID, - 1, &Len, - Len, pMeasureReportIE, - END_OF_ARGS); - - *pFrameLen = *pFrameLen + TempLen; - - if ((ReportLnfoLen > 0) && (pReportInfo != NULL)) - { - MakeOutgoingFrame(pFrameBuf + *pFrameLen, &TempLen, - ReportLnfoLen, pReportInfo, - END_OF_ARGS); - - *pFrameLen = *pFrameLen + TempLen; - } - return; -} - -/* - ========================================================================== - Description: - Prepare Measurement request action frame and enqueue it into - management queue waiting for transmition. - - Parametrs: - 1. the destination mac address of the frame. - - Return : None. - ========================================================================== - */ -VOID EnqueueMeasurementReq( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDA, - IN UINT8 MeasureToken, - IN UINT8 MeasureReqMode, - IN UINT8 MeasureReqType, - IN UINT8 MeasureCh, - IN UINT16 MeasureDuration) -{ - PUCHAR pOutBuffer = NULL; - NDIS_STATUS NStatus; - ULONG FrameLen; - HEADER_802_11 ActHdr; - MEASURE_REQ_INFO MeasureReqIE; - UINT8 RmReqDailogToken = RandomByte(pAd); - UINT64 MeasureStartTime = GetCurrentTimeStamp(pAd); - - // build action frame header. - MgtMacHeaderInit(pAd, &ActHdr, SUBTYPE_ACTION, 0, pDA, - pAd->CurrentAddress); - - NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory - if(NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __FUNCTION__)); - return; - } - NdisMoveMemory(pOutBuffer, (PCHAR)&ActHdr, sizeof(HEADER_802_11)); - FrameLen = sizeof(HEADER_802_11); - - InsertActField(pAd, (pOutBuffer + FrameLen), &FrameLen, CATEGORY_SPECTRUM, SPEC_MRQ); - - // fill Dialog Token - InsertDialogToken(pAd, (pOutBuffer + FrameLen), &FrameLen, MeasureToken); - - // prepare Measurement IE. - NdisZeroMemory(&MeasureReqIE, sizeof(MEASURE_REQ_INFO)); - MeasureReqIE.Token = RmReqDailogToken; - MeasureReqIE.ReqMode.word = MeasureReqMode; - MeasureReqIE.ReqType = MeasureReqType; - MeasureReqIE.MeasureReq.ChNum = MeasureCh; - MeasureReqIE.MeasureReq.MeasureStartTime = cpu2le64(MeasureStartTime); - MeasureReqIE.MeasureReq.MeasureDuration = cpu2le16(MeasureDuration); - InsertMeasureReqIE(pAd, (pOutBuffer + FrameLen), &FrameLen, &MeasureReqIE); - - MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); - - return; -} - -/* - ========================================================================== - Description: - Prepare Measurement report action frame and enqueue it into - management queue waiting for transmition. - - Parametrs: - 1. the destination mac address of the frame. - - Return : None. - ========================================================================== - */ -VOID EnqueueMeasurementRep( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDA, - IN UINT8 DialogToken, - IN UINT8 MeasureToken, - IN UINT8 MeasureReqMode, - IN UINT8 MeasureReqType, - IN UINT8 ReportInfoLen, - IN PUINT8 pReportInfo) -{ - PUCHAR pOutBuffer = NULL; - NDIS_STATUS NStatus; - ULONG FrameLen; - HEADER_802_11 ActHdr; - MEASURE_REPORT_INFO MeasureRepIE; - - // build action frame header. - MgtMacHeaderInit(pAd, &ActHdr, SUBTYPE_ACTION, 0, pDA, - pAd->CurrentAddress); - - NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory - if(NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __FUNCTION__)); - return; - } - NdisMoveMemory(pOutBuffer, (PCHAR)&ActHdr, sizeof(HEADER_802_11)); - FrameLen = sizeof(HEADER_802_11); - - InsertActField(pAd, (pOutBuffer + FrameLen), &FrameLen, CATEGORY_SPECTRUM, SPEC_MRP); - - // fill Dialog Token - InsertDialogToken(pAd, (pOutBuffer + FrameLen), &FrameLen, DialogToken); - - // prepare Measurement IE. - NdisZeroMemory(&MeasureRepIE, sizeof(MEASURE_REPORT_INFO)); - MeasureRepIE.Token = MeasureToken; - MeasureRepIE.ReportMode.word = MeasureReqMode; - MeasureRepIE.ReportType = MeasureReqType; - InsertMeasureReportIE(pAd, (pOutBuffer + FrameLen), &FrameLen, &MeasureRepIE, ReportInfoLen, pReportInfo); - - MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); - - return; -} - -/* - ========================================================================== - Description: - Prepare TPC Request action frame and enqueue it into - management queue waiting for transmition. - - Parametrs: - 1. the destination mac address of the frame. - - Return : None. - ========================================================================== - */ -VOID EnqueueTPCReq( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDA, - IN UCHAR DialogToken) -{ - PUCHAR pOutBuffer = NULL; - NDIS_STATUS NStatus; - ULONG FrameLen; - - HEADER_802_11 ActHdr; - - // build action frame header. - MgtMacHeaderInit(pAd, &ActHdr, SUBTYPE_ACTION, 0, pDA, - pAd->CurrentAddress); - - NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory - if(NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __FUNCTION__)); - return; - } - NdisMoveMemory(pOutBuffer, (PCHAR)&ActHdr, sizeof(HEADER_802_11)); - FrameLen = sizeof(HEADER_802_11); - - InsertActField(pAd, (pOutBuffer + FrameLen), &FrameLen, CATEGORY_SPECTRUM, SPEC_TPCRQ); - - // fill Dialog Token - InsertDialogToken(pAd, (pOutBuffer + FrameLen), &FrameLen, DialogToken); - - // Insert TPC Request IE. - InsertTpcReqIE(pAd, (pOutBuffer + FrameLen), &FrameLen); - - MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); - - return; -} - -/* - ========================================================================== - Description: - Prepare TPC Report action frame and enqueue it into - management queue waiting for transmition. - - Parametrs: - 1. the destination mac address of the frame. - - Return : None. - ========================================================================== - */ -VOID EnqueueTPCRep( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDA, - IN UINT8 DialogToken, - IN UINT8 TxPwr, - IN UINT8 LinkMargin) -{ - PUCHAR pOutBuffer = NULL; - NDIS_STATUS NStatus; - ULONG FrameLen; - - HEADER_802_11 ActHdr; - - // build action frame header. - MgtMacHeaderInit(pAd, &ActHdr, SUBTYPE_ACTION, 0, pDA, - pAd->CurrentAddress); - - NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory - if(NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __FUNCTION__)); - return; - } - NdisMoveMemory(pOutBuffer, (PCHAR)&ActHdr, sizeof(HEADER_802_11)); - FrameLen = sizeof(HEADER_802_11); - - InsertActField(pAd, (pOutBuffer + FrameLen), &FrameLen, CATEGORY_SPECTRUM, SPEC_TPCRP); - - // fill Dialog Token - InsertDialogToken(pAd, (pOutBuffer + FrameLen), &FrameLen, DialogToken); - - // Insert TPC Request IE. - InsertTpcReportIE(pAd, (pOutBuffer + FrameLen), &FrameLen, TxPwr, LinkMargin); - - MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); - - return; -} - -/* - ========================================================================== - Description: - Prepare Channel Switch Announcement action frame and enqueue it into - management queue waiting for transmition. - - Parametrs: - 1. the destination mac address of the frame. - 2. Channel switch announcement mode. - 2. a New selected channel. - - Return : None. - ========================================================================== - */ -VOID EnqueueChSwAnn( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDA, - IN UINT8 ChSwMode, - IN UINT8 NewCh) -{ - PUCHAR pOutBuffer = NULL; - NDIS_STATUS NStatus; - ULONG FrameLen; - - HEADER_802_11 ActHdr; - - // build action frame header. - MgtMacHeaderInit(pAd, &ActHdr, SUBTYPE_ACTION, 0, pDA, - pAd->CurrentAddress); - - NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory - if(NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __FUNCTION__)); - return; - } - NdisMoveMemory(pOutBuffer, (PCHAR)&ActHdr, sizeof(HEADER_802_11)); - FrameLen = sizeof(HEADER_802_11); - - InsertActField(pAd, (pOutBuffer + FrameLen), &FrameLen, CATEGORY_SPECTRUM, SPEC_CHANNEL_SWITCH); - - InsertChSwAnnIE(pAd, (pOutBuffer + FrameLen), &FrameLen, ChSwMode, NewCh, 0); - - MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); - - return; -} - -static BOOLEAN DfsRequirementCheck( - IN PRTMP_ADAPTER pAd, - IN UINT8 Channel) -{ - BOOLEAN Result = FALSE; - INT i; - - do - { - // check DFS procedure is running. - // make sure DFS procedure won't start twice. - if (pAd->CommonCfg.RadarDetect.RDMode != RD_NORMAL_MODE) - { - Result = FALSE; - break; - } - - // check the new channel carried from Channel Switch Announcemnet is valid. - for (i=0; iChannelListNum; i++) - { - if ((Channel == pAd->ChannelList[i].Channel) - &&(pAd->ChannelList[i].RemainingTimeForUse == 0)) - { - // found radar signal in the channel. the channel can't use at least for 30 minutes. - pAd->ChannelList[i].RemainingTimeForUse = 1800;//30 min = 1800 sec - Result = TRUE; - break; - } - } - } while(FALSE); - - return Result; -} - -VOID NotifyChSwAnnToPeerAPs( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pRA, - IN PUCHAR pTA, - IN UINT8 ChSwMode, - IN UINT8 Channel) -{ -#ifdef WDS_SUPPORT - if (!((pRA[0] & 0xff) == 0xff)) // is pRA a broadcase address. - { - INT i; - // info neighbor APs that Radar signal found throgh WDS link. - for (i = 0; i < MAX_WDS_ENTRY; i++) - { - if (ValidWdsEntry(pAd, i)) - { - PUCHAR pDA = pAd->WdsTab.WdsEntry[i].PeerWdsAddr; - - // DA equal to SA. have no necessary orignal AP which found Radar signal. - if (MAC_ADDR_EQUAL(pTA, pDA)) - continue; - - // send Channel Switch Action frame to info Neighbro APs. - EnqueueChSwAnn(pAd, pDA, ChSwMode, Channel); - } - } - } -#endif // WDS_SUPPORT // -} - -static VOID StartDFSProcedure( - IN PRTMP_ADAPTER pAd, - IN UCHAR Channel, - IN UINT8 ChSwMode) -{ - // start DFS procedure - pAd->CommonCfg.Channel = Channel; -#ifdef DOT11_N_SUPPORT - N_ChannelCheck(pAd); -#endif // DOT11_N_SUPPORT // - pAd->CommonCfg.RadarDetect.RDMode = RD_SWITCHING_MODE; - pAd->CommonCfg.RadarDetect.CSCount = 0; -} - -/* - ========================================================================== - Description: - Channel Switch Announcement action frame sanity check. - - Parametrs: - 1. MLME message containing the received frame - 2. message length. - 3. Channel switch announcement infomation buffer. - - - Return : None. - ========================================================================== - */ - -/* - Channel Switch Announcement IE. - +----+-----+-----------+------------+-----------+ - | ID | Len |Ch Sw Mode | New Ch Num | Ch Sw Cnt | - +----+-----+-----------+------------+-----------+ - 1 1 1 1 1 -*/ -static BOOLEAN PeerChSwAnnSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *pMsg, - IN ULONG MsgLen, - OUT PCH_SW_ANN_INFO pChSwAnnInfo) -{ - PFRAME_802_11 Fr = (PFRAME_802_11)pMsg; - PUCHAR pFramePtr = Fr->Octet; - BOOLEAN result = FALSE; - PEID_STRUCT eid_ptr; - - // skip 802.11 header. - MsgLen -= sizeof(HEADER_802_11); - - // skip category and action code. - pFramePtr += 2; - MsgLen -= 2; - - if (pChSwAnnInfo == NULL) - return result; - - eid_ptr = (PEID_STRUCT)pFramePtr; - while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((PUCHAR)pFramePtr + MsgLen)) - { - switch(eid_ptr->Eid) - { - case IE_CHANNEL_SWITCH_ANNOUNCEMENT: - NdisMoveMemory(&pChSwAnnInfo->ChSwMode, eid_ptr->Octet, 1); - NdisMoveMemory(&pChSwAnnInfo->Channel, eid_ptr->Octet + 1, 1); - NdisMoveMemory(&pChSwAnnInfo->ChSwCnt, eid_ptr->Octet + 2, 1); - - result = TRUE; - break; - - default: - break; - } - eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len); - } - - return result; -} - -/* - ========================================================================== - Description: - Measurement request action frame sanity check. - - Parametrs: - 1. MLME message containing the received frame - 2. message length. - 3. Measurement request infomation buffer. - - Return : None. - ========================================================================== - */ -static BOOLEAN PeerMeasureReqSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *pMsg, - IN ULONG MsgLen, - OUT PUINT8 pDialogToken, - OUT PMEASURE_REQ_INFO pMeasureReqInfo) -{ - PFRAME_802_11 Fr = (PFRAME_802_11)pMsg; - PUCHAR pFramePtr = Fr->Octet; - BOOLEAN result = FALSE; - PEID_STRUCT eid_ptr; - PUCHAR ptr; - UINT64 MeasureStartTime; - UINT16 MeasureDuration; - - // skip 802.11 header. - MsgLen -= sizeof(HEADER_802_11); - - // skip category and action code. - pFramePtr += 2; - MsgLen -= 2; - - if (pMeasureReqInfo == NULL) - return result; - - NdisMoveMemory(pDialogToken, pFramePtr, 1); - pFramePtr += 1; - MsgLen -= 1; - - eid_ptr = (PEID_STRUCT)pFramePtr; - while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((PUCHAR)pFramePtr + MsgLen)) - { - switch(eid_ptr->Eid) - { - case IE_MEASUREMENT_REQUEST: - NdisMoveMemory(&pMeasureReqInfo->Token, eid_ptr->Octet, 1); - NdisMoveMemory(&pMeasureReqInfo->ReqMode.word, eid_ptr->Octet + 1, 1); - NdisMoveMemory(&pMeasureReqInfo->ReqType, eid_ptr->Octet + 2, 1); - ptr = eid_ptr->Octet + 3; - NdisMoveMemory(&pMeasureReqInfo->MeasureReq.ChNum, ptr, 1); - NdisMoveMemory(&MeasureStartTime, ptr + 1, 8); - pMeasureReqInfo->MeasureReq.MeasureStartTime = SWAP64(MeasureStartTime); - NdisMoveMemory(&MeasureDuration, ptr + 9, 2); - pMeasureReqInfo->MeasureReq.MeasureDuration = SWAP16(MeasureDuration); - - result = TRUE; - break; - - default: - break; - } - eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len); - } - - return result; -} - -/* - ========================================================================== - Description: - Measurement report action frame sanity check. - - Parametrs: - 1. MLME message containing the received frame - 2. message length. - 3. Measurement report infomation buffer. - 4. basic report infomation buffer. - - Return : None. - ========================================================================== - */ - -/* - Measurement Report IE. - +----+-----+-------+-------------+--------------+----------------+ - | ID | Len | Token | Report Mode | Measure Type | Measure Report | - +----+-----+-------+-------------+--------------+----------------+ - 1 1 1 1 1 variable - - Basic Report. - +--------+------------+----------+-----+ - | Ch Num | Start Time | Duration | Map | - +--------+------------+----------+-----+ - 1 8 2 1 - - Map Field Bit Format. - +-----+---------------+---------------------+-------+------------+----------+ - | Bss | OFDM Preamble | Unidentified signal | Radar | Unmeasured | Reserved | - +-----+---------------+---------------------+-------+------------+----------+ - 0 1 2 3 4 5-7 -*/ -static BOOLEAN PeerMeasureReportSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *pMsg, - IN ULONG MsgLen, - OUT PUINT8 pDialogToken, - OUT PMEASURE_REPORT_INFO pMeasureReportInfo, - OUT PUINT8 pReportBuf) -{ - PFRAME_802_11 Fr = (PFRAME_802_11)pMsg; - PUCHAR pFramePtr = Fr->Octet; - BOOLEAN result = FALSE; - PEID_STRUCT eid_ptr; - PUCHAR ptr; - - // skip 802.11 header. - MsgLen -= sizeof(HEADER_802_11); - - // skip category and action code. - pFramePtr += 2; - MsgLen -= 2; - - if (pMeasureReportInfo == NULL) - return result; - - NdisMoveMemory(pDialogToken, pFramePtr, 1); - pFramePtr += 1; - MsgLen -= 1; - - eid_ptr = (PEID_STRUCT)pFramePtr; - while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((PUCHAR)pFramePtr + MsgLen)) - { - switch(eid_ptr->Eid) - { - case IE_MEASUREMENT_REPORT: - NdisMoveMemory(&pMeasureReportInfo->Token, eid_ptr->Octet, 1); - NdisMoveMemory(&pMeasureReportInfo->ReportMode, eid_ptr->Octet + 1, 1); - NdisMoveMemory(&pMeasureReportInfo->ReportType, eid_ptr->Octet + 2, 1); - if (pMeasureReportInfo->ReportType == RM_BASIC) - { - PMEASURE_BASIC_REPORT pReport = (PMEASURE_BASIC_REPORT)pReportBuf; - ptr = eid_ptr->Octet + 3; - NdisMoveMemory(&pReport->ChNum, ptr, 1); - NdisMoveMemory(&pReport->MeasureStartTime, ptr + 1, 8); - NdisMoveMemory(&pReport->MeasureDuration, ptr + 9, 2); - NdisMoveMemory(&pReport->Map, ptr + 11, 1); - - } - else if (pMeasureReportInfo->ReportType == RM_CCA) - { - PMEASURE_CCA_REPORT pReport = (PMEASURE_CCA_REPORT)pReportBuf; - ptr = eid_ptr->Octet + 3; - NdisMoveMemory(&pReport->ChNum, ptr, 1); - NdisMoveMemory(&pReport->MeasureStartTime, ptr + 1, 8); - NdisMoveMemory(&pReport->MeasureDuration, ptr + 9, 2); - NdisMoveMemory(&pReport->CCA_Busy_Fraction, ptr + 11, 1); - - } - else if (pMeasureReportInfo->ReportType == RM_RPI_HISTOGRAM) - { - PMEASURE_RPI_REPORT pReport = (PMEASURE_RPI_REPORT)pReportBuf; - ptr = eid_ptr->Octet + 3; - NdisMoveMemory(&pReport->ChNum, ptr, 1); - NdisMoveMemory(&pReport->MeasureStartTime, ptr + 1, 8); - NdisMoveMemory(&pReport->MeasureDuration, ptr + 9, 2); - NdisMoveMemory(&pReport->RPI_Density, ptr + 11, 8); - } - result = TRUE; - break; - - default: - break; - } - eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len); - } - - return result; -} - -/* - ========================================================================== - Description: - TPC Request action frame sanity check. - - Parametrs: - 1. MLME message containing the received frame - 2. message length. - 3. Dialog Token. - - Return : None. - ========================================================================== - */ -static BOOLEAN PeerTpcReqSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *pMsg, - IN ULONG MsgLen, - OUT PUINT8 pDialogToken) -{ - PFRAME_802_11 Fr = (PFRAME_802_11)pMsg; - PUCHAR pFramePtr = Fr->Octet; - BOOLEAN result = FALSE; - PEID_STRUCT eid_ptr; - - MsgLen -= sizeof(HEADER_802_11); - - // skip category and action code. - pFramePtr += 2; - MsgLen -= 2; - - if (pDialogToken == NULL) - return result; - - NdisMoveMemory(pDialogToken, pFramePtr, 1); - pFramePtr += 1; - MsgLen -= 1; - - eid_ptr = (PEID_STRUCT)pFramePtr; - while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((PUCHAR)pFramePtr + MsgLen)) - { - switch(eid_ptr->Eid) - { - case IE_TPC_REQUEST: - result = TRUE; - break; - - default: - break; - } - eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len); - } - - return result; -} - -/* - ========================================================================== - Description: - TPC Report action frame sanity check. - - Parametrs: - 1. MLME message containing the received frame - 2. message length. - 3. Dialog Token. - 4. TPC Report IE. - - Return : None. - ========================================================================== - */ -static BOOLEAN PeerTpcRepSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *pMsg, - IN ULONG MsgLen, - OUT PUINT8 pDialogToken, - OUT PTPC_REPORT_INFO pTpcRepInfo) -{ - PFRAME_802_11 Fr = (PFRAME_802_11)pMsg; - PUCHAR pFramePtr = Fr->Octet; - BOOLEAN result = FALSE; - PEID_STRUCT eid_ptr; - - MsgLen -= sizeof(HEADER_802_11); - - // skip category and action code. - pFramePtr += 2; - MsgLen -= 2; - - if (pDialogToken == NULL) - return result; - - NdisMoveMemory(pDialogToken, pFramePtr, 1); - pFramePtr += 1; - MsgLen -= 1; - - eid_ptr = (PEID_STRUCT)pFramePtr; - while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((PUCHAR)pFramePtr + MsgLen)) - { - switch(eid_ptr->Eid) - { - case IE_TPC_REPORT: - NdisMoveMemory(&pTpcRepInfo->TxPwr, eid_ptr->Octet, 1); - NdisMoveMemory(&pTpcRepInfo->LinkMargin, eid_ptr->Octet + 1, 1); - result = TRUE; - break; - - default: - break; - } - eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len); - } - - return result; -} - -/* - ========================================================================== - Description: - Channel Switch Announcement action frame handler. - - Parametrs: - Elme - MLME message containing the received frame - - Return : None. - ========================================================================== - */ -static VOID PeerChSwAnnAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - CH_SW_ANN_INFO ChSwAnnInfo; - PFRAME_802_11 pFr = (PFRAME_802_11)Elem->Msg; -#ifdef CONFIG_STA_SUPPORT - UCHAR index = 0, Channel = 0, NewChannel = 0; - ULONG Bssidx = 0; -#endif // CONFIG_STA_SUPPORT // - - NdisZeroMemory(&ChSwAnnInfo, sizeof(CH_SW_ANN_INFO)); - if (! PeerChSwAnnSanity(pAd, Elem->Msg, Elem->MsgLen, &ChSwAnnInfo)) - { - DBGPRINT(RT_DEBUG_TRACE, ("Invalid Channel Switch Action Frame.\n")); - return; - } - - -#ifdef CONFIG_STA_SUPPORT - if (pAd->OpMode == OPMODE_STA) - { - Bssidx = BssTableSearch(&pAd->ScanTab, pFr->Hdr.Addr3, pAd->CommonCfg.Channel); - if (Bssidx == BSS_NOT_FOUND) - { - DBGPRINT(RT_DEBUG_TRACE, ("PeerChSwAnnAction - Bssidx is not found\n")); - return; - } - - DBGPRINT(RT_DEBUG_TRACE, ("\n****Bssidx is %d, Channel = %d\n", index, pAd->ScanTab.BssEntry[Bssidx].Channel)); - hex_dump("SSID",pAd->ScanTab.BssEntry[Bssidx].Bssid ,6); - - Channel = pAd->CommonCfg.Channel; - NewChannel = ChSwAnnInfo.Channel; - - if ((pAd->CommonCfg.bIEEE80211H == 1) && (NewChannel != 0) && (Channel != NewChannel)) - { - // Switching to channel 1 can prevent from rescanning the current channel immediately (by auto reconnection). - // In addition, clear the MLME queue and the scan table to discard the RX packets and previous scanning results. - AsicSwitchChannel(pAd, 1, FALSE); - AsicLockChannel(pAd, 1); - LinkDown(pAd, FALSE); - MlmeQueueInit(&pAd->Mlme.Queue); - BssTableInit(&pAd->ScanTab); - RTMPusecDelay(1000000); // use delay to prevent STA do reassoc - - // channel sanity check - for (index = 0 ; index < pAd->ChannelListNum; index++) - { - if (pAd->ChannelList[index].Channel == NewChannel) - { - pAd->ScanTab.BssEntry[Bssidx].Channel = NewChannel; - pAd->CommonCfg.Channel = NewChannel; - AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); - AsicLockChannel(pAd, pAd->CommonCfg.Channel); - DBGPRINT(RT_DEBUG_TRACE, ("&&&&&&&&&&&&&&&&PeerChSwAnnAction - STA receive channel switch announcement IE (New Channel =%d)\n", NewChannel)); - break; - } - } - - if (index >= pAd->ChannelListNum) - { - DBGPRINT_ERR(("&&&&&&&&&&&&&&&&&&&&&&&&&&PeerChSwAnnAction(can not find New Channel=%d in ChannelList[%d]\n", pAd->CommonCfg.Channel, pAd->ChannelListNum)); - } - } - } -#endif // CONFIG_STA_SUPPORT // - - return; -} - - -/* - ========================================================================== - Description: - Measurement Request action frame handler. - - Parametrs: - Elme - MLME message containing the received frame - - Return : None. - ========================================================================== - */ -static VOID PeerMeasureReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - PFRAME_802_11 pFr = (PFRAME_802_11)Elem->Msg; - UINT8 DialogToken; - MEASURE_REQ_INFO MeasureReqInfo; - MEASURE_REPORT_MODE ReportMode; - - if(PeerMeasureReqSanity(pAd, Elem->Msg, Elem->MsgLen, &DialogToken, &MeasureReqInfo)) - { - ReportMode.word = 0; - ReportMode.field.Incapable = 1; - EnqueueMeasurementRep(pAd, pFr->Hdr.Addr2, DialogToken, MeasureReqInfo.Token, ReportMode.word, MeasureReqInfo.ReqType, 0, NULL); - } - - return; -} - -/* - ========================================================================== - Description: - Measurement Report action frame handler. - - Parametrs: - Elme - MLME message containing the received frame - - Return : None. - ========================================================================== - */ -static VOID PeerMeasureReportAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - MEASURE_REPORT_INFO MeasureReportInfo; - PFRAME_802_11 pFr = (PFRAME_802_11)Elem->Msg; - UINT8 DialogToken; - PUINT8 pMeasureReportInfo; - -// if (pAd->CommonCfg.bIEEE80211H != TRUE) -// return; - - if ((pMeasureReportInfo = kmalloc(sizeof(MEASURE_RPI_REPORT), GFP_ATOMIC)) == NULL) - { - DBGPRINT(RT_DEBUG_ERROR, ("%s unable to alloc memory for measure report buffer (size=%d).\n", __FUNCTION__, sizeof(MEASURE_RPI_REPORT))); - return; - } - - NdisZeroMemory(&MeasureReportInfo, sizeof(MEASURE_REPORT_INFO)); - NdisZeroMemory(pMeasureReportInfo, sizeof(MEASURE_RPI_REPORT)); - if (PeerMeasureReportSanity(pAd, Elem->Msg, Elem->MsgLen, &DialogToken, &MeasureReportInfo, pMeasureReportInfo)) - { - do { - PMEASURE_REQ_ENTRY pEntry = NULL; - - // Not a autonomous measure report. - // check the dialog token field. drop it if the dialog token doesn't match. - if ((DialogToken != 0) - && ((pEntry = MeasureReqLookUp(pAd, DialogToken)) == NULL)) - break; - - if (pEntry != NULL) - MeasureReqDelete(pAd, pEntry->DialogToken); - - if (MeasureReportInfo.ReportType == RM_BASIC) - { - PMEASURE_BASIC_REPORT pBasicReport = (PMEASURE_BASIC_REPORT)pMeasureReportInfo; - if ((pBasicReport->Map.field.Radar) - && (DfsRequirementCheck(pAd, pBasicReport->ChNum) == TRUE)) - { - NotifyChSwAnnToPeerAPs(pAd, pFr->Hdr.Addr1, pFr->Hdr.Addr2, 1, pBasicReport->ChNum); - StartDFSProcedure(pAd, pBasicReport->ChNum, 1); - } - } - } while (FALSE); - } - else - DBGPRINT(RT_DEBUG_TRACE, ("Invalid Measurement Report Frame.\n")); - - kfree(pMeasureReportInfo); - - return; -} - -/* - ========================================================================== - Description: - TPC Request action frame handler. - - Parametrs: - Elme - MLME message containing the received frame - - Return : None. - ========================================================================== - */ -static VOID PeerTpcReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - PFRAME_802_11 pFr = (PFRAME_802_11)Elem->Msg; - PUCHAR pFramePtr = pFr->Octet; - UINT8 DialogToken; - UINT8 TxPwr = GetCurTxPwr(pAd, Elem->Wcid); - UINT8 LinkMargin = 0; - CHAR RealRssi; - - // link margin: Ratio of the received signal power to the minimum desired by the station (STA). The - // STA may incorporate rate information and channel conditions, including interference, into its computation - // of link margin. - - RealRssi = RTMPMaxRssi(pAd, ConvertToRssi(pAd, Elem->Rssi0, RSSI_0), - ConvertToRssi(pAd, Elem->Rssi1, RSSI_1), - ConvertToRssi(pAd, Elem->Rssi2, RSSI_2)); - - // skip Category and action code. - pFramePtr += 2; - - // Dialog token. - NdisMoveMemory(&DialogToken, pFramePtr, 1); - - LinkMargin = (RealRssi / MIN_RCV_PWR); - if (PeerTpcReqSanity(pAd, Elem->Msg, Elem->MsgLen, &DialogToken)) - EnqueueTPCRep(pAd, pFr->Hdr.Addr2, DialogToken, TxPwr, LinkMargin); - - return; -} - -/* - ========================================================================== - Description: - TPC Report action frame handler. - - Parametrs: - Elme - MLME message containing the received frame - - Return : None. - ========================================================================== - */ -static VOID PeerTpcRepAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - UINT8 DialogToken; - TPC_REPORT_INFO TpcRepInfo; - PTPC_REQ_ENTRY pEntry = NULL; - - NdisZeroMemory(&TpcRepInfo, sizeof(TPC_REPORT_INFO)); - if (PeerTpcRepSanity(pAd, Elem->Msg, Elem->MsgLen, &DialogToken, &TpcRepInfo)) - { - if ((pEntry = TpcReqLookUp(pAd, DialogToken)) != NULL) - { - TpcReqDelete(pAd, pEntry->DialogToken); - DBGPRINT(RT_DEBUG_TRACE, ("%s: DialogToken=%x, TxPwr=%d, LinkMargin=%d\n", - __FUNCTION__, DialogToken, TpcRepInfo.TxPwr, TpcRepInfo.LinkMargin)); - } - } - - return; -} - -/* - ========================================================================== - Description: - Spectrun action frames Handler such as channel switch annoucement, - measurement report, measurement request actions frames. - - Parametrs: - Elme - MLME message containing the received frame - - Return : None. - ========================================================================== - */ -VOID PeerSpectrumAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - - UCHAR Action = Elem->Msg[LENGTH_802_11+1]; - - if (pAd->CommonCfg.bIEEE80211H != TRUE) - return; - - switch(Action) - { - case SPEC_MRQ: - // current rt2860 unable do such measure specified in Measurement Request. - // reject all measurement request. - PeerMeasureReqAction(pAd, Elem); - break; - - case SPEC_MRP: - PeerMeasureReportAction(pAd, Elem); - break; - - case SPEC_TPCRQ: - PeerTpcReqAction(pAd, Elem); - break; - - case SPEC_TPCRP: - PeerTpcRepAction(pAd, Elem); - break; - - case SPEC_CHANNEL_SWITCH: -{ -#ifdef DOT11N_DRAFT3 - SEC_CHA_OFFSET_IE Secondary; - CHA_SWITCH_ANNOUNCE_IE ChannelSwitch; - - // 802.11h only has Channel Switch Announcement IE. - RTMPMoveMemory(&ChannelSwitch, &Elem->Msg[LENGTH_802_11+4], sizeof (CHA_SWITCH_ANNOUNCE_IE)); - - // 802.11n D3.03 adds secondary channel offset element in the end. - if (Elem->MsgLen == (LENGTH_802_11 + 2 + sizeof (CHA_SWITCH_ANNOUNCE_IE) + sizeof (SEC_CHA_OFFSET_IE))) - { - RTMPMoveMemory(&Secondary, &Elem->Msg[LENGTH_802_11+9], sizeof (SEC_CHA_OFFSET_IE)); - } - else - { - Secondary.SecondaryChannelOffset = 0; - } - - if ((Elem->Msg[LENGTH_802_11+2] == IE_CHANNEL_SWITCH_ANNOUNCEMENT) && (Elem->Msg[LENGTH_802_11+3] == 3)) - { - ChannelSwitchAction(pAd, Elem->Wcid, ChannelSwitch.NewChannel, Secondary.SecondaryChannelOffset); - } -#endif // DOT11N_DRAFT3 // -} - PeerChSwAnnAction(pAd, Elem); - break; - } - - return; -} - -/* - ========================================================================== - Description: - - Parametrs: - - Return : None. - ========================================================================== - */ -INT Set_MeasureReq_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - UINT Aid = 1; - UINT ArgIdx; - PUCHAR thisChar; - - MEASURE_REQ_MODE MeasureReqMode; - UINT8 MeasureReqToken = RandomByte(pAd); - UINT8 MeasureReqType = RM_BASIC; - UINT8 MeasureCh = 1; - - ArgIdx = 1; - while ((thisChar = strsep((char **)&arg, "-")) != NULL) - { - switch(ArgIdx) - { - case 1: // Aid. - Aid = simple_strtol(thisChar, 0, 16); - break; - - case 2: // Measurement Request Type. - MeasureReqType = simple_strtol(thisChar, 0, 16); - if (MeasureReqType > 3) - { - DBGPRINT(RT_DEBUG_ERROR, ("%s: unknow MeasureReqType(%d)\n", __FUNCTION__, MeasureReqType)); - return TRUE; - } - break; - - case 3: // Measurement channel. - MeasureCh = simple_strtol(thisChar, 0, 16); - break; - } - ArgIdx++; - } - - DBGPRINT(RT_DEBUG_TRACE, ("%s::Aid = %d, MeasureReqType=%d MeasureCh=%d\n", __FUNCTION__, Aid, MeasureReqType, MeasureCh)); - if (!VALID_WCID(Aid)) - { - DBGPRINT(RT_DEBUG_ERROR, ("%s: unknow sta of Aid(%d)\n", __FUNCTION__, Aid)); - return TRUE; - } - - MeasureReqMode.word = 0; - MeasureReqMode.field.Enable = 1; - - MeasureReqInsert(pAd, MeasureReqToken); - - EnqueueMeasurementReq(pAd, pAd->MacTab.Content[Aid].Addr, - MeasureReqToken, MeasureReqMode.word, MeasureReqType, MeasureCh, 2000); - - return TRUE; -} - -INT Set_TpcReq_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - UINT Aid; - - UINT8 TpcReqToken = RandomByte(pAd); - - Aid = simple_strtol(arg, 0, 16); - - DBGPRINT(RT_DEBUG_TRACE, ("%s::Aid = %d\n", __FUNCTION__, Aid)); - if (!VALID_WCID(Aid)) - { - DBGPRINT(RT_DEBUG_ERROR, ("%s: unknow sta of Aid(%d)\n", __FUNCTION__, Aid)); - return TRUE; - } - - TpcReqInsert(pAd, TpcReqToken); - - EnqueueTPCReq(pAd, pAd->MacTab.Content[Aid].Addr, TpcReqToken); - - return TRUE; -} - +#include "../../rt2870/common/spectrum.c" diff --git a/drivers/staging/rt3070/dfs.h b/drivers/staging/rt3070/dfs.h index 752a6352d9dd..b9c92e354f20 100644 --- a/drivers/staging/rt3070/dfs.h +++ b/drivers/staging/rt3070/dfs.h @@ -1,100 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - dfs.h - - Abstract: - Support DFS function. - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Fonchi 03-12-2007 created -*/ - -#define RADAR_PULSE 1 -#define RADAR_WIDTH 2 - -#define WIDTH_RD_IDLE 0 -#define WIDTH_RD_CHECK 1 - - -VOID BbpRadarDetectionStart( - IN PRTMP_ADAPTER pAd); - -VOID BbpRadarDetectionStop( - IN PRTMP_ADAPTER pAd); - -VOID RadarDetectionStart( - IN PRTMP_ADAPTER pAd, - IN BOOLEAN CTS_Protect, - IN UINT8 CTSPeriod); - -VOID RadarDetectionStop( - IN PRTMP_ADAPTER pAd); - -VOID RadarDetectPeriodic( - IN PRTMP_ADAPTER pAd); - - -BOOLEAN RadarChannelCheck( - IN PRTMP_ADAPTER pAd, - IN UCHAR Ch); - -ULONG JapRadarType( - IN PRTMP_ADAPTER pAd); - -ULONG RTMPBbpReadRadarDuration( - IN PRTMP_ADAPTER pAd); - -ULONG RTMPReadRadarDuration( - IN PRTMP_ADAPTER pAd); - -VOID RTMPCleanRadarDuration( - IN PRTMP_ADAPTER pAd); - -VOID RTMPPrepareRDCTSFrame( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDA, - IN ULONG Duration, - IN UCHAR RTSRate, - IN ULONG CTSBaseAddr, - IN UCHAR FrameGap); - -VOID RTMPPrepareRadarDetectParams( - IN PRTMP_ADAPTER pAd); - - -INT Set_ChMovingTime_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_LongPulseRadarTh_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - - +#include "../rt2870/dfs.h" diff --git a/drivers/staging/rt3070/leap.h b/drivers/staging/rt3070/leap.h deleted file mode 100644 index 6818c1ff4d73..000000000000 --- a/drivers/staging/rt3070/leap.h +++ /dev/null @@ -1,215 +0,0 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - leap.h - - Abstract: - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Name Date Modification logs -*/ -#ifndef __LEAP_H__ -#define __LEAP_H__ - -// Messages for Associate state machine -#define LEAP_MACHINE_BASE 30 - -#define LEAP_MSG_REQUEST_IDENTITY 31 -#define LEAP_MSG_REQUEST_LEAP 32 -#define LEAP_MSG_SUCCESS 33 -#define LEAP_MSG_FAILED 34 -#define LEAP_MSG_RESPONSE_LEAP 35 -#define LEAP_MSG_EAPOLKEY 36 -#define LEAP_MSG_UNKNOWN 37 -#define LEAP_MSG 38 -//! assoc state-machine states -#define LEAP_IDLE 0 -#define LEAP_WAIT_IDENTITY_REQUEST 1 -#define LEAP_WAIT_CHANLLENGE_REQUEST 2 -#define LEAP_WAIT_SUCCESS 3 -#define LEAP_WAIT_CHANLLENGE_RESPONSE 4 -#define LEAP_WAIT_EAPOLKEY 5 - -#define LEAP_REASON_INVALID_AUTH 0x01 -#define LEAP_REASON_AUTH_TIMEOUT 0x02 -#define LEAP_REASON_CHALLENGE_FROM_AP_FAILED 0x03 -#define LEAP_REASON_CHALLENGE_TO_AP_FAILED 0x04 - -#define CISCO_AuthModeLEAP 0x80 -#define CISCO_AuthModeLEAPNone 0x00 -#define LEAP_AUTH_TIMEOUT 30000 -#define LEAP_CHALLENGE_RESPONSE_LENGTH 24 -#define LEAP_CHALLENGE_REQUEST_LENGTH 8 - -typedef struct _LEAP_EAPOL_HEADER_ { - UCHAR Version; - UCHAR Type; - UCHAR Length[2]; -} LEAP_EAPOL_HEADER, *PLEAP_EAPOL_HEADER; - -typedef struct _LEAP_EAPOL_PACKET_ { - UCHAR Code; - UCHAR Identifier; - UCHAR Length[2]; - UCHAR Type; -} LEAP_EAPOL_PACKET, *PLEAP_EAPOL_PACKET; - -typedef struct _LEAP_EAP_CONTENTS_ { - UCHAR Version; - UCHAR Reserved; - UCHAR Length; -} LEAP_EAP_CONTENTS, *PLEAP_EAP_CONTENTS; - -/*** EAPOL key ***/ -typedef struct _EAPOL_KEY_HEADER_ { - UCHAR Type; - UCHAR Length[2]; - UCHAR Counter[8]; - UCHAR IV[16]; - UCHAR Index; - UCHAR Signature[16]; -} EAPOL_KEY_HEADER, *PEAPOL_KEY_HEADER; - -BOOLEAN LeapMsgTypeSubst( - IN UCHAR EAPType, - OUT ULONG *MsgType); - -VOID LeapMachinePerformAction( - IN PRTMP_ADAPTER pAd, - IN STATE_MACHINE *S, - IN MLME_QUEUE_ELEM *Elem); - -VOID LeapMacHeaderInit( - IN PRTMP_ADAPTER pAd, - IN OUT PHEADER_802_11 pHdr80211, - IN UCHAR wep, - IN PUCHAR pAddr3); - -VOID LeapStartAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID LeapIdentityAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID LeapPeerChallengeAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID HashPwd( - IN PUCHAR pwd, - IN INT pwdlen, - OUT PUCHAR hash); - -VOID PeerChallengeResponse( - IN PUCHAR szChallenge, - IN PUCHAR smbPasswd, - OUT PUCHAR szResponse); - -VOID ParityKey( - OUT PUCHAR szOut, - IN PUCHAR szIn); - -VOID DesKey( - OUT ULONG k[16][2], - IN PUCHAR key, - IN INT decrypt); - -VOID Des( - IN ULONG ks[16][2], - OUT UCHAR block[8]); - -VOID DesEncrypt( - IN PUCHAR szClear, - IN PUCHAR szKey, - OUT PUCHAR szOut); - -VOID LeapNetworkChallengeAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID LeapNetworkChallengeResponse( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID HashpwdHash( - IN PUCHAR hash, - IN PUCHAR hashhash); - -VOID ProcessSessionKey( - OUT PUCHAR SessionKey, - IN PUCHAR hash2, - IN PUCHAR ChallengeToRadius, - IN PUCHAR ChallengeResponseFromRadius, - IN PUCHAR ChallengeFromRadius, - IN PUCHAR ChallengeResponseToRadius); - -VOID LeapEapolKeyAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID RogueApTableInit( - IN ROGUEAP_TABLE *Tab); - -ULONG RogueApTableSearch( - IN ROGUEAP_TABLE *Tab, - IN PUCHAR pAddr); - -VOID RogueApEntrySet( - IN PRTMP_ADAPTER pAd, - OUT ROGUEAP_ENTRY *pRogueAp, - IN PUCHAR pAddr, - IN UCHAR FaileCode); - -ULONG RogueApTableSetEntry( - IN PRTMP_ADAPTER pAd, - OUT ROGUEAP_TABLE *Tab, - IN PUCHAR pAddr, - IN UCHAR FaileCode); - -VOID RogueApTableDeleteEntry( - IN OUT ROGUEAP_TABLE *Tab, - IN PUCHAR pAddr); - -VOID LeapAuthTimeout( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); - -VOID LeapSendRogueAPReport( - IN PRTMP_ADAPTER pAd); - -BOOLEAN CCKMAssocRspSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen); - -#endif // __LEAP_H__ diff --git a/drivers/staging/rt3070/link_list.h b/drivers/staging/rt3070/link_list.h index f6521133fd5e..5550b2f45164 100644 --- a/drivers/staging/rt3070/link_list.h +++ b/drivers/staging/rt3070/link_list.h @@ -1,134 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - */ - -#ifndef __LINK_LIST_H__ -#define __LINK_LIST_H__ - -typedef struct _LIST_ENTRY -{ - struct _LIST_ENTRY *pNext; -} LIST_ENTRY, *PLIST_ENTRY; - -typedef struct _LIST_HEADR -{ - PLIST_ENTRY pHead; - PLIST_ENTRY pTail; - UCHAR size; -} LIST_HEADER, *PLIST_HEADER; - -static inline VOID initList( - IN PLIST_HEADER pList) -{ - pList->pHead = pList->pTail = NULL; - pList->size = 0; - return; -} - -static inline VOID insertTailList( - IN PLIST_HEADER pList, - IN PLIST_ENTRY pEntry) -{ - pEntry->pNext = NULL; - if (pList->pTail) - pList->pTail->pNext = pEntry; - else - pList->pHead = pEntry; - pList->pTail = pEntry; - pList->size++; - - return; -} - -static inline PLIST_ENTRY removeHeadList( - IN PLIST_HEADER pList) -{ - PLIST_ENTRY pNext; - PLIST_ENTRY pEntry; - - pEntry = pList->pHead; - if (pList->pHead != NULL) - { - pNext = pList->pHead->pNext; - pList->pHead = pNext; - if (pNext == NULL) - pList->pTail = NULL; - pList->size--; - } - return pEntry; -} - -static inline int getListSize( - IN PLIST_HEADER pList) -{ - return pList->size; -} - -static inline PLIST_ENTRY delEntryList( - IN PLIST_HEADER pList, - IN PLIST_ENTRY pEntry) -{ - PLIST_ENTRY pCurEntry; - PLIST_ENTRY pPrvEntry; - - if(pList->pHead == NULL) - return NULL; - - if(pEntry == pList->pHead) - { - pCurEntry = pList->pHead; - pList->pHead = pCurEntry->pNext; - - if(pList->pHead == NULL) - pList->pTail = NULL; - - pList->size--; - return pCurEntry; - } - - pPrvEntry = pList->pHead; - pCurEntry = pPrvEntry->pNext; - while(pCurEntry != NULL) - { - if (pEntry == pCurEntry) - { - pPrvEntry->pNext = pCurEntry->pNext; - - if(pEntry == pList->pTail) - pList->pTail = pPrvEntry; - - pList->size--; - break; - } - pPrvEntry = pCurEntry; - pCurEntry = pPrvEntry->pNext; - } - - return pCurEntry; -} - -#endif // ___LINK_LIST_H__ // - +#include "../rt2870/link_list.h" diff --git a/drivers/staging/rt3070/md5.h b/drivers/staging/rt3070/md5.h index d85db12170d5..1042a994dc72 100644 --- a/drivers/staging/rt3070/md5.h +++ b/drivers/staging/rt3070/md5.h @@ -1,107 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - md5.h - - Abstract: - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Name Date Modification logs - jan 10-28-03 Initial - Rita 11-23-04 Modify MD5 and SHA-1 -*/ - -#ifndef uint8 -#define uint8 unsigned char -#endif - -#ifndef uint32 -#define uint32 unsigned long int -#endif - - -#ifndef __MD5_H__ -#define __MD5_H__ - -#define MD5_MAC_LEN 16 - -typedef struct _MD5_CTX { - UINT32 Buf[4]; // buffers of four states - UCHAR Input[64]; // input message - UINT32 LenInBitCount[2]; // length counter for input message, 0 up to 64 bits -} MD5_CTX; - -VOID MD5Init(MD5_CTX *pCtx); -VOID MD5Update(MD5_CTX *pCtx, UCHAR *pData, UINT32 LenInBytes); -VOID MD5Final(UCHAR Digest[16], MD5_CTX *pCtx); -VOID MD5Transform(UINT32 Buf[4], UINT32 Mes[16]); - -void md5_mac(u8 *key, size_t key_len, u8 *data, size_t data_len, u8 *mac); -void hmac_md5(u8 *key, size_t key_len, u8 *data, size_t data_len, u8 *mac); - -// -// SHA context -// -typedef struct _SHA_CTX -{ - UINT32 Buf[5]; // buffers of five states - UCHAR Input[80]; // input message - UINT32 LenInBitCount[2]; // length counter for input message, 0 up to 64 bits - -} SHA_CTX; - -VOID SHAInit(SHA_CTX *pCtx); -UCHAR SHAUpdate(SHA_CTX *pCtx, UCHAR *pData, UINT32 LenInBytes); -VOID SHAFinal(SHA_CTX *pCtx, UCHAR Digest[20]); -VOID SHATransform(UINT32 Buf[5], UINT32 Mes[20]); - -#define SHA_DIGEST_LEN 20 -#endif // __MD5_H__ - -/******************************************************************************/ -#ifndef _AES_H -#define _AES_H - -typedef struct -{ - uint32 erk[64]; /* encryption round keys */ - uint32 drk[64]; /* decryption round keys */ - int nr; /* number of rounds */ -} -aes_context; - -int rtmp_aes_set_key( aes_context *ctx, uint8 *key, int nbits ); -void rtmp_aes_encrypt( aes_context *ctx, uint8 input[16], uint8 output[16] ); -void rtmp_aes_decrypt( aes_context *ctx, uint8 input[16], uint8 output[16] ); - -void F(char *password, unsigned char *ssid, int ssidlength, int iterations, int count, unsigned char *output); -int PasswordHash(char *password, unsigned char *ssid, int ssidlength, unsigned char *output); - -#endif /* aes.h */ - +#include "../rt2870/md5.h" diff --git a/drivers/staging/rt3070/mlme.h b/drivers/staging/rt3070/mlme.h index b0035e1fa8ea..773c0edfcea9 100644 --- a/drivers/staging/rt3070/mlme.h +++ b/drivers/staging/rt3070/mlme.h @@ -1,1468 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - mlme.h - - Abstract: - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - John Chang 2003-08-28 Created - John Chang 2004-09-06 modified for RT2600 - -*/ -#ifndef __MLME_H__ -#define __MLME_H__ - -//extern UCHAR BROADCAST_ADDR[]; - -// maximum supported capability information - -// ESS, IBSS, Privacy, Short Preamble, Spectrum mgmt, Short Slot -#define SUPPORTED_CAPABILITY_INFO 0x0533 - -#define END_OF_ARGS -1 -#define LFSR_MASK 0x80000057 -#define MLME_TASK_EXEC_INTV 100/*200*/ // -#define LEAD_TIME 5 -#define MLME_TASK_EXEC_MULTIPLE 10 /*5*/ // MLME_TASK_EXEC_MULTIPLE * MLME_TASK_EXEC_INTV = 1 sec -#define REORDER_EXEC_INTV 100 // 0.1 sec -//#define TBTT_PRELOAD_TIME 384 // usec. LomgPreamble + 24-byte at 1Mbps - -// The definition of Radar detection duration region -#define CE 0 -#define FCC 1 -#define JAP 2 -#define JAP_W53 3 -#define JAP_W56 4 -#define MAX_RD_REGION 5 - -#ifdef NDIS51_MINIPORT -#define BEACON_LOST_TIME 4000 // 2048 msec = 2 sec -#else -#define BEACON_LOST_TIME 4 * OS_HZ // 2048 msec = 2 sec -#endif - -#define DLS_TIMEOUT 1200 // unit: msec -#define AUTH_TIMEOUT 300 // unit: msec -#define ASSOC_TIMEOUT 300 // unit: msec -#define JOIN_TIMEOUT 2 * OS_HZ // unit: msec -#define SHORT_CHANNEL_TIME 90 // unit: msec -#define MIN_CHANNEL_TIME 110 // unit: msec, for dual band scan -#define MAX_CHANNEL_TIME 140 // unit: msec, for single band scan -#define FAST_ACTIVE_SCAN_TIME 30 // Active scan waiting for probe response time -#define CW_MIN_IN_BITS 4 // actual CwMin = 2^CW_MIN_IN_BITS - 1 - - -#ifdef CONFIG_STA_SUPPORT -#ifndef CONFIG_AP_SUPPORT -#define CW_MAX_IN_BITS 10 // actual CwMax = 2^CW_MAX_IN_BITS - 1 -#endif -#endif // CONFIG_STA_SUPPORT // - -#ifdef CONFIG_APSTA_MIXED_SUPPORT -extern UINT32 CW_MAX_IN_BITS; -#endif // CONFIG_APSTA_MIXED_SUPPORT // - -// Note: RSSI_TO_DBM_OFFSET has been changed to variable for new RF (2004-0720). -// SHould not refer to this constant anymore -//#define RSSI_TO_DBM_OFFSET 120 // for RT2530 RSSI-115 = dBm -#define RSSI_FOR_MID_TX_POWER -55 // -55 db is considered mid-distance -#define RSSI_FOR_LOW_TX_POWER -45 // -45 db is considered very short distance and - // eligible to use a lower TX power -#define RSSI_FOR_LOWEST_TX_POWER -30 -//#define MID_TX_POWER_DELTA 0 // 0 db from full TX power upon mid-distance to AP -#define LOW_TX_POWER_DELTA 6 // -3 db from full TX power upon very short distance. 1 grade is 0.5 db -#define LOWEST_TX_POWER_DELTA 16 // -8 db from full TX power upon shortest distance. 1 grade is 0.5 db - -#define RSSI_TRIGGERED_UPON_BELOW_THRESHOLD 0 -#define RSSI_TRIGGERED_UPON_EXCCEED_THRESHOLD 1 -#define RSSI_THRESHOLD_FOR_ROAMING 25 -#define RSSI_DELTA 5 - -// Channel Quality Indication -#define CQI_IS_GOOD(cqi) ((cqi) >= 50) -//#define CQI_IS_FAIR(cqi) (((cqi) >= 20) && ((cqi) < 50)) -#define CQI_IS_POOR(cqi) (cqi < 50) //(((cqi) >= 5) && ((cqi) < 20)) -#define CQI_IS_BAD(cqi) (cqi < 5) -#define CQI_IS_DEAD(cqi) (cqi == 0) - -// weighting factor to calculate Channel quality, total should be 100% -#define RSSI_WEIGHTING 50 -#define TX_WEIGHTING 30 -#define RX_WEIGHTING 20 - -//#define PEER_KEY_NOT_USED 0 -//#define PEER_KEY_64_BIT 64 -//#define PEER_KEY_128_BIT 128 - -//#define PEER_KEY_64BIT_LEN 8 -//#define PEER_KEY_128BIT_LEN 16 - -#define BSS_NOT_FOUND 0xFFFFFFFF - - -#ifdef CONFIG_STA_SUPPORT -#define MAX_LEN_OF_MLME_QUEUE 40 //10 -#endif // CONFIG_STA_SUPPORT // - -#define SCAN_PASSIVE 18 // scan with no probe request, only wait beacon and probe response -#define SCAN_ACTIVE 19 // scan with probe request, and wait beacon and probe response -#define SCAN_CISCO_PASSIVE 20 // Single channel passive scan -#define SCAN_CISCO_ACTIVE 21 // Single channel active scan -#define SCAN_CISCO_NOISE 22 // Single channel passive scan for noise histogram collection -#define SCAN_CISCO_CHANNEL_LOAD 23 // Single channel passive scan for channel load collection -#define FAST_SCAN_ACTIVE 24 // scan with probe request, and wait beacon and probe response - -#ifdef DOT11N_DRAFT3 -#define SCAN_2040_BSS_COEXIST 26 -#endif // DOT11N_DRAFT3 // - -//#define BSS_TABLE_EMPTY(x) ((x).BssNr == 0) -#define MAC_ADDR_IS_GROUP(Addr) (((Addr[0]) & 0x01)) -#define MAC_ADDR_HASH(Addr) (Addr[0] ^ Addr[1] ^ Addr[2] ^ Addr[3] ^ Addr[4] ^ Addr[5]) -#define MAC_ADDR_HASH_INDEX(Addr) (MAC_ADDR_HASH(Addr) % HASH_TABLE_SIZE) -#define TID_MAC_HASH(Addr,TID) (TID^Addr[0] ^ Addr[1] ^ Addr[2] ^ Addr[3] ^ Addr[4] ^ Addr[5]) -#define TID_MAC_HASH_INDEX(Addr,TID) (TID_MAC_HASH(Addr,TID) % HASH_TABLE_SIZE) - -// LED Control -// assoiation ON. one LED ON. another blinking when TX, OFF when idle -// no association, both LED off -#define ASIC_LED_ACT_ON(pAd) RTMP_IO_WRITE32(pAd, MAC_CSR14, 0x00031e46) -#define ASIC_LED_ACT_OFF(pAd) RTMP_IO_WRITE32(pAd, MAC_CSR14, 0x00001e46) - -// bit definition of the 2-byte pBEACON->Capability field -#define CAP_IS_ESS_ON(x) (((x) & 0x0001) != 0) -#define CAP_IS_IBSS_ON(x) (((x) & 0x0002) != 0) -#define CAP_IS_CF_POLLABLE_ON(x) (((x) & 0x0004) != 0) -#define CAP_IS_CF_POLL_REQ_ON(x) (((x) & 0x0008) != 0) -#define CAP_IS_PRIVACY_ON(x) (((x) & 0x0010) != 0) -#define CAP_IS_SHORT_PREAMBLE_ON(x) (((x) & 0x0020) != 0) -#define CAP_IS_PBCC_ON(x) (((x) & 0x0040) != 0) -#define CAP_IS_AGILITY_ON(x) (((x) & 0x0080) != 0) -#define CAP_IS_SPECTRUM_MGMT(x) (((x) & 0x0100) != 0) // 802.11e d9 -#define CAP_IS_QOS(x) (((x) & 0x0200) != 0) // 802.11e d9 -#define CAP_IS_SHORT_SLOT(x) (((x) & 0x0400) != 0) -#define CAP_IS_APSD(x) (((x) & 0x0800) != 0) // 802.11e d9 -#define CAP_IS_IMMED_BA(x) (((x) & 0x1000) != 0) // 802.11e d9 -#define CAP_IS_DSSS_OFDM(x) (((x) & 0x2000) != 0) -#define CAP_IS_DELAY_BA(x) (((x) & 0x4000) != 0) // 802.11e d9 - -#define CAP_GENERATE(ess,ibss,priv,s_pre,s_slot,spectrum) (((ess) ? 0x0001 : 0x0000) | ((ibss) ? 0x0002 : 0x0000) | ((priv) ? 0x0010 : 0x0000) | ((s_pre) ? 0x0020 : 0x0000) | ((s_slot) ? 0x0400 : 0x0000) | ((spectrum) ? 0x0100 : 0x0000)) - -//#define STA_QOS_CAPABILITY 0 // 1-byte. see 802.11e d9.0 for bit definition - -#define ERP_IS_NON_ERP_PRESENT(x) (((x) & 0x01) != 0) // 802.11g -#define ERP_IS_USE_PROTECTION(x) (((x) & 0x02) != 0) // 802.11g -#define ERP_IS_USE_BARKER_PREAMBLE(x) (((x) & 0x04) != 0) // 802.11g - -#define DRS_TX_QUALITY_WORST_BOUND 8// 3 // just test by gary -#define DRS_PENALTY 8 - -#define BA_NOTUSE 2 -//BA Policy subfiled value in ADDBA frame -#define IMMED_BA 1 -#define DELAY_BA 0 - -// BA Initiator subfield in DELBA frame -#define ORIGINATOR 1 -#define RECIPIENT 0 - -// ADDBA Status Code -#define ADDBA_RESULTCODE_SUCCESS 0 -#define ADDBA_RESULTCODE_REFUSED 37 -#define ADDBA_RESULTCODE_INVALID_PARAMETERS 38 - -// DELBA Reason Code -#define DELBA_REASONCODE_QSTA_LEAVING 36 -#define DELBA_REASONCODE_END_BA 37 -#define DELBA_REASONCODE_UNKNOWN_BA 38 -#define DELBA_REASONCODE_TIMEOUT 39 - -// reset all OneSecTx counters -#define RESET_ONE_SEC_TX_CNT(__pEntry) \ -if (((__pEntry)) != NULL) \ -{ \ - (__pEntry)->OneSecTxRetryOkCount = 0; \ - (__pEntry)->OneSecTxFailCount = 0; \ - (__pEntry)->OneSecTxNoRetryOkCount = 0; \ -} - -// -// 802.11 frame formats -// -// HT Capability INFO field in HT Cap IE . -typedef struct PACKED { -#ifdef RT_BIG_ENDIAN - USHORT LSIGTxopProSup:1; - USHORT Forty_Mhz_Intolerant:1; - USHORT PSMP:1; - USHORT CCKmodein40:1; - USHORT AMsduSize:1; - USHORT DelayedBA:1; //rt2860c not support - USHORT RxSTBC:2; - USHORT TxSTBC:1; - USHORT ShortGIfor40:1; //for40MHz - USHORT ShortGIfor20:1; - USHORT GF:1; //green field - USHORT MimoPs:2;//momi power safe - USHORT ChannelWidth:1; - USHORT AdvCoding:1; -#else - USHORT AdvCoding:1; - USHORT ChannelWidth:1; - USHORT MimoPs:2;//momi power safe - USHORT GF:1; //green field - USHORT ShortGIfor20:1; - USHORT ShortGIfor40:1; //for40MHz - USHORT TxSTBC:1; - USHORT RxSTBC:2; - USHORT DelayedBA:1; //rt2860c not support - USHORT AMsduSize:1; // only support as zero - USHORT CCKmodein40:1; - USHORT PSMP:1; - USHORT Forty_Mhz_Intolerant:1; - USHORT LSIGTxopProSup:1; -#endif /* !RT_BIG_ENDIAN */ -} HT_CAP_INFO, *PHT_CAP_INFO; - -// HT Capability INFO field in HT Cap IE . -typedef struct PACKED { -#ifdef RT_BIG_ENDIAN - UCHAR rsv:3;//momi power safe - UCHAR MpduDensity:3; - UCHAR MaxRAmpduFactor:2; -#else - UCHAR MaxRAmpduFactor:2; - UCHAR MpduDensity:3; - UCHAR rsv:3;//momi power safe -#endif /* !RT_BIG_ENDIAN */ -} HT_CAP_PARM, *PHT_CAP_PARM; - -// HT Capability INFO field in HT Cap IE . -typedef struct PACKED { - UCHAR MCSSet[10]; - UCHAR SupRate[2]; // unit : 1Mbps -#ifdef RT_BIG_ENDIAN - UCHAR rsv:3; - UCHAR MpduDensity:1; - UCHAR TxStream:2; - UCHAR TxRxNotEqual:1; - UCHAR TxMCSSetDefined:1; -#else - UCHAR TxMCSSetDefined:1; - UCHAR TxRxNotEqual:1; - UCHAR TxStream:2; - UCHAR MpduDensity:1; - UCHAR rsv:3; -#endif // RT_BIG_ENDIAN // - UCHAR rsv3[3]; -} HT_MCS_SET, *PHT_MCS_SET; - -// HT Capability INFO field in HT Cap IE . -typedef struct PACKED { -#ifdef RT_BIG_ENDIAN - USHORT rsv2:4; - USHORT RDGSupport:1; //reverse Direction Grant support - USHORT PlusHTC:1; //+HTC control field support - USHORT MCSFeedback:2; //0:no MCS feedback, 2:unsolicited MCS feedback, 3:Full MCS feedback, 1:rsv. - USHORT rsv:5;//momi power safe - USHORT TranTime:2; - USHORT Pco:1; -#else - USHORT Pco:1; - USHORT TranTime:2; - USHORT rsv:5;//momi power safe - USHORT MCSFeedback:2; //0:no MCS feedback, 2:unsolicited MCS feedback, 3:Full MCS feedback, 1:rsv. - USHORT PlusHTC:1; //+HTC control field support - USHORT RDGSupport:1; //reverse Direction Grant support - USHORT rsv2:4; -#endif /* RT_BIG_ENDIAN */ -} EXT_HT_CAP_INFO, *PEXT_HT_CAP_INFO; - -// HT Beamforming field in HT Cap IE . -typedef struct PACKED _HT_BF_CAP{ -#ifdef RT_BIG_ENDIAN - ULONG rsv:3; - ULONG ChanEstimation:2; - ULONG CSIRowBFSup:2; - ULONG ComSteerBFAntSup:2; - ULONG NoComSteerBFAntSup:2; - ULONG CSIBFAntSup:2; - ULONG MinGrouping:2; - ULONG ExpComBF:2; - ULONG ExpNoComBF:2; - ULONG ExpCSIFbk:2; - ULONG ExpComSteerCapable:1; - ULONG ExpNoComSteerCapable:1; - ULONG ExpCSICapable:1; - ULONG Calibration:2; - ULONG ImpTxBFCapable:1; - ULONG TxNDPCapable:1; - ULONG RxNDPCapable:1; - ULONG TxSoundCapable:1; - ULONG RxSoundCapable:1; - ULONG TxBFRecCapable:1; -#else - ULONG TxBFRecCapable:1; - ULONG RxSoundCapable:1; - ULONG TxSoundCapable:1; - ULONG RxNDPCapable:1; - ULONG TxNDPCapable:1; - ULONG ImpTxBFCapable:1; - ULONG Calibration:2; - ULONG ExpCSICapable:1; - ULONG ExpNoComSteerCapable:1; - ULONG ExpComSteerCapable:1; - ULONG ExpCSIFbk:2; - ULONG ExpNoComBF:2; - ULONG ExpComBF:2; - ULONG MinGrouping:2; - ULONG CSIBFAntSup:2; - ULONG NoComSteerBFAntSup:2; - ULONG ComSteerBFAntSup:2; - ULONG CSIRowBFSup:2; - ULONG ChanEstimation:2; - ULONG rsv:3; -#endif // RT_BIG_ENDIAN // -} HT_BF_CAP, *PHT_BF_CAP; - -// HT antenna selection field in HT Cap IE . -typedef struct PACKED _HT_AS_CAP{ -#ifdef RT_BIG_ENDIAN - UCHAR rsv:1; - UCHAR TxSoundPPDU:1; - UCHAR RxASel:1; - UCHAR AntIndFbk:1; - UCHAR ExpCSIFbk:1; - UCHAR AntIndFbkTxASEL:1; - UCHAR ExpCSIFbkTxASEL:1; - UCHAR AntSelect:1; -#else - UCHAR AntSelect:1; - UCHAR ExpCSIFbkTxASEL:1; - UCHAR AntIndFbkTxASEL:1; - UCHAR ExpCSIFbk:1; - UCHAR AntIndFbk:1; - UCHAR RxASel:1; - UCHAR TxSoundPPDU:1; - UCHAR rsv:1; -#endif // RT_BIG_ENDIAN // -} HT_AS_CAP, *PHT_AS_CAP; - -// Draft 1.0 set IE length 26, but is extensible.. -#define SIZE_HT_CAP_IE 26 -// The structure for HT Capability IE. -typedef struct PACKED _HT_CAPABILITY_IE{ - HT_CAP_INFO HtCapInfo; - HT_CAP_PARM HtCapParm; -// HT_MCS_SET HtMCSSet; - UCHAR MCSSet[16]; - EXT_HT_CAP_INFO ExtHtCapInfo; - HT_BF_CAP TxBFCap; // beamforming cap. rt2860c not support beamforming. - HT_AS_CAP ASCap; //antenna selection. -} HT_CAPABILITY_IE, *PHT_CAPABILITY_IE; - - -// 802.11n draft3 related structure definitions. -// 7.3.2.60 -#define dot11OBSSScanPassiveDwell 20 // in TU. min amount of time that the STA continously scans each channel when performing an active OBSS scan. -#define dot11OBSSScanActiveDwell 10 // in TU.min amount of time that the STA continously scans each channel when performing an passive OBSS scan. -#define dot11BSSWidthTriggerScanInterval 300 // in sec. max interval between scan operations to be performed to detect BSS channel width trigger events. -#define dot11OBSSScanPassiveTotalPerChannel 200 // in TU. min total amount of time that the STA scans each channel when performing a passive OBSS scan. -#define dot11OBSSScanActiveTotalPerChannel 20 //in TU. min total amount of time that the STA scans each channel when performing a active OBSS scan -#define dot11BSSWidthChannelTransactionDelayFactor 5 // min ratio between the delay time in performing a switch from 20MHz BSS to 20/40 BSS operation and the maxima - // interval between overlapping BSS scan operations. -#define dot11BSSScanActivityThreshold 25 // in %%, max total time that a STA may be active on the medium during a period of - // (dot11BSSWidthChannelTransactionDelayFactor * dot11BSSWidthTriggerScanInterval) seconds without - // being obligated to perform OBSS Scan operations. default is 25(== 0.25%) - -typedef struct PACKED _OVERLAP_BSS_SCAN_IE{ - USHORT ScanPassiveDwell; - USHORT ScanActiveDwell; - USHORT TriggerScanInt; // Trigger scan interval - USHORT PassiveTalPerChannel; // passive total per channel - USHORT ActiveTalPerChannel; // active total per channel - USHORT DelayFactor; // BSS width channel transition delay factor - USHORT ScanActThre; // Scan Activity threshold -}OVERLAP_BSS_SCAN_IE, *POVERLAP_BSS_SCAN_IE; - - -// 7.3.2.56. 20/40 Coexistence element used in Element ID = 72 = IE_2040_BSS_COEXIST -typedef union PACKED _BSS_2040_COEXIST_IE{ - struct PACKED { - #ifdef RT_BIG_ENDIAN - UCHAR rsv:5; - UCHAR BSS20WidthReq:1; - UCHAR Intolerant40:1; - UCHAR InfoReq:1; - #else - UCHAR InfoReq:1; - UCHAR Intolerant40:1; // Inter-BSS. set 1 when prohibits a receiving BSS from operating as a 20/40 Mhz BSS. - UCHAR BSS20WidthReq:1; // Intra-BSS set 1 when prohibits a receiving AP from operating its BSS as a 20/40MHz BSS. - UCHAR rsv:5; -#endif // RT_BIG_ENDIAN // - } field; - UCHAR word; -} BSS_2040_COEXIST_IE, *PBSS_2040_COEXIST_IE; - - -typedef struct _TRIGGER_EVENTA{ - BOOLEAN bValid; - UCHAR BSSID[6]; - UCHAR RegClass; // Regulatory Class - USHORT Channel; - ULONG CDCounter; // Maintain a seperate count down counter for each Event A. -} TRIGGER_EVENTA, *PTRIGGER_EVENTA; - -// 20/40 trigger event table -// If one Event A delete or created, or if Event B is detected or not detected, STA should send 2040BSSCoexistence to AP. -#define MAX_TRIGGER_EVENT 64 -typedef struct _TRIGGER_EVENT_TAB{ - UCHAR EventANo; - TRIGGER_EVENTA EventA[MAX_TRIGGER_EVENT]; - ULONG EventBCountDown; // Count down counter for Event B. -} TRIGGER_EVENT_TAB, *PTRIGGER_EVENT_TAB; - -// 7.3.27 20/40 Bss Coexistence Mgmt capability used in extended capabilities information IE( ID = 127 = IE_EXT_CAPABILITY). -// This is the first octet and was defined in 802.11n D3.03 and 802.11yD9.0 -typedef struct PACKED _EXT_CAP_INFO_ELEMENT{ -#ifdef RT_BIG_ENDIAN - UCHAR rsv2:5; - UCHAR ExtendChannelSwitch:1; - UCHAR rsv:1; - UCHAR BssCoexistMgmtSupport:1; -#else - UCHAR BssCoexistMgmtSupport:1; - UCHAR rsv:1; - UCHAR ExtendChannelSwitch:1; - UCHAR rsv2:5; -#endif // RT_BIG_ENDIAN // -}EXT_CAP_INFO_ELEMENT, *PEXT_CAP_INFO_ELEMENT; - - -// 802.11n 7.3.2.61 -typedef struct PACKED _BSS_2040_COEXIST_ELEMENT{ - UCHAR ElementID; // ID = IE_2040_BSS_COEXIST = 72 - UCHAR Len; - BSS_2040_COEXIST_IE BssCoexistIe; -}BSS_2040_COEXIST_ELEMENT, *PBSS_2040_COEXIST_ELEMENT; - - -//802.11n 7.3.2.59 -typedef struct PACKED _BSS_2040_INTOLERANT_CH_REPORT{ - UCHAR ElementID; // ID = IE_2040_BSS_INTOLERANT_REPORT = 73 - UCHAR Len; - UCHAR RegulatoryClass; - UCHAR ChList[0]; -}BSS_2040_INTOLERANT_CH_REPORT, *PBSS_2040_INTOLERANT_CH_REPORT; - - -// The structure for channel switch annoucement IE. This is in 802.11n D3.03 -typedef struct PACKED _CHA_SWITCH_ANNOUNCE_IE{ - UCHAR SwitchMode; //channel switch mode - UCHAR NewChannel; // - UCHAR SwitchCount; // -} CHA_SWITCH_ANNOUNCE_IE, *PCHA_SWITCH_ANNOUNCE_IE; - - -// The structure for channel switch annoucement IE. This is in 802.11n D3.03 -typedef struct PACKED _SEC_CHA_OFFSET_IE{ - UCHAR SecondaryChannelOffset; // 1: Secondary above, 3: Secondary below, 0: no Secondary -} SEC_CHA_OFFSET_IE, *PSEC_CHA_OFFSET_IE; - - -// This structure is extracted from struct RT_HT_CAPABILITY -typedef struct { - BOOLEAN bHtEnable; // If we should use ht rate. - BOOLEAN bPreNHt; // If we should use ht rate. - //Substract from HT Capability IE - UCHAR MCSSet[16]; //only supoort MCS=0-15,32 , -} RT_HT_PHY_INFO, *PRT_HT_PHY_INFO; - -//This structure substracts ralink supports from all 802.11n-related features. -//Features not listed here but contained in 802.11n spec are not supported in rt2860. -typedef struct { -#ifdef RT_BIG_ENDIAN - USHORT rsv:5; - USHORT AmsduSize:1; // Max receiving A-MSDU size - USHORT AmsduEnable:1; // Enable to transmit A-MSDU. Suggest disable. We should use A-MPDU to gain best benifit of 802.11n - USHORT RxSTBC:2; // 2 bits - USHORT TxSTBC:1; - USHORT ShortGIfor40:1; //for40MHz - USHORT ShortGIfor20:1; - USHORT GF:1; //green field - USHORT MimoPs:2;//mimo power safe MMPS_ - USHORT ChannelWidth:1; -#else - USHORT ChannelWidth:1; - USHORT MimoPs:2;//mimo power safe MMPS_ - USHORT GF:1; //green field - USHORT ShortGIfor20:1; - USHORT ShortGIfor40:1; //for40MHz - USHORT TxSTBC:1; - USHORT RxSTBC:2; // 2 bits - USHORT AmsduEnable:1; // Enable to transmit A-MSDU. Suggest disable. We should use A-MPDU to gain best benifit of 802.11n - USHORT AmsduSize:1; // Max receiving A-MSDU size - USHORT rsv:5; -#endif - - //Substract from Addiont HT INFO IE -#ifdef RT_BIG_ENDIAN - UCHAR RecomWidth:1; - UCHAR ExtChanOffset:2; // Please not the difference with following UCHAR NewExtChannelOffset; from 802.11n - UCHAR MpduDensity:3; - UCHAR MaxRAmpduFactor:2; -#else - UCHAR MaxRAmpduFactor:2; - UCHAR MpduDensity:3; - UCHAR ExtChanOffset:2; // Please not the difference with following UCHAR NewExtChannelOffset; from 802.11n - UCHAR RecomWidth:1; -#endif - -#ifdef RT_BIG_ENDIAN - USHORT rsv2:11; - USHORT OBSS_NonHTExist:1; - USHORT rsv3:1; - USHORT NonGfPresent:1; - USHORT OperaionMode:2; -#else - USHORT OperaionMode:2; - USHORT NonGfPresent:1; - USHORT rsv3:1; - USHORT OBSS_NonHTExist:1; - USHORT rsv2:11; -#endif - - // New Extension Channel Offset IE - UCHAR NewExtChannelOffset; - // Extension Capability IE = 127 - UCHAR BSSCoexist2040; -} RT_HT_CAPABILITY, *PRT_HT_CAPABILITY; - -// field in Addtional HT Information IE . -typedef struct PACKED { -#ifdef RT_BIG_ENDIAN - UCHAR SerInterGranu:3; - UCHAR S_PSMPSup:1; - UCHAR RifsMode:1; - UCHAR RecomWidth:1; - UCHAR ExtChanOffset:2; -#else - UCHAR ExtChanOffset:2; - UCHAR RecomWidth:1; - UCHAR RifsMode:1; - UCHAR S_PSMPSup:1; //Indicate support for scheduled PSMP - UCHAR SerInterGranu:3; //service interval granularity -#endif -} ADD_HTINFO, *PADD_HTINFO; - -typedef struct PACKED{ -#ifdef RT_BIG_ENDIAN - USHORT rsv2:11; - USHORT OBSS_NonHTExist:1; - USHORT rsv:1; - USHORT NonGfPresent:1; - USHORT OperaionMode:2; -#else - USHORT OperaionMode:2; - USHORT NonGfPresent:1; - USHORT rsv:1; - USHORT OBSS_NonHTExist:1; - USHORT rsv2:11; -#endif -} ADD_HTINFO2, *PADD_HTINFO2; - - -// TODO: Need sync with spec about the definition of StbcMcs. In Draft 3.03, it's reserved. -typedef struct PACKED{ -#ifdef RT_BIG_ENDIAN - USHORT rsv:4; - USHORT PcoPhase:1; - USHORT PcoActive:1; - USHORT LsigTxopProt:1; - USHORT STBCBeacon:1; - USHORT DualCTSProtect:1; - USHORT DualBeacon:1; - USHORT StbcMcs:6; -#else - USHORT StbcMcs:6; - USHORT DualBeacon:1; - USHORT DualCTSProtect:1; - USHORT STBCBeacon:1; - USHORT LsigTxopProt:1; // L-SIG TXOP protection full support - USHORT PcoActive:1; - USHORT PcoPhase:1; - USHORT rsv:4; -#endif // RT_BIG_ENDIAN // -} ADD_HTINFO3, *PADD_HTINFO3; - -#define SIZE_ADD_HT_INFO_IE 22 -typedef struct PACKED{ - UCHAR ControlChan; - ADD_HTINFO AddHtInfo; - ADD_HTINFO2 AddHtInfo2; - ADD_HTINFO3 AddHtInfo3; - UCHAR MCSSet[16]; // Basic MCS set -} ADD_HT_INFO_IE, *PADD_HT_INFO_IE; - -typedef struct PACKED{ - UCHAR NewExtChanOffset; -} NEW_EXT_CHAN_IE, *PNEW_EXT_CHAN_IE; - - -// 4-byte HTC field. maybe included in any frame except non-QOS data frame. The Order bit must set 1. -typedef struct PACKED { -#ifdef RT_BIG_ENDIAN - UINT32 RDG:1; //RDG / More PPDU - UINT32 ACConstraint:1; //feedback request - UINT32 rsv:5; //calibration sequence - UINT32 ZLFAnnouce:1; // ZLF announcement - UINT32 CSISTEERING:2; //CSI/ STEERING - UINT32 FBKReq:2; //feedback request - UINT32 CalSeq:2; //calibration sequence - UINT32 CalPos:2; // calibration position - UINT32 MFBorASC:7; //Link adaptation feedback containing recommended MCS. 0x7f for no feedback or not available - UINT32 MFS:3; //SET to the received value of MRS. 0x111 for unsolicited MFB. - UINT32 MRSorASI:3; // MRQ Sequence identifier. unchanged during entire procedure. 0x000-0x110. - UINT32 MRQ:1; //MCS feedback. Request for a MCS feedback - UINT32 TRQ:1; //sounding request - UINT32 MA:1; //management action payload exist in (QoS Null+HTC) -#else - UINT32 MA:1; //management action payload exist in (QoS Null+HTC) - UINT32 TRQ:1; //sounding request - UINT32 MRQ:1; //MCS feedback. Request for a MCS feedback - UINT32 MRSorASI:3; // MRQ Sequence identifier. unchanged during entire procedure. 0x000-0x110. - UINT32 MFS:3; //SET to the received value of MRS. 0x111 for unsolicited MFB. - UINT32 MFBorASC:7; //Link adaptation feedback containing recommended MCS. 0x7f for no feedback or not available - UINT32 CalPos:2; // calibration position - UINT32 CalSeq:2; //calibration sequence - UINT32 FBKReq:2; //feedback request - UINT32 CSISTEERING:2; //CSI/ STEERING - UINT32 ZLFAnnouce:1; // ZLF announcement - UINT32 rsv:5; //calibration sequence - UINT32 ACConstraint:1; //feedback request - UINT32 RDG:1; //RDG / More PPDU -#endif /* !RT_BIG_ENDIAN */ -} HT_CONTROL, *PHT_CONTROL; - -// 2-byte QOS CONTROL field -typedef struct PACKED { -#ifdef RT_BIG_ENDIAN - USHORT Txop_QueueSize:8; - USHORT AMsduPresent:1; - USHORT AckPolicy:2; //0: normal ACK 1:No ACK 2:scheduled under MTBA/PSMP 3: BA - USHORT EOSP:1; - USHORT TID:4; -#else - USHORT TID:4; - USHORT EOSP:1; - USHORT AckPolicy:2; //0: normal ACK 1:No ACK 2:scheduled under MTBA/PSMP 3: BA - USHORT AMsduPresent:1; - USHORT Txop_QueueSize:8; -#endif /* !RT_BIG_ENDIAN */ -} QOS_CONTROL, *PQOS_CONTROL; - -// 2-byte Frame control field -typedef struct PACKED { -#ifdef RT_BIG_ENDIAN - USHORT Order:1; // Strict order expected - USHORT Wep:1; // Wep data - USHORT MoreData:1; // More data bit - USHORT PwrMgmt:1; // Power management bit - USHORT Retry:1; // Retry status bit - USHORT MoreFrag:1; // More fragment bit - USHORT FrDs:1; // From DS indication - USHORT ToDs:1; // To DS indication - USHORT SubType:4; // MSDU subtype - USHORT Type:2; // MSDU type - USHORT Ver:2; // Protocol version -#else - USHORT Ver:2; // Protocol version - USHORT Type:2; // MSDU type - USHORT SubType:4; // MSDU subtype - USHORT ToDs:1; // To DS indication - USHORT FrDs:1; // From DS indication - USHORT MoreFrag:1; // More fragment bit - USHORT Retry:1; // Retry status bit - USHORT PwrMgmt:1; // Power management bit - USHORT MoreData:1; // More data bit - USHORT Wep:1; // Wep data - USHORT Order:1; // Strict order expected -#endif /* !RT_BIG_ENDIAN */ -} FRAME_CONTROL, *PFRAME_CONTROL; - -typedef struct PACKED _HEADER_802_11 { - FRAME_CONTROL FC; - USHORT Duration; - UCHAR Addr1[MAC_ADDR_LEN]; - UCHAR Addr2[MAC_ADDR_LEN]; - UCHAR Addr3[MAC_ADDR_LEN]; -#ifdef RT_BIG_ENDIAN - USHORT Sequence:12; - USHORT Frag:4; -#else - USHORT Frag:4; - USHORT Sequence:12; -#endif /* !RT_BIG_ENDIAN */ - UCHAR Octet[0]; -} HEADER_802_11, *PHEADER_802_11; - -typedef struct PACKED _FRAME_802_11 { - HEADER_802_11 Hdr; - UCHAR Octet[1]; -} FRAME_802_11, *PFRAME_802_11; - -// QoSNull embedding of management action. When HT Control MA field set to 1. -typedef struct PACKED _MA_BODY { - UCHAR Category; - UCHAR Action; - UCHAR Octet[1]; -} MA_BODY, *PMA_BODY; - -typedef struct PACKED _HEADER_802_3 { - UCHAR DAAddr1[MAC_ADDR_LEN]; - UCHAR SAAddr2[MAC_ADDR_LEN]; - UCHAR Octet[2]; -} HEADER_802_3, *PHEADER_802_3; -////Block ACK related format -// 2-byte BA Parameter field in DELBA frames to terminate an already set up bA -typedef struct PACKED{ -#ifdef RT_BIG_ENDIAN - USHORT TID:4; // value of TC os TS - USHORT Initiator:1; // 1: originator 0:recipient - USHORT Rsv:11; // always set to 0 -#else - USHORT Rsv:11; // always set to 0 - USHORT Initiator:1; // 1: originator 0:recipient - USHORT TID:4; // value of TC os TS -#endif /* !RT_BIG_ENDIAN */ -} DELBA_PARM, *PDELBA_PARM; - -// 2-byte BA Parameter Set field in ADDBA frames to signal parm for setting up a BA -typedef struct PACKED { -#ifdef RT_BIG_ENDIAN - USHORT BufSize:10; // number of buffe of size 2304 octetsr - USHORT TID:4; // value of TC os TS - USHORT BAPolicy:1; // 1: immediately BA 0:delayed BA - USHORT AMSDUSupported:1; // 0: not permitted 1: permitted -#else - USHORT AMSDUSupported:1; // 0: not permitted 1: permitted - USHORT BAPolicy:1; // 1: immediately BA 0:delayed BA - USHORT TID:4; // value of TC os TS - USHORT BufSize:10; // number of buffe of size 2304 octetsr -#endif /* !RT_BIG_ENDIAN */ -} BA_PARM, *PBA_PARM; - -// 2-byte BA Starting Seq CONTROL field -typedef union PACKED { - struct PACKED { -#ifdef RT_BIG_ENDIAN - USHORT StartSeq:12; // sequence number of the 1st MSDU for which this BAR is sent - USHORT FragNum:4; // always set to 0 -#else - USHORT FragNum:4; // always set to 0 - USHORT StartSeq:12; // sequence number of the 1st MSDU for which this BAR is sent -#endif /* RT_BIG_ENDIAN */ - } field; - USHORT word; -} BASEQ_CONTROL, *PBASEQ_CONTROL; - -//BAControl and BARControl are the same -// 2-byte BA CONTROL field in BA frame -typedef struct PACKED { -#ifdef RT_BIG_ENDIAN - USHORT TID:4; - USHORT Rsv:9; - USHORT Compressed:1; - USHORT MTID:1; //EWC V1.24 - USHORT ACKPolicy:1; // only related to N-Delayed BA. But not support in RT2860b. 0:NormalACK 1:No ACK -#else - USHORT ACKPolicy:1; // only related to N-Delayed BA. But not support in RT2860b. 0:NormalACK 1:No ACK - USHORT MTID:1; //EWC V1.24 - USHORT Compressed:1; - USHORT Rsv:9; - USHORT TID:4; -#endif /* !RT_BIG_ENDIAN */ -} BA_CONTROL, *PBA_CONTROL; - -// 2-byte BAR CONTROL field in BAR frame -typedef struct PACKED { -#ifdef RT_BIG_ENDIAN - USHORT TID:4; - USHORT Rsv1:9; - USHORT Compressed:1; - USHORT MTID:1; //if this bit1, use FRAME_MTBA_REQ, if 0, use FRAME_BA_REQ - USHORT ACKPolicy:1; -#else - USHORT ACKPolicy:1; // 0:normal ack, 1:no ack. - USHORT MTID:1; //if this bit1, use FRAME_MTBA_REQ, if 0, use FRAME_BA_REQ - USHORT Compressed:1; - USHORT Rsv1:9; - USHORT TID:4; -#endif /* !RT_BIG_ENDIAN */ -} BAR_CONTROL, *PBAR_CONTROL; - -// BARControl in MTBAR frame -typedef struct PACKED { -#ifdef RT_BIG_ENDIAN - USHORT NumTID:4; - USHORT Rsv1:9; - USHORT Compressed:1; - USHORT MTID:1; - USHORT ACKPolicy:1; -#else - USHORT ACKPolicy:1; - USHORT MTID:1; - USHORT Compressed:1; - USHORT Rsv1:9; - USHORT NumTID:4; -#endif /* !RT_BIG_ENDIAN */ -} MTBAR_CONTROL, *PMTBAR_CONTROL; - -typedef struct PACKED { -#ifdef RT_BIG_ENDIAN - USHORT TID:4; - USHORT Rsv1:12; -#else - USHORT Rsv1:12; - USHORT TID:4; -#endif /* !RT_BIG_ENDIAN */ -} PER_TID_INFO, *PPER_TID_INFO; - -typedef struct { - PER_TID_INFO PerTID; - BASEQ_CONTROL BAStartingSeq; -} EACH_TID, *PEACH_TID; - - -typedef struct PACKED _PSPOLL_FRAME { - FRAME_CONTROL FC; - USHORT Aid; - UCHAR Bssid[MAC_ADDR_LEN]; - UCHAR Ta[MAC_ADDR_LEN]; -} PSPOLL_FRAME, *PPSPOLL_FRAME; - -typedef struct PACKED _RTS_FRAME { - FRAME_CONTROL FC; - USHORT Duration; - UCHAR Addr1[MAC_ADDR_LEN]; - UCHAR Addr2[MAC_ADDR_LEN]; -}RTS_FRAME, *PRTS_FRAME; - -// BAREQ AND MTBAREQ have the same subtype BAR, 802.11n BAR use compressed bitmap. -typedef struct PACKED _FRAME_BA_REQ { - FRAME_CONTROL FC; - USHORT Duration; - UCHAR Addr1[MAC_ADDR_LEN]; - UCHAR Addr2[MAC_ADDR_LEN]; - BAR_CONTROL BARControl; - BASEQ_CONTROL BAStartingSeq; -} FRAME_BA_REQ, *PFRAME_BA_REQ; - -typedef struct PACKED _FRAME_MTBA_REQ { - FRAME_CONTROL FC; - USHORT Duration; - UCHAR Addr1[MAC_ADDR_LEN]; - UCHAR Addr2[MAC_ADDR_LEN]; - MTBAR_CONTROL MTBARControl; - PER_TID_INFO PerTIDInfo; - BASEQ_CONTROL BAStartingSeq; -} FRAME_MTBA_REQ, *PFRAME_MTBA_REQ; - -// Compressed format is mandantory in HT STA -typedef struct PACKED _FRAME_MTBA { - FRAME_CONTROL FC; - USHORT Duration; - UCHAR Addr1[MAC_ADDR_LEN]; - UCHAR Addr2[MAC_ADDR_LEN]; - BA_CONTROL BAControl; - BASEQ_CONTROL BAStartingSeq; - UCHAR BitMap[8]; -} FRAME_MTBA, *PFRAME_MTBA; - -typedef struct PACKED _FRAME_PSMP_ACTION { - HEADER_802_11 Hdr; - UCHAR Category; - UCHAR Action; - UCHAR Psmp; // 7.3.1.25 -} FRAME_PSMP_ACTION, *PFRAME_PSMP_ACTION; - -typedef struct PACKED _FRAME_ACTION_HDR { - HEADER_802_11 Hdr; - UCHAR Category; - UCHAR Action; -} FRAME_ACTION_HDR, *PFRAME_ACTION_HDR; - -//Action Frame -//Action Frame Category:Spectrum, Action:Channel Switch. 7.3.2.20 -typedef struct PACKED _CHAN_SWITCH_ANNOUNCE { - UCHAR ElementID; // ID = IE_CHANNEL_SWITCH_ANNOUNCEMENT = 37 - UCHAR Len; - CHA_SWITCH_ANNOUNCE_IE CSAnnounceIe; -} CHAN_SWITCH_ANNOUNCE, *PCHAN_SWITCH_ANNOUNCE; - - -//802.11n : 7.3.2.20a -typedef struct PACKED _SECOND_CHAN_OFFSET { - UCHAR ElementID; // ID = IE_SECONDARY_CH_OFFSET = 62 - UCHAR Len; - SEC_CHA_OFFSET_IE SecChOffsetIe; -} SECOND_CHAN_OFFSET, *PSECOND_CHAN_OFFSET; - - -typedef struct PACKED _FRAME_SPETRUM_CS { - HEADER_802_11 Hdr; - UCHAR Category; - UCHAR Action; - CHAN_SWITCH_ANNOUNCE CSAnnounce; - SECOND_CHAN_OFFSET SecondChannel; -} FRAME_SPETRUM_CS, *PFRAME_SPETRUM_CS; - - -typedef struct PACKED _FRAME_ADDBA_REQ { - HEADER_802_11 Hdr; - UCHAR Category; - UCHAR Action; - UCHAR Token; // 1 - BA_PARM BaParm; // 2 - 10 - USHORT TimeOutValue; // 0 - 0 - BASEQ_CONTROL BaStartSeq; // 0-0 -} FRAME_ADDBA_REQ, *PFRAME_ADDBA_REQ; - -typedef struct PACKED _FRAME_ADDBA_RSP { - HEADER_802_11 Hdr; - UCHAR Category; - UCHAR Action; - UCHAR Token; - USHORT StatusCode; - BA_PARM BaParm; //0 - 2 - USHORT TimeOutValue; -} FRAME_ADDBA_RSP, *PFRAME_ADDBA_RSP; - -typedef struct PACKED _FRAME_DELBA_REQ { - HEADER_802_11 Hdr; - UCHAR Category; - UCHAR Action; - DELBA_PARM DelbaParm; - USHORT ReasonCode; -} FRAME_DELBA_REQ, *PFRAME_DELBA_REQ; - - -//7.2.1.7 -typedef struct PACKED _FRAME_BAR { - FRAME_CONTROL FC; - USHORT Duration; - UCHAR Addr1[MAC_ADDR_LEN]; - UCHAR Addr2[MAC_ADDR_LEN]; - BAR_CONTROL BarControl; - BASEQ_CONTROL StartingSeq; -} FRAME_BAR, *PFRAME_BAR; - -//7.2.1.7 -typedef struct PACKED _FRAME_BA { - FRAME_CONTROL FC; - USHORT Duration; - UCHAR Addr1[MAC_ADDR_LEN]; - UCHAR Addr2[MAC_ADDR_LEN]; - BAR_CONTROL BarControl; - BASEQ_CONTROL StartingSeq; - UCHAR bitmask[8]; -} FRAME_BA, *PFRAME_BA; - - -// Radio Measuement Request Frame Format -typedef struct PACKED _FRAME_RM_REQ_ACTION { - HEADER_802_11 Hdr; - UCHAR Category; - UCHAR Action; - UCHAR Token; - USHORT Repetition; - UCHAR data[0]; -} FRAME_RM_REQ_ACTION, *PFRAME_RM_REQ_ACTION; - -typedef struct PACKED { - UCHAR ID; - UCHAR Length; - UCHAR ChannelSwitchMode; - UCHAR NewRegClass; - UCHAR NewChannelNum; - UCHAR ChannelSwitchCount; -} HT_EXT_CHANNEL_SWITCH_ANNOUNCEMENT_IE, *PHT_EXT_CHANNEL_SWITCH_ANNOUNCEMENT_IE; - - -// -// _Limit must be the 2**n - 1 -// _SEQ1 , _SEQ2 must be within 0 ~ _Limit -// -#define SEQ_STEPONE(_SEQ1, _SEQ2, _Limit) ((_SEQ1 == ((_SEQ2+1) & _Limit))) -#define SEQ_SMALLER(_SEQ1, _SEQ2, _Limit) (((_SEQ1-_SEQ2) & ((_Limit+1)>>1))) -#define SEQ_LARGER(_SEQ1, _SEQ2, _Limit) ((_SEQ1 != _SEQ2) && !(((_SEQ1-_SEQ2) & ((_Limit+1)>>1)))) -#define SEQ_WITHIN_WIN(_SEQ1, _SEQ2, _WIN, _Limit) (SEQ_LARGER(_SEQ1, _SEQ2, _Limit) && \ - SEQ_SMALLER(_SEQ1, ((_SEQ2+_WIN+1)&_Limit), _Limit)) - -// -// Contention-free parameter (without ID and Length) -// -typedef struct PACKED { - BOOLEAN bValid; // 1: variable contains valid value - UCHAR CfpCount; - UCHAR CfpPeriod; - USHORT CfpMaxDuration; - USHORT CfpDurRemaining; -} CF_PARM, *PCF_PARM; - -typedef struct _CIPHER_SUITE { - NDIS_802_11_ENCRYPTION_STATUS PairCipher; // Unicast cipher 1, this one has more secured cipher suite - NDIS_802_11_ENCRYPTION_STATUS PairCipherAux; // Unicast cipher 2 if AP announce two unicast cipher suite - NDIS_802_11_ENCRYPTION_STATUS GroupCipher; // Group cipher - USHORT RsnCapability; // RSN capability from beacon - BOOLEAN bMixMode; // Indicate Pair & Group cipher might be different -} CIPHER_SUITE, *PCIPHER_SUITE; - -// EDCA configuration from AP's BEACON/ProbeRsp -typedef struct { - BOOLEAN bValid; // 1: variable contains valid value - BOOLEAN bAdd; // 1: variable contains valid value - BOOLEAN bQAck; - BOOLEAN bQueueRequest; - BOOLEAN bTxopRequest; - BOOLEAN bAPSDCapable; -// BOOLEAN bMoreDataAck; - UCHAR EdcaUpdateCount; - UCHAR Aifsn[4]; // 0:AC_BK, 1:AC_BE, 2:AC_VI, 3:AC_VO - UCHAR Cwmin[4]; - UCHAR Cwmax[4]; - USHORT Txop[4]; // in unit of 32-us - BOOLEAN bACM[4]; // 1: Admission Control of AC_BK is mandattory -} EDCA_PARM, *PEDCA_PARM; - -// QBSS LOAD information from QAP's BEACON/ProbeRsp -typedef struct { - BOOLEAN bValid; // 1: variable contains valid value - USHORT StaNum; - UCHAR ChannelUtilization; - USHORT RemainingAdmissionControl; // in unit of 32-us -} QBSS_LOAD_PARM, *PQBSS_LOAD_PARM; - -// QBSS Info field in QSTA's assoc req -typedef struct PACKED { -#ifdef RT_BIG_ENDIAN - UCHAR Rsv2:1; - UCHAR MaxSPLength:2; - UCHAR Rsv1:1; - UCHAR UAPSD_AC_BE:1; - UCHAR UAPSD_AC_BK:1; - UCHAR UAPSD_AC_VI:1; - UCHAR UAPSD_AC_VO:1; -#else - UCHAR UAPSD_AC_VO:1; - UCHAR UAPSD_AC_VI:1; - UCHAR UAPSD_AC_BK:1; - UCHAR UAPSD_AC_BE:1; - UCHAR Rsv1:1; - UCHAR MaxSPLength:2; - UCHAR Rsv2:1; -#endif /* !RT_BIG_ENDIAN */ -} QBSS_STA_INFO_PARM, *PQBSS_STA_INFO_PARM; - -// QBSS Info field in QAP's Beacon/ProbeRsp -typedef struct PACKED { -#ifdef RT_BIG_ENDIAN - UCHAR UAPSD:1; - UCHAR Rsv:3; - UCHAR ParamSetCount:4; -#else - UCHAR ParamSetCount:4; - UCHAR Rsv:3; - UCHAR UAPSD:1; -#endif /* !RT_BIG_ENDIAN */ -} QBSS_AP_INFO_PARM, *PQBSS_AP_INFO_PARM; - -// QOS Capability reported in QAP's BEACON/ProbeRsp -// QOS Capability sent out in QSTA's AssociateReq/ReAssociateReq -typedef struct { - BOOLEAN bValid; // 1: variable contains valid value - BOOLEAN bQAck; - BOOLEAN bQueueRequest; - BOOLEAN bTxopRequest; -// BOOLEAN bMoreDataAck; - UCHAR EdcaUpdateCount; -} QOS_CAPABILITY_PARM, *PQOS_CAPABILITY_PARM; - -#ifdef CONFIG_STA_SUPPORT -typedef struct { - UCHAR IELen; - UCHAR IE[MAX_CUSTOM_LEN]; -} WPA_IE_; -#endif // CONFIG_STA_SUPPORT // - - -typedef struct { - UCHAR Bssid[MAC_ADDR_LEN]; - UCHAR Channel; - UCHAR CentralChannel; //Store the wide-band central channel for 40MHz. .used in 40MHz AP. Or this is the same as Channel. - UCHAR BssType; - USHORT AtimWin; - USHORT BeaconPeriod; - - UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES]; - UCHAR SupRateLen; - UCHAR ExtRate[MAX_LEN_OF_SUPPORTED_RATES]; - UCHAR ExtRateLen; - HT_CAPABILITY_IE HtCapability; - UCHAR HtCapabilityLen; - ADD_HT_INFO_IE AddHtInfo; // AP might use this additional ht info IE - UCHAR AddHtInfoLen; - UCHAR NewExtChanOffset; - CHAR Rssi; - UCHAR Privacy; // Indicate security function ON/OFF. Don't mess up with auth mode. - UCHAR Hidden; - - USHORT DtimPeriod; - USHORT CapabilityInfo; - - USHORT CfpCount; - USHORT CfpPeriod; - USHORT CfpMaxDuration; - USHORT CfpDurRemaining; - UCHAR SsidLen; - CHAR Ssid[MAX_LEN_OF_SSID]; - - ULONG LastBeaconRxTime; // OS's timestamp - - BOOLEAN bSES; - - // New for WPA2 - CIPHER_SUITE WPA; // AP announced WPA cipher suite - CIPHER_SUITE WPA2; // AP announced WPA2 cipher suite - - // New for microsoft WPA support - NDIS_802_11_FIXED_IEs FixIEs; - NDIS_802_11_AUTHENTICATION_MODE AuthModeAux; // Addition mode for WPA2 / WPA capable AP - NDIS_802_11_AUTHENTICATION_MODE AuthMode; - NDIS_802_11_WEP_STATUS WepStatus; // Unicast Encryption Algorithm extract from VAR_IE - USHORT VarIELen; // Length of next VIE include EID & Length - UCHAR VarIEs[MAX_VIE_LEN]; - - // CCX Ckip information - UCHAR CkipFlag; - - // CCX 2 TSF - UCHAR PTSF[4]; // Parent TSF - UCHAR TTSF[8]; // Target TSF - - // 802.11e d9, and WMM - EDCA_PARM EdcaParm; - QOS_CAPABILITY_PARM QosCapability; - QBSS_LOAD_PARM QbssLoad; -#ifdef CONFIG_STA_SUPPORT - WPA_IE_ WpaIE; - WPA_IE_ RsnIE; -#ifdef EXT_BUILD_CHANNEL_LIST - UCHAR CountryString[3]; - BOOLEAN bHasCountryIE; -#endif // EXT_BUILD_CHANNEL_LIST // -#endif // CONFIG_STA_SUPPORT // -} BSS_ENTRY, *PBSS_ENTRY; - -typedef struct { - UCHAR BssNr; - UCHAR BssOverlapNr; - BSS_ENTRY BssEntry[MAX_LEN_OF_BSS_TABLE]; -} BSS_TABLE, *PBSS_TABLE; - - -typedef struct _MLME_QUEUE_ELEM { - ULONG Machine; - ULONG MsgType; - ULONG MsgLen; - UCHAR Msg[MGMT_DMA_BUFFER_SIZE]; - LARGE_INTEGER TimeStamp; - UCHAR Rssi0; - UCHAR Rssi1; - UCHAR Rssi2; - UCHAR Signal; - UCHAR Channel; - UCHAR Wcid; - BOOLEAN Occupied; -#ifdef MLME_EX - USHORT Idx; -#endif // MLME_EX // -} MLME_QUEUE_ELEM, *PMLME_QUEUE_ELEM; - -typedef struct _MLME_QUEUE { - ULONG Num; - ULONG Head; - ULONG Tail; - NDIS_SPIN_LOCK Lock; - MLME_QUEUE_ELEM Entry[MAX_LEN_OF_MLME_QUEUE]; -} MLME_QUEUE, *PMLME_QUEUE; - -typedef VOID (*STATE_MACHINE_FUNC)(VOID *Adaptor, MLME_QUEUE_ELEM *Elem); - -typedef struct _STATE_MACHINE { - ULONG Base; - ULONG NrState; - ULONG NrMsg; - ULONG CurrState; - STATE_MACHINE_FUNC *TransFunc; -} STATE_MACHINE, *PSTATE_MACHINE; - - -// MLME AUX data structure that hold temporarliy settings during a connection attempt. -// Once this attemp succeeds, all settings will be copy to pAd->StaActive. -// A connection attempt (user set OID, roaming, CCX fast roaming,..) consists of -// several steps (JOIN, AUTH, ASSOC or REASSOC) and may fail at any step. We purposely -// separate this under-trial settings away from pAd->StaActive so that once -// this new attempt failed, driver can auto-recover back to the active settings. -typedef struct _MLME_AUX { - UCHAR BssType; - UCHAR Ssid[MAX_LEN_OF_SSID]; - UCHAR SsidLen; - UCHAR Bssid[MAC_ADDR_LEN]; - UCHAR AutoReconnectSsid[MAX_LEN_OF_SSID]; - UCHAR AutoReconnectSsidLen; - USHORT Alg; - UCHAR ScanType; - UCHAR Channel; - UCHAR CentralChannel; - USHORT Aid; - USHORT CapabilityInfo; - USHORT BeaconPeriod; - USHORT CfpMaxDuration; - USHORT CfpPeriod; - USHORT AtimWin; - - // Copy supported rate from desired AP's beacon. We are trying to match - // AP's supported and extended rate settings. - UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES]; - UCHAR ExtRate[MAX_LEN_OF_SUPPORTED_RATES]; - UCHAR SupRateLen; - UCHAR ExtRateLen; - HT_CAPABILITY_IE HtCapability; - UCHAR HtCapabilityLen; - ADD_HT_INFO_IE AddHtInfo; // AP might use this additional ht info IE - UCHAR NewExtChannelOffset; - //RT_HT_CAPABILITY SupportedHtPhy; - - // new for QOS - QOS_CAPABILITY_PARM APQosCapability; // QOS capability of the current associated AP - EDCA_PARM APEdcaParm; // EDCA parameters of the current associated AP - QBSS_LOAD_PARM APQbssLoad; // QBSS load of the current associated AP - - // new to keep Ralink specific feature - ULONG APRalinkIe; - - BSS_TABLE SsidBssTab; // AP list for the same SSID - BSS_TABLE RoamTab; // AP list eligible for roaming - ULONG BssIdx; - ULONG RoamIdx; - - BOOLEAN CurrReqIsFromNdis; - - RALINK_TIMER_STRUCT BeaconTimer, ScanTimer; - RALINK_TIMER_STRUCT AuthTimer; - RALINK_TIMER_STRUCT AssocTimer, ReassocTimer, DisassocTimer; -} MLME_AUX, *PMLME_AUX; - -typedef struct _MLME_ADDBA_REQ_STRUCT{ - UCHAR Wcid; // - UCHAR pAddr[MAC_ADDR_LEN]; - UCHAR BaBufSize; - USHORT TimeOutValue; - UCHAR TID; - UCHAR Token; - USHORT BaStartSeq; -} MLME_ADDBA_REQ_STRUCT, *PMLME_ADDBA_REQ_STRUCT; - - -typedef struct _MLME_DELBA_REQ_STRUCT{ - UCHAR Wcid; // - UCHAR Addr[MAC_ADDR_LEN]; - UCHAR TID; - UCHAR Initiator; -} MLME_DELBA_REQ_STRUCT, *PMLME_DELBA_REQ_STRUCT; - -// assoc struct is equal to reassoc -typedef struct _MLME_ASSOC_REQ_STRUCT{ - UCHAR Addr[MAC_ADDR_LEN]; - USHORT CapabilityInfo; - USHORT ListenIntv; - ULONG Timeout; -} MLME_ASSOC_REQ_STRUCT, *PMLME_ASSOC_REQ_STRUCT, MLME_REASSOC_REQ_STRUCT, *PMLME_REASSOC_REQ_STRUCT; - -typedef struct _MLME_DISASSOC_REQ_STRUCT{ - UCHAR Addr[MAC_ADDR_LEN]; - USHORT Reason; -} MLME_DISASSOC_REQ_STRUCT, *PMLME_DISASSOC_REQ_STRUCT; - -typedef struct _MLME_AUTH_REQ_STRUCT { - UCHAR Addr[MAC_ADDR_LEN]; - USHORT Alg; - ULONG Timeout; -} MLME_AUTH_REQ_STRUCT, *PMLME_AUTH_REQ_STRUCT; - -typedef struct _MLME_DEAUTH_REQ_STRUCT { - UCHAR Addr[MAC_ADDR_LEN]; - USHORT Reason; -} MLME_DEAUTH_REQ_STRUCT, *PMLME_DEAUTH_REQ_STRUCT; - -typedef struct { - ULONG BssIdx; -} MLME_JOIN_REQ_STRUCT; - -typedef struct _MLME_SCAN_REQ_STRUCT { - UCHAR Bssid[MAC_ADDR_LEN]; - UCHAR BssType; - UCHAR ScanType; - UCHAR SsidLen; - CHAR Ssid[MAX_LEN_OF_SSID]; -} MLME_SCAN_REQ_STRUCT, *PMLME_SCAN_REQ_STRUCT; - -typedef struct _MLME_START_REQ_STRUCT { - CHAR Ssid[MAX_LEN_OF_SSID]; - UCHAR SsidLen; -} MLME_START_REQ_STRUCT, *PMLME_START_REQ_STRUCT; - -#ifdef CONFIG_STA_SUPPORT -#ifdef QOS_DLS_SUPPORT -// structure for DLS -typedef struct _RT_802_11_DLS { - USHORT TimeOut; // Use to time out while slience, unit: second , set by UI - USHORT CountDownTimer; // Use to time out while slience,unit: second , used by driver only - NDIS_802_11_MAC_ADDRESS MacAddr; // set by UI - UCHAR Status; // 0: none , 1: wait STAkey, 2: finish DLS setup , set by driver only - BOOLEAN Valid; // 1: valid , 0: invalid , set by UI, use to setup or tear down DLS link - RALINK_TIMER_STRUCT Timer; // Use to time out while handshake - USHORT Sequence; - USHORT MacTabMatchWCID; // ASIC - BOOLEAN bHTCap; - PVOID pAd; -} RT_802_11_DLS, *PRT_802_11_DLS; - -typedef struct _MLME_DLS_REQ_STRUCT { - PRT_802_11_DLS pDLS; - USHORT Reason; -} MLME_DLS_REQ_STRUCT, *PMLME_DLS_REQ_STRUCT; -#endif // QOS_DLS_SUPPORT // -#endif // CONFIG_STA_SUPPORT // - -typedef struct PACKED { - UCHAR Eid; - UCHAR Len; - CHAR Octet[1]; -} EID_STRUCT,*PEID_STRUCT, BEACON_EID_STRUCT, *PBEACON_EID_STRUCT; - -typedef struct PACKED _RTMP_TX_RATE_SWITCH -{ - UCHAR ItemNo; -#ifdef RT_BIG_ENDIAN - UCHAR Rsv2:2; - UCHAR Mode:2; - UCHAR Rsv1:1; - UCHAR BW:1; - UCHAR ShortGI:1; - UCHAR STBC:1; -#else - UCHAR STBC:1; - UCHAR ShortGI:1; - UCHAR BW:1; - UCHAR Rsv1:1; - UCHAR Mode:2; - UCHAR Rsv2:2; -#endif - UCHAR CurrMCS; - UCHAR TrainUp; - UCHAR TrainDown; -} RRTMP_TX_RATE_SWITCH, *PRTMP_TX_RATE_SWITCH; - -// ========================== AP mlme.h =============================== -#define TBTT_PRELOAD_TIME 384 // usec. LomgPreamble + 24-byte at 1Mbps -#define DEFAULT_DTIM_PERIOD 1 - -// weighting factor to calculate Channel quality, total should be 100% -//#define RSSI_WEIGHTING 0 -//#define TX_WEIGHTING 40 -//#define RX_WEIGHTING 60 - -#define MAC_TABLE_AGEOUT_TIME 300 // unit: sec -#define MAC_TABLE_ASSOC_TIMEOUT 5 // unit: sec -#define MAC_TABLE_FULL(Tab) ((Tab).size == MAX_LEN_OF_MAC_TABLE) - -// AP shall drop the sta if contine Tx fail count reach it. -#define MAC_ENTRY_LIFE_CHECK_CNT 20 // packet cnt. - -// Value domain of pMacEntry->Sst -typedef enum _Sst { - SST_NOT_AUTH, // 0: equivalent to IEEE 802.11/1999 state 1 - SST_AUTH, // 1: equivalent to IEEE 802.11/1999 state 2 - SST_ASSOC // 2: equivalent to IEEE 802.11/1999 state 3 -} SST; - -// value domain of pMacEntry->AuthState -typedef enum _AuthState { - AS_NOT_AUTH, - AS_AUTH_OPEN, // STA has been authenticated using OPEN SYSTEM - AS_AUTH_KEY, // STA has been authenticated using SHARED KEY - AS_AUTHENTICATING // STA is waiting for AUTH seq#3 using SHARED KEY -} AUTH_STATE; - -//for-wpa value domain of pMacEntry->WpaState 802.1i D3 p.114 -typedef enum _ApWpaState { - AS_NOTUSE, // 0 - AS_DISCONNECT, // 1 - AS_DISCONNECTED, // 2 - AS_INITIALIZE, // 3 - AS_AUTHENTICATION, // 4 - AS_AUTHENTICATION2, // 5 - AS_INITPMK, // 6 - AS_INITPSK, // 7 - AS_PTKSTART, // 8 - AS_PTKINIT_NEGOTIATING, // 9 - AS_PTKINITDONE, // 10 - AS_UPDATEKEYS, // 11 - AS_INTEGRITY_FAILURE, // 12 - AS_KEYUPDATE, // 13 -} AP_WPA_STATE; - -// for-wpa value domain of pMacEntry->WpaState 802.1i D3 p.114 -typedef enum _GTKState { - REKEY_NEGOTIATING, - REKEY_ESTABLISHED, - KEYERROR, -} GTK_STATE; - -// for-wpa value domain of pMacEntry->WpaState 802.1i D3 p.114 -typedef enum _WpaGTKState { - SETKEYS, - SETKEYS_DONE, -} WPA_GTK_STATE; -// ====================== end of AP mlme.h ============================ - - -#endif // MLME_H__ +#include "../rt2870/mlme.h" diff --git a/drivers/staging/rt3070/netif_block.h b/drivers/staging/rt3070/netif_block.h deleted file mode 100644 index 6e5151c41095..000000000000 --- a/drivers/staging/rt3070/netif_block.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - */ - -#ifndef __NET_IF_BLOCK_H__ -#define __NET_IF_BLOCK_H__ - -//#include -#include "link_list.h" -#include "rtmp.h" - -#define FREE_NETIF_POOL_SIZE 32 - -typedef struct _NETIF_ENTRY -{ - struct _NETIF_ENTRY *pNext; - PNET_DEV pNetDev; -} NETIF_ENTRY, *PNETIF_ENTRY; - -void initblockQueueTab( - IN PRTMP_ADAPTER pAd); - -BOOLEAN blockNetIf( - IN PBLOCK_QUEUE_ENTRY pBlockQueueEntry, - IN PNET_DEV pNetDev); - -VOID releaseNetIf( - IN PBLOCK_QUEUE_ENTRY pBlockQueueEntry); - -VOID StopNetIfQueue( - IN PRTMP_ADAPTER pAd, - IN UCHAR QueIdx, - IN PNDIS_PACKET pPacket); -#endif // __NET_IF_BLOCK_H__ - diff --git a/drivers/staging/rt3070/oid.h b/drivers/staging/rt3070/oid.h index f78bf0a5f140..cbf16a8ae615 100644 --- a/drivers/staging/rt3070/oid.h +++ b/drivers/staging/rt3070/oid.h @@ -1,1142 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - oid.h - - Abstract: - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Name Date Modification logs -*/ -#ifndef _OID_H_ -#define _OID_H_ - -//#include - - -#define TRUE 1 -#define FALSE 0 -// -// IEEE 802.11 Structures and definitions -// -#define MAX_TX_POWER_LEVEL 100 /* mW */ -#define MAX_RSSI_TRIGGER -10 /* dBm */ -#define MIN_RSSI_TRIGGER -200 /* dBm */ -#define MAX_FRAG_THRESHOLD 2346 /* byte count */ -#define MIN_FRAG_THRESHOLD 256 /* byte count */ -#define MAX_RTS_THRESHOLD 2347 /* byte count */ - -// new types for Media Specific Indications -// Extension channel offset -#define EXTCHA_NONE 0 -#define EXTCHA_ABOVE 0x1 -#define EXTCHA_BELOW 0x3 - -// BW -#define BAND_WIDTH_20 0 -#define BAND_WIDTH_40 1 -#define BAND_WIDTH_BOTH 2 -#define BAND_WIDTH_10 3 // 802.11j has 10MHz. This definition is for internal usage. doesn't fill in the IE or other field. -// SHORTGI -#define GAP_INTERVAL_400 1 // only support in HT mode -#define GAP_INTERVAL_800 0 -#define GAP_INTERVAL_BOTH 2 - -#define NdisMediaStateConnected 1 -#define NdisMediaStateDisconnected 0 - -#define NDIS_802_11_LENGTH_SSID 32 -#define NDIS_802_11_LENGTH_RATES 8 -#define NDIS_802_11_LENGTH_RATES_EX 16 -#define MAC_ADDR_LENGTH 6 -#define MAX_NUM_OF_CHS 49 // 14 channels @2.4G + 12@UNII + 4 @MMAC + 11 @HiperLAN2 + 7 @Japan + 1 as NULL terminationc -#define MAX_NUMBER_OF_EVENT 10 // entry # in EVENT table -#define MAX_NUMBER_OF_MAC 32 // if MAX_MBSSID_NUM is 8, this value can't be larger than 211 -#define MAX_NUMBER_OF_ACL 64 -#define MAX_LENGTH_OF_SUPPORT_RATES 12 // 1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54 -#define MAX_NUMBER_OF_DLS_ENTRY 4 - - - -#ifndef UNDER_CE -// OID definition, since NDIS 5.0 didn't define these, we need to define for our own -//#if _WIN32_WINNT<=0x0500 - -#define OID_GEN_MACHINE_NAME 0x0001021A - -#ifdef RALINK_ATE -#define RT_QUERY_ATE_TXDONE_COUNT 0x0401 -#endif // RALINK_ATE // -#define RT_QUERY_SIGNAL_CONTEXT 0x0402 -#define RT_SET_IAPP_PID 0x0404 -#define RT_SET_APD_PID 0x0405 -#define RT_SET_DEL_MAC_ENTRY 0x0406 - -// -// IEEE 802.11 OIDs -// -#define OID_GET_SET_TOGGLE 0x8000 - -#define OID_802_11_NETWORK_TYPES_SUPPORTED 0x0103 -#define OID_802_11_NETWORK_TYPE_IN_USE 0x0104 -#define OID_802_11_RSSI_TRIGGER 0x0107 -#define RT_OID_802_11_RSSI 0x0108 //rt2860 only , kathy -#define RT_OID_802_11_RSSI_1 0x0109 //rt2860 only , kathy -#define RT_OID_802_11_RSSI_2 0x010A //rt2860 only , kathy -#define OID_802_11_NUMBER_OF_ANTENNAS 0x010B -#define OID_802_11_RX_ANTENNA_SELECTED 0x010C -#define OID_802_11_TX_ANTENNA_SELECTED 0x010D -#define OID_802_11_SUPPORTED_RATES 0x010E -#define OID_802_11_ADD_WEP 0x0112 -#define OID_802_11_REMOVE_WEP 0x0113 -#define OID_802_11_DISASSOCIATE 0x0114 -#define OID_802_11_PRIVACY_FILTER 0x0118 -#define OID_802_11_ASSOCIATION_INFORMATION 0x011E -#define OID_802_11_TEST 0x011F -#define RT_OID_802_11_COUNTRY_REGION 0x0507 -#define OID_802_11_BSSID_LIST_SCAN 0x0508 -#define OID_802_11_SSID 0x0509 -#define OID_802_11_BSSID 0x050A -#define RT_OID_802_11_RADIO 0x050B -#define RT_OID_802_11_PHY_MODE 0x050C -#define RT_OID_802_11_STA_CONFIG 0x050D -#define OID_802_11_DESIRED_RATES 0x050E -#define RT_OID_802_11_PREAMBLE 0x050F -#define OID_802_11_WEP_STATUS 0x0510 -#define OID_802_11_AUTHENTICATION_MODE 0x0511 -#define OID_802_11_INFRASTRUCTURE_MODE 0x0512 -#define RT_OID_802_11_RESET_COUNTERS 0x0513 -#define OID_802_11_RTS_THRESHOLD 0x0514 -#define OID_802_11_FRAGMENTATION_THRESHOLD 0x0515 -#define OID_802_11_POWER_MODE 0x0516 -#define OID_802_11_TX_POWER_LEVEL 0x0517 -#define RT_OID_802_11_ADD_WPA 0x0518 -#define OID_802_11_REMOVE_KEY 0x0519 -#define OID_802_11_ADD_KEY 0x0520 -#define OID_802_11_CONFIGURATION 0x0521 -#define OID_802_11_TX_PACKET_BURST 0x0522 -#define RT_OID_802_11_QUERY_NOISE_LEVEL 0x0523 -#define RT_OID_802_11_EXTRA_INFO 0x0524 -#ifdef DBG -#define RT_OID_802_11_HARDWARE_REGISTER 0x0525 -#endif -#define OID_802_11_ENCRYPTION_STATUS OID_802_11_WEP_STATUS -#define OID_802_11_DEAUTHENTICATION 0x0526 -#define OID_802_11_DROP_UNENCRYPTED 0x0527 -#define OID_802_11_MIC_FAILURE_REPORT_FRAME 0x0528 - -// For 802.1x daemin using to require current driver configuration -#define OID_802_11_RADIUS_QUERY_SETTING 0x0540 - -#define RT_OID_DEVICE_NAME 0x0607 -#define RT_OID_VERSION_INFO 0x0608 -#define OID_802_11_BSSID_LIST 0x0609 -#define OID_802_3_CURRENT_ADDRESS 0x060A -#define OID_GEN_MEDIA_CONNECT_STATUS 0x060B -#define RT_OID_802_11_QUERY_LINK_STATUS 0x060C -#define OID_802_11_RSSI 0x060D -#define OID_802_11_STATISTICS 0x060E -#define OID_GEN_RCV_OK 0x060F -#define OID_GEN_RCV_NO_BUFFER 0x0610 -#define RT_OID_802_11_QUERY_EEPROM_VERSION 0x0611 -#define RT_OID_802_11_QUERY_FIRMWARE_VERSION 0x0612 -#define RT_OID_802_11_QUERY_LAST_RX_RATE 0x0613 -#define RT_OID_802_11_TX_POWER_LEVEL_1 0x0614 -#define RT_OID_802_11_QUERY_PIDVID 0x0615 -//for WPA_SUPPLICANT_SUPPORT -#define OID_SET_COUNTERMEASURES 0x0616 -#define OID_802_11_SET_IEEE8021X 0x0617 -#define OID_802_11_SET_IEEE8021X_REQUIRE_KEY 0x0618 -#define OID_802_11_PMKID 0x0620 -#define RT_OID_WPA_SUPPLICANT_SUPPORT 0x0621 -#define RT_OID_WE_VERSION_COMPILED 0x0622 -#define RT_OID_NEW_DRIVER 0x0623 - - -//rt2860 , kathy -#define RT_OID_802_11_SNR_0 0x0630 -#define RT_OID_802_11_SNR_1 0x0631 -#define RT_OID_802_11_QUERY_LAST_TX_RATE 0x0632 -#define RT_OID_802_11_QUERY_HT_PHYMODE 0x0633 -#define RT_OID_802_11_SET_HT_PHYMODE 0x0634 -#define OID_802_11_RELOAD_DEFAULTS 0x0635 -#define RT_OID_802_11_QUERY_APSD_SETTING 0x0636 -#define RT_OID_802_11_SET_APSD_SETTING 0x0637 -#define RT_OID_802_11_QUERY_APSD_PSM 0x0638 -#define RT_OID_802_11_SET_APSD_PSM 0x0639 -#define RT_OID_802_11_QUERY_DLS 0x063A -#define RT_OID_802_11_SET_DLS 0x063B -#define RT_OID_802_11_QUERY_DLS_PARAM 0x063C -#define RT_OID_802_11_SET_DLS_PARAM 0x063D -#define RT_OID_802_11_QUERY_WMM 0x063E -#define RT_OID_802_11_SET_WMM 0x063F -#define RT_OID_802_11_QUERY_IMME_BA_CAP 0x0640 -#define RT_OID_802_11_SET_IMME_BA_CAP 0x0641 -#define RT_OID_802_11_QUERY_BATABLE 0x0642 -#define RT_OID_802_11_ADD_IMME_BA 0x0643 -#define RT_OID_802_11_TEAR_IMME_BA 0x0644 -#define RT_OID_DRIVER_DEVICE_NAME 0x0645 -#define RT_OID_802_11_QUERY_DAT_HT_PHYMODE 0x0646 -#define RT_OID_QUERY_MULTIPLE_CARD_SUPPORT 0x0647 - -// Ralink defined OIDs -// Dennis Lee move to platform specific - -#define RT_OID_802_11_BSSID (OID_GET_SET_TOGGLE | OID_802_11_BSSID) -#define RT_OID_802_11_SSID (OID_GET_SET_TOGGLE | OID_802_11_SSID) -#define RT_OID_802_11_INFRASTRUCTURE_MODE (OID_GET_SET_TOGGLE | OID_802_11_INFRASTRUCTURE_MODE) -#define RT_OID_802_11_ADD_WEP (OID_GET_SET_TOGGLE | OID_802_11_ADD_WEP) -#define RT_OID_802_11_ADD_KEY (OID_GET_SET_TOGGLE | OID_802_11_ADD_KEY) -#define RT_OID_802_11_REMOVE_WEP (OID_GET_SET_TOGGLE | OID_802_11_REMOVE_WEP) -#define RT_OID_802_11_REMOVE_KEY (OID_GET_SET_TOGGLE | OID_802_11_REMOVE_KEY) -#define RT_OID_802_11_DISASSOCIATE (OID_GET_SET_TOGGLE | OID_802_11_DISASSOCIATE) -#define RT_OID_802_11_AUTHENTICATION_MODE (OID_GET_SET_TOGGLE | OID_802_11_AUTHENTICATION_MODE) -#define RT_OID_802_11_PRIVACY_FILTER (OID_GET_SET_TOGGLE | OID_802_11_PRIVACY_FILTER) -#define RT_OID_802_11_BSSID_LIST_SCAN (OID_GET_SET_TOGGLE | OID_802_11_BSSID_LIST_SCAN) -#define RT_OID_802_11_WEP_STATUS (OID_GET_SET_TOGGLE | OID_802_11_WEP_STATUS) -#define RT_OID_802_11_RELOAD_DEFAULTS (OID_GET_SET_TOGGLE | OID_802_11_RELOAD_DEFAULTS) -#define RT_OID_802_11_NETWORK_TYPE_IN_USE (OID_GET_SET_TOGGLE | OID_802_11_NETWORK_TYPE_IN_USE) -#define RT_OID_802_11_TX_POWER_LEVEL (OID_GET_SET_TOGGLE | OID_802_11_TX_POWER_LEVEL) -#define RT_OID_802_11_RSSI_TRIGGER (OID_GET_SET_TOGGLE | OID_802_11_RSSI_TRIGGER) -#define RT_OID_802_11_FRAGMENTATION_THRESHOLD (OID_GET_SET_TOGGLE | OID_802_11_FRAGMENTATION_THRESHOLD) -#define RT_OID_802_11_RTS_THRESHOLD (OID_GET_SET_TOGGLE | OID_802_11_RTS_THRESHOLD) -#define RT_OID_802_11_RX_ANTENNA_SELECTED (OID_GET_SET_TOGGLE | OID_802_11_RX_ANTENNA_SELECTED) -#define RT_OID_802_11_TX_ANTENNA_SELECTED (OID_GET_SET_TOGGLE | OID_802_11_TX_ANTENNA_SELECTED) -#define RT_OID_802_11_SUPPORTED_RATES (OID_GET_SET_TOGGLE | OID_802_11_SUPPORTED_RATES) -#define RT_OID_802_11_DESIRED_RATES (OID_GET_SET_TOGGLE | OID_802_11_DESIRED_RATES) -#define RT_OID_802_11_CONFIGURATION (OID_GET_SET_TOGGLE | OID_802_11_CONFIGURATION) -#define RT_OID_802_11_POWER_MODE (OID_GET_SET_TOGGLE | OID_802_11_POWER_MODE) - - - -typedef enum _NDIS_802_11_STATUS_TYPE -{ - Ndis802_11StatusType_Authentication, - Ndis802_11StatusType_MediaStreamMode, - Ndis802_11StatusType_PMKID_CandidateList, - Ndis802_11StatusTypeMax // not a real type, defined as an upper bound -} NDIS_802_11_STATUS_TYPE, *PNDIS_802_11_STATUS_TYPE; - -typedef UCHAR NDIS_802_11_MAC_ADDRESS[6]; - -typedef struct _NDIS_802_11_STATUS_INDICATION -{ - NDIS_802_11_STATUS_TYPE StatusType; -} NDIS_802_11_STATUS_INDICATION, *PNDIS_802_11_STATUS_INDICATION; - -// mask for authentication/integrity fields -#define NDIS_802_11_AUTH_REQUEST_AUTH_FIELDS 0x0f - -#define NDIS_802_11_AUTH_REQUEST_REAUTH 0x01 -#define NDIS_802_11_AUTH_REQUEST_KEYUPDATE 0x02 -#define NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR 0x06 -#define NDIS_802_11_AUTH_REQUEST_GROUP_ERROR 0x0E - -typedef struct _NDIS_802_11_AUTHENTICATION_REQUEST -{ - ULONG Length; // Length of structure - NDIS_802_11_MAC_ADDRESS Bssid; - ULONG Flags; -} NDIS_802_11_AUTHENTICATION_REQUEST, *PNDIS_802_11_AUTHENTICATION_REQUEST; - -//Added new types for PMKID Candidate lists. -typedef struct _PMKID_CANDIDATE { - NDIS_802_11_MAC_ADDRESS BSSID; - ULONG Flags; -} PMKID_CANDIDATE, *PPMKID_CANDIDATE; - -typedef struct _NDIS_802_11_PMKID_CANDIDATE_LIST -{ - ULONG Version; // Version of the structure - ULONG NumCandidates; // No. of pmkid candidates - PMKID_CANDIDATE CandidateList[1]; -} NDIS_802_11_PMKID_CANDIDATE_LIST, *PNDIS_802_11_PMKID_CANDIDATE_LIST; - -//Flags for PMKID Candidate list structure -#define NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED 0x01 - -// Added new types for OFDM 5G and 2.4G -typedef enum _NDIS_802_11_NETWORK_TYPE -{ - Ndis802_11FH, - Ndis802_11DS, - Ndis802_11OFDM5, - Ndis802_11OFDM5_N, - Ndis802_11OFDM24, - Ndis802_11OFDM24_N, - Ndis802_11Automode, - Ndis802_11NetworkTypeMax // not a real type, defined as an upper bound -} NDIS_802_11_NETWORK_TYPE, *PNDIS_802_11_NETWORK_TYPE; - -typedef struct _NDIS_802_11_NETWORK_TYPE_LIST -{ - UINT NumberOfItems; // in list below, at least 1 - NDIS_802_11_NETWORK_TYPE NetworkType [1]; -} NDIS_802_11_NETWORK_TYPE_LIST, *PNDIS_802_11_NETWORK_TYPE_LIST; - -typedef enum _NDIS_802_11_POWER_MODE -{ - Ndis802_11PowerModeCAM, - Ndis802_11PowerModeMAX_PSP, - Ndis802_11PowerModeFast_PSP, - Ndis802_11PowerModeLegacy_PSP, - Ndis802_11PowerModeMax // not a real mode, defined as an upper bound -} NDIS_802_11_POWER_MODE, *PNDIS_802_11_POWER_MODE; - -typedef ULONG NDIS_802_11_TX_POWER_LEVEL; // in milliwatts - -// -// Received Signal Strength Indication -// -typedef LONG NDIS_802_11_RSSI; // in dBm - -typedef struct _NDIS_802_11_CONFIGURATION_FH -{ - ULONG Length; // Length of structure - ULONG HopPattern; // As defined by 802.11, MSB set - ULONG HopSet; // to one if non-802.11 - ULONG DwellTime; // units are Kusec -} NDIS_802_11_CONFIGURATION_FH, *PNDIS_802_11_CONFIGURATION_FH; - -typedef struct _NDIS_802_11_CONFIGURATION -{ - ULONG Length; // Length of structure - ULONG BeaconPeriod; // units are Kusec - ULONG ATIMWindow; // units are Kusec - ULONG DSConfig; // Frequency, units are kHz - NDIS_802_11_CONFIGURATION_FH FHConfig; -} NDIS_802_11_CONFIGURATION, *PNDIS_802_11_CONFIGURATION; - -typedef struct _NDIS_802_11_STATISTICS -{ - ULONG Length; // Length of structure - LARGE_INTEGER TransmittedFragmentCount; - LARGE_INTEGER MulticastTransmittedFrameCount; - LARGE_INTEGER FailedCount; - LARGE_INTEGER RetryCount; - LARGE_INTEGER MultipleRetryCount; - LARGE_INTEGER RTSSuccessCount; - LARGE_INTEGER RTSFailureCount; - LARGE_INTEGER ACKFailureCount; - LARGE_INTEGER FrameDuplicateCount; - LARGE_INTEGER ReceivedFragmentCount; - LARGE_INTEGER MulticastReceivedFrameCount; - LARGE_INTEGER FCSErrorCount; - LARGE_INTEGER TKIPLocalMICFailures; - LARGE_INTEGER TKIPRemoteMICErrors; - LARGE_INTEGER TKIPICVErrors; - LARGE_INTEGER TKIPCounterMeasuresInvoked; - LARGE_INTEGER TKIPReplays; - LARGE_INTEGER CCMPFormatErrors; - LARGE_INTEGER CCMPReplays; - LARGE_INTEGER CCMPDecryptErrors; - LARGE_INTEGER FourWayHandshakeFailures; -} NDIS_802_11_STATISTICS, *PNDIS_802_11_STATISTICS; - -typedef ULONG NDIS_802_11_KEY_INDEX; -typedef ULONGLONG NDIS_802_11_KEY_RSC; - -#define MAX_RADIUS_SRV_NUM 2 // 802.1x failover number - -typedef struct PACKED _RADIUS_SRV_INFO { - UINT32 radius_ip; - UINT32 radius_port; - UCHAR radius_key[64]; - UCHAR radius_key_len; -} RADIUS_SRV_INFO, *PRADIUS_SRV_INFO; - -typedef struct PACKED _RADIUS_KEY_INFO -{ - UCHAR radius_srv_num; - RADIUS_SRV_INFO radius_srv_info[MAX_RADIUS_SRV_NUM]; - UCHAR ieee8021xWEP; // dynamic WEP - UCHAR key_index; - UCHAR key_length; // length of key in bytes - UCHAR key_material[13]; -} RADIUS_KEY_INFO, *PRADIUS_KEY_INFO; - -// It's used by 802.1x daemon to require relative configuration -typedef struct PACKED _RADIUS_CONF -{ - UINT32 Length; // Length of this structure - UCHAR mbss_num; // indicate multiple BSS number - UINT32 own_ip_addr; - UINT32 retry_interval; - UINT32 session_timeout_interval; - UCHAR EAPifname[IFNAMSIZ]; - UCHAR EAPifname_len; - UCHAR PreAuthifname[IFNAMSIZ]; - UCHAR PreAuthifname_len; - RADIUS_KEY_INFO RadiusInfo[8/*MAX_MBSSID_NUM*/]; -} RADIUS_CONF, *PRADIUS_CONF; - - - -#ifdef CONFIG_STA_SUPPORT -// Key mapping keys require a BSSID -typedef struct _NDIS_802_11_KEY -{ - UINT Length; // Length of this structure - UINT KeyIndex; - UINT KeyLength; // length of key in bytes - NDIS_802_11_MAC_ADDRESS BSSID; - NDIS_802_11_KEY_RSC KeyRSC; - UCHAR KeyMaterial[1]; // variable length depending on above field -} NDIS_802_11_KEY, *PNDIS_802_11_KEY; -#endif // CONFIG_STA_SUPPORT // - -typedef struct _NDIS_802_11_REMOVE_KEY -{ - UINT Length; // Length of this structure - UINT KeyIndex; - NDIS_802_11_MAC_ADDRESS BSSID; -} NDIS_802_11_REMOVE_KEY, *PNDIS_802_11_REMOVE_KEY; - -typedef struct _NDIS_802_11_WEP -{ - UINT Length; // Length of this structure - UINT KeyIndex; // 0 is the per-client key, 1-N are the - // global keys - UINT KeyLength; // length of key in bytes - UCHAR KeyMaterial[1];// variable length depending on above field -} NDIS_802_11_WEP, *PNDIS_802_11_WEP; - - -typedef enum _NDIS_802_11_NETWORK_INFRASTRUCTURE -{ - Ndis802_11IBSS, - Ndis802_11Infrastructure, - Ndis802_11AutoUnknown, - Ndis802_11Monitor, - Ndis802_11InfrastructureMax // Not a real value, defined as upper bound -} NDIS_802_11_NETWORK_INFRASTRUCTURE, *PNDIS_802_11_NETWORK_INFRASTRUCTURE; - -// Add new authentication modes -typedef enum _NDIS_802_11_AUTHENTICATION_MODE -{ - Ndis802_11AuthModeOpen, - Ndis802_11AuthModeShared, - Ndis802_11AuthModeAutoSwitch, - Ndis802_11AuthModeWPA, - Ndis802_11AuthModeWPAPSK, - Ndis802_11AuthModeWPANone, - Ndis802_11AuthModeWPA2, - Ndis802_11AuthModeWPA2PSK, - Ndis802_11AuthModeWPA1WPA2, - Ndis802_11AuthModeWPA1PSKWPA2PSK, - Ndis802_11AuthModeMax // Not a real mode, defined as upper bound -} NDIS_802_11_AUTHENTICATION_MODE, *PNDIS_802_11_AUTHENTICATION_MODE; - -typedef UCHAR NDIS_802_11_RATES[NDIS_802_11_LENGTH_RATES]; // Set of 8 data rates -typedef UCHAR NDIS_802_11_RATES_EX[NDIS_802_11_LENGTH_RATES_EX]; // Set of 16 data rates - -typedef struct PACKED _NDIS_802_11_SSID -{ - UINT SsidLength; // length of SSID field below, in bytes; - // this can be zero. - UCHAR Ssid[NDIS_802_11_LENGTH_SSID]; // SSID information field -} NDIS_802_11_SSID, *PNDIS_802_11_SSID; - - -typedef struct PACKED _NDIS_WLAN_BSSID -{ - ULONG Length; // Length of this structure - NDIS_802_11_MAC_ADDRESS MacAddress; // BSSID - UCHAR Reserved[2]; - NDIS_802_11_SSID Ssid; // SSID - ULONG Privacy; // WEP encryption requirement - NDIS_802_11_RSSI Rssi; // receive signal strength in dBm - NDIS_802_11_NETWORK_TYPE NetworkTypeInUse; - NDIS_802_11_CONFIGURATION Configuration; - NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode; - NDIS_802_11_RATES SupportedRates; -} NDIS_WLAN_BSSID, *PNDIS_WLAN_BSSID; - -typedef struct PACKED _NDIS_802_11_BSSID_LIST -{ - UINT NumberOfItems; // in list below, at least 1 - NDIS_WLAN_BSSID Bssid[1]; -} NDIS_802_11_BSSID_LIST, *PNDIS_802_11_BSSID_LIST; - -// Added Capabilities, IELength and IEs for each BSSID -typedef struct PACKED _NDIS_WLAN_BSSID_EX -{ - ULONG Length; // Length of this structure - NDIS_802_11_MAC_ADDRESS MacAddress; // BSSID - UCHAR Reserved[2]; - NDIS_802_11_SSID Ssid; // SSID - UINT Privacy; // WEP encryption requirement - NDIS_802_11_RSSI Rssi; // receive signal - // strength in dBm - NDIS_802_11_NETWORK_TYPE NetworkTypeInUse; - NDIS_802_11_CONFIGURATION Configuration; - NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode; - NDIS_802_11_RATES_EX SupportedRates; - ULONG IELength; - UCHAR IEs[1]; -} NDIS_WLAN_BSSID_EX, *PNDIS_WLAN_BSSID_EX; - -typedef struct PACKED _NDIS_802_11_BSSID_LIST_EX -{ - UINT NumberOfItems; // in list below, at least 1 - NDIS_WLAN_BSSID_EX Bssid[1]; -} NDIS_802_11_BSSID_LIST_EX, *PNDIS_802_11_BSSID_LIST_EX; - -typedef struct PACKED _NDIS_802_11_FIXED_IEs -{ - UCHAR Timestamp[8]; - USHORT BeaconInterval; - USHORT Capabilities; -} NDIS_802_11_FIXED_IEs, *PNDIS_802_11_FIXED_IEs; - -typedef struct _NDIS_802_11_VARIABLE_IEs -{ - UCHAR ElementID; - UCHAR Length; // Number of bytes in data field - UCHAR data[1]; -} NDIS_802_11_VARIABLE_IEs, *PNDIS_802_11_VARIABLE_IEs; - -typedef ULONG NDIS_802_11_FRAGMENTATION_THRESHOLD; - -typedef ULONG NDIS_802_11_RTS_THRESHOLD; - -typedef ULONG NDIS_802_11_ANTENNA; - -typedef enum _NDIS_802_11_PRIVACY_FILTER -{ - Ndis802_11PrivFilterAcceptAll, - Ndis802_11PrivFilter8021xWEP -} NDIS_802_11_PRIVACY_FILTER, *PNDIS_802_11_PRIVACY_FILTER; - -// Added new encryption types -// Also aliased typedef to new name -typedef enum _NDIS_802_11_WEP_STATUS -{ - Ndis802_11WEPEnabled, - Ndis802_11Encryption1Enabled = Ndis802_11WEPEnabled, - Ndis802_11WEPDisabled, - Ndis802_11EncryptionDisabled = Ndis802_11WEPDisabled, - Ndis802_11WEPKeyAbsent, - Ndis802_11Encryption1KeyAbsent = Ndis802_11WEPKeyAbsent, - Ndis802_11WEPNotSupported, - Ndis802_11EncryptionNotSupported = Ndis802_11WEPNotSupported, - Ndis802_11Encryption2Enabled, - Ndis802_11Encryption2KeyAbsent, - Ndis802_11Encryption3Enabled, - Ndis802_11Encryption3KeyAbsent, - Ndis802_11Encryption4Enabled, // TKIP or AES mix - Ndis802_11Encryption4KeyAbsent, -} NDIS_802_11_WEP_STATUS, *PNDIS_802_11_WEP_STATUS, - NDIS_802_11_ENCRYPTION_STATUS, *PNDIS_802_11_ENCRYPTION_STATUS; - -typedef enum _NDIS_802_11_RELOAD_DEFAULTS -{ - Ndis802_11ReloadWEPKeys -} NDIS_802_11_RELOAD_DEFAULTS, *PNDIS_802_11_RELOAD_DEFAULTS; - -#define NDIS_802_11_AI_REQFI_CAPABILITIES 1 -#define NDIS_802_11_AI_REQFI_LISTENINTERVAL 2 -#define NDIS_802_11_AI_REQFI_CURRENTAPADDRESS 4 - -#define NDIS_802_11_AI_RESFI_CAPABILITIES 1 -#define NDIS_802_11_AI_RESFI_STATUSCODE 2 -#define NDIS_802_11_AI_RESFI_ASSOCIATIONID 4 - -typedef struct _NDIS_802_11_AI_REQFI -{ - USHORT Capabilities; - USHORT ListenInterval; - NDIS_802_11_MAC_ADDRESS CurrentAPAddress; -} NDIS_802_11_AI_REQFI, *PNDIS_802_11_AI_REQFI; - -typedef struct _NDIS_802_11_AI_RESFI -{ - USHORT Capabilities; - USHORT StatusCode; - USHORT AssociationId; -} NDIS_802_11_AI_RESFI, *PNDIS_802_11_AI_RESFI; - -typedef struct _NDIS_802_11_ASSOCIATION_INFORMATION -{ - ULONG Length; - USHORT AvailableRequestFixedIEs; - NDIS_802_11_AI_REQFI RequestFixedIEs; - ULONG RequestIELength; - ULONG OffsetRequestIEs; - USHORT AvailableResponseFixedIEs; - NDIS_802_11_AI_RESFI ResponseFixedIEs; - ULONG ResponseIELength; - ULONG OffsetResponseIEs; -} NDIS_802_11_ASSOCIATION_INFORMATION, *PNDIS_802_11_ASSOCIATION_INFORMATION; - -typedef struct _NDIS_802_11_AUTHENTICATION_EVENT -{ - NDIS_802_11_STATUS_INDICATION Status; - NDIS_802_11_AUTHENTICATION_REQUEST Request[1]; -} NDIS_802_11_AUTHENTICATION_EVENT, *PNDIS_802_11_AUTHENTICATION_EVENT; - -/* -typedef struct _NDIS_802_11_TEST -{ - ULONG Length; - ULONG Type; - union - { - NDIS_802_11_AUTHENTICATION_EVENT AuthenticationEvent; - NDIS_802_11_RSSI RssiTrigger; - }; -} NDIS_802_11_TEST, *PNDIS_802_11_TEST; - */ - -// 802.11 Media stream constraints, associated with OID_802_11_MEDIA_STREAM_MODE -typedef enum _NDIS_802_11_MEDIA_STREAM_MODE -{ - Ndis802_11MediaStreamOff, - Ndis802_11MediaStreamOn, -} NDIS_802_11_MEDIA_STREAM_MODE, *PNDIS_802_11_MEDIA_STREAM_MODE; - -// PMKID Structures -typedef UCHAR NDIS_802_11_PMKID_VALUE[16]; - -#ifdef CONFIG_STA_SUPPORT -typedef struct _BSSID_INFO -{ - NDIS_802_11_MAC_ADDRESS BSSID; - NDIS_802_11_PMKID_VALUE PMKID; -} BSSID_INFO, *PBSSID_INFO; - -typedef struct _NDIS_802_11_PMKID -{ - UINT Length; - UINT BSSIDInfoCount; - BSSID_INFO BSSIDInfo[1]; -} NDIS_802_11_PMKID, *PNDIS_802_11_PMKID; -#endif // CONFIG_STA_SUPPORT // - - -typedef struct _NDIS_802_11_AUTHENTICATION_ENCRYPTION -{ - NDIS_802_11_AUTHENTICATION_MODE AuthModeSupported; - NDIS_802_11_ENCRYPTION_STATUS EncryptStatusSupported; -} NDIS_802_11_AUTHENTICATION_ENCRYPTION, *PNDIS_802_11_AUTHENTICATION_ENCRYPTION; - -typedef struct _NDIS_802_11_CAPABILITY -{ - ULONG Length; - ULONG Version; - ULONG NoOfPMKIDs; - ULONG NoOfAuthEncryptPairsSupported; - NDIS_802_11_AUTHENTICATION_ENCRYPTION AuthenticationEncryptionSupported[1]; -} NDIS_802_11_CAPABILITY, *PNDIS_802_11_CAPABILITY; - -//#endif //of WIN 2k -#endif //UNDER_CE - -#if WIRELESS_EXT <= 11 -#ifndef SIOCDEVPRIVATE -#define SIOCDEVPRIVATE 0x8BE0 -#endif -#define SIOCIWFIRSTPRIV SIOCDEVPRIVATE -#endif - -#ifdef CONFIG_STA_SUPPORT -#define RT_PRIV_IOCTL_EXT (SIOCIWFIRSTPRIV + 0x01) // Sync. with AP for wsc upnp daemon -#define RTPRIV_IOCTL_SET (SIOCIWFIRSTPRIV + 0x02) - -#ifdef DBG -#define RTPRIV_IOCTL_BBP (SIOCIWFIRSTPRIV + 0x03) -#define RTPRIV_IOCTL_MAC (SIOCIWFIRSTPRIV + 0x05) -#define RTPRIV_IOCTL_RF (SIOCIWFIRSTPRIV + 0x13) -#define RTPRIV_IOCTL_E2P (SIOCIWFIRSTPRIV + 0x07) -#endif - -#ifdef RALINK_ATE -#ifdef RALINK_28xx_QA -#define RTPRIV_IOCTL_ATE (SIOCIWFIRSTPRIV + 0x08) -#endif // RALINK_28xx_QA // -#endif // RALINK_ATE // - -#define RTPRIV_IOCTL_STATISTICS (SIOCIWFIRSTPRIV + 0x09) -#define RTPRIV_IOCTL_ADD_PMKID_CACHE (SIOCIWFIRSTPRIV + 0x0A) -#define RTPRIV_IOCTL_RADIUS_DATA (SIOCIWFIRSTPRIV + 0x0C) -#define RTPRIV_IOCTL_GSITESURVEY (SIOCIWFIRSTPRIV + 0x0D) -#define RT_PRIV_IOCTL (SIOCIWFIRSTPRIV + 0x0E) // Sync. with RT61 (for wpa_supplicant) -#define RTPRIV_IOCTL_GET_MAC_TABLE (SIOCIWFIRSTPRIV + 0x0F) - -#define RTPRIV_IOCTL_SHOW (SIOCIWFIRSTPRIV + 0x11) -enum { - SHOW_CONN_STATUS = 4, - SHOW_DRVIER_VERION = 5, - SHOW_BA_INFO = 6, - SHOW_DESC_INFO = 7, -#ifdef RT2870 - SHOW_RXBULK_INFO = 8, - SHOW_TXBULK_INFO = 9, -#endif // RT2870 // - RAIO_OFF = 10, - RAIO_ON = 11, -#ifdef QOS_DLS_SUPPORT - SHOW_DLS_ENTRY_INFO = 19, -#endif // QOS_DLS_SUPPORT // - SHOW_CFG_VALUE = 20, -}; - - -#endif // CONFIG_STA_SUPPORT // - - - -#ifdef SNMP_SUPPORT -//SNMP ieee 802dot11, kathy , 2008_0220 -// dot11res(3) -#define RT_OID_802_11_MANUFACTUREROUI 0x0700 -#define RT_OID_802_11_MANUFACTURERNAME 0x0701 -#define RT_OID_802_11_RESOURCETYPEIDNAME 0x0702 - -// dot11smt(1) -#define RT_OID_802_11_PRIVACYOPTIONIMPLEMENTED 0x0703 -#define RT_OID_802_11_POWERMANAGEMENTMODE 0x0704 -#define OID_802_11_WEPDEFAULTKEYVALUE 0x0705 // read , write -#define OID_802_11_WEPDEFAULTKEYID 0x0706 -#define RT_OID_802_11_WEPKEYMAPPINGLENGTH 0x0707 -#define OID_802_11_SHORTRETRYLIMIT 0x0708 -#define OID_802_11_LONGRETRYLIMIT 0x0709 -#define RT_OID_802_11_PRODUCTID 0x0710 -#define RT_OID_802_11_MANUFACTUREID 0x0711 - -// //dot11Phy(4) -#define OID_802_11_CURRENTCHANNEL 0x0712 - -//dot11mac -#define RT_OID_802_11_MAC_ADDRESS 0x0713 -#endif // SNMP_SUPPORT // - -#define OID_802_11_BUILD_CHANNEL_EX 0x0714 -#define OID_802_11_GET_CH_LIST 0x0715 -#define OID_802_11_GET_COUNTRY_CODE 0x0716 -#define OID_802_11_GET_CHANNEL_GEOGRAPHY 0x0717 - -//#define RT_OID_802_11_STATISTICS (OID_GET_SET_TOGGLE | OID_802_11_STATISTICS) - -#ifdef CONFIG_STA_SUPPORT -#define RT_OID_WSC_SET_PASSPHRASE 0x0740 // passphrase for wpa(2)-psk -#define RT_OID_WSC_DRIVER_AUTO_CONNECT 0x0741 -#define RT_OID_WSC_QUERY_DEFAULT_PROFILE 0x0742 -#define RT_OID_WSC_SET_CONN_BY_PROFILE_INDEX 0x0743 -#define RT_OID_WSC_SET_ACTION 0x0744 -#define RT_OID_WSC_SET_SSID 0x0745 -#define RT_OID_WSC_SET_PIN_CODE 0x0746 -#define RT_OID_WSC_SET_MODE 0x0747 // PIN or PBC -#define RT_OID_WSC_SET_CONF_MODE 0x0748 // Enrollee or Registrar -#define RT_OID_WSC_SET_PROFILE 0x0749 -#endif // CONFIG_STA_SUPPORT // -#define RT_OID_802_11_WSC_QUERY_PROFILE 0x0750 -// for consistency with RT61 -#define RT_OID_WSC_QUERY_STATUS 0x0751 -#define RT_OID_WSC_PIN_CODE 0x0752 -#define RT_OID_WSC_UUID 0x0753 -#define RT_OID_WSC_SET_SELECTED_REGISTRAR 0x0754 -#define RT_OID_WSC_EAPMSG 0x0755 -#define RT_OID_WSC_MANUFACTURER 0x0756 -#define RT_OID_WSC_MODEL_NAME 0x0757 -#define RT_OID_WSC_MODEL_NO 0x0758 -#define RT_OID_WSC_SERIAL_NO 0x0759 -#define RT_OID_WSC_MAC_ADDRESS 0x0760 - -#ifdef LLTD_SUPPORT -// for consistency with RT61 -#define RT_OID_GET_PHY_MODE 0x761 -#endif // LLTD_SUPPORT // - -#ifdef NINTENDO_AP -//#define RT_OID_NINTENDO 0x0D010770 -#define RT_OID_802_11_NINTENDO_GET_TABLE 0x0771 //((RT_OID_NINTENDO + 0x01) & 0xffff) -#define RT_OID_802_11_NINTENDO_SET_TABLE 0x0772 //((RT_OID_NINTENDO + 0x02) & 0xffff) -#define RT_OID_802_11_NINTENDO_CAPABLE 0x0773 //((RT_OID_NINTENDO + 0x03) & 0xffff) -#endif // NINTENDO_AP // - -//Add Paul Chen for Accton -//#define RT_OID_TX_POWER_LEVEL 0xFF020010 -//#define RT_OID_SET_TX_POWER_LEVEL (OID_GET_SET_TOGGLE | RT_OID_TX_POWER_LEVEL) - -// New for MeetingHouse Api support -#define OID_MH_802_1X_SUPPORTED 0xFFEDC100 - -// MIMO Tx parameter, ShortGI, MCS, STBC, etc. these are fields in TXWI. Don't change this definition!!! -typedef union _HTTRANSMIT_SETTING { -#ifdef RT_BIG_ENDIAN - struct { - USHORT MODE:2; // Use definition MODE_xxx. -// USHORT rsv:3; - USHORT TxBF:1; - USHORT rsv:2; - USHORT STBC:2; //SPACE - USHORT ShortGI:1; - USHORT BW:1; //channel bandwidth 20MHz or 40 MHz - USHORT MCS:7; // MCS - } field; -#else - struct { - USHORT MCS:7; // MCS - USHORT BW:1; //channel bandwidth 20MHz or 40 MHz - USHORT ShortGI:1; - USHORT STBC:2; //SPACE -// USHORT rsv:3; - USHORT rsv:2; - USHORT TxBF:1; - USHORT MODE:2; // Use definition MODE_xxx. - } field; -#endif - USHORT word; - } HTTRANSMIT_SETTING, *PHTTRANSMIT_SETTING; - -typedef enum _RT_802_11_PREAMBLE { - Rt802_11PreambleLong, - Rt802_11PreambleShort, - Rt802_11PreambleAuto -} RT_802_11_PREAMBLE, *PRT_802_11_PREAMBLE; - -// Only for STA, need to sync with AP -// 2005-03-08 match current RaConfig. -typedef enum _RT_802_11_PHY_MODE { - PHY_11BG_MIXED = 0, - PHY_11B, - PHY_11A, - PHY_11ABG_MIXED, - PHY_11G, -#ifdef DOT11_N_SUPPORT - PHY_11ABGN_MIXED, // both band 5 - PHY_11N_2_4G, // 11n-only with 2.4G band 6 - PHY_11GN_MIXED, // 2.4G band 7 - PHY_11AN_MIXED, // 5G band 8 - PHY_11BGN_MIXED, // if check 802.11b. 9 - PHY_11AGN_MIXED, // if check 802.11b. 10 - PHY_11N_5G, // 11n-only with 5G band 11 -#endif // DOT11_N_SUPPORT // -} RT_802_11_PHY_MODE; - -// put all proprietery for-query objects here to reduce # of Query_OID -typedef struct _RT_802_11_LINK_STATUS { - ULONG CurrTxRate; // in units of 0.5Mbps - ULONG ChannelQuality; // 0..100 % - ULONG TxByteCount; // both ok and fail - ULONG RxByteCount; // both ok and fail - ULONG CentralChannel; // 40MHz central channel number -} RT_802_11_LINK_STATUS, *PRT_802_11_LINK_STATUS; - -typedef struct _RT_802_11_EVENT_LOG { - LARGE_INTEGER SystemTime; // timestammp via NdisGetCurrentSystemTime() - UCHAR Addr[MAC_ADDR_LENGTH]; - USHORT Event; // EVENT_xxx -} RT_802_11_EVENT_LOG, *PRT_802_11_EVENT_LOG; - -typedef struct _RT_802_11_EVENT_TABLE { - ULONG Num; - ULONG Rsv; // to align Log[] at LARGE_INEGER boundary - RT_802_11_EVENT_LOG Log[MAX_NUMBER_OF_EVENT]; -} RT_802_11_EVENT_TABLE, PRT_802_11_EVENT_TABLE; - -// MIMO Tx parameter, ShortGI, MCS, STBC, etc. these are fields in TXWI. Don't change this definition!!! -typedef union _MACHTTRANSMIT_SETTING { - struct { - USHORT MCS:7; // MCS - USHORT BW:1; //channel bandwidth 20MHz or 40 MHz - USHORT ShortGI:1; - USHORT STBC:2; //SPACE - USHORT rsv:3; - USHORT MODE:2; // Use definition MODE_xxx. - } field; - USHORT word; - } MACHTTRANSMIT_SETTING, *PMACHTTRANSMIT_SETTING; - -typedef struct _RT_802_11_MAC_ENTRY { - UCHAR Addr[MAC_ADDR_LENGTH]; - UCHAR Aid; - UCHAR Psm; // 0:PWR_ACTIVE, 1:PWR_SAVE - UCHAR MimoPs; // 0:MMPS_STATIC, 1:MMPS_DYNAMIC, 3:MMPS_Enabled - CHAR AvgRssi0; - CHAR AvgRssi1; - CHAR AvgRssi2; - UINT32 ConnectedTime; - MACHTTRANSMIT_SETTING TxRate; -} RT_802_11_MAC_ENTRY, *PRT_802_11_MAC_ENTRY; - -typedef struct _RT_802_11_MAC_TABLE { - ULONG Num; - RT_802_11_MAC_ENTRY Entry[MAX_NUMBER_OF_MAC]; -} RT_802_11_MAC_TABLE, *PRT_802_11_MAC_TABLE; - -// structure for query/set hardware register - MAC, BBP, RF register -typedef struct _RT_802_11_HARDWARE_REGISTER { - ULONG HardwareType; // 0:MAC, 1:BBP, 2:RF register, 3:EEPROM - ULONG Offset; // Q/S register offset addr - ULONG Data; // R/W data buffer -} RT_802_11_HARDWARE_REGISTER, *PRT_802_11_HARDWARE_REGISTER; - -// structure to tune BBP R17 "RX AGC VGC init" -//typedef struct _RT_802_11_RX_AGC_VGC_TUNING { -// UCHAR FalseCcaLowerThreshold; // 0-255, def 10 -// UCHAR FalseCcaUpperThreshold; // 0-255, def 100 -// UCHAR VgcDelta; // R17 +-= VgcDelta whenever flase CCA over UpprThreshold -// // or lower than LowerThresholdupper threshold -// UCHAR VgcUpperBound; // max value of R17 -//} RT_802_11_RX_AGC_VGC_TUNING, *PRT_802_11_RX_AGC_VGC_TUNING; - -typedef struct _RT_802_11_AP_CONFIG { - ULONG EnableTxBurst; // 0-disable, 1-enable - ULONG EnableTurboRate; // 0-disable, 1-enable 72/100mbps turbo rate - ULONG IsolateInterStaTraffic; // 0-disable, 1-enable isolation - ULONG HideSsid; // 0-disable, 1-enable hiding - ULONG UseBGProtection; // 0-AUTO, 1-always ON, 2-always OFF - ULONG UseShortSlotTime; // 0-no use, 1-use 9-us short slot time - ULONG Rsv1; // must be 0 - ULONG SystemErrorBitmap; // ignore upon SET, return system error upon QUERY -} RT_802_11_AP_CONFIG, *PRT_802_11_AP_CONFIG; - -// structure to query/set STA_CONFIG -typedef struct _RT_802_11_STA_CONFIG { - ULONG EnableTxBurst; // 0-disable, 1-enable - ULONG EnableTurboRate; // 0-disable, 1-enable 72/100mbps turbo rate - ULONG UseBGProtection; // 0-AUTO, 1-always ON, 2-always OFF - ULONG UseShortSlotTime; // 0-no use, 1-use 9-us short slot time when applicable - ULONG AdhocMode; // 0-11b rates only (WIFI spec), 1 - b/g mixed, 2 - g only - ULONG HwRadioStatus; // 0-OFF, 1-ON, default is 1, Read-Only - ULONG Rsv1; // must be 0 - ULONG SystemErrorBitmap; // ignore upon SET, return system error upon QUERY -} RT_802_11_STA_CONFIG, *PRT_802_11_STA_CONFIG; - -// -// For OID Query or Set about BA structure -// -typedef struct _OID_BACAP_STRUC { - UCHAR RxBAWinLimit; - UCHAR TxBAWinLimit; - UCHAR Policy; // 0: DELAY_BA 1:IMMED_BA (//BA Policy subfiled value in ADDBA frame) 2:BA-not use. other value invalid - UCHAR MpduDensity; // 0: DELAY_BA 1:IMMED_BA (//BA Policy subfiled value in ADDBA frame) 2:BA-not use. other value invalid - UCHAR AmsduEnable; //Enable AMSDU transmisstion - UCHAR AmsduSize; // 0:3839, 1:7935 bytes. UINT MSDUSizeToBytes[] = { 3839, 7935}; - UCHAR MMPSmode; // MIMO power save more, 0:static, 1:dynamic, 2:rsv, 3:mimo enable - BOOLEAN AutoBA; // Auto BA will automatically -} OID_BACAP_STRUC, *POID_BACAP_STRUC; - -typedef struct _RT_802_11_ACL_ENTRY { - UCHAR Addr[MAC_ADDR_LENGTH]; - USHORT Rsv; -} RT_802_11_ACL_ENTRY, *PRT_802_11_ACL_ENTRY; - -typedef struct PACKED _RT_802_11_ACL { - ULONG Policy; // 0-disable, 1-positive list, 2-negative list - ULONG Num; - RT_802_11_ACL_ENTRY Entry[MAX_NUMBER_OF_ACL]; -} RT_802_11_ACL, *PRT_802_11_ACL; - -typedef struct _RT_802_11_WDS { - ULONG Num; - NDIS_802_11_MAC_ADDRESS Entry[24/*MAX_NUM_OF_WDS_LINK*/]; - ULONG KeyLength; - UCHAR KeyMaterial[32]; -} RT_802_11_WDS, *PRT_802_11_WDS; - -typedef struct _RT_802_11_TX_RATES_ { - UCHAR SupRateLen; - UCHAR SupRate[MAX_LENGTH_OF_SUPPORT_RATES]; - UCHAR ExtRateLen; - UCHAR ExtRate[MAX_LENGTH_OF_SUPPORT_RATES]; -} RT_802_11_TX_RATES, *PRT_802_11_TX_RATES; - - -// Definition of extra information code -#define GENERAL_LINK_UP 0x0 // Link is Up -#define GENERAL_LINK_DOWN 0x1 // Link is Down -#define HW_RADIO_OFF 0x2 // Hardware radio off -#define SW_RADIO_OFF 0x3 // Software radio off -#define AUTH_FAIL 0x4 // Open authentication fail -#define AUTH_FAIL_KEYS 0x5 // Shared authentication fail -#define ASSOC_FAIL 0x6 // Association failed -#define EAP_MIC_FAILURE 0x7 // Deauthencation because MIC failure -#define EAP_4WAY_TIMEOUT 0x8 // Deauthencation on 4-way handshake timeout -#define EAP_GROUP_KEY_TIMEOUT 0x9 // Deauthencation on group key handshake timeout -#define EAP_SUCCESS 0xa // EAP succeed -#define DETECT_RADAR_SIGNAL 0xb // Radar signal occur in current channel -#define EXTRA_INFO_MAX 0xb // Indicate Last OID - -#define EXTRA_INFO_CLEAR 0xffffffff - -// This is OID setting structure. So only GF or MM as Mode. This is valid when our wirelss mode has 802.11n in use. -typedef struct { - RT_802_11_PHY_MODE PhyMode; // - UCHAR TransmitNo; - UCHAR HtMode; //HTMODE_GF or HTMODE_MM - UCHAR ExtOffset; //extension channel above or below - UCHAR MCS; - UCHAR BW; - UCHAR STBC; - UCHAR SHORTGI; - UCHAR rsv; -} OID_SET_HT_PHYMODE, *POID_SET_HT_PHYMODE; - -#ifdef NINTENDO_AP -#define NINTENDO_MAX_ENTRY 16 -#define NINTENDO_SSID_NAME_LN 8 -#define NINTENDO_SSID_NAME "NWCUSBAP" -#define NINTENDO_PROBE_REQ_FLAG_MASK 0x03 -#define NINTENDO_PROBE_REQ_ON 0x01 -#define NINTENDO_PROBE_REQ_SIGNAL 0x02 -#define NINTENDO_PROBE_RSP_ON 0x01 -#define NINTENDO_SSID_NICKNAME_LN 20 - -#define NINTENDO_WEPKEY_LN 13 - -typedef struct _NINTENDO_SSID -{ - UCHAR NINTENDOFixChar[NINTENDO_SSID_NAME_LN]; - UCHAR zero1; - UCHAR registe; - UCHAR ID; - UCHAR zero2; - UCHAR NICKname[NINTENDO_SSID_NICKNAME_LN]; -} RT_NINTENDO_SSID, *PRT_NINTENDO_SSID; - -typedef struct _NINTENDO_ENTRY -{ - UCHAR NICKname[NINTENDO_SSID_NICKNAME_LN]; - UCHAR DS_Addr[ETH_LENGTH_OF_ADDRESS]; - UCHAR registe; - UCHAR UserSpaceAck; -} RT_NINTENDO_ENTRY, *PRT_NINTENDO_ENTRY; - -//RTPRIV_IOCTL_NINTENDO_GET_TABLE -//RTPRIV_IOCTL_NINTENDO_SET_TABLE -typedef struct _NINTENDO_TABLE -{ - UINT number; - RT_NINTENDO_ENTRY entry[NINTENDO_MAX_ENTRY]; -} RT_NINTENDO_TABLE, *PRT_NINTENDO_TABLE; - -//RTPRIV_IOCTL_NINTENDO_SEED_WEPKEY -typedef struct _NINTENDO_SEED_WEPKEY -{ - UCHAR seed[NINTENDO_SSID_NICKNAME_LN]; - UCHAR wepkey[16];//use 13 for 104 bits wep key -} RT_NINTENDO_SEED_WEPKEY, *PRT_NINTENDO_SEED_WEPKEY; -#endif // NINTENDO_AP // - -#ifdef LLTD_SUPPORT -typedef struct _RT_LLTD_ASSOICATION_ENTRY { - UCHAR Addr[ETH_LENGTH_OF_ADDRESS]; - unsigned short MOR; // maximum operational rate - UCHAR phyMode; -} RT_LLTD_ASSOICATION_ENTRY, *PRT_LLTD_ASSOICATION_ENTRY; - -typedef struct _RT_LLTD_ASSOICATION_TABLE { - unsigned int Num; - RT_LLTD_ASSOICATION_ENTRY Entry[MAX_NUMBER_OF_MAC]; -} RT_LLTD_ASSOICATION_TABLE, *PRT_LLTD_ASSOICATION_TABLE; -#endif // LLTD_SUPPORT // - -#ifdef CONFIG_STA_SUPPORT -#ifdef QOS_DLS_SUPPORT -//rt2860, kathy 2007-0118 -// structure for DLS -typedef struct _RT_802_11_DLS_UI { - USHORT TimeOut; // unit: second , set by UI - USHORT CountDownTimer; // unit: second , used by driver only - NDIS_802_11_MAC_ADDRESS MacAddr; // set by UI - UCHAR Status; // 0: none , 1: wait STAkey, 2: finish DLS setup , set by driver only - BOOLEAN Valid; // 1: valid , 0: invalid , set by UI, use to setup or tear down DLS link -} RT_802_11_DLS_UI, *PRT_802_11_DLS_UI; - -typedef struct _RT_802_11_DLS_INFO { - RT_802_11_DLS_UI Entry[MAX_NUMBER_OF_DLS_ENTRY]; - UCHAR num; -} RT_802_11_DLS_INFO, *PRT_802_11_DLS_INFO; - -typedef enum _RT_802_11_DLS_MODE { - DLS_NONE, - DLS_WAIT_KEY, - DLS_FINISH -} RT_802_11_DLS_MODE; -#endif // QOS_DLS_SUPPORT // - -#ifdef WPA_SUPPLICANT_SUPPORT -#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT -#define RT_ASSOC_EVENT_FLAG 0x0101 -#define RT_DISASSOC_EVENT_FLAG 0x0102 -#define RT_REQIE_EVENT_FLAG 0x0103 -#define RT_RESPIE_EVENT_FLAG 0x0104 -#define RT_ASSOCINFO_EVENT_FLAG 0x0105 -#define RT_PMKIDCAND_FLAG 0x0106 -#define RT_INTERFACE_DOWN 0x0107 -#define RT_INTERFACE_UP 0x0108 -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // -#endif // WPA_SUPPLICANT_SUPPORT // -#endif // CONFIG_STA_SUPPORT // - - -#define MAX_CUSTOM_LEN 128 - -#ifdef CONFIG_STA_SUPPORT -typedef enum _RT_802_11_D_CLIENT_MODE -{ - Rt802_11_D_None, - Rt802_11_D_Flexible, - Rt802_11_D_Strict, -} RT_802_11_D_CLIENT_MODE, *PRT_802_11_D_CLIENT_MODE; -#endif // CONFIG_STA_SUPPORT // - -typedef struct _RT_CHANNEL_LIST_INFO -{ - UCHAR ChannelList[MAX_NUM_OF_CHS]; // list all supported channels for site survey - UCHAR ChannelListNum; // number of channel in ChannelList[] -} RT_CHANNEL_LIST_INFO, *PRT_CHANNEL_LIST_INFO; - -// WSC configured credential -typedef struct _WSC_CREDENTIAL -{ - NDIS_802_11_SSID SSID; // mandatory - USHORT AuthType; // mandatory, 1: open, 2: wpa-psk, 4: shared, 8:wpa, 0x10: wpa2, 0x20: wpa2-psk - USHORT EncrType; // mandatory, 1: none, 2: wep, 4: tkip, 8: aes - UCHAR Key[64]; // mandatory, Maximum 64 byte - USHORT KeyLength; - UCHAR MacAddr[6]; // mandatory, AP MAC address - UCHAR KeyIndex; // optional, default is 1 - UCHAR Rsvd[3]; // Make alignment -} WSC_CREDENTIAL, *PWSC_CREDENTIAL; - -// WSC configured profiles -typedef struct _WSC_PROFILE -{ - UINT ProfileCnt; - WSC_CREDENTIAL Profile[8]; // Support up to 8 profiles -} WSC_PROFILE, *PWSC_PROFILE; - - - -#endif // _OID_H_ - +#include "../rt2870/oid.h" diff --git a/drivers/staging/rt3070/rt2870.h b/drivers/staging/rt3070/rt2870.h index d32a2bf1d040..16d8717b9dbd 100644 --- a/drivers/staging/rt3070/rt2870.h +++ b/drivers/staging/rt3070/rt2870.h @@ -1,756 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - */ - -#ifndef __RT2870_H__ -#define __RT2870_H__ - -//usb header files -#include - -/* rtmp_def.h */ -// -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) -#define BULKAGGRE_ZISE 100 -#define RT28XX_DRVDATA_SET(_a) usb_set_intfdata(_a, pAd); -#define RT28XX_PUT_DEVICE usb_put_dev -#define RTUSB_ALLOC_URB(iso) usb_alloc_urb(iso, GFP_ATOMIC) -#define RTUSB_SUBMIT_URB(pUrb) usb_submit_urb(pUrb, GFP_ATOMIC) -#define RTUSB_URB_ALLOC_BUFFER(pUsb_Dev, BufSize, pDma_addr) usb_buffer_alloc(pUsb_Dev, BufSize, GFP_ATOMIC, pDma_addr) -#define RTUSB_URB_FREE_BUFFER(pUsb_Dev, BufSize, pTransferBuf, Dma_addr) usb_buffer_free(pUsb_Dev, BufSize, pTransferBuf, Dma_addr) -#else -#define BULKAGGRE_ZISE 60 -#define RT28XX_DRVDATA_SET(_a) -#define RT28XX_PUT_DEVICE(dev_p) -#define RTUSB_ALLOC_URB(iso) usb_alloc_urb(iso) -#define RTUSB_SUBMIT_URB(pUrb) usb_submit_urb(pUrb) -#define RTUSB_URB_ALLOC_BUFFER(pUsb_Dev, BufSize, pDma_addr) kmalloc(BufSize, GFP_ATOMIC) -#define RTUSB_URB_FREE_BUFFER(pUsb_Dev, BufSize, pTransferBuf, Dma_addr) kfree(pTransferBuf) -#endif - -#define RXBULKAGGRE_ZISE 12 -#define MAX_TXBULK_LIMIT (LOCAL_TXBUF_SIZE*(BULKAGGRE_ZISE-1)) -#define MAX_TXBULK_SIZE (LOCAL_TXBUF_SIZE*BULKAGGRE_ZISE) -#define MAX_RXBULK_SIZE (LOCAL_TXBUF_SIZE*RXBULKAGGRE_ZISE) -#define MAX_MLME_HANDLER_MEMORY 20 -#define BUFFER_SIZE 2400 //2048 -#define TX_RING 0xa -#define PRIO_RING 0xc - - -// Flags for Bulkflags control for bulk out data -// -#define fRTUSB_BULK_OUT_DATA_NULL 0x00000001 -#define fRTUSB_BULK_OUT_RTS 0x00000002 -#define fRTUSB_BULK_OUT_MLME 0x00000004 - -#define fRTUSB_BULK_OUT_DATA_NORMAL 0x00010000 -#define fRTUSB_BULK_OUT_DATA_NORMAL_2 0x00020000 -#define fRTUSB_BULK_OUT_DATA_NORMAL_3 0x00040000 -#define fRTUSB_BULK_OUT_DATA_NORMAL_4 0x00080000 -#define fRTUSB_BULK_OUT_DATA_NORMAL_5 0x00100000 - -#define fRTUSB_BULK_OUT_PSPOLL 0x00000020 -#define fRTUSB_BULK_OUT_DATA_FRAG 0x00000040 -#define fRTUSB_BULK_OUT_DATA_FRAG_2 0x00000080 -#define fRTUSB_BULK_OUT_DATA_FRAG_3 0x00000100 -#define fRTUSB_BULK_OUT_DATA_FRAG_4 0x00000200 - -#ifdef RALINK_ATE -#define fRTUSB_BULK_OUT_DATA_ATE 0x00100000 -#endif // RALINK_ATE // - -#define RT2870_USB_DEVICES \ -{ \ - {USB_DEVICE(0x148F,0x2770)}, /* Ralink */ \ - {USB_DEVICE(0x148F,0x2870)}, /* Ralink */ \ - {USB_DEVICE(0x148F,0x3070)}, /* Ralink 3070 */ \ - {USB_DEVICE(0x148F,0x3071)}, /* Ralink 3071 */ \ - {USB_DEVICE(0x148F,0x3072)}, /* Ralink 3072 */ \ - {USB_DEVICE(0x0B05,0x1731)}, /* Asus */ \ - {USB_DEVICE(0x0B05,0x1732)}, /* Asus */ \ - {USB_DEVICE(0x0B05,0x1742)}, /* Asus */ \ - {USB_DEVICE(0x0DF6,0x0017)}, /* Sitecom */ \ - {USB_DEVICE(0x0DF6,0x002B)}, /* Sitecom */ \ - {USB_DEVICE(0x0DF6,0x002C)}, /* Sitecom */ \ - {USB_DEVICE(0x0DF6,0x003E)}, /* Sitecom 3070 */ \ - {USB_DEVICE(0x0DF6,0x002D)}, /* Sitecom */ \ - {USB_DEVICE(0x0DF6,0x0039)}, /* Sitecom 2770 */ \ - {USB_DEVICE(0x14B2,0x3C06)}, /* Conceptronic */ \ - {USB_DEVICE(0x14B2,0x3C28)}, /* Conceptronic */ \ - {USB_DEVICE(0x2019,0xED06)}, /* Planex Communications, Inc. */ \ - {USB_DEVICE(0x2019,0xAB25)}, /* Planex Communications, Inc. RT3070 */ \ - {USB_DEVICE(0x07D1,0x3C09)}, /* D-Link */ \ - {USB_DEVICE(0x07D1,0x3C11)}, /* D-Link */ \ - {USB_DEVICE(0x2001,0x3C09)}, /* D-Link */ \ - {USB_DEVICE(0x2001,0x3C0A)}, /* D-Link 3072*/ \ - {USB_DEVICE(0x14B2,0x3C07)}, /* AL */ \ - {USB_DEVICE(0x14B2,0x3C12)}, /* AL 3070 */ \ - {USB_DEVICE(0x050D,0x8053)}, /* Belkin */ \ - {USB_DEVICE(0x14B2,0x3C23)}, /* Airlink */ \ - {USB_DEVICE(0x14B2,0x3C27)}, /* Airlink */ \ - {USB_DEVICE(0x07AA,0x002F)}, /* Corega */ \ - {USB_DEVICE(0x07AA,0x003C)}, /* Corega */ \ - {USB_DEVICE(0x07AA,0x003F)}, /* Corega */ \ - {USB_DEVICE(0x18C5,0x0012)}, /* Corega 3070 */ \ - {USB_DEVICE(0x1044,0x800B)}, /* Gigabyte */ \ - {USB_DEVICE(0x1044,0x800D)}, /* Gigabyte GN-WB32L 3070 */ \ - {USB_DEVICE(0x15A9,0x0006)}, /* Sparklan */ \ - {USB_DEVICE(0x083A,0xB522)}, /* SMC */ \ - {USB_DEVICE(0x083A,0xA618)}, /* SMC */ \ - {USB_DEVICE(0x083A,0x8522)}, /* Arcadyan */ \ - {USB_DEVICE(0x083A,0x7512)}, /* Arcadyan 2770 */ \ - {USB_DEVICE(0x083A,0x7522)}, /* Arcadyan */ \ - {USB_DEVICE(0x083A,0x7511)}, /* Arcadyan 3070 */ \ - {USB_DEVICE(0x0CDE,0x0022)}, /* ZCOM */ \ - {USB_DEVICE(0x0586,0x3416)}, /* Zyxel */ \ - {USB_DEVICE(0x0CDE,0x0025)}, /* Zyxel */ \ - {USB_DEVICE(0x1740,0x9701)}, /* EnGenius */ \ - {USB_DEVICE(0x1740,0x9702)}, /* EnGenius */ \ - {USB_DEVICE(0x1740,0x9703)}, /* EnGenius 3070 */ \ - {USB_DEVICE(0x0471,0x200f)}, /* Philips */ \ - {USB_DEVICE(0x14B2,0x3C25)}, /* Draytek */ \ - {USB_DEVICE(0x13D3,0x3247)}, /* AzureWave */ \ - {USB_DEVICE(0x13D3,0x3273)}, /* AzureWave 3070*/ \ - {USB_DEVICE(0x083A,0x6618)}, /* Accton */ \ - {USB_DEVICE(0x15c5,0x0008)}, /* Amit */ \ - {USB_DEVICE(0x0E66,0x0001)}, /* Hawking */ \ - {USB_DEVICE(0x0E66,0x0003)}, /* Hawking */ \ - {USB_DEVICE(0x129B,0x1828)}, /* Siemens */ \ - {USB_DEVICE(0x157E,0x300E)}, /* U-Media */ \ - {USB_DEVICE(0x050d,0x805c)}, \ - {USB_DEVICE(0x1482,0x3C09)}, /* Abocom*/ \ - {USB_DEVICE(0x14B2,0x3C09)}, /* Alpha */ \ - {USB_DEVICE(0x04E8,0x2018)}, /* samsung */ \ - {USB_DEVICE(0x07B8,0x3070)}, /* AboCom 3070 */ \ - {USB_DEVICE(0x07B8,0x3071)}, /* AboCom 3071 */ \ - {USB_DEVICE(0x07B8,0x3072)}, /* Abocom 3072 */ \ - {USB_DEVICE(0x7392,0x7711)}, /* Edimax 3070 */ \ - {USB_DEVICE(0x5A57,0x0280)}, /* Zinwell */ \ - {USB_DEVICE(0x5A57,0x0282)}, /* Zinwell */ \ - {USB_DEVICE(0x1A32,0x0304)}, /* Quanta 3070 */ \ - {USB_DEVICE(0x0789,0x0162)}, /* Logitec 2870 */ \ - {USB_DEVICE(0x0789,0x0163)}, /* Logitec 2870 */ \ - {USB_DEVICE(0x0789,0x0164)}, /* Logitec 2870 */ \ - {USB_DEVICE(0x1EDA,0x2310)}, /* AirTies 3070 */ \ - { }/* Terminating entry */ \ -} - -#define FREE_HTTX_RING(_p, _b, _t) \ -{ \ - if ((_t)->ENextBulkOutPosition == (_t)->CurWritePosition) \ - { \ - (_t)->bRingEmpty = TRUE; \ - } \ - /*NdisInterlockedDecrement(&(_p)->TxCount); */\ -} - -// -// RXINFO appends at the end of each rx packet. -// -#ifdef RT_BIG_ENDIAN -typedef struct PACKED _RXINFO_STRUC { - UINT32 PlcpSignal:12; - UINT32 LastAMSDU:1; - UINT32 CipherAlg:1; - UINT32 PlcpRssil:1; - UINT32 Decrypted:1; - UINT32 AMPDU:1; // To be moved - UINT32 L2PAD:1; - UINT32 RSSI:1; - UINT32 HTC:1; - UINT32 AMSDU:1; // rx with 802.3 header, not 802.11 header. - UINT32 CipherErr:2; // 0: decryption okay, 1:ICV error, 2:MIC error, 3:KEY not valid - UINT32 Crc:1; // 1: CRC error - UINT32 MyBss:1; // 1: this frame belongs to the same BSSID - UINT32 Bcast:1; // 1: this is a broadcast frame - UINT32 Mcast:1; // 1: this is a multicast frame - UINT32 U2M:1; // 1: this RX frame is unicast to me - UINT32 FRAG:1; - UINT32 NULLDATA:1; - UINT32 DATA:1; - UINT32 BA:1; -} RXINFO_STRUC, *PRXINFO_STRUC, RT28XX_RXD_STRUC, *PRT28XX_RXD_STRUC; -#else -typedef struct PACKED _RXINFO_STRUC { - UINT32 BA:1; - UINT32 DATA:1; - UINT32 NULLDATA:1; - UINT32 FRAG:1; - UINT32 U2M:1; // 1: this RX frame is unicast to me - UINT32 Mcast:1; // 1: this is a multicast frame - UINT32 Bcast:1; // 1: this is a broadcast frame - UINT32 MyBss:1; // 1: this frame belongs to the same BSSID - UINT32 Crc:1; // 1: CRC error - UINT32 CipherErr:2; // 0: decryption okay, 1:ICV error, 2:MIC error, 3:KEY not valid - UINT32 AMSDU:1; // rx with 802.3 header, not 802.11 header. - UINT32 HTC:1; - UINT32 RSSI:1; - UINT32 L2PAD:1; - UINT32 AMPDU:1; // To be moved - UINT32 Decrypted:1; - UINT32 PlcpRssil:1; - UINT32 CipherAlg:1; - UINT32 LastAMSDU:1; - UINT32 PlcpSignal:12; -} RXINFO_STRUC, *PRXINFO_STRUC, RT28XX_RXD_STRUC, *PRT28XX_RXD_STRUC; -#endif - - -// -// TXINFO -// -#ifdef RT_BIG_ENDIAN -typedef struct _TXINFO_STRUC { - // Word 0 - UINT32 USBDMATxburst:1;//used ONLY in USB bulk Aggre. Force USB DMA transmit frame from current selected endpoint - UINT32 USBDMANextVLD:1; //used ONLY in USB bulk Aggregation, NextValid - UINT32 rsv2:2; // Software use. - UINT32 SwUseLastRound:1; // Software use. - UINT32 QSEL:2; // select on-chip FIFO ID for 2nd-stage output scheduler.0:MGMT, 1:HCCA 2:EDCA - UINT32 WIV:1; // Wireless Info Valid. 1 if Driver already fill WI, o if DMA needs to copy WI to correctposition - UINT32 rsv:8; - UINT32 USBDMATxPktLen:16; //used ONLY in USB bulk Aggregation, Total byte counts of all sub-frame. -} TXINFO_STRUC, *PTXINFO_STRUC; -#else -typedef struct _TXINFO_STRUC { - // Word 0 - UINT32 USBDMATxPktLen:16; //used ONLY in USB bulk Aggregation, Total byte counts of all sub-frame. - UINT32 rsv:8; - UINT32 WIV:1; // Wireless Info Valid. 1 if Driver already fill WI, o if DMA needs to copy WI to correctposition - UINT32 QSEL:2; // select on-chip FIFO ID for 2nd-stage output scheduler.0:MGMT, 1:HCCA 2:EDCA - UINT32 SwUseLastRound:1; // Software use. - UINT32 rsv2:2; // Software use. - UINT32 USBDMANextVLD:1; //used ONLY in USB bulk Aggregation, NextValid - UINT32 USBDMATxburst:1;//used ONLY in USB bulk Aggre. Force USB DMA transmit frame from current selected endpoint -} TXINFO_STRUC, *PTXINFO_STRUC; -#endif - -#define TXINFO_SIZE 4 -#define RXINFO_SIZE 4 -#define TXPADDING_SIZE 11 - -// -// Management ring buffer format -// -typedef struct _MGMT_STRUC { - BOOLEAN Valid; - PUCHAR pBuffer; - ULONG Length; -} MGMT_STRUC, *PMGMT_STRUC; - - -/* ----------------- EEPROM Related MACRO ----------------- */ -#ifdef RT30xx -#define RT28xx_EEPROM_READ16(pAd, offset, var) \ - do { \ - RTUSBReadEEPROM(pAd, offset, (PUCHAR)&(var), 2); \ - if(!pAd->bUseEfuse) \ - var = le2cpu16(var); \ - }while(0) - -#define RT28xx_EEPROM_WRITE16(pAd, offset, var) \ - do{ \ - USHORT _tmpVar=var; \ - if(!pAd->bUseEfuse) \ - _tmpVar = cpu2le16(var); \ - RTUSBWriteEEPROM(pAd, offset, (PUCHAR)&(_tmpVar), 2); \ - }while(0) -#endif // RT30xx // -#ifndef RT30xx -#define RT28xx_EEPROM_READ16(pAd, offset, var) \ - do { \ - RTUSBReadEEPROM(pAd, offset, (PUCHAR)&(var), 2); \ - var = le2cpu16(var); \ - }while(0) - -#define RT28xx_EEPROM_WRITE16(pAd, offset, var) \ - do{ \ - USHORT _tmpVar=var; \ - _tmpVar = cpu2le16(var); \ - RTUSBWriteEEPROM(pAd, offset, (PUCHAR)&(_tmpVar), 2); \ - }while(0) -#endif // RT30xx // - -/* ----------------- TASK/THREAD Related MACRO ----------------- */ -#define RT28XX_TASK_THREAD_INIT(pAd, Status) \ - Status = CreateThreads(net_dev); - - -/* ----------------- Frimware Related MACRO ----------------- */ -#define RT28XX_WRITE_FIRMWARE(_pAd, _pFwImage, _FwLen) \ - RTUSBFirmwareWrite(_pAd, _pFwImage, _FwLen) - -/* ----------------- TX Related MACRO ----------------- */ -#define RT28XX_START_DEQUEUE(pAd, QueIdx, irqFlags) \ - { \ - RTMP_IRQ_LOCK(&pAd->DeQueueLock[QueIdx], irqFlags); \ - if (pAd->DeQueueRunning[QueIdx]) \ - { \ - RTMP_IRQ_UNLOCK(&pAd->DeQueueLock[QueIdx], irqFlags);\ - printk("DeQueueRunning[%d]= TRUE!\n", QueIdx); \ - continue; \ - } \ - else \ - { \ - pAd->DeQueueRunning[QueIdx] = TRUE; \ - RTMP_IRQ_UNLOCK(&pAd->DeQueueLock[QueIdx], irqFlags);\ - } \ - } -#define RT28XX_STOP_DEQUEUE(pAd, QueIdx, irqFlags) \ - do{ \ - RTMP_IRQ_LOCK(&pAd->DeQueueLock[QueIdx], irqFlags); \ - pAd->DeQueueRunning[QueIdx] = FALSE; \ - RTMP_IRQ_UNLOCK(&pAd->DeQueueLock[QueIdx], irqFlags); \ - }while(0) - - -#define RT28XX_HAS_ENOUGH_FREE_DESC(pAd, pTxBlk, freeNum, pPacket) \ - (RTUSBFreeDescriptorRequest(pAd, pTxBlk->QueIdx, (pTxBlk->TotalFrameLen + GET_OS_PKT_LEN(pPacket))) == NDIS_STATUS_SUCCESS) - -#define RT28XX_RELEASE_DESC_RESOURCE(pAd, QueIdx) \ - do{}while(0) - -#define NEED_QUEUE_BACK_FOR_AGG(_pAd, _QueIdx, _freeNum, _TxFrameType) \ - ((_TxFrameType == TX_RALINK_FRAME) && (RTUSBNeedQueueBackForAgg(_pAd, _QueIdx))) - - - -#define fRTMP_ADAPTER_NEED_STOP_TX \ - (fRTMP_ADAPTER_NIC_NOT_EXIST | fRTMP_ADAPTER_HALT_IN_PROGRESS | \ - fRTMP_ADAPTER_RESET_IN_PROGRESS | fRTMP_ADAPTER_BULKOUT_RESET | \ - fRTMP_ADAPTER_RADIO_OFF | fRTMP_ADAPTER_REMOVE_IN_PROGRESS) - - -#define HAL_WriteSubTxResource(pAd, pTxBlk, bIsLast, pFreeNumber) \ - RtmpUSB_WriteSubTxResource(pAd, pTxBlk, bIsLast, pFreeNumber) - -#define HAL_WriteTxResource(pAd, pTxBlk,bIsLast, pFreeNumber) \ - RtmpUSB_WriteSingleTxResource(pAd, pTxBlk,bIsLast, pFreeNumber) - -#define HAL_WriteFragTxResource(pAd, pTxBlk, fragNum, pFreeNumber) \ - RtmpUSB_WriteFragTxResource(pAd, pTxBlk, fragNum, pFreeNumber) - -#define HAL_WriteMultiTxResource(pAd, pTxBlk,frameNum, pFreeNumber) \ - RtmpUSB_WriteMultiTxResource(pAd, pTxBlk,frameNum, pFreeNumber) - -#define HAL_FinalWriteTxResource(pAd, pTxBlk, totalMPDUSize, TxIdx) \ - RtmpUSB_FinalWriteTxResource(pAd, pTxBlk, totalMPDUSize, TxIdx) - -#define HAL_LastTxIdx(pAd, QueIdx,TxIdx) \ - /*RtmpUSBDataLastTxIdx(pAd, QueIdx,TxIdx)*/ - -#define HAL_KickOutTx(pAd, pTxBlk, QueIdx) \ - RtmpUSBDataKickOut(pAd, pTxBlk, QueIdx) - - -#define HAL_KickOutMgmtTx(pAd, QueIdx, pPacket, pSrcBufVA, SrcBufLen) \ - RtmpUSBMgmtKickOut(pAd, QueIdx, pPacket, pSrcBufVA, SrcBufLen) - -#define HAL_KickOutNullFrameTx(_pAd, _QueIdx, _pNullFrame, _frameLen) \ - RtmpUSBNullFrameKickOut(_pAd, _QueIdx, _pNullFrame, _frameLen) - -#define RTMP_PKT_TAIL_PADDING 11 // 3(max 4 byte padding) + 4 (last packet padding) + 4 (MaxBulkOutsize align padding) - -extern UCHAR EpToQueue[6]; - - -#ifdef RT2870 -#define GET_TXRING_FREENO(_pAd, _QueIdx) (_QueIdx) //(_pAd->TxRing[_QueIdx].TxSwFreeIdx) -#define GET_MGMTRING_FREENO(_pAd) (_pAd->MgmtRing.TxSwFreeIdx) -#endif // RT2870 // - - -/* ----------------- RX Related MACRO ----------------- */ -//#define RT28XX_RX_ERROR_CHECK RTMPCheckRxWI - -#define RT28XX_RV_ALL_BUF_END(bBulkReceive) \ - /* We return STATUS_MORE_PROCESSING_REQUIRED so that the completion */ \ - /* routine (IofCompleteRequest) will stop working on the irp. */ \ - if (bBulkReceive == TRUE) RTUSBBulkReceive(pAd); - - -/* ----------------- ASIC Related MACRO ----------------- */ -// reset MAC of a station entry to 0xFFFFFFFFFFFF -#define RT28XX_STA_ENTRY_MAC_RESET(pAd, Wcid) \ - { RT_SET_ASIC_WCID SetAsicWcid; \ - SetAsicWcid.WCID = Wcid; \ - SetAsicWcid.SetTid = 0xffffffff; \ - SetAsicWcid.DeleteTid = 0xffffffff; \ - RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_SET_ASIC_WCID, \ - &SetAsicWcid, sizeof(RT_SET_ASIC_WCID)); } - -// add this entry into ASIC RX WCID search table -#define RT28XX_STA_ENTRY_ADD(pAd, pEntry) \ - RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_SET_CLIENT_MAC_ENTRY, \ - pEntry, sizeof(MAC_TABLE_ENTRY)); - -// add by johnli, fix "in_interrupt" error when call "MacTableDeleteEntry" in Rx tasklet -// Set MAC register value according operation mode -#define RT28XX_UPDATE_PROTECT(pAd) \ - RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_UPDATE_PROTECT, NULL, 0); -// end johnli - -// remove Pair-wise key material from ASIC -// yet implement -#define RT28XX_STA_ENTRY_KEY_DEL(pAd, BssIdx, Wcid) - -// add Client security information into ASIC WCID table and IVEIV table -#define RT28XX_STA_SECURITY_INFO_ADD(pAd, apidx, KeyID, pEntry) \ - { RT28XX_STA_ENTRY_MAC_RESET(pAd, pEntry->Aid); \ - if (pEntry->Aid >= 1) { \ - RT_SET_ASIC_WCID_ATTRI SetAsicWcidAttri; \ - SetAsicWcidAttri.WCID = pEntry->Aid; \ - if ((pEntry->AuthMode <= Ndis802_11AuthModeAutoSwitch) && \ - (pEntry->WepStatus == Ndis802_11Encryption1Enabled)) \ - { \ - SetAsicWcidAttri.Cipher = pAd->SharedKey[apidx][KeyID].CipherAlg; \ - } \ - else if (pEntry->AuthMode == Ndis802_11AuthModeWPANone) \ - { \ - SetAsicWcidAttri.Cipher = pAd->SharedKey[apidx][KeyID].CipherAlg; \ - } \ - else SetAsicWcidAttri.Cipher = 0; \ - DBGPRINT(RT_DEBUG_TRACE, ("aid cipher = %ld\n",SetAsicWcidAttri.Cipher)); \ - RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_SET_ASIC_WCID_CIPHER, \ - &SetAsicWcidAttri, sizeof(RT_SET_ASIC_WCID_ATTRI)); } } - -// Insert the BA bitmap to ASIC for the Wcid entry -#define RT28XX_ADD_BA_SESSION_TO_ASIC(_pAd, _Aid, _TID) \ - do{ \ - RT_SET_ASIC_WCID SetAsicWcid; \ - SetAsicWcid.WCID = (_Aid); \ - SetAsicWcid.SetTid = (0x10000<<(_TID)); \ - SetAsicWcid.DeleteTid = 0xffffffff; \ - RTUSBEnqueueInternalCmd((_pAd), CMDTHREAD_SET_ASIC_WCID, &SetAsicWcid, sizeof(RT_SET_ASIC_WCID)); \ - }while(0) - -// Remove the BA bitmap from ASIC for the Wcid entry -#define RT28XX_DEL_BA_SESSION_FROM_ASIC(_pAd, _Wcid, _TID) \ - do{ \ - RT_SET_ASIC_WCID SetAsicWcid; \ - SetAsicWcid.WCID = (_Wcid); \ - SetAsicWcid.SetTid = (0xffffffff); \ - SetAsicWcid.DeleteTid = (0x10000<<(_TID) ); \ - RTUSBEnqueueInternalCmd((_pAd), CMDTHREAD_SET_ASIC_WCID, &SetAsicWcid, sizeof(RT_SET_ASIC_WCID)); \ - }while(0) - - -/* ----------------- PCI/USB Related MACRO ----------------- */ -#define RT28XX_HANDLE_DEV_ASSIGN(handle, dev_p) \ - ((POS_COOKIE)handle)->pUsb_Dev = dev_p; - -// no use -#define RT28XX_UNMAP() -#define RT28XX_IRQ_REQUEST(net_dev) -#define RT28XX_IRQ_RELEASE(net_dev) -#define RT28XX_IRQ_INIT(pAd) -#define RT28XX_IRQ_ENABLE(pAd) - - -/* ----------------- MLME Related MACRO ----------------- */ -#define RT28XX_MLME_HANDLER(pAd) RTUSBMlmeUp(pAd) - -#define RT28XX_MLME_PRE_SANITY_CHECK(pAd) \ - { if ((pAd->CommonCfg.bHardwareRadio == TRUE) && \ - (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) && \ - (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS))) { \ - RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_CHECK_GPIO, NULL, 0); } } - -#define RT28XX_MLME_STA_QUICK_RSP_WAKE_UP(pAd) \ - { RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_QKERIODIC_EXECUT, NULL, 0); \ - RTUSBMlmeUp(pAd); } - -#define RT28XX_MLME_RESET_STATE_MACHINE(pAd) \ - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_RESET_CONF, 0, NULL); \ - RTUSBMlmeUp(pAd); - -#define RT28XX_HANDLE_COUNTER_MEASURE(_pAd, _pEntry) \ - { RTUSBEnqueueInternalCmd(_pAd, CMDTHREAD_802_11_COUNTER_MEASURE, _pEntry, sizeof(MAC_TABLE_ENTRY)); \ - RTUSBMlmeUp(_pAd); \ - } - - -/* ----------------- Power Save Related MACRO ----------------- */ -#define RT28XX_PS_POLL_ENQUEUE(pAd) \ - { RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_PSPOLL); \ - RTUSBKickBulkOut(pAd); } - -#define RT28xx_CHIP_NAME "RT2870" -#define USB_CYC_CFG 0x02a4 -#define NT_SUCCESS(status) (((status) > 0) ? (1):(0)) -#define InterlockedIncrement atomic_inc -#define NdisInterlockedIncrement atomic_inc -#define InterlockedDecrement atomic_dec -#define NdisInterlockedDecrement atomic_dec -#define InterlockedExchange atomic_set -//#define NdisMSendComplete RTMP_SendComplete -#define NdisMCancelTimer RTMPCancelTimer -#define NdisAllocMemory(_ptr, _size, _flag) \ - do{_ptr = kmalloc((_size),(_flag));}while(0) -#define NdisFreeMemory(a, b, c) kfree((a)) -#define NdisMSleep RTMPusecDelay /* unit: microsecond */ - - -#define USBD_TRANSFER_DIRECTION_OUT 0 -#define USBD_TRANSFER_DIRECTION_IN 0 -#define USBD_SHORT_TRANSFER_OK 0 -#define PURB purbb_t - -#define RTUSB_FREE_URB(pUrb) usb_free_urb(pUrb) - -//#undef MlmeAllocateMemory -//#undef MlmeFreeMemory - -typedef struct usb_device * PUSB_DEV; - -/* MACRO for linux usb */ -typedef struct urb *purbb_t; -typedef struct usb_ctrlrequest devctrlrequest; -#define PIRP PVOID -#define PMDL PVOID -#define NDIS_OID UINT -#ifndef USB_ST_NOERROR -#define USB_ST_NOERROR 0 -#endif - -// vendor-specific control operations -#define CONTROL_TIMEOUT_JIFFIES ( (100 * HZ) / 1000) -#define UNLINK_TIMEOUT_MS 3 - -/* unlink urb */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,7) -#define RTUSB_UNLINK_URB(pUrb) usb_kill_urb(pUrb) -#else -#define RTUSB_UNLINK_URB(pUrb) usb_unlink_urb(pUrb) -#endif - -// Prototypes of completion funuc. -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) -#define RTUSBBulkOutDataPacketComplete(purb, pt_regs) RTUSBBulkOutDataPacketComplete(purb) -#define RTUSBBulkOutMLMEPacketComplete(pUrb, pt_regs) RTUSBBulkOutMLMEPacketComplete(pUrb) -#define RTUSBBulkOutNullFrameComplete(pUrb, pt_regs) RTUSBBulkOutNullFrameComplete(pUrb) -#define RTUSBBulkOutRTSFrameComplete(pUrb, pt_regs) RTUSBBulkOutRTSFrameComplete(pUrb) -#define RTUSBBulkOutPsPollComplete(pUrb, pt_regs) RTUSBBulkOutPsPollComplete(pUrb) -#define RTUSBBulkRxComplete(pUrb, pt_regs) RTUSBBulkRxComplete(pUrb) -#endif - - -VOID RTUSBBulkOutDataPacketComplete(purbb_t purb, struct pt_regs *pt_regs); -VOID RTUSBBulkOutMLMEPacketComplete(purbb_t pUrb, struct pt_regs *pt_regs); -VOID RTUSBBulkOutNullFrameComplete(purbb_t pUrb, struct pt_regs *pt_regs); -VOID RTUSBBulkOutRTSFrameComplete(purbb_t pUrb, struct pt_regs *pt_regs); -VOID RTUSBBulkOutPsPollComplete(purbb_t pUrb, struct pt_regs *pt_regs); -VOID RTUSBBulkRxComplete(purbb_t pUrb, struct pt_regs *pt_regs); - - -#define RTUSBMlmeUp(pAd) \ -{ \ - POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie; \ - if(pObj->MLMEThr_pid>0) \ - up(&(pAd->mlme_semaphore)); \ -} - -#define RTUSBCMDUp(pAd) \ -{ \ - POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie; \ - if(pObj->RTUSBCmdThr_pid>0) \ - up(&(pAd->RTUSBCmd_semaphore)); \ -} - - -static inline NDIS_STATUS RTMPAllocateMemory( - OUT PVOID *ptr, - IN size_t size) -{ - *ptr = kmalloc(size, GFP_ATOMIC); - if(*ptr) - return NDIS_STATUS_SUCCESS; - else - return NDIS_STATUS_RESOURCES; -} - -/* rtmp.h */ -#define BEACON_RING_SIZE 2 -#define DEVICE_VENDOR_REQUEST_OUT 0x40 -#define DEVICE_VENDOR_REQUEST_IN 0xc0 -#define INTERFACE_VENDOR_REQUEST_OUT 0x41 -#define INTERFACE_VENDOR_REQUEST_IN 0xc1 -#define MGMTPIPEIDX 0 // EP6 is highest priority - -#define BULKOUT_MGMT_RESET_FLAG 0x80 - -#define RTUSB_SET_BULK_FLAG(_M, _F) ((_M)->BulkFlags |= (_F)) -#define RTUSB_CLEAR_BULK_FLAG(_M, _F) ((_M)->BulkFlags &= ~(_F)) -#define RTUSB_TEST_BULK_FLAG(_M, _F) (((_M)->BulkFlags & (_F)) != 0) - -#define EnqueueCmd(cmdq, cmdqelmt) \ -{ \ - if (cmdq->size == 0) \ - cmdq->head = cmdqelmt; \ - else \ - cmdq->tail->next = cmdqelmt; \ - cmdq->tail = cmdqelmt; \ - cmdqelmt->next = NULL; \ - cmdq->size++; \ -} - -typedef struct _RT_SET_ASIC_WCID { - ULONG WCID; // mechanism for rekeying: 0:disable, 1: time-based, 2: packet-based - ULONG SetTid; // time-based: seconds, packet-based: kilo-packets - ULONG DeleteTid; // time-based: seconds, packet-based: kilo-packets -} RT_SET_ASIC_WCID,*PRT_SET_ASIC_WCID; - -typedef struct _RT_SET_ASIC_WCID_ATTRI { - ULONG WCID; // mechanism for rekeying: 0:disable, 1: time-based, 2: packet-based - ULONG Cipher; // ASIC Cipher definition - UCHAR Addr[ETH_LENGTH_OF_ADDRESS]; -} RT_SET_ASIC_WCID_ATTRI,*PRT_SET_ASIC_WCID_ATTRI; - -typedef struct _MLME_MEMORY_STRUCT { - PVOID AllocVa; //Pointer to the base virtual address of the allocated memory - struct _MLME_MEMORY_STRUCT *Next; //Pointer to the next virtual address of the allocated memory -} MLME_MEMORY_STRUCT, *PMLME_MEMORY_STRUCT; - -typedef struct _MLME_MEMORY_HANDLER { - BOOLEAN MemRunning; //The flag of the Mlme memory handler's status - UINT MemoryCount; //Total nonpaged system-space memory not size - UINT InUseCount; //Nonpaged system-space memory in used counts - UINT UnUseCount; //Nonpaged system-space memory available counts - INT PendingCount; //Nonpaged system-space memory for free counts - PMLME_MEMORY_STRUCT pInUseHead; //Pointer to the first nonpaed memory not used - PMLME_MEMORY_STRUCT pInUseTail; //Pointer to the last nonpaged memory not used - PMLME_MEMORY_STRUCT pUnUseHead; //Pointer to the first nonpaged memory in used - PMLME_MEMORY_STRUCT pUnUseTail; //Pointer to the last nonpaged memory in used - PULONG MemFreePending[MAX_MLME_HANDLER_MEMORY]; //an array to keep pending free-memory's pointer (32bits) -} MLME_MEMORY_HANDLER, *PMLME_MEMORY_HANDLER; - -typedef struct _CmdQElmt { - UINT command; - PVOID buffer; - ULONG bufferlength; - BOOLEAN CmdFromNdis; - BOOLEAN SetOperation; - struct _CmdQElmt *next; -} CmdQElmt, *PCmdQElmt; - -typedef struct _CmdQ { - UINT size; - CmdQElmt *head; - CmdQElmt *tail; - UINT32 CmdQState; -}CmdQ, *PCmdQ; - -// -// For WPA SUPPLICANT: WIRELESS EXT support wireless events: v14 or newer -// -#if WIRELESS_EXT >= 14 -//#define WPA_SUPPLICANT_SUPPORT 1 -#endif - -/* oid.h */ -// Cipher suite type for mixed mode group cipher, P802.11i-2004 -typedef enum _RT_802_11_CIPHER_SUITE_TYPE { - Cipher_Type_NONE, - Cipher_Type_WEP40, - Cipher_Type_TKIP, - Cipher_Type_RSVD, - Cipher_Type_CCMP, - Cipher_Type_WEP104 -} RT_802_11_CIPHER_SUITE_TYPE, *PRT_802_11_CIPHER_SUITE_TYPE; - -//CMDTHREAD_MULTI_READ_MAC -//CMDTHREAD_MULTI_WRITE_MAC -//CMDTHREAD_VENDOR_EEPROM_READ -//CMDTHREAD_VENDOR_EEPROM_WRITE -typedef struct _CMDHandler_TLV { - USHORT Offset; - USHORT Length; - UCHAR DataFirst; -} CMDHandler_TLV, *PCMDHandler_TLV; - -// New for MeetingHouse Api support -#define CMDTHREAD_VENDOR_RESET 0x0D730101 // cmd -#define CMDTHREAD_VENDOR_UNPLUG 0x0D730102 // cmd -#define CMDTHREAD_VENDOR_SWITCH_FUNCTION 0x0D730103 // cmd -#define CMDTHREAD_MULTI_WRITE_MAC 0x0D730107 // cmd -#define CMDTHREAD_MULTI_READ_MAC 0x0D730108 // cmd -#define CMDTHREAD_VENDOR_EEPROM_WRITE 0x0D73010A // cmd -#define CMDTHREAD_VENDOR_EEPROM_READ 0x0D73010B // cmd -#define CMDTHREAD_VENDOR_ENTER_TESTMODE 0x0D73010C // cmd -#define CMDTHREAD_VENDOR_EXIT_TESTMODE 0x0D73010D // cmd -#define CMDTHREAD_VENDOR_WRITE_BBP 0x0D730119 // cmd -#define CMDTHREAD_VENDOR_READ_BBP 0x0D730118 // cmd -#define CMDTHREAD_VENDOR_WRITE_RF 0x0D73011A // cmd -#define CMDTHREAD_VENDOR_FLIP_IQ 0x0D73011D // cmd -#define CMDTHREAD_RESET_BULK_OUT 0x0D730210 // cmd -#define CMDTHREAD_RESET_BULK_IN 0x0D730211 // cmd -#define CMDTHREAD_SET_PSM_BIT_SAVE 0x0D730212 // cmd -#define CMDTHREAD_SET_RADIO 0x0D730214 // cmd -#define CMDTHREAD_UPDATE_TX_RATE 0x0D730216 // cmd -#define CMDTHREAD_802_11_ADD_KEY_WEP 0x0D730218 // cmd -#define CMDTHREAD_RESET_FROM_ERROR 0x0D73021A // cmd -#define CMDTHREAD_LINK_DOWN 0x0D73021B // cmd -#define CMDTHREAD_RESET_FROM_NDIS 0x0D73021C // cmd -#define CMDTHREAD_CHECK_GPIO 0x0D730215 // cmd -#define CMDTHREAD_FORCE_WAKE_UP 0x0D730222 // cmd -#define CMDTHREAD_SET_BW 0x0D730225 // cmd -#define CMDTHREAD_SET_ASIC_WCID 0x0D730226 // cmd -#define CMDTHREAD_SET_ASIC_WCID_CIPHER 0x0D730227 // cmd -#define CMDTHREAD_QKERIODIC_EXECUT 0x0D73023D // cmd -#define RT_CMD_SET_KEY_TABLE 0x0D730228 // cmd -#define RT_CMD_SET_RX_WCID_TABLE 0x0D730229 // cmd -#define CMDTHREAD_SET_CLIENT_MAC_ENTRY 0x0D73023E // cmd -#define CMDTHREAD_802_11_QUERY_HARDWARE_REGISTER 0x0D710105 // cmd -#define CMDTHREAD_802_11_SET_PHY_MODE 0x0D79010C // cmd -#define CMDTHREAD_802_11_SET_STA_CONFIG 0x0D790111 // cmd -#define CMDTHREAD_802_11_SET_PREAMBLE 0x0D790101 // cmd -#define CMDTHREAD_802_11_COUNTER_MEASURE 0x0D790102 // cmd -// add by johnli, fix "in_interrupt" error when call "MacTableDeleteEntry" in Rx tasklet -#define CMDTHREAD_UPDATE_PROTECT 0x0D790103 // cmd -// end johnli - -#define WPA1AKMBIT 0x01 -#define WPA2AKMBIT 0x02 -#define WPA1PSKAKMBIT 0x04 -#define WPA2PSKAKMBIT 0x08 -#define TKIPBIT 0x01 -#define CCMPBIT 0x02 - - -#define RT28XX_STA_FORCE_WAKEUP(pAd, bFromTx) \ - RT28xxUsbStaAsicForceWakeup(pAd, bFromTx); - -#define RT28XX_STA_SLEEP_THEN_AUTO_WAKEUP(pAd, TbttNumToNextWakeUp) \ - RT28xxUsbStaAsicSleepThenAutoWakeup(pAd, TbttNumToNextWakeUp); - -#define RT28XX_MLME_RADIO_ON(pAd) \ - RT28xxUsbMlmeRadioOn(pAd); - -#define RT28XX_MLME_RADIO_OFF(pAd) \ - RT28xxUsbMlmeRadioOFF(pAd); - -#endif //__RT2870_H__ +#include "../rt2870/rt2870.h" diff --git a/drivers/staging/rt3070/rt28xx.h b/drivers/staging/rt3070/rt28xx.h index b637c4ee6096..c47ddc8bd9e9 100644 --- a/drivers/staging/rt3070/rt28xx.h +++ b/drivers/staging/rt3070/rt28xx.h @@ -1,2725 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - rt28xx.h - - Abstract: - RT28xx ASIC related definition & structures - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Jan Lee Jan-3-2006 created for RT2860c -*/ - -#ifndef __RT28XX_H__ -#define __RT28XX_H__ - - -// -// PCI registers - base address 0x0000 -// -#define PCI_CFG 0x0000 -#define PCI_EECTRL 0x0004 -#define PCI_MCUCTRL 0x0008 - -#define OPT_14 0x114 - -typedef int NTSTATUS; -#define RETRY_LIMIT 10 -#define STATUS_SUCCESS 0x00 -#define STATUS_UNSUCCESSFUL 0x01 - -// -// SCH/DMA registers - base address 0x0200 -// -// INT_SOURCE_CSR: Interrupt source register. Write one to clear corresponding bit -// -#define DMA_CSR0 0x200 -#define INT_SOURCE_CSR 0x200 -#ifdef RT_BIG_ENDIAN -typedef union _INT_SOURCE_CSR_STRUC { - struct { - UINT32 :14; - UINT32 TxCoherent:1; - UINT32 RxCoherent:1; - UINT32 GPTimer:1; - UINT32 AutoWakeup:1;//bit14 - UINT32 TXFifoStatusInt:1;//FIFO Statistics is full, sw should read 0x171c - UINT32 PreTBTT:1; - UINT32 TBTTInt:1; - UINT32 RxTxCoherent:1; - UINT32 MCUCommandINT:1; - UINT32 MgmtDmaDone:1; - UINT32 HccaDmaDone:1; - UINT32 Ac3DmaDone:1; - UINT32 Ac2DmaDone:1; - UINT32 Ac1DmaDone:1; - UINT32 Ac0DmaDone:1; - UINT32 RxDone:1; - UINT32 TxDelayINT:1; //delayed interrupt, not interrupt until several int or time limit hit - UINT32 RxDelayINT:1; //dealyed interrupt - } field; - UINT32 word; -} INT_SOURCE_CSR_STRUC, *PINT_SOURCE_CSR_STRUC; -#else -typedef union _INT_SOURCE_CSR_STRUC { - struct { - UINT32 RxDelayINT:1; - UINT32 TxDelayINT:1; - UINT32 RxDone:1; - UINT32 Ac0DmaDone:1;//4 - UINT32 Ac1DmaDone:1; - UINT32 Ac2DmaDone:1; - UINT32 Ac3DmaDone:1; - UINT32 HccaDmaDone:1; // bit7 - UINT32 MgmtDmaDone:1; - UINT32 MCUCommandINT:1;//bit 9 - UINT32 RxTxCoherent:1; - UINT32 TBTTInt:1; - UINT32 PreTBTT:1; - UINT32 TXFifoStatusInt:1;//FIFO Statistics is full, sw should read 0x171c - UINT32 AutoWakeup:1;//bit14 - UINT32 GPTimer:1; - UINT32 RxCoherent:1;//bit16 - UINT32 TxCoherent:1; - UINT32 :14; - } field; - UINT32 word; -} INT_SOURCE_CSR_STRUC, *PINT_SOURCE_CSR_STRUC; -#endif - -// -// INT_MASK_CSR: Interrupt MASK register. 1: the interrupt is mask OFF -// -#define INT_MASK_CSR 0x204 -#ifdef RT_BIG_ENDIAN -typedef union _INT_MASK_CSR_STRUC { - struct { - UINT32 TxCoherent:1; - UINT32 RxCoherent:1; - UINT32 :20; - UINT32 MCUCommandINT:1; - UINT32 MgmtDmaDone:1; - UINT32 HccaDmaDone:1; - UINT32 Ac3DmaDone:1; - UINT32 Ac2DmaDone:1; - UINT32 Ac1DmaDone:1; - UINT32 Ac0DmaDone:1; - UINT32 RxDone:1; - UINT32 TxDelay:1; - UINT32 RXDelay_INT_MSK:1; - } field; - UINT32 word; -}INT_MASK_CSR_STRUC, *PINT_MASK_CSR_STRUC; -#else -typedef union _INT_MASK_CSR_STRUC { - struct { - UINT32 RXDelay_INT_MSK:1; - UINT32 TxDelay:1; - UINT32 RxDone:1; - UINT32 Ac0DmaDone:1; - UINT32 Ac1DmaDone:1; - UINT32 Ac2DmaDone:1; - UINT32 Ac3DmaDone:1; - UINT32 HccaDmaDone:1; - UINT32 MgmtDmaDone:1; - UINT32 MCUCommandINT:1; - UINT32 :20; - UINT32 RxCoherent:1; - UINT32 TxCoherent:1; - } field; - UINT32 word; -} INT_MASK_CSR_STRUC, *PINT_MASK_CSR_STRUC; -#endif -#define WPDMA_GLO_CFG 0x208 -#ifdef RT_BIG_ENDIAN -typedef union _WPDMA_GLO_CFG_STRUC { - struct { - UINT32 HDR_SEG_LEN:16; - UINT32 RXHdrScater:8; - UINT32 BigEndian:1; - UINT32 EnTXWriteBackDDONE:1; - UINT32 WPDMABurstSIZE:2; - UINT32 RxDMABusy:1; - UINT32 EnableRxDMA:1; - UINT32 TxDMABusy:1; - UINT32 EnableTxDMA:1; - } field; - UINT32 word; -}WPDMA_GLO_CFG_STRUC, *PWPDMA_GLO_CFG_STRUC; -#else -typedef union _WPDMA_GLO_CFG_STRUC { - struct { - UINT32 EnableTxDMA:1; - UINT32 TxDMABusy:1; - UINT32 EnableRxDMA:1; - UINT32 RxDMABusy:1; - UINT32 WPDMABurstSIZE:2; - UINT32 EnTXWriteBackDDONE:1; - UINT32 BigEndian:1; - UINT32 RXHdrScater:8; - UINT32 HDR_SEG_LEN:16; - } field; - UINT32 word; -} WPDMA_GLO_CFG_STRUC, *PWPDMA_GLO_CFG_STRUC; -#endif -#define WPDMA_RST_IDX 0x20c -#ifdef RT_BIG_ENDIAN -typedef union _WPDMA_RST_IDX_STRUC { - struct { - UINT32 :15; - UINT32 RST_DRX_IDX0:1; - UINT32 rsv:10; - UINT32 RST_DTX_IDX5:1; - UINT32 RST_DTX_IDX4:1; - UINT32 RST_DTX_IDX3:1; - UINT32 RST_DTX_IDX2:1; - UINT32 RST_DTX_IDX1:1; - UINT32 RST_DTX_IDX0:1; - } field; - UINT32 word; -}WPDMA_RST_IDX_STRUC, *PWPDMA_RST_IDX_STRUC; -#else -typedef union _WPDMA_RST_IDX_STRUC { - struct { - UINT32 RST_DTX_IDX0:1; - UINT32 RST_DTX_IDX1:1; - UINT32 RST_DTX_IDX2:1; - UINT32 RST_DTX_IDX3:1; - UINT32 RST_DTX_IDX4:1; - UINT32 RST_DTX_IDX5:1; - UINT32 rsv:10; - UINT32 RST_DRX_IDX0:1; - UINT32 :15; - } field; - UINT32 word; -} WPDMA_RST_IDX_STRUC, *PWPDMA_RST_IDX_STRUC; -#endif -#define DELAY_INT_CFG 0x0210 -#ifdef RT_BIG_ENDIAN -typedef union _DELAY_INT_CFG_STRUC { - struct { - UINT32 TXDLY_INT_EN:1; - UINT32 TXMAX_PINT:7; - UINT32 TXMAX_PTIME:8; - UINT32 RXDLY_INT_EN:1; - UINT32 RXMAX_PINT:7; - UINT32 RXMAX_PTIME:8; - } field; - UINT32 word; -}DELAY_INT_CFG_STRUC, *PDELAY_INT_CFG_STRUC; -#else -typedef union _DELAY_INT_CFG_STRUC { - struct { - UINT32 RXMAX_PTIME:8; - UINT32 RXMAX_PINT:7; - UINT32 RXDLY_INT_EN:1; - UINT32 TXMAX_PTIME:8; - UINT32 TXMAX_PINT:7; - UINT32 TXDLY_INT_EN:1; - } field; - UINT32 word; -} DELAY_INT_CFG_STRUC, *PDELAY_INT_CFG_STRUC; -#endif -#define WMM_AIFSN_CFG 0x0214 -#ifdef RT_BIG_ENDIAN -typedef union _AIFSN_CSR_STRUC { - struct { - UINT32 Rsv:16; - UINT32 Aifsn3:4; // for AC_VO - UINT32 Aifsn2:4; // for AC_VI - UINT32 Aifsn1:4; // for AC_BK - UINT32 Aifsn0:4; // for AC_BE - } field; - UINT32 word; -} AIFSN_CSR_STRUC, *PAIFSN_CSR_STRUC; -#else -typedef union _AIFSN_CSR_STRUC { - struct { - UINT32 Aifsn0:4; // for AC_BE - UINT32 Aifsn1:4; // for AC_BK - UINT32 Aifsn2:4; // for AC_VI - UINT32 Aifsn3:4; // for AC_VO - UINT32 Rsv:16; - } field; - UINT32 word; -} AIFSN_CSR_STRUC, *PAIFSN_CSR_STRUC; -#endif -// -// CWMIN_CSR: CWmin for each EDCA AC -// -#define WMM_CWMIN_CFG 0x0218 -#ifdef RT_BIG_ENDIAN -typedef union _CWMIN_CSR_STRUC { - struct { - UINT32 Rsv:16; - UINT32 Cwmin3:4; // for AC_VO - UINT32 Cwmin2:4; // for AC_VI - UINT32 Cwmin1:4; // for AC_BK - UINT32 Cwmin0:4; // for AC_BE - } field; - UINT32 word; -} CWMIN_CSR_STRUC, *PCWMIN_CSR_STRUC; -#else -typedef union _CWMIN_CSR_STRUC { - struct { - UINT32 Cwmin0:4; // for AC_BE - UINT32 Cwmin1:4; // for AC_BK - UINT32 Cwmin2:4; // for AC_VI - UINT32 Cwmin3:4; // for AC_VO - UINT32 Rsv:16; - } field; - UINT32 word; -} CWMIN_CSR_STRUC, *PCWMIN_CSR_STRUC; -#endif - -// -// CWMAX_CSR: CWmin for each EDCA AC -// -#define WMM_CWMAX_CFG 0x021c -#ifdef RT_BIG_ENDIAN -typedef union _CWMAX_CSR_STRUC { - struct { - UINT32 Rsv:16; - UINT32 Cwmax3:4; // for AC_VO - UINT32 Cwmax2:4; // for AC_VI - UINT32 Cwmax1:4; // for AC_BK - UINT32 Cwmax0:4; // for AC_BE - } field; - UINT32 word; -} CWMAX_CSR_STRUC, *PCWMAX_CSR_STRUC; -#else -typedef union _CWMAX_CSR_STRUC { - struct { - UINT32 Cwmax0:4; // for AC_BE - UINT32 Cwmax1:4; // for AC_BK - UINT32 Cwmax2:4; // for AC_VI - UINT32 Cwmax3:4; // for AC_VO - UINT32 Rsv:16; - } field; - UINT32 word; -} CWMAX_CSR_STRUC, *PCWMAX_CSR_STRUC; -#endif - - -// -// AC_TXOP_CSR0: AC_BK/AC_BE TXOP register -// -#define WMM_TXOP0_CFG 0x0220 -#ifdef RT_BIG_ENDIAN -typedef union _AC_TXOP_CSR0_STRUC { - struct { - USHORT Ac1Txop; // for AC_BE, in unit of 32us - USHORT Ac0Txop; // for AC_BK, in unit of 32us - } field; - UINT32 word; -} AC_TXOP_CSR0_STRUC, *PAC_TXOP_CSR0_STRUC; -#else -typedef union _AC_TXOP_CSR0_STRUC { - struct { - USHORT Ac0Txop; // for AC_BK, in unit of 32us - USHORT Ac1Txop; // for AC_BE, in unit of 32us - } field; - UINT32 word; -} AC_TXOP_CSR0_STRUC, *PAC_TXOP_CSR0_STRUC; -#endif - -// -// AC_TXOP_CSR1: AC_VO/AC_VI TXOP register -// -#define WMM_TXOP1_CFG 0x0224 -#ifdef RT_BIG_ENDIAN -typedef union _AC_TXOP_CSR1_STRUC { - struct { - USHORT Ac3Txop; // for AC_VO, in unit of 32us - USHORT Ac2Txop; // for AC_VI, in unit of 32us - } field; - UINT32 word; -} AC_TXOP_CSR1_STRUC, *PAC_TXOP_CSR1_STRUC; -#else -typedef union _AC_TXOP_CSR1_STRUC { - struct { - USHORT Ac2Txop; // for AC_VI, in unit of 32us - USHORT Ac3Txop; // for AC_VO, in unit of 32us - } field; - UINT32 word; -} AC_TXOP_CSR1_STRUC, *PAC_TXOP_CSR1_STRUC; -#endif -#define RINGREG_DIFF 0x10 -#define GPIO_CTRL_CFG 0x0228 //MAC_CSR13 -#define MCU_CMD_CFG 0x022c -#define TX_BASE_PTR0 0x0230 //AC_BK base address -#define TX_MAX_CNT0 0x0234 -#define TX_CTX_IDX0 0x0238 -#define TX_DTX_IDX0 0x023c -#define TX_BASE_PTR1 0x0240 //AC_BE base address -#define TX_MAX_CNT1 0x0244 -#define TX_CTX_IDX1 0x0248 -#define TX_DTX_IDX1 0x024c -#define TX_BASE_PTR2 0x0250 //AC_VI base address -#define TX_MAX_CNT2 0x0254 -#define TX_CTX_IDX2 0x0258 -#define TX_DTX_IDX2 0x025c -#define TX_BASE_PTR3 0x0260 //AC_VO base address -#define TX_MAX_CNT3 0x0264 -#define TX_CTX_IDX3 0x0268 -#define TX_DTX_IDX3 0x026c -#define TX_BASE_PTR4 0x0270 //HCCA base address -#define TX_MAX_CNT4 0x0274 -#define TX_CTX_IDX4 0x0278 -#define TX_DTX_IDX4 0x027c -#define TX_BASE_PTR5 0x0280 //MGMT base address -#define TX_MAX_CNT5 0x0284 -#define TX_CTX_IDX5 0x0288 -#define TX_DTX_IDX5 0x028c -#define TX_MGMTMAX_CNT TX_MAX_CNT5 -#define TX_MGMTCTX_IDX TX_CTX_IDX5 -#define TX_MGMTDTX_IDX TX_DTX_IDX5 -#define RX_BASE_PTR 0x0290 //RX base address -#define RX_MAX_CNT 0x0294 -#define RX_CRX_IDX 0x0298 -#define RX_DRX_IDX 0x029c -#define USB_DMA_CFG 0x02a0 -#ifdef RT_BIG_ENDIAN -typedef union _USB_DMA_CFG_STRUC { - struct { - UINT32 TxBusy:1; //USB DMA TX FSM busy . debug only - UINT32 RxBusy:1; //USB DMA RX FSM busy . debug only - UINT32 EpoutValid:6; //OUT endpoint data valid. debug only - UINT32 TxBulkEn:1; //Enable USB DMA Tx - UINT32 RxBulkEn:1; //Enable USB DMA Rx - UINT32 RxBulkAggEn:1; //Enable Rx Bulk Aggregation - UINT32 TxopHalt:1; //Halt TXOP count down when TX buffer is full. - UINT32 TxClear:1; //Clear USB DMA TX path - UINT32 rsv:2; - UINT32 phyclear:1; //phy watch dog enable. write 1 - UINT32 RxBulkAggLmt:8; //Rx Bulk Aggregation Limit in unit of 1024 bytes - UINT32 RxBulkAggTOut:8; //Rx Bulk Aggregation TimeOut in unit of 33ns - } field; - UINT32 word; -} USB_DMA_CFG_STRUC, *PUSB_DMA_CFG_STRUC; -#else -typedef union _USB_DMA_CFG_STRUC { - struct { - UINT32 RxBulkAggTOut:8; //Rx Bulk Aggregation TimeOut in unit of 33ns - UINT32 RxBulkAggLmt:8; //Rx Bulk Aggregation Limit in unit of 256 bytes - UINT32 phyclear:1; //phy watch dog enable. write 1 - UINT32 rsv:2; - UINT32 TxClear:1; //Clear USB DMA TX path - UINT32 TxopHalt:1; //Halt TXOP count down when TX buffer is full. - UINT32 RxBulkAggEn:1; //Enable Rx Bulk Aggregation - UINT32 RxBulkEn:1; //Enable USB DMA Rx - UINT32 TxBulkEn:1; //Enable USB DMA Tx - UINT32 EpoutValid:6; //OUT endpoint data valid - UINT32 RxBusy:1; //USB DMA RX FSM busy - UINT32 TxBusy:1; //USB DMA TX FSM busy - } field; - UINT32 word; -} USB_DMA_CFG_STRUC, *PUSB_DMA_CFG_STRUC; -#endif - -// -// 3 PBF registers -// -// -// Most are for debug. Driver doesn't touch PBF register. -#define PBF_SYS_CTRL 0x0400 -#define PBF_CFG 0x0408 -#define PBF_MAX_PCNT 0x040C -#define PBF_CTRL 0x0410 -#define PBF_INT_STA 0x0414 -#define PBF_INT_ENA 0x0418 -#define TXRXQ_PCNT 0x0438 -#define PBF_DBG 0x043c -#define PBF_CAP_CTRL 0x0440 - - -// eFuse registers -#define EFUSE_CTRL 0x0580 -#define EFUSE_DATA0 0x0590 -#define EFUSE_DATA1 0x0594 -#define EFUSE_DATA2 0x0598 -#define EFUSE_DATA3 0x059c -#define EFUSE_USAGE_MAP_START 0x2d0 -#define EFUSE_USAGE_MAP_END 0x2fc -#define EFUSE_TAG 0x2fe -#define EFUSE_USAGE_MAP_SIZE 45 - -#ifdef RT_BIG_ENDIAN -typedef union _EFUSE_CTRL_STRUC { - struct { - UINT32 SEL_EFUSE:1; - UINT32 EFSROM_KICK:1; - UINT32 RESERVED:4; - UINT32 EFSROM_AIN:10; - UINT32 EFSROM_LDO_ON_TIME:2; - UINT32 EFSROM_LDO_OFF_TIME:6; - UINT32 EFSROM_MODE:2; - UINT32 EFSROM_AOUT:6; - } field; - UINT32 word; -} EFUSE_CTRL_STRUC, *PEFUSE_CTRL_STRUC; -#else -typedef union _EFUSE_CTRL_STRUC { - struct { - UINT32 EFSROM_AOUT:6; - UINT32 EFSROM_MODE:2; - UINT32 EFSROM_LDO_OFF_TIME:6; - UINT32 EFSROM_LDO_ON_TIME:2; - UINT32 EFSROM_AIN:10; - UINT32 RESERVED:4; - UINT32 EFSROM_KICK:1; - UINT32 SEL_EFUSE:1; - } field; - UINT32 word; -} EFUSE_CTRL_STRUC, *PEFUSE_CTRL_STRUC; -#endif // RT_BIG_ENDIAN // - -#define LDO_CFG0 0x05d4 -#define GPIO_SWITCH 0x05dc - -// -// 4 MAC registers -// -// -// 4.1 MAC SYSTEM configuration registers (offset:0x1000) -// -#define MAC_CSR0 0x1000 -#ifdef RT_BIG_ENDIAN -typedef union _ASIC_VER_ID_STRUC { - struct { - USHORT ASICVer; // version : 2860 - USHORT ASICRev; // reversion : 0 - } field; - UINT32 word; -} ASIC_VER_ID_STRUC, *PASIC_VER_ID_STRUC; -#else -typedef union _ASIC_VER_ID_STRUC { - struct { - USHORT ASICRev; // reversion : 0 - USHORT ASICVer; // version : 2860 - } field; - UINT32 word; -} ASIC_VER_ID_STRUC, *PASIC_VER_ID_STRUC; -#endif -#define MAC_SYS_CTRL 0x1004 //MAC_CSR1 -#define MAC_ADDR_DW0 0x1008 // MAC ADDR DW0 -#define MAC_ADDR_DW1 0x100c // MAC ADDR DW1 -// -// MAC_CSR2: STA MAC register 0 -// -#ifdef RT_BIG_ENDIAN -typedef union _MAC_DW0_STRUC { - struct { - UCHAR Byte3; // MAC address byte 3 - UCHAR Byte2; // MAC address byte 2 - UCHAR Byte1; // MAC address byte 1 - UCHAR Byte0; // MAC address byte 0 - } field; - UINT32 word; -} MAC_DW0_STRUC, *PMAC_DW0_STRUC; -#else -typedef union _MAC_DW0_STRUC { - struct { - UCHAR Byte0; // MAC address byte 0 - UCHAR Byte1; // MAC address byte 1 - UCHAR Byte2; // MAC address byte 2 - UCHAR Byte3; // MAC address byte 3 - } field; - UINT32 word; -} MAC_DW0_STRUC, *PMAC_DW0_STRUC; -#endif - -// -// MAC_CSR3: STA MAC register 1 -// -#ifdef RT_BIG_ENDIAN -typedef union _MAC_DW1_STRUC { - struct { - UCHAR Rsvd1; - UCHAR U2MeMask; - UCHAR Byte5; // MAC address byte 5 - UCHAR Byte4; // MAC address byte 4 - } field; - UINT32 word; -} MAC_DW1_STRUC, *PMAC_DW1_STRUC; -#else -typedef union _MAC_DW1_STRUC { - struct { - UCHAR Byte4; // MAC address byte 4 - UCHAR Byte5; // MAC address byte 5 - UCHAR U2MeMask; - UCHAR Rsvd1; - } field; - UINT32 word; -} MAC_DW1_STRUC, *PMAC_DW1_STRUC; -#endif - -#define MAC_BSSID_DW0 0x1010 // MAC BSSID DW0 -#define MAC_BSSID_DW1 0x1014 // MAC BSSID DW1 - -// -// MAC_CSR5: BSSID register 1 -// -#ifdef RT_BIG_ENDIAN -typedef union _MAC_CSR5_STRUC { - struct { - USHORT Rsvd:11; - USHORT MBssBcnNum:3; - USHORT BssIdMode:2; // 0: one BSSID, 10: 4 BSSID, 01: 2 BSSID , 11: 8BSSID - UCHAR Byte5; // BSSID byte 5 - UCHAR Byte4; // BSSID byte 4 - } field; - UINT32 word; -} MAC_CSR5_STRUC, *PMAC_CSR5_STRUC; -#else -typedef union _MAC_CSR5_STRUC { - struct { - UCHAR Byte4; // BSSID byte 4 - UCHAR Byte5; // BSSID byte 5 - USHORT BssIdMask:2; // 0: one BSSID, 10: 4 BSSID, 01: 2 BSSID , 11: 8BSSID - USHORT MBssBcnNum:3; - USHORT Rsvd:11; - } field; - UINT32 word; -} MAC_CSR5_STRUC, *PMAC_CSR5_STRUC; -#endif - -#define MAX_LEN_CFG 0x1018 // rt2860b max 16k bytes. bit12:13 Maximum PSDU length (power factor) 0:2^13, 1:2^14, 2:2^15, 3:2^16 -#define BBP_CSR_CFG 0x101c // -// -// BBP_CSR_CFG: BBP serial control register -// -#ifdef RT_BIG_ENDIAN -typedef union _BBP_CSR_CFG_STRUC { - struct { - UINT32 :12; - UINT32 BBP_RW_MODE:1; // 0: use serial mode 1:parallel - UINT32 BBP_PAR_DUR:1; // 0: 4 MAC clock cycles 1: 8 MAC clock cycles - UINT32 Busy:1; // 1: ASIC is busy execute BBP programming. - UINT32 fRead:1; // 0: Write BBP, 1: Read BBP - UINT32 RegNum:8; // Selected BBP register - UINT32 Value:8; // Register value to program into BBP - } field; - UINT32 word; -} BBP_CSR_CFG_STRUC, *PBBP_CSR_CFG_STRUC; -#else -typedef union _BBP_CSR_CFG_STRUC { - struct { - UINT32 Value:8; // Register value to program into BBP - UINT32 RegNum:8; // Selected BBP register - UINT32 fRead:1; // 0: Write BBP, 1: Read BBP - UINT32 Busy:1; // 1: ASIC is busy execute BBP programming. - UINT32 BBP_PAR_DUR:1; // 0: 4 MAC clock cycles 1: 8 MAC clock cycles - UINT32 BBP_RW_MODE:1; // 0: use serial mode 1:parallel - UINT32 :12; - } field; - UINT32 word; -} BBP_CSR_CFG_STRUC, *PBBP_CSR_CFG_STRUC; -#endif -#define RF_CSR_CFG0 0x1020 -// -// RF_CSR_CFG: RF control register -// -#ifdef RT_BIG_ENDIAN -typedef union _RF_CSR_CFG0_STRUC { - struct { - UINT32 Busy:1; // 0: idle 1: 8busy - UINT32 Sel:1; // 0:RF_LE0 activate 1:RF_LE1 activate - UINT32 StandbyMode:1; // 0: high when stand by 1: low when standby - UINT32 bitwidth:5; // Selected BBP register - UINT32 RegIdAndContent:24; // Register value to program into BBP - } field; - UINT32 word; -} RF_CSR_CFG0_STRUC, *PRF_CSR_CFG0_STRUC; -#else -typedef union _RF_CSR_CFG0_STRUC { - struct { - UINT32 RegIdAndContent:24; // Register value to program into BBP - UINT32 bitwidth:5; // Selected BBP register - UINT32 StandbyMode:1; // 0: high when stand by 1: low when standby - UINT32 Sel:1; // 0:RF_LE0 activate 1:RF_LE1 activate - UINT32 Busy:1; // 0: idle 1: 8busy - } field; - UINT32 word; -} RF_CSR_CFG0_STRUC, *PRF_CSR_CFG0_STRUC; -#endif -#define RF_CSR_CFG1 0x1024 -#ifdef RT_BIG_ENDIAN -typedef union _RF_CSR_CFG1_STRUC { - struct { - UINT32 rsv:7; // 0: idle 1: 8busy - UINT32 RFGap:5; // Gap between BB_CONTROL_RF and RF_LE. 0: 3 system clock cycle (37.5usec) 1: 5 system clock cycle (62.5usec) - UINT32 RegIdAndContent:24; // Register value to program into BBP - } field; - UINT32 word; -} RF_CSR_CFG1_STRUC, *PRF_CSR_CFG1_STRUC; -#else -typedef union _RF_CSR_CFG1_STRUC { - struct { - UINT32 RegIdAndContent:24; // Register value to program into BBP - UINT32 RFGap:5; // Gap between BB_CONTROL_RF and RF_LE. 0: 3 system clock cycle (37.5usec) 1: 5 system clock cycle (62.5usec) - UINT32 rsv:7; // 0: idle 1: 8busy - } field; - UINT32 word; -} RF_CSR_CFG1_STRUC, *PRF_CSR_CFG1_STRUC; -#endif -#define RF_CSR_CFG2 0x1028 // -#ifdef RT_BIG_ENDIAN -typedef union _RF_CSR_CFG2_STRUC { - struct { - UINT32 rsv:8; // 0: idle 1: 8busy - UINT32 RegIdAndContent:24; // Register value to program into BBP - } field; - UINT32 word; -} RF_CSR_CFG2_STRUC, *PRF_CSR_CFG2_STRUC; -#else -typedef union _RF_CSR_CFG2_STRUC { - struct { - UINT32 RegIdAndContent:24; // Register value to program into BBP - UINT32 rsv:8; // 0: idle 1: 8busy - } field; - UINT32 word; -} RF_CSR_CFG2_STRUC, *PRF_CSR_CFG2_STRUC; -#endif -#define LED_CFG 0x102c // MAC_CSR14 -#ifdef RT_BIG_ENDIAN -typedef union _LED_CFG_STRUC { - struct { - UINT32 :1; - UINT32 LedPolar:1; // Led Polarity. 0: active low1: active high - UINT32 YLedMode:2; // yellow Led Mode - UINT32 GLedMode:2; // green Led Mode - UINT32 RLedMode:2; // red Led Mode 0: off1: blinking upon TX2: periodic slow blinking3: always on - UINT32 rsv:2; - UINT32 SlowBlinkPeriod:6; // slow blinking period. unit:1ms - UINT32 OffPeriod:8; // blinking off period unit 1ms - UINT32 OnPeriod:8; // blinking on period unit 1ms - } field; - UINT32 word; -} LED_CFG_STRUC, *PLED_CFG_STRUC; -#else -typedef union _LED_CFG_STRUC { - struct { - UINT32 OnPeriod:8; // blinking on period unit 1ms - UINT32 OffPeriod:8; // blinking off period unit 1ms - UINT32 SlowBlinkPeriod:6; // slow blinking period. unit:1ms - UINT32 rsv:2; - UINT32 RLedMode:2; // red Led Mode 0: off1: blinking upon TX2: periodic slow blinking3: always on - UINT32 GLedMode:2; // green Led Mode - UINT32 YLedMode:2; // yellow Led Mode - UINT32 LedPolar:1; // Led Polarity. 0: active low1: active high - UINT32 :1; - } field; - UINT32 word; -} LED_CFG_STRUC, *PLED_CFG_STRUC; -#endif -// -// 4.2 MAC TIMING configuration registers (offset:0x1100) -// -#define XIFS_TIME_CFG 0x1100 // MAC_CSR8 MAC_CSR9 -#ifdef RT_BIG_ENDIAN -typedef union _IFS_SLOT_CFG_STRUC { - struct { - UINT32 rsv:2; - UINT32 BBRxendEnable:1; // reference RXEND signal to begin XIFS defer - UINT32 EIFS:9; // unit 1us - UINT32 OfdmXifsTime:4; //OFDM SIFS. unit 1us. Applied after OFDM RX when MAC doesn't reference BBP signal BBRXEND - UINT32 OfdmSifsTime:8; // unit 1us. Applied after OFDM RX/TX - UINT32 CckmSifsTime:8; // unit 1us. Applied after CCK RX/TX - } field; - UINT32 word; -} IFS_SLOT_CFG_STRUC, *PIFS_SLOT_CFG_STRUC; -#else -typedef union _IFS_SLOT_CFG_STRUC { - struct { - UINT32 CckmSifsTime:8; // unit 1us. Applied after CCK RX/TX - UINT32 OfdmSifsTime:8; // unit 1us. Applied after OFDM RX/TX - UINT32 OfdmXifsTime:4; //OFDM SIFS. unit 1us. Applied after OFDM RX when MAC doesn't reference BBP signal BBRXEND - UINT32 EIFS:9; // unit 1us - UINT32 BBRxendEnable:1; // reference RXEND signal to begin XIFS defer - UINT32 rsv:2; - } field; - UINT32 word; -} IFS_SLOT_CFG_STRUC, *PIFS_SLOT_CFG_STRUC; -#endif - -#define BKOFF_SLOT_CFG 0x1104 // mac_csr9 last 8 bits -#define NAV_TIME_CFG 0x1108 // NAV (MAC_CSR15) -#define CH_TIME_CFG 0x110C // Count as channel busy -#define PBF_LIFE_TIMER 0x1110 //TX/RX MPDU timestamp timer (free run)Unit: 1us -#define BCN_TIME_CFG 0x1114 // TXRX_CSR9 - -#define BCN_OFFSET0 0x042C -#define BCN_OFFSET1 0x0430 - -// -// BCN_TIME_CFG : Synchronization control register -// -#ifdef RT_BIG_ENDIAN -typedef union _BCN_TIME_CFG_STRUC { - struct { - UINT32 TxTimestampCompensate:8; - UINT32 :3; - UINT32 bBeaconGen:1; // Enable beacon generator - UINT32 bTBTTEnable:1; - UINT32 TsfSyncMode:2; // Enable TSF sync, 00: disable, 01: infra mode, 10: ad-hoc mode - UINT32 bTsfTicking:1; // Enable TSF auto counting - UINT32 BeaconInterval:16; // in unit of 1/16 TU - } field; - UINT32 word; -} BCN_TIME_CFG_STRUC, *PBCN_TIME_CFG_STRUC; -#else -typedef union _BCN_TIME_CFG_STRUC { - struct { - UINT32 BeaconInterval:16; // in unit of 1/16 TU - UINT32 bTsfTicking:1; // Enable TSF auto counting - UINT32 TsfSyncMode:2; // Enable TSF sync, 00: disable, 01: infra mode, 10: ad-hoc mode - UINT32 bTBTTEnable:1; - UINT32 bBeaconGen:1; // Enable beacon generator - UINT32 :3; - UINT32 TxTimestampCompensate:8; - } field; - UINT32 word; -} BCN_TIME_CFG_STRUC, *PBCN_TIME_CFG_STRUC; -#endif -#define TBTT_SYNC_CFG 0x1118 // txrx_csr10 -#define TSF_TIMER_DW0 0x111C // Local TSF timer lsb 32 bits. Read-only -#define TSF_TIMER_DW1 0x1120 // msb 32 bits. Read-only. -#define TBTT_TIMER 0x1124 // TImer remains till next TBTT. Read-only. TXRX_CSR14 -#define INT_TIMER_CFG 0x1128 // -#define INT_TIMER_EN 0x112c // GP-timer and pre-tbtt Int enable -#define CH_IDLE_STA 0x1130 // channel idle time -#define CH_BUSY_STA 0x1134 // channle busy time -// -// 4.2 MAC POWER configuration registers (offset:0x1200) -// -#define MAC_STATUS_CFG 0x1200 // old MAC_CSR12 -#define PWR_PIN_CFG 0x1204 // old MAC_CSR12 -#define AUTO_WAKEUP_CFG 0x1208 // old MAC_CSR10 -// -// AUTO_WAKEUP_CFG: Manual power control / status register -// -#ifdef RT_BIG_ENDIAN -typedef union _AUTO_WAKEUP_STRUC { - struct { - UINT32 :16; - UINT32 EnableAutoWakeup:1; // 0:sleep, 1:awake - UINT32 NumofSleepingTbtt:7; // ForceWake has high privilege than PutToSleep when both set - UINT32 AutoLeadTime:8; - } field; - UINT32 word; -} AUTO_WAKEUP_STRUC, *PAUTO_WAKEUP_STRUC; -#else -typedef union _AUTO_WAKEUP_STRUC { - struct { - UINT32 AutoLeadTime:8; - UINT32 NumofSleepingTbtt:7; // ForceWake has high privilege than PutToSleep when both set - UINT32 EnableAutoWakeup:1; // 0:sleep, 1:awake - UINT32 :16; - } field; - UINT32 word; -} AUTO_WAKEUP_STRUC, *PAUTO_WAKEUP_STRUC; -#endif -// -// 4.3 MAC TX configuration registers (offset:0x1300) -// - -#define EDCA_AC0_CFG 0x1300 //AC_TXOP_CSR0 0x3474 -#define EDCA_AC1_CFG 0x1304 -#define EDCA_AC2_CFG 0x1308 -#define EDCA_AC3_CFG 0x130c -#ifdef RT_BIG_ENDIAN -typedef union _EDCA_AC_CFG_STRUC { - struct { - UINT32 :12; // - UINT32 Cwmax:4; //unit power of 2 - UINT32 Cwmin:4; // - UINT32 Aifsn:4; // # of slot time - UINT32 AcTxop:8; // in unit of 32us - } field; - UINT32 word; -} EDCA_AC_CFG_STRUC, *PEDCA_AC_CFG_STRUC; -#else -typedef union _EDCA_AC_CFG_STRUC { - struct { - UINT32 AcTxop:8; // in unit of 32us - UINT32 Aifsn:4; // # of slot time - UINT32 Cwmin:4; // - UINT32 Cwmax:4; //unit power of 2 - UINT32 :12; // - } field; - UINT32 word; -} EDCA_AC_CFG_STRUC, *PEDCA_AC_CFG_STRUC; -#endif - -#define EDCA_TID_AC_MAP 0x1310 -#define TX_PWR_CFG_0 0x1314 -#define TX_PWR_CFG_1 0x1318 -#define TX_PWR_CFG_2 0x131C -#define TX_PWR_CFG_3 0x1320 -#define TX_PWR_CFG_4 0x1324 -#define TX_PIN_CFG 0x1328 -#define TX_BAND_CFG 0x132c // 0x1 use upper 20MHz. 0 juse lower 20MHz -#define TX_SW_CFG0 0x1330 -#define TX_SW_CFG1 0x1334 -#define TX_SW_CFG2 0x1338 -#define TXOP_THRES_CFG 0x133c -#define TXOP_CTRL_CFG 0x1340 -#define TX_RTS_CFG 0x1344 - -#ifdef RT_BIG_ENDIAN -typedef union _TX_RTS_CFG_STRUC { - struct { - UINT32 rsv:7; - UINT32 RtsFbkEn:1; // enable rts rate fallback - UINT32 RtsThres:16; // unit:byte - UINT32 AutoRtsRetryLimit:8; - } field; - UINT32 word; -} TX_RTS_CFG_STRUC, *PTX_RTS_CFG_STRUC; -#else -typedef union _TX_RTS_CFG_STRUC { - struct { - UINT32 AutoRtsRetryLimit:8; - UINT32 RtsThres:16; // unit:byte - UINT32 RtsFbkEn:1; // enable rts rate fallback - UINT32 rsv:7; // 1: HT non-STBC control frame enable - } field; - UINT32 word; -} TX_RTS_CFG_STRUC, *PTX_RTS_CFG_STRUC; -#endif -#define TX_TIMEOUT_CFG 0x1348 -#ifdef RT_BIG_ENDIAN -typedef union _TX_TIMEOUT_CFG_STRUC { - struct { - UINT32 rsv2:8; - UINT32 TxopTimeout:8; //TXOP timeout value for TXOP truncation. It is recommended that (SLOT_TIME) > (TX_OP_TIMEOUT) > (RX_ACK_TIMEOUT) - UINT32 RxAckTimeout:8; // unit:slot. Used for TX precedure - UINT32 MpduLifeTime:4; // expiration time = 2^(9+MPDU LIFE TIME) us - UINT32 rsv:4; - } field; - UINT32 word; -} TX_TIMEOUT_CFG_STRUC, *PTX_TIMEOUT_CFG_STRUC; -#else -typedef union _TX_TIMEOUT_CFG_STRUC { - struct { - UINT32 rsv:4; - UINT32 MpduLifeTime:4; // expiration time = 2^(9+MPDU LIFE TIME) us - UINT32 RxAckTimeout:8; // unit:slot. Used for TX precedure - UINT32 TxopTimeout:8; //TXOP timeout value for TXOP truncation. It is recommended that (SLOT_TIME) > (TX_OP_TIMEOUT) > (RX_ACK_TIMEOUT) - UINT32 rsv2:8; // 1: HT non-STBC control frame enable - } field; - UINT32 word; -} TX_TIMEOUT_CFG_STRUC, *PTX_TIMEOUT_CFG_STRUC; -#endif -#define TX_RTY_CFG 0x134c -#ifdef RT_BIG_ENDIAN -typedef union PACKED _TX_RTY_CFG_STRUC { - struct { - UINT32 rsv:1; - UINT32 TxautoFBEnable:1; // Tx retry PHY rate auto fallback enable - UINT32 AggRtyMode:1; // Aggregate MPDU retry mode. 0:expired by retry limit, 1: expired by mpdu life timer - UINT32 NonAggRtyMode:1; // Non-Aggregate MPDU retry mode. 0:expired by retry limit, 1: expired by mpdu life timer - UINT32 LongRtyThre:12; // Long retry threshoold - UINT32 LongRtyLimit:8; //long retry limit - UINT32 ShortRtyLimit:8; // short retry limit - - } field; - UINT32 word; -} TX_RTY_CFG_STRUC, *PTX_RTY_CFG_STRUC; -#else -typedef union PACKED _TX_RTY_CFG_STRUC { - struct { - UINT32 ShortRtyLimit:8; // short retry limit - UINT32 LongRtyLimit:8; //long retry limit - UINT32 LongRtyThre:12; // Long retry threshoold - UINT32 NonAggRtyMode:1; // Non-Aggregate MPDU retry mode. 0:expired by retry limit, 1: expired by mpdu life timer - UINT32 AggRtyMode:1; // Aggregate MPDU retry mode. 0:expired by retry limit, 1: expired by mpdu life timer - UINT32 TxautoFBEnable:1; // Tx retry PHY rate auto fallback enable - UINT32 rsv:1; // 1: HT non-STBC control frame enable - } field; - UINT32 word; -} TX_RTY_CFG_STRUC, *PTX_RTY_CFG_STRUC; -#endif -#define TX_LINK_CFG 0x1350 -#ifdef RT_BIG_ENDIAN -typedef union PACKED _TX_LINK_CFG_STRUC { - struct PACKED { - UINT32 RemotMFS:8; //remote MCS feedback sequence number - UINT32 RemotMFB:8; // remote MCS feedback - UINT32 rsv:3; // - UINT32 TxCFAckEn:1; // Piggyback CF-ACK enable - UINT32 TxRDGEn:1; // RDG TX enable - UINT32 TxMRQEn:1; // MCS request TX enable - UINT32 RemoteUMFSEnable:1; // remote unsolicit MFB enable. 0: not apply remote remote unsolicit (MFS=7) - UINT32 MFBEnable:1; // TX apply remote MFB 1:enable - UINT32 RemoteMFBLifeTime:8; //remote MFB life time. unit : 32us - } field; - UINT32 word; -} TX_LINK_CFG_STRUC, *PTX_LINK_CFG_STRUC; -#else -typedef union PACKED _TX_LINK_CFG_STRUC { - struct PACKED { - UINT32 RemoteMFBLifeTime:8; //remote MFB life time. unit : 32us - UINT32 MFBEnable:1; // TX apply remote MFB 1:enable - UINT32 RemoteUMFSEnable:1; // remote unsolicit MFB enable. 0: not apply remote remote unsolicit (MFS=7) - UINT32 TxMRQEn:1; // MCS request TX enable - UINT32 TxRDGEn:1; // RDG TX enable - UINT32 TxCFAckEn:1; // Piggyback CF-ACK enable - UINT32 rsv:3; // - UINT32 RemotMFB:8; // remote MCS feedback - UINT32 RemotMFS:8; //remote MCS feedback sequence number - } field; - UINT32 word; -} TX_LINK_CFG_STRUC, *PTX_LINK_CFG_STRUC; -#endif -#define HT_FBK_CFG0 0x1354 -#ifdef RT_BIG_ENDIAN -typedef union PACKED _HT_FBK_CFG0_STRUC { - struct { - UINT32 HTMCS7FBK:4; - UINT32 HTMCS6FBK:4; - UINT32 HTMCS5FBK:4; - UINT32 HTMCS4FBK:4; - UINT32 HTMCS3FBK:4; - UINT32 HTMCS2FBK:4; - UINT32 HTMCS1FBK:4; - UINT32 HTMCS0FBK:4; - } field; - UINT32 word; -} HT_FBK_CFG0_STRUC, *PHT_FBK_CFG0_STRUC; -#else -typedef union PACKED _HT_FBK_CFG0_STRUC { - struct { - UINT32 HTMCS0FBK:4; - UINT32 HTMCS1FBK:4; - UINT32 HTMCS2FBK:4; - UINT32 HTMCS3FBK:4; - UINT32 HTMCS4FBK:4; - UINT32 HTMCS5FBK:4; - UINT32 HTMCS6FBK:4; - UINT32 HTMCS7FBK:4; - } field; - UINT32 word; -} HT_FBK_CFG0_STRUC, *PHT_FBK_CFG0_STRUC; -#endif -#define HT_FBK_CFG1 0x1358 -#ifdef RT_BIG_ENDIAN -typedef union _HT_FBK_CFG1_STRUC { - struct { - UINT32 HTMCS15FBK:4; - UINT32 HTMCS14FBK:4; - UINT32 HTMCS13FBK:4; - UINT32 HTMCS12FBK:4; - UINT32 HTMCS11FBK:4; - UINT32 HTMCS10FBK:4; - UINT32 HTMCS9FBK:4; - UINT32 HTMCS8FBK:4; - } field; - UINT32 word; -} HT_FBK_CFG1_STRUC, *PHT_FBK_CFG1_STRUC; -#else -typedef union _HT_FBK_CFG1_STRUC { - struct { - UINT32 HTMCS8FBK:4; - UINT32 HTMCS9FBK:4; - UINT32 HTMCS10FBK:4; - UINT32 HTMCS11FBK:4; - UINT32 HTMCS12FBK:4; - UINT32 HTMCS13FBK:4; - UINT32 HTMCS14FBK:4; - UINT32 HTMCS15FBK:4; - } field; - UINT32 word; -} HT_FBK_CFG1_STRUC, *PHT_FBK_CFG1_STRUC; -#endif -#define LG_FBK_CFG0 0x135c -#ifdef RT_BIG_ENDIAN -typedef union _LG_FBK_CFG0_STRUC { - struct { - UINT32 OFDMMCS7FBK:4; //initial value is 6 - UINT32 OFDMMCS6FBK:4; //initial value is 5 - UINT32 OFDMMCS5FBK:4; //initial value is 4 - UINT32 OFDMMCS4FBK:4; //initial value is 3 - UINT32 OFDMMCS3FBK:4; //initial value is 2 - UINT32 OFDMMCS2FBK:4; //initial value is 1 - UINT32 OFDMMCS1FBK:4; //initial value is 0 - UINT32 OFDMMCS0FBK:4; //initial value is 0 - } field; - UINT32 word; -} LG_FBK_CFG0_STRUC, *PLG_FBK_CFG0_STRUC; -#else -typedef union _LG_FBK_CFG0_STRUC { - struct { - UINT32 OFDMMCS0FBK:4; //initial value is 0 - UINT32 OFDMMCS1FBK:4; //initial value is 0 - UINT32 OFDMMCS2FBK:4; //initial value is 1 - UINT32 OFDMMCS3FBK:4; //initial value is 2 - UINT32 OFDMMCS4FBK:4; //initial value is 3 - UINT32 OFDMMCS5FBK:4; //initial value is 4 - UINT32 OFDMMCS6FBK:4; //initial value is 5 - UINT32 OFDMMCS7FBK:4; //initial value is 6 - } field; - UINT32 word; -} LG_FBK_CFG0_STRUC, *PLG_FBK_CFG0_STRUC; -#endif -#define LG_FBK_CFG1 0x1360 -#ifdef RT_BIG_ENDIAN -typedef union _LG_FBK_CFG1_STRUC { - struct { - UINT32 rsv:16; - UINT32 CCKMCS3FBK:4; //initial value is 2 - UINT32 CCKMCS2FBK:4; //initial value is 1 - UINT32 CCKMCS1FBK:4; //initial value is 0 - UINT32 CCKMCS0FBK:4; //initial value is 0 - } field; - UINT32 word; -} LG_FBK_CFG1_STRUC, *PLG_FBK_CFG1_STRUC; -#else -typedef union _LG_FBK_CFG1_STRUC { - struct { - UINT32 CCKMCS0FBK:4; //initial value is 0 - UINT32 CCKMCS1FBK:4; //initial value is 0 - UINT32 CCKMCS2FBK:4; //initial value is 1 - UINT32 CCKMCS3FBK:4; //initial value is 2 - UINT32 rsv:16; - } field; - UINT32 word; -} LG_FBK_CFG1_STRUC, *PLG_FBK_CFG1_STRUC; -#endif - -//======================================================= -//================ Protection Paramater================================ -//======================================================= -#define CCK_PROT_CFG 0x1364 //CCK Protection -#define ASIC_SHORTNAV 1 -#define ASIC_LONGNAV 2 -#define ASIC_RTS 1 -#define ASIC_CTS 2 -#ifdef RT_BIG_ENDIAN -typedef union _PROT_CFG_STRUC { - struct { - UINT32 rsv:5; - UINT32 RTSThEn:1; //RTS threshold enable on CCK TX - UINT32 TxopAllowGF40:1; //CCK TXOP allowance.0:disallow. - UINT32 TxopAllowGF20:1; //CCK TXOP allowance.0:disallow. - UINT32 TxopAllowMM40:1; //CCK TXOP allowance.0:disallow. - UINT32 TxopAllowMM20:1; //CCK TXOP allowance. 0:disallow. - UINT32 TxopAllowOfdm:1; //CCK TXOP allowance.0:disallow. - UINT32 TxopAllowCck:1; //CCK TXOP allowance.0:disallow. - UINT32 ProtectNav:2; //TXOP protection type for CCK TX. 0:None, 1:ShortNAVprotect, 2:LongNAVProtect, 3:rsv - UINT32 ProtectCtrl:2; //Protection control frame type for CCK TX. 1:RTS/CTS, 2:CTS-to-self, 0:None, 3:rsv - UINT32 ProtectRate:16; //Protection control frame rate for CCK TX(RTS/CTS/CFEnd). - } field; - UINT32 word; -} PROT_CFG_STRUC, *PPROT_CFG_STRUC; -#else -typedef union _PROT_CFG_STRUC { - struct { - UINT32 ProtectRate:16; //Protection control frame rate for CCK TX(RTS/CTS/CFEnd). - UINT32 ProtectCtrl:2; //Protection control frame type for CCK TX. 1:RTS/CTS, 2:CTS-to-self, 0:None, 3:rsv - UINT32 ProtectNav:2; //TXOP protection type for CCK TX. 0:None, 1:ShortNAVprotect, 2:LongNAVProtect, 3:rsv - UINT32 TxopAllowCck:1; //CCK TXOP allowance.0:disallow. - UINT32 TxopAllowOfdm:1; //CCK TXOP allowance.0:disallow. - UINT32 TxopAllowMM20:1; //CCK TXOP allowance. 0:disallow. - UINT32 TxopAllowMM40:1; //CCK TXOP allowance.0:disallow. - UINT32 TxopAllowGF20:1; //CCK TXOP allowance.0:disallow. - UINT32 TxopAllowGF40:1; //CCK TXOP allowance.0:disallow. - UINT32 RTSThEn:1; //RTS threshold enable on CCK TX - UINT32 rsv:5; - } field; - UINT32 word; -} PROT_CFG_STRUC, *PPROT_CFG_STRUC; -#endif - -#define OFDM_PROT_CFG 0x1368 //OFDM Protection -#define MM20_PROT_CFG 0x136C //MM20 Protection -#define MM40_PROT_CFG 0x1370 //MM40 Protection -#define GF20_PROT_CFG 0x1374 //GF20 Protection -#define GF40_PROT_CFG 0x1378 //GR40 Protection -#define EXP_CTS_TIME 0x137C // -#define EXP_ACK_TIME 0x1380 // - -// -// 4.4 MAC RX configuration registers (offset:0x1400) -// -#define RX_FILTR_CFG 0x1400 //TXRX_CSR0 -#define AUTO_RSP_CFG 0x1404 //TXRX_CSR4 -// -// TXRX_CSR4: Auto-Responder/ -// -#ifdef RT_BIG_ENDIAN -typedef union _AUTO_RSP_CFG_STRUC { - struct { - UINT32 :24; - UINT32 AckCtsPsmBit:1; // Power bit value in conrtrol frame - UINT32 DualCTSEn:1; // Power bit value in conrtrol frame - UINT32 rsv:1; // Power bit value in conrtrol frame - UINT32 AutoResponderPreamble:1; // 0:long, 1:short preamble - UINT32 CTS40MRef:1; // Response CTS 40MHz duplicate mode - UINT32 CTS40MMode:1; // Response CTS 40MHz duplicate mode - UINT32 BACAckPolicyEnable:1; // 0:long, 1:short preamble - UINT32 AutoResponderEnable:1; - } field; - UINT32 word; -} AUTO_RSP_CFG_STRUC, *PAUTO_RSP_CFG_STRUC; -#else -typedef union _AUTO_RSP_CFG_STRUC { - struct { - UINT32 AutoResponderEnable:1; - UINT32 BACAckPolicyEnable:1; // 0:long, 1:short preamble - UINT32 CTS40MMode:1; // Response CTS 40MHz duplicate mode - UINT32 CTS40MRef:1; // Response CTS 40MHz duplicate mode - UINT32 AutoResponderPreamble:1; // 0:long, 1:short preamble - UINT32 rsv:1; // Power bit value in conrtrol frame - UINT32 DualCTSEn:1; // Power bit value in conrtrol frame - UINT32 AckCtsPsmBit:1; // Power bit value in conrtrol frame - UINT32 :24; - } field; - UINT32 word; -} AUTO_RSP_CFG_STRUC, *PAUTO_RSP_CFG_STRUC; -#endif - -#define LEGACY_BASIC_RATE 0x1408 // TXRX_CSR5 0x3054 -#define HT_BASIC_RATE 0x140c -#define HT_CTRL_CFG 0x1410 -#define SIFS_COST_CFG 0x1414 -#define RX_PARSER_CFG 0x1418 //Set NAV for all received frames - -// -// 4.5 MAC Security configuration (offset:0x1500) -// -#define TX_SEC_CNT0 0x1500 // -#define RX_SEC_CNT0 0x1504 // -#define CCMP_FC_MUTE 0x1508 // -// -// 4.6 HCCA/PSMP (offset:0x1600) -// -#define TXOP_HLDR_ADDR0 0x1600 -#define TXOP_HLDR_ADDR1 0x1604 -#define TXOP_HLDR_ET 0x1608 -#define QOS_CFPOLL_RA_DW0 0x160c -#define QOS_CFPOLL_A1_DW1 0x1610 -#define QOS_CFPOLL_QC 0x1614 -// -// 4.7 MAC Statistis registers (offset:0x1700) -// -#define RX_STA_CNT0 0x1700 // -#define RX_STA_CNT1 0x1704 // -#define RX_STA_CNT2 0x1708 // - -// -// RX_STA_CNT0_STRUC: RX PLCP error count & RX CRC error count -// -#ifdef RT_BIG_ENDIAN -typedef union _RX_STA_CNT0_STRUC { - struct { - USHORT PhyErr; - USHORT CrcErr; - } field; - UINT32 word; -} RX_STA_CNT0_STRUC, *PRX_STA_CNT0_STRUC; -#else -typedef union _RX_STA_CNT0_STRUC { - struct { - USHORT CrcErr; - USHORT PhyErr; - } field; - UINT32 word; -} RX_STA_CNT0_STRUC, *PRX_STA_CNT0_STRUC; -#endif - -// -// RX_STA_CNT1_STRUC: RX False CCA count & RX LONG frame count -// -#ifdef RT_BIG_ENDIAN -typedef union _RX_STA_CNT1_STRUC { - struct { - USHORT PlcpErr; - USHORT FalseCca; - } field; - UINT32 word; -} RX_STA_CNT1_STRUC, *PRX_STA_CNT1_STRUC; -#else -typedef union _RX_STA_CNT1_STRUC { - struct { - USHORT FalseCca; - USHORT PlcpErr; - } field; - UINT32 word; -} RX_STA_CNT1_STRUC, *PRX_STA_CNT1_STRUC; -#endif - -// -// RX_STA_CNT2_STRUC: -// -#ifdef RT_BIG_ENDIAN -typedef union _RX_STA_CNT2_STRUC { - struct { - USHORT RxFifoOverflowCount; - USHORT RxDupliCount; - } field; - UINT32 word; -} RX_STA_CNT2_STRUC, *PRX_STA_CNT2_STRUC; -#else -typedef union _RX_STA_CNT2_STRUC { - struct { - USHORT RxDupliCount; - USHORT RxFifoOverflowCount; - } field; - UINT32 word; -} RX_STA_CNT2_STRUC, *PRX_STA_CNT2_STRUC; -#endif -#define TX_STA_CNT0 0x170C // -// -// STA_CSR3: TX Beacon count -// -#ifdef RT_BIG_ENDIAN -typedef union _TX_STA_CNT0_STRUC { - struct { - USHORT TxBeaconCount; - USHORT TxFailCount; - } field; - UINT32 word; -} TX_STA_CNT0_STRUC, *PTX_STA_CNT0_STRUC; -#else -typedef union _TX_STA_CNT0_STRUC { - struct { - USHORT TxFailCount; - USHORT TxBeaconCount; - } field; - UINT32 word; -} TX_STA_CNT0_STRUC, *PTX_STA_CNT0_STRUC; -#endif -#define TX_STA_CNT1 0x1710 // -// -// TX_STA_CNT1: TX tx count -// -#ifdef RT_BIG_ENDIAN -typedef union _TX_STA_CNT1_STRUC { - struct { - USHORT TxRetransmit; - USHORT TxSuccess; - } field; - UINT32 word; -} TX_STA_CNT1_STRUC, *PTX_STA_CNT1_STRUC; -#else -typedef union _TX_STA_CNT1_STRUC { - struct { - USHORT TxSuccess; - USHORT TxRetransmit; - } field; - UINT32 word; -} TX_STA_CNT1_STRUC, *PTX_STA_CNT1_STRUC; -#endif -#define TX_STA_CNT2 0x1714 // -// -// TX_STA_CNT2: TX tx count -// -#ifdef RT_BIG_ENDIAN -typedef union _TX_STA_CNT2_STRUC { - struct { - USHORT TxUnderFlowCount; - USHORT TxZeroLenCount; - } field; - UINT32 word; -} TX_STA_CNT2_STRUC, *PTX_STA_CNT2_STRUC; -#else -typedef union _TX_STA_CNT2_STRUC { - struct { - USHORT TxZeroLenCount; - USHORT TxUnderFlowCount; - } field; - UINT32 word; -} TX_STA_CNT2_STRUC, *PTX_STA_CNT2_STRUC; -#endif -#define TX_STA_FIFO 0x1718 // -// -// TX_STA_FIFO_STRUC: TX Result for specific PID status fifo register -// -#ifdef RT_BIG_ENDIAN -typedef union PACKED _TX_STA_FIFO_STRUC { - struct { - UINT32 Reserve:2; - UINT32 TxBF:1; // 3*3 - UINT32 SuccessRate:13; //include MCS, mode ,shortGI, BW settingSame format as TXWI Word 0 Bit 31-16. -// UINT32 SuccessRate:16; //include MCS, mode ,shortGI, BW settingSame format as TXWI Word 0 Bit 31-16. - UINT32 wcid:8; //wireless client index - UINT32 TxAckRequired:1; // ack required - UINT32 TxAggre:1; // Tx is aggregated - UINT32 TxSuccess:1; // Tx success. whether success or not - UINT32 PidType:4; - UINT32 bValid:1; // 1:This register contains a valid TX result - } field; - UINT32 word; -} TX_STA_FIFO_STRUC, *PTX_STA_FIFO_STRUC; -#else -typedef union PACKED _TX_STA_FIFO_STRUC { - struct { - UINT32 bValid:1; // 1:This register contains a valid TX result - UINT32 PidType:4; - UINT32 TxSuccess:1; // Tx No retry success - UINT32 TxAggre:1; // Tx Retry Success - UINT32 TxAckRequired:1; // Tx fail - UINT32 wcid:8; //wireless client index -// UINT32 SuccessRate:16; //include MCS, mode ,shortGI, BW settingSame format as TXWI Word 0 Bit 31-16. - UINT32 SuccessRate:13; //include MCS, mode ,shortGI, BW settingSame format as TXWI Word 0 Bit 31-16. - UINT32 TxBF:1; - UINT32 Reserve:2; - } field; - UINT32 word; -} TX_STA_FIFO_STRUC, *PTX_STA_FIFO_STRUC; -#endif -// Debug counter -#define TX_AGG_CNT 0x171c -#ifdef RT_BIG_ENDIAN -typedef union _TX_AGG_CNT_STRUC { - struct { - USHORT AggTxCount; - USHORT NonAggTxCount; - } field; - UINT32 word; -} TX_AGG_CNT_STRUC, *PTX_AGG_CNT_STRUC; -#else -typedef union _TX_AGG_CNT_STRUC { - struct { - USHORT NonAggTxCount; - USHORT AggTxCount; - } field; - UINT32 word; -} TX_AGG_CNT_STRUC, *PTX_AGG_CNT_STRUC; -#endif -// Debug counter -#define TX_AGG_CNT0 0x1720 -#ifdef RT_BIG_ENDIAN -typedef union _TX_AGG_CNT0_STRUC { - struct { - USHORT AggSize2Count; - USHORT AggSize1Count; - } field; - UINT32 word; -} TX_AGG_CNT0_STRUC, *PTX_AGG_CNT0_STRUC; -#else -typedef union _TX_AGG_CNT0_STRUC { - struct { - USHORT AggSize1Count; - USHORT AggSize2Count; - } field; - UINT32 word; -} TX_AGG_CNT0_STRUC, *PTX_AGG_CNT0_STRUC; -#endif -// Debug counter -#define TX_AGG_CNT1 0x1724 -#ifdef RT_BIG_ENDIAN -typedef union _TX_AGG_CNT1_STRUC { - struct { - USHORT AggSize4Count; - USHORT AggSize3Count; - } field; - UINT32 word; -} TX_AGG_CNT1_STRUC, *PTX_AGG_CNT1_STRUC; -#else -typedef union _TX_AGG_CNT1_STRUC { - struct { - USHORT AggSize3Count; - USHORT AggSize4Count; - } field; - UINT32 word; -} TX_AGG_CNT1_STRUC, *PTX_AGG_CNT1_STRUC; -#endif -#define TX_AGG_CNT2 0x1728 -#ifdef RT_BIG_ENDIAN -typedef union _TX_AGG_CNT2_STRUC { - struct { - USHORT AggSize6Count; - USHORT AggSize5Count; - } field; - UINT32 word; -} TX_AGG_CNT2_STRUC, *PTX_AGG_CNT2_STRUC; -#else -typedef union _TX_AGG_CNT2_STRUC { - struct { - USHORT AggSize5Count; - USHORT AggSize6Count; - } field; - UINT32 word; -} TX_AGG_CNT2_STRUC, *PTX_AGG_CNT2_STRUC; -#endif -// Debug counter -#define TX_AGG_CNT3 0x172c -#ifdef RT_BIG_ENDIAN -typedef union _TX_AGG_CNT3_STRUC { - struct { - USHORT AggSize8Count; - USHORT AggSize7Count; - } field; - UINT32 word; -} TX_AGG_CNT3_STRUC, *PTX_AGG_CNT3_STRUC; -#else -typedef union _TX_AGG_CNT3_STRUC { - struct { - USHORT AggSize7Count; - USHORT AggSize8Count; - } field; - UINT32 word; -} TX_AGG_CNT3_STRUC, *PTX_AGG_CNT3_STRUC; -#endif -// Debug counter -#define TX_AGG_CNT4 0x1730 -#ifdef RT_BIG_ENDIAN -typedef union _TX_AGG_CNT4_STRUC { - struct { - USHORT AggSize10Count; - USHORT AggSize9Count; - } field; - UINT32 word; -} TX_AGG_CNT4_STRUC, *PTX_AGG_CNT4_STRUC; -#else -typedef union _TX_AGG_CNT4_STRUC { - struct { - USHORT AggSize9Count; - USHORT AggSize10Count; - } field; - UINT32 word; -} TX_AGG_CNT4_STRUC, *PTX_AGG_CNT4_STRUC; -#endif -#define TX_AGG_CNT5 0x1734 -#ifdef RT_BIG_ENDIAN -typedef union _TX_AGG_CNT5_STRUC { - struct { - USHORT AggSize12Count; - USHORT AggSize11Count; - } field; - UINT32 word; -} TX_AGG_CNT5_STRUC, *PTX_AGG_CNT5_STRUC; -#else -typedef union _TX_AGG_CNT5_STRUC { - struct { - USHORT AggSize11Count; - USHORT AggSize12Count; - } field; - UINT32 word; -} TX_AGG_CNT5_STRUC, *PTX_AGG_CNT5_STRUC; -#endif -#define TX_AGG_CNT6 0x1738 -#ifdef RT_BIG_ENDIAN -typedef union _TX_AGG_CNT6_STRUC { - struct { - USHORT AggSize14Count; - USHORT AggSize13Count; - } field; - UINT32 word; -} TX_AGG_CNT6_STRUC, *PTX_AGG_CNT6_STRUC; -#else -typedef union _TX_AGG_CNT6_STRUC { - struct { - USHORT AggSize13Count; - USHORT AggSize14Count; - } field; - UINT32 word; -} TX_AGG_CNT6_STRUC, *PTX_AGG_CNT6_STRUC; -#endif -#define TX_AGG_CNT7 0x173c -#ifdef RT_BIG_ENDIAN -typedef union _TX_AGG_CNT7_STRUC { - struct { - USHORT AggSize16Count; - USHORT AggSize15Count; - } field; - UINT32 word; -} TX_AGG_CNT7_STRUC, *PTX_AGG_CNT7_STRUC; -#else -typedef union _TX_AGG_CNT7_STRUC { - struct { - USHORT AggSize15Count; - USHORT AggSize16Count; - } field; - UINT32 word; -} TX_AGG_CNT7_STRUC, *PTX_AGG_CNT7_STRUC; -#endif -#define MPDU_DENSITY_CNT 0x1740 -#ifdef RT_BIG_ENDIAN -typedef union _MPDU_DEN_CNT_STRUC { - struct { - USHORT RXZeroDelCount; //RX zero length delimiter count - USHORT TXZeroDelCount; //TX zero length delimiter count - } field; - UINT32 word; -} MPDU_DEN_CNT_STRUC, *PMPDU_DEN_CNT_STRUC; -#else -typedef union _MPDU_DEN_CNT_STRUC { - struct { - USHORT TXZeroDelCount; //TX zero length delimiter count - USHORT RXZeroDelCount; //RX zero length delimiter count - } field; - UINT32 word; -} MPDU_DEN_CNT_STRUC, *PMPDU_DEN_CNT_STRUC; -#endif -// -// TXRX control registers - base address 0x3000 -// -// rt2860b UNKNOWN reg use R/O Reg Addr 0x77d0 first.. -#define TXRX_CSR1 0x77d0 - -// -// Security key table memory, base address = 0x1000 -// -#define MAC_WCID_BASE 0x1800 //8-bytes(use only 6-bytes) * 256 entry = -#define HW_WCID_ENTRY_SIZE 8 -#define PAIRWISE_KEY_TABLE_BASE 0x4000 // 32-byte * 256-entry = -byte -#define HW_KEY_ENTRY_SIZE 0x20 -#define PAIRWISE_IVEIV_TABLE_BASE 0x6000 // 8-byte * 256-entry = -byte -#define MAC_IVEIV_TABLE_BASE 0x6000 // 8-byte * 256-entry = -byte -#define HW_IVEIV_ENTRY_SIZE 8 -#define MAC_WCID_ATTRIBUTE_BASE 0x6800 // 4-byte * 256-entry = -byte -#define HW_WCID_ATTRI_SIZE 4 -#define WCID_RESERVED 0x6bfc -#define SHARED_KEY_TABLE_BASE 0x6c00 // 32-byte * 16-entry = 512-byte -#define SHARED_KEY_MODE_BASE 0x7000 // 32-byte * 16-entry = 512-byte -#define HW_SHARED_KEY_MODE_SIZE 4 -#define SHAREDKEYTABLE 0 -#define PAIRWISEKEYTABLE 1 - - -#ifdef RT_BIG_ENDIAN -typedef union _SHAREDKEY_MODE_STRUC { - struct { - UINT32 :1; - UINT32 Bss1Key3CipherAlg:3; - UINT32 :1; - UINT32 Bss1Key2CipherAlg:3; - UINT32 :1; - UINT32 Bss1Key1CipherAlg:3; - UINT32 :1; - UINT32 Bss1Key0CipherAlg:3; - UINT32 :1; - UINT32 Bss0Key3CipherAlg:3; - UINT32 :1; - UINT32 Bss0Key2CipherAlg:3; - UINT32 :1; - UINT32 Bss0Key1CipherAlg:3; - UINT32 :1; - UINT32 Bss0Key0CipherAlg:3; - } field; - UINT32 word; -} SHAREDKEY_MODE_STRUC, *PSHAREDKEY_MODE_STRUC; -#else -typedef union _SHAREDKEY_MODE_STRUC { - struct { - UINT32 Bss0Key0CipherAlg:3; - UINT32 :1; - UINT32 Bss0Key1CipherAlg:3; - UINT32 :1; - UINT32 Bss0Key2CipherAlg:3; - UINT32 :1; - UINT32 Bss0Key3CipherAlg:3; - UINT32 :1; - UINT32 Bss1Key0CipherAlg:3; - UINT32 :1; - UINT32 Bss1Key1CipherAlg:3; - UINT32 :1; - UINT32 Bss1Key2CipherAlg:3; - UINT32 :1; - UINT32 Bss1Key3CipherAlg:3; - UINT32 :1; - } field; - UINT32 word; -} SHAREDKEY_MODE_STRUC, *PSHAREDKEY_MODE_STRUC; -#endif -// 64-entry for pairwise key table -typedef struct _HW_WCID_ENTRY { // 8-byte per entry - UCHAR Address[6]; - UCHAR Rsv[2]; -} HW_WCID_ENTRY, PHW_WCID_ENTRY; - - - -// -// Other on-chip shared memory space, base = 0x2000 -// - -// CIS space - base address = 0x2000 -#define HW_CIS_BASE 0x2000 - -// Carrier-sense CTS frame base address. It's where mac stores carrier-sense frame for carrier-sense function. -#define HW_CS_CTS_BASE 0x7700 -// DFS CTS frame base address. It's where mac stores CTS frame for DFS. -#define HW_DFS_CTS_BASE 0x7780 -#define HW_CTS_FRAME_SIZE 0x80 - -// 2004-11-08 john - since NULL frame won't be that long (256 byte). We steal 16 tail bytes -// to save debugging settings -#define HW_DEBUG_SETTING_BASE 0x77f0 // 0x77f0~0x77ff total 16 bytes -#define HW_DEBUG_SETTING_BASE2 0x7770 // 0x77f0~0x77ff total 16 bytes - -// In order to support maximum 8 MBSS and its maximum length is 512 for each beacon -// Three section discontinue memory segments will be used. -// 1. The original region for BCN 0~3 -// 2. Extract memory from FCE table for BCN 4~5 -// 3. Extract memory from Pair-wise key table for BCN 6~7 -// It occupied those memory of wcid 238~253 for BCN 6 -// and wcid 222~237 for BCN 7 -#define HW_BEACON_MAX_SIZE 0x1000 /* unit: byte */ -#define HW_BEACON_BASE0 0x7800 -#define HW_BEACON_BASE1 0x7A00 -#define HW_BEACON_BASE2 0x7C00 -#define HW_BEACON_BASE3 0x7E00 -#define HW_BEACON_BASE4 0x7200 -#define HW_BEACON_BASE5 0x7400 -#define HW_BEACON_BASE6 0x5DC0 -#define HW_BEACON_BASE7 0x5BC0 - -#define HW_BEACON_MAX_COUNT 8 -#define HW_BEACON_OFFSET 0x0200 -#define HW_BEACON_CONTENT_LEN (HW_BEACON_OFFSET - TXWI_SIZE) - -// HOST-MCU shared memory - base address = 0x2100 -#define HOST_CMD_CSR 0x404 -#define H2M_MAILBOX_CSR 0x7010 -#define H2M_MAILBOX_CID 0x7014 -#define H2M_MAILBOX_STATUS 0x701c -#define H2M_INT_SRC 0x7024 -#define H2M_BBP_AGENT 0x7028 -#define M2H_CMD_DONE_CSR 0x000c -#define MCU_TXOP_ARRAY_BASE 0x000c // TODO: to be provided by Albert -#define MCU_TXOP_ENTRY_SIZE 32 // TODO: to be provided by Albert -#define MAX_NUM_OF_TXOP_ENTRY 16 // TODO: must be same with 8051 firmware -#define MCU_MBOX_VERSION 0x01 // TODO: to be confirmed by Albert -#define MCU_MBOX_VERSION_OFFSET 5 // TODO: to be provided by Albert - -// -// Host DMA registers - base address 0x200 . TX0-3=EDCAQid0-3, TX4=HCCA, TX5=MGMT, -// -// -// DMA RING DESCRIPTOR -// -#define E2PROM_CSR 0x0004 -#define IO_CNTL_CSR 0x77d0 - -#ifdef RT2870 -// 8051 firmware image for usb - use last-half base address = 0x3000 -#define FIRMWARE_IMAGE_BASE 0x3000 -#define MAX_FIRMWARE_IMAGE_SIZE 0x1000 // 4kbyte -#endif // RT2870 // - -// TODO: ????? old RT2560 registers. to keep them or remove them? -//#define MCAST0 0x0178 // multicast filter register 0 -//#define MCAST1 0x017c // multicast filter register 1 - - -// ================================================================ -// Tx / Rx / Mgmt ring descriptor definition -// ================================================================ - -// the following PID values are used to mark outgoing frame type in TXD->PID so that -// proper TX statistics can be collected based on these categories -// b3-2 of PID field - -#define PID_MGMT 0x05 -#define PID_BEACON 0x0c -#define PID_DATA_NORMALUCAST 0x02 -#define PID_DATA_AMPDU 0x04 -#define PID_DATA_NO_ACK 0x08 -#define PID_DATA_NOT_NORM_ACK 0x03 -// value domain of pTxD->HostQId (4-bit: 0~15) -#define QID_AC_BK 1 // meet ACI definition in 802.11e -#define QID_AC_BE 0 // meet ACI definition in 802.11e -#define QID_AC_VI 2 -#define QID_AC_VO 3 -#define QID_HCCA 4 -#define NUM_OF_TX_RING 5 -#define QID_MGMT 13 -#define QID_RX 14 -#define QID_OTHER 15 - - -// ------------------------------------------------------ -// BBP & RF definition -// ------------------------------------------------------ -#define BUSY 1 -#define IDLE 0 - -#define RF_R00 0 -#define RF_R01 1 -#define RF_R02 2 -#define RF_R03 3 -#define RF_R04 4 -#define RF_R05 5 -#define RF_R06 6 -#define RF_R07 7 -#define RF_R08 8 -#define RF_R09 9 -#define RF_R10 10 -#define RF_R11 11 -#define RF_R12 12 -#define RF_R13 13 -#define RF_R14 14 -#define RF_R15 15 -#define RF_R16 16 -#define RF_R17 17 -#define RF_R18 18 -#define RF_R19 19 -#define RF_R20 20 -#define RF_R21 21 -#define RF_R22 22 -#define RF_R23 23 -#define RF_R24 24 -#define RF_R25 25 -#define RF_R26 26 -#define RF_R27 27 -#define RF_R28 28 -#define RF_R29 29 -#define RF_R30 30 -#define RF_R31 31 - -#define BBP_R0 0 // version -#define BBP_R1 1 // TSSI -#define BBP_R2 2 // TX configure -#define BBP_R3 3 -#define BBP_R4 4 -#define BBP_R5 5 -#define BBP_R6 6 -#define BBP_R14 14 // RX configure -#define BBP_R16 16 -#define BBP_R17 17 // RX sensibility -#define BBP_R18 18 -#define BBP_R21 21 -#define BBP_R22 22 -#define BBP_R24 24 -#define BBP_R25 25 -#define BBP_R31 31 -#define BBP_R49 49 //TSSI -#define BBP_R50 50 -#define BBP_R51 51 -#define BBP_R52 52 -#define BBP_R55 55 -#define BBP_R62 62 // Rx SQ0 Threshold HIGH -#define BBP_R63 63 -#define BBP_R64 64 -#define BBP_R65 65 -#define BBP_R66 66 -#define BBP_R67 67 -#define BBP_R68 68 -#define BBP_R69 69 -#define BBP_R70 70 // Rx AGC SQ CCK Xcorr threshold -#define BBP_R73 73 -#define BBP_R75 75 -#define BBP_R77 77 -#define BBP_R79 79 -#define BBP_R80 80 -#define BBP_R81 81 -#define BBP_R82 82 -#define BBP_R83 83 -#define BBP_R84 84 -#define BBP_R86 86 -#define BBP_R91 91 -#define BBP_R92 92 -#define BBP_R94 94 // Tx Gain Control -#define BBP_R103 103 -#define BBP_R105 105 -#define BBP_R113 113 -#define BBP_R114 114 -#define BBP_R115 115 -#define BBP_R116 116 -#define BBP_R117 117 -#define BBP_R118 118 -#define BBP_R119 119 -#define BBP_R120 120 -#define BBP_R121 121 -#define BBP_R122 122 -#define BBP_R123 123 -#ifdef RT30xx -#define BBP_R138 138 // add by johnli, RF power sequence setup, ADC dynamic on/off control -#endif // RT30xx // - - -#define BBPR94_DEFAULT 0x06 // Add 1 value will gain 1db - -//#define PHY_TR_SWITCH_TIME 5 // usec - -//#define BBP_R17_LOW_SENSIBILITY 0x50 -//#define BBP_R17_MID_SENSIBILITY 0x41 -//#define BBP_R17_DYNAMIC_UP_BOUND 0x40 -#define RSSI_FOR_VERY_LOW_SENSIBILITY -35 -#define RSSI_FOR_LOW_SENSIBILITY -58 -#define RSSI_FOR_MID_LOW_SENSIBILITY -80 -#define RSSI_FOR_MID_SENSIBILITY -90 - -//------------------------------------------------------------------------- -// EEPROM definition -//------------------------------------------------------------------------- -#define EEDO 0x08 -#define EEDI 0x04 -#define EECS 0x02 -#define EESK 0x01 -#define EERL 0x80 - -#define EEPROM_WRITE_OPCODE 0x05 -#define EEPROM_READ_OPCODE 0x06 -#define EEPROM_EWDS_OPCODE 0x10 -#define EEPROM_EWEN_OPCODE 0x13 - -#define NUM_EEPROM_BBP_PARMS 19 // Include NIC Config 0, 1, CR, TX ALC step, BBPs -#define NUM_EEPROM_TX_G_PARMS 7 -#define EEPROM_NIC1_OFFSET 0x34 // The address is from NIC config 0, not BBP register ID -#define EEPROM_NIC2_OFFSET 0x36 // The address is from NIC config 0, not BBP register ID -#define EEPROM_BBP_BASE_OFFSET 0xf0 // The address is from NIC config 0, not BBP register ID -#define EEPROM_G_TX_PWR_OFFSET 0x52 -#define EEPROM_G_TX2_PWR_OFFSET 0x60 -#define EEPROM_LED1_OFFSET 0x3c -#define EEPROM_LED2_OFFSET 0x3e -#define EEPROM_LED3_OFFSET 0x40 -#define EEPROM_LNA_OFFSET 0x44 -#define EEPROM_RSSI_BG_OFFSET 0x46 -#define EEPROM_RSSI_A_OFFSET 0x4a -#define EEPROM_DEFINE_MAX_TXPWR 0x4e -#define EEPROM_TXPOWER_BYRATE_20MHZ_2_4G 0xde // 20MHZ 2.4G tx power. -#define EEPROM_TXPOWER_BYRATE_40MHZ_2_4G 0xee // 40MHZ 2.4G tx power. -#define EEPROM_TXPOWER_BYRATE_20MHZ_5G 0xfa // 20MHZ 5G tx power. -#define EEPROM_TXPOWER_BYRATE_40MHZ_5G 0x10a // 40MHZ 5G tx power. -#define EEPROM_A_TX_PWR_OFFSET 0x78 -#define EEPROM_A_TX2_PWR_OFFSET 0xa6 -//#define EEPROM_Japan_TX_PWR_OFFSET 0x90 // 802.11j -//#define EEPROM_Japan_TX2_PWR_OFFSET 0xbe -//#define EEPROM_TSSI_REF_OFFSET 0x54 -//#define EEPROM_TSSI_DELTA_OFFSET 0x24 -//#define EEPROM_CCK_TX_PWR_OFFSET 0x62 -//#define EEPROM_CALIBRATE_OFFSET 0x7c -#define EEPROM_VERSION_OFFSET 0x02 -#define EEPROM_FREQ_OFFSET 0x3a -#define EEPROM_TXPOWER_BYRATE 0xde // 20MHZ power. -#define EEPROM_TXPOWER_DELTA 0x50 // 20MHZ AND 40 MHZ use different power. This is delta in 40MHZ. -#define VALID_EEPROM_VERSION 1 - -// PairKeyMode definition -#define PKMODE_NONE 0 -#define PKMODE_WEP64 1 -#define PKMODE_WEP128 2 -#define PKMODE_TKIP 3 -#define PKMODE_AES 4 -#define PKMODE_CKIP64 5 -#define PKMODE_CKIP128 6 -#define PKMODE_TKIP_NO_MIC 7 // MIC appended by driver: not a valid value in hardware key table - -// ================================================================================= -// WCID format -// ================================================================================= -//7.1 WCID ENTRY format : 8bytes -typedef struct _WCID_ENTRY_STRUC { - UCHAR RXBABitmap7; // bit0 for TID8, bit7 for TID 15 - UCHAR RXBABitmap0; // bit0 for TID0, bit7 for TID 7 - UCHAR MAC[6]; // 0 for shared key table. 1 for pairwise key table -} WCID_ENTRY_STRUC, *PWCID_ENTRY_STRUC; - -//8.1.1 SECURITY KEY format : 8DW -// 32-byte per entry, total 16-entry for shared key table, 64-entry for pairwise key table -typedef struct _HW_KEY_ENTRY { // 32-byte per entry - UCHAR Key[16]; - UCHAR TxMic[8]; - UCHAR RxMic[8]; -} HW_KEY_ENTRY, *PHW_KEY_ENTRY; - -//8.1.2 IV/EIV format : 2DW - -//8.1.3 RX attribute entry format : 1DW -#ifdef RT_BIG_ENDIAN -typedef struct _MAC_ATTRIBUTE_STRUC { - UINT32 rsv:22; - UINT32 RXWIUDF:3; - UINT32 BSSIDIdx:3; //multipleBSS index for the WCID - UINT32 PairKeyMode:3; - UINT32 KeyTab:1; // 0 for shared key table. 1 for pairwise key table -} MAC_ATTRIBUTE_STRUC, *PMAC_ATTRIBUTE_STRUC; -#else -typedef struct _MAC_ATTRIBUTE_STRUC { - UINT32 KeyTab:1; // 0 for shared key table. 1 for pairwise key table - UINT32 PairKeyMode:3; - UINT32 BSSIDIdx:3; //multipleBSS index for the WCID - UINT32 RXWIUDF:3; - UINT32 rsv:22; -} MAC_ATTRIBUTE_STRUC, *PMAC_ATTRIBUTE_STRUC; -#endif - - -// ================================================================================= -// TX / RX ring descriptor format -// ================================================================================= - -// the first 24-byte in TXD is called TXINFO and will be DMAed to MAC block through TXFIFO. -// MAC block use this TXINFO to control the transmission behavior of this frame. -#define FIFO_MGMT 0 -#define FIFO_HCCA 1 -#define FIFO_EDCA 2 - -// -// TX descriptor format, Tx ring, Mgmt Ring -// -#ifdef RT_BIG_ENDIAN -typedef struct PACKED _TXD_STRUC { - // Word 0 - UINT32 SDPtr0; - // Word 1 - UINT32 DMADONE:1; - UINT32 LastSec0:1; - UINT32 SDLen0:14; - UINT32 Burst:1; - UINT32 LastSec1:1; - UINT32 SDLen1:14; - // Word 2 - UINT32 SDPtr1; - // Word 3 - UINT32 ICO:1; - UINT32 UCO:1; - UINT32 TCO:1; - UINT32 rsv:2; - UINT32 QSEL:2; // select on-chip FIFO ID for 2nd-stage output scheduler.0:MGMT, 1:HCCA 2:EDCA - UINT32 WIV:1; // Wireless Info Valid. 1 if Driver already fill WI, o if DMA needs to copy WI to correctposition - UINT32 rsv2:24; -} TXD_STRUC, *PTXD_STRUC; -#else -typedef struct PACKED _TXD_STRUC { - // Word 0 - UINT32 SDPtr0; - // Word 1 - UINT32 SDLen1:14; - UINT32 LastSec1:1; - UINT32 Burst:1; - UINT32 SDLen0:14; - UINT32 LastSec0:1; - UINT32 DMADONE:1; - //Word2 - UINT32 SDPtr1; - //Word3 - UINT32 rsv2:24; - UINT32 WIV:1; // Wireless Info Valid. 1 if Driver already fill WI, o if DMA needs to copy WI to correctposition - UINT32 QSEL:2; // select on-chip FIFO ID for 2nd-stage output scheduler.0:MGMT, 1:HCCA 2:EDCA - UINT32 rsv:2; - UINT32 TCO:1; // - UINT32 UCO:1; // - UINT32 ICO:1; // -} TXD_STRUC, *PTXD_STRUC; -#endif - - -// -// TXD Wireless Information format for Tx ring and Mgmt Ring -// -//txop : for txop mode -// 0:txop for the MPDU frame will be handles by ASIC by register -// 1/2/3:the MPDU frame is send after PIFS/backoff/SIFS -#ifdef RT_BIG_ENDIAN -typedef struct PACKED _TXWI_STRUC { - // Word 0 - UINT32 PHYMODE:2; - UINT32 TxBF:1; // 3*3 - UINT32 rsv2:1; -// UINT32 rsv2:2; - UINT32 Ifs:1; // - UINT32 STBC:2; //channel bandwidth 20MHz or 40 MHz - UINT32 ShortGI:1; - UINT32 BW:1; //channel bandwidth 20MHz or 40 MHz - UINT32 MCS:7; - - UINT32 rsv:6; - UINT32 txop:2; //tx back off mode 0:HT TXOP rule , 1:PIFS TX ,2:Backoff, 3:sifs only when previous frame exchange is successful. - UINT32 MpduDensity:3; - UINT32 AMPDU:1; - - UINT32 TS:1; - UINT32 CFACK:1; - UINT32 MIMOps:1; // the remote peer is in dynamic MIMO-PS mode - UINT32 FRAG:1; // 1 to inform TKIP engine this is a fragment. - // Word 1 - UINT32 PacketId:4; - UINT32 MPDUtotalByteCount:12; - UINT32 WirelessCliID:8; - UINT32 BAWinSize:6; - UINT32 NSEQ:1; - UINT32 ACK:1; - // Word 2 - UINT32 IV; - // Word 3 - UINT32 EIV; -} TXWI_STRUC, *PTXWI_STRUC; -#else -typedef struct PACKED _TXWI_STRUC { - // Word 0 - UINT32 FRAG:1; // 1 to inform TKIP engine this is a fragment. - UINT32 MIMOps:1; // the remote peer is in dynamic MIMO-PS mode - UINT32 CFACK:1; - UINT32 TS:1; - - UINT32 AMPDU:1; - UINT32 MpduDensity:3; - UINT32 txop:2; //FOR "THIS" frame. 0:HT TXOP rule , 1:PIFS TX ,2:Backoff, 3:sifs only when previous frame exchange is successful. - UINT32 rsv:6; - - UINT32 MCS:7; - UINT32 BW:1; //channel bandwidth 20MHz or 40 MHz - UINT32 ShortGI:1; - UINT32 STBC:2; // 1: STBC support MCS =0-7, 2,3 : RESERVE - UINT32 Ifs:1; // -// UINT32 rsv2:2; //channel bandwidth 20MHz or 40 MHz - UINT32 rsv2:1; - UINT32 TxBF:1; // 3*3 - UINT32 PHYMODE:2; - // Word 1 - UINT32 ACK:1; - UINT32 NSEQ:1; - UINT32 BAWinSize:6; - UINT32 WirelessCliID:8; - UINT32 MPDUtotalByteCount:12; - UINT32 PacketId:4; - //Word2 - UINT32 IV; - //Word3 - UINT32 EIV; -} TXWI_STRUC, *PTXWI_STRUC; -#endif -// -// Rx descriptor format, Rx Ring -// -// -// RXWI wireless information format, in PBF. invisible in driver. -// -#ifdef RT_BIG_ENDIAN -typedef struct PACKED _RXWI_STRUC { - // Word 0 - UINT32 TID:4; - UINT32 MPDUtotalByteCount:12; - UINT32 UDF:3; - UINT32 BSSID:3; - UINT32 KeyIndex:2; - UINT32 WirelessCliID:8; - // Word 1 - UINT32 PHYMODE:2; // 1: this RX frame is unicast to me - UINT32 rsv:3; - UINT32 STBC:2; - UINT32 ShortGI:1; - UINT32 BW:1; - UINT32 MCS:7; - UINT32 SEQUENCE:12; - UINT32 FRAG:4; - // Word 2 - UINT32 rsv1:8; - UINT32 RSSI2:8; - UINT32 RSSI1:8; - UINT32 RSSI0:8; - // Word 3 - UINT32 rsv2:16; - UINT32 SNR1:8; - UINT32 SNR0:8; -} RXWI_STRUC, *PRXWI_STRUC; -#else -typedef struct PACKED _RXWI_STRUC { - // Word 0 - UINT32 WirelessCliID:8; - UINT32 KeyIndex:2; - UINT32 BSSID:3; - UINT32 UDF:3; - UINT32 MPDUtotalByteCount:12; - UINT32 TID:4; - // Word 1 - UINT32 FRAG:4; - UINT32 SEQUENCE:12; - UINT32 MCS:7; - UINT32 BW:1; - UINT32 ShortGI:1; - UINT32 STBC:2; - UINT32 rsv:3; - UINT32 PHYMODE:2; // 1: this RX frame is unicast to me - //Word2 - UINT32 RSSI0:8; - UINT32 RSSI1:8; - UINT32 RSSI2:8; - UINT32 rsv1:8; - //Word3 - UINT32 SNR0:8; - UINT32 SNR1:8; - UINT32 rsv2:16; -} RXWI_STRUC, *PRXWI_STRUC; -#endif - - -// ================================================================================= -// HOST-MCU communication data structure -// ================================================================================= - -// -// H2M_MAILBOX_CSR: Host-to-MCU Mailbox -// -#ifdef RT_BIG_ENDIAN -typedef union _H2M_MAILBOX_STRUC { - struct { - UINT32 Owner:8; - UINT32 CmdToken:8; // 0xff tells MCU not to report CmdDoneInt after excuting the command - UINT32 HighByte:8; - UINT32 LowByte:8; - } field; - UINT32 word; -} H2M_MAILBOX_STRUC, *PH2M_MAILBOX_STRUC; -#else -typedef union _H2M_MAILBOX_STRUC { - struct { - UINT32 LowByte:8; - UINT32 HighByte:8; - UINT32 CmdToken:8; - UINT32 Owner:8; - } field; - UINT32 word; -} H2M_MAILBOX_STRUC, *PH2M_MAILBOX_STRUC; -#endif - -// -// M2H_CMD_DONE_CSR: MCU-to-Host command complete indication -// -#ifdef RT_BIG_ENDIAN -typedef union _M2H_CMD_DONE_STRUC { - struct { - UINT32 CmdToken3; - UINT32 CmdToken2; - UINT32 CmdToken1; - UINT32 CmdToken0; - } field; - UINT32 word; -} M2H_CMD_DONE_STRUC, *PM2H_CMD_DONE_STRUC; -#else -typedef union _M2H_CMD_DONE_STRUC { - struct { - UINT32 CmdToken0; - UINT32 CmdToken1; - UINT32 CmdToken2; - UINT32 CmdToken3; - } field; - UINT32 word; -} M2H_CMD_DONE_STRUC, *PM2H_CMD_DONE_STRUC; -#endif - - - -// -// MCU_LEDCS: MCU LED Control Setting. -// -#ifdef RT_BIG_ENDIAN -typedef union _MCU_LEDCS_STRUC { - struct { - UCHAR Polarity:1; - UCHAR LedMode:7; - } field; - UCHAR word; -} MCU_LEDCS_STRUC, *PMCU_LEDCS_STRUC; -#else -typedef union _MCU_LEDCS_STRUC { - struct { - UCHAR LedMode:7; - UCHAR Polarity:1; - } field; - UCHAR word; -} MCU_LEDCS_STRUC, *PMCU_LEDCS_STRUC; -#endif -// ================================================================================= -// Register format -// ================================================================================= - - - -//NAV_TIME_CFG :NAV -#ifdef RT_BIG_ENDIAN -typedef union _NAV_TIME_CFG_STRUC { - struct { - USHORT rsv:6; - USHORT ZeroSifs:1; // Applied zero SIFS timer after OFDM RX 0: disable - USHORT Eifs:9; // in unit of 1-us - UCHAR SlotTime; // in unit of 1-us - UCHAR Sifs; // in unit of 1-us - } field; - UINT32 word; -} NAV_TIME_CFG_STRUC, *PNAV_TIME_CFG_STRUC; -#else -typedef union _NAV_TIME_CFG_STRUC { - struct { - UCHAR Sifs; // in unit of 1-us - UCHAR SlotTime; // in unit of 1-us - USHORT Eifs:9; // in unit of 1-us - USHORT ZeroSifs:1; // Applied zero SIFS timer after OFDM RX 0: disable - USHORT rsv:6; - } field; - UINT32 word; -} NAV_TIME_CFG_STRUC, *PNAV_TIME_CFG_STRUC; -#endif - - - - - -// -// RX_FILTR_CFG: /RX configuration register -// -#ifdef RT_BIG_ENDIAN -typedef union RX_FILTR_CFG_STRUC { - struct { - UINT32 :15; - UINT32 DropRsvCntlType:1; - - UINT32 DropBAR:1; // - UINT32 DropBA:1; // - UINT32 DropPsPoll:1; // Drop Ps-Poll - UINT32 DropRts:1; // Drop Ps-Poll - - UINT32 DropCts:1; // Drop Ps-Poll - UINT32 DropAck:1; // Drop Ps-Poll - UINT32 DropCFEnd:1; // Drop Ps-Poll - UINT32 DropCFEndAck:1; // Drop Ps-Poll - - UINT32 DropDuplicate:1; // Drop duplicate frame - UINT32 DropBcast:1; // Drop broadcast frames - UINT32 DropMcast:1; // Drop multicast frames - UINT32 DropVerErr:1; // Drop version error frame - - UINT32 DropNotMyBSSID:1; // Drop fram ToDs bit is true - UINT32 DropNotToMe:1; // Drop not to me unicast frame - UINT32 DropPhyErr:1; // Drop physical error - UINT32 DropCRCErr:1; // Drop CRC error - } field; - UINT32 word; -} RX_FILTR_CFG_STRUC, *PRX_FILTR_CFG_STRUC; -#else -typedef union _RX_FILTR_CFG_STRUC { - struct { - UINT32 DropCRCErr:1; // Drop CRC error - UINT32 DropPhyErr:1; // Drop physical error - UINT32 DropNotToMe:1; // Drop not to me unicast frame - UINT32 DropNotMyBSSID:1; // Drop fram ToDs bit is true - - UINT32 DropVerErr:1; // Drop version error frame - UINT32 DropMcast:1; // Drop multicast frames - UINT32 DropBcast:1; // Drop broadcast frames - UINT32 DropDuplicate:1; // Drop duplicate frame - - UINT32 DropCFEndAck:1; // Drop Ps-Poll - UINT32 DropCFEnd:1; // Drop Ps-Poll - UINT32 DropAck:1; // Drop Ps-Poll - UINT32 DropCts:1; // Drop Ps-Poll - - UINT32 DropRts:1; // Drop Ps-Poll - UINT32 DropPsPoll:1; // Drop Ps-Poll - UINT32 DropBA:1; // - UINT32 DropBAR:1; // - - UINT32 DropRsvCntlType:1; - UINT32 :15; - } field; - UINT32 word; -} RX_FILTR_CFG_STRUC, *PRX_FILTR_CFG_STRUC; -#endif - - - - -// -// PHY_CSR4: RF serial control register -// -#ifdef RT_BIG_ENDIAN -typedef union _PHY_CSR4_STRUC { - struct { - UINT32 Busy:1; // 1: ASIC is busy execute RF programming. - UINT32 PLL_LD:1; // RF PLL_LD status - UINT32 IFSelect:1; // 1: select IF to program, 0: select RF to program - UINT32 NumberOfBits:5; // Number of bits used in RFRegValue (I:20, RFMD:22) - UINT32 RFRegValue:24; // Register value (include register id) serial out to RF/IF chip. - } field; - UINT32 word; -} PHY_CSR4_STRUC, *PPHY_CSR4_STRUC; -#else -typedef union _PHY_CSR4_STRUC { - struct { - UINT32 RFRegValue:24; // Register value (include register id) serial out to RF/IF chip. - UINT32 NumberOfBits:5; // Number of bits used in RFRegValue (I:20, RFMD:22) - UINT32 IFSelect:1; // 1: select IF to program, 0: select RF to program - UINT32 PLL_LD:1; // RF PLL_LD status - UINT32 Busy:1; // 1: ASIC is busy execute RF programming. - } field; - UINT32 word; -} PHY_CSR4_STRUC, *PPHY_CSR4_STRUC; -#endif - - -// -// SEC_CSR5: shared key table security mode register -// -#ifdef RT_BIG_ENDIAN -typedef union _SEC_CSR5_STRUC { - struct { - UINT32 :1; - UINT32 Bss3Key3CipherAlg:3; - UINT32 :1; - UINT32 Bss3Key2CipherAlg:3; - UINT32 :1; - UINT32 Bss3Key1CipherAlg:3; - UINT32 :1; - UINT32 Bss3Key0CipherAlg:3; - UINT32 :1; - UINT32 Bss2Key3CipherAlg:3; - UINT32 :1; - UINT32 Bss2Key2CipherAlg:3; - UINT32 :1; - UINT32 Bss2Key1CipherAlg:3; - UINT32 :1; - UINT32 Bss2Key0CipherAlg:3; - } field; - UINT32 word; -} SEC_CSR5_STRUC, *PSEC_CSR5_STRUC; -#else -typedef union _SEC_CSR5_STRUC { - struct { - UINT32 Bss2Key0CipherAlg:3; - UINT32 :1; - UINT32 Bss2Key1CipherAlg:3; - UINT32 :1; - UINT32 Bss2Key2CipherAlg:3; - UINT32 :1; - UINT32 Bss2Key3CipherAlg:3; - UINT32 :1; - UINT32 Bss3Key0CipherAlg:3; - UINT32 :1; - UINT32 Bss3Key1CipherAlg:3; - UINT32 :1; - UINT32 Bss3Key2CipherAlg:3; - UINT32 :1; - UINT32 Bss3Key3CipherAlg:3; - UINT32 :1; - } field; - UINT32 word; -} SEC_CSR5_STRUC, *PSEC_CSR5_STRUC; -#endif - - -// -// HOST_CMD_CSR: For HOST to interrupt embedded processor -// -#ifdef RT_BIG_ENDIAN -typedef union _HOST_CMD_CSR_STRUC { - struct { - UINT32 Rsv:24; - UINT32 HostCommand:8; - } field; - UINT32 word; -} HOST_CMD_CSR_STRUC, *PHOST_CMD_CSR_STRUC; -#else -typedef union _HOST_CMD_CSR_STRUC { - struct { - UINT32 HostCommand:8; - UINT32 Rsv:24; - } field; - UINT32 word; -} HOST_CMD_CSR_STRUC, *PHOST_CMD_CSR_STRUC; -#endif - - -// -// AIFSN_CSR: AIFSN for each EDCA AC -// - - - -// -// E2PROM_CSR: EEPROM control register -// -#ifdef RT_BIG_ENDIAN -typedef union _E2PROM_CSR_STRUC { - struct { - UINT32 Rsvd:25; - UINT32 LoadStatus:1; // 1:loading, 0:done - UINT32 Type:1; // 1: 93C46, 0:93C66 - UINT32 EepromDO:1; - UINT32 EepromDI:1; - UINT32 EepromCS:1; - UINT32 EepromSK:1; - UINT32 Reload:1; // Reload EEPROM content, write one to reload, self-cleared. - } field; - UINT32 word; -} E2PROM_CSR_STRUC, *PE2PROM_CSR_STRUC; -#else -typedef union _E2PROM_CSR_STRUC { - struct { - UINT32 Reload:1; // Reload EEPROM content, write one to reload, self-cleared. - UINT32 EepromSK:1; - UINT32 EepromCS:1; - UINT32 EepromDI:1; - UINT32 EepromDO:1; - UINT32 Type:1; // 1: 93C46, 0:93C66 - UINT32 LoadStatus:1; // 1:loading, 0:done - UINT32 Rsvd:25; - } field; - UINT32 word; -} E2PROM_CSR_STRUC, *PE2PROM_CSR_STRUC; -#endif - - -// ------------------------------------------------------------------- -// E2PROM data layout -// ------------------------------------------------------------------- - -// -// EEPROM antenna select format -// -#ifdef RT_BIG_ENDIAN -typedef union _EEPROM_ANTENNA_STRUC { - struct { - USHORT Rsv:4; - USHORT RfIcType:4; // see E2PROM document - USHORT TxPath:4; // 1: 1T, 2: 2T - USHORT RxPath:4; // 1: 1R, 2: 2R, 3: 3R - } field; - USHORT word; -} EEPROM_ANTENNA_STRUC, *PEEPROM_ANTENNA_STRUC; -#else -typedef union _EEPROM_ANTENNA_STRUC { - struct { - USHORT RxPath:4; // 1: 1R, 2: 2R, 3: 3R - USHORT TxPath:4; // 1: 1T, 2: 2T - USHORT RfIcType:4; // see E2PROM document - USHORT Rsv:4; - } field; - USHORT word; -} EEPROM_ANTENNA_STRUC, *PEEPROM_ANTENNA_STRUC; -#endif - -#ifdef RT_BIG_ENDIAN -typedef union _EEPROM_NIC_CINFIG2_STRUC { - struct { - USHORT DACTestBit:1; // control if driver should patch the DAC issue - USHORT Rsv2:3; // must be 0 - USHORT AntDiversity:1; // Antenna diversity - USHORT Rsv1:1; // must be 0 - USHORT BW40MAvailForA:1; // 0:enable, 1:disable - USHORT BW40MAvailForG:1; // 0:enable, 1:disable - USHORT EnableWPSPBC:1; // WPS PBC Control bit - USHORT BW40MSidebandForA:1; - USHORT BW40MSidebandForG:1; - USHORT CardbusAcceleration:1; // !!! NOTE: 0 - enable, 1 - disable - USHORT ExternalLNAForA:1; // external LNA enable for 5G - USHORT ExternalLNAForG:1; // external LNA enable for 2.4G - USHORT DynamicTxAgcControl:1; // - USHORT HardwareRadioControl:1; // Whether RF is controlled by driver or HW. 1:enable hw control, 0:disable - } field; - USHORT word; -} EEPROM_NIC_CONFIG2_STRUC, *PEEPROM_NIC_CONFIG2_STRUC; -#else -typedef union _EEPROM_NIC_CINFIG2_STRUC { - struct { - USHORT HardwareRadioControl:1; // 1:enable, 0:disable - USHORT DynamicTxAgcControl:1; // - USHORT ExternalLNAForG:1; // - USHORT ExternalLNAForA:1; // external LNA enable for 2.4G - USHORT CardbusAcceleration:1; // !!! NOTE: 0 - enable, 1 - disable - USHORT BW40MSidebandForG:1; - USHORT BW40MSidebandForA:1; - USHORT EnableWPSPBC:1; // WPS PBC Control bit - USHORT BW40MAvailForG:1; // 0:enable, 1:disable - USHORT BW40MAvailForA:1; // 0:enable, 1:disable - USHORT Rsv1:1; // must be 0 - USHORT AntDiversity:1; // Antenna diversity - USHORT Rsv2:3; // must be 0 - USHORT DACTestBit:1; // control if driver should patch the DAC issue - } field; - USHORT word; -} EEPROM_NIC_CONFIG2_STRUC, *PEEPROM_NIC_CONFIG2_STRUC; -#endif - -// -// TX_PWR Value valid range 0xFA(-6) ~ 0x24(36) -// -#ifdef RT_BIG_ENDIAN -typedef union _EEPROM_TX_PWR_STRUC { - struct { - CHAR Byte1; // High Byte - CHAR Byte0; // Low Byte - } field; - USHORT word; -} EEPROM_TX_PWR_STRUC, *PEEPROM_TX_PWR_STRUC; -#else -typedef union _EEPROM_TX_PWR_STRUC { - struct { - CHAR Byte0; // Low Byte - CHAR Byte1; // High Byte - } field; - USHORT word; -} EEPROM_TX_PWR_STRUC, *PEEPROM_TX_PWR_STRUC; -#endif - -#ifdef RT_BIG_ENDIAN -typedef union _EEPROM_VERSION_STRUC { - struct { - UCHAR Version; // High Byte - UCHAR FaeReleaseNumber; // Low Byte - } field; - USHORT word; -} EEPROM_VERSION_STRUC, *PEEPROM_VERSION_STRUC; -#else -typedef union _EEPROM_VERSION_STRUC { - struct { - UCHAR FaeReleaseNumber; // Low Byte - UCHAR Version; // High Byte - } field; - USHORT word; -} EEPROM_VERSION_STRUC, *PEEPROM_VERSION_STRUC; -#endif - -#ifdef RT_BIG_ENDIAN -typedef union _EEPROM_LED_STRUC { - struct { - USHORT Rsvd:3; // Reserved - USHORT LedMode:5; // Led mode. - USHORT PolarityGPIO_4:1; // Polarity GPIO#4 setting. - USHORT PolarityGPIO_3:1; // Polarity GPIO#3 setting. - USHORT PolarityGPIO_2:1; // Polarity GPIO#2 setting. - USHORT PolarityGPIO_1:1; // Polarity GPIO#1 setting. - USHORT PolarityGPIO_0:1; // Polarity GPIO#0 setting. - USHORT PolarityACT:1; // Polarity ACT setting. - USHORT PolarityRDY_A:1; // Polarity RDY_A setting. - USHORT PolarityRDY_G:1; // Polarity RDY_G setting. - } field; - USHORT word; -} EEPROM_LED_STRUC, *PEEPROM_LED_STRUC; -#else -typedef union _EEPROM_LED_STRUC { - struct { - USHORT PolarityRDY_G:1; // Polarity RDY_G setting. - USHORT PolarityRDY_A:1; // Polarity RDY_A setting. - USHORT PolarityACT:1; // Polarity ACT setting. - USHORT PolarityGPIO_0:1; // Polarity GPIO#0 setting. - USHORT PolarityGPIO_1:1; // Polarity GPIO#1 setting. - USHORT PolarityGPIO_2:1; // Polarity GPIO#2 setting. - USHORT PolarityGPIO_3:1; // Polarity GPIO#3 setting. - USHORT PolarityGPIO_4:1; // Polarity GPIO#4 setting. - USHORT LedMode:5; // Led mode. - USHORT Rsvd:3; // Reserved - } field; - USHORT word; -} EEPROM_LED_STRUC, *PEEPROM_LED_STRUC; -#endif - -#ifdef RT_BIG_ENDIAN -typedef union _EEPROM_TXPOWER_DELTA_STRUC { - struct { - UCHAR TxPowerEnable:1;// Enable - UCHAR Type:1; // 1: plus the delta value, 0: minus the delta value - UCHAR DeltaValue:6; // Tx Power dalta value (MAX=4) - } field; - UCHAR value; -} EEPROM_TXPOWER_DELTA_STRUC, *PEEPROM_TXPOWER_DELTA_STRUC; -#else -typedef union _EEPROM_TXPOWER_DELTA_STRUC { - struct { - UCHAR DeltaValue:6; // Tx Power dalta value (MAX=4) - UCHAR Type:1; // 1: plus the delta value, 0: minus the delta value - UCHAR TxPowerEnable:1;// Enable - } field; - UCHAR value; -} EEPROM_TXPOWER_DELTA_STRUC, *PEEPROM_TXPOWER_DELTA_STRUC; -#endif - -// -// QOS_CSR0: TXOP holder address0 register -// -#ifdef RT_BIG_ENDIAN -typedef union _QOS_CSR0_STRUC { - struct { - UCHAR Byte3; // MAC address byte 3 - UCHAR Byte2; // MAC address byte 2 - UCHAR Byte1; // MAC address byte 1 - UCHAR Byte0; // MAC address byte 0 - } field; - UINT32 word; -} QOS_CSR0_STRUC, *PQOS_CSR0_STRUC; -#else -typedef union _QOS_CSR0_STRUC { - struct { - UCHAR Byte0; // MAC address byte 0 - UCHAR Byte1; // MAC address byte 1 - UCHAR Byte2; // MAC address byte 2 - UCHAR Byte3; // MAC address byte 3 - } field; - UINT32 word; -} QOS_CSR0_STRUC, *PQOS_CSR0_STRUC; -#endif - -// -// QOS_CSR1: TXOP holder address1 register -// -#ifdef RT_BIG_ENDIAN -typedef union _QOS_CSR1_STRUC { - struct { - UCHAR Rsvd1; - UCHAR Rsvd0; - UCHAR Byte5; // MAC address byte 5 - UCHAR Byte4; // MAC address byte 4 - } field; - UINT32 word; -} QOS_CSR1_STRUC, *PQOS_CSR1_STRUC; -#else -typedef union _QOS_CSR1_STRUC { - struct { - UCHAR Byte4; // MAC address byte 4 - UCHAR Byte5; // MAC address byte 5 - UCHAR Rsvd0; - UCHAR Rsvd1; - } field; - UINT32 word; -} QOS_CSR1_STRUC, *PQOS_CSR1_STRUC; -#endif - -#define RF_CSR_CFG 0x500 -#ifdef RT_BIG_ENDIAN -typedef union _RF_CSR_CFG_STRUC { - struct { - UINT Rsvd1:14; // Reserved - UINT RF_CSR_KICK:1; // kick RF register read/write - UINT RF_CSR_WR:1; // 0: read 1: write - UINT Rsvd2:3; // Reserved - UINT TESTCSR_RFACC_REGNUM:5; // RF register ID - UINT RF_CSR_DATA:8; // DATA - } field; - UINT word; -} RF_CSR_CFG_STRUC, *PRF_CSR_CFG_STRUC; -#else -typedef union _RF_CSR_CFG_STRUC { - struct { - UINT RF_CSR_DATA:8; // DATA - UINT TESTCSR_RFACC_REGNUM:5; // RF register ID - UINT Rsvd2:3; // Reserved - UINT RF_CSR_WR:1; // 0: read 1: write - UINT RF_CSR_KICK:1; // kick RF register read/write - UINT Rsvd1:14; // Reserved - } field; - UINT word; -} RF_CSR_CFG_STRUC, *PRF_CSR_CFG_STRUC; -#endif - -#endif // __RT28XX_H__ +#include "../rt2870/rt28xx.h" diff --git a/drivers/staging/rt3070/rt_ate.c b/drivers/staging/rt3070/rt_ate.c deleted file mode 100644 index 9238d960121c..000000000000 --- a/drivers/staging/rt3070/rt_ate.c +++ /dev/null @@ -1,6506 +0,0 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * 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 "rt_config.h" - -#ifdef UCOS -INT IoctlResponse(PUCHAR payload, PUCHAR msg, INT len); -#endif // UCOS // - -#define ATE_BBP_REG_NUM 168 -UCHAR restore_BBP[ATE_BBP_REG_NUM]={0}; - -#ifdef RALINK_ATE -UCHAR TemplateFrame[24] = {0x08/* Data type */,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0xAA,0xBB,0x12,0x34,0x56,0x00,0x11,0x22,0xAA,0xBB,0xCC,0x00,0x00}; // 802.11 MAC Header, Type:Data, Length:24bytes -extern RTMP_RF_REGS RF2850RegTable[]; -extern UCHAR NUM_OF_2850_CHNL; - -#ifdef RT2870 -extern UCHAR EpToQueue[]; -extern VOID RTUSBRejectPendingPackets( IN PRTMP_ADAPTER pAd); -#endif // RT2870 // - -#ifdef RT30xx -//2008/07/10:KH adds to support 3070 ATE<-- -extern FREQUENCY_ITEM FreqItems3020[]; -extern UCHAR NUM_OF_3020_CHNL; -//2008/07/10:KH adds to support 3070 ATE--> -#endif // RT30xx // - -#ifdef UCOS -extern INT ConsoleResponse(IN PUCHAR buff); -extern int (*remote_display)(char *); -#endif // UCOS // - -static CHAR CCKRateTable[] = {0, 1, 2, 3, 8, 9, 10, 11, -1}; /* CCK Mode. */ -static CHAR OFDMRateTable[] = {0, 1, 2, 3, 4, 5, 6, 7, -1}; /* OFDM Mode. */ -static CHAR HTMIXRateTable[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, -1}; /* HT Mix Mode. */ - -static INT TxDmaBusy( - IN PRTMP_ADAPTER pAd); - -static INT RxDmaBusy( - IN PRTMP_ADAPTER pAd); - -static VOID RtmpDmaEnable( - IN PRTMP_ADAPTER pAd, - IN INT Enable); - -static VOID BbpSoftReset( - IN PRTMP_ADAPTER pAd); - -static VOID RtmpRfIoWrite( - IN PRTMP_ADAPTER pAd); - -static INT ATESetUpFrame( - IN PRTMP_ADAPTER pAd, - IN UINT32 TxIdx); - -static INT ATETxPwrHandler( - IN PRTMP_ADAPTER pAd, - IN char index); - -static INT ATECmdHandler( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -static int CheckMCSValid( - IN UCHAR Mode, - IN UCHAR Mcs); - - -#ifdef RT2870 -static VOID ATEWriteTxInfo( - IN PRTMP_ADAPTER pAd, - IN PTXINFO_STRUC pTxInfo, - IN USHORT USBDMApktLen, - IN BOOLEAN bWiv, - IN UCHAR QueueSel, - IN UCHAR NextValid, - IN UCHAR TxBurst); - -static VOID ATEWriteTxWI( - IN PRTMP_ADAPTER pAd, - IN PTXWI_STRUC pTxWI, - IN BOOLEAN FRAG, - IN BOOLEAN InsTimestamp, - IN BOOLEAN AMPDU, - IN BOOLEAN Ack, - IN BOOLEAN NSeq, // HW new a sequence. - IN UCHAR BASize, - IN UCHAR WCID, - IN ULONG Length, - IN UCHAR PID, - IN UCHAR MIMOps, - IN UCHAR Txopmode, - IN BOOLEAN CfAck, - IN HTTRANSMIT_SETTING Transmit); - -#endif // RT2870 // - -static VOID SetJapanFilter( - IN PRTMP_ADAPTER pAd); - -/*=========================end of prototype=========================*/ - - -#ifdef RT2870 -static INT TxDmaBusy( - IN PRTMP_ADAPTER pAd) -{ - INT result; - USB_DMA_CFG_STRUC UsbCfg; - - RTMP_IO_READ32(pAd, USB_DMA_CFG, &UsbCfg.word); // disable DMA - if (UsbCfg.field.TxBusy) - result = 1; - else - result = 0; - - return result; -} - -static INT RxDmaBusy( - IN PRTMP_ADAPTER pAd) -{ - INT result; - USB_DMA_CFG_STRUC UsbCfg; - - RTMP_IO_READ32(pAd, USB_DMA_CFG, &UsbCfg.word); // disable DMA - if (UsbCfg.field.RxBusy) - result = 1; - else - result = 0; - - return result; -} - -static VOID RtmpDmaEnable( - IN PRTMP_ADAPTER pAd, - IN INT Enable) -{ - BOOLEAN value; - ULONG WaitCnt; - USB_DMA_CFG_STRUC UsbCfg; - - value = Enable > 0 ? 1 : 0; - - // check DMA is in busy mode. - WaitCnt = 0; - while (TxDmaBusy(pAd) || RxDmaBusy(pAd)) - { - RTMPusecDelay(10); - if (WaitCnt++ > 100) - break; - } - - //Why not to clear USB DMA TX path first ??? - RTMP_IO_READ32(pAd, USB_DMA_CFG, &UsbCfg.word); // disable DMA - UsbCfg.field.TxBulkEn = value; - UsbCfg.field.RxBulkEn = value; - RTMP_IO_WRITE32(pAd, USB_DMA_CFG, UsbCfg.word); // abort all TX rings - RTMPusecDelay(5000); - - return; -} -#endif // RT2870 // - -static VOID BbpSoftReset( - IN PRTMP_ADAPTER pAd) -{ - UCHAR BbpData = 0; - - // Soft reset, set BBP R21 bit0=1->0 - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R21, &BbpData); - BbpData |= 0x00000001; //set bit0=1 - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R21, BbpData); - - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R21, &BbpData); - BbpData &= ~(0x00000001); //set bit0=0 - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R21, BbpData); - - return; -} - -static VOID RtmpRfIoWrite( - IN PRTMP_ADAPTER pAd) -{ - // Set RF value 1's set R3[bit2] = [0] - RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R1); - RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R2); - RTMP_RF_IO_WRITE32(pAd, (pAd->LatchRfRegs.R3 & (~0x04))); - RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R4); - - RTMPusecDelay(200); - - // Set RF value 2's set R3[bit2] = [1] - RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R1); - RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R2); - RTMP_RF_IO_WRITE32(pAd, (pAd->LatchRfRegs.R3 | 0x04)); - RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R4); - - RTMPusecDelay(200); - - // Set RF value 3's set R3[bit2] = [0] - RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R1); - RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R2); - RTMP_RF_IO_WRITE32(pAd, (pAd->LatchRfRegs.R3 & (~0x04))); - RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R4); - - return; -} - -static int CheckMCSValid( - UCHAR Mode, - UCHAR Mcs) -{ - int i; - PCHAR pRateTab; - - switch(Mode) - { - case 0: - pRateTab = CCKRateTable; - break; - case 1: - pRateTab = OFDMRateTable; - break; - case 2: - case 3: - pRateTab = HTMIXRateTable; - break; - default: - ATEDBGPRINT(RT_DEBUG_ERROR, ("unrecognizable Tx Mode %d\n", Mode)); - return -1; - break; - } - - i = 0; - while(pRateTab[i] != -1) - { - if (pRateTab[i] == Mcs) - return 0; - i++; - } - - return -1; -} - -#if 1 -static INT ATETxPwrHandler( - IN PRTMP_ADAPTER pAd, - IN char index) -{ - ULONG R; - CHAR TxPower; - UCHAR Bbp94 = 0; - BOOLEAN bPowerReduce = FALSE; -#ifdef RT30xx - UCHAR RFValue; -#endif // RT30xx // -#ifdef RALINK_28xx_QA - if ((pAd->ate.bQATxStart == TRUE) || (pAd->ate.bQARxStart == TRUE)) - { - /* When QA is used for Tx, pAd->ate.TxPower0/1 and real tx power - ** are not synchronized. - */ -/* - pAd->ate.TxPower0 = pAd->LatchRfRegs.xxx; - pAd->ate.TxPower1 = pAd->LatchRfRegs.xxx; -*/ - return 0; - } - else -#endif // RALINK_28xx_QA // - { - TxPower = index == 0 ? pAd->ate.TxPower0 : pAd->ate.TxPower1; - - if (pAd->ate.Channel <= 14) - { - if (TxPower > 31) - { - // - // R3, R4 can't large than 31 (0x24), 31 ~ 36 used by BBP 94 - // - R = 31; - if (TxPower <= 36) - Bbp94 = BBPR94_DEFAULT + (UCHAR)(TxPower - 31); - } - else if (TxPower < 0) - { - // - // R3, R4 can't less than 0, -1 ~ -6 used by BBP 94 - // - R = 0; - if (TxPower >= -6) - Bbp94 = BBPR94_DEFAULT + TxPower; - } - else - { - // 0 ~ 31 - R = (ULONG) TxPower; - Bbp94 = BBPR94_DEFAULT; - } - - ATEDBGPRINT(RT_DEBUG_TRACE, ("%s (TxPower=%d, R=%ld, BBP_R94=%d)\n", __FUNCTION__, TxPower, R, Bbp94)); - } - else// 5.5 GHz - { - if (TxPower > 15) - { - // - // R3, R4 can't large than 15 (0x0F) - // - R = 15; - } - else if (TxPower < 0) - { - // - // R3, R4 can't less than 0 - // - // -1 ~ -7 - ASSERT((TxPower >= -7)); - R = (ULONG)(TxPower + 7); - bPowerReduce = TRUE; - } - else - { - // 0 ~ 15 - R = (ULONG) TxPower; - } - - ATEDBGPRINT(RT_DEBUG_TRACE, ("%s (TxPower=%d, R=%lu)\n", __FUNCTION__, TxPower, R)); - } -//2008/09/10:KH adds to support 3070 ATE TX Power tunning real time<-- -#ifdef RT30xx - if(IS_RT30xx(pAd)) - { - // Set Tx Power - - RT30xxReadRFRegister(pAd, RF_R12, (PUCHAR)&RFValue); - RFValue = (RFValue & 0xE0) | TxPower; - RT30xxWriteRFRegister(pAd, RF_R12, (UCHAR)RFValue); - ATEDBGPRINT(RT_DEBUG_TRACE, ("3070 or 2070:%s (TxPower=%d, RFValue=%x)\n", __FUNCTION__, TxPower, RFValue)); - - } - else -#endif // RT30xx // - { - if (pAd->ate.Channel <= 14) - { - if (index == 0) - { - R = R << 9; // shift TX power control to correct RF(R3) register bit position - R |= (pAd->LatchRfRegs.R3 & 0xffffc1ff); - pAd->LatchRfRegs.R3 = R; - } - else - { - R = R << 6; // shift TX power control to correct RF(R4) register bit position - R |= (pAd->LatchRfRegs.R4 & 0xfffff83f); - pAd->LatchRfRegs.R4 = R; - } - } - else// 5.5GHz - { - if (bPowerReduce == FALSE) - { - if (index == 0) - { - R = (R << 10) | (1 << 9); // shift TX power control to correct RF(R3) register bit position - R |= (pAd->LatchRfRegs.R3 & 0xffffc1ff); - pAd->LatchRfRegs.R3 = R; - } - else - { - R = (R << 7) | (1 << 6); // shift TX power control to correct RF(R4) register bit position - R |= (pAd->LatchRfRegs.R4 & 0xfffff83f); - pAd->LatchRfRegs.R4 = R; - } - } - else - { - if (index == 0) - { - R = (R << 10); // shift TX power control to correct RF(R3) register bit position - R |= (pAd->LatchRfRegs.R3 & 0xffffc1ff); - - /* Clear bit 9 of R3 to reduce 7dB. */ - pAd->LatchRfRegs.R3 = (R & (~(1 << 9))); - } - else - { - R = (R << 7); // shift TX power control to correct RF(R4) register bit position - R |= (pAd->LatchRfRegs.R4 & 0xfffff83f); - - /* Clear bit 6 of R4 to reduce 7dB. */ - pAd->LatchRfRegs.R4 = (R & (~(1 << 6))); - } - } - } - RtmpRfIoWrite(pAd); - } -//2008/09/10:KH adds to support 3070 ATE TX Power tunning real time--> - - return 0; - } -} -#else// 1 // -static INT ATETxPwrHandler( - IN PRTMP_ADAPTER pAd, - IN char index) -{ - ULONG R; - CHAR TxPower; - UCHAR Bbp94 = 0; - -#ifdef RALINK_28xx_QA - if ((pAd->ate.bQATxStart == TRUE) || (pAd->ate.bQARxStart == TRUE)) - { - // TODO: how to get current TxPower0/1 from pAd->LatchRfRegs ? - /* When QA is used for Tx, pAd->ate.TxPower0/1 and real tx power - ** are not synchronized. - */ -/* - pAd->ate.TxPower0 = pAd->LatchRfRegs.xxx; - pAd->ate.TxPower1 = pAd->LatchRfRegs.xxx; -*/ - return 0; - } - else -#endif // RALINK_28xx_QA // - { - TxPower = index == 0 ? pAd->ate.TxPower0 : pAd->ate.TxPower1; - - if (TxPower > 31) - { - // - // R3, R4 can't large than 36 (0x24), 31 ~ 36 used by BBP 94 - // - R = 31; - if (TxPower <= 36) - Bbp94 = BBPR94_DEFAULT + (UCHAR)(TxPower - 31); - } - else if (TxPower < 0) - { - // - // R3, R4 can't less than 0, -1 ~ -6 used by BBP 94 - // - R = 0; - if (TxPower >= -6) - Bbp94 = BBPR94_DEFAULT + TxPower; - } - else - { - // 0 ~ 31 - R = (ULONG) TxPower; - Bbp94 = BBPR94_DEFAULT; - } - - ATEDBGPRINT(RT_DEBUG_TRACE, ("%s (TxPower=%d, R3=%ld, BBP_R94=%d)\n", __FUNCTION__, TxPower, R, Bbp94)); - - if (pAd->ate.Channel <= 14) - { - if (index == 0) - { - R = R << 9; // shift TX power control to correct RF(R3) register bit position - R |= (pAd->LatchRfRegs.R3 & 0xffffc1ff); - pAd->LatchRfRegs.R3 = R; - } - else - { - R = R << 6; // shift TX power control to correct RF(R4) register bit position - R |= (pAd->LatchRfRegs.R4 & 0xfffff83f); - pAd->LatchRfRegs.R4 = R; - } - } - else - { - if (index == 0) - { - R = (R << 10) | (1 << 9); // shift TX power control to correct RF(R3) register bit position - R |= (pAd->LatchRfRegs.R3 & 0xffffc1ff); - pAd->LatchRfRegs.R3 = R; - } - else - { - R = (R << 7) | (1 << 6); // shift TX power control to correct RF(R4) register bit position - R |= (pAd->LatchRfRegs.R4 & 0xfffff83f); - pAd->LatchRfRegs.R4 = R; - } - } - - RtmpRfIoWrite(pAd); - - return 0; - } -} -#endif // 1 // -/* - ========================================================================== - Description: - Set ATE operation mode to - 0. ATESTART = Start ATE Mode - 1. ATESTOP = Stop ATE Mode - 2. TXCONT = Continuous Transmit - 3. TXCARR = Transmit Carrier - 4. TXFRAME = Transmit Frames - 5. RXFRAME = Receive Frames -#ifdef RALINK_28xx_QA - 6. TXSTOP = Stop Any Type of Transmition - 7. RXSTOP = Stop Receiving Frames -#endif // RALINK_28xx_QA // - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -/* */ -/* */ -/*=======================End of RT2860=======================*/ - - -/*======================Start of RT2870======================*/ -/* */ -/* */ - -#ifdef RT2870 -static INT ATECmdHandler( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - UINT32 Value; - UCHAR BbpData; - UINT32 MacData; - UINT i=0, atemode; - //NDIS_STATUS Status = NDIS_STATUS_SUCCESS; - //PUCHAR pDest; - UINT32 temp; - ULONG IrqFlags; - - ATEDBGPRINT(RT_DEBUG_TRACE, ("===> ATECmdHandler()\n")); - ATEAsicSwitchChannel(pAd); - /* AsicLockChannel() is empty function so far in fact */ - AsicLockChannel(pAd, pAd->ate.Channel); - - RTMPusecDelay(5000); - - // Default value in BBP R22 is 0x0. - BbpData = 0; - - /* Enter ATE mode and set Tx/Rx Idle */ - if (!strcmp(arg, "ATESTART")) - { -#ifdef CONFIG_STA_SUPPORT - BOOLEAN Cancelled; -#endif // CONFIG_STA_SUPPORT // - ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE: ATESTART\n")); - - netif_stop_queue(pAd->net_dev); - - atemode = pAd->ate.Mode; - pAd->ate.Mode = ATE_START; -// pAd->ate.TxDoneCount = pAd->ate.TxCount; - // Disable Rx - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value &= ~(1 << 3); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - - // Disable auto responder - RTMP_IO_READ32(pAd, AUTO_RSP_CFG, &temp); - temp = temp & 0xFFFFFFFE; - RTMP_IO_WRITE32(pAd, AUTO_RSP_CFG, temp); - - // read MAC_SYS_CTRL and backup MAC_SYS_CTRL value. - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &MacData); - // clean bit4 to stop continuous Tx production test. - MacData &= 0xFFFFFFEF; - // Stop continuous TX production test. - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, MacData);//disable or cancel pending irp first ??? - - if (atemode & ATE_TXCARR -#ifdef RT30xx - || atemode & ATE_TXCONT -#endif // RT30xx // -) - { -#ifdef RT30xx - //Hardware Reset BBP - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &temp); - temp = temp |0x00000002; - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, temp); - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &temp); - temp = temp & ~(0x00000002); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, temp); - //Restore All BBP Value - for(i=0;iMlmeAux.AssocTimer, &Cancelled); - RTMPCancelTimer(&pAd->MlmeAux.ReassocTimer, &Cancelled); - RTMPCancelTimer(&pAd->MlmeAux.DisassocTimer, &Cancelled); - RTMPCancelTimer(&pAd->MlmeAux.AuthTimer, &Cancelled); - RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer, &Cancelled); - RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &Cancelled); -#endif // CONFIG_STA_SUPPORT // - - //RTUSBCleanUpMLMEWaitQueue(pAd); /* not used in RT28xx */ - RTUSBCleanUpMLMEBulkOutQueue(pAd); - - // Sometimes kernel will hang on, so we avoid calling MlmeSuspend(). -// MlmeSuspend(pAd, TRUE); - //RTMPCancelTimer(&pAd->Mlme.PeriodicTimer, &Cancelled); - - // Disable Rx - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value &= ~(1 << 3); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - - // Abort Tx, RX DMA. - RtmpDmaEnable(pAd, 0); - - // Disable Tx - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value &= ~(1 << 2); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - - // Make sure there are no pending bulk in/out IRPs before we go on. -/*=========================================================================*/ - /* pAd->PendingRx is not of type atomic_t anymore in 28xx */ -// while ((atomic_read(&pAd->PendingRx) > 0)) //pAd->BulkFlags != 0 wait bulk out finish - while ((pAd->PendingRx > 0)) //pAd->BulkFlags != 0 wait bulk out finish - { -#if 1 - ATE_RTUSBCancelPendingBulkInIRP(pAd); -#else - NdisInterlockedDecrement(&pAd->PendingRx); -#endif - /* delay 0.5 seconds */ - RTMPusecDelay(500000); - pAd->PendingRx = 0; - } - /* peter : why don't we have to get BulkOutLock first ? */ - while (((pAd->BulkOutPending[0] == TRUE) || - (pAd->BulkOutPending[1] == TRUE) || - (pAd->BulkOutPending[2] == TRUE) || - (pAd->BulkOutPending[3] == TRUE)) && (pAd->BulkFlags != 0)) //pAd->BulkFlags != 0 wait bulk out finish - { - do - { - /* pAd->BulkOutPending[y] will be set to FALSE in RTUSBCancelPendingBulkOutIRP(pAd) */ - RTUSBCancelPendingBulkOutIRP(pAd); - } while (FALSE); - - /* we have enough time delay in RTUSBCancelPendingBulkOutIRP(pAd) - ** so this is not necessary - */ -// RTMPusecDelay(500000); - } - - /* pAd->PendingRx is not of type atomic_t anymore in 28xx */ -// ASSERT(atomic_read(&pAd->PendingRx) == 0); - ASSERT(pAd->PendingRx == 0); -/*=========================================================================*/ - - // reset Rx statistics. - pAd->ate.LastSNR0 = 0; - pAd->ate.LastSNR1 = 0; - pAd->ate.LastRssi0 = 0; - pAd->ate.LastRssi1 = 0; - pAd->ate.LastRssi2 = 0; - pAd->ate.AvgRssi0 = 0; - pAd->ate.AvgRssi1 = 0; - pAd->ate.AvgRssi2 = 0; - pAd->ate.AvgRssi0X8 = 0; - pAd->ate.AvgRssi1X8 = 0; - pAd->ate.AvgRssi2X8 = 0; - pAd->ate.NumOfAvgRssiSample = 0; - -#ifdef RALINK_28xx_QA - // Tx frame - pAd->ate.bQATxStart = FALSE; - pAd->ate.bQARxStart = FALSE; - pAd->ate.seq = 0; - - // counters - pAd->ate.U2M = 0; - pAd->ate.OtherData = 0; - pAd->ate.Beacon = 0; - pAd->ate.OtherCount = 0; - pAd->ate.TxAc0 = 0; - pAd->ate.TxAc1 = 0; - pAd->ate.TxAc2 = 0; - pAd->ate.TxAc3 = 0; - pAd->ate.TxHCCA = 0; - pAd->ate.TxMgmt = 0; - pAd->ate.RSSI0 = 0; - pAd->ate.RSSI1 = 0; - pAd->ate.RSSI2 = 0; - pAd->ate.SNR0 = 0; - pAd->ate.SNR1 = 0; - - // control - pAd->ate.TxDoneCount = 0; - pAd->ate.TxStatus = 0; // task Tx status // 0 --> task is idle, 1 --> task is running -#endif // RALINK_28xx_QA // - - // Soft reset BBP. - BbpSoftReset(pAd); - - -#ifdef CONFIG_STA_SUPPORT - AsicDisableSync(pAd); - - /* - ** If we skip "LinkDown()", we should disable protection - ** to prevent from sending out RTS or CTS-to-self. - */ - ATEDisableAsicProtect(pAd); - RTMPStationStop(pAd); -#endif // CONFIG_STA_SUPPORT // - - // Default value in BBP R22 is 0x0. - BbpData = 0; - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &MacData); - - // Clean bit4 to stop continuous Tx production test. - MacData &= 0xFFFFFFEF; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, MacData); - //Clean ATE Bulk in/out counter and continue setup - InterlockedExchange(&pAd->BulkOutRemained, 0); - - /* NdisAcquireSpinLock()/NdisReleaseSpinLock() need only one argument in RT28xx */ - NdisAcquireSpinLock(&pAd->GenericLock); - pAd->ContinBulkOut = FALSE; - pAd->ContinBulkIn = FALSE; - NdisReleaseSpinLock(&pAd->GenericLock); - - RTUSB_CLEAR_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_ATE); - } - else if (!strcmp(arg, "ATESTOP")) - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE : ATESTOP ===>\n")); - - // Default value in BBP R22 is 0x0. - BbpData = 0; - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &MacData);//0820 - // Clean bit4 to stop continuous Tx production test. - MacData &= 0xFFFFFFEF; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, MacData); // recover the MAC_SYS_CTRL register back. - - // Disable Rx - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value &= ~(1 << 3); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - - /* - ** Abort Tx, RX DMA. - ** Q : How to do the following I/O if Tx, Rx DMA is aborted ? - ** Ans : Bulk endpoints are aborted, while the control endpoint is not. - */ - RtmpDmaEnable(pAd, 0); - - // Disable Tx - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value &= ~(1 << 2); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - - /* Make sure there are no pending bulk in/out IRPs before we go on. */ -/*=========================================================================*/ -// while ((atomic_read(&pAd->PendingRx) > 0)) //pAd->BulkFlags != 0 wait bulk out finish - while (pAd->PendingRx > 0) - { -#if 1 - ATE_RTUSBCancelPendingBulkInIRP(pAd); -#else -// NdisInterlockedDecrement(&pAd->PendingRx); - pAd->PendingRx--; -#endif - RTMPusecDelay(500000); - } - - while (((pAd->BulkOutPending[0] == TRUE) || - (pAd->BulkOutPending[1] == TRUE) || - (pAd->BulkOutPending[2] == TRUE) || - (pAd->BulkOutPending[3] == TRUE)) && (pAd->BulkFlags != 0)) //pAd->BulkFlags != 0 wait bulk out finish - { - do - { - RTUSBCancelPendingBulkOutIRP(pAd); - } while (FALSE); - - RTMPusecDelay(500000); - } - -// ASSERT(atomic_read(&pAd->PendingRx) == 0); - ASSERT(pAd->PendingRx == 0); -/*=========================================================================*/ -/* Reset Rx RING */ -/*=========================================================================*/ -// InterlockedExchange(&pAd->PendingRx, 0); - pAd->PendingRx = 0; - pAd->NextRxBulkInReadIndex = 0; // Next Rx Read index - pAd->NextRxBulkInIndex = RX_RING_SIZE - 1; // Rx Bulk pointer - pAd->NextRxBulkInPosition = 0; - for (i = 0; i < (RX_RING_SIZE); i++) - { - PRX_CONTEXT pRxContext = &(pAd->RxContext[i]); - NdisZeroMemory(pRxContext->TransferBuffer, MAX_RXBULK_SIZE); - /* peter : why don't we have to get BulkInLock first ? */ - pRxContext->pAd = pAd; - pRxContext->pIrp = NULL; - /* peter debug ++ */ - pRxContext->BulkInOffset = 0; - pRxContext->bRxHandling = FALSE; - /* peter debug -- */ - pRxContext->InUse = FALSE; - pRxContext->IRPPending = FALSE; - pRxContext->Readable = FALSE; -// pRxContext->ReorderInUse = FALSE; -// pRxContext->ReadPosOffset = 0; - } - -/*=========================================================================*/ -/* Reset Tx RING */ -/*=========================================================================*/ - do - { - RTUSBCancelPendingBulkOutIRP(pAd); - } while (FALSE); - -/*=========================================================================*/ - // Enable auto responder. - RTMP_IO_READ32(pAd, AUTO_RSP_CFG, &temp); - temp = temp | (0x01); - RTMP_IO_WRITE32(pAd, AUTO_RSP_CFG, temp); - -/*================================================*/ - AsicEnableBssSync(pAd); - - /* Soft reset BBP.*/ - /* In 2870 chipset, ATE_BBP_IO_READ8_BY_REG_ID() == RTMP_BBP_IO_READ8_BY_REG_ID() */ - /* Both rt2870ap and rt2870sta use BbpSoftReset(pAd) to do BBP soft reset */ - BbpSoftReset(pAd); -/*================================================*/ - { -#ifdef CONFIG_STA_SUPPORT - // Set all state machines back IDLE - pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; - pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; - pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; - pAd->Mlme.AuthRspMachine.CurrState = AUTH_RSP_IDLE; - pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; - pAd->Mlme.ActMachine.CurrState = ACT_IDLE; -#endif // CONFIG_STA_SUPPORT // - - // - // ===> refer to MlmeRestartStateMachine(). - // When we entered ATE_START mode, PeriodicTimer was not cancelled. - // So we don't have to set it here. - // - //RTMPSetTimer(pAd, &pAd->Mlme.PeriodicTimer, MLME_TASK_EXEC_INTV); - - ASSERT(pAd->CommonCfg.Channel != 0); - - AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); - AsicLockChannel(pAd, pAd->CommonCfg.Channel); - - -#ifdef CONFIG_STA_SUPPORT - RTMPStationStart(pAd); -#endif // CONFIG_STA_SUPPORT // - } -// -// These two steps have been done when entering ATE_STOP mode. -// - // Clean ATE Bulk in/out counter and continue setup. - InterlockedExchange(&pAd->BulkOutRemained, 0); - NdisAcquireSpinLock(&pAd->GenericLock); - pAd->ContinBulkOut = FALSE; - pAd->ContinBulkIn = FALSE; - NdisReleaseSpinLock(&pAd->GenericLock); - - /* Wait 50ms to prevent next URB to bulkout during HW reset. */ - /* todo : remove this if not necessary */ - NdisMSleep(50000); - - pAd->ate.Mode = ATE_STOP; - - // Enable Tx - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value |= (1 << 2); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - -/*=========================================================================*/ - /* restore RX_FILTR_CFG */ -#ifdef CONFIG_STA_SUPPORT - /* restore RX_FILTR_CFG in order that QA maybe set it to 0x3 */ - RTMP_IO_WRITE32(pAd, RX_FILTR_CFG, STANORMAL); -#endif // CONFIG_STA_SUPPORT // -/*=========================================================================*/ - - // Enable Tx, RX DMA. - RtmpDmaEnable(pAd, 1); - - // Enable Rx - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value |= (1 << 3); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - - // Wait 10ms to wait all of the bulk-in URBs to complete. - /* todo : remove this if not necessary */ - NdisMSleep(10000); - - // Everything is ready to start normal Tx/Rx. - RTUSBBulkReceive(pAd); - netif_start_queue(pAd->net_dev); - - ATEDBGPRINT(RT_DEBUG_TRACE, ("<=== ATE : ATESTOP \n")); - } - else if (!strcmp(arg, "TXCARR")) // Tx Carrier - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE: TXCARR\n")); - pAd->ate.Mode |= ATE_TXCARR; - -#ifdef RT30xx - for(i=0;iate.bQATxStart == FALSE) - { - // Soft reset BBP. - BbpSoftReset(pAd); - - // Carrier Test set BBP R22 bit7=1, bit6=1, bit[5~0]=0x01 - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R22, &BbpData); - BbpData &= 0xFFFFFF00; //clear bit7, bit6, bit[5~0] - BbpData |= 0x000000C1; //set bit7=1, bit6=1, bit[5~0]=0x01 - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); - - // set MAC_SYS_CTRL(0x1004) Continuous Tx Production Test (bit4) = 1 - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value = Value | 0x00000010; - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - } - } - else if (!strcmp(arg, "TXCONT")) // Tx Continue - { - if (pAd->ate.bQATxStart == TRUE) - { - /* set MAC_SYS_CTRL(0x1004) bit4(Continuous Tx Production Test) - and bit2(MAC TX enable) back to zero. */ - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &MacData); - MacData &= 0xFFFFFFEB; - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, MacData); - - // set BBP R22 bit7=0 - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R22, &BbpData); - BbpData &= 0xFFFFFF7F; //set bit7=0 - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); - } - - /* for TxCont mode. - ** Step 1: Send 50 packets first then wait for a moment. - ** Step 2: Send more 50 packet then start continue mode. - */ - ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE: TXCONT\n")); - -#ifdef RT30xx - for(i=0;iate.Mode |= ATE_TXCONT; - pAd->ate.TxCount = 50; - pAd->ate.TxDoneCount = 0; - - // Soft reset BBP. - BbpSoftReset(pAd); - - // Abort Tx, RX DMA. - RtmpDmaEnable(pAd, 0); - - - /* Only needed if we have to send some normal frames. */ - SetJapanFilter(pAd); - - // Setup frame format. - ATESetUpFrame(pAd, 0); - - // Enable Tx - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value |= (1 << 2); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - - // Disable Rx - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value &= ~(1 << 3); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - - // Start Tx, RX DMA. - RtmpDmaEnable(pAd, 1); - - InterlockedExchange(&pAd->BulkOutRemained, pAd->ate.TxCount); - -#ifdef RALINK_28xx_QA - if (pAd->ate.bQATxStart == TRUE) - { - pAd->ate.TxStatus = 1; - //pAd->ate.Repeat = 0; - } -#endif // RALINK_28xx_QA // - - NdisAcquireSpinLock(&pAd->GenericLock);//0820 - pAd->ContinBulkOut = FALSE; - NdisReleaseSpinLock(&pAd->GenericLock); - - RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_ATE); - - // Kick bulk out - RTUSBKickBulkOut(pAd); - - /* To make sure all the 50 frames have been bulk out before executing step 2 */ - while (atomic_read(&pAd->BulkOutRemained) > 0) - { - RTMPusecDelay(5000); - } - - // Step 2: send more 50 packets then start continue mode. - // Abort Tx, RX DMA. - RtmpDmaEnable(pAd, 0); - - // Cont. TX set BBP R22 bit7=1 - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R22, &BbpData); - BbpData |= 0x00000080; //set bit7=1 - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); - - pAd->ate.TxCount = 50; - pAd->ate.TxDoneCount = 0; - - SetJapanFilter(pAd); - - // Setup frame format. - ATESetUpFrame(pAd, 0); - - // Enable Tx - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value |= (1 << 2); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - - // Disable Rx - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value &= ~(1 << 3); - - // Start Tx, RX DMA. - RtmpDmaEnable(pAd, 1); - - InterlockedExchange(&pAd->BulkOutRemained, pAd->ate.TxCount); - -#ifdef RALINK_28xx_QA - if (pAd->ate.bQATxStart == TRUE) - { - pAd->ate.TxStatus = 1; - //pAd->ate.Repeat = 0; - } -#endif // RALINK_28xx_QA // - - NdisAcquireSpinLock(&pAd->GenericLock);//0820 - pAd->ContinBulkOut = FALSE; - NdisReleaseSpinLock(&pAd->GenericLock); - - RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_ATE); - // Kick bulk out - RTUSBKickBulkOut(pAd); - -#if 1 - RTMPusecDelay(500); -#else - while (atomic_read(&pAd->BulkOutRemained) > 0) - { - RTMPusecDelay(5000); - } -#endif // 1 // - - // Set MAC_SYS_CTRL(0x1004) Continuous Tx Production Test (bit4) = 1. - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &MacData); - MacData |= 0x00000010; - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, MacData); - } - else if (!strcmp(arg, "TXFRAME")) // Tx Frames - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE: TXFRAME(Count=0x%08x)\n", pAd->ate.TxCount)); - pAd->ate.Mode |= ATE_TXFRAME; - - // Soft reset BBP. - BbpSoftReset(pAd); - - // Default value in BBP R22 is 0x0. - BbpData = 0; - - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &MacData); - - // Clean bit4 to stop continuous Tx production test. - MacData &= 0xFFFFFFEF; - - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, MacData); - -#ifdef RALINK_28xx_QA - // add this for LoopBack mode - if (pAd->ate.bQARxStart == FALSE) - { - // Disable Rx - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value &= ~(1 << 3); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - } - - if (pAd->ate.bQATxStart == TRUE) - { - pAd->ate.TxStatus = 1; - //pAd->ate.Repeat = 0; - } -#else - // Disable Rx - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value &= ~(1 << 3); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); -#endif // RALINK_28xx_QA // - - // Enable Tx - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value |= (1 << 2); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - - SetJapanFilter(pAd); - - // Abort Tx, RX DMA. - RtmpDmaEnable(pAd, 0); - - pAd->ate.TxDoneCount = 0; - - // Setup frame format - ATESetUpFrame(pAd, 0); - - // Start Tx, RX DMA. - RtmpDmaEnable(pAd, 1); - - // Check count is continuous or not yet. - // - // Due to the type mismatch between "pAd->BulkOutRemained"(atomic_t) and "pAd->ate.TxCount"(UINT32) - // - if (pAd->ate.TxCount == 0) - { - InterlockedExchange(&pAd->BulkOutRemained, 0); - } - else - { - InterlockedExchange(&pAd->BulkOutRemained, pAd->ate.TxCount); - } - ATEDBGPRINT(RT_DEBUG_TRACE, ("bulk out count = %d\n", atomic_read(&pAd->BulkOutRemained))); - ASSERT((atomic_read(&pAd->BulkOutRemained) >= 0)); - - if (atomic_read(&pAd->BulkOutRemained) == 0) - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("Send packet countinuously\n")); - - /* In 28xx, NdisAcquireSpinLock() == spin_lock_bh() */ - /* NdisAcquireSpinLock only need one argument in 28xx. */ - NdisAcquireSpinLock(&pAd->GenericLock); - pAd->ContinBulkOut = TRUE; - NdisReleaseSpinLock(&pAd->GenericLock); - - /* In 28xx, BULK_OUT_LOCK() == spin_lock_irqsave() */ - BULK_OUT_LOCK(&pAd->BulkOutLock[0], IrqFlags);// peter : NdisAcquireSpinLock ==> BULK_OUT_LOCK - pAd->BulkOutPending[0] = FALSE; - BULK_OUT_UNLOCK(&pAd->BulkOutLock[0], IrqFlags);// peter : NdisAcquireSpinLock ==> BULK_OUT_LOCK - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("Send packets depend on counter\n")); - - NdisAcquireSpinLock(&pAd->GenericLock); - pAd->ContinBulkOut = FALSE; - NdisReleaseSpinLock(&pAd->GenericLock); - - BULK_OUT_LOCK(&pAd->BulkOutLock[0], IrqFlags); - pAd->BulkOutPending[0] = FALSE; - BULK_OUT_UNLOCK(&pAd->BulkOutLock[0], IrqFlags); - } - - RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_ATE); - - // Kick bulk out - RTUSBKickBulkOut(pAd); - } -#ifdef RALINK_28xx_QA - else if (!strcmp(arg, "TXSTOP")) //Enter ATE mode and set Tx/Rx Idle - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE: TXSTOP\n")); - - atemode = pAd->ate.Mode; - pAd->ate.Mode &= ATE_TXSTOP; - pAd->ate.bQATxStart = FALSE; -// pAd->ate.TxDoneCount = pAd->ate.TxCount; - -/*=========================================================================*/ - if (atemode & ATE_TXCARR) - { - // No Carrier Test set BBP R22 bit7=0, bit6=0, bit[5~0]=0x0 - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R22, &BbpData); - BbpData &= 0xFFFFFF00; //clear bit7, bit6, bit[5~0] - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); - } - else if (atemode & ATE_TXCARRSUPP) - { - // No Cont. TX set BBP R22 bit7=0 - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R22, &BbpData); - BbpData &= ~(1 << 7); //set bit7=0 - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); - - // No Carrier Suppression set BBP R24 bit0=0 - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R24, &BbpData); - BbpData &= 0xFFFFFFFE; //clear bit0 - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R24, BbpData); - } - else if ((atemode & ATE_TXFRAME) || (atemode == ATE_STOP)) - { - if (atemode & ATE_TXCONT) - { - // No Cont. TX set BBP R22 bit7=0 - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R22, &BbpData); - BbpData &= ~(1 << 7); //set bit7=0 - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); - } - } - -/*=========================================================================*/ - RTUSBRejectPendingPackets(pAd); - RTUSBCleanUpDataBulkOutQueue(pAd); - - /* not used in RT28xx */ - //RTUSBCleanUpMLMEWaitQueue(pAd); - /* empty function so far */ - RTUSBCleanUpMLMEBulkOutQueue(pAd); -/*=========================================================================*/ - // Abort Tx, RX DMA. - RtmpDmaEnable(pAd, 0); -/*=========================================================================*/ - - /* In 28xx, pAd->PendingRx is not of type atomic_t anymore */ -// while ((atomic_read(&pAd->PendingRx) > 0)) //pAd->BulkFlags != 0 wait bulk out finish - /* peter todo : BulkInLock */ - while (pAd->PendingRx > 0) - { -#if 1 - ATE_RTUSBCancelPendingBulkInIRP(pAd); -#else -// NdisInterlockedDecrement(&pAd->PendingRx); - pAd->PendingRx--; -#endif - RTMPusecDelay(500000); - } - - while (((pAd->BulkOutPending[0] == TRUE) || - (pAd->BulkOutPending[1] == TRUE) || - (pAd->BulkOutPending[2] == TRUE) || - (pAd->BulkOutPending[3] == TRUE)) && (pAd->BulkFlags != 0)) //pAd->BulkFlags != 0 wait bulk out finish - { - do - { - RTUSBCancelPendingBulkOutIRP(pAd); - } while (FALSE); - - RTMPusecDelay(500000); - } - - ASSERT(pAd->PendingRx == 0); -/*=========================================================================*/ - // Enable Tx, Rx DMA. - RtmpDmaEnable(pAd, 1); - - /* task Tx status : 0 --> task is idle, 1 --> task is running */ - pAd->ate.TxStatus = 0; - - // Soft reset BBP. - BbpSoftReset(pAd); - - // Disable Tx - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &MacData); - MacData &= (0xfffffffb); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, MacData); - - //Clean ATE Bulk in/out counter and continue setup - InterlockedExchange(&pAd->BulkOutRemained, 0); - - pAd->ContinBulkOut = FALSE; - } - else if (!strcmp(arg, "RXSTOP")) - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE: RXSTOP\n")); - atemode = pAd->ate.Mode; - - // Disable Rx - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value &= ~(1 << 3); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - - pAd->ate.Mode &= ATE_RXSTOP; - pAd->ate.bQARxStart = FALSE; -// pAd->ate.TxDoneCount = pAd->ate.TxCount; - -/*=========================================================================*/ - RTUSBRejectPendingPackets(pAd); - RTUSBCleanUpDataBulkOutQueue(pAd); - - /* not used in RT28xx */ - //RTUSBCleanUpMLMEWaitQueue(pAd); - RTUSBCleanUpMLMEBulkOutQueue(pAd); -/*=========================================================================*/ - - // Abort Tx, RX DMA. - RtmpDmaEnable(pAd, 0); -/*=========================================================================*/ -// while ((atomic_read(&pAd->PendingRx) > 0)) - while (pAd->PendingRx > 0) - { -#if 1 - ATE_RTUSBCancelPendingBulkInIRP(pAd); -#else -// NdisInterlockedDecrement(&pAd->PendingRx); - pAd->PendingRx--; -#endif - RTMPusecDelay(500000); - } - - while (((pAd->BulkOutPending[0] == TRUE) || - (pAd->BulkOutPending[1] == TRUE) || - (pAd->BulkOutPending[2] == TRUE) || - (pAd->BulkOutPending[3] == TRUE)) && (pAd->BulkFlags != 0)) //pAd->BulkFlags != 0 wait bulk out finish - { - do - { - RTUSBCancelPendingBulkOutIRP(pAd); - } while (FALSE); - - RTMPusecDelay(500000); - } - - ASSERT(pAd->PendingRx == 0); -/*=========================================================================*/ - - // Soft reset BBP. - BbpSoftReset(pAd); - pAd->ContinBulkIn = FALSE; - } -#endif // RALINK_28xx_QA // - else if (!strcmp(arg, "RXFRAME")) // Rx Frames - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE: RXFRAME\n")); - - // Disable Rx of MAC block - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value &= ~(1 << 3); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - - // Default value in BBP R22 is 0x0. - BbpData = 0; - - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &MacData); - // Clean bit4 to stop continuous Tx production test. - MacData &= 0xFFFFFFEF; - - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, MacData); - - pAd->ate.Mode |= ATE_RXFRAME; - - // Abort Tx, RX DMA. - RtmpDmaEnable(pAd, 0); - - // Disable TX of MAC block - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value &= ~(1 << 2); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - - // Reset Rx RING. - for ( i = 0; i < (RX_RING_SIZE); i++) - { - PRX_CONTEXT pRxContext = &(pAd->RxContext[i]); - - pRxContext->InUse = FALSE; - pRxContext->IRPPending = FALSE; - pRxContext->Readable = FALSE; - - // - // Get the urb from kernel back to driver. - // - RTUSB_UNLINK_URB(pRxContext->pUrb); - - /* Sleep 200 microsecs to give cancellation time to work. */ - NdisMSleep(200); - pAd->BulkInReq = 0; - -// InterlockedExchange(&pAd->PendingRx, 0); - pAd->PendingRx = 0; - pAd->NextRxBulkInReadIndex = 0; // Next Rx Read index - pAd->NextRxBulkInIndex = RX_RING_SIZE - 1; // Rx Bulk pointer - pAd->NextRxBulkInPosition = 0; - } - - // read to clear counters - RTUSBReadMACRegister(pAd, RX_STA_CNT0, &temp); //RX PHY & RX CRC count - RTUSBReadMACRegister(pAd, RX_STA_CNT1, &temp); //RX PLCP error count & CCA false alarm count - RTUSBReadMACRegister(pAd, RX_STA_CNT2, &temp); //RX FIFO overflow frame count & RX duplicated filtered frame count - - pAd->ContinBulkIn = TRUE; - - // Enable Tx, RX DMA. - RtmpDmaEnable(pAd, 1); - - // Enable RX of MAC block - RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); - Value |= (1 << 3); - RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); - - // Kick bulk in - RTUSBBulkReceive(pAd); - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE: Invalid arg!\n")); - return FALSE; - } - RTMPusecDelay(5000); - - ATEDBGPRINT(RT_DEBUG_TRACE, ("<=== ATECmdHandler()\n")); - - return TRUE; -} -#endif // RT2870 // - -INT Set_ATE_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - if (ATECmdHandler(pAd, arg)) - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_Proc Success\n")); - - - return TRUE; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_Proc Failed\n")); - return FALSE; - } -} - -/* - ========================================================================== - Description: - Set ATE ADDR1=DA for TxFrame(AP : To DS = 0 ; From DS = 1) - or - Set ATE ADDR3=DA for TxFrame(STA : To DS = 1 ; From DS = 0) - - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_ATE_DA_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - CHAR *value; - INT i; - - if(strlen(arg) != 17) //Mac address acceptable format 01:02:03:04:05:06 length 17 - return FALSE; - - for (i=0, value = rstrtok(arg, ":"); value; value = rstrtok(NULL, ":")) - { - if((strlen(value) != 2) || (!isxdigit(*value)) || (!isxdigit(*(value+1))) ) - return FALSE; //Invalid - - -#ifdef CONFIG_STA_SUPPORT - AtoH(value, &pAd->ate.Addr3[i++], 1); -#endif // CONFIG_STA_SUPPORT // - } - - if(i != 6) - return FALSE; //Invalid - - -#ifdef CONFIG_STA_SUPPORT - ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_DA_Proc (DA = %2X:%2X:%2X:%2X:%2X:%2X)\n", pAd->ate.Addr3[0], - pAd->ate.Addr3[1], pAd->ate.Addr3[2], pAd->ate.Addr3[3], pAd->ate.Addr3[4], pAd->ate.Addr3[5])); -#endif // CONFIG_STA_SUPPORT // - - ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_DA_Proc Success\n")); - - return TRUE; -} - -/* - ========================================================================== - Description: - Set ATE ADDR3=SA for TxFrame(AP : To DS = 0 ; From DS = 1) - or - Set ATE ADDR2=SA for TxFrame(STA : To DS = 1 ; From DS = 0) - - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_ATE_SA_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - CHAR *value; - INT i; - - if(strlen(arg) != 17) //Mac address acceptable format 01:02:03:04:05:06 length 17 - return FALSE; - - for (i=0, value = rstrtok(arg, ":"); value; value = rstrtok(NULL, ":")) - { - if((strlen(value) != 2) || (!isxdigit(*value)) || (!isxdigit(*(value+1))) ) - return FALSE; //Invalid - - -#ifdef CONFIG_STA_SUPPORT - AtoH(value, &pAd->ate.Addr2[i++], 1); -#endif // CONFIG_STA_SUPPORT // - } - - if(i != 6) - return FALSE; //Invalid - - -#ifdef CONFIG_STA_SUPPORT - ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_SA_Proc (SA = %2X:%2X:%2X:%2X:%2X:%2X)\n", pAd->ate.Addr2[0], - pAd->ate.Addr2[1], pAd->ate.Addr2[2], pAd->ate.Addr2[3], pAd->ate.Addr2[4], pAd->ate.Addr2[5])); -#endif // CONFIG_STA_SUPPORT // - - ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_SA_Proc Success\n")); - - return TRUE; -} - -/* - ========================================================================== - Description: - Set ATE ADDR2=BSSID for TxFrame(AP : To DS = 0 ; From DS = 1) - or - Set ATE ADDR1=BSSID for TxFrame(STA : To DS = 1 ; From DS = 0) - - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_ATE_BSSID_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - CHAR *value; - INT i; - - if(strlen(arg) != 17) //Mac address acceptable format 01:02:03:04:05:06 length 17 - return FALSE; - - for (i=0, value = rstrtok(arg, ":"); value; value = rstrtok(NULL, ":")) - { - if((strlen(value) != 2) || (!isxdigit(*value)) || (!isxdigit(*(value+1))) ) - return FALSE; //Invalid - - -#ifdef CONFIG_STA_SUPPORT - AtoH(value, &pAd->ate.Addr1[i++], 1); -#endif // CONFIG_STA_SUPPORT // - } - - if(i != 6) - return FALSE; //Invalid - - -#ifdef CONFIG_STA_SUPPORT - ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_BSSID_Proc (BSSID = %2X:%2X:%2X:%2X:%2X:%2X)\n", pAd->ate.Addr1[0], - pAd->ate.Addr1[1], pAd->ate.Addr1[2], pAd->ate.Addr1[3], pAd->ate.Addr1[4], pAd->ate.Addr1[5])); -#endif // CONFIG_STA_SUPPORT // - - ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_BSSID_Proc Success\n")); - - return TRUE; -} - -/* - ========================================================================== - Description: - Set ATE Tx Channel - - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_ATE_CHANNEL_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - UCHAR channel; - - channel = simple_strtol(arg, 0, 10); - - if ((channel < 1) || (channel > 216))// to allow A band channel : ((channel < 1) || (channel > 14)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_CHANNEL_Proc::Out of range, it should be in range of 1~14.\n")); - return FALSE; - } - pAd->ate.Channel = channel; - - ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_CHANNEL_Proc (ATE Channel = %d)\n", pAd->ate.Channel)); - ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_CHANNEL_Proc Success\n")); - - - return TRUE; -} - -/* - ========================================================================== - Description: - Set ATE Tx Power0 - - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_ATE_TX_POWER0_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - CHAR TxPower; - - TxPower = simple_strtol(arg, 0, 10); - - if (pAd->ate.Channel <= 14) - { - if ((TxPower > 31) || (TxPower < 0)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_POWER0_Proc::Out of range (Value=%d)\n", TxPower)); - return FALSE; - } - } - else// 5.5GHz - { - if ((TxPower > 15) || (TxPower < -7)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_POWER0_Proc::Out of range (Value=%d)\n", TxPower)); - return FALSE; - } - } - - pAd->ate.TxPower0 = TxPower; - ATETxPwrHandler(pAd, 0); - ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_POWER0_Proc Success\n")); - - - return TRUE; -} - -/* - ========================================================================== - Description: - Set ATE Tx Power1 - - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_ATE_TX_POWER1_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - CHAR TxPower; - - TxPower = simple_strtol(arg, 0, 10); - - if (pAd->ate.Channel <= 14) - { - if ((TxPower > 31) || (TxPower < 0)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_POWER1_Proc::Out of range (Value=%d)\n", TxPower)); - return FALSE; - } - } - else - { - if ((TxPower > 15) || (TxPower < -7)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_POWER1_Proc::Out of range (Value=%d)\n", TxPower)); - return FALSE; - } - } - - pAd->ate.TxPower1 = TxPower; - ATETxPwrHandler(pAd, 1); - ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_POWER1_Proc Success\n")); - - - return TRUE; -} - -/* - ========================================================================== - Description: - Set ATE Tx Antenna - - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_ATE_TX_Antenna_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - CHAR value; - - value = simple_strtol(arg, 0, 10); - - if ((value > 2) || (value < 0)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_Antenna_Proc::Out of range (Value=%d)\n", value)); - return FALSE; - } - - pAd->ate.TxAntennaSel = value; - - ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_TX_Antenna_Proc (Antenna = %d)\n", pAd->ate.TxAntennaSel)); - ATEDBGPRINT(RT_DEBUG_TRACE,("Ralink: Set_ATE_TX_Antenna_Proc Success\n")); - - - return TRUE; -} - -/* - ========================================================================== - Description: - Set ATE Rx Antenna - - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_ATE_RX_Antenna_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - CHAR value; - - value = simple_strtol(arg, 0, 10); - - if ((value > 3) || (value < 0)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_RX_Antenna_Proc::Out of range (Value=%d)\n", value)); - return FALSE; - } - - pAd->ate.RxAntennaSel = value; - - ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_RX_Antenna_Proc (Antenna = %d)\n", pAd->ate.RxAntennaSel)); - ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_RX_Antenna_Proc Success\n")); - - - return TRUE; -} - -/* - ========================================================================== - Description: - Set ATE RF frequence offset - - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_ATE_TX_FREQOFFSET_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - UCHAR RFFreqOffset; - ULONG R4; - - RFFreqOffset = simple_strtol(arg, 0, 10); -#ifndef RT30xx - if(RFFreqOffset >= 64) -#endif // RT30xx // -#ifdef RT30xx -//2008/08/06: KH modified the limit of offset value from 65 to 95(0x5F) - if(RFFreqOffset >= 95) -#endif // RT30xx // - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_FREQOFFSET_Proc::Out of range, it should be in range of 0~63.\n")); - return FALSE; - } - - pAd->ate.RFFreqOffset = RFFreqOffset; -#ifdef RT30xx - if(IS_RT30xx(pAd)) - { - // Set RF offset - UCHAR RFValue; - RT30xxReadRFRegister(pAd, RF_R23, (PUCHAR)&RFValue); - //2008/08/06: KH modified "pAd->RFFreqOffset" to "pAd->ate.RFFreqOffset" - RFValue = (RFValue & 0x80) | pAd->ate.RFFreqOffset; - RT30xxWriteRFRegister(pAd, RF_R23, (UCHAR)RFValue); - } - else -#endif // RT30xx // - { - - R4 = pAd->ate.RFFreqOffset << 15; // shift TX power control to correct RF register bit position - R4 |= (pAd->LatchRfRegs.R4 & ((~0x001f8000))); - pAd->LatchRfRegs.R4 = R4; - - RtmpRfIoWrite(pAd); - } - ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_TX_FREQOFFSET_Proc (RFFreqOffset = %d)\n", pAd->ate.RFFreqOffset)); - ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_FREQOFFSET_Proc Success\n")); - - - return TRUE; -} - -/* - ========================================================================== - Description: - Set ATE RF BW - - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_ATE_TX_BW_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - int i; - UCHAR value = 0; - UCHAR BBPCurrentBW; - - BBPCurrentBW = simple_strtol(arg, 0, 10); - - if(BBPCurrentBW == 0) - pAd->ate.TxWI.BW = BW_20; - else - pAd->ate.TxWI.BW = BW_40; - - if(pAd->ate.TxWI.BW == BW_20) - { - if(pAd->ate.Channel <= 14) - { - for (i=0; i<5; i++) - { - if (pAd->Tx20MPwrCfgGBand[i] != 0xffffffff) - { - RTMP_IO_WRITE32(pAd, TX_PWR_CFG_0 + i*4, pAd->Tx20MPwrCfgGBand[i]); - RTMPusecDelay(5000); - } - } - } - else - { - for (i=0; i<5; i++) - { - if (pAd->Tx20MPwrCfgABand[i] != 0xffffffff) - { - RTMP_IO_WRITE32(pAd, TX_PWR_CFG_0 + i*4, pAd->Tx20MPwrCfgABand[i]); - RTMPusecDelay(5000); - } - } - } - - //Set BBP R4 bit[4:3]=0:0 - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &value); - value &= (~0x18); - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, value); - - //Set BBP R66=0x3C - value = 0x3C; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, value); - //Set BBP R68=0x0B - //to improve Rx sensitivity. - value = 0x0B; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R68, value); - //Set BBP R69=0x16 - value = 0x16; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, value); - //Set BBP R70=0x08 - value = 0x08; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, value); - //Set BBP R73=0x11 - value = 0x11; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R73, value); - - // If Channel=14, Bandwidth=20M and Mode=CCK, Set BBP R4 bit5=1 - // (Japan filter coefficients) - // This segment of code will only works when ATETXMODE and ATECHANNEL - // were set to MODE_CCK and 14 respectively before ATETXBW is set to 0. - //===================================================================== - if (pAd->ate.Channel == 14) - { - int TxMode = pAd->ate.TxWI.PHYMODE; - if (TxMode == MODE_CCK) - { - // when Channel==14 && Mode==CCK && BandWidth==20M, BBP R4 bit5=1 - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &value); - value |= 0x20; //set bit5=1 - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, value); - } - } - - //===================================================================== - // If bandwidth != 40M, RF Reg4 bit 21 = 0. -#ifdef RT30xx - // Set BW - if(IS_RT30xx(pAd)) - RT30xxWriteRFRegister(pAd, RF_R24, (UCHAR) pAd->Mlme.CaliBW20RfR24); - else -#endif // RT30xx // - { - pAd->LatchRfRegs.R4 &= ~0x00200000; - RtmpRfIoWrite(pAd); - } - - } - else if(pAd->ate.TxWI.BW == BW_40) - { - if(pAd->ate.Channel <= 14) - { - for (i=0; i<5; i++) - { - if (pAd->Tx40MPwrCfgGBand[i] != 0xffffffff) - { - RTMP_IO_WRITE32(pAd, TX_PWR_CFG_0 + i*4, pAd->Tx40MPwrCfgGBand[i]); - RTMPusecDelay(5000); - } - } - } - else - { - for (i=0; i<5; i++) - { - if (pAd->Tx40MPwrCfgABand[i] != 0xffffffff) - { - RTMP_IO_WRITE32(pAd, TX_PWR_CFG_0 + i*4, pAd->Tx40MPwrCfgABand[i]); - RTMPusecDelay(5000); - } - } -#ifdef DOT11_N_SUPPORT - if ((pAd->ate.TxWI.PHYMODE >= MODE_HTMIX) && (pAd->ate.TxWI.MCS == 7)) - { - value = 0x28; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R67, value); - } -#endif // DOT11_N_SUPPORT // - } - - //Set BBP R4 bit[4:3]=1:0 - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &value); - value &= (~0x18); - value |= 0x10; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, value); - - //Set BBP R66=0x3C - value = 0x3C; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, value); - //Set BBP R68=0x0C - //to improve Rx sensitivity. - value = 0x0C; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R68, value); - //Set BBP R69=0x1A - value = 0x1A; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, value); - //Set BBP R70=0x0A - value = 0x0A; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, value); - //Set BBP R73=0x16 - value = 0x16; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R73, value); - - // If bandwidth = 40M, set RF Reg4 bit 21 = 1. -#ifdef RT30xx - // Set BW - if(IS_RT30xx(pAd)) - RT30xxWriteRFRegister(pAd, RF_R24, (UCHAR) pAd->Mlme.CaliBW40RfR24); - else -#endif // RT30xx // - { - pAd->LatchRfRegs.R4 |= 0x00200000; - RtmpRfIoWrite(pAd); - } - } - - ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_TX_BW_Proc (BBPCurrentBW = %d)\n", pAd->ate.TxWI.BW)); - ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_BW_Proc Success\n")); - - - return TRUE; -} - -/* - ========================================================================== - Description: - Set ATE Tx frame length - - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_ATE_TX_LENGTH_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - pAd->ate.TxLength = simple_strtol(arg, 0, 10); - - if((pAd->ate.TxLength < 24) || (pAd->ate.TxLength > (MAX_FRAME_SIZE - 34/* == 2312 */))) - { - pAd->ate.TxLength = (MAX_FRAME_SIZE - 34/* == 2312 */); - ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_LENGTH_Proc::Out of range, it should be in range of 24~%d.\n", (MAX_FRAME_SIZE - 34/* == 2312 */))); - return FALSE; - } - - ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_TX_LENGTH_Proc (TxLength = %d)\n", pAd->ate.TxLength)); - ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_LENGTH_Proc Success\n")); - - - return TRUE; -} - -/* - ========================================================================== - Description: - Set ATE Tx frame count - - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_ATE_TX_COUNT_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - pAd->ate.TxCount = simple_strtol(arg, 0, 10); - - ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_TX_COUNT_Proc (TxCount = %d)\n", pAd->ate.TxCount)); - ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_COUNT_Proc Success\n")); - - - return TRUE; -} - -/* - ========================================================================== - Description: - Set ATE Tx frame MCS - - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_ATE_TX_MCS_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - UCHAR MCS; - int result; - - MCS = simple_strtol(arg, 0, 10); - result = CheckMCSValid(pAd->ate.TxWI.PHYMODE, MCS); - - if (result != -1) - { - pAd->ate.TxWI.MCS = (UCHAR)MCS; - } - else - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_MCS_Proc::Out of range, refer to rate table.\n")); - return FALSE; - } - - ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_TX_MCS_Proc (MCS = %d)\n", pAd->ate.TxWI.MCS)); - ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_MCS_Proc Success\n")); - - - return TRUE; -} - -/* - ========================================================================== - Description: - Set ATE Tx frame Mode - 0: MODE_CCK - 1: MODE_OFDM - 2: MODE_HTMIX - 3: MODE_HTGREENFIELD - - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_ATE_TX_MODE_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - pAd->ate.TxWI.PHYMODE = simple_strtol(arg, 0, 10); - - if(pAd->ate.TxWI.PHYMODE > 3) - { - pAd->ate.TxWI.PHYMODE = 0; - ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_MODE_Proc::Out of range. it should be in range of 0~3\n")); - ATEDBGPRINT(RT_DEBUG_ERROR, ("0: CCK, 1: OFDM, 2: HT_MIX, 3: HT_GREEN_FIELD.\n")); - return FALSE; - } - - ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_TX_MODE_Proc (TxMode = %d)\n", pAd->ate.TxWI.PHYMODE)); - ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_MODE_Proc Success\n")); - - - return TRUE; -} - -/* - ========================================================================== - Description: - Set ATE Tx frame GI - - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_ATE_TX_GI_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - pAd->ate.TxWI.ShortGI = simple_strtol(arg, 0, 10); - - if(pAd->ate.TxWI.ShortGI > 1) - { - pAd->ate.TxWI.ShortGI = 0; - ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_GI_Proc::Out of range\n")); - return FALSE; - } - - ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_TX_GI_Proc (GI = %d)\n", pAd->ate.TxWI.ShortGI)); - ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_GI_Proc Success\n")); - - - return TRUE; -} - -/* - ========================================================================== - Description: - ========================================================================== - */ -INT Set_ATE_RX_FER_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - pAd->ate.bRxFer = simple_strtol(arg, 0, 10); - - if (pAd->ate.bRxFer == 1) - { - pAd->ate.RxCntPerSec = 0; - pAd->ate.RxTotalCnt = 0; - } - - ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_RX_FER_Proc (bRxFer = %d)\n", pAd->ate.bRxFer)); - ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_RX_FER_Proc Success\n")); - - - return TRUE; -} - -INT Set_ATE_Read_RF_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ -#ifdef RT30xx -//2008/07/10:KH add to support RT30xx ATE<-- - if(IS_RT30xx(pAd)) - { - /* modify by WY for Read RF Reg. error */ - UCHAR RFValue; - INT index=0; - for (index = 0; index < 32; index++) - { - RT30xxReadRFRegister(pAd, index, (PUCHAR)&RFValue); - printk("R%d=%d\n",index,RFValue); - } - } - else -//2008/07/10:KH add to support RT30xx ATE--> -#endif // RT30xx // - { - ate_print(KERN_EMERG "R1 = %lx\n", pAd->LatchRfRegs.R1); - ate_print(KERN_EMERG "R2 = %lx\n", pAd->LatchRfRegs.R2); - ate_print(KERN_EMERG "R3 = %lx\n", pAd->LatchRfRegs.R3); - ate_print(KERN_EMERG "R4 = %lx\n", pAd->LatchRfRegs.R4); - } - return TRUE; -} - -INT Set_ATE_Write_RF1_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ -#ifdef RT30xx -//2008/07/10:KH add to support 3070 ATE<-- - if(IS_RT30xx(pAd)) - { - printk("Warning!! RT30xx Don't Support\n"); - return FALSE; - - } - else -//2008/07/10:KH add to support 3070 ATE--> -#endif // RT30xx // - { - UINT32 value = simple_strtol(arg, 0, 16); - - pAd->LatchRfRegs.R1 = value; - RtmpRfIoWrite(pAd); - } - return TRUE; - -} - -INT Set_ATE_Write_RF2_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ -#ifdef RT30xx -//2008/07/10:KH add to support 3070 ATE<-- - if(IS_RT30xx(pAd)) - { - printk("Warning!! RT30xx Don't Support\n"); - return FALSE; - - } - else -//2008/07/10:KH add to support 3070 ATE--> -#endif // RT30xx // - { - UINT32 value = simple_strtol(arg, 0, 16); - - pAd->LatchRfRegs.R2 = value; - RtmpRfIoWrite(pAd); - } - return TRUE; -} - -INT Set_ATE_Write_RF3_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ -#ifdef RT30xx -//2008/07/10:KH add to support 3070 ATE<-- - if(IS_RT30xx(pAd)) - { - printk("Warning!! RT30xx Don't Support\n"); - return FALSE; - - } - else -//2008/07/10:KH add to support 3070 ATE--> -#endif // RT30xx // - { - UINT32 value = simple_strtol(arg, 0, 16); - - pAd->LatchRfRegs.R3 = value; - RtmpRfIoWrite(pAd); - } - return TRUE; -} - -INT Set_ATE_Write_RF4_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ -#ifdef RT30xx -//2008/07/10:KH add to support 3070 ATE<-- - if(IS_RT30xx(pAd)) - { - printk("Warning!! RT30xx Don't Support\n"); - return FALSE; - - } - else -//2008/07/10:KH add to support 3070 ATE--> -#endif // RT30xx // - { - UINT32 value = simple_strtol(arg, 0, 16); - - pAd->LatchRfRegs.R4 = value; - RtmpRfIoWrite(pAd); - } - return TRUE; -} -#ifdef RT30xx -//2008/07/10:KH add to support 3070 ATE<-- -INT SET_ATE_3070RF_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - CHAR *this_char; - CHAR *value; - UINT32 Reg,RFValue; - if(IS_RT30xx(pAd)) - { - printk("SET_ATE_3070RF_Proc=%s\n",arg); - this_char =arg; - if ((value = strchr(this_char, ':')) != NULL) - *value++ = 0; - Reg= simple_strtol(this_char, 0, 16); - RFValue= simple_strtol(value, 0, 16); - printk("RF Reg[%d]=%d\n",Reg,RFValue); - RT30xxWriteRFRegister(pAd, Reg,RFValue); - } - else - printk("Warning!! Only 3070 Support\n"); - return TRUE; -} -//2008/07/10:KH add to support 3070 ATE--> -#endif // RT30xx // -/* - ========================================================================== - Description: - Load and Write EEPROM from a binary file prepared in advance. - - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -#ifndef UCOS -INT Set_ATE_Load_E2P_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - BOOLEAN ret = FALSE; - PUCHAR src = EEPROM_BIN_FILE_NAME; - struct file *srcf; - INT32 retval, orgfsuid, orgfsgid; - mm_segment_t orgfs; - USHORT WriteEEPROM[(EEPROM_SIZE/2)]; - UINT32 FileLength = 0; - UINT32 value = simple_strtol(arg, 0, 10); - - ATEDBGPRINT(RT_DEBUG_ERROR, ("===> %s (value=%d)\n\n", __FUNCTION__, value)); - - if (value > 0) - { - /* zero the e2p buffer */ - NdisZeroMemory((PUCHAR)WriteEEPROM, EEPROM_SIZE); - - /* save uid and gid used for filesystem access. - ** set user and group to 0 (root) - */ - orgfsuid = current->fsuid; - orgfsgid = current->fsgid; - /* as root */ - current->fsuid = current->fsgid = 0; - orgfs = get_fs(); - set_fs(KERNEL_DS); - - do - { - /* open the bin file */ - srcf = filp_open(src, O_RDONLY, 0); - - if (IS_ERR(srcf)) - { - ate_print("%s - Error %ld opening %s\n", __FUNCTION__, -PTR_ERR(srcf), src); - break; - } - - /* the object must have a read method */ - if ((srcf->f_op == NULL) || (srcf->f_op->read == NULL)) - { - ate_print("%s - %s does not have a read method\n", __FUNCTION__, src); - break; - } - - /* read the firmware from the file *.bin */ - FileLength = srcf->f_op->read(srcf, - (PUCHAR)WriteEEPROM, - EEPROM_SIZE, - &srcf->f_pos); - - if (FileLength != EEPROM_SIZE) - { - ate_print("%s: error file length (=%d) in e2p.bin\n", - __FUNCTION__, FileLength); - break; - } - else - { - /* write the content of .bin file to EEPROM */ - rt_ee_write_all(pAd, WriteEEPROM); - ret = TRUE; - } - break; - } while(TRUE); - - /* close firmware file */ - if (IS_ERR(srcf)) - { - ; - } - else - { - retval = filp_close(srcf, NULL); - if (retval) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("--> Error %d closing %s\n", -retval, src)); - - } - } - - /* restore */ - set_fs(orgfs); - current->fsuid = orgfsuid; - current->fsgid = orgfsgid; - } - ATEDBGPRINT(RT_DEBUG_ERROR, ("<=== %s (ret=%d)\n", __FUNCTION__, ret)); - - return ret; - -} -#else -INT Set_ATE_Load_E2P_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - USHORT WriteEEPROM[(EEPROM_SIZE/2)]; - struct iwreq *wrq = (struct iwreq *)arg; - - ATEDBGPRINT(RT_DEBUG_TRACE, ("===> %s (wrq->u.data.length = %d)\n\n", __FUNCTION__, wrq->u.data.length)); - - if (wrq->u.data.length != EEPROM_SIZE) - { - ate_print("%s: error length (=%d) from host\n", - __FUNCTION__, wrq->u.data.length); - return FALSE; - } - else/* (wrq->u.data.length == EEPROM_SIZE) */ - { - /* zero the e2p buffer */ - NdisZeroMemory((PUCHAR)WriteEEPROM, EEPROM_SIZE); - - /* fill the local buffer */ - NdisMoveMemory((PUCHAR)WriteEEPROM, wrq->u.data.pointer, wrq->u.data.length); - - do - { - /* write the content of .bin file to EEPROM */ - rt_ee_write_all(pAd, WriteEEPROM); - - } while(FALSE); - } - - ATEDBGPRINT(RT_DEBUG_TRACE, ("<=== %s\n", __FUNCTION__)); - - return TRUE; - -} -#endif // !UCOS // - -INT Set_ATE_Read_E2P_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - USHORT buffer[EEPROM_SIZE/2]; - USHORT *p; - int i; - - rt_ee_read_all(pAd, (USHORT *)buffer); - p = buffer; - for (i = 0; i < (EEPROM_SIZE/2); i++) - { - ate_print("%4.4x ", *p); - if (((i+1) % 16) == 0) - ate_print("\n"); - p++; - } - return TRUE; -} - -INT Set_ATE_Show_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ate_print("Mode=%d\n", pAd->ate.Mode); - ate_print("TxPower0=%d\n", pAd->ate.TxPower0); - ate_print("TxPower1=%d\n", pAd->ate.TxPower1); - ate_print("TxAntennaSel=%d\n", pAd->ate.TxAntennaSel); - ate_print("RxAntennaSel=%d\n", pAd->ate.RxAntennaSel); - ate_print("BBPCurrentBW=%d\n", pAd->ate.TxWI.BW); - ate_print("GI=%d\n", pAd->ate.TxWI.ShortGI); - ate_print("MCS=%d\n", pAd->ate.TxWI.MCS); - ate_print("TxMode=%d\n", pAd->ate.TxWI.PHYMODE); - ate_print("Addr1=%02x:%02x:%02x:%02x:%02x:%02x\n", - pAd->ate.Addr1[0], pAd->ate.Addr1[1], pAd->ate.Addr1[2], pAd->ate.Addr1[3], pAd->ate.Addr1[4], pAd->ate.Addr1[5]); - ate_print("Addr2=%02x:%02x:%02x:%02x:%02x:%02x\n", - pAd->ate.Addr2[0], pAd->ate.Addr2[1], pAd->ate.Addr2[2], pAd->ate.Addr2[3], pAd->ate.Addr2[4], pAd->ate.Addr2[5]); - ate_print("Addr3=%02x:%02x:%02x:%02x:%02x:%02x\n", - pAd->ate.Addr3[0], pAd->ate.Addr3[1], pAd->ate.Addr3[2], pAd->ate.Addr3[3], pAd->ate.Addr3[4], pAd->ate.Addr3[5]); - ate_print("Channel=%d\n", pAd->ate.Channel); - ate_print("TxLength=%d\n", pAd->ate.TxLength); - ate_print("TxCount=%u\n", pAd->ate.TxCount); - ate_print("RFFreqOffset=%d\n", pAd->ate.RFFreqOffset); - ate_print(KERN_EMERG "Set_ATE_Show_Proc Success\n"); - return TRUE; -} - -INT Set_ATE_Help_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ate_print("ATE=ATESTART, ATESTOP, TXCONT, TXCARR, TXFRAME, RXFRAME\n"); - ate_print("ATEDA\n"); - ate_print("ATESA\n"); - ate_print("ATEBSSID\n"); - ate_print("ATECHANNEL, range:0~14(unless A band !)\n"); - ate_print("ATETXPOW0, set power level of antenna 1.\n"); - ate_print("ATETXPOW1, set power level of antenna 2.\n"); - ate_print("ATETXANT, set TX antenna. 0:all, 1:antenna one, 2:antenna two.\n"); - ate_print("ATERXANT, set RX antenna.0:all, 1:antenna one, 2:antenna two, 3:antenna three.\n"); - ate_print("ATETXFREQOFFSET, set frequency offset, range 0~63\n"); - ate_print("ATETXBW, set BandWidth, 0:20MHz, 1:40MHz.\n"); - ate_print("ATETXLEN, set Frame length, range 24~%d\n", (MAX_FRAME_SIZE - 34/* == 2312 */)); - ate_print("ATETXCNT, set how many frame going to transmit.\n"); - ate_print("ATETXMCS, set MCS, reference to rate table.\n"); - ate_print("ATETXMODE, set Mode 0:CCK, 1:OFDM, 2:HT-Mix, 3:GreenField, reference to rate table.\n"); - ate_print("ATETXGI, set GI interval, 0:Long, 1:Short\n"); - ate_print("ATERXFER, 0:disable Rx Frame error rate. 1:enable Rx Frame error rate.\n"); - ate_print("ATERRF, show all RF registers.\n"); - ate_print("ATEWRF1, set RF1 register.\n"); - ate_print("ATEWRF2, set RF2 register.\n"); - ate_print("ATEWRF3, set RF3 register.\n"); - ate_print("ATEWRF4, set RF4 register.\n"); - ate_print("ATELDE2P, load EEPROM from .bin file.\n"); - ate_print("ATERE2P, display all EEPROM content.\n"); - ate_print("ATESHOW, display all parameters of ATE.\n"); - ate_print("ATEHELP, online help.\n"); - - return TRUE; -} - -/* - ========================================================================== - Description: - - AsicSwitchChannel() dedicated for ATE. - - ========================================================================== -*/ -VOID ATEAsicSwitchChannel( - IN PRTMP_ADAPTER pAd) -{ - UINT32 R2 = 0, R3 = DEFAULT_RF_TX_POWER, R4 = 0, Value = 0; - CHAR TxPwer = 0, TxPwer2 = 0; - UCHAR index, BbpValue = 0, R66 = 0x30; - RTMP_RF_REGS *RFRegTable; - UCHAR Channel; - -#ifdef RALINK_28xx_QA - if ((pAd->ate.bQATxStart == TRUE) || (pAd->ate.bQARxStart == TRUE)) - { - if (pAd->ate.Channel != pAd->LatchRfRegs.Channel) - { - pAd->ate.Channel = pAd->LatchRfRegs.Channel; - } - return; - } - else -#endif // RALINK_28xx_QA // - Channel = pAd->ate.Channel; - - // Select antenna - AsicAntennaSelect(pAd, Channel); - - // fill Tx power value - TxPwer = pAd->ate.TxPower0; - TxPwer2 = pAd->ate.TxPower1; -#ifdef RT30xx -//2008/07/10:KH add to support 3070 ATE<-- - - // The RF programming sequence is difference between 3xxx and 2xxx - // The 3070 is 1T1R. Therefore, we don't need to set the number of Tx/Rx path and the only job is to set the parameters of channels. - if (IS_RT30xx(pAd) && ((pAd->RfIcType == RFIC_3020) || -(pAd->RfIcType == RFIC_3021) || (pAd->RfIcType == RFIC_3022) || -(pAd->RfIcType == RFIC_2020))) - { - /* modify by WY for Read RF Reg. error */ - UCHAR RFValue; - - for (index = 0; index < NUM_OF_3020_CHNL; index++) - { - if (Channel == FreqItems3020[index].Channel) - { - // Programming channel parameters - RT30xxWriteRFRegister(pAd, RF_R02, FreqItems3020[index].N); - RT30xxWriteRFRegister(pAd, RF_R03, FreqItems3020[index].K); - - RT30xxReadRFRegister(pAd, RF_R06, (PUCHAR)&RFValue); - RFValue = (RFValue & 0xFC) | FreqItems3020[index].R; - RT30xxWriteRFRegister(pAd, RF_R06, (UCHAR)RFValue); - - // Set Tx Power - RT30xxReadRFRegister(pAd, RF_R12, (PUCHAR)&RFValue); - RFValue = (RFValue & 0xE0) | TxPwer; - RT30xxWriteRFRegister(pAd, RF_R12, (UCHAR)RFValue); - - // Set RF offset - RT30xxReadRFRegister(pAd, RF_R23, (PUCHAR)&RFValue); - //2008/08/06: KH modified "pAd->RFFreqOffset" to "pAd->ate.RFFreqOffset" - RFValue = (RFValue & 0x80) | pAd->ate.RFFreqOffset; - RT30xxWriteRFRegister(pAd, RF_R23, (UCHAR)RFValue); - - // Set BW - if (pAd->ate.TxWI.BW == BW_40) - { - RFValue = pAd->Mlme.CaliBW40RfR24; - //DISABLE_11N_CHECK(pAd); - } - else - { - RFValue = pAd->Mlme.CaliBW20RfR24; - } - RT30xxWriteRFRegister(pAd, RF_R24, (UCHAR)RFValue); - - // Enable RF tuning - RT30xxReadRFRegister(pAd, RF_R07, (PUCHAR)&RFValue); - RFValue = RFValue | 0x1; - RT30xxWriteRFRegister(pAd, RF_R07, (UCHAR)RFValue); - - // latch channel for future usage. - pAd->LatchRfRegs.Channel = Channel; - - break; - } - } - - DBGPRINT(RT_DEBUG_TRACE, ("SwitchChannel#%d(RF=%d, Pwr0=%d, Pwr1=%d, %dT), N=0x%02X, K=0x%02X, R=0x%02X\n", - Channel, - pAd->RfIcType, - TxPwer, - TxPwer2, - pAd->Antenna.field.TxPath, - FreqItems3020[index].N, - FreqItems3020[index].K, - FreqItems3020[index].R)); - } - else -//2008/07/10:KH add to support 3070 ATE--> -#endif // RT30xx // -{ - RFRegTable = RF2850RegTable; - - switch (pAd->RfIcType) - { - /* But only 2850 and 2750 support 5.5GHz band... */ - case RFIC_2820: - case RFIC_2850: - case RFIC_2720: - case RFIC_2750: - - for (index = 0; index < NUM_OF_2850_CHNL; index++) - { - if (Channel == RFRegTable[index].Channel) - { - R2 = RFRegTable[index].R2; - if (pAd->Antenna.field.TxPath == 1) - { - R2 |= 0x4000; // If TXpath is 1, bit 14 = 1; - } - - if (pAd->Antenna.field.RxPath == 2) - { - switch (pAd->ate.RxAntennaSel) - { - case 1: - R2 |= 0x20040; - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BbpValue); - BbpValue &= 0xE4; - BbpValue |= 0x00; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BbpValue); - break; - case 2: - R2 |= 0x10040; - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BbpValue); - BbpValue &= 0xE4; - BbpValue |= 0x01; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BbpValue); - break; - default: - R2 |= 0x40; - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BbpValue); - BbpValue &= 0xE4; - /* Only enable two Antenna to receive. */ - BbpValue |= 0x08; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BbpValue); - break; - } - } - else if (pAd->Antenna.field.RxPath == 1) - { - R2 |= 0x20040; // write 1 to off RxPath - } - - if (pAd->Antenna.field.TxPath == 2) - { - if (pAd->ate.TxAntennaSel == 1) - { - R2 |= 0x4000; // If TX Antenna select is 1 , bit 14 = 1; Disable Ant 2 - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R1, &BbpValue); - BbpValue &= 0xE7; //11100111B - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R1, BbpValue); - } - else if (pAd->ate.TxAntennaSel == 2) - { - R2 |= 0x8000; // If TX Antenna select is 2 , bit 15 = 1; Disable Ant 1 - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R1, &BbpValue); - BbpValue &= 0xE7; - BbpValue |= 0x08; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R1, BbpValue); - } - else - { - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R1, &BbpValue); - BbpValue &= 0xE7; - BbpValue |= 0x10; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R1, BbpValue); - } - } - if (pAd->Antenna.field.RxPath == 3) - { - switch (pAd->ate.RxAntennaSel) - { - case 1: - R2 |= 0x20040; - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BbpValue); - BbpValue &= 0xE4; - BbpValue |= 0x00; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BbpValue); - break; - case 2: - R2 |= 0x10040; - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BbpValue); - BbpValue &= 0xE4; - BbpValue |= 0x01; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BbpValue); - break; - case 3: - R2 |= 0x30000; - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BbpValue); - BbpValue &= 0xE4; - BbpValue |= 0x02; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BbpValue); - break; - default: - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BbpValue); - BbpValue &= 0xE4; - BbpValue |= 0x10; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BbpValue); - break; - } - } - - if (Channel > 14) - { - // initialize R3, R4 - R3 = (RFRegTable[index].R3 & 0xffffc1ff); - R4 = (RFRegTable[index].R4 & (~0x001f87c0)) | (pAd->ate.RFFreqOffset << 15); - - // According the Rory's suggestion to solve the middle range issue. - // 5.5G band power range: 0xF9~0X0F, TX0 Reg3 bit9/TX1 Reg4 bit6="0" means the TX power reduce 7dB - // R3 - if ((TxPwer >= -7) && (TxPwer < 0)) - { - TxPwer = (7+TxPwer); - TxPwer = (TxPwer > 0xF) ? (0xF) : (TxPwer); - R3 |= (TxPwer << 10); - ATEDBGPRINT(RT_DEBUG_TRACE, ("ATEAsicSwitchChannel: TxPwer=%d \n", TxPwer)); - } - else - { - TxPwer = (TxPwer > 0xF) ? (0xF) : (TxPwer); - R3 |= (TxPwer << 10) | (1 << 9); - } - - // R4 - if ((TxPwer2 >= -7) && (TxPwer2 < 0)) - { - TxPwer2 = (7+TxPwer2); - TxPwer2 = (TxPwer2 > 0xF) ? (0xF) : (TxPwer2); - R4 |= (TxPwer2 << 7); - ATEDBGPRINT(RT_DEBUG_TRACE, ("ATEAsicSwitchChannel: TxPwer2=%d \n", TxPwer2)); - } - else - { - TxPwer2 = (TxPwer2 > 0xF) ? (0xF) : (TxPwer2); - R4 |= (TxPwer2 << 7) | (1 << 6); - } - } - else - { - R3 = (RFRegTable[index].R3 & 0xffffc1ff) | (TxPwer << 9); // set TX power0 - R4 = (RFRegTable[index].R4 & (~0x001f87c0)) | (pAd->ate.RFFreqOffset << 15) | (TxPwer2 <<6);// Set freq offset & TxPwr1 - } - - // Based on BBP current mode before changing RF channel. - if (pAd->ate.TxWI.BW == BW_40) - { - R4 |=0x200000; - } - - // Update variables - pAd->LatchRfRegs.Channel = Channel; - pAd->LatchRfRegs.R1 = RFRegTable[index].R1; - pAd->LatchRfRegs.R2 = R2; - pAd->LatchRfRegs.R3 = R3; - pAd->LatchRfRegs.R4 = R4; - - RtmpRfIoWrite(pAd); - - break; - } - } - break; - - default: - break; - } -} - // Change BBP setting during switch from a->g, g->a - if (Channel <= 14) - { - ULONG TxPinCfg = 0x00050F0A;// 2007.10.09 by Brian : 0x0005050A ==> 0x00050F0A - - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R62, (0x37 - GET_LNA_GAIN(pAd))); - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R63, (0x37 - GET_LNA_GAIN(pAd))); - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R64, (0x37 - GET_LNA_GAIN(pAd))); - - /* For 1T/2R chip only... */ - if (pAd->NicConfig2.field.ExternalLNAForG) - { - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R82, 0x62); - } - else - { - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R82, 0x84); - } - - // According the Rory's suggestion to solve the middle range issue. - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R86, &BbpValue); - ASSERT((BbpValue == 0x00)); - if ((BbpValue != 0x00)) - { - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R86, 0x00); - } - - // 5.5GHz band selection PIN, bit1 and bit2 are complement - RTMP_IO_READ32(pAd, TX_BAND_CFG, &Value); - Value &= (~0x6); - Value |= (0x04); - RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Value); - - // Turn off unused PA or LNA when only 1T or 1R. - if (pAd->Antenna.field.TxPath == 1) - { - TxPinCfg &= 0xFFFFFFF3; - } - if (pAd->Antenna.field.RxPath == 1) - { - TxPinCfg &= 0xFFFFF3FF; - } - - RTMP_IO_WRITE32(pAd, TX_PIN_CFG, TxPinCfg); - } - else - { - ULONG TxPinCfg = 0x00050F05;//2007.10.09 by Brian : 0x00050505 ==> 0x00050F05 - - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R62, (0x37 - GET_LNA_GAIN(pAd))); - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R63, (0x37 - GET_LNA_GAIN(pAd))); - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R64, (0x37 - GET_LNA_GAIN(pAd))); - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R82, 0xF2); - - // According the Rory's suggestion to solve the middle range issue. - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R86, &BbpValue); - ASSERT((BbpValue == 0x00)); - if ((BbpValue != 0x00)) - { - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R86, 0x00); - } - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R91, &BbpValue); - ASSERT((BbpValue == 0x04)); - - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R92, &BbpValue); - ASSERT((BbpValue == 0x00)); - - // 5.5GHz band selection PIN, bit1 and bit2 are complement - RTMP_IO_READ32(pAd, TX_BAND_CFG, &Value); - Value &= (~0x6); - Value |= (0x02); - RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Value); - - // Turn off unused PA or LNA when only 1T or 1R. - if (pAd->Antenna.field.TxPath == 1) - { - TxPinCfg &= 0xFFFFFFF3; - } - if (pAd->Antenna.field.RxPath == 1) - { - TxPinCfg &= 0xFFFFF3FF; - } - - RTMP_IO_WRITE32(pAd, TX_PIN_CFG, TxPinCfg); - } - - // R66 should be set according to Channel and use 20MHz when scanning - if (Channel <= 14) - { - // BG band - R66 = 0x2E + GET_LNA_GAIN(pAd); - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); - } - else - { - // 5.5 GHz band - if (pAd->ate.TxWI.BW == BW_20) - { - R66 = (UCHAR)(0x32 + (GET_LNA_GAIN(pAd)*5)/3); - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); - } - else - { - R66 = (UCHAR)(0x3A + (GET_LNA_GAIN(pAd)*5)/3); - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); - } - } - - // - // On 11A, We should delay and wait RF/BBP to be stable - // and the appropriate time should be 1000 micro seconds - // 2005/06/05 - On 11G, We also need this delay time. Otherwise it's difficult to pass the WHQL. - // - RTMPusecDelay(1000); - - if (Channel > 14) - { - // When 5.5GHz band the LSB of TxPwr will be used to reduced 7dB or not. - ATEDBGPRINT(RT_DEBUG_TRACE, ("SwitchChannel#%d(RF=%d, %dT) to , R1=0x%08lx, R2=0x%08lx, R3=0x%08lx, R4=0x%08lx\n", - Channel, - pAd->RfIcType, - pAd->Antenna.field.TxPath, - pAd->LatchRfRegs.R1, - pAd->LatchRfRegs.R2, - pAd->LatchRfRegs.R3, - pAd->LatchRfRegs.R4)); - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("SwitchChannel#%d(RF=%d, Pwr0=%u, Pwr1=%u, %dT) to , R1=0x%08lx, R2=0x%08lx, R3=0x%08lx, R4=0x%08lx\n", - Channel, - pAd->RfIcType, - (R3 & 0x00003e00) >> 9, - (R4 & 0x000007c0) >> 6, - pAd->Antenna.field.TxPath, - pAd->LatchRfRegs.R1, - pAd->LatchRfRegs.R2, - pAd->LatchRfRegs.R3, - pAd->LatchRfRegs.R4)); - } -} - -// -// In fact, no one will call this routine so far ! -// -/* - ========================================================================== - Description: - Gives CCK TX rate 2 more dB TX power. - This routine works only in ATE mode. - - calculate desired Tx power in RF R3.Tx0~5, should consider - - 0. if current radio is a noisy environment (pAd->DrsCounters.fNoisyEnvironment) - 1. TxPowerPercentage - 2. auto calibration based on TSSI feedback - 3. extra 2 db for CCK - 4. -10 db upon very-short distance (AvgRSSI >= -40db) to AP - - NOTE: Since this routine requires the value of (pAd->DrsCounters.fNoisyEnvironment), - it should be called AFTER MlmeDynamicTxRateSwitching() - ========================================================================== - */ -VOID ATEAsicAdjustTxPower( - IN PRTMP_ADAPTER pAd) -{ - INT i, j; - CHAR DeltaPwr = 0; - BOOLEAN bAutoTxAgc = FALSE; - UCHAR TssiRef, *pTssiMinusBoundary, *pTssiPlusBoundary, TxAgcStep; - UCHAR BbpR49 = 0, idx; - PCHAR pTxAgcCompensate; - ULONG TxPwr[5]; - CHAR Value; - - /* no one calls this procedure so far */ - if (pAd->ate.TxWI.BW == BW_40) - { - if (pAd->ate.Channel > 14) - { - TxPwr[0] = pAd->Tx40MPwrCfgABand[0]; - TxPwr[1] = pAd->Tx40MPwrCfgABand[1]; - TxPwr[2] = pAd->Tx40MPwrCfgABand[2]; - TxPwr[3] = pAd->Tx40MPwrCfgABand[3]; - TxPwr[4] = pAd->Tx40MPwrCfgABand[4]; - } - else - { - TxPwr[0] = pAd->Tx40MPwrCfgGBand[0]; - TxPwr[1] = pAd->Tx40MPwrCfgGBand[1]; - TxPwr[2] = pAd->Tx40MPwrCfgGBand[2]; - TxPwr[3] = pAd->Tx40MPwrCfgGBand[3]; - TxPwr[4] = pAd->Tx40MPwrCfgGBand[4]; - } - } - else - { - if (pAd->ate.Channel > 14) - { - TxPwr[0] = pAd->Tx20MPwrCfgABand[0]; - TxPwr[1] = pAd->Tx20MPwrCfgABand[1]; - TxPwr[2] = pAd->Tx20MPwrCfgABand[2]; - TxPwr[3] = pAd->Tx20MPwrCfgABand[3]; - TxPwr[4] = pAd->Tx20MPwrCfgABand[4]; - } - else - { - TxPwr[0] = pAd->Tx20MPwrCfgGBand[0]; - TxPwr[1] = pAd->Tx20MPwrCfgGBand[1]; - TxPwr[2] = pAd->Tx20MPwrCfgGBand[2]; - TxPwr[3] = pAd->Tx20MPwrCfgGBand[3]; - TxPwr[4] = pAd->Tx20MPwrCfgGBand[4]; - } - } - - // TX power compensation for temperature variation based on TSSI. - // Do it per 4 seconds. - if (pAd->Mlme.OneSecPeriodicRound % 4 == 0) - { - if (pAd->ate.Channel <= 14) - { - /* bg channel */ - bAutoTxAgc = pAd->bAutoTxAgcG; - TssiRef = pAd->TssiRefG; - pTssiMinusBoundary = &pAd->TssiMinusBoundaryG[0]; - pTssiPlusBoundary = &pAd->TssiPlusBoundaryG[0]; - TxAgcStep = pAd->TxAgcStepG; - pTxAgcCompensate = &pAd->TxAgcCompensateG; - } - else - { - /* a channel */ - bAutoTxAgc = pAd->bAutoTxAgcA; - TssiRef = pAd->TssiRefA; - pTssiMinusBoundary = &pAd->TssiMinusBoundaryA[0]; - pTssiPlusBoundary = &pAd->TssiPlusBoundaryA[0]; - TxAgcStep = pAd->TxAgcStepA; - pTxAgcCompensate = &pAd->TxAgcCompensateA; - } - - if (bAutoTxAgc) - { - /* BbpR49 is unsigned char */ - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R49, &BbpR49); - - /* (p) TssiPlusBoundaryG[0] = 0 = (m) TssiMinusBoundaryG[0] */ - /* compensate: +4 +3 +2 +1 0 -1 -2 -3 -4 * steps */ - /* step value is defined in pAd->TxAgcStepG for tx power value */ - - /* [4]+1+[4] p4 p3 p2 p1 o1 m1 m2 m3 m4 */ - /* ex: 0x00 0x15 0x25 0x45 0x88 0xA0 0xB5 0xD0 0xF0 - above value are examined in mass factory production */ - /* [4] [3] [2] [1] [0] [1] [2] [3] [4] */ - - /* plus is 0x10 ~ 0x40, minus is 0x60 ~ 0x90 */ - /* if value is between p1 ~ o1 or o1 ~ s1, no need to adjust tx power */ - /* if value is 0x65, tx power will be -= TxAgcStep*(2-1) */ - - if (BbpR49 > pTssiMinusBoundary[1]) - { - // Reading is larger than the reference value. - // Check for how large we need to decrease the Tx power. - for (idx = 1; idx < 5; idx++) - { - if (BbpR49 <= pTssiMinusBoundary[idx]) // Found the range - break; - } - // The index is the step we should decrease, idx = 0 means there is nothing to compensate -// if (R3 > (ULONG) (TxAgcStep * (idx-1))) - *pTxAgcCompensate = -(TxAgcStep * (idx-1)); -// else -// *pTxAgcCompensate = -((UCHAR)R3); - - DeltaPwr += (*pTxAgcCompensate); - ATEDBGPRINT(RT_DEBUG_TRACE, ("-- Tx Power, BBP R1=%x, TssiRef=%x, TxAgcStep=%x, step = -%d\n", - BbpR49, TssiRef, TxAgcStep, idx-1)); - } - else if (BbpR49 < pTssiPlusBoundary[1]) - { - // Reading is smaller than the reference value - // check for how large we need to increase the Tx power - for (idx = 1; idx < 5; idx++) - { - if (BbpR49 >= pTssiPlusBoundary[idx]) // Found the range - break; - } - // The index is the step we should increase, idx = 0 means there is nothing to compensate - *pTxAgcCompensate = TxAgcStep * (idx-1); - DeltaPwr += (*pTxAgcCompensate); - ATEDBGPRINT(RT_DEBUG_TRACE, ("++ Tx Power, BBP R1=%x, TssiRef=%x, TxAgcStep=%x, step = +%d\n", - BbpR49, TssiRef, TxAgcStep, idx-1)); - } - else - { - *pTxAgcCompensate = 0; - ATEDBGPRINT(RT_DEBUG_TRACE, (" Tx Power, BBP R1=%x, TssiRef=%x, TxAgcStep=%x, step = +%d\n", - BbpR49, TssiRef, TxAgcStep, 0)); - } - } - } - else - { - if (pAd->ate.Channel <= 14) - { - bAutoTxAgc = pAd->bAutoTxAgcG; - pTxAgcCompensate = &pAd->TxAgcCompensateG; - } - else - { - bAutoTxAgc = pAd->bAutoTxAgcA; - pTxAgcCompensate = &pAd->TxAgcCompensateA; - } - - if (bAutoTxAgc) - DeltaPwr += (*pTxAgcCompensate); - } - - /* calculate delta power based on the percentage specified from UI */ - // E2PROM setting is calibrated for maximum TX power (i.e. 100%) - // We lower TX power here according to the percentage specified from UI - if (pAd->CommonCfg.TxPowerPercentage == 0xffffffff) // AUTO TX POWER control - ; - else if (pAd->CommonCfg.TxPowerPercentage > 90) // 91 ~ 100% & AUTO, treat as 100% in terms of mW - ; - else if (pAd->CommonCfg.TxPowerPercentage > 60) // 61 ~ 90%, treat as 75% in terms of mW - { - DeltaPwr -= 1; - } - else if (pAd->CommonCfg.TxPowerPercentage > 30) // 31 ~ 60%, treat as 50% in terms of mW - { - DeltaPwr -= 3; - } - else if (pAd->CommonCfg.TxPowerPercentage > 15) // 16 ~ 30%, treat as 25% in terms of mW - { - DeltaPwr -= 6; - } - else if (pAd->CommonCfg.TxPowerPercentage > 9) // 10 ~ 15%, treat as 12.5% in terms of mW - { - DeltaPwr -= 9; - } - else // 0 ~ 9 %, treat as MIN(~3%) in terms of mW - { - DeltaPwr -= 12; - } - - /* reset different new tx power for different TX rate */ - for(i=0; i<5; i++) - { - if (TxPwr[i] != 0xffffffff) - { - for (j=0; j<8; j++) - { - Value = (CHAR)((TxPwr[i] >> j*4) & 0x0F); /* 0 ~ 15 */ - - if ((Value + DeltaPwr) < 0) - { - Value = 0; /* min */ - } - else if ((Value + DeltaPwr) > 0xF) - { - Value = 0xF; /* max */ - } - else - { - Value += DeltaPwr; /* temperature compensation */ - } - - /* fill new value to CSR offset */ - TxPwr[i] = (TxPwr[i] & ~(0x0000000F << j*4)) | (Value << j*4); - } - - /* write tx power value to CSR */ - /* TX_PWR_CFG_0 (8 tx rate) for TX power for OFDM 12M/18M - TX power for OFDM 6M/9M - TX power for CCK5.5M/11M - TX power for CCK1M/2M */ - /* TX_PWR_CFG_1 ~ TX_PWR_CFG_4 */ - RTMP_IO_WRITE32(pAd, TX_PWR_CFG_0 + i*4, TxPwr[i]); - - - } - } - -} - -/* - ======================================================================== - Routine Description: - Write TxWI for ATE mode. - - Return Value: - None - ======================================================================== -*/ - -#ifdef RT2870 -static VOID ATEWriteTxWI( - IN PRTMP_ADAPTER pAd, - IN PTXWI_STRUC pTxWI, - IN BOOLEAN FRAG, - IN BOOLEAN InsTimestamp, - IN BOOLEAN AMPDU, - IN BOOLEAN Ack, - IN BOOLEAN NSeq, // HW new a sequence. - IN UCHAR BASize, - IN UCHAR WCID, - IN ULONG Length, - IN UCHAR PID, - IN UCHAR MIMOps, - IN UCHAR Txopmode, - IN BOOLEAN CfAck, - IN HTTRANSMIT_SETTING Transmit) -{ - // - // Always use Long preamble before verifiation short preamble functionality works well. - // Todo: remove the following line if short preamble functionality works - // - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED); - pTxWI->FRAG= FRAG; - pTxWI->TS= InsTimestamp; - pTxWI->AMPDU = AMPDU; - - pTxWI->MIMOps = PWR_ACTIVE; - pTxWI->MpduDensity = 4; - pTxWI->ACK = Ack; - pTxWI->txop = Txopmode; - pTxWI->NSEQ = NSeq; - pTxWI->BAWinSize = BASize; - - pTxWI->WirelessCliID = WCID; - pTxWI->MPDUtotalByteCount = Length; - pTxWI->PacketId = PID; - - pTxWI->BW = Transmit.field.BW; - pTxWI->ShortGI = Transmit.field.ShortGI; - pTxWI->STBC= Transmit.field.STBC; - - pTxWI->MCS = Transmit.field.MCS; - pTxWI->PHYMODE= Transmit.field.MODE; - -#ifdef DOT11_N_SUPPORT - // - // MMPS is 802.11n features. Because TxWI->MCS > 7 must be HT mode, - // so need not check if it's HT rate. - // - if ((MIMOps == MMPS_STATIC) && (pTxWI->MCS > 7)) - pTxWI->MCS = 7; - - if ((MIMOps == MMPS_DYNAMIC) && (pTxWI->MCS > 7)) // SMPS protect 2 spatial. - pTxWI->MIMOps = 1; -#endif // DOT11_N_SUPPORT // - - pTxWI->CFACK = CfAck; - - return; -} -#endif // RT2870 // -/* - ======================================================================== - - Routine Description: - Disable protection for ATE. - ======================================================================== -*/ -VOID ATEDisableAsicProtect( - IN PRTMP_ADAPTER pAd) -{ - PROT_CFG_STRUC ProtCfg, ProtCfg4; - UINT32 Protect[6]; - USHORT offset; - UCHAR i; - UINT32 MacReg = 0; - - // Config ASIC RTS threshold register - RTMP_IO_READ32(pAd, TX_RTS_CFG, &MacReg); - MacReg &= 0xFF0000FF; - MacReg |= (pAd->CommonCfg.RtsThreshold << 8); - RTMP_IO_WRITE32(pAd, TX_RTS_CFG, MacReg); - - // Initial common protection settings - RTMPZeroMemory(Protect, sizeof(Protect)); - ProtCfg4.word = 0; - ProtCfg.word = 0; - ProtCfg.field.TxopAllowGF40 = 1; - ProtCfg.field.TxopAllowGF20 = 1; - ProtCfg.field.TxopAllowMM40 = 1; - ProtCfg.field.TxopAllowMM20 = 1; - ProtCfg.field.TxopAllowOfdm = 1; - ProtCfg.field.TxopAllowCck = 1; - ProtCfg.field.RTSThEn = 1; - ProtCfg.field.ProtectNav = ASIC_SHORTNAV; - - // Handle legacy(B/G) protection - ProtCfg.field.ProtectRate = pAd->CommonCfg.RtsRate; - ProtCfg.field.ProtectCtrl = 0; - Protect[0] = ProtCfg.word; - Protect[1] = ProtCfg.word; - - // NO PROTECT - // 1.All STAs in the BSS are 20/40 MHz HT - // 2. in ai 20/40MHz BSS - // 3. all STAs are 20MHz in a 20MHz BSS - // Pure HT. no protection. - - // MM20_PROT_CFG - // Reserved (31:27) - // PROT_TXOP(25:20) -- 010111 - // PROT_NAV(19:18) -- 01 (Short NAV protection) - // PROT_CTRL(17:16) -- 00 (None) - // PROT_RATE(15:0) -- 0x4004 (OFDM 24M) - Protect[2] = 0x01744004; - - // MM40_PROT_CFG - // Reserved (31:27) - // PROT_TXOP(25:20) -- 111111 - // PROT_NAV(19:18) -- 01 (Short NAV protection) - // PROT_CTRL(17:16) -- 00 (None) - // PROT_RATE(15:0) -- 0x4084 (duplicate OFDM 24M) - Protect[3] = 0x03f44084; - - // CF20_PROT_CFG - // Reserved (31:27) - // PROT_TXOP(25:20) -- 010111 - // PROT_NAV(19:18) -- 01 (Short NAV protection) - // PROT_CTRL(17:16) -- 00 (None) - // PROT_RATE(15:0) -- 0x4004 (OFDM 24M) - Protect[4] = 0x01744004; - - // CF40_PROT_CFG - // Reserved (31:27) - // PROT_TXOP(25:20) -- 111111 - // PROT_NAV(19:18) -- 01 (Short NAV protection) - // PROT_CTRL(17:16) -- 00 (None) - // PROT_RATE(15:0) -- 0x4084 (duplicate OFDM 24M) - Protect[5] = 0x03f44084; - - pAd->CommonCfg.IOTestParm.bRTSLongProtOn = FALSE; - - offset = CCK_PROT_CFG; - for (i = 0;i < 6;i++) - RTMP_IO_WRITE32(pAd, offset + i*4, Protect[i]); - -} - -#ifdef RT2870 -/* - ======================================================================== - Routine Description: - Write TxInfo for ATE mode. - - Return Value: - None - ======================================================================== -*/ -static VOID ATEWriteTxInfo( - IN PRTMP_ADAPTER pAd, - IN PTXINFO_STRUC pTxInfo, - IN USHORT USBDMApktLen, - IN BOOLEAN bWiv, - IN UCHAR QueueSel, - IN UCHAR NextValid, - IN UCHAR TxBurst) -{ - pTxInfo->USBDMATxPktLen = USBDMApktLen; - pTxInfo->QSEL = QueueSel; - - if (QueueSel != FIFO_EDCA) - ATEDBGPRINT(RT_DEBUG_TRACE, ("=======> QueueSel != FIFO_EDCA<=======\n")); - - pTxInfo->USBDMANextVLD = NextValid; - pTxInfo->USBDMATxburst = TxBurst; - pTxInfo->WIV = bWiv; - pTxInfo->SwUseLastRound = 0; - pTxInfo->rsv = 0; - pTxInfo->rsv2 = 0; - - return; -} -#endif // RT2870 // - -/* There are two ways to convert Rssi */ -#if 1 -// -// The way used with GET_LNA_GAIN(). -// -CHAR ATEConvertToRssi( - IN PRTMP_ADAPTER pAd, - IN CHAR Rssi, - IN UCHAR RssiNumber) -{ - UCHAR RssiOffset, LNAGain; - - // Rssi equals to zero should be an invalid value - if (Rssi == 0) - return -99; - - LNAGain = GET_LNA_GAIN(pAd); - if (pAd->LatchRfRegs.Channel > 14) - { - if (RssiNumber == 0) - RssiOffset = pAd->ARssiOffset0; - else if (RssiNumber == 1) - RssiOffset = pAd->ARssiOffset1; - else - RssiOffset = pAd->ARssiOffset2; - } - else - { - if (RssiNumber == 0) - RssiOffset = pAd->BGRssiOffset0; - else if (RssiNumber == 1) - RssiOffset = pAd->BGRssiOffset1; - else - RssiOffset = pAd->BGRssiOffset2; - } - - return (-12 - RssiOffset - LNAGain - Rssi); -} -#else -// -// The way originally used in ATE of rt2860ap. -// -CHAR ATEConvertToRssi( - IN PRTMP_ADAPTER pAd, - IN CHAR Rssi, - IN UCHAR RssiNumber) -{ - UCHAR RssiOffset, LNAGain; - - // Rssi equals to zero should be an invalid value - if (Rssi == 0) - return -99; - - if (pAd->LatchRfRegs.Channel > 14) - { - LNAGain = pAd->ALNAGain; - if (RssiNumber == 0) - RssiOffset = pAd->ARssiOffset0; - else if (RssiNumber == 1) - RssiOffset = pAd->ARssiOffset1; - else - RssiOffset = pAd->ARssiOffset2; - } - else - { - LNAGain = pAd->BLNAGain; - if (RssiNumber == 0) - RssiOffset = pAd->BGRssiOffset0; - else if (RssiNumber == 1) - RssiOffset = pAd->BGRssiOffset1; - else - RssiOffset = pAd->BGRssiOffset2; - } - - return (-32 - RssiOffset + LNAGain - Rssi); -} -#endif /* end of #if 1 */ - -/* - ======================================================================== - - Routine Description: - Set Japan filter coefficients if needed. - Note: - This routine should only be called when - entering TXFRAME mode or TXCONT mode. - - ======================================================================== -*/ -static VOID SetJapanFilter( - IN PRTMP_ADAPTER pAd) -{ - UCHAR BbpData = 0; - - // - // If Channel=14 and Bandwidth=20M and Mode=CCK, set BBP R4 bit5=1 - // (Japan Tx filter coefficients)when (TXFRAME or TXCONT). - // - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BbpData); - - if ((pAd->ate.TxWI.PHYMODE == MODE_CCK) && (pAd->ate.Channel == 14) && (pAd->ate.TxWI.BW == BW_20)) - { - BbpData |= 0x20; // turn on - ATEDBGPRINT(RT_DEBUG_TRACE, ("SetJapanFilter!!!\n")); - } - else - { - BbpData &= 0xdf; // turn off - ATEDBGPRINT(RT_DEBUG_TRACE, ("ClearJapanFilter!!!\n")); - } - - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BbpData); -} - -VOID ATESampleRssi( - IN PRTMP_ADAPTER pAd, - IN PRXWI_STRUC pRxWI) -{ - /* There are two ways to collect RSSI. */ -#if 1 - //pAd->LastRxRate = (USHORT)((pRxWI->MCS) + (pRxWI->BW <<7) + (pRxWI->ShortGI <<8)+ (pRxWI->PHYMODE <<14)) ; - if (pRxWI->RSSI0 != 0) - { - pAd->ate.LastRssi0 = ATEConvertToRssi(pAd, (CHAR) pRxWI->RSSI0, RSSI_0); - pAd->ate.AvgRssi0X8 = (pAd->ate.AvgRssi0X8 - pAd->ate.AvgRssi0) + pAd->ate.LastRssi0; - pAd->ate.AvgRssi0 = pAd->ate.AvgRssi0X8 >> 3; - } - if (pRxWI->RSSI1 != 0) - { - pAd->ate.LastRssi1 = ATEConvertToRssi(pAd, (CHAR) pRxWI->RSSI1, RSSI_1); - pAd->ate.AvgRssi1X8 = (pAd->ate.AvgRssi1X8 - pAd->ate.AvgRssi1) + pAd->ate.LastRssi1; - pAd->ate.AvgRssi1 = pAd->ate.AvgRssi1X8 >> 3; - } - if (pRxWI->RSSI2 != 0) - { - pAd->ate.LastRssi2 = ATEConvertToRssi(pAd, (CHAR) pRxWI->RSSI2, RSSI_2); - pAd->ate.AvgRssi2X8 = (pAd->ate.AvgRssi2X8 - pAd->ate.AvgRssi2) + pAd->ate.LastRssi2; - pAd->ate.AvgRssi2 = pAd->ate.AvgRssi2X8 >> 3; - } - - pAd->ate.LastSNR0 = (CHAR)(pRxWI->SNR0);// CHAR ==> UCHAR ? - pAd->ate.LastSNR1 = (CHAR)(pRxWI->SNR1);// CHAR ==> UCHAR ? - - pAd->ate.NumOfAvgRssiSample ++; -#else - pAd->ate.LastSNR0 = (CHAR)(pRxWI->SNR0); - pAd->ate.LastSNR1 = (CHAR)(pRxWI->SNR1); - pAd->ate.RxCntPerSec++; - pAd->ate.LastRssi0 = ATEConvertToRssi(pAd, (CHAR) pRxWI->RSSI0, RSSI_0); - pAd->ate.LastRssi1 = ATEConvertToRssi(pAd, (CHAR) pRxWI->RSSI1, RSSI_1); - pAd->ate.LastRssi2 = ATEConvertToRssi(pAd, (CHAR) pRxWI->RSSI2, RSSI_2); - pAd->ate.AvgRssi0X8 = (pAd->ate.AvgRssi0X8 - pAd->ate.AvgRssi0) + pAd->ate.LastRssi0; - pAd->ate.AvgRssi0 = pAd->ate.AvgRssi0X8 >> 3; - pAd->ate.AvgRssi1X8 = (pAd->ate.AvgRssi1X8 - pAd->ate.AvgRssi1) + pAd->ate.LastRssi1; - pAd->ate.AvgRssi1 = pAd->ate.AvgRssi1X8 >> 3; - pAd->ate.AvgRssi2X8 = (pAd->ate.AvgRssi2X8 - pAd->ate.AvgRssi2) + pAd->ate.LastRssi2; - pAd->ate.AvgRssi2 = pAd->ate.AvgRssi2X8 >> 3; - pAd->ate.NumOfAvgRssiSample ++; -#endif -} - -#ifdef CONFIG_STA_SUPPORT -VOID RTMPStationStop( - IN PRTMP_ADAPTER pAd) -{ -// BOOLEAN Cancelled; - - ATEDBGPRINT(RT_DEBUG_TRACE, ("==> RTMPStationStop\n")); - - // For rx statistics, we need to keep this timer running. -// RTMPCancelTimer(&pAd->Mlme.PeriodicTimer, &Cancelled); - - ATEDBGPRINT(RT_DEBUG_TRACE, ("<== RTMPStationStop\n")); -} - -VOID RTMPStationStart( - IN PRTMP_ADAPTER pAd) -{ - ATEDBGPRINT(RT_DEBUG_TRACE, ("==> RTMPStationStart\n")); - ATEDBGPRINT(RT_DEBUG_TRACE, ("<== RTMPStationStart\n")); -} -#endif // CONFIG_STA_SUPPORT // - -/* - ========================================================================== - Description: - Setup Frame format. - NOTE: - This routine should only be used in ATE mode. - ========================================================================== - */ - -#ifdef RT2870 -/*======================Start of RT2870======================*/ -/* */ -/* */ -static INT ATESetUpFrame( - IN PRTMP_ADAPTER pAd, - IN UINT32 TxIdx) -{ - UINT j; - PTX_CONTEXT pNullContext; - PUCHAR pDest; - HTTRANSMIT_SETTING TxHTPhyMode; - PTXWI_STRUC pTxWI; - PTXINFO_STRUC pTxInfo; - UINT32 TransferBufferLength, OrgBufferLength = 0; - UCHAR padLen = 0; -#ifdef RALINK_28xx_QA - PHEADER_802_11 pHeader80211 = NULL; -#endif // RALINK_28xx_QA // - - if ((RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS)) || - (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET)) || - (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) || - (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))) - { - return -1; - } - - /* We always use QID_AC_BE and FIFO_EDCA in ATE mode. */ - - pNullContext = &(pAd->NullContext); - ASSERT(pNullContext != NULL); - - if (pNullContext->InUse == FALSE) - { - // Set the in use bit - pNullContext->InUse = TRUE; - NdisZeroMemory(&(pAd->NullFrame), sizeof(HEADER_802_11)); - - // Fill 802.11 header. -#ifdef RALINK_28xx_QA - if (pAd->ate.bQATxStart == TRUE) - { - pHeader80211 = NdisMoveMemory(&(pAd->NullFrame), pAd->ate.Header, pAd->ate.HLen); -// pDest = NdisMoveMemory(&(pAd->NullFrame), pAd->ate.Header, pAd->ate.HLen); -// pHeader80211 = (PHEADER_802_11)pDest; - } - else -#endif // RALINK_28xx_QA // - { - // Fill 802.11 header. - NdisMoveMemory(&(pAd->NullFrame), TemplateFrame, sizeof(HEADER_802_11)); - } -#ifdef RT_BIG_ENDIAN - RTMPFrameEndianChange(pAd, (PUCHAR)&(pAd->NullFrame), DIR_READ, FALSE); -#endif // RT_BIG_ENDIAN // - -#ifdef RALINK_28xx_QA - if (pAd->ate.bQATxStart == TRUE) - { - /* modify sequence number.... */ - if (pAd->ate.TxDoneCount == 0) - { - pAd->ate.seq = pHeader80211->Sequence; - } - else - { - pHeader80211->Sequence = ++pAd->ate.seq; - } - /* We already got all the addr. fields from QA GUI. */ - } - else -#endif // RALINK_28xx_QA // - { - COPY_MAC_ADDR(pAd->NullFrame.Addr1, pAd->ate.Addr1); - COPY_MAC_ADDR(pAd->NullFrame.Addr2, pAd->ate.Addr2); - COPY_MAC_ADDR(pAd->NullFrame.Addr3, pAd->ate.Addr3); - } - - RTMPZeroMemory(&pAd->NullContext.TransferBuffer->field.WirelessPacket[0], TX_BUFFER_NORMSIZE);//??? - pTxInfo = (PTXINFO_STRUC)&pAd->NullContext.TransferBuffer->field.WirelessPacket[0]; - -#ifdef RALINK_28xx_QA - if (pAd->ate.bQATxStart == TRUE) - { - // Avoid to exceed the range of WirelessPacket[]. - ASSERT(pAd->ate.TxInfo.USBDMATxPktLen <= (MAX_FRAME_SIZE - 34/* == 2312 */)); - NdisMoveMemory(pTxInfo, &(pAd->ate.TxInfo), sizeof(pAd->ate.TxInfo)); - } - else -#endif // RALINK_28xx_QA // - { - // Avoid to exceed the range of WirelessPacket[]. - ASSERT(pAd->ate.TxLength <= (MAX_FRAME_SIZE - 34/* == 2312 */)); - - // pTxInfo->USBDMATxPktLen will be updated to include padding later. - ATEWriteTxInfo(pAd, pTxInfo, (USHORT)(TXWI_SIZE + pAd->ate.TxLength), TRUE, EpToQueue[MGMTPIPEIDX], FALSE, FALSE); - pTxInfo->QSEL = FIFO_EDCA; - } - - pTxWI = (PTXWI_STRUC)&pAd->NullContext.TransferBuffer->field.WirelessPacket[TXINFO_SIZE]; - - // Fill TxWI. - if (pAd->ate.bQATxStart == TRUE) - { - TxHTPhyMode.field.BW = pAd->ate.TxWI.BW; - TxHTPhyMode.field.ShortGI = pAd->ate.TxWI.ShortGI; - TxHTPhyMode.field.STBC = pAd->ate.TxWI.STBC; - TxHTPhyMode.field.MCS = pAd->ate.TxWI.MCS; - TxHTPhyMode.field.MODE = pAd->ate.TxWI.PHYMODE; - ATEWriteTxWI(pAd, pTxWI, pAd->ate.TxWI.FRAG, pAd->ate.TxWI.TS, pAd->ate.TxWI.AMPDU, pAd->ate.TxWI.ACK, pAd->ate.TxWI.NSEQ, - pAd->ate.TxWI.BAWinSize, BSSID_WCID, pAd->ate.TxWI.MPDUtotalByteCount/* include 802.11 header */, pAd->ate.TxWI.PacketId, 0, pAd->ate.TxWI.txop/*IFS_HTTXOP*/, pAd->ate.TxWI.CFACK/*FALSE*/, TxHTPhyMode); - } - else - { - TxHTPhyMode.field.BW = pAd->ate.TxWI.BW; - TxHTPhyMode.field.ShortGI = pAd->ate.TxWI.ShortGI; - TxHTPhyMode.field.STBC = 0; - TxHTPhyMode.field.MCS = pAd->ate.TxWI.MCS; - TxHTPhyMode.field.MODE = pAd->ate.TxWI.PHYMODE; - - ATEWriteTxWI(pAd, pTxWI, FALSE, FALSE, FALSE, FALSE/* No ack required. */, FALSE, 0, BSSID_WCID, pAd->ate.TxLength, - 0, 0, IFS_HTTXOP, FALSE, TxHTPhyMode);// "MMPS_STATIC" instead of "MMPS_DYNAMIC" ??? - } - - RTMPMoveMemory(&pAd->NullContext.TransferBuffer->field.WirelessPacket[TXINFO_SIZE+TXWI_SIZE], &pAd->NullFrame, sizeof(HEADER_802_11)); - - pDest = &(pAd->NullContext.TransferBuffer->field.WirelessPacket[TXINFO_SIZE+TXWI_SIZE+sizeof(HEADER_802_11)]); - - // Prepare frame payload -#ifdef RALINK_28xx_QA - if (pAd->ate.bQATxStart == TRUE) - { - // copy pattern - if ((pAd->ate.PLen != 0)) - { - for (j = 0; j < pAd->ate.DLen; j+=pAd->ate.PLen) - { - RTMPMoveMemory(pDest, pAd->ate.Pattern, pAd->ate.PLen); - pDest += pAd->ate.PLen; - } - } - TransferBufferLength = TXINFO_SIZE + TXWI_SIZE + pAd->ate.TxWI.MPDUtotalByteCount; - } - else -#endif // RALINK_28xx_QA // - { - for (j = 0; j < (pAd->ate.TxLength - sizeof(HEADER_802_11)); j++) - { - *pDest = 0xA5; - pDest += 1; - } - TransferBufferLength = TXINFO_SIZE + TXWI_SIZE + pAd->ate.TxLength; - } - -#if 1 - OrgBufferLength = TransferBufferLength; - TransferBufferLength = (TransferBufferLength + 3) & (~3); - - // Always add 4 extra bytes at every packet. - padLen = TransferBufferLength - OrgBufferLength + 4;/* 4 == last packet padding */ - ASSERT((padLen <= (RTMP_PKT_TAIL_PADDING - 4/* 4 == MaxBulkOutsize alignment padding */))); - - /* Now memzero all extra padding bytes. */ - NdisZeroMemory(pDest, padLen); - pDest += padLen; -#else - if ((TransferBufferLength % 4) == 1) - { - NdisZeroMemory(pDest, 7); - pDest += 7; - TransferBufferLength += 3; - } - else if ((TransferBufferLength % 4) == 2) - { - NdisZeroMemory(pDest, 6); - pDest += 6; - TransferBufferLength += 2; - } - else if ((TransferBufferLength % 4) == 3) - { - NdisZeroMemory(pDest, 5); - pDest += 5; - TransferBufferLength += 1; - } -#endif // 1 // - - // Update pTxInfo->USBDMATxPktLen to include padding. - pTxInfo->USBDMATxPktLen = TransferBufferLength - TXINFO_SIZE; - - TransferBufferLength += 4; - - // If TransferBufferLength is multiple of 64, add extra 4 bytes again. - if ((TransferBufferLength % pAd->BulkOutMaxPacketSize) == 0) - { - NdisZeroMemory(pDest, 4); - TransferBufferLength += 4; - } - - // Fill out frame length information for global Bulk out arbitor - pAd->NullContext.BulkOutSize = TransferBufferLength; - } -#ifdef RT_BIG_ENDIAN - RTMPWIEndianChange((PUCHAR)pTxWI, TYPE_TXWI); - RTMPFrameEndianChange(pAd, (((PUCHAR)pTxInfo)+TXWI_SIZE+TXINFO_SIZE), DIR_WRITE, FALSE); - RTMPDescriptorEndianChange((PUCHAR)pTxInfo, TYPE_TXINFO); -#endif // RT_BIG_ENDIAN // - return 0; -} - -VOID ATE_RTUSBBulkOutDataPacketComplete(purbb_t pUrb, struct pt_regs *pt_regs) -{ - PRTMP_ADAPTER pAd; - PTX_CONTEXT pNullContext; - UCHAR BulkOutPipeId; - NTSTATUS Status; - unsigned long IrqFlags; - ULONG OldValue; - - pNullContext = (PTX_CONTEXT)pUrb->context; - pAd = pNullContext->pAd; - - - // Reset Null frame context flags - pNullContext->IRPPending = FALSE; - pNullContext->InUse = FALSE; - Status = pUrb->status; - - // Store BulkOut PipeId - BulkOutPipeId = pNullContext->BulkOutPipeId; - pAd->BulkOutDataOneSecCount++; - - if (Status == USB_ST_NOERROR) - { -#ifdef RALINK_28xx_QA - if ((ATE_ON(pAd)) && (pAd->ate.bQATxStart == TRUE)) - { - if (pAd->ate.QID == BulkOutPipeId) - { - // Let Rx can have a chance to break in during Tx process, - // especially for loopback mode in QA ATE. - // To trade off between tx performance and loopback mode integrity. - /* Q : Now Rx is handled by tasklet, do we still need this delay ? */ - /* Ans : Even tasklet is used, Rx/Tx < 1 if we do not delay for a while right here. */ - RTMPusecDelay(500); - pAd->ate.TxDoneCount++; - pAd->RalinkCounters.KickTxCount++; - ASSERT(pAd->ate.QID == 0); - pAd->ate.TxAc0++; - } - } -#endif // RALINK_28xx_QA // - pAd->BulkOutComplete++; - - pAd->Counters8023.GoodTransmits++; - - /* Don't worry about the queue is empty or not. This function will check itself. */ - RTMPDeQueuePacket(pAd, TRUE, BulkOutPipeId, MAX_TX_PROCESS); - - /* In 28xx, SendTxWaitQueue ==> TxSwQueue */ -/* - if (pAd->SendTxWaitQueue[BulkOutPipeId].Number > 0) - { - RTMPDeQueuePacket(pAd, BulkOutPipeId); - } -*/ - } - else // STATUS_OTHER - { - pAd->BulkOutCompleteOther++; - - ATEDBGPRINT(RT_DEBUG_ERROR, ("BulkOutDataPacket Failed STATUS_OTHER = 0x%x . \n", Status)); - ATEDBGPRINT(RT_DEBUG_ERROR, (">>BulkOutReq=0x%lx, BulkOutComplete=0x%lx\n", pAd->BulkOutReq, pAd->BulkOutComplete)); - - if ((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS)) && - (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) && - (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) && - (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET))) - { - RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET); - /* In 28xx, RT_OID_USB_RESET_BULK_OUT ==> CMDTHREAD_RESET_BULK_OUT */ - RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_OUT, NULL, 0); - // Check - BULK_OUT_LOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); - pAd->BulkOutPending[BulkOutPipeId] = FALSE; - pAd->bulkResetPipeid = BulkOutPipeId; - BULK_OUT_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); - return; - } - } - - - - if (atomic_read(&pAd->BulkOutRemained) > 0) - { - atomic_dec(&pAd->BulkOutRemained); - } - - // 1st - Transmit Success - OldValue = pAd->WlanCounters.TransmittedFragmentCount.u.LowPart; - pAd->WlanCounters.TransmittedFragmentCount.u.LowPart++; - - if (pAd->WlanCounters.TransmittedFragmentCount.u.LowPart < OldValue) - { - pAd->WlanCounters.TransmittedFragmentCount.u.HighPart++; - } - - if(((pAd->ContinBulkOut == TRUE ) ||(atomic_read(&pAd->BulkOutRemained) > 0)) && (pAd->ate.Mode & ATE_TXFRAME)) - { - RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_ATE); - } - else - { - RTUSB_CLEAR_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_ATE); -#ifdef RALINK_28xx_QA - pAd->ate.TxStatus = 0; -#endif // RALINK_28xx_QA // - } - - BULK_OUT_LOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); - pAd->BulkOutPending[BulkOutPipeId] = FALSE; - BULK_OUT_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); - - // Always call Bulk routine, even reset bulk. - // The protection of rest bulk should be in BulkOut routine. - RTUSBKickBulkOut(pAd); -} - -/* - ======================================================================== - - Routine Description: - - Arguments: - - Return Value: - - Note: - - ======================================================================== -*/ -VOID ATE_RTUSBBulkOutDataPacket( - IN PRTMP_ADAPTER pAd, - IN UCHAR BulkOutPipeId) -{ - PTX_CONTEXT pNullContext = &(pAd->NullContext); - PURB pUrb; - int ret = 0; - unsigned long IrqFlags; - - - ASSERT(BulkOutPipeId == 0); - - /* Build up the frame first. */ -// ATESetUpFrame(pAd, 0); - - BULK_OUT_LOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); - - if (pAd->BulkOutPending[BulkOutPipeId] == TRUE) - { - BULK_OUT_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); - return; - } - - pAd->BulkOutPending[BulkOutPipeId] = TRUE; - BULK_OUT_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); - - // Increase Total transmit byte counter - pAd->RalinkCounters.OneSecTransmittedByteCount += pNullContext->BulkOutSize; - pAd->RalinkCounters.TransmittedByteCount += pNullContext->BulkOutSize; - - // Clear ATE frame bulk out flag - RTUSB_CLEAR_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_ATE); - - // Init Tx context descriptor - pNullContext->IRPPending = TRUE; - RTUSBInitTxDesc(pAd, pNullContext, BulkOutPipeId, (usb_complete_t)ATE_RTUSBBulkOutDataPacketComplete); - pUrb = pNullContext->pUrb; - - if((ret = RTUSB_SUBMIT_URB(pUrb))!=0) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("ATE_RTUSBBulkOutDataPacket: Submit Tx URB failed %d\n", ret)); - return; - } - - pAd->BulkOutReq++; - return; - -} - -/* - ======================================================================== - - Routine Description: - - Arguments: - - Return Value: - - Note: - - ======================================================================== -*/ -VOID ATE_RTUSBCancelPendingBulkInIRP( - IN PRTMP_ADAPTER pAd) -{ - PRX_CONTEXT pRxContext; - UINT i; - - ATEDBGPRINT(RT_DEBUG_TRACE, ("--->ATE_RTUSBCancelPendingBulkInIRP\n")); -#if 1 - for ( i = 0; i < (RX_RING_SIZE); i++) - { - pRxContext = &(pAd->RxContext[i]); - if(pRxContext->IRPPending == TRUE) - { - RTUSB_UNLINK_URB(pRxContext->pUrb); - pRxContext->IRPPending = FALSE; - pRxContext->InUse = FALSE; - //NdisInterlockedDecrement(&pAd->PendingRx); - //pAd->PendingRx--; - } - } -#else - for ( i = 0; i < (RX_RING_SIZE); i++) - { - pRxContext = &(pAd->RxContext[i]); - if(atomic_read(&pRxContext->IrpLock) == IRPLOCK_CANCELABLE) - { - RTUSB_UNLINK_URB(pRxContext->pUrb); - } - InterlockedExchange(&pRxContext->IrpLock, IRPLOCK_CANCE_START); - } -#endif // 1 // - ATEDBGPRINT(RT_DEBUG_TRACE, ("<---ATE_RTUSBCancelPendingBulkInIRP\n")); - return; -} -#endif // RT2870 // - -VOID rt_ee_read_all(PRTMP_ADAPTER pAd, USHORT *Data) -{ - USHORT i; - USHORT value; - - for (i = 0 ; i < EEPROM_SIZE/2 ; ) - { - /* "value" is expecially for some compilers... */ - RT28xx_EEPROM_READ16(pAd, i*2, value); - Data[i] = value; - i++; - } -} - -VOID rt_ee_write_all(PRTMP_ADAPTER pAd, USHORT *Data) -{ - USHORT i; - USHORT value; - - for (i = 0 ; i < EEPROM_SIZE/2 ; ) - { - /* "value" is expecially for some compilers... */ - value = Data[i]; - RT28xx_EEPROM_WRITE16(pAd, i*2, value); - i ++; - } -} -#ifdef RALINK_28xx_QA -VOID ATE_QA_Statistics( - IN PRTMP_ADAPTER pAd, - IN PRXWI_STRUC pRxWI, - IN PRT28XX_RXD_STRUC pRxD, - IN PHEADER_802_11 pHeader) -{ - // update counter first - if (pHeader != NULL) - { - if (pHeader->FC.Type == BTYPE_DATA) - { - if (pRxD->U2M) - pAd->ate.U2M++; - else - pAd->ate.OtherData++; - } - else if (pHeader->FC.Type == BTYPE_MGMT) - { - if (pHeader->FC.SubType == SUBTYPE_BEACON) - pAd->ate.Beacon++; - else - pAd->ate.OtherCount++; - } - else if (pHeader->FC.Type == BTYPE_CNTL) - { - pAd->ate.OtherCount++; - } - } - pAd->ate.RSSI0 = pRxWI->RSSI0; - pAd->ate.RSSI1 = pRxWI->RSSI1; - pAd->ate.RSSI2 = pRxWI->RSSI2; - pAd->ate.SNR0 = pRxWI->SNR0; - pAd->ate.SNR1 = pRxWI->SNR1; -} - -/* command id with Cmd Type == 0x0008(for 28xx)/0x0005(for iNIC) */ -#define RACFG_CMD_RF_WRITE_ALL 0x0000 -#define RACFG_CMD_E2PROM_READ16 0x0001 -#define RACFG_CMD_E2PROM_WRITE16 0x0002 -#define RACFG_CMD_E2PROM_READ_ALL 0x0003 -#define RACFG_CMD_E2PROM_WRITE_ALL 0x0004 -#define RACFG_CMD_IO_READ 0x0005 -#define RACFG_CMD_IO_WRITE 0x0006 -#define RACFG_CMD_IO_READ_BULK 0x0007 -#define RACFG_CMD_BBP_READ8 0x0008 -#define RACFG_CMD_BBP_WRITE8 0x0009 -#define RACFG_CMD_BBP_READ_ALL 0x000a -#define RACFG_CMD_GET_COUNTER 0x000b -#define RACFG_CMD_CLEAR_COUNTER 0x000c - -#define RACFG_CMD_RSV1 0x000d -#define RACFG_CMD_RSV2 0x000e -#define RACFG_CMD_RSV3 0x000f - -#define RACFG_CMD_TX_START 0x0010 -#define RACFG_CMD_GET_TX_STATUS 0x0011 -#define RACFG_CMD_TX_STOP 0x0012 -#define RACFG_CMD_RX_START 0x0013 -#define RACFG_CMD_RX_STOP 0x0014 -#define RACFG_CMD_GET_NOISE_LEVEL 0x0015 - -#define RACFG_CMD_ATE_START 0x0080 -#define RACFG_CMD_ATE_STOP 0x0081 - -#define RACFG_CMD_ATE_START_TX_CARRIER 0x0100 -#define RACFG_CMD_ATE_START_TX_CONT 0x0101 -#define RACFG_CMD_ATE_START_TX_FRAME 0x0102 -#define RACFG_CMD_ATE_SET_BW 0x0103 -#define RACFG_CMD_ATE_SET_TX_POWER0 0x0104 -#define RACFG_CMD_ATE_SET_TX_POWER1 0x0105 -#define RACFG_CMD_ATE_SET_FREQ_OFFSET 0x0106 -#define RACFG_CMD_ATE_GET_STATISTICS 0x0107 -#define RACFG_CMD_ATE_RESET_COUNTER 0x0108 -#define RACFG_CMD_ATE_SEL_TX_ANTENNA 0x0109 -#define RACFG_CMD_ATE_SEL_RX_ANTENNA 0x010a -#define RACFG_CMD_ATE_SET_PREAMBLE 0x010b -#define RACFG_CMD_ATE_SET_CHANNEL 0x010c -#define RACFG_CMD_ATE_SET_ADDR1 0x010d -#define RACFG_CMD_ATE_SET_ADDR2 0x010e -#define RACFG_CMD_ATE_SET_ADDR3 0x010f -#define RACFG_CMD_ATE_SET_RATE 0x0110 -#define RACFG_CMD_ATE_SET_TX_FRAME_LEN 0x0111 -#define RACFG_CMD_ATE_SET_TX_FRAME_COUNT 0x0112 -#define RACFG_CMD_ATE_START_RX_FRAME 0x0113 -#define RACFG_CMD_ATE_E2PROM_READ_BULK 0x0114 -#define RACFG_CMD_ATE_E2PROM_WRITE_BULK 0x0115 -#define RACFG_CMD_ATE_IO_WRITE_BULK 0x0116 -#define RACFG_CMD_ATE_BBP_READ_BULK 0x0117 -#define RACFG_CMD_ATE_BBP_WRITE_BULK 0x0118 -#define RACFG_CMD_ATE_RF_READ_BULK 0x0119 -#define RACFG_CMD_ATE_RF_WRITE_BULK 0x011a - - - -#define A2Hex(_X, _p) \ -{ \ - UCHAR *p; \ - _X = 0; \ - p = _p; \ - while (((*p >= 'a') && (*p <= 'f')) || ((*p >= 'A') && (*p <= 'F')) || ((*p >= '0') && (*p <= '9'))) \ - { \ - if ((*p >= 'a') && (*p <= 'f')) \ - _X = _X * 16 + *p - 87; \ - else if ((*p >= 'A') && (*p <= 'F')) \ - _X = _X * 16 + *p - 55; \ - else if ((*p >= '0') && (*p <= '9')) \ - _X = _X * 16 + *p - 48; \ - p++; \ - } \ -} - - -static VOID memcpy_exl(PRTMP_ADAPTER pAd, UCHAR *dst, UCHAR *src, ULONG len); -static VOID memcpy_exs(PRTMP_ADAPTER pAd, UCHAR *dst, UCHAR *src, ULONG len); -static VOID RTMP_IO_READ_BULK(PRTMP_ADAPTER pAd, UCHAR *dst, UCHAR *src, UINT32 len); - -#ifdef UCOS -int ate_copy_to_user( - IN PUCHAR payload, - IN PUCHAR msg, - IN INT len) -{ - memmove(payload, msg, len); - return 0; -} - -#undef copy_to_user -#define copy_to_user(x,y,z) ate_copy_to_user((PUCHAR)x, (PUCHAR)y, z) -#endif // UCOS // - -#define LEN_OF_ARG 16 - -VOID RtmpDoAte( - IN PRTMP_ADAPTER pAdapter, - IN struct iwreq *wrq) -{ - unsigned short Command_Id; - struct ate_racfghdr *pRaCfg; - INT Status = NDIS_STATUS_SUCCESS; - - - - if((pRaCfg = kmalloc(sizeof(struct ate_racfghdr), GFP_KERNEL)) == NULL) - { - Status = -EINVAL; - return; - } - - NdisZeroMemory(pRaCfg, sizeof(struct ate_racfghdr)); - - if (copy_from_user((PUCHAR)pRaCfg, wrq->u.data.pointer, wrq->u.data.length)) - { - Status = -EFAULT; - kfree(pRaCfg); - return; - } - - - Command_Id = ntohs(pRaCfg->command_id); - - ATEDBGPRINT(RT_DEBUG_TRACE,("\n%s: Command_Id = 0x%04x !\n", __FUNCTION__, Command_Id)); - - switch (Command_Id) - { - // We will get this command when QA starts. - case RACFG_CMD_ATE_START: - { - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_START\n")); - - // prepare feedback as soon as we can to avoid QA timeout. - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - ATEDBGPRINT(RT_DEBUG_TRACE, ("wrq->u.data.length = %d\n", wrq->u.data.length)); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("copy_to_user() fail in case RACFG_CMD_ATE_START\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_START is done !\n")); - } - Set_ATE_Proc(pAdapter, "ATESTART"); - } - break; - - // We will get this command either QA is closed or ated is killed by user. - case RACFG_CMD_ATE_STOP: - { -#ifndef UCOS - INT32 ret; -#endif // !UCOS // - - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_STOP\n")); - - // Distinguish this command came from QA(via ated) - // or ate daemon according to the existence of pid in payload. - // No need to prepare feedback if this cmd came directly from ate daemon. - pRaCfg->length = ntohs(pRaCfg->length); - - if (pRaCfg->length == sizeof(pAdapter->ate.AtePid)) - { - // This command came from QA. - // Get the pid of ATE daemon. - memcpy((UCHAR *)&pAdapter->ate.AtePid, - (&pRaCfg->data[0]) - 2/* == &(pRaCfg->status) */, - sizeof(pAdapter->ate.AtePid)); - - // prepare feedback as soon as we can to avoid QA timeout. - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - ATEDBGPRINT(RT_DEBUG_TRACE, ("wrq->u.data.length = %d\n", wrq->u.data.length)); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_STOP\n")); - Status = -EFAULT; - } - - // - // kill ATE daemon when leaving ATE mode. - // We must kill ATE daemon first before setting ATESTOP, - // or Microsoft will report sth. wrong. -#ifndef UCOS - ret = kill_proc(pAdapter->ate.AtePid, SIGTERM, 1); - if (ret) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("%s: unable to signal thread\n", pAdapter->net_dev->name)); - } -#endif // !UCOS // - } - -#ifdef UCOS - // Roger add to avoid error message after close QA - if (pAdapter->CSRBaseAddress == RT2860_CSR_ADDR) - { - - // prepare feedback as soon as we can to avoid QA timeout. - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - ATEDBGPRINT(RT_DEBUG_TRACE, ("wrq->u.data.length = %d\n", wrq->u.data.length)); - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("copy_to_user() fail in case RACFG_CMD_AP_START\n")); - Status = -EFAULT; - } - } -#endif // UCOS // - - // AP might have in ATE_STOP mode due to cmd from QA. - if (ATE_ON(pAdapter)) - { - // Someone has killed ate daemon while QA GUI is still open. - Set_ATE_Proc(pAdapter, "ATESTOP"); - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_AP_START is done !\n")); - } - } - break; - - case RACFG_CMD_RF_WRITE_ALL: - { - UINT32 R1, R2, R3, R4; - USHORT channel; - - memcpy(&R1, pRaCfg->data-2, 4); - memcpy(&R2, pRaCfg->data+2, 4); - memcpy(&R3, pRaCfg->data+6, 4); - memcpy(&R4, pRaCfg->data+10, 4); - memcpy(&channel, pRaCfg->data+14, 2); - - pAdapter->LatchRfRegs.R1 = ntohl(R1); - pAdapter->LatchRfRegs.R2 = ntohl(R2); - pAdapter->LatchRfRegs.R3 = ntohl(R3); - pAdapter->LatchRfRegs.R4 = ntohl(R4); - pAdapter->LatchRfRegs.Channel = ntohs(channel); - - RTMP_RF_IO_WRITE32(pAdapter, pAdapter->LatchRfRegs.R1); - RTMP_RF_IO_WRITE32(pAdapter, pAdapter->LatchRfRegs.R2); - RTMP_RF_IO_WRITE32(pAdapter, pAdapter->LatchRfRegs.R3); - RTMP_RF_IO_WRITE32(pAdapter, pAdapter->LatchRfRegs.R4); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - ATEDBGPRINT(RT_DEBUG_TRACE, ("wrq->u.data.length = %d\n", wrq->u.data.length)); - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_RF_WRITE_ALL\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_RF_WRITE_ALL is done !\n")); - } - } - break; - - case RACFG_CMD_E2PROM_READ16: - { - USHORT offset, value, tmp; - - offset = ntohs(pRaCfg->status); - /* "tmp" is expecially for some compilers... */ - RT28xx_EEPROM_READ16(pAdapter, offset, tmp); - value = tmp; - value = htons(value); - - ATEDBGPRINT(RT_DEBUG_TRACE,("EEPROM Read offset = 0x%04x, value = 0x%04x\n", offset, value)); - - // prepare feedback - pRaCfg->length = htons(4); - pRaCfg->status = htons(0); - memcpy(pRaCfg->data, &value, 2); - - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - ATEDBGPRINT(RT_DEBUG_TRACE, ("sizeof(struct ate_racfghdr) = %d\n", sizeof(struct ate_racfghdr))); - ATEDBGPRINT(RT_DEBUG_TRACE, ("wrq->u.data.length = %d\n", wrq->u.data.length)); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_E2PROM_READ16\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_E2PROM_READ16 is done !\n")); - } - } - break; - - case RACFG_CMD_E2PROM_WRITE16: - { - USHORT offset, value; - - offset = ntohs(pRaCfg->status); - memcpy(&value, pRaCfg->data, 2); - value = ntohs(value); - RT28xx_EEPROM_WRITE16(pAdapter, offset, value); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_E2PROM_WRITE16\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_E2PROM_WRITE16 is done !\n")); - } - } - break; - - case RACFG_CMD_E2PROM_READ_ALL: - { - USHORT buffer[EEPROM_SIZE/2]; - - rt_ee_read_all(pAdapter,(USHORT *)buffer); - memcpy_exs(pAdapter, pRaCfg->data, (UCHAR *)buffer, EEPROM_SIZE); - - // prepare feedback - pRaCfg->length = htons(2+EEPROM_SIZE); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_E2PROM_READ_ALL\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_E2PROM_READ_ALL is done !\n")); - } - } - break; - - case RACFG_CMD_E2PROM_WRITE_ALL: - { - USHORT buffer[EEPROM_SIZE/2]; - - NdisZeroMemory((UCHAR *)buffer, EEPROM_SIZE); - memcpy_exs(pAdapter, (UCHAR *)buffer, (UCHAR *)&pRaCfg->status, EEPROM_SIZE); - rt_ee_write_all(pAdapter,(USHORT *)buffer); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_E2PROM_WRITE_ALL\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("RACFG_CMD_E2PROM_WRITE_ALL is done !\n")); - } - - } - break; - - case RACFG_CMD_IO_READ: - { - UINT32 offset; - UINT32 value; - - memcpy(&offset, &pRaCfg->status, 4); - offset = ntohl(offset); - - // We do not need the base address. - // So just extract the offset out. - offset &= 0x0000FFFF; - RTMP_IO_READ32(pAdapter, offset, &value); - value = htonl(value); - - // prepare feedback - pRaCfg->length = htons(6); - pRaCfg->status = htons(0); - memcpy(pRaCfg->data, &value, 4); - - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_IO_READ\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_IO_READ is done !\n")); - } - } - break; - - case RACFG_CMD_IO_WRITE: - { - UINT32 offset, value; - - memcpy(&offset, pRaCfg->data-2, 4); - memcpy(&value, pRaCfg->data+2, 4); - - offset = ntohl(offset); - - // We do not need the base address. - // So just extract out the offset. - offset &= 0x0000FFFF; - value = ntohl(value); - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_IO_WRITE: offset = %x, value = %x\n", offset, value)); - RTMP_IO_WRITE32(pAdapter, offset, value); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_IO_WRITE\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_IO_WRITE is done !\n")); - } - } - break; - - case RACFG_CMD_IO_READ_BULK: - { - UINT32 offset; - USHORT len; - - memcpy(&offset, &pRaCfg->status, 4); - offset = ntohl(offset); - - // We do not need the base address. - // So just extract the offset. - offset &= 0x0000FFFF; - memcpy(&len, pRaCfg->data+2, 2); - len = ntohs(len); - - if (len > 371) - { - ATEDBGPRINT(RT_DEBUG_TRACE,("len is too large, make it smaller\n")); - pRaCfg->length = htons(2); - pRaCfg->status = htons(1); - break; - } - - RTMP_IO_READ_BULK(pAdapter, pRaCfg->data, (UCHAR *)offset, len*4);// unit in four bytes - - // prepare feedback - pRaCfg->length = htons(2+len*4);// unit in four bytes - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_IO_READ_BULK\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_IO_READ_BULK is done !\n")); - } - } - break; - - case RACFG_CMD_BBP_READ8: - { - USHORT offset; - UCHAR value; - - value = 0; - offset = ntohs(pRaCfg->status); - - if (ATE_ON(pAdapter)) - { - ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, offset, &value); - } - else - { - RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, offset, &value); - } - // prepare feedback - pRaCfg->length = htons(3); - pRaCfg->status = htons(0); - pRaCfg->data[0] = value; - - ATEDBGPRINT(RT_DEBUG_TRACE,("BBP value = %x\n", value)); - - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_BBP_READ8\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_BBP_READ8 is done !\n")); - } - } - break; - case RACFG_CMD_BBP_WRITE8: - { - USHORT offset; - UCHAR value; - - offset = ntohs(pRaCfg->status); - memcpy(&value, pRaCfg->data, 1); - - if (ATE_ON(pAdapter)) - { - ATE_BBP_IO_WRITE8_BY_REG_ID(pAdapter, offset, value); - } - else - { - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, offset, value); - } - - if ((offset == BBP_R1) || (offset == BBP_R3)) - { - SyncTxRxConfig(pAdapter, offset, value); - } - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_BBP_WRITE8\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_BBP_WRITE8 is done !\n")); - } - } - break; - - case RACFG_CMD_BBP_READ_ALL: - { - USHORT j; - - for (j = 0; j < 137; j++) - { - pRaCfg->data[j] = 0; - - if (ATE_ON(pAdapter)) - { - ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, j, &pRaCfg->data[j]); - } - else - { - RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, j, &pRaCfg->data[j]); - } - } - - // prepare feedback - pRaCfg->length = htons(2+137); - pRaCfg->status = htons(0); - - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_BBP_READ_ALL\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_BBP_READ_ALL is done !\n")); - } - } - - break; - - case RACFG_CMD_ATE_E2PROM_READ_BULK: - { - USHORT offset; - USHORT len; - USHORT buffer[EEPROM_SIZE/2]; - - offset = ntohs(pRaCfg->status); - memcpy(&len, pRaCfg->data, 2); - len = ntohs(len); - - rt_ee_read_all(pAdapter,(USHORT *)buffer); - if (offset + len <= EEPROM_SIZE) - memcpy_exs(pAdapter, pRaCfg->data, (UCHAR *)buffer+offset, len); - else - ATEDBGPRINT(RT_DEBUG_ERROR, ("exceed EEPROM size\n")); - - // prepare feedback - pRaCfg->length = htons(2+len); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_E2PROM_READ_BULK\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_E2PROM_READ_BULK is done !\n")); - } - - } - break; - - case RACFG_CMD_ATE_E2PROM_WRITE_BULK: - { - USHORT offset; - USHORT len; - USHORT buffer[EEPROM_SIZE/2]; - - offset = ntohs(pRaCfg->status); - memcpy(&len, pRaCfg->data, 2); - len = ntohs(len); - - rt_ee_read_all(pAdapter,(USHORT *)buffer); - memcpy_exs(pAdapter, (UCHAR *)buffer + offset, (UCHAR *)pRaCfg->data + 2, len); - rt_ee_write_all(pAdapter,(USHORT *)buffer); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_E2PROM_WRITE_BULK\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("RACFG_CMD_ATE_E2PROM_WRITE_BULK is done !\n")); - } - - } - break; - - case RACFG_CMD_ATE_IO_WRITE_BULK: - { - UINT32 offset, i, value; - USHORT len; - - memcpy(&offset, &pRaCfg->status, 4); - offset = ntohl(offset); - memcpy(&len, pRaCfg->data+2, 2); - len = ntohs(len); - - for (i = 0; i < len; i += 4) - { - memcpy_exl(pAdapter, (UCHAR *)&value, pRaCfg->data+4+i, 4); - printk("Write %x %x\n", offset + i, value); - RTMP_IO_WRITE32(pAdapter, (offset +i) & 0xffff, value); - } - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_IO_WRITE_BULK\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("RACFG_CMD_ATE_IO_WRITE_BULK is done !\n")); - } - - } - break; - - case RACFG_CMD_ATE_BBP_READ_BULK: - { - USHORT offset; - USHORT len; - USHORT j; - - offset = ntohs(pRaCfg->status); - memcpy(&len, pRaCfg->data, 2); - len = ntohs(len); - - - for (j = offset; j < (offset+len); j++) - { - pRaCfg->data[j - offset] = 0; - - if (pAdapter->ate.Mode == ATE_STOP) - { - RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, j, &pRaCfg->data[j - offset]); - } - else - { - ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, j, &pRaCfg->data[j - offset]); - } - } - - // prepare feedback - pRaCfg->length = htons(2+len); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_BBP_READ_BULK\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_BBP_READ_BULK is done !\n")); - } - - } - break; - - case RACFG_CMD_ATE_BBP_WRITE_BULK: - { - USHORT offset; - USHORT len; - USHORT j; - UCHAR *value; - - offset = ntohs(pRaCfg->status); - memcpy(&len, pRaCfg->data, 2); - len = ntohs(len); - - for (j = offset; j < (offset+len); j++) - { - value = pRaCfg->data + 2 + (j - offset); - if (pAdapter->ate.Mode == ATE_STOP) - { - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, j, *value); - } - else - { - ATE_BBP_IO_WRITE8_BY_REG_ID(pAdapter, j, *value); - } - } - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_BBP_WRITE_BULK\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_BBP_WRITE_BULK is done !\n")); - } - } - break; - -#ifdef CONFIG_RALINK_RT3052 - case RACFG_CMD_ATE_RF_READ_BULK: - { - USHORT offset; - USHORT len; - USHORT j; - - offset = ntohs(pRaCfg->status); - memcpy(&len, pRaCfg->data, 2); - len = ntohs(len); - - for (j = offset; j < (offset+len); j++) - { - pRaCfg->data[j - offset] = 0; - RT30xxReadRFRegister(pAdapter, j, &pRaCfg->data[j - offset]); - } - - // prepare feedback - pRaCfg->length = htons(2+len); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_RF_READ_BULK\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_RF_READ_BULK is done !\n")); - } - - } - break; - - case RACFG_CMD_ATE_RF_WRITE_BULK: - { - USHORT offset; - USHORT len; - USHORT j; - UCHAR *value; - - offset = ntohs(pRaCfg->status); - memcpy(&len, pRaCfg->data, 2); - len = ntohs(len); - - for (j = offset; j < (offset+len); j++) - { - value = pRaCfg->data + 2 + (j - offset); - RT30xxWriteRFRegister(pAdapter, j, *value); - } - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_RF_WRITE_BULK\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_RF_WRITE_BULK is done !\n")); - } - - } - break; -#endif - - - case RACFG_CMD_GET_NOISE_LEVEL: - { - UCHAR channel; - INT32 buffer[3][10];/* 3 : RxPath ; 10 : no. of per rssi samples */ - - channel = (ntohs(pRaCfg->status) & 0x00FF); - CalNoiseLevel(pAdapter, channel, buffer); - memcpy_exl(pAdapter, (UCHAR *)pRaCfg->data, (UCHAR *)&(buffer[0][0]), (sizeof(INT32)*3*10)); - - // prepare feedback - pRaCfg->length = htons(2 + (sizeof(INT32)*3*10)); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_GET_NOISE_LEVEL\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_GET_NOISE_LEVEL is done !\n")); - } - } - break; - - case RACFG_CMD_GET_COUNTER: - { - memcpy_exl(pAdapter, &pRaCfg->data[0], (UCHAR *)&pAdapter->ate.U2M, 4); - memcpy_exl(pAdapter, &pRaCfg->data[4], (UCHAR *)&pAdapter->ate.OtherData, 4); - memcpy_exl(pAdapter, &pRaCfg->data[8], (UCHAR *)&pAdapter->ate.Beacon, 4); - memcpy_exl(pAdapter, &pRaCfg->data[12], (UCHAR *)&pAdapter->ate.OtherCount, 4); - memcpy_exl(pAdapter, &pRaCfg->data[16], (UCHAR *)&pAdapter->ate.TxAc0, 4); - memcpy_exl(pAdapter, &pRaCfg->data[20], (UCHAR *)&pAdapter->ate.TxAc1, 4); - memcpy_exl(pAdapter, &pRaCfg->data[24], (UCHAR *)&pAdapter->ate.TxAc2, 4); - memcpy_exl(pAdapter, &pRaCfg->data[28], (UCHAR *)&pAdapter->ate.TxAc3, 4); - memcpy_exl(pAdapter, &pRaCfg->data[32], (UCHAR *)&pAdapter->ate.TxHCCA, 4); - memcpy_exl(pAdapter, &pRaCfg->data[36], (UCHAR *)&pAdapter->ate.TxMgmt, 4); - memcpy_exl(pAdapter, &pRaCfg->data[40], (UCHAR *)&pAdapter->ate.RSSI0, 4); - memcpy_exl(pAdapter, &pRaCfg->data[44], (UCHAR *)&pAdapter->ate.RSSI1, 4); - memcpy_exl(pAdapter, &pRaCfg->data[48], (UCHAR *)&pAdapter->ate.RSSI2, 4); - memcpy_exl(pAdapter, &pRaCfg->data[52], (UCHAR *)&pAdapter->ate.SNR0, 4); - memcpy_exl(pAdapter, &pRaCfg->data[56], (UCHAR *)&pAdapter->ate.SNR1, 4); - - pRaCfg->length = htons(2+60); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_GET_COUNTER\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_GET_COUNTER is done !\n")); - } - } - break; - - case RACFG_CMD_CLEAR_COUNTER: - { - pAdapter->ate.U2M = 0; - pAdapter->ate.OtherData = 0; - pAdapter->ate.Beacon = 0; - pAdapter->ate.OtherCount = 0; - pAdapter->ate.TxAc0 = 0; - pAdapter->ate.TxAc1 = 0; - pAdapter->ate.TxAc2 = 0; - pAdapter->ate.TxAc3 = 0; - pAdapter->ate.TxHCCA = 0; - pAdapter->ate.TxMgmt = 0; - pAdapter->ate.TxDoneCount = 0; - - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_CLEAR_COUNTER\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_CLEAR_COUNTER is done !\n")); - } - } - - break; - - case RACFG_CMD_TX_START: - { - USHORT *p; - USHORT err = 1; - UCHAR Bbp22Value = 0, Bbp24Value = 0; - - if ((pAdapter->ate.TxStatus != 0) && (pAdapter->ate.Mode & ATE_TXFRAME)) - { - ATEDBGPRINT(RT_DEBUG_TRACE,("Ate Tx is already running, to run next Tx, you must stop it first\n")); - err = 2; - goto TX_START_ERROR; - } - else if ((pAdapter->ate.TxStatus != 0) && !(pAdapter->ate.Mode & ATE_TXFRAME)) - { - int i = 0; - - while ((i++ < 10) && (pAdapter->ate.TxStatus != 0)) - { - RTMPusecDelay(5000); - } - - // force it to stop - pAdapter->ate.TxStatus = 0; - pAdapter->ate.TxDoneCount = 0; - //pAdapter->ate.Repeat = 0; - pAdapter->ate.bQATxStart = FALSE; - } - - // If pRaCfg->length == 0, this "RACFG_CMD_TX_START" is for Carrier test or Carrier Suppression. - if (ntohs(pRaCfg->length) != 0) - { - // Get frame info -#ifdef RT2870 - NdisMoveMemory(&pAdapter->ate.TxInfo, pRaCfg->data - 2, 4); -#ifdef RT_BIG_ENDIAN - RTMPDescriptorEndianChange((PUCHAR) &pAdapter->ate.TxInfo, TYPE_TXINFO); -#endif // RT_BIG_ENDIAN // -#endif // RT2870 // - - NdisMoveMemory(&pAdapter->ate.TxWI, pRaCfg->data + 2, 16); -#ifdef RT_BIG_ENDIAN - RTMPWIEndianChange((PUCHAR)&pAdapter->ate.TxWI, TYPE_TXWI); -#endif // RT_BIG_ENDIAN // - - NdisMoveMemory(&pAdapter->ate.TxCount, pRaCfg->data + 18, 4); - pAdapter->ate.TxCount = ntohl(pAdapter->ate.TxCount); - - p = (USHORT *)(&pRaCfg->data[22]); - //p = pRaCfg->data + 22; - // always use QID_AC_BE - pAdapter->ate.QID = 0; - p = (USHORT *)(&pRaCfg->data[24]); - //p = pRaCfg->data + 24; - pAdapter->ate.HLen = ntohs(*p); - - if (pAdapter->ate.HLen > 32) - { - ATEDBGPRINT(RT_DEBUG_ERROR,("pAdapter->ate.HLen > 32\n")); - err = 3; - goto TX_START_ERROR; - } - - NdisMoveMemory(&pAdapter->ate.Header, pRaCfg->data + 26, pAdapter->ate.HLen); - - - pAdapter->ate.PLen = ntohs(pRaCfg->length) - (pAdapter->ate.HLen + 28); - - if (pAdapter->ate.PLen > 32) - { - ATEDBGPRINT(RT_DEBUG_ERROR,("pAdapter->ate.PLen > 32\n")); - err = 4; - goto TX_START_ERROR; - } - - NdisMoveMemory(&pAdapter->ate.Pattern, pRaCfg->data + 26 + pAdapter->ate.HLen, pAdapter->ate.PLen); - pAdapter->ate.DLen = pAdapter->ate.TxWI.MPDUtotalByteCount - pAdapter->ate.HLen; - } - - ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, BBP_R22, &Bbp22Value); - - switch (Bbp22Value) - { - case BBP22_TXFRAME: - { - if (pAdapter->ate.TxCount == 0) - { - } - ATEDBGPRINT(RT_DEBUG_TRACE,("START TXFRAME\n")); - pAdapter->ate.bQATxStart = TRUE; - Set_ATE_Proc(pAdapter, "TXFRAME"); - } - break; - - case BBP22_TXCONT_OR_CARRSUPP: - { - ATEDBGPRINT(RT_DEBUG_TRACE,("BBP22_TXCONT_OR_CARRSUPP\n")); - ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, 24, &Bbp24Value); - - switch (Bbp24Value) - { - case BBP24_TXCONT: - { - ATEDBGPRINT(RT_DEBUG_TRACE,("START TXCONT\n")); - pAdapter->ate.bQATxStart = TRUE; - Set_ATE_Proc(pAdapter, "TXCONT"); - } - break; - - case BBP24_CARRSUPP: - { - ATEDBGPRINT(RT_DEBUG_TRACE,("START TXCARRSUPP\n")); - pAdapter->ate.bQATxStart = TRUE; - pAdapter->ate.Mode |= ATE_TXCARRSUPP; - } - break; - - default: - { - ATEDBGPRINT(RT_DEBUG_ERROR,("Unknown Start TX subtype !")); - } - break; - } - } - break; - - case BBP22_TXCARR: - { - ATEDBGPRINT(RT_DEBUG_TRACE,("START TXCARR\n")); - pAdapter->ate.bQATxStart = TRUE; - Set_ATE_Proc(pAdapter, "TXCARR"); - } - break; - - default: - { - ATEDBGPRINT(RT_DEBUG_ERROR,("Unknown Start TX subtype !")); - } - break; - } - - if (pAdapter->ate.bQATxStart == TRUE) - { - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() was failed in case RACFG_CMD_TX_START\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_TX_START is done !\n")); - } - break; - } - -TX_START_ERROR: - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(err); - - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_TX_START\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("feedback of TX_START_ERROR is done !\n")); - } - } - break; - - case RACFG_CMD_GET_TX_STATUS: - { - UINT32 count; - - // prepare feedback - pRaCfg->length = htons(6); - pRaCfg->status = htons(0); - count = htonl(pAdapter->ate.TxDoneCount); - NdisMoveMemory(pRaCfg->data, &count, 4); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_GET_TX_STATUS\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_GET_TX_STATUS is done !\n")); - } - } - break; - - case RACFG_CMD_TX_STOP: - { - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_TX_STOP\n")); - - Set_ATE_Proc(pAdapter, "TXSTOP"); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("copy_to_user() fail in case RACFG_CMD_TX_STOP\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_TX_STOP is done !\n")); - } - } - break; - - case RACFG_CMD_RX_START: - { - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_RX_START\n")); - - pAdapter->ate.bQARxStart = TRUE; - Set_ATE_Proc(pAdapter, "RXFRAME"); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_RX_START\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_RX_START is done !\n")); - } - } - break; - - case RACFG_CMD_RX_STOP: - { - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_RX_STOP\n")); - - Set_ATE_Proc(pAdapter, "RXSTOP"); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_RX_STOP\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_RX_STOP is done !\n")); - } - } - break; - - /* The following cases are for new ATE GUI(not QA). */ - /*==================================================*/ - case RACFG_CMD_ATE_START_TX_CARRIER: - { - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_START_TX_CARRIER\n")); - - Set_ATE_Proc(pAdapter, "TXCARR"); - - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - ATEDBGPRINT(RT_DEBUG_TRACE, ("wrq->u.data.length = %d\n", wrq->u.data.length)); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_START_TX_CARRIER\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_START_TX_CARRIER is done !\n")); - } - } - break; - - case RACFG_CMD_ATE_START_TX_CONT: - { - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_START_TX_CONT\n")); - - Set_ATE_Proc(pAdapter, "TXCONT"); - - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - ATEDBGPRINT(RT_DEBUG_TRACE, ("wrq->u.data.length = %d\n", wrq->u.data.length)); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_START_TX_CONT\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_START_TX_CONT is done !\n")); - } - } - break; - - case RACFG_CMD_ATE_START_TX_FRAME: - { - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_START_TX_FRAME\n")); - - Set_ATE_Proc(pAdapter, "TXFRAME"); - - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - ATEDBGPRINT(RT_DEBUG_TRACE, ("wrq->u.data.length = %d\n", wrq->u.data.length)); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_START_TX_FRAME\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_START_TX_FRAME is done !\n")); - } - } - break; - - case RACFG_CMD_ATE_SET_BW: - { - SHORT value = 0; - UCHAR str[LEN_OF_ARG]; - - NdisZeroMemory(str, LEN_OF_ARG); - - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_BW\n")); - - memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); - value = ntohs(value); - sprintf((PCHAR)str, "%d", value); - - Set_ATE_TX_BW_Proc(pAdapter, str); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_BW\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_BW is done !\n")); - } - } - break; - - case RACFG_CMD_ATE_SET_TX_POWER0: - { - SHORT value = 0; - UCHAR str[LEN_OF_ARG]; - - NdisZeroMemory(str, LEN_OF_ARG); - - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_TX_POWER0\n")); - - memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); - value = ntohs(value); - sprintf((PCHAR)str, "%d", value); - Set_ATE_TX_POWER0_Proc(pAdapter, str); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_TX_POWER0\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_TX_POWER0 is done !\n")); - } - } - break; - - case RACFG_CMD_ATE_SET_TX_POWER1: - { - SHORT value = 0; - UCHAR str[LEN_OF_ARG]; - - NdisZeroMemory(str, LEN_OF_ARG); - - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_TX_POWER1\n")); - - memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); - value = ntohs(value); - sprintf((PCHAR)str, "%d", value); - Set_ATE_TX_POWER1_Proc(pAdapter, str); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_TX_POWER1\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_TX_POWER1 is done !\n")); - } - } - break; - - case RACFG_CMD_ATE_SET_FREQ_OFFSET: - { - SHORT value = 0; - UCHAR str[LEN_OF_ARG]; - - NdisZeroMemory(str, LEN_OF_ARG); - - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_FREQ_OFFSET\n")); - - memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); - value = ntohs(value); - sprintf((PCHAR)str, "%d", value); - Set_ATE_TX_FREQOFFSET_Proc(pAdapter, str); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_FREQ_OFFSET\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_FREQ_OFFSET is done !\n")); - } - } - break; - - case RACFG_CMD_ATE_GET_STATISTICS: - { - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_GET_STATISTICS\n")); - - memcpy_exl(pAdapter, &pRaCfg->data[0], (UCHAR *)&pAdapter->ate.TxDoneCount, 4); - memcpy_exl(pAdapter, &pRaCfg->data[4], (UCHAR *)&pAdapter->WlanCounters.RetryCount.u.LowPart, 4); - memcpy_exl(pAdapter, &pRaCfg->data[8], (UCHAR *)&pAdapter->WlanCounters.FailedCount.u.LowPart, 4); - memcpy_exl(pAdapter, &pRaCfg->data[12], (UCHAR *)&pAdapter->WlanCounters.RTSSuccessCount.u.LowPart, 4); - memcpy_exl(pAdapter, &pRaCfg->data[16], (UCHAR *)&pAdapter->WlanCounters.RTSFailureCount.u.LowPart, 4); - memcpy_exl(pAdapter, &pRaCfg->data[20], (UCHAR *)&pAdapter->WlanCounters.ReceivedFragmentCount.QuadPart, 4); - memcpy_exl(pAdapter, &pRaCfg->data[24], (UCHAR *)&pAdapter->WlanCounters.FCSErrorCount.u.LowPart, 4); - memcpy_exl(pAdapter, &pRaCfg->data[28], (UCHAR *)&pAdapter->Counters8023.RxNoBuffer, 4); - memcpy_exl(pAdapter, &pRaCfg->data[32], (UCHAR *)&pAdapter->WlanCounters.FrameDuplicateCount.u.LowPart, 4); - memcpy_exl(pAdapter, &pRaCfg->data[36], (UCHAR *)&pAdapter->RalinkCounters.OneSecFalseCCACnt, 4); - - if (pAdapter->ate.RxAntennaSel == 0) - { - INT32 RSSI0 = 0; - INT32 RSSI1 = 0; - INT32 RSSI2 = 0; - - RSSI0 = (INT32)(pAdapter->ate.LastRssi0 - pAdapter->BbpRssiToDbmDelta); - RSSI1 = (INT32)(pAdapter->ate.LastRssi1 - pAdapter->BbpRssiToDbmDelta); - RSSI2 = (INT32)(pAdapter->ate.LastRssi2 - pAdapter->BbpRssiToDbmDelta); - memcpy_exl(pAdapter, &pRaCfg->data[40], (UCHAR *)&RSSI0, 4); - memcpy_exl(pAdapter, &pRaCfg->data[44], (UCHAR *)&RSSI1, 4); - memcpy_exl(pAdapter, &pRaCfg->data[48], (UCHAR *)&RSSI2, 4); - pRaCfg->length = htons(2+52); - } - else - { - INT32 RSSI0 = 0; - - RSSI0 = (INT32)(pAdapter->ate.LastRssi0 - pAdapter->BbpRssiToDbmDelta); - memcpy_exl(pAdapter, &pRaCfg->data[40], (UCHAR *)&RSSI0, 4); - pRaCfg->length = htons(2+44); - } - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_GET_STATISTICS\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_GET_STATISTICS is done !\n")); - } - } - break; - - case RACFG_CMD_ATE_RESET_COUNTER: - { - SHORT value = 1; - UCHAR str[LEN_OF_ARG]; - - NdisZeroMemory(str, LEN_OF_ARG); - - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_RESET_COUNTER\n")); - - sprintf((PCHAR)str, "%d", value); - Set_ResetStatCounter_Proc(pAdapter, str); - - pAdapter->ate.TxDoneCount = 0; - - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_RESET_COUNTER\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_RESET_COUNTER is done !\n")); - } - } - - break; - - case RACFG_CMD_ATE_SEL_TX_ANTENNA: - { - SHORT value = 0; - UCHAR str[LEN_OF_ARG]; - - NdisZeroMemory(str, LEN_OF_ARG); - - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SEL_TX_ANTENNA\n")); - - memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); - value = ntohs(value); - sprintf((PCHAR)str, "%d", value); - Set_ATE_TX_Antenna_Proc(pAdapter, str); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SEL_TX_ANTENNA\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SEL_TX_ANTENNA is done !\n")); - } - } - break; - - case RACFG_CMD_ATE_SEL_RX_ANTENNA: - { - SHORT value = 0; - UCHAR str[LEN_OF_ARG]; - - NdisZeroMemory(str, LEN_OF_ARG); - - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SEL_RX_ANTENNA\n")); - - memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); - value = ntohs(value); - sprintf((PCHAR)str, "%d", value); - Set_ATE_RX_Antenna_Proc(pAdapter, str); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SEL_RX_ANTENNA\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SEL_RX_ANTENNA is done !\n")); - } - } - break; - - case RACFG_CMD_ATE_SET_PREAMBLE: - { - SHORT value = 0; - UCHAR str[LEN_OF_ARG]; - - NdisZeroMemory(str, LEN_OF_ARG); - - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_PREAMBLE\n")); - - memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); - value = ntohs(value); - sprintf((PCHAR)str, "%d", value); - Set_ATE_TX_MODE_Proc(pAdapter, str); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_PREAMBLE\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_PREAMBLE is done !\n")); - } - } - break; - - case RACFG_CMD_ATE_SET_CHANNEL: - { - SHORT value = 0; - UCHAR str[LEN_OF_ARG]; - - NdisZeroMemory(str, LEN_OF_ARG); - - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_CHANNEL\n")); - - memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); - value = ntohs(value); - sprintf((PCHAR)str, "%d", value); - Set_ATE_CHANNEL_Proc(pAdapter, str); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_CHANNEL\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_CHANNEL is done !\n")); - } - } - break; - - case RACFG_CMD_ATE_SET_ADDR1: - { - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_ADDR1\n")); - - // Addr is an array of UCHAR, - // so no need to perform endian swap. - memcpy(pAdapter->ate.Addr1, (PUCHAR)(pRaCfg->data - 2), MAC_ADDR_LEN); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_ADDR1\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_ADDR1 is done !\n (ADDR1 = %2X:%2X:%2X:%2X:%2X:%2X)\n", pAdapter->ate.Addr1[0], - pAdapter->ate.Addr1[1], pAdapter->ate.Addr1[2], pAdapter->ate.Addr1[3], pAdapter->ate.Addr1[4], pAdapter->ate.Addr1[5])); - } - } - break; - - case RACFG_CMD_ATE_SET_ADDR2: - { - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_ADDR2\n")); - - // Addr is an array of UCHAR, - // so no need to perform endian swap. - memcpy(pAdapter->ate.Addr2, (PUCHAR)(pRaCfg->data - 2), MAC_ADDR_LEN); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_ADDR2\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_ADDR2 is done !\n (ADDR2 = %2X:%2X:%2X:%2X:%2X:%2X)\n", pAdapter->ate.Addr2[0], - pAdapter->ate.Addr2[1], pAdapter->ate.Addr2[2], pAdapter->ate.Addr2[3], pAdapter->ate.Addr2[4], pAdapter->ate.Addr2[5])); - } - } - break; - - case RACFG_CMD_ATE_SET_ADDR3: - { - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_ADDR3\n")); - - // Addr is an array of UCHAR, - // so no need to perform endian swap. - memcpy(pAdapter->ate.Addr3, (PUCHAR)(pRaCfg->data - 2), MAC_ADDR_LEN); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_ADDR3\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_ADDR3 is done !\n (ADDR3 = %2X:%2X:%2X:%2X:%2X:%2X)\n", pAdapter->ate.Addr3[0], - pAdapter->ate.Addr3[1], pAdapter->ate.Addr3[2], pAdapter->ate.Addr3[3], pAdapter->ate.Addr3[4], pAdapter->ate.Addr3[5])); - } - } - break; - - case RACFG_CMD_ATE_SET_RATE: - { - SHORT value = 0; - UCHAR str[LEN_OF_ARG]; - - NdisZeroMemory(str, LEN_OF_ARG); - - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_RATE\n")); - - memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); - value = ntohs(value); - sprintf((PCHAR)str, "%d", value); - Set_ATE_TX_MCS_Proc(pAdapter, str); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_RATE\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_RATE is done !\n")); - } - } - break; - - case RACFG_CMD_ATE_SET_TX_FRAME_LEN: - { - SHORT value = 0; - UCHAR str[LEN_OF_ARG]; - - NdisZeroMemory(str, LEN_OF_ARG); - - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_TX_FRAME_LEN\n")); - - memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); - value = ntohs(value); - sprintf((PCHAR)str, "%d", value); - Set_ATE_TX_LENGTH_Proc(pAdapter, str); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_TX_FRAME_LEN\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_TX_FRAME_LEN is done !\n")); - } - } - break; - - case RACFG_CMD_ATE_SET_TX_FRAME_COUNT: - { - USHORT value = 0; - UCHAR str[LEN_OF_ARG]; - - NdisZeroMemory(str, LEN_OF_ARG); - - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_TX_FRAME_COUNT\n")); - - memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); - value = ntohs(value); - { - sprintf((PCHAR)str, "%d", value); - Set_ATE_TX_COUNT_Proc(pAdapter, str); - } - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_TX_FRAME_COUNT\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_TX_FRAME_COUNT is done !\n")); - } - } - break; - - case RACFG_CMD_ATE_START_RX_FRAME: - { - ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_RX_START\n")); - - Set_ATE_Proc(pAdapter, "RXFRAME"); - - // prepare feedback - pRaCfg->length = htons(2); - pRaCfg->status = htons(0); - wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) - + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) - + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); - - if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) - { - ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_RX_START\n")); - Status = -EFAULT; - } - else - { - ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_RX_START is done !\n")); - } - } - break; - default: - break; - } - ASSERT(pRaCfg != NULL); - if (pRaCfg != NULL) - { - kfree(pRaCfg); - } - return; -} - -VOID BubbleSort(INT32 n, INT32 a[]) -{ - INT32 k, j, temp; - - for (k = n-1; k>0; k--) - { - for (j = 0; j a[j+1]) - { - temp = a[j]; - a[j]=a[j+1]; - a[j+1]=temp; - } - } - } -} - -VOID CalNoiseLevel(PRTMP_ADAPTER pAd, UCHAR channel, INT32 RSSI[3][10]) -{ - INT32 RSSI0, RSSI1, RSSI2; - CHAR Rssi0Offset, Rssi1Offset, Rssi2Offset; - UCHAR BbpR50Rssi0 = 0, BbpR51Rssi1 = 0, BbpR52Rssi2 = 0; - UCHAR Org_BBP66value = 0, Org_BBP69value = 0, Org_BBP70value = 0, data = 0; - USHORT LNA_Gain = 0; - INT32 j = 0; - UCHAR Org_Channel = pAd->ate.Channel; - USHORT GainValue = 0, OffsetValue = 0; - - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R66, &Org_BBP66value); - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R69, &Org_BBP69value); - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R70, &Org_BBP70value); - - //********************************************************************** - // Read the value of LNA gain and Rssi offset - //********************************************************************** - RT28xx_EEPROM_READ16(pAd, EEPROM_LNA_OFFSET, GainValue); - - // for Noise Level - if (channel <= 14) - { - LNA_Gain = GainValue & 0x00FF; - - RT28xx_EEPROM_READ16(pAd, EEPROM_RSSI_BG_OFFSET, OffsetValue); - Rssi0Offset = OffsetValue & 0x00FF; - Rssi1Offset = (OffsetValue & 0xFF00) >> 8; - RT28xx_EEPROM_READ16(pAd, (EEPROM_RSSI_BG_OFFSET + 2)/* 0x48 */, OffsetValue); - Rssi2Offset = OffsetValue & 0x00FF; - } - else - { - LNA_Gain = (GainValue & 0xFF00) >> 8; - - RT28xx_EEPROM_READ16(pAd, EEPROM_RSSI_A_OFFSET, OffsetValue); - Rssi0Offset = OffsetValue & 0x00FF; - Rssi1Offset = (OffsetValue & 0xFF00) >> 8; - RT28xx_EEPROM_READ16(pAd, (EEPROM_RSSI_A_OFFSET + 2)/* 0x4C */, OffsetValue); - Rssi2Offset = OffsetValue & 0x00FF; - } - //********************************************************************** - { - pAd->ate.Channel = channel; - ATEAsicSwitchChannel(pAd); - mdelay(5); - - data = 0x10; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, data); - data = 0x40; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, data); - data = 0x40; - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, data); - mdelay(5); - - // Start Rx - pAd->ate.bQARxStart = TRUE; - Set_ATE_Proc(pAd, "RXFRAME"); - - mdelay(5); - - for (j = 0; j < 10; j++) - { - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R50, &BbpR50Rssi0); - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R51, &BbpR51Rssi1); - ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R52, &BbpR52Rssi2); - - mdelay(10); - - // Calculate RSSI 0 - if (BbpR50Rssi0 == 0) - { - RSSI0 = -100; - } - else - { - RSSI0 = (INT32)(-12 - BbpR50Rssi0 - LNA_Gain - Rssi0Offset); - } - RSSI[0][j] = RSSI0; - - if ( pAd->Antenna.field.RxPath >= 2 ) // 2R - { - // Calculate RSSI 1 - if (BbpR51Rssi1 == 0) - { - RSSI1 = -100; - } - else - { - RSSI1 = (INT32)(-12 - BbpR51Rssi1 - LNA_Gain - Rssi1Offset); - } - RSSI[1][j] = RSSI1; - } - - if ( pAd->Antenna.field.RxPath >= 3 ) // 3R - { - // Calculate RSSI 2 - if (BbpR52Rssi2 == 0) - RSSI2 = -100; - else - RSSI2 = (INT32)(-12 - BbpR52Rssi2 - LNA_Gain - Rssi2Offset); - - RSSI[2][j] = RSSI2; - } - } - - // Stop Rx - Set_ATE_Proc(pAd, "RXSTOP"); - - mdelay(5); - - BubbleSort(10, RSSI[0]); // 1R - - if ( pAd->Antenna.field.RxPath >= 2 ) // 2R - { - BubbleSort(10, RSSI[1]); - } - - if ( pAd->Antenna.field.RxPath >= 3 ) // 3R - { - BubbleSort(10, RSSI[2]); - } - - } - - pAd->ate.Channel = Org_Channel; - ATEAsicSwitchChannel(pAd); - - // Restore original value - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, Org_BBP66value); - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, Org_BBP69value); - ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, Org_BBP70value); - - return; -} - -BOOLEAN SyncTxRxConfig(PRTMP_ADAPTER pAd, USHORT offset, UCHAR value) -{ - UCHAR tmp = 0, bbp_data = 0; - - if (ATE_ON(pAd)) - { - ATE_BBP_IO_READ8_BY_REG_ID(pAd, offset, &bbp_data); - } - else - { - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, offset, &bbp_data); - } - - /* confirm again */ - ASSERT(bbp_data == value); - - switch(offset) - { - case BBP_R1: - /* Need to sync. tx configuration with legacy ATE. */ - tmp = (bbp_data & ((1 << 4) | (1 << 3))/* 0x18 */) >> 3; - switch(tmp) - { - /* The BBP R1 bit[4:3] = 2 :: Both DACs will be used by QA. */ - case 2: - /* All */ - pAd->ate.TxAntennaSel = 0; - break; - /* The BBP R1 bit[4:3] = 0 :: DAC 0 will be used by QA. */ - case 0: - /* Antenna one */ - pAd->ate.TxAntennaSel = 1; - break; - /* The BBP R1 bit[4:3] = 1 :: DAC 1 will be used by QA. */ - case 1: - /* Antenna two */ - pAd->ate.TxAntennaSel = 2; - break; - default: - DBGPRINT(RT_DEBUG_TRACE, ("%s -- Sth. wrong! : return FALSE; \n", __FUNCTION__)); - return FALSE; - } - break;/* case BBP_R1 */ - - case BBP_R3: - /* Need to sync. rx configuration with legacy ATE. */ - tmp = (bbp_data & ((1 << 1) | (1 << 0))/* 0x03 */); - switch(tmp) - { - /* The BBP R3 bit[1:0] = 3 :: All ADCs will be used by QA. */ - case 3: - /* All */ - pAd->ate.RxAntennaSel = 0; - break; - /* The BBP R3 bit[1:0] = 0 :: ADC 0 will be used by QA, */ - /* unless the BBP R3 bit[4:3] = 2 */ - case 0: - /* Antenna one */ - pAd->ate.RxAntennaSel = 1; - tmp = ((bbp_data & ((1 << 4) | (1 << 3))/* 0x03 */) >> 3); - if (tmp == 2)// 3R - { - /* Default : All ADCs will be used by QA */ - pAd->ate.RxAntennaSel = 0; - } - break; - /* The BBP R3 bit[1:0] = 1 :: ADC 1 will be used by QA. */ - case 1: - /* Antenna two */ - pAd->ate.RxAntennaSel = 2; - break; - /* The BBP R3 bit[1:0] = 2 :: ADC 2 will be used by QA. */ - case 2: - /* Antenna three */ - pAd->ate.RxAntennaSel = 3; - break; - default: - DBGPRINT(RT_DEBUG_ERROR, ("%s -- Impossible! : return FALSE; \n", __FUNCTION__)); - return FALSE; - } - break;/* case BBP_R3 */ - - default: - DBGPRINT(RT_DEBUG_ERROR, ("%s -- Sth. wrong! : return FALSE; \n", __FUNCTION__)); - return FALSE; - - } - return TRUE; -} - -static VOID memcpy_exl(PRTMP_ADAPTER pAd, UCHAR *dst, UCHAR *src, ULONG len) -{ - ULONG i, Value = 0; - ULONG *pDst, *pSrc; - UCHAR *p8; - - p8 = src; - pDst = (ULONG *) dst; - pSrc = (ULONG *) src; - - for (i = 0 ; i < (len/4); i++) - { - /* For alignment issue, we need a variable "Value". */ - memmove(&Value, pSrc, 4); - Value = htonl(Value); - memmove(pDst, &Value, 4); - pDst++; - pSrc++; - } - if ((len % 4) != 0) - { - /* wish that it will never reach here */ - memmove(&Value, pSrc, (len % 4)); - Value = htonl(Value); - memmove(pDst, &Value, (len % 4)); - } -} - -static VOID memcpy_exs(PRTMP_ADAPTER pAd, UCHAR *dst, UCHAR *src, ULONG len) -{ - ULONG i; - UCHAR *pDst, *pSrc; - - pDst = dst; - pSrc = src; - - for (i = 0; i < (len/2); i++) - { - memmove(pDst, pSrc, 2); - *((USHORT *)pDst) = htons(*((USHORT *)pDst)); - pDst+=2; - pSrc+=2; - } - - if ((len % 2) != 0) - { - memmove(pDst, pSrc, 1); - } -} - -static VOID RTMP_IO_READ_BULK(PRTMP_ADAPTER pAd, UCHAR *dst, UCHAR *src, UINT32 len) -{ - UINT32 i, Value; - UINT32 *pDst, *pSrc; - - pDst = (UINT32 *) dst; - pSrc = (UINT32 *) src; - - for (i = 0 ; i < (len/4); i++) - { - RTMP_IO_READ32(pAd, (ULONG)pSrc, &Value); - Value = htonl(Value); - memmove(pDst, &Value, 4); - pDst++; - pSrc++; - } - return; -} - -INT Set_TxStop_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ATEDBGPRINT(RT_DEBUG_TRACE,("Set_TxStop_Proc\n")); - - if (Set_ATE_Proc(pAd, "TXSTOP")) - { - return TRUE; -} - else - { - return FALSE; - } -} - -INT Set_RxStop_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - ATEDBGPRINT(RT_DEBUG_TRACE,("Set_RxStop_Proc\n")); - - if (Set_ATE_Proc(pAd, "RXSTOP")) - { - return TRUE; -} - else - { - return FALSE; - } -} -#endif // RALINK_28xx_QA // -#endif // RALINK_ATE // - diff --git a/drivers/staging/rt3070/rt_ate.h b/drivers/staging/rt3070/rt_ate.h deleted file mode 100644 index 829ebb5f7236..000000000000 --- a/drivers/staging/rt3070/rt_ate.h +++ /dev/null @@ -1,294 +0,0 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - */ - -#ifndef __ATE_H__ -#define __ATE_H__ - -#ifndef UCOS -#define ate_print printk -#define ATEDBGPRINT DBGPRINT - -#ifdef RT2870 -#define EEPROM_SIZE 0x400 -#ifdef CONFIG_STA_SUPPORT -#define EEPROM_BIN_FILE_NAME "/etc/Wireless/RT2870STA/e2p.bin" -#endif // CONFIG_STA_SUPPORT // -#endif // RT2870 // -#else // !UCOS // -#define fATE_LOAD_EEPROM 0x0C43 -#ifdef CONFIG_PRINTK -extern INT ConsoleResponse(IN PUCHAR buff); -extern int (*remote_display)(char *); -extern void puts (const char *s); - -/* specificly defined to redirect and show ate-related messages to host. */ -/* Try to define ate_print as a macro. */ -#define ate_print(fmt, args...) \ -do{ int (*org_remote_display)(char *) = NULL; \ - org_remote_display = remote_display;\ - /* Save original "remote_display" */\ - remote_display = (int (*)(char *))ConsoleResponse; \ - printk(fmt, ## args); \ - /* Restore the remote_display function pointer */ \ - remote_display = org_remote_display; }while(0) - -#define ATEDBGPRINT(Level, Fmt) \ -{ \ - if ((Level) <= RTDebugLevel) \ - { \ - ate_print Fmt; \ - } \ -} -#endif // CONFIG_PRINTK // -#endif // !UCOS // - -#define ATE_ON(_p) (((_p)->ate.Mode) != ATE_STOP) - -/* RT2880_iNIC will define "RT2860". */ - -/* RT2880_iNIC will define RT2860. */ - -#ifdef RT2870 -#define EEPROM_SIZE 0x400 -#ifdef CONFIG_STA_SUPPORT -#define EEPROM_BIN_FILE_NAME "/etc/Wireless/RT2870STA/e2p.bin" -#endif // CONFIG_STA_SUPPORT // -#endif // RT2870 // - -#ifdef RT2870 -#define ATE_BBP_IO_READ8_BY_REG_ID(_A, _I, _pV) RTMP_BBP_IO_READ8_BY_REG_ID(_A, _I, _pV) -#define ATE_BBP_IO_WRITE8_BY_REG_ID(_A, _I, _V) RTMP_BBP_IO_WRITE8_BY_REG_ID(_A, _I, _V) - -#define BULK_OUT_LOCK(pLock, IrqFlags) \ - if(1 /*!(in_interrupt() & 0xffff0000)*/) \ - RTMP_IRQ_LOCK((pLock), IrqFlags); - -#define BULK_OUT_UNLOCK(pLock, IrqFlags) \ - if(1 /*!(in_interrupt() & 0xffff0000)*/) \ - RTMP_IRQ_UNLOCK((pLock), IrqFlags); - -// Prototypes of completion funuc. -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) -#define ATE_RTUSBBulkOutDataPacketComplete(purb, pt_regs) ATE_RTUSBBulkOutDataPacketComplete(purb) -#endif - -VOID ATE_RTUSBBulkOutDataPacketComplete( - IN purbb_t purb, - OUT struct pt_regs *pt_regs); - -VOID ATE_RTUSBBulkOutDataPacket( - IN PRTMP_ADAPTER pAd, - IN UCHAR BulkOutPipeId); - -VOID ATE_RTUSBCancelPendingBulkInIRP( - IN PRTMP_ADAPTER pAd); -#endif // RT2870 // - -#ifdef RT30xx -#define ATE_RF_IO_READ8_BY_REG_ID(_A, _I, _pV) RTMP_RF_IO_READ8_BY_REG_ID(_A, _I, _pV) -#define ATE_RF_IO_WRITE8_BY_REG_ID(_A, _I, _V) RTMP_RF_IO_WRITE8_BY_REG_ID(_A, _I, _V) -#endif // RT30xx // - - -VOID rt_ee_read_all( - IN PRTMP_ADAPTER pAd, - OUT USHORT *Data); - - -VOID rt_ee_write_all( - IN PRTMP_ADAPTER pAd, - IN USHORT *Data); - -INT Set_ATE_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_DA_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_SA_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_BSSID_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_CHANNEL_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_TX_POWER0_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_TX_POWER1_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_TX_Antenna_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_RX_Antenna_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_TX_FREQOFFSET_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_TX_BW_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_TX_LENGTH_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_TX_COUNT_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_TX_MCS_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_TX_MODE_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_TX_GI_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - - -INT Set_ATE_RX_FER_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_Read_RF_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_Write_RF1_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_Write_RF2_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_Write_RF3_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_Write_RF4_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_Load_E2P_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_Read_E2P_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_Show_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ATE_Help_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -#ifdef RALINK_ATE -#ifdef RALINK_28xx_QA -VOID ATE_QA_Statistics( - IN PRTMP_ADAPTER pAd, - IN PRXWI_STRUC pRxWI, - IN PRT28XX_RXD_STRUC p28xxRxD, - IN PHEADER_802_11 pHeader); - -VOID RtmpDoAte( - IN PRTMP_ADAPTER pAdapter, - IN struct iwreq *wrq); - -VOID BubbleSort( - IN INT32 n, - IN INT32 a[]); - -VOID CalNoiseLevel( - IN PRTMP_ADAPTER pAdapter, - IN UCHAR channel, - OUT INT32 buffer[3][10]); - -BOOLEAN SyncTxRxConfig( - IN PRTMP_ADAPTER pAdapter, - IN USHORT offset, - IN UCHAR value); - -INT Set_TxStop_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_RxStop_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -#endif // RALINK_28xx_QA // -#endif // RALINK_ATE // - -VOID ATEAsicSwitchChannel( - IN PRTMP_ADAPTER pAd); - -VOID ATEAsicAdjustTxPower( - IN PRTMP_ADAPTER pAd); - -VOID ATEDisableAsicProtect( - IN PRTMP_ADAPTER pAd); - -CHAR ATEConvertToRssi( - IN PRTMP_ADAPTER pAd, - IN CHAR Rssi, - IN UCHAR RssiNumber); - -VOID ATESampleRssi( - IN PRTMP_ADAPTER pAd, - IN PRXWI_STRUC pRxWI); - - -#ifdef CONFIG_STA_SUPPORT -VOID RTMPStationStop( - IN PRTMP_ADAPTER pAd); - -VOID RTMPStationStart( - IN PRTMP_ADAPTER pAd); -#endif // CONFIG_STA_SUPPORT // -#endif // __ATE_H__ // diff --git a/drivers/staging/rt3070/rt_config.h b/drivers/staging/rt3070/rt_config.h index 9e06417f63d3..3e8fcbdd5794 100644 --- a/drivers/staging/rt3070/rt_config.h +++ b/drivers/staging/rt3070/rt_config.h @@ -1,121 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - rt_config.h - - Abstract: - Central header file to maintain all include files for all NDIS - miniport driver routines. - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Paul Lin 08-01-2002 created - -*/ -#ifndef __RT_CONFIG_H__ -#define __RT_CONFIG_H__ - -#include "rtmp_type.h" -#ifdef UCOS -#include "includes.h" -#include -#include "rt_ucos.h" -#endif - -#ifdef LINUX -#include "rt_linux.h" -#endif -#include "rtmp_def.h" -#include "rt28xx.h" - - -#ifdef RT2870 -#include "rt2870.h" -#endif // RT2870 // - -#include "oid.h" -#include "mlme.h" -#include "wpa.h" -#include "md5.h" -#include "rtmp.h" -#include "ap.h" -#include "dfs.h" -#include "chlist.h" -#include "spectrum.h" -#ifdef MLME_EX -#include "mlme_ex_def.h" -#include "mlme_ex.h" -#endif // MLME_EX // - -#undef AP_WSC_INCLUDED -#undef STA_WSC_INCLUDED -#undef WSC_INCLUDED - - -#ifdef LEAP_SUPPORT -#include "leap.h" -#endif // LEAP_SUPPORT // - -#ifdef CONFIG_STA_SUPPORT -#endif // CONFIG_STA_SUPPORT // - -#ifdef BLOCK_NET_IF -#include "netif_block.h" -#endif // BLOCK_NET_IF // - -#ifdef IGMP_SNOOP_SUPPORT -#include "igmp_snoop.h" -#endif // IGMP_SNOOP_SUPPORT // - -#ifdef RALINK_ATE -#include "rt_ate.h" -#endif // RALINK_ATE // - - - -#if defined(AP_WSC_INCLUDED) || defined(STA_WSC_INCLUDED) -#define WSC_INCLUDED -#endif - - -#ifdef CONFIG_STA_SUPPORT -#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT -#ifndef WPA_SUPPLICANT_SUPPORT -#error "Build for being controlled by NetworkManager or wext, please set HAS_WPA_SUPPLICANT=y and HAS_NATIVE_WPA_SUPPLICANT_SUPPORT=y" -#endif // WPA_SUPPLICANT_SUPPORT // -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // - -#endif // CONFIG_STA_SUPPORT // - - -#ifdef IKANOS_VX_1X0 -#include "vr_ikans.h" -#endif // IKANOS_VX_1X0 // - -#endif // __RT_CONFIG_H__ - +#include "../rt2870/rt_config.h" diff --git a/drivers/staging/rt3070/rt_linux.c b/drivers/staging/rt3070/rt_linux.c index bf3385365da1..6185f2e99924 100644 --- a/drivers/staging/rt3070/rt_linux.c +++ b/drivers/staging/rt3070/rt_linux.c @@ -1,1063 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * 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 "rt_config.h" - -ULONG RTDebugLevel = RT_DEBUG_ERROR; - -BUILD_TIMER_FUNCTION(MlmePeriodicExec); -//BUILD_TIMER_FUNCTION(MlmeRssiReportExec); -BUILD_TIMER_FUNCTION(AsicRxAntEvalTimeout); -BUILD_TIMER_FUNCTION(APSDPeriodicExec); -BUILD_TIMER_FUNCTION(AsicRfTuningExec); -#ifdef RT2870 -BUILD_TIMER_FUNCTION(BeaconUpdateExec); -#endif // RT2870 // - - -#ifdef CONFIG_STA_SUPPORT -BUILD_TIMER_FUNCTION(BeaconTimeout); -BUILD_TIMER_FUNCTION(ScanTimeout); -BUILD_TIMER_FUNCTION(AuthTimeout); -BUILD_TIMER_FUNCTION(AssocTimeout); -BUILD_TIMER_FUNCTION(ReassocTimeout); -BUILD_TIMER_FUNCTION(DisassocTimeout); -BUILD_TIMER_FUNCTION(LinkDownExec); -#ifdef LEAP_SUPPORT -BUILD_TIMER_FUNCTION(LeapAuthTimeout); -#endif -BUILD_TIMER_FUNCTION(StaQuickResponeForRateUpExec); -BUILD_TIMER_FUNCTION(WpaDisassocApAndBlockAssoc); -#ifdef QOS_DLS_SUPPORT -BUILD_TIMER_FUNCTION(DlsTimeoutAction); -#endif // QOS_DLS_SUPPORT // -#endif // CONFIG_STA_SUPPORT // - - - - -// for wireless system event message -char const *pWirelessSysEventText[IW_SYS_EVENT_TYPE_NUM] = { - // system status event - "had associated successfully", /* IW_ASSOC_EVENT_FLAG */ - "had disassociated", /* IW_DISASSOC_EVENT_FLAG */ - "had deauthenticated", /* IW_DEAUTH_EVENT_FLAG */ - "had been aged-out and disassociated", /* IW_AGEOUT_EVENT_FLAG */ - "occurred CounterMeasures attack", /* IW_COUNTER_MEASURES_EVENT_FLAG */ - "occurred replay counter different in Key Handshaking", /* IW_REPLAY_COUNTER_DIFF_EVENT_FLAG */ - "occurred RSNIE different in Key Handshaking", /* IW_RSNIE_DIFF_EVENT_FLAG */ - "occurred MIC different in Key Handshaking", /* IW_MIC_DIFF_EVENT_FLAG */ - "occurred ICV error in RX", /* IW_ICV_ERROR_EVENT_FLAG */ - "occurred MIC error in RX", /* IW_MIC_ERROR_EVENT_FLAG */ - "Group Key Handshaking timeout", /* IW_GROUP_HS_TIMEOUT_EVENT_FLAG */ - "Pairwise Key Handshaking timeout", /* IW_PAIRWISE_HS_TIMEOUT_EVENT_FLAG */ - "RSN IE sanity check failure", /* IW_RSNIE_SANITY_FAIL_EVENT_FLAG */ - "set key done in WPA/WPAPSK", /* IW_SET_KEY_DONE_WPA1_EVENT_FLAG */ - "set key done in WPA2/WPA2PSK", /* IW_SET_KEY_DONE_WPA2_EVENT_FLAG */ - "connects with our wireless client", /* IW_STA_LINKUP_EVENT_FLAG */ - "disconnects with our wireless client", /* IW_STA_LINKDOWN_EVENT_FLAG */ - "scan completed" /* IW_SCAN_COMPLETED_EVENT_FLAG */ - "scan terminate!! Busy!! Enqueue fail!!" /* IW_SCAN_ENQUEUE_FAIL_EVENT_FLAG */ - }; - -// for wireless IDS_spoof_attack event message -char const *pWirelessSpoofEventText[IW_SPOOF_EVENT_TYPE_NUM] = { - "detected conflict SSID", /* IW_CONFLICT_SSID_EVENT_FLAG */ - "detected spoofed association response", /* IW_SPOOF_ASSOC_RESP_EVENT_FLAG */ - "detected spoofed reassociation responses", /* IW_SPOOF_REASSOC_RESP_EVENT_FLAG */ - "detected spoofed probe response", /* IW_SPOOF_PROBE_RESP_EVENT_FLAG */ - "detected spoofed beacon", /* IW_SPOOF_BEACON_EVENT_FLAG */ - "detected spoofed disassociation", /* IW_SPOOF_DISASSOC_EVENT_FLAG */ - "detected spoofed authentication", /* IW_SPOOF_AUTH_EVENT_FLAG */ - "detected spoofed deauthentication", /* IW_SPOOF_DEAUTH_EVENT_FLAG */ - "detected spoofed unknown management frame", /* IW_SPOOF_UNKNOWN_MGMT_EVENT_FLAG */ - "detected replay attack" /* IW_REPLAY_ATTACK_EVENT_FLAG */ - }; - -// for wireless IDS_flooding_attack event message -char const *pWirelessFloodEventText[IW_FLOOD_EVENT_TYPE_NUM] = { - "detected authentication flooding", /* IW_FLOOD_AUTH_EVENT_FLAG */ - "detected association request flooding", /* IW_FLOOD_ASSOC_REQ_EVENT_FLAG */ - "detected reassociation request flooding", /* IW_FLOOD_REASSOC_REQ_EVENT_FLAG */ - "detected probe request flooding", /* IW_FLOOD_PROBE_REQ_EVENT_FLAG */ - "detected disassociation flooding", /* IW_FLOOD_DISASSOC_EVENT_FLAG */ - "detected deauthentication flooding", /* IW_FLOOD_DEAUTH_EVENT_FLAG */ - "detected 802.1x eap-request flooding" /* IW_FLOOD_EAP_REQ_EVENT_FLAG */ - }; - - -/* timeout -- ms */ -VOID RTMP_SetPeriodicTimer( - IN NDIS_MINIPORT_TIMER *pTimer, - IN unsigned long timeout) -{ - timeout = ((timeout*HZ) / 1000); - pTimer->expires = jiffies + timeout; - add_timer(pTimer); -} - -/* convert NdisMInitializeTimer --> RTMP_OS_Init_Timer */ -VOID RTMP_OS_Init_Timer( - IN PRTMP_ADAPTER pAd, - IN NDIS_MINIPORT_TIMER *pTimer, - IN TIMER_FUNCTION function, - IN PVOID data) -{ - init_timer(pTimer); - pTimer->data = (unsigned long)data; - pTimer->function = function; -} - - -VOID RTMP_OS_Add_Timer( - IN NDIS_MINIPORT_TIMER *pTimer, - IN unsigned long timeout) -{ - if (timer_pending(pTimer)) - return; - - timeout = ((timeout*HZ) / 1000); - pTimer->expires = jiffies + timeout; - add_timer(pTimer); -} - -VOID RTMP_OS_Mod_Timer( - IN NDIS_MINIPORT_TIMER *pTimer, - IN unsigned long timeout) -{ - timeout = ((timeout*HZ) / 1000); - mod_timer(pTimer, jiffies + timeout); -} - -VOID RTMP_OS_Del_Timer( - IN NDIS_MINIPORT_TIMER *pTimer, - OUT BOOLEAN *pCancelled) -{ - if (timer_pending(pTimer)) - { - *pCancelled = del_timer_sync(pTimer); - } - else - { - *pCancelled = TRUE; - } - -} - -VOID RTMP_OS_Release_Packet( - IN PRTMP_ADAPTER pAd, - IN PQUEUE_ENTRY pEntry) -{ - //RTMPFreeNdisPacket(pAd, (struct sk_buff *)pEntry); -} - -// Unify all delay routine by using udelay -VOID RTMPusecDelay( - IN ULONG usec) -{ - ULONG i; - - for (i = 0; i < (usec / 50); i++) - udelay(50); - - if (usec % 50) - udelay(usec % 50); -} - -void RTMP_GetCurrentSystemTime(LARGE_INTEGER *time) -{ - time->u.LowPart = jiffies; -} - -// pAd MUST allow to be NULL -NDIS_STATUS os_alloc_mem( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR *mem, - IN ULONG size) -{ - *mem = (PUCHAR) kmalloc(size, GFP_ATOMIC); - if (*mem) - return (NDIS_STATUS_SUCCESS); - else - return (NDIS_STATUS_FAILURE); -} - -// pAd MUST allow to be NULL -NDIS_STATUS os_free_mem( - IN PRTMP_ADAPTER pAd, - IN PUCHAR mem) -{ - - ASSERT(mem); - kfree(mem); - return (NDIS_STATUS_SUCCESS); -} - - -PNDIS_PACKET RTMP_AllocateFragPacketBuffer( - IN PRTMP_ADAPTER pAd, - IN ULONG Length) -{ - struct sk_buff *pkt; - - pkt = dev_alloc_skb(Length); - - if (pkt == NULL) - { - DBGPRINT(RT_DEBUG_ERROR, ("can't allocate frag rx %ld size packet\n",Length)); - } - - if (pkt) - { - RTMP_SET_PACKET_SOURCE(OSPKT_TO_RTPKT(pkt), PKTSRC_NDIS); - } - - return (PNDIS_PACKET) pkt; -} - - -PNDIS_PACKET RTMP_AllocateTxPacketBuffer( - IN PRTMP_ADAPTER pAd, - IN ULONG Length, - IN BOOLEAN Cached, - OUT PVOID *VirtualAddress) -{ - struct sk_buff *pkt; - - pkt = dev_alloc_skb(Length); - - if (pkt == NULL) - { - DBGPRINT(RT_DEBUG_ERROR, ("can't allocate tx %ld size packet\n",Length)); - } - - if (pkt) - { - RTMP_SET_PACKET_SOURCE(OSPKT_TO_RTPKT(pkt), PKTSRC_NDIS); - *VirtualAddress = (PVOID) pkt->data; - } - else - { - *VirtualAddress = (PVOID) NULL; - } - - return (PNDIS_PACKET) pkt; -} - - -VOID build_tx_packet( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket, - IN PUCHAR pFrame, - IN ULONG FrameLen) -{ - - struct sk_buff *pTxPkt; - - ASSERT(pPacket); - pTxPkt = RTPKT_TO_OSPKT(pPacket); - - NdisMoveMemory(skb_put(pTxPkt, FrameLen), pFrame, FrameLen); -} - -VOID RTMPFreeAdapter( - IN PRTMP_ADAPTER pAd) -{ - POS_COOKIE os_cookie; - int index; - - os_cookie=(POS_COOKIE)pAd->OS_Cookie; - - kfree(pAd->BeaconBuf); - - - NdisFreeSpinLock(&pAd->MgmtRingLock); - - - for (index =0 ; index < NUM_OF_TX_RING; index++) - { - NdisFreeSpinLock(&pAd->TxSwQueueLock[index]); - NdisFreeSpinLock(&pAd->DeQueueLock[index]); - pAd->DeQueueRunning[index] = FALSE; - } - - NdisFreeSpinLock(&pAd->irq_lock); - - - vfree(pAd); // pci_free_consistent(os_cookie->pci_dev,sizeof(RTMP_ADAPTER),pAd,os_cookie->pAd_pa); - kfree(os_cookie); -} - -BOOLEAN OS_Need_Clone_Packet(void) -{ - return (FALSE); -} - - - -/* - ======================================================================== - - Routine Description: - clone an input NDIS PACKET to another one. The new internally created NDIS PACKET - must have only one NDIS BUFFER - return - byte copied. 0 means can't create NDIS PACKET - NOTE: internally created NDIS_PACKET should be destroyed by RTMPFreeNdisPacket - - Arguments: - pAd Pointer to our adapter - pInsAMSDUHdr EWC A-MSDU format has extra 14-bytes header. if TRUE, insert this 14-byte hdr in front of MSDU. - *pSrcTotalLen return total packet length. This lenght is calculated with 802.3 format packet. - - Return Value: - NDIS_STATUS_SUCCESS - NDIS_STATUS_FAILURE - - Note: - - ======================================================================== -*/ -NDIS_STATUS RTMPCloneNdisPacket( - IN PRTMP_ADAPTER pAd, - IN BOOLEAN pInsAMSDUHdr, - IN PNDIS_PACKET pInPacket, - OUT PNDIS_PACKET *ppOutPacket) -{ - - struct sk_buff *pkt; - - ASSERT(pInPacket); - ASSERT(ppOutPacket); - - // 1. Allocate a packet - pkt = dev_alloc_skb(2048); - - if (pkt == NULL) - { - return NDIS_STATUS_FAILURE; - } - - skb_put(pkt, GET_OS_PKT_LEN(pInPacket)); - NdisMoveMemory(pkt->data, GET_OS_PKT_DATAPTR(pInPacket), GET_OS_PKT_LEN(pInPacket)); - *ppOutPacket = OSPKT_TO_RTPKT(pkt); - - - RTMP_SET_PACKET_SOURCE(OSPKT_TO_RTPKT(pkt), PKTSRC_NDIS); - - printk("###Clone###\n"); - - return NDIS_STATUS_SUCCESS; -} - - -// the allocated NDIS PACKET must be freed via RTMPFreeNdisPacket() -NDIS_STATUS RTMPAllocateNdisPacket( - IN PRTMP_ADAPTER pAd, - OUT PNDIS_PACKET *ppPacket, - IN PUCHAR pHeader, - IN UINT HeaderLen, - IN PUCHAR pData, - IN UINT DataLen) -{ - PNDIS_PACKET pPacket; - ASSERT(pData); - ASSERT(DataLen); - - // 1. Allocate a packet - pPacket = (PNDIS_PACKET *) dev_alloc_skb(HeaderLen + DataLen + TXPADDING_SIZE); - if (pPacket == NULL) - { - *ppPacket = NULL; -#ifdef DEBUG - printk("RTMPAllocateNdisPacket Fail\n\n"); -#endif - return NDIS_STATUS_FAILURE; - } - - // 2. clone the frame content - if (HeaderLen > 0) - NdisMoveMemory(GET_OS_PKT_DATAPTR(pPacket), pHeader, HeaderLen); - if (DataLen > 0) - NdisMoveMemory(GET_OS_PKT_DATAPTR(pPacket) + HeaderLen, pData, DataLen); - - // 3. update length of packet - skb_put(GET_OS_PKT_TYPE(pPacket), HeaderLen+DataLen); - - RTMP_SET_PACKET_SOURCE(pPacket, PKTSRC_NDIS); -// printk("%s : pPacket = %p, len = %d\n", __FUNCTION__, pPacket, GET_OS_PKT_LEN(pPacket)); - *ppPacket = pPacket; - return NDIS_STATUS_SUCCESS; -} - -/* - ======================================================================== - Description: - This routine frees a miniport internally allocated NDIS_PACKET and its - corresponding NDIS_BUFFER and allocated memory. - ======================================================================== -*/ -VOID RTMPFreeNdisPacket( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket) -{ - dev_kfree_skb_any(RTPKT_TO_OSPKT(pPacket)); -} - - -// IRQL = DISPATCH_LEVEL -// NOTE: we do have an assumption here, that Byte0 and Byte1 always reasid at the same -// scatter gather buffer -NDIS_STATUS Sniff2BytesFromNdisBuffer( - IN PNDIS_BUFFER pFirstBuffer, - IN UCHAR DesiredOffset, - OUT PUCHAR pByte0, - OUT PUCHAR pByte1) -{ - *pByte0 = *(PUCHAR)(pFirstBuffer + DesiredOffset); - *pByte1 = *(PUCHAR)(pFirstBuffer + DesiredOffset + 1); - - return NDIS_STATUS_SUCCESS; -} - - -void RTMP_QueryPacketInfo( - IN PNDIS_PACKET pPacket, - OUT PACKET_INFO *pPacketInfo, - OUT PUCHAR *pSrcBufVA, - OUT UINT *pSrcBufLen) -{ - pPacketInfo->BufferCount = 1; - pPacketInfo->pFirstBuffer = GET_OS_PKT_DATAPTR(pPacket); - pPacketInfo->PhysicalBufferCount = 1; - pPacketInfo->TotalPacketLength = GET_OS_PKT_LEN(pPacket); - - *pSrcBufVA = GET_OS_PKT_DATAPTR(pPacket); - *pSrcBufLen = GET_OS_PKT_LEN(pPacket); -} - -void RTMP_QueryNextPacketInfo( - IN PNDIS_PACKET *ppPacket, - OUT PACKET_INFO *pPacketInfo, - OUT PUCHAR *pSrcBufVA, - OUT UINT *pSrcBufLen) -{ - PNDIS_PACKET pPacket = NULL; - - if (*ppPacket) - pPacket = GET_OS_PKT_NEXT(*ppPacket); - - if (pPacket) - { - pPacketInfo->BufferCount = 1; - pPacketInfo->pFirstBuffer = GET_OS_PKT_DATAPTR(pPacket); - pPacketInfo->PhysicalBufferCount = 1; - pPacketInfo->TotalPacketLength = GET_OS_PKT_LEN(pPacket); - - *pSrcBufVA = GET_OS_PKT_DATAPTR(pPacket); - *pSrcBufLen = GET_OS_PKT_LEN(pPacket); - *ppPacket = GET_OS_PKT_NEXT(pPacket); - } - else - { - pPacketInfo->BufferCount = 0; - pPacketInfo->pFirstBuffer = NULL; - pPacketInfo->PhysicalBufferCount = 0; - pPacketInfo->TotalPacketLength = 0; - - *pSrcBufVA = NULL; - *pSrcBufLen = 0; - *ppPacket = NULL; - } -} - -// not yet support MBSS -PNET_DEV get_netdev_from_bssid( - IN PRTMP_ADAPTER pAd, - IN UCHAR FromWhichBSSID) -{ - PNET_DEV dev_p = NULL; - - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - dev_p = pAd->net_dev; - } -#endif // CONFIG_STA_SUPPORT // - - ASSERT(dev_p); - return dev_p; /* return one of MBSS */ -} - -PNDIS_PACKET DuplicatePacket( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket, - IN UCHAR FromWhichBSSID) -{ - struct sk_buff *skb; - PNDIS_PACKET pRetPacket = NULL; - USHORT DataSize; - UCHAR *pData; - - DataSize = (USHORT) GET_OS_PKT_LEN(pPacket); - pData = (PUCHAR) GET_OS_PKT_DATAPTR(pPacket); - - - skb = skb_clone(RTPKT_TO_OSPKT(pPacket), MEM_ALLOC_FLAG); - if (skb) - { - skb->dev = get_netdev_from_bssid(pAd, FromWhichBSSID); - pRetPacket = OSPKT_TO_RTPKT(skb); - } - - return pRetPacket; - -} - -PNDIS_PACKET duplicate_pkt( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pHeader802_3, - IN UINT HdrLen, - IN PUCHAR pData, - IN ULONG DataSize, - IN UCHAR FromWhichBSSID) -{ - struct sk_buff *skb; - PNDIS_PACKET pPacket = NULL; - - - if ((skb = __dev_alloc_skb(HdrLen + DataSize + 2, MEM_ALLOC_FLAG)) != NULL) - { - skb_reserve(skb, 2); - NdisMoveMemory(skb->tail, pHeader802_3, HdrLen); - skb_put(skb, HdrLen); - NdisMoveMemory(skb->tail, pData, DataSize); - skb_put(skb, DataSize); - skb->dev = get_netdev_from_bssid(pAd, FromWhichBSSID); - pPacket = OSPKT_TO_RTPKT(skb); - } - - return pPacket; -} - - -#define TKIP_TX_MIC_SIZE 8 -PNDIS_PACKET duplicate_pkt_with_TKIP_MIC( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket) -{ - struct sk_buff *skb, *newskb; - - - skb = RTPKT_TO_OSPKT(pPacket); - if (skb_tailroom(skb) < TKIP_TX_MIC_SIZE) - { - // alloc a new skb and copy the packet - newskb = skb_copy_expand(skb, skb_headroom(skb), TKIP_TX_MIC_SIZE, GFP_ATOMIC); - dev_kfree_skb_any(skb); - if (newskb == NULL) - { - DBGPRINT(RT_DEBUG_ERROR, ("Extend Tx.MIC for packet failed!, dropping packet!\n")); - return NULL; - } - skb = newskb; - } - - return OSPKT_TO_RTPKT(skb); -} - - - - -PNDIS_PACKET ClonePacket( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket, - IN PUCHAR pData, - IN ULONG DataSize) -{ - struct sk_buff *pRxPkt; - struct sk_buff *pClonedPkt; - - ASSERT(pPacket); - pRxPkt = RTPKT_TO_OSPKT(pPacket); - - // clone the packet - pClonedPkt = skb_clone(pRxPkt, MEM_ALLOC_FLAG); - - if (pClonedPkt) - { - // set the correct dataptr and data len - pClonedPkt->dev = pRxPkt->dev; - pClonedPkt->data = pData; - pClonedPkt->len = DataSize; - pClonedPkt->tail = pClonedPkt->data + pClonedPkt->len; - ASSERT(DataSize < 1530); - } - return pClonedPkt; -} - -// -// change OS packet DataPtr and DataLen -// -void update_os_packet_info( - IN PRTMP_ADAPTER pAd, - IN RX_BLK *pRxBlk, - IN UCHAR FromWhichBSSID) -{ - struct sk_buff *pOSPkt; - - ASSERT(pRxBlk->pRxPacket); - pOSPkt = RTPKT_TO_OSPKT(pRxBlk->pRxPacket); - - pOSPkt->dev = get_netdev_from_bssid(pAd, FromWhichBSSID); - pOSPkt->data = pRxBlk->pData; - pOSPkt->len = pRxBlk->DataSize; - pOSPkt->tail = pOSPkt->data + pOSPkt->len; -} - - -void wlan_802_11_to_802_3_packet( - IN PRTMP_ADAPTER pAd, - IN RX_BLK *pRxBlk, - IN PUCHAR pHeader802_3, - IN UCHAR FromWhichBSSID) -{ - struct sk_buff *pOSPkt; - - ASSERT(pRxBlk->pRxPacket); - ASSERT(pHeader802_3); - - pOSPkt = RTPKT_TO_OSPKT(pRxBlk->pRxPacket); - - pOSPkt->dev = get_netdev_from_bssid(pAd, FromWhichBSSID); - pOSPkt->data = pRxBlk->pData; - pOSPkt->len = pRxBlk->DataSize; - pOSPkt->tail = pOSPkt->data + pOSPkt->len; - - // - // copy 802.3 header - // - // - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - NdisMoveMemory(skb_push(pOSPkt, LENGTH_802_3), pHeader802_3, LENGTH_802_3); -#endif // CONFIG_STA_SUPPORT // - } - - - -void announce_802_3_packet( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket) -{ - - struct sk_buff *pRxPkt; - - ASSERT(pPacket); - - pRxPkt = RTPKT_TO_OSPKT(pPacket); - -#ifdef CONFIG_STA_SUPPORT -#endif // CONFIG_STA_SUPPORT // - - /* Push up the protocol stack */ -#ifdef IKANOS_VX_1X0 - IKANOS_DataFrameRx(pAd, pRxPkt->dev, pRxPkt, pRxPkt->len); -#else - pRxPkt->protocol = eth_type_trans(pRxPkt, pRxPkt->dev); - -//#ifdef CONFIG_5VT_ENHANCE -// *(int*)(pRxPkt->cb) = BRIDGE_TAG; -//#endif - netif_rx(pRxPkt); -#endif // IKANOS_VX_1X0 // -} - - -PRTMP_SCATTER_GATHER_LIST -rt_get_sg_list_from_packet(PNDIS_PACKET pPacket, RTMP_SCATTER_GATHER_LIST *sg) -{ - sg->NumberOfElements = 1; - sg->Elements[0].Address = GET_OS_PKT_DATAPTR(pPacket); - sg->Elements[0].Length = GET_OS_PKT_LEN(pPacket); - return (sg); -} - -void hex_dump(char *str, unsigned char *pSrcBufVA, unsigned int SrcBufLen) -{ - unsigned char *pt; - int x; - - if (RTDebugLevel < RT_DEBUG_TRACE) - return; - - pt = pSrcBufVA; - printk("%s: %p, len = %d\n",str, pSrcBufVA, SrcBufLen); - for (x=0; x= 15 - - union iwreq_data wrqu; - PUCHAR pBuf = NULL, pBufPtr = NULL; - USHORT event, type, BufLen; - UCHAR event_table_len = 0; - - type = Event_flag & 0xFF00; - event = Event_flag & 0x00FF; - - switch (type) - { - case IW_SYS_EVENT_FLAG_START: - event_table_len = IW_SYS_EVENT_TYPE_NUM; - break; - - case IW_SPOOF_EVENT_FLAG_START: - event_table_len = IW_SPOOF_EVENT_TYPE_NUM; - break; - - case IW_FLOOD_EVENT_FLAG_START: - event_table_len = IW_FLOOD_EVENT_TYPE_NUM; - break; - } - - if (event_table_len == 0) - { - DBGPRINT(RT_DEBUG_ERROR, ("%s : The type(%0x02x) is not valid.\n", __FUNCTION__, type)); - return; - } - - if (event >= event_table_len) - { - DBGPRINT(RT_DEBUG_ERROR, ("%s : The event(%0x02x) is not valid.\n", __FUNCTION__, event)); - return; - } - - //Allocate memory and copy the msg. - if((pBuf = kmalloc(IW_CUSTOM_MAX_LEN, GFP_ATOMIC)) != NULL) - { - //Prepare the payload - memset(pBuf, 0, IW_CUSTOM_MAX_LEN); - - pBufPtr = pBuf; - - if (pAddr) - pBufPtr += sprintf(pBufPtr, "(RT2860) STA(%02x:%02x:%02x:%02x:%02x:%02x) ", PRINT_MAC(pAddr)); - else if (BssIdx < MAX_MBSSID_NUM) - pBufPtr += sprintf(pBufPtr, "(RT2860) BSS(ra%d) ", BssIdx); - else - pBufPtr += sprintf(pBufPtr, "(RT2860) "); - - if (type == IW_SYS_EVENT_FLAG_START) - pBufPtr += sprintf(pBufPtr, "%s", pWirelessSysEventText[event]); - else if (type == IW_SPOOF_EVENT_FLAG_START) - pBufPtr += sprintf(pBufPtr, "%s (RSSI=%d)", pWirelessSpoofEventText[event], Rssi); - else if (type == IW_FLOOD_EVENT_FLAG_START) - pBufPtr += sprintf(pBufPtr, "%s", pWirelessFloodEventText[event]); - else - pBufPtr += sprintf(pBufPtr, "%s", "unknown event"); - - pBufPtr[pBufPtr - pBuf] = '\0'; - BufLen = pBufPtr - pBuf; - - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.flags = Event_flag; - wrqu.data.length = BufLen; - - //send wireless event - wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, pBuf); - - //DBGPRINT(RT_DEBUG_TRACE, ("%s : %s\n", __FUNCTION__, pBuf)); - - kfree(pBuf); - } - else - DBGPRINT(RT_DEBUG_ERROR, ("%s : Can't allocate memory for wireless event.\n", __FUNCTION__)); -#else - DBGPRINT(RT_DEBUG_ERROR, ("%s : The Wireless Extension MUST be v15 or newer.\n", __FUNCTION__)); -#endif /* WIRELESS_EXT >= 15 */ -} - - -#ifdef CONFIG_STA_SUPPORT -void send_monitor_packets( - IN PRTMP_ADAPTER pAd, - IN RX_BLK *pRxBlk) -{ - struct sk_buff *pOSPkt; - wlan_ng_prism2_header *ph; - int rate_index = 0; - USHORT header_len = 0; - UCHAR temp_header[40] = {0}; - - u_int32_t ralinkrate[256] = {2,4,11,22, 12,18,24,36,48,72,96, 108, 109, 110, 111, 112, 13, 26, 39, 52,78,104, 117, 130, 26, 52, 78,104, 156, 208, 234, 260, 27, 54,81,108,162, 216, 243, 270, // Last 38 - 54, 108, 162, 216, 324, 432, 486, 540, 14, 29, 43, 57, 87, 115, 130, 144, 29, 59,87,115, 173, 230,260, 288, 30, 60,90,120,180,240,270,300,60,120,180,240,360,480,540,600, 0,1,2,3,4,5,6,7,8,9,10, - 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80}; - - - ASSERT(pRxBlk->pRxPacket); - if (pRxBlk->DataSize < 10) - { - DBGPRINT(RT_DEBUG_ERROR, ("%s : Size is too small! (%d)\n", __FUNCTION__, pRxBlk->DataSize)); - goto err_free_sk_buff; - } - - if (pRxBlk->DataSize + sizeof(wlan_ng_prism2_header) > RX_BUFFER_AGGRESIZE) - { - DBGPRINT(RT_DEBUG_ERROR, ("%s : Size is too large! (%d)\n", __FUNCTION__, pRxBlk->DataSize + sizeof(wlan_ng_prism2_header))); - goto err_free_sk_buff; - } - - pOSPkt = RTPKT_TO_OSPKT(pRxBlk->pRxPacket); - pOSPkt->dev = get_netdev_from_bssid(pAd, BSS0); - if (pRxBlk->pHeader->FC.Type == BTYPE_DATA) - { - pRxBlk->DataSize -= LENGTH_802_11; - if ((pRxBlk->pHeader->FC.ToDs == 1) && - (pRxBlk->pHeader->FC.FrDs == 1)) - header_len = LENGTH_802_11_WITH_ADDR4; - else - header_len = LENGTH_802_11; - - // QOS - if (pRxBlk->pHeader->FC.SubType & 0x08) - { - header_len += 2; - // Data skip QOS contorl field - pRxBlk->DataSize -=2; - } - - // Order bit: A-Ralink or HTC+ - if (pRxBlk->pHeader->FC.Order) - { - header_len += 4; - // Data skip HTC contorl field - pRxBlk->DataSize -= 4; - } - - // Copy Header - if (header_len <= 40) - NdisMoveMemory(temp_header, pRxBlk->pData, header_len); - - // skip HW padding - if (pRxBlk->RxD.L2PAD) - pRxBlk->pData += (header_len + 2); - else - pRxBlk->pData += header_len; - } //end if - - - if (pRxBlk->DataSize < pOSPkt->len) { - skb_trim(pOSPkt,pRxBlk->DataSize); - } else { - skb_put(pOSPkt,(pRxBlk->DataSize - pOSPkt->len)); - } //end if - - if ((pRxBlk->pData - pOSPkt->data) > 0) { - skb_put(pOSPkt,(pRxBlk->pData - pOSPkt->data)); - skb_pull(pOSPkt,(pRxBlk->pData - pOSPkt->data)); - } //end if - - if (skb_headroom(pOSPkt) < (sizeof(wlan_ng_prism2_header)+ header_len)) { - if (pskb_expand_head(pOSPkt, (sizeof(wlan_ng_prism2_header) + header_len), 0, GFP_ATOMIC)) { - DBGPRINT(RT_DEBUG_ERROR, ("%s : Reallocate header size of sk_buff fail!\n", __FUNCTION__)); - goto err_free_sk_buff; - } //end if - } //end if - - if (header_len > 0) - NdisMoveMemory(skb_push(pOSPkt, header_len), temp_header, header_len); - - ph = (wlan_ng_prism2_header *) skb_push(pOSPkt, sizeof(wlan_ng_prism2_header)); - NdisZeroMemory(ph, sizeof(wlan_ng_prism2_header)); - - ph->msgcode = DIDmsg_lnxind_wlansniffrm; - ph->msglen = sizeof(wlan_ng_prism2_header); - strcpy(ph->devname, pAd->net_dev->name); - - ph->hosttime.did = DIDmsg_lnxind_wlansniffrm_hosttime; - ph->hosttime.status = 0; - ph->hosttime.len = 4; - ph->hosttime.data = jiffies; - - ph->mactime.did = DIDmsg_lnxind_wlansniffrm_mactime; - ph->mactime.status = 0; - ph->mactime.len = 0; - ph->mactime.data = 0; - - ph->istx.did = DIDmsg_lnxind_wlansniffrm_istx; - ph->istx.status = 0; - ph->istx.len = 0; - ph->istx.data = 0; - - ph->channel.did = DIDmsg_lnxind_wlansniffrm_channel; - ph->channel.status = 0; - ph->channel.len = 4; - - ph->channel.data = (u_int32_t)pAd->CommonCfg.Channel; - - ph->rssi.did = DIDmsg_lnxind_wlansniffrm_rssi; - ph->rssi.status = 0; - ph->rssi.len = 4; - ph->rssi.data = (u_int32_t)RTMPMaxRssi(pAd, ConvertToRssi(pAd, pRxBlk->pRxWI->RSSI0, RSSI_0), ConvertToRssi(pAd, pRxBlk->pRxWI->RSSI1, RSSI_1), ConvertToRssi(pAd, pRxBlk->pRxWI->RSSI2, RSSI_2));; - - ph->signal.did = DIDmsg_lnxind_wlansniffrm_signal; - ph->signal.status = 0; - ph->signal.len = 4; - ph->signal.data = 0; //rssi + noise; - - ph->noise.did = DIDmsg_lnxind_wlansniffrm_noise; - ph->noise.status = 0; - ph->noise.len = 4; - ph->noise.data = 0; - -#ifdef DOT11_N_SUPPORT - if (pRxBlk->pRxWI->PHYMODE >= MODE_HTMIX) - { - rate_index = 16 + ((UCHAR)pRxBlk->pRxWI->BW *16) + ((UCHAR)pRxBlk->pRxWI->ShortGI *32) + ((UCHAR)pRxBlk->pRxWI->MCS); - } - else -#endif // DOT11_N_SUPPORT // - if (pRxBlk->pRxWI->PHYMODE == MODE_OFDM) - rate_index = (UCHAR)(pRxBlk->pRxWI->MCS) + 4; - else - rate_index = (UCHAR)(pRxBlk->pRxWI->MCS); - if (rate_index < 0) - rate_index = 0; - if (rate_index > 255) - rate_index = 255; - - ph->rate.did = DIDmsg_lnxind_wlansniffrm_rate; - ph->rate.status = 0; - ph->rate.len = 4; - ph->rate.data = ralinkrate[rate_index]; - - ph->frmlen.did = DIDmsg_lnxind_wlansniffrm_frmlen; - ph->frmlen.status = 0; - ph->frmlen.len = 4; - ph->frmlen.data = (u_int32_t)pRxBlk->DataSize; - - - pOSPkt->pkt_type = PACKET_OTHERHOST; - pOSPkt->protocol = eth_type_trans(pOSPkt, pOSPkt->dev); - pOSPkt->ip_summed = CHECKSUM_NONE; - netif_rx(pOSPkt); - - return; - -err_free_sk_buff: - RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); - return; - -} -#endif // CONFIG_STA_SUPPORT // - - -void rtmp_os_thread_init(PUCHAR pThreadName, PVOID pNotify) -{ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) - daemonize(pThreadName /*"%s",pAd->net_dev->name*/); - - allow_signal(SIGTERM); - allow_signal(SIGKILL); - current->flags |= PF_NOFREEZE; -#else - unsigned long flags; - - daemonize(); - reparent_to_init(); - strcpy(current->comm, pThreadName); - - siginitsetinv(¤t->blocked, sigmask(SIGTERM) | sigmask(SIGKILL)); - - /* Allow interception of SIGKILL only - * Don't allow other signals to interrupt the transmission */ -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,22) - spin_lock_irqsave(¤t->sigmask_lock, flags); - flush_signals(current); - recalc_sigpending(current); - spin_unlock_irqrestore(¤t->sigmask_lock, flags); -#endif -#endif - - /* signal that we've started the thread */ - complete(pNotify); - -} - -void RTMP_IndicateMediaState( - IN PRTMP_ADAPTER pAd) -{ - if (pAd->CommonCfg.bWirelessEvent) - { - if (pAd->IndicateMediaState == NdisMediaStateConnected) - { - RTMPSendWirelessEvent(pAd, IW_STA_LINKUP_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); - } - else - { - RTMPSendWirelessEvent(pAd, IW_STA_LINKDOWN_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); - } - } -} - +#include "../rt2870/rt_linux.c" diff --git a/drivers/staging/rt3070/rt_linux.h b/drivers/staging/rt3070/rt_linux.h index 0540d02da79b..9f7efee3d609 100644 --- a/drivers/staging/rt3070/rt_linux.h +++ b/drivers/staging/rt3070/rt_linux.h @@ -1,887 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * 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. * - * * - ************************************************************************* - */ - -/***********************************************************************/ -/* */ -/* Program: rt_linux.c */ -/* Created: 4/21/2006 1:17:38 PM */ -/* Author: Wu Xi-Kun */ -/* Comments: `description` */ -/* */ -/*---------------------------------------------------------------------*/ -/* */ -/* History: */ -/* Revision 1.1 4/21/2006 1:17:38 PM xsikun */ -/* Initial revision */ -/* */ -/***********************************************************************/ - -#include "rtmp_type.h" -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#include -#include - -// load firmware -#define __KERNEL_SYSCALLS__ -#include -#include - - -#define MEM_ALLOC_FLAG (GFP_ATOMIC) //(GFP_DMA | GFP_ATOMIC) - -#ifndef IFNAMSIZ -#define IFNAMSIZ 16 -#endif - -//#define CONFIG_CKIP_SUPPORT - -#undef __inline -#define __inline static inline - -typedef int (*HARD_START_XMIT_FUNC)(struct sk_buff *skb, struct net_device *net_dev); - -// add by kathy - -#ifdef CONFIG_STA_SUPPORT - -#ifdef RT2870 -#define STA_PROFILE_PATH "/etc/Wireless/RT2870STA/RT2870STA.dat" -#define STA_RT2870_IMAGE_FILE_NAME "/etc/Wireless/RT2870STA/rt2870.bin" -#define STA_NIC_DEVICE_NAME "RT2870STA" -#define STA_DRIVER_VERSION "2.0.1.0" -#ifdef MULTIPLE_CARD_SUPPORT -#define CARD_INFO_PATH "/etc/Wireless/RT2870STA/RT2870STACard.dat" -#endif // MULTIPLE_CARD_SUPPORT // -#endif // RT2870 // - -#endif // CONFIG_STA_SUPPORT // - - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) - -#define RTMP_TIME_AFTER(a,b) \ - (typecheck(unsigned long, (unsigned long)a) && \ - typecheck(unsigned long, (unsigned long)b) && \ - ((long)(b) - (long)(a) < 0)) - -#define RTMP_TIME_AFTER_EQ(a,b) \ - (typecheck(unsigned long, (unsigned long)a) && \ - typecheck(unsigned long, (unsigned long)b) && \ - ((long)(a) - (long)(b) >= 0)) -#define RTMP_TIME_BEFORE(a,b) RTMP_TIME_AFTER_EQ(b,a) -#else -#define RTMP_TIME_AFTER(a,b) time_after(a, b) -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) -#define RT_MOD_INC_USE_COUNT() \ - if (!try_module_get(THIS_MODULE)) \ - { \ - DBGPRINT(RT_DEBUG_ERROR, ("%s: cannot reserve module\n", __FUNCTION__)); \ - return -1; \ - } - -#define RT_MOD_DEC_USE_COUNT() module_put(THIS_MODULE); -#else -#define RT_MOD_INC_USE_COUNT() MOD_INC_USE_COUNT; -#define RT_MOD_DEC_USE_COUNT() MOD_DEC_USE_COUNT; -#endif - -#define OS_HZ HZ - -#define ETH_LENGTH_OF_ADDRESS 6 - -#define IN -#define OUT - -#define NDIS_STATUS INT -#define NDIS_STATUS_SUCCESS 0x00 -#define NDIS_STATUS_FAILURE 0x01 -#define NDIS_STATUS_INVALID_DATA 0x02 -#define NDIS_STATUS_RESOURCES 0x03 - -#define MIN_NET_DEVICE_FOR_AID 0x00 //0x00~0x3f -#define MIN_NET_DEVICE_FOR_MBSSID 0x00 //0x00,0x10,0x20,0x30 -#define MIN_NET_DEVICE_FOR_WDS 0x10 //0x40,0x50,0x60,0x70 -#define MIN_NET_DEVICE_FOR_APCLI 0x20 -#define MIN_NET_DEVICE_FOR_MESH 0x30 -#ifdef CONFIG_STA_SUPPORT -#define MIN_NET_DEVICE_FOR_DLS 0x40 -#endif // CONFIG_STA_SUPPORT // - - -#ifdef CONFIG_STA_SUPPORT -#define NDIS_PACKET_TYPE_DIRECTED 0 -#define NDIS_PACKET_TYPE_MULTICAST 1 -#define NDIS_PACKET_TYPE_BROADCAST 2 -#define NDIS_PACKET_TYPE_ALL_MULTICAST 3 -#endif // CONFIG_STA_SUPPORT // - -struct os_lock { - spinlock_t lock; - unsigned long flags; -}; - - -struct os_cookie { - -#ifdef RT2870 - struct usb_device *pUsb_Dev; - - struct pid * MLMEThr_pid; - struct pid * RTUSBCmdThr_pid; - struct pid * TimerQThr_pid; -#endif // RT2870 // - - struct tasklet_struct rx_done_task; - struct tasklet_struct mgmt_dma_done_task; - struct tasklet_struct ac0_dma_done_task; - struct tasklet_struct ac1_dma_done_task; - struct tasklet_struct ac2_dma_done_task; - struct tasklet_struct ac3_dma_done_task; - struct tasklet_struct hcca_dma_done_task; - struct tasklet_struct tbtt_task; -#ifdef RT2870 - struct tasklet_struct null_frame_complete_task; - struct tasklet_struct rts_frame_complete_task; - struct tasklet_struct pspoll_frame_complete_task; -#endif // RT2870 // - - - unsigned long apd_pid; //802.1x daemon pid - INT ioctl_if_type; - INT ioctl_if; -}; - -typedef struct _VIRTUAL_ADAPTER -{ - struct net_device *RtmpDev; - struct net_device *VirtualDev; -} VIRTUAL_ADAPTER, PVIRTUAL_ADAPTER; - -#undef ASSERT -#define ASSERT(x) \ -{ \ - if (!(x)) \ - { \ - printk(KERN_WARNING __FILE__ ":%d assert " #x "failed\n", __LINE__); \ - } \ -} - -typedef struct os_cookie * POS_COOKIE; -typedef struct pci_dev * PPCI_DEV; -typedef struct net_device * PNET_DEV; -typedef void * PNDIS_PACKET; -typedef char NDIS_PACKET; -typedef PNDIS_PACKET * PPNDIS_PACKET; -typedef dma_addr_t NDIS_PHYSICAL_ADDRESS; -typedef dma_addr_t * PNDIS_PHYSICAL_ADDRESS; -//typedef struct timer_list RALINK_TIMER_STRUCT; -//typedef struct timer_list * PRALINK_TIMER_STRUCT; -//typedef struct os_lock NDIS_SPIN_LOCK; -typedef spinlock_t NDIS_SPIN_LOCK; -typedef struct timer_list NDIS_MINIPORT_TIMER; -typedef void * NDIS_HANDLE; -typedef char * PNDIS_BUFFER; - - - -void hex_dump(char *str, unsigned char *pSrcBufVA, unsigned int SrcBufLen); - -dma_addr_t linux_pci_map_single(void *handle, void *ptr, size_t size, int sd_idx, int direction); -void linux_pci_unmap_single(void *handle, dma_addr_t dma_addr, size_t size, int direction); - - -//////////////////////////////////////// -// MOVE TO rtmp.h ? -///////////////////////////////////////// -#define PKTSRC_NDIS 0x7f -#define PKTSRC_DRIVER 0x0f -#define PRINT_MAC(addr) \ - addr[0], addr[1], addr[2], addr[3], addr[4], addr[5] - - -#define RT2860_PCI_DEVICE_ID 0x0601 - -#ifdef RT2870 -#define PCI_MAP_SINGLE(_handle, _ptr, _size, _dir) (ULONG)0 - -#define PCI_UNMAP_SINGLE(_handle, _ptr, _size, _dir) -#endif // RT2870 // - - -#define BEACON_FRAME_DMA_CACHE_WBACK(_ptr, _size) \ - dma_cache_wback(_ptr, _size) - - -////////////////////////////////////////// -// -////////////////////////////////////////// - - -#define NdisMIndicateStatus(_w, _x, _y, _z) - - -typedef struct timer_list RTMP_OS_TIMER; - -#ifdef RT2870 -/* ----------------- Timer Related MARCO ---------------*/ -// In RT2870, we have a lot of timer functions and will read/write register, it's -// not allowed in Linux USB sub-system to do it ( because of sleep issue when submit -// to ctrl pipe). So we need a wrapper function to take care it. - -typedef VOID (*RT2870_TIMER_HANDLE)( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); -#endif // RT2870 // - - -typedef struct _RALINK_TIMER_STRUCT { - RTMP_OS_TIMER TimerObj; // Ndis Timer object - BOOLEAN Valid; // Set to True when call RTMPInitTimer - BOOLEAN State; // True if timer cancelled - BOOLEAN PeriodicType; // True if timer is periodic timer - BOOLEAN Repeat; // True if periodic timer - ULONG TimerValue; // Timer value in milliseconds - ULONG cookie; // os specific object -#ifdef RT2870 - RT2870_TIMER_HANDLE handle; - void *pAd; -#endif // RT2870 // -} RALINK_TIMER_STRUCT, *PRALINK_TIMER_STRUCT; - - -#ifdef RT2870 - -typedef enum _RT2870_KERNEL_THREAD_STATUS_ -{ - RT2870_THREAD_UNKNOWN = 0, - RT2870_THREAD_INITED = 1, - RT2870_THREAD_RUNNING = 2, - RT2870_THREAD_STOPED = 4, -}RT2870_KERNEL_THREAD_STATUS; - -#define RT2870_THREAD_CAN_DO_INSERT (RT2870_THREAD_INITED |RT2870_THREAD_RUNNING) - -typedef struct _RT2870_TIMER_ENTRY_ -{ - RALINK_TIMER_STRUCT *pRaTimer; - struct _RT2870_TIMER_ENTRY_ *pNext; -}RT2870_TIMER_ENTRY; - - -#define TIMER_QUEUE_SIZE_MAX 128 -typedef struct _RT2870_TIMER_QUEUE_ -{ - unsigned int status; - //wait_queue_head_t timerWaitQ; - //atomic_t count; - UCHAR *pTimerQPoll; - RT2870_TIMER_ENTRY *pQPollFreeList; - RT2870_TIMER_ENTRY *pQHead; - RT2870_TIMER_ENTRY *pQTail; -}RT2870_TIMER_QUEUE; -#endif // RT2870 // - - -//#define DBG 1 - -// -// MACRO for debugging information -// - -#ifdef DBG -extern ULONG RTDebugLevel; - -#define DBGPRINT_RAW(Level, Fmt) \ -{ \ - if (Level <= RTDebugLevel) \ - { \ - printk Fmt; \ - } \ -} - -#define DBGPRINT(Level, Fmt) DBGPRINT_RAW(Level, Fmt) - - -#define DBGPRINT_ERR(Fmt) \ -{ \ - printk("ERROR!!! "); \ - printk Fmt; \ -} - -#define DBGPRINT_S(Status, Fmt) \ -{ \ - printk Fmt; \ -} - - -#else -#define DBGPRINT(Level, Fmt) -#define DBGPRINT_RAW(Level, Fmt) -#define DBGPRINT_S(Status, Fmt) -#define DBGPRINT_ERR(Fmt) -#endif - - -// -// spin_lock enhanced for Nested spin lock -// -#define NdisAllocateSpinLock(__lock) \ -{ \ - spin_lock_init((spinlock_t *)(__lock)); \ -} - -#define NdisFreeSpinLock(lock) \ -{ \ -} - - -#define RTMP_SEM_LOCK(__lock) \ -{ \ - spin_lock_bh((spinlock_t *)(__lock)); \ -} - -#define RTMP_SEM_UNLOCK(__lock) \ -{ \ - spin_unlock_bh((spinlock_t *)(__lock)); \ -} - -// sample, use semaphore lock to replace IRQ lock, 2007/11/15 -#define RTMP_IRQ_LOCK(__lock, __irqflags) \ -{ \ - __irqflags = 0; \ - spin_lock_bh((spinlock_t *)(__lock)); \ - pAd->irq_disabled |= 1; \ -} - -#define RTMP_IRQ_UNLOCK(__lock, __irqflag) \ -{ \ - pAd->irq_disabled &= 0; \ - spin_unlock_bh((spinlock_t *)(__lock)); \ -} - -#define RTMP_INT_LOCK(__lock, __irqflags) \ -{ \ - spin_lock_irqsave((spinlock_t *)__lock, __irqflags); \ -} - -#define RTMP_INT_UNLOCK(__lock, __irqflag) \ -{ \ - spin_unlock_irqrestore((spinlock_t *)(__lock), ((unsigned long)__irqflag)); \ -} - -#ifdef RT2870 -#define RTMP_IO_READ32(_A, _R, _pV) \ - RTUSBReadMACRegister(_A, _R, _pV) - -#define RTMP_IO_READ8(_A, _R, _pV) \ -{ \ -} - -#define RTMP_IO_WRITE32(_A, _R, _V) \ - RTUSBWriteMACRegister(_A, _R, _V) - - -#define RTMP_IO_WRITE8(_A, _R, _V) \ -{ \ - USHORT _Val = _V; \ - RTUSBSingleWrite(_A, _R, _Val); \ -} - - -#define RTMP_IO_WRITE16(_A, _R, _V) \ -{ \ - RTUSBSingleWrite(_A, _R, _V); \ -} -#endif // RT2870 // - -#ifndef wait_event_interruptible_timeout -#define __wait_event_interruptible_timeout(wq, condition, ret) \ -do { \ - wait_queue_t __wait; \ - init_waitqueue_entry(&__wait, current); \ - add_wait_queue(&wq, &__wait); \ - for (;;) { \ - set_current_state(TASK_INTERRUPTIBLE); \ - if (condition) \ - break; \ - if (!signal_pending(current)) { \ - ret = schedule_timeout(ret); \ - if (!ret) \ - break; \ - continue; \ - } \ - ret = -ERESTARTSYS; \ - break; \ - } \ - current->state = TASK_RUNNING; \ - remove_wait_queue(&wq, &__wait); \ -} while (0) - -#define wait_event_interruptible_timeout(wq, condition, timeout) \ -({ \ - long __ret = timeout; \ - if (!(condition)) \ - __wait_event_interruptible_timeout(wq, condition, __ret); \ - __ret; \ -}) -#endif -#define ONE_TICK 1 -#define OS_WAIT(_time) \ -{ int _i; \ - long _loop = ((_time)/(1000/OS_HZ)) > 0 ? ((_time)/(1000/OS_HZ)) : 1;\ - wait_queue_head_t _wait; \ - init_waitqueue_head(&_wait); \ - for (_i=0; _i<(_loop); _i++) \ - wait_event_interruptible_timeout(_wait, 0, ONE_TICK); } - - -/* Modified by Wu Xi-Kun 4/21/2006 */ -typedef void (*TIMER_FUNCTION)(unsigned long); - -#define COPY_MAC_ADDR(Addr1, Addr2) memcpy((Addr1), (Addr2), MAC_ADDR_LEN) - -#define MlmeAllocateMemory(_pAd, _ppVA) os_alloc_mem(_pAd, _ppVA, MGMT_DMA_BUFFER_SIZE) -#define MlmeFreeMemory(_pAd, _pVA) os_free_mem(_pAd, _pVA) - - -#ifdef RT2870 -#define BUILD_TIMER_FUNCTION(_func) \ -void linux_##_func(unsigned long data) \ -{ \ - PRALINK_TIMER_STRUCT _pTimer = (PRALINK_TIMER_STRUCT)data; \ - RT2870_TIMER_ENTRY *_pQNode; \ - RTMP_ADAPTER *_pAd; \ - \ - _pTimer->handle = _func; \ - _pAd = (RTMP_ADAPTER *)_pTimer->pAd; \ - _pQNode = RT2870_TimerQ_Insert(_pAd, _pTimer); \ - if ((_pQNode == NULL) && (_pAd->TimerQ.status & RT2870_THREAD_CAN_DO_INSERT)) \ - RTMP_OS_Add_Timer(&_pTimer->TimerObj, HZ); \ -} -#endif // RT2870 // - - -#define DECLARE_TIMER_FUNCTION(_func) \ -void linux_##_func(unsigned long data) - -#define GET_TIMER_FUNCTION(_func) \ - linux_##_func - -DECLARE_TIMER_FUNCTION(MlmePeriodicExec); -DECLARE_TIMER_FUNCTION(MlmeRssiReportExec); -DECLARE_TIMER_FUNCTION(AsicRxAntEvalTimeout); -DECLARE_TIMER_FUNCTION(APSDPeriodicExec); -DECLARE_TIMER_FUNCTION(AsicRfTuningExec); -#ifdef RT2870 -DECLARE_TIMER_FUNCTION(BeaconUpdateExec); -#endif // RT2870 // - - -#ifdef CONFIG_STA_SUPPORT -DECLARE_TIMER_FUNCTION(BeaconTimeout); -DECLARE_TIMER_FUNCTION(ScanTimeout); -DECLARE_TIMER_FUNCTION(AuthTimeout); -DECLARE_TIMER_FUNCTION(AssocTimeout); -DECLARE_TIMER_FUNCTION(ReassocTimeout); -DECLARE_TIMER_FUNCTION(DisassocTimeout); -DECLARE_TIMER_FUNCTION(LinkDownExec); -#ifdef LEAP_SUPPORT -DECLARE_TIMER_FUNCTION(LeapAuthTimeout); -#endif -DECLARE_TIMER_FUNCTION(StaQuickResponeForRateUpExec); -DECLARE_TIMER_FUNCTION(WpaDisassocApAndBlockAssoc); -DECLARE_TIMER_FUNCTION(PsPollWakeExec); -DECLARE_TIMER_FUNCTION(RadioOnExec); - -#ifdef QOS_DLS_SUPPORT -DECLARE_TIMER_FUNCTION(DlsTimeoutAction); -#endif // QOS_DLS_SUPPORT // -#endif // CONFIG_STA_SUPPORT // - -#undef AP_WSC_INCLUDED -#undef STA_WSC_INCLUDED -#undef WSC_INCLUDED - - -#ifdef CONFIG_STA_SUPPORT -#endif // CONFIG_STA_SUPPORT // - -#if defined(AP_WSC_INCLUDED) || defined(STA_WSC_INCLUDED) -#define WSC_INCLUDED -#endif - - - -void RTMP_GetCurrentSystemTime(LARGE_INTEGER *time); - - -/* - * packet helper - * - convert internal rt packet to os packet or - * os packet to rt packet - */ -#define RTPKT_TO_OSPKT(_p) ((struct sk_buff *)(_p)) -#define OSPKT_TO_RTPKT(_p) ((PNDIS_PACKET)(_p)) - -#define GET_OS_PKT_DATAPTR(_pkt) \ - (RTPKT_TO_OSPKT(_pkt)->data) - -#define GET_OS_PKT_LEN(_pkt) \ - (RTPKT_TO_OSPKT(_pkt)->len) - -#define GET_OS_PKT_DATATAIL(_pkt) \ - (RTPKT_TO_OSPKT(_pkt)->tail) - -#define GET_OS_PKT_HEAD(_pkt) \ - (RTPKT_TO_OSPKT(_pkt)->head) - -#define GET_OS_PKT_END(_pkt) \ - (RTPKT_TO_OSPKT(_pkt)->end) - -#define GET_OS_PKT_NETDEV(_pkt) \ - (RTPKT_TO_OSPKT(_pkt)->dev) - -#define GET_OS_PKT_TYPE(_pkt) \ - (RTPKT_TO_OSPKT(_pkt)) - -#define GET_OS_PKT_NEXT(_pkt) \ - (RTPKT_TO_OSPKT(_pkt)->next) - - -#define OS_NTOHS(_Val) \ - (ntohs(_Val)) -#define OS_HTONS(_Val) \ - (htons(_Val)) -#define OS_NTOHL(_Val) \ - (ntohl(_Val)) -#define OS_HTONL(_Val) \ - (htonl(_Val)) - -/* statistics counter */ -#define STATS_INC_RX_PACKETS(_pAd, _dev) -#define STATS_INC_TX_PACKETS(_pAd, _dev) - -#define STATS_INC_RX_BYTESS(_pAd, _dev, len) -#define STATS_INC_TX_BYTESS(_pAd, _dev, len) - -#define STATS_INC_RX_ERRORS(_pAd, _dev) -#define STATS_INC_TX_ERRORS(_pAd, _dev) - -#define STATS_INC_RX_DROPPED(_pAd, _dev) -#define STATS_INC_TX_DROPPED(_pAd, _dev) - - -#define CB_OFF 10 - - -// check DDK NDIS_PACKET data structure and find out only MiniportReservedEx[0..7] can be used by our driver without -// ambiguity. Fields after pPacket->MiniportReservedEx[8] may be used by other wrapper layer thus crashes the driver -// -//#define RTMP_GET_PACKET_MR(_p) (RTPKT_TO_OSPKT(_p)) - -// User Priority -#define RTMP_SET_PACKET_UP(_p, _prio) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+0] = _prio) -#define RTMP_GET_PACKET_UP(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+0]) - -// Fragment # -#define RTMP_SET_PACKET_FRAGMENTS(_p, _num) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+1] = _num) -#define RTMP_GET_PACKET_FRAGMENTS(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+1]) - -// 0x0 ~0x7f: TX to AP's own BSS which has the specified AID. if AID>127, set bit 7 in RTMP_SET_PACKET_EMACTAB too. -//(this value also as MAC(on-chip WCID) table index) -// 0x80~0xff: TX to a WDS link. b0~6: WDS index -#define RTMP_SET_PACKET_WCID(_p, _wdsidx) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+2] = _wdsidx) -#define RTMP_GET_PACKET_WCID(_p) ((UCHAR)(RTPKT_TO_OSPKT(_p)->cb[CB_OFF+2])) - -// 0xff: PKTSRC_NDIS, others: local TX buffer index. This value affects how to a packet -#define RTMP_SET_PACKET_SOURCE(_p, _pktsrc) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+3] = _pktsrc) -#define RTMP_GET_PACKET_SOURCE(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+3]) - -// RTS/CTS-to-self protection method -#define RTMP_SET_PACKET_RTS(_p, _num) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+4] = _num) -#define RTMP_GET_PACKET_RTS(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+4]) -// see RTMP_S(G)ET_PACKET_EMACTAB - -// TX rate index -#define RTMP_SET_PACKET_TXRATE(_p, _rate) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+5] = _rate) -#define RTMP_GET_PACKET_TXRATE(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+5]) - -// From which Interface -#define RTMP_SET_PACKET_IF(_p, _ifdx) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+6] = _ifdx) -#define RTMP_GET_PACKET_IF(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+6]) -#define RTMP_SET_PACKET_NET_DEVICE_MBSSID(_p, _bss) RTMP_SET_PACKET_IF((_p), (_bss)) -#define RTMP_SET_PACKET_NET_DEVICE_WDS(_p, _bss) RTMP_SET_PACKET_IF((_p), ((_bss) + MIN_NET_DEVICE_FOR_WDS)) -#define RTMP_SET_PACKET_NET_DEVICE_APCLI(_p, _idx) RTMP_SET_PACKET_IF((_p), ((_idx) + MIN_NET_DEVICE_FOR_APCLI)) -#define RTMP_SET_PACKET_NET_DEVICE_MESH(_p, _idx) RTMP_SET_PACKET_IF((_p), ((_idx) + MIN_NET_DEVICE_FOR_MESH)) -#define RTMP_GET_PACKET_NET_DEVICE_MBSSID(_p) RTMP_GET_PACKET_IF((_p)) -#define RTMP_GET_PACKET_NET_DEVICE(_p) RTMP_GET_PACKET_IF((_p)) - -#define RTMP_SET_PACKET_MOREDATA(_p, _morebit) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+7] = _morebit) -#define RTMP_GET_PACKET_MOREDATA(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+7]) - -//#define RTMP_SET_PACKET_NET_DEVICE_MBSSID(_p, _bss) (RTPKT_TO_OSPKT(_p)->cb[8] = _bss) -//#define RTMP_GET_PACKET_NET_DEVICE_MBSSID(_p) (RTPKT_TO_OSPKT(_p)->cb[8]) - -// -// Sepcific Pakcet Type definition -// -#define RTMP_PACKET_SPECIFIC_CB_OFFSET 11 - -#define RTMP_PACKET_SPECIFIC_DHCP 0x01 -#define RTMP_PACKET_SPECIFIC_EAPOL 0x02 -#define RTMP_PACKET_SPECIFIC_IPV4 0x04 -#define RTMP_PACKET_SPECIFIC_WAI 0x08 -#define RTMP_PACKET_SPECIFIC_VLAN 0x10 -#define RTMP_PACKET_SPECIFIC_LLCSNAP 0x20 - -//Specific -#define RTMP_SET_PACKET_SPECIFIC(_p, _flg) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11] = _flg) - -//DHCP -#define RTMP_SET_PACKET_DHCP(_p, _flg) \ - do{ \ - if (_flg) \ - (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) |= (RTMP_PACKET_SPECIFIC_DHCP); \ - else \ - (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) &= (!RTMP_PACKET_SPECIFIC_DHCP); \ - }while(0) -#define RTMP_GET_PACKET_DHCP(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11] & RTMP_PACKET_SPECIFIC_DHCP) - -//EAPOL -#define RTMP_SET_PACKET_EAPOL(_p, _flg) \ - do{ \ - if (_flg) \ - (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) |= (RTMP_PACKET_SPECIFIC_EAPOL); \ - else \ - (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) &= (!RTMP_PACKET_SPECIFIC_EAPOL); \ - }while(0) -#define RTMP_GET_PACKET_EAPOL(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11] & RTMP_PACKET_SPECIFIC_EAPOL) - -//WAI -#define RTMP_SET_PACKET_WAI(_p, _flg) \ - do{ \ - if (_flg) \ - (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) |= (RTMP_PACKET_SPECIFIC_WAI); \ - else \ - (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) &= (!RTMP_PACKET_SPECIFIC_WAI); \ - }while(0) -#define RTMP_GET_PACKET_WAI(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11] & RTMP_PACKET_SPECIFIC_WAI) - -#define RTMP_GET_PACKET_LOWRATE(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11] & (RTMP_PACKET_SPECIFIC_EAPOL | RTMP_PACKET_SPECIFIC_DHCP | RTMP_PACKET_SPECIFIC_WAI)) - -//VLAN -#define RTMP_SET_PACKET_VLAN(_p, _flg) \ - do{ \ - if (_flg) \ - (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) |= (RTMP_PACKET_SPECIFIC_VLAN); \ - else \ - (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) &= (!RTMP_PACKET_SPECIFIC_VLAN); \ - }while(0) -#define RTMP_GET_PACKET_VLAN(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11] & RTMP_PACKET_SPECIFIC_VLAN) - -//LLC/SNAP -#define RTMP_SET_PACKET_LLCSNAP(_p, _flg) \ - do{ \ - if (_flg) \ - (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) |= (RTMP_PACKET_SPECIFIC_LLCSNAP); \ - else \ - (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) &= (!RTMP_PACKET_SPECIFIC_LLCSNAP); \ - }while(0) - -#define RTMP_GET_PACKET_LLCSNAP(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11] & RTMP_PACKET_SPECIFIC_LLCSNAP) - -// IP -#define RTMP_SET_PACKET_IPV4(_p, _flg) \ - do{ \ - if (_flg) \ - (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) |= (RTMP_PACKET_SPECIFIC_IPV4); \ - else \ - (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) &= (!RTMP_PACKET_SPECIFIC_IPV4); \ - }while(0) - -#define RTMP_GET_PACKET_IPV4(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11] & RTMP_PACKET_SPECIFIC_IPV4) - -// If this flag is set, it indicates that this EAPoL frame MUST be clear. -#define RTMP_SET_PACKET_CLEAR_EAP_FRAME(_p, _flg) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+12] = _flg) -#define RTMP_GET_PACKET_CLEAR_EAP_FRAME(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+12]) - -#define RTMP_SET_PACKET_5VT(_p, _flg) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+22] = _flg) -#define RTMP_GET_PACKET_5VT(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+22]) - - -#ifdef INF_AMAZON_SE -/*Iverson patch for WMM A5-T07 ,WirelessStaToWirelessSta do not bulk out aggregate */ -#define RTMP_SET_PACKET_NOBULKOUT(_p, _morebit) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+23] = _morebit) -#define RTMP_GET_PACKET_NOBULKOUT(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+23]) -#endif // INF_AMAZON_SE // - - - -#ifdef CONFIG_5VT_ENHANCE -#define BRIDGE_TAG 0x35564252 // depends on 5VT define in br_input.c -#endif - - -#define NDIS_SET_PACKET_STATUS(_p, _status) - - -#define GET_SG_LIST_FROM_PACKET(_p, _sc) \ - rt_get_sg_list_from_packet(_p, _sc) - -#define NdisMoveMemory(Destination, Source, Length) memmove(Destination, Source, Length) -#define NdisZeroMemory(Destination, Length) memset(Destination, 0, Length) -#define NdisFillMemory(Destination, Length, Fill) memset(Destination, Fill, Length) -#define NdisEqualMemory(Source1, Source2, Length) (!memcmp(Source1, Source2, Length)) -#define RTMPEqualMemory(Source1, Source2, Length) (!memcmp(Source1, Source2, Length)) - - -#define RTMP_INC_REF(_A) 0 -#define RTMP_DEC_REF(_A) 0 -#define RTMP_GET_REF(_A) 0 - - - -/* - * ULONG - * RTMP_GetPhysicalAddressLow( - * IN NDIS_PHYSICAL_ADDRESS PhysicalAddress); - */ -#define RTMP_GetPhysicalAddressLow(PhysicalAddress) (PhysicalAddress) - -/* - * ULONG - * RTMP_GetPhysicalAddressHigh( - * IN NDIS_PHYSICAL_ADDRESS PhysicalAddress); - */ -#define RTMP_GetPhysicalAddressHigh(PhysicalAddress) (0) - -/* - * VOID - * RTMP_SetPhysicalAddressLow( - * IN NDIS_PHYSICAL_ADDRESS PhysicalAddress, - * IN ULONG Value); - */ -#define RTMP_SetPhysicalAddressLow(PhysicalAddress, Value) \ - PhysicalAddress = Value; - -/* - * VOID - * RTMP_SetPhysicalAddressHigh( - * IN NDIS_PHYSICAL_ADDRESS PhysicalAddress, - * IN ULONG Value); - */ -#define RTMP_SetPhysicalAddressHigh(PhysicalAddress, Value) - - -//CONTAINING_RECORD(pEntry, NDIS_PACKET, MiniportReservedEx); -#define QUEUE_ENTRY_TO_PACKET(pEntry) \ - (PNDIS_PACKET)(pEntry) - -#define PACKET_TO_QUEUE_ENTRY(pPacket) \ - (PQUEUE_ENTRY)(pPacket) - - -#ifndef CONTAINING_RECORD -#define CONTAINING_RECORD(address, type, field) \ -((type *)((PCHAR)(address) - offsetof(type, field))) -#endif - - -#define RELEASE_NDIS_PACKET(_pAd, _pPacket, _Status) \ -{ \ - RTMPFreeNdisPacket(_pAd, _pPacket); \ -} - - -#define SWITCH_PhyAB(_pAA, _pBB) \ -{ \ - ULONG AABasePaHigh; \ - ULONG AABasePaLow; \ - ULONG BBBasePaHigh; \ - ULONG BBBasePaLow; \ - BBBasePaHigh = RTMP_GetPhysicalAddressHigh(_pBB); \ - BBBasePaLow = RTMP_GetPhysicalAddressLow(_pBB); \ - AABasePaHigh = RTMP_GetPhysicalAddressHigh(_pAA); \ - AABasePaLow = RTMP_GetPhysicalAddressLow(_pAA); \ - RTMP_SetPhysicalAddressHigh(_pAA, BBBasePaHigh); \ - RTMP_SetPhysicalAddressLow(_pAA, BBBasePaLow); \ - RTMP_SetPhysicalAddressHigh(_pBB, AABasePaHigh); \ - RTMP_SetPhysicalAddressLow(_pBB, AABasePaLow); \ -} - - -#define NdisWriteErrorLogEntry(_a, _b, _c, _d) -#define NdisMAllocateMapRegisters(_a, _b, _c, _d, _e) NDIS_STATUS_SUCCESS - - -#define NdisAcquireSpinLock RTMP_SEM_LOCK -#define NdisReleaseSpinLock RTMP_SEM_UNLOCK - -static inline void NdisGetSystemUpTime(ULONG *time) -{ - *time = jiffies; -} - -//pPacket = CONTAINING_RECORD(pEntry, NDIS_PACKET, MiniportReservedEx); -#define QUEUE_ENTRY_TO_PKT(pEntry) \ - ((PNDIS_PACKET) (pEntry)) - -int rt28xx_packet_xmit(struct sk_buff *skb); - - - -void rtmp_os_thread_init(PUCHAR pThreadName, PVOID pNotify); - - - +#include "../../rt2870/rt_linux.h" diff --git a/drivers/staging/rt3070/rt_main_dev.c b/drivers/staging/rt3070/rt_main_dev.c index 81f769cf1096..c8bcd4029c3c 100644 --- a/drivers/staging/rt3070/rt_main_dev.c +++ b/drivers/staging/rt3070/rt_main_dev.c @@ -1,1801 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - rt_main_dev.c - - Abstract: - Create and register network interface. - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Sample Mar/21/07 Merge RT2870 and RT2860 drivers. -*/ - -#include "rt_config.h" - -#define FORTY_MHZ_INTOLERANT_INTERVAL (60*1000) // 1 min - -#ifdef MULTIPLE_CARD_SUPPORT -// record whether the card in the card list is used in the card file -UINT8 MC_CardUsed[MAX_NUM_OF_MULTIPLE_CARD]; -// record used card mac address in the card list -static UINT8 MC_CardMac[MAX_NUM_OF_MULTIPLE_CARD][6]; -#endif // MULTIPLE_CARD_SUPPORT // - -#ifdef CONFIG_APSTA_MIXED_SUPPORT -UINT32 CW_MAX_IN_BITS; -#endif // CONFIG_APSTA_MIXED_SUPPORT // - -/*---------------------------------------------------------------------*/ -/* Private Variables Used */ -/*---------------------------------------------------------------------*/ -//static RALINK_TIMER_STRUCT PeriodicTimer; - -char *mac = ""; // default 00:00:00:00:00:00 -char *hostname = ""; // default CMPC -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,12) -MODULE_PARM (mac, "s"); -#else -module_param (mac, charp, 0); -#endif -MODULE_PARM_DESC (mac, "rt28xx: wireless mac addr"); - - -/*---------------------------------------------------------------------*/ -/* Prototypes of Functions Used */ -/*---------------------------------------------------------------------*/ -#ifdef DOT11_N_SUPPORT -extern BOOLEAN ba_reordering_resource_init(PRTMP_ADAPTER pAd, int num); -extern void ba_reordering_resource_release(PRTMP_ADAPTER pAd); -#endif // DOT11_N_SUPPORT // -extern NDIS_STATUS NICLoadRateSwitchingParams(IN PRTMP_ADAPTER pAd); - - -// public function prototype -INT __devinit rt28xx_probe(IN void *_dev_p, IN void *_dev_id_p, - IN UINT argc, OUT PRTMP_ADAPTER *ppAd); - -// private function prototype -static int rt28xx_init(IN struct net_device *net_dev); -INT rt28xx_send_packets(IN struct sk_buff *skb_p, IN struct net_device *net_dev); - -#if LINUX_VERSION_CODE <= 0x20402 // Red Hat 7.1 -struct net_device *alloc_netdev( - int sizeof_priv, - const char *mask, - void (*setup)(struct net_device *)); -#endif // LINUX_VERSION_CODE // - -static void CfgInitHook(PRTMP_ADAPTER pAd); -//static BOOLEAN RT28XXAvailRANameAssign(IN CHAR *name_p); - -#ifdef CONFIG_STA_SUPPORT -extern const struct iw_handler_def rt28xx_iw_handler_def; -#endif // CONFIG_STA_SUPPORT // - -#ifdef CONFIG_APSTA_MIXED_SUPPORT -extern const struct iw_handler_def rt28xx_ap_iw_handler_def; -#endif // CONFIG_APSTA_MIXED_SUPPORT // - -#if WIRELESS_EXT >= 12 -// This function will be called when query /proc -struct iw_statistics *rt28xx_get_wireless_stats( - IN struct net_device *net_dev); -#endif - -struct net_device_stats *RT28xx_get_ether_stats( - IN struct net_device *net_dev); - -/* -======================================================================== -Routine Description: - Close raxx interface. - -Arguments: - *net_dev the raxx interface pointer - -Return Value: - 0 Open OK - otherwise Open Fail - -Note: - 1. if open fail, kernel will not call the close function. - 2. Free memory for - (1) Mlme Memory Handler: MlmeHalt() - (2) TX & RX: RTMPFreeTxRxRingMemory() - (3) BA Reordering: ba_reordering_resource_release() -======================================================================== -*/ -int MainVirtualIF_close(IN struct net_device *net_dev) -{ - RTMP_ADAPTER *pAd = net_dev->ml_priv; - - // Sanity check for pAd - if (pAd == NULL) - return 0; // close ok - - netif_carrier_off(pAd->net_dev); - netif_stop_queue(pAd->net_dev); - - - - VIRTUAL_IF_DOWN(pAd); - - RT_MOD_DEC_USE_COUNT(); - - return 0; // close ok -} - -/* -======================================================================== -Routine Description: - Open raxx interface. - -Arguments: - *net_dev the raxx interface pointer - -Return Value: - 0 Open OK - otherwise Open Fail - -Note: - 1. if open fail, kernel will not call the close function. - 2. Free memory for - (1) Mlme Memory Handler: MlmeHalt() - (2) TX & RX: RTMPFreeTxRxRingMemory() - (3) BA Reordering: ba_reordering_resource_release() -======================================================================== -*/ -int MainVirtualIF_open(IN struct net_device *net_dev) -{ - RTMP_ADAPTER *pAd = net_dev->ml_priv; - - // Sanity check for pAd - if (pAd == NULL) - return 0; // close ok - - if (VIRTUAL_IF_UP(pAd) != 0) - return -1; - - // increase MODULE use count - RT_MOD_INC_USE_COUNT(); - - netif_start_queue(net_dev); - netif_carrier_on(net_dev); - netif_wake_queue(net_dev); - - return 0; -} - -/* -======================================================================== -Routine Description: - Close raxx interface. - -Arguments: - *net_dev the raxx interface pointer - -Return Value: - 0 Open OK - otherwise Open Fail - -Note: - 1. if open fail, kernel will not call the close function. - 2. Free memory for - (1) Mlme Memory Handler: MlmeHalt() - (2) TX & RX: RTMPFreeTxRxRingMemory() - (3) BA Reordering: ba_reordering_resource_release() -======================================================================== -*/ -int rt28xx_close(IN PNET_DEV dev) -{ - struct net_device * net_dev = (struct net_device *)dev; - RTMP_ADAPTER *pAd = net_dev->ml_priv; - BOOLEAN Cancelled = FALSE; - UINT32 i = 0; -#ifdef RT2870 - DECLARE_WAIT_QUEUE_HEAD(unlink_wakeup); - DECLARE_WAITQUEUE(wait, current); - - //RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_REMOVE_IN_PROGRESS); -#endif // RT2870 // - - - DBGPRINT(RT_DEBUG_TRACE, ("===> rt28xx_close\n")); - - // Sanity check for pAd - if (pAd == NULL) - return 0; // close ok - - -#ifdef WDS_SUPPORT - WdsDown(pAd); -#endif // WDS_SUPPORT // - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - - // If dirver doesn't wake up firmware here, - // NICLoadFirmware will hang forever when interface is up again. - if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) - { - AsicForceWakeup(pAd, TRUE); - } - -#ifdef QOS_DLS_SUPPORT - // send DLS-TEAR_DOWN message, - if (pAd->CommonCfg.bDLSCapable) - { - UCHAR i; - - // tear down local dls table entry - for (i=0; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH)) - { - RTMPSendDLSTearDownFrame(pAd, pAd->StaCfg.DLSEntry[i].MacAddr); - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - pAd->StaCfg.DLSEntry[i].Valid = FALSE; - } - } - - // tear down peer dls table entry - for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH)) - { - RTMPSendDLSTearDownFrame(pAd, pAd->StaCfg.DLSEntry[i].MacAddr); - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - pAd->StaCfg.DLSEntry[i].Valid = FALSE; - } - } - RT28XX_MLME_HANDLER(pAd); - } -#endif // QOS_DLS_SUPPORT // - - if (INFRA_ON(pAd) && - (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))) - { - MLME_DISASSOC_REQ_STRUCT DisReq; - MLME_QUEUE_ELEM *MsgElem = (MLME_QUEUE_ELEM *) kmalloc(sizeof(MLME_QUEUE_ELEM), MEM_ALLOC_FLAG); - - COPY_MAC_ADDR(DisReq.Addr, pAd->CommonCfg.Bssid); - DisReq.Reason = REASON_DEAUTH_STA_LEAVING; - - MsgElem->Machine = ASSOC_STATE_MACHINE; - MsgElem->MsgType = MT2_MLME_DISASSOC_REQ; - MsgElem->MsgLen = sizeof(MLME_DISASSOC_REQ_STRUCT); - NdisMoveMemory(MsgElem->Msg, &DisReq, sizeof(MLME_DISASSOC_REQ_STRUCT)); - - // Prevent to connect AP again in STAMlmePeriodicExec - pAd->MlmeAux.AutoReconnectSsidLen= 32; - NdisZeroMemory(pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.AutoReconnectSsidLen); - - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_DISASSOC; - MlmeDisassocReqAction(pAd, MsgElem); - kfree(MsgElem); - - RTMPusecDelay(1000); - } - -#ifdef RT2870 - RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_REMOVE_IN_PROGRESS); -#endif // RT2870 // - -#ifdef CCX_SUPPORT - RTMPCancelTimer(&pAd->StaCfg.LeapAuthTimer, &Cancelled); -#endif - - RTMPCancelTimer(&pAd->StaCfg.StaQuickResponeForRateUpTimer, &Cancelled); - RTMPCancelTimer(&pAd->StaCfg.WpaDisassocAndBlockAssocTimer, &Cancelled); - -#ifdef WPA_SUPPLICANT_SUPPORT -#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT - { - union iwreq_data wrqu; - // send wireless event to wpa_supplicant for infroming interface down. - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.flags = RT_INTERFACE_DOWN; - wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); - } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // -#endif // WPA_SUPPLICANT_SUPPORT // - - MlmeRadioOff(pAd); - } -#endif // CONFIG_STA_SUPPORT // - - RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS); - - for (i = 0 ; i < NUM_OF_TX_RING; i++) - { - while (pAd->DeQueueRunning[i] == TRUE) - { - printk("Waiting for TxQueue[%d] done..........\n", i); - RTMPusecDelay(1000); - } - } - -#ifdef RT2870 - // ensure there are no more active urbs. - add_wait_queue (&unlink_wakeup, &wait); - pAd->wait = &unlink_wakeup; - - // maybe wait for deletions to finish. - i = 0; - //while((i < 25) && atomic_read(&pAd->PendingRx) > 0) - while(i < 25) - { - unsigned long IrqFlags; - - RTMP_IRQ_LOCK(&pAd->BulkInLock, IrqFlags); - if (pAd->PendingRx == 0) - { - RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); - break; - } - RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); - -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) - msleep(UNLINK_TIMEOUT_MS); //Time in millisecond -#else - RTMPusecDelay(UNLINK_TIMEOUT_MS*1000); //Time in microsecond -#endif - i++; - } - pAd->wait = NULL; - remove_wait_queue (&unlink_wakeup, &wait); -#endif // RT2870 // - - //RTUSBCleanUpMLMEWaitQueue(pAd); /*not used in RT28xx*/ - - -#ifdef RT2870 - // We need clear timerQ related structure before exits of the timer thread. - RT2870_TimerQ_Exit(pAd); - // Close kernel threads or tasklets - RT28xxThreadTerminate(pAd); -#endif // RT2870 // - - // Stop Mlme state machine - MlmeHalt(pAd); - - // Close kernel threads or tasklets - kill_thread_task(pAd); - - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - MacTableReset(pAd); - } -#endif // CONFIG_STA_SUPPORT // - - - MeasureReqTabExit(pAd); - TpcReqTabExit(pAd); - - - - - // Free Ring or USB buffers - RTMPFreeTxRxRingMemory(pAd); - - RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS); - -#ifdef DOT11_N_SUPPORT - // Free BA reorder resource - ba_reordering_resource_release(pAd); -#endif // DOT11_N_SUPPORT // - -#ifdef RT2870 -#ifdef INF_AMAZON_SE - if (pAd->UsbVendorReqBuf) - os_free_mem(pAd, pAd->UsbVendorReqBuf); -#endif // INF_AMAZON_SE // -#endif // RT2870 // - - RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_START_UP); - - return 0; // close ok -} /* End of rt28xx_close */ - -static int rt28xx_init(IN struct net_device *net_dev) -{ - PRTMP_ADAPTER pAd = net_dev->ml_priv; - UINT index; - UCHAR TmpPhy; -// ULONG Value=0; - NDIS_STATUS Status; -// OID_SET_HT_PHYMODE SetHT; -// WPDMA_GLO_CFG_STRUC GloCfg; - UINT32 MacCsr0 = 0; - -#ifdef RT2870 -#ifdef INF_AMAZON_SE - init_MUTEX(&(pAd->UsbVendorReq_semaphore)); - os_alloc_mem(pAd, (PUCHAR)&pAd->UsbVendorReqBuf, MAX_PARAM_BUFFER_SIZE - 1); - if (pAd->UsbVendorReqBuf == NULL) - { - DBGPRINT(RT_DEBUG_ERROR, ("Allocate vendor request temp buffer failed!\n")); - goto err0; - } -#endif // INF_AMAZON_SE // -#endif // RT2870 // - -#ifdef DOT11_N_SUPPORT - // Allocate BA Reordering memory - ba_reordering_resource_init(pAd, MAX_REORDERING_MPDU_NUM); -#endif // DOT11_N_SUPPORT // - - // Make sure MAC gets ready. - index = 0; - do - { - RTMP_IO_READ32(pAd, MAC_CSR0, &MacCsr0); - pAd->MACVersion = MacCsr0; - - if ((pAd->MACVersion != 0x00) && (pAd->MACVersion != 0xFFFFFFFF)) - break; - - RTMPusecDelay(10); - } while (index++ < 100); - - DBGPRINT(RT_DEBUG_TRACE, ("MAC_CSR0 [ Ver:Rev=0x%08x]\n", pAd->MACVersion)); -/*Iverson patch PCIE L1 issue */ - - // Disable DMA - RT28XXDMADisable(pAd); - - - // Load 8051 firmware - Status = NICLoadFirmware(pAd); - if (Status != NDIS_STATUS_SUCCESS) - { - DBGPRINT_ERR(("NICLoadFirmware failed, Status[=0x%08x]\n", Status)); - goto err1; - } - - NICLoadRateSwitchingParams(pAd); - - // Disable interrupts here which is as soon as possible - // This statement should never be true. We might consider to remove it later - - Status = RTMPAllocTxRxRingMemory(pAd); - if (Status != NDIS_STATUS_SUCCESS) - { - DBGPRINT_ERR(("RTMPAllocDMAMemory failed, Status[=0x%08x]\n", Status)); - goto err1; - } - - RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE); - - // initialize MLME - // - - Status = MlmeInit(pAd); - if (Status != NDIS_STATUS_SUCCESS) - { - DBGPRINT_ERR(("MlmeInit failed, Status[=0x%08x]\n", Status)); - goto err2; - } - - // Initialize pAd->StaCfg, pAd->ApCfg, pAd->CommonCfg to manufacture default - // - UserCfgInit(pAd); - -#ifdef RT2870 - // We need init timerQ related structure before create the timer thread. - RT2870_TimerQ_Init(pAd); -#endif // RT2870 // - - RT28XX_TASK_THREAD_INIT(pAd, Status); - if (Status != NDIS_STATUS_SUCCESS) - goto err1; - -// COPY_MAC_ADDR(pAd->ApCfg.MBSSID[apidx].Bssid, netif->hwaddr); -// pAd->bForcePrintTX = TRUE; - - CfgInitHook(pAd); - - -#ifdef BLOCK_NET_IF - initblockQueueTab(pAd); -#endif // BLOCK_NET_IF // - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - NdisAllocateSpinLock(&pAd->MacTabLock); -#endif // CONFIG_STA_SUPPORT // - - MeasureReqTabInit(pAd); - TpcReqTabInit(pAd); - - // - // Init the hardware, we need to init asic before read registry, otherwise mac register will be reset - // - Status = NICInitializeAdapter(pAd, TRUE); - if (Status != NDIS_STATUS_SUCCESS) - { - DBGPRINT_ERR(("NICInitializeAdapter failed, Status[=0x%08x]\n", Status)); - if (Status != NDIS_STATUS_SUCCESS) - goto err3; - } - - // Read parameters from Config File - Status = RTMPReadParametersHook(pAd); - - printk("1. Phy Mode = %d\n", pAd->CommonCfg.PhyMode); - if (Status != NDIS_STATUS_SUCCESS) - { - DBGPRINT_ERR(("NICReadRegParameters failed, Status[=0x%08x]\n",Status)); - goto err4; - } - -#ifdef RT2870 - pAd->CommonCfg.bMultipleIRP = FALSE; - - if (pAd->CommonCfg.bMultipleIRP) - pAd->CommonCfg.NumOfBulkInIRP = RX_RING_SIZE; - else - pAd->CommonCfg.NumOfBulkInIRP = 1; -#endif // RT2870 // - - - //Init Ba Capability parameters. -// RT28XX_BA_INIT(pAd); -#ifdef DOT11_N_SUPPORT - pAd->CommonCfg.DesiredHtPhy.MpduDensity = (UCHAR)pAd->CommonCfg.BACapability.field.MpduDensity; - pAd->CommonCfg.DesiredHtPhy.AmsduEnable = (USHORT)pAd->CommonCfg.BACapability.field.AmsduEnable; - pAd->CommonCfg.DesiredHtPhy.AmsduSize = (USHORT)pAd->CommonCfg.BACapability.field.AmsduSize; - pAd->CommonCfg.DesiredHtPhy.MimoPs = (USHORT)pAd->CommonCfg.BACapability.field.MMPSmode; - // UPdata to HT IE - pAd->CommonCfg.HtCapability.HtCapInfo.MimoPs = (USHORT)pAd->CommonCfg.BACapability.field.MMPSmode; - pAd->CommonCfg.HtCapability.HtCapInfo.AMsduSize = (USHORT)pAd->CommonCfg.BACapability.field.AmsduSize; - pAd->CommonCfg.HtCapability.HtCapParm.MpduDensity = (UCHAR)pAd->CommonCfg.BACapability.field.MpduDensity; -#endif // DOT11_N_SUPPORT // - - // after reading Registry, we now know if in AP mode or STA mode - - // Load 8051 firmware; crash when FW image not existent - // Status = NICLoadFirmware(pAd); - // if (Status != NDIS_STATUS_SUCCESS) - // break; - - printk("2. Phy Mode = %d\n", pAd->CommonCfg.PhyMode); - - // We should read EEPROM for all cases. rt2860b - NICReadEEPROMParameters(pAd, mac); -#ifdef CONFIG_STA_SUPPORT -#endif // CONFIG_STA_SUPPORT // - - printk("3. Phy Mode = %d\n", pAd->CommonCfg.PhyMode); - - NICInitAsicFromEEPROM(pAd); //rt2860b - - // Set PHY to appropriate mode - TmpPhy = pAd->CommonCfg.PhyMode; - pAd->CommonCfg.PhyMode = 0xff; - RTMPSetPhyMode(pAd, TmpPhy); -#ifdef DOT11_N_SUPPORT - SetCommonHT(pAd); -#endif // DOT11_N_SUPPORT // - - // No valid channels. - if (pAd->ChannelListNum == 0) - { - printk("Wrong configuration. No valid channel found. Check \"ContryCode\" and \"ChannelGeography\" setting.\n"); - goto err4; - } - -#ifdef DOT11_N_SUPPORT - printk("MCS Set = %02x %02x %02x %02x %02x\n", pAd->CommonCfg.HtCapability.MCSSet[0], - pAd->CommonCfg.HtCapability.MCSSet[1], pAd->CommonCfg.HtCapability.MCSSet[2], - pAd->CommonCfg.HtCapability.MCSSet[3], pAd->CommonCfg.HtCapability.MCSSet[4]); -#endif // DOT11_N_SUPPORT // - -#ifdef RT30xx - //Init RT30xx RFRegisters after read RFIC type from EEPROM - NICInitRT30xxRFRegisters(pAd); -#endif // RT30xx // - -// APInitialize(pAd); - -#ifdef IKANOS_VX_1X0 - VR_IKANOS_FP_Init(pAd->ApCfg.BssidNum, pAd->PermanentAddress); -#endif // IKANOS_VX_1X0 // - - // - // Initialize RF register to default value - // - AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); - AsicLockChannel(pAd, pAd->CommonCfg.Channel); - - if (pAd && (Status != NDIS_STATUS_SUCCESS)) - { - // - // Undo everything if it failed - // - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { -// NdisMDeregisterInterrupt(&pAd->Interrupt); - RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE); - } -// RTMPFreeAdapter(pAd); // we will free it in disconnect() - } - else if (pAd) - { - // Microsoft HCT require driver send a disconnect event after driver initialization. - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED); -// pAd->IndicateMediaState = NdisMediaStateDisconnected; - RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_MEDIA_STATE_CHANGE); - - DBGPRINT(RT_DEBUG_TRACE, ("NDIS_STATUS_MEDIA_DISCONNECT Event B!\n")); - - -#ifdef RT2870 - RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS); - RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_REMOVE_IN_PROGRESS); - - // - // Support multiple BulkIn IRP, - // the value on pAd->CommonCfg.NumOfBulkInIRP may be large than 1. - // - for(index=0; indexCommonCfg.NumOfBulkInIRP; index++) - { - RTUSBBulkReceive(pAd); - DBGPRINT(RT_DEBUG_TRACE, ("RTUSBBulkReceive!\n" )); - } -#endif // RT2870 // - }// end of else - - - DBGPRINT_S(Status, ("<==== RTMPInitialize, Status=%x\n", Status)); - - return TRUE; - - -err4: -err3: - MlmeHalt(pAd); -err2: - RTMPFreeTxRxRingMemory(pAd); -// RTMPFreeAdapter(pAd); -err1: - -#ifdef DOT11_N_SUPPORT - os_free_mem(pAd, pAd->mpdu_blk_pool.mem); // free BA pool -#endif // DOT11_N_SUPPORT // - RT28XX_IRQ_RELEASE(net_dev); - - // shall not set priv to NULL here because the priv didn't been free yet. - //net_dev->ml_priv = 0; -#ifdef INF_AMAZON_SE -err0: -#endif // INF_AMAZON_SE // - printk("!!! %s Initialized fail !!!\n", RT28xx_CHIP_NAME); - return FALSE; -} /* End of rt28xx_init */ - - -/* -======================================================================== -Routine Description: - Open raxx interface. - -Arguments: - *net_dev the raxx interface pointer - -Return Value: - 0 Open OK - otherwise Open Fail - -Note: -======================================================================== -*/ -int rt28xx_open(IN PNET_DEV dev) -{ - struct net_device * net_dev = (struct net_device *)dev; - PRTMP_ADAPTER pAd = net_dev->ml_priv; - int retval = 0; - POS_COOKIE pObj; - - - // Sanity check for pAd - if (pAd == NULL) - { - /* if 1st open fail, pAd will be free; - So the net_dev->ml_priv will be NULL in 2rd open */ - return -1; - } - -#ifdef CONFIG_APSTA_MIXED_SUPPORT - if (pAd->OpMode == OPMODE_AP) - { - CW_MAX_IN_BITS = 6; - } - else if (pAd->OpMode == OPMODE_STA) - { - CW_MAX_IN_BITS = 10; - } - -#if WIRELESS_EXT >= 12 - if (net_dev->ml_priv_flags == INT_MAIN) - { - if (pAd->OpMode == OPMODE_AP) - net_dev->wireless_handlers = (struct iw_handler_def *) &rt28xx_ap_iw_handler_def; - else if (pAd->OpMode == OPMODE_STA) - net_dev->wireless_handlers = (struct iw_handler_def *) &rt28xx_iw_handler_def; - } -#endif // WIRELESS_EXT >= 12 // -#endif // CONFIG_APSTA_MIXED_SUPPORT // - -#ifdef CONFIG_STA_SUPPORT -#endif // CONFIG_STA_SUPPORT // - - // Init - pObj = (POS_COOKIE)pAd->OS_Cookie; - - // reset Adapter flags - RTMP_CLEAR_FLAGS(pAd); - - // Request interrupt service routine for PCI device - // register the interrupt routine with the os - RT28XX_IRQ_REQUEST(net_dev); - - - // Init BssTab & ChannelInfo tabbles for auto channel select. - - - // Chip & other init - if (rt28xx_init(net_dev) == FALSE) - goto err; - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - NdisZeroMemory(pAd->StaCfg.dev_name, 16); - NdisMoveMemory(pAd->StaCfg.dev_name, net_dev->name, strlen(net_dev->name)); - } -#endif // CONFIG_STA_SUPPORT // - - // Set up the Mac address - NdisMoveMemory(net_dev->dev_addr, (void *) pAd->CurrentAddress, 6); - - // Init IRQ parameters - RT28XX_IRQ_INIT(pAd); - - // Various AP function init - - - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { -#ifdef WPA_SUPPLICANT_SUPPORT -#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT - { - union iwreq_data wrqu; - // send wireless event to wpa_supplicant for infroming interface down. - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.flags = RT_INTERFACE_UP; - wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); - } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // -#endif // WPA_SUPPLICANT_SUPPORT // - - } -#endif // CONFIG_STA_SUPPORT // - - // Enable Interrupt - RT28XX_IRQ_ENABLE(pAd); - - // Now Enable RxTx - RTMPEnableRxTx(pAd); - RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_START_UP); - - { - UINT32 reg = 0; - RTMP_IO_READ32(pAd, 0x1300, ®); // clear garbage interrupts - printk("0x1300 = %08x\n", reg); - } - - { -// u32 reg; -// u8 byte; -// u16 tmp; - -// RTMP_IO_READ32(pAd, XIFS_TIME_CFG, ®); - -// tmp = 0x0805; -// reg = (reg & 0xffff0000) | tmp; -// RTMP_IO_WRITE32(pAd, XIFS_TIME_CFG, reg); - - } - -#ifdef CONFIG_STA_SUPPORT -#endif // CONFIG_STA_SUPPORT // - - return (retval); - -err: - return (-1); -} /* End of rt28xx_open */ - -static const struct net_device_ops rt3070_netdev_ops = { - .ndo_open = MainVirtualIF_open, - .ndo_stop = MainVirtualIF_close, - .ndo_do_ioctl = rt28xx_ioctl, - .ndo_get_stats = RT28xx_get_ether_stats, - .ndo_validate_addr = NULL, - .ndo_set_mac_address = eth_mac_addr, - .ndo_change_mtu = eth_change_mtu, -#ifdef IKANOS_VX_1X0 - .ndo_start_xmit = IKANOS_DataFramesTx, -#else - .ndo_start_xmit = rt28xx_send_packets, -#endif -}; - -/* Must not be called for mdev and apdev */ -static NDIS_STATUS rt_ieee80211_if_setup(struct net_device *dev, PRTMP_ADAPTER pAd) -{ - NDIS_STATUS Status; - INT i=0; - CHAR slot_name[IFNAMSIZ]; - struct net_device *device; - - - //ether_setup(dev); -// dev->set_multicast_list = ieee80211_set_multicast_list; -// dev->change_mtu = ieee80211_change_mtu; -#ifdef CONFIG_STA_SUPPORT -#if WIRELESS_EXT >= 12 - if (pAd->OpMode == OPMODE_STA) - { - dev->wireless_handlers = &rt28xx_iw_handler_def; - } -#endif //WIRELESS_EXT >= 12 -#endif // CONFIG_STA_SUPPORT // - -#ifdef CONFIG_APSTA_MIXED_SUPPORT -#if WIRELESS_EXT >= 12 - if (pAd->OpMode == OPMODE_AP) - { - dev->wireless_handlers = &rt28xx_ap_iw_handler_def; - } -#endif //WIRELESS_EXT >= 12 -#endif // CONFIG_APSTA_MIXED_SUPPORT // - -#if WIRELESS_EXT < 21 - dev->get_wireless_stats = rt28xx_get_wireless_stats; -#endif -// dev->uninit = ieee80211_if_reinit; -// dev->destructor = ieee80211_if_free; - dev->priv_flags = INT_MAIN; - dev->netdev_ops = &rt3070_netdev_ops; - // find available device name - for (i = 0; i < 8; i++) - { -#ifdef MULTIPLE_CARD_SUPPORT - if (pAd->MC_RowID >= 0) - sprintf(slot_name, "ra%02d_%d", pAd->MC_RowID, i); - else -#endif // MULTIPLE_CARD_SUPPORT // - sprintf(slot_name, "ra%d", i); - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) - device = dev_get_by_name(dev_net(dev), slot_name); -#else - device = dev_get_by_name(dev->nd_net, slot_name); -#endif -#else - device = dev_get_by_name(slot_name); -#endif - if (device != NULL) dev_put(device); -#else - for (device = dev_base; device != NULL; device = device->next) - { - if (strncmp(device->name, slot_name, 4) == 0) - break; - } -#endif - if(device == NULL) - break; - } - - if(i == 8) - { - DBGPRINT(RT_DEBUG_ERROR, ("No available slot name\n")); - Status = NDIS_STATUS_FAILURE; - } - else - { -#ifdef MULTIPLE_CARD_SUPPORT - if (pAd->MC_RowID >= 0) - sprintf(dev->name, "ra%02d_%d", pAd->MC_RowID, i); - else -#endif // MULTIPLE_CARD_SUPPORT // - sprintf(dev->name, "ra%d", i); - Status = NDIS_STATUS_SUCCESS; - } - - return Status; - -} - - -#ifdef MULTIPLE_CARD_SUPPORT -/* -======================================================================== -Routine Description: - Get card profile path. - -Arguments: - pAd - -Return Value: - TRUE - Find a card profile - FALSE - use default profile - -Note: -======================================================================== -*/ -extern INT RTMPGetKeyParameter( - IN PCHAR key, - OUT PCHAR dest, - IN INT destsize, - IN PCHAR buffer); - -BOOLEAN RTMP_CardInfoRead( - IN PRTMP_ADAPTER pAd) -{ -#define MC_SELECT_CARDID 0 /* use CARD ID (0 ~ 31) to identify different cards */ -#define MC_SELECT_MAC 1 /* use CARD MAC to identify different cards */ -#define MC_SELECT_CARDTYPE 2 /* use CARD type (abgn or bgn) to identify different cards */ - -#define LETTER_CASE_TRANSLATE(txt_p, card_id) \ - { UINT32 _len; char _char; \ - for(_len=0; _lenfsuid; - orgfsgid = current->fsgid; - current->fsuid = current->fsgid = 0; - orgfs = get_fs(); - set_fs(KERNEL_DS); - - // get RF IC type - RTMP_IO_READ32(pAd, E2PROM_CSR, &data); - - if ((data & 0x30) == 0) - pAd->EEPROMAddressNum = 6; // 93C46 - else if ((data & 0x30) == 0x10) - pAd->EEPROMAddressNum = 8; // 93C66 - else - pAd->EEPROMAddressNum = 8; // 93C86 - - //antenna.word = RTMP_EEPROM_READ16(pAd, EEPROM_NIC1_OFFSET); - RT28xx_EEPROM_READ16(pAd, EEPROM_NIC1_OFFSET, antenna.word); - - if ((antenna.field.RfIcType == RFIC_2850) || - (antenna.field.RfIcType == RFIC_2750)) - { - /* ABGN card */ - strcpy(RFIC_word, "abgn"); - } - else - { - /* BGN card */ - strcpy(RFIC_word, "bgn"); - } - - // get MAC address - //addr01 = RTMP_EEPROM_READ16(pAd, 0x04); - //addr23 = RTMP_EEPROM_READ16(pAd, 0x06); - //addr45 = RTMP_EEPROM_READ16(pAd, 0x08); - RT28xx_EEPROM_READ16(pAd, 0x04, addr01); - RT28xx_EEPROM_READ16(pAd, 0x06, addr23); - RT28xx_EEPROM_READ16(pAd, 0x08, addr45); - - mac[0] = (UCHAR)(addr01 & 0xff); - mac[1] = (UCHAR)(addr01 >> 8); - mac[2] = (UCHAR)(addr23 & 0xff); - mac[3] = (UCHAR)(addr23 >> 8); - mac[4] = (UCHAR)(addr45 & 0xff); - mac[5] = (UCHAR)(addr45 >> 8); - - // open card information file - srcf = filp_open(CARD_INFO_PATH, O_RDONLY, 0); - if (IS_ERR(srcf)) - { - /* card information file does not exist */ - DBGPRINT(RT_DEBUG_TRACE, - ("--> Error %ld opening %s\n", -PTR_ERR(srcf), CARD_INFO_PATH)); - return FALSE; - } - - if (srcf->f_op && srcf->f_op->read) - { - /* card information file exists so reading the card information */ - memset(buffer, 0x00, MAX_INI_BUFFER_SIZE); - retval = srcf->f_op->read(srcf, buffer, MAX_INI_BUFFER_SIZE, &srcf->f_pos); - if (retval < 0) - { - /* read fail */ - DBGPRINT(RT_DEBUG_TRACE, - ("--> Read %s error %d\n", CARD_INFO_PATH, -retval)); - } - else - { - /* get card selection method */ - memset(tmpbuf, 0x00, MAX_PARAM_BUFFER_SIZE); - card_select_method = MC_SELECT_CARDTYPE; // default - - if (RTMPGetKeyParameter("SELECT", tmpbuf, 256, buffer)) - { - if (strcmp(tmpbuf, "CARDID") == 0) - card_select_method = MC_SELECT_CARDID; - else if (strcmp(tmpbuf, "MAC") == 0) - card_select_method = MC_SELECT_MAC; - else if (strcmp(tmpbuf, "CARDTYPE") == 0) - card_select_method = MC_SELECT_CARDTYPE; - } - - DBGPRINT(RT_DEBUG_TRACE, - ("MC> Card Selection = %d\n", card_select_method)); - - // init - card_free_id = -1; - card_nouse_id = -1; - card_same_mac_id = -1; - card_match_id = -1; - - // search current card information records - for(card_index=0; - card_index Free = %d, Same = %d, NOUSE = %d\n", - card_free_id, card_same_mac_id, card_nouse_id)); - - if ((card_same_mac_id >= 0) && - ((card_select_method == MC_SELECT_CARDID) || - (card_select_method == MC_SELECT_CARDTYPE))) - { - // same MAC entry is found - card_match_id = card_same_mac_id; - - if (card_select_method == MC_SELECT_CARDTYPE) - { - // for CARDTYPE - sprintf(card_id_buf, "%02dCARDTYPE%s", - card_match_id, RFIC_word); - - if ((start_ptr=rtstrstruncasecmp(buffer, card_id_buf)) != NULL) - { - // we found the card ID - LETTER_CASE_TRANSLATE(start_ptr, card_id_buf); - } - } - } - else - { - // the card is 1st plug-in, try to find the match card profile - switch(card_select_method) - { - case MC_SELECT_CARDID: // CARDID - default: - if (card_free_id >= 0) - card_match_id = card_free_id; - else - card_match_id = card_nouse_id; - break; - - case MC_SELECT_MAC: // MAC - sprintf(card_id_buf, "MAC%02x:%02x:%02x:%02x:%02x:%02x", - mac[0], mac[1], mac[2], - mac[3], mac[4], mac[5]); - - /* try to find the key word in the card file */ - if ((start_ptr=rtstrstruncasecmp(buffer, card_id_buf)) != NULL) - { - LETTER_CASE_TRANSLATE(start_ptr, card_id_buf); - - /* get the row ID (2 ASCII characters) */ - start_ptr -= 2; - card_id_buf[0] = *(start_ptr); - card_id_buf[1] = *(start_ptr+1); - card_id_buf[2] = 0x00; - - card_match_id = simple_strtol(card_id_buf, 0, 10); - } - break; - - case MC_SELECT_CARDTYPE: // CARDTYPE - card_nouse_id = -1; - - for(card_index=0; - card_index= 0) - { - // make up search keyword - switch(card_select_method) - { - case MC_SELECT_CARDID: // CARDID - sprintf(card_id_buf, "%02dCARDID", card_match_id); - break; - - case MC_SELECT_MAC: // MAC - sprintf(card_id_buf, - "%02dmac%02x:%02x:%02x:%02x:%02x:%02x", - card_match_id, - mac[0], mac[1], mac[2], - mac[3], mac[4], mac[5]); - break; - - case MC_SELECT_CARDTYPE: // CARDTYPE - default: - sprintf(card_id_buf, "%02dcardtype%s", - card_match_id, RFIC_word); - break; - } - - DBGPRINT(RT_DEBUG_TRACE, ("Search Keyword = %s\n", card_id_buf)); - - // read card file path - if (RTMPGetKeyParameter(card_id_buf, tmpbuf, 256, buffer)) - { - if (strlen(tmpbuf) < sizeof(pAd->MC_FileName)) - { - // backup card information - pAd->MC_RowID = card_match_id; /* base 0 */ - MC_CardUsed[card_match_id] = 1; - memcpy(MC_CardMac[card_match_id], mac, sizeof(mac)); - - // backup card file path - NdisMoveMemory(pAd->MC_FileName, tmpbuf , strlen(tmpbuf)); - pAd->MC_FileName[strlen(tmpbuf)] = '\0'; - flg_match_ok = TRUE; - - DBGPRINT(RT_DEBUG_TRACE, - ("Card Profile Name = %s\n", pAd->MC_FileName)); - } - else - { - DBGPRINT(RT_DEBUG_ERROR, - ("Card Profile Name length too large!\n")); - } - } - else - { - DBGPRINT(RT_DEBUG_ERROR, - ("Can not find search key word in card.dat!\n")); - } - - if ((flg_match_ok != TRUE) && - (card_match_id < MAX_NUM_OF_MULTIPLE_CARD)) - { - MC_CardUsed[card_match_id] = 0; - memset(MC_CardMac[card_match_id], 0, sizeof(mac)); - } - } // if (card_match_id >= 0) - } - } - - // close file - retval = filp_close(srcf, NULL); - set_fs(orgfs); - current->fsuid = orgfsuid; - current->fsgid = orgfsgid; - kfree(buffer); - kfree(tmpbuf); - return flg_match_ok; -} -#endif // MULTIPLE_CARD_SUPPORT // - - -/* -======================================================================== -Routine Description: - Probe RT28XX chipset. - -Arguments: - _dev_p Point to the PCI or USB device - _dev_id_p Point to the PCI or USB device ID - -Return Value: - 0 Probe OK - -ENODEV Probe Fail - -Note: -======================================================================== -*/ -INT __devinit rt28xx_probe( - IN void *_dev_p, - IN void *_dev_id_p, - IN UINT argc, - OUT PRTMP_ADAPTER *ppAd) -{ - struct net_device *net_dev; - PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) NULL; - INT status; - PVOID handle; -#ifdef RT2870 -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* kernel 2.4 series */ - struct usb_device *dev_p = (struct usb_device *)_dev_p; -#else - struct usb_interface *intf = (struct usb_interface *)_dev_p; - struct usb_device *dev_p = interface_to_usbdev(intf); - - dev_p = usb_get_dev(dev_p); -#endif // LINUX_VERSION_CODE // -#endif // RT2870 // - - -#ifdef CONFIG_STA_SUPPORT - DBGPRINT(RT_DEBUG_TRACE, ("STA Driver version-%s\n", STA_DRIVER_VERSION)); -#endif // CONFIG_STA_SUPPORT // - - // Check chipset vendor/product ID -// if (RT28XXChipsetCheck(_dev_p) == FALSE) -// goto err_out; - -#if LINUX_VERSION_CODE <= 0x20402 // Red Hat 7.1 - net_dev = alloc_netdev(sizeof(PRTMP_ADAPTER), "eth%d", ether_setup); -#else - net_dev = alloc_etherdev(sizeof(PRTMP_ADAPTER)); -#endif - if (net_dev == NULL) - { - printk("alloc_netdev failed\n"); - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) - module_put(THIS_MODULE); -#endif //LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) -#else - MOD_DEC_USE_COUNT; -#endif - goto err_out; - } - -// sample -// if (rt_ieee80211_if_setup(net_dev) != NDIS_STATUS_SUCCESS) -// goto err_out; - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) - SET_MODULE_OWNER(net_dev); -#endif - - netif_stop_queue(net_dev); -#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT -/* for supporting Network Manager */ -/* Set the sysfs physical device reference for the network logical device - * if set prior to registration will cause a symlink during initialization. - */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) - SET_NETDEV_DEV(net_dev, &(dev_p->dev)); -#endif -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // - - // Allocate RTMP_ADAPTER miniport adapter structure - handle = kmalloc(sizeof(struct os_cookie), GFP_KERNEL); - RT28XX_HANDLE_DEV_ASSIGN(handle, dev_p); - - status = RTMPAllocAdapterBlock(handle, &pAd); - if (status != NDIS_STATUS_SUCCESS) - goto err_out_free_netdev; - - net_dev->ml_priv = (PVOID)pAd; - pAd->net_dev = net_dev; // must be before RT28XXNetDevInit() - - RT28XXNetDevInit(_dev_p, net_dev, pAd); - -#ifdef CONFIG_STA_SUPPORT - pAd->StaCfg.OriDevType = net_dev->type; -#endif // CONFIG_STA_SUPPORT // - - // Find and assign a free interface name, raxx -// RT28XXAvailRANameAssign(net_dev->name); - - // Post config -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - if (RT28XXProbePostConfig(_dev_p, pAd, argc) == FALSE) - goto err_out_unmap; -#else - if (RT28XXProbePostConfig(_dev_p, pAd, 0) == FALSE) - goto err_out_unmap; -#endif // LINUX_VERSION_CODE // - -#ifdef CONFIG_STA_SUPPORT - pAd->OpMode = OPMODE_STA; -#endif // CONFIG_STA_SUPPORT // - - -#ifdef MULTIPLE_CARD_SUPPORT - // find its profile path - pAd->MC_RowID = -1; // use default profile path - RTMP_CardInfoRead(pAd); - - if (pAd->MC_RowID == -1) -#ifdef CONFIG_STA_SUPPORT - strcpy(pAd->MC_FileName, STA_PROFILE_PATH); -#endif // CONFIG_STA_SUPPORT // - - DBGPRINT(RT_DEBUG_TRACE, - ("MC> ROW = %d, PATH = %s\n", pAd->MC_RowID, pAd->MC_FileName)); -#endif // MULTIPLE_CARD_SUPPORT // - - // sample move - if (rt_ieee80211_if_setup(net_dev, pAd) != NDIS_STATUS_SUCCESS) - goto err_out_unmap; - - // Register this device - status = register_netdev(net_dev); - if (status) - goto err_out_unmap; - - // Set driver data - RT28XX_DRVDATA_SET(_dev_p); - - - - *ppAd = pAd; - return 0; // probe ok - - - /* --------------------------- ERROR HANDLE --------------------------- */ -err_out_unmap: - RTMPFreeAdapter(pAd); - RT28XX_UNMAP(); - -err_out_free_netdev: -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) - free_netdev(net_dev); -#else - kfree(net_dev); -#endif - -err_out: - RT28XX_PUT_DEVICE(dev_p); - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - return (LONG)NULL; -#else - return -ENODEV; /* probe fail */ -#endif // LINUX_VERSION_CODE // -} /* End of rt28xx_probe */ - - -/* -======================================================================== -Routine Description: - The entry point for Linux kernel sent packet to our driver. - -Arguments: - sk_buff *skb the pointer refer to a sk_buffer. - -Return Value: - 0 - -Note: - This function is the entry point of Tx Path for Os delivery packet to - our driver. You only can put OS-depened & STA/AP common handle procedures - in here. -======================================================================== -*/ -int rt28xx_packet_xmit(struct sk_buff *skb) -{ - struct net_device *net_dev = skb->dev; - PRTMP_ADAPTER pAd = net_dev->ml_priv; - int status = 0; - PNDIS_PACKET pPacket = (PNDIS_PACKET) skb; - - /* RT2870STA does this in RTMPSendPackets() */ -#ifdef RALINK_ATE - if (ATE_ON(pAd)) - { - RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_RESOURCES); - return 0; - } -#endif // RALINK_ATE // - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - // Drop send request since we are in monitor mode - if (MONITOR_ON(pAd)) - { - RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); - goto done; - } - } -#endif // CONFIG_STA_SUPPORT // - - // EapolStart size is 18 - if (skb->len < 14) - { - //printk("bad packet size: %d\n", pkt->len); - hex_dump("bad packet", skb->data, skb->len); - RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); - goto done; - } - - RTMP_SET_PACKET_5VT(pPacket, 0); -// MiniportMMRequest(pAd, pkt->data, pkt->len); -#ifdef CONFIG_5VT_ENHANCE - if (*(int*)(skb->cb) == BRIDGE_TAG) { - RTMP_SET_PACKET_5VT(pPacket, 1); - } -#endif - - - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - - STASendPackets((NDIS_HANDLE)pAd, (PPNDIS_PACKET) &pPacket, 1); - } - -#endif // CONFIG_STA_SUPPORT // - - status = 0; -done: - - return status; -} - - -/* -======================================================================== -Routine Description: - Send a packet to WLAN. - -Arguments: - skb_p points to our adapter - dev_p which WLAN network interface - -Return Value: - 0: transmit successfully - otherwise: transmit fail - -Note: -======================================================================== -*/ -INT rt28xx_send_packets( - IN struct sk_buff *skb_p, - IN struct net_device *net_dev) -{ - RTMP_ADAPTER *pAd = net_dev->ml_priv; - - if (!(net_dev->flags & IFF_UP)) - { - RELEASE_NDIS_PACKET(pAd, (PNDIS_PACKET)skb_p, NDIS_STATUS_FAILURE); - return 0; - } - - NdisZeroMemory((PUCHAR)&skb_p->cb[CB_OFF], 15); - RTMP_SET_PACKET_NET_DEVICE_MBSSID(skb_p, MAIN_MBSSID); - - return rt28xx_packet_xmit(skb_p); -} /* End of MBSS_VirtualIF_PacketSend */ - - - - -#if LINUX_VERSION_CODE <= 0x20402 // Red Hat 7.1 -//static struct net_device *alloc_netdev(int sizeof_priv, const char *mask, void (*setup)(struct net_device *)) //sample -struct net_device *alloc_netdev( - int sizeof_priv, - const char *mask, - void (*setup)(struct net_device *)) -{ - struct net_device *dev; - INT alloc_size; - - - /* ensure 32-byte alignment of the private area */ - alloc_size = sizeof (*dev) + sizeof_priv + 31; - - dev = (struct net_device *) kmalloc(alloc_size, GFP_KERNEL); - if (dev == NULL) - { - DBGPRINT(RT_DEBUG_ERROR, - ("alloc_netdev: Unable to allocate device memory.\n")); - return NULL; - } - - memset(dev, 0, alloc_size); - - if (sizeof_priv) - dev->ml_priv = (void *) (((long)(dev + 1) + 31) & ~31); - - setup(dev); - strcpy(dev->name, mask); - - return dev; -} -#endif // LINUX_VERSION_CODE // - - -void CfgInitHook(PRTMP_ADAPTER pAd) -{ - pAd->bBroadComHT = TRUE; -} /* End of CfgInitHook */ - - -#if WIRELESS_EXT >= 12 -// This function will be called when query /proc -struct iw_statistics *rt28xx_get_wireless_stats( - IN struct net_device *net_dev) -{ - PRTMP_ADAPTER pAd = net_dev->ml_priv; - - - DBGPRINT(RT_DEBUG_TRACE, ("rt28xx_get_wireless_stats --->\n")); - - pAd->iw_stats.status = 0; // Status - device dependent for now - - // link quality - pAd->iw_stats.qual.qual = ((pAd->Mlme.ChannelQuality * 12)/10 + 10); - if(pAd->iw_stats.qual.qual > 100) - pAd->iw_stats.qual.qual = 100; - -#ifdef CONFIG_STA_SUPPORT - if (pAd->OpMode == OPMODE_STA) - pAd->iw_stats.qual.level = RTMPMaxRssi(pAd, pAd->StaCfg.RssiSample.LastRssi0, pAd->StaCfg.RssiSample.LastRssi1, pAd->StaCfg.RssiSample.LastRssi2); -#endif // CONFIG_STA_SUPPORT // - - pAd->iw_stats.qual.noise = pAd->BbpWriteLatch[66]; // noise level (dBm) - - pAd->iw_stats.qual.noise += 256 - 143; - pAd->iw_stats.qual.updated = 1; // Flags to know if updated -#ifdef IW_QUAL_DBM - pAd->iw_stats.qual.updated |= IW_QUAL_DBM; // Level + Noise are dBm -#endif // IW_QUAL_DBM // - - pAd->iw_stats.discard.nwid = 0; // Rx : Wrong nwid/essid - pAd->iw_stats.miss.beacon = 0; // Missed beacons/superframe - - DBGPRINT(RT_DEBUG_TRACE, ("<--- rt28xx_get_wireless_stats\n")); - return &pAd->iw_stats; -} /* End of rt28xx_get_wireless_stats */ -#endif // WIRELESS_EXT // - - - -void tbtt_tasklet(unsigned long data) -{ -#define MAX_TX_IN_TBTT (16) - -} - -INT rt28xx_ioctl( - IN struct net_device *net_dev, - IN OUT struct ifreq *rq, - IN INT cmd) -{ - VIRTUAL_ADAPTER *pVirtualAd = NULL; - RTMP_ADAPTER *pAd = NULL; - INT ret = 0; - - if (net_dev->priv_flags == INT_MAIN) - { - pAd = net_dev->ml_priv; - } - else - { - pVirtualAd = net_dev->ml_priv; - pAd = pVirtualAd->RtmpDev->ml_priv; - } - - if (pAd == NULL) - { - /* if 1st open fail, pAd will be free; - So the net_dev->ml_priv will be NULL in 2rd open */ - return -ENETDOWN; - } - - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - ret = rt28xx_sta_ioctl(net_dev, rq, cmd); - } -#endif // CONFIG_STA_SUPPORT // - - return ret; -} - -/* - ======================================================================== - - Routine Description: - return ethernet statistics counter - - Arguments: - net_dev Pointer to net_device - - Return Value: - net_device_stats* - - Note: - - ======================================================================== -*/ -struct net_device_stats *RT28xx_get_ether_stats( - IN struct net_device *net_dev) -{ - RTMP_ADAPTER *pAd = NULL; - - if (net_dev) - pAd = net_dev->ml_priv; - - if (pAd) - { - - pAd->stats.rx_packets = pAd->WlanCounters.ReceivedFragmentCount.QuadPart; - pAd->stats.tx_packets = pAd->WlanCounters.TransmittedFragmentCount.QuadPart; - - pAd->stats.rx_bytes = pAd->RalinkCounters.ReceivedByteCount; - pAd->stats.tx_bytes = pAd->RalinkCounters.TransmittedByteCount; - - pAd->stats.rx_errors = pAd->Counters8023.RxErrors; - pAd->stats.tx_errors = pAd->Counters8023.TxErrors; - - pAd->stats.rx_dropped = 0; - pAd->stats.tx_dropped = 0; - - pAd->stats.multicast = pAd->WlanCounters.MulticastReceivedFrameCount.QuadPart; // multicast packets received - pAd->stats.collisions = pAd->Counters8023.OneCollision + pAd->Counters8023.MoreCollisions; // Collision packets - - pAd->stats.rx_length_errors = 0; - pAd->stats.rx_over_errors = pAd->Counters8023.RxNoBuffer; // receiver ring buff overflow - pAd->stats.rx_crc_errors = 0;//pAd->WlanCounters.FCSErrorCount; // recved pkt with crc error - pAd->stats.rx_frame_errors = pAd->Counters8023.RcvAlignmentErrors; // recv'd frame alignment error - pAd->stats.rx_fifo_errors = pAd->Counters8023.RxNoBuffer; // recv'r fifo overrun - pAd->stats.rx_missed_errors = 0; // receiver missed packet - - // detailed tx_errors - pAd->stats.tx_aborted_errors = 0; - pAd->stats.tx_carrier_errors = 0; - pAd->stats.tx_fifo_errors = 0; - pAd->stats.tx_heartbeat_errors = 0; - pAd->stats.tx_window_errors = 0; - - // for cslip etc - pAd->stats.rx_compressed = 0; - pAd->stats.tx_compressed = 0; - - return &pAd->stats; - } - else - return NULL; -} - +#include "../rt2870/rt_main_dev.c" diff --git a/drivers/staging/rt3070/rt_profile.c b/drivers/staging/rt3070/rt_profile.c index 6eda27e6b8dc..ab9eb1d55bb1 100644 --- a/drivers/staging/rt3070/rt_profile.c +++ b/drivers/staging/rt3070/rt_profile.c @@ -1,2041 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * 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 "rt_config.h" - -#ifdef DOT11_N_SUPPORT -static void HTParametersHook( - IN PRTMP_ADAPTER pAd, - IN CHAR *pValueStr, - IN CHAR *pInput); -#endif // DOT11_N_SUPPORT // - -#define ETH_MAC_ADDR_STR_LEN 17 // in format of xx:xx:xx:xx:xx:xx - -// We assume the s1 is a sting, s2 is a memory space with 6 bytes. and content of s1 will be changed. -BOOLEAN rtstrmactohex(char *s1, char *s2) -{ - int i = 0; - char *ptokS = s1, *ptokE = s1; - - if (strlen(s1) != ETH_MAC_ADDR_STR_LEN) - return FALSE; - - while((*ptokS) != '\0') - { - if((ptokE = strchr(ptokS, ':')) != NULL) - *ptokE++ = '\0'; - if ((strlen(ptokS) != 2) || (!isxdigit(*ptokS)) || (!isxdigit(*(ptokS+1)))) - break; // fail - AtoH(ptokS, &s2[i++], 1); - ptokS = ptokE; - if (i == 6) - break; // parsing finished - } - - return ( i == 6 ? TRUE : FALSE); - -} - - -// we assume the s1 and s2 both are strings. -BOOLEAN rtstrcasecmp(char *s1, char *s2) -{ - char *p1 = s1, *p2 = s2; - - if (strlen(s1) != strlen(s2)) - return FALSE; - - while(*p1 != '\0') - { - if((*p1 != *p2) && ((*p1 ^ *p2) != 0x20)) - return FALSE; - p1++; - p2++; - } - - return TRUE; -} - -// we assume the s1 (buffer) and s2 (key) both are strings. -char * rtstrstruncasecmp(char * s1, char * s2) -{ - INT l1, l2, i; - char temp1, temp2; - - l2 = strlen(s2); - if (!l2) - return (char *) s1; - - l1 = strlen(s1); - - while (l1 >= l2) - { - l1--; - - for(i=0; i= l2) - { - l1--; - if (!memcmp(s1,s2,l2)) - return (char *) s1; - s1++; - } - - return NULL; -} - -/** - * rstrtok - Split a string into tokens - * @s: The string to be searched - * @ct: The characters to search for - * * WARNING: strtok is deprecated, use strsep instead. However strsep is not compatible with old architecture. - */ -char * __rstrtok; -char * rstrtok(char * s,const char * ct) -{ - char *sbegin, *send; - - sbegin = s ? s : __rstrtok; - if (!sbegin) - { - return NULL; - } - - sbegin += strspn(sbegin,ct); - if (*sbegin == '\0') - { - __rstrtok = NULL; - return( NULL ); - } - - send = strpbrk( sbegin, ct); - if (send && *send != '\0') - *send++ = '\0'; - - __rstrtok = send; - - return (sbegin); -} - -/** - * delimitcnt - return the count of a given delimiter in a given string. - * @s: The string to be searched. - * @ct: The delimiter to search for. - * Notice : We suppose the delimiter is a single-char string(for example : ";"). - */ -INT delimitcnt(char * s,const char * ct) -{ - INT count = 0; - /* point to the beginning of the line */ - const char *token = s; - - for ( ;; ) - { - token = strpbrk(token, ct); /* search for delimiters */ - - if ( token == NULL ) - { - /* advanced to the terminating null character */ - break; - } - /* skip the delimiter */ - ++token; - - /* - * Print the found text: use len with %.*s to specify field width. - */ - - /* accumulate delimiter count */ - ++count; - } - return count; -} - -/* - * converts the Internet host address from the standard numbers-and-dots notation - * into binary data. - * returns nonzero if the address is valid, zero if not. - */ -int rtinet_aton(const char *cp, unsigned int *addr) -{ - unsigned int val; - int base, n; - char c; - unsigned int parts[4]; - unsigned int *pp = parts; - - for (;;) - { - /* - * Collect number up to ``.''. - * Values are specified as for C: - * 0x=hex, 0=octal, other=decimal. - */ - val = 0; - base = 10; - if (*cp == '0') - { - if (*++cp == 'x' || *cp == 'X') - base = 16, cp++; - else - base = 8; - } - while ((c = *cp) != '\0') - { - if (isdigit((unsigned char) c)) - { - val = (val * base) + (c - '0'); - cp++; - continue; - } - if (base == 16 && isxdigit((unsigned char) c)) - { - val = (val << 4) + - (c + 10 - (islower((unsigned char) c) ? 'a' : 'A')); - cp++; - continue; - } - break; - } - if (*cp == '.') - { - /* - * Internet format: a.b.c.d a.b.c (with c treated as 16-bits) - * a.b (with b treated as 24 bits) - */ - if (pp >= parts + 3 || val > 0xff) - return 0; - *pp++ = val, cp++; - } - else - break; - } - - /* - * Check for trailing junk. - */ - while (*cp) - if (!isspace((unsigned char) *cp++)) - return 0; - - /* - * Concoct the address according to the number of parts specified. - */ - n = pp - parts + 1; - switch (n) - { - - case 1: /* a -- 32 bits */ - break; - - case 2: /* a.b -- 8.24 bits */ - if (val > 0xffffff) - return 0; - val |= parts[0] << 24; - break; - - case 3: /* a.b.c -- 8.8.16 bits */ - if (val > 0xffff) - return 0; - val |= (parts[0] << 24) | (parts[1] << 16); - break; - - case 4: /* a.b.c.d -- 8.8.8.8 bits */ - if (val > 0xff) - return 0; - val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); - break; - } - - *addr = htonl(val); - return 1; - -} - -/* - ======================================================================== - - Routine Description: - Find key section for Get key parameter. - - Arguments: - buffer Pointer to the buffer to start find the key section - section the key of the secion to be find - - Return Value: - NULL Fail - Others Success - ======================================================================== -*/ -PUCHAR RTMPFindSection( - IN PCHAR buffer) -{ - CHAR temp_buf[32]; - PUCHAR ptr; - - strcpy(temp_buf, "Default"); - - if((ptr = rtstrstr(buffer, temp_buf)) != NULL) - return (ptr+strlen("\n")); - else - return NULL; -} - -/* - ======================================================================== - - Routine Description: - Get key parameter. - - Arguments: - key Pointer to key string - dest Pointer to destination - destsize The datasize of the destination - buffer Pointer to the buffer to start find the key - - Return Value: - TRUE Success - FALSE Fail - - Note: - This routine get the value with the matched key (case case-sensitive) - ======================================================================== -*/ -INT RTMPGetKeyParameter( - IN PCHAR key, - OUT PCHAR dest, - IN INT destsize, - IN PCHAR buffer) -{ - UCHAR *temp_buf1 = NULL; - UCHAR *temp_buf2 = NULL; - CHAR *start_ptr; - CHAR *end_ptr; - CHAR *ptr; - CHAR *offset = 0; - INT len; - - //temp_buf1 = kmalloc(MAX_PARAM_BUFFER_SIZE, MEM_ALLOC_FLAG); - os_alloc_mem(NULL, &temp_buf1, MAX_PARAM_BUFFER_SIZE); - - if(temp_buf1 == NULL) - return (FALSE); - - //temp_buf2 = kmalloc(MAX_PARAM_BUFFER_SIZE, MEM_ALLOC_FLAG); - os_alloc_mem(NULL, &temp_buf2, MAX_PARAM_BUFFER_SIZE); - if(temp_buf2 == NULL) - { - os_free_mem(NULL, temp_buf1); - return (FALSE); - } - - //find section - if((offset = RTMPFindSection(buffer)) == NULL) - { - os_free_mem(NULL, temp_buf1); - os_free_mem(NULL, temp_buf2); - return (FALSE); - } - - strcpy(temp_buf1, "\n"); - strcat(temp_buf1, key); - strcat(temp_buf1, "="); - - //search key - if((start_ptr=rtstrstr(offset, temp_buf1))==NULL) - { - os_free_mem(NULL, temp_buf1); - os_free_mem(NULL, temp_buf2); - return (FALSE); - } - - start_ptr+=strlen("\n"); - if((end_ptr=rtstrstr(start_ptr, "\n"))==NULL) - end_ptr=start_ptr+strlen(start_ptr); - - if (end_ptrSharedKey[i][idx].KeyLen = KeyLen / 2; - AtoH(keybuff, pAd->SharedKey[i][idx].Key, KeyLen / 2); - if (KeyLen == 10) - CipherAlg = CIPHER_WEP64; - else - CipherAlg = CIPHER_WEP128; - pAd->SharedKey[i][idx].CipherAlg = CipherAlg; - - DBGPRINT(RT_DEBUG_TRACE, ("I/F(ra%d) Key%dStr=%s and type=%s\n", i, idx+1, keybuff, (KeyType == 0) ? "Hex":"Ascii")); - return 1; - } - else - {//Invalid key length - DBGPRINT(RT_DEBUG_ERROR, ("I/F(ra%d) Key%dStr is Invalid key length! KeyLen = %ld!\n", i, idx+1, KeyLen)); - return 0; - } - } -} -static void rtmp_read_key_parms_from_file(IN PRTMP_ADAPTER pAd, char *tmpbuf, char *buffer) -{ - char tok_str[16]; - PUCHAR macptr; - INT i = 0, idx; - ULONG KeyType[MAX_MBSSID_NUM]; - ULONG KeyIdx; - - NdisZeroMemory(KeyType, MAX_MBSSID_NUM); - - //DefaultKeyID - if(RTMPGetKeyParameter("DefaultKeyID", tmpbuf, 25, buffer)) - { - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - KeyIdx = simple_strtol(tmpbuf, 0, 10); - if((KeyIdx >= 1 ) && (KeyIdx <= 4)) - pAd->StaCfg.DefaultKeyId = (UCHAR) (KeyIdx - 1); - else - pAd->StaCfg.DefaultKeyId = 0; - - DBGPRINT(RT_DEBUG_TRACE, ("DefaultKeyID(0~3)=%d\n", pAd->StaCfg.DefaultKeyId)); - } -#endif // CONFIG_STA_SUPPORT // - } - - - for (idx = 0; idx < 4; idx++) - { - sprintf(tok_str, "Key%dType", idx + 1); - //Key1Type - if (RTMPGetKeyParameter(tok_str, tmpbuf, 128, buffer)) - { - for (i = 0, macptr = rstrtok(tmpbuf,";"); macptr; macptr = rstrtok(NULL,";"), i++) - { - KeyType[i] = simple_strtol(macptr, 0, 10); - } - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - sprintf(tok_str, "Key%dStr", idx + 1); - if (RTMPGetCriticalParameter(tok_str, tmpbuf, 128, buffer)) - { - rtmp_parse_key_buffer_from_file(pAd, tmpbuf, KeyType[BSS0], BSS0, idx); - } - } -#endif // CONFIG_STA_SUPPORT // - } - } -} - - -#ifdef CONFIG_STA_SUPPORT -static void rtmp_read_sta_wmm_parms_from_file(IN PRTMP_ADAPTER pAd, char *tmpbuf, char *buffer) -{ - PUCHAR macptr; - INT i=0; - BOOLEAN bWmmEnable = FALSE; - - //WmmCapable - if(RTMPGetKeyParameter("WmmCapable", tmpbuf, 32, buffer)) - { - if(simple_strtol(tmpbuf, 0, 10) != 0) //Enable - { - pAd->CommonCfg.bWmmCapable = TRUE; - bWmmEnable = TRUE; - } - else //Disable - { - pAd->CommonCfg.bWmmCapable = FALSE; - } - - DBGPRINT(RT_DEBUG_TRACE, ("WmmCapable=%d\n", pAd->CommonCfg.bWmmCapable)); - } - -#ifdef QOS_DLS_SUPPORT - //DLSCapable - if(RTMPGetKeyParameter("DLSCapable", tmpbuf, 32, buffer)) - { - if(simple_strtol(tmpbuf, 0, 10) != 0) //Enable - { - pAd->CommonCfg.bDLSCapable = TRUE; - } - else //Disable - { - pAd->CommonCfg.bDLSCapable = FALSE; - } - - DBGPRINT(RT_DEBUG_TRACE, ("bDLSCapable=%d\n", pAd->CommonCfg.bDLSCapable)); - } -#endif // QOS_DLS_SUPPORT // - - //AckPolicy for AC_BK, AC_BE, AC_VI, AC_VO - if(RTMPGetKeyParameter("AckPolicy", tmpbuf, 32, buffer)) - { - for (i = 0, macptr = rstrtok(tmpbuf,";"); macptr; macptr = rstrtok(NULL,";"), i++) - { - pAd->CommonCfg.AckPolicy[i] = (UCHAR)simple_strtol(macptr, 0, 10); - - DBGPRINT(RT_DEBUG_TRACE, ("AckPolicy[%d]=%d\n", i, pAd->CommonCfg.AckPolicy[i])); - } - } - - if (bWmmEnable) - { - //APSDCapable - if(RTMPGetKeyParameter("APSDCapable", tmpbuf, 10, buffer)) - { - if(simple_strtol(tmpbuf, 0, 10) != 0) //Enable - pAd->CommonCfg.bAPSDCapable = TRUE; - else - pAd->CommonCfg.bAPSDCapable = FALSE; - - DBGPRINT(RT_DEBUG_TRACE, ("APSDCapable=%d\n", pAd->CommonCfg.bAPSDCapable)); - } - - //APSDAC for AC_BE, AC_BK, AC_VI, AC_VO - if(RTMPGetKeyParameter("APSDAC", tmpbuf, 32, buffer)) - { - BOOLEAN apsd_ac[4]; - - for (i = 0, macptr = rstrtok(tmpbuf,";"); macptr; macptr = rstrtok(NULL,";"), i++) - { - apsd_ac[i] = (BOOLEAN)simple_strtol(macptr, 0, 10); - - DBGPRINT(RT_DEBUG_TRACE, ("APSDAC%d %d\n", i, apsd_ac[i])); - } - - pAd->CommonCfg.bAPSDAC_BE = apsd_ac[0]; - pAd->CommonCfg.bAPSDAC_BK = apsd_ac[1]; - pAd->CommonCfg.bAPSDAC_VI = apsd_ac[2]; - pAd->CommonCfg.bAPSDAC_VO = apsd_ac[3]; - } - } - -} -#endif // CONFIG_STA_SUPPORT // - - -NDIS_STATUS RTMPReadParametersHook( - IN PRTMP_ADAPTER pAd) -{ - PUCHAR src = NULL; - struct file *srcf; - INT retval, orgfsuid, orgfsgid; - mm_segment_t orgfs; - CHAR *buffer; - CHAR *tmpbuf; - ULONG RtsThresh; - ULONG FragThresh; -#ifdef CONFIG_STA_SUPPORT - UCHAR keyMaterial[40]; -#endif // CONFIG_STA_SUPPORT // - - - PUCHAR macptr; - INT i = 0; - - buffer = kmalloc(MAX_INI_BUFFER_SIZE, MEM_ALLOC_FLAG); - if(buffer == NULL) - return NDIS_STATUS_FAILURE; - - tmpbuf = kmalloc(MAX_PARAM_BUFFER_SIZE, MEM_ALLOC_FLAG); - if(tmpbuf == NULL) - { - kfree(buffer); - return NDIS_STATUS_FAILURE; - } - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - src = STA_PROFILE_PATH; -#endif // CONFIG_STA_SUPPORT // -#ifdef MULTIPLE_CARD_SUPPORT - src = pAd->MC_FileName; -#endif // MULTIPLE_CARD_SUPPORT // - - // Save uid and gid used for filesystem access. - // Set user and group to 0 (root) -#if 0 - orgfsuid = current->fsuid; - orgfsgid = current->fsgid; - current->fsuid=current->fsgid = 0; -#endif - orgfs = get_fs(); - set_fs(KERNEL_DS); - - if (src && *src) - { - srcf = filp_open(src, O_RDONLY, 0); - if (IS_ERR(srcf)) - { - DBGPRINT(RT_DEBUG_ERROR, ("--> Error %ld opening %s\n", -PTR_ERR(srcf),src)); - } - else - { - // The object must have a read method - if (srcf->f_op && srcf->f_op->read) - { - memset(buffer, 0x00, MAX_INI_BUFFER_SIZE); - retval=srcf->f_op->read(srcf, buffer, MAX_INI_BUFFER_SIZE, &srcf->f_pos); - if (retval < 0) - { - DBGPRINT(RT_DEBUG_TRACE, ("--> Read %s error %d\n", src, -retval)); - } - else - { - // set file parameter to portcfg - //CountryRegion - if(RTMPGetKeyParameter("CountryRegion", tmpbuf, 25, buffer)) - { - pAd->CommonCfg.CountryRegion = (UCHAR) simple_strtol(tmpbuf, 0, 10); - DBGPRINT(RT_DEBUG_TRACE, ("CountryRegion=%d\n", pAd->CommonCfg.CountryRegion)); - } - //CountryRegionABand - if(RTMPGetKeyParameter("CountryRegionABand", tmpbuf, 25, buffer)) - { - pAd->CommonCfg.CountryRegionForABand= (UCHAR) simple_strtol(tmpbuf, 0, 10); - DBGPRINT(RT_DEBUG_TRACE, ("CountryRegionABand=%d\n", pAd->CommonCfg.CountryRegionForABand)); - } - //CountryCode - if(RTMPGetKeyParameter("CountryCode", tmpbuf, 25, buffer)) - { - NdisMoveMemory(pAd->CommonCfg.CountryCode, tmpbuf , 2); -#ifdef CONFIG_STA_SUPPORT -#ifdef EXT_BUILD_CHANNEL_LIST - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - NdisMoveMemory(pAd->StaCfg.StaOriCountryCode, tmpbuf , 2); -#endif // EXT_BUILD_CHANNEL_LIST // -#endif // CONFIG_STA_SUPPORT // - if (strlen(pAd->CommonCfg.CountryCode) != 0) - { - pAd->CommonCfg.bCountryFlag = TRUE; - } - DBGPRINT(RT_DEBUG_TRACE, ("CountryCode=%s\n", pAd->CommonCfg.CountryCode)); - } - //ChannelGeography - if(RTMPGetKeyParameter("ChannelGeography", tmpbuf, 25, buffer)) - { - UCHAR Geography = (UCHAR) simple_strtol(tmpbuf, 0, 10); - if (Geography <= BOTH) - { - pAd->CommonCfg.Geography = Geography; - pAd->CommonCfg.CountryCode[2] = - (pAd->CommonCfg.Geography == BOTH) ? ' ' : ((pAd->CommonCfg.Geography == IDOR) ? 'I' : 'O'); -#ifdef CONFIG_STA_SUPPORT -#ifdef EXT_BUILD_CHANNEL_LIST - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - pAd->StaCfg.StaOriGeography = pAd->CommonCfg.Geography; -#endif // EXT_BUILD_CHANNEL_LIST // -#endif // CONFIG_STA_SUPPORT // - DBGPRINT(RT_DEBUG_TRACE, ("ChannelGeography=%d\n", pAd->CommonCfg.Geography)); - } - } - else - { - pAd->CommonCfg.Geography = BOTH; - pAd->CommonCfg.CountryCode[2] = ' '; - } - - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - //SSID - if (RTMPGetCriticalParameter("SSID", tmpbuf, 256, buffer)) - { - if (strlen(tmpbuf) <= 32) - { - pAd->CommonCfg.SsidLen = (UCHAR) strlen(tmpbuf); - NdisZeroMemory(pAd->CommonCfg.Ssid, NDIS_802_11_LENGTH_SSID); - NdisMoveMemory(pAd->CommonCfg.Ssid, tmpbuf, pAd->CommonCfg.SsidLen); - pAd->MlmeAux.AutoReconnectSsidLen = pAd->CommonCfg.SsidLen; - NdisZeroMemory(pAd->MlmeAux.AutoReconnectSsid, NDIS_802_11_LENGTH_SSID); - NdisMoveMemory(pAd->MlmeAux.AutoReconnectSsid, tmpbuf, pAd->MlmeAux.AutoReconnectSsidLen); - pAd->MlmeAux.SsidLen = pAd->CommonCfg.SsidLen; - NdisZeroMemory(pAd->MlmeAux.Ssid, NDIS_802_11_LENGTH_SSID); - NdisMoveMemory(pAd->MlmeAux.Ssid, tmpbuf, pAd->MlmeAux.SsidLen); - DBGPRINT(RT_DEBUG_TRACE, ("%s::(SSID=%s)\n", __FUNCTION__, tmpbuf)); - } - } - } -#endif // CONFIG_STA_SUPPORT // - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - //NetworkType - if (RTMPGetKeyParameter("NetworkType", tmpbuf, 25, buffer)) - { - pAd->bConfigChanged = TRUE; - if (strcmp(tmpbuf, "Adhoc") == 0) - pAd->StaCfg.BssType = BSS_ADHOC; - else //Default Infrastructure mode - pAd->StaCfg.BssType = BSS_INFRA; - // Reset Ralink supplicant to not use, it will be set to start when UI set PMK key - pAd->StaCfg.WpaState = SS_NOTUSE; - DBGPRINT(RT_DEBUG_TRACE, ("%s::(NetworkType=%d)\n", __FUNCTION__, pAd->StaCfg.BssType)); - } - } -#endif // CONFIG_STA_SUPPORT // - //Channel - if(RTMPGetKeyParameter("Channel", tmpbuf, 10, buffer)) - { - pAd->CommonCfg.Channel = (UCHAR) simple_strtol(tmpbuf, 0, 10); - DBGPRINT(RT_DEBUG_TRACE, ("Channel=%d\n", pAd->CommonCfg.Channel)); - } - //WirelessMode - if(RTMPGetKeyParameter("WirelessMode", tmpbuf, 10, buffer)) - { - int value = 0, maxPhyMode = PHY_11G; - -#ifdef DOT11_N_SUPPORT - maxPhyMode = PHY_11N_5G; -#endif // DOT11_N_SUPPORT // - - value = simple_strtol(tmpbuf, 0, 10); - - if (value <= maxPhyMode) - { - pAd->CommonCfg.PhyMode = value; - } - DBGPRINT(RT_DEBUG_TRACE, ("PhyMode=%d\n", pAd->CommonCfg.PhyMode)); - } - //BasicRate - if(RTMPGetKeyParameter("BasicRate", tmpbuf, 10, buffer)) - { - pAd->CommonCfg.BasicRateBitmap = (ULONG) simple_strtol(tmpbuf, 0, 10); - DBGPRINT(RT_DEBUG_TRACE, ("BasicRate=%ld\n", pAd->CommonCfg.BasicRateBitmap)); - } - //BeaconPeriod - if(RTMPGetKeyParameter("BeaconPeriod", tmpbuf, 10, buffer)) - { - pAd->CommonCfg.BeaconPeriod = (USHORT) simple_strtol(tmpbuf, 0, 10); - DBGPRINT(RT_DEBUG_TRACE, ("BeaconPeriod=%d\n", pAd->CommonCfg.BeaconPeriod)); - } - //TxPower - if(RTMPGetKeyParameter("TxPower", tmpbuf, 10, buffer)) - { - pAd->CommonCfg.TxPowerPercentage = (ULONG) simple_strtol(tmpbuf, 0, 10); -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - pAd->CommonCfg.TxPowerDefault = pAd->CommonCfg.TxPowerPercentage; -#endif // CONFIG_STA_SUPPORT // - DBGPRINT(RT_DEBUG_TRACE, ("TxPower=%ld\n", pAd->CommonCfg.TxPowerPercentage)); - } - //BGProtection - if(RTMPGetKeyParameter("BGProtection", tmpbuf, 10, buffer)) - { - switch (simple_strtol(tmpbuf, 0, 10)) - { - case 1: //Always On - pAd->CommonCfg.UseBGProtection = 1; - break; - case 2: //Always OFF - pAd->CommonCfg.UseBGProtection = 2; - break; - case 0: //AUTO - default: - pAd->CommonCfg.UseBGProtection = 0; - break; - } - DBGPRINT(RT_DEBUG_TRACE, ("BGProtection=%ld\n", pAd->CommonCfg.UseBGProtection)); - } - //OLBCDetection - if(RTMPGetKeyParameter("DisableOLBC", tmpbuf, 10, buffer)) - { - switch (simple_strtol(tmpbuf, 0, 10)) - { - case 1: //disable OLBC Detection - pAd->CommonCfg.DisableOLBCDetect = 1; - break; - case 0: //enable OLBC Detection - pAd->CommonCfg.DisableOLBCDetect = 0; - break; - default: - pAd->CommonCfg.DisableOLBCDetect= 0; - break; - } - DBGPRINT(RT_DEBUG_TRACE, ("OLBCDetection=%ld\n", pAd->CommonCfg.DisableOLBCDetect)); - } - //TxPreamble - if(RTMPGetKeyParameter("TxPreamble", tmpbuf, 10, buffer)) - { - switch (simple_strtol(tmpbuf, 0, 10)) - { - case Rt802_11PreambleShort: - pAd->CommonCfg.TxPreamble = Rt802_11PreambleShort; - break; - case Rt802_11PreambleLong: - default: - pAd->CommonCfg.TxPreamble = Rt802_11PreambleLong; - break; - } - DBGPRINT(RT_DEBUG_TRACE, ("TxPreamble=%ld\n", pAd->CommonCfg.TxPreamble)); - } - //RTSThreshold - if(RTMPGetKeyParameter("RTSThreshold", tmpbuf, 10, buffer)) - { - RtsThresh = simple_strtol(tmpbuf, 0, 10); - if( (RtsThresh >= 1) && (RtsThresh <= MAX_RTS_THRESHOLD) ) - pAd->CommonCfg.RtsThreshold = (USHORT)RtsThresh; - else - pAd->CommonCfg.RtsThreshold = MAX_RTS_THRESHOLD; - - DBGPRINT(RT_DEBUG_TRACE, ("RTSThreshold=%d\n", pAd->CommonCfg.RtsThreshold)); - } - //FragThreshold - if(RTMPGetKeyParameter("FragThreshold", tmpbuf, 10, buffer)) - { - FragThresh = simple_strtol(tmpbuf, 0, 10); - pAd->CommonCfg.bUseZeroToDisableFragment = FALSE; - - if (FragThresh > MAX_FRAG_THRESHOLD || FragThresh < MIN_FRAG_THRESHOLD) - { //illegal FragThresh so we set it to default - pAd->CommonCfg.FragmentThreshold = MAX_FRAG_THRESHOLD; - pAd->CommonCfg.bUseZeroToDisableFragment = TRUE; - } - else if (FragThresh % 2 == 1) - { - // The length of each fragment shall always be an even number of octets, except for the last fragment - // of an MSDU or MMPDU, which may be either an even or an odd number of octets. - pAd->CommonCfg.FragmentThreshold = (USHORT)(FragThresh - 1); - } - else - { - pAd->CommonCfg.FragmentThreshold = (USHORT)FragThresh; - } - //pAd->CommonCfg.AllowFragSize = (pAd->CommonCfg.FragmentThreshold) - LENGTH_802_11 - LENGTH_CRC; - DBGPRINT(RT_DEBUG_TRACE, ("FragThreshold=%d\n", pAd->CommonCfg.FragmentThreshold)); - } - //TxBurst - if(RTMPGetKeyParameter("TxBurst", tmpbuf, 10, buffer)) - { -//#ifdef WIFI_TEST -// pAd->CommonCfg.bEnableTxBurst = FALSE; -//#else - if(simple_strtol(tmpbuf, 0, 10) != 0) //Enable - pAd->CommonCfg.bEnableTxBurst = TRUE; - else //Disable - pAd->CommonCfg.bEnableTxBurst = FALSE; -//#endif - DBGPRINT(RT_DEBUG_TRACE, ("TxBurst=%d\n", pAd->CommonCfg.bEnableTxBurst)); - } - -#ifdef AGGREGATION_SUPPORT - //PktAggregate - if(RTMPGetKeyParameter("PktAggregate", tmpbuf, 10, buffer)) - { - if(simple_strtol(tmpbuf, 0, 10) != 0) //Enable - pAd->CommonCfg.bAggregationCapable = TRUE; - else //Disable - pAd->CommonCfg.bAggregationCapable = FALSE; -#ifdef PIGGYBACK_SUPPORT - pAd->CommonCfg.bPiggyBackCapable = pAd->CommonCfg.bAggregationCapable; -#endif // PIGGYBACK_SUPPORT // - DBGPRINT(RT_DEBUG_TRACE, ("PktAggregate=%d\n", pAd->CommonCfg.bAggregationCapable)); - } -#else - pAd->CommonCfg.bAggregationCapable = FALSE; - pAd->CommonCfg.bPiggyBackCapable = FALSE; -#endif // AGGREGATION_SUPPORT // - - // WmmCapable - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - rtmp_read_sta_wmm_parms_from_file(pAd, tmpbuf, buffer); -#endif // CONFIG_STA_SUPPORT // - - //ShortSlot - if(RTMPGetKeyParameter("ShortSlot", tmpbuf, 10, buffer)) - { - if(simple_strtol(tmpbuf, 0, 10) != 0) //Enable - pAd->CommonCfg.bUseShortSlotTime = TRUE; - else //Disable - pAd->CommonCfg.bUseShortSlotTime = FALSE; - - DBGPRINT(RT_DEBUG_TRACE, ("ShortSlot=%d\n", pAd->CommonCfg.bUseShortSlotTime)); - } - //IEEE80211H - if(RTMPGetKeyParameter("IEEE80211H", tmpbuf, 10, buffer)) - { - for (i = 0, macptr = rstrtok(tmpbuf,";"); macptr; macptr = rstrtok(NULL,";"), i++) - { - if(simple_strtol(macptr, 0, 10) != 0) //Enable - pAd->CommonCfg.bIEEE80211H = TRUE; - else //Disable - pAd->CommonCfg.bIEEE80211H = FALSE; - - DBGPRINT(RT_DEBUG_TRACE, ("IEEE80211H=%d\n", pAd->CommonCfg.bIEEE80211H)); - } - } - //CSPeriod - if(RTMPGetKeyParameter("CSPeriod", tmpbuf, 10, buffer)) - { - if(simple_strtol(tmpbuf, 0, 10) != 0) - pAd->CommonCfg.RadarDetect.CSPeriod = simple_strtol(tmpbuf, 0, 10); - else - pAd->CommonCfg.RadarDetect.CSPeriod = 0; - - DBGPRINT(RT_DEBUG_TRACE, ("CSPeriod=%d\n", pAd->CommonCfg.RadarDetect.CSPeriod)); - } - - //RDRegion - if(RTMPGetKeyParameter("RDRegion", tmpbuf, 128, buffer)) - { - if ((strncmp(tmpbuf, "JAP_W53", 7) == 0) || (strncmp(tmpbuf, "jap_w53", 7) == 0)) - { - pAd->CommonCfg.RadarDetect.RDDurRegion = JAP_W53; - pAd->CommonCfg.RadarDetect.DfsSessionTime = 15; - } - else if ((strncmp(tmpbuf, "JAP_W56", 7) == 0) || (strncmp(tmpbuf, "jap_w56", 7) == 0)) - { - pAd->CommonCfg.RadarDetect.RDDurRegion = JAP_W56; - pAd->CommonCfg.RadarDetect.DfsSessionTime = 13; - } - else if ((strncmp(tmpbuf, "JAP", 3) == 0) || (strncmp(tmpbuf, "jap", 3) == 0)) - { - pAd->CommonCfg.RadarDetect.RDDurRegion = JAP; - pAd->CommonCfg.RadarDetect.DfsSessionTime = 5; - } - else if ((strncmp(tmpbuf, "FCC", 3) == 0) || (strncmp(tmpbuf, "fcc", 3) == 0)) - { - pAd->CommonCfg.RadarDetect.RDDurRegion = FCC; - pAd->CommonCfg.RadarDetect.DfsSessionTime = 5; - } - else if ((strncmp(tmpbuf, "CE", 2) == 0) || (strncmp(tmpbuf, "ce", 2) == 0)) - { - pAd->CommonCfg.RadarDetect.RDDurRegion = CE; - pAd->CommonCfg.RadarDetect.DfsSessionTime = 13; - } - else - { - pAd->CommonCfg.RadarDetect.RDDurRegion = CE; - pAd->CommonCfg.RadarDetect.DfsSessionTime = 13; - } - - DBGPRINT(RT_DEBUG_TRACE, ("RDRegion=%d\n", pAd->CommonCfg.RadarDetect.RDDurRegion)); - } - else - { - pAd->CommonCfg.RadarDetect.RDDurRegion = CE; - pAd->CommonCfg.RadarDetect.DfsSessionTime = 13; - } - - //WirelessEvent - if(RTMPGetKeyParameter("WirelessEvent", tmpbuf, 10, buffer)) - { -#if WIRELESS_EXT >= 15 - if(simple_strtol(tmpbuf, 0, 10) != 0) - pAd->CommonCfg.bWirelessEvent = simple_strtol(tmpbuf, 0, 10); - else - pAd->CommonCfg.bWirelessEvent = 0; // disable -#else - pAd->CommonCfg.bWirelessEvent = 0; // disable -#endif - DBGPRINT(RT_DEBUG_TRACE, ("WirelessEvent=%d\n", pAd->CommonCfg.bWirelessEvent)); - } - if(RTMPGetKeyParameter("WiFiTest", tmpbuf, 10, buffer)) - { - if(simple_strtol(tmpbuf, 0, 10) != 0) - pAd->CommonCfg.bWiFiTest= simple_strtol(tmpbuf, 0, 10); - else - pAd->CommonCfg.bWiFiTest = 0; // disable - - DBGPRINT(RT_DEBUG_TRACE, ("WiFiTest=%d\n", pAd->CommonCfg.bWiFiTest)); - } - //AuthMode - if(RTMPGetKeyParameter("AuthMode", tmpbuf, 128, buffer)) - { -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - if ((strcmp(tmpbuf, "WEPAUTO") == 0) || (strcmp(tmpbuf, "wepauto") == 0)) - pAd->StaCfg.AuthMode = Ndis802_11AuthModeAutoSwitch; - else if ((strcmp(tmpbuf, "SHARED") == 0) || (strcmp(tmpbuf, "shared") == 0)) - pAd->StaCfg.AuthMode = Ndis802_11AuthModeShared; - else if ((strcmp(tmpbuf, "WPAPSK") == 0) || (strcmp(tmpbuf, "wpapsk") == 0)) - pAd->StaCfg.AuthMode = Ndis802_11AuthModeWPAPSK; - else if ((strcmp(tmpbuf, "WPANONE") == 0) || (strcmp(tmpbuf, "wpanone") == 0)) - pAd->StaCfg.AuthMode = Ndis802_11AuthModeWPANone; - else if ((strcmp(tmpbuf, "WPA2PSK") == 0) || (strcmp(tmpbuf, "wpa2psk") == 0)) - pAd->StaCfg.AuthMode = Ndis802_11AuthModeWPA2PSK; -#ifdef WPA_SUPPLICANT_SUPPORT - else if ((strcmp(tmpbuf, "WPA") == 0) || (strcmp(tmpbuf, "wpa") == 0)) - pAd->StaCfg.AuthMode = Ndis802_11AuthModeWPA; - else if ((strcmp(tmpbuf, "WPA2") == 0) || (strcmp(tmpbuf, "wpa2") == 0)) - pAd->StaCfg.AuthMode = Ndis802_11AuthModeWPA2; -#endif // WPA_SUPPLICANT_SUPPORT // - else - pAd->StaCfg.AuthMode = Ndis802_11AuthModeOpen; - - pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; - - DBGPRINT(RT_DEBUG_TRACE, ("%s::(EncrypType=%d)\n", __FUNCTION__, pAd->StaCfg.WepStatus)); - } -#endif // CONFIG_STA_SUPPORT // - } - //EncrypType - if(RTMPGetKeyParameter("EncrypType", tmpbuf, 128, buffer)) - { - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - if ((strcmp(tmpbuf, "WEP") == 0) || (strcmp(tmpbuf, "wep") == 0)) - pAd->StaCfg.WepStatus = Ndis802_11WEPEnabled; - else if ((strcmp(tmpbuf, "TKIP") == 0) || (strcmp(tmpbuf, "tkip") == 0)) - pAd->StaCfg.WepStatus = Ndis802_11Encryption2Enabled; - else if ((strcmp(tmpbuf, "AES") == 0) || (strcmp(tmpbuf, "aes") == 0)) - pAd->StaCfg.WepStatus = Ndis802_11Encryption3Enabled; - else - pAd->StaCfg.WepStatus = Ndis802_11WEPDisabled; - - // Update all wepstatus related - pAd->StaCfg.PairCipher = pAd->StaCfg.WepStatus; - pAd->StaCfg.GroupCipher = pAd->StaCfg.WepStatus; - pAd->StaCfg.OrigWepStatus = pAd->StaCfg.WepStatus; - pAd->StaCfg.bMixCipher = FALSE; - - //RTMPMakeRSNIE(pAd, pAd->StaCfg.AuthMode, pAd->StaCfg.WepStatus, 0); - DBGPRINT(RT_DEBUG_TRACE, ("%s::(EncrypType=%d)\n", __FUNCTION__, pAd->StaCfg.WepStatus)); - } -#endif // CONFIG_STA_SUPPORT // - } - - - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - if(RTMPGetCriticalParameter("WPAPSK", tmpbuf, 512, buffer)) - { - int err=0; - - tmpbuf[strlen(tmpbuf)] = '\0'; // make STA can process .$^& for WPAPSK input - - if ((pAd->StaCfg.AuthMode != Ndis802_11AuthModeWPAPSK) && - (pAd->StaCfg.AuthMode != Ndis802_11AuthModeWPA2PSK) && - (pAd->StaCfg.AuthMode != Ndis802_11AuthModeWPANone) - ) - { - err = 1; - } - else if ((strlen(tmpbuf) >= 8) && (strlen(tmpbuf) < 64)) - { - PasswordHash((char *)tmpbuf, pAd->CommonCfg.Ssid, pAd->CommonCfg.SsidLen, keyMaterial); - NdisMoveMemory(pAd->StaCfg.PMK, keyMaterial, 32); - - } - else if (strlen(tmpbuf) == 64) - { - AtoH(tmpbuf, keyMaterial, 32); - NdisMoveMemory(pAd->StaCfg.PMK, keyMaterial, 32); - } - else - { - err = 1; - DBGPRINT(RT_DEBUG_ERROR, ("%s::(WPAPSK key-string required 8 ~ 64 characters!)\n", __FUNCTION__)); - } - - if (err == 0) - { - if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) || - (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)) - { - // Start STA supplicant state machine - pAd->StaCfg.WpaState = SS_START; - } - else if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) - { - /* - NdisZeroMemory(&pAd->SharedKey[BSS0][0], sizeof(CIPHER_KEY)); - pAd->SharedKey[BSS0][0].KeyLen = LEN_TKIP_EK; - NdisMoveMemory(pAd->SharedKey[BSS0][0].Key, pAd->StaCfg.PMK, LEN_TKIP_EK); - NdisMoveMemory(pAd->SharedKey[BSS0][0].RxMic, &pAd->StaCfg.PMK[16], LEN_TKIP_RXMICK); - NdisMoveMemory(pAd->SharedKey[BSS0][0].TxMic, &pAd->StaCfg.PMK[16], LEN_TKIP_TXMICK); - - // Decide its ChiperAlg - if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled) - pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_TKIP; - else if (pAd->StaCfg.PairCipher == Ndis802_11Encryption3Enabled) - pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_AES; - else - pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_NONE; - */ - pAd->StaCfg.WpaState = SS_NOTUSE; - } - - DBGPRINT(RT_DEBUG_TRACE, ("%s::(WPAPSK=%s)\n", __FUNCTION__, tmpbuf)); - } - } - } -#endif // CONFIG_STA_SUPPORT // - - //DefaultKeyID, KeyType, KeyStr - rtmp_read_key_parms_from_file(pAd, tmpbuf, buffer); - - - //HSCounter - /*if(RTMPGetKeyParameter("HSCounter", tmpbuf, 10, buffer)) - { - switch (simple_strtol(tmpbuf, 0, 10)) - { - case 1: //Enable - pAd->CommonCfg.bEnableHSCounter = TRUE; - break; - case 0: //Disable - default: - pAd->CommonCfg.bEnableHSCounter = FALSE; - break; - } - DBGPRINT(RT_DEBUG_TRACE, "HSCounter=%d\n", pAd->CommonCfg.bEnableHSCounter); - }*/ - -#ifdef DOT11_N_SUPPORT - HTParametersHook(pAd, tmpbuf, buffer); -#endif // DOT11_N_SUPPORT // - - -#ifdef CARRIER_DETECTION_SUPPORT - //CarrierDetect - if(RTMPGetKeyParameter("CarrierDetect", tmpbuf, 128, buffer)) - { - if ((strncmp(tmpbuf, "0", 1) == 0)) - pAd->CommonCfg.CarrierDetect.Enable = FALSE; - else if ((strncmp(tmpbuf, "1", 1) == 0)) - pAd->CommonCfg.CarrierDetect.Enable = TRUE; - else - pAd->CommonCfg.CarrierDetect.Enable = FALSE; - - DBGPRINT(RT_DEBUG_TRACE, ("CarrierDetect.Enable=%d\n", pAd->CommonCfg.CarrierDetect.Enable)); - } - else - pAd->CommonCfg.CarrierDetect.Enable = FALSE; -#endif // CARRIER_DETECTION_SUPPORT // - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - //PSMode - if (RTMPGetKeyParameter("PSMode", tmpbuf, 10, buffer)) - { - if (pAd->StaCfg.BssType == BSS_INFRA) - { - if ((strcmp(tmpbuf, "MAX_PSP") == 0) || (strcmp(tmpbuf, "max_psp") == 0)) - { - // do NOT turn on PSM bit here, wait until MlmeCheckForPsmChange() - // to exclude certain situations. - // MlmeSetPsm(pAd, PWR_SAVE); - OPSTATUS_SET_FLAG(pAd, fOP_STATUS_RECEIVE_DTIM); - if (pAd->StaCfg.bWindowsACCAMEnable == FALSE) - pAd->StaCfg.WindowsPowerMode = Ndis802_11PowerModeMAX_PSP; - pAd->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeMAX_PSP; - pAd->StaCfg.DefaultListenCount = 5; - } - else if ((strcmp(tmpbuf, "Fast_PSP") == 0) || (strcmp(tmpbuf, "fast_psp") == 0) - || (strcmp(tmpbuf, "FAST_PSP") == 0)) - { - // do NOT turn on PSM bit here, wait until MlmeCheckForPsmChange() - // to exclude certain situations. - // MlmeSetPsmBit(pAd, PWR_SAVE); - OPSTATUS_SET_FLAG(pAd, fOP_STATUS_RECEIVE_DTIM); - if (pAd->StaCfg.bWindowsACCAMEnable == FALSE) - pAd->StaCfg.WindowsPowerMode = Ndis802_11PowerModeFast_PSP; - pAd->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeFast_PSP; - pAd->StaCfg.DefaultListenCount = 3; - } - else if ((strcmp(tmpbuf, "Legacy_PSP") == 0) || (strcmp(tmpbuf, "legacy_psp") == 0) - || (strcmp(tmpbuf, "LEGACY_PSP") == 0)) - { - // do NOT turn on PSM bit here, wait until MlmeCheckForPsmChange() - // to exclude certain situations. - // MlmeSetPsmBit(pAd, PWR_SAVE); - OPSTATUS_SET_FLAG(pAd, fOP_STATUS_RECEIVE_DTIM); - if (pAd->StaCfg.bWindowsACCAMEnable == FALSE) - pAd->StaCfg.WindowsPowerMode = Ndis802_11PowerModeLegacy_PSP; - pAd->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeLegacy_PSP; - pAd->StaCfg.DefaultListenCount = 3; - } - else - { //Default Ndis802_11PowerModeCAM - // clear PSM bit immediately - MlmeSetPsmBit(pAd, PWR_ACTIVE); - OPSTATUS_SET_FLAG(pAd, fOP_STATUS_RECEIVE_DTIM); - if (pAd->StaCfg.bWindowsACCAMEnable == FALSE) - pAd->StaCfg.WindowsPowerMode = Ndis802_11PowerModeCAM; - pAd->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeCAM; - } - DBGPRINT(RT_DEBUG_TRACE, ("PSMode=%ld\n", pAd->StaCfg.WindowsPowerMode)); - } - } - // FastRoaming - if (RTMPGetKeyParameter("FastRoaming", tmpbuf, 32, buffer)) - { - if (simple_strtol(tmpbuf, 0, 10) == 0) - pAd->StaCfg.bFastRoaming = FALSE; - else - pAd->StaCfg.bFastRoaming = TRUE; - - DBGPRINT(RT_DEBUG_TRACE, ("FastRoaming=%d\n", pAd->StaCfg.bFastRoaming)); - } - // RoamThreshold - if (RTMPGetKeyParameter("RoamThreshold", tmpbuf, 32, buffer)) - { - long lInfo = simple_strtol(tmpbuf, 0, 10); - - if (lInfo > 90 || lInfo < 60) - pAd->StaCfg.dBmToRoam = -70; - else - pAd->StaCfg.dBmToRoam = (CHAR)(-1)*lInfo; - - DBGPRINT(RT_DEBUG_TRACE, ("RoamThreshold=%d dBm\n", pAd->StaCfg.dBmToRoam)); - } - - if(RTMPGetKeyParameter("TGnWifiTest", tmpbuf, 10, buffer)) - { - if(simple_strtol(tmpbuf, 0, 10) == 0) - pAd->StaCfg.bTGnWifiTest = FALSE; - else - pAd->StaCfg.bTGnWifiTest = TRUE; - DBGPRINT(RT_DEBUG_TRACE, ("TGnWifiTest=%d\n", pAd->StaCfg.bTGnWifiTest)); - } - } -#endif // CONFIG_STA_SUPPORT // - - -#ifdef RT30xx -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - if(RTMPGetKeyParameter("AntDiversity", tmpbuf, 10, buffer)) - { - for (i = 0, macptr = rstrtok(tmpbuf,";"); macptr; macptr = rstrtok(NULL,";"), i++) - { - if(simple_strtol(macptr, 0, 10) != 0) //Enable - pAd->CommonCfg.bRxAntDiversity = TRUE; - else //Disable - pAd->CommonCfg.bRxAntDiversity = FALSE; - - DBGPRINT(RT_DEBUG_ERROR, ("AntDiversity=%d\n", pAd->CommonCfg.bRxAntDiversity)); - } - } - } -#endif // CONFIG_STA_SUPPORT // -#endif // RT30xx // - } - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("--> %s does not have a write method\n", src)); - } - - retval=filp_close(srcf,NULL); - - if (retval) - { - DBGPRINT(RT_DEBUG_TRACE, ("--> Error %d closing %s\n", -retval, src)); - } - } - } - - set_fs(orgfs); -#if 0 - current->fsuid = orgfsuid; - current->fsgid = orgfsgid; -#endif - - kfree(buffer); - kfree(tmpbuf); - - return (NDIS_STATUS_SUCCESS); -} - -#ifdef DOT11_N_SUPPORT -static void HTParametersHook( - IN PRTMP_ADAPTER pAd, - IN CHAR *pValueStr, - IN CHAR *pInput) -{ - - INT Value; - - if (RTMPGetKeyParameter("HT_PROTECT", pValueStr, 25, pInput)) - { - Value = simple_strtol(pValueStr, 0, 10); - if (Value == 0) - { - pAd->CommonCfg.bHTProtect = FALSE; - } - else - { - pAd->CommonCfg.bHTProtect = TRUE; - } - DBGPRINT(RT_DEBUG_TRACE, ("HT: Protection = %s\n", (Value==0) ? "Disable" : "Enable")); - } - - if (RTMPGetKeyParameter("HT_MIMOPSEnable", pValueStr, 25, pInput)) - { - Value = simple_strtol(pValueStr, 0, 10); - if (Value == 0) - { - pAd->CommonCfg.bMIMOPSEnable = FALSE; - } - else - { - pAd->CommonCfg.bMIMOPSEnable = TRUE; - } - DBGPRINT(RT_DEBUG_TRACE, ("HT: MIMOPSEnable = %s\n", (Value==0) ? "Disable" : "Enable")); - } - - - if (RTMPGetKeyParameter("HT_MIMOPSMode", pValueStr, 25, pInput)) - { - Value = simple_strtol(pValueStr, 0, 10); - if (Value > MMPS_ENABLE) - { - pAd->CommonCfg.BACapability.field.MMPSmode = MMPS_ENABLE; - } - else - { - //TODO: add mimo power saving mechanism - pAd->CommonCfg.BACapability.field.MMPSmode = MMPS_ENABLE; - //pAd->CommonCfg.BACapability.field.MMPSmode = Value; - } - DBGPRINT(RT_DEBUG_TRACE, ("HT: MIMOPS Mode = %d\n", Value)); - } - - if (RTMPGetKeyParameter("HT_BADecline", pValueStr, 25, pInput)) - { - Value = simple_strtol(pValueStr, 0, 10); - if (Value == 0) - { - pAd->CommonCfg.bBADecline = FALSE; - } - else - { - pAd->CommonCfg.bBADecline = TRUE; - } - DBGPRINT(RT_DEBUG_TRACE, ("HT: BA Decline = %s\n", (Value==0) ? "Disable" : "Enable")); - } - - - if (RTMPGetKeyParameter("HT_DisableReordering", pValueStr, 25, pInput)) - { - Value = simple_strtol(pValueStr, 0, 10); - if (Value == 0) - { - pAd->CommonCfg.bDisableReordering = FALSE; - } - else - { - pAd->CommonCfg.bDisableReordering = TRUE; - } - DBGPRINT(RT_DEBUG_TRACE, ("HT: DisableReordering = %s\n", (Value==0) ? "Disable" : "Enable")); - } - - if (RTMPGetKeyParameter("HT_AutoBA", pValueStr, 25, pInput)) - { - Value = simple_strtol(pValueStr, 0, 10); - if (Value == 0) - { - pAd->CommonCfg.BACapability.field.AutoBA = FALSE; - pAd->CommonCfg.BACapability.field.Policy = BA_NOTUSE; - } - else - { - pAd->CommonCfg.BACapability.field.AutoBA = TRUE; - pAd->CommonCfg.BACapability.field.Policy = IMMED_BA; - } - pAd->CommonCfg.REGBACapability.field.AutoBA = pAd->CommonCfg.BACapability.field.AutoBA; - pAd->CommonCfg.REGBACapability.field.Policy = pAd->CommonCfg.BACapability.field.Policy; - DBGPRINT(RT_DEBUG_TRACE, ("HT: Auto BA = %s\n", (Value==0) ? "Disable" : "Enable")); - } - - // Tx_+HTC frame - if (RTMPGetKeyParameter("HT_HTC", pValueStr, 25, pInput)) - { - Value = simple_strtol(pValueStr, 0, 10); - if (Value == 0) - { - pAd->HTCEnable = FALSE; - } - else - { - pAd->HTCEnable = TRUE; - } - DBGPRINT(RT_DEBUG_TRACE, ("HT: Tx +HTC frame = %s\n", (Value==0) ? "Disable" : "Enable")); - } - - // Enable HT Link Adaptation Control - if (RTMPGetKeyParameter("HT_LinkAdapt", pValueStr, 25, pInput)) - { - Value = simple_strtol(pValueStr, 0, 10); - if (Value == 0) - { - pAd->bLinkAdapt = FALSE; - } - else - { - pAd->HTCEnable = TRUE; - pAd->bLinkAdapt = TRUE; - } - DBGPRINT(RT_DEBUG_TRACE, ("HT: Link Adaptation Control = %s\n", (Value==0) ? "Disable" : "Enable(+HTC)")); - } - - // Reverse Direction Mechanism - if (RTMPGetKeyParameter("HT_RDG", pValueStr, 25, pInput)) - { - Value = simple_strtol(pValueStr, 0, 10); - if (Value == 0) - { - pAd->CommonCfg.bRdg = FALSE; - } - else - { - pAd->HTCEnable = TRUE; - pAd->CommonCfg.bRdg = TRUE; - } - DBGPRINT(RT_DEBUG_TRACE, ("HT: RDG = %s\n", (Value==0) ? "Disable" : "Enable(+HTC)")); - } - - - - - // Tx A-MSUD ? - if (RTMPGetKeyParameter("HT_AMSDU", pValueStr, 25, pInput)) - { - Value = simple_strtol(pValueStr, 0, 10); - if (Value == 0) - { - pAd->CommonCfg.BACapability.field.AmsduEnable = FALSE; - } - else - { - pAd->CommonCfg.BACapability.field.AmsduEnable = TRUE; - } - DBGPRINT(RT_DEBUG_TRACE, ("HT: Tx A-MSDU = %s\n", (Value==0) ? "Disable" : "Enable")); - } - - // MPDU Density - if (RTMPGetKeyParameter("HT_MpduDensity", pValueStr, 25, pInput)) - { - Value = simple_strtol(pValueStr, 0, 10); - if (Value <=7 && Value >= 0) - { - pAd->CommonCfg.BACapability.field.MpduDensity = Value; - DBGPRINT(RT_DEBUG_TRACE, ("HT: MPDU Density = %d\n", Value)); - } - else - { - pAd->CommonCfg.BACapability.field.MpduDensity = 4; - DBGPRINT(RT_DEBUG_TRACE, ("HT: MPDU Density = %d (Default)\n", 4)); - } - } - - // Max Rx BA Window Size - if (RTMPGetKeyParameter("HT_BAWinSize", pValueStr, 25, pInput)) - { - Value = simple_strtol(pValueStr, 0, 10); - - if (Value >=1 && Value <= 64) - { - pAd->CommonCfg.REGBACapability.field.RxBAWinLimit = Value; - pAd->CommonCfg.BACapability.field.RxBAWinLimit = Value; - DBGPRINT(RT_DEBUG_TRACE, ("HT: BA Windw Size = %d\n", Value)); - } - else - { - pAd->CommonCfg.REGBACapability.field.RxBAWinLimit = 64; - pAd->CommonCfg.BACapability.field.RxBAWinLimit = 64; - DBGPRINT(RT_DEBUG_TRACE, ("HT: BA Windw Size = 64 (Defualt)\n")); - } - - } - - // Guard Interval - if (RTMPGetKeyParameter("HT_GI", pValueStr, 25, pInput)) - { - Value = simple_strtol(pValueStr, 0, 10); - - if (Value == GI_400) - { - pAd->CommonCfg.RegTransmitSetting.field.ShortGI = GI_400; - } - else - { - pAd->CommonCfg.RegTransmitSetting.field.ShortGI = GI_800; - } - - DBGPRINT(RT_DEBUG_TRACE, ("HT: Guard Interval = %s\n", (Value==GI_400) ? "400" : "800" )); - } - - // HT Operation Mode : Mixed Mode , Green Field - if (RTMPGetKeyParameter("HT_OpMode", pValueStr, 25, pInput)) - { - Value = simple_strtol(pValueStr, 0, 10); - - if (Value == HTMODE_GF) - { - - pAd->CommonCfg.RegTransmitSetting.field.HTMODE = HTMODE_GF; - } - else - { - pAd->CommonCfg.RegTransmitSetting.field.HTMODE = HTMODE_MM; - } - - DBGPRINT(RT_DEBUG_TRACE, ("HT: Operate Mode = %s\n", (Value==HTMODE_GF) ? "Green Field" : "Mixed Mode" )); - } - - // Fixed Tx mode : CCK, OFDM - if (RTMPGetKeyParameter("FixedTxMode", pValueStr, 25, pInput)) - { - UCHAR fix_tx_mode; - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - fix_tx_mode = FIXED_TXMODE_HT; - - if (strcmp(pValueStr, "OFDM") == 0 || strcmp(pValueStr, "ofdm") == 0) - { - fix_tx_mode = FIXED_TXMODE_OFDM; - } - else if (strcmp(pValueStr, "CCK") == 0 || strcmp(pValueStr, "cck") == 0) - { - fix_tx_mode = FIXED_TXMODE_CCK; - } - else if (strcmp(pValueStr, "HT") == 0 || strcmp(pValueStr, "ht") == 0) - { - fix_tx_mode = FIXED_TXMODE_HT; - } - else - { - Value = simple_strtol(pValueStr, 0, 10); - // 1 : CCK - // 2 : OFDM - // otherwise : HT - if (Value == FIXED_TXMODE_CCK || Value == FIXED_TXMODE_OFDM) - fix_tx_mode = Value; - else - fix_tx_mode = FIXED_TXMODE_HT; - } - - pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode = fix_tx_mode; - DBGPRINT(RT_DEBUG_TRACE, ("Fixed Tx Mode = %d\n", fix_tx_mode)); - - } -#endif // CONFIG_STA_SUPPORT // - } - - - // Channel Width - if (RTMPGetKeyParameter("HT_BW", pValueStr, 25, pInput)) - { - Value = simple_strtol(pValueStr, 0, 10); - - if (Value == BW_40) - { - pAd->CommonCfg.RegTransmitSetting.field.BW = BW_40; - } - else - { - pAd->CommonCfg.RegTransmitSetting.field.BW = BW_20; - } - -#ifdef MCAST_RATE_SPECIFIC - pAd->CommonCfg.MCastPhyMode.field.BW = pAd->CommonCfg.RegTransmitSetting.field.BW; -#endif // MCAST_RATE_SPECIFIC // - - DBGPRINT(RT_DEBUG_TRACE, ("HT: Channel Width = %s\n", (Value==BW_40) ? "40 MHz" : "20 MHz" )); - } - - if (RTMPGetKeyParameter("HT_EXTCHA", pValueStr, 25, pInput)) - { - Value = simple_strtol(pValueStr, 0, 10); - - if (Value == 0) - { - - pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_BELOW; - } - else - { - pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_ABOVE; - } - - DBGPRINT(RT_DEBUG_TRACE, ("HT: Ext Channel = %s\n", (Value==0) ? "BELOW" : "ABOVE" )); - } - - // MSC - if (RTMPGetKeyParameter("HT_MCS", pValueStr, 50, pInput)) - { - -#ifdef CONFIG_STA_SUPPORT - IF_DEV_CONFIG_OPMODE_ON_STA(pAd) - { - Value = simple_strtol(pValueStr, 0, 10); - -// if ((Value >= 0 && Value <= 15) || (Value == 32)) - if ((Value >= 0 && Value <= 23) || (Value == 32)) // 3*3 - { - pAd->StaCfg.DesiredTransmitSetting.field.MCS = Value; - pAd->StaCfg.bAutoTxRateSwitch = FALSE; - DBGPRINT(RT_DEBUG_TRACE, ("HT: MCS = %d\n", pAd->StaCfg.DesiredTransmitSetting.field.MCS)); - } - else - { - pAd->StaCfg.DesiredTransmitSetting.field.MCS = MCS_AUTO; - pAd->StaCfg.bAutoTxRateSwitch = TRUE; - DBGPRINT(RT_DEBUG_TRACE, ("HT: MCS = AUTO\n")); - } - } -#endif // CONFIG_STA_SUPPORT // - } - - // STBC - if (RTMPGetKeyParameter("HT_STBC", pValueStr, 25, pInput)) - { - Value = simple_strtol(pValueStr, 0, 10); - if (Value == STBC_USE) - { - pAd->CommonCfg.RegTransmitSetting.field.STBC = STBC_USE; - } - else - { - pAd->CommonCfg.RegTransmitSetting.field.STBC = STBC_NONE; - } - DBGPRINT(RT_DEBUG_TRACE, ("HT: STBC = %d\n", pAd->CommonCfg.RegTransmitSetting.field.STBC)); - } - - // 40_Mhz_Intolerant - if (RTMPGetKeyParameter("HT_40MHZ_INTOLERANT", pValueStr, 25, pInput)) - { - Value = simple_strtol(pValueStr, 0, 10); - if (Value == 0) - { - pAd->CommonCfg.bForty_Mhz_Intolerant = FALSE; - } - else - { - pAd->CommonCfg.bForty_Mhz_Intolerant = TRUE; - } - DBGPRINT(RT_DEBUG_TRACE, ("HT: 40MHZ INTOLERANT = %d\n", pAd->CommonCfg.bForty_Mhz_Intolerant)); - } - //HT_TxStream - if(RTMPGetKeyParameter("HT_TxStream", pValueStr, 10, pInput)) - { - switch (simple_strtol(pValueStr, 0, 10)) - { - case 1: - pAd->CommonCfg.TxStream = 1; - break; - case 2: - pAd->CommonCfg.TxStream = 2; - break; - case 3: // 3*3 - default: - pAd->CommonCfg.TxStream = 3; - - if (pAd->MACVersion < RALINK_2883_VERSION) - pAd->CommonCfg.TxStream = 2; // only 2 tx streams for RT2860 series - break; - } - DBGPRINT(RT_DEBUG_TRACE, ("HT: Tx Stream = %d\n", pAd->CommonCfg.TxStream)); - } - //HT_RxStream - if(RTMPGetKeyParameter("HT_RxStream", pValueStr, 10, pInput)) - { - switch (simple_strtol(pValueStr, 0, 10)) - { - case 1: - pAd->CommonCfg.RxStream = 1; - break; - case 2: - pAd->CommonCfg.RxStream = 2; - break; - case 3: - default: - pAd->CommonCfg.RxStream = 3; - - if (pAd->MACVersion < RALINK_2883_VERSION) - pAd->CommonCfg.RxStream = 2; // only 2 rx streams for RT2860 series - break; - } - DBGPRINT(RT_DEBUG_TRACE, ("HT: Rx Stream = %d\n", pAd->CommonCfg.RxStream)); - } - -} -#endif // DOT11_N_SUPPORT // - +#include "../rt2870/rt_profile.c" diff --git a/drivers/staging/rt3070/rtmp.h b/drivers/staging/rt3070/rtmp.h index d80d74ffbc89..5390ca3eb27a 100644 --- a/drivers/staging/rt3070/rtmp.h +++ b/drivers/staging/rt3070/rtmp.h @@ -1,7728 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - rtmp.h - - Abstract: - Miniport generic portion header file - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Paul Lin 2002-08-01 created - James Tan 2002-09-06 modified (Revise NTCRegTable) - John Chang 2004-09-06 modified for RT2600 -*/ -#ifndef __RTMP_H__ -#define __RTMP_H__ - -#include "link_list.h" -#include "spectrum_def.h" - -#ifdef MLME_EX -#include "mlme_ex_def.h" -#endif // MLME_EX // - -#ifdef CONFIG_STA_SUPPORT -#include "aironet.h" -#endif // CONFIG_STA_SUPPORT // - -#undef AP_WSC_INCLUDED -#undef STA_WSC_INCLUDED -#undef WSC_INCLUDED - - -#ifdef CONFIG_STA_SUPPORT -#endif // CONFIG_STA_SUPPORT // - -#if defined(AP_WSC_INCLUDED) || defined(STA_WSC_INCLUDED) -#define WSC_INCLUDED -#endif - - - - - -//#define DBG 1 - -//#define DBG_DIAGNOSE 1 - -#if defined(CONFIG_AP_SUPPORT) && defined(CONFIG_STA_SUPPORT) -#define IF_DEV_CONFIG_OPMODE_ON_AP(_pAd) if(_pAd->OpMode == OPMODE_AP) -#define IF_DEV_CONFIG_OPMODE_ON_STA(_pAd) if(_pAd->OpMode == OPMODE_STA) -#else -#define IF_DEV_CONFIG_OPMODE_ON_AP(_pAd) -#define IF_DEV_CONFIG_OPMODE_ON_STA(_pAd) -#endif - -#define VIRTUAL_IF_INC(__pAd) ((__pAd)->VirtualIfCnt++) -#define VIRTUAL_IF_DEC(__pAd) ((__pAd)->VirtualIfCnt--) -#define VIRTUAL_IF_NUM(__pAd) ((__pAd)->VirtualIfCnt) - -#ifdef RT2870 -//////////////////////////////////////////////////////////////////////////// -// The TX_BUFFER structure forms the transmitted USB packet to the device -//////////////////////////////////////////////////////////////////////////// -typedef struct __TX_BUFFER{ - union { - UCHAR WirelessPacket[TX_BUFFER_NORMSIZE]; - HEADER_802_11 NullFrame; - PSPOLL_FRAME PsPollPacket; - RTS_FRAME RTSFrame; - }field; - UCHAR Aggregation[4]; //Buffer for save Aggregation size. -} TX_BUFFER, *PTX_BUFFER; - -typedef struct __HTTX_BUFFER{ - union { - UCHAR WirelessPacket[MAX_TXBULK_SIZE]; - HEADER_802_11 NullFrame; - PSPOLL_FRAME PsPollPacket; - RTS_FRAME RTSFrame; - }field; - UCHAR Aggregation[4]; //Buffer for save Aggregation size. -} HTTX_BUFFER, *PHTTX_BUFFER; - - -// used to track driver-generated write irps -typedef struct _TX_CONTEXT -{ - PVOID pAd; //Initialized in MiniportInitialize - PURB pUrb; //Initialized in MiniportInitialize - PIRP pIrp; //used to cancel pending bulk out. - //Initialized in MiniportInitialize - PTX_BUFFER TransferBuffer; //Initialized in MiniportInitialize - ULONG BulkOutSize; - UCHAR BulkOutPipeId; - UCHAR SelfIdx; - BOOLEAN InUse; - BOOLEAN bWaitingBulkOut; // at least one packet is in this TxContext, ready for making IRP anytime. - BOOLEAN bFullForBulkOut; // all tx buffer are full , so waiting for tx bulkout. - BOOLEAN IRPPending; - BOOLEAN LastOne; - BOOLEAN bAggregatible; - UCHAR Header_802_3[LENGTH_802_3]; - UCHAR Rsv[2]; - ULONG DataOffset; - UINT TxRate; - dma_addr_t data_dma; // urb dma on linux - -} TX_CONTEXT, *PTX_CONTEXT, **PPTX_CONTEXT; - - -// used to track driver-generated write irps -typedef struct _HT_TX_CONTEXT -{ - PVOID pAd; //Initialized in MiniportInitialize - PURB pUrb; //Initialized in MiniportInitialize - PIRP pIrp; //used to cancel pending bulk out. - //Initialized in MiniportInitialize - PHTTX_BUFFER TransferBuffer; //Initialized in MiniportInitialize - ULONG BulkOutSize; // Indicate the total bulk-out size in bytes in one bulk-transmission - UCHAR BulkOutPipeId; - BOOLEAN IRPPending; - BOOLEAN LastOne; - BOOLEAN bCurWriting; - BOOLEAN bRingEmpty; - BOOLEAN bCopySavePad; - UCHAR SavedPad[8]; - UCHAR Header_802_3[LENGTH_802_3]; - ULONG CurWritePosition; // Indicate the buffer offset which packet will be inserted start from. - ULONG CurWriteRealPos; // Indicate the buffer offset which packet now are writing to. - ULONG NextBulkOutPosition; // Indicate the buffer start offset of a bulk-transmission - ULONG ENextBulkOutPosition; // Indicate the buffer end offset of a bulk-transmission - UINT TxRate; - dma_addr_t data_dma; // urb dma on linux -} HT_TX_CONTEXT, *PHT_TX_CONTEXT, **PPHT_TX_CONTEXT; - - -// -// Structure to keep track of receive packets and buffers to indicate -// receive data to the protocol. -// -typedef struct _RX_CONTEXT -{ - PUCHAR TransferBuffer; - PVOID pAd; - PIRP pIrp;//used to cancel pending bulk in. - PURB pUrb; - //These 2 Boolean shouldn't both be 1 at the same time. - ULONG BulkInOffset; // number of packets waiting for reordering . -// BOOLEAN ReorderInUse; // At least one packet in this buffer are in reordering buffer and wait for receive indication - BOOLEAN bRxHandling; // Notify this packet is being process now. - BOOLEAN InUse; // USB Hardware Occupied. Wait for USB HW to put packet. - BOOLEAN Readable; // Receive Complete back. OK for driver to indicate receiving packet. - BOOLEAN IRPPending; // TODO: To be removed - atomic_t IrpLock; - NDIS_SPIN_LOCK RxContextLock; - dma_addr_t data_dma; // urb dma on linux -} RX_CONTEXT, *PRX_CONTEXT; -#endif // RT2870 // - - -// -// NDIS Version definitions -// -#ifdef NDIS50_MINIPORT -#define RTMP_NDIS_MAJOR_VERSION 5 -#define RTMP_NDIS_MINOR_VERSION 0 -#endif - -#ifdef NDIS51_MINIPORT -#define RTMP_NDIS_MAJOR_VERSION 5 -#define RTMP_NDIS_MINOR_VERSION 1 -#endif - -extern char NIC_VENDOR_DESC[]; -extern int NIC_VENDOR_DESC_LEN; - -extern unsigned char SNAP_AIRONET[]; -extern unsigned char CipherSuiteCiscoCCKM[]; -extern unsigned char CipherSuiteCiscoCCKMLen; -extern unsigned char CipherSuiteCiscoCCKM24[]; -extern unsigned char CipherSuiteCiscoCCKM24Len; -extern unsigned char CipherSuiteCCXTkip[]; -extern unsigned char CipherSuiteCCXTkipLen; -extern unsigned char CISCO_OUI[]; -extern UCHAR BaSizeArray[4]; - -extern UCHAR BROADCAST_ADDR[MAC_ADDR_LEN]; -extern UCHAR MULTICAST_ADDR[MAC_ADDR_LEN]; -extern UCHAR ZERO_MAC_ADDR[MAC_ADDR_LEN]; -extern ULONG BIT32[32]; -extern UCHAR BIT8[8]; -extern char* CipherName[]; -extern char* MCSToMbps[]; -extern UCHAR RxwiMCSToOfdmRate[12]; -extern UCHAR SNAP_802_1H[6]; -extern UCHAR SNAP_BRIDGE_TUNNEL[6]; -extern UCHAR SNAP_AIRONET[8]; -extern UCHAR CKIP_LLC_SNAP[8]; -extern UCHAR EAPOL_LLC_SNAP[8]; -extern UCHAR EAPOL[2]; -extern UCHAR IPX[2]; -extern UCHAR APPLE_TALK[2]; -extern UCHAR RateIdToPlcpSignal[12]; // see IEEE802.11a-1999 p.14 -extern UCHAR OfdmRateToRxwiMCS[]; -extern UCHAR OfdmSignalToRateId[16] ; -extern UCHAR default_cwmin[4]; -extern UCHAR default_cwmax[4]; -extern UCHAR default_sta_aifsn[4]; -extern UCHAR MapUserPriorityToAccessCategory[8]; - -extern USHORT RateUpPER[]; -extern USHORT RateDownPER[]; -extern UCHAR Phy11BNextRateDownward[]; -extern UCHAR Phy11BNextRateUpward[]; -extern UCHAR Phy11BGNextRateDownward[]; -extern UCHAR Phy11BGNextRateUpward[]; -extern UCHAR Phy11ANextRateDownward[]; -extern UCHAR Phy11ANextRateUpward[]; -extern CHAR RssiSafeLevelForTxRate[]; -extern UCHAR RateIdToMbps[]; -extern USHORT RateIdTo500Kbps[]; - -extern UCHAR CipherSuiteWpaNoneTkip[]; -extern UCHAR CipherSuiteWpaNoneTkipLen; - -extern UCHAR CipherSuiteWpaNoneAes[]; -extern UCHAR CipherSuiteWpaNoneAesLen; - -extern UCHAR SsidIe; -extern UCHAR SupRateIe; -extern UCHAR ExtRateIe; - -#ifdef DOT11_N_SUPPORT -extern UCHAR HtCapIe; -extern UCHAR AddHtInfoIe; -extern UCHAR NewExtChanIe; -#ifdef DOT11N_DRAFT3 -extern UCHAR ExtHtCapIe; -#endif // DOT11N_DRAFT3 // -#endif // DOT11_N_SUPPORT // - -extern UCHAR ErpIe; -extern UCHAR DsIe; -extern UCHAR TimIe; -extern UCHAR WpaIe; -extern UCHAR Wpa2Ie; -extern UCHAR IbssIe; -extern UCHAR Ccx2Ie; -extern UCHAR WapiIe; - -extern UCHAR WPA_OUI[]; -extern UCHAR RSN_OUI[]; -extern UCHAR WAPI_OUI[]; -extern UCHAR WME_INFO_ELEM[]; -extern UCHAR WME_PARM_ELEM[]; -extern UCHAR Ccx2QosInfo[]; -extern UCHAR Ccx2IeInfo[]; -extern UCHAR RALINK_OUI[]; -extern UCHAR PowerConstraintIE[]; - - -extern UCHAR RateSwitchTable[]; -extern UCHAR RateSwitchTable11B[]; -extern UCHAR RateSwitchTable11G[]; -extern UCHAR RateSwitchTable11BG[]; - -#ifdef DOT11_N_SUPPORT -extern UCHAR RateSwitchTable11BGN1S[]; -extern UCHAR RateSwitchTable11BGN2S[]; -extern UCHAR RateSwitchTable11BGN2SForABand[]; -extern UCHAR RateSwitchTable11N1S[]; -extern UCHAR RateSwitchTable11N2S[]; -extern UCHAR RateSwitchTable11N2SForABand[]; - -#ifdef CONFIG_STA_SUPPORT -extern UCHAR PRE_N_HT_OUI[]; -#endif // CONFIG_STA_SUPPORT // -#endif // DOT11_N_SUPPORT // - -#define MAXSEQ (0xFFF) - -#ifdef RALINK_ATE -typedef struct _ATE_INFO { - UCHAR Mode; - CHAR TxPower0; - CHAR TxPower1; - CHAR TxAntennaSel; - CHAR RxAntennaSel; - TXWI_STRUC TxWI; // TXWI - USHORT QID; - UCHAR Addr1[MAC_ADDR_LEN]; - UCHAR Addr2[MAC_ADDR_LEN]; - UCHAR Addr3[MAC_ADDR_LEN]; - UCHAR Channel; - UINT32 TxLength; - UINT32 TxCount; - UINT32 TxDoneCount; // Tx DMA Done - UINT32 RFFreqOffset; - BOOLEAN bRxFer; - BOOLEAN bQATxStart; // Have compiled QA in and use it to ATE tx. - BOOLEAN bQARxStart; // Have compiled QA in and use it to ATE rx. - UINT32 RxTotalCnt; - UINT32 RxCntPerSec; - - CHAR LastSNR0; // last received SNR - CHAR LastSNR1; // last received SNR for 2nd antenna - CHAR LastRssi0; // last received RSSI - CHAR LastRssi1; // last received RSSI for 2nd antenna - CHAR LastRssi2; // last received RSSI for 3rd antenna - CHAR AvgRssi0; // last 8 frames' average RSSI - CHAR AvgRssi1; // last 8 frames' average RSSI - CHAR AvgRssi2; // last 8 frames' average RSSI - SHORT AvgRssi0X8; // sum of last 8 frames' RSSI - SHORT AvgRssi1X8; // sum of last 8 frames' RSSI - SHORT AvgRssi2X8; // sum of last 8 frames' RSSI - - UINT32 NumOfAvgRssiSample; - -#ifdef RALINK_28xx_QA - // Tx frame -#ifdef RT2870 - /* not used in RT2860 */ - TXINFO_STRUC TxInfo; // TxInfo -#endif // RT2870 // - USHORT HLen; // Header Length - USHORT PLen; // Pattern Length - UCHAR Header[32]; // Header buffer - UCHAR Pattern[32]; // Pattern buffer - USHORT DLen; // Data Length - USHORT seq; - UINT32 CID; - pid_t AtePid; - // counters - UINT32 U2M; - UINT32 OtherData; - UINT32 Beacon; - UINT32 OtherCount; - UINT32 TxAc0; - UINT32 TxAc1; - UINT32 TxAc2; - UINT32 TxAc3; - UINT32 TxHCCA; - UINT32 TxMgmt; - UINT32 RSSI0; - UINT32 RSSI1; - UINT32 RSSI2; - UINT32 SNR0; - UINT32 SNR1; - // control - //UINT32 Repeat; // Tx Cpu count - UCHAR TxStatus; // task Tx status // 0 --> task is idle, 1 --> task is running -#endif // RALINK_28xx_QA // -} ATE_INFO, *PATE_INFO; - -#ifdef RALINK_28xx_QA -struct ate_racfghdr { - UINT32 magic_no; - USHORT command_type; - USHORT command_id; - USHORT length; - USHORT sequence; - USHORT status; - UCHAR data[2046]; -} __attribute__((packed)); -#endif // RALINK_28xx_QA // -#endif // RALINK_ATE // - -#ifdef DOT11_N_SUPPORT -struct reordering_mpdu -{ - struct reordering_mpdu *next; - PNDIS_PACKET pPacket; /* coverted to 802.3 frame */ - int Sequence; /* sequence number of MPDU */ - BOOLEAN bAMSDU; -}; - -struct reordering_list -{ - struct reordering_mpdu *next; - int qlen; -}; - -struct reordering_mpdu_pool -{ - PVOID mem; - NDIS_SPIN_LOCK lock; - struct reordering_list freelist; -}; -#endif // DOT11_N_SUPPORT // - -typedef struct _RSSI_SAMPLE { - CHAR LastRssi0; // last received RSSI - CHAR LastRssi1; // last received RSSI - CHAR LastRssi2; // last received RSSI - CHAR AvgRssi0; - CHAR AvgRssi1; - CHAR AvgRssi2; - SHORT AvgRssi0X8; - SHORT AvgRssi1X8; - SHORT AvgRssi2X8; -} RSSI_SAMPLE; - -// -// Queue structure and macros -// -typedef struct _QUEUE_ENTRY { - struct _QUEUE_ENTRY *Next; -} QUEUE_ENTRY, *PQUEUE_ENTRY; - -// Queue structure -typedef struct _QUEUE_HEADER { - PQUEUE_ENTRY Head; - PQUEUE_ENTRY Tail; - ULONG Number; -} QUEUE_HEADER, *PQUEUE_HEADER; - -#define InitializeQueueHeader(QueueHeader) \ -{ \ - (QueueHeader)->Head = (QueueHeader)->Tail = NULL; \ - (QueueHeader)->Number = 0; \ -} - -#define RemoveHeadQueue(QueueHeader) \ -(QueueHeader)->Head; \ -{ \ - PQUEUE_ENTRY pNext; \ - if ((QueueHeader)->Head != NULL) \ - { \ - pNext = (QueueHeader)->Head->Next; \ - (QueueHeader)->Head = pNext; \ - if (pNext == NULL) \ - (QueueHeader)->Tail = NULL; \ - (QueueHeader)->Number--; \ - } \ -} - -#define InsertHeadQueue(QueueHeader, QueueEntry) \ -{ \ - ((PQUEUE_ENTRY)QueueEntry)->Next = (QueueHeader)->Head; \ - (QueueHeader)->Head = (PQUEUE_ENTRY)(QueueEntry); \ - if ((QueueHeader)->Tail == NULL) \ - (QueueHeader)->Tail = (PQUEUE_ENTRY)(QueueEntry); \ - (QueueHeader)->Number++; \ -} - -#define InsertTailQueue(QueueHeader, QueueEntry) \ -{ \ - ((PQUEUE_ENTRY)QueueEntry)->Next = NULL; \ - if ((QueueHeader)->Tail) \ - (QueueHeader)->Tail->Next = (PQUEUE_ENTRY)(QueueEntry); \ - else \ - (QueueHeader)->Head = (PQUEUE_ENTRY)(QueueEntry); \ - (QueueHeader)->Tail = (PQUEUE_ENTRY)(QueueEntry); \ - (QueueHeader)->Number++; \ -} - -// -// Macros for flag and ref count operations -// -#define RTMP_SET_FLAG(_M, _F) ((_M)->Flags |= (_F)) -#define RTMP_CLEAR_FLAG(_M, _F) ((_M)->Flags &= ~(_F)) -#define RTMP_CLEAR_FLAGS(_M) ((_M)->Flags = 0) -#define RTMP_TEST_FLAG(_M, _F) (((_M)->Flags & (_F)) != 0) -#define RTMP_TEST_FLAGS(_M, _F) (((_M)->Flags & (_F)) == (_F)) - -#define OPSTATUS_SET_FLAG(_pAd, _F) ((_pAd)->CommonCfg.OpStatusFlags |= (_F)) -#define OPSTATUS_CLEAR_FLAG(_pAd, _F) ((_pAd)->CommonCfg.OpStatusFlags &= ~(_F)) -#define OPSTATUS_TEST_FLAG(_pAd, _F) (((_pAd)->CommonCfg.OpStatusFlags & (_F)) != 0) - -#define CLIENT_STATUS_SET_FLAG(_pEntry,_F) ((_pEntry)->ClientStatusFlags |= (_F)) -#define CLIENT_STATUS_CLEAR_FLAG(_pEntry,_F) ((_pEntry)->ClientStatusFlags &= ~(_F)) -#define CLIENT_STATUS_TEST_FLAG(_pEntry,_F) (((_pEntry)->ClientStatusFlags & (_F)) != 0) - -#define RX_FILTER_SET_FLAG(_pAd, _F) ((_pAd)->CommonCfg.PacketFilter |= (_F)) -#define RX_FILTER_CLEAR_FLAG(_pAd, _F) ((_pAd)->CommonCfg.PacketFilter &= ~(_F)) -#define RX_FILTER_TEST_FLAG(_pAd, _F) (((_pAd)->CommonCfg.PacketFilter & (_F)) != 0) - -#ifdef CONFIG_STA_SUPPORT -#define STA_NO_SECURITY_ON(_p) (_p->StaCfg.WepStatus == Ndis802_11EncryptionDisabled) -#define STA_WEP_ON(_p) (_p->StaCfg.WepStatus == Ndis802_11Encryption1Enabled) -#define STA_TKIP_ON(_p) (_p->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) -#define STA_AES_ON(_p) (_p->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) - -#define STA_TGN_WIFI_ON(_p) (_p->StaCfg.bTGnWifiTest == TRUE) -#endif // CONFIG_STA_SUPPORT // - -#define CKIP_KP_ON(_p) ((((_p)->StaCfg.CkipFlag) & 0x10) && ((_p)->StaCfg.bCkipCmicOn == TRUE)) -#define CKIP_CMIC_ON(_p) ((((_p)->StaCfg.CkipFlag) & 0x08) && ((_p)->StaCfg.bCkipCmicOn == TRUE)) - - -#define INC_RING_INDEX(_idx, _RingSize) \ -{ \ - (_idx) = (_idx+1) % (_RingSize); \ -} - -// We will have a cost down version which mac version is 0x3090xxxx -#define IS_RT3090(_pAd) ((((_pAd)->MACVersion & 0xffff0000) == 0x30710000) || (((_pAd)->MACVersion & 0xffff0000) == 0x30900000)) - -#define IS_RT3070(_pAd) (((_pAd)->MACVersion & 0xffff0000) == 0x30700000) -#define IS_RT3071(_pAd) (((_pAd)->MACVersion & 0xffff0000) == 0x30710000) -#define IS_RT2070(_pAd) (((_pAd)->RfIcType == RFIC_2020) || ((_pAd)->EFuseTag == 0x27)) - -#define IS_RT30xx(_pAd) (((_pAd)->MACVersion & 0xfff00000) == 0x30700000) - -#define RING_PACKET_INIT(_TxRing, _idx) \ -{ \ - _TxRing->Cell[_idx].pNdisPacket = NULL; \ - _TxRing->Cell[_idx].pNextNdisPacket = NULL; \ -} - -#define TXDT_INIT(_TxD) \ -{ \ - NdisZeroMemory(_TxD, TXD_SIZE); \ - _TxD->DMADONE = 1; \ -} - -//Set last data segment -#define RING_SET_LASTDS(_TxD, _IsSD0) \ -{ \ - if (_IsSD0) {_TxD->LastSec0 = 1;} \ - else {_TxD->LastSec1 = 1;} \ -} - -// Increase TxTsc value for next transmission -// TODO: -// When i==6, means TSC has done one full cycle, do re-keying stuff follow specs -// Should send a special event microsoft defined to request re-key -#define INC_TX_TSC(_tsc) \ -{ \ - int i=0; \ - while (++_tsc[i] == 0x0) \ - { \ - i++; \ - if (i == 6) \ - break; \ - } \ -} - -#ifdef DOT11_N_SUPPORT -// StaActive.SupportedHtPhy.MCSSet is copied from AP beacon. Don't need to update here. -#define COPY_HTSETTINGS_FROM_MLME_AUX_TO_ACTIVE_CFG(_pAd) \ -{ \ - _pAd->StaActive.SupportedHtPhy.ChannelWidth = _pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth; \ - _pAd->StaActive.SupportedHtPhy.MimoPs = _pAd->MlmeAux.HtCapability.HtCapInfo.MimoPs; \ - _pAd->StaActive.SupportedHtPhy.GF = _pAd->MlmeAux.HtCapability.HtCapInfo.GF; \ - _pAd->StaActive.SupportedHtPhy.ShortGIfor20 = _pAd->MlmeAux.HtCapability.HtCapInfo.ShortGIfor20; \ - _pAd->StaActive.SupportedHtPhy.ShortGIfor40 = _pAd->MlmeAux.HtCapability.HtCapInfo.ShortGIfor40; \ - _pAd->StaActive.SupportedHtPhy.TxSTBC = _pAd->MlmeAux.HtCapability.HtCapInfo.TxSTBC; \ - _pAd->StaActive.SupportedHtPhy.RxSTBC = _pAd->MlmeAux.HtCapability.HtCapInfo.RxSTBC; \ - _pAd->StaActive.SupportedHtPhy.ExtChanOffset = _pAd->MlmeAux.AddHtInfo.AddHtInfo.ExtChanOffset; \ - _pAd->StaActive.SupportedHtPhy.RecomWidth = _pAd->MlmeAux.AddHtInfo.AddHtInfo.RecomWidth; \ - _pAd->StaActive.SupportedHtPhy.OperaionMode = _pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode; \ - _pAd->StaActive.SupportedHtPhy.NonGfPresent = _pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent; \ - NdisMoveMemory((_pAd)->MacTab.Content[BSSID_WCID].HTCapability.MCSSet, (_pAd)->StaActive.SupportedPhyInfo.MCSSet, sizeof(UCHAR) * 16);\ -} - -#define COPY_AP_HTSETTINGS_FROM_BEACON(_pAd, _pHtCapability) \ -{ \ - _pAd->MacTab.Content[BSSID_WCID].AMsduSize = (UCHAR)(_pHtCapability->HtCapInfo.AMsduSize); \ - _pAd->MacTab.Content[BSSID_WCID].MmpsMode= (UCHAR)(_pHtCapability->HtCapInfo.MimoPs); \ - _pAd->MacTab.Content[BSSID_WCID].MaxRAmpduFactor = (UCHAR)(_pHtCapability->HtCapParm.MaxRAmpduFactor); \ -} -#endif // DOT11_N_SUPPORT // - -// -// MACRO for 32-bit PCI register read / write -// -// Usage : RTMP_IO_READ32( -// PRTMP_ADAPTER pAd, -// ULONG Register_Offset, -// PULONG pValue) -// -// RTMP_IO_WRITE32( -// PRTMP_ADAPTER pAd, -// ULONG Register_Offset, -// ULONG Value) -// - -// -// BBP & RF are using indirect access. Before write any value into it. -// We have to make sure there is no outstanding command pending via checking busy bit. -// -#define MAX_BUSY_COUNT 100 // Number of retry before failing access BBP & RF indirect register -// - -#ifdef RT2870 -#define RTMP_RF_IO_WRITE32(_A, _V) RTUSBWriteRFRegister(_A, _V) -#define RTMP_BBP_IO_READ8_BY_REG_ID(_A, _I, _pV) RTUSBReadBBPRegister(_A, _I, _pV) -#define RTMP_BBP_IO_WRITE8_BY_REG_ID(_A, _I, _V) RTUSBWriteBBPRegister(_A, _I, _V) - -#define BBP_IO_WRITE8_BY_REG_ID(_A, _I, _V) RTUSBWriteBBPRegister(_A, _I, _V) -#define BBP_IO_READ8_BY_REG_ID(_A, _I, _pV) RTUSBReadBBPRegister(_A, _I, _pV) -#endif // RT2870 // - -#ifdef RT30xx -#define RTMP_RF_IO_READ8_BY_REG_ID(_A, _I, _pV) RT30xxReadRFRegister(_A, _I, _pV) -#define RTMP_RF_IO_WRITE8_BY_REG_ID(_A, _I, _V) RT30xxWriteRFRegister(_A, _I, _V) -#endif // RT30xx // - -#define MAP_CHANNEL_ID_TO_KHZ(ch, khz) { \ - switch (ch) \ - { \ - case 1: khz = 2412000; break; \ - case 2: khz = 2417000; break; \ - case 3: khz = 2422000; break; \ - case 4: khz = 2427000; break; \ - case 5: khz = 2432000; break; \ - case 6: khz = 2437000; break; \ - case 7: khz = 2442000; break; \ - case 8: khz = 2447000; break; \ - case 9: khz = 2452000; break; \ - case 10: khz = 2457000; break; \ - case 11: khz = 2462000; break; \ - case 12: khz = 2467000; break; \ - case 13: khz = 2472000; break; \ - case 14: khz = 2484000; break; \ - case 36: /* UNII */ khz = 5180000; break; \ - case 40: /* UNII */ khz = 5200000; break; \ - case 44: /* UNII */ khz = 5220000; break; \ - case 48: /* UNII */ khz = 5240000; break; \ - case 52: /* UNII */ khz = 5260000; break; \ - case 56: /* UNII */ khz = 5280000; break; \ - case 60: /* UNII */ khz = 5300000; break; \ - case 64: /* UNII */ khz = 5320000; break; \ - case 149: /* UNII */ khz = 5745000; break; \ - case 153: /* UNII */ khz = 5765000; break; \ - case 157: /* UNII */ khz = 5785000; break; \ - case 161: /* UNII */ khz = 5805000; break; \ - case 165: /* UNII */ khz = 5825000; break; \ - case 100: /* HiperLAN2 */ khz = 5500000; break; \ - case 104: /* HiperLAN2 */ khz = 5520000; break; \ - case 108: /* HiperLAN2 */ khz = 5540000; break; \ - case 112: /* HiperLAN2 */ khz = 5560000; break; \ - case 116: /* HiperLAN2 */ khz = 5580000; break; \ - case 120: /* HiperLAN2 */ khz = 5600000; break; \ - case 124: /* HiperLAN2 */ khz = 5620000; break; \ - case 128: /* HiperLAN2 */ khz = 5640000; break; \ - case 132: /* HiperLAN2 */ khz = 5660000; break; \ - case 136: /* HiperLAN2 */ khz = 5680000; break; \ - case 140: /* HiperLAN2 */ khz = 5700000; break; \ - case 34: /* Japan MMAC */ khz = 5170000; break; \ - case 38: /* Japan MMAC */ khz = 5190000; break; \ - case 42: /* Japan MMAC */ khz = 5210000; break; \ - case 46: /* Japan MMAC */ khz = 5230000; break; \ - case 184: /* Japan */ khz = 4920000; break; \ - case 188: /* Japan */ khz = 4940000; break; \ - case 192: /* Japan */ khz = 4960000; break; \ - case 196: /* Japan */ khz = 4980000; break; \ - case 208: /* Japan, means J08 */ khz = 5040000; break; \ - case 212: /* Japan, means J12 */ khz = 5060000; break; \ - case 216: /* Japan, means J16 */ khz = 5080000; break; \ - default: khz = 2412000; break; \ - } \ - } - -#define MAP_KHZ_TO_CHANNEL_ID(khz, ch) { \ - switch (khz) \ - { \ - case 2412000: ch = 1; break; \ - case 2417000: ch = 2; break; \ - case 2422000: ch = 3; break; \ - case 2427000: ch = 4; break; \ - case 2432000: ch = 5; break; \ - case 2437000: ch = 6; break; \ - case 2442000: ch = 7; break; \ - case 2447000: ch = 8; break; \ - case 2452000: ch = 9; break; \ - case 2457000: ch = 10; break; \ - case 2462000: ch = 11; break; \ - case 2467000: ch = 12; break; \ - case 2472000: ch = 13; break; \ - case 2484000: ch = 14; break; \ - case 5180000: ch = 36; /* UNII */ break; \ - case 5200000: ch = 40; /* UNII */ break; \ - case 5220000: ch = 44; /* UNII */ break; \ - case 5240000: ch = 48; /* UNII */ break; \ - case 5260000: ch = 52; /* UNII */ break; \ - case 5280000: ch = 56; /* UNII */ break; \ - case 5300000: ch = 60; /* UNII */ break; \ - case 5320000: ch = 64; /* UNII */ break; \ - case 5745000: ch = 149; /* UNII */ break; \ - case 5765000: ch = 153; /* UNII */ break; \ - case 5785000: ch = 157; /* UNII */ break; \ - case 5805000: ch = 161; /* UNII */ break; \ - case 5825000: ch = 165; /* UNII */ break; \ - case 5500000: ch = 100; /* HiperLAN2 */ break; \ - case 5520000: ch = 104; /* HiperLAN2 */ break; \ - case 5540000: ch = 108; /* HiperLAN2 */ break; \ - case 5560000: ch = 112; /* HiperLAN2 */ break; \ - case 5580000: ch = 116; /* HiperLAN2 */ break; \ - case 5600000: ch = 120; /* HiperLAN2 */ break; \ - case 5620000: ch = 124; /* HiperLAN2 */ break; \ - case 5640000: ch = 128; /* HiperLAN2 */ break; \ - case 5660000: ch = 132; /* HiperLAN2 */ break; \ - case 5680000: ch = 136; /* HiperLAN2 */ break; \ - case 5700000: ch = 140; /* HiperLAN2 */ break; \ - case 5170000: ch = 34; /* Japan MMAC */ break; \ - case 5190000: ch = 38; /* Japan MMAC */ break; \ - case 5210000: ch = 42; /* Japan MMAC */ break; \ - case 5230000: ch = 46; /* Japan MMAC */ break; \ - case 4920000: ch = 184; /* Japan */ break; \ - case 4940000: ch = 188; /* Japan */ break; \ - case 4960000: ch = 192; /* Japan */ break; \ - case 4980000: ch = 196; /* Japan */ break; \ - case 5040000: ch = 208; /* Japan, means J08 */ break; \ - case 5060000: ch = 212; /* Japan, means J12 */ break; \ - case 5080000: ch = 216; /* Japan, means J16 */ break; \ - default: ch = 1; break; \ - } \ - } - -// -// Common fragment list structure - Identical to the scatter gather frag list structure -// -//#define RTMP_SCATTER_GATHER_ELEMENT SCATTER_GATHER_ELEMENT -//#define PRTMP_SCATTER_GATHER_ELEMENT PSCATTER_GATHER_ELEMENT -#define NIC_MAX_PHYS_BUF_COUNT 8 - -typedef struct _RTMP_SCATTER_GATHER_ELEMENT { - PVOID Address; - ULONG Length; - PULONG Reserved; -} RTMP_SCATTER_GATHER_ELEMENT, *PRTMP_SCATTER_GATHER_ELEMENT; - - -typedef struct _RTMP_SCATTER_GATHER_LIST { - ULONG NumberOfElements; - PULONG Reserved; - RTMP_SCATTER_GATHER_ELEMENT Elements[NIC_MAX_PHYS_BUF_COUNT]; -} RTMP_SCATTER_GATHER_LIST, *PRTMP_SCATTER_GATHER_LIST; - -// -// Some utility macros -// -#ifndef min -#define min(_a, _b) (((_a) < (_b)) ? (_a) : (_b)) -#endif - -#ifndef max -#define max(_a, _b) (((_a) > (_b)) ? (_a) : (_b)) -#endif - -#define GET_LNA_GAIN(_pAd) ((_pAd->LatchRfRegs.Channel <= 14) ? (_pAd->BLNAGain) : ((_pAd->LatchRfRegs.Channel <= 64) ? (_pAd->ALNAGain0) : ((_pAd->LatchRfRegs.Channel <= 128) ? (_pAd->ALNAGain1) : (_pAd->ALNAGain2)))) - -#define INC_COUNTER64(Val) (Val.QuadPart++) - -#define INFRA_ON(_p) (OPSTATUS_TEST_FLAG(_p, fOP_STATUS_INFRA_ON)) -#define ADHOC_ON(_p) (OPSTATUS_TEST_FLAG(_p, fOP_STATUS_ADHOC_ON)) -#define MONITOR_ON(_p) (((_p)->StaCfg.BssType) == BSS_MONITOR) -#define IDLE_ON(_p) (!INFRA_ON(_p) && !ADHOC_ON(_p)) - -// Check LEAP & CCKM flags -#define LEAP_ON(_p) (((_p)->StaCfg.LeapAuthMode) == CISCO_AuthModeLEAP) -#define LEAP_CCKM_ON(_p) ((((_p)->StaCfg.LeapAuthMode) == CISCO_AuthModeLEAP) && ((_p)->StaCfg.LeapAuthInfo.CCKM == TRUE)) - -// if orginal Ethernet frame contains no LLC/SNAP, then an extra LLC/SNAP encap is required -#define EXTRA_LLCSNAP_ENCAP_FROM_PKT_START(_pBufVA, _pExtraLlcSnapEncap) \ -{ \ - if (((*(_pBufVA + 12) << 8) + *(_pBufVA + 13)) > 1500) \ - { \ - _pExtraLlcSnapEncap = SNAP_802_1H; \ - if (NdisEqualMemory(IPX, _pBufVA + 12, 2) || \ - NdisEqualMemory(APPLE_TALK, _pBufVA + 12, 2)) \ - { \ - _pExtraLlcSnapEncap = SNAP_BRIDGE_TUNNEL; \ - } \ - } \ - else \ - { \ - _pExtraLlcSnapEncap = NULL; \ - } \ -} - -// New Define for new Tx Path. -#define EXTRA_LLCSNAP_ENCAP_FROM_PKT_OFFSET(_pBufVA, _pExtraLlcSnapEncap) \ -{ \ - if (((*(_pBufVA) << 8) + *(_pBufVA + 1)) > 1500) \ - { \ - _pExtraLlcSnapEncap = SNAP_802_1H; \ - if (NdisEqualMemory(IPX, _pBufVA, 2) || \ - NdisEqualMemory(APPLE_TALK, _pBufVA, 2)) \ - { \ - _pExtraLlcSnapEncap = SNAP_BRIDGE_TUNNEL; \ - } \ - } \ - else \ - { \ - _pExtraLlcSnapEncap = NULL; \ - } \ -} - - -#define MAKE_802_3_HEADER(_p, _pMac1, _pMac2, _pType) \ -{ \ - NdisMoveMemory(_p, _pMac1, MAC_ADDR_LEN); \ - NdisMoveMemory((_p + MAC_ADDR_LEN), _pMac2, MAC_ADDR_LEN); \ - NdisMoveMemory((_p + MAC_ADDR_LEN * 2), _pType, LENGTH_802_3_TYPE); \ -} - -// if pData has no LLC/SNAP (neither RFC1042 nor Bridge tunnel), keep it that way. -// else if the received frame is LLC/SNAP-encaped IPX or APPLETALK, preserve the LLC/SNAP field -// else remove the LLC/SNAP field from the result Ethernet frame -// Patch for WHQL only, which did not turn on Netbios but use IPX within its payload -// Note: -// _pData & _DataSize may be altered (remove 8-byte LLC/SNAP) by this MACRO -// _pRemovedLLCSNAP: pointer to removed LLC/SNAP; NULL is not removed -#define CONVERT_TO_802_3(_p8023hdr, _pDA, _pSA, _pData, _DataSize, _pRemovedLLCSNAP) \ -{ \ - char LLC_Len[2]; \ - \ - _pRemovedLLCSNAP = NULL; \ - if (NdisEqualMemory(SNAP_802_1H, _pData, 6) || \ - NdisEqualMemory(SNAP_BRIDGE_TUNNEL, _pData, 6)) \ - { \ - PUCHAR pProto = _pData + 6; \ - \ - if ((NdisEqualMemory(IPX, pProto, 2) || NdisEqualMemory(APPLE_TALK, pProto, 2)) && \ - NdisEqualMemory(SNAP_802_1H, _pData, 6)) \ - { \ - LLC_Len[0] = (UCHAR)(_DataSize / 256); \ - LLC_Len[1] = (UCHAR)(_DataSize % 256); \ - MAKE_802_3_HEADER(_p8023hdr, _pDA, _pSA, LLC_Len); \ - } \ - else \ - { \ - MAKE_802_3_HEADER(_p8023hdr, _pDA, _pSA, pProto); \ - _pRemovedLLCSNAP = _pData; \ - _DataSize -= LENGTH_802_1_H; \ - _pData += LENGTH_802_1_H; \ - } \ - } \ - else \ - { \ - LLC_Len[0] = (UCHAR)(_DataSize / 256); \ - LLC_Len[1] = (UCHAR)(_DataSize % 256); \ - MAKE_802_3_HEADER(_p8023hdr, _pDA, _pSA, LLC_Len); \ - } \ -} - -#define SWITCH_AB( _pAA, _pBB) \ -{ \ - PVOID pCC; \ - pCC = _pBB; \ - _pBB = _pAA; \ - _pAA = pCC; \ -} - -// Enqueue this frame to MLME engine -// We need to enqueue the whole frame because MLME need to pass data type -// information from 802.11 header -#ifdef RT2870 -#define REPORT_MGMT_FRAME_TO_MLME(_pAd, Wcid, _pFrame, _FrameSize, _Rssi0, _Rssi1, _Rssi2, _PlcpSignal) \ -{ \ - UINT32 High32TSF=0, Low32TSF=0; \ - MlmeEnqueueForRecv(_pAd, Wcid, High32TSF, Low32TSF, (UCHAR)_Rssi0, (UCHAR)_Rssi1,(UCHAR)_Rssi2,_FrameSize, _pFrame, (UCHAR)_PlcpSignal); \ -} -#endif // RT2870 // - -#ifdef RT30xx -//Need to collect each ant's rssi concurrently -//rssi1 is report to pair2 Ant and rss2 is reprot to pair1 Ant when 4 Ant -#define COLLECT_RX_ANTENNA_AVERAGE_RSSI(_pAd, _rssi1, _rssi2) \ -{ \ - SHORT AvgRssi; \ - UCHAR UsedAnt; \ - if (_pAd->RxAnt.EvaluatePeriod == 0) \ - { \ - UsedAnt = _pAd->RxAnt.Pair1PrimaryRxAnt; \ - AvgRssi = _pAd->RxAnt.Pair1AvgRssi[UsedAnt]; \ - if (AvgRssi < 0) \ - AvgRssi = AvgRssi - (AvgRssi >> 3) + _rssi1; \ - else \ - AvgRssi = _rssi1 << 3; \ - _pAd->RxAnt.Pair1AvgRssi[UsedAnt] = AvgRssi; \ - } \ - else \ - { \ - UsedAnt = _pAd->RxAnt.Pair1SecondaryRxAnt; \ - AvgRssi = _pAd->RxAnt.Pair1AvgRssi[UsedAnt]; \ - if ((AvgRssi < 0) && (_pAd->RxAnt.FirstPktArrivedWhenEvaluate)) \ - AvgRssi = AvgRssi - (AvgRssi >> 3) + _rssi1; \ - else \ - { \ - _pAd->RxAnt.FirstPktArrivedWhenEvaluate = TRUE; \ - AvgRssi = _rssi1 << 3; \ - } \ - _pAd->RxAnt.Pair1AvgRssi[UsedAnt] = AvgRssi; \ - _pAd->RxAnt.RcvPktNumWhenEvaluate++; \ - } \ -} -#endif // RT30xx // - - -#define NDIS_QUERY_BUFFER(_NdisBuf, _ppVA, _pBufLen) \ - NdisQueryBuffer(_NdisBuf, _ppVA, _pBufLen) - -#define MAC_ADDR_EQUAL(pAddr1,pAddr2) RTMPEqualMemory((PVOID)(pAddr1), (PVOID)(pAddr2), MAC_ADDR_LEN) -#define SSID_EQUAL(ssid1, len1, ssid2, len2) ((len1==len2) && (RTMPEqualMemory(ssid1, ssid2, len1))) - -// -// Check if it is Japan W53(ch52,56,60,64) channel. -// -#define JapanChannelCheck(channel) ((channel == 52) || (channel == 56) || (channel == 60) || (channel == 64)) - -#ifdef CONFIG_STA_SUPPORT -#define STA_PORT_SECURED(_pAd) \ -{ \ - _pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; \ - NdisAcquireSpinLock(&_pAd->MacTabLock); \ - _pAd->MacTab.Content[BSSID_WCID].PortSecured = _pAd->StaCfg.PortSecured; \ - NdisReleaseSpinLock(&_pAd->MacTabLock); \ -} -#endif // CONFIG_STA_SUPPORT // - - -// -// Register set pair for initialzation register set definition -// -typedef struct _RTMP_REG_PAIR -{ - ULONG Register; - ULONG Value; -} RTMP_REG_PAIR, *PRTMP_REG_PAIR; - -typedef struct _REG_PAIR -{ - UCHAR Register; - UCHAR Value; -} REG_PAIR, *PREG_PAIR; - -// -// Register set pair for initialzation register set definition -// -typedef struct _RTMP_RF_REGS -{ - UCHAR Channel; - ULONG R1; - ULONG R2; - ULONG R3; - ULONG R4; -} RTMP_RF_REGS, *PRTMP_RF_REGS; - -typedef struct _FREQUENCY_ITEM { - UCHAR Channel; - UCHAR N; - UCHAR R; - UCHAR K; -} FREQUENCY_ITEM, *PFREQUENCY_ITEM; - -// -// Data buffer for DMA operation, the buffer must be contiguous physical memory -// Both DMA to / from CPU use the same structure. -// -typedef struct _RTMP_DMABUF -{ - ULONG AllocSize; - PVOID AllocVa; // TxBuf virtual address - NDIS_PHYSICAL_ADDRESS AllocPa; // TxBuf physical address -} RTMP_DMABUF, *PRTMP_DMABUF; - - -typedef union _HEADER_802_11_SEQ{ -#ifdef RT_BIG_ENDIAN - struct { - USHORT Sequence:12; - USHORT Frag:4; - } field; -#else - struct { - USHORT Frag:4; - USHORT Sequence:12; - } field; -#endif - USHORT value; -} HEADER_802_11_SEQ, *PHEADER_802_11_SEQ; - -// -// Data buffer for DMA operation, the buffer must be contiguous physical memory -// Both DMA to / from CPU use the same structure. -// -typedef struct _RTMP_REORDERBUF -{ - BOOLEAN IsFull; - PVOID AllocVa; // TxBuf virtual address - UCHAR Header802_3[14]; - HEADER_802_11_SEQ Sequence; //support compressed bitmap BA, so no consider fragment in BA - UCHAR DataOffset; - USHORT Datasize; - ULONG AllocSize; -#ifdef RT2870 - PUCHAR AllocPa; -#endif // RT2870 // -} RTMP_REORDERBUF, *PRTMP_REORDERBUF; - -// -// Control block (Descriptor) for all ring descriptor DMA operation, buffer must be -// contiguous physical memory. NDIS_PACKET stored the binding Rx packet descriptor -// which won't be released, driver has to wait until upper layer return the packet -// before giveing up this rx ring descriptor to ASIC. NDIS_BUFFER is assocaited pair -// to describe the packet buffer. For Tx, NDIS_PACKET stored the tx packet descriptor -// which driver should ACK upper layer when the tx is physically done or failed. -// -typedef struct _RTMP_DMACB -{ - ULONG AllocSize; // Control block size - PVOID AllocVa; // Control block virtual address - NDIS_PHYSICAL_ADDRESS AllocPa; // Control block physical address - PNDIS_PACKET pNdisPacket; - PNDIS_PACKET pNextNdisPacket; - - RTMP_DMABUF DmaBuf; // Associated DMA buffer structure -} RTMP_DMACB, *PRTMP_DMACB; - -typedef struct _RTMP_TX_BUF -{ - PQUEUE_ENTRY Next; - UCHAR Index; - ULONG AllocSize; // Control block size - PVOID AllocVa; // Control block virtual address - NDIS_PHYSICAL_ADDRESS AllocPa; // Control block physical address -} RTMP_TXBUF, *PRTMP_TXBUF; - -typedef struct _RTMP_RX_BUF -{ - BOOLEAN InUse; - ULONG ByBaRecIndex; - RTMP_REORDERBUF MAP_RXBuf[MAX_RX_REORDERBUF]; -} RTMP_RXBUF, *PRTMP_RXBUF; -typedef struct _RTMP_TX_RING -{ - RTMP_DMACB Cell[TX_RING_SIZE]; - UINT32 TxCpuIdx; - UINT32 TxDmaIdx; - UINT32 TxSwFreeIdx; // software next free tx index -} RTMP_TX_RING, *PRTMP_TX_RING; - -typedef struct _RTMP_RX_RING -{ - RTMP_DMACB Cell[RX_RING_SIZE]; - UINT32 RxCpuIdx; - UINT32 RxDmaIdx; - INT32 RxSwReadIdx; // software next read index -} RTMP_RX_RING, *PRTMP_RX_RING; - -typedef struct _RTMP_MGMT_RING -{ - RTMP_DMACB Cell[MGMT_RING_SIZE]; - UINT32 TxCpuIdx; - UINT32 TxDmaIdx; - UINT32 TxSwFreeIdx; // software next free tx index -} RTMP_MGMT_RING, *PRTMP_MGMT_RING; - -// -// Statistic counter structure -// -typedef struct _COUNTER_802_3 -{ - // General Stats - ULONG GoodTransmits; - ULONG GoodReceives; - ULONG TxErrors; - ULONG RxErrors; - ULONG RxNoBuffer; - - // Ethernet Stats - ULONG RcvAlignmentErrors; - ULONG OneCollision; - ULONG MoreCollisions; - -} COUNTER_802_3, *PCOUNTER_802_3; - -typedef struct _COUNTER_802_11 { - ULONG Length; - LARGE_INTEGER LastTransmittedFragmentCount; - LARGE_INTEGER TransmittedFragmentCount; - LARGE_INTEGER MulticastTransmittedFrameCount; - LARGE_INTEGER FailedCount; - LARGE_INTEGER RetryCount; - LARGE_INTEGER MultipleRetryCount; - LARGE_INTEGER RTSSuccessCount; - LARGE_INTEGER RTSFailureCount; - LARGE_INTEGER ACKFailureCount; - LARGE_INTEGER FrameDuplicateCount; - LARGE_INTEGER ReceivedFragmentCount; - LARGE_INTEGER MulticastReceivedFrameCount; - LARGE_INTEGER FCSErrorCount; -} COUNTER_802_11, *PCOUNTER_802_11; - -typedef struct _COUNTER_RALINK { - ULONG TransmittedByteCount; // both successful and failure, used to calculate TX throughput - ULONG ReceivedByteCount; // both CRC okay and CRC error, used to calculate RX throughput - ULONG BeenDisassociatedCount; - ULONG BadCQIAutoRecoveryCount; - ULONG PoorCQIRoamingCount; - ULONG MgmtRingFullCount; - ULONG RxCountSinceLastNULL; - ULONG RxCount; - ULONG RxRingErrCount; - ULONG KickTxCount; - ULONG TxRingErrCount; - LARGE_INTEGER RealFcsErrCount; - ULONG PendingNdisPacketCount; - - ULONG OneSecOsTxCount[NUM_OF_TX_RING]; - ULONG OneSecDmaDoneCount[NUM_OF_TX_RING]; - UINT32 OneSecTxDoneCount; - ULONG OneSecRxCount; - UINT32 OneSecTxAggregationCount; - UINT32 OneSecRxAggregationCount; - - UINT32 OneSecFrameDuplicateCount; - -#ifdef RT2870 - ULONG OneSecTransmittedByteCount; // both successful and failure, used to calculate TX throughput -#endif // RT2870 // - - UINT32 OneSecTxNoRetryOkCount; - UINT32 OneSecTxRetryOkCount; - UINT32 OneSecTxFailCount; - UINT32 OneSecFalseCCACnt; // CCA error count, for debug purpose, might move to global counter - UINT32 OneSecRxOkCnt; // RX without error - UINT32 OneSecRxOkDataCnt; // unicast-to-me DATA frame count - UINT32 OneSecRxFcsErrCnt; // CRC error - UINT32 OneSecBeaconSentCnt; - UINT32 LastOneSecTotalTxCount; // OneSecTxNoRetryOkCount + OneSecTxRetryOkCount + OneSecTxFailCount - UINT32 LastOneSecRxOkDataCnt; // OneSecRxOkDataCnt - ULONG DuplicateRcv; - ULONG TxAggCount; - ULONG TxNonAggCount; - ULONG TxAgg1MPDUCount; - ULONG TxAgg2MPDUCount; - ULONG TxAgg3MPDUCount; - ULONG TxAgg4MPDUCount; - ULONG TxAgg5MPDUCount; - ULONG TxAgg6MPDUCount; - ULONG TxAgg7MPDUCount; - ULONG TxAgg8MPDUCount; - ULONG TxAgg9MPDUCount; - ULONG TxAgg10MPDUCount; - ULONG TxAgg11MPDUCount; - ULONG TxAgg12MPDUCount; - ULONG TxAgg13MPDUCount; - ULONG TxAgg14MPDUCount; - ULONG TxAgg15MPDUCount; - ULONG TxAgg16MPDUCount; - - LARGE_INTEGER TransmittedOctetsInAMSDU; - LARGE_INTEGER TransmittedAMSDUCount; - LARGE_INTEGER ReceivedOctesInAMSDUCount; - LARGE_INTEGER ReceivedAMSDUCount; - LARGE_INTEGER TransmittedAMPDUCount; - LARGE_INTEGER TransmittedMPDUsInAMPDUCount; - LARGE_INTEGER TransmittedOctetsInAMPDUCount; - LARGE_INTEGER MPDUInReceivedAMPDUCount; -} COUNTER_RALINK, *PCOUNTER_RALINK; - -typedef struct _PID_COUNTER { - ULONG TxAckRequiredCount; // CRC error - ULONG TxAggreCount; - ULONG TxSuccessCount; // OneSecTxNoRetryOkCount + OneSecTxRetryOkCount + OneSecTxFailCount - ULONG LastSuccessRate; -} PID_COUNTER, *PPID_COUNTER; - -typedef struct _COUNTER_DRS { - // to record the each TX rate's quality. 0 is best, the bigger the worse. - USHORT TxQuality[MAX_STEP_OF_TX_RATE_SWITCH]; - UCHAR PER[MAX_STEP_OF_TX_RATE_SWITCH]; - UCHAR TxRateUpPenalty; // extra # of second penalty due to last unstable condition - ULONG CurrTxRateStableTime; // # of second in current TX rate - BOOLEAN fNoisyEnvironment; - BOOLEAN fLastSecAccordingRSSI; - UCHAR LastSecTxRateChangeAction; // 0: no change, 1:rate UP, 2:rate down - UCHAR LastTimeTxRateChangeAction; //Keep last time value of LastSecTxRateChangeAction - ULONG LastTxOkCount; -} COUNTER_DRS, *PCOUNTER_DRS; - -// -// Arcfour Structure Added by PaulWu -// -typedef struct _ARCFOUR -{ - UINT X; - UINT Y; - UCHAR STATE[256]; -} ARCFOURCONTEXT, *PARCFOURCONTEXT; - -// MIMO Tx parameter, ShortGI, MCS, STBC, etc. these are fields in TXWI too. just copy to TXWI. -typedef struct _RECEIVE_SETTING { -#ifdef RT_BIG_ENDIAN - USHORT MIMO:1; - USHORT OFDM:1; - USHORT rsv:3; - USHORT STBC:2; //SPACE - USHORT ShortGI:1; - USHORT Mode:2; //channel bandwidth 20MHz or 40 MHz - USHORT NumOfRX:2; // MIMO. WE HAVE 3R -#else - USHORT NumOfRX:2; // MIMO. WE HAVE 3R - USHORT Mode:2; //channel bandwidth 20MHz or 40 MHz - USHORT ShortGI:1; - USHORT STBC:2; //SPACE - USHORT rsv:3; - USHORT OFDM:1; - USHORT MIMO:1; -#endif - } RECEIVE_SETTING, *PRECEIVE_SETTING; - -// Shared key data structure -typedef struct _WEP_KEY { - UCHAR KeyLen; // Key length for each key, 0: entry is invalid - UCHAR Key[MAX_LEN_OF_KEY]; // right now we implement 4 keys, 128 bits max -} WEP_KEY, *PWEP_KEY; - -typedef struct _CIPHER_KEY { - UCHAR Key[16]; // right now we implement 4 keys, 128 bits max - UCHAR RxMic[8]; // make alignment - UCHAR TxMic[8]; - UCHAR TxTsc[6]; // 48bit TSC value - UCHAR RxTsc[6]; // 48bit TSC value - UCHAR CipherAlg; // 0-none, 1:WEP64, 2:WEP128, 3:TKIP, 4:AES, 5:CKIP64, 6:CKIP128 - UCHAR KeyLen; -#ifdef CONFIG_STA_SUPPORT - UCHAR BssId[6]; -#endif // CONFIG_STA_SUPPORT // - // Key length for each key, 0: entry is invalid - UCHAR Type; // Indicate Pairwise/Group when reporting MIC error -} CIPHER_KEY, *PCIPHER_KEY; - -typedef struct _BBP_TUNING_STRUCT { - BOOLEAN Enable; - UCHAR FalseCcaCountUpperBound; // 100 per sec - UCHAR FalseCcaCountLowerBound; // 10 per sec - UCHAR R17LowerBound; // specified in E2PROM - UCHAR R17UpperBound; // 0x68 according to David Tung - UCHAR CurrentR17Value; -} BBP_TUNING, *PBBP_TUNING; - -typedef struct _SOFT_RX_ANT_DIVERSITY_STRUCT { - UCHAR EvaluatePeriod; // 0:not evalute status, 1: evaluate status, 2: switching status - UCHAR EvaluateStableCnt; - UCHAR Pair1PrimaryRxAnt; // 0:Ant-E1, 1:Ant-E2 - UCHAR Pair1SecondaryRxAnt; // 0:Ant-E1, 1:Ant-E2 - UCHAR Pair2PrimaryRxAnt; // 0:Ant-E3, 1:Ant-E4 - UCHAR Pair2SecondaryRxAnt; // 0:Ant-E3, 1:Ant-E4 - SHORT Pair1AvgRssi[2]; // AvgRssi[0]:E1, AvgRssi[1]:E2 - SHORT Pair2AvgRssi[2]; // AvgRssi[0]:E3, AvgRssi[1]:E4 - SHORT Pair1LastAvgRssi; // - SHORT Pair2LastAvgRssi; // - ULONG RcvPktNumWhenEvaluate; - BOOLEAN FirstPktArrivedWhenEvaluate; - RALINK_TIMER_STRUCT RxAntDiversityTimer; -} SOFT_RX_ANT_DIVERSITY, *PSOFT_RX_ANT_DIVERSITY; - -typedef struct _LEAP_AUTH_INFO { - BOOLEAN Enabled; //Ture: Enable LEAP Authentication - BOOLEAN CCKM; //Ture: Use Fast Reauthentication with CCKM - UCHAR Reserve[2]; - UCHAR UserName[256]; //LEAP, User name - ULONG UserNameLen; - UCHAR Password[256]; //LEAP, User Password - ULONG PasswordLen; -} LEAP_AUTH_INFO, *PLEAP_AUTH_INFO; - -typedef struct { - UCHAR Addr[MAC_ADDR_LEN]; - UCHAR ErrorCode[2]; //00 01-Invalid authentication type - //00 02-Authentication timeout - //00 03-Challenge from AP failed - //00 04-Challenge to AP failed - BOOLEAN Reported; -} ROGUEAP_ENTRY, *PROGUEAP_ENTRY; - -typedef struct { - UCHAR RogueApNr; - ROGUEAP_ENTRY RogueApEntry[MAX_LEN_OF_BSS_TABLE]; -} ROGUEAP_TABLE, *PROGUEAP_TABLE; - -typedef struct { - BOOLEAN Enable; - UCHAR Delta; - BOOLEAN PlusSign; -} CCK_TX_POWER_CALIBRATE, *PCCK_TX_POWER_CALIBRATE; - -// -// Receive Tuple Cache Format -// -typedef struct _TUPLE_CACHE { - BOOLEAN Valid; - UCHAR MacAddress[MAC_ADDR_LEN]; - USHORT Sequence; - USHORT Frag; -} TUPLE_CACHE, *PTUPLE_CACHE; - -// -// Fragment Frame structure -// -typedef struct _FRAGMENT_FRAME { - PNDIS_PACKET pFragPacket; - ULONG RxSize; - USHORT Sequence; - USHORT LastFrag; - ULONG Flags; // Some extra frame information. bit 0: LLC presented -} FRAGMENT_FRAME, *PFRAGMENT_FRAME; - - -// -// Packet information for NdisQueryPacket -// -typedef struct _PACKET_INFO { - UINT PhysicalBufferCount; // Physical breaks of buffer descripor chained - UINT BufferCount ; // Number of Buffer descriptor chained - UINT TotalPacketLength ; // Self explained - PNDIS_BUFFER pFirstBuffer; // Pointer to first buffer descriptor -} PACKET_INFO, *PPACKET_INFO; - -// -// Tkip Key structure which RC4 key & MIC calculation -// -typedef struct _TKIP_KEY_INFO { - UINT nBytesInM; // # bytes in M for MICKEY - ULONG IV16; - ULONG IV32; - ULONG K0; // for MICKEY Low - ULONG K1; // for MICKEY Hig - ULONG L; // Current state for MICKEY - ULONG R; // Current state for MICKEY - ULONG M; // Message accumulator for MICKEY - UCHAR RC4KEY[16]; - UCHAR MIC[8]; -} TKIP_KEY_INFO, *PTKIP_KEY_INFO; - -// -// Private / Misc data, counters for driver internal use -// -typedef struct __PRIVATE_STRUC { - UINT SystemResetCnt; // System reset counter - UINT TxRingFullCnt; // Tx ring full occurrance number - UINT PhyRxErrCnt; // PHY Rx error count, for debug purpose, might move to global counter - // Variables for WEP encryption / decryption in rtmp_wep.c - UINT FCSCRC32; - ARCFOURCONTEXT WEPCONTEXT; - // Tkip stuff - TKIP_KEY_INFO Tx; - TKIP_KEY_INFO Rx; -} PRIVATE_STRUC, *PPRIVATE_STRUC; - -// structure to tune BBP R66 (BBP TUNING) -typedef struct _BBP_R66_TUNING { - BOOLEAN bEnable; - USHORT FalseCcaLowerThreshold; // default 100 - USHORT FalseCcaUpperThreshold; // default 512 - UCHAR R66Delta; - UCHAR R66CurrentValue; - BOOLEAN R66LowerUpperSelect; //Before LinkUp, Used LowerBound or UpperBound as R66 value. -} BBP_R66_TUNING, *PBBP_R66_TUNING; - -// structure to store channel TX power -typedef struct _CHANNEL_TX_POWER { - USHORT RemainingTimeForUse; //unit: sec - UCHAR Channel; -#ifdef DOT11N_DRAFT3 - BOOLEAN bEffectedChannel; // For BW 40 operating in 2.4GHz , the "effected channel" is the channel that is covered in 40Mhz. -#endif // DOT11N_DRAFT3 // - CHAR Power; - CHAR Power2; - UCHAR MaxTxPwr; - UCHAR DfsReq; -} CHANNEL_TX_POWER, *PCHANNEL_TX_POWER; - -// structure to store 802.11j channel TX power -typedef struct _CHANNEL_11J_TX_POWER { - UCHAR Channel; - UCHAR BW; // BW_10 or BW_20 - CHAR Power; - CHAR Power2; - USHORT RemainingTimeForUse; //unit: sec -} CHANNEL_11J_TX_POWER, *PCHANNEL_11J_TX_POWER; - -typedef enum _ABGBAND_STATE_ { - UNKNOWN_BAND, - BG_BAND, - A_BAND, -} ABGBAND_STATE; - -typedef struct _MLME_STRUCT { -#ifdef CONFIG_STA_SUPPORT - // STA state machines - STATE_MACHINE CntlMachine; - STATE_MACHINE AssocMachine; - STATE_MACHINE AuthMachine; - STATE_MACHINE AuthRspMachine; - STATE_MACHINE SyncMachine; - STATE_MACHINE WpaPskMachine; - STATE_MACHINE LeapMachine; - STATE_MACHINE AironetMachine; - STATE_MACHINE_FUNC AssocFunc[ASSOC_FUNC_SIZE]; - STATE_MACHINE_FUNC AuthFunc[AUTH_FUNC_SIZE]; - STATE_MACHINE_FUNC AuthRspFunc[AUTH_RSP_FUNC_SIZE]; - STATE_MACHINE_FUNC SyncFunc[SYNC_FUNC_SIZE]; - STATE_MACHINE_FUNC WpaPskFunc[WPA_PSK_FUNC_SIZE]; - STATE_MACHINE_FUNC AironetFunc[AIRONET_FUNC_SIZE]; -#endif // CONFIG_STA_SUPPORT // - STATE_MACHINE_FUNC ActFunc[ACT_FUNC_SIZE]; - // Action - STATE_MACHINE ActMachine; - - -#ifdef QOS_DLS_SUPPORT - STATE_MACHINE DlsMachine; - STATE_MACHINE_FUNC DlsFunc[DLS_FUNC_SIZE]; -#endif // QOS_DLS_SUPPORT // - - - - - ULONG ChannelQuality; // 0..100, Channel Quality Indication for Roaming - ULONG Now32; // latch the value of NdisGetSystemUpTime() - ULONG LastSendNULLpsmTime; - - BOOLEAN bRunning; - NDIS_SPIN_LOCK TaskLock; - MLME_QUEUE Queue; - - UINT ShiftReg; - - RALINK_TIMER_STRUCT PeriodicTimer; - RALINK_TIMER_STRUCT APSDPeriodicTimer; - RALINK_TIMER_STRUCT LinkDownTimer; - RALINK_TIMER_STRUCT LinkUpTimer; - ULONG PeriodicRound; - ULONG OneSecPeriodicRound; - - UCHAR RealRxPath; - BOOLEAN bLowThroughput; - BOOLEAN bEnableAutoAntennaCheck; - RALINK_TIMER_STRUCT RxAntEvalTimer; - -#ifdef RT30xx - UCHAR CaliBW40RfR24; - UCHAR CaliBW20RfR24; -#endif // RT30xx // - -} MLME_STRUCT, *PMLME_STRUCT; - -// structure for radar detection and channel switch -typedef struct _RADAR_DETECT_STRUCT { - //BOOLEAN IEEE80211H; // 0: disable, 1: enable IEEE802.11h - UCHAR CSCount; //Channel switch counter - UCHAR CSPeriod; //Channel switch period (beacon count) - UCHAR RDCount; //Radar detection counter - UCHAR RDMode; //Radar Detection mode - UCHAR RDDurRegion; //Radar detection duration region - UCHAR BBPR16; - UCHAR BBPR17; - UCHAR BBPR18; - UCHAR BBPR21; - UCHAR BBPR22; - UCHAR BBPR64; - ULONG InServiceMonitorCount; // unit: sec - UINT8 DfsSessionTime; - BOOLEAN bFastDfs; - UINT8 ChMovingTime; - UINT8 LongPulseRadarTh; -} RADAR_DETECT_STRUCT, *PRADAR_DETECT_STRUCT; - -#ifdef CARRIER_DETECTION_SUPPORT -typedef enum CD_STATE_n -{ - CD_NORMAL, - CD_SILENCE, - CD_MAX_STATE -} CD_STATE; - -typedef struct CARRIER_DETECTION_s -{ - BOOLEAN Enable; - UINT8 CDSessionTime; - UINT8 CDPeriod; - CD_STATE CD_State; -} CARRIER_DETECTION, *PCARRIER_DETECTION; -#endif // CARRIER_DETECTION_SUPPORT // - -typedef enum _REC_BLOCKACK_STATUS -{ - Recipient_NONE=0, - Recipient_USED, - Recipient_HandleRes, - Recipient_Accept -} REC_BLOCKACK_STATUS, *PREC_BLOCKACK_STATUS; - -typedef enum _ORI_BLOCKACK_STATUS -{ - Originator_NONE=0, - Originator_USED, - Originator_WaitRes, - Originator_Done -} ORI_BLOCKACK_STATUS, *PORI_BLOCKACK_STATUS; - -#ifdef DOT11_N_SUPPORT -typedef struct _BA_ORI_ENTRY{ - UCHAR Wcid; - UCHAR TID; - UCHAR BAWinSize; - UCHAR Token; -// Sequence is to fill every outgoing QoS DATA frame's sequence field in 802.11 header. - USHORT Sequence; - USHORT TimeOutValue; - ORI_BLOCKACK_STATUS ORI_BA_Status; - RALINK_TIMER_STRUCT ORIBATimer; - PVOID pAdapter; -} BA_ORI_ENTRY, *PBA_ORI_ENTRY; - -typedef struct _BA_REC_ENTRY { - UCHAR Wcid; - UCHAR TID; - UCHAR BAWinSize; // 7.3.1.14. each buffer is capable of holding a max AMSDU or MSDU. - //UCHAR NumOfRxPkt; - //UCHAR Curindidx; // the head in the RX reordering buffer - USHORT LastIndSeq; -// USHORT LastIndSeqAtTimer; - USHORT TimeOutValue; - RALINK_TIMER_STRUCT RECBATimer; - ULONG LastIndSeqAtTimer; - ULONG nDropPacket; - ULONG rcvSeq; - REC_BLOCKACK_STATUS REC_BA_Status; -// UCHAR RxBufIdxUsed; - // corresponding virtual address for RX reordering packet storage. - //RTMP_REORDERDMABUF MAP_RXBuf[MAX_RX_REORDERBUF]; - NDIS_SPIN_LOCK RxReRingLock; // Rx Ring spinlock -// struct _BA_REC_ENTRY *pNext; - PVOID pAdapter; - struct reordering_list list; -} BA_REC_ENTRY, *PBA_REC_ENTRY; - - -typedef struct { - ULONG numAsRecipient; // I am recipient of numAsRecipient clients. These client are in the BARecEntry[] - ULONG numAsOriginator; // I am originator of numAsOriginator clients. These clients are in the BAOriEntry[] - BA_ORI_ENTRY BAOriEntry[MAX_LEN_OF_BA_ORI_TABLE]; - BA_REC_ENTRY BARecEntry[MAX_LEN_OF_BA_REC_TABLE]; -} BA_TABLE, *PBA_TABLE; - -//For QureyBATableOID use; -typedef struct PACKED _OID_BA_REC_ENTRY{ - UCHAR MACAddr[MAC_ADDR_LEN]; - UCHAR BaBitmap; // if (BaBitmap&(1<> 3) + 1) /* /8 + 1 */ -#define WLAN_CT_TIM_BCMC_OFFSET 0 /* unit: 32B */ - -/* clear bcmc TIM bit */ -#define WLAN_MR_TIM_BCMC_CLEAR(apidx) \ - pAd->ApCfg.MBSSID[apidx].TimBitmaps[WLAN_CT_TIM_BCMC_OFFSET] &= ~BIT8[0]; - -/* set bcmc TIM bit */ -#define WLAN_MR_TIM_BCMC_SET(apidx) \ - pAd->ApCfg.MBSSID[apidx].TimBitmaps[WLAN_CT_TIM_BCMC_OFFSET] |= BIT8[0]; - -/* clear a station PS TIM bit */ -#define WLAN_MR_TIM_BIT_CLEAR(ad_p, apidx, wcid) \ - { UCHAR tim_offset = wcid >> 3; \ - UCHAR bit_offset = wcid & 0x7; \ - ad_p->ApCfg.MBSSID[apidx].TimBitmaps[tim_offset] &= (~BIT8[bit_offset]); } - -/* set a station PS TIM bit */ -#define WLAN_MR_TIM_BIT_SET(ad_p, apidx, wcid) \ - { UCHAR tim_offset = wcid >> 3; \ - UCHAR bit_offset = wcid & 0x7; \ - ad_p->ApCfg.MBSSID[apidx].TimBitmaps[tim_offset] |= BIT8[bit_offset]; } - -#ifdef RT2870 -#define BEACON_BITMAP_MASK 0xff -typedef struct _BEACON_SYNC_STRUCT_ -{ - UCHAR BeaconBuf[HW_BEACON_MAX_COUNT][HW_BEACON_OFFSET]; - UCHAR BeaconTxWI[HW_BEACON_MAX_COUNT][TXWI_SIZE]; - ULONG TimIELocationInBeacon[HW_BEACON_MAX_COUNT]; - ULONG CapabilityInfoLocationInBeacon[HW_BEACON_MAX_COUNT]; - BOOLEAN EnableBeacon; // trigger to enable beacon transmission. - UCHAR BeaconBitMap; // NOTE: If the MAX_MBSSID_NUM is larger than 8, this parameter need to change. - UCHAR DtimBitOn; // NOTE: If the MAX_MBSSID_NUM is larger than 8, this parameter need to change. -}BEACON_SYNC_STRUCT; -#endif // RT2870 // - -typedef struct _MULTISSID_STRUCT { - UCHAR Bssid[MAC_ADDR_LEN]; - UCHAR SsidLen; - CHAR Ssid[MAX_LEN_OF_SSID]; - USHORT CapabilityInfo; - - PNET_DEV MSSIDDev; - - NDIS_802_11_AUTHENTICATION_MODE AuthMode; - NDIS_802_11_WEP_STATUS WepStatus; - NDIS_802_11_WEP_STATUS GroupKeyWepStatus; - WPA_MIX_PAIR_CIPHER WpaMixPairCipher; - - ULONG TxCount; - ULONG RxCount; - ULONG ReceivedByteCount; - ULONG TransmittedByteCount; - ULONG RxErrorCount; - ULONG RxDropCount; - - HTTRANSMIT_SETTING HTPhyMode, MaxHTPhyMode, MinHTPhyMode;// For transmit phy setting in TXWI. - RT_HT_PHY_INFO DesiredHtPhyInfo; - DESIRED_TRANSMIT_SETTING DesiredTransmitSetting; // Desired transmit setting. this is for reading registry setting only. not useful. - BOOLEAN bAutoTxRateSwitch; - - //CIPHER_KEY SharedKey[SHARE_KEY_NUM]; // ref pAd->SharedKey[BSS][4] - UCHAR DefaultKeyId; - - UCHAR TxRate; // RATE_1, RATE_2, RATE_5_5, RATE_11, ... - UCHAR DesiredRates[MAX_LEN_OF_SUPPORTED_RATES];// OID_802_11_DESIRED_RATES - UCHAR DesiredRatesIndex; - UCHAR MaxTxRate; // RATE_1, RATE_2, RATE_5_5, RATE_11 - -// ULONG TimBitmap; // bit0 for broadcast, 1 for AID1, 2 for AID2, ...so on -// ULONG TimBitmap2; // b0 for AID32, b1 for AID33, ... and so on - UCHAR TimBitmaps[WLAN_MAX_NUM_OF_TIM]; - - // WPA - UCHAR GMK[32]; - UCHAR PMK[32]; - UCHAR GTK[32]; - BOOLEAN IEEE8021X; - BOOLEAN PreAuth; - UCHAR GNonce[32]; - UCHAR PortSecured; - NDIS_802_11_PRIVACY_FILTER PrivacyFilter; - UCHAR BANClass3Data; - ULONG IsolateInterStaTraffic; - - UCHAR RSNIE_Len[2]; - UCHAR RSN_IE[2][MAX_LEN_OF_RSNIE]; - - - UCHAR TimIELocationInBeacon; - UCHAR CapabilityInfoLocationInBeacon; - // outgoing BEACON frame buffer and corresponding TXWI - // PTXWI_STRUC BeaconTxWI; // - CHAR BeaconBuf[MAX_BEACON_SIZE]; // NOTE: BeaconBuf should be 4-byte aligned - - BOOLEAN bHideSsid; - UINT16 StationKeepAliveTime; // unit: second - - USHORT VLAN_VID; - USHORT VLAN_Priority; - - RT_802_11_ACL AccessControlList; - - // EDCA Qos - BOOLEAN bWmmCapable; // 0:disable WMM, 1:enable WMM - BOOLEAN bDLSCapable; // 0:disable DLS, 1:enable DLS - - UCHAR DlsPTK[64]; // Due to windows dirver count on meetinghouse to handle 4-way shake - - // For 802.1x daemon setting per BSS - UCHAR radius_srv_num; - RADIUS_SRV_INFO radius_srv_info[MAX_RADIUS_SRV_NUM]; - -#ifdef RTL865X_SOC - unsigned int mylinkid; -#endif - - - UINT32 RcvdConflictSsidCount; - UINT32 RcvdSpoofedAssocRespCount; - UINT32 RcvdSpoofedReassocRespCount; - UINT32 RcvdSpoofedProbeRespCount; - UINT32 RcvdSpoofedBeaconCount; - UINT32 RcvdSpoofedDisassocCount; - UINT32 RcvdSpoofedAuthCount; - UINT32 RcvdSpoofedDeauthCount; - UINT32 RcvdSpoofedUnknownMgmtCount; - UINT32 RcvdReplayAttackCount; - - CHAR RssiOfRcvdConflictSsid; - CHAR RssiOfRcvdSpoofedAssocResp; - CHAR RssiOfRcvdSpoofedReassocResp; - CHAR RssiOfRcvdSpoofedProbeResp; - CHAR RssiOfRcvdSpoofedBeacon; - CHAR RssiOfRcvdSpoofedDisassoc; - CHAR RssiOfRcvdSpoofedAuth; - CHAR RssiOfRcvdSpoofedDeauth; - CHAR RssiOfRcvdSpoofedUnknownMgmt; - CHAR RssiOfRcvdReplayAttack; - - BOOLEAN bBcnSntReq; - UCHAR BcnBufIdx; -} MULTISSID_STRUCT, *PMULTISSID_STRUCT; - - - -#ifdef DOT11N_DRAFT3 -typedef enum _BSS2040COEXIST_FLAG{ - BSS_2040_COEXIST_DISABLE = 0, - BSS_2040_COEXIST_TIMER_FIRED = 1, - BSS_2040_COEXIST_INFO_SYNC = 2, - BSS_2040_COEXIST_INFO_NOTIFY = 4, -}BSS2040COEXIST_FLAG; -#endif // DOT11N_DRAFT3 // - -// configuration common to OPMODE_AP as well as OPMODE_STA -typedef struct _COMMON_CONFIG { - - BOOLEAN bCountryFlag; - UCHAR CountryCode[3]; - UCHAR Geography; - UCHAR CountryRegion; // Enum of country region, 0:FCC, 1:IC, 2:ETSI, 3:SPAIN, 4:France, 5:MKK, 6:MKK1, 7:Israel - UCHAR CountryRegionForABand; // Enum of country region for A band - UCHAR PhyMode; // PHY_11A, PHY_11B, PHY_11BG_MIXED, PHY_ABG_MIXED - USHORT Dsifs; // in units of usec - ULONG PacketFilter; // Packet filter for receiving - - CHAR Ssid[MAX_LEN_OF_SSID]; // NOT NULL-terminated - UCHAR SsidLen; // the actual ssid length in used - UCHAR LastSsidLen; // the actual ssid length in used - CHAR LastSsid[MAX_LEN_OF_SSID]; // NOT NULL-terminated - UCHAR LastBssid[MAC_ADDR_LEN]; - - UCHAR Bssid[MAC_ADDR_LEN]; - USHORT BeaconPeriod; - UCHAR Channel; - UCHAR CentralChannel; // Central Channel when using 40MHz is indicating. not real channel. - - UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES]; - UCHAR SupRateLen; - UCHAR ExtRate[MAX_LEN_OF_SUPPORTED_RATES]; - UCHAR ExtRateLen; - UCHAR DesireRate[MAX_LEN_OF_SUPPORTED_RATES]; // OID_802_11_DESIRED_RATES - UCHAR MaxDesiredRate; - UCHAR ExpectedACKRate[MAX_LEN_OF_SUPPORTED_RATES]; - - ULONG BasicRateBitmap; // backup basic ratebitmap - - BOOLEAN bAPSDCapable; - BOOLEAN bInServicePeriod; - BOOLEAN bAPSDAC_BE; - BOOLEAN bAPSDAC_BK; - BOOLEAN bAPSDAC_VI; - BOOLEAN bAPSDAC_VO; - BOOLEAN bNeedSendTriggerFrame; - BOOLEAN bAPSDForcePowerSave; // Force power save mode, should only use in APSD-STAUT - ULONG TriggerTimerCount; - UCHAR MaxSPLength; - UCHAR BBPCurrentBW; // BW_10, BW_20, BW_40 - // move to MULTISSID_STRUCT for MBSS - //HTTRANSMIT_SETTING HTPhyMode, MaxHTPhyMode, MinHTPhyMode;// For transmit phy setting in TXWI. - REG_TRANSMIT_SETTING RegTransmitSetting; //registry transmit setting. this is for reading registry setting only. not useful. - //UCHAR FixedTxMode; // Fixed Tx Mode (CCK, OFDM), for HT fixed tx mode (GF, MIX) , refer to RegTransmitSetting.field.HTMode - UCHAR TxRate; // Same value to fill in TXD. TxRate is 6-bit - UCHAR MaxTxRate; // RATE_1, RATE_2, RATE_5_5, RATE_11 - UCHAR TxRateIndex; // Tx rate index in RateSwitchTable - UCHAR TxRateTableSize; // Valid Tx rate table size in RateSwitchTable - //BOOLEAN bAutoTxRateSwitch; - UCHAR MinTxRate; // RATE_1, RATE_2, RATE_5_5, RATE_11 - UCHAR RtsRate; // RATE_xxx - HTTRANSMIT_SETTING MlmeTransmit; // MGMT frame PHY rate setting when operatin at Ht rate. - UCHAR MlmeRate; // RATE_xxx, used to send MLME frames - UCHAR BasicMlmeRate; // Default Rate for sending MLME frames - - USHORT RtsThreshold; // in unit of BYTE - USHORT FragmentThreshold; // in unit of BYTE - - UCHAR TxPower; // in unit of mW - ULONG TxPowerPercentage; // 0~100 % - ULONG TxPowerDefault; // keep for TxPowerPercentage - -#ifdef DOT11_N_SUPPORT - BACAP_STRUC BACapability; // NO USE = 0XFF ; IMMED_BA =1 ; DELAY_BA=0 - BACAP_STRUC REGBACapability; // NO USE = 0XFF ; IMMED_BA =1 ; DELAY_BA=0 -#endif // DOT11_N_SUPPORT // - IOT_STRUC IOTestParm; // 802.11n InterOpbility Test Parameter; - ULONG TxPreamble; // Rt802_11PreambleLong, Rt802_11PreambleShort, Rt802_11PreambleAuto - BOOLEAN bUseZeroToDisableFragment; // Microsoft use 0 as disable - ULONG UseBGProtection; // 0: auto, 1: always use, 2: always not use - BOOLEAN bUseShortSlotTime; // 0: disable, 1 - use short slot (9us) - BOOLEAN bEnableTxBurst; // 1: enble TX PACKET BURST, 0: disable TX PACKET BURST - BOOLEAN bAggregationCapable; // 1: enable TX aggregation when the peer supports it - BOOLEAN bPiggyBackCapable; // 1: enable TX piggy-back according MAC's version - BOOLEAN bIEEE80211H; // 1: enable IEEE802.11h spec. - ULONG DisableOLBCDetect; // 0: enable OLBC detect; 1 disable OLBC detect - -#ifdef DOT11_N_SUPPORT - BOOLEAN bRdg; -#endif // DOT11_N_SUPPORT // - BOOLEAN bWmmCapable; // 0:disable WMM, 1:enable WMM - QOS_CAPABILITY_PARM APQosCapability; // QOS capability of the current associated AP - EDCA_PARM APEdcaParm; // EDCA parameters of the current associated AP - QBSS_LOAD_PARM APQbssLoad; // QBSS load of the current associated AP - UCHAR AckPolicy[4]; // ACK policy of the specified AC. see ACK_xxx -#ifdef CONFIG_STA_SUPPORT - BOOLEAN bDLSCapable; // 0:disable DLS, 1:enable DLS -#endif // CONFIG_STA_SUPPORT // - // a bitmap of BOOLEAN flags. each bit represent an operation status of a particular - // BOOLEAN control, either ON or OFF. These flags should always be accessed via - // OPSTATUS_TEST_FLAG(), OPSTATUS_SET_FLAG(), OP_STATUS_CLEAR_FLAG() macros. - // see fOP_STATUS_xxx in RTMP_DEF.C for detail bit definition - ULONG OpStatusFlags; - - BOOLEAN NdisRadioStateOff; //For HCT 12.0, set this flag to TRUE instead of called MlmeRadioOff. - ABGBAND_STATE BandState; // For setting BBP used on B/G or A mode. - BOOLEAN bRxAntDiversity; // 0:disable, 1:enable Software Rx Antenna Diversity. - - // IEEE802.11H--DFS. - RADAR_DETECT_STRUCT RadarDetect; - -#ifdef CARRIER_DETECTION_SUPPORT - CARRIER_DETECTION CarrierDetect; -#endif // CARRIER_DETECTION_SUPPORT // - -#ifdef DOT11_N_SUPPORT - // HT - UCHAR BASize; // USer desired BAWindowSize. Should not exceed our max capability - //RT_HT_CAPABILITY SupportedHtPhy; - RT_HT_CAPABILITY DesiredHtPhy; - HT_CAPABILITY_IE HtCapability; - ADD_HT_INFO_IE AddHTInfo; // Useful as AP. - //This IE is used with channel switch announcement element when changing to a new 40MHz. - //This IE is included in channel switch ammouncement frames 7.4.1.5, beacons, probe Rsp. - NEW_EXT_CHAN_IE NewExtChanOffset; //7.3.2.20A, 1 if extension channel is above the control channel, 3 if below, 0 if not present - -#ifdef DOT11N_DRAFT3 - UCHAR Bss2040CoexistFlag; // bit 0: bBssCoexistTimerRunning, bit 1: NeedSyncAddHtInfo. - RALINK_TIMER_STRUCT Bss2040CoexistTimer; - - //This IE is used for 20/40 BSS Coexistence. - BSS_2040_COEXIST_IE BSS2040CoexistInfo; - // ====== 11n D3.0 =======================> - USHORT Dot11OBssScanPassiveDwell; // Unit : TU. 5~1000 - USHORT Dot11OBssScanActiveDwell; // Unit : TU. 10~1000 - USHORT Dot11BssWidthTriggerScanInt; // Unit : Second - USHORT Dot11OBssScanPassiveTotalPerChannel; // Unit : TU. 200~10000 - USHORT Dot11OBssScanActiveTotalPerChannel; // Unit : TU. 20~10000 - USHORT Dot11BssWidthChanTranDelayFactor; - USHORT Dot11OBssScanActivityThre; // Unit : percentage - - ULONG Dot11BssWidthChanTranDelay; // multiple of (Dot11BssWidthTriggerScanInt * Dot11BssWidthChanTranDelayFactor) - ULONG CountDownCtr; // CountDown Counter from (Dot11BssWidthTriggerScanInt * Dot11BssWidthChanTranDelayFactor) - - NDIS_SPIN_LOCK TriggerEventTabLock; - BSS_2040_COEXIST_IE LastBSSCoexist2040; - BSS_2040_COEXIST_IE BSSCoexist2040; - TRIGGER_EVENT_TAB TriggerEventTab; - UCHAR ChannelListIdx; - // <====== 11n D3.0 ======================= - BOOLEAN bOverlapScanning; -#endif // DOT11N_DRAFT3 // - - BOOLEAN bHTProtect; - BOOLEAN bMIMOPSEnable; - BOOLEAN bBADecline; - BOOLEAN bDisableReordering; - BOOLEAN bForty_Mhz_Intolerant; - BOOLEAN bExtChannelSwitchAnnouncement; - BOOLEAN bRcvBSSWidthTriggerEvents; - ULONG LastRcvBSSWidthTriggerEventsTime; - - UCHAR TxBASize; -#endif // DOT11_N_SUPPORT // - - // Enable wireless event - BOOLEAN bWirelessEvent; - BOOLEAN bWiFiTest; // Enable this parameter for WiFi test - - // Tx & Rx Stream number selection - UCHAR TxStream; - UCHAR RxStream; - - // transmit phy mode, trasmit rate for Multicast. -#ifdef MCAST_RATE_SPECIFIC - UCHAR McastTransmitMcs; - UCHAR McastTransmitPhyMode; -#endif // MCAST_RATE_SPECIFIC // - - BOOLEAN bHardwareRadio; // Hardware controlled Radio enabled - -#ifdef RT2870 - BOOLEAN bMultipleIRP; // Multiple Bulk IN flag - UCHAR NumOfBulkInIRP; // if bMultipleIRP == TRUE, NumOfBulkInIRP will be 4 otherwise be 1 - RT_HT_CAPABILITY SupportedHtPhy; - ULONG MaxPktOneTxBulk; - UCHAR TxBulkFactor; - UCHAR RxBulkFactor; - - BEACON_SYNC_STRUCT *pBeaconSync; - RALINK_TIMER_STRUCT BeaconUpdateTimer; - UINT32 BeaconAdjust; - UINT32 BeaconFactor; - UINT32 BeaconRemain; -#endif // RT2870 // - - - NDIS_SPIN_LOCK MeasureReqTabLock; - PMEASURE_REQ_TAB pMeasureReqTab; - - NDIS_SPIN_LOCK TpcReqTabLock; - PTPC_REQ_TAB pTpcReqTab; - - // transmit phy mode, trasmit rate for Multicast. -#ifdef MCAST_RATE_SPECIFIC - HTTRANSMIT_SETTING MCastPhyMode; -#endif // MCAST_RATE_SPECIFIC // - -#ifdef SINGLE_SKU - UINT16 DefineMaxTxPwr; -#endif // SINGLE_SKU // - - -} COMMON_CONFIG, *PCOMMON_CONFIG; - - -#ifdef CONFIG_STA_SUPPORT -/* Modified by Wu Xi-Kun 4/21/2006 */ -// STA configuration and status -typedef struct _STA_ADMIN_CONFIG { - // GROUP 1 - - // User configuration loaded from Registry, E2PROM or OID_xxx. These settings describe - // the user intended configuration, but not necessary fully equal to the final - // settings in ACTIVE BSS after negotiation/compromize with the BSS holder (either - // AP or IBSS holder). - // Once initialized, user configuration can only be changed via OID_xxx - UCHAR BssType; // BSS_INFRA or BSS_ADHOC - USHORT AtimWin; // used when starting a new IBSS - - // GROUP 2 - - // User configuration loaded from Registry, E2PROM or OID_xxx. These settings describe - // the user intended configuration, and should be always applied to the final - // settings in ACTIVE BSS without compromising with the BSS holder. - // Once initialized, user configuration can only be changed via OID_xxx - UCHAR RssiTrigger; - UCHAR RssiTriggerMode; // RSSI_TRIGGERED_UPON_BELOW_THRESHOLD or RSSI_TRIGGERED_UPON_EXCCEED_THRESHOLD - USHORT DefaultListenCount; // default listen count; - ULONG WindowsPowerMode; // Power mode for AC power - ULONG WindowsBatteryPowerMode; // Power mode for battery if exists - BOOLEAN bWindowsACCAMEnable; // Enable CAM power mode when AC on - BOOLEAN bAutoReconnect; // Set to TRUE when setting OID_802_11_SSID with no matching BSSID - ULONG WindowsPowerProfile; // Windows power profile, for NDIS5.1 PnP - - // MIB:ieee802dot11.dot11smt(1).dot11StationConfigTable(1) - USHORT Psm; // power management mode (PWR_ACTIVE|PWR_SAVE) - USHORT DisassocReason; - UCHAR DisassocSta[MAC_ADDR_LEN]; - USHORT DeauthReason; - UCHAR DeauthSta[MAC_ADDR_LEN]; - USHORT AuthFailReason; - UCHAR AuthFailSta[MAC_ADDR_LEN]; - - NDIS_802_11_PRIVACY_FILTER PrivacyFilter; // PrivacyFilter enum for 802.1X - NDIS_802_11_AUTHENTICATION_MODE AuthMode; // This should match to whatever microsoft defined - NDIS_802_11_WEP_STATUS WepStatus; - NDIS_802_11_WEP_STATUS OrigWepStatus; // Original wep status set from OID - - // Add to support different cipher suite for WPA2/WPA mode - NDIS_802_11_ENCRYPTION_STATUS GroupCipher; // Multicast cipher suite - NDIS_802_11_ENCRYPTION_STATUS PairCipher; // Unicast cipher suite - BOOLEAN bMixCipher; // Indicate current Pair & Group use different cipher suites - USHORT RsnCapability; - - NDIS_802_11_WEP_STATUS GroupKeyWepStatus; - - UCHAR PMK[32]; // WPA PSK mode PMK - UCHAR PTK[64]; // WPA PSK mode PTK - UCHAR GTK[32]; // GTK from authenticator - BSSID_INFO SavedPMK[PMKID_NO]; - UINT SavedPMKNum; // Saved PMKID number - - UCHAR DefaultKeyId; - - - // WPA 802.1x port control, WPA_802_1X_PORT_SECURED, WPA_802_1X_PORT_NOT_SECURED - UCHAR PortSecured; - - // For WPA countermeasures - ULONG LastMicErrorTime; // record last MIC error time - ULONG MicErrCnt; // Should be 0, 1, 2, then reset to zero (after disassoiciation). - BOOLEAN bBlockAssoc; // Block associate attempt for 60 seconds after counter measure occurred. - // For WPA-PSK supplicant state - WPA_STATE WpaState; // Default is SS_NOTUSE and handled by microsoft 802.1x - UCHAR ReplayCounter[8]; - UCHAR ANonce[32]; // ANonce for WPA-PSK from aurhenticator - UCHAR SNonce[32]; // SNonce for WPA-PSK - - UCHAR LastSNR0; // last received BEACON's SNR - UCHAR LastSNR1; // last received BEACON's SNR for 2nd antenna - RSSI_SAMPLE RssiSample; - ULONG NumOfAvgRssiSample; - - ULONG LastBeaconRxTime; // OS's timestamp of the last BEACON RX time - ULONG Last11bBeaconRxTime; // OS's timestamp of the last 11B BEACON RX time - ULONG Last11gBeaconRxTime; // OS's timestamp of the last 11G BEACON RX time - ULONG Last20NBeaconRxTime; // OS's timestamp of the last 20MHz N BEACON RX time - - ULONG LastScanTime; // Record last scan time for issue BSSID_SCAN_LIST - ULONG ScanCnt; // Scan counts since most recent SSID, BSSID, SCAN OID request - BOOLEAN bSwRadio; // Software controlled Radio On/Off, TRUE: On - BOOLEAN bHwRadio; // Hardware controlled Radio On/Off, TRUE: On - BOOLEAN bRadio; // Radio state, And of Sw & Hw radio state - BOOLEAN bHardwareRadio; // Hardware controlled Radio enabled - BOOLEAN bShowHiddenSSID; // Show all known SSID in SSID list get operation - - //BOOLEAN AdhocBOnlyJoined; // Indicate Adhoc B Join. - //BOOLEAN AdhocBGJoined; // Indicate Adhoc B/G Join. - //BOOLEAN Adhoc20NJoined; // Indicate Adhoc 20MHz N Join. - - // New for WPA, windows want us to to keep association information and - // Fixed IEs from last association response - NDIS_802_11_ASSOCIATION_INFORMATION AssocInfo; - USHORT ReqVarIELen; // Length of next VIE include EID & Length - UCHAR ReqVarIEs[MAX_VIE_LEN]; // The content saved here should be little-endian format. - USHORT ResVarIELen; // Length of next VIE include EID & Length - UCHAR ResVarIEs[MAX_VIE_LEN]; - - UCHAR RSNIE_Len; - UCHAR RSN_IE[MAX_LEN_OF_RSNIE]; // The content saved here should be little-endian format. - - // New variables used for CCX 1.0 - BOOLEAN bCkipOn; - BOOLEAN bCkipCmicOn; - UCHAR CkipFlag; - UCHAR GIV[3]; //for CCX iv - UCHAR RxSEQ[4]; - UCHAR TxSEQ[4]; - UCHAR CKIPMIC[4]; - UCHAR LeapAuthMode; - LEAP_AUTH_INFO LeapAuthInfo; - UCHAR HashPwd[16]; - UCHAR NetworkChallenge[8]; - UCHAR NetworkChallengeResponse[24]; - UCHAR PeerChallenge[8]; - - UCHAR PeerChallengeResponse[24]; - UCHAR SessionKey[16]; //Network session keys (NSK) - RALINK_TIMER_STRUCT LeapAuthTimer; - ROGUEAP_TABLE RogueApTab; //Cisco CCX1 Rogue AP Detection - - // New control flags for CCX - CCX_CONTROL CCXControl; // Master administration state - BOOLEAN CCXEnable; // Actual CCX state - UCHAR CCXScanChannel; // Selected channel for CCX beacon request - USHORT CCXScanTime; // Time out to wait for beacon and probe response - UCHAR CCXReqType; // Current processing CCX request type - BSS_TABLE CCXBssTab; // BSS Table - UCHAR FrameReportBuf[2048]; // Buffer for creating frame report - USHORT FrameReportLen; // Current Frame report length - ULONG CLBusyBytes; // Save the total bytes received durning channel load scan time - USHORT RPIDensity[8]; // Array for RPI density collection - // Start address of each BSS table within FrameReportBuf - // It's important to update the RxPower of the corresponding Bss - USHORT BssReportOffset[MAX_LEN_OF_BSS_TABLE]; - USHORT BeaconToken; // Token for beacon report - ULONG LastBssIndex; // Most current reported Bss index - RM_REQUEST_ACTION MeasurementRequest[16]; // Saved measurement request - UCHAR RMReqCnt; // Number of measurement request saved. - UCHAR CurrentRMReqIdx; // Number of measurement request saved. - BOOLEAN ParallelReq; // Parallel measurement, only one request performed, - // It must be the same channel with maximum duration - USHORT ParallelDuration; // Maximum duration for parallel measurement - UCHAR ParallelChannel; // Only one channel with parallel measurement - USHORT IAPPToken; // IAPP dialog token - UCHAR CCXQosECWMin; // Cisco QOS ECWMin for AC 0 - UCHAR CCXQosECWMax; // Cisco QOS ECWMax for AC 0 - // Hack for channel load and noise histogram parameters - UCHAR NHFactor; // Parameter for Noise histogram - UCHAR CLFactor; // Parameter for channel load - - UCHAR KRK[16]; //Key Refresh Key. - UCHAR BTK[32]; //Base Transient Key - BOOLEAN CCKMLinkUpFlag; - ULONG CCKMRN; //(Re)Association request number. - LARGE_INTEGER CCKMBeaconAtJoinTimeStamp; //TSF timer for Re-assocaite to the new AP - UCHAR AironetCellPowerLimit; //in dBm - UCHAR AironetIPAddress[4]; //eg. 192.168.1.1 - BOOLEAN CCXAdjacentAPReportFlag; //flag for determining report Assoc Lost time - CHAR CCXAdjacentAPSsid[MAX_LEN_OF_SSID]; //Adjacent AP's SSID report - UCHAR CCXAdjacentAPSsidLen; // the actual ssid length in used - UCHAR CCXAdjacentAPBssid[MAC_ADDR_LEN]; //Adjacent AP's BSSID report - USHORT CCXAdjacentAPChannel; - ULONG CCXAdjacentAPLinkDownTime; //for Spec S32. - - RALINK_TIMER_STRUCT StaQuickResponeForRateUpTimer; - BOOLEAN StaQuickResponeForRateUpTimerRunning; - - UCHAR DtimCount; // 0.. DtimPeriod-1 - UCHAR DtimPeriod; // default = 3 - -#ifdef QOS_DLS_SUPPORT - RT_802_11_DLS DLSEntry[MAX_NUM_OF_DLS_ENTRY]; - UCHAR DlsReplayCounter[8]; -#endif // QOS_DLS_SUPPORT // - //////////////////////////////////////////////////////////////////////////////////////// - // This is only for WHQL test. - BOOLEAN WhqlTest; - //////////////////////////////////////////////////////////////////////////////////////// - - RALINK_TIMER_STRUCT WpaDisassocAndBlockAssocTimer; - // Fast Roaming - BOOLEAN bFastRoaming; // 0:disable fast roaming, 1:enable fast roaming - CHAR dBmToRoam; // the condition to roam when receiving Rssi less than this value. It's negative value. - -#ifdef WPA_SUPPLICANT_SUPPORT - BOOLEAN IEEE8021X; - BOOLEAN IEEE8021x_required_keys; - CIPHER_KEY DesireSharedKey[4]; // Record user desired WEP keys - UCHAR DesireSharedKeyId; - - // 0: driver ignores wpa_supplicant - // 1: wpa_supplicant initiates scanning and AP selection - // 2: driver takes care of scanning, AP selection, and IEEE 802.11 association parameters - UCHAR WpaSupplicantUP; - UCHAR WpaSupplicantScanCount; -#endif // WPA_SUPPLICANT_SUPPORT // - - CHAR dev_name[16]; - USHORT OriDevType; - - BOOLEAN bTGnWifiTest; - BOOLEAN bScanReqIsFromWebUI; - - HTTRANSMIT_SETTING HTPhyMode, MaxHTPhyMode, MinHTPhyMode;// For transmit phy setting in TXWI. - DESIRED_TRANSMIT_SETTING DesiredTransmitSetting; - RT_HT_PHY_INFO DesiredHtPhyInfo; - BOOLEAN bAutoTxRateSwitch; - - -#ifdef EXT_BUILD_CHANNEL_LIST - UCHAR IEEE80211dClientMode; - UCHAR StaOriCountryCode[3]; - UCHAR StaOriGeography; -#endif // EXT_BUILD_CHANNEL_LIST // -} STA_ADMIN_CONFIG, *PSTA_ADMIN_CONFIG; - -// This data structure keep the current active BSS/IBSS's configuration that this STA -// had agreed upon joining the network. Which means these parameters are usually decided -// by the BSS/IBSS creator instead of user configuration. Data in this data structurre -// is valid only when either ADHOC_ON(pAd) or INFRA_ON(pAd) is TRUE. -// Normally, after SCAN or failed roaming attempts, we need to recover back to -// the current active settings. -typedef struct _STA_ACTIVE_CONFIG { - USHORT Aid; - USHORT AtimWin; // in kusec; IBSS parameter set element - USHORT CapabilityInfo; - USHORT CfpMaxDuration; - USHORT CfpPeriod; - - // Copy supported rate from desired AP's beacon. We are trying to match - // AP's supported and extended rate settings. - UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES]; - UCHAR ExtRate[MAX_LEN_OF_SUPPORTED_RATES]; - UCHAR SupRateLen; - UCHAR ExtRateLen; - // Copy supported ht from desired AP's beacon. We are trying to match - RT_HT_PHY_INFO SupportedPhyInfo; - RT_HT_CAPABILITY SupportedHtPhy; -} STA_ACTIVE_CONFIG, *PSTA_ACTIVE_CONFIG; -#endif // CONFIG_STA_SUPPORT // - -#ifdef RT2870 -typedef struct RT_ADD_PAIRWISE_KEY_ENTRY { - NDIS_802_11_MAC_ADDRESS MacAddr; - USHORT MacTabMatchWCID; // ASIC - CIPHER_KEY CipherKey; -} RT_ADD_PAIRWISE_KEY_ENTRY,*PRT_ADD_PAIRWISE_KEY_ENTRY; -#endif // RT2870 // - -// ----------- start of AP -------------------------- -// AUTH-RSP State Machine Aux data structure -typedef struct _AP_MLME_AUX { - UCHAR Addr[MAC_ADDR_LEN]; - USHORT Alg; - CHAR Challenge[CIPHER_TEXT_LEN]; -} AP_MLME_AUX, *PAP_MLME_AUX; - -// structure to define WPA Group Key Rekey Interval -typedef struct PACKED _RT_802_11_WPA_REKEY { - ULONG ReKeyMethod; // mechanism for rekeying: 0:disable, 1: time-based, 2: packet-based - ULONG ReKeyInterval; // time-based: seconds, packet-based: kilo-packets -} RT_WPA_REKEY,*PRT_WPA_REKEY, RT_802_11_WPA_REKEY, *PRT_802_11_WPA_REKEY; - -typedef struct _MAC_TABLE_ENTRY { - //Choose 1 from ValidAsWDS and ValidAsCLI to validize. - BOOLEAN ValidAsCLI; // Sta mode, set this TRUE after Linkup,too. - BOOLEAN ValidAsWDS; // This is WDS Entry. only for AP mode. - BOOLEAN ValidAsApCli; //This is a AP-Client entry, only for AP mode which enable AP-Client functions. - BOOLEAN ValidAsMesh; - BOOLEAN ValidAsDls; // This is DLS Entry. only for STA mode. - BOOLEAN isCached; - BOOLEAN bIAmBadAtheros; - - UCHAR EnqueueEapolStartTimerRunning; // Enqueue EAPoL-Start for triggering EAP SM - //jan for wpa - // record which entry revoke MIC Failure , if it leaves the BSS itself, AP won't update aMICFailTime MIB - UCHAR CMTimerRunning; - UCHAR apidx; // MBSS number - UCHAR RSNIE_Len; - UCHAR RSN_IE[MAX_LEN_OF_RSNIE]; - UCHAR ANonce[LEN_KEY_DESC_NONCE]; - UCHAR R_Counter[LEN_KEY_DESC_REPLAY]; - UCHAR PTK[64]; - UCHAR ReTryCounter; - RALINK_TIMER_STRUCT RetryTimer; - RALINK_TIMER_STRUCT EnqueueStartForPSKTimer; // A timer which enqueue EAPoL-Start for triggering PSK SM - NDIS_802_11_AUTHENTICATION_MODE AuthMode; // This should match to whatever microsoft defined - NDIS_802_11_WEP_STATUS WepStatus; - AP_WPA_STATE WpaState; - GTK_STATE GTKState; - USHORT PortSecured; - NDIS_802_11_PRIVACY_FILTER PrivacyFilter; // PrivacyFilter enum for 802.1X - CIPHER_KEY PairwiseKey; - PVOID pAd; - INT PMKID_CacheIdx; - UCHAR PMKID[LEN_PMKID]; - - - UCHAR Addr[MAC_ADDR_LEN]; - UCHAR PsMode; - SST Sst; - AUTH_STATE AuthState; // for SHARED KEY authentication state machine used only - BOOLEAN IsReassocSta; // Indicate whether this is a reassociation procedure - USHORT Aid; - USHORT CapabilityInfo; - UCHAR LastRssi; - ULONG NoDataIdleCount; - UINT16 StationKeepAliveCount; // unit: second - ULONG PsQIdleCount; - QUEUE_HEADER PsQueue; - - UINT32 StaConnectTime; // the live time of this station since associated with AP - - -#ifdef DOT11_N_SUPPORT - BOOLEAN bSendBAR; - USHORT NoBADataCountDown; - - UINT32 CachedBuf[16]; // UINT (4 bytes) for alignment - UINT TxBFCount; // 3*3 -#endif // DOT11_N_SUPPORT // - UINT FIFOCount; - UINT DebugFIFOCount; - UINT DebugTxCount; - BOOLEAN bDlsInit; - - -//==================================================== -//WDS entry needs these -// rt2860 add this. if ValidAsWDS==TRUE, MatchWDSTabIdx is the index in WdsTab.MacTab - UINT MatchWDSTabIdx; - UCHAR MaxSupportedRate; - UCHAR CurrTxRate; - UCHAR CurrTxRateIndex; - // to record the each TX rate's quality. 0 is best, the bigger the worse. - USHORT TxQuality[MAX_STEP_OF_TX_RATE_SWITCH]; -// USHORT OneSecTxOkCount; - UINT32 OneSecTxNoRetryOkCount; - UINT32 OneSecTxRetryOkCount; - UINT32 OneSecTxFailCount; - UINT32 ContinueTxFailCnt; - UINT32 CurrTxRateStableTime; // # of second in current TX rate - UCHAR TxRateUpPenalty; // extra # of second penalty due to last unstable condition -//==================================================== - - - -#ifdef CONFIG_STA_SUPPORT -#ifdef QOS_DLS_SUPPORT - UINT MatchDlsEntryIdx; // indicate the index in pAd->StaCfg.DLSEntry -#endif // QOS_DLS_SUPPORT // -#endif // CONFIG_STA_SUPPORT // - - BOOLEAN fNoisyEnvironment; - BOOLEAN fLastSecAccordingRSSI; - UCHAR LastSecTxRateChangeAction; // 0: no change, 1:rate UP, 2:rate down - CHAR LastTimeTxRateChangeAction; //Keep last time value of LastSecTxRateChangeAction - ULONG LastTxOkCount; - UCHAR PER[MAX_STEP_OF_TX_RATE_SWITCH]; - - // a bitmap of BOOLEAN flags. each bit represent an operation status of a particular - // BOOLEAN control, either ON or OFF. These flags should always be accessed via - // CLIENT_STATUS_TEST_FLAG(), CLIENT_STATUS_SET_FLAG(), CLIENT_STATUS_CLEAR_FLAG() macros. - // see fOP_STATUS_xxx in RTMP_DEF.C for detail bit definition. fCLIENT_STATUS_AMSDU_INUSED - ULONG ClientStatusFlags; - - // TODO: Shall we move that to DOT11_N_SUPPORT??? - HTTRANSMIT_SETTING HTPhyMode, MaxHTPhyMode, MinHTPhyMode;// For transmit phy setting in TXWI. - -#ifdef DOT11_N_SUPPORT - // HT EWC MIMO-N used parameters - USHORT RXBAbitmap; // fill to on-chip RXWI_BA_BITMASK in 8.1.3RX attribute entry format - USHORT TXBAbitmap; // This bitmap as originator, only keep in software used to mark AMPDU bit in TXWI - USHORT TXAutoBAbitmap; - USHORT BADeclineBitmap; - USHORT BARecWcidArray[NUM_OF_TID]; // The mapping wcid of recipient session. if RXBAbitmap bit is masked - USHORT BAOriWcidArray[NUM_OF_TID]; // The mapping wcid of originator session. if TXBAbitmap bit is masked - USHORT BAOriSequence[NUM_OF_TID]; // The mapping wcid of originator session. if TXBAbitmap bit is masked - - // 802.11n features. - UCHAR MpduDensity; - UCHAR MaxRAmpduFactor; - UCHAR AMsduSize; - UCHAR MmpsMode; // MIMO power save more. - - HT_CAPABILITY_IE HTCapability; - -#ifdef DOT11N_DRAFT3 - UCHAR BSS2040CoexistenceMgmtSupport; -#endif // DOT11N_DRAFT3 // -#endif // DOT11_N_SUPPORT // - - BOOLEAN bAutoTxRateSwitch; - - UCHAR RateLen; - struct _MAC_TABLE_ENTRY *pNext; - USHORT TxSeq[NUM_OF_TID]; - USHORT NonQosDataSeq; - - RSSI_SAMPLE RssiSample; - - UINT32 TXMCSExpected[16]; - UINT32 TXMCSSuccessful[16]; - UINT32 TXMCSFailed[16]; - UINT32 TXMCSAutoFallBack[16][16]; - -#ifdef CONFIG_STA_SUPPORT - ULONG LastBeaconRxTime; -#endif // CONFIG_STA_SUPPORT // -} MAC_TABLE_ENTRY, *PMAC_TABLE_ENTRY; - -typedef struct _MAC_TABLE { - USHORT Size; - MAC_TABLE_ENTRY *Hash[HASH_TABLE_SIZE]; - MAC_TABLE_ENTRY Content[MAX_LEN_OF_MAC_TABLE]; - QUEUE_HEADER McastPsQueue; - ULONG PsQIdleCount; - BOOLEAN fAnyStationInPsm; - BOOLEAN fAnyStationBadAtheros; // Check if any Station is atheros 802.11n Chip. We need to use RTS/CTS with Atheros 802,.11n chip. - BOOLEAN fAnyTxOPForceDisable; // Check if it is necessary to disable BE TxOP - BOOLEAN fAllStationAsRalink; // Check if all stations are ralink-chipset -#ifdef DOT11_N_SUPPORT - BOOLEAN fAnyStationIsLegacy; // Check if I use legacy rate to transmit to my BSS Station/ - BOOLEAN fAnyStationNonGF; // Check if any Station can't support GF. - BOOLEAN fAnyStation20Only; // Check if any Station can't support GF. - BOOLEAN fAnyStationMIMOPSDynamic; // Check if any Station is MIMO Dynamic - BOOLEAN fAnyBASession; // Check if there is BA session. Force turn on RTS/CTS -#endif // DOT11_N_SUPPORT // -} MAC_TABLE, *PMAC_TABLE; - -#ifdef DOT11_N_SUPPORT -#define IS_HT_STA(_pMacEntry) \ - (_pMacEntry->MaxHTPhyMode.field.MODE >= MODE_HTMIX) - -#define IS_HT_RATE(_pMacEntry) \ - (_pMacEntry->HTPhyMode.field.MODE >= MODE_HTMIX) - -#define PEER_IS_HT_RATE(_pMacEntry) \ - (_pMacEntry->HTPhyMode.field.MODE >= MODE_HTMIX) -#endif // DOT11_N_SUPPORT // - -typedef struct _WDS_ENTRY { - BOOLEAN Valid; - UCHAR Addr[MAC_ADDR_LEN]; - ULONG NoDataIdleCount; - struct _WDS_ENTRY *pNext; -} WDS_ENTRY, *PWDS_ENTRY; - -typedef struct _WDS_TABLE_ENTRY { - USHORT Size; - UCHAR WdsAddr[MAC_ADDR_LEN]; - WDS_ENTRY *Hash[HASH_TABLE_SIZE]; - WDS_ENTRY Content[MAX_LEN_OF_MAC_TABLE]; - UCHAR MaxSupportedRate; - UCHAR CurrTxRate; - USHORT TxQuality[MAX_LEN_OF_SUPPORTED_RATES]; - USHORT OneSecTxOkCount; - USHORT OneSecTxRetryOkCount; - USHORT OneSecTxFailCount; - ULONG CurrTxRateStableTime; // # of second in current TX rate - UCHAR TxRateUpPenalty; // extra # of second penalty due to last unstable condition -} WDS_TABLE_ENTRY, *PWDS_TABLE_ENTRY; - -typedef struct _RT_802_11_WDS_ENTRY { - PNET_DEV dev; - UCHAR Valid; - UCHAR PhyMode; - UCHAR PeerWdsAddr[MAC_ADDR_LEN]; - UCHAR MacTabMatchWCID; // ASIC - NDIS_802_11_WEP_STATUS WepStatus; - UCHAR KeyIdx; - CIPHER_KEY WdsKey; - HTTRANSMIT_SETTING HTPhyMode, MaxHTPhyMode, MinHTPhyMode; - RT_HT_PHY_INFO DesiredHtPhyInfo; - BOOLEAN bAutoTxRateSwitch; - DESIRED_TRANSMIT_SETTING DesiredTransmitSetting; // Desired transmit setting. -} RT_802_11_WDS_ENTRY, *PRT_802_11_WDS_ENTRY; - -typedef struct _WDS_TABLE { - UCHAR Mode; - ULONG Size; - RT_802_11_WDS_ENTRY WdsEntry[MAX_WDS_ENTRY]; -} WDS_TABLE, *PWDS_TABLE; - -typedef struct _APCLI_STRUCT { - PNET_DEV dev; -#ifdef RTL865X_SOC - unsigned int mylinkid; -#endif - BOOLEAN Enable; // Set it as 1 if the apcli interface was configured to "1" or by iwpriv cmd "ApCliEnable" - BOOLEAN Valid; // Set it as 1 if the apcli interface associated success to remote AP. - UCHAR MacTabWCID; //WCID value, which point to the entry of ASIC Mac table. - UCHAR SsidLen; - CHAR Ssid[MAX_LEN_OF_SSID]; - - UCHAR CfgSsidLen; - CHAR CfgSsid[MAX_LEN_OF_SSID]; - UCHAR CfgApCliBssid[ETH_LENGTH_OF_ADDRESS]; - UCHAR CurrentAddress[ETH_LENGTH_OF_ADDRESS]; - - ULONG ApCliRcvBeaconTime; - - ULONG CtrlCurrState; - ULONG SyncCurrState; - ULONG AuthCurrState; - ULONG AssocCurrState; - ULONG WpaPskCurrState; - - USHORT AuthReqCnt; - USHORT AssocReqCnt; - - ULONG ClientStatusFlags; - UCHAR MpduDensity; - - NDIS_802_11_AUTHENTICATION_MODE AuthMode; // This should match to whatever microsoft defined - NDIS_802_11_WEP_STATUS WepStatus; - - // Add to support different cipher suite for WPA2/WPA mode - NDIS_802_11_ENCRYPTION_STATUS GroupCipher; // Multicast cipher suite - NDIS_802_11_ENCRYPTION_STATUS PairCipher; // Unicast cipher suite - BOOLEAN bMixCipher; // Indicate current Pair & Group use different cipher suites - USHORT RsnCapability; - - UCHAR PSK[100]; // reserve PSK key material - UCHAR PSKLen; - UCHAR PMK[32]; // WPA PSK mode PMK - //UCHAR PTK[64]; // WPA PSK mode PTK - UCHAR GTK[32]; // GTK from authenticator - - //CIPHER_KEY PairwiseKey; - CIPHER_KEY SharedKey[SHARE_KEY_NUM]; - UCHAR DefaultKeyId; - - // WPA 802.1x port control, WPA_802_1X_PORT_SECURED, WPA_802_1X_PORT_NOT_SECURED - //UCHAR PortSecured; - - // store RSN_IE built by driver - UCHAR RSN_IE[MAX_LEN_OF_RSNIE]; // The content saved here should be convert to little-endian format. - UCHAR RSNIE_Len; - - // For WPA countermeasures - ULONG LastMicErrorTime; // record last MIC error time - //ULONG MicErrCnt; // Should be 0, 1, 2, then reset to zero (after disassoiciation). - BOOLEAN bBlockAssoc; // Block associate attempt for 60 seconds after counter measure occurred. - - // For WPA-PSK supplicant state - //WPA_STATE WpaState; // Default is SS_NOTUSE - //UCHAR ReplayCounter[8]; - //UCHAR ANonce[32]; // ANonce for WPA-PSK from authenticator - UCHAR SNonce[32]; // SNonce for WPA-PSK - UCHAR GNonce[32]; // GNonce for WPA-PSK from authenticator - - HTTRANSMIT_SETTING HTPhyMode, MaxHTPhyMode, MinHTPhyMode; - RT_HT_PHY_INFO DesiredHtPhyInfo; - BOOLEAN bAutoTxRateSwitch; - DESIRED_TRANSMIT_SETTING DesiredTransmitSetting; // Desired transmit setting. -} APCLI_STRUCT, *PAPCLI_STRUCT; - -// ----------- end of AP ---------------------------- - -#ifdef BLOCK_NET_IF -typedef struct _BLOCK_QUEUE_ENTRY -{ - BOOLEAN SwTxQueueBlockFlag; - LIST_HEADER NetIfList; -} BLOCK_QUEUE_ENTRY, *PBLOCK_QUEUE_ENTRY; -#endif // BLOCK_NET_IF // - - -struct wificonf -{ - BOOLEAN bShortGI; - BOOLEAN bGreenField; -}; - - - - -typedef struct _INF_PCI_CONFIG -{ - PUCHAR CSRBaseAddress; // PCI MMIO Base Address, all access will use -}INF_PCI_CONFIG; - -typedef struct _INF_USB_CONFIG -{ - UINT BulkInEpAddr; // bulk-in endpoint address - UINT BulkOutEpAddr[6]; // bulk-out endpoint address - -}INF_USB_CONFIG; - -#ifdef IKANOS_VX_1X0 - typedef void (*IkanosWlanTxCbFuncP)(void *, void *); - - struct IKANOS_TX_INFO - { - struct net_device *netdev; - IkanosWlanTxCbFuncP *fp; - }; -#endif // IKANOS_VX_1X0 // - -#ifdef NINTENDO_AP -typedef struct _NINDO_CTRL_BLOCK { - - RT_NINTENDO_TABLE DS_TABLE; - -#ifdef CHIP25XX - spinlock_t NINTENDO_TABLE_Lock; -#else - NDIS_SPIN_LOCK NINTENDO_TABLE_Lock; -#endif // CHIP25XX // - - UCHAR NINTENDO_UP_BUFFER[512]; - UCHAR Local_KeyIdx; - CIPHER_KEY Local_SharedKey; - UCHAR Local_bHideSsid; - UCHAR Local_AuthMode; - UCHAR Local_WepStatus; - USHORT Local_CapabilityInfo; -} NINDO_CTRL_BLOCK; -#endif // NINTENDO_AP // - - -#ifdef DBG_DIAGNOSE -#define DIAGNOSE_TIME 10 // 10 sec -typedef struct _RtmpDiagStrcut_ -{ // Diagnosis Related element - unsigned char inited; - unsigned char qIdx; - unsigned char ArrayStartIdx; - unsigned char ArrayCurIdx; - // Tx Related Count - USHORT TxDataCnt[DIAGNOSE_TIME]; - USHORT TxFailCnt[DIAGNOSE_TIME]; -// USHORT TxDescCnt[DIAGNOSE_TIME][16]; // TxDesc queue length in scale of 0~14, >=15 - USHORT TxDescCnt[DIAGNOSE_TIME][24]; // 3*3 // TxDesc queue length in scale of 0~14, >=15 -// USHORT TxMcsCnt[DIAGNOSE_TIME][16]; // TxDate MCS Count in range from 0 to 15, step in 1. - USHORT TxMcsCnt[DIAGNOSE_TIME][24]; // 3*3 - USHORT TxSWQueCnt[DIAGNOSE_TIME][9]; // TxSwQueue length in scale of 0, 1, 2, 3, 4, 5, 6, 7, >=8 - - USHORT TxAggCnt[DIAGNOSE_TIME]; - USHORT TxNonAggCnt[DIAGNOSE_TIME]; -// USHORT TxAMPDUCnt[DIAGNOSE_TIME][16]; // 10 sec, TxDMA APMDU Aggregation count in range from 0 to 15, in setp of 1. - USHORT TxAMPDUCnt[DIAGNOSE_TIME][24]; // 3*3 // 10 sec, TxDMA APMDU Aggregation count in range from 0 to 15, in setp of 1. - USHORT TxRalinkCnt[DIAGNOSE_TIME]; // TxRalink Aggregation Count in 1 sec scale. - USHORT TxAMSDUCnt[DIAGNOSE_TIME]; // TxAMSUD Aggregation Count in 1 sec scale. - - // Rx Related Count - USHORT RxDataCnt[DIAGNOSE_TIME]; // Rx Total Data count. - USHORT RxCrcErrCnt[DIAGNOSE_TIME]; -// USHORT RxMcsCnt[DIAGNOSE_TIME][16]; // Rx MCS Count in range from 0 to 15, step in 1. - USHORT RxMcsCnt[DIAGNOSE_TIME][24]; // 3*3 -}RtmpDiagStruct; -#endif // DBG_DIAGNOSE // - - -// -// The miniport adapter structure -// -typedef struct _RTMP_ADAPTER -{ - PVOID OS_Cookie; // save specific structure relative to OS - PNET_DEV net_dev; - ULONG VirtualIfCnt; - - - - NDIS_SPIN_LOCK irq_lock; - UCHAR irq_disabled; - -#ifdef RT2870 -/*****************************************************************************************/ -/* USB related parameters */ -/*****************************************************************************************/ - struct usb_config_descriptor *config; - UINT BulkInEpAddr; // bulk-in endpoint address - UINT BulkOutEpAddr[6]; // bulk-out endpoint address - - UINT NumberOfPipes; - USHORT BulkOutMaxPacketSize; - USHORT BulkInMaxPacketSize; - - //======Control Flags - LONG PendingIoCount; - ULONG BulkFlags; - BOOLEAN bUsbTxBulkAggre; // Flags for bulk out data priority - - - //======Timer Thread - RT2870_TIMER_QUEUE TimerQ; - NDIS_SPIN_LOCK TimerQLock; - - - //======Cmd Thread - CmdQ CmdQ; - NDIS_SPIN_LOCK CmdQLock; // CmdQLock spinlock - - BOOLEAN TimerFunc_kill; - BOOLEAN mlme_kill; - - - //======Semaphores (event) - struct semaphore mlme_semaphore; /* to sleep thread on */ - struct semaphore RTUSBCmd_semaphore; /* to sleep thread on */ - struct semaphore RTUSBTimer_semaphore; -#ifdef INF_AMAZON_SE - struct semaphore UsbVendorReq_semaphore; - PVOID UsbVendorReqBuf; -#endif // INF_AMAZON_SE // - struct completion TimerQComplete; - struct completion mlmeComplete; - struct completion CmdQComplete; - wait_queue_head_t *wait; - - //======Lock for 2870 ATE -#ifdef RALINK_ATE - NDIS_SPIN_LOCK GenericLock; // ATE Tx/Rx generic spinlock -#endif // RALINK_ATE // - -#endif // RT2870 // - - -/*****************************************************************************************/ - /* Both PCI/USB related parameters */ -/*****************************************************************************************/ - - -/*****************************************************************************************/ -/* Tx related parameters */ -/*****************************************************************************************/ - BOOLEAN DeQueueRunning[NUM_OF_TX_RING]; // for ensuring RTUSBDeQueuePacket get call once - NDIS_SPIN_LOCK DeQueueLock[NUM_OF_TX_RING]; - -#ifdef RT2870 - // Data related context and AC specified, 4 AC supported - NDIS_SPIN_LOCK BulkOutLock[6]; // BulkOut spinlock for 4 ACs - NDIS_SPIN_LOCK MLMEBulkOutLock; // MLME BulkOut lock - - HT_TX_CONTEXT TxContext[NUM_OF_TX_RING]; - NDIS_SPIN_LOCK TxContextQueueLock[NUM_OF_TX_RING]; // TxContextQueue spinlock - - // 4 sets of Bulk Out index and pending flag - UCHAR NextBulkOutIndex[4]; // only used for 4 EDCA bulkout pipe - - BOOLEAN BulkOutPending[6]; // used for total 6 bulkout pipe - UCHAR bulkResetPipeid; - BOOLEAN MgmtBulkPending; - ULONG bulkResetReq[6]; -#endif // RT2870 // - - // resource for software backlog queues - QUEUE_HEADER TxSwQueue[NUM_OF_TX_RING]; // 4 AC + 1 HCCA - NDIS_SPIN_LOCK TxSwQueueLock[NUM_OF_TX_RING]; // TxSwQueue spinlock - - RTMP_DMABUF MgmtDescRing; // Shared memory for MGMT descriptors - RTMP_MGMT_RING MgmtRing; - NDIS_SPIN_LOCK MgmtRingLock; // Prio Ring spinlock - - -/*****************************************************************************************/ -/* Rx related parameters */ -/*****************************************************************************************/ - - -#ifdef RT2870 - RX_CONTEXT RxContext[RX_RING_SIZE]; // 1 for redundant multiple IRP bulk in. - NDIS_SPIN_LOCK BulkInLock; // BulkIn spinlock for 4 ACs - UCHAR PendingRx; // The Maxima pending Rx value should be RX_RING_SIZE. - UCHAR NextRxBulkInIndex; // Indicate the current RxContext Index which hold by Host controller. - UCHAR NextRxBulkInReadIndex; // Indicate the current RxContext Index which driver can read & process it. - ULONG NextRxBulkInPosition; // Want to contatenate 2 URB buffer while 1st is bulkin failed URB. This Position is 1st URB TransferLength. - ULONG TransferBufferLength; // current length of the packet buffer - ULONG ReadPosition; // current read position in a packet buffer -#endif // RT2870 // - - -/*****************************************************************************************/ -/* ASIC related parameters */ -/*****************************************************************************************/ - UINT32 MACVersion; // MAC version. Record rt2860C(0x28600100) or rt2860D (0x28600101).. - - // --------------------------- - // E2PROM - // --------------------------- - ULONG EepromVersion; // byte 0: version, byte 1: revision, byte 2~3: unused - UCHAR EEPROMAddressNum; // 93c46=6 93c66=8 - USHORT EEPROMDefaultValue[NUM_EEPROM_BBP_PARMS]; - BOOLEAN EepromAccess; - UCHAR EFuseTag; - ULONG FirmwareVersion; // byte 0: Minor version, byte 1: Major version, otherwise unused. - - // --------------------------- - // BBP Control - // --------------------------- - UCHAR BbpWriteLatch[140]; // record last BBP register value written via BBP_IO_WRITE/BBP_IO_WRITE_VY_REG_ID - UCHAR BbpRssiToDbmDelta; - BBP_R66_TUNING BbpTuning; - - // ---------------------------- - // RFIC control - // ---------------------------- - UCHAR RfIcType; // RFIC_xxx - ULONG RfFreqOffset; // Frequency offset for channel switching - RTMP_RF_REGS LatchRfRegs; // latch th latest RF programming value since RF IC doesn't support READ - - EEPROM_ANTENNA_STRUC Antenna; // Since ANtenna definition is different for a & g. We need to save it for future reference. - EEPROM_NIC_CONFIG2_STRUC NicConfig2; - - // This soft Rx Antenna Diversity mechanism is used only when user set - // RX Antenna = DIVERSITY ON - SOFT_RX_ANT_DIVERSITY RxAnt; - - UCHAR RFProgSeq; - CHANNEL_TX_POWER TxPower[MAX_NUM_OF_CHANNELS]; // Store Tx power value for all channels. - CHANNEL_TX_POWER ChannelList[MAX_NUM_OF_CHANNELS]; // list all supported channels for site survey - CHANNEL_11J_TX_POWER TxPower11J[MAX_NUM_OF_11JCHANNELS]; // 802.11j channel and bw - CHANNEL_11J_TX_POWER ChannelList11J[MAX_NUM_OF_11JCHANNELS]; // list all supported channels for site survey - - UCHAR ChannelListNum; // number of channel in ChannelList[] - UCHAR Bbp94; - BOOLEAN BbpForCCK; - ULONG Tx20MPwrCfgABand[5]; - ULONG Tx20MPwrCfgGBand[5]; - ULONG Tx40MPwrCfgABand[5]; - ULONG Tx40MPwrCfgGBand[5]; - - BOOLEAN bAutoTxAgcA; // Enable driver auto Tx Agc control - UCHAR TssiRefA; // Store Tssi reference value as 25 temperature. - UCHAR TssiPlusBoundaryA[5]; // Tssi boundary for increase Tx power to compensate. - UCHAR TssiMinusBoundaryA[5]; // Tssi boundary for decrease Tx power to compensate. - UCHAR TxAgcStepA; // Store Tx TSSI delta increment / decrement value - CHAR TxAgcCompensateA; // Store the compensation (TxAgcStep * (idx-1)) - - BOOLEAN bAutoTxAgcG; // Enable driver auto Tx Agc control - UCHAR TssiRefG; // Store Tssi reference value as 25 temperature. - UCHAR TssiPlusBoundaryG[5]; // Tssi boundary for increase Tx power to compensate. - UCHAR TssiMinusBoundaryG[5]; // Tssi boundary for decrease Tx power to compensate. - UCHAR TxAgcStepG; // Store Tx TSSI delta increment / decrement value - CHAR TxAgcCompensateG; // Store the compensation (TxAgcStep * (idx-1)) - - //+++For RT2870, the parameteres is start from BGRssiOffset1 ~ BGRssiOffset3 - CHAR BGRssiOffset0; // Store B/G RSSI#0 Offset value on EEPROM 0x46h - CHAR BGRssiOffset1; // Store B/G RSSI#1 Offset value - CHAR BGRssiOffset2; // Store B/G RSSI#2 Offset value - //--- - - //+++For RT2870, the parameteres is start from ARssiOffset1 ~ ARssiOffset3 - CHAR ARssiOffset0; // Store A RSSI#0 Offset value on EEPROM 0x4Ah - CHAR ARssiOffset1; // Store A RSSI#1 Offset value - CHAR ARssiOffset2; // Store A RSSI#2 Offset value - //--- - - CHAR BLNAGain; // Store B/G external LNA#0 value on EEPROM 0x44h - CHAR ALNAGain0; // Store A external LNA#0 value for ch36~64 - CHAR ALNAGain1; // Store A external LNA#1 value for ch100~128 - CHAR ALNAGain2; // Store A external LNA#2 value for ch132~165 - - // ---------------------------- - // LED control - // ---------------------------- - MCU_LEDCS_STRUC LedCntl; - USHORT Led1; // read from EEPROM 0x3c - USHORT Led2; // EEPROM 0x3e - USHORT Led3; // EEPROM 0x40 - UCHAR LedIndicatorStregth; - UCHAR RssiSingalstrengthOffet; - BOOLEAN bLedOnScanning; - UCHAR LedStatus; - -/*****************************************************************************************/ -/* 802.11 related parameters */ -/*****************************************************************************************/ - // outgoing BEACON frame buffer and corresponding TXD - TXWI_STRUC BeaconTxWI; - PUCHAR BeaconBuf; - USHORT BeaconOffset[HW_BEACON_MAX_COUNT]; - - // pre-build PS-POLL and NULL frame upon link up. for efficiency purpose. - PSPOLL_FRAME PsPollFrame; - HEADER_802_11 NullFrame; - -#ifdef RT2870 - TX_CONTEXT BeaconContext[BEACON_RING_SIZE]; - TX_CONTEXT NullContext; - TX_CONTEXT PsPollContext; - TX_CONTEXT RTSContext; -#endif // RT2870 // - - - -//=========AP=========== - - -//=======STA=========== -#ifdef CONFIG_STA_SUPPORT -/* Modified by Wu Xi-Kun 4/21/2006 */ - // ----------------------------------------------- - // STA specific configuration & operation status - // used only when pAd->OpMode == OPMODE_STA - // ----------------------------------------------- - STA_ADMIN_CONFIG StaCfg; // user desired settings - STA_ACTIVE_CONFIG StaActive; // valid only when ADHOC_ON(pAd) || INFRA_ON(pAd) - CHAR nickname[IW_ESSID_MAX_SIZE+1]; // nickname, only used in the iwconfig i/f - NDIS_MEDIA_STATE PreMediaState; -#endif // CONFIG_STA_SUPPORT // - -//=======Common=========== - // OP mode: either AP or STA - UCHAR OpMode; // OPMODE_STA, OPMODE_AP - - NDIS_MEDIA_STATE IndicateMediaState; // Base on Indication state, default is NdisMediaStateDisConnected - - - // MAT related parameters - - // configuration: read from Registry & E2PROM - BOOLEAN bLocalAdminMAC; // Use user changed MAC - UCHAR PermanentAddress[MAC_ADDR_LEN]; // Factory default MAC address - UCHAR CurrentAddress[MAC_ADDR_LEN]; // User changed MAC address - - // ------------------------------------------------------ - // common configuration to both OPMODE_STA and OPMODE_AP - // ------------------------------------------------------ - COMMON_CONFIG CommonCfg; - MLME_STRUCT Mlme; - - // AP needs those vaiables for site survey feature. - MLME_AUX MlmeAux; // temporary settings used during MLME state machine - BSS_TABLE ScanTab; // store the latest SCAN result - - //About MacTab, the sta driver will use #0 and #1 for multicast and AP. - MAC_TABLE MacTab; // ASIC on-chip WCID entry table. At TX, ASIC always use key according to this on-chip table. - NDIS_SPIN_LOCK MacTabLock; - -#ifdef DOT11_N_SUPPORT - BA_TABLE BATable; -#endif // DOT11_N_SUPPORT // - NDIS_SPIN_LOCK BATabLock; - RALINK_TIMER_STRUCT RECBATimer; - - // encryption/decryption KEY tables - CIPHER_KEY SharedKey[MAX_MBSSID_NUM][4]; // STA always use SharedKey[BSS0][0..3] - - // RX re-assembly buffer for fragmentation - FRAGMENT_FRAME FragFrame; // Frame storage for fragment frame - - // various Counters - COUNTER_802_3 Counters8023; // 802.3 counters - COUNTER_802_11 WlanCounters; // 802.11 MIB counters - COUNTER_RALINK RalinkCounters; // Ralink propriety counters - COUNTER_DRS DrsCounters; // counters for Dynamic TX Rate Switching - PRIVATE_STRUC PrivateInfo; // Private information & counters - - // flags, see fRTMP_ADAPTER_xxx flags - ULONG Flags; // Represent current device status - - // current TX sequence # - USHORT Sequence; - -#ifdef UNDER_CE - NDIS_HANDLE hGiISR; -#endif - - - // Control disconnect / connect event generation - //+++Didn't used anymore - ULONG LinkDownTime; - //--- - ULONG LastRxRate; - ULONG LastTxRate; - //+++Used only for Station - BOOLEAN bConfigChanged; // Config Change flag for the same SSID setting - //--- - - ULONG ExtraInfo; // Extra information for displaying status - ULONG SystemErrorBitmap; // b0: E2PROM version error - - //+++Didn't used anymore - ULONG MacIcVersion; // MAC/BBP serial interface issue solved after ver.D - //--- - - // --------------------------- - // System event log - // --------------------------- - RT_802_11_EVENT_TABLE EventTab; - - - BOOLEAN HTCEnable; - - /*****************************************************************************************/ - /* Statistic related parameters */ - /*****************************************************************************************/ -#ifdef RT2870 - ULONG BulkOutDataOneSecCount; - ULONG BulkInDataOneSecCount; - ULONG BulkLastOneSecCount; // BulkOutDataOneSecCount + BulkInDataOneSecCount - ULONG watchDogRxCnt; - ULONG watchDogRxOverFlowCnt; - ULONG watchDogTxPendingCnt[NUM_OF_TX_RING]; -#endif // RT2870 // - - BOOLEAN bUpdateBcnCntDone; - ULONG watchDogMacDeadlock; // prevent MAC/BBP into deadlock condition - // ---------------------------- - // DEBUG paramerts - // ---------------------------- - //ULONG DebugSetting[4]; - BOOLEAN bBanAllBaSetup; - BOOLEAN bPromiscuous; - - // ---------------------------- - // rt2860c emulation-use Parameters - // ---------------------------- - ULONG rtsaccu[30]; - ULONG ctsaccu[30]; - ULONG cfendaccu[30]; - ULONG bacontent[16]; - ULONG rxint[RX_RING_SIZE+1]; - UCHAR rcvba[60]; - BOOLEAN bLinkAdapt; - BOOLEAN bForcePrintTX; - BOOLEAN bForcePrintRX; - BOOLEAN bDisablescanning; //defined in RT2870 USB - BOOLEAN bStaFifoTest; - BOOLEAN bProtectionTest; - BOOLEAN bHCCATest; - BOOLEAN bGenOneHCCA; - BOOLEAN bBroadComHT; - //+++Following add from RT2870 USB. - ULONG BulkOutReq; - ULONG BulkOutComplete; - ULONG BulkOutCompleteOther; - ULONG BulkOutCompleteCancel; // seems not use now? - ULONG BulkInReq; - ULONG BulkInComplete; - ULONG BulkInCompleteFail; - //--- - - struct wificonf WIFItestbed; - -#ifdef RALINK_ATE - ATE_INFO ate; -#ifdef RT2870 - BOOLEAN ContinBulkOut; //ATE bulk out control - BOOLEAN ContinBulkIn; //ATE bulk in control - atomic_t BulkOutRemained; - atomic_t BulkInRemained; -#endif // RT2870 // -#endif // RALINK_ATE // - -#ifdef DOT11_N_SUPPORT - struct reordering_mpdu_pool mpdu_blk_pool; -#endif // DOT11_N_SUPPORT // - - ULONG OneSecondnonBEpackets; // record non BE packets per second - -#if WIRELESS_EXT >= 12 - struct iw_statistics iw_stats; -#endif - - struct net_device_stats stats; - -#ifdef BLOCK_NET_IF - BLOCK_QUEUE_ENTRY blockQueueTab[NUM_OF_TX_RING]; -#endif // BLOCK_NET_IF // - - - -#ifdef MULTIPLE_CARD_SUPPORT - INT32 MC_RowID; - UCHAR MC_FileName[256]; -#endif // MULTIPLE_CARD_SUPPORT // - - ULONG TbttTickCount; -#ifdef PCI_MSI_SUPPORT - BOOLEAN HaveMsi; -#endif // PCI_MSI_SUPPORT // - - - UCHAR is_on; - -#define TIME_BASE (1000000/OS_HZ) -#define TIME_ONE_SECOND (1000000/TIME_BASE) - UCHAR flg_be_adjust; - ULONG be_adjust_last_time; - -#ifdef NINTENDO_AP - NINDO_CTRL_BLOCK nindo_ctrl_block; -#endif // NINTENDO_AP // - - -#ifdef IKANOS_VX_1X0 - struct IKANOS_TX_INFO IkanosTxInfo; - struct IKANOS_TX_INFO IkanosRxInfo[MAX_MBSSID_NUM + MAX_WDS_ENTRY + MAX_APCLI_NUM + MAX_MESH_NUM]; -#endif // IKANOS_VX_1X0 // - - -#ifdef DBG_DIAGNOSE - RtmpDiagStruct DiagStruct; -#endif // DBG_DIAGNOSE // - - - UINT8 PM_FlgSuspend; - -#ifdef RT30xx -//======efuse - BOOLEAN bUseEfuse; - BOOLEAN bEEPROMFile; -#endif // RT30xx // - -} RTMP_ADAPTER, *PRTMP_ADAPTER; - -// -// Cisco IAPP format -// -typedef struct _CISCO_IAPP_CONTENT_ -{ - USHORT Length; //IAPP Length - UCHAR MessageType; //IAPP type - UCHAR FunctionCode; //IAPP function type - UCHAR DestinaionMAC[MAC_ADDR_LEN]; - UCHAR SourceMAC[MAC_ADDR_LEN]; - USHORT Tag; //Tag(element IE) - Adjacent AP report - USHORT TagLength; //Length of element not including 4 byte header - UCHAR OUI[4]; //0x00, 0x40, 0x96, 0x00 - UCHAR PreviousAP[MAC_ADDR_LEN]; //MAC Address of access point - USHORT Channel; - USHORT SsidLen; - UCHAR Ssid[MAX_LEN_OF_SSID]; - USHORT Seconds; //Seconds that the client has been disassociated. -} CISCO_IAPP_CONTENT, *PCISCO_IAPP_CONTENT; - -#define DELAYINTMASK 0x0003fffb -#define INTMASK 0x0003fffb -#define IndMask 0x0003fffc -#define RxINT 0x00000005 // Delayed Rx or indivi rx -#define TxDataInt 0x000000fa // Delayed Tx or indivi tx -#define TxMgmtInt 0x00000102 // Delayed Tx or indivi tx -#define TxCoherent 0x00020000 // tx coherent -#define RxCoherent 0x00010000 // rx coherent -#define McuCommand 0x00000200 // mcu -#define PreTBTTInt 0x00001000 // Pre-TBTT interrupt -#define TBTTInt 0x00000800 // TBTT interrupt -#define GPTimeOutInt 0x00008000 // GPtimeout interrupt -#define AutoWakeupInt 0x00004000 // AutoWakeupInt interrupt -#define FifoStaFullInt 0x00002000 // fifo statistics full interrupt - - -typedef struct _RX_BLK_ -{ -// RXD_STRUC RxD; // sample - RT28XX_RXD_STRUC RxD; - PRXWI_STRUC pRxWI; - PHEADER_802_11 pHeader; - PNDIS_PACKET pRxPacket; - UCHAR *pData; - USHORT DataSize; - USHORT Flags; - UCHAR UserPriority; // for calculate TKIP MIC using -} RX_BLK; - - -#define RX_BLK_SET_FLAG(_pRxBlk, _flag) (_pRxBlk->Flags |= _flag) -#define RX_BLK_TEST_FLAG(_pRxBlk, _flag) (_pRxBlk->Flags & _flag) -#define RX_BLK_CLEAR_FLAG(_pRxBlk, _flag) (_pRxBlk->Flags &= ~(_flag)) - - -#define fRX_WDS 0x0001 -#define fRX_AMSDU 0x0002 -#define fRX_ARALINK 0x0004 -#define fRX_HTC 0x0008 -#define fRX_PAD 0x0010 -#define fRX_AMPDU 0x0020 -#define fRX_QOS 0x0040 -#define fRX_INFRA 0x0080 -#define fRX_EAP 0x0100 -#define fRX_MESH 0x0200 -#define fRX_APCLI 0x0400 -#define fRX_DLS 0x0800 -#define fRX_WPI 0x1000 - -#define LENGTH_AMSDU_SUBFRAMEHEAD 14 -#define LENGTH_ARALINK_SUBFRAMEHEAD 14 -#define LENGTH_ARALINK_HEADER_FIELD 2 - -#define TX_UNKOWN_FRAME 0x00 -#define TX_MCAST_FRAME 0x01 -#define TX_LEGACY_FRAME 0x02 -#define TX_AMPDU_FRAME 0x04 -#define TX_AMSDU_FRAME 0x08 -#define TX_RALINK_FRAME 0x10 -#define TX_FRAG_FRAME 0x20 - - -// Currently the sizeof(TX_BLK) is 148 bytes. -typedef struct _TX_BLK_ -{ - UCHAR QueIdx; - UCHAR TxFrameType; // Indicate the Transmission type of the all frames in one batch - UCHAR TotalFrameNum; // Total frame number want to send-out in one batch - USHORT TotalFragNum; // Total frame fragments required in one batch - USHORT TotalFrameLen; // Total length of all frames want to send-out in one batch - - QUEUE_HEADER TxPacketList; - MAC_TABLE_ENTRY *pMacEntry; // NULL: packet with 802.11 RA field is multicast/broadcast address - HTTRANSMIT_SETTING *pTransmit; - - // Following structure used for the characteristics of a specific packet. - PNDIS_PACKET pPacket; - PUCHAR pSrcBufHeader; // Reference to the head of sk_buff->data - PUCHAR pSrcBufData; // Reference to the sk_buff->data, will changed depends on hanlding progresss - UINT SrcBufLen; // Length of packet payload which not including Layer 2 header - PUCHAR pExtraLlcSnapEncap; // NULL means no extra LLC/SNAP is required - UCHAR HeaderBuf[80]; // TempBuffer for TX_INFO + TX_WI + 802.11 Header + padding + AMSDU SubHeader + LLC/SNAP - UCHAR MpduHeaderLen; // 802.11 header length NOT including the padding - UCHAR HdrPadLen; // recording Header Padding Length; - UCHAR apidx; // The interface associated to this packet - UCHAR Wcid; // The MAC entry associated to this packet - UCHAR UserPriority; // priority class of packet - UCHAR FrameGap; // what kind of IFS this packet use - UCHAR MpduReqNum; // number of fragments of this frame - UCHAR TxRate; // TODO: Obsoleted? Should change to MCS? - UCHAR CipherAlg; // cipher alogrithm - PCIPHER_KEY pKey; - - - - USHORT Flags; //See following definitions for detail. - - //YOU SHOULD NOT TOUCH IT! Following parameters are used for hardware-depended layer. - ULONG Priv; // Hardware specific value saved in here. -} TX_BLK, *PTX_BLK; - - -#define fTX_bRtsRequired 0x0001 // Indicate if need send RTS frame for protection. Not used in RT2860/RT2870. -#define fTX_bAckRequired 0x0002 // the packet need ack response -#define fTX_bPiggyBack 0x0004 // Legacy device use Piggback or not -#define fTX_bHTRate 0x0008 // allow to use HT rate -//#define fTX_bForceLowRate 0x0010 // force to use Low Rate -#define fTX_bForceNonQoS 0x0010 // force to transmit frame without WMM-QoS in HT mode -#define fTX_bAllowFrag 0x0020 // allow to fragment the packet, A-MPDU, A-MSDU, A-Ralink is not allowed to fragment -#define fTX_bMoreData 0x0040 // there are more data packets in PowerSave Queue -#define fTX_bWMM 0x0080 // QOS Data - -#define fTX_bClearEAPFrame 0x0100 - - -#ifdef CONFIG_STA_SUPPORT -#endif // CONFIG_STA_SUPPORT // - - - -#define TX_BLK_ASSIGN_FLAG(_pTxBlk, _flag, value) \ - do { \ - if (value) \ - (_pTxBlk->Flags |= _flag) \ - else \ - (_pTxBlk->Flags &= ~(_flag)) \ - }while(0) - -#define TX_BLK_SET_FLAG(_pTxBlk, _flag) (_pTxBlk->Flags |= _flag) -#define TX_BLK_TEST_FLAG(_pTxBlk, _flag) (((_pTxBlk->Flags & _flag) == _flag) ? 1 : 0) -#define TX_BLK_CLEAR_FLAG(_pTxBlk, _flag) (_pTxBlk->Flags &= ~(_flag)) - - - - - -//------------------------------------------------------------------------------------------ - - - -#ifdef RT_BIG_ENDIAN -static inline VOID WriteBackToDescriptor( - IN PUCHAR Dest, - IN PUCHAR Src, - IN BOOLEAN DoEncrypt, - IN ULONG DescriptorType) -{ - UINT32 *p1, *p2; - - p1 = ((UINT32 *)Dest); - p2 = ((UINT32 *)Src); - - *p1 = *p2; - *(p1+2) = *(p2+2); - *(p1+3) = *(p2+3); - *(p1+1) = *(p2+1); // Word 1; this must be written back last -} - -/* - ======================================================================== - - Routine Description: - Endian conversion of Tx/Rx descriptor . - - Arguments: - pAd Pointer to our adapter - pData Pointer to Tx/Rx descriptor - DescriptorType Direction of the frame - - Return Value: - None - - Note: - Call this function when read or update descriptor - ======================================================================== -*/ -static inline VOID RTMPWIEndianChange( - IN PUCHAR pData, - IN ULONG DescriptorType) -{ - int size; - int i; - - size = ((DescriptorType == TYPE_TXWI) ? TXWI_SIZE : RXWI_SIZE); - - if(DescriptorType == TYPE_TXWI) - { - *((UINT32 *)(pData)) = SWAP32(*((UINT32 *)(pData))); // Byte 0~3 - *((UINT32 *)(pData + 4)) = SWAP32(*((UINT32 *)(pData+4))); // Byte 4~7 - } - else - { - for(i=0; i < size/4 ; i++) - *(((UINT32 *)pData) +i) = SWAP32(*(((UINT32 *)pData)+i)); - } -} - -/* - ======================================================================== - - Routine Description: - Endian conversion of Tx/Rx descriptor . - - Arguments: - pAd Pointer to our adapter - pData Pointer to Tx/Rx descriptor - DescriptorType Direction of the frame - - Return Value: - None - - Note: - Call this function when read or update descriptor - ======================================================================== -*/ - -#ifdef RT2870 -static inline VOID RTMPDescriptorEndianChange( - IN PUCHAR pData, - IN ULONG DescriptorType) -{ - *((UINT32 *)(pData)) = SWAP32(*((UINT32 *)(pData))); -} -#endif // RT2870 // -/* - ======================================================================== - - Routine Description: - Endian conversion of all kinds of 802.11 frames . - - Arguments: - pAd Pointer to our adapter - pData Pointer to the 802.11 frame structure - Dir Direction of the frame - FromRxDoneInt Caller is from RxDone interrupt - - Return Value: - None - - Note: - Call this function when read or update buffer data - ======================================================================== -*/ -static inline VOID RTMPFrameEndianChange( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pData, - IN ULONG Dir, - IN BOOLEAN FromRxDoneInt) -{ - PHEADER_802_11 pFrame; - PUCHAR pMacHdr; - - // swab 16 bit fields - Frame Control field - if(Dir == DIR_READ) - { - *(USHORT *)pData = SWAP16(*(USHORT *)pData); - } - - pFrame = (PHEADER_802_11) pData; - pMacHdr = (PUCHAR) pFrame; - - // swab 16 bit fields - Duration/ID field - *(USHORT *)(pMacHdr + 2) = SWAP16(*(USHORT *)(pMacHdr + 2)); - - // swab 16 bit fields - Sequence Control field - *(USHORT *)(pMacHdr + 22) = SWAP16(*(USHORT *)(pMacHdr + 22)); - - if(pFrame->FC.Type == BTYPE_MGMT) - { - switch(pFrame->FC.SubType) - { - case SUBTYPE_ASSOC_REQ: - case SUBTYPE_REASSOC_REQ: - // swab 16 bit fields - CapabilityInfo field - pMacHdr += sizeof(HEADER_802_11); - *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); - - // swab 16 bit fields - Listen Interval field - pMacHdr += 2; - *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); - break; - - case SUBTYPE_ASSOC_RSP: - case SUBTYPE_REASSOC_RSP: - // swab 16 bit fields - CapabilityInfo field - pMacHdr += sizeof(HEADER_802_11); - *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); - - // swab 16 bit fields - Status Code field - pMacHdr += 2; - *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); - - // swab 16 bit fields - AID field - pMacHdr += 2; - *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); - break; - - case SUBTYPE_AUTH: - // If from APHandleRxDoneInterrupt routine, it is still a encrypt format. - // The convertion is delayed to RTMPHandleDecryptionDoneInterrupt. - if(!FromRxDoneInt && pFrame->FC.Wep == 1) - break; - else - { - // swab 16 bit fields - Auth Alg No. field - pMacHdr += sizeof(HEADER_802_11); - *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); - - // swab 16 bit fields - Auth Seq No. field - pMacHdr += 2; - *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); - - // swab 16 bit fields - Status Code field - pMacHdr += 2; - *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); - } - break; - - case SUBTYPE_BEACON: - case SUBTYPE_PROBE_RSP: - // swab 16 bit fields - BeaconInterval field - pMacHdr += (sizeof(HEADER_802_11) + TIMESTAMP_LEN); - *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); - - // swab 16 bit fields - CapabilityInfo field - pMacHdr += sizeof(USHORT); - *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); - break; - - case SUBTYPE_DEAUTH: - case SUBTYPE_DISASSOC: - // swab 16 bit fields - Reason code field - pMacHdr += sizeof(HEADER_802_11); - *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); - break; - } - } - else if( pFrame->FC.Type == BTYPE_DATA ) - { - } - else if(pFrame->FC.Type == BTYPE_CNTL) - { - switch(pFrame->FC.SubType) - { - case SUBTYPE_BLOCK_ACK_REQ: - { - PFRAME_BA_REQ pBAReq = (PFRAME_BA_REQ)pFrame; - *(USHORT *)(&pBAReq->BARControl) = SWAP16(*(USHORT *)(&pBAReq->BARControl)); - pBAReq->BAStartingSeq.word = SWAP16(pBAReq->BAStartingSeq.word); - } - break; - case SUBTYPE_BLOCK_ACK: - // For Block Ack packet, the HT_CONTROL field is in the same offset with Addr3 - *(UINT32 *)(&pFrame->Addr3[0]) = SWAP32(*(UINT32 *)(&pFrame->Addr3[0])); - break; - - case SUBTYPE_ACK: - //For ACK packet, the HT_CONTROL field is in the same offset with Addr2 - *(UINT32 *)(&pFrame->Addr2[0])= SWAP32(*(UINT32 *)(&pFrame->Addr2[0])); - break; - } - } - else - { - DBGPRINT(RT_DEBUG_ERROR,("Invalid Frame Type!!!\n")); - } - - // swab 16 bit fields - Frame Control - if(Dir == DIR_WRITE) - { - *(USHORT *)pData = SWAP16(*(USHORT *)pData); - } -} -#endif // RT_BIG_ENDIAN // - - -static inline VOID ConvertMulticastIP2MAC( - IN PUCHAR pIpAddr, - IN PUCHAR *ppMacAddr, - IN UINT16 ProtoType) -{ - if (pIpAddr == NULL) - return; - - if (ppMacAddr == NULL || *ppMacAddr == NULL) - return; - - switch (ProtoType) - { - case ETH_P_IPV6: -// memset(*ppMacAddr, 0, ETH_LENGTH_OF_ADDRESS); - *(*ppMacAddr) = 0x33; - *(*ppMacAddr + 1) = 0x33; - *(*ppMacAddr + 2) = pIpAddr[12]; - *(*ppMacAddr + 3) = pIpAddr[13]; - *(*ppMacAddr + 4) = pIpAddr[14]; - *(*ppMacAddr + 5) = pIpAddr[15]; - break; - - case ETH_P_IP: - default: -// memset(*ppMacAddr, 0, ETH_LENGTH_OF_ADDRESS); - *(*ppMacAddr) = 0x01; - *(*ppMacAddr + 1) = 0x00; - *(*ppMacAddr + 2) = 0x5e; - *(*ppMacAddr + 3) = pIpAddr[1] & 0x7f; - *(*ppMacAddr + 4) = pIpAddr[2]; - *(*ppMacAddr + 5) = pIpAddr[3]; - break; - } - - return; -} - -BOOLEAN RTMPCheckForHang( - IN NDIS_HANDLE MiniportAdapterContext - ); - -VOID RTMPHalt( - IN NDIS_HANDLE MiniportAdapterContext - ); - -// -// Private routines in rtmp_init.c -// -NDIS_STATUS RTMPAllocAdapterBlock( - IN PVOID handle, - OUT PRTMP_ADAPTER *ppAdapter - ); - -NDIS_STATUS RTMPAllocTxRxRingMemory( - IN PRTMP_ADAPTER pAd - ); - -NDIS_STATUS RTMPFindAdapter( - IN PRTMP_ADAPTER pAd, - IN NDIS_HANDLE WrapperConfigurationContext - ); - -NDIS_STATUS RTMPReadParametersHook( - IN PRTMP_ADAPTER pAd - ); - -VOID RTMPFreeAdapter( - IN PRTMP_ADAPTER pAd - ); - -NDIS_STATUS NICReadRegParameters( - IN PRTMP_ADAPTER pAd, - IN NDIS_HANDLE WrapperConfigurationContext - ); - -#ifdef RT30xx -VOID NICInitRT30xxRFRegisters( - IN PRTMP_ADAPTER pAd); -#endif // RT30xx // - -VOID NICReadEEPROMParameters( - IN PRTMP_ADAPTER pAd, - IN PUCHAR mac_addr); - -VOID NICInitAsicFromEEPROM( - IN PRTMP_ADAPTER pAd); - -VOID NICInitTxRxRingAndBacklogQueue( - IN PRTMP_ADAPTER pAd); - -NDIS_STATUS NICInitializeAdapter( - IN PRTMP_ADAPTER pAd, - IN BOOLEAN bHardReset); - -NDIS_STATUS NICInitializeAsic( - IN PRTMP_ADAPTER pAd, - IN BOOLEAN bHardReset); - -VOID NICIssueReset( - IN PRTMP_ADAPTER pAd); - -VOID RTMPRingCleanUp( - IN PRTMP_ADAPTER pAd, - IN UCHAR RingType); - -VOID RxTest( - IN PRTMP_ADAPTER pAd); - -NDIS_STATUS DbgSendPacket( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket); - -VOID UserCfgInit( - IN PRTMP_ADAPTER pAd); - -VOID NICResetFromError( - IN PRTMP_ADAPTER pAd); - -VOID NICEraseFirmware( - IN PRTMP_ADAPTER pAd); - -NDIS_STATUS NICLoadFirmware( - IN PRTMP_ADAPTER pAd); - -NDIS_STATUS NICLoadRateSwitchingParams( - IN PRTMP_ADAPTER pAd); - -BOOLEAN NICCheckForHang( - IN PRTMP_ADAPTER pAd); - -VOID NICUpdateFifoStaCounters( - IN PRTMP_ADAPTER pAd); - -VOID NICUpdateRawCounters( - IN PRTMP_ADAPTER pAd); - -ULONG RTMPNotAllZero( - IN PVOID pSrc1, - IN ULONG Length); - -VOID RTMPZeroMemory( - IN PVOID pSrc, - IN ULONG Length); - -ULONG RTMPCompareMemory( - IN PVOID pSrc1, - IN PVOID pSrc2, - IN ULONG Length); - -VOID RTMPMoveMemory( - OUT PVOID pDest, - IN PVOID pSrc, - IN ULONG Length); - -VOID AtoH( - char *src, - UCHAR *dest, - int destlen); - -UCHAR BtoH( - char ch); - -VOID RTMPPatchMacBbpBug( - IN PRTMP_ADAPTER pAd); - -VOID RTMPPatchCardBus( - IN PRTMP_ADAPTER pAdapter); - -VOID RTMPPatchRalinkCardBus( - IN PRTMP_ADAPTER pAdapter, - IN ULONG Bus); - -ULONG RTMPReadCBConfig( - IN ULONG Bus, - IN ULONG Slot, - IN ULONG Func, - IN ULONG Offset); - -VOID RTMPWriteCBConfig( - IN ULONG Bus, - IN ULONG Slot, - IN ULONG Func, - IN ULONG Offset, - IN ULONG Value); - -VOID RTMPInitTimer( - IN PRTMP_ADAPTER pAd, - IN PRALINK_TIMER_STRUCT pTimer, - IN PVOID pTimerFunc, - IN PVOID pData, - IN BOOLEAN Repeat); - -VOID RTMPSetTimer( - IN PRALINK_TIMER_STRUCT pTimer, - IN ULONG Value); - - -VOID RTMPModTimer( - IN PRALINK_TIMER_STRUCT pTimer, - IN ULONG Value); - -VOID RTMPCancelTimer( - IN PRALINK_TIMER_STRUCT pTimer, - OUT BOOLEAN *pCancelled); - -VOID RTMPSetLED( - IN PRTMP_ADAPTER pAd, - IN UCHAR Status); - -VOID RTMPSetSignalLED( - IN PRTMP_ADAPTER pAd, - IN NDIS_802_11_RSSI Dbm); - -VOID RTMPEnableRxTx( - IN PRTMP_ADAPTER pAd); - -// -// prototype in action.c -// -VOID ActionStateMachineInit( - IN PRTMP_ADAPTER pAd, - IN STATE_MACHINE *S, - OUT STATE_MACHINE_FUNC Trans[]); - -VOID MlmeADDBAAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID MlmeDELBAAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID MlmeDLSAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID MlmeInvalidAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID MlmeQOSAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -#ifdef DOT11_N_SUPPORT -VOID PeerAddBAReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID PeerAddBARspAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID PeerDelBAAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID PeerBAAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); -#endif // DOT11_N_SUPPORT // - -VOID SendPSMPAction( - IN PRTMP_ADAPTER pAd, - IN UCHAR Wcid, - IN UCHAR Psmp); - - -#ifdef DOT11N_DRAFT3 -VOID SendBSS2040CoexistMgmtAction( - IN PRTMP_ADAPTER pAd, - IN UCHAR Wcid, - IN UCHAR apidx, - IN UCHAR InfoReq); - -VOID SendNotifyBWActionFrame( - IN PRTMP_ADAPTER pAd, - IN UCHAR Wcid, - IN UCHAR apidx); - -BOOLEAN ChannelSwitchSanityCheck( - IN PRTMP_ADAPTER pAd, - IN UCHAR Wcid, - IN UCHAR NewChannel, - IN UCHAR Secondary); - -VOID ChannelSwitchAction( - IN PRTMP_ADAPTER pAd, - IN UCHAR Wcid, - IN UCHAR Channel, - IN UCHAR Secondary); - -ULONG BuildIntolerantChannelRep( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDest); - -VOID Update2040CoexistFrameAndNotify( - IN PRTMP_ADAPTER pAd, - IN UCHAR Wcid, - IN BOOLEAN bAddIntolerantCha); - -VOID Send2040CoexistAction( - IN PRTMP_ADAPTER pAd, - IN UCHAR Wcid, - IN BOOLEAN bAddIntolerantCha); -#endif // DOT11N_DRAFT3 // - -VOID PeerRMAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID PeerPublicAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -#ifdef CONFIG_STA_SUPPORT -VOID StaPublicAction( - IN PRTMP_ADAPTER pAd, - IN UCHAR Bss2040Coexist); -#endif // CONFIG_STA_SUPPORT // - - -VOID PeerBSSTranAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -#ifdef DOT11_N_SUPPORT -VOID PeerHTAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); -#endif // DOT11_N_SUPPORT // - -VOID PeerQOSAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -#ifdef QOS_DLS_SUPPORT -VOID PeerDLSAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); -#endif // QOS_DLS_SUPPORT // - -#ifdef CONFIG_STA_SUPPORT -#ifdef QOS_DLS_SUPPORT -VOID DlsParmFill( - IN PRTMP_ADAPTER pAd, - IN OUT MLME_DLS_REQ_STRUCT *pDlsReq, - IN PRT_802_11_DLS pDls, - IN USHORT reason); -#endif // QOS_DLS_SUPPORT // -#endif // CONFIG_STA_SUPPORT // - -#ifdef DOT11_N_SUPPORT -VOID RECBATimerTimeout( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); - -VOID ORIBATimerTimeout( - IN PRTMP_ADAPTER pAd); - -VOID SendRefreshBAR( - IN PRTMP_ADAPTER pAd, - IN MAC_TABLE_ENTRY *pEntry); -#endif // DOT11_N_SUPPORT // - -VOID ActHeaderInit( - IN PRTMP_ADAPTER pAd, - IN OUT PHEADER_802_11 pHdr80211, - IN PUCHAR Addr1, - IN PUCHAR Addr2, - IN PUCHAR Addr3); - -VOID BarHeaderInit( - IN PRTMP_ADAPTER pAd, - IN OUT PFRAME_BAR pCntlBar, - IN PUCHAR pDA, - IN PUCHAR pSA); - -VOID InsertActField( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pFrameBuf, - OUT PULONG pFrameLen, - IN UINT8 Category, - IN UINT8 ActCode); - -BOOLEAN QosBADataParse( - IN PRTMP_ADAPTER pAd, - IN BOOLEAN bAMSDU, - IN PUCHAR p8023Header, - IN UCHAR WCID, - IN UCHAR TID, - IN USHORT Sequence, - IN UCHAR DataOffset, - IN USHORT Datasize, - IN UINT CurRxIndex); - -#ifdef DOT11_N_SUPPORT -BOOLEAN CntlEnqueueForRecv( - IN PRTMP_ADAPTER pAd, - IN ULONG Wcid, - IN ULONG MsgLen, - IN PFRAME_BA_REQ pMsg); - -VOID BaAutoManSwitch( - IN PRTMP_ADAPTER pAd); -#endif // DOT11_N_SUPPORT // - -VOID HTIOTCheck( - IN PRTMP_ADAPTER pAd, - IN UCHAR BatRecIdx); - -// -// Private routines in rtmp_data.c -// -BOOLEAN RTMPHandleRxDoneInterrupt( - IN PRTMP_ADAPTER pAd); - -VOID RTMPHandleTxDoneInterrupt( - IN PRTMP_ADAPTER pAd); - -BOOLEAN RTMPHandleTxRingDmaDoneInterrupt( - IN PRTMP_ADAPTER pAd, - IN INT_SOURCE_CSR_STRUC TxRingBitmap); - -VOID RTMPHandleMgmtRingDmaDoneInterrupt( - IN PRTMP_ADAPTER pAd); - -VOID RTMPHandleTBTTInterrupt( - IN PRTMP_ADAPTER pAd); - -VOID RTMPHandlePreTBTTInterrupt( - IN PRTMP_ADAPTER pAd); - -void RTMPHandleTwakeupInterrupt( - IN PRTMP_ADAPTER pAd); - -VOID RTMPHandleRxCoherentInterrupt( - IN PRTMP_ADAPTER pAd); - -BOOLEAN TxFrameIsAggregatible( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pPrevAddr1, - IN PUCHAR p8023hdr); - -BOOLEAN PeerIsAggreOn( - IN PRTMP_ADAPTER pAd, - IN ULONG TxRate, - IN PMAC_TABLE_ENTRY pMacEntry); - -NDIS_STATUS Sniff2BytesFromNdisBuffer( - IN PNDIS_BUFFER pFirstBuffer, - IN UCHAR DesiredOffset, - OUT PUCHAR pByte0, - OUT PUCHAR pByte1); - -NDIS_STATUS STASendPacket( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket); - -VOID STASendPackets( - IN NDIS_HANDLE MiniportAdapterContext, - IN PPNDIS_PACKET ppPacketArray, - IN UINT NumberOfPackets); - -VOID RTMPDeQueuePacket( - IN PRTMP_ADAPTER pAd, - IN BOOLEAN bIntContext, - IN UCHAR QueIdx, - IN UCHAR Max_Tx_Packets); - -NDIS_STATUS RTMPHardTransmit( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket, - IN UCHAR QueIdx, - OUT PULONG pFreeTXDLeft); - -NDIS_STATUS STAHardTransmit( - IN PRTMP_ADAPTER pAd, - IN TX_BLK *pTxBlk, - IN UCHAR QueIdx); - -VOID STARxEAPOLFrameIndicate( - IN PRTMP_ADAPTER pAd, - IN MAC_TABLE_ENTRY *pEntry, - IN RX_BLK *pRxBlk, - IN UCHAR FromWhichBSSID); - -NDIS_STATUS RTMPFreeTXDRequest( - IN PRTMP_ADAPTER pAd, - IN UCHAR RingType, - IN UCHAR NumberRequired, - IN PUCHAR FreeNumberIs); - -NDIS_STATUS MlmeHardTransmit( - IN PRTMP_ADAPTER pAd, - IN UCHAR QueIdx, - IN PNDIS_PACKET pPacket); - -NDIS_STATUS MlmeHardTransmitMgmtRing( - IN PRTMP_ADAPTER pAd, - IN UCHAR QueIdx, - IN PNDIS_PACKET pPacket); - -NDIS_STATUS MlmeHardTransmitTxRing( - IN PRTMP_ADAPTER pAd, - IN UCHAR QueIdx, - IN PNDIS_PACKET pPacket); - -USHORT RTMPCalcDuration( - IN PRTMP_ADAPTER pAd, - IN UCHAR Rate, - IN ULONG Size); - -VOID RTMPWriteTxWI( - IN PRTMP_ADAPTER pAd, - IN PTXWI_STRUC pTxWI, - IN BOOLEAN FRAG, - IN BOOLEAN CFACK, - IN BOOLEAN InsTimestamp, - IN BOOLEAN AMPDU, - IN BOOLEAN Ack, - IN BOOLEAN NSeq, // HW new a sequence. - IN UCHAR BASize, - IN UCHAR WCID, - IN ULONG Length, - IN UCHAR PID, - IN UCHAR TID, - IN UCHAR TxRate, - IN UCHAR Txopmode, - IN BOOLEAN CfAck, - IN HTTRANSMIT_SETTING *pTransmit); - - -VOID RTMPWriteTxWI_Data( - IN PRTMP_ADAPTER pAd, - IN OUT PTXWI_STRUC pTxWI, - IN TX_BLK *pTxBlk); - - -VOID RTMPWriteTxWI_Cache( - IN PRTMP_ADAPTER pAd, - IN OUT PTXWI_STRUC pTxWI, - IN TX_BLK *pTxBlk); - -VOID RTMPWriteTxDescriptor( - IN PRTMP_ADAPTER pAd, - IN PTXD_STRUC pTxD, - IN BOOLEAN bWIV, - IN UCHAR QSEL); - -VOID RTMPSuspendMsduTransmission( - IN PRTMP_ADAPTER pAd); - -VOID RTMPResumeMsduTransmission( - IN PRTMP_ADAPTER pAd); - -NDIS_STATUS MiniportMMRequest( - IN PRTMP_ADAPTER pAd, - IN UCHAR QueIdx, - IN PUCHAR pData, - IN UINT Length); - -NDIS_STATUS MiniportDataMMRequest( - IN PRTMP_ADAPTER pAd, - IN UCHAR QueIdx, - IN PUCHAR pData, - IN UINT Length); - -VOID RTMPSendNullFrame( - IN PRTMP_ADAPTER pAd, - IN UCHAR TxRate, - IN BOOLEAN bQosNull); - -VOID RTMPSendDisassociationFrame( - IN PRTMP_ADAPTER pAd); - -VOID RTMPSendRTSFrame( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDA, - IN unsigned int NextMpduSize, - IN UCHAR TxRate, - IN UCHAR RTSRate, - IN USHORT AckDuration, - IN UCHAR QueIdx, - IN UCHAR FrameGap); - - -NDIS_STATUS RTMPApplyPacketFilter( - IN PRTMP_ADAPTER pAd, - IN PRT28XX_RXD_STRUC pRxD, - IN PHEADER_802_11 pHeader); - -PQUEUE_HEADER RTMPCheckTxSwQueue( - IN PRTMP_ADAPTER pAd, - OUT UCHAR *QueIdx); - -#ifdef CONFIG_STA_SUPPORT -VOID RTMPReportMicError( - IN PRTMP_ADAPTER pAd, - IN PCIPHER_KEY pWpaKey); - -VOID WpaMicFailureReportFrame( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID WpaDisassocApAndBlockAssoc( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); -#endif // CONFIG_STA_SUPPORT // - -NDIS_STATUS RTMPCloneNdisPacket( - IN PRTMP_ADAPTER pAd, - IN BOOLEAN pInsAMSDUHdr, - IN PNDIS_PACKET pInPacket, - OUT PNDIS_PACKET *ppOutPacket); - -NDIS_STATUS RTMPAllocateNdisPacket( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET *pPacket, - IN PUCHAR pHeader, - IN UINT HeaderLen, - IN PUCHAR pData, - IN UINT DataLen); - -VOID RTMPFreeNdisPacket( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket); - -BOOLEAN RTMPFreeTXDUponTxDmaDone( - IN PRTMP_ADAPTER pAd, - IN UCHAR QueIdx); - -BOOLEAN RTMPCheckDHCPFrame( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket); - - -BOOLEAN RTMPCheckEtherType( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket); - - -VOID RTMPCckBbpTuning( - IN PRTMP_ADAPTER pAd, - IN UINT TxRate); - -// -// Private routines in rtmp_wep.c -// -VOID RTMPInitWepEngine( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pKey, - IN UCHAR KeyId, - IN UCHAR KeyLen, - IN PUCHAR pDest); - -VOID RTMPEncryptData( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pSrc, - IN PUCHAR pDest, - IN UINT Len); - -BOOLEAN RTMPDecryptData( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR pSrc, - IN UINT Len, - IN UINT idx); - -BOOLEAN RTMPSoftDecryptWEP( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pData, - IN ULONG DataByteCnt, - IN PCIPHER_KEY pGroupKey); - -VOID RTMPSetICV( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDest); - -VOID ARCFOUR_INIT( - IN PARCFOURCONTEXT Ctx, - IN PUCHAR pKey, - IN UINT KeyLen); - -UCHAR ARCFOUR_BYTE( - IN PARCFOURCONTEXT Ctx); - -VOID ARCFOUR_DECRYPT( - IN PARCFOURCONTEXT Ctx, - IN PUCHAR pDest, - IN PUCHAR pSrc, - IN UINT Len); - -VOID ARCFOUR_ENCRYPT( - IN PARCFOURCONTEXT Ctx, - IN PUCHAR pDest, - IN PUCHAR pSrc, - IN UINT Len); - -VOID WPAARCFOUR_ENCRYPT( - IN PARCFOURCONTEXT Ctx, - IN PUCHAR pDest, - IN PUCHAR pSrc, - IN UINT Len); - -UINT RTMP_CALC_FCS32( - IN UINT Fcs, - IN PUCHAR Cp, - IN INT Len); - -// -// MLME routines -// - -// Asic/RF/BBP related functions - -VOID AsicAdjustTxPower( - IN PRTMP_ADAPTER pAd); - -VOID AsicUpdateProtect( - IN PRTMP_ADAPTER pAd, - IN USHORT OperaionMode, - IN UCHAR SetMask, - IN BOOLEAN bDisableBGProtect, - IN BOOLEAN bNonGFExist); - -VOID AsicSwitchChannel( - IN PRTMP_ADAPTER pAd, - IN UCHAR Channel, - IN BOOLEAN bScan); - -VOID AsicLockChannel( - IN PRTMP_ADAPTER pAd, - IN UCHAR Channel) ; - -VOID AsicAntennaSelect( - IN PRTMP_ADAPTER pAd, - IN UCHAR Channel); - -VOID AsicAntennaSetting( - IN PRTMP_ADAPTER pAd, - IN ABGBAND_STATE BandState); - -VOID AsicRfTuningExec( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); - -#ifdef CONFIG_STA_SUPPORT -VOID AsicSleepThenAutoWakeup( - IN PRTMP_ADAPTER pAd, - IN USHORT TbttNumToNextWakeUp); - -VOID AsicForceSleep( - IN PRTMP_ADAPTER pAd); - -VOID AsicForceWakeup( - IN PRTMP_ADAPTER pAd, - IN BOOLEAN bFromTx); -#endif // CONFIG_STA_SUPPORT // - -VOID AsicSetBssid( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pBssid); - -VOID AsicSetMcastWC( - IN PRTMP_ADAPTER pAd); - -VOID AsicDelWcidTab( - IN PRTMP_ADAPTER pAd, - IN UCHAR Wcid); - -VOID AsicEnableRDG( - IN PRTMP_ADAPTER pAd); - -VOID AsicDisableRDG( - IN PRTMP_ADAPTER pAd); - -VOID AsicDisableSync( - IN PRTMP_ADAPTER pAd); - -VOID AsicEnableBssSync( - IN PRTMP_ADAPTER pAd); - -VOID AsicEnableIbssSync( - IN PRTMP_ADAPTER pAd); - -VOID AsicSetEdcaParm( - IN PRTMP_ADAPTER pAd, - IN PEDCA_PARM pEdcaParm); - -VOID AsicSetSlotTime( - IN PRTMP_ADAPTER pAd, - IN BOOLEAN bUseShortSlotTime); - -VOID AsicAddSharedKeyEntry( - IN PRTMP_ADAPTER pAd, - IN UCHAR BssIndex, - IN UCHAR KeyIdx, - IN UCHAR CipherAlg, - IN PUCHAR pKey, - IN PUCHAR pTxMic, - IN PUCHAR pRxMic); - -VOID AsicRemoveSharedKeyEntry( - IN PRTMP_ADAPTER pAd, - IN UCHAR BssIndex, - IN UCHAR KeyIdx); - -VOID AsicUpdateWCIDAttribute( - IN PRTMP_ADAPTER pAd, - IN USHORT WCID, - IN UCHAR BssIndex, - IN UCHAR CipherAlg, - IN BOOLEAN bUsePairewiseKeyTable); - -VOID AsicUpdateWCIDIVEIV( - IN PRTMP_ADAPTER pAd, - IN USHORT WCID, - IN ULONG uIV, - IN ULONG uEIV); - -VOID AsicUpdateRxWCIDTable( - IN PRTMP_ADAPTER pAd, - IN USHORT WCID, - IN PUCHAR pAddr); - -VOID AsicAddKeyEntry( - IN PRTMP_ADAPTER pAd, - IN USHORT WCID, - IN UCHAR BssIndex, - IN UCHAR KeyIdx, - IN PCIPHER_KEY pCipherKey, - IN BOOLEAN bUsePairewiseKeyTable, - IN BOOLEAN bTxKey); - -VOID AsicAddPairwiseKeyEntry( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pAddr, - IN UCHAR WCID, - IN CIPHER_KEY *pCipherKey); - -VOID AsicRemovePairwiseKeyEntry( - IN PRTMP_ADAPTER pAd, - IN UCHAR BssIdx, - IN UCHAR Wcid); - -BOOLEAN AsicSendCommandToMcu( - IN PRTMP_ADAPTER pAd, - IN UCHAR Command, - IN UCHAR Token, - IN UCHAR Arg0, - IN UCHAR Arg1); - - -VOID MacAddrRandomBssid( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pAddr); - -VOID MgtMacHeaderInit( - IN PRTMP_ADAPTER pAd, - IN OUT PHEADER_802_11 pHdr80211, - IN UCHAR SubType, - IN UCHAR ToDs, - IN PUCHAR pDA, - IN PUCHAR pBssid); - -VOID MlmeRadioOff( - IN PRTMP_ADAPTER pAd); - -VOID MlmeRadioOn( - IN PRTMP_ADAPTER pAd); - - -VOID BssTableInit( - IN BSS_TABLE *Tab); - -#ifdef DOT11_N_SUPPORT -VOID BATableInit( - IN PRTMP_ADAPTER pAd, - IN BA_TABLE *Tab); -#endif // DOT11_N_SUPPORT // - -ULONG BssTableSearch( - IN BSS_TABLE *Tab, - IN PUCHAR pBssid, - IN UCHAR Channel); - -ULONG BssSsidTableSearch( - IN BSS_TABLE *Tab, - IN PUCHAR pBssid, - IN PUCHAR pSsid, - IN UCHAR SsidLen, - IN UCHAR Channel); - -ULONG BssTableSearchWithSSID( - IN BSS_TABLE *Tab, - IN PUCHAR Bssid, - IN PUCHAR pSsid, - IN UCHAR SsidLen, - IN UCHAR Channel); - -VOID BssTableDeleteEntry( - IN OUT PBSS_TABLE pTab, - IN PUCHAR pBssid, - IN UCHAR Channel); - -#ifdef DOT11_N_SUPPORT -VOID BATableDeleteORIEntry( - IN OUT PRTMP_ADAPTER pAd, - IN BA_ORI_ENTRY *pBAORIEntry); - -VOID BATableDeleteRECEntry( - IN OUT PRTMP_ADAPTER pAd, - IN BA_REC_ENTRY *pBARECEntry); - -VOID BATableTearORIEntry( - IN OUT PRTMP_ADAPTER pAd, - IN UCHAR TID, - IN UCHAR Wcid, - IN BOOLEAN bForceDelete, - IN BOOLEAN ALL); - -VOID BATableTearRECEntry( - IN OUT PRTMP_ADAPTER pAd, - IN UCHAR TID, - IN UCHAR WCID, - IN BOOLEAN ALL); -#endif // DOT11_N_SUPPORT // - -VOID BssEntrySet( - IN PRTMP_ADAPTER pAd, - OUT PBSS_ENTRY pBss, - IN PUCHAR pBssid, - IN CHAR Ssid[], - IN UCHAR SsidLen, - IN UCHAR BssType, - IN USHORT BeaconPeriod, - IN PCF_PARM CfParm, - IN USHORT AtimWin, - IN USHORT CapabilityInfo, - IN UCHAR SupRate[], - IN UCHAR SupRateLen, - IN UCHAR ExtRate[], - IN UCHAR ExtRateLen, - IN HT_CAPABILITY_IE *pHtCapability, - IN ADD_HT_INFO_IE *pAddHtInfo, // AP might use this additional ht info IE - IN UCHAR HtCapabilityLen, - IN UCHAR AddHtInfoLen, - IN UCHAR NewExtChanOffset, - IN UCHAR Channel, - IN CHAR Rssi, - IN LARGE_INTEGER TimeStamp, - IN UCHAR CkipFlag, - IN PEDCA_PARM pEdcaParm, - IN PQOS_CAPABILITY_PARM pQosCapability, - IN PQBSS_LOAD_PARM pQbssLoad, - IN USHORT LengthVIE, - IN PNDIS_802_11_VARIABLE_IEs pVIE); - -ULONG BssTableSetEntry( - IN PRTMP_ADAPTER pAd, - OUT PBSS_TABLE pTab, - IN PUCHAR pBssid, - IN CHAR Ssid[], - IN UCHAR SsidLen, - IN UCHAR BssType, - IN USHORT BeaconPeriod, - IN CF_PARM *CfParm, - IN USHORT AtimWin, - IN USHORT CapabilityInfo, - IN UCHAR SupRate[], - IN UCHAR SupRateLen, - IN UCHAR ExtRate[], - IN UCHAR ExtRateLen, - IN HT_CAPABILITY_IE *pHtCapability, - IN ADD_HT_INFO_IE *pAddHtInfo, // AP might use this additional ht info IE - IN UCHAR HtCapabilityLen, - IN UCHAR AddHtInfoLen, - IN UCHAR NewExtChanOffset, - IN UCHAR Channel, - IN CHAR Rssi, - IN LARGE_INTEGER TimeStamp, - IN UCHAR CkipFlag, - IN PEDCA_PARM pEdcaParm, - IN PQOS_CAPABILITY_PARM pQosCapability, - IN PQBSS_LOAD_PARM pQbssLoad, - IN USHORT LengthVIE, - IN PNDIS_802_11_VARIABLE_IEs pVIE); - -#ifdef DOT11_N_SUPPORT -VOID BATableInsertEntry( - IN PRTMP_ADAPTER pAd, - IN USHORT Aid, - IN USHORT TimeOutValue, - IN USHORT StartingSeq, - IN UCHAR TID, - IN UCHAR BAWinSize, - IN UCHAR OriginatorStatus, - IN BOOLEAN IsRecipient); - -#ifdef DOT11N_DRAFT3 -VOID Bss2040CoexistTimeOut( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); - - -VOID TriEventInit( - IN PRTMP_ADAPTER pAd); - -ULONG TriEventTableSetEntry( - IN PRTMP_ADAPTER pAd, - OUT TRIGGER_EVENT_TAB *Tab, - IN PUCHAR pBssid, - IN HT_CAPABILITY_IE *pHtCapability, - IN UCHAR HtCapabilityLen, - IN UCHAR RegClass, - IN UCHAR ChannelNo); - -VOID TriEventCounterMaintenance( - IN PRTMP_ADAPTER pAd); -#endif // DOT11N_DRAFT3 // -#endif // DOT11_N_SUPPORT // - -VOID BssTableSsidSort( - IN PRTMP_ADAPTER pAd, - OUT BSS_TABLE *OutTab, - IN CHAR Ssid[], - IN UCHAR SsidLen); - -VOID BssTableSortByRssi( - IN OUT BSS_TABLE *OutTab); - -VOID BssCipherParse( - IN OUT PBSS_ENTRY pBss); - -NDIS_STATUS MlmeQueueInit( - IN MLME_QUEUE *Queue); - -VOID MlmeQueueDestroy( - IN MLME_QUEUE *Queue); - -BOOLEAN MlmeEnqueue( - IN PRTMP_ADAPTER pAd, - IN ULONG Machine, - IN ULONG MsgType, - IN ULONG MsgLen, - IN VOID *Msg); - -BOOLEAN MlmeEnqueueForRecv( - IN PRTMP_ADAPTER pAd, - IN ULONG Wcid, - IN ULONG TimeStampHigh, - IN ULONG TimeStampLow, - IN UCHAR Rssi0, - IN UCHAR Rssi1, - IN UCHAR Rssi2, - IN ULONG MsgLen, - IN PVOID Msg, - IN UCHAR Signal); - - -BOOLEAN MlmeDequeue( - IN MLME_QUEUE *Queue, - OUT MLME_QUEUE_ELEM **Elem); - -VOID MlmeRestartStateMachine( - IN PRTMP_ADAPTER pAd); - -BOOLEAN MlmeQueueEmpty( - IN MLME_QUEUE *Queue); - -BOOLEAN MlmeQueueFull( - IN MLME_QUEUE *Queue); - -BOOLEAN MsgTypeSubst( - IN PRTMP_ADAPTER pAd, - IN PFRAME_802_11 pFrame, - OUT INT *Machine, - OUT INT *MsgType); - -VOID StateMachineInit( - IN STATE_MACHINE *Sm, - IN STATE_MACHINE_FUNC Trans[], - IN ULONG StNr, - IN ULONG MsgNr, - IN STATE_MACHINE_FUNC DefFunc, - IN ULONG InitState, - IN ULONG Base); - -VOID StateMachineSetAction( - IN STATE_MACHINE *S, - IN ULONG St, - ULONG Msg, - IN STATE_MACHINE_FUNC F); - -VOID StateMachinePerformAction( - IN PRTMP_ADAPTER pAd, - IN STATE_MACHINE *S, - IN MLME_QUEUE_ELEM *Elem); - -VOID Drop( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID AssocStateMachineInit( - IN PRTMP_ADAPTER pAd, - IN STATE_MACHINE *Sm, - OUT STATE_MACHINE_FUNC Trans[]); - -VOID ReassocTimeout( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); - -VOID AssocTimeout( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); - -VOID DisassocTimeout( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); - -//---------------------------------------------- -VOID MlmeDisassocReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID MlmeAssocReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID MlmeReassocReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID MlmeDisassocReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID PeerAssocRspAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID PeerReassocRspAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID PeerDisassocAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID DisassocTimeoutAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID AssocTimeoutAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID ReassocTimeoutAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID Cls3errAction( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pAddr); - -VOID SwitchBetweenWepAndCkip( - IN PRTMP_ADAPTER pAd); - -VOID InvalidStateWhenAssoc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID InvalidStateWhenReassoc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID InvalidStateWhenDisassociate( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -#ifdef RT2870 -VOID MlmeCntlConfirm( - IN PRTMP_ADAPTER pAd, - IN ULONG MsgType, - IN USHORT Msg); -#endif // RT2870 // - -VOID ComposePsPoll( - IN PRTMP_ADAPTER pAd); - -VOID ComposeNullFrame( - IN PRTMP_ADAPTER pAd); - -VOID AssocPostProc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pAddr2, - IN USHORT CapabilityInfo, - IN USHORT Aid, - IN UCHAR SupRate[], - IN UCHAR SupRateLen, - IN UCHAR ExtRate[], - IN UCHAR ExtRateLen, - IN PEDCA_PARM pEdcaParm, - IN HT_CAPABILITY_IE *pHtCapability, - IN UCHAR HtCapabilityLen, - IN ADD_HT_INFO_IE *pAddHtInfo); - -VOID AuthStateMachineInit( - IN PRTMP_ADAPTER pAd, - IN PSTATE_MACHINE sm, - OUT STATE_MACHINE_FUNC Trans[]); - -VOID AuthTimeout( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); - -VOID MlmeAuthReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID PeerAuthRspAtSeq2Action( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID PeerAuthRspAtSeq4Action( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID AuthTimeoutAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID Cls2errAction( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pAddr); - -VOID MlmeDeauthReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID InvalidStateWhenAuth( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -//============================================= - -VOID AuthRspStateMachineInit( - IN PRTMP_ADAPTER pAd, - IN PSTATE_MACHINE Sm, - IN STATE_MACHINE_FUNC Trans[]); - -VOID PeerDeauthAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID PeerAuthSimpleRspGenAndSend( - IN PRTMP_ADAPTER pAd, - IN PHEADER_802_11 pHdr80211, - IN USHORT Alg, - IN USHORT Seq, - IN USHORT Reason, - IN USHORT Status); - -// -// Private routines in dls.c -// - -#ifdef CONFIG_STA_SUPPORT -#ifdef QOS_DLS_SUPPORT -void DlsStateMachineInit( - IN PRTMP_ADAPTER pAd, - IN STATE_MACHINE *Sm, - OUT STATE_MACHINE_FUNC Trans[]); - -VOID MlmeDlsReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID PeerDlsReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID PeerDlsRspAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID MlmeDlsTearDownAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID PeerDlsTearDownAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID RTMPCheckDLSTimeOut( - IN PRTMP_ADAPTER pAd); - -BOOLEAN RTMPRcvFrameDLSCheck( - IN PRTMP_ADAPTER pAd, - IN PHEADER_802_11 pHeader, - IN ULONG Len, - IN PRT28XX_RXD_STRUC pRxD); - -INT RTMPCheckDLSFrame( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDA); - -VOID RTMPSendDLSTearDownFrame( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDA); - -NDIS_STATUS RTMPSendSTAKeyRequest( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDA); - -NDIS_STATUS RTMPSendSTAKeyHandShake( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDA); - -VOID DlsTimeoutAction( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); - -BOOLEAN MlmeDlsReqSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PRT_802_11_DLS *pDLS, - OUT PUSHORT pReason); - -INT Set_DlsEntryInfo_Display_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -MAC_TABLE_ENTRY *MacTableInsertDlsEntry( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pAddr, - IN UINT DlsEntryIdx); - -BOOLEAN MacTableDeleteDlsEntry( - IN PRTMP_ADAPTER pAd, - IN USHORT wcid, - IN PUCHAR pAddr); - -MAC_TABLE_ENTRY *DlsEntryTableLookup( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pAddr, - IN BOOLEAN bResetIdelCount); - -MAC_TABLE_ENTRY *DlsEntryTableLookupByWcid( - IN PRTMP_ADAPTER pAd, - IN UCHAR wcid, - IN PUCHAR pAddr, - IN BOOLEAN bResetIdelCount); - -INT Set_DlsAddEntry_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_DlsTearDownEntry_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); -#endif // QOS_DLS_SUPPORT // -#endif // CONFIG_STA_SUPPORT // - -#ifdef QOS_DLS_SUPPORT -BOOLEAN PeerDlsReqSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PUCHAR pDA, - OUT PUCHAR pSA, - OUT USHORT *pCapabilityInfo, - OUT USHORT *pDlsTimeout, - OUT UCHAR *pRatesLen, - OUT UCHAR Rates[], - OUT UCHAR *pHtCapabilityLen, - OUT HT_CAPABILITY_IE *pHtCapability); - -BOOLEAN PeerDlsRspSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PUCHAR pDA, - OUT PUCHAR pSA, - OUT USHORT *pCapabilityInfo, - OUT USHORT *pStatus, - OUT UCHAR *pRatesLen, - OUT UCHAR Rates[], - OUT UCHAR *pHtCapabilityLen, - OUT HT_CAPABILITY_IE *pHtCapability); - -BOOLEAN PeerDlsTearDownSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PUCHAR pDA, - OUT PUCHAR pSA, - OUT USHORT *pReason); -#endif // QOS_DLS_SUPPORT // - -//======================================== - -VOID SyncStateMachineInit( - IN PRTMP_ADAPTER pAd, - IN STATE_MACHINE *Sm, - OUT STATE_MACHINE_FUNC Trans[]); - -VOID BeaconTimeout( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); - -VOID ScanTimeout( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); - -VOID MlmeScanReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID InvalidStateWhenScan( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID InvalidStateWhenJoin( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID InvalidStateWhenStart( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID PeerBeacon( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID EnqueueProbeRequest( - IN PRTMP_ADAPTER pAd); - -BOOLEAN ScanRunning( - IN PRTMP_ADAPTER pAd); -//========================================= - -VOID MlmeCntlInit( - IN PRTMP_ADAPTER pAd, - IN STATE_MACHINE *S, - OUT STATE_MACHINE_FUNC Trans[]); - -VOID MlmeCntlMachinePerformAction( - IN PRTMP_ADAPTER pAd, - IN STATE_MACHINE *S, - IN MLME_QUEUE_ELEM *Elem); - -VOID CntlIdleProc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID CntlOidScanProc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID CntlOidSsidProc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM * Elem); - -VOID CntlOidRTBssidProc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM * Elem); - -VOID CntlMlmeRoamingProc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM * Elem); - -VOID CntlWaitDisassocProc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID CntlWaitJoinProc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID CntlWaitReassocProc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID CntlWaitStartProc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID CntlWaitAuthProc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID CntlWaitAuthProc2( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID CntlWaitAssocProc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -#ifdef QOS_DLS_SUPPORT -VOID CntlOidDLSSetupProc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); -#endif // QOS_DLS_SUPPORT // - -VOID LinkUp( - IN PRTMP_ADAPTER pAd, - IN UCHAR BssType); - -VOID LinkDown( - IN PRTMP_ADAPTER pAd, - IN BOOLEAN IsReqFromAP); - -VOID IterateOnBssTab( - IN PRTMP_ADAPTER pAd); - -VOID IterateOnBssTab2( - IN PRTMP_ADAPTER pAd);; - -VOID JoinParmFill( - IN PRTMP_ADAPTER pAd, - IN OUT MLME_JOIN_REQ_STRUCT *JoinReq, - IN ULONG BssIdx); - -VOID AssocParmFill( - IN PRTMP_ADAPTER pAd, - IN OUT MLME_ASSOC_REQ_STRUCT *AssocReq, - IN PUCHAR pAddr, - IN USHORT CapabilityInfo, - IN ULONG Timeout, - IN USHORT ListenIntv); - -VOID ScanParmFill( - IN PRTMP_ADAPTER pAd, - IN OUT MLME_SCAN_REQ_STRUCT *ScanReq, - IN CHAR Ssid[], - IN UCHAR SsidLen, - IN UCHAR BssType, - IN UCHAR ScanType); - -VOID DisassocParmFill( - IN PRTMP_ADAPTER pAd, - IN OUT MLME_DISASSOC_REQ_STRUCT *DisassocReq, - IN PUCHAR pAddr, - IN USHORT Reason); - -VOID StartParmFill( - IN PRTMP_ADAPTER pAd, - IN OUT MLME_START_REQ_STRUCT *StartReq, - IN CHAR Ssid[], - IN UCHAR SsidLen); - -VOID AuthParmFill( - IN PRTMP_ADAPTER pAd, - IN OUT MLME_AUTH_REQ_STRUCT *AuthReq, - IN PUCHAR pAddr, - IN USHORT Alg); - -VOID EnqueuePsPoll( - IN PRTMP_ADAPTER pAd); - -VOID EnqueueBeaconFrame( - IN PRTMP_ADAPTER pAd); - -VOID MlmeJoinReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID MlmeScanReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID MlmeStartReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID ScanTimeoutAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID BeaconTimeoutAtJoinAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID PeerBeaconAtScanAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID PeerBeaconAtJoinAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID PeerBeacon( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID PeerProbeReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID ScanNextChannel( - IN PRTMP_ADAPTER pAd); - -ULONG MakeIbssBeacon( - IN PRTMP_ADAPTER pAd); - -VOID CCXAdjacentAPReport( - IN PRTMP_ADAPTER pAd); - -BOOLEAN MlmeScanReqSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT UCHAR *BssType, - OUT CHAR ssid[], - OUT UCHAR *SsidLen, - OUT UCHAR *ScanType); - -BOOLEAN PeerBeaconAndProbeRspSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - IN UCHAR MsgChannel, - OUT PUCHAR pAddr2, - OUT PUCHAR pBssid, - OUT CHAR Ssid[], - OUT UCHAR *pSsidLen, - OUT UCHAR *pBssType, - OUT USHORT *pBeaconPeriod, - OUT UCHAR *pChannel, - OUT UCHAR *pNewChannel, - OUT LARGE_INTEGER *pTimestamp, - OUT CF_PARM *pCfParm, - OUT USHORT *pAtimWin, - OUT USHORT *pCapabilityInfo, - OUT UCHAR *pErp, - OUT UCHAR *pDtimCount, - OUT UCHAR *pDtimPeriod, - OUT UCHAR *pBcastFlag, - OUT UCHAR *pMessageToMe, - OUT UCHAR SupRate[], - OUT UCHAR *pSupRateLen, - OUT UCHAR ExtRate[], - OUT UCHAR *pExtRateLen, - OUT UCHAR *pCkipFlag, - OUT UCHAR *pAironetCellPowerLimit, - OUT PEDCA_PARM pEdcaParm, - OUT PQBSS_LOAD_PARM pQbssLoad, - OUT PQOS_CAPABILITY_PARM pQosCapability, - OUT ULONG *pRalinkIe, - OUT UCHAR *pHtCapabilityLen, -#ifdef CONFIG_STA_SUPPORT - OUT UCHAR *pPreNHtCapabilityLen, -#endif // CONFIG_STA_SUPPORT // - OUT HT_CAPABILITY_IE *pHtCapability, - OUT UCHAR *AddHtInfoLen, - OUT ADD_HT_INFO_IE *AddHtInfo, - OUT UCHAR *NewExtChannel, - OUT USHORT *LengthVIE, - OUT PNDIS_802_11_VARIABLE_IEs pVIE); - -BOOLEAN PeerAddBAReqActionSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *pMsg, - IN ULONG MsgLen, - OUT PUCHAR pAddr2); - -BOOLEAN PeerAddBARspActionSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *pMsg, - IN ULONG MsgLen); - -BOOLEAN PeerDelBAActionSanity( - IN PRTMP_ADAPTER pAd, - IN UCHAR Wcid, - IN VOID *pMsg, - IN ULONG MsgLen); - -BOOLEAN MlmeAssocReqSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PUCHAR pApAddr, - OUT USHORT *CapabilityInfo, - OUT ULONG *Timeout, - OUT USHORT *ListenIntv); - -BOOLEAN MlmeAuthReqSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PUCHAR pAddr, - OUT ULONG *Timeout, - OUT USHORT *Alg); - -BOOLEAN MlmeStartReqSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT CHAR Ssid[], - OUT UCHAR *Ssidlen); - -BOOLEAN PeerAuthSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PUCHAR pAddr, - OUT USHORT *Alg, - OUT USHORT *Seq, - OUT USHORT *Status, - OUT CHAR ChlgText[]); - -BOOLEAN PeerAssocRspSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *pMsg, - IN ULONG MsgLen, - OUT PUCHAR pAddr2, - OUT USHORT *pCapabilityInfo, - OUT USHORT *pStatus, - OUT USHORT *pAid, - OUT UCHAR SupRate[], - OUT UCHAR *pSupRateLen, - OUT UCHAR ExtRate[], - OUT UCHAR *pExtRateLen, - OUT HT_CAPABILITY_IE *pHtCapability, - OUT ADD_HT_INFO_IE *pAddHtInfo, // AP might use this additional ht info IE - OUT UCHAR *pHtCapabilityLen, - OUT UCHAR *pAddHtInfoLen, - OUT UCHAR *pNewExtChannelOffset, - OUT PEDCA_PARM pEdcaParm, - OUT UCHAR *pCkipFlag); - -BOOLEAN PeerDisassocSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PUCHAR pAddr2, - OUT USHORT *Reason); - -BOOLEAN PeerWpaMessageSanity( - IN PRTMP_ADAPTER pAd, - IN PEAPOL_PACKET pMsg, - IN ULONG MsgLen, - IN UCHAR MsgType, - IN MAC_TABLE_ENTRY *pEntry); - -BOOLEAN PeerDeauthSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PUCHAR pAddr2, - OUT USHORT *Reason); - -BOOLEAN PeerProbeReqSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PUCHAR pAddr2, - OUT CHAR Ssid[], - OUT UCHAR *pSsidLen); - -BOOLEAN GetTimBit( - IN CHAR *Ptr, - IN USHORT Aid, - OUT UCHAR *TimLen, - OUT UCHAR *BcastFlag, - OUT UCHAR *DtimCount, - OUT UCHAR *DtimPeriod, - OUT UCHAR *MessageToMe); - -UCHAR ChannelSanity( - IN PRTMP_ADAPTER pAd, - IN UCHAR channel); - -NDIS_802_11_NETWORK_TYPE NetworkTypeInUseSanity( - IN PBSS_ENTRY pBss); - -BOOLEAN MlmeDelBAReqSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen); - -BOOLEAN MlmeAddBAReqSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PUCHAR pAddr2); - -ULONG MakeOutgoingFrame( - OUT CHAR *Buffer, - OUT ULONG *Length, ...); - -VOID LfsrInit( - IN PRTMP_ADAPTER pAd, - IN ULONG Seed); - -UCHAR RandomByte( - IN PRTMP_ADAPTER pAd); - -VOID AsicUpdateAutoFallBackTable( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pTxRate); - -VOID MlmePeriodicExec( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); - -VOID LinkDownExec( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); - -VOID LinkUpExec( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); - -VOID STAMlmePeriodicExec( - PRTMP_ADAPTER pAd); - -VOID MlmeAutoScan( - IN PRTMP_ADAPTER pAd); - -VOID MlmeAutoReconnectLastSSID( - IN PRTMP_ADAPTER pAd); - -BOOLEAN MlmeValidateSSID( - IN PUCHAR pSsid, - IN UCHAR SsidLen); - -VOID MlmeCheckForRoaming( - IN PRTMP_ADAPTER pAd, - IN ULONG Now32); - -VOID MlmeCheckForFastRoaming( - IN PRTMP_ADAPTER pAd, - IN ULONG Now); - -VOID MlmeDynamicTxRateSwitching( - IN PRTMP_ADAPTER pAd); - -VOID MlmeSetTxRate( - IN PRTMP_ADAPTER pAd, - IN PMAC_TABLE_ENTRY pEntry, - IN PRTMP_TX_RATE_SWITCH pTxRate); - -VOID MlmeSelectTxRateTable( - IN PRTMP_ADAPTER pAd, - IN PMAC_TABLE_ENTRY pEntry, - IN PUCHAR *ppTable, - IN PUCHAR pTableSize, - IN PUCHAR pInitTxRateIdx); - -VOID MlmeCalculateChannelQuality( - IN PRTMP_ADAPTER pAd, - IN ULONG Now); - -VOID MlmeCheckPsmChange( - IN PRTMP_ADAPTER pAd, - IN ULONG Now32); - -VOID MlmeSetPsmBit( - IN PRTMP_ADAPTER pAd, - IN USHORT psm); - -VOID MlmeSetTxPreamble( - IN PRTMP_ADAPTER pAd, - IN USHORT TxPreamble); - -VOID UpdateBasicRateBitmap( - IN PRTMP_ADAPTER pAd); - -VOID MlmeUpdateTxRates( - IN PRTMP_ADAPTER pAd, - IN BOOLEAN bLinkUp, - IN UCHAR apidx); - -#ifdef DOT11_N_SUPPORT -VOID MlmeUpdateHtTxRates( - IN PRTMP_ADAPTER pAd, - IN UCHAR apidx); -#endif // DOT11_N_SUPPORT // - -VOID RTMPCheckRates( - IN PRTMP_ADAPTER pAd, - IN OUT UCHAR SupRate[], - IN OUT UCHAR *SupRateLen); - -#ifdef CONFIG_STA_SUPPORT -BOOLEAN RTMPCheckChannel( - IN PRTMP_ADAPTER pAd, - IN UCHAR CentralChannel, - IN UCHAR Channel); -#endif // CONFIG_STA_SUPPORT // - -BOOLEAN RTMPCheckHt( - IN PRTMP_ADAPTER pAd, - IN UCHAR Wcid, - IN OUT HT_CAPABILITY_IE *pHtCapability, - IN OUT ADD_HT_INFO_IE *pAddHtInfo); - -VOID StaQuickResponeForRateUpExec( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); - -VOID AsicBbpTuning1( - IN PRTMP_ADAPTER pAd); - -VOID AsicBbpTuning2( - IN PRTMP_ADAPTER pAd); - -VOID RTMPUpdateMlmeRate( - IN PRTMP_ADAPTER pAd); - -CHAR RTMPMaxRssi( - IN PRTMP_ADAPTER pAd, - IN CHAR Rssi0, - IN CHAR Rssi1, - IN CHAR Rssi2); - -VOID AsicSetRxAnt( - IN PRTMP_ADAPTER pAd, - IN UCHAR Ant); - -VOID AsicEvaluateRxAnt( - IN PRTMP_ADAPTER pAd); - -VOID AsicRxAntEvalTimeout( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); - -VOID APSDPeriodicExec( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); - -BOOLEAN RTMPCheckEntryEnableAutoRateSwitch( - IN PRTMP_ADAPTER pAd, - IN PMAC_TABLE_ENTRY pEntry); - -UCHAR RTMPStaFixedTxMode( - IN PRTMP_ADAPTER pAd, - IN PMAC_TABLE_ENTRY pEntry); - -VOID RTMPUpdateLegacyTxSetting( - UCHAR fixed_tx_mode, - PMAC_TABLE_ENTRY pEntry); - -BOOLEAN RTMPAutoRateSwitchCheck( - IN PRTMP_ADAPTER pAd); - -NDIS_STATUS MlmeInit( - IN PRTMP_ADAPTER pAd); - -VOID MlmeHandler( - IN PRTMP_ADAPTER pAd); - -VOID MlmeHalt( - IN PRTMP_ADAPTER pAd); - -VOID MlmeResetRalinkCounters( - IN PRTMP_ADAPTER pAd); - -VOID BuildChannelList( - IN PRTMP_ADAPTER pAd); - -UCHAR FirstChannel( - IN PRTMP_ADAPTER pAd); - -UCHAR NextChannel( - IN PRTMP_ADAPTER pAd, - IN UCHAR channel); - -VOID ChangeToCellPowerLimit( - IN PRTMP_ADAPTER pAd, - IN UCHAR AironetCellPowerLimit); - -VOID RaiseClock( - IN PRTMP_ADAPTER pAd, - IN UINT32 *x); - -VOID LowerClock( - IN PRTMP_ADAPTER pAd, - IN UINT32 *x); - -USHORT ShiftInBits( - IN PRTMP_ADAPTER pAd); - -VOID ShiftOutBits( - IN PRTMP_ADAPTER pAd, - IN USHORT data, - IN USHORT count); - -VOID EEpromCleanup( - IN PRTMP_ADAPTER pAd); - -VOID EWDS( - IN PRTMP_ADAPTER pAd); - -VOID EWEN( - IN PRTMP_ADAPTER pAd); - -USHORT RTMP_EEPROM_READ16( - IN PRTMP_ADAPTER pAd, - IN USHORT Offset); - -VOID RTMP_EEPROM_WRITE16( - IN PRTMP_ADAPTER pAd, - IN USHORT Offset, - IN USHORT Data); - -// -// Prototypes of function definition in rtmp_tkip.c -// -VOID RTMPInitTkipEngine( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pTKey, - IN UCHAR KeyId, - IN PUCHAR pTA, - IN PUCHAR pMICKey, - IN PUCHAR pTSC, - OUT PULONG pIV16, - OUT PULONG pIV32); - -VOID RTMPInitMICEngine( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pKey, - IN PUCHAR pDA, - IN PUCHAR pSA, - IN UCHAR UserPriority, - IN PUCHAR pMICKey); - -BOOLEAN RTMPTkipCompareMICValue( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pSrc, - IN PUCHAR pDA, - IN PUCHAR pSA, - IN PUCHAR pMICKey, - IN UCHAR UserPriority, - IN UINT Len); - -VOID RTMPCalculateMICValue( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket, - IN PUCHAR pEncap, - IN PCIPHER_KEY pKey, - IN UCHAR apidx); - -BOOLEAN RTMPTkipCompareMICValueWithLLC( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pLLC, - IN PUCHAR pSrc, - IN PUCHAR pDA, - IN PUCHAR pSA, - IN PUCHAR pMICKey, - IN UINT Len); - -VOID RTMPTkipAppendByte( - IN PTKIP_KEY_INFO pTkip, - IN UCHAR uChar); - -VOID RTMPTkipAppend( - IN PTKIP_KEY_INFO pTkip, - IN PUCHAR pSrc, - IN UINT nBytes); - -VOID RTMPTkipGetMIC( - IN PTKIP_KEY_INFO pTkip); - -BOOLEAN RTMPSoftDecryptTKIP( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pData, - IN ULONG DataByteCnt, - IN UCHAR UserPriority, - IN PCIPHER_KEY pWpaKey); - -BOOLEAN RTMPSoftDecryptAES( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pData, - IN ULONG DataByteCnt, - IN PCIPHER_KEY pWpaKey); - -// -// Prototypes of function definition in cmm_info.c -// -NDIS_STATUS RTMPWPARemoveKeyProc( - IN PRTMP_ADAPTER pAd, - IN PVOID pBuf); - -VOID RTMPWPARemoveAllKeys( - IN PRTMP_ADAPTER pAd); - -BOOLEAN RTMPCheckStrPrintAble( - IN CHAR *pInPutStr, - IN UCHAR strLen); - -VOID RTMPSetPhyMode( - IN PRTMP_ADAPTER pAd, - IN ULONG phymode); - -VOID RTMPUpdateHTIE( - IN RT_HT_CAPABILITY *pRtHt, - IN UCHAR *pMcsSet, - OUT HT_CAPABILITY_IE *pHtCapability, - OUT ADD_HT_INFO_IE *pAddHtInfo); - -VOID RTMPAddWcidAttributeEntry( - IN PRTMP_ADAPTER pAd, - IN UCHAR BssIdx, - IN UCHAR KeyIdx, - IN UCHAR CipherAlg, - IN MAC_TABLE_ENTRY *pEntry); - -CHAR *GetEncryptType( - CHAR enc); - -CHAR *GetAuthMode( - CHAR auth); - -VOID RTMPIoctlGetSiteSurvey( - IN PRTMP_ADAPTER pAdapter, - IN struct iwreq *wrq); - -VOID RTMPIoctlGetMacTable( - IN PRTMP_ADAPTER pAd, - IN struct iwreq *wrq); - -VOID RTMPIndicateWPA2Status( - IN PRTMP_ADAPTER pAdapter); - -VOID RTMPOPModeSwitching( - IN PRTMP_ADAPTER pAd); - -#ifdef CONFIG_STA_SUPPORT -VOID RTMPAddBSSIDCipher( - IN PRTMP_ADAPTER pAd, - IN UCHAR Aid, - IN PNDIS_802_11_KEY pKey, - IN UCHAR CipherAlg); -#endif // CONFIG_STA_SUPPORT // - -#ifdef DOT11_N_SUPPORT -VOID RTMPSetHT( - IN PRTMP_ADAPTER pAd, - IN OID_SET_HT_PHYMODE *pHTPhyMode); - -VOID RTMPSetIndividualHT( - IN PRTMP_ADAPTER pAd, - IN UCHAR apidx); -#endif // DOT11_N_SUPPORT // - -VOID RTMPSendWirelessEvent( - IN PRTMP_ADAPTER pAd, - IN USHORT Event_flag, - IN PUCHAR pAddr, - IN UCHAR BssIdx, - IN CHAR Rssi); - -VOID NICUpdateCntlCounters( - IN PRTMP_ADAPTER pAd, - IN PHEADER_802_11 pHeader, - IN UCHAR SubType, - IN PRXWI_STRUC pRxWI); -// -// prototype in wpa.c -// -BOOLEAN WpaMsgTypeSubst( - IN UCHAR EAPType, - OUT INT *MsgType); - -VOID WpaPskStateMachineInit( - IN PRTMP_ADAPTER pAd, - IN STATE_MACHINE *S, - OUT STATE_MACHINE_FUNC Trans[]); - -VOID WpaEAPOLKeyAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID WpaPairMsg1Action( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID WpaPairMsg3Action( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID WpaGroupMsg1Action( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID WpaMacHeaderInit( - IN PRTMP_ADAPTER pAd, - IN OUT PHEADER_802_11 pHdr80211, - IN UCHAR wep, - IN PUCHAR pAddr1); - -VOID Wpa2PairMsg1Action( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID Wpa2PairMsg3Action( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -BOOLEAN ParseKeyData( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pKeyData, - IN UCHAR KeyDataLen, - IN UCHAR bPairewise); - -VOID RTMPToWirelessSta( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pHeader802_3, - IN UINT HdrLen, - IN PUCHAR pData, - IN UINT DataLen, - IN BOOLEAN is4wayFrame); - -VOID HMAC_SHA1( - IN UCHAR *text, - IN UINT text_len, - IN UCHAR *key, - IN UINT key_len, - IN UCHAR *digest); - -VOID PRF( - IN UCHAR *key, - IN INT key_len, - IN UCHAR *prefix, - IN INT prefix_len, - IN UCHAR *data, - IN INT data_len, - OUT UCHAR *output, - IN INT len); - -VOID CCKMPRF( - IN UCHAR *key, - IN INT key_len, - IN UCHAR *data, - IN INT data_len, - OUT UCHAR *output, - IN INT len); - -VOID WpaCountPTK( - IN PRTMP_ADAPTER pAd, - IN UCHAR *PMK, - IN UCHAR *ANonce, - IN UCHAR *AA, - IN UCHAR *SNonce, - IN UCHAR *SA, - OUT UCHAR *output, - IN UINT len); - -VOID GenRandom( - IN PRTMP_ADAPTER pAd, - IN UCHAR *macAddr, - OUT UCHAR *random); - -// -// prototype in aironet.c -// -VOID AironetStateMachineInit( - IN PRTMP_ADAPTER pAd, - IN STATE_MACHINE *S, - OUT STATE_MACHINE_FUNC Trans[]); - -VOID AironetMsgAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID AironetRequestAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID ChannelLoadRequestAction( - IN PRTMP_ADAPTER pAd, - IN UCHAR Index); - -VOID NoiseHistRequestAction( - IN PRTMP_ADAPTER pAd, - IN UCHAR Index); - -VOID BeaconRequestAction( - IN PRTMP_ADAPTER pAd, - IN UCHAR Index); - -VOID AironetReportAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID ChannelLoadReportAction( - IN PRTMP_ADAPTER pAd, - IN UCHAR Index); - -VOID NoiseHistReportAction( - IN PRTMP_ADAPTER pAd, - IN UCHAR Index); - -VOID AironetFinalReportAction( - IN PRTMP_ADAPTER pAd); - -VOID BeaconReportAction( - IN PRTMP_ADAPTER pAd, - IN UCHAR Index); - -VOID AironetAddBeaconReport( - IN PRTMP_ADAPTER pAd, - IN ULONG Index, - IN PMLME_QUEUE_ELEM pElem); - -VOID AironetCreateBeaconReportFromBssTable( - IN PRTMP_ADAPTER pAd); - -VOID DBGPRINT_TX_RING( - IN PRTMP_ADAPTER pAd, - IN UCHAR QueIdx); - -VOID DBGPRINT_RX_RING( - IN PRTMP_ADAPTER pAd); - -CHAR ConvertToRssi( - IN PRTMP_ADAPTER pAd, - IN CHAR Rssi, - IN UCHAR RssiNumber); - - -#ifdef DOT11N_DRAFT3 -VOID BuildEffectedChannelList( - IN PRTMP_ADAPTER pAd); -#endif // DOT11N_DRAFT3 // - - -VOID APAsicEvaluateRxAnt( - IN PRTMP_ADAPTER pAd); - - -VOID APAsicRxAntEvalTimeout( - IN PRTMP_ADAPTER pAd); - -// -// function prototype in cmm_wpa.c -// -BOOLEAN RTMPCheckWPAframe( - IN PRTMP_ADAPTER pAd, - IN PMAC_TABLE_ENTRY pEntry, - IN PUCHAR pData, - IN ULONG DataByteCount, - IN UCHAR FromWhichBSSID); - -VOID AES_GTK_KEY_UNWRAP( - IN UCHAR *key, - OUT UCHAR *plaintext, - IN UCHAR c_len, - IN UCHAR *ciphertext); - -BOOLEAN RTMPCheckRSNIE( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pData, - IN UCHAR DataLen, - IN MAC_TABLE_ENTRY *pEntry, - OUT UCHAR *Offset); - -BOOLEAN RTMPParseEapolKeyData( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pKeyData, - IN UCHAR KeyDataLen, - IN UCHAR GroupKeyIndex, - IN UCHAR MsgType, - IN BOOLEAN bWPA2, - IN MAC_TABLE_ENTRY *pEntry); - -VOID ConstructEapolMsg( - IN PRTMP_ADAPTER pAd, - IN UCHAR PeerAuthMode, - IN UCHAR PeerWepStatus, - IN UCHAR MyGroupKeyWepStatus, - IN UCHAR MsgType, - IN UCHAR DefaultKeyIdx, - IN UCHAR *ReplayCounter, - IN UCHAR *KeyNonce, - IN UCHAR *TxRSC, - IN UCHAR *PTK, - IN UCHAR *GTK, - IN UCHAR *RSNIE, - IN UCHAR RSNIE_Len, - OUT PEAPOL_PACKET pMsg); - -VOID CalculateMIC( - IN PRTMP_ADAPTER pAd, - IN UCHAR PeerWepStatus, - IN UCHAR *PTK, - OUT PEAPOL_PACKET pMsg); - -NDIS_STATUS RTMPSoftDecryptBroadCastData( - IN PRTMP_ADAPTER pAd, - IN RX_BLK *pRxBlk, - IN NDIS_802_11_ENCRYPTION_STATUS GroupCipher, - IN PCIPHER_KEY pShard_key); - -VOID ConstructEapolKeyData( - IN PRTMP_ADAPTER pAd, - IN UCHAR PeerAuthMode, - IN UCHAR PeerWepStatus, - IN UCHAR GroupKeyWepStatus, - IN UCHAR MsgType, - IN UCHAR DefaultKeyIdx, - IN BOOLEAN bWPA2Capable, - IN UCHAR *PTK, - IN UCHAR *GTK, - IN UCHAR *RSNIE, - IN UCHAR RSNIE_LEN, - OUT PEAPOL_PACKET pMsg); - -VOID RTMPMakeRSNIE( - IN PRTMP_ADAPTER pAd, - IN UINT AuthMode, - IN UINT WepStatus, - IN UCHAR apidx); - -// -// function prototype in ap_wpa.c -// - -BOOLEAN APWpaMsgTypeSubst( - IN UCHAR EAPType, - OUT INT *MsgType) ; - -MAC_TABLE_ENTRY *PACInquiry( - IN PRTMP_ADAPTER pAd, - IN ULONG Wcid); - -BOOLEAN RTMPCheckMcast( - IN PRTMP_ADAPTER pAd, - IN PEID_STRUCT eid_ptr, - IN MAC_TABLE_ENTRY *pEntry); - -BOOLEAN RTMPCheckUcast( - IN PRTMP_ADAPTER pAd, - IN PEID_STRUCT eid_ptr, - IN MAC_TABLE_ENTRY *pEntry); - -BOOLEAN RTMPCheckAUTH( - IN PRTMP_ADAPTER pAd, - IN PEID_STRUCT eid_ptr, - IN MAC_TABLE_ENTRY *pEntry); - -VOID WPAStart4WayHS( - IN PRTMP_ADAPTER pAd, - IN MAC_TABLE_ENTRY *pEntry, - IN ULONG TimeInterval); - -VOID WPAStart2WayGroupHS( - IN PRTMP_ADAPTER pAd, - IN MAC_TABLE_ENTRY *pEntry); - -VOID APWpaEAPPacketAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID APWpaEAPOLStartAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID APWpaEAPOLLogoffAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID APWpaEAPOLKeyAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID APWpaEAPOLASFAlertAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -VOID HandleCounterMeasure( - IN PRTMP_ADAPTER pAd, - IN MAC_TABLE_ENTRY *pEntry); - -VOID PeerPairMsg2Action( - IN PRTMP_ADAPTER pAd, - IN MAC_TABLE_ENTRY *pEntry, - IN MLME_QUEUE_ELEM *Elem); - -VOID PeerPairMsg4Action( - IN PRTMP_ADAPTER pAd, - IN MAC_TABLE_ENTRY *pEntry, - IN MLME_QUEUE_ELEM *Elem); - -VOID CMTimerExec( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); - -VOID WPARetryExec( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); - -VOID EnqueueStartForPSKExec( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); - -VOID RTMPHandleSTAKey( - IN PRTMP_ADAPTER pAdapter, - IN MAC_TABLE_ENTRY *pEntry, - IN MLME_QUEUE_ELEM *Elem); - -VOID PeerGroupMsg2Action( - IN PRTMP_ADAPTER pAd, - IN PMAC_TABLE_ENTRY pEntry, - IN VOID *Msg, - IN UINT MsgLen); - -VOID PairDisAssocAction( - IN PRTMP_ADAPTER pAd, - IN PMAC_TABLE_ENTRY pEntry, - IN USHORT Reason); - -VOID MlmeDeAuthAction( - IN PRTMP_ADAPTER pAd, - IN PMAC_TABLE_ENTRY pEntry, - IN USHORT Reason); - -VOID GREKEYPeriodicExec( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3); - -VOID CountGTK( - IN UCHAR *PMK, - IN UCHAR *GNonce, - IN UCHAR *AA, - OUT UCHAR *output, - IN UINT len); - -VOID GetSmall( - IN PVOID pSrc1, - IN PVOID pSrc2, - OUT PUCHAR out, - IN ULONG Length); - -VOID GetLarge( - IN PVOID pSrc1, - IN PVOID pSrc2, - OUT PUCHAR out, - IN ULONG Length); - -VOID APGenRandom( - IN PRTMP_ADAPTER pAd, - OUT UCHAR *random); - -VOID AES_GTK_KEY_WRAP( - IN UCHAR *key, - IN UCHAR *plaintext, - IN UCHAR p_len, - OUT UCHAR *ciphertext); - -VOID WpaSend( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR pPacket, - IN ULONG Len); - -VOID APToWirelessSta( - IN PRTMP_ADAPTER pAd, - IN MAC_TABLE_ENTRY *pEntry, - IN PUCHAR pHeader802_3, - IN UINT HdrLen, - IN PUCHAR pData, - IN UINT DataLen, - IN BOOLEAN bClearFrame); - -VOID RTMPAddPMKIDCache( - IN PRTMP_ADAPTER pAd, - IN INT apidx, - IN PUCHAR pAddr, - IN UCHAR *PMKID, - IN UCHAR *PMK); - -INT RTMPSearchPMKIDCache( - IN PRTMP_ADAPTER pAd, - IN INT apidx, - IN PUCHAR pAddr); - -VOID RTMPDeletePMKIDCache( - IN PRTMP_ADAPTER pAd, - IN INT apidx, - IN INT idx); - -VOID RTMPMaintainPMKIDCache( - IN PRTMP_ADAPTER pAd); - -VOID RTMPSendTriggerFrame( - IN PRTMP_ADAPTER pAd, - IN PVOID pBuffer, - IN ULONG Length, - IN UCHAR TxRate, - IN BOOLEAN bQosNull); - -#ifdef RT30xx -VOID RTMPFilterCalibration( - IN PRTMP_ADAPTER pAd); -#endif // RT30xx // - - -//typedef void (*TIMER_FUNCTION)(unsigned long); - - -/* timeout -- ms */ -VOID RTMP_SetPeriodicTimer( - IN NDIS_MINIPORT_TIMER *pTimer, - IN unsigned long timeout); - -VOID RTMP_OS_Init_Timer( - IN PRTMP_ADAPTER pAd, - IN NDIS_MINIPORT_TIMER *pTimer, - IN TIMER_FUNCTION function, - IN PVOID data); - -VOID RTMP_OS_Add_Timer( - IN NDIS_MINIPORT_TIMER *pTimer, - IN unsigned long timeout); - -VOID RTMP_OS_Mod_Timer( - IN NDIS_MINIPORT_TIMER *pTimer, - IN unsigned long timeout); - - -VOID RTMP_OS_Del_Timer( - IN NDIS_MINIPORT_TIMER *pTimer, - OUT BOOLEAN *pCancelled); - - -VOID RTMP_OS_Release_Packet( - IN PRTMP_ADAPTER pAd, - IN PQUEUE_ENTRY pEntry); - -VOID RTMPusecDelay( - IN ULONG usec); - -NDIS_STATUS os_alloc_mem( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR *mem, - IN ULONG size); - -NDIS_STATUS os_free_mem( - IN PRTMP_ADAPTER pAd, - IN PUCHAR mem); - - -void RTMP_AllocateSharedMemory( - IN PRTMP_ADAPTER pAd, - IN ULONG Length, - IN BOOLEAN Cached, - OUT PVOID *VirtualAddress, - OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress); - -VOID RTMPFreeTxRxRingMemory( - IN PRTMP_ADAPTER pAd); - -NDIS_STATUS AdapterBlockAllocateMemory( - IN PVOID handle, - OUT PVOID *ppAd); - -void RTMP_AllocateTxDescMemory( - IN PRTMP_ADAPTER pAd, - IN UINT Index, - IN ULONG Length, - IN BOOLEAN Cached, - OUT PVOID *VirtualAddress, - OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress); - -void RTMP_AllocateFirstTxBuffer( - IN PRTMP_ADAPTER pAd, - IN UINT Index, - IN ULONG Length, - IN BOOLEAN Cached, - OUT PVOID *VirtualAddress, - OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress); - -void RTMP_AllocateMgmtDescMemory( - IN PRTMP_ADAPTER pAd, - IN ULONG Length, - IN BOOLEAN Cached, - OUT PVOID *VirtualAddress, - OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress); - -void RTMP_AllocateRxDescMemory( - IN PRTMP_ADAPTER pAd, - IN ULONG Length, - IN BOOLEAN Cached, - OUT PVOID *VirtualAddress, - OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress); - -PNDIS_PACKET RTMP_AllocateRxPacketBuffer( - IN PRTMP_ADAPTER pAd, - IN ULONG Length, - IN BOOLEAN Cached, - OUT PVOID *VirtualAddress, - OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress); - -PNDIS_PACKET RTMP_AllocateTxPacketBuffer( - IN PRTMP_ADAPTER pAd, - IN ULONG Length, - IN BOOLEAN Cached, - OUT PVOID *VirtualAddress); - -PNDIS_PACKET RTMP_AllocateFragPacketBuffer( - IN PRTMP_ADAPTER pAd, - IN ULONG Length); - -void RTMP_QueryPacketInfo( - IN PNDIS_PACKET pPacket, - OUT PACKET_INFO *pPacketInfo, - OUT PUCHAR *pSrcBufVA, - OUT UINT *pSrcBufLen); - -void RTMP_QueryNextPacketInfo( - IN PNDIS_PACKET *ppPacket, - OUT PACKET_INFO *pPacketInfo, - OUT PUCHAR *pSrcBufVA, - OUT UINT *pSrcBufLen); - - -BOOLEAN RTMP_FillTxBlkInfo( - IN RTMP_ADAPTER *pAd, - IN TX_BLK *pTxBlk); - - -PRTMP_SCATTER_GATHER_LIST -rt_get_sg_list_from_packet(PNDIS_PACKET pPacket, RTMP_SCATTER_GATHER_LIST *sg); - - - void announce_802_3_packet( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket); - - -UINT BA_Reorder_AMSDU_Annnounce( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket); - - -UINT Handle_AMSDU_Packet( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pData, - IN ULONG DataSize, - IN UCHAR FromWhichBSSID); - - -void convert_802_11_to_802_3_packet( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket, - IN PUCHAR p8023hdr, - IN PUCHAR pData, - IN ULONG DataSize, - IN UCHAR FromWhichBSSID); - - -PNET_DEV get_netdev_from_bssid( - IN PRTMP_ADAPTER pAd, - IN UCHAR FromWhichBSSID); - - -PNDIS_PACKET duplicate_pkt( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pHeader802_3, - IN UINT HdrLen, - IN PUCHAR pData, - IN ULONG DataSize, - IN UCHAR FromWhichBSSID); - - -PNDIS_PACKET duplicate_pkt_with_TKIP_MIC( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pOldPkt); - -PNDIS_PACKET duplicate_pkt_with_VLAN( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pHeader802_3, - IN UINT HdrLen, - IN PUCHAR pData, - IN ULONG DataSize, - IN UCHAR FromWhichBSSID); - -PNDIS_PACKET duplicate_pkt_with_WPI( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket, - IN UINT32 ext_head_len, - IN UINT32 ext_tail_len); - -UCHAR VLAN_8023_Header_Copy( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pHeader802_3, - IN UINT HdrLen, - OUT PUCHAR pData, - IN UCHAR FromWhichBSSID); - -#ifdef DOT11_N_SUPPORT -void ba_flush_reordering_timeout_mpdus( - IN PRTMP_ADAPTER pAd, - IN PBA_REC_ENTRY pBAEntry, - IN ULONG Now32); - - -VOID BAOriSessionSetUp( - IN PRTMP_ADAPTER pAd, - IN MAC_TABLE_ENTRY *pEntry, - IN UCHAR TID, - IN USHORT TimeOut, - IN ULONG DelayTime, - IN BOOLEAN isForced); - -VOID BASessionTearDownALL( - IN OUT PRTMP_ADAPTER pAd, - IN UCHAR Wcid); -#endif // DOT11_N_SUPPORT // - -BOOLEAN OS_Need_Clone_Packet(void); - - -VOID build_tx_packet( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket, - IN PUCHAR pFrame, - IN ULONG FrameLen); - - -VOID BAOriSessionTearDown( - IN OUT PRTMP_ADAPTER pAd, - IN UCHAR Wcid, - IN UCHAR TID, - IN BOOLEAN bPassive, - IN BOOLEAN bForceSend); - -VOID BARecSessionTearDown( - IN OUT PRTMP_ADAPTER pAd, - IN UCHAR Wcid, - IN UCHAR TID, - IN BOOLEAN bPassive); - -BOOLEAN ba_reordering_resource_init(PRTMP_ADAPTER pAd, int num); -void ba_reordering_resource_release(PRTMP_ADAPTER pAd); - -ULONG AutoChBssInsertEntry( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pBssid, - IN CHAR Ssid[], - IN UCHAR SsidLen, - IN UCHAR ChannelNo, - IN CHAR Rssi); - -void AutoChBssTableInit( - IN PRTMP_ADAPTER pAd); - -void ChannelInfoInit( - IN PRTMP_ADAPTER pAd); - -void AutoChBssTableDestroy( - IN PRTMP_ADAPTER pAd); - -void ChannelInfoDestroy( - IN PRTMP_ADAPTER pAd); - -UCHAR New_ApAutoSelectChannel( - IN PRTMP_ADAPTER pAd); - - -#ifdef NINTENDO_AP -VOID InitNINTENDO_TABLE( - IN PRTMP_ADAPTER pAd); - -UCHAR CheckNINTENDO_TABLE( - IN PRTMP_ADAPTER pAd, - PCHAR pDS_Ssid, - UCHAR DS_SsidLen, - PUCHAR pDS_Addr); - -UCHAR DelNINTENDO_ENTRY( - IN PRTMP_ADAPTER pAd, - UCHAR * pDS_Addr); - -VOID RTMPIoctlNintendoCapable( - IN PRTMP_ADAPTER pAd, - IN struct iwreq *wrq); - -VOID RTMPIoctlNintendoGetTable( - IN PRTMP_ADAPTER pAd, - IN struct iwreq *wrq); - -VOID RTMPIoctlNintendoSetTable( - IN PRTMP_ADAPTER pAd, - IN struct iwreq *wrq); - -#endif // NINTENDO_AP // - -BOOLEAN rtstrmactohex( - IN char *s1, - IN char *s2); - -BOOLEAN rtstrcasecmp( - IN char *s1, - IN char *s2); - -char *rtstrstruncasecmp( - IN char *s1, - IN char *s2); - -char *rtstrstr( - IN const char * s1, - IN const char * s2); - -char *rstrtok( - IN char * s, - IN const char * ct); - -int rtinet_aton( - const char *cp, - unsigned int *addr); - -////////// common ioctl functions ////////// -INT Set_DriverVersion_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_CountryRegion_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_CountryRegionABand_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_WirelessMode_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_Channel_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ShortSlot_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_TxPower_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_BGProtection_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_TxPreamble_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_RTSThreshold_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_FragThreshold_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_TxBurst_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -#ifdef AGGREGATION_SUPPORT -INT Set_PktAggregate_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); -#endif - -INT Set_IEEE80211H_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -#ifdef DBG -INT Set_Debug_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); -#endif - -INT Show_DescInfo_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ResetStatCounter_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -#ifdef DOT11_N_SUPPORT -INT Set_BASetup_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_BADecline_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_BAOriTearDown_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_BARecTearDown_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_HtBw_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_HtMcs_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_HtGi_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_HtOpMode_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_HtStbc_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_HtHtc_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_HtExtcha_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_HtMpduDensity_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_HtBaWinSize_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_HtRdg_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_HtLinkAdapt_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_HtAmsdu_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_HtAutoBa_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_HtProtect_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_HtMimoPs_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - - -INT Set_ForceShortGI_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_ForceGF_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT SetCommonHT( - IN PRTMP_ADAPTER pAd); - -INT Set_SendPSMPAction_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_HtMIMOPSmode_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - - -INT Set_HtTxBASize_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); -#endif // DOT11_N_SUPPORT // - - - -#ifdef CONFIG_STA_SUPPORT -//Dls , kathy -VOID RTMPSendDLSTearDownFrame( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDA); - -#ifdef DOT11_N_SUPPORT -//Block ACK -VOID QueryBATABLE( - IN PRTMP_ADAPTER pAd, - OUT PQUERYBA_TABLE pBAT); -#endif // DOT11_N_SUPPORT // - -#ifdef WPA_SUPPLICANT_SUPPORT -INT WpaCheckEapCode( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pFrame, - IN USHORT FrameLen, - IN USHORT OffSet); - -VOID WpaSendMicFailureToWpaSupplicant( - IN PRTMP_ADAPTER pAd, - IN BOOLEAN bUnicast); - -VOID SendAssocIEsToWpaSupplicant( - IN PRTMP_ADAPTER pAd); -#endif // WPA_SUPPLICANT_SUPPORT // - -#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT -int wext_notify_event_assoc( - IN RTMP_ADAPTER *pAd); -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // - -#endif // CONFIG_STA_SUPPORT // - - - -#ifdef DOT11_N_SUPPORT -VOID Handle_BSS_Width_Trigger_Events( - IN PRTMP_ADAPTER pAd); - -void build_ext_channel_switch_ie( - IN PRTMP_ADAPTER pAd, - IN HT_EXT_CHANNEL_SWITCH_ANNOUNCEMENT_IE *pIE); -#endif // DOT11_N_SUPPORT // - - -BOOLEAN APRxDoneInterruptHandle( - IN PRTMP_ADAPTER pAd); - -BOOLEAN STARxDoneInterruptHandle( - IN PRTMP_ADAPTER pAd, - IN BOOLEAN argc); - -#ifdef DOT11_N_SUPPORT -// AMPDU packet indication -VOID Indicate_AMPDU_Packet( - IN PRTMP_ADAPTER pAd, - IN RX_BLK *pRxBlk, - IN UCHAR FromWhichBSSID); - -// AMSDU packet indication -VOID Indicate_AMSDU_Packet( - IN PRTMP_ADAPTER pAd, - IN RX_BLK *pRxBlk, - IN UCHAR FromWhichBSSID); -#endif // DOT11_N_SUPPORT // - -// Normal legacy Rx packet indication -VOID Indicate_Legacy_Packet( - IN PRTMP_ADAPTER pAd, - IN RX_BLK *pRxBlk, - IN UCHAR FromWhichBSSID); - -VOID Indicate_EAPOL_Packet( - IN PRTMP_ADAPTER pAd, - IN RX_BLK *pRxBlk, - IN UCHAR FromWhichBSSID); - -void update_os_packet_info( - IN PRTMP_ADAPTER pAd, - IN RX_BLK *pRxBlk, - IN UCHAR FromWhichBSSID); - -void wlan_802_11_to_802_3_packet( - IN PRTMP_ADAPTER pAd, - IN RX_BLK *pRxBlk, - IN PUCHAR pHeader802_3, - IN UCHAR FromWhichBSSID); - -UINT deaggregate_AMSDU_announce( - IN PRTMP_ADAPTER pAd, - PNDIS_PACKET pPacket, - IN PUCHAR pData, - IN ULONG DataSize); - - -#ifdef CONFIG_STA_SUPPORT -// remove LLC and get 802_3 Header -#define RTMP_802_11_REMOVE_LLC_AND_CONVERT_TO_802_3(_pRxBlk, _pHeader802_3) \ -{ \ - PUCHAR _pRemovedLLCSNAP = NULL, _pDA, _pSA; \ - \ - if (RX_BLK_TEST_FLAG(_pRxBlk, fRX_MESH)) \ - { \ - _pDA = _pRxBlk->pHeader->Addr3; \ - _pSA = (PUCHAR)_pRxBlk->pHeader + sizeof(HEADER_802_11); \ - } \ - else \ - { \ - if (RX_BLK_TEST_FLAG(_pRxBlk, fRX_INFRA)) \ - { \ - _pDA = _pRxBlk->pHeader->Addr1; \ - if (RX_BLK_TEST_FLAG(_pRxBlk, fRX_DLS)) \ - _pSA = _pRxBlk->pHeader->Addr2; \ - else \ - _pSA = _pRxBlk->pHeader->Addr3; \ - } \ - else \ - { \ - _pDA = _pRxBlk->pHeader->Addr1; \ - _pSA = _pRxBlk->pHeader->Addr2; \ - } \ - } \ - \ - CONVERT_TO_802_3(_pHeader802_3, _pDA, _pSA, _pRxBlk->pData, \ - _pRxBlk->DataSize, _pRemovedLLCSNAP); \ -} -#endif // CONFIG_STA_SUPPORT // - - -BOOLEAN APFowardWirelessStaToWirelessSta( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket, - IN ULONG FromWhichBSSID); - -VOID Announce_or_Forward_802_3_Packet( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket, - IN UCHAR FromWhichBSSID); - -VOID Sta_Announce_or_Forward_802_3_Packet( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket, - IN UCHAR FromWhichBSSID); - - -#ifdef CONFIG_STA_SUPPORT -#define ANNOUNCE_OR_FORWARD_802_3_PACKET(_pAd, _pPacket, _FromWhichBSS)\ - Sta_Announce_or_Forward_802_3_Packet(_pAd, _pPacket, _FromWhichBSS); - //announce_802_3_packet(_pAd, _pPacket); -#endif // CONFIG_STA_SUPPORT // - - -PNDIS_PACKET DuplicatePacket( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket, - IN UCHAR FromWhichBSSID); - - -PNDIS_PACKET ClonePacket( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket, - IN PUCHAR pData, - IN ULONG DataSize); - - -// Normal, AMPDU or AMSDU -VOID CmmRxnonRalinkFrameIndicate( - IN PRTMP_ADAPTER pAd, - IN RX_BLK *pRxBlk, - IN UCHAR FromWhichBSSID); - -VOID CmmRxRalinkFrameIndicate( - IN PRTMP_ADAPTER pAd, - IN MAC_TABLE_ENTRY *pEntry, - IN RX_BLK *pRxBlk, - IN UCHAR FromWhichBSSID); - -VOID Update_Rssi_Sample( - IN PRTMP_ADAPTER pAd, - IN RSSI_SAMPLE *pRssi, - IN PRXWI_STRUC pRxWI); - -PNDIS_PACKET GetPacketFromRxRing( - IN PRTMP_ADAPTER pAd, - OUT PRT28XX_RXD_STRUC pSaveRxD, - OUT BOOLEAN *pbReschedule, - IN OUT UINT32 *pRxPending); - -PNDIS_PACKET RTMPDeFragmentDataFrame( - IN PRTMP_ADAPTER pAd, - IN RX_BLK *pRxBlk); - -//////////////////////////////////////// - - - - - -#ifdef SNMP_SUPPORT -//for snmp , kathy -typedef struct _DefaultKeyIdxValue -{ - UCHAR KeyIdx; - UCHAR Value[16]; -} DefaultKeyIdxValue, *PDefaultKeyIdxValue; -#endif - - -#ifdef CONFIG_STA_SUPPORT -enum { - DIDmsg_lnxind_wlansniffrm = 0x00000044, - DIDmsg_lnxind_wlansniffrm_hosttime = 0x00010044, - DIDmsg_lnxind_wlansniffrm_mactime = 0x00020044, - DIDmsg_lnxind_wlansniffrm_channel = 0x00030044, - DIDmsg_lnxind_wlansniffrm_rssi = 0x00040044, - DIDmsg_lnxind_wlansniffrm_sq = 0x00050044, - DIDmsg_lnxind_wlansniffrm_signal = 0x00060044, - DIDmsg_lnxind_wlansniffrm_noise = 0x00070044, - DIDmsg_lnxind_wlansniffrm_rate = 0x00080044, - DIDmsg_lnxind_wlansniffrm_istx = 0x00090044, - DIDmsg_lnxind_wlansniffrm_frmlen = 0x000A0044 -}; -enum { - P80211ENUM_msgitem_status_no_value = 0x00 -}; -enum { - P80211ENUM_truth_false = 0x00, - P80211ENUM_truth_true = 0x01 -}; - -/* Definition from madwifi */ -typedef struct { - UINT32 did; - UINT16 status; - UINT16 len; - UINT32 data; -} p80211item_uint32_t; - -typedef struct { - UINT32 msgcode; - UINT32 msglen; -#define WLAN_DEVNAMELEN_MAX 16 - UINT8 devname[WLAN_DEVNAMELEN_MAX]; - p80211item_uint32_t hosttime; - p80211item_uint32_t mactime; - p80211item_uint32_t channel; - p80211item_uint32_t rssi; - p80211item_uint32_t sq; - p80211item_uint32_t signal; - p80211item_uint32_t noise; - p80211item_uint32_t rate; - p80211item_uint32_t istx; - p80211item_uint32_t frmlen; -} wlan_ng_prism2_header; - -/* The radio capture header precedes the 802.11 header. */ -typedef struct PACKED _ieee80211_radiotap_header { - UINT8 it_version; /* Version 0. Only increases - * for drastic changes, - * introduction of compatible - * new fields does not count. - */ - UINT8 it_pad; - UINT16 it_len; /* length of the whole - * header in bytes, including - * it_version, it_pad, - * it_len, and data fields. - */ - UINT32 it_present; /* A bitmap telling which - * fields are present. Set bit 31 - * (0x80000000) to extend the - * bitmap by another 32 bits. - * Additional extensions are made - * by setting bit 31. - */ -}ieee80211_radiotap_header ; - -enum ieee80211_radiotap_type { - IEEE80211_RADIOTAP_TSFT = 0, - IEEE80211_RADIOTAP_FLAGS = 1, - IEEE80211_RADIOTAP_RATE = 2, - IEEE80211_RADIOTAP_CHANNEL = 3, - IEEE80211_RADIOTAP_FHSS = 4, - IEEE80211_RADIOTAP_DBM_ANTSIGNAL = 5, - IEEE80211_RADIOTAP_DBM_ANTNOISE = 6, - IEEE80211_RADIOTAP_LOCK_QUALITY = 7, - IEEE80211_RADIOTAP_TX_ATTENUATION = 8, - IEEE80211_RADIOTAP_DB_TX_ATTENUATION = 9, - IEEE80211_RADIOTAP_DBM_TX_POWER = 10, - IEEE80211_RADIOTAP_ANTENNA = 11, - IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12, - IEEE80211_RADIOTAP_DB_ANTNOISE = 13 -}; - -#define WLAN_RADIOTAP_PRESENT ( \ - (1 << IEEE80211_RADIOTAP_TSFT) | \ - (1 << IEEE80211_RADIOTAP_FLAGS) | \ - (1 << IEEE80211_RADIOTAP_RATE) | \ - 0) - -typedef struct _wlan_radiotap_header { - ieee80211_radiotap_header wt_ihdr; - INT64 wt_tsft; - UINT8 wt_flags; - UINT8 wt_rate; -} wlan_radiotap_header; -/* Definition from madwifi */ - -void send_monitor_packets( - IN PRTMP_ADAPTER pAd, - IN RX_BLK *pRxBlk); - -#if WIRELESS_EXT >= 12 -// This function will be called when query /proc -struct iw_statistics *rt28xx_get_wireless_stats( - IN struct net_device *net_dev); -#endif - -VOID RTMPSetDesiredRates( - IN PRTMP_ADAPTER pAdapter, - IN LONG Rates); -#endif // CONFIG_STA_SUPPORT // - -INT Set_FixedTxMode_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -#ifdef CONFIG_APSTA_MIXED_SUPPORT -INT Set_OpMode_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); -#endif // CONFIG_APSTA_MIXED_SUPPORT // - -static inline char* GetPhyMode( - int Mode) -{ - switch(Mode) - { - case MODE_CCK: - return "CCK"; - - case MODE_OFDM: - return "OFDM"; -#ifdef DOT11_N_SUPPORT - case MODE_HTMIX: - return "HTMIX"; - - case MODE_HTGREENFIELD: - return "GREEN"; -#endif // DOT11_N_SUPPORT // - default: - return "N/A"; - } -} - - -static inline char* GetBW( - int BW) -{ - switch(BW) - { - case BW_10: - return "10M"; - - case BW_20: - return "20M"; -#ifdef DOT11_N_SUPPORT - case BW_40: - return "40M"; -#endif // DOT11_N_SUPPORT // - default: - return "N/A"; - } -} - - -VOID RT28xxThreadTerminate( - IN RTMP_ADAPTER *pAd); - -BOOLEAN RT28XXChipsetCheck( - IN void *_dev_p); - -BOOLEAN RT28XXNetDevInit( - IN void *_dev_p, - IN struct net_device *net_dev, - IN RTMP_ADAPTER *pAd); - -BOOLEAN RT28XXProbePostConfig( - IN void *_dev_p, - IN RTMP_ADAPTER *pAd, - IN INT32 argc); - -VOID RT28XXDMADisable( - IN RTMP_ADAPTER *pAd); - -VOID RT28XXDMAEnable( - IN RTMP_ADAPTER *pAd); - -VOID RT28xx_UpdateBeaconToAsic( - IN RTMP_ADAPTER * pAd, - IN INT apidx, - IN ULONG BeaconLen, - IN ULONG UpdatePos); - -INT rt28xx_ioctl( - IN struct net_device *net_dev, - IN OUT struct ifreq *rq, - IN INT cmd); - - -#ifdef CONFIG_STA_SUPPORT -INT rt28xx_sta_ioctl( - IN struct net_device *net_dev, - IN OUT struct ifreq *rq, - IN INT cmd); -#endif // CONFIG_STA_SUPPORT // - -BOOLEAN RT28XXSecurityKeyAdd( - IN PRTMP_ADAPTER pAd, - IN ULONG apidx, - IN ULONG KeyIdx, - IN MAC_TABLE_ENTRY *pEntry); - -//////////////////////////////////////// -PNDIS_PACKET GetPacketFromRxRing( - IN PRTMP_ADAPTER pAd, - OUT PRT28XX_RXD_STRUC pSaveRxD, - OUT BOOLEAN *pbReschedule, - IN OUT UINT32 *pRxPending); - - -void kill_thread_task(PRTMP_ADAPTER pAd); - -void tbtt_tasklet(unsigned long data); - - -VOID AsicTurnOffRFClk( - IN PRTMP_ADAPTER pAd, - IN UCHAR Channel); - -VOID AsicTurnOnRFClk( - IN PRTMP_ADAPTER pAd, - IN UCHAR Channel); - -#ifdef RT30xx -NTSTATUS RT30xxWriteRFRegister( - IN PRTMP_ADAPTER pAd, - IN UCHAR RegID, - IN UCHAR Value); - -NTSTATUS RT30xxReadRFRegister( - IN PRTMP_ADAPTER pAd, - IN UCHAR RegID, - IN PUCHAR pValue); - -//2008/09/11:KH add to support efuse<-- -UCHAR eFuseReadRegisters( - IN PRTMP_ADAPTER pAd, - IN USHORT Offset, - IN USHORT Length, - OUT USHORT* pData); - -VOID eFuseReadPhysical( - IN PRTMP_ADAPTER pAd, - IN PUSHORT lpInBuffer, - IN ULONG nInBufferSize, - OUT PUSHORT lpOutBuffer, - IN ULONG nOutBufferSize -); - -NTSTATUS eFuseRead( - IN PRTMP_ADAPTER pAd, - IN USHORT Offset, - OUT PUCHAR pData, - IN USHORT Length); - -VOID eFusePhysicalWriteRegisters( - IN PRTMP_ADAPTER pAd, - IN USHORT Offset, - IN USHORT Length, - OUT USHORT* pData); - -NTSTATUS eFuseWriteRegisters( - IN PRTMP_ADAPTER pAd, - IN USHORT Offset, - IN USHORT Length, - IN USHORT* pData); - -VOID eFuseWritePhysical( - IN PRTMP_ADAPTER pAd, - PUSHORT lpInBuffer, - ULONG nInBufferSize, - PUCHAR lpOutBuffer, - ULONG nOutBufferSize -); - -NTSTATUS eFuseWrite( - IN PRTMP_ADAPTER pAd, - IN USHORT Offset, - IN PUCHAR pData, - IN USHORT length); - -INT set_eFuseGetFreeBlockCount_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT set_eFusedump_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT set_eFuseLoadFromBin_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -NTSTATUS eFuseWriteRegistersFromBin( - IN PRTMP_ADAPTER pAd, - IN USHORT Offset, - IN USHORT Length, - IN USHORT* pData); - -VOID eFusePhysicalReadRegisters( - IN PRTMP_ADAPTER pAd, - IN USHORT Offset, - IN USHORT Length, - OUT USHORT* pData); - -NDIS_STATUS NICLoadEEPROM( - IN PRTMP_ADAPTER pAd); - -BOOLEAN bNeedLoadEEPROM( - IN PRTMP_ADAPTER pAd); -//2008/09/11:KH add to support efuse--> -#endif // RT30xx // - -#ifdef RT30xx -// add by johnli, RF power sequence setup -VOID RT30xxLoadRFNormalModeSetup( - IN PRTMP_ADAPTER pAd); - -VOID RT30xxLoadRFSleepModeSetup( - IN PRTMP_ADAPTER pAd); - -VOID RT30xxReverseRFSleepModeSetup( - IN PRTMP_ADAPTER pAd); -// end johnli -#endif // RT30xx // - -#ifdef RT2870 -// -// Function Prototype in rtusb_bulk.c -// -VOID RTUSBInitTxDesc( - IN PRTMP_ADAPTER pAd, - IN PTX_CONTEXT pTxContext, - IN UCHAR BulkOutPipeId, - IN usb_complete_t Func); - -VOID RTUSBInitHTTxDesc( - IN PRTMP_ADAPTER pAd, - IN PHT_TX_CONTEXT pTxContext, - IN UCHAR BulkOutPipeId, - IN ULONG BulkOutSize, - IN usb_complete_t Func); - -VOID RTUSBInitRxDesc( - IN PRTMP_ADAPTER pAd, - IN PRX_CONTEXT pRxContext); - -VOID RTUSBCleanUpDataBulkOutQueue( - IN PRTMP_ADAPTER pAd); - -VOID RTUSBCancelPendingBulkOutIRP( - IN PRTMP_ADAPTER pAd); - -VOID RTUSBBulkOutDataPacket( - IN PRTMP_ADAPTER pAd, - IN UCHAR BulkOutPipeId, - IN UCHAR Index); - -VOID RTUSBBulkOutNullFrame( - IN PRTMP_ADAPTER pAd); - -VOID RTUSBBulkOutRTSFrame( - IN PRTMP_ADAPTER pAd); - -VOID RTUSBCancelPendingBulkInIRP( - IN PRTMP_ADAPTER pAd); - -VOID RTUSBCancelPendingIRPs( - IN PRTMP_ADAPTER pAd); - -VOID RTUSBBulkOutMLMEPacket( - IN PRTMP_ADAPTER pAd, - IN UCHAR Index); - -VOID RTUSBBulkOutPsPoll( - IN PRTMP_ADAPTER pAd); - -VOID RTUSBCleanUpMLMEBulkOutQueue( - IN PRTMP_ADAPTER pAd); - -VOID RTUSBKickBulkOut( - IN PRTMP_ADAPTER pAd); - -VOID RTUSBBulkReceive( - IN PRTMP_ADAPTER pAd); - -VOID DoBulkIn( - IN RTMP_ADAPTER *pAd); - -VOID RTUSBInitRxDesc( - IN PRTMP_ADAPTER pAd, - IN PRX_CONTEXT pRxContext); - -VOID RTUSBBulkRxHandle( - IN unsigned long data); - -// -// Function Prototype in rtusb_io.c -// -NTSTATUS RTUSBMultiRead( - IN PRTMP_ADAPTER pAd, - IN USHORT Offset, - OUT PUCHAR pData, - IN USHORT length); - -NTSTATUS RTUSBMultiWrite( - IN PRTMP_ADAPTER pAd, - IN USHORT Offset, - IN PUCHAR pData, - IN USHORT length); - -NTSTATUS RTUSBMultiWrite_OneByte( - IN PRTMP_ADAPTER pAd, - IN USHORT Offset, - IN PUCHAR pData); - -NTSTATUS RTUSBReadBBPRegister( - IN PRTMP_ADAPTER pAd, - IN UCHAR Id, - IN PUCHAR pValue); - -NTSTATUS RTUSBWriteBBPRegister( - IN PRTMP_ADAPTER pAd, - IN UCHAR Id, - IN UCHAR Value); - -NTSTATUS RTUSBWriteRFRegister( - IN PRTMP_ADAPTER pAd, - IN UINT32 Value); - -NTSTATUS RTUSB_VendorRequest( - IN PRTMP_ADAPTER pAd, - IN UINT32 TransferFlags, - IN UCHAR ReservedBits, - IN UCHAR Request, - IN USHORT Value, - IN USHORT Index, - IN PVOID TransferBuffer, - IN UINT32 TransferBufferLength); - -NTSTATUS RTUSBReadEEPROM( - IN PRTMP_ADAPTER pAd, - IN USHORT Offset, - OUT PUCHAR pData, - IN USHORT length); - -NTSTATUS RTUSBWriteEEPROM( - IN PRTMP_ADAPTER pAd, - IN USHORT Offset, - IN PUCHAR pData, - IN USHORT length); - -VOID RTUSBPutToSleep( - IN PRTMP_ADAPTER pAd); - -NTSTATUS RTUSBWakeUp( - IN PRTMP_ADAPTER pAd); - -VOID RTUSBInitializeCmdQ( - IN PCmdQ cmdq); - -NDIS_STATUS RTUSBEnqueueCmdFromNdis( - IN PRTMP_ADAPTER pAd, - IN NDIS_OID Oid, - IN BOOLEAN SetInformation, - IN PVOID pInformationBuffer, - IN UINT32 InformationBufferLength); - -NDIS_STATUS RTUSBEnqueueInternalCmd( - IN PRTMP_ADAPTER pAd, - IN NDIS_OID Oid, - IN PVOID pInformationBuffer, - IN UINT32 InformationBufferLength); - -VOID RTUSBDequeueCmd( - IN PCmdQ cmdq, - OUT PCmdQElmt *pcmdqelmt); - -INT RTUSBCmdThread( - IN OUT PVOID Context); - -INT TimerQThread( - IN OUT PVOID Context); - -RT2870_TIMER_ENTRY *RT2870_TimerQ_Insert( - IN RTMP_ADAPTER *pAd, - IN RALINK_TIMER_STRUCT *pTimer); - -BOOLEAN RT2870_TimerQ_Remove( - IN RTMP_ADAPTER *pAd, - IN RALINK_TIMER_STRUCT *pTimer); - -void RT2870_TimerQ_Exit( - IN RTMP_ADAPTER *pAd); - -void RT2870_TimerQ_Init( - IN RTMP_ADAPTER *pAd); - -VOID RT2870_BssBeaconExit( - IN RTMP_ADAPTER *pAd); - -VOID RT2870_BssBeaconStop( - IN RTMP_ADAPTER *pAd); - -VOID RT2870_BssBeaconStart( - IN RTMP_ADAPTER * pAd); - -VOID RT2870_BssBeaconInit( - IN RTMP_ADAPTER *pAd); - -VOID RT2870_WatchDog( - IN RTMP_ADAPTER *pAd); - -NTSTATUS RTUSBWriteMACRegister( - IN PRTMP_ADAPTER pAd, - IN USHORT Offset, - IN UINT32 Value); - -NTSTATUS RTUSBReadMACRegister( - IN PRTMP_ADAPTER pAd, - IN USHORT Offset, - OUT PUINT32 pValue); - -NTSTATUS RTUSBSingleWrite( - IN RTMP_ADAPTER *pAd, - IN USHORT Offset, - IN USHORT Value); - -NTSTATUS RTUSBFirmwareRun( - IN PRTMP_ADAPTER pAd); - -NTSTATUS RTUSBFirmwareWrite( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pFwImage, - IN ULONG FwLen); - -NTSTATUS RTUSBFirmwareOpmode( - IN PRTMP_ADAPTER pAd, - OUT PUINT32 pValue); - -NTSTATUS RTUSBVenderReset( - IN PRTMP_ADAPTER pAd); - -NDIS_STATUS RTUSBSetHardWareRegister( - IN PRTMP_ADAPTER pAdapter, - IN PVOID pBuf); - -NDIS_STATUS RTUSBQueryHardWareRegister( - IN PRTMP_ADAPTER pAdapter, - IN PVOID pBuf); - -VOID CMDHandler( - IN PRTMP_ADAPTER pAd); - - -NDIS_STATUS CreateThreads( - IN struct net_device *net_dev ); - - -VOID MacTableInitialize( - IN PRTMP_ADAPTER pAd); - -VOID MlmeSetPsm( - IN PRTMP_ADAPTER pAd, - IN USHORT psm); - -NDIS_STATUS RTMPWPAAddKeyProc( - IN PRTMP_ADAPTER pAd, - IN PVOID pBuf); - -VOID AsicRxAntEvalAction( - IN PRTMP_ADAPTER pAd); - -void append_pkt( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pHeader802_3, - IN UINT HdrLen, - IN PUCHAR pData, - IN ULONG DataSize, - OUT PNDIS_PACKET *ppPacket); - -UINT deaggregate_AMSDU_announce( - IN PRTMP_ADAPTER pAd, - PNDIS_PACKET pPacket, - IN PUCHAR pData, - IN ULONG DataSize); - -NDIS_STATUS RTMPCheckRxError( - IN PRTMP_ADAPTER pAd, - IN PHEADER_802_11 pHeader, - IN PRXWI_STRUC pRxWI, - IN PRT28XX_RXD_STRUC pRxINFO); - - -VOID RTUSBMlmeHardTransmit( - IN PRTMP_ADAPTER pAd, - IN PMGMT_STRUC pMgmt); - -INT MlmeThread( - IN PVOID Context); - -// -// Function Prototype in rtusb_data.c -// -NDIS_STATUS RTUSBFreeDescriptorRequest( - IN PRTMP_ADAPTER pAd, - IN UCHAR BulkOutPipeId, - IN UINT32 NumberRequired); - - -BOOLEAN RTUSBNeedQueueBackForAgg( - IN RTMP_ADAPTER *pAd, - IN UCHAR BulkOutPipeId); - - -VOID RTMPWriteTxInfo( - IN PRTMP_ADAPTER pAd, - IN PTXINFO_STRUC pTxInfo, - IN USHORT USBDMApktLen, - IN BOOLEAN bWiv, - IN UCHAR QueueSel, - IN UCHAR NextValid, - IN UCHAR TxBurst); - -// -// Function Prototype in cmm_data_2870.c -// -USHORT RtmpUSB_WriteSubTxResource( - IN PRTMP_ADAPTER pAd, - IN TX_BLK *pTxBlk, - IN BOOLEAN bIsLast, - OUT USHORT *FreeNumber); - -USHORT RtmpUSB_WriteSingleTxResource( - IN PRTMP_ADAPTER pAd, - IN TX_BLK *pTxBlk, - IN BOOLEAN bIsLast, - OUT USHORT *FreeNumber); - -USHORT RtmpUSB_WriteFragTxResource( - IN PRTMP_ADAPTER pAd, - IN TX_BLK *pTxBlk, - IN UCHAR fragNum, - OUT USHORT *FreeNumber); - -USHORT RtmpUSB_WriteMultiTxResource( - IN PRTMP_ADAPTER pAd, - IN TX_BLK *pTxBlk, - IN UCHAR frameNum, - OUT USHORT *FreeNumber); - -VOID RtmpUSB_FinalWriteTxResource( - IN PRTMP_ADAPTER pAd, - IN TX_BLK *pTxBlk, - IN USHORT totalMPDUSize, - IN USHORT TxIdx); - -VOID RtmpUSBDataLastTxIdx( - IN PRTMP_ADAPTER pAd, - IN UCHAR QueIdx, - IN USHORT TxIdx); - -VOID RtmpUSBDataKickOut( - IN PRTMP_ADAPTER pAd, - IN TX_BLK *pTxBlk, - IN UCHAR QueIdx); - - -int RtmpUSBMgmtKickOut( - IN RTMP_ADAPTER *pAd, - IN UCHAR QueIdx, - IN PNDIS_PACKET pPacket, - IN PUCHAR pSrcBufVA, - IN UINT SrcBufLen); - -VOID RtmpUSBNullFrameKickOut( - IN RTMP_ADAPTER *pAd, - IN UCHAR QueIdx, - IN UCHAR *pNullFrame, - IN UINT32 frameLen); - -VOID RT28xxUsbStaAsicForceWakeup( - IN PRTMP_ADAPTER pAd, - IN BOOLEAN bFromTx); - -VOID RT28xxUsbStaAsicSleepThenAutoWakeup( - IN PRTMP_ADAPTER pAd, - IN USHORT TbttNumToNextWakeUp); - -VOID RT28xxUsbMlmeRadioOn( - IN PRTMP_ADAPTER pAd); - -VOID RT28xxUsbMlmeRadioOFF( - IN PRTMP_ADAPTER pAd); -#endif // RT2870 // - -//////////////////////////////////////// - -VOID QBSS_LoadInit( - IN RTMP_ADAPTER *pAd); - -UINT32 QBSS_LoadElementAppend( - IN RTMP_ADAPTER *pAd, - OUT UINT8 *buf_p); - -VOID QBSS_LoadUpdate( - IN RTMP_ADAPTER *pAd); - -/////////////////////////////////////// -INT RTMPShowCfgValue( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pName, - IN PUCHAR pBuf); - -PCHAR RTMPGetRalinkAuthModeStr( - IN NDIS_802_11_AUTHENTICATION_MODE authMode); - -PCHAR RTMPGetRalinkEncryModeStr( - IN USHORT encryMode); -////////////////////////////////////// - -#ifdef CONFIG_STA_SUPPORT -VOID AsicStaBbpTuning( - IN PRTMP_ADAPTER pAd); - -BOOLEAN StaAddMacTableEntry( - IN PRTMP_ADAPTER pAd, - IN PMAC_TABLE_ENTRY pEntry, - IN UCHAR MaxSupportedRateIn500Kbps, - IN HT_CAPABILITY_IE *pHtCapability, - IN UCHAR HtCapabilityLen, - IN USHORT CapabilityInfo); -#endif // CONFIG_STA_SUPPORT // - -void RTMP_IndicateMediaState( - IN PRTMP_ADAPTER pAd); - -VOID ReSyncBeaconTime( - IN PRTMP_ADAPTER pAd); - -VOID RTMPSetAGCInitValue( - IN PRTMP_ADAPTER pAd, - IN UCHAR BandWidth); - -int rt28xx_close(IN PNET_DEV dev); -int rt28xx_open(IN PNET_DEV dev); - -__inline INT VIRTUAL_IF_UP(PRTMP_ADAPTER pAd) -{ -extern VOID MeshMakeBeacon(IN PRTMP_ADAPTER pAd, IN UCHAR idx); -extern VOID MeshUpdateBeaconFrame(IN PRTMP_ADAPTER pAd, IN UCHAR idx); - - if (VIRTUAL_IF_NUM(pAd) == 0) - { - if (rt28xx_open(pAd->net_dev) != 0) - return -1; - } - else - { - } - VIRTUAL_IF_INC(pAd); - return 0; -} - -__inline VOID VIRTUAL_IF_DOWN(PRTMP_ADAPTER pAd) -{ - VIRTUAL_IF_DEC(pAd); - if (VIRTUAL_IF_NUM(pAd) == 0) - rt28xx_close(pAd->net_dev); - return; -} - - -#endif // __RTMP_H__ - +#include "../rt2870/rtmp.h" diff --git a/drivers/staging/rt3070/rtmp_ckipmic.h b/drivers/staging/rt3070/rtmp_ckipmic.h index a3d949a39d39..4956093f4751 100644 --- a/drivers/staging/rt3070/rtmp_ckipmic.h +++ b/drivers/staging/rt3070/rtmp_ckipmic.h @@ -1,113 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - rtmp_ckipmic.h - - Abstract: - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Name Date Modification logs -*/ -#ifndef __RTMP_CKIPMIC_H__ -#define __RTMP_CKIPMIC_H__ - -typedef struct _MIC_CONTEXT { - /* --- MMH context */ - UCHAR CK[16]; /* the key */ - UCHAR coefficient[16]; /* current aes counter mode coefficients */ - ULONGLONG accum; /* accumulated mic, reduced to u32 in final() */ - UINT position; /* current position (byte offset) in message */ - UCHAR part[4]; /* for conversion of message to u32 for mmh */ -} MIC_CONTEXT, *PMIC_CONTEXT; - -VOID CKIP_key_permute( - OUT UCHAR *PK, /* output permuted key */ - IN UCHAR *CK, /* input CKIP key */ - IN UCHAR toDsFromDs, /* input toDs/FromDs bits */ - IN UCHAR *piv); /* input pointer to IV */ - -VOID RTMPCkipMicInit( - IN PMIC_CONTEXT pContext, - IN PUCHAR CK); - -VOID RTMPMicUpdate( - IN PMIC_CONTEXT pContext, - IN PUCHAR pOctets, - IN INT len); - -ULONG RTMPMicGetCoefficient( - IN PMIC_CONTEXT pContext); - -VOID xor_128( - IN PUCHAR a, - IN PUCHAR b, - OUT PUCHAR out); - -UCHAR RTMPCkipSbox( - IN UCHAR a); - -VOID xor_32( - IN PUCHAR a, - IN PUCHAR b, - OUT PUCHAR out); - -VOID next_key( - IN PUCHAR key, - IN INT round); - -VOID byte_sub( - IN PUCHAR in, - OUT PUCHAR out); - -VOID shift_row( - IN PUCHAR in, - OUT PUCHAR out); - -VOID mix_column( - IN PUCHAR in, - OUT PUCHAR out); - -VOID RTMPAesEncrypt( - IN PUCHAR key, - IN PUCHAR data, - IN PUCHAR ciphertext); - -VOID RTMPMicFinal( - IN PMIC_CONTEXT pContext, - OUT UCHAR digest[4]); - -VOID RTMPCkipInsertCMIC( - IN PRTMP_ADAPTER pAd, - OUT PUCHAR pMIC, - IN PUCHAR p80211hdr, - IN PNDIS_PACKET pPacket, - IN PCIPHER_KEY pKey, - IN PUCHAR mic_snap); - -#endif //__RTMP_CKIPMIC_H__ +#include "../rt2870/rtmp_ckipmic.h" diff --git a/drivers/staging/rt3070/rtmp_def.h b/drivers/staging/rt3070/rtmp_def.h index 2599f7c836e8..fa3b6b55cfee 100644 --- a/drivers/staging/rt3070/rtmp_def.h +++ b/drivers/staging/rt3070/rtmp_def.h @@ -1,1559 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - rtmp_def.h - - Abstract: - Miniport related definition header - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Paul Lin 08-01-2002 created - John Chang 08-05-2003 add definition for 11g & other drafts -*/ -#ifndef __RTMP_DEF_H__ -#define __RTMP_DEF_H__ - -#include "oid.h" - -#undef AP_WSC_INCLUDED -#undef STA_WSC_INCLUDED -#undef WSC_INCLUDED - - -#ifdef CONFIG_STA_SUPPORT -#endif // CONFIG_STA_SUPPORT // - -#if defined(AP_WSC_INCLUDED) || defined(STA_WSC_INCLUDED) -#define WSC_INCLUDED -#endif -// -// Debug information verbosity: lower values indicate higher urgency -// -#define RT_DEBUG_OFF 0 -#define RT_DEBUG_ERROR 1 -#define RT_DEBUG_WARN 2 -#define RT_DEBUG_TRACE 3 -#define RT_DEBUG_INFO 4 -#define RT_DEBUG_LOUD 5 - -#define NIC_TAG ((ULONG)'0682') -#define NIC_DBG_STRING ("**RT28xx**") - -#ifdef SNMP_SUPPORT -// for snmp -// to get manufacturer OUI, kathy, 2008_0220 -#define ManufacturerOUI_LEN 3 -#define ManufacturerNAME ("Ralink Technology Company.") -#define ResourceTypeIdName ("Ralink_ID") -#endif - - -//#define PACKED - -#define RALINK_2883_VERSION ((UINT32)0x28830300) -#define RALINK_2880E_VERSION ((UINT32)0x28720200) -#define RALINK_3070_VERSION ((UINT32)0x30700200) - -// -// NDIS version in use by the NIC driver. -// The high byte is the major version. The low byte is the minor version. -// -#ifdef NDIS51_MINIPORT -#define NIC_DRIVER_VERSION 0x0501 -#else -#define NIC_DRIVER_VERSION 0x0500 -#endif - -// -// NDIS media type, current is ethernet, change if native wireless supported -// -#define NIC_MEDIA_TYPE NdisMedium802_3 -#define NIC_PCI_HDR_LENGTH 0xe2 -#define NIC_MAX_PACKET_SIZE 2304 -#define NIC_HEADER_SIZE 14 -#define MAX_MAP_REGISTERS_NEEDED 32 -#define MIN_MAP_REGISTERS_NEEDED 2 //Todo: should consider fragment issue. - -// -// interface type, we use PCI -// -#define NIC_INTERFACE_TYPE NdisInterfacePci -#define NIC_INTERRUPT_MODE NdisInterruptLevelSensitive - -// -// buffer size passed in NdisMQueryAdapterResources -// We should only need three adapter resources (IO, interrupt and memory), -// Some devices get extra resources, so have room for 10 resources -// UF_SIZE (sizeof(NDIS_RESOURCE_LIST) + (10*sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR))) - - -#define NIC_RESOURCE_B// -// IO space length -// -#define NIC_MAP_IOSPACE_LENGTH sizeof(CSR_STRUC) - -#define MAX_RX_PKT_LEN 1520 - -// -// Entry number for each DMA descriptor ring -// - - -#ifdef RT2870 -#define TX_RING_SIZE 8 // 1 -#define PRIO_RING_SIZE 8 -#define MGMT_RING_SIZE 32 // PRIO_RING_SIZE -#define RX_RING_SIZE 8 -#define MAX_TX_PROCESS 4 -#define LOCAL_TXBUF_SIZE 2048 -#endif // RT2870 // - -#ifdef MULTIPLE_CARD_SUPPORT -// MC: Multple Cards -#define MAX_NUM_OF_MULTIPLE_CARD 32 -#endif // MULTIPLE_CARD_SUPPORT // - -#define MAX_RX_PROCESS 128 //64 //32 -#define NUM_OF_LOCAL_TXBUF 2 -#define TXD_SIZE 16 -#define TXWI_SIZE 16 -#define RXD_SIZE 16 -#define RXWI_SIZE 16 -// TXINFO_SIZE + TXWI_SIZE + 802.11 Header Size + AMSDU sub frame header -#define TX_DMA_1ST_BUFFER_SIZE 96 // only the 1st physical buffer is pre-allocated -#define MGMT_DMA_BUFFER_SIZE 1536 //2048 -#define RX_BUFFER_AGGRESIZE 3840 //3904 //3968 //4096 //2048 //4096 -#define RX_BUFFER_NORMSIZE 3840 //3904 //3968 //4096 //2048 //4096 -#define TX_BUFFER_NORMSIZE RX_BUFFER_NORMSIZE -#define MAX_FRAME_SIZE 2346 // Maximum 802.11 frame size -#define MAX_AGGREGATION_SIZE 3840 //3904 //3968 //4096 -#define MAX_NUM_OF_TUPLE_CACHE 2 -#define MAX_MCAST_LIST_SIZE 32 -#define MAX_LEN_OF_VENDOR_DESC 64 -//#define MAX_SIZE_OF_MCAST_PSQ (NUM_OF_LOCAL_TXBUF >> 2) // AP won't spend more than 1/4 of total buffers on M/BCAST PSQ -#define MAX_SIZE_OF_MCAST_PSQ 32 - -#define MAX_RX_PROCESS_CNT (RX_RING_SIZE) - - -#define MAX_PACKETS_IN_QUEUE (512) //(512) // to pass WMM A5-WPAPSK -#define MAX_PACKETS_IN_MCAST_PS_QUEUE 32 -#define MAX_PACKETS_IN_PS_QUEUE 128 //32 -#define WMM_NUM_OF_AC 4 /* AC0, AC1, AC2, and AC3 */ - - -//2008/09/11:KH add to support efuse<-- -#define MAX_EEPROM_BIN_FILE_SIZE 1024 -//2008/09/11:KH add to support efuse--> - -// RxFilter -#define STANORMAL 0x17f97 -#define APNORMAL 0x15f97 -// -// RTMP_ADAPTER flags -// -#define fRTMP_ADAPTER_MAP_REGISTER 0x00000001 -#define fRTMP_ADAPTER_INTERRUPT_IN_USE 0x00000002 -#define fRTMP_ADAPTER_HARDWARE_ERROR 0x00000004 -#define fRTMP_ADAPTER_SCATTER_GATHER 0x00000008 -#define fRTMP_ADAPTER_SEND_PACKET_ERROR 0x00000010 -#define fRTMP_ADAPTER_MLME_RESET_IN_PROGRESS 0x00000020 -#define fRTMP_ADAPTER_HALT_IN_PROGRESS 0x00000040 -#define fRTMP_ADAPTER_RESET_IN_PROGRESS 0x00000080 -#define fRTMP_ADAPTER_NIC_NOT_EXIST 0x00000100 -#define fRTMP_ADAPTER_TX_RING_ALLOCATED 0x00000200 -#define fRTMP_ADAPTER_REMOVE_IN_PROGRESS 0x00000400 -#define fRTMP_ADAPTER_MIMORATE_INUSED 0x00000800 -#define fRTMP_ADAPTER_RX_RING_ALLOCATED 0x00001000 -#define fRTMP_ADAPTER_INTERRUPT_ACTIVE 0x00002000 -#define fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS 0x00004000 -#define fRTMP_ADAPTER_REASSOC_IN_PROGRESS 0x00008000 -#define fRTMP_ADAPTER_MEDIA_STATE_PENDING 0x00010000 -#define fRTMP_ADAPTER_RADIO_OFF 0x00020000 -#define fRTMP_ADAPTER_BULKOUT_RESET 0x00040000 -#define fRTMP_ADAPTER_BULKIN_RESET 0x00080000 -#define fRTMP_ADAPTER_RDG_ACTIVE 0x00100000 -#define fRTMP_ADAPTER_DYNAMIC_BE_TXOP_ACTIVE 0x00200000 -#define fRTMP_ADAPTER_SCAN_2040 0x04000000 -#define fRTMP_ADAPTER_RADIO_MEASUREMENT 0x08000000 - -#define fRTMP_ADAPTER_START_UP 0x10000000 //Devive already initialized and enabled Tx/Rx. -#define fRTMP_ADAPTER_MEDIA_STATE_CHANGE 0x20000000 -#define fRTMP_ADAPTER_IDLE_RADIO_OFF 0x40000000 - -// Lock bit for accessing different ring buffers -//#define fRTMP_ADAPTER_TX_RING_BUSY 0x80000000 -//#define fRTMP_ADAPTER_MGMT_RING_BUSY 0x40000000 -//#define fRTMP_ADAPTER_ATIM_RING_BUSY 0x20000000 -//#define fRTMP_ADAPTER_RX_RING_BUSY 0x10000000 - -// Lock bit for accessing different queue -//#define fRTMP_ADAPTER_TX_QUEUE_BUSY 0x08000000 -//#define fRTMP_ADAPTER_MGMT_QUEUE_BUSY 0x04000000 - -// -// STA operation status flags -// -#define fOP_STATUS_INFRA_ON 0x00000001 -#define fOP_STATUS_ADHOC_ON 0x00000002 -#define fOP_STATUS_BG_PROTECTION_INUSED 0x00000004 -#define fOP_STATUS_SHORT_SLOT_INUSED 0x00000008 -#define fOP_STATUS_SHORT_PREAMBLE_INUSED 0x00000010 -#define fOP_STATUS_RECEIVE_DTIM 0x00000020 -//#define fOP_STATUS_TX_RATE_SWITCH_ENABLED 0x00000040 -#define fOP_STATUS_MEDIA_STATE_CONNECTED 0x00000080 -#define fOP_STATUS_WMM_INUSED 0x00000100 -#define fOP_STATUS_AGGREGATION_INUSED 0x00000200 -#define fOP_STATUS_DOZE 0x00000400 // debug purpose -#define fOP_STATUS_PIGGYBACK_INUSED 0x00000800 // piggy-back, and aggregation -#define fOP_STATUS_APSD_INUSED 0x00001000 -#define fOP_STATUS_TX_AMSDU_INUSED 0x00002000 -#define fOP_STATUS_MAX_RETRY_ENABLED 0x00004000 -#define fOP_STATUS_WAKEUP_NOW 0x00008000 -#define fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE 0x00020000 - -#ifdef DOT11N_DRAFT3 -#define fOP_STATUS_SCAN_2040 0x00040000 -#endif // DOT11N_DRAFT3 // - -#define CCKSETPROTECT 0x1 -#define OFDMSETPROTECT 0x2 -#define MM20SETPROTECT 0x4 -#define MM40SETPROTECT 0x8 -#define GF20SETPROTECT 0x10 -#define GR40SETPROTECT 0x20 -#define ALLN_SETPROTECT (GR40SETPROTECT | GF20SETPROTECT | MM40SETPROTECT | MM20SETPROTECT) - -// -// AP's client table operation status flags -// -#define fCLIENT_STATUS_WMM_CAPABLE 0x00000001 // CLIENT can parse QOS DATA frame -#define fCLIENT_STATUS_AGGREGATION_CAPABLE 0x00000002 // CLIENT can receive Ralink's proprietary TX aggregation frame -#define fCLIENT_STATUS_PIGGYBACK_CAPABLE 0x00000004 // CLIENT support piggy-back -#define fCLIENT_STATUS_AMSDU_INUSED 0x00000008 -#define fCLIENT_STATUS_SGI20_CAPABLE 0x00000010 -#define fCLIENT_STATUS_SGI40_CAPABLE 0x00000020 -#define fCLIENT_STATUS_TxSTBC_CAPABLE 0x00000040 -#define fCLIENT_STATUS_RxSTBC_CAPABLE 0x00000080 -#define fCLIENT_STATUS_HTC_CAPABLE 0x00000100 -#define fCLIENT_STATUS_RDG_CAPABLE 0x00000200 -#define fCLIENT_STATUS_MCSFEEDBACK_CAPABLE 0x00000400 -#define fCLIENT_STATUS_APSD_CAPABLE 0x00000800 /* UAPSD STATION */ - -#ifdef DOT11N_DRAFT3 -#define fCLIENT_STATUS_BSSCOEXIST_CAPABLE 0x00001000 -#endif // DOT11N_DRAFT3 // - -#define fCLIENT_STATUS_RALINK_CHIPSET 0x00100000 -// -// STA configuration flags -// -//#define fSTA_CFG_ENABLE_TX_BURST 0x00000001 - -// 802.11n Operating Mode Definition. 0-3 also used in ASICUPdateProtect switch case -#define HT_NO_PROTECT 0 -#define HT_LEGACY_PROTECT 1 -#define HT_40_PROTECT 2 -#define HT_2040_PROTECT 3 -#define HT_RTSCTS_6M 7 -//following is our own definition in order to turn on our ASIC protection register in INFRASTRUCTURE. -#define HT_ATHEROS 8 -#define HT_FORCERTSCTS 9 // Force turn on RTS/CTS first. then go to evaluate if this force RTS is necessary. - -// -// RX Packet Filter control flags. Apply on pAd->PacketFilter -// -#define fRX_FILTER_ACCEPT_DIRECT NDIS_PACKET_TYPE_DIRECTED -#define fRX_FILTER_ACCEPT_MULTICAST NDIS_PACKET_TYPE_MULTICAST -#define fRX_FILTER_ACCEPT_BROADCAST NDIS_PACKET_TYPE_BROADCAST -#define fRX_FILTER_ACCEPT_ALL_MULTICAST NDIS_PACKET_TYPE_ALL_MULTICAST - -// -// Error code section -// -// NDIS_ERROR_CODE_ADAPTER_NOT_FOUND -#define ERRLOG_READ_PCI_SLOT_FAILED 0x00000101L -#define ERRLOG_WRITE_PCI_SLOT_FAILED 0x00000102L -#define ERRLOG_VENDOR_DEVICE_NOMATCH 0x00000103L - -// NDIS_ERROR_CODE_ADAPTER_DISABLED -#define ERRLOG_BUS_MASTER_DISABLED 0x00000201L - -// NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION -#define ERRLOG_INVALID_SPEED_DUPLEX 0x00000301L -#define ERRLOG_SET_SECONDARY_FAILED 0x00000302L - -// NDIS_ERROR_CODE_OUT_OF_RESOURCES -#define ERRLOG_OUT_OF_MEMORY 0x00000401L -#define ERRLOG_OUT_OF_SHARED_MEMORY 0x00000402L -#define ERRLOG_OUT_OF_MAP_REGISTERS 0x00000403L -#define ERRLOG_OUT_OF_BUFFER_POOL 0x00000404L -#define ERRLOG_OUT_OF_NDIS_BUFFER 0x00000405L -#define ERRLOG_OUT_OF_PACKET_POOL 0x00000406L -#define ERRLOG_OUT_OF_NDIS_PACKET 0x00000407L -#define ERRLOG_OUT_OF_LOOKASIDE_MEMORY 0x00000408L - -// NDIS_ERROR_CODE_HARDWARE_FAILURE -#define ERRLOG_SELFTEST_FAILED 0x00000501L -#define ERRLOG_INITIALIZE_ADAPTER 0x00000502L -#define ERRLOG_REMOVE_MINIPORT 0x00000503L - -// NDIS_ERROR_CODE_RESOURCE_CONFLICT -#define ERRLOG_MAP_IO_SPACE 0x00000601L -#define ERRLOG_QUERY_ADAPTER_RESOURCES 0x00000602L -#define ERRLOG_NO_IO_RESOURCE 0x00000603L -#define ERRLOG_NO_INTERRUPT_RESOURCE 0x00000604L -#define ERRLOG_NO_MEMORY_RESOURCE 0x00000605L - - -// WDS definition -#define MAX_WDS_ENTRY 4 -#define WDS_PAIRWISE_KEY_OFFSET 60 // WDS links uses pairwise key#60 ~ 63 in ASIC pairwise key table - -#define WDS_DISABLE_MODE 0 -#define WDS_RESTRICT_MODE 1 -#define WDS_BRIDGE_MODE 2 -#define WDS_REPEATER_MODE 3 -#define WDS_LAZY_MODE 4 - - -#define MAX_MESH_NUM 0 - -#define MAX_APCLI_NUM 0 - -#define MAX_MBSSID_NUM 1 -#ifdef MBSS_SUPPORT -#undef MAX_MBSSID_NUM -#define MAX_MBSSID_NUM (8 - MAX_MESH_NUM - MAX_APCLI_NUM) -#endif // MBSS_SUPPORT // - -/* sanity check for apidx */ -#define MBSS_MR_APIDX_SANITY_CHECK(apidx) \ - { if (apidx > MAX_MBSSID_NUM) { \ - printk("%s> Error! apidx = %d > MAX_MBSSID_NUM!\n", __FUNCTION__, apidx); \ - apidx = MAIN_MBSSID; } } - -#define VALID_WCID(_wcid) ((_wcid) > 0 && (_wcid) < MAX_LEN_OF_MAC_TABLE ) - -#define MAIN_MBSSID 0 -#define FIRST_MBSSID 1 - - -#define MAX_BEACON_SIZE 512 -// If the MAX_MBSSID_NUM is larger than 6, -// it shall reserve some WCID space(wcid 222~253) for beacon frames. -// - these wcid 238~253 are reserved for beacon#6(ra6). -// - these wcid 222~237 are reserved for beacon#7(ra7). -#if defined(MAX_MBSSID_NUM) && (MAX_MBSSID_NUM == 8) -#define HW_RESERVED_WCID 222 -#elif defined(MAX_MBSSID_NUM) && (MAX_MBSSID_NUM == 7) -#define HW_RESERVED_WCID 238 -#else -#define HW_RESERVED_WCID 255 -#endif - -// Then dedicate wcid of DFS and Carrier-Sense. -#define DFS_CTS_WCID (HW_RESERVED_WCID - 1) -#define CS_CTS_WCID (HW_RESERVED_WCID - 2) -#define LAST_SPECIFIC_WCID (HW_RESERVED_WCID - 2) - -// If MAX_MBSSID_NUM is 8, the maximum available wcid for the associated STA is 211. -// If MAX_MBSSID_NUM is 7, the maximum available wcid for the associated STA is 228. -#define MAX_AVAILABLE_CLIENT_WCID (LAST_SPECIFIC_WCID - MAX_MBSSID_NUM - 1) - -// TX need WCID to find Cipher Key -// these wcid 212 ~ 219 are reserved for bc/mc packets if MAX_MBSSID_NUM is 8. -#define GET_GroupKey_WCID(__wcid, __bssidx) \ - { \ - __wcid = LAST_SPECIFIC_WCID - (MAX_MBSSID_NUM) + __bssidx; \ - } - -#define IsGroupKeyWCID(__wcid) (((__wcid) < LAST_SPECIFIC_WCID) && ((__wcid) >= (LAST_SPECIFIC_WCID - (MAX_MBSSID_NUM)))) - - -// definition to support multiple BSSID -#define BSS0 0 -#define BSS1 1 -#define BSS2 2 -#define BSS3 3 -#define BSS4 4 -#define BSS5 5 -#define BSS6 6 -#define BSS7 7 - - -//============================================================ -// Length definitions -#define PEER_KEY_NO 2 -#define MAC_ADDR_LEN 6 -#define TIMESTAMP_LEN 8 -#define MAX_LEN_OF_SUPPORTED_RATES MAX_LENGTH_OF_SUPPORT_RATES // 1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54 -#define MAX_LEN_OF_KEY 32 // 32 octets == 256 bits, Redefine for WPA -#define MAX_NUM_OF_CHANNELS MAX_NUM_OF_CHS // 14 channels @2.4G + 12@UNII + 4 @MMAC + 11 @HiperLAN2 + 7 @Japan + 1 as NULL termination -#define MAX_NUM_OF_11JCHANNELS 20 // 14 channels @2.4G + 12@UNII + 4 @MMAC + 11 @HiperLAN2 + 7 @Japan + 1 as NULL termination -#define MAX_LEN_OF_SSID 32 -#define CIPHER_TEXT_LEN 128 -#define HASH_TABLE_SIZE 256 -#define MAX_VIE_LEN 1024 // New for WPA cipher suite variable IE sizes. -#define MAX_SUPPORT_MCS 32 - -//============================================================ -// ASIC WCID Table definition. -//============================================================ -#define BSSID_WCID 1 // in infra mode, always put bssid with this WCID -#define MCAST_WCID 0x0 -#define BSS0Mcast_WCID 0x0 -#define BSS1Mcast_WCID 0xf8 -#define BSS2Mcast_WCID 0xf9 -#define BSS3Mcast_WCID 0xfa -#define BSS4Mcast_WCID 0xfb -#define BSS5Mcast_WCID 0xfc -#define BSS6Mcast_WCID 0xfd -#define BSS7Mcast_WCID 0xfe -#define RESERVED_WCID 0xff - -#define MAX_NUM_OF_ACL_LIST MAX_NUMBER_OF_ACL - -#define MAX_LEN_OF_MAC_TABLE MAX_NUMBER_OF_MAC // if MAX_MBSSID_NUM is 8, this value can't be larger than 211 - -#if MAX_LEN_OF_MAC_TABLE>MAX_AVAILABLE_CLIENT_WCID -#error MAX_LEN_OF_MAC_TABLE can not be larger than MAX_AVAILABLE_CLIENT_WCID!!!! -#endif - -#define MAX_NUM_OF_WDS_LINK_PERBSSID 3 -#define MAX_NUM_OF_WDS_LINK (MAX_NUM_OF_WDS_LINK_PERBSSID*MAX_MBSSID_NUM) -#define MAX_NUM_OF_EVENT MAX_NUMBER_OF_EVENT -#define WDS_LINK_START_WCID (MAX_LEN_OF_MAC_TABLE-1) - -#define NUM_OF_TID 8 -#define MAX_AID_BA 4 -#define MAX_LEN_OF_BA_REC_TABLE ((NUM_OF_TID * MAX_LEN_OF_MAC_TABLE)/2)// (NUM_OF_TID*MAX_AID_BA + 32) //Block ACK recipient -#define MAX_LEN_OF_BA_ORI_TABLE ((NUM_OF_TID * MAX_LEN_OF_MAC_TABLE)/2)// (NUM_OF_TID*MAX_AID_BA + 32) // Block ACK originator -#define MAX_LEN_OF_BSS_TABLE 64 -#define MAX_REORDERING_MPDU_NUM 512 - -// key related definitions -#define SHARE_KEY_NUM 4 -#define MAX_LEN_OF_SHARE_KEY 16 // byte count -#define MAX_LEN_OF_PEER_KEY 16 // byte count -#define PAIRWISE_KEY_NUM 64 // in MAC ASIC pairwise key table -#define GROUP_KEY_NUM 4 -#define PMK_LEN 32 -#define WDS_PAIRWISE_KEY_OFFSET 60 // WDS links uses pairwise key#60 ~ 63 in ASIC pairwise key table -#define PMKID_NO 4 // Number of PMKID saved supported -#define MAX_LEN_OF_MLME_BUFFER 2048 - -// power status related definitions -#define PWR_ACTIVE 0 -#define PWR_SAVE 1 -#define PWR_MMPS 2 //MIMO power save -//#define PWR_UNKNOWN 2 - -// Auth and Assoc mode related definitions -#define AUTH_MODE_OPEN 0x00 -#define AUTH_MODE_KEY 0x01 -//#define AUTH_MODE_AUTO_SWITCH 0x03 -//#define AUTH_MODE_DEAUTH 0x04 -//#define AUTH_MODE_UPLAYER 0x05 // reserved for 802.11i use - -// BSS Type definitions -#define BSS_ADHOC 0 // = Ndis802_11IBSS -#define BSS_INFRA 1 // = Ndis802_11Infrastructure -#define BSS_ANY 2 // = Ndis802_11AutoUnknown -#define BSS_MONITOR 3 // = Ndis802_11Monitor - - -// Reason code definitions -#define REASON_RESERVED 0 -#define REASON_UNSPECIFY 1 -#define REASON_NO_LONGER_VALID 2 -#define REASON_DEAUTH_STA_LEAVING 3 -#define REASON_DISASSOC_INACTIVE 4 -#define REASON_DISASSPC_AP_UNABLE 5 -#define REASON_CLS2ERR 6 -#define REASON_CLS3ERR 7 -#define REASON_DISASSOC_STA_LEAVING 8 -#define REASON_STA_REQ_ASSOC_NOT_AUTH 9 -#define REASON_INVALID_IE 13 -#define REASON_MIC_FAILURE 14 -#define REASON_4_WAY_TIMEOUT 15 -#define REASON_GROUP_KEY_HS_TIMEOUT 16 -#define REASON_IE_DIFFERENT 17 -#define REASON_MCIPHER_NOT_VALID 18 -#define REASON_UCIPHER_NOT_VALID 19 -#define REASON_AKMP_NOT_VALID 20 -#define REASON_UNSUPPORT_RSNE_VER 21 -#define REASON_INVALID_RSNE_CAP 22 -#define REASON_8021X_AUTH_FAIL 23 -#define REASON_CIPHER_SUITE_REJECTED 24 -#define REASON_DECLINED 37 - -#define REASON_QOS_UNSPECIFY 32 -#define REASON_QOS_LACK_BANDWIDTH 33 -#define REASON_POOR_CHANNEL_CONDITION 34 -#define REASON_QOS_OUTSIDE_TXOP_LIMITION 35 -#define REASON_QOS_QSTA_LEAVING_QBSS 36 -#define REASON_QOS_UNWANTED_MECHANISM 37 -#define REASON_QOS_MECH_SETUP_REQUIRED 38 -#define REASON_QOS_REQUEST_TIMEOUT 39 -#define REASON_QOS_CIPHER_NOT_SUPPORT 45 - -// Status code definitions -#define MLME_SUCCESS 0 -#define MLME_UNSPECIFY_FAIL 1 -#define MLME_CANNOT_SUPPORT_CAP 10 -#define MLME_REASSOC_DENY_ASSOC_EXIST 11 -#define MLME_ASSOC_DENY_OUT_SCOPE 12 -#define MLME_ALG_NOT_SUPPORT 13 -#define MLME_SEQ_NR_OUT_OF_SEQUENCE 14 -#define MLME_REJ_CHALLENGE_FAILURE 15 -#define MLME_REJ_TIMEOUT 16 -#define MLME_ASSOC_REJ_UNABLE_HANDLE_STA 17 -#define MLME_ASSOC_REJ_DATA_RATE 18 - -#define MLME_ASSOC_REJ_NO_EXT_RATE 22 -#define MLME_ASSOC_REJ_NO_EXT_RATE_PBCC 23 -#define MLME_ASSOC_REJ_NO_CCK_OFDM 24 - -#define MLME_QOS_UNSPECIFY 32 -#define MLME_REQUEST_DECLINED 37 -#define MLME_REQUEST_WITH_INVALID_PARAM 38 -#define MLME_DLS_NOT_ALLOW_IN_QBSS 48 -#define MLME_DEST_STA_NOT_IN_QBSS 49 -#define MLME_DEST_STA_IS_NOT_A_QSTA 50 - -#define MLME_INVALID_FORMAT 0x51 -#define MLME_FAIL_NO_RESOURCE 0x52 -#define MLME_STATE_MACHINE_REJECT 0x53 -#define MLME_MAC_TABLE_FAIL 0x54 - -// IE code -#define IE_SSID 0 -#define IE_SUPP_RATES 1 -#define IE_FH_PARM 2 -#define IE_DS_PARM 3 -#define IE_CF_PARM 4 -#define IE_TIM 5 -#define IE_IBSS_PARM 6 -#define IE_COUNTRY 7 // 802.11d -#define IE_802_11D_REQUEST 10 // 802.11d -#define IE_QBSS_LOAD 11 // 802.11e d9 -#define IE_EDCA_PARAMETER 12 // 802.11e d9 -#define IE_TSPEC 13 // 802.11e d9 -#define IE_TCLAS 14 // 802.11e d9 -#define IE_SCHEDULE 15 // 802.11e d9 -#define IE_CHALLENGE_TEXT 16 -#define IE_POWER_CONSTRAINT 32 // 802.11h d3.3 -#define IE_POWER_CAPABILITY 33 // 802.11h d3.3 -#define IE_TPC_REQUEST 34 // 802.11h d3.3 -#define IE_TPC_REPORT 35 // 802.11h d3.3 -#define IE_SUPP_CHANNELS 36 // 802.11h d3.3 -#define IE_CHANNEL_SWITCH_ANNOUNCEMENT 37 // 802.11h d3.3 -#define IE_MEASUREMENT_REQUEST 38 // 802.11h d3.3 -#define IE_MEASUREMENT_REPORT 39 // 802.11h d3.3 -#define IE_QUIET 40 // 802.11h d3.3 -#define IE_IBSS_DFS 41 // 802.11h d3.3 -#define IE_ERP 42 // 802.11g -#define IE_TS_DELAY 43 // 802.11e d9 -#define IE_TCLAS_PROCESSING 44 // 802.11e d9 -#define IE_QOS_CAPABILITY 46 // 802.11e d6 -#define IE_HT_CAP 45 // 802.11n d1. HT CAPABILITY. ELEMENT ID TBD -#define IE_AP_CHANNEL_REPORT 51 // 802.11k d6 -#define IE_HT_CAP2 52 // 802.11n d1. HT CAPABILITY. ELEMENT ID TBD -#define IE_RSN 48 // 802.11i d3.0 -#define IE_WPA2 48 // WPA2 -#define IE_EXT_SUPP_RATES 50 // 802.11g -#define IE_SUPP_REG_CLASS 59 // 802.11y. Supported regulatory classes. -#define IE_EXT_CHANNEL_SWITCH_ANNOUNCEMENT 60 // 802.11n -#define IE_ADD_HT 61 // 802.11n d1. ADDITIONAL HT CAPABILITY. ELEMENT ID TBD -#define IE_ADD_HT2 53 // 802.11n d1. ADDITIONAL HT CAPABILITY. ELEMENT ID TBD - - -// For 802.11n D3.03 -//#define IE_NEW_EXT_CHA_OFFSET 62 // 802.11n d1. New extension channel offset elemet -#define IE_SECONDARY_CH_OFFSET 62 // 802.11n D3.03 Secondary Channel Offset element -#define IE_WAPI 68 // WAPI information element -#define IE_2040_BSS_COEXIST 72 // 802.11n D3.0.3 -#define IE_2040_BSS_INTOLERANT_REPORT 73 // 802.11n D3.03 -#define IE_OVERLAPBSS_SCAN_PARM 74 // 802.11n D3.03 -#define IE_EXT_CAPABILITY 127 // 802.11n D3.03 - - -#define IE_WPA 221 // WPA -#define IE_VENDOR_SPECIFIC 221 // Wifi WMM (WME) - -#define OUI_BROADCOM_HT 51 // -#define OUI_BROADCOM_HTADD 52 // -#define OUI_PREN_HT_CAP 51 // -#define OUI_PREN_ADD_HT 52 // - -// CCX information -#define IE_AIRONET_CKIP 133 // CCX1.0 ID 85H for CKIP -#define IE_AP_TX_POWER 150 // CCX 2.0 for AP transmit power -#define IE_MEASUREMENT_CAPABILITY 221 // CCX 2.0 -#define IE_CCX_V2 221 -#define IE_AIRONET_IPADDRESS 149 // CCX ID 95H for IP Address -#define IE_AIRONET_CCKMREASSOC 156 // CCX ID 9CH for CCKM Reassociation Request element -#define CKIP_NEGOTIATION_LENGTH 30 -#define AIRONET_IPADDRESS_LENGTH 10 -#define AIRONET_CCKMREASSOC_LENGTH 24 - -// ======================================================== -// MLME state machine definition -// ======================================================== - -// STA MLME state mahcines -#define ASSOC_STATE_MACHINE 1 -#define AUTH_STATE_MACHINE 2 -#define AUTH_RSP_STATE_MACHINE 3 -#define SYNC_STATE_MACHINE 4 -#define MLME_CNTL_STATE_MACHINE 5 -#define WPA_PSK_STATE_MACHINE 6 -#define LEAP_STATE_MACHINE 7 -#define AIRONET_STATE_MACHINE 8 -#define ACTION_STATE_MACHINE 9 - -// AP MLME state machines -#define AP_ASSOC_STATE_MACHINE 11 -#define AP_AUTH_STATE_MACHINE 12 -#define AP_AUTH_RSP_STATE_MACHINE 13 -#define AP_SYNC_STATE_MACHINE 14 -#define AP_CNTL_STATE_MACHINE 15 -#define AP_WPA_STATE_MACHINE 16 - -#define WSC_STATE_MACHINE 17 -#define WSC_UPNP_STATE_MACHINE 18 - - - -#ifdef QOS_DLS_SUPPORT -#define DLS_STATE_MACHINE 26 -#endif // QOS_DLS_SUPPORT // - -// -// STA's CONTROL/CONNECT state machine: states, events, total function # -// -#define CNTL_IDLE 0 -#define CNTL_WAIT_DISASSOC 1 -#define CNTL_WAIT_JOIN 2 -#define CNTL_WAIT_REASSOC 3 -#define CNTL_WAIT_START 4 -#define CNTL_WAIT_AUTH 5 -#define CNTL_WAIT_ASSOC 6 -#define CNTL_WAIT_AUTH2 7 -#define CNTL_WAIT_OID_LIST_SCAN 8 -#define CNTL_WAIT_OID_DISASSOC 9 -#ifdef RT2870 -#define CNTL_WAIT_SCAN_FOR_CONNECT 10 -#endif // RT2870 // - -#define MT2_ASSOC_CONF 34 -#define MT2_AUTH_CONF 35 -#define MT2_DEAUTH_CONF 36 -#define MT2_DISASSOC_CONF 37 -#define MT2_REASSOC_CONF 38 -#define MT2_PWR_MGMT_CONF 39 -#define MT2_JOIN_CONF 40 -#define MT2_SCAN_CONF 41 -#define MT2_START_CONF 42 -#define MT2_GET_CONF 43 -#define MT2_SET_CONF 44 -#define MT2_RESET_CONF 45 -#define MT2_MLME_ROAMING_REQ 52 - -#define CNTL_FUNC_SIZE 1 - -// -// STA's ASSOC state machine: states, events, total function # -// -#define ASSOC_IDLE 0 -#define ASSOC_WAIT_RSP 1 -#define REASSOC_WAIT_RSP 2 -#define DISASSOC_WAIT_RSP 3 -#define MAX_ASSOC_STATE 4 - -#define ASSOC_MACHINE_BASE 0 -#define MT2_MLME_ASSOC_REQ 0 -#define MT2_MLME_REASSOC_REQ 1 -#define MT2_MLME_DISASSOC_REQ 2 -#define MT2_PEER_DISASSOC_REQ 3 -#define MT2_PEER_ASSOC_REQ 4 -#define MT2_PEER_ASSOC_RSP 5 -#define MT2_PEER_REASSOC_REQ 6 -#define MT2_PEER_REASSOC_RSP 7 -#define MT2_DISASSOC_TIMEOUT 8 -#define MT2_ASSOC_TIMEOUT 9 -#define MT2_REASSOC_TIMEOUT 10 -#define MAX_ASSOC_MSG 11 - -#define ASSOC_FUNC_SIZE (MAX_ASSOC_STATE * MAX_ASSOC_MSG) - -// -// ACT state machine: states, events, total function # -// -#define ACT_IDLE 0 -#define MAX_ACT_STATE 1 - -#define ACT_MACHINE_BASE 0 - -//Those PEER_xx_CATE number is based on real Categary value in IEEE spec. Please don'es modify it by your self. -//Category -#define MT2_PEER_SPECTRUM_CATE 0 -#define MT2_PEER_QOS_CATE 1 -#define MT2_PEER_DLS_CATE 2 -#define MT2_PEER_BA_CATE 3 -#define MT2_PEER_PUBLIC_CATE 4 -#define MT2_PEER_RM_CATE 5 -#define MT2_PEER_HT_CATE 7 // 7.4.7 -#define MAX_PEER_CATE_MSG 7 -#define MT2_MLME_ADD_BA_CATE 8 -#define MT2_MLME_ORI_DELBA_CATE 9 -#define MT2_MLME_REC_DELBA_CATE 10 -#define MT2_MLME_QOS_CATE 11 -#define MT2_MLME_DLS_CATE 12 -#define MT2_ACT_INVALID 13 -#define MAX_ACT_MSG 14 - -//Category field -#define CATEGORY_SPECTRUM 0 -#define CATEGORY_QOS 1 -#define CATEGORY_DLS 2 -#define CATEGORY_BA 3 -#define CATEGORY_PUBLIC 4 -#define CATEGORY_RM 5 -#define CATEGORY_HT 7 - - -// DLS Action frame definition -#define ACTION_DLS_REQUEST 0 -#define ACTION_DLS_RESPONSE 1 -#define ACTION_DLS_TEARDOWN 2 - -//Spectrum Action field value 802.11h 7.4.1 -#define SPEC_MRQ 0 // Request -#define SPEC_MRP 1 //Report -#define SPEC_TPCRQ 2 -#define SPEC_TPCRP 3 -#define SPEC_CHANNEL_SWITCH 4 - - -//BA Action field value -#define ADDBA_REQ 0 -#define ADDBA_RESP 1 -#define DELBA 2 - -//Public's Action field value in Public Category. Some in 802.11y and some in 11n -#define ACTION_BSS_2040_COEXIST 0 // 11n -#define ACTION_DSE_ENABLEMENT 1 // 11y D9.0 -#define ACTION_DSE_DEENABLEMENT 2 // 11y D9.0 -#define ACTION_DSE_REG_LOCATION_ANNOUNCE 3 // 11y D9.0 -#define ACTION_EXT_CH_SWITCH_ANNOUNCE 4 // 11y D9.0 -#define ACTION_DSE_MEASUREMENT_REQ 5 // 11y D9.0 -#define ACTION_DSE_MEASUREMENT_REPORT 6 // 11y D9.0 -#define ACTION_MEASUREMENT_PILOT_ACTION 7 // 11y D9.0 -#define ACTION_DSE_POWER_CONSTRAINT 8 // 11y D9.0 - - -//HT Action field value -#define NOTIFY_BW_ACTION 0 -#define SMPS_ACTION 1 -#define PSMP_ACTION 2 -#define SETPCO_ACTION 3 -#define MIMO_CHA_MEASURE_ACTION 4 -#define MIMO_N_BEACONFORM 5 -#define MIMO_BEACONFORM 6 -#define ANTENNA_SELECT 7 -#define HT_INFO_EXCHANGE 8 - -#define ACT_FUNC_SIZE (MAX_ACT_STATE * MAX_ACT_MSG) -// -// STA's AUTHENTICATION state machine: states, evvents, total function # -// -#define AUTH_REQ_IDLE 0 -#define AUTH_WAIT_SEQ2 1 -#define AUTH_WAIT_SEQ4 2 -#define MAX_AUTH_STATE 3 - -#define AUTH_MACHINE_BASE 0 -#define MT2_MLME_AUTH_REQ 0 -#define MT2_PEER_AUTH_EVEN 1 -#define MT2_AUTH_TIMEOUT 2 -#define MAX_AUTH_MSG 3 - -#define AUTH_FUNC_SIZE (MAX_AUTH_STATE * MAX_AUTH_MSG) - -// -// STA's AUTH_RSP state machine: states, events, total function # -// -#define AUTH_RSP_IDLE 0 -#define AUTH_RSP_WAIT_CHAL 1 -#define MAX_AUTH_RSP_STATE 2 - -#define AUTH_RSP_MACHINE_BASE 0 -#define MT2_AUTH_CHALLENGE_TIMEOUT 0 -#define MT2_PEER_AUTH_ODD 1 -#define MT2_PEER_DEAUTH 2 -#define MAX_AUTH_RSP_MSG 3 - -#define AUTH_RSP_FUNC_SIZE (MAX_AUTH_RSP_STATE * MAX_AUTH_RSP_MSG) - -// -// STA's SYNC state machine: states, events, total function # -// -#define SYNC_IDLE 0 // merge NO_BSS,IBSS_IDLE,IBSS_ACTIVE and BSS in to 1 state -#define JOIN_WAIT_BEACON 1 -#define SCAN_LISTEN 2 -#define MAX_SYNC_STATE 3 - -#define SYNC_MACHINE_BASE 0 -#define MT2_MLME_SCAN_REQ 0 -#define MT2_MLME_JOIN_REQ 1 -#define MT2_MLME_START_REQ 2 -#define MT2_PEER_BEACON 3 -#define MT2_PEER_PROBE_RSP 4 -#define MT2_PEER_ATIM 5 -#define MT2_SCAN_TIMEOUT 6 -#define MT2_BEACON_TIMEOUT 7 -#define MT2_ATIM_TIMEOUT 8 -#define MT2_PEER_PROBE_REQ 9 -#define MAX_SYNC_MSG 10 - -#define SYNC_FUNC_SIZE (MAX_SYNC_STATE * MAX_SYNC_MSG) - -//Messages for the DLS state machine -#define DLS_IDLE 0 -#define MAX_DLS_STATE 1 - -#define DLS_MACHINE_BASE 0 -#define MT2_MLME_DLS_REQ 0 -#define MT2_PEER_DLS_REQ 1 -#define MT2_PEER_DLS_RSP 2 -#define MT2_MLME_DLS_TEAR_DOWN 3 -#define MT2_PEER_DLS_TEAR_DOWN 4 -#define MAX_DLS_MSG 5 - -#define DLS_FUNC_SIZE (MAX_DLS_STATE * MAX_DLS_MSG) - -// -// STA's WPA-PSK State machine: states, events, total function # -// -#define WPA_PSK_IDLE 0 -#define MAX_WPA_PSK_STATE 1 - -#define WPA_MACHINE_BASE 0 -#define MT2_EAPPacket 0 -#define MT2_EAPOLStart 1 -#define MT2_EAPOLLogoff 2 -#define MT2_EAPOLKey 3 -#define MT2_EAPOLASFAlert 4 -#define MAX_WPA_PSK_MSG 5 - -#define WPA_PSK_FUNC_SIZE (MAX_WPA_PSK_STATE * MAX_WPA_PSK_MSG) - -// -// STA's CISCO-AIRONET State machine: states, events, total function # -// -#define AIRONET_IDLE 0 -#define AIRONET_SCANNING 1 -#define MAX_AIRONET_STATE 2 - -#define AIRONET_MACHINE_BASE 0 -#define MT2_AIRONET_MSG 0 -#define MT2_AIRONET_SCAN_REQ 1 -#define MT2_AIRONET_SCAN_DONE 2 -#define MAX_AIRONET_MSG 3 - -#define AIRONET_FUNC_SIZE (MAX_AIRONET_STATE * MAX_AIRONET_MSG) - -// -// WSC State machine: states, events, total function # -// - -// -// AP's CONTROL/CONNECT state machine: states, events, total function # -// -#define AP_CNTL_FUNC_SIZE 1 - -// -// AP's ASSOC state machine: states, events, total function # -// -#define AP_ASSOC_IDLE 0 -#define AP_MAX_ASSOC_STATE 1 - -#define AP_ASSOC_MACHINE_BASE 0 -#define APMT2_MLME_DISASSOC_REQ 0 -#define APMT2_PEER_DISASSOC_REQ 1 -#define APMT2_PEER_ASSOC_REQ 2 -#define APMT2_PEER_REASSOC_REQ 3 -#define APMT2_CLS3ERR 4 -#define AP_MAX_ASSOC_MSG 5 - -#define AP_ASSOC_FUNC_SIZE (AP_MAX_ASSOC_STATE * AP_MAX_ASSOC_MSG) - -// -// AP's AUTHENTICATION state machine: states, events, total function # -// -#define AP_AUTH_REQ_IDLE 0 -#define AP_MAX_AUTH_STATE 1 - -#define AP_AUTH_MACHINE_BASE 0 -#define APMT2_MLME_DEAUTH_REQ 0 -#define APMT2_CLS2ERR 1 -#define AP_MAX_AUTH_MSG 2 - -#define AP_AUTH_FUNC_SIZE (AP_MAX_AUTH_STATE * AP_MAX_AUTH_MSG) - -// -// AP's AUTH-RSP state machine: states, events, total function # -// -#define AP_AUTH_RSP_IDLE 0 -#define AP_MAX_AUTH_RSP_STATE 1 - -#define AP_AUTH_RSP_MACHINE_BASE 0 -#define APMT2_AUTH_CHALLENGE_TIMEOUT 0 -#define APMT2_PEER_AUTH_ODD 1 -#define APMT2_PEER_DEAUTH 2 -#define AP_MAX_AUTH_RSP_MSG 3 - -#define AP_AUTH_RSP_FUNC_SIZE (AP_MAX_AUTH_RSP_STATE * AP_MAX_AUTH_RSP_MSG) - -// -// AP's SYNC state machine: states, events, total function # -// -#define AP_SYNC_IDLE 0 -#define AP_SCAN_LISTEN 1 -#define AP_MAX_SYNC_STATE 2 - -#define AP_SYNC_MACHINE_BASE 0 -#define APMT2_PEER_PROBE_REQ 0 -#define APMT2_PEER_BEACON 1 -#define APMT2_MLME_SCAN_REQ 2 -#define APMT2_PEER_PROBE_RSP 3 -#define APMT2_SCAN_TIMEOUT 4 -#define APMT2_MLME_SCAN_CNCL 5 -#define AP_MAX_SYNC_MSG 6 - -#define AP_SYNC_FUNC_SIZE (AP_MAX_SYNC_STATE * AP_MAX_SYNC_MSG) - -// -// AP's WPA state machine: states, events, total function # -// -#define AP_WPA_PTK 0 -#define AP_MAX_WPA_PTK_STATE 1 - -#define AP_WPA_MACHINE_BASE 0 -#define APMT2_EAPPacket 0 -#define APMT2_EAPOLStart 1 -#define APMT2_EAPOLLogoff 2 -#define APMT2_EAPOLKey 3 -#define APMT2_EAPOLASFAlert 4 -#define AP_MAX_WPA_MSG 5 - -#define AP_WPA_FUNC_SIZE (AP_MAX_WPA_PTK_STATE * AP_MAX_WPA_MSG) - - - -// ============================================================================= - -// value domain of 802.11 header FC.Tyte, which is b3..b2 of the 1st-byte of MAC header -#define BTYPE_MGMT 0 -#define BTYPE_CNTL 1 -#define BTYPE_DATA 2 - -// value domain of 802.11 MGMT frame's FC.subtype, which is b7..4 of the 1st-byte of MAC header -#define SUBTYPE_ASSOC_REQ 0 -#define SUBTYPE_ASSOC_RSP 1 -#define SUBTYPE_REASSOC_REQ 2 -#define SUBTYPE_REASSOC_RSP 3 -#define SUBTYPE_PROBE_REQ 4 -#define SUBTYPE_PROBE_RSP 5 -#define SUBTYPE_BEACON 8 -#define SUBTYPE_ATIM 9 -#define SUBTYPE_DISASSOC 10 -#define SUBTYPE_AUTH 11 -#define SUBTYPE_DEAUTH 12 -#define SUBTYPE_ACTION 13 -#define SUBTYPE_ACTION_NO_ACK 14 - -// value domain of 802.11 CNTL frame's FC.subtype, which is b7..4 of the 1st-byte of MAC header -#define SUBTYPE_WRAPPER 7 -#define SUBTYPE_BLOCK_ACK_REQ 8 -#define SUBTYPE_BLOCK_ACK 9 -#define SUBTYPE_PS_POLL 10 -#define SUBTYPE_RTS 11 -#define SUBTYPE_CTS 12 -#define SUBTYPE_ACK 13 -#define SUBTYPE_CFEND 14 -#define SUBTYPE_CFEND_CFACK 15 - -// value domain of 802.11 DATA frame's FC.subtype, which is b7..4 of the 1st-byte of MAC header -#define SUBTYPE_DATA 0 -#define SUBTYPE_DATA_CFACK 1 -#define SUBTYPE_DATA_CFPOLL 2 -#define SUBTYPE_DATA_CFACK_CFPOLL 3 -#define SUBTYPE_NULL_FUNC 4 -#define SUBTYPE_CFACK 5 -#define SUBTYPE_CFPOLL 6 -#define SUBTYPE_CFACK_CFPOLL 7 -#define SUBTYPE_QDATA 8 -#define SUBTYPE_QDATA_CFACK 9 -#define SUBTYPE_QDATA_CFPOLL 10 -#define SUBTYPE_QDATA_CFACK_CFPOLL 11 -#define SUBTYPE_QOS_NULL 12 -#define SUBTYPE_QOS_CFACK 13 -#define SUBTYPE_QOS_CFPOLL 14 -#define SUBTYPE_QOS_CFACK_CFPOLL 15 - -// ACK policy of QOS Control field bit 6:5 -#define NORMAL_ACK 0x00 // b6:5 = 00 -#define NO_ACK 0x20 // b6:5 = 01 -#define NO_EXPLICIT_ACK 0x40 // b6:5 = 10 -#define BLOCK_ACK 0x60 // b6:5 = 11 - -// -// rtmp_data.c use these definition -// -#define LENGTH_802_11 24 -#define LENGTH_802_11_AND_H 30 -#define LENGTH_802_11_CRC_H 34 -#define LENGTH_802_11_CRC 28 -#define LENGTH_802_11_WITH_ADDR4 30 -#define LENGTH_802_3 14 -#define LENGTH_802_3_TYPE 2 -#define LENGTH_802_1_H 8 -#define LENGTH_EAPOL_H 4 -#define LENGTH_WMMQOS_H 2 -#define LENGTH_CRC 4 -#define MAX_SEQ_NUMBER 0x0fff -#define LENGTH_802_3_NO_TYPE 12 -#define LENGTH_802_1Q 4 /* VLAN related */ - -// STA_CSR4.field.TxResult -#define TX_RESULT_SUCCESS 0 -#define TX_RESULT_ZERO_LENGTH 1 -#define TX_RESULT_UNDER_RUN 2 -#define TX_RESULT_OHY_ERROR 4 -#define TX_RESULT_RETRY_FAIL 6 - -// All PHY rate summary in TXD -// Preamble MODE in TxD -#define MODE_CCK 0 -#define MODE_OFDM 1 -#ifdef DOT11_N_SUPPORT -#define MODE_HTMIX 2 -#define MODE_HTGREENFIELD 3 -#endif // DOT11_N_SUPPORT // -// MCS for CCK. BW.SGI.STBC are reserved -#define MCS_LONGP_RATE_1 0 // long preamble CCK 1Mbps -#define MCS_LONGP_RATE_2 1 // long preamble CCK 1Mbps -#define MCS_LONGP_RATE_5_5 2 -#define MCS_LONGP_RATE_11 3 -#define MCS_SHORTP_RATE_1 4 // long preamble CCK 1Mbps. short is forbidden in 1Mbps -#define MCS_SHORTP_RATE_2 5 // short preamble CCK 2Mbps -#define MCS_SHORTP_RATE_5_5 6 -#define MCS_SHORTP_RATE_11 7 -// To send duplicate legacy OFDM. set BW=BW_40. SGI.STBC are reserved -#define MCS_RATE_6 0 // legacy OFDM -#define MCS_RATE_9 1 // OFDM -#define MCS_RATE_12 2 // OFDM -#define MCS_RATE_18 3 // OFDM -#define MCS_RATE_24 4 // OFDM -#define MCS_RATE_36 5 // OFDM -#define MCS_RATE_48 6 // OFDM -#define MCS_RATE_54 7 // OFDM -// HT -#define MCS_0 0 // 1S -#define MCS_1 1 -#define MCS_2 2 -#define MCS_3 3 -#define MCS_4 4 -#define MCS_5 5 -#define MCS_6 6 -#define MCS_7 7 -#define MCS_8 8 // 2S -#define MCS_9 9 -#define MCS_10 10 -#define MCS_11 11 -#define MCS_12 12 -#define MCS_13 13 -#define MCS_14 14 -#define MCS_15 15 -#define MCS_16 16 // 3*3 -#define MCS_17 17 -#define MCS_18 18 -#define MCS_19 19 -#define MCS_20 20 -#define MCS_21 21 -#define MCS_22 22 -#define MCS_23 23 -#define MCS_32 32 -#define MCS_AUTO 33 - -#ifdef DOT11_N_SUPPORT -// OID_HTPHYMODE -// MODE -#define HTMODE_MM 0 -#define HTMODE_GF 1 -#endif // DOT11_N_SUPPORT // - -// Fixed Tx MODE - HT, CCK or OFDM -#define FIXED_TXMODE_HT 0 -#define FIXED_TXMODE_CCK 1 -#define FIXED_TXMODE_OFDM 2 -// BW -#define BW_20 BAND_WIDTH_20 -#define BW_40 BAND_WIDTH_40 -#define BW_BOTH BAND_WIDTH_BOTH -#define BW_10 BAND_WIDTH_10 // 802.11j has 10MHz. This definition is for internal usage. doesn't fill in the IE or other field. - -#ifdef DOT11_N_SUPPORT -// SHORTGI -#define GI_400 GAP_INTERVAL_400 // only support in HT mode -#define GI_BOTH GAP_INTERVAL_BOTH -#endif // DOT11_N_SUPPORT // -#define GI_800 GAP_INTERVAL_800 -// STBC -#define STBC_NONE 0 -#ifdef DOT11_N_SUPPORT -#define STBC_USE 1 // limited use in rt2860b phy -#define RXSTBC_ONE 1 // rx support of one spatial stream -#define RXSTBC_TWO 2 // rx support of 1 and 2 spatial stream -#define RXSTBC_THR 3 // rx support of 1~3 spatial stream -// MCS FEEDBACK -#define MCSFBK_NONE 0 // not support mcs feedback / -#define MCSFBK_RSV 1 // reserved -#define MCSFBK_UNSOLICIT 2 // only support unsolict mcs feedback -#define MCSFBK_MRQ 3 // response to both MRQ and unsolict mcs feedback - -// MIMO power safe -#define MMPS_STATIC 0 -#define MMPS_DYNAMIC 1 -#define MMPS_RSV 2 -#define MMPS_ENABLE 3 - - -// A-MSDU size -#define AMSDU_0 0 -#define AMSDU_1 1 - -#endif // DOT11_N_SUPPORT // - -// MCS use 7 bits -#define TXRATEMIMO 0x80 -#define TXRATEMCS 0x7F -#define TXRATEOFDM 0x7F -#define RATE_1 0 -#define RATE_2 1 -#define RATE_5_5 2 -#define RATE_11 3 -#define RATE_6 4 // OFDM -#define RATE_9 5 // OFDM -#define RATE_12 6 // OFDM -#define RATE_18 7 // OFDM -#define RATE_24 8 // OFDM -#define RATE_36 9 // OFDM -#define RATE_48 10 // OFDM -#define RATE_54 11 // OFDM -#define RATE_FIRST_OFDM_RATE RATE_6 -#define RATE_LAST_OFDM_RATE RATE_54 -#define RATE_6_5 12 // HT mix -#define RATE_13 13 // HT mix -#define RATE_19_5 14 // HT mix -#define RATE_26 15 // HT mix -#define RATE_39 16 // HT mix -#define RATE_52 17 // HT mix -#define RATE_58_5 18 // HT mix -#define RATE_65 19 // HT mix -#define RATE_78 20 // HT mix -#define RATE_104 21 // HT mix -#define RATE_117 22 // HT mix -#define RATE_130 23 // HT mix -//#define RATE_AUTO_SWITCH 255 // for StaCfg.FixedTxRate only -#define HTRATE_0 12 -#define RATE_FIRST_MM_RATE HTRATE_0 -#define RATE_FIRST_HT_RATE HTRATE_0 -#define RATE_LAST_HT_RATE HTRATE_0 - -// pTxWI->txop -#define IFS_HTTXOP 0 // The txop will be handles by ASIC. -#define IFS_PIFS 1 -#define IFS_SIFS 2 -#define IFS_BACKOFF 3 - -// pTxD->RetryMode -#define LONG_RETRY 1 -#define SHORT_RETRY 0 - -// Country Region definition -#define REGION_MINIMUM_BG_BAND 0 -#define REGION_0_BG_BAND 0 // 1-11 -#define REGION_1_BG_BAND 1 // 1-13 -#define REGION_2_BG_BAND 2 // 10-11 -#define REGION_3_BG_BAND 3 // 10-13 -#define REGION_4_BG_BAND 4 // 14 -#define REGION_5_BG_BAND 5 // 1-14 -#define REGION_6_BG_BAND 6 // 3-9 -#define REGION_7_BG_BAND 7 // 5-13 -#define REGION_31_BG_BAND 31 // 5-13 -#define REGION_MAXIMUM_BG_BAND 7 - -#define REGION_MINIMUM_A_BAND 0 -#define REGION_0_A_BAND 0 // 36, 40, 44, 48, 52, 56, 60, 64, 149, 153, 157, 161, 165 -#define REGION_1_A_BAND 1 // 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140 -#define REGION_2_A_BAND 2 // 36, 40, 44, 48, 52, 56, 60, 64 -#define REGION_3_A_BAND 3 // 52, 56, 60, 64, 149, 153, 157, 161 -#define REGION_4_A_BAND 4 // 149, 153, 157, 161, 165 -#define REGION_5_A_BAND 5 // 149, 153, 157, 161 -#define REGION_6_A_BAND 6 // 36, 40, 44, 48 -#define REGION_7_A_BAND 7 // 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165 -#define REGION_8_A_BAND 8 // 52, 56, 60, 64 -#define REGION_9_A_BAND 9 // 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 132, 136, 140, 149, 153, 157, 161, 165 -#define REGION_10_A_BAND 10 // 36, 40, 44, 48, 149, 153, 157, 161, 165 -#define REGION_11_A_BAND 11 // 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 149, 153, 157, 161 -#define REGION_MAXIMUM_A_BAND 11 - -// pTxD->CipherAlg -#define CIPHER_NONE 0 -#define CIPHER_WEP64 1 -#define CIPHER_WEP128 2 -#define CIPHER_TKIP 3 -#define CIPHER_AES 4 -#define CIPHER_CKIP64 5 -#define CIPHER_CKIP128 6 -#define CIPHER_TKIP_NO_MIC 7 // MIC appended by driver: not a valid value in hardware key table -#define CIPHER_SMS4 8 - -// value domain of pAd->RfIcType -#define RFIC_2820 1 // 2.4G 2T3R -#define RFIC_2850 2 // 2.4G/5G 2T3R -#define RFIC_2720 3 // 2.4G 1T2R -#define RFIC_2750 4 // 2.4G/5G 1T2R -#define RFIC_3020 5 // 2.4G 1T1R -#define RFIC_2020 6 // 2.4G B/G -#define RFIC_3021 7 // 2.4G 1T2R -#define RFIC_3022 8 // 2.4G 2T2R - -// LED Status. -#define LED_LINK_DOWN 0 -#define LED_LINK_UP 1 -#define LED_RADIO_OFF 2 -#define LED_RADIO_ON 3 -#define LED_HALT 4 -#define LED_WPS 5 -#define LED_ON_SITE_SURVEY 6 -#define LED_POWER_UP 7 - -// value domain of pAd->LedCntl.LedMode and E2PROM -#define LED_MODE_DEFAULT 0 -#define LED_MODE_TWO_LED 1 -#define LED_MODE_SIGNAL_STREGTH 8 // EEPROM define =8 - -// RC4 init value, used fro WEP & TKIP -#define PPPINITFCS32 0xffffffff /* Initial FCS value */ - -// value domain of pAd->StaCfg.PortSecured. 802.1X controlled port definition -#define WPA_802_1X_PORT_SECURED 1 -#define WPA_802_1X_PORT_NOT_SECURED 2 - -#define PAIRWISE_KEY 1 -#define GROUP_KEY 2 - -//definition of DRS -#define MAX_STEP_OF_TX_RATE_SWITCH 32 - - -// pre-allocated free NDIS PACKET/BUFFER poll for internal usage -#define MAX_NUM_OF_FREE_NDIS_PACKET 128 - -//Block ACK -#define MAX_TX_REORDERBUF 64 -#define MAX_RX_REORDERBUF 64 -#define DEFAULT_TX_TIMEOUT 30 -#define DEFAULT_RX_TIMEOUT 30 - -// definition of Recipient or Originator -#define I_RECIPIENT TRUE -#define I_ORIGINATOR FALSE - -#define DEFAULT_BBP_TX_POWER 0 -#define DEFAULT_RF_TX_POWER 5 - -#define MAX_INI_BUFFER_SIZE 4096 -#define MAX_PARAM_BUFFER_SIZE (2048) // enough for ACL (18*64) - //18 : the length of Mac address acceptable format "01:02:03:04:05:06;") - //64 : MAX_NUM_OF_ACL_LIST -// definition of pAd->OpMode -#define OPMODE_STA 0 -#define OPMODE_AP 1 -//#define OPMODE_L3_BRG 2 // as AP and STA at the same time - -#ifdef RT_BIG_ENDIAN -#define DIR_READ 0 -#define DIR_WRITE 1 -#define TYPE_TXD 0 -#define TYPE_RXD 1 -#define TYPE_TXINFO 0 -#define TYPE_RXINFO 1 -#define TYPE_TXWI 0 -#define TYPE_RXWI 1 -#endif - -// ========================= AP rtmp_def.h =========================== -// value domain for pAd->EventTab.Log[].Event -#define EVENT_RESET_ACCESS_POINT 0 // Log = "hh:mm:ss Restart Access Point" -#define EVENT_ASSOCIATED 1 // Log = "hh:mm:ss STA 00:01:02:03:04:05 associated" -#define EVENT_DISASSOCIATED 2 // Log = "hh:mm:ss STA 00:01:02:03:04:05 left this BSS" -#define EVENT_AGED_OUT 3 // Log = "hh:mm:ss STA 00:01:02:03:04:05 was aged-out and removed from this BSS" -#define EVENT_COUNTER_M 4 -#define EVENT_INVALID_PSK 5 -#define EVENT_MAX_EVENT_TYPE 6 -// ==== end of AP rtmp_def.h ============ - -// definition RSSI Number -#define RSSI_0 0 -#define RSSI_1 1 -#define RSSI_2 2 - -// definition of radar detection -#define RD_NORMAL_MODE 0 // Not found radar signal -#define RD_SWITCHING_MODE 1 // Found radar signal, and doing channel switch -#define RD_SILENCE_MODE 2 // After channel switch, need to be silence a while to ensure radar not found - -//Driver defined cid for mapping status and command. -#define SLEEPCID 0x11 -#define WAKECID 0x22 -#define QUERYPOWERCID 0x33 -#define OWNERMCU 0x1 -#define OWNERCPU 0x0 - -// MBSSID definition -#define ENTRY_NOT_FOUND 0xFF - - -/* After Linux 2.6.9, - * VLAN module use Private (from user) interface flags (netdevice->priv_flags). - * #define IFF_802_1Q_VLAN 0x1 -- 802.1Q VLAN device. in if.h - * ref to ip_sabotage_out() [ out->priv_flags & IFF_802_1Q_VLAN ] in br_netfilter.c - * - * For this reason, we MUST use EVEN value in priv_flags - */ -#define INT_MAIN 0x0100 -#define INT_MBSSID 0x0200 -#define INT_WDS 0x0300 -#define INT_APCLI 0x0400 -#define INT_MESH 0x0500 - -// Use bitmap to allow coexist of ATE_TXFRAME and ATE_RXFRAME(i.e.,to support LoopBack mode) -#ifdef RALINK_ATE -#define ATE_START 0x00 // Start ATE -#define ATE_STOP 0x80 // Stop ATE -#define ATE_TXCONT 0x05 // Continuous Transmit -#define ATE_TXCARR 0x09 // Transmit Carrier -#define ATE_TXCARRSUPP 0x11 // Transmit Carrier Suppression -#define ATE_TXFRAME 0x01 // Transmit Frames -#define ATE_RXFRAME 0x02 // Receive Frames -#ifdef RALINK_28xx_QA -#define ATE_TXSTOP 0xe2 // Stop Transmition(i.e., TXCONT, TXCARR, TXCARRSUPP, and TXFRAME) -#define ATE_RXSTOP 0xfd // Stop receiving Frames -#define BBP22_TXFRAME 0x00 // Transmit Frames -#define BBP22_TXCONT_OR_CARRSUPP 0x80 // Continuous Transmit or Carrier Suppression -#define BBP22_TXCARR 0xc1 // Transmit Carrier -#define BBP24_TXCONT 0x00 // Continuous Transmit -#define BBP24_CARRSUPP 0x01 // Carrier Suppression -#endif // RALINK_28xx_QA // -#endif // RALINK_ATE // - -// WEP Key TYPE -#define WEP_HEXADECIMAL_TYPE 0 -#define WEP_ASCII_TYPE 1 - - - -// WIRELESS EVENTS definition -/* Max number of char in custom event, refer to wireless_tools.28/wireless.20.h */ -#define IW_CUSTOM_MAX_LEN 255 /* In bytes */ - -// For system event - start -#define IW_SYS_EVENT_FLAG_START 0x0200 -#define IW_ASSOC_EVENT_FLAG 0x0200 -#define IW_DISASSOC_EVENT_FLAG 0x0201 -#define IW_DEAUTH_EVENT_FLAG 0x0202 -#define IW_AGEOUT_EVENT_FLAG 0x0203 -#define IW_COUNTER_MEASURES_EVENT_FLAG 0x0204 -#define IW_REPLAY_COUNTER_DIFF_EVENT_FLAG 0x0205 -#define IW_RSNIE_DIFF_EVENT_FLAG 0x0206 -#define IW_MIC_DIFF_EVENT_FLAG 0x0207 -#define IW_ICV_ERROR_EVENT_FLAG 0x0208 -#define IW_MIC_ERROR_EVENT_FLAG 0x0209 -#define IW_GROUP_HS_TIMEOUT_EVENT_FLAG 0x020A -#define IW_PAIRWISE_HS_TIMEOUT_EVENT_FLAG 0x020B -#define IW_RSNIE_SANITY_FAIL_EVENT_FLAG 0x020C -#define IW_SET_KEY_DONE_WPA1_EVENT_FLAG 0x020D -#define IW_SET_KEY_DONE_WPA2_EVENT_FLAG 0x020E -#define IW_STA_LINKUP_EVENT_FLAG 0x020F -#define IW_STA_LINKDOWN_EVENT_FLAG 0x0210 -#define IW_SCAN_COMPLETED_EVENT_FLAG 0x0211 -#define IW_SCAN_ENQUEUE_FAIL_EVENT_FLAG 0x0212 -// if add new system event flag, please upadte the IW_SYS_EVENT_FLAG_END -#define IW_SYS_EVENT_FLAG_END 0x0212 -#define IW_SYS_EVENT_TYPE_NUM (IW_SYS_EVENT_FLAG_END - IW_SYS_EVENT_FLAG_START + 1) -// For system event - end - -// For spoof attack event - start -#define IW_SPOOF_EVENT_FLAG_START 0x0300 -#define IW_CONFLICT_SSID_EVENT_FLAG 0x0300 -#define IW_SPOOF_ASSOC_RESP_EVENT_FLAG 0x0301 -#define IW_SPOOF_REASSOC_RESP_EVENT_FLAG 0x0302 -#define IW_SPOOF_PROBE_RESP_EVENT_FLAG 0x0303 -#define IW_SPOOF_BEACON_EVENT_FLAG 0x0304 -#define IW_SPOOF_DISASSOC_EVENT_FLAG 0x0305 -#define IW_SPOOF_AUTH_EVENT_FLAG 0x0306 -#define IW_SPOOF_DEAUTH_EVENT_FLAG 0x0307 -#define IW_SPOOF_UNKNOWN_MGMT_EVENT_FLAG 0x0308 -#define IW_REPLAY_ATTACK_EVENT_FLAG 0x0309 -// if add new spoof attack event flag, please upadte the IW_SPOOF_EVENT_FLAG_END -#define IW_SPOOF_EVENT_FLAG_END 0x0309 -#define IW_SPOOF_EVENT_TYPE_NUM (IW_SPOOF_EVENT_FLAG_END - IW_SPOOF_EVENT_FLAG_START + 1) -// For spoof attack event - end - -// For flooding attack event - start -#define IW_FLOOD_EVENT_FLAG_START 0x0400 -#define IW_FLOOD_AUTH_EVENT_FLAG 0x0400 -#define IW_FLOOD_ASSOC_REQ_EVENT_FLAG 0x0401 -#define IW_FLOOD_REASSOC_REQ_EVENT_FLAG 0x0402 -#define IW_FLOOD_PROBE_REQ_EVENT_FLAG 0x0403 -#define IW_FLOOD_DISASSOC_EVENT_FLAG 0x0404 -#define IW_FLOOD_DEAUTH_EVENT_FLAG 0x0405 -#define IW_FLOOD_EAP_REQ_EVENT_FLAG 0x0406 -// if add new flooding attack event flag, please upadte the IW_FLOOD_EVENT_FLAG_END -#define IW_FLOOD_EVENT_FLAG_END 0x0406 -#define IW_FLOOD_EVENT_TYPE_NUM (IW_FLOOD_EVENT_FLAG_END - IW_FLOOD_EVENT_FLAG_START + 1) -// For flooding attack - end - -// End - WIRELESS EVENTS definition - -#ifdef CONFIG_STA_SUPPORT -// definition for DLS, kathy -#define MAX_NUM_OF_INIT_DLS_ENTRY 1 -#define MAX_NUM_OF_DLS_ENTRY MAX_NUMBER_OF_DLS_ENTRY - -//Block ACK , rt2860, kathy -#define MAX_TX_REORDERBUF 64 -#define MAX_RX_REORDERBUF 64 -#define DEFAULT_TX_TIMEOUT 30 -#define DEFAULT_RX_TIMEOUT 30 -#ifndef CONFIG_AP_SUPPORT -#define MAX_BARECI_SESSION 8 -#endif - -#ifndef IW_ESSID_MAX_SIZE -/* Maximum size of the ESSID and pAd->nickname strings */ -#define IW_ESSID_MAX_SIZE 32 -#endif -#endif // CONFIG_STA_SUPPORT // - -#ifdef MCAST_RATE_SPECIFIC -#define MCAST_DISABLE 0 -#define MCAST_CCK 1 -#define MCAST_OFDM 2 -#define MCAST_HTMIX 3 -#endif // MCAST_RATE_SPECIFIC // - -// For AsicRadioOff/AsicRadioOn function -#define DOT11POWERSAVE 0 -#define GUIRADIO_OFF 1 -#define RTMP_HALT 2 -#define GUI_IDLE_POWER_SAVE 3 -// -- - - -// definition for WpaSupport flag -#define WPA_SUPPLICANT_DISABLE 0 -#define WPA_SUPPLICANT_ENABLE 1 -#define WPA_SUPPLICANT_ENABLE_WITH_WEB_UI 2 - -// Endian byte swapping codes -#define SWAP16(x) \ - ((UINT16)( \ - (((UINT16)(x) & (UINT16) 0x00ffU) << 8) | \ - (((UINT16)(x) & (UINT16) 0xff00U) >> 8) )) - -#define SWAP32(x) \ - ((UINT32)( \ - (((UINT32)(x) & (UINT32) 0x000000ffUL) << 24) | \ - (((UINT32)(x) & (UINT32) 0x0000ff00UL) << 8) | \ - (((UINT32)(x) & (UINT32) 0x00ff0000UL) >> 8) | \ - (((UINT32)(x) & (UINT32) 0xff000000UL) >> 24) )) - -#define SWAP64(x) \ - ((UINT64)( \ - (UINT64)(((UINT64)(x) & (UINT64) 0x00000000000000ffULL) << 56) | \ - (UINT64)(((UINT64)(x) & (UINT64) 0x000000000000ff00ULL) << 40) | \ - (UINT64)(((UINT64)(x) & (UINT64) 0x0000000000ff0000ULL) << 24) | \ - (UINT64)(((UINT64)(x) & (UINT64) 0x00000000ff000000ULL) << 8) | \ - (UINT64)(((UINT64)(x) & (UINT64) 0x000000ff00000000ULL) >> 8) | \ - (UINT64)(((UINT64)(x) & (UINT64) 0x0000ff0000000000ULL) >> 24) | \ - (UINT64)(((UINT64)(x) & (UINT64) 0x00ff000000000000ULL) >> 40) | \ - (UINT64)(((UINT64)(x) & (UINT64) 0xff00000000000000ULL) >> 56) )) - -#ifdef RT_BIG_ENDIAN - -#define cpu2le64(x) SWAP64((x)) -#define le2cpu64(x) SWAP64((x)) -#define cpu2le32(x) SWAP32((x)) -#define le2cpu32(x) SWAP32((x)) -#define cpu2le16(x) SWAP16((x)) -#define le2cpu16(x) SWAP16((x)) -#define cpu2be64(x) ((UINT64)(x)) -#define be2cpu64(x) ((UINT64)(x)) -#define cpu2be32(x) ((UINT32)(x)) -#define be2cpu32(x) ((UINT32)(x)) -#define cpu2be16(x) ((UINT16)(x)) -#define be2cpu16(x) ((UINT16)(x)) - -#else // Little_Endian - -#define cpu2le64(x) ((UINT64)(x)) -#define le2cpu64(x) ((UINT64)(x)) -#define cpu2le32(x) ((UINT32)(x)) -#define le2cpu32(x) ((UINT32)(x)) -#define cpu2le16(x) ((UINT16)(x)) -#define le2cpu16(x) ((UINT16)(x)) -#define cpu2be64(x) SWAP64((x)) -#define be2cpu64(x) SWAP64((x)) -#define cpu2be32(x) SWAP32((x)) -#define be2cpu32(x) SWAP32((x)) -#define cpu2be16(x) SWAP16((x)) -#define be2cpu16(x) SWAP16((x)) - -#endif // RT_BIG_ENDIAN - -#endif // __RTMP_DEF_H__ - - +#include "../rt2870/rtmp_def.h" diff --git a/drivers/staging/rt3070/rtmp_type.h b/drivers/staging/rt3070/rtmp_type.h index 4e4b168b9e92..42384e50679f 100644 --- a/drivers/staging/rt3070/rtmp_type.h +++ b/drivers/staging/rt3070/rtmp_type.h @@ -1,95 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - rtmp_type.h - - Abstract: - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Name Date Modification logs - Paul Lin 1-2-2004 -*/ -#ifndef __RTMP_TYPE_H__ -#define __RTMP_TYPE_H__ - - -#define PACKED __attribute__ ((packed)) - -// Put platform dependent declaration here -// For example, linux type definition -typedef unsigned char UINT8; -typedef unsigned short UINT16; -typedef unsigned int UINT32; -typedef unsigned long long UINT64; -typedef int INT32; -typedef long long INT64; - -typedef unsigned char * PUINT8; -typedef unsigned short * PUINT16; -typedef unsigned int * PUINT32; -typedef unsigned long long * PUINT64; -typedef int * PINT32; -typedef long long * PINT64; - -typedef signed char CHAR; -typedef signed short SHORT; -typedef signed int INT; -typedef signed long LONG; -typedef signed long long LONGLONG; - - -typedef unsigned char UCHAR; -typedef unsigned short USHORT; -typedef unsigned int UINT; -typedef unsigned long ULONG; -typedef unsigned long long ULONGLONG; - -typedef unsigned char BOOLEAN; -typedef void VOID; - -typedef VOID * PVOID; -typedef CHAR * PCHAR; -typedef UCHAR * PUCHAR; -typedef USHORT * PUSHORT; -typedef LONG * PLONG; -typedef ULONG * PULONG; -typedef UINT * PUINT; - -typedef unsigned int NDIS_MEDIA_STATE; - -typedef union _LARGE_INTEGER { - struct { - UINT LowPart; - INT32 HighPart; - } u; - INT64 QuadPart; -} LARGE_INTEGER; - -#endif // __RTMP_TYPE_H__ - +#include "../rt2870/rtmp_type.h" diff --git a/drivers/staging/rt3070/spectrum.h b/drivers/staging/rt3070/spectrum.h index 94cfa5b174fc..1ca9c2584bff 100644 --- a/drivers/staging/rt3070/spectrum.h +++ b/drivers/staging/rt3070/spectrum.h @@ -1,322 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - */ - -#ifndef __SPECTRUM_H__ -#define __SPECTRUM_H__ - -#include "rtmp_type.h" -#include "spectrum_def.h" - -typedef struct PACKED _TPC_REPORT_INFO -{ - UINT8 TxPwr; - UINT8 LinkMargin; -} TPC_REPORT_INFO, *PTPC_REPORT_INFO; - -typedef struct PACKED _CH_SW_ANN_INFO -{ - UINT8 ChSwMode; - UINT8 Channel; - UINT8 ChSwCnt; -} CH_SW_ANN_INFO, *PCH_SW_ANN_INFO; - -typedef union PACKED _MEASURE_REQ_MODE -{ -#ifdef RT_BIG_ENDIAN - struct PACKED - { - UINT8 Rev1:4; - UINT8 Report:1; - UINT8 Request:1; - UINT8 Enable:1; - UINT8 Rev0:1; - } field; -#else - struct PACKED - { - UINT8 Rev0:1; - UINT8 Enable:1; - UINT8 Request:1; - UINT8 Report:1; - UINT8 Rev1:4; - } field; -#endif // RT_BIG_ENDIAN // - UINT8 word; -} MEASURE_REQ_MODE, *PMEASURE_REQ_MODE; - -typedef struct PACKED _MEASURE_REQ -{ - UINT8 ChNum; - UINT64 MeasureStartTime; - UINT16 MeasureDuration; -} MEASURE_REQ, *PMEASURE_REQ; - -typedef struct PACKED _MEASURE_REQ_INFO -{ - UINT8 Token; - MEASURE_REQ_MODE ReqMode; - UINT8 ReqType; - MEASURE_REQ MeasureReq; -} MEASURE_REQ_INFO, *PMEASURE_REQ_INFO; - -typedef union PACKED _MEASURE_BASIC_REPORT_MAP -{ -#ifdef RT_BIG_ENDIAN - struct PACKED - { - UINT8 Rev:3; - UINT8 Unmeasure:1; - UINT8 Radar:1; - UINT8 UnidentifiedSignal:1; - UINT8 OfdmPreamble:1; - UINT8 BSS:1; - } field; -#else - struct PACKED - { - UINT8 BSS:1; - UINT8 OfdmPreamble:1; - UINT8 UnidentifiedSignal:1; - UINT8 Radar:1; - UINT8 Unmeasure:1; - UINT8 Rev:3; - } field; -#endif // RT_BIG_ENDIAN // - UINT8 word; -} MEASURE_BASIC_REPORT_MAP, *PMEASURE_BASIC_REPORT_MAP; - -typedef struct PACKED _MEASURE_BASIC_REPORT -{ - UINT8 ChNum; - UINT64 MeasureStartTime; - UINT16 MeasureDuration; - MEASURE_BASIC_REPORT_MAP Map; -} MEASURE_BASIC_REPORT, *PMEASURE_BASIC_REPORT; - -typedef struct PACKED _MEASURE_CCA_REPORT -{ - UINT8 ChNum; - UINT64 MeasureStartTime; - UINT16 MeasureDuration; - UINT8 CCA_Busy_Fraction; -} MEASURE_CCA_REPORT, *PMEASURE_CCA_REPORT; - -typedef struct PACKED _MEASURE_RPI_REPORT -{ - UINT8 ChNum; - UINT64 MeasureStartTime; - UINT16 MeasureDuration; - UINT8 RPI_Density[8]; -} MEASURE_RPI_REPORT, *PMEASURE_RPI_REPORT; - -typedef union PACKED _MEASURE_REPORT_MODE -{ - struct PACKED - { -#ifdef RT_BIG_ENDIAN - UINT8 Rev:5; - UINT8 Refused:1; - UINT8 Incapable:1; - UINT8 Late:1; -#else - UINT8 Late:1; - UINT8 Incapable:1; - UINT8 Refused:1; - UINT8 Rev:5; -#endif // RT_BIG_ENDIAN // - } field; - UINT8 word; -} MEASURE_REPORT_MODE, *PMEASURE_REPORT_MODE; - -typedef struct PACKED _MEASURE_REPORT_INFO -{ - UINT8 Token; - MEASURE_REPORT_MODE ReportMode; - UINT8 ReportType; - UINT8 Octect[0]; -} MEASURE_REPORT_INFO, *PMEASURE_REPORT_INFO; - -typedef struct PACKED _QUIET_INFO -{ - UINT8 QuietCnt; - UINT8 QuietPeriod; - UINT8 QuietDuration; - UINT8 QuietOffset; -} QUIET_INFO, *PQUIET_INFO; - -/* - ========================================================================== - Description: - Prepare Measurement request action frame and enqueue it into - management queue waiting for transmition. - - Parametrs: - 1. the destination mac address of the frame. - - Return : None. - ========================================================================== - */ -VOID EnqueueMeasurementReq( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDA, - IN UINT8 MeasureToken, - IN UINT8 MeasureReqMode, - IN UINT8 MeasureReqType, - IN UINT8 MeasureCh, - IN UINT16 MeasureDuration); - -/* - ========================================================================== - Description: - Prepare Measurement report action frame and enqueue it into - management queue waiting for transmition. - - Parametrs: - 1. the destination mac address of the frame. - - Return : None. - ========================================================================== - */ -VOID EnqueueMeasurementRep( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDA, - IN UINT8 DialogToken, - IN UINT8 MeasureToken, - IN UINT8 MeasureReqMode, - IN UINT8 MeasureReqType, - IN UINT8 ReportInfoLen, - IN PUINT8 pReportInfo); - -/* - ========================================================================== - Description: - Prepare TPC Request action frame and enqueue it into - management queue waiting for transmition. - - Parametrs: - 1. the destination mac address of the frame. - - Return : None. - ========================================================================== - */ -VOID EnqueueTPCReq( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDA, - IN UCHAR DialogToken); - -/* - ========================================================================== - Description: - Prepare TPC Report action frame and enqueue it into - management queue waiting for transmition. - - Parametrs: - 1. the destination mac address of the frame. - - Return : None. - ========================================================================== - */ -VOID EnqueueTPCRep( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDA, - IN UINT8 DialogToken, - IN UINT8 TxPwr, - IN UINT8 LinkMargin); - -/* - ========================================================================== - Description: - Prepare Channel Switch Announcement action frame and enqueue it into - management queue waiting for transmition. - - Parametrs: - 1. the destination mac address of the frame. - 2. Channel switch announcement mode. - 2. a New selected channel. - - Return : None. - ========================================================================== - */ -VOID EnqueueChSwAnn( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDA, - IN UINT8 ChSwMode, - IN UINT8 NewCh); - -/* - ========================================================================== - Description: - Spectrun action frames Handler such as channel switch annoucement, - measurement report, measurement request actions frames. - - Parametrs: - Elme - MLME message containing the received frame - - Return : None. - ========================================================================== - */ -VOID PeerSpectrumAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem); - -/* - ========================================================================== - Description: - - Parametrs: - - Return : None. - ========================================================================== - */ -INT Set_MeasureReq_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -INT Set_TpcReq_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); - -VOID MeasureReqTabInit( - IN PRTMP_ADAPTER pAd); - -VOID MeasureReqTabExit( - IN PRTMP_ADAPTER pAd); - -VOID TpcReqTabInit( - IN PRTMP_ADAPTER pAd); - -VOID TpcReqTabExit( - IN PRTMP_ADAPTER pAd); - -VOID NotifyChSwAnnToPeerAPs( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pRA, - IN PUCHAR pTA, - IN UINT8 ChSwMode, - IN UINT8 Channel); -#endif // __SPECTRUM_H__ // - +#include "../rt2870/spectrum.h" diff --git a/drivers/staging/rt3070/spectrum_def.h b/drivers/staging/rt3070/spectrum_def.h index 4ca4817bba05..892bc88c65f5 100644 --- a/drivers/staging/rt3070/spectrum_def.h +++ b/drivers/staging/rt3070/spectrum_def.h @@ -1,95 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - spectrum_def.h - - Abstract: - Handle association related requests either from WSTA or from local MLME - - Revision History: - Who When What - --------- ---------- ---------------------------------------------- - Fonchi Wu 2008 created for 802.11h - */ - -#ifndef __SPECTRUM_DEF_H__ -#define __SPECTRUM_DEF_H__ - -#define MAX_MEASURE_REQ_TAB_SIZE 3 -#define MAX_HASH_MEASURE_REQ_TAB_SIZE MAX_MEASURE_REQ_TAB_SIZE - -#define MAX_TPC_REQ_TAB_SIZE 3 -#define MAX_HASH_TPC_REQ_TAB_SIZE MAX_TPC_REQ_TAB_SIZE - -#define MIN_RCV_PWR 100 /* Negative value ((dBm) */ - -#define RM_TPC_REQ 0 -#define RM_MEASURE_REQ 1 - -#define RM_BASIC 0 -#define RM_CCA 1 -#define RM_RPI_HISTOGRAM 2 - -#define TPC_REQ_AGE_OUT 500 /* ms */ -#define MQ_REQ_AGE_OUT 500 /* ms */ - -#define TPC_DIALOGTOKEN_HASH_INDEX(_DialogToken) ((_DialogToken) % MAX_HASH_TPC_REQ_TAB_SIZE) -#define MQ_DIALOGTOKEN_HASH_INDEX(_DialogToken) ((_DialogToken) % MAX_MEASURE_REQ_TAB_SIZE) - -typedef struct _MEASURE_REQ_ENTRY -{ - struct _MEASURE_REQ_ENTRY *pNext; - ULONG lastTime; - BOOLEAN Valid; - UINT8 DialogToken; - UINT8 MeasureDialogToken[3]; // 0:basic measure, 1: CCA measure, 2: RPI_Histogram measure. -} MEASURE_REQ_ENTRY, *PMEASURE_REQ_ENTRY; - -typedef struct _MEASURE_REQ_TAB -{ - UCHAR Size; - PMEASURE_REQ_ENTRY Hash[MAX_HASH_MEASURE_REQ_TAB_SIZE]; - MEASURE_REQ_ENTRY Content[MAX_MEASURE_REQ_TAB_SIZE]; -} MEASURE_REQ_TAB, *PMEASURE_REQ_TAB; - -typedef struct _TPC_REQ_ENTRY -{ - struct _TPC_REQ_ENTRY *pNext; - ULONG lastTime; - BOOLEAN Valid; - UINT8 DialogToken; -} TPC_REQ_ENTRY, *PTPC_REQ_ENTRY; - -typedef struct _TPC_REQ_TAB -{ - UCHAR Size; - PTPC_REQ_ENTRY Hash[MAX_HASH_TPC_REQ_TAB_SIZE]; - TPC_REQ_ENTRY Content[MAX_TPC_REQ_TAB_SIZE]; -} TPC_REQ_TAB, *PTPC_REQ_TAB; - -#endif // __SPECTRUM_DEF_H__ // - +#include "../rt2870/spectrum_def.h" diff --git a/drivers/staging/rt3070/sta/aironet.c b/drivers/staging/rt3070/sta/aironet.c index 4af4a1906181..48fcc4695275 100644 --- a/drivers/staging/rt3070/sta/aironet.c +++ b/drivers/staging/rt3070/sta/aironet.c @@ -1,1312 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - aironet.c - - Abstract: - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Paul Lin 04-06-15 Initial -*/ -#include "../rt_config.h" - -/* - ========================================================================== - Description: - association state machine init, including state transition and timer init - Parameters: - S - pointer to the association state machine - ========================================================================== - */ -VOID AironetStateMachineInit( - IN PRTMP_ADAPTER pAd, - IN STATE_MACHINE *S, - OUT STATE_MACHINE_FUNC Trans[]) -{ - StateMachineInit(S, Trans, MAX_AIRONET_STATE, MAX_AIRONET_MSG, (STATE_MACHINE_FUNC)Drop, AIRONET_IDLE, AIRONET_MACHINE_BASE); - StateMachineSetAction(S, AIRONET_IDLE, MT2_AIRONET_MSG, (STATE_MACHINE_FUNC)AironetMsgAction); - StateMachineSetAction(S, AIRONET_IDLE, MT2_AIRONET_SCAN_REQ, (STATE_MACHINE_FUNC)AironetRequestAction); - StateMachineSetAction(S, AIRONET_SCANNING, MT2_AIRONET_SCAN_DONE, (STATE_MACHINE_FUNC)AironetReportAction); -} - -/* - ========================================================================== - Description: - This is state machine function. - When receiving EAPOL packets which is for 802.1x key management. - Use both in WPA, and WPAPSK case. - In this function, further dispatch to different functions according to the received packet. 3 categories are : - 1. normal 4-way pairwisekey and 2-way groupkey handshake - 2. MIC error (Countermeasures attack) report packet from STA. - 3. Request for pairwise/group key update from STA - Return: - ========================================================================== -*/ -VOID AironetMsgAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - USHORT Length; - UCHAR Index, i; - PUCHAR pData; - PAIRONET_RM_REQUEST_FRAME pRMReq; - PRM_REQUEST_ACTION pReqElem; - - DBGPRINT(RT_DEBUG_TRACE, ("-----> AironetMsgAction\n")); - - // 0. Get Aironet IAPP header first - pRMReq = (PAIRONET_RM_REQUEST_FRAME) &Elem->Msg[LENGTH_802_11]; - pData = (PUCHAR) &Elem->Msg[LENGTH_802_11]; - - // 1. Change endian format form network to little endian - Length = be2cpu16(pRMReq->IAPP.Length); - - // 2.0 Sanity check, this should only happen when CCX 2.0 support is enabled - if (pAd->StaCfg.CCXEnable != TRUE) - return; - - // 2.1 Radio measurement must be on - if (pAd->StaCfg.CCXControl.field.RMEnable != 1) - return; - - // 2.2. Debug print all bit information - DBGPRINT(RT_DEBUG_TRACE, ("IAPP ID & Length %d\n", Length)); - DBGPRINT(RT_DEBUG_TRACE, ("IAPP Type %x\n", pRMReq->IAPP.Type)); - DBGPRINT(RT_DEBUG_TRACE, ("IAPP SubType %x\n", pRMReq->IAPP.SubType)); - DBGPRINT(RT_DEBUG_TRACE, ("IAPP Dialog Token %x\n", pRMReq->IAPP.Token)); - DBGPRINT(RT_DEBUG_TRACE, ("IAPP Activation Delay %x\n", pRMReq->Delay)); - DBGPRINT(RT_DEBUG_TRACE, ("IAPP Measurement Offset %x\n", pRMReq->Offset)); - - // 3. Check IAPP frame type, it must be 0x32 for Cisco Aironet extension - if (pRMReq->IAPP.Type != AIRONET_IAPP_TYPE) - { - DBGPRINT(RT_DEBUG_ERROR, ("Wrong IAPP type for Cisco Aironet extension\n")); - return; - } - - // 4. Check IAPP frame subtype, it must be 0x01 for Cisco Aironet extension request. - // Since we are acting as client only, we will disregards reply subtype. - if (pRMReq->IAPP.SubType != AIRONET_IAPP_SUBTYPE_REQUEST) - { - DBGPRINT(RT_DEBUG_ERROR, ("Wrong IAPP subtype for Cisco Aironet extension\n")); - return; - } - - // 5. Verify Destination MAC and Source MAC, both should be all zeros. - if (! MAC_ADDR_EQUAL(pRMReq->IAPP.DA, ZERO_MAC_ADDR)) - { - DBGPRINT(RT_DEBUG_ERROR, ("Wrong IAPP DA for Cisco Aironet extension, it's not Zero\n")); - return; - } - - if (! MAC_ADDR_EQUAL(pRMReq->IAPP.SA, ZERO_MAC_ADDR)) - { - DBGPRINT(RT_DEBUG_ERROR, ("Wrong IAPP SA for Cisco Aironet extension, it's not Zero\n")); - return; - } - - // 6. Reinit all report related fields - NdisZeroMemory(pAd->StaCfg.FrameReportBuf, 2048); - NdisZeroMemory(pAd->StaCfg.BssReportOffset, sizeof(USHORT) * MAX_LEN_OF_BSS_TABLE); - NdisZeroMemory(pAd->StaCfg.MeasurementRequest, sizeof(RM_REQUEST_ACTION) * 4); - - // 7. Point to the start of first element report element - pAd->StaCfg.FrameReportLen = LENGTH_802_11 + sizeof(AIRONET_IAPP_HEADER); - DBGPRINT(RT_DEBUG_TRACE, ("FR len = %d\n", pAd->StaCfg.FrameReportLen)); - pAd->StaCfg.LastBssIndex = 0xff; - pAd->StaCfg.RMReqCnt = 0; - pAd->StaCfg.ParallelReq = FALSE; - pAd->StaCfg.ParallelDuration = 0; - pAd->StaCfg.ParallelChannel = 0; - pAd->StaCfg.IAPPToken = pRMReq->IAPP.Token; - pAd->StaCfg.CurrentRMReqIdx = 0; - pAd->StaCfg.CLBusyBytes = 0; - // Reset the statistics - for (i = 0; i < 8; i++) - pAd->StaCfg.RPIDensity[i] = 0; - - Index = 0; - - // 8. Save dialog token for report - pAd->StaCfg.IAPPToken = pRMReq->IAPP.Token; - - // Save Activation delay & measurement offset, Not really needed - - // 9. Point to the first request element - pData += sizeof(AIRONET_RM_REQUEST_FRAME); - // Length should exclude the CISCO Aironet SNAP header - Length -= (sizeof(AIRONET_RM_REQUEST_FRAME) - LENGTH_802_1_H); - - // 10. Start Parsing the Measurement elements. - // Be careful about multiple MR elements within one frames. - while (Length > 0) - { - pReqElem = (PRM_REQUEST_ACTION) pData; - switch (pReqElem->ReqElem.Eid) - { - case IE_MEASUREMENT_REQUEST: - // From the example, it seems we only need to support one request in one frame - // There is no multiple request in one frame. - // Besides, looks like we need to take care the measurement request only. - // The measurement request is always 4 bytes. - - // Start parsing this type of request. - // 0. Eid is IE_MEASUREMENT_REQUEST - // 1. Length didn't include Eid and Length field, it always be 8. - // 2. Measurement Token, we nned to save it for the corresponding report. - // 3. Measurement Mode, Although there are definitions, but we din't see value other than - // 0 from test specs examples. - // 4. Measurement Type, this is what we need to do. - switch (pReqElem->ReqElem.Type) - { - case MSRN_TYPE_CHANNEL_LOAD_REQ: - case MSRN_TYPE_NOISE_HIST_REQ: - case MSRN_TYPE_BEACON_REQ: - // Check the Enable non-serving channel measurement control - if (pAd->StaCfg.CCXControl.field.DCRMEnable == 0) - { - // Check channel before enqueue the action - if (pReqElem->Measurement.Channel != pAd->CommonCfg.Channel) - break; - } - else - { - // If off channel measurement, check the TU duration limit - if (pReqElem->Measurement.Channel != pAd->CommonCfg.Channel) - if (pReqElem->Measurement.Duration > pAd->StaCfg.CCXControl.field.TuLimit) - break; - } - - // Save requests and execute actions later - NdisMoveMemory(&pAd->StaCfg.MeasurementRequest[Index], pReqElem, sizeof(RM_REQUEST_ACTION)); - Index += 1; - break; - - case MSRN_TYPE_FRAME_REQ: - // Since it's option, we will support later - // FrameRequestAction(pAd, pData); - break; - - default: - break; - } - - // Point to next Measurement request - pData += sizeof(RM_REQUEST_ACTION); - Length -= sizeof(RM_REQUEST_ACTION); - break; - - // We accept request only, all others are dropped - case IE_MEASUREMENT_REPORT: - case IE_AP_TX_POWER: - case IE_MEASUREMENT_CAPABILITY: - default: - return; - } - } - - // 11. Update some flags and index - pAd->StaCfg.RMReqCnt = Index; - - if (Index) - { - MlmeEnqueue(pAd, AIRONET_STATE_MACHINE, MT2_AIRONET_SCAN_REQ, 0, NULL); - RT28XX_MLME_HANDLER(pAd); - } - - DBGPRINT(RT_DEBUG_TRACE, ("<----- AironetMsgAction\n")); -} - -/* - ======================================================================== - - Routine Description: - - Arguments: - - Return Value: - None - - Note: - - ======================================================================== -*/ -VOID AironetRequestAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - PRM_REQUEST_ACTION pReq; - - // 1. Point to next request element - pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[pAd->StaCfg.CurrentRMReqIdx]; - - // 2. Parse measurement type and call appropriate functions - if (pReq->ReqElem.Type == MSRN_TYPE_CHANNEL_LOAD_REQ) - // Channel Load measurement request - ChannelLoadRequestAction(pAd, pAd->StaCfg.CurrentRMReqIdx); - else if (pReq->ReqElem.Type == MSRN_TYPE_NOISE_HIST_REQ) - // Noise Histogram measurement request - NoiseHistRequestAction(pAd, pAd->StaCfg.CurrentRMReqIdx); - else if (pReq->ReqElem.Type == MSRN_TYPE_BEACON_REQ) - // Beacon measurement request - BeaconRequestAction(pAd, pAd->StaCfg.CurrentRMReqIdx); - else - // Unknown. Do nothing and return, this should never happen - return; - - // 3. Peek into the next request, if it's parallel, we will update the scan time to the largest one - if ((pAd->StaCfg.CurrentRMReqIdx + 1) < pAd->StaCfg.RMReqCnt) - { - pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[pAd->StaCfg.CurrentRMReqIdx + 1]; - // Check for parallel bit - if ((pReq->ReqElem.Mode & 0x01) && (pReq->Measurement.Channel == pAd->StaCfg.CCXScanChannel)) - { - // Update parallel mode request information - pAd->StaCfg.ParallelReq = TRUE; - pAd->StaCfg.CCXScanTime = ((pReq->Measurement.Duration > pAd->StaCfg.CCXScanTime) ? - (pReq->Measurement.Duration) : (pAd->StaCfg.CCXScanTime)); - } - } - - // 4. Call RT28XX_MLME_HANDLER to execute the request mlme commands, Scan request is the only one used - RT28XX_MLME_HANDLER(pAd); - -} - - -/* - ======================================================================== - - Routine Description: - Prepare channel load report action, special scan operation added - to support - - Arguments: - pAd Pointer to our adapter - pData Start from element ID - - Return Value: - None - - Note: - - ======================================================================== -*/ -VOID ChannelLoadRequestAction( - IN PRTMP_ADAPTER pAd, - IN UCHAR Index) -{ - PRM_REQUEST_ACTION pReq; - MLME_SCAN_REQ_STRUCT ScanReq; - UCHAR ZeroSsid[32]; - NDIS_STATUS NStatus; - PUCHAR pOutBuffer = NULL; - PHEADER_802_11 pNullFrame; - - DBGPRINT(RT_DEBUG_TRACE, ("ChannelLoadRequestAction ----->\n")); - - pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[Index]; - NdisZeroMemory(ZeroSsid, 32); - - // Prepare for special scan request - // The scan definition is different with our Active, Passive scan definition. - // For CCX2, Active means send out probe request with broadcast BSSID. - // Passive means no probe request sent, only listen to the beacons. - // The channel scanned is fixed as specified, no need to scan all channels. - // The scan wait time is specified in the request too. - // Passive scan Mode - - // Control state machine is not idle, reject the request - if ((pAd->Mlme.CntlMachine.CurrState != CNTL_IDLE) && (Index == 0)) - return; - - // Fill out stuff for scan request - ScanParmFill(pAd, &ScanReq, ZeroSsid, 0, BSS_ANY, SCAN_CISCO_CHANNEL_LOAD); - MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq); - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN; - - // Reset some internal control flags to make sure this scan works. - BssTableInit(&pAd->StaCfg.CCXBssTab); - pAd->StaCfg.ScanCnt = 0; - pAd->StaCfg.CCXScanChannel = pReq->Measurement.Channel; - pAd->StaCfg.CCXScanTime = pReq->Measurement.Duration; - - DBGPRINT(RT_DEBUG_TRACE, ("Duration %d, Channel %d!\n", pReq->Measurement.Duration, pReq->Measurement.Channel)); - - // If it's non serving channel scan, send out a null frame with PSM bit on. - if (pAd->StaCfg.CCXScanChannel != pAd->CommonCfg.Channel) - { - // Use MLME enqueue method - NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory - if (NStatus != NDIS_STATUS_SUCCESS) - return; - - pNullFrame = (PHEADER_802_11) pOutBuffer;; - // Make the power save Null frame with PSM bit on - MgtMacHeaderInit(pAd, pNullFrame, SUBTYPE_NULL_FUNC, 1, pAd->CommonCfg.Bssid, pAd->CommonCfg.Bssid); - pNullFrame->Duration = 0; - pNullFrame->FC.Type = BTYPE_DATA; - pNullFrame->FC.PwrMgmt = PWR_SAVE; - - // Send using priority queue - MiniportMMRequest(pAd, 0, pOutBuffer, sizeof(HEADER_802_11)); - MlmeFreeMemory(pAd, pOutBuffer); - DBGPRINT(RT_DEBUG_TRACE, ("Send PSM Data frame for off channel RM\n")); - RTMPusecDelay(5000); - } - - pAd->StaCfg.CCXReqType = MSRN_TYPE_CHANNEL_LOAD_REQ; - pAd->StaCfg.CLBusyBytes = 0; - // Enable Rx with promiscuous reception - RTMP_IO_WRITE32(pAd, RX_FILTR_CFG, 0x1010); - - // Set channel load measurement flag - RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_MEASUREMENT); - - pAd->Mlme.AironetMachine.CurrState = AIRONET_SCANNING; - - DBGPRINT(RT_DEBUG_TRACE, ("ChannelLoadRequestAction <-----\n")); -} - -/* - ======================================================================== - - Routine Description: - Prepare noise histogram report action, special scan operation added - to support - - Arguments: - pAd Pointer to our adapter - pData Start from element ID - - Return Value: - None - - Note: - - ======================================================================== -*/ -VOID NoiseHistRequestAction( - IN PRTMP_ADAPTER pAd, - IN UCHAR Index) -{ - PRM_REQUEST_ACTION pReq; - MLME_SCAN_REQ_STRUCT ScanReq; - UCHAR ZeroSsid[32], i; - NDIS_STATUS NStatus; - PUCHAR pOutBuffer = NULL; - PHEADER_802_11 pNullFrame; - - DBGPRINT(RT_DEBUG_TRACE, ("NoiseHistRequestAction ----->\n")); - - pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[Index]; - NdisZeroMemory(ZeroSsid, 32); - - // Prepare for special scan request - // The scan definition is different with our Active, Passive scan definition. - // For CCX2, Active means send out probe request with broadcast BSSID. - // Passive means no probe request sent, only listen to the beacons. - // The channel scanned is fixed as specified, no need to scan all channels. - // The scan wait time is specified in the request too. - // Passive scan Mode - - // Control state machine is not idle, reject the request - if ((pAd->Mlme.CntlMachine.CurrState != CNTL_IDLE) && (Index == 0)) - return; - - // Fill out stuff for scan request - ScanParmFill(pAd, &ScanReq, ZeroSsid, 0, BSS_ANY, SCAN_CISCO_NOISE); - MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq); - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN; - - // Reset some internal control flags to make sure this scan works. - BssTableInit(&pAd->StaCfg.CCXBssTab); - pAd->StaCfg.ScanCnt = 0; - pAd->StaCfg.CCXScanChannel = pReq->Measurement.Channel; - pAd->StaCfg.CCXScanTime = pReq->Measurement.Duration; - pAd->StaCfg.CCXReqType = MSRN_TYPE_NOISE_HIST_REQ; - - DBGPRINT(RT_DEBUG_TRACE, ("Duration %d, Channel %d!\n", pReq->Measurement.Duration, pReq->Measurement.Channel)); - - // If it's non serving channel scan, send out a null frame with PSM bit on. - if (pAd->StaCfg.CCXScanChannel != pAd->CommonCfg.Channel) - { - // Use MLME enqueue method - NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory - if (NStatus != NDIS_STATUS_SUCCESS) - return; - - pNullFrame = (PHEADER_802_11) pOutBuffer; - // Make the power save Null frame with PSM bit on - MgtMacHeaderInit(pAd, pNullFrame, SUBTYPE_NULL_FUNC, 1, pAd->CommonCfg.Bssid, pAd->CommonCfg.Bssid); - pNullFrame->Duration = 0; - pNullFrame->FC.Type = BTYPE_DATA; - pNullFrame->FC.PwrMgmt = PWR_SAVE; - - // Send using priority queue - MiniportMMRequest(pAd, 0, pOutBuffer, sizeof(HEADER_802_11)); - MlmeFreeMemory(pAd, pOutBuffer); - DBGPRINT(RT_DEBUG_TRACE, ("Send PSM Data frame for off channel RM\n")); - RTMPusecDelay(5000); - } - - // Reset the statistics - for (i = 0; i < 8; i++) - pAd->StaCfg.RPIDensity[i] = 0; - - // Enable Rx with promiscuous reception - RTMP_IO_WRITE32(pAd, RX_FILTR_CFG, 0x1010); - - // Set channel load measurement flag - RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_MEASUREMENT); - - pAd->Mlme.AironetMachine.CurrState = AIRONET_SCANNING; - - DBGPRINT(RT_DEBUG_TRACE, ("NoiseHistRequestAction <-----\n")); -} - -/* - ======================================================================== - - Routine Description: - Prepare Beacon report action, special scan operation added - to support - - Arguments: - pAd Pointer to our adapter - pData Start from element ID - - Return Value: - None - - Note: - - ======================================================================== -*/ -VOID BeaconRequestAction( - IN PRTMP_ADAPTER pAd, - IN UCHAR Index) -{ - PRM_REQUEST_ACTION pReq; - NDIS_STATUS NStatus; - PUCHAR pOutBuffer = NULL; - PHEADER_802_11 pNullFrame; - MLME_SCAN_REQ_STRUCT ScanReq; - UCHAR ZeroSsid[32]; - - DBGPRINT(RT_DEBUG_TRACE, ("BeaconRequestAction ----->\n")); - - pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[Index]; - NdisZeroMemory(ZeroSsid, 32); - - // Prepare for special scan request - // The scan definition is different with our Active, Passive scan definition. - // For CCX2, Active means send out probe request with broadcast BSSID. - // Passive means no probe request sent, only listen to the beacons. - // The channel scanned is fixed as specified, no need to scan all channels. - // The scan wait time is specified in the request too. - if (pReq->Measurement.ScanMode == MSRN_SCAN_MODE_PASSIVE) - { - // Passive scan Mode - DBGPRINT(RT_DEBUG_TRACE, ("Passive Scan Mode!\n")); - - // Control state machine is not idle, reject the request - if ((pAd->Mlme.CntlMachine.CurrState != CNTL_IDLE) && (Index == 0)) - return; - - // Fill out stuff for scan request - ScanParmFill(pAd, &ScanReq, ZeroSsid, 0, BSS_ANY, SCAN_CISCO_PASSIVE); - MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq); - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN; - - // Reset some internal control flags to make sure this scan works. - BssTableInit(&pAd->StaCfg.CCXBssTab); - pAd->StaCfg.ScanCnt = 0; - pAd->StaCfg.CCXScanChannel = pReq->Measurement.Channel; - pAd->StaCfg.CCXScanTime = pReq->Measurement.Duration; - pAd->StaCfg.CCXReqType = MSRN_TYPE_BEACON_REQ; - DBGPRINT(RT_DEBUG_TRACE, ("Duration %d!\n", pReq->Measurement.Duration)); - - // If it's non serving channel scan, send out a null frame with PSM bit on. - if (pAd->StaCfg.CCXScanChannel != pAd->CommonCfg.Channel) - { - // Use MLME enqueue method - NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory - if (NStatus != NDIS_STATUS_SUCCESS) - return; - - pNullFrame = (PHEADER_802_11) pOutBuffer; - // Make the power save Null frame with PSM bit on - MgtMacHeaderInit(pAd, pNullFrame, SUBTYPE_NULL_FUNC, 1, pAd->CommonCfg.Bssid, pAd->CommonCfg.Bssid); - pNullFrame->Duration = 0; - pNullFrame->FC.Type = BTYPE_DATA; - pNullFrame->FC.PwrMgmt = PWR_SAVE; - - // Send using priority queue - MiniportMMRequest(pAd, 0, pOutBuffer, sizeof(HEADER_802_11)); - MlmeFreeMemory(pAd, pOutBuffer); - DBGPRINT(RT_DEBUG_TRACE, ("Send PSM Data frame for off channel RM\n")); - RTMPusecDelay(5000); - } - - pAd->Mlme.AironetMachine.CurrState = AIRONET_SCANNING; - } - else if (pReq->Measurement.ScanMode == MSRN_SCAN_MODE_ACTIVE) - { - // Active scan Mode - DBGPRINT(RT_DEBUG_TRACE, ("Active Scan Mode!\n")); - - // Control state machine is not idle, reject the request - if (pAd->Mlme.CntlMachine.CurrState != CNTL_IDLE) - return; - - // Fill out stuff for scan request - ScanParmFill(pAd, &ScanReq, ZeroSsid, 0, BSS_ANY, SCAN_CISCO_ACTIVE); - MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq); - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN; - - // Reset some internal control flags to make sure this scan works. - BssTableInit(&pAd->StaCfg.CCXBssTab); - pAd->StaCfg.ScanCnt = 0; - pAd->StaCfg.CCXScanChannel = pReq->Measurement.Channel; - pAd->StaCfg.CCXScanTime = pReq->Measurement.Duration; - pAd->StaCfg.CCXReqType = MSRN_TYPE_BEACON_REQ; - DBGPRINT(RT_DEBUG_TRACE, ("Duration %d!\n", pReq->Measurement.Duration)); - - // If it's non serving channel scan, send out a null frame with PSM bit on. - if (pAd->StaCfg.CCXScanChannel != pAd->CommonCfg.Channel) - { - // Use MLME enqueue method - NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory - if (NStatus != NDIS_STATUS_SUCCESS) - return; - - pNullFrame = (PHEADER_802_11) pOutBuffer; - // Make the power save Null frame with PSM bit on - MgtMacHeaderInit(pAd, pNullFrame, SUBTYPE_NULL_FUNC, 1, pAd->CommonCfg.Bssid, pAd->CommonCfg.Bssid); - pNullFrame->Duration = 0; - pNullFrame->FC.Type = BTYPE_DATA; - pNullFrame->FC.PwrMgmt = PWR_SAVE; - - // Send using priority queue - MiniportMMRequest(pAd, 0, pOutBuffer, sizeof(HEADER_802_11)); - MlmeFreeMemory(pAd, pOutBuffer); - DBGPRINT(RT_DEBUG_TRACE, ("Send PSM Data frame for off channel RM\n")); - RTMPusecDelay(5000); - } - - pAd->Mlme.AironetMachine.CurrState = AIRONET_SCANNING; - } - else if (pReq->Measurement.ScanMode == MSRN_SCAN_MODE_BEACON_TABLE) - { - // Beacon report Mode, report all the APS in current bss table - DBGPRINT(RT_DEBUG_TRACE, ("Beacon Report Mode!\n")); - - // Copy current BSS table to CCX table, we can omit this step later on. - NdisMoveMemory(&pAd->StaCfg.CCXBssTab, &pAd->ScanTab, sizeof(BSS_TABLE)); - - // Create beacon report from Bss table - AironetCreateBeaconReportFromBssTable(pAd); - - // Set state to scanning - pAd->Mlme.AironetMachine.CurrState = AIRONET_SCANNING; - - // Enqueue report request - // Cisco scan request is finished, prepare beacon report - MlmeEnqueue(pAd, AIRONET_STATE_MACHINE, MT2_AIRONET_SCAN_DONE, 0, NULL); - } - else - { - // Wrong scan Mode - DBGPRINT(RT_DEBUG_TRACE, ("Wrong Scan Mode!\n")); - } - - DBGPRINT(RT_DEBUG_TRACE, ("BeaconRequestAction <-----\n")); -} - -/* - ======================================================================== - - Routine Description: - - Arguments: - - Return Value: - None - - Note: - - ======================================================================== -*/ -VOID AironetReportAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - PRM_REQUEST_ACTION pReq; - ULONG Now32; - - NdisGetSystemUpTime(&Now32); - pAd->StaCfg.LastBeaconRxTime = Now32; - - pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[pAd->StaCfg.CurrentRMReqIdx]; - - DBGPRINT(RT_DEBUG_TRACE, ("AironetReportAction ----->\n")); - - // 1. Parse measurement type and call appropriate functions - if (pReq->ReqElem.Type == MSRN_TYPE_CHANNEL_LOAD_REQ) - // Channel Load measurement request - ChannelLoadReportAction(pAd, pAd->StaCfg.CurrentRMReqIdx); - else if (pReq->ReqElem.Type == MSRN_TYPE_NOISE_HIST_REQ) - // Noise Histogram measurement request - NoiseHistReportAction(pAd, pAd->StaCfg.CurrentRMReqIdx); - else if (pReq->ReqElem.Type == MSRN_TYPE_BEACON_REQ) - // Beacon measurement request - BeaconReportAction(pAd, pAd->StaCfg.CurrentRMReqIdx); - else - // Unknown. Do nothing and return - ; - - // 2. Point to the correct index of action element, start from 0 - pAd->StaCfg.CurrentRMReqIdx++; - - // 3. Check for parallel actions - if (pAd->StaCfg.ParallelReq == TRUE) - { - pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[pAd->StaCfg.CurrentRMReqIdx]; - - // Process next action right away - if (pReq->ReqElem.Type == MSRN_TYPE_CHANNEL_LOAD_REQ) - // Channel Load measurement request - ChannelLoadReportAction(pAd, pAd->StaCfg.CurrentRMReqIdx); - else if (pReq->ReqElem.Type == MSRN_TYPE_NOISE_HIST_REQ) - // Noise Histogram measurement request - NoiseHistReportAction(pAd, pAd->StaCfg.CurrentRMReqIdx); - - pAd->StaCfg.ParallelReq = FALSE; - pAd->StaCfg.CurrentRMReqIdx++; - } - - if (pAd->StaCfg.CurrentRMReqIdx >= pAd->StaCfg.RMReqCnt) - { - // 4. There is no more unprocessed measurement request, go for transmit this report - AironetFinalReportAction(pAd); - pAd->Mlme.AironetMachine.CurrState = AIRONET_IDLE; - } - else - { - pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[pAd->StaCfg.CurrentRMReqIdx]; - - if (pReq->Measurement.Channel != pAd->CommonCfg.Channel) - { - RTMPusecDelay(100000); - } - - // 5. There are more requests to be measure - MlmeEnqueue(pAd, AIRONET_STATE_MACHINE, MT2_AIRONET_SCAN_REQ, 0, NULL); - RT28XX_MLME_HANDLER(pAd); - } - - DBGPRINT(RT_DEBUG_TRACE, ("AironetReportAction <-----\n")); -} - -/* - ======================================================================== - - Routine Description: - - Arguments: - - Return Value: - None - - Note: - - ======================================================================== -*/ -VOID AironetFinalReportAction( - IN PRTMP_ADAPTER pAd) -{ - PUCHAR pDest; - PAIRONET_IAPP_HEADER pIAPP; - PHEADER_802_11 pHeader; - UCHAR AckRate = RATE_2; - USHORT AckDuration = 0; - NDIS_STATUS NStatus; - PUCHAR pOutBuffer = NULL; - ULONG FrameLen = 0; - - DBGPRINT(RT_DEBUG_TRACE, ("AironetFinalReportAction ----->\n")); - - // 0. Set up the frame pointer, Frame was inited at the end of message action - pDest = &pAd->StaCfg.FrameReportBuf[LENGTH_802_11]; - - // 1. Update report IAPP fields - pIAPP = (PAIRONET_IAPP_HEADER) pDest; - - // 2. Copy Cisco SNAP header - NdisMoveMemory(pIAPP->CiscoSnapHeader, SNAP_AIRONET, LENGTH_802_1_H); - - // 3. network order for this 16bit length - pIAPP->Length = cpu2be16(pAd->StaCfg.FrameReportLen - LENGTH_802_11 - LENGTH_802_1_H); - - // 3.1 sanity check the report length, ignore it if there is nothing to report - if (be2cpu16(pIAPP->Length) <= 18) - return; - - // 4. Type must be 0x32 - pIAPP->Type = AIRONET_IAPP_TYPE; - - // 5. SubType for report must be 0x81 - pIAPP->SubType = AIRONET_IAPP_SUBTYPE_REPORT; - - // 6. DA is not used and must be zero, although the whole frame was cleared at the start of function - // We will do it again here. We can use BSSID instead - COPY_MAC_ADDR(pIAPP->DA, pAd->CommonCfg.Bssid); - - // 7. SA is the client reporting which must be our MAC - COPY_MAC_ADDR(pIAPP->SA, pAd->CurrentAddress); - - // 8. Copy the saved dialog token - pIAPP->Token = pAd->StaCfg.IAPPToken; - - // 9. Make the Report frame 802.11 header - // Reuse function in wpa.c - pHeader = (PHEADER_802_11) pAd->StaCfg.FrameReportBuf; - pAd->Sequence ++; - WpaMacHeaderInit(pAd, pHeader, 0, pAd->CommonCfg.Bssid); - - // ACK size is 14 include CRC, and its rate is based on real time information - AckRate = pAd->CommonCfg.ExpectedACKRate[pAd->CommonCfg.MlmeRate]; - AckDuration = RTMPCalcDuration(pAd, AckRate, 14); - pHeader->Duration = pAd->CommonCfg.Dsifs + AckDuration; - - // Use MLME enqueue method - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory - if (NStatus != NDIS_STATUS_SUCCESS) - return; - - // 10. Prepare report frame with dynamic outbuffer. Just simply copy everything. - MakeOutgoingFrame(pOutBuffer, &FrameLen, - pAd->StaCfg.FrameReportLen, pAd->StaCfg.FrameReportBuf, - END_OF_ARGS); - - // 11. Send using priority queue - MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); - - pAd->StaCfg.CCXReqType = MSRN_TYPE_UNUSED; - - DBGPRINT(RT_DEBUG_TRACE, ("AironetFinalReportAction <-----\n")); -} - -/* - ======================================================================== - - Routine Description: - - Arguments: - - Return Value: - None - - Note: - - ======================================================================== -*/ -VOID ChannelLoadReportAction( - IN PRTMP_ADAPTER pAd, - IN UCHAR Index) -{ - PMEASUREMENT_REPORT_ELEMENT pReport; - PCHANNEL_LOAD_REPORT pLoad; - PUCHAR pDest; - UCHAR CCABusyFraction; - - DBGPRINT(RT_DEBUG_TRACE, ("ChannelLoadReportAction ----->\n")); - - // Disable Rx with promiscuous reception, make it back to normal - RTMP_IO_WRITE32(pAd, RX_FILTR_CFG, STANORMAL); // Staion not drop control frame will fail WiFi Certification. - - // 0. Setup pointer for processing beacon & probe response - pDest = (PUCHAR) &pAd->StaCfg.FrameReportBuf[pAd->StaCfg.FrameReportLen]; - pReport = (PMEASUREMENT_REPORT_ELEMENT) pDest; - - // 1. Fill Measurement report element field. - pReport->Eid = IE_MEASUREMENT_REPORT; - // Fixed Length at 9, not include Eid and length fields - pReport->Length = 9; - pReport->Token = pAd->StaCfg.MeasurementRequest[Index].ReqElem.Token; - pReport->Mode = pAd->StaCfg.MeasurementRequest[Index].ReqElem.Mode; - pReport->Type = MSRN_TYPE_CHANNEL_LOAD_REQ; - - // 2. Fill channel report measurement data - pDest += sizeof(MEASUREMENT_REPORT_ELEMENT); - pLoad = (PCHANNEL_LOAD_REPORT) pDest; - pLoad->Channel = pAd->StaCfg.MeasurementRequest[Index].Measurement.Channel; - pLoad->Spare = 0; - pLoad->Duration = pAd->StaCfg.MeasurementRequest[Index].Measurement.Duration; - - // 3. Calculate the CCA Busy Fraction - // (Bytes + ACK size) * 8 / Tx speed * 255 / 1000 / measurement duration, use 24 us Tx speed - // = (Bytes + ACK) / 12 / duration - // 9 is the good value for pAd->StaCfg.CLFactor - // CCABusyFraction = (UCHAR) (pAd->StaCfg.CLBusyBytes / 9 / pLoad->Duration); - CCABusyFraction = (UCHAR) (pAd->StaCfg.CLBusyBytes / pAd->StaCfg.CLFactor / pLoad->Duration); - if (CCABusyFraction < 10) - CCABusyFraction = (UCHAR) (pAd->StaCfg.CLBusyBytes / 3 / pLoad->Duration) + 1; - - pLoad->CCABusy = CCABusyFraction; - DBGPRINT(RT_DEBUG_TRACE, ("CLBusyByte %ld, Duration %d, Result, %d\n", pAd->StaCfg.CLBusyBytes, pLoad->Duration, CCABusyFraction)); - - DBGPRINT(RT_DEBUG_TRACE, ("FrameReportLen %d\n", pAd->StaCfg.FrameReportLen)); - pAd->StaCfg.FrameReportLen += (sizeof(MEASUREMENT_REPORT_ELEMENT) + sizeof(CHANNEL_LOAD_REPORT)); - DBGPRINT(RT_DEBUG_TRACE, ("FrameReportLen %d\n", pAd->StaCfg.FrameReportLen)); - - // 4. Clear channel load measurement flag - RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_MEASUREMENT); - - // 5. reset to idle state - pAd->Mlme.AironetMachine.CurrState = AIRONET_IDLE; - - DBGPRINT(RT_DEBUG_TRACE, ("ChannelLoadReportAction <-----\n")); -} - -/* - ======================================================================== - - Routine Description: - - Arguments: - - Return Value: - None - - Note: - - ======================================================================== -*/ -VOID NoiseHistReportAction( - IN PRTMP_ADAPTER pAd, - IN UCHAR Index) -{ - PMEASUREMENT_REPORT_ELEMENT pReport; - PNOISE_HIST_REPORT pNoise; - PUCHAR pDest; - UCHAR i,NoiseCnt; - USHORT TotalRPICnt, TotalRPISum; - - DBGPRINT(RT_DEBUG_TRACE, ("NoiseHistReportAction ----->\n")); - - // 0. Disable Rx with promiscuous reception, make it back to normal - RTMP_IO_WRITE32(pAd, RX_FILTR_CFG, STANORMAL); // Staion not drop control frame will fail WiFi Certification. - // 1. Setup pointer for processing beacon & probe response - pDest = (PUCHAR) &pAd->StaCfg.FrameReportBuf[pAd->StaCfg.FrameReportLen]; - pReport = (PMEASUREMENT_REPORT_ELEMENT) pDest; - - // 2. Fill Measurement report element field. - pReport->Eid = IE_MEASUREMENT_REPORT; - // Fixed Length at 16, not include Eid and length fields - pReport->Length = 16; - pReport->Token = pAd->StaCfg.MeasurementRequest[Index].ReqElem.Token; - pReport->Mode = pAd->StaCfg.MeasurementRequest[Index].ReqElem.Mode; - pReport->Type = MSRN_TYPE_NOISE_HIST_REQ; - - // 3. Fill noise histogram report measurement data - pDest += sizeof(MEASUREMENT_REPORT_ELEMENT); - pNoise = (PNOISE_HIST_REPORT) pDest; - pNoise->Channel = pAd->StaCfg.MeasurementRequest[Index].Measurement.Channel; - pNoise->Spare = 0; - pNoise->Duration = pAd->StaCfg.MeasurementRequest[Index].Measurement.Duration; - // 4. Fill Noise histogram, the total RPI counts should be 0.4 * TU - // We estimate 4000 normal packets received durning 10 seconds test. - // Adjust it if required. - // 3 is a good value for pAd->StaCfg.NHFactor - // TotalRPICnt = pNoise->Duration * 3 / 10; - TotalRPICnt = pNoise->Duration * pAd->StaCfg.NHFactor / 10; - TotalRPISum = 0; - - for (i = 0; i < 8; i++) - { - TotalRPISum += pAd->StaCfg.RPIDensity[i]; - DBGPRINT(RT_DEBUG_TRACE, ("RPI %d Conuts %d\n", i, pAd->StaCfg.RPIDensity[i])); - } - - // Double check if the counter is larger than our expectation. - // We will replace it with the total number plus a fraction. - if (TotalRPISum > TotalRPICnt) - TotalRPICnt = TotalRPISum + pNoise->Duration / 20; - - DBGPRINT(RT_DEBUG_TRACE, ("Total RPI Conuts %d\n", TotalRPICnt)); - - // 5. Initialize noise count for the total summation of 0xff - NoiseCnt = 0; - for (i = 1; i < 8; i++) - { - pNoise->Density[i] = (UCHAR) (pAd->StaCfg.RPIDensity[i] * 255 / TotalRPICnt); - if ((pNoise->Density[i] == 0) && (pAd->StaCfg.RPIDensity[i] != 0)) - pNoise->Density[i]++; - NoiseCnt += pNoise->Density[i]; - DBGPRINT(RT_DEBUG_TRACE, ("Reported RPI[%d] = 0x%02x\n", i, pNoise->Density[i])); - } - - // 6. RPI[0] represents the rest of counts - pNoise->Density[0] = 0xff - NoiseCnt; - DBGPRINT(RT_DEBUG_TRACE, ("Reported RPI[0] = 0x%02x\n", pNoise->Density[0])); - - pAd->StaCfg.FrameReportLen += (sizeof(MEASUREMENT_REPORT_ELEMENT) + sizeof(NOISE_HIST_REPORT)); - - // 7. Clear channel load measurement flag - RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_MEASUREMENT); - - // 8. reset to idle state - pAd->Mlme.AironetMachine.CurrState = AIRONET_IDLE; - - DBGPRINT(RT_DEBUG_TRACE, ("NoiseHistReportAction <-----\n")); -} - -/* - ======================================================================== - - Routine Description: - Prepare Beacon report action, - - Arguments: - pAd Pointer to our adapter - - Return Value: - None - - Note: - - ======================================================================== -*/ -VOID BeaconReportAction( - IN PRTMP_ADAPTER pAd, - IN UCHAR Index) -{ - DBGPRINT(RT_DEBUG_TRACE, ("BeaconReportAction ----->\n")); - - // Looks like we don't have anything thing need to do here. - // All measurement report already finished in AddBeaconReport - // The length is in the FrameReportLen - - // reset Beacon index for next beacon request - pAd->StaCfg.LastBssIndex = 0xff; - - // reset to idle state - pAd->Mlme.AironetMachine.CurrState = AIRONET_IDLE; - - DBGPRINT(RT_DEBUG_TRACE, ("BeaconReportAction <-----\n")); -} - -/* - ======================================================================== - - Routine Description: - - Arguments: - Index Current BSSID in CCXBsstab entry index - - Return Value: - - Note: - - ======================================================================== -*/ -VOID AironetAddBeaconReport( - IN PRTMP_ADAPTER pAd, - IN ULONG Index, - IN PMLME_QUEUE_ELEM pElem) -{ - PVOID pMsg; - PUCHAR pSrc, pDest; - UCHAR ReqIdx; - ULONG MsgLen; - USHORT Length; - PFRAME_802_11 pFrame; - PMEASUREMENT_REPORT_ELEMENT pReport; - PEID_STRUCT pEid; - PBEACON_REPORT pBeaconReport; - PBSS_ENTRY pBss; - - // 0. Setup pointer for processing beacon & probe response - pMsg = pElem->Msg; - MsgLen = pElem->MsgLen; - pFrame = (PFRAME_802_11) pMsg; - pSrc = pFrame->Octet; // Start from AP TSF - pBss = (PBSS_ENTRY) &pAd->StaCfg.CCXBssTab.BssEntry[Index]; - ReqIdx = pAd->StaCfg.CurrentRMReqIdx; - - // 1 Check the Index, if we already create this entry, only update the average RSSI - if ((Index <= pAd->StaCfg.LastBssIndex) && (pAd->StaCfg.LastBssIndex != 0xff)) - { - pDest = (PUCHAR) &pAd->StaCfg.FrameReportBuf[pAd->StaCfg.BssReportOffset[Index]]; - // Point to bss report information - pDest += sizeof(MEASUREMENT_REPORT_ELEMENT); - pBeaconReport = (PBEACON_REPORT) pDest; - - // Update Rx power, in dBm - // Get the original RSSI readback from BBP - pBeaconReport->RxPower += pAd->BbpRssiToDbmDelta; - // Average the Rssi reading - pBeaconReport->RxPower = (pBeaconReport->RxPower + pBss->Rssi) / 2; - // Get to dBm format - pBeaconReport->RxPower -= pAd->BbpRssiToDbmDelta; - - DBGPRINT(RT_DEBUG_TRACE, ("Bssid %02x:%02x:%02x:%02x:%02x:%02x ", - pBss->Bssid[0], pBss->Bssid[1], pBss->Bssid[2], - pBss->Bssid[3], pBss->Bssid[4], pBss->Bssid[5])); - DBGPRINT(RT_DEBUG_TRACE, ("RxPower[%ld] Rssi %d, Avg Rssi %d\n", Index, (pBss->Rssi - pAd->BbpRssiToDbmDelta), pBeaconReport->RxPower - 256)); - DBGPRINT(RT_DEBUG_TRACE, ("FrameReportLen = %d\n", pAd->StaCfg.BssReportOffset[Index])); - - // Update other information here - - // Done - return; - } - - // 2. Update reported Index - pAd->StaCfg.LastBssIndex = Index; - - // 3. Setup the buffer address for copying this BSSID into reporting frame - // The offset should start after 802.11 header and report frame header. - pDest = (PUCHAR) &pAd->StaCfg.FrameReportBuf[pAd->StaCfg.FrameReportLen]; - - // 4. Save the start offset of each Bss in report frame - pAd->StaCfg.BssReportOffset[Index] = pAd->StaCfg.FrameReportLen; - - // 5. Fill Measurement report fields - pReport = (PMEASUREMENT_REPORT_ELEMENT) pDest; - pReport->Eid = IE_MEASUREMENT_REPORT; - pReport->Length = 0; - pReport->Token = pAd->StaCfg.MeasurementRequest[ReqIdx].ReqElem.Token; - pReport->Mode = pAd->StaCfg.MeasurementRequest[ReqIdx].ReqElem.Mode; - pReport->Type = MSRN_TYPE_BEACON_REQ; - Length = sizeof(MEASUREMENT_REPORT_ELEMENT); - pDest += sizeof(MEASUREMENT_REPORT_ELEMENT); - - // 6. Start thebeacon report format - pBeaconReport = (PBEACON_REPORT) pDest; - pDest += sizeof(BEACON_REPORT); - Length += sizeof(BEACON_REPORT); - - // 7. Copy Channel number - pBeaconReport->Channel = pBss->Channel; - pBeaconReport->Spare = 0; - pBeaconReport->Duration = pAd->StaCfg.MeasurementRequest[ReqIdx].Measurement.Duration; - pBeaconReport->PhyType = ((pBss->SupRateLen+pBss->ExtRateLen > 4) ? PHY_ERP : PHY_DSS); - // 8. Rx power, in dBm - pBeaconReport->RxPower = pBss->Rssi - pAd->BbpRssiToDbmDelta; - - DBGPRINT(RT_DEBUG_TRACE, ("Bssid %02x:%02x:%02x:%02x:%02x:%02x ", - pBss->Bssid[0], pBss->Bssid[1], pBss->Bssid[2], - pBss->Bssid[3], pBss->Bssid[4], pBss->Bssid[5])); - DBGPRINT(RT_DEBUG_TRACE, ("RxPower[%ld], Rssi %d\n", Index, pBeaconReport->RxPower - 256)); - DBGPRINT(RT_DEBUG_TRACE, ("FrameReportLen = %d\n", pAd->StaCfg.FrameReportLen)); - - pBeaconReport->BeaconInterval = pBss->BeaconPeriod; - COPY_MAC_ADDR(pBeaconReport->BSSID, pFrame->Hdr.Addr3); - NdisMoveMemory(pBeaconReport->ParentTSF, pSrc, 4); - NdisMoveMemory(pBeaconReport->TargetTSF, &pElem->TimeStamp.u.LowPart, 4); - NdisMoveMemory(&pBeaconReport->TargetTSF[4], &pElem->TimeStamp.u.HighPart, 4); - - // 9. Skip the beacon frame and offset to start of capabilityinfo since we already processed capabilityinfo - pSrc += (TIMESTAMP_LEN + 2); - pBeaconReport->CapabilityInfo = *(USHORT *)pSrc; - - // 10. Point to start of element ID - pSrc += 2; - pEid = (PEID_STRUCT) pSrc; - - // 11. Start process all variable Eid oayload and add the appropriate to the frame report - while (((PUCHAR) pEid + pEid->Len + 1) < ((PUCHAR) pFrame + MsgLen)) - { - // Only limited EID are required to report for CCX 2. It includes SSID, Supported rate, - // FH paramenter set, DS parameter set, CF parameter set, IBSS parameter set, - // TIM (report first 4 bytes only, radio measurement capability - switch (pEid->Eid) - { - case IE_SSID: - case IE_SUPP_RATES: - case IE_FH_PARM: - case IE_DS_PARM: - case IE_CF_PARM: - case IE_IBSS_PARM: - NdisMoveMemory(pDest, pEid, pEid->Len + 2); - pDest += (pEid->Len + 2); - Length += (pEid->Len + 2); - break; - - case IE_MEASUREMENT_CAPABILITY: - // Since this IE is duplicated with WPA security IE, we has to do sanity check before - // recognize it. - // 1. It also has fixed 6 bytes IE length. - if (pEid->Len != 6) - break; - // 2. Check the Cisco Aironet OUI - if (NdisEqualMemory(CISCO_OUI, (pSrc + 2), 3)) - { - // Matched, this is what we want - NdisMoveMemory(pDest, pEid, pEid->Len + 2); - pDest += (pEid->Len + 2); - Length += (pEid->Len + 2); - } - break; - - case IE_TIM: - if (pEid->Len > 4) - { - // May truncate and report the first 4 bytes only, with the eid & len, total should be 6 - NdisMoveMemory(pDest, pEid, 6); - pDest += 6; - Length += 6; - } - else - { - NdisMoveMemory(pDest, pEid, pEid->Len + 2); - pDest += (pEid->Len + 2); - Length += (pEid->Len + 2); - } - break; - - default: - break; - } - // 12. Move to next element ID - pSrc += (2 + pEid->Len); - pEid = (PEID_STRUCT) pSrc; - } - - // 13. Update the length in the header, not include EID and length - pReport->Length = Length - 4; - - // 14. Update the frame report buffer data length - pAd->StaCfg.FrameReportLen += Length; - DBGPRINT(RT_DEBUG_TRACE, ("FR len = %d\n", pAd->StaCfg.FrameReportLen)); -} - -/* - ======================================================================== - - Routine Description: - - Arguments: - Index Current BSSID in CCXBsstab entry index - - Return Value: - - Note: - - ======================================================================== -*/ -VOID AironetCreateBeaconReportFromBssTable( - IN PRTMP_ADAPTER pAd) -{ - PMEASUREMENT_REPORT_ELEMENT pReport; - PBEACON_REPORT pBeaconReport; - UCHAR Index, ReqIdx; - USHORT Length; - PUCHAR pDest; - PBSS_ENTRY pBss; - - // 0. setup base pointer - ReqIdx = pAd->StaCfg.CurrentRMReqIdx; - - for (Index = 0; Index < pAd->StaCfg.CCXBssTab.BssNr; Index++) - { - // 1. Setup the buffer address for copying this BSSID into reporting frame - // The offset should start after 802.11 header and report frame header. - pDest = (PUCHAR) &pAd->StaCfg.FrameReportBuf[pAd->StaCfg.FrameReportLen]; - pBss = (PBSS_ENTRY) &pAd->StaCfg.CCXBssTab.BssEntry[Index]; - Length = 0; - - // 2. Fill Measurement report fields - pReport = (PMEASUREMENT_REPORT_ELEMENT) pDest; - pReport->Eid = IE_MEASUREMENT_REPORT; - pReport->Length = 0; - pReport->Token = pAd->StaCfg.MeasurementRequest[ReqIdx].ReqElem.Token; - pReport->Mode = pAd->StaCfg.MeasurementRequest[ReqIdx].ReqElem.Mode; - pReport->Type = MSRN_TYPE_BEACON_REQ; - Length = sizeof(MEASUREMENT_REPORT_ELEMENT); - pDest += sizeof(MEASUREMENT_REPORT_ELEMENT); - - // 3. Start the beacon report format - pBeaconReport = (PBEACON_REPORT) pDest; - pDest += sizeof(BEACON_REPORT); - Length += sizeof(BEACON_REPORT); - - // 4. Copy Channel number - pBeaconReport->Channel = pBss->Channel; - pBeaconReport->Spare = 0; - pBeaconReport->Duration = pAd->StaCfg.MeasurementRequest[ReqIdx].Measurement.Duration; - pBeaconReport->PhyType = ((pBss->SupRateLen+pBss->ExtRateLen > 4) ? PHY_ERP : PHY_DSS); - pBeaconReport->RxPower = pBss->Rssi - pAd->BbpRssiToDbmDelta; - pBeaconReport->BeaconInterval = pBss->BeaconPeriod; - pBeaconReport->CapabilityInfo = pBss->CapabilityInfo; - COPY_MAC_ADDR(pBeaconReport->BSSID, pBss->Bssid); - NdisMoveMemory(pBeaconReport->ParentTSF, pBss->PTSF, 4); - NdisMoveMemory(pBeaconReport->TargetTSF, pBss->TTSF, 8); - - // 5. Create SSID - *pDest++ = 0x00; - *pDest++ = pBss->SsidLen; - NdisMoveMemory(pDest, pBss->Ssid, pBss->SsidLen); - pDest += pBss->SsidLen; - Length += (2 + pBss->SsidLen); - - // 6. Create SupportRates - *pDest++ = 0x01; - *pDest++ = pBss->SupRateLen; - NdisMoveMemory(pDest, pBss->SupRate, pBss->SupRateLen); - pDest += pBss->SupRateLen; - Length += (2 + pBss->SupRateLen); - - // 7. DS Parameter - *pDest++ = 0x03; - *pDest++ = 1; - *pDest++ = pBss->Channel; - Length += 3; - - // 8. IBSS parameter if presents - if (pBss->BssType == BSS_ADHOC) - { - *pDest++ = 0x06; - *pDest++ = 2; - *(PUSHORT) pDest = pBss->AtimWin; - pDest += 2; - Length += 4; - } - - // 9. Update length field, not include EID and length - pReport->Length = Length - 4; - - // 10. Update total frame size - pAd->StaCfg.FrameReportLen += Length; - } -} +#include "../../rt2870/sta/aironet.c" diff --git a/drivers/staging/rt3070/sta/assoc.c b/drivers/staging/rt3070/sta/assoc.c index 5c33a895bf7f..1987a2a4b05f 100644 --- a/drivers/staging/rt3070/sta/assoc.c +++ b/drivers/staging/rt3070/sta/assoc.c @@ -1,2060 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - assoc.c - - Abstract: - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - John 2004-9-3 porting from RT2500 -*/ -#include "../rt_config.h" - -UCHAR CipherWpaTemplate[] = { - 0xdd, // WPA IE - 0x16, // Length - 0x00, 0x50, 0xf2, 0x01, // oui - 0x01, 0x00, // Version - 0x00, 0x50, 0xf2, 0x02, // Multicast - 0x01, 0x00, // Number of unicast - 0x00, 0x50, 0xf2, 0x02, // unicast - 0x01, 0x00, // number of authentication method - 0x00, 0x50, 0xf2, 0x01 // authentication - }; - -UCHAR CipherWpa2Template[] = { - 0x30, // RSN IE - 0x14, // Length - 0x01, 0x00, // Version - 0x00, 0x0f, 0xac, 0x02, // group cipher, TKIP - 0x01, 0x00, // number of pairwise - 0x00, 0x0f, 0xac, 0x02, // unicast - 0x01, 0x00, // number of authentication method - 0x00, 0x0f, 0xac, 0x02, // authentication - 0x00, 0x00, // RSN capability - }; - -UCHAR Ccx2IeInfo[] = { 0x00, 0x40, 0x96, 0x03, 0x02}; - -/* - ========================================================================== - Description: - association state machine init, including state transition and timer init - Parameters: - S - pointer to the association state machine - - IRQL = PASSIVE_LEVEL - - ========================================================================== - */ -VOID AssocStateMachineInit( - IN PRTMP_ADAPTER pAd, - IN STATE_MACHINE *S, - OUT STATE_MACHINE_FUNC Trans[]) -{ - StateMachineInit(S, Trans, MAX_ASSOC_STATE, MAX_ASSOC_MSG, (STATE_MACHINE_FUNC)Drop, ASSOC_IDLE, ASSOC_MACHINE_BASE); - - // first column - StateMachineSetAction(S, ASSOC_IDLE, MT2_MLME_ASSOC_REQ, (STATE_MACHINE_FUNC)MlmeAssocReqAction); - StateMachineSetAction(S, ASSOC_IDLE, MT2_MLME_REASSOC_REQ, (STATE_MACHINE_FUNC)MlmeReassocReqAction); - StateMachineSetAction(S, ASSOC_IDLE, MT2_MLME_DISASSOC_REQ, (STATE_MACHINE_FUNC)MlmeDisassocReqAction); - StateMachineSetAction(S, ASSOC_IDLE, MT2_PEER_DISASSOC_REQ, (STATE_MACHINE_FUNC)PeerDisassocAction); - - // second column - StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_MLME_ASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenAssoc); - StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_MLME_REASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenReassoc); - StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_MLME_DISASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenDisassociate); - StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_PEER_DISASSOC_REQ, (STATE_MACHINE_FUNC)PeerDisassocAction); - StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_PEER_ASSOC_RSP, (STATE_MACHINE_FUNC)PeerAssocRspAction); - // - // Patch 3Com AP MOde:3CRWE454G72 - // We send Assoc request frame to this AP, it always send Reassoc Rsp not Associate Rsp. - // - StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_PEER_REASSOC_RSP, (STATE_MACHINE_FUNC)PeerAssocRspAction); - StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_ASSOC_TIMEOUT, (STATE_MACHINE_FUNC)AssocTimeoutAction); - - // third column - StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_MLME_ASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenAssoc); - StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_MLME_REASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenReassoc); - StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_MLME_DISASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenDisassociate); - StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_PEER_DISASSOC_REQ, (STATE_MACHINE_FUNC)PeerDisassocAction); - StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_PEER_REASSOC_RSP, (STATE_MACHINE_FUNC)PeerReassocRspAction); - // - // Patch, AP doesn't send Reassociate Rsp frame to Station. - // - StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_PEER_ASSOC_RSP, (STATE_MACHINE_FUNC)PeerReassocRspAction); - StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_REASSOC_TIMEOUT, (STATE_MACHINE_FUNC)ReassocTimeoutAction); - - // fourth column - StateMachineSetAction(S, DISASSOC_WAIT_RSP, MT2_MLME_ASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenAssoc); - StateMachineSetAction(S, DISASSOC_WAIT_RSP, MT2_MLME_REASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenReassoc); - StateMachineSetAction(S, DISASSOC_WAIT_RSP, MT2_MLME_DISASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenDisassociate); - StateMachineSetAction(S, DISASSOC_WAIT_RSP, MT2_PEER_DISASSOC_REQ, (STATE_MACHINE_FUNC)PeerDisassocAction); - StateMachineSetAction(S, DISASSOC_WAIT_RSP, MT2_DISASSOC_TIMEOUT, (STATE_MACHINE_FUNC)DisassocTimeoutAction); - - // initialize the timer - RTMPInitTimer(pAd, &pAd->MlmeAux.AssocTimer, GET_TIMER_FUNCTION(AssocTimeout), pAd, FALSE); - RTMPInitTimer(pAd, &pAd->MlmeAux.ReassocTimer, GET_TIMER_FUNCTION(ReassocTimeout), pAd, FALSE); - RTMPInitTimer(pAd, &pAd->MlmeAux.DisassocTimer, GET_TIMER_FUNCTION(DisassocTimeout), pAd, FALSE); -} - -/* - ========================================================================== - Description: - Association timeout procedure. After association timeout, this function - will be called and it will put a message into the MLME queue - Parameters: - Standard timer parameters - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID AssocTimeout(IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3) -{ - RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext; - - // Do nothing if the driver is starting halt state. - // This might happen when timer already been fired before cancel timer with mlmehalt - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) - return; - - MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_ASSOC_TIMEOUT, 0, NULL); - RT28XX_MLME_HANDLER(pAd); -} - -/* - ========================================================================== - Description: - Reassociation timeout procedure. After reassociation timeout, this - function will be called and put a message into the MLME queue - Parameters: - Standard timer parameters - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID ReassocTimeout(IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3) -{ - RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext; - - // Do nothing if the driver is starting halt state. - // This might happen when timer already been fired before cancel timer with mlmehalt - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) - return; - - MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_REASSOC_TIMEOUT, 0, NULL); - RT28XX_MLME_HANDLER(pAd); -} - -/* - ========================================================================== - Description: - Disassociation timeout procedure. After disassociation timeout, this - function will be called and put a message into the MLME queue - Parameters: - Standard timer parameters - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID DisassocTimeout(IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3) -{ - RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext; - - // Do nothing if the driver is starting halt state. - // This might happen when timer already been fired before cancel timer with mlmehalt - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) - return; - - MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_DISASSOC_TIMEOUT, 0, NULL); - RT28XX_MLME_HANDLER(pAd); -} - -/* - ========================================================================== - Description: - mlme assoc req handling procedure - Parameters: - Adapter - Adapter pointer - Elem - MLME Queue Element - Pre: - the station has been authenticated and the following information is stored in the config - -# SSID - -# supported rates and their length - -# listen interval (Adapter->StaCfg.default_listen_count) - -# Transmit power (Adapter->StaCfg.tx_power) - Post : - -# An association request frame is generated and sent to the air - -# Association timer starts - -# Association state -> ASSOC_WAIT_RSP - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID MlmeAssocReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - UCHAR ApAddr[6]; - HEADER_802_11 AssocHdr; - UCHAR Ccx2Len = 5; - UCHAR WmeIe[9] = {IE_VENDOR_SPECIFIC, 0x07, 0x00, 0x50, 0xf2, 0x02, 0x00, 0x01, 0x00}; - USHORT ListenIntv; - ULONG Timeout; - USHORT CapabilityInfo; - BOOLEAN TimerCancelled; - PUCHAR pOutBuffer = NULL; - NDIS_STATUS NStatus; - ULONG FrameLen = 0; - ULONG tmp; - USHORT VarIesOffset; - UCHAR CkipFlag; - UCHAR CkipNegotiationBuffer[CKIP_NEGOTIATION_LENGTH]; - UCHAR AironetCkipIe = IE_AIRONET_CKIP; - UCHAR AironetCkipLen = CKIP_NEGOTIATION_LENGTH; - UCHAR AironetIPAddressIE = IE_AIRONET_IPADDRESS; - UCHAR AironetIPAddressLen = AIRONET_IPADDRESS_LENGTH; - UCHAR AironetIPAddressBuffer[AIRONET_IPADDRESS_LENGTH] = {0x00, 0x40, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00}; - USHORT Status; - - // Block all authentication request durning WPA block period - if (pAd->StaCfg.bBlockAssoc == TRUE) - { - DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - Block Assoc request durning WPA block period!\n")); - pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; - Status = MLME_STATE_MACHINE_REJECT; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_ASSOC_CONF, 2, &Status); - } - // check sanity first - else if (MlmeAssocReqSanity(pAd, Elem->Msg, Elem->MsgLen, ApAddr, &CapabilityInfo, &Timeout, &ListenIntv)) - { - RTMPCancelTimer(&pAd->MlmeAux.AssocTimer, &TimerCancelled); - COPY_MAC_ADDR(pAd->MlmeAux.Bssid, ApAddr); - - // Get an unused nonpaged memory - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); - if (NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_TRACE,("ASSOC - MlmeAssocReqAction() allocate memory failed \n")); - pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; - Status = MLME_FAIL_NO_RESOURCE; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_ASSOC_CONF, 2, &Status); - return; - } - - // Add by James 03/06/27 - pAd->StaCfg.AssocInfo.Length = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION); - // Association don't need to report MAC address - pAd->StaCfg.AssocInfo.AvailableRequestFixedIEs = - NDIS_802_11_AI_REQFI_CAPABILITIES | NDIS_802_11_AI_REQFI_LISTENINTERVAL; - pAd->StaCfg.AssocInfo.RequestFixedIEs.Capabilities = CapabilityInfo; - pAd->StaCfg.AssocInfo.RequestFixedIEs.ListenInterval = ListenIntv; - // Only reassociate need this - //COPY_MAC_ADDR(pAd->StaCfg.AssocInfo.RequestFixedIEs.CurrentAPAddress, ApAddr); - pAd->StaCfg.AssocInfo.OffsetRequestIEs = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION); - - NdisZeroMemory(pAd->StaCfg.ReqVarIEs, MAX_VIE_LEN); - // First add SSID - VarIesOffset = 0; - NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, &SsidIe, 1); - VarIesOffset += 1; - NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, &pAd->MlmeAux.SsidLen, 1); - VarIesOffset += 1; - NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen); - VarIesOffset += pAd->MlmeAux.SsidLen; - - // Second add Supported rates - NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, &SupRateIe, 1); - VarIesOffset += 1; - NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, &pAd->MlmeAux.SupRateLen, 1); - VarIesOffset += 1; - NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, pAd->MlmeAux.SupRate, pAd->MlmeAux.SupRateLen); - VarIesOffset += pAd->MlmeAux.SupRateLen; - // End Add by James - - if ((pAd->CommonCfg.Channel > 14) && - (pAd->CommonCfg.bIEEE80211H == TRUE)) - CapabilityInfo |= 0x0100; - - DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - Send ASSOC request...\n")); - MgtMacHeaderInit(pAd, &AssocHdr, SUBTYPE_ASSOC_REQ, 0, ApAddr, ApAddr); - - // Build basic frame first - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(HEADER_802_11), &AssocHdr, - 2, &CapabilityInfo, - 2, &ListenIntv, - 1, &SsidIe, - 1, &pAd->MlmeAux.SsidLen, - pAd->MlmeAux.SsidLen, pAd->MlmeAux.Ssid, - 1, &SupRateIe, - 1, &pAd->MlmeAux.SupRateLen, - pAd->MlmeAux.SupRateLen, pAd->MlmeAux.SupRate, - END_OF_ARGS); - - if (pAd->MlmeAux.ExtRateLen != 0) - { - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - 1, &ExtRateIe, - 1, &pAd->MlmeAux.ExtRateLen, - pAd->MlmeAux.ExtRateLen, pAd->MlmeAux.ExtRate, - END_OF_ARGS); - FrameLen += tmp; - } - -#ifdef DOT11_N_SUPPORT - // HT - if ((pAd->MlmeAux.HtCapabilityLen > 0) && (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) - { - ULONG TmpLen; - UCHAR HtLen; - UCHAR BROADCOM[4] = {0x0, 0x90, 0x4c, 0x33}; - if (pAd->StaActive.SupportedPhyInfo.bPreNHt == TRUE) - { - HtLen = SIZE_HT_CAP_IE + 4; - MakeOutgoingFrame(pOutBuffer + FrameLen, &TmpLen, - 1, &WpaIe, - 1, &HtLen, - 4, &BROADCOM[0], - pAd->MlmeAux.HtCapabilityLen, &pAd->MlmeAux.HtCapability, - END_OF_ARGS); - } - else - { -#ifdef RT_BIG_ENDIAN - HT_CAPABILITY_IE HtCapabilityTmp; -#endif - -#ifndef RT_BIG_ENDIAN - MakeOutgoingFrame(pOutBuffer + FrameLen, &TmpLen, - 1, &HtCapIe, - 1, &pAd->MlmeAux.HtCapabilityLen, - pAd->MlmeAux.HtCapabilityLen, &pAd->MlmeAux.HtCapability, - END_OF_ARGS); -#else - NdisZeroMemory(&HtCapabilityTmp, sizeof(HT_CAPABILITY_IE)); - NdisMoveMemory(&HtCapabilityTmp, &pAd->MlmeAux.HtCapability, pAd->MlmeAux.HtCapabilityLen); - *(USHORT *)(&HtCapabilityTmp.HtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.HtCapInfo)); - *(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo)); - - MakeOutgoingFrame(pOutBuffer + FrameLen, &TmpLen, - 1, &HtCapIe, - 1, &pAd->MlmeAux.HtCapabilityLen, - pAd->MlmeAux.HtCapabilityLen,&HtCapabilityTmp, - END_OF_ARGS); -#endif - } - FrameLen += TmpLen; - } -#endif // DOT11_N_SUPPORT // - - // add Ralink proprietary IE to inform AP this STA is going to use AGGREGATION or PIGGY-BACK+AGGREGATION - // Case I: (Aggregation + Piggy-Back) - // 1. user enable aggregation, AND - // 2. Mac support piggy-back - // 3. AP annouces it's PIGGY-BACK+AGGREGATION-capable in BEACON - // Case II: (Aggregation) - // 1. user enable aggregation, AND - // 2. AP annouces it's AGGREGATION-capable in BEACON - if (pAd->CommonCfg.bAggregationCapable) - { - if ((pAd->CommonCfg.bPiggyBackCapable) && ((pAd->MlmeAux.APRalinkIe & 0x00000003) == 3)) - { - ULONG TmpLen; - UCHAR RalinkIe[9] = {IE_VENDOR_SPECIFIC, 7, 0x00, 0x0c, 0x43, 0x03, 0x00, 0x00, 0x00}; - MakeOutgoingFrame(pOutBuffer+FrameLen, &TmpLen, - 9, RalinkIe, - END_OF_ARGS); - FrameLen += TmpLen; - } - else if (pAd->MlmeAux.APRalinkIe & 0x00000001) - { - ULONG TmpLen; - UCHAR RalinkIe[9] = {IE_VENDOR_SPECIFIC, 7, 0x00, 0x0c, 0x43, 0x01, 0x00, 0x00, 0x00}; - MakeOutgoingFrame(pOutBuffer+FrameLen, &TmpLen, - 9, RalinkIe, - END_OF_ARGS); - FrameLen += TmpLen; - } - } - else - { - ULONG TmpLen; - UCHAR RalinkIe[9] = {IE_VENDOR_SPECIFIC, 7, 0x00, 0x0c, 0x43, 0x06, 0x00, 0x00, 0x00}; - MakeOutgoingFrame(pOutBuffer+FrameLen, &TmpLen, - 9, RalinkIe, - END_OF_ARGS); - FrameLen += TmpLen; - } - - if (pAd->MlmeAux.APEdcaParm.bValid) - { - if (pAd->CommonCfg.bAPSDCapable && pAd->MlmeAux.APEdcaParm.bAPSDCapable) - { - QBSS_STA_INFO_PARM QosInfo; - - NdisZeroMemory(&QosInfo, sizeof(QBSS_STA_INFO_PARM)); - QosInfo.UAPSD_AC_BE = pAd->CommonCfg.bAPSDAC_BE; - QosInfo.UAPSD_AC_BK = pAd->CommonCfg.bAPSDAC_BK; - QosInfo.UAPSD_AC_VI = pAd->CommonCfg.bAPSDAC_VI; - QosInfo.UAPSD_AC_VO = pAd->CommonCfg.bAPSDAC_VO; - QosInfo.MaxSPLength = pAd->CommonCfg.MaxSPLength; - WmeIe[8] |= *(PUCHAR)&QosInfo; - } - else - { - // The Parameter Set Count is set to ¡§0¡¨ in the association request frames - // WmeIe[8] |= (pAd->MlmeAux.APEdcaParm.EdcaUpdateCount & 0x0f); - } - - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - 9, &WmeIe[0], - END_OF_ARGS); - FrameLen += tmp; - } - - // - // Let WPA(#221) Element ID on the end of this association frame. - // Otherwise some AP will fail on parsing Element ID and set status fail on Assoc Rsp. - // For example: Put Vendor Specific IE on the front of WPA IE. - // This happens on AP (Model No:Linksys WRK54G) - // - if (((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) || - (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) || - (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || - (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) - ) - ) - { - UCHAR RSNIe = IE_WPA; - - if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) || - (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2)) - { - RSNIe = IE_WPA2; - } - -#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT -#ifdef SIOCSIWGENIE - if (pAd->StaCfg.WpaSupplicantUP != 1) -#endif // SIOCSIWGENIE // -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // - RTMPMakeRSNIE(pAd, pAd->StaCfg.AuthMode, pAd->StaCfg.WepStatus, BSS0); - - // Check for WPA PMK cache list - if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) - { - INT idx; - BOOLEAN FoundPMK = FALSE; - // Search chched PMKID, append it if existed - for (idx = 0; idx < PMKID_NO; idx++) - { - if (NdisEqualMemory(ApAddr, &pAd->StaCfg.SavedPMK[idx].BSSID, 6)) - { - FoundPMK = TRUE; - break; - } - } - - if (FoundPMK) - { - // Set PMK number - *(PUSHORT) &pAd->StaCfg.RSN_IE[pAd->StaCfg.RSNIE_Len] = 1; - NdisMoveMemory(&pAd->StaCfg.RSN_IE[pAd->StaCfg.RSNIE_Len + 2], &pAd->StaCfg.SavedPMK[idx].PMKID, 16); - pAd->StaCfg.RSNIE_Len += 18; - } - } - -#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT -#ifdef SIOCSIWGENIE - if (pAd->StaCfg.WpaSupplicantUP == 1) - { - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - pAd->StaCfg.RSNIE_Len, pAd->StaCfg.RSN_IE, - END_OF_ARGS); - } - else -#endif -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // - { - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - 1, &RSNIe, - 1, &pAd->StaCfg.RSNIE_Len, - pAd->StaCfg.RSNIE_Len, pAd->StaCfg.RSN_IE, - END_OF_ARGS); - } - - FrameLen += tmp; - -#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT -#ifdef SIOCSIWGENIE - if (pAd->StaCfg.WpaSupplicantUP != 1) -#endif -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // - { - // Append Variable IE - NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, &RSNIe, 1); - VarIesOffset += 1; - NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, &pAd->StaCfg.RSNIE_Len, 1); - VarIesOffset += 1; - } - NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, pAd->StaCfg.RSN_IE, pAd->StaCfg.RSNIE_Len); - VarIesOffset += pAd->StaCfg.RSNIE_Len; - - // Set Variable IEs Length - pAd->StaCfg.ReqVarIELen = VarIesOffset; - } - - // We have update that at PeerBeaconAtJoinRequest() - CkipFlag = pAd->StaCfg.CkipFlag; - if (CkipFlag != 0) - { - NdisZeroMemory(CkipNegotiationBuffer, CKIP_NEGOTIATION_LENGTH); - CkipNegotiationBuffer[2] = 0x66; - // Make it try KP & MIC, since we have to follow the result from AssocRsp - CkipNegotiationBuffer[8] = 0x18; - CkipNegotiationBuffer[CKIP_NEGOTIATION_LENGTH - 1] = 0x22; - CkipFlag = 0x18; - - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - 1, &AironetCkipIe, - 1, &AironetCkipLen, - AironetCkipLen, CkipNegotiationBuffer, - END_OF_ARGS); - FrameLen += tmp; - } - - // Add CCX v2 request if CCX2 admin state is on - if (pAd->StaCfg.CCXControl.field.Enable == 1) - { - - // - // Add AironetIPAddressIE for Cisco CCX 2.X - // Add CCX Version - // - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - 1, &AironetIPAddressIE, - 1, &AironetIPAddressLen, - AironetIPAddressLen, AironetIPAddressBuffer, - 1, &Ccx2Ie, - 1, &Ccx2Len, - Ccx2Len, Ccx2IeInfo, - END_OF_ARGS); - FrameLen += tmp; - - // - // Add CipherSuite CCKM or LeapTkip if setting. - // -#ifdef LEAP_SUPPORT - if (LEAP_CCKM_ON(pAd)) - { - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - CipherSuiteCiscoCCKMLen, CipherSuiteCiscoCCKM, - END_OF_ARGS); - FrameLen += tmp; - - // Third add RSN - NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, CipherSuiteCiscoCCKM, CipherSuiteCiscoCCKMLen); //Save CipherSuite - VarIesOffset += CipherSuiteCiscoCCKMLen; - } - else if ((pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) && (pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled)) - { - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - CipherSuiteCCXTkipLen, CipherSuiteCCXTkip, - END_OF_ARGS); - FrameLen += tmp; - - // Third add RSN - NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, CipherSuiteCCXTkip, CipherSuiteCCXTkipLen); - VarIesOffset += CipherSuiteCCXTkipLen; - } -#endif // LEAP_SUPPORT // - - // Add by James 03/06/27 - // Set Variable IEs Length - pAd->StaCfg.ReqVarIELen = VarIesOffset; - pAd->StaCfg.AssocInfo.RequestIELength = VarIesOffset; - - // OffsetResponseIEs follow ReqVarIE - pAd->StaCfg.AssocInfo.OffsetResponseIEs = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION) + pAd->StaCfg.ReqVarIELen; - // End Add by James - } - - - MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); - - RTMPSetTimer(&pAd->MlmeAux.AssocTimer, Timeout); - pAd->Mlme.AssocMachine.CurrState = ASSOC_WAIT_RSP; - } - else - { - DBGPRINT(RT_DEBUG_TRACE,("ASSOC - MlmeAssocReqAction() sanity check failed. BUG!!!!!! \n")); - pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; - Status = MLME_INVALID_FORMAT; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_ASSOC_CONF, 2, &Status); - } - -} - -/* - ========================================================================== - Description: - mlme reassoc req handling procedure - Parameters: - Elem - - Pre: - -# SSID (Adapter->StaCfg.ssid[]) - -# BSSID (AP address, Adapter->StaCfg.bssid) - -# Supported rates (Adapter->StaCfg.supported_rates[]) - -# Supported rates length (Adapter->StaCfg.supported_rates_len) - -# Tx power (Adapter->StaCfg.tx_power) - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID MlmeReassocReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - UCHAR ApAddr[6]; - HEADER_802_11 ReassocHdr; - UCHAR Ccx2Len = 5; - UCHAR WmeIe[9] = {IE_VENDOR_SPECIFIC, 0x07, 0x00, 0x50, 0xf2, 0x02, 0x00, 0x01, 0x00}; - USHORT CapabilityInfo, ListenIntv; - ULONG Timeout; - ULONG FrameLen = 0; - BOOLEAN TimerCancelled; - NDIS_STATUS NStatus; - ULONG tmp; - PUCHAR pOutBuffer = NULL; -//CCX 2.X -#ifdef LEAP_SUPPORT - UCHAR CkipFlag; - UCHAR CkipNegotiationBuffer[CKIP_NEGOTIATION_LENGTH]; - UCHAR AironetCkipIe = IE_AIRONET_CKIP; - UCHAR AironetCkipLen = CKIP_NEGOTIATION_LENGTH; - UCHAR AironetIPAddressIE = IE_AIRONET_IPADDRESS; - UCHAR AironetIPAddressLen = AIRONET_IPADDRESS_LENGTH; - UCHAR AironetIPAddressBuffer[AIRONET_IPADDRESS_LENGTH] = {0x00, 0x40, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00}; - UCHAR AironetCCKMReassocIE = IE_AIRONET_CCKMREASSOC; - UCHAR AironetCCKMReassocLen = AIRONET_CCKMREASSOC_LENGTH; - UCHAR AironetCCKMReassocBuffer[AIRONET_CCKMREASSOC_LENGTH]; - UCHAR AironetOUI[] = {0x00, 0x40, 0x96, 0x00}; - UCHAR MICMN[16]; - UCHAR CalcMicBuffer[80]; - ULONG CalcMicBufferLen = 0; -#endif // LEAP_SUPPORT // - USHORT Status; - - // Block all authentication request durning WPA block period - if (pAd->StaCfg.bBlockAssoc == TRUE) - { - DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - Block ReAssoc request durning WPA block period!\n")); - pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; - Status = MLME_STATE_MACHINE_REJECT; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_REASSOC_CONF, 2, &Status); - } - // the parameters are the same as the association - else if(MlmeAssocReqSanity(pAd, Elem->Msg, Elem->MsgLen, ApAddr, &CapabilityInfo, &Timeout, &ListenIntv)) - { - RTMPCancelTimer(&pAd->MlmeAux.ReassocTimer, &TimerCancelled); - - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory - if(NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_TRACE,("ASSOC - MlmeReassocReqAction() allocate memory failed \n")); - pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; - Status = MLME_FAIL_NO_RESOURCE; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_REASSOC_CONF, 2, &Status); - return; - } - - COPY_MAC_ADDR(pAd->MlmeAux.Bssid, ApAddr); - - // make frame, use bssid as the AP address?? - DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - Send RE-ASSOC request...\n")); - MgtMacHeaderInit(pAd, &ReassocHdr, SUBTYPE_REASSOC_REQ, 0, ApAddr, ApAddr); - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(HEADER_802_11), &ReassocHdr, - 2, &CapabilityInfo, - 2, &ListenIntv, - MAC_ADDR_LEN, ApAddr, - 1, &SsidIe, - 1, &pAd->MlmeAux.SsidLen, - pAd->MlmeAux.SsidLen, pAd->MlmeAux.Ssid, - 1, &SupRateIe, - 1, &pAd->MlmeAux.SupRateLen, - pAd->MlmeAux.SupRateLen, pAd->MlmeAux.SupRate, - END_OF_ARGS); - - if (pAd->MlmeAux.ExtRateLen != 0) - { - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - 1, &ExtRateIe, - 1, &pAd->MlmeAux.ExtRateLen, - pAd->MlmeAux.ExtRateLen, pAd->MlmeAux.ExtRate, - END_OF_ARGS); - FrameLen += tmp; - } - - if (pAd->MlmeAux.APEdcaParm.bValid) - { - if (pAd->CommonCfg.bAPSDCapable && pAd->MlmeAux.APEdcaParm.bAPSDCapable) - { - QBSS_STA_INFO_PARM QosInfo; - - NdisZeroMemory(&QosInfo, sizeof(QBSS_STA_INFO_PARM)); - QosInfo.UAPSD_AC_BE = pAd->CommonCfg.bAPSDAC_BE; - QosInfo.UAPSD_AC_BK = pAd->CommonCfg.bAPSDAC_BK; - QosInfo.UAPSD_AC_VI = pAd->CommonCfg.bAPSDAC_VI; - QosInfo.UAPSD_AC_VO = pAd->CommonCfg.bAPSDAC_VO; - QosInfo.MaxSPLength = pAd->CommonCfg.MaxSPLength; - WmeIe[8] |= *(PUCHAR)&QosInfo; - } - - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - 9, &WmeIe[0], - END_OF_ARGS); - FrameLen += tmp; - } - -#ifdef DOT11_N_SUPPORT - // HT - if ((pAd->MlmeAux.HtCapabilityLen > 0) && (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) - { - ULONG TmpLen; - UCHAR HtLen; - UCHAR BROADCOM[4] = {0x0, 0x90, 0x4c, 0x33}; - if (pAd->StaActive.SupportedPhyInfo.bPreNHt == TRUE) - { - HtLen = SIZE_HT_CAP_IE + 4; - MakeOutgoingFrame(pOutBuffer + FrameLen, &TmpLen, - 1, &WpaIe, - 1, &HtLen, - 4, &BROADCOM[0], - pAd->MlmeAux.HtCapabilityLen, &pAd->MlmeAux.HtCapability, - END_OF_ARGS); - } - else - { - MakeOutgoingFrame(pOutBuffer + FrameLen, &TmpLen, - 1, &HtCapIe, - 1, &pAd->MlmeAux.HtCapabilityLen, - pAd->MlmeAux.HtCapabilityLen, &pAd->MlmeAux.HtCapability, - END_OF_ARGS); - } - FrameLen += TmpLen; - } -#endif // DOT11_N_SUPPORT // - - // add Ralink proprietary IE to inform AP this STA is going to use AGGREGATION or PIGGY-BACK+AGGREGATION - // Case I: (Aggregation + Piggy-Back) - // 1. user enable aggregation, AND - // 2. Mac support piggy-back - // 3. AP annouces it's PIGGY-BACK+AGGREGATION-capable in BEACON - // Case II: (Aggregation) - // 1. user enable aggregation, AND - // 2. AP annouces it's AGGREGATION-capable in BEACON - if (pAd->CommonCfg.bAggregationCapable) - { - if ((pAd->CommonCfg.bPiggyBackCapable) && ((pAd->MlmeAux.APRalinkIe & 0x00000003) == 3)) - { - ULONG TmpLen; - UCHAR RalinkIe[9] = {IE_VENDOR_SPECIFIC, 7, 0x00, 0x0c, 0x43, 0x03, 0x00, 0x00, 0x00}; - MakeOutgoingFrame(pOutBuffer+FrameLen, &TmpLen, - 9, RalinkIe, - END_OF_ARGS); - FrameLen += TmpLen; - } - else if (pAd->MlmeAux.APRalinkIe & 0x00000001) - { - ULONG TmpLen; - UCHAR RalinkIe[9] = {IE_VENDOR_SPECIFIC, 7, 0x00, 0x0c, 0x43, 0x01, 0x00, 0x00, 0x00}; - MakeOutgoingFrame(pOutBuffer+FrameLen, &TmpLen, - 9, RalinkIe, - END_OF_ARGS); - FrameLen += TmpLen; - } - } - else - { - ULONG TmpLen; - UCHAR RalinkIe[9] = {IE_VENDOR_SPECIFIC, 7, 0x00, 0x0c, 0x43, 0x04, 0x00, 0x00, 0x00}; - MakeOutgoingFrame(pOutBuffer+FrameLen, &TmpLen, - 9, RalinkIe, - END_OF_ARGS); - FrameLen += TmpLen; - } -#ifdef LEAP_SUPPORT - if (LEAP_CCKM_ON(pAd) && (pAd->StaCfg.CCKMLinkUpFlag == TRUE)) - { - CkipFlag = pAd->StaCfg.CkipFlag; // We have update that at PeerBeaconAtJoinRequest() - if (CkipFlag != 0) - { - NdisZeroMemory(CkipNegotiationBuffer, CKIP_NEGOTIATION_LENGTH); - CkipNegotiationBuffer[2] = 0x66; - // Make it try KP & MIC, since we have to follow the result from AssocRsp - CkipNegotiationBuffer[8] = 0x18; - CkipNegotiationBuffer[CKIP_NEGOTIATION_LENGTH - 1] = 0x22; - - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - 1, &AironetCkipIe, - 1, &AironetCkipLen, - AironetCkipLen, CkipNegotiationBuffer, - END_OF_ARGS); - FrameLen += tmp; - } - - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - 1, &AironetIPAddressIE, - 1, &AironetIPAddressLen, - AironetIPAddressLen, AironetIPAddressBuffer, - END_OF_ARGS); - FrameLen += tmp; - - // - // The RN is incremented before each reassociation request. - // - pAd->StaCfg.CCKMRN++; - // - // Calculate MIC = hmac-md5(krk, STA-ID|BSSID|RSNIE|TSF|RN); - // - COPY_MAC_ADDR(CalcMicBuffer, pAd->CurrentAddress); - CalcMicBufferLen = MAC_ADDR_LEN; - COPY_MAC_ADDR(CalcMicBuffer + CalcMicBufferLen, pAd->MlmeAux.Bssid); - CalcMicBufferLen += MAC_ADDR_LEN; - NdisMoveMemory(CalcMicBuffer + CalcMicBufferLen, CipherSuiteCiscoCCKM, CipherSuiteCiscoCCKMLen); - CalcMicBufferLen += CipherSuiteCiscoCCKMLen; - NdisMoveMemory(CalcMicBuffer + CalcMicBufferLen, (PUCHAR) &pAd->StaCfg.CCKMBeaconAtJoinTimeStamp, sizeof(pAd->StaCfg.CCKMBeaconAtJoinTimeStamp)); - CalcMicBufferLen += sizeof(pAd->StaCfg.CCKMBeaconAtJoinTimeStamp); - NdisMoveMemory(CalcMicBuffer + CalcMicBufferLen, (PUCHAR)&pAd->StaCfg.CCKMRN, sizeof(pAd->StaCfg.CCKMRN)); - CalcMicBufferLen += sizeof(pAd->StaCfg.CCKMRN); - hmac_md5(pAd->StaCfg.KRK, LEN_EAP_MICK, CalcMicBuffer, CalcMicBufferLen, MICMN); - - // - // fill up CCKM reassociation request element - // - NdisMoveMemory(AironetCCKMReassocBuffer, AironetOUI, 4); - NdisMoveMemory(AironetCCKMReassocBuffer + 4, (PUCHAR)&pAd->StaCfg.CCKMBeaconAtJoinTimeStamp, 8); - NdisMoveMemory(AironetCCKMReassocBuffer + 12, (PUCHAR) &pAd->StaCfg.CCKMRN, 4); - NdisMoveMemory(AironetCCKMReassocBuffer +16, MICMN, 8); - - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - 1, &AironetCCKMReassocIE, - 1, &AironetCCKMReassocLen, - AironetCCKMReassocLen, AironetCCKMReassocBuffer, - END_OF_ARGS); - FrameLen += tmp; - - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - CipherSuiteCiscoCCKMLen,CipherSuiteCiscoCCKM, - END_OF_ARGS); - FrameLen += tmp; - } -#endif // LEAP_SUPPORT // - - // Add CCX v2 request if CCX2 admin state is on - if (pAd->StaCfg.CCXControl.field.Enable == 1) - { - // - // Add CCX Version - // - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - 1, &Ccx2Ie, - 1, &Ccx2Len, - Ccx2Len, Ccx2IeInfo, - END_OF_ARGS); - FrameLen += tmp; - } - - MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); - - RTMPSetTimer(&pAd->MlmeAux.ReassocTimer, Timeout); /* in mSec */ - pAd->Mlme.AssocMachine.CurrState = REASSOC_WAIT_RSP; - } - else - { - DBGPRINT(RT_DEBUG_TRACE,("ASSOC - MlmeReassocReqAction() sanity check failed. BUG!!!! \n")); - pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; - Status = MLME_INVALID_FORMAT; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_REASSOC_CONF, 2, &Status); - } -} - -/* - ========================================================================== - Description: - Upper layer issues disassoc request - Parameters: - Elem - - - IRQL = PASSIVE_LEVEL - - ========================================================================== - */ -VOID MlmeDisassocReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - PMLME_DISASSOC_REQ_STRUCT pDisassocReq; - HEADER_802_11 DisassocHdr; - PHEADER_802_11 pDisassocHdr; - PUCHAR pOutBuffer = NULL; - ULONG FrameLen = 0; - NDIS_STATUS NStatus; - BOOLEAN TimerCancelled; - ULONG Timeout = 0; - USHORT Status; - -#ifdef QOS_DLS_SUPPORT - // send DLS-TEAR_DOWN message, - if (pAd->CommonCfg.bDLSCapable) - { - UCHAR i; - - // tear down local dls table entry - for (i=0; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH)) - { - RTMPSendDLSTearDownFrame(pAd, pAd->StaCfg.DLSEntry[i].MacAddr); - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - pAd->StaCfg.DLSEntry[i].Valid = FALSE; - } - } - - // tear down peer dls table entry - for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH)) - { - RTMPSendDLSTearDownFrame(pAd, pAd->StaCfg.DLSEntry[i].MacAddr); - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - pAd->StaCfg.DLSEntry[i].Valid = FALSE; - } - } - } -#endif // QOS_DLS_SUPPORT // - - // skip sanity check - pDisassocReq = (PMLME_DISASSOC_REQ_STRUCT)(Elem->Msg); - - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory - if (NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - MlmeDisassocReqAction() allocate memory failed\n")); - pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; - Status = MLME_FAIL_NO_RESOURCE; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_DISASSOC_CONF, 2, &Status); - return; - } - - - - RTMPCancelTimer(&pAd->MlmeAux.DisassocTimer, &TimerCancelled); - - DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - Send DISASSOC request[BSSID::%02x:%02x:%02x:%02x:%02x:%02x (Reason=%d)\n", - pDisassocReq->Addr[0], pDisassocReq->Addr[1], pDisassocReq->Addr[2], - pDisassocReq->Addr[3], pDisassocReq->Addr[4], pDisassocReq->Addr[5], pDisassocReq->Reason)); - MgtMacHeaderInit(pAd, &DisassocHdr, SUBTYPE_DISASSOC, 0, pDisassocReq->Addr, pDisassocReq->Addr); // patch peap ttls switching issue - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(HEADER_802_11),&DisassocHdr, - 2, &pDisassocReq->Reason, - END_OF_ARGS); - MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); - - // To patch Instance and Buffalo(N) AP - // Driver has to send deauth to Instance AP, but Buffalo(N) needs to send disassoc to reset Authenticator's state machine - // Therefore, we send both of them. - pDisassocHdr = (PHEADER_802_11)pOutBuffer; - pDisassocHdr->FC.SubType = SUBTYPE_DEAUTH; - MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); - - MlmeFreeMemory(pAd, pOutBuffer); - - pAd->StaCfg.DisassocReason = REASON_DISASSOC_STA_LEAVING; - COPY_MAC_ADDR(pAd->StaCfg.DisassocSta, pDisassocReq->Addr); - - RTMPSetTimer(&pAd->MlmeAux.DisassocTimer, Timeout); /* in mSec */ - pAd->Mlme.AssocMachine.CurrState = DISASSOC_WAIT_RSP; - -#ifdef WPA_SUPPLICANT_SUPPORT -#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT - if (pAd->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_DISABLE) - { - union iwreq_data wrqu; - //send disassociate event to wpa_supplicant - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.flags = RT_DISASSOC_EVENT_FLAG; - wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); - } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // -#endif // WPA_SUPPLICANT_SUPPORT // - -#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT - { - union iwreq_data wrqu; - memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN); - wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); - } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // - -} - -/* - ========================================================================== - Description: - peer sends assoc rsp back - Parameters: - Elme - MLME message containing the received frame - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID PeerAssocRspAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - USHORT CapabilityInfo, Status, Aid; - UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES], SupRateLen; - UCHAR ExtRate[MAX_LEN_OF_SUPPORTED_RATES], ExtRateLen; - UCHAR Addr2[MAC_ADDR_LEN]; - BOOLEAN TimerCancelled; - UCHAR CkipFlag; - EDCA_PARM EdcaParm; - HT_CAPABILITY_IE HtCapability; - ADD_HT_INFO_IE AddHtInfo; // AP might use this additional ht info IE - UCHAR HtCapabilityLen; - UCHAR AddHtInfoLen; - UCHAR NewExtChannelOffset = 0xff; - - if (PeerAssocRspSanity(pAd, Elem->Msg, Elem->MsgLen, Addr2, &CapabilityInfo, &Status, &Aid, SupRate, &SupRateLen, ExtRate, &ExtRateLen, - &HtCapability,&AddHtInfo, &HtCapabilityLen,&AddHtInfoLen,&NewExtChannelOffset, &EdcaParm, &CkipFlag)) - { - // The frame is for me ? - if(MAC_ADDR_EQUAL(Addr2, pAd->MlmeAux.Bssid)) - { - DBGPRINT(RT_DEBUG_TRACE, ("PeerAssocRspAction():ASSOC - receive ASSOC_RSP to me (status=%d)\n", Status)); -#ifdef DOT11_N_SUPPORT - DBGPRINT(RT_DEBUG_TRACE, ("PeerAssocRspAction():MacTable [%d].AMsduSize = %d. ClientStatusFlags = 0x%lx \n",Elem->Wcid, pAd->MacTab.Content[BSSID_WCID].AMsduSize, pAd->MacTab.Content[BSSID_WCID].ClientStatusFlags)); -#endif // DOT11_N_SUPPORT // - RTMPCancelTimer(&pAd->MlmeAux.AssocTimer, &TimerCancelled); - if(Status == MLME_SUCCESS) - { - UCHAR MaxSupportedRateIn500Kbps = 0; - UCHAR idx; - - // supported rates array may not be sorted. sort it and find the maximum rate - for (idx=0; idxMacTab.Content[BSSID_WCID], MaxSupportedRateIn500Kbps, &HtCapability, HtCapabilityLen, CapabilityInfo); - - pAd->StaCfg.CkipFlag = CkipFlag; - if (CkipFlag & 0x18) - { - NdisZeroMemory(pAd->StaCfg.TxSEQ, 4); - NdisZeroMemory(pAd->StaCfg.RxSEQ, 4); - NdisZeroMemory(pAd->StaCfg.CKIPMIC, 4); - pAd->StaCfg.GIV[0] = RandomByte(pAd); - pAd->StaCfg.GIV[1] = RandomByte(pAd); - pAd->StaCfg.GIV[2] = RandomByte(pAd); - pAd->StaCfg.bCkipOn = TRUE; - DBGPRINT(RT_DEBUG_TRACE, (" pAd->StaCfg.CkipFlag = 0x%02x\n", pAd->StaCfg.CkipFlag)); - } - } - else - { - // Faile on Association, we need to check the status code - // Is that a Rogue AP? -#ifdef LEAP_SUPPORT - if ((pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) && (Status == MLME_ALG_NOT_SUPPORT)) - { //Possibly Rogue AP - RogueApTableSetEntry(pAd, &pAd->StaCfg.RogueApTab, pAd->MlmeAux.Bssid, LEAP_REASON_INVALID_AUTH); - } -#endif // LEAP_SUPPORT // - } - pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_ASSOC_CONF, 2, &Status); - } - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - PeerAssocRspAction() sanity check fail\n")); - } -} - -/* - ========================================================================== - Description: - peer sends reassoc rsp - Parametrs: - Elem - MLME message cntaining the received frame - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID PeerReassocRspAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - USHORT CapabilityInfo; - USHORT Status; - USHORT Aid; - UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES], SupRateLen; - UCHAR ExtRate[MAX_LEN_OF_SUPPORTED_RATES], ExtRateLen; - UCHAR Addr2[MAC_ADDR_LEN]; - UCHAR CkipFlag; - BOOLEAN TimerCancelled; - EDCA_PARM EdcaParm; - HT_CAPABILITY_IE HtCapability; - ADD_HT_INFO_IE AddHtInfo; // AP might use this additional ht info IE - UCHAR HtCapabilityLen; - UCHAR AddHtInfoLen; - UCHAR NewExtChannelOffset = 0xff; - - if(PeerAssocRspSanity(pAd, Elem->Msg, Elem->MsgLen, Addr2, &CapabilityInfo, &Status, &Aid, SupRate, &SupRateLen, ExtRate, &ExtRateLen, - &HtCapability, &AddHtInfo, &HtCapabilityLen, &AddHtInfoLen,&NewExtChannelOffset, &EdcaParm, &CkipFlag)) - { - if(MAC_ADDR_EQUAL(Addr2, pAd->MlmeAux.Bssid)) // The frame is for me ? - { - DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - receive REASSOC_RSP to me (status=%d)\n", Status)); - RTMPCancelTimer(&pAd->MlmeAux.ReassocTimer, &TimerCancelled); - - if(Status == MLME_SUCCESS) - { - // go to procedure listed on page 376 - AssocPostProc(pAd, Addr2, CapabilityInfo, Aid, SupRate, SupRateLen, ExtRate, ExtRateLen, - &EdcaParm, &HtCapability, HtCapabilityLen, &AddHtInfo); - -#ifdef WPA_SUPPLICANT_SUPPORT -#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT - if (pAd->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_DISABLE) - { - union iwreq_data wrqu; - - SendAssocIEsToWpaSupplicant(pAd); - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.flags = RT_ASSOC_EVENT_FLAG; - wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); - } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // -#endif // WPA_SUPPLICANT_SUPPORT // - -#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT - { - union iwreq_data wrqu; - wext_notify_event_assoc(pAd); - - memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN); - memcpy(wrqu.ap_addr.sa_data, pAd->MlmeAux.Bssid, MAC_ADDR_LEN); - wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); - - } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // - - } - - // - // Cisco Leap CCKM supported Re-association. - // -#ifdef LEAP_SUPPORT - if (LEAP_CCKM_ON(pAd) && (pAd->StaCfg.CCKMLinkUpFlag == TRUE)) - { - if (CCKMAssocRspSanity(pAd, Elem->Msg, Elem->MsgLen) == TRUE) - { - pAd->StaCfg.CkipFlag = CkipFlag; - if (CkipFlag & 0x18) - { - NdisZeroMemory(pAd->StaCfg.TxSEQ, 4); - NdisZeroMemory(pAd->StaCfg.RxSEQ, 4); - NdisZeroMemory(pAd->StaCfg.CKIPMIC, 4); - pAd->StaCfg.GIV[0] = RandomByte(pAd); - pAd->StaCfg.GIV[1] = RandomByte(pAd); - pAd->StaCfg.GIV[2] = RandomByte(pAd); - pAd->StaCfg.bCkipOn = TRUE; - DBGPRINT(RT_DEBUG_TRACE, (" pAd->StaCfg.CkipFlag = 0x%02x\n", pAd->StaCfg.CkipFlag)); - } - - pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_REASSOC_CONF, 2, &Status); - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - CCKMAssocRspSanity() sanity check fail\n")); - } - } - else -#endif // LEAP_SUPPORT // - { - // CkipFlag is no use for reassociate - pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_REASSOC_CONF, 2, &Status); - } - } - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - PeerReassocRspAction() sanity check fail\n")); - } - -} - -/* - ========================================================================== - Description: - procedures on IEEE 802.11/1999 p.376 - Parametrs: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID AssocPostProc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pAddr2, - IN USHORT CapabilityInfo, - IN USHORT Aid, - IN UCHAR SupRate[], - IN UCHAR SupRateLen, - IN UCHAR ExtRate[], - IN UCHAR ExtRateLen, - IN PEDCA_PARM pEdcaParm, - IN HT_CAPABILITY_IE *pHtCapability, - IN UCHAR HtCapabilityLen, - IN ADD_HT_INFO_IE *pAddHtInfo) // AP might use this additional ht info IE -{ - ULONG Idx; - - pAd->MlmeAux.BssType = BSS_INFRA; - COPY_MAC_ADDR(pAd->MlmeAux.Bssid, pAddr2); - pAd->MlmeAux.Aid = Aid; - pAd->MlmeAux.CapabilityInfo = CapabilityInfo & SUPPORTED_CAPABILITY_INFO; -#ifdef DOT11_N_SUPPORT - // Some HT AP might lost WMM IE. We add WMM ourselves. beacuase HT requires QoS on. - if ((HtCapabilityLen > 0) && (pEdcaParm->bValid == FALSE)) - { - pEdcaParm->bValid = TRUE; - pEdcaParm->Aifsn[0] = 3; - pEdcaParm->Aifsn[1] = 7; - pEdcaParm->Aifsn[2] = 2; - pEdcaParm->Aifsn[3] = 2; - - pEdcaParm->Cwmin[0] = 4; - pEdcaParm->Cwmin[1] = 4; - pEdcaParm->Cwmin[2] = 3; - pEdcaParm->Cwmin[3] = 2; - - pEdcaParm->Cwmax[0] = 10; - pEdcaParm->Cwmax[1] = 10; - pEdcaParm->Cwmax[2] = 4; - pEdcaParm->Cwmax[3] = 3; - - pEdcaParm->Txop[0] = 0; - pEdcaParm->Txop[1] = 0; - pEdcaParm->Txop[2] = 96; - pEdcaParm->Txop[3] = 48; - - } -#endif // DOT11_N_SUPPORT // - - NdisMoveMemory(&pAd->MlmeAux.APEdcaParm, pEdcaParm, sizeof(EDCA_PARM)); - - // filter out un-supported rates - pAd->MlmeAux.SupRateLen = SupRateLen; - NdisMoveMemory(pAd->MlmeAux.SupRate, SupRate, SupRateLen); - RTMPCheckRates(pAd, pAd->MlmeAux.SupRate, &pAd->MlmeAux.SupRateLen); - - // filter out un-supported rates - pAd->MlmeAux.ExtRateLen = ExtRateLen; - NdisMoveMemory(pAd->MlmeAux.ExtRate, ExtRate, ExtRateLen); - RTMPCheckRates(pAd, pAd->MlmeAux.ExtRate, &pAd->MlmeAux.ExtRateLen); - -#ifdef DOT11_N_SUPPORT - if (HtCapabilityLen > 0) - { - RTMPCheckHt(pAd, BSSID_WCID, pHtCapability, pAddHtInfo); - } - DBGPRINT(RT_DEBUG_TRACE, ("AssocPostProc===> AP.AMsduSize = %d. ClientStatusFlags = 0x%lx \n", pAd->MacTab.Content[BSSID_WCID].AMsduSize, pAd->MacTab.Content[BSSID_WCID].ClientStatusFlags)); - - DBGPRINT(RT_DEBUG_TRACE, ("AssocPostProc===> (Mmps=%d, AmsduSize=%d, )\n", - pAd->MacTab.Content[BSSID_WCID].MmpsMode, pAd->MacTab.Content[BSSID_WCID].AMsduSize)); -#endif // DOT11_N_SUPPORT // - - // Set New WPA information - Idx = BssTableSearch(&pAd->ScanTab, pAddr2, pAd->MlmeAux.Channel); - if (Idx == BSS_NOT_FOUND) - { - DBGPRINT_ERR(("ASSOC - Can't find BSS after receiving Assoc response\n")); - } - else - { - // Init variable - pAd->MacTab.Content[BSSID_WCID].RSNIE_Len = 0; - NdisZeroMemory(pAd->MacTab.Content[BSSID_WCID].RSN_IE, MAX_LEN_OF_RSNIE); - - // Store appropriate RSN_IE for WPA SM negotiation later - if ((pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) && (pAd->ScanTab.BssEntry[Idx].VarIELen != 0)) - { - PUCHAR pVIE; - USHORT len; - PEID_STRUCT pEid; - - pVIE = pAd->ScanTab.BssEntry[Idx].VarIEs; - len = pAd->ScanTab.BssEntry[Idx].VarIELen; - - while (len > 0) - { - pEid = (PEID_STRUCT) pVIE; - // For WPA/WPAPSK - if ((pEid->Eid == IE_WPA) && (NdisEqualMemory(pEid->Octet, WPA_OUI, 4)) - && (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA || pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) - { - NdisMoveMemory(pAd->MacTab.Content[BSSID_WCID].RSN_IE, pVIE, (pEid->Len + 2)); - pAd->MacTab.Content[BSSID_WCID].RSNIE_Len = (pEid->Len + 2); - DBGPRINT(RT_DEBUG_TRACE, ("AssocPostProc===> Store RSN_IE for WPA SM negotiation \n")); - } - // For WPA2/WPA2PSK - else if ((pEid->Eid == IE_RSN) && (NdisEqualMemory(pEid->Octet + 2, RSN_OUI, 3)) - && (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2 || pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)) - { - NdisMoveMemory(pAd->MacTab.Content[BSSID_WCID].RSN_IE, pVIE, (pEid->Len + 2)); - pAd->MacTab.Content[BSSID_WCID].RSNIE_Len = (pEid->Len + 2); - DBGPRINT(RT_DEBUG_TRACE, ("AssocPostProc===> Store RSN_IE for WPA2 SM negotiation \n")); - } - - pVIE += (pEid->Len + 2); - len -= (pEid->Len + 2); - } - } - - if (pAd->MacTab.Content[BSSID_WCID].RSNIE_Len == 0) - { - DBGPRINT(RT_DEBUG_TRACE, ("AssocPostProc===> no RSN_IE \n")); - } - else - { - hex_dump("RSN_IE", pAd->MacTab.Content[BSSID_WCID].RSN_IE, pAd->MacTab.Content[BSSID_WCID].RSNIE_Len); - } - } -} - -/* - ========================================================================== - Description: - left part of IEEE 802.11/1999 p.374 - Parameters: - Elem - MLME message containing the received frame - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID PeerDisassocAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - UCHAR Addr2[MAC_ADDR_LEN]; - USHORT Reason; - - DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - PeerDisassocAction()\n")); - if(PeerDisassocSanity(pAd, Elem->Msg, Elem->MsgLen, Addr2, &Reason)) - { - DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - PeerDisassocAction() Reason = %d\n", Reason)); - if (INFRA_ON(pAd) && MAC_ADDR_EQUAL(pAd->CommonCfg.Bssid, Addr2)) - { - - if (pAd->CommonCfg.bWirelessEvent) - { - RTMPSendWirelessEvent(pAd, IW_DISASSOC_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); - } - - -#ifdef LEAP_SUPPORT - if (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) - { - // Cisco_LEAP has start a timer - // We should cancel it if using LEAP - RTMPCancelTimer(&pAd->StaCfg.LeapAuthTimer, &TimerCancelled); - //Check is it mach the LEAP Authentication failed as possible a Rogue AP - //on it's PortSecured not equal to WPA_802_1X_PORT_SECURED while process the Association. - if ((pAd->Mlme.LeapMachine.CurrState != LEAP_IDLE) && (pAd->StaCfg.PortSecured != WPA_802_1X_PORT_SECURED)) - { - RogueApTableSetEntry(pAd, &pAd->StaCfg.RogueApTab, Addr2, LEAP_REASON_AUTH_TIMEOUT); - } - } -#endif // LEAP_SUPPORT // - // - // Get Current System time and Turn on AdjacentAPReport - // - NdisGetSystemUpTime(&pAd->StaCfg.CCXAdjacentAPLinkDownTime); - pAd->StaCfg.CCXAdjacentAPReportFlag = TRUE; - LinkDown(pAd, TRUE); - pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; - -#ifdef WPA_SUPPLICANT_SUPPORT -#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT - if (pAd->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_DISABLE) - { - union iwreq_data wrqu; - //send disassociate event to wpa_supplicant - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.flags = RT_DISASSOC_EVENT_FLAG; - wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); - } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // -#endif // WPA_SUPPLICANT_SUPPORT // - -#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT - { - union iwreq_data wrqu; - memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN); - wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); - } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // - } - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - PeerDisassocAction() sanity check fail\n")); - } - -} - -/* - ========================================================================== - Description: - what the state machine will do after assoc timeout - Parameters: - Elme - - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID AssocTimeoutAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - USHORT Status; - DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - AssocTimeoutAction\n")); - pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; - Status = MLME_REJ_TIMEOUT; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_ASSOC_CONF, 2, &Status); -} - -/* - ========================================================================== - Description: - what the state machine will do after reassoc timeout - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID ReassocTimeoutAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - USHORT Status; - DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - ReassocTimeoutAction\n")); - pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; - Status = MLME_REJ_TIMEOUT; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_REASSOC_CONF, 2, &Status); -} - -/* - ========================================================================== - Description: - what the state machine will do after disassoc timeout - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID DisassocTimeoutAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - USHORT Status; - DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - DisassocTimeoutAction\n")); - pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; - Status = MLME_SUCCESS; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_DISASSOC_CONF, 2, &Status); -} - -VOID InvalidStateWhenAssoc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - USHORT Status; - DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - InvalidStateWhenAssoc(state=%ld), reset ASSOC state machine\n", - pAd->Mlme.AssocMachine.CurrState)); - pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; - Status = MLME_STATE_MACHINE_REJECT; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_ASSOC_CONF, 2, &Status); -} - -VOID InvalidStateWhenReassoc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - USHORT Status; - DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - InvalidStateWhenReassoc(state=%ld), reset ASSOC state machine\n", - pAd->Mlme.AssocMachine.CurrState)); - pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; - Status = MLME_STATE_MACHINE_REJECT; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_REASSOC_CONF, 2, &Status); -} - -VOID InvalidStateWhenDisassociate( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - USHORT Status; - DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - InvalidStateWhenDisassoc(state=%ld), reset ASSOC state machine\n", - pAd->Mlme.AssocMachine.CurrState)); - pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; - Status = MLME_STATE_MACHINE_REJECT; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_DISASSOC_CONF, 2, &Status); -} - -/* - ========================================================================== - Description: - right part of IEEE 802.11/1999 page 374 - Note: - This event should never cause ASSOC state machine perform state - transition, and has no relationship with CNTL machine. So we separate - this routine as a service outside of ASSOC state transition table. - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID Cls3errAction( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pAddr) -{ - HEADER_802_11 DisassocHdr; - PHEADER_802_11 pDisassocHdr; - PUCHAR pOutBuffer = NULL; - ULONG FrameLen = 0; - NDIS_STATUS NStatus; - USHORT Reason = REASON_CLS3ERR; - - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory - if (NStatus != NDIS_STATUS_SUCCESS) - return; - - DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - Class 3 Error, Send DISASSOC frame\n")); - MgtMacHeaderInit(pAd, &DisassocHdr, SUBTYPE_DISASSOC, 0, pAddr, pAd->CommonCfg.Bssid); // patch peap ttls switching issue - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(HEADER_802_11),&DisassocHdr, - 2, &Reason, - END_OF_ARGS); - MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); - - // To patch Instance and Buffalo(N) AP - // Driver has to send deauth to Instance AP, but Buffalo(N) needs to send disassoc to reset Authenticator's state machine - // Therefore, we send both of them. - pDisassocHdr = (PHEADER_802_11)pOutBuffer; - pDisassocHdr->FC.SubType = SUBTYPE_DEAUTH; - MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); - - MlmeFreeMemory(pAd, pOutBuffer); - - pAd->StaCfg.DisassocReason = REASON_CLS3ERR; - COPY_MAC_ADDR(pAd->StaCfg.DisassocSta, pAddr); -} - - /* - ========================================================================== - Description: - Switch between WEP and CKIP upon new association up. - Parameters: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID SwitchBetweenWepAndCkip( - IN PRTMP_ADAPTER pAd) -{ - int i; - SHAREDKEY_MODE_STRUC csr1; - - // if KP is required. change the CipherAlg in hardware shard key table from WEP - // to CKIP. else remain as WEP - if (pAd->StaCfg.bCkipOn && (pAd->StaCfg.CkipFlag & 0x10)) - { - // modify hardware key table so that MAC use correct algorithm to decrypt RX - RTMP_IO_READ32(pAd, SHARED_KEY_MODE_BASE, &csr1.word); - if (csr1.field.Bss0Key0CipherAlg == CIPHER_WEP64) - csr1.field.Bss0Key0CipherAlg = CIPHER_CKIP64; - else if (csr1.field.Bss0Key0CipherAlg == CIPHER_WEP128) - csr1.field.Bss0Key0CipherAlg = CIPHER_CKIP128; - - if (csr1.field.Bss0Key1CipherAlg == CIPHER_WEP64) - csr1.field.Bss0Key1CipherAlg = CIPHER_CKIP64; - else if (csr1.field.Bss0Key1CipherAlg == CIPHER_WEP128) - csr1.field.Bss0Key1CipherAlg = CIPHER_CKIP128; - - if (csr1.field.Bss0Key2CipherAlg == CIPHER_WEP64) - csr1.field.Bss0Key2CipherAlg = CIPHER_CKIP64; - else if (csr1.field.Bss0Key2CipherAlg == CIPHER_WEP128) - csr1.field.Bss0Key2CipherAlg = CIPHER_CKIP128; - - if (csr1.field.Bss0Key3CipherAlg == CIPHER_WEP64) - csr1.field.Bss0Key3CipherAlg = CIPHER_CKIP64; - else if (csr1.field.Bss0Key3CipherAlg == CIPHER_WEP128) - csr1.field.Bss0Key3CipherAlg = CIPHER_CKIP128; - RTMP_IO_WRITE32(pAd, SHARED_KEY_MODE_BASE, csr1.word); - DBGPRINT(RT_DEBUG_TRACE, ("SwitchBetweenWepAndCkip: modify BSS0 cipher to %s\n", CipherName[csr1.field.Bss0Key0CipherAlg])); - - // modify software key table so that driver can specify correct algorithm in TXD upon TX - for (i=0; iSharedKey[BSS0][i].CipherAlg == CIPHER_WEP64) - pAd->SharedKey[BSS0][i].CipherAlg = CIPHER_CKIP64; - else if (pAd->SharedKey[BSS0][i].CipherAlg == CIPHER_WEP128) - pAd->SharedKey[BSS0][i].CipherAlg = CIPHER_CKIP128; - } - } - - // else if KP NOT inused. change the CipherAlg in hardware shard key table from CKIP - // to WEP. - else - { - // modify hardware key table so that MAC use correct algorithm to decrypt RX - RTMP_IO_READ32(pAd, SHARED_KEY_MODE_BASE, &csr1.word); - if (csr1.field.Bss0Key0CipherAlg == CIPHER_CKIP64) - csr1.field.Bss0Key0CipherAlg = CIPHER_WEP64; - else if (csr1.field.Bss0Key0CipherAlg == CIPHER_CKIP128) - csr1.field.Bss0Key0CipherAlg = CIPHER_WEP128; - - if (csr1.field.Bss0Key1CipherAlg == CIPHER_CKIP64) - csr1.field.Bss0Key1CipherAlg = CIPHER_WEP64; - else if (csr1.field.Bss0Key1CipherAlg == CIPHER_CKIP128) - csr1.field.Bss0Key1CipherAlg = CIPHER_WEP128; - - if (csr1.field.Bss0Key2CipherAlg == CIPHER_CKIP64) - csr1.field.Bss0Key2CipherAlg = CIPHER_WEP64; - else if (csr1.field.Bss0Key2CipherAlg == CIPHER_CKIP128) - csr1.field.Bss0Key2CipherAlg = CIPHER_WEP128; - - if (csr1.field.Bss0Key3CipherAlg == CIPHER_CKIP64) - csr1.field.Bss0Key3CipherAlg = CIPHER_WEP64; - else if (csr1.field.Bss0Key3CipherAlg == CIPHER_CKIP128) - csr1.field.Bss0Key3CipherAlg = CIPHER_WEP128; - - // modify software key table so that driver can specify correct algorithm in TXD upon TX - for (i=0; iSharedKey[BSS0][i].CipherAlg == CIPHER_CKIP64) - pAd->SharedKey[BSS0][i].CipherAlg = CIPHER_WEP64; - else if (pAd->SharedKey[BSS0][i].CipherAlg == CIPHER_CKIP128) - pAd->SharedKey[BSS0][i].CipherAlg = CIPHER_WEP128; - } - - // - // On WPA-NONE, must update CipherAlg. - // Because the OID_802_11_WEP_STATUS was been set after OID_802_11_ADD_KEY - // and CipherAlg will be CIPHER_NONE by Windows ZeroConfig. - // So we need to update CipherAlg after connect. - // - if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) - { - for (i = 0; i < SHARE_KEY_NUM; i++) - { - if (pAd->SharedKey[BSS0][i].KeyLen != 0) - { - if (pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) - { - pAd->SharedKey[BSS0][i].CipherAlg = CIPHER_TKIP; - } - else if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) - { - pAd->SharedKey[BSS0][i].CipherAlg = CIPHER_AES; - } - } - else - { - pAd->SharedKey[BSS0][i].CipherAlg = CIPHER_NONE; - } - } - - csr1.field.Bss0Key0CipherAlg = pAd->SharedKey[BSS0][0].CipherAlg; - csr1.field.Bss0Key1CipherAlg = pAd->SharedKey[BSS0][1].CipherAlg; - csr1.field.Bss0Key2CipherAlg = pAd->SharedKey[BSS0][2].CipherAlg; - csr1.field.Bss0Key3CipherAlg = pAd->SharedKey[BSS0][3].CipherAlg; - } - RTMP_IO_WRITE32(pAd, SHARED_KEY_MODE_BASE, csr1.word); - DBGPRINT(RT_DEBUG_TRACE, ("SwitchBetweenWepAndCkip: modify BSS0 cipher to %s\n", CipherName[csr1.field.Bss0Key0CipherAlg])); - } -} - -#ifdef WPA_SUPPLICANT_SUPPORT -#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT -VOID SendAssocIEsToWpaSupplicant( - IN PRTMP_ADAPTER pAd) -{ - union iwreq_data wrqu; - unsigned char custom[IW_CUSTOM_MAX] = {0}; - - if ((pAd->StaCfg.ReqVarIELen + 17) <= IW_CUSTOM_MAX) - { - sprintf(custom, "ASSOCINFO_ReqIEs="); - NdisMoveMemory(custom+17, pAd->StaCfg.ReqVarIEs, pAd->StaCfg.ReqVarIELen); - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.length = pAd->StaCfg.ReqVarIELen + 17; - wrqu.data.flags = RT_REQIE_EVENT_FLAG; - wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, custom); - - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.flags = RT_ASSOCINFO_EVENT_FLAG; - wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); - } - else - DBGPRINT(RT_DEBUG_TRACE, ("pAd->StaCfg.ReqVarIELen + 17 > MAX_CUSTOM_LEN\n")); - - return; -} -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // -#endif // WPA_SUPPLICANT_SUPPORT // - -#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT -int wext_notify_event_assoc( - IN RTMP_ADAPTER *pAd) -{ - union iwreq_data wrqu; - char custom[IW_CUSTOM_MAX] = {0}; - -#if WIRELESS_EXT > 17 - if (pAd->StaCfg.ReqVarIELen <= IW_CUSTOM_MAX) - { - wrqu.data.length = pAd->StaCfg.ReqVarIELen; - memcpy(custom, pAd->StaCfg.ReqVarIEs, pAd->StaCfg.ReqVarIELen); - wireless_send_event(pAd->net_dev, IWEVASSOCREQIE, &wrqu, custom); - } - else - DBGPRINT(RT_DEBUG_TRACE, ("pAd->StaCfg.ReqVarIELen > MAX_CUSTOM_LEN\n")); -#else - if (((pAd->StaCfg.ReqVarIELen*2) + 17) <= IW_CUSTOM_MAX) - { - UCHAR idx; - wrqu.data.length = (pAd->StaCfg.ReqVarIELen*2) + 17; - sprintf(custom, "ASSOCINFO(ReqIEs="); - for (idx=0; idxStaCfg.ReqVarIELen; idx++) - sprintf(custom, "%s%02x", custom, pAd->StaCfg.ReqVarIEs[idx]); - wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, custom); - } - else - DBGPRINT(RT_DEBUG_TRACE, ("(pAd->StaCfg.ReqVarIELen*2) + 17 > MAX_CUSTOM_LEN\n")); -#endif - - return 0; - -} -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // - - -BOOLEAN StaAddMacTableEntry( - IN PRTMP_ADAPTER pAd, - IN PMAC_TABLE_ENTRY pEntry, - IN UCHAR MaxSupportedRateIn500Kbps, - IN HT_CAPABILITY_IE *pHtCapability, - IN UCHAR HtCapabilityLen, - IN USHORT CapabilityInfo) -{ - UCHAR MaxSupportedRate = RATE_11; - - if (ADHOC_ON(pAd)) - CLIENT_STATUS_CLEAR_FLAG(pEntry, fCLIENT_STATUS_WMM_CAPABLE); - - switch (MaxSupportedRateIn500Kbps) - { - case 108: MaxSupportedRate = RATE_54; break; - case 96: MaxSupportedRate = RATE_48; break; - case 72: MaxSupportedRate = RATE_36; break; - case 48: MaxSupportedRate = RATE_24; break; - case 36: MaxSupportedRate = RATE_18; break; - case 24: MaxSupportedRate = RATE_12; break; - case 18: MaxSupportedRate = RATE_9; break; - case 12: MaxSupportedRate = RATE_6; break; - case 22: MaxSupportedRate = RATE_11; break; - case 11: MaxSupportedRate = RATE_5_5; break; - case 4: MaxSupportedRate = RATE_2; break; - case 2: MaxSupportedRate = RATE_1; break; - default: MaxSupportedRate = RATE_11; break; - } - - if ((pAd->CommonCfg.PhyMode == PHY_11G) && (MaxSupportedRate < RATE_FIRST_OFDM_RATE)) - return FALSE; - -#ifdef DOT11_N_SUPPORT - // 11n only - if (((pAd->CommonCfg.PhyMode == PHY_11N_2_4G) || (pAd->CommonCfg.PhyMode == PHY_11N_5G))&& (HtCapabilityLen == 0)) - return FALSE; -#endif // DOT11_N_SUPPORT // - - if (!pEntry) - return FALSE; - - NdisAcquireSpinLock(&pAd->MacTabLock); - if (pEntry) - { - pEntry->PortSecured = WPA_802_1X_PORT_SECURED; - if ((MaxSupportedRate < RATE_FIRST_OFDM_RATE) || - (pAd->CommonCfg.PhyMode == PHY_11B)) - { - pEntry->RateLen = 4; - if (MaxSupportedRate >= RATE_FIRST_OFDM_RATE) - MaxSupportedRate = RATE_11; - } - else - pEntry->RateLen = 12; - - pEntry->MaxHTPhyMode.word = 0; - pEntry->MinHTPhyMode.word = 0; - pEntry->HTPhyMode.word = 0; - pEntry->MaxSupportedRate = MaxSupportedRate; - if (pEntry->MaxSupportedRate < RATE_FIRST_OFDM_RATE) - { - pEntry->MaxHTPhyMode.field.MODE = MODE_CCK; - pEntry->MaxHTPhyMode.field.MCS = pEntry->MaxSupportedRate; - pEntry->MinHTPhyMode.field.MODE = MODE_CCK; - pEntry->MinHTPhyMode.field.MCS = pEntry->MaxSupportedRate; - pEntry->HTPhyMode.field.MODE = MODE_CCK; - pEntry->HTPhyMode.field.MCS = pEntry->MaxSupportedRate; - } - else - { - pEntry->MaxHTPhyMode.field.MODE = MODE_OFDM; - pEntry->MaxHTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; - pEntry->MinHTPhyMode.field.MODE = MODE_OFDM; - pEntry->MinHTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; - pEntry->HTPhyMode.field.MODE = MODE_OFDM; - pEntry->HTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; - } - pEntry->CapabilityInfo = CapabilityInfo; - CLIENT_STATUS_CLEAR_FLAG(pEntry, fCLIENT_STATUS_AGGREGATION_CAPABLE); - CLIENT_STATUS_CLEAR_FLAG(pEntry, fCLIENT_STATUS_PIGGYBACK_CAPABLE); - } - -#ifdef DOT11_N_SUPPORT - // If this Entry supports 802.11n, upgrade to HT rate. - if ((HtCapabilityLen != 0) && (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) - { - UCHAR j, bitmask; //k,bitmask; - CHAR i; - - if (ADHOC_ON(pAd)) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_WMM_CAPABLE); - if ((pHtCapability->HtCapInfo.GF) && (pAd->CommonCfg.DesiredHtPhy.GF)) - { - pEntry->MaxHTPhyMode.field.MODE = MODE_HTGREENFIELD; - } - else - { - pEntry->MaxHTPhyMode.field.MODE = MODE_HTMIX; - pAd->MacTab.fAnyStationNonGF = TRUE; - pAd->CommonCfg.AddHTInfo.AddHtInfo2.NonGfPresent = 1; - } - - if ((pHtCapability->HtCapInfo.ChannelWidth) && (pAd->CommonCfg.DesiredHtPhy.ChannelWidth)) - { - pEntry->MaxHTPhyMode.field.BW= BW_40; - pEntry->MaxHTPhyMode.field.ShortGI = ((pAd->CommonCfg.DesiredHtPhy.ShortGIfor40)&(pHtCapability->HtCapInfo.ShortGIfor40)); - } - else - { - pEntry->MaxHTPhyMode.field.BW = BW_20; - pEntry->MaxHTPhyMode.field.ShortGI = ((pAd->CommonCfg.DesiredHtPhy.ShortGIfor20)&(pHtCapability->HtCapInfo.ShortGIfor20)); - pAd->MacTab.fAnyStation20Only = TRUE; - } - - // 3*3 - if (pAd->MACVersion >= RALINK_2883_VERSION && pAd->MACVersion < RALINK_3070_VERSION) - pEntry->MaxHTPhyMode.field.TxBF = pAd->CommonCfg.RegTransmitSetting.field.TxBF; - - // find max fixed rate - for (i=23; i>=0; i--) // 3*3 - { - j = i/8; - bitmask = (1<<(i-(j*8))); - if ((pAd->StaCfg.DesiredHtPhyInfo.MCSSet[j] & bitmask) && (pHtCapability->MCSSet[j] & bitmask)) - { - pEntry->MaxHTPhyMode.field.MCS = i; - break; - } - if (i==0) - break; - } - - - if (pAd->StaCfg.DesiredTransmitSetting.field.MCS != MCS_AUTO) - { - if (pAd->StaCfg.DesiredTransmitSetting.field.MCS == 32) - { - // Fix MCS as HT Duplicated Mode - pEntry->MaxHTPhyMode.field.BW = 1; - pEntry->MaxHTPhyMode.field.MODE = MODE_HTMIX; - pEntry->MaxHTPhyMode.field.STBC = 0; - pEntry->MaxHTPhyMode.field.ShortGI = 0; - pEntry->MaxHTPhyMode.field.MCS = 32; - } - else if (pEntry->MaxHTPhyMode.field.MCS > pAd->StaCfg.HTPhyMode.field.MCS) - { - // STA supports fixed MCS - pEntry->MaxHTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; - } - } - - pEntry->MaxHTPhyMode.field.STBC = (pHtCapability->HtCapInfo.RxSTBC & (pAd->CommonCfg.DesiredHtPhy.TxSTBC)); - pEntry->MpduDensity = pHtCapability->HtCapParm.MpduDensity; - pEntry->MaxRAmpduFactor = pHtCapability->HtCapParm.MaxRAmpduFactor; - pEntry->MmpsMode = (UCHAR)pHtCapability->HtCapInfo.MimoPs; - pEntry->AMsduSize = (UCHAR)pHtCapability->HtCapInfo.AMsduSize; - pEntry->HTPhyMode.word = pEntry->MaxHTPhyMode.word; - - if (pAd->CommonCfg.DesiredHtPhy.AmsduEnable && (pAd->CommonCfg.REGBACapability.field.AutoBA == FALSE)) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_AMSDU_INUSED); - if (pHtCapability->HtCapInfo.ShortGIfor20) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_SGI20_CAPABLE); - if (pHtCapability->HtCapInfo.ShortGIfor40) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_SGI40_CAPABLE); - if (pHtCapability->HtCapInfo.TxSTBC) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_TxSTBC_CAPABLE); - if (pHtCapability->HtCapInfo.RxSTBC) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_RxSTBC_CAPABLE); - if (pHtCapability->ExtHtCapInfo.PlusHTC) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_HTC_CAPABLE); - if (pAd->CommonCfg.bRdg && pHtCapability->ExtHtCapInfo.RDGSupport) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_RDG_CAPABLE); - if (pHtCapability->ExtHtCapInfo.MCSFeedback == 0x03) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_MCSFEEDBACK_CAPABLE); - } - else - { - pAd->MacTab.fAnyStationIsLegacy = TRUE; - } - - NdisMoveMemory(&pEntry->HTCapability, pHtCapability, sizeof(HT_CAPABILITY_IE)); -#endif // DOT11_N_SUPPORT // - - pEntry->HTPhyMode.word = pEntry->MaxHTPhyMode.word; - pEntry->CurrTxRate = pEntry->MaxSupportedRate; - - // Set asic auto fall back - if (pAd->StaCfg.bAutoTxRateSwitch == TRUE) - { - PUCHAR pTable; - UCHAR TableSize = 0; - - MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize, &pEntry->CurrTxRateIndex); - pEntry->bAutoTxRateSwitch = TRUE; - } - else - { - pEntry->HTPhyMode.field.MODE = pAd->StaCfg.HTPhyMode.field.MODE; - pEntry->HTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; - pEntry->bAutoTxRateSwitch = FALSE; - - // If the legacy mode is set, overwrite the transmit setting of this entry. - RTMPUpdateLegacyTxSetting((UCHAR)pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode, pEntry); - } - - pEntry->PortSecured = WPA_802_1X_PORT_SECURED; - pEntry->Sst = SST_ASSOC; - pEntry->AuthState = AS_AUTH_OPEN; - pEntry->AuthMode = pAd->StaCfg.AuthMode; - pEntry->WepStatus = pAd->StaCfg.WepStatus; - - NdisReleaseSpinLock(&pAd->MacTabLock); - -#ifdef WPA_SUPPLICANT_SUPPORT -#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT - if (pAd->StaCfg.WpaSupplicantUP) - { - union iwreq_data wrqu; - - SendAssocIEsToWpaSupplicant(pAd); - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.flags = RT_ASSOC_EVENT_FLAG; - wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); - } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // -#endif // WPA_SUPPLICANT_SUPPORT // - -#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT - { - union iwreq_data wrqu; - wext_notify_event_assoc(pAd); - - memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN); - memcpy(wrqu.ap_addr.sa_data, pAd->MlmeAux.Bssid, MAC_ADDR_LEN); - wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); - - } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // - return TRUE; -} - - +#include "../../rt2870/sta/assoc.c" diff --git a/drivers/staging/rt3070/sta/auth.c b/drivers/staging/rt3070/sta/auth.c index 032b5df058bc..d55198288d92 100644 --- a/drivers/staging/rt3070/sta/auth.c +++ b/drivers/staging/rt3070/sta/auth.c @@ -1,475 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - auth.c - - Abstract: - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - John 2004-9-3 porting from RT2500 -*/ -#include "../rt_config.h" - -/* - ========================================================================== - Description: - authenticate state machine init, including state transition and timer init - Parameters: - Sm - pointer to the auth state machine - Note: - The state machine looks like this - - AUTH_REQ_IDLE AUTH_WAIT_SEQ2 AUTH_WAIT_SEQ4 - MT2_MLME_AUTH_REQ mlme_auth_req_action invalid_state_when_auth invalid_state_when_auth - MT2_PEER_AUTH_EVEN drop peer_auth_even_at_seq2_action peer_auth_even_at_seq4_action - MT2_AUTH_TIMEOUT Drop auth_timeout_action auth_timeout_action - - IRQL = PASSIVE_LEVEL - - ========================================================================== - */ - -void AuthStateMachineInit( - IN PRTMP_ADAPTER pAd, - IN STATE_MACHINE *Sm, - OUT STATE_MACHINE_FUNC Trans[]) -{ - StateMachineInit(Sm, Trans, MAX_AUTH_STATE, MAX_AUTH_MSG, (STATE_MACHINE_FUNC)Drop, AUTH_REQ_IDLE, AUTH_MACHINE_BASE); - - // the first column - StateMachineSetAction(Sm, AUTH_REQ_IDLE, MT2_MLME_AUTH_REQ, (STATE_MACHINE_FUNC)MlmeAuthReqAction); - - // the second column - StateMachineSetAction(Sm, AUTH_WAIT_SEQ2, MT2_MLME_AUTH_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenAuth); - StateMachineSetAction(Sm, AUTH_WAIT_SEQ2, MT2_PEER_AUTH_EVEN, (STATE_MACHINE_FUNC)PeerAuthRspAtSeq2Action); - StateMachineSetAction(Sm, AUTH_WAIT_SEQ2, MT2_AUTH_TIMEOUT, (STATE_MACHINE_FUNC)AuthTimeoutAction); - - // the third column - StateMachineSetAction(Sm, AUTH_WAIT_SEQ4, MT2_MLME_AUTH_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenAuth); - StateMachineSetAction(Sm, AUTH_WAIT_SEQ4, MT2_PEER_AUTH_EVEN, (STATE_MACHINE_FUNC)PeerAuthRspAtSeq4Action); - StateMachineSetAction(Sm, AUTH_WAIT_SEQ4, MT2_AUTH_TIMEOUT, (STATE_MACHINE_FUNC)AuthTimeoutAction); - - RTMPInitTimer(pAd, &pAd->MlmeAux.AuthTimer, GET_TIMER_FUNCTION(AuthTimeout), pAd, FALSE); -} - -/* - ========================================================================== - Description: - function to be executed at timer thread when auth timer expires - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID AuthTimeout( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3) -{ - RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext; - - DBGPRINT(RT_DEBUG_TRACE,("AUTH - AuthTimeout\n")); - - // Do nothing if the driver is starting halt state. - // This might happen when timer already been fired before cancel timer with mlmehalt - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) - return; - - // send a de-auth to reset AP's state machine (Patch AP-Dir635) - if (pAd->Mlme.AuthMachine.CurrState == AUTH_WAIT_SEQ2) - Cls2errAction(pAd, pAd->MlmeAux.Bssid); - - - MlmeEnqueue(pAd, AUTH_STATE_MACHINE, MT2_AUTH_TIMEOUT, 0, NULL); - RT28XX_MLME_HANDLER(pAd); -} - - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID MlmeAuthReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - UCHAR Addr[6]; - USHORT Alg, Seq, Status; - ULONG Timeout; - HEADER_802_11 AuthHdr; - BOOLEAN TimerCancelled; - NDIS_STATUS NStatus; - PUCHAR pOutBuffer = NULL; - ULONG FrameLen = 0; - - // Block all authentication request durning WPA block period - if (pAd->StaCfg.bBlockAssoc == TRUE) - { - DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Block Auth request durning WPA block period!\n")); - pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; - Status = MLME_STATE_MACHINE_REJECT; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status); - } - else if(MlmeAuthReqSanity(pAd, Elem->Msg, Elem->MsgLen, Addr, &Timeout, &Alg)) - { - // reset timer - RTMPCancelTimer(&pAd->MlmeAux.AuthTimer, &TimerCancelled); - COPY_MAC_ADDR(pAd->MlmeAux.Bssid, Addr); - pAd->MlmeAux.Alg = Alg; - Seq = 1; - Status = MLME_SUCCESS; - - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory - if(NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_TRACE, ("AUTH - MlmeAuthReqAction(Alg:%d) allocate memory failed\n", Alg)); - pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; - Status = MLME_FAIL_NO_RESOURCE; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status); - return; - } - - DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Send AUTH request seq#1 (Alg=%d)...\n", Alg)); - MgtMacHeaderInit(pAd, &AuthHdr, SUBTYPE_AUTH, 0, Addr, pAd->MlmeAux.Bssid); - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(HEADER_802_11),&AuthHdr, - 2, &Alg, - 2, &Seq, - 2, &Status, - END_OF_ARGS); - MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); - - RTMPSetTimer(&pAd->MlmeAux.AuthTimer, Timeout); - pAd->Mlme.AuthMachine.CurrState = AUTH_WAIT_SEQ2; - } - else - { - DBGPRINT_ERR(("AUTH - MlmeAuthReqAction() sanity check failed\n")); - pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; - Status = MLME_INVALID_FORMAT; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status); - } -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID PeerAuthRspAtSeq2Action( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - UCHAR Addr2[MAC_ADDR_LEN]; - USHORT Seq, Status, RemoteStatus, Alg; - UCHAR ChlgText[CIPHER_TEXT_LEN]; - UCHAR CyperChlgText[CIPHER_TEXT_LEN + 8 + 8]; - UCHAR Element[2]; - HEADER_802_11 AuthHdr; - BOOLEAN TimerCancelled; - PUCHAR pOutBuffer = NULL; - NDIS_STATUS NStatus; - ULONG FrameLen = 0; - USHORT Status2; - - if (PeerAuthSanity(pAd, Elem->Msg, Elem->MsgLen, Addr2, &Alg, &Seq, &Status, ChlgText)) - { - if (MAC_ADDR_EQUAL(pAd->MlmeAux.Bssid, Addr2) && Seq == 2) - { - DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Receive AUTH_RSP seq#2 to me (Alg=%d, Status=%d)\n", Alg, Status)); - RTMPCancelTimer(&pAd->MlmeAux.AuthTimer, &TimerCancelled); - - if (Status == MLME_SUCCESS) - { - // Authentication Mode "LEAP" has allow for CCX 1.X - if ((pAd->MlmeAux.Alg == Ndis802_11AuthModeOpen) -#ifdef LEAP_SUPPORT - || (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) -#endif // LEAP_SUPPORT // - ) - { - pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; -#ifdef LEAP_SUPPORT - pAd->Mlme.LeapMachine.CurrState = LEAP_IDLE; -#endif // LEAP_SUPPORT // - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status); - } - else - { - // 2. shared key, need to be challenged - Seq++; - RemoteStatus = MLME_SUCCESS; - - // Get an unused nonpaged memory - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); - if(NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_TRACE, ("AUTH - PeerAuthRspAtSeq2Action() allocate memory fail\n")); - pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; - Status2 = MLME_FAIL_NO_RESOURCE; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status2); - return; - } - - DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Send AUTH request seq#3...\n")); - MgtMacHeaderInit(pAd, &AuthHdr, SUBTYPE_AUTH, 0, Addr2, pAd->MlmeAux.Bssid); - AuthHdr.FC.Wep = 1; - // Encrypt challenge text & auth information - RTMPInitWepEngine( - pAd, - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, - pAd->StaCfg.DefaultKeyId, - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].KeyLen, - CyperChlgText); - - Alg = cpu2le16(*(USHORT *)&Alg); - Seq = cpu2le16(*(USHORT *)&Seq); - RemoteStatus= cpu2le16(*(USHORT *)&RemoteStatus); - - RTMPEncryptData(pAd, (PUCHAR) &Alg, CyperChlgText + 4, 2); - RTMPEncryptData(pAd, (PUCHAR) &Seq, CyperChlgText + 6, 2); - RTMPEncryptData(pAd, (PUCHAR) &RemoteStatus, CyperChlgText + 8, 2); - Element[0] = 16; - Element[1] = 128; - RTMPEncryptData(pAd, Element, CyperChlgText + 10, 2); - RTMPEncryptData(pAd, ChlgText, CyperChlgText + 12, 128); - RTMPSetICV(pAd, CyperChlgText + 140); - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(HEADER_802_11), &AuthHdr, - CIPHER_TEXT_LEN + 16, CyperChlgText, - END_OF_ARGS); - MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); - - RTMPSetTimer(&pAd->MlmeAux.AuthTimer, AUTH_TIMEOUT); - pAd->Mlme.AuthMachine.CurrState = AUTH_WAIT_SEQ4; - } - } - else - { -#ifdef LEAP_SUPPORT - if (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) - { - //Invalid Authentication possible rogue AP - //Add this Ap to Rogue AP. - RogueApTableSetEntry(pAd, &pAd->StaCfg.RogueApTab, Addr2, LEAP_REASON_INVALID_AUTH); - } -#endif // LEAP_SUPPORT // - pAd->StaCfg.AuthFailReason = Status; - COPY_MAC_ADDR(pAd->StaCfg.AuthFailSta, Addr2); - pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status); - } - } - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("AUTH - PeerAuthSanity() sanity check fail\n")); - } -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID PeerAuthRspAtSeq4Action( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - UCHAR Addr2[MAC_ADDR_LEN]; - USHORT Alg, Seq, Status; - CHAR ChlgText[CIPHER_TEXT_LEN]; - BOOLEAN TimerCancelled; - - if(PeerAuthSanity(pAd, Elem->Msg, Elem->MsgLen, Addr2, &Alg, &Seq, &Status, ChlgText)) - { - if(MAC_ADDR_EQUAL(pAd->MlmeAux.Bssid, Addr2) && Seq == 4) - { - DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Receive AUTH_RSP seq#4 to me\n")); - RTMPCancelTimer(&pAd->MlmeAux.AuthTimer, &TimerCancelled); - - if (Status != MLME_SUCCESS) - { - pAd->StaCfg.AuthFailReason = Status; - COPY_MAC_ADDR(pAd->StaCfg.AuthFailSta, Addr2); - } - - pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status); - } - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("AUTH - PeerAuthRspAtSeq4Action() sanity check fail\n")); - } -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID MlmeDeauthReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - MLME_DEAUTH_REQ_STRUCT *pInfo; - HEADER_802_11 DeauthHdr; - PUCHAR pOutBuffer = NULL; - NDIS_STATUS NStatus; - ULONG FrameLen = 0; - USHORT Status; - - pInfo = (MLME_DEAUTH_REQ_STRUCT *)Elem->Msg; - - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory - if (NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_TRACE, ("AUTH - MlmeDeauthReqAction() allocate memory fail\n")); - pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; - Status = MLME_FAIL_NO_RESOURCE; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_DEAUTH_CONF, 2, &Status); - return; - } - - - DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Send DE-AUTH request (Reason=%d)...\n", pInfo->Reason)); - MgtMacHeaderInit(pAd, &DeauthHdr, SUBTYPE_DEAUTH, 0, pInfo->Addr, pAd->MlmeAux.Bssid); - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(HEADER_802_11),&DeauthHdr, - 2, &pInfo->Reason, - END_OF_ARGS); - MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); - - pAd->StaCfg.DeauthReason = pInfo->Reason; - COPY_MAC_ADDR(pAd->StaCfg.DeauthSta, pInfo->Addr); - pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; - Status = MLME_SUCCESS; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_DEAUTH_CONF, 2, &Status); - - // send wireless event - for deauthentication - if (pAd->CommonCfg.bWirelessEvent) - RTMPSendWirelessEvent(pAd, IW_DEAUTH_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID AuthTimeoutAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - USHORT Status; - DBGPRINT(RT_DEBUG_TRACE, ("AUTH - AuthTimeoutAction\n")); - pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; - Status = MLME_REJ_TIMEOUT; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status); -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID InvalidStateWhenAuth( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - USHORT Status; - DBGPRINT(RT_DEBUG_TRACE, ("AUTH - InvalidStateWhenAuth (state=%ld), reset AUTH state machine\n", pAd->Mlme.AuthMachine.CurrState)); - pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; - Status = MLME_STATE_MACHINE_REJECT; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status); -} - -/* - ========================================================================== - Description: - Some STA/AP - Note: - This action should never trigger AUTH state transition, therefore we - separate it from AUTH state machine, and make it as a standalone service - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID Cls2errAction( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pAddr) -{ - HEADER_802_11 DeauthHdr; - PUCHAR pOutBuffer = NULL; - NDIS_STATUS NStatus; - ULONG FrameLen = 0; - USHORT Reason = REASON_CLS2ERR; - - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory - if (NStatus != NDIS_STATUS_SUCCESS) - return; - - DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Class 2 error, Send DEAUTH frame...\n")); - MgtMacHeaderInit(pAd, &DeauthHdr, SUBTYPE_DEAUTH, 0, pAddr, pAd->MlmeAux.Bssid); - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(HEADER_802_11),&DeauthHdr, - 2, &Reason, - END_OF_ARGS); - MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); - - pAd->StaCfg.DeauthReason = Reason; - COPY_MAC_ADDR(pAd->StaCfg.DeauthSta, pAddr); -} - - +#include "../../rt2870/sta/auth.c" diff --git a/drivers/staging/rt3070/sta/auth_rsp.c b/drivers/staging/rt3070/sta/auth_rsp.c index f7aa4b99cf56..c4ea2dc49ad7 100644 --- a/drivers/staging/rt3070/sta/auth_rsp.c +++ b/drivers/staging/rt3070/sta/auth_rsp.c @@ -1,167 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - auth_rsp.c - - Abstract: - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - John 2004-10-1 copy from RT2560 -*/ -#include "../rt_config.h" - -/* - ========================================================================== - Description: - authentication state machine init procedure - Parameters: - Sm - the state machine - - IRQL = PASSIVE_LEVEL - - ========================================================================== - */ -VOID AuthRspStateMachineInit( - IN PRTMP_ADAPTER pAd, - IN PSTATE_MACHINE Sm, - IN STATE_MACHINE_FUNC Trans[]) -{ - StateMachineInit(Sm, Trans, MAX_AUTH_RSP_STATE, MAX_AUTH_RSP_MSG, (STATE_MACHINE_FUNC)Drop, AUTH_RSP_IDLE, AUTH_RSP_MACHINE_BASE); - - // column 1 - StateMachineSetAction(Sm, AUTH_RSP_IDLE, MT2_PEER_DEAUTH, (STATE_MACHINE_FUNC)PeerDeauthAction); - - // column 2 - StateMachineSetAction(Sm, AUTH_RSP_WAIT_CHAL, MT2_PEER_DEAUTH, (STATE_MACHINE_FUNC)PeerDeauthAction); - -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== -*/ -VOID PeerAuthSimpleRspGenAndSend( - IN PRTMP_ADAPTER pAd, - IN PHEADER_802_11 pHdr80211, - IN USHORT Alg, - IN USHORT Seq, - IN USHORT Reason, - IN USHORT Status) -{ - HEADER_802_11 AuthHdr; - ULONG FrameLen = 0; - PUCHAR pOutBuffer = NULL; - NDIS_STATUS NStatus; - - if (Reason != MLME_SUCCESS) - { - DBGPRINT(RT_DEBUG_TRACE, ("Peer AUTH fail...\n")); - return; - } - - //Get an unused nonpaged memory - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); - if (NStatus != NDIS_STATUS_SUCCESS) - return; - - DBGPRINT(RT_DEBUG_TRACE, ("Send AUTH response (seq#2)...\n")); - MgtMacHeaderInit(pAd, &AuthHdr, SUBTYPE_AUTH, 0, pHdr80211->Addr2, pAd->MlmeAux.Bssid); - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(HEADER_802_11), &AuthHdr, - 2, &Alg, - 2, &Seq, - 2, &Reason, - END_OF_ARGS); - MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== -*/ -VOID PeerDeauthAction( - IN PRTMP_ADAPTER pAd, - IN PMLME_QUEUE_ELEM Elem) -{ - UCHAR Addr2[MAC_ADDR_LEN]; - USHORT Reason; - - if (PeerDeauthSanity(pAd, Elem->Msg, Elem->MsgLen, Addr2, &Reason)) - { - if (INFRA_ON(pAd) && MAC_ADDR_EQUAL(Addr2, pAd->CommonCfg.Bssid)) - { - DBGPRINT(RT_DEBUG_TRACE,("AUTH_RSP - receive DE-AUTH from our AP (Reason=%d)\n", Reason)); - - -#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT - { - union iwreq_data wrqu; - memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN); - wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); - } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // - - - // send wireless event - for deauthentication - if (pAd->CommonCfg.bWirelessEvent) - RTMPSendWirelessEvent(pAd, IW_DEAUTH_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); - - LinkDown(pAd, TRUE); - - // Authentication Mode Cisco_LEAP has start a timer - // We should cancel it if using LEAP -#ifdef LEAP_SUPPORT - if (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) - { - RTMPCancelTimer(&pAd->StaCfg.LeapAuthTimer, &TimerCancelled); - //Check is it mach the LEAP Authentication failed as possible a Rogue AP - //on it's PortSecured not equal to WPA_802_1X_PORT_SECURED while process the Authenticaton. - if ((pAd->StaCfg.PortSecured != WPA_802_1X_PORT_SECURED) && (pAd->Mlme.LeapMachine.CurrState != LEAP_IDLE)) - { - RogueApTableSetEntry(pAd, &pAd->StaCfg.RogueApTab, Addr2, LEAP_REASON_AUTH_TIMEOUT); - } - } -#endif // LEAP_SUPPORT // - } - } - else - { - DBGPRINT(RT_DEBUG_TRACE,("AUTH_RSP - PeerDeauthAction() sanity check fail\n")); - } -} - +#include "../../rt2870/sta/auth_rsp.c" diff --git a/drivers/staging/rt3070/sta/connect.c b/drivers/staging/rt3070/sta/connect.c index 152c0bd0f822..d77802caa305 100644 --- a/drivers/staging/rt3070/sta/connect.c +++ b/drivers/staging/rt3070/sta/connect.c @@ -1,2857 +1,2 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - connect.c - - Abstract: - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - John 2004-08-08 Major modification from RT2560 -*/ -#include "../rt_config.h" - -UCHAR CipherSuiteWpaNoneTkip[] = { - 0x00, 0x50, 0xf2, 0x01, // oui - 0x01, 0x00, // Version - 0x00, 0x50, 0xf2, 0x02, // Multicast - 0x01, 0x00, // Number of unicast - 0x00, 0x50, 0xf2, 0x02, // unicast - 0x01, 0x00, // number of authentication method - 0x00, 0x50, 0xf2, 0x00 // authentication - }; -UCHAR CipherSuiteWpaNoneTkipLen = (sizeof(CipherSuiteWpaNoneTkip) / sizeof(UCHAR)); - -UCHAR CipherSuiteWpaNoneAes[] = { - 0x00, 0x50, 0xf2, 0x01, // oui - 0x01, 0x00, // Version - 0x00, 0x50, 0xf2, 0x04, // Multicast - 0x01, 0x00, // Number of unicast - 0x00, 0x50, 0xf2, 0x04, // unicast - 0x01, 0x00, // number of authentication method - 0x00, 0x50, 0xf2, 0x00 // authentication - }; -UCHAR CipherSuiteWpaNoneAesLen = (sizeof(CipherSuiteWpaNoneAes) / sizeof(UCHAR)); - -// The following MACRO is called after 1. starting an new IBSS, 2. succesfully JOIN an IBSS, -// or 3. succesfully ASSOCIATE to a BSS, 4. successfully RE_ASSOCIATE to a BSS -// All settings successfuly negotiated furing MLME state machines become final settings -// and are copied to pAd->StaActive -#define COPY_SETTINGS_FROM_MLME_AUX_TO_ACTIVE_CFG(_pAd) \ -{ \ - (_pAd)->CommonCfg.SsidLen = (_pAd)->MlmeAux.SsidLen; \ - NdisMoveMemory((_pAd)->CommonCfg.Ssid, (_pAd)->MlmeAux.Ssid, (_pAd)->MlmeAux.SsidLen); \ - COPY_MAC_ADDR((_pAd)->CommonCfg.Bssid, (_pAd)->MlmeAux.Bssid); \ - (_pAd)->CommonCfg.Channel = (_pAd)->MlmeAux.Channel; \ - (_pAd)->CommonCfg.CentralChannel = (_pAd)->MlmeAux.CentralChannel; \ - (_pAd)->StaActive.Aid = (_pAd)->MlmeAux.Aid; \ - (_pAd)->StaActive.AtimWin = (_pAd)->MlmeAux.AtimWin; \ - (_pAd)->StaActive.CapabilityInfo = (_pAd)->MlmeAux.CapabilityInfo; \ - (_pAd)->CommonCfg.BeaconPeriod = (_pAd)->MlmeAux.BeaconPeriod; \ - (_pAd)->StaActive.CfpMaxDuration = (_pAd)->MlmeAux.CfpMaxDuration; \ - (_pAd)->StaActive.CfpPeriod = (_pAd)->MlmeAux.CfpPeriod; \ - (_pAd)->StaActive.SupRateLen = (_pAd)->MlmeAux.SupRateLen; \ - NdisMoveMemory((_pAd)->StaActive.SupRate, (_pAd)->MlmeAux.SupRate, (_pAd)->MlmeAux.SupRateLen);\ - (_pAd)->StaActive.ExtRateLen = (_pAd)->MlmeAux.ExtRateLen; \ - NdisMoveMemory((_pAd)->StaActive.ExtRate, (_pAd)->MlmeAux.ExtRate, (_pAd)->MlmeAux.ExtRateLen);\ - NdisMoveMemory(&(_pAd)->CommonCfg.APEdcaParm, &(_pAd)->MlmeAux.APEdcaParm, sizeof(EDCA_PARM));\ - NdisMoveMemory(&(_pAd)->CommonCfg.APQosCapability, &(_pAd)->MlmeAux.APQosCapability, sizeof(QOS_CAPABILITY_PARM));\ - NdisMoveMemory(&(_pAd)->CommonCfg.APQbssLoad, &(_pAd)->MlmeAux.APQbssLoad, sizeof(QBSS_LOAD_PARM));\ - COPY_MAC_ADDR((_pAd)->MacTab.Content[BSSID_WCID].Addr, (_pAd)->MlmeAux.Bssid); \ - (_pAd)->MacTab.Content[BSSID_WCID].Aid = (_pAd)->MlmeAux.Aid; \ - (_pAd)->MacTab.Content[BSSID_WCID].PairwiseKey.CipherAlg = (_pAd)->StaCfg.PairCipher;\ - COPY_MAC_ADDR((_pAd)->MacTab.Content[BSSID_WCID].PairwiseKey.BssId, (_pAd)->MlmeAux.Bssid);\ - (_pAd)->MacTab.Content[BSSID_WCID].RateLen = (_pAd)->StaActive.SupRateLen + (_pAd)->StaActive.ExtRateLen;\ -} - -/* - ========================================================================== - Description: - - IRQL = PASSIVE_LEVEL - - ========================================================================== -*/ -VOID MlmeCntlInit( - IN PRTMP_ADAPTER pAd, - IN STATE_MACHINE *S, - OUT STATE_MACHINE_FUNC Trans[]) -{ - // Control state machine differs from other state machines, the interface - // follows the standard interface - pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== -*/ -VOID MlmeCntlMachinePerformAction( - IN PRTMP_ADAPTER pAd, - IN STATE_MACHINE *S, - IN MLME_QUEUE_ELEM *Elem) -{ - switch(pAd->Mlme.CntlMachine.CurrState) - { - case CNTL_IDLE: - { - CntlIdleProc(pAd, Elem); - } - break; - case CNTL_WAIT_DISASSOC: - CntlWaitDisassocProc(pAd, Elem); - break; - case CNTL_WAIT_JOIN: - CntlWaitJoinProc(pAd, Elem); - break; - - // CNTL_WAIT_REASSOC is the only state in CNTL machine that does - // not triggered directly or indirectly by "RTMPSetInformation(OID_xxx)". - // Therefore not protected by NDIS's "only one outstanding OID request" - // rule. Which means NDIS may SET OID in the middle of ROAMing attempts. - // Current approach is to block new SET request at RTMPSetInformation() - // when CntlMachine.CurrState is not CNTL_IDLE - case CNTL_WAIT_REASSOC: - CntlWaitReassocProc(pAd, Elem); - break; - - case CNTL_WAIT_START: - CntlWaitStartProc(pAd, Elem); - break; - case CNTL_WAIT_AUTH: - CntlWaitAuthProc(pAd, Elem); - break; - case CNTL_WAIT_AUTH2: - CntlWaitAuthProc2(pAd, Elem); - break; - case CNTL_WAIT_ASSOC: - CntlWaitAssocProc(pAd, Elem); - break; - - case CNTL_WAIT_OID_LIST_SCAN: - if(Elem->MsgType == MT2_SCAN_CONF) - { - // Resume TxRing after SCANING complete. We hope the out-of-service time - // won't be too long to let upper layer time-out the waiting frames - RTMPResumeMsduTransmission(pAd); - if (pAd->StaCfg.CCXReqType != MSRN_TYPE_UNUSED) - { - // Cisco scan request is finished, prepare beacon report - MlmeEnqueue(pAd, AIRONET_STATE_MACHINE, MT2_AIRONET_SCAN_DONE, 0, NULL); - } - pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; - - // - // Set LED status to previous status. - // - if (pAd->bLedOnScanning) - { - pAd->bLedOnScanning = FALSE; - RTMPSetLED(pAd, pAd->LedStatus); - } -#ifdef DOT11N_DRAFT3 - // AP sent a 2040Coexistence mgmt frame, then station perform a scan, and then send back the respone. - if (pAd->CommonCfg.BSSCoexist2040.field.InfoReq == 1) - { - Update2040CoexistFrameAndNotify(pAd, BSSID_WCID, TRUE); - } -#endif // DOT11N_DRAFT3 // - } - break; - - case CNTL_WAIT_OID_DISASSOC: - if (Elem->MsgType == MT2_DISASSOC_CONF) - { - LinkDown(pAd, FALSE); - pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; - } - break; -#ifdef RT2870 - // - // This state is for that we want to connect to an AP but - // it didn't find on BSS List table. So we need to scan the air first, - // after that we can try to connect to the desired AP if available. - // - case CNTL_WAIT_SCAN_FOR_CONNECT: - if(Elem->MsgType == MT2_SCAN_CONF) - { - // Resume TxRing after SCANING complete. We hope the out-of-service time - // won't be too long to let upper layer time-out the waiting frames - RTMPResumeMsduTransmission(pAd); -#ifdef CCX_SUPPORT - if (pAd->StaCfg.CCXReqType != MSRN_TYPE_UNUSED) - { - // Cisco scan request is finished, prepare beacon report - MlmeEnqueue(pAd, AIRONET_STATE_MACHINE, MT2_AIRONET_SCAN_DONE, 0, NULL); - } -#endif // CCX_SUPPORT // - pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; - - // - // Check if we can connect to. - // - BssTableSsidSort(pAd, &pAd->MlmeAux.SsidBssTab, pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.AutoReconnectSsidLen); - if (pAd->MlmeAux.SsidBssTab.BssNr > 0) - { - MlmeAutoReconnectLastSSID(pAd); - } - } - break; -#endif // RT2870 // - default: - DBGPRINT_ERR(("!ERROR! CNTL - Illegal message type(=%ld)", Elem->MsgType)); - break; - } -} - - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== -*/ -VOID CntlIdleProc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - MLME_DISASSOC_REQ_STRUCT DisassocReq; - - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF)) - return; - - switch(Elem->MsgType) - { - case OID_802_11_SSID: - CntlOidSsidProc(pAd, Elem); - break; - - case OID_802_11_BSSID: - CntlOidRTBssidProc(pAd,Elem); - break; - - case OID_802_11_BSSID_LIST_SCAN: - CntlOidScanProc(pAd,Elem); - break; - - case OID_802_11_DISASSOCIATE: -#ifdef RALINK_ATE - if(ATE_ON(pAd)) - { - DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now\n")); - break; - } -#endif // RALINK_ATE // - DisassocParmFill(pAd, &DisassocReq, pAd->CommonCfg.Bssid, REASON_DISASSOC_STA_LEAVING); - MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ, sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq); - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_DISASSOC; -#ifdef WPA_SUPPLICANT_SUPPORT - if (pAd->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_ENABLE_WITH_WEB_UI) -#endif // WPA_SUPPLICANT_SUPPORT // - { - // Set the AutoReconnectSsid to prevent it reconnect to old SSID - // Since calling this indicate user don't want to connect to that SSID anymore. - pAd->MlmeAux.AutoReconnectSsidLen= 32; - NdisZeroMemory(pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.AutoReconnectSsidLen); - } - break; - - case MT2_MLME_ROAMING_REQ: - CntlMlmeRoamingProc(pAd, Elem); - break; - - case OID_802_11_MIC_FAILURE_REPORT_FRAME: - WpaMicFailureReportFrame(pAd, Elem); - break; - -#ifdef QOS_DLS_SUPPORT - case RT_OID_802_11_SET_DLS_PARAM: - CntlOidDLSSetupProc(pAd, Elem); - break; -#endif // QOS_DLS_SUPPORT // - - default: - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Illegal message in CntlIdleProc(MsgType=%ld)\n",Elem->MsgType)); - break; - } -} - -VOID CntlOidScanProc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - MLME_SCAN_REQ_STRUCT ScanReq; - ULONG BssIdx = BSS_NOT_FOUND; - BSS_ENTRY CurrBss; - -#ifdef RALINK_ATE -/* Disable scanning when ATE is running. */ - if (ATE_ON(pAd)) - return; -#endif // RALINK_ATE // - - - // record current BSS if network is connected. - // 2003-2-13 do not include current IBSS if this is the only STA in this IBSS. - if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) - { - BssIdx = BssSsidTableSearch(&pAd->ScanTab, pAd->CommonCfg.Bssid, pAd->CommonCfg.Ssid, pAd->CommonCfg.SsidLen, pAd->CommonCfg.Channel); - if (BssIdx != BSS_NOT_FOUND) - { - NdisMoveMemory(&CurrBss, &pAd->ScanTab.BssEntry[BssIdx], sizeof(BSS_ENTRY)); - } - } - - // clean up previous SCAN result, add current BSS back to table if any - BssTableInit(&pAd->ScanTab); - if (BssIdx != BSS_NOT_FOUND) - { - // DDK Note: If the NIC is associated with a particular BSSID and SSID - // that are not contained in the list of BSSIDs generated by this scan, the - // BSSID description of the currently associated BSSID and SSID should be - // appended to the list of BSSIDs in the NIC's database. - // To ensure this, we append this BSS as the first entry in SCAN result - NdisMoveMemory(&pAd->ScanTab.BssEntry[0], &CurrBss, sizeof(BSS_ENTRY)); - pAd->ScanTab.BssNr = 1; - } - - ScanParmFill(pAd, &ScanReq, "", 0, BSS_ANY, SCAN_ACTIVE); - MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, - sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq); - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN; -} - -/* - ========================================================================== - Description: - Before calling this routine, user desired SSID should already been - recorded in CommonCfg.Ssid[] - IRQL = DISPATCH_LEVEL - - ========================================================================== -*/ -VOID CntlOidSsidProc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM * Elem) -{ - PNDIS_802_11_SSID pOidSsid = (NDIS_802_11_SSID *)Elem->Msg; - MLME_DISASSOC_REQ_STRUCT DisassocReq; - ULONG Now; - - // Step 1. record the desired user settings to MlmeAux - NdisZeroMemory(pAd->MlmeAux.Ssid, MAX_LEN_OF_SSID); - NdisMoveMemory(pAd->MlmeAux.Ssid, pOidSsid->Ssid, pOidSsid->SsidLength); - pAd->MlmeAux.SsidLen = (UCHAR)pOidSsid->SsidLength; - NdisZeroMemory(pAd->MlmeAux.Bssid, MAC_ADDR_LEN); - pAd->MlmeAux.BssType = pAd->StaCfg.BssType; - - - // - // Update Reconnect Ssid, that user desired to connect. - // - NdisZeroMemory(pAd->MlmeAux.AutoReconnectSsid, MAX_LEN_OF_SSID); - NdisMoveMemory(pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen); - pAd->MlmeAux.AutoReconnectSsidLen = pAd->MlmeAux.SsidLen; - - // step 2. find all matching BSS in the lastest SCAN result (inBssTab) - // & log them into MlmeAux.SsidBssTab for later-on iteration. Sort by RSSI order - BssTableSsidSort(pAd, &pAd->MlmeAux.SsidBssTab, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen); - - DBGPRINT(RT_DEBUG_TRACE, ("CntlOidSsidProc():CNTL - %d BSS of %d BSS match the desire (%d)SSID - %s\n", - pAd->MlmeAux.SsidBssTab.BssNr, pAd->ScanTab.BssNr, pAd->MlmeAux.SsidLen, pAd->MlmeAux.Ssid)); - NdisGetSystemUpTime(&Now); - - if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) && - (pAd->CommonCfg.SsidLen == pAd->MlmeAux.SsidBssTab.BssEntry[0].SsidLen) && - NdisEqualMemory(pAd->CommonCfg.Ssid, pAd->MlmeAux.SsidBssTab.BssEntry[0].Ssid, pAd->CommonCfg.SsidLen) && - MAC_ADDR_EQUAL(pAd->CommonCfg.Bssid, pAd->MlmeAux.SsidBssTab.BssEntry[0].Bssid)) - { - // Case 1. already connected with an AP who has the desired SSID - // with highest RSSI - - // Add checking Mode "LEAP" for CCX 1.0 - if (((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || - (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) || - (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || - (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) -#ifdef LEAP_SUPPORT - || (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) -#endif // LEAP_SUPPORT // - ) && - (pAd->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED)) - { - // case 1.1 For WPA, WPA-PSK, if the 1x port is not secured, we have to redo - // connection process - DBGPRINT(RT_DEBUG_TRACE, ("CntlOidSsidProc():CNTL - disassociate with current AP...\n")); - DisassocParmFill(pAd, &DisassocReq, pAd->CommonCfg.Bssid, REASON_DISASSOC_STA_LEAVING); - MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ, - sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq); - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_DISASSOC; - } - else if (pAd->bConfigChanged == TRUE) - { - // case 1.2 Important Config has changed, we have to reconnect to the same AP - DBGPRINT(RT_DEBUG_TRACE, ("CntlOidSsidProc():CNTL - disassociate with current AP Because config changed...\n")); - DisassocParmFill(pAd, &DisassocReq, pAd->CommonCfg.Bssid, REASON_DISASSOC_STA_LEAVING); - MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ, - sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq); - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_DISASSOC; - } - else - { - // case 1.3. already connected to the SSID with highest RSSI. - DBGPRINT(RT_DEBUG_TRACE, ("CntlOidSsidProc():CNTL - already with this BSSID. ignore this SET_SSID request\n")); - // - // (HCT 12.1) 1c_wlan_mediaevents required - // media connect events are indicated when associating with the same AP - // - if (INFRA_ON(pAd)) - { - // - // Since MediaState already is NdisMediaStateConnected - // We just indicate the connect event again to meet the WHQL required. - // - pAd->IndicateMediaState = NdisMediaStateConnected; - RTMP_IndicateMediaState(pAd); - pAd->ExtraInfo = GENERAL_LINK_UP; // Update extra information to link is up - } - - pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; -#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT - { - union iwreq_data wrqu; - - memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN); - memcpy(wrqu.ap_addr.sa_data, pAd->MlmeAux.Bssid, MAC_ADDR_LEN); - wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); - - } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // - } - } - else if (INFRA_ON(pAd)) - { - // - // For RT61 - // [88888] OID_802_11_SSID should have returned NDTEST_WEP_AP2(Returned: ) - // RT61 may lost SSID, and not connect to NDTEST_WEP_AP2 and will connect to NDTEST_WEP_AP2 by Autoreconnect - // But media status is connected, so the SSID not report correctly. - // - if (!SSID_EQUAL(pAd->CommonCfg.Ssid, pAd->CommonCfg.SsidLen, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen)) - { - // - // Different SSID means not Roaming case, so we let LinkDown() to Indicate a disconnect event. - // - pAd->MlmeAux.CurrReqIsFromNdis = TRUE; - } - // case 2. active INFRA association existent - // roaming is done within miniport driver, nothing to do with configuration - // utility. so upon a new SET(OID_802_11_SSID) is received, we just - // disassociate with the current associated AP, - // then perform a new association with this new SSID, no matter the - // new/old SSID are the same or not. - DBGPRINT(RT_DEBUG_TRACE, ("CntlOidSsidProc():CNTL - disassociate with current AP...\n")); - DisassocParmFill(pAd, &DisassocReq, pAd->CommonCfg.Bssid, REASON_DISASSOC_STA_LEAVING); - MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ, - sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq); - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_DISASSOC; - } - else - { - if (ADHOC_ON(pAd)) - { - DBGPRINT(RT_DEBUG_TRACE, ("CntlOidSsidProc():CNTL - drop current ADHOC\n")); - LinkDown(pAd, FALSE); - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED); - pAd->IndicateMediaState = NdisMediaStateDisconnected; - RTMP_IndicateMediaState(pAd); - pAd->ExtraInfo = GENERAL_LINK_DOWN; - DBGPRINT(RT_DEBUG_TRACE, ("CntlOidSsidProc():NDIS_STATUS_MEDIA_DISCONNECT Event C!\n")); - } - - if ((pAd->MlmeAux.SsidBssTab.BssNr == 0) && - (pAd->StaCfg.bAutoReconnect == TRUE) && - (pAd->MlmeAux.BssType == BSS_INFRA) && - (MlmeValidateSSID(pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen) == TRUE) - ) - { - MLME_SCAN_REQ_STRUCT ScanReq; - - DBGPRINT(RT_DEBUG_TRACE, ("CntlOidSsidProc():CNTL - No matching BSS, start a new scan\n")); - ScanParmFill(pAd, &ScanReq, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen, BSS_ANY, SCAN_ACTIVE); - MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq); - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN; - // Reset Missed scan number - pAd->StaCfg.LastScanTime = Now; - } - else - { - pAd->MlmeAux.BssIdx = 0; - IterateOnBssTab(pAd); - } - } -} - - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== -*/ -VOID CntlOidRTBssidProc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM * Elem) -{ - ULONG BssIdx; - PUCHAR pOidBssid = (PUCHAR)Elem->Msg; - MLME_DISASSOC_REQ_STRUCT DisassocReq; - MLME_JOIN_REQ_STRUCT JoinReq; - -#ifdef RALINK_ATE -/* No need to perform this routine when ATE is running. */ - if (ATE_ON(pAd)) - return; -#endif // RALINK_ATE // - - // record user desired settings - COPY_MAC_ADDR(pAd->MlmeAux.Bssid, pOidBssid); - pAd->MlmeAux.BssType = pAd->StaCfg.BssType; - - // - // Update Reconnect Ssid, that user desired to connect. - // - NdisZeroMemory(pAd->MlmeAux.AutoReconnectSsid, MAX_LEN_OF_SSID); - pAd->MlmeAux.AutoReconnectSsidLen = pAd->MlmeAux.SsidLen; - NdisMoveMemory(pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen); - - // find the desired BSS in the latest SCAN result table - BssIdx = BssTableSearch(&pAd->ScanTab, pOidBssid, pAd->MlmeAux.Channel); - if (BssIdx == BSS_NOT_FOUND) - { - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - BSSID not found. reply NDIS_STATUS_NOT_ACCEPTED\n")); - pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; - return; - } - - // copy the matched BSS entry from ScanTab to MlmeAux.SsidBssTab. Why? - // Because we need this entry to become the JOIN target in later on SYNC state machine - pAd->MlmeAux.BssIdx = 0; - pAd->MlmeAux.SsidBssTab.BssNr = 1; - NdisMoveMemory(&pAd->MlmeAux.SsidBssTab.BssEntry[0], &pAd->ScanTab.BssEntry[BssIdx], sizeof(BSS_ENTRY)); - - //pAd->MlmeAux.AutoReconnectSsidLen = pAd->ScanTab.BssEntry[BssIdx].SsidLen; - //NdisMoveMemory(pAd->MlmeAux.AutoReconnectSsid, pAd->ScanTab.BssEntry[BssIdx].Ssid, pAd->ScanTab.BssEntry[BssIdx].SsidLen); - - // Add SSID into MlmeAux for site surey joining hidden SSID - //pAd->MlmeAux.SsidLen = pAd->ScanTab.BssEntry[BssIdx].SsidLen; - //NdisMoveMemory(pAd->MlmeAux.Ssid, pAd->ScanTab.BssEntry[BssIdx].Ssid, pAd->MlmeAux.SsidLen); - - // 2002-11-26 skip the following checking. i.e. if user wants to re-connect to same AP - // we just follow normal procedure. The reason of user doing this may because he/she changed - // AP to another channel, but we still received BEACON from it thus don't claim Link Down. - // Since user knows he's changed AP channel, he'll re-connect again. By skipping the following - // checking, we'll disassociate then re-do normal association with this AP at the new channel. - // 2003-1-6 Re-enable this feature based on microsoft requirement which prefer not to re-do - // connection when setting the same BSSID. - if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) && - MAC_ADDR_EQUAL(pAd->CommonCfg.Bssid, pOidBssid)) - { - // already connected to the same BSSID, go back to idle state directly - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - already in this BSSID. ignore this SET_BSSID request\n")); - pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; -#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT - { - union iwreq_data wrqu; - - memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN); - memcpy(wrqu.ap_addr.sa_data, pAd->MlmeAux.Bssid, MAC_ADDR_LEN); - wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); - - } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // - } - else - { - if (INFRA_ON(pAd)) - { - // disassoc from current AP first - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - disassociate with current AP ...\n")); - DisassocParmFill(pAd, &DisassocReq, pAd->CommonCfg.Bssid, REASON_DISASSOC_STA_LEAVING); - MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ, - sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq); - - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_DISASSOC; - } - else - { - if (ADHOC_ON(pAd)) - { - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - drop current ADHOC\n")); - LinkDown(pAd, FALSE); - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED); - pAd->IndicateMediaState = NdisMediaStateDisconnected; - RTMP_IndicateMediaState(pAd); - pAd->ExtraInfo = GENERAL_LINK_DOWN; - DBGPRINT(RT_DEBUG_TRACE, ("NDIS_STATUS_MEDIA_DISCONNECT Event C!\n")); - } - - // Change the wepstatus to original wepstatus - pAd->StaCfg.WepStatus = pAd->StaCfg.OrigWepStatus; - pAd->StaCfg.PairCipher = pAd->StaCfg.OrigWepStatus; - pAd->StaCfg.GroupCipher = pAd->StaCfg.OrigWepStatus; - - // Check cipher suite, AP must have more secured cipher than station setting - // Set the Pairwise and Group cipher to match the intended AP setting - // We can only connect to AP with less secured cipher setting - if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) - { - pAd->StaCfg.GroupCipher = pAd->ScanTab.BssEntry[BssIdx].WPA.GroupCipher; - - if (pAd->StaCfg.WepStatus == pAd->ScanTab.BssEntry[BssIdx].WPA.PairCipher) - pAd->StaCfg.PairCipher = pAd->ScanTab.BssEntry[BssIdx].WPA.PairCipher; - else if (pAd->ScanTab.BssEntry[BssIdx].WPA.PairCipherAux != Ndis802_11WEPDisabled) - pAd->StaCfg.PairCipher = pAd->ScanTab.BssEntry[BssIdx].WPA.PairCipherAux; - else // There is no PairCipher Aux, downgrade our capability to TKIP - pAd->StaCfg.PairCipher = Ndis802_11Encryption2Enabled; - } - else if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)) - { - pAd->StaCfg.GroupCipher = pAd->ScanTab.BssEntry[BssIdx].WPA2.GroupCipher; - - if (pAd->StaCfg.WepStatus == pAd->ScanTab.BssEntry[BssIdx].WPA2.PairCipher) - pAd->StaCfg.PairCipher = pAd->ScanTab.BssEntry[BssIdx].WPA2.PairCipher; - else if (pAd->ScanTab.BssEntry[BssIdx].WPA2.PairCipherAux != Ndis802_11WEPDisabled) - pAd->StaCfg.PairCipher = pAd->ScanTab.BssEntry[BssIdx].WPA2.PairCipherAux; - else // There is no PairCipher Aux, downgrade our capability to TKIP - pAd->StaCfg.PairCipher = Ndis802_11Encryption2Enabled; - - // RSN capability - pAd->StaCfg.RsnCapability = pAd->ScanTab.BssEntry[BssIdx].WPA2.RsnCapability; - } - - // Set Mix cipher flag - pAd->StaCfg.bMixCipher = (pAd->StaCfg.PairCipher == pAd->StaCfg.GroupCipher) ? FALSE : TRUE; - if (pAd->StaCfg.bMixCipher == TRUE) - { - // If mix cipher, re-build RSNIE - RTMPMakeRSNIE(pAd, pAd->StaCfg.AuthMode, pAd->StaCfg.WepStatus, 0); - } - // No active association, join the BSS immediately - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - joining %02x:%02x:%02x:%02x:%02x:%02x ...\n", - pOidBssid[0],pOidBssid[1],pOidBssid[2],pOidBssid[3],pOidBssid[4],pOidBssid[5])); - - JoinParmFill(pAd, &JoinReq, pAd->MlmeAux.BssIdx); - MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_JOIN_REQ, sizeof(MLME_JOIN_REQ_STRUCT), &JoinReq); - - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_JOIN; - } - } -} - -// Roaming is the only external request triggering CNTL state machine -// despite of other "SET OID" operation. All "SET OID" related oerations -// happen in sequence, because no other SET OID will be sent to this device -// until the the previous SET operation is complete (successful o failed). -// So, how do we quarantee this ROAMING request won't corrupt other "SET OID"? -// or been corrupted by other "SET OID"? -// -// IRQL = DISPATCH_LEVEL -VOID CntlMlmeRoamingProc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - // TODO: - // AP in different channel may show lower RSSI than actual value?? - // should we add a weighting factor to compensate it? - DBGPRINT(RT_DEBUG_TRACE,("CNTL - Roaming in MlmeAux.RoamTab...\n")); - - NdisMoveMemory(&pAd->MlmeAux.SsidBssTab, &pAd->MlmeAux.RoamTab, sizeof(pAd->MlmeAux.RoamTab)); - pAd->MlmeAux.SsidBssTab.BssNr = pAd->MlmeAux.RoamTab.BssNr; - - BssTableSortByRssi(&pAd->MlmeAux.SsidBssTab); - pAd->MlmeAux.BssIdx = 0; - IterateOnBssTab(pAd); -} - -#ifdef QOS_DLS_SUPPORT -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== -*/ -VOID CntlOidDLSSetupProc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - PRT_802_11_DLS pDLS = (PRT_802_11_DLS)Elem->Msg; - MLME_DLS_REQ_STRUCT MlmeDlsReq; - INT i; - USHORT reason = REASON_UNSPECIFY; - - DBGPRINT(RT_DEBUG_TRACE,("CNTL - (OID set %02x:%02x:%02x:%02x:%02x:%02x with Valid=%d, Status=%d, TimeOut=%d, CountDownTimer=%d)\n", - pDLS->MacAddr[0], pDLS->MacAddr[1], pDLS->MacAddr[2], pDLS->MacAddr[3], pDLS->MacAddr[4], pDLS->MacAddr[5], - pDLS->Valid, pDLS->Status, pDLS->TimeOut, pDLS->CountDownTimer)); - - if (!pAd->CommonCfg.bDLSCapable) - return; - - // DLS will not be supported when Adhoc mode - if (INFRA_ON(pAd)) - { - for (i = 0; i < MAX_NUM_OF_DLS_ENTRY; i++) - { - if (pDLS->Valid && pAd->StaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) && - (pDLS->TimeOut == pAd->StaCfg.DLSEntry[i].TimeOut) && MAC_ADDR_EQUAL(pDLS->MacAddr, pAd->StaCfg.DLSEntry[i].MacAddr)) - { - // 1. Same setting, just drop it - DBGPRINT(RT_DEBUG_TRACE,("CNTL - setting unchanged\n")); - break; - } - else if (!pDLS->Valid && pAd->StaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) && - MAC_ADDR_EQUAL(pDLS->MacAddr, pAd->StaCfg.DLSEntry[i].MacAddr)) - { - // 2. Disable DLS link case, just tear down DLS link - reason = REASON_QOS_UNWANTED_MECHANISM; - pAd->StaCfg.DLSEntry[i].Valid = FALSE; - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); - MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_TEAR_DOWN, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); - DBGPRINT(RT_DEBUG_TRACE,("CNTL - start tear down procedure\n")); - break; - } - else if ((i < MAX_NUM_OF_DLS_ENTRY) && pDLS->Valid && !pAd->StaCfg.DLSEntry[i].Valid) - { - // 3. Enable case, start DLS setup procedure - NdisMoveMemory(&pAd->StaCfg.DLSEntry[i], pDLS, sizeof(RT_802_11_DLS_UI)); - - //Update countdown timer - pAd->StaCfg.DLSEntry[i].CountDownTimer = pAd->StaCfg.DLSEntry[i].TimeOut; - DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); - MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_REQ, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); - DBGPRINT(RT_DEBUG_TRACE,("CNTL - DLS setup case\n")); - break; - } - else if ((i < MAX_NUM_OF_DLS_ENTRY) && pDLS->Valid && pAd->StaCfg.DLSEntry[i].Valid && - (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) && !MAC_ADDR_EQUAL(pDLS->MacAddr, pAd->StaCfg.DLSEntry[i].MacAddr)) - { - // 4. update mac case, tear down old DLS and setup new DLS - reason = REASON_QOS_UNWANTED_MECHANISM; - pAd->StaCfg.DLSEntry[i].Valid = FALSE; - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); - MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_TEAR_DOWN, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); - NdisMoveMemory(&pAd->StaCfg.DLSEntry[i], pDLS, sizeof(RT_802_11_DLS_UI)); - DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); - MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_REQ, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); - DBGPRINT(RT_DEBUG_TRACE,("CNTL - DLS tear down and restart case\n")); - break; - } - else if (pDLS->Valid && pAd->StaCfg.DLSEntry[i].Valid && - MAC_ADDR_EQUAL(pDLS->MacAddr, pAd->StaCfg.DLSEntry[i].MacAddr) && (pAd->StaCfg.DLSEntry[i].TimeOut != pDLS->TimeOut)) - { - // 5. update timeout case, start DLS setup procedure (no tear down) - pAd->StaCfg.DLSEntry[i].TimeOut = pDLS->TimeOut; - //Update countdown timer - pAd->StaCfg.DLSEntry[i].CountDownTimer = pAd->StaCfg.DLSEntry[i].TimeOut; - DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); - MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_REQ, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); - DBGPRINT(RT_DEBUG_TRACE,("CNTL - DLS update timeout case\n")); - break; - } - else if (pDLS->Valid && pAd->StaCfg.DLSEntry[i].Valid && - (pAd->StaCfg.DLSEntry[i].Status != DLS_FINISH) && MAC_ADDR_EQUAL(pDLS->MacAddr, pAd->StaCfg.DLSEntry[i].MacAddr)) - { - // 6. re-setup case, start DLS setup procedure (no tear down) - DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); - MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_REQ, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); - DBGPRINT(RT_DEBUG_TRACE,("CNTL - DLS retry setup procedure\n")); - break; - } - else - { - DBGPRINT(RT_DEBUG_WARN,("CNTL - DLS not changed in entry - %d - Valid=%d, Status=%d, TimeOut=%d\n", - i, pAd->StaCfg.DLSEntry[i].Valid, pAd->StaCfg.DLSEntry[i].Status, pAd->StaCfg.DLSEntry[i].TimeOut)); - } - } - } -} -#endif // QOS_DLS_SUPPORT // - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== -*/ -VOID CntlWaitDisassocProc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - MLME_START_REQ_STRUCT StartReq; - - if (Elem->MsgType == MT2_DISASSOC_CONF) - { - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Dis-associate successful\n")); - - if (pAd->CommonCfg.bWirelessEvent) - { - RTMPSendWirelessEvent(pAd, IW_DISASSOC_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); - } - - LinkDown(pAd, FALSE); - - // case 1. no matching BSS, and user wants ADHOC, so we just start a new one - if ((pAd->MlmeAux.SsidBssTab.BssNr==0) && (pAd->StaCfg.BssType == BSS_ADHOC)) - { - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - No matching BSS, start a new ADHOC (Ssid=%s)...\n",pAd->MlmeAux.Ssid)); - StartParmFill(pAd, &StartReq, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen); - MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_START_REQ, sizeof(MLME_START_REQ_STRUCT), &StartReq); - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_START; - } - // case 2. try each matched BSS - else - { - pAd->MlmeAux.BssIdx = 0; - - IterateOnBssTab(pAd); - } - } -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== -*/ -VOID CntlWaitJoinProc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - USHORT Reason; - MLME_AUTH_REQ_STRUCT AuthReq; - - if (Elem->MsgType == MT2_JOIN_CONF) - { - NdisMoveMemory(&Reason, Elem->Msg, sizeof(USHORT)); - if (Reason == MLME_SUCCESS) - { - // 1. joined an IBSS, we are pretty much done here - if (pAd->MlmeAux.BssType == BSS_ADHOC) - { - // - // 5G bands rules of Japan: - // Ad hoc must be disabled in W53(ch52,56,60,64) channels. - // - if ( (pAd->CommonCfg.bIEEE80211H == 1) && - RadarChannelCheck(pAd, pAd->CommonCfg.Channel) - ) - { - pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Channel=%d, Join adhoc on W53(52,56,60,64) Channels are not accepted\n", pAd->CommonCfg.Channel)); - return; - } - - LinkUp(pAd, BSS_ADHOC); - pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - join the IBSS = %02x:%02x:%02x:%02x:%02x:%02x ...\n", - pAd->CommonCfg.Bssid[0],pAd->CommonCfg.Bssid[1],pAd->CommonCfg.Bssid[2], - pAd->CommonCfg.Bssid[3],pAd->CommonCfg.Bssid[4],pAd->CommonCfg.Bssid[5])); - - pAd->IndicateMediaState = NdisMediaStateConnected; - pAd->ExtraInfo = GENERAL_LINK_UP; - } - // 2. joined a new INFRA network, start from authentication - else - { -#ifdef LEAP_SUPPORT - // Add AuthMode "LEAP" for CCX 1.X - if (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) - { - AuthParmFill(pAd, &AuthReq, pAd->MlmeAux.Bssid, CISCO_AuthModeLEAP); - } - else -#endif // LEAP_SUPPORT // - { - // either Ndis802_11AuthModeShared or Ndis802_11AuthModeAutoSwitch, try shared key first - if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeShared) || - (pAd->StaCfg.AuthMode == Ndis802_11AuthModeAutoSwitch)) - { - AuthParmFill(pAd, &AuthReq, pAd->MlmeAux.Bssid, Ndis802_11AuthModeShared); - } - else - { - AuthParmFill(pAd, &AuthReq, pAd->MlmeAux.Bssid, Ndis802_11AuthModeOpen); - } - } - MlmeEnqueue(pAd, AUTH_STATE_MACHINE, MT2_MLME_AUTH_REQ, - sizeof(MLME_AUTH_REQ_STRUCT), &AuthReq); - - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_AUTH; - } - } - else - { - // 3. failed, try next BSS - pAd->MlmeAux.BssIdx++; - IterateOnBssTab(pAd); - } - } -} - - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== -*/ -VOID CntlWaitStartProc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - USHORT Result; - - if (Elem->MsgType == MT2_START_CONF) - { - NdisMoveMemory(&Result, Elem->Msg, sizeof(USHORT)); - if (Result == MLME_SUCCESS) - { - // - // 5G bands rules of Japan: - // Ad hoc must be disabled in W53(ch52,56,60,64) channels. - // - if ( (pAd->CommonCfg.bIEEE80211H == 1) && - RadarChannelCheck(pAd, pAd->CommonCfg.Channel) - ) - { - pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Channel=%d, Start adhoc on W53(52,56,60,64) Channels are not accepted\n", pAd->CommonCfg.Channel)); - return; - } -#ifdef DOT11_N_SUPPORT - if (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) - { - N_ChannelCheck(pAd); - SetCommonHT(pAd); - NdisMoveMemory(&pAd->MlmeAux.AddHtInfo, &pAd->CommonCfg.AddHTInfo, sizeof(ADD_HT_INFO_IE)); - RTMPCheckHt(pAd, BSSID_WCID, &pAd->CommonCfg.HtCapability, &pAd->CommonCfg.AddHTInfo); - pAd->StaActive.SupportedPhyInfo.bHtEnable = TRUE; - NdisZeroMemory(&pAd->StaActive.SupportedPhyInfo.MCSSet[0], 16); - NdisMoveMemory(&pAd->StaActive.SupportedPhyInfo.MCSSet[0], &pAd->CommonCfg.HtCapability.MCSSet[0], 16); - COPY_HTSETTINGS_FROM_MLME_AUX_TO_ACTIVE_CFG(pAd); - - if ((pAd->CommonCfg.HtCapability.HtCapInfo.ChannelWidth == BW_40) && - (pAd->CommonCfg.AddHTInfo.AddHtInfo.ExtChanOffset == EXTCHA_ABOVE)) - { - pAd->MlmeAux.CentralChannel = pAd->CommonCfg.Channel + 2; - } - else if ((pAd->CommonCfg.HtCapability.HtCapInfo.ChannelWidth == BW_40) && - (pAd->CommonCfg.AddHTInfo.AddHtInfo.ExtChanOffset == EXTCHA_BELOW)) - { - pAd->MlmeAux.CentralChannel = pAd->CommonCfg.Channel - 2; - } - } - else -#endif // DOT11_N_SUPPORT // - { - pAd->StaActive.SupportedPhyInfo.bHtEnable = FALSE; - } - LinkUp(pAd, BSS_ADHOC); - pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; - // Before send beacon, driver need do radar detection - if ((pAd->CommonCfg.Channel > 14 ) - && (pAd->CommonCfg.bIEEE80211H == 1) - && RadarChannelCheck(pAd, pAd->CommonCfg.Channel)) - { - pAd->CommonCfg.RadarDetect.RDMode = RD_SILENCE_MODE; - pAd->CommonCfg.RadarDetect.RDCount = 0; -#ifdef DFS_SUPPORT - BbpRadarDetectionStart(pAd); -#endif // DFS_SUPPORT // - } - - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - start a new IBSS = %02x:%02x:%02x:%02x:%02x:%02x ...\n", - pAd->CommonCfg.Bssid[0],pAd->CommonCfg.Bssid[1],pAd->CommonCfg.Bssid[2], - pAd->CommonCfg.Bssid[3],pAd->CommonCfg.Bssid[4],pAd->CommonCfg.Bssid[5])); - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Start IBSS fail. BUG!!!!!\n")); - pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; - } - } -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== -*/ -VOID CntlWaitAuthProc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - USHORT Reason; - MLME_ASSOC_REQ_STRUCT AssocReq; - MLME_AUTH_REQ_STRUCT AuthReq; - - if (Elem->MsgType == MT2_AUTH_CONF) - { - NdisMoveMemory(&Reason, Elem->Msg, sizeof(USHORT)); - if (Reason == MLME_SUCCESS) - { - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - AUTH OK\n")); - AssocParmFill(pAd, &AssocReq, pAd->MlmeAux.Bssid, pAd->MlmeAux.CapabilityInfo, - ASSOC_TIMEOUT, pAd->StaCfg.DefaultListenCount); - -#ifdef LEAP_SUPPORT - // - // Cisco Leap CCKM supported Re-association. - // - if (LEAP_CCKM_ON(pAd) && (pAd->StaCfg.CCKMLinkUpFlag == TRUE)) - { - //if CCKM is turn on , that's mean Fast Reauthentication - //Use CCKM Reassociation instead of normal association for Fast Roaming. - MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_REASSOC_REQ, - sizeof(MLME_ASSOC_REQ_STRUCT), &AssocReq); - - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_REASSOC; - } - else -#endif // LEAP_SUPPORT // - { - MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_ASSOC_REQ, - sizeof(MLME_ASSOC_REQ_STRUCT), &AssocReq); - - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_ASSOC; - } - } - else - { - // This fail may because of the AP already keep us in its MAC table without - // ageing-out. The previous authentication attempt must have let it remove us. - // so try Authentication again may help. For D-Link DWL-900AP+ compatibility. - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - AUTH FAIL, try again...\n")); -#ifdef LEAP_SUPPORT - //Add AuthMode "LEAP" for CCX 1.X - if (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) - { - AuthParmFill(pAd, &AuthReq, pAd->MlmeAux.Bssid, CISCO_AuthModeLEAP); - } - else -#endif // LEAP_SUPPORT // - { - if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeShared) || - (pAd->StaCfg.AuthMode == Ndis802_11AuthModeAutoSwitch)) - { - // either Ndis802_11AuthModeShared or Ndis802_11AuthModeAutoSwitch, try shared key first - AuthParmFill(pAd, &AuthReq, pAd->MlmeAux.Bssid, Ndis802_11AuthModeShared); - } - else - { - AuthParmFill(pAd, &AuthReq, pAd->MlmeAux.Bssid, Ndis802_11AuthModeOpen); - } - } - MlmeEnqueue(pAd, AUTH_STATE_MACHINE, MT2_MLME_AUTH_REQ, - sizeof(MLME_AUTH_REQ_STRUCT), &AuthReq); - - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_AUTH2; - } - } -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== -*/ -VOID CntlWaitAuthProc2( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - USHORT Reason; - MLME_ASSOC_REQ_STRUCT AssocReq; - MLME_AUTH_REQ_STRUCT AuthReq; - - if (Elem->MsgType == MT2_AUTH_CONF) - { - NdisMoveMemory(&Reason, Elem->Msg, sizeof(USHORT)); - if (Reason == MLME_SUCCESS) - { - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - AUTH OK\n")); - AssocParmFill(pAd, &AssocReq, pAd->MlmeAux.Bssid, pAd->MlmeAux.CapabilityInfo, - ASSOC_TIMEOUT, pAd->StaCfg.DefaultListenCount); - MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_ASSOC_REQ, - sizeof(MLME_ASSOC_REQ_STRUCT), &AssocReq); - - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_ASSOC; - } - else - { -#ifdef LEAP_SUPPORT - // Process LEAP first, since it use different control variable - // We don't want to affect other poven operation - if (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) - { - // LEAP Auth not success, try next BSS - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - *LEAP* AUTH FAIL, give up; try next BSS\n")); - DBGPRINT(RT_DEBUG_TRACE, ("Total match BSSID [=%d]\n", pAd->MlmeAux.SsidBssTab.BssNr)); - pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; - pAd->MlmeAux.BssIdx++; - IterateOnBssTab(pAd); - } - else -#endif // LEAP_SUPPORT // - if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeAutoSwitch) && - (pAd->MlmeAux.Alg == Ndis802_11AuthModeShared)) - { - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - AUTH FAIL, try OPEN system...\n")); - AuthParmFill(pAd, &AuthReq, pAd->MlmeAux.Bssid, Ndis802_11AuthModeOpen); - MlmeEnqueue(pAd, AUTH_STATE_MACHINE, MT2_MLME_AUTH_REQ, - sizeof(MLME_AUTH_REQ_STRUCT), &AuthReq); - - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_AUTH2; - } - else - { - // not success, try next BSS - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - AUTH FAIL, give up; try next BSS\n")); - pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; //??????? - pAd->MlmeAux.BssIdx++; - IterateOnBssTab(pAd); - } - } - } -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== -*/ -VOID CntlWaitAssocProc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - USHORT Reason; - - if (Elem->MsgType == MT2_ASSOC_CONF) - { - NdisMoveMemory(&Reason, Elem->Msg, sizeof(USHORT)); - if (Reason == MLME_SUCCESS) - { - LinkUp(pAd, BSS_INFRA); - pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Association successful on BSS #%ld\n",pAd->MlmeAux.BssIdx)); - - if (pAd->CommonCfg.bWirelessEvent) - { - RTMPSendWirelessEvent(pAd, IW_ASSOC_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); - } - } - else - { - // not success, try next BSS - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Association fails on BSS #%ld\n",pAd->MlmeAux.BssIdx)); - pAd->MlmeAux.BssIdx++; - IterateOnBssTab(pAd); - } - } -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== -*/ -VOID CntlWaitReassocProc( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - USHORT Result; - - if (Elem->MsgType == MT2_REASSOC_CONF) - { - NdisMoveMemory(&Result, Elem->Msg, sizeof(USHORT)); - if (Result == MLME_SUCCESS) - { - // - // NDIS requires a new Link UP indication but no Link Down for RE-ASSOC - // - LinkUp(pAd, BSS_INFRA); - - // send wireless event - for association - if (pAd->CommonCfg.bWirelessEvent) - RTMPSendWirelessEvent(pAd, IW_ASSOC_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); - - -#ifdef LEAP_SUPPORT - if (LEAP_CCKM_ON(pAd)) - { - STA_PORT_SECURED(pAd); - pAd->StaCfg.WpaState = SS_FINISH; - } -#endif // LEAP_SUPPORT // - pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Re-assocition successful on BSS #%ld\n", pAd->MlmeAux.RoamIdx)); - } - else - { - // reassoc failed, try to pick next BSS in the BSS Table - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Re-assocition fails on BSS #%ld\n", pAd->MlmeAux.RoamIdx)); - pAd->MlmeAux.RoamIdx++; - IterateOnBssTab2(pAd); - } - } -} - - -VOID AdhocTurnOnQos( - IN PRTMP_ADAPTER pAd) -{ -#define AC0_DEF_TXOP 0 -#define AC1_DEF_TXOP 0 -#define AC2_DEF_TXOP 94 -#define AC3_DEF_TXOP 47 - - // Turn on QOs if use HT rate. - if (pAd->CommonCfg.APEdcaParm.bValid == FALSE) - { - pAd->CommonCfg.APEdcaParm.bValid = TRUE; - pAd->CommonCfg.APEdcaParm.Aifsn[0] = 3; - pAd->CommonCfg.APEdcaParm.Aifsn[1] = 7; - pAd->CommonCfg.APEdcaParm.Aifsn[2] = 1; - pAd->CommonCfg.APEdcaParm.Aifsn[3] = 1; - - pAd->CommonCfg.APEdcaParm.Cwmin[0] = 4; - pAd->CommonCfg.APEdcaParm.Cwmin[1] = 4; - pAd->CommonCfg.APEdcaParm.Cwmin[2] = 3; - pAd->CommonCfg.APEdcaParm.Cwmin[3] = 2; - - pAd->CommonCfg.APEdcaParm.Cwmax[0] = 10; - pAd->CommonCfg.APEdcaParm.Cwmax[1] = 6; - pAd->CommonCfg.APEdcaParm.Cwmax[2] = 4; - pAd->CommonCfg.APEdcaParm.Cwmax[3] = 3; - - pAd->CommonCfg.APEdcaParm.Txop[0] = 0; - pAd->CommonCfg.APEdcaParm.Txop[1] = 0; - pAd->CommonCfg.APEdcaParm.Txop[2] = AC2_DEF_TXOP; - pAd->CommonCfg.APEdcaParm.Txop[3] = AC3_DEF_TXOP; - } - AsicSetEdcaParm(pAd, &pAd->CommonCfg.APEdcaParm); -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== -*/ -VOID LinkUp( - IN PRTMP_ADAPTER pAd, - IN UCHAR BssType) -{ - ULONG Now; - UINT32 Data; - BOOLEAN Cancelled; - UCHAR Value = 0, idx; - MAC_TABLE_ENTRY *pEntry = NULL, *pCurrEntry; - - pEntry = &pAd->MacTab.Content[BSSID_WCID]; - - // - // ASSOC - DisassocTimeoutAction - // CNTL - Dis-associate successful - // !!! LINK DOWN !!! - // [88888] OID_802_11_SSID should have returned NDTEST_WEP_AP2(Returned: ) - // - // To prevent DisassocTimeoutAction to call Link down after we link up, - // cancel the DisassocTimer no matter what it start or not. - // - RTMPCancelTimer(&pAd->MlmeAux.DisassocTimer, &Cancelled); - - COPY_SETTINGS_FROM_MLME_AUX_TO_ACTIVE_CFG(pAd); - -#ifdef DOT11_N_SUPPORT - COPY_HTSETTINGS_FROM_MLME_AUX_TO_ACTIVE_CFG(pAd); -#endif // DOT11_N_SUPPORT // - // It's quite difficult to tell if a newly added KEY is WEP or CKIP until a new BSS - // is formed (either ASSOC/RE-ASSOC done or IBSS started. LinkUP should be a safe place - // to examine if cipher algorithm switching is required. - //rt2860b. Don't know why need this - SwitchBetweenWepAndCkip(pAd); - - - if (BssType == BSS_ADHOC) - { - OPSTATUS_SET_FLAG(pAd, fOP_STATUS_ADHOC_ON); - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_INFRA_ON); - -#ifdef DOT11_N_SUPPORT - if ((pAd->CommonCfg.HtCapability.HtCapInfo.ChannelWidth == BW_40) && - (pAd->CommonCfg.AddHTInfo.AddHtInfo.ExtChanOffset == EXTCHA_ABOVE)) - { - pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel + 2; - } - else if ((pAd->CommonCfg.Channel > 2) && - (pAd->CommonCfg.HtCapability.HtCapInfo.ChannelWidth == BW_40) && - (pAd->CommonCfg.AddHTInfo.AddHtInfo.ExtChanOffset == EXTCHA_BELOW)) - { - pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel - 2; - } -#endif // DOT11_N_SUPPORT // - -#ifdef CARRIER_DETECTION_SUPPORT // Roger sync Carrier - // No carrier detection when adhoc - // CarrierDetectionStop(pAd); - pAd->CommonCfg.CarrierDetect.CD_State = CD_NORMAL; -#endif // CARRIER_DETECTION_SUPPORT // - -#ifdef DOT11_N_SUPPORT - if (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) - AdhocTurnOnQos(pAd); -#endif // DOT11_N_SUPPORT // - - DBGPRINT(RT_DEBUG_TRACE, ("!!!Adhoc LINK UP !!! \n" )); - } - else - { - OPSTATUS_SET_FLAG(pAd, fOP_STATUS_INFRA_ON); - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_ADHOC_ON); - - DBGPRINT(RT_DEBUG_TRACE, ("!!!Infra LINK UP !!! \n" )); - } - - // 3*3 - // reset Tx beamforming bit - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &Value); - Value &= (~0x01); - Value |= pAd->CommonCfg.RegTransmitSetting.field.TxBF; - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, Value); - -#ifdef DOT11_N_SUPPORT - // Change to AP channel - if ((pAd->CommonCfg.CentralChannel > pAd->CommonCfg.Channel) && (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40)) - { - // Must using 40MHz. - pAd->CommonCfg.BBPCurrentBW = BW_40; - AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE); - AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel); - - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &Value); - Value &= (~0x18); - Value |= 0x10; - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, Value); - - // RX : control channel at lower - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &Value); - Value &= (~0x20); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, Value); - - RTMP_IO_READ32(pAd, TX_BAND_CFG, &Data); - Data &= 0xfffffffe; - RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Data); - - if (pAd->MACVersion == 0x28600100) - { - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, 0x1A); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, 0x0A); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R73, 0x16); - DBGPRINT(RT_DEBUG_TRACE, ("!!!rt2860C !!! \n" )); - } - - DBGPRINT(RT_DEBUG_TRACE, ("!!!40MHz Lower LINK UP !!! Control Channel at Below. Central = %d \n", pAd->CommonCfg.CentralChannel )); - } - else if ((pAd->CommonCfg.CentralChannel < pAd->CommonCfg.Channel) && (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40)) - { - // Must using 40MHz. - pAd->CommonCfg.BBPCurrentBW = BW_40; - AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE); - AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel); - - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &Value); - Value &= (~0x18); - Value |= 0x10; - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, Value); - - RTMP_IO_READ32(pAd, TX_BAND_CFG, &Data); - Data |= 0x1; - RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Data); - - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &Value); - Value |= (0x20); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, Value); - - if (pAd->MACVersion == 0x28600100) - { - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, 0x1A); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, 0x0A); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R73, 0x16); - DBGPRINT(RT_DEBUG_TRACE, ("!!!rt2860C !!! \n" )); - } - - DBGPRINT(RT_DEBUG_TRACE, ("!!! 40MHz Upper LINK UP !!! Control Channel at UpperCentral = %d \n", pAd->CommonCfg.CentralChannel )); - } - else -#endif // DOT11_N_SUPPORT // - { - pAd->CommonCfg.BBPCurrentBW = BW_20; - pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel; - AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); - AsicLockChannel(pAd, pAd->CommonCfg.Channel); - - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &Value); - Value &= (~0x18); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, Value); - - RTMP_IO_READ32(pAd, TX_BAND_CFG, &Data); - Data &= 0xfffffffe; - RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Data); - - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &Value); - Value &= (~0x20); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, Value); - - if (pAd->MACVersion == 0x28600100) - { - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, 0x16); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, 0x08); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R73, 0x11); - DBGPRINT(RT_DEBUG_TRACE, ("!!!rt2860C !!! \n" )); - } - - DBGPRINT(RT_DEBUG_TRACE, ("!!! 20MHz LINK UP !!! \n" )); - } - - RTMPSetAGCInitValue(pAd, pAd->CommonCfg.BBPCurrentBW); - // - // Save BBP_R66 value, it will be used in RTUSBResumeMsduTransmission - // - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R66, &pAd->BbpTuning.R66CurrentValue); - - DBGPRINT(RT_DEBUG_TRACE, ("!!! LINK UP !!! (BssType=%d, AID=%d, ssid=%s, Channel=%d, CentralChannel = %d)\n", - BssType, pAd->StaActive.Aid, pAd->CommonCfg.Ssid, pAd->CommonCfg.Channel, pAd->CommonCfg.CentralChannel)); - -#ifdef DOT11_N_SUPPORT - DBGPRINT(RT_DEBUG_TRACE, ("!!! LINK UP !!! (Density =%d, )\n", pAd->MacTab.Content[BSSID_WCID].MpduDensity)); -#endif // DOT11_N_SUPPORT // - - AsicSetBssid(pAd, pAd->CommonCfg.Bssid); - - AsicSetSlotTime(pAd, TRUE); - AsicSetEdcaParm(pAd, &pAd->CommonCfg.APEdcaParm); - - // Call this for RTS protectionfor legacy rate, we will always enable RTS threshold, but normally it will not hit - AsicUpdateProtect(pAd, 0, (OFDMSETPROTECT | CCKSETPROTECT), TRUE, FALSE); - -#ifdef DOT11_N_SUPPORT - if ((pAd->StaActive.SupportedPhyInfo.bHtEnable == TRUE)) - { - // Update HT protectionfor based on AP's operating mode. - if (pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent == 1) - { - AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, ALLN_SETPROTECT, FALSE, TRUE); - } - else - AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, ALLN_SETPROTECT, FALSE, FALSE); - } -#endif // DOT11_N_SUPPORT // - - NdisZeroMemory(&pAd->DrsCounters, sizeof(COUNTER_DRS)); - - NdisGetSystemUpTime(&Now); - pAd->StaCfg.LastBeaconRxTime = Now; // last RX timestamp - - if ((pAd->CommonCfg.TxPreamble != Rt802_11PreambleLong) && - CAP_IS_SHORT_PREAMBLE_ON(pAd->StaActive.CapabilityInfo)) - { - MlmeSetTxPreamble(pAd, Rt802_11PreambleShort); - } - - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED); - - if (pAd->CommonCfg.RadarDetect.RDMode == RD_SILENCE_MODE) - { -#ifdef DFS_SUPPORT - RadarDetectionStop(pAd); -#endif // DFS_SUPPORT // - } - pAd->CommonCfg.RadarDetect.RDMode = RD_NORMAL_MODE; - - if (BssType == BSS_ADHOC) - { - MakeIbssBeacon(pAd); - if ((pAd->CommonCfg.Channel > 14) - && (pAd->CommonCfg.bIEEE80211H == 1) - && RadarChannelCheck(pAd, pAd->CommonCfg.Channel)) - { - ; //Do nothing - } - else - { - AsicEnableIbssSync(pAd); - } - - // In ad hoc mode, use MAC table from index 1. - // p.s ASIC use all 0xff as termination of WCID table search.To prevent it's 0xff-ff-ff-ff-ff-ff, Write 0 here. - RTMP_IO_WRITE32(pAd, MAC_WCID_BASE, 0x00); - RTMP_IO_WRITE32(pAd, 0x1808, 0x00); - - // If WEP is enabled, add key material and cipherAlg into Asic - // Fill in Shared Key Table(offset: 0x6c00) and Shared Key Mode(offset: 0x7000) - - if (pAd->StaCfg.WepStatus == Ndis802_11WEPEnabled) - { - PUCHAR Key; - UCHAR CipherAlg; - - for (idx=0; idx < SHARE_KEY_NUM; idx++) - { - CipherAlg = pAd->SharedKey[BSS0][idx].CipherAlg; - Key = pAd->SharedKey[BSS0][idx].Key; - - if (pAd->SharedKey[BSS0][idx].KeyLen > 0) - { - // Set key material and cipherAlg to Asic - AsicAddSharedKeyEntry(pAd, BSS0, idx, CipherAlg, Key, NULL, NULL); - - if (idx == pAd->StaCfg.DefaultKeyId) - { - // Update WCID attribute table and IVEIV table for this group key table - RTMPAddWcidAttributeEntry(pAd, BSS0, idx, CipherAlg, NULL); - } - } - - - } - } - // If WPANone is enabled, add key material and cipherAlg into Asic - // Fill in Shared Key Table(offset: 0x6c00) and Shared Key Mode(offset: 0x7000) - else if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) - { - pAd->StaCfg.DefaultKeyId = 0; // always be zero - - NdisZeroMemory(&pAd->SharedKey[BSS0][0], sizeof(CIPHER_KEY)); - pAd->SharedKey[BSS0][0].KeyLen = LEN_TKIP_EK; - NdisMoveMemory(pAd->SharedKey[BSS0][0].Key, pAd->StaCfg.PMK, LEN_TKIP_EK); - - if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled) - { - NdisMoveMemory(pAd->SharedKey[BSS0][0].RxMic, &pAd->StaCfg.PMK[16], LEN_TKIP_RXMICK); - NdisMoveMemory(pAd->SharedKey[BSS0][0].TxMic, &pAd->StaCfg.PMK[16], LEN_TKIP_TXMICK); - } - - // Decide its ChiperAlg - if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled) - pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_TKIP; - else if (pAd->StaCfg.PairCipher == Ndis802_11Encryption3Enabled) - pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_AES; - else - { - DBGPRINT(RT_DEBUG_TRACE, ("Unknow Cipher (=%d), set Cipher to AES\n", pAd->StaCfg.PairCipher)); - pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_AES; - } - - // Set key material and cipherAlg to Asic - AsicAddSharedKeyEntry(pAd, - BSS0, - 0, - pAd->SharedKey[BSS0][0].CipherAlg, - pAd->SharedKey[BSS0][0].Key, - pAd->SharedKey[BSS0][0].TxMic, - pAd->SharedKey[BSS0][0].RxMic); - - // Update WCID attribute table and IVEIV table for this group key table - RTMPAddWcidAttributeEntry(pAd, BSS0, 0, pAd->SharedKey[BSS0][0].CipherAlg, NULL); - - } - - } - else // BSS_INFRA - { - // Check the new SSID with last SSID - while (Cancelled == TRUE) - { - if (pAd->CommonCfg.LastSsidLen == pAd->CommonCfg.SsidLen) - { - if (RTMPCompareMemory(pAd->CommonCfg.LastSsid, pAd->CommonCfg.Ssid, pAd->CommonCfg.LastSsidLen) == 0) - { - // Link to the old one no linkdown is required. - break; - } - } - // Send link down event before set to link up - pAd->IndicateMediaState = NdisMediaStateDisconnected; - RTMP_IndicateMediaState(pAd); - pAd->ExtraInfo = GENERAL_LINK_DOWN; - DBGPRINT(RT_DEBUG_TRACE, ("NDIS_STATUS_MEDIA_DISCONNECT Event AA!\n")); - break; - } - - // - // On WPA mode, Remove All Keys if not connect to the last BSSID - // Key will be set after 4-way handshake. - // - if ((pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA)) - { - ULONG IV; - - // Remove all WPA keys - RTMPWPARemoveAllKeys(pAd); - pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; - pAd->StaCfg.PrivacyFilter = Ndis802_11PrivFilter8021xWEP; - - // Fixed connection failed with Range Maximizer - 515 AP (Marvell Chip) when security is WPAPSK/TKIP - // If IV related values are too large in GroupMsg2, AP would ignore this message. - IV = 0; - IV |= (pAd->StaCfg.DefaultKeyId << 30); - AsicUpdateWCIDIVEIV(pAd, BSSID_WCID, IV, 0); - } - // NOTE: - // the decision of using "short slot time" or not may change dynamically due to - // new STA association to the AP. so we have to decide that upon parsing BEACON, not here - - // NOTE: - // the decision to use "RTC/CTS" or "CTS-to-self" protection or not may change dynamically - // due to new STA association to the AP. so we have to decide that upon parsing BEACON, not here - - ComposePsPoll(pAd); - ComposeNullFrame(pAd); - - AsicEnableBssSync(pAd); - - // Add BSSID to WCID search table - AsicUpdateRxWCIDTable(pAd, BSSID_WCID, pAd->CommonCfg.Bssid); - - NdisAcquireSpinLock(&pAd->MacTabLock); - // add this BSSID entry into HASH table - { - UCHAR HashIdx; - - //pEntry = &pAd->MacTab.Content[BSSID_WCID]; - HashIdx = MAC_ADDR_HASH_INDEX(pAd->CommonCfg.Bssid); - if (pAd->MacTab.Hash[HashIdx] == NULL) - { - pAd->MacTab.Hash[HashIdx] = pEntry; - } - else - { - pCurrEntry = pAd->MacTab.Hash[HashIdx]; - while (pCurrEntry->pNext != NULL) - pCurrEntry = pCurrEntry->pNext; - pCurrEntry->pNext = pEntry; - } - } - NdisReleaseSpinLock(&pAd->MacTabLock); - - - // If WEP is enabled, add paiewise and shared key -#ifdef WPA_SUPPLICANT_SUPPORT - if (((pAd->StaCfg.WpaSupplicantUP)&& - (pAd->StaCfg.WepStatus == Ndis802_11WEPEnabled)&& - (pAd->StaCfg.PortSecured == WPA_802_1X_PORT_SECURED)) || - ((pAd->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_DISABLE)&& - (pAd->StaCfg.WepStatus == Ndis802_11WEPEnabled))) -#else - if (pAd->StaCfg.WepStatus == Ndis802_11WEPEnabled) -#endif // WPA_SUPPLICANT_SUPPORT // - { - PUCHAR Key; - UCHAR CipherAlg; - - for (idx=0; idx < SHARE_KEY_NUM; idx++) - { - CipherAlg = pAd->SharedKey[BSS0][idx].CipherAlg; - Key = pAd->SharedKey[BSS0][idx].Key; - - if (pAd->SharedKey[BSS0][idx].KeyLen > 0) - { - // Set key material and cipherAlg to Asic - AsicAddSharedKeyEntry(pAd, BSS0, idx, CipherAlg, Key, NULL, NULL); - - if (idx == pAd->StaCfg.DefaultKeyId) - { - // Assign group key info - RTMPAddWcidAttributeEntry(pAd, BSS0, idx, CipherAlg, NULL); - - // Assign pairwise key info - RTMPAddWcidAttributeEntry(pAd, BSS0, idx, CipherAlg, pEntry); - } - } - } - } - - // only INFRASTRUCTURE mode need to indicate connectivity immediately; ADHOC mode - // should wait until at least 2 active nodes in this BSSID. - OPSTATUS_SET_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED); - - // For GUI ++ - if (pAd->StaCfg.AuthMode < Ndis802_11AuthModeWPA) - { - pAd->IndicateMediaState = NdisMediaStateConnected; - pAd->ExtraInfo = GENERAL_LINK_UP; - RTMP_IndicateMediaState(pAd); - } - // -- - - // Add BSSID in my MAC Table. - NdisAcquireSpinLock(&pAd->MacTabLock); - RTMPMoveMemory(pAd->MacTab.Content[BSSID_WCID].Addr, pAd->CommonCfg.Bssid, MAC_ADDR_LEN); - pAd->MacTab.Content[BSSID_WCID].Aid = BSSID_WCID; - pAd->MacTab.Content[BSSID_WCID].pAd = pAd; - pAd->MacTab.Content[BSSID_WCID].ValidAsCLI = TRUE; //Although this is bssid..still set ValidAsCl - pAd->MacTab.Size = 1; // infra mode always set MACtab size =1. - pAd->MacTab.Content[BSSID_WCID].Sst = SST_ASSOC; - pAd->MacTab.Content[BSSID_WCID].AuthState = SST_ASSOC; - pAd->MacTab.Content[BSSID_WCID].AuthMode = pAd->StaCfg.AuthMode; - pAd->MacTab.Content[BSSID_WCID].WepStatus = pAd->StaCfg.WepStatus; - NdisReleaseSpinLock(&pAd->MacTabLock); - - DBGPRINT(RT_DEBUG_TRACE, ("!!! LINK UP !!! ClientStatusFlags=%lx)\n", - pAd->MacTab.Content[BSSID_WCID].ClientStatusFlags)); - - MlmeUpdateTxRates(pAd, TRUE, BSS0); -#ifdef DOT11_N_SUPPORT - MlmeUpdateHtTxRates(pAd, BSS0); - DBGPRINT(RT_DEBUG_TRACE, ("!!! LINK UP !! (StaActive.bHtEnable =%d, )\n", pAd->StaActive.SupportedPhyInfo.bHtEnable)); -#endif // DOT11_N_SUPPORT // - - // - // Report Adjacent AP report. - // -#ifdef LEAP_SUPPORT - CCXAdjacentAPReport(pAd); -#endif // LEAP_SUPPORT // - - if (pAd->CommonCfg.bAggregationCapable) - { - if ((pAd->CommonCfg.bPiggyBackCapable) && (pAd->MlmeAux.APRalinkIe & 0x00000003) == 3) - { - - OPSTATUS_SET_FLAG(pAd, fOP_STATUS_PIGGYBACK_INUSED); - OPSTATUS_SET_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED); - RTMPSetPiggyBack(pAd, TRUE); - DBGPRINT(RT_DEBUG_TRACE, ("Turn on Piggy-Back\n")); - } - else if (pAd->MlmeAux.APRalinkIe & 0x00000001) - { - OPSTATUS_SET_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED); - } - } - - if (pAd->MlmeAux.APRalinkIe != 0x0) - { -#ifdef DOT11_N_SUPPORT - if (CLIENT_STATUS_TEST_FLAG(&pAd->MacTab.Content[BSSID_WCID], fCLIENT_STATUS_RDG_CAPABLE)) - { - AsicEnableRDG(pAd); - } -#endif // DOT11_N_SUPPORT // - OPSTATUS_SET_FLAG(pAd, fCLIENT_STATUS_RALINK_CHIPSET); - CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[BSSID_WCID], fCLIENT_STATUS_RALINK_CHIPSET); - } - else - { - OPSTATUS_CLEAR_FLAG(pAd, fCLIENT_STATUS_RALINK_CHIPSET); - CLIENT_STATUS_CLEAR_FLAG(&pAd->MacTab.Content[BSSID_WCID], fCLIENT_STATUS_RALINK_CHIPSET); - } - } - -#ifdef DOT11_N_SUPPORT - DBGPRINT(RT_DEBUG_TRACE, ("NDIS_STATUS_MEDIA_CONNECT Event B!.BACapability = %x. ClientStatusFlags = %lx\n", pAd->CommonCfg.BACapability.word, pAd->MacTab.Content[BSSID_WCID].ClientStatusFlags)); -#endif // DOT11_N_SUPPORT // - - // Set LED - RTMPSetLED(pAd, LED_LINK_UP); - - pAd->Mlme.PeriodicRound = 0; - pAd->Mlme.OneSecPeriodicRound = 0; - pAd->bConfigChanged = FALSE; // Reset config flag - pAd->ExtraInfo = GENERAL_LINK_UP; // Update extra information to link is up - - // Set asic auto fall back - { - PUCHAR pTable; - UCHAR TableSize = 0; - - MlmeSelectTxRateTable(pAd, &pAd->MacTab.Content[BSSID_WCID], &pTable, &TableSize, &pAd->CommonCfg.TxRateIndex); - AsicUpdateAutoFallBackTable(pAd, pTable); - } - - NdisAcquireSpinLock(&pAd->MacTabLock); - pEntry->HTPhyMode.word = pAd->StaCfg.HTPhyMode.word; - pEntry->MaxHTPhyMode.word = pAd->StaCfg.HTPhyMode.word; - if (pAd->StaCfg.bAutoTxRateSwitch == FALSE) - { - pEntry->bAutoTxRateSwitch = FALSE; -#ifdef DOT11_N_SUPPORT - if (pEntry->HTPhyMode.field.MCS == 32) - pEntry->HTPhyMode.field.ShortGI = GI_800; - - if ((pEntry->HTPhyMode.field.MCS > MCS_7) || (pEntry->HTPhyMode.field.MCS == 32)) - pEntry->HTPhyMode.field.STBC = STBC_NONE; -#endif // DOT11_N_SUPPORT // - // If the legacy mode is set, overwrite the transmit setting of this entry. - if (pEntry->HTPhyMode.field.MODE <= MODE_OFDM) - RTMPUpdateLegacyTxSetting((UCHAR)pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode, pEntry); - } - else - pEntry->bAutoTxRateSwitch = TRUE; - NdisReleaseSpinLock(&pAd->MacTabLock); - - // Let Link Status Page display first initial rate. - pAd->LastTxRate = (USHORT)(pEntry->HTPhyMode.word); - // Select DAC according to HT or Legacy - if (pAd->StaActive.SupportedPhyInfo.MCSSet[0] != 0x00) - { - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R1, &Value); - Value &= (~0x18); - if (pAd->Antenna.field.TxPath == 2) - { - Value |= 0x10; - } - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R1, Value); - } - else - { - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R1, &Value); - Value &= (~0x18); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R1, Value); - } - -#ifdef DOT11_N_SUPPORT - if (pAd->StaActive.SupportedPhyInfo.bHtEnable == FALSE) - { - } - else if (pEntry->MaxRAmpduFactor == 0) - { - // If HT AP doesn't support MaxRAmpduFactor = 1, we need to set max PSDU to 0. - // Because our Init value is 1 at MACRegTable. - RTMP_IO_WRITE32(pAd, MAX_LEN_CFG, 0x0fff); - } -#endif // DOT11_N_SUPPORT // - - // Patch for Marvel AP to gain high throughput - // Need to set as following, - // 1. Set txop in register-EDCA_AC0_CFG as 0x60 - // 2. Set EnTXWriteBackDDONE in register-WPDMA_GLO_CFG as zero - // 3. PBF_MAX_PCNT as 0x1F3FBF9F - // 4. kick per two packets when dequeue - // - // Txop can only be modified when RDG is off, WMM is disable and TxBurst is enable - // - // if 1. Legacy AP WMM on, or 2. 11n AP, AMPDU disable. Force turn off burst no matter what bEnableTxBurst is. -#ifdef DOT11_N_SUPPORT -// if ((!IS_RT30xx(pAd)) && - if (!((pAd->CommonCfg.RxStream == 1)&&(pAd->CommonCfg.TxStream == 1)) && - (((pAd->StaActive.SupportedPhyInfo.bHtEnable == FALSE) && OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED)) - || ((pAd->StaActive.SupportedPhyInfo.bHtEnable == TRUE) && (pAd->CommonCfg.BACapability.field.Policy == BA_NOTUSE)))) - { - RTMP_IO_READ32(pAd, EDCA_AC0_CFG, &Data); - Data &= 0xFFFFFF00; - RTMP_IO_WRITE32(pAd, EDCA_AC0_CFG, Data); - - RTMP_IO_WRITE32(pAd, PBF_MAX_PCNT, 0x1F3F7F9F); - DBGPRINT(RT_DEBUG_TRACE, ("Txburst 1\n")); - } - else -#endif // DOT11_N_SUPPORT // - if (pAd->CommonCfg.bEnableTxBurst) - { - RTMP_IO_READ32(pAd, EDCA_AC0_CFG, &Data); - Data &= 0xFFFFFF00; - Data |= 0x60; - RTMP_IO_WRITE32(pAd, EDCA_AC0_CFG, Data); - pAd->CommonCfg.IOTestParm.bNowAtherosBurstOn = TRUE; - - RTMP_IO_WRITE32(pAd, PBF_MAX_PCNT, 0x1F3FBF9F); - DBGPRINT(RT_DEBUG_TRACE, ("Txburst 2\n")); - } - else - { - RTMP_IO_READ32(pAd, EDCA_AC0_CFG, &Data); - Data &= 0xFFFFFF00; - RTMP_IO_WRITE32(pAd, EDCA_AC0_CFG, Data); - - RTMP_IO_WRITE32(pAd, PBF_MAX_PCNT, 0x1F3F7F9F); - DBGPRINT(RT_DEBUG_TRACE, ("Txburst 3\n")); - } - -#ifdef DOT11_N_SUPPORT - // Re-check to turn on TX burst or not. - if ((pAd->CommonCfg.IOTestParm.bLastAtheros == TRUE) && ((STA_WEP_ON(pAd))||(STA_TKIP_ON(pAd)))) - { - pAd->CommonCfg.IOTestParm.bNextDisableRxBA = TRUE; - if (pAd->CommonCfg.bEnableTxBurst) - { - UINT32 MACValue = 0; - // Force disable TXOP value in this case. The same action in MLMEUpdateProtect too. - // I didn't change PBF_MAX_PCNT setting. - RTMP_IO_READ32(pAd, EDCA_AC0_CFG, &MACValue); - MACValue &= 0xFFFFFF00; - RTMP_IO_WRITE32(pAd, EDCA_AC0_CFG, MACValue); - pAd->CommonCfg.IOTestParm.bNowAtherosBurstOn = FALSE; - } - } - else - { - pAd->CommonCfg.IOTestParm.bNextDisableRxBA = FALSE; - } -#endif // DOT11_N_SUPPORT // - - pAd->CommonCfg.IOTestParm.bLastAtheros = FALSE; - COPY_MAC_ADDR(pAd->CommonCfg.LastBssid, pAd->CommonCfg.Bssid); - DBGPRINT(RT_DEBUG_TRACE, ("!!!pAd->bNextDisableRxBA= %d \n", pAd->CommonCfg.IOTestParm.bNextDisableRxBA)); - // BSSID add in one MAC entry too. Because in Tx, ASIC need to check Cipher and IV/EIV, BAbitmap - // Pther information in MACTab.Content[BSSID_WCID] is not necessary for driver. - // Note: As STA, The MACTab.Content[BSSID_WCID]. PairwiseKey and Shared Key for BSS0 are the same. - - if (pAd->StaCfg.WepStatus <= Ndis802_11WEPDisabled) - { - pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; - pAd->StaCfg.PrivacyFilter = Ndis802_11PrivFilterAcceptAll; - } - - NdisAcquireSpinLock(&pAd->MacTabLock); - pEntry->PortSecured = pAd->StaCfg.PortSecured; - NdisReleaseSpinLock(&pAd->MacTabLock); - - // - // Patch Atheros AP TX will breakdown issue. - // AP Model: DLink DWL-8200AP - // - if (INFRA_ON(pAd) && OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED) && STA_TKIP_ON(pAd)) - { - RTMP_IO_WRITE32(pAd, RX_PARSER_CFG, 0x01); - } - else - { - RTMP_IO_WRITE32(pAd, RX_PARSER_CFG, 0x00); - } - - RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS); - -#ifdef DOT11_N_SUPPORT -#ifdef DOT11N_DRAFT3 - if ((pAd->CommonCfg.BACapability.field.b2040CoexistScanSup) && (pAd->CommonCfg.Channel <= 11)) - { - OPSTATUS_SET_FLAG(pAd, fOP_STATUS_SCAN_2040); - BuildEffectedChannelList(pAd); - } -#endif // DOT11N_DRAFT3 // -#endif // DOT11_N_SUPPORT // -} - -/* - ========================================================================== - - Routine Description: - Disconnect current BSSID - - Arguments: - pAd - Pointer to our adapter - IsReqFromAP - Request from AP - - Return Value: - None - - IRQL = DISPATCH_LEVEL - - Note: - We need more information to know it's this requst from AP. - If yes! we need to do extra handling, for example, remove the WPA key. - Otherwise on 4-way handshaking will faied, since the WPA key didn't be - remove while auto reconnect. - Disconnect request from AP, it means we will start afresh 4-way handshaking - on WPA mode. - - ========================================================================== -*/ -VOID LinkDown( - IN PRTMP_ADAPTER pAd, - IN BOOLEAN IsReqFromAP) -{ - UCHAR i, ByteValue = 0; - - // Do nothing if monitor mode is on - if (MONITOR_ON(pAd)) - return; - -#ifdef RALINK_ATE - // Nothing to do in ATE mode. - if (ATE_ON(pAd)) - return; -#endif // RALINK_ATE // - - if (pAd->CommonCfg.bWirelessEvent) - { - RTMPSendWirelessEvent(pAd, IW_STA_LINKDOWN_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); - } - - DBGPRINT(RT_DEBUG_TRACE, ("!!! LINK DOWN !!!\n")); - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED); - - if (ADHOC_ON(pAd)) // Adhoc mode link down - { - DBGPRINT(RT_DEBUG_TRACE, ("!!! LINK DOWN 1!!!\n")); - - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_ADHOC_ON); - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED); - pAd->IndicateMediaState = NdisMediaStateDisconnected; - RTMP_IndicateMediaState(pAd); - pAd->ExtraInfo = GENERAL_LINK_DOWN; - BssTableDeleteEntry(&pAd->ScanTab, pAd->CommonCfg.Bssid, pAd->CommonCfg.Channel); - DBGPRINT(RT_DEBUG_TRACE, ("!!! MacTab.Size=%d !!!\n", pAd->MacTab.Size)); - } - else // Infra structure mode - { - DBGPRINT(RT_DEBUG_TRACE, ("!!! LINK DOWN 2!!!\n")); - -#ifdef QOS_DLS_SUPPORT - // DLS tear down frame must be sent before link down - // send DLS-TEAR_DOWN message - if (pAd->CommonCfg.bDLSCapable) - { - // tear down local dls table entry - for (i=0; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH)) - { - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - RTMPSendDLSTearDownFrame(pAd, pAd->StaCfg.DLSEntry[i].MacAddr); - } - } - - // tear down peer dls table entry - for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH)) - { - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - RTMPSendDLSTearDownFrame(pAd, pAd->StaCfg.DLSEntry[i].MacAddr); - } - } - } -#endif // QOS_DLS_SUPPORT // - - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_INFRA_ON); - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED); - - // Saved last SSID for linkup comparison - pAd->CommonCfg.LastSsidLen = pAd->CommonCfg.SsidLen; - NdisMoveMemory(pAd->CommonCfg.LastSsid, pAd->CommonCfg.Ssid, pAd->CommonCfg.LastSsidLen); - COPY_MAC_ADDR(pAd->CommonCfg.LastBssid, pAd->CommonCfg.Bssid); - if (pAd->MlmeAux.CurrReqIsFromNdis == TRUE) - { - pAd->IndicateMediaState = NdisMediaStateDisconnected; - RTMP_IndicateMediaState(pAd); - pAd->ExtraInfo = GENERAL_LINK_DOWN; - DBGPRINT(RT_DEBUG_TRACE, ("NDIS_STATUS_MEDIA_DISCONNECT Event A!\n")); - pAd->MlmeAux.CurrReqIsFromNdis = FALSE; - } - else - { - // - // If disassociation request is from NDIS, then we don't need to delete BSSID from entry. - // Otherwise lost beacon or receive De-Authentication from AP, - // then we should delete BSSID from BssTable. - // If we don't delete from entry, roaming will fail. - // - BssTableDeleteEntry(&pAd->ScanTab, pAd->CommonCfg.Bssid, pAd->CommonCfg.Channel); - } - - // restore back to - - // 1. long slot (20 us) or short slot (9 us) time - // 2. turn on/off RTS/CTS and/or CTS-to-self protection - // 3. short preamble - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_BG_PROTECTION_INUSED); - - if (pAd->StaCfg.CCXAdjacentAPReportFlag == TRUE) - { - // - // Record current AP's information. - // for later used reporting Adjacent AP report. - // - pAd->StaCfg.CCXAdjacentAPChannel = pAd->CommonCfg.Channel; - pAd->StaCfg.CCXAdjacentAPSsidLen = pAd->CommonCfg.SsidLen; - NdisMoveMemory(pAd->StaCfg.CCXAdjacentAPSsid, pAd->CommonCfg.Ssid, pAd->StaCfg.CCXAdjacentAPSsidLen); - COPY_MAC_ADDR(pAd->StaCfg.CCXAdjacentAPBssid, pAd->CommonCfg.Bssid); - } - -#ifdef EXT_BUILD_CHANNEL_LIST - // Country IE of the AP will be evaluated and will be used. - if (pAd->StaCfg.IEEE80211dClientMode != Rt802_11_D_None) - { - NdisMoveMemory(&pAd->CommonCfg.CountryCode[0], &pAd->StaCfg.StaOriCountryCode[0], 2); - pAd->CommonCfg.Geography = pAd->StaCfg.StaOriGeography; - BuildChannelListEx(pAd); - } -#endif // EXT_BUILD_CHANNEL_LIST // - - } - - for (i=1; iMacTab.Content[i].ValidAsCLI == TRUE) - MacTableDeleteEntry(pAd, pAd->MacTab.Content[i].Aid, pAd->MacTab.Content[i].Addr); - } - - pAd->StaCfg.CCXQosECWMin = 4; - pAd->StaCfg.CCXQosECWMax = 10; - - AsicSetSlotTime(pAd, TRUE); //FALSE); - AsicSetEdcaParm(pAd, NULL); - - // Set LED - RTMPSetLED(pAd, LED_LINK_DOWN); - pAd->LedIndicatorStregth = 0xF0; - RTMPSetSignalLED(pAd, -100); // Force signal strength Led to be turned off, firmware is not done it. - - AsicDisableSync(pAd); - - pAd->Mlme.PeriodicRound = 0; - pAd->Mlme.OneSecPeriodicRound = 0; - - if (pAd->StaCfg.BssType == BSS_INFRA) - { - // Remove StaCfg Information after link down - NdisZeroMemory(pAd->CommonCfg.Bssid, MAC_ADDR_LEN); - NdisZeroMemory(pAd->CommonCfg.Ssid, MAX_LEN_OF_SSID); - pAd->CommonCfg.SsidLen = 0; - } -#ifdef DOT11_N_SUPPORT - NdisZeroMemory(&pAd->MlmeAux.HtCapability, sizeof(HT_CAPABILITY_IE)); - NdisZeroMemory(&pAd->MlmeAux.AddHtInfo, sizeof(ADD_HT_INFO_IE)); - pAd->MlmeAux.HtCapabilityLen = 0; - pAd->MlmeAux.NewExtChannelOffset = 0xff; -#endif // DOT11_N_SUPPORT // - - // Reset WPA-PSK state. Only reset when supplicant enabled - if (pAd->StaCfg.WpaState != SS_NOTUSE) - { - pAd->StaCfg.WpaState = SS_START; - // Clear Replay counter - NdisZeroMemory(pAd->StaCfg.ReplayCounter, 8); - -#ifdef QOS_DLS_SUPPORT - if (pAd->CommonCfg.bDLSCapable) - NdisZeroMemory(pAd->StaCfg.DlsReplayCounter, 8); -#endif // QOS_DLS_SUPPORT // - } - - - // - // if link down come from AP, we need to remove all WPA keys on WPA mode. - // otherwise will cause 4-way handshaking failed, since the WPA key not empty. - // - if ((IsReqFromAP) && (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA)) - { - // Remove all WPA keys - RTMPWPARemoveAllKeys(pAd); - } - - // 802.1x port control -#ifdef WPA_SUPPLICANT_SUPPORT - // Prevent clear PortSecured here with static WEP - // NetworkManger set security policy first then set SSID to connect AP. - if (pAd->StaCfg.WpaSupplicantUP && - (pAd->StaCfg.WepStatus == Ndis802_11WEPEnabled) && - (pAd->StaCfg.IEEE8021X == FALSE)) - { - pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; - } - else -#endif // WPA_SUPPLICANT_SUPPORT // - { - pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; - pAd->StaCfg.PrivacyFilter = Ndis802_11PrivFilter8021xWEP; - } - - NdisAcquireSpinLock(&pAd->MacTabLock); - pAd->MacTab.Content[BSSID_WCID].PortSecured = pAd->StaCfg.PortSecured; - NdisReleaseSpinLock(&pAd->MacTabLock); - - pAd->StaCfg.MicErrCnt = 0; - - // Turn off Ckip control flag - pAd->StaCfg.bCkipOn = FALSE; - pAd->StaCfg.CCXEnable = FALSE; - - pAd->IndicateMediaState = NdisMediaStateDisconnected; - // Update extra information to link is up - pAd->ExtraInfo = GENERAL_LINK_DOWN; - - //pAd->StaCfg.AdhocBOnlyJoined = FALSE; - //pAd->StaCfg.AdhocBGJoined = FALSE; - //pAd->StaCfg.Adhoc20NJoined = FALSE; - pAd->StaActive.SupportedPhyInfo.bHtEnable = FALSE; - - // Reset the Current AP's IP address - NdisZeroMemory(pAd->StaCfg.AironetIPAddress, 4); -#ifdef RT2870 - pAd->bUsbTxBulkAggre = FALSE; -#endif // RT2870 // - - // Clean association information - NdisZeroMemory(&pAd->StaCfg.AssocInfo, sizeof(NDIS_802_11_ASSOCIATION_INFORMATION)); - pAd->StaCfg.AssocInfo.Length = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION); - pAd->StaCfg.ReqVarIELen = 0; - pAd->StaCfg.ResVarIELen = 0; - - // - // Reset RSSI value after link down - // - pAd->StaCfg.RssiSample.AvgRssi0 = 0; - pAd->StaCfg.RssiSample.AvgRssi0X8 = 0; - pAd->StaCfg.RssiSample.AvgRssi1 = 0; - pAd->StaCfg.RssiSample.AvgRssi1X8 = 0; - pAd->StaCfg.RssiSample.AvgRssi2 = 0; - pAd->StaCfg.RssiSample.AvgRssi2X8 = 0; - - // Restore MlmeRate - pAd->CommonCfg.MlmeRate = pAd->CommonCfg.BasicMlmeRate; - pAd->CommonCfg.RtsRate = pAd->CommonCfg.BasicMlmeRate; - -#ifdef DOT11_N_SUPPORT - // - // After Link down, reset piggy-back setting in ASIC. Disable RDG. - // - if (pAd->CommonCfg.BBPCurrentBW == BW_40) - { - pAd->CommonCfg.BBPCurrentBW = BW_20; - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &ByteValue); - ByteValue &= (~0x18); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, ByteValue); - } -#endif // DOT11_N_SUPPORT // - // Reset DAC - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R1, &ByteValue); - ByteValue &= (~0x18); - if (pAd->Antenna.field.TxPath == 2) - { - ByteValue |= 0x10; - } - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R1, ByteValue); - - RTMPSetPiggyBack(pAd,FALSE); - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_PIGGYBACK_INUSED); - -#ifdef DOT11_N_SUPPORT - pAd->CommonCfg.BACapability.word = pAd->CommonCfg.REGBACapability.word; -#endif // DOT11_N_SUPPORT // - - // Restore all settings in the following. - AsicUpdateProtect(pAd, 0, (ALLN_SETPROTECT|CCKSETPROTECT|OFDMSETPROTECT), TRUE, FALSE); - AsicDisableRDG(pAd); - pAd->CommonCfg.IOTestParm.bCurrentAtheros = FALSE; - pAd->CommonCfg.IOTestParm.bNowAtherosBurstOn = FALSE; - -#ifdef DOT11_N_SUPPORT -#ifdef DOT11N_DRAFT3 - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SCAN_2040); - pAd->CommonCfg.BSSCoexist2040.word = 0; - TriEventInit(pAd); - for (i = 0; i < (pAd->ChannelListNum - 1); i++) - { - pAd->ChannelList[i].bEffectedChannel = FALSE; - } -#endif // DOT11N_DRAFT3 // -#endif // DOT11_N_SUPPORT // - - RTMP_IO_WRITE32(pAd, MAX_LEN_CFG, 0x1fff); - RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS); - -#ifdef WPA_SUPPLICANT_SUPPORT -#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT - if (pAd->StaCfg.WpaSupplicantUP) { - union iwreq_data wrqu; - //send disassociate event to wpa_supplicant - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.flags = RT_DISASSOC_EVENT_FLAG; - wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); - } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // -#endif // WPA_SUPPLICANT_SUPPORT // - -#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT - { - union iwreq_data wrqu; - memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN); - wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); - } -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // - -#ifdef RT30xx - if (IS_RT3090(pAd)) - { - UINT32 macdata; - // disable MMPS BBP control register - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &ByteValue); - ByteValue &= ~(0x04); //bit 2 - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, ByteValue); - - // disable MMPS MAC control register - RTMP_IO_READ32(pAd, 0x1210, &macdata); - macdata &= ~(0x09); //bit 0, 3 - RTMP_IO_WRITE32(pAd, 0x1210, macdata); - } -#endif // RT30xx // - -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== -*/ -VOID IterateOnBssTab( - IN PRTMP_ADAPTER pAd) -{ - MLME_START_REQ_STRUCT StartReq; - MLME_JOIN_REQ_STRUCT JoinReq; - ULONG BssIdx; - - // Change the wepstatus to original wepstatus - pAd->StaCfg.WepStatus = pAd->StaCfg.OrigWepStatus; - pAd->StaCfg.PairCipher = pAd->StaCfg.OrigWepStatus; - pAd->StaCfg.GroupCipher = pAd->StaCfg.OrigWepStatus; - - BssIdx = pAd->MlmeAux.BssIdx; - if (BssIdx < pAd->MlmeAux.SsidBssTab.BssNr) - { - // Check cipher suite, AP must have more secured cipher than station setting - // Set the Pairwise and Group cipher to match the intended AP setting - // We can only connect to AP with less secured cipher setting - if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) - { - pAd->StaCfg.GroupCipher = pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA.GroupCipher; - - if (pAd->StaCfg.WepStatus == pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA.PairCipher) - pAd->StaCfg.PairCipher = pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA.PairCipher; - else if (pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA.PairCipherAux != Ndis802_11WEPDisabled) - pAd->StaCfg.PairCipher = pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA.PairCipherAux; - else // There is no PairCipher Aux, downgrade our capability to TKIP - pAd->StaCfg.PairCipher = Ndis802_11Encryption2Enabled; - } - else if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)) - { - pAd->StaCfg.GroupCipher = pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA2.GroupCipher; - - if (pAd->StaCfg.WepStatus == pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA2.PairCipher) - pAd->StaCfg.PairCipher = pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA2.PairCipher; - else if (pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA2.PairCipherAux != Ndis802_11WEPDisabled) - pAd->StaCfg.PairCipher = pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA2.PairCipherAux; - else // There is no PairCipher Aux, downgrade our capability to TKIP - pAd->StaCfg.PairCipher = Ndis802_11Encryption2Enabled; - - // RSN capability - pAd->StaCfg.RsnCapability = pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA2.RsnCapability; - } - - // Set Mix cipher flag - pAd->StaCfg.bMixCipher = (pAd->StaCfg.PairCipher == pAd->StaCfg.GroupCipher) ? FALSE : TRUE; - if (pAd->StaCfg.bMixCipher == TRUE) - { - // If mix cipher, re-build RSNIE - RTMPMakeRSNIE(pAd, pAd->StaCfg.AuthMode, pAd->StaCfg.WepStatus, 0); - } - - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - iterate BSS %ld of %d\n", BssIdx, pAd->MlmeAux.SsidBssTab.BssNr)); - JoinParmFill(pAd, &JoinReq, BssIdx); - MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_JOIN_REQ, sizeof(MLME_JOIN_REQ_STRUCT), - &JoinReq); - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_JOIN; - } - else if (pAd->StaCfg.BssType == BSS_ADHOC) - { - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - All BSS fail; start a new ADHOC (Ssid=%s)...\n",pAd->MlmeAux.Ssid)); - StartParmFill(pAd, &StartReq, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen); - MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_START_REQ, sizeof(MLME_START_REQ_STRUCT), &StartReq); - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_START; - } - else // no more BSS - { - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - All roaming failed, stay @ ch #%d\n", pAd->CommonCfg.Channel)); - AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); - AsicLockChannel(pAd, pAd->CommonCfg.Channel); - pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; - } -} - -// for re-association only -// IRQL = DISPATCH_LEVEL -VOID IterateOnBssTab2( - IN PRTMP_ADAPTER pAd) -{ - MLME_REASSOC_REQ_STRUCT ReassocReq; - ULONG BssIdx; - BSS_ENTRY *pBss; - - BssIdx = pAd->MlmeAux.RoamIdx; - pBss = &pAd->MlmeAux.RoamTab.BssEntry[BssIdx]; - - if (BssIdx < pAd->MlmeAux.RoamTab.BssNr) - { - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - iterate BSS %ld of %d\n", BssIdx, pAd->MlmeAux.RoamTab.BssNr)); - - AsicSwitchChannel(pAd, pBss->Channel, FALSE); - AsicLockChannel(pAd, pBss->Channel); - - // reassociate message has the same structure as associate message - AssocParmFill(pAd, &ReassocReq, pBss->Bssid, pBss->CapabilityInfo, - ASSOC_TIMEOUT, pAd->StaCfg.DefaultListenCount); - MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_REASSOC_REQ, - sizeof(MLME_REASSOC_REQ_STRUCT), &ReassocReq); - - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_REASSOC; - } - else // no more BSS - { - DBGPRINT(RT_DEBUG_TRACE, ("CNTL - All fast roaming failed, back to ch #%d\n",pAd->CommonCfg.Channel)); - AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); - AsicLockChannel(pAd, pAd->CommonCfg.Channel); - pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; - } -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== -*/ -VOID JoinParmFill( - IN PRTMP_ADAPTER pAd, - IN OUT MLME_JOIN_REQ_STRUCT *JoinReq, - IN ULONG BssIdx) -{ - JoinReq->BssIdx = BssIdx; -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== -*/ -VOID ScanParmFill( - IN PRTMP_ADAPTER pAd, - IN OUT MLME_SCAN_REQ_STRUCT *ScanReq, - IN CHAR Ssid[], - IN UCHAR SsidLen, - IN UCHAR BssType, - IN UCHAR ScanType) -{ - NdisZeroMemory(ScanReq->Ssid, MAX_LEN_OF_SSID); - ScanReq->SsidLen = SsidLen; - NdisMoveMemory(ScanReq->Ssid, Ssid, SsidLen); - ScanReq->BssType = BssType; - ScanReq->ScanType = ScanType; -} - -#ifdef QOS_DLS_SUPPORT -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== -*/ -VOID DlsParmFill( - IN PRTMP_ADAPTER pAd, - IN OUT MLME_DLS_REQ_STRUCT *pDlsReq, - IN PRT_802_11_DLS pDls, - IN USHORT reason) -{ - pDlsReq->pDLS = pDls; - pDlsReq->Reason = reason; -} -#endif // QOS_DLS_SUPPORT // - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== -*/ -VOID StartParmFill( - IN PRTMP_ADAPTER pAd, - IN OUT MLME_START_REQ_STRUCT *StartReq, - IN CHAR Ssid[], - IN UCHAR SsidLen) -{ - ASSERT(SsidLen <= MAX_LEN_OF_SSID); - NdisMoveMemory(StartReq->Ssid, Ssid, SsidLen); - StartReq->SsidLen = SsidLen; -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== -*/ -VOID AuthParmFill( - IN PRTMP_ADAPTER pAd, - IN OUT MLME_AUTH_REQ_STRUCT *AuthReq, - IN PUCHAR pAddr, - IN USHORT Alg) -{ - COPY_MAC_ADDR(AuthReq->Addr, pAddr); - AuthReq->Alg = Alg; - AuthReq->Timeout = AUTH_TIMEOUT; -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ - - -#ifdef RT2870 - -VOID MlmeCntlConfirm( - IN PRTMP_ADAPTER pAd, - IN ULONG MsgType, - IN USHORT Msg) -{ - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MsgType, sizeof(USHORT), &Msg); -} - -VOID ComposePsPoll( - IN PRTMP_ADAPTER pAd) -{ - PTXINFO_STRUC pTxInfo; - PTXWI_STRUC pTxWI; - - DBGPRINT(RT_DEBUG_TRACE, ("ComposePsPoll\n")); - NdisZeroMemory(&pAd->PsPollFrame, sizeof(PSPOLL_FRAME)); - - pAd->PsPollFrame.FC.PwrMgmt = 0; - pAd->PsPollFrame.FC.Type = BTYPE_CNTL; - pAd->PsPollFrame.FC.SubType = SUBTYPE_PS_POLL; - pAd->PsPollFrame.Aid = pAd->StaActive.Aid | 0xC000; - COPY_MAC_ADDR(pAd->PsPollFrame.Bssid, pAd->CommonCfg.Bssid); - COPY_MAC_ADDR(pAd->PsPollFrame.Ta, pAd->CurrentAddress); - - RTMPZeroMemory(&pAd->PsPollContext.TransferBuffer->field.WirelessPacket[0], 100); - pTxInfo = (PTXINFO_STRUC)&pAd->PsPollContext.TransferBuffer->field.WirelessPacket[0]; - RTMPWriteTxInfo(pAd, pTxInfo, (USHORT)(sizeof(PSPOLL_FRAME)+TXWI_SIZE), TRUE, EpToQueue[MGMTPIPEIDX], FALSE, FALSE); - pTxWI = (PTXWI_STRUC)&pAd->PsPollContext.TransferBuffer->field.WirelessPacket[TXINFO_SIZE]; - RTMPWriteTxWI(pAd, pTxWI, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, 0, BSSID_WCID, (sizeof(PSPOLL_FRAME)), - 0, 0, (UCHAR)pAd->CommonCfg.MlmeTransmit.field.MCS, IFS_BACKOFF, FALSE, &pAd->CommonCfg.MlmeTransmit); - RTMPMoveMemory(&pAd->PsPollContext.TransferBuffer->field.WirelessPacket[TXWI_SIZE+TXINFO_SIZE], &pAd->PsPollFrame, sizeof(PSPOLL_FRAME)); - // Append 4 extra zero bytes. - pAd->PsPollContext.BulkOutSize = TXINFO_SIZE + TXWI_SIZE + sizeof(PSPOLL_FRAME) + 4; -} - -// IRQL = DISPATCH_LEVEL -VOID ComposeNullFrame( - IN PRTMP_ADAPTER pAd) -{ - PTXINFO_STRUC pTxInfo; - PTXWI_STRUC pTxWI; - - NdisZeroMemory(&pAd->NullFrame, sizeof(HEADER_802_11)); - pAd->NullFrame.FC.Type = BTYPE_DATA; - pAd->NullFrame.FC.SubType = SUBTYPE_NULL_FUNC; - pAd->NullFrame.FC.ToDs = 1; - COPY_MAC_ADDR(pAd->NullFrame.Addr1, pAd->CommonCfg.Bssid); - COPY_MAC_ADDR(pAd->NullFrame.Addr2, pAd->CurrentAddress); - COPY_MAC_ADDR(pAd->NullFrame.Addr3, pAd->CommonCfg.Bssid); - RTMPZeroMemory(&pAd->NullContext.TransferBuffer->field.WirelessPacket[0], 100); - pTxInfo = (PTXINFO_STRUC)&pAd->NullContext.TransferBuffer->field.WirelessPacket[0]; - RTMPWriteTxInfo(pAd, pTxInfo, (USHORT)(sizeof(HEADER_802_11)+TXWI_SIZE), TRUE, EpToQueue[MGMTPIPEIDX], FALSE, FALSE); - pTxWI = (PTXWI_STRUC)&pAd->NullContext.TransferBuffer->field.WirelessPacket[TXINFO_SIZE]; - RTMPWriteTxWI(pAd, pTxWI, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, 0, BSSID_WCID, (sizeof(HEADER_802_11)), - 0, 0, (UCHAR)pAd->CommonCfg.MlmeTransmit.field.MCS, IFS_BACKOFF, FALSE, &pAd->CommonCfg.MlmeTransmit); - RTMPMoveMemory(&pAd->NullContext.TransferBuffer->field.WirelessPacket[TXWI_SIZE+TXINFO_SIZE], &pAd->NullFrame, sizeof(HEADER_802_11)); - pAd->NullContext.BulkOutSize = TXINFO_SIZE + TXWI_SIZE + sizeof(pAd->NullFrame) + 4; -} -#endif // RT2870 // - - -/* - ========================================================================== - Description: - Pre-build a BEACON frame in the shared memory - - IRQL = PASSIVE_LEVEL - IRQL = DISPATCH_LEVEL - - ========================================================================== -*/ -ULONG MakeIbssBeacon( - IN PRTMP_ADAPTER pAd) -{ - UCHAR DsLen = 1, IbssLen = 2; - UCHAR LocalErpIe[3] = {IE_ERP, 1, 0x04}; - HEADER_802_11 BcnHdr; - USHORT CapabilityInfo; - LARGE_INTEGER FakeTimestamp; - ULONG FrameLen = 0; - PTXWI_STRUC pTxWI = &pAd->BeaconTxWI; - CHAR *pBeaconFrame = pAd->BeaconBuf; - BOOLEAN Privacy; - UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES]; - UCHAR SupRateLen = 0; - UCHAR ExtRate[MAX_LEN_OF_SUPPORTED_RATES]; - UCHAR ExtRateLen = 0; - UCHAR RSNIe = IE_WPA; - - if ((pAd->CommonCfg.PhyMode == PHY_11B) && (pAd->CommonCfg.Channel <= 14)) - { - SupRate[0] = 0x82; // 1 mbps - SupRate[1] = 0x84; // 2 mbps - SupRate[2] = 0x8b; // 5.5 mbps - SupRate[3] = 0x96; // 11 mbps - SupRateLen = 4; - ExtRateLen = 0; - } - else if (pAd->CommonCfg.Channel > 14) - { - SupRate[0] = 0x8C; // 6 mbps, in units of 0.5 Mbps, basic rate - SupRate[1] = 0x12; // 9 mbps, in units of 0.5 Mbps - SupRate[2] = 0x98; // 12 mbps, in units of 0.5 Mbps, basic rate - SupRate[3] = 0x24; // 18 mbps, in units of 0.5 Mbps - SupRate[4] = 0xb0; // 24 mbps, in units of 0.5 Mbps, basic rate - SupRate[5] = 0x48; // 36 mbps, in units of 0.5 Mbps - SupRate[6] = 0x60; // 48 mbps, in units of 0.5 Mbps - SupRate[7] = 0x6c; // 54 mbps, in units of 0.5 Mbps - SupRateLen = 8; - ExtRateLen = 0; - - // - // Also Update MlmeRate & RtsRate for G only & A only - // - pAd->CommonCfg.MlmeRate = RATE_6; - pAd->CommonCfg.RtsRate = RATE_6; - pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM; - pAd->CommonCfg.MlmeTransmit.field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate]; - pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MODE = MODE_OFDM; - pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate]; - } - else - { - SupRate[0] = 0x82; // 1 mbps - SupRate[1] = 0x84; // 2 mbps - SupRate[2] = 0x8b; // 5.5 mbps - SupRate[3] = 0x96; // 11 mbps - SupRateLen = 4; - - ExtRate[0] = 0x0C; // 6 mbps, in units of 0.5 Mbps, - ExtRate[1] = 0x12; // 9 mbps, in units of 0.5 Mbps - ExtRate[2] = 0x18; // 12 mbps, in units of 0.5 Mbps, - ExtRate[3] = 0x24; // 18 mbps, in units of 0.5 Mbps - ExtRate[4] = 0x30; // 24 mbps, in units of 0.5 Mbps, - ExtRate[5] = 0x48; // 36 mbps, in units of 0.5 Mbps - ExtRate[6] = 0x60; // 48 mbps, in units of 0.5 Mbps - ExtRate[7] = 0x6c; // 54 mbps, in units of 0.5 Mbps - ExtRateLen = 8; - } - - pAd->StaActive.SupRateLen = SupRateLen; - NdisMoveMemory(pAd->StaActive.SupRate, SupRate, SupRateLen); - pAd->StaActive.ExtRateLen = ExtRateLen; - NdisMoveMemory(pAd->StaActive.ExtRate, ExtRate, ExtRateLen); - - // compose IBSS beacon frame - MgtMacHeaderInit(pAd, &BcnHdr, SUBTYPE_BEACON, 0, BROADCAST_ADDR, pAd->CommonCfg.Bssid); - Privacy = (pAd->StaCfg.WepStatus == Ndis802_11Encryption1Enabled) || - (pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) || - (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled); - CapabilityInfo = CAP_GENERATE(0, 1, Privacy, (pAd->CommonCfg.TxPreamble == Rt802_11PreambleShort), 0, 0); - - MakeOutgoingFrame(pBeaconFrame, &FrameLen, - sizeof(HEADER_802_11), &BcnHdr, - TIMESTAMP_LEN, &FakeTimestamp, - 2, &pAd->CommonCfg.BeaconPeriod, - 2, &CapabilityInfo, - 1, &SsidIe, - 1, &pAd->CommonCfg.SsidLen, - pAd->CommonCfg.SsidLen, pAd->CommonCfg.Ssid, - 1, &SupRateIe, - 1, &SupRateLen, - SupRateLen, SupRate, - 1, &DsIe, - 1, &DsLen, - 1, &pAd->CommonCfg.Channel, - 1, &IbssIe, - 1, &IbssLen, - 2, &pAd->StaActive.AtimWin, - END_OF_ARGS); - - // add ERP_IE and EXT_RAE IE of in 802.11g - if (ExtRateLen) - { - ULONG tmp; - - MakeOutgoingFrame(pBeaconFrame + FrameLen, &tmp, - 3, LocalErpIe, - 1, &ExtRateIe, - 1, &ExtRateLen, - ExtRateLen, ExtRate, - END_OF_ARGS); - FrameLen += tmp; - } - - // If adhoc secruity is set for WPA-None, append the cipher suite IE - if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) - { - ULONG tmp; - RTMPMakeRSNIE(pAd, pAd->StaCfg.AuthMode, pAd->StaCfg.WepStatus, BSS0); - - MakeOutgoingFrame(pBeaconFrame + FrameLen, &tmp, - 1, &RSNIe, - 1, &pAd->StaCfg.RSNIE_Len, - pAd->StaCfg.RSNIE_Len, pAd->StaCfg.RSN_IE, - END_OF_ARGS); - FrameLen += tmp; - } - -#ifdef DOT11_N_SUPPORT - if ((pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) - { - ULONG TmpLen; - UCHAR HtLen, HtLen1; - -#ifdef RT_BIG_ENDIAN - HT_CAPABILITY_IE HtCapabilityTmp; - ADD_HT_INFO_IE addHTInfoTmp; - USHORT b2lTmp, b2lTmp2; -#endif - - // add HT Capability IE - HtLen = sizeof(pAd->CommonCfg.HtCapability); - HtLen1 = sizeof(pAd->CommonCfg.AddHTInfo); -#ifndef RT_BIG_ENDIAN - MakeOutgoingFrame(pBeaconFrame+FrameLen, &TmpLen, - 1, &HtCapIe, - 1, &HtLen, - HtLen, &pAd->CommonCfg.HtCapability, - 1, &AddHtInfoIe, - 1, &HtLen1, - HtLen1, &pAd->CommonCfg.AddHTInfo, - END_OF_ARGS); -#else - NdisMoveMemory(&HtCapabilityTmp, &pAd->CommonCfg.HtCapability, HtLen); - *(USHORT *)(&HtCapabilityTmp.HtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.HtCapInfo)); - *(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo)); - - NdisMoveMemory(&addHTInfoTmp, &pAd->CommonCfg.AddHTInfo, HtLen1); - *(USHORT *)(&addHTInfoTmp.AddHtInfo2) = SWAP16(*(USHORT *)(&addHTInfoTmp.AddHtInfo2)); - *(USHORT *)(&addHTInfoTmp.AddHtInfo3) = SWAP16(*(USHORT *)(&addHTInfoTmp.AddHtInfo3)); - - MakeOutgoingFrame(pBeaconFrame+FrameLen, &TmpLen, - 1, &HtCapIe, - 1, &HtLen, - HtLen, &HtCapabilityTmp, - 1, &AddHtInfoIe, - 1, &HtLen1, - HtLen1, &addHTInfoTmp, - END_OF_ARGS); -#endif - FrameLen += TmpLen; - } -#endif // DOT11_N_SUPPORT // - - //beacon use reserved WCID 0xff - if (pAd->CommonCfg.Channel > 14) - { - RTMPWriteTxWI(pAd, pTxWI, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, 0, 0xff, FrameLen, - PID_MGMT, PID_BEACON, RATE_1, IFS_HTTXOP, FALSE, &pAd->CommonCfg.MlmeTransmit); - } - else - { - // Set to use 1Mbps for Adhoc beacon. - HTTRANSMIT_SETTING Transmit; - Transmit.word = 0; - RTMPWriteTxWI(pAd, pTxWI, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, 0, 0xff, FrameLen, - PID_MGMT, PID_BEACON, RATE_1, IFS_HTTXOP, FALSE, &Transmit); - } - -#ifdef RT_BIG_ENDIAN - RTMPFrameEndianChange(pAd, pBeaconFrame, DIR_WRITE, FALSE); - RTMPWIEndianChange((PUCHAR)pTxWI, TYPE_TXWI); -#endif - - DBGPRINT(RT_DEBUG_TRACE, ("MakeIbssBeacon (len=%ld), SupRateLen=%d, ExtRateLen=%d, Channel=%d, PhyMode=%d\n", - FrameLen, SupRateLen, ExtRateLen, pAd->CommonCfg.Channel, pAd->CommonCfg.PhyMode)); - return FrameLen; -} - +#include "../../rt2870/sta/connect.c" diff --git a/drivers/staging/rt3070/sta/dls.c b/drivers/staging/rt3070/sta/dls.c deleted file mode 100644 index 8bcd41329343..000000000000 --- a/drivers/staging/rt3070/sta/dls.c +++ /dev/null @@ -1,2170 +0,0 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - dls.c - - Abstract: - Handle WMM-DLS state machine - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Rory Chen 02-14-2006 - Arvin Tai 06-03-2008 Modified for RT28xx - */ - -#include "../rt_config.h" - -/* - ========================================================================== - Description: - dls state machine init, including state transition and timer init - Parameters: - Sm - pointer to the dls state machine - Note: - The state machine looks like this - - DLS_IDLE - MT2_MLME_DLS_REQUEST MlmeDlsReqAction - MT2_PEER_DLS_REQUEST PeerDlsReqAction - MT2_PEER_DLS_RESPONSE PeerDlsRspAction - MT2_MLME_DLS_TEARDOWN MlmeTearDownAction - MT2_PEER_DLS_TEARDOWN PeerTearDownAction - - IRQL = PASSIVE_LEVEL - - ========================================================================== - */ -void DlsStateMachineInit( - IN PRTMP_ADAPTER pAd, - IN STATE_MACHINE *Sm, - OUT STATE_MACHINE_FUNC Trans[]) -{ - UCHAR i; - - StateMachineInit(Sm, (STATE_MACHINE_FUNC*)Trans, MAX_DLS_STATE, MAX_DLS_MSG, (STATE_MACHINE_FUNC)Drop, DLS_IDLE, DLS_MACHINE_BASE); - - // the first column - StateMachineSetAction(Sm, DLS_IDLE, MT2_MLME_DLS_REQ, (STATE_MACHINE_FUNC)MlmeDlsReqAction); - StateMachineSetAction(Sm, DLS_IDLE, MT2_PEER_DLS_REQ, (STATE_MACHINE_FUNC)PeerDlsReqAction); - StateMachineSetAction(Sm, DLS_IDLE, MT2_PEER_DLS_RSP, (STATE_MACHINE_FUNC)PeerDlsRspAction); - StateMachineSetAction(Sm, DLS_IDLE, MT2_MLME_DLS_TEAR_DOWN, (STATE_MACHINE_FUNC)MlmeDlsTearDownAction); - StateMachineSetAction(Sm, DLS_IDLE, MT2_PEER_DLS_TEAR_DOWN, (STATE_MACHINE_FUNC)PeerDlsTearDownAction); - - for (i=0; iStaCfg.DLSEntry[i].pAd = pAd; - RTMPInitTimer(pAd, &pAd->StaCfg.DLSEntry[i].Timer, GET_TIMER_FUNCTION(DlsTimeoutAction), pAd, FALSE); - } -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID MlmeDlsReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - PUCHAR pOutBuffer = NULL; - NDIS_STATUS NStatus; - ULONG FrameLen = 0; - HEADER_802_11 DlsReqHdr; - PRT_802_11_DLS pDLS = NULL; - UCHAR Category = CATEGORY_DLS; - UCHAR Action = ACTION_DLS_REQUEST; - ULONG tmp; - USHORT reason; - ULONG Timeout; - BOOLEAN TimerCancelled; - - if(!MlmeDlsReqSanity(pAd, Elem->Msg, Elem->MsgLen, &pDLS, &reason)) - return; - - DBGPRINT(RT_DEBUG_TRACE,("DLS - MlmeDlsReqAction() \n")); - - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory - if (NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_ERROR,("DLS - MlmeDlsReqAction() allocate memory failed \n")); - return; - } - - ActHeaderInit(pAd, &DlsReqHdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pAd->CommonCfg.Bssid); - - // Build basic frame first - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(HEADER_802_11), &DlsReqHdr, - 1, &Category, - 1, &Action, - 6, &pDLS->MacAddr, - 6, pAd->CurrentAddress, - 2, &pAd->StaActive.CapabilityInfo, - 2, &pDLS->TimeOut, - 1, &SupRateIe, - 1, &pAd->MlmeAux.SupRateLen, - pAd->MlmeAux.SupRateLen, pAd->MlmeAux.SupRate, - END_OF_ARGS); - - if (pAd->MlmeAux.ExtRateLen != 0) - { - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - 1, &ExtRateIe, - 1, &pAd->MlmeAux.ExtRateLen, - pAd->MlmeAux.ExtRateLen, pAd->MlmeAux.ExtRate, - END_OF_ARGS); - FrameLen += tmp; - } - -#ifdef DOT11_N_SUPPORT - if ((pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) - { - UCHAR HtLen; - -#ifdef RT_BIG_ENDIAN - HT_CAPABILITY_IE HtCapabilityTmp; -#endif - - // add HT Capability IE - HtLen = sizeof(HT_CAPABILITY_IE); -#ifndef RT_BIG_ENDIAN - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - 1, &HtCapIe, - 1, &HtLen, - HtLen, &pAd->CommonCfg.HtCapability, - END_OF_ARGS); -#else - NdisMoveMemory(&HtCapabilityTmp, &pAd->CommonCfg.HtCapability, HtLen); - *(USHORT *)(&HtCapabilityTmp.HtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.HtCapInfo)); - *(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo)); - - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - 1, &HtCapIe, - 1, &HtLen, - HtLen, &HtCapabilityTmp, - END_OF_ARGS); -#endif - FrameLen = FrameLen + tmp; - } -#endif // DOT11_N_SUPPORT // - - RTMPCancelTimer(&pDLS->Timer, &TimerCancelled); - Timeout = DLS_TIMEOUT; - RTMPSetTimer(&pDLS->Timer, Timeout); - - MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID PeerDlsReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - PUCHAR pOutBuffer = NULL; - NDIS_STATUS NStatus; - ULONG FrameLen = 0; - USHORT StatusCode = MLME_SUCCESS; - HEADER_802_11 DlsRspHdr; - UCHAR Category = CATEGORY_DLS; - UCHAR Action = ACTION_DLS_RESPONSE; - ULONG tmp; - USHORT CapabilityInfo; - UCHAR DA[MAC_ADDR_LEN], SA[MAC_ADDR_LEN]; - USHORT DLSTimeOut; - SHORT i; - ULONG Timeout; - BOOLEAN TimerCancelled; - PRT_802_11_DLS pDLS = NULL; - UCHAR MaxSupportedRateIn500Kbps = 0; - UCHAR SupportedRatesLen; - UCHAR SupportedRates[MAX_LEN_OF_SUPPORTED_RATES]; - UCHAR HtCapabilityLen; - HT_CAPABILITY_IE HtCapability; - - if (!PeerDlsReqSanity(pAd, Elem->Msg, Elem->MsgLen, DA, SA, &CapabilityInfo, &DLSTimeOut, - &SupportedRatesLen, &SupportedRates[0], &HtCapabilityLen, &HtCapability)) - return; - - // supported rates array may not be sorted. sort it and find the maximum rate - for (i = 0; i < SupportedRatesLen; i++) - { - if (MaxSupportedRateIn500Kbps < (SupportedRates[i] & 0x7f)) - MaxSupportedRateIn500Kbps = SupportedRates[i] & 0x7f; - } - - DBGPRINT(RT_DEBUG_TRACE,("DLS - PeerDlsReqAction() from %02x:%02x:%02x:%02x:%02x:%02x\n", SA[0], SA[1], SA[2], SA[3], SA[4], SA[5])); - - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory - if (NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_ERROR,("DLS - PeerDlsReqAction() allocate memory failed \n")); - return; - } - - if (!INFRA_ON(pAd)) - { - StatusCode = MLME_REQUEST_DECLINED; - } - else if (!pAd->CommonCfg.bWmmCapable) - { - StatusCode = MLME_DEST_STA_IS_NOT_A_QSTA; - } - else if (!pAd->CommonCfg.bDLSCapable) - { - StatusCode = MLME_REQUEST_DECLINED; - } - else - { - // find table to update parameters - for (i = (MAX_NUM_OF_DLS_ENTRY-1); i >= 0; i--) - { - if (pAd->StaCfg.DLSEntry[i].Valid && MAC_ADDR_EQUAL(SA, pAd->StaCfg.DLSEntry[i].MacAddr)) - { - if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - pAd->StaCfg.DLSEntry[i].Status = DLS_WAIT_KEY; - else - { - RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); - pAd->StaCfg.DLSEntry[i].Status = DLS_FINISH; - } - - pAd->StaCfg.DLSEntry[i].Sequence = 0; - pAd->StaCfg.DLSEntry[i].TimeOut = DLSTimeOut; - pAd->StaCfg.DLSEntry[i].CountDownTimer = DLSTimeOut; - if (HtCapabilityLen != 0) - pAd->StaCfg.DLSEntry[i].bHTCap = TRUE; - else - pAd->StaCfg.DLSEntry[i].bHTCap = FALSE; - pDLS = &pAd->StaCfg.DLSEntry[i]; - break; - } - } - - // can not find in table, create a new one - if (i < 0) - { - DBGPRINT(RT_DEBUG_TRACE,("DLS - PeerDlsReqAction() can not find same entry \n")); - for (i=(MAX_NUM_OF_DLS_ENTRY - 1); i >= MAX_NUM_OF_INIT_DLS_ENTRY; i--) - { - if (!pAd->StaCfg.DLSEntry[i].Valid) - { - MAC_TABLE_ENTRY *pEntry; - UCHAR MaxSupportedRate = RATE_11; - - if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - { - pAd->StaCfg.DLSEntry[i].Status = DLS_WAIT_KEY; - } - else - { - RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); - pAd->StaCfg.DLSEntry[i].Status = DLS_FINISH; - } - - pAd->StaCfg.DLSEntry[i].Sequence = 0; - pAd->StaCfg.DLSEntry[i].Valid = TRUE; - pAd->StaCfg.DLSEntry[i].TimeOut = DLSTimeOut; - pAd->StaCfg.DLSEntry[i].CountDownTimer = DLSTimeOut; - NdisMoveMemory(pAd->StaCfg.DLSEntry[i].MacAddr, SA, MAC_ADDR_LEN); - if (HtCapabilityLen != 0) - pAd->StaCfg.DLSEntry[i].bHTCap = TRUE; - else - pAd->StaCfg.DLSEntry[i].bHTCap = FALSE; - pDLS = &pAd->StaCfg.DLSEntry[i]; - pEntry = MacTableInsertDlsEntry(pAd, SA, i); - - switch (MaxSupportedRateIn500Kbps) - { - case 108: MaxSupportedRate = RATE_54; break; - case 96: MaxSupportedRate = RATE_48; break; - case 72: MaxSupportedRate = RATE_36; break; - case 48: MaxSupportedRate = RATE_24; break; - case 36: MaxSupportedRate = RATE_18; break; - case 24: MaxSupportedRate = RATE_12; break; - case 18: MaxSupportedRate = RATE_9; break; - case 12: MaxSupportedRate = RATE_6; break; - case 22: MaxSupportedRate = RATE_11; break; - case 11: MaxSupportedRate = RATE_5_5; break; - case 4: MaxSupportedRate = RATE_2; break; - case 2: MaxSupportedRate = RATE_1; break; - default: MaxSupportedRate = RATE_11; break; - } - - pEntry->MaxSupportedRate = min(pAd->CommonCfg.MaxTxRate, MaxSupportedRate); - - if (pEntry->MaxSupportedRate < RATE_FIRST_OFDM_RATE) - { - pEntry->MaxHTPhyMode.field.MODE = MODE_CCK; - pEntry->MaxHTPhyMode.field.MCS = pEntry->MaxSupportedRate; - pEntry->MinHTPhyMode.field.MODE = MODE_CCK; - pEntry->MinHTPhyMode.field.MCS = pEntry->MaxSupportedRate; - pEntry->HTPhyMode.field.MODE = MODE_CCK; - pEntry->HTPhyMode.field.MCS = pEntry->MaxSupportedRate; - } - else - { - pEntry->MaxHTPhyMode.field.MODE = MODE_OFDM; - pEntry->MaxHTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; - pEntry->MinHTPhyMode.field.MODE = MODE_OFDM; - pEntry->MinHTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; - pEntry->HTPhyMode.field.MODE = MODE_OFDM; - pEntry->HTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; - } - - pEntry->MaxHTPhyMode.field.BW = BW_20; - pEntry->MinHTPhyMode.field.BW = BW_20; - -#ifdef DOT11_N_SUPPORT - pEntry->HTCapability.MCSSet[0] = 0; - pEntry->HTCapability.MCSSet[1] = 0; - - // If this Entry supports 802.11n, upgrade to HT rate. - if ((HtCapabilityLen != 0) && (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) - { - UCHAR j, bitmask; //k,bitmask; - CHAR ii; - - if ((HtCapability.HtCapInfo.GF) && (pAd->CommonCfg.DesiredHtPhy.GF)) - { - pEntry->MaxHTPhyMode.field.MODE = MODE_HTGREENFIELD; - } - else - { - pEntry->MaxHTPhyMode.field.MODE = MODE_HTMIX; - pAd->MacTab.fAnyStationNonGF = TRUE; - pAd->CommonCfg.AddHTInfo.AddHtInfo2.NonGfPresent = 1; - } - - if ((HtCapability.HtCapInfo.ChannelWidth) && (pAd->CommonCfg.DesiredHtPhy.ChannelWidth)) - { - pEntry->MaxHTPhyMode.field.BW= BW_40; - pEntry->MaxHTPhyMode.field.ShortGI = ((pAd->CommonCfg.DesiredHtPhy.ShortGIfor40)&(HtCapability.HtCapInfo.ShortGIfor40)); - } - else - { - pEntry->MaxHTPhyMode.field.BW = BW_20; - pEntry->MaxHTPhyMode.field.ShortGI = ((pAd->CommonCfg.DesiredHtPhy.ShortGIfor20)&(HtCapability.HtCapInfo.ShortGIfor20)); - pAd->MacTab.fAnyStation20Only = TRUE; - } - - // find max fixed rate - for (ii=15; ii>=0; ii--) - { - j = ii/8; - bitmask = (1<<(ii-(j*8))); - if ( (pAd->StaCfg.DesiredHtPhyInfo.MCSSet[j]&bitmask) && (HtCapability.MCSSet[j]&bitmask)) - { - pEntry->MaxHTPhyMode.field.MCS = ii; - break; - } - if (ii==0) - break; - } - - - if (pAd->StaCfg.DesiredTransmitSetting.field.MCS != MCS_AUTO) - { - - printk("@@@ pAd->CommonCfg.RegTransmitSetting.field.MCS = %d\n", - pAd->StaCfg.DesiredTransmitSetting.field.MCS); - if (pAd->StaCfg.DesiredTransmitSetting.field.MCS == 32) - { - // Fix MCS as HT Duplicated Mode - pEntry->MaxHTPhyMode.field.BW = 1; - pEntry->MaxHTPhyMode.field.MODE = MODE_HTMIX; - pEntry->MaxHTPhyMode.field.STBC = 0; - pEntry->MaxHTPhyMode.field.ShortGI = 0; - pEntry->MaxHTPhyMode.field.MCS = 32; - } - else if (pEntry->MaxHTPhyMode.field.MCS > pAd->StaCfg.HTPhyMode.field.MCS) - { - // STA supports fixed MCS - pEntry->MaxHTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; - } - } - - pEntry->MaxHTPhyMode.field.STBC = (HtCapability.HtCapInfo.RxSTBC & (pAd->CommonCfg.DesiredHtPhy.TxSTBC)); - pEntry->MpduDensity = HtCapability.HtCapParm.MpduDensity; - pEntry->MaxRAmpduFactor = HtCapability.HtCapParm.MaxRAmpduFactor; - pEntry->MmpsMode = (UCHAR)HtCapability.HtCapInfo.MimoPs; - pEntry->AMsduSize = (UCHAR)HtCapability.HtCapInfo.AMsduSize; - pEntry->HTPhyMode.word = pEntry->MaxHTPhyMode.word; - - if (HtCapability.HtCapInfo.ShortGIfor20) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_SGI20_CAPABLE); - if (HtCapability.HtCapInfo.ShortGIfor40) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_SGI40_CAPABLE); - if (HtCapability.HtCapInfo.TxSTBC) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_TxSTBC_CAPABLE); - if (HtCapability.HtCapInfo.RxSTBC) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_RxSTBC_CAPABLE); - if (HtCapability.ExtHtCapInfo.PlusHTC) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_HTC_CAPABLE); - if (pAd->CommonCfg.bRdg && HtCapability.ExtHtCapInfo.RDGSupport) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_RDG_CAPABLE); - if (HtCapability.ExtHtCapInfo.MCSFeedback == 0x03) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_MCSFEEDBACK_CAPABLE); - - NdisMoveMemory(&pEntry->HTCapability, &HtCapability, sizeof(HT_CAPABILITY_IE)); - } -#endif // DOT11_N_SUPPORT // - - pEntry->HTPhyMode.word = pEntry->MaxHTPhyMode.word; - pEntry->CurrTxRate = pEntry->MaxSupportedRate; - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_WMM_CAPABLE); - - if (pAd->StaCfg.bAutoTxRateSwitch == TRUE) - { - PUCHAR pTable; - UCHAR TableSize = 0; - - MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize, &pEntry->CurrTxRateIndex); - pEntry->bAutoTxRateSwitch = TRUE; - } - else - { - pEntry->HTPhyMode.field.MODE = pAd->StaCfg.HTPhyMode.field.MODE; - pEntry->HTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; - pEntry->bAutoTxRateSwitch = FALSE; - - RTMPUpdateLegacyTxSetting((UCHAR)pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode, pEntry); - } - pEntry->RateLen = SupportedRatesLen; - - break; - } - } - } - StatusCode = MLME_SUCCESS; - - // can not find in table, create a new one - if (i < 0) - { - StatusCode = MLME_QOS_UNSPECIFY; - DBGPRINT(RT_DEBUG_ERROR,("DLS - PeerDlsReqAction() DLSEntry table full(only can support %d DLS session) \n", MAX_NUM_OF_DLS_ENTRY - MAX_NUM_OF_INIT_DLS_ENTRY)); - } - else - { - DBGPRINT(RT_DEBUG_TRACE,("DLS - PeerDlsReqAction() use entry(%d) %02x:%02x:%02x:%02x:%02x:%02x\n", - i, SA[0], SA[1], SA[2], SA[3], SA[4], SA[5])); - } - } - - ActHeaderInit(pAd, &DlsRspHdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pAd->CommonCfg.Bssid); - - // Build basic frame first - if (StatusCode == MLME_SUCCESS) - { - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(HEADER_802_11), &DlsRspHdr, - 1, &Category, - 1, &Action, - 2, &StatusCode, - 6, SA, - 6, pAd->CurrentAddress, - 2, &pAd->StaActive.CapabilityInfo, - 1, &SupRateIe, - 1, &pAd->MlmeAux.SupRateLen, - pAd->MlmeAux.SupRateLen, pAd->MlmeAux.SupRate, - END_OF_ARGS); - - if (pAd->MlmeAux.ExtRateLen != 0) - { - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - 1, &ExtRateIe, - 1, &pAd->MlmeAux.ExtRateLen, - pAd->MlmeAux.ExtRateLen, pAd->MlmeAux.ExtRate, - END_OF_ARGS); - FrameLen += tmp; - } - -#ifdef DOT11_N_SUPPORT - if ((pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) - { - UCHAR HtLen; - -#ifdef RT_BIG_ENDIAN - HT_CAPABILITY_IE HtCapabilityTmp; -#endif - - // add HT Capability IE - HtLen = sizeof(HT_CAPABILITY_IE); -#ifndef RT_BIG_ENDIAN - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - 1, &HtCapIe, - 1, &HtLen, - HtLen, &pAd->CommonCfg.HtCapability, - END_OF_ARGS); -#else - NdisMoveMemory(&HtCapabilityTmp, &pAd->CommonCfg.HtCapability, HtLen); - *(USHORT *)(&HtCapabilityTmp.HtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.HtCapInfo)); - *(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo)); - - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - 1, &HtCapIe, - 1, &HtLen, - HtLen, &HtCapabilityTmp, - END_OF_ARGS); -#endif - FrameLen = FrameLen + tmp; - } -#endif // DOT11_N_SUPPORT // - - if (pDLS && (pDLS->Status != DLS_FINISH)) - { - RTMPCancelTimer(&pDLS->Timer, &TimerCancelled); - Timeout = DLS_TIMEOUT; - RTMPSetTimer(&pDLS->Timer, Timeout); - } - } - else - { - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(HEADER_802_11), &DlsRspHdr, - 1, &Category, - 1, &Action, - 2, &StatusCode, - 6, SA, - 6, pAd->CurrentAddress, - END_OF_ARGS); - } - - MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID PeerDlsRspAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - USHORT CapabilityInfo; - UCHAR DA[MAC_ADDR_LEN], SA[MAC_ADDR_LEN]; - USHORT StatusCode; - SHORT i; - BOOLEAN TimerCancelled; - UCHAR MaxSupportedRateIn500Kbps = 0; - UCHAR SupportedRatesLen; - UCHAR SupportedRates[MAX_LEN_OF_SUPPORTED_RATES]; - UCHAR HtCapabilityLen; - HT_CAPABILITY_IE HtCapability; - - if (!pAd->CommonCfg.bDLSCapable) - return; - - if (!INFRA_ON(pAd)) - return; - - if (!PeerDlsRspSanity(pAd, Elem->Msg, Elem->MsgLen, DA, SA, &CapabilityInfo, &StatusCode, - &SupportedRatesLen, &SupportedRates[0], &HtCapabilityLen, &HtCapability)) - return; - - // supported rates array may not be sorted. sort it and find the maximum rate - for (i=0; iStaCfg.DLSEntry[i].Valid && MAC_ADDR_EQUAL(SA, pAd->StaCfg.DLSEntry[i].MacAddr)) - { - if (StatusCode == MLME_SUCCESS) - { - MAC_TABLE_ENTRY *pEntry; - UCHAR MaxSupportedRate = RATE_11; - - pEntry = MacTableInsertDlsEntry(pAd, SA, i); - - switch (MaxSupportedRateIn500Kbps) - { - case 108: MaxSupportedRate = RATE_54; break; - case 96: MaxSupportedRate = RATE_48; break; - case 72: MaxSupportedRate = RATE_36; break; - case 48: MaxSupportedRate = RATE_24; break; - case 36: MaxSupportedRate = RATE_18; break; - case 24: MaxSupportedRate = RATE_12; break; - case 18: MaxSupportedRate = RATE_9; break; - case 12: MaxSupportedRate = RATE_6; break; - case 22: MaxSupportedRate = RATE_11; break; - case 11: MaxSupportedRate = RATE_5_5; break; - case 4: MaxSupportedRate = RATE_2; break; - case 2: MaxSupportedRate = RATE_1; break; - default: MaxSupportedRate = RATE_11; break; - } - - pEntry->MaxSupportedRate = min(pAd->CommonCfg.MaxTxRate, MaxSupportedRate); - - if (pEntry->MaxSupportedRate < RATE_FIRST_OFDM_RATE) - { - pEntry->MaxHTPhyMode.field.MODE = MODE_CCK; - pEntry->MaxHTPhyMode.field.MCS = pEntry->MaxSupportedRate; - pEntry->MinHTPhyMode.field.MODE = MODE_CCK; - pEntry->MinHTPhyMode.field.MCS = pEntry->MaxSupportedRate; - pEntry->HTPhyMode.field.MODE = MODE_CCK; - pEntry->HTPhyMode.field.MCS = pEntry->MaxSupportedRate; - } - else - { - pEntry->MaxHTPhyMode.field.MODE = MODE_OFDM; - pEntry->MaxHTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; - pEntry->MinHTPhyMode.field.MODE = MODE_OFDM; - pEntry->MinHTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; - pEntry->HTPhyMode.field.MODE = MODE_OFDM; - pEntry->HTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; - } - - pEntry->MaxHTPhyMode.field.BW = BW_20; - pEntry->MinHTPhyMode.field.BW = BW_20; - -#ifdef DOT11_N_SUPPORT - pEntry->HTCapability.MCSSet[0] = 0; - pEntry->HTCapability.MCSSet[1] = 0; - - // If this Entry supports 802.11n, upgrade to HT rate. - if ((HtCapabilityLen != 0) && (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) - { - UCHAR j, bitmask; //k,bitmask; - CHAR ii; - - if ((HtCapability.HtCapInfo.GF) && (pAd->CommonCfg.DesiredHtPhy.GF)) - { - pEntry->MaxHTPhyMode.field.MODE = MODE_HTGREENFIELD; - } - else - { - pEntry->MaxHTPhyMode.field.MODE = MODE_HTMIX; - pAd->MacTab.fAnyStationNonGF = TRUE; - pAd->CommonCfg.AddHTInfo.AddHtInfo2.NonGfPresent = 1; - } - - if ((HtCapability.HtCapInfo.ChannelWidth) && (pAd->CommonCfg.DesiredHtPhy.ChannelWidth)) - { - pEntry->MaxHTPhyMode.field.BW= BW_40; - pEntry->MaxHTPhyMode.field.ShortGI = ((pAd->CommonCfg.DesiredHtPhy.ShortGIfor40)&(HtCapability.HtCapInfo.ShortGIfor40)); - } - else - { - pEntry->MaxHTPhyMode.field.BW = BW_20; - pEntry->MaxHTPhyMode.field.ShortGI = ((pAd->CommonCfg.DesiredHtPhy.ShortGIfor20)&(HtCapability.HtCapInfo.ShortGIfor20)); - pAd->MacTab.fAnyStation20Only = TRUE; - } - - // find max fixed rate - for (ii=15; ii>=0; ii--) - { - j = ii/8; - bitmask = (1<<(ii-(j*8))); - if ( (pAd->StaCfg.DesiredHtPhyInfo.MCSSet[j]&bitmask) && (HtCapability.MCSSet[j]&bitmask)) - { - pEntry->MaxHTPhyMode.field.MCS = ii; - break; - } - if (ii==0) - break; - } - - if (pAd->StaCfg.DesiredTransmitSetting.field.MCS != MCS_AUTO) - { - if (pAd->StaCfg.DesiredTransmitSetting.field.MCS == 32) - { - // Fix MCS as HT Duplicated Mode - pEntry->MaxHTPhyMode.field.BW = 1; - pEntry->MaxHTPhyMode.field.MODE = MODE_HTMIX; - pEntry->MaxHTPhyMode.field.STBC = 0; - pEntry->MaxHTPhyMode.field.ShortGI = 0; - pEntry->MaxHTPhyMode.field.MCS = 32; - } - else if (pEntry->MaxHTPhyMode.field.MCS > pAd->StaCfg.HTPhyMode.field.MCS) - { - // STA supports fixed MCS - pEntry->MaxHTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; - } - } - - pEntry->MaxHTPhyMode.field.STBC = (HtCapability.HtCapInfo.RxSTBC & (pAd->CommonCfg.DesiredHtPhy.TxSTBC)); - pEntry->MpduDensity = HtCapability.HtCapParm.MpduDensity; - pEntry->MaxRAmpduFactor = HtCapability.HtCapParm.MaxRAmpduFactor; - pEntry->MmpsMode = (UCHAR)HtCapability.HtCapInfo.MimoPs; - pEntry->AMsduSize = (UCHAR)HtCapability.HtCapInfo.AMsduSize; - pEntry->HTPhyMode.word = pEntry->MaxHTPhyMode.word; - - if (HtCapability.HtCapInfo.ShortGIfor20) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_SGI20_CAPABLE); - if (HtCapability.HtCapInfo.ShortGIfor40) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_SGI40_CAPABLE); - if (HtCapability.HtCapInfo.TxSTBC) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_TxSTBC_CAPABLE); - if (HtCapability.HtCapInfo.RxSTBC) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_RxSTBC_CAPABLE); - if (HtCapability.ExtHtCapInfo.PlusHTC) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_HTC_CAPABLE); - if (pAd->CommonCfg.bRdg && HtCapability.ExtHtCapInfo.RDGSupport) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_RDG_CAPABLE); - if (HtCapability.ExtHtCapInfo.MCSFeedback == 0x03) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_MCSFEEDBACK_CAPABLE); - - NdisMoveMemory(&pEntry->HTCapability, &HtCapability, sizeof(HT_CAPABILITY_IE)); - } -#endif // DOT11_N_SUPPORT // - pEntry->HTPhyMode.word = pEntry->MaxHTPhyMode.word; - pEntry->CurrTxRate = pEntry->MaxSupportedRate; - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_WMM_CAPABLE); - - if (pAd->StaCfg.bAutoTxRateSwitch == TRUE) - { - PUCHAR pTable; - UCHAR TableSize = 0; - - MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize, &pEntry->CurrTxRateIndex); - pEntry->bAutoTxRateSwitch = TRUE; - } - else - { - pEntry->HTPhyMode.field.MODE = pAd->StaCfg.HTPhyMode.field.MODE; - pEntry->HTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; - pEntry->bAutoTxRateSwitch = FALSE; - - RTMPUpdateLegacyTxSetting((UCHAR)pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode, pEntry); - } - pEntry->RateLen = SupportedRatesLen; - - if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - { - // If support WPA or WPA2, start STAKey hand shake, - // If failed hand shake, just tear down peer DLS - if (RTMPSendSTAKeyRequest(pAd, pAd->StaCfg.DLSEntry[i].MacAddr) != NDIS_STATUS_SUCCESS) - { - MLME_DLS_REQ_STRUCT MlmeDlsReq; - USHORT reason = REASON_QOS_CIPHER_NOT_SUPPORT; - - DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); - MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_TEAR_DOWN, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - pAd->StaCfg.DLSEntry[i].Valid = FALSE; - DBGPRINT(RT_DEBUG_ERROR,("DLS - PeerDlsRspAction failed when call RTMPSendSTAKeyRequest \n")); - } - else - { - pAd->StaCfg.DLSEntry[i].Status = DLS_WAIT_KEY; - DBGPRINT(RT_DEBUG_TRACE,("DLS - waiting for STAKey handshake procedure\n")); - } - } - else - { - RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); - pAd->StaCfg.DLSEntry[i].Status = DLS_FINISH; - DBGPRINT(RT_DEBUG_TRACE,("DLS - PeerDlsRspAction() from %02x:%02x:%02x:%02x:%02x:%02x Succeed with WEP or no security\n", SA[0], SA[1], SA[2], SA[3], SA[4], SA[5])); - } - - //initialize seq no for DLS frames. - pAd->StaCfg.DLSEntry[i].Sequence = 0; - if (HtCapabilityLen != 0) - pAd->StaCfg.DLSEntry[i].bHTCap = TRUE; - else - pAd->StaCfg.DLSEntry[i].bHTCap = FALSE; - } - else - { - // DLS setup procedure failed. - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - pAd->StaCfg.DLSEntry[i].Valid = FALSE; - RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); - DBGPRINT(RT_DEBUG_ERROR,("DLS - PeerDlsRspAction failed with StatusCode=%d \n", StatusCode)); - } - } - } - - if (i >= MAX_NUM_OF_INIT_DLS_ENTRY) - { - DBGPRINT(RT_DEBUG_TRACE,("DLS - PeerDlsRspAction() update timeout value \n")); - for (i=(MAX_NUM_OF_DLS_ENTRY-1); i>=MAX_NUM_OF_INIT_DLS_ENTRY; i--) - { - if (pAd->StaCfg.DLSEntry[i].Valid && MAC_ADDR_EQUAL(SA, pAd->StaCfg.DLSEntry[i].MacAddr)) - { - if (StatusCode == MLME_SUCCESS) - { - MAC_TABLE_ENTRY *pEntry; - UCHAR MaxSupportedRate = RATE_11; - - pEntry = MacTableInsertDlsEntry(pAd, SA, i); - - switch (MaxSupportedRateIn500Kbps) - { - case 108: MaxSupportedRate = RATE_54; break; - case 96: MaxSupportedRate = RATE_48; break; - case 72: MaxSupportedRate = RATE_36; break; - case 48: MaxSupportedRate = RATE_24; break; - case 36: MaxSupportedRate = RATE_18; break; - case 24: MaxSupportedRate = RATE_12; break; - case 18: MaxSupportedRate = RATE_9; break; - case 12: MaxSupportedRate = RATE_6; break; - case 22: MaxSupportedRate = RATE_11; break; - case 11: MaxSupportedRate = RATE_5_5; break; - case 4: MaxSupportedRate = RATE_2; break; - case 2: MaxSupportedRate = RATE_1; break; - default: MaxSupportedRate = RATE_11; break; - } - - pEntry->MaxSupportedRate = min(pAd->CommonCfg.MaxTxRate, MaxSupportedRate); - - if (pEntry->MaxSupportedRate < RATE_FIRST_OFDM_RATE) - { - pEntry->MaxHTPhyMode.field.MODE = MODE_CCK; - pEntry->MaxHTPhyMode.field.MCS = pEntry->MaxSupportedRate; - pEntry->MinHTPhyMode.field.MODE = MODE_CCK; - pEntry->MinHTPhyMode.field.MCS = pEntry->MaxSupportedRate; - pEntry->HTPhyMode.field.MODE = MODE_CCK; - pEntry->HTPhyMode.field.MCS = pEntry->MaxSupportedRate; - } - else - { - pEntry->MaxHTPhyMode.field.MODE = MODE_OFDM; - pEntry->MaxHTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; - pEntry->MinHTPhyMode.field.MODE = MODE_OFDM; - pEntry->MinHTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; - pEntry->HTPhyMode.field.MODE = MODE_OFDM; - pEntry->HTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; - } - - pEntry->MaxHTPhyMode.field.BW = BW_20; - pEntry->MinHTPhyMode.field.BW = BW_20; - -#ifdef DOT11_N_SUPPORT - pEntry->HTCapability.MCSSet[0] = 0; - pEntry->HTCapability.MCSSet[1] = 0; - - // If this Entry supports 802.11n, upgrade to HT rate. - if ((HtCapabilityLen != 0) && (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) - { - UCHAR j, bitmask; //k,bitmask; - CHAR ii; - - if ((HtCapability.HtCapInfo.GF) && (pAd->CommonCfg.DesiredHtPhy.GF)) - { - pEntry->MaxHTPhyMode.field.MODE = MODE_HTGREENFIELD; - } - else - { - pEntry->MaxHTPhyMode.field.MODE = MODE_HTMIX; - pAd->MacTab.fAnyStationNonGF = TRUE; - pAd->CommonCfg.AddHTInfo.AddHtInfo2.NonGfPresent = 1; - } - - if ((HtCapability.HtCapInfo.ChannelWidth) && (pAd->CommonCfg.DesiredHtPhy.ChannelWidth)) - { - pEntry->MaxHTPhyMode.field.BW= BW_40; - pEntry->MaxHTPhyMode.field.ShortGI = ((pAd->CommonCfg.DesiredHtPhy.ShortGIfor40)&(HtCapability.HtCapInfo.ShortGIfor40)); - } - else - { - pEntry->MaxHTPhyMode.field.BW = BW_20; - pEntry->MaxHTPhyMode.field.ShortGI = ((pAd->CommonCfg.DesiredHtPhy.ShortGIfor20)&(HtCapability.HtCapInfo.ShortGIfor20)); - pAd->MacTab.fAnyStation20Only = TRUE; - } - - // find max fixed rate - for (ii=15; ii>=0; ii--) - { - j = ii/8; - bitmask = (1<<(ii-(j*8))); - if ( (pAd->StaCfg.DesiredHtPhyInfo.MCSSet[j]&bitmask) && (HtCapability.MCSSet[j]&bitmask)) - { - pEntry->MaxHTPhyMode.field.MCS = ii; - break; - } - if (ii==0) - break; - } - - if (pAd->StaCfg.DesiredTransmitSetting.field.MCS != MCS_AUTO) - { - printk("@@@ pAd->CommonCfg.RegTransmitSetting.field.MCS = %d\n", - pAd->StaCfg.DesiredTransmitSetting.field.MCS); - if (pAd->StaCfg.DesiredTransmitSetting.field.MCS == 32) - { - // Fix MCS as HT Duplicated Mode - pEntry->MaxHTPhyMode.field.BW = 1; - pEntry->MaxHTPhyMode.field.MODE = MODE_HTMIX; - pEntry->MaxHTPhyMode.field.STBC = 0; - pEntry->MaxHTPhyMode.field.ShortGI = 0; - pEntry->MaxHTPhyMode.field.MCS = 32; - } - else if (pEntry->MaxHTPhyMode.field.MCS > pAd->StaCfg.HTPhyMode.field.MCS) - { - // STA supports fixed MCS - pEntry->MaxHTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; - } - } - - pEntry->MaxHTPhyMode.field.STBC = (HtCapability.HtCapInfo.RxSTBC & (pAd->CommonCfg.DesiredHtPhy.TxSTBC)); - pEntry->MpduDensity = HtCapability.HtCapParm.MpduDensity; - pEntry->MaxRAmpduFactor = HtCapability.HtCapParm.MaxRAmpduFactor; - pEntry->MmpsMode = (UCHAR)HtCapability.HtCapInfo.MimoPs; - pEntry->AMsduSize = (UCHAR)HtCapability.HtCapInfo.AMsduSize; - pEntry->HTPhyMode.word = pEntry->MaxHTPhyMode.word; - - if (HtCapability.HtCapInfo.ShortGIfor20) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_SGI20_CAPABLE); - if (HtCapability.HtCapInfo.ShortGIfor40) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_SGI40_CAPABLE); - if (HtCapability.HtCapInfo.TxSTBC) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_TxSTBC_CAPABLE); - if (HtCapability.HtCapInfo.RxSTBC) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_RxSTBC_CAPABLE); - if (HtCapability.ExtHtCapInfo.PlusHTC) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_HTC_CAPABLE); - if (pAd->CommonCfg.bRdg && HtCapability.ExtHtCapInfo.RDGSupport) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_RDG_CAPABLE); - if (HtCapability.ExtHtCapInfo.MCSFeedback == 0x03) - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_MCSFEEDBACK_CAPABLE); - - NdisMoveMemory(&pEntry->HTCapability, &HtCapability, sizeof(HT_CAPABILITY_IE)); - } -#endif // DOT11_N_SUPPORT // - - pEntry->HTPhyMode.word = pEntry->MaxHTPhyMode.word; - pEntry->CurrTxRate = pEntry->MaxSupportedRate; - CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_WMM_CAPABLE); - - if (pAd->StaCfg.bAutoTxRateSwitch == TRUE) - { - PUCHAR pTable; - UCHAR TableSize = 0; - - MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize, &pEntry->CurrTxRateIndex); - pEntry->bAutoTxRateSwitch = TRUE; - } - else - { - pEntry->HTPhyMode.field.MODE = pAd->StaCfg.HTPhyMode.field.MODE; - pEntry->HTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; - pEntry->bAutoTxRateSwitch = FALSE; - - RTMPUpdateLegacyTxSetting((UCHAR)pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode, pEntry); - } - pEntry->RateLen = SupportedRatesLen; - - if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - { - // If support WPA or WPA2, start STAKey hand shake, - // If failed hand shake, just tear down peer DLS - if (RTMPSendSTAKeyRequest(pAd, pAd->StaCfg.DLSEntry[i].MacAddr) != NDIS_STATUS_SUCCESS) - { - MLME_DLS_REQ_STRUCT MlmeDlsReq; - USHORT reason = REASON_QOS_CIPHER_NOT_SUPPORT; - - DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); - MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_TEAR_DOWN, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - pAd->StaCfg.DLSEntry[i].Valid = FALSE; - DBGPRINT(RT_DEBUG_ERROR,("DLS - PeerDlsRspAction failed when call RTMPSendSTAKeyRequest \n")); - } - else - { - pAd->StaCfg.DLSEntry[i].Status = DLS_WAIT_KEY; - DBGPRINT(RT_DEBUG_TRACE,("DLS - waiting for STAKey handshake procedure\n")); - } - } - else - { - RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); - pAd->StaCfg.DLSEntry[i].Status = DLS_FINISH; - DBGPRINT(RT_DEBUG_TRACE,("DLS - PeerDlsRspAction() from %02x:%02x:%02x:%02x:%02x:%02x Succeed with WEP or no security\n", SA[0], SA[1], SA[2], SA[3], SA[4], SA[5])); - } - pAd->StaCfg.DLSEntry[i].Sequence = 0; - if (HtCapabilityLen != 0) - pAd->StaCfg.DLSEntry[i].bHTCap = TRUE; - else - pAd->StaCfg.DLSEntry[i].bHTCap = FALSE; - } - else - { - // DLS setup procedure failed. - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - pAd->StaCfg.DLSEntry[i].Valid = FALSE; - RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); - DBGPRINT(RT_DEBUG_ERROR,("DLS - PeerDlsRspAction failed with StatusCode=%d \n", StatusCode)); - } - } - } - } -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID MlmeDlsTearDownAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - PUCHAR pOutBuffer = NULL; - NDIS_STATUS NStatus; - ULONG FrameLen = 0; - UCHAR Category = CATEGORY_DLS; - UCHAR Action = ACTION_DLS_TEARDOWN; - USHORT ReasonCode = REASON_QOS_UNSPECIFY; - HEADER_802_11 DlsTearDownHdr; - PRT_802_11_DLS pDLS; - BOOLEAN TimerCancelled; - UCHAR i; - - if(!MlmeDlsReqSanity(pAd, Elem->Msg, Elem->MsgLen, &pDLS, &ReasonCode)) - return; - - DBGPRINT(RT_DEBUG_TRACE,("DLS - MlmeDlsTearDownAction() with ReasonCode=%d \n", ReasonCode)); - - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory - if (NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_ERROR,("DLS - MlmeDlsTearDownAction() allocate memory failed \n")); - return; - } - - ActHeaderInit(pAd, &DlsTearDownHdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pAd->CommonCfg.Bssid); - - // Build basic frame first - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(HEADER_802_11), &DlsTearDownHdr, - 1, &Category, - 1, &Action, - 6, &pDLS->MacAddr, - 6, pAd->CurrentAddress, - 2, &ReasonCode, - END_OF_ARGS); - - MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); - RTMPCancelTimer(&pDLS->Timer, &TimerCancelled); - - // Remove key in local dls table entry - for (i = 0; i < MAX_NUM_OF_INIT_DLS_ENTRY; i++) - { - if (MAC_ADDR_EQUAL(pDLS->MacAddr, pAd->StaCfg.DLSEntry[i].MacAddr)) - { - MacTableDeleteDlsEntry(pAd, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID, pAd->StaCfg.DLSEntry[i].MacAddr); - } - } - - // clear peer dls table entry - for (i = MAX_NUM_OF_INIT_DLS_ENTRY; i < MAX_NUM_OF_DLS_ENTRY; i++) - { - if (MAC_ADDR_EQUAL(pDLS->MacAddr, pAd->StaCfg.DLSEntry[i].MacAddr)) - { - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - pAd->StaCfg.DLSEntry[i].Valid = FALSE; - RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); - MacTableDeleteDlsEntry(pAd, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID, pAd->StaCfg.DLSEntry[i].MacAddr); - } - } -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID PeerDlsTearDownAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - UCHAR DA[MAC_ADDR_LEN], SA[MAC_ADDR_LEN]; - USHORT ReasonCode; - UINT i; - BOOLEAN TimerCancelled; - - if (!pAd->CommonCfg.bDLSCapable) - return; - - if (!INFRA_ON(pAd)) - return; - - if (!PeerDlsTearDownSanity(pAd, Elem->Msg, Elem->MsgLen, DA, SA, &ReasonCode)) - return; - - DBGPRINT(RT_DEBUG_TRACE,("DLS - PeerDlsTearDownAction() from %02x:%02x:%02x:%02x:%02x:%02x with ReasonCode=%d\n", SA[0], SA[1], SA[2], SA[3], SA[4], SA[5], ReasonCode)); - - // clear local dls table entry - for (i=0; iStaCfg.DLSEntry[i].Valid && MAC_ADDR_EQUAL(SA, pAd->StaCfg.DLSEntry[i].MacAddr)) - { - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - pAd->StaCfg.DLSEntry[i].Valid = FALSE; - RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); - //AsicDelWcidTab(pAd, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID); - //AsicRemovePairwiseKeyEntry(pAd, BSS0, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID); - MacTableDeleteDlsEntry(pAd, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID, pAd->StaCfg.DLSEntry[i].MacAddr); - } - } - - // clear peer dls table entry - for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid && MAC_ADDR_EQUAL(SA, pAd->StaCfg.DLSEntry[i].MacAddr)) - { - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - pAd->StaCfg.DLSEntry[i].Valid = FALSE; - RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); - //AsicDelWcidTab(pAd, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID); - //AsicRemovePairwiseKeyEntry(pAd, BSS0, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID); - MacTableDeleteDlsEntry(pAd, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID, pAd->StaCfg.DLSEntry[i].MacAddr); - } - } -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID RTMPCheckDLSTimeOut( - IN PRTMP_ADAPTER pAd) -{ - ULONG i; - MLME_DLS_REQ_STRUCT MlmeDlsReq; - USHORT reason = REASON_QOS_UNSPECIFY; - - if (! pAd->CommonCfg.bDLSCapable) - return; - - if (! INFRA_ON(pAd)) - return; - - // If timeout value is equaled to zero, it means always not be timeout. - - // update local dls table entry - for (i=0; iStaCfg.DLSEntry[i].Valid) && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) - && (pAd->StaCfg.DLSEntry[i].TimeOut != 0)) - { - pAd->StaCfg.DLSEntry[i].CountDownTimer --; - - if (pAd->StaCfg.DLSEntry[i].CountDownTimer == 0) - { - reason = REASON_QOS_REQUEST_TIMEOUT; - pAd->StaCfg.DLSEntry[i].Valid = FALSE; - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); - MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_TEAR_DOWN, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); - } - } - } - - // update peer dls table entry - for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid) && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) - && (pAd->StaCfg.DLSEntry[i].TimeOut != 0)) - { - pAd->StaCfg.DLSEntry[i].CountDownTimer --; - - if (pAd->StaCfg.DLSEntry[i].CountDownTimer == 0) - { - reason = REASON_QOS_REQUEST_TIMEOUT; - pAd->StaCfg.DLSEntry[i].Valid = FALSE; - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); - MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_TEAR_DOWN, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); - } - } - } -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -BOOLEAN RTMPRcvFrameDLSCheck( - IN PRTMP_ADAPTER pAd, - IN PHEADER_802_11 pHeader, - IN ULONG Len, - IN PRT28XX_RXD_STRUC pRxD) -{ - ULONG i; - BOOLEAN bFindEntry = FALSE; - BOOLEAN bSTAKeyFrame = FALSE; - PEAPOL_PACKET pEap; - PUCHAR pProto, pAddr = NULL; - PUCHAR pSTAKey = NULL; - UCHAR ZeroReplay[LEN_KEY_DESC_REPLAY]; - UCHAR Mic[16], OldMic[16]; - UCHAR digest[80]; - UCHAR DlsPTK[80]; - UCHAR temp[64]; - BOOLEAN TimerCancelled; - CIPHER_KEY PairwiseKey; - - - if (! pAd->CommonCfg.bDLSCapable) - return bSTAKeyFrame; - - if (! INFRA_ON(pAd)) - return bSTAKeyFrame; - - if (! (pHeader->FC.SubType & 0x08)) - return bSTAKeyFrame; - - if (Len < LENGTH_802_11 + 6 + 2 + 2) - return bSTAKeyFrame; - - pProto = (PUCHAR)pHeader + LENGTH_802_11 + 2 + 6; // QOS Control field , 0xAA 0xAA 0xAA 0x00 0x00 0x00 - pAddr = pHeader->Addr2; - - // L2PAD bit on will pad 2 bytes at LLC - if (pRxD->L2PAD) - { - pProto += 2; - } - - if (RTMPEqualMemory(EAPOL, pProto, 2) && (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA)) - { - pEap = (PEAPOL_PACKET) (pProto + 2); - - DBGPRINT(RT_DEBUG_TRACE,("DLS - Sniff Len=%ld, DataLen=%d, KeyMic=%d, Install=%d, KeyAck=%d, Secure=%d, EKD_DL=%d, Error=%d, Request=%d\n", Len, - (LENGTH_802_11 + 6 + 2 + 2 + sizeof(EAPOL_PACKET) - MAX_LEN_OF_RSNIE + 16), - pEap->KeyDesc.KeyInfo.KeyMic, - pEap->KeyDesc.KeyInfo.Install, - pEap->KeyDesc.KeyInfo.KeyAck, - pEap->KeyDesc.KeyInfo.Secure, - pEap->KeyDesc.KeyInfo.EKD_DL, - pEap->KeyDesc.KeyInfo.Error, - pEap->KeyDesc.KeyInfo.Request)); - - if ((Len >= (LENGTH_802_11 + 6 + 2 + 2 + sizeof(EAPOL_PACKET) - MAX_LEN_OF_RSNIE + 16)) && pEap->KeyDesc.KeyInfo.KeyMic - && pEap->KeyDesc.KeyInfo.Install && pEap->KeyDesc.KeyInfo.KeyAck && pEap->KeyDesc.KeyInfo.Secure - && pEap->KeyDesc.KeyInfo.EKD_DL && !pEap->KeyDesc.KeyInfo.Error && !pEap->KeyDesc.KeyInfo.Request) - { - // First validate replay counter, only accept message with larger replay counter - // Let equal pass, some AP start with all zero replay counter - NdisZeroMemory(ZeroReplay, LEN_KEY_DESC_REPLAY); - if ((RTMPCompareMemory(pEap->KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY) != 1) && - (RTMPCompareMemory(pEap->KeyDesc.ReplayCounter, ZeroReplay, LEN_KEY_DESC_REPLAY) != 0)) - return bSTAKeyFrame; - - //RTMPMoveMemory(pAd->StaCfg.ReplayCounter, pEap->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); - RTMPMoveMemory(pAd->StaCfg.DlsReplayCounter, pEap->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); - DBGPRINT(RT_DEBUG_TRACE,("DLS - Sniff replay counter (%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x) Len=%ld, KeyDataLen=%d\n", - pAd->StaCfg.ReplayCounter[0], pAd->StaCfg.ReplayCounter[1], pAd->StaCfg.ReplayCounter[2], - pAd->StaCfg.ReplayCounter[3], pAd->StaCfg.ReplayCounter[4], pAd->StaCfg.ReplayCounter[5], - pAd->StaCfg.ReplayCounter[6], pAd->StaCfg.ReplayCounter[7], Len, pEap->KeyDesc.KeyData[1])); - - // put these code segment to get the replay counter - if (pAd->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED) - return bSTAKeyFrame; - - // Check MIC value - // Save the MIC and replace with zero - // use proprietary PTK - NdisZeroMemory(temp, 64); - NdisMoveMemory(temp, "IEEE802.11 WIRELESS ACCESS POINT", 32); - WpaCountPTK(pAd, temp, temp, pAd->CommonCfg.Bssid, temp, pAd->CurrentAddress, DlsPTK, LEN_PTK); - - NdisMoveMemory(OldMic, pEap->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); - NdisZeroMemory(pEap->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); - if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) - { - // AES - HMAC_SHA1((PUCHAR) pEap, pEap->Body_Len[1] + 4, DlsPTK, LEN_EAP_MICK, digest); - NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); - } - else - { - hmac_md5(DlsPTK, LEN_EAP_MICK, (PUCHAR) pEap, pEap->Body_Len[1] + 4, Mic); - } - - if (!NdisEqualMemory(OldMic, Mic, LEN_KEY_DESC_MIC)) - { - DBGPRINT(RT_DEBUG_ERROR, ("MIC Different in Msg1 of STAKey handshake! \n")); - return bSTAKeyFrame; - } - else - DBGPRINT(RT_DEBUG_TRACE, ("MIC VALID in Msg1 of STAKey handshake! \n")); -#if 1 - if ((pEap->KeyDesc.KeyData[0] == 0xDD) && (pEap->KeyDesc.KeyData[2] == 0x00) && (pEap->KeyDesc.KeyData[3] == 0x0C) - && (pEap->KeyDesc.KeyData[4] == 0x43) && (pEap->KeyDesc.KeyData[5] == 0x02)) - { - pAddr = pEap->KeyDesc.KeyData + 8; // Tpe(1), Len(1), OUI(3), DataType(1), Reserved(2) - pSTAKey = pEap->KeyDesc.KeyData + 14; // Tpe(1), Len(1), OUI(3), DataType(1), Reserved(2), STAKey_Mac_Addr(6) - - DBGPRINT(RT_DEBUG_TRACE,("DLS - Receive STAKey Message-1 from %02x:%02x:%02x:%02x:%02x:%02x Len=%ld, KeyDataLen=%d\n", - pAddr[0], pAddr[1], pAddr[2], pAddr[3], pAddr[4], pAddr[5], Len, pEap->KeyDesc.KeyData[1])); - - bSTAKeyFrame = TRUE; - } -#else - if ((pEap->KeyDesc.KeyData[0] == 0xDD) && (pEap->KeyDesc.KeyData[2] == 0x00) && (pEap->KeyDesc.KeyData[3] == 0x0F) - && (pEap->KeyDesc.KeyData[4] == 0xAC) && (pEap->KeyDesc.KeyData[5] == 0x02)) - { - pAddr = pEap->KeyDesc.KeyData + 8; // Tpe(1), Len(1), OUI(3), DataType(1), Reserved(2) - pSTAKey = pEap->KeyDesc.KeyData + 14; // Tpe(1), Len(1), OUI(3), DataType(1), Reserved(2), STAKey_Mac_Addr(6) - - DBGPRINT(RT_DEBUG_TRACE,("DLS - Receive STAKey Message-1 from %02x:%02x:%02x:%02x:%02x:%02x Len=%d, KeyDataLen=%d\n", - pAddr[0], pAddr[1], pAddr[2], pAddr[3], pAddr[4], pAddr[5], Len, pEap->KeyDesc.KeyData[1])); - - bSTAKeyFrame = TRUE; - } -#endif - - } - else if (Len >= (LENGTH_802_11 + 6 + 2 + 2 + sizeof(EAPOL_PACKET) - MAX_LEN_OF_RSNIE)) - { - RTMPMoveMemory(pAd->StaCfg.DlsReplayCounter, pEap->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); - DBGPRINT(RT_DEBUG_TRACE,("DLS - Sniff replay counter 2(%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x) Len=%ld, KeyDataLen=%d\n", - pAd->StaCfg.ReplayCounter[0], pAd->StaCfg.ReplayCounter[1], pAd->StaCfg.ReplayCounter[2], - pAd->StaCfg.ReplayCounter[3], pAd->StaCfg.ReplayCounter[4], pAd->StaCfg.ReplayCounter[5], - pAd->StaCfg.ReplayCounter[6], pAd->StaCfg.ReplayCounter[7], Len, pEap->KeyDesc.KeyData[1])); - - } - } - - // If timeout value is equaled to zero, it means always not be timeout. - // update local dls table entry - for (i= 0; i < MAX_NUM_OF_INIT_DLS_ENTRY; i++) - { - if (pAd->StaCfg.DLSEntry[i].Valid && MAC_ADDR_EQUAL(pAddr, pAd->StaCfg.DLSEntry[i].MacAddr)) - { - if (bSTAKeyFrame) - { - PMAC_TABLE_ENTRY pEntry; - - // STAKey frame, add pairwise key table - pAd->StaCfg.DLSEntry[i].Status = DLS_FINISH; - RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); - - PairwiseKey.KeyLen = LEN_TKIP_EK; - NdisMoveMemory(PairwiseKey.Key, &pSTAKey[0], LEN_TKIP_EK); - NdisMoveMemory(PairwiseKey.TxMic, &pSTAKey[16], LEN_TKIP_RXMICK); - NdisMoveMemory(PairwiseKey.RxMic, &pSTAKey[24], LEN_TKIP_TXMICK); - - PairwiseKey.CipherAlg = pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg; - - pEntry = DlsEntryTableLookup(pAd, pAd->StaCfg.DLSEntry[i].MacAddr, TRUE); - //AsicAddKeyEntry(pAd, (USHORT)(i + 2), BSS0, 0, &PairwiseKey, TRUE, TRUE); // reserve 0 for multicast, 1 for unicast - //AsicUpdateRxWCIDTable(pAd, (USHORT)(i + 2), pAddr); - // Add Pair-wise key to Asic -#ifdef RT2870 -//Benson modified for USB interface, avoid in interrupt when write key, 20080724 --> - { - RT_ADD_PAIRWISE_KEY_ENTRY KeyInfo; - COPY_MAC_ADDR(KeyInfo.MacAddr,pAd->StaCfg.DLSEntry[i].MacAddr); - KeyInfo.MacTabMatchWCID=pAd->StaCfg.DLSEntry[i].MacTabMatchWCID; - NdisMoveMemory(&KeyInfo.CipherKey, &PairwiseKey,sizeof(CIPHER_KEY)); - RTUSBEnqueueInternalCmd(pAd, RT_CMD_SET_KEY_TABLE, &KeyInfo, sizeof(RT_ADD_PAIRWISE_KEY_ENTRY)); - } - { - PMAC_TABLE_ENTRY pDLSEntry; - pDLSEntry = DlsEntryTableLookup(pAd, pAd->StaCfg.DLSEntry[i].MacAddr, TRUE); - pDLSEntry->PairwiseKey.CipherAlg=PairwiseKey.CipherAlg; - RTUSBEnqueueInternalCmd(pAd, RT_CMD_SET_RX_WCID_TABLE, pDLSEntry, sizeof(MAC_TABLE_ENTRY)); - } -//Benson modified for USB interface, avoid in interrupt when write key, 20080724 <-- -#endif // RT2870 // - NdisMoveMemory(&pEntry->PairwiseKey, &PairwiseKey, sizeof(CIPHER_KEY)); - DBGPRINT(RT_DEBUG_TRACE,("DLS - Receive STAKey Message-1 (Peer STA MAC Address STAKey) \n")); - - RTMPSendSTAKeyHandShake(pAd, pAd->StaCfg.DLSEntry[i].MacAddr); - - DBGPRINT(RT_DEBUG_TRACE,("DLS - Finish STAKey handshake procedure (Initiator side)\n")); - } - else - { - // Data frame, update timeout value - if (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) - { - pAd->StaCfg.DLSEntry[i].CountDownTimer = pAd->StaCfg.DLSEntry[i].TimeOut; - //AsicUpdateRxWCIDTable(pAd, (USHORT)(i + 2), pAddr); - } - } - - bFindEntry = TRUE; - } - } - - // update peer dls table entry - for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid && MAC_ADDR_EQUAL(pAddr, pAd->StaCfg.DLSEntry[i].MacAddr)) - { - if (bSTAKeyFrame) - { - PMAC_TABLE_ENTRY pEntry = NULL; - - // STAKey frame, add pairwise key table, and send STAkey Msg-2 - pAd->StaCfg.DLSEntry[i].Status = DLS_FINISH; - RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); - - PairwiseKey.KeyLen = LEN_TKIP_EK; - NdisMoveMemory(PairwiseKey.Key, &pSTAKey[0], LEN_TKIP_EK); - NdisMoveMemory(PairwiseKey.TxMic, &pSTAKey[16], LEN_TKIP_RXMICK); - NdisMoveMemory(PairwiseKey.RxMic, &pSTAKey[24], LEN_TKIP_TXMICK); - - PairwiseKey.CipherAlg = pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg; - - pEntry = DlsEntryTableLookup(pAd, pAd->StaCfg.DLSEntry[i].MacAddr, TRUE); - //AsicAddKeyEntry(pAd, (USHORT)(i + 2), BSS0, 0, &PairwiseKey, TRUE, TRUE); // reserve 0 for multicast, 1 for unicast - //AsicUpdateRxWCIDTable(pAd, (USHORT)(i + 2), pAddr); - // Add Pair-wise key to Asic -#ifdef RT2870 -//Benson modified for USB interface, avoid in interrupt when write key, 20080724 --> - { - RT_ADD_PAIRWISE_KEY_ENTRY KeyInfo; - COPY_MAC_ADDR(KeyInfo.MacAddr,pAd->StaCfg.DLSEntry[i].MacAddr); - KeyInfo.MacTabMatchWCID=pAd->StaCfg.DLSEntry[i].MacTabMatchWCID; - NdisMoveMemory(&KeyInfo.CipherKey, &PairwiseKey,sizeof(CIPHER_KEY)); - RTUSBEnqueueInternalCmd(pAd, RT_CMD_SET_KEY_TABLE, &KeyInfo, sizeof(RT_ADD_PAIRWISE_KEY_ENTRY)); - } - { - PMAC_TABLE_ENTRY pDLSEntry; - pDLSEntry = DlsEntryTableLookup(pAd, pAd->StaCfg.DLSEntry[i].MacAddr, TRUE); - pDLSEntry->PairwiseKey.CipherAlg=PairwiseKey.CipherAlg; - RTUSBEnqueueInternalCmd(pAd, RT_CMD_SET_RX_WCID_TABLE, pDLSEntry, sizeof(MAC_TABLE_ENTRY)); - } -//Benson modified for USB interface, avoid in interrupt when write key, 20080724 <-- -#endif // RT2870 // - NdisMoveMemory(&pEntry->PairwiseKey, &PairwiseKey, sizeof(CIPHER_KEY)); - DBGPRINT(RT_DEBUG_TRACE,("DLS - Receive STAKey Message-1 (Initiator STA MAC Address STAKey)\n")); - - // If support WPA or WPA2, start STAKey hand shake, - // If failed hand shake, just tear down peer DLS - if (RTMPSendSTAKeyHandShake(pAd, pAddr) != NDIS_STATUS_SUCCESS) - { - MLME_DLS_REQ_STRUCT MlmeDlsReq; - USHORT reason = REASON_QOS_CIPHER_NOT_SUPPORT; - - pAd->StaCfg.DLSEntry[i].Valid = FALSE; - pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; - DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); - MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_TEAR_DOWN, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); - } - else - { - DBGPRINT(RT_DEBUG_TRACE,("DLS - Finish STAKey handshake procedure (Peer side)\n")); - } - } - else - { - // Data frame, update timeout value - if (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) - { - pAd->StaCfg.DLSEntry[i].CountDownTimer = pAd->StaCfg.DLSEntry[i].TimeOut; - } - } - - bFindEntry = TRUE; - } - } - - - return bSTAKeyFrame; -} - -/* - ======================================================================== - - Routine Description: - Check if the frame can be sent through DLS direct link interface - - Arguments: - pAd Pointer to adapter - - Return Value: - DLS entry index - - Note: - - ======================================================================== -*/ -INT RTMPCheckDLSFrame( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDA) -{ - INT rval = -1; - INT i; - - if (!pAd->CommonCfg.bDLSCapable) - return rval; - - if (!INFRA_ON(pAd)) - return rval; - - do{ - // check local dls table entry - for (i=0; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) && - MAC_ADDR_EQUAL(pDA, pAd->StaCfg.DLSEntry[i].MacAddr)) - { - rval = i; - break; - } - } - - // check peer dls table entry - for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) && - MAC_ADDR_EQUAL(pDA, pAd->StaCfg.DLSEntry[i].MacAddr)) - { - rval = i; - break; - } - } - } while (FALSE); - - return rval; -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID RTMPSendDLSTearDownFrame( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDA) -{ - PUCHAR pOutBuffer = NULL; - NDIS_STATUS NStatus; - HEADER_802_11 DlsTearDownHdr; - ULONG FrameLen = 0; - USHORT Reason = REASON_QOS_QSTA_LEAVING_QBSS; - UCHAR Category = CATEGORY_DLS; - UCHAR Action = ACTION_DLS_TEARDOWN; - UCHAR i = 0; - - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS) || - RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) - return; - - DBGPRINT(RT_DEBUG_TRACE, ("Send DLS TearDown Frame \n")); - - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory - if (NStatus != NDIS_STATUS_SUCCESS) - { - DBGPRINT(RT_DEBUG_ERROR,("ASSOC - RTMPSendDLSTearDownFrame() allocate memory failed \n")); - return; - } - - ActHeaderInit(pAd, &DlsTearDownHdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pAd->CommonCfg.Bssid); - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(HEADER_802_11), &DlsTearDownHdr, - 1, &Category, - 1, &Action, - 6, pDA, - 6, pAd->CurrentAddress, - 2, &Reason, - END_OF_ARGS); - - MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); - - // Remove key in local dls table entry - for (i = 0; i < MAX_NUM_OF_INIT_DLS_ENTRY; i++) - { - if (pAd->StaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) - && MAC_ADDR_EQUAL(pDA, pAd->StaCfg.DLSEntry[i].MacAddr)) - { - MacTableDeleteDlsEntry(pAd, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID, pAd->StaCfg.DLSEntry[i].MacAddr); - } - } - - // Remove key in peer dls table entry - for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) - && MAC_ADDR_EQUAL(pDA, pAd->StaCfg.DLSEntry[i].MacAddr)) - { - MacTableDeleteDlsEntry(pAd, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID, pAd->StaCfg.DLSEntry[i].MacAddr); - } - } - - DBGPRINT(RT_DEBUG_TRACE, ("Send DLS TearDown Frame and remove key in (i=%d) \n", i)); -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -NDIS_STATUS RTMPSendSTAKeyRequest( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDA) -{ - UCHAR Header802_3[14]; - NDIS_STATUS NStatus; - ULONG FrameLen = 0; - EAPOL_PACKET Packet; - UCHAR Mic[16]; - UCHAR digest[80]; - PUCHAR pOutBuffer = NULL; - PNDIS_PACKET pNdisPacket; - UCHAR temp[64]; - UCHAR DlsPTK[80]; - - DBGPRINT(RT_DEBUG_TRACE,("DLS - RTMPSendSTAKeyRequest() to %02x:%02x:%02x:%02x:%02x:%02x\n", pDA[0], pDA[1], pDA[2], pDA[3], pDA[4], pDA[5])); - - pAd->Sequence ++; - MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL); - - // Zero message body - NdisZeroMemory(&Packet, sizeof(Packet)); - Packet.ProVer = EAPOL_VER; - Packet.ProType = EAPOLKey; - Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE + 6 + MAC_ADDR_LEN; // data field contain KDE andPeer MAC address - - // STAKey Message is as EAPOL-Key(1,1,0,0,G/0,0,0, MIC, 0,Peer MAC KDE) - if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) - { - Packet.KeyDesc.Type = WPA1_KEY_DESC; - } - else if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)) - { - Packet.KeyDesc.Type = WPA2_KEY_DESC; - } - - // Key descriptor version - Packet.KeyDesc.KeyInfo.KeyDescVer = - (((pAd->StaCfg.PairCipher == Ndis802_11Encryption3Enabled) || (pAd->StaCfg.GroupCipher == Ndis802_11Encryption3Enabled)) ? (DESC_TYPE_AES) : (DESC_TYPE_TKIP)); - - Packet.KeyDesc.KeyInfo.KeyMic = 1; - Packet.KeyDesc.KeyInfo.Secure = 1; - Packet.KeyDesc.KeyInfo.Request = 1; - - Packet.KeyDesc.KeyDataLen[1] = 12; - - // use our own OUI to distinguish proprietary with standard. - Packet.KeyDesc.KeyData[0] = 0xDD; - Packet.KeyDesc.KeyData[1] = 0x0A; - Packet.KeyDesc.KeyData[2] = 0x00; - Packet.KeyDesc.KeyData[3] = 0x0C; - Packet.KeyDesc.KeyData[4] = 0x43; - Packet.KeyDesc.KeyData[5] = 0x03; - NdisMoveMemory(&Packet.KeyDesc.KeyData[6], pDA, MAC_ADDR_LEN); - - NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pAd->StaCfg.DlsReplayCounter, LEN_KEY_DESC_REPLAY); - - // Allocate buffer for transmitting message - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); - if (NStatus != NDIS_STATUS_SUCCESS) - return NStatus; - - // Prepare EAPOL frame for MIC calculation - // Be careful, only EAPOL frame is counted for MIC calculation - MakeOutgoingFrame(pOutBuffer, &FrameLen, - Packet.Body_Len[1] + 4, &Packet, - END_OF_ARGS); - - // use proprietary PTK - NdisZeroMemory(temp, 64); - NdisMoveMemory(temp, "IEEE802.11 WIRELESS ACCESS POINT", 32); - WpaCountPTK(pAd, temp, temp, pAd->CommonCfg.Bssid, temp, pAd->CurrentAddress, DlsPTK, LEN_PTK); - - // calculate MIC - if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) - { - // AES - NdisZeroMemory(digest, sizeof(digest)); - HMAC_SHA1(pOutBuffer, FrameLen, DlsPTK, LEN_EAP_MICK, digest); - NdisMoveMemory(Packet.KeyDesc.KeyMic, digest, LEN_KEY_DESC_MIC); - } - else - { - NdisZeroMemory(Mic, sizeof(Mic)); - hmac_md5(DlsPTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic); - NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC); - } - - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(Header802_3), Header802_3, - Packet.Body_Len[1] + 4, &Packet, - END_OF_ARGS); - - NStatus = RTMPAllocateNdisPacket(pAd, &pNdisPacket, NULL, 0, pOutBuffer, FrameLen); - if (NStatus == NDIS_STATUS_SUCCESS) - { - RTMP_SET_PACKET_WCID(pNdisPacket, BSSID_WCID); - STASendPacket(pAd, pNdisPacket); - RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, MAX_TX_PROCESS); - } - - MlmeFreeMemory(pAd, pOutBuffer); - - DBGPRINT(RT_DEBUG_TRACE, ("RTMPSendSTAKeyRequest- Send STAKey request (NStatus=%x, FrameLen=%ld)\n", NStatus, FrameLen)); - - return NStatus; -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -NDIS_STATUS RTMPSendSTAKeyHandShake( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDA) -{ - UCHAR Header802_3[14]; - NDIS_STATUS NStatus; - ULONG FrameLen = 0; - EAPOL_PACKET Packet; - UCHAR Mic[16]; - UCHAR digest[80]; - PUCHAR pOutBuffer = NULL; - PNDIS_PACKET pNdisPacket; - UCHAR temp[64]; - UCHAR DlsPTK[80]; // Due to dirver can not get PTK, use proprietary PTK - - DBGPRINT(RT_DEBUG_TRACE,("DLS - RTMPSendSTAKeyHandShake() to %02x:%02x:%02x:%02x:%02x:%02x\n", pDA[0], pDA[1], pDA[2], pDA[3], pDA[4], pDA[5])); - - pAd->Sequence ++; - MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL); - - // Zero message body - NdisZeroMemory(&Packet, sizeof(Packet)); - Packet.ProVer = EAPOL_VER; - Packet.ProType = EAPOLKey; - Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE + 6 + MAC_ADDR_LEN; // data field contain KDE and Peer MAC address - - // STAKey Message is as EAPOL-Key(1,1,0,0,G/0,0,0, MIC, 0,Peer MAC KDE) - if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) - { - Packet.KeyDesc.Type = WPA1_KEY_DESC; - } - else if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)) - { - Packet.KeyDesc.Type = WPA2_KEY_DESC; - } - - // Key descriptor version - Packet.KeyDesc.KeyInfo.KeyDescVer = - (((pAd->StaCfg.PairCipher == Ndis802_11Encryption3Enabled) || (pAd->StaCfg.GroupCipher == Ndis802_11Encryption3Enabled)) ? (DESC_TYPE_AES) : (DESC_TYPE_TKIP)); - - Packet.KeyDesc.KeyInfo.KeyMic = 1; - Packet.KeyDesc.KeyInfo.Secure = 1; - - Packet.KeyDesc.KeyDataLen[1] = 12; - - // use our own OUI to distinguish proprietary with standard. - Packet.KeyDesc.KeyData[0] = 0xDD; - Packet.KeyDesc.KeyData[1] = 0x0A; - Packet.KeyDesc.KeyData[2] = 0x00; - Packet.KeyDesc.KeyData[3] = 0x0C; - Packet.KeyDesc.KeyData[4] = 0x43; - Packet.KeyDesc.KeyData[5] = 0x03; - NdisMoveMemory(&Packet.KeyDesc.KeyData[6], pDA, MAC_ADDR_LEN); - - NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pAd->StaCfg.DlsReplayCounter, LEN_KEY_DESC_REPLAY); - - // Allocate buffer for transmitting message - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); - if (NStatus != NDIS_STATUS_SUCCESS) - return NStatus; - - // Prepare EAPOL frame for MIC calculation - // Be careful, only EAPOL frame is counted for MIC calculation - MakeOutgoingFrame(pOutBuffer, &FrameLen, - Packet.Body_Len[1] + 4, &Packet, - END_OF_ARGS); - - // use proprietary PTK - NdisZeroMemory(temp, 64); - NdisMoveMemory(temp, "IEEE802.11 WIRELESS ACCESS POINT", 32); - WpaCountPTK(pAd, temp, temp, pAd->CommonCfg.Bssid, temp, pAd->CurrentAddress, DlsPTK, LEN_PTK); - - // calculate MIC - if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) - { - // AES - NdisZeroMemory(digest, sizeof(digest)); - HMAC_SHA1(pOutBuffer, FrameLen, DlsPTK, LEN_EAP_MICK, digest); - NdisMoveMemory(Packet.KeyDesc.KeyMic, digest, LEN_KEY_DESC_MIC); - } - else - { - NdisZeroMemory(Mic, sizeof(Mic)); - hmac_md5(DlsPTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic); - NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC); - } - - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(Header802_3), Header802_3, - Packet.Body_Len[1] + 4, &Packet, - END_OF_ARGS); - - NStatus = RTMPAllocateNdisPacket(pAd, &pNdisPacket, NULL, 0, pOutBuffer, FrameLen); - if (NStatus == NDIS_STATUS_SUCCESS) - { - RTMP_SET_PACKET_WCID(pNdisPacket, BSSID_WCID); - STASendPacket(pAd, pNdisPacket); - RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, MAX_TX_PROCESS); - } - - MlmeFreeMemory(pAd, pOutBuffer); - - DBGPRINT(RT_DEBUG_TRACE, ("RTMPSendSTAKeyHandShake- Send STAKey Message-2 (NStatus=%x, FrameLen=%ld)\n", NStatus, FrameLen)); - - return NStatus; -} - -VOID DlsTimeoutAction( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3) -{ - MLME_DLS_REQ_STRUCT MlmeDlsReq; - USHORT reason; - PRT_802_11_DLS pDLS = (PRT_802_11_DLS)FunctionContext; - PRTMP_ADAPTER pAd = pDLS->pAd; - - DBGPRINT(RT_DEBUG_TRACE, ("DlsTimeout - Tear down DLS links (%02x:%02x:%02x:%02x:%02x:%02x)\n", - pDLS->MacAddr[0], pDLS->MacAddr[1], pDLS->MacAddr[2], pDLS->MacAddr[3], pDLS->MacAddr[4], pDLS->MacAddr[5])); - - if ((pDLS) && (pDLS->Valid)) - { - reason = REASON_QOS_REQUEST_TIMEOUT; - pDLS->Valid = FALSE; - pDLS->Status = DLS_NONE; - DlsParmFill(pAd, &MlmeDlsReq, pDLS, reason); - MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_TEAR_DOWN, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); - RT28XX_MLME_HANDLER(pAd); - } -} - -/* -================================================================ -Description : because DLS and CLI share the same WCID table in ASIC. -Mesh entry also insert to pAd->MacTab.content[]. Such is marked as ValidAsDls = TRUE. -Also fills the pairwise key. -Because front MAX_AID_BA entries have direct mapping to BAEntry, which is only used as CLI. So we insert Dls -from index MAX_AID_BA. -================================================================ -*/ -MAC_TABLE_ENTRY *MacTableInsertDlsEntry( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pAddr, - IN UINT DlsEntryIdx) -{ - PMAC_TABLE_ENTRY pEntry = NULL; - - DBGPRINT(RT_DEBUG_TRACE, ("====> MacTableInsertDlsEntry\n")); - // if FULL, return - if (pAd->MacTab.Size >= MAX_LEN_OF_MAC_TABLE) - return NULL; - - do - { - if((pEntry = DlsEntryTableLookup(pAd, pAddr, TRUE)) != NULL) - break; - - // allocate one MAC entry - pEntry = MacTableInsertEntry(pAd, pAddr, DlsEntryIdx + MIN_NET_DEVICE_FOR_DLS, TRUE); - if (pEntry) - { - pAd->StaCfg.DLSEntry[DlsEntryIdx].MacTabMatchWCID = pEntry->Aid; - pEntry->MatchDlsEntryIdx = DlsEntryIdx; - pEntry->AuthMode = pAd->StaCfg.AuthMode; - pEntry->WepStatus = pAd->StaCfg.WepStatus; - - DBGPRINT(RT_DEBUG_TRACE, ("MacTableInsertDlsEntry - allocate entry #%d, Total= %d\n",pEntry->Aid, pAd->MacTab.Size)); - - // If legacy WEP is used, set pair-wise cipherAlg into WCID attribute table for this entry - if ((pEntry->ValidAsDls) && (pEntry->WepStatus == Ndis802_11WEPEnabled)) - { - UCHAR KeyIdx = 0; - UCHAR CipherAlg = 0; - - KeyIdx = pAd->StaCfg.DefaultKeyId; - - CipherAlg = pAd->SharedKey[BSS0][KeyIdx].CipherAlg; - - RTMPAddWcidAttributeEntry(pAd, - BSS0, - pAd->StaCfg.DefaultKeyId, - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, - pEntry); - } - - break; - } - } while(FALSE); - - DBGPRINT(RT_DEBUG_TRACE, ("<==== MacTableInsertDlsEntry\n")); - - return pEntry; -} - - -/* - ========================================================================== - Description: - Delete all Mesh Entry in pAd->MacTab - ========================================================================== - */ -BOOLEAN MacTableDeleteDlsEntry( - IN PRTMP_ADAPTER pAd, - IN USHORT wcid, - IN PUCHAR pAddr) -{ - DBGPRINT(RT_DEBUG_TRACE, ("====> MacTableDeleteDlsEntry\n")); - - if (!VALID_WCID(wcid)) - return FALSE; - - MacTableDeleteEntry(pAd, wcid, pAddr); - - DBGPRINT(RT_DEBUG_TRACE, ("<==== MacTableDeleteDlsEntry\n")); - - return TRUE; -} - -MAC_TABLE_ENTRY *DlsEntryTableLookup( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pAddr, - IN BOOLEAN bResetIdelCount) -{ - ULONG HashIdx; - MAC_TABLE_ENTRY *pEntry = NULL; - - RTMP_SEM_LOCK(&pAd->MacTabLock); - HashIdx = MAC_ADDR_HASH_INDEX(pAddr); - pEntry = pAd->MacTab.Hash[HashIdx]; - - while (pEntry) - { - if ((pEntry->ValidAsDls == TRUE) - && MAC_ADDR_EQUAL(pEntry->Addr, pAddr)) - { - if(bResetIdelCount) - pEntry->NoDataIdleCount = 0; - break; - } - else - pEntry = pEntry->pNext; - } - - RTMP_SEM_UNLOCK(&pAd->MacTabLock); - return pEntry; -} - -MAC_TABLE_ENTRY *DlsEntryTableLookupByWcid( - IN PRTMP_ADAPTER pAd, - IN UCHAR wcid, - IN PUCHAR pAddr, - IN BOOLEAN bResetIdelCount) -{ - ULONG DLsIndex; - PMAC_TABLE_ENTRY pCurEntry = NULL; - PMAC_TABLE_ENTRY pEntry = NULL; - - if (!VALID_WCID(wcid)) - return NULL; - - RTMP_SEM_LOCK(&pAd->MacTabLock); - - do - { - pCurEntry = &pAd->MacTab.Content[wcid]; - - DLsIndex = 0xff; - if ((pCurEntry) && (pCurEntry->ValidAsDls== TRUE)) - { - DLsIndex = pCurEntry->MatchDlsEntryIdx; - } - - if (DLsIndex == 0xff) - break; - - if (MAC_ADDR_EQUAL(pCurEntry->Addr, pAddr)) - { - if(bResetIdelCount) - pCurEntry->NoDataIdleCount = 0; - pEntry = pCurEntry; - break; - } - } while(FALSE); - - RTMP_SEM_UNLOCK(&pAd->MacTabLock); - - return pEntry; -} - -INT Set_DlsEntryInfo_Display_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - INT i; - - printk("\n%-19s%-8s\n", "MAC", "TIMEOUT\n"); - for (i=0; iStaCfg.DLSEntry[i].Valid) && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH)) - { - printk("%02x:%02x:%02x:%02x:%02x:%02x ", - pAd->StaCfg.DLSEntry[i].MacAddr[0], pAd->StaCfg.DLSEntry[i].MacAddr[1], pAd->StaCfg.DLSEntry[i].MacAddr[2], - pAd->StaCfg.DLSEntry[i].MacAddr[3], pAd->StaCfg.DLSEntry[i].MacAddr[4], pAd->StaCfg.DLSEntry[i].MacAddr[5]); - printk("%-8d\n", pAd->StaCfg.DLSEntry[i].TimeOut); - } - } - - return TRUE; -} - -INT Set_DlsAddEntry_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - UCHAR mac[MAC_ADDR_LEN]; - USHORT Timeout; - char *token, sepValue[] = ":", DASH = '-'; - INT i; - RT_802_11_DLS Dls; - - if(strlen(arg) < 19) //Mac address acceptable format 01:02:03:04:05:06 length 17 plus the "-" and timeout value in decimal format. - return FALSE; - - token = strchr(arg, DASH); - if ((token != NULL) && (strlen(token)>1)) - { - Timeout = simple_strtol((token+1), 0, 10); - - *token = '\0'; - for (i = 0, token = rstrtok(arg, &sepValue[0]); token; token = rstrtok(NULL, &sepValue[0]), i++) - { - if((strlen(token) != 2) || (!isxdigit(*token)) || (!isxdigit(*(token+1)))) - return FALSE; - AtoH(token, (PUCHAR)(&mac[i]), 1); - } - if(i != 6) - return FALSE; - - printk("\n%02x:%02x:%02x:%02x:%02x:%02x-%d", mac[0], mac[1], - mac[2], mac[3], mac[4], mac[5], (int)Timeout); - - NdisZeroMemory(&Dls, sizeof(RT_802_11_DLS)); - Dls.TimeOut = Timeout; - COPY_MAC_ADDR(Dls.MacAddr, mac); - Dls.Valid = 1; - - MlmeEnqueue(pAd, - MLME_CNTL_STATE_MACHINE, - RT_OID_802_11_SET_DLS_PARAM, - sizeof(RT_802_11_DLS), - &Dls); - - return TRUE; - } - - return FALSE; - -} - -INT Set_DlsTearDownEntry_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - UCHAR macAddr[MAC_ADDR_LEN]; - CHAR *value; - INT i; - RT_802_11_DLS Dls; - - if(strlen(arg) != 17) //Mac address acceptable format 01:02:03:04:05:06 length 17 - return FALSE; - - for (i=0, value = rstrtok(arg,":"); value; value = rstrtok(NULL,":")) - { - if((strlen(value) != 2) || (!isxdigit(*value)) || (!isxdigit(*(value+1))) ) - return FALSE; //Invalid - - AtoH(value, &macAddr[i++], 2); - } - - printk("\n%02x:%02x:%02x:%02x:%02x:%02x", macAddr[0], macAddr[1], - macAddr[2], macAddr[3], macAddr[4], macAddr[5]); - - NdisZeroMemory(&Dls, sizeof(RT_802_11_DLS)); - COPY_MAC_ADDR(Dls.MacAddr, macAddr); - Dls.Valid = 0; - - MlmeEnqueue(pAd, - MLME_CNTL_STATE_MACHINE, - RT_OID_802_11_SET_DLS_PARAM, - sizeof(RT_802_11_DLS), - &Dls); - - return TRUE; -} - diff --git a/drivers/staging/rt3070/sta/rtmp_data.c b/drivers/staging/rt3070/sta/rtmp_data.c index b0f259b35c74..bf091206f5cc 100644 --- a/drivers/staging/rt3070/sta/rtmp_data.c +++ b/drivers/staging/rt3070/sta/rtmp_data.c @@ -1,2637 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - rtmp_data.c - - Abstract: - Data path subroutines - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - John Aug/17/04 major modification for RT2561/2661 - Jan Lee Mar/17/06 major modification for RT2860 New Ring Design -*/ -#include "../rt_config.h" - - - -VOID STARxEAPOLFrameIndicate( - IN PRTMP_ADAPTER pAd, - IN MAC_TABLE_ENTRY *pEntry, - IN RX_BLK *pRxBlk, - IN UCHAR FromWhichBSSID) -{ - PRT28XX_RXD_STRUC pRxD = &(pRxBlk->RxD); - PRXWI_STRUC pRxWI = pRxBlk->pRxWI; - UCHAR *pTmpBuf; - - -#ifdef WPA_SUPPLICANT_SUPPORT - if (pAd->StaCfg.WpaSupplicantUP) - { - // All EAPoL frames have to pass to upper layer (ex. WPA_SUPPLICANT daemon) - // TBD : process fragmented EAPol frames - { - // In 802.1x mode, if the received frame is EAP-SUCCESS packet, turn on the PortSecured variable - if ( pAd->StaCfg.IEEE8021X == TRUE && - (EAP_CODE_SUCCESS == WpaCheckEapCode(pAd, pRxBlk->pData, pRxBlk->DataSize, LENGTH_802_1_H))) - { - PUCHAR Key; - UCHAR CipherAlg; - int idx = 0; - - DBGPRINT_RAW(RT_DEBUG_TRACE, ("Receive EAP-SUCCESS Packet\n")); - //pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; - STA_PORT_SECURED(pAd); - - if (pAd->StaCfg.IEEE8021x_required_keys == FALSE) - { - idx = pAd->StaCfg.DesireSharedKeyId; - CipherAlg = pAd->StaCfg.DesireSharedKey[idx].CipherAlg; - Key = pAd->StaCfg.DesireSharedKey[idx].Key; - - if (pAd->StaCfg.DesireSharedKey[idx].KeyLen > 0) - { -#ifdef RT2870 - union - { - char buf[sizeof(NDIS_802_11_WEP)+MAX_LEN_OF_KEY- 1]; - NDIS_802_11_WEP keyinfo; - } WepKey; - int len; - - - NdisZeroMemory(&WepKey, sizeof(WepKey)); - len =pAd->StaCfg.DesireSharedKey[idx].KeyLen; - - NdisMoveMemory(WepKey.keyinfo.KeyMaterial, - pAd->StaCfg.DesireSharedKey[idx].Key, - pAd->StaCfg.DesireSharedKey[idx].KeyLen); - - WepKey.keyinfo.KeyIndex = 0x80000000 + idx; - WepKey.keyinfo.KeyLength = len; - pAd->SharedKey[BSS0][idx].KeyLen =(UCHAR) (len <= 5 ? 5 : 13); - - pAd->IndicateMediaState = NdisMediaStateConnected; - pAd->ExtraInfo = GENERAL_LINK_UP; - // need to enqueue cmd to thread - RTUSBEnqueueCmdFromNdis(pAd, OID_802_11_ADD_WEP, TRUE, &WepKey, sizeof(WepKey.keyinfo) + len - 1); -#endif // RT2870 // - // For Preventing ShardKey Table is cleared by remove key procedure. - pAd->SharedKey[BSS0][idx].CipherAlg = CipherAlg; - pAd->SharedKey[BSS0][idx].KeyLen = pAd->StaCfg.DesireSharedKey[idx].KeyLen; - NdisMoveMemory(pAd->SharedKey[BSS0][idx].Key, - pAd->StaCfg.DesireSharedKey[idx].Key, - pAd->StaCfg.DesireSharedKey[idx].KeyLen); - } - } - } - - Indicate_Legacy_Packet(pAd, pRxBlk, FromWhichBSSID); - return; - } - } - else -#endif // WPA_SUPPLICANT_SUPPORT // - { - // Special DATA frame that has to pass to MLME - // 1. Cisco Aironet frames for CCX2. We need pass it to MLME for special process - // 2. EAPOL handshaking frames when driver supplicant enabled, pass to MLME for special process - { - pTmpBuf = pRxBlk->pData - LENGTH_802_11; - NdisMoveMemory(pTmpBuf, pRxBlk->pHeader, LENGTH_802_11); - REPORT_MGMT_FRAME_TO_MLME(pAd, pRxWI->WirelessCliID, pTmpBuf, pRxBlk->DataSize + LENGTH_802_11, pRxWI->RSSI0, pRxWI->RSSI1, pRxWI->RSSI2, pRxD->PlcpSignal); - DBGPRINT_RAW(RT_DEBUG_TRACE, ("!!! report EAPOL/AIRONET DATA to MLME (len=%d) !!!\n", pRxBlk->DataSize)); - } - } - - RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); - return; - -} - -VOID STARxDataFrameAnnounce( - IN PRTMP_ADAPTER pAd, - IN MAC_TABLE_ENTRY *pEntry, - IN RX_BLK *pRxBlk, - IN UCHAR FromWhichBSSID) -{ - - // non-EAP frame - if (!RTMPCheckWPAframe(pAd, pEntry, pRxBlk->pData, pRxBlk->DataSize, FromWhichBSSID)) - { - - { - // drop all non-EAP DATA frame before - // this client's Port-Access-Control is secured - if (pRxBlk->pHeader->FC.Wep) - { - // unsupported cipher suite - if (pAd->StaCfg.WepStatus == Ndis802_11EncryptionDisabled) - { - // release packet - RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); - return; - } - } - else - { - // encryption in-use but receive a non-EAPOL clear text frame, drop it - if ((pAd->StaCfg.WepStatus != Ndis802_11EncryptionDisabled) && - (pAd->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED)) - { - // release packet - RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); - return; - } - } - } - RX_BLK_CLEAR_FLAG(pRxBlk, fRX_EAP); - if (!RX_BLK_TEST_FLAG(pRxBlk, fRX_ARALINK)) - { - // Normal legacy, AMPDU or AMSDU - CmmRxnonRalinkFrameIndicate(pAd, pRxBlk, FromWhichBSSID); - - } - else - { - // ARALINK - CmmRxRalinkFrameIndicate(pAd, pEntry, pRxBlk, FromWhichBSSID); - } -#ifdef QOS_DLS_SUPPORT - RX_BLK_CLEAR_FLAG(pRxBlk, fRX_DLS); -#endif // QOS_DLS_SUPPORT // - } - else - { - RX_BLK_SET_FLAG(pRxBlk, fRX_EAP); -#ifdef DOT11_N_SUPPORT - if (RX_BLK_TEST_FLAG(pRxBlk, fRX_AMPDU) && (pAd->CommonCfg.bDisableReordering == 0)) - { - Indicate_AMPDU_Packet(pAd, pRxBlk, FromWhichBSSID); - } - else -#endif // DOT11_N_SUPPORT // - { - // Determin the destination of the EAP frame - // to WPA state machine or upper layer - STARxEAPOLFrameIndicate(pAd, pEntry, pRxBlk, FromWhichBSSID); - } - } -} - - -// For TKIP frame, calculate the MIC value -BOOLEAN STACheckTkipMICValue( - IN PRTMP_ADAPTER pAd, - IN MAC_TABLE_ENTRY *pEntry, - IN RX_BLK *pRxBlk) -{ - PHEADER_802_11 pHeader = pRxBlk->pHeader; - UCHAR *pData = pRxBlk->pData; - USHORT DataSize = pRxBlk->DataSize; - UCHAR UserPriority = pRxBlk->UserPriority; - PCIPHER_KEY pWpaKey; - UCHAR *pDA, *pSA; - - pWpaKey = &pAd->SharedKey[BSS0][pRxBlk->pRxWI->KeyIndex]; - - pDA = pHeader->Addr1; - if (RX_BLK_TEST_FLAG(pRxBlk, fRX_INFRA)) - { - pSA = pHeader->Addr3; - } - else - { - pSA = pHeader->Addr2; - } - - if (RTMPTkipCompareMICValue(pAd, - pData, - pDA, - pSA, - pWpaKey->RxMic, - UserPriority, - DataSize) == FALSE) - { - DBGPRINT_RAW(RT_DEBUG_ERROR,("Rx MIC Value error 2\n")); - -#ifdef WPA_SUPPLICANT_SUPPORT - if (pAd->StaCfg.WpaSupplicantUP) - { - WpaSendMicFailureToWpaSupplicant(pAd, (pWpaKey->Type == PAIRWISEKEY) ? TRUE : FALSE); - } - else -#endif // WPA_SUPPLICANT_SUPPORT // - { - RTMPReportMicError(pAd, pWpaKey); - } - - // release packet - RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); - return FALSE; - } - - return TRUE; -} - - -// -// All Rx routines use RX_BLK structure to hande rx events -// It is very important to build pRxBlk attributes -// 1. pHeader pointer to 802.11 Header -// 2. pData pointer to payload including LLC (just skip Header) -// 3. set payload size including LLC to DataSize -// 4. set some flags with RX_BLK_SET_FLAG() -// -VOID STAHandleRxDataFrame( - IN PRTMP_ADAPTER pAd, - IN RX_BLK *pRxBlk) -{ - PRT28XX_RXD_STRUC pRxD = &(pRxBlk->RxD); - PRXWI_STRUC pRxWI = pRxBlk->pRxWI; - PHEADER_802_11 pHeader = pRxBlk->pHeader; - PNDIS_PACKET pRxPacket = pRxBlk->pRxPacket; - BOOLEAN bFragment = FALSE; - MAC_TABLE_ENTRY *pEntry = NULL; - UCHAR FromWhichBSSID = BSS0; - UCHAR UserPriority = 0; - - { - // before LINK UP, all DATA frames are rejected - if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) - { - // release packet - RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); - return; - } - -#ifdef QOS_DLS_SUPPORT - //if ((pHeader->FC.FrDs == 0) && (pHeader->FC.ToDs == 0)) - if (RTMPRcvFrameDLSCheck(pAd, pHeader, pRxWI->MPDUtotalByteCount, pRxD)) - { - return; - } -#endif // QOS_DLS_SUPPORT // - - // Drop not my BSS frames - if (pRxD->MyBss == 0) - { - { - // release packet - RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); - return; - } - } - - pAd->RalinkCounters.RxCountSinceLastNULL++; - if (pAd->CommonCfg.bAPSDCapable && pAd->CommonCfg.APEdcaParm.bAPSDCapable && (pHeader->FC.SubType & 0x08)) - { - UCHAR *pData; - DBGPRINT(RT_DEBUG_TRACE,("bAPSDCapable\n")); - - // Qos bit 4 - pData = (PUCHAR)pHeader + LENGTH_802_11; - if ((*pData >> 4) & 0x01) - { - DBGPRINT(RT_DEBUG_TRACE,("RxDone- Rcv EOSP frame, driver may fall into sleep\n")); - pAd->CommonCfg.bInServicePeriod = FALSE; - - // Force driver to fall into sleep mode when rcv EOSP frame - if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) - { - USHORT TbttNumToNextWakeUp; - USHORT NextDtim = pAd->StaCfg.DtimPeriod; - ULONG Now; - - NdisGetSystemUpTime(&Now); - NextDtim -= (USHORT)(Now - pAd->StaCfg.LastBeaconRxTime)/pAd->CommonCfg.BeaconPeriod; - - TbttNumToNextWakeUp = pAd->StaCfg.DefaultListenCount; - if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_RECEIVE_DTIM) && (TbttNumToNextWakeUp > NextDtim)) - TbttNumToNextWakeUp = NextDtim; - - MlmeSetPsmBit(pAd, PWR_SAVE); - // if WMM-APSD is failed, try to disable following line - AsicSleepThenAutoWakeup(pAd, TbttNumToNextWakeUp); - } - } - - if ((pHeader->FC.MoreData) && (pAd->CommonCfg.bInServicePeriod)) - { - DBGPRINT(RT_DEBUG_TRACE,("Sending another trigger frame when More Data bit is set to 1\n")); - } - } - - // Drop NULL, CF-ACK(no data), CF-POLL(no data), and CF-ACK+CF-POLL(no data) data frame - if ((pHeader->FC.SubType & 0x04)) // bit 2 : no DATA - { - // release packet - RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); - return; - } - - // Drop not my BSS frame (we can not only check the MyBss bit in RxD) -#ifdef QOS_DLS_SUPPORT - if (!pAd->CommonCfg.bDLSCapable) - { -#endif // QOS_DLS_SUPPORT // - if (INFRA_ON(pAd)) - { - // Infrastructure mode, check address 2 for BSSID - if (!RTMPEqualMemory(&pHeader->Addr2, &pAd->CommonCfg.Bssid, 6)) - { - // Receive frame not my BSSID - // release packet - RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); - return; - } - } - else // Ad-Hoc mode or Not associated - { - // Ad-Hoc mode, check address 3 for BSSID - if (!RTMPEqualMemory(&pHeader->Addr3, &pAd->CommonCfg.Bssid, 6)) - { - // Receive frame not my BSSID - // release packet - RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); - return; - } - } -#ifdef QOS_DLS_SUPPORT - } -#endif // QOS_DLS_SUPPORT // - - // - // find pEntry - // - if (pRxWI->WirelessCliID < MAX_LEN_OF_MAC_TABLE) - { - pEntry = &pAd->MacTab.Content[pRxWI->WirelessCliID]; - } - else - { - // 1. release packet if infra mode - // 2. new a pEntry if ad-hoc mode - RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); - return; - } - - // infra or ad-hoc - if (INFRA_ON(pAd)) - { - RX_BLK_SET_FLAG(pRxBlk, fRX_INFRA); -#ifdef QOS_DLS_SUPPORT - if ((pHeader->FC.FrDs == 0) && (pHeader->FC.ToDs == 0)) - RX_BLK_SET_FLAG(pRxBlk, fRX_DLS); - else -#endif // QOS_DLS_SUPPORT // - ASSERT(pRxWI->WirelessCliID == BSSID_WCID); - } - - // check Atheros Client - if ((pEntry->bIAmBadAtheros == FALSE) && (pRxD->AMPDU == 1) && (pHeader->FC.Retry )) - { - pEntry->bIAmBadAtheros = TRUE; - pAd->CommonCfg.IOTestParm.bCurrentAtheros = TRUE; - pAd->CommonCfg.IOTestParm.bLastAtheros = TRUE; - if (!STA_AES_ON(pAd)) - { - AsicUpdateProtect(pAd, 8, ALLN_SETPROTECT, TRUE, FALSE); - } - } - } - - pRxBlk->pData = (UCHAR *)pHeader; - - // - // update RxBlk->pData, DataSize - // 802.11 Header, QOS, HTC, Hw Padding - // - - // 1. skip 802.11 HEADER - { - pRxBlk->pData += LENGTH_802_11; - pRxBlk->DataSize -= LENGTH_802_11; - } - - // 2. QOS - if (pHeader->FC.SubType & 0x08) - { - RX_BLK_SET_FLAG(pRxBlk, fRX_QOS); - UserPriority = *(pRxBlk->pData) & 0x0f; - // bit 7 in QoS Control field signals the HT A-MSDU format - if ((*pRxBlk->pData) & 0x80) - { - RX_BLK_SET_FLAG(pRxBlk, fRX_AMSDU); - } - - // skip QOS contorl field - pRxBlk->pData += 2; - pRxBlk->DataSize -=2; - } - pRxBlk->UserPriority = UserPriority; - - // 3. Order bit: A-Ralink or HTC+ - if (pHeader->FC.Order) - { -#ifdef AGGREGATION_SUPPORT - if ((pRxWI->PHYMODE <= MODE_OFDM) && (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED))) - { - RX_BLK_SET_FLAG(pRxBlk, fRX_ARALINK); - } - else -#endif - { -#ifdef DOT11_N_SUPPORT - RX_BLK_SET_FLAG(pRxBlk, fRX_HTC); - // skip HTC contorl field - pRxBlk->pData += 4; - pRxBlk->DataSize -= 4; -#endif // DOT11_N_SUPPORT // - } - } - - // 4. skip HW padding - if (pRxD->L2PAD) - { - // just move pData pointer - // because DataSize excluding HW padding - RX_BLK_SET_FLAG(pRxBlk, fRX_PAD); - pRxBlk->pData += 2; - } - -#ifdef DOT11_N_SUPPORT - if (pRxD->BA) - { - RX_BLK_SET_FLAG(pRxBlk, fRX_AMPDU); - } -#endif // DOT11_N_SUPPORT // - - - // - // Case I Process Broadcast & Multicast data frame - // - if (pRxD->Bcast || pRxD->Mcast) - { - INC_COUNTER64(pAd->WlanCounters.MulticastReceivedFrameCount); - - // Drop Mcast/Bcast frame with fragment bit on - if (pHeader->FC.MoreFrag) - { - // release packet - RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); - return; - } - - // Filter out Bcast frame which AP relayed for us - if (pHeader->FC.FrDs && MAC_ADDR_EQUAL(pHeader->Addr3, pAd->CurrentAddress)) - { - // release packet - RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); - return; - } - - Indicate_Legacy_Packet(pAd, pRxBlk, FromWhichBSSID); - return; - } - else if (pRxD->U2M) - { - pAd->LastRxRate = (USHORT)((pRxWI->MCS) + (pRxWI->BW <<7) + (pRxWI->ShortGI <<8)+ (pRxWI->PHYMODE <<14)) ; - - -#ifdef QOS_DLS_SUPPORT - if (RX_BLK_TEST_FLAG(pRxBlk, fRX_DLS)) - { - MAC_TABLE_ENTRY *pDlsEntry = NULL; - - pDlsEntry = DlsEntryTableLookupByWcid(pAd, pRxWI->WirelessCliID, pHeader->Addr2, TRUE); - if(pDlsEntry) - Update_Rssi_Sample(pAd, &pDlsEntry->RssiSample, pRxWI); - } - else -#endif // QOS_DLS_SUPPORT // - if (ADHOC_ON(pAd)) - { - pEntry = MacTableLookup(pAd, pHeader->Addr2); - if (pEntry) - Update_Rssi_Sample(pAd, &pEntry->RssiSample, pRxWI); - } - - - Update_Rssi_Sample(pAd, &pAd->StaCfg.RssiSample, pRxWI); - - pAd->StaCfg.LastSNR0 = (UCHAR)(pRxWI->SNR0); - pAd->StaCfg.LastSNR1 = (UCHAR)(pRxWI->SNR1); - - pAd->RalinkCounters.OneSecRxOkDataCnt++; - - - if (!((pHeader->Frag == 0) && (pHeader->FC.MoreFrag == 0))) - { - // re-assemble the fragmented packets - // return complete frame (pRxPacket) or NULL - bFragment = TRUE; - pRxPacket = RTMPDeFragmentDataFrame(pAd, pRxBlk); - } - - if (pRxPacket) - { - pEntry = &pAd->MacTab.Content[pRxWI->WirelessCliID]; - - // process complete frame - if (bFragment && (pRxD->Decrypted) && (pEntry->WepStatus == Ndis802_11Encryption2Enabled)) - { - // Minus MIC length - pRxBlk->DataSize -= 8; - - // For TKIP frame, calculate the MIC value - if (STACheckTkipMICValue(pAd, pEntry, pRxBlk) == FALSE) - { - return; - } - } - - STARxDataFrameAnnounce(pAd, pEntry, pRxBlk, FromWhichBSSID); - return; - } - else - { - // just return - // because RTMPDeFragmentDataFrame() will release rx packet, - // if packet is fragmented - return; - } - } - - ASSERT(0); - // release packet - RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); -} - -VOID STAHandleRxMgmtFrame( - IN PRTMP_ADAPTER pAd, - IN RX_BLK *pRxBlk) -{ - PRT28XX_RXD_STRUC pRxD = &(pRxBlk->RxD); - PRXWI_STRUC pRxWI = pRxBlk->pRxWI; - PHEADER_802_11 pHeader = pRxBlk->pHeader; - PNDIS_PACKET pRxPacket = pRxBlk->pRxPacket; - - do - { - - // We should collect RSSI not only U2M data but also my beacon - if ((pHeader->FC.SubType == SUBTYPE_BEACON) && (MAC_ADDR_EQUAL(&pAd->CommonCfg.Bssid, &pHeader->Addr2)) - && (pAd->RxAnt.EvaluatePeriod == 0)) - { - Update_Rssi_Sample(pAd, &pAd->StaCfg.RssiSample, pRxWI); - - pAd->StaCfg.LastSNR0 = (UCHAR)(pRxWI->SNR0); - pAd->StaCfg.LastSNR1 = (UCHAR)(pRxWI->SNR1); - } - -#ifdef RT30xx - // collect rssi information for antenna diversity - if (pAd->NicConfig2.field.AntDiversity) - { - if ((pRxD->U2M) || ((pHeader->FC.SubType == SUBTYPE_BEACON) && (MAC_ADDR_EQUAL(&pAd->CommonCfg.Bssid, &pHeader->Addr2)))) - { - COLLECT_RX_ANTENNA_AVERAGE_RSSI(pAd, ConvertToRssi(pAd, (UCHAR)pRxWI->RSSI0, RSSI_0), 0); //Note: RSSI2 not used on RT73 - pAd->StaCfg.NumOfAvgRssiSample ++; - } - } -#endif // RT30xx // - - // First check the size, it MUST not exceed the mlme queue size - if (pRxWI->MPDUtotalByteCount > MGMT_DMA_BUFFER_SIZE) - { - DBGPRINT_ERR(("STAHandleRxMgmtFrame: frame too large, size = %d \n", pRxWI->MPDUtotalByteCount)); - break; - } - - REPORT_MGMT_FRAME_TO_MLME(pAd, pRxWI->WirelessCliID, pHeader, pRxWI->MPDUtotalByteCount, - pRxWI->RSSI0, pRxWI->RSSI1, pRxWI->RSSI2, pRxD->PlcpSignal); - } while (FALSE); - - RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_SUCCESS); -} - -VOID STAHandleRxControlFrame( - IN PRTMP_ADAPTER pAd, - IN RX_BLK *pRxBlk) -{ -#ifdef DOT11_N_SUPPORT - PRXWI_STRUC pRxWI = pRxBlk->pRxWI; -#endif // DOT11_N_SUPPORT // - PHEADER_802_11 pHeader = pRxBlk->pHeader; - PNDIS_PACKET pRxPacket = pRxBlk->pRxPacket; - - switch (pHeader->FC.SubType) - { - case SUBTYPE_BLOCK_ACK_REQ: -#ifdef DOT11_N_SUPPORT - { - CntlEnqueueForRecv(pAd, pRxWI->WirelessCliID, (pRxWI->MPDUtotalByteCount), (PFRAME_BA_REQ)pHeader); - } - break; -#endif // DOT11_N_SUPPORT // - case SUBTYPE_BLOCK_ACK: - case SUBTYPE_ACK: - default: - break; - } - - RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); -} - - -/* - ======================================================================== - - Routine Description: - Process RxDone interrupt, running in DPC level - - Arguments: - pAd Pointer to our adapter - - Return Value: - None - - IRQL = DISPATCH_LEVEL - - Note: - This routine has to maintain Rx ring read pointer. - Need to consider QOS DATA format when converting to 802.3 - ======================================================================== -*/ -BOOLEAN STARxDoneInterruptHandle( - IN PRTMP_ADAPTER pAd, - IN BOOLEAN argc) -{ - NDIS_STATUS Status; - UINT32 RxProcessed, RxPending; - BOOLEAN bReschedule = FALSE; - RT28XX_RXD_STRUC *pRxD; - UCHAR *pData; - PRXWI_STRUC pRxWI; - PNDIS_PACKET pRxPacket; - PHEADER_802_11 pHeader; - RX_BLK RxCell; - - RxProcessed = RxPending = 0; - - // process whole rx ring - while (1) - { - - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF | - fRTMP_ADAPTER_RESET_IN_PROGRESS | - fRTMP_ADAPTER_HALT_IN_PROGRESS | - fRTMP_ADAPTER_NIC_NOT_EXIST) || - !RTMP_TEST_FLAG(pAd,fRTMP_ADAPTER_START_UP)) - { - break; - } - - - RxProcessed ++; // test - - // 1. allocate a new data packet into rx ring to replace received packet - // then processing the received packet - // 2. the callee must take charge of release of packet - // 3. As far as driver is concerned , - // the rx packet must - // a. be indicated to upper layer or - // b. be released if it is discarded - pRxPacket = GetPacketFromRxRing(pAd, &(RxCell.RxD), &bReschedule, &RxPending); - if (pRxPacket == NULL) - { - // no more packet to process - break; - } - - // get rx ring descriptor - pRxD = &(RxCell.RxD); - // get rx data buffer - pData = GET_OS_PKT_DATAPTR(pRxPacket); - pRxWI = (PRXWI_STRUC) pData; - pHeader = (PHEADER_802_11) (pData+RXWI_SIZE) ; - -#ifdef RT_BIG_ENDIAN - RTMPFrameEndianChange(pAd, (PUCHAR)pHeader, DIR_READ, TRUE); - RTMPWIEndianChange((PUCHAR)pRxWI, TYPE_RXWI); -#endif - - // build RxCell - RxCell.pRxWI = pRxWI; - RxCell.pHeader = pHeader; - RxCell.pRxPacket = pRxPacket; - RxCell.pData = (UCHAR *) pHeader; - RxCell.DataSize = pRxWI->MPDUtotalByteCount; - RxCell.Flags = 0; - - // Increase Total receive byte counter after real data received no mater any error or not - pAd->RalinkCounters.ReceivedByteCount += pRxWI->MPDUtotalByteCount; - pAd->RalinkCounters.RxCount ++; - - INC_COUNTER64(pAd->WlanCounters.ReceivedFragmentCount); - - if (pRxWI->MPDUtotalByteCount < 14) - Status = NDIS_STATUS_FAILURE; - - if (MONITOR_ON(pAd)) - { - send_monitor_packets(pAd, &RxCell); - break; - } - /* RT2870 invokes STARxDoneInterruptHandle() in rtusb_bulk.c */ -#ifdef RALINK_ATE - if (ATE_ON(pAd)) - { - pAd->ate.RxCntPerSec++; - ATESampleRssi(pAd, pRxWI); -#ifdef RALINK_28xx_QA - if (pAd->ate.bQARxStart == TRUE) - { - /* (*pRxD) has been swapped in GetPacketFromRxRing() */ - ATE_QA_Statistics(pAd, pRxWI, pRxD, pHeader); - } -#endif // RALINK_28xx_QA // - RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_SUCCESS); - continue; - } -#endif // RALINK_ATE // - - // Check for all RxD errors - Status = RTMPCheckRxError(pAd, pHeader, pRxWI, pRxD); - - // Handle the received frame - if (Status == NDIS_STATUS_SUCCESS) - { - switch (pHeader->FC.Type) - { - // CASE I, receive a DATA frame - case BTYPE_DATA: - { - // process DATA frame - STAHandleRxDataFrame(pAd, &RxCell); - } - break; - // CASE II, receive a MGMT frame - case BTYPE_MGMT: - { - STAHandleRxMgmtFrame(pAd, &RxCell); - } - break; - // CASE III. receive a CNTL frame - case BTYPE_CNTL: - { - STAHandleRxControlFrame(pAd, &RxCell); - } - break; - // discard other type - default: - RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); - break; - } - } - else - { - pAd->Counters8023.RxErrors++; - // discard this frame - RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); - } - } - - return bReschedule; -} - -/* - ======================================================================== - - Routine Description: - Arguments: - pAd Pointer to our adapter - - IRQL = DISPATCH_LEVEL - - ======================================================================== -*/ -VOID RTMPHandleTwakeupInterrupt( - IN PRTMP_ADAPTER pAd) -{ - AsicForceWakeup(pAd, FALSE); -} - -/* -======================================================================== -Routine Description: - Early checking and OS-depened parsing for Tx packet send to our STA driver. - -Arguments: - NDIS_HANDLE MiniportAdapterContext Pointer refer to the device handle, i.e., the pAd. - PPNDIS_PACKET ppPacketArray The packet array need to do transmission. - UINT NumberOfPackets Number of packet in packet array. - -Return Value: - NONE - -Note: - This function do early checking and classification for send-out packet. - You only can put OS-depened & STA related code in here. -======================================================================== -*/ -VOID STASendPackets( - IN NDIS_HANDLE MiniportAdapterContext, - IN PPNDIS_PACKET ppPacketArray, - IN UINT NumberOfPackets) -{ - UINT Index; - PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) MiniportAdapterContext; - PNDIS_PACKET pPacket; - BOOLEAN allowToSend = FALSE; - - - for (Index = 0; Index < NumberOfPackets; Index++) - { - pPacket = ppPacketArray[Index]; - - do - { - - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS) || - RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS) || - RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF)) - { - // Drop send request since hardware is in reset state - break; - } - else if (!INFRA_ON(pAd) && !ADHOC_ON(pAd)) - { - // Drop send request since there are no physical connection yet - break; - } - else - { - // Record that orignal packet source is from NDIS layer,so that - // later on driver knows how to release this NDIS PACKET -#ifdef QOS_DLS_SUPPORT - MAC_TABLE_ENTRY *pEntry; - PUCHAR pSrcBufVA = GET_OS_PKT_DATAPTR(pPacket); - - pEntry = MacTableLookup(pAd, pSrcBufVA); - if (pEntry && (pEntry->ValidAsDls == TRUE)) - { - RTMP_SET_PACKET_WCID(pPacket, pEntry->Aid); - } - else -#endif // QOS_DLS_SUPPORT // - RTMP_SET_PACKET_WCID(pPacket, 0); // this field is useless when in STA mode - RTMP_SET_PACKET_SOURCE(pPacket, PKTSRC_NDIS); - NDIS_SET_PACKET_STATUS(pPacket, NDIS_STATUS_PENDING); - pAd->RalinkCounters.PendingNdisPacketCount++; - - allowToSend = TRUE; - } - } while(FALSE); - - if (allowToSend == TRUE) - STASendPacket(pAd, pPacket); - else - RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); - } - - // Dequeue outgoing frames from TxSwQueue[] and process it - RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, MAX_TX_PROCESS); - -} - - -/* -======================================================================== -Routine Description: - This routine is used to do packet parsing and classification for Tx packet - to STA device, and it will en-queue packets to our TxSwQueue depends on AC - class. - -Arguments: - pAd Pointer to our adapter - pPacket Pointer to send packet - -Return Value: - NDIS_STATUS_SUCCESS If succes to queue the packet into TxSwQueue. - NDIS_STATUS_FAILURE If failed to do en-queue. - -Note: - You only can put OS-indepened & STA related code in here. -======================================================================== -*/ -NDIS_STATUS STASendPacket( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket) -{ - PACKET_INFO PacketInfo; - PUCHAR pSrcBufVA; - UINT SrcBufLen; - UINT AllowFragSize; - UCHAR NumberOfFrag; -// UCHAR RTSRequired; - UCHAR QueIdx, UserPriority; - MAC_TABLE_ENTRY *pEntry = NULL; - unsigned int IrqFlags; - UCHAR FlgIsIP = 0; - UCHAR Rate; - - // Prepare packet information structure for buffer descriptor - // chained within a single NDIS packet. - RTMP_QueryPacketInfo(pPacket, &PacketInfo, &pSrcBufVA, &SrcBufLen); - - if (pSrcBufVA == NULL) - { - DBGPRINT(RT_DEBUG_ERROR,("STASendPacket --> pSrcBufVA == NULL !!!SrcBufLen=%x\n",SrcBufLen)); - // Resourece is low, system did not allocate virtual address - // return NDIS_STATUS_FAILURE directly to upper layer - RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); - return NDIS_STATUS_FAILURE; - } - - - if (SrcBufLen < 14) - { - DBGPRINT(RT_DEBUG_ERROR,("STASendPacket --> Ndis Packet buffer error !!!\n")); - RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); - return (NDIS_STATUS_FAILURE); - } - - // In HT rate adhoc mode, A-MPDU is often used. So need to lookup BA Table and MAC Entry. - // Note multicast packets in adhoc also use BSSID_WCID index. - { - if(INFRA_ON(pAd)) - { -#ifdef QOS_DLS_SUPPORT - USHORT tmpWcid; - - tmpWcid = RTMP_GET_PACKET_WCID(pPacket); - if (VALID_WCID(tmpWcid) && - (pAd->MacTab.Content[tmpWcid].ValidAsDls== TRUE)) - { - pEntry = &pAd->MacTab.Content[tmpWcid]; - Rate = pAd->MacTab.Content[tmpWcid].CurrTxRate; - } - else -#endif // QOS_DLS_SUPPORT // - { - pEntry = &pAd->MacTab.Content[BSSID_WCID]; - RTMP_SET_PACKET_WCID(pPacket, BSSID_WCID); - Rate = pAd->CommonCfg.TxRate; - } - } - else if (ADHOC_ON(pAd)) - { - if (*pSrcBufVA & 0x01) - { - RTMP_SET_PACKET_WCID(pPacket, MCAST_WCID); - pEntry = &pAd->MacTab.Content[MCAST_WCID]; - } - else - { - pEntry = MacTableLookup(pAd, pSrcBufVA); - } - Rate = pAd->CommonCfg.TxRate; - } - } - - if (!pEntry) - { - DBGPRINT(RT_DEBUG_ERROR,("STASendPacket->Cannot find pEntry(%2x:%2x:%2x:%2x:%2x:%2x) in MacTab!\n", PRINT_MAC(pSrcBufVA))); - // Resourece is low, system did not allocate virtual address - // return NDIS_STATUS_FAILURE directly to upper layer - RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); - return NDIS_STATUS_FAILURE; - } - - if (ADHOC_ON(pAd) - ) - { - RTMP_SET_PACKET_WCID(pPacket, (UCHAR)pEntry->Aid); - } - - // - // Check the Ethernet Frame type of this packet, and set the RTMP_SET_PACKET_SPECIFIC flags. - // Here we set the PACKET_SPECIFIC flags(LLC, VLAN, DHCP/ARP, EAPOL). - RTMPCheckEtherType(pAd, pPacket); - - - - // - // WPA 802.1x secured port control - drop all non-802.1x frame before port secured - // - if (((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || - (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) || - (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || - (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) -#ifdef WPA_SUPPLICANT_SUPPORT - || (pAd->StaCfg.IEEE8021X == TRUE) -#endif // WPA_SUPPLICANT_SUPPORT // -#ifdef LEAP_SUPPORT - || (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) -#endif // LEAP_SUPPORT // - ) - && ((pAd->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED) || (pAd->StaCfg.MicErrCnt >= 2)) - && (RTMP_GET_PACKET_EAPOL(pPacket)== FALSE) - ) - { - DBGPRINT(RT_DEBUG_TRACE,("STASendPacket --> Drop packet before port secured !!!\n")); - RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); - - return (NDIS_STATUS_FAILURE); - } - - - // STEP 1. Decide number of fragments required to deliver this MSDU. - // The estimation here is not very accurate because difficult to - // take encryption overhead into consideration here. The result - // "NumberOfFrag" is then just used to pre-check if enough free - // TXD are available to hold this MSDU. - - - if (*pSrcBufVA & 0x01) // fragmentation not allowed on multicast & broadcast - NumberOfFrag = 1; - else if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED)) - NumberOfFrag = 1; // Aggregation overwhelms fragmentation - else if (CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_AMSDU_INUSED)) - NumberOfFrag = 1; // Aggregation overwhelms fragmentation -#ifdef DOT11_N_SUPPORT - else if ((pAd->StaCfg.HTPhyMode.field.MODE == MODE_HTMIX) || (pAd->StaCfg.HTPhyMode.field.MODE == MODE_HTGREENFIELD)) - NumberOfFrag = 1; // MIMO RATE overwhelms fragmentation -#endif // DOT11_N_SUPPORT // - else - { - // The calculated "NumberOfFrag" is a rough estimation because of various - // encryption/encapsulation overhead not taken into consideration. This number is just - // used to make sure enough free TXD are available before fragmentation takes place. - // In case the actual required number of fragments of an NDIS packet - // excceeds "NumberOfFrag"caculated here and not enough free TXD available, the - // last fragment (i.e. last MPDU) will be dropped in RTMPHardTransmit() due to out of - // resource, and the NDIS packet will be indicated NDIS_STATUS_FAILURE. This should - // rarely happen and the penalty is just like a TX RETRY fail. Affordable. - - AllowFragSize = (pAd->CommonCfg.FragmentThreshold) - LENGTH_802_11 - LENGTH_CRC; - NumberOfFrag = ((PacketInfo.TotalPacketLength - LENGTH_802_3 + LENGTH_802_1_H) / AllowFragSize) + 1; - // To get accurate number of fragmentation, Minus 1 if the size just match to allowable fragment size - if (((PacketInfo.TotalPacketLength - LENGTH_802_3 + LENGTH_802_1_H) % AllowFragSize) == 0) - { - NumberOfFrag--; - } - } - - // Save fragment number to Ndis packet reserved field - RTMP_SET_PACKET_FRAGMENTS(pPacket, NumberOfFrag); - - - // STEP 2. Check the requirement of RTS: - // If multiple fragment required, RTS is required only for the first fragment - // if the fragment size large than RTS threshold - // For RT28xx, Let ASIC send RTS/CTS - RTMP_SET_PACKET_RTS(pPacket, 0); - RTMP_SET_PACKET_TXRATE(pPacket, pAd->CommonCfg.TxRate); - - // - // STEP 3. Traffic classification. outcome = - // - UserPriority = 0; - QueIdx = QID_AC_BE; - if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED) && - CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_WMM_CAPABLE)) - { - USHORT Protocol; - UCHAR LlcSnapLen = 0, Byte0, Byte1; - do - { - // get Ethernet protocol field - Protocol = (USHORT)((pSrcBufVA[12] << 8) + pSrcBufVA[13]); - if (Protocol <= 1500) - { - // get Ethernet protocol field from LLC/SNAP - if (Sniff2BytesFromNdisBuffer(PacketInfo.pFirstBuffer, LENGTH_802_3 + 6, &Byte0, &Byte1) != NDIS_STATUS_SUCCESS) - break; - - Protocol = (USHORT)((Byte0 << 8) + Byte1); - LlcSnapLen = 8; - } - - // always AC_BE for non-IP packet - if (Protocol != 0x0800) - break; - - // get IP header - if (Sniff2BytesFromNdisBuffer(PacketInfo.pFirstBuffer, LENGTH_802_3 + LlcSnapLen, &Byte0, &Byte1) != NDIS_STATUS_SUCCESS) - break; - - // return AC_BE if packet is not IPv4 - if ((Byte0 & 0xf0) != 0x40) - break; - - FlgIsIP = 1; - UserPriority = (Byte1 & 0xe0) >> 5; - QueIdx = MapUserPriorityToAccessCategory[UserPriority]; - - // TODO: have to check ACM bit. apply TSPEC if ACM is ON - // TODO: downgrade UP & QueIdx before passing ACM - if (pAd->CommonCfg.APEdcaParm.bACM[QueIdx]) - { - UserPriority = 0; - QueIdx = QID_AC_BE; - } - } while (FALSE); - } - - RTMP_SET_PACKET_UP(pPacket, UserPriority); - - - - // Make sure SendTxWait queue resource won't be used by other threads - RTMP_IRQ_LOCK(&pAd->irq_lock, IrqFlags); - if (pAd->TxSwQueue[QueIdx].Number >= MAX_PACKETS_IN_QUEUE) - { - RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags); -#ifdef BLOCK_NET_IF - StopNetIfQueue(pAd, QueIdx, pPacket); -#endif // BLOCK_NET_IF // - RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); - - return NDIS_STATUS_FAILURE; - } - else - { - InsertTailQueue(&pAd->TxSwQueue[QueIdx], PACKET_TO_QUEUE_ENTRY(pPacket)); - } - RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags); - -#ifdef DOT11_N_SUPPORT - if ((pAd->CommonCfg.BACapability.field.AutoBA == TRUE)&& - IS_HT_STA(pEntry)) - { - //PMAC_TABLE_ENTRY pMacEntry = &pAd->MacTab.Content[BSSID_WCID]; - if (((pEntry->TXBAbitmap & (1<BADeclineBitmap & (1<PortSecured == WPA_802_1X_PORT_SECURED) - // For IOT compatibility, if - // 1. It is Ralink chip or - // 2. It is OPEN or AES mode, - // then BA session can be bulit. - && ((pEntry->ValidAsCLI && pAd->MlmeAux.APRalinkIe != 0x0) || - (pEntry->WepStatus == Ndis802_11WEPDisabled || pEntry->WepStatus == Ndis802_11Encryption3Enabled)) - ) - { - BAOriSessionSetUp(pAd, pEntry, 0, 0, 10, FALSE); - } - } -#endif // DOT11_N_SUPPORT // - - pAd->RalinkCounters.OneSecOsTxCount[QueIdx]++; // TODO: for debug only. to be removed - return NDIS_STATUS_SUCCESS; -} - - -/* - ======================================================================== - - Routine Description: - This subroutine will scan through releative ring descriptor to find - out avaliable free ring descriptor and compare with request size. - - Arguments: - pAd Pointer to our adapter - QueIdx Selected TX Ring - - Return Value: - NDIS_STATUS_FAILURE Not enough free descriptor - NDIS_STATUS_SUCCESS Enough free descriptor - - IRQL = PASSIVE_LEVEL - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ - -#ifdef RT2870 -/* - Actually, this function used to check if the TxHardware Queue still has frame need to send. - If no frame need to send, go to sleep, else, still wake up. -*/ -NDIS_STATUS RTMPFreeTXDRequest( - IN PRTMP_ADAPTER pAd, - IN UCHAR QueIdx, - IN UCHAR NumberRequired, - IN PUCHAR FreeNumberIs) -{ - //ULONG FreeNumber = 0; - NDIS_STATUS Status = NDIS_STATUS_FAILURE; - unsigned long IrqFlags; - HT_TX_CONTEXT *pHTTXContext; - - switch (QueIdx) - { - case QID_AC_BK: - case QID_AC_BE: - case QID_AC_VI: - case QID_AC_VO: - case QID_HCCA: - { - pHTTXContext = &pAd->TxContext[QueIdx]; - RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); - if ((pHTTXContext->CurWritePosition != pHTTXContext->ENextBulkOutPosition) || - (pHTTXContext->IRPPending == TRUE)) - { - Status = NDIS_STATUS_FAILURE; - } - else - { - Status = NDIS_STATUS_SUCCESS; - } - RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); - } - break; - - case QID_MGMT: - if (pAd->MgmtRing.TxSwFreeIdx != MGMT_RING_SIZE) - Status = NDIS_STATUS_FAILURE; - else - Status = NDIS_STATUS_SUCCESS; - break; - - default: - DBGPRINT(RT_DEBUG_ERROR,("RTMPFreeTXDRequest::Invalid QueIdx(=%d)\n", QueIdx)); - break; - } - - return (Status); - -} -#endif // RT2870 // - - -VOID RTMPSendDisassociationFrame( - IN PRTMP_ADAPTER pAd) -{ -} - -VOID RTMPSendNullFrame( - IN PRTMP_ADAPTER pAd, - IN UCHAR TxRate, - IN BOOLEAN bQosNull) -{ - UCHAR NullFrame[48]; - ULONG Length; - PHEADER_802_11 pHeader_802_11; - - -#ifdef RALINK_ATE - if(ATE_ON(pAd)) - { - return; - } -#endif // RALINK_ATE // - - // WPA 802.1x secured port control - if (((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || - (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) || - (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || - (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) -#ifdef WPA_SUPPLICANT_SUPPORT - || (pAd->StaCfg.IEEE8021X == TRUE) -#endif - ) && - (pAd->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED)) - { - return; - } - - NdisZeroMemory(NullFrame, 48); - Length = sizeof(HEADER_802_11); - - pHeader_802_11 = (PHEADER_802_11) NullFrame; - - pHeader_802_11->FC.Type = BTYPE_DATA; - pHeader_802_11->FC.SubType = SUBTYPE_NULL_FUNC; - pHeader_802_11->FC.ToDs = 1; - COPY_MAC_ADDR(pHeader_802_11->Addr1, pAd->CommonCfg.Bssid); - COPY_MAC_ADDR(pHeader_802_11->Addr2, pAd->CurrentAddress); - COPY_MAC_ADDR(pHeader_802_11->Addr3, pAd->CommonCfg.Bssid); - - if (pAd->CommonCfg.bAPSDForcePowerSave) - { - pHeader_802_11->FC.PwrMgmt = PWR_SAVE; - } - else - { - pHeader_802_11->FC.PwrMgmt = (pAd->StaCfg.Psm == PWR_SAVE) ? 1: 0; - } - pHeader_802_11->Duration = pAd->CommonCfg.Dsifs + RTMPCalcDuration(pAd, TxRate, 14); - - pAd->Sequence++; - pHeader_802_11->Sequence = pAd->Sequence; - - // Prepare QosNull function frame - if (bQosNull) - { - pHeader_802_11->FC.SubType = SUBTYPE_QOS_NULL; - - // copy QOS control bytes - NullFrame[Length] = 0; - NullFrame[Length+1] = 0; - Length += 2;// if pad with 2 bytes for alignment, APSD will fail - } - - HAL_KickOutNullFrameTx(pAd, 0, NullFrame, Length); - -} - -// IRQL = DISPATCH_LEVEL -VOID RTMPSendRTSFrame( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pDA, - IN unsigned int NextMpduSize, - IN UCHAR TxRate, - IN UCHAR RTSRate, - IN USHORT AckDuration, - IN UCHAR QueIdx, - IN UCHAR FrameGap) -{ -} - - - -// -------------------------------------------------------- -// FIND ENCRYPT KEY AND DECIDE CIPHER ALGORITHM -// Find the WPA key, either Group or Pairwise Key -// LEAP + TKIP also use WPA key. -// -------------------------------------------------------- -// Decide WEP bit and cipher suite to be used. Same cipher suite should be used for whole fragment burst -// In Cisco CCX 2.0 Leap Authentication -// WepStatus is Ndis802_11Encryption1Enabled but the key will use PairwiseKey -// Instead of the SharedKey, SharedKey Length may be Zero. -VOID STAFindCipherAlgorithm( - IN PRTMP_ADAPTER pAd, - IN TX_BLK *pTxBlk) -{ - NDIS_802_11_ENCRYPTION_STATUS Cipher; // To indicate cipher used for this packet - UCHAR CipherAlg = CIPHER_NONE; // cipher alogrithm - UCHAR KeyIdx = 0xff; - PUCHAR pSrcBufVA; - PCIPHER_KEY pKey = NULL; - - pSrcBufVA = GET_OS_PKT_DATAPTR(pTxBlk->pPacket); - - { - // Select Cipher - if ((*pSrcBufVA & 0x01) && (ADHOC_ON(pAd))) - Cipher = pAd->StaCfg.GroupCipher; // Cipher for Multicast or Broadcast - else - Cipher = pAd->StaCfg.PairCipher; // Cipher for Unicast - - if (RTMP_GET_PACKET_EAPOL(pTxBlk->pPacket)) - { - ASSERT(pAd->SharedKey[BSS0][0].CipherAlg <= CIPHER_CKIP128); - - // 4-way handshaking frame must be clear - if (!(TX_BLK_TEST_FLAG(pTxBlk, fTX_bClearEAPFrame)) && (pAd->SharedKey[BSS0][0].CipherAlg) && - (pAd->SharedKey[BSS0][0].KeyLen)) - { - CipherAlg = pAd->SharedKey[BSS0][0].CipherAlg; - KeyIdx = 0; - } - } - else if (Cipher == Ndis802_11Encryption1Enabled) - { -#ifdef LEAP_SUPPORT - if (pAd->StaCfg.CkipFlag & 0x10) // Cisco CKIP KP is on - { - if (LEAP_CCKM_ON(pAd)) - { - if (((*pSrcBufVA & 0x01) && (ADHOC_ON(pAd)))) - KeyIdx = 1; - else - KeyIdx = 0; - } - else - KeyIdx = pAd->StaCfg.DefaultKeyId; - } - else if (pAd->StaCfg.CkipFlag & 0x08) // only CKIP CMIC - KeyIdx = pAd->StaCfg.DefaultKeyId; - else if (LEAP_CCKM_ON(pAd)) - { - if ((*pSrcBufVA & 0x01) && (ADHOC_ON(pAd))) - KeyIdx = 1; - else - KeyIdx = 0; - } - else // standard WEP64 or WEP128 -#endif // LEAP_SUPPORT // - KeyIdx = pAd->StaCfg.DefaultKeyId; - } - else if ((Cipher == Ndis802_11Encryption2Enabled) || - (Cipher == Ndis802_11Encryption3Enabled)) - { - if ((*pSrcBufVA & 0x01) && (ADHOC_ON(pAd))) // multicast - KeyIdx = pAd->StaCfg.DefaultKeyId; - else if (pAd->SharedKey[BSS0][0].KeyLen) - KeyIdx = 0; - else - KeyIdx = pAd->StaCfg.DefaultKeyId; - } - - if (KeyIdx == 0xff) - CipherAlg = CIPHER_NONE; - else if ((Cipher == Ndis802_11EncryptionDisabled) || (pAd->SharedKey[BSS0][KeyIdx].KeyLen == 0)) - CipherAlg = CIPHER_NONE; -#ifdef WPA_SUPPLICANT_SUPPORT - else if ( pAd->StaCfg.WpaSupplicantUP && - (Cipher == Ndis802_11Encryption1Enabled) && - (pAd->StaCfg.IEEE8021X == TRUE) && - (pAd->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED)) - CipherAlg = CIPHER_NONE; -#endif // WPA_SUPPLICANT_SUPPORT // - else - { - //Header_802_11.FC.Wep = 1; - CipherAlg = pAd->SharedKey[BSS0][KeyIdx].CipherAlg; - pKey = &pAd->SharedKey[BSS0][KeyIdx]; - } - } - - pTxBlk->CipherAlg = CipherAlg; - pTxBlk->pKey = pKey; -} - - -VOID STABuildCommon802_11Header( - IN PRTMP_ADAPTER pAd, - IN TX_BLK *pTxBlk) -{ - - HEADER_802_11 *pHeader_802_11; -#ifdef QOS_DLS_SUPPORT - BOOLEAN bDLSFrame = FALSE; - INT DlsEntryIndex = 0; -#endif // QOS_DLS_SUPPORT // - - // - // MAKE A COMMON 802.11 HEADER - // - - // normal wlan header size : 24 octets - pTxBlk->MpduHeaderLen = sizeof(HEADER_802_11); - - pHeader_802_11 = (HEADER_802_11 *) &pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE]; - - NdisZeroMemory(pHeader_802_11, sizeof(HEADER_802_11)); - - pHeader_802_11->FC.FrDs = 0; - pHeader_802_11->FC.Type = BTYPE_DATA; - pHeader_802_11->FC.SubType = ((TX_BLK_TEST_FLAG(pTxBlk, fTX_bWMM)) ? SUBTYPE_QDATA : SUBTYPE_DATA); - -#ifdef QOS_DLS_SUPPORT - if (INFRA_ON(pAd)) - { - // Check if the frame can be sent through DLS direct link interface - // If packet can be sent through DLS, then force aggregation disable. (Hard to determine peer STA's capability) - DlsEntryIndex = RTMPCheckDLSFrame(pAd, pTxBlk->pSrcBufHeader); - if (DlsEntryIndex >= 0) - bDLSFrame = TRUE; - else - bDLSFrame = FALSE; - } -#endif // QOS_DLS_SUPPORT // - - if (pTxBlk->pMacEntry) - { - if (TX_BLK_TEST_FLAG(pTxBlk, fTX_bForceNonQoS)) - { - pHeader_802_11->Sequence = pTxBlk->pMacEntry->NonQosDataSeq; - pTxBlk->pMacEntry->NonQosDataSeq = (pTxBlk->pMacEntry->NonQosDataSeq+1) & MAXSEQ; - } - else - { -#ifdef QOS_DLS_SUPPORT - if (bDLSFrame) - { - pHeader_802_11->Sequence = pAd->StaCfg.DLSEntry[DlsEntryIndex].Sequence; - pAd->StaCfg.DLSEntry[DlsEntryIndex].Sequence = (pAd->StaCfg.DLSEntry[DlsEntryIndex].Sequence+1) & MAXSEQ; - } - else -#endif // QOS_DLS_SUPPORT // - { - pHeader_802_11->Sequence = pTxBlk->pMacEntry->TxSeq[pTxBlk->UserPriority]; - pTxBlk->pMacEntry->TxSeq[pTxBlk->UserPriority] = (pTxBlk->pMacEntry->TxSeq[pTxBlk->UserPriority]+1) & MAXSEQ; - } - } - } - else - { - pHeader_802_11->Sequence = pAd->Sequence; - pAd->Sequence = (pAd->Sequence+1) & MAXSEQ; // next sequence - } - - pHeader_802_11->Frag = 0; - - pHeader_802_11->FC.MoreData = TX_BLK_TEST_FLAG(pTxBlk, fTX_bMoreData); - - { - if (INFRA_ON(pAd)) - { -#ifdef QOS_DLS_SUPPORT - if (bDLSFrame) - { - COPY_MAC_ADDR(pHeader_802_11->Addr1, pTxBlk->pSrcBufHeader); - COPY_MAC_ADDR(pHeader_802_11->Addr2, pAd->CurrentAddress); - COPY_MAC_ADDR(pHeader_802_11->Addr3, pAd->CommonCfg.Bssid); - pHeader_802_11->FC.ToDs = 0; - } - else -#endif // QOS_DLS_SUPPORT // - { - COPY_MAC_ADDR(pHeader_802_11->Addr1, pAd->CommonCfg.Bssid); - COPY_MAC_ADDR(pHeader_802_11->Addr2, pAd->CurrentAddress); - COPY_MAC_ADDR(pHeader_802_11->Addr3, pTxBlk->pSrcBufHeader); - pHeader_802_11->FC.ToDs = 1; - } - } - else if (ADHOC_ON(pAd)) - { - COPY_MAC_ADDR(pHeader_802_11->Addr1, pTxBlk->pSrcBufHeader); - COPY_MAC_ADDR(pHeader_802_11->Addr2, pAd->CurrentAddress); - COPY_MAC_ADDR(pHeader_802_11->Addr3, pAd->CommonCfg.Bssid); - pHeader_802_11->FC.ToDs = 0; - } - } - - if (pTxBlk->CipherAlg != CIPHER_NONE) - pHeader_802_11->FC.Wep = 1; - - // ----------------------------------------------------------------- - // STEP 2. MAKE A COMMON 802.11 HEADER SHARED BY ENTIRE FRAGMENT BURST. Fill sequence later. - // ----------------------------------------------------------------- - if (pAd->CommonCfg.bAPSDForcePowerSave) - pHeader_802_11->FC.PwrMgmt = PWR_SAVE; - else - pHeader_802_11->FC.PwrMgmt = (pAd->StaCfg.Psm == PWR_SAVE); -} - -#ifdef DOT11_N_SUPPORT -VOID STABuildCache802_11Header( - IN RTMP_ADAPTER *pAd, - IN TX_BLK *pTxBlk, - IN UCHAR *pHeader) -{ - MAC_TABLE_ENTRY *pMacEntry; - PHEADER_802_11 pHeader80211; - - pHeader80211 = (PHEADER_802_11)pHeader; - pMacEntry = pTxBlk->pMacEntry; - - // - // Update the cached 802.11 HEADER - // - - // normal wlan header size : 24 octets - pTxBlk->MpduHeaderLen = sizeof(HEADER_802_11); - - // More Bit - pHeader80211->FC.MoreData = TX_BLK_TEST_FLAG(pTxBlk, fTX_bMoreData); - - // Sequence - pHeader80211->Sequence = pMacEntry->TxSeq[pTxBlk->UserPriority]; - pMacEntry->TxSeq[pTxBlk->UserPriority] = (pMacEntry->TxSeq[pTxBlk->UserPriority]+1) & MAXSEQ; - - { - // Check if the frame can be sent through DLS direct link interface - // If packet can be sent through DLS, then force aggregation disable. (Hard to determine peer STA's capability) -#ifdef QOS_DLS_SUPPORT - BOOLEAN bDLSFrame = FALSE; - INT DlsEntryIndex = 0; - - DlsEntryIndex = RTMPCheckDLSFrame(pAd, pTxBlk->pSrcBufHeader); - if (DlsEntryIndex >= 0) - bDLSFrame = TRUE; - else - bDLSFrame = FALSE; -#endif // QOS_DLS_SUPPORT // - - // The addr3 of normal packet send from DS is Dest Mac address. -#ifdef QOS_DLS_SUPPORT - if (bDLSFrame) - { - COPY_MAC_ADDR(pHeader80211->Addr1, pTxBlk->pSrcBufHeader); - COPY_MAC_ADDR(pHeader80211->Addr3, pAd->CommonCfg.Bssid); - pHeader80211->FC.ToDs = 0; - } - else -#endif // QOS_DLS_SUPPORT // - if (ADHOC_ON(pAd)) - COPY_MAC_ADDR(pHeader80211->Addr3, pAd->CommonCfg.Bssid); - else - COPY_MAC_ADDR(pHeader80211->Addr3, pTxBlk->pSrcBufHeader); - } - - // ----------------------------------------------------------------- - // STEP 2. MAKE A COMMON 802.11 HEADER SHARED BY ENTIRE FRAGMENT BURST. Fill sequence later. - // ----------------------------------------------------------------- - if (pAd->CommonCfg.bAPSDForcePowerSave) - pHeader80211->FC.PwrMgmt = PWR_SAVE; - else - pHeader80211->FC.PwrMgmt = (pAd->StaCfg.Psm == PWR_SAVE); -} -#endif // DOT11_N_SUPPORT // - -static inline PUCHAR STA_Build_ARalink_Frame_Header( - IN RTMP_ADAPTER *pAd, - IN TX_BLK *pTxBlk) -{ - PUCHAR pHeaderBufPtr; - HEADER_802_11 *pHeader_802_11; - PNDIS_PACKET pNextPacket; - UINT32 nextBufLen; - PQUEUE_ENTRY pQEntry; - - STAFindCipherAlgorithm(pAd, pTxBlk); - STABuildCommon802_11Header(pAd, pTxBlk); - - - pHeaderBufPtr = &pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE]; - pHeader_802_11 = (HEADER_802_11 *) pHeaderBufPtr; - - // steal "order" bit to mark "aggregation" - pHeader_802_11->FC.Order = 1; - - // skip common header - pHeaderBufPtr += pTxBlk->MpduHeaderLen; - - if (TX_BLK_TEST_FLAG(pTxBlk, fTX_bWMM)) - { - // - // build QOS Control bytes - // - *pHeaderBufPtr = (pTxBlk->UserPriority & 0x0F); - - *(pHeaderBufPtr+1) = 0; - pHeaderBufPtr +=2; - pTxBlk->MpduHeaderLen += 2; - } - - // padding at front of LLC header. LLC header should at 4-bytes aligment. - pTxBlk->HdrPadLen = (ULONG)pHeaderBufPtr; - pHeaderBufPtr = (PCHAR)ROUND_UP(pHeaderBufPtr, 4); - pTxBlk->HdrPadLen = (ULONG)(pHeaderBufPtr - pTxBlk->HdrPadLen); - - // For RA Aggregation, - // put the 2nd MSDU length(extra 2-byte field) after QOS_CONTROL in little endian format - pQEntry = pTxBlk->TxPacketList.Head; - pNextPacket = QUEUE_ENTRY_TO_PKT(pQEntry); - nextBufLen = GET_OS_PKT_LEN(pNextPacket); - if (RTMP_GET_PACKET_VLAN(pNextPacket)) - nextBufLen -= LENGTH_802_1Q; - - *pHeaderBufPtr = (UCHAR)nextBufLen & 0xff; - *(pHeaderBufPtr+1) = (UCHAR)(nextBufLen >> 8); - - pHeaderBufPtr += 2; - pTxBlk->MpduHeaderLen += 2; - - return pHeaderBufPtr; - -} - -#ifdef DOT11_N_SUPPORT -static inline PUCHAR STA_Build_AMSDU_Frame_Header( - IN RTMP_ADAPTER *pAd, - IN TX_BLK *pTxBlk) -{ - PUCHAR pHeaderBufPtr;//, pSaveBufPtr; - HEADER_802_11 *pHeader_802_11; - - - STAFindCipherAlgorithm(pAd, pTxBlk); - STABuildCommon802_11Header(pAd, pTxBlk); - - pHeaderBufPtr = &pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE]; - pHeader_802_11 = (HEADER_802_11 *) pHeaderBufPtr; - - // skip common header - pHeaderBufPtr += pTxBlk->MpduHeaderLen; - - // - // build QOS Control bytes - // - *pHeaderBufPtr = (pTxBlk->UserPriority & 0x0F); - - // - // A-MSDU packet - // - *pHeaderBufPtr |= 0x80; - - *(pHeaderBufPtr+1) = 0; - pHeaderBufPtr +=2; - pTxBlk->MpduHeaderLen += 2; - - //pSaveBufPtr = pHeaderBufPtr; - - // - // padding at front of LLC header - // LLC header should locate at 4-octets aligment - // - // @@@ MpduHeaderLen excluding padding @@@ - // - pTxBlk->HdrPadLen = (ULONG)pHeaderBufPtr; - pHeaderBufPtr = (PCHAR) ROUND_UP(pHeaderBufPtr, 4); - pTxBlk->HdrPadLen = (ULONG)(pHeaderBufPtr - pTxBlk->HdrPadLen); - - return pHeaderBufPtr; - -} - - -VOID STA_AMPDU_Frame_Tx( - IN PRTMP_ADAPTER pAd, - IN TX_BLK *pTxBlk) -{ - HEADER_802_11 *pHeader_802_11; - PUCHAR pHeaderBufPtr; - USHORT FreeNumber; - MAC_TABLE_ENTRY *pMacEntry; - BOOLEAN bVLANPkt; - PQUEUE_ENTRY pQEntry; - - ASSERT(pTxBlk); - - while(pTxBlk->TxPacketList.Head) - { - pQEntry = RemoveHeadQueue(&pTxBlk->TxPacketList); - pTxBlk->pPacket = QUEUE_ENTRY_TO_PACKET(pQEntry); - if ( RTMP_FillTxBlkInfo(pAd, pTxBlk) != TRUE) - { - RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_FAILURE); - continue; - } - - bVLANPkt = (RTMP_GET_PACKET_VLAN(pTxBlk->pPacket) ? TRUE : FALSE); - - pMacEntry = pTxBlk->pMacEntry; - if (pMacEntry->isCached) - { - // NOTE: Please make sure the size of pMacEntry->CachedBuf[] is smaller than pTxBlk->HeaderBuf[]!!!! - NdisMoveMemory((PUCHAR)&pTxBlk->HeaderBuf[TXINFO_SIZE], (PUCHAR)&pMacEntry->CachedBuf[0], TXWI_SIZE + sizeof(HEADER_802_11)); - pHeaderBufPtr = (PUCHAR)(&pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE]); - STABuildCache802_11Header(pAd, pTxBlk, pHeaderBufPtr); - } - else - { - STAFindCipherAlgorithm(pAd, pTxBlk); - STABuildCommon802_11Header(pAd, pTxBlk); - - pHeaderBufPtr = &pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE]; - } - - - pHeader_802_11 = (HEADER_802_11 *) pHeaderBufPtr; - - // skip common header - pHeaderBufPtr += pTxBlk->MpduHeaderLen; - - // - // build QOS Control bytes - // - *pHeaderBufPtr = (pTxBlk->UserPriority & 0x0F); - *(pHeaderBufPtr+1) = 0; - pHeaderBufPtr +=2; - pTxBlk->MpduHeaderLen += 2; - - // - // build HTC+ - // HTC control filed following QoS field - // - if ((pAd->CommonCfg.bRdg == TRUE) && CLIENT_STATUS_TEST_FLAG(pTxBlk->pMacEntry, fCLIENT_STATUS_RDG_CAPABLE)) - { - if (pMacEntry->isCached == FALSE) - { - // mark HTC bit - pHeader_802_11->FC.Order = 1; - - NdisZeroMemory(pHeaderBufPtr, 4); - *(pHeaderBufPtr+3) |= 0x80; - } - pHeaderBufPtr += 4; - pTxBlk->MpduHeaderLen += 4; - } - - //pTxBlk->MpduHeaderLen = pHeaderBufPtr - pTxBlk->HeaderBuf - TXWI_SIZE - TXINFO_SIZE; - ASSERT(pTxBlk->MpduHeaderLen >= 24); - - // skip 802.3 header - pTxBlk->pSrcBufData = pTxBlk->pSrcBufHeader + LENGTH_802_3; - pTxBlk->SrcBufLen -= LENGTH_802_3; - - // skip vlan tag - if (bVLANPkt) - { - pTxBlk->pSrcBufData += LENGTH_802_1Q; - pTxBlk->SrcBufLen -= LENGTH_802_1Q; - } - - // - // padding at front of LLC header - // LLC header should locate at 4-octets aligment - // - // @@@ MpduHeaderLen excluding padding @@@ - // - pTxBlk->HdrPadLen = (ULONG)pHeaderBufPtr; - pHeaderBufPtr = (PCHAR) ROUND_UP(pHeaderBufPtr, 4); - pTxBlk->HdrPadLen = (ULONG)(pHeaderBufPtr - pTxBlk->HdrPadLen); - - { - - // - // Insert LLC-SNAP encapsulation - 8 octets - // - EXTRA_LLCSNAP_ENCAP_FROM_PKT_OFFSET(pTxBlk->pSrcBufData-2, pTxBlk->pExtraLlcSnapEncap); - if (pTxBlk->pExtraLlcSnapEncap) - { - NdisMoveMemory(pHeaderBufPtr, pTxBlk->pExtraLlcSnapEncap, 6); - pHeaderBufPtr += 6; - // get 2 octets (TypeofLen) - NdisMoveMemory(pHeaderBufPtr, pTxBlk->pSrcBufData-2, 2); - pHeaderBufPtr += 2; - pTxBlk->MpduHeaderLen += LENGTH_802_1_H; - } - - } - - if (pMacEntry->isCached) - { - RTMPWriteTxWI_Cache(pAd, (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), pTxBlk); - } - else - { - RTMPWriteTxWI_Data(pAd, (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), pTxBlk); - - NdisZeroMemory((PUCHAR)(&pMacEntry->CachedBuf[0]), sizeof(pMacEntry->CachedBuf)); - NdisMoveMemory((PUCHAR)(&pMacEntry->CachedBuf[0]), (PUCHAR)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), (pHeaderBufPtr - (PUCHAR)(&pTxBlk->HeaderBuf[TXINFO_SIZE]))); - pMacEntry->isCached = TRUE; - } - - // calculate Transmitted AMPDU count and ByteCount - { - pAd->RalinkCounters.TransmittedMPDUsInAMPDUCount.u.LowPart ++; - pAd->RalinkCounters.TransmittedOctetsInAMPDUCount.QuadPart += pTxBlk->SrcBufLen; - } - - //FreeNumber = GET_TXRING_FREENO(pAd, QueIdx); - - HAL_WriteTxResource(pAd, pTxBlk, TRUE, &FreeNumber); - - // - // Kick out Tx - // - HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx); - - pAd->RalinkCounters.KickTxCount++; - pAd->RalinkCounters.OneSecTxDoneCount++; - } - -} - - -VOID STA_AMSDU_Frame_Tx( - IN PRTMP_ADAPTER pAd, - IN TX_BLK *pTxBlk) -{ - PUCHAR pHeaderBufPtr; - USHORT FreeNumber; - USHORT subFramePayloadLen = 0; // AMSDU Subframe length without AMSDU-Header / Padding. - USHORT totalMPDUSize=0; - UCHAR *subFrameHeader; - UCHAR padding = 0; - USHORT FirstTx = 0, LastTxIdx = 0; - BOOLEAN bVLANPkt; - int frameNum = 0; - PQUEUE_ENTRY pQEntry; - - - ASSERT(pTxBlk); - - ASSERT((pTxBlk->TxPacketList.Number > 1)); - - while(pTxBlk->TxPacketList.Head) - { - pQEntry = RemoveHeadQueue(&pTxBlk->TxPacketList); - pTxBlk->pPacket = QUEUE_ENTRY_TO_PACKET(pQEntry); - if (RTMP_FillTxBlkInfo(pAd, pTxBlk) != TRUE) - { - RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_FAILURE); - continue; - } - - bVLANPkt = (RTMP_GET_PACKET_VLAN(pTxBlk->pPacket) ? TRUE : FALSE); - - // skip 802.3 header - pTxBlk->pSrcBufData = pTxBlk->pSrcBufHeader + LENGTH_802_3; - pTxBlk->SrcBufLen -= LENGTH_802_3; - - // skip vlan tag - if (bVLANPkt) - { - pTxBlk->pSrcBufData += LENGTH_802_1Q; - pTxBlk->SrcBufLen -= LENGTH_802_1Q; - } - - if (frameNum == 0) - { - pHeaderBufPtr = STA_Build_AMSDU_Frame_Header(pAd, pTxBlk); - - // NOTE: TxWI->MPDUtotalByteCount will be updated after final frame was handled. - RTMPWriteTxWI_Data(pAd, (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), pTxBlk); - } - else - { - pHeaderBufPtr = &pTxBlk->HeaderBuf[0]; - padding = ROUND_UP(LENGTH_AMSDU_SUBFRAMEHEAD + subFramePayloadLen, 4) - (LENGTH_AMSDU_SUBFRAMEHEAD + subFramePayloadLen); - NdisZeroMemory(pHeaderBufPtr, padding + LENGTH_AMSDU_SUBFRAMEHEAD); - pHeaderBufPtr += padding; - pTxBlk->MpduHeaderLen = padding; - } - - // - // A-MSDU subframe - // DA(6)+SA(6)+Length(2) + LLC/SNAP Encap - // - subFrameHeader = pHeaderBufPtr; - subFramePayloadLen = pTxBlk->SrcBufLen; - - NdisMoveMemory(subFrameHeader, pTxBlk->pSrcBufHeader, 12); - - - pHeaderBufPtr += LENGTH_AMSDU_SUBFRAMEHEAD; - pTxBlk->MpduHeaderLen += LENGTH_AMSDU_SUBFRAMEHEAD; - - - // - // Insert LLC-SNAP encapsulation - 8 octets - // - EXTRA_LLCSNAP_ENCAP_FROM_PKT_OFFSET(pTxBlk->pSrcBufData-2, pTxBlk->pExtraLlcSnapEncap); - - subFramePayloadLen = pTxBlk->SrcBufLen; - - if (pTxBlk->pExtraLlcSnapEncap) - { - NdisMoveMemory(pHeaderBufPtr, pTxBlk->pExtraLlcSnapEncap, 6); - pHeaderBufPtr += 6; - // get 2 octets (TypeofLen) - NdisMoveMemory(pHeaderBufPtr, pTxBlk->pSrcBufData-2, 2); - pHeaderBufPtr += 2; - pTxBlk->MpduHeaderLen += LENGTH_802_1_H; - subFramePayloadLen += LENGTH_802_1_H; - } - - // update subFrame Length field - subFrameHeader[12] = (subFramePayloadLen & 0xFF00) >> 8; - subFrameHeader[13] = subFramePayloadLen & 0xFF; - - totalMPDUSize += pTxBlk->MpduHeaderLen + pTxBlk->SrcBufLen; - - if (frameNum ==0) - FirstTx = HAL_WriteMultiTxResource(pAd, pTxBlk, frameNum, &FreeNumber); - else - LastTxIdx = HAL_WriteMultiTxResource(pAd, pTxBlk, frameNum, &FreeNumber); - - frameNum++; - - pAd->RalinkCounters.KickTxCount++; - pAd->RalinkCounters.OneSecTxDoneCount++; - - // calculate Transmitted AMSDU Count and ByteCount - { - pAd->RalinkCounters.TransmittedAMSDUCount.u.LowPart ++; - pAd->RalinkCounters.TransmittedOctetsInAMSDU.QuadPart += totalMPDUSize; - } - - } - - HAL_FinalWriteTxResource(pAd, pTxBlk, totalMPDUSize, FirstTx); - HAL_LastTxIdx(pAd, pTxBlk->QueIdx, LastTxIdx); - - // - // Kick out Tx - // - HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx); -} -#endif // DOT11_N_SUPPORT // - -VOID STA_Legacy_Frame_Tx( - IN PRTMP_ADAPTER pAd, - IN TX_BLK *pTxBlk) -{ - HEADER_802_11 *pHeader_802_11; - PUCHAR pHeaderBufPtr; - USHORT FreeNumber; - BOOLEAN bVLANPkt; - PQUEUE_ENTRY pQEntry; - - ASSERT(pTxBlk); - - - pQEntry = RemoveHeadQueue(&pTxBlk->TxPacketList); - pTxBlk->pPacket = QUEUE_ENTRY_TO_PACKET(pQEntry); - if (RTMP_FillTxBlkInfo(pAd, pTxBlk) != TRUE) - { - RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_FAILURE); - return; - } - - if (pTxBlk->TxFrameType == TX_MCAST_FRAME) - { - INC_COUNTER64(pAd->WlanCounters.MulticastTransmittedFrameCount); - } - - if (RTMP_GET_PACKET_RTS(pTxBlk->pPacket)) - TX_BLK_SET_FLAG(pTxBlk, fTX_bRtsRequired); - else - TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bRtsRequired); - - bVLANPkt = (RTMP_GET_PACKET_VLAN(pTxBlk->pPacket) ? TRUE : FALSE); - - if (pTxBlk->TxRate < pAd->CommonCfg.MinTxRate) - pTxBlk->TxRate = pAd->CommonCfg.MinTxRate; - - STAFindCipherAlgorithm(pAd, pTxBlk); - STABuildCommon802_11Header(pAd, pTxBlk); - - - // skip 802.3 header - pTxBlk->pSrcBufData = pTxBlk->pSrcBufHeader + LENGTH_802_3; - pTxBlk->SrcBufLen -= LENGTH_802_3; - - // skip vlan tag - if (bVLANPkt) - { - pTxBlk->pSrcBufData += LENGTH_802_1Q; - pTxBlk->SrcBufLen -= LENGTH_802_1Q; - } - - pHeaderBufPtr = &pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE]; - pHeader_802_11 = (HEADER_802_11 *) pHeaderBufPtr; - - // skip common header - pHeaderBufPtr += pTxBlk->MpduHeaderLen; - - if (TX_BLK_TEST_FLAG(pTxBlk, fTX_bWMM)) - { - // - // build QOS Control bytes - // - *pHeaderBufPtr = (pTxBlk->UserPriority & 0x0F); - *(pHeaderBufPtr+1) = 0; - pHeaderBufPtr +=2; - pTxBlk->MpduHeaderLen += 2; - } - - // The remaining content of MPDU header should locate at 4-octets aligment - pTxBlk->HdrPadLen = (ULONG)pHeaderBufPtr; - pHeaderBufPtr = (PCHAR) ROUND_UP(pHeaderBufPtr, 4); - pTxBlk->HdrPadLen = (ULONG)(pHeaderBufPtr - pTxBlk->HdrPadLen); - - { - - // - // Insert LLC-SNAP encapsulation - 8 octets - // - // - // if original Ethernet frame contains no LLC/SNAP, - // then an extra LLC/SNAP encap is required - // - EXTRA_LLCSNAP_ENCAP_FROM_PKT_START(pTxBlk->pSrcBufHeader, pTxBlk->pExtraLlcSnapEncap); - if (pTxBlk->pExtraLlcSnapEncap) - { - UCHAR vlan_size; - - NdisMoveMemory(pHeaderBufPtr, pTxBlk->pExtraLlcSnapEncap, 6); - pHeaderBufPtr += 6; - // skip vlan tag - vlan_size = (bVLANPkt) ? LENGTH_802_1Q : 0; - // get 2 octets (TypeofLen) - NdisMoveMemory(pHeaderBufPtr, pTxBlk->pSrcBufHeader+12+vlan_size, 2); - pHeaderBufPtr += 2; - pTxBlk->MpduHeaderLen += LENGTH_802_1_H; - } - - } - - // - // prepare for TXWI - // use Wcid as Key Index - // - - RTMPWriteTxWI_Data(pAd, (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), pTxBlk); - - //FreeNumber = GET_TXRING_FREENO(pAd, QueIdx); - - HAL_WriteTxResource(pAd, pTxBlk, TRUE, &FreeNumber); - - pAd->RalinkCounters.KickTxCount++; - pAd->RalinkCounters.OneSecTxDoneCount++; - - // - // Kick out Tx - // - HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx); -} - - -VOID STA_ARalink_Frame_Tx( - IN PRTMP_ADAPTER pAd, - IN TX_BLK *pTxBlk) -{ - PUCHAR pHeaderBufPtr; - USHORT FreeNumber; - USHORT totalMPDUSize=0; - USHORT FirstTx, LastTxIdx; - int frameNum = 0; - BOOLEAN bVLANPkt; - PQUEUE_ENTRY pQEntry; - - - ASSERT(pTxBlk); - - ASSERT((pTxBlk->TxPacketList.Number== 2)); - - - FirstTx = LastTxIdx = 0; // Is it ok init they as 0? - while(pTxBlk->TxPacketList.Head) - { - pQEntry = RemoveHeadQueue(&pTxBlk->TxPacketList); - pTxBlk->pPacket = QUEUE_ENTRY_TO_PACKET(pQEntry); - - if (RTMP_FillTxBlkInfo(pAd, pTxBlk) != TRUE) - { - RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_FAILURE); - continue; - } - - bVLANPkt = (RTMP_GET_PACKET_VLAN(pTxBlk->pPacket) ? TRUE : FALSE); - - // skip 802.3 header - pTxBlk->pSrcBufData = pTxBlk->pSrcBufHeader + LENGTH_802_3; - pTxBlk->SrcBufLen -= LENGTH_802_3; - - // skip vlan tag - if (bVLANPkt) - { - pTxBlk->pSrcBufData += LENGTH_802_1Q; - pTxBlk->SrcBufLen -= LENGTH_802_1Q; - } - - if (frameNum == 0) - { // For first frame, we need to create the 802.11 header + padding(optional) + RA-AGG-LEN + SNAP Header - - pHeaderBufPtr = STA_Build_ARalink_Frame_Header(pAd, pTxBlk); - - // It's ok write the TxWI here, because the TxWI->MPDUtotalByteCount - // will be updated after final frame was handled. - RTMPWriteTxWI_Data(pAd, (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), pTxBlk); - - - // - // Insert LLC-SNAP encapsulation - 8 octets - // - EXTRA_LLCSNAP_ENCAP_FROM_PKT_OFFSET(pTxBlk->pSrcBufData-2, pTxBlk->pExtraLlcSnapEncap); - - if (pTxBlk->pExtraLlcSnapEncap) - { - NdisMoveMemory(pHeaderBufPtr, pTxBlk->pExtraLlcSnapEncap, 6); - pHeaderBufPtr += 6; - // get 2 octets (TypeofLen) - NdisMoveMemory(pHeaderBufPtr, pTxBlk->pSrcBufData-2, 2); - pHeaderBufPtr += 2; - pTxBlk->MpduHeaderLen += LENGTH_802_1_H; - } - } - else - { // For second aggregated frame, we need create the 802.3 header to headerBuf, because PCI will copy it to SDPtr0. - - pHeaderBufPtr = &pTxBlk->HeaderBuf[0]; - pTxBlk->MpduHeaderLen = 0; - - // A-Ralink sub-sequent frame header is the same as 802.3 header. - // DA(6)+SA(6)+FrameType(2) - NdisMoveMemory(pHeaderBufPtr, pTxBlk->pSrcBufHeader, 12); - pHeaderBufPtr += 12; - // get 2 octets (TypeofLen) - NdisMoveMemory(pHeaderBufPtr, pTxBlk->pSrcBufData-2, 2); - pHeaderBufPtr += 2; - pTxBlk->MpduHeaderLen = LENGTH_ARALINK_SUBFRAMEHEAD; - } - - totalMPDUSize += pTxBlk->MpduHeaderLen + pTxBlk->SrcBufLen; - - //FreeNumber = GET_TXRING_FREENO(pAd, QueIdx); - if (frameNum ==0) - FirstTx = HAL_WriteMultiTxResource(pAd, pTxBlk, frameNum, &FreeNumber); - else - LastTxIdx = HAL_WriteMultiTxResource(pAd, pTxBlk, frameNum, &FreeNumber); - - frameNum++; - - pAd->RalinkCounters.OneSecTxAggregationCount++; - pAd->RalinkCounters.KickTxCount++; - pAd->RalinkCounters.OneSecTxDoneCount++; - - } - - HAL_FinalWriteTxResource(pAd, pTxBlk, totalMPDUSize, FirstTx); - HAL_LastTxIdx(pAd, pTxBlk->QueIdx, LastTxIdx); - - // - // Kick out Tx - // - HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx); - -} - - -VOID STA_Fragment_Frame_Tx( - IN RTMP_ADAPTER *pAd, - IN TX_BLK *pTxBlk) -{ - HEADER_802_11 *pHeader_802_11; - PUCHAR pHeaderBufPtr; - USHORT FreeNumber; - UCHAR fragNum = 0; - PACKET_INFO PacketInfo; - USHORT EncryptionOverhead = 0; - UINT32 FreeMpduSize, SrcRemainingBytes; - USHORT AckDuration; - UINT NextMpduSize; - BOOLEAN bVLANPkt; - PQUEUE_ENTRY pQEntry; - - - ASSERT(pTxBlk); - - pQEntry = RemoveHeadQueue(&pTxBlk->TxPacketList); - pTxBlk->pPacket = QUEUE_ENTRY_TO_PACKET(pQEntry); - if (RTMP_FillTxBlkInfo(pAd, pTxBlk) != TRUE) - { - RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_FAILURE); - return; - } - - ASSERT(TX_BLK_TEST_FLAG(pTxBlk, fTX_bAllowFrag)); - bVLANPkt = (RTMP_GET_PACKET_VLAN(pTxBlk->pPacket) ? TRUE : FALSE); - - STAFindCipherAlgorithm(pAd, pTxBlk); - STABuildCommon802_11Header(pAd, pTxBlk); - - if (pTxBlk->CipherAlg == CIPHER_TKIP) - { - pTxBlk->pPacket = duplicate_pkt_with_TKIP_MIC(pAd, pTxBlk->pPacket); - if (pTxBlk->pPacket == NULL) - return; - RTMP_QueryPacketInfo(pTxBlk->pPacket, &PacketInfo, &pTxBlk->pSrcBufHeader, &pTxBlk->SrcBufLen); - } - - // skip 802.3 header - pTxBlk->pSrcBufData = pTxBlk->pSrcBufHeader + LENGTH_802_3; - pTxBlk->SrcBufLen -= LENGTH_802_3; - - - // skip vlan tag - if (bVLANPkt) - { - pTxBlk->pSrcBufData += LENGTH_802_1Q; - pTxBlk->SrcBufLen -= LENGTH_802_1Q; - } - - pHeaderBufPtr = &pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE]; - pHeader_802_11 = (HEADER_802_11 *)pHeaderBufPtr; - - - // skip common header - pHeaderBufPtr += pTxBlk->MpduHeaderLen; - - if (TX_BLK_TEST_FLAG(pTxBlk, fTX_bWMM)) - { - // - // build QOS Control bytes - // - *pHeaderBufPtr = (pTxBlk->UserPriority & 0x0F); - - *(pHeaderBufPtr+1) = 0; - pHeaderBufPtr +=2; - pTxBlk->MpduHeaderLen += 2; - } - - // - // padding at front of LLC header - // LLC header should locate at 4-octets aligment - // - pTxBlk->HdrPadLen = (ULONG)pHeaderBufPtr; - pHeaderBufPtr = (PCHAR) ROUND_UP(pHeaderBufPtr, 4); - pTxBlk->HdrPadLen = (ULONG)(pHeaderBufPtr - pTxBlk->HdrPadLen); - - - - // - // Insert LLC-SNAP encapsulation - 8 octets - // - // - // if original Ethernet frame contains no LLC/SNAP, - // then an extra LLC/SNAP encap is required - // - EXTRA_LLCSNAP_ENCAP_FROM_PKT_START(pTxBlk->pSrcBufHeader, pTxBlk->pExtraLlcSnapEncap); - if (pTxBlk->pExtraLlcSnapEncap) - { - UCHAR vlan_size; - - NdisMoveMemory(pHeaderBufPtr, pTxBlk->pExtraLlcSnapEncap, 6); - pHeaderBufPtr += 6; - // skip vlan tag - vlan_size = (bVLANPkt) ? LENGTH_802_1Q : 0; - // get 2 octets (TypeofLen) - NdisMoveMemory(pHeaderBufPtr, pTxBlk->pSrcBufHeader+12+vlan_size, 2); - pHeaderBufPtr += 2; - pTxBlk->MpduHeaderLen += LENGTH_802_1_H; - } - - - // If TKIP is used and fragmentation is required. Driver has to - // append TKIP MIC at tail of the scatter buffer - // MAC ASIC will only perform IV/EIV/ICV insertion but no TKIP MIC - if (pTxBlk->CipherAlg == CIPHER_TKIP) - { - - // NOTE: DON'T refer the skb->len directly after following copy. Becasue the length is not adjust - // to correct lenght, refer to pTxBlk->SrcBufLen for the packet length in following progress. - NdisMoveMemory(pTxBlk->pSrcBufData + pTxBlk->SrcBufLen, &pAd->PrivateInfo.Tx.MIC[0], 8); - //skb_put((RTPKT_TO_OSPKT(pTxBlk->pPacket))->tail, 8); - pTxBlk->SrcBufLen += 8; - pTxBlk->TotalFrameLen += 8; - pTxBlk->CipherAlg = CIPHER_TKIP_NO_MIC; - } - - // - // calcuate the overhead bytes that encryption algorithm may add. This - // affects the calculate of "duration" field - // - if ((pTxBlk->CipherAlg == CIPHER_WEP64) || (pTxBlk->CipherAlg == CIPHER_WEP128)) - EncryptionOverhead = 8; //WEP: IV[4] + ICV[4]; - else if (pTxBlk->CipherAlg == CIPHER_TKIP_NO_MIC) - EncryptionOverhead = 12;//TKIP: IV[4] + EIV[4] + ICV[4], MIC will be added to TotalPacketLength - else if (pTxBlk->CipherAlg == CIPHER_TKIP) - EncryptionOverhead = 20;//TKIP: IV[4] + EIV[4] + ICV[4] + MIC[8] - else if (pTxBlk->CipherAlg == CIPHER_AES) - EncryptionOverhead = 16; // AES: IV[4] + EIV[4] + MIC[8] - else - EncryptionOverhead = 0; - - // decide how much time an ACK/CTS frame will consume in the air - AckDuration = RTMPCalcDuration(pAd, pAd->CommonCfg.ExpectedACKRate[pTxBlk->TxRate], 14); - - // Init the total payload length of this frame. - SrcRemainingBytes = pTxBlk->SrcBufLen; - - pTxBlk->TotalFragNum = 0xff; - - do { - - FreeMpduSize = pAd->CommonCfg.FragmentThreshold - LENGTH_CRC; - - FreeMpduSize -= pTxBlk->MpduHeaderLen; - - if (SrcRemainingBytes <= FreeMpduSize) - { // this is the last or only fragment - - pTxBlk->SrcBufLen = SrcRemainingBytes; - - pHeader_802_11->FC.MoreFrag = 0; - pHeader_802_11->Duration = pAd->CommonCfg.Dsifs + AckDuration; - - // Indicate the lower layer that this's the last fragment. - pTxBlk->TotalFragNum = fragNum; - } - else - { // more fragment is required - - pTxBlk->SrcBufLen = FreeMpduSize; - - NextMpduSize = min(((UINT)SrcRemainingBytes - pTxBlk->SrcBufLen), ((UINT)pAd->CommonCfg.FragmentThreshold)); - pHeader_802_11->FC.MoreFrag = 1; - pHeader_802_11->Duration = (3 * pAd->CommonCfg.Dsifs) + (2 * AckDuration) + RTMPCalcDuration(pAd, pTxBlk->TxRate, NextMpduSize + EncryptionOverhead); - } - - if (fragNum == 0) - pTxBlk->FrameGap = IFS_HTTXOP; - else - pTxBlk->FrameGap = IFS_SIFS; - - RTMPWriteTxWI_Data(pAd, (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), pTxBlk); - - HAL_WriteFragTxResource(pAd, pTxBlk, fragNum, &FreeNumber); - - pAd->RalinkCounters.KickTxCount++; - pAd->RalinkCounters.OneSecTxDoneCount++; - - // Update the frame number, remaining size of the NDIS packet payload. - - // space for 802.11 header. - if (fragNum == 0 && pTxBlk->pExtraLlcSnapEncap) - pTxBlk->MpduHeaderLen -= LENGTH_802_1_H; - - fragNum++; - SrcRemainingBytes -= pTxBlk->SrcBufLen; - pTxBlk->pSrcBufData += pTxBlk->SrcBufLen; - - pHeader_802_11->Frag++; // increase Frag # - - }while(SrcRemainingBytes > 0); - - // - // Kick out Tx - // - HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx); -} - - -#define RELEASE_FRAMES_OF_TXBLK(_pAd, _pTxBlk, _pQEntry, _Status) \ - while(_pTxBlk->TxPacketList.Head) \ - { \ - _pQEntry = RemoveHeadQueue(&_pTxBlk->TxPacketList); \ - RELEASE_NDIS_PACKET(_pAd, QUEUE_ENTRY_TO_PACKET(_pQEntry), _Status); \ - } - - -/* - ======================================================================== - - Routine Description: - Copy frame from waiting queue into relative ring buffer and set - appropriate ASIC register to kick hardware encryption before really - sent out to air. - - Arguments: - pAd Pointer to our adapter - PNDIS_PACKET Pointer to outgoing Ndis frame - NumberOfFrag Number of fragment required - - Return Value: - None - - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -NDIS_STATUS STAHardTransmit( - IN PRTMP_ADAPTER pAd, - IN TX_BLK *pTxBlk, - IN UCHAR QueIdx) -{ - NDIS_PACKET *pPacket; - PQUEUE_ENTRY pQEntry; - - // --------------------------------------------- - // STEP 0. DO SANITY CHECK AND SOME EARLY PREPARATION. - // --------------------------------------------- - // - ASSERT(pTxBlk->TxPacketList.Number); - if (pTxBlk->TxPacketList.Head == NULL) - { - DBGPRINT(RT_DEBUG_ERROR, ("pTxBlk->TotalFrameNum == %ld!\n", pTxBlk->TxPacketList.Number)); - return NDIS_STATUS_FAILURE; - } - - pPacket = QUEUE_ENTRY_TO_PACKET(pTxBlk->TxPacketList.Head); - - // ------------------------------------------------------------------ - // STEP 1. WAKE UP PHY - // outgoing frame always wakeup PHY to prevent frame lost and - // turn off PSM bit to improve performance - // ------------------------------------------------------------------ - // not to change PSM bit, just send this frame out? - if ((pAd->StaCfg.Psm == PWR_SAVE) && OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) - { - DBGPRINT_RAW(RT_DEBUG_TRACE, ("AsicForceWakeup At HardTx\n")); - AsicForceWakeup(pAd, TRUE); - } - - // It should not change PSM bit, when APSD turn on. - if ((!(pAd->CommonCfg.bAPSDCapable && pAd->CommonCfg.APEdcaParm.bAPSDCapable) && (pAd->CommonCfg.bAPSDForcePowerSave == FALSE)) - || (RTMP_GET_PACKET_EAPOL(pTxBlk->pPacket)) - || (RTMP_GET_PACKET_WAI(pTxBlk->pPacket))) - { - if ((pAd->StaCfg.Psm == PWR_SAVE) && - (pAd->StaCfg.WindowsPowerMode == Ndis802_11PowerModeFast_PSP)) - MlmeSetPsmBit(pAd, PWR_ACTIVE); - } - - switch (pTxBlk->TxFrameType) - { -#ifdef DOT11_N_SUPPORT - case TX_AMPDU_FRAME: - STA_AMPDU_Frame_Tx(pAd, pTxBlk); - break; - case TX_AMSDU_FRAME: - STA_AMSDU_Frame_Tx(pAd, pTxBlk); - break; -#endif // DOT11_N_SUPPORT // - case TX_LEGACY_FRAME: - STA_Legacy_Frame_Tx(pAd, pTxBlk); - break; - case TX_MCAST_FRAME: - STA_Legacy_Frame_Tx(pAd, pTxBlk); - break; - case TX_RALINK_FRAME: - STA_ARalink_Frame_Tx(pAd, pTxBlk); - break; - case TX_FRAG_FRAME: - STA_Fragment_Frame_Tx(pAd, pTxBlk); - break; - default: - { - // It should not happened! - DBGPRINT(RT_DEBUG_ERROR, ("Send a pacekt was not classified!! It should not happen!\n")); - while(pTxBlk->TxPacketList.Number) - { - pQEntry = RemoveHeadQueue(&pTxBlk->TxPacketList); - pPacket = QUEUE_ENTRY_TO_PACKET(pQEntry); - if (pPacket) - RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); - } - } - break; - } - - return (NDIS_STATUS_SUCCESS); - -} - -ULONG HashBytesPolynomial(UCHAR *value, unsigned int len) -{ - unsigned char *word = value; - unsigned int ret = 0; - unsigned int i; - - for(i=0; i < len; i++) - { - int mod = i % 32; - ret ^=(unsigned int) (word[i]) << mod; - ret ^=(unsigned int) (word[i]) >> (32 - mod); - } - return ret; -} - -VOID Sta_Announce_or_Forward_802_3_Packet( - IN PRTMP_ADAPTER pAd, - IN PNDIS_PACKET pPacket, - IN UCHAR FromWhichBSSID) -{ - if (TRUE - ) - { - announce_802_3_packet(pAd, pPacket); - } - else - { - // release packet - RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); - } -} - +#include "../../rt2870/sta/rtmp_data.c" diff --git a/drivers/staging/rt3070/sta/sanity.c b/drivers/staging/rt3070/sta/sanity.c index 239872464bed..b4954779b316 100644 --- a/drivers/staging/rt3070/sta/sanity.c +++ b/drivers/staging/rt3070/sta/sanity.c @@ -1,420 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - sanity.c - - Abstract: - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - John Chang 2004-09-01 add WMM support -*/ -#include "../rt_config.h" - -extern UCHAR CISCO_OUI[]; - -extern UCHAR WPA_OUI[]; -extern UCHAR RSN_OUI[]; -extern UCHAR WME_INFO_ELEM[]; -extern UCHAR WME_PARM_ELEM[]; -extern UCHAR Ccx2QosInfo[]; -extern UCHAR RALINK_OUI[]; -extern UCHAR BROADCOM_OUI[]; - -/* - ========================================================================== - Description: - MLME message sanity check - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== - */ -BOOLEAN MlmeStartReqSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT CHAR Ssid[], - OUT UCHAR *pSsidLen) -{ - MLME_START_REQ_STRUCT *Info; - - Info = (MLME_START_REQ_STRUCT *)(Msg); - - if (Info->SsidLen > MAX_LEN_OF_SSID) - { - DBGPRINT(RT_DEBUG_TRACE, ("MlmeStartReqSanity fail - wrong SSID length\n")); - return FALSE; - } - - *pSsidLen = Info->SsidLen; - NdisMoveMemory(Ssid, Info->Ssid, *pSsidLen); - - return TRUE; -} - -/* - ========================================================================== - Description: - MLME message sanity check - Return: - TRUE if all parameters are OK, FALSE otherwise - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -BOOLEAN PeerAssocRspSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *pMsg, - IN ULONG MsgLen, - OUT PUCHAR pAddr2, - OUT USHORT *pCapabilityInfo, - OUT USHORT *pStatus, - OUT USHORT *pAid, - OUT UCHAR SupRate[], - OUT UCHAR *pSupRateLen, - OUT UCHAR ExtRate[], - OUT UCHAR *pExtRateLen, - OUT HT_CAPABILITY_IE *pHtCapability, - OUT ADD_HT_INFO_IE *pAddHtInfo, // AP might use this additional ht info IE - OUT UCHAR *pHtCapabilityLen, - OUT UCHAR *pAddHtInfoLen, - OUT UCHAR *pNewExtChannelOffset, - OUT PEDCA_PARM pEdcaParm, - OUT UCHAR *pCkipFlag) -{ - CHAR IeType, *Ptr; - PFRAME_802_11 pFrame = (PFRAME_802_11)pMsg; - PEID_STRUCT pEid; - ULONG Length = 0; - - *pNewExtChannelOffset = 0xff; - *pHtCapabilityLen = 0; - *pAddHtInfoLen = 0; - COPY_MAC_ADDR(pAddr2, pFrame->Hdr.Addr2); - Ptr = pFrame->Octet; - Length += LENGTH_802_11; - - NdisMoveMemory(pCapabilityInfo, &pFrame->Octet[0], 2); - Length += 2; - NdisMoveMemory(pStatus, &pFrame->Octet[2], 2); - Length += 2; - *pCkipFlag = 0; - *pExtRateLen = 0; - pEdcaParm->bValid = FALSE; - - if (*pStatus != MLME_SUCCESS) - return TRUE; - - NdisMoveMemory(pAid, &pFrame->Octet[4], 2); - Length += 2; - - // Aid already swaped byte order in RTMPFrameEndianChange() for big endian platform - *pAid = (*pAid) & 0x3fff; // AID is low 14-bit - - // -- get supported rates from payload and advance the pointer - IeType = pFrame->Octet[6]; - *pSupRateLen = pFrame->Octet[7]; - if ((IeType != IE_SUPP_RATES) || (*pSupRateLen > MAX_LEN_OF_SUPPORTED_RATES)) - { - DBGPRINT(RT_DEBUG_TRACE, ("PeerAssocRspSanity fail - wrong SupportedRates IE\n")); - return FALSE; - } - else - NdisMoveMemory(SupRate, &pFrame->Octet[8], *pSupRateLen); - - Length = Length + 2 + *pSupRateLen; - - // many AP implement proprietary IEs in non-standard order, we'd better - // tolerate mis-ordered IEs to get best compatibility - pEid = (PEID_STRUCT) &pFrame->Octet[8 + (*pSupRateLen)]; - - // get variable fields from payload and advance the pointer - while ((Length + 2 + pEid->Len) <= MsgLen) - { - switch (pEid->Eid) - { - case IE_EXT_SUPP_RATES: - if (pEid->Len <= MAX_LEN_OF_SUPPORTED_RATES) - { - NdisMoveMemory(ExtRate, pEid->Octet, pEid->Len); - *pExtRateLen = pEid->Len; - } - break; - - case IE_HT_CAP: - case IE_HT_CAP2: - if (pEid->Len >= SIZE_HT_CAP_IE) //Note: allow extension.!! - { - NdisMoveMemory(pHtCapability, pEid->Octet, SIZE_HT_CAP_IE); - - *(USHORT *)(&pHtCapability->HtCapInfo) = cpu2le16(*(USHORT *)(&pHtCapability->HtCapInfo)); - *(USHORT *)(&pHtCapability->ExtHtCapInfo) = cpu2le16(*(USHORT *)(&pHtCapability->ExtHtCapInfo)); - - *pHtCapabilityLen = SIZE_HT_CAP_IE; - } - else - { - DBGPRINT(RT_DEBUG_WARN, ("PeerAssocRspSanity - wrong IE_HT_CAP. \n")); - } - - break; -#ifdef DOT11_N_SUPPORT - case IE_ADD_HT: - case IE_ADD_HT2: - if (pEid->Len >= sizeof(ADD_HT_INFO_IE)) - { - // This IE allows extension, but we can ignore extra bytes beyond our knowledge , so only - // copy first sizeof(ADD_HT_INFO_IE) - NdisMoveMemory(pAddHtInfo, pEid->Octet, sizeof(ADD_HT_INFO_IE)); - - *(USHORT *)(&pAddHtInfo->AddHtInfo2) = cpu2le16(*(USHORT *)(&pAddHtInfo->AddHtInfo2)); - *(USHORT *)(&pAddHtInfo->AddHtInfo3) = cpu2le16(*(USHORT *)(&pAddHtInfo->AddHtInfo3)); - - *pAddHtInfoLen = SIZE_ADD_HT_INFO_IE; - } - else - { - DBGPRINT(RT_DEBUG_WARN, ("PeerAssocRspSanity - wrong IE_ADD_HT. \n")); - } - - break; - case IE_SECONDARY_CH_OFFSET: - if (pEid->Len == 1) - { - *pNewExtChannelOffset = pEid->Octet[0]; - } - else - { - DBGPRINT(RT_DEBUG_WARN, ("PeerAssocRspSanity - wrong IE_SECONDARY_CH_OFFSET. \n")); - } -#endif // DOT11_N_SUPPORT // - break; - case IE_AIRONET_CKIP: - // 0. Check Aironet IE length, it must be larger or equal to 28 - // Cisco's AP VxWork version(will not be supported) used this IE length as 28 - // Cisco's AP IOS version used this IE length as 30 - if (pEid->Len < (CKIP_NEGOTIATION_LENGTH - 2)) - break; - - // 1. Copy CKIP flag byte to buffer for process - *pCkipFlag = *(pEid->Octet + 8); - break; - - case IE_AIRONET_IPADDRESS: - if (pEid->Len != 0x0A) - break; - - // Get Cisco Aironet IP information - if (NdisEqualMemory(pEid->Octet, CISCO_OUI, 3) == 1) - NdisMoveMemory(pAd->StaCfg.AironetIPAddress, pEid->Octet + 4, 4); - break; - - // CCX2, WMM use the same IE value - // case IE_CCX_V2: - case IE_VENDOR_SPECIFIC: - // handle WME PARAMTER ELEMENT - if (NdisEqualMemory(pEid->Octet, WME_PARM_ELEM, 6) && (pEid->Len == 24)) - { - PUCHAR ptr; - int i; - - // parsing EDCA parameters - pEdcaParm->bValid = TRUE; - pEdcaParm->bQAck = FALSE; // pEid->Octet[0] & 0x10; - pEdcaParm->bQueueRequest = FALSE; // pEid->Octet[0] & 0x20; - pEdcaParm->bTxopRequest = FALSE; // pEid->Octet[0] & 0x40; - //pEdcaParm->bMoreDataAck = FALSE; // pEid->Octet[0] & 0x80; - pEdcaParm->EdcaUpdateCount = pEid->Octet[6] & 0x0f; - pEdcaParm->bAPSDCapable = (pEid->Octet[6] & 0x80) ? 1 : 0; - ptr = &pEid->Octet[8]; - for (i=0; i<4; i++) - { - UCHAR aci = (*ptr & 0x60) >> 5; // b5~6 is AC INDEX - pEdcaParm->bACM[aci] = (((*ptr) & 0x10) == 0x10); // b5 is ACM - pEdcaParm->Aifsn[aci] = (*ptr) & 0x0f; // b0~3 is AIFSN - pEdcaParm->Cwmin[aci] = *(ptr+1) & 0x0f; // b0~4 is Cwmin - pEdcaParm->Cwmax[aci] = *(ptr+1) >> 4; // b5~8 is Cwmax - pEdcaParm->Txop[aci] = *(ptr+2) + 256 * (*(ptr+3)); // in unit of 32-us - ptr += 4; // point to next AC - } - } - - // handle CCX IE - else - { - // 0. Check the size and CCX admin control - if (pAd->StaCfg.CCXControl.field.Enable == 0) - break; - if (pEid->Len != 5) - break; - - // Turn CCX2 if matched - if (NdisEqualMemory(pEid->Octet, Ccx2IeInfo, 5) == 1) - pAd->StaCfg.CCXEnable = TRUE; - break; - } - break; - - default: - DBGPRINT(RT_DEBUG_TRACE, ("PeerAssocRspSanity - ignore unrecognized EID = %d\n", pEid->Eid)); - break; - } - - Length = Length + 2 + pEid->Len; - pEid = (PEID_STRUCT)((UCHAR*)pEid + 2 + pEid->Len); - } - - // Force CCX2 enable to TRUE for those AP didn't replay CCX v2 IE, we still force it to be on - if (pAd->StaCfg.CCXControl.field.Enable == 1) - pAd->StaCfg.CCXEnable = TRUE; - - return TRUE; -} - -/* - ========================================================================== - Description: - MLME message sanity check - Return: - TRUE if all parameters are OK, FALSE otherwise - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -BOOLEAN PeerProbeReqSanity( - IN PRTMP_ADAPTER pAd, - IN VOID *Msg, - IN ULONG MsgLen, - OUT PUCHAR pAddr2, - OUT CHAR Ssid[], - OUT UCHAR *pSsidLen) -{ - UCHAR Idx; - UCHAR RateLen; - CHAR IeType; - PFRAME_802_11 pFrame = (PFRAME_802_11)Msg; - - COPY_MAC_ADDR(pAddr2, pFrame->Hdr.Addr2); - - if ((pFrame->Octet[0] != IE_SSID) || (pFrame->Octet[1] > MAX_LEN_OF_SSID)) - { - DBGPRINT(RT_DEBUG_TRACE, ("PeerProbeReqSanity fail - wrong SSID IE(Type=%d,Len=%d)\n",pFrame->Octet[0],pFrame->Octet[1])); - return FALSE; - } - - *pSsidLen = pFrame->Octet[1]; - NdisMoveMemory(Ssid, &pFrame->Octet[2], *pSsidLen); - - Idx = *pSsidLen + 2; - - // -- get supported rates from payload and advance the pointer - IeType = pFrame->Octet[Idx]; - RateLen = pFrame->Octet[Idx + 1]; - if (IeType != IE_SUPP_RATES) - { - DBGPRINT(RT_DEBUG_TRACE, ("PeerProbeReqSanity fail - wrong SupportRates IE(Type=%d,Len=%d)\n",pFrame->Octet[Idx],pFrame->Octet[Idx+1])); - return FALSE; - } - else - { - if ((pAd->CommonCfg.PhyMode == PHY_11G) && (RateLen < 8)) - return (FALSE); - } - - return TRUE; -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -BOOLEAN GetTimBit( - IN CHAR *Ptr, - IN USHORT Aid, - OUT UCHAR *TimLen, - OUT UCHAR *BcastFlag, - OUT UCHAR *DtimCount, - OUT UCHAR *DtimPeriod, - OUT UCHAR *MessageToMe) -{ - UCHAR BitCntl, N1, N2, MyByte, MyBit; - CHAR *IdxPtr; - - IdxPtr = Ptr; - - IdxPtr ++; - *TimLen = *IdxPtr; - - // get DTIM Count from TIM element - IdxPtr ++; - *DtimCount = *IdxPtr; - - // get DTIM Period from TIM element - IdxPtr++; - *DtimPeriod = *IdxPtr; - - // get Bitmap Control from TIM element - IdxPtr++; - BitCntl = *IdxPtr; - - if ((*DtimCount == 0) && (BitCntl & 0x01)) - *BcastFlag = TRUE; - else - *BcastFlag = FALSE; - - // Parse Partial Virtual Bitmap from TIM element - N1 = BitCntl & 0xfe; // N1 is the first bitmap byte# - N2 = *TimLen - 4 + N1; // N2 is the last bitmap byte# - - if ((Aid < (N1 << 3)) || (Aid >= ((N2 + 1) << 3))) - *MessageToMe = FALSE; - else - { - MyByte = (Aid >> 3) - N1; // my byte position in the bitmap byte-stream - MyBit = Aid % 16 - ((MyByte & 0x01)? 8:0); - - IdxPtr += (MyByte + 1); - - //if (*IdxPtr) - // DBGPRINT(RT_DEBUG_WARN, ("TIM bitmap = 0x%02x\n", *IdxPtr)); - - if (*IdxPtr & (0x01 << MyBit)) - *MessageToMe = TRUE; - else - *MessageToMe = FALSE; - } - - return TRUE; -} - +#include "../../rt2870/sta/sanity.c" diff --git a/drivers/staging/rt3070/sta/sync.c b/drivers/staging/rt3070/sta/sync.c index 2b5b3b07661d..b7b8eb4f446a 100644 --- a/drivers/staging/rt3070/sta/sync.c +++ b/drivers/staging/rt3070/sta/sync.c @@ -1,1755 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - sync.c - - Abstract: - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - John Chang 2004-09-01 modified for rt2561/2661 - Jan Lee 2006-08-01 modified for rt2860 for 802.11n -*/ -#include "../rt_config.h" - -#define ADHOC_ENTRY_BEACON_LOST_TIME (2*OS_HZ) // 2 sec - -/* - ========================================================================== - Description: - The sync state machine, - Parameters: - Sm - pointer to the state machine - Note: - the state machine looks like the following - - ========================================================================== - */ -VOID SyncStateMachineInit( - IN PRTMP_ADAPTER pAd, - IN STATE_MACHINE *Sm, - OUT STATE_MACHINE_FUNC Trans[]) -{ - StateMachineInit(Sm, Trans, MAX_SYNC_STATE, MAX_SYNC_MSG, (STATE_MACHINE_FUNC)Drop, SYNC_IDLE, SYNC_MACHINE_BASE); - - // column 1 - StateMachineSetAction(Sm, SYNC_IDLE, MT2_MLME_SCAN_REQ, (STATE_MACHINE_FUNC)MlmeScanReqAction); - StateMachineSetAction(Sm, SYNC_IDLE, MT2_MLME_JOIN_REQ, (STATE_MACHINE_FUNC)MlmeJoinReqAction); - StateMachineSetAction(Sm, SYNC_IDLE, MT2_MLME_START_REQ, (STATE_MACHINE_FUNC)MlmeStartReqAction); - StateMachineSetAction(Sm, SYNC_IDLE, MT2_PEER_BEACON, (STATE_MACHINE_FUNC)PeerBeacon); - StateMachineSetAction(Sm, SYNC_IDLE, MT2_PEER_PROBE_REQ, (STATE_MACHINE_FUNC)PeerProbeReqAction); - - //column 2 - StateMachineSetAction(Sm, JOIN_WAIT_BEACON, MT2_MLME_SCAN_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenScan); - StateMachineSetAction(Sm, JOIN_WAIT_BEACON, MT2_MLME_JOIN_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenJoin); - StateMachineSetAction(Sm, JOIN_WAIT_BEACON, MT2_MLME_START_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenStart); - StateMachineSetAction(Sm, JOIN_WAIT_BEACON, MT2_PEER_BEACON, (STATE_MACHINE_FUNC)PeerBeaconAtJoinAction); - StateMachineSetAction(Sm, JOIN_WAIT_BEACON, MT2_BEACON_TIMEOUT, (STATE_MACHINE_FUNC)BeaconTimeoutAtJoinAction); - - // column 3 - StateMachineSetAction(Sm, SCAN_LISTEN, MT2_MLME_SCAN_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenScan); - StateMachineSetAction(Sm, SCAN_LISTEN, MT2_MLME_JOIN_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenJoin); - StateMachineSetAction(Sm, SCAN_LISTEN, MT2_MLME_START_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenStart); - StateMachineSetAction(Sm, SCAN_LISTEN, MT2_PEER_BEACON, (STATE_MACHINE_FUNC)PeerBeaconAtScanAction); - StateMachineSetAction(Sm, SCAN_LISTEN, MT2_PEER_PROBE_RSP, (STATE_MACHINE_FUNC)PeerBeaconAtScanAction); - StateMachineSetAction(Sm, SCAN_LISTEN, MT2_SCAN_TIMEOUT, (STATE_MACHINE_FUNC)ScanTimeoutAction); - - // timer init - RTMPInitTimer(pAd, &pAd->MlmeAux.BeaconTimer, GET_TIMER_FUNCTION(BeaconTimeout), pAd, FALSE); - RTMPInitTimer(pAd, &pAd->MlmeAux.ScanTimer, GET_TIMER_FUNCTION(ScanTimeout), pAd, FALSE); -} - -/* - ========================================================================== - Description: - Beacon timeout handler, executed in timer thread - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID BeaconTimeout( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3) -{ - RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext; - - DBGPRINT(RT_DEBUG_TRACE,("SYNC - BeaconTimeout\n")); - - // Do nothing if the driver is starting halt state. - // This might happen when timer already been fired before cancel timer with mlmehalt - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) - return; - -#ifdef DOT11_N_SUPPORT - if ((pAd->CommonCfg.BBPCurrentBW == BW_40) - ) - { - UCHAR BBPValue = 0; - AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE); - AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel); - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); - BBPValue &= (~0x18); - BBPValue |= 0x10; - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); - DBGPRINT(RT_DEBUG_TRACE, ("SYNC - End of SCAN, restore to 40MHz channel %d, Total BSS[%02d]\n",pAd->CommonCfg.CentralChannel, pAd->ScanTab.BssNr)); - } -#endif // DOT11_N_SUPPORT // - - MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_BEACON_TIMEOUT, 0, NULL); - RT28XX_MLME_HANDLER(pAd); -} - -/* - ========================================================================== - Description: - Scan timeout handler, executed in timer thread - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID ScanTimeout( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3) -{ - RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext; - - - // Do nothing if the driver is starting halt state. - // This might happen when timer already been fired before cancel timer with mlmehalt - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) - return; - - if (MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_SCAN_TIMEOUT, 0, NULL)) - { - RT28XX_MLME_HANDLER(pAd); - } - else - { - // To prevent SyncMachine.CurrState is SCAN_LISTEN forever. - pAd->MlmeAux.Channel = 0; - ScanNextChannel(pAd); - if (pAd->CommonCfg.bWirelessEvent) - { - RTMPSendWirelessEvent(pAd, IW_SCAN_ENQUEUE_FAIL_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); - } - } -} - -/* - ========================================================================== - Description: - MLME SCAN req state machine procedure - ========================================================================== - */ -VOID MlmeScanReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - UCHAR Ssid[MAX_LEN_OF_SSID], SsidLen, ScanType, BssType, BBPValue = 0; - BOOLEAN TimerCancelled; - ULONG Now; - USHORT Status; - PHEADER_802_11 pHdr80211; - PUCHAR pOutBuffer = NULL; - NDIS_STATUS NStatus; - - // Check the total scan tries for one single OID command - // If this is the CCX 2.0 Case, skip that! - if ( !RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_START_UP)) - { - DBGPRINT(RT_DEBUG_TRACE, ("SYNC - MlmeScanReqAction before Startup\n")); - return; - } - - // Increase the scan retry counters. - pAd->StaCfg.ScanCnt++; - - - // first check the parameter sanity - if (MlmeScanReqSanity(pAd, - Elem->Msg, - Elem->MsgLen, - &BssType, - Ssid, - &SsidLen, - &ScanType)) - { - - // Check for channel load and noise hist request - // Suspend MSDU only at scan request, not the last two mentioned - if ((ScanType == SCAN_CISCO_NOISE) || (ScanType == SCAN_CISCO_CHANNEL_LOAD)) - { - if (pAd->StaCfg.CCXScanChannel != pAd->CommonCfg.Channel) - RTMPSuspendMsduTransmission(pAd); // Suspend MSDU transmission here - } - else - { - // Suspend MSDU transmission here - RTMPSuspendMsduTransmission(pAd); - } - - // - // To prevent data lost. - // Send an NULL data with turned PSM bit on to current associated AP before SCAN progress. - // And should send an NULL data with turned PSM bit off to AP, when scan progress done - // - if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) && (INFRA_ON(pAd))) - { - NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); - if (NStatus == NDIS_STATUS_SUCCESS) - { - pHdr80211 = (PHEADER_802_11) pOutBuffer; - MgtMacHeaderInit(pAd, pHdr80211, SUBTYPE_NULL_FUNC, 1, pAd->CommonCfg.Bssid, pAd->CommonCfg.Bssid); - pHdr80211->Duration = 0; - pHdr80211->FC.Type = BTYPE_DATA; - pHdr80211->FC.PwrMgmt = PWR_SAVE; - - // Send using priority queue - MiniportMMRequest(pAd, 0, pOutBuffer, sizeof(HEADER_802_11)); - DBGPRINT(RT_DEBUG_TRACE, ("MlmeScanReqAction -- Send PSM Data frame for off channel RM\n")); - MlmeFreeMemory(pAd, pOutBuffer); - RTMPusecDelay(5000); - } - } - - NdisGetSystemUpTime(&Now); - pAd->StaCfg.LastScanTime = Now; - // reset all the timers - RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer, &TimerCancelled); - RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &TimerCancelled); - - // record desired BSS parameters - pAd->MlmeAux.BssType = BssType; - pAd->MlmeAux.ScanType = ScanType; - pAd->MlmeAux.SsidLen = SsidLen; - NdisZeroMemory(pAd->MlmeAux.Ssid, MAX_LEN_OF_SSID); - NdisMoveMemory(pAd->MlmeAux.Ssid, Ssid, SsidLen); - - // start from the first channel - pAd->MlmeAux.Channel = FirstChannel(pAd); - - // Change the scan channel when dealing with CCX beacon report - if ((ScanType == SCAN_CISCO_PASSIVE) || (ScanType == SCAN_CISCO_ACTIVE) || - (ScanType == SCAN_CISCO_CHANNEL_LOAD) || (ScanType == SCAN_CISCO_NOISE)) - pAd->MlmeAux.Channel = pAd->StaCfg.CCXScanChannel; - - // Let BBP register at 20MHz to do scan - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); - BBPValue &= (~0x18); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); - DBGPRINT(RT_DEBUG_TRACE, ("SYNC - BBP R4 to 20MHz.l\n")); - ScanNextChannel(pAd); - } - else - { - DBGPRINT_ERR(("SYNC - MlmeScanReqAction() sanity check fail\n")); - pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; - Status = MLME_INVALID_FORMAT; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_SCAN_CONF, 2, &Status); - } -} - -/* - ========================================================================== - Description: - MLME JOIN req state machine procedure - ========================================================================== - */ -VOID MlmeJoinReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - UCHAR BBPValue = 0; - BSS_ENTRY *pBss; - BOOLEAN TimerCancelled; - HEADER_802_11 Hdr80211; - NDIS_STATUS NStatus; - ULONG FrameLen = 0; - PUCHAR pOutBuffer = NULL; - PUCHAR pSupRate = NULL; - UCHAR SupRateLen; - PUCHAR pExtRate = NULL; - UCHAR ExtRateLen; - UCHAR ASupRate[] = {0x8C, 0x12, 0x98, 0x24, 0xb0, 0x48, 0x60, 0x6C}; - UCHAR ASupRateLen = sizeof(ASupRate)/sizeof(UCHAR); - MLME_JOIN_REQ_STRUCT *pInfo = (MLME_JOIN_REQ_STRUCT *)(Elem->Msg); - - DBGPRINT(RT_DEBUG_TRACE, ("SYNC - MlmeJoinReqAction(BSS #%ld)\n", pInfo->BssIdx)); - - - // reset all the timers - RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &TimerCancelled); - RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer, &TimerCancelled); - - pBss = &pAd->MlmeAux.SsidBssTab.BssEntry[pInfo->BssIdx]; - - // record the desired SSID & BSSID we're waiting for - COPY_MAC_ADDR(pAd->MlmeAux.Bssid, pBss->Bssid); - - // If AP's SSID is not hidden, it is OK for updating ssid to MlmeAux again. - if (pBss->Hidden == 0) - { - NdisMoveMemory(pAd->MlmeAux.Ssid, pBss->Ssid, pBss->SsidLen); - pAd->MlmeAux.SsidLen = pBss->SsidLen; - } - - pAd->MlmeAux.BssType = pBss->BssType; - pAd->MlmeAux.Channel = pBss->Channel; - pAd->MlmeAux.CentralChannel = pBss->CentralChannel; - -#ifdef EXT_BUILD_CHANNEL_LIST - // Country IE of the AP will be evaluated and will be used. - if ((pAd->StaCfg.IEEE80211dClientMode != Rt802_11_D_None) && - (pBss->bHasCountryIE == TRUE)) - { - NdisMoveMemory(&pAd->CommonCfg.CountryCode[0], &pBss->CountryString[0], 2); - if (pBss->CountryString[2] == 'I') - pAd->CommonCfg.Geography = IDOR; - else if (pBss->CountryString[2] == 'O') - pAd->CommonCfg.Geography = ODOR; - else - pAd->CommonCfg.Geography = BOTH; - BuildChannelListEx(pAd); - } -#endif // EXT_BUILD_CHANNEL_LIST // - - // Let BBP register at 20MHz to do scan - RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); - BBPValue &= (~0x18); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); - DBGPRINT(RT_DEBUG_TRACE, ("SYNC - BBP R4 to 20MHz.l\n")); - - // switch channel and waiting for beacon timer - AsicSwitchChannel(pAd, pAd->MlmeAux.Channel, FALSE); - AsicLockChannel(pAd, pAd->MlmeAux.Channel); - RTMPSetTimer(&pAd->MlmeAux.BeaconTimer, JOIN_TIMEOUT); - - do - { - if (((pAd->CommonCfg.bIEEE80211H == 1) && - (pAd->MlmeAux.Channel > 14) && - RadarChannelCheck(pAd, pAd->MlmeAux.Channel)) -#ifdef CARRIER_DETECTION_SUPPORT // Roger sync Carrier - || (pAd->CommonCfg.CarrierDetect.Enable == TRUE) -#endif // CARRIER_DETECTION_SUPPORT // - ) - { - // - // We can't send any Probe request frame to meet 802.11h. - // - if (pBss->Hidden == 0) - break; - } - - // - // send probe request - // - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); - if (NStatus == NDIS_STATUS_SUCCESS) - { - if (pAd->MlmeAux.Channel <= 14) - { - pSupRate = pAd->CommonCfg.SupRate; - SupRateLen = pAd->CommonCfg.SupRateLen; - pExtRate = pAd->CommonCfg.ExtRate; - ExtRateLen = pAd->CommonCfg.ExtRateLen; - } - else - { - // - // Overwrite Support Rate, CCK rate are not allowed - // - pSupRate = ASupRate; - SupRateLen = ASupRateLen; - ExtRateLen = 0; - } - - if (pAd->MlmeAux.BssType == BSS_INFRA) - MgtMacHeaderInit(pAd, &Hdr80211, SUBTYPE_PROBE_REQ, 0, pAd->MlmeAux.Bssid, pAd->MlmeAux.Bssid); - else - MgtMacHeaderInit(pAd, &Hdr80211, SUBTYPE_PROBE_REQ, 0, BROADCAST_ADDR, BROADCAST_ADDR); - - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(HEADER_802_11), &Hdr80211, - 1, &SsidIe, - 1, &pAd->MlmeAux.SsidLen, - pAd->MlmeAux.SsidLen, pAd->MlmeAux.Ssid, - 1, &SupRateIe, - 1, &SupRateLen, - SupRateLen, pSupRate, - END_OF_ARGS); - - if (ExtRateLen) - { - ULONG Tmp; - MakeOutgoingFrame(pOutBuffer + FrameLen, &Tmp, - 1, &ExtRateIe, - 1, &ExtRateLen, - ExtRateLen, pExtRate, - END_OF_ARGS); - FrameLen += Tmp; - } - - - MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); - } - } while (FALSE); - - DBGPRINT(RT_DEBUG_TRACE, ("SYNC - Switch to ch %d, Wait BEACON from %02x:%02x:%02x:%02x:%02x:%02x\n", - pBss->Channel, pBss->Bssid[0], pBss->Bssid[1], pBss->Bssid[2], pBss->Bssid[3], pBss->Bssid[4], pBss->Bssid[5])); - - pAd->Mlme.SyncMachine.CurrState = JOIN_WAIT_BEACON; -} - -/* - ========================================================================== - Description: - MLME START Request state machine procedure, starting an IBSS - ========================================================================== - */ -VOID MlmeStartReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - UCHAR Ssid[MAX_LEN_OF_SSID], SsidLen; - BOOLEAN TimerCancelled; - - // New for WPA security suites - UCHAR VarIE[MAX_VIE_LEN]; // Total VIE length = MAX_VIE_LEN - -5 - NDIS_802_11_VARIABLE_IEs *pVIE = NULL; - LARGE_INTEGER TimeStamp; - BOOLEAN Privacy; - USHORT Status; - - // Init Variable IE structure - pVIE = (PNDIS_802_11_VARIABLE_IEs) VarIE; - pVIE->Length = 0; - TimeStamp.u.LowPart = 0; - TimeStamp.u.HighPart = 0; - - if (MlmeStartReqSanity(pAd, Elem->Msg, Elem->MsgLen, Ssid, &SsidLen)) - { - // reset all the timers - RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &TimerCancelled); - RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer, &TimerCancelled); - - // - // Start a new IBSS. All IBSS parameters are decided now.... - // - DBGPRINT(RT_DEBUG_TRACE, ("MlmeStartReqAction - Start a new IBSS. All IBSS parameters are decided now.... \n")); - pAd->MlmeAux.BssType = BSS_ADHOC; - NdisMoveMemory(pAd->MlmeAux.Ssid, Ssid, SsidLen); - pAd->MlmeAux.SsidLen = SsidLen; - - // generate a radom number as BSSID - MacAddrRandomBssid(pAd, pAd->MlmeAux.Bssid); - DBGPRINT(RT_DEBUG_TRACE, ("MlmeStartReqAction - generate a radom number as BSSID \n")); - - Privacy = (pAd->StaCfg.WepStatus == Ndis802_11Encryption1Enabled) || - (pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) || - (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled); - pAd->MlmeAux.CapabilityInfo = CAP_GENERATE(0,1,Privacy, (pAd->CommonCfg.TxPreamble == Rt802_11PreambleShort), 1, 0); - pAd->MlmeAux.BeaconPeriod = pAd->CommonCfg.BeaconPeriod; - pAd->MlmeAux.AtimWin = pAd->StaCfg.AtimWin; - pAd->MlmeAux.Channel = pAd->CommonCfg.Channel; - - pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel; - pAd->MlmeAux.CentralChannel = pAd->CommonCfg.CentralChannel; - - pAd->MlmeAux.SupRateLen= pAd->CommonCfg.SupRateLen; - NdisMoveMemory(pAd->MlmeAux.SupRate, pAd->CommonCfg.SupRate, MAX_LEN_OF_SUPPORTED_RATES); - RTMPCheckRates(pAd, pAd->MlmeAux.SupRate, &pAd->MlmeAux.SupRateLen); - pAd->MlmeAux.ExtRateLen = pAd->CommonCfg.ExtRateLen; - NdisMoveMemory(pAd->MlmeAux.ExtRate, pAd->CommonCfg.ExtRate, MAX_LEN_OF_SUPPORTED_RATES); - RTMPCheckRates(pAd, pAd->MlmeAux.ExtRate, &pAd->MlmeAux.ExtRateLen); -#ifdef DOT11_N_SUPPORT - if (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) - { - RTMPUpdateHTIE(&pAd->CommonCfg.DesiredHtPhy, &pAd->StaCfg.DesiredHtPhyInfo.MCSSet[0], &pAd->MlmeAux.HtCapability, &pAd->MlmeAux.AddHtInfo); - pAd->MlmeAux.HtCapabilityLen = sizeof(HT_CAPABILITY_IE); - // Not turn pAd->StaActive.SupportedHtPhy.bHtEnable = TRUE here. - DBGPRINT(RT_DEBUG_TRACE, ("SYNC -pAd->StaActive.SupportedHtPhy.bHtEnable = TRUE\n")); - } - else -#endif // DOT11_N_SUPPORT // - { - pAd->MlmeAux.HtCapabilityLen = 0; - pAd->StaActive.SupportedPhyInfo.bHtEnable = FALSE; - } - // temporarily not support QOS in IBSS - NdisZeroMemory(&pAd->MlmeAux.APEdcaParm, sizeof(EDCA_PARM)); - NdisZeroMemory(&pAd->MlmeAux.APQbssLoad, sizeof(QBSS_LOAD_PARM)); - NdisZeroMemory(&pAd->MlmeAux.APQosCapability, sizeof(QOS_CAPABILITY_PARM)); - - AsicSwitchChannel(pAd, pAd->MlmeAux.Channel, FALSE); - AsicLockChannel(pAd, pAd->MlmeAux.Channel); - - DBGPRINT(RT_DEBUG_TRACE, ("SYNC - MlmeStartReqAction(ch= %d,sup rates= %d, ext rates=%d)\n", - pAd->MlmeAux.Channel, pAd->MlmeAux.SupRateLen, pAd->MlmeAux.ExtRateLen)); - - pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; - Status = MLME_SUCCESS; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_START_CONF, 2, &Status); - } - else - { - DBGPRINT_ERR(("SYNC - MlmeStartReqAction() sanity check fail.\n")); - pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; - Status = MLME_INVALID_FORMAT; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_START_CONF, 2, &Status); - } -} - -/* - ========================================================================== - Description: - peer sends beacon back when scanning - ========================================================================== - */ -VOID PeerBeaconAtScanAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - UCHAR Bssid[MAC_ADDR_LEN], Addr2[MAC_ADDR_LEN]; - UCHAR Ssid[MAX_LEN_OF_SSID], BssType, Channel, NewChannel, - SsidLen, DtimCount, DtimPeriod, BcastFlag, MessageToMe; - CF_PARM CfParm; - USHORT BeaconPeriod, AtimWin, CapabilityInfo; - PFRAME_802_11 pFrame; - LARGE_INTEGER TimeStamp; - UCHAR Erp; - UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES], ExtRate[MAX_LEN_OF_SUPPORTED_RATES]; - UCHAR SupRateLen, ExtRateLen; - USHORT LenVIE; - UCHAR CkipFlag; - UCHAR AironetCellPowerLimit; - EDCA_PARM EdcaParm; - QBSS_LOAD_PARM QbssLoad; - QOS_CAPABILITY_PARM QosCapability; - ULONG RalinkIe; - UCHAR VarIE[MAX_VIE_LEN]; // Total VIE length = MAX_VIE_LEN - -5 - NDIS_802_11_VARIABLE_IEs *pVIE = NULL; - HT_CAPABILITY_IE HtCapability; - ADD_HT_INFO_IE AddHtInfo; // AP might use this additional ht info IE - UCHAR HtCapabilityLen = 0, PreNHtCapabilityLen = 0; - UCHAR AddHtInfoLen; - UCHAR NewExtChannelOffset = 0xff; - - - // NdisFillMemory(Ssid, MAX_LEN_OF_SSID, 0x00); - pFrame = (PFRAME_802_11) Elem->Msg; - // Init Variable IE structure - pVIE = (PNDIS_802_11_VARIABLE_IEs) VarIE; - pVIE->Length = 0; -#ifdef DOT11_N_SUPPORT - RTMPZeroMemory(&HtCapability, sizeof(HtCapability)); - RTMPZeroMemory(&AddHtInfo, sizeof(ADD_HT_INFO_IE)); -#endif // DOT11_N_SUPPORT // - - if (PeerBeaconAndProbeRspSanity(pAd, - Elem->Msg, - Elem->MsgLen, - Elem->Channel, - Addr2, - Bssid, - Ssid, - &SsidLen, - &BssType, - &BeaconPeriod, - &Channel, - &NewChannel, - &TimeStamp, - &CfParm, - &AtimWin, - &CapabilityInfo, - &Erp, - &DtimCount, - &DtimPeriod, - &BcastFlag, - &MessageToMe, - SupRate, - &SupRateLen, - ExtRate, - &ExtRateLen, - &CkipFlag, - &AironetCellPowerLimit, - &EdcaParm, - &QbssLoad, - &QosCapability, - &RalinkIe, - &HtCapabilityLen, - &PreNHtCapabilityLen, - &HtCapability, - &AddHtInfoLen, - &AddHtInfo, - &NewExtChannelOffset, - &LenVIE, - pVIE)) - { - ULONG Idx; - CHAR Rssi = 0; - - Idx = BssTableSearch(&pAd->ScanTab, Bssid, Channel); - if (Idx != BSS_NOT_FOUND) - Rssi = pAd->ScanTab.BssEntry[Idx].Rssi; - - Rssi = RTMPMaxRssi(pAd, ConvertToRssi(pAd, Elem->Rssi0, RSSI_0), ConvertToRssi(pAd, Elem->Rssi1, RSSI_1), ConvertToRssi(pAd, Elem->Rssi2, RSSI_2)); - - -#ifdef DOT11_N_SUPPORT - if ((HtCapabilityLen > 0) || (PreNHtCapabilityLen > 0)) - HtCapabilityLen = SIZE_HT_CAP_IE; -#endif // DOT11_N_SUPPORT // - if ((pAd->StaCfg.CCXReqType != MSRN_TYPE_UNUSED) && (Channel == pAd->StaCfg.CCXScanChannel)) - { - Idx = BssTableSetEntry(pAd, &pAd->StaCfg.CCXBssTab, Bssid, Ssid, SsidLen, BssType, BeaconPeriod, - &CfParm, AtimWin, CapabilityInfo, SupRate, SupRateLen,ExtRate, ExtRateLen, &HtCapability, - &AddHtInfo, HtCapabilityLen, AddHtInfoLen, NewExtChannelOffset, Channel, Rssi, TimeStamp, CkipFlag, - &EdcaParm, &QosCapability, &QbssLoad, LenVIE, pVIE); - if (Idx != BSS_NOT_FOUND) - { - NdisMoveMemory(pAd->StaCfg.CCXBssTab.BssEntry[Idx].PTSF, &Elem->Msg[24], 4); - NdisMoveMemory(&pAd->StaCfg.CCXBssTab.BssEntry[Idx].TTSF[0], &Elem->TimeStamp.u.LowPart, 4); - NdisMoveMemory(&pAd->StaCfg.CCXBssTab.BssEntry[Idx].TTSF[4], &Elem->TimeStamp.u.LowPart, 4); - if (pAd->StaCfg.CCXReqType == MSRN_TYPE_BEACON_REQ) - AironetAddBeaconReport(pAd, Idx, Elem); - } - } - else - { - Idx = BssTableSetEntry(pAd, &pAd->ScanTab, Bssid, Ssid, SsidLen, BssType, BeaconPeriod, - &CfParm, AtimWin, CapabilityInfo, SupRate, SupRateLen, ExtRate, ExtRateLen, &HtCapability, - &AddHtInfo, HtCapabilityLen, AddHtInfoLen, NewExtChannelOffset, Channel, Rssi, TimeStamp, CkipFlag, - &EdcaParm, &QosCapability, &QbssLoad, LenVIE, pVIE); -#ifdef DOT11_N_SUPPORT -#ifdef DOT11N_DRAFT3 - if (pAd->ChannelList[pAd->CommonCfg.ChannelListIdx].bEffectedChannel == TRUE) - { - UCHAR RegClass; - PeerBeaconAndProbeRspSanity2(pAd, Elem->Msg, Elem->MsgLen, &RegClass); - TriEventTableSetEntry(pAd, &pAd->CommonCfg.TriggerEventTab, Bssid, &HtCapability, HtCapabilityLen, RegClass, Channel); - } -#endif // DOT11N_DRAFT3 // -#endif // DOT11_N_SUPPORT // - if (Idx != BSS_NOT_FOUND) - { - NdisMoveMemory(pAd->ScanTab.BssEntry[Idx].PTSF, &Elem->Msg[24], 4); - NdisMoveMemory(&pAd->ScanTab.BssEntry[Idx].TTSF[0], &Elem->TimeStamp.u.LowPart, 4); - NdisMoveMemory(&pAd->ScanTab.BssEntry[Idx].TTSF[4], &Elem->TimeStamp.u.LowPart, 4); - } - } - } - // sanity check fail, ignored -} - -/* - ========================================================================== - Description: - When waiting joining the (I)BSS, beacon received from external - ========================================================================== - */ -VOID PeerBeaconAtJoinAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - UCHAR Bssid[MAC_ADDR_LEN], Addr2[MAC_ADDR_LEN]; - UCHAR Ssid[MAX_LEN_OF_SSID], SsidLen, BssType, Channel, MessageToMe, - DtimCount, DtimPeriod, BcastFlag, NewChannel; - LARGE_INTEGER TimeStamp; - USHORT BeaconPeriod, AtimWin, CapabilityInfo; - CF_PARM Cf; - BOOLEAN TimerCancelled; - UCHAR Erp; - UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES], ExtRate[MAX_LEN_OF_SUPPORTED_RATES]; - UCHAR SupRateLen, ExtRateLen; - UCHAR CkipFlag; - USHORT LenVIE; - UCHAR AironetCellPowerLimit; - EDCA_PARM EdcaParm; - QBSS_LOAD_PARM QbssLoad; - QOS_CAPABILITY_PARM QosCapability; - USHORT Status; - UCHAR VarIE[MAX_VIE_LEN]; // Total VIE length = MAX_VIE_LEN - -5 - NDIS_802_11_VARIABLE_IEs *pVIE = NULL; - ULONG RalinkIe; - ULONG Idx; - HT_CAPABILITY_IE HtCapability; - ADD_HT_INFO_IE AddHtInfo; // AP might use this additional ht info IE - UCHAR HtCapabilityLen = 0, PreNHtCapabilityLen = 0; - UCHAR AddHtInfoLen; - UCHAR NewExtChannelOffset = 0xff; -#ifdef DOT11_N_SUPPORT - UCHAR CentralChannel; -#endif // DOT11_N_SUPPORT // - - // Init Variable IE structure - pVIE = (PNDIS_802_11_VARIABLE_IEs) VarIE; - pVIE->Length = 0; - RTMPZeroMemory(&HtCapability, sizeof(HtCapability)); - RTMPZeroMemory(&AddHtInfo, sizeof(ADD_HT_INFO_IE)); - - - if (PeerBeaconAndProbeRspSanity(pAd, - Elem->Msg, - Elem->MsgLen, - Elem->Channel, - Addr2, - Bssid, - Ssid, - &SsidLen, - &BssType, - &BeaconPeriod, - &Channel, - &NewChannel, - &TimeStamp, - &Cf, - &AtimWin, - &CapabilityInfo, - &Erp, - &DtimCount, - &DtimPeriod, - &BcastFlag, - &MessageToMe, - SupRate, - &SupRateLen, - ExtRate, - &ExtRateLen, - &CkipFlag, - &AironetCellPowerLimit, - &EdcaParm, - &QbssLoad, - &QosCapability, - &RalinkIe, - &HtCapabilityLen, - &PreNHtCapabilityLen, - &HtCapability, - &AddHtInfoLen, - &AddHtInfo, - &NewExtChannelOffset, - &LenVIE, - pVIE)) - { - // Disqualify 11b only adhoc when we are in 11g only adhoc mode - if ((BssType == BSS_ADHOC) && (pAd->CommonCfg.PhyMode == PHY_11G) && ((SupRateLen+ExtRateLen)< 12)) - return; - - // BEACON from desired BSS/IBSS found. We should be able to decide most - // BSS parameters here. - // Q. But what happen if this JOIN doesn't conclude a successful ASSOCIATEION? - // Do we need to receover back all parameters belonging to previous BSS? - // A. Should be not. There's no back-door recover to previous AP. It still need - // a new JOIN-AUTH-ASSOC sequence. - if (MAC_ADDR_EQUAL(pAd->MlmeAux.Bssid, Bssid)) - { - DBGPRINT(RT_DEBUG_TRACE, ("SYNC - receive desired BEACON at JoinWaitBeacon... Channel = %d\n", Channel)); - RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer, &TimerCancelled); - - // Update RSSI to prevent No signal display when cards first initialized - pAd->StaCfg.RssiSample.LastRssi0 = ConvertToRssi(pAd, Elem->Rssi0, RSSI_0); - pAd->StaCfg.RssiSample.LastRssi1 = ConvertToRssi(pAd, Elem->Rssi1, RSSI_1); - pAd->StaCfg.RssiSample.LastRssi2 = ConvertToRssi(pAd, Elem->Rssi2, RSSI_2); - pAd->StaCfg.RssiSample.AvgRssi0 = pAd->StaCfg.RssiSample.LastRssi0; - pAd->StaCfg.RssiSample.AvgRssi0X8 = pAd->StaCfg.RssiSample.AvgRssi0 << 3; - pAd->StaCfg.RssiSample.AvgRssi1 = pAd->StaCfg.RssiSample.LastRssi1; - pAd->StaCfg.RssiSample.AvgRssi1X8 = pAd->StaCfg.RssiSample.AvgRssi1 << 3; - pAd->StaCfg.RssiSample.AvgRssi2 = pAd->StaCfg.RssiSample.LastRssi2; - pAd->StaCfg.RssiSample.AvgRssi2X8 = pAd->StaCfg.RssiSample.AvgRssi2 << 3; - - // - // We need to check if SSID only set to any, then we can record the current SSID. - // Otherwise will cause hidden SSID association failed. - // - if (pAd->MlmeAux.SsidLen == 0) - { - NdisMoveMemory(pAd->MlmeAux.Ssid, Ssid, SsidLen); - pAd->MlmeAux.SsidLen = SsidLen; - } - else - { - Idx = BssSsidTableSearch(&pAd->ScanTab, Bssid, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen, Channel); - - if (Idx != BSS_NOT_FOUND) - { - // - // Multiple SSID case, used correct CapabilityInfo - // - CapabilityInfo = pAd->ScanTab.BssEntry[Idx].CapabilityInfo; - } - } - NdisMoveMemory(pAd->MlmeAux.Bssid, Bssid, MAC_ADDR_LEN); - pAd->MlmeAux.CapabilityInfo = CapabilityInfo & SUPPORTED_CAPABILITY_INFO; - pAd->MlmeAux.BssType = BssType; - pAd->MlmeAux.BeaconPeriod = BeaconPeriod; - pAd->MlmeAux.Channel = Channel; - pAd->MlmeAux.AtimWin = AtimWin; - pAd->MlmeAux.CfpPeriod = Cf.CfpPeriod; - pAd->MlmeAux.CfpMaxDuration = Cf.CfpMaxDuration; - pAd->MlmeAux.APRalinkIe = RalinkIe; - - // Copy AP's supported rate to MlmeAux for creating assoication request - // Also filter out not supported rate - pAd->MlmeAux.SupRateLen = SupRateLen; - NdisMoveMemory(pAd->MlmeAux.SupRate, SupRate, SupRateLen); - RTMPCheckRates(pAd, pAd->MlmeAux.SupRate, &pAd->MlmeAux.SupRateLen); - pAd->MlmeAux.ExtRateLen = ExtRateLen; - NdisMoveMemory(pAd->MlmeAux.ExtRate, ExtRate, ExtRateLen); - RTMPCheckRates(pAd, pAd->MlmeAux.ExtRate, &pAd->MlmeAux.ExtRateLen); - - NdisZeroMemory(pAd->StaActive.SupportedPhyInfo.MCSSet, 16); -#ifdef DOT11_N_SUPPORT - pAd->MlmeAux.NewExtChannelOffset = NewExtChannelOffset; - pAd->MlmeAux.HtCapabilityLen = HtCapabilityLen; - - // filter out un-supported ht rates - if (((HtCapabilityLen > 0) || (PreNHtCapabilityLen > 0)) && (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) - { - RTMPZeroMemory(&pAd->MlmeAux.HtCapability, SIZE_HT_CAP_IE); - RTMPMoveMemory(&pAd->MlmeAux.AddHtInfo, &AddHtInfo, SIZE_ADD_HT_INFO_IE); - - // StaActive.SupportedHtPhy.MCSSet stores Peer AP's 11n Rx capability - NdisMoveMemory(pAd->StaActive.SupportedPhyInfo.MCSSet, HtCapability.MCSSet, 16); - pAd->MlmeAux.NewExtChannelOffset = NewExtChannelOffset; - pAd->MlmeAux.HtCapabilityLen = SIZE_HT_CAP_IE; - pAd->StaActive.SupportedPhyInfo.bHtEnable = TRUE; - if (PreNHtCapabilityLen > 0) - pAd->StaActive.SupportedPhyInfo.bPreNHt = TRUE; - RTMPCheckHt(pAd, BSSID_WCID, &HtCapability, &AddHtInfo); - // Copy AP Parameter to StaActive. This is also in LinkUp. - DBGPRINT(RT_DEBUG_TRACE, ("PeerBeaconAtJoinAction! (MpduDensity=%d, MaxRAmpduFactor=%d, BW=%d)\n", - pAd->StaActive.SupportedHtPhy.MpduDensity, pAd->StaActive.SupportedHtPhy.MaxRAmpduFactor, HtCapability.HtCapInfo.ChannelWidth)); - - if (AddHtInfoLen > 0) - { - CentralChannel = AddHtInfo.ControlChan; - // Check again the Bandwidth capability of this AP. - if ((AddHtInfo.ControlChan > 2)&& (AddHtInfo.AddHtInfo.ExtChanOffset == EXTCHA_BELOW) && (HtCapability.HtCapInfo.ChannelWidth == BW_40)) - { - CentralChannel = AddHtInfo.ControlChan - 2; - } - else if ((AddHtInfo.AddHtInfo.ExtChanOffset == EXTCHA_ABOVE) && (HtCapability.HtCapInfo.ChannelWidth == BW_40)) - { - CentralChannel = AddHtInfo.ControlChan + 2; - } - - // Check Error . - if (pAd->MlmeAux.CentralChannel != CentralChannel) - DBGPRINT(RT_DEBUG_ERROR, ("PeerBeaconAtJoinAction HT===>Beacon Central Channel = %d, Control Channel = %d. Mlmeaux CentralChannel = %d\n", CentralChannel, AddHtInfo.ControlChan, pAd->MlmeAux.CentralChannel)); - - DBGPRINT(RT_DEBUG_TRACE, ("PeerBeaconAtJoinAction HT===>Central Channel = %d, Control Channel = %d, .\n", CentralChannel, AddHtInfo.ControlChan)); - - } - - } - else -#endif // DOT11_N_SUPPORT // - { - // To prevent error, let legacy AP must have same CentralChannel and Channel. - if ((HtCapabilityLen == 0) && (PreNHtCapabilityLen == 0)) - pAd->MlmeAux.CentralChannel = pAd->MlmeAux.Channel; - - pAd->StaActive.SupportedPhyInfo.bHtEnable = FALSE; - RTMPZeroMemory(&pAd->MlmeAux.HtCapability, SIZE_HT_CAP_IE); - RTMPZeroMemory(&pAd->MlmeAux.AddHtInfo, SIZE_ADD_HT_INFO_IE); - } - - RTMPUpdateMlmeRate(pAd); - - // copy QOS related information - if ((pAd->CommonCfg.bWmmCapable) -#ifdef DOT11_N_SUPPORT - || (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) -#endif // DOT11_N_SUPPORT // - ) - { - NdisMoveMemory(&pAd->MlmeAux.APEdcaParm, &EdcaParm, sizeof(EDCA_PARM)); - NdisMoveMemory(&pAd->MlmeAux.APQbssLoad, &QbssLoad, sizeof(QBSS_LOAD_PARM)); - NdisMoveMemory(&pAd->MlmeAux.APQosCapability, &QosCapability, sizeof(QOS_CAPABILITY_PARM)); - } - else - { - NdisZeroMemory(&pAd->MlmeAux.APEdcaParm, sizeof(EDCA_PARM)); - NdisZeroMemory(&pAd->MlmeAux.APQbssLoad, sizeof(QBSS_LOAD_PARM)); - NdisZeroMemory(&pAd->MlmeAux.APQosCapability, sizeof(QOS_CAPABILITY_PARM)); - } - - DBGPRINT(RT_DEBUG_TRACE, ("SYNC - after JOIN, SupRateLen=%d, ExtRateLen=%d\n", - pAd->MlmeAux.SupRateLen, pAd->MlmeAux.ExtRateLen)); - -#ifdef LEAP_SUPPORT - // Update CkipFlag - pAd->StaCfg.CkipFlag = CkipFlag; - - // Keep TimeStamp for Re-Association used. - if (LEAP_CCKM_ON(pAd) && (pAd->StaCfg.CCKMLinkUpFlag == TRUE)) - pAd->StaCfg.CCKMBeaconAtJoinTimeStamp = TimeStamp; -#endif // LEAP_SUPPORT // - - if (AironetCellPowerLimit != 0xFF) - { - //We need to change our TxPower for CCX 2.0 AP Control of Client Transmit Power - ChangeToCellPowerLimit(pAd, AironetCellPowerLimit); - } - else //Used the default TX Power Percentage. - pAd->CommonCfg.TxPowerPercentage = pAd->CommonCfg.TxPowerDefault; - - pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; - Status = MLME_SUCCESS; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_JOIN_CONF, 2, &Status); - } - // not to me BEACON, ignored - } - // sanity check fail, ignore this frame -} - -/* - ========================================================================== - Description: - receive BEACON from peer - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID PeerBeacon( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - UCHAR Bssid[MAC_ADDR_LEN], Addr2[MAC_ADDR_LEN]; - CHAR Ssid[MAX_LEN_OF_SSID]; - CF_PARM CfParm; - UCHAR SsidLen, MessageToMe=0, BssType, Channel, NewChannel, index=0; - UCHAR DtimCount=0, DtimPeriod=0, BcastFlag=0; - USHORT CapabilityInfo, AtimWin, BeaconPeriod; - LARGE_INTEGER TimeStamp; - USHORT TbttNumToNextWakeUp; - UCHAR Erp; - UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES], ExtRate[MAX_LEN_OF_SUPPORTED_RATES]; - UCHAR SupRateLen, ExtRateLen; - UCHAR CkipFlag; - USHORT LenVIE; - UCHAR AironetCellPowerLimit; - EDCA_PARM EdcaParm; - QBSS_LOAD_PARM QbssLoad; - QOS_CAPABILITY_PARM QosCapability; - ULONG RalinkIe; - // New for WPA security suites - UCHAR VarIE[MAX_VIE_LEN]; // Total VIE length = MAX_VIE_LEN - -5 - NDIS_802_11_VARIABLE_IEs *pVIE = NULL; - HT_CAPABILITY_IE HtCapability; - ADD_HT_INFO_IE AddHtInfo; // AP might use this additional ht info IE - UCHAR HtCapabilityLen, PreNHtCapabilityLen; - UCHAR AddHtInfoLen; - UCHAR NewExtChannelOffset = 0xff; - - -#ifdef RALINK_ATE - if (ATE_ON(pAd)) - { - return; - } -#endif // RALINK_ATE // - - if (!(INFRA_ON(pAd) || ADHOC_ON(pAd) - )) - return; - - // Init Variable IE structure - pVIE = (PNDIS_802_11_VARIABLE_IEs) VarIE; - pVIE->Length = 0; - RTMPZeroMemory(&HtCapability, sizeof(HtCapability)); - RTMPZeroMemory(&AddHtInfo, sizeof(ADD_HT_INFO_IE)); - - if (PeerBeaconAndProbeRspSanity(pAd, - Elem->Msg, - Elem->MsgLen, - Elem->Channel, - Addr2, - Bssid, - Ssid, - &SsidLen, - &BssType, - &BeaconPeriod, - &Channel, - &NewChannel, - &TimeStamp, - &CfParm, - &AtimWin, - &CapabilityInfo, - &Erp, - &DtimCount, - &DtimPeriod, - &BcastFlag, - &MessageToMe, - SupRate, - &SupRateLen, - ExtRate, - &ExtRateLen, - &CkipFlag, - &AironetCellPowerLimit, - &EdcaParm, - &QbssLoad, - &QosCapability, - &RalinkIe, - &HtCapabilityLen, - &PreNHtCapabilityLen, - &HtCapability, - &AddHtInfoLen, - &AddHtInfo, - &NewExtChannelOffset, - &LenVIE, - pVIE)) - { - BOOLEAN is_my_bssid, is_my_ssid; - ULONG Bssidx, Now; - BSS_ENTRY *pBss; - CHAR RealRssi = RTMPMaxRssi(pAd, ConvertToRssi(pAd, Elem->Rssi0, RSSI_0), ConvertToRssi(pAd, Elem->Rssi1, RSSI_1), ConvertToRssi(pAd, Elem->Rssi2, RSSI_2)); - - is_my_bssid = MAC_ADDR_EQUAL(Bssid, pAd->CommonCfg.Bssid)? TRUE : FALSE; - is_my_ssid = SSID_EQUAL(Ssid, SsidLen, pAd->CommonCfg.Ssid, pAd->CommonCfg.SsidLen)? TRUE:FALSE; - - - // ignore BEACON not for my SSID - if ((! is_my_ssid) && (! is_my_bssid)) - return; - - // It means STA waits disassoc completely from this AP, ignores this beacon. - if (pAd->Mlme.CntlMachine.CurrState == CNTL_WAIT_DISASSOC) - return; - -#ifdef DOT11_N_SUPPORT - // Copy Control channel for this BSSID. - if (AddHtInfoLen != 0) - Channel = AddHtInfo.ControlChan; - - if ((HtCapabilityLen > 0) || (PreNHtCapabilityLen > 0)) - HtCapabilityLen = SIZE_HT_CAP_IE; -#endif // DOT11_N_SUPPORT // - - // - // Housekeeping "SsidBssTab" table for later-on ROAMing usage. - // - Bssidx = BssTableSearch(&pAd->ScanTab, Bssid, Channel); - if (Bssidx == BSS_NOT_FOUND) - { - // discover new AP of this network, create BSS entry - Bssidx = BssTableSetEntry(pAd, &pAd->ScanTab, Bssid, Ssid, SsidLen, BssType, BeaconPeriod, - &CfParm, AtimWin, CapabilityInfo, SupRate, SupRateLen, ExtRate, ExtRateLen, - &HtCapability, &AddHtInfo,HtCapabilityLen,AddHtInfoLen,NewExtChannelOffset, Channel, - RealRssi, TimeStamp, CkipFlag, &EdcaParm, &QosCapability, - &QbssLoad, LenVIE, pVIE); - if (Bssidx == BSS_NOT_FOUND) // return if BSS table full - return; - - NdisMoveMemory(pAd->ScanTab.BssEntry[Bssidx].PTSF, &Elem->Msg[24], 4); - NdisMoveMemory(&pAd->ScanTab.BssEntry[Bssidx].TTSF[0], &Elem->TimeStamp.u.LowPart, 4); - NdisMoveMemory(&pAd->ScanTab.BssEntry[Bssidx].TTSF[4], &Elem->TimeStamp.u.LowPart, 4); - - - - } - - if ((pAd->CommonCfg.bIEEE80211H == 1) && (NewChannel != 0) && (Channel != NewChannel)) - { - // Switching to channel 1 can prevent from rescanning the current channel immediately (by auto reconnection). - // In addition, clear the MLME queue and the scan table to discard the RX packets and previous scanning results. - AsicSwitchChannel(pAd, 1, FALSE); - AsicLockChannel(pAd, 1); - LinkDown(pAd, FALSE); - MlmeQueueInit(&pAd->Mlme.Queue); - BssTableInit(&pAd->ScanTab); - RTMPusecDelay(1000000); // use delay to prevent STA do reassoc - - // channel sanity check - for (index = 0 ; index < pAd->ChannelListNum; index++) - { - if (pAd->ChannelList[index].Channel == NewChannel) - { - pAd->ScanTab.BssEntry[Bssidx].Channel = NewChannel; - pAd->CommonCfg.Channel = NewChannel; - AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); - AsicLockChannel(pAd, pAd->CommonCfg.Channel); - DBGPRINT(RT_DEBUG_TRACE, ("PeerBeacon - STA receive channel switch announcement IE (New Channel =%d)\n", NewChannel)); - break; - } - } - - if (index >= pAd->ChannelListNum) - { - DBGPRINT_ERR(("PeerBeacon(can not find New Channel=%d in ChannelList[%d]\n", pAd->CommonCfg.Channel, pAd->ChannelListNum)); - } - } - - // if the ssid matched & bssid unmatched, we should select the bssid with large value. - // This might happened when two STA start at the same time - if ((! is_my_bssid) && ADHOC_ON(pAd)) - { - INT i; - - // Add the safeguard against the mismatch of adhoc wep status - if (pAd->StaCfg.WepStatus != pAd->ScanTab.BssEntry[Bssidx].WepStatus) - { - DBGPRINT(RT_DEBUG_TRACE, ("SYNC - Not matched wep status %d %d\n", pAd->StaCfg.WepStatus, pAd->ScanTab.BssEntry[Bssidx].WepStatus)); - DBGPRINT(RT_DEBUG_TRACE, ("bssid=%s\n", pAd->ScanTab.BssEntry[Bssidx].Bssid)); - return; - } - - // collapse into the ADHOC network which has bigger BSSID value. - for (i = 0; i < 6; i++) - { - if (Bssid[i] > pAd->CommonCfg.Bssid[i]) - { - DBGPRINT(RT_DEBUG_TRACE, ("SYNC - merge to the IBSS with bigger BSSID=%02x:%02x:%02x:%02x:%02x:%02x\n", - Bssid[0], Bssid[1], Bssid[2], Bssid[3], Bssid[4], Bssid[5])); - AsicDisableSync(pAd); - COPY_MAC_ADDR(pAd->CommonCfg.Bssid, Bssid); - AsicSetBssid(pAd, pAd->CommonCfg.Bssid); - MakeIbssBeacon(pAd); // re-build BEACON frame - AsicEnableIbssSync(pAd); // copy BEACON frame to on-chip memory - is_my_bssid = TRUE; - break; - } - else if (Bssid[i] < pAd->CommonCfg.Bssid[i]) - break; - } - } - - - NdisGetSystemUpTime(&Now); - pBss = &pAd->ScanTab.BssEntry[Bssidx]; - pBss->Rssi = RealRssi; // lastest RSSI - pBss->LastBeaconRxTime = Now; // last RX timestamp - - // - // BEACON from my BSSID - either IBSS or INFRA network - // - if (is_my_bssid) - { - RXWI_STRUC RxWI; - - pAd->StaCfg.DtimCount = DtimCount; - pAd->StaCfg.DtimPeriod = DtimPeriod; - pAd->StaCfg.LastBeaconRxTime = Now; - - - RxWI.RSSI0 = Elem->Rssi0; - RxWI.RSSI1 = Elem->Rssi1; - RxWI.RSSI2 = Elem->Rssi2; - - Update_Rssi_Sample(pAd, &pAd->StaCfg.RssiSample, &RxWI); - if (AironetCellPowerLimit != 0xFF) - { - // - // We get the Cisco (ccx) "TxPower Limit" required - // Changed to appropriate TxPower Limit for Ciso Compatible Extensions - // - ChangeToCellPowerLimit(pAd, AironetCellPowerLimit); - } - else - { - // - // AironetCellPowerLimit equal to 0xFF means the Cisco (ccx) "TxPower Limit" not exist. - // Used the default TX Power Percentage, that set from UI. - // - pAd->CommonCfg.TxPowerPercentage = pAd->CommonCfg.TxPowerDefault; - } - - if (ADHOC_ON(pAd) && (CAP_IS_IBSS_ON(CapabilityInfo))) - { - UCHAR MaxSupportedRateIn500Kbps = 0; - UCHAR idx; - MAC_TABLE_ENTRY *pEntry; - - // supported rates array may not be sorted. sort it and find the maximum rate - for (idx=0; idxWcid == RESERVED_WCID)) || - (pEntry && ((pEntry->LastBeaconRxTime + ADHOC_ENTRY_BEACON_LOST_TIME) < Now))) - { - if (pEntry == NULL) - // Another adhoc joining, add to our MAC table. - pEntry = MacTableInsertEntry(pAd, Addr2, BSS0, FALSE); - - if (StaAddMacTableEntry(pAd, pEntry, MaxSupportedRateIn500Kbps, &HtCapability, HtCapabilityLen, CapabilityInfo) == FALSE) - { - DBGPRINT(RT_DEBUG_TRACE, ("ADHOC - Add Entry failed.\n")); - return; - } - - if (pEntry && - (Elem->Wcid == RESERVED_WCID)) - { - idx = pAd->StaCfg.DefaultKeyId; - RT28XX_STA_SECURITY_INFO_ADD(pAd, BSS0, idx, pEntry); - } - } - - if (pEntry && pEntry->ValidAsCLI) - pEntry->LastBeaconRxTime = Now; - - // At least another peer in this IBSS, declare MediaState as CONNECTED - if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) - { - OPSTATUS_SET_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED); - - pAd->IndicateMediaState = NdisMediaStateConnected; - RTMP_IndicateMediaState(pAd); - pAd->ExtraInfo = GENERAL_LINK_UP; - AsicSetBssid(pAd, pAd->CommonCfg.Bssid); - - // 2003/03/12 - john - // Make sure this entry in "ScanTab" table, thus complies to Microsoft's policy that - // "site survey" result should always include the current connected network. - // - Bssidx = BssTableSearch(&pAd->ScanTab, Bssid, Channel); - if (Bssidx == BSS_NOT_FOUND) - { - Bssidx = BssTableSetEntry(pAd, &pAd->ScanTab, Bssid, Ssid, SsidLen, BssType, BeaconPeriod, - &CfParm, AtimWin, CapabilityInfo, SupRate, SupRateLen, ExtRate, ExtRateLen, &HtCapability, - &AddHtInfo, HtCapabilityLen, AddHtInfoLen, NewExtChannelOffset, Channel, RealRssi, TimeStamp, 0, - &EdcaParm, &QosCapability, &QbssLoad, LenVIE, pVIE); - } - DBGPRINT(RT_DEBUG_TRACE, ("ADHOC fOP_STATUS_MEDIA_STATE_CONNECTED.\n")); - } - } - - if (INFRA_ON(pAd)) - { - BOOLEAN bUseShortSlot, bUseBGProtection; - - // decide to use/change to - - // 1. long slot (20 us) or short slot (9 us) time - // 2. turn on/off RTS/CTS and/or CTS-to-self protection - // 3. short preamble - - //bUseShortSlot = pAd->CommonCfg.bUseShortSlotTime && CAP_IS_SHORT_SLOT(CapabilityInfo); - bUseShortSlot = CAP_IS_SHORT_SLOT(CapabilityInfo); - if (bUseShortSlot != OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_SHORT_SLOT_INUSED)) - AsicSetSlotTime(pAd, bUseShortSlot); - - bUseBGProtection = (pAd->CommonCfg.UseBGProtection == 1) || // always use - ((pAd->CommonCfg.UseBGProtection == 0) && ERP_IS_USE_PROTECTION(Erp)); - - if (pAd->CommonCfg.Channel > 14) // always no BG protection in A-band. falsely happened when switching A/G band to a dual-band AP - bUseBGProtection = FALSE; - - if (bUseBGProtection != OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_BG_PROTECTION_INUSED)) - { - if (bUseBGProtection) - { - OPSTATUS_SET_FLAG(pAd, fOP_STATUS_BG_PROTECTION_INUSED); - AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, (OFDMSETPROTECT|CCKSETPROTECT|ALLN_SETPROTECT),FALSE,(pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent == 1)); - } - else - { - OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_BG_PROTECTION_INUSED); - AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, (OFDMSETPROTECT|CCKSETPROTECT|ALLN_SETPROTECT),TRUE,(pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent == 1)); - } - - DBGPRINT(RT_DEBUG_WARN, ("SYNC - AP changed B/G protection to %d\n", bUseBGProtection)); - } - -#ifdef DOT11_N_SUPPORT - // check Ht protection mode. and adhere to the Non-GF device indication by AP. - if ((AddHtInfoLen != 0) && - ((AddHtInfo.AddHtInfo2.OperaionMode != pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode) || - (AddHtInfo.AddHtInfo2.NonGfPresent != pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent))) - { - pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent = AddHtInfo.AddHtInfo2.NonGfPresent; - pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode = AddHtInfo.AddHtInfo2.OperaionMode; - if (pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent == 1) - { - AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, ALLN_SETPROTECT, FALSE, TRUE); - } - else - AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, ALLN_SETPROTECT, FALSE, FALSE); - - DBGPRINT(RT_DEBUG_TRACE, ("SYNC - AP changed N OperaionMode to %d\n", pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode)); - } -#endif // DOT11_N_SUPPORT // - - if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED) && - ERP_IS_USE_BARKER_PREAMBLE(Erp)) - { - MlmeSetTxPreamble(pAd, Rt802_11PreambleLong); - DBGPRINT(RT_DEBUG_TRACE, ("SYNC - AP forced to use LONG preamble\n")); - } - - if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED) && - (EdcaParm.bValid == TRUE) && - (EdcaParm.EdcaUpdateCount != pAd->CommonCfg.APEdcaParm.EdcaUpdateCount)) - { - DBGPRINT(RT_DEBUG_TRACE, ("SYNC - AP change EDCA parameters(from %d to %d)\n", - pAd->CommonCfg.APEdcaParm.EdcaUpdateCount, - EdcaParm.EdcaUpdateCount)); - AsicSetEdcaParm(pAd, &EdcaParm); - } - - // copy QOS related information - NdisMoveMemory(&pAd->CommonCfg.APQbssLoad, &QbssLoad, sizeof(QBSS_LOAD_PARM)); - NdisMoveMemory(&pAd->CommonCfg.APQosCapability, &QosCapability, sizeof(QOS_CAPABILITY_PARM)); - } - - // only INFRASTRUCTURE mode support power-saving feature - if ((INFRA_ON(pAd) && (pAd->StaCfg.Psm == PWR_SAVE)) || (pAd->CommonCfg.bAPSDForcePowerSave)) - { - UCHAR FreeNumber; - // 1. AP has backlogged unicast-to-me frame, stay AWAKE, send PSPOLL - // 2. AP has backlogged broadcast/multicast frame and we want those frames, stay AWAKE - // 3. we have outgoing frames in TxRing or MgmtRing, better stay AWAKE - // 4. Psm change to PWR_SAVE, but AP not been informed yet, we better stay AWAKE - // 5. otherwise, put PHY back to sleep to save battery. - if (MessageToMe) - { - if (pAd->CommonCfg.bAPSDCapable && pAd->CommonCfg.APEdcaParm.bAPSDCapable && - pAd->CommonCfg.bAPSDAC_BE && pAd->CommonCfg.bAPSDAC_BK && pAd->CommonCfg.bAPSDAC_VI && pAd->CommonCfg.bAPSDAC_VO) - { - pAd->CommonCfg.bNeedSendTriggerFrame = TRUE; - } - else - RT28XX_PS_POLL_ENQUEUE(pAd); - } - else if (BcastFlag && (DtimCount == 0) && OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_RECEIVE_DTIM)) - { - } - else if ((pAd->TxSwQueue[QID_AC_BK].Number != 0) || - (pAd->TxSwQueue[QID_AC_BE].Number != 0) || - (pAd->TxSwQueue[QID_AC_VI].Number != 0) || - (pAd->TxSwQueue[QID_AC_VO].Number != 0) || - (RTMPFreeTXDRequest(pAd, QID_AC_BK, TX_RING_SIZE - 1, &FreeNumber) != NDIS_STATUS_SUCCESS) || - (RTMPFreeTXDRequest(pAd, QID_AC_BE, TX_RING_SIZE - 1, &FreeNumber) != NDIS_STATUS_SUCCESS) || - (RTMPFreeTXDRequest(pAd, QID_AC_VI, TX_RING_SIZE - 1, &FreeNumber) != NDIS_STATUS_SUCCESS) || - (RTMPFreeTXDRequest(pAd, QID_AC_VO, TX_RING_SIZE - 1, &FreeNumber) != NDIS_STATUS_SUCCESS) || - (RTMPFreeTXDRequest(pAd, QID_MGMT, MGMT_RING_SIZE - 1, &FreeNumber) != NDIS_STATUS_SUCCESS)) - { - // TODO: consider scheduled HCCA. might not be proper to use traditional DTIM-based power-saving scheme - // can we cheat here (i.e. just check MGMT & AC_BE) for better performance? - } - else - { - USHORT NextDtim = DtimCount; - - if (NextDtim == 0) - NextDtim = DtimPeriod; - - TbttNumToNextWakeUp = pAd->StaCfg.DefaultListenCount; - if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_RECEIVE_DTIM) && (TbttNumToNextWakeUp > NextDtim)) - TbttNumToNextWakeUp = NextDtim; - - if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) - { - AsicSleepThenAutoWakeup(pAd, TbttNumToNextWakeUp); - } - } - } - } - // not my BSSID, ignore it - } - // sanity check fail, ignore this frame -} - -/* - ========================================================================== - Description: - Receive PROBE REQ from remote peer when operating in IBSS mode - ========================================================================== - */ -VOID PeerProbeReqAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - UCHAR Addr2[MAC_ADDR_LEN]; - CHAR Ssid[MAX_LEN_OF_SSID]; - UCHAR SsidLen; -#ifdef DOT11_N_SUPPORT - UCHAR HtLen, AddHtLen, NewExtLen; -#endif // DOT11_N_SUPPORT // - HEADER_802_11 ProbeRspHdr; - NDIS_STATUS NStatus; - PUCHAR pOutBuffer = NULL; - ULONG FrameLen = 0; - LARGE_INTEGER FakeTimestamp; - UCHAR DsLen = 1, IbssLen = 2; - UCHAR LocalErpIe[3] = {IE_ERP, 1, 0}; - BOOLEAN Privacy; - USHORT CapabilityInfo; - UCHAR RSNIe = IE_WPA; - - if (! ADHOC_ON(pAd)) - return; - - if (PeerProbeReqSanity(pAd, Elem->Msg, Elem->MsgLen, Addr2, Ssid, &SsidLen)) - { - if ((SsidLen == 0) || SSID_EQUAL(Ssid, SsidLen, pAd->CommonCfg.Ssid, pAd->CommonCfg.SsidLen)) - { - // allocate and send out ProbeRsp frame - NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory - if (NStatus != NDIS_STATUS_SUCCESS) - return; - - //pAd->StaCfg.AtimWin = 0; // ?????? - - Privacy = (pAd->StaCfg.WepStatus == Ndis802_11Encryption1Enabled) || - (pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) || - (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled); - CapabilityInfo = CAP_GENERATE(0, 1, Privacy, (pAd->CommonCfg.TxPreamble == Rt802_11PreambleShort), 0, 0); - - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(HEADER_802_11), &ProbeRspHdr, - TIMESTAMP_LEN, &FakeTimestamp, - 2, &pAd->CommonCfg.BeaconPeriod, - 2, &CapabilityInfo, - 1, &SsidIe, - 1, &pAd->CommonCfg.SsidLen, - pAd->CommonCfg.SsidLen, pAd->CommonCfg.Ssid, - 1, &SupRateIe, - 1, &pAd->StaActive.SupRateLen, - pAd->StaActive.SupRateLen, pAd->StaActive.SupRate, - 1, &DsIe, - 1, &DsLen, - 1, &pAd->CommonCfg.Channel, - 1, &IbssIe, - 1, &IbssLen, - 2, &pAd->StaActive.AtimWin, - END_OF_ARGS); - - if (pAd->StaActive.ExtRateLen) - { - ULONG tmp; - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - 3, LocalErpIe, - 1, &ExtRateIe, - 1, &pAd->StaActive.ExtRateLen, - pAd->StaActive.ExtRateLen, &pAd->StaActive.ExtRate, - END_OF_ARGS); - FrameLen += tmp; - } - - // If adhoc secruity is set for WPA-None, append the cipher suite IE - if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) - { - ULONG tmp; - MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, - 1, &RSNIe, - 1, &pAd->StaCfg.RSNIE_Len, - pAd->StaCfg.RSNIE_Len, pAd->StaCfg.RSN_IE, - END_OF_ARGS); - FrameLen += tmp; - } -#ifdef DOT11_N_SUPPORT - if (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) - { - ULONG TmpLen; - UCHAR BROADCOM[4] = {0x0, 0x90, 0x4c, 0x33}; - HtLen = sizeof(pAd->CommonCfg.HtCapability); - AddHtLen = sizeof(pAd->CommonCfg.AddHTInfo); - NewExtLen = 1; - //New extension channel offset IE is included in Beacon, Probe Rsp or channel Switch Announcement Frame - if (pAd->bBroadComHT == TRUE) - { - MakeOutgoingFrame(pOutBuffer + FrameLen, &TmpLen, - 1, &WpaIe, - 4, &BROADCOM[0], - pAd->MlmeAux.HtCapabilityLen, &pAd->MlmeAux.HtCapability, - END_OF_ARGS); - } - else - { - MakeOutgoingFrame(pOutBuffer + FrameLen, &TmpLen, - 1, &HtCapIe, - 1, &HtLen, - sizeof(HT_CAPABILITY_IE), &pAd->CommonCfg.HtCapability, - 1, &AddHtInfoIe, - 1, &AddHtLen, - sizeof(ADD_HT_INFO_IE), &pAd->CommonCfg.AddHTInfo, - 1, &NewExtChanIe, - 1, &NewExtLen, - sizeof(NEW_EXT_CHAN_IE), &pAd->CommonCfg.NewExtChanOffset, - END_OF_ARGS); - } - FrameLen += TmpLen; - } -#endif // DOT11_N_SUPPORT // - MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); - } - } -} - -VOID BeaconTimeoutAtJoinAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - USHORT Status; - DBGPRINT(RT_DEBUG_TRACE, ("SYNC - BeaconTimeoutAtJoinAction\n")); - pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; - Status = MLME_REJ_TIMEOUT; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_JOIN_CONF, 2, &Status); -} - -/* - ========================================================================== - Description: - Scan timeout procedure. basically add channel index by 1 and rescan - ========================================================================== - */ -VOID ScanTimeoutAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - pAd->MlmeAux.Channel = NextChannel(pAd, pAd->MlmeAux.Channel); - - // Only one channel scanned for CISCO beacon request - if ((pAd->MlmeAux.ScanType == SCAN_CISCO_ACTIVE) || - (pAd->MlmeAux.ScanType == SCAN_CISCO_PASSIVE) || - (pAd->MlmeAux.ScanType == SCAN_CISCO_NOISE) || - (pAd->MlmeAux.ScanType == SCAN_CISCO_CHANNEL_LOAD)) - pAd->MlmeAux.Channel = 0; - - // this routine will stop if pAd->MlmeAux.Channel == 0 - ScanNextChannel(pAd); -} - -/* - ========================================================================== - Description: - ========================================================================== - */ -VOID InvalidStateWhenScan( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - USHORT Status; - DBGPRINT(RT_DEBUG_TRACE, ("AYNC - InvalidStateWhenScan(state=%ld). Reset SYNC machine\n", pAd->Mlme.SyncMachine.CurrState)); - pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; - Status = MLME_STATE_MACHINE_REJECT; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_SCAN_CONF, 2, &Status); -} - -/* - ========================================================================== - Description: - ========================================================================== - */ -VOID InvalidStateWhenJoin( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - USHORT Status; - DBGPRINT(RT_DEBUG_TRACE, ("InvalidStateWhenJoin(state=%ld). Reset SYNC machine\n", pAd->Mlme.SyncMachine.CurrState)); - pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; - Status = MLME_STATE_MACHINE_REJECT; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_JOIN_CONF, 2, &Status); -} - -/* - ========================================================================== - Description: - ========================================================================== - */ -VOID InvalidStateWhenStart( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - USHORT Status; - DBGPRINT(RT_DEBUG_TRACE, ("InvalidStateWhenStart(state=%ld). Reset SYNC machine\n", pAd->Mlme.SyncMachine.CurrState)); - pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; - Status = MLME_STATE_MACHINE_REJECT; - MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_START_CONF, 2, &Status); -} - -/* - ========================================================================== - Description: - - IRQL = DISPATCH_LEVEL - - ========================================================================== - */ -VOID EnqueuePsPoll( - IN PRTMP_ADAPTER pAd) -{ -#ifdef RALINK_ATE - if (ATE_ON(pAd)) - { - return; - } -#endif // RALINK_ATE // - - - if (pAd->StaCfg.WindowsPowerMode == Ndis802_11PowerModeLegacy_PSP) - pAd->PsPollFrame.FC.PwrMgmt = PWR_SAVE; - MiniportMMRequest(pAd, 0, (PUCHAR)&pAd->PsPollFrame, sizeof(PSPOLL_FRAME)); -} - - -/* - ========================================================================== - Description: - ========================================================================== - */ -VOID EnqueueProbeRequest( - IN PRTMP_ADAPTER pAd) -{ - NDIS_STATUS NState; - PUCHAR pOutBuffer; - ULONG FrameLen = 0; - HEADER_802_11 Hdr80211; - - DBGPRINT(RT_DEBUG_TRACE, ("force out a ProbeRequest ...\n")); - - NState = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory - if (NState == NDIS_STATUS_SUCCESS) - { - MgtMacHeaderInit(pAd, &Hdr80211, SUBTYPE_PROBE_REQ, 0, BROADCAST_ADDR, BROADCAST_ADDR); - - // this ProbeRequest explicitly specify SSID to reduce unwanted ProbeResponse - MakeOutgoingFrame(pOutBuffer, &FrameLen, - sizeof(HEADER_802_11), &Hdr80211, - 1, &SsidIe, - 1, &pAd->CommonCfg.SsidLen, - pAd->CommonCfg.SsidLen, pAd->CommonCfg.Ssid, - 1, &SupRateIe, - 1, &pAd->StaActive.SupRateLen, - pAd->StaActive.SupRateLen, pAd->StaActive.SupRate, - END_OF_ARGS); - MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); - MlmeFreeMemory(pAd, pOutBuffer); - } - -} - -#ifdef DOT11_N_SUPPORT -#ifdef DOT11N_DRAFT3 -VOID BuildEffectedChannelList( - IN PRTMP_ADAPTER pAd) -{ - UCHAR EChannel[11]; - UCHAR i, j, k; - UCHAR UpperChannel = 0, LowerChannel = 0; - - RTMPZeroMemory(EChannel, 11); - i = 0; - // Find upper channel and lower channel. - if (pAd->CommonCfg.CentralChannel < pAd->CommonCfg.Channel) - { - UpperChannel = pAd->CommonCfg.Channel; - LowerChannel = pAd->CommonCfg.CentralChannel; - } - else if (pAd->CommonCfg.CentralChannel > pAd->CommonCfg.Channel) - { - UpperChannel = pAd->CommonCfg.CentralChannel; - LowerChannel = pAd->CommonCfg.Channel; - } - else - { - return; - } - - // Record channels that is below lower channel.. - if (LowerChannel > 1) - { - EChannel[0] = LowerChannel - 1; - i = 1; - if (LowerChannel > 2) - { - EChannel[1] = LowerChannel - 2; - i = 2; - if (LowerChannel > 3) - { - EChannel[2] = LowerChannel - 3; - i = 3; - } - } - } - // Record channels that is between lower channel and upper channel. - for (k = LowerChannel;k < UpperChannel;k++) - { - EChannel[i] = k; - i++; - } - // Record channels that is above upper channel.. - if (LowerChannel < 11) - { - EChannel[i] = UpperChannel + 1; - i++; - if (LowerChannel < 10) - { - EChannel[i] = LowerChannel + 2; - i++; - if (LowerChannel < 9) - { - EChannel[i] = LowerChannel + 3; - i++; - } - } - } - // - for (j = 0;j < i;j++) - { - for (k = 0;k < pAd->ChannelListNum;k++) - { - if (pAd->ChannelList[k].Channel == EChannel[j]) - { - pAd->ChannelList[k].bEffectedChannel = TRUE; - DBGPRINT(RT_DEBUG_TRACE,(" EffectedChannel( =%d)\n", EChannel[j])); - break; - } - } - } -} -#endif // DOT11N_DRAFT3 // -#endif // DOT11_N_SUPPORT // - -BOOLEAN ScanRunning( - IN PRTMP_ADAPTER pAd) -{ - return (pAd->Mlme.SyncMachine.CurrState == SCAN_LISTEN) ? TRUE : FALSE; -} - +#include "../../rt2870/sta/sync.c" diff --git a/drivers/staging/rt3070/sta/wpa.c b/drivers/staging/rt3070/sta/wpa.c index 63d08306bf6f..95543bb1f0ec 100644 --- a/drivers/staging/rt3070/sta/wpa.c +++ b/drivers/staging/rt3070/sta/wpa.c @@ -1,2099 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - wpa.c - - Abstract: - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Jan Lee 03-07-22 Initial - Paul Lin 03-11-28 Modify for supplicant -*/ -#include "../rt_config.h" - -#define WPARSNIE 0xdd -#define WPA2RSNIE 0x30 - -//extern UCHAR BIT8[]; -UCHAR CipherWpaPskTkip[] = { - 0xDD, 0x16, // RSN IE - 0x00, 0x50, 0xf2, 0x01, // oui - 0x01, 0x00, // Version - 0x00, 0x50, 0xf2, 0x02, // Multicast - 0x01, 0x00, // Number of unicast - 0x00, 0x50, 0xf2, 0x02, // unicast - 0x01, 0x00, // number of authentication method - 0x00, 0x50, 0xf2, 0x02 // authentication - }; -UCHAR CipherWpaPskTkipLen = (sizeof(CipherWpaPskTkip) / sizeof(UCHAR)); - -UCHAR CipherWpaPskAes[] = { - 0xDD, 0x16, // RSN IE - 0x00, 0x50, 0xf2, 0x01, // oui - 0x01, 0x00, // Version - 0x00, 0x50, 0xf2, 0x04, // Multicast - 0x01, 0x00, // Number of unicast - 0x00, 0x50, 0xf2, 0x04, // unicast - 0x01, 0x00, // number of authentication method - 0x00, 0x50, 0xf2, 0x02 // authentication - }; -UCHAR CipherWpaPskAesLen = (sizeof(CipherWpaPskAes) / sizeof(UCHAR)); - -UCHAR CipherSuiteCiscoCCKM[] = { - 0xDD, 0x16, // RSN IE - 0x00, 0x50, 0xf2, 0x01, // oui - 0x01, 0x00, // Version - 0x00, 0x40, 0x96, 0x01, // Multicast - 0x01, 0x00, // Number of uicast - 0x00, 0x40, 0x96, 0x01, // unicast - 0x01, 0x00, // number of authentication method - 0x00, 0x40, 0x96, 0x00 // Authentication - }; -UCHAR CipherSuiteCiscoCCKMLen = (sizeof(CipherSuiteCiscoCCKM) / sizeof(UCHAR)); - -UCHAR CipherSuiteCiscoCCKM24[] = { - 0xDD, 0x18, // RSN IE - 0x00, 0x50, 0xf2, 0x01, // oui - 0x01, 0x00, // Version - 0x00, 0x40, 0x96, 0x01, // Multicast - 0x01, 0x00, // Number of uicast - 0x00, 0x40, 0x96, 0x01, // unicast - 0x01, 0x00, // number of authentication method - 0x00, 0x40, 0x96, 0x00, - 0x28, 0x00// Authentication - }; - -UCHAR CipherSuiteCiscoCCKM24Len = (sizeof(CipherSuiteCiscoCCKM24) / sizeof(UCHAR)); - -UCHAR CipherSuiteCCXTkip[] = { - 0xDD, 0x16, // RSN IE - 0x00, 0x50, 0xf2, 0x01, // oui - 0x01, 0x00, // Version - 0x00, 0x50, 0xf2, 0x02, // Multicast - 0x01, 0x00, // Number of unicast - 0x00, 0x50, 0xf2, 0x02, // unicast - 0x01, 0x00, // number of authentication method - 0x00, 0x50, 0xf2, 0x01 // authentication - }; -UCHAR CipherSuiteCCXTkipLen = (sizeof(CipherSuiteCCXTkip) / sizeof(UCHAR)); - -UCHAR CCX_LLC_HDR[] = {0xAA, 0xAA, 0x03, 0x00, 0x40, 0x96, 0x00, 0x02}; -UCHAR LLC_NORMAL[] = {0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00}; - -UCHAR EAPOL_FRAME[] = {0x88, 0x8E}; - -BOOLEAN CheckRSNIE( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pData, - IN UCHAR DataLen, - OUT UCHAR *Offset); - -void inc_byte_array(UCHAR *counter, int len); - -/* - ======================================================================== - - Routine Description: - Classify WPA EAP message type - - Arguments: - EAPType Value of EAP message type - MsgType Internal Message definition for MLME state machine - - Return Value: - TRUE Found appropriate message type - FALSE No appropriate message type - - IRQL = DISPATCH_LEVEL - - Note: - All these constants are defined in wpa.h - For supplicant, there is only EAPOL Key message avaliable - - ======================================================================== -*/ -BOOLEAN WpaMsgTypeSubst( - IN UCHAR EAPType, - OUT INT *MsgType) -{ - switch (EAPType) - { - case EAPPacket: - *MsgType = MT2_EAPPacket; - break; - case EAPOLStart: - *MsgType = MT2_EAPOLStart; - break; - case EAPOLLogoff: - *MsgType = MT2_EAPOLLogoff; - break; - case EAPOLKey: - *MsgType = MT2_EAPOLKey; - break; - case EAPOLASFAlert: - *MsgType = MT2_EAPOLASFAlert; - break; - default: - return FALSE; - } - return TRUE; -} - -/* - ========================================================================== - Description: - association state machine init, including state transition and timer init - Parameters: - S - pointer to the association state machine - ========================================================================== - */ -VOID WpaPskStateMachineInit( - IN PRTMP_ADAPTER pAd, - IN STATE_MACHINE *S, - OUT STATE_MACHINE_FUNC Trans[]) -{ - StateMachineInit(S, Trans, MAX_WPA_PSK_STATE, MAX_WPA_PSK_MSG, (STATE_MACHINE_FUNC)Drop, WPA_PSK_IDLE, WPA_MACHINE_BASE); - StateMachineSetAction(S, WPA_PSK_IDLE, MT2_EAPOLKey, (STATE_MACHINE_FUNC)WpaEAPOLKeyAction); -} - -/* - ========================================================================== - Description: - This is state machine function. - When receiving EAPOL packets which is for 802.1x key management. - Use both in WPA, and WPAPSK case. - In this function, further dispatch to different functions according to the received packet. 3 categories are : - 1. normal 4-way pairwisekey and 2-way groupkey handshake - 2. MIC error (Countermeasures attack) report packet from STA. - 3. Request for pairwise/group key update from STA - Return: - ========================================================================== -*/ -VOID WpaEAPOLKeyAction( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) - -{ - INT MsgType = EAPOL_MSG_INVALID; - PKEY_DESCRIPTER pKeyDesc; - PHEADER_802_11 pHeader; //red - UCHAR ZeroReplay[LEN_KEY_DESC_REPLAY]; - UCHAR EapolVr; - KEY_INFO peerKeyInfo; - - DBGPRINT(RT_DEBUG_TRACE, ("-----> WpaEAPOLKeyAction\n")); - - // Get 802.11 header first - pHeader = (PHEADER_802_11) Elem->Msg; - - // Get EAPoL-Key Descriptor - pKeyDesc = (PKEY_DESCRIPTER) &Elem->Msg[(LENGTH_802_11 + LENGTH_802_1_H + LENGTH_EAPOL_H)]; - - NdisZeroMemory((PUCHAR)&peerKeyInfo, sizeof(peerKeyInfo)); - NdisMoveMemory((PUCHAR)&peerKeyInfo, (PUCHAR)&pKeyDesc->KeyInfo, sizeof(KEY_INFO)); - - *((USHORT *)&peerKeyInfo) = cpu2le16(*((USHORT *)&peerKeyInfo)); - - - // 1. Check EAPOL frame version and type - EapolVr = (UCHAR) Elem->Msg[LENGTH_802_11+LENGTH_802_1_H]; - - if (((EapolVr != EAPOL_VER) && (EapolVr != EAPOL_VER2)) || ((pKeyDesc->Type != WPA1_KEY_DESC) && (pKeyDesc->Type != WPA2_KEY_DESC))) - { - DBGPRINT(RT_DEBUG_ERROR, ("Key descripter does not match with WPA rule\n")); - return; - } - - // First validate replay counter, only accept message with larger replay counter - // Let equal pass, some AP start with all zero replay counter - NdisZeroMemory(ZeroReplay, LEN_KEY_DESC_REPLAY); - - if((RTMPCompareMemory(pKeyDesc->ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY) != 1) && - (RTMPCompareMemory(pKeyDesc->ReplayCounter, ZeroReplay, LEN_KEY_DESC_REPLAY) != 0)) - { - DBGPRINT(RT_DEBUG_ERROR, (" ReplayCounter not match \n")); - return; - } - - // Process WPA2PSK frame - if(pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) - { - if((peerKeyInfo.KeyType == PAIRWISEKEY) && - (peerKeyInfo.EKD_DL == 0) && - (peerKeyInfo.KeyAck == 1) && - (peerKeyInfo.KeyMic == 0) && - (peerKeyInfo.Secure == 0) && - (peerKeyInfo.Error == 0) && - (peerKeyInfo.Request == 0)) - { - MsgType = EAPOL_PAIR_MSG_1; - DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL Key Pairwise Message 1\n")); - } else if((peerKeyInfo.KeyType == PAIRWISEKEY) && - (peerKeyInfo.EKD_DL == 1) && - (peerKeyInfo.KeyAck == 1) && - (peerKeyInfo.KeyMic == 1) && - (peerKeyInfo.Secure == 1) && - (peerKeyInfo.Error == 0) && - (peerKeyInfo.Request == 0)) - { - MsgType = EAPOL_PAIR_MSG_3; - DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL Key Pairwise Message 3\n")); - } else if((peerKeyInfo.KeyType == GROUPKEY) && - (peerKeyInfo.EKD_DL == 1) && - (peerKeyInfo.KeyAck == 1) && - (peerKeyInfo.KeyMic == 1) && - (peerKeyInfo.Secure == 1) && - (peerKeyInfo.Error == 0) && - (peerKeyInfo.Request == 0)) - { - MsgType = EAPOL_GROUP_MSG_1; - DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL Key Group Message 1\n")); - } - - // We will assume link is up (assoc suceess and port not secured). - // All state has to be able to process message from previous state - switch(pAd->StaCfg.WpaState) - { - case SS_START: - if(MsgType == EAPOL_PAIR_MSG_1) - { - Wpa2PairMsg1Action(pAd, Elem); - pAd->StaCfg.WpaState = SS_WAIT_MSG_3; - } - break; - - case SS_WAIT_MSG_3: - if(MsgType == EAPOL_PAIR_MSG_1) - { - Wpa2PairMsg1Action(pAd, Elem); - pAd->StaCfg.WpaState = SS_WAIT_MSG_3; - } - else if(MsgType == EAPOL_PAIR_MSG_3) - { - Wpa2PairMsg3Action(pAd, Elem); - pAd->StaCfg.WpaState = SS_WAIT_GROUP; - } - break; - - case SS_WAIT_GROUP: // When doing group key exchange - case SS_FINISH: // This happened when update group key - if(MsgType == EAPOL_PAIR_MSG_1) - { - // Reset port secured variable - pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; - Wpa2PairMsg1Action(pAd, Elem); - pAd->StaCfg.WpaState = SS_WAIT_MSG_3; - } - else if(MsgType == EAPOL_PAIR_MSG_3) - { - // Reset port secured variable - pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; - Wpa2PairMsg3Action(pAd, Elem); - pAd->StaCfg.WpaState = SS_WAIT_GROUP; - } - else if(MsgType == EAPOL_GROUP_MSG_1) - { - WpaGroupMsg1Action(pAd, Elem); - pAd->StaCfg.WpaState = SS_FINISH; - } - break; - - default: - break; - } - } - // Process WPAPSK Frame - // Classify message Type, either pairwise message 1, 3, or group message 1 for supplicant - else if(pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) - { - if((peerKeyInfo.KeyType == PAIRWISEKEY) && - (peerKeyInfo.KeyIndex == 0) && - (peerKeyInfo.KeyAck == 1) && - (peerKeyInfo.KeyMic == 0) && - (peerKeyInfo.Secure == 0) && - (peerKeyInfo.Error == 0) && - (peerKeyInfo.Request == 0)) - { - MsgType = EAPOL_PAIR_MSG_1; - DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL Key Pairwise Message 1\n")); - } - else if((peerKeyInfo.KeyType == PAIRWISEKEY) && - (peerKeyInfo.KeyIndex == 0) && - (peerKeyInfo.KeyAck == 1) && - (peerKeyInfo.KeyMic == 1) && - (peerKeyInfo.Secure == 0) && - (peerKeyInfo.Error == 0) && - (peerKeyInfo.Request == 0)) - { - MsgType = EAPOL_PAIR_MSG_3; - DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL Key Pairwise Message 3\n")); - } - else if((peerKeyInfo.KeyType == GROUPKEY) && - (peerKeyInfo.KeyIndex != 0) && - (peerKeyInfo.KeyAck == 1) && - (peerKeyInfo.KeyMic == 1) && - (peerKeyInfo.Secure == 1) && - (peerKeyInfo.Error == 0) && - (peerKeyInfo.Request == 0)) - { - MsgType = EAPOL_GROUP_MSG_1; - DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL Key Group Message 1\n")); - } - - // We will assume link is up (assoc suceess and port not secured). - // All state has to be able to process message from previous state - switch(pAd->StaCfg.WpaState) - { - case SS_START: - if(MsgType == EAPOL_PAIR_MSG_1) - { - WpaPairMsg1Action(pAd, Elem); - pAd->StaCfg.WpaState = SS_WAIT_MSG_3; - } - break; - - case SS_WAIT_MSG_3: - if(MsgType == EAPOL_PAIR_MSG_1) - { - WpaPairMsg1Action(pAd, Elem); - pAd->StaCfg.WpaState = SS_WAIT_MSG_3; - } - else if(MsgType == EAPOL_PAIR_MSG_3) - { - WpaPairMsg3Action(pAd, Elem); - pAd->StaCfg.WpaState = SS_WAIT_GROUP; - } - break; - - case SS_WAIT_GROUP: // When doing group key exchange - case SS_FINISH: // This happened when update group key - if(MsgType == EAPOL_PAIR_MSG_1) - { - WpaPairMsg1Action(pAd, Elem); - pAd->StaCfg.WpaState = SS_WAIT_MSG_3; - // Reset port secured variable - pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; - } - else if(MsgType == EAPOL_PAIR_MSG_3) - { - WpaPairMsg3Action(pAd, Elem); - pAd->StaCfg.WpaState = SS_WAIT_GROUP; - // Reset port secured variable - pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; - } - else if(MsgType == EAPOL_GROUP_MSG_1) - { - WpaGroupMsg1Action(pAd, Elem); - pAd->StaCfg.WpaState = SS_FINISH; - } - break; - - default: - break; - } - } - - DBGPRINT(RT_DEBUG_TRACE, ("<----- WpaEAPOLKeyAction\n")); -} - -/* - ======================================================================== - - Routine Description: - Process Pairwise key 4-way handshaking - - Arguments: - pAd Pointer to our adapter - Elem Message body - - Return Value: - None - - Note: - - ======================================================================== -*/ -VOID WpaPairMsg1Action( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - PHEADER_802_11 pHeader; - UCHAR *mpool, *PTK, *digest; - PUCHAR pOutBuffer = NULL; - UCHAR Header802_3[14]; - ULONG FrameLen = 0; - PEAPOL_PACKET pMsg1; - EAPOL_PACKET Packet; - UCHAR Mic[16]; - - DBGPRINT(RT_DEBUG_TRACE, ("WpaPairMsg1Action ----->\n")); - - // allocate memory pool - os_alloc_mem(pAd, (PUCHAR *)&mpool, 256); - - if (mpool == NULL) - return; - - // PTK Len = 80. - PTK = (UCHAR *) ROUND_UP(mpool, 4); - // digest Len = 80. - digest = (UCHAR *) ROUND_UP(PTK + 80, 4); - - pHeader = (PHEADER_802_11) Elem->Msg; - - // Process message 1 from authenticator - pMsg1 = (PEAPOL_PACKET) &Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H]; - - // 1. Save Replay counter, it will use to verify message 3 and construct message 2 - NdisMoveMemory(pAd->StaCfg.ReplayCounter, pMsg1->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); - - // 2. Save ANonce - NdisMoveMemory(pAd->StaCfg.ANonce, pMsg1->KeyDesc.KeyNonce, LEN_KEY_DESC_NONCE); - - // Generate random SNonce - GenRandom(pAd, pAd->CurrentAddress, pAd->StaCfg.SNonce); - - // Calc PTK(ANonce, SNonce) - WpaCountPTK(pAd, - pAd->StaCfg.PMK, - pAd->StaCfg.ANonce, - pAd->CommonCfg.Bssid, - pAd->StaCfg.SNonce, - pAd->CurrentAddress, - PTK, - LEN_PTK); - - // Save key to PTK entry - NdisMoveMemory(pAd->StaCfg.PTK, PTK, LEN_PTK); - - // init 802.3 header and Fill Packet - MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL); - - // Zero Message 2 body - NdisZeroMemory(&Packet, sizeof(Packet)); - Packet.ProVer = EAPOL_VER; - Packet.ProType = EAPOLKey; - // - // Message 2 as EAPOL-Key(0,1,0,0,0,P,0,SNonce,MIC,RSN IE) - // - Packet.KeyDesc.Type = WPA1_KEY_DESC; - // 1. Key descriptor version and appropriate RSN IE - if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) - { - Packet.KeyDesc.KeyInfo.KeyDescVer = 2; - } - else // TKIP - { - Packet.KeyDesc.KeyInfo.KeyDescVer = 1; - } - - // fill in Data Material and its length - Packet.KeyDesc.KeyData[0] = IE_WPA; - Packet.KeyDesc.KeyData[1] = pAd->StaCfg.RSNIE_Len; - Packet.KeyDesc.KeyDataLen[1] = pAd->StaCfg.RSNIE_Len + 2; - NdisMoveMemory(&Packet.KeyDesc.KeyData[2], pAd->StaCfg.RSN_IE, pAd->StaCfg.RSNIE_Len); - - // Update packet length after decide Key data payload - Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE + Packet.KeyDesc.KeyDataLen[1]; - - // Update Key length - Packet.KeyDesc.KeyLength[0] = pMsg1->KeyDesc.KeyLength[0]; - Packet.KeyDesc.KeyLength[1] = pMsg1->KeyDesc.KeyLength[1]; - // 2. Key Type PeerKey - Packet.KeyDesc.KeyInfo.KeyType = PAIRWISEKEY; - - // 3. KeyMic field presented - Packet.KeyDesc.KeyInfo.KeyMic = 1; - - //Convert to little-endian format. - *((USHORT *)&Packet.KeyDesc.KeyInfo) = cpu2le16(*((USHORT *)&Packet.KeyDesc.KeyInfo)); - - - // 4. Fill SNonce - NdisMoveMemory(Packet.KeyDesc.KeyNonce, pAd->StaCfg.SNonce, LEN_KEY_DESC_NONCE); - - // 5. Key Replay Count - NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY); - - // Send EAPOL(0, 1, 0, 0, 0, P, 0, SNonce, MIC, RSN_IE) - // Out buffer for transmitting message 2 - MlmeAllocateMemory(pAd, (PUCHAR *)&pOutBuffer); // allocate memory - if(pOutBuffer == NULL) - { - os_free_mem(pAd, mpool); - return; - } - // Prepare EAPOL frame for MIC calculation - // Be careful, only EAPOL frame is counted for MIC calculation - MakeOutgoingFrame(pOutBuffer, &FrameLen, - Packet.Body_Len[1] + 4, &Packet, - END_OF_ARGS); - - // 6. Prepare and Fill MIC value - NdisZeroMemory(Mic, sizeof(Mic)); - if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) - { // AES - - HMAC_SHA1(pOutBuffer, FrameLen, PTK, LEN_EAP_MICK, digest); - NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); - } - else - { // TKIP - hmac_md5(PTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic); - } - NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC); - - //hex_dump("MIC", Mic, LEN_KEY_DESC_MIC); - - MakeOutgoingFrame(pOutBuffer, &FrameLen, - LENGTH_802_3, &Header802_3, - Packet.Body_Len[1] + 4, &Packet, - END_OF_ARGS); - - - // 5. Copy frame to Tx ring and send Msg 2 to authenticator - RTMPToWirelessSta(pAd, Header802_3, LENGTH_802_3, (PUCHAR)&Packet, Packet.Body_Len[1] + 4, TRUE); - - MlmeFreeMemory(pAd, (PUCHAR)pOutBuffer); - os_free_mem(pAd, (PUCHAR)mpool); - - DBGPRINT(RT_DEBUG_TRACE, ("WpaPairMsg1Action <-----\n")); -} - -VOID Wpa2PairMsg1Action( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - PHEADER_802_11 pHeader; - UCHAR *mpool, *PTK, *digest; - PUCHAR pOutBuffer = NULL; - UCHAR Header802_3[14]; - ULONG FrameLen = 0; - PEAPOL_PACKET pMsg1; - EAPOL_PACKET Packet; - UCHAR Mic[16]; - - DBGPRINT(RT_DEBUG_TRACE, ("Wpa2PairMsg1Action ----->\n")); - - // allocate memory pool - os_alloc_mem(pAd, (PUCHAR *)&mpool, 256); - - if (mpool == NULL) - return; - - // PTK Len = 80. - PTK = (UCHAR *) ROUND_UP(mpool, 4); - // digest Len = 80. - digest = (UCHAR *) ROUND_UP(PTK + 80, 4); - - pHeader = (PHEADER_802_11) Elem->Msg; - - // Process message 1 from authenticator - pMsg1 = (PEAPOL_PACKET) &Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H]; - - // 1. Save Replay counter, it will use to verify message 3 and construct message 2 - NdisMoveMemory(pAd->StaCfg.ReplayCounter, pMsg1->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); - - // 2. Save ANonce - NdisMoveMemory(pAd->StaCfg.ANonce, pMsg1->KeyDesc.KeyNonce, LEN_KEY_DESC_NONCE); - - // Generate random SNonce - GenRandom(pAd, pAd->CurrentAddress, pAd->StaCfg.SNonce); - - if(pMsg1->KeyDesc.KeyDataLen[1] > 0 ) - { - // cached PMKID - } - - // Calc PTK(ANonce, SNonce) - WpaCountPTK(pAd, - pAd->StaCfg.PMK, - pAd->StaCfg.ANonce, - pAd->CommonCfg.Bssid, - pAd->StaCfg.SNonce, - pAd->CurrentAddress, - PTK, - LEN_PTK); - - // Save key to PTK entry - NdisMoveMemory(pAd->StaCfg.PTK, PTK, LEN_PTK); - - // init 802.3 header and Fill Packet - MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL); - - // Zero message 2 body - NdisZeroMemory(&Packet, sizeof(Packet)); - Packet.ProVer = EAPOL_VER; - Packet.ProType = EAPOLKey; - // - // Message 2 as EAPOL-Key(0,1,0,0,0,P,0,SNonce,MIC,RSN IE) - // - Packet.KeyDesc.Type = WPA2_KEY_DESC; - - // 1. Key descriptor version and appropriate RSN IE - if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) - { - Packet.KeyDesc.KeyInfo.KeyDescVer = 2; - } - else // TKIP - { - Packet.KeyDesc.KeyInfo.KeyDescVer = 1; - } - - // fill in Data Material and its length - Packet.KeyDesc.KeyData[0] = IE_WPA2; - Packet.KeyDesc.KeyData[1] = pAd->StaCfg.RSNIE_Len; - Packet.KeyDesc.KeyDataLen[1] = pAd->StaCfg.RSNIE_Len + 2; - NdisMoveMemory(&Packet.KeyDesc.KeyData[2], pAd->StaCfg.RSN_IE, pAd->StaCfg.RSNIE_Len); - - // Update packet length after decide Key data payload - Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE + Packet.KeyDesc.KeyDataLen[1]; - - // 2. Key Type PeerKey - Packet.KeyDesc.KeyInfo.KeyType = PAIRWISEKEY; - - // 3. KeyMic field presented - Packet.KeyDesc.KeyInfo.KeyMic = 1; - - // Update Key Length - Packet.KeyDesc.KeyLength[0] = 0; - Packet.KeyDesc.KeyLength[1] = pMsg1->KeyDesc.KeyLength[1]; - - // 4. Fill SNonce - NdisMoveMemory(Packet.KeyDesc.KeyNonce, pAd->StaCfg.SNonce, LEN_KEY_DESC_NONCE); - - // 5. Key Replay Count - NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY); - - // Convert to little-endian format. - *((USHORT *)&Packet.KeyDesc.KeyInfo) = cpu2le16(*((USHORT *)&Packet.KeyDesc.KeyInfo)); - - // Send EAPOL-Key(0,1,0,0,0,P,0,SNonce,MIC,RSN IE) - // Out buffer for transmitting message 2 - MlmeAllocateMemory(pAd, (PUCHAR *)&pOutBuffer); // allocate memory - if(pOutBuffer == NULL) - { - os_free_mem(pAd, mpool); - return; - } - - // Prepare EAPOL frame for MIC calculation - // Be careful, only EAPOL frame is counted for MIC calculation - MakeOutgoingFrame(pOutBuffer, &FrameLen, - Packet.Body_Len[1] + 4, &Packet, - END_OF_ARGS); - - // 6. Prepare and Fill MIC value - NdisZeroMemory(Mic, sizeof(Mic)); - if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) - { - // AES - HMAC_SHA1(pOutBuffer, FrameLen, PTK, LEN_EAP_MICK, digest); - NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); - } - else - { - hmac_md5(PTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic); - } - NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC); - - - // Make Transmitting frame - MakeOutgoingFrame(pOutBuffer, &FrameLen, - LENGTH_802_3, &Header802_3, - Packet.Body_Len[1] + 4, &Packet, - END_OF_ARGS); - - - // 5. Copy frame to Tx ring - RTMPToWirelessSta(pAd, Header802_3, LENGTH_802_3, (PUCHAR)&Packet, Packet.Body_Len[1] + 4, TRUE); - - MlmeFreeMemory(pAd, pOutBuffer); - os_free_mem(pAd, mpool); - - DBGPRINT(RT_DEBUG_TRACE, ("Wpa2PairMsg1Action <-----\n")); - -} - -/* - ======================================================================== - - Routine Description: - Process Pairwise key 4-way handshaking - - Arguments: - pAd Pointer to our adapter - Elem Message body - - Return Value: - None - - Note: - - ======================================================================== -*/ -VOID WpaPairMsg3Action( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) - -{ - PHEADER_802_11 pHeader; - PUCHAR pOutBuffer = NULL; - UCHAR Header802_3[14]; - ULONG FrameLen = 0; - EAPOL_PACKET Packet; - PEAPOL_PACKET pMsg3; - UCHAR Mic[16], OldMic[16]; - MAC_TABLE_ENTRY *pEntry = NULL; - UCHAR skip_offset; - KEY_INFO peerKeyInfo; - - DBGPRINT(RT_DEBUG_TRACE, ("WpaPairMsg3Action ----->\n")); - - // Record 802.11 header & the received EAPOL packet Msg3 - pHeader = (PHEADER_802_11) Elem->Msg; - pMsg3 = (PEAPOL_PACKET) &Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H]; - - NdisZeroMemory((PUCHAR)&peerKeyInfo, sizeof(peerKeyInfo)); - NdisMoveMemory((PUCHAR)&peerKeyInfo, (PUCHAR)&pMsg3->KeyDesc.KeyInfo, sizeof(KEY_INFO)); - - *((USHORT*)&peerKeyInfo) = cpu2le16(*((USHORT*)&peerKeyInfo)); - - - // 1. Verify cipher type match - if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled && (peerKeyInfo.KeyDescVer != 2)) - { - return; - } - else if(pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled && (peerKeyInfo.KeyDescVer != 1)) - { - return; - } - - // Verify RSN IE - //if (!RTMPEqualMemory(pMsg3->KeyDesc.KeyData, pAd->MacTab.Content[BSSID_WCID].RSN_IE, pAd->MacTab.Content[BSSID_WCID].RSNIE_Len)) - if (!CheckRSNIE(pAd, pMsg3->KeyDesc.KeyData, pMsg3->KeyDesc.KeyDataLen[1], &skip_offset)) - { - DBGPRINT(RT_DEBUG_ERROR, ("RSN_IE Different in Msg 3 of WPA1 4-way handshake!! \n")); - hex_dump("The original RSN_IE", pAd->MacTab.Content[BSSID_WCID].RSN_IE, pAd->MacTab.Content[BSSID_WCID].RSNIE_Len); - hex_dump("The received RSN_IE", pMsg3->KeyDesc.KeyData, pMsg3->KeyDesc.KeyDataLen[1]); - return; - } - else - DBGPRINT(RT_DEBUG_TRACE, ("RSN_IE VALID in Msg 3 of WPA1 4-way handshake!! \n")); - - - // 2. Check MIC value - // Save the MIC and replace with zero - NdisMoveMemory(OldMic, pMsg3->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); - NdisZeroMemory(pMsg3->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); - if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) - { - // AES - UCHAR digest[80]; - - HMAC_SHA1((PUCHAR) pMsg3, pMsg3->Body_Len[1] + 4, pAd->StaCfg.PTK, LEN_EAP_MICK, digest); - NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); - } - else // TKIP - { - hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, (PUCHAR) pMsg3, pMsg3->Body_Len[1] + 4, Mic); - } - - if(!NdisEqualMemory(OldMic, Mic, LEN_KEY_DESC_MIC)) - { - DBGPRINT(RT_DEBUG_ERROR, (" MIC Different in msg 3 of 4-way handshake!!!!!!!!!! \n")); - return; - } - else - DBGPRINT(RT_DEBUG_TRACE, (" MIC VALID in msg 3 of 4-way handshake!!!!!!!!!! \n")); - - // 3. Check Replay Counter, it has to be larger than last one. No need to be exact one larger - if(RTMPCompareMemory(pMsg3->KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY) != 1) - return; - - // Update new replay counter - NdisMoveMemory(pAd->StaCfg.ReplayCounter, pMsg3->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); - - // 4. Double check ANonce - if(!NdisEqualMemory(pAd->StaCfg.ANonce, pMsg3->KeyDesc.KeyNonce, LEN_KEY_DESC_NONCE)) - return; - - // init 802.3 header and Fill Packet - MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL); - - // Zero Message 4 body - NdisZeroMemory(&Packet, sizeof(Packet)); - Packet.ProVer = EAPOL_VER; - Packet.ProType = EAPOLKey; - Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE; // No data field - - // - // Message 4 as EAPOL-Key(0,1,0,0,0,P,0,0,MIC,0) - // - Packet.KeyDesc.Type = WPA1_KEY_DESC; - - // Key descriptor version and appropriate RSN IE - Packet.KeyDesc.KeyInfo.KeyDescVer = peerKeyInfo.KeyDescVer; - - // Update Key Length - Packet.KeyDesc.KeyLength[0] = pMsg3->KeyDesc.KeyLength[0]; - Packet.KeyDesc.KeyLength[1] = pMsg3->KeyDesc.KeyLength[1]; - - // Key Type PeerKey - Packet.KeyDesc.KeyInfo.KeyType = PAIRWISEKEY; - - // KeyMic field presented - Packet.KeyDesc.KeyInfo.KeyMic = 1; - - // In Msg3, KeyInfo.secure =0 if Group Key HS to come. 1 if no group key HS - // Station sends Msg4 KeyInfo.secure should be the same as that in Msg.3 - Packet.KeyDesc.KeyInfo.Secure= peerKeyInfo.Secure; - - // Convert to little-endian format. - *((USHORT *)&Packet.KeyDesc.KeyInfo) = cpu2le16(*((USHORT *)&Packet.KeyDesc.KeyInfo)); - - // Key Replay count - NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pMsg3->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); - - // Out buffer for transmitting message 4 - MlmeAllocateMemory(pAd, (PUCHAR *)&pOutBuffer); // allocate memory - if(pOutBuffer == NULL) - return; - - // Prepare EAPOL frame for MIC calculation - // Be careful, only EAPOL frame is counted for MIC calculation - MakeOutgoingFrame(pOutBuffer, &FrameLen, - Packet.Body_Len[1] + 4, &Packet, - END_OF_ARGS); - - // Prepare and Fill MIC value - NdisZeroMemory(Mic, sizeof(Mic)); - if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) - { - // AES - UCHAR digest[80]; - - HMAC_SHA1(pOutBuffer, FrameLen, pAd->StaCfg.PTK, LEN_EAP_MICK, digest); - NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); - } - else - { - hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic); - } - NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC); - - // Update PTK - // Prepare pair-wise key information into shared key table - NdisZeroMemory(&pAd->SharedKey[BSS0][0], sizeof(CIPHER_KEY)); - pAd->SharedKey[BSS0][0].KeyLen = LEN_TKIP_EK; - NdisMoveMemory(pAd->SharedKey[BSS0][0].Key, &pAd->StaCfg.PTK[32], LEN_TKIP_EK); - NdisMoveMemory(pAd->SharedKey[BSS0][0].RxMic, &pAd->StaCfg.PTK[48], LEN_TKIP_RXMICK); - NdisMoveMemory(pAd->SharedKey[BSS0][0].TxMic, &pAd->StaCfg.PTK[48+LEN_TKIP_RXMICK], LEN_TKIP_TXMICK); - - // Decide its ChiperAlg - if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled) - pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_TKIP; - else if (pAd->StaCfg.PairCipher == Ndis802_11Encryption3Enabled) - pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_AES; - else - pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_NONE; - - // Update these related information to MAC_TABLE_ENTRY - pEntry = &pAd->MacTab.Content[BSSID_WCID]; - NdisMoveMemory(pEntry->PairwiseKey.Key, &pAd->StaCfg.PTK[32], LEN_TKIP_EK); - NdisMoveMemory(pEntry->PairwiseKey.RxMic, &pAd->StaCfg.PTK[48], LEN_TKIP_RXMICK); - NdisMoveMemory(pEntry->PairwiseKey.TxMic, &pAd->StaCfg.PTK[48+LEN_TKIP_RXMICK], LEN_TKIP_TXMICK); - pEntry->PairwiseKey.CipherAlg = pAd->SharedKey[BSS0][0].CipherAlg; - - // Update pairwise key information to ASIC Shared Key Table - AsicAddSharedKeyEntry(pAd, - BSS0, - 0, - pAd->SharedKey[BSS0][0].CipherAlg, - pAd->SharedKey[BSS0][0].Key, - pAd->SharedKey[BSS0][0].TxMic, - pAd->SharedKey[BSS0][0].RxMic); - - // Update ASIC WCID attribute table and IVEIV table - RTMPAddWcidAttributeEntry(pAd, - BSS0, - 0, - pAd->SharedKey[BSS0][0].CipherAlg, - pEntry); - - // Make transmitting frame - MakeOutgoingFrame(pOutBuffer, &FrameLen, - LENGTH_802_3, &Header802_3, - Packet.Body_Len[1] + 4, &Packet, - END_OF_ARGS); - - - // Copy frame to Tx ring and Send Message 4 to authenticator - RTMPToWirelessSta(pAd, Header802_3, LENGTH_802_3, (PUCHAR)&Packet, Packet.Body_Len[1] + 4, TRUE); - - MlmeFreeMemory(pAd, (PUCHAR)pOutBuffer); - - DBGPRINT(RT_DEBUG_TRACE, ("WpaPairMsg3Action <-----\n")); -} - -VOID Wpa2PairMsg3Action( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) - -{ - PHEADER_802_11 pHeader; - PUCHAR pOutBuffer = NULL; - UCHAR Header802_3[14]; - ULONG FrameLen = 0; - EAPOL_PACKET Packet; - PEAPOL_PACKET pMsg3; - UCHAR Mic[16], OldMic[16]; - UCHAR *mpool, *KEYDATA, *digest; - UCHAR Key[32]; - MAC_TABLE_ENTRY *pEntry = NULL; - KEY_INFO peerKeyInfo; - - // allocate memory - os_alloc_mem(pAd, (PUCHAR *)&mpool, 1024); - - if(mpool == NULL) - return; - - // KEYDATA Len = 512. - KEYDATA = (UCHAR *) ROUND_UP(mpool, 4); - // digest Len = 80. - digest = (UCHAR *) ROUND_UP(KEYDATA + 512, 4); - - DBGPRINT(RT_DEBUG_TRACE, ("Wpa2PairMsg3Action ----->\n")); - - pHeader = (PHEADER_802_11) Elem->Msg; - - // Process message 3 frame. - pMsg3 = (PEAPOL_PACKET) &Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H]; - - NdisZeroMemory((PUCHAR)&peerKeyInfo, sizeof(peerKeyInfo)); - NdisMoveMemory((PUCHAR)&peerKeyInfo, (PUCHAR)&pMsg3->KeyDesc.KeyInfo, sizeof(KEY_INFO)); - - *((USHORT*)&peerKeyInfo) = cpu2le16(*((USHORT*)&peerKeyInfo)); - - // 1. Verify cipher type match - if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled && (peerKeyInfo.KeyDescVer!= 2)) - { - os_free_mem(pAd, (PUCHAR)mpool); - return; - } - else if(pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled && (peerKeyInfo.KeyDescVer != 1)) - { - os_free_mem(pAd, (PUCHAR)mpool); - return; - } - - // 2. Check MIC value - // Save the MIC and replace with zero - NdisMoveMemory(OldMic, pMsg3->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); - NdisZeroMemory(pMsg3->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); - if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) - { - // AES - HMAC_SHA1((PUCHAR) pMsg3, pMsg3->Body_Len[1] + 4, pAd->StaCfg.PTK, LEN_EAP_MICK, digest); - NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); - } - else - { - hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, (PUCHAR) pMsg3, pMsg3->Body_Len[1] + 4, Mic); - } - - if(!NdisEqualMemory(OldMic, Mic, LEN_KEY_DESC_MIC)) - { - DBGPRINT(RT_DEBUG_ERROR, (" MIC Different in msg 3 of 4-way handshake!!!!!!!!!! \n")); - os_free_mem(pAd, (PUCHAR)mpool); - return; - } - else - DBGPRINT(RT_DEBUG_TRACE, (" MIC VALID in msg 3 of 4-way handshake!!!!!!!!!! \n")); - - // 3. Check Replay Counter, it has to be larger than last one. No need to be exact one larger - if(RTMPCompareMemory(pMsg3->KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY) != 1) - { - os_free_mem(pAd, (PUCHAR)mpool); - return; - } - - // Update new replay counter - NdisMoveMemory(pAd->StaCfg.ReplayCounter, pMsg3->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); - - // 4. Double check ANonce - if(!NdisEqualMemory(pAd->StaCfg.ANonce, pMsg3->KeyDesc.KeyNonce, LEN_KEY_DESC_NONCE)) - { - os_free_mem(pAd, (PUCHAR)mpool); - return; - } - - // Obtain GTK - // 5. Decrypt GTK from Key Data - DBGPRINT_RAW(RT_DEBUG_TRACE, ("EKD = %d\n", peerKeyInfo.EKD_DL)); - if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) - { - // Decrypt AES GTK - AES_GTK_KEY_UNWRAP(&pAd->StaCfg.PTK[16], KEYDATA, pMsg3->KeyDesc.KeyDataLen[1],pMsg3->KeyDesc.KeyData); - } - else // TKIP - { - INT i; - // Decrypt TKIP GTK - // Construct 32 bytes RC4 Key - NdisMoveMemory(Key, pMsg3->KeyDesc.KeyIv, 16); - NdisMoveMemory(&Key[16], &pAd->StaCfg.PTK[16], 16); - ARCFOUR_INIT(&pAd->PrivateInfo.WEPCONTEXT, Key, 32); - //discard first 256 bytes - for(i = 0; i < 256; i++) - ARCFOUR_BYTE(&pAd->PrivateInfo.WEPCONTEXT); - // Decrypt GTK. Becareful, there is no ICV to check the result is correct or not - ARCFOUR_DECRYPT(&pAd->PrivateInfo.WEPCONTEXT, KEYDATA, pMsg3->KeyDesc.KeyData, pMsg3->KeyDesc.KeyDataLen[1]); - } - - if (!ParseKeyData(pAd, KEYDATA, pMsg3->KeyDesc.KeyDataLen[1], 1)) - { - os_free_mem(pAd, (PUCHAR)mpool); - return; - } - - // Update GTK to ASIC - // Update group key information to ASIC Shared Key Table - AsicAddSharedKeyEntry(pAd, - BSS0, - pAd->StaCfg.DefaultKeyId, - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic); - - // Update ASIC WCID attribute table and IVEIV table - RTMPAddWcidAttributeEntry(pAd, - BSS0, - pAd->StaCfg.DefaultKeyId, - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, - NULL); - - // init 802.3 header and Fill Packet - MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL); - - // Zero message 4 body - NdisZeroMemory(&Packet, sizeof(Packet)); - Packet.ProVer = EAPOL_VER; - Packet.ProType = EAPOLKey; - Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE; // No data field - - // - // Message 4 as EAPOL-Key(0,1,0,0,0,P,0,0,MIC,0) - // - Packet.KeyDesc.Type = WPA2_KEY_DESC; - - // Key descriptor version and appropriate RSN IE - Packet.KeyDesc.KeyInfo.KeyDescVer = peerKeyInfo.KeyDescVer; - - // Update Key Length - Packet.KeyDesc.KeyLength[0] = pMsg3->KeyDesc.KeyLength[0]; - Packet.KeyDesc.KeyLength[1] = pMsg3->KeyDesc.KeyLength[1]; - - // Key Type PeerKey - Packet.KeyDesc.KeyInfo.KeyType = PAIRWISEKEY; - - // KeyMic field presented - Packet.KeyDesc.KeyInfo.KeyMic = 1; - Packet.KeyDesc.KeyInfo.Secure = 1; - - // Convert to little-endian format. - *((USHORT *)&Packet.KeyDesc.KeyInfo) = cpu2le16(*((USHORT *)&Packet.KeyDesc.KeyInfo)); - - // Key Replay count - NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pMsg3->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); - - // Out buffer for transmitting message 4 - MlmeAllocateMemory(pAd, (PUCHAR *)&pOutBuffer); // allocate memory - if(pOutBuffer == NULL) - { - os_free_mem(pAd, (PUCHAR)mpool); - return; - } - - // Prepare EAPOL frame for MIC calculation - // Be careful, only EAPOL frame is counted for MIC calculation - MakeOutgoingFrame(pOutBuffer, &FrameLen, - Packet.Body_Len[1] + 4, &Packet, - END_OF_ARGS); - - // Prepare and Fill MIC value - NdisZeroMemory(Mic, sizeof(Mic)); - if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) - { - // AES - HMAC_SHA1(pOutBuffer, FrameLen, pAd->StaCfg.PTK, LEN_EAP_MICK, digest); - NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); - } - else - { - hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic); - } - NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC); - - // Update PTK - // Prepare pair-wise key information into shared key table - NdisZeroMemory(&pAd->SharedKey[BSS0][0], sizeof(CIPHER_KEY)); - pAd->SharedKey[BSS0][0].KeyLen = LEN_TKIP_EK; - NdisMoveMemory(pAd->SharedKey[BSS0][0].Key, &pAd->StaCfg.PTK[32], LEN_TKIP_EK); - NdisMoveMemory(pAd->SharedKey[BSS0][0].RxMic, &pAd->StaCfg.PTK[48], LEN_TKIP_RXMICK); - NdisMoveMemory(pAd->SharedKey[BSS0][0].TxMic, &pAd->StaCfg.PTK[48+LEN_TKIP_RXMICK], LEN_TKIP_TXMICK); - - // Decide its ChiperAlg - if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled) - pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_TKIP; - else if (pAd->StaCfg.PairCipher == Ndis802_11Encryption3Enabled) - pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_AES; - else - pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_NONE; - - // Update these related information to MAC_TABLE_ENTRY - pEntry = &pAd->MacTab.Content[BSSID_WCID]; - NdisMoveMemory(&pEntry->PairwiseKey.Key, &pAd->StaCfg.PTK[32], LEN_TKIP_EK); - NdisMoveMemory(&pEntry->PairwiseKey.RxMic, &pAd->StaCfg.PTK[48], LEN_TKIP_RXMICK); - NdisMoveMemory(&pEntry->PairwiseKey.TxMic, &pAd->StaCfg.PTK[48+LEN_TKIP_RXMICK], LEN_TKIP_TXMICK); - pEntry->PairwiseKey.CipherAlg = pAd->SharedKey[BSS0][0].CipherAlg; - - // Update pairwise key information to ASIC Shared Key Table - AsicAddSharedKeyEntry(pAd, - BSS0, - 0, - pAd->SharedKey[BSS0][0].CipherAlg, - pAd->SharedKey[BSS0][0].Key, - pAd->SharedKey[BSS0][0].TxMic, - pAd->SharedKey[BSS0][0].RxMic); - - // Update ASIC WCID attribute table and IVEIV table - RTMPAddWcidAttributeEntry(pAd, - BSS0, - 0, - pAd->SharedKey[BSS0][0].CipherAlg, - pEntry); - - // Make Transmitting frame - MakeOutgoingFrame(pOutBuffer, &FrameLen, - LENGTH_802_3, &Header802_3, - Packet.Body_Len[1] + 4, &Packet, - END_OF_ARGS); - - - // Copy frame to Tx ring and Send Message 4 to authenticator - RTMPToWirelessSta(pAd, Header802_3, LENGTH_802_3, (PUCHAR)&Packet, Packet.Body_Len[1] + 4, TRUE); - - // set 802.1x port control - //pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; - STA_PORT_SECURED(pAd); - - // Indicate Connected for GUI - pAd->IndicateMediaState = NdisMediaStateConnected; - - MlmeFreeMemory(pAd, (PUCHAR)pOutBuffer); - os_free_mem(pAd, (PUCHAR)mpool); - - - // send wireless event - for set key done WPA2 - if (pAd->CommonCfg.bWirelessEvent) - RTMPSendWirelessEvent(pAd, IW_SET_KEY_DONE_WPA2_EVENT_FLAG, pEntry->Addr, BSS0, 0); - - DBGPRINT(RT_DEBUG_ERROR, ("Wpa2PairMsg3Action <-----\n")); - -} - -/* - ======================================================================== - - Routine Description: - Process Group key 2-way handshaking - - Arguments: - pAd Pointer to our adapter - Elem Message body - - Return Value: - None - - Note: - - ======================================================================== -*/ -VOID WpaGroupMsg1Action( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) - -{ - PUCHAR pOutBuffer = NULL; - UCHAR Header802_3[14]; - ULONG FrameLen = 0; - EAPOL_PACKET Packet; - PEAPOL_PACKET pGroup; - UCHAR *mpool, *digest, *KEYDATA; - UCHAR Mic[16], OldMic[16]; - UCHAR GTK[32], Key[32]; - KEY_INFO peerKeyInfo; - - // allocate memory - os_alloc_mem(pAd, (PUCHAR *)&mpool, 1024); - - if(mpool == NULL) - return; - - // digest Len = 80. - digest = (UCHAR *) ROUND_UP(mpool, 4); - // KEYDATA Len = 512. - KEYDATA = (UCHAR *) ROUND_UP(digest + 80, 4); - - DBGPRINT(RT_DEBUG_TRACE, ("WpaGroupMsg1Action ----->\n")); - - // Process Group Message 1 frame. skip 802.11 header(24) & LLC_SNAP header(8) - pGroup = (PEAPOL_PACKET) &Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H]; - - NdisZeroMemory((PUCHAR)&peerKeyInfo, sizeof(peerKeyInfo)); - NdisMoveMemory((PUCHAR)&peerKeyInfo, (PUCHAR)&pGroup->KeyDesc.KeyInfo, sizeof(KEY_INFO)); - - *((USHORT*)&peerKeyInfo) = cpu2le16(*((USHORT*)&peerKeyInfo)); - - // 0. Check cipher type match - if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled && (peerKeyInfo.KeyDescVer != 2)) - { - os_free_mem(pAd, (PUCHAR)mpool); - return; - } - else if (pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled && (peerKeyInfo.KeyDescVer != 1)) - { - os_free_mem(pAd, (PUCHAR)mpool); - return; - } - - // 1. Verify Replay counter - // Check Replay Counter, it has to be larger than last one. No need to be exact one larger - if(RTMPCompareMemory(pGroup->KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY) != 1) - { - os_free_mem(pAd, (PUCHAR)mpool); - return; - } - - // Update new replay counter - NdisMoveMemory(pAd->StaCfg.ReplayCounter, pGroup->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); - - // 2. Verify MIC is valid - // Save the MIC and replace with zero - NdisMoveMemory(OldMic, pGroup->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); - NdisZeroMemory(pGroup->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); - - if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) - { // AES - HMAC_SHA1((PUCHAR) pGroup, pGroup->Body_Len[1] + 4, pAd->StaCfg.PTK, LEN_EAP_MICK, digest); - NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); - } - else - { // TKIP - hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, (PUCHAR) pGroup, pGroup->Body_Len[1] + 4, Mic); - } - - if(!NdisEqualMemory(OldMic, Mic, LEN_KEY_DESC_MIC)) - { - DBGPRINT(RT_DEBUG_ERROR, (" MIC Different in group msg 1 of 2-way handshake!!!!!!!!!! \n")); - MlmeFreeMemory(pAd, (PUCHAR)mpool); - return; - } - else - DBGPRINT(RT_DEBUG_TRACE, (" MIC VALID in group msg 1 of 2-way handshake!!!!!!!!!! \n")); - - - // 3. Decrypt GTK from Key Data - if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) - { - // Decrypt AES GTK - AES_GTK_KEY_UNWRAP(&pAd->StaCfg.PTK[16], KEYDATA, pGroup->KeyDesc.KeyDataLen[1], pGroup->KeyDesc.KeyData); - } - else // TKIP - { - INT i; - - // Decrypt TKIP GTK - // Construct 32 bytes RC4 Key - NdisMoveMemory(Key, pGroup->KeyDesc.KeyIv, 16); - NdisMoveMemory(&Key[16], &pAd->StaCfg.PTK[16], 16); - ARCFOUR_INIT(&pAd->PrivateInfo.WEPCONTEXT, Key, 32); - //discard first 256 bytes - for(i = 0; i < 256; i++) - ARCFOUR_BYTE(&pAd->PrivateInfo.WEPCONTEXT); - // Decrypt GTK. Becareful, there is no ICV to check the result is correct or not - ARCFOUR_DECRYPT(&pAd->PrivateInfo.WEPCONTEXT, KEYDATA, pGroup->KeyDesc.KeyData, pGroup->KeyDesc.KeyDataLen[1]); - } - - // Process decrypted key data material - // Parse keyData to handle KDE format for WPA2PSK - if (peerKeyInfo.EKD_DL) - { - if (!ParseKeyData(pAd, KEYDATA, pGroup->KeyDesc.KeyDataLen[1], 0)) - { - os_free_mem(pAd, (PUCHAR)mpool); - return; - } - } - else // WPAPSK - { - // set key material, TxMic and RxMic for WPAPSK - NdisMoveMemory(GTK, KEYDATA, 32); - NdisMoveMemory(pAd->StaCfg.GTK, GTK, 32); - pAd->StaCfg.DefaultKeyId = peerKeyInfo.KeyIndex; - - // Prepare pair-wise key information into shared key table - NdisZeroMemory(&pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId], sizeof(CIPHER_KEY)); - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].KeyLen = LEN_TKIP_EK; - NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, GTK, LEN_TKIP_EK); - NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic, >K[16], LEN_TKIP_RXMICK); - NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, >K[24], LEN_TKIP_TXMICK); - - // Update Shared Key CipherAlg - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_NONE; - if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption2Enabled) - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_TKIP; - else if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption3Enabled) - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_AES; - - //hex_dump("Group Key :", pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, LEN_TKIP_EK); - } - - // Update group key information to ASIC Shared Key Table - AsicAddSharedKeyEntry(pAd, - BSS0, - pAd->StaCfg.DefaultKeyId, - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic); - - // Update ASIC WCID attribute table and IVEIV table - RTMPAddWcidAttributeEntry(pAd, - BSS0, - pAd->StaCfg.DefaultKeyId, - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, - NULL); - - // set 802.1x port control - //pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; - STA_PORT_SECURED(pAd); - - // Indicate Connected for GUI - pAd->IndicateMediaState = NdisMediaStateConnected; - - // init header and Fill Packet - MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL); - - // Zero Group message 1 body - NdisZeroMemory(&Packet, sizeof(Packet)); - Packet.ProVer = EAPOL_VER; - Packet.ProType = EAPOLKey; - Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE; // No data field - - // - // Group Message 2 as EAPOL-Key(1,0,0,0,G,0,0,MIC,0) - // - if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) - { - Packet.KeyDesc.Type = WPA2_KEY_DESC; - } - else - { - Packet.KeyDesc.Type = WPA1_KEY_DESC; - } - - // Key descriptor version and appropriate RSN IE - Packet.KeyDesc.KeyInfo.KeyDescVer = peerKeyInfo.KeyDescVer; - - // Update Key Length - Packet.KeyDesc.KeyLength[0] = pGroup->KeyDesc.KeyLength[0]; - Packet.KeyDesc.KeyLength[1] = pGroup->KeyDesc.KeyLength[1]; - - // Key Index as G-Msg 1 - if(pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) - Packet.KeyDesc.KeyInfo.KeyIndex = peerKeyInfo.KeyIndex; - - // Key Type Group key - Packet.KeyDesc.KeyInfo.KeyType = GROUPKEY; - - // KeyMic field presented - Packet.KeyDesc.KeyInfo.KeyMic = 1; - - // Secure bit - Packet.KeyDesc.KeyInfo.Secure = 1; - - // Convert to little-endian format. - *((USHORT *)&Packet.KeyDesc.KeyInfo) = cpu2le16(*((USHORT *)&Packet.KeyDesc.KeyInfo)); - - // Key Replay count - NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pGroup->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); - - // Out buffer for transmitting group message 2 - MlmeAllocateMemory(pAd, (PUCHAR *)&pOutBuffer); // allocate memory - if(pOutBuffer == NULL) - { - MlmeFreeMemory(pAd, (PUCHAR)mpool); - return; - } - - // Prepare EAPOL frame for MIC calculation - // Be careful, only EAPOL frame is counted for MIC calculation - MakeOutgoingFrame(pOutBuffer, &FrameLen, - Packet.Body_Len[1] + 4, &Packet, - END_OF_ARGS); - - // Prepare and Fill MIC value - NdisZeroMemory(Mic, sizeof(Mic)); - if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) - { - // AES - HMAC_SHA1(pOutBuffer, FrameLen, pAd->StaCfg.PTK, LEN_EAP_MICK, digest); - NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); - } - else - { - hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic); - } - NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC); - - - MakeOutgoingFrame(pOutBuffer, &FrameLen, - LENGTH_802_3, &Header802_3, - Packet.Body_Len[1] + 4, &Packet, - END_OF_ARGS); - - - // 5. Copy frame to Tx ring and prepare for encryption - RTMPToWirelessSta(pAd, Header802_3, LENGTH_802_3, (PUCHAR)&Packet, Packet.Body_Len[1] + 4, FALSE); - - // 6 Free allocated memory - MlmeFreeMemory(pAd, (PUCHAR)pOutBuffer); - os_free_mem(pAd, (PUCHAR)mpool); - - // send wireless event - for set key done WPA2 - if (pAd->CommonCfg.bWirelessEvent) - RTMPSendWirelessEvent(pAd, IW_SET_KEY_DONE_WPA2_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); - - DBGPRINT(RT_DEBUG_TRACE, ("WpaGroupMsg1Action <-----\n")); -} - -/* - ======================================================================== - - Routine Description: - Init WPA MAC header - - Arguments: - pAd Pointer to our adapter - - Return Value: - None - - Note: - - ======================================================================== -*/ -VOID WpaMacHeaderInit( - IN PRTMP_ADAPTER pAd, - IN OUT PHEADER_802_11 pHdr80211, - IN UCHAR wep, - IN PUCHAR pAddr1) -{ - NdisZeroMemory(pHdr80211, sizeof(HEADER_802_11)); - pHdr80211->FC.Type = BTYPE_DATA; - pHdr80211->FC.ToDs = 1; - if (wep == 1) - pHdr80211->FC.Wep = 1; - - // Addr1: BSSID, Addr2: SA, Addr3: DA - COPY_MAC_ADDR(pHdr80211->Addr1, pAddr1); - COPY_MAC_ADDR(pHdr80211->Addr2, pAd->CurrentAddress); - COPY_MAC_ADDR(pHdr80211->Addr3, pAd->CommonCfg.Bssid); - pHdr80211->Sequence = pAd->Sequence; -} - -/* - ======================================================================== - - Routine Description: - Copy frame from waiting queue into relative ring buffer and set - appropriate ASIC register to kick hardware encryption before really - sent out to air. - - Arguments: - pAd Pointer to our adapter - PNDIS_PACKET Pointer to outgoing Ndis frame - NumberOfFrag Number of fragment required - - Return Value: - None - - Note: - - ======================================================================== -*/ -VOID RTMPToWirelessSta( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pHeader802_3, - IN UINT HdrLen, - IN PUCHAR pData, - IN UINT DataLen, - IN BOOLEAN is4wayFrame) - -{ - NDIS_STATUS Status; - PNDIS_PACKET pPacket; - UCHAR Index; - - do - { - // 1. build a NDIS packet and call RTMPSendPacket(); - // be careful about how/when to release this internal allocated NDIS PACKET buffer - Status = RTMPAllocateNdisPacket(pAd, &pPacket, pHeader802_3, HdrLen, pData, DataLen); - if (Status != NDIS_STATUS_SUCCESS) - break; - - if (is4wayFrame) - RTMP_SET_PACKET_CLEAR_EAP_FRAME(pPacket, 1); - else - RTMP_SET_PACKET_CLEAR_EAP_FRAME(pPacket, 0); - - // 2. send out the packet - Status = STASendPacket(pAd, pPacket); - if(Status == NDIS_STATUS_SUCCESS) - { - // Dequeue one frame from TxSwQueue0..3 queue and process it - // There are three place calling dequeue for TX ring. - // 1. Here, right after queueing the frame. - // 2. At the end of TxRingTxDone service routine. - // 3. Upon NDIS call RTMPSendPackets - if((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) && - (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS))) - { - for(Index = 0; Index < 5; Index ++) - if(pAd->TxSwQueue[Index].Number > 0) - RTMPDeQueuePacket(pAd, FALSE, Index, MAX_TX_PROCESS); - } - } - } while(FALSE); - -} - -/* - ======================================================================== - - Routine Description: - Check Sanity RSN IE form AP - - Arguments: - - Return Value: - - - ======================================================================== -*/ -BOOLEAN CheckRSNIE( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pData, - IN UCHAR DataLen, - OUT UCHAR *Offset) -{ - PUCHAR pVIE; - UCHAR len; - PEID_STRUCT pEid; - BOOLEAN result = FALSE; - - pVIE = pData; - len = DataLen; - *Offset = 0; - - while (len > sizeof(RSNIE2)) - { - pEid = (PEID_STRUCT) pVIE; - // WPA RSN IE - if ((pEid->Eid == IE_WPA) && (NdisEqualMemory(pEid->Octet, WPA_OUI, 4))) - { - if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA || pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) && - (NdisEqualMemory(pVIE, pAd->MacTab.Content[BSSID_WCID].RSN_IE, pAd->MacTab.Content[BSSID_WCID].RSNIE_Len)) && - (pAd->MacTab.Content[BSSID_WCID].RSNIE_Len == (pEid->Len + 2))) - { - DBGPRINT(RT_DEBUG_TRACE, ("CheckRSNIE ==> WPA/WPAPSK RSN IE matched in Msg 3, Length(%d) \n", (pEid->Len + 2))); - result = TRUE; - } - - *Offset += (pEid->Len + 2); - } - // WPA2 RSN IE - else if ((pEid->Eid == IE_RSN) && (NdisEqualMemory(pEid->Octet + 2, RSN_OUI, 3))) - { - if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2 || pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) && - (NdisEqualMemory(pVIE, pAd->MacTab.Content[BSSID_WCID].RSN_IE, pAd->MacTab.Content[BSSID_WCID].RSNIE_Len)) && - (pAd->MacTab.Content[BSSID_WCID].RSNIE_Len == (pEid->Len + 2))) - { - DBGPRINT(RT_DEBUG_TRACE, ("CheckRSNIE ==> WPA2/WPA2PSK RSN IE matched in Msg 3, Length(%d) \n", (pEid->Len + 2))); - result = TRUE; - } - - *Offset += (pEid->Len + 2); - } - else - { - break; - } - - pVIE += (pEid->Len + 2); - len -= (pEid->Len + 2); - } - - DBGPRINT(RT_DEBUG_TRACE, ("CheckRSNIE ==> skip_offset(%d) \n", *Offset)); - - return result; - -} - - -/* - ======================================================================== - - Routine Description: - Parse KEYDATA field. KEYDATA[] May contain 2 RSN IE and optionally GTK. - GTK is encaptulated in KDE format at p.83 802.11i D10 - - Arguments: - - Return Value: - - Note: - 802.11i D10 - - ======================================================================== -*/ -BOOLEAN ParseKeyData( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pKeyData, - IN UCHAR KeyDataLen, - IN UCHAR bPairewise) -{ - PKDE_ENCAP pKDE = NULL; - PUCHAR pMyKeyData = pKeyData; - UCHAR KeyDataLength = KeyDataLen; - UCHAR GTKLEN; - UCHAR skip_offset; - - // Verify The RSN IE contained in Pairewise-Msg 3 and skip it - if (bPairewise) - { - // Check RSN IE whether it is WPA2/WPA2PSK - if (!CheckRSNIE(pAd, pKeyData, KeyDataLen, &skip_offset)) - { - DBGPRINT(RT_DEBUG_ERROR, ("ParseKeyData ==> WPA2/WPA2PSK RSN IE mismatched \n")); - hex_dump("Get KEYDATA :", pKeyData, KeyDataLen); - return FALSE; - } - else - { - // skip RSN IE - pMyKeyData += skip_offset; - KeyDataLength -= skip_offset; - - //DBGPRINT(RT_DEBUG_TRACE, ("ParseKeyData ==> WPA2/WPA2PSK RSN IE matched in Msg 3, Length(%d) \n", skip_offset)); - } - } - - DBGPRINT(RT_DEBUG_TRACE,("ParseKeyData ==> KeyDataLength %d without RSN_IE \n", KeyDataLength)); - - // Parse EKD format - if (KeyDataLength >= 8) - { - pKDE = (PKDE_ENCAP) pMyKeyData; - } - else - { - DBGPRINT(RT_DEBUG_ERROR, ("ERROR: KeyDataLength is too short \n")); - return FALSE; - } - - - // Sanity check - shared key index should not be 0 - if (pKDE->GTKEncap.Kid == 0) - { - DBGPRINT(RT_DEBUG_ERROR, ("ERROR: GTK Key index zero \n")); - return FALSE; - } - - // Sanity check - KED length - if (KeyDataLength < (pKDE->Len + 2)) - { - DBGPRINT(RT_DEBUG_ERROR, ("ERROR: The len from KDE is too short \n")); - return FALSE; - } - - // Get GTK length - refer to IEEE 802.11i-2004 p.82 - GTKLEN = pKDE->Len -6; - - if (GTKLEN < LEN_AES_KEY) - { - DBGPRINT(RT_DEBUG_ERROR, ("ERROR: GTK Key length is too short (%d) \n", GTKLEN)); - return FALSE; - } - else - DBGPRINT(RT_DEBUG_TRACE, ("GTK Key with KDE formet got index=%d, len=%d \n", pKDE->GTKEncap.Kid, GTKLEN)); - - // Update GTK - // set key material, TxMic and RxMic for WPAPSK - NdisMoveMemory(pAd->StaCfg.GTK, pKDE->GTKEncap.GTK, 32); - pAd->StaCfg.DefaultKeyId = pKDE->GTKEncap.Kid; - - // Update shared key table - NdisZeroMemory(&pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId], sizeof(CIPHER_KEY)); - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].KeyLen = LEN_TKIP_EK; - NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, pKDE->GTKEncap.GTK, LEN_TKIP_EK); - NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic, &pKDE->GTKEncap.GTK[16], LEN_TKIP_RXMICK); - NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, &pKDE->GTKEncap.GTK[24], LEN_TKIP_TXMICK); - - // Update Shared Key CipherAlg - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_NONE; - if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption2Enabled) - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_TKIP; - else if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption3Enabled) - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_AES; - - return TRUE; - -} - -/* - ======================================================================== - - Routine Description: - Cisco CCKM PRF function - - Arguments: - key Cisco Base Transient Key (BTK) - key_len The key length of the BTK - data Ruquest Number(RN) + BSSID - data_len The length of the data - output Store for PTK(Pairwise transient keys) - len The length of the output - Return Value: - None - - Note: - 802.1i Annex F.9 - - ======================================================================== -*/ -VOID CCKMPRF( - IN UCHAR *key, - IN INT key_len, - IN UCHAR *data, - IN INT data_len, - OUT UCHAR *output, - IN INT len) -{ - INT i; - UCHAR input[1024]; - INT currentindex = 0; - INT total_len; - - NdisMoveMemory(input, data, data_len); - total_len = data_len; - input[total_len] = 0; - total_len++; - for (i = 0; i < (len + 19) / 20; i++) - { - HMAC_SHA1(input, total_len, key, key_len, &output[currentindex]); - currentindex += 20; - input[total_len - 1]++; - } -} - -/* - ======================================================================== - - Routine Description: - Process MIC error indication and record MIC error timer. - - Arguments: - pAd Pointer to our adapter - pWpaKey Pointer to the WPA key structure - - Return Value: - None - - IRQL = DISPATCH_LEVEL - - Note: - - ======================================================================== -*/ -VOID RTMPReportMicError( - IN PRTMP_ADAPTER pAd, - IN PCIPHER_KEY pWpaKey) -{ - ULONG Now; - UCHAR unicastKey = (pWpaKey->Type == PAIRWISE_KEY ? 1:0); - - // Record Last MIC error time and count - Now = jiffies; - if (pAd->StaCfg.MicErrCnt == 0) - { - pAd->StaCfg.MicErrCnt++; - pAd->StaCfg.LastMicErrorTime = Now; - NdisZeroMemory(pAd->StaCfg.ReplayCounter, 8); - } - else if (pAd->StaCfg.MicErrCnt == 1) - { - if ((pAd->StaCfg.LastMicErrorTime + (60 * OS_HZ)) < Now) - { - // Update Last MIC error time, this did not violate two MIC errors within 60 seconds - pAd->StaCfg.LastMicErrorTime = Now; - } - else - { - - if (pAd->CommonCfg.bWirelessEvent) - RTMPSendWirelessEvent(pAd, IW_COUNTER_MEASURES_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); - - pAd->StaCfg.LastMicErrorTime = Now; - // Violate MIC error counts, MIC countermeasures kicks in - pAd->StaCfg.MicErrCnt++; - // We shall block all reception - // We shall clean all Tx ring and disassoicate from AP after next EAPOL frame - // - // No necessary to clean all Tx ring, on RTMPHardTransmit will stop sending non-802.1X EAPOL packets - // if pAd->StaCfg.MicErrCnt greater than 2. - // - // RTMPRingCleanUp(pAd, QID_AC_BK); - // RTMPRingCleanUp(pAd, QID_AC_BE); - // RTMPRingCleanUp(pAd, QID_AC_VI); - // RTMPRingCleanUp(pAd, QID_AC_VO); - // RTMPRingCleanUp(pAd, QID_HCCA); - } - } - else - { - // MIC error count >= 2 - // This should not happen - ; - } - MlmeEnqueue(pAd, - MLME_CNTL_STATE_MACHINE, - OID_802_11_MIC_FAILURE_REPORT_FRAME, - 1, - &unicastKey); - - if (pAd->StaCfg.MicErrCnt == 2) - { - RTMPSetTimer(&pAd->StaCfg.WpaDisassocAndBlockAssocTimer, 100); - } -} - - -#ifdef WPA_SUPPLICANT_SUPPORT -#define LENGTH_EAP_H 4 -// If the received frame is EAP-Packet ,find out its EAP-Code (Request(0x01), Response(0x02), Success(0x03), Failure(0x04)). -INT WpaCheckEapCode( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pFrame, - IN USHORT FrameLen, - IN USHORT OffSet) -{ - - PUCHAR pData; - INT result = 0; - - if( FrameLen < OffSet + LENGTH_EAPOL_H + LENGTH_EAP_H ) - return result; - - pData = pFrame + OffSet; // skip offset bytes - - if(*(pData+1) == EAPPacket) // 802.1x header - Packet Type - { - result = *(pData+4); // EAP header - Code - } - - return result; -} - -VOID WpaSendMicFailureToWpaSupplicant( - IN PRTMP_ADAPTER pAd, - IN BOOLEAN bUnicast) -{ - union iwreq_data wrqu; - char custom[IW_CUSTOM_MAX] = {0}; - - sprintf(custom, "MLME-MICHAELMICFAILURE.indication"); - if (bUnicast) - sprintf(custom, "%s unicast", custom); - wrqu.data.length = strlen(custom); - wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, custom); - - return; -} -#endif // WPA_SUPPLICANT_SUPPORT // - -VOID WpaMicFailureReportFrame( - IN PRTMP_ADAPTER pAd, - IN MLME_QUEUE_ELEM *Elem) -{ - PUCHAR pOutBuffer = NULL; - UCHAR Header802_3[14]; - ULONG FrameLen = 0; - EAPOL_PACKET Packet; - UCHAR Mic[16]; - BOOLEAN bUnicast; - - DBGPRINT(RT_DEBUG_TRACE, ("WpaMicFailureReportFrame ----->\n")); - - bUnicast = (Elem->Msg[0] == 1 ? TRUE:FALSE); - pAd->Sequence = ((pAd->Sequence) + 1) & (MAX_SEQ_NUMBER); - - // init 802.3 header and Fill Packet - MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL); - - NdisZeroMemory(&Packet, sizeof(Packet)); - Packet.ProVer = EAPOL_VER; - Packet.ProType = EAPOLKey; - - Packet.KeyDesc.Type = WPA1_KEY_DESC; - - // Request field presented - Packet.KeyDesc.KeyInfo.Request = 1; - - if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) - { - Packet.KeyDesc.KeyInfo.KeyDescVer = 2; - } - else // TKIP - { - Packet.KeyDesc.KeyInfo.KeyDescVer = 1; - } - - Packet.KeyDesc.KeyInfo.KeyType = (bUnicast ? PAIRWISEKEY : GROUPKEY); - - // KeyMic field presented - Packet.KeyDesc.KeyInfo.KeyMic = 1; - - // Error field presented - Packet.KeyDesc.KeyInfo.Error = 1; - - // Update packet length after decide Key data payload - Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE; - - // Key Replay Count - NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY); - inc_byte_array(pAd->StaCfg.ReplayCounter, 8); - - // Convert to little-endian format. - *((USHORT *)&Packet.KeyDesc.KeyInfo) = cpu2le16(*((USHORT *)&Packet.KeyDesc.KeyInfo)); - - - MlmeAllocateMemory(pAd, (PUCHAR *)&pOutBuffer); // allocate memory - if(pOutBuffer == NULL) - { - return; - } - - // Prepare EAPOL frame for MIC calculation - // Be careful, only EAPOL frame is counted for MIC calculation - MakeOutgoingFrame(pOutBuffer, &FrameLen, - Packet.Body_Len[1] + 4, &Packet, - END_OF_ARGS); - - // Prepare and Fill MIC value - NdisZeroMemory(Mic, sizeof(Mic)); - if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) - { // AES - UCHAR digest[20] = {0}; - HMAC_SHA1(pOutBuffer, FrameLen, pAd->StaCfg.PTK, LEN_EAP_MICK, digest); - NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); - } - else - { // TKIP - hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic); - } - NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC); - - MakeOutgoingFrame(pOutBuffer, &FrameLen, - LENGTH_802_3, &Header802_3, - Packet.Body_Len[1] + 4, &Packet, - END_OF_ARGS); - - // opy frame to Tx ring and send MIC failure report frame to authenticator - RTMPToWirelessSta(pAd, Header802_3, LENGTH_802_3, (PUCHAR)&Packet, Packet.Body_Len[1] + 4, FALSE); - - MlmeFreeMemory(pAd, (PUCHAR)pOutBuffer); - - DBGPRINT(RT_DEBUG_TRACE, ("WpaMicFailureReportFrame <-----\n")); -} - -/** from wpa_supplicant - * inc_byte_array - Increment arbitrary length byte array by one - * @counter: Pointer to byte array - * @len: Length of the counter in bytes - * - * This function increments the last byte of the counter by one and continues - * rolling over to more significant bytes if the byte was incremented from - * 0xff to 0x00. - */ -void inc_byte_array(UCHAR *counter, int len) -{ - int pos = len - 1; - while (pos >= 0) { - counter[pos]++; - if (counter[pos] != 0) - break; - pos--; - } -} - -VOID WpaDisassocApAndBlockAssoc( - IN PVOID SystemSpecific1, - IN PVOID FunctionContext, - IN PVOID SystemSpecific2, - IN PVOID SystemSpecific3) -{ - RTMP_ADAPTER *pAd = (PRTMP_ADAPTER)FunctionContext; - MLME_DISASSOC_REQ_STRUCT DisassocReq; - - // disassoc from current AP first - DBGPRINT(RT_DEBUG_TRACE, ("RTMPReportMicError - disassociate with current AP after sending second continuous EAPOL frame\n")); - DisassocParmFill(pAd, &DisassocReq, pAd->CommonCfg.Bssid, REASON_MIC_FAILURE); - MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ, sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq); - - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_DISASSOC; - pAd->StaCfg.bBlockAssoc = TRUE; -} - +#include "../../rt2870/sta/wpa.c" diff --git a/drivers/staging/rt3070/sta_ioctl.c b/drivers/staging/rt3070/sta_ioctl.c index 079454835a43..ac56507e3c8f 100644 --- a/drivers/staging/rt3070/sta_ioctl.c +++ b/drivers/staging/rt3070/sta_ioctl.c @@ -1,7203 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - sta_ioctl.c - - Abstract: - IOCTL related subroutines - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Rory Chen 01-03-2003 created - Rory Chen 02-14-2005 modify to support RT61 -*/ - -#include "rt_config.h" - -#ifdef DBG -extern ULONG RTDebugLevel; -#endif - -#define NR_WEP_KEYS 4 -#define WEP_SMALL_KEY_LEN (40/8) -#define WEP_LARGE_KEY_LEN (104/8) - -#define GROUP_KEY_NO 4 - -extern UCHAR CipherWpa2Template[]; -extern UCHAR CipherWpaPskTkip[]; -extern UCHAR CipherWpaPskTkipLen; - -typedef struct PACKED _RT_VERSION_INFO{ - UCHAR DriverVersionW; - UCHAR DriverVersionX; - UCHAR DriverVersionY; - UCHAR DriverVersionZ; - UINT DriverBuildYear; - UINT DriverBuildMonth; - UINT DriverBuildDay; -} RT_VERSION_INFO, *PRT_VERSION_INFO; - -struct iw_priv_args privtab[] = { -{ RTPRIV_IOCTL_SET, - IW_PRIV_TYPE_CHAR | 1024, 0, - "set"}, - -{ RTPRIV_IOCTL_SHOW, 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, - ""}, -{ RTPRIV_IOCTL_SHOW, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, - ""}, -/* --- sub-ioctls definitions --- */ - { SHOW_CONN_STATUS, - 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "connStatus" }, - { SHOW_DRVIER_VERION, - 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "driverVer" }, - { SHOW_BA_INFO, - 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "bainfo" }, - { SHOW_DESC_INFO, - 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "descinfo" }, - { RAIO_OFF, - 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "radio_off" }, - { RAIO_ON, - 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "radio_on" }, -#ifdef QOS_DLS_SUPPORT - { SHOW_DLS_ENTRY_INFO, - 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "dlsentryinfo" }, -#endif // QOS_DLS_SUPPORT // - { SHOW_CFG_VALUE, - IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "show" }, -/* --- sub-ioctls relations --- */ - -#ifdef DBG -{ RTPRIV_IOCTL_BBP, - IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, - "bbp"}, -{ RTPRIV_IOCTL_MAC, - IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | 1024, - "mac"}, -#ifdef RT30xx -{ RTPRIV_IOCTL_RF, - IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, - "rf"}, -#endif // RT30xx // -{ RTPRIV_IOCTL_E2P, - IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | 1024, - "e2p"}, -#endif /* DBG */ - -{ RTPRIV_IOCTL_STATISTICS, - 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, - "stat"}, -{ RTPRIV_IOCTL_GSITESURVEY, - 0, IW_PRIV_TYPE_CHAR | 1024, - "get_site_survey"}, - - -}; - -INT Set_SSID_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - -#ifdef WMM_SUPPORT -INT Set_WmmCapable_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); -#endif - -INT Set_NetworkType_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - -INT Set_AuthMode_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - -INT Set_EncrypType_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - -INT Set_DefaultKeyID_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - -INT Set_Key1_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - -INT Set_Key2_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - -INT Set_Key3_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - -INT Set_Key4_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - -INT Set_WPAPSK_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - - -INT Set_PSMode_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - -#ifdef WPA_SUPPLICANT_SUPPORT -INT Set_Wpa_Support( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); -#endif // WPA_SUPPLICANT_SUPPORT // - -#ifdef DBG - -VOID RTMPIoctlMAC( - IN PRTMP_ADAPTER pAdapter, - IN struct iwreq *wrq); - -VOID RTMPIoctlE2PROM( - IN PRTMP_ADAPTER pAdapter, - IN struct iwreq *wrq); - -#ifdef RT30xx -VOID RTMPIoctlRF( - IN PRTMP_ADAPTER pAdapter, - IN struct iwreq *wrq); -#endif // RT30xx // -#endif // DBG // - - -NDIS_STATUS RTMPWPANoneAddKeyProc( - IN PRTMP_ADAPTER pAd, - IN PVOID pBuf); - -INT Set_FragTest_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - -#ifdef DOT11_N_SUPPORT -INT Set_TGnWifiTest_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); -#endif // DOT11_N_SUPPORT // - -INT Set_LongRetryLimit_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - -INT Set_ShortRetryLimit_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); - -#ifdef EXT_BUILD_CHANNEL_LIST -INT Set_Ieee80211dClientMode_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg); -#endif // EXT_BUILD_CHANNEL_LIST // - -#ifdef CARRIER_DETECTION_SUPPORT -INT Set_CarrierDetect_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg); -#endif // CARRIER_DETECTION_SUPPORT // - -static struct { - CHAR *name; - INT (*set_proc)(PRTMP_ADAPTER pAdapter, PUCHAR arg); -} *PRTMP_PRIVATE_SET_PROC, RTMP_PRIVATE_SUPPORT_PROC[] = { - {"DriverVersion", Set_DriverVersion_Proc}, - {"CountryRegion", Set_CountryRegion_Proc}, - {"CountryRegionABand", Set_CountryRegionABand_Proc}, - {"SSID", Set_SSID_Proc}, - {"WirelessMode", Set_WirelessMode_Proc}, - {"TxBurst", Set_TxBurst_Proc}, - {"TxPreamble", Set_TxPreamble_Proc}, - {"TxPower", Set_TxPower_Proc}, - {"Channel", Set_Channel_Proc}, - {"BGProtection", Set_BGProtection_Proc}, - {"RTSThreshold", Set_RTSThreshold_Proc}, - {"FragThreshold", Set_FragThreshold_Proc}, -#ifdef DOT11_N_SUPPORT - {"HtBw", Set_HtBw_Proc}, - {"HtMcs", Set_HtMcs_Proc}, - {"HtGi", Set_HtGi_Proc}, - {"HtOpMode", Set_HtOpMode_Proc}, - {"HtExtcha", Set_HtExtcha_Proc}, - {"HtMpduDensity", Set_HtMpduDensity_Proc}, - {"HtBaWinSize", Set_HtBaWinSize_Proc}, - {"HtRdg", Set_HtRdg_Proc}, - {"HtAmsdu", Set_HtAmsdu_Proc}, - {"HtAutoBa", Set_HtAutoBa_Proc}, - {"HtBaDecline", Set_BADecline_Proc}, - {"HtProtect", Set_HtProtect_Proc}, - {"HtMimoPs", Set_HtMimoPs_Proc}, -#endif // DOT11_N_SUPPORT // - -#ifdef AGGREGATION_SUPPORT - {"PktAggregate", Set_PktAggregate_Proc}, -#endif - -#ifdef WMM_SUPPORT - {"WmmCapable", Set_WmmCapable_Proc}, -#endif - {"IEEE80211H", Set_IEEE80211H_Proc}, - {"NetworkType", Set_NetworkType_Proc}, - {"AuthMode", Set_AuthMode_Proc}, - {"EncrypType", Set_EncrypType_Proc}, - {"DefaultKeyID", Set_DefaultKeyID_Proc}, - {"Key1", Set_Key1_Proc}, - {"Key2", Set_Key2_Proc}, - {"Key3", Set_Key3_Proc}, - {"Key4", Set_Key4_Proc}, - {"WPAPSK", Set_WPAPSK_Proc}, - {"ResetCounter", Set_ResetStatCounter_Proc}, - {"PSMode", Set_PSMode_Proc}, -#ifdef DBG - {"Debug", Set_Debug_Proc}, -#endif - -#ifdef RALINK_ATE - {"ATE", Set_ATE_Proc}, - {"ATEDA", Set_ATE_DA_Proc}, - {"ATESA", Set_ATE_SA_Proc}, - {"ATEBSSID", Set_ATE_BSSID_Proc}, - {"ATECHANNEL", Set_ATE_CHANNEL_Proc}, - {"ATETXPOW0", Set_ATE_TX_POWER0_Proc}, - {"ATETXPOW1", Set_ATE_TX_POWER1_Proc}, - {"ATETXANT", Set_ATE_TX_Antenna_Proc}, - {"ATERXANT", Set_ATE_RX_Antenna_Proc}, - {"ATETXFREQOFFSET", Set_ATE_TX_FREQOFFSET_Proc}, - {"ATETXBW", Set_ATE_TX_BW_Proc}, - {"ATETXLEN", Set_ATE_TX_LENGTH_Proc}, - {"ATETXCNT", Set_ATE_TX_COUNT_Proc}, - {"ATETXMCS", Set_ATE_TX_MCS_Proc}, - {"ATETXMODE", Set_ATE_TX_MODE_Proc}, - {"ATETXGI", Set_ATE_TX_GI_Proc}, - {"ATERXFER", Set_ATE_RX_FER_Proc}, - {"ATERRF", Set_ATE_Read_RF_Proc}, - {"ATEWRF1", Set_ATE_Write_RF1_Proc}, - {"ATEWRF2", Set_ATE_Write_RF2_Proc}, - {"ATEWRF3", Set_ATE_Write_RF3_Proc}, - {"ATEWRF4", Set_ATE_Write_RF4_Proc}, - {"ATELDE2P", Set_ATE_Load_E2P_Proc}, - {"ATERE2P", Set_ATE_Read_E2P_Proc}, - {"ATESHOW", Set_ATE_Show_Proc}, - {"ATEHELP", Set_ATE_Help_Proc}, - -#ifdef RALINK_28xx_QA - {"TxStop", Set_TxStop_Proc}, - {"RxStop", Set_RxStop_Proc}, -#endif // RALINK_28xx_QA // -#endif // RALINK_ATE // - -#ifdef WPA_SUPPLICANT_SUPPORT - {"WpaSupport", Set_Wpa_Support}, -#endif // WPA_SUPPLICANT_SUPPORT // - - - - {"FixedTxMode", Set_FixedTxMode_Proc}, -#ifdef CONFIG_APSTA_MIXED_SUPPORT - {"OpMode", Set_OpMode_Proc}, -#endif // CONFIG_APSTA_MIXED_SUPPORT // -#ifdef DOT11_N_SUPPORT - {"TGnWifiTest", Set_TGnWifiTest_Proc}, - {"ForceGF", Set_ForceGF_Proc}, -#endif // DOT11_N_SUPPORT // -#ifdef QOS_DLS_SUPPORT - {"DlsAddEntry", Set_DlsAddEntry_Proc}, - {"DlsTearDownEntry", Set_DlsTearDownEntry_Proc}, -#endif // QOS_DLS_SUPPORT // - {"LongRetry", Set_LongRetryLimit_Proc}, - {"ShortRetry", Set_ShortRetryLimit_Proc}, -#ifdef EXT_BUILD_CHANNEL_LIST - {"11dClientMode", Set_Ieee80211dClientMode_Proc}, -#endif // EXT_BUILD_CHANNEL_LIST // -#ifdef CARRIER_DETECTION_SUPPORT - {"CarrierDetect", Set_CarrierDetect_Proc}, -#endif // CARRIER_DETECTION_SUPPORT // -//2008/09/11:KH add to support efuse<-- -#ifdef RT30xx - {"efuseFreeNumber", set_eFuseGetFreeBlockCount_Proc}, - {"efuseDump", set_eFusedump_Proc}, - {"efuseLoadFromBin", set_eFuseLoadFromBin_Proc}, -#endif // RT30xx // -//2008/09/11:KH add to support efuse--> - {NULL,} -}; - - -VOID RTMPAddKey( - IN PRTMP_ADAPTER pAd, - IN PNDIS_802_11_KEY pKey) -{ - ULONG KeyIdx; - MAC_TABLE_ENTRY *pEntry; - - DBGPRINT(RT_DEBUG_TRACE, ("RTMPAddKey ------>\n")); - - if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - { - if (pKey->KeyIndex & 0x80000000) - { - if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) - { - NdisZeroMemory(pAd->StaCfg.PMK, 32); - NdisMoveMemory(pAd->StaCfg.PMK, pKey->KeyMaterial, pKey->KeyLength); - goto end; - } - // Update PTK - NdisZeroMemory(&pAd->SharedKey[BSS0][0], sizeof(CIPHER_KEY)); - pAd->SharedKey[BSS0][0].KeyLen = LEN_TKIP_EK; - NdisMoveMemory(pAd->SharedKey[BSS0][0].Key, pKey->KeyMaterial, LEN_TKIP_EK); -#ifdef WPA_SUPPLICANT_SUPPORT - if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled) - { - NdisMoveMemory(pAd->SharedKey[BSS0][0].RxMic, pKey->KeyMaterial + LEN_TKIP_EK, LEN_TKIP_TXMICK); - NdisMoveMemory(pAd->SharedKey[BSS0][0].TxMic, pKey->KeyMaterial + LEN_TKIP_EK + LEN_TKIP_TXMICK, LEN_TKIP_RXMICK); - } - else -#endif // WPA_SUPPLICANT_SUPPORT // - { - NdisMoveMemory(pAd->SharedKey[BSS0][0].TxMic, pKey->KeyMaterial + LEN_TKIP_EK, LEN_TKIP_TXMICK); - NdisMoveMemory(pAd->SharedKey[BSS0][0].RxMic, pKey->KeyMaterial + LEN_TKIP_EK + LEN_TKIP_TXMICK, LEN_TKIP_RXMICK); - } - - // Decide its ChiperAlg - if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled) - pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_TKIP; - else if (pAd->StaCfg.PairCipher == Ndis802_11Encryption3Enabled) - pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_AES; - else - pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_NONE; - - // Update these related information to MAC_TABLE_ENTRY - pEntry = &pAd->MacTab.Content[BSSID_WCID]; - NdisMoveMemory(pEntry->PairwiseKey.Key, pAd->SharedKey[BSS0][0].Key, LEN_TKIP_EK); - NdisMoveMemory(pEntry->PairwiseKey.RxMic, pAd->SharedKey[BSS0][0].RxMic, LEN_TKIP_RXMICK); - NdisMoveMemory(pEntry->PairwiseKey.TxMic, pAd->SharedKey[BSS0][0].TxMic, LEN_TKIP_TXMICK); - pEntry->PairwiseKey.CipherAlg = pAd->SharedKey[BSS0][0].CipherAlg; - - // Update pairwise key information to ASIC Shared Key Table - AsicAddSharedKeyEntry(pAd, - BSS0, - 0, - pAd->SharedKey[BSS0][0].CipherAlg, - pAd->SharedKey[BSS0][0].Key, - pAd->SharedKey[BSS0][0].TxMic, - pAd->SharedKey[BSS0][0].RxMic); - - // Update ASIC WCID attribute table and IVEIV table - RTMPAddWcidAttributeEntry(pAd, - BSS0, - 0, - pAd->SharedKey[BSS0][0].CipherAlg, - pEntry); - - if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA2) - { - // set 802.1x port control - //pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; - STA_PORT_SECURED(pAd); - - // Indicate Connected for GUI - pAd->IndicateMediaState = NdisMediaStateConnected; - } - } - else - { - // Update GTK - pAd->StaCfg.DefaultKeyId = (pKey->KeyIndex & 0xFF); - NdisZeroMemory(&pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId], sizeof(CIPHER_KEY)); - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].KeyLen = LEN_TKIP_EK; - NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, pKey->KeyMaterial, LEN_TKIP_EK); -#ifdef WPA_SUPPLICANT_SUPPORT - if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption2Enabled) - { - NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic, pKey->KeyMaterial + LEN_TKIP_EK, LEN_TKIP_TXMICK); - NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, pKey->KeyMaterial + LEN_TKIP_EK + LEN_TKIP_TXMICK, LEN_TKIP_RXMICK); - } - else -#endif // WPA_SUPPLICANT_SUPPORT // - { - NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, pKey->KeyMaterial + LEN_TKIP_EK, LEN_TKIP_TXMICK); - NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic, pKey->KeyMaterial + LEN_TKIP_EK + LEN_TKIP_TXMICK, LEN_TKIP_RXMICK); - } - - // Update Shared Key CipherAlg - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_NONE; - if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption2Enabled) - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_TKIP; - else if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption3Enabled) - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_AES; - - // Update group key information to ASIC Shared Key Table - AsicAddSharedKeyEntry(pAd, - BSS0, - pAd->StaCfg.DefaultKeyId, - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic); - - // Update ASIC WCID attribute table and IVEIV table - RTMPAddWcidAttributeEntry(pAd, - BSS0, - pAd->StaCfg.DefaultKeyId, - pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, - NULL); - - // set 802.1x port control - //pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; - STA_PORT_SECURED(pAd); - - // Indicate Connected for GUI - pAd->IndicateMediaState = NdisMediaStateConnected; - } - } - else // dynamic WEP from wpa_supplicant - { - UCHAR CipherAlg; - PUCHAR Key; - - if(pKey->KeyLength == 32) - goto end; - - KeyIdx = pKey->KeyIndex & 0x0fffffff; - - if (KeyIdx < 4) - { - // it is a default shared key, for Pairwise key setting - if (pKey->KeyIndex & 0x80000000) - { - pEntry = MacTableLookup(pAd, pKey->BSSID); - - if (pEntry) - { - DBGPRINT(RT_DEBUG_TRACE, ("RTMPAddKey: Set Pair-wise Key\n")); - - // set key material and key length - pEntry->PairwiseKey.KeyLen = (UCHAR)pKey->KeyLength; - NdisMoveMemory(pEntry->PairwiseKey.Key, &pKey->KeyMaterial, pKey->KeyLength); - - // set Cipher type - if (pKey->KeyLength == 5) - pEntry->PairwiseKey.CipherAlg = CIPHER_WEP64; - else - pEntry->PairwiseKey.CipherAlg = CIPHER_WEP128; - - // Add Pair-wise key to Asic - AsicAddPairwiseKeyEntry( - pAd, - pEntry->Addr, - (UCHAR)pEntry->Aid, - &pEntry->PairwiseKey); - - // update WCID attribute table and IVEIV table for this entry - RTMPAddWcidAttributeEntry( - pAd, - BSS0, - KeyIdx, // The value may be not zero - pEntry->PairwiseKey.CipherAlg, - pEntry); - - } - } - else - { - // Default key for tx (shared key) - pAd->StaCfg.DefaultKeyId = (UCHAR) KeyIdx; - - // set key material and key length - pAd->SharedKey[BSS0][KeyIdx].KeyLen = (UCHAR) pKey->KeyLength; - NdisMoveMemory(pAd->SharedKey[BSS0][KeyIdx].Key, &pKey->KeyMaterial, pKey->KeyLength); - - // Set Ciper type - if (pKey->KeyLength == 5) - pAd->SharedKey[BSS0][KeyIdx].CipherAlg = CIPHER_WEP64; - else - pAd->SharedKey[BSS0][KeyIdx].CipherAlg = CIPHER_WEP128; - - CipherAlg = pAd->SharedKey[BSS0][KeyIdx].CipherAlg; - Key = pAd->SharedKey[BSS0][KeyIdx].Key; - - // Set Group key material to Asic - AsicAddSharedKeyEntry(pAd, BSS0, KeyIdx, CipherAlg, Key, NULL, NULL); - - // Update WCID attribute table and IVEIV table for this group key table - RTMPAddWcidAttributeEntry(pAd, BSS0, KeyIdx, CipherAlg, NULL); - - } - } - } -end: - return; -} - -char * rtstrchr(const char * s, int c) -{ - for(; *s != (char) c; ++s) - if (*s == '\0') - return NULL; - return (char *) s; -} - -/* -This is required for LinEX2004/kernel2.6.7 to provide iwlist scanning function -*/ - -int -rt_ioctl_giwname(struct net_device *dev, - struct iw_request_info *info, - char *name, char *extra) -{ -// PRTMP_ADAPTER pAdapter = dev->ml_priv; - -#ifdef RT2870 - strncpy(name, "RT2870 Wireless", IFNAMSIZ); -#endif // RT2870 // - return 0; -} - -int rt_ioctl_siwfreq(struct net_device *dev, - struct iw_request_info *info, - struct iw_freq *freq, char *extra) -{ - PRTMP_ADAPTER pAdapter = dev->ml_priv; - int chan = -1; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - - if (freq->e > 1) - return -EINVAL; - - if((freq->e == 0) && (freq->m <= 1000)) - chan = freq->m; // Setting by channel number - else - MAP_KHZ_TO_CHANNEL_ID( (freq->m /100) , chan); // Setting by frequency - search the table , like 2.412G, 2.422G, - - if (ChannelSanity(pAdapter, chan) == TRUE) - { - pAdapter->CommonCfg.Channel = chan; - DBGPRINT(RT_DEBUG_ERROR, ("==>rt_ioctl_siwfreq::SIOCSIWFREQ[cmd=0x%x] (Channel=%d)\n", SIOCSIWFREQ, pAdapter->CommonCfg.Channel)); - } - else - return -EINVAL; - - return 0; -} -int rt_ioctl_giwfreq(struct net_device *dev, - struct iw_request_info *info, - struct iw_freq *freq, char *extra) -{ - VIRTUAL_ADAPTER *pVirtualAd = NULL; - PRTMP_ADAPTER pAdapter; - UCHAR ch; - ULONG m; - - if (dev->priv_flags == INT_MAIN) - { - pAdapter = dev->ml_priv; - } - else - { - pVirtualAd = dev->ml_priv; - pAdapter = pVirtualAd->RtmpDev->ml_priv; - } - - if (pAdapter == NULL) - { - /* if 1st open fail, pAd will be free; - So the net_dev->ml_priv will be NULL in 2rd open */ - return -ENETDOWN; - } - - ch = pAdapter->CommonCfg.Channel; - - DBGPRINT(RT_DEBUG_TRACE,("==>rt_ioctl_giwfreq %d\n", ch)); - - MAP_CHANNEL_ID_TO_KHZ(ch, m); - freq->m = m * 100; - freq->e = 1; - return 0; -} - -int rt_ioctl_siwmode(struct net_device *dev, - struct iw_request_info *info, - __u32 *mode, char *extra) -{ - PRTMP_ADAPTER pAdapter = dev->ml_priv; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - switch (*mode) - { - case IW_MODE_ADHOC: - Set_NetworkType_Proc(pAdapter, "Adhoc"); - break; - case IW_MODE_INFRA: - Set_NetworkType_Proc(pAdapter, "Infra"); - break; -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,20)) - case IW_MODE_MONITOR: - Set_NetworkType_Proc(pAdapter, "Monitor"); - break; -#endif - default: - DBGPRINT(RT_DEBUG_TRACE, ("===>rt_ioctl_siwmode::SIOCSIWMODE (unknown %d)\n", *mode)); - return -EINVAL; - } - - // Reset Ralink supplicant to not use, it will be set to start when UI set PMK key - pAdapter->StaCfg.WpaState = SS_NOTUSE; - - return 0; -} - -int rt_ioctl_giwmode(struct net_device *dev, - struct iw_request_info *info, - __u32 *mode, char *extra) -{ - PRTMP_ADAPTER pAdapter = dev->ml_priv; - - if (ADHOC_ON(pAdapter)) - *mode = IW_MODE_ADHOC; - else if (INFRA_ON(pAdapter)) - *mode = IW_MODE_INFRA; -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,20)) - else if (MONITOR_ON(pAdapter)) - { - *mode = IW_MODE_MONITOR; - } -#endif - else - *mode = IW_MODE_AUTO; - - DBGPRINT(RT_DEBUG_TRACE, ("==>rt_ioctl_giwmode(mode=%d)\n", *mode)); - return 0; -} - -int rt_ioctl_siwsens(struct net_device *dev, - struct iw_request_info *info, - char *name, char *extra) -{ - PRTMP_ADAPTER pAdapter = dev->ml_priv; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - return 0; -} - -int rt_ioctl_giwsens(struct net_device *dev, - struct iw_request_info *info, - char *name, char *extra) -{ - return 0; -} - -int rt_ioctl_giwrange(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *extra) -{ - PRTMP_ADAPTER pAdapter = dev->ml_priv; - - struct iw_range *range = (struct iw_range *) extra; - u16 val; - int i; - - DBGPRINT(RT_DEBUG_TRACE ,("===>rt_ioctl_giwrange\n")); - data->length = sizeof(struct iw_range); - memset(range, 0, sizeof(struct iw_range)); - - range->txpower_capa = IW_TXPOW_DBM; - - if (INFRA_ON(pAdapter)||ADHOC_ON(pAdapter)) - { - range->min_pmp = 1 * 1024; - range->max_pmp = 65535 * 1024; - range->min_pmt = 1 * 1024; - range->max_pmt = 1000 * 1024; - range->pmp_flags = IW_POWER_PERIOD; - range->pmt_flags = IW_POWER_TIMEOUT; - range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | - IW_POWER_UNICAST_R | IW_POWER_ALL_R; - } - - range->we_version_compiled = WIRELESS_EXT; - range->we_version_source = 14; - - range->retry_capa = IW_RETRY_LIMIT; - range->retry_flags = IW_RETRY_LIMIT; - range->min_retry = 0; - range->max_retry = 255; - - range->num_channels = pAdapter->ChannelListNum; - - val = 0; - for (i = 1; i <= range->num_channels; i++) - { - u32 m; - range->freq[val].i = pAdapter->ChannelList[i-1].Channel; - MAP_CHANNEL_ID_TO_KHZ(pAdapter->ChannelList[i-1].Channel, m); - range->freq[val].m = m * 100; /* HZ */ - - range->freq[val].e = 1; - val++; - if (val == IW_MAX_FREQUENCIES) - break; - } - range->num_frequency = val; - - range->max_qual.qual = 100; /* what is correct max? This was not - * documented exactly. At least - * 69 has been observed. */ - range->max_qual.level = 0; /* dB */ - range->max_qual.noise = 0; /* dB */ - - /* What would be suitable values for "average/typical" qual? */ - range->avg_qual.qual = 20; - range->avg_qual.level = -60; - range->avg_qual.noise = -95; - range->sensitivity = 3; - - range->max_encoding_tokens = NR_WEP_KEYS; - range->num_encoding_sizes = 2; - range->encoding_size[0] = 5; - range->encoding_size[1] = 13; - - range->min_rts = 0; - range->max_rts = 2347; - range->min_frag = 256; - range->max_frag = 2346; - -#if WIRELESS_EXT > 17 - /* IW_ENC_CAPA_* bit field */ - range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | - IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; -#endif - - return 0; -} - -int rt_ioctl_siwap(struct net_device *dev, - struct iw_request_info *info, - struct sockaddr *ap_addr, char *extra) -{ - PRTMP_ADAPTER pAdapter = dev->ml_priv; - NDIS_802_11_MAC_ADDRESS Bssid; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) - { - RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); - DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); - } - - // tell CNTL state machine to call NdisMSetInformationComplete() after completing - // this request, because this request is initiated by NDIS. - pAdapter->MlmeAux.CurrReqIsFromNdis = FALSE; - // Prevent to connect AP again in STAMlmePeriodicExec - pAdapter->MlmeAux.AutoReconnectSsidLen= 32; - - memset(Bssid, 0, MAC_ADDR_LEN); - memcpy(Bssid, ap_addr->sa_data, MAC_ADDR_LEN); - MlmeEnqueue(pAdapter, - MLME_CNTL_STATE_MACHINE, - OID_802_11_BSSID, - sizeof(NDIS_802_11_MAC_ADDRESS), - (VOID *)&Bssid); - - DBGPRINT(RT_DEBUG_TRACE, ("IOCTL::SIOCSIWAP %02x:%02x:%02x:%02x:%02x:%02x\n", - Bssid[0], Bssid[1], Bssid[2], Bssid[3], Bssid[4], Bssid[5])); - - return 0; -} - -int rt_ioctl_giwap(struct net_device *dev, - struct iw_request_info *info, - struct sockaddr *ap_addr, char *extra) -{ - PRTMP_ADAPTER pAdapter = dev->ml_priv; - - if (INFRA_ON(pAdapter) || ADHOC_ON(pAdapter)) - { - ap_addr->sa_family = ARPHRD_ETHER; - memcpy(ap_addr->sa_data, &pAdapter->CommonCfg.Bssid, ETH_ALEN); - } -#ifdef WPA_SUPPLICANT_SUPPORT - // Add for RT2870 - else if (pAdapter->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_DISABLE) - { - ap_addr->sa_family = ARPHRD_ETHER; - memcpy(ap_addr->sa_data, &pAdapter->MlmeAux.Bssid, ETH_ALEN); - } -#endif // WPA_SUPPLICANT_SUPPORT // - else - { - DBGPRINT(RT_DEBUG_TRACE, ("IOCTL::SIOCGIWAP(=EMPTY)\n")); - return -ENOTCONN; - } - - return 0; -} - -/* - * Units are in db above the noise floor. That means the - * rssi values reported in the tx/rx descriptors in the - * driver are the SNR expressed in db. - * - * If you assume that the noise floor is -95, which is an - * excellent assumption 99.5 % of the time, then you can - * derive the absolute signal level (i.e. -95 + rssi). - * There are some other slight factors to take into account - * depending on whether the rssi measurement is from 11b, - * 11g, or 11a. These differences are at most 2db and - * can be documented. - * - * NB: various calculations are based on the orinoco/wavelan - * drivers for compatibility - */ -static void set_quality(PRTMP_ADAPTER pAdapter, - struct iw_quality *iq, - signed char rssi) -{ - __u8 ChannelQuality; - - // Normalize Rssi - if (rssi >= -50) - ChannelQuality = 100; - else if (rssi >= -80) // between -50 ~ -80dbm - ChannelQuality = (__u8)(24 + ((rssi + 80) * 26)/10); - else if (rssi >= -90) // between -80 ~ -90dbm - ChannelQuality = (__u8)((rssi + 90) * 26)/10; - else - ChannelQuality = 0; - - iq->qual = (__u8)ChannelQuality; - - iq->level = (__u8)(rssi); - iq->noise = (pAdapter->BbpWriteLatch[66] > pAdapter->BbpTuning.FalseCcaUpperThreshold) ? ((__u8)pAdapter->BbpTuning.FalseCcaUpperThreshold) : ((__u8) pAdapter->BbpWriteLatch[66]); // noise level (dBm) - iq->noise += 256 - 143; - iq->updated = pAdapter->iw_stats.qual.updated; -} - -int rt_ioctl_iwaplist(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *extra) -{ - PRTMP_ADAPTER pAdapter = dev->ml_priv; - - struct sockaddr addr[IW_MAX_AP]; - struct iw_quality qual[IW_MAX_AP]; - int i; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - data->length = 0; - return 0; - //return -ENETDOWN; - } - - for (i = 0; i = pAdapter->ScanTab.BssNr) - break; - addr[i].sa_family = ARPHRD_ETHER; - memcpy(addr[i].sa_data, &pAdapter->ScanTab.BssEntry[i].Bssid, MAC_ADDR_LEN); - set_quality(pAdapter, &qual[i], pAdapter->ScanTab.BssEntry[i].Rssi); - } - data->length = i; - memcpy(extra, &addr, i*sizeof(addr[0])); - data->flags = 1; /* signal quality present (sort of) */ - memcpy(extra + i*sizeof(addr[0]), &qual, i*sizeof(qual[i])); - - return 0; -} - -#ifdef SIOCGIWSCAN -int rt_ioctl_siwscan(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *extra) -{ - PRTMP_ADAPTER pAdapter = dev->ml_priv; - - ULONG Now; - int Status = NDIS_STATUS_SUCCESS; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - if (MONITOR_ON(pAdapter)) - { - DBGPRINT(RT_DEBUG_TRACE, ("!!! Driver is in Monitor Mode now !!!\n")); - return -EINVAL; - } - - -#ifdef WPA_SUPPLICANT_SUPPORT - if (pAdapter->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_ENABLE) - { - pAdapter->StaCfg.WpaSupplicantScanCount++; - } -#endif // WPA_SUPPLICANT_SUPPORT // - - pAdapter->StaCfg.bScanReqIsFromWebUI = TRUE; - if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) - return 0; - do{ - Now = jiffies; - -#ifdef WPA_SUPPLICANT_SUPPORT - if ((pAdapter->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_ENABLE) && - (pAdapter->StaCfg.WpaSupplicantScanCount > 3)) - { - DBGPRINT(RT_DEBUG_TRACE, ("!!! WpaSupplicantScanCount > 3\n")); - Status = NDIS_STATUS_SUCCESS; - break; - } -#endif // WPA_SUPPLICANT_SUPPORT // - - if ((OPSTATUS_TEST_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED)) && - ((pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || - (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) && - (pAdapter->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED)) - { - DBGPRINT(RT_DEBUG_TRACE, ("!!! Link UP, Port Not Secured! ignore this set::OID_802_11_BSSID_LIST_SCAN\n")); - Status = NDIS_STATUS_SUCCESS; - break; - } - - if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) - { - RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); - DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); - } - - // tell CNTL state machine to call NdisMSetInformationComplete() after completing - // this request, because this request is initiated by NDIS. - pAdapter->MlmeAux.CurrReqIsFromNdis = FALSE; - // Reset allowed scan retries - pAdapter->StaCfg.ScanCnt = 0; - pAdapter->StaCfg.LastScanTime = Now; - - MlmeEnqueue(pAdapter, - MLME_CNTL_STATE_MACHINE, - OID_802_11_BSSID_LIST_SCAN, - 0, - NULL); - - Status = NDIS_STATUS_SUCCESS; - RT28XX_MLME_HANDLER(pAdapter); - }while(0); - return 0; -} - -int rt_ioctl_giwscan(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *extra) -{ - - PRTMP_ADAPTER pAdapter = dev->ml_priv; - int i=0; - char *current_ev = extra, *previous_ev = extra; - char *end_buf; - char *current_val, custom[MAX_CUSTOM_LEN] = {0}; -#ifndef IWEVGENIE - char idx; -#endif // IWEVGENIE // - struct iw_event iwe; - - if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) - { - /* - * Still scanning, indicate the caller should try again. - */ - return -EAGAIN; - } - - -#ifdef WPA_SUPPLICANT_SUPPORT - if (pAdapter->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_ENABLE) - { - pAdapter->StaCfg.WpaSupplicantScanCount = 0; - } -#endif // WPA_SUPPLICANT_SUPPORT // - - if (pAdapter->ScanTab.BssNr == 0) - { - data->length = 0; - return 0; - } - -#if WIRELESS_EXT >= 17 - if (data->length > 0) - end_buf = extra + data->length; - else - end_buf = extra + IW_SCAN_MAX_DATA; -#else - end_buf = extra + IW_SCAN_MAX_DATA; -#endif - - for (i = 0; i < pAdapter->ScanTab.BssNr; i++) - { - if (current_ev >= end_buf) - { -#if WIRELESS_EXT >= 17 - return -E2BIG; -#else - break; -#endif - } - - //MAC address - //================================ - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWAP; - iwe.u.ap_addr.sa_family = ARPHRD_ETHER; - memcpy(iwe.u.ap_addr.sa_data, &pAdapter->ScanTab.BssEntry[i].Bssid, ETH_ALEN); - - previous_ev = current_ev; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_ADDR_LEN); - if (current_ev == previous_ev) -#if WIRELESS_EXT >= 17 - return -E2BIG; -#else - break; -#endif - - /* - Protocol: - it will show scanned AP's WirelessMode . - it might be - 802.11a - 802.11a/n - 802.11g/n - 802.11b/g/n - 802.11g - 802.11b/g - */ - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWNAME; - - - { - PBSS_ENTRY pBssEntry=&pAdapter->ScanTab.BssEntry[i]; - BOOLEAN isGonly=FALSE; - int rateCnt=0; - - if (pBssEntry->Channel>14) - { - if (pBssEntry->HtCapabilityLen!=0) - strcpy(iwe.u.name,"802.11a/n"); - else - strcpy(iwe.u.name,"802.11a"); - } - else - { - /* - if one of non B mode rate is set supported rate . it mean G only. - */ - for (rateCnt=0;rateCntSupRateLen;rateCnt++) - { - /* - 6Mbps(140) 9Mbps(146) and >=12Mbps(152) are supported rate , it mean G only. - */ - if (pBssEntry->SupRate[rateCnt]==140 || pBssEntry->SupRate[rateCnt]==146 || pBssEntry->SupRate[rateCnt]>=152) - isGonly=TRUE; - } - - for (rateCnt=0;rateCntExtRateLen;rateCnt++) - { - if (pBssEntry->ExtRate[rateCnt]==140 || pBssEntry->ExtRate[rateCnt]==146 || pBssEntry->ExtRate[rateCnt]>=152) - isGonly=TRUE; - } - - - if (pBssEntry->HtCapabilityLen!=0) - { - if (isGonly==TRUE) - strcpy(iwe.u.name,"802.11g/n"); - else - strcpy(iwe.u.name,"802.11b/g/n"); - } - else - { - if (isGonly==TRUE) - strcpy(iwe.u.name,"802.11g"); - else - { - if (pBssEntry->SupRateLen==4 && pBssEntry->ExtRateLen==0) - strcpy(iwe.u.name,"802.11b"); - else - strcpy(iwe.u.name,"802.11b/g"); - } - } - } - } - - previous_ev = current_ev; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_ADDR_LEN); - if (current_ev == previous_ev) -#if WIRELESS_EXT >= 17 - return -E2BIG; -#else - break; -#endif - - //ESSID - //================================ - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWESSID; - iwe.u.data.length = pAdapter->ScanTab.BssEntry[i].SsidLen; - iwe.u.data.flags = 1; - - previous_ev = current_ev; - current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, pAdapter->ScanTab.BssEntry[i].Ssid); - if (current_ev == previous_ev) -#if WIRELESS_EXT >= 17 - return -E2BIG; -#else - break; -#endif - - //Network Type - //================================ - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWMODE; - if (pAdapter->ScanTab.BssEntry[i].BssType == Ndis802_11IBSS) - { - iwe.u.mode = IW_MODE_ADHOC; - } - else if (pAdapter->ScanTab.BssEntry[i].BssType == Ndis802_11Infrastructure) - { - iwe.u.mode = IW_MODE_INFRA; - } - else - { - iwe.u.mode = IW_MODE_AUTO; - } - iwe.len = IW_EV_UINT_LEN; - - previous_ev = current_ev; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_UINT_LEN); - if (current_ev == previous_ev) -#if WIRELESS_EXT >= 17 - return -E2BIG; -#else - break; -#endif - - //Channel and Frequency - //================================ - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWFREQ; - if (INFRA_ON(pAdapter) || ADHOC_ON(pAdapter)) - iwe.u.freq.m = pAdapter->ScanTab.BssEntry[i].Channel; - else - iwe.u.freq.m = pAdapter->ScanTab.BssEntry[i].Channel; - iwe.u.freq.e = 0; - iwe.u.freq.i = 0; - - previous_ev = current_ev; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_FREQ_LEN); - if (current_ev == previous_ev) -#if WIRELESS_EXT >= 17 - return -E2BIG; -#else - break; -#endif - - //Add quality statistics - //================================ - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = IWEVQUAL; - iwe.u.qual.level = 0; - iwe.u.qual.noise = 0; - set_quality(pAdapter, &iwe.u.qual, pAdapter->ScanTab.BssEntry[i].Rssi); - current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_QUAL_LEN); - if (current_ev == previous_ev) -#if WIRELESS_EXT >= 17 - return -E2BIG; -#else - break; -#endif - - //Encyption key - //================================ - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWENCODE; - if (CAP_IS_PRIVACY_ON (pAdapter->ScanTab.BssEntry[i].CapabilityInfo )) - iwe.u.data.flags =IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; - else - iwe.u.data.flags = IW_ENCODE_DISABLED; - - previous_ev = current_ev; - current_ev = iwe_stream_add_point(info, current_ev, end_buf,&iwe, (char *)pAdapter->SharedKey[BSS0][(iwe.u.data.flags & IW_ENCODE_INDEX)-1].Key); - if (current_ev == previous_ev) -#if WIRELESS_EXT >= 17 - return -E2BIG; -#else - break; -#endif - - //Bit Rate - //================================ - if (pAdapter->ScanTab.BssEntry[i].SupRateLen) - { - UCHAR tmpRate = pAdapter->ScanTab.BssEntry[i].SupRate[pAdapter->ScanTab.BssEntry[i].SupRateLen-1]; - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWRATE; - current_val = current_ev + IW_EV_LCP_LEN; - if (tmpRate == 0x82) - iwe.u.bitrate.value = 1 * 1000000; - else if (tmpRate == 0x84) - iwe.u.bitrate.value = 2 * 1000000; - else if (tmpRate == 0x8B) - iwe.u.bitrate.value = 5.5 * 1000000; - else if (tmpRate == 0x96) - iwe.u.bitrate.value = 11 * 1000000; - else - iwe.u.bitrate.value = (tmpRate/2) * 1000000; - - iwe.u.bitrate.disabled = 0; - current_val = iwe_stream_add_value(info, current_ev, - current_val, end_buf, &iwe, - IW_EV_PARAM_LEN); - - if((current_val-current_ev)>IW_EV_LCP_LEN) - current_ev = current_val; - else -#if WIRELESS_EXT >= 17 - return -E2BIG; -#else - break; -#endif - } - -#ifdef IWEVGENIE - //WPA IE - if (pAdapter->ScanTab.BssEntry[i].WpaIE.IELen > 0) - { - memset(&iwe, 0, sizeof(iwe)); - memset(&custom[0], 0, MAX_CUSTOM_LEN); - memcpy(custom, &(pAdapter->ScanTab.BssEntry[i].WpaIE.IE[0]), - pAdapter->ScanTab.BssEntry[i].WpaIE.IELen); - iwe.cmd = IWEVGENIE; - iwe.u.data.length = pAdapter->ScanTab.BssEntry[i].WpaIE.IELen; - current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, custom); - if (current_ev == previous_ev) -#if WIRELESS_EXT >= 17 - return -E2BIG; -#else - break; -#endif - } - - //WPA2 IE - if (pAdapter->ScanTab.BssEntry[i].RsnIE.IELen > 0) - { - memset(&iwe, 0, sizeof(iwe)); - memset(&custom[0], 0, MAX_CUSTOM_LEN); - memcpy(custom, &(pAdapter->ScanTab.BssEntry[i].RsnIE.IE[0]), - pAdapter->ScanTab.BssEntry[i].RsnIE.IELen); - iwe.cmd = IWEVGENIE; - iwe.u.data.length = pAdapter->ScanTab.BssEntry[i].RsnIE.IELen; - current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, custom); - if (current_ev == previous_ev) -#if WIRELESS_EXT >= 17 - return -E2BIG; -#else - break; -#endif - } -#else - //WPA IE - //================================ - if (pAdapter->ScanTab.BssEntry[i].WpaIE.IELen > 0) - { - NdisZeroMemory(&iwe, sizeof(iwe)); - memset(&custom[0], 0, MAX_CUSTOM_LEN); - iwe.cmd = IWEVCUSTOM; - iwe.u.data.length = (pAdapter->ScanTab.BssEntry[i].WpaIE.IELen * 2) + 7; - NdisMoveMemory(custom, "wpa_ie=", 7); - for (idx = 0; idx < pAdapter->ScanTab.BssEntry[i].WpaIE.IELen; idx++) - sprintf(custom, "%s%02x", custom, pAdapter->ScanTab.BssEntry[i].WpaIE.IE[idx]); - previous_ev = current_ev; - current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, custom); - if (current_ev == previous_ev) -#if WIRELESS_EXT >= 17 - return -E2BIG; -#else - break; -#endif - } - - //WPA2 IE - if (pAdapter->ScanTab.BssEntry[i].RsnIE.IELen > 0) - { - NdisZeroMemory(&iwe, sizeof(iwe)); - memset(&custom[0], 0, MAX_CUSTOM_LEN); - iwe.cmd = IWEVCUSTOM; - iwe.u.data.length = (pAdapter->ScanTab.BssEntry[i].RsnIE.IELen * 2) + 7; - NdisMoveMemory(custom, "rsn_ie=", 7); - for (idx = 0; idx < pAdapter->ScanTab.BssEntry[i].RsnIE.IELen; idx++) - sprintf(custom, "%s%02x", custom, pAdapter->ScanTab.BssEntry[i].RsnIE.IE[idx]); - previous_ev = current_ev; - current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, custom); - if (current_ev == previous_ev) -#if WIRELESS_EXT >= 17 - return -E2BIG; -#else - break; -#endif - } -#endif // IWEVGENIE // - } - - data->length = current_ev - extra; - pAdapter->StaCfg.bScanReqIsFromWebUI = FALSE; - DBGPRINT(RT_DEBUG_ERROR ,("===>rt_ioctl_giwscan. %d(%d) BSS returned, data->length = %d\n",i , pAdapter->ScanTab.BssNr, data->length)); - return 0; -} -#endif - -int rt_ioctl_siwessid(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *essid) -{ - PRTMP_ADAPTER pAdapter = dev->ml_priv; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - if (data->flags) - { - PCHAR pSsidString = NULL; - - // Includes null character. - if (data->length > (IW_ESSID_MAX_SIZE + 1)) - return -E2BIG; - - pSsidString = (CHAR *) kmalloc(MAX_LEN_OF_SSID+1, MEM_ALLOC_FLAG); - if (pSsidString) - { - NdisZeroMemory(pSsidString, MAX_LEN_OF_SSID+1); - NdisMoveMemory(pSsidString, essid, data->length); - if (Set_SSID_Proc(pAdapter, pSsidString) == FALSE) - return -EINVAL; - } - else - return -ENOMEM; - } - else - { - // ANY ssid - if (Set_SSID_Proc(pAdapter, "") == FALSE) - return -EINVAL; - } - return 0; -} - -int rt_ioctl_giwessid(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *essid) -{ - PRTMP_ADAPTER pAdapter = dev->ml_priv; - - data->flags = 1; - if (MONITOR_ON(pAdapter)) - { - data->length = 0; - return 0; - } - - if (OPSTATUS_TEST_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED)) - { - DBGPRINT(RT_DEBUG_TRACE ,("MediaState is connected\n")); - data->length = pAdapter->CommonCfg.SsidLen; - memcpy(essid, pAdapter->CommonCfg.Ssid, pAdapter->CommonCfg.SsidLen); - } -#ifdef RT2870 -#ifdef WPA_SUPPLICANT_SUPPORT - // Add for RT2870 - else if (pAdapter->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_DISABLE) - { - data->length = pAdapter->CommonCfg.SsidLen; - memcpy(essid, pAdapter->CommonCfg.Ssid, pAdapter->CommonCfg.SsidLen); - } -#endif // WPA_SUPPLICANT_SUPPORT // -#endif // RT2870 // - else - {//the ANY ssid was specified - data->length = 0; - DBGPRINT(RT_DEBUG_TRACE ,("MediaState is not connected, ess\n")); - } - - return 0; - -} - -int rt_ioctl_siwnickn(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *nickname) -{ - PRTMP_ADAPTER pAdapter = dev->ml_priv; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE ,("INFO::Network is down!\n")); - return -ENETDOWN; - } - - if (data->length > IW_ESSID_MAX_SIZE) - return -EINVAL; - - memset(pAdapter->nickname, 0, IW_ESSID_MAX_SIZE + 1); - memcpy(pAdapter->nickname, nickname, data->length); - - - return 0; -} - -int rt_ioctl_giwnickn(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *nickname) -{ - PRTMP_ADAPTER pAdapter = dev->ml_priv; - - if (data->length > strlen(pAdapter->nickname) + 1) - data->length = strlen(pAdapter->nickname) + 1; - if (data->length > 0) { - memcpy(nickname, pAdapter->nickname, data->length-1); - nickname[data->length-1] = '\0'; - } - return 0; -} - -int rt_ioctl_siwrts(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *rts, char *extra) -{ - PRTMP_ADAPTER pAdapter = dev->ml_priv; - u16 val; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - if (rts->disabled) - val = MAX_RTS_THRESHOLD; - else if (rts->value < 0 || rts->value > MAX_RTS_THRESHOLD) - return -EINVAL; - else if (rts->value == 0) - val = MAX_RTS_THRESHOLD; - else - val = rts->value; - - if (val != pAdapter->CommonCfg.RtsThreshold) - pAdapter->CommonCfg.RtsThreshold = val; - - return 0; -} - -int rt_ioctl_giwrts(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *rts, char *extra) -{ - PRTMP_ADAPTER pAdapter = dev->ml_priv; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - rts->value = pAdapter->CommonCfg.RtsThreshold; - rts->disabled = (rts->value == MAX_RTS_THRESHOLD); - rts->fixed = 1; - - return 0; -} - -int rt_ioctl_siwfrag(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *frag, char *extra) -{ - PRTMP_ADAPTER pAdapter = dev->ml_priv; - u16 val; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - if (frag->disabled) - val = MAX_FRAG_THRESHOLD; - else if (frag->value >= MIN_FRAG_THRESHOLD || frag->value <= MAX_FRAG_THRESHOLD) - val = __cpu_to_le16(frag->value & ~0x1); /* even numbers only */ - else if (frag->value == 0) - val = MAX_FRAG_THRESHOLD; - else - return -EINVAL; - - pAdapter->CommonCfg.FragmentThreshold = val; - return 0; -} - -int rt_ioctl_giwfrag(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *frag, char *extra) -{ - PRTMP_ADAPTER pAdapter = dev->ml_priv; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - frag->value = pAdapter->CommonCfg.FragmentThreshold; - frag->disabled = (frag->value == MAX_FRAG_THRESHOLD); - frag->fixed = 1; - - return 0; -} - -#define MAX_WEP_KEY_SIZE 13 -#define MIN_WEP_KEY_SIZE 5 -int rt_ioctl_siwencode(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *erq, char *extra) -{ - PRTMP_ADAPTER pAdapter = dev->ml_priv; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - if ((erq->length == 0) && - (erq->flags & IW_ENCODE_DISABLED)) - { - pAdapter->StaCfg.PairCipher = Ndis802_11WEPDisabled; - pAdapter->StaCfg.GroupCipher = Ndis802_11WEPDisabled; - pAdapter->StaCfg.WepStatus = Ndis802_11WEPDisabled; - pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; - goto done; - } - else if (erq->flags & IW_ENCODE_RESTRICTED || erq->flags & IW_ENCODE_OPEN) - { - //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; - STA_PORT_SECURED(pAdapter); - pAdapter->StaCfg.PairCipher = Ndis802_11WEPEnabled; - pAdapter->StaCfg.GroupCipher = Ndis802_11WEPEnabled; - pAdapter->StaCfg.WepStatus = Ndis802_11WEPEnabled; - pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; - if (erq->flags & IW_ENCODE_RESTRICTED) - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeShared; - else - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; - } - - if (erq->length > 0) - { - int keyIdx = (erq->flags & IW_ENCODE_INDEX) - 1; - /* Check the size of the key */ - if (erq->length > MAX_WEP_KEY_SIZE) - { - return -EINVAL; - } - /* Check key index */ - if ((keyIdx < 0) || (keyIdx >= NR_WEP_KEYS)) - { - DBGPRINT(RT_DEBUG_TRACE ,("==>rt_ioctl_siwencode::Wrong keyIdx=%d! Using default key instead (%d)\n", - keyIdx, pAdapter->StaCfg.DefaultKeyId)); - - //Using default key - keyIdx = pAdapter->StaCfg.DefaultKeyId; - } - else - { - pAdapter->StaCfg.DefaultKeyId=keyIdx; - } - - NdisZeroMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, 16); - - if (erq->length == MAX_WEP_KEY_SIZE) - { - pAdapter->SharedKey[BSS0][keyIdx].KeyLen = MAX_WEP_KEY_SIZE; - pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CIPHER_WEP128; - } - else if (erq->length == MIN_WEP_KEY_SIZE) - { - pAdapter->SharedKey[BSS0][keyIdx].KeyLen = MIN_WEP_KEY_SIZE; - pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CIPHER_WEP64; - } - else - /* Disable the key */ - pAdapter->SharedKey[BSS0][keyIdx].KeyLen = 0; - - /* Check if the key is not marked as invalid */ - if(!(erq->flags & IW_ENCODE_NOKEY)) - { - /* Copy the key in the driver */ - NdisMoveMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, extra, erq->length); - } - } - else - { - /* Do we want to just set the transmit key index ? */ - int index = (erq->flags & IW_ENCODE_INDEX) - 1; - if ((index >= 0) && (index < 4)) - { - pAdapter->StaCfg.DefaultKeyId = index; - } - else - /* Don't complain if only change the mode */ - if(!erq->flags & IW_ENCODE_MODE) - { - return -EINVAL; - } - } - -done: - DBGPRINT(RT_DEBUG_TRACE ,("==>rt_ioctl_siwencode::erq->flags=%x\n",erq->flags)); - DBGPRINT(RT_DEBUG_TRACE ,("==>rt_ioctl_siwencode::AuthMode=%x\n",pAdapter->StaCfg.AuthMode)); - DBGPRINT(RT_DEBUG_TRACE ,("==>rt_ioctl_siwencode::DefaultKeyId=%x, KeyLen = %d\n",pAdapter->StaCfg.DefaultKeyId , pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen)); - DBGPRINT(RT_DEBUG_TRACE ,("==>rt_ioctl_siwencode::WepStatus=%x\n",pAdapter->StaCfg.WepStatus)); - return 0; -} - -int -rt_ioctl_giwencode(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *erq, char *key) -{ - PRTMP_ADAPTER pAdapter = dev->ml_priv; - int kid; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - kid = erq->flags & IW_ENCODE_INDEX; - DBGPRINT(RT_DEBUG_TRACE, ("===>rt_ioctl_giwencode %d\n", erq->flags & IW_ENCODE_INDEX)); - - if (pAdapter->StaCfg.WepStatus == Ndis802_11WEPDisabled) - { - erq->length = 0; - erq->flags = IW_ENCODE_DISABLED; - } - else if ((kid > 0) && (kid <=4)) - { - // copy wep key - erq->flags = kid ; /* NB: base 1 */ - if (erq->length > pAdapter->SharedKey[BSS0][kid-1].KeyLen) - erq->length = pAdapter->SharedKey[BSS0][kid-1].KeyLen; - memcpy(key, pAdapter->SharedKey[BSS0][kid-1].Key, erq->length); - //if ((kid == pAdapter->PortCfg.DefaultKeyId)) - //erq->flags |= IW_ENCODE_ENABLED; /* XXX */ - if (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeShared) - erq->flags |= IW_ENCODE_RESTRICTED; /* XXX */ - else - erq->flags |= IW_ENCODE_OPEN; /* XXX */ - - } - else if (kid == 0) - { - if (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeShared) - erq->flags |= IW_ENCODE_RESTRICTED; /* XXX */ - else - erq->flags |= IW_ENCODE_OPEN; /* XXX */ - erq->length = pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen; - memcpy(key, pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].Key, erq->length); - // copy default key ID - if (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeShared) - erq->flags |= IW_ENCODE_RESTRICTED; /* XXX */ - else - erq->flags |= IW_ENCODE_OPEN; /* XXX */ - erq->flags = pAdapter->StaCfg.DefaultKeyId + 1; /* NB: base 1 */ - erq->flags |= IW_ENCODE_ENABLED; /* XXX */ - } - - return 0; - -} - -static int -rt_ioctl_setparam(struct net_device *dev, struct iw_request_info *info, - void *w, char *extra) -{ - VIRTUAL_ADAPTER *pVirtualAd = NULL; - PRTMP_ADAPTER pAdapter; - POS_COOKIE pObj; - char *this_char = extra; - char *value; - int Status=0; - - if (dev->priv_flags == INT_MAIN) - { - pAdapter = dev->ml_priv; - } - else - { - pVirtualAd = dev->ml_priv; - pAdapter = pVirtualAd->RtmpDev->ml_priv; - } - pObj = (POS_COOKIE) pAdapter->OS_Cookie; - - if (pAdapter == NULL) - { - /* if 1st open fail, pAd will be free; - So the net_dev->ml_priv will be NULL in 2rd open */ - return -ENETDOWN; - } - - { - pObj->ioctl_if_type = INT_MAIN; - pObj->ioctl_if = MAIN_MBSSID; - } - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - if (!*this_char) - return -EINVAL; - - if ((value = rtstrchr(this_char, '=')) != NULL) - *value++ = 0; - - if (!value) - return -EINVAL; - - // reject setting nothing besides ANY ssid(ssidLen=0) - if (!*value && (strcmp(this_char, "SSID") != 0)) - return -EINVAL; - - for (PRTMP_PRIVATE_SET_PROC = RTMP_PRIVATE_SUPPORT_PROC; PRTMP_PRIVATE_SET_PROC->name; PRTMP_PRIVATE_SET_PROC++) - { - if (strcmp(this_char, PRTMP_PRIVATE_SET_PROC->name) == 0) - { - if(!PRTMP_PRIVATE_SET_PROC->set_proc(pAdapter, value)) - { //FALSE:Set private failed then return Invalid argument - Status = -EINVAL; - } - break; //Exit for loop. - } - } - - if(PRTMP_PRIVATE_SET_PROC->name == NULL) - { //Not found argument - Status = -EINVAL; - DBGPRINT(RT_DEBUG_TRACE, ("===>rt_ioctl_setparam:: (iwpriv) Not Support Set Command [%s=%s]\n", this_char, value)); - } - - return Status; -} - - -static int -rt_private_get_statistics(struct net_device *dev, struct iw_request_info *info, - struct iw_point *wrq, char *extra) -{ - INT Status = 0; - PRTMP_ADAPTER pAd = dev->ml_priv; - - if (extra == NULL) - { - wrq->length = 0; - return -EIO; - } - - memset(extra, 0x00, IW_PRIV_SIZE_MASK); - sprintf(extra, "\n\n"); - -#ifdef RALINK_ATE - if (ATE_ON(pAd)) - { - sprintf(extra+strlen(extra), "Tx success = %ld\n", (ULONG)pAd->ate.TxDoneCount); - //sprintf(extra+strlen(extra), "Tx success without retry = %ld\n", (ULONG)pAd->ate.TxDoneCount); - } - else -#endif // RALINK_ATE // - { - sprintf(extra+strlen(extra), "Tx success = %ld\n", (ULONG)pAd->WlanCounters.TransmittedFragmentCount.QuadPart); - sprintf(extra+strlen(extra), "Tx success without retry = %ld\n", (ULONG)pAd->WlanCounters.TransmittedFragmentCount.QuadPart - (ULONG)pAd->WlanCounters.RetryCount.QuadPart); - } - sprintf(extra+strlen(extra), "Tx success after retry = %ld\n", (ULONG)pAd->WlanCounters.RetryCount.QuadPart); - sprintf(extra+strlen(extra), "Tx fail to Rcv ACK after retry = %ld\n", (ULONG)pAd->WlanCounters.FailedCount.QuadPart); - sprintf(extra+strlen(extra), "RTS Success Rcv CTS = %ld\n", (ULONG)pAd->WlanCounters.RTSSuccessCount.QuadPart); - sprintf(extra+strlen(extra), "RTS Fail Rcv CTS = %ld\n", (ULONG)pAd->WlanCounters.RTSFailureCount.QuadPart); - - sprintf(extra+strlen(extra), "Rx success = %ld\n", (ULONG)pAd->WlanCounters.ReceivedFragmentCount.QuadPart); - sprintf(extra+strlen(extra), "Rx with CRC = %ld\n", (ULONG)pAd->WlanCounters.FCSErrorCount.QuadPart); - sprintf(extra+strlen(extra), "Rx drop due to out of resource = %ld\n", (ULONG)pAd->Counters8023.RxNoBuffer); - sprintf(extra+strlen(extra), "Rx duplicate frame = %ld\n", (ULONG)pAd->WlanCounters.FrameDuplicateCount.QuadPart); - - sprintf(extra+strlen(extra), "False CCA (one second) = %ld\n", (ULONG)pAd->RalinkCounters.OneSecFalseCCACnt); -#ifdef RALINK_ATE - if (ATE_ON(pAd)) - { - if (pAd->ate.RxAntennaSel == 0) - { - sprintf(extra+strlen(extra), "RSSI-A = %ld\n", (LONG)(pAd->ate.LastRssi0 - pAd->BbpRssiToDbmDelta)); - sprintf(extra+strlen(extra), "RSSI-B (if available) = %ld\n", (LONG)(pAd->ate.LastRssi1 - pAd->BbpRssiToDbmDelta)); - sprintf(extra+strlen(extra), "RSSI-C (if available) = %ld\n\n", (LONG)(pAd->ate.LastRssi2 - pAd->BbpRssiToDbmDelta)); - } - else - { - sprintf(extra+strlen(extra), "RSSI = %ld\n", (LONG)(pAd->ate.LastRssi0 - pAd->BbpRssiToDbmDelta)); - } - } - else -#endif // RALINK_ATE // - { - sprintf(extra+strlen(extra), "RSSI-A = %ld\n", (LONG)(pAd->StaCfg.RssiSample.LastRssi0 - pAd->BbpRssiToDbmDelta)); - sprintf(extra+strlen(extra), "RSSI-B (if available) = %ld\n", (LONG)(pAd->StaCfg.RssiSample.LastRssi1 - pAd->BbpRssiToDbmDelta)); - sprintf(extra+strlen(extra), "RSSI-C (if available) = %ld\n\n", (LONG)(pAd->StaCfg.RssiSample.LastRssi2 - pAd->BbpRssiToDbmDelta)); - } -#ifdef WPA_SUPPLICANT_SUPPORT - sprintf(extra+strlen(extra), "WpaSupplicantUP = %d\n\n", pAd->StaCfg.WpaSupplicantUP); -#endif // WPA_SUPPLICANT_SUPPORT // - - - wrq->length = strlen(extra) + 1; // 1: size of '\0' - DBGPRINT(RT_DEBUG_TRACE, ("<== rt_private_get_statistics, wrq->length = %d\n", wrq->length)); - - return Status; -} - -#ifdef DOT11_N_SUPPORT -void getBaInfo( - IN PRTMP_ADAPTER pAd, - IN PUCHAR pOutBuf) -{ - INT i, j; - BA_ORI_ENTRY *pOriBAEntry; - BA_REC_ENTRY *pRecBAEntry; - - for (i=0; iMacTab.Content[i]; - if (((pEntry->ValidAsCLI || pEntry->ValidAsApCli) && (pEntry->Sst == SST_ASSOC)) - || (pEntry->ValidAsWDS) || (pEntry->ValidAsMesh)) - { - sprintf(pOutBuf, "%s\n%02X:%02X:%02X:%02X:%02X:%02X (Aid = %d) (AP) -\n", - pOutBuf, - pEntry->Addr[0], pEntry->Addr[1], pEntry->Addr[2], - pEntry->Addr[3], pEntry->Addr[4], pEntry->Addr[5], pEntry->Aid); - - sprintf(pOutBuf, "%s[Recipient]\n", pOutBuf); - for (j=0; j < NUM_OF_TID; j++) - { - if (pEntry->BARecWcidArray[j] != 0) - { - pRecBAEntry =&pAd->BATable.BARecEntry[pEntry->BARecWcidArray[j]]; - sprintf(pOutBuf, "%sTID=%d, BAWinSize=%d, LastIndSeq=%d, ReorderingPkts=%d\n", pOutBuf, j, pRecBAEntry->BAWinSize, pRecBAEntry->LastIndSeq, pRecBAEntry->list.qlen); - } - } - sprintf(pOutBuf, "%s\n", pOutBuf); - - sprintf(pOutBuf, "%s[Originator]\n", pOutBuf); - for (j=0; j < NUM_OF_TID; j++) - { - if (pEntry->BAOriWcidArray[j] != 0) - { - pOriBAEntry =&pAd->BATable.BAOriEntry[pEntry->BAOriWcidArray[j]]; - sprintf(pOutBuf, "%sTID=%d, BAWinSize=%d, StartSeq=%d, CurTxSeq=%d\n", pOutBuf, j, pOriBAEntry->BAWinSize, pOriBAEntry->Sequence, pEntry->TxSeq[j]); - } - } - sprintf(pOutBuf, "%s\n\n", pOutBuf); - } - if (strlen(pOutBuf) > (IW_PRIV_SIZE_MASK - 30)) - break; - } - - return; -} -#endif // DOT11_N_SUPPORT // - -static int -rt_private_show(struct net_device *dev, struct iw_request_info *info, - struct iw_point *wrq, char *extra) -{ - INT Status = 0; - VIRTUAL_ADAPTER *pVirtualAd = NULL; - PRTMP_ADAPTER pAd; - POS_COOKIE pObj; - u32 subcmd = wrq->flags; - - if (dev->priv_flags == INT_MAIN) - pAd = dev->ml_priv; - else - { - pVirtualAd = dev->ml_priv; - pAd = pVirtualAd->RtmpDev->ml_priv; - } - pObj = (POS_COOKIE) pAd->OS_Cookie; - - if (pAd == NULL) - { - /* if 1st open fail, pAd will be free; - So the net_dev->ml_priv will be NULL in 2rd open */ - return -ENETDOWN; - } - - if (extra == NULL) - { - wrq->length = 0; - return -EIO; - } - memset(extra, 0x00, IW_PRIV_SIZE_MASK); - - { - pObj->ioctl_if_type = INT_MAIN; - pObj->ioctl_if = MAIN_MBSSID; - } - - switch(subcmd) - { - - case SHOW_CONN_STATUS: - if (MONITOR_ON(pAd)) - { -#ifdef DOT11_N_SUPPORT - if (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED && - pAd->CommonCfg.RegTransmitSetting.field.BW) - sprintf(extra, "Monitor Mode(CentralChannel %d)\n", pAd->CommonCfg.CentralChannel); - else -#endif // DOT11_N_SUPPORT // - sprintf(extra, "Monitor Mode(Channel %d)\n", pAd->CommonCfg.Channel); - } - else - { - if (pAd->IndicateMediaState == NdisMediaStateConnected) - { - if (INFRA_ON(pAd)) - { - sprintf(extra, "Connected(AP: %s[%02X:%02X:%02X:%02X:%02X:%02X])\n", - pAd->CommonCfg.Ssid, - pAd->CommonCfg.Bssid[0], - pAd->CommonCfg.Bssid[1], - pAd->CommonCfg.Bssid[2], - pAd->CommonCfg.Bssid[3], - pAd->CommonCfg.Bssid[4], - pAd->CommonCfg.Bssid[5]); - DBGPRINT(RT_DEBUG_TRACE ,("Ssid=%s ,Ssidlen = %d\n",pAd->CommonCfg.Ssid, pAd->CommonCfg.SsidLen)); - } - else if (ADHOC_ON(pAd)) - sprintf(extra, "Connected\n"); - } - else - { - sprintf(extra, "Disconnected\n"); - DBGPRINT(RT_DEBUG_TRACE ,("ConnStatus is not connected\n")); - } - } - wrq->length = strlen(extra) + 1; // 1: size of '\0' - break; - case SHOW_DRVIER_VERION: - sprintf(extra, "Driver version-%s, %s %s\n", STA_DRIVER_VERSION, __DATE__, __TIME__ ); - wrq->length = strlen(extra) + 1; // 1: size of '\0' - break; -#ifdef DOT11_N_SUPPORT - case SHOW_BA_INFO: - getBaInfo(pAd, extra); - wrq->length = strlen(extra) + 1; // 1: size of '\0' - break; -#endif // DOT11_N_SUPPORT // - case SHOW_DESC_INFO: - { - Show_DescInfo_Proc(pAd, NULL); - wrq->length = 0; // 1: size of '\0' - } - break; - case RAIO_OFF: - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) - { - sprintf(extra, "Scanning\n"); - wrq->length = strlen(extra) + 1; // 1: size of '\0' - break; - } - pAd->StaCfg.bSwRadio = FALSE; - if (pAd->StaCfg.bRadio != (pAd->StaCfg.bHwRadio && pAd->StaCfg.bSwRadio)) - { - pAd->StaCfg.bRadio = (pAd->StaCfg.bHwRadio && pAd->StaCfg.bSwRadio); - if (pAd->StaCfg.bRadio == FALSE) - { - MlmeRadioOff(pAd); - // Update extra information - pAd->ExtraInfo = SW_RADIO_OFF; - } - } - sprintf(extra, "Radio Off\n"); - wrq->length = strlen(extra) + 1; // 1: size of '\0' - break; - case RAIO_ON: - if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) - { - sprintf(extra, "Scanning\n"); - wrq->length = strlen(extra) + 1; // 1: size of '\0' - break; - } - pAd->StaCfg.bSwRadio = TRUE; - //if (pAd->StaCfg.bRadio != (pAd->StaCfg.bHwRadio && pAd->StaCfg.bSwRadio)) - { - pAd->StaCfg.bRadio = (pAd->StaCfg.bHwRadio && pAd->StaCfg.bSwRadio); - if (pAd->StaCfg.bRadio == TRUE) - { - MlmeRadioOn(pAd); - // Update extra information - pAd->ExtraInfo = EXTRA_INFO_CLEAR; - } - } - sprintf(extra, "Radio On\n"); - wrq->length = strlen(extra) + 1; // 1: size of '\0' - break; - - -#ifdef QOS_DLS_SUPPORT - case SHOW_DLS_ENTRY_INFO: - { - Set_DlsEntryInfo_Display_Proc(pAd, NULL); - wrq->length = 0; // 1: size of '\0' - } - break; -#endif // QOS_DLS_SUPPORT // - - case SHOW_CFG_VALUE: - { - Status = RTMPShowCfgValue(pAd, wrq->pointer, extra); - if (Status == 0) - wrq->length = strlen(extra) + 1; // 1: size of '\0' - } - break; - default: - DBGPRINT(RT_DEBUG_TRACE, ("%s - unknow subcmd = %d\n", __FUNCTION__, subcmd)); - break; - } - - return Status; -} - -#ifdef SIOCSIWMLME -int rt_ioctl_siwmlme(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - PRTMP_ADAPTER pAd = dev->ml_priv; - struct iw_mlme *pMlme = (struct iw_mlme *)wrqu->data.pointer; - MLME_QUEUE_ELEM MsgElem; - MLME_DISASSOC_REQ_STRUCT DisAssocReq; - MLME_DEAUTH_REQ_STRUCT DeAuthReq; - - DBGPRINT(RT_DEBUG_TRACE, ("====> %s\n", __FUNCTION__)); - - if (pMlme == NULL) - return -EINVAL; - - switch(pMlme->cmd) - { -#ifdef IW_MLME_DEAUTH - case IW_MLME_DEAUTH: - DBGPRINT(RT_DEBUG_TRACE, ("====> %s - IW_MLME_DEAUTH\n", __FUNCTION__)); - COPY_MAC_ADDR(DeAuthReq.Addr, pAd->CommonCfg.Bssid); - DeAuthReq.Reason = pMlme->reason_code; - MsgElem.MsgLen = sizeof(MLME_DEAUTH_REQ_STRUCT); - NdisMoveMemory(MsgElem.Msg, &DeAuthReq, sizeof(MLME_DEAUTH_REQ_STRUCT)); - MlmeDeauthReqAction(pAd, &MsgElem); - if (INFRA_ON(pAd)) - { - LinkDown(pAd, FALSE); - pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; - } - break; -#endif // IW_MLME_DEAUTH // -#ifdef IW_MLME_DISASSOC - case IW_MLME_DISASSOC: - DBGPRINT(RT_DEBUG_TRACE, ("====> %s - IW_MLME_DISASSOC\n", __FUNCTION__)); - COPY_MAC_ADDR(DisAssocReq.Addr, pAd->CommonCfg.Bssid); - DisAssocReq.Reason = pMlme->reason_code; - - MsgElem.Machine = ASSOC_STATE_MACHINE; - MsgElem.MsgType = MT2_MLME_DISASSOC_REQ; - MsgElem.MsgLen = sizeof(MLME_DISASSOC_REQ_STRUCT); - NdisMoveMemory(MsgElem.Msg, &DisAssocReq, sizeof(MLME_DISASSOC_REQ_STRUCT)); - - pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_DISASSOC; - MlmeDisassocReqAction(pAd, &MsgElem); - break; -#endif // IW_MLME_DISASSOC // - default: - DBGPRINT(RT_DEBUG_TRACE, ("====> %s - Unknow Command\n", __FUNCTION__)); - break; - } - - return 0; -} -#endif // SIOCSIWMLME // - -#if WIRELESS_EXT > 17 -int rt_ioctl_siwauth(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - PRTMP_ADAPTER pAdapter = dev->ml_priv; - struct iw_param *param = &wrqu->param; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - switch (param->flags & IW_AUTH_INDEX) { - case IW_AUTH_WPA_VERSION: - if (param->value == IW_AUTH_WPA_VERSION_WPA) - { - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPAPSK; - if (pAdapter->StaCfg.BssType == BSS_ADHOC) - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPANone; - } - else if (param->value == IW_AUTH_WPA_VERSION_WPA2) - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA2PSK; - - DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_VERSION - param->value = %d!\n", __FUNCTION__, param->value)); - break; - case IW_AUTH_CIPHER_PAIRWISE: - if (param->value == IW_AUTH_CIPHER_NONE) - { - pAdapter->StaCfg.WepStatus = Ndis802_11WEPDisabled; - pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; - pAdapter->StaCfg.PairCipher = Ndis802_11WEPDisabled; - } - else if (param->value == IW_AUTH_CIPHER_WEP40 || - param->value == IW_AUTH_CIPHER_WEP104) - { - pAdapter->StaCfg.WepStatus = Ndis802_11WEPEnabled; - pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; - pAdapter->StaCfg.PairCipher = Ndis802_11WEPEnabled; -#ifdef WPA_SUPPLICANT_SUPPORT - pAdapter->StaCfg.IEEE8021X = FALSE; -#endif // WPA_SUPPLICANT_SUPPORT // - } - else if (param->value == IW_AUTH_CIPHER_TKIP) - { - pAdapter->StaCfg.WepStatus = Ndis802_11Encryption2Enabled; - pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; - pAdapter->StaCfg.PairCipher = Ndis802_11Encryption2Enabled; - } - else if (param->value == IW_AUTH_CIPHER_CCMP) - { - pAdapter->StaCfg.WepStatus = Ndis802_11Encryption3Enabled; - pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; - pAdapter->StaCfg.PairCipher = Ndis802_11Encryption3Enabled; - } - DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_CIPHER_PAIRWISE - param->value = %d!\n", __FUNCTION__, param->value)); - break; - case IW_AUTH_CIPHER_GROUP: - if (param->value == IW_AUTH_CIPHER_NONE) - { - pAdapter->StaCfg.GroupCipher = Ndis802_11WEPDisabled; - } - else if (param->value == IW_AUTH_CIPHER_WEP40 || - param->value == IW_AUTH_CIPHER_WEP104) - { - pAdapter->StaCfg.GroupCipher = Ndis802_11WEPEnabled; - } - else if (param->value == IW_AUTH_CIPHER_TKIP) - { - pAdapter->StaCfg.GroupCipher = Ndis802_11Encryption2Enabled; - } - else if (param->value == IW_AUTH_CIPHER_CCMP) - { - pAdapter->StaCfg.GroupCipher = Ndis802_11Encryption3Enabled; - } - DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_CIPHER_GROUP - param->value = %d!\n", __FUNCTION__, param->value)); - break; - case IW_AUTH_KEY_MGMT: - if (param->value == IW_AUTH_KEY_MGMT_802_1X) - { - if (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) - { - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA; -#ifdef WPA_SUPPLICANT_SUPPORT - pAdapter->StaCfg.IEEE8021X = FALSE; -#endif // WPA_SUPPLICANT_SUPPORT // - } - else if (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) - { - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA2; -#ifdef WPA_SUPPLICANT_SUPPORT - pAdapter->StaCfg.IEEE8021X = FALSE; -#endif // WPA_SUPPLICANT_SUPPORT // - } -#ifdef WPA_SUPPLICANT_SUPPORT - else - // WEP 1x - pAdapter->StaCfg.IEEE8021X = TRUE; -#endif // WPA_SUPPLICANT_SUPPORT // - } - else if (param->value == 0) - { - //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; - STA_PORT_SECURED(pAdapter); - } - DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_KEY_MGMT - param->value = %d!\n", __FUNCTION__, param->value)); - break; - case IW_AUTH_RX_UNENCRYPTED_EAPOL: - break; - case IW_AUTH_PRIVACY_INVOKED: - /*if (param->value == 0) - { - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; - pAdapter->StaCfg.WepStatus = Ndis802_11WEPDisabled; - pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; - pAdapter->StaCfg.PairCipher = Ndis802_11WEPDisabled; - pAdapter->StaCfg.GroupCipher = Ndis802_11WEPDisabled; - }*/ - DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_PRIVACY_INVOKED - param->value = %d!\n", __FUNCTION__, param->value)); - break; - case IW_AUTH_DROP_UNENCRYPTED: - if (param->value != 0) - pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; - else - { - //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; - STA_PORT_SECURED(pAdapter); - } - DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_VERSION - param->value = %d!\n", __FUNCTION__, param->value)); - break; - case IW_AUTH_80211_AUTH_ALG: - if (param->value & IW_AUTH_ALG_SHARED_KEY) - { - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeShared; - } - else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) - { - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; - } - else - return -EINVAL; - DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_80211_AUTH_ALG - param->value = %d!\n", __FUNCTION__, param->value)); - break; - case IW_AUTH_WPA_ENABLED: - DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_ENABLED - Driver supports WPA!(param->value = %d)\n", __FUNCTION__, param->value)); - break; - default: - return -EOPNOTSUPP; -} - - return 0; -} - -int rt_ioctl_giwauth(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - PRTMP_ADAPTER pAdapter = dev->ml_priv; - struct iw_param *param = &wrqu->param; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - switch (param->flags & IW_AUTH_INDEX) { - case IW_AUTH_DROP_UNENCRYPTED: - param->value = (pAdapter->StaCfg.WepStatus == Ndis802_11WEPDisabled) ? 0 : 1; - break; - - case IW_AUTH_80211_AUTH_ALG: - param->value = (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeShared) ? IW_AUTH_ALG_SHARED_KEY : IW_AUTH_ALG_OPEN_SYSTEM; - break; - - case IW_AUTH_WPA_ENABLED: - param->value = (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ? 1 : 0; - break; - - default: - return -EOPNOTSUPP; - } - DBGPRINT(RT_DEBUG_TRACE, ("rt_ioctl_giwauth::param->value = %d!\n", param->value)); - return 0; -} - -void fnSetCipherKey( - IN PRTMP_ADAPTER pAdapter, - IN INT keyIdx, - IN UCHAR CipherAlg, - IN BOOLEAN bGTK, - IN struct iw_encode_ext *ext) -{ - NdisZeroMemory(&pAdapter->SharedKey[BSS0][keyIdx], sizeof(CIPHER_KEY)); - pAdapter->SharedKey[BSS0][keyIdx].KeyLen = LEN_TKIP_EK; - NdisMoveMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, ext->key, LEN_TKIP_EK); - NdisMoveMemory(pAdapter->SharedKey[BSS0][keyIdx].TxMic, ext->key + LEN_TKIP_EK, LEN_TKIP_TXMICK); - NdisMoveMemory(pAdapter->SharedKey[BSS0][keyIdx].RxMic, ext->key + LEN_TKIP_EK + LEN_TKIP_TXMICK, LEN_TKIP_RXMICK); - pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CipherAlg; - - // Update group key information to ASIC Shared Key Table - AsicAddSharedKeyEntry(pAdapter, - BSS0, - keyIdx, - pAdapter->SharedKey[BSS0][keyIdx].CipherAlg, - pAdapter->SharedKey[BSS0][keyIdx].Key, - pAdapter->SharedKey[BSS0][keyIdx].TxMic, - pAdapter->SharedKey[BSS0][keyIdx].RxMic); - - if (bGTK) - // Update ASIC WCID attribute table and IVEIV table - RTMPAddWcidAttributeEntry(pAdapter, - BSS0, - keyIdx, - pAdapter->SharedKey[BSS0][keyIdx].CipherAlg, - NULL); - else - // Update ASIC WCID attribute table and IVEIV table - RTMPAddWcidAttributeEntry(pAdapter, - BSS0, - keyIdx, - pAdapter->SharedKey[BSS0][keyIdx].CipherAlg, - &pAdapter->MacTab.Content[BSSID_WCID]); -} - -int rt_ioctl_siwencodeext(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) - { - PRTMP_ADAPTER pAdapter = dev->ml_priv; - struct iw_point *encoding = &wrqu->encoding; - struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; - int keyIdx, alg = ext->alg; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - if (encoding->flags & IW_ENCODE_DISABLED) - { - keyIdx = (encoding->flags & IW_ENCODE_INDEX) - 1; - // set BSSID wcid entry of the Pair-wise Key table as no-security mode - AsicRemovePairwiseKeyEntry(pAdapter, BSS0, BSSID_WCID); - pAdapter->SharedKey[BSS0][keyIdx].KeyLen = 0; - pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CIPHER_NONE; - AsicRemoveSharedKeyEntry(pAdapter, 0, (UCHAR)keyIdx); - NdisZeroMemory(&pAdapter->SharedKey[BSS0][keyIdx], sizeof(CIPHER_KEY)); - DBGPRINT(RT_DEBUG_TRACE, ("%s::Remove all keys!(encoding->flags = %x)\n", __FUNCTION__, encoding->flags)); - } - else - { - // Get Key Index and convet to our own defined key index - keyIdx = (encoding->flags & IW_ENCODE_INDEX) - 1; - if((keyIdx < 0) || (keyIdx >= NR_WEP_KEYS)) - return -EINVAL; - - if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) - { - pAdapter->StaCfg.DefaultKeyId = keyIdx; - DBGPRINT(RT_DEBUG_TRACE, ("%s::DefaultKeyId = %d\n", __FUNCTION__, pAdapter->StaCfg.DefaultKeyId)); - } - - switch (alg) { - case IW_ENCODE_ALG_NONE: - DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_NONE\n", __FUNCTION__)); - break; - case IW_ENCODE_ALG_WEP: - DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_WEP - ext->key_len = %d, keyIdx = %d\n", __FUNCTION__, ext->key_len, keyIdx)); - if (ext->key_len == MAX_WEP_KEY_SIZE) - { - pAdapter->SharedKey[BSS0][keyIdx].KeyLen = MAX_WEP_KEY_SIZE; - pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CIPHER_WEP128; - } - else if (ext->key_len == MIN_WEP_KEY_SIZE) - { - pAdapter->SharedKey[BSS0][keyIdx].KeyLen = MIN_WEP_KEY_SIZE; - pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CIPHER_WEP64; - } - else - return -EINVAL; - - NdisZeroMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, 16); - NdisMoveMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, ext->key, ext->key_len); - break; - case IW_ENCODE_ALG_TKIP: - DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_TKIP - keyIdx = %d, ext->key_len = %d\n", __FUNCTION__, keyIdx, ext->key_len)); - if (ext->key_len == 32) - { - if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) - { - fnSetCipherKey(pAdapter, keyIdx, CIPHER_TKIP, FALSE, ext); - if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA2) - { - //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; - STA_PORT_SECURED(pAdapter); - } - } - else if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) - { - fnSetCipherKey(pAdapter, keyIdx, CIPHER_TKIP, TRUE, ext); - - // set 802.1x port control - //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; - STA_PORT_SECURED(pAdapter); - } - } - else - return -EINVAL; - break; - case IW_ENCODE_ALG_CCMP: - if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) - { - fnSetCipherKey(pAdapter, keyIdx, CIPHER_AES, FALSE, ext); - if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA2) - //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; - STA_PORT_SECURED(pAdapter); - } - else if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) - { - fnSetCipherKey(pAdapter, keyIdx, CIPHER_AES, TRUE, ext); - - // set 802.1x port control - //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; - STA_PORT_SECURED(pAdapter); - } - break; - default: - return -EINVAL; - } - } - - return 0; -} - -int -rt_ioctl_giwencodeext(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - PRTMP_ADAPTER pAd = dev->ml_priv; - PCHAR pKey = NULL; - struct iw_point *encoding = &wrqu->encoding; - struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; - int idx, max_key_len; - - DBGPRINT(RT_DEBUG_TRACE ,("===> rt_ioctl_giwencodeext\n")); - - max_key_len = encoding->length - sizeof(*ext); - if (max_key_len < 0) - return -EINVAL; - - idx = encoding->flags & IW_ENCODE_INDEX; - if (idx) - { - if (idx < 1 || idx > 4) - return -EINVAL; - idx--; - - if ((pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) || - (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled)) - { - if (idx != pAd->StaCfg.DefaultKeyId) - { - ext->key_len = 0; - return 0; - } - } - } - else - idx = pAd->StaCfg.DefaultKeyId; - - encoding->flags = idx + 1; - memset(ext, 0, sizeof(*ext)); - - ext->key_len = 0; - switch(pAd->StaCfg.WepStatus) { - case Ndis802_11WEPDisabled: - ext->alg = IW_ENCODE_ALG_NONE; - encoding->flags |= IW_ENCODE_DISABLED; - break; - case Ndis802_11WEPEnabled: - ext->alg = IW_ENCODE_ALG_WEP; - if (pAd->SharedKey[BSS0][idx].KeyLen > max_key_len) - return -E2BIG; - else - { - ext->key_len = pAd->SharedKey[BSS0][idx].KeyLen; - pKey = &(pAd->SharedKey[BSS0][idx].Key[0]); - } - break; - case Ndis802_11Encryption2Enabled: - case Ndis802_11Encryption3Enabled: - if (pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) - ext->alg = IW_ENCODE_ALG_TKIP; - else - ext->alg = IW_ENCODE_ALG_CCMP; - - if (max_key_len < 32) - return -E2BIG; - else - { - ext->key_len = 32; - pKey = &pAd->StaCfg.PMK[0]; - } - break; - default: - return -EINVAL; - } - - if (ext->key_len && pKey) - { - encoding->flags |= IW_ENCODE_ENABLED; - memcpy(ext->key, pKey, ext->key_len); - } - - return 0; -} - -#ifdef SIOCSIWGENIE -int rt_ioctl_siwgenie(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - PRTMP_ADAPTER pAd = dev->ml_priv; - - if (wrqu->data.length > MAX_LEN_OF_RSNIE || - (wrqu->data.length && extra == NULL)) - return -EINVAL; - - if (wrqu->data.length) - { - pAd->StaCfg.RSNIE_Len = wrqu->data.length; - NdisMoveMemory(&pAd->StaCfg.RSN_IE[0], extra, pAd->StaCfg.RSNIE_Len); - } - else - { - pAd->StaCfg.RSNIE_Len = 0; - NdisZeroMemory(&pAd->StaCfg.RSN_IE[0], MAX_LEN_OF_RSNIE); - } - - return 0; -} -#endif // SIOCSIWGENIE // - -int rt_ioctl_giwgenie(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - PRTMP_ADAPTER pAd = dev->ml_priv; - - if ((pAd->StaCfg.RSNIE_Len == 0) || - (pAd->StaCfg.AuthMode < Ndis802_11AuthModeWPA)) - { - wrqu->data.length = 0; - return 0; - } - -#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT -#ifdef SIOCSIWGENIE - if (pAd->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_ENABLE) - { - if (wrqu->data.length < pAd->StaCfg.RSNIE_Len) - return -E2BIG; - - wrqu->data.length = pAd->StaCfg.RSNIE_Len; - memcpy(extra, &pAd->StaCfg.RSN_IE[0], pAd->StaCfg.RSNIE_Len); - } - else -#endif // SIOCSIWGENIE // -#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // - { - UCHAR RSNIe = IE_WPA; - - if (wrqu->data.length < (pAd->StaCfg.RSNIE_Len + 2)) // ID, Len - return -E2BIG; - wrqu->data.length = pAd->StaCfg.RSNIE_Len + 2; - - if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) || - (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2)) - RSNIe = IE_RSN; - - extra[0] = (char)RSNIe; - extra[1] = pAd->StaCfg.RSNIE_Len; - memcpy(extra+2, &pAd->StaCfg.RSN_IE[0], pAd->StaCfg.RSNIE_Len); - } - - return 0; -} - -int rt_ioctl_siwpmksa(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - PRTMP_ADAPTER pAd = dev->ml_priv; - struct iw_pmksa *pPmksa = (struct iw_pmksa *)wrqu->data.pointer; - INT CachedIdx = 0, idx = 0; - - if (pPmksa == NULL) - return -EINVAL; - - DBGPRINT(RT_DEBUG_TRACE ,("===> rt_ioctl_siwpmksa\n")); - switch(pPmksa->cmd) - { - case IW_PMKSA_FLUSH: - NdisZeroMemory(pAd->StaCfg.SavedPMK, sizeof(BSSID_INFO)*PMKID_NO); - DBGPRINT(RT_DEBUG_TRACE ,("rt_ioctl_siwpmksa - IW_PMKSA_FLUSH\n")); - break; - case IW_PMKSA_REMOVE: - for (CachedIdx = 0; CachedIdx < pAd->StaCfg.SavedPMKNum; CachedIdx++) - { - // compare the BSSID - if (NdisEqualMemory(pPmksa->bssid.sa_data, pAd->StaCfg.SavedPMK[CachedIdx].BSSID, MAC_ADDR_LEN)) - { - NdisZeroMemory(pAd->StaCfg.SavedPMK[CachedIdx].BSSID, MAC_ADDR_LEN); - NdisZeroMemory(pAd->StaCfg.SavedPMK[CachedIdx].PMKID, 16); - for (idx = CachedIdx; idx < (pAd->StaCfg.SavedPMKNum - 1); idx++) - { - NdisMoveMemory(&pAd->StaCfg.SavedPMK[idx].BSSID[0], &pAd->StaCfg.SavedPMK[idx+1].BSSID[0], MAC_ADDR_LEN); - NdisMoveMemory(&pAd->StaCfg.SavedPMK[idx].PMKID[0], &pAd->StaCfg.SavedPMK[idx+1].PMKID[0], 16); - } - pAd->StaCfg.SavedPMKNum--; - break; - } - } - - DBGPRINT(RT_DEBUG_TRACE ,("rt_ioctl_siwpmksa - IW_PMKSA_REMOVE\n")); - break; - case IW_PMKSA_ADD: - for (CachedIdx = 0; CachedIdx < pAd->StaCfg.SavedPMKNum; CachedIdx++) - { - // compare the BSSID - if (NdisEqualMemory(pPmksa->bssid.sa_data, pAd->StaCfg.SavedPMK[CachedIdx].BSSID, MAC_ADDR_LEN)) - break; - } - - // Found, replace it - if (CachedIdx < PMKID_NO) - { - DBGPRINT(RT_DEBUG_OFF, ("Update PMKID, idx = %d\n", CachedIdx)); - NdisMoveMemory(&pAd->StaCfg.SavedPMK[CachedIdx].BSSID[0], pPmksa->bssid.sa_data, MAC_ADDR_LEN); - NdisMoveMemory(&pAd->StaCfg.SavedPMK[CachedIdx].PMKID[0], pPmksa->pmkid, 16); - pAd->StaCfg.SavedPMKNum++; - } - // Not found, replace the last one - else - { - // Randomly replace one - CachedIdx = (pPmksa->bssid.sa_data[5] % PMKID_NO); - DBGPRINT(RT_DEBUG_OFF, ("Update PMKID, idx = %d\n", CachedIdx)); - NdisMoveMemory(&pAd->StaCfg.SavedPMK[CachedIdx].BSSID[0], pPmksa->bssid.sa_data, MAC_ADDR_LEN); - NdisMoveMemory(&pAd->StaCfg.SavedPMK[CachedIdx].PMKID[0], pPmksa->pmkid, 16); - } - - DBGPRINT(RT_DEBUG_TRACE ,("rt_ioctl_siwpmksa - IW_PMKSA_ADD\n")); - break; - default: - DBGPRINT(RT_DEBUG_TRACE ,("rt_ioctl_siwpmksa - Unknow Command!!\n")); - break; - } - - return 0; -} -#endif // #if WIRELESS_EXT > 17 - -#ifdef DBG -static int -rt_private_ioctl_bbp(struct net_device *dev, struct iw_request_info *info, - struct iw_point *wrq, char *extra) - { - CHAR *this_char; - CHAR *value = NULL; - UCHAR regBBP = 0; -// CHAR arg[255]={0}; - UINT32 bbpId; - UINT32 bbpValue; - BOOLEAN bIsPrintAllBBP = FALSE; - INT Status = 0; - PRTMP_ADAPTER pAdapter = dev->ml_priv; - - - memset(extra, 0x00, IW_PRIV_SIZE_MASK); - - if (wrq->length > 1) //No parameters. - { - sprintf(extra, "\n"); - - //Parsing Read or Write - this_char = wrq->pointer; - DBGPRINT(RT_DEBUG_TRACE, ("this_char=%s\n", this_char)); - if (!*this_char) - goto next; - - if ((value = rtstrchr(this_char, '=')) != NULL) - *value++ = 0; - - if (!value || !*value) - { //Read - DBGPRINT(RT_DEBUG_TRACE, ("this_char=%s, value=%s\n", this_char, value)); - if (sscanf(this_char, "%d", &(bbpId)) == 1) - { -#ifndef RT30xx - if (bbpId <= 136) -#endif // RT30xx // -#ifdef RT30xx - if (bbpId <= 138) // edit by johnli, RF power sequence setup, add BBP R138 for ADC dynamic on/off control -#endif // RT30xx // - { -#ifdef RALINK_ATE - if (ATE_ON(pAdapter)) - { - ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); - } - else -#endif // RALINK_ATE // - { - RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); - } - sprintf(extra+strlen(extra), "R%02d[0x%02X]:%02X\n", bbpId, bbpId*2, regBBP); - wrq->length = strlen(extra) + 1; // 1: size of '\0' - DBGPRINT(RT_DEBUG_TRACE, ("msg=%s\n", extra)); - } - else - {//Invalid parametes, so default printk all bbp - bIsPrintAllBBP = TRUE; - goto next; - } - } - else - { //Invalid parametes, so default printk all bbp - bIsPrintAllBBP = TRUE; - goto next; - } - } - else - { //Write - if ((sscanf(this_char, "%d", &(bbpId)) == 1) && (sscanf(value, "%x", &(bbpValue)) == 1)) - { -#ifndef RT30xx - if (bbpId <= 136) -#endif // RT30xx // -#ifdef RT30xx - if (bbpId <= 138) // edit by johnli, RF power sequence setup, add BBP R138 for ADC dynamic on/off control -#endif // RT30xx // - { -#ifdef RALINK_ATE - if (ATE_ON(pAdapter)) - { - ATE_BBP_IO_WRITE8_BY_REG_ID(pAdapter, bbpId, bbpValue); - //Read it back for showing - ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); - } - else -#endif // RALINK_ATE // - { - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, bbpId, bbpValue); - //Read it back for showing - RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); - } - sprintf(extra+strlen(extra), "R%02d[0x%02X]:%02X\n", bbpId, bbpId*2, regBBP); - wrq->length = strlen(extra) + 1; // 1: size of '\0' - DBGPRINT(RT_DEBUG_TRACE, ("msg=%s\n", extra)); - } - else - {//Invalid parametes, so default printk all bbp - bIsPrintAllBBP = TRUE; - goto next; - } - } - else - { //Invalid parametes, so default printk all bbp - bIsPrintAllBBP = TRUE; - goto next; - } - } - } - else - bIsPrintAllBBP = TRUE; - -next: - if (bIsPrintAllBBP) - { - memset(extra, 0x00, IW_PRIV_SIZE_MASK); - sprintf(extra, "\n"); -#ifndef RT30xx - for (bbpId = 0; bbpId <= 136; bbpId++) -#endif // RT30xx // -#ifdef RT30xx - for (bbpId = 0; bbpId <= 138; bbpId++) // edit by johnli, RF power sequence setup, add BBP R138 for ADC dynamic on/off control -#endif // RT30xx // - { - if (strlen(extra) >= (IW_PRIV_SIZE_MASK - 10)) - break; -#ifdef RALINK_ATE - if (ATE_ON(pAdapter)) - { - ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); - } - else -#endif // RALINK_ATE // - RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); -/* - sprintf(extra+strlen(extra), "R%02d[0x%02X]:%02X ", bbpId, bbpId*2, regBBP); - if (bbpId%5 == 4) - sprintf(extra+strlen(extra), "\n"); -*/ - sprintf(extra+strlen(extra), "%03d = %02X\n", bbpId, regBBP); // edit by johnli, change display format - } - - wrq->length = strlen(extra) + 1; // 1: size of '\0' - DBGPRINT(RT_DEBUG_TRACE, ("wrq->length = %d\n", wrq->length)); - } - - DBGPRINT(RT_DEBUG_TRACE, ("<==rt_private_ioctl_bbp\n\n")); - - return Status; -} -#endif // DBG // - -int rt_ioctl_siwrate(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - PRTMP_ADAPTER pAd = dev->ml_priv; - UINT32 rate = wrqu->bitrate.value, fixed = wrqu->bitrate.fixed; - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("rt_ioctl_siwrate::Network is down!\n")); - return -ENETDOWN; - } - - DBGPRINT(RT_DEBUG_TRACE, ("rt_ioctl_siwrate::(rate = %d, fixed = %d)\n", rate, fixed)); - /* rate = -1 => auto rate - rate = X, fixed = 1 => (fixed rate X) - */ - if (rate == -1) - { - //Auto Rate - pAd->StaCfg.DesiredTransmitSetting.field.MCS = MCS_AUTO; - pAd->StaCfg.bAutoTxRateSwitch = TRUE; - if ((pAd->CommonCfg.PhyMode <= PHY_11G) || - (pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MODE <= MODE_OFDM)) - RTMPSetDesiredRates(pAd, -1); - -#ifdef DOT11_N_SUPPORT - SetCommonHT(pAd); -#endif // DOT11_N_SUPPORT // - } - else - { - if (fixed) - { - pAd->StaCfg.bAutoTxRateSwitch = FALSE; - if ((pAd->CommonCfg.PhyMode <= PHY_11G) || - (pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MODE <= MODE_OFDM)) - RTMPSetDesiredRates(pAd, rate); - else - { - pAd->StaCfg.DesiredTransmitSetting.field.MCS = MCS_AUTO; -#ifdef DOT11_N_SUPPORT - SetCommonHT(pAd); -#endif // DOT11_N_SUPPORT // - } - DBGPRINT(RT_DEBUG_TRACE, ("rt_ioctl_siwrate::(HtMcs=%d)\n",pAd->StaCfg.DesiredTransmitSetting.field.MCS)); - } - else - { - // TODO: rate = X, fixed = 0 => (rates <= X) - return -EOPNOTSUPP; - } - } - - return 0; -} - -int rt_ioctl_giwrate(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - PRTMP_ADAPTER pAd = dev->ml_priv; - int rate_index = 0, rate_count = 0; - HTTRANSMIT_SETTING ht_setting; - __s32 ralinkrate[] = - {2, 4, 11, 22, // CCK - 12, 18, 24, 36, 48, 72, 96, 108, // OFDM - 13, 26, 39, 52, 78, 104, 117, 130, 26, 52, 78, 104, 156, 208, 234, 260, // 20MHz, 800ns GI, MCS: 0 ~ 15 - 39, 78, 117, 156, 234, 312, 351, 390, // 20MHz, 800ns GI, MCS: 16 ~ 23 - 27, 54, 81, 108, 162, 216, 243, 270, 54, 108, 162, 216, 324, 432, 486, 540, // 40MHz, 800ns GI, MCS: 0 ~ 15 - 81, 162, 243, 324, 486, 648, 729, 810, // 40MHz, 800ns GI, MCS: 16 ~ 23 - 14, 29, 43, 57, 87, 115, 130, 144, 29, 59, 87, 115, 173, 230, 260, 288, // 20MHz, 400ns GI, MCS: 0 ~ 15 - 43, 87, 130, 173, 260, 317, 390, 433, // 20MHz, 400ns GI, MCS: 16 ~ 23 - 30, 60, 90, 120, 180, 240, 270, 300, 60, 120, 180, 240, 360, 480, 540, 600, // 40MHz, 400ns GI, MCS: 0 ~ 15 - 90, 180, 270, 360, 540, 720, 810, 900}; // 40MHz, 400ns GI, MCS: 16 ~ 23 - - rate_count = sizeof(ralinkrate)/sizeof(__s32); - //check if the interface is down - if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - - if ((pAd->StaCfg.bAutoTxRateSwitch == FALSE) && - (INFRA_ON(pAd)) && - ((pAd->CommonCfg.PhyMode <= PHY_11G) || (pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MODE <= MODE_OFDM))) - ht_setting.word = pAd->StaCfg.HTPhyMode.word; - else - ht_setting.word = pAd->MacTab.Content[BSSID_WCID].HTPhyMode.word; - -#ifdef DOT11_N_SUPPORT - if (ht_setting.field.MODE >= MODE_HTMIX) - { -// rate_index = 12 + ((UCHAR)ht_setting.field.BW *16) + ((UCHAR)ht_setting.field.ShortGI *32) + ((UCHAR)ht_setting.field.MCS); - rate_index = 12 + ((UCHAR)ht_setting.field.BW *24) + ((UCHAR)ht_setting.field.ShortGI *48) + ((UCHAR)ht_setting.field.MCS); - } - else -#endif // DOT11_N_SUPPORT // - if (ht_setting.field.MODE == MODE_OFDM) - rate_index = (UCHAR)(ht_setting.field.MCS) + 4; - else if (ht_setting.field.MODE == MODE_CCK) - rate_index = (UCHAR)(ht_setting.field.MCS); - - if (rate_index < 0) - rate_index = 0; - - if (rate_index > rate_count) - rate_index = rate_count; - - wrqu->bitrate.value = ralinkrate[rate_index] * 500000; - wrqu->bitrate.disabled = 0; - - return 0; -} - -static const iw_handler rt_handler[] = -{ - (iw_handler) NULL, /* SIOCSIWCOMMIT */ - (iw_handler) rt_ioctl_giwname, /* SIOCGIWNAME */ - (iw_handler) NULL, /* SIOCSIWNWID */ - (iw_handler) NULL, /* SIOCGIWNWID */ - (iw_handler) rt_ioctl_siwfreq, /* SIOCSIWFREQ */ - (iw_handler) rt_ioctl_giwfreq, /* SIOCGIWFREQ */ - (iw_handler) rt_ioctl_siwmode, /* SIOCSIWMODE */ - (iw_handler) rt_ioctl_giwmode, /* SIOCGIWMODE */ - (iw_handler) NULL, /* SIOCSIWSENS */ - (iw_handler) NULL, /* SIOCGIWSENS */ - (iw_handler) NULL /* not used */, /* SIOCSIWRANGE */ - (iw_handler) rt_ioctl_giwrange, /* SIOCGIWRANGE */ - (iw_handler) NULL /* not used */, /* SIOCSIWPRIV */ - (iw_handler) NULL /* kernel code */, /* SIOCGIWPRIV */ - (iw_handler) NULL /* not used */, /* SIOCSIWSTATS */ - (iw_handler) rt28xx_get_wireless_stats /* kernel code */, /* SIOCGIWSTATS */ - (iw_handler) NULL, /* SIOCSIWSPY */ - (iw_handler) NULL, /* SIOCGIWSPY */ - (iw_handler) NULL, /* SIOCSIWTHRSPY */ - (iw_handler) NULL, /* SIOCGIWTHRSPY */ - (iw_handler) rt_ioctl_siwap, /* SIOCSIWAP */ - (iw_handler) rt_ioctl_giwap, /* SIOCGIWAP */ -#ifdef SIOCSIWMLME - (iw_handler) rt_ioctl_siwmlme, /* SIOCSIWMLME */ -#else - (iw_handler) NULL, /* SIOCSIWMLME */ -#endif // SIOCSIWMLME // - (iw_handler) rt_ioctl_iwaplist, /* SIOCGIWAPLIST */ -#ifdef SIOCGIWSCAN - (iw_handler) rt_ioctl_siwscan, /* SIOCSIWSCAN */ - (iw_handler) rt_ioctl_giwscan, /* SIOCGIWSCAN */ -#else - (iw_handler) NULL, /* SIOCSIWSCAN */ - (iw_handler) NULL, /* SIOCGIWSCAN */ -#endif /* SIOCGIWSCAN */ - (iw_handler) rt_ioctl_siwessid, /* SIOCSIWESSID */ - (iw_handler) rt_ioctl_giwessid, /* SIOCGIWESSID */ - (iw_handler) rt_ioctl_siwnickn, /* SIOCSIWNICKN */ - (iw_handler) rt_ioctl_giwnickn, /* SIOCGIWNICKN */ - (iw_handler) NULL, /* -- hole -- */ - (iw_handler) NULL, /* -- hole -- */ - (iw_handler) rt_ioctl_siwrate, /* SIOCSIWRATE */ - (iw_handler) rt_ioctl_giwrate, /* SIOCGIWRATE */ - (iw_handler) rt_ioctl_siwrts, /* SIOCSIWRTS */ - (iw_handler) rt_ioctl_giwrts, /* SIOCGIWRTS */ - (iw_handler) rt_ioctl_siwfrag, /* SIOCSIWFRAG */ - (iw_handler) rt_ioctl_giwfrag, /* SIOCGIWFRAG */ - (iw_handler) NULL, /* SIOCSIWTXPOW */ - (iw_handler) NULL, /* SIOCGIWTXPOW */ - (iw_handler) NULL, /* SIOCSIWRETRY */ - (iw_handler) NULL, /* SIOCGIWRETRY */ - (iw_handler) rt_ioctl_siwencode, /* SIOCSIWENCODE */ - (iw_handler) rt_ioctl_giwencode, /* SIOCGIWENCODE */ - (iw_handler) NULL, /* SIOCSIWPOWER */ - (iw_handler) NULL, /* SIOCGIWPOWER */ - (iw_handler) NULL, /* -- hole -- */ - (iw_handler) NULL, /* -- hole -- */ -#if WIRELESS_EXT > 17 - (iw_handler) rt_ioctl_siwgenie, /* SIOCSIWGENIE */ - (iw_handler) rt_ioctl_giwgenie, /* SIOCGIWGENIE */ - (iw_handler) rt_ioctl_siwauth, /* SIOCSIWAUTH */ - (iw_handler) rt_ioctl_giwauth, /* SIOCGIWAUTH */ - (iw_handler) rt_ioctl_siwencodeext, /* SIOCSIWENCODEEXT */ - (iw_handler) rt_ioctl_giwencodeext, /* SIOCGIWENCODEEXT */ - (iw_handler) rt_ioctl_siwpmksa, /* SIOCSIWPMKSA */ -#endif -}; - -static const iw_handler rt_priv_handlers[] = { - (iw_handler) NULL, /* + 0x00 */ - (iw_handler) NULL, /* + 0x01 */ -#ifndef CONFIG_AP_SUPPORT - (iw_handler) rt_ioctl_setparam, /* + 0x02 */ -#else - (iw_handler) NULL, /* + 0x02 */ -#endif // CONFIG_AP_SUPPORT // -#ifdef DBG - (iw_handler) rt_private_ioctl_bbp, /* + 0x03 */ -#else - (iw_handler) NULL, /* + 0x03 */ -#endif - (iw_handler) NULL, /* + 0x04 */ - (iw_handler) NULL, /* + 0x05 */ - (iw_handler) NULL, /* + 0x06 */ - (iw_handler) NULL, /* + 0x07 */ - (iw_handler) NULL, /* + 0x08 */ - (iw_handler) rt_private_get_statistics, /* + 0x09 */ - (iw_handler) NULL, /* + 0x0A */ - (iw_handler) NULL, /* + 0x0B */ - (iw_handler) NULL, /* + 0x0C */ - (iw_handler) NULL, /* + 0x0D */ - (iw_handler) NULL, /* + 0x0E */ - (iw_handler) NULL, /* + 0x0F */ - (iw_handler) NULL, /* + 0x10 */ - (iw_handler) rt_private_show, /* + 0x11 */ - (iw_handler) NULL, /* + 0x12 */ - (iw_handler) NULL, /* + 0x13 */ - (iw_handler) NULL, /* + 0x15 */ - (iw_handler) NULL, /* + 0x17 */ - (iw_handler) NULL, /* + 0x18 */ -}; - -const struct iw_handler_def rt28xx_iw_handler_def = -{ -#define N(a) (sizeof (a) / sizeof (a[0])) - .standard = (iw_handler *) rt_handler, - .num_standard = sizeof(rt_handler) / sizeof(iw_handler), - .private = (iw_handler *) rt_priv_handlers, - .num_private = N(rt_priv_handlers), - .private_args = (struct iw_priv_args *) privtab, - .num_private_args = N(privtab), -#if IW_HANDLER_VERSION >= 7 - .get_wireless_stats = rt28xx_get_wireless_stats, -#endif -}; - -INT RTMPSetInformation( - IN PRTMP_ADAPTER pAdapter, - IN OUT struct ifreq *rq, - IN INT cmd) -{ - struct iwreq *wrq = (struct iwreq *) rq; - NDIS_802_11_SSID Ssid; - NDIS_802_11_MAC_ADDRESS Bssid; - RT_802_11_PHY_MODE PhyMode; - RT_802_11_STA_CONFIG StaConfig; - NDIS_802_11_RATES aryRates; - RT_802_11_PREAMBLE Preamble; - NDIS_802_11_WEP_STATUS WepStatus; - NDIS_802_11_AUTHENTICATION_MODE AuthMode = Ndis802_11AuthModeMax; - NDIS_802_11_NETWORK_INFRASTRUCTURE BssType; - NDIS_802_11_RTS_THRESHOLD RtsThresh; - NDIS_802_11_FRAGMENTATION_THRESHOLD FragThresh; - NDIS_802_11_POWER_MODE PowerMode; - PNDIS_802_11_KEY pKey = NULL; - PNDIS_802_11_WEP pWepKey =NULL; - PNDIS_802_11_REMOVE_KEY pRemoveKey = NULL; - NDIS_802_11_CONFIGURATION Config, *pConfig = NULL; - NDIS_802_11_NETWORK_TYPE NetType; - ULONG Now; - UINT KeyIdx = 0; - INT Status = NDIS_STATUS_SUCCESS, MaxPhyMode = PHY_11G; - ULONG PowerTemp; - BOOLEAN RadioState; - BOOLEAN StateMachineTouched = FALSE; -#ifdef DOT11_N_SUPPORT - OID_SET_HT_PHYMODE HT_PhyMode; //11n ,kathy -#endif // DOT11_N_SUPPORT // -#ifdef WPA_SUPPLICANT_SUPPORT - PNDIS_802_11_PMKID pPmkId = NULL; - BOOLEAN IEEE8021xState = FALSE; - BOOLEAN IEEE8021x_required_keys = FALSE; - UCHAR wpa_supplicant_enable = 0; -#endif // WPA_SUPPLICANT_SUPPORT // - -#ifdef SNMP_SUPPORT - TX_RTY_CFG_STRUC tx_rty_cfg; - ULONG ShortRetryLimit, LongRetryLimit; - UCHAR ctmp; -#endif // SNMP_SUPPORT // - - -#ifdef DOT11_N_SUPPORT - MaxPhyMode = PHY_11N_5G; -#endif // DOT11_N_SUPPORT // - - - DBGPRINT(RT_DEBUG_TRACE, ("-->RTMPSetInformation(), 0x%08x\n", cmd&0x7FFF)); - switch(cmd & 0x7FFF) { - case RT_OID_802_11_COUNTRY_REGION: - if (wrq->u.data.length < sizeof(UCHAR)) - Status = -EINVAL; - // Only avaliable when EEPROM not programming - else if (!(pAdapter->CommonCfg.CountryRegion & 0x80) && !(pAdapter->CommonCfg.CountryRegionForABand & 0x80)) - { - ULONG Country; - UCHAR TmpPhy; - - Status = copy_from_user(&Country, wrq->u.data.pointer, wrq->u.data.length); - pAdapter->CommonCfg.CountryRegion = (UCHAR)(Country & 0x000000FF); - pAdapter->CommonCfg.CountryRegionForABand = (UCHAR)((Country >> 8) & 0x000000FF); - TmpPhy = pAdapter->CommonCfg.PhyMode; - pAdapter->CommonCfg.PhyMode = 0xff; - // Build all corresponding channel information - RTMPSetPhyMode(pAdapter, TmpPhy); -#ifdef DOT11_N_SUPPORT - SetCommonHT(pAdapter); -#endif // DOT11_N_SUPPORT // - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_COUNTRY_REGION (A:%d B/G:%d)\n", pAdapter->CommonCfg.CountryRegionForABand, - pAdapter->CommonCfg.CountryRegion)); - } - break; - case OID_802_11_BSSID_LIST_SCAN: - #ifdef RALINK_ATE - if (ATE_ON(pAdapter)) - { - DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now\n")); - break; - } -#endif // RALINK_ATE // - Now = jiffies; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_BSSID_LIST_SCAN, TxCnt = %d \n", pAdapter->RalinkCounters.LastOneSecTotalTxCount)); - - if (MONITOR_ON(pAdapter)) - { - DBGPRINT(RT_DEBUG_TRACE, ("!!! Driver is in Monitor Mode now !!!\n")); - break; - } - - //Benson add 20080527, when radio off, sta don't need to scan - if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RADIO_OFF)) - break; - - if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) - { - DBGPRINT(RT_DEBUG_TRACE, ("!!! Driver is scanning now !!!\n")); - pAdapter->StaCfg.bScanReqIsFromWebUI = TRUE; - Status = NDIS_STATUS_SUCCESS; - break; - } - - if (pAdapter->RalinkCounters.LastOneSecTotalTxCount > 100) - { - DBGPRINT(RT_DEBUG_TRACE, ("!!! Link UP, ignore this set::OID_802_11_BSSID_LIST_SCAN\n")); - Status = NDIS_STATUS_SUCCESS; - pAdapter->StaCfg.ScanCnt = 99; // Prevent auto scan triggered by this OID - break; - } - - if ((OPSTATUS_TEST_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED)) && - ((pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || - (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) || - (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || - (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)) && - (pAdapter->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED)) - { - DBGPRINT(RT_DEBUG_TRACE, ("!!! Link UP, Port Not Secured! ignore this set::OID_802_11_BSSID_LIST_SCAN\n")); - Status = NDIS_STATUS_SUCCESS; - pAdapter->StaCfg.ScanCnt = 99; // Prevent auto scan triggered by this OID - break; - } - - - if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) - { - RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); - DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); - } - - // tell CNTL state machine to call NdisMSetInformationComplete() after completing - // this request, because this request is initiated by NDIS. - pAdapter->MlmeAux.CurrReqIsFromNdis = FALSE; - // Reset allowed scan retries - pAdapter->StaCfg.ScanCnt = 0; - pAdapter->StaCfg.LastScanTime = Now; - - pAdapter->StaCfg.bScanReqIsFromWebUI = TRUE; - RTMP_SET_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS); - MlmeEnqueue(pAdapter, - MLME_CNTL_STATE_MACHINE, - OID_802_11_BSSID_LIST_SCAN, - 0, - NULL); - - Status = NDIS_STATUS_SUCCESS; - StateMachineTouched = TRUE; - break; - case OID_802_11_SSID: - if (wrq->u.data.length != sizeof(NDIS_802_11_SSID)) - Status = -EINVAL; - else - { - PCHAR pSsidString = NULL; - Status = copy_from_user(&Ssid, wrq->u.data.pointer, wrq->u.data.length); - - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_SSID (Len=%d,Ssid=%s)\n", Ssid.SsidLength, Ssid.Ssid)); - if (Ssid.SsidLength > MAX_LEN_OF_SSID) - Status = -EINVAL; - else - { - if (Ssid.SsidLength == 0) - { - Set_SSID_Proc(pAdapter, ""); - } - else - { - pSsidString = (CHAR *) kmalloc(MAX_LEN_OF_SSID+1, MEM_ALLOC_FLAG); - if (pSsidString) - { - NdisZeroMemory(pSsidString, MAX_LEN_OF_SSID+1); - NdisMoveMemory(pSsidString, Ssid.Ssid, Ssid.SsidLength); - Set_SSID_Proc(pAdapter, pSsidString); - kfree(pSsidString); - } - else - Status = -ENOMEM; - } - } - } - break; - case OID_802_11_BSSID: -#ifdef RALINK_ATE - if (ATE_ON(pAdapter)) - { - DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now\n")); - break; - } -#endif // RALINK_ATE // - if (wrq->u.data.length != sizeof(NDIS_802_11_MAC_ADDRESS)) - Status = -EINVAL; - else - { - Status = copy_from_user(&Bssid, wrq->u.data.pointer, wrq->u.data.length); - - // tell CNTL state machine to call NdisMSetInformationComplete() after completing - // this request, because this request is initiated by NDIS. - pAdapter->MlmeAux.CurrReqIsFromNdis = FALSE; - - // Prevent to connect AP again in STAMlmePeriodicExec - pAdapter->MlmeAux.AutoReconnectSsidLen= 32; - - // Reset allowed scan retries - pAdapter->StaCfg.ScanCnt = 0; - - if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) - { - RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); - DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); - } - MlmeEnqueue(pAdapter, - MLME_CNTL_STATE_MACHINE, - OID_802_11_BSSID, - sizeof(NDIS_802_11_MAC_ADDRESS), - (VOID *)&Bssid); - Status = NDIS_STATUS_SUCCESS; - StateMachineTouched = TRUE; - - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_BSSID %02x:%02x:%02x:%02x:%02x:%02x\n", - Bssid[0], Bssid[1], Bssid[2], Bssid[3], Bssid[4], Bssid[5])); - } - break; - case RT_OID_802_11_RADIO: - if (wrq->u.data.length != sizeof(BOOLEAN)) - Status = -EINVAL; - else - { - Status = copy_from_user(&RadioState, wrq->u.data.pointer, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_RADIO (=%d)\n", RadioState)); - if (pAdapter->StaCfg.bSwRadio != RadioState) - { - pAdapter->StaCfg.bSwRadio = RadioState; - if (pAdapter->StaCfg.bRadio != (pAdapter->StaCfg.bHwRadio && pAdapter->StaCfg.bSwRadio)) - { - pAdapter->StaCfg.bRadio = (pAdapter->StaCfg.bHwRadio && pAdapter->StaCfg.bSwRadio); - if (pAdapter->StaCfg.bRadio == TRUE) - { - MlmeRadioOn(pAdapter); - // Update extra information - pAdapter->ExtraInfo = EXTRA_INFO_CLEAR; - } - else - { - MlmeRadioOff(pAdapter); - // Update extra information - pAdapter->ExtraInfo = SW_RADIO_OFF; - } - } - } - } - break; - case RT_OID_802_11_PHY_MODE: - if (wrq->u.data.length != sizeof(RT_802_11_PHY_MODE)) - Status = -EINVAL; - else - { - Status = copy_from_user(&PhyMode, wrq->u.data.pointer, wrq->u.data.length); - if (PhyMode <= MaxPhyMode) - { - RTMPSetPhyMode(pAdapter, PhyMode); -#ifdef DOT11_N_SUPPORT - SetCommonHT(pAdapter); -#endif // DOT11_N_SUPPORT // - } - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_PHY_MODE (=%d)\n", PhyMode)); - } - break; - case RT_OID_802_11_STA_CONFIG: - if (wrq->u.data.length != sizeof(RT_802_11_STA_CONFIG)) - Status = -EINVAL; - else - { - Status = copy_from_user(&StaConfig, wrq->u.data.pointer, wrq->u.data.length); - pAdapter->CommonCfg.bEnableTxBurst = StaConfig.EnableTxBurst; - pAdapter->CommonCfg.UseBGProtection = StaConfig.UseBGProtection; - pAdapter->CommonCfg.bUseShortSlotTime = 1; // 2003-10-30 always SHORT SLOT capable - if ((pAdapter->CommonCfg.PhyMode != StaConfig.AdhocMode) && - (StaConfig.AdhocMode <= MaxPhyMode)) - { - // allow dynamic change of "USE OFDM rate or not" in ADHOC mode - // if setting changed, need to reset current TX rate as well as BEACON frame format - pAdapter->CommonCfg.PhyMode = StaConfig.AdhocMode; - if (pAdapter->StaCfg.BssType == BSS_ADHOC) - { - RTMPSetPhyMode(pAdapter, PhyMode); - MlmeUpdateTxRates(pAdapter, FALSE, 0); - MakeIbssBeacon(pAdapter); // re-build BEACON frame - AsicEnableIbssSync(pAdapter); // copy to on-chip memory - } - } - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_SET_STA_CONFIG (Burst=%d, Protection=%ld,ShortSlot=%d\n", - pAdapter->CommonCfg.bEnableTxBurst, - pAdapter->CommonCfg.UseBGProtection, - pAdapter->CommonCfg.bUseShortSlotTime)); - } - break; - case OID_802_11_DESIRED_RATES: - if (wrq->u.data.length != sizeof(NDIS_802_11_RATES)) - Status = -EINVAL; - else - { - Status = copy_from_user(&aryRates, wrq->u.data.pointer, wrq->u.data.length); - NdisZeroMemory(pAdapter->CommonCfg.DesireRate, MAX_LEN_OF_SUPPORTED_RATES); - NdisMoveMemory(pAdapter->CommonCfg.DesireRate, &aryRates, sizeof(NDIS_802_11_RATES)); - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_DESIRED_RATES (%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x)\n", - pAdapter->CommonCfg.DesireRate[0],pAdapter->CommonCfg.DesireRate[1], - pAdapter->CommonCfg.DesireRate[2],pAdapter->CommonCfg.DesireRate[3], - pAdapter->CommonCfg.DesireRate[4],pAdapter->CommonCfg.DesireRate[5], - pAdapter->CommonCfg.DesireRate[6],pAdapter->CommonCfg.DesireRate[7] )); - // Changing DesiredRate may affect the MAX TX rate we used to TX frames out - MlmeUpdateTxRates(pAdapter, FALSE, 0); - } - break; - case RT_OID_802_11_PREAMBLE: - if (wrq->u.data.length != sizeof(RT_802_11_PREAMBLE)) - Status = -EINVAL; - else - { - Status = copy_from_user(&Preamble, wrq->u.data.pointer, wrq->u.data.length); - if (Preamble == Rt802_11PreambleShort) - { - pAdapter->CommonCfg.TxPreamble = Preamble; - MlmeSetTxPreamble(pAdapter, Rt802_11PreambleShort); - } - else if ((Preamble == Rt802_11PreambleLong) || (Preamble == Rt802_11PreambleAuto)) - { - // if user wants AUTO, initialize to LONG here, then change according to AP's - // capability upon association. - pAdapter->CommonCfg.TxPreamble = Preamble; - MlmeSetTxPreamble(pAdapter, Rt802_11PreambleLong); - } - else - { - Status = -EINVAL; - break; - } - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_PREAMBLE (=%d)\n", Preamble)); - } - break; - case OID_802_11_WEP_STATUS: - if (wrq->u.data.length != sizeof(NDIS_802_11_WEP_STATUS)) - Status = -EINVAL; - else - { - Status = copy_from_user(&WepStatus, wrq->u.data.pointer, wrq->u.data.length); - // Since TKIP, AES, WEP are all supported. It should not have any invalid setting - if (WepStatus <= Ndis802_11Encryption3KeyAbsent) - { - if (pAdapter->StaCfg.WepStatus != WepStatus) - { - // Config has changed - pAdapter->bConfigChanged = TRUE; - } - pAdapter->StaCfg.WepStatus = WepStatus; - pAdapter->StaCfg.OrigWepStatus = WepStatus; - pAdapter->StaCfg.PairCipher = WepStatus; - pAdapter->StaCfg.GroupCipher = WepStatus; - } - else - { - Status = -EINVAL; - break; - } - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_WEP_STATUS (=%d)\n",WepStatus)); - } - break; - case OID_802_11_AUTHENTICATION_MODE: - if (wrq->u.data.length != sizeof(NDIS_802_11_AUTHENTICATION_MODE)) - Status = -EINVAL; - else - { - Status = copy_from_user(&AuthMode, wrq->u.data.pointer, wrq->u.data.length); - if (AuthMode > Ndis802_11AuthModeMax) - { - Status = -EINVAL; - break; - } - else - { - if (pAdapter->StaCfg.AuthMode != AuthMode) - { - // Config has changed - pAdapter->bConfigChanged = TRUE; - } - pAdapter->StaCfg.AuthMode = AuthMode; - } - pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_AUTHENTICATION_MODE (=%d) \n",pAdapter->StaCfg.AuthMode)); - } - break; - case OID_802_11_INFRASTRUCTURE_MODE: - if (wrq->u.data.length != sizeof(NDIS_802_11_NETWORK_INFRASTRUCTURE)) - Status = -EINVAL; - else - { - Status = copy_from_user(&BssType, wrq->u.data.pointer, wrq->u.data.length); - - if (BssType == Ndis802_11IBSS) - Set_NetworkType_Proc(pAdapter, "Adhoc"); - else if (BssType == Ndis802_11Infrastructure) - Set_NetworkType_Proc(pAdapter, "Infra"); - else if (BssType == Ndis802_11Monitor) - Set_NetworkType_Proc(pAdapter, "Monitor"); - else - { - Status = -EINVAL; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_INFRASTRUCTURE_MODE (unknown)\n")); - } - } - break; - case OID_802_11_REMOVE_WEP: - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_WEP\n")); - if (wrq->u.data.length != sizeof(NDIS_802_11_KEY_INDEX)) - { - Status = -EINVAL; - } - else - { - KeyIdx = *(NDIS_802_11_KEY_INDEX *) wrq->u.data.pointer; - - if (KeyIdx & 0x80000000) - { - // Should never set default bit when remove key - Status = -EINVAL; - } - else - { - KeyIdx = KeyIdx & 0x0fffffff; - if (KeyIdx >= 4){ - Status = -EINVAL; - } - else - { - pAdapter->SharedKey[BSS0][KeyIdx].KeyLen = 0; - pAdapter->SharedKey[BSS0][KeyIdx].CipherAlg = CIPHER_NONE; - AsicRemoveSharedKeyEntry(pAdapter, 0, (UCHAR)KeyIdx); - } - } - } - break; - case RT_OID_802_11_RESET_COUNTERS: - NdisZeroMemory(&pAdapter->WlanCounters, sizeof(COUNTER_802_11)); - NdisZeroMemory(&pAdapter->Counters8023, sizeof(COUNTER_802_3)); - NdisZeroMemory(&pAdapter->RalinkCounters, sizeof(COUNTER_RALINK)); - pAdapter->Counters8023.RxNoBuffer = 0; - pAdapter->Counters8023.GoodReceives = 0; - pAdapter->Counters8023.RxNoBuffer = 0; -#ifdef RT2870 - pAdapter->BulkOutComplete = 0; - pAdapter->BulkOutCompleteOther= 0; - pAdapter->BulkOutCompleteCancel = 0; - pAdapter->BulkOutReq = 0; - pAdapter->BulkInReq= 0; - pAdapter->BulkInComplete = 0; - pAdapter->BulkInCompleteFail = 0; -#endif // RT2870 // - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_RESET_COUNTERS \n")); - break; - case OID_802_11_RTS_THRESHOLD: - if (wrq->u.data.length != sizeof(NDIS_802_11_RTS_THRESHOLD)) - Status = -EINVAL; - else - { - Status = copy_from_user(&RtsThresh, wrq->u.data.pointer, wrq->u.data.length); - if (RtsThresh > MAX_RTS_THRESHOLD) - Status = -EINVAL; - else - pAdapter->CommonCfg.RtsThreshold = (USHORT)RtsThresh; - } - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_RTS_THRESHOLD (=%ld)\n",RtsThresh)); - break; - case OID_802_11_FRAGMENTATION_THRESHOLD: - if (wrq->u.data.length != sizeof(NDIS_802_11_FRAGMENTATION_THRESHOLD)) - Status = -EINVAL; - else - { - Status = copy_from_user(&FragThresh, wrq->u.data.pointer, wrq->u.data.length); - pAdapter->CommonCfg.bUseZeroToDisableFragment = FALSE; - if (FragThresh > MAX_FRAG_THRESHOLD || FragThresh < MIN_FRAG_THRESHOLD) - { - if (FragThresh == 0) - { - pAdapter->CommonCfg.FragmentThreshold = MAX_FRAG_THRESHOLD; - pAdapter->CommonCfg.bUseZeroToDisableFragment = TRUE; - } - else - Status = -EINVAL; - } - else - pAdapter->CommonCfg.FragmentThreshold = (USHORT)FragThresh; - } - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_FRAGMENTATION_THRESHOLD (=%ld) \n",FragThresh)); - break; - case OID_802_11_POWER_MODE: - if (wrq->u.data.length != sizeof(NDIS_802_11_POWER_MODE)) - Status = -EINVAL; - else - { - Status = copy_from_user(&PowerMode, wrq->u.data.pointer, wrq->u.data.length); - if (PowerMode == Ndis802_11PowerModeCAM) - Set_PSMode_Proc(pAdapter, "CAM"); - else if (PowerMode == Ndis802_11PowerModeMAX_PSP) - Set_PSMode_Proc(pAdapter, "Max_PSP"); - else if (PowerMode == Ndis802_11PowerModeFast_PSP) - Set_PSMode_Proc(pAdapter, "Fast_PSP"); - else if (PowerMode == Ndis802_11PowerModeLegacy_PSP) - Set_PSMode_Proc(pAdapter, "Legacy_PSP"); - else - Status = -EINVAL; - } - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_POWER_MODE (=%d)\n",PowerMode)); - break; - case RT_OID_802_11_TX_POWER_LEVEL_1: - if (wrq->u.data.length < sizeof(ULONG)) - Status = -EINVAL; - else - { - Status = copy_from_user(&PowerTemp, wrq->u.data.pointer, wrq->u.data.length); - if (PowerTemp > 100) - PowerTemp = 0xffffffff; // AUTO - pAdapter->CommonCfg.TxPowerDefault = PowerTemp; //keep current setting. - pAdapter->CommonCfg.TxPowerPercentage = pAdapter->CommonCfg.TxPowerDefault; - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_TX_POWER_LEVEL_1 (=%ld)\n", pAdapter->CommonCfg.TxPowerPercentage)); - } - break; - case OID_802_11_NETWORK_TYPE_IN_USE: - if (wrq->u.data.length != sizeof(NDIS_802_11_NETWORK_TYPE)) - Status = -EINVAL; - else - { - Status = copy_from_user(&NetType, wrq->u.data.pointer, wrq->u.data.length); - - if (NetType == Ndis802_11DS) - RTMPSetPhyMode(pAdapter, PHY_11B); - else if (NetType == Ndis802_11OFDM24) - RTMPSetPhyMode(pAdapter, PHY_11BG_MIXED); - else if (NetType == Ndis802_11OFDM5) - RTMPSetPhyMode(pAdapter, PHY_11A); - else - Status = -EINVAL; -#ifdef DOT11_N_SUPPORT - if (Status == NDIS_STATUS_SUCCESS) - SetCommonHT(pAdapter); -#endif // DOT11_N_SUPPORT // - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_NETWORK_TYPE_IN_USE (=%d)\n",NetType)); - } - break; - // For WPA PSK PMK key - case RT_OID_802_11_ADD_WPA: - pKey = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); - if(pKey == NULL) - { - Status = -ENOMEM; - break; - } - - Status = copy_from_user(pKey, wrq->u.data.pointer, wrq->u.data.length); - if (pKey->Length != wrq->u.data.length) - { - Status = -EINVAL; - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_ADD_WPA, Failed!!\n")); - } - else - { - if ((pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPAPSK) && - (pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPA2PSK) && - (pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPANone) ) - { - Status = -EOPNOTSUPP; - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_ADD_WPA, Failed!! [AuthMode != WPAPSK/WPA2PSK/WPANONE]\n")); - } - else if ((pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) || - (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) || - (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) ) // Only for WPA PSK mode - { - NdisMoveMemory(pAdapter->StaCfg.PMK, &pKey->KeyMaterial, pKey->KeyLength); - // Use RaConfig as PSK agent. - // Start STA supplicant state machine - if (pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPANone) - pAdapter->StaCfg.WpaState = SS_START; - - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_ADD_WPA (id=0x%x, Len=%d-byte)\n", pKey->KeyIndex, pKey->KeyLength)); - } - else - { - pAdapter->StaCfg.WpaState = SS_NOTUSE; - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_ADD_WPA (id=0x%x, Len=%d-byte)\n", pKey->KeyIndex, pKey->KeyLength)); - } - } - kfree(pKey); - break; - case OID_802_11_REMOVE_KEY: - pRemoveKey = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); - if(pRemoveKey == NULL) - { - Status = -ENOMEM; - break; - } - - Status = copy_from_user(pRemoveKey, wrq->u.data.pointer, wrq->u.data.length); - if (pRemoveKey->Length != wrq->u.data.length) - { - Status = -EINVAL; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_KEY, Failed!!\n")); - } - else - { - if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - { - RTMPWPARemoveKeyProc(pAdapter, pRemoveKey); - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_KEY, Remove WPA Key!!\n")); - } - else - { - KeyIdx = pRemoveKey->KeyIndex; - - if (KeyIdx & 0x80000000) - { - // Should never set default bit when remove key - Status = -EINVAL; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_KEY, Failed!!(Should never set default bit when remove key)\n")); - } - else - { - KeyIdx = KeyIdx & 0x0fffffff; - if (KeyIdx > 3) - { - Status = -EINVAL; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_KEY, Failed!!(KeyId[%d] out of range)\n", KeyIdx)); - } - else - { - pAdapter->SharedKey[BSS0][KeyIdx].KeyLen = 0; - pAdapter->SharedKey[BSS0][KeyIdx].CipherAlg = CIPHER_NONE; - AsicRemoveSharedKeyEntry(pAdapter, 0, (UCHAR)KeyIdx); - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_KEY (id=0x%x, Len=%d-byte)\n", pRemoveKey->KeyIndex, pRemoveKey->Length)); - } - } - } - } - kfree(pRemoveKey); - break; - // New for WPA - case OID_802_11_ADD_KEY: - pKey = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); - if(pKey == NULL) - { - Status = -ENOMEM; - break; - } - Status = copy_from_user(pKey, wrq->u.data.pointer, wrq->u.data.length); - if (pKey->Length != wrq->u.data.length) - { - Status = -EINVAL; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_KEY, Failed!!\n")); - } - else - { - RTMPAddKey(pAdapter, pKey); - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_KEY (id=0x%x, Len=%d-byte)\n", pKey->KeyIndex, pKey->KeyLength)); - } - kfree(pKey); - break; - case OID_802_11_CONFIGURATION: - if (wrq->u.data.length != sizeof(NDIS_802_11_CONFIGURATION)) - Status = -EINVAL; - else - { - Status = copy_from_user(&Config, wrq->u.data.pointer, wrq->u.data.length); - pConfig = &Config; - - if ((pConfig->BeaconPeriod >= 20) && (pConfig->BeaconPeriod <=400)) - pAdapter->CommonCfg.BeaconPeriod = (USHORT) pConfig->BeaconPeriod; - - pAdapter->StaActive.AtimWin = (USHORT) pConfig->ATIMWindow; - MAP_KHZ_TO_CHANNEL_ID(pConfig->DSConfig, pAdapter->CommonCfg.Channel); - // - // Save the channel on MlmeAux for CntlOidRTBssidProc used. - // - pAdapter->MlmeAux.Channel = pAdapter->CommonCfg.Channel; - - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_CONFIGURATION (BeacnPeriod=%ld,AtimW=%ld,Ch=%d)\n", - pConfig->BeaconPeriod, pConfig->ATIMWindow, pAdapter->CommonCfg.Channel)); - // Config has changed - pAdapter->bConfigChanged = TRUE; - } - break; -#ifdef DOT11_N_SUPPORT - case RT_OID_802_11_SET_HT_PHYMODE: - if (wrq->u.data.length != sizeof(OID_SET_HT_PHYMODE)) - Status = -EINVAL; - else - { - POID_SET_HT_PHYMODE pHTPhyMode = &HT_PhyMode; - - Status = copy_from_user(&HT_PhyMode, wrq->u.data.pointer, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Set::pHTPhyMode (PhyMode = %d,TransmitNo = %d, HtMode = %d, ExtOffset = %d , MCS = %d, BW = %d, STBC = %d, SHORTGI = %d) \n", - pHTPhyMode->PhyMode, pHTPhyMode->TransmitNo,pHTPhyMode->HtMode,pHTPhyMode->ExtOffset, - pHTPhyMode->MCS, pHTPhyMode->BW, pHTPhyMode->STBC, pHTPhyMode->SHORTGI)); - if (pAdapter->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) - RTMPSetHT(pAdapter, pHTPhyMode); - } - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_SET_HT_PHYMODE(MCS=%d,BW=%d,SGI=%d,STBC=%d)\n", - pAdapter->StaCfg.HTPhyMode.field.MCS, pAdapter->StaCfg.HTPhyMode.field.BW, pAdapter->StaCfg.HTPhyMode.field.ShortGI, - pAdapter->StaCfg.HTPhyMode.field.STBC)); - break; -#endif // DOT11_N_SUPPORT // - case RT_OID_802_11_SET_APSD_SETTING: - if (wrq->u.data.length != sizeof(ULONG)) - Status = -EINVAL; - else - { - ULONG apsd ; - Status = copy_from_user(&apsd, wrq->u.data.pointer, wrq->u.data.length); - - /*------------------------------------------------------------------- - |B31~B7 | B6~B5 | B4 | B3 | B2 | B1 | B0 | - --------------------------------------------------------------------- - | Rsvd | Max SP Len | AC_VO | AC_VI | AC_BK | AC_BE | APSD Capable | - ---------------------------------------------------------------------*/ - pAdapter->CommonCfg.bAPSDCapable = (apsd & 0x00000001) ? TRUE : FALSE; - pAdapter->CommonCfg.bAPSDAC_BE = ((apsd & 0x00000002) >> 1) ? TRUE : FALSE; - pAdapter->CommonCfg.bAPSDAC_BK = ((apsd & 0x00000004) >> 2) ? TRUE : FALSE; - pAdapter->CommonCfg.bAPSDAC_VI = ((apsd & 0x00000008) >> 3) ? TRUE : FALSE; - pAdapter->CommonCfg.bAPSDAC_VO = ((apsd & 0x00000010) >> 4) ? TRUE : FALSE; - pAdapter->CommonCfg.MaxSPLength = (UCHAR)((apsd & 0x00000060) >> 5); - - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_SET_APSD_SETTING (apsd=0x%lx, APSDCap=%d, [BE,BK,VI,VO]=[%d/%d/%d/%d], MaxSPLen=%d)\n", apsd, pAdapter->CommonCfg.bAPSDCapable, - pAdapter->CommonCfg.bAPSDAC_BE, pAdapter->CommonCfg.bAPSDAC_BK, pAdapter->CommonCfg.bAPSDAC_VI, pAdapter->CommonCfg.bAPSDAC_VO, pAdapter->CommonCfg.MaxSPLength)); - } - break; - - case RT_OID_802_11_SET_APSD_PSM: - if (wrq->u.data.length != sizeof(ULONG)) - Status = -EINVAL; - else - { - // Driver needs to notify AP when PSM changes - Status = copy_from_user(&pAdapter->CommonCfg.bAPSDForcePowerSave, wrq->u.data.pointer, wrq->u.data.length); - if (pAdapter->CommonCfg.bAPSDForcePowerSave != pAdapter->StaCfg.Psm) - { - MlmeSetPsmBit(pAdapter, pAdapter->CommonCfg.bAPSDForcePowerSave); - RTMPSendNullFrame(pAdapter, pAdapter->CommonCfg.TxRate, TRUE); - } - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_SET_APSD_PSM (bAPSDForcePowerSave:%d)\n", pAdapter->CommonCfg.bAPSDForcePowerSave)); - } - break; -#ifdef QOS_DLS_SUPPORT - case RT_OID_802_11_SET_DLS: - if (wrq->u.data.length != sizeof(ULONG)) - Status = -EINVAL; - else - { - BOOLEAN oldvalue = pAdapter->CommonCfg.bDLSCapable; - Status = copy_from_user(&pAdapter->CommonCfg.bDLSCapable, wrq->u.data.pointer, wrq->u.data.length); - if (oldvalue && !pAdapter->CommonCfg.bDLSCapable) - { - int i; - // tear down local dls table entry - for (i=0; iStaCfg.DLSEntry[i].Valid && (pAdapter->StaCfg.DLSEntry[i].Status == DLS_FINISH)) - { - pAdapter->StaCfg.DLSEntry[i].Status = DLS_NONE; - pAdapter->StaCfg.DLSEntry[i].Valid = FALSE; - RTMPSendDLSTearDownFrame(pAdapter, pAdapter->StaCfg.DLSEntry[i].MacAddr); - } - } - - // tear down peer dls table entry - for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid && (pAdapter->StaCfg.DLSEntry[i].Status == DLS_FINISH)) - { - pAdapter->StaCfg.DLSEntry[i].Status = DLS_NONE; - pAdapter->StaCfg.DLSEntry[i].Valid = FALSE; - RTMPSendDLSTearDownFrame(pAdapter, pAdapter->StaCfg.DLSEntry[i].MacAddr); - } - } - } - - DBGPRINT(RT_DEBUG_TRACE,("Set::RT_OID_802_11_SET_DLS (=%d)\n", pAdapter->CommonCfg.bDLSCapable)); - } - break; - - case RT_OID_802_11_SET_DLS_PARAM: - if (wrq->u.data.length != sizeof(RT_802_11_DLS_UI)) - Status = -EINVAL; - else - { - RT_802_11_DLS Dls; - - NdisZeroMemory(&Dls, sizeof(RT_802_11_DLS)); - RTMPMoveMemory(&Dls, wrq->u.data.pointer, sizeof(RT_802_11_DLS_UI)); - MlmeEnqueue(pAdapter, - MLME_CNTL_STATE_MACHINE, - RT_OID_802_11_SET_DLS_PARAM, - sizeof(RT_802_11_DLS), - &Dls); - DBGPRINT(RT_DEBUG_TRACE,("Set::RT_OID_802_11_SET_DLS_PARAM \n")); - } - break; -#endif // QOS_DLS_SUPPORT // - case RT_OID_802_11_SET_WMM: - if (wrq->u.data.length != sizeof(BOOLEAN)) - Status = -EINVAL; - else - { - Status = copy_from_user(&pAdapter->CommonCfg.bWmmCapable, wrq->u.data.pointer, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_SET_WMM (=%d) \n", pAdapter->CommonCfg.bWmmCapable)); - } - break; - - case OID_802_11_DISASSOCIATE: -#ifdef RALINK_ATE - if (ATE_ON(pAdapter)) - { - DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now\n")); - break; - } -#endif // RALINK_ATE // - // - // Set NdisRadioStateOff to TRUE, instead of called MlmeRadioOff. - // Later on, NDIS_802_11_BSSID_LIST_EX->NumberOfItems should be 0 - // when query OID_802_11_BSSID_LIST. - // - // TRUE: NumberOfItems will set to 0. - // FALSE: NumberOfItems no change. - // - pAdapter->CommonCfg.NdisRadioStateOff = TRUE; - // Set to immediately send the media disconnect event - pAdapter->MlmeAux.CurrReqIsFromNdis = TRUE; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_DISASSOCIATE \n")); - - if (INFRA_ON(pAdapter)) - { - if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) - { - RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); - DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); - } - - MlmeEnqueue(pAdapter, - MLME_CNTL_STATE_MACHINE, - OID_802_11_DISASSOCIATE, - 0, - NULL); - - StateMachineTouched = TRUE; - } - break; - -#ifdef DOT11_N_SUPPORT - case RT_OID_802_11_SET_IMME_BA_CAP: - if (wrq->u.data.length != sizeof(OID_BACAP_STRUC)) - Status = -EINVAL; - else - { - OID_BACAP_STRUC Orde ; - Status = copy_from_user(&Orde, wrq->u.data.pointer, wrq->u.data.length); - if (Orde.Policy > BA_NOTUSE) - { - Status = NDIS_STATUS_INVALID_DATA; - } - else if (Orde.Policy == BA_NOTUSE) - { - pAdapter->CommonCfg.BACapability.field.Policy = BA_NOTUSE; - pAdapter->CommonCfg.BACapability.field.MpduDensity = Orde.MpduDensity; - pAdapter->CommonCfg.DesiredHtPhy.MpduDensity = Orde.MpduDensity; - pAdapter->CommonCfg.DesiredHtPhy.AmsduEnable = Orde.AmsduEnable; - pAdapter->CommonCfg.DesiredHtPhy.AmsduSize= Orde.AmsduSize; - pAdapter->CommonCfg.DesiredHtPhy.MimoPs= Orde.MMPSmode; - pAdapter->CommonCfg.BACapability.field.MMPSmode = Orde.MMPSmode; - // UPdata to HT IE - pAdapter->CommonCfg.HtCapability.HtCapInfo.MimoPs = Orde.MMPSmode; - pAdapter->CommonCfg.HtCapability.HtCapInfo.AMsduSize = Orde.AmsduSize; - pAdapter->CommonCfg.HtCapability.HtCapParm.MpduDensity = Orde.MpduDensity; - } - else - { - pAdapter->CommonCfg.BACapability.field.AutoBA = Orde.AutoBA; - pAdapter->CommonCfg.BACapability.field.Policy = IMMED_BA; // we only support immediate BA. - pAdapter->CommonCfg.BACapability.field.MpduDensity = Orde.MpduDensity; - pAdapter->CommonCfg.DesiredHtPhy.MpduDensity = Orde.MpduDensity; - pAdapter->CommonCfg.DesiredHtPhy.AmsduEnable = Orde.AmsduEnable; - pAdapter->CommonCfg.DesiredHtPhy.AmsduSize= Orde.AmsduSize; - pAdapter->CommonCfg.DesiredHtPhy.MimoPs = Orde.MMPSmode; - pAdapter->CommonCfg.BACapability.field.MMPSmode = Orde.MMPSmode; - - // UPdata to HT IE - pAdapter->CommonCfg.HtCapability.HtCapInfo.MimoPs = Orde.MMPSmode; - pAdapter->CommonCfg.HtCapability.HtCapInfo.AMsduSize = Orde.AmsduSize; - pAdapter->CommonCfg.HtCapability.HtCapParm.MpduDensity = Orde.MpduDensity; - - if (pAdapter->CommonCfg.BACapability.field.RxBAWinLimit > MAX_RX_REORDERBUF) - pAdapter->CommonCfg.BACapability.field.RxBAWinLimit = MAX_RX_REORDERBUF; - - } - - pAdapter->CommonCfg.REGBACapability.word = pAdapter->CommonCfg.BACapability.word; - DBGPRINT(RT_DEBUG_TRACE, ("Set::(Orde.AutoBA = %d) (Policy=%d)(ReBAWinLimit=%d)(TxBAWinLimit=%d)(AutoMode=%d)\n",Orde.AutoBA, pAdapter->CommonCfg.BACapability.field.Policy, - pAdapter->CommonCfg.BACapability.field.RxBAWinLimit,pAdapter->CommonCfg.BACapability.field.TxBAWinLimit, pAdapter->CommonCfg.BACapability.field.AutoBA)); - DBGPRINT(RT_DEBUG_TRACE, ("Set::(MimoPs = %d)(AmsduEnable = %d) (AmsduSize=%d)(MpduDensity=%d)\n",pAdapter->CommonCfg.DesiredHtPhy.MimoPs, pAdapter->CommonCfg.DesiredHtPhy.AmsduEnable, - pAdapter->CommonCfg.DesiredHtPhy.AmsduSize, pAdapter->CommonCfg.DesiredHtPhy.MpduDensity)); - } - - break; - case RT_OID_802_11_ADD_IMME_BA: - DBGPRINT(RT_DEBUG_TRACE, (" Set :: RT_OID_802_11_ADD_IMME_BA \n")); - if (wrq->u.data.length != sizeof(OID_ADD_BA_ENTRY)) - Status = -EINVAL; - else - { - UCHAR index; - OID_ADD_BA_ENTRY BA; - MAC_TABLE_ENTRY *pEntry; - - Status = copy_from_user(&BA, wrq->u.data.pointer, wrq->u.data.length); - if (BA.TID > 15) - { - Status = NDIS_STATUS_INVALID_DATA; - break; - } - else - { - //BATableInsertEntry - //As ad-hoc mode, BA pair is not limited to only BSSID. so add via OID. - index = BA.TID; - // in ad hoc mode, when adding BA pair, we should insert this entry into MACEntry too - pEntry = MacTableLookup(pAdapter, BA.MACAddr); - if (!pEntry) - { - DBGPRINT(RT_DEBUG_TRACE, ("RT_OID_802_11_ADD_IMME_BA. break on no connection.----:%x:%x\n", BA.MACAddr[4], BA.MACAddr[5])); - break; - } - if (BA.IsRecipient == FALSE) - { - if (pEntry->bIAmBadAtheros == TRUE) - pAdapter->CommonCfg.BACapability.field.RxBAWinLimit = 0x10; - - BAOriSessionSetUp(pAdapter, pEntry, index, 0, 100, TRUE); - } - else - { - //BATableInsertEntry(pAdapter, pEntry->Aid, BA.MACAddr, 0, 0xffff, BA.TID, BA.nMSDU, BA.IsRecipient); - } - - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_ADD_IMME_BA. Rec = %d. Mac = %x:%x:%x:%x:%x:%x . \n", - BA.IsRecipient, BA.MACAddr[0], BA.MACAddr[1], BA.MACAddr[2], BA.MACAddr[2] - , BA.MACAddr[4], BA.MACAddr[5])); - } - } - break; - - case RT_OID_802_11_TEAR_IMME_BA: - DBGPRINT(RT_DEBUG_TRACE, ("Set :: RT_OID_802_11_TEAR_IMME_BA \n")); - if (wrq->u.data.length != sizeof(OID_ADD_BA_ENTRY)) - Status = -EINVAL; - else - { - POID_ADD_BA_ENTRY pBA; - MAC_TABLE_ENTRY *pEntry; - - pBA = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); - - if (pBA == NULL) - { - DBGPRINT(RT_DEBUG_TRACE, ("Set :: RT_OID_802_11_TEAR_IMME_BA kmalloc() can't allocate enough memory\n")); - Status = NDIS_STATUS_FAILURE; - } - else - { - Status = copy_from_user(pBA, wrq->u.data.pointer, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Set :: RT_OID_802_11_TEAR_IMME_BA(TID=%d, bAllTid=%d)\n", pBA->TID, pBA->bAllTid)); - - if (!pBA->bAllTid && (pBA->TID > NUM_OF_TID)) - { - Status = NDIS_STATUS_INVALID_DATA; - break; - } - - if (pBA->IsRecipient == FALSE) - { - pEntry = MacTableLookup(pAdapter, pBA->MACAddr); - DBGPRINT(RT_DEBUG_TRACE, (" pBA->IsRecipient == FALSE\n")); - if (pEntry) - { - DBGPRINT(RT_DEBUG_TRACE, (" pBA->pEntry\n")); - BAOriSessionTearDown(pAdapter, pEntry->Aid, pBA->TID, FALSE, TRUE); - } - else - DBGPRINT(RT_DEBUG_TRACE, ("Set :: Not found pEntry \n")); - } - else - { - pEntry = MacTableLookup(pAdapter, pBA->MACAddr); - if (pEntry) - { - BARecSessionTearDown( pAdapter, (UCHAR)pEntry->Aid, pBA->TID, TRUE); - } - else - DBGPRINT(RT_DEBUG_TRACE, ("Set :: Not found pEntry \n")); - } - kfree(pBA); - } - } - break; -#endif // DOT11_N_SUPPORT // - - // For WPA_SUPPLICANT to set static wep key - case OID_802_11_ADD_WEP: - pWepKey = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); - - if(pWepKey == NULL) - { - Status = -ENOMEM; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_WEP, Failed!!\n")); - break; - } - Status = copy_from_user(pWepKey, wrq->u.data.pointer, wrq->u.data.length); - if (Status) - { - Status = -EINVAL; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_WEP, Failed (length mismatch)!!\n")); - } - else - { - KeyIdx = pWepKey->KeyIndex & 0x0fffffff; - // KeyIdx must be 0 ~ 3 - if (KeyIdx > 4) - { - Status = -EINVAL; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_WEP, Failed (KeyIdx must be smaller than 4)!!\n")); - } - else - { - UCHAR CipherAlg = 0; - PUCHAR Key; - - // set key material and key length - NdisZeroMemory(pAdapter->SharedKey[BSS0][KeyIdx].Key, 16); - pAdapter->SharedKey[BSS0][KeyIdx].KeyLen = (UCHAR) pWepKey->KeyLength; - NdisMoveMemory(pAdapter->SharedKey[BSS0][KeyIdx].Key, &pWepKey->KeyMaterial, pWepKey->KeyLength); - - switch(pWepKey->KeyLength) - { - case 5: - CipherAlg = CIPHER_WEP64; - break; - case 13: - CipherAlg = CIPHER_WEP128; - break; - default: - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_WEP, only support CIPHER_WEP64(len:5) & CIPHER_WEP128(len:13)!!\n")); - Status = -EINVAL; - break; - } - pAdapter->SharedKey[BSS0][KeyIdx].CipherAlg = CipherAlg; - - // Default key for tx (shared key) - if (pWepKey->KeyIndex & 0x80000000) - { -#ifdef WPA_SUPPLICANT_SUPPORT - // set key material and key length - NdisZeroMemory(pAdapter->StaCfg.DesireSharedKey[KeyIdx].Key, 16); - pAdapter->StaCfg.DesireSharedKey[KeyIdx].KeyLen = (UCHAR) pWepKey->KeyLength; - NdisMoveMemory(pAdapter->StaCfg.DesireSharedKey[KeyIdx].Key, &pWepKey->KeyMaterial, pWepKey->KeyLength); - pAdapter->StaCfg.DesireSharedKeyId = KeyIdx; - pAdapter->StaCfg.DesireSharedKey[KeyIdx].CipherAlg = CipherAlg; -#endif // WPA_SUPPLICANT_SUPPORT // - pAdapter->StaCfg.DefaultKeyId = (UCHAR) KeyIdx; - } - -#ifdef WPA_SUPPLICANT_SUPPORT - if (pAdapter->StaCfg.PortSecured == WPA_802_1X_PORT_SECURED) -#endif // WPA_SUPPLICANT_SUPPORT - { - Key = pAdapter->SharedKey[BSS0][KeyIdx].Key; - - // Set key material and cipherAlg to Asic - AsicAddSharedKeyEntry(pAdapter, BSS0, KeyIdx, CipherAlg, Key, NULL, NULL); - - if (pWepKey->KeyIndex & 0x80000000) - { - PMAC_TABLE_ENTRY pEntry = &pAdapter->MacTab.Content[BSSID_WCID]; - // Assign group key info - RTMPAddWcidAttributeEntry(pAdapter, BSS0, KeyIdx, CipherAlg, NULL); - // Assign pairwise key info - RTMPAddWcidAttributeEntry(pAdapter, BSS0, KeyIdx, CipherAlg, pEntry); - } - } - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_WEP (id=0x%x, Len=%d-byte), %s\n", pWepKey->KeyIndex, pWepKey->KeyLength, (pAdapter->StaCfg.PortSecured == WPA_802_1X_PORT_SECURED) ? "Port Secured":"Port NOT Secured")); - } - } - kfree(pWepKey); - break; -#ifdef WPA_SUPPLICANT_SUPPORT - case OID_SET_COUNTERMEASURES: - if (wrq->u.data.length != sizeof(int)) - Status = -EINVAL; - else - { - int enabled = 0; - Status = copy_from_user(&enabled, wrq->u.data.pointer, wrq->u.data.length); - if (enabled == 1) - pAdapter->StaCfg.bBlockAssoc = TRUE; - else - // WPA MIC error should block association attempt for 60 seconds - pAdapter->StaCfg.bBlockAssoc = FALSE; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_SET_COUNTERMEASURES bBlockAssoc=%s\n", pAdapter->StaCfg.bBlockAssoc ? "TRUE":"FALSE")); - } - break; - case RT_OID_WPA_SUPPLICANT_SUPPORT: - if (wrq->u.data.length != sizeof(UCHAR)) - Status = -EINVAL; - else - { - Status = copy_from_user(&wpa_supplicant_enable, wrq->u.data.pointer, wrq->u.data.length); - pAdapter->StaCfg.WpaSupplicantUP = wpa_supplicant_enable; - DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_WPA_SUPPLICANT_SUPPORT (=%d)\n", pAdapter->StaCfg.WpaSupplicantUP)); - } - break; - case OID_802_11_DEAUTHENTICATION: - if (wrq->u.data.length != sizeof(MLME_DEAUTH_REQ_STRUCT)) - Status = -EINVAL; - else - { - MLME_DEAUTH_REQ_STRUCT *pInfo; - MLME_QUEUE_ELEM *MsgElem = (MLME_QUEUE_ELEM *) kmalloc(sizeof(MLME_QUEUE_ELEM), MEM_ALLOC_FLAG); - - pInfo = (MLME_DEAUTH_REQ_STRUCT *) MsgElem->Msg; - Status = copy_from_user(pInfo, wrq->u.data.pointer, wrq->u.data.length); - MlmeDeauthReqAction(pAdapter, MsgElem); - kfree(MsgElem); - - if (INFRA_ON(pAdapter)) - { - LinkDown(pAdapter, FALSE); - pAdapter->Mlme.AssocMachine.CurrState = ASSOC_IDLE; - } - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_DEAUTHENTICATION (Reason=%d)\n", pInfo->Reason)); - } - break; - case OID_802_11_DROP_UNENCRYPTED: - if (wrq->u.data.length != sizeof(int)) - Status = -EINVAL; - else - { - int enabled = 0; - Status = copy_from_user(&enabled, wrq->u.data.pointer, wrq->u.data.length); - if (enabled == 1) - pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; - else - pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; - NdisAcquireSpinLock(&pAdapter->MacTabLock); - pAdapter->MacTab.Content[BSSID_WCID].PortSecured = pAdapter->StaCfg.PortSecured; - NdisReleaseSpinLock(&pAdapter->MacTabLock); - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_DROP_UNENCRYPTED (=%d)\n", enabled)); - } - break; - case OID_802_11_SET_IEEE8021X: - if (wrq->u.data.length != sizeof(BOOLEAN)) - Status = -EINVAL; - else - { - Status = copy_from_user(&IEEE8021xState, wrq->u.data.pointer, wrq->u.data.length); - pAdapter->StaCfg.IEEE8021X = IEEE8021xState; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_SET_IEEE8021X (=%d)\n", IEEE8021xState)); - } - break; - case OID_802_11_SET_IEEE8021X_REQUIRE_KEY: - if (wrq->u.data.length != sizeof(BOOLEAN)) - Status = -EINVAL; - else - { - Status = copy_from_user(&IEEE8021x_required_keys, wrq->u.data.pointer, wrq->u.data.length); - pAdapter->StaCfg.IEEE8021x_required_keys = IEEE8021x_required_keys; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_SET_IEEE8021X_REQUIRE_KEY (%d)\n", IEEE8021x_required_keys)); - } - break; - case OID_802_11_PMKID: - pPmkId = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); - - if(pPmkId == NULL) { - Status = -ENOMEM; - break; - } - Status = copy_from_user(pPmkId, wrq->u.data.pointer, wrq->u.data.length); - - // check the PMKID information - if (pPmkId->BSSIDInfoCount == 0) - NdisZeroMemory(pAdapter->StaCfg.SavedPMK, sizeof(BSSID_INFO)*PMKID_NO); - else - { - PBSSID_INFO pBssIdInfo; - UINT BssIdx; - UINT CachedIdx; - - for (BssIdx = 0; BssIdx < pPmkId->BSSIDInfoCount; BssIdx++) - { - // point to the indexed BSSID_INFO structure - pBssIdInfo = (PBSSID_INFO) ((PUCHAR) pPmkId + 2 * sizeof(UINT) + BssIdx * sizeof(BSSID_INFO)); - // Find the entry in the saved data base. - for (CachedIdx = 0; CachedIdx < pAdapter->StaCfg.SavedPMKNum; CachedIdx++) - { - // compare the BSSID - if (NdisEqualMemory(pBssIdInfo->BSSID, pAdapter->StaCfg.SavedPMK[CachedIdx].BSSID, sizeof(NDIS_802_11_MAC_ADDRESS))) - break; - } - - // Found, replace it - if (CachedIdx < PMKID_NO) - { - DBGPRINT(RT_DEBUG_OFF, ("Update OID_802_11_PMKID, idx = %d\n", CachedIdx)); - NdisMoveMemory(&pAdapter->StaCfg.SavedPMK[CachedIdx], pBssIdInfo, sizeof(BSSID_INFO)); - pAdapter->StaCfg.SavedPMKNum++; - } - // Not found, replace the last one - else - { - // Randomly replace one - CachedIdx = (pBssIdInfo->BSSID[5] % PMKID_NO); - DBGPRINT(RT_DEBUG_OFF, ("Update OID_802_11_PMKID, idx = %d\n", CachedIdx)); - NdisMoveMemory(&pAdapter->StaCfg.SavedPMK[CachedIdx], pBssIdInfo, sizeof(BSSID_INFO)); - } - } - } - if(pPmkId) - kfree(pPmkId); - break; -#endif // WPA_SUPPLICANT_SUPPORT // - - - -#ifdef SNMP_SUPPORT - case OID_802_11_SHORTRETRYLIMIT: - if (wrq->u.data.length != sizeof(ULONG)) - Status = -EINVAL; - else - { - Status = copy_from_user(&ShortRetryLimit, wrq->u.data.pointer, wrq->u.data.length); - RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); - tx_rty_cfg.field.ShortRtyLimit = ShortRetryLimit; - RTMP_IO_WRITE32(pAdapter, TX_RTY_CFG, tx_rty_cfg.word); - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_SHORTRETRYLIMIT (tx_rty_cfg.field.ShortRetryLimit=%d, ShortRetryLimit=%ld)\n", tx_rty_cfg.field.ShortRtyLimit, ShortRetryLimit)); - } - break; - - case OID_802_11_LONGRETRYLIMIT: - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_LONGRETRYLIMIT \n")); - if (wrq->u.data.length != sizeof(ULONG)) - Status = -EINVAL; - else - { - Status = copy_from_user(&LongRetryLimit, wrq->u.data.pointer, wrq->u.data.length); - RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); - tx_rty_cfg.field.LongRtyLimit = LongRetryLimit; - RTMP_IO_WRITE32(pAdapter, TX_RTY_CFG, tx_rty_cfg.word); - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_LONGRETRYLIMIT (tx_rty_cfg.field.LongRetryLimit= %d,LongRetryLimit=%ld)\n", tx_rty_cfg.field.LongRtyLimit, LongRetryLimit)); - } - break; - - case OID_802_11_WEPDEFAULTKEYVALUE: - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_WEPDEFAULTKEYVALUE\n")); - pKey = kmalloc(wrq->u.data.length, GFP_KERNEL); - Status = copy_from_user(pKey, wrq->u.data.pointer, wrq->u.data.length); - //pKey = &WepKey; - - if ( pKey->Length != wrq->u.data.length) - { - Status = -EINVAL; - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_WEPDEFAULTKEYVALUE, Failed!!\n")); - } - KeyIdx = pKey->KeyIndex & 0x0fffffff; - DBGPRINT(RT_DEBUG_TRACE,("pKey->KeyIndex =%d, pKey->KeyLength=%d\n", pKey->KeyIndex, pKey->KeyLength)); - - // it is a shared key - if (KeyIdx > 4) - Status = -EINVAL; - else - { - pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen = (UCHAR) pKey->KeyLength; - NdisMoveMemory(&pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].Key, &pKey->KeyMaterial, pKey->KeyLength); - if (pKey->KeyIndex & 0x80000000) - { - // Default key for tx (shared key) - pAdapter->StaCfg.DefaultKeyId = (UCHAR) KeyIdx; - } - //RestartAPIsRequired = TRUE; - } - break; - - - case OID_802_11_WEPDEFAULTKEYID: - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_WEPDEFAULTKEYID \n")); - - if (wrq->u.data.length != sizeof(UCHAR)) - Status = -EINVAL; - else - Status = copy_from_user(&pAdapter->StaCfg.DefaultKeyId, wrq->u.data.pointer, wrq->u.data.length); - - break; - - - case OID_802_11_CURRENTCHANNEL: - DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_CURRENTCHANNEL \n")); - if (wrq->u.data.length != sizeof(UCHAR)) - Status = -EINVAL; - else - { - Status = copy_from_user(&ctmp, wrq->u.data.pointer, wrq->u.data.length); - sprintf(&ctmp,"%d", ctmp); - Set_Channel_Proc(pAdapter, &ctmp); - } - break; -#endif - - - - default: - DBGPRINT(RT_DEBUG_TRACE, ("Set::unknown IOCTL's subcmd = 0x%08x\n", cmd)); - Status = -EOPNOTSUPP; - break; - } - - - return Status; -} - -INT RTMPQueryInformation( - IN PRTMP_ADAPTER pAdapter, - IN OUT struct ifreq *rq, - IN INT cmd) -{ - struct iwreq *wrq = (struct iwreq *) rq; - NDIS_802_11_BSSID_LIST_EX *pBssidList = NULL; - PNDIS_WLAN_BSSID_EX pBss; - NDIS_802_11_SSID Ssid; - NDIS_802_11_CONFIGURATION *pConfiguration = NULL; - RT_802_11_LINK_STATUS *pLinkStatus = NULL; - RT_802_11_STA_CONFIG *pStaConfig = NULL; - NDIS_802_11_STATISTICS *pStatistics = NULL; - NDIS_802_11_RTS_THRESHOLD RtsThresh; - NDIS_802_11_FRAGMENTATION_THRESHOLD FragThresh; - NDIS_802_11_POWER_MODE PowerMode; - NDIS_802_11_NETWORK_INFRASTRUCTURE BssType; - RT_802_11_PREAMBLE PreamType; - NDIS_802_11_AUTHENTICATION_MODE AuthMode; - NDIS_802_11_WEP_STATUS WepStatus; - NDIS_MEDIA_STATE MediaState; - ULONG BssBufSize, ulInfo=0, NetworkTypeList[4], apsd = 0; - USHORT BssLen = 0; - PUCHAR pBuf = NULL, pPtr; - INT Status = NDIS_STATUS_SUCCESS; - UINT we_version_compiled; - UCHAR i, Padding = 0; - BOOLEAN RadioState; - UCHAR driverVersion[8]; - OID_SET_HT_PHYMODE *pHTPhyMode = NULL; - - -#ifdef SNMP_SUPPORT - //for snmp, kathy - DefaultKeyIdxValue *pKeyIdxValue; - INT valueLen; - TX_RTY_CFG_STRUC tx_rty_cfg; - ULONG ShortRetryLimit, LongRetryLimit; - UCHAR tmp[64]; -#endif //SNMP - - switch(cmd) - { - case RT_OID_DEVICE_NAME: - wrq->u.data.length = sizeof(STA_NIC_DEVICE_NAME); - Status = copy_to_user(wrq->u.data.pointer, STA_NIC_DEVICE_NAME, wrq->u.data.length); - break; - case RT_OID_VERSION_INFO: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_VERSION_INFO \n")); - wrq->u.data.length = 8*sizeof(UCHAR); - sprintf(&driverVersion[0], "%s", STA_DRIVER_VERSION); - driverVersion[7] = '\0'; - if (copy_to_user(wrq->u.data.pointer, &driverVersion, wrq->u.data.length)) - { - Status = -EFAULT; - } - break; -#ifdef RALINK_ATE - case RT_QUERY_ATE_TXDONE_COUNT: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_QUERY_ATE_TXDONE_COUNT \n")); - wrq->u.data.length = sizeof(UINT32); - if (copy_to_user(wrq->u.data.pointer, &pAdapter->ate.TxDoneCount, wrq->u.data.length)) - { - Status = -EFAULT; - } - break; -#endif // RALINK_ATE // - case OID_802_11_BSSID_LIST: - if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) - { - /* - * Still scanning, indicate the caller should try again. - */ - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_BSSID_LIST (Still scanning)\n")); - return -EAGAIN; - } - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_BSSID_LIST (%d BSS returned)\n",pAdapter->ScanTab.BssNr)); - pAdapter->StaCfg.bScanReqIsFromWebUI = FALSE; - // Claculate total buffer size required - BssBufSize = sizeof(ULONG); - - for (i = 0; i < pAdapter->ScanTab.BssNr; i++) - { - // Align pointer to 4 bytes boundary. - //Padding = 4 - (pAdapter->ScanTab.BssEntry[i].VarIELen & 0x0003); - //if (Padding == 4) - // Padding = 0; - BssBufSize += (sizeof(NDIS_WLAN_BSSID_EX) - 1 + sizeof(NDIS_802_11_FIXED_IEs) + pAdapter->ScanTab.BssEntry[i].VarIELen + Padding); - } - - // For safety issue, we add 256 bytes just in case - BssBufSize += 256; - // Allocate the same size as passed from higher layer - pBuf = kmalloc(BssBufSize, MEM_ALLOC_FLAG); - if(pBuf == NULL) - { - Status = -ENOMEM; - break; - } - // Init 802_11_BSSID_LIST_EX structure - NdisZeroMemory(pBuf, BssBufSize); - pBssidList = (PNDIS_802_11_BSSID_LIST_EX) pBuf; - pBssidList->NumberOfItems = pAdapter->ScanTab.BssNr; - - // Calculate total buffer length - BssLen = 4; // Consist of NumberOfItems - // Point to start of NDIS_WLAN_BSSID_EX - // pPtr = pBuf + sizeof(ULONG); - pPtr = (PUCHAR) &pBssidList->Bssid[0]; - for (i = 0; i < pAdapter->ScanTab.BssNr; i++) - { - pBss = (PNDIS_WLAN_BSSID_EX) pPtr; - NdisMoveMemory(&pBss->MacAddress, &pAdapter->ScanTab.BssEntry[i].Bssid, MAC_ADDR_LEN); - if ((pAdapter->ScanTab.BssEntry[i].Hidden == 1) && (pAdapter->StaCfg.bShowHiddenSSID == FALSE)) - { - // - // We must return this SSID during 4way handshaking, otherwise Aegis will failed to parse WPA infomation - // and then failed to send EAPOl farame. - // - if ((pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) && (pAdapter->StaCfg.PortSecured != WPA_802_1X_PORT_SECURED)) - { - pBss->Ssid.SsidLength = pAdapter->ScanTab.BssEntry[i].SsidLen; - NdisMoveMemory(pBss->Ssid.Ssid, pAdapter->ScanTab.BssEntry[i].Ssid, pAdapter->ScanTab.BssEntry[i].SsidLen); - } - else - pBss->Ssid.SsidLength = 0; - } - else - { - pBss->Ssid.SsidLength = pAdapter->ScanTab.BssEntry[i].SsidLen; - NdisMoveMemory(pBss->Ssid.Ssid, pAdapter->ScanTab.BssEntry[i].Ssid, pAdapter->ScanTab.BssEntry[i].SsidLen); - } - pBss->Privacy = pAdapter->ScanTab.BssEntry[i].Privacy; - pBss->Rssi = pAdapter->ScanTab.BssEntry[i].Rssi - pAdapter->BbpRssiToDbmDelta; - pBss->NetworkTypeInUse = NetworkTypeInUseSanity(&pAdapter->ScanTab.BssEntry[i]); - pBss->Configuration.Length = sizeof(NDIS_802_11_CONFIGURATION); - pBss->Configuration.BeaconPeriod = pAdapter->ScanTab.BssEntry[i].BeaconPeriod; - pBss->Configuration.ATIMWindow = pAdapter->ScanTab.BssEntry[i].AtimWin; - - MAP_CHANNEL_ID_TO_KHZ(pAdapter->ScanTab.BssEntry[i].Channel, pBss->Configuration.DSConfig); - - if (pAdapter->ScanTab.BssEntry[i].BssType == BSS_INFRA) - pBss->InfrastructureMode = Ndis802_11Infrastructure; - else - pBss->InfrastructureMode = Ndis802_11IBSS; - - NdisMoveMemory(pBss->SupportedRates, pAdapter->ScanTab.BssEntry[i].SupRate, pAdapter->ScanTab.BssEntry[i].SupRateLen); - NdisMoveMemory(pBss->SupportedRates + pAdapter->ScanTab.BssEntry[i].SupRateLen, - pAdapter->ScanTab.BssEntry[i].ExtRate, - pAdapter->ScanTab.BssEntry[i].ExtRateLen); - - if (pAdapter->ScanTab.BssEntry[i].VarIELen == 0) - { - pBss->IELength = sizeof(NDIS_802_11_FIXED_IEs); - NdisMoveMemory(pBss->IEs, &pAdapter->ScanTab.BssEntry[i].FixIEs, sizeof(NDIS_802_11_FIXED_IEs)); - pPtr = pPtr + sizeof(NDIS_WLAN_BSSID_EX) - 1 + sizeof(NDIS_802_11_FIXED_IEs); - } - else - { - pBss->IELength = (ULONG)(sizeof(NDIS_802_11_FIXED_IEs) + pAdapter->ScanTab.BssEntry[i].VarIELen); - pPtr = pPtr + sizeof(NDIS_WLAN_BSSID_EX) - 1 + sizeof(NDIS_802_11_FIXED_IEs); - NdisMoveMemory(pBss->IEs, &pAdapter->ScanTab.BssEntry[i].FixIEs, sizeof(NDIS_802_11_FIXED_IEs)); - NdisMoveMemory(pBss->IEs + sizeof(NDIS_802_11_FIXED_IEs), pAdapter->ScanTab.BssEntry[i].VarIEs, pAdapter->ScanTab.BssEntry[i].VarIELen); - pPtr += pAdapter->ScanTab.BssEntry[i].VarIELen; - } - pBss->Length = (ULONG)(sizeof(NDIS_WLAN_BSSID_EX) - 1 + sizeof(NDIS_802_11_FIXED_IEs) + pAdapter->ScanTab.BssEntry[i].VarIELen + Padding); - -#if WIRELESS_EXT < 17 - if ((BssLen + pBss->Length) < wrq->u.data.length) - BssLen += pBss->Length; - else - { - pBssidList->NumberOfItems = i; - break; - } -#else - BssLen += pBss->Length; -#endif - } - -#if WIRELESS_EXT < 17 - wrq->u.data.length = BssLen; -#else - if (BssLen > wrq->u.data.length) - { - kfree(pBssidList); - return -E2BIG; - } - else - wrq->u.data.length = BssLen; -#endif - Status = copy_to_user(wrq->u.data.pointer, pBssidList, BssLen); - kfree(pBssidList); - break; - case OID_802_3_CURRENT_ADDRESS: - wrq->u.data.length = MAC_ADDR_LEN; - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CurrentAddress, wrq->u.data.length); - break; - case OID_GEN_MEDIA_CONNECT_STATUS: - if (pAdapter->IndicateMediaState == NdisMediaStateConnected) - MediaState = NdisMediaStateConnected; - else - MediaState = NdisMediaStateDisconnected; - - wrq->u.data.length = sizeof(NDIS_MEDIA_STATE); - Status = copy_to_user(wrq->u.data.pointer, &MediaState, wrq->u.data.length); - break; - case OID_802_11_BSSID: -#ifdef RALINK_ATE - if (ATE_ON(pAdapter)) - { - DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now\n")); - Status = NDIS_STATUS_RESOURCES; - break; - } -#endif // RALINK_ATE // - if (INFRA_ON(pAdapter) || ADHOC_ON(pAdapter)) - { - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.Bssid, sizeof(NDIS_802_11_MAC_ADDRESS)); - - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_BSSID(=EMPTY)\n")); - Status = -ENOTCONN; - } - break; - case OID_802_11_SSID: - NdisZeroMemory(&Ssid, sizeof(NDIS_802_11_SSID)); - NdisZeroMemory(Ssid.Ssid, MAX_LEN_OF_SSID); - Ssid.SsidLength = pAdapter->CommonCfg.SsidLen; - memcpy(Ssid.Ssid, pAdapter->CommonCfg.Ssid, Ssid.SsidLength); - wrq->u.data.length = sizeof(NDIS_802_11_SSID); - Status = copy_to_user(wrq->u.data.pointer, &Ssid, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_SSID (Len=%d, ssid=%s)\n", Ssid.SsidLength,Ssid.Ssid)); - break; - case RT_OID_802_11_QUERY_LINK_STATUS: - pLinkStatus = (RT_802_11_LINK_STATUS *) kmalloc(sizeof(RT_802_11_LINK_STATUS), MEM_ALLOC_FLAG); - if (pLinkStatus) - { - pLinkStatus->CurrTxRate = RateIdTo500Kbps[pAdapter->CommonCfg.TxRate]; // unit : 500 kbps - pLinkStatus->ChannelQuality = pAdapter->Mlme.ChannelQuality; - pLinkStatus->RxByteCount = pAdapter->RalinkCounters.ReceivedByteCount; - pLinkStatus->TxByteCount = pAdapter->RalinkCounters.TransmittedByteCount; - pLinkStatus->CentralChannel = pAdapter->CommonCfg.CentralChannel; - wrq->u.data.length = sizeof(RT_802_11_LINK_STATUS); - Status = copy_to_user(wrq->u.data.pointer, pLinkStatus, wrq->u.data.length); - kfree(pLinkStatus); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_LINK_STATUS\n")); - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_LINK_STATUS(kmalloc failed)\n")); - Status = -EFAULT; - } - break; - case OID_802_11_CONFIGURATION: - pConfiguration = (NDIS_802_11_CONFIGURATION *) kmalloc(sizeof(NDIS_802_11_CONFIGURATION), MEM_ALLOC_FLAG); - if (pConfiguration) - { - pConfiguration->Length = sizeof(NDIS_802_11_CONFIGURATION); - pConfiguration->BeaconPeriod = pAdapter->CommonCfg.BeaconPeriod; - pConfiguration->ATIMWindow = pAdapter->StaActive.AtimWin; - MAP_CHANNEL_ID_TO_KHZ(pAdapter->CommonCfg.Channel, pConfiguration->DSConfig); - wrq->u.data.length = sizeof(NDIS_802_11_CONFIGURATION); - Status = copy_to_user(wrq->u.data.pointer, pConfiguration, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_CONFIGURATION(BeaconPeriod=%ld,AtimW=%ld,Channel=%d) \n", - pConfiguration->BeaconPeriod, pConfiguration->ATIMWindow, pAdapter->CommonCfg.Channel)); - kfree(pConfiguration); - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_CONFIGURATION(kmalloc failed)\n")); - Status = -EFAULT; - } - break; - case RT_OID_802_11_SNR_0: - if ((pAdapter->StaCfg.LastSNR0 > 0)) - { - ulInfo = ((0xeb - pAdapter->StaCfg.LastSNR0) * 3) / 16 ; - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_SNR_0(0x=%lx)\n", ulInfo)); - } - else - Status = -EFAULT; - break; - case RT_OID_802_11_SNR_1: - if ((pAdapter->Antenna.field.RxPath > 1) && - (pAdapter->StaCfg.LastSNR1 > 0)) - { - ulInfo = ((0xeb - pAdapter->StaCfg.LastSNR1) * 3) / 16 ; - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE,("Query::RT_OID_802_11_SNR_1(0x=%lx)\n",ulInfo)); - } - else - Status = -EFAULT; - DBGPRINT(RT_DEBUG_TRACE,("Query::RT_OID_802_11_SNR_1(pAdapter->StaCfg.LastSNR1=%d)\n",pAdapter->StaCfg.LastSNR1)); - break; - case OID_802_11_RSSI_TRIGGER: - ulInfo = pAdapter->StaCfg.RssiSample.LastRssi0 - pAdapter->BbpRssiToDbmDelta; - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_RSSI_TRIGGER(=%ld)\n", ulInfo)); - break; - case OID_802_11_RSSI: - case RT_OID_802_11_RSSI: - ulInfo = pAdapter->StaCfg.RssiSample.LastRssi0; - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - break; - case RT_OID_802_11_RSSI_1: - ulInfo = pAdapter->StaCfg.RssiSample.LastRssi1; - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - break; - case RT_OID_802_11_RSSI_2: - ulInfo = pAdapter->StaCfg.RssiSample.LastRssi2; - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - break; - case OID_802_11_STATISTICS: - pStatistics = (NDIS_802_11_STATISTICS *) kmalloc(sizeof(NDIS_802_11_STATISTICS), MEM_ALLOC_FLAG); - if (pStatistics) - { - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_STATISTICS \n")); - // add the most up-to-date h/w raw counters into software counters - NICUpdateRawCounters(pAdapter); - - // Sanity check for calculation of sucessful count - if (pAdapter->WlanCounters.TransmittedFragmentCount.QuadPart < pAdapter->WlanCounters.RetryCount.QuadPart) - pAdapter->WlanCounters.TransmittedFragmentCount.QuadPart = pAdapter->WlanCounters.RetryCount.QuadPart; - - pStatistics->TransmittedFragmentCount.QuadPart = pAdapter->WlanCounters.TransmittedFragmentCount.QuadPart; - pStatistics->MulticastTransmittedFrameCount.QuadPart = pAdapter->WlanCounters.MulticastTransmittedFrameCount.QuadPart; - pStatistics->FailedCount.QuadPart = pAdapter->WlanCounters.FailedCount.QuadPart; - pStatistics->RetryCount.QuadPart = pAdapter->WlanCounters.RetryCount.QuadPart; - pStatistics->MultipleRetryCount.QuadPart = pAdapter->WlanCounters.MultipleRetryCount.QuadPart; - pStatistics->RTSSuccessCount.QuadPart = pAdapter->WlanCounters.RTSSuccessCount.QuadPart; - pStatistics->RTSFailureCount.QuadPart = pAdapter->WlanCounters.RTSFailureCount.QuadPart; - pStatistics->ACKFailureCount.QuadPart = pAdapter->WlanCounters.ACKFailureCount.QuadPart; - pStatistics->FrameDuplicateCount.QuadPart = pAdapter->WlanCounters.FrameDuplicateCount.QuadPart; - pStatistics->ReceivedFragmentCount.QuadPart = pAdapter->WlanCounters.ReceivedFragmentCount.QuadPart; - pStatistics->MulticastReceivedFrameCount.QuadPart = pAdapter->WlanCounters.MulticastReceivedFrameCount.QuadPart; -#ifdef DBG - pStatistics->FCSErrorCount = pAdapter->RalinkCounters.RealFcsErrCount; -#else - pStatistics->FCSErrorCount.QuadPart = pAdapter->WlanCounters.FCSErrorCount.QuadPart; - pStatistics->FrameDuplicateCount.u.LowPart = pAdapter->WlanCounters.FrameDuplicateCount.u.LowPart / 100; -#endif - wrq->u.data.length = sizeof(NDIS_802_11_STATISTICS); - Status = copy_to_user(wrq->u.data.pointer, pStatistics, wrq->u.data.length); - kfree(pStatistics); - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_STATISTICS(kmalloc failed)\n")); - Status = -EFAULT; - } - break; - case OID_GEN_RCV_OK: - ulInfo = pAdapter->Counters8023.GoodReceives; - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - break; - case OID_GEN_RCV_NO_BUFFER: - ulInfo = pAdapter->Counters8023.RxNoBuffer; - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - break; - case RT_OID_802_11_PHY_MODE: - ulInfo = (ULONG)pAdapter->CommonCfg.PhyMode; - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_PHY_MODE (=%ld)\n", ulInfo)); - break; - case RT_OID_802_11_STA_CONFIG: - pStaConfig = (RT_802_11_STA_CONFIG *) kmalloc(sizeof(RT_802_11_STA_CONFIG), MEM_ALLOC_FLAG); - if (pStaConfig) - { - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_STA_CONFIG\n")); - pStaConfig->EnableTxBurst = pAdapter->CommonCfg.bEnableTxBurst; - pStaConfig->EnableTurboRate = 0; - pStaConfig->UseBGProtection = pAdapter->CommonCfg.UseBGProtection; - pStaConfig->UseShortSlotTime = pAdapter->CommonCfg.bUseShortSlotTime; - //pStaConfig->AdhocMode = pAdapter->StaCfg.AdhocMode; - pStaConfig->HwRadioStatus = (pAdapter->StaCfg.bHwRadio == TRUE) ? 1 : 0; - pStaConfig->Rsv1 = 0; - pStaConfig->SystemErrorBitmap = pAdapter->SystemErrorBitmap; - wrq->u.data.length = sizeof(RT_802_11_STA_CONFIG); - Status = copy_to_user(wrq->u.data.pointer, pStaConfig, wrq->u.data.length); - kfree(pStaConfig); - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_STA_CONFIG(kmalloc failed)\n")); - Status = -EFAULT; - } - break; - case OID_802_11_RTS_THRESHOLD: - RtsThresh = pAdapter->CommonCfg.RtsThreshold; - wrq->u.data.length = sizeof(RtsThresh); - Status = copy_to_user(wrq->u.data.pointer, &RtsThresh, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_RTS_THRESHOLD(=%ld)\n", RtsThresh)); - break; - case OID_802_11_FRAGMENTATION_THRESHOLD: - FragThresh = pAdapter->CommonCfg.FragmentThreshold; - if (pAdapter->CommonCfg.bUseZeroToDisableFragment == TRUE) - FragThresh = 0; - wrq->u.data.length = sizeof(FragThresh); - Status = copy_to_user(wrq->u.data.pointer, &FragThresh, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_FRAGMENTATION_THRESHOLD(=%ld)\n", FragThresh)); - break; - case OID_802_11_POWER_MODE: - PowerMode = pAdapter->StaCfg.WindowsPowerMode; - wrq->u.data.length = sizeof(PowerMode); - Status = copy_to_user(wrq->u.data.pointer, &PowerMode, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_POWER_MODE(=%d)\n", PowerMode)); - break; - case RT_OID_802_11_RADIO: - RadioState = (BOOLEAN) pAdapter->StaCfg.bSwRadio; - wrq->u.data.length = sizeof(RadioState); - Status = copy_to_user(wrq->u.data.pointer, &RadioState, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_RADIO (=%d)\n", RadioState)); - break; - case OID_802_11_INFRASTRUCTURE_MODE: - if (pAdapter->StaCfg.BssType == BSS_ADHOC) - BssType = Ndis802_11IBSS; - else if (pAdapter->StaCfg.BssType == BSS_INFRA) - BssType = Ndis802_11Infrastructure; - else if (pAdapter->StaCfg.BssType == BSS_MONITOR) - BssType = Ndis802_11Monitor; - else - BssType = Ndis802_11AutoUnknown; - - wrq->u.data.length = sizeof(BssType); - Status = copy_to_user(wrq->u.data.pointer, &BssType, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_INFRASTRUCTURE_MODE(=%d)\n", BssType)); - break; - case RT_OID_802_11_PREAMBLE: - PreamType = pAdapter->CommonCfg.TxPreamble; - wrq->u.data.length = sizeof(PreamType); - Status = copy_to_user(wrq->u.data.pointer, &PreamType, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_PREAMBLE(=%d)\n", PreamType)); - break; - case OID_802_11_AUTHENTICATION_MODE: - AuthMode = pAdapter->StaCfg.AuthMode; - wrq->u.data.length = sizeof(AuthMode); - Status = copy_to_user(wrq->u.data.pointer, &AuthMode, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_AUTHENTICATION_MODE(=%d)\n", AuthMode)); - break; - case OID_802_11_WEP_STATUS: - WepStatus = pAdapter->StaCfg.WepStatus; - wrq->u.data.length = sizeof(WepStatus); - Status = copy_to_user(wrq->u.data.pointer, &WepStatus, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_WEP_STATUS(=%d)\n", WepStatus)); - break; - case OID_802_11_TX_POWER_LEVEL: - wrq->u.data.length = sizeof(ULONG); - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.TxPower, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_TX_POWER_LEVEL %x\n",pAdapter->CommonCfg.TxPower)); - break; - case RT_OID_802_11_TX_POWER_LEVEL_1: - wrq->u.data.length = sizeof(ULONG); - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.TxPowerPercentage, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_TX_POWER_LEVEL_1 (=%ld)\n", pAdapter->CommonCfg.TxPowerPercentage)); - break; - case OID_802_11_NETWORK_TYPES_SUPPORTED: - if ((pAdapter->RfIcType == RFIC_2850) || (pAdapter->RfIcType == RFIC_2750)) - { - NetworkTypeList[0] = 3; // NumberOfItems = 3 - NetworkTypeList[1] = Ndis802_11DS; // NetworkType[1] = 11b - NetworkTypeList[2] = Ndis802_11OFDM24; // NetworkType[2] = 11g - NetworkTypeList[3] = Ndis802_11OFDM5; // NetworkType[3] = 11a - wrq->u.data.length = 16; - Status = copy_to_user(wrq->u.data.pointer, &NetworkTypeList[0], wrq->u.data.length); - } - else - { - NetworkTypeList[0] = 2; // NumberOfItems = 2 - NetworkTypeList[1] = Ndis802_11DS; // NetworkType[1] = 11b - NetworkTypeList[2] = Ndis802_11OFDM24; // NetworkType[2] = 11g - wrq->u.data.length = 12; - Status = copy_to_user(wrq->u.data.pointer, &NetworkTypeList[0], wrq->u.data.length); - } - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_NETWORK_TYPES_SUPPORTED\n")); - break; - case OID_802_11_NETWORK_TYPE_IN_USE: - wrq->u.data.length = sizeof(ULONG); - if (pAdapter->CommonCfg.PhyMode == PHY_11A) - ulInfo = Ndis802_11OFDM5; - else if ((pAdapter->CommonCfg.PhyMode == PHY_11BG_MIXED) || (pAdapter->CommonCfg.PhyMode == PHY_11G)) - ulInfo = Ndis802_11OFDM24; - else - ulInfo = Ndis802_11DS; - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - break; - case RT_OID_802_11_QUERY_LAST_RX_RATE: - ulInfo = (ULONG)pAdapter->LastRxRate; - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_LAST_RX_RATE (=%ld)\n", ulInfo)); - break; - case RT_OID_802_11_QUERY_LAST_TX_RATE: - //ulInfo = (ULONG)pAdapter->LastTxRate; - ulInfo = (ULONG)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.word; - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_LAST_TX_RATE (=%lx)\n", ulInfo)); - break; - case RT_OID_802_11_QUERY_EEPROM_VERSION: - wrq->u.data.length = sizeof(ULONG); - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->EepromVersion, wrq->u.data.length); - break; - case RT_OID_802_11_QUERY_FIRMWARE_VERSION: - wrq->u.data.length = sizeof(ULONG); - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->FirmwareVersion, wrq->u.data.length); - break; - case RT_OID_802_11_QUERY_NOISE_LEVEL: - wrq->u.data.length = sizeof(UCHAR); - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->BbpWriteLatch[66], wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_NOISE_LEVEL (=%d)\n", pAdapter->BbpWriteLatch[66])); - break; - case RT_OID_802_11_EXTRA_INFO: - wrq->u.data.length = sizeof(ULONG); - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->ExtraInfo, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_EXTRA_INFO (=%ld)\n", pAdapter->ExtraInfo)); - break; - case RT_OID_WE_VERSION_COMPILED: - wrq->u.data.length = sizeof(UINT); - we_version_compiled = WIRELESS_EXT; - Status = copy_to_user(wrq->u.data.pointer, &we_version_compiled, wrq->u.data.length); - break; - case RT_OID_802_11_QUERY_APSD_SETTING: - apsd = (pAdapter->CommonCfg.bAPSDCapable | (pAdapter->CommonCfg.bAPSDAC_BE << 1) | (pAdapter->CommonCfg.bAPSDAC_BK << 2) - | (pAdapter->CommonCfg.bAPSDAC_VI << 3) | (pAdapter->CommonCfg.bAPSDAC_VO << 4) | (pAdapter->CommonCfg.MaxSPLength << 5)); - - wrq->u.data.length = sizeof(ULONG); - Status = copy_to_user(wrq->u.data.pointer, &apsd, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_APSD_SETTING (=0x%lx,APSDCap=%d,AC_BE=%d,AC_BK=%d,AC_VI=%d,AC_VO=%d,MAXSPLen=%d)\n", - apsd,pAdapter->CommonCfg.bAPSDCapable,pAdapter->CommonCfg.bAPSDAC_BE,pAdapter->CommonCfg.bAPSDAC_BK,pAdapter->CommonCfg.bAPSDAC_VI,pAdapter->CommonCfg.bAPSDAC_VO,pAdapter->CommonCfg.MaxSPLength)); - break; - case RT_OID_802_11_QUERY_APSD_PSM: - wrq->u.data.length = sizeof(ULONG); - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.bAPSDForcePowerSave, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_APSD_PSM (=%d)\n", pAdapter->CommonCfg.bAPSDForcePowerSave)); - break; - case RT_OID_802_11_QUERY_WMM: - wrq->u.data.length = sizeof(BOOLEAN); - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.bWmmCapable, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_WMM (=%d)\n", pAdapter->CommonCfg.bWmmCapable)); - break; -#ifdef WPA_SUPPLICANT_SUPPORT - case RT_OID_NEW_DRIVER: - { - UCHAR enabled = 1; - wrq->u.data.length = sizeof(UCHAR); - Status = copy_to_user(wrq->u.data.pointer, &enabled, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_NEW_DRIVER (=%d)\n", enabled)); - } - break; - case RT_OID_WPA_SUPPLICANT_SUPPORT: - wrq->u.data.length = sizeof(UCHAR); - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->StaCfg.WpaSupplicantUP, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_WPA_SUPPLICANT_SUPPORT (=%d)\n", pAdapter->StaCfg.WpaSupplicantUP)); - break; -#endif // WPA_SUPPLICANT_SUPPORT // - - case RT_OID_DRIVER_DEVICE_NAME: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_DRIVER_DEVICE_NAME \n")); - wrq->u.data.length = 16; - if (copy_to_user(wrq->u.data.pointer, pAdapter->StaCfg.dev_name, wrq->u.data.length)) - { - Status = -EFAULT; - } - break; - case RT_OID_802_11_QUERY_HT_PHYMODE: - pHTPhyMode = (OID_SET_HT_PHYMODE *) kmalloc(sizeof(OID_SET_HT_PHYMODE), MEM_ALLOC_FLAG); - if (pHTPhyMode) - { - pHTPhyMode->PhyMode = pAdapter->CommonCfg.PhyMode; - pHTPhyMode->HtMode = (UCHAR)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.field.MODE; - pHTPhyMode->BW = (UCHAR)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.field.BW; - pHTPhyMode->MCS= (UCHAR)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.field.MCS; - pHTPhyMode->SHORTGI= (UCHAR)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.field.ShortGI; - pHTPhyMode->STBC= (UCHAR)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.field.STBC; - - pHTPhyMode->ExtOffset = ((pAdapter->CommonCfg.CentralChannel < pAdapter->CommonCfg.Channel) ? (EXTCHA_BELOW) : (EXTCHA_ABOVE)); - wrq->u.data.length = sizeof(OID_SET_HT_PHYMODE); - if (copy_to_user(wrq->u.data.pointer, pHTPhyMode, wrq->u.data.length)) - { - Status = -EFAULT; - } - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_HT_PHYMODE (PhyMode = %d, MCS =%d, BW = %d, STBC = %d, ExtOffset=%d)\n", - pHTPhyMode->HtMode, pHTPhyMode->MCS, pHTPhyMode->BW, pHTPhyMode->STBC, pHTPhyMode->ExtOffset)); - DBGPRINT(RT_DEBUG_TRACE, (" MlmeUpdateTxRates (.word = %x )\n", pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.word)); - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_STA_CONFIG(kmalloc failed)\n")); - Status = -EFAULT; - } - break; - case RT_OID_802_11_COUNTRY_REGION: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_COUNTRY_REGION \n")); - wrq->u.data.length = sizeof(ulInfo); - ulInfo = pAdapter->CommonCfg.CountryRegionForABand; - ulInfo = (ulInfo << 8)|(pAdapter->CommonCfg.CountryRegion); - if (copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length)) - { - Status = -EFAULT; - } - break; - case RT_OID_802_11_QUERY_DAT_HT_PHYMODE: - pHTPhyMode = (OID_SET_HT_PHYMODE *) kmalloc(sizeof(OID_SET_HT_PHYMODE), MEM_ALLOC_FLAG); - if (pHTPhyMode) - { - pHTPhyMode->PhyMode = pAdapter->CommonCfg.PhyMode; - pHTPhyMode->HtMode = (UCHAR)pAdapter->CommonCfg.RegTransmitSetting.field.HTMODE; - pHTPhyMode->BW = (UCHAR)pAdapter->CommonCfg.RegTransmitSetting.field.BW; - pHTPhyMode->MCS= (UCHAR)pAdapter->StaCfg.DesiredTransmitSetting.field.MCS; - pHTPhyMode->SHORTGI= (UCHAR)pAdapter->CommonCfg.RegTransmitSetting.field.ShortGI; - pHTPhyMode->STBC= (UCHAR)pAdapter->CommonCfg.RegTransmitSetting.field.STBC; - - wrq->u.data.length = sizeof(OID_SET_HT_PHYMODE); - if (copy_to_user(wrq->u.data.pointer, pHTPhyMode, wrq->u.data.length)) - { - Status = -EFAULT; - } - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_HT_PHYMODE (PhyMode = %d, MCS =%d, BW = %d, STBC = %d, ExtOffset=%d)\n", - pHTPhyMode->HtMode, pHTPhyMode->MCS, pHTPhyMode->BW, pHTPhyMode->STBC, pHTPhyMode->ExtOffset)); - DBGPRINT(RT_DEBUG_TRACE, (" MlmeUpdateTxRates (.word = %x )\n", pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.word)); - } - else - { - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_STA_CONFIG(kmalloc failed)\n")); - Status = -EFAULT; - } - break; - case RT_OID_QUERY_MULTIPLE_CARD_SUPPORT: - wrq->u.data.length = sizeof(UCHAR); - i = 0; -#ifdef MULTIPLE_CARD_SUPPORT - i = 1; -#endif // MULTIPLE_CARD_SUPPORT // - if (copy_to_user(wrq->u.data.pointer, &i, wrq->u.data.length)) - { - Status = -EFAULT; - } - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_QUERY_MULTIPLE_CARD_SUPPORT(=%d) \n", i)); - break; -#ifdef SNMP_SUPPORT - case RT_OID_802_11_MAC_ADDRESS: - wrq->u.data.length = MAC_ADDR_LEN; - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CurrentAddress, wrq->u.data.length); - break; - - case RT_OID_802_11_MANUFACTUREROUI: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_MANUFACTUREROUI \n")); - wrq->u.data.length = ManufacturerOUI_LEN; - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CurrentAddress, wrq->u.data.length); - break; - - case RT_OID_802_11_MANUFACTURERNAME: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_MANUFACTURERNAME \n")); - wrq->u.data.length = strlen(ManufacturerNAME); - Status = copy_to_user(wrq->u.data.pointer, ManufacturerNAME, wrq->u.data.length); - break; - - case RT_OID_802_11_RESOURCETYPEIDNAME: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_RESOURCETYPEIDNAME \n")); - wrq->u.data.length = strlen(ResourceTypeIdName); - Status = copy_to_user(wrq->u.data.pointer, ResourceTypeIdName, wrq->u.data.length); - break; - - case RT_OID_802_11_PRIVACYOPTIONIMPLEMENTED: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_PRIVACYOPTIONIMPLEMENTED \n")); - ulInfo = 1; // 1 is support wep else 2 is not support. - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - break; - - case RT_OID_802_11_POWERMANAGEMENTMODE: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_POWERMANAGEMENTMODE \n")); - if (pAdapter->StaCfg.Psm == PSMP_ACTION) - ulInfo = 1; // 1 is power active else 2 is power save. - else - ulInfo = 2; - - wrq->u.data.length = sizeof(ulInfo); - Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); - break; - - case OID_802_11_WEPDEFAULTKEYVALUE: - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_WEPDEFAULTKEYVALUE \n")); - //KeyIdxValue.KeyIdx = pAd->PortCfg.MBSSID[pAd->IoctlIF].DefaultKeyId; - pKeyIdxValue = wrq->u.data.pointer; - DBGPRINT(RT_DEBUG_TRACE,("KeyIdxValue.KeyIdx = %d, \n",pKeyIdxValue->KeyIdx)); - valueLen = pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen; - NdisMoveMemory(pKeyIdxValue->Value, - &pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].Key, - valueLen); - pKeyIdxValue->Value[valueLen]='\0'; - - wrq->u.data.length = sizeof(DefaultKeyIdxValue); - - Status = copy_to_user(wrq->u.data.pointer, pKeyIdxValue, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE,("DefaultKeyId = %d, total len = %d, str len=%d, KeyValue= %02x %02x %02x %02x \n", pAdapter->StaCfg.DefaultKeyId, wrq->u.data.length, pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen, - pAdapter->SharedKey[BSS0][0].Key[0], - pAdapter->SharedKey[BSS0][1].Key[0], - pAdapter->SharedKey[BSS0][2].Key[0], - pAdapter->SharedKey[BSS0][3].Key[0])); - break; - - case OID_802_11_WEPDEFAULTKEYID: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_WEPDEFAULTKEYID \n")); - wrq->u.data.length = sizeof(UCHAR); - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->StaCfg.DefaultKeyId, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("DefaultKeyId =%d \n", pAdapter->StaCfg.DefaultKeyId)); - break; - - case RT_OID_802_11_WEPKEYMAPPINGLENGTH: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_WEPKEYMAPPINGLENGTH \n")); - wrq->u.data.length = sizeof(UCHAR); - Status = copy_to_user(wrq->u.data.pointer, - &pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen, - wrq->u.data.length); - break; - - case OID_802_11_SHORTRETRYLIMIT: - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_SHORTRETRYLIMIT \n")); - wrq->u.data.length = sizeof(ULONG); - RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); - ShortRetryLimit = tx_rty_cfg.field.ShortRtyLimit; - DBGPRINT(RT_DEBUG_TRACE, ("ShortRetryLimit =%ld, tx_rty_cfg.field.ShortRetryLimit=%d\n", ShortRetryLimit, tx_rty_cfg.field.ShortRtyLimit)); - Status = copy_to_user(wrq->u.data.pointer, &ShortRetryLimit, wrq->u.data.length); - break; - - case OID_802_11_LONGRETRYLIMIT: - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_LONGRETRYLIMIT \n")); - wrq->u.data.length = sizeof(ULONG); - RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); - LongRetryLimit = tx_rty_cfg.field.LongRtyLimit; - DBGPRINT(RT_DEBUG_TRACE, ("LongRetryLimit =%ld, tx_rty_cfg.field.LongRtyLimit=%d\n", LongRetryLimit, tx_rty_cfg.field.LongRtyLimit)); - Status = copy_to_user(wrq->u.data.pointer, &LongRetryLimit, wrq->u.data.length); - break; - - case RT_OID_802_11_PRODUCTID: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_PRODUCTID \n")); - -#ifdef RT2870 - sprintf(tmp, "%04x %04x\n", ((POS_COOKIE)pAdapter->OS_Cookie)->pUsb_Dev->descriptor.idVendor ,((POS_COOKIE)pAdapter->OS_Cookie)->pUsb_Dev->descriptor.idProduct); - -#endif // RT2870 // - wrq->u.data.length = strlen(tmp); - Status = copy_to_user(wrq->u.data.pointer, tmp, wrq->u.data.length); - break; - - case RT_OID_802_11_MANUFACTUREID: - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_MANUFACTUREID \n")); - wrq->u.data.length = strlen(ManufacturerNAME); - Status = copy_to_user(wrq->u.data.pointer, ManufacturerNAME, wrq->u.data.length); - break; - - case OID_802_11_CURRENTCHANNEL: - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_CURRENTCHANNEL \n")); - wrq->u.data.length = sizeof(UCHAR); - DBGPRINT(RT_DEBUG_TRACE, ("sizeof UCHAR=%d, channel=%d \n", sizeof(UCHAR), pAdapter->CommonCfg.Channel)); - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.Channel, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Status=%d\n", Status)); - break; -#endif //SNMP_SUPPORT - - case OID_802_11_BUILD_CHANNEL_EX: - { - UCHAR value; - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_BUILD_CHANNEL_EX \n")); - wrq->u.data.length = sizeof(UCHAR); -#ifdef EXT_BUILD_CHANNEL_LIST - DBGPRINT(RT_DEBUG_TRACE, ("Support EXT_BUILD_CHANNEL_LIST.\n")); - value = 1; -#else - DBGPRINT(RT_DEBUG_TRACE, ("Doesn't support EXT_BUILD_CHANNEL_LIST.\n")); - value = 0; -#endif // EXT_BUILD_CHANNEL_LIST // - Status = copy_to_user(wrq->u.data.pointer, &value, 1); - DBGPRINT(RT_DEBUG_TRACE, ("Status=%d\n", Status)); - } - break; - - case OID_802_11_GET_CH_LIST: - { - PRT_CHANNEL_LIST_INFO pChListBuf; - - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_GET_CH_LIST \n")); - if (pAdapter->ChannelListNum == 0) - { - wrq->u.data.length = 0; - break; - } - - pChListBuf = (RT_CHANNEL_LIST_INFO *) kmalloc(sizeof(RT_CHANNEL_LIST_INFO), MEM_ALLOC_FLAG); - if (pChListBuf == NULL) - { - wrq->u.data.length = 0; - break; - } - - pChListBuf->ChannelListNum = pAdapter->ChannelListNum; - for (i = 0; i < pChListBuf->ChannelListNum; i++) - pChListBuf->ChannelList[i] = pAdapter->ChannelList[i].Channel; - - wrq->u.data.length = sizeof(RT_CHANNEL_LIST_INFO); - Status = copy_to_user(wrq->u.data.pointer, pChListBuf, sizeof(RT_CHANNEL_LIST_INFO)); - DBGPRINT(RT_DEBUG_TRACE, ("Status=%d\n", Status)); - - if (pChListBuf) - kfree(pChListBuf); - } - break; - - case OID_802_11_GET_COUNTRY_CODE: - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_GET_COUNTRY_CODE \n")); - wrq->u.data.length = 2; - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.CountryCode, 2); - DBGPRINT(RT_DEBUG_TRACE, ("Status=%d\n", Status)); - break; - - case OID_802_11_GET_CHANNEL_GEOGRAPHY: - DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_GET_CHANNEL_GEOGRAPHY \n")); - wrq->u.data.length = 1; - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.Geography, 1); - DBGPRINT(RT_DEBUG_TRACE, ("Status=%d\n", Status)); - break; - - -#ifdef QOS_DLS_SUPPORT - case RT_OID_802_11_QUERY_DLS: - wrq->u.data.length = sizeof(BOOLEAN); - Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.bDLSCapable, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_DLS(=%d)\n", pAdapter->CommonCfg.bDLSCapable)); - break; - - case RT_OID_802_11_QUERY_DLS_PARAM: - { - PRT_802_11_DLS_INFO pDlsInfo = kmalloc(sizeof(RT_802_11_DLS_INFO), GFP_ATOMIC); - if (pDlsInfo == NULL) - break; - - for (i=0; iEntry[i], &pAdapter->StaCfg.DLSEntry[i], sizeof(RT_802_11_DLS_UI)); - } - - pDlsInfo->num = MAX_NUM_OF_DLS_ENTRY; - wrq->u.data.length = sizeof(RT_802_11_DLS_INFO); - Status = copy_to_user(wrq->u.data.pointer, pDlsInfo, wrq->u.data.length); - DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_DLS_PARAM\n")); - - if (pDlsInfo) - kfree(pDlsInfo); - } - break; -#endif // QOS_DLS_SUPPORT // - default: - DBGPRINT(RT_DEBUG_TRACE, ("Query::unknown IOCTL's subcmd = 0x%08x\n", cmd)); - Status = -EOPNOTSUPP; - break; - } - return Status; -} - -INT rt28xx_sta_ioctl( - IN struct net_device *net_dev, - IN OUT struct ifreq *rq, - IN INT cmd) -{ - POS_COOKIE pObj; - VIRTUAL_ADAPTER *pVirtualAd = NULL; - RTMP_ADAPTER *pAd = NULL; - struct iwreq *wrq = (struct iwreq *) rq; - BOOLEAN StateMachineTouched = FALSE; - INT Status = NDIS_STATUS_SUCCESS; - USHORT subcmd; - - if (net_dev->priv_flags == INT_MAIN) - { - pAd = net_dev->ml_priv; - } - else - { - pVirtualAd = net_dev->ml_priv; - pAd = pVirtualAd->RtmpDev->ml_priv; - } - pObj = (POS_COOKIE) pAd->OS_Cookie; - - if (pAd == NULL) - { - /* if 1st open fail, pAd will be free; - So the net_dev->ml_priv will be NULL in 2rd open */ - return -ENETDOWN; - } - - //check if the interface is down - if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) - { -#ifdef CONFIG_APSTA_MIXED_SUPPORT - if (wrq->u.data.pointer == NULL) - { - return Status; - } - - if (strstr(wrq->u.data.pointer, "OpMode") == NULL) -#endif // CONFIG_APSTA_MIXED_SUPPORT // - { - DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); - return -ENETDOWN; - } - } - - { // determine this ioctl command is comming from which interface. - pObj->ioctl_if_type = INT_MAIN; - pObj->ioctl_if = MAIN_MBSSID; - } - - switch(cmd) - { -#ifdef RALINK_ATE -#ifdef RALINK_28xx_QA - case RTPRIV_IOCTL_ATE: - { - RtmpDoAte(pAd, wrq); - } - break; -#endif // RALINK_28xx_QA // -#endif // RALINK_ATE // - case SIOCGIFHWADDR: - DBGPRINT(RT_DEBUG_TRACE, ("IOCTL::SIOCGIFHWADDR\n")); - memcpy(wrq->u.name, pAd->CurrentAddress, ETH_ALEN); - break; - case SIOCGIWNAME: - { - char *name=&wrq->u.name[0]; - rt_ioctl_giwname(net_dev, NULL, name, NULL); - break; - } - case SIOCGIWESSID: //Get ESSID - { - struct iw_point *essid=&wrq->u.essid; - rt_ioctl_giwessid(net_dev, NULL, essid, essid->pointer); - break; - } - case SIOCSIWESSID: //Set ESSID - { - struct iw_point *essid=&wrq->u.essid; - rt_ioctl_siwessid(net_dev, NULL, essid, essid->pointer); - break; - } - case SIOCSIWNWID: // set network id (the cell) - case SIOCGIWNWID: // get network id - Status = -EOPNOTSUPP; - break; - case SIOCSIWFREQ: //set channel/frequency (Hz) - { - struct iw_freq *freq=&wrq->u.freq; - rt_ioctl_siwfreq(net_dev, NULL, freq, NULL); - break; - } - case SIOCGIWFREQ: // get channel/frequency (Hz) - { - struct iw_freq *freq=&wrq->u.freq; - rt_ioctl_giwfreq(net_dev, NULL, freq, NULL); - break; - } - case SIOCSIWNICKN: //set node name/nickname - { - struct iw_point *data=&wrq->u.data; - rt_ioctl_siwnickn(net_dev, NULL, data, NULL); - break; - } - case SIOCGIWNICKN: //get node name/nickname - { - struct iw_point *data=&wrq->u.data; - rt_ioctl_giwnickn(net_dev, NULL, data, NULL); - break; - } - case SIOCGIWRATE: //get default bit rate (bps) - rt_ioctl_giwrate(net_dev, NULL, &wrq->u, NULL); - break; - case SIOCSIWRATE: //set default bit rate (bps) - rt_ioctl_siwrate(net_dev, NULL, &wrq->u, NULL); - break; - case SIOCGIWRTS: // get RTS/CTS threshold (bytes) - { - struct iw_param *rts=&wrq->u.rts; - rt_ioctl_giwrts(net_dev, NULL, rts, NULL); - break; - } - case SIOCSIWRTS: //set RTS/CTS threshold (bytes) - { - struct iw_param *rts=&wrq->u.rts; - rt_ioctl_siwrts(net_dev, NULL, rts, NULL); - break; - } - case SIOCGIWFRAG: //get fragmentation thr (bytes) - { - struct iw_param *frag=&wrq->u.frag; - rt_ioctl_giwfrag(net_dev, NULL, frag, NULL); - break; - } - case SIOCSIWFRAG: //set fragmentation thr (bytes) - { - struct iw_param *frag=&wrq->u.frag; - rt_ioctl_siwfrag(net_dev, NULL, frag, NULL); - break; - } - case SIOCGIWENCODE: //get encoding token & mode - { - struct iw_point *erq=&wrq->u.encoding; - if(erq->pointer) - rt_ioctl_giwencode(net_dev, NULL, erq, erq->pointer); - break; - } - case SIOCSIWENCODE: //set encoding token & mode - { - struct iw_point *erq=&wrq->u.encoding; - if(erq->pointer) - rt_ioctl_siwencode(net_dev, NULL, erq, erq->pointer); - break; - } - case SIOCGIWAP: //get access point MAC addresses - { - struct sockaddr *ap_addr=&wrq->u.ap_addr; - rt_ioctl_giwap(net_dev, NULL, ap_addr, ap_addr->sa_data); - break; - } - case SIOCSIWAP: //set access point MAC addresses - { - struct sockaddr *ap_addr=&wrq->u.ap_addr; - rt_ioctl_siwap(net_dev, NULL, ap_addr, ap_addr->sa_data); - break; - } - case SIOCGIWMODE: //get operation mode - { - __u32 *mode=&wrq->u.mode; - rt_ioctl_giwmode(net_dev, NULL, mode, NULL); - break; - } - case SIOCSIWMODE: //set operation mode - { - __u32 *mode=&wrq->u.mode; - rt_ioctl_siwmode(net_dev, NULL, mode, NULL); - break; - } - case SIOCGIWSENS: //get sensitivity (dBm) - case SIOCSIWSENS: //set sensitivity (dBm) - case SIOCGIWPOWER: //get Power Management settings - case SIOCSIWPOWER: //set Power Management settings - case SIOCGIWTXPOW: //get transmit power (dBm) - case SIOCSIWTXPOW: //set transmit power (dBm) - case SIOCGIWRANGE: //Get range of parameters - case SIOCGIWRETRY: //get retry limits and lifetime - case SIOCSIWRETRY: //set retry limits and lifetime - Status = -EOPNOTSUPP; - break; - case RT_PRIV_IOCTL: - case RT_PRIV_IOCTL_EXT: - subcmd = wrq->u.data.flags; - if( subcmd & OID_GET_SET_TOGGLE) - Status = RTMPSetInformation(pAd, rq, subcmd); - else - Status = RTMPQueryInformation(pAd, rq, subcmd); - break; - case SIOCGIWPRIV: - if (wrq->u.data.pointer) - { - if ( access_ok(VERIFY_WRITE, wrq->u.data.pointer, sizeof(privtab)) != TRUE) - break; - wrq->u.data.length = sizeof(privtab) / sizeof(privtab[0]); - if (copy_to_user(wrq->u.data.pointer, privtab, sizeof(privtab))) - Status = -EFAULT; - } - break; - case RTPRIV_IOCTL_SET: - if(access_ok(VERIFY_READ, wrq->u.data.pointer, wrq->u.data.length) != TRUE) - break; - rt_ioctl_setparam(net_dev, NULL, NULL, wrq->u.data.pointer); - break; - case RTPRIV_IOCTL_GSITESURVEY: - RTMPIoctlGetSiteSurvey(pAd, wrq); - break; -#ifdef DBG - case RTPRIV_IOCTL_MAC: - RTMPIoctlMAC(pAd, wrq); - break; - case RTPRIV_IOCTL_E2P: - RTMPIoctlE2PROM(pAd, wrq); - break; -#ifdef RT30xx - case RTPRIV_IOCTL_RF: - RTMPIoctlRF(pAd, wrq); - break; -#endif // RT30xx // -#endif // DBG // - case SIOCETHTOOL: - break; - default: - DBGPRINT(RT_DEBUG_ERROR, ("IOCTL::unknown IOCTL's cmd = 0x%08x\n", cmd)); - Status = -EOPNOTSUPP; - break; - } - - if(StateMachineTouched) // Upper layer sent a MLME-related operations - RT28XX_MLME_HANDLER(pAd); - - return Status; -} - -/* - ========================================================================== - Description: - Set SSID - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_SSID_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - NDIS_802_11_SSID Ssid, *pSsid=NULL; - BOOLEAN StateMachineTouched = FALSE; - int success = TRUE; - - if( strlen(arg) <= MAX_LEN_OF_SSID) - { - NdisZeroMemory(&Ssid, sizeof(NDIS_802_11_SSID)); - if (strlen(arg) != 0) - { - NdisMoveMemory(Ssid.Ssid, arg, strlen(arg)); - Ssid.SsidLength = strlen(arg); - } - else //ANY ssid - { - Ssid.SsidLength = 0; - memcpy(Ssid.Ssid, "", 0); - pAdapter->StaCfg.BssType = BSS_INFRA; - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; - pAdapter->StaCfg.WepStatus = Ndis802_11EncryptionDisabled; - } - pSsid = &Ssid; - - if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) - { - RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); - DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); - } - - pAdapter->MlmeAux.CurrReqIsFromNdis = TRUE; - pAdapter->StaCfg.bScanReqIsFromWebUI = FALSE; - pAdapter->bConfigChanged = TRUE; - - MlmeEnqueue(pAdapter, - MLME_CNTL_STATE_MACHINE, - OID_802_11_SSID, - sizeof(NDIS_802_11_SSID), - (VOID *)pSsid); - - StateMachineTouched = TRUE; - DBGPRINT(RT_DEBUG_TRACE, ("Set_SSID_Proc::(Len=%d,Ssid=%s)\n", Ssid.SsidLength, Ssid.Ssid)); - } - else - success = FALSE; - - if (StateMachineTouched) // Upper layer sent a MLME-related operations - RT28XX_MLME_HANDLER(pAdapter); - - return success; -} - -#ifdef WMM_SUPPORT -/* - ========================================================================== - Description: - Set WmmCapable Enable or Disable - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_WmmCapable_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - BOOLEAN bWmmCapable; - - bWmmCapable = simple_strtol(arg, 0, 10); - - if ((bWmmCapable == 1) -#ifdef RT2870 - && (pAd->NumberOfPipes >= 5) -#endif // RT2870 // - ) - pAd->CommonCfg.bWmmCapable = TRUE; - else if (bWmmCapable == 0) - pAd->CommonCfg.bWmmCapable = FALSE; - else - return FALSE; //Invalid argument - - DBGPRINT(RT_DEBUG_TRACE, ("Set_WmmCapable_Proc::(bWmmCapable=%d)\n", - pAd->CommonCfg.bWmmCapable)); - - return TRUE; -} -#endif // WMM_SUPPORT // - -/* - ========================================================================== - Description: - Set Network Type(Infrastructure/Adhoc mode) - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_NetworkType_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - UINT32 Value = 0; - - if (strcmp(arg, "Adhoc") == 0) - { - if (pAdapter->StaCfg.BssType != BSS_ADHOC) - { - // Config has changed - pAdapter->bConfigChanged = TRUE; - if (MONITOR_ON(pAdapter)) - { - RTMP_IO_WRITE32(pAdapter, RX_FILTR_CFG, STANORMAL); - RTMP_IO_READ32(pAdapter, MAC_SYS_CTRL, &Value); - Value &= (~0x80); - RTMP_IO_WRITE32(pAdapter, MAC_SYS_CTRL, Value); - OPSTATUS_CLEAR_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED); - pAdapter->StaCfg.bAutoReconnect = TRUE; - LinkDown(pAdapter, FALSE); - } - if (INFRA_ON(pAdapter)) - { - //BOOLEAN Cancelled; - // Set the AutoReconnectSsid to prevent it reconnect to old SSID - // Since calling this indicate user don't want to connect to that SSID anymore. - pAdapter->MlmeAux.AutoReconnectSsidLen= 32; - NdisZeroMemory(pAdapter->MlmeAux.AutoReconnectSsid, pAdapter->MlmeAux.AutoReconnectSsidLen); - - LinkDown(pAdapter, FALSE); - - DBGPRINT(RT_DEBUG_TRACE, ("NDIS_STATUS_MEDIA_DISCONNECT Event BB!\n")); - } - } - pAdapter->StaCfg.BssType = BSS_ADHOC; - pAdapter->net_dev->type = pAdapter->StaCfg.OriDevType; - DBGPRINT(RT_DEBUG_TRACE, ("===>Set_NetworkType_Proc::(AD-HOC)\n")); - } - else if (strcmp(arg, "Infra") == 0) - { - if (pAdapter->StaCfg.BssType != BSS_INFRA) - { - // Config has changed - pAdapter->bConfigChanged = TRUE; - if (MONITOR_ON(pAdapter)) - { - RTMP_IO_WRITE32(pAdapter, RX_FILTR_CFG, STANORMAL); - RTMP_IO_READ32(pAdapter, MAC_SYS_CTRL, &Value); - Value &= (~0x80); - RTMP_IO_WRITE32(pAdapter, MAC_SYS_CTRL, Value); - OPSTATUS_CLEAR_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED); - pAdapter->StaCfg.bAutoReconnect = TRUE; - LinkDown(pAdapter, FALSE); - } - if (ADHOC_ON(pAdapter)) - { - // Set the AutoReconnectSsid to prevent it reconnect to old SSID - // Since calling this indicate user don't want to connect to that SSID anymore. - pAdapter->MlmeAux.AutoReconnectSsidLen= 32; - NdisZeroMemory(pAdapter->MlmeAux.AutoReconnectSsid, pAdapter->MlmeAux.AutoReconnectSsidLen); - - LinkDown(pAdapter, FALSE); - } - } - pAdapter->StaCfg.BssType = BSS_INFRA; - pAdapter->net_dev->type = pAdapter->StaCfg.OriDevType; - DBGPRINT(RT_DEBUG_TRACE, ("===>Set_NetworkType_Proc::(INFRA)\n")); - - pAdapter->StaCfg.BssType = BSS_INFRA; - } - else if (strcmp(arg, "Monitor") == 0) - { - UCHAR bbpValue = 0; - BCN_TIME_CFG_STRUC csr; - OPSTATUS_CLEAR_FLAG(pAdapter, fOP_STATUS_INFRA_ON); - OPSTATUS_CLEAR_FLAG(pAdapter, fOP_STATUS_ADHOC_ON); - OPSTATUS_SET_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED); - // disable all periodic state machine - pAdapter->StaCfg.bAutoReconnect = FALSE; - // reset all mlme state machine - RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); - DBGPRINT(RT_DEBUG_TRACE, ("fOP_STATUS_MEDIA_STATE_CONNECTED \n")); - if (pAdapter->CommonCfg.CentralChannel == 0) - { -#ifdef DOT11_N_SUPPORT - if (pAdapter->CommonCfg.PhyMode == PHY_11AN_MIXED) - pAdapter->CommonCfg.CentralChannel = 36; - else -#endif // DOT11_N_SUPPORT // - pAdapter->CommonCfg.CentralChannel = 6; - } -#ifdef DOT11_N_SUPPORT - else - N_ChannelCheck(pAdapter); -#endif // DOT11_N_SUPPORT // - -#ifdef DOT11_N_SUPPORT - if (pAdapter->CommonCfg.PhyMode >= PHY_11ABGN_MIXED && - pAdapter->CommonCfg.RegTransmitSetting.field.BW == BW_40 && - pAdapter->CommonCfg.RegTransmitSetting.field.EXTCHA == EXTCHA_ABOVE) - { - // 40MHz ,control channel at lower - RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, BBP_R4, &bbpValue); - bbpValue &= (~0x18); - bbpValue |= 0x10; - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R4, bbpValue); - pAdapter->CommonCfg.BBPCurrentBW = BW_40; - // RX : control channel at lower - RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, BBP_R3, &bbpValue); - bbpValue &= (~0x20); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R3, bbpValue); - - RTMP_IO_READ32(pAdapter, TX_BAND_CFG, &Value); - Value &= 0xfffffffe; - RTMP_IO_WRITE32(pAdapter, TX_BAND_CFG, Value); - pAdapter->CommonCfg.CentralChannel = pAdapter->CommonCfg.Channel + 2; - AsicSwitchChannel(pAdapter, pAdapter->CommonCfg.CentralChannel, FALSE); - AsicLockChannel(pAdapter, pAdapter->CommonCfg.CentralChannel); - DBGPRINT(RT_DEBUG_TRACE, ("BW_40 ,control_channel(%d), CentralChannel(%d) \n", - pAdapter->CommonCfg.Channel, - pAdapter->CommonCfg.CentralChannel)); - } - else if (pAdapter->CommonCfg.PhyMode >= PHY_11ABGN_MIXED && - pAdapter->CommonCfg.RegTransmitSetting.field.BW == BW_40 && - pAdapter->CommonCfg.RegTransmitSetting.field.EXTCHA == EXTCHA_BELOW) - { - // 40MHz ,control channel at upper - RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, BBP_R4, &bbpValue); - bbpValue &= (~0x18); - bbpValue |= 0x10; - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R4, bbpValue); - pAdapter->CommonCfg.BBPCurrentBW = BW_40; - RTMP_IO_READ32(pAdapter, TX_BAND_CFG, &Value); - Value |= 0x1; - RTMP_IO_WRITE32(pAdapter, TX_BAND_CFG, Value); - - RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, BBP_R3, &bbpValue); - bbpValue |= (0x20); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R3, bbpValue); - pAdapter->CommonCfg.CentralChannel = pAdapter->CommonCfg.Channel - 2; - AsicSwitchChannel(pAdapter, pAdapter->CommonCfg.CentralChannel, FALSE); - AsicLockChannel(pAdapter, pAdapter->CommonCfg.CentralChannel); - DBGPRINT(RT_DEBUG_TRACE, ("BW_40 ,control_channel(%d), CentralChannel(%d) \n", - pAdapter->CommonCfg.Channel, - pAdapter->CommonCfg.CentralChannel)); - } - else -#endif // DOT11_N_SUPPORT // - { - // 20MHz - RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, BBP_R4, &bbpValue); - bbpValue &= (~0x18); - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R4, bbpValue); - pAdapter->CommonCfg.BBPCurrentBW = BW_20; - AsicSwitchChannel(pAdapter, pAdapter->CommonCfg.Channel, FALSE); - AsicLockChannel(pAdapter, pAdapter->CommonCfg.Channel); - DBGPRINT(RT_DEBUG_TRACE, ("BW_20, Channel(%d)\n", pAdapter->CommonCfg.Channel)); - } - // Enable Rx with promiscuous reception - RTMP_IO_WRITE32(pAdapter, RX_FILTR_CFG, 0x3); - // ASIC supporsts sniffer function with replacing RSSI with timestamp. - //RTMP_IO_READ32(pAdapter, MAC_SYS_CTRL, &Value); - //Value |= (0x80); - //RTMP_IO_WRITE32(pAdapter, MAC_SYS_CTRL, Value); - // disable sync - RTMP_IO_READ32(pAdapter, BCN_TIME_CFG, &csr.word); - csr.field.bBeaconGen = 0; - csr.field.bTBTTEnable = 0; - csr.field.TsfSyncMode = 0; - RTMP_IO_WRITE32(pAdapter, BCN_TIME_CFG, csr.word); - - pAdapter->StaCfg.BssType = BSS_MONITOR; - pAdapter->net_dev->type = ARPHRD_IEEE80211_PRISM; //ARPHRD_IEEE80211; // IEEE80211 - DBGPRINT(RT_DEBUG_TRACE, ("===>Set_NetworkType_Proc::(MONITOR)\n")); - } - - // Reset Ralink supplicant to not use, it will be set to start when UI set PMK key - pAdapter->StaCfg.WpaState = SS_NOTUSE; - - DBGPRINT(RT_DEBUG_TRACE, ("Set_NetworkType_Proc::(NetworkType=%d)\n", pAdapter->StaCfg.BssType)); - - return TRUE; -} - -/* - ========================================================================== - Description: - Set Authentication mode - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_AuthMode_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - if ((strcmp(arg, "WEPAUTO") == 0) || (strcmp(arg, "wepauto") == 0)) - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeAutoSwitch; - else if ((strcmp(arg, "OPEN") == 0) || (strcmp(arg, "open") == 0)) - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; - else if ((strcmp(arg, "SHARED") == 0) || (strcmp(arg, "shared") == 0)) - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeShared; - else if ((strcmp(arg, "WPAPSK") == 0) || (strcmp(arg, "wpapsk") == 0)) - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPAPSK; - else if ((strcmp(arg, "WPANONE") == 0) || (strcmp(arg, "wpanone") == 0)) - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPANone; - else if ((strcmp(arg, "WPA2PSK") == 0) || (strcmp(arg, "wpa2psk") == 0)) - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA2PSK; -#ifdef WPA_SUPPLICANT_SUPPORT - else if ((strcmp(arg, "WPA") == 0) || (strcmp(arg, "wpa") == 0)) - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA; - else if ((strcmp(arg, "WPA2") == 0) || (strcmp(arg, "wpa2") == 0)) - pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA2; -#endif // WPA_SUPPLICANT_SUPPORT // - else - return FALSE; - - pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; - - DBGPRINT(RT_DEBUG_TRACE, ("Set_AuthMode_Proc::(AuthMode=%d)\n", pAdapter->StaCfg.AuthMode)); - - return TRUE; -} - -/* - ========================================================================== - Description: - Set Encryption Type - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_EncrypType_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - if ((strcmp(arg, "NONE") == 0) || (strcmp(arg, "none") == 0)) - { - if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - return TRUE; // do nothing - - pAdapter->StaCfg.WepStatus = Ndis802_11WEPDisabled; - pAdapter->StaCfg.PairCipher = Ndis802_11WEPDisabled; - pAdapter->StaCfg.GroupCipher = Ndis802_11WEPDisabled; - } - else if ((strcmp(arg, "WEP") == 0) || (strcmp(arg, "wep") == 0)) - { - if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - return TRUE; // do nothing - - pAdapter->StaCfg.WepStatus = Ndis802_11WEPEnabled; - pAdapter->StaCfg.PairCipher = Ndis802_11WEPEnabled; - pAdapter->StaCfg.GroupCipher = Ndis802_11WEPEnabled; - } - else if ((strcmp(arg, "TKIP") == 0) || (strcmp(arg, "tkip") == 0)) - { - if (pAdapter->StaCfg.AuthMode < Ndis802_11AuthModeWPA) - return TRUE; // do nothing - - pAdapter->StaCfg.WepStatus = Ndis802_11Encryption2Enabled; - pAdapter->StaCfg.PairCipher = Ndis802_11Encryption2Enabled; - pAdapter->StaCfg.GroupCipher = Ndis802_11Encryption2Enabled; - } - else if ((strcmp(arg, "AES") == 0) || (strcmp(arg, "aes") == 0)) - { - if (pAdapter->StaCfg.AuthMode < Ndis802_11AuthModeWPA) - return TRUE; // do nothing - - pAdapter->StaCfg.WepStatus = Ndis802_11Encryption3Enabled; - pAdapter->StaCfg.PairCipher = Ndis802_11Encryption3Enabled; - pAdapter->StaCfg.GroupCipher = Ndis802_11Encryption3Enabled; - } - else - return FALSE; - - pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; - - DBGPRINT(RT_DEBUG_TRACE, ("Set_EncrypType_Proc::(EncrypType=%d)\n", pAdapter->StaCfg.WepStatus)); - - return TRUE; -} - -/* - ========================================================================== - Description: - Set Default Key ID - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_DefaultKeyID_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - ULONG KeyIdx; - - KeyIdx = simple_strtol(arg, 0, 10); - if((KeyIdx >= 1 ) && (KeyIdx <= 4)) - pAdapter->StaCfg.DefaultKeyId = (UCHAR) (KeyIdx - 1 ); - else - return FALSE; //Invalid argument - - DBGPRINT(RT_DEBUG_TRACE, ("Set_DefaultKeyID_Proc::(DefaultKeyID=%d)\n", pAdapter->StaCfg.DefaultKeyId)); - - return TRUE; -} - -/* - ========================================================================== - Description: - Set WEP KEY1 - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_Key1_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - int KeyLen; - int i; - UCHAR CipherAlg=CIPHER_WEP64; - - if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - return TRUE; // do nothing - - KeyLen = strlen(arg); - - switch (KeyLen) - { - case 5: //wep 40 Ascii type - pAdapter->SharedKey[BSS0][0].KeyLen = KeyLen; - memcpy(pAdapter->SharedKey[BSS0][0].Key, arg, KeyLen); - CipherAlg = CIPHER_WEP64; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key1_Proc::(Key1=%s and type=%s)\n", arg, "Ascii")); - break; - case 10: //wep 40 Hex type - for(i=0; i < KeyLen; i++) - { - if( !isxdigit(*(arg+i)) ) - return FALSE; //Not Hex value; - } - pAdapter->SharedKey[BSS0][0].KeyLen = KeyLen / 2 ; - AtoH(arg, pAdapter->SharedKey[BSS0][0].Key, KeyLen / 2); - CipherAlg = CIPHER_WEP64; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key1_Proc::(Key1=%s and type=%s)\n", arg, "Hex")); - break; - case 13: //wep 104 Ascii type - pAdapter->SharedKey[BSS0][0].KeyLen = KeyLen; - memcpy(pAdapter->SharedKey[BSS0][0].Key, arg, KeyLen); - CipherAlg = CIPHER_WEP128; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key1_Proc::(Key1=%s and type=%s)\n", arg, "Ascii")); - break; - case 26: //wep 104 Hex type - for(i=0; i < KeyLen; i++) - { - if( !isxdigit(*(arg+i)) ) - return FALSE; //Not Hex value; - } - pAdapter->SharedKey[BSS0][0].KeyLen = KeyLen / 2 ; - AtoH(arg, pAdapter->SharedKey[BSS0][0].Key, KeyLen / 2); - CipherAlg = CIPHER_WEP128; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key1_Proc::(Key1=%s and type=%s)\n", arg, "Hex")); - break; - default: //Invalid argument - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key1_Proc::Invalid argument (=%s)\n", arg)); - return FALSE; - } - - pAdapter->SharedKey[BSS0][0].CipherAlg = CipherAlg; - - // Set keys (into ASIC) - if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - ; // not support - else // Old WEP stuff - { - AsicAddSharedKeyEntry(pAdapter, - 0, - 0, - pAdapter->SharedKey[BSS0][0].CipherAlg, - pAdapter->SharedKey[BSS0][0].Key, - NULL, - NULL); - } - - return TRUE; -} -/* - ========================================================================== - - Description: - Set WEP KEY2 - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_Key2_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - int KeyLen; - int i; - UCHAR CipherAlg=CIPHER_WEP64; - - if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - return TRUE; // do nothing - - KeyLen = strlen(arg); - - switch (KeyLen) - { - case 5: //wep 40 Ascii type - pAdapter->SharedKey[BSS0][1].KeyLen = KeyLen; - memcpy(pAdapter->SharedKey[BSS0][1].Key, arg, KeyLen); - CipherAlg = CIPHER_WEP64; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key2_Proc::(Key2=%s and type=%s)\n", arg, "Ascii")); - break; - case 10: //wep 40 Hex type - for(i=0; i < KeyLen; i++) - { - if( !isxdigit(*(arg+i)) ) - return FALSE; //Not Hex value; - } - pAdapter->SharedKey[BSS0][1].KeyLen = KeyLen / 2 ; - AtoH(arg, pAdapter->SharedKey[BSS0][1].Key, KeyLen / 2); - CipherAlg = CIPHER_WEP64; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key2_Proc::(Key2=%s and type=%s)\n", arg, "Hex")); - break; - case 13: //wep 104 Ascii type - pAdapter->SharedKey[BSS0][1].KeyLen = KeyLen; - memcpy(pAdapter->SharedKey[BSS0][1].Key, arg, KeyLen); - CipherAlg = CIPHER_WEP128; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key2_Proc::(Key2=%s and type=%s)\n", arg, "Ascii")); - break; - case 26: //wep 104 Hex type - for(i=0; i < KeyLen; i++) - { - if( !isxdigit(*(arg+i)) ) - return FALSE; //Not Hex value; - } - pAdapter->SharedKey[BSS0][1].KeyLen = KeyLen / 2 ; - AtoH(arg, pAdapter->SharedKey[BSS0][1].Key, KeyLen / 2); - CipherAlg = CIPHER_WEP128; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key2_Proc::(Key2=%s and type=%s)\n", arg, "Hex")); - break; - default: //Invalid argument - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key2_Proc::Invalid argument (=%s)\n", arg)); - return FALSE; - } - pAdapter->SharedKey[BSS0][1].CipherAlg = CipherAlg; - - // Set keys (into ASIC) - if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - ; // not support - else // Old WEP stuff - { - AsicAddSharedKeyEntry(pAdapter, - 0, - 1, - pAdapter->SharedKey[BSS0][1].CipherAlg, - pAdapter->SharedKey[BSS0][1].Key, - NULL, - NULL); - } - - return TRUE; -} -/* - ========================================================================== - Description: - Set WEP KEY3 - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_Key3_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - int KeyLen; - int i; - UCHAR CipherAlg=CIPHER_WEP64; - - if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - return TRUE; // do nothing - - KeyLen = strlen(arg); - - switch (KeyLen) - { - case 5: //wep 40 Ascii type - pAdapter->SharedKey[BSS0][2].KeyLen = KeyLen; - memcpy(pAdapter->SharedKey[BSS0][2].Key, arg, KeyLen); - CipherAlg = CIPHER_WEP64; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key3_Proc::(Key3=%s and type=Ascii)\n", arg)); - break; - case 10: //wep 40 Hex type - for(i=0; i < KeyLen; i++) - { - if( !isxdigit(*(arg+i)) ) - return FALSE; //Not Hex value; - } - pAdapter->SharedKey[BSS0][2].KeyLen = KeyLen / 2 ; - AtoH(arg, pAdapter->SharedKey[BSS0][2].Key, KeyLen / 2); - CipherAlg = CIPHER_WEP64; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key3_Proc::(Key3=%s and type=Hex)\n", arg)); - break; - case 13: //wep 104 Ascii type - pAdapter->SharedKey[BSS0][2].KeyLen = KeyLen; - memcpy(pAdapter->SharedKey[BSS0][2].Key, arg, KeyLen); - CipherAlg = CIPHER_WEP128; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key3_Proc::(Key3=%s and type=Ascii)\n", arg)); - break; - case 26: //wep 104 Hex type - for(i=0; i < KeyLen; i++) - { - if( !isxdigit(*(arg+i)) ) - return FALSE; //Not Hex value; - } - pAdapter->SharedKey[BSS0][2].KeyLen = KeyLen / 2 ; - AtoH(arg, pAdapter->SharedKey[BSS0][2].Key, KeyLen / 2); - CipherAlg = CIPHER_WEP128; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key3_Proc::(Key3=%s and type=Hex)\n", arg)); - break; - default: //Invalid argument - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key3_Proc::Invalid argument (=%s)\n", arg)); - return FALSE; - } - pAdapter->SharedKey[BSS0][2].CipherAlg = CipherAlg; - - // Set keys (into ASIC) - if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - ; // not support - else // Old WEP stuff - { - AsicAddSharedKeyEntry(pAdapter, - 0, - 2, - pAdapter->SharedKey[BSS0][2].CipherAlg, - pAdapter->SharedKey[BSS0][2].Key, - NULL, - NULL); - } - - return TRUE; -} -/* - ========================================================================== - Description: - Set WEP KEY4 - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_Key4_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - int KeyLen; - int i; - UCHAR CipherAlg=CIPHER_WEP64; - - if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - return TRUE; // do nothing - - KeyLen = strlen(arg); - - switch (KeyLen) - { - case 5: //wep 40 Ascii type - pAdapter->SharedKey[BSS0][3].KeyLen = KeyLen; - memcpy(pAdapter->SharedKey[BSS0][3].Key, arg, KeyLen); - CipherAlg = CIPHER_WEP64; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key4_Proc::(Key4=%s and type=%s)\n", arg, "Ascii")); - break; - case 10: //wep 40 Hex type - for(i=0; i < KeyLen; i++) - { - if( !isxdigit(*(arg+i)) ) - return FALSE; //Not Hex value; - } - pAdapter->SharedKey[BSS0][3].KeyLen = KeyLen / 2 ; - AtoH(arg, pAdapter->SharedKey[BSS0][3].Key, KeyLen / 2); - CipherAlg = CIPHER_WEP64; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key4_Proc::(Key4=%s and type=%s)\n", arg, "Hex")); - break; - case 13: //wep 104 Ascii type - pAdapter->SharedKey[BSS0][3].KeyLen = KeyLen; - memcpy(pAdapter->SharedKey[BSS0][3].Key, arg, KeyLen); - CipherAlg = CIPHER_WEP128; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key4_Proc::(Key4=%s and type=%s)\n", arg, "Ascii")); - break; - case 26: //wep 104 Hex type - for(i=0; i < KeyLen; i++) - { - if( !isxdigit(*(arg+i)) ) - return FALSE; //Not Hex value; - } - pAdapter->SharedKey[BSS0][3].KeyLen = KeyLen / 2 ; - AtoH(arg, pAdapter->SharedKey[BSS0][3].Key, KeyLen / 2); - CipherAlg = CIPHER_WEP128; - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key4_Proc::(Key4=%s and type=%s)\n", arg, "Hex")); - break; - default: //Invalid argument - DBGPRINT(RT_DEBUG_TRACE, ("Set_Key4_Proc::Invalid argument (=%s)\n", arg)); - return FALSE; - } - pAdapter->SharedKey[BSS0][3].CipherAlg = CipherAlg; - - // Set keys (into ASIC) - if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) - ; // not support - else // Old WEP stuff - { - AsicAddSharedKeyEntry(pAdapter, - 0, - 3, - pAdapter->SharedKey[BSS0][3].CipherAlg, - pAdapter->SharedKey[BSS0][3].Key, - NULL, - NULL); - } - - return TRUE; -} - -/* - ========================================================================== - Description: - Set WPA PSK key - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_WPAPSK_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - UCHAR keyMaterial[40]; - - if ((pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPAPSK) && - (pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPA2PSK) && - (pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPANone) - ) - return TRUE; // do nothing - - DBGPRINT(RT_DEBUG_TRACE, ("Set_WPAPSK_Proc::(WPAPSK=%s)\n", arg)); - - NdisZeroMemory(keyMaterial, 40); - - if ((strlen(arg) < 8) || (strlen(arg) > 64)) - { - DBGPRINT(RT_DEBUG_TRACE, ("Set failed!!(WPAPSK=%s), WPAPSK key-string required 8 ~ 64 characters \n", arg)); - return FALSE; - } - - if (strlen(arg) == 64) - { - AtoH(arg, keyMaterial, 32); - NdisMoveMemory(pAdapter->StaCfg.PMK, keyMaterial, 32); - - } - else - { - PasswordHash((char *)arg, pAdapter->MlmeAux.Ssid, pAdapter->MlmeAux.SsidLen, keyMaterial); - NdisMoveMemory(pAdapter->StaCfg.PMK, keyMaterial, 32); - } - - - - if(pAdapter->StaCfg.BssType == BSS_ADHOC && - pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) - { - pAdapter->StaCfg.WpaState = SS_NOTUSE; - } - else - { - // Start STA supplicant state machine - pAdapter->StaCfg.WpaState = SS_START; - } - - return TRUE; -} - -/* - ========================================================================== - Description: - Set Power Saving mode - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_PSMode_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - if (pAdapter->StaCfg.BssType == BSS_INFRA) - { - if ((strcmp(arg, "Max_PSP") == 0) || - (strcmp(arg, "max_psp") == 0) || - (strcmp(arg, "MAX_PSP") == 0)) - { - // do NOT turn on PSM bit here, wait until MlmeCheckForPsmChange() - // to exclude certain situations. - if (pAdapter->StaCfg.bWindowsACCAMEnable == FALSE) - pAdapter->StaCfg.WindowsPowerMode = Ndis802_11PowerModeMAX_PSP; - pAdapter->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeMAX_PSP; - OPSTATUS_SET_FLAG(pAdapter, fOP_STATUS_RECEIVE_DTIM); - pAdapter->StaCfg.DefaultListenCount = 5; - - } - else if ((strcmp(arg, "Fast_PSP") == 0) || - (strcmp(arg, "fast_psp") == 0) || - (strcmp(arg, "FAST_PSP") == 0)) - { - // do NOT turn on PSM bit here, wait until MlmeCheckForPsmChange() - // to exclude certain situations. - OPSTATUS_SET_FLAG(pAdapter, fOP_STATUS_RECEIVE_DTIM); - if (pAdapter->StaCfg.bWindowsACCAMEnable == FALSE) - pAdapter->StaCfg.WindowsPowerMode = Ndis802_11PowerModeFast_PSP; - pAdapter->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeFast_PSP; - pAdapter->StaCfg.DefaultListenCount = 3; - } - else if ((strcmp(arg, "Legacy_PSP") == 0) || - (strcmp(arg, "legacy_psp") == 0) || - (strcmp(arg, "LEGACY_PSP") == 0)) - { - // do NOT turn on PSM bit here, wait until MlmeCheckForPsmChange() - // to exclude certain situations. - OPSTATUS_SET_FLAG(pAdapter, fOP_STATUS_RECEIVE_DTIM); - if (pAdapter->StaCfg.bWindowsACCAMEnable == FALSE) - pAdapter->StaCfg.WindowsPowerMode = Ndis802_11PowerModeLegacy_PSP; - pAdapter->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeLegacy_PSP; - pAdapter->StaCfg.DefaultListenCount = 3; - } - else - { - //Default Ndis802_11PowerModeCAM - // clear PSM bit immediately - MlmeSetPsmBit(pAdapter, PWR_ACTIVE); - OPSTATUS_SET_FLAG(pAdapter, fOP_STATUS_RECEIVE_DTIM); - if (pAdapter->StaCfg.bWindowsACCAMEnable == FALSE) - pAdapter->StaCfg.WindowsPowerMode = Ndis802_11PowerModeCAM; - pAdapter->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeCAM; - } - - DBGPRINT(RT_DEBUG_TRACE, ("Set_PSMode_Proc::(PSMode=%ld)\n", pAdapter->StaCfg.WindowsPowerMode)); - } - else - return FALSE; - - - return TRUE; -} - -#ifdef WPA_SUPPLICANT_SUPPORT -/* - ========================================================================== - Description: - Set WpaSupport flag. - Value: - 0: Driver ignore wpa_supplicant. - 1: wpa_supplicant initiates scanning and AP selection. - 2: driver takes care of scanning, AP selection, and IEEE 802.11 association parameters. - Return: - TRUE if all parameters are OK, FALSE otherwise - ========================================================================== -*/ -INT Set_Wpa_Support( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - - if ( simple_strtol(arg, 0, 10) == 0) - pAd->StaCfg.WpaSupplicantUP = WPA_SUPPLICANT_DISABLE; - else if ( simple_strtol(arg, 0, 10) == 1) - pAd->StaCfg.WpaSupplicantUP = WPA_SUPPLICANT_ENABLE; - else if ( simple_strtol(arg, 0, 10) == 2) - pAd->StaCfg.WpaSupplicantUP = WPA_SUPPLICANT_ENABLE_WITH_WEB_UI; - else - pAd->StaCfg.WpaSupplicantUP = WPA_SUPPLICANT_DISABLE; - - DBGPRINT(RT_DEBUG_TRACE, ("Set_Wpa_Support::(WpaSupplicantUP=%d)\n", pAd->StaCfg.WpaSupplicantUP)); - - return TRUE; -} -#endif // WPA_SUPPLICANT_SUPPORT // - -#ifdef DBG -/* - ========================================================================== - Description: - Read / Write MAC - Arguments: - pAdapter Pointer to our adapter - wrq Pointer to the ioctl argument - - Return Value: - None - - Note: - Usage: - 1.) iwpriv ra0 mac 0 ==> read MAC where Addr=0x0 - 2.) iwpriv ra0 mac 0=12 ==> write MAC where Addr=0x0, value=12 - ========================================================================== -*/ -VOID RTMPIoctlMAC( - IN PRTMP_ADAPTER pAdapter, - IN struct iwreq *wrq) -{ - CHAR *this_char; - CHAR *value; - INT j = 0, k = 0; - CHAR msg[1024]; - CHAR arg[255]; - ULONG macAddr = 0; - UCHAR temp[16], temp2[16]; - UINT32 macValue = 0; - INT Status; - BOOLEAN bIsPrintAllMAC = FALSE; - - - memset(msg, 0x00, 1024); - if (wrq->u.data.length > 1) //No parameters. - { - Status = copy_from_user(arg, wrq->u.data.pointer, (wrq->u.data.length > 255) ? 255 : wrq->u.data.length); - sprintf(msg, "\n"); - - //Parsing Read or Write - this_char = arg; - if (!*this_char) - goto next; - - if ((value = rtstrchr(this_char, '=')) != NULL) - *value++ = 0; - - if (!value || !*value) - { //Read - // Sanity check - if(strlen(this_char) > 4) - goto next; - - j = strlen(this_char); - while(j-- > 0) - { - if(this_char[j] > 'f' || this_char[j] < '0') - return; - } - - // Mac Addr - k = j = strlen(this_char); - while(j-- > 0) - { - this_char[4-k+j] = this_char[j]; - } - - while(k < 4) - this_char[3-k++]='0'; - this_char[4]='\0'; - - if(strlen(this_char) == 4) - { - AtoH(this_char, temp, 2); - macAddr = *temp*256 + temp[1]; - if (macAddr < 0xFFFF) - { - RTMP_IO_READ32(pAdapter, macAddr, &macValue); - DBGPRINT(RT_DEBUG_TRACE, ("MacAddr=%lx, MacValue=%x\n", macAddr, macValue)); - sprintf(msg+strlen(msg), "[0x%08lX]:%08X ", macAddr , macValue); - } - else - {//Invalid parametes, so default printk all mac - bIsPrintAllMAC = TRUE; - goto next; - } - } - } - else - { //Write - memcpy(&temp2, value, strlen(value)); - temp2[strlen(value)] = '\0'; - - // Sanity check - if((strlen(this_char) > 4) || strlen(temp2) > 8) - goto next; - - j = strlen(this_char); - while(j-- > 0) - { - if(this_char[j] > 'f' || this_char[j] < '0') - return; - } - - j = strlen(temp2); - while(j-- > 0) - { - if(temp2[j] > 'f' || temp2[j] < '0') - return; - } - - //MAC Addr - k = j = strlen(this_char); - while(j-- > 0) - { - this_char[4-k+j] = this_char[j]; - } - - while(k < 4) - this_char[3-k++]='0'; - this_char[4]='\0'; - - //MAC value - k = j = strlen(temp2); - while(j-- > 0) - { - temp2[8-k+j] = temp2[j]; - } - - while(k < 8) - temp2[7-k++]='0'; - temp2[8]='\0'; - - { - AtoH(this_char, temp, 2); - macAddr = *temp*256 + temp[1]; - - AtoH(temp2, temp, 4); - macValue = *temp*256*256*256 + temp[1]*256*256 + temp[2]*256 + temp[3]; - - // debug mode - if (macAddr == (HW_DEBUG_SETTING_BASE + 4)) - { - // 0x2bf4: byte0 non-zero: enable R17 tuning, 0: disable R17 tuning - if (macValue & 0x000000ff) - { - pAdapter->BbpTuning.bEnable = TRUE; - DBGPRINT(RT_DEBUG_TRACE,("turn on R17 tuning\n")); - } - else - { - UCHAR R66; - pAdapter->BbpTuning.bEnable = FALSE; - R66 = 0x26 + GET_LNA_GAIN(pAdapter); -#ifdef RALINK_ATE - if (ATE_ON(pAdapter)) - { - ATE_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R66, (0x26 + GET_LNA_GAIN(pAdapter))); - } - else -#endif // RALINK_ATE // - RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R66, (0x26 + GET_LNA_GAIN(pAdapter))); - DBGPRINT(RT_DEBUG_TRACE,("turn off R17 tuning, restore to 0x%02x\n", R66)); - } - return; - } - - DBGPRINT(RT_DEBUG_TRACE, ("MacAddr=%02lx, MacValue=0x%x\n", macAddr, macValue)); - - RTMP_IO_WRITE32(pAdapter, macAddr, macValue); - sprintf(msg+strlen(msg), "[0x%08lX]:%08X ", macAddr, macValue); - } - } - } - else - bIsPrintAllMAC = TRUE; -next: - if (bIsPrintAllMAC) - { - struct file *file_w; - PCHAR fileName = "MacDump.txt"; - mm_segment_t orig_fs; - - orig_fs = get_fs(); - set_fs(KERNEL_DS); - - // open file - file_w = filp_open(fileName, O_WRONLY|O_CREAT, 0); - if (IS_ERR(file_w)) - { - DBGPRINT(RT_DEBUG_TRACE, ("-->2) %s: Error %ld opening %s\n", __FUNCTION__, -PTR_ERR(file_w), fileName)); - } - else - { - if (file_w->f_op && file_w->f_op->write) - { - file_w->f_pos = 0; - macAddr = 0x1000; - - while (macAddr <= 0x1800) - { - RTMP_IO_READ32(pAdapter, macAddr, &macValue); - sprintf(msg, "%08lx = %08X\n", macAddr, macValue); - - // write data to file - file_w->f_op->write(file_w, msg, strlen(msg), &file_w->f_pos); - - printk("%s", msg); - macAddr += 4; - } - sprintf(msg, "\nDump all MAC values to %s\n", fileName); - } - filp_close(file_w, NULL); - } - set_fs(orig_fs); - } - if(strlen(msg) == 1) - sprintf(msg+strlen(msg), "===>Error command format!"); - - // Copy the information into the user buffer - wrq->u.data.length = strlen(msg); - Status = copy_to_user(wrq->u.data.pointer, msg, wrq->u.data.length); - - DBGPRINT(RT_DEBUG_TRACE, ("<==RTMPIoctlMAC\n\n")); -} - -/* - ========================================================================== - Description: - Read / Write E2PROM - Arguments: - pAdapter Pointer to our adapter - wrq Pointer to the ioctl argument - - Return Value: - None - - Note: - Usage: - 1.) iwpriv ra0 e2p 0 ==> read E2PROM where Addr=0x0 - 2.) iwpriv ra0 e2p 0=1234 ==> write E2PROM where Addr=0x0, value=1234 - ========================================================================== -*/ -VOID RTMPIoctlE2PROM( - IN PRTMP_ADAPTER pAdapter, - IN struct iwreq *wrq) -{ - CHAR *this_char; - CHAR *value; - INT j = 0, k = 0; - CHAR msg[1024]; - CHAR arg[255]; - USHORT eepAddr = 0; - UCHAR temp[16], temp2[16]; - USHORT eepValue; - int Status; - BOOLEAN bIsPrintAllE2P = FALSE; - - - memset(msg, 0x00, 1024); - if (wrq->u.data.length > 1) //No parameters. - { - Status = copy_from_user(arg, wrq->u.data.pointer, (wrq->u.data.length > 255) ? 255 : wrq->u.data.length); - sprintf(msg, "\n"); - - //Parsing Read or Write - this_char = arg; - - - if (!*this_char) - goto next; - - if ((value = rtstrchr(this_char, '=')) != NULL) - *value++ = 0; - - if (!value || !*value) - { //Read - - // Sanity check - if(strlen(this_char) > 4) - goto next; - - j = strlen(this_char); - while(j-- > 0) - { - if(this_char[j] > 'f' || this_char[j] < '0') - return; - } - - // E2PROM addr - k = j = strlen(this_char); - while(j-- > 0) - { - this_char[4-k+j] = this_char[j]; - } - - while(k < 4) - this_char[3-k++]='0'; - this_char[4]='\0'; - - if(strlen(this_char) == 4) - { - AtoH(this_char, temp, 2); - eepAddr = *temp*256 + temp[1]; - if (eepAddr < 0xFFFF) - { - RT28xx_EEPROM_READ16(pAdapter, eepAddr, eepValue); - sprintf(msg+strlen(msg), "[0x%04X]:0x%04X ", eepAddr , eepValue); - } - else - {//Invalid parametes, so default printk all bbp - bIsPrintAllE2P = TRUE; - goto next; - } - } - } - else - { //Write - memcpy(&temp2, value, strlen(value)); - temp2[strlen(value)] = '\0'; - - // Sanity check - if((strlen(this_char) > 4) || strlen(temp2) > 8) - goto next; - - j = strlen(this_char); - while(j-- > 0) - { - if(this_char[j] > 'f' || this_char[j] < '0') - return; - } - j = strlen(temp2); - while(j-- > 0) - { - if(temp2[j] > 'f' || temp2[j] < '0') - return; - } - - //MAC Addr - k = j = strlen(this_char); - while(j-- > 0) - { - this_char[4-k+j] = this_char[j]; - } - - while(k < 4) - this_char[3-k++]='0'; - this_char[4]='\0'; - - //MAC value - k = j = strlen(temp2); - while(j-- > 0) - { - temp2[4-k+j] = temp2[j]; - } - - while(k < 4) - temp2[3-k++]='0'; - temp2[4]='\0'; - - AtoH(this_char, temp, 2); - eepAddr = *temp*256 + temp[1]; - - AtoH(temp2, temp, 2); - eepValue = *temp*256 + temp[1]; - - RT28xx_EEPROM_WRITE16(pAdapter, eepAddr, eepValue); - sprintf(msg+strlen(msg), "[0x%02X]:%02X ", eepAddr, eepValue); - } - } - else - bIsPrintAllE2P = TRUE; -next: - if (bIsPrintAllE2P) - { - struct file *file_w; - PCHAR fileName = "EEPROMDump.txt"; - mm_segment_t orig_fs; - - orig_fs = get_fs(); - set_fs(KERNEL_DS); - - // open file - file_w = filp_open(fileName, O_WRONLY|O_CREAT, 0); - if (IS_ERR(file_w)) - { - DBGPRINT(RT_DEBUG_TRACE, ("-->2) %s: Error %ld opening %s\n", __FUNCTION__, -PTR_ERR(file_w), fileName)); - } - else - { - if (file_w->f_op && file_w->f_op->write) - { - file_w->f_pos = 0; - eepAddr = 0x00; - - while (eepAddr <= 0xFE) - { - RT28xx_EEPROM_READ16(pAdapter, eepAddr, eepValue); - sprintf(msg, "%08x = %04x\n", eepAddr , eepValue); - - // write data to file - file_w->f_op->write(file_w, msg, strlen(msg), &file_w->f_pos); - - printk("%s", msg); - eepAddr += 2; - } - sprintf(msg, "\nDump all EEPROM values to %s\n", fileName); - } - filp_close(file_w, NULL); - } - set_fs(orig_fs); - } - if(strlen(msg) == 1) - sprintf(msg+strlen(msg), "===>Error command format!"); - - - // Copy the information into the user buffer - wrq->u.data.length = strlen(msg); - Status = copy_to_user(wrq->u.data.pointer, msg, wrq->u.data.length); - - DBGPRINT(RT_DEBUG_TRACE, ("<==RTMPIoctlE2PROM\n")); -} -#ifdef RT30xx -/* - ========================================================================== - Description: - Read / Write RF register -Arguments: - pAdapter Pointer to our adapter - wrq Pointer to the ioctl argument - - Return Value: - None - - Note: - Usage: - 1.) iwpriv ra0 rf ==> read all RF registers - 2.) iwpriv ra0 rf 1 ==> read RF where RegID=1 - 3.) iwpriv ra0 rf 1=10 ==> write RF R1=0x10 - ========================================================================== -*/ -VOID RTMPIoctlRF( - IN PRTMP_ADAPTER pAdapter, - IN struct iwreq *wrq) -{ - CHAR *this_char; - CHAR *value; - UCHAR regRF = 0; - CHAR msg[2048]; - CHAR arg[255]; - INT rfId; - LONG rfValue; - int Status; - BOOLEAN bIsPrintAllRF = FALSE; - - - memset(msg, 0x00, 2048); - if (wrq->u.data.length > 1) //No parameters. - { - Status = copy_from_user(arg, wrq->u.data.pointer, (wrq->u.data.length > 255) ? 255 : wrq->u.data.length); - sprintf(msg, "\n"); - - //Parsing Read or Write - this_char = arg; - if (!*this_char) - goto next; - - if ((value = strchr(this_char, '=')) != NULL) - *value++ = 0; - - if (!value || !*value) - { //Read - if (sscanf(this_char, "%d", &(rfId)) == 1) - { - if (rfId <= 31) - { - // In RT2860 ATE mode, we do not load 8051 firmware. - //We must access RF directly. - // For RT2870 ATE mode, ATE_RF_IO_WRITE8(/READ8)_BY_REG_ID are redefined. -#ifdef RALINK_ATE - if (ATE_ON(pAdapter)) - { - ATE_RF_IO_READ8_BY_REG_ID(pAdapter, rfId, ®RF); - } - else -#endif // RALINK_ATE // - // according to Andy, Gary, David require. - // the command rf shall read rf register directly for dubug. - // BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); - RT30xxReadRFRegister(pAdapter, rfId, ®RF); - - sprintf(msg+strlen(msg), "R%02d[0x%02x]:%02X ", rfId, rfId*2, regRF); - } - else - {//Invalid parametes, so default printk all RF - bIsPrintAllRF = TRUE; - goto next; - } - } - else - { //Invalid parametes, so default printk all RF - bIsPrintAllRF = TRUE; - goto next; - } - } - else - { //Write - if ((sscanf(this_char, "%d", &(rfId)) == 1) && (sscanf(value, "%lx", &(rfValue)) == 1)) - { - if (rfId <= 31) - { - // In RT2860 ATE mode, we do not load 8051 firmware. - // We should access RF registers directly. - // For RT2870 ATE mode, ATE_RF_IO_WRITE8/READ8_BY_REG_ID are redefined. -#ifdef RALINK_ATE - if (ATE_ON(pAdapter)) - { - ATE_RF_IO_READ8_BY_REG_ID(pAdapter, rfId, ®RF); - ATE_RF_IO_WRITE8_BY_REG_ID(pAdapter, (UCHAR)rfId,(UCHAR) rfValue); - //Read it back for showing - ATE_RF_IO_READ8_BY_REG_ID(pAdapter, rfId, ®RF); - sprintf(msg+strlen(msg), "R%02d[0x%02X]:%02X\n", rfId, rfId*2, regRF); - } - else -#endif // RALINK_ATE // - { - // according to Andy, Gary, David require. - // the command RF shall read/write RF register directly for dubug. - //BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); - //BBP_IO_WRITE8_BY_REG_ID(pAdapter, (UCHAR)bbpId,(UCHAR) bbpValue); - RT30xxReadRFRegister(pAdapter, rfId, ®RF); - RT30xxWriteRFRegister(pAdapter, (UCHAR)rfId,(UCHAR) rfValue); - //Read it back for showing - //BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); - RT30xxReadRFRegister(pAdapter, rfId, ®RF); - sprintf(msg+strlen(msg), "R%02d[0x%02X]:%02X\n", rfId, rfId*2, regRF); - } - } - else - {//Invalid parametes, so default printk all RF - bIsPrintAllRF = TRUE; - } - } - else - { //Invalid parametes, so default printk all RF - bIsPrintAllRF = TRUE; - } - } - } - else - bIsPrintAllRF = TRUE; -next: - if (bIsPrintAllRF) - { - memset(msg, 0x00, 2048); - sprintf(msg, "\n"); - for (rfId = 0; rfId <= 31; rfId++) - { - // In RT2860 ATE mode, we do not load 8051 firmware. - // We should access RF registers directly. - // For RT2870 ATE mode, ATE_RF_IO_WRITE8/READ8_BY_REG_ID are redefined. -#ifdef RALINK_ATE - if (ATE_ON(pAdapter)) - { - ATE_RF_IO_READ8_BY_REG_ID(pAdapter, rfId, ®RF); - } - else -#endif // RALINK_ATE // - - // according to Andy, Gary, David require. - // the command RF shall read/write RF register directly for dubug. - RT30xxReadRFRegister(pAdapter, rfId, ®RF); - sprintf(msg+strlen(msg), "%03d = %02X\n", rfId, regRF); - } - // Copy the information into the user buffer - DBGPRINT(RT_DEBUG_TRACE, ("strlen(msg)=%d\n", (UINT32)strlen(msg))); - wrq->u.data.length = strlen(msg); - if (copy_to_user(wrq->u.data.pointer, msg, wrq->u.data.length)) - { - DBGPRINT(RT_DEBUG_TRACE, ("%s: copy_to_user() fail\n", __FUNCTION__)); - } - } - else - { - if(strlen(msg) == 1) - sprintf(msg+strlen(msg), "===>Error command format!"); - - DBGPRINT(RT_DEBUG_TRACE, ("copy to user [msg=%s]\n", msg)); - // Copy the information into the user buffer - DBGPRINT(RT_DEBUG_TRACE, ("strlen(msg) =%d\n", (UINT32)strlen(msg))); - - // Copy the information into the user buffer - wrq->u.data.length = strlen(msg); - Status = copy_to_user(wrq->u.data.pointer, msg, wrq->u.data.length); - } - - DBGPRINT(RT_DEBUG_TRACE, ("<==RTMPIoctlRF\n\n")); -} -#endif // RT30xx // -#endif // DBG // - - - - -INT Set_TGnWifiTest_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - if (simple_strtol(arg, 0, 10) == 0) - pAd->StaCfg.bTGnWifiTest = FALSE; - else - pAd->StaCfg.bTGnWifiTest = TRUE; - - DBGPRINT(RT_DEBUG_TRACE, ("IF Set_TGnWifiTest_Proc::(bTGnWifiTest=%d)\n", pAd->StaCfg.bTGnWifiTest)); - return TRUE; -} - -INT Set_LongRetryLimit_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - TX_RTY_CFG_STRUC tx_rty_cfg; - UCHAR LongRetryLimit = (UCHAR)simple_strtol(arg, 0, 10); - - RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); - tx_rty_cfg.field.LongRtyLimit = LongRetryLimit; - RTMP_IO_WRITE32(pAdapter, TX_RTY_CFG, tx_rty_cfg.word); - DBGPRINT(RT_DEBUG_TRACE, ("IF Set_LongRetryLimit_Proc::(tx_rty_cfg=0x%x)\n", tx_rty_cfg.word)); - return TRUE; -} - -INT Set_ShortRetryLimit_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - TX_RTY_CFG_STRUC tx_rty_cfg; - UCHAR ShortRetryLimit = (UCHAR)simple_strtol(arg, 0, 10); - - RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); - tx_rty_cfg.field.ShortRtyLimit = ShortRetryLimit; - RTMP_IO_WRITE32(pAdapter, TX_RTY_CFG, tx_rty_cfg.word); - DBGPRINT(RT_DEBUG_TRACE, ("IF Set_ShortRetryLimit_Proc::(tx_rty_cfg=0x%x)\n", tx_rty_cfg.word)); - return TRUE; -} - -#ifdef EXT_BUILD_CHANNEL_LIST -INT Set_Ieee80211dClientMode_Proc( - IN PRTMP_ADAPTER pAdapter, - IN PUCHAR arg) -{ - if (simple_strtol(arg, 0, 10) == 0) - pAdapter->StaCfg.IEEE80211dClientMode = Rt802_11_D_None; - else if (simple_strtol(arg, 0, 10) == 1) - pAdapter->StaCfg.IEEE80211dClientMode = Rt802_11_D_Flexible; - else if (simple_strtol(arg, 0, 10) == 2) - pAdapter->StaCfg.IEEE80211dClientMode = Rt802_11_D_Strict; - else - return FALSE; - - DBGPRINT(RT_DEBUG_TRACE, ("Set_Ieee802dMode_Proc::(IEEEE0211dMode=%d)\n", pAdapter->StaCfg.IEEE80211dClientMode)); - return TRUE; -} -#endif // EXT_BUILD_CHANNEL_LIST // - -#ifdef CARRIER_DETECTION_SUPPORT -INT Set_CarrierDetect_Proc( - IN PRTMP_ADAPTER pAd, - IN PUCHAR arg) -{ - if (simple_strtol(arg, 0, 10) == 0) - pAd->CommonCfg.CarrierDetect.Enable = FALSE; - else - pAd->CommonCfg.CarrierDetect.Enable = TRUE; - - DBGPRINT(RT_DEBUG_TRACE, ("IF Set_CarrierDetect_Proc::(CarrierDetect.Enable=%d)\n", pAd->CommonCfg.CarrierDetect.Enable)); - return TRUE; -} -#endif // CARRIER_DETECTION_SUPPORT // - +#include "../rt2870/sta_ioctl.c" diff --git a/drivers/staging/rt3070/wpa.h b/drivers/staging/rt3070/wpa.h index 88c7c8bf3fcd..94bb23279400 100644 --- a/drivers/staging/rt3070/wpa.h +++ b/drivers/staging/rt3070/wpa.h @@ -1,356 +1 @@ -/* - ************************************************************************* - * Ralink Tech Inc. - * 5F., No.36, Taiyuan St., Jhubei City, - * Hsinchu County 302, - * Taiwan, R.O.C. - * - * (c) Copyright 2002-2007, Ralink Technology, 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. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - ************************************************************************* - - Module Name: - wpa.h - - Abstract: - - Revision History: - Who When What - -------- ---------- ---------------------------------------------- - Name Date Modification logs -*/ - -#ifndef __WPA_H__ -#define __WPA_H__ - -// EAPOL Key descripter frame format related length -#define LEN_KEY_DESC_NONCE 32 -#define LEN_KEY_DESC_IV 16 -#define LEN_KEY_DESC_RSC 8 -#define LEN_KEY_DESC_ID 8 -#define LEN_KEY_DESC_REPLAY 8 -#define LEN_KEY_DESC_MIC 16 - -// The length is the EAPoL-Key frame except key data field. -// Please refer to 802.11i-2004 ,Figure 43u in p.78 -#define LEN_EAPOL_KEY_MSG (sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE) - -// EAP Code Type. -#define EAP_CODE_REQUEST 1 -#define EAP_CODE_RESPONSE 2 -#define EAP_CODE_SUCCESS 3 -#define EAP_CODE_FAILURE 4 - -// EAPOL frame Protocol Version -#define EAPOL_VER 1 -#define EAPOL_VER2 2 - -// EAPOL-KEY Descriptor Type -#define WPA1_KEY_DESC 0xfe -#define WPA2_KEY_DESC 0x02 - -// Key Descriptor Version of Key Information -#define DESC_TYPE_TKIP 1 -#define DESC_TYPE_AES 2 -#define DESC_TYPE_MESH 3 - -#define LEN_MSG1_2WAY 0x7f -#define MAX_LEN_OF_EAP_HS 256 - -#define LEN_MASTER_KEY 32 - -// EAPOL EK, MK -#define LEN_EAP_EK 16 -#define LEN_EAP_MICK 16 -#define LEN_EAP_KEY ((LEN_EAP_EK)+(LEN_EAP_MICK)) -// TKIP key related -#define LEN_PMKID 16 -#define LEN_TKIP_EK 16 -#define LEN_TKIP_RXMICK 8 -#define LEN_TKIP_TXMICK 8 -#define LEN_AES_EK 16 -#define LEN_AES_KEY LEN_AES_EK -#define LEN_TKIP_KEY ((LEN_TKIP_EK)+(LEN_TKIP_RXMICK)+(LEN_TKIP_TXMICK)) -#define TKIP_AP_TXMICK_OFFSET ((LEN_EAP_KEY)+(LEN_TKIP_EK)) -#define TKIP_AP_RXMICK_OFFSET (TKIP_AP_TXMICK_OFFSET+LEN_TKIP_TXMICK) -#define TKIP_GTK_LENGTH ((LEN_TKIP_EK)+(LEN_TKIP_RXMICK)+(LEN_TKIP_TXMICK)) -#define LEN_PTK ((LEN_EAP_KEY)+(LEN_TKIP_KEY)) - -// RSN IE Length definition -#define MAX_LEN_OF_RSNIE 90 -#define MIN_LEN_OF_RSNIE 8 - -//EAP Packet Type -#define EAPPacket 0 -#define EAPOLStart 1 -#define EAPOLLogoff 2 -#define EAPOLKey 3 -#define EAPOLASFAlert 4 -#define EAPTtypeMax 5 - -#define EAPOL_MSG_INVALID 0 -#define EAPOL_PAIR_MSG_1 1 -#define EAPOL_PAIR_MSG_2 2 -#define EAPOL_PAIR_MSG_3 3 -#define EAPOL_PAIR_MSG_4 4 -#define EAPOL_GROUP_MSG_1 5 -#define EAPOL_GROUP_MSG_2 6 - -#define PAIRWISEKEY 1 -#define GROUPKEY 0 - -// Retry timer counter initial value -#define PEER_MSG1_RETRY_TIMER_CTR 0 -#define PEER_MSG3_RETRY_TIMER_CTR 10 -#define GROUP_MSG1_RETRY_TIMER_CTR 20 - - -#define EAPOL_START_DISABLE 0 -#define EAPOL_START_PSK 1 -#define EAPOL_START_1X 2 - -#define MIX_CIPHER_WPA_TKIP_ON(x) (((x) & 0x08) != 0) -#define MIX_CIPHER_WPA_AES_ON(x) (((x) & 0x04) != 0) -#define MIX_CIPHER_WPA2_TKIP_ON(x) (((x) & 0x02) != 0) -#define MIX_CIPHER_WPA2_AES_ON(x) (((x) & 0x01) != 0) - -#define ROUND_UP(__x, __y) \ - (((ULONG)((__x)+((__y)-1))) & ((ULONG)~((__y)-1))) - -#define ADD_ONE_To_64BIT_VAR(_V) \ -{ \ - UCHAR cnt = LEN_KEY_DESC_REPLAY; \ - do \ - { \ - cnt--; \ - _V[cnt]++; \ - if (cnt == 0) \ - break; \ - }while (_V[cnt] == 0); \ -} - -#define IS_WPA_CAPABILITY(a) (((a) >= Ndis802_11AuthModeWPA) && ((a) <= Ndis802_11AuthModeWPA1PSKWPA2PSK)) - -// EAPOL Key Information definition within Key descriptor format -typedef struct PACKED _KEY_INFO -{ -#ifdef RT_BIG_ENDIAN - UCHAR KeyAck:1; - UCHAR Install:1; - UCHAR KeyIndex:2; - UCHAR KeyType:1; - UCHAR KeyDescVer:3; - UCHAR Rsvd:3; - UCHAR EKD_DL:1; // EKD for AP; DL for STA - UCHAR Request:1; - UCHAR Error:1; - UCHAR Secure:1; - UCHAR KeyMic:1; -#else - UCHAR KeyMic:1; - UCHAR Secure:1; - UCHAR Error:1; - UCHAR Request:1; - UCHAR EKD_DL:1; // EKD for AP; DL for STA - UCHAR Rsvd:3; - UCHAR KeyDescVer:3; - UCHAR KeyType:1; - UCHAR KeyIndex:2; - UCHAR Install:1; - UCHAR KeyAck:1; -#endif -} KEY_INFO, *PKEY_INFO; - -// EAPOL Key descriptor format -typedef struct PACKED _KEY_DESCRIPTER -{ - UCHAR Type; - KEY_INFO KeyInfo; - UCHAR KeyLength[2]; - UCHAR ReplayCounter[LEN_KEY_DESC_REPLAY]; - UCHAR KeyNonce[LEN_KEY_DESC_NONCE]; - UCHAR KeyIv[LEN_KEY_DESC_IV]; - UCHAR KeyRsc[LEN_KEY_DESC_RSC]; - UCHAR KeyId[LEN_KEY_DESC_ID]; - UCHAR KeyMic[LEN_KEY_DESC_MIC]; - UCHAR KeyDataLen[2]; - UCHAR KeyData[MAX_LEN_OF_RSNIE]; -} KEY_DESCRIPTER, *PKEY_DESCRIPTER; - -typedef struct PACKED _EAPOL_PACKET -{ - UCHAR ProVer; - UCHAR ProType; - UCHAR Body_Len[2]; - KEY_DESCRIPTER KeyDesc; -} EAPOL_PACKET, *PEAPOL_PACKET; - -//802.11i D10 page 83 -typedef struct PACKED _GTK_ENCAP -{ -#ifndef RT_BIG_ENDIAN - UCHAR Kid:2; - UCHAR tx:1; - UCHAR rsv:5; - UCHAR rsv1; -#else - UCHAR rsv:5; - UCHAR tx:1; - UCHAR Kid:2; - UCHAR rsv1; -#endif - UCHAR GTK[TKIP_GTK_LENGTH]; -} GTK_ENCAP, *PGTK_ENCAP; - -typedef struct PACKED _KDE_ENCAP -{ - UCHAR Type; - UCHAR Len; - UCHAR OUI[3]; - UCHAR DataType; - GTK_ENCAP GTKEncap; -} KDE_ENCAP, *PKDE_ENCAP; - -// For WPA1 -typedef struct PACKED _RSNIE { - UCHAR oui[4]; - USHORT version; - UCHAR mcast[4]; - USHORT ucount; - struct PACKED { - UCHAR oui[4]; - }ucast[1]; -} RSNIE, *PRSNIE; - -// For WPA2 -typedef struct PACKED _RSNIE2 { - USHORT version; - UCHAR mcast[4]; - USHORT ucount; - struct PACKED { - UCHAR oui[4]; - }ucast[1]; -} RSNIE2, *PRSNIE2; - -// AKM Suite -typedef struct PACKED _RSNIE_AUTH { - USHORT acount; - struct PACKED { - UCHAR oui[4]; - }auth[1]; -} RSNIE_AUTH,*PRSNIE_AUTH; - -typedef union PACKED _RSN_CAPABILITIES { - struct PACKED { -#ifdef RT_BIG_ENDIAN - USHORT Rsvd:10; - USHORT GTKSA_R_Counter:2; - USHORT PTKSA_R_Counter:2; - USHORT No_Pairwise:1; - USHORT PreAuth:1; -#else - USHORT PreAuth:1; - USHORT No_Pairwise:1; - USHORT PTKSA_R_Counter:2; - USHORT GTKSA_R_Counter:2; - USHORT Rsvd:10; -#endif - } field; - USHORT word; -} RSN_CAPABILITIES, *PRSN_CAPABILITIES; - -typedef struct PACKED _EAP_HDR { - UCHAR ProVer; - UCHAR ProType; - UCHAR Body_Len[2]; - UCHAR code; - UCHAR identifier; - UCHAR length[2]; // including code and identifier, followed by length-2 octets of data -} EAP_HDR, *PEAP_HDR; - -// For supplicant state machine states. 802.11i Draft 4.1, p. 97 -// We simplified it -typedef enum _WpaState -{ - SS_NOTUSE, // 0 - SS_START, // 1 - SS_WAIT_MSG_3, // 2 - SS_WAIT_GROUP, // 3 - SS_FINISH, // 4 - SS_KEYUPDATE, // 5 -} WPA_STATE; - -// -// The definition of the cipher combination -// -// bit3 bit2 bit1 bit0 -// +------------+------------+ -// | WPA | WPA2 | -// +------+-----+------+-----+ -// | TKIP | AES | TKIP | AES | -// | 0 | 1 | 1 | 0 | -> 0x06 -// | 0 | 1 | 1 | 1 | -> 0x07 -// | 1 | 0 | 0 | 1 | -> 0x09 -// | 1 | 0 | 1 | 1 | -> 0x0B -// | 1 | 1 | 0 | 1 | -> 0x0D -// | 1 | 1 | 1 | 0 | -> 0x0E -// | 1 | 1 | 1 | 1 | -> 0x0F -// +------+-----+------+-----+ -// -typedef enum _WpaMixPairCipher -{ - MIX_CIPHER_NOTUSE = 0x00, - WPA_NONE_WPA2_TKIPAES = 0x03, // WPA2-TKIPAES - WPA_AES_WPA2_TKIP = 0x06, - WPA_AES_WPA2_TKIPAES = 0x07, - WPA_TKIP_WPA2_AES = 0x09, - WPA_TKIP_WPA2_TKIPAES = 0x0B, - WPA_TKIPAES_WPA2_NONE = 0x0C, // WPA-TKIPAES - WPA_TKIPAES_WPA2_AES = 0x0D, - WPA_TKIPAES_WPA2_TKIP = 0x0E, - WPA_TKIPAES_WPA2_TKIPAES = 0x0F, -} WPA_MIX_PAIR_CIPHER; - -typedef struct PACKED _RSN_IE_HEADER_STRUCT { - UCHAR Eid; - UCHAR Length; - USHORT Version; // Little endian format -} RSN_IE_HEADER_STRUCT, *PRSN_IE_HEADER_STRUCT; - -// Cipher suite selector types -typedef struct PACKED _CIPHER_SUITE_STRUCT { - UCHAR Oui[3]; - UCHAR Type; -} CIPHER_SUITE_STRUCT, *PCIPHER_SUITE_STRUCT; - -// Authentication and Key Management suite selector -typedef struct PACKED _AKM_SUITE_STRUCT { - UCHAR Oui[3]; - UCHAR Type; -} AKM_SUITE_STRUCT, *PAKM_SUITE_STRUCT; - -// RSN capability -typedef struct PACKED _RSN_CAPABILITY { - USHORT Rsv:10; - USHORT GTKSAReplayCnt:2; - USHORT PTKSAReplayCnt:2; - USHORT NoPairwise:1; - USHORT PreAuth:1; -} RSN_CAPABILITY, *PRSN_CAPABILITY; - -#endif +#include "../rt2870/wpa.h" diff --git a/drivers/staging/rtl8187se/Kconfig b/drivers/staging/rtl8187se/Kconfig index f636296b54bc..236e42725447 100644 --- a/drivers/staging/rtl8187se/Kconfig +++ b/drivers/staging/rtl8187se/Kconfig @@ -1,6 +1,6 @@ config RTL8187SE tristate "RealTek RTL8187SE Wireless LAN NIC driver" depends on PCI - depends on WIRELESS_EXT && COMPAT_NET_DEV_OPS + depends on WIRELESS_EXT default N ---help--- diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_module.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_module.c index 0c9fef0b4e3f..c2b61e648e4e 100644 --- a/drivers/staging/rtl8187se/ieee80211/ieee80211_module.c +++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_module.c @@ -114,7 +114,6 @@ struct net_device *alloc_ieee80211(int sizeof_priv) goto failed; } ieee = netdev_priv(dev); - dev->hard_start_xmit = ieee80211_xmit; ieee->dev = dev; diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c index 23519b37538f..4d4ee563275e 100644 --- a/drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c +++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c @@ -1680,7 +1680,7 @@ inline void update_network(struct ieee80211_network *dst, if(src->wmm_param[0].ac_aci_acm_aifsn|| \ src->wmm_param[1].ac_aci_acm_aifsn|| \ src->wmm_param[2].ac_aci_acm_aifsn|| \ - src->wmm_param[1].ac_aci_acm_aifsn) { + src->wmm_param[3].ac_aci_acm_aifsn) { memcpy(dst->wmm_param, src->wmm_param, WME_AC_PRAM_LEN); } dst->QoS_Enable = src->QoS_Enable; diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c index 33a0687252af..1294e05fcf13 100644 --- a/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c +++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c @@ -814,7 +814,7 @@ int ieee80211_xmit(struct sk_buff *skb, spin_unlock_irqrestore(&ieee->lock, flags); netif_stop_queue(dev); stats->tx_errors++; - return 1; + return NETDEV_TX_BUSY; } diff --git a/drivers/staging/rtl8187se/r8180_core.c b/drivers/staging/rtl8187se/r8180_core.c index e10413cee0df..7e2fecae813c 100644 --- a/drivers/staging/rtl8187se/r8180_core.c +++ b/drivers/staging/rtl8187se/r8180_core.c @@ -198,7 +198,8 @@ static void __devexit rtl8180_pci_remove(struct pci_dev *pdev); static void rtl8180_shutdown (struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); - dev->stop(dev); + if (dev->netdev_ops->ndo_stop) + dev->netdev_ops->ndo_stop(dev); pci_disable_device(pdev); } @@ -4551,8 +4552,6 @@ short rtl8180_init(struct net_device *dev) //DMESG("Reported EEPROM chip is a 93c46 (1Kbit)"); } - dev->get_stats = rtl8180_stats; - dev->dev_addr[0]=eprom_read(dev,MAC_ADR) & 0xff; dev->dev_addr[1]=(eprom_read(dev,MAC_ADR) & 0xff00)>>8; dev->dev_addr[2]=eprom_read(dev,MAC_ADR+1) & 0xff; @@ -5832,6 +5831,18 @@ int rtl8180_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -----------------------------PCI STUFF--------------------------- *****************************************************************************/ +static const struct net_device_ops rtl8180_netdev_ops = { + .ndo_open = rtl8180_open, + .ndo_stop = rtl8180_close, + .ndo_get_stats = rtl8180_stats, + .ndo_tx_timeout = rtl8180_restart, + .ndo_do_ioctl = rtl8180_ioctl, + .ndo_set_multicast_list = r8180_set_multicast, + .ndo_set_mac_address = r8180_set_mac_adr, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, + .ndo_start_xmit = ieee80211_xmit, +}; static int __devinit rtl8180_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) @@ -5936,14 +5947,8 @@ static int __devinit rtl8180_pci_probe(struct pci_dev *pdev, dev->irq = pdev->irq; priv->irq = 0; - dev->open = rtl8180_open; - dev->stop = rtl8180_close; - //dev->hard_start_xmit = ieee80211_xmit; - dev->tx_timeout = rtl8180_restart; + dev->netdev_ops = &rtl8180_netdev_ops; dev->wireless_handlers = &r8180_wx_handlers_def; - dev->do_ioctl = rtl8180_ioctl; - dev->set_multicast_list = r8180_set_multicast; - dev->set_mac_address = r8180_set_mac_adr; #if WIRELESS_EXT >= 12 #if WIRELESS_EXT < 17 diff --git a/drivers/staging/rtl8187se/r8180_dm.c b/drivers/staging/rtl8187se/r8180_dm.c index 93b5a7bb2559..e772f0f6b67c 100644 --- a/drivers/staging/rtl8187se/r8180_dm.c +++ b/drivers/staging/rtl8187se/r8180_dm.c @@ -132,7 +132,7 @@ void rtl8180_tx_pw_wq (struct work_struct *work) // struct r8180_priv *priv = container_of(work, struct r8180_priv, watch_dog_wq); // struct ieee80211_device * ieee = (struct ieee80211_device*) // container_of(work, struct ieee80211_device, watch_dog_wq); - struct delayed_work *dwork = container_of(work,struct delayed_work,work); + struct delayed_work *dwork = to_delayed_work(work); struct ieee80211_device *ieee = container_of(dwork,struct ieee80211_device,tx_pw_wq); struct net_device *dev = ieee->dev; #else @@ -314,7 +314,7 @@ void rtl8180_hw_dig_wq (struct work_struct *work) // struct r8180_priv *priv = container_of(work, struct r8180_priv, watch_dog_wq); // struct ieee80211_device * ieee = (struct ieee80211_device*) // container_of(work, struct ieee80211_device, watch_dog_wq); - struct delayed_work *dwork = container_of(work,struct delayed_work,work); + struct delayed_work *dwork = to_delayed_work(work); struct ieee80211_device *ieee = container_of(dwork,struct ieee80211_device,hw_dig_wq); struct net_device *dev = ieee->dev; #else @@ -1250,7 +1250,7 @@ SetInitialGain: #if LINUX_VERSION_CODE >=KERNEL_VERSION(2,6,20) void rtl8180_rate_adapter(struct work_struct * work) { - struct delayed_work *dwork = container_of(work,struct delayed_work,work); + struct delayed_work *dwork = to_delayed_work(work); struct ieee80211_device *ieee = container_of(dwork,struct ieee80211_device,rate_adapter_wq); struct net_device *dev = ieee->dev; #else diff --git a/drivers/staging/rtl8187se/r8180_pm.c b/drivers/staging/rtl8187se/r8180_pm.c index 3851b9368356..2b3d642db77f 100644 --- a/drivers/staging/rtl8187se/r8180_pm.c +++ b/drivers/staging/rtl8187se/r8180_pm.c @@ -30,7 +30,8 @@ int rtl8180_suspend (struct pci_dev *pdev, pm_message_t state) if (!netif_running(dev)) goto out_pci_suspend; - dev->stop(dev); + if (dev->netdev_ops->ndo_stop) + dev->netdev_ops->ndo_stop(dev); netif_device_detach(dev); @@ -71,7 +72,8 @@ int rtl8180_resume (struct pci_dev *pdev) if(!netif_running(dev)) goto out; - dev->open(dev); + if (dev->netdev_ops->ndo_open) + dev->netdev_ops->ndo_open(dev); netif_device_attach(dev); out: return 0; diff --git a/drivers/staging/rtl8192su/Kconfig b/drivers/staging/rtl8192su/Kconfig new file mode 100644 index 000000000000..4b5552c5926e --- /dev/null +++ b/drivers/staging/rtl8192su/Kconfig @@ -0,0 +1,6 @@ +config RTL8192SU + tristate "RealTek RTL8192SU Wireless LAN NIC driver" + depends on PCI + depends on WIRELESS_EXT && COMPAT_NET_DEV_OPS + default N + ---help--- diff --git a/drivers/staging/rtl8192su/Makefile b/drivers/staging/rtl8192su/Makefile new file mode 100644 index 000000000000..f010ab502a97 --- /dev/null +++ b/drivers/staging/rtl8192su/Makefile @@ -0,0 +1,66 @@ +NIC_SELECT = RTL8192SU + +EXTRA_CFLAGS += -std=gnu89 +EXTRA_CFLAGS += -O2 +EXTRA_CFLAGS += -mhard-float -DCONFIG_FORCE_HARD_FLOAT=y + +EXTRA_CFLAGS += -DJACKSON_NEW_RX +EXTRA_CFLAGS += -DTHOMAS_BEACON -DTHOMAS_TURBO +#EXTRA_CFLAGS += -DUSE_ONE_PIPE +EXTRA_CFLAGS += -DENABLE_DOT11D + +EXTRA_CFLAGS += -DRTL8192SU +EXTRA_CFLAGS += -DRTL8190_Download_Firmware_From_Header=1 +EXTRA_CFLAGS += -DRTL8192S_PREPARE_FOR_NORMAL_RELEASE +EXTRA_CFLAGS += -DRTL8192SU_DISABLE_IQK=1 + +#EXTRA_CFLAGS += -DEEPROM_OLD_FORMAT_SUPPORT + +#EXTRA_CFLAGS += -DUSB_RX_AGGREGATION_SUPPORT=0 +#EXTRA_CFLAGS += -DUSB_TX_DRIVER_AGGREGATION_ENABLE=0 +#EXTRA_CFLAGS += -DRTL8192SU_DISABLE_CCK_RATE=0 +EXTRA_CFLAGS += -DRTL8192S_DISABLE_FW_DM=0 +EXTRA_CFLAGS += -DDISABLE_BB_RF=0 +EXTRA_CFLAGS += -DRTL8192SU_USE_PARAM_TXPWR=0 +EXTRA_CFLAGS += -DRTL8192SU_FPGA_UNSPECIFIED_NETWORK=0 +#EXTRA_CFLAGS += -DRTL8192SU_FPGA_2MAC_VERIFICATION #=0 +EXTRA_CFLAGS += -DRTL8192SU_ASIC_VERIFICATION +EXTRA_CFLAGS += -DRTL8192SU_USB_PHY_TEST=0 + +#EXTRA_CFLAGS += -DMUTIPLE_BULK_OUT +EXTRA_CFLAGS += -DCONFIG_RTL8192_PM + +r8192s_usb-objs := \ + r8180_93cx6.o \ + r8192U_wx.o \ + r8192S_phy.o \ + r8192S_rtl6052.o \ + r8192S_rtl8225.o \ + r819xU_cmdpkt.o \ + r8192U_dm.o \ + r8192SU_HWImg.o \ + r8192S_firmware.o \ + r8192S_Efuse.o \ + r8192U_core.o \ + r8192U_pm.o + +ieee80211-rsl-objs := \ + ieee80211/ieee80211_rx.o \ + ieee80211/ieee80211_softmac.o \ + ieee80211/ieee80211_tx.o \ + ieee80211/ieee80211_wx.o \ + ieee80211/ieee80211_module.o \ + ieee80211/ieee80211_softmac_wx.o\ + ieee80211/rtl819x_HTProc.o \ + ieee80211/rtl819x_TSProc.o \ + ieee80211/rtl819x_BAProc.o \ + ieee80211/dot11d.o + +obj-$(CONFIG_RTL8192SU) += r8192s_usb.o +obj-$(CONFIG_RTL8192SU) += ieee80211-rsl.o +obj-$(CONFIG_RTL8192SU) += ieee80211/ieee80211_crypt.o +obj-$(CONFIG_RTL8192SU) += ieee80211/ieee80211_crypt_tkip.o +obj-$(CONFIG_RTL8192SU) += ieee80211/ieee80211_crypt_ccmp.o +obj-$(CONFIG_RTL8192SU) += ieee80211/ieee80211_crypt_wep.o + + diff --git a/drivers/staging/rtl8192su/authors b/drivers/staging/rtl8192su/authors new file mode 100644 index 000000000000..b08bbae39e72 --- /dev/null +++ b/drivers/staging/rtl8192su/authors @@ -0,0 +1 @@ +Andrea Merello diff --git a/drivers/staging/rtl8192su/dot11d.h b/drivers/staging/rtl8192su/dot11d.h new file mode 100644 index 000000000000..15b7a4ba37b6 --- /dev/null +++ b/drivers/staging/rtl8192su/dot11d.h @@ -0,0 +1,102 @@ +#ifndef __INC_DOT11D_H +#define __INC_DOT11D_H + +#ifdef ENABLE_DOT11D +#include "ieee80211.h" + +//#define ENABLE_DOT11D + +//#define DOT11D_MAX_CHNL_NUM 83 + +typedef struct _CHNL_TXPOWER_TRIPLE { + u8 FirstChnl; + u8 NumChnls; + u8 MaxTxPowerInDbm; +}CHNL_TXPOWER_TRIPLE, *PCHNL_TXPOWER_TRIPLE; + +typedef enum _DOT11D_STATE { + DOT11D_STATE_NONE = 0, + DOT11D_STATE_LEARNED, + DOT11D_STATE_DONE, +}DOT11D_STATE; + +typedef struct _RT_DOT11D_INFO { + //DECLARE_RT_OBJECT(RT_DOT11D_INFO); + + bool bEnabled; // dot11MultiDomainCapabilityEnabled + + u16 CountryIeLen; // > 0 if CountryIeBuf[] contains valid country information element. + u8 CountryIeBuf[MAX_IE_LEN]; + u8 CountryIeSrcAddr[6]; // Source AP of the country IE. + u8 CountryIeWatchdog; + + u8 channel_map[MAX_CHANNEL_NUMBER+1]; //!!!Value 0: Invalid, 1: Valid (active scan), 2: Valid (passive scan) + //u8 ChnlListLen; // #Bytes valid in ChnlList[]. + //u8 ChnlList[DOT11D_MAX_CHNL_NUM]; + u8 MaxTxPwrDbmList[MAX_CHANNEL_NUMBER+1]; + + DOT11D_STATE State; +}RT_DOT11D_INFO, *PRT_DOT11D_INFO; +#define eqMacAddr(a,b) ( ((a)[0]==(b)[0] && (a)[1]==(b)[1] && (a)[2]==(b)[2] && (a)[3]==(b)[3] && (a)[4]==(b)[4] && (a)[5]==(b)[5]) ? 1:0 ) +#define cpMacAddr(des,src) ((des)[0]=(src)[0],(des)[1]=(src)[1],(des)[2]=(src)[2],(des)[3]=(src)[3],(des)[4]=(src)[4],(des)[5]=(src)[5]) +#define GET_DOT11D_INFO(__pIeeeDev) ((PRT_DOT11D_INFO)((__pIeeeDev)->pDot11dInfo)) + +#define IS_DOT11D_ENABLE(__pIeeeDev) GET_DOT11D_INFO(__pIeeeDev)->bEnabled +#define IS_COUNTRY_IE_VALID(__pIeeeDev) (GET_DOT11D_INFO(__pIeeeDev)->CountryIeLen > 0) + +#define IS_EQUAL_CIE_SRC(__pIeeeDev, __pTa) eqMacAddr(GET_DOT11D_INFO(__pIeeeDev)->CountryIeSrcAddr, __pTa) +#define UPDATE_CIE_SRC(__pIeeeDev, __pTa) cpMacAddr(GET_DOT11D_INFO(__pIeeeDev)->CountryIeSrcAddr, __pTa) + +#define IS_COUNTRY_IE_CHANGED(__pIeeeDev, __Ie) \ + (((__Ie).Length == 0 || (__Ie).Length != GET_DOT11D_INFO(__pIeeeDev)->CountryIeLen) ? \ + FALSE : \ + (!memcmp(GET_DOT11D_INFO(__pIeeeDev)->CountryIeBuf, (__Ie).Octet, (__Ie).Length))) + +#define CIE_WATCHDOG_TH 1 +#define GET_CIE_WATCHDOG(__pIeeeDev) GET_DOT11D_INFO(__pIeeeDev)->CountryIeWatchdog +#define RESET_CIE_WATCHDOG(__pIeeeDev) GET_CIE_WATCHDOG(__pIeeeDev) = 0 +#define UPDATE_CIE_WATCHDOG(__pIeeeDev) ++GET_CIE_WATCHDOG(__pIeeeDev) + +#define IS_DOT11D_STATE_DONE(__pIeeeDev) (GET_DOT11D_INFO(__pIeeeDev)->State == DOT11D_STATE_DONE) + + +void +Dot11d_Init( + struct ieee80211_device *dev + ); + +void +Dot11d_Reset( + struct ieee80211_device *dev + ); + +void +Dot11d_UpdateCountryIe( + struct ieee80211_device *dev, + u8 * pTaddr, + u16 CoutryIeLen, + u8 * pCoutryIe + ); + +u8 +DOT11D_GetMaxTxPwrInDbm( + struct ieee80211_device *dev, + u8 Channel + ); + +void +DOT11D_ScanComplete( + struct ieee80211_device * dev + ); + +int IsLegalChannel( + struct ieee80211_device * dev, + u8 channel +); + +int ToLegalChannel( + struct ieee80211_device * dev, + u8 channel +); +#endif //ENABLE_DOT11D +#endif // #ifndef __INC_DOT11D_H diff --git a/drivers/staging/rtl8192su/ieee80211.h b/drivers/staging/rtl8192su/ieee80211.h new file mode 100644 index 000000000000..0edb09a536f9 --- /dev/null +++ b/drivers/staging/rtl8192su/ieee80211.h @@ -0,0 +1,2901 @@ +/* + * Merged with mainline ieee80211.h in Aug 2004. Original ieee802_11 + * remains copyright by the original authors + * + * Portions of the merged code are based on Host AP (software wireless + * LAN access point) driver for Intersil Prism2/2.5/3. + * + * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen + * + * Copyright (c) 2002-2003, Jouni Malinen + * + * Adaption to a generic IEEE 802.11 stack by James Ketrenos + * + * Copyright (c) 2004, Intel Corporation + * + * Modified for Realtek's wi-fi cards by Andrea Merello + * + * + * 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. See README and COPYING for + * more details. + */ +#ifndef IEEE80211_H +#define IEEE80211_H +#include /* ETH_ALEN */ +#include /* ARRAY_SIZE */ +#include +#include +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) +#include +#else +#include +#include +#endif +#include +#include + +#include +#include + +#include "ieee80211/rtl819x_HT.h" +#include "ieee80211/rtl819x_BA.h" +#include "ieee80211/rtl819x_TS.h" + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)) +#ifndef bool +typedef enum{false = 0, true} bool; +#endif +#endif + +#ifndef IW_MODE_MONITOR +#define IW_MODE_MONITOR 6 +#endif + +#ifndef IWEVCUSTOM +#define IWEVCUSTOM 0x8c02 +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) +#ifndef __bitwise +#define __bitwise __attribute__((bitwise)) +#endif +typedef __u16 __le16; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,27)) +struct iw_spy_data{ + /* --- Standard spy support --- */ + int spy_number; + u_char spy_address[IW_MAX_SPY][ETH_ALEN]; + struct iw_quality spy_stat[IW_MAX_SPY]; + /* --- Enhanced spy support (event) */ + struct iw_quality spy_thr_low; /* Low threshold */ + struct iw_quality spy_thr_high; /* High threshold */ + u_char spy_thr_under[IW_MAX_SPY]; +}; +#endif +#endif + +#ifndef container_of +/** + * container_of - cast a member of a structure out to the containing structure + * + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + * + */ +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) +#endif + +#define KEY_TYPE_NA 0x0 +#define KEY_TYPE_WEP40 0x1 +#define KEY_TYPE_TKIP 0x2 +#define KEY_TYPE_CCMP 0x4 +#define KEY_TYPE_WEP104 0x5 + +/* added for rtl819x tx procedure */ +#define MAX_QUEUE_SIZE 0x10 + +// +// 8190 queue mapping +// +#define BK_QUEUE 0 +#define BE_QUEUE 1 +#define VI_QUEUE 2 +#define VO_QUEUE 3 +#define HCCA_QUEUE 4 +#define TXCMD_QUEUE 5 +#define MGNT_QUEUE 6 +#define HIGH_QUEUE 7 +#define BEACON_QUEUE 8 + +#define LOW_QUEUE BE_QUEUE +#define NORMAL_QUEUE MGNT_QUEUE + +//added by amy for ps +#define SWRF_TIMEOUT 50 + +//added by amy for LEAP related +#define IE_CISCO_FLAG_POSITION 0x08 // Flag byte: byte 8, numbered from 0. +#define SUPPORT_CKIP_MIC 0x08 // bit3 +#define SUPPORT_CKIP_PK 0x10 // bit4 +//added by amy for ps +// RF Off Level for IPS or HW/SW radio off +#define RT_RF_OFF_LEVL_ASPM BIT0 // PCI ASPM +#define RT_RF_OFF_LEVL_CLK_REQ BIT1 // PCI clock request +#define RT_RF_OFF_LEVL_PCI_D3 BIT2 // PCI D3 mode +#define RT_RF_OFF_LEVL_HALT_NIC BIT3 // NIC halt, re-initialize hw parameters +#define RT_RF_OFF_LEVL_FREE_FW BIT4 // FW free, re-download the FW +#define RT_RF_OFF_LEVL_FW_32K BIT5 // FW in 32k +#define RT_RF_PS_LEVEL_ALWAYS_ASPM BIT6 // Always enable ASPM and Clock Req in initialization. +#define RT_RF_LPS_DISALBE_2R BIT30 // When LPS is on, disable 2R if no packet is received or transmittd. +#define RT_RF_LPS_LEVEL_ASPM BIT31 // LPS with ASPM +#define RT_IN_PS_LEVEL(pPSC, _PS_FLAG) ((pPSC->CurPsLevel & _PS_FLAG) ? true : false) +#define RT_CLEAR_PS_LEVEL(pPSC, _PS_FLAG) (pPSC->CurPsLevel &= (~(_PS_FLAG))) +#define RT_SET_PS_LEVEL(pPSC, _PS_FLAG) (pPSC->CurPsLevel->CurPsLevel |= _PS_FLAG) +/* defined for skb cb field */ +/* At most 28 byte */ +typedef struct cb_desc { + /* Tx Desc Related flags (8-9) */ + u8 bLastIniPkt:1; + u8 bCmdOrInit:1; + u8 bFirstSeg:1; + u8 bLastSeg:1; + u8 bEncrypt:1; + u8 bTxDisableRateFallBack:1; + u8 bTxUseDriverAssingedRate:1; + u8 bHwSec:1; //indicate whether use Hw security. WB + + u8 reserved1; + + /* Tx Firmware Relaged flags (10-11)*/ + u8 bCTSEnable:1; + u8 bRTSEnable:1; + u8 bUseShortGI:1; + u8 bUseShortPreamble:1; + u8 bTxEnableFwCalcDur:1; + u8 bAMPDUEnable:1; + u8 bRTSSTBC:1; + u8 RTSSC:1; + + u8 bRTSBW:1; + u8 bPacketBW:1; + u8 bRTSUseShortPreamble:1; + u8 bRTSUseShortGI:1; + u8 bMulticast:1; + u8 bBroadcast:1; + //u8 reserved2:2; + u8 drv_agg_enable:1; + u8 reserved2:1; + + /* Tx Desc related element(12-19) */ + u8 rata_index; + u8 queue_index; + //u8 reserved3; + //u8 reserved4; + u16 txbuf_size; + //u8 reserved5; + u8 RATRIndex; + u8 reserved6; + u8 reserved7; + u8 reserved8; + + /* Tx firmware related element(20-27) */ + u8 data_rate; + u8 rts_rate; + u8 ampdu_factor; + u8 ampdu_density; + //u8 reserved9; + //u8 reserved10; + //u8 reserved11; + u8 DrvAggrNum; + u16 pkt_size; + u8 reserved12; +}cb_desc, *pcb_desc; + +/*--------------------------Define -------------------------------------------*/ +#define MGN_1M 0x02 +#define MGN_2M 0x04 +#define MGN_5_5M 0x0b +#define MGN_11M 0x16 + +#define MGN_6M 0x0c +#define MGN_9M 0x12 +#define MGN_12M 0x18 +#define MGN_18M 0x24 +#define MGN_24M 0x30 +#define MGN_36M 0x48 +#define MGN_48M 0x60 +#define MGN_54M 0x6c + +#define MGN_MCS0 0x80 +#define MGN_MCS1 0x81 +#define MGN_MCS2 0x82 +#define MGN_MCS3 0x83 +#define MGN_MCS4 0x84 +#define MGN_MCS5 0x85 +#define MGN_MCS6 0x86 +#define MGN_MCS7 0x87 +#define MGN_MCS8 0x88 +#define MGN_MCS9 0x89 +#define MGN_MCS10 0x8a +#define MGN_MCS11 0x8b +#define MGN_MCS12 0x8c +#define MGN_MCS13 0x8d +#define MGN_MCS14 0x8e +#define MGN_MCS15 0x8f +#define MGN_MCS0_SG 0x90 +#define MGN_MCS1_SG 0x91 +#define MGN_MCS2_SG 0x92 +#define MGN_MCS3_SG 0x93 +#define MGN_MCS4_SG 0x94 +#define MGN_MCS5_SG 0x95 +#define MGN_MCS6_SG 0x96 +#define MGN_MCS7_SG 0x97 +#define MGN_MCS8_SG 0x98 +#define MGN_MCS9_SG 0x99 +#define MGN_MCS10_SG 0x9a +#define MGN_MCS11_SG 0x9b +#define MGN_MCS12_SG 0x9c +#define MGN_MCS13_SG 0x9d +#define MGN_MCS14_SG 0x9e +#define MGN_MCS15_SG 0x9f + + +//---------------------------------------------------------------------------- +// 802.11 Management frame Reason Code field +//---------------------------------------------------------------------------- +enum _ReasonCode{ + unspec_reason = 0x1, + auth_not_valid = 0x2, + deauth_lv_ss = 0x3, + inactivity = 0x4, + ap_overload = 0x5, + class2_err = 0x6, + class3_err = 0x7, + disas_lv_ss = 0x8, + asoc_not_auth = 0x9, + + //----MIC_CHECK + mic_failure = 0xe, + //----END MIC_CHECK + + // Reason code defined in 802.11i D10.0 p.28. + invalid_IE = 0x0d, + four_way_tmout = 0x0f, + two_way_tmout = 0x10, + IE_dismatch = 0x11, + invalid_Gcipher = 0x12, + invalid_Pcipher = 0x13, + invalid_AKMP = 0x14, + unsup_RSNIEver = 0x15, + invalid_RSNIE = 0x16, + auth_802_1x_fail= 0x17, + ciper_reject = 0x18, + + // Reason code defined in 7.3.1.7, 802.1e D13.0, p.42. Added by Annie, 2005-11-15. + QoS_unspec = 0x20, // 32 + QAP_bandwidth = 0x21, // 33 + poor_condition = 0x22, // 34 + no_facility = 0x23, // 35 + // Where is 36??? + req_declined = 0x25, // 37 + invalid_param = 0x26, // 38 + req_not_honored= 0x27, // 39 + TS_not_created = 0x2F, // 47 + DL_not_allowed = 0x30, // 48 + dest_not_exist = 0x31, // 49 + dest_not_QSTA = 0x32, // 50 +}; + + + +#define aSifsTime (((priv->ieee80211->current_network.mode == IEEE_A)||(priv->ieee80211->current_network.mode == IEEE_N_24G)||(priv->ieee80211->current_network.mode == IEEE_N_5G))? 16 : 10) + +#define MGMT_QUEUE_NUM 5 + +#define IEEE_CMD_SET_WPA_PARAM 1 +#define IEEE_CMD_SET_WPA_IE 2 +#define IEEE_CMD_SET_ENCRYPTION 3 +#define IEEE_CMD_MLME 4 + +#define IEEE_PARAM_WPA_ENABLED 1 +#define IEEE_PARAM_TKIP_COUNTERMEASURES 2 +#define IEEE_PARAM_DROP_UNENCRYPTED 3 +#define IEEE_PARAM_PRIVACY_INVOKED 4 +#define IEEE_PARAM_AUTH_ALGS 5 +#define IEEE_PARAM_IEEE_802_1X 6 +//It should consistent with the driver_XXX.c +// David, 2006.9.26 +#define IEEE_PARAM_WPAX_SELECT 7 +//Added for notify the encryption type selection +// David, 2006.9.26 +#define IEEE_PROTO_WPA 1 +#define IEEE_PROTO_RSN 2 +//Added for notify the encryption type selection +// David, 2006.9.26 +#define IEEE_WPAX_USEGROUP 0 +#define IEEE_WPAX_WEP40 1 +#define IEEE_WPAX_TKIP 2 +#define IEEE_WPAX_WRAP 3 +#define IEEE_WPAX_CCMP 4 +#define IEEE_WPAX_WEP104 5 + +#define IEEE_KEY_MGMT_IEEE8021X 1 +#define IEEE_KEY_MGMT_PSK 2 + +#define IEEE_MLME_STA_DEAUTH 1 +#define IEEE_MLME_STA_DISASSOC 2 + + +#define IEEE_CRYPT_ERR_UNKNOWN_ALG 2 +#define IEEE_CRYPT_ERR_UNKNOWN_ADDR 3 +#define IEEE_CRYPT_ERR_CRYPT_INIT_FAILED 4 +#define IEEE_CRYPT_ERR_KEY_SET_FAILED 5 +#define IEEE_CRYPT_ERR_TX_KEY_SET_FAILED 6 +#define IEEE_CRYPT_ERR_CARD_CONF_FAILED 7 + + +#define IEEE_CRYPT_ALG_NAME_LEN 16 + +#define MAX_IE_LEN 0xff + +// added for kernel conflict +#define ieee80211_crypt_deinit_entries ieee80211_crypt_deinit_entries_rsl +#define ieee80211_crypt_deinit_handler ieee80211_crypt_deinit_handler_rsl +#define ieee80211_crypt_delayed_deinit ieee80211_crypt_delayed_deinit_rsl +#define ieee80211_register_crypto_ops ieee80211_register_crypto_ops_rsl +#define ieee80211_unregister_crypto_ops ieee80211_unregister_crypto_ops_rsl +#define ieee80211_get_crypto_ops ieee80211_get_crypto_ops_rsl + +#define ieee80211_ccmp_null ieee80211_ccmp_null_rsl + +#define ieee80211_tkip_null ieee80211_tkip_null_rsl + +#define ieee80211_wep_null ieee80211_wep_null_rsl + +#define free_ieee80211 free_ieee80211_rsl +#define alloc_ieee80211 alloc_ieee80211_rsl + +#define ieee80211_rx ieee80211_rx_rsl +#define ieee80211_rx_mgt ieee80211_rx_mgt_rsl + +#define ieee80211_get_beacon ieee80211_get_beacon_rsl +#define ieee80211_wake_queue ieee80211_wake_queue_rsl +#define ieee80211_stop_queue ieee80211_stop_queue_rsl +#define ieee80211_reset_queue ieee80211_reset_queue_rsl +#define ieee80211_softmac_stop_protocol ieee80211_softmac_stop_protocol_rsl +#define ieee80211_softmac_start_protocol ieee80211_softmac_start_protocol_rsl +#define ieee80211_is_shortslot ieee80211_is_shortslot_rsl +#define ieee80211_is_54g ieee80211_is_54g_rsl +#define ieee80211_wpa_supplicant_ioctl ieee80211_wpa_supplicant_ioctl_rsl +#define ieee80211_ps_tx_ack ieee80211_ps_tx_ack_rsl +#define ieee80211_softmac_xmit ieee80211_softmac_xmit_rsl +#define ieee80211_stop_send_beacons ieee80211_stop_send_beacons_rsl +#define notify_wx_assoc_event notify_wx_assoc_event_rsl +#define SendDisassociation SendDisassociation_rsl +#define ieee80211_disassociate ieee80211_disassociate_rsl +#define ieee80211_start_send_beacons ieee80211_start_send_beacons_rsl +#define ieee80211_stop_scan ieee80211_stop_scan_rsl +#define ieee80211_send_probe_requests ieee80211_send_probe_requests_rsl +#define ieee80211_softmac_scan_syncro ieee80211_softmac_scan_syncro_rsl +#define ieee80211_start_scan_syncro ieee80211_start_scan_syncro_rsl + +#define ieee80211_wx_get_essid ieee80211_wx_get_essid_rsl +#define ieee80211_wx_set_essid ieee80211_wx_set_essid_rsl +#define ieee80211_wx_set_rate ieee80211_wx_set_rate_rsl +#define ieee80211_wx_get_rate ieee80211_wx_get_rate_rsl +#define ieee80211_wx_set_wap ieee80211_wx_set_wap_rsl +#define ieee80211_wx_get_wap ieee80211_wx_get_wap_rsl +#define ieee80211_wx_set_mode ieee80211_wx_set_mode_rsl +#define ieee80211_wx_get_mode ieee80211_wx_get_mode_rsl +#define ieee80211_wx_set_scan ieee80211_wx_set_scan_rsl +#define ieee80211_wx_get_freq ieee80211_wx_get_freq_rsl +#define ieee80211_wx_set_freq ieee80211_wx_set_freq_rsl +#define ieee80211_wx_set_rawtx ieee80211_wx_set_rawtx_rsl +#define ieee80211_wx_get_name ieee80211_wx_get_name_rsl +#define ieee80211_wx_set_power ieee80211_wx_set_power_rsl +#define ieee80211_wx_get_power ieee80211_wx_get_power_rsl +#define ieee80211_wlan_frequencies ieee80211_wlan_frequencies_rsl +#define ieee80211_wx_set_rts ieee80211_wx_set_rts_rsl +#define ieee80211_wx_get_rts ieee80211_wx_get_rts_rsl + +#define ieee80211_txb_free ieee80211_txb_free_rsl + +#define ieee80211_wx_set_gen_ie ieee80211_wx_set_gen_ie_rsl +#define ieee80211_wx_get_scan ieee80211_wx_get_scan_rsl +#define ieee80211_wx_set_encode ieee80211_wx_set_encode_rsl +#define ieee80211_wx_get_encode ieee80211_wx_get_encode_rsl +#if WIRELESS_EXT >= 18 +#define ieee80211_wx_set_mlme ieee80211_wx_set_mlme_rsl +#define ieee80211_wx_set_auth ieee80211_wx_set_auth_rsl +#define ieee80211_wx_set_encode_ext ieee80211_wx_set_encode_ext_rsl +#define ieee80211_wx_get_encode_ext ieee80211_wx_get_encode_ext_rsl +#endif + + +typedef struct ieee_param { + u32 cmd; + u8 sta_addr[ETH_ALEN]; + union { + struct { + u8 name; + u32 value; + } wpa_param; + struct { + u32 len; + u8 reserved[32]; + u8 data[0]; + } wpa_ie; + struct{ + int command; + int reason_code; + } mlme; + struct { + u8 alg[IEEE_CRYPT_ALG_NAME_LEN]; + u8 set_tx; + u32 err; + u8 idx; + u8 seq[8]; /* sequence counter (set: RX, get: TX) */ + u16 key_len; + u8 key[0]; + } crypt; + } u; +}ieee_param; + + +#if WIRELESS_EXT < 17 +#define IW_QUAL_QUAL_INVALID 0x10 +#define IW_QUAL_LEVEL_INVALID 0x20 +#define IW_QUAL_NOISE_INVALID 0x40 +#define IW_QUAL_QUAL_UPDATED 0x1 +#define IW_QUAL_LEVEL_UPDATED 0x2 +#define IW_QUAL_NOISE_UPDATED 0x4 +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) +static inline void tq_init(struct tq_struct * task, void(*func)(void *), void *data) +{ + task->routine = func; + task->data = data; + //task->next = NULL; + INIT_LIST_HEAD(&task->list); + task->sync = 0; +} +#endif + +// linux under 2.6.9 release may not support it, so modify it for common use +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9)) +//#define MSECS(t) (1000 * ((t) / HZ) + 1000 * ((t) % HZ) / HZ) +#define MSECS(t) (HZ * ((t) / 1000) + (HZ * ((t) % 1000)) / 1000) +static inline unsigned long msleep_interruptible_rsl(unsigned int msecs) +{ + unsigned long timeout = MSECS(msecs) + 1; + + while (timeout) { + set_current_state(TASK_INTERRUPTIBLE); + timeout = schedule_timeout(timeout); + } + return timeout; +} +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,31)) +static inline void msleep(unsigned int msecs) +{ + unsigned long timeout = MSECS(msecs) + 1; + + while (timeout) { + set_current_state(TASK_UNINTERRUPTIBLE); + timeout = schedule_timeout(timeout); + } +} +#endif +#else +#define MSECS(t) msecs_to_jiffies(t) +#define msleep_interruptible_rsl msleep_interruptible +#endif + +#define IEEE80211_DATA_LEN 2304 +/* Maximum size for the MA-UNITDATA primitive, 802.11 standard section + 6.2.1.1.2. + + The figure in section 7.1.2 suggests a body size of up to 2312 + bytes is allowed, which is a bit confusing, I suspect this + represents the 2304 bytes of real data, plus a possible 8 bytes of + WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */ +#define IEEE80211_1ADDR_LEN 10 +#define IEEE80211_2ADDR_LEN 16 +#define IEEE80211_3ADDR_LEN 24 +#define IEEE80211_4ADDR_LEN 30 +#define IEEE80211_FCS_LEN 4 +#define IEEE80211_HLEN (IEEE80211_4ADDR_LEN) +#define IEEE80211_FRAME_LEN (IEEE80211_DATA_LEN + IEEE80211_HLEN) +#define IEEE80211_MGMT_HDR_LEN 24 +#define IEEE80211_DATA_HDR3_LEN 24 +#define IEEE80211_DATA_HDR4_LEN 30 + +#define MIN_FRAG_THRESHOLD 256U +#define MAX_FRAG_THRESHOLD 2346U + + +/* Frame control field constants */ +#define IEEE80211_FCTL_VERS 0x0003 +#define IEEE80211_FCTL_FTYPE 0x000c +#define IEEE80211_FCTL_STYPE 0x00f0 +#define IEEE80211_FCTL_FRAMETYPE 0x00fc +#define IEEE80211_FCTL_TODS 0x0100 +#define IEEE80211_FCTL_FROMDS 0x0200 +#define IEEE80211_FCTL_DSTODS 0x0300 //added by david +#define IEEE80211_FCTL_MOREFRAGS 0x0400 +#define IEEE80211_FCTL_RETRY 0x0800 +#define IEEE80211_FCTL_PM 0x1000 +#define IEEE80211_FCTL_MOREDATA 0x2000 +#define IEEE80211_FCTL_WEP 0x4000 +#define IEEE80211_FCTL_ORDER 0x8000 + +#define IEEE80211_FTYPE_MGMT 0x0000 +#define IEEE80211_FTYPE_CTL 0x0004 +#define IEEE80211_FTYPE_DATA 0x0008 + +/* management */ +#define IEEE80211_STYPE_ASSOC_REQ 0x0000 +#define IEEE80211_STYPE_ASSOC_RESP 0x0010 +#define IEEE80211_STYPE_REASSOC_REQ 0x0020 +#define IEEE80211_STYPE_REASSOC_RESP 0x0030 +#define IEEE80211_STYPE_PROBE_REQ 0x0040 +#define IEEE80211_STYPE_PROBE_RESP 0x0050 +#define IEEE80211_STYPE_BEACON 0x0080 +#define IEEE80211_STYPE_ATIM 0x0090 +#define IEEE80211_STYPE_DISASSOC 0x00A0 +#define IEEE80211_STYPE_AUTH 0x00B0 +#define IEEE80211_STYPE_DEAUTH 0x00C0 +#define IEEE80211_STYPE_MANAGE_ACT 0x00D0 + +/* control */ +#define IEEE80211_STYPE_PSPOLL 0x00A0 +#define IEEE80211_STYPE_RTS 0x00B0 +#define IEEE80211_STYPE_CTS 0x00C0 +#define IEEE80211_STYPE_ACK 0x00D0 +#define IEEE80211_STYPE_CFEND 0x00E0 +#define IEEE80211_STYPE_CFENDACK 0x00F0 +#define IEEE80211_STYPE_BLOCKACK 0x0094 + +/* data */ +#define IEEE80211_STYPE_DATA 0x0000 +#define IEEE80211_STYPE_DATA_CFACK 0x0010 +#define IEEE80211_STYPE_DATA_CFPOLL 0x0020 +#define IEEE80211_STYPE_DATA_CFACKPOLL 0x0030 +#define IEEE80211_STYPE_NULLFUNC 0x0040 +#define IEEE80211_STYPE_CFACK 0x0050 +#define IEEE80211_STYPE_CFPOLL 0x0060 +#define IEEE80211_STYPE_CFACKPOLL 0x0070 +#define IEEE80211_STYPE_QOS_DATA 0x0080 //added for WMM 2006/8/2 +#define IEEE80211_STYPE_QOS_NULL 0x00C0 + +#define IEEE80211_SCTL_FRAG 0x000F +#define IEEE80211_SCTL_SEQ 0xFFF0 + +/* QOS control */ +#define IEEE80211_QCTL_TID 0x000F + +#define FC_QOS_BIT BIT7 +#define IsDataFrame(pdu) ( ((pdu[0] & 0x0C)==0x08) ? true : false ) +#define IsLegacyDataFrame(pdu) (IsDataFrame(pdu) && (!(pdu[0]&FC_QOS_BIT)) ) +//added by wb. Is this right? +#define IsQoSDataFrame(pframe) ((*(u16*)pframe&(IEEE80211_STYPE_QOS_DATA|IEEE80211_FTYPE_DATA)) == (IEEE80211_STYPE_QOS_DATA|IEEE80211_FTYPE_DATA)) +#define Frame_Order(pframe) (*(u16*)pframe&IEEE80211_FCTL_ORDER) +#define SN_LESS(a, b) (((a-b)&0x800)!=0) +#define SN_EQUAL(a, b) (a == b) +#define MAX_DEV_ADDR_SIZE 8 +typedef enum _ACT_CATEGORY{ + ACT_CAT_QOS = 1, + ACT_CAT_DLS = 2, + ACT_CAT_BA = 3, + ACT_CAT_HT = 7, + ACT_CAT_WMM = 17, +} ACT_CATEGORY, *PACT_CATEGORY; + +typedef enum _TS_ACTION{ + ACT_ADDTSREQ = 0, + ACT_ADDTSRSP = 1, + ACT_DELTS = 2, + ACT_SCHEDULE = 3, +} TS_ACTION, *PTS_ACTION; + +typedef enum _BA_ACTION{ + ACT_ADDBAREQ = 0, + ACT_ADDBARSP = 1, + ACT_DELBA = 2, +} BA_ACTION, *PBA_ACTION; + +typedef enum _InitialGainOpType{ + IG_Backup=0, + IG_Restore, + IG_Max +}InitialGainOpType; +//added by amy for LED 090319 +//================================================================================ +// LED customization. +//================================================================================ +typedef enum _LED_CTL_MODE{ + LED_CTL_POWER_ON = 1, + LED_CTL_LINK = 2, + LED_CTL_NO_LINK = 3, + LED_CTL_TX = 4, + LED_CTL_RX = 5, + LED_CTL_SITE_SURVEY = 6, + LED_CTL_POWER_OFF = 7, + LED_CTL_START_TO_LINK = 8, + LED_CTL_START_WPS = 9, + LED_CTL_STOP_WPS = 10, + LED_CTL_START_WPS_BOTTON = 11, //added for runtop +}LED_CTL_MODE; + +/* debug macros */ +#define CONFIG_IEEE80211_DEBUG +#ifdef CONFIG_IEEE80211_DEBUG +extern u32 ieee80211_debug_level; +#define IEEE80211_DEBUG(level, fmt, args...) \ +do { if (ieee80211_debug_level & (level)) \ + printk(KERN_DEBUG "ieee80211: " fmt, ## args); } while (0) +//wb added to debug out data buf +//if you want print DATA buffer related BA, please set ieee80211_debug_level to DATA|BA +#define IEEE80211_DEBUG_DATA(level, data, datalen) \ + do{ if ((ieee80211_debug_level & (level)) == (level)) \ + { \ + int i; \ + u8* pdata = (u8*) data; \ + printk(KERN_DEBUG "ieee80211: %s()\n", __FUNCTION__); \ + for(i=0; i<(int)(datalen); i++) \ + { \ + printk("%2x ", pdata[i]); \ + if ((i+1)%16 == 0) printk("\n"); \ + } \ + printk("\n"); \ + } \ + } while (0) +#else +#define IEEE80211_DEBUG(level, fmt, args...) do {} while (0) +#define IEEE80211_DEBUG_DATA(level, data, datalen) do {} while(0) +#endif /* CONFIG_IEEE80211_DEBUG */ + +/* debug macros not dependent on CONFIG_IEEE80211_DEBUG */ + +#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x" +#define MAC_ARG(x) ((u8*)(x))[0],((u8*)(x))[1],((u8*)(x))[2],((u8*)(x))[3],((u8*)(x))[4],((u8*)(x))[5] + +/* + * To use the debug system; + * + * If you are defining a new debug classification, simply add it to the #define + * list here in the form of: + * + * #define IEEE80211_DL_xxxx VALUE + * + * shifting value to the left one bit from the previous entry. xxxx should be + * the name of the classification (for example, WEP) + * + * You then need to either add a IEEE80211_xxxx_DEBUG() macro definition for your + * classification, or use IEEE80211_DEBUG(IEEE80211_DL_xxxx, ...) whenever you want + * to send output to that classification. + * + * To add your debug level to the list of levels seen when you perform + * + * % cat /proc/net/ipw/debug_level + * + * you simply need to add your entry to the ipw_debug_levels array. + * + * If you do not see debug_level in /proc/net/ipw then you do not have + * CONFIG_IEEE80211_DEBUG defined in your kernel configuration + * + */ + +#define IEEE80211_DL_INFO (1<<0) +#define IEEE80211_DL_WX (1<<1) +#define IEEE80211_DL_SCAN (1<<2) +#define IEEE80211_DL_STATE (1<<3) +#define IEEE80211_DL_MGMT (1<<4) +#define IEEE80211_DL_FRAG (1<<5) +#define IEEE80211_DL_EAP (1<<6) +#define IEEE80211_DL_DROP (1<<7) + +#define IEEE80211_DL_TX (1<<8) +#define IEEE80211_DL_RX (1<<9) + +#define IEEE80211_DL_HT (1<<10) //HT +#define IEEE80211_DL_BA (1<<11) //ba +#define IEEE80211_DL_TS (1<<12) //TS +#define IEEE80211_DL_QOS (1<<13) +#define IEEE80211_DL_REORDER (1<<14) +#define IEEE80211_DL_IOT (1<<15) +#define IEEE80211_DL_IPS (1<<16) +#define IEEE80211_DL_TRACE (1<<29) //trace function, need to user net_ratelimit() together in order not to print too much to the screen +#define IEEE80211_DL_DATA (1<<30) //use this flag to control whether print data buf out. +#define IEEE80211_DL_ERR (1<<31) //always open +#define IEEE80211_ERROR(f, a...) printk(KERN_ERR "ieee80211: " f, ## a) +#define IEEE80211_WARNING(f, a...) printk(KERN_WARNING "ieee80211: " f, ## a) +#define IEEE80211_DEBUG_INFO(f, a...) IEEE80211_DEBUG(IEEE80211_DL_INFO, f, ## a) + +#define IEEE80211_DEBUG_WX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_WX, f, ## a) +#define IEEE80211_DEBUG_SCAN(f, a...) IEEE80211_DEBUG(IEEE80211_DL_SCAN, f, ## a) +#define IEEE80211_DEBUG_STATE(f, a...) IEEE80211_DEBUG(IEEE80211_DL_STATE, f, ## a) +#define IEEE80211_DEBUG_MGMT(f, a...) IEEE80211_DEBUG(IEEE80211_DL_MGMT, f, ## a) +#define IEEE80211_DEBUG_FRAG(f, a...) IEEE80211_DEBUG(IEEE80211_DL_FRAG, f, ## a) +#define IEEE80211_DEBUG_EAP(f, a...) IEEE80211_DEBUG(IEEE80211_DL_EAP, f, ## a) +#define IEEE80211_DEBUG_DROP(f, a...) IEEE80211_DEBUG(IEEE80211_DL_DROP, f, ## a) +#define IEEE80211_DEBUG_TX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_TX, f, ## a) +#define IEEE80211_DEBUG_RX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_RX, f, ## a) +#define IEEE80211_DEBUG_QOS(f, a...) IEEE80211_DEBUG(IEEE80211_DL_QOS, f, ## a) + +#ifdef CONFIG_IEEE80211_DEBUG +/* Added by Annie, 2005-11-22. */ +#define MAX_STR_LEN 64 +/* I want to see ASCII 33 to 126 only. Otherwise, I print '?'. Annie, 2005-11-22.*/ +#define PRINTABLE(_ch) (_ch>'!' && _ch<'~') +#define IEEE80211_PRINT_STR(_Comp, _TitleString, _Ptr, _Len) \ + if((_Comp) & level) \ + { \ + int __i; \ + u8 buffer[MAX_STR_LEN]; \ + int length = (_Len\n", _Len, buffer); \ + } +#else +#define IEEE80211_PRINT_STR(_Comp, _TitleString, _Ptr, _Len) do {} while (0) +#endif + +#include +#include /* ARPHRD_ETHER */ + +#ifndef WIRELESS_SPY +#define WIRELESS_SPY // enable iwspy support +#endif +#include // new driver API + +#ifndef ETH_P_PAE +#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */ +#endif /* ETH_P_PAE */ + +#define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */ + +#ifndef ETH_P_80211_RAW +#define ETH_P_80211_RAW (ETH_P_ECONET + 1) +#endif + +/* IEEE 802.11 defines */ + +#define P80211_OUI_LEN 3 + +struct ieee80211_snap_hdr { + + u8 dsap; /* always 0xAA */ + u8 ssap; /* always 0xAA */ + u8 ctrl; /* always 0x03 */ + u8 oui[P80211_OUI_LEN]; /* organizational universal id */ + +} __attribute__ ((packed)); + +#define SNAP_SIZE sizeof(struct ieee80211_snap_hdr) + +#define WLAN_FC_GET_VERS(fc) ((fc) & IEEE80211_FCTL_VERS) +#define WLAN_FC_GET_TYPE(fc) ((fc) & IEEE80211_FCTL_FTYPE) +#define WLAN_FC_GET_STYPE(fc) ((fc) & IEEE80211_FCTL_STYPE) + +#define WLAN_FC_GET_FRAMETYPE(fc) ((fc) & IEEE80211_FCTL_FRAMETYPE) +#define WLAN_GET_SEQ_FRAG(seq) ((seq) & IEEE80211_SCTL_FRAG) +#define WLAN_GET_SEQ_SEQ(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4) + +/* Authentication algorithms */ +#define WLAN_AUTH_OPEN 0 +#define WLAN_AUTH_SHARED_KEY 1 +#define WLAN_AUTH_LEAP 2 + +#define WLAN_AUTH_CHALLENGE_LEN 128 + +#define WLAN_CAPABILITY_BSS (1<<0) +#define WLAN_CAPABILITY_IBSS (1<<1) +#define WLAN_CAPABILITY_CF_POLLABLE (1<<2) +#define WLAN_CAPABILITY_CF_POLL_REQUEST (1<<3) +#define WLAN_CAPABILITY_PRIVACY (1<<4) +#define WLAN_CAPABILITY_SHORT_PREAMBLE (1<<5) +#define WLAN_CAPABILITY_PBCC (1<<6) +#define WLAN_CAPABILITY_CHANNEL_AGILITY (1<<7) +#define WLAN_CAPABILITY_SPECTRUM_MGMT (1<<8) +#define WLAN_CAPABILITY_QOS (1<<9) +#define WLAN_CAPABILITY_SHORT_SLOT (1<<10) +#define WLAN_CAPABILITY_DSSS_OFDM (1<<13) + +/* 802.11g ERP information element */ +#define WLAN_ERP_NON_ERP_PRESENT (1<<0) +#define WLAN_ERP_USE_PROTECTION (1<<1) +#define WLAN_ERP_BARKER_PREAMBLE (1<<2) + +/* Status codes */ +enum ieee80211_statuscode { + WLAN_STATUS_SUCCESS = 0, + WLAN_STATUS_UNSPECIFIED_FAILURE = 1, + WLAN_STATUS_CAPS_UNSUPPORTED = 10, + WLAN_STATUS_REASSOC_NO_ASSOC = 11, + WLAN_STATUS_ASSOC_DENIED_UNSPEC = 12, + WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG = 13, + WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION = 14, + WLAN_STATUS_CHALLENGE_FAIL = 15, + WLAN_STATUS_AUTH_TIMEOUT = 16, + WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA = 17, + WLAN_STATUS_ASSOC_DENIED_RATES = 18, + /* 802.11b */ + WLAN_STATUS_ASSOC_DENIED_NOSHORTPREAMBLE = 19, + WLAN_STATUS_ASSOC_DENIED_NOPBCC = 20, + WLAN_STATUS_ASSOC_DENIED_NOAGILITY = 21, + /* 802.11h */ + WLAN_STATUS_ASSOC_DENIED_NOSPECTRUM = 22, + WLAN_STATUS_ASSOC_REJECTED_BAD_POWER = 23, + WLAN_STATUS_ASSOC_REJECTED_BAD_SUPP_CHAN = 24, + /* 802.11g */ + WLAN_STATUS_ASSOC_DENIED_NOSHORTTIME = 25, + WLAN_STATUS_ASSOC_DENIED_NODSSSOFDM = 26, + /* 802.11i */ + WLAN_STATUS_INVALID_IE = 40, + WLAN_STATUS_INVALID_GROUP_CIPHER = 41, + WLAN_STATUS_INVALID_PAIRWISE_CIPHER = 42, + WLAN_STATUS_INVALID_AKMP = 43, + WLAN_STATUS_UNSUPP_RSN_VERSION = 44, + WLAN_STATUS_INVALID_RSN_IE_CAP = 45, + WLAN_STATUS_CIPHER_SUITE_REJECTED = 46, +}; + +/* Reason codes */ +enum ieee80211_reasoncode { + WLAN_REASON_UNSPECIFIED = 1, + WLAN_REASON_PREV_AUTH_NOT_VALID = 2, + WLAN_REASON_DEAUTH_LEAVING = 3, + WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY = 4, + WLAN_REASON_DISASSOC_AP_BUSY = 5, + WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA = 6, + WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA = 7, + WLAN_REASON_DISASSOC_STA_HAS_LEFT = 8, + WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH = 9, + /* 802.11h */ + WLAN_REASON_DISASSOC_BAD_POWER = 10, + WLAN_REASON_DISASSOC_BAD_SUPP_CHAN = 11, + /* 802.11i */ + WLAN_REASON_INVALID_IE = 13, + WLAN_REASON_MIC_FAILURE = 14, + WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT = 15, + WLAN_REASON_GROUP_KEY_HANDSHAKE_TIMEOUT = 16, + WLAN_REASON_IE_DIFFERENT = 17, + WLAN_REASON_INVALID_GROUP_CIPHER = 18, + WLAN_REASON_INVALID_PAIRWISE_CIPHER = 19, + WLAN_REASON_INVALID_AKMP = 20, + WLAN_REASON_UNSUPP_RSN_VERSION = 21, + WLAN_REASON_INVALID_RSN_IE_CAP = 22, + WLAN_REASON_IEEE8021X_FAILED = 23, + WLAN_REASON_CIPHER_SUITE_REJECTED = 24, +}; + +#define IEEE80211_STATMASK_SIGNAL (1<<0) +#define IEEE80211_STATMASK_RSSI (1<<1) +#define IEEE80211_STATMASK_NOISE (1<<2) +#define IEEE80211_STATMASK_RATE (1<<3) +#define IEEE80211_STATMASK_WEMASK 0x7 + +#define IEEE80211_CCK_MODULATION (1<<0) +#define IEEE80211_OFDM_MODULATION (1<<1) + +#define IEEE80211_24GHZ_BAND (1<<0) +#define IEEE80211_52GHZ_BAND (1<<1) + +#define IEEE80211_CCK_RATE_LEN 4 +#define IEEE80211_CCK_RATE_1MB 0x02 +#define IEEE80211_CCK_RATE_2MB 0x04 +#define IEEE80211_CCK_RATE_5MB 0x0B +#define IEEE80211_CCK_RATE_11MB 0x16 +#define IEEE80211_OFDM_RATE_LEN 8 +#define IEEE80211_OFDM_RATE_6MB 0x0C +#define IEEE80211_OFDM_RATE_9MB 0x12 +#define IEEE80211_OFDM_RATE_12MB 0x18 +#define IEEE80211_OFDM_RATE_18MB 0x24 +#define IEEE80211_OFDM_RATE_24MB 0x30 +#define IEEE80211_OFDM_RATE_36MB 0x48 +#define IEEE80211_OFDM_RATE_48MB 0x60 +#define IEEE80211_OFDM_RATE_54MB 0x6C +#define IEEE80211_BASIC_RATE_MASK 0x80 + +#define IEEE80211_CCK_RATE_1MB_MASK (1<<0) +#define IEEE80211_CCK_RATE_2MB_MASK (1<<1) +#define IEEE80211_CCK_RATE_5MB_MASK (1<<2) +#define IEEE80211_CCK_RATE_11MB_MASK (1<<3) +#define IEEE80211_OFDM_RATE_6MB_MASK (1<<4) +#define IEEE80211_OFDM_RATE_9MB_MASK (1<<5) +#define IEEE80211_OFDM_RATE_12MB_MASK (1<<6) +#define IEEE80211_OFDM_RATE_18MB_MASK (1<<7) +#define IEEE80211_OFDM_RATE_24MB_MASK (1<<8) +#define IEEE80211_OFDM_RATE_36MB_MASK (1<<9) +#define IEEE80211_OFDM_RATE_48MB_MASK (1<<10) +#define IEEE80211_OFDM_RATE_54MB_MASK (1<<11) + +#define IEEE80211_CCK_RATES_MASK 0x0000000F +#define IEEE80211_CCK_BASIC_RATES_MASK (IEEE80211_CCK_RATE_1MB_MASK | \ + IEEE80211_CCK_RATE_2MB_MASK) +#define IEEE80211_CCK_DEFAULT_RATES_MASK (IEEE80211_CCK_BASIC_RATES_MASK | \ + IEEE80211_CCK_RATE_5MB_MASK | \ + IEEE80211_CCK_RATE_11MB_MASK) + +#define IEEE80211_OFDM_RATES_MASK 0x00000FF0 +#define IEEE80211_OFDM_BASIC_RATES_MASK (IEEE80211_OFDM_RATE_6MB_MASK | \ + IEEE80211_OFDM_RATE_12MB_MASK | \ + IEEE80211_OFDM_RATE_24MB_MASK) +#define IEEE80211_OFDM_DEFAULT_RATES_MASK (IEEE80211_OFDM_BASIC_RATES_MASK | \ + IEEE80211_OFDM_RATE_9MB_MASK | \ + IEEE80211_OFDM_RATE_18MB_MASK | \ + IEEE80211_OFDM_RATE_36MB_MASK | \ + IEEE80211_OFDM_RATE_48MB_MASK | \ + IEEE80211_OFDM_RATE_54MB_MASK) +#define IEEE80211_DEFAULT_RATES_MASK (IEEE80211_OFDM_DEFAULT_RATES_MASK | \ + IEEE80211_CCK_DEFAULT_RATES_MASK) + +#define IEEE80211_NUM_OFDM_RATES 8 +#define IEEE80211_NUM_CCK_RATES 4 +#define IEEE80211_OFDM_SHIFT_MASK_A 4 + + +/* this is stolen and modified from the madwifi driver*/ +#define IEEE80211_FC0_TYPE_MASK 0x0c +#define IEEE80211_FC0_TYPE_DATA 0x08 +#define IEEE80211_FC0_SUBTYPE_MASK 0xB0 +#define IEEE80211_FC0_SUBTYPE_QOS 0x80 + +#define IEEE80211_QOS_HAS_SEQ(fc) \ + (((fc) & (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) == \ + (IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_QOS)) + +/* this is stolen from ipw2200 driver */ +#define IEEE_IBSS_MAC_HASH_SIZE 31 +struct ieee_ibss_seq { + u8 mac[ETH_ALEN]; + u16 seq_num[17]; + u16 frag_num[17]; + unsigned long packet_time[17]; + struct list_head list; +}; + +/* NOTE: This data is for statistical purposes; not all hardware provides this + * information for frames received. Not setting these will not cause + * any adverse affects. */ +struct ieee80211_rx_stats { +#if 1 + u32 mac_time[2]; + s8 rssi; + u8 signal; + u8 noise; + u16 rate; /* in 100 kbps */ + u8 received_channel; + u8 control; + u8 mask; + u8 freq; + u16 len; + u64 tsf; + u32 beacon_time; + u8 nic_type; + u16 Length; + // u8 DataRate; // In 0.5 Mbps + u8 SignalQuality; // in 0-100 index. + s32 RecvSignalPower; // Real power in dBm for this packet, no beautification and aggregation. + s8 RxPower; // in dBm Translate from PWdB + u8 SignalStrength; // in 0-100 index. + u16 bHwError:1; + u16 bCRC:1; + u16 bICV:1; + u16 bShortPreamble:1; + u16 Antenna:1; //for rtl8185 + u16 Decrypted:1; //for rtl8185, rtl8187 + u16 Wakeup:1; //for rtl8185 + u16 Reserved0:1; //for rtl8185 + u8 AGC; + u32 TimeStampLow; + u32 TimeStampHigh; + bool bShift; + bool bIsQosData; // Added by Annie, 2005-12-22. + u8 UserPriority; + + //1!!!!!!!!!!!!!!!!!!!!!!!!!!! + //1Attention Please!!!<11n or 8190 specific code should be put below this line> + //1!!!!!!!!!!!!!!!!!!!!!!!!!!! + + u8 RxDrvInfoSize; + u8 RxBufShift; + bool bIsAMPDU; + bool bFirstMPDU; + bool bContainHTC; + bool RxIs40MHzPacket; + u32 RxPWDBAll; + u8 RxMIMOSignalStrength[4]; // in 0~100 index + s8 RxMIMOSignalQuality[2]; + bool bPacketMatchBSSID; + bool bIsCCK; + bool bPacketToSelf; + //added by amy + u8* virtual_address; + u16 packetlength; // Total packet length: Must equal to sum of all FragLength + u16 fraglength; // FragLength should equal to PacketLength in non-fragment case + u16 fragoffset; // Data offset for this fragment + u16 ntotalfrag; + bool bisrxaggrsubframe; + bool bPacketBeacon; //cosa add for rssi + bool bToSelfBA; //cosa add for rssi + char cck_adc_pwdb[4]; //cosa add for rx path selection + u16 Seq_Num; + u8 nTotalAggPkt; // Number of aggregated packets. +#endif + +}; + +/* IEEE 802.11 requires that STA supports concurrent reception of at least + * three fragmented frames. This define can be increased to support more + * concurrent frames, but it should be noted that each entry can consume about + * 2 kB of RAM and increasing cache size will slow down frame reassembly. */ +#define IEEE80211_FRAG_CACHE_LEN 4 + +struct ieee80211_frag_entry { + unsigned long first_frag_time; + unsigned int seq; + unsigned int last_frag; + struct sk_buff *skb; + u8 src_addr[ETH_ALEN]; + u8 dst_addr[ETH_ALEN]; +}; + +struct ieee80211_stats { + unsigned int tx_unicast_frames; + unsigned int tx_multicast_frames; + unsigned int tx_fragments; + unsigned int tx_unicast_octets; + unsigned int tx_multicast_octets; + unsigned int tx_deferred_transmissions; + unsigned int tx_single_retry_frames; + unsigned int tx_multiple_retry_frames; + unsigned int tx_retry_limit_exceeded; + unsigned int tx_discards; + unsigned int rx_unicast_frames; + unsigned int rx_multicast_frames; + unsigned int rx_fragments; + unsigned int rx_unicast_octets; + unsigned int rx_multicast_octets; + unsigned int rx_fcs_errors; + unsigned int rx_discards_no_buffer; + unsigned int tx_discards_wrong_sa; + unsigned int rx_discards_undecryptable; + unsigned int rx_message_in_msg_fragments; + unsigned int rx_message_in_bad_msg_fragments; +}; + +struct ieee80211_device; + +#include "ieee80211_crypt.h" + +#define SEC_KEY_1 (1<<0) +#define SEC_KEY_2 (1<<1) +#define SEC_KEY_3 (1<<2) +#define SEC_KEY_4 (1<<3) +#define SEC_ACTIVE_KEY (1<<4) +#define SEC_AUTH_MODE (1<<5) +#define SEC_UNICAST_GROUP (1<<6) +#define SEC_LEVEL (1<<7) +#define SEC_ENABLED (1<<8) +#define SEC_ENCRYPT (1<<9) + +#define SEC_LEVEL_0 0 /* None */ +#define SEC_LEVEL_1 1 /* WEP 40 and 104 bit */ +#define SEC_LEVEL_2 2 /* Level 1 + TKIP */ +#define SEC_LEVEL_2_CKIP 3 /* Level 1 + CKIP */ +#define SEC_LEVEL_3 4 /* Level 2 + CCMP */ + +#define SEC_ALG_NONE 0 +#define SEC_ALG_WEP 1 +#define SEC_ALG_TKIP 2 +#define SEC_ALG_CCMP 3 + +#define WEP_KEYS 4 +#define WEP_KEY_LEN 13 +#define SCM_KEY_LEN 32 +#define SCM_TEMPORAL_KEY_LENGTH 16 + +struct ieee80211_security { + u16 active_key:2, + enabled:1, + auth_mode:2, + auth_algo:4, + unicast_uses_group:1, + encrypt:1; + u8 key_sizes[WEP_KEYS]; + u8 keys[WEP_KEYS][SCM_KEY_LEN]; + u8 level; + u16 flags; +} __attribute__ ((packed)); + + +/* + 802.11 data frame from AP + ,-------------------------------------------------------------------. +Bytes | 2 | 2 | 6 | 6 | 6 | 2 | 0..2312 | 4 | + |------|------|---------|---------|---------|------|---------|------| +Desc. | ctrl | dura | DA/RA | TA | SA | Sequ | frame | fcs | + | | tion | (BSSID) | | | ence | data | | + `-------------------------------------------------------------------' +Total: 28-2340 bytes +*/ + +/* Management Frame Information Element Types */ +enum ieee80211_mfie { + MFIE_TYPE_SSID = 0, + MFIE_TYPE_RATES = 1, + MFIE_TYPE_FH_SET = 2, + MFIE_TYPE_DS_SET = 3, + MFIE_TYPE_CF_SET = 4, + MFIE_TYPE_TIM = 5, + MFIE_TYPE_IBSS_SET = 6, + MFIE_TYPE_COUNTRY = 7, + MFIE_TYPE_HOP_PARAMS = 8, + MFIE_TYPE_HOP_TABLE = 9, + MFIE_TYPE_REQUEST = 10, + MFIE_TYPE_CHALLENGE = 16, + MFIE_TYPE_POWER_CONSTRAINT = 32, + MFIE_TYPE_POWER_CAPABILITY = 33, + MFIE_TYPE_TPC_REQUEST = 34, + MFIE_TYPE_TPC_REPORT = 35, + MFIE_TYPE_SUPP_CHANNELS = 36, + MFIE_TYPE_CSA = 37, + MFIE_TYPE_MEASURE_REQUEST = 38, + MFIE_TYPE_MEASURE_REPORT = 39, + MFIE_TYPE_QUIET = 40, + MFIE_TYPE_IBSS_DFS = 41, + MFIE_TYPE_ERP = 42, + MFIE_TYPE_RSN = 48, + MFIE_TYPE_RATES_EX = 50, + MFIE_TYPE_HT_CAP= 45, + MFIE_TYPE_HT_INFO= 61, + MFIE_TYPE_AIRONET=133, + MFIE_TYPE_GENERIC = 221, + MFIE_TYPE_QOS_PARAMETER = 222, +}; + +/* Minimal header; can be used for passing 802.11 frames with sufficient + * information to determine what type of underlying data type is actually + * stored in the data. */ +struct ieee80211_hdr { + __le16 frame_ctl; + __le16 duration_id; + u8 payload[0]; +} __attribute__ ((packed)); + +struct ieee80211_hdr_1addr { + __le16 frame_ctl; + __le16 duration_id; + u8 addr1[ETH_ALEN]; + u8 payload[0]; +} __attribute__ ((packed)); + +struct ieee80211_hdr_2addr { + __le16 frame_ctl; + __le16 duration_id; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 payload[0]; +} __attribute__ ((packed)); + +struct ieee80211_hdr_3addr { + __le16 frame_ctl; + __le16 duration_id; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 addr3[ETH_ALEN]; + __le16 seq_ctl; + u8 payload[0]; +} __attribute__ ((packed)); + +struct ieee80211_hdr_4addr { + __le16 frame_ctl; + __le16 duration_id; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 addr3[ETH_ALEN]; + __le16 seq_ctl; + u8 addr4[ETH_ALEN]; + u8 payload[0]; +} __attribute__ ((packed)); + +struct ieee80211_hdr_3addrqos { + __le16 frame_ctl; + __le16 duration_id; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 addr3[ETH_ALEN]; + __le16 seq_ctl; + u8 payload[0]; + __le16 qos_ctl; +} __attribute__ ((packed)); + +struct ieee80211_hdr_4addrqos { + __le16 frame_ctl; + __le16 duration_id; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 addr3[ETH_ALEN]; + __le16 seq_ctl; + u8 addr4[ETH_ALEN]; + u8 payload[0]; + __le16 qos_ctl; +} __attribute__ ((packed)); + +struct ieee80211_info_element { + u8 id; + u8 len; + u8 data[0]; +} __attribute__ ((packed)); + +struct ieee80211_authentication { + struct ieee80211_hdr_3addr header; + __le16 algorithm; + __le16 transaction; + __le16 status; + /*challenge*/ + struct ieee80211_info_element info_element[0]; +} __attribute__ ((packed)); + +struct ieee80211_disassoc { + struct ieee80211_hdr_3addr header; + __le16 reason; +} __attribute__ ((packed)); + +struct ieee80211_probe_request { + struct ieee80211_hdr_3addr header; + /* SSID, supported rates */ + struct ieee80211_info_element info_element[0]; +} __attribute__ ((packed)); + +struct ieee80211_probe_response { + struct ieee80211_hdr_3addr header; + u32 time_stamp[2]; + __le16 beacon_interval; + __le16 capability; + /* SSID, supported rates, FH params, DS params, + * CF params, IBSS params, TIM (if beacon), RSN */ + struct ieee80211_info_element info_element[0]; +} __attribute__ ((packed)); + +/* Alias beacon for probe_response */ +#define ieee80211_beacon ieee80211_probe_response + +struct ieee80211_assoc_request_frame { + struct ieee80211_hdr_3addr header; + __le16 capability; + __le16 listen_interval; + /* SSID, supported rates, RSN */ + struct ieee80211_info_element info_element[0]; +} __attribute__ ((packed)); + +struct ieee80211_reassoc_request_frame { + struct ieee80211_hdr_3addr header; + __le16 capability; + __le16 listen_interval; + u8 current_ap[ETH_ALEN]; + /* SSID, supported rates, RSN */ + struct ieee80211_info_element info_element[0]; +} __attribute__ ((packed)); + +struct ieee80211_assoc_response_frame { + struct ieee80211_hdr_3addr header; + __le16 capability; + __le16 status; + __le16 aid; + struct ieee80211_info_element info_element[0]; /* supported rates */ +} __attribute__ ((packed)); + +struct ieee80211_txb { + u8 nr_frags; + u8 encrypted; + u8 queue_index; + u8 rts_included; + u16 reserved; + __le16 frag_size; + __le16 payload_size; + struct sk_buff *fragments[0]; +}; + +#define MAX_TX_AGG_COUNT 16 +struct ieee80211_drv_agg_txb { + u8 nr_drv_agg_frames; + struct sk_buff *tx_agg_frames[MAX_TX_AGG_COUNT]; +}__attribute__((packed)); + +#define MAX_SUBFRAME_COUNT 64 +struct ieee80211_rxb { + u8 nr_subframes; + struct sk_buff *subframes[MAX_SUBFRAME_COUNT]; + u8 dst[ETH_ALEN]; + u8 src[ETH_ALEN]; +}__attribute__((packed)); + +typedef union _frameqos { + u16 shortdata; + u8 chardata[2]; + struct { + u16 tid:4; + u16 eosp:1; + u16 ack_policy:2; + u16 reserved:1; + u16 txop:8; + }field; +}frameqos,*pframeqos; + +/* SWEEP TABLE ENTRIES NUMBER*/ +#define MAX_SWEEP_TAB_ENTRIES 42 +#define MAX_SWEEP_TAB_ENTRIES_PER_PACKET 7 +/* MAX_RATES_LENGTH needs to be 12. The spec says 8, and many APs + * only use 8, and then use extended rates for the remaining supported + * rates. Other APs, however, stick all of their supported rates on the + * main rates information element... */ +#define MAX_RATES_LENGTH ((u8)12) +#define MAX_RATES_EX_LENGTH ((u8)16) +#define MAX_NETWORK_COUNT 128 + +#define MAX_CHANNEL_NUMBER 161 +#define IEEE80211_SOFTMAC_SCAN_TIME 100 +//(HZ / 2) +#define IEEE80211_SOFTMAC_ASSOC_RETRY_TIME (HZ * 2) + +#define CRC_LENGTH 4U + +#define MAX_WPA_IE_LEN 64 + +#define NETWORK_EMPTY_ESSID (1<<0) +#define NETWORK_HAS_OFDM (1<<1) +#define NETWORK_HAS_CCK (1<<2) + +/* QoS structure */ +#define NETWORK_HAS_QOS_PARAMETERS (1<<3) +#define NETWORK_HAS_QOS_INFORMATION (1<<4) +#define NETWORK_HAS_QOS_MASK (NETWORK_HAS_QOS_PARAMETERS | \ + NETWORK_HAS_QOS_INFORMATION) +/* 802.11h */ +#define NETWORK_HAS_POWER_CONSTRAINT (1<<5) +#define NETWORK_HAS_CSA (1<<6) +#define NETWORK_HAS_QUIET (1<<7) +#define NETWORK_HAS_IBSS_DFS (1<<8) +#define NETWORK_HAS_TPC_REPORT (1<<9) + +#define NETWORK_HAS_ERP_VALUE (1<<10) + +#define QOS_QUEUE_NUM 4 +#define QOS_OUI_LEN 3 +#define QOS_OUI_TYPE 2 +#define QOS_ELEMENT_ID 221 +#define QOS_OUI_INFO_SUB_TYPE 0 +#define QOS_OUI_PARAM_SUB_TYPE 1 +#define QOS_VERSION_1 1 +#define QOS_AIFSN_MIN_VALUE 2 +#if 1 +struct ieee80211_qos_information_element { + u8 elementID; + u8 length; + u8 qui[QOS_OUI_LEN]; + u8 qui_type; + u8 qui_subtype; + u8 version; + u8 ac_info; +} __attribute__ ((packed)); + +struct ieee80211_qos_ac_parameter { + u8 aci_aifsn; + u8 ecw_min_max; + __le16 tx_op_limit; +} __attribute__ ((packed)); + +struct ieee80211_qos_parameter_info { + struct ieee80211_qos_information_element info_element; + u8 reserved; + struct ieee80211_qos_ac_parameter ac_params_record[QOS_QUEUE_NUM]; +} __attribute__ ((packed)); + +struct ieee80211_qos_parameters { + __le16 cw_min[QOS_QUEUE_NUM]; + __le16 cw_max[QOS_QUEUE_NUM]; + u8 aifs[QOS_QUEUE_NUM]; + u8 flag[QOS_QUEUE_NUM]; + __le16 tx_op_limit[QOS_QUEUE_NUM]; +} __attribute__ ((packed)); + +struct ieee80211_qos_data { + struct ieee80211_qos_parameters parameters; + int active; + int supported; + u8 param_count; + u8 old_param_count; +}; + +struct ieee80211_tim_parameters { + u8 tim_count; + u8 tim_period; +} __attribute__ ((packed)); + +//#else +struct ieee80211_wmm_ac_param { + u8 ac_aci_acm_aifsn; + u8 ac_ecwmin_ecwmax; + u16 ac_txop_limit; +}; + +struct ieee80211_wmm_ts_info { + u8 ac_dir_tid; + u8 ac_up_psb; + u8 reserved; +} __attribute__ ((packed)); + +struct ieee80211_wmm_tspec_elem { + struct ieee80211_wmm_ts_info ts_info; + u16 norm_msdu_size; + u16 max_msdu_size; + u32 min_serv_inter; + u32 max_serv_inter; + u32 inact_inter; + u32 suspen_inter; + u32 serv_start_time; + u32 min_data_rate; + u32 mean_data_rate; + u32 peak_data_rate; + u32 max_burst_size; + u32 delay_bound; + u32 min_phy_rate; + u16 surp_band_allow; + u16 medium_time; +}__attribute__((packed)); +#endif +enum eap_type { + EAP_PACKET = 0, + EAPOL_START, + EAPOL_LOGOFF, + EAPOL_KEY, + EAPOL_ENCAP_ASF_ALERT +}; + +static const char *eap_types[] = { + [EAP_PACKET] = "EAP-Packet", + [EAPOL_START] = "EAPOL-Start", + [EAPOL_LOGOFF] = "EAPOL-Logoff", + [EAPOL_KEY] = "EAPOL-Key", + [EAPOL_ENCAP_ASF_ALERT] = "EAPOL-Encap-ASF-Alert" +}; + +static inline const char *eap_get_type(int type) +{ + return ((u32)type >= ARRAY_SIZE(eap_types)) ? "Unknown" : eap_types[type]; +} +//added by amy for reorder +static inline u8 Frame_QoSTID(u8* buf) +{ + struct ieee80211_hdr_3addr *hdr; + u16 fc; + hdr = (struct ieee80211_hdr_3addr *)buf; + fc = le16_to_cpu(hdr->frame_ctl); + return (u8)((frameqos*)(buf + (((fc & IEEE80211_FCTL_TODS)&&(fc & IEEE80211_FCTL_FROMDS))? 30 : 24)))->field.tid; +} + +//added by amy for reorder + +struct eapol { + u8 snap[6]; + u16 ethertype; + u8 version; + u8 type; + u16 length; +} __attribute__ ((packed)); + +struct ieee80211_softmac_stats{ + unsigned int rx_ass_ok; + unsigned int rx_ass_err; + unsigned int rx_probe_rq; + unsigned int tx_probe_rs; + unsigned int tx_beacons; + unsigned int rx_auth_rq; + unsigned int rx_auth_rs_ok; + unsigned int rx_auth_rs_err; + unsigned int tx_auth_rq; + unsigned int no_auth_rs; + unsigned int no_ass_rs; + unsigned int tx_ass_rq; + unsigned int rx_ass_rq; + unsigned int tx_probe_rq; + unsigned int reassoc; + unsigned int swtxstop; + unsigned int swtxawake; + unsigned char CurrentShowTxate; + unsigned char last_packet_rate; + unsigned int txretrycount; +}; + +#define BEACON_PROBE_SSID_ID_POSITION 12 + +struct ieee80211_info_element_hdr { + u8 id; + u8 len; +} __attribute__ ((packed)); + +/* + * These are the data types that can make up management packets + * + u16 auth_algorithm; + u16 auth_sequence; + u16 beacon_interval; + u16 capability; + u8 current_ap[ETH_ALEN]; + u16 listen_interval; + struct { + u16 association_id:14, reserved:2; + } __attribute__ ((packed)); + u32 time_stamp[2]; + u16 reason; + u16 status; +*/ + +#define IEEE80211_DEFAULT_TX_ESSID "Penguin" +#define IEEE80211_DEFAULT_BASIC_RATE 2 //1Mbps + +enum {WMM_all_frame, WMM_two_frame, WMM_four_frame, WMM_six_frame}; +#define MAX_SP_Len (WMM_all_frame << 4) +#define IEEE80211_QOS_TID 0x0f +#define QOS_CTL_NOTCONTAIN_ACK (0x01 << 5) + +#define IEEE80211_DTIM_MBCAST 4 +#define IEEE80211_DTIM_UCAST 2 +#define IEEE80211_DTIM_VALID 1 +#define IEEE80211_DTIM_INVALID 0 + +#define IEEE80211_PS_DISABLED 0 +#define IEEE80211_PS_UNICAST IEEE80211_DTIM_UCAST +#define IEEE80211_PS_MBCAST IEEE80211_DTIM_MBCAST + +//added by David for QoS 2006/6/30 +//#define WMM_Hang_8187 +#ifdef WMM_Hang_8187 +#undef WMM_Hang_8187 +#endif + +#define WME_AC_BK 0x00 +#define WME_AC_BE 0x01 +#define WME_AC_VI 0x02 +#define WME_AC_VO 0x03 +#define WME_ACI_MASK 0x03 +#define WME_AIFSN_MASK 0x03 +#define WME_AC_PRAM_LEN 16 + +#define MAX_RECEIVE_BUFFER_SIZE 9100 + +//UP Mapping to AC, using in MgntQuery_SequenceNumber() and maybe for DSCP +//#define UP2AC(up) ((up<3) ? ((up==0)?1:0) : (up>>1)) +#if 1 +#define UP2AC(up) ( \ + ((up) < 1) ? WME_AC_BE : \ + ((up) < 3) ? WME_AC_BK : \ + ((up) < 4) ? WME_AC_BE : \ + ((up) < 6) ? WME_AC_VI : \ + WME_AC_VO) +#endif +//AC Mapping to UP, using in Tx part for selecting the corresponding TX queue +#define AC2UP(_ac) ( \ + ((_ac) == WME_AC_VO) ? 6 : \ + ((_ac) == WME_AC_VI) ? 5 : \ + ((_ac) == WME_AC_BK) ? 1 : \ + 0) + +#define ETHER_ADDR_LEN 6 /* length of an Ethernet address */ +#define ETHERNET_HEADER_SIZE 14 /* length of two Ethernet address plus ether type*/ + +struct ether_header { + u8 ether_dhost[ETHER_ADDR_LEN]; + u8 ether_shost[ETHER_ADDR_LEN]; + u16 ether_type; +} __attribute__((packed)); + +#ifndef ETHERTYPE_PAE +#define ETHERTYPE_PAE 0x888e /* EAPOL PAE/802.1x */ +#endif +#ifndef ETHERTYPE_IP +#define ETHERTYPE_IP 0x0800 /* IP protocol */ +#endif + +typedef struct _bss_ht{ + + bool support_ht; + + // HT related elements + u8 ht_cap_buf[32]; + u16 ht_cap_len; + u8 ht_info_buf[32]; + u16 ht_info_len; + + HT_SPEC_VER ht_spec_ver; + //HT_CAPABILITY_ELE bdHTCapEle; + //HT_INFORMATION_ELE bdHTInfoEle; + + bool aggregation; + bool long_slot_time; +}bss_ht, *pbss_ht; + +typedef enum _erp_t{ + ERP_NonERPpresent = 0x01, + ERP_UseProtection = 0x02, + ERP_BarkerPreambleMode = 0x04, +} erp_t; + + +struct ieee80211_network { + /* These entries are used to identify a unique network */ + u8 bssid[ETH_ALEN]; + u8 channel; + /* Ensure null-terminated for any debug msgs */ + u8 ssid[IW_ESSID_MAX_SIZE + 1]; + u8 ssid_len; +#if 1 + struct ieee80211_qos_data qos_data; +#else + // Qos related. Added by Annie, 2005-11-01. + BSS_QOS BssQos; +#endif + + //added by amy for LEAP + bool bWithAironetIE; + bool bCkipSupported; + bool bCcxRmEnable; + u16 CcxRmState[2]; + // CCXv4 S59, MBSSID. + bool bMBssidValid; + u8 MBssidMask; + u8 MBssid[6]; + // CCX 2 S38, WLAN Device Version Number element. Annie, 2006-08-20. + bool bWithCcxVerNum; + u8 BssCcxVerNumber; + /* These are network statistics */ + struct ieee80211_rx_stats stats; + u16 capability; + u8 rates[MAX_RATES_LENGTH]; + u8 rates_len; + u8 rates_ex[MAX_RATES_EX_LENGTH]; + u8 rates_ex_len; + unsigned long last_scanned; + u8 mode; + u32 flags; + u32 last_associate; + u32 time_stamp[2]; + u16 beacon_interval; + u16 listen_interval; + u16 atim_window; + u8 erp_value; + u8 wpa_ie[MAX_WPA_IE_LEN]; + size_t wpa_ie_len; + u8 rsn_ie[MAX_WPA_IE_LEN]; + size_t rsn_ie_len; + + struct ieee80211_tim_parameters tim; + u8 dtim_period; + u8 dtim_data; + u32 last_dtim_sta_time[2]; + + //appeded for QoS + u8 wmm_info; + struct ieee80211_wmm_ac_param wmm_param[4]; + u8 QoS_Enable; +#ifdef THOMAS_TURBO + u8 Turbo_Enable;//enable turbo mode, added by thomas +#endif +#ifdef ENABLE_DOT11D + u16 CountryIeLen; + u8 CountryIeBuf[MAX_IE_LEN]; +#endif + // HT Related, by amy, 2008.04.29 + BSS_HT bssht; + // Add to handle broadcom AP management frame CCK rate. + bool broadcom_cap_exist; + bool realtek_cap_exit; + bool marvell_cap_exist; + bool ralink_cap_exist; + bool atheros_cap_exist; + bool cisco_cap_exist; + bool unknown_cap_exist; +// u8 berp_info; + bool berp_info_valid; + bool buseprotection; + //put at the end of the structure. + struct list_head list; +}; + +#if 1 +enum ieee80211_state { + + /* the card is not linked at all */ + IEEE80211_NOLINK = 0, + + /* IEEE80211_ASSOCIATING* are for BSS client mode + * the driver shall not perform RX filtering unless + * the state is LINKED. + * The driver shall just check for the state LINKED and + * defaults to NOLINK for ALL the other states (including + * LINKED_SCANNING) + */ + + /* the association procedure will start (wq scheduling)*/ + IEEE80211_ASSOCIATING, + IEEE80211_ASSOCIATING_RETRY, + + /* the association procedure is sending AUTH request*/ + IEEE80211_ASSOCIATING_AUTHENTICATING, + + /* the association procedure has successfully authentcated + * and is sending association request + */ + IEEE80211_ASSOCIATING_AUTHENTICATED, + + /* the link is ok. the card associated to a BSS or linked + * to a ibss cell or acting as an AP and creating the bss + */ + IEEE80211_LINKED, + + /* same as LINKED, but the driver shall apply RX filter + * rules as we are in NO_LINK mode. As the card is still + * logically linked, but it is doing a syncro site survey + * then it will be back to LINKED state. + */ + IEEE80211_LINKED_SCANNING, + +}; +#else +enum ieee80211_state { + IEEE80211_UNINITIALIZED = 0, + IEEE80211_INITIALIZED, + IEEE80211_ASSOCIATING, + IEEE80211_ASSOCIATED, + IEEE80211_AUTHENTICATING, + IEEE80211_AUTHENTICATED, + IEEE80211_SHUTDOWN +}; +#endif + +#define DEFAULT_MAX_SCAN_AGE (15 * HZ) +#define DEFAULT_FTS 2346 + +#define CFG_IEEE80211_RESERVE_FCS (1<<0) +#define CFG_IEEE80211_COMPUTE_FCS (1<<1) +#define CFG_IEEE80211_RTS (1<<2) + +#define IEEE80211_24GHZ_MIN_CHANNEL 1 +#define IEEE80211_24GHZ_MAX_CHANNEL 14 +#define IEEE80211_24GHZ_CHANNELS (IEEE80211_24GHZ_MAX_CHANNEL - \ + IEEE80211_24GHZ_MIN_CHANNEL + 1) + +#define IEEE80211_52GHZ_MIN_CHANNEL 34 +#define IEEE80211_52GHZ_MAX_CHANNEL 165 +#define IEEE80211_52GHZ_CHANNELS (IEEE80211_52GHZ_MAX_CHANNEL - \ + IEEE80211_52GHZ_MIN_CHANNEL + 1) + +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,11)) +extern inline int is_multicast_ether_addr(const u8 *addr) +{ + return ((addr[0] != 0xff) && (0x01 & addr[0])); +} +#endif + +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13)) +extern inline int is_broadcast_ether_addr(const u8 *addr) +{ + return ((addr[0] == 0xff) && (addr[1] == 0xff) && (addr[2] == 0xff) && \ + (addr[3] == 0xff) && (addr[4] == 0xff) && (addr[5] == 0xff)); +} +#endif + +typedef struct tx_pending_t{ + int frag; + struct ieee80211_txb *txb; +}tx_pending_t; + +typedef struct _bandwidth_autoswitch +{ + long threshold_20Mhzto40Mhz; + long threshold_40Mhzto20Mhz; + bool bforced_tx20Mhz; + bool bautoswitch_enable; +}bandwidth_autoswitch,*pbandwidth_autoswitch; + + +//added by amy for order + +#define REORDER_WIN_SIZE 128 +#define REORDER_ENTRY_NUM 128 +typedef struct _RX_REORDER_ENTRY +{ + struct list_head List; + u16 SeqNum; + struct ieee80211_rxb* prxb; +} RX_REORDER_ENTRY, *PRX_REORDER_ENTRY; +//added by amy for order +typedef enum _Fsync_State{ + Default_Fsync, + HW_Fsync, + SW_Fsync +}Fsync_State; + +// Power save mode configured. +typedef enum _RT_PS_MODE +{ + eActive, // Active/Continuous access. + eMaxPs, // Max power save mode. + eFastPs // Fast power save mode. +}RT_PS_MODE; + +typedef enum _IPS_CALLBACK_FUNCION +{ + IPS_CALLBACK_NONE = 0, + IPS_CALLBACK_MGNT_LINK_REQUEST = 1, + IPS_CALLBACK_JOIN_REQUEST = 2, +}IPS_CALLBACK_FUNCION; + +typedef enum _RT_JOIN_ACTION{ + RT_JOIN_INFRA = 1, + RT_JOIN_IBSS = 2, + RT_START_IBSS = 3, + RT_NO_ACTION = 4, +}RT_JOIN_ACTION; + +typedef struct _IbssParms{ + u16 atimWin; +}IbssParms, *PIbssParms; +#define MAX_NUM_RATES 264 // Max num of support rates element: 8, Max num of ext. support rate: 255. 061122, by rcnjko. + +// RF state. +typedef enum _RT_RF_POWER_STATE +{ + eRfOn, + eRfSleep, + eRfOff +}RT_RF_POWER_STATE; + +typedef struct _RT_POWER_SAVE_CONTROL +{ + + // + // Inactive Power Save(IPS) : Disable RF when disconnected + // + bool bInactivePs; + bool bIPSModeBackup; + bool bHaltAdapterClkRQ; + bool bSwRfProcessing; + RT_RF_POWER_STATE eInactivePowerState; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + struct work_struct InactivePsWorkItem; +#else + struct tq_struct InactivePsWorkItem; +#endif + struct timer_list InactivePsTimer; + + // Return point for join action + IPS_CALLBACK_FUNCION ReturnPoint; + + // Recored Parameters for rescheduled JoinRequest + bool bTmpBssDesc; + RT_JOIN_ACTION tmpJoinAction; + struct ieee80211_network tmpBssDesc; + + // Recored Parameters for rescheduled MgntLinkRequest + bool bTmpScanOnly; + bool bTmpActiveScan; + bool bTmpFilterHiddenAP; + bool bTmpUpdateParms; + u8 tmpSsidBuf[33]; + OCTET_STRING tmpSsid2Scan; + bool bTmpSsid2Scan; + u8 tmpNetworkType; + u8 tmpChannelNumber; + u16 tmpBcnPeriod; + u8 tmpDtimPeriod; + u16 tmpmCap; + OCTET_STRING tmpSuppRateSet; + u8 tmpSuppRateBuf[MAX_NUM_RATES]; + bool bTmpSuppRate; + IbssParms tmpIbpm; + bool bTmpIbpm; + + // + // Leisre Poswer Save : Disable RF if connected but traffic is not busy + // + bool bLeisurePs; + u32 PowerProfile; + u8 LpsIdleCount; + u8 RegMaxLPSAwakeIntvl; + u8 LPSAwakeIntvl; + + //RF OFF Level + u32 CurPsLevel; + u32 RegRfPsLevel; + + //Fw Control LPS + bool bFwCtrlLPS; + u8 FWCtrlPSMode; + + //2009.01.01 added by tynli + // Record if there is a link request in IPS RF off progress. + bool LinkReqInIPSRFOffPgs; + // To make sure that connect info should be executed, so we set the bit to filter the link info which comes after the connect info. + bool BufConnectinfoBefore; + +}RT_POWER_SAVE_CONTROL,*PRT_POWER_SAVE_CONTROL; + +typedef u32 RT_RF_CHANGE_SOURCE; +#define RF_CHANGE_BY_SW BIT31 +#define RF_CHANGE_BY_HW BIT30 +#define RF_CHANGE_BY_PS BIT29 +#define RF_CHANGE_BY_IPS BIT28 +#define RF_CHANGE_BY_INIT 0 // Do not change the RFOff reason. Defined by Bruce, 2008-01-17. + +#ifdef ENABLE_DOT11D +typedef enum +{ + COUNTRY_CODE_FCC = 0, + COUNTRY_CODE_IC = 1, + COUNTRY_CODE_ETSI = 2, + COUNTRY_CODE_SPAIN = 3, + COUNTRY_CODE_FRANCE = 4, + COUNTRY_CODE_MKK = 5, + COUNTRY_CODE_MKK1 = 6, + COUNTRY_CODE_ISRAEL = 7, + COUNTRY_CODE_TELEC, + COUNTRY_CODE_MIC, + COUNTRY_CODE_GLOBAL_DOMAIN +}country_code_type_t; +#endif + // Firmware realted CMD IO. +typedef enum _FW_CMD_IO_TYPE{ + FW_CMD_DIG_ENABLE = 0, // For DIG DM + FW_CMD_DIG_DISABLE = 1, + FW_CMD_DIG_HALT = 2, + FW_CMD_DIG_RESUME = 3, + FW_CMD_HIGH_PWR_ENABLE = 4, // For High Power DM + FW_CMD_HIGH_PWR_DISABLE = 5, + FW_CMD_RA_RESET = 6, // For Rate adaptive DM + FW_CMD_RA_ACTIVE= 7, + FW_CMD_RA_REFRESH_N= 8, + FW_CMD_RA_REFRESH_BG= 9, + FW_CMD_IQK_ENABLE = 10, // For FW supported IQK + FW_CMD_TXPWR_TRACK_ENABLE = 11, // Tx power tracking switch + FW_CMD_TXPWR_TRACK_DISABLE = 12, // Tx power tracking switch + FW_CMD_PAUSE_DM_BY_SCAN = 13, + FW_CMD_RESUME_DM_BY_SCAN = 14, + FW_CMD_MID_HIGH_PWR_ENABLE = 15, + FW_CMD_LPS_ENTER = 16, // Indifate firmware that driver enters LPS, For PS-Poll hardware bug + FW_CMD_LPS_LEAVE = 17, // Indicate firmware that driver leave LPS, 2009/1/4, by Emily +}FW_CMD_IO_TYPE,*PFW_CMD_IO_TYPE; +#define RT_MAX_LD_SLOT_NUM 10 +typedef struct _RT_LINK_DETECT_T{ + + u32 NumRecvBcnInPeriod; + u32 NumRecvDataInPeriod; + + u32 RxBcnNum[RT_MAX_LD_SLOT_NUM]; // number of Rx beacon / CheckForHang_period to determine link status + u32 RxDataNum[RT_MAX_LD_SLOT_NUM]; // number of Rx data / CheckForHang_period to determine link status + u16 SlotNum; // number of CheckForHang period to determine link status + u16 SlotIndex; + + u32 NumTxOkInPeriod; + u32 NumRxOkInPeriod; + bool bBusyTraffic; +}RT_LINK_DETECT_T, *PRT_LINK_DETECT_T; + + +struct ieee80211_device { + struct net_device *dev; + struct ieee80211_security sec; + + //hw security related +// u8 hwsec_support; //support? + u8 hwsec_active; //hw security active. + bool is_silent_reset; + bool is_roaming; + bool ieee_up; + //added by amy + bool bSupportRemoteWakeUp; + RT_PS_MODE dot11PowerSaveMode; // Power save mode configured. + bool actscanning; + //added by amy 090313 + bool be_scan_inprogress; + bool beinretry; + RT_RF_POWER_STATE eRFPowerState; + RT_RF_CHANGE_SOURCE RfOffReason; + bool is_set_key; + //11n spec related I wonder if These info structure need to be moved out of ieee80211_device + + //11n HT below + PRT_HIGH_THROUGHPUT pHTInfo; + //struct timer_list SwBwTimer; +// spinlock_t chnlop_spinlock; + spinlock_t bw_spinlock; + + spinlock_t reorder_spinlock; + // for HT operation rate set. we use this one for HT data rate to seperate different descriptors + //the way fill this is the same as in the IE + u8 Regdot11HTOperationalRateSet[16]; //use RATR format + u8 dot11HTOperationalRateSet[16]; //use RATR format + u8 RegHTSuppRateSet[16]; + u8 HTCurrentOperaRate; + u8 HTHighestOperaRate; + //wb added for rate operation mode to firmware + u8 bTxDisableRateFallBack; + u8 bTxUseDriverAssingedRate; + atomic_t atm_chnlop; + atomic_t atm_swbw; +// u8 HTHighestOperaRate; +// u8 HTCurrentOperaRate; + + // 802.11e and WMM Traffic Stream Info (TX) + struct list_head Tx_TS_Admit_List; + struct list_head Tx_TS_Pending_List; + struct list_head Tx_TS_Unused_List; + TX_TS_RECORD TxTsRecord[TOTAL_TS_NUM]; + // 802.11e and WMM Traffic Stream Info (RX) + struct list_head Rx_TS_Admit_List; + struct list_head Rx_TS_Pending_List; + struct list_head Rx_TS_Unused_List; + RX_TS_RECORD RxTsRecord[TOTAL_TS_NUM]; +//#ifdef TO_DO_LIST + RX_REORDER_ENTRY RxReorderEntry[128]; + struct list_head RxReorder_Unused_List; +//#endif + // Qos related. Added by Annie, 2005-11-01. +// PSTA_QOS pStaQos; + u8 ForcedPriority; // Force per-packet priority 1~7. (default: 0, not to force it.) + + + /* Bookkeeping structures */ + struct net_device_stats stats; + struct ieee80211_stats ieee_stats; + struct ieee80211_softmac_stats softmac_stats; + + /* Probe / Beacon management */ + struct list_head network_free_list; + struct list_head network_list; + struct ieee80211_network *networks; + int scans; + int scan_age; + + int iw_mode; /* operating mode (IW_MODE_*) */ + struct iw_spy_data spy_data; + + spinlock_t lock; + spinlock_t wpax_suitlist_lock; + + int tx_headroom; /* Set to size of any additional room needed at front + * of allocated Tx SKBs */ + u32 config; + + /* WEP and other encryption related settings at the device level */ + int open_wep; /* Set to 1 to allow unencrypted frames */ + int auth_mode; + int reset_on_keychange; /* Set to 1 if the HW needs to be reset on + * WEP key changes */ + + /* If the host performs {en,de}cryption, then set to 1 */ + int host_encrypt; + int host_encrypt_msdu; + int host_decrypt; + /* host performs multicast decryption */ + int host_mc_decrypt; + + /* host should strip IV and ICV from protected frames */ + /* meaningful only when hardware decryption is being used */ + int host_strip_iv_icv; + + int host_open_frag; + int host_build_iv; + int ieee802_1x; /* is IEEE 802.1X used */ + + /* WPA data */ + bool bHalfWirelessN24GMode; + int wpa_enabled; + int drop_unencrypted; + int tkip_countermeasures; + int privacy_invoked; + size_t wpa_ie_len; + u8 *wpa_ie; + u8 ap_mac_addr[6]; + u16 pairwise_key_type; + u16 group_key_type; + struct list_head crypt_deinit_list; + struct ieee80211_crypt_data *crypt[WEP_KEYS]; + int tx_keyidx; /* default TX key index (crypt[tx_keyidx]) */ + struct timer_list crypt_deinit_timer; + int crypt_quiesced; + + int bcrx_sta_key; /* use individual keys to override default keys even + * with RX of broad/multicast frames */ + + /* Fragmentation structures */ + // each streaming contain a entry + struct ieee80211_frag_entry frag_cache[17][IEEE80211_FRAG_CACHE_LEN]; + unsigned int frag_next_idx[17]; + u16 fts; /* Fragmentation Threshold */ +#define DEFAULT_RTS_THRESHOLD 2346U +#define MIN_RTS_THRESHOLD 1 +#define MAX_RTS_THRESHOLD 2346U + u16 rts; /* RTS threshold */ + + /* Association info */ + u8 bssid[ETH_ALEN]; + + /* This stores infos for the current network. + * Either the network we are associated in INFRASTRUCTURE + * or the network that we are creating in MASTER mode. + * ad-hoc is a mixture ;-). + * Note that in infrastructure mode, even when not associated, + * fields bssid and essid may be valid (if wpa_set and essid_set + * are true) as thy carry the value set by the user via iwconfig + */ + struct ieee80211_network current_network; + + enum ieee80211_state state; + + int short_slot; + int reg_mode; + int mode; /* A, B, G */ + int modulation; /* CCK, OFDM */ + int freq_band; /* 2.4Ghz, 5.2Ghz, Mixed */ + int abg_true; /* ABG flag */ + + /* used for forcing the ibss workqueue to terminate + * without wait for the syncro scan to terminate + */ + short sync_scan_hurryup; + u16 scan_watch_dog; + int perfect_rssi; + int worst_rssi; + + u16 prev_seq_ctl; /* used to drop duplicate frames */ + + /* map of allowed channels. 0 is dummy */ + // FIXME: remeber to default to a basic channel plan depending of the PHY type +#ifdef ENABLE_DOT11D + void* pDot11dInfo; + bool bGlobalDomain; +#else + int channel_map[MAX_CHANNEL_NUMBER+1]; +#endif + int rate; /* current rate */ + int basic_rate; + //FIXME: pleace callback, see if redundant with softmac_features + short active_scan; + + /* this contains flags for selectively enable softmac support */ + u16 softmac_features; + + /* if the sequence control field is not filled by HW */ + u16 seq_ctrl[5]; + + /* association procedure transaction sequence number */ + u16 associate_seq; + + /* AID for RTXed association responses */ + u16 assoc_id; + + /* power save mode related*/ + u8 ack_tx_to_ieee; + short ps; + short sta_sleep; + int ps_timeout; + int ps_period; + struct tasklet_struct ps_task; + u32 ps_th; + u32 ps_tl; + + short raw_tx; + /* used if IEEE_SOFTMAC_TX_QUEUE is set */ + short queue_stop; + short scanning; + short proto_started; + + struct semaphore wx_sem; + struct semaphore scan_sem; + + spinlock_t mgmt_tx_lock; + spinlock_t beacon_lock; + + short beacon_txing; + + short wap_set; + short ssid_set; + + u8 wpax_type_set; //{added by David, 2006.9.28} + u32 wpax_type_notify; //{added by David, 2006.9.26} + + /* QoS related flag */ + char init_wmmparam_flag; + /* set on initialization */ + u8 qos_support; + + /* for discarding duplicated packets in IBSS */ + struct list_head ibss_mac_hash[IEEE_IBSS_MAC_HASH_SIZE]; + + /* for discarding duplicated packets in BSS */ + u16 last_rxseq_num[17]; /* rx seq previous per-tid */ + u16 last_rxfrag_num[17];/* tx frag previous per-tid */ + unsigned long last_packet_time[17]; + + /* for PS mode */ + unsigned long last_rx_ps_time; + + /* used if IEEE_SOFTMAC_SINGLE_QUEUE is set */ + struct sk_buff *mgmt_queue_ring[MGMT_QUEUE_NUM]; + int mgmt_queue_head; + int mgmt_queue_tail; +//{ added for rtl819x +#define IEEE80211_QUEUE_LIMIT 128 + u8 AsocRetryCount; + unsigned int hw_header; + struct sk_buff_head skb_waitQ[MAX_QUEUE_SIZE]; + struct sk_buff_head skb_aggQ[MAX_QUEUE_SIZE]; + struct sk_buff_head skb_drv_aggQ[MAX_QUEUE_SIZE]; + u32 sta_edca_param[4]; + bool aggregation; + // Enable/Disable Rx immediate BA capability. + bool enable_rx_imm_BA; + bool bibsscoordinator; + + //+by amy for DM ,080515 + //Dynamic Tx power for near/far range enable/Disable , by amy , 2008-05-15 + bool bdynamic_txpower_enable; + + bool bCTSToSelfEnable; + u8 CTSToSelfTH; + + u32 fsync_time_interval; + u32 fsync_rate_bitmap; + u8 fsync_rssi_threshold; + bool bfsync_enable; + + u8 fsync_multiple_timeinterval; // FsyncMultipleTimeInterval * FsyncTimeInterval + u32 fsync_firstdiff_ratethreshold; // low threshold + u32 fsync_seconddiff_ratethreshold; // decrease threshold + Fsync_State fsync_state; + bool bis_any_nonbepkts; + //20Mhz 40Mhz AutoSwitch Threshold + bandwidth_autoswitch bandwidth_auto_switch; + //for txpower tracking + bool FwRWRF; + + //added by amy for AP roaming + RT_LINK_DETECT_T LinkDetectInfo; + //added by amy for ps + RT_POWER_SAVE_CONTROL PowerSaveControl; +//} + /* used if IEEE_SOFTMAC_TX_QUEUE is set */ + struct tx_pending_t tx_pending; + + /* used if IEEE_SOFTMAC_ASSOCIATE is set */ + struct timer_list associate_timer; + + /* used if IEEE_SOFTMAC_BEACONS is set */ + struct timer_list beacon_timer; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + struct work_struct associate_complete_wq; + struct work_struct associate_procedure_wq; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + struct delayed_work softmac_scan_wq; + struct delayed_work associate_retry_wq; + struct delayed_work start_ibss_wq; + struct delayed_work hw_wakeup_wq; + struct delayed_work hw_sleep_wq; + struct delayed_work link_change_wq; +#else + struct work_struct softmac_scan_wq; + struct work_struct associate_retry_wq; + struct work_struct start_ibss_wq; + struct work_struct hw_wakeup_wq; + struct work_struct hw_sleep_wq; + struct work_struct link_change_wq; +#endif + struct work_struct wx_sync_scan_wq; + struct workqueue_struct *wq; +#else + /* used for periodly scan */ + struct timer_list scan_timer; + + struct tq_struct associate_complete_wq; + struct tq_struct associate_retry_wq; + struct tq_struct start_ibss_wq; + struct tq_struct associate_procedure_wq; + struct tq_struct softmac_scan_wq; + struct tq_struct wx_sync_scan_wq; + struct tq_struct hw_wakeup_wq; + struct tq_struct hw_sleep_wq; + struct tq_struct link_change_wq; + +#endif + // Qos related. Added by Annie, 2005-11-01. + //STA_QOS StaQos; + + //u32 STA_EDCA_PARAM[4]; + //CHANNEL_ACCESS_SETTING ChannelAccessSetting; + + + /* Callback functions */ + void (*set_security)(struct net_device *dev, + struct ieee80211_security *sec); + + /* Used to TX data frame by using txb structs. + * this is not used if in the softmac_features + * is set the flag IEEE_SOFTMAC_TX_QUEUE + */ + int (*hard_start_xmit)(struct ieee80211_txb *txb, + struct net_device *dev); + + int (*reset_port)(struct net_device *dev); + int (*is_queue_full) (struct net_device * dev, int pri); + + int (*handle_management) (struct net_device * dev, + struct ieee80211_network * network, u16 type); + int (*is_qos_active) (struct net_device *dev, struct sk_buff *skb); + + /* Softmac-generated frames (mamagement) are TXed via this + * callback if the flag IEEE_SOFTMAC_SINGLE_QUEUE is + * not set. As some cards may have different HW queues that + * one might want to use for data and management frames + * the option to have two callbacks might be useful. + * This fucntion can't sleep. + */ + int (*softmac_hard_start_xmit)(struct sk_buff *skb, + struct net_device *dev); + + /* used instead of hard_start_xmit (not softmac_hard_start_xmit) + * if the IEEE_SOFTMAC_TX_QUEUE feature is used to TX data + * frames. I the option IEEE_SOFTMAC_SINGLE_QUEUE is also set + * then also management frames are sent via this callback. + * This function can't sleep. + */ + void (*softmac_data_hard_start_xmit)(struct sk_buff *skb, + struct net_device *dev,int rate); + + /* stops the HW queue for DATA frames. Useful to avoid + * waste time to TX data frame when we are reassociating + * This function can sleep. + */ + void (*data_hard_stop)(struct net_device *dev); + + /* OK this is complementar to data_poll_hard_stop */ + void (*data_hard_resume)(struct net_device *dev); + + /* ask to the driver to retune the radio . + * This function can sleep. the driver should ensure + * the radio has been swithced before return. + */ + void (*set_chan)(struct net_device *dev,short ch); + + /* These are not used if the ieee stack takes care of + * scanning (IEEE_SOFTMAC_SCAN feature set). + * In this case only the set_chan is used. + * + * The syncro version is similar to the start_scan but + * does not return until all channels has been scanned. + * this is called in user context and should sleep, + * it is called in a work_queue when swithcing to ad-hoc mode + * or in behalf of iwlist scan when the card is associated + * and root user ask for a scan. + * the fucntion stop_scan should stop both the syncro and + * background scanning and can sleep. + * The fucntion start_scan should initiate the background + * scanning and can't sleep. + */ + void (*scan_syncro)(struct net_device *dev); + void (*start_scan)(struct net_device *dev); + void (*stop_scan)(struct net_device *dev); + + /* indicate the driver that the link state is changed + * for example it may indicate the card is associated now. + * Driver might be interested in this to apply RX filter + * rules or simply light the LINK led + */ + void (*link_change)(struct net_device *dev); + + /* these two function indicates to the HW when to start + * and stop to send beacons. This is used when the + * IEEE_SOFTMAC_BEACONS is not set. For now the + * stop_send_bacons is NOT guaranteed to be called only + * after start_send_beacons. + */ + void (*start_send_beacons) (struct net_device *dev); + void (*stop_send_beacons) (struct net_device *dev); + + /* power save mode related */ + void (*sta_wake_up) (struct net_device *dev); +// void (*ps_request_tx_ack) (struct net_device *dev); + void (*enter_sleep_state) (struct net_device *dev, u32 th, u32 tl); + short (*ps_is_queue_empty) (struct net_device *dev); +#if 0 + /* Typical STA methods */ + int (*handle_auth) (struct net_device * dev, + struct ieee80211_auth * auth); + int (*handle_deauth) (struct net_device * dev, + struct ieee80211_deauth * auth); + int (*handle_action) (struct net_device * dev, + struct ieee80211_action * action, + struct ieee80211_rx_stats * stats); + int (*handle_disassoc) (struct net_device * dev, + struct ieee80211_disassoc * assoc); +#endif + int (*handle_beacon) (struct net_device * dev, struct ieee80211_beacon * beacon, struct ieee80211_network * network); +#if 0 + int (*handle_probe_response) (struct net_device * dev, + struct ieee80211_probe_response * resp, + struct ieee80211_network * network); + int (*handle_probe_request) (struct net_device * dev, + struct ieee80211_probe_request * req, + struct ieee80211_rx_stats * stats); +#endif + int (*handle_assoc_response) (struct net_device * dev, struct ieee80211_assoc_response_frame * resp, struct ieee80211_network * network); + +#if 0 + /* Typical AP methods */ + int (*handle_assoc_request) (struct net_device * dev); + int (*handle_reassoc_request) (struct net_device * dev, + struct ieee80211_reassoc_request * req); +#endif + + /* check whether Tx hw resouce available */ + short (*check_nic_enough_desc)(struct net_device *dev, int queue_index); + //added by wb for HT related +// void (*SwChnlByTimerHandler)(struct net_device *dev, int channel); + void (*SetBWModeHandler)(struct net_device *dev, HT_CHANNEL_WIDTH Bandwidth, HT_EXTCHNL_OFFSET Offset); +// void (*UpdateHalRATRTableHandler)(struct net_device* dev, u8* pMcsRate); + bool (*GetNmodeSupportBySecCfg)(struct net_device* dev); + void (*SetWirelessMode)(struct net_device* dev, u8 wireless_mode); + bool (*GetHalfNmodeSupportByAPsHandler)(struct net_device* dev); + bool (*is_ap_in_wep_tkip)(struct net_device* dev); + void (*InitialGainHandler)(struct net_device *dev, u8 Operation); + bool (*SetFwCmdHandler)(struct net_device *dev, FW_CMD_IO_TYPE FwCmdIO); + void (*LedControlHandler)(struct net_device * dev, LED_CTL_MODE LedAction); + /* This must be the last item so that it points to the data + * allocated beyond this structure by alloc_ieee80211 */ + u8 priv[0]; +}; + +#define IEEE_A (1<<0) +#define IEEE_B (1<<1) +#define IEEE_G (1<<2) +#define IEEE_N_24G (1<<4) +#define IEEE_N_5G (1<<5) +#define IEEE_MODE_MASK (IEEE_A|IEEE_B|IEEE_G) + +/* Generate a 802.11 header */ + +/* Uses the channel change callback directly + * instead of [start/stop] scan callbacks + */ +#define IEEE_SOFTMAC_SCAN (1<<2) + +/* Perform authentication and association handshake */ +#define IEEE_SOFTMAC_ASSOCIATE (1<<3) + +/* Generate probe requests */ +#define IEEE_SOFTMAC_PROBERQ (1<<4) + +/* Generate respones to probe requests */ +#define IEEE_SOFTMAC_PROBERS (1<<5) + +/* The ieee802.11 stack will manages the netif queue + * wake/stop for the driver, taking care of 802.11 + * fragmentation. See softmac.c for details. */ +#define IEEE_SOFTMAC_TX_QUEUE (1<<7) + +/* Uses only the softmac_data_hard_start_xmit + * even for TX management frames. + */ +#define IEEE_SOFTMAC_SINGLE_QUEUE (1<<8) + +/* Generate beacons. The stack will enqueue beacons + * to the card + */ +#define IEEE_SOFTMAC_BEACONS (1<<6) + +static inline void *ieee80211_priv(struct net_device *dev) +{ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + return ((struct ieee80211_device *)netdev_priv(dev))->priv; +#else + return ((struct ieee80211_device *)dev->priv)->priv; +#endif +} + +extern inline int ieee80211_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; +} + +extern inline int ieee80211_is_valid_mode(struct ieee80211_device *ieee, int mode) +{ + /* + * It is possible for both access points and our device to support + * combinations of modes, so as long as there is one valid combination + * of ap/device supported modes, then return success + * + */ + if ((mode & IEEE_A) && + (ieee->modulation & IEEE80211_OFDM_MODULATION) && + (ieee->freq_band & IEEE80211_52GHZ_BAND)) + return 1; + + if ((mode & IEEE_G) && + (ieee->modulation & IEEE80211_OFDM_MODULATION) && + (ieee->freq_band & IEEE80211_24GHZ_BAND)) + return 1; + + if ((mode & IEEE_B) && + (ieee->modulation & IEEE80211_CCK_MODULATION) && + (ieee->freq_band & IEEE80211_24GHZ_BAND)) + return 1; + + return 0; +} + +extern inline int ieee80211_get_hdrlen(u16 fc) +{ + int hdrlen = IEEE80211_3ADDR_LEN; + + switch (WLAN_FC_GET_TYPE(fc)) { + case IEEE80211_FTYPE_DATA: + if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS)) + hdrlen = IEEE80211_4ADDR_LEN; /* Addr4 */ + if(IEEE80211_QOS_HAS_SEQ(fc)) + hdrlen += 2; /* QOS ctrl*/ + break; + case IEEE80211_FTYPE_CTL: + switch (WLAN_FC_GET_STYPE(fc)) { + case IEEE80211_STYPE_CTS: + case IEEE80211_STYPE_ACK: + hdrlen = IEEE80211_1ADDR_LEN; + break; + default: + hdrlen = IEEE80211_2ADDR_LEN; + break; + } + break; + } + + return hdrlen; +} + +static inline u8 *ieee80211_get_payload(struct ieee80211_hdr *hdr) +{ + switch (ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl))) { + case IEEE80211_1ADDR_LEN: + return ((struct ieee80211_hdr_1addr *)hdr)->payload; + case IEEE80211_2ADDR_LEN: + return ((struct ieee80211_hdr_2addr *)hdr)->payload; + case IEEE80211_3ADDR_LEN: + return ((struct ieee80211_hdr_3addr *)hdr)->payload; + case IEEE80211_4ADDR_LEN: + return ((struct ieee80211_hdr_4addr *)hdr)->payload; + } + return NULL; +} + +static inline int ieee80211_is_ofdm_rate(u8 rate) +{ + switch (rate & ~IEEE80211_BASIC_RATE_MASK) { + case IEEE80211_OFDM_RATE_6MB: + case IEEE80211_OFDM_RATE_9MB: + case IEEE80211_OFDM_RATE_12MB: + case IEEE80211_OFDM_RATE_18MB: + case IEEE80211_OFDM_RATE_24MB: + case IEEE80211_OFDM_RATE_36MB: + case IEEE80211_OFDM_RATE_48MB: + case IEEE80211_OFDM_RATE_54MB: + return 1; + } + return 0; +} + +static inline int ieee80211_is_cck_rate(u8 rate) +{ + switch (rate & ~IEEE80211_BASIC_RATE_MASK) { + case IEEE80211_CCK_RATE_1MB: + case IEEE80211_CCK_RATE_2MB: + case IEEE80211_CCK_RATE_5MB: + case IEEE80211_CCK_RATE_11MB: + return 1; + } + return 0; +} + + +/* ieee80211.c */ +extern void free_ieee80211(struct net_device *dev); +extern struct net_device *alloc_ieee80211(int sizeof_priv); + +extern int ieee80211_set_encryption(struct ieee80211_device *ieee); + +/* ieee80211_tx.c */ + +extern int ieee80211_encrypt_fragment( + struct ieee80211_device *ieee, + struct sk_buff *frag, + int hdr_len); + +extern int ieee80211_xmit(struct sk_buff *skb, + struct net_device *dev); +extern void ieee80211_txb_free(struct ieee80211_txb *); + + +/* ieee80211_rx.c */ +extern int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, + struct ieee80211_rx_stats *rx_stats); +extern void ieee80211_rx_mgt(struct ieee80211_device *ieee, + struct ieee80211_hdr_4addr *header, + struct ieee80211_rx_stats *stats); + +/* ieee80211_wx.c */ +extern int ieee80211_wx_get_scan(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *key); +extern int ieee80211_wx_set_encode(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *key); +extern int ieee80211_wx_get_encode(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *key); +#if WIRELESS_EXT >= 18 +extern int ieee80211_wx_get_encode_ext(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data* wrqu, char *extra); +extern int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data* wrqu, char *extra); +extern int ieee80211_wx_set_auth(struct ieee80211_device *ieee, + struct iw_request_info *info, + struct iw_param *data, char *extra); +extern int ieee80211_wx_set_mlme(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); +#endif +extern int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len); + +/* ieee80211_softmac.c */ +extern short ieee80211_is_54g(struct ieee80211_network net); +extern short ieee80211_is_shortslot(struct ieee80211_network net); +extern int ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb, + struct ieee80211_rx_stats *rx_stats, u16 type, + u16 stype); +extern void ieee80211_softmac_new_net(struct ieee80211_device *ieee, struct ieee80211_network *net); + +void SendDisassociation(struct ieee80211_device *ieee, u8* asSta, u8 asRsn); +extern void ieee80211_softmac_xmit(struct ieee80211_txb *txb, struct ieee80211_device *ieee); + +extern void ieee80211_stop_send_beacons(struct ieee80211_device *ieee); +extern void notify_wx_assoc_event(struct ieee80211_device *ieee); +extern void ieee80211_softmac_check_all_nets(struct ieee80211_device *ieee); +extern void ieee80211_start_bss(struct ieee80211_device *ieee); +extern void ieee80211_start_master_bss(struct ieee80211_device *ieee); +extern void ieee80211_start_ibss(struct ieee80211_device *ieee); +extern void ieee80211_softmac_init(struct ieee80211_device *ieee); +extern void ieee80211_softmac_free(struct ieee80211_device *ieee); +extern void ieee80211_associate_abort(struct ieee80211_device *ieee); +extern void ieee80211_disassociate(struct ieee80211_device *ieee); +extern void ieee80211_stop_scan(struct ieee80211_device *ieee); +extern void ieee80211_start_scan_syncro(struct ieee80211_device *ieee); +extern void ieee80211_check_all_nets(struct ieee80211_device *ieee); +extern void ieee80211_start_protocol(struct ieee80211_device *ieee); +extern void ieee80211_stop_protocol(struct ieee80211_device *ieee); +extern void ieee80211_softmac_start_protocol(struct ieee80211_device *ieee); +extern void ieee80211_softmac_stop_protocol(struct ieee80211_device *ieee); +extern void ieee80211_reset_queue(struct ieee80211_device *ieee); +extern void ieee80211_wake_queue(struct ieee80211_device *ieee); +extern void ieee80211_stop_queue(struct ieee80211_device *ieee); +extern struct sk_buff *ieee80211_get_beacon(struct ieee80211_device *ieee); +extern void ieee80211_start_send_beacons(struct ieee80211_device *ieee); +extern void ieee80211_stop_send_beacons(struct ieee80211_device *ieee); +extern int ieee80211_wpa_supplicant_ioctl(struct ieee80211_device *ieee, struct iw_point *p); +extern void notify_wx_assoc_event(struct ieee80211_device *ieee); +extern void ieee80211_ps_tx_ack(struct ieee80211_device *ieee, short success); + +extern void softmac_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *ieee); + +/* ieee80211_crypt_ccmp&tkip&wep.c */ +extern void ieee80211_tkip_null(void); +extern void ieee80211_wep_null(void); +extern void ieee80211_ccmp_null(void); + +/* ieee80211_softmac_wx.c */ + +extern int ieee80211_wx_get_wap(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *ext); + +extern int ieee80211_wx_set_wap(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *awrq, + char *extra); + +extern int ieee80211_wx_get_essid(struct ieee80211_device *ieee, struct iw_request_info *a,union iwreq_data *wrqu,char *b); + +extern int ieee80211_wx_set_rate(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +extern int ieee80211_wx_get_rate(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +extern int ieee80211_wx_set_mode(struct ieee80211_device *ieee, struct iw_request_info *a, + union iwreq_data *wrqu, char *b); + +extern int ieee80211_wx_set_scan(struct ieee80211_device *ieee, struct iw_request_info *a, + union iwreq_data *wrqu, char *b); + +extern int ieee80211_wx_set_essid(struct ieee80211_device *ieee, + struct iw_request_info *a, + union iwreq_data *wrqu, char *extra); + +extern int ieee80211_wx_get_mode(struct ieee80211_device *ieee, struct iw_request_info *a, + union iwreq_data *wrqu, char *b); + +extern int ieee80211_wx_set_freq(struct ieee80211_device *ieee, struct iw_request_info *a, + union iwreq_data *wrqu, char *b); + +extern int ieee80211_wx_get_freq(struct ieee80211_device *ieee, struct iw_request_info *a, + union iwreq_data *wrqu, char *b); + +//extern void ieee80211_wx_sync_scan_wq(struct ieee80211_device *ieee); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) +extern void ieee80211_wx_sync_scan_wq(struct work_struct *work); +#else + extern void ieee80211_wx_sync_scan_wq(struct ieee80211_device *ieee); +#endif + + +extern int ieee80211_wx_set_rawtx(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +extern int ieee80211_wx_get_name(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +extern int ieee80211_wx_set_power(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +extern int ieee80211_wx_get_power(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +extern int ieee80211_wx_set_rts(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +extern int ieee80211_wx_get_rts(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); +//HT +#define MAX_RECEIVE_BUFFER_SIZE 9100 // +extern void HTDebugHTCapability(u8* CapIE, u8* TitleString ); +extern void HTDebugHTInfo(u8* InfoIE, u8* TitleString); + +void HTSetConnectBwMode(struct ieee80211_device* ieee, HT_CHANNEL_WIDTH Bandwidth, HT_EXTCHNL_OFFSET Offset); +extern void HTUpdateDefaultSetting(struct ieee80211_device* ieee); +extern void HTConstructCapabilityElement(struct ieee80211_device* ieee, u8* posHTCap, u8* len, u8 isEncrypt); +extern void HTConstructInfoElement(struct ieee80211_device* ieee, u8* posHTInfo, u8* len, u8 isEncrypt); +extern void HTConstructRT2RTAggElement(struct ieee80211_device* ieee, u8* posRT2RTAgg, u8* len); +extern void HTOnAssocRsp(struct ieee80211_device *ieee); +extern void HTInitializeHTInfo(struct ieee80211_device* ieee); +extern void HTInitializeBssDesc(PBSS_HT pBssHT); +extern void HTResetSelfAndSavePeerSetting(struct ieee80211_device* ieee, struct ieee80211_network * pNetwork); +extern void HTUpdateSelfAndPeerSetting(struct ieee80211_device* ieee, struct ieee80211_network * pNetwork); +extern u8 HTGetHighestMCSRate(struct ieee80211_device* ieee, u8* pMCSRateSet, u8* pMCSFilter); +extern u8 MCS_FILTER_ALL[]; +extern u16 MCS_DATA_RATE[2][2][77] ; +extern u8 HTCCheck(struct ieee80211_device* ieee, u8* pFrame); +//extern void HTSetConnectBwModeCallback(unsigned long data); +extern void HTResetIOTSetting(PRT_HIGH_THROUGHPUT pHTInfo); +extern bool IsHTHalfNmodeAPs(struct ieee80211_device* ieee); +extern u16 HTHalfMcsToDataRate(struct ieee80211_device* ieee, u8 nMcsRate); +extern u16 HTMcsToDataRate( struct ieee80211_device* ieee, u8 nMcsRate); +extern u16 TxCountToDataRate( struct ieee80211_device* ieee, u8 nDataRate); +//function in BAPROC.c +extern int ieee80211_rx_ADDBAReq( struct ieee80211_device* ieee, struct sk_buff *skb); +extern int ieee80211_rx_ADDBARsp( struct ieee80211_device* ieee, struct sk_buff *skb); +extern int ieee80211_rx_DELBA(struct ieee80211_device* ieee,struct sk_buff *skb); +extern void TsInitAddBA( struct ieee80211_device* ieee, PTX_TS_RECORD pTS, u8 Policy, u8 bOverwritePending); +extern void TsInitDelBA( struct ieee80211_device* ieee, PTS_COMMON_INFO pTsCommonInfo, TR_SELECT TxRxSelect); +extern void BaSetupTimeOut(unsigned long data); +extern void TxBaInactTimeout(unsigned long data); +extern void RxBaInactTimeout(unsigned long data); +extern void ResetBaEntry( PBA_RECORD pBA); +//function in TS.c +extern bool GetTs( + struct ieee80211_device* ieee, + PTS_COMMON_INFO *ppTS, + u8* Addr, + u8 TID, + TR_SELECT TxRxSelect, //Rx:1, Tx:0 + bool bAddNewTs + ); +extern void TSInitialize(struct ieee80211_device *ieee); +extern void TsStartAddBaProcess(struct ieee80211_device* ieee, PTX_TS_RECORD pTxTS); +extern void RemovePeerTS(struct ieee80211_device* ieee, u8* Addr); +extern void RemoveAllTS(struct ieee80211_device* ieee); +void ieee80211_softmac_scan_syncro(struct ieee80211_device *ieee); + +extern const long ieee80211_wlan_frequencies[]; + +extern inline void ieee80211_increment_scans(struct ieee80211_device *ieee) +{ + ieee->scans++; +} + +extern inline int ieee80211_get_scans(struct ieee80211_device *ieee) +{ + return ieee->scans; +} + +static inline const char *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 (ieee80211_is_empty_essid(essid, essid_len)) { + memcpy(escaped, "", sizeof("")); + 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; +} + +/* For the function is more related to hardware setting, it's better to use the + * ieee handler to refer to it. + */ +extern short check_nic_enough_desc(struct net_device *dev, int queue_index); +extern int ieee80211_data_xmit(struct sk_buff *skb, struct net_device *dev); +extern int ieee80211_parse_info_param(struct ieee80211_device *ieee, + struct ieee80211_info_element *info_element, + u16 length, + struct ieee80211_network *network, + struct ieee80211_rx_stats *stats); + +void ieee80211_indicate_packets(struct ieee80211_device *ieee, struct ieee80211_rxb** prxbIndicateArray,u8 index); +#define RT_ASOC_RETRY_LIMIT 5 +#endif /* IEEE80211_H */ diff --git a/drivers/staging/rtl8192su/ieee80211/EndianFree.h b/drivers/staging/rtl8192su/ieee80211/EndianFree.h new file mode 100644 index 000000000000..0c417a6234a9 --- /dev/null +++ b/drivers/staging/rtl8192su/ieee80211/EndianFree.h @@ -0,0 +1,199 @@ +#ifndef __INC_ENDIANFREE_H +#define __INC_ENDIANFREE_H + +/* + * Call endian free function when + * 1. Read/write packet content. + * 2. Before write integer to IO. + * 3. After read integer from IO. + */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)) +#ifndef bool +typedef enum{false = 0, true} bool; +#endif +#endif + +#define __MACHINE_LITTLE_ENDIAN 1234 /* LSB first: i386, vax */ +#define __MACHINE_BIG_ENDIAN 4321 /* MSB first: 68000, ibm, net, ppc */ + +#define BYTE_ORDER __MACHINE_LITTLE_ENDIAN + +#if BYTE_ORDER == __MACHINE_LITTLE_ENDIAN +// Convert data +#define EF1Byte(_val) ((u8)(_val)) +#define EF2Byte(_val) ((u16)(_val)) +#define EF4Byte(_val) ((u32)(_val)) + +#else +// Convert data +#define EF1Byte(_val) ((u8)(_val)) +#define EF2Byte(_val) (((((u16)(_val))&0x00ff)<<8)|((((u16)(_val))&0xff00)>>8)) +#define EF4Byte(_val) (((((u32)(_val))&0x000000ff)<<24)|\ + ((((u32)(_val))&0x0000ff00)<<8)|\ + ((((u32)(_val))&0x00ff0000)>>8)|\ + ((((u32)(_val))&0xff000000)>>24)) +#endif + +// Read data from memory +#define ReadEF1Byte(_ptr) EF1Byte(*((u8 *)(_ptr))) +#define ReadEF2Byte(_ptr) EF2Byte(*((u16 *)(_ptr))) +#define ReadEF4Byte(_ptr) EF4Byte(*((u32 *)(_ptr))) + +// Write data to memory +#define WriteEF1Byte(_ptr, _val) (*((u8 *)(_ptr)))=EF1Byte(_val) +#define WriteEF2Byte(_ptr, _val) (*((u16 *)(_ptr)))=EF2Byte(_val) +#define WriteEF4Byte(_ptr, _val) (*((u32 *)(_ptr)))=EF4Byte(_val) +// Convert Host system specific byte ording (litten or big endia) to Network byte ording (big endian). +// 2006.05.07, by rcnjko. +#if BYTE_ORDER == __MACHINE_LITTLE_ENDIAN +#define H2N1BYTE(_val) ((u8)(_val)) +#define H2N2BYTE(_val) (((((u16)(_val))&0x00ff)<<8)|\ + ((((u16)(_val))&0xff00)>>8)) +#define H2N4BYTE(_val) (((((u32)(_val))&0x000000ff)<<24)|\ + ((((u32)(_val))&0x0000ff00)<<8) |\ + ((((u32)(_val))&0x00ff0000)>>8) |\ + ((((u32)(_val))&0xff000000)>>24)) +#else +#define H2N1BYTE(_val) ((u8)(_val)) +#define H2N2BYTE(_val) ((u16)(_val)) +#define H2N4BYTE(_val) ((u32)(_val)) +#endif + +// Convert from Network byte ording (big endian) to Host system specific byte ording (litten or big endia). +// 2006.05.07, by rcnjko. +#if BYTE_ORDER == __MACHINE_LITTLE_ENDIAN +#define N2H1BYTE(_val) ((u8)(_val)) +#define N2H2BYTE(_val) (((((u16)(_val))&0x00ff)<<8)|\ + ((((u16)(_val))&0xff00)>>8)) +#define N2H4BYTE(_val) (((((u32)(_val))&0x000000ff)<<24)|\ + ((((u32)(_val))&0x0000ff00)<<8) |\ + ((((u32)(_val))&0x00ff0000)>>8) |\ + ((((u32)(_val))&0xff000000)>>24)) +#else +#define N2H1BYTE(_val) ((u8)(_val)) +#define N2H2BYTE(_val) ((u16)(_val)) +#define N2H4BYTE(_val) ((u32)(_val)) +#endif + +// +// Example: +// BIT_LEN_MASK_32(0) => 0x00000000 +// BIT_LEN_MASK_32(1) => 0x00000001 +// BIT_LEN_MASK_32(2) => 0x00000003 +// BIT_LEN_MASK_32(32) => 0xFFFFFFFF +// +#define BIT_LEN_MASK_32(__BitLen) (0xFFFFFFFF >> (32 - (__BitLen))) +// +// Example: +// BIT_OFFSET_LEN_MASK_32(0, 2) => 0x00000003 +// BIT_OFFSET_LEN_MASK_32(16, 2) => 0x00030000 +// +#define BIT_OFFSET_LEN_MASK_32(__BitOffset, __BitLen) (BIT_LEN_MASK_32(__BitLen) << (__BitOffset)) + +// +// Description: +// Return 4-byte value in host byte ordering from +// 4-byte pointer in litten-endian system. +// +#define LE_P4BYTE_TO_HOST_4BYTE(__pStart) (EF4Byte(*((u32 *)(__pStart)))) + +// +// Description: +// Translate subfield (continuous bits in little-endian) of 4-byte value in litten byte to +// 4-byte value in host byte ordering. +// +#define LE_BITS_TO_4BYTE(__pStart, __BitOffset, __BitLen) \ + ( \ + ( LE_P4BYTE_TO_HOST_4BYTE(__pStart) >> (__BitOffset) ) \ + & \ + BIT_LEN_MASK_32(__BitLen) \ + ) + +// +// Description: +// Mask subfield (continuous bits in little-endian) of 4-byte value in litten byte oredering +// and return the result in 4-byte value in host byte ordering. +// +#define LE_BITS_CLEARED_TO_4BYTE(__pStart, __BitOffset, __BitLen) \ + ( \ + LE_P4BYTE_TO_HOST_4BYTE(__pStart) \ + & \ + ( ~BIT_OFFSET_LEN_MASK_32(__BitOffset, __BitLen) ) \ + ) + +// +// Description: +// Set subfield of little-endian 4-byte value to specified value. +// +#define SET_BITS_TO_LE_4BYTE(__pStart, __BitOffset, __BitLen, __Value) \ + *((u32 *)(__pStart)) = \ + EF4Byte( \ + LE_BITS_CLEARED_TO_4BYTE(__pStart, __BitOffset, __BitLen) \ + | \ + ( (((u32)__Value) & BIT_LEN_MASK_32(__BitLen)) << (__BitOffset) ) \ + ); + + +#define BIT_LEN_MASK_16(__BitLen) \ + (0xFFFF >> (16 - (__BitLen))) + +#define BIT_OFFSET_LEN_MASK_16(__BitOffset, __BitLen) \ + (BIT_LEN_MASK_16(__BitLen) << (__BitOffset)) + +#define LE_P2BYTE_TO_HOST_2BYTE(__pStart) \ + (EF2Byte(*((u16 *)(__pStart)))) + +#define LE_BITS_TO_2BYTE(__pStart, __BitOffset, __BitLen) \ + ( \ + ( LE_P2BYTE_TO_HOST_2BYTE(__pStart) >> (__BitOffset) ) \ + & \ + BIT_LEN_MASK_16(__BitLen) \ + ) + +#define LE_BITS_CLEARED_TO_2BYTE(__pStart, __BitOffset, __BitLen) \ + ( \ + LE_P2BYTE_TO_HOST_2BYTE(__pStart) \ + & \ + ( ~BIT_OFFSET_LEN_MASK_16(__BitOffset, __BitLen) ) \ + ) + +#define SET_BITS_TO_LE_2BYTE(__pStart, __BitOffset, __BitLen, __Value) \ + *((u16 *)(__pStart)) = \ + EF2Byte( \ + LE_BITS_CLEARED_TO_2BYTE(__pStart, __BitOffset, __BitLen) \ + | \ + ( (((u16)__Value) & BIT_LEN_MASK_16(__BitLen)) << (__BitOffset) ) \ + ); + +#define BIT_LEN_MASK_8(__BitLen) \ + (0xFF >> (8 - (__BitLen))) + +#define BIT_OFFSET_LEN_MASK_8(__BitOffset, __BitLen) \ + (BIT_LEN_MASK_8(__BitLen) << (__BitOffset)) + +#define LE_P1BYTE_TO_HOST_1BYTE(__pStart) \ + (EF1Byte(*((u8 *)(__pStart)))) + +#define LE_BITS_TO_1BYTE(__pStart, __BitOffset, __BitLen) \ + ( \ + ( LE_P1BYTE_TO_HOST_1BYTE(__pStart) >> (__BitOffset) ) \ + & \ + BIT_LEN_MASK_8(__BitLen) \ + ) + +#define LE_BITS_CLEARED_TO_1BYTE(__pStart, __BitOffset, __BitLen) \ + ( \ + LE_P1BYTE_TO_HOST_1BYTE(__pStart) \ + & \ + ( ~BIT_OFFSET_LEN_MASK_8(__BitOffset, __BitLen) ) \ + ) + +#define SET_BITS_TO_LE_1BYTE(__pStart, __BitOffset, __BitLen, __Value) \ + *((u8 *)(__pStart)) = \ + EF1Byte( \ + LE_BITS_CLEARED_TO_1BYTE(__pStart, __BitOffset, __BitLen) \ + | \ + ( (((u8)__Value) & BIT_LEN_MASK_8(__BitLen)) << (__BitOffset) ) \ + ); + +#endif // #ifndef __INC_ENDIANFREE_H diff --git a/drivers/staging/rtl8192su/ieee80211/Makefile b/drivers/staging/rtl8192su/ieee80211/Makefile new file mode 100644 index 000000000000..295a18f3c9ca --- /dev/null +++ b/drivers/staging/rtl8192su/ieee80211/Makefile @@ -0,0 +1,31 @@ +NIC_SELECT = RTL8192SU + +EXTRA_CFLAGS += -O2 +EXTRA_CFLAGS += -DRTL8192S_DISABLE_FW_DM=0 +EXTRA_CFLAGS += -DRTL8192SU +#EXTRA_CFLAGS += -DJOHN_NOCPY +EXTRA_CFLAGS += -DTHOMAS_TURBO +#flags to enable or disble 80211D feature +EXTRA_CFLAGS += -DENABLE_DOT11D +ieee80211-rsl-objs := ieee80211_rx.o \ + ieee80211_softmac.o \ + ieee80211_tx.o \ + ieee80211_wx.o \ + ieee80211_module.o \ + ieee80211_softmac_wx.o\ + rtl819x_HTProc.o\ + rtl819x_TSProc.o\ + rtl819x_BAProc.o\ + dot11d.o + +ieee80211_crypt-rsl-objs := ieee80211_crypt.o +ieee80211_crypt_tkip-rsl-objs := ieee80211_crypt_tkip.o +ieee80211_crypt_ccmp-rsl-objs := ieee80211_crypt_ccmp.o +ieee80211_crypt_wep-rsl-objs := ieee80211_crypt_wep.o + +obj-m +=ieee80211-rsl.o +obj-m +=ieee80211_crypt-rsl.o +obj-m +=ieee80211_crypt_wep-rsl.o +obj-m +=ieee80211_crypt_tkip-rsl.o +obj-m +=ieee80211_crypt_ccmp-rsl.o + diff --git a/drivers/staging/rtl8192su/ieee80211/aes.c b/drivers/staging/rtl8192su/ieee80211/aes.c new file mode 100644 index 000000000000..0c176e29a797 --- /dev/null +++ b/drivers/staging/rtl8192su/ieee80211/aes.c @@ -0,0 +1,469 @@ +/* + * Cryptographic API. + * + * AES Cipher Algorithm. + * + * Based on Brian Gladman's code. + * + * Linux developers: + * Alexander Kjeldaas + * Herbert Valerio Riedel + * Kyle McMartin + * Adam J. Richter (conversion to 2.5 API). + * + * 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. + * + * --------------------------------------------------------------------------- + * Copyright (c) 2002, Dr Brian Gladman , Worcester, UK. + * All rights reserved. + * + * LICENSE TERMS + * + * The free distribution and use of this software in both source and binary + * form is allowed (with or without changes) provided that: + * + * 1. distributions of this source code include the above copyright + * notice, this list of conditions and the following disclaimer; + * + * 2. distributions in binary form include the above copyright + * notice, this list of conditions and the following disclaimer + * in the documentation and/or other associated materials; + * + * 3. the copyright holder's name is not used to endorse products + * built using this software without specific written permission. + * + * ALTERNATIVELY, provided that this notice is retained in full, this product + * may be distributed under the terms of the GNU General Public License (GPL), + * in which case the provisions of the GPL apply INSTEAD OF those given above. + * + * DISCLAIMER + * + * This software is provided 'as is' with no explicit or implied warranties + * in respect of its properties, including, but not limited to, correctness + * and/or fitness for purpose. + * --------------------------------------------------------------------------- + */ + +/* Some changes from the Gladman version: + s/RIJNDAEL(e_key)/E_KEY/g + s/RIJNDAEL(d_key)/D_KEY/g +*/ + +#include +#include +#include +#include +//#include +#include "rtl_crypto.h" +#include + +#define AES_MIN_KEY_SIZE 16 +#define AES_MAX_KEY_SIZE 32 + +#define AES_BLOCK_SIZE 16 + +static inline +u32 generic_rotr32 (const u32 x, const unsigned bits) +{ + const unsigned n = bits % 32; + return (x >> n) | (x << (32 - n)); +} + +static inline +u32 generic_rotl32 (const u32 x, const unsigned bits) +{ + const unsigned n = bits % 32; + return (x << n) | (x >> (32 - n)); +} + +#define rotl generic_rotl32 +#define rotr generic_rotr32 + +/* + * #define byte(x, nr) ((unsigned char)((x) >> (nr*8))) + */ +inline static u8 +byte(const u32 x, const unsigned n) +{ + return x >> (n << 3); +} + +#define u32_in(x) le32_to_cpu(*(const u32 *)(x)) +#define u32_out(to, from) (*(u32 *)(to) = cpu_to_le32(from)) + +struct aes_ctx { + int key_length; + u32 E[60]; + u32 D[60]; +}; + +#define E_KEY ctx->E +#define D_KEY ctx->D + +static u8 pow_tab[256] __initdata; +static u8 log_tab[256] __initdata; +static u8 sbx_tab[256] __initdata; +static u8 isb_tab[256] __initdata; +static u32 rco_tab[10]; +static u32 ft_tab[4][256]; +static u32 it_tab[4][256]; + +static u32 fl_tab[4][256]; +static u32 il_tab[4][256]; + +static inline u8 __init +f_mult (u8 a, u8 b) +{ + u8 aa = log_tab[a], cc = aa + log_tab[b]; + + return pow_tab[cc + (cc < aa ? 1 : 0)]; +} + +#define ff_mult(a,b) (a && b ? f_mult(a, b) : 0) + +#define f_rn(bo, bi, n, k) \ + bo[n] = ft_tab[0][byte(bi[n],0)] ^ \ + ft_tab[1][byte(bi[(n + 1) & 3],1)] ^ \ + ft_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ + ft_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n) + +#define i_rn(bo, bi, n, k) \ + bo[n] = it_tab[0][byte(bi[n],0)] ^ \ + it_tab[1][byte(bi[(n + 3) & 3],1)] ^ \ + it_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ + it_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n) + +#define ls_box(x) \ + ( fl_tab[0][byte(x, 0)] ^ \ + fl_tab[1][byte(x, 1)] ^ \ + fl_tab[2][byte(x, 2)] ^ \ + fl_tab[3][byte(x, 3)] ) + +#define f_rl(bo, bi, n, k) \ + bo[n] = fl_tab[0][byte(bi[n],0)] ^ \ + fl_tab[1][byte(bi[(n + 1) & 3],1)] ^ \ + fl_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ + fl_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n) + +#define i_rl(bo, bi, n, k) \ + bo[n] = il_tab[0][byte(bi[n],0)] ^ \ + il_tab[1][byte(bi[(n + 3) & 3],1)] ^ \ + il_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ + il_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n) + +static void __init +gen_tabs (void) +{ + u32 i, t; + u8 p, q; + + /* log and power tables for GF(2**8) finite field with + 0x011b as modular polynomial - the simplest primitive + root is 0x03, used here to generate the tables */ + + for (i = 0, p = 1; i < 256; ++i) { + pow_tab[i] = (u8) p; + log_tab[p] = (u8) i; + + p ^= (p << 1) ^ (p & 0x80 ? 0x01b : 0); + } + + log_tab[1] = 0; + + for (i = 0, p = 1; i < 10; ++i) { + rco_tab[i] = p; + + p = (p << 1) ^ (p & 0x80 ? 0x01b : 0); + } + + for (i = 0; i < 256; ++i) { + p = (i ? pow_tab[255 - log_tab[i]] : 0); + q = ((p >> 7) | (p << 1)) ^ ((p >> 6) | (p << 2)); + p ^= 0x63 ^ q ^ ((q >> 6) | (q << 2)); + sbx_tab[i] = p; + isb_tab[p] = (u8) i; + } + + for (i = 0; i < 256; ++i) { + p = sbx_tab[i]; + + t = p; + fl_tab[0][i] = t; + fl_tab[1][i] = rotl (t, 8); + fl_tab[2][i] = rotl (t, 16); + fl_tab[3][i] = rotl (t, 24); + + t = ((u32) ff_mult (2, p)) | + ((u32) p << 8) | + ((u32) p << 16) | ((u32) ff_mult (3, p) << 24); + + ft_tab[0][i] = t; + ft_tab[1][i] = rotl (t, 8); + ft_tab[2][i] = rotl (t, 16); + ft_tab[3][i] = rotl (t, 24); + + p = isb_tab[i]; + + t = p; + il_tab[0][i] = t; + il_tab[1][i] = rotl (t, 8); + il_tab[2][i] = rotl (t, 16); + il_tab[3][i] = rotl (t, 24); + + t = ((u32) ff_mult (14, p)) | + ((u32) ff_mult (9, p) << 8) | + ((u32) ff_mult (13, p) << 16) | + ((u32) ff_mult (11, p) << 24); + + it_tab[0][i] = t; + it_tab[1][i] = rotl (t, 8); + it_tab[2][i] = rotl (t, 16); + it_tab[3][i] = rotl (t, 24); + } +} + +#define star_x(x) (((x) & 0x7f7f7f7f) << 1) ^ ((((x) & 0x80808080) >> 7) * 0x1b) + +#define imix_col(y,x) \ + u = star_x(x); \ + v = star_x(u); \ + w = star_x(v); \ + t = w ^ (x); \ + (y) = u ^ v ^ w; \ + (y) ^= rotr(u ^ t, 8) ^ \ + rotr(v ^ t, 16) ^ \ + rotr(t,24) + +/* initialise the key schedule from the user supplied key */ + +#define loop4(i) \ +{ t = rotr(t, 8); t = ls_box(t) ^ rco_tab[i]; \ + t ^= E_KEY[4 * i]; E_KEY[4 * i + 4] = t; \ + t ^= E_KEY[4 * i + 1]; E_KEY[4 * i + 5] = t; \ + t ^= E_KEY[4 * i + 2]; E_KEY[4 * i + 6] = t; \ + t ^= E_KEY[4 * i + 3]; E_KEY[4 * i + 7] = t; \ +} + +#define loop6(i) \ +{ t = rotr(t, 8); t = ls_box(t) ^ rco_tab[i]; \ + t ^= E_KEY[6 * i]; E_KEY[6 * i + 6] = t; \ + t ^= E_KEY[6 * i + 1]; E_KEY[6 * i + 7] = t; \ + t ^= E_KEY[6 * i + 2]; E_KEY[6 * i + 8] = t; \ + t ^= E_KEY[6 * i + 3]; E_KEY[6 * i + 9] = t; \ + t ^= E_KEY[6 * i + 4]; E_KEY[6 * i + 10] = t; \ + t ^= E_KEY[6 * i + 5]; E_KEY[6 * i + 11] = t; \ +} + +#define loop8(i) \ +{ t = rotr(t, 8); ; t = ls_box(t) ^ rco_tab[i]; \ + t ^= E_KEY[8 * i]; E_KEY[8 * i + 8] = t; \ + t ^= E_KEY[8 * i + 1]; E_KEY[8 * i + 9] = t; \ + t ^= E_KEY[8 * i + 2]; E_KEY[8 * i + 10] = t; \ + t ^= E_KEY[8 * i + 3]; E_KEY[8 * i + 11] = t; \ + t = E_KEY[8 * i + 4] ^ ls_box(t); \ + E_KEY[8 * i + 12] = t; \ + t ^= E_KEY[8 * i + 5]; E_KEY[8 * i + 13] = t; \ + t ^= E_KEY[8 * i + 6]; E_KEY[8 * i + 14] = t; \ + t ^= E_KEY[8 * i + 7]; E_KEY[8 * i + 15] = t; \ +} + +static int +aes_set_key(void *ctx_arg, const u8 *in_key, unsigned int key_len, u32 *flags) +{ + struct aes_ctx *ctx = ctx_arg; + u32 i, t, u, v, w; + + if (key_len != 16 && key_len != 24 && key_len != 32) { + *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; + return -EINVAL; + } + + ctx->key_length = key_len; + + E_KEY[0] = u32_in (in_key); + E_KEY[1] = u32_in (in_key + 4); + E_KEY[2] = u32_in (in_key + 8); + E_KEY[3] = u32_in (in_key + 12); + + switch (key_len) { + case 16: + t = E_KEY[3]; + for (i = 0; i < 10; ++i) + loop4 (i); + break; + + case 24: + E_KEY[4] = u32_in (in_key + 16); + t = E_KEY[5] = u32_in (in_key + 20); + for (i = 0; i < 8; ++i) + loop6 (i); + break; + + case 32: + E_KEY[4] = u32_in (in_key + 16); + E_KEY[5] = u32_in (in_key + 20); + E_KEY[6] = u32_in (in_key + 24); + t = E_KEY[7] = u32_in (in_key + 28); + for (i = 0; i < 7; ++i) + loop8 (i); + break; + } + + D_KEY[0] = E_KEY[0]; + D_KEY[1] = E_KEY[1]; + D_KEY[2] = E_KEY[2]; + D_KEY[3] = E_KEY[3]; + + for (i = 4; i < key_len + 24; ++i) { + imix_col (D_KEY[i], E_KEY[i]); + } + + return 0; +} + +/* encrypt a block of text */ + +#define f_nround(bo, bi, k) \ + f_rn(bo, bi, 0, k); \ + f_rn(bo, bi, 1, k); \ + f_rn(bo, bi, 2, k); \ + f_rn(bo, bi, 3, k); \ + k += 4 + +#define f_lround(bo, bi, k) \ + f_rl(bo, bi, 0, k); \ + f_rl(bo, bi, 1, k); \ + f_rl(bo, bi, 2, k); \ + f_rl(bo, bi, 3, k) + +static void aes_encrypt(void *ctx_arg, u8 *out, const u8 *in) +{ + const struct aes_ctx *ctx = ctx_arg; + u32 b0[4], b1[4]; + const u32 *kp = E_KEY + 4; + + b0[0] = u32_in (in) ^ E_KEY[0]; + b0[1] = u32_in (in + 4) ^ E_KEY[1]; + b0[2] = u32_in (in + 8) ^ E_KEY[2]; + b0[3] = u32_in (in + 12) ^ E_KEY[3]; + + if (ctx->key_length > 24) { + f_nround (b1, b0, kp); + f_nround (b0, b1, kp); + } + + if (ctx->key_length > 16) { + f_nround (b1, b0, kp); + f_nround (b0, b1, kp); + } + + f_nround (b1, b0, kp); + f_nround (b0, b1, kp); + f_nround (b1, b0, kp); + f_nround (b0, b1, kp); + f_nround (b1, b0, kp); + f_nround (b0, b1, kp); + f_nround (b1, b0, kp); + f_nround (b0, b1, kp); + f_nround (b1, b0, kp); + f_lround (b0, b1, kp); + + u32_out (out, b0[0]); + u32_out (out + 4, b0[1]); + u32_out (out + 8, b0[2]); + u32_out (out + 12, b0[3]); +} + +/* decrypt a block of text */ + +#define i_nround(bo, bi, k) \ + i_rn(bo, bi, 0, k); \ + i_rn(bo, bi, 1, k); \ + i_rn(bo, bi, 2, k); \ + i_rn(bo, bi, 3, k); \ + k -= 4 + +#define i_lround(bo, bi, k) \ + i_rl(bo, bi, 0, k); \ + i_rl(bo, bi, 1, k); \ + i_rl(bo, bi, 2, k); \ + i_rl(bo, bi, 3, k) + +static void aes_decrypt(void *ctx_arg, u8 *out, const u8 *in) +{ + const struct aes_ctx *ctx = ctx_arg; + u32 b0[4], b1[4]; + const int key_len = ctx->key_length; + const u32 *kp = D_KEY + key_len + 20; + + b0[0] = u32_in (in) ^ E_KEY[key_len + 24]; + b0[1] = u32_in (in + 4) ^ E_KEY[key_len + 25]; + b0[2] = u32_in (in + 8) ^ E_KEY[key_len + 26]; + b0[3] = u32_in (in + 12) ^ E_KEY[key_len + 27]; + + if (key_len > 24) { + i_nround (b1, b0, kp); + i_nround (b0, b1, kp); + } + + if (key_len > 16) { + i_nround (b1, b0, kp); + i_nround (b0, b1, kp); + } + + i_nround (b1, b0, kp); + i_nround (b0, b1, kp); + i_nround (b1, b0, kp); + i_nround (b0, b1, kp); + i_nround (b1, b0, kp); + i_nround (b0, b1, kp); + i_nround (b1, b0, kp); + i_nround (b0, b1, kp); + i_nround (b1, b0, kp); + i_lround (b0, b1, kp); + + u32_out (out, b0[0]); + u32_out (out + 4, b0[1]); + u32_out (out + 8, b0[2]); + u32_out (out + 12, b0[3]); +} + + +static struct crypto_alg aes_alg = { + .cra_name = "aes", + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct aes_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(aes_alg.cra_list), + .cra_u = { + .cipher = { + .cia_min_keysize = AES_MIN_KEY_SIZE, + .cia_max_keysize = AES_MAX_KEY_SIZE, + .cia_setkey = aes_set_key, + .cia_encrypt = aes_encrypt, + .cia_decrypt = aes_decrypt + } + } +}; + +static int __init aes_init(void) +{ + gen_tabs(); + return crypto_register_alg(&aes_alg); +} + +static void __exit aes_fini(void) +{ + crypto_unregister_alg(&aes_alg); +} + +module_init(aes_init); +module_exit(aes_fini); + +MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm"); +MODULE_LICENSE("Dual BSD/GPL"); + diff --git a/drivers/staging/rtl8192su/ieee80211/api.c b/drivers/staging/rtl8192su/ieee80211/api.c new file mode 100644 index 000000000000..c627d029528b --- /dev/null +++ b/drivers/staging/rtl8192su/ieee80211/api.c @@ -0,0 +1,246 @@ +/* + * Scatterlist Cryptographic API. + * + * Copyright (c) 2002 James Morris + * Copyright (c) 2002 David S. Miller (davem@redhat.com) + * + * Portions derived from Cryptoapi, by Alexander Kjeldaas + * and Nettle, by Niels Mé°ˆler. + * + * 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 "kmap_types.h" + +#include +#include +//#include +#include "rtl_crypto.h" +#include +#include +#include +#include "internal.h" + +LIST_HEAD(crypto_alg_list); +DECLARE_RWSEM(crypto_alg_sem); + +static inline int crypto_alg_get(struct crypto_alg *alg) +{ + return try_inc_mod_count(alg->cra_module); +} + +static inline void crypto_alg_put(struct crypto_alg *alg) +{ + if (alg->cra_module) + __MOD_DEC_USE_COUNT(alg->cra_module); +} + +struct crypto_alg *crypto_alg_lookup(const char *name) +{ + struct crypto_alg *q, *alg = NULL; + + if (!name) + return NULL; + + down_read(&crypto_alg_sem); + + list_for_each_entry(q, &crypto_alg_list, cra_list) { + if (!(strcmp(q->cra_name, name))) { + if (crypto_alg_get(q)) + alg = q; + break; + } + } + + up_read(&crypto_alg_sem); + return alg; +} + +static int crypto_init_flags(struct crypto_tfm *tfm, u32 flags) +{ + tfm->crt_flags = 0; + + switch (crypto_tfm_alg_type(tfm)) { + case CRYPTO_ALG_TYPE_CIPHER: + return crypto_init_cipher_flags(tfm, flags); + + case CRYPTO_ALG_TYPE_DIGEST: + return crypto_init_digest_flags(tfm, flags); + + case CRYPTO_ALG_TYPE_COMPRESS: + return crypto_init_compress_flags(tfm, flags); + + default: + break; + } + + BUG(); + return -EINVAL; +} + +static int crypto_init_ops(struct crypto_tfm *tfm) +{ + switch (crypto_tfm_alg_type(tfm)) { + case CRYPTO_ALG_TYPE_CIPHER: + return crypto_init_cipher_ops(tfm); + + case CRYPTO_ALG_TYPE_DIGEST: + return crypto_init_digest_ops(tfm); + + case CRYPTO_ALG_TYPE_COMPRESS: + return crypto_init_compress_ops(tfm); + + default: + break; + } + + BUG(); + return -EINVAL; +} + +static void crypto_exit_ops(struct crypto_tfm *tfm) +{ + switch (crypto_tfm_alg_type(tfm)) { + case CRYPTO_ALG_TYPE_CIPHER: + crypto_exit_cipher_ops(tfm); + break; + + case CRYPTO_ALG_TYPE_DIGEST: + crypto_exit_digest_ops(tfm); + break; + + case CRYPTO_ALG_TYPE_COMPRESS: + crypto_exit_compress_ops(tfm); + break; + + default: + BUG(); + + } +} + +struct crypto_tfm *crypto_alloc_tfm(const char *name, u32 flags) +{ + struct crypto_tfm *tfm = NULL; + struct crypto_alg *alg; + + alg = crypto_alg_mod_lookup(name); + if (alg == NULL) + goto out; + + tfm = kmalloc(sizeof(*tfm) + alg->cra_ctxsize, GFP_KERNEL); + if (tfm == NULL) + goto out_put; + + memset(tfm, 0, sizeof(*tfm) + alg->cra_ctxsize); + + tfm->__crt_alg = alg; + + if (crypto_init_flags(tfm, flags)) + goto out_free_tfm; + + if (crypto_init_ops(tfm)) { + crypto_exit_ops(tfm); + goto out_free_tfm; + } + + goto out; + +out_free_tfm: + kfree(tfm); + tfm = NULL; +out_put: + crypto_alg_put(alg); +out: + return tfm; +} + +void crypto_free_tfm(struct crypto_tfm *tfm) +{ + struct crypto_alg *alg = tfm->__crt_alg; + int size = sizeof(*tfm) + alg->cra_ctxsize; + + crypto_exit_ops(tfm); + crypto_alg_put(alg); + memset(tfm, 0, size); + kfree(tfm); +} + +int crypto_register_alg(struct crypto_alg *alg) +{ + int ret = 0; + struct crypto_alg *q; + + down_write(&crypto_alg_sem); + + list_for_each_entry(q, &crypto_alg_list, cra_list) { + if (!(strcmp(q->cra_name, alg->cra_name))) { + ret = -EEXIST; + goto out; + } + } + + list_add_tail(&alg->cra_list, &crypto_alg_list); +out: + up_write(&crypto_alg_sem); + return ret; +} + +int crypto_unregister_alg(struct crypto_alg *alg) +{ + int ret = -ENOENT; + struct crypto_alg *q; + + BUG_ON(!alg->cra_module); + + down_write(&crypto_alg_sem); + list_for_each_entry(q, &crypto_alg_list, cra_list) { + if (alg == q) { + list_del(&alg->cra_list); + ret = 0; + goto out; + } + } +out: + up_write(&crypto_alg_sem); + return ret; +} + +int crypto_alg_available(const char *name, u32 flags) +{ + int ret = 0; + struct crypto_alg *alg = crypto_alg_mod_lookup(name); + + if (alg) { + crypto_alg_put(alg); + ret = 1; + } + + return ret; +} + +static int __init init_crypto(void) +{ + printk(KERN_INFO "Initializing Cryptographic API\n"); + crypto_init_proc(); + return 0; +} + +__initcall(init_crypto); + +/* +EXPORT_SYMBOL_GPL(crypto_register_alg); +EXPORT_SYMBOL_GPL(crypto_unregister_alg); +EXPORT_SYMBOL_GPL(crypto_alloc_tfm); +EXPORT_SYMBOL_GPL(crypto_free_tfm); +EXPORT_SYMBOL_GPL(crypto_alg_available); +*/ + +EXPORT_SYMBOL_NOVERS(crypto_register_alg); +EXPORT_SYMBOL_NOVERS(crypto_unregister_alg); +EXPORT_SYMBOL_NOVERS(crypto_alloc_tfm); +EXPORT_SYMBOL_NOVERS(crypto_free_tfm); +EXPORT_SYMBOL_NOVERS(crypto_alg_available); diff --git a/drivers/staging/rtl8192su/ieee80211/arc4.c b/drivers/staging/rtl8192su/ieee80211/arc4.c new file mode 100644 index 000000000000..e408472af305 --- /dev/null +++ b/drivers/staging/rtl8192su/ieee80211/arc4.c @@ -0,0 +1,103 @@ +/* + * Cryptographic API + * + * ARC4 Cipher Algorithm + * + * Jon Oberheide + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ +#include +#include +#include "rtl_crypto.h" + +#define ARC4_MIN_KEY_SIZE 1 +#define ARC4_MAX_KEY_SIZE 256 +#define ARC4_BLOCK_SIZE 1 + +struct arc4_ctx { + u8 S[256]; + u8 x, y; +}; + +static int arc4_set_key(void *ctx_arg, const u8 *in_key, unsigned int key_len, u32 *flags) +{ + struct arc4_ctx *ctx = ctx_arg; + int i, j = 0, k = 0; + + ctx->x = 1; + ctx->y = 0; + + for(i = 0; i < 256; i++) + ctx->S[i] = i; + + for(i = 0; i < 256; i++) + { + u8 a = ctx->S[i]; + j = (j + in_key[k] + a) & 0xff; + ctx->S[i] = ctx->S[j]; + ctx->S[j] = a; + if((unsigned int)++k >= key_len) + k = 0; + } + + return 0; +} + +static void arc4_crypt(void *ctx_arg, u8 *out, const u8 *in) +{ + struct arc4_ctx *ctx = ctx_arg; + + u8 *const S = ctx->S; + u8 x = ctx->x; + u8 y = ctx->y; + u8 a, b; + + a = S[x]; + y = (y + a) & 0xff; + b = S[y]; + S[x] = b; + S[y] = a; + x = (x + 1) & 0xff; + *out++ = *in ^ S[(a + b) & 0xff]; + + ctx->x = x; + ctx->y = y; +} + +static struct crypto_alg arc4_alg = { + .cra_name = "arc4", + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = ARC4_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct arc4_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(arc4_alg.cra_list), + .cra_u = { .cipher = { + .cia_min_keysize = ARC4_MIN_KEY_SIZE, + .cia_max_keysize = ARC4_MAX_KEY_SIZE, + .cia_setkey = arc4_set_key, + .cia_encrypt = arc4_crypt, + .cia_decrypt = arc4_crypt } } +}; + +static int __init arc4_init(void) +{ + return crypto_register_alg(&arc4_alg); +} + + +static void __exit arc4_exit(void) +{ + crypto_unregister_alg(&arc4_alg); +} + +module_init(arc4_init); +module_exit(arc4_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("ARC4 Cipher Algorithm"); +MODULE_AUTHOR("Jon Oberheide "); diff --git a/drivers/staging/rtl8192su/ieee80211/autoload.c b/drivers/staging/rtl8192su/ieee80211/autoload.c new file mode 100644 index 000000000000..c97756f3b2ea --- /dev/null +++ b/drivers/staging/rtl8192su/ieee80211/autoload.c @@ -0,0 +1,40 @@ +/* + * Cryptographic API. + * + * Algorithm autoloader. + * + * Copyright (c) 2002 James Morris + * + * 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 "kmap_types.h" + +#include +//#include +#include "rtl_crypto.h" +#include +#include +#include "internal.h" + +/* + * A far more intelligent version of this is planned. For now, just + * try an exact match on the name of the algorithm. + */ +void crypto_alg_autoload(const char *name) +{ + request_module(name); +} + +struct crypto_alg *crypto_alg_mod_lookup(const char *name) +{ + struct crypto_alg *alg = crypto_alg_lookup(name); + if (alg == NULL) { + crypto_alg_autoload(name); + alg = crypto_alg_lookup(name); + } + return alg; +} diff --git a/drivers/staging/rtl8192su/ieee80211/cipher.c b/drivers/staging/rtl8192su/ieee80211/cipher.c new file mode 100644 index 000000000000..1968acfe32b1 --- /dev/null +++ b/drivers/staging/rtl8192su/ieee80211/cipher.c @@ -0,0 +1,299 @@ +/* + * Cryptographic API. + * + * Cipher operations. + * + * Copyright (c) 2002 James Morris + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ +#include +//#include +#include "rtl_crypto.h" +#include +#include +#include +#include +#include "internal.h" +#include "scatterwalk.h" + +typedef void (cryptfn_t)(void *, u8 *, const u8 *); +typedef void (procfn_t)(struct crypto_tfm *, u8 *, + u8*, cryptfn_t, int enc, void *, int); + +static inline void xor_64(u8 *a, const u8 *b) +{ + ((u32 *)a)[0] ^= ((u32 *)b)[0]; + ((u32 *)a)[1] ^= ((u32 *)b)[1]; +} + +static inline void xor_128(u8 *a, const u8 *b) +{ + ((u32 *)a)[0] ^= ((u32 *)b)[0]; + ((u32 *)a)[1] ^= ((u32 *)b)[1]; + ((u32 *)a)[2] ^= ((u32 *)b)[2]; + ((u32 *)a)[3] ^= ((u32 *)b)[3]; +} + + +/* + * Generic encrypt/decrypt wrapper for ciphers, handles operations across + * multiple page boundaries by using temporary blocks. In user context, + * the kernel is given a chance to schedule us once per block. + */ +static int crypt(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes, cryptfn_t crfn, + procfn_t prfn, int enc, void *info) +{ + struct scatter_walk walk_in, walk_out; + const unsigned int bsize = crypto_tfm_alg_blocksize(tfm); + u8 tmp_src[bsize]; + u8 tmp_dst[bsize]; + + if (!nbytes) + return 0; + + if (nbytes % bsize) { + tfm->crt_flags |= CRYPTO_TFM_RES_BAD_BLOCK_LEN; + return -EINVAL; + } + + scatterwalk_start(&walk_in, src); + scatterwalk_start(&walk_out, dst); + + for(;;) { + u8 *src_p, *dst_p; + int in_place; + + scatterwalk_map(&walk_in, 0); + scatterwalk_map(&walk_out, 1); + src_p = scatterwalk_whichbuf(&walk_in, bsize, tmp_src); + dst_p = scatterwalk_whichbuf(&walk_out, bsize, tmp_dst); + in_place = scatterwalk_samebuf(&walk_in, &walk_out, + src_p, dst_p); + + nbytes -= bsize; + + scatterwalk_copychunks(src_p, &walk_in, bsize, 0); + + prfn(tfm, dst_p, src_p, crfn, enc, info, in_place); + + scatterwalk_done(&walk_in, 0, nbytes); + + scatterwalk_copychunks(dst_p, &walk_out, bsize, 1); + scatterwalk_done(&walk_out, 1, nbytes); + + if (!nbytes) + return 0; + + crypto_yield(tfm); + } +} + +static void cbc_process(struct crypto_tfm *tfm, u8 *dst, u8 *src, + cryptfn_t fn, int enc, void *info, int in_place) +{ + u8 *iv = info; + + /* Null encryption */ + if (!iv) + return; + + if (enc) { + tfm->crt_u.cipher.cit_xor_block(iv, src); + fn(crypto_tfm_ctx(tfm), dst, iv); + memcpy(iv, dst, crypto_tfm_alg_blocksize(tfm)); + } else { + u8 stack[in_place ? crypto_tfm_alg_blocksize(tfm) : 0]; + u8 *buf = in_place ? stack : dst; + + fn(crypto_tfm_ctx(tfm), buf, src); + tfm->crt_u.cipher.cit_xor_block(buf, iv); + memcpy(iv, src, crypto_tfm_alg_blocksize(tfm)); + if (buf != dst) + memcpy(dst, buf, crypto_tfm_alg_blocksize(tfm)); + } +} + +static void ecb_process(struct crypto_tfm *tfm, u8 *dst, u8 *src, + cryptfn_t fn, int enc, void *info, int in_place) +{ + fn(crypto_tfm_ctx(tfm), dst, src); +} + +static int setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen) +{ + struct cipher_alg *cia = &tfm->__crt_alg->cra_cipher; + + if (keylen < cia->cia_min_keysize || keylen > cia->cia_max_keysize) { + tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; + return -EINVAL; + } else + return cia->cia_setkey(crypto_tfm_ctx(tfm), key, keylen, + &tfm->crt_flags); +} + +static int ecb_encrypt(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + return crypt(tfm, dst, src, nbytes, + tfm->__crt_alg->cra_cipher.cia_encrypt, + ecb_process, 1, NULL); +} + +static int ecb_decrypt(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes) +{ + return crypt(tfm, dst, src, nbytes, + tfm->__crt_alg->cra_cipher.cia_decrypt, + ecb_process, 1, NULL); +} + +static int cbc_encrypt(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes) +{ + return crypt(tfm, dst, src, nbytes, + tfm->__crt_alg->cra_cipher.cia_encrypt, + cbc_process, 1, tfm->crt_cipher.cit_iv); +} + +static int cbc_encrypt_iv(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes, u8 *iv) +{ + return crypt(tfm, dst, src, nbytes, + tfm->__crt_alg->cra_cipher.cia_encrypt, + cbc_process, 1, iv); +} + +static int cbc_decrypt(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes) +{ + return crypt(tfm, dst, src, nbytes, + tfm->__crt_alg->cra_cipher.cia_decrypt, + cbc_process, 0, tfm->crt_cipher.cit_iv); +} + +static int cbc_decrypt_iv(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes, u8 *iv) +{ + return crypt(tfm, dst, src, nbytes, + tfm->__crt_alg->cra_cipher.cia_decrypt, + cbc_process, 0, iv); +} + +static int nocrypt(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes) +{ + return -ENOSYS; +} + +static int nocrypt_iv(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes, u8 *iv) +{ + return -ENOSYS; +} + +int crypto_init_cipher_flags(struct crypto_tfm *tfm, u32 flags) +{ + u32 mode = flags & CRYPTO_TFM_MODE_MASK; + + tfm->crt_cipher.cit_mode = mode ? mode : CRYPTO_TFM_MODE_ECB; + if (flags & CRYPTO_TFM_REQ_WEAK_KEY) + tfm->crt_flags = CRYPTO_TFM_REQ_WEAK_KEY; + + return 0; +} + +int crypto_init_cipher_ops(struct crypto_tfm *tfm) +{ + int ret = 0; + struct cipher_tfm *ops = &tfm->crt_cipher; + + ops->cit_setkey = setkey; + + switch (tfm->crt_cipher.cit_mode) { + case CRYPTO_TFM_MODE_ECB: + ops->cit_encrypt = ecb_encrypt; + ops->cit_decrypt = ecb_decrypt; + break; + + case CRYPTO_TFM_MODE_CBC: + ops->cit_encrypt = cbc_encrypt; + ops->cit_decrypt = cbc_decrypt; + ops->cit_encrypt_iv = cbc_encrypt_iv; + ops->cit_decrypt_iv = cbc_decrypt_iv; + break; + + case CRYPTO_TFM_MODE_CFB: + ops->cit_encrypt = nocrypt; + ops->cit_decrypt = nocrypt; + ops->cit_encrypt_iv = nocrypt_iv; + ops->cit_decrypt_iv = nocrypt_iv; + break; + + case CRYPTO_TFM_MODE_CTR: + ops->cit_encrypt = nocrypt; + ops->cit_decrypt = nocrypt; + ops->cit_encrypt_iv = nocrypt_iv; + ops->cit_decrypt_iv = nocrypt_iv; + break; + + default: + BUG(); + } + + if (ops->cit_mode == CRYPTO_TFM_MODE_CBC) { + + switch (crypto_tfm_alg_blocksize(tfm)) { + case 8: + ops->cit_xor_block = xor_64; + break; + + case 16: + ops->cit_xor_block = xor_128; + break; + + default: + printk(KERN_WARNING "%s: block size %u not supported\n", + crypto_tfm_alg_name(tfm), + crypto_tfm_alg_blocksize(tfm)); + ret = -EINVAL; + goto out; + } + + ops->cit_ivsize = crypto_tfm_alg_blocksize(tfm); + ops->cit_iv = kmalloc(ops->cit_ivsize, GFP_KERNEL); + if (ops->cit_iv == NULL) + ret = -ENOMEM; + } + +out: + return ret; +} + +void crypto_exit_cipher_ops(struct crypto_tfm *tfm) +{ + if (tfm->crt_cipher.cit_iv) + kfree(tfm->crt_cipher.cit_iv); +} diff --git a/drivers/staging/rtl8192su/ieee80211/compress.c b/drivers/staging/rtl8192su/ieee80211/compress.c new file mode 100644 index 000000000000..c2df80e2ed9d --- /dev/null +++ b/drivers/staging/rtl8192su/ieee80211/compress.c @@ -0,0 +1,64 @@ +/* + * Cryptographic API. + * + * Compression operations. + * + * Copyright (c) 2002 James Morris + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ +#include +//#include +#include "rtl_crypto.h" +#include +#include +#include +#include "internal.h" + +static int crypto_compress(struct crypto_tfm *tfm, + const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen) +{ + return tfm->__crt_alg->cra_compress.coa_compress(crypto_tfm_ctx(tfm), + src, slen, dst, + dlen); +} + +static int crypto_decompress(struct crypto_tfm *tfm, + const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen) +{ + return tfm->__crt_alg->cra_compress.coa_decompress(crypto_tfm_ctx(tfm), + src, slen, dst, + dlen); +} + +int crypto_init_compress_flags(struct crypto_tfm *tfm, u32 flags) +{ + return flags ? -EINVAL : 0; +} + +int crypto_init_compress_ops(struct crypto_tfm *tfm) +{ + int ret = 0; + struct compress_tfm *ops = &tfm->crt_compress; + + ret = tfm->__crt_alg->cra_compress.coa_init(crypto_tfm_ctx(tfm)); + if (ret) + goto out; + + ops->cot_compress = crypto_compress; + ops->cot_decompress = crypto_decompress; + +out: + return ret; +} + +void crypto_exit_compress_ops(struct crypto_tfm *tfm) +{ + tfm->__crt_alg->cra_compress.coa_exit(crypto_tfm_ctx(tfm)); +} diff --git a/drivers/staging/rtl8192su/ieee80211/crypto_compat.h b/drivers/staging/rtl8192su/ieee80211/crypto_compat.h new file mode 100644 index 000000000000..587e8bb2db6a --- /dev/null +++ b/drivers/staging/rtl8192su/ieee80211/crypto_compat.h @@ -0,0 +1,90 @@ +/* + * Header file to maintain compatibility among different kernel versions. + * + * Copyright (c) 2004-2006 + * + * 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. See README and COPYING for + * more details. + */ + +#include + +static inline int crypto_cipher_encrypt(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); + return tfm->crt_cipher.cit_encrypt(tfm, dst, src, nbytes); +} + + +static inline int crypto_cipher_decrypt(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); + return tfm->crt_cipher.cit_decrypt(tfm, dst, src, nbytes); +} + +#if 0 +/* + * crypto_free_tfm - Free crypto transform + * @tfm: Transform to free + * + * crypto_free_tfm() frees up the transform and any associated resources, + * then drops the refcount on the associated algorithm. + */ +void crypto_free_tfm(struct crypto_tfm *tfm) +{ + struct crypto_alg *alg; + int size; + + if (unlikely(!tfm)) + return; + + alg = tfm->__crt_alg; + size = sizeof(*tfm) + alg->cra_ctxsize; + + if (alg->cra_exit) + alg->cra_exit(tfm); + crypto_exit_ops(tfm); + crypto_mod_put(alg); + memset(tfm, 0, size); + kfree(tfm); +} + +#endif +#if 1 + struct crypto_tfm *crypto_alloc_tfm(const char *name, u32 flags) +{ + struct crypto_tfm *tfm = NULL; + int err; + printk("call crypto_alloc_tfm!!!\n"); + do { + struct crypto_alg *alg; + + alg = crypto_alg_mod_lookup(name, 0, CRYPTO_ALG_ASYNC); + err = PTR_ERR(alg); + if (IS_ERR(alg)) + continue; + + tfm = __crypto_alloc_tfm(alg, flags); + err = 0; + if (IS_ERR(tfm)) { + crypto_mod_put(alg); + err = PTR_ERR(tfm); + tfm = NULL; + } + } while (err == -EAGAIN && !signal_pending(current)); + + return tfm; +} +#endif +//EXPORT_SYMBOL_GPL(crypto_alloc_tfm); +//EXPORT_SYMBOL_GPL(crypto_free_tfm); + + diff --git a/drivers/staging/rtl8192su/ieee80211/digest.c b/drivers/staging/rtl8192su/ieee80211/digest.c new file mode 100644 index 000000000000..1a95f2d37837 --- /dev/null +++ b/drivers/staging/rtl8192su/ieee80211/digest.c @@ -0,0 +1,108 @@ +/* + * Cryptographic API. + * + * Digest operations. + * + * Copyright (c) 2002 James Morris + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ +//#include +#include "rtl_crypto.h" +#include +#include +#include +#include +#include "internal.h" + +static void init(struct crypto_tfm *tfm) +{ + tfm->__crt_alg->cra_digest.dia_init(crypto_tfm_ctx(tfm)); +} + +static void update(struct crypto_tfm *tfm, + struct scatterlist *sg, unsigned int nsg) +{ + unsigned int i; + + for (i = 0; i < nsg; i++) { + + struct page *pg = sg[i].page; + unsigned int offset = sg[i].offset; + unsigned int l = sg[i].length; + + do { + unsigned int bytes_from_page = min(l, ((unsigned int) + (PAGE_SIZE)) - + offset); + char *p = crypto_kmap(pg, 0) + offset; + + tfm->__crt_alg->cra_digest.dia_update + (crypto_tfm_ctx(tfm), p, + bytes_from_page); + crypto_kunmap(p, 0); + crypto_yield(tfm); + offset = 0; + pg++; + l -= bytes_from_page; + } while (l > 0); + } +} + +static void final(struct crypto_tfm *tfm, u8 *out) +{ + tfm->__crt_alg->cra_digest.dia_final(crypto_tfm_ctx(tfm), out); +} + +static int setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen) +{ + u32 flags; + if (tfm->__crt_alg->cra_digest.dia_setkey == NULL) + return -ENOSYS; + return tfm->__crt_alg->cra_digest.dia_setkey(crypto_tfm_ctx(tfm), + key, keylen, &flags); +} + +static void digest(struct crypto_tfm *tfm, + struct scatterlist *sg, unsigned int nsg, u8 *out) +{ + unsigned int i; + + tfm->crt_digest.dit_init(tfm); + + for (i = 0; i < nsg; i++) { + char *p = crypto_kmap(sg[i].page, 0) + sg[i].offset; + tfm->__crt_alg->cra_digest.dia_update(crypto_tfm_ctx(tfm), + p, sg[i].length); + crypto_kunmap(p, 0); + crypto_yield(tfm); + } + crypto_digest_final(tfm, out); +} + +int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags) +{ + return flags ? -EINVAL : 0; +} + +int crypto_init_digest_ops(struct crypto_tfm *tfm) +{ + struct digest_tfm *ops = &tfm->crt_digest; + + ops->dit_init = init; + ops->dit_update = update; + ops->dit_final = final; + ops->dit_digest = digest; + ops->dit_setkey = setkey; + + return crypto_alloc_hmac_block(tfm); +} + +void crypto_exit_digest_ops(struct crypto_tfm *tfm) +{ + crypto_free_hmac_block(tfm); +} diff --git a/drivers/staging/rtl8192su/ieee80211/dot11d.c b/drivers/staging/rtl8192su/ieee80211/dot11d.c new file mode 100644 index 000000000000..e5f2dedc4372 --- /dev/null +++ b/drivers/staging/rtl8192su/ieee80211/dot11d.c @@ -0,0 +1,239 @@ +#ifdef ENABLE_DOT11D +//----------------------------------------------------------------------------- +// File: +// Dot11d.c +// +// Description: +// Implement 802.11d. +// +//----------------------------------------------------------------------------- + +#include "dot11d.h" + +void +Dot11d_Init(struct ieee80211_device *ieee) +{ + PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(ieee); + + pDot11dInfo->bEnabled = 0; + + pDot11dInfo->State = DOT11D_STATE_NONE; + pDot11dInfo->CountryIeLen = 0; + memset(pDot11dInfo->channel_map, 0, MAX_CHANNEL_NUMBER+1); + memset(pDot11dInfo->MaxTxPwrDbmList, 0xFF, MAX_CHANNEL_NUMBER+1); + RESET_CIE_WATCHDOG(ieee); + + printk("Dot11d_Init()\n"); +} + +// +// Description: +// Reset to the state as we are just entering a regulatory domain. +// +void +Dot11d_Reset(struct ieee80211_device *ieee) +{ + u32 i; + PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(ieee); +#if 0 + if(!pDot11dInfo->bEnabled) + return; +#endif + // Clear old channel map + memset(pDot11dInfo->channel_map, 0, MAX_CHANNEL_NUMBER+1); + memset(pDot11dInfo->MaxTxPwrDbmList, 0xFF, MAX_CHANNEL_NUMBER+1); + // Set new channel map + for (i=1; i<=11; i++) { + (pDot11dInfo->channel_map)[i] = 1; + } + for (i=12; i<=14; i++) { + (pDot11dInfo->channel_map)[i] = 2; + } + + pDot11dInfo->State = DOT11D_STATE_NONE; + pDot11dInfo->CountryIeLen = 0; + RESET_CIE_WATCHDOG(ieee); + + //printk("Dot11d_Reset()\n"); +} + +// +// Description: +// Update country IE from Beacon or Probe Resopnse +// and configure PHY for operation in the regulatory domain. +// +// TODO: +// Configure Tx power. +// +// Assumption: +// 1. IS_DOT11D_ENABLE() is TRUE. +// 2. Input IE is an valid one. +// +void +Dot11d_UpdateCountryIe( + struct ieee80211_device *dev, + u8 * pTaddr, + u16 CoutryIeLen, + u8 * pCoutryIe + ) +{ + PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev); + u8 i, j, NumTriples, MaxChnlNum; + PCHNL_TXPOWER_TRIPLE pTriple; + + memset(pDot11dInfo->channel_map, 0, MAX_CHANNEL_NUMBER+1); + memset(pDot11dInfo->MaxTxPwrDbmList, 0xFF, MAX_CHANNEL_NUMBER+1); + MaxChnlNum = 0; + NumTriples = (CoutryIeLen - 3) / 3; // skip 3-byte country string. + pTriple = (PCHNL_TXPOWER_TRIPLE)(pCoutryIe + 3); + for(i = 0; i < NumTriples; i++) + { + if(MaxChnlNum >= pTriple->FirstChnl) + { // It is not in a monotonically increasing order, so stop processing. + printk("Dot11d_UpdateCountryIe(): Invalid country IE, skip it........1\n"); + return; + } + if(MAX_CHANNEL_NUMBER < (pTriple->FirstChnl + pTriple->NumChnls)) + { // It is not a valid set of channel id, so stop processing. + printk("Dot11d_UpdateCountryIe(): Invalid country IE, skip it........2\n"); + return; + } + + for(j = 0 ; j < pTriple->NumChnls; j++) + { + pDot11dInfo->channel_map[pTriple->FirstChnl + j] = 1; + pDot11dInfo->MaxTxPwrDbmList[pTriple->FirstChnl + j] = pTriple->MaxTxPowerInDbm; + MaxChnlNum = pTriple->FirstChnl + j; + } + + pTriple = (PCHNL_TXPOWER_TRIPLE)((u8*)pTriple + 3); + } +#if 1 + //printk("Dot11d_UpdateCountryIe(): Channel List:\n"); + printk("Channel List:"); + for(i=1; i<= MAX_CHANNEL_NUMBER; i++) + if(pDot11dInfo->channel_map[i] > 0) + printk(" %d", i); + printk("\n"); +#endif + + UPDATE_CIE_SRC(dev, pTaddr); + + pDot11dInfo->CountryIeLen = CoutryIeLen; + memcpy(pDot11dInfo->CountryIeBuf, pCoutryIe,CoutryIeLen); + pDot11dInfo->State = DOT11D_STATE_LEARNED; +} + + +u8 +DOT11D_GetMaxTxPwrInDbm( + struct ieee80211_device *dev, + u8 Channel + ) +{ + PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev); + u8 MaxTxPwrInDbm = 255; + + if(MAX_CHANNEL_NUMBER < Channel) + { + printk("DOT11D_GetMaxTxPwrInDbm(): Invalid Channel\n"); + return MaxTxPwrInDbm; + } + if(pDot11dInfo->channel_map[Channel]) + { + MaxTxPwrInDbm = pDot11dInfo->MaxTxPwrDbmList[Channel]; + } + + return MaxTxPwrInDbm; +} + + +void +DOT11D_ScanComplete( + struct ieee80211_device * dev + ) +{ + PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev); + + switch(pDot11dInfo->State) + { + case DOT11D_STATE_LEARNED: + pDot11dInfo->State = DOT11D_STATE_DONE; + break; + + case DOT11D_STATE_DONE: + if( GET_CIE_WATCHDOG(dev) == 0 ) + { // Reset country IE if previous one is gone. + Dot11d_Reset(dev); + } + break; + case DOT11D_STATE_NONE: + break; + } +} + +int IsLegalChannel( + struct ieee80211_device * dev, + u8 channel +) +{ + PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev); + + if(MAX_CHANNEL_NUMBER < channel) + { + printk("IsLegalChannel(): Invalid Channel\n"); + return 0; + } + if(pDot11dInfo->channel_map[channel] > 0) + return 1; + return 0; +} + +int ToLegalChannel( + struct ieee80211_device * dev, + u8 channel +) +{ + PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev); + u8 default_chn = 0; + u32 i = 0; + + for (i=1; i<= MAX_CHANNEL_NUMBER; i++) + { + if(pDot11dInfo->channel_map[i] > 0) + { + default_chn = i; + break; + } + } + + if(MAX_CHANNEL_NUMBER < channel) + { + printk("IsLegalChannel(): Invalid Channel\n"); + return default_chn; + } + + if(pDot11dInfo->channel_map[channel] > 0) + return channel; + + return default_chn; +} +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) +EXPORT_SYMBOL(Dot11d_Init); +EXPORT_SYMBOL(Dot11d_Reset); +EXPORT_SYMBOL(Dot11d_UpdateCountryIe); +EXPORT_SYMBOL(DOT11D_GetMaxTxPwrInDbm); +EXPORT_SYMBOL(DOT11D_ScanComplete); +EXPORT_SYMBOL(IsLegalChannel); +EXPORT_SYMBOL(ToLegalChannel); +#else +EXPORT_SYMBOL_NOVERS(Dot11d_Init); +EXPORT_SYMBOL_NOVERS(Dot11d_Reset); +EXPORT_SYMBOL_NOVERS(Dot11d_UpdateCountryIe); +EXPORT_SYMBOL_NOVERS(DOT11D_GetMaxTxPwrInDbm); +EXPORT_SYMBOL_NOVERS(DOT11D_ScanComplete); +EXPORT_SYMBOL_NOVERS(IsLegalChannel); +EXPORT_SYMBOL_NOVERS(ToLegalChannel); +#endif + +#endif diff --git a/drivers/staging/rtl8192su/ieee80211/dot11d.h b/drivers/staging/rtl8192su/ieee80211/dot11d.h new file mode 100644 index 000000000000..15b7a4ba37b6 --- /dev/null +++ b/drivers/staging/rtl8192su/ieee80211/dot11d.h @@ -0,0 +1,102 @@ +#ifndef __INC_DOT11D_H +#define __INC_DOT11D_H + +#ifdef ENABLE_DOT11D +#include "ieee80211.h" + +//#define ENABLE_DOT11D + +//#define DOT11D_MAX_CHNL_NUM 83 + +typedef struct _CHNL_TXPOWER_TRIPLE { + u8 FirstChnl; + u8 NumChnls; + u8 MaxTxPowerInDbm; +}CHNL_TXPOWER_TRIPLE, *PCHNL_TXPOWER_TRIPLE; + +typedef enum _DOT11D_STATE { + DOT11D_STATE_NONE = 0, + DOT11D_STATE_LEARNED, + DOT11D_STATE_DONE, +}DOT11D_STATE; + +typedef struct _RT_DOT11D_INFO { + //DECLARE_RT_OBJECT(RT_DOT11D_INFO); + + bool bEnabled; // dot11MultiDomainCapabilityEnabled + + u16 CountryIeLen; // > 0 if CountryIeBuf[] contains valid country information element. + u8 CountryIeBuf[MAX_IE_LEN]; + u8 CountryIeSrcAddr[6]; // Source AP of the country IE. + u8 CountryIeWatchdog; + + u8 channel_map[MAX_CHANNEL_NUMBER+1]; //!!!Value 0: Invalid, 1: Valid (active scan), 2: Valid (passive scan) + //u8 ChnlListLen; // #Bytes valid in ChnlList[]. + //u8 ChnlList[DOT11D_MAX_CHNL_NUM]; + u8 MaxTxPwrDbmList[MAX_CHANNEL_NUMBER+1]; + + DOT11D_STATE State; +}RT_DOT11D_INFO, *PRT_DOT11D_INFO; +#define eqMacAddr(a,b) ( ((a)[0]==(b)[0] && (a)[1]==(b)[1] && (a)[2]==(b)[2] && (a)[3]==(b)[3] && (a)[4]==(b)[4] && (a)[5]==(b)[5]) ? 1:0 ) +#define cpMacAddr(des,src) ((des)[0]=(src)[0],(des)[1]=(src)[1],(des)[2]=(src)[2],(des)[3]=(src)[3],(des)[4]=(src)[4],(des)[5]=(src)[5]) +#define GET_DOT11D_INFO(__pIeeeDev) ((PRT_DOT11D_INFO)((__pIeeeDev)->pDot11dInfo)) + +#define IS_DOT11D_ENABLE(__pIeeeDev) GET_DOT11D_INFO(__pIeeeDev)->bEnabled +#define IS_COUNTRY_IE_VALID(__pIeeeDev) (GET_DOT11D_INFO(__pIeeeDev)->CountryIeLen > 0) + +#define IS_EQUAL_CIE_SRC(__pIeeeDev, __pTa) eqMacAddr(GET_DOT11D_INFO(__pIeeeDev)->CountryIeSrcAddr, __pTa) +#define UPDATE_CIE_SRC(__pIeeeDev, __pTa) cpMacAddr(GET_DOT11D_INFO(__pIeeeDev)->CountryIeSrcAddr, __pTa) + +#define IS_COUNTRY_IE_CHANGED(__pIeeeDev, __Ie) \ + (((__Ie).Length == 0 || (__Ie).Length != GET_DOT11D_INFO(__pIeeeDev)->CountryIeLen) ? \ + FALSE : \ + (!memcmp(GET_DOT11D_INFO(__pIeeeDev)->CountryIeBuf, (__Ie).Octet, (__Ie).Length))) + +#define CIE_WATCHDOG_TH 1 +#define GET_CIE_WATCHDOG(__pIeeeDev) GET_DOT11D_INFO(__pIeeeDev)->CountryIeWatchdog +#define RESET_CIE_WATCHDOG(__pIeeeDev) GET_CIE_WATCHDOG(__pIeeeDev) = 0 +#define UPDATE_CIE_WATCHDOG(__pIeeeDev) ++GET_CIE_WATCHDOG(__pIeeeDev) + +#define IS_DOT11D_STATE_DONE(__pIeeeDev) (GET_DOT11D_INFO(__pIeeeDev)->State == DOT11D_STATE_DONE) + + +void +Dot11d_Init( + struct ieee80211_device *dev + ); + +void +Dot11d_Reset( + struct ieee80211_device *dev + ); + +void +Dot11d_UpdateCountryIe( + struct ieee80211_device *dev, + u8 * pTaddr, + u16 CoutryIeLen, + u8 * pCoutryIe + ); + +u8 +DOT11D_GetMaxTxPwrInDbm( + struct ieee80211_device *dev, + u8 Channel + ); + +void +DOT11D_ScanComplete( + struct ieee80211_device * dev + ); + +int IsLegalChannel( + struct ieee80211_device * dev, + u8 channel +); + +int ToLegalChannel( + struct ieee80211_device * dev, + u8 channel +); +#endif //ENABLE_DOT11D +#endif // #ifndef __INC_DOT11D_H diff --git a/drivers/staging/rtl8192su/ieee80211/ieee80211.h b/drivers/staging/rtl8192su/ieee80211/ieee80211.h new file mode 100644 index 000000000000..720bfcbfadc1 --- /dev/null +++ b/drivers/staging/rtl8192su/ieee80211/ieee80211.h @@ -0,0 +1,2901 @@ +/* + * Merged with mainline ieee80211.h in Aug 2004. Original ieee802_11 + * remains copyright by the original authors + * + * Portions of the merged code are based on Host AP (software wireless + * LAN access point) driver for Intersil Prism2/2.5/3. + * + * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen + * + * Copyright (c) 2002-2003, Jouni Malinen + * + * Adaption to a generic IEEE 802.11 stack by James Ketrenos + * + * Copyright (c) 2004, Intel Corporation + * + * Modified for Realtek's wi-fi cards by Andrea Merello + * + * + * 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. See README and COPYING for + * more details. + */ +#ifndef IEEE80211_H +#define IEEE80211_H +#include /* ETH_ALEN */ +#include /* ARRAY_SIZE */ +#include +#include +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) +#include +#else +#include +#include +#endif +#include +#include + +#include +#include + +#include "rtl819x_HT.h" +#include "rtl819x_BA.h" +#include "rtl819x_TS.h" + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)) +#ifndef bool +typedef enum{false = 0, true} bool; +#endif +#endif + +#ifndef IW_MODE_MONITOR +#define IW_MODE_MONITOR 6 +#endif + +#ifndef IWEVCUSTOM +#define IWEVCUSTOM 0x8c02 +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) +#ifndef __bitwise +#define __bitwise __attribute__((bitwise)) +#endif +typedef __u16 __le16; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,27)) +struct iw_spy_data{ + /* --- Standard spy support --- */ + int spy_number; + u_char spy_address[IW_MAX_SPY][ETH_ALEN]; + struct iw_quality spy_stat[IW_MAX_SPY]; + /* --- Enhanced spy support (event) */ + struct iw_quality spy_thr_low; /* Low threshold */ + struct iw_quality spy_thr_high; /* High threshold */ + u_char spy_thr_under[IW_MAX_SPY]; +}; +#endif +#endif + +#ifndef container_of +/** + * container_of - cast a member of a structure out to the containing structure + * + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + * + */ +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) +#endif + +#define KEY_TYPE_NA 0x0 +#define KEY_TYPE_WEP40 0x1 +#define KEY_TYPE_TKIP 0x2 +#define KEY_TYPE_CCMP 0x4 +#define KEY_TYPE_WEP104 0x5 + +/* added for rtl819x tx procedure */ +#define MAX_QUEUE_SIZE 0x10 + +// +// 8190 queue mapping +// +#define BK_QUEUE 0 +#define BE_QUEUE 1 +#define VI_QUEUE 2 +#define VO_QUEUE 3 +#define HCCA_QUEUE 4 +#define TXCMD_QUEUE 5 +#define MGNT_QUEUE 6 +#define HIGH_QUEUE 7 +#define BEACON_QUEUE 8 + +#define LOW_QUEUE BE_QUEUE +#define NORMAL_QUEUE MGNT_QUEUE + +//added by amy for ps +#define SWRF_TIMEOUT 50 + +//added by amy for LEAP related +#define IE_CISCO_FLAG_POSITION 0x08 // Flag byte: byte 8, numbered from 0. +#define SUPPORT_CKIP_MIC 0x08 // bit3 +#define SUPPORT_CKIP_PK 0x10 // bit4 +//added by amy for ps +// RF Off Level for IPS or HW/SW radio off +#define RT_RF_OFF_LEVL_ASPM BIT0 // PCI ASPM +#define RT_RF_OFF_LEVL_CLK_REQ BIT1 // PCI clock request +#define RT_RF_OFF_LEVL_PCI_D3 BIT2 // PCI D3 mode +#define RT_RF_OFF_LEVL_HALT_NIC BIT3 // NIC halt, re-initialize hw parameters +#define RT_RF_OFF_LEVL_FREE_FW BIT4 // FW free, re-download the FW +#define RT_RF_OFF_LEVL_FW_32K BIT5 // FW in 32k +#define RT_RF_PS_LEVEL_ALWAYS_ASPM BIT6 // Always enable ASPM and Clock Req in initialization. +#define RT_RF_LPS_DISALBE_2R BIT30 // When LPS is on, disable 2R if no packet is received or transmittd. +#define RT_RF_LPS_LEVEL_ASPM BIT31 // LPS with ASPM +#define RT_IN_PS_LEVEL(pPSC, _PS_FLAG) ((pPSC->CurPsLevel & _PS_FLAG) ? true : false) +#define RT_CLEAR_PS_LEVEL(pPSC, _PS_FLAG) (pPSC->CurPsLevel &= (~(_PS_FLAG))) +#define RT_SET_PS_LEVEL(pPSC, _PS_FLAG) (pPSC->CurPsLevel->CurPsLevel |= _PS_FLAG) +/* defined for skb cb field */ +/* At most 28 byte */ +typedef struct cb_desc { + /* Tx Desc Related flags (8-9) */ + u8 bLastIniPkt:1; + u8 bCmdOrInit:1; + u8 bFirstSeg:1; + u8 bLastSeg:1; + u8 bEncrypt:1; + u8 bTxDisableRateFallBack:1; + u8 bTxUseDriverAssingedRate:1; + u8 bHwSec:1; //indicate whether use Hw security. WB + + u8 reserved1; + + /* Tx Firmware Relaged flags (10-11)*/ + u8 bCTSEnable:1; + u8 bRTSEnable:1; + u8 bUseShortGI:1; + u8 bUseShortPreamble:1; + u8 bTxEnableFwCalcDur:1; + u8 bAMPDUEnable:1; + u8 bRTSSTBC:1; + u8 RTSSC:1; + + u8 bRTSBW:1; + u8 bPacketBW:1; + u8 bRTSUseShortPreamble:1; + u8 bRTSUseShortGI:1; + u8 bMulticast:1; + u8 bBroadcast:1; + //u8 reserved2:2; + u8 drv_agg_enable:1; + u8 reserved2:1; + + /* Tx Desc related element(12-19) */ + u8 rata_index; + u8 queue_index; + //u8 reserved3; + //u8 reserved4; + u16 txbuf_size; + //u8 reserved5; + u8 RATRIndex; + u8 reserved6; + u8 reserved7; + u8 reserved8; + + /* Tx firmware related element(20-27) */ + u8 data_rate; + u8 rts_rate; + u8 ampdu_factor; + u8 ampdu_density; + //u8 reserved9; + //u8 reserved10; + //u8 reserved11; + u8 DrvAggrNum; + u16 pkt_size; + u8 reserved12; +}cb_desc, *pcb_desc; + +/*--------------------------Define -------------------------------------------*/ +#define MGN_1M 0x02 +#define MGN_2M 0x04 +#define MGN_5_5M 0x0b +#define MGN_11M 0x16 + +#define MGN_6M 0x0c +#define MGN_9M 0x12 +#define MGN_12M 0x18 +#define MGN_18M 0x24 +#define MGN_24M 0x30 +#define MGN_36M 0x48 +#define MGN_48M 0x60 +#define MGN_54M 0x6c + +#define MGN_MCS0 0x80 +#define MGN_MCS1 0x81 +#define MGN_MCS2 0x82 +#define MGN_MCS3 0x83 +#define MGN_MCS4 0x84 +#define MGN_MCS5 0x85 +#define MGN_MCS6 0x86 +#define MGN_MCS7 0x87 +#define MGN_MCS8 0x88 +#define MGN_MCS9 0x89 +#define MGN_MCS10 0x8a +#define MGN_MCS11 0x8b +#define MGN_MCS12 0x8c +#define MGN_MCS13 0x8d +#define MGN_MCS14 0x8e +#define MGN_MCS15 0x8f +#define MGN_MCS0_SG 0x90 +#define MGN_MCS1_SG 0x91 +#define MGN_MCS2_SG 0x92 +#define MGN_MCS3_SG 0x93 +#define MGN_MCS4_SG 0x94 +#define MGN_MCS5_SG 0x95 +#define MGN_MCS6_SG 0x96 +#define MGN_MCS7_SG 0x97 +#define MGN_MCS8_SG 0x98 +#define MGN_MCS9_SG 0x99 +#define MGN_MCS10_SG 0x9a +#define MGN_MCS11_SG 0x9b +#define MGN_MCS12_SG 0x9c +#define MGN_MCS13_SG 0x9d +#define MGN_MCS14_SG 0x9e +#define MGN_MCS15_SG 0x9f + + +//---------------------------------------------------------------------------- +// 802.11 Management frame Reason Code field +//---------------------------------------------------------------------------- +enum _ReasonCode{ + unspec_reason = 0x1, + auth_not_valid = 0x2, + deauth_lv_ss = 0x3, + inactivity = 0x4, + ap_overload = 0x5, + class2_err = 0x6, + class3_err = 0x7, + disas_lv_ss = 0x8, + asoc_not_auth = 0x9, + + //----MIC_CHECK + mic_failure = 0xe, + //----END MIC_CHECK + + // Reason code defined in 802.11i D10.0 p.28. + invalid_IE = 0x0d, + four_way_tmout = 0x0f, + two_way_tmout = 0x10, + IE_dismatch = 0x11, + invalid_Gcipher = 0x12, + invalid_Pcipher = 0x13, + invalid_AKMP = 0x14, + unsup_RSNIEver = 0x15, + invalid_RSNIE = 0x16, + auth_802_1x_fail= 0x17, + ciper_reject = 0x18, + + // Reason code defined in 7.3.1.7, 802.1e D13.0, p.42. Added by Annie, 2005-11-15. + QoS_unspec = 0x20, // 32 + QAP_bandwidth = 0x21, // 33 + poor_condition = 0x22, // 34 + no_facility = 0x23, // 35 + // Where is 36??? + req_declined = 0x25, // 37 + invalid_param = 0x26, // 38 + req_not_honored= 0x27, // 39 + TS_not_created = 0x2F, // 47 + DL_not_allowed = 0x30, // 48 + dest_not_exist = 0x31, // 49 + dest_not_QSTA = 0x32, // 50 +}; + + + +#define aSifsTime (((priv->ieee80211->current_network.mode == IEEE_A)||(priv->ieee80211->current_network.mode == IEEE_N_24G)||(priv->ieee80211->current_network.mode == IEEE_N_5G))? 16 : 10) + +#define MGMT_QUEUE_NUM 5 + +#define IEEE_CMD_SET_WPA_PARAM 1 +#define IEEE_CMD_SET_WPA_IE 2 +#define IEEE_CMD_SET_ENCRYPTION 3 +#define IEEE_CMD_MLME 4 + +#define IEEE_PARAM_WPA_ENABLED 1 +#define IEEE_PARAM_TKIP_COUNTERMEASURES 2 +#define IEEE_PARAM_DROP_UNENCRYPTED 3 +#define IEEE_PARAM_PRIVACY_INVOKED 4 +#define IEEE_PARAM_AUTH_ALGS 5 +#define IEEE_PARAM_IEEE_802_1X 6 +//It should consistent with the driver_XXX.c +// David, 2006.9.26 +#define IEEE_PARAM_WPAX_SELECT 7 +//Added for notify the encryption type selection +// David, 2006.9.26 +#define IEEE_PROTO_WPA 1 +#define IEEE_PROTO_RSN 2 +//Added for notify the encryption type selection +// David, 2006.9.26 +#define IEEE_WPAX_USEGROUP 0 +#define IEEE_WPAX_WEP40 1 +#define IEEE_WPAX_TKIP 2 +#define IEEE_WPAX_WRAP 3 +#define IEEE_WPAX_CCMP 4 +#define IEEE_WPAX_WEP104 5 + +#define IEEE_KEY_MGMT_IEEE8021X 1 +#define IEEE_KEY_MGMT_PSK 2 + +#define IEEE_MLME_STA_DEAUTH 1 +#define IEEE_MLME_STA_DISASSOC 2 + + +#define IEEE_CRYPT_ERR_UNKNOWN_ALG 2 +#define IEEE_CRYPT_ERR_UNKNOWN_ADDR 3 +#define IEEE_CRYPT_ERR_CRYPT_INIT_FAILED 4 +#define IEEE_CRYPT_ERR_KEY_SET_FAILED 5 +#define IEEE_CRYPT_ERR_TX_KEY_SET_FAILED 6 +#define IEEE_CRYPT_ERR_CARD_CONF_FAILED 7 + + +#define IEEE_CRYPT_ALG_NAME_LEN 16 + +#define MAX_IE_LEN 0xff + +// added for kernel conflict +#define ieee80211_crypt_deinit_entries ieee80211_crypt_deinit_entries_rsl +#define ieee80211_crypt_deinit_handler ieee80211_crypt_deinit_handler_rsl +#define ieee80211_crypt_delayed_deinit ieee80211_crypt_delayed_deinit_rsl +#define ieee80211_register_crypto_ops ieee80211_register_crypto_ops_rsl +#define ieee80211_unregister_crypto_ops ieee80211_unregister_crypto_ops_rsl +#define ieee80211_get_crypto_ops ieee80211_get_crypto_ops_rsl + +#define ieee80211_ccmp_null ieee80211_ccmp_null_rsl + +#define ieee80211_tkip_null ieee80211_tkip_null_rsl + +#define ieee80211_wep_null ieee80211_wep_null_rsl + +#define free_ieee80211 free_ieee80211_rsl +#define alloc_ieee80211 alloc_ieee80211_rsl + +#define ieee80211_rx ieee80211_rx_rsl +#define ieee80211_rx_mgt ieee80211_rx_mgt_rsl + +#define ieee80211_get_beacon ieee80211_get_beacon_rsl +#define ieee80211_wake_queue ieee80211_wake_queue_rsl +#define ieee80211_stop_queue ieee80211_stop_queue_rsl +#define ieee80211_reset_queue ieee80211_reset_queue_rsl +#define ieee80211_softmac_stop_protocol ieee80211_softmac_stop_protocol_rsl +#define ieee80211_softmac_start_protocol ieee80211_softmac_start_protocol_rsl +#define ieee80211_is_shortslot ieee80211_is_shortslot_rsl +#define ieee80211_is_54g ieee80211_is_54g_rsl +#define ieee80211_wpa_supplicant_ioctl ieee80211_wpa_supplicant_ioctl_rsl +#define ieee80211_ps_tx_ack ieee80211_ps_tx_ack_rsl +#define ieee80211_softmac_xmit ieee80211_softmac_xmit_rsl +#define ieee80211_stop_send_beacons ieee80211_stop_send_beacons_rsl +#define notify_wx_assoc_event notify_wx_assoc_event_rsl +#define SendDisassociation SendDisassociation_rsl +#define ieee80211_disassociate ieee80211_disassociate_rsl +#define ieee80211_start_send_beacons ieee80211_start_send_beacons_rsl +#define ieee80211_stop_scan ieee80211_stop_scan_rsl +#define ieee80211_send_probe_requests ieee80211_send_probe_requests_rsl +#define ieee80211_softmac_scan_syncro ieee80211_softmac_scan_syncro_rsl +#define ieee80211_start_scan_syncro ieee80211_start_scan_syncro_rsl + +#define ieee80211_wx_get_essid ieee80211_wx_get_essid_rsl +#define ieee80211_wx_set_essid ieee80211_wx_set_essid_rsl +#define ieee80211_wx_set_rate ieee80211_wx_set_rate_rsl +#define ieee80211_wx_get_rate ieee80211_wx_get_rate_rsl +#define ieee80211_wx_set_wap ieee80211_wx_set_wap_rsl +#define ieee80211_wx_get_wap ieee80211_wx_get_wap_rsl +#define ieee80211_wx_set_mode ieee80211_wx_set_mode_rsl +#define ieee80211_wx_get_mode ieee80211_wx_get_mode_rsl +#define ieee80211_wx_set_scan ieee80211_wx_set_scan_rsl +#define ieee80211_wx_get_freq ieee80211_wx_get_freq_rsl +#define ieee80211_wx_set_freq ieee80211_wx_set_freq_rsl +#define ieee80211_wx_set_rawtx ieee80211_wx_set_rawtx_rsl +#define ieee80211_wx_get_name ieee80211_wx_get_name_rsl +#define ieee80211_wx_set_power ieee80211_wx_set_power_rsl +#define ieee80211_wx_get_power ieee80211_wx_get_power_rsl +#define ieee80211_wlan_frequencies ieee80211_wlan_frequencies_rsl +#define ieee80211_wx_set_rts ieee80211_wx_set_rts_rsl +#define ieee80211_wx_get_rts ieee80211_wx_get_rts_rsl + +#define ieee80211_txb_free ieee80211_txb_free_rsl + +#define ieee80211_wx_set_gen_ie ieee80211_wx_set_gen_ie_rsl +#define ieee80211_wx_get_scan ieee80211_wx_get_scan_rsl +#define ieee80211_wx_set_encode ieee80211_wx_set_encode_rsl +#define ieee80211_wx_get_encode ieee80211_wx_get_encode_rsl +#if WIRELESS_EXT >= 18 +#define ieee80211_wx_set_mlme ieee80211_wx_set_mlme_rsl +#define ieee80211_wx_set_auth ieee80211_wx_set_auth_rsl +#define ieee80211_wx_set_encode_ext ieee80211_wx_set_encode_ext_rsl +#define ieee80211_wx_get_encode_ext ieee80211_wx_get_encode_ext_rsl +#endif + + +typedef struct ieee_param { + u32 cmd; + u8 sta_addr[ETH_ALEN]; + union { + struct { + u8 name; + u32 value; + } wpa_param; + struct { + u32 len; + u8 reserved[32]; + u8 data[0]; + } wpa_ie; + struct{ + int command; + int reason_code; + } mlme; + struct { + u8 alg[IEEE_CRYPT_ALG_NAME_LEN]; + u8 set_tx; + u32 err; + u8 idx; + u8 seq[8]; /* sequence counter (set: RX, get: TX) */ + u16 key_len; + u8 key[0]; + } crypt; + } u; +}ieee_param; + + +#if WIRELESS_EXT < 17 +#define IW_QUAL_QUAL_INVALID 0x10 +#define IW_QUAL_LEVEL_INVALID 0x20 +#define IW_QUAL_NOISE_INVALID 0x40 +#define IW_QUAL_QUAL_UPDATED 0x1 +#define IW_QUAL_LEVEL_UPDATED 0x2 +#define IW_QUAL_NOISE_UPDATED 0x4 +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) +static inline void tq_init(struct tq_struct * task, void(*func)(void *), void *data) +{ + task->routine = func; + task->data = data; + //task->next = NULL; + INIT_LIST_HEAD(&task->list); + task->sync = 0; +} +#endif + +// linux under 2.6.9 release may not support it, so modify it for common use +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9)) +//#define MSECS(t) (1000 * ((t) / HZ) + 1000 * ((t) % HZ) / HZ) +#define MSECS(t) (HZ * ((t) / 1000) + (HZ * ((t) % 1000)) / 1000) +static inline unsigned long msleep_interruptible_rsl(unsigned int msecs) +{ + unsigned long timeout = MSECS(msecs) + 1; + + while (timeout) { + set_current_state(TASK_INTERRUPTIBLE); + timeout = schedule_timeout(timeout); + } + return timeout; +} +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,31)) +static inline void msleep(unsigned int msecs) +{ + unsigned long timeout = MSECS(msecs) + 1; + + while (timeout) { + set_current_state(TASK_UNINTERRUPTIBLE); + timeout = schedule_timeout(timeout); + } +} +#endif +#else +#define MSECS(t) msecs_to_jiffies(t) +#define msleep_interruptible_rsl msleep_interruptible +#endif + +#define IEEE80211_DATA_LEN 2304 +/* Maximum size for the MA-UNITDATA primitive, 802.11 standard section + 6.2.1.1.2. + + The figure in section 7.1.2 suggests a body size of up to 2312 + bytes is allowed, which is a bit confusing, I suspect this + represents the 2304 bytes of real data, plus a possible 8 bytes of + WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */ +#define IEEE80211_1ADDR_LEN 10 +#define IEEE80211_2ADDR_LEN 16 +#define IEEE80211_3ADDR_LEN 24 +#define IEEE80211_4ADDR_LEN 30 +#define IEEE80211_FCS_LEN 4 +#define IEEE80211_HLEN (IEEE80211_4ADDR_LEN) +#define IEEE80211_FRAME_LEN (IEEE80211_DATA_LEN + IEEE80211_HLEN) +#define IEEE80211_MGMT_HDR_LEN 24 +#define IEEE80211_DATA_HDR3_LEN 24 +#define IEEE80211_DATA_HDR4_LEN 30 + +#define MIN_FRAG_THRESHOLD 256U +#define MAX_FRAG_THRESHOLD 2346U + + +/* Frame control field constants */ +#define IEEE80211_FCTL_VERS 0x0003 +#define IEEE80211_FCTL_FTYPE 0x000c +#define IEEE80211_FCTL_STYPE 0x00f0 +#define IEEE80211_FCTL_FRAMETYPE 0x00fc +#define IEEE80211_FCTL_TODS 0x0100 +#define IEEE80211_FCTL_FROMDS 0x0200 +#define IEEE80211_FCTL_DSTODS 0x0300 //added by david +#define IEEE80211_FCTL_MOREFRAGS 0x0400 +#define IEEE80211_FCTL_RETRY 0x0800 +#define IEEE80211_FCTL_PM 0x1000 +#define IEEE80211_FCTL_MOREDATA 0x2000 +#define IEEE80211_FCTL_WEP 0x4000 +#define IEEE80211_FCTL_ORDER 0x8000 + +#define IEEE80211_FTYPE_MGMT 0x0000 +#define IEEE80211_FTYPE_CTL 0x0004 +#define IEEE80211_FTYPE_DATA 0x0008 + +/* management */ +#define IEEE80211_STYPE_ASSOC_REQ 0x0000 +#define IEEE80211_STYPE_ASSOC_RESP 0x0010 +#define IEEE80211_STYPE_REASSOC_REQ 0x0020 +#define IEEE80211_STYPE_REASSOC_RESP 0x0030 +#define IEEE80211_STYPE_PROBE_REQ 0x0040 +#define IEEE80211_STYPE_PROBE_RESP 0x0050 +#define IEEE80211_STYPE_BEACON 0x0080 +#define IEEE80211_STYPE_ATIM 0x0090 +#define IEEE80211_STYPE_DISASSOC 0x00A0 +#define IEEE80211_STYPE_AUTH 0x00B0 +#define IEEE80211_STYPE_DEAUTH 0x00C0 +#define IEEE80211_STYPE_MANAGE_ACT 0x00D0 + +/* control */ +#define IEEE80211_STYPE_PSPOLL 0x00A0 +#define IEEE80211_STYPE_RTS 0x00B0 +#define IEEE80211_STYPE_CTS 0x00C0 +#define IEEE80211_STYPE_ACK 0x00D0 +#define IEEE80211_STYPE_CFEND 0x00E0 +#define IEEE80211_STYPE_CFENDACK 0x00F0 +#define IEEE80211_STYPE_BLOCKACK 0x0094 + +/* data */ +#define IEEE80211_STYPE_DATA 0x0000 +#define IEEE80211_STYPE_DATA_CFACK 0x0010 +#define IEEE80211_STYPE_DATA_CFPOLL 0x0020 +#define IEEE80211_STYPE_DATA_CFACKPOLL 0x0030 +#define IEEE80211_STYPE_NULLFUNC 0x0040 +#define IEEE80211_STYPE_CFACK 0x0050 +#define IEEE80211_STYPE_CFPOLL 0x0060 +#define IEEE80211_STYPE_CFACKPOLL 0x0070 +#define IEEE80211_STYPE_QOS_DATA 0x0080 //added for WMM 2006/8/2 +#define IEEE80211_STYPE_QOS_NULL 0x00C0 + +#define IEEE80211_SCTL_FRAG 0x000F +#define IEEE80211_SCTL_SEQ 0xFFF0 + +/* QOS control */ +#define IEEE80211_QCTL_TID 0x000F + +#define FC_QOS_BIT BIT7 +#define IsDataFrame(pdu) ( ((pdu[0] & 0x0C)==0x08) ? true : false ) +#define IsLegacyDataFrame(pdu) (IsDataFrame(pdu) && (!(pdu[0]&FC_QOS_BIT)) ) +//added by wb. Is this right? +#define IsQoSDataFrame(pframe) ((*(u16*)pframe&(IEEE80211_STYPE_QOS_DATA|IEEE80211_FTYPE_DATA)) == (IEEE80211_STYPE_QOS_DATA|IEEE80211_FTYPE_DATA)) +#define Frame_Order(pframe) (*(u16*)pframe&IEEE80211_FCTL_ORDER) +#define SN_LESS(a, b) (((a-b)&0x800)!=0) +#define SN_EQUAL(a, b) (a == b) +#define MAX_DEV_ADDR_SIZE 8 +typedef enum _ACT_CATEGORY{ + ACT_CAT_QOS = 1, + ACT_CAT_DLS = 2, + ACT_CAT_BA = 3, + ACT_CAT_HT = 7, + ACT_CAT_WMM = 17, +} ACT_CATEGORY, *PACT_CATEGORY; + +typedef enum _TS_ACTION{ + ACT_ADDTSREQ = 0, + ACT_ADDTSRSP = 1, + ACT_DELTS = 2, + ACT_SCHEDULE = 3, +} TS_ACTION, *PTS_ACTION; + +typedef enum _BA_ACTION{ + ACT_ADDBAREQ = 0, + ACT_ADDBARSP = 1, + ACT_DELBA = 2, +} BA_ACTION, *PBA_ACTION; + +typedef enum _InitialGainOpType{ + IG_Backup=0, + IG_Restore, + IG_Max +}InitialGainOpType; +//added by amy for LED 090319 +//================================================================================ +// LED customization. +//================================================================================ +typedef enum _LED_CTL_MODE{ + LED_CTL_POWER_ON = 1, + LED_CTL_LINK = 2, + LED_CTL_NO_LINK = 3, + LED_CTL_TX = 4, + LED_CTL_RX = 5, + LED_CTL_SITE_SURVEY = 6, + LED_CTL_POWER_OFF = 7, + LED_CTL_START_TO_LINK = 8, + LED_CTL_START_WPS = 9, + LED_CTL_STOP_WPS = 10, + LED_CTL_START_WPS_BOTTON = 11, //added for runtop +}LED_CTL_MODE; + +/* debug macros */ +#define CONFIG_IEEE80211_DEBUG +#ifdef CONFIG_IEEE80211_DEBUG +extern u32 ieee80211_debug_level; +#define IEEE80211_DEBUG(level, fmt, args...) \ +do { if (ieee80211_debug_level & (level)) \ + printk(KERN_DEBUG "ieee80211: " fmt, ## args); } while (0) +//wb added to debug out data buf +//if you want print DATA buffer related BA, please set ieee80211_debug_level to DATA|BA +#define IEEE80211_DEBUG_DATA(level, data, datalen) \ + do{ if ((ieee80211_debug_level & (level)) == (level)) \ + { \ + int i; \ + u8* pdata = (u8*) data; \ + printk(KERN_DEBUG "ieee80211: %s()\n", __FUNCTION__); \ + for(i=0; i<(int)(datalen); i++) \ + { \ + printk("%2x ", pdata[i]); \ + if ((i+1)%16 == 0) printk("\n"); \ + } \ + printk("\n"); \ + } \ + } while (0) +#else +#define IEEE80211_DEBUG(level, fmt, args...) do {} while (0) +#define IEEE80211_DEBUG_DATA(level, data, datalen) do {} while(0) +#endif /* CONFIG_IEEE80211_DEBUG */ + +/* debug macros not dependent on CONFIG_IEEE80211_DEBUG */ + +#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x" +#define MAC_ARG(x) ((u8*)(x))[0],((u8*)(x))[1],((u8*)(x))[2],((u8*)(x))[3],((u8*)(x))[4],((u8*)(x))[5] + +/* + * To use the debug system; + * + * If you are defining a new debug classification, simply add it to the #define + * list here in the form of: + * + * #define IEEE80211_DL_xxxx VALUE + * + * shifting value to the left one bit from the previous entry. xxxx should be + * the name of the classification (for example, WEP) + * + * You then need to either add a IEEE80211_xxxx_DEBUG() macro definition for your + * classification, or use IEEE80211_DEBUG(IEEE80211_DL_xxxx, ...) whenever you want + * to send output to that classification. + * + * To add your debug level to the list of levels seen when you perform + * + * % cat /proc/net/ipw/debug_level + * + * you simply need to add your entry to the ipw_debug_levels array. + * + * If you do not see debug_level in /proc/net/ipw then you do not have + * CONFIG_IEEE80211_DEBUG defined in your kernel configuration + * + */ + +#define IEEE80211_DL_INFO (1<<0) +#define IEEE80211_DL_WX (1<<1) +#define IEEE80211_DL_SCAN (1<<2) +#define IEEE80211_DL_STATE (1<<3) +#define IEEE80211_DL_MGMT (1<<4) +#define IEEE80211_DL_FRAG (1<<5) +#define IEEE80211_DL_EAP (1<<6) +#define IEEE80211_DL_DROP (1<<7) + +#define IEEE80211_DL_TX (1<<8) +#define IEEE80211_DL_RX (1<<9) + +#define IEEE80211_DL_HT (1<<10) //HT +#define IEEE80211_DL_BA (1<<11) //ba +#define IEEE80211_DL_TS (1<<12) //TS +#define IEEE80211_DL_QOS (1<<13) +#define IEEE80211_DL_REORDER (1<<14) +#define IEEE80211_DL_IOT (1<<15) +#define IEEE80211_DL_IPS (1<<16) +#define IEEE80211_DL_TRACE (1<<29) //trace function, need to user net_ratelimit() together in order not to print too much to the screen +#define IEEE80211_DL_DATA (1<<30) //use this flag to control whether print data buf out. +#define IEEE80211_DL_ERR (1<<31) //always open +#define IEEE80211_ERROR(f, a...) printk(KERN_ERR "ieee80211: " f, ## a) +#define IEEE80211_WARNING(f, a...) printk(KERN_WARNING "ieee80211: " f, ## a) +#define IEEE80211_DEBUG_INFO(f, a...) IEEE80211_DEBUG(IEEE80211_DL_INFO, f, ## a) + +#define IEEE80211_DEBUG_WX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_WX, f, ## a) +#define IEEE80211_DEBUG_SCAN(f, a...) IEEE80211_DEBUG(IEEE80211_DL_SCAN, f, ## a) +#define IEEE80211_DEBUG_STATE(f, a...) IEEE80211_DEBUG(IEEE80211_DL_STATE, f, ## a) +#define IEEE80211_DEBUG_MGMT(f, a...) IEEE80211_DEBUG(IEEE80211_DL_MGMT, f, ## a) +#define IEEE80211_DEBUG_FRAG(f, a...) IEEE80211_DEBUG(IEEE80211_DL_FRAG, f, ## a) +#define IEEE80211_DEBUG_EAP(f, a...) IEEE80211_DEBUG(IEEE80211_DL_EAP, f, ## a) +#define IEEE80211_DEBUG_DROP(f, a...) IEEE80211_DEBUG(IEEE80211_DL_DROP, f, ## a) +#define IEEE80211_DEBUG_TX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_TX, f, ## a) +#define IEEE80211_DEBUG_RX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_RX, f, ## a) +#define IEEE80211_DEBUG_QOS(f, a...) IEEE80211_DEBUG(IEEE80211_DL_QOS, f, ## a) + +#ifdef CONFIG_IEEE80211_DEBUG +/* Added by Annie, 2005-11-22. */ +#define MAX_STR_LEN 64 +/* I want to see ASCII 33 to 126 only. Otherwise, I print '?'. Annie, 2005-11-22.*/ +#define PRINTABLE(_ch) (_ch>'!' && _ch<'~') +#define IEEE80211_PRINT_STR(_Comp, _TitleString, _Ptr, _Len) \ + if((_Comp) & level) \ + { \ + int __i; \ + u8 buffer[MAX_STR_LEN]; \ + int length = (_Len\n", _Len, buffer); \ + } +#else +#define IEEE80211_PRINT_STR(_Comp, _TitleString, _Ptr, _Len) do {} while (0) +#endif + +#include +#include /* ARPHRD_ETHER */ + +#ifndef WIRELESS_SPY +#define WIRELESS_SPY // enable iwspy support +#endif +#include // new driver API + +#ifndef ETH_P_PAE +#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */ +#endif /* ETH_P_PAE */ + +#define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */ + +#ifndef ETH_P_80211_RAW +#define ETH_P_80211_RAW (ETH_P_ECONET + 1) +#endif + +/* IEEE 802.11 defines */ + +#define P80211_OUI_LEN 3 + +struct ieee80211_snap_hdr { + + u8 dsap; /* always 0xAA */ + u8 ssap; /* always 0xAA */ + u8 ctrl; /* always 0x03 */ + u8 oui[P80211_OUI_LEN]; /* organizational universal id */ + +} __attribute__ ((packed)); + +#define SNAP_SIZE sizeof(struct ieee80211_snap_hdr) + +#define WLAN_FC_GET_VERS(fc) ((fc) & IEEE80211_FCTL_VERS) +#define WLAN_FC_GET_TYPE(fc) ((fc) & IEEE80211_FCTL_FTYPE) +#define WLAN_FC_GET_STYPE(fc) ((fc) & IEEE80211_FCTL_STYPE) + +#define WLAN_FC_GET_FRAMETYPE(fc) ((fc) & IEEE80211_FCTL_FRAMETYPE) +#define WLAN_GET_SEQ_FRAG(seq) ((seq) & IEEE80211_SCTL_FRAG) +#define WLAN_GET_SEQ_SEQ(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4) + +/* Authentication algorithms */ +#define WLAN_AUTH_OPEN 0 +#define WLAN_AUTH_SHARED_KEY 1 +#define WLAN_AUTH_LEAP 2 + +#define WLAN_AUTH_CHALLENGE_LEN 128 + +#define WLAN_CAPABILITY_BSS (1<<0) +#define WLAN_CAPABILITY_IBSS (1<<1) +#define WLAN_CAPABILITY_CF_POLLABLE (1<<2) +#define WLAN_CAPABILITY_CF_POLL_REQUEST (1<<3) +#define WLAN_CAPABILITY_PRIVACY (1<<4) +#define WLAN_CAPABILITY_SHORT_PREAMBLE (1<<5) +#define WLAN_CAPABILITY_PBCC (1<<6) +#define WLAN_CAPABILITY_CHANNEL_AGILITY (1<<7) +#define WLAN_CAPABILITY_SPECTRUM_MGMT (1<<8) +#define WLAN_CAPABILITY_QOS (1<<9) +#define WLAN_CAPABILITY_SHORT_SLOT (1<<10) +#define WLAN_CAPABILITY_DSSS_OFDM (1<<13) + +/* 802.11g ERP information element */ +#define WLAN_ERP_NON_ERP_PRESENT (1<<0) +#define WLAN_ERP_USE_PROTECTION (1<<1) +#define WLAN_ERP_BARKER_PREAMBLE (1<<2) + +/* Status codes */ +enum ieee80211_statuscode { + WLAN_STATUS_SUCCESS = 0, + WLAN_STATUS_UNSPECIFIED_FAILURE = 1, + WLAN_STATUS_CAPS_UNSUPPORTED = 10, + WLAN_STATUS_REASSOC_NO_ASSOC = 11, + WLAN_STATUS_ASSOC_DENIED_UNSPEC = 12, + WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG = 13, + WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION = 14, + WLAN_STATUS_CHALLENGE_FAIL = 15, + WLAN_STATUS_AUTH_TIMEOUT = 16, + WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA = 17, + WLAN_STATUS_ASSOC_DENIED_RATES = 18, + /* 802.11b */ + WLAN_STATUS_ASSOC_DENIED_NOSHORTPREAMBLE = 19, + WLAN_STATUS_ASSOC_DENIED_NOPBCC = 20, + WLAN_STATUS_ASSOC_DENIED_NOAGILITY = 21, + /* 802.11h */ + WLAN_STATUS_ASSOC_DENIED_NOSPECTRUM = 22, + WLAN_STATUS_ASSOC_REJECTED_BAD_POWER = 23, + WLAN_STATUS_ASSOC_REJECTED_BAD_SUPP_CHAN = 24, + /* 802.11g */ + WLAN_STATUS_ASSOC_DENIED_NOSHORTTIME = 25, + WLAN_STATUS_ASSOC_DENIED_NODSSSOFDM = 26, + /* 802.11i */ + WLAN_STATUS_INVALID_IE = 40, + WLAN_STATUS_INVALID_GROUP_CIPHER = 41, + WLAN_STATUS_INVALID_PAIRWISE_CIPHER = 42, + WLAN_STATUS_INVALID_AKMP = 43, + WLAN_STATUS_UNSUPP_RSN_VERSION = 44, + WLAN_STATUS_INVALID_RSN_IE_CAP = 45, + WLAN_STATUS_CIPHER_SUITE_REJECTED = 46, +}; + +/* Reason codes */ +enum ieee80211_reasoncode { + WLAN_REASON_UNSPECIFIED = 1, + WLAN_REASON_PREV_AUTH_NOT_VALID = 2, + WLAN_REASON_DEAUTH_LEAVING = 3, + WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY = 4, + WLAN_REASON_DISASSOC_AP_BUSY = 5, + WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA = 6, + WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA = 7, + WLAN_REASON_DISASSOC_STA_HAS_LEFT = 8, + WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH = 9, + /* 802.11h */ + WLAN_REASON_DISASSOC_BAD_POWER = 10, + WLAN_REASON_DISASSOC_BAD_SUPP_CHAN = 11, + /* 802.11i */ + WLAN_REASON_INVALID_IE = 13, + WLAN_REASON_MIC_FAILURE = 14, + WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT = 15, + WLAN_REASON_GROUP_KEY_HANDSHAKE_TIMEOUT = 16, + WLAN_REASON_IE_DIFFERENT = 17, + WLAN_REASON_INVALID_GROUP_CIPHER = 18, + WLAN_REASON_INVALID_PAIRWISE_CIPHER = 19, + WLAN_REASON_INVALID_AKMP = 20, + WLAN_REASON_UNSUPP_RSN_VERSION = 21, + WLAN_REASON_INVALID_RSN_IE_CAP = 22, + WLAN_REASON_IEEE8021X_FAILED = 23, + WLAN_REASON_CIPHER_SUITE_REJECTED = 24, +}; + +#define IEEE80211_STATMASK_SIGNAL (1<<0) +#define IEEE80211_STATMASK_RSSI (1<<1) +#define IEEE80211_STATMASK_NOISE (1<<2) +#define IEEE80211_STATMASK_RATE (1<<3) +#define IEEE80211_STATMASK_WEMASK 0x7 + +#define IEEE80211_CCK_MODULATION (1<<0) +#define IEEE80211_OFDM_MODULATION (1<<1) + +#define IEEE80211_24GHZ_BAND (1<<0) +#define IEEE80211_52GHZ_BAND (1<<1) + +#define IEEE80211_CCK_RATE_LEN 4 +#define IEEE80211_CCK_RATE_1MB 0x02 +#define IEEE80211_CCK_RATE_2MB 0x04 +#define IEEE80211_CCK_RATE_5MB 0x0B +#define IEEE80211_CCK_RATE_11MB 0x16 +#define IEEE80211_OFDM_RATE_LEN 8 +#define IEEE80211_OFDM_RATE_6MB 0x0C +#define IEEE80211_OFDM_RATE_9MB 0x12 +#define IEEE80211_OFDM_RATE_12MB 0x18 +#define IEEE80211_OFDM_RATE_18MB 0x24 +#define IEEE80211_OFDM_RATE_24MB 0x30 +#define IEEE80211_OFDM_RATE_36MB 0x48 +#define IEEE80211_OFDM_RATE_48MB 0x60 +#define IEEE80211_OFDM_RATE_54MB 0x6C +#define IEEE80211_BASIC_RATE_MASK 0x80 + +#define IEEE80211_CCK_RATE_1MB_MASK (1<<0) +#define IEEE80211_CCK_RATE_2MB_MASK (1<<1) +#define IEEE80211_CCK_RATE_5MB_MASK (1<<2) +#define IEEE80211_CCK_RATE_11MB_MASK (1<<3) +#define IEEE80211_OFDM_RATE_6MB_MASK (1<<4) +#define IEEE80211_OFDM_RATE_9MB_MASK (1<<5) +#define IEEE80211_OFDM_RATE_12MB_MASK (1<<6) +#define IEEE80211_OFDM_RATE_18MB_MASK (1<<7) +#define IEEE80211_OFDM_RATE_24MB_MASK (1<<8) +#define IEEE80211_OFDM_RATE_36MB_MASK (1<<9) +#define IEEE80211_OFDM_RATE_48MB_MASK (1<<10) +#define IEEE80211_OFDM_RATE_54MB_MASK (1<<11) + +#define IEEE80211_CCK_RATES_MASK 0x0000000F +#define IEEE80211_CCK_BASIC_RATES_MASK (IEEE80211_CCK_RATE_1MB_MASK | \ + IEEE80211_CCK_RATE_2MB_MASK) +#define IEEE80211_CCK_DEFAULT_RATES_MASK (IEEE80211_CCK_BASIC_RATES_MASK | \ + IEEE80211_CCK_RATE_5MB_MASK | \ + IEEE80211_CCK_RATE_11MB_MASK) + +#define IEEE80211_OFDM_RATES_MASK 0x00000FF0 +#define IEEE80211_OFDM_BASIC_RATES_MASK (IEEE80211_OFDM_RATE_6MB_MASK | \ + IEEE80211_OFDM_RATE_12MB_MASK | \ + IEEE80211_OFDM_RATE_24MB_MASK) +#define IEEE80211_OFDM_DEFAULT_RATES_MASK (IEEE80211_OFDM_BASIC_RATES_MASK | \ + IEEE80211_OFDM_RATE_9MB_MASK | \ + IEEE80211_OFDM_RATE_18MB_MASK | \ + IEEE80211_OFDM_RATE_36MB_MASK | \ + IEEE80211_OFDM_RATE_48MB_MASK | \ + IEEE80211_OFDM_RATE_54MB_MASK) +#define IEEE80211_DEFAULT_RATES_MASK (IEEE80211_OFDM_DEFAULT_RATES_MASK | \ + IEEE80211_CCK_DEFAULT_RATES_MASK) + +#define IEEE80211_NUM_OFDM_RATES 8 +#define IEEE80211_NUM_CCK_RATES 4 +#define IEEE80211_OFDM_SHIFT_MASK_A 4 + + +/* this is stolen and modified from the madwifi driver*/ +#define IEEE80211_FC0_TYPE_MASK 0x0c +#define IEEE80211_FC0_TYPE_DATA 0x08 +#define IEEE80211_FC0_SUBTYPE_MASK 0xB0 +#define IEEE80211_FC0_SUBTYPE_QOS 0x80 + +#define IEEE80211_QOS_HAS_SEQ(fc) \ + (((fc) & (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) == \ + (IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_QOS)) + +/* this is stolen from ipw2200 driver */ +#define IEEE_IBSS_MAC_HASH_SIZE 31 +struct ieee_ibss_seq { + u8 mac[ETH_ALEN]; + u16 seq_num[17]; + u16 frag_num[17]; + unsigned long packet_time[17]; + struct list_head list; +}; + +/* NOTE: This data is for statistical purposes; not all hardware provides this + * information for frames received. Not setting these will not cause + * any adverse affects. */ +struct ieee80211_rx_stats { +#if 1 + u32 mac_time[2]; + s8 rssi; + u8 signal; + u8 noise; + u16 rate; /* in 100 kbps */ + u8 received_channel; + u8 control; + u8 mask; + u8 freq; + u16 len; + u64 tsf; + u32 beacon_time; + u8 nic_type; + u16 Length; + // u8 DataRate; // In 0.5 Mbps + u8 SignalQuality; // in 0-100 index. + s32 RecvSignalPower; // Real power in dBm for this packet, no beautification and aggregation. + s8 RxPower; // in dBm Translate from PWdB + u8 SignalStrength; // in 0-100 index. + u16 bHwError:1; + u16 bCRC:1; + u16 bICV:1; + u16 bShortPreamble:1; + u16 Antenna:1; //for rtl8185 + u16 Decrypted:1; //for rtl8185, rtl8187 + u16 Wakeup:1; //for rtl8185 + u16 Reserved0:1; //for rtl8185 + u8 AGC; + u32 TimeStampLow; + u32 TimeStampHigh; + bool bShift; + bool bIsQosData; // Added by Annie, 2005-12-22. + u8 UserPriority; + + //1!!!!!!!!!!!!!!!!!!!!!!!!!!! + //1Attention Please!!!<11n or 8190 specific code should be put below this line> + //1!!!!!!!!!!!!!!!!!!!!!!!!!!! + + u8 RxDrvInfoSize; + u8 RxBufShift; + bool bIsAMPDU; + bool bFirstMPDU; + bool bContainHTC; + bool RxIs40MHzPacket; + u32 RxPWDBAll; + u8 RxMIMOSignalStrength[4]; // in 0~100 index + s8 RxMIMOSignalQuality[2]; + bool bPacketMatchBSSID; + bool bIsCCK; + bool bPacketToSelf; + //added by amy + u8* virtual_address; + u16 packetlength; // Total packet length: Must equal to sum of all FragLength + u16 fraglength; // FragLength should equal to PacketLength in non-fragment case + u16 fragoffset; // Data offset for this fragment + u16 ntotalfrag; + bool bisrxaggrsubframe; + bool bPacketBeacon; //cosa add for rssi + bool bToSelfBA; //cosa add for rssi + char cck_adc_pwdb[4]; //cosa add for rx path selection + u16 Seq_Num; + u8 nTotalAggPkt; // Number of aggregated packets. +#endif + +}; + +/* IEEE 802.11 requires that STA supports concurrent reception of at least + * three fragmented frames. This define can be increased to support more + * concurrent frames, but it should be noted that each entry can consume about + * 2 kB of RAM and increasing cache size will slow down frame reassembly. */ +#define IEEE80211_FRAG_CACHE_LEN 4 + +struct ieee80211_frag_entry { + unsigned long first_frag_time; + unsigned int seq; + unsigned int last_frag; + struct sk_buff *skb; + u8 src_addr[ETH_ALEN]; + u8 dst_addr[ETH_ALEN]; +}; + +struct ieee80211_stats { + unsigned int tx_unicast_frames; + unsigned int tx_multicast_frames; + unsigned int tx_fragments; + unsigned int tx_unicast_octets; + unsigned int tx_multicast_octets; + unsigned int tx_deferred_transmissions; + unsigned int tx_single_retry_frames; + unsigned int tx_multiple_retry_frames; + unsigned int tx_retry_limit_exceeded; + unsigned int tx_discards; + unsigned int rx_unicast_frames; + unsigned int rx_multicast_frames; + unsigned int rx_fragments; + unsigned int rx_unicast_octets; + unsigned int rx_multicast_octets; + unsigned int rx_fcs_errors; + unsigned int rx_discards_no_buffer; + unsigned int tx_discards_wrong_sa; + unsigned int rx_discards_undecryptable; + unsigned int rx_message_in_msg_fragments; + unsigned int rx_message_in_bad_msg_fragments; +}; + +struct ieee80211_device; + +#include "ieee80211_crypt.h" + +#define SEC_KEY_1 (1<<0) +#define SEC_KEY_2 (1<<1) +#define SEC_KEY_3 (1<<2) +#define SEC_KEY_4 (1<<3) +#define SEC_ACTIVE_KEY (1<<4) +#define SEC_AUTH_MODE (1<<5) +#define SEC_UNICAST_GROUP (1<<6) +#define SEC_LEVEL (1<<7) +#define SEC_ENABLED (1<<8) +#define SEC_ENCRYPT (1<<9) + +#define SEC_LEVEL_0 0 /* None */ +#define SEC_LEVEL_1 1 /* WEP 40 and 104 bit */ +#define SEC_LEVEL_2 2 /* Level 1 + TKIP */ +#define SEC_LEVEL_2_CKIP 3 /* Level 1 + CKIP */ +#define SEC_LEVEL_3 4 /* Level 2 + CCMP */ + +#define SEC_ALG_NONE 0 +#define SEC_ALG_WEP 1 +#define SEC_ALG_TKIP 2 +#define SEC_ALG_CCMP 3 + +#define WEP_KEYS 4 +#define WEP_KEY_LEN 13 +#define SCM_KEY_LEN 32 +#define SCM_TEMPORAL_KEY_LENGTH 16 + +struct ieee80211_security { + u16 active_key:2, + enabled:1, + auth_mode:2, + auth_algo:4, + unicast_uses_group:1, + encrypt:1; + u8 key_sizes[WEP_KEYS]; + u8 keys[WEP_KEYS][SCM_KEY_LEN]; + u8 level; + u16 flags; +} __attribute__ ((packed)); + + +/* + 802.11 data frame from AP + ,-------------------------------------------------------------------. +Bytes | 2 | 2 | 6 | 6 | 6 | 2 | 0..2312 | 4 | + |------|------|---------|---------|---------|------|---------|------| +Desc. | ctrl | dura | DA/RA | TA | SA | Sequ | frame | fcs | + | | tion | (BSSID) | | | ence | data | | + `-------------------------------------------------------------------' +Total: 28-2340 bytes +*/ + +/* Management Frame Information Element Types */ +enum ieee80211_mfie { + MFIE_TYPE_SSID = 0, + MFIE_TYPE_RATES = 1, + MFIE_TYPE_FH_SET = 2, + MFIE_TYPE_DS_SET = 3, + MFIE_TYPE_CF_SET = 4, + MFIE_TYPE_TIM = 5, + MFIE_TYPE_IBSS_SET = 6, + MFIE_TYPE_COUNTRY = 7, + MFIE_TYPE_HOP_PARAMS = 8, + MFIE_TYPE_HOP_TABLE = 9, + MFIE_TYPE_REQUEST = 10, + MFIE_TYPE_CHALLENGE = 16, + MFIE_TYPE_POWER_CONSTRAINT = 32, + MFIE_TYPE_POWER_CAPABILITY = 33, + MFIE_TYPE_TPC_REQUEST = 34, + MFIE_TYPE_TPC_REPORT = 35, + MFIE_TYPE_SUPP_CHANNELS = 36, + MFIE_TYPE_CSA = 37, + MFIE_TYPE_MEASURE_REQUEST = 38, + MFIE_TYPE_MEASURE_REPORT = 39, + MFIE_TYPE_QUIET = 40, + MFIE_TYPE_IBSS_DFS = 41, + MFIE_TYPE_ERP = 42, + MFIE_TYPE_RSN = 48, + MFIE_TYPE_RATES_EX = 50, + MFIE_TYPE_HT_CAP= 45, + MFIE_TYPE_HT_INFO= 61, + MFIE_TYPE_AIRONET=133, + MFIE_TYPE_GENERIC = 221, + MFIE_TYPE_QOS_PARAMETER = 222, +}; + +/* Minimal header; can be used for passing 802.11 frames with sufficient + * information to determine what type of underlying data type is actually + * stored in the data. */ +struct ieee80211_hdr { + __le16 frame_ctl; + __le16 duration_id; + u8 payload[0]; +} __attribute__ ((packed)); + +struct ieee80211_hdr_1addr { + __le16 frame_ctl; + __le16 duration_id; + u8 addr1[ETH_ALEN]; + u8 payload[0]; +} __attribute__ ((packed)); + +struct ieee80211_hdr_2addr { + __le16 frame_ctl; + __le16 duration_id; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 payload[0]; +} __attribute__ ((packed)); + +struct ieee80211_hdr_3addr { + __le16 frame_ctl; + __le16 duration_id; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 addr3[ETH_ALEN]; + __le16 seq_ctl; + u8 payload[0]; +} __attribute__ ((packed)); + +struct ieee80211_hdr_4addr { + __le16 frame_ctl; + __le16 duration_id; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 addr3[ETH_ALEN]; + __le16 seq_ctl; + u8 addr4[ETH_ALEN]; + u8 payload[0]; +} __attribute__ ((packed)); + +struct ieee80211_hdr_3addrqos { + __le16 frame_ctl; + __le16 duration_id; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 addr3[ETH_ALEN]; + __le16 seq_ctl; + u8 payload[0]; + __le16 qos_ctl; +} __attribute__ ((packed)); + +struct ieee80211_hdr_4addrqos { + __le16 frame_ctl; + __le16 duration_id; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 addr3[ETH_ALEN]; + __le16 seq_ctl; + u8 addr4[ETH_ALEN]; + u8 payload[0]; + __le16 qos_ctl; +} __attribute__ ((packed)); + +struct ieee80211_info_element { + u8 id; + u8 len; + u8 data[0]; +} __attribute__ ((packed)); + +struct ieee80211_authentication { + struct ieee80211_hdr_3addr header; + __le16 algorithm; + __le16 transaction; + __le16 status; + /*challenge*/ + struct ieee80211_info_element info_element[0]; +} __attribute__ ((packed)); + +struct ieee80211_disassoc { + struct ieee80211_hdr_3addr header; + __le16 reason; +} __attribute__ ((packed)); + +struct ieee80211_probe_request { + struct ieee80211_hdr_3addr header; + /* SSID, supported rates */ + struct ieee80211_info_element info_element[0]; +} __attribute__ ((packed)); + +struct ieee80211_probe_response { + struct ieee80211_hdr_3addr header; + u32 time_stamp[2]; + __le16 beacon_interval; + __le16 capability; + /* SSID, supported rates, FH params, DS params, + * CF params, IBSS params, TIM (if beacon), RSN */ + struct ieee80211_info_element info_element[0]; +} __attribute__ ((packed)); + +/* Alias beacon for probe_response */ +#define ieee80211_beacon ieee80211_probe_response + +struct ieee80211_assoc_request_frame { + struct ieee80211_hdr_3addr header; + __le16 capability; + __le16 listen_interval; + /* SSID, supported rates, RSN */ + struct ieee80211_info_element info_element[0]; +} __attribute__ ((packed)); + +struct ieee80211_reassoc_request_frame { + struct ieee80211_hdr_3addr header; + __le16 capability; + __le16 listen_interval; + u8 current_ap[ETH_ALEN]; + /* SSID, supported rates, RSN */ + struct ieee80211_info_element info_element[0]; +} __attribute__ ((packed)); + +struct ieee80211_assoc_response_frame { + struct ieee80211_hdr_3addr header; + __le16 capability; + __le16 status; + __le16 aid; + struct ieee80211_info_element info_element[0]; /* supported rates */ +} __attribute__ ((packed)); + +struct ieee80211_txb { + u8 nr_frags; + u8 encrypted; + u8 queue_index; + u8 rts_included; + u16 reserved; + __le16 frag_size; + __le16 payload_size; + struct sk_buff *fragments[0]; +}; + +#define MAX_TX_AGG_COUNT 16 +struct ieee80211_drv_agg_txb { + u8 nr_drv_agg_frames; + struct sk_buff *tx_agg_frames[MAX_TX_AGG_COUNT]; +}__attribute__((packed)); + +#define MAX_SUBFRAME_COUNT 64 +struct ieee80211_rxb { + u8 nr_subframes; + struct sk_buff *subframes[MAX_SUBFRAME_COUNT]; + u8 dst[ETH_ALEN]; + u8 src[ETH_ALEN]; +}__attribute__((packed)); + +typedef union _frameqos { + u16 shortdata; + u8 chardata[2]; + struct { + u16 tid:4; + u16 eosp:1; + u16 ack_policy:2; + u16 reserved:1; + u16 txop:8; + }field; +}frameqos,*pframeqos; + +/* SWEEP TABLE ENTRIES NUMBER*/ +#define MAX_SWEEP_TAB_ENTRIES 42 +#define MAX_SWEEP_TAB_ENTRIES_PER_PACKET 7 +/* MAX_RATES_LENGTH needs to be 12. The spec says 8, and many APs + * only use 8, and then use extended rates for the remaining supported + * rates. Other APs, however, stick all of their supported rates on the + * main rates information element... */ +#define MAX_RATES_LENGTH ((u8)12) +#define MAX_RATES_EX_LENGTH ((u8)16) +#define MAX_NETWORK_COUNT 128 + +#define MAX_CHANNEL_NUMBER 161 +#define IEEE80211_SOFTMAC_SCAN_TIME 100 +//(HZ / 2) +#define IEEE80211_SOFTMAC_ASSOC_RETRY_TIME (HZ * 2) + +#define CRC_LENGTH 4U + +#define MAX_WPA_IE_LEN 64 + +#define NETWORK_EMPTY_ESSID (1<<0) +#define NETWORK_HAS_OFDM (1<<1) +#define NETWORK_HAS_CCK (1<<2) + +/* QoS structure */ +#define NETWORK_HAS_QOS_PARAMETERS (1<<3) +#define NETWORK_HAS_QOS_INFORMATION (1<<4) +#define NETWORK_HAS_QOS_MASK (NETWORK_HAS_QOS_PARAMETERS | \ + NETWORK_HAS_QOS_INFORMATION) +/* 802.11h */ +#define NETWORK_HAS_POWER_CONSTRAINT (1<<5) +#define NETWORK_HAS_CSA (1<<6) +#define NETWORK_HAS_QUIET (1<<7) +#define NETWORK_HAS_IBSS_DFS (1<<8) +#define NETWORK_HAS_TPC_REPORT (1<<9) + +#define NETWORK_HAS_ERP_VALUE (1<<10) + +#define QOS_QUEUE_NUM 4 +#define QOS_OUI_LEN 3 +#define QOS_OUI_TYPE 2 +#define QOS_ELEMENT_ID 221 +#define QOS_OUI_INFO_SUB_TYPE 0 +#define QOS_OUI_PARAM_SUB_TYPE 1 +#define QOS_VERSION_1 1 +#define QOS_AIFSN_MIN_VALUE 2 +#if 1 +struct ieee80211_qos_information_element { + u8 elementID; + u8 length; + u8 qui[QOS_OUI_LEN]; + u8 qui_type; + u8 qui_subtype; + u8 version; + u8 ac_info; +} __attribute__ ((packed)); + +struct ieee80211_qos_ac_parameter { + u8 aci_aifsn; + u8 ecw_min_max; + __le16 tx_op_limit; +} __attribute__ ((packed)); + +struct ieee80211_qos_parameter_info { + struct ieee80211_qos_information_element info_element; + u8 reserved; + struct ieee80211_qos_ac_parameter ac_params_record[QOS_QUEUE_NUM]; +} __attribute__ ((packed)); + +struct ieee80211_qos_parameters { + __le16 cw_min[QOS_QUEUE_NUM]; + __le16 cw_max[QOS_QUEUE_NUM]; + u8 aifs[QOS_QUEUE_NUM]; + u8 flag[QOS_QUEUE_NUM]; + __le16 tx_op_limit[QOS_QUEUE_NUM]; +} __attribute__ ((packed)); + +struct ieee80211_qos_data { + struct ieee80211_qos_parameters parameters; + int active; + int supported; + u8 param_count; + u8 old_param_count; +}; + +struct ieee80211_tim_parameters { + u8 tim_count; + u8 tim_period; +} __attribute__ ((packed)); + +//#else +struct ieee80211_wmm_ac_param { + u8 ac_aci_acm_aifsn; + u8 ac_ecwmin_ecwmax; + u16 ac_txop_limit; +}; + +struct ieee80211_wmm_ts_info { + u8 ac_dir_tid; + u8 ac_up_psb; + u8 reserved; +} __attribute__ ((packed)); + +struct ieee80211_wmm_tspec_elem { + struct ieee80211_wmm_ts_info ts_info; + u16 norm_msdu_size; + u16 max_msdu_size; + u32 min_serv_inter; + u32 max_serv_inter; + u32 inact_inter; + u32 suspen_inter; + u32 serv_start_time; + u32 min_data_rate; + u32 mean_data_rate; + u32 peak_data_rate; + u32 max_burst_size; + u32 delay_bound; + u32 min_phy_rate; + u16 surp_band_allow; + u16 medium_time; +}__attribute__((packed)); +#endif +enum eap_type { + EAP_PACKET = 0, + EAPOL_START, + EAPOL_LOGOFF, + EAPOL_KEY, + EAPOL_ENCAP_ASF_ALERT +}; + +static const char *eap_types[] = { + [EAP_PACKET] = "EAP-Packet", + [EAPOL_START] = "EAPOL-Start", + [EAPOL_LOGOFF] = "EAPOL-Logoff", + [EAPOL_KEY] = "EAPOL-Key", + [EAPOL_ENCAP_ASF_ALERT] = "EAPOL-Encap-ASF-Alert" +}; + +static inline const char *eap_get_type(int type) +{ + return ((u32)type >= ARRAY_SIZE(eap_types)) ? "Unknown" : eap_types[type]; +} +//added by amy for reorder +static inline u8 Frame_QoSTID(u8* buf) +{ + struct ieee80211_hdr_3addr *hdr; + u16 fc; + hdr = (struct ieee80211_hdr_3addr *)buf; + fc = le16_to_cpu(hdr->frame_ctl); + return (u8)((frameqos*)(buf + (((fc & IEEE80211_FCTL_TODS)&&(fc & IEEE80211_FCTL_FROMDS))? 30 : 24)))->field.tid; +} + +//added by amy for reorder + +struct eapol { + u8 snap[6]; + u16 ethertype; + u8 version; + u8 type; + u16 length; +} __attribute__ ((packed)); + +struct ieee80211_softmac_stats{ + unsigned int rx_ass_ok; + unsigned int rx_ass_err; + unsigned int rx_probe_rq; + unsigned int tx_probe_rs; + unsigned int tx_beacons; + unsigned int rx_auth_rq; + unsigned int rx_auth_rs_ok; + unsigned int rx_auth_rs_err; + unsigned int tx_auth_rq; + unsigned int no_auth_rs; + unsigned int no_ass_rs; + unsigned int tx_ass_rq; + unsigned int rx_ass_rq; + unsigned int tx_probe_rq; + unsigned int reassoc; + unsigned int swtxstop; + unsigned int swtxawake; + unsigned char CurrentShowTxate; + unsigned char last_packet_rate; + unsigned int txretrycount; +}; + +#define BEACON_PROBE_SSID_ID_POSITION 12 + +struct ieee80211_info_element_hdr { + u8 id; + u8 len; +} __attribute__ ((packed)); + +/* + * These are the data types that can make up management packets + * + u16 auth_algorithm; + u16 auth_sequence; + u16 beacon_interval; + u16 capability; + u8 current_ap[ETH_ALEN]; + u16 listen_interval; + struct { + u16 association_id:14, reserved:2; + } __attribute__ ((packed)); + u32 time_stamp[2]; + u16 reason; + u16 status; +*/ + +#define IEEE80211_DEFAULT_TX_ESSID "Penguin" +#define IEEE80211_DEFAULT_BASIC_RATE 2 //1Mbps + +enum {WMM_all_frame, WMM_two_frame, WMM_four_frame, WMM_six_frame}; +#define MAX_SP_Len (WMM_all_frame << 4) +#define IEEE80211_QOS_TID 0x0f +#define QOS_CTL_NOTCONTAIN_ACK (0x01 << 5) + +#define IEEE80211_DTIM_MBCAST 4 +#define IEEE80211_DTIM_UCAST 2 +#define IEEE80211_DTIM_VALID 1 +#define IEEE80211_DTIM_INVALID 0 + +#define IEEE80211_PS_DISABLED 0 +#define IEEE80211_PS_UNICAST IEEE80211_DTIM_UCAST +#define IEEE80211_PS_MBCAST IEEE80211_DTIM_MBCAST + +//added by David for QoS 2006/6/30 +//#define WMM_Hang_8187 +#ifdef WMM_Hang_8187 +#undef WMM_Hang_8187 +#endif + +#define WME_AC_BK 0x00 +#define WME_AC_BE 0x01 +#define WME_AC_VI 0x02 +#define WME_AC_VO 0x03 +#define WME_ACI_MASK 0x03 +#define WME_AIFSN_MASK 0x03 +#define WME_AC_PRAM_LEN 16 + +#define MAX_RECEIVE_BUFFER_SIZE 9100 + +//UP Mapping to AC, using in MgntQuery_SequenceNumber() and maybe for DSCP +//#define UP2AC(up) ((up<3) ? ((up==0)?1:0) : (up>>1)) +#if 1 +#define UP2AC(up) ( \ + ((up) < 1) ? WME_AC_BE : \ + ((up) < 3) ? WME_AC_BK : \ + ((up) < 4) ? WME_AC_BE : \ + ((up) < 6) ? WME_AC_VI : \ + WME_AC_VO) +#endif +//AC Mapping to UP, using in Tx part for selecting the corresponding TX queue +#define AC2UP(_ac) ( \ + ((_ac) == WME_AC_VO) ? 6 : \ + ((_ac) == WME_AC_VI) ? 5 : \ + ((_ac) == WME_AC_BK) ? 1 : \ + 0) + +#define ETHER_ADDR_LEN 6 /* length of an Ethernet address */ +#define ETHERNET_HEADER_SIZE 14 /* length of two Ethernet address plus ether type*/ + +struct ether_header { + u8 ether_dhost[ETHER_ADDR_LEN]; + u8 ether_shost[ETHER_ADDR_LEN]; + u16 ether_type; +} __attribute__((packed)); + +#ifndef ETHERTYPE_PAE +#define ETHERTYPE_PAE 0x888e /* EAPOL PAE/802.1x */ +#endif +#ifndef ETHERTYPE_IP +#define ETHERTYPE_IP 0x0800 /* IP protocol */ +#endif + +typedef struct _bss_ht{ + + bool support_ht; + + // HT related elements + u8 ht_cap_buf[32]; + u16 ht_cap_len; + u8 ht_info_buf[32]; + u16 ht_info_len; + + HT_SPEC_VER ht_spec_ver; + //HT_CAPABILITY_ELE bdHTCapEle; + //HT_INFORMATION_ELE bdHTInfoEle; + + bool aggregation; + bool long_slot_time; +}bss_ht, *pbss_ht; + +typedef enum _erp_t{ + ERP_NonERPpresent = 0x01, + ERP_UseProtection = 0x02, + ERP_BarkerPreambleMode = 0x04, +} erp_t; + + +struct ieee80211_network { + /* These entries are used to identify a unique network */ + u8 bssid[ETH_ALEN]; + u8 channel; + /* Ensure null-terminated for any debug msgs */ + u8 ssid[IW_ESSID_MAX_SIZE + 1]; + u8 ssid_len; +#if 1 + struct ieee80211_qos_data qos_data; +#else + // Qos related. Added by Annie, 2005-11-01. + BSS_QOS BssQos; +#endif + + //added by amy for LEAP + bool bWithAironetIE; + bool bCkipSupported; + bool bCcxRmEnable; + u16 CcxRmState[2]; + // CCXv4 S59, MBSSID. + bool bMBssidValid; + u8 MBssidMask; + u8 MBssid[6]; + // CCX 2 S38, WLAN Device Version Number element. Annie, 2006-08-20. + bool bWithCcxVerNum; + u8 BssCcxVerNumber; + /* These are network statistics */ + struct ieee80211_rx_stats stats; + u16 capability; + u8 rates[MAX_RATES_LENGTH]; + u8 rates_len; + u8 rates_ex[MAX_RATES_EX_LENGTH]; + u8 rates_ex_len; + unsigned long last_scanned; + u8 mode; + u32 flags; + u32 last_associate; + u32 time_stamp[2]; + u16 beacon_interval; + u16 listen_interval; + u16 atim_window; + u8 erp_value; + u8 wpa_ie[MAX_WPA_IE_LEN]; + size_t wpa_ie_len; + u8 rsn_ie[MAX_WPA_IE_LEN]; + size_t rsn_ie_len; + + struct ieee80211_tim_parameters tim; + u8 dtim_period; + u8 dtim_data; + u32 last_dtim_sta_time[2]; + + //appeded for QoS + u8 wmm_info; + struct ieee80211_wmm_ac_param wmm_param[4]; + u8 QoS_Enable; +#ifdef THOMAS_TURBO + u8 Turbo_Enable;//enable turbo mode, added by thomas +#endif +#ifdef ENABLE_DOT11D + u16 CountryIeLen; + u8 CountryIeBuf[MAX_IE_LEN]; +#endif + // HT Related, by amy, 2008.04.29 + BSS_HT bssht; + // Add to handle broadcom AP management frame CCK rate. + bool broadcom_cap_exist; + bool realtek_cap_exit; + bool marvell_cap_exist; + bool ralink_cap_exist; + bool atheros_cap_exist; + bool cisco_cap_exist; + bool unknown_cap_exist; +// u8 berp_info; + bool berp_info_valid; + bool buseprotection; + //put at the end of the structure. + struct list_head list; +}; + +#if 1 +enum ieee80211_state { + + /* the card is not linked at all */ + IEEE80211_NOLINK = 0, + + /* IEEE80211_ASSOCIATING* are for BSS client mode + * the driver shall not perform RX filtering unless + * the state is LINKED. + * The driver shall just check for the state LINKED and + * defaults to NOLINK for ALL the other states (including + * LINKED_SCANNING) + */ + + /* the association procedure will start (wq scheduling)*/ + IEEE80211_ASSOCIATING, + IEEE80211_ASSOCIATING_RETRY, + + /* the association procedure is sending AUTH request*/ + IEEE80211_ASSOCIATING_AUTHENTICATING, + + /* the association procedure has successfully authentcated + * and is sending association request + */ + IEEE80211_ASSOCIATING_AUTHENTICATED, + + /* the link is ok. the card associated to a BSS or linked + * to a ibss cell or acting as an AP and creating the bss + */ + IEEE80211_LINKED, + + /* same as LINKED, but the driver shall apply RX filter + * rules as we are in NO_LINK mode. As the card is still + * logically linked, but it is doing a syncro site survey + * then it will be back to LINKED state. + */ + IEEE80211_LINKED_SCANNING, + +}; +#else +enum ieee80211_state { + IEEE80211_UNINITIALIZED = 0, + IEEE80211_INITIALIZED, + IEEE80211_ASSOCIATING, + IEEE80211_ASSOCIATED, + IEEE80211_AUTHENTICATING, + IEEE80211_AUTHENTICATED, + IEEE80211_SHUTDOWN +}; +#endif + +#define DEFAULT_MAX_SCAN_AGE (15 * HZ) +#define DEFAULT_FTS 2346 + +#define CFG_IEEE80211_RESERVE_FCS (1<<0) +#define CFG_IEEE80211_COMPUTE_FCS (1<<1) +#define CFG_IEEE80211_RTS (1<<2) + +#define IEEE80211_24GHZ_MIN_CHANNEL 1 +#define IEEE80211_24GHZ_MAX_CHANNEL 14 +#define IEEE80211_24GHZ_CHANNELS (IEEE80211_24GHZ_MAX_CHANNEL - \ + IEEE80211_24GHZ_MIN_CHANNEL + 1) + +#define IEEE80211_52GHZ_MIN_CHANNEL 34 +#define IEEE80211_52GHZ_MAX_CHANNEL 165 +#define IEEE80211_52GHZ_CHANNELS (IEEE80211_52GHZ_MAX_CHANNEL - \ + IEEE80211_52GHZ_MIN_CHANNEL + 1) + +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,11)) +extern inline int is_multicast_ether_addr(const u8 *addr) +{ + return ((addr[0] != 0xff) && (0x01 & addr[0])); +} +#endif + +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13)) +extern inline int is_broadcast_ether_addr(const u8 *addr) +{ + return ((addr[0] == 0xff) && (addr[1] == 0xff) && (addr[2] == 0xff) && \ + (addr[3] == 0xff) && (addr[4] == 0xff) && (addr[5] == 0xff)); +} +#endif + +typedef struct tx_pending_t{ + int frag; + struct ieee80211_txb *txb; +}tx_pending_t; + +typedef struct _bandwidth_autoswitch +{ + long threshold_20Mhzto40Mhz; + long threshold_40Mhzto20Mhz; + bool bforced_tx20Mhz; + bool bautoswitch_enable; +}bandwidth_autoswitch,*pbandwidth_autoswitch; + + +//added by amy for order + +#define REORDER_WIN_SIZE 128 +#define REORDER_ENTRY_NUM 128 +typedef struct _RX_REORDER_ENTRY +{ + struct list_head List; + u16 SeqNum; + struct ieee80211_rxb* prxb; +} RX_REORDER_ENTRY, *PRX_REORDER_ENTRY; +//added by amy for order +typedef enum _Fsync_State{ + Default_Fsync, + HW_Fsync, + SW_Fsync +}Fsync_State; + +// Power save mode configured. +typedef enum _RT_PS_MODE +{ + eActive, // Active/Continuous access. + eMaxPs, // Max power save mode. + eFastPs // Fast power save mode. +}RT_PS_MODE; + +typedef enum _IPS_CALLBACK_FUNCION +{ + IPS_CALLBACK_NONE = 0, + IPS_CALLBACK_MGNT_LINK_REQUEST = 1, + IPS_CALLBACK_JOIN_REQUEST = 2, +}IPS_CALLBACK_FUNCION; + +typedef enum _RT_JOIN_ACTION{ + RT_JOIN_INFRA = 1, + RT_JOIN_IBSS = 2, + RT_START_IBSS = 3, + RT_NO_ACTION = 4, +}RT_JOIN_ACTION; + +typedef struct _IbssParms{ + u16 atimWin; +}IbssParms, *PIbssParms; +#define MAX_NUM_RATES 264 // Max num of support rates element: 8, Max num of ext. support rate: 255. 061122, by rcnjko. + +// RF state. +typedef enum _RT_RF_POWER_STATE +{ + eRfOn, + eRfSleep, + eRfOff +}RT_RF_POWER_STATE; + +typedef struct _RT_POWER_SAVE_CONTROL +{ + + // + // Inactive Power Save(IPS) : Disable RF when disconnected + // + bool bInactivePs; + bool bIPSModeBackup; + bool bHaltAdapterClkRQ; + bool bSwRfProcessing; + RT_RF_POWER_STATE eInactivePowerState; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + struct work_struct InactivePsWorkItem; +#else + struct tq_struct InactivePsWorkItem; +#endif + struct timer_list InactivePsTimer; + + // Return point for join action + IPS_CALLBACK_FUNCION ReturnPoint; + + // Recored Parameters for rescheduled JoinRequest + bool bTmpBssDesc; + RT_JOIN_ACTION tmpJoinAction; + struct ieee80211_network tmpBssDesc; + + // Recored Parameters for rescheduled MgntLinkRequest + bool bTmpScanOnly; + bool bTmpActiveScan; + bool bTmpFilterHiddenAP; + bool bTmpUpdateParms; + u8 tmpSsidBuf[33]; + OCTET_STRING tmpSsid2Scan; + bool bTmpSsid2Scan; + u8 tmpNetworkType; + u8 tmpChannelNumber; + u16 tmpBcnPeriod; + u8 tmpDtimPeriod; + u16 tmpmCap; + OCTET_STRING tmpSuppRateSet; + u8 tmpSuppRateBuf[MAX_NUM_RATES]; + bool bTmpSuppRate; + IbssParms tmpIbpm; + bool bTmpIbpm; + + // + // Leisre Poswer Save : Disable RF if connected but traffic is not busy + // + bool bLeisurePs; + u32 PowerProfile; + u8 LpsIdleCount; + u8 RegMaxLPSAwakeIntvl; + u8 LPSAwakeIntvl; + + //RF OFF Level + u32 CurPsLevel; + u32 RegRfPsLevel; + + //Fw Control LPS + bool bFwCtrlLPS; + u8 FWCtrlPSMode; + + //2009.01.01 added by tynli + // Record if there is a link request in IPS RF off progress. + bool LinkReqInIPSRFOffPgs; + // To make sure that connect info should be executed, so we set the bit to filter the link info which comes after the connect info. + bool BufConnectinfoBefore; + +}RT_POWER_SAVE_CONTROL,*PRT_POWER_SAVE_CONTROL; + +typedef u32 RT_RF_CHANGE_SOURCE; +#define RF_CHANGE_BY_SW BIT31 +#define RF_CHANGE_BY_HW BIT30 +#define RF_CHANGE_BY_PS BIT29 +#define RF_CHANGE_BY_IPS BIT28 +#define RF_CHANGE_BY_INIT 0 // Do not change the RFOff reason. Defined by Bruce, 2008-01-17. + +#ifdef ENABLE_DOT11D +typedef enum +{ + COUNTRY_CODE_FCC = 0, + COUNTRY_CODE_IC = 1, + COUNTRY_CODE_ETSI = 2, + COUNTRY_CODE_SPAIN = 3, + COUNTRY_CODE_FRANCE = 4, + COUNTRY_CODE_MKK = 5, + COUNTRY_CODE_MKK1 = 6, + COUNTRY_CODE_ISRAEL = 7, + COUNTRY_CODE_TELEC, + COUNTRY_CODE_MIC, + COUNTRY_CODE_GLOBAL_DOMAIN +}country_code_type_t; +#endif + // Firmware realted CMD IO. +typedef enum _FW_CMD_IO_TYPE{ + FW_CMD_DIG_ENABLE = 0, // For DIG DM + FW_CMD_DIG_DISABLE = 1, + FW_CMD_DIG_HALT = 2, + FW_CMD_DIG_RESUME = 3, + FW_CMD_HIGH_PWR_ENABLE = 4, // For High Power DM + FW_CMD_HIGH_PWR_DISABLE = 5, + FW_CMD_RA_RESET = 6, // For Rate adaptive DM + FW_CMD_RA_ACTIVE= 7, + FW_CMD_RA_REFRESH_N= 8, + FW_CMD_RA_REFRESH_BG= 9, + FW_CMD_IQK_ENABLE = 10, // For FW supported IQK + FW_CMD_TXPWR_TRACK_ENABLE = 11, // Tx power tracking switch + FW_CMD_TXPWR_TRACK_DISABLE = 12, // Tx power tracking switch + FW_CMD_PAUSE_DM_BY_SCAN = 13, + FW_CMD_RESUME_DM_BY_SCAN = 14, + FW_CMD_MID_HIGH_PWR_ENABLE = 15, + FW_CMD_LPS_ENTER = 16, // Indifate firmware that driver enters LPS, For PS-Poll hardware bug + FW_CMD_LPS_LEAVE = 17, // Indicate firmware that driver leave LPS, 2009/1/4, by Emily +}FW_CMD_IO_TYPE,*PFW_CMD_IO_TYPE; +#define RT_MAX_LD_SLOT_NUM 10 +typedef struct _RT_LINK_DETECT_T{ + + u32 NumRecvBcnInPeriod; + u32 NumRecvDataInPeriod; + + u32 RxBcnNum[RT_MAX_LD_SLOT_NUM]; // number of Rx beacon / CheckForHang_period to determine link status + u32 RxDataNum[RT_MAX_LD_SLOT_NUM]; // number of Rx data / CheckForHang_period to determine link status + u16 SlotNum; // number of CheckForHang period to determine link status + u16 SlotIndex; + + u32 NumTxOkInPeriod; + u32 NumRxOkInPeriod; + bool bBusyTraffic; +}RT_LINK_DETECT_T, *PRT_LINK_DETECT_T; + + +struct ieee80211_device { + struct net_device *dev; + struct ieee80211_security sec; + + //hw security related +// u8 hwsec_support; //support? + u8 hwsec_active; //hw security active. + bool is_silent_reset; + bool is_roaming; + bool ieee_up; + //added by amy + bool bSupportRemoteWakeUp; + RT_PS_MODE dot11PowerSaveMode; // Power save mode configured. + bool actscanning; + //added by amy 090313 + bool be_scan_inprogress; + bool beinretry; + RT_RF_POWER_STATE eRFPowerState; + RT_RF_CHANGE_SOURCE RfOffReason; + bool is_set_key; + //11n spec related I wonder if These info structure need to be moved out of ieee80211_device + + //11n HT below + PRT_HIGH_THROUGHPUT pHTInfo; + //struct timer_list SwBwTimer; +// spinlock_t chnlop_spinlock; + spinlock_t bw_spinlock; + + spinlock_t reorder_spinlock; + // for HT operation rate set. we use this one for HT data rate to seperate different descriptors + //the way fill this is the same as in the IE + u8 Regdot11HTOperationalRateSet[16]; //use RATR format + u8 dot11HTOperationalRateSet[16]; //use RATR format + u8 RegHTSuppRateSet[16]; + u8 HTCurrentOperaRate; + u8 HTHighestOperaRate; + //wb added for rate operation mode to firmware + u8 bTxDisableRateFallBack; + u8 bTxUseDriverAssingedRate; + atomic_t atm_chnlop; + atomic_t atm_swbw; +// u8 HTHighestOperaRate; +// u8 HTCurrentOperaRate; + + // 802.11e and WMM Traffic Stream Info (TX) + struct list_head Tx_TS_Admit_List; + struct list_head Tx_TS_Pending_List; + struct list_head Tx_TS_Unused_List; + TX_TS_RECORD TxTsRecord[TOTAL_TS_NUM]; + // 802.11e and WMM Traffic Stream Info (RX) + struct list_head Rx_TS_Admit_List; + struct list_head Rx_TS_Pending_List; + struct list_head Rx_TS_Unused_List; + RX_TS_RECORD RxTsRecord[TOTAL_TS_NUM]; +//#ifdef TO_DO_LIST + RX_REORDER_ENTRY RxReorderEntry[128]; + struct list_head RxReorder_Unused_List; +//#endif + // Qos related. Added by Annie, 2005-11-01. +// PSTA_QOS pStaQos; + u8 ForcedPriority; // Force per-packet priority 1~7. (default: 0, not to force it.) + + + /* Bookkeeping structures */ + struct net_device_stats stats; + struct ieee80211_stats ieee_stats; + struct ieee80211_softmac_stats softmac_stats; + + /* Probe / Beacon management */ + struct list_head network_free_list; + struct list_head network_list; + struct ieee80211_network *networks; + int scans; + int scan_age; + + int iw_mode; /* operating mode (IW_MODE_*) */ + struct iw_spy_data spy_data; + + spinlock_t lock; + spinlock_t wpax_suitlist_lock; + + int tx_headroom; /* Set to size of any additional room needed at front + * of allocated Tx SKBs */ + u32 config; + + /* WEP and other encryption related settings at the device level */ + int open_wep; /* Set to 1 to allow unencrypted frames */ + int auth_mode; + int reset_on_keychange; /* Set to 1 if the HW needs to be reset on + * WEP key changes */ + + /* If the host performs {en,de}cryption, then set to 1 */ + int host_encrypt; + int host_encrypt_msdu; + int host_decrypt; + /* host performs multicast decryption */ + int host_mc_decrypt; + + /* host should strip IV and ICV from protected frames */ + /* meaningful only when hardware decryption is being used */ + int host_strip_iv_icv; + + int host_open_frag; + int host_build_iv; + int ieee802_1x; /* is IEEE 802.1X used */ + + /* WPA data */ + bool bHalfWirelessN24GMode; + int wpa_enabled; + int drop_unencrypted; + int tkip_countermeasures; + int privacy_invoked; + size_t wpa_ie_len; + u8 *wpa_ie; + u8 ap_mac_addr[6]; + u16 pairwise_key_type; + u16 group_key_type; + struct list_head crypt_deinit_list; + struct ieee80211_crypt_data *crypt[WEP_KEYS]; + int tx_keyidx; /* default TX key index (crypt[tx_keyidx]) */ + struct timer_list crypt_deinit_timer; + int crypt_quiesced; + + int bcrx_sta_key; /* use individual keys to override default keys even + * with RX of broad/multicast frames */ + + /* Fragmentation structures */ + // each streaming contain a entry + struct ieee80211_frag_entry frag_cache[17][IEEE80211_FRAG_CACHE_LEN]; + unsigned int frag_next_idx[17]; + u16 fts; /* Fragmentation Threshold */ +#define DEFAULT_RTS_THRESHOLD 2346U +#define MIN_RTS_THRESHOLD 1 +#define MAX_RTS_THRESHOLD 2346U + u16 rts; /* RTS threshold */ + + /* Association info */ + u8 bssid[ETH_ALEN]; + + /* This stores infos for the current network. + * Either the network we are associated in INFRASTRUCTURE + * or the network that we are creating in MASTER mode. + * ad-hoc is a mixture ;-). + * Note that in infrastructure mode, even when not associated, + * fields bssid and essid may be valid (if wpa_set and essid_set + * are true) as thy carry the value set by the user via iwconfig + */ + struct ieee80211_network current_network; + + enum ieee80211_state state; + + int short_slot; + int reg_mode; + int mode; /* A, B, G */ + int modulation; /* CCK, OFDM */ + int freq_band; /* 2.4Ghz, 5.2Ghz, Mixed */ + int abg_true; /* ABG flag */ + + /* used for forcing the ibss workqueue to terminate + * without wait for the syncro scan to terminate + */ + short sync_scan_hurryup; + u16 scan_watch_dog; + int perfect_rssi; + int worst_rssi; + + u16 prev_seq_ctl; /* used to drop duplicate frames */ + + /* map of allowed channels. 0 is dummy */ + // FIXME: remeber to default to a basic channel plan depending of the PHY type +#ifdef ENABLE_DOT11D + void* pDot11dInfo; + bool bGlobalDomain; +#else + int channel_map[MAX_CHANNEL_NUMBER+1]; +#endif + int rate; /* current rate */ + int basic_rate; + //FIXME: pleace callback, see if redundant with softmac_features + short active_scan; + + /* this contains flags for selectively enable softmac support */ + u16 softmac_features; + + /* if the sequence control field is not filled by HW */ + u16 seq_ctrl[5]; + + /* association procedure transaction sequence number */ + u16 associate_seq; + + /* AID for RTXed association responses */ + u16 assoc_id; + + /* power save mode related*/ + u8 ack_tx_to_ieee; + short ps; + short sta_sleep; + int ps_timeout; + int ps_period; + struct tasklet_struct ps_task; + u32 ps_th; + u32 ps_tl; + + short raw_tx; + /* used if IEEE_SOFTMAC_TX_QUEUE is set */ + short queue_stop; + short scanning; + short proto_started; + + struct semaphore wx_sem; + struct semaphore scan_sem; + + spinlock_t mgmt_tx_lock; + spinlock_t beacon_lock; + + short beacon_txing; + + short wap_set; + short ssid_set; + + u8 wpax_type_set; //{added by David, 2006.9.28} + u32 wpax_type_notify; //{added by David, 2006.9.26} + + /* QoS related flag */ + char init_wmmparam_flag; + /* set on initialization */ + u8 qos_support; + + /* for discarding duplicated packets in IBSS */ + struct list_head ibss_mac_hash[IEEE_IBSS_MAC_HASH_SIZE]; + + /* for discarding duplicated packets in BSS */ + u16 last_rxseq_num[17]; /* rx seq previous per-tid */ + u16 last_rxfrag_num[17];/* tx frag previous per-tid */ + unsigned long last_packet_time[17]; + + /* for PS mode */ + unsigned long last_rx_ps_time; + + /* used if IEEE_SOFTMAC_SINGLE_QUEUE is set */ + struct sk_buff *mgmt_queue_ring[MGMT_QUEUE_NUM]; + int mgmt_queue_head; + int mgmt_queue_tail; +//{ added for rtl819x +#define IEEE80211_QUEUE_LIMIT 128 + u8 AsocRetryCount; + unsigned int hw_header; + struct sk_buff_head skb_waitQ[MAX_QUEUE_SIZE]; + struct sk_buff_head skb_aggQ[MAX_QUEUE_SIZE]; + struct sk_buff_head skb_drv_aggQ[MAX_QUEUE_SIZE]; + u32 sta_edca_param[4]; + bool aggregation; + // Enable/Disable Rx immediate BA capability. + bool enable_rx_imm_BA; + bool bibsscoordinator; + + //+by amy for DM ,080515 + //Dynamic Tx power for near/far range enable/Disable , by amy , 2008-05-15 + bool bdynamic_txpower_enable; + + bool bCTSToSelfEnable; + u8 CTSToSelfTH; + + u32 fsync_time_interval; + u32 fsync_rate_bitmap; + u8 fsync_rssi_threshold; + bool bfsync_enable; + + u8 fsync_multiple_timeinterval; // FsyncMultipleTimeInterval * FsyncTimeInterval + u32 fsync_firstdiff_ratethreshold; // low threshold + u32 fsync_seconddiff_ratethreshold; // decrease threshold + Fsync_State fsync_state; + bool bis_any_nonbepkts; + //20Mhz 40Mhz AutoSwitch Threshold + bandwidth_autoswitch bandwidth_auto_switch; + //for txpower tracking + bool FwRWRF; + + //added by amy for AP roaming + RT_LINK_DETECT_T LinkDetectInfo; + //added by amy for ps + RT_POWER_SAVE_CONTROL PowerSaveControl; +//} + /* used if IEEE_SOFTMAC_TX_QUEUE is set */ + struct tx_pending_t tx_pending; + + /* used if IEEE_SOFTMAC_ASSOCIATE is set */ + struct timer_list associate_timer; + + /* used if IEEE_SOFTMAC_BEACONS is set */ + struct timer_list beacon_timer; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + struct work_struct associate_complete_wq; + struct work_struct associate_procedure_wq; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + struct delayed_work softmac_scan_wq; + struct delayed_work associate_retry_wq; + struct delayed_work start_ibss_wq; + struct delayed_work hw_wakeup_wq; + struct delayed_work hw_sleep_wq; + struct delayed_work link_change_wq; +#else + struct work_struct softmac_scan_wq; + struct work_struct associate_retry_wq; + struct work_struct start_ibss_wq; + struct work_struct hw_wakeup_wq; + struct work_struct hw_sleep_wq; + struct work_struct link_change_wq; +#endif + struct work_struct wx_sync_scan_wq; + struct workqueue_struct *wq; +#else + /* used for periodly scan */ + struct timer_list scan_timer; + + struct tq_struct associate_complete_wq; + struct tq_struct associate_retry_wq; + struct tq_struct start_ibss_wq; + struct tq_struct associate_procedure_wq; + struct tq_struct softmac_scan_wq; + struct tq_struct wx_sync_scan_wq; + struct tq_struct hw_wakeup_wq; + struct tq_struct hw_sleep_wq; + struct tq_struct link_change_wq; + +#endif + // Qos related. Added by Annie, 2005-11-01. + //STA_QOS StaQos; + + //u32 STA_EDCA_PARAM[4]; + //CHANNEL_ACCESS_SETTING ChannelAccessSetting; + + + /* Callback functions */ + void (*set_security)(struct net_device *dev, + struct ieee80211_security *sec); + + /* Used to TX data frame by using txb structs. + * this is not used if in the softmac_features + * is set the flag IEEE_SOFTMAC_TX_QUEUE + */ + int (*hard_start_xmit)(struct ieee80211_txb *txb, + struct net_device *dev); + + int (*reset_port)(struct net_device *dev); + int (*is_queue_full) (struct net_device * dev, int pri); + + int (*handle_management) (struct net_device * dev, + struct ieee80211_network * network, u16 type); + int (*is_qos_active) (struct net_device *dev, struct sk_buff *skb); + + /* Softmac-generated frames (mamagement) are TXed via this + * callback if the flag IEEE_SOFTMAC_SINGLE_QUEUE is + * not set. As some cards may have different HW queues that + * one might want to use for data and management frames + * the option to have two callbacks might be useful. + * This fucntion can't sleep. + */ + int (*softmac_hard_start_xmit)(struct sk_buff *skb, + struct net_device *dev); + + /* used instead of hard_start_xmit (not softmac_hard_start_xmit) + * if the IEEE_SOFTMAC_TX_QUEUE feature is used to TX data + * frames. I the option IEEE_SOFTMAC_SINGLE_QUEUE is also set + * then also management frames are sent via this callback. + * This function can't sleep. + */ + void (*softmac_data_hard_start_xmit)(struct sk_buff *skb, + struct net_device *dev,int rate); + + /* stops the HW queue for DATA frames. Useful to avoid + * waste time to TX data frame when we are reassociating + * This function can sleep. + */ + void (*data_hard_stop)(struct net_device *dev); + + /* OK this is complementar to data_poll_hard_stop */ + void (*data_hard_resume)(struct net_device *dev); + + /* ask to the driver to retune the radio . + * This function can sleep. the driver should ensure + * the radio has been swithced before return. + */ + void (*set_chan)(struct net_device *dev,short ch); + + /* These are not used if the ieee stack takes care of + * scanning (IEEE_SOFTMAC_SCAN feature set). + * In this case only the set_chan is used. + * + * The syncro version is similar to the start_scan but + * does not return until all channels has been scanned. + * this is called in user context and should sleep, + * it is called in a work_queue when swithcing to ad-hoc mode + * or in behalf of iwlist scan when the card is associated + * and root user ask for a scan. + * the fucntion stop_scan should stop both the syncro and + * background scanning and can sleep. + * The fucntion start_scan should initiate the background + * scanning and can't sleep. + */ + void (*scan_syncro)(struct net_device *dev); + void (*start_scan)(struct net_device *dev); + void (*stop_scan)(struct net_device *dev); + + /* indicate the driver that the link state is changed + * for example it may indicate the card is associated now. + * Driver might be interested in this to apply RX filter + * rules or simply light the LINK led + */ + void (*link_change)(struct net_device *dev); + + /* these two function indicates to the HW when to start + * and stop to send beacons. This is used when the + * IEEE_SOFTMAC_BEACONS is not set. For now the + * stop_send_bacons is NOT guaranteed to be called only + * after start_send_beacons. + */ + void (*start_send_beacons) (struct net_device *dev); + void (*stop_send_beacons) (struct net_device *dev); + + /* power save mode related */ + void (*sta_wake_up) (struct net_device *dev); +// void (*ps_request_tx_ack) (struct net_device *dev); + void (*enter_sleep_state) (struct net_device *dev, u32 th, u32 tl); + short (*ps_is_queue_empty) (struct net_device *dev); +#if 0 + /* Typical STA methods */ + int (*handle_auth) (struct net_device * dev, + struct ieee80211_auth * auth); + int (*handle_deauth) (struct net_device * dev, + struct ieee80211_deauth * auth); + int (*handle_action) (struct net_device * dev, + struct ieee80211_action * action, + struct ieee80211_rx_stats * stats); + int (*handle_disassoc) (struct net_device * dev, + struct ieee80211_disassoc * assoc); +#endif + int (*handle_beacon) (struct net_device * dev, struct ieee80211_beacon * beacon, struct ieee80211_network * network); +#if 0 + int (*handle_probe_response) (struct net_device * dev, + struct ieee80211_probe_response * resp, + struct ieee80211_network * network); + int (*handle_probe_request) (struct net_device * dev, + struct ieee80211_probe_request * req, + struct ieee80211_rx_stats * stats); +#endif + int (*handle_assoc_response) (struct net_device * dev, struct ieee80211_assoc_response_frame * resp, struct ieee80211_network * network); + +#if 0 + /* Typical AP methods */ + int (*handle_assoc_request) (struct net_device * dev); + int (*handle_reassoc_request) (struct net_device * dev, + struct ieee80211_reassoc_request * req); +#endif + + /* check whether Tx hw resouce available */ + short (*check_nic_enough_desc)(struct net_device *dev, int queue_index); + //added by wb for HT related +// void (*SwChnlByTimerHandler)(struct net_device *dev, int channel); + void (*SetBWModeHandler)(struct net_device *dev, HT_CHANNEL_WIDTH Bandwidth, HT_EXTCHNL_OFFSET Offset); +// void (*UpdateHalRATRTableHandler)(struct net_device* dev, u8* pMcsRate); + bool (*GetNmodeSupportBySecCfg)(struct net_device* dev); + void (*SetWirelessMode)(struct net_device* dev, u8 wireless_mode); + bool (*GetHalfNmodeSupportByAPsHandler)(struct net_device* dev); + bool (*is_ap_in_wep_tkip)(struct net_device* dev); + void (*InitialGainHandler)(struct net_device *dev, u8 Operation); + bool (*SetFwCmdHandler)(struct net_device *dev, FW_CMD_IO_TYPE FwCmdIO); + void (*LedControlHandler)(struct net_device * dev, LED_CTL_MODE LedAction); + /* This must be the last item so that it points to the data + * allocated beyond this structure by alloc_ieee80211 */ + u8 priv[0]; +}; + +#define IEEE_A (1<<0) +#define IEEE_B (1<<1) +#define IEEE_G (1<<2) +#define IEEE_N_24G (1<<4) +#define IEEE_N_5G (1<<5) +#define IEEE_MODE_MASK (IEEE_A|IEEE_B|IEEE_G) + +/* Generate a 802.11 header */ + +/* Uses the channel change callback directly + * instead of [start/stop] scan callbacks + */ +#define IEEE_SOFTMAC_SCAN (1<<2) + +/* Perform authentication and association handshake */ +#define IEEE_SOFTMAC_ASSOCIATE (1<<3) + +/* Generate probe requests */ +#define IEEE_SOFTMAC_PROBERQ (1<<4) + +/* Generate respones to probe requests */ +#define IEEE_SOFTMAC_PROBERS (1<<5) + +/* The ieee802.11 stack will manages the netif queue + * wake/stop for the driver, taking care of 802.11 + * fragmentation. See softmac.c for details. */ +#define IEEE_SOFTMAC_TX_QUEUE (1<<7) + +/* Uses only the softmac_data_hard_start_xmit + * even for TX management frames. + */ +#define IEEE_SOFTMAC_SINGLE_QUEUE (1<<8) + +/* Generate beacons. The stack will enqueue beacons + * to the card + */ +#define IEEE_SOFTMAC_BEACONS (1<<6) + +static inline void *ieee80211_priv(struct net_device *dev) +{ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + return ((struct ieee80211_device *)netdev_priv(dev))->priv; +#else + return ((struct ieee80211_device *)dev->priv)->priv; +#endif +} + +extern inline int ieee80211_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; +} + +extern inline int ieee80211_is_valid_mode(struct ieee80211_device *ieee, int mode) +{ + /* + * It is possible for both access points and our device to support + * combinations of modes, so as long as there is one valid combination + * of ap/device supported modes, then return success + * + */ + if ((mode & IEEE_A) && + (ieee->modulation & IEEE80211_OFDM_MODULATION) && + (ieee->freq_band & IEEE80211_52GHZ_BAND)) + return 1; + + if ((mode & IEEE_G) && + (ieee->modulation & IEEE80211_OFDM_MODULATION) && + (ieee->freq_band & IEEE80211_24GHZ_BAND)) + return 1; + + if ((mode & IEEE_B) && + (ieee->modulation & IEEE80211_CCK_MODULATION) && + (ieee->freq_band & IEEE80211_24GHZ_BAND)) + return 1; + + return 0; +} + +extern inline int ieee80211_get_hdrlen(u16 fc) +{ + int hdrlen = IEEE80211_3ADDR_LEN; + + switch (WLAN_FC_GET_TYPE(fc)) { + case IEEE80211_FTYPE_DATA: + if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS)) + hdrlen = IEEE80211_4ADDR_LEN; /* Addr4 */ + if(IEEE80211_QOS_HAS_SEQ(fc)) + hdrlen += 2; /* QOS ctrl*/ + break; + case IEEE80211_FTYPE_CTL: + switch (WLAN_FC_GET_STYPE(fc)) { + case IEEE80211_STYPE_CTS: + case IEEE80211_STYPE_ACK: + hdrlen = IEEE80211_1ADDR_LEN; + break; + default: + hdrlen = IEEE80211_2ADDR_LEN; + break; + } + break; + } + + return hdrlen; +} + +static inline u8 *ieee80211_get_payload(struct ieee80211_hdr *hdr) +{ + switch (ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl))) { + case IEEE80211_1ADDR_LEN: + return ((struct ieee80211_hdr_1addr *)hdr)->payload; + case IEEE80211_2ADDR_LEN: + return ((struct ieee80211_hdr_2addr *)hdr)->payload; + case IEEE80211_3ADDR_LEN: + return ((struct ieee80211_hdr_3addr *)hdr)->payload; + case IEEE80211_4ADDR_LEN: + return ((struct ieee80211_hdr_4addr *)hdr)->payload; + } + return NULL; +} + +static inline int ieee80211_is_ofdm_rate(u8 rate) +{ + switch (rate & ~IEEE80211_BASIC_RATE_MASK) { + case IEEE80211_OFDM_RATE_6MB: + case IEEE80211_OFDM_RATE_9MB: + case IEEE80211_OFDM_RATE_12MB: + case IEEE80211_OFDM_RATE_18MB: + case IEEE80211_OFDM_RATE_24MB: + case IEEE80211_OFDM_RATE_36MB: + case IEEE80211_OFDM_RATE_48MB: + case IEEE80211_OFDM_RATE_54MB: + return 1; + } + return 0; +} + +static inline int ieee80211_is_cck_rate(u8 rate) +{ + switch (rate & ~IEEE80211_BASIC_RATE_MASK) { + case IEEE80211_CCK_RATE_1MB: + case IEEE80211_CCK_RATE_2MB: + case IEEE80211_CCK_RATE_5MB: + case IEEE80211_CCK_RATE_11MB: + return 1; + } + return 0; +} + + +/* ieee80211.c */ +extern void free_ieee80211(struct net_device *dev); +extern struct net_device *alloc_ieee80211(int sizeof_priv); + +extern int ieee80211_set_encryption(struct ieee80211_device *ieee); + +/* ieee80211_tx.c */ + +extern int ieee80211_encrypt_fragment( + struct ieee80211_device *ieee, + struct sk_buff *frag, + int hdr_len); + +extern int ieee80211_xmit(struct sk_buff *skb, + struct net_device *dev); +extern void ieee80211_txb_free(struct ieee80211_txb *); + + +/* ieee80211_rx.c */ +extern int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, + struct ieee80211_rx_stats *rx_stats); +extern void ieee80211_rx_mgt(struct ieee80211_device *ieee, + struct ieee80211_hdr_4addr *header, + struct ieee80211_rx_stats *stats); + +/* ieee80211_wx.c */ +extern int ieee80211_wx_get_scan(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *key); +extern int ieee80211_wx_set_encode(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *key); +extern int ieee80211_wx_get_encode(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *key); +#if WIRELESS_EXT >= 18 +extern int ieee80211_wx_get_encode_ext(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data* wrqu, char *extra); +extern int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data* wrqu, char *extra); +extern int ieee80211_wx_set_auth(struct ieee80211_device *ieee, + struct iw_request_info *info, + struct iw_param *data, char *extra); +extern int ieee80211_wx_set_mlme(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); +#endif +extern int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len); + +/* ieee80211_softmac.c */ +extern short ieee80211_is_54g(struct ieee80211_network net); +extern short ieee80211_is_shortslot(struct ieee80211_network net); +extern int ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb, + struct ieee80211_rx_stats *rx_stats, u16 type, + u16 stype); +extern void ieee80211_softmac_new_net(struct ieee80211_device *ieee, struct ieee80211_network *net); + +void SendDisassociation(struct ieee80211_device *ieee, u8* asSta, u8 asRsn); +extern void ieee80211_softmac_xmit(struct ieee80211_txb *txb, struct ieee80211_device *ieee); + +extern void ieee80211_stop_send_beacons(struct ieee80211_device *ieee); +extern void notify_wx_assoc_event(struct ieee80211_device *ieee); +extern void ieee80211_softmac_check_all_nets(struct ieee80211_device *ieee); +extern void ieee80211_start_bss(struct ieee80211_device *ieee); +extern void ieee80211_start_master_bss(struct ieee80211_device *ieee); +extern void ieee80211_start_ibss(struct ieee80211_device *ieee); +extern void ieee80211_softmac_init(struct ieee80211_device *ieee); +extern void ieee80211_softmac_free(struct ieee80211_device *ieee); +extern void ieee80211_associate_abort(struct ieee80211_device *ieee); +extern void ieee80211_disassociate(struct ieee80211_device *ieee); +extern void ieee80211_stop_scan(struct ieee80211_device *ieee); +extern void ieee80211_start_scan_syncro(struct ieee80211_device *ieee); +extern void ieee80211_check_all_nets(struct ieee80211_device *ieee); +extern void ieee80211_start_protocol(struct ieee80211_device *ieee); +extern void ieee80211_stop_protocol(struct ieee80211_device *ieee); +extern void ieee80211_softmac_start_protocol(struct ieee80211_device *ieee); +extern void ieee80211_softmac_stop_protocol(struct ieee80211_device *ieee); +extern void ieee80211_reset_queue(struct ieee80211_device *ieee); +extern void ieee80211_wake_queue(struct ieee80211_device *ieee); +extern void ieee80211_stop_queue(struct ieee80211_device *ieee); +extern struct sk_buff *ieee80211_get_beacon(struct ieee80211_device *ieee); +extern void ieee80211_start_send_beacons(struct ieee80211_device *ieee); +extern void ieee80211_stop_send_beacons(struct ieee80211_device *ieee); +extern int ieee80211_wpa_supplicant_ioctl(struct ieee80211_device *ieee, struct iw_point *p); +extern void notify_wx_assoc_event(struct ieee80211_device *ieee); +extern void ieee80211_ps_tx_ack(struct ieee80211_device *ieee, short success); + +extern void softmac_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *ieee); + +/* ieee80211_crypt_ccmp&tkip&wep.c */ +extern void ieee80211_tkip_null(void); +extern void ieee80211_wep_null(void); +extern void ieee80211_ccmp_null(void); + +/* ieee80211_softmac_wx.c */ + +extern int ieee80211_wx_get_wap(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *ext); + +extern int ieee80211_wx_set_wap(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *awrq, + char *extra); + +extern int ieee80211_wx_get_essid(struct ieee80211_device *ieee, struct iw_request_info *a,union iwreq_data *wrqu,char *b); + +extern int ieee80211_wx_set_rate(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +extern int ieee80211_wx_get_rate(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +extern int ieee80211_wx_set_mode(struct ieee80211_device *ieee, struct iw_request_info *a, + union iwreq_data *wrqu, char *b); + +extern int ieee80211_wx_set_scan(struct ieee80211_device *ieee, struct iw_request_info *a, + union iwreq_data *wrqu, char *b); + +extern int ieee80211_wx_set_essid(struct ieee80211_device *ieee, + struct iw_request_info *a, + union iwreq_data *wrqu, char *extra); + +extern int ieee80211_wx_get_mode(struct ieee80211_device *ieee, struct iw_request_info *a, + union iwreq_data *wrqu, char *b); + +extern int ieee80211_wx_set_freq(struct ieee80211_device *ieee, struct iw_request_info *a, + union iwreq_data *wrqu, char *b); + +extern int ieee80211_wx_get_freq(struct ieee80211_device *ieee, struct iw_request_info *a, + union iwreq_data *wrqu, char *b); + +//extern void ieee80211_wx_sync_scan_wq(struct ieee80211_device *ieee); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) +extern void ieee80211_wx_sync_scan_wq(struct work_struct *work); +#else + extern void ieee80211_wx_sync_scan_wq(struct ieee80211_device *ieee); +#endif + + +extern int ieee80211_wx_set_rawtx(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +extern int ieee80211_wx_get_name(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +extern int ieee80211_wx_set_power(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +extern int ieee80211_wx_get_power(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +extern int ieee80211_wx_set_rts(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +extern int ieee80211_wx_get_rts(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); +//HT +#define MAX_RECEIVE_BUFFER_SIZE 9100 // +extern void HTDebugHTCapability(u8* CapIE, u8* TitleString ); +extern void HTDebugHTInfo(u8* InfoIE, u8* TitleString); + +void HTSetConnectBwMode(struct ieee80211_device* ieee, HT_CHANNEL_WIDTH Bandwidth, HT_EXTCHNL_OFFSET Offset); +extern void HTUpdateDefaultSetting(struct ieee80211_device* ieee); +extern void HTConstructCapabilityElement(struct ieee80211_device* ieee, u8* posHTCap, u8* len, u8 isEncrypt); +extern void HTConstructInfoElement(struct ieee80211_device* ieee, u8* posHTInfo, u8* len, u8 isEncrypt); +extern void HTConstructRT2RTAggElement(struct ieee80211_device* ieee, u8* posRT2RTAgg, u8* len); +extern void HTOnAssocRsp(struct ieee80211_device *ieee); +extern void HTInitializeHTInfo(struct ieee80211_device* ieee); +extern void HTInitializeBssDesc(PBSS_HT pBssHT); +extern void HTResetSelfAndSavePeerSetting(struct ieee80211_device* ieee, struct ieee80211_network * pNetwork); +extern void HTUpdateSelfAndPeerSetting(struct ieee80211_device* ieee, struct ieee80211_network * pNetwork); +extern u8 HTGetHighestMCSRate(struct ieee80211_device* ieee, u8* pMCSRateSet, u8* pMCSFilter); +extern u8 MCS_FILTER_ALL[]; +extern u16 MCS_DATA_RATE[2][2][77] ; +extern u8 HTCCheck(struct ieee80211_device* ieee, u8* pFrame); +//extern void HTSetConnectBwModeCallback(unsigned long data); +extern void HTResetIOTSetting(PRT_HIGH_THROUGHPUT pHTInfo); +extern bool IsHTHalfNmodeAPs(struct ieee80211_device* ieee); +extern u16 HTHalfMcsToDataRate(struct ieee80211_device* ieee, u8 nMcsRate); +extern u16 HTMcsToDataRate( struct ieee80211_device* ieee, u8 nMcsRate); +extern u16 TxCountToDataRate( struct ieee80211_device* ieee, u8 nDataRate); +//function in BAPROC.c +extern int ieee80211_rx_ADDBAReq( struct ieee80211_device* ieee, struct sk_buff *skb); +extern int ieee80211_rx_ADDBARsp( struct ieee80211_device* ieee, struct sk_buff *skb); +extern int ieee80211_rx_DELBA(struct ieee80211_device* ieee,struct sk_buff *skb); +extern void TsInitAddBA( struct ieee80211_device* ieee, PTX_TS_RECORD pTS, u8 Policy, u8 bOverwritePending); +extern void TsInitDelBA( struct ieee80211_device* ieee, PTS_COMMON_INFO pTsCommonInfo, TR_SELECT TxRxSelect); +extern void BaSetupTimeOut(unsigned long data); +extern void TxBaInactTimeout(unsigned long data); +extern void RxBaInactTimeout(unsigned long data); +extern void ResetBaEntry( PBA_RECORD pBA); +//function in TS.c +extern bool GetTs( + struct ieee80211_device* ieee, + PTS_COMMON_INFO *ppTS, + u8* Addr, + u8 TID, + TR_SELECT TxRxSelect, //Rx:1, Tx:0 + bool bAddNewTs + ); +extern void TSInitialize(struct ieee80211_device *ieee); +extern void TsStartAddBaProcess(struct ieee80211_device* ieee, PTX_TS_RECORD pTxTS); +extern void RemovePeerTS(struct ieee80211_device* ieee, u8* Addr); +extern void RemoveAllTS(struct ieee80211_device* ieee); +void ieee80211_softmac_scan_syncro(struct ieee80211_device *ieee); + +extern const long ieee80211_wlan_frequencies[]; + +extern inline void ieee80211_increment_scans(struct ieee80211_device *ieee) +{ + ieee->scans++; +} + +extern inline int ieee80211_get_scans(struct ieee80211_device *ieee) +{ + return ieee->scans; +} + +static inline const char *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 (ieee80211_is_empty_essid(essid, essid_len)) { + memcpy(escaped, "", sizeof("")); + 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; +} + +/* For the function is more related to hardware setting, it's better to use the + * ieee handler to refer to it. + */ +extern short check_nic_enough_desc(struct net_device *dev, int queue_index); +extern int ieee80211_data_xmit(struct sk_buff *skb, struct net_device *dev); +extern int ieee80211_parse_info_param(struct ieee80211_device *ieee, + struct ieee80211_info_element *info_element, + u16 length, + struct ieee80211_network *network, + struct ieee80211_rx_stats *stats); + +void ieee80211_indicate_packets(struct ieee80211_device *ieee, struct ieee80211_rxb** prxbIndicateArray,u8 index); +#define RT_ASOC_RETRY_LIMIT 5 +#endif /* IEEE80211_H */ diff --git a/drivers/staging/rtl8192su/ieee80211/ieee80211_crypt.c b/drivers/staging/rtl8192su/ieee80211/ieee80211_crypt.c new file mode 100644 index 000000000000..199ee1695ad3 --- /dev/null +++ b/drivers/staging/rtl8192su/ieee80211/ieee80211_crypt.c @@ -0,0 +1,273 @@ +/* + * Host AP crypto routines + * + * Copyright (c) 2002-2003, Jouni Malinen + * Portions Copyright (C) 2004, Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. See README and COPYING for + * more details. + * + */ + +//#include +#include +#include +#include +#include +#include +#include + +#include "ieee80211.h" + +MODULE_AUTHOR("Jouni Malinen"); +MODULE_DESCRIPTION("HostAP crypto"); +MODULE_LICENSE("GPL"); + +struct ieee80211_crypto_alg { + struct list_head list; + struct ieee80211_crypto_ops *ops; +}; + + +struct ieee80211_crypto { + struct list_head algs; + spinlock_t lock; +}; + +static struct ieee80211_crypto *hcrypt; + +void ieee80211_crypt_deinit_entries(struct ieee80211_device *ieee, + int force) +{ + struct list_head *ptr, *n; + struct ieee80211_crypt_data *entry; + + for (ptr = ieee->crypt_deinit_list.next, n = ptr->next; + ptr != &ieee->crypt_deinit_list; ptr = n, n = ptr->next) { + entry = list_entry(ptr, struct ieee80211_crypt_data, list); + + if (atomic_read(&entry->refcnt) != 0 && !force) + continue; + + list_del(ptr); + + if (entry->ops) { + entry->ops->deinit(entry->priv); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + module_put(entry->ops->owner); +#else + __MOD_DEC_USE_COUNT(entry->ops->owner); +#endif + } + kfree(entry); + } +} + +void ieee80211_crypt_deinit_handler(unsigned long data) +{ + struct ieee80211_device *ieee = (struct ieee80211_device *)data; + unsigned long flags; + + spin_lock_irqsave(&ieee->lock, flags); + ieee80211_crypt_deinit_entries(ieee, 0); + if (!list_empty(&ieee->crypt_deinit_list)) { + printk(KERN_DEBUG "%s: entries remaining in delayed crypt " + "deletion list\n", ieee->dev->name); + ieee->crypt_deinit_timer.expires = jiffies + HZ; + add_timer(&ieee->crypt_deinit_timer); + } + spin_unlock_irqrestore(&ieee->lock, flags); + +} + +void ieee80211_crypt_delayed_deinit(struct ieee80211_device *ieee, + struct ieee80211_crypt_data **crypt) +{ + struct ieee80211_crypt_data *tmp; + unsigned long flags; + + if (*crypt == NULL) + return; + + tmp = *crypt; + *crypt = NULL; + + /* must not run ops->deinit() while there may be pending encrypt or + * decrypt operations. Use a list of delayed deinits to avoid needing + * locking. */ + + spin_lock_irqsave(&ieee->lock, flags); + list_add(&tmp->list, &ieee->crypt_deinit_list); + if (!timer_pending(&ieee->crypt_deinit_timer)) { + ieee->crypt_deinit_timer.expires = jiffies + HZ; + add_timer(&ieee->crypt_deinit_timer); + } + spin_unlock_irqrestore(&ieee->lock, flags); +} + +int ieee80211_register_crypto_ops(struct ieee80211_crypto_ops *ops) +{ + unsigned long flags; + struct ieee80211_crypto_alg *alg; + + if (hcrypt == NULL) + return -1; + + alg = kmalloc(sizeof(*alg), GFP_KERNEL); + if (alg == NULL) + return -ENOMEM; + + memset(alg, 0, sizeof(*alg)); + alg->ops = ops; + + spin_lock_irqsave(&hcrypt->lock, flags); + list_add(&alg->list, &hcrypt->algs); + spin_unlock_irqrestore(&hcrypt->lock, flags); + + printk(KERN_DEBUG "ieee80211_crypt: registered algorithm '%s'\n", + ops->name); + + return 0; +} + +int ieee80211_unregister_crypto_ops(struct ieee80211_crypto_ops *ops) +{ + unsigned long flags; + struct list_head *ptr; + struct ieee80211_crypto_alg *del_alg = NULL; + + if (hcrypt == NULL) + return -1; + + spin_lock_irqsave(&hcrypt->lock, flags); + for (ptr = hcrypt->algs.next; ptr != &hcrypt->algs; ptr = ptr->next) { + struct ieee80211_crypto_alg *alg = + (struct ieee80211_crypto_alg *) ptr; + if (alg->ops == ops) { + list_del(&alg->list); + del_alg = alg; + break; + } + } + spin_unlock_irqrestore(&hcrypt->lock, flags); + + if (del_alg) { + printk(KERN_DEBUG "ieee80211_crypt: unregistered algorithm " + "'%s'\n", ops->name); + kfree(del_alg); + } + + return del_alg ? 0 : -1; +} + + +struct ieee80211_crypto_ops * ieee80211_get_crypto_ops(const char *name) +{ + unsigned long flags; + struct list_head *ptr; + struct ieee80211_crypto_alg *found_alg = NULL; + + if (hcrypt == NULL) + return NULL; + + spin_lock_irqsave(&hcrypt->lock, flags); + for (ptr = hcrypt->algs.next; ptr != &hcrypt->algs; ptr = ptr->next) { + struct ieee80211_crypto_alg *alg = + (struct ieee80211_crypto_alg *) ptr; + if (strcmp(alg->ops->name, name) == 0) { + found_alg = alg; + break; + } + } + spin_unlock_irqrestore(&hcrypt->lock, flags); + + if (found_alg) + return found_alg->ops; + else + return NULL; +} + + +static void * ieee80211_crypt_null_init(int keyidx) { return (void *) 1; } +static void ieee80211_crypt_null_deinit(void *priv) {} + +static struct ieee80211_crypto_ops ieee80211_crypt_null = { + .name = "NULL", + .init = ieee80211_crypt_null_init, + .deinit = ieee80211_crypt_null_deinit, + .encrypt_mpdu = NULL, + .decrypt_mpdu = NULL, + .encrypt_msdu = NULL, + .decrypt_msdu = NULL, + .set_key = NULL, + .get_key = NULL, + .extra_prefix_len = 0, + .extra_postfix_len = 0, + .owner = THIS_MODULE, +}; + + +static int __init ieee80211_crypto_init(void) +{ + int ret = -ENOMEM; + + hcrypt = kmalloc(sizeof(*hcrypt), GFP_KERNEL); + if (!hcrypt) + goto out; + + memset(hcrypt, 0, sizeof(*hcrypt)); + INIT_LIST_HEAD(&hcrypt->algs); + spin_lock_init(&hcrypt->lock); + + ret = ieee80211_register_crypto_ops(&ieee80211_crypt_null); + if (ret < 0) { + kfree(hcrypt); + hcrypt = NULL; + } +out: + return ret; +} + + +static void __exit ieee80211_crypto_deinit(void) +{ + struct list_head *ptr, *n; + + if (hcrypt == NULL) + return; + + for (ptr = hcrypt->algs.next, n = ptr->next; ptr != &hcrypt->algs; + ptr = n, n = ptr->next) { + struct ieee80211_crypto_alg *alg = + (struct ieee80211_crypto_alg *) ptr; + list_del(ptr); + printk(KERN_DEBUG "ieee80211_crypt: unregistered algorithm " + "'%s' (deinit)\n", alg->ops->name); + kfree(alg); + } + + kfree(hcrypt); +} + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) +EXPORT_SYMBOL(ieee80211_crypt_deinit_entries); +EXPORT_SYMBOL(ieee80211_crypt_deinit_handler); +EXPORT_SYMBOL(ieee80211_crypt_delayed_deinit); + +EXPORT_SYMBOL(ieee80211_register_crypto_ops); +EXPORT_SYMBOL(ieee80211_unregister_crypto_ops); +EXPORT_SYMBOL(ieee80211_get_crypto_ops); +#else +EXPORT_SYMBOL_NOVERS(ieee80211_crypt_deinit_entries); +EXPORT_SYMBOL_NOVERS(ieee80211_crypt_deinit_handler); +EXPORT_SYMBOL_NOVERS(ieee80211_crypt_delayed_deinit); + +EXPORT_SYMBOL_NOVERS(ieee80211_register_crypto_ops); +EXPORT_SYMBOL_NOVERS(ieee80211_unregister_crypto_ops); +EXPORT_SYMBOL_NOVERS(ieee80211_get_crypto_ops); +#endif + +module_init(ieee80211_crypto_init); +module_exit(ieee80211_crypto_deinit); diff --git a/drivers/staging/rtl8192su/ieee80211/ieee80211_crypt.h b/drivers/staging/rtl8192su/ieee80211/ieee80211_crypt.h new file mode 100644 index 000000000000..a84df4b76489 --- /dev/null +++ b/drivers/staging/rtl8192su/ieee80211/ieee80211_crypt.h @@ -0,0 +1,93 @@ +/* + * Original code based on Host AP (software wireless LAN access point) driver + * for Intersil Prism2/2.5/3. + * + * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen + * + * Copyright (c) 2002-2003, Jouni Malinen + * + * Adaption to a generic IEEE 802.11 stack by James Ketrenos + * + * + * Copyright (c) 2004, Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. See README and COPYING for + * more details. + */ + +/* + * This file defines the interface to the ieee80211 crypto module. + */ +#ifndef IEEE80211_CRYPT_H +#define IEEE80211_CRYPT_H + +#include + +struct ieee80211_crypto_ops { + const char *name; + + /* init new crypto context (e.g., allocate private data space, + * select IV, etc.); returns NULL on failure or pointer to allocated + * private data on success */ + void * (*init)(int keyidx); + + /* deinitialize crypto context and free allocated private data */ + void (*deinit)(void *priv); + + /* encrypt/decrypt return < 0 on error or >= 0 on success. The return + * value from decrypt_mpdu is passed as the keyidx value for + * decrypt_msdu. skb must have enough head and tail room for the + * encryption; if not, error will be returned; these functions are + * called for all MPDUs (i.e., fragments). + */ + int (*encrypt_mpdu)(struct sk_buff *skb, int hdr_len, void *priv); + int (*decrypt_mpdu)(struct sk_buff *skb, int hdr_len, void *priv); + + /* These functions are called for full MSDUs, i.e. full frames. + * These can be NULL if full MSDU operations are not needed. */ + int (*encrypt_msdu)(struct sk_buff *skb, int hdr_len, void *priv); + int (*decrypt_msdu)(struct sk_buff *skb, int keyidx, int hdr_len, + void *priv); + + int (*set_key)(void *key, int len, u8 *seq, void *priv); + int (*get_key)(void *key, int len, u8 *seq, void *priv); + + /* procfs handler for printing out key information and possible + * statistics */ + char * (*print_stats)(char *p, void *priv); + + /* maximum number of bytes added by encryption; encrypt buf is + * allocated with extra_prefix_len bytes, copy of in_buf, and + * extra_postfix_len; encrypt need not use all this space, but + * the result must start at the beginning of the buffer and correct + * length must be returned */ + int extra_prefix_len, extra_postfix_len; + + struct module *owner; +}; + +struct ieee80211_crypt_data { + struct list_head list; /* delayed deletion list */ + struct ieee80211_crypto_ops *ops; + void *priv; + atomic_t refcnt; +}; + +int ieee80211_register_crypto_ops(struct ieee80211_crypto_ops *ops); +int ieee80211_unregister_crypto_ops(struct ieee80211_crypto_ops *ops); +struct ieee80211_crypto_ops * ieee80211_get_crypto_ops(const char *name); +void ieee80211_crypt_deinit_entries(struct ieee80211_device *, int); +void ieee80211_crypt_deinit_handler(unsigned long); +void ieee80211_crypt_delayed_deinit(struct ieee80211_device *ieee, + struct ieee80211_crypt_data **crypt); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) +#define offset_in_page(p) ((unsigned long)(p) & ~PAGE_MASK) +#endif +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,31)) +#define crypto_alloc_tfm crypto_alloc_tfm_rsl +#define crypto_free_tfm crypto_free_tfm_rsl +#endif + +#endif diff --git a/drivers/staging/rtl8192su/ieee80211/ieee80211_crypt_ccmp.c b/drivers/staging/rtl8192su/ieee80211/ieee80211_crypt_ccmp.c new file mode 100644 index 000000000000..a86c26eceb34 --- /dev/null +++ b/drivers/staging/rtl8192su/ieee80211/ieee80211_crypt_ccmp.c @@ -0,0 +1,534 @@ +/* + * Host AP crypt: host-based CCMP encryption implementation for Host AP driver + * + * Copyright (c) 2003-2004, Jouni Malinen + * + * 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. See README and COPYING for + * more details. + */ + +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ieee80211.h" + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) +#include "rtl_crypto.h" +#else +#include +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + #include +#else + #include +#endif +//#include + +MODULE_AUTHOR("Jouni Malinen"); +MODULE_DESCRIPTION("Host AP crypt: CCMP"); +MODULE_LICENSE("GPL"); + +#ifndef OPENSUSE_SLED +#define OPENSUSE_SLED 0 +#endif + +#define AES_BLOCK_LEN 16 +#define CCMP_HDR_LEN 8 +#define CCMP_MIC_LEN 8 +#define CCMP_TK_LEN 16 +#define CCMP_PN_LEN 6 + +struct ieee80211_ccmp_data { + u8 key[CCMP_TK_LEN]; + int key_set; + + u8 tx_pn[CCMP_PN_LEN]; + u8 rx_pn[CCMP_PN_LEN]; + + u32 dot11RSNAStatsCCMPFormatErrors; + u32 dot11RSNAStatsCCMPReplays; + u32 dot11RSNAStatsCCMPDecryptErrors; + + int key_idx; + + struct crypto_tfm *tfm; + + /* scratch buffers for virt_to_page() (crypto API) */ + u8 tx_b0[AES_BLOCK_LEN], tx_b[AES_BLOCK_LEN], + tx_e[AES_BLOCK_LEN], tx_s0[AES_BLOCK_LEN]; + u8 rx_b0[AES_BLOCK_LEN], rx_b[AES_BLOCK_LEN], rx_a[AES_BLOCK_LEN]; +}; + +void ieee80211_ccmp_aes_encrypt(struct crypto_tfm *tfm, + const u8 pt[16], u8 ct[16]) +{ +#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED)) + struct scatterlist src, dst; + + src.page = virt_to_page(pt); + src.offset = offset_in_page(pt); + src.length = AES_BLOCK_LEN; + + dst.page = virt_to_page(ct); + dst.offset = offset_in_page(ct); + dst.length = AES_BLOCK_LEN; + + crypto_cipher_encrypt(tfm, &dst, &src, AES_BLOCK_LEN); +#else + crypto_cipher_encrypt_one((void*)tfm, ct, pt); +#endif +} + +static void * ieee80211_ccmp_init(int key_idx) +{ + struct ieee80211_ccmp_data *priv; + + priv = kmalloc(sizeof(*priv), GFP_ATOMIC); + if (priv == NULL) + goto fail; + memset(priv, 0, sizeof(*priv)); + priv->key_idx = key_idx; + +#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED)) + priv->tfm = crypto_alloc_tfm("aes", 0); + if (priv->tfm == NULL) { + printk(KERN_DEBUG "ieee80211_crypt_ccmp: could not allocate " + "crypto API aes\n"); + goto fail; + } + #else + priv->tfm = (void*)crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(priv->tfm)) { + printk(KERN_DEBUG "ieee80211_crypt_ccmp: could not allocate " + "crypto API aes\n"); + priv->tfm = NULL; + goto fail; + } + #endif + return priv; + +fail: + if (priv) { + if (priv->tfm) + #if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) + crypto_free_tfm(priv->tfm); + #else + crypto_free_cipher((void*)priv->tfm); + #endif + kfree(priv); + } + + return NULL; +} + + +static void ieee80211_ccmp_deinit(void *priv) +{ + struct ieee80211_ccmp_data *_priv = priv; + if (_priv && _priv->tfm) +#if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) + crypto_free_tfm(_priv->tfm); +#else + crypto_free_cipher((void*)_priv->tfm); +#endif + kfree(priv); +} + + +static inline void xor_block(u8 *b, u8 *a, size_t len) +{ + int i; + for (i = 0; i < len; i++) + b[i] ^= a[i]; +} + + + +static void ccmp_init_blocks(struct crypto_tfm *tfm, + struct ieee80211_hdr_4addr *hdr, + u8 *pn, size_t dlen, u8 *b0, u8 *auth, + u8 *s0) +{ + u8 *pos, qc = 0; + size_t aad_len; + u16 fc; + int a4_included, qc_included; + u8 aad[2 * AES_BLOCK_LEN]; + + fc = le16_to_cpu(hdr->frame_ctl); + a4_included = ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == + (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)); + /* + qc_included = ((WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA) && + (WLAN_FC_GET_STYPE(fc) & 0x08)); + */ + // fixed by David :2006.9.6 + qc_included = ((WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA) && + (WLAN_FC_GET_STYPE(fc) & 0x80)); + aad_len = 22; + if (a4_included) + aad_len += 6; + if (qc_included) { + pos = (u8 *) &hdr->addr4; + if (a4_included) + pos += 6; + qc = *pos & 0x0f; + aad_len += 2; + } + /* CCM Initial Block: + * Flag (Include authentication header, M=3 (8-octet MIC), + * L=1 (2-octet Dlen)) + * Nonce: 0x00 | A2 | PN + * Dlen */ + b0[0] = 0x59; + b0[1] = qc; + memcpy(b0 + 2, hdr->addr2, ETH_ALEN); + memcpy(b0 + 8, pn, CCMP_PN_LEN); + b0[14] = (dlen >> 8) & 0xff; + b0[15] = dlen & 0xff; + + /* AAD: + * FC with bits 4..6 and 11..13 masked to zero; 14 is always one + * A1 | A2 | A3 + * SC with bits 4..15 (seq#) masked to zero + * A4 (if present) + * QC (if present) + */ + pos = (u8 *) hdr; + aad[0] = 0; /* aad_len >> 8 */ + aad[1] = aad_len & 0xff; + aad[2] = pos[0] & 0x8f; + aad[3] = pos[1] & 0xc7; + memcpy(aad + 4, hdr->addr1, 3 * ETH_ALEN); + pos = (u8 *) &hdr->seq_ctl; + aad[22] = pos[0] & 0x0f; + aad[23] = 0; /* all bits masked */ + memset(aad + 24, 0, 8); + if (a4_included) + memcpy(aad + 24, hdr->addr4, ETH_ALEN); + if (qc_included) { + aad[a4_included ? 30 : 24] = qc; + /* rest of QC masked */ + } + + /* Start with the first block and AAD */ + ieee80211_ccmp_aes_encrypt(tfm, b0, auth); + xor_block(auth, aad, AES_BLOCK_LEN); + ieee80211_ccmp_aes_encrypt(tfm, auth, auth); + xor_block(auth, &aad[AES_BLOCK_LEN], AES_BLOCK_LEN); + ieee80211_ccmp_aes_encrypt(tfm, auth, auth); + b0[0] &= 0x07; + b0[14] = b0[15] = 0; + ieee80211_ccmp_aes_encrypt(tfm, b0, s0); +} + + + +static int ieee80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv) +{ + struct ieee80211_ccmp_data *key = priv; + int data_len, i; + u8 *pos; + struct ieee80211_hdr_4addr *hdr; + cb_desc *tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE); + + if (skb_headroom(skb) < CCMP_HDR_LEN || + skb_tailroom(skb) < CCMP_MIC_LEN || + skb->len < hdr_len) + return -1; + + data_len = skb->len - hdr_len; + pos = skb_push(skb, CCMP_HDR_LEN); + memmove(pos, pos + CCMP_HDR_LEN, hdr_len); + pos += hdr_len; +// mic = skb_put(skb, CCMP_MIC_LEN); + + i = CCMP_PN_LEN - 1; + while (i >= 0) { + key->tx_pn[i]++; + if (key->tx_pn[i] != 0) + break; + i--; + } + + *pos++ = key->tx_pn[5]; + *pos++ = key->tx_pn[4]; + *pos++ = 0; + *pos++ = (key->key_idx << 6) | (1 << 5) /* Ext IV included */; + *pos++ = key->tx_pn[3]; + *pos++ = key->tx_pn[2]; + *pos++ = key->tx_pn[1]; + *pos++ = key->tx_pn[0]; + + + hdr = (struct ieee80211_hdr_4addr *) skb->data; + if (!tcb_desc->bHwSec) + { + int blocks, last, len; + u8 *mic; + u8 *b0 = key->tx_b0; + u8 *b = key->tx_b; + u8 *e = key->tx_e; + u8 *s0 = key->tx_s0; + + //mic is moved to here by john + mic = skb_put(skb, CCMP_MIC_LEN); + + ccmp_init_blocks(key->tfm, hdr, key->tx_pn, data_len, b0, b, s0); + + blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN; + last = data_len % AES_BLOCK_LEN; + + for (i = 1; i <= blocks; i++) { + len = (i == blocks && last) ? last : AES_BLOCK_LEN; + /* Authentication */ + xor_block(b, pos, len); + ieee80211_ccmp_aes_encrypt(key->tfm, b, b); + /* Encryption, with counter */ + b0[14] = (i >> 8) & 0xff; + b0[15] = i & 0xff; + ieee80211_ccmp_aes_encrypt(key->tfm, b0, e); + xor_block(pos, e, len); + pos += len; + } + + for (i = 0; i < CCMP_MIC_LEN; i++) + mic[i] = b[i] ^ s0[i]; + } + return 0; +} + + +static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv) +{ + struct ieee80211_ccmp_data *key = priv; + u8 keyidx, *pos; + struct ieee80211_hdr_4addr *hdr; + cb_desc *tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE); + u8 pn[6]; + + if (skb->len < hdr_len + CCMP_HDR_LEN + CCMP_MIC_LEN) { + key->dot11RSNAStatsCCMPFormatErrors++; + return -1; + } + + hdr = (struct ieee80211_hdr_4addr *) skb->data; + pos = skb->data + hdr_len; + keyidx = pos[3]; + if (!(keyidx & (1 << 5))) { + if (net_ratelimit()) { + printk(KERN_DEBUG "CCMP: received packet without ExtIV" + " flag from " MAC_FMT "\n", MAC_ARG(hdr->addr2)); + } + key->dot11RSNAStatsCCMPFormatErrors++; + return -2; + } + keyidx >>= 6; + if (key->key_idx != keyidx) { + printk(KERN_DEBUG "CCMP: RX tkey->key_idx=%d frame " + "keyidx=%d priv=%p\n", key->key_idx, keyidx, priv); + return -6; + } + if (!key->key_set) { + if (net_ratelimit()) { + printk(KERN_DEBUG "CCMP: received packet from " MAC_FMT + " with keyid=%d that does not have a configured" + " key\n", MAC_ARG(hdr->addr2), keyidx); + } + return -3; + } + + pn[0] = pos[7]; + pn[1] = pos[6]; + pn[2] = pos[5]; + pn[3] = pos[4]; + pn[4] = pos[1]; + pn[5] = pos[0]; + pos += 8; + + if (memcmp(pn, key->rx_pn, CCMP_PN_LEN) <= 0) { + if (net_ratelimit()) { + printk(KERN_DEBUG "CCMP: replay detected: STA=" MAC_FMT + " previous PN %02x%02x%02x%02x%02x%02x " + "received PN %02x%02x%02x%02x%02x%02x\n", + MAC_ARG(hdr->addr2), MAC_ARG(key->rx_pn), + MAC_ARG(pn)); + } + key->dot11RSNAStatsCCMPReplays++; + return -4; + } + if (!tcb_desc->bHwSec) + { + size_t data_len = skb->len - hdr_len - CCMP_HDR_LEN - CCMP_MIC_LEN; + u8 *mic = skb->data + skb->len - CCMP_MIC_LEN; + u8 *b0 = key->rx_b0; + u8 *b = key->rx_b; + u8 *a = key->rx_a; + int i, blocks, last, len; + + + ccmp_init_blocks(key->tfm, hdr, pn, data_len, b0, a, b); + xor_block(mic, b, CCMP_MIC_LEN); + + blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN; + last = data_len % AES_BLOCK_LEN; + + for (i = 1; i <= blocks; i++) { + len = (i == blocks && last) ? last : AES_BLOCK_LEN; + /* Decrypt, with counter */ + b0[14] = (i >> 8) & 0xff; + b0[15] = i & 0xff; + ieee80211_ccmp_aes_encrypt(key->tfm, b0, b); + xor_block(pos, b, len); + /* Authentication */ + xor_block(a, pos, len); + ieee80211_ccmp_aes_encrypt(key->tfm, a, a); + pos += len; + } + + if (memcmp(mic, a, CCMP_MIC_LEN) != 0) { + if (net_ratelimit()) { + printk(KERN_DEBUG "CCMP: decrypt failed: STA=" + MAC_FMT "\n", MAC_ARG(hdr->addr2)); + } + key->dot11RSNAStatsCCMPDecryptErrors++; + return -5; + } + + memcpy(key->rx_pn, pn, CCMP_PN_LEN); + } + /* Remove hdr and MIC */ + memmove(skb->data + CCMP_HDR_LEN, skb->data, hdr_len); + skb_pull(skb, CCMP_HDR_LEN); + skb_trim(skb, skb->len - CCMP_MIC_LEN); + + return keyidx; +} + + +static int ieee80211_ccmp_set_key(void *key, int len, u8 *seq, void *priv) +{ + struct ieee80211_ccmp_data *data = priv; + int keyidx; + struct crypto_tfm *tfm = data->tfm; + + keyidx = data->key_idx; + memset(data, 0, sizeof(*data)); + data->key_idx = keyidx; + data->tfm = tfm; + if (len == CCMP_TK_LEN) { + memcpy(data->key, key, CCMP_TK_LEN); + data->key_set = 1; + if (seq) { + data->rx_pn[0] = seq[5]; + data->rx_pn[1] = seq[4]; + data->rx_pn[2] = seq[3]; + data->rx_pn[3] = seq[2]; + data->rx_pn[4] = seq[1]; + data->rx_pn[5] = seq[0]; + } + crypto_cipher_setkey((void*)data->tfm, data->key, CCMP_TK_LEN); + } else if (len == 0) + data->key_set = 0; + else + return -1; + + return 0; +} + + +static int ieee80211_ccmp_get_key(void *key, int len, u8 *seq, void *priv) +{ + struct ieee80211_ccmp_data *data = priv; + + if (len < CCMP_TK_LEN) + return -1; + + if (!data->key_set) + return 0; + memcpy(key, data->key, CCMP_TK_LEN); + + if (seq) { + seq[0] = data->tx_pn[5]; + seq[1] = data->tx_pn[4]; + seq[2] = data->tx_pn[3]; + seq[3] = data->tx_pn[2]; + seq[4] = data->tx_pn[1]; + seq[5] = data->tx_pn[0]; + } + + return CCMP_TK_LEN; +} + + +static char * ieee80211_ccmp_print_stats(char *p, void *priv) +{ + struct ieee80211_ccmp_data *ccmp = priv; + p += sprintf(p, "key[%d] alg=CCMP key_set=%d " + "tx_pn=%02x%02x%02x%02x%02x%02x " + "rx_pn=%02x%02x%02x%02x%02x%02x " + "format_errors=%d replays=%d decrypt_errors=%d\n", + ccmp->key_idx, ccmp->key_set, + MAC_ARG(ccmp->tx_pn), MAC_ARG(ccmp->rx_pn), + ccmp->dot11RSNAStatsCCMPFormatErrors, + ccmp->dot11RSNAStatsCCMPReplays, + ccmp->dot11RSNAStatsCCMPDecryptErrors); + + return p; +} + +void ieee80211_ccmp_null(void) +{ +// printk("============>%s()\n", __FUNCTION__); + return; +} + +static struct ieee80211_crypto_ops ieee80211_crypt_ccmp = { + .name = "CCMP", + .init = ieee80211_ccmp_init, + .deinit = ieee80211_ccmp_deinit, + .encrypt_mpdu = ieee80211_ccmp_encrypt, + .decrypt_mpdu = ieee80211_ccmp_decrypt, + .encrypt_msdu = NULL, + .decrypt_msdu = NULL, + .set_key = ieee80211_ccmp_set_key, + .get_key = ieee80211_ccmp_get_key, + .print_stats = ieee80211_ccmp_print_stats, + .extra_prefix_len = CCMP_HDR_LEN, + .extra_postfix_len = CCMP_MIC_LEN, + .owner = THIS_MODULE, +}; + + +static int __init ieee80211_crypto_ccmp_init(void) +{ + return ieee80211_register_crypto_ops(&ieee80211_crypt_ccmp); +} + + +static void __exit ieee80211_crypto_ccmp_exit(void) +{ + ieee80211_unregister_crypto_ops(&ieee80211_crypt_ccmp); +} + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) +EXPORT_SYMBOL(ieee80211_ccmp_null); +#else +EXPORT_SYMBOL_NOVERS(ieee80211_ccmp_null); +#endif + +module_init(ieee80211_crypto_ccmp_init); +module_exit(ieee80211_crypto_ccmp_exit); diff --git a/drivers/staging/rtl8192su/ieee80211/ieee80211_crypt_tkip.c b/drivers/staging/rtl8192su/ieee80211/ieee80211_crypt_tkip.c new file mode 100644 index 000000000000..b031b6495247 --- /dev/null +++ b/drivers/staging/rtl8192su/ieee80211/ieee80211_crypt_tkip.c @@ -0,0 +1,1034 @@ +/* + * Host AP crypt: host-based TKIP encryption implementation for Host AP driver + * + * Copyright (c) 2003-2004, Jouni Malinen + * + * 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. See README and COPYING for + * more details. + */ + +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ieee80211.h" +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,20)) +//#include "crypto_compat.h" +#endif + + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) +#include "rtl_crypto.h" +#else +#include +#endif +//#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + #include +#else + #include +#endif + +#include + +MODULE_AUTHOR("Jouni Malinen"); +MODULE_DESCRIPTION("Host AP crypt: TKIP"); +MODULE_LICENSE("GPL"); + +#ifndef OPENSUSE_SLED +#define OPENSUSE_SLED 0 +#endif + +struct ieee80211_tkip_data { +#define TKIP_KEY_LEN 32 + u8 key[TKIP_KEY_LEN]; + int key_set; + + u32 tx_iv32; + u16 tx_iv16; + u16 tx_ttak[5]; + int tx_phase1_done; + + u32 rx_iv32; + u16 rx_iv16; + u16 rx_ttak[5]; + int rx_phase1_done; + u32 rx_iv32_new; + u16 rx_iv16_new; + + u32 dot11RSNAStatsTKIPReplays; + u32 dot11RSNAStatsTKIPICVErrors; + u32 dot11RSNAStatsTKIPLocalMICFailures; + + int key_idx; +#if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)) || (OPENSUSE_SLED)) + struct crypto_blkcipher *rx_tfm_arc4; + struct crypto_hash *rx_tfm_michael; + struct crypto_blkcipher *tx_tfm_arc4; + struct crypto_hash *tx_tfm_michael; +#else + struct crypto_tfm *tx_tfm_arc4; + struct crypto_tfm *tx_tfm_michael; + struct crypto_tfm *rx_tfm_arc4; + struct crypto_tfm *rx_tfm_michael; +#endif + /* scratch buffers for virt_to_page() (crypto API) */ + u8 rx_hdr[16], tx_hdr[16]; +}; + +static void * ieee80211_tkip_init(int key_idx) +{ + struct ieee80211_tkip_data *priv; + + priv = kmalloc(sizeof(*priv), GFP_ATOMIC); + if (priv == NULL) + goto fail; + memset(priv, 0, sizeof(*priv)); + priv->key_idx = key_idx; +#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED)) + priv->tx_tfm_arc4 = crypto_alloc_tfm("arc4", 0); + if (priv->tx_tfm_arc4 == NULL) { + printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " + "crypto API arc4\n"); + goto fail; + } + + priv->tx_tfm_michael = crypto_alloc_tfm("michael_mic", 0); + if (priv->tx_tfm_michael == NULL) { + printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " + "crypto API michael_mic\n"); + goto fail; + } + + priv->rx_tfm_arc4 = crypto_alloc_tfm("arc4", 0); + if (priv->rx_tfm_arc4 == NULL) { + printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " + "crypto API arc4\n"); + goto fail; + } + + priv->rx_tfm_michael = crypto_alloc_tfm("michael_mic", 0); + if (priv->rx_tfm_michael == NULL) { + printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " + "crypto API michael_mic\n"); + goto fail; + } +#else + priv->tx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, + CRYPTO_ALG_ASYNC); + if (IS_ERR(priv->tx_tfm_arc4)) { + printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " + "crypto API arc4\n"); + priv->tx_tfm_arc4 = NULL; + goto fail; + } + + priv->tx_tfm_michael = crypto_alloc_hash("michael_mic", 0, + CRYPTO_ALG_ASYNC); + if (IS_ERR(priv->tx_tfm_michael)) { + printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " + "crypto API michael_mic\n"); + priv->tx_tfm_michael = NULL; + goto fail; + } + + priv->rx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, + CRYPTO_ALG_ASYNC); + if (IS_ERR(priv->rx_tfm_arc4)) { + printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " + "crypto API arc4\n"); + priv->rx_tfm_arc4 = NULL; + goto fail; + } + + priv->rx_tfm_michael = crypto_alloc_hash("michael_mic", 0, + CRYPTO_ALG_ASYNC); + if (IS_ERR(priv->rx_tfm_michael)) { + printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " + "crypto API michael_mic\n"); + priv->rx_tfm_michael = NULL; + goto fail; + } +#endif + return priv; + +fail: + if (priv) { +#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED)) + if (priv->tx_tfm_michael) + crypto_free_tfm(priv->tx_tfm_michael); + if (priv->tx_tfm_arc4) + crypto_free_tfm(priv->tx_tfm_arc4); + if (priv->rx_tfm_michael) + crypto_free_tfm(priv->rx_tfm_michael); + if (priv->rx_tfm_arc4) + crypto_free_tfm(priv->rx_tfm_arc4); + +#else + if (priv->tx_tfm_michael) + crypto_free_hash(priv->tx_tfm_michael); + if (priv->tx_tfm_arc4) + crypto_free_blkcipher(priv->tx_tfm_arc4); + if (priv->rx_tfm_michael) + crypto_free_hash(priv->rx_tfm_michael); + if (priv->rx_tfm_arc4) + crypto_free_blkcipher(priv->rx_tfm_arc4); +#endif + kfree(priv); + } + + return NULL; +} + + +static void ieee80211_tkip_deinit(void *priv) +{ + struct ieee80211_tkip_data *_priv = priv; +#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED)) + if (_priv->tx_tfm_michael) + crypto_free_tfm(_priv->tx_tfm_michael); + if (_priv->tx_tfm_arc4) + crypto_free_tfm(_priv->tx_tfm_arc4); + if (_priv->rx_tfm_michael) + crypto_free_tfm(_priv->rx_tfm_michael); + if (_priv->rx_tfm_arc4) + crypto_free_tfm(_priv->rx_tfm_arc4); +#else + if (_priv) { + if (_priv->tx_tfm_michael) + crypto_free_hash(_priv->tx_tfm_michael); + if (_priv->tx_tfm_arc4) + crypto_free_blkcipher(_priv->tx_tfm_arc4); + if (_priv->rx_tfm_michael) + crypto_free_hash(_priv->rx_tfm_michael); + if (_priv->rx_tfm_arc4) + crypto_free_blkcipher(_priv->rx_tfm_arc4); + } +#endif + kfree(priv); +} + + +static inline u16 RotR1(u16 val) +{ + return (val >> 1) | (val << 15); +} + + +static inline u8 Lo8(u16 val) +{ + return val & 0xff; +} + + +static inline u8 Hi8(u16 val) +{ + return val >> 8; +} + + +static inline u16 Lo16(u32 val) +{ + return val & 0xffff; +} + + +static inline u16 Hi16(u32 val) +{ + return val >> 16; +} + + +static inline u16 Mk16(u8 hi, u8 lo) +{ + return lo | (((u16) hi) << 8); +} + + +static inline u16 Mk16_le(u16 *v) +{ + return le16_to_cpu(*v); +} + + +static const u16 Sbox[256] = +{ + 0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154, + 0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A, + 0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B, + 0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B, + 0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F, + 0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F, + 0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5, + 0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F, + 0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB, + 0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397, + 0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED, + 0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A, + 0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194, + 0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3, + 0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104, + 0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D, + 0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39, + 0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695, + 0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83, + 0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76, + 0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4, + 0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B, + 0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0, + 0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018, + 0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751, + 0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85, + 0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12, + 0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9, + 0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7, + 0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A, + 0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8, + 0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A, +}; + + +static inline u16 _S_(u16 v) +{ + u16 t = Sbox[Hi8(v)]; + return Sbox[Lo8(v)] ^ ((t << 8) | (t >> 8)); +} + + +#define PHASE1_LOOP_COUNT 8 + + +static void tkip_mixing_phase1(u16 *TTAK, const u8 *TK, const u8 *TA, u32 IV32) +{ + int i, j; + + /* Initialize the 80-bit TTAK from TSC (IV32) and TA[0..5] */ + TTAK[0] = Lo16(IV32); + TTAK[1] = Hi16(IV32); + TTAK[2] = Mk16(TA[1], TA[0]); + TTAK[3] = Mk16(TA[3], TA[2]); + TTAK[4] = Mk16(TA[5], TA[4]); + + for (i = 0; i < PHASE1_LOOP_COUNT; i++) { + j = 2 * (i & 1); + TTAK[0] += _S_(TTAK[4] ^ Mk16(TK[1 + j], TK[0 + j])); + TTAK[1] += _S_(TTAK[0] ^ Mk16(TK[5 + j], TK[4 + j])); + TTAK[2] += _S_(TTAK[1] ^ Mk16(TK[9 + j], TK[8 + j])); + TTAK[3] += _S_(TTAK[2] ^ Mk16(TK[13 + j], TK[12 + j])); + TTAK[4] += _S_(TTAK[3] ^ Mk16(TK[1 + j], TK[0 + j])) + i; + } +} + + +static void tkip_mixing_phase2(u8 *WEPSeed, const u8 *TK, const u16 *TTAK, + u16 IV16) +{ + /* Make temporary area overlap WEP seed so that the final copy can be + * avoided on little endian hosts. */ + u16 *PPK = (u16 *) &WEPSeed[4]; + + /* Step 1 - make copy of TTAK and bring in TSC */ + PPK[0] = TTAK[0]; + PPK[1] = TTAK[1]; + PPK[2] = TTAK[2]; + PPK[3] = TTAK[3]; + PPK[4] = TTAK[4]; + PPK[5] = TTAK[4] + IV16; + + /* Step 2 - 96-bit bijective mixing using S-box */ + PPK[0] += _S_(PPK[5] ^ Mk16_le((u16 *) &TK[0])); + PPK[1] += _S_(PPK[0] ^ Mk16_le((u16 *) &TK[2])); + PPK[2] += _S_(PPK[1] ^ Mk16_le((u16 *) &TK[4])); + PPK[3] += _S_(PPK[2] ^ Mk16_le((u16 *) &TK[6])); + PPK[4] += _S_(PPK[3] ^ Mk16_le((u16 *) &TK[8])); + PPK[5] += _S_(PPK[4] ^ Mk16_le((u16 *) &TK[10])); + + PPK[0] += RotR1(PPK[5] ^ Mk16_le((u16 *) &TK[12])); + PPK[1] += RotR1(PPK[0] ^ Mk16_le((u16 *) &TK[14])); + PPK[2] += RotR1(PPK[1]); + PPK[3] += RotR1(PPK[2]); + PPK[4] += RotR1(PPK[3]); + PPK[5] += RotR1(PPK[4]); + + /* Step 3 - bring in last of TK bits, assign 24-bit WEP IV value + * WEPSeed[0..2] is transmitted as WEP IV */ + WEPSeed[0] = Hi8(IV16); + WEPSeed[1] = (Hi8(IV16) | 0x20) & 0x7F; + WEPSeed[2] = Lo8(IV16); + WEPSeed[3] = Lo8((PPK[5] ^ Mk16_le((u16 *) &TK[0])) >> 1); + +#ifdef __BIG_ENDIAN + { + int i; + for (i = 0; i < 6; i++) + PPK[i] = (PPK[i] << 8) | (PPK[i] >> 8); + } +#endif +} + + +static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) +{ + struct ieee80211_tkip_data *tkey = priv; + int len; + u8 *pos; + struct ieee80211_hdr_4addr *hdr; + cb_desc *tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE); + + #if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)) || (OPENSUSE_SLED)) + struct blkcipher_desc desc = {.tfm = tkey->tx_tfm_arc4}; + int ret = 0; + #endif + u8 rc4key[16], *icv; + u32 crc; + struct scatterlist sg; + + if (skb_headroom(skb) < 8 || skb_tailroom(skb) < 4 || + skb->len < hdr_len) + return -1; + + hdr = (struct ieee80211_hdr_4addr *) skb->data; + +#if 0 +printk("@@ tkey\n"); +printk("%x|", ((u32*)tkey->key)[0]); +printk("%x|", ((u32*)tkey->key)[1]); +printk("%x|", ((u32*)tkey->key)[2]); +printk("%x|", ((u32*)tkey->key)[3]); +printk("%x|", ((u32*)tkey->key)[4]); +printk("%x|", ((u32*)tkey->key)[5]); +printk("%x|", ((u32*)tkey->key)[6]); +printk("%x\n", ((u32*)tkey->key)[7]); +#endif + + if (!tcb_desc->bHwSec) + { + if (!tkey->tx_phase1_done) { + tkip_mixing_phase1(tkey->tx_ttak, tkey->key, hdr->addr2, + tkey->tx_iv32); + tkey->tx_phase1_done = 1; + } + tkip_mixing_phase2(rc4key, tkey->key, tkey->tx_ttak, tkey->tx_iv16); + } + else + tkey->tx_phase1_done = 1; + + + len = skb->len - hdr_len; + pos = skb_push(skb, 8); + memmove(pos, pos + 8, hdr_len); + pos += hdr_len; + + if (tcb_desc->bHwSec) + { + *pos++ = Hi8(tkey->tx_iv16); + *pos++ = (Hi8(tkey->tx_iv16) | 0x20) & 0x7F; + *pos++ = Lo8(tkey->tx_iv16); + } + else + { + *pos++ = rc4key[0]; + *pos++ = rc4key[1]; + *pos++ = rc4key[2]; + } + + *pos++ = (tkey->key_idx << 6) | (1 << 5) /* Ext IV included */; + *pos++ = tkey->tx_iv32 & 0xff; + *pos++ = (tkey->tx_iv32 >> 8) & 0xff; + *pos++ = (tkey->tx_iv32 >> 16) & 0xff; + *pos++ = (tkey->tx_iv32 >> 24) & 0xff; + + if (!tcb_desc->bHwSec) + { + icv = skb_put(skb, 4); +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) + crc = ~crc32_le(~0, pos, len); +#else + crc = ~ether_crc_le(len, pos); +#endif + icv[0] = crc; + icv[1] = crc >> 8; + icv[2] = crc >> 16; + icv[3] = crc >> 24; +#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED)) + crypto_cipher_setkey(tkey->tx_tfm_arc4, rc4key, 16); + sg.page = virt_to_page(pos); + sg.offset = offset_in_page(pos); + sg.length = len + 4; + crypto_cipher_encrypt(tkey->tx_tfm_arc4, &sg, &sg, len + 4); +#else + crypto_blkcipher_setkey(tkey->tx_tfm_arc4, rc4key, 16); +#if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) + sg.page = virt_to_page(pos); + sg.offset = offset_in_page(pos); + sg.length = len + 4; +#else + sg_init_one(&sg, pos, len+4); +#endif + ret= crypto_blkcipher_encrypt(&desc, &sg, &sg, len + 4); +#endif + + } + + tkey->tx_iv16++; + if (tkey->tx_iv16 == 0) { + tkey->tx_phase1_done = 0; + tkey->tx_iv32++; + } + + if (!tcb_desc->bHwSec) +#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED)) + return 0; + #else + return ret; + #endif + else + return 0; + + +} + +static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) +{ + struct ieee80211_tkip_data *tkey = priv; + u8 keyidx, *pos; + u32 iv32; + u16 iv16; + struct ieee80211_hdr_4addr *hdr; + cb_desc *tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE); + #if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)) || (OPENSUSE_SLED)) + struct blkcipher_desc desc = {.tfm = tkey->rx_tfm_arc4}; + #endif + u8 rc4key[16]; + u8 icv[4]; + u32 crc; + struct scatterlist sg; + int plen; + if (skb->len < hdr_len + 8 + 4) + return -1; + + hdr = (struct ieee80211_hdr_4addr *) skb->data; + pos = skb->data + hdr_len; + keyidx = pos[3]; + if (!(keyidx & (1 << 5))) { + if (net_ratelimit()) { + printk(KERN_DEBUG "TKIP: received packet without ExtIV" + " flag from " MAC_FMT "\n", MAC_ARG(hdr->addr2)); + } + return -2; + } + keyidx >>= 6; + if (tkey->key_idx != keyidx) { + printk(KERN_DEBUG "TKIP: RX tkey->key_idx=%d frame " + "keyidx=%d priv=%p\n", tkey->key_idx, keyidx, priv); + return -6; + } + if (!tkey->key_set) { + if (net_ratelimit()) { + printk(KERN_DEBUG "TKIP: received packet from " MAC_FMT + " with keyid=%d that does not have a configured" + " key\n", MAC_ARG(hdr->addr2), keyidx); + } + return -3; + } + iv16 = (pos[0] << 8) | pos[2]; + iv32 = pos[4] | (pos[5] << 8) | (pos[6] << 16) | (pos[7] << 24); + pos += 8; + + if (!tcb_desc->bHwSec) + { + if (iv32 < tkey->rx_iv32 || + (iv32 == tkey->rx_iv32 && iv16 <= tkey->rx_iv16)) { + if (net_ratelimit()) { + printk(KERN_DEBUG "TKIP: replay detected: STA=" MAC_FMT + " previous TSC %08x%04x received TSC " + "%08x%04x\n", MAC_ARG(hdr->addr2), + tkey->rx_iv32, tkey->rx_iv16, iv32, iv16); + } + tkey->dot11RSNAStatsTKIPReplays++; + return -4; + } + + if (iv32 != tkey->rx_iv32 || !tkey->rx_phase1_done) { + tkip_mixing_phase1(tkey->rx_ttak, tkey->key, hdr->addr2, iv32); + tkey->rx_phase1_done = 1; + } + tkip_mixing_phase2(rc4key, tkey->key, tkey->rx_ttak, iv16); + + plen = skb->len - hdr_len - 12; + +#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED)) + crypto_cipher_setkey(tkey->rx_tfm_arc4, rc4key, 16); + sg.page = virt_to_page(pos); + sg.offset = offset_in_page(pos); + sg.length = plen + 4; + crypto_cipher_decrypt(tkey->rx_tfm_arc4, &sg, &sg, plen + 4); +#else + crypto_blkcipher_setkey(tkey->rx_tfm_arc4, rc4key, 16); +#if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) + sg.page = virt_to_page(pos); + sg.offset = offset_in_page(pos); + sg.length = plen + 4; +#else + sg_init_one(&sg, pos, plen+4); +#endif + if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4)) { + if (net_ratelimit()) { + printk(KERN_DEBUG ": TKIP: failed to decrypt " + "received packet from " MAC_FMT "\n", + MAC_ARG(hdr->addr2)); + } + return -7; + } +#endif + + #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) + crc = ~crc32_le(~0, pos, plen); + #else + crc = ~ether_crc_le(plen, pos); + #endif + icv[0] = crc; + icv[1] = crc >> 8; + icv[2] = crc >> 16; + icv[3] = crc >> 24; + + if (memcmp(icv, pos + plen, 4) != 0) { + if (iv32 != tkey->rx_iv32) { + /* Previously cached Phase1 result was already lost, so + * it needs to be recalculated for the next packet. */ + tkey->rx_phase1_done = 0; + } + if (net_ratelimit()) { + printk(KERN_DEBUG "TKIP: ICV error detected: STA=" + MAC_FMT "\n", MAC_ARG(hdr->addr2)); + } + tkey->dot11RSNAStatsTKIPICVErrors++; + return -5; + } + + } + + /* Update real counters only after Michael MIC verification has + * completed */ + tkey->rx_iv32_new = iv32; + tkey->rx_iv16_new = iv16; + + /* Remove IV and ICV */ + memmove(skb->data + 8, skb->data, hdr_len); + skb_pull(skb, 8); + skb_trim(skb, skb->len - 4); + +//john's test +#ifdef JOHN_DUMP +if( ((u16*)skb->data)[0] & 0x4000){ + printk("@@ rx decrypted skb->data"); + int i; + for(i=0;ilen;i++){ + if( (i%24)==0 ) printk("\n"); + printk("%2x ", ((u8*)skb->data)[i]); + } + printk("\n"); +} +#endif /*JOHN_DUMP*/ + return keyidx; +} + + +#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED)) +static int michael_mic(struct crypto_tfm * tfm_michael, u8 *key, u8 *hdr, + u8 *data, size_t data_len, u8 *mic) +{ + struct scatterlist sg[2]; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + struct hash_desc desc; + int ret = 0; +#endif + + if (tfm_michael == NULL){ + printk(KERN_WARNING "michael_mic: tfm_michael == NULL\n"); + return -1; + } + sg[0].page = virt_to_page(hdr); + sg[0].offset = offset_in_page(hdr); + sg[0].length = 16; + + sg[1].page = virt_to_page(data); + sg[1].offset = offset_in_page(data); + sg[1].length = data_len; + + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + crypto_digest_init(tfm_michael); + crypto_digest_setkey(tfm_michael, key, 8); + crypto_digest_update(tfm_michael, sg, 2); + crypto_digest_final(tfm_michael, mic); + return 0; +#else +if (crypto_hash_setkey(tkey->tfm_michael, key, 8)) + return -1; + +// return 0; + desc.tfm = tkey->tfm_michael; + desc.flags = 0; + ret = crypto_hash_digest(&desc, sg, data_len + 16, mic); + return ret; +#endif +} +#else +static int michael_mic(struct crypto_hash *tfm_michael, u8 * key, u8 * hdr, + u8 * data, size_t data_len, u8 * mic) +{ + struct hash_desc desc; + struct scatterlist sg[2]; + + if (tfm_michael == NULL) { + printk(KERN_WARNING "michael_mic: tfm_michael == NULL\n"); + return -1; + } +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) + sg[0].page = virt_to_page(hdr); + sg[0].offset = offset_in_page(hdr); + sg[0].length = 16; + + sg[1].page = virt_to_page(data); + sg[1].offset = offset_in_page(data); + sg[1].length = data_len; +#else + sg_init_table(sg, 2); + sg_set_buf(&sg[0], hdr, 16); + sg_set_buf(&sg[1], data, data_len); +#endif + + if (crypto_hash_setkey(tfm_michael, key, 8)) + return -1; + + desc.tfm = tfm_michael; + desc.flags = 0; + return crypto_hash_digest(&desc, sg, data_len + 16, mic); +} +#endif + + + +static void michael_mic_hdr(struct sk_buff *skb, u8 *hdr) +{ + struct ieee80211_hdr_4addr *hdr11; + + hdr11 = (struct ieee80211_hdr_4addr *) skb->data; + switch (le16_to_cpu(hdr11->frame_ctl) & + (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) { + case IEEE80211_FCTL_TODS: + memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */ + memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */ + break; + case IEEE80211_FCTL_FROMDS: + memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */ + memcpy(hdr + ETH_ALEN, hdr11->addr3, ETH_ALEN); /* SA */ + break; + case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS: + memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */ + memcpy(hdr + ETH_ALEN, hdr11->addr4, ETH_ALEN); /* SA */ + break; + case 0: + memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */ + memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */ + break; + } + + hdr[12] = 0; /* priority */ + + hdr[13] = hdr[14] = hdr[15] = 0; /* reserved */ +} + + +static int ieee80211_michael_mic_add(struct sk_buff *skb, int hdr_len, void *priv) +{ + struct ieee80211_tkip_data *tkey = priv; + u8 *pos; + struct ieee80211_hdr_4addr *hdr; + + hdr = (struct ieee80211_hdr_4addr *) skb->data; + + if (skb_tailroom(skb) < 8 || skb->len < hdr_len) { + printk(KERN_DEBUG "Invalid packet for Michael MIC add " + "(tailroom=%d hdr_len=%d skb->len=%d)\n", + skb_tailroom(skb), hdr_len, skb->len); + return -1; + } + + michael_mic_hdr(skb, tkey->tx_hdr); + + // { david, 2006.9.1 + // fix the wpa process with wmm enabled. + if(IEEE80211_QOS_HAS_SEQ(le16_to_cpu(hdr->frame_ctl))) { + tkey->tx_hdr[12] = *(skb->data + hdr_len - 2) & 0x07; + } + // } + pos = skb_put(skb, 8); +#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED)) + if (michael_mic(tkey->tx_tfm_michael, &tkey->key[16], tkey->tx_hdr, + skb->data + hdr_len, skb->len - 8 - hdr_len, pos)) +#else + if (michael_mic(tkey->tx_tfm_michael, &tkey->key[16], tkey->tx_hdr, + skb->data + hdr_len, skb->len - 8 - hdr_len, pos)) +#endif + return -1; + + return 0; +} + + +#if WIRELESS_EXT >= 18 +static void ieee80211_michael_mic_failure(struct net_device *dev, + struct ieee80211_hdr_4addr *hdr, + int keyidx) +{ + union iwreq_data wrqu; + struct iw_michaelmicfailure ev; + + /* TODO: needed parameters: count, keyid, key type, TSC */ + memset(&ev, 0, sizeof(ev)); + ev.flags = keyidx & IW_MICFAILURE_KEY_ID; + if (hdr->addr1[0] & 0x01) + ev.flags |= IW_MICFAILURE_GROUP; + else + ev.flags |= IW_MICFAILURE_PAIRWISE; + ev.src_addr.sa_family = ARPHRD_ETHER; + memcpy(ev.src_addr.sa_data, hdr->addr2, ETH_ALEN); + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = sizeof(ev); + wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu, (char *) &ev); +} +#elif WIRELESS_EXT >= 15 +static void ieee80211_michael_mic_failure(struct net_device *dev, + struct ieee80211_hdr_4addr *hdr, + int keyidx) +{ + union iwreq_data wrqu; + char buf[128]; + + /* TODO: needed parameters: count, keyid, key type, TSC */ + sprintf(buf, "MLME-MICHAELMICFAILURE.indication(keyid=%d %scast addr=" + MAC_FMT ")", keyidx, hdr->addr1[0] & 0x01 ? "broad" : "uni", + MAC_ARG(hdr->addr2)); + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = strlen(buf); + wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf); +} +#else /* WIRELESS_EXT >= 15 */ +static inline void ieee80211_michael_mic_failure(struct net_device *dev, + struct ieee80211_hdr_4addr *hdr, + int keyidx) +{ +} +#endif /* WIRELESS_EXT >= 15 */ + +static int ieee80211_michael_mic_verify(struct sk_buff *skb, int keyidx, + int hdr_len, void *priv) +{ + struct ieee80211_tkip_data *tkey = priv; + u8 mic[8]; + struct ieee80211_hdr_4addr *hdr; + + hdr = (struct ieee80211_hdr_4addr *) skb->data; + + if (!tkey->key_set) + return -1; + + michael_mic_hdr(skb, tkey->rx_hdr); + // { david, 2006.9.1 + // fix the wpa process with wmm enabled. + if(IEEE80211_QOS_HAS_SEQ(le16_to_cpu(hdr->frame_ctl))) { + tkey->rx_hdr[12] = *(skb->data + hdr_len - 2) & 0x07; + } + // } + +#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED)) + if (michael_mic(tkey->rx_tfm_michael, &tkey->key[24], tkey->rx_hdr, + skb->data + hdr_len, skb->len - 8 - hdr_len, mic)) +#else + if (michael_mic(tkey->rx_tfm_michael, &tkey->key[24], tkey->rx_hdr, + skb->data + hdr_len, skb->len - 8 - hdr_len, mic)) +#endif + return -1; + if (memcmp(mic, skb->data + skb->len - 8, 8) != 0) { + struct ieee80211_hdr_4addr *hdr; + hdr = (struct ieee80211_hdr_4addr *) skb->data; + printk(KERN_DEBUG "%s: Michael MIC verification failed for " + "MSDU from " MAC_FMT " keyidx=%d\n", + skb->dev ? skb->dev->name : "N/A", MAC_ARG(hdr->addr2), + keyidx); + if (skb->dev) + ieee80211_michael_mic_failure(skb->dev, hdr, keyidx); + tkey->dot11RSNAStatsTKIPLocalMICFailures++; + return -1; + } + + /* Update TSC counters for RX now that the packet verification has + * completed. */ + tkey->rx_iv32 = tkey->rx_iv32_new; + tkey->rx_iv16 = tkey->rx_iv16_new; + + skb_trim(skb, skb->len - 8); + + return 0; +} + + +static int ieee80211_tkip_set_key(void *key, int len, u8 *seq, void *priv) +{ + struct ieee80211_tkip_data *tkey = priv; + int keyidx; +#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED)) + struct crypto_tfm *tfm = tkey->tx_tfm_michael; + struct crypto_tfm *tfm2 = tkey->tx_tfm_arc4; + struct crypto_tfm *tfm3 = tkey->rx_tfm_michael; + struct crypto_tfm *tfm4 = tkey->rx_tfm_arc4; +#else + struct crypto_hash *tfm = tkey->tx_tfm_michael; + struct crypto_blkcipher *tfm2 = tkey->tx_tfm_arc4; + struct crypto_hash *tfm3 = tkey->rx_tfm_michael; + struct crypto_blkcipher *tfm4 = tkey->rx_tfm_arc4; +#endif + + keyidx = tkey->key_idx; + memset(tkey, 0, sizeof(*tkey)); + tkey->key_idx = keyidx; +#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED)) + tkey->tx_tfm_michael = tfm; + tkey->tx_tfm_arc4 = tfm2; + tkey->rx_tfm_michael = tfm3; + tkey->rx_tfm_arc4 = tfm4; +#else + tkey->tx_tfm_michael = tfm; + tkey->tx_tfm_arc4 = tfm2; + tkey->rx_tfm_michael = tfm3; + tkey->rx_tfm_arc4 = tfm4; +#endif + + if (len == TKIP_KEY_LEN) { + memcpy(tkey->key, key, TKIP_KEY_LEN); + tkey->key_set = 1; + tkey->tx_iv16 = 1; /* TSC is initialized to 1 */ + if (seq) { + tkey->rx_iv32 = (seq[5] << 24) | (seq[4] << 16) | + (seq[3] << 8) | seq[2]; + tkey->rx_iv16 = (seq[1] << 8) | seq[0]; + } + } else if (len == 0) + tkey->key_set = 0; + else + return -1; + + return 0; +} + + +static int ieee80211_tkip_get_key(void *key, int len, u8 *seq, void *priv) +{ + struct ieee80211_tkip_data *tkey = priv; + + if (len < TKIP_KEY_LEN) + return -1; + + if (!tkey->key_set) + return 0; + memcpy(key, tkey->key, TKIP_KEY_LEN); + + if (seq) { + /* Return the sequence number of the last transmitted frame. */ + u16 iv16 = tkey->tx_iv16; + u32 iv32 = tkey->tx_iv32; + if (iv16 == 0) + iv32--; + iv16--; + seq[0] = tkey->tx_iv16; + seq[1] = tkey->tx_iv16 >> 8; + seq[2] = tkey->tx_iv32; + seq[3] = tkey->tx_iv32 >> 8; + seq[4] = tkey->tx_iv32 >> 16; + seq[5] = tkey->tx_iv32 >> 24; + } + + return TKIP_KEY_LEN; +} + + +static char * ieee80211_tkip_print_stats(char *p, void *priv) +{ + struct ieee80211_tkip_data *tkip = priv; + p += sprintf(p, "key[%d] alg=TKIP key_set=%d " + "tx_pn=%02x%02x%02x%02x%02x%02x " + "rx_pn=%02x%02x%02x%02x%02x%02x " + "replays=%d icv_errors=%d local_mic_failures=%d\n", + tkip->key_idx, tkip->key_set, + (tkip->tx_iv32 >> 24) & 0xff, + (tkip->tx_iv32 >> 16) & 0xff, + (tkip->tx_iv32 >> 8) & 0xff, + tkip->tx_iv32 & 0xff, + (tkip->tx_iv16 >> 8) & 0xff, + tkip->tx_iv16 & 0xff, + (tkip->rx_iv32 >> 24) & 0xff, + (tkip->rx_iv32 >> 16) & 0xff, + (tkip->rx_iv32 >> 8) & 0xff, + tkip->rx_iv32 & 0xff, + (tkip->rx_iv16 >> 8) & 0xff, + tkip->rx_iv16 & 0xff, + tkip->dot11RSNAStatsTKIPReplays, + tkip->dot11RSNAStatsTKIPICVErrors, + tkip->dot11RSNAStatsTKIPLocalMICFailures); + return p; +} + + +static struct ieee80211_crypto_ops ieee80211_crypt_tkip = { + .name = "TKIP", + .init = ieee80211_tkip_init, + .deinit = ieee80211_tkip_deinit, + .encrypt_mpdu = ieee80211_tkip_encrypt, + .decrypt_mpdu = ieee80211_tkip_decrypt, + .encrypt_msdu = ieee80211_michael_mic_add, + .decrypt_msdu = ieee80211_michael_mic_verify, + .set_key = ieee80211_tkip_set_key, + .get_key = ieee80211_tkip_get_key, + .print_stats = ieee80211_tkip_print_stats, + .extra_prefix_len = 4 + 4, /* IV + ExtIV */ + .extra_postfix_len = 8 + 4, /* MIC + ICV */ + .owner = THIS_MODULE, +}; + + +static int __init ieee80211_crypto_tkip_init(void) +{ + return ieee80211_register_crypto_ops(&ieee80211_crypt_tkip); +} + + +static void __exit ieee80211_crypto_tkip_exit(void) +{ + ieee80211_unregister_crypto_ops(&ieee80211_crypt_tkip); +} + +void ieee80211_tkip_null(void) +{ +// printk("============>%s()\n", __FUNCTION__); + return; +} +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) +EXPORT_SYMBOL(ieee80211_tkip_null); +#else +EXPORT_SYMBOL_NOVERS(ieee80211_tkip_null); +#endif + +module_init(ieee80211_crypto_tkip_init); +module_exit(ieee80211_crypto_tkip_exit); diff --git a/drivers/staging/rtl8192su/ieee80211/ieee80211_crypt_wep.c b/drivers/staging/rtl8192su/ieee80211/ieee80211_crypt_wep.c new file mode 100644 index 000000000000..7e394328ec90 --- /dev/null +++ b/drivers/staging/rtl8192su/ieee80211/ieee80211_crypt_wep.c @@ -0,0 +1,397 @@ +/* + * Host AP crypt: host-based WEP encryption implementation for Host AP driver + * + * Copyright (c) 2002-2004, Jouni Malinen + * + * 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. See README and COPYING for + * more details. + */ + +//#include +#include +#include +#include +#include +#include +#include +#include + +#include "ieee80211.h" + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,20)) +//#include "crypto_compat.h" +#endif + + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) +#include "rtl_crypto.h" +#else +#include +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + #include +#else + #include +#endif +//#include +#include +// +/* +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) +#include "rtl_crypto.h" +#else +#include +#endif + +#include +#include +*/ +MODULE_AUTHOR("Jouni Malinen"); +MODULE_DESCRIPTION("Host AP crypt: WEP"); +MODULE_LICENSE("GPL"); +#ifndef OPENSUSE_SLED +#define OPENSUSE_SLED 0 +#endif + +struct prism2_wep_data { + u32 iv; +#define WEP_KEY_LEN 13 + u8 key[WEP_KEY_LEN + 1]; + u8 key_len; + u8 key_idx; +#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED)) + struct crypto_tfm *tfm; + #else + struct crypto_blkcipher *tx_tfm; + struct crypto_blkcipher *rx_tfm; + #endif +}; + + +static void * prism2_wep_init(int keyidx) +{ + struct prism2_wep_data *priv; + + priv = kmalloc(sizeof(*priv), GFP_ATOMIC); + if (priv == NULL) + goto fail; + memset(priv, 0, sizeof(*priv)); + priv->key_idx = keyidx; + +#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED)) + priv->tfm = crypto_alloc_tfm("arc4", 0); + if (priv->tfm == NULL) { + printk(KERN_DEBUG "ieee80211_crypt_wep: could not allocate " + "crypto API arc4\n"); + goto fail; + } + #else + priv->tx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(priv->tx_tfm)) { + printk(KERN_DEBUG "ieee80211_crypt_wep: could not allocate " + "crypto API arc4\n"); + priv->tx_tfm = NULL; + goto fail; + } + priv->rx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(priv->rx_tfm)) { + printk(KERN_DEBUG "ieee80211_crypt_wep: could not allocate " + "crypto API arc4\n"); + priv->rx_tfm = NULL; + goto fail; + } + #endif + + /* start WEP IV from a random value */ + get_random_bytes(&priv->iv, 4); + + return priv; + +fail: +#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED)) + if (priv) { + if (priv->tfm) + crypto_free_tfm(priv->tfm); + kfree(priv); + } + #else + if (priv) { + if (priv->tx_tfm) + crypto_free_blkcipher(priv->tx_tfm); + if (priv->rx_tfm) + crypto_free_blkcipher(priv->rx_tfm); + kfree(priv); + } + #endif + return NULL; +} + + +static void prism2_wep_deinit(void *priv) +{ + struct prism2_wep_data *_priv = priv; +#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED)) + if (_priv && _priv->tfm) + crypto_free_tfm(_priv->tfm); + #else + if (_priv) { + if (_priv->tx_tfm) + crypto_free_blkcipher(_priv->tx_tfm); + if (_priv->rx_tfm) + crypto_free_blkcipher(_priv->rx_tfm); + } + #endif + kfree(priv); +} + +/* Perform WEP encryption on given skb that has at least 4 bytes of headroom + * for IV and 4 bytes of tailroom for ICV. Both IV and ICV will be transmitted, + * so the payload length increases with 8 bytes. + * + * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data)) + */ +static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv) +{ + struct prism2_wep_data *wep = priv; + u32 klen, len; + u8 key[WEP_KEY_LEN + 3]; + u8 *pos; + cb_desc *tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE); + #if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)) || (OPENSUSE_SLED)) + struct blkcipher_desc desc = {.tfm = wep->tx_tfm}; + #endif + u32 crc; + u8 *icv; + struct scatterlist sg; + if (skb_headroom(skb) < 4 || skb_tailroom(skb) < 4 || + skb->len < hdr_len) + return -1; + + len = skb->len - hdr_len; + pos = skb_push(skb, 4); + memmove(pos, pos + 4, hdr_len); + pos += hdr_len; + + klen = 3 + wep->key_len; + + wep->iv++; + + /* Fluhrer, Mantin, and Shamir have reported weaknesses in the key + * scheduling algorithm of RC4. At least IVs (KeyByte + 3, 0xff, N) + * can be used to speedup attacks, so avoid using them. */ + if ((wep->iv & 0xff00) == 0xff00) { + u8 B = (wep->iv >> 16) & 0xff; + if (B >= 3 && B < klen) + wep->iv += 0x0100; + } + + /* Prepend 24-bit IV to RC4 key and TX frame */ + *pos++ = key[0] = (wep->iv >> 16) & 0xff; + *pos++ = key[1] = (wep->iv >> 8) & 0xff; + *pos++ = key[2] = wep->iv & 0xff; + *pos++ = wep->key_idx << 6; + + /* Copy rest of the WEP key (the secret part) */ + memcpy(key + 3, wep->key, wep->key_len); + + if (!tcb_desc->bHwSec) + { + + /* Append little-endian CRC32 and encrypt it to produce ICV */ + #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) + crc = ~crc32_le(~0, pos, len); + #else + crc = ~ether_crc_le(len, pos); + #endif + icv = skb_put(skb, 4); + icv[0] = crc; + icv[1] = crc >> 8; + icv[2] = crc >> 16; + icv[3] = crc >> 24; + +#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED)) + crypto_cipher_setkey(wep->tfm, key, klen); + sg.page = virt_to_page(pos); + sg.offset = offset_in_page(pos); + sg.length = len + 4; + crypto_cipher_encrypt(wep->tfm, &sg, &sg, len + 4); + return 0; + #else + crypto_blkcipher_setkey(wep->tx_tfm, key, klen); + #if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) + sg.page = virt_to_page(pos); + sg.offset = offset_in_page(pos); + sg.length = len + 4; + #else + sg_init_one(&sg, pos, len+4); + #endif + return crypto_blkcipher_encrypt(&desc, &sg, &sg, len + 4); + #endif + } + + return 0; +} + + +/* Perform WEP decryption on given buffer. Buffer includes whole WEP part of + * the frame: IV (4 bytes), encrypted payload (including SNAP header), + * ICV (4 bytes). len includes both IV and ICV. + * + * Returns 0 if frame was decrypted successfully and ICV was correct and -1 on + * failure. If frame is OK, IV and ICV will be removed. + */ +static int prism2_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv) +{ + struct prism2_wep_data *wep = priv; + u32 klen, plen; + u8 key[WEP_KEY_LEN + 3]; + u8 keyidx, *pos; + cb_desc *tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE); + #if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)) || (OPENSUSE_SLED)) + struct blkcipher_desc desc = {.tfm = wep->rx_tfm}; + #endif + u32 crc; + u8 icv[4]; + struct scatterlist sg; + if (skb->len < hdr_len + 8) + return -1; + + pos = skb->data + hdr_len; + key[0] = *pos++; + key[1] = *pos++; + key[2] = *pos++; + keyidx = *pos++ >> 6; + if (keyidx != wep->key_idx) + return -1; + + klen = 3 + wep->key_len; + + /* Copy rest of the WEP key (the secret part) */ + memcpy(key + 3, wep->key, wep->key_len); + + /* Apply RC4 to data and compute CRC32 over decrypted data */ + plen = skb->len - hdr_len - 8; + + if (!tcb_desc->bHwSec) + { +#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED)) + crypto_cipher_setkey(wep->tfm, key, klen); + sg.page = virt_to_page(pos); + sg.offset = offset_in_page(pos); + sg.length = plen + 4; + crypto_cipher_decrypt(wep->tfm, &sg, &sg, plen + 4); + #else + crypto_blkcipher_setkey(wep->rx_tfm, key, klen); + #if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) + sg.page = virt_to_page(pos); + sg.offset = offset_in_page(pos); + sg.length = plen + 4; + #else + sg_init_one(&sg, pos, plen+4); + #endif + if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4)) + return -7; + #endif + #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) + crc = ~crc32_le(~0, pos, plen); + #else + crc = ~ether_crc_le(plen, pos); + #endif + icv[0] = crc; + icv[1] = crc >> 8; + icv[2] = crc >> 16; + icv[3] = crc >> 24; + if (memcmp(icv, pos + plen, 4) != 0) { + /* ICV mismatch - drop frame */ + return -2; + } + } + /* Remove IV and ICV */ + memmove(skb->data + 4, skb->data, hdr_len); + skb_pull(skb, 4); + skb_trim(skb, skb->len - 4); + + return 0; +} + + +static int prism2_wep_set_key(void *key, int len, u8 *seq, void *priv) +{ + struct prism2_wep_data *wep = priv; + + if (len < 0 || len > WEP_KEY_LEN) + return -1; + + memcpy(wep->key, key, len); + wep->key_len = len; + + return 0; +} + + +static int prism2_wep_get_key(void *key, int len, u8 *seq, void *priv) +{ + struct prism2_wep_data *wep = priv; + + if (len < wep->key_len) + return -1; + + memcpy(key, wep->key, wep->key_len); + + return wep->key_len; +} + + +static char * prism2_wep_print_stats(char *p, void *priv) +{ + struct prism2_wep_data *wep = priv; + p += sprintf(p, "key[%d] alg=WEP len=%d\n", + wep->key_idx, wep->key_len); + return p; +} + + +static struct ieee80211_crypto_ops ieee80211_crypt_wep = { + .name = "WEP", + .init = prism2_wep_init, + .deinit = prism2_wep_deinit, + .encrypt_mpdu = prism2_wep_encrypt, + .decrypt_mpdu = prism2_wep_decrypt, + .encrypt_msdu = NULL, + .decrypt_msdu = NULL, + .set_key = prism2_wep_set_key, + .get_key = prism2_wep_get_key, + .print_stats = prism2_wep_print_stats, + .extra_prefix_len = 4, /* IV */ + .extra_postfix_len = 4, /* ICV */ + .owner = THIS_MODULE, +}; + + +static int __init ieee80211_crypto_wep_init(void) +{ + return ieee80211_register_crypto_ops(&ieee80211_crypt_wep); +} + + +static void __exit ieee80211_crypto_wep_exit(void) +{ + ieee80211_unregister_crypto_ops(&ieee80211_crypt_wep); +} + +void ieee80211_wep_null(void) +{ +// printk("============>%s()\n", __FUNCTION__); + return; +} +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) +EXPORT_SYMBOL(ieee80211_wep_null); +#else +EXPORT_SYMBOL_NOVERS(ieee80211_wep_null); +#endif + +module_init(ieee80211_crypto_wep_init); +module_exit(ieee80211_crypto_wep_exit); diff --git a/drivers/staging/rtl8192su/ieee80211/ieee80211_module.c b/drivers/staging/rtl8192su/ieee80211/ieee80211_module.c new file mode 100644 index 000000000000..f408b4583b82 --- /dev/null +++ b/drivers/staging/rtl8192su/ieee80211/ieee80211_module.c @@ -0,0 +1,394 @@ +/******************************************************************************* + + Copyright(c) 2004 Intel Corporation. All rights reserved. + + Portions of this file are based on the WEP enablement code provided by the + Host AP project hostap-drivers v0.1.3 + Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen + + Copyright (c) 2002-2003, Jouni Malinen + + 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., 59 + Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + The full GNU General Public License is included in this distribution in the + file called LICENSE. + + Contact Information: + James P. Ketrenos + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#include +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ieee80211.h" + +MODULE_DESCRIPTION("802.11 data/management/control stack"); +MODULE_AUTHOR("Copyright (C) 2004 Intel Corporation "); +MODULE_LICENSE("GPL"); + +#define DRV_NAME "ieee80211" + +static inline int ieee80211_networks_allocate(struct ieee80211_device *ieee) +{ + if (ieee->networks) + return 0; + + ieee->networks = kmalloc( + MAX_NETWORK_COUNT * sizeof(struct ieee80211_network), + GFP_KERNEL); + if (!ieee->networks) { + printk(KERN_WARNING "%s: Out of memory allocating beacons\n", + ieee->dev->name); + return -ENOMEM; + } + + memset(ieee->networks, 0, + MAX_NETWORK_COUNT * sizeof(struct ieee80211_network)); + + return 0; +} + +static inline void ieee80211_networks_free(struct ieee80211_device *ieee) +{ + if (!ieee->networks) + return; + kfree(ieee->networks); + ieee->networks = NULL; +} + +static inline void ieee80211_networks_initialize(struct ieee80211_device *ieee) +{ + int i; + + INIT_LIST_HEAD(&ieee->network_free_list); + INIT_LIST_HEAD(&ieee->network_list); + for (i = 0; i < MAX_NETWORK_COUNT; i++) + list_add_tail(&ieee->networks[i].list, &ieee->network_free_list); +} + + +struct net_device *alloc_ieee80211(int sizeof_priv) +{ + struct ieee80211_device *ieee; + struct net_device *dev; + int i,err; + + IEEE80211_DEBUG_INFO("Initializing...\n"); + + dev = alloc_etherdev(sizeof(struct ieee80211_device) + sizeof_priv); + if (!dev) { + IEEE80211_ERROR("Unable to network device.\n"); + goto failed; + } + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)) + ieee = netdev_priv(dev); +#else + ieee = (struct ieee80211_device *)dev->priv; +#endif + dev->hard_start_xmit = ieee80211_xmit; + + memset(ieee, 0, sizeof(struct ieee80211_device)+sizeof_priv); + ieee->dev = dev; + + err = ieee80211_networks_allocate(ieee); + if (err) { + IEEE80211_ERROR("Unable to allocate beacon storage: %d\n", + err); + goto failed; + } + ieee80211_networks_initialize(ieee); + + + /* Default fragmentation threshold is maximum payload size */ + ieee->fts = DEFAULT_FTS; + ieee->scan_age = DEFAULT_MAX_SCAN_AGE; + ieee->open_wep = 1; + + /* Default to enabling full open WEP with host based encrypt/decrypt */ + ieee->host_encrypt = 1; + ieee->host_decrypt = 1; + ieee->ieee802_1x = 1; /* Default to supporting 802.1x */ + + INIT_LIST_HEAD(&ieee->crypt_deinit_list); + init_timer(&ieee->crypt_deinit_timer); + ieee->crypt_deinit_timer.data = (unsigned long)ieee; + ieee->crypt_deinit_timer.function = ieee80211_crypt_deinit_handler; + + spin_lock_init(&ieee->lock); + spin_lock_init(&ieee->wpax_suitlist_lock); + spin_lock_init(&ieee->bw_spinlock); + spin_lock_init(&ieee->reorder_spinlock); + //added by WB + atomic_set(&(ieee->atm_chnlop), 0); + atomic_set(&(ieee->atm_swbw), 0); + + ieee->wpax_type_set = 0; + ieee->wpa_enabled = 0; + ieee->tkip_countermeasures = 0; + ieee->drop_unencrypted = 0; + ieee->privacy_invoked = 0; + ieee->ieee802_1x = 1; + ieee->raw_tx = 0; + //ieee->hwsec_support = 1; //defalt support hw security. //use module_param instead. + ieee->hwsec_active = 0; //disable hwsec, switch it on when necessary. + + ieee80211_softmac_init(ieee); + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13)) + ieee->pHTInfo = (RT_HIGH_THROUGHPUT*)kzalloc(sizeof(RT_HIGH_THROUGHPUT), GFP_KERNEL); +#else + ieee->pHTInfo = (RT_HIGH_THROUGHPUT*)kmalloc(sizeof(RT_HIGH_THROUGHPUT), GFP_KERNEL); + memset(ieee->pHTInfo,0,sizeof(RT_HIGH_THROUGHPUT)); +#endif + if (ieee->pHTInfo == NULL) + { + IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't alloc memory for HTInfo\n"); + return NULL; + } + HTUpdateDefaultSetting(ieee); + HTInitializeHTInfo(ieee); //may move to other place. + TSInitialize(ieee); +#if 0 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) + INIT_WORK(&ieee->ht_onAssRsp, (void(*)(void*)) HTOnAssocRsp_wq); +#else + INIT_WORK(&ieee->ht_onAssRsp, (void(*)(void*)) HTOnAssocRsp_wq, ieee); +#endif +#endif + for (i = 0; i < IEEE_IBSS_MAC_HASH_SIZE; i++) + INIT_LIST_HEAD(&ieee->ibss_mac_hash[i]); + + for (i = 0; i < 17; i++) { + ieee->last_rxseq_num[i] = -1; + ieee->last_rxfrag_num[i] = -1; + ieee->last_packet_time[i] = 0; + } + +//These function were added to load crypte module autoly + ieee80211_tkip_null(); + ieee80211_wep_null(); + ieee80211_ccmp_null(); + + return dev; + + failed: + if (dev) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)) + free_netdev(dev); +#else + kfree(dev); +#endif + return NULL; +} + + +void free_ieee80211(struct net_device *dev) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)) + struct ieee80211_device *ieee = netdev_priv(dev); +#else + struct ieee80211_device *ieee = (struct ieee80211_device *)dev->priv; +#endif + int i; + //struct list_head *p, *q; +// del_timer_sync(&ieee->SwBwTimer); +#if 1 + if (ieee->pHTInfo != NULL) + { + kfree(ieee->pHTInfo); + ieee->pHTInfo = NULL; + } +#endif + RemoveAllTS(ieee); + ieee80211_softmac_free(ieee); + del_timer_sync(&ieee->crypt_deinit_timer); + ieee80211_crypt_deinit_entries(ieee, 1); + + for (i = 0; i < WEP_KEYS; i++) { + struct ieee80211_crypt_data *crypt = ieee->crypt[i]; + if (crypt) { + if (crypt->ops) { + crypt->ops->deinit(crypt->priv); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + module_put(crypt->ops->owner); +#else + __MOD_DEC_USE_COUNT(crypt->ops->owner); +#endif + } + kfree(crypt); + ieee->crypt[i] = NULL; + } + } + + ieee80211_networks_free(ieee); +#if 0 + for (i = 0; i < IEEE_IBSS_MAC_HASH_SIZE; i++) { + list_for_each_safe(p, q, &ieee->ibss_mac_hash[i]) { + kfree(list_entry(p, struct ieee_ibss_seq, list)); + list_del(p); + } + } + +#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)) + free_netdev(dev); +#else + kfree(dev); +#endif +} + +#ifdef CONFIG_IEEE80211_DEBUG + +u32 ieee80211_debug_level = 0; +static int debug = \ + // IEEE80211_DL_INFO | + // IEEE80211_DL_WX | + // IEEE80211_DL_SCAN | + // IEEE80211_DL_STATE | + // IEEE80211_DL_MGMT | + // IEEE80211_DL_FRAG | + // IEEE80211_DL_EAP | + // IEEE80211_DL_DROP | + // IEEE80211_DL_TX | + // IEEE80211_DL_RX | + //IEEE80211_DL_QOS | + // IEEE80211_DL_HT | + // IEEE80211_DL_TS | +// IEEE80211_DL_BA | + // IEEE80211_DL_REORDER| +// IEEE80211_DL_TRACE | + //IEEE80211_DL_DATA | + IEEE80211_DL_ERR //awayls open this flags to show error out + ; +struct proc_dir_entry *ieee80211_proc = NULL; + +static int show_debug_level(char *page, char **start, off_t offset, + int count, int *eof, void *data) +{ + return snprintf(page, count, "0x%08X\n", ieee80211_debug_level); +} + +static int store_debug_level(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char buf[] = "0x00000000"; + unsigned long len = min(sizeof(buf) - 1, (u32)count); + char *p = (char *)buf; + unsigned long val; + + if (copy_from_user(buf, buffer, len)) + return count; + buf[len] = 0; + if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') { + p++; + if (p[0] == 'x' || p[0] == 'X') + p++; + val = simple_strtoul(p, &p, 16); + } else + val = simple_strtoul(p, &p, 10); + if (p == buf) + printk(KERN_INFO DRV_NAME + ": %s is not in hex or decimal form.\n", buf); + else + ieee80211_debug_level = val; + + return strnlen(buf, count); +} + +static int __init ieee80211_init(void) +{ + struct proc_dir_entry *e; + + ieee80211_debug_level = debug; +#if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) + ieee80211_proc = create_proc_entry(DRV_NAME, S_IFDIR, proc_net); +#else + ieee80211_proc = create_proc_entry(DRV_NAME, S_IFDIR, init_net.proc_net); +#endif + if (ieee80211_proc == NULL) { + IEEE80211_ERROR("Unable to create " DRV_NAME + " proc directory\n"); + return -EIO; + } + e = create_proc_entry("debug_level", S_IFREG | S_IRUGO | S_IWUSR, + ieee80211_proc); + if (!e) { +#if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) + remove_proc_entry(DRV_NAME, proc_net); +#else + remove_proc_entry(DRV_NAME, init_net.proc_net); +#endif + ieee80211_proc = NULL; + return -EIO; + } + e->read_proc = show_debug_level; + e->write_proc = store_debug_level; + e->data = NULL; + + return 0; +} + +static void __exit ieee80211_exit(void) +{ + if (ieee80211_proc) { + remove_proc_entry("debug_level", ieee80211_proc); +#if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) + remove_proc_entry(DRV_NAME, proc_net); +#else + remove_proc_entry(DRV_NAME, init_net.proc_net); +#endif + ieee80211_proc = NULL; + } +} + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) +#include +module_param(debug, int, 0444); +MODULE_PARM_DESC(debug, "debug output mask"); + + +module_exit(ieee80211_exit); +module_init(ieee80211_init); +#endif +#endif + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) +EXPORT_SYMBOL(alloc_ieee80211); +EXPORT_SYMBOL(free_ieee80211); +#else +EXPORT_SYMBOL_NOVERS(alloc_ieee80211); +EXPORT_SYMBOL_NOVERS(free_ieee80211); +#endif diff --git a/drivers/staging/rtl8192su/ieee80211/ieee80211_rx.c b/drivers/staging/rtl8192su/ieee80211/ieee80211_rx.c new file mode 100644 index 000000000000..2b2ffd34bc92 --- /dev/null +++ b/drivers/staging/rtl8192su/ieee80211/ieee80211_rx.c @@ -0,0 +1,2832 @@ +/* + * Original code based Host AP (software wireless LAN access point) driver + * for Intersil Prism2/2.5/3 - hostap.o module, common routines + * + * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen + * + * Copyright (c) 2002-2003, Jouni Malinen + * Copyright (c) 2004, Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. See README and COPYING for + * more details. + ****************************************************************************** + + Few modifications for Realtek's Wi-Fi drivers by + Andrea Merello + + A special thanks goes to Realtek for their support ! + +******************************************************************************/ + + +#include +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ieee80211.h" +#ifdef ENABLE_DOT11D +#include "dot11d.h" +#endif +static inline void ieee80211_monitor_rx(struct ieee80211_device *ieee, + struct sk_buff *skb, + struct ieee80211_rx_stats *rx_stats) +{ + struct ieee80211_hdr_4addr *hdr = (struct ieee80211_hdr_4addr *)skb->data; + u16 fc = le16_to_cpu(hdr->frame_ctl); + + skb->dev = ieee->dev; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) + skb_reset_mac_header(skb); +#else + skb->mac.raw = skb->data; +#endif + + skb_pull(skb, ieee80211_get_hdrlen(fc)); + skb->pkt_type = PACKET_OTHERHOST; + skb->protocol = __constant_htons(ETH_P_80211_RAW); + memset(skb->cb, 0, sizeof(skb->cb)); + netif_rx(skb); +} + + +/* Called only as a tasklet (software IRQ) */ +static struct ieee80211_frag_entry * +ieee80211_frag_cache_find(struct ieee80211_device *ieee, unsigned int seq, + unsigned int frag, u8 tid,u8 *src, u8 *dst) +{ + struct ieee80211_frag_entry *entry; + int i; + + for (i = 0; i < IEEE80211_FRAG_CACHE_LEN; i++) { + entry = &ieee->frag_cache[tid][i]; + if (entry->skb != NULL && + time_after(jiffies, entry->first_frag_time + 2 * HZ)) { + IEEE80211_DEBUG_FRAG( + "expiring fragment cache entry " + "seq=%u last_frag=%u\n", + entry->seq, entry->last_frag); + dev_kfree_skb_any(entry->skb); + entry->skb = NULL; + } + + if (entry->skb != NULL && entry->seq == seq && + (entry->last_frag + 1 == frag || frag == -1) && + memcmp(entry->src_addr, src, ETH_ALEN) == 0 && + memcmp(entry->dst_addr, dst, ETH_ALEN) == 0) + return entry; + } + + return NULL; +} + +/* Called only as a tasklet (software IRQ) */ +static struct sk_buff * +ieee80211_frag_cache_get(struct ieee80211_device *ieee, + struct ieee80211_hdr_4addr *hdr) +{ + struct sk_buff *skb = NULL; + u16 fc = le16_to_cpu(hdr->frame_ctl); + u16 sc = le16_to_cpu(hdr->seq_ctl); + unsigned int frag = WLAN_GET_SEQ_FRAG(sc); + unsigned int seq = WLAN_GET_SEQ_SEQ(sc); + struct ieee80211_frag_entry *entry; + struct ieee80211_hdr_3addrqos *hdr_3addrqos; + struct ieee80211_hdr_4addrqos *hdr_4addrqos; + u8 tid; + + if (((fc & IEEE80211_FCTL_DSTODS) == IEEE80211_FCTL_DSTODS)&&IEEE80211_QOS_HAS_SEQ(fc)) { + hdr_4addrqos = (struct ieee80211_hdr_4addrqos *)hdr; + tid = le16_to_cpu(hdr_4addrqos->qos_ctl) & IEEE80211_QCTL_TID; + tid = UP2AC(tid); + tid ++; + } else if (IEEE80211_QOS_HAS_SEQ(fc)) { + hdr_3addrqos = (struct ieee80211_hdr_3addrqos *)hdr; + tid = le16_to_cpu(hdr_3addrqos->qos_ctl) & IEEE80211_QCTL_TID; + tid = UP2AC(tid); + tid ++; + } else { + tid = 0; + } + + if (frag == 0) { + /* Reserve enough space to fit maximum frame length */ + skb = dev_alloc_skb(ieee->dev->mtu + + sizeof(struct ieee80211_hdr_4addr) + + 8 /* LLC */ + + 2 /* alignment */ + + 8 /* WEP */ + + ETH_ALEN /* WDS */ + + (IEEE80211_QOS_HAS_SEQ(fc)?2:0) /* QOS Control */); + if (skb == NULL) + return NULL; + + entry = &ieee->frag_cache[tid][ieee->frag_next_idx[tid]]; + ieee->frag_next_idx[tid]++; + if (ieee->frag_next_idx[tid] >= IEEE80211_FRAG_CACHE_LEN) + ieee->frag_next_idx[tid] = 0; + + if (entry->skb != NULL) + dev_kfree_skb_any(entry->skb); + + entry->first_frag_time = jiffies; + entry->seq = seq; + entry->last_frag = frag; + entry->skb = skb; + memcpy(entry->src_addr, hdr->addr2, ETH_ALEN); + memcpy(entry->dst_addr, hdr->addr1, ETH_ALEN); + } else { + /* received a fragment of a frame for which the head fragment + * should have already been received */ + entry = ieee80211_frag_cache_find(ieee, seq, frag, tid,hdr->addr2, + hdr->addr1); + if (entry != NULL) { + entry->last_frag = frag; + skb = entry->skb; + } + } + + return skb; +} + + +/* Called only as a tasklet (software IRQ) */ +static int ieee80211_frag_cache_invalidate(struct ieee80211_device *ieee, + struct ieee80211_hdr_4addr *hdr) +{ + u16 fc = le16_to_cpu(hdr->frame_ctl); + u16 sc = le16_to_cpu(hdr->seq_ctl); + unsigned int seq = WLAN_GET_SEQ_SEQ(sc); + struct ieee80211_frag_entry *entry; + struct ieee80211_hdr_3addrqos *hdr_3addrqos; + struct ieee80211_hdr_4addrqos *hdr_4addrqos; + u8 tid; + + if(((fc & IEEE80211_FCTL_DSTODS) == IEEE80211_FCTL_DSTODS)&&IEEE80211_QOS_HAS_SEQ(fc)) { + hdr_4addrqos = (struct ieee80211_hdr_4addrqos *)hdr; + tid = le16_to_cpu(hdr_4addrqos->qos_ctl) & IEEE80211_QCTL_TID; + tid = UP2AC(tid); + tid ++; + } else if (IEEE80211_QOS_HAS_SEQ(fc)) { + hdr_3addrqos = (struct ieee80211_hdr_3addrqos *)hdr; + tid = le16_to_cpu(hdr_3addrqos->qos_ctl) & IEEE80211_QCTL_TID; + tid = UP2AC(tid); + tid ++; + } else { + tid = 0; + } + + entry = ieee80211_frag_cache_find(ieee, seq, -1, tid,hdr->addr2, + hdr->addr1); + + if (entry == NULL) { + IEEE80211_DEBUG_FRAG( + "could not invalidate fragment cache " + "entry (seq=%u)\n", seq); + return -1; + } + + entry->skb = NULL; + return 0; +} + + + +/* ieee80211_rx_frame_mgtmt + * + * Responsible for handling management control frames + * + * Called by ieee80211_rx */ +static inline int +ieee80211_rx_frame_mgmt(struct ieee80211_device *ieee, struct sk_buff *skb, + struct ieee80211_rx_stats *rx_stats, u16 type, + u16 stype) +{ + /* On the struct stats definition there is written that + * this is not mandatory.... but seems that the probe + * response parser uses it + */ + struct ieee80211_hdr_3addr * hdr = (struct ieee80211_hdr_3addr *)skb->data; + + rx_stats->len = skb->len; + ieee80211_rx_mgt(ieee,(struct ieee80211_hdr_4addr *)skb->data,rx_stats); + //if ((ieee->state == IEEE80211_LINKED) && (memcmp(hdr->addr3, ieee->current_network.bssid, ETH_ALEN))) + if ((memcmp(hdr->addr1, ieee->dev->dev_addr, ETH_ALEN)))//use ADDR1 to perform address matching for Management frames + { + dev_kfree_skb_any(skb); + return 0; + } + + ieee80211_rx_frame_softmac(ieee, skb, rx_stats, type, stype); + + dev_kfree_skb_any(skb); + + return 0; + + #ifdef NOT_YET + if (ieee->iw_mode == IW_MODE_MASTER) { + printk(KERN_DEBUG "%s: Master mode not yet suppported.\n", + ieee->dev->name); + return 0; +/* + hostap_update_sta_ps(ieee, (struct hostap_ieee80211_hdr_4addr *) + skb->data);*/ + } + + if (ieee->hostapd && type == IEEE80211_TYPE_MGMT) { + if (stype == WLAN_FC_STYPE_BEACON && + ieee->iw_mode == IW_MODE_MASTER) { + struct sk_buff *skb2; + /* Process beacon frames also in kernel driver to + * update STA(AP) table statistics */ + skb2 = skb_clone(skb, GFP_ATOMIC); + if (skb2) + hostap_rx(skb2->dev, skb2, rx_stats); + } + + /* send management frames to the user space daemon for + * processing */ + ieee->apdevstats.rx_packets++; + ieee->apdevstats.rx_bytes += skb->len; + prism2_rx_80211(ieee->apdev, skb, rx_stats, PRISM2_RX_MGMT); + return 0; + } + + if (ieee->iw_mode == IW_MODE_MASTER) { + if (type != WLAN_FC_TYPE_MGMT && type != WLAN_FC_TYPE_CTRL) { + printk(KERN_DEBUG "%s: unknown management frame " + "(type=0x%02x, stype=0x%02x) dropped\n", + skb->dev->name, type, stype); + return -1; + } + + hostap_rx(skb->dev, skb, rx_stats); + return 0; + } + + printk(KERN_DEBUG "%s: hostap_rx_frame_mgmt: management frame " + "received in non-Host AP mode\n", skb->dev->name); + return -1; + #endif +} + + + +/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ +/* Ethernet-II snap header (RFC1042 for most EtherTypes) */ +static unsigned char rfc1042_header[] = +{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; +/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ +static unsigned char bridge_tunnel_header[] = +{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; +/* No encapsulation header if EtherType < 0x600 (=length) */ + +/* Called by ieee80211_rx_frame_decrypt */ +static int ieee80211_is_eapol_frame(struct ieee80211_device *ieee, + struct sk_buff *skb, size_t hdrlen) +{ + struct net_device *dev = ieee->dev; + u16 fc, ethertype; + struct ieee80211_hdr_4addr *hdr; + u8 *pos; + + if (skb->len < 24) + return 0; + + hdr = (struct ieee80211_hdr_4addr *) skb->data; + fc = le16_to_cpu(hdr->frame_ctl); + + /* check that the frame is unicast frame to us */ + if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == + IEEE80211_FCTL_TODS && + memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0 && + memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN) == 0) { + /* ToDS frame with own addr BSSID and DA */ + } else if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == + IEEE80211_FCTL_FROMDS && + memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0) { + /* FromDS frame with own addr as DA */ + } else + return 0; + + if (skb->len < 24 + 8) + return 0; + + /* check for port access entity Ethernet type */ +// pos = skb->data + 24; + pos = skb->data + hdrlen; + ethertype = (pos[6] << 8) | pos[7]; + if (ethertype == ETH_P_PAE) + return 1; + + return 0; +} + +/* Called only as a tasklet (software IRQ), by ieee80211_rx */ +static inline int +ieee80211_rx_frame_decrypt(struct ieee80211_device* ieee, struct sk_buff *skb, + struct ieee80211_crypt_data *crypt) +{ + struct ieee80211_hdr_4addr *hdr; + int res, hdrlen; + + if (crypt == NULL || crypt->ops->decrypt_mpdu == NULL) + return 0; +#if 1 + if (ieee->hwsec_active) + { + cb_desc *tcb_desc = (cb_desc *)(skb->cb+ MAX_DEV_ADDR_SIZE); + tcb_desc->bHwSec = 1; + } +#endif + hdr = (struct ieee80211_hdr_4addr *) skb->data; + hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); + +#ifdef CONFIG_IEEE80211_CRYPT_TKIP + if (ieee->tkip_countermeasures && + strcmp(crypt->ops->name, "TKIP") == 0) { + if (net_ratelimit()) { + printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " + "received packet from " MAC_FMT "\n", + ieee->dev->name, MAC_ARG(hdr->addr2)); + } + return -1; + } +#endif + + atomic_inc(&crypt->refcnt); + res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv); + atomic_dec(&crypt->refcnt); + if (res < 0) { + IEEE80211_DEBUG_DROP( + "decryption failed (SA=" MAC_FMT + ") res=%d\n", MAC_ARG(hdr->addr2), res); + if (res == -2) + IEEE80211_DEBUG_DROP("Decryption failed ICV " + "mismatch (key %d)\n", + skb->data[hdrlen + 3] >> 6); + ieee->ieee_stats.rx_discards_undecryptable++; + return -1; + } + + return res; +} + + +/* Called only as a tasklet (software IRQ), by ieee80211_rx */ +static inline int +ieee80211_rx_frame_decrypt_msdu(struct ieee80211_device* ieee, struct sk_buff *skb, + int keyidx, struct ieee80211_crypt_data *crypt) +{ + struct ieee80211_hdr_4addr *hdr; + int res, hdrlen; + + if (crypt == NULL || crypt->ops->decrypt_msdu == NULL) + return 0; + if (ieee->hwsec_active) + { + cb_desc *tcb_desc = (cb_desc *)(skb->cb+ MAX_DEV_ADDR_SIZE); + tcb_desc->bHwSec = 1; + } + + hdr = (struct ieee80211_hdr_4addr *) skb->data; + hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); + + atomic_inc(&crypt->refcnt); + res = crypt->ops->decrypt_msdu(skb, keyidx, hdrlen, crypt->priv); + atomic_dec(&crypt->refcnt); + if (res < 0) { + printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed" + " (SA=" MAC_FMT " keyidx=%d)\n", + ieee->dev->name, MAC_ARG(hdr->addr2), keyidx); + return -1; + } + + return 0; +} + + +/* this function is stolen from ipw2200 driver*/ +#define IEEE_PACKET_RETRY_TIME (5*HZ) +static int is_duplicate_packet(struct ieee80211_device *ieee, + struct ieee80211_hdr_4addr *header) +{ + u16 fc = le16_to_cpu(header->frame_ctl); + u16 sc = le16_to_cpu(header->seq_ctl); + u16 seq = WLAN_GET_SEQ_SEQ(sc); + u16 frag = WLAN_GET_SEQ_FRAG(sc); + u16 *last_seq, *last_frag; + unsigned long *last_time; + struct ieee80211_hdr_3addrqos *hdr_3addrqos; + struct ieee80211_hdr_4addrqos *hdr_4addrqos; + u8 tid; + + + //TO2DS and QoS + if(((fc & IEEE80211_FCTL_DSTODS) == IEEE80211_FCTL_DSTODS)&&IEEE80211_QOS_HAS_SEQ(fc)) { + hdr_4addrqos = (struct ieee80211_hdr_4addrqos *)header; + tid = le16_to_cpu(hdr_4addrqos->qos_ctl) & IEEE80211_QCTL_TID; + tid = UP2AC(tid); + tid ++; + } else if(IEEE80211_QOS_HAS_SEQ(fc)) { //QoS + hdr_3addrqos = (struct ieee80211_hdr_3addrqos*)header; + tid = le16_to_cpu(hdr_3addrqos->qos_ctl) & IEEE80211_QCTL_TID; + tid = UP2AC(tid); + tid ++; + } else { // no QoS + tid = 0; + } + + switch (ieee->iw_mode) { + case IW_MODE_ADHOC: + { + struct list_head *p; + struct ieee_ibss_seq *entry = NULL; + u8 *mac = header->addr2; + int index = mac[5] % IEEE_IBSS_MAC_HASH_SIZE; + //for (pos = (head)->next; pos != (head); pos = pos->next) + //__list_for_each(p, &ieee->ibss_mac_hash[index]) { + list_for_each(p, &ieee->ibss_mac_hash[index]) { + entry = list_entry(p, struct ieee_ibss_seq, list); + if (!memcmp(entry->mac, mac, ETH_ALEN)) + break; + } + // if (memcmp(entry->mac, mac, ETH_ALEN)){ + if (p == &ieee->ibss_mac_hash[index]) { + entry = kmalloc(sizeof(struct ieee_ibss_seq), GFP_ATOMIC); + if (!entry) { + printk(KERN_WARNING "Cannot malloc new mac entry\n"); + return 0; + } + memcpy(entry->mac, mac, ETH_ALEN); + entry->seq_num[tid] = seq; + entry->frag_num[tid] = frag; + entry->packet_time[tid] = jiffies; + list_add(&entry->list, &ieee->ibss_mac_hash[index]); + return 0; + } + last_seq = &entry->seq_num[tid]; + last_frag = &entry->frag_num[tid]; + last_time = &entry->packet_time[tid]; + break; + } + + case IW_MODE_INFRA: + last_seq = &ieee->last_rxseq_num[tid]; + last_frag = &ieee->last_rxfrag_num[tid]; + last_time = &ieee->last_packet_time[tid]; + + break; + default: + return 0; + } + +// if(tid != 0) { +// printk(KERN_WARNING ":)))))))))))%x %x %x, fc(%x)\n", tid, *last_seq, seq, header->frame_ctl); +// } + if ((*last_seq == seq) && + time_after(*last_time + IEEE_PACKET_RETRY_TIME, jiffies)) { + if (*last_frag == frag){ + //printk(KERN_WARNING "[1] go drop!\n"); + goto drop; + + } + if (*last_frag + 1 != frag) + /* out-of-order fragment */ + //printk(KERN_WARNING "[2] go drop!\n"); + goto drop; + } else + *last_seq = seq; + + *last_frag = frag; + *last_time = jiffies; + return 0; + +drop: +// BUG_ON(!(fc & IEEE80211_FCTL_RETRY)); +// printk("DUP\n"); + + return 1; +} +bool +AddReorderEntry( + PRX_TS_RECORD pTS, + PRX_REORDER_ENTRY pReorderEntry + ) +{ + struct list_head *pList = &pTS->RxPendingPktList; +#if 1 + while(pList->next != &pTS->RxPendingPktList) + { + if( SN_LESS(pReorderEntry->SeqNum, ((PRX_REORDER_ENTRY)list_entry(pList->next,RX_REORDER_ENTRY,List))->SeqNum) ) + { + pList = pList->next; + } + else if( SN_EQUAL(pReorderEntry->SeqNum, ((PRX_REORDER_ENTRY)list_entry(pList->next,RX_REORDER_ENTRY,List))->SeqNum) ) + { + return false; + } + else + { + break; + } + } +#endif + pReorderEntry->List.next = pList->next; + pReorderEntry->List.next->prev = &pReorderEntry->List; + pReorderEntry->List.prev = pList; + pList->next = &pReorderEntry->List; + + return true; +} + +void ieee80211_indicate_packets(struct ieee80211_device *ieee, struct ieee80211_rxb** prxbIndicateArray,u8 index) +{ + u8 i = 0 , j=0; + u16 ethertype; +// if(index > 1) +// IEEE80211_DEBUG(IEEE80211_DL_REORDER,"%s(): hahahahhhh, We indicate packet from reorder list, index is %u\n",__FUNCTION__,index); + for(j = 0; jnr_subframes; i++) { + struct sk_buff *sub_skb = prxb->subframes[i]; + + /* convert hdr + possible LLC headers into Ethernet header */ + ethertype = (sub_skb->data[6] << 8) | sub_skb->data[7]; + if (sub_skb->len >= 8 && + ((memcmp(sub_skb->data, rfc1042_header, SNAP_SIZE) == 0 && + ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || + memcmp(sub_skb->data, bridge_tunnel_header, SNAP_SIZE) == 0)) { + /* remove RFC1042 or Bridge-Tunnel encapsulation and + * replace EtherType */ + skb_pull(sub_skb, SNAP_SIZE); + memcpy(skb_push(sub_skb, ETH_ALEN), prxb->src, ETH_ALEN); + memcpy(skb_push(sub_skb, ETH_ALEN), prxb->dst, ETH_ALEN); + } else { + u16 len; + /* Leave Ethernet header part of hdr and full payload */ + len = htons(sub_skb->len); + memcpy(skb_push(sub_skb, 2), &len, 2); + memcpy(skb_push(sub_skb, ETH_ALEN), prxb->src, ETH_ALEN); + memcpy(skb_push(sub_skb, ETH_ALEN), prxb->dst, ETH_ALEN); + } + //stats->rx_packets++; + //stats->rx_bytes += sub_skb->len; + + /* Indicat the packets to upper layer */ + if (sub_skb) { + //printk("0skb_len(%d)\n", skb->len); + sub_skb->protocol = eth_type_trans(sub_skb, ieee->dev); + memset(sub_skb->cb, 0, sizeof(sub_skb->cb)); + sub_skb->dev = ieee->dev; + sub_skb->ip_summed = CHECKSUM_NONE; /* 802.11 crc not sufficient */ + //skb->ip_summed = CHECKSUM_UNNECESSARY; /* 802.11 crc not sufficient */ + ieee->last_rx_ps_time = jiffies; + //printk("1skb_len(%d)\n", skb->len); + netif_rx(sub_skb); + } + } + kfree(prxb); + prxb = NULL; + } +} + + +void RxReorderIndicatePacket( struct ieee80211_device *ieee, + struct ieee80211_rxb* prxb, + PRX_TS_RECORD pTS, + u16 SeqNum) +{ + PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; + PRX_REORDER_ENTRY pReorderEntry = NULL; + struct ieee80211_rxb* prxbIndicateArray[REORDER_WIN_SIZE]; + u8 WinSize = pHTInfo->RxReorderWinSize; + u16 WinEnd = (pTS->RxIndicateSeq + WinSize -1)%4096; + u8 index = 0; + bool bMatchWinStart = false, bPktInBuf = false; + IEEE80211_DEBUG(IEEE80211_DL_REORDER,"%s(): Seq is %d,pTS->RxIndicateSeq is %d, WinSize is %d\n",__FUNCTION__,SeqNum,pTS->RxIndicateSeq,WinSize); +#if 0 + if(!list_empty(&ieee->RxReorder_Unused_List)) + IEEE80211_DEBUG(IEEE80211_DL_REORDER,"%s(): ieee->RxReorder_Unused_List is nut NULL\n"); +#endif + /* Rx Reorder initialize condition.*/ + if(pTS->RxIndicateSeq == 0xffff) { + pTS->RxIndicateSeq = SeqNum; + } + + /* Drop out the packet which SeqNum is smaller than WinStart */ + if(SN_LESS(SeqNum, pTS->RxIndicateSeq)) { + IEEE80211_DEBUG(IEEE80211_DL_REORDER,"Packet Drop! IndicateSeq: %d, NewSeq: %d\n", + pTS->RxIndicateSeq, SeqNum); + pHTInfo->RxReorderDropCounter++; + { + int i; + for(i =0; i < prxb->nr_subframes; i++) { + dev_kfree_skb(prxb->subframes[i]); + } + kfree(prxb); + prxb = NULL; + } + return; + } + + /* + * Sliding window manipulation. Conditions includes: + * 1. Incoming SeqNum is equal to WinStart =>Window shift 1 + * 2. Incoming SeqNum is larger than the WinEnd => Window shift N + */ + if(SN_EQUAL(SeqNum, pTS->RxIndicateSeq)) { + pTS->RxIndicateSeq = (pTS->RxIndicateSeq + 1) % 4096; + bMatchWinStart = true; + } else if(SN_LESS(WinEnd, SeqNum)) { + if(SeqNum >= (WinSize - 1)) { + pTS->RxIndicateSeq = SeqNum + 1 -WinSize; + } else { + pTS->RxIndicateSeq = 4095 - (WinSize - (SeqNum +1)) + 1; + } + IEEE80211_DEBUG(IEEE80211_DL_REORDER, "Window Shift! IndicateSeq: %d, NewSeq: %d\n",pTS->RxIndicateSeq, SeqNum); + } + + /* + * Indication process. + * After Packet dropping and Sliding Window shifting as above, we can now just indicate the packets + * with the SeqNum smaller than latest WinStart and buffer other packets. + */ + /* For Rx Reorder condition: + * 1. All packets with SeqNum smaller than WinStart => Indicate + * 2. All packets with SeqNum larger than or equal to WinStart => Buffer it. + */ + if(bMatchWinStart) { + /* Current packet is going to be indicated.*/ + IEEE80211_DEBUG(IEEE80211_DL_REORDER, "Packets indication!! IndicateSeq: %d, NewSeq: %d\n",\ + pTS->RxIndicateSeq, SeqNum); + prxbIndicateArray[0] = prxb; +// printk("========================>%s(): SeqNum is %d\n",__FUNCTION__,SeqNum); + index = 1; + } else { + /* Current packet is going to be inserted into pending list.*/ + //IEEE80211_DEBUG(IEEE80211_DL_REORDER,"%s(): We RX no ordered packed, insert to orderd list\n",__FUNCTION__); + if(!list_empty(&ieee->RxReorder_Unused_List)) { + pReorderEntry = (PRX_REORDER_ENTRY)list_entry(ieee->RxReorder_Unused_List.next,RX_REORDER_ENTRY,List); + list_del_init(&pReorderEntry->List); + + /* Make a reorder entry and insert into a the packet list.*/ + pReorderEntry->SeqNum = SeqNum; + pReorderEntry->prxb = prxb; + // IEEE80211_DEBUG(IEEE80211_DL_REORDER,"%s(): pREorderEntry->SeqNum is %d\n",__FUNCTION__,pReorderEntry->SeqNum); + +#if 1 + if(!AddReorderEntry(pTS, pReorderEntry)) { + IEEE80211_DEBUG(IEEE80211_DL_REORDER, "%s(): Duplicate packet is dropped!! IndicateSeq: %d, NewSeq: %d\n", + __FUNCTION__, pTS->RxIndicateSeq, SeqNum); + list_add_tail(&pReorderEntry->List,&ieee->RxReorder_Unused_List); + { + int i; + for(i =0; i < prxb->nr_subframes; i++) { + dev_kfree_skb(prxb->subframes[i]); + } + kfree(prxb); + prxb = NULL; + } + } else { + IEEE80211_DEBUG(IEEE80211_DL_REORDER, + "Pkt insert into buffer!! IndicateSeq: %d, NewSeq: %d\n",pTS->RxIndicateSeq, SeqNum); + } +#endif + } + else { + /* + * Packets are dropped if there is not enough reorder entries. + * This part shall be modified!! We can just indicate all the + * packets in buffer and get reorder entries. + */ + IEEE80211_DEBUG(IEEE80211_DL_ERR, "RxReorderIndicatePacket(): There is no reorder entry!! Packet is dropped!!\n"); + { + int i; + for(i =0; i < prxb->nr_subframes; i++) { + dev_kfree_skb(prxb->subframes[i]); + } + kfree(prxb); + prxb = NULL; + } + } + } + + /* Check if there is any packet need indicate.*/ + while(!list_empty(&pTS->RxPendingPktList)) { + IEEE80211_DEBUG(IEEE80211_DL_REORDER,"%s(): start RREORDER indicate\n",__FUNCTION__); +#if 1 + pReorderEntry = (PRX_REORDER_ENTRY)list_entry(pTS->RxPendingPktList.prev,RX_REORDER_ENTRY,List); + if( SN_LESS(pReorderEntry->SeqNum, pTS->RxIndicateSeq) || + SN_EQUAL(pReorderEntry->SeqNum, pTS->RxIndicateSeq)) + { + /* This protect buffer from overflow. */ + if(index >= REORDER_WIN_SIZE) { + IEEE80211_DEBUG(IEEE80211_DL_ERR, "RxReorderIndicatePacket(): Buffer overflow!! \n"); + bPktInBuf = true; + break; + } + + list_del_init(&pReorderEntry->List); + + if(SN_EQUAL(pReorderEntry->SeqNum, pTS->RxIndicateSeq)) + pTS->RxIndicateSeq = (pTS->RxIndicateSeq + 1) % 4096; + + IEEE80211_DEBUG(IEEE80211_DL_REORDER,"Packets indication!! IndicateSeq: %d, NewSeq: %d\n",pTS->RxIndicateSeq, SeqNum); + prxbIndicateArray[index] = pReorderEntry->prxb; + // printk("========================>%s(): pReorderEntry->SeqNum is %d\n",__FUNCTION__,pReorderEntry->SeqNum); + index++; + + list_add_tail(&pReorderEntry->List,&ieee->RxReorder_Unused_List); + } else { + bPktInBuf = true; + break; + } +#endif + } + + /* Handling pending timer. Set this timer to prevent from long time Rx buffering.*/ + if(index>0) { + // Cancel previous pending timer. + if(timer_pending(&pTS->RxPktPendingTimer)) + { + del_timer_sync(&pTS->RxPktPendingTimer); + } + // del_timer_sync(&pTS->RxPktPendingTimer); + pTS->RxTimeoutIndicateSeq = 0xffff; + + // Indicate packets + if(index>REORDER_WIN_SIZE){ + IEEE80211_DEBUG(IEEE80211_DL_ERR, "RxReorderIndicatePacket(): Rx Reorer buffer full!! \n"); + return; + } + ieee80211_indicate_packets(ieee, prxbIndicateArray, index); + bPktInBuf = false; + } + +#if 1 + if(bPktInBuf && pTS->RxTimeoutIndicateSeq==0xffff) { + // Set new pending timer. + IEEE80211_DEBUG(IEEE80211_DL_REORDER,"%s(): SET rx timeout timer\n", __FUNCTION__); + pTS->RxTimeoutIndicateSeq = pTS->RxIndicateSeq; +#if 0 + if(timer_pending(&pTS->RxPktPendingTimer)) + del_timer_sync(&pTS->RxPktPendingTimer); + pTS->RxPktPendingTimer.expires = jiffies + MSECS(pHTInfo->RxReorderPendingTime); + add_timer(&pTS->RxPktPendingTimer); +#else + mod_timer(&pTS->RxPktPendingTimer, jiffies + MSECS(pHTInfo->RxReorderPendingTime)); +#endif + } +#endif +} + +u8 parse_subframe(struct sk_buff *skb, + struct ieee80211_rx_stats *rx_stats, + struct ieee80211_rxb *rxb,u8* src,u8* dst) +{ + struct ieee80211_hdr_3addr *hdr = (struct ieee80211_hdr_3addr* )skb->data; + u16 fc = le16_to_cpu(hdr->frame_ctl); + + u16 LLCOffset= sizeof(struct ieee80211_hdr_3addr); + u16 ChkLength; + bool bIsAggregateFrame = false; + u16 nSubframe_Length; + u8 nPadding_Length = 0; + u16 SeqNum=0; + + struct sk_buff *sub_skb; + u8 *data_ptr; + /* just for debug purpose */ + SeqNum = WLAN_GET_SEQ_SEQ(le16_to_cpu(hdr->seq_ctl)); + + if((IEEE80211_QOS_HAS_SEQ(fc))&&\ + (((frameqos *)(skb->data + IEEE80211_3ADDR_LEN))->field.reserved)) { + bIsAggregateFrame = true; + } + + if(IEEE80211_QOS_HAS_SEQ(fc)) { + LLCOffset += 2; + } + + if(rx_stats->bContainHTC) { + LLCOffset += sHTCLng; + } + //printk("ChkLength = %d\n", LLCOffset); + // Null packet, don't indicate it to upper layer + ChkLength = LLCOffset;/* + (Frame_WEP(frame)!=0 ?Adapter->MgntInfo.SecurityInfo.EncryptionHeadOverhead:0);*/ + + if( skb->len <= ChkLength ) { + return 0; + } + + skb_pull(skb, LLCOffset); + + if(!bIsAggregateFrame) { + rxb->nr_subframes = 1; +#ifdef JOHN_NOCPY + rxb->subframes[0] = skb; +#else + rxb->subframes[0] = skb_copy(skb, GFP_ATOMIC); +#endif + + memcpy(rxb->src,src,ETH_ALEN); + memcpy(rxb->dst,dst,ETH_ALEN); + //IEEE80211_DEBUG_DATA(IEEE80211_DL_RX,skb->data,skb->len); + return 1; + } else { + rxb->nr_subframes = 0; + memcpy(rxb->src,src,ETH_ALEN); + memcpy(rxb->dst,dst,ETH_ALEN); + while(skb->len > ETHERNET_HEADER_SIZE) { + /* Offset 12 denote 2 mac address */ + nSubframe_Length = *((u16*)(skb->data + 12)); + //==m==>change the length order + nSubframe_Length = (nSubframe_Length>>8) + (nSubframe_Length<<8); + + if(skb->len<(ETHERNET_HEADER_SIZE + nSubframe_Length)) { +#if 0//cosa + RT_ASSERT( + (nRemain_Length>=(ETHERNET_HEADER_SIZE + nSubframe_Length)), + ("ParseSubframe(): A-MSDU subframe parse error!! Subframe Length: %d\n", nSubframe_Length) ); +#endif + printk("%s: A-MSDU parse error!! pRfd->nTotalSubframe : %d\n",\ + __FUNCTION__,rxb->nr_subframes); + printk("%s: A-MSDU parse error!! Subframe Length: %d\n",__FUNCTION__, nSubframe_Length); + printk("nRemain_Length is %d and nSubframe_Length is : %d\n",skb->len,nSubframe_Length); + printk("The Packet SeqNum is %d\n",SeqNum); + return 0; + } + + /* move the data point to data content */ + skb_pull(skb, ETHERNET_HEADER_SIZE); + +#ifdef JOHN_NOCPY + sub_skb = skb_clone(skb, GFP_ATOMIC); + sub_skb->len = nSubframe_Length; + sub_skb->tail = sub_skb->data + nSubframe_Length; +#else + /* Allocate new skb for releasing to upper layer */ + sub_skb = dev_alloc_skb(nSubframe_Length + 12); + skb_reserve(sub_skb, 12); + data_ptr = (u8 *)skb_put(sub_skb, nSubframe_Length); + memcpy(data_ptr,skb->data,nSubframe_Length); +#endif + rxb->subframes[rxb->nr_subframes++] = sub_skb; + if(rxb->nr_subframes >= MAX_SUBFRAME_COUNT) { + IEEE80211_DEBUG_RX("ParseSubframe(): Too many Subframes! Packets dropped!\n"); + break; + } + skb_pull(skb,nSubframe_Length); + + if(skb->len != 0) { + nPadding_Length = 4 - ((nSubframe_Length + ETHERNET_HEADER_SIZE) % 4); + if(nPadding_Length == 4) { + nPadding_Length = 0; + } + + if(skb->len < nPadding_Length) { + return 0; + } + + skb_pull(skb,nPadding_Length); + } + } +#ifdef JOHN_NOCPY + dev_kfree_skb(skb); +#endif + //{just for debug added by david + //printk("AMSDU::rxb->nr_subframes = %d\n",rxb->nr_subframes); + //} + return rxb->nr_subframes; + } +} + +/* All received frames are sent to this function. @skb contains the frame in + * IEEE 802.11 format, i.e., in the format it was sent over air. + * This function is called only as a tasklet (software IRQ). */ +int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, + struct ieee80211_rx_stats *rx_stats) +{ + struct net_device *dev = ieee->dev; + struct ieee80211_hdr_4addr *hdr; + //struct ieee80211_hdr_3addrqos *hdr; + + size_t hdrlen; + u16 fc, type, stype, sc; + struct net_device_stats *stats; + unsigned int frag; + u8 *payload; + u16 ethertype; + //added by amy for reorder + u8 TID = 0; + u16 SeqNum = 0; + PRX_TS_RECORD pTS = NULL; + //bool bIsAggregateFrame = false; + //added by amy for reorder +#ifdef NOT_YET + struct net_device *wds = NULL; + struct sk_buff *skb2 = NULL; + struct net_device *wds = NULL; + int frame_authorized = 0; + int from_assoc_ap = 0; + void *sta = NULL; +#endif +// u16 qos_ctl = 0; + u8 dst[ETH_ALEN]; + u8 src[ETH_ALEN]; + u8 bssid[ETH_ALEN]; + struct ieee80211_crypt_data *crypt = NULL; + int keyidx = 0; + + int i; + struct ieee80211_rxb* rxb = NULL; + // cheat the the hdr type + hdr = (struct ieee80211_hdr_4addr *)skb->data; + stats = &ieee->stats; + + if (skb->len < 10) { + printk(KERN_INFO "%s: SKB length < 10\n", + dev->name); + goto rx_dropped; + } + + fc = le16_to_cpu(hdr->frame_ctl); + type = WLAN_FC_GET_TYPE(fc); + stype = WLAN_FC_GET_STYPE(fc); + sc = le16_to_cpu(hdr->seq_ctl); + + frag = WLAN_GET_SEQ_FRAG(sc); + hdrlen = ieee80211_get_hdrlen(fc); + + if(HTCCheck(ieee, skb->data)) + { + if(net_ratelimit()) + printk("find HTCControl\n"); + hdrlen += 4; + rx_stats->bContainHTC = 1; + } + + //IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA, skb->data, skb->len); +#ifdef NOT_YET +#if WIRELESS_EXT > 15 + /* Put this code here so that we avoid duplicating it in all + * Rx paths. - Jean II */ +#ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */ + /* If spy monitoring on */ + if (iface->spy_data.spy_number > 0) { + struct iw_quality wstats; + wstats.level = rx_stats->rssi; + wstats.noise = rx_stats->noise; + wstats.updated = 6; /* No qual value */ + /* Update spy records */ + wireless_spy_update(dev, hdr->addr2, &wstats); + } +#endif /* IW_WIRELESS_SPY */ +#endif /* WIRELESS_EXT > 15 */ + hostap_update_rx_stats(local->ap, hdr, rx_stats); +#endif + +#if WIRELESS_EXT > 15 + if (ieee->iw_mode == IW_MODE_MONITOR) { + ieee80211_monitor_rx(ieee, skb, rx_stats); + stats->rx_packets++; + stats->rx_bytes += skb->len; + return 1; + } +#endif + if (ieee->host_decrypt) { + int idx = 0; + if (skb->len >= hdrlen + 3) + idx = skb->data[hdrlen + 3] >> 6; + crypt = ieee->crypt[idx]; +#ifdef NOT_YET + sta = NULL; + + /* Use station specific key to override default keys if the + * receiver address is a unicast address ("individual RA"). If + * bcrx_sta_key parameter is set, station specific key is used + * even with broad/multicast targets (this is against IEEE + * 802.11, but makes it easier to use different keys with + * stations that do not support WEP key mapping). */ + + if (!(hdr->addr1[0] & 0x01) || local->bcrx_sta_key) + (void) hostap_handle_sta_crypto(local, hdr, &crypt, + &sta); +#endif + + /* allow NULL decrypt to indicate an station specific override + * for default encryption */ + if (crypt && (crypt->ops == NULL || + crypt->ops->decrypt_mpdu == NULL)) + crypt = NULL; + + if (!crypt && (fc & IEEE80211_FCTL_WEP)) { + /* This seems to be triggered by some (multicast?) + * frames from other than current BSS, so just drop the + * frames silently instead of filling system log with + * these reports. */ + IEEE80211_DEBUG_DROP("Decryption failed (not set)" + " (SA=" MAC_FMT ")\n", + MAC_ARG(hdr->addr2)); + ieee->ieee_stats.rx_discards_undecryptable++; + goto rx_dropped; + } + } + + if (skb->len < IEEE80211_DATA_HDR3_LEN) + goto rx_dropped; + + // if QoS enabled, should check the sequence for each of the AC + if( (ieee->pHTInfo->bCurRxReorderEnable == false) || !ieee->current_network.qos_data.active|| !IsDataFrame(skb->data) || IsLegacyDataFrame(skb->data)){ + if (is_duplicate_packet(ieee, hdr)) + goto rx_dropped; + + } + else + { + PRX_TS_RECORD pRxTS = NULL; + #if 0 + struct ieee80211_hdr_3addr *hdr; + u16 fc; + hdr = (struct ieee80211_hdr_3addr *)skb->data; + fc = le16_to_cpu(hdr->frame_ctl); + u8 tmp = (fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS); + + u8 tid = (*((u8*)skb->data + (((fc& IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS))?30:24)))&0xf; + printk("====================>fc:%x, tid:%d, tmp:%d\n", fc, tid, tmp); + //u8 tid = (u8)((frameqos*)(buf + ((fc & IEEE80211_FCTL_TODS)&&(fc & IEEE80211_FCTL_FROMDS))? 30 : 24))->field.tid; + #endif + //IEEE80211_DEBUG(IEEE80211_DL_REORDER,"%s(): QOS ENABLE AND RECEIVE QOS DATA , we will get Ts, tid:%d\n",__FUNCTION__, tid); +#if 1 + if(GetTs( + ieee, + (PTS_COMMON_INFO*) &pRxTS, + hdr->addr2, + (u8)Frame_QoSTID((u8*)(skb->data)), + RX_DIR, + true)) + { + + // IEEE80211_DEBUG(IEEE80211_DL_REORDER,"%s(): pRxTS->RxLastFragNum is %d,frag is %d,pRxTS->RxLastSeqNum is %d,seq is %d\n",__FUNCTION__,pRxTS->RxLastFragNum,frag,pRxTS->RxLastSeqNum,WLAN_GET_SEQ_SEQ(sc)); + if( (fc & (1<<11)) && + (frag == pRxTS->RxLastFragNum) && + (WLAN_GET_SEQ_SEQ(sc) == pRxTS->RxLastSeqNum) ) + { + goto rx_dropped; + } + else + { + pRxTS->RxLastFragNum = frag; + pRxTS->RxLastSeqNum = WLAN_GET_SEQ_SEQ(sc); + } + } + else + { + IEEE80211_DEBUG(IEEE80211_DL_ERR, "%s(): No TS!! Skip the check!!\n",__FUNCTION__); + goto rx_dropped; + } + } +#endif + if (type == IEEE80211_FTYPE_MGMT) { + + #if 0 + if ( stype == IEEE80211_STYPE_AUTH && + fc & IEEE80211_FCTL_WEP && ieee->host_decrypt && + (keyidx = hostap_rx_frame_decrypt(ieee, skb, crypt)) < 0) + { + printk(KERN_DEBUG "%s: failed to decrypt mgmt::auth " + "from " MAC_FMT "\n", dev->name, + MAC_ARG(hdr->addr2)); + /* TODO: could inform hostapd about this so that it + * could send auth failure report */ + goto rx_dropped; + } + #endif + + //IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA, skb->data, skb->len); + if (ieee80211_rx_frame_mgmt(ieee, skb, rx_stats, type, stype)) + goto rx_dropped; + else + goto rx_exit; + } + + /* Data frame - extract src/dst addresses */ + switch (fc & (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) { + case IEEE80211_FCTL_FROMDS: + memcpy(dst, hdr->addr1, ETH_ALEN); + memcpy(src, hdr->addr3, ETH_ALEN); + memcpy(bssid, hdr->addr2, ETH_ALEN); + break; + case IEEE80211_FCTL_TODS: + memcpy(dst, hdr->addr3, ETH_ALEN); + memcpy(src, hdr->addr2, ETH_ALEN); + memcpy(bssid, hdr->addr1, ETH_ALEN); + break; + case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS: + if (skb->len < IEEE80211_DATA_HDR4_LEN) + goto rx_dropped; + memcpy(dst, hdr->addr3, ETH_ALEN); + memcpy(src, hdr->addr4, ETH_ALEN); + memcpy(bssid, ieee->current_network.bssid, ETH_ALEN); + break; + case 0: + memcpy(dst, hdr->addr1, ETH_ALEN); + memcpy(src, hdr->addr2, ETH_ALEN); + memcpy(bssid, hdr->addr3, ETH_ALEN); + break; + } + +#ifdef NOT_YET + if (hostap_rx_frame_wds(ieee, hdr, fc, &wds)) + goto rx_dropped; + if (wds) { + skb->dev = dev = wds; + stats = hostap_get_stats(dev); + } + + if (ieee->iw_mode == IW_MODE_MASTER && !wds && + (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == IEEE80211_FCTL_FROMDS && + ieee->stadev && + memcmp(hdr->addr2, ieee->assoc_ap_addr, ETH_ALEN) == 0) { + /* Frame from BSSID of the AP for which we are a client */ + skb->dev = dev = ieee->stadev; + stats = hostap_get_stats(dev); + from_assoc_ap = 1; + } +#endif + + dev->last_rx = jiffies; + +#ifdef NOT_YET + if ((ieee->iw_mode == IW_MODE_MASTER || + ieee->iw_mode == IW_MODE_REPEAT) && + !from_assoc_ap) { + switch (hostap_handle_sta_rx(ieee, dev, skb, rx_stats, + wds != NULL)) { + case AP_RX_CONTINUE_NOT_AUTHORIZED: + frame_authorized = 0; + break; + case AP_RX_CONTINUE: + frame_authorized = 1; + break; + case AP_RX_DROP: + goto rx_dropped; + case AP_RX_EXIT: + goto rx_exit; + } + } +#endif + //IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA, skb->data, skb->len); + /* Nullfunc frames may have PS-bit set, so they must be passed to + * hostap_handle_sta_rx() before being dropped here. */ + if (stype != IEEE80211_STYPE_DATA && + stype != IEEE80211_STYPE_DATA_CFACK && + stype != IEEE80211_STYPE_DATA_CFPOLL && + stype != IEEE80211_STYPE_DATA_CFACKPOLL&& + stype != IEEE80211_STYPE_QOS_DATA//add by David,2006.8.4 + ) { + if (stype != IEEE80211_STYPE_NULLFUNC) + IEEE80211_DEBUG_DROP( + "RX: dropped data frame " + "with no data (type=0x%02x, " + "subtype=0x%02x, len=%d)\n", + type, stype, skb->len); + goto rx_dropped; + } + if (memcmp(bssid, ieee->current_network.bssid, ETH_ALEN)) + goto rx_dropped; + + /* skb: hdr + (possibly fragmented, possibly encrypted) payload */ + + if (ieee->host_decrypt && (fc & IEEE80211_FCTL_WEP) && + (keyidx = ieee80211_rx_frame_decrypt(ieee, skb, crypt)) < 0) + { + printk("decrypt frame error\n"); + goto rx_dropped; + } + + + hdr = (struct ieee80211_hdr_4addr *) skb->data; + + /* skb: hdr + (possibly fragmented) plaintext payload */ + // PR: FIXME: hostap has additional conditions in the "if" below: + // ieee->host_decrypt && (fc & IEEE80211_FCTL_WEP) && + if ((frag != 0 || (fc & IEEE80211_FCTL_MOREFRAGS))) { + int flen; + struct sk_buff *frag_skb = ieee80211_frag_cache_get(ieee, hdr); + IEEE80211_DEBUG_FRAG("Rx Fragment received (%u)\n", frag); + + if (!frag_skb) { + IEEE80211_DEBUG(IEEE80211_DL_RX | IEEE80211_DL_FRAG, + "Rx cannot get skb from fragment " + "cache (morefrag=%d seq=%u frag=%u)\n", + (fc & IEEE80211_FCTL_MOREFRAGS) != 0, + WLAN_GET_SEQ_SEQ(sc), frag); + goto rx_dropped; + } + flen = skb->len; + if (frag != 0) + flen -= hdrlen; + + if (frag_skb->tail + flen > frag_skb->end) { + printk(KERN_WARNING "%s: host decrypted and " + "reassembled frame did not fit skb\n", + dev->name); + ieee80211_frag_cache_invalidate(ieee, hdr); + goto rx_dropped; + } + + if (frag == 0) { + /* copy first fragment (including full headers) into + * beginning of the fragment cache skb */ + memcpy(skb_put(frag_skb, flen), skb->data, flen); + } else { + /* append frame payload to the end of the fragment + * cache skb */ + memcpy(skb_put(frag_skb, flen), skb->data + hdrlen, + flen); + } + dev_kfree_skb_any(skb); + skb = NULL; + + if (fc & IEEE80211_FCTL_MOREFRAGS) { + /* more fragments expected - leave the skb in fragment + * cache for now; it will be delivered to upper layers + * after all fragments have been received */ + goto rx_exit; + } + + /* this was the last fragment and the frame will be + * delivered, so remove skb from fragment cache */ + skb = frag_skb; + hdr = (struct ieee80211_hdr_4addr *) skb->data; + ieee80211_frag_cache_invalidate(ieee, hdr); + } + + /* skb: hdr + (possible reassembled) full MSDU payload; possibly still + * encrypted/authenticated */ + if (ieee->host_decrypt && (fc & IEEE80211_FCTL_WEP) && + ieee80211_rx_frame_decrypt_msdu(ieee, skb, keyidx, crypt)) + { + printk("==>decrypt msdu error\n"); + goto rx_dropped; + } + + //added by amy for AP roaming + ieee->LinkDetectInfo.NumRecvDataInPeriod++; + ieee->LinkDetectInfo.NumRxOkInPeriod++; + + hdr = (struct ieee80211_hdr_4addr *) skb->data; + if (crypt && !(fc & IEEE80211_FCTL_WEP) && !ieee->open_wep) { + if (/*ieee->ieee802_1x &&*/ + ieee80211_is_eapol_frame(ieee, skb, hdrlen)) { + +#ifdef CONFIG_IEEE80211_DEBUG + /* pass unencrypted EAPOL frames even if encryption is + * configured */ + struct eapol *eap = (struct eapol *)(skb->data + + 24); + IEEE80211_DEBUG_EAP("RX: IEEE 802.1X EAPOL frame: %s\n", + eap_get_type(eap->type)); +#endif + } else { + IEEE80211_DEBUG_DROP( + "encryption configured, but RX " + "frame not encrypted (SA=" MAC_FMT ")\n", + MAC_ARG(hdr->addr2)); + goto rx_dropped; + } + } + +#ifdef CONFIG_IEEE80211_DEBUG + if (crypt && !(fc & IEEE80211_FCTL_WEP) && + ieee80211_is_eapol_frame(ieee, skb, hdrlen)) { + struct eapol *eap = (struct eapol *)(skb->data + + 24); + IEEE80211_DEBUG_EAP("RX: IEEE 802.1X EAPOL frame: %s\n", + eap_get_type(eap->type)); + } +#endif + + if (crypt && !(fc & IEEE80211_FCTL_WEP) && !ieee->open_wep && + !ieee80211_is_eapol_frame(ieee, skb, hdrlen)) { + IEEE80211_DEBUG_DROP( + "dropped unencrypted RX data " + "frame from " MAC_FMT + " (drop_unencrypted=1)\n", + MAC_ARG(hdr->addr2)); + goto rx_dropped; + } +/* + if(ieee80211_is_eapol_frame(ieee, skb, hdrlen)) { + printk(KERN_WARNING "RX: IEEE802.1X EPAOL frame!\n"); + } +*/ +//added by amy for reorder +#if 1 + if(ieee->current_network.qos_data.active && IsQoSDataFrame(skb->data) + && !is_multicast_ether_addr(hdr->addr1) && !is_broadcast_ether_addr(hdr->addr1)) + { + TID = Frame_QoSTID(skb->data); + SeqNum = WLAN_GET_SEQ_SEQ(sc); + GetTs(ieee,(PTS_COMMON_INFO*) &pTS,hdr->addr2,TID,RX_DIR,true); + if(TID !=0 && TID !=3) + { + ieee->bis_any_nonbepkts = true; + } + } +#endif +//added by amy for reorder + /* skb: hdr + (possible reassembled) full plaintext payload */ + payload = skb->data + hdrlen; + //ethertype = (payload[6] << 8) | payload[7]; + rxb = (struct ieee80211_rxb*)kmalloc(sizeof(struct ieee80211_rxb),GFP_ATOMIC); + if(rxb == NULL) + { + IEEE80211_DEBUG(IEEE80211_DL_ERR,"%s(): kmalloc rxb error\n",__FUNCTION__); + goto rx_dropped; + } + /* to parse amsdu packets */ + /* qos data packets & reserved bit is 1 */ + if(parse_subframe(skb,rx_stats,rxb,src,dst) == 0) { + /* only to free rxb, and not submit the packets to upper layer */ + for(i =0; i < rxb->nr_subframes; i++) { + dev_kfree_skb(rxb->subframes[i]); + } + kfree(rxb); + rxb = NULL; + goto rx_dropped; + } + + ieee->last_rx_ps_time = jiffies; +//added by amy for reorder + if(ieee->pHTInfo->bCurRxReorderEnable == false ||pTS == NULL){ +//added by amy for reorder + for(i = 0; inr_subframes; i++) { + struct sk_buff *sub_skb = rxb->subframes[i]; + + if (sub_skb) { + /* convert hdr + possible LLC headers into Ethernet header */ + ethertype = (sub_skb->data[6] << 8) | sub_skb->data[7]; + if (sub_skb->len >= 8 && + ((memcmp(sub_skb->data, rfc1042_header, SNAP_SIZE) == 0 && + ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || + memcmp(sub_skb->data, bridge_tunnel_header, SNAP_SIZE) == 0)) { + /* remove RFC1042 or Bridge-Tunnel encapsulation and + * replace EtherType */ + skb_pull(sub_skb, SNAP_SIZE); + memcpy(skb_push(sub_skb, ETH_ALEN), src, ETH_ALEN); + memcpy(skb_push(sub_skb, ETH_ALEN), dst, ETH_ALEN); + } else { + u16 len; + /* Leave Ethernet header part of hdr and full payload */ + len = htons(sub_skb->len); + memcpy(skb_push(sub_skb, 2), &len, 2); + memcpy(skb_push(sub_skb, ETH_ALEN), src, ETH_ALEN); + memcpy(skb_push(sub_skb, ETH_ALEN), dst, ETH_ALEN); + } + + stats->rx_packets++; + stats->rx_bytes += sub_skb->len; + if(is_multicast_ether_addr(dst)) { + stats->multicast++; + } + + /* Indicat the packets to upper layer */ + //printk("0skb_len(%d)\n", skb->len); + sub_skb->protocol = eth_type_trans(sub_skb, dev); + memset(sub_skb->cb, 0, sizeof(sub_skb->cb)); + sub_skb->dev = dev; + sub_skb->ip_summed = CHECKSUM_NONE; /* 802.11 crc not sufficient */ + //skb->ip_summed = CHECKSUM_UNNECESSARY; /* 802.11 crc not sufficient */ + //printk("1skb_len(%d)\n", skb->len); + netif_rx(sub_skb); + } + } + kfree(rxb); + rxb = NULL; + + } + else + { + IEEE80211_DEBUG(IEEE80211_DL_REORDER,"%s(): REORDER ENABLE AND PTS not NULL, and we will enter RxReorderIndicatePacket()\n",__FUNCTION__); + RxReorderIndicatePacket(ieee, rxb, pTS, SeqNum); + } +#ifndef JOHN_NOCPY + dev_kfree_skb(skb); +#endif + + rx_exit: +#ifdef NOT_YET + if (sta) + hostap_handle_sta_release(sta); +#endif + return 1; + + rx_dropped: + if (rxb != NULL) + { + kfree(rxb); + rxb = NULL; + } + stats->rx_dropped++; + + /* Returning 0 indicates to caller that we have not handled the SKB-- + * so it is still allocated and can be used again by underlying + * hardware as a DMA target */ + return 0; +} + +#define MGMT_FRAME_FIXED_PART_LENGTH 0x24 + +static u8 qos_oui[QOS_OUI_LEN] = { 0x00, 0x50, 0xF2 }; + +/* +* Make ther structure we read from the beacon packet has +* the right values +*/ +static int ieee80211_verify_qos_info(struct ieee80211_qos_information_element + *info_element, int sub_type) +{ + + if (info_element->qui_subtype != sub_type) + return -1; + if (memcmp(info_element->qui, qos_oui, QOS_OUI_LEN)) + return -1; + if (info_element->qui_type != QOS_OUI_TYPE) + return -1; + if (info_element->version != QOS_VERSION_1) + return -1; + + return 0; +} + + +/* + * Parse a QoS parameter element + */ +static int ieee80211_read_qos_param_element(struct ieee80211_qos_parameter_info + *element_param, struct ieee80211_info_element + *info_element) +{ + int ret = 0; + u16 size = sizeof(struct ieee80211_qos_parameter_info) - 2; + + if ((info_element == NULL) || (element_param == NULL)) + return -1; + + if (info_element->id == QOS_ELEMENT_ID && info_element->len == size) { + memcpy(element_param->info_element.qui, info_element->data, + info_element->len); + element_param->info_element.elementID = info_element->id; + element_param->info_element.length = info_element->len; + } else + ret = -1; + if (ret == 0) + ret = ieee80211_verify_qos_info(&element_param->info_element, + QOS_OUI_PARAM_SUB_TYPE); + return ret; +} + +/* + * Parse a QoS information element + */ +static int ieee80211_read_qos_info_element(struct + ieee80211_qos_information_element + *element_info, struct ieee80211_info_element + *info_element) +{ + int ret = 0; + u16 size = sizeof(struct ieee80211_qos_information_element) - 2; + + if (element_info == NULL) + return -1; + if (info_element == NULL) + return -1; + + if ((info_element->id == QOS_ELEMENT_ID) && (info_element->len == size)) { + memcpy(element_info->qui, info_element->data, + info_element->len); + element_info->elementID = info_element->id; + element_info->length = info_element->len; + } else + ret = -1; + + if (ret == 0) + ret = ieee80211_verify_qos_info(element_info, + QOS_OUI_INFO_SUB_TYPE); + return ret; +} + + +/* + * Write QoS parameters from the ac parameters. + */ +static int ieee80211_qos_convert_ac_to_parameters(struct + ieee80211_qos_parameter_info + *param_elm, struct + ieee80211_qos_parameters + *qos_param) +{ + int rc = 0; + int i; + struct ieee80211_qos_ac_parameter *ac_params; + u8 aci; + //u8 cw_min; + //u8 cw_max; + + for (i = 0; i < QOS_QUEUE_NUM; i++) { + ac_params = &(param_elm->ac_params_record[i]); + + aci = (ac_params->aci_aifsn & 0x60) >> 5; + + if(aci >= QOS_QUEUE_NUM) + continue; + qos_param->aifs[aci] = (ac_params->aci_aifsn) & 0x0f; + + /* WMM spec P.11: The minimum value for AIFSN shall be 2 */ + qos_param->aifs[aci] = (qos_param->aifs[aci] < 2) ? 2:qos_param->aifs[aci]; + + qos_param->cw_min[aci] = ac_params->ecw_min_max & 0x0F; + + qos_param->cw_max[aci] = (ac_params->ecw_min_max & 0xF0) >> 4; + + qos_param->flag[aci] = + (ac_params->aci_aifsn & 0x10) ? 0x01 : 0x00; + qos_param->tx_op_limit[aci] = le16_to_cpu(ac_params->tx_op_limit); + } + return rc; +} + +/* + * we have a generic data element which it may contain QoS information or + * parameters element. check the information element length to decide + * which type to read + */ +static int ieee80211_parse_qos_info_param_IE(struct ieee80211_info_element + *info_element, + struct ieee80211_network *network) +{ + int rc = 0; + struct ieee80211_qos_parameters *qos_param = NULL; + struct ieee80211_qos_information_element qos_info_element; + + rc = ieee80211_read_qos_info_element(&qos_info_element, info_element); + + if (rc == 0) { + network->qos_data.param_count = qos_info_element.ac_info & 0x0F; + network->flags |= NETWORK_HAS_QOS_INFORMATION; + } else { + struct ieee80211_qos_parameter_info param_element; + + rc = ieee80211_read_qos_param_element(¶m_element, + info_element); + if (rc == 0) { + qos_param = &(network->qos_data.parameters); + ieee80211_qos_convert_ac_to_parameters(¶m_element, + qos_param); + network->flags |= NETWORK_HAS_QOS_PARAMETERS; + network->qos_data.param_count = + param_element.info_element.ac_info & 0x0F; + } + } + + if (rc == 0) { + IEEE80211_DEBUG_QOS("QoS is supported\n"); + network->qos_data.supported = 1; + } + return rc; +} + +#ifdef CONFIG_IEEE80211_DEBUG +#define MFIE_STRING(x) case MFIE_TYPE_ ##x: return #x + +static const char *get_info_element_string(u16 id) +{ + switch (id) { + MFIE_STRING(SSID); + MFIE_STRING(RATES); + MFIE_STRING(FH_SET); + MFIE_STRING(DS_SET); + MFIE_STRING(CF_SET); + MFIE_STRING(TIM); + MFIE_STRING(IBSS_SET); + MFIE_STRING(COUNTRY); + MFIE_STRING(HOP_PARAMS); + MFIE_STRING(HOP_TABLE); + MFIE_STRING(REQUEST); + MFIE_STRING(CHALLENGE); + MFIE_STRING(POWER_CONSTRAINT); + MFIE_STRING(POWER_CAPABILITY); + MFIE_STRING(TPC_REQUEST); + MFIE_STRING(TPC_REPORT); + MFIE_STRING(SUPP_CHANNELS); + MFIE_STRING(CSA); + MFIE_STRING(MEASURE_REQUEST); + MFIE_STRING(MEASURE_REPORT); + MFIE_STRING(QUIET); + MFIE_STRING(IBSS_DFS); + // MFIE_STRING(ERP_INFO); + MFIE_STRING(RSN); + MFIE_STRING(RATES_EX); + MFIE_STRING(GENERIC); + MFIE_STRING(QOS_PARAMETER); + default: + return "UNKNOWN"; + } +} +#endif + +#ifdef ENABLE_DOT11D +static inline void ieee80211_extract_country_ie( + struct ieee80211_device *ieee, + struct ieee80211_info_element *info_element, + struct ieee80211_network *network, + u8 * addr2 +) +{ + if(IS_DOT11D_ENABLE(ieee)) + { + if(info_element->len!= 0) + { + memcpy(network->CountryIeBuf, info_element->data, info_element->len); + network->CountryIeLen = info_element->len; + + if(!IS_COUNTRY_IE_VALID(ieee)) + { + Dot11d_UpdateCountryIe(ieee, addr2, info_element->len, info_element->data); + } + } + + // + // 070305, rcnjko: I update country IE watch dog here because + // some AP (e.g. Cisco 1242) don't include country IE in their + // probe response frame. + // + if(IS_EQUAL_CIE_SRC(ieee, addr2) ) + { + UPDATE_CIE_WATCHDOG(ieee); + } + } + +} +#endif + +int ieee80211_parse_info_param(struct ieee80211_device *ieee, + struct ieee80211_info_element *info_element, + u16 length, + struct ieee80211_network *network, + struct ieee80211_rx_stats *stats) +{ + u8 i; + short offset; + u16 tmp_htcap_len=0; + u16 tmp_htinfo_len=0; + u16 ht_realtek_agg_len=0; + u8 ht_realtek_agg_buf[MAX_IE_LEN]; +// u16 broadcom_len = 0; +#ifdef CONFIG_IEEE80211_DEBUG + char rates_str[64]; + char *p; +#endif + + while (length >= sizeof(*info_element)) { + if (sizeof(*info_element) + info_element->len > length) { + IEEE80211_DEBUG_MGMT("Info elem: parse failed: " + "info_element->len + 2 > left : " + "info_element->len+2=%zd left=%d, id=%d.\n", + info_element->len + + sizeof(*info_element), + length, info_element->id); + /* We stop processing but don't return an error here + * because some misbehaviour APs break this rule. ie. + * Orinoco AP1000. */ + break; + } + + switch (info_element->id) { + case MFIE_TYPE_SSID: + if (ieee80211_is_empty_essid(info_element->data, + info_element->len)) { + network->flags |= NETWORK_EMPTY_ESSID; + break; + } + + network->ssid_len = min(info_element->len, + (u8) IW_ESSID_MAX_SIZE); + memcpy(network->ssid, info_element->data, network->ssid_len); + if (network->ssid_len < IW_ESSID_MAX_SIZE) + memset(network->ssid + network->ssid_len, 0, + IW_ESSID_MAX_SIZE - network->ssid_len); + + IEEE80211_DEBUG_MGMT("MFIE_TYPE_SSID: '%s' len=%d.\n", + network->ssid, network->ssid_len); + break; + + case MFIE_TYPE_RATES: +#ifdef CONFIG_IEEE80211_DEBUG + p = rates_str; +#endif + network->rates_len = min(info_element->len, + MAX_RATES_LENGTH); + for (i = 0; i < network->rates_len; i++) { + network->rates[i] = info_element->data[i]; +#ifdef CONFIG_IEEE80211_DEBUG + p += snprintf(p, sizeof(rates_str) - + (p - rates_str), "%02X ", + network->rates[i]); +#endif + if (ieee80211_is_ofdm_rate + (info_element->data[i])) { + network->flags |= NETWORK_HAS_OFDM; + if (info_element->data[i] & + IEEE80211_BASIC_RATE_MASK) + network->flags &= + ~NETWORK_HAS_CCK; + } + } + + IEEE80211_DEBUG_MGMT("MFIE_TYPE_RATES: '%s' (%d)\n", + rates_str, network->rates_len); + break; + + case MFIE_TYPE_RATES_EX: +#ifdef CONFIG_IEEE80211_DEBUG + p = rates_str; +#endif + network->rates_ex_len = min(info_element->len, + MAX_RATES_EX_LENGTH); + for (i = 0; i < network->rates_ex_len; i++) { + network->rates_ex[i] = info_element->data[i]; +#ifdef CONFIG_IEEE80211_DEBUG + p += snprintf(p, sizeof(rates_str) - + (p - rates_str), "%02X ", + network->rates[i]); +#endif + if (ieee80211_is_ofdm_rate + (info_element->data[i])) { + network->flags |= NETWORK_HAS_OFDM; + if (info_element->data[i] & + IEEE80211_BASIC_RATE_MASK) + network->flags &= + ~NETWORK_HAS_CCK; + } + } + + IEEE80211_DEBUG_MGMT("MFIE_TYPE_RATES_EX: '%s' (%d)\n", + rates_str, network->rates_ex_len); + break; + + case MFIE_TYPE_DS_SET: + IEEE80211_DEBUG_MGMT("MFIE_TYPE_DS_SET: %d\n", + info_element->data[0]); + network->channel = info_element->data[0]; + break; + + case MFIE_TYPE_FH_SET: + IEEE80211_DEBUG_MGMT("MFIE_TYPE_FH_SET: ignored\n"); + break; + + case MFIE_TYPE_CF_SET: + IEEE80211_DEBUG_MGMT("MFIE_TYPE_CF_SET: ignored\n"); + break; + + case MFIE_TYPE_TIM: + if(info_element->len < 4) + break; + + network->tim.tim_count = info_element->data[0]; + network->tim.tim_period = info_element->data[1]; + + network->dtim_period = info_element->data[1]; + if(ieee->state != IEEE80211_LINKED) + break; +#if 0 + network->last_dtim_sta_time[0] = stats->mac_time[0]; +#else + //we use jiffies for legacy Power save + network->last_dtim_sta_time[0] = jiffies; +#endif + network->last_dtim_sta_time[1] = stats->mac_time[1]; + + network->dtim_data = IEEE80211_DTIM_VALID; + + if(info_element->data[0] != 0) + break; + + if(info_element->data[2] & 1) + network->dtim_data |= IEEE80211_DTIM_MBCAST; + + offset = (info_element->data[2] >> 1)*2; + + //printk("offset1:%x aid:%x\n",offset, ieee->assoc_id); + + if(ieee->assoc_id < 8*offset || + ieee->assoc_id > 8*(offset + info_element->len -3)) + + break; + + offset = (ieee->assoc_id / 8) - offset;// + ((aid % 8)? 0 : 1) ; + + if(info_element->data[3+offset] & (1<<(ieee->assoc_id%8))) + network->dtim_data |= IEEE80211_DTIM_UCAST; + + //IEEE80211_DEBUG_MGMT("MFIE_TYPE_TIM: partially ignored\n"); + break; + + case MFIE_TYPE_ERP: + network->erp_value = info_element->data[0]; + network->flags |= NETWORK_HAS_ERP_VALUE; + IEEE80211_DEBUG_MGMT("MFIE_TYPE_ERP_SET: %d\n", + network->erp_value); + break; + case MFIE_TYPE_IBSS_SET: + network->atim_window = info_element->data[0]; + IEEE80211_DEBUG_MGMT("MFIE_TYPE_IBSS_SET: %d\n", + network->atim_window); + break; + + case MFIE_TYPE_CHALLENGE: + IEEE80211_DEBUG_MGMT("MFIE_TYPE_CHALLENGE: ignored\n"); + break; + + case MFIE_TYPE_GENERIC: + IEEE80211_DEBUG_MGMT("MFIE_TYPE_GENERIC: %d bytes\n", + info_element->len); + if (!ieee80211_parse_qos_info_param_IE(info_element, + network)) + break; + + if (info_element->len >= 4 && + info_element->data[0] == 0x00 && + info_element->data[1] == 0x50 && + info_element->data[2] == 0xf2 && + info_element->data[3] == 0x01) { + network->wpa_ie_len = min(info_element->len + 2, + MAX_WPA_IE_LEN); + memcpy(network->wpa_ie, info_element, + network->wpa_ie_len); + break; + } + +#ifdef THOMAS_TURBO + if (info_element->len == 7 && + info_element->data[0] == 0x00 && + info_element->data[1] == 0xe0 && + info_element->data[2] == 0x4c && + info_element->data[3] == 0x01 && + info_element->data[4] == 0x02) { + network->Turbo_Enable = 1; + } +#endif + + //for HTcap and HTinfo parameters + if(tmp_htcap_len == 0){ + if(info_element->len >= 4 && + info_element->data[0] == 0x00 && + info_element->data[1] == 0x90 && + info_element->data[2] == 0x4c && + info_element->data[3] == 0x033){ + + tmp_htcap_len = min(info_element->len,(u8)MAX_IE_LEN); + if(tmp_htcap_len != 0){ + network->bssht.bdHTSpecVer = HT_SPEC_VER_EWC; + network->bssht.bdHTCapLen = tmp_htcap_len > sizeof(network->bssht.bdHTCapBuf)?\ + sizeof(network->bssht.bdHTCapBuf):tmp_htcap_len; + memcpy(network->bssht.bdHTCapBuf,info_element->data,network->bssht.bdHTCapLen); + } + } + if(tmp_htcap_len != 0){ + network->bssht.bdSupportHT = true; + network->bssht.bdHT1R = ((((PHT_CAPABILITY_ELE)(network->bssht.bdHTCapBuf))->MCS[1]) == 0); + }else{ + network->bssht.bdSupportHT = false; + network->bssht.bdHT1R = false; + } + } + + + if(tmp_htinfo_len == 0){ + if(info_element->len >= 4 && + info_element->data[0] == 0x00 && + info_element->data[1] == 0x90 && + info_element->data[2] == 0x4c && + info_element->data[3] == 0x034){ + + tmp_htinfo_len = min(info_element->len,(u8)MAX_IE_LEN); + if(tmp_htinfo_len != 0){ + network->bssht.bdHTSpecVer = HT_SPEC_VER_EWC; + if(tmp_htinfo_len){ + network->bssht.bdHTInfoLen = tmp_htinfo_len > sizeof(network->bssht.bdHTInfoBuf)?\ + sizeof(network->bssht.bdHTInfoBuf):tmp_htinfo_len; + memcpy(network->bssht.bdHTInfoBuf,info_element->data,network->bssht.bdHTInfoLen); + } + + } + + } + } + + if(ieee->aggregation){ + if(network->bssht.bdSupportHT){ + if(info_element->len >= 4 && + info_element->data[0] == 0x00 && + info_element->data[1] == 0xe0 && + info_element->data[2] == 0x4c && + info_element->data[3] == 0x02){ + + ht_realtek_agg_len = min(info_element->len,(u8)MAX_IE_LEN); + memcpy(ht_realtek_agg_buf,info_element->data,info_element->len); + + } + if(ht_realtek_agg_len >= 5){ + network->realtek_cap_exit = true; + network->bssht.bdRT2RTAggregation = true; + + if((ht_realtek_agg_buf[4] == 1) && (ht_realtek_agg_buf[5] & 0x02)) + network->bssht.bdRT2RTLongSlotTime = true; + + if((ht_realtek_agg_buf[4]==1) && (ht_realtek_agg_buf[5] & RT_HT_CAP_USE_92SE)) + { + network->bssht.RT2RT_HT_Mode |= RT_HT_CAP_USE_92SE; + //bssDesc->Vender = HT_IOT_PEER_REALTEK_92SE; + } + } + } + + } + + //if(tmp_htcap_len !=0 || tmp_htinfo_len != 0) + { + if((info_element->len >= 3 && + info_element->data[0] == 0x00 && + info_element->data[1] == 0x05 && + info_element->data[2] == 0xb5) || + (info_element->len >= 3 && + info_element->data[0] == 0x00 && + info_element->data[1] == 0x0a && + info_element->data[2] == 0xf7) || + (info_element->len >= 3 && + info_element->data[0] == 0x00 && + info_element->data[1] == 0x10 && + info_element->data[2] == 0x18)){ + + network->broadcom_cap_exist = true; + + } + } +#if 0 + if (tmp_htcap_len !=0) + { + u16 cap_ext = ((PHT_CAPABILITY_ELE)&info_element->data[0])->ExtHTCapInfo; + if ((cap_ext & 0x0c00) == 0x0c00) + { + network->ralink_cap_exist = true; + } + } +#endif + if(info_element->len >= 3 && + info_element->data[0] == 0x00 && + info_element->data[1] == 0x0c && + info_element->data[2] == 0x43) + { + network->ralink_cap_exist = true; + } + else + network->ralink_cap_exist = false; + //added by amy for atheros AP + if((info_element->len >= 3 && + info_element->data[0] == 0x00 && + info_element->data[1] == 0x03 && + info_element->data[2] == 0x7f) || + (info_element->len >= 3 && + info_element->data[0] == 0x00 && + info_element->data[1] == 0x13 && + info_element->data[2] == 0x74)) + { + // printk("========>%s(): athros AP is exist\n",__FUNCTION__); + network->atheros_cap_exist = true; + } + else + network->atheros_cap_exist = false; + + if ((info_element->len >= 3 && + info_element->data[0] == 0x00 && + info_element->data[1] == 0x50 && + info_element->data[2] == 0x43) ) + { + network->marvell_cap_exist = true; + } + else + network->marvell_cap_exist = false; + + if(info_element->len >= 3 && + info_element->data[0] == 0x00 && + info_element->data[1] == 0x40 && + info_element->data[2] == 0x96) + { + network->cisco_cap_exist = true; + } + else + network->cisco_cap_exist = false; + //added by amy for LEAP of cisco + if(info_element->len > 4 && + info_element->data[0] == 0x00 && + info_element->data[1] == 0x40 && + info_element->data[2] == 0x96 && + info_element->data[3] == 0x01) + { + if(info_element->len == 6) + { + memcpy(network->CcxRmState, &info_element[4], 2); + if(network->CcxRmState[0] != 0) + { + network->bCcxRmEnable = true; + } + else + network->bCcxRmEnable = false; + // + // CCXv4 Table 59-1 MBSSID Masks. + // + network->MBssidMask = network->CcxRmState[1] & 0x07; + if(network->MBssidMask != 0) + { + network->bMBssidValid = true; + network->MBssidMask = 0xff << (network->MBssidMask); + cpMacAddr(network->MBssid, network->bssid); + network->MBssid[5] &= network->MBssidMask; + } + else + { + network->bMBssidValid = false; + } + } + else + { + network->bCcxRmEnable = false; + } + } + if(info_element->len > 4 && + info_element->data[0] == 0x00 && + info_element->data[1] == 0x40 && + info_element->data[2] == 0x96 && + info_element->data[3] == 0x03) + { + if(info_element->len == 5) + { + network->bWithCcxVerNum = true; + network->BssCcxVerNumber = info_element->data[4]; + } + else + { + network->bWithCcxVerNum = false; + network->BssCcxVerNumber = 0; + } + } + break; + + case MFIE_TYPE_RSN: + IEEE80211_DEBUG_MGMT("MFIE_TYPE_RSN: %d bytes\n", + info_element->len); + network->rsn_ie_len = min(info_element->len + 2, + MAX_WPA_IE_LEN); + memcpy(network->rsn_ie, info_element, + network->rsn_ie_len); + break; + + //HT related element. + case MFIE_TYPE_HT_CAP: + IEEE80211_DEBUG_SCAN("MFIE_TYPE_HT_CAP: %d bytes\n", + info_element->len); + tmp_htcap_len = min(info_element->len,(u8)MAX_IE_LEN); + if(tmp_htcap_len != 0){ + network->bssht.bdHTSpecVer = HT_SPEC_VER_EWC; + network->bssht.bdHTCapLen = tmp_htcap_len > sizeof(network->bssht.bdHTCapBuf)?\ + sizeof(network->bssht.bdHTCapBuf):tmp_htcap_len; + memcpy(network->bssht.bdHTCapBuf,info_element->data,network->bssht.bdHTCapLen); + + //If peer is HT, but not WMM, call QosSetLegacyWMMParamWithHT() + // windows driver will update WMM parameters each beacon received once connected + // Linux driver is a bit different. + network->bssht.bdSupportHT = true; + network->bssht.bdHT1R = ((((PHT_CAPABILITY_ELE)(network->bssht.bdHTCapBuf))->MCS[1]) == 0); + } + else{ + network->bssht.bdSupportHT = false; + network->bssht.bdHT1R = false; + } + break; + + + case MFIE_TYPE_HT_INFO: + IEEE80211_DEBUG_SCAN("MFIE_TYPE_HT_INFO: %d bytes\n", + info_element->len); + tmp_htinfo_len = min(info_element->len,(u8)MAX_IE_LEN); + if(tmp_htinfo_len){ + network->bssht.bdHTSpecVer = HT_SPEC_VER_IEEE; + network->bssht.bdHTInfoLen = tmp_htinfo_len > sizeof(network->bssht.bdHTInfoBuf)?\ + sizeof(network->bssht.bdHTInfoBuf):tmp_htinfo_len; + memcpy(network->bssht.bdHTInfoBuf,info_element->data,network->bssht.bdHTInfoLen); + } + break; + + case MFIE_TYPE_AIRONET: + IEEE80211_DEBUG_SCAN("MFIE_TYPE_AIRONET: %d bytes\n", + info_element->len); + if(info_element->len >IE_CISCO_FLAG_POSITION) + { + network->bWithAironetIE = true; + + // CCX 1 spec v1.13, A01.1 CKIP Negotiation (page23): + // "A Cisco access point advertises support for CKIP in beacon and probe response packets, + // by adding an Aironet element and setting one or both of the CKIP negotiation bits." + if( (info_element->data[IE_CISCO_FLAG_POSITION]&SUPPORT_CKIP_MIC) || + (info_element->data[IE_CISCO_FLAG_POSITION]&SUPPORT_CKIP_PK) ) + { + network->bCkipSupported = true; + } + else + { + network->bCkipSupported = false; + } + } + else + { + network->bWithAironetIE = false; + network->bCkipSupported = false; + } + break; + case MFIE_TYPE_QOS_PARAMETER: + printk(KERN_ERR + "QoS Error need to parse QOS_PARAMETER IE\n"); + break; + +#ifdef ENABLE_DOT11D + case MFIE_TYPE_COUNTRY: + IEEE80211_DEBUG_SCAN("MFIE_TYPE_COUNTRY: %d bytes\n", + info_element->len); + //printk("=====>Receive <%s> Country IE\n",network->ssid); + ieee80211_extract_country_ie(ieee, info_element, network, network->bssid);//addr2 is same as addr3 when from an AP + break; +#endif +/* TODO */ +#if 0 + /* 802.11h */ + case MFIE_TYPE_POWER_CONSTRAINT: + network->power_constraint = info_element->data[0]; + network->flags |= NETWORK_HAS_POWER_CONSTRAINT; + break; + + case MFIE_TYPE_CSA: + network->power_constraint = info_element->data[0]; + network->flags |= NETWORK_HAS_CSA; + break; + + case MFIE_TYPE_QUIET: + network->quiet.count = info_element->data[0]; + network->quiet.period = info_element->data[1]; + network->quiet.duration = info_element->data[2]; + network->quiet.offset = info_element->data[3]; + network->flags |= NETWORK_HAS_QUIET; + break; + + case MFIE_TYPE_IBSS_DFS: + if (network->ibss_dfs) + break; + network->ibss_dfs = kmemdup(info_element->data, + info_element->len, + GFP_ATOMIC); + if (!network->ibss_dfs) + return 1; + network->flags |= NETWORK_HAS_IBSS_DFS; + break; + + case MFIE_TYPE_TPC_REPORT: + network->tpc_report.transmit_power = + info_element->data[0]; + network->tpc_report.link_margin = info_element->data[1]; + network->flags |= NETWORK_HAS_TPC_REPORT; + break; +#endif + default: + IEEE80211_DEBUG_MGMT + ("Unsupported info element: %s (%d)\n", + get_info_element_string(info_element->id), + info_element->id); + break; + } + + length -= sizeof(*info_element) + info_element->len; + info_element = + (struct ieee80211_info_element *)&info_element-> + data[info_element->len]; + } + + if(!network->atheros_cap_exist && !network->broadcom_cap_exist && + !network->cisco_cap_exist && !network->ralink_cap_exist && !network->bssht.bdRT2RTAggregation) + { + network->unknown_cap_exist = true; + } + else + { + network->unknown_cap_exist = false; + } + return 0; +} + +static inline u8 ieee80211_SignalStrengthTranslate( + u8 CurrSS + ) +{ + u8 RetSS; + + // Step 1. Scale mapping. + if(CurrSS >= 71 && CurrSS <= 100) + { + RetSS = 90 + ((CurrSS - 70) / 3); + } + else if(CurrSS >= 41 && CurrSS <= 70) + { + RetSS = 78 + ((CurrSS - 40) / 3); + } + else if(CurrSS >= 31 && CurrSS <= 40) + { + RetSS = 66 + (CurrSS - 30); + } + else if(CurrSS >= 21 && CurrSS <= 30) + { + RetSS = 54 + (CurrSS - 20); + } + else if(CurrSS >= 5 && CurrSS <= 20) + { + RetSS = 42 + (((CurrSS - 5) * 2) / 3); + } + else if(CurrSS == 4) + { + RetSS = 36; + } + else if(CurrSS == 3) + { + RetSS = 27; + } + else if(CurrSS == 2) + { + RetSS = 18; + } + else if(CurrSS == 1) + { + RetSS = 9; + } + else + { + RetSS = CurrSS; + } + //RT_TRACE(COMP_DBG, DBG_LOUD, ("##### After Mapping: LastSS: %d, CurrSS: %d, RetSS: %d\n", LastSS, CurrSS, RetSS)); + + // Step 2. Smoothing. + + //RT_TRACE(COMP_DBG, DBG_LOUD, ("$$$$$ After Smoothing: LastSS: %d, CurrSS: %d, RetSS: %d\n", LastSS, CurrSS, RetSS)); + + return RetSS; +} + +long ieee80211_translate_todbm(u8 signal_strength_index )// 0-100 index. +{ + long signal_power; // in dBm. + + // Translate to dBm (x=0.5y-95). + signal_power = (long)((signal_strength_index + 1) >> 1); + signal_power -= 95; + + return signal_power; +} + +static inline int ieee80211_network_init( + struct ieee80211_device *ieee, + struct ieee80211_probe_response *beacon, + struct ieee80211_network *network, + struct ieee80211_rx_stats *stats) +{ +#ifdef CONFIG_IEEE80211_DEBUG + //char rates_str[64]; + //char *p; +#endif + + network->qos_data.active = 0; + network->qos_data.supported = 0; + network->qos_data.param_count = 0; + network->qos_data.old_param_count = 0; + + /* Pull out fixed field data */ + memcpy(network->bssid, beacon->header.addr3, ETH_ALEN); + network->capability = le16_to_cpu(beacon->capability); + network->last_scanned = jiffies; + network->time_stamp[0] = le32_to_cpu(beacon->time_stamp[0]); + network->time_stamp[1] = le32_to_cpu(beacon->time_stamp[1]); + network->beacon_interval = le32_to_cpu(beacon->beacon_interval); + /* Where to pull this? beacon->listen_interval;*/ + network->listen_interval = 0x0A; + network->rates_len = network->rates_ex_len = 0; + network->last_associate = 0; + network->ssid_len = 0; + network->flags = 0; + network->atim_window = 0; + network->erp_value = (network->capability & WLAN_CAPABILITY_IBSS) ? + 0x3 : 0x0; + network->berp_info_valid = false; + network->broadcom_cap_exist = false; + network->ralink_cap_exist = false; + network->atheros_cap_exist = false; + network->cisco_cap_exist = false; + network->unknown_cap_exist = false; + network->realtek_cap_exit = false; + network->marvell_cap_exist = false; +#ifdef THOMAS_TURBO + network->Turbo_Enable = 0; +#endif +#ifdef ENABLE_DOT11D + network->CountryIeLen = 0; + memset(network->CountryIeBuf, 0, MAX_IE_LEN); +#endif +//Initialize HT parameters + //ieee80211_ht_initialize(&network->bssht); + HTInitializeBssDesc(&network->bssht); + if (stats->freq == IEEE80211_52GHZ_BAND) { + /* for A band (No DS info) */ + network->channel = stats->received_channel; + } else + network->flags |= NETWORK_HAS_CCK; + + network->wpa_ie_len = 0; + network->rsn_ie_len = 0; + + if (ieee80211_parse_info_param + (ieee,beacon->info_element, stats->len - sizeof(*beacon), network, stats)) + return 1; + + network->mode = 0; + if (stats->freq == IEEE80211_52GHZ_BAND) + network->mode = IEEE_A; + else { + if (network->flags & NETWORK_HAS_OFDM) + network->mode |= IEEE_G; + if (network->flags & NETWORK_HAS_CCK) + network->mode |= IEEE_B; + } + + if (network->mode == 0) { + IEEE80211_DEBUG_SCAN("Filtered out '%s (" MAC_FMT ")' " + "network.\n", + escape_essid(network->ssid, + network->ssid_len), + MAC_ARG(network->bssid)); + return 1; + } + + if(network->bssht.bdSupportHT){ + if(network->mode == IEEE_A) + network->mode = IEEE_N_5G; + else if(network->mode & (IEEE_G | IEEE_B)) + network->mode = IEEE_N_24G; + } + if (ieee80211_is_empty_essid(network->ssid, network->ssid_len)) + network->flags |= NETWORK_EMPTY_ESSID; + +#if 1 + stats->signal = 30 + (stats->SignalStrength * 70) / 100; + //stats->signal = ieee80211_SignalStrengthTranslate(stats->signal); + stats->noise = ieee80211_translate_todbm((u8)(100-stats->signal)) -25; +#endif + + memcpy(&network->stats, stats, sizeof(network->stats)); + + return 0; +} + +static inline int is_same_network(struct ieee80211_network *src, + struct ieee80211_network *dst, struct ieee80211_device* ieee) +{ + /* A network is only a duplicate if the channel, BSSID, ESSID + * and the capability field (in particular IBSS and BSS) all match. + * We treat all with the same BSSID and channel + * as one network */ + return //((src->ssid_len == dst->ssid_len) && + (((src->ssid_len == dst->ssid_len) || (ieee->iw_mode == IW_MODE_INFRA)) && + (src->channel == dst->channel) && + !memcmp(src->bssid, dst->bssid, ETH_ALEN) && + //!memcmp(src->ssid, dst->ssid, src->ssid_len) && + (!memcmp(src->ssid, dst->ssid, src->ssid_len) || (ieee->iw_mode == IW_MODE_INFRA)) && + ((src->capability & WLAN_CAPABILITY_IBSS) == + (dst->capability & WLAN_CAPABILITY_IBSS)) && + ((src->capability & WLAN_CAPABILITY_BSS) == + (dst->capability & WLAN_CAPABILITY_BSS))); +} + +static inline void update_network(struct ieee80211_network *dst, + struct ieee80211_network *src) +{ + int qos_active; + u8 old_param; + + memcpy(&dst->stats, &src->stats, sizeof(struct ieee80211_rx_stats)); + dst->capability = src->capability; + memcpy(dst->rates, src->rates, src->rates_len); + dst->rates_len = src->rates_len; + memcpy(dst->rates_ex, src->rates_ex, src->rates_ex_len); + dst->rates_ex_len = src->rates_ex_len; + if(src->ssid_len > 0) + { + memset(dst->ssid, 0, dst->ssid_len); + dst->ssid_len = src->ssid_len; + memcpy(dst->ssid, src->ssid, src->ssid_len); + } + dst->mode = src->mode; + dst->flags = src->flags; + dst->time_stamp[0] = src->time_stamp[0]; + dst->time_stamp[1] = src->time_stamp[1]; + if (src->flags & NETWORK_HAS_ERP_VALUE) + { + dst->erp_value = src->erp_value; + dst->berp_info_valid = src->berp_info_valid = true; + } + dst->beacon_interval = src->beacon_interval; + dst->listen_interval = src->listen_interval; + dst->atim_window = src->atim_window; + dst->dtim_period = src->dtim_period; + dst->dtim_data = src->dtim_data; + dst->last_dtim_sta_time[0] = src->last_dtim_sta_time[0]; + dst->last_dtim_sta_time[1] = src->last_dtim_sta_time[1]; + memcpy(&dst->tim, &src->tim, sizeof(struct ieee80211_tim_parameters)); + + dst->bssht.bdSupportHT = src->bssht.bdSupportHT; + dst->bssht.bdRT2RTAggregation = src->bssht.bdRT2RTAggregation; + dst->bssht.bdHTCapLen= src->bssht.bdHTCapLen; + memcpy(dst->bssht.bdHTCapBuf,src->bssht.bdHTCapBuf,src->bssht.bdHTCapLen); + dst->bssht.bdHTInfoLen= src->bssht.bdHTInfoLen; + memcpy(dst->bssht.bdHTInfoBuf,src->bssht.bdHTInfoBuf,src->bssht.bdHTInfoLen); + dst->bssht.bdHTSpecVer = src->bssht.bdHTSpecVer; + dst->bssht.bdRT2RTLongSlotTime = src->bssht.bdRT2RTLongSlotTime; + dst->broadcom_cap_exist = src->broadcom_cap_exist; + dst->ralink_cap_exist = src->ralink_cap_exist; + dst->atheros_cap_exist = src->atheros_cap_exist; + dst->realtek_cap_exit = src->realtek_cap_exit; + dst->marvell_cap_exist = src->marvell_cap_exist; + dst->cisco_cap_exist = src->cisco_cap_exist; + dst->unknown_cap_exist = src->unknown_cap_exist; + memcpy(dst->wpa_ie, src->wpa_ie, src->wpa_ie_len); + dst->wpa_ie_len = src->wpa_ie_len; + memcpy(dst->rsn_ie, src->rsn_ie, src->rsn_ie_len); + dst->rsn_ie_len = src->rsn_ie_len; + + dst->last_scanned = jiffies; + /* qos related parameters */ + //qos_active = src->qos_data.active; + qos_active = dst->qos_data.active; + //old_param = dst->qos_data.old_param_count; + old_param = dst->qos_data.param_count; + if(dst->flags & NETWORK_HAS_QOS_MASK){ + //not update QOS paramter in beacon, as most AP will set all these parameter to 0.//WB + // printk("====>%s(), aifs:%x, %x\n", __FUNCTION__, dst->qos_data.parameters.aifs[0], src->qos_data.parameters.aifs[0]); + // memcpy(&dst->qos_data, &src->qos_data, + // sizeof(struct ieee80211_qos_data)); + } + else { + dst->qos_data.supported = src->qos_data.supported; + dst->qos_data.param_count = src->qos_data.param_count; + } + + if(dst->qos_data.supported == 1) { + dst->QoS_Enable = 1; + if(dst->ssid_len) + IEEE80211_DEBUG_QOS + ("QoS the network %s is QoS supported\n", + dst->ssid); + else + IEEE80211_DEBUG_QOS + ("QoS the network is QoS supported\n"); + } + dst->qos_data.active = qos_active; + dst->qos_data.old_param_count = old_param; + + /* dst->last_associate is not overwritten */ +#if 1 + dst->wmm_info = src->wmm_info; //sure to exist in beacon or probe response frame. + if(src->wmm_param[0].ac_aci_acm_aifsn|| \ + src->wmm_param[1].ac_aci_acm_aifsn|| \ + src->wmm_param[2].ac_aci_acm_aifsn|| \ + src->wmm_param[1].ac_aci_acm_aifsn) { + memcpy(dst->wmm_param, src->wmm_param, WME_AC_PRAM_LEN); + } + //dst->QoS_Enable = src->QoS_Enable; +#else + dst->QoS_Enable = 1;//for Rtl8187 simulation +#endif +#ifdef THOMAS_TURBO + dst->Turbo_Enable = src->Turbo_Enable; +#endif + +#ifdef ENABLE_DOT11D + dst->CountryIeLen = src->CountryIeLen; + memcpy(dst->CountryIeBuf, src->CountryIeBuf, src->CountryIeLen); +#endif + + //added by amy for LEAP + dst->bWithAironetIE = src->bWithAironetIE; + dst->bCkipSupported = src->bCkipSupported; + memcpy(dst->CcxRmState,src->CcxRmState,2); + dst->bCcxRmEnable = src->bCcxRmEnable; + dst->MBssidMask = src->MBssidMask; + dst->bMBssidValid = src->bMBssidValid; + memcpy(dst->MBssid,src->MBssid,6); + dst->bWithCcxVerNum = src->bWithCcxVerNum; + dst->BssCcxVerNumber = src->BssCcxVerNumber; + +} + +static inline int is_beacon(__le16 fc) +{ + return (WLAN_FC_GET_STYPE(le16_to_cpu(fc)) == IEEE80211_STYPE_BEACON); +} + +static inline void ieee80211_process_probe_response( + struct ieee80211_device *ieee, + struct ieee80211_probe_response *beacon, + struct ieee80211_rx_stats *stats) +{ + struct ieee80211_network network; + struct ieee80211_network *target; + struct ieee80211_network *oldest = NULL; +#ifdef CONFIG_IEEE80211_DEBUG + struct ieee80211_info_element *info_element = &beacon->info_element[0]; +#endif + unsigned long flags; + short renew; + //u8 wmm_info; + + memset(&network, 0, sizeof(struct ieee80211_network)); + IEEE80211_DEBUG_SCAN( + "'%s' (" MAC_FMT "): %c%c%c%c %c%c%c%c-%c%c%c%c %c%c%c%c\n", + escape_essid(info_element->data, info_element->len), + MAC_ARG(beacon->header.addr3), + (beacon->capability & (1<<0xf)) ? '1' : '0', + (beacon->capability & (1<<0xe)) ? '1' : '0', + (beacon->capability & (1<<0xd)) ? '1' : '0', + (beacon->capability & (1<<0xc)) ? '1' : '0', + (beacon->capability & (1<<0xb)) ? '1' : '0', + (beacon->capability & (1<<0xa)) ? '1' : '0', + (beacon->capability & (1<<0x9)) ? '1' : '0', + (beacon->capability & (1<<0x8)) ? '1' : '0', + (beacon->capability & (1<<0x7)) ? '1' : '0', + (beacon->capability & (1<<0x6)) ? '1' : '0', + (beacon->capability & (1<<0x5)) ? '1' : '0', + (beacon->capability & (1<<0x4)) ? '1' : '0', + (beacon->capability & (1<<0x3)) ? '1' : '0', + (beacon->capability & (1<<0x2)) ? '1' : '0', + (beacon->capability & (1<<0x1)) ? '1' : '0', + (beacon->capability & (1<<0x0)) ? '1' : '0'); + + if (ieee80211_network_init(ieee, beacon, &network, stats)) { + IEEE80211_DEBUG_SCAN("Dropped '%s' (" MAC_FMT ") via %s.\n", + escape_essid(info_element->data, + info_element->len), + MAC_ARG(beacon->header.addr3), + WLAN_FC_GET_STYPE(beacon->header.frame_ctl) == + IEEE80211_STYPE_PROBE_RESP ? + "PROBE RESPONSE" : "BEACON"); + return; + } + +#ifdef ENABLE_DOT11D + // For Asus EeePc request, + // (1) if wireless adapter receive get any 802.11d country code in AP beacon, + // wireless adapter should follow the country code. + // (2) If there is no any country code in beacon, + // then wireless adapter should do active scan from ch1~11 and + // passive scan from ch12~14 + + if( !IsLegalChannel(ieee, network.channel) ) + return; + if(ieee->bGlobalDomain) + { + if (WLAN_FC_GET_STYPE(beacon->header.frame_ctl) == IEEE80211_STYPE_PROBE_RESP) + { + // Case 1: Country code + if(IS_COUNTRY_IE_VALID(ieee) ) + { + if( !IsLegalChannel(ieee, network.channel) ) + { + printk("GetScanInfo(): For Country code, filter probe response at channel(%d).\n", network.channel); + return; + } + } + // Case 2: No any country code. + else + { + // Filter over channel ch12~14 + if(network.channel > 11) + { + printk("GetScanInfo(): For Global Domain, filter probe response at channel(%d).\n", network.channel); + return; + } + } + } + else + { + // Case 1: Country code + if(IS_COUNTRY_IE_VALID(ieee) ) + { + if( !IsLegalChannel(ieee, network.channel) ) + { + printk("GetScanInfo(): For Country code, filter beacon at channel(%d).\n",network.channel); + return; + } + } + // Case 2: No any country code. + else + { + // Filter over channel ch12~14 + if(network.channel > 14) + { + printk("GetScanInfo(): For Global Domain, filter beacon at channel(%d).\n",network.channel); + return; + } + } + } + } +#endif + + /* The network parsed correctly -- so now we scan our known networks + * to see if we can find it in our list. + * + * NOTE: This search is definitely not optimized. Once its doing + * the "right thing" we'll optimize it for efficiency if + * necessary */ + + /* Search for this entry in the list and update it if it is + * already there. */ + + spin_lock_irqsave(&ieee->lock, flags); + + if(is_same_network(&ieee->current_network, &network, ieee)) { + update_network(&ieee->current_network, &network); + if((ieee->current_network.mode == IEEE_N_24G || ieee->current_network.mode == IEEE_G) + && ieee->current_network.berp_info_valid){ + if(ieee->current_network.erp_value& ERP_UseProtection) + ieee->current_network.buseprotection = true; + else + ieee->current_network.buseprotection = false; + } + if(is_beacon(beacon->header.frame_ctl)) + { + if(ieee->state == IEEE80211_LINKED) + ieee->LinkDetectInfo.NumRecvBcnInPeriod++; + } + else //hidden AP + network.flags = (~NETWORK_EMPTY_ESSID & network.flags)|(NETWORK_EMPTY_ESSID & ieee->current_network.flags); + } + + list_for_each_entry(target, &ieee->network_list, list) { + if (is_same_network(target, &network, ieee)) + break; + if ((oldest == NULL) || + (target->last_scanned < oldest->last_scanned)) + oldest = target; + } + + /* If we didn't find a match, then get a new network slot to initialize + * with this beacon's information */ + if (&target->list == &ieee->network_list) { + if (list_empty(&ieee->network_free_list)) { + /* If there are no more slots, expire the oldest */ + list_del(&oldest->list); + target = oldest; + IEEE80211_DEBUG_SCAN("Expired '%s' (" MAC_FMT ") from " + "network list.\n", + escape_essid(target->ssid, + target->ssid_len), + MAC_ARG(target->bssid)); + } else { + /* Otherwise just pull from the free list */ + target = list_entry(ieee->network_free_list.next, + struct ieee80211_network, list); + list_del(ieee->network_free_list.next); + } + + +#ifdef CONFIG_IEEE80211_DEBUG + IEEE80211_DEBUG_SCAN("Adding '%s' (" MAC_FMT ") via %s.\n", + escape_essid(network.ssid, + network.ssid_len), + MAC_ARG(network.bssid), + WLAN_FC_GET_STYPE(beacon->header.frame_ctl) == + IEEE80211_STYPE_PROBE_RESP ? + "PROBE RESPONSE" : "BEACON"); +#endif + memcpy(target, &network, sizeof(*target)); + list_add_tail(&target->list, &ieee->network_list); + if(ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) + ieee80211_softmac_new_net(ieee,&network); + } else { + IEEE80211_DEBUG_SCAN("Updating '%s' (" MAC_FMT ") via %s.\n", + escape_essid(target->ssid, + target->ssid_len), + MAC_ARG(target->bssid), + WLAN_FC_GET_STYPE(beacon->header.frame_ctl) == + IEEE80211_STYPE_PROBE_RESP ? + "PROBE RESPONSE" : "BEACON"); + + /* we have an entry and we are going to update it. But this entry may + * be already expired. In this case we do the same as we found a new + * net and call the new_net handler + */ + renew = !time_after(target->last_scanned + ieee->scan_age, jiffies); + //YJ,add,080819,for hidden ap + if(is_beacon(beacon->header.frame_ctl) == 0) + network.flags = (~NETWORK_EMPTY_ESSID & network.flags)|(NETWORK_EMPTY_ESSID & target->flags); + //if(strncmp(network.ssid, "linksys-c",9) == 0) + // printk("====>2 network.ssid=%s FLAG=%d target.ssid=%s FLAG=%d\n", network.ssid, network.flags, target->ssid, target->flags); + if(((network.flags & NETWORK_EMPTY_ESSID) == NETWORK_EMPTY_ESSID) \ + && (((network.ssid_len > 0) && (strncmp(target->ssid, network.ssid, network.ssid_len)))\ + ||((ieee->current_network.ssid_len == network.ssid_len)&&(strncmp(ieee->current_network.ssid, network.ssid, network.ssid_len) == 0)&&(ieee->state == IEEE80211_NOLINK)))) + renew = 1; + //YJ,add,080819,for hidden ap,end + + update_network(target, &network); + if(renew && (ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE)) + ieee80211_softmac_new_net(ieee,&network); + } + + spin_unlock_irqrestore(&ieee->lock, flags); + if (is_beacon(beacon->header.frame_ctl)&&is_same_network(&ieee->current_network, &network, ieee)&&\ + (ieee->state == IEEE80211_LINKED)) { + if(ieee->handle_beacon != NULL) { + ieee->handle_beacon(ieee->dev,beacon,&ieee->current_network); + } + } +} + +void ieee80211_rx_mgt(struct ieee80211_device *ieee, + struct ieee80211_hdr_4addr *header, + struct ieee80211_rx_stats *stats) +{ + if(ieee->sta_sleep || (ieee->ps != IEEE80211_PS_DISABLED && + ieee->iw_mode == IW_MODE_INFRA && + ieee->state == IEEE80211_LINKED)) + { + tasklet_schedule(&ieee->ps_task); + } + + if(WLAN_FC_GET_STYPE(header->frame_ctl) != IEEE80211_STYPE_PROBE_RESP && + WLAN_FC_GET_STYPE(header->frame_ctl) != IEEE80211_STYPE_BEACON) + ieee->last_rx_ps_time = jiffies; + + switch (WLAN_FC_GET_STYPE(header->frame_ctl)) { + + case IEEE80211_STYPE_BEACON: + IEEE80211_DEBUG_MGMT("received BEACON (%d)\n", + WLAN_FC_GET_STYPE(header->frame_ctl)); + IEEE80211_DEBUG_SCAN("Beacon\n"); + ieee80211_process_probe_response( + ieee, (struct ieee80211_probe_response *)header, stats); + break; + + case IEEE80211_STYPE_PROBE_RESP: + IEEE80211_DEBUG_MGMT("received PROBE RESPONSE (%d)\n", + WLAN_FC_GET_STYPE(header->frame_ctl)); + IEEE80211_DEBUG_SCAN("Probe response\n"); + ieee80211_process_probe_response( + ieee, (struct ieee80211_probe_response *)header, stats); + break; + + } +} + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) +EXPORT_SYMBOL(ieee80211_rx_mgt); +EXPORT_SYMBOL(ieee80211_rx); +#else +EXPORT_SYMBOL_NOVERS(ieee80211_rx_mgt); +EXPORT_SYMBOL_NOVERS(ieee80211_rx); +#endif diff --git a/drivers/staging/rtl8192su/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8192su/ieee80211/ieee80211_softmac.c new file mode 100644 index 000000000000..6773e84c778e --- /dev/null +++ b/drivers/staging/rtl8192su/ieee80211/ieee80211_softmac.c @@ -0,0 +1,3580 @@ +/* IEEE 802.11 SoftMAC layer + * Copyright (c) 2005 Andrea Merello + * + * Mostly extracted from the rtl8180-sa2400 driver for the + * in-kernel generic ieee802.11 stack. + * + * Few lines might be stolen from other part of the ieee80211 + * stack. Copyright who own it's copyright + * + * WPA code stolen from the ipw2200 driver. + * Copyright who own it's copyright. + * + * released under the GPL + */ + + +#include "ieee80211.h" + +#include +#include +#include +#include +#ifdef ENABLE_DOT11D +#include "dot11d.h" +#endif + +u8 rsn_authen_cipher_suite[16][4] = { + {0x00,0x0F,0xAC,0x00}, //Use group key, //Reserved + {0x00,0x0F,0xAC,0x01}, //WEP-40 //RSNA default + {0x00,0x0F,0xAC,0x02}, //TKIP //NONE //{used just as default} + {0x00,0x0F,0xAC,0x03}, //WRAP-historical + {0x00,0x0F,0xAC,0x04}, //CCMP + {0x00,0x0F,0xAC,0x05}, //WEP-104 +}; + +short ieee80211_is_54g(struct ieee80211_network net) +{ + return ((net.rates_ex_len > 0) || (net.rates_len > 4)); +} + +short ieee80211_is_shortslot(struct ieee80211_network net) +{ + return (net.capability & WLAN_CAPABILITY_SHORT_SLOT); +} + +/* returns the total length needed for pleacing the RATE MFIE + * tag and the EXTENDED RATE MFIE tag if needed. + * It encludes two bytes per tag for the tag itself and its len + */ +unsigned int ieee80211_MFIE_rate_len(struct ieee80211_device *ieee) +{ + unsigned int rate_len = 0; + + if (ieee->modulation & IEEE80211_CCK_MODULATION) + rate_len = IEEE80211_CCK_RATE_LEN + 2; + + if (ieee->modulation & IEEE80211_OFDM_MODULATION) + + rate_len += IEEE80211_OFDM_RATE_LEN + 2; + + return rate_len; +} + +/* pleace the MFIE rate, tag to the memory (double) poined. + * Then it updates the pointer so that + * it points after the new MFIE tag added. + */ +void ieee80211_MFIE_Brate(struct ieee80211_device *ieee, u8 **tag_p) +{ + u8 *tag = *tag_p; + + if (ieee->modulation & IEEE80211_CCK_MODULATION){ + *tag++ = MFIE_TYPE_RATES; + *tag++ = 4; + *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB; + *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB; + *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_5MB; + *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_11MB; + } + + /* We may add an option for custom rates that specific HW might support */ + *tag_p = tag; +} + +void ieee80211_MFIE_Grate(struct ieee80211_device *ieee, u8 **tag_p) +{ + u8 *tag = *tag_p; + + if (ieee->modulation & IEEE80211_OFDM_MODULATION){ + + *tag++ = MFIE_TYPE_RATES_EX; + *tag++ = 8; + *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_6MB; + *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_9MB; + *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_12MB; + *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_18MB; + *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_24MB; + *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_36MB; + *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_48MB; + *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_54MB; + + } + + /* We may add an option for custom rates that specific HW might support */ + *tag_p = tag; +} + + +void ieee80211_WMM_Info(struct ieee80211_device *ieee, u8 **tag_p) { + u8 *tag = *tag_p; + + *tag++ = MFIE_TYPE_GENERIC; //0 + *tag++ = 7; + *tag++ = 0x00; + *tag++ = 0x50; + *tag++ = 0xf2; + *tag++ = 0x02;//5 + *tag++ = 0x00; + *tag++ = 0x01; +#ifdef SUPPORT_USPD + if(ieee->current_network.wmm_info & 0x80) { + *tag++ = 0x0f|MAX_SP_Len; + } else { + *tag++ = MAX_SP_Len; + } +#else + *tag++ = MAX_SP_Len; +#endif + *tag_p = tag; +} + +#ifdef THOMAS_TURBO +void ieee80211_TURBO_Info(struct ieee80211_device *ieee, u8 **tag_p) { + u8 *tag = *tag_p; + + *tag++ = MFIE_TYPE_GENERIC; //0 + *tag++ = 7; + *tag++ = 0x00; + *tag++ = 0xe0; + *tag++ = 0x4c; + *tag++ = 0x01;//5 + *tag++ = 0x02; + *tag++ = 0x11; + *tag++ = 0x00; + + *tag_p = tag; + printk(KERN_ALERT "This is enable turbo mode IE process\n"); +} +#endif + +void enqueue_mgmt(struct ieee80211_device *ieee, struct sk_buff *skb) +{ + int nh; + nh = (ieee->mgmt_queue_head +1) % MGMT_QUEUE_NUM; + +/* + * if the queue is full but we have newer frames then + * just overwrites the oldest. + * + * if (nh == ieee->mgmt_queue_tail) + * return -1; + */ + ieee->mgmt_queue_head = nh; + ieee->mgmt_queue_ring[nh] = skb; + + //return 0; +} + +struct sk_buff *dequeue_mgmt(struct ieee80211_device *ieee) +{ + struct sk_buff *ret; + + if(ieee->mgmt_queue_tail == ieee->mgmt_queue_head) + return NULL; + + ret = ieee->mgmt_queue_ring[ieee->mgmt_queue_tail]; + + ieee->mgmt_queue_tail = + (ieee->mgmt_queue_tail+1) % MGMT_QUEUE_NUM; + + return ret; +} + +void init_mgmt_queue(struct ieee80211_device *ieee) +{ + ieee->mgmt_queue_tail = ieee->mgmt_queue_head = 0; +} + +u8 MgntQuery_MgntFrameTxRate(struct ieee80211_device *ieee) +{ + PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; + u8 rate; + + // 2008/01/25 MH For broadcom, MGNT frame set as OFDM 6M. + if(pHTInfo->IOTAction & HT_IOT_ACT_MGNT_USE_CCK_6M) + rate = 0x0c; + else + rate = ieee->basic_rate & 0x7f; + + if(rate == 0){ + // 2005.01.26, by rcnjko. + if(ieee->mode == IEEE_A|| + ieee->mode== IEEE_N_5G|| + (ieee->mode== IEEE_N_24G&&!pHTInfo->bCurSuppCCK)) + rate = 0x0c; + else + rate = 0x02; + } + + /* + // Data rate of ProbeReq is already decided. Annie, 2005-03-31 + if( pMgntInfo->bScanInProgress || (pMgntInfo->bDualModeScanStep!=0) ) + { + if(pMgntInfo->dot11CurrentWirelessMode==WIRELESS_MODE_A) + rate = 0x0c; + else + rate = 0x02; + } + */ + return rate; +} + + +void ieee80211_sta_wakeup(struct ieee80211_device *ieee, short nl); + +inline void softmac_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *ieee) +{ + unsigned long flags; + short single = ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE; + struct ieee80211_hdr_3addr *header= + (struct ieee80211_hdr_3addr *) skb->data; + + cb_desc *tcb_desc = (cb_desc *)(skb->cb + 8); + spin_lock_irqsave(&ieee->lock, flags); + + /* called with 2nd param 0, no mgmt lock required */ + ieee80211_sta_wakeup(ieee,0); + + tcb_desc->queue_index = MGNT_QUEUE; + tcb_desc->data_rate = MgntQuery_MgntFrameTxRate(ieee); + tcb_desc->RATRIndex = 7; + tcb_desc->bTxDisableRateFallBack = 1; + tcb_desc->bTxUseDriverAssingedRate = 1; + + if(single){ + if(ieee->queue_stop){ + enqueue_mgmt(ieee,skb); + }else{ + header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0]<<4); + + if (ieee->seq_ctrl[0] == 0xFFF) + ieee->seq_ctrl[0] = 0; + else + ieee->seq_ctrl[0]++; + + /* avoid watchdog triggers */ + // ieee->dev->trans_start = jiffies; + ieee->softmac_data_hard_start_xmit(skb,ieee->dev,ieee->basic_rate); + //dev_kfree_skb_any(skb);//edit by thomas + } + + spin_unlock_irqrestore(&ieee->lock, flags); + }else{ + spin_unlock_irqrestore(&ieee->lock, flags); + spin_lock_irqsave(&ieee->mgmt_tx_lock, flags); + + header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4); + + if (ieee->seq_ctrl[0] == 0xFFF) + ieee->seq_ctrl[0] = 0; + else + ieee->seq_ctrl[0]++; + + /* check wether the managed packet queued greater than 5 */ + if(!ieee->check_nic_enough_desc(ieee->dev,tcb_desc->queue_index)||\ + (skb_queue_len(&ieee->skb_waitQ[tcb_desc->queue_index]) != 0)||\ + (ieee->queue_stop) ) { + /* insert the skb packet to the management queue */ + /* as for the completion function, it does not need + * to check it any more. + * */ + printk("%s():insert to waitqueue!\n",__FUNCTION__); + skb_queue_tail(&ieee->skb_waitQ[tcb_desc->queue_index], skb); + } else { + //printk("TX packet!\n"); + ieee->softmac_hard_start_xmit(skb,ieee->dev); + //dev_kfree_skb_any(skb);//edit by thomas + } + spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags); + } +} + +inline void softmac_ps_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *ieee) +{ + + short single = ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE; + struct ieee80211_hdr_3addr *header = + (struct ieee80211_hdr_3addr *) skb->data; + cb_desc *tcb_desc = (cb_desc *)(skb->cb + 8); + + tcb_desc->queue_index = MGNT_QUEUE; + tcb_desc->data_rate = MgntQuery_MgntFrameTxRate(ieee); + tcb_desc->RATRIndex = 7; + tcb_desc->bTxDisableRateFallBack = 1; + tcb_desc->bTxUseDriverAssingedRate = 1; + //printk("=============>%s()\n", __FUNCTION__); + if(single){ + + header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4); + + if (ieee->seq_ctrl[0] == 0xFFF) + ieee->seq_ctrl[0] = 0; + else + ieee->seq_ctrl[0]++; + + /* avoid watchdog triggers */ + // ieee->dev->trans_start = jiffies; + ieee->softmac_data_hard_start_xmit(skb,ieee->dev,ieee->basic_rate); + + }else{ + + header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4); + + if (ieee->seq_ctrl[0] == 0xFFF) + ieee->seq_ctrl[0] = 0; + else + ieee->seq_ctrl[0]++; + + ieee->softmac_hard_start_xmit(skb,ieee->dev); + + } + //dev_kfree_skb_any(skb);//edit by thomas +} + +inline struct sk_buff *ieee80211_probe_req(struct ieee80211_device *ieee) +{ + unsigned int len,rate_len; + u8 *tag; + struct sk_buff *skb; + struct ieee80211_probe_request *req; + + len = ieee->current_network.ssid_len; + + rate_len = ieee80211_MFIE_rate_len(ieee); + + skb = dev_alloc_skb(sizeof(struct ieee80211_probe_request) + + 2 + len + rate_len + ieee->tx_headroom); + if (!skb) + return NULL; + + skb_reserve(skb, ieee->tx_headroom); + + req = (struct ieee80211_probe_request *) skb_put(skb,sizeof(struct ieee80211_probe_request)); + req->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); + req->header.duration_id = 0; //FIXME: is this OK ? + + memset(req->header.addr1, 0xff, ETH_ALEN); + memcpy(req->header.addr2, ieee->dev->dev_addr, ETH_ALEN); + memset(req->header.addr3, 0xff, ETH_ALEN); + + tag = (u8 *) skb_put(skb,len+2+rate_len); + + *tag++ = MFIE_TYPE_SSID; + *tag++ = len; + memcpy(tag, ieee->current_network.ssid, len); + tag += len; + + ieee80211_MFIE_Brate(ieee,&tag); + ieee80211_MFIE_Grate(ieee,&tag); + return skb; +} + +struct sk_buff *ieee80211_get_beacon_(struct ieee80211_device *ieee); +void ieee80211_send_beacon(struct ieee80211_device *ieee) +{ + struct sk_buff *skb; + if(!ieee->ieee_up) + return; + //unsigned long flags; + skb = ieee80211_get_beacon_(ieee); + + if (skb){ + softmac_mgmt_xmit(skb, ieee); + ieee->softmac_stats.tx_beacons++; + //dev_kfree_skb_any(skb);//edit by thomas + } +// ieee->beacon_timer.expires = jiffies + +// (MSECS( ieee->current_network.beacon_interval -5)); + + //spin_lock_irqsave(&ieee->beacon_lock,flags); + if(ieee->beacon_txing && ieee->ieee_up){ +// if(!timer_pending(&ieee->beacon_timer)) +// add_timer(&ieee->beacon_timer); + mod_timer(&ieee->beacon_timer,jiffies+(MSECS(ieee->current_network.beacon_interval-5))); + } + //spin_unlock_irqrestore(&ieee->beacon_lock,flags); +} + + +void ieee80211_send_beacon_cb(unsigned long _ieee) +{ + struct ieee80211_device *ieee = + (struct ieee80211_device *) _ieee; + unsigned long flags; + + spin_lock_irqsave(&ieee->beacon_lock, flags); + ieee80211_send_beacon(ieee); + spin_unlock_irqrestore(&ieee->beacon_lock, flags); +} + + +void ieee80211_send_probe(struct ieee80211_device *ieee) +{ + struct sk_buff *skb; + + skb = ieee80211_probe_req(ieee); + if (skb){ + softmac_mgmt_xmit(skb, ieee); + ieee->softmac_stats.tx_probe_rq++; + //dev_kfree_skb_any(skb);//edit by thomas + } +} + +void ieee80211_send_probe_requests(struct ieee80211_device *ieee) +{ + if (ieee->active_scan && (ieee->softmac_features & IEEE_SOFTMAC_PROBERQ)){ + ieee80211_send_probe(ieee); + ieee80211_send_probe(ieee); + } +} + +/* this performs syncro scan blocking the caller until all channels + * in the allowed channel map has been checked. + */ +void ieee80211_softmac_scan_syncro(struct ieee80211_device *ieee) +{ + short ch = 0; +#ifdef ENABLE_DOT11D + u8 channel_map[MAX_CHANNEL_NUMBER+1]; + memcpy(channel_map, GET_DOT11D_INFO(ieee)->channel_map, MAX_CHANNEL_NUMBER+1); +#endif + ieee->be_scan_inprogress = true; + down(&ieee->scan_sem); + + while(1) + { + + do{ + ch++; + if (ch > MAX_CHANNEL_NUMBER) + goto out; /* scan completed */ +#ifdef ENABLE_DOT11D + }while(!channel_map[ch]); +#else + }while(!ieee->channel_map[ch]); +#endif + + /* this fuction can be called in two situations + * 1- We have switched to ad-hoc mode and we are + * performing a complete syncro scan before conclude + * there are no interesting cell and to create a + * new one. In this case the link state is + * IEEE80211_NOLINK until we found an interesting cell. + * If so the ieee8021_new_net, called by the RX path + * will set the state to IEEE80211_LINKED, so we stop + * scanning + * 2- We are linked and the root uses run iwlist scan. + * So we switch to IEEE80211_LINKED_SCANNING to remember + * that we are still logically linked (not interested in + * new network events, despite for updating the net list, + * but we are temporarly 'unlinked' as the driver shall + * not filter RX frames and the channel is changing. + * So the only situation in witch are interested is to check + * if the state become LINKED because of the #1 situation + */ + + if (ieee->state == IEEE80211_LINKED) + goto out; + ieee->set_chan(ieee->dev, ch); +#ifdef ENABLE_DOT11D + if(channel_map[ch] == 1) +#endif + ieee80211_send_probe_requests(ieee); + + /* this prevent excessive time wait when we + * need to wait for a syncro scan to end.. + */ + if(ieee->state < IEEE80211_LINKED) + ; + else + if (ieee->sync_scan_hurryup) + goto out; + + + msleep_interruptible_rsl(IEEE80211_SOFTMAC_SCAN_TIME); + + } +out: + if(ieee->state < IEEE80211_LINKED){ + ieee->actscanning = false; + up(&ieee->scan_sem); + ieee->be_scan_inprogress = false; + } + else{ + ieee->sync_scan_hurryup = 0; +#ifdef ENABLE_DOT11D + if(IS_DOT11D_ENABLE(ieee)) + DOT11D_ScanComplete(ieee); +#endif + up(&ieee->scan_sem); + ieee->be_scan_inprogress = false; +} +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +/* called both by wq with ieee->lock held */ +void ieee80211_softmac_scan(struct ieee80211_device *ieee) +{ +#if 0 + short watchdog = 0; + do{ + ieee->current_network.channel = + (ieee->current_network.channel + 1) % MAX_CHANNEL_NUMBER; + if (watchdog++ > MAX_CHANNEL_NUMBER) + return; /* no good chans */ + + }while(!ieee->channel_map[ieee->current_network.channel]); +#endif + + schedule_task(&ieee->softmac_scan_wq); +} +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) +void ieee80211_softmac_scan_wq(struct work_struct *work) +{ + struct delayed_work *dwork = container_of(work, struct delayed_work, work); + struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, softmac_scan_wq); +#else +void ieee80211_softmac_scan_wq(struct ieee80211_device *ieee) +{ +#endif + u8 last_channel = ieee->current_network.channel; //recored init channel inorder not change current channel when comming out the scan unexpectedly. WB. +#ifdef ENABLE_DOT11D + u8 channel_map[MAX_CHANNEL_NUMBER+1]; + memcpy(channel_map, GET_DOT11D_INFO(ieee)->channel_map, MAX_CHANNEL_NUMBER+1); +#endif + if(!ieee->ieee_up) + return; + down(&ieee->scan_sem); + do{ + ieee->current_network.channel = + (ieee->current_network.channel + 1) % MAX_CHANNEL_NUMBER; + if (ieee->scan_watch_dog++ > MAX_CHANNEL_NUMBER) + { + //if current channel is not in channel map, set to default channel. + #ifdef ENABLE_DOT11D + if (!channel_map[ieee->current_network.channel]); + #else + if (!ieee->channel_map[ieee->current_network.channel]); + #endif + ieee->current_network.channel = 6; + goto out; /* no good chans */ + } +#ifdef ENABLE_DOT11D + }while(!channel_map[ieee->current_network.channel]); +#else + }while(!ieee->channel_map[ieee->current_network.channel]); +#endif + if (ieee->scanning == 0 ) + goto out; + ieee->set_chan(ieee->dev, ieee->current_network.channel); +#ifdef ENABLE_DOT11D + if(channel_map[ieee->current_network.channel] == 1) +#endif + ieee80211_send_probe_requests(ieee); + + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + queue_delayed_work(ieee->wq, &ieee->softmac_scan_wq, IEEE80211_SOFTMAC_SCAN_TIME); +#else + //ieee->scan_timer.expires = jiffies + MSECS(IEEE80211_SOFTMAC_SCAN_TIME); + if (ieee->scanning == 1) + mod_timer(&ieee->scan_timer,(jiffies + MSECS(IEEE80211_SOFTMAC_SCAN_TIME))); +#endif + + up(&ieee->scan_sem); + return; +out: +#ifdef ENABLE_DOT11D + if(IS_DOT11D_ENABLE(ieee)) + DOT11D_ScanComplete(ieee); +#endif + ieee->current_network.channel = last_channel; + ieee->actscanning = false; + ieee->scan_watch_dog = 0; + ieee->scanning = 0; + up(&ieee->scan_sem); +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +void ieee80211_softmac_scan_cb(unsigned long _dev) +{ + unsigned long flags; + struct ieee80211_device *ieee = (struct ieee80211_device *)_dev; + + spin_lock_irqsave(&ieee->lock, flags); + ieee80211_softmac_scan(ieee); + spin_unlock_irqrestore(&ieee->lock, flags); +} +#endif + + +void ieee80211_beacons_start(struct ieee80211_device *ieee) +{ + unsigned long flags; + spin_lock_irqsave(&ieee->beacon_lock,flags); + + ieee->beacon_txing = 1; + ieee80211_send_beacon(ieee); + + spin_unlock_irqrestore(&ieee->beacon_lock,flags); +} + +void ieee80211_beacons_stop(struct ieee80211_device *ieee) +{ + unsigned long flags; + + spin_lock_irqsave(&ieee->beacon_lock,flags); + + ieee->beacon_txing = 0; + del_timer_sync(&ieee->beacon_timer); + + spin_unlock_irqrestore(&ieee->beacon_lock,flags); + +} + + +void ieee80211_stop_send_beacons(struct ieee80211_device *ieee) +{ + if(ieee->stop_send_beacons) + ieee->stop_send_beacons(ieee->dev); + if (ieee->softmac_features & IEEE_SOFTMAC_BEACONS) + ieee80211_beacons_stop(ieee); +} + + +void ieee80211_start_send_beacons(struct ieee80211_device *ieee) +{ + if(ieee->start_send_beacons) + ieee->start_send_beacons(ieee->dev); + if(ieee->softmac_features & IEEE_SOFTMAC_BEACONS) + ieee80211_beacons_start(ieee); +} + + +void ieee80211_softmac_stop_scan(struct ieee80211_device *ieee) +{ +// unsigned long flags; + + //ieee->sync_scan_hurryup = 1; + + down(&ieee->scan_sem); +// spin_lock_irqsave(&ieee->lock, flags); + ieee->scan_watch_dog = 0; + if (ieee->scanning == 1){ + ieee->scanning = 0; + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + cancel_delayed_work(&ieee->softmac_scan_wq); +#else + del_timer_sync(&ieee->scan_timer); +#endif + } + +// spin_unlock_irqrestore(&ieee->lock, flags); + up(&ieee->scan_sem); +} + +void ieee80211_stop_scan(struct ieee80211_device *ieee) +{ + if (ieee->softmac_features & IEEE_SOFTMAC_SCAN) + ieee80211_softmac_stop_scan(ieee); + else + ieee->stop_scan(ieee->dev); +} + +/* called with ieee->lock held */ +void ieee80211_start_scan(struct ieee80211_device *ieee) +{ +#ifdef ENABLE_DOT11D + if(IS_DOT11D_ENABLE(ieee) ) + { + if(IS_COUNTRY_IE_VALID(ieee)) + { + RESET_CIE_WATCHDOG(ieee); + } + } +#endif + if (ieee->softmac_features & IEEE_SOFTMAC_SCAN){ + if (ieee->scanning == 0){ + ieee->scanning = 1; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + queue_delayed_work(ieee->wq, &ieee->softmac_scan_wq, 0); +#else + + queue_work(ieee->wq, &ieee->softmac_scan_wq); +#endif +#else + ieee80211_softmac_scan(ieee); +#endif + } + }else + ieee->start_scan(ieee->dev); + +} + +/* called with wx_sem held */ +void ieee80211_start_scan_syncro(struct ieee80211_device *ieee) +{ +#ifdef ENABLE_DOT11D + if(IS_DOT11D_ENABLE(ieee) ) + { + if(IS_COUNTRY_IE_VALID(ieee)) + { + RESET_CIE_WATCHDOG(ieee); + } + } +#endif + ieee->sync_scan_hurryup = 0; + if (ieee->softmac_features & IEEE_SOFTMAC_SCAN) + ieee80211_softmac_scan_syncro(ieee); + else + ieee->scan_syncro(ieee->dev); + +} + +inline struct sk_buff *ieee80211_authentication_req(struct ieee80211_network *beacon, + struct ieee80211_device *ieee, int challengelen) +{ + struct sk_buff *skb; + struct ieee80211_authentication *auth; + int len = sizeof(struct ieee80211_authentication) + challengelen + ieee->tx_headroom; + + + skb = dev_alloc_skb(len); + if (!skb) return NULL; + + skb_reserve(skb, ieee->tx_headroom); + auth = (struct ieee80211_authentication *) + skb_put(skb, sizeof(struct ieee80211_authentication)); + + auth->header.frame_ctl = IEEE80211_STYPE_AUTH; + if (challengelen) auth->header.frame_ctl |= IEEE80211_FCTL_WEP; + + auth->header.duration_id = 0x013a; //FIXME + + memcpy(auth->header.addr1, beacon->bssid, ETH_ALEN); + memcpy(auth->header.addr2, ieee->dev->dev_addr, ETH_ALEN); + memcpy(auth->header.addr3, beacon->bssid, ETH_ALEN); + + //auth->algorithm = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY; + if(ieee->auth_mode == 0) + auth->algorithm = WLAN_AUTH_OPEN; + else if(ieee->auth_mode == 1) + auth->algorithm = WLAN_AUTH_SHARED_KEY; + else if(ieee->auth_mode == 2) + auth->algorithm = WLAN_AUTH_OPEN;//0x80; + printk("=================>%s():auth->algorithm is %d\n",__FUNCTION__,auth->algorithm); + auth->transaction = cpu_to_le16(ieee->associate_seq); + ieee->associate_seq++; + + auth->status = cpu_to_le16(WLAN_STATUS_SUCCESS); + + return skb; + +} + + +static struct sk_buff* ieee80211_probe_resp(struct ieee80211_device *ieee, u8 *dest) +{ + u8 *tag; + int beacon_size; + struct ieee80211_probe_response *beacon_buf; + struct sk_buff *skb = NULL; + int encrypt; + int atim_len,erp_len; + struct ieee80211_crypt_data* crypt; + + char *ssid = ieee->current_network.ssid; + int ssid_len = ieee->current_network.ssid_len; + int rate_len = ieee->current_network.rates_len+2; + int rate_ex_len = ieee->current_network.rates_ex_len; + int wpa_ie_len = ieee->wpa_ie_len; + u8 erpinfo_content = 0; + + u8* tmp_ht_cap_buf; + u8 tmp_ht_cap_len=0; + u8* tmp_ht_info_buf; + u8 tmp_ht_info_len=0; + PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; + u8* tmp_generic_ie_buf=NULL; + u8 tmp_generic_ie_len=0; + + if(rate_ex_len > 0) rate_ex_len+=2; + + if(ieee->current_network.capability & WLAN_CAPABILITY_IBSS) + atim_len = 4; + else + atim_len = 0; + +#if 1 + if(ieee80211_is_54g(ieee->current_network)) + erp_len = 3; + else + erp_len = 0; +#else + if((ieee->current_network.mode == IEEE_G) + ||( ieee->current_network.mode == IEEE_N_24G && ieee->pHTInfo->bCurSuppCCK)) { + erp_len = 3; + erpinfo_content = 0; + if(ieee->current_network.buseprotection) + erpinfo_content |= ERP_UseProtection; + } + else + erp_len = 0; +#endif + + + crypt = ieee->crypt[ieee->tx_keyidx]; + + + encrypt = ieee->host_encrypt && crypt && crypt->ops && + ((0 == strcmp(crypt->ops->name, "WEP") || wpa_ie_len)); + //HT ralated element +#if 1 + tmp_ht_cap_buf =(u8*) &(ieee->pHTInfo->SelfHTCap); + tmp_ht_cap_len = sizeof(ieee->pHTInfo->SelfHTCap); + tmp_ht_info_buf =(u8*) &(ieee->pHTInfo->SelfHTInfo); + tmp_ht_info_len = sizeof(ieee->pHTInfo->SelfHTInfo); + HTConstructCapabilityElement(ieee, tmp_ht_cap_buf, &tmp_ht_cap_len,encrypt); + HTConstructInfoElement(ieee,tmp_ht_info_buf,&tmp_ht_info_len, encrypt); + + + if(pHTInfo->bRegRT2RTAggregation) + { + tmp_generic_ie_buf = ieee->pHTInfo->szRT2RTAggBuffer; + tmp_generic_ie_len = sizeof(ieee->pHTInfo->szRT2RTAggBuffer); + HTConstructRT2RTAggElement(ieee, tmp_generic_ie_buf, &tmp_generic_ie_len); + } +// printk("===============>tmp_ht_cap_len is %d,tmp_ht_info_len is %d, tmp_generic_ie_len is %d\n",tmp_ht_cap_len,tmp_ht_info_len,tmp_generic_ie_len); +#endif + beacon_size = sizeof(struct ieee80211_probe_response)+2+ + ssid_len + +3 //channel + +rate_len + +rate_ex_len + +atim_len + +erp_len + +wpa_ie_len + // +tmp_ht_cap_len + // +tmp_ht_info_len + // +tmp_generic_ie_len +// +wmm_len+2 + +ieee->tx_headroom; + skb = dev_alloc_skb(beacon_size); + if (!skb) + return NULL; + skb_reserve(skb, ieee->tx_headroom); + beacon_buf = (struct ieee80211_probe_response*) skb_put(skb, (beacon_size - ieee->tx_headroom)); + memcpy (beacon_buf->header.addr1, dest,ETH_ALEN); + memcpy (beacon_buf->header.addr2, ieee->dev->dev_addr, ETH_ALEN); + memcpy (beacon_buf->header.addr3, ieee->current_network.bssid, ETH_ALEN); + + beacon_buf->header.duration_id = 0; //FIXME + beacon_buf->beacon_interval = + cpu_to_le16(ieee->current_network.beacon_interval); + beacon_buf->capability = + cpu_to_le16(ieee->current_network.capability & WLAN_CAPABILITY_IBSS); + beacon_buf->capability |= + cpu_to_le16(ieee->current_network.capability & WLAN_CAPABILITY_SHORT_PREAMBLE); //add short preamble here + + if(ieee->short_slot && (ieee->current_network.capability & WLAN_CAPABILITY_SHORT_SLOT)) + cpu_to_le16((beacon_buf->capability |= WLAN_CAPABILITY_SHORT_SLOT)); + + crypt = ieee->crypt[ieee->tx_keyidx]; +#if 0 + encrypt = ieee->host_encrypt && crypt && crypt->ops && + (0 == strcmp(crypt->ops->name, "WEP")); +#endif + if (encrypt) + beacon_buf->capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY); + + + beacon_buf->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_RESP); + beacon_buf->info_element[0].id = MFIE_TYPE_SSID; + beacon_buf->info_element[0].len = ssid_len; + + tag = (u8*) beacon_buf->info_element[0].data; + + memcpy(tag, ssid, ssid_len); + + tag += ssid_len; + + *(tag++) = MFIE_TYPE_RATES; + *(tag++) = rate_len-2; + memcpy(tag,ieee->current_network.rates,rate_len-2); + tag+=rate_len-2; + + *(tag++) = MFIE_TYPE_DS_SET; + *(tag++) = 1; + *(tag++) = ieee->current_network.channel; + + if(atim_len){ + u16 val16; + *(tag++) = MFIE_TYPE_IBSS_SET; + *(tag++) = 2; + //*((u16*)(tag)) = cpu_to_le16(ieee->current_network.atim_window); + val16 = cpu_to_le16(ieee->current_network.atim_window); + memcpy((u8 *)tag, (u8 *)&val16, 2); + tag+=2; + } + + if(erp_len){ + *(tag++) = MFIE_TYPE_ERP; + *(tag++) = 1; + *(tag++) = erpinfo_content; + } +#if 0 + //Include High Throuput capability + + *(tag++) = MFIE_TYPE_HT_CAP; + *(tag++) = tmp_ht_cap_len - 2; + memcpy(tag, tmp_ht_cap_buf, tmp_ht_cap_len - 2); + tag += tmp_ht_cap_len - 2; +#endif + if(rate_ex_len){ + *(tag++) = MFIE_TYPE_RATES_EX; + *(tag++) = rate_ex_len-2; + memcpy(tag,ieee->current_network.rates_ex,rate_ex_len-2); + tag+=rate_ex_len-2; + } + +#if 0 + //Include High Throuput info + + *(tag++) = MFIE_TYPE_HT_INFO; + *(tag++) = tmp_ht_info_len - 2; + memcpy(tag, tmp_ht_info_buf, tmp_ht_info_len -2); + tag += tmp_ht_info_len - 2; +#endif + if (wpa_ie_len) + { + if (ieee->iw_mode == IW_MODE_ADHOC) + {//as Windows will set pairwise key same as the group key which is not allowed in Linux, so set this for IOT issue. WB 2008.07.07 + memcpy(&ieee->wpa_ie[14], &ieee->wpa_ie[8], 4); + } + memcpy(tag, ieee->wpa_ie, ieee->wpa_ie_len); + tag += wpa_ie_len; + } + +#if 0 + // + // Construct Realtek Proprietary Aggregation mode (Set AMPDU Factor to 2, 32k) + // + if(pHTInfo->bRegRT2RTAggregation) + { + (*tag++) = 0xdd; + (*tag++) = tmp_generic_ie_len - 2; + memcpy(tag,tmp_generic_ie_buf,tmp_generic_ie_len -2); + tag += tmp_generic_ie_len -2; + + } +#endif +#if 0 + if(ieee->qos_support) + { + (*tag++) = 0xdd; + (*tag++) = wmm_len; + memcpy(tag,QosOui,wmm_len); + tag += wmm_len; + } +#endif + //skb->dev = ieee->dev; + return skb; +} + + +struct sk_buff* ieee80211_assoc_resp(struct ieee80211_device *ieee, u8 *dest) +{ + struct sk_buff *skb; + u8* tag; + + struct ieee80211_crypt_data* crypt; + struct ieee80211_assoc_response_frame *assoc; + short encrypt; + + unsigned int rate_len = ieee80211_MFIE_rate_len(ieee); + int len = sizeof(struct ieee80211_assoc_response_frame) + rate_len + ieee->tx_headroom; + + skb = dev_alloc_skb(len); + + if (!skb) + return NULL; + + skb_reserve(skb, ieee->tx_headroom); + + assoc = (struct ieee80211_assoc_response_frame *) + skb_put(skb,sizeof(struct ieee80211_assoc_response_frame)); + + assoc->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP); + memcpy(assoc->header.addr1, dest,ETH_ALEN); + memcpy(assoc->header.addr3, ieee->dev->dev_addr, ETH_ALEN); + memcpy(assoc->header.addr2, ieee->dev->dev_addr, ETH_ALEN); + assoc->capability = cpu_to_le16(ieee->iw_mode == IW_MODE_MASTER ? + WLAN_CAPABILITY_BSS : WLAN_CAPABILITY_IBSS); + + + if(ieee->short_slot) + assoc->capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT); + + if (ieee->host_encrypt) + crypt = ieee->crypt[ieee->tx_keyidx]; + else crypt = NULL; + + encrypt = ( crypt && crypt->ops); + + if (encrypt) + assoc->capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY); + + assoc->status = 0; + assoc->aid = cpu_to_le16(ieee->assoc_id); + if (ieee->assoc_id == 0x2007) ieee->assoc_id=0; + else ieee->assoc_id++; + + tag = (u8*) skb_put(skb, rate_len); + + ieee80211_MFIE_Brate(ieee, &tag); + ieee80211_MFIE_Grate(ieee, &tag); + + return skb; +} + +struct sk_buff* ieee80211_auth_resp(struct ieee80211_device *ieee,int status, u8 *dest) +{ + struct sk_buff *skb; + struct ieee80211_authentication *auth; + int len = ieee->tx_headroom + sizeof(struct ieee80211_authentication)+1; + + skb = dev_alloc_skb(len); + + if (!skb) + return NULL; + + skb->len = sizeof(struct ieee80211_authentication); + + auth = (struct ieee80211_authentication *)skb->data; + + auth->status = cpu_to_le16(status); + auth->transaction = cpu_to_le16(2); + auth->algorithm = cpu_to_le16(WLAN_AUTH_OPEN); + + memcpy(auth->header.addr3, ieee->dev->dev_addr, ETH_ALEN); + memcpy(auth->header.addr2, ieee->dev->dev_addr, ETH_ALEN); + memcpy(auth->header.addr1, dest, ETH_ALEN); + auth->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_AUTH); + return skb; + + +} + +struct sk_buff* ieee80211_null_func(struct ieee80211_device *ieee,short pwr) +{ + struct sk_buff *skb; + struct ieee80211_hdr_3addr* hdr; + + skb = dev_alloc_skb(sizeof(struct ieee80211_hdr_3addr)); + + if (!skb) + return NULL; + + hdr = (struct ieee80211_hdr_3addr*)skb_put(skb,sizeof(struct ieee80211_hdr_3addr)); + + memcpy(hdr->addr1, ieee->current_network.bssid, ETH_ALEN); + memcpy(hdr->addr2, ieee->dev->dev_addr, ETH_ALEN); + memcpy(hdr->addr3, ieee->current_network.bssid, ETH_ALEN); + + hdr->frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA | + IEEE80211_STYPE_NULLFUNC | IEEE80211_FCTL_TODS | + (pwr ? IEEE80211_FCTL_PM:0)); + + return skb; + + +} + + +void ieee80211_resp_to_assoc_rq(struct ieee80211_device *ieee, u8* dest) +{ + struct sk_buff *buf = ieee80211_assoc_resp(ieee, dest); + + if (buf) + softmac_mgmt_xmit(buf, ieee); +} + + +void ieee80211_resp_to_auth(struct ieee80211_device *ieee, int s, u8* dest) +{ + struct sk_buff *buf = ieee80211_auth_resp(ieee, s, dest); + + if (buf) + softmac_mgmt_xmit(buf, ieee); +} + + +void ieee80211_resp_to_probe(struct ieee80211_device *ieee, u8 *dest) +{ + + + struct sk_buff *buf = ieee80211_probe_resp(ieee, dest); + if (buf) + softmac_mgmt_xmit(buf, ieee); +} + + +inline struct sk_buff *ieee80211_association_req(struct ieee80211_network *beacon,struct ieee80211_device *ieee) +{ + struct sk_buff *skb; + //unsigned long flags; + + struct ieee80211_assoc_request_frame *hdr; + u8 *tag;//,*rsn_ie; + //short info_addr = 0; + //int i; + //u16 suite_count = 0; + //u8 suit_select = 0; + //unsigned int wpa_len = beacon->wpa_ie_len; + //for HT + u8* ht_cap_buf = NULL; + u8 ht_cap_len=0; + u8* realtek_ie_buf=NULL; + u8 realtek_ie_len=0; + int wpa_ie_len= ieee->wpa_ie_len; + unsigned int ckip_ie_len=0; + unsigned int ccxrm_ie_len=0; + unsigned int cxvernum_ie_len=0; + struct ieee80211_crypt_data* crypt; + int encrypt; + + unsigned int rate_len = ieee80211_MFIE_rate_len(ieee); + unsigned int wmm_info_len = beacon->qos_data.supported?9:0; +#ifdef THOMAS_TURBO + unsigned int turbo_info_len = beacon->Turbo_Enable?9:0; +#endif + + int len = 0; + + crypt = ieee->crypt[ieee->tx_keyidx]; + encrypt = ieee->host_encrypt && crypt && crypt->ops && ((0 == strcmp(crypt->ops->name,"WEP") || wpa_ie_len)); + + //Include High Throuput capability && Realtek proprietary + if(ieee->pHTInfo->bCurrentHTSupport&&ieee->pHTInfo->bEnableHT) + { + ht_cap_buf = (u8*)&(ieee->pHTInfo->SelfHTCap); + ht_cap_len = sizeof(ieee->pHTInfo->SelfHTCap); + HTConstructCapabilityElement(ieee, ht_cap_buf, &ht_cap_len, encrypt); + if(ieee->pHTInfo->bCurrentRT2RTAggregation) + { + realtek_ie_buf = ieee->pHTInfo->szRT2RTAggBuffer; + realtek_ie_len = sizeof( ieee->pHTInfo->szRT2RTAggBuffer); + HTConstructRT2RTAggElement(ieee, realtek_ie_buf, &realtek_ie_len); + + } + } + if(ieee->qos_support){ + wmm_info_len = beacon->qos_data.supported?9:0; + } + + + if(beacon->bCkipSupported) + { + ckip_ie_len = 30+2; + } + if(beacon->bCcxRmEnable) + { + ccxrm_ie_len = 6+2; + } + if( beacon->BssCcxVerNumber >= 2 ) + { + cxvernum_ie_len = 5+2; + } +#ifdef THOMAS_TURBO + len = sizeof(struct ieee80211_assoc_request_frame)+ 2 + + beacon->ssid_len//essid tagged val + + rate_len//rates tagged val + + wpa_ie_len + + wmm_info_len + + turbo_info_len + + ht_cap_len + + realtek_ie_len + + ckip_ie_len + + ccxrm_ie_len + + cxvernum_ie_len + + ieee->tx_headroom; +#else + len = sizeof(struct ieee80211_assoc_request_frame)+ 2 + + beacon->ssid_len//essid tagged val + + rate_len//rates tagged val + + wpa_ie_len + + wmm_info_len + + ht_cap_len + + realtek_ie_len + + ckip_ie_len + + ccxrm_ie_len + + cxvernum_ie_len + + ieee->tx_headroom; +#endif + + skb = dev_alloc_skb(len); + + if (!skb) + return NULL; + + skb_reserve(skb, ieee->tx_headroom); + + hdr = (struct ieee80211_assoc_request_frame *) + skb_put(skb, sizeof(struct ieee80211_assoc_request_frame)+2); + + + hdr->header.frame_ctl = IEEE80211_STYPE_ASSOC_REQ; + hdr->header.duration_id= 37; //FIXME + memcpy(hdr->header.addr1, beacon->bssid, ETH_ALEN); + memcpy(hdr->header.addr2, ieee->dev->dev_addr, ETH_ALEN); + memcpy(hdr->header.addr3, beacon->bssid, ETH_ALEN); + + memcpy(ieee->ap_mac_addr, beacon->bssid, ETH_ALEN);//for HW security, John + + hdr->capability = cpu_to_le16(WLAN_CAPABILITY_BSS); + if (beacon->capability & WLAN_CAPABILITY_PRIVACY ) + hdr->capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY); + + if (beacon->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) + hdr->capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE); //add short_preamble here + + if(ieee->short_slot) + hdr->capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT); + if (wmm_info_len) //QOS + hdr->capability |= cpu_to_le16(WLAN_CAPABILITY_QOS); + + hdr->listen_interval = 0xa; //FIXME + + hdr->info_element[0].id = MFIE_TYPE_SSID; + + hdr->info_element[0].len = beacon->ssid_len; + tag = skb_put(skb, beacon->ssid_len); + memcpy(tag, beacon->ssid, beacon->ssid_len); + + tag = skb_put(skb, rate_len); + + ieee80211_MFIE_Brate(ieee, &tag); + ieee80211_MFIE_Grate(ieee, &tag); + // For CCX 1 S13, CKIP. Added by Annie, 2006-08-14. + if( beacon->bCkipSupported ) + { + static u8 AironetIeOui[] = {0x00, 0x01, 0x66}; // "4500-client" + u8 CcxAironetBuf[30]; + OCTET_STRING osCcxAironetIE; + + memset(CcxAironetBuf, 0,30); + osCcxAironetIE.Octet = CcxAironetBuf; + osCcxAironetIE.Length = sizeof(CcxAironetBuf); + // + // Ref. CCX test plan v3.61, 3.2.3.1 step 13. + // We want to make the device type as "4500-client". 060926, by CCW. + // + memcpy(osCcxAironetIE.Octet, AironetIeOui, sizeof(AironetIeOui)); + + // CCX1 spec V1.13, A01.1 CKIP Negotiation (page23): + // "The CKIP negotiation is started with the associate request from the client to the access point, + // containing an Aironet element with both the MIC and KP bits set." + osCcxAironetIE.Octet[IE_CISCO_FLAG_POSITION] |= (SUPPORT_CKIP_PK|SUPPORT_CKIP_MIC) ; + tag = skb_put(skb, ckip_ie_len); + *tag++ = MFIE_TYPE_AIRONET; + *tag++ = osCcxAironetIE.Length; + memcpy(tag,osCcxAironetIE.Octet,osCcxAironetIE.Length); + tag += osCcxAironetIE.Length; + } + + if(beacon->bCcxRmEnable) + { + static u8 CcxRmCapBuf[] = {0x00, 0x40, 0x96, 0x01, 0x01, 0x00}; + OCTET_STRING osCcxRmCap; + + osCcxRmCap.Octet = CcxRmCapBuf; + osCcxRmCap.Length = sizeof(CcxRmCapBuf); + tag = skb_put(skb,ccxrm_ie_len); + *tag++ = MFIE_TYPE_GENERIC; + *tag++ = osCcxRmCap.Length; + memcpy(tag,osCcxRmCap.Octet,osCcxRmCap.Length); + tag += osCcxRmCap.Length; + } + + if( beacon->BssCcxVerNumber >= 2 ) + { + u8 CcxVerNumBuf[] = {0x00, 0x40, 0x96, 0x03, 0x00}; + OCTET_STRING osCcxVerNum; + CcxVerNumBuf[4] = beacon->BssCcxVerNumber; + osCcxVerNum.Octet = CcxVerNumBuf; + osCcxVerNum.Length = sizeof(CcxVerNumBuf); + tag = skb_put(skb,cxvernum_ie_len); + *tag++ = MFIE_TYPE_GENERIC; + *tag++ = osCcxVerNum.Length; + memcpy(tag,osCcxVerNum.Octet,osCcxVerNum.Length); + tag += osCcxVerNum.Length; + } + //HT cap element + if(ieee->pHTInfo->bCurrentHTSupport&&ieee->pHTInfo->bEnableHT){ + if(ieee->pHTInfo->ePeerHTSpecVer != HT_SPEC_VER_EWC) + { + tag = skb_put(skb, ht_cap_len); + *tag++ = MFIE_TYPE_HT_CAP; + *tag++ = ht_cap_len - 2; + memcpy(tag, ht_cap_buf,ht_cap_len -2); + tag += ht_cap_len -2; + } + } + + + //choose what wpa_supplicant gives to associate. + tag = skb_put(skb, wpa_ie_len); + if (wpa_ie_len){ + memcpy(tag, ieee->wpa_ie, ieee->wpa_ie_len); + } + + tag = skb_put(skb,wmm_info_len); + if(wmm_info_len) { + ieee80211_WMM_Info(ieee, &tag); + } +#ifdef THOMAS_TURBO + tag = skb_put(skb,turbo_info_len); + if(turbo_info_len) { + ieee80211_TURBO_Info(ieee, &tag); + } +#endif + + if(ieee->pHTInfo->bCurrentHTSupport&&ieee->pHTInfo->bEnableHT){ + if(ieee->pHTInfo->ePeerHTSpecVer == HT_SPEC_VER_EWC) + { + tag = skb_put(skb, ht_cap_len); + *tag++ = MFIE_TYPE_GENERIC; + *tag++ = ht_cap_len - 2; + memcpy(tag, ht_cap_buf,ht_cap_len - 2); + tag += ht_cap_len -2; + } + + if(ieee->pHTInfo->bCurrentRT2RTAggregation){ + tag = skb_put(skb, realtek_ie_len); + *tag++ = MFIE_TYPE_GENERIC; + *tag++ = realtek_ie_len - 2; + memcpy(tag, realtek_ie_buf,realtek_ie_len -2 ); + } + } +// printk("<=====%s(), %p, %p\n", __FUNCTION__, ieee->dev, ieee->dev->dev_addr); +// IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA, skb->data, skb->len); + return skb; +} + +void ieee80211_associate_abort(struct ieee80211_device *ieee) +{ + + unsigned long flags; + spin_lock_irqsave(&ieee->lock, flags); + + ieee->associate_seq++; + + /* don't scan, and avoid to have the RX path possibily + * try again to associate. Even do not react to AUTH or + * ASSOC response. Just wait for the retry wq to be scheduled. + * Here we will check if there are good nets to associate + * with, so we retry or just get back to NO_LINK and scanning + */ + if (ieee->state == IEEE80211_ASSOCIATING_AUTHENTICATING){ + IEEE80211_DEBUG_MGMT("Authentication failed\n"); + ieee->softmac_stats.no_auth_rs++; + }else{ + IEEE80211_DEBUG_MGMT("Association failed\n"); + ieee->softmac_stats.no_ass_rs++; + } + + ieee->state = IEEE80211_ASSOCIATING_RETRY; + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + queue_delayed_work(ieee->wq, &ieee->associate_retry_wq, \ + IEEE80211_SOFTMAC_ASSOC_RETRY_TIME); +#else + schedule_task(&ieee->associate_retry_wq); +#endif + + spin_unlock_irqrestore(&ieee->lock, flags); +} + +void ieee80211_associate_abort_cb(unsigned long dev) +{ + ieee80211_associate_abort((struct ieee80211_device *) dev); +} + + +void ieee80211_associate_step1(struct ieee80211_device *ieee) +{ + struct ieee80211_network *beacon = &ieee->current_network; + struct sk_buff *skb; + + IEEE80211_DEBUG_MGMT("Stopping scan\n"); + + ieee->softmac_stats.tx_auth_rq++; + skb=ieee80211_authentication_req(beacon, ieee, 0); + + if (!skb) + ieee80211_associate_abort(ieee); + else{ + ieee->state = IEEE80211_ASSOCIATING_AUTHENTICATING ; + IEEE80211_DEBUG_MGMT("Sending authentication request\n"); + //printk(KERN_WARNING "Sending authentication request\n"); + softmac_mgmt_xmit(skb, ieee); + //BUGON when you try to add_timer twice, using mod_timer may be better, john0709 + if(!timer_pending(&ieee->associate_timer)){ + ieee->associate_timer.expires = jiffies + (HZ / 2); + add_timer(&ieee->associate_timer); + } + //dev_kfree_skb_any(skb);//edit by thomas + } +} + +void ieee80211_auth_challenge(struct ieee80211_device *ieee, u8 *challenge, int chlen) +{ + u8 *c; + struct sk_buff *skb; + struct ieee80211_network *beacon = &ieee->current_network; +// int hlen = sizeof(struct ieee80211_authentication); + + ieee->associate_seq++; + ieee->softmac_stats.tx_auth_rq++; + + skb = ieee80211_authentication_req(beacon, ieee, chlen+2); + if (!skb) + ieee80211_associate_abort(ieee); + else{ + c = skb_put(skb, chlen+2); + *(c++) = MFIE_TYPE_CHALLENGE; + *(c++) = chlen; + memcpy(c, challenge, chlen); + + IEEE80211_DEBUG_MGMT("Sending authentication challenge response\n"); + + ieee80211_encrypt_fragment(ieee, skb, sizeof(struct ieee80211_hdr_3addr )); + + softmac_mgmt_xmit(skb, ieee); + mod_timer(&ieee->associate_timer, jiffies + (HZ/2)); +#if 0 + ieee->associate_timer.expires = jiffies + (HZ / 2); + add_timer(&ieee->associate_timer); +#endif + //dev_kfree_skb_any(skb);//edit by thomas + } + kfree(challenge); +} + +void ieee80211_associate_step2(struct ieee80211_device *ieee) +{ + struct sk_buff* skb; + struct ieee80211_network *beacon = &ieee->current_network; + + del_timer_sync(&ieee->associate_timer); + + IEEE80211_DEBUG_MGMT("Sending association request\n"); + + ieee->softmac_stats.tx_ass_rq++; + skb=ieee80211_association_req(beacon, ieee); + if (!skb) + ieee80211_associate_abort(ieee); + else{ + softmac_mgmt_xmit(skb, ieee); + mod_timer(&ieee->associate_timer, jiffies + (HZ/2)); +#if 0 + ieee->associate_timer.expires = jiffies + (HZ / 2); + add_timer(&ieee->associate_timer); +#endif + //dev_kfree_skb_any(skb);//edit by thomas + } +} +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) +void ieee80211_associate_complete_wq(struct work_struct *work) +{ + struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, associate_complete_wq); +#else +void ieee80211_associate_complete_wq(struct ieee80211_device *ieee) +{ +#endif + printk(KERN_INFO "Associated successfully\n"); + ieee->is_roaming = false; + if(ieee80211_is_54g(ieee->current_network) && + (ieee->modulation & IEEE80211_OFDM_MODULATION)){ + + ieee->rate = 108; + printk(KERN_INFO"Using G rates:%d\n", ieee->rate); + }else{ + ieee->rate = 22; + printk(KERN_INFO"Using B rates:%d\n", ieee->rate); + } + if (ieee->pHTInfo->bCurrentHTSupport&&ieee->pHTInfo->bEnableHT) + { + printk("Successfully associated, ht enabled\n"); + HTOnAssocRsp(ieee); + } + else + { + printk("Successfully associated, ht not enabled(%d, %d)\n", ieee->pHTInfo->bCurrentHTSupport, ieee->pHTInfo->bEnableHT); + memset(ieee->dot11HTOperationalRateSet, 0, 16); + //HTSetConnectBwMode(ieee, HT_CHANNEL_WIDTH_20, HT_EXTCHNL_OFFSET_NO_EXT); + } + ieee->LinkDetectInfo.SlotNum = 2 * (1 + ieee->current_network.beacon_interval/500); + // To prevent the immediately calling watch_dog after association. + if(ieee->LinkDetectInfo.NumRecvBcnInPeriod==0||ieee->LinkDetectInfo.NumRecvDataInPeriod==0 ) + { + ieee->LinkDetectInfo.NumRecvBcnInPeriod = 1; + ieee->LinkDetectInfo.NumRecvDataInPeriod= 1; + } + ieee->link_change(ieee->dev); + if(ieee->is_silent_reset == 0){ + printk("============>normal associate\n"); + notify_wx_assoc_event(ieee); + } + else if(ieee->is_silent_reset == 1) + { + printk("==================>silent reset associate\n"); + ieee->is_silent_reset = 0; + } + + if (ieee->data_hard_resume) + ieee->data_hard_resume(ieee->dev); + netif_carrier_on(ieee->dev); +} + +void ieee80211_associate_complete(struct ieee80211_device *ieee) +{ +// int i; +// struct net_device* dev = ieee->dev; + del_timer_sync(&ieee->associate_timer); + +#if 0 + for(i = 0; i < 6; i++) { + ieee->seq_ctrl[i] = 0; + } +#endif + ieee->state = IEEE80211_LINKED; +#if 0 + if (ieee->pHTInfo->bCurrentHTSupport) + { + printk("Successfully associated, ht enabled\n"); + queue_work(ieee->wq, &ieee->ht_onAssRsp); + } + else + { + printk("Successfully associated, ht not enabled\n"); + memset(ieee->dot11HTOperationalRateSet, 0, 16); + HTSetConnectBwMode(ieee, HT_CHANNEL_WIDTH_20, HT_EXTCHNL_OFFSET_NO_EXT); + } +#endif + //ieee->UpdateHalRATRTableHandler(dev, ieee->dot11HTOperationalRateSet); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + queue_work(ieee->wq, &ieee->associate_complete_wq); +#else + schedule_task(&ieee->associate_complete_wq); +#endif +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) +void ieee80211_associate_procedure_wq(struct work_struct *work) +{ + struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, associate_procedure_wq); +#else +void ieee80211_associate_procedure_wq(struct ieee80211_device *ieee) +{ +#endif + ieee->sync_scan_hurryup = 1; + down(&ieee->wx_sem); + + if (ieee->data_hard_stop) + ieee->data_hard_stop(ieee->dev); + + ieee80211_stop_scan(ieee); + printk("===>%s(), chan:%d\n", __FUNCTION__, ieee->current_network.channel); + //ieee->set_chan(ieee->dev, ieee->current_network.channel); + HTSetConnectBwMode(ieee, HT_CHANNEL_WIDTH_20, HT_EXTCHNL_OFFSET_NO_EXT); + + ieee->associate_seq = 1; + ieee80211_associate_step1(ieee); + + up(&ieee->wx_sem); +} + +inline void ieee80211_softmac_new_net(struct ieee80211_device *ieee, struct ieee80211_network *net) +{ + u8 tmp_ssid[IW_ESSID_MAX_SIZE+1]; + int tmp_ssid_len = 0; + + short apset,ssidset,ssidbroad,apmatch,ssidmatch; + + /* we are interested in new new only if we are not associated + * and we are not associating / authenticating + */ + if (ieee->state != IEEE80211_NOLINK) + return; + + if ((ieee->iw_mode == IW_MODE_INFRA) && !(net->capability & WLAN_CAPABILITY_BSS)) + return; + + if ((ieee->iw_mode == IW_MODE_ADHOC) && !(net->capability & WLAN_CAPABILITY_IBSS)) + return; + + + if (ieee->iw_mode == IW_MODE_INFRA || ieee->iw_mode == IW_MODE_ADHOC){ + /* if the user specified the AP MAC, we need also the essid + * This could be obtained by beacons or, if the network does not + * broadcast it, it can be put manually. + */ + apset = ieee->wap_set;//(memcmp(ieee->current_network.bssid, zero,ETH_ALEN)!=0 ); + ssidset = ieee->ssid_set;//ieee->current_network.ssid[0] != '\0'; + ssidbroad = !(net->ssid_len == 0 || net->ssid[0]== '\0'); + apmatch = (memcmp(ieee->current_network.bssid, net->bssid, ETH_ALEN)==0); + ssidmatch = (ieee->current_network.ssid_len == net->ssid_len)&&\ + (!strncmp(ieee->current_network.ssid, net->ssid, net->ssid_len)); + + + if ( /* if the user set the AP check if match. + * if the network does not broadcast essid we check the user supplyed ANY essid + * if the network does broadcast and the user does not set essid it is OK + * if the network does broadcast and the user did set essid chech if essid match + */ + ( apset && apmatch && + ((ssidset && ssidbroad && ssidmatch) || (ssidbroad && !ssidset) || (!ssidbroad && ssidset)) ) || + /* if the ap is not set, check that the user set the bssid + * and the network does bradcast and that those two bssid matches + */ + (!apset && ssidset && ssidbroad && ssidmatch) + ){ + /* if the essid is hidden replace it with the + * essid provided by the user. + */ + if (!ssidbroad){ + strncpy(tmp_ssid, ieee->current_network.ssid, IW_ESSID_MAX_SIZE); + tmp_ssid_len = ieee->current_network.ssid_len; + } + memcpy(&ieee->current_network, net, sizeof(struct ieee80211_network)); + + if (!ssidbroad){ + strncpy(ieee->current_network.ssid, tmp_ssid, IW_ESSID_MAX_SIZE); + ieee->current_network.ssid_len = tmp_ssid_len; + } + printk(KERN_INFO"Linking with %s,channel:%d, qos:%d, myHT:%d, networkHT:%d, mode:%x\n",ieee->current_network.ssid,ieee->current_network.channel, ieee->current_network.qos_data.supported, ieee->pHTInfo->bEnableHT, ieee->current_network.bssht.bdSupportHT, ieee->current_network.mode); + + //ieee->pHTInfo->IOTAction = 0; + HTResetIOTSetting(ieee->pHTInfo); + if (ieee->iw_mode == IW_MODE_INFRA){ + /* Join the network for the first time */ + ieee->AsocRetryCount = 0; + //for HT by amy 080514 + if((ieee->current_network.qos_data.supported == 1) && + // (ieee->pHTInfo->bEnableHT && ieee->current_network.bssht.bdSupportHT)) + ieee->current_network.bssht.bdSupportHT) +/*WB, 2008.09.09:bCurrentHTSupport and bEnableHT two flags are going to put together to check whether we are in HT now, so needn't to check bEnableHT flags here. That's is to say we will set to HT support whenever joined AP has the ability to support HT. And whether we are in HT or not, please check bCurrentHTSupport&&bEnableHT now please.*/ + { + // ieee->pHTInfo->bCurrentHTSupport = true; + HTResetSelfAndSavePeerSetting(ieee, &(ieee->current_network)); + } + else + { + ieee->pHTInfo->bCurrentHTSupport = false; + } + + ieee->state = IEEE80211_ASSOCIATING; + if(ieee->LedControlHandler != NULL) + ieee->LedControlHandler(ieee->dev, LED_CTL_START_TO_LINK); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + queue_work(ieee->wq, &ieee->associate_procedure_wq); +#else + schedule_task(&ieee->associate_procedure_wq); +#endif + }else{ + if(ieee80211_is_54g(ieee->current_network) && + (ieee->modulation & IEEE80211_OFDM_MODULATION)){ + ieee->rate = 108; + ieee->SetWirelessMode(ieee->dev, IEEE_G); + printk(KERN_INFO"Using G rates\n"); + }else{ + ieee->rate = 22; + ieee->SetWirelessMode(ieee->dev, IEEE_B); + printk(KERN_INFO"Using B rates\n"); + } + memset(ieee->dot11HTOperationalRateSet, 0, 16); + //HTSetConnectBwMode(ieee, HT_CHANNEL_WIDTH_20, HT_EXTCHNL_OFFSET_NO_EXT); + ieee->state = IEEE80211_LINKED; + } + + } + } + +} + +void ieee80211_softmac_check_all_nets(struct ieee80211_device *ieee) +{ + unsigned long flags; + struct ieee80211_network *target; + + spin_lock_irqsave(&ieee->lock, flags); + + list_for_each_entry(target, &ieee->network_list, list) { + + /* if the state become different that NOLINK means + * we had found what we are searching for + */ + + if (ieee->state != IEEE80211_NOLINK) + break; + + if (ieee->scan_age == 0 || time_after(target->last_scanned + ieee->scan_age, jiffies)) + ieee80211_softmac_new_net(ieee, target); + } + + spin_unlock_irqrestore(&ieee->lock, flags); + +} + + +static inline u16 auth_parse(struct sk_buff *skb, u8** challenge, int *chlen) +{ + struct ieee80211_authentication *a; + u8 *t; + if (skb->len < (sizeof(struct ieee80211_authentication)-sizeof(struct ieee80211_info_element))){ + IEEE80211_DEBUG_MGMT("invalid len in auth resp: %d\n",skb->len); + return 0xcafe; + } + *challenge = NULL; + a = (struct ieee80211_authentication*) skb->data; + if(skb->len > (sizeof(struct ieee80211_authentication) +3)){ + t = skb->data + sizeof(struct ieee80211_authentication); + + if(*(t++) == MFIE_TYPE_CHALLENGE){ + *chlen = *(t++); + *challenge = (u8*)kmalloc(*chlen, GFP_ATOMIC); + memcpy(*challenge, t, *chlen); + } + } + + return cpu_to_le16(a->status); + +} + + +int auth_rq_parse(struct sk_buff *skb,u8* dest) +{ + struct ieee80211_authentication *a; + + if (skb->len < (sizeof(struct ieee80211_authentication)-sizeof(struct ieee80211_info_element))){ + IEEE80211_DEBUG_MGMT("invalid len in auth request: %d\n",skb->len); + return -1; + } + a = (struct ieee80211_authentication*) skb->data; + + memcpy(dest,a->header.addr2, ETH_ALEN); + + if (le16_to_cpu(a->algorithm) != WLAN_AUTH_OPEN) + return WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG; + + return WLAN_STATUS_SUCCESS; +} + +static short probe_rq_parse(struct ieee80211_device *ieee, struct sk_buff *skb, u8 *src) +{ + u8 *tag; + u8 *skbend; + u8 *ssid=NULL; + u8 ssidlen = 0; + + struct ieee80211_hdr_3addr *header = + (struct ieee80211_hdr_3addr *) skb->data; + + if (skb->len < sizeof (struct ieee80211_hdr_3addr )) + return -1; /* corrupted */ + + memcpy(src,header->addr2, ETH_ALEN); + + skbend = (u8*)skb->data + skb->len; + + tag = skb->data + sizeof (struct ieee80211_hdr_3addr ); + + while (tag+1 < skbend){ + if (*tag == 0){ + ssid = tag+2; + ssidlen = *(tag+1); + break; + } + tag++; /* point to the len field */ + tag = tag + *(tag); /* point to the last data byte of the tag */ + tag++; /* point to the next tag */ + } + + //IEEE80211DMESG("Card MAC address is "MACSTR, MAC2STR(src)); + if (ssidlen == 0) return 1; + + if (!ssid) return 1; /* ssid not found in tagged param */ + return (!strncmp(ssid, ieee->current_network.ssid, ssidlen)); + +} + +int assoc_rq_parse(struct sk_buff *skb,u8* dest) +{ + struct ieee80211_assoc_request_frame *a; + + if (skb->len < (sizeof(struct ieee80211_assoc_request_frame) - + sizeof(struct ieee80211_info_element))) { + + IEEE80211_DEBUG_MGMT("invalid len in auth request:%d \n", skb->len); + return -1; + } + + a = (struct ieee80211_assoc_request_frame*) skb->data; + + memcpy(dest,a->header.addr2,ETH_ALEN); + + return 0; +} + +static inline u16 assoc_parse(struct ieee80211_device *ieee, struct sk_buff *skb, int *aid) +{ + struct ieee80211_assoc_response_frame *response_head; + u16 status_code; + + if (skb->len < sizeof(struct ieee80211_assoc_response_frame)){ + IEEE80211_DEBUG_MGMT("invalid len in auth resp: %d\n", skb->len); + return 0xcafe; + } + + response_head = (struct ieee80211_assoc_response_frame*) skb->data; + *aid = le16_to_cpu(response_head->aid) & 0x3fff; + + status_code = le16_to_cpu(response_head->status); + if((status_code==WLAN_STATUS_ASSOC_DENIED_RATES || \ + status_code==WLAN_STATUS_CAPS_UNSUPPORTED)&& + ((ieee->mode == IEEE_G) && + (ieee->current_network.mode == IEEE_N_24G) && + (ieee->AsocRetryCount++ < (RT_ASOC_RETRY_LIMIT-1)))) { + ieee->pHTInfo->IOTAction |= HT_IOT_ACT_PURE_N_MODE; + }else { + ieee->AsocRetryCount = 0; + } + + return le16_to_cpu(response_head->status); +} + +static inline void +ieee80211_rx_probe_rq(struct ieee80211_device *ieee, struct sk_buff *skb) +{ + u8 dest[ETH_ALEN]; + + //IEEE80211DMESG("Rx probe"); + ieee->softmac_stats.rx_probe_rq++; + //DMESG("Dest is "MACSTR, MAC2STR(dest)); + if (probe_rq_parse(ieee, skb, dest)){ + //IEEE80211DMESG("Was for me!"); + ieee->softmac_stats.tx_probe_rs++; + ieee80211_resp_to_probe(ieee, dest); + } +} + +static inline void +ieee80211_rx_auth_rq(struct ieee80211_device *ieee, struct sk_buff *skb) +{ + u8 dest[ETH_ALEN]; + int status; + //IEEE80211DMESG("Rx probe"); + ieee->softmac_stats.rx_auth_rq++; + + if ((status = auth_rq_parse(skb, dest))!= -1){ + ieee80211_resp_to_auth(ieee, status, dest); + } + //DMESG("Dest is "MACSTR, MAC2STR(dest)); + +} + +static inline void +ieee80211_rx_assoc_rq(struct ieee80211_device *ieee, struct sk_buff *skb) +{ + + u8 dest[ETH_ALEN]; + //unsigned long flags; + + ieee->softmac_stats.rx_ass_rq++; + if (assoc_rq_parse(skb,dest) != -1){ + ieee80211_resp_to_assoc_rq(ieee, dest); + } + + printk(KERN_INFO"New client associated: "MAC_FMT"\n", MAC_ARG(dest)); + //FIXME + #if 0 + spin_lock_irqsave(&ieee->lock,flags); + add_associate(ieee,dest); + spin_unlock_irqrestore(&ieee->lock,flags); + #endif +} + + + +void ieee80211_sta_ps_send_null_frame(struct ieee80211_device *ieee, short pwr) +{ + + struct sk_buff *buf = ieee80211_null_func(ieee, pwr); + + if (buf) + softmac_ps_mgmt_xmit(buf, ieee); + +} + + +short ieee80211_sta_ps_sleep(struct ieee80211_device *ieee, u32 *time_h, u32 *time_l) +{ + int timeout = ieee->ps_timeout; + u8 dtim; + /*if(ieee->ps == IEEE80211_PS_DISABLED || + ieee->iw_mode != IW_MODE_INFRA || + ieee->state != IEEE80211_LINKED) + + return 0; + */ + dtim = ieee->current_network.dtim_data; + //printk("DTIM\n"); + if(!(dtim & IEEE80211_DTIM_VALID)) + return 0; + timeout = ieee->current_network.beacon_interval; //should we use ps_timeout value or beacon_interval + //printk("VALID\n"); + ieee->current_network.dtim_data = IEEE80211_DTIM_INVALID; + + if(dtim & ((IEEE80211_DTIM_UCAST | IEEE80211_DTIM_MBCAST)& ieee->ps)) + return 2; + + if(!time_after(jiffies, ieee->dev->trans_start + MSECS(timeout))) + return 0; + + if(!time_after(jiffies, ieee->last_rx_ps_time + MSECS(timeout))) + return 0; + + if((ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE ) && + (ieee->mgmt_queue_tail != ieee->mgmt_queue_head)) + return 0; + + if(time_l){ + *time_l = ieee->current_network.last_dtim_sta_time[0] + + (ieee->current_network.beacon_interval); + // * ieee->current_network.dtim_period) * 1000; + } + + if(time_h){ + *time_h = ieee->current_network.last_dtim_sta_time[1]; + if(time_l && *time_l < ieee->current_network.last_dtim_sta_time[0]) + *time_h += 1; + } + + return 1; + + +} + +inline void ieee80211_sta_ps(struct ieee80211_device *ieee) +{ + + u32 th,tl; + short sleep; + + unsigned long flags,flags2; + + spin_lock_irqsave(&ieee->lock, flags); + + if((ieee->ps == IEEE80211_PS_DISABLED || + ieee->iw_mode != IW_MODE_INFRA || + ieee->state != IEEE80211_LINKED)){ + + // #warning CHECK_LOCK_HERE + spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2); + + ieee80211_sta_wakeup(ieee, 1); + + spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2); + } + + sleep = ieee80211_sta_ps_sleep(ieee,&th, &tl); + /* 2 wake, 1 sleep, 0 do nothing */ + if(sleep == 0) + goto out; + + if(sleep == 1){ + + if(ieee->sta_sleep == 1) + ieee->enter_sleep_state(ieee->dev,th,tl); + + else if(ieee->sta_sleep == 0){ + // printk("send null 1\n"); + spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2); + + if(ieee->ps_is_queue_empty(ieee->dev)){ + + + ieee->sta_sleep = 2; + + ieee->ack_tx_to_ieee = 1; + + ieee80211_sta_ps_send_null_frame(ieee,1); + + ieee->ps_th = th; + ieee->ps_tl = tl; + } + spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2); + + } + + + }else if(sleep == 2){ +//#warning CHECK_LOCK_HERE + spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2); + + ieee80211_sta_wakeup(ieee,1); + + spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2); + } + +out: + spin_unlock_irqrestore(&ieee->lock, flags); + +} + +void ieee80211_sta_wakeup(struct ieee80211_device *ieee, short nl) +{ + if(ieee->sta_sleep == 0){ + if(nl){ + printk("Warning: driver is probably failing to report TX ps error\n"); + ieee->ack_tx_to_ieee = 1; + ieee80211_sta_ps_send_null_frame(ieee, 0); + } + return; + + } + + if(ieee->sta_sleep == 1) + ieee->sta_wake_up(ieee->dev); + + ieee->sta_sleep = 0; + + if(nl){ + ieee->ack_tx_to_ieee = 1; + ieee80211_sta_ps_send_null_frame(ieee, 0); + } +} + +void ieee80211_ps_tx_ack(struct ieee80211_device *ieee, short success) +{ + unsigned long flags,flags2; + + spin_lock_irqsave(&ieee->lock, flags); + + if(ieee->sta_sleep == 2){ + /* Null frame with PS bit set */ + if(success){ + ieee->sta_sleep = 1; + ieee->enter_sleep_state(ieee->dev,ieee->ps_th,ieee->ps_tl); + } + /* if the card report not success we can't be sure the AP + * has not RXed so we can't assume the AP believe us awake + */ + } + /* 21112005 - tx again null without PS bit if lost */ + else { + + if((ieee->sta_sleep == 0) && !success){ + spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2); + ieee80211_sta_ps_send_null_frame(ieee, 0); + spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2); + } + } + spin_unlock_irqrestore(&ieee->lock, flags); +} +void ieee80211_process_action(struct ieee80211_device* ieee, struct sk_buff* skb) +{ + struct ieee80211_hdr* header = (struct ieee80211_hdr*)skb->data; + u8* act = ieee80211_get_payload(header); + u8 tmp = 0; +// IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA|IEEE80211_DL_BA, skb->data, skb->len); + if (act == NULL) + { + IEEE80211_DEBUG(IEEE80211_DL_ERR, "error to get payload of action frame\n"); + return; + } + tmp = *act; + act ++; + switch (tmp) + { + case ACT_CAT_BA: + if (*act == ACT_ADDBAREQ) + ieee80211_rx_ADDBAReq(ieee, skb); + else if (*act == ACT_ADDBARSP) + ieee80211_rx_ADDBARsp(ieee, skb); + else if (*act == ACT_DELBA) + ieee80211_rx_DELBA(ieee, skb); + break; + default: +// if (net_ratelimit()) +// IEEE80211_DEBUG(IEEE80211_DL_BA, "unknown action frame(%d)\n", tmp); + break; + } + return; + +} +inline int +ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb, + struct ieee80211_rx_stats *rx_stats, u16 type, + u16 stype) +{ + struct ieee80211_hdr_3addr *header = (struct ieee80211_hdr_3addr *) skb->data; + u16 errcode; + u8* challenge; + int chlen=0; + int aid; + struct ieee80211_assoc_response_frame *assoc_resp; +// struct ieee80211_info_element *info_element; + bool bSupportNmode = true, bHalfSupportNmode = false; //default support N mode, disable halfNmode + + if(!ieee->proto_started) + return 0; +#if 0 + printk("%d, %d, %d, %d\n", ieee->sta_sleep, ieee->ps, ieee->iw_mode, ieee->state); + if(ieee->sta_sleep || (ieee->ps != IEEE80211_PS_DISABLED && + ieee->iw_mode == IW_MODE_INFRA && + ieee->state == IEEE80211_LINKED)) + + tasklet_schedule(&ieee->ps_task); + + if(WLAN_FC_GET_STYPE(header->frame_ctl) != IEEE80211_STYPE_PROBE_RESP && + WLAN_FC_GET_STYPE(header->frame_ctl) != IEEE80211_STYPE_BEACON) + ieee->last_rx_ps_time = jiffies; +#endif + + switch (WLAN_FC_GET_STYPE(header->frame_ctl)) { + + case IEEE80211_STYPE_ASSOC_RESP: + case IEEE80211_STYPE_REASSOC_RESP: + + IEEE80211_DEBUG_MGMT("received [RE]ASSOCIATION RESPONSE (%d)\n", + WLAN_FC_GET_STYPE(header->frame_ctl)); + if ((ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) && + ieee->state == IEEE80211_ASSOCIATING_AUTHENTICATED && + ieee->iw_mode == IW_MODE_INFRA){ + struct ieee80211_network network_resp; + struct ieee80211_network *network = &network_resp; + + if (0 == (errcode=assoc_parse(ieee,skb, &aid))){ + ieee->state=IEEE80211_LINKED; + ieee->assoc_id = aid; + ieee->softmac_stats.rx_ass_ok++; + /* station support qos */ + /* Let the register setting defaultly with Legacy station */ + if(ieee->qos_support) { + assoc_resp = (struct ieee80211_assoc_response_frame*)skb->data; + memset(network, 0, sizeof(*network)); + if (ieee80211_parse_info_param(ieee,assoc_resp->info_element,\ + rx_stats->len - sizeof(*assoc_resp),\ + network,rx_stats)){ + return 1; + } + else + { //filling the PeerHTCap. //maybe not neccesary as we can get its info from current_network. + memcpy(ieee->pHTInfo->PeerHTCapBuf, network->bssht.bdHTCapBuf, network->bssht.bdHTCapLen); + memcpy(ieee->pHTInfo->PeerHTInfoBuf, network->bssht.bdHTInfoBuf, network->bssht.bdHTInfoLen); + } + if (ieee->handle_assoc_response != NULL) + ieee->handle_assoc_response(ieee->dev, (struct ieee80211_assoc_response_frame*)header, network); + } + ieee80211_associate_complete(ieee); + } else { + /* aid could not been allocated */ + ieee->softmac_stats.rx_ass_err++; + printk( + "Association response status code 0x%x\n", + errcode); + IEEE80211_DEBUG_MGMT( + "Association response status code 0x%x\n", + errcode); + if(ieee->AsocRetryCount < RT_ASOC_RETRY_LIMIT) { +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + queue_work(ieee->wq, &ieee->associate_procedure_wq); +#else + schedule_task(&ieee->associate_procedure_wq); +#endif + } else { + ieee80211_associate_abort(ieee); + } + } + } + break; + + case IEEE80211_STYPE_ASSOC_REQ: + case IEEE80211_STYPE_REASSOC_REQ: + + if ((ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) && + ieee->iw_mode == IW_MODE_MASTER) + + ieee80211_rx_assoc_rq(ieee, skb); + break; + + case IEEE80211_STYPE_AUTH: + + if (ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE){ + if (ieee->state == IEEE80211_ASSOCIATING_AUTHENTICATING && + ieee->iw_mode == IW_MODE_INFRA){ + + IEEE80211_DEBUG_MGMT("Received authentication response"); + + if (0 == (errcode=auth_parse(skb, &challenge, &chlen))){ + if(ieee->open_wep || !challenge){ + ieee->state = IEEE80211_ASSOCIATING_AUTHENTICATED; + ieee->softmac_stats.rx_auth_rs_ok++; + if(!(ieee->pHTInfo->IOTAction&HT_IOT_ACT_PURE_N_MODE)) + { + if (!ieee->GetNmodeSupportBySecCfg(ieee->dev)) + { + // WEP or TKIP encryption + if(IsHTHalfNmodeAPs(ieee)) + { + bSupportNmode = true; + bHalfSupportNmode = true; + } + else + { + bSupportNmode = false; + bHalfSupportNmode = false; + } + printk("==========>to link with AP using SEC(%d, %d)", bSupportNmode, bHalfSupportNmode); + } + } + /* Dummy wirless mode setting to avoid encryption issue */ + if(bSupportNmode) { + //N mode setting + ieee->SetWirelessMode(ieee->dev, \ + ieee->current_network.mode); + }else{ + //b/g mode setting + /*TODO*/ + ieee->SetWirelessMode(ieee->dev, IEEE_G); + } + + if (ieee->current_network.mode == IEEE_N_24G && bHalfSupportNmode == true) + { + printk("===============>entern half N mode\n"); + ieee->bHalfWirelessN24GMode = true; + } + else + ieee->bHalfWirelessN24GMode = false; + + ieee80211_associate_step2(ieee); + }else{ + ieee80211_auth_challenge(ieee, challenge, chlen); + } + }else{ + ieee->softmac_stats.rx_auth_rs_err++; + IEEE80211_DEBUG_MGMT("Authentication respose status code 0x%x",errcode); + + printk("Authentication respose status code 0x%x",errcode); + ieee80211_associate_abort(ieee); + } + + }else if (ieee->iw_mode == IW_MODE_MASTER){ + ieee80211_rx_auth_rq(ieee, skb); + } + } + break; + + case IEEE80211_STYPE_PROBE_REQ: + + if ((ieee->softmac_features & IEEE_SOFTMAC_PROBERS) && + ((ieee->iw_mode == IW_MODE_ADHOC || + ieee->iw_mode == IW_MODE_MASTER) && + ieee->state == IEEE80211_LINKED)){ + ieee80211_rx_probe_rq(ieee, skb); + } + break; + + case IEEE80211_STYPE_DISASSOC: + case IEEE80211_STYPE_DEAUTH: + /* FIXME for now repeat all the association procedure + * both for disassociation and deauthentication + */ + if ((ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) && + ieee->state == IEEE80211_LINKED && + ieee->iw_mode == IW_MODE_INFRA){ + printk("==========>received disassoc/deauth(%x) frame, reason code:%x\n",WLAN_FC_GET_STYPE(header->frame_ctl), ((struct ieee80211_disassoc*)skb->data)->reason); + ieee->state = IEEE80211_ASSOCIATING; + ieee->softmac_stats.reassoc++; + ieee->is_roaming = true; + ieee80211_disassociate(ieee); + // notify_wx_assoc_event(ieee); + //HTSetConnectBwMode(ieee, HT_CHANNEL_WIDTH_20, HT_EXTCHNL_OFFSET_NO_EXT); + RemovePeerTS(ieee, header->addr2); + if(ieee->LedControlHandler != NULL) + ieee->LedControlHandler(ieee->dev, LED_CTL_START_TO_LINK); //added by amy for LED 090318 +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + queue_work(ieee->wq, &ieee->associate_procedure_wq); +#else + schedule_task(&ieee->associate_procedure_wq); +#endif + } + break; + case IEEE80211_STYPE_MANAGE_ACT: + ieee80211_process_action(ieee,skb); + break; + default: + return -1; + break; + } + + //dev_kfree_skb_any(skb); + return 0; +} + +/* following are for a simplier TX queue management. + * Instead of using netif_[stop/wake]_queue the driver + * will uses these two function (plus a reset one), that + * will internally uses the kernel netif_* and takes + * care of the ieee802.11 fragmentation. + * So the driver receives a fragment per time and might + * call the stop function when it want without take care + * to have enought room to TX an entire packet. + * This might be useful if each fragment need it's own + * descriptor, thus just keep a total free memory > than + * the max fragmentation treshold is not enought.. If the + * ieee802.11 stack passed a TXB struct then you needed + * to keep N free descriptors where + * N = MAX_PACKET_SIZE / MIN_FRAG_TRESHOLD + * In this way you need just one and the 802.11 stack + * will take care of buffering fragments and pass them to + * to the driver later, when it wakes the queue. + */ +void ieee80211_softmac_xmit(struct ieee80211_txb *txb, struct ieee80211_device *ieee) +{ + + unsigned int queue_index = txb->queue_index; + unsigned long flags; + int i; + cb_desc *tcb_desc = NULL; + + spin_lock_irqsave(&ieee->lock,flags); + + /* called with 2nd parm 0, no tx mgmt lock required */ + ieee80211_sta_wakeup(ieee,0); + + /* update the tx status */ +// ieee->stats.tx_bytes += txb->payload_size; +// ieee->stats.tx_packets++; + tcb_desc = (cb_desc *)(txb->fragments[0]->cb + MAX_DEV_ADDR_SIZE); + if(tcb_desc->bMulticast) { + ieee->stats.multicast++; + } +#if 1 + /* if xmit available, just xmit it immediately, else just insert it to the wait queue */ + for(i = 0; i < txb->nr_frags; i++) { +#ifdef USB_TX_DRIVER_AGGREGATION_ENABLE + if ((skb_queue_len(&ieee->skb_drv_aggQ[queue_index]) != 0) || +#else + if ((skb_queue_len(&ieee->skb_waitQ[queue_index]) != 0) || +#endif + (!ieee->check_nic_enough_desc(ieee->dev,queue_index))||\ + (ieee->queue_stop)) { + /* insert the skb packet to the wait queue */ + /* as for the completion function, it does not need + * to check it any more. + * */ + //printk("error:no descriptor left@queue_index %d, %d, %d\n", queue_index, skb_queue_len(&ieee->skb_waitQ[queue_index]), ieee->check_nic_enough_desc(ieee->dev,queue_index)); + //ieee80211_stop_queue(ieee); +#ifdef USB_TX_DRIVER_AGGREGATION_ENABLE + skb_queue_tail(&ieee->skb_drv_aggQ[queue_index], txb->fragments[i]); +#else + skb_queue_tail(&ieee->skb_waitQ[queue_index], txb->fragments[i]); +#endif + }else{ + ieee->softmac_data_hard_start_xmit( + txb->fragments[i], + ieee->dev,ieee->rate); + //ieee->stats.tx_packets++; + //ieee->stats.tx_bytes += txb->fragments[i]->len; + //ieee->dev->trans_start = jiffies; + } + } +#endif + ieee80211_txb_free(txb); + +//exit: + spin_unlock_irqrestore(&ieee->lock,flags); + +} + +/* called with ieee->lock acquired */ +void ieee80211_resume_tx(struct ieee80211_device *ieee) +{ + int i; + for(i = ieee->tx_pending.frag; i < ieee->tx_pending.txb->nr_frags; i++) { + + if (ieee->queue_stop){ + ieee->tx_pending.frag = i; + return; + }else{ + + ieee->softmac_data_hard_start_xmit( + ieee->tx_pending.txb->fragments[i], + ieee->dev,ieee->rate); + //(i+1)tx_pending.txb->nr_frags); + ieee->stats.tx_packets++; + // ieee->dev->trans_start = jiffies; + } + } + + + ieee80211_txb_free(ieee->tx_pending.txb); + ieee->tx_pending.txb = NULL; +} + + +void ieee80211_reset_queue(struct ieee80211_device *ieee) +{ + unsigned long flags; + + spin_lock_irqsave(&ieee->lock,flags); + init_mgmt_queue(ieee); + if (ieee->tx_pending.txb){ + ieee80211_txb_free(ieee->tx_pending.txb); + ieee->tx_pending.txb = NULL; + } + ieee->queue_stop = 0; + spin_unlock_irqrestore(&ieee->lock,flags); + +} + +void ieee80211_wake_queue(struct ieee80211_device *ieee) +{ + + unsigned long flags; + struct sk_buff *skb; + struct ieee80211_hdr_3addr *header; + + spin_lock_irqsave(&ieee->lock,flags); + if (! ieee->queue_stop) goto exit; + + ieee->queue_stop = 0; + + if(ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE){ + while (!ieee->queue_stop && (skb = dequeue_mgmt(ieee))){ + + header = (struct ieee80211_hdr_3addr *) skb->data; + + header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4); + + if (ieee->seq_ctrl[0] == 0xFFF) + ieee->seq_ctrl[0] = 0; + else + ieee->seq_ctrl[0]++; + + ieee->softmac_data_hard_start_xmit(skb,ieee->dev,ieee->basic_rate); + //dev_kfree_skb_any(skb);//edit by thomas + } + } + if (!ieee->queue_stop && ieee->tx_pending.txb) + ieee80211_resume_tx(ieee); + + if (!ieee->queue_stop && netif_queue_stopped(ieee->dev)){ + ieee->softmac_stats.swtxawake++; + netif_wake_queue(ieee->dev); + } + +exit : + spin_unlock_irqrestore(&ieee->lock,flags); +} + + +void ieee80211_stop_queue(struct ieee80211_device *ieee) +{ + //unsigned long flags; + //spin_lock_irqsave(&ieee->lock,flags); + + if (! netif_queue_stopped(ieee->dev)){ + netif_stop_queue(ieee->dev); + ieee->softmac_stats.swtxstop++; + } + ieee->queue_stop = 1; + //spin_unlock_irqrestore(&ieee->lock,flags); + +} + + +inline void ieee80211_randomize_cell(struct ieee80211_device *ieee) +{ + + get_random_bytes(ieee->current_network.bssid, ETH_ALEN); + + /* an IBSS cell address must have the two less significant + * bits of the first byte = 2 + */ + ieee->current_network.bssid[0] &= ~0x01; + ieee->current_network.bssid[0] |= 0x02; +} + +/* called in user context only */ +void ieee80211_start_master_bss(struct ieee80211_device *ieee) +{ + ieee->assoc_id = 1; + + if (ieee->current_network.ssid_len == 0){ + strncpy(ieee->current_network.ssid, + IEEE80211_DEFAULT_TX_ESSID, + IW_ESSID_MAX_SIZE); + + ieee->current_network.ssid_len = strlen(IEEE80211_DEFAULT_TX_ESSID); + ieee->ssid_set = 1; + } + + memcpy(ieee->current_network.bssid, ieee->dev->dev_addr, ETH_ALEN); + + ieee->set_chan(ieee->dev, ieee->current_network.channel); + ieee->state = IEEE80211_LINKED; + ieee->link_change(ieee->dev); + notify_wx_assoc_event(ieee); + + if (ieee->data_hard_resume) + ieee->data_hard_resume(ieee->dev); + + netif_carrier_on(ieee->dev); +} + +void ieee80211_start_monitor_mode(struct ieee80211_device *ieee) +{ + if(ieee->raw_tx){ + + if (ieee->data_hard_resume) + ieee->data_hard_resume(ieee->dev); + + netif_carrier_on(ieee->dev); + } +} +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) +void ieee80211_start_ibss_wq(struct work_struct *work) +{ + + struct delayed_work *dwork = container_of(work, struct delayed_work, work); + struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, start_ibss_wq); +#else +void ieee80211_start_ibss_wq(struct ieee80211_device *ieee) +{ +#endif + /* iwconfig mode ad-hoc will schedule this and return + * on the other hand this will block further iwconfig SET + * operations because of the wx_sem hold. + * Anyway some most set operations set a flag to speed-up + * (abort) this wq (when syncro scanning) before sleeping + * on the semaphore + */ + if(!ieee->proto_started){ + printk("==========oh driver down return\n"); + return; + } + down(&ieee->wx_sem); + //FIXME:set back to 20M whenever HT for ibss is not ready. Otherwise,after being connected to 40M AP, it will still stay in 40M when set to ibss mode. WB 2009.02.04 + HTSetConnectBwMode(ieee, HT_CHANNEL_WIDTH_20, HT_EXTCHNL_OFFSET_NO_EXT); + + if (ieee->current_network.ssid_len == 0){ + strcpy(ieee->current_network.ssid,IEEE80211_DEFAULT_TX_ESSID); + ieee->current_network.ssid_len = strlen(IEEE80211_DEFAULT_TX_ESSID); + ieee->ssid_set = 1; + } + + /* check if we have this cell in our network list */ + ieee80211_softmac_check_all_nets(ieee); + + +#ifdef ENABLE_DOT11D //if creating an ad-hoc, set its channel to 10 temporarily--this is the requirement for ASUS, not 11D, so disable 11d. +// if((IS_DOT11D_ENABLE(ieee)) && (ieee->state == IEEE80211_NOLINK)) + if (ieee->state == IEEE80211_NOLINK) + ieee->current_network.channel = 6; +#endif + /* if not then the state is not linked. Maybe the user swithced to + * ad-hoc mode just after being in monitor mode, or just after + * being very few time in managed mode (so the card have had no + * time to scan all the chans..) or we have just run up the iface + * after setting ad-hoc mode. So we have to give another try.. + * Here, in ibss mode, should be safe to do this without extra care + * (in bss mode we had to make sure no-one tryed to associate when + * we had just checked the ieee->state and we was going to start the + * scan) beacause in ibss mode the ieee80211_new_net function, when + * finds a good net, just set the ieee->state to IEEE80211_LINKED, + * so, at worst, we waste a bit of time to initiate an unneeded syncro + * scan, that will stop at the first round because it sees the state + * associated. + */ + if (ieee->state == IEEE80211_NOLINK) + ieee80211_start_scan_syncro(ieee); + + /* the network definitively is not here.. create a new cell */ + if (ieee->state == IEEE80211_NOLINK){ + printk("creating new IBSS cell\n"); + if(!ieee->wap_set) + ieee80211_randomize_cell(ieee); + + if(ieee->modulation & IEEE80211_CCK_MODULATION){ + + ieee->current_network.rates_len = 4; + + ieee->current_network.rates[0] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB; + ieee->current_network.rates[1] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB; + ieee->current_network.rates[2] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_5MB; + ieee->current_network.rates[3] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_11MB; + + }else + ieee->current_network.rates_len = 0; + + if(ieee->modulation & IEEE80211_OFDM_MODULATION){ + ieee->current_network.rates_ex_len = 8; + + ieee->current_network.rates_ex[0] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_6MB; + ieee->current_network.rates_ex[1] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_9MB; + ieee->current_network.rates_ex[2] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_12MB; + ieee->current_network.rates_ex[3] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_18MB; + ieee->current_network.rates_ex[4] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_24MB; + ieee->current_network.rates_ex[5] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_36MB; + ieee->current_network.rates_ex[6] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_48MB; + ieee->current_network.rates_ex[7] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_54MB; + + ieee->rate = 108; + }else{ + ieee->current_network.rates_ex_len = 0; + ieee->rate = 22; + } + + // By default, WMM function will be disabled in IBSS mode + ieee->current_network.QoS_Enable = 0; + ieee->SetWirelessMode(ieee->dev, IEEE_G); + ieee->current_network.atim_window = 0; + ieee->current_network.capability = WLAN_CAPABILITY_IBSS; + if(ieee->short_slot) + ieee->current_network.capability |= WLAN_CAPABILITY_SHORT_SLOT; + + } + + ieee->state = IEEE80211_LINKED; + + ieee->set_chan(ieee->dev, ieee->current_network.channel); + ieee->link_change(ieee->dev); + if(ieee->LedControlHandler != NULL) + ieee->LedControlHandler(ieee->dev,LED_CTL_LINK); + notify_wx_assoc_event(ieee); + + ieee80211_start_send_beacons(ieee); + + if (ieee->data_hard_resume) + ieee->data_hard_resume(ieee->dev); + netif_carrier_on(ieee->dev); + + up(&ieee->wx_sem); +} + +inline void ieee80211_start_ibss(struct ieee80211_device *ieee) +{ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + queue_delayed_work(ieee->wq, &ieee->start_ibss_wq, 150); +#else + schedule_task(&ieee->start_ibss_wq); +#endif +} + +/* this is called only in user context, with wx_sem held */ +void ieee80211_start_bss(struct ieee80211_device *ieee) +{ + unsigned long flags; +#ifdef ENABLE_DOT11D + // + // Ref: 802.11d 11.1.3.3 + // STA shall not start a BSS unless properly formed Beacon frame including a Country IE. + // + if(IS_DOT11D_ENABLE(ieee) && !IS_COUNTRY_IE_VALID(ieee)) + { + if(! ieee->bGlobalDomain) + { + return; + } + } +#endif + /* check if we have already found the net we + * are interested in (if any). + * if not (we are disassociated and we are not + * in associating / authenticating phase) start the background scanning. + */ + ieee80211_softmac_check_all_nets(ieee); + + /* ensure no-one start an associating process (thus setting + * the ieee->state to ieee80211_ASSOCIATING) while we + * have just cheked it and we are going to enable scan. + * The ieee80211_new_net function is always called with + * lock held (from both ieee80211_softmac_check_all_nets and + * the rx path), so we cannot be in the middle of such function + */ + spin_lock_irqsave(&ieee->lock, flags); + + if (ieee->state == IEEE80211_NOLINK){ + ieee->actscanning = true; + ieee80211_start_scan(ieee); + } + spin_unlock_irqrestore(&ieee->lock, flags); +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) +void ieee80211_link_change_wq(struct work_struct *work) +{ + struct delayed_work *dwork = container_of(work, struct delayed_work, work); + struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, link_change_wq); +#else +void ieee80211_link_change_wq(struct ieee80211_device *ieee) +{ +#endif + ieee->link_change(ieee->dev); +} +/* called only in userspace context */ +void ieee80211_disassociate(struct ieee80211_device *ieee) +{ + + + netif_carrier_off(ieee->dev); + if (ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE) + ieee80211_reset_queue(ieee); + + if (ieee->data_hard_stop) + ieee->data_hard_stop(ieee->dev); +#ifdef ENABLE_DOT11D + if(IS_DOT11D_ENABLE(ieee)) + Dot11d_Reset(ieee); +#endif + ieee->state = IEEE80211_NOLINK; + ieee->is_set_key = false; + + //LZM for usb dev crash. + //ieee->link_change(ieee->dev); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + queue_delayed_work(ieee->wq, &ieee->link_change_wq, 0); +#else + schedule_task(&ieee->link_change_wq); +#endif + + //HTSetConnectBwMode(ieee, HT_CHANNEL_WIDTH_20, HT_EXTCHNL_OFFSET_NO_EXT); + notify_wx_assoc_event(ieee); + +} +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) +void ieee80211_associate_retry_wq(struct work_struct *work) +{ + struct delayed_work *dwork = container_of(work, struct delayed_work, work); + struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, associate_retry_wq); +#else +void ieee80211_associate_retry_wq(struct ieee80211_device *ieee) +{ +#endif + unsigned long flags; + + down(&ieee->wx_sem); + if(!ieee->proto_started) + goto exit; + + if(ieee->state != IEEE80211_ASSOCIATING_RETRY) + goto exit; + + /* until we do not set the state to IEEE80211_NOLINK + * there are no possibility to have someone else trying + * to start an association procdure (we get here with + * ieee->state = IEEE80211_ASSOCIATING). + * When we set the state to IEEE80211_NOLINK it is possible + * that the RX path run an attempt to associate, but + * both ieee80211_softmac_check_all_nets and the + * RX path works with ieee->lock held so there are no + * problems. If we are still disassociated then start a scan. + * the lock here is necessary to ensure no one try to start + * an association procedure when we have just checked the + * state and we are going to start the scan. + */ + ieee->beinretry = true; + ieee->state = IEEE80211_NOLINK; + + ieee80211_softmac_check_all_nets(ieee); + + spin_lock_irqsave(&ieee->lock, flags); + + if(ieee->state == IEEE80211_NOLINK) + { + ieee->actscanning = true; + ieee80211_start_scan(ieee); + } + spin_unlock_irqrestore(&ieee->lock, flags); + + ieee->beinretry = false; +exit: + up(&ieee->wx_sem); +} + +struct sk_buff *ieee80211_get_beacon_(struct ieee80211_device *ieee) +{ + u8 broadcast_addr[] = {0xff,0xff,0xff,0xff,0xff,0xff}; + + struct sk_buff *skb; + struct ieee80211_probe_response *b; + + skb = ieee80211_probe_resp(ieee, broadcast_addr); + + if (!skb) + return NULL; + + b = (struct ieee80211_probe_response *) skb->data; + b->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_BEACON); + + return skb; + +} + +struct sk_buff *ieee80211_get_beacon(struct ieee80211_device *ieee) +{ + struct sk_buff *skb; + struct ieee80211_probe_response *b; + + skb = ieee80211_get_beacon_(ieee); + if(!skb) + return NULL; + + b = (struct ieee80211_probe_response *) skb->data; + b->header.seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4); + + if (ieee->seq_ctrl[0] == 0xFFF) + ieee->seq_ctrl[0] = 0; + else + ieee->seq_ctrl[0]++; + + return skb; +} + +void ieee80211_softmac_stop_protocol(struct ieee80211_device *ieee) +{ + ieee->sync_scan_hurryup = 1; + down(&ieee->wx_sem); + ieee80211_stop_protocol(ieee); + up(&ieee->wx_sem); +} + + +void ieee80211_stop_protocol(struct ieee80211_device *ieee) +{ + if (!ieee->proto_started) + return; + + ieee->proto_started = 0; + + ieee80211_stop_send_beacons(ieee); + del_timer_sync(&ieee->associate_timer); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + cancel_delayed_work(&ieee->associate_retry_wq); + cancel_delayed_work(&ieee->start_ibss_wq); + cancel_delayed_work(&ieee->link_change_wq); +#endif + ieee80211_stop_scan(ieee); + + ieee80211_disassociate(ieee); + RemoveAllTS(ieee); //added as we disconnect from the previous BSS, Remove all TS +} + +void ieee80211_softmac_start_protocol(struct ieee80211_device *ieee) +{ + ieee->sync_scan_hurryup = 0; + down(&ieee->wx_sem); + ieee80211_start_protocol(ieee); + up(&ieee->wx_sem); +} + +void ieee80211_start_protocol(struct ieee80211_device *ieee) +{ + short ch = 0; + int i = 0; + if (ieee->proto_started) + return; + + ieee->proto_started = 1; + + if (ieee->current_network.channel == 0){ + do{ + ch++; + if (ch > MAX_CHANNEL_NUMBER) + return; /* no channel found */ +#ifdef ENABLE_DOT11D + }while(!GET_DOT11D_INFO(ieee)->channel_map[ch]); +#else + }while(!ieee->channel_map[ch]); +#endif + ieee->current_network.channel = ch; + } + + if (ieee->current_network.beacon_interval == 0) + ieee->current_network.beacon_interval = 100; +// printk("===>%s(), chan:%d\n", __FUNCTION__, ieee->current_network.channel); +// ieee->set_chan(ieee->dev,ieee->current_network.channel); + + for(i = 0; i < 17; i++) { + ieee->last_rxseq_num[i] = -1; + ieee->last_rxfrag_num[i] = -1; + ieee->last_packet_time[i] = 0; + } + + ieee->init_wmmparam_flag = 0;//reinitialize AC_xx_PARAM registers. + + + /* if the user set the MAC of the ad-hoc cell and then + * switch to managed mode, shall we make sure that association + * attempts does not fail just because the user provide the essid + * and the nic is still checking for the AP MAC ?? + */ + if (ieee->iw_mode == IW_MODE_INFRA) + ieee80211_start_bss(ieee); + + else if (ieee->iw_mode == IW_MODE_ADHOC) + ieee80211_start_ibss(ieee); + + else if (ieee->iw_mode == IW_MODE_MASTER) + ieee80211_start_master_bss(ieee); + + else if(ieee->iw_mode == IW_MODE_MONITOR) + ieee80211_start_monitor_mode(ieee); +} + + +#define DRV_NAME "Ieee80211" +void ieee80211_softmac_init(struct ieee80211_device *ieee) +{ + int i; + memset(&ieee->current_network, 0, sizeof(struct ieee80211_network)); + + ieee->state = IEEE80211_NOLINK; + ieee->sync_scan_hurryup = 0; + for(i = 0; i < 5; i++) { + ieee->seq_ctrl[i] = 0; + } +#ifdef ENABLE_DOT11D + ieee->pDot11dInfo = kmalloc(sizeof(RT_DOT11D_INFO), GFP_ATOMIC); + if (!ieee->pDot11dInfo) + IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't alloc memory for DOT11D\n"); + memset(ieee->pDot11dInfo, 0, sizeof(RT_DOT11D_INFO)); +#endif + //added for AP roaming + ieee->LinkDetectInfo.SlotNum = 2; + ieee->LinkDetectInfo.NumRecvBcnInPeriod=0; + ieee->LinkDetectInfo.NumRecvDataInPeriod=0; + + ieee->assoc_id = 0; + ieee->queue_stop = 0; + ieee->scanning = 0; + ieee->softmac_features = 0; //so IEEE2100-like driver are happy + ieee->wap_set = 0; + ieee->ssid_set = 0; + ieee->proto_started = 0; + ieee->basic_rate = IEEE80211_DEFAULT_BASIC_RATE; + ieee->rate = 22; + ieee->ps = IEEE80211_PS_DISABLED; + ieee->sta_sleep = 0; + ieee->Regdot11HTOperationalRateSet[0]= 0xff;//support MCS 0~7 + ieee->Regdot11HTOperationalRateSet[1]= 0xff;//support MCS 8~15 + ieee->Regdot11HTOperationalRateSet[4]= 0x01; + //added by amy + ieee->actscanning = false; + ieee->beinretry = false; + ieee->is_set_key = false; + init_mgmt_queue(ieee); + + ieee->sta_edca_param[0] = 0x0000A403; + ieee->sta_edca_param[1] = 0x0000A427; + ieee->sta_edca_param[2] = 0x005E4342; + ieee->sta_edca_param[3] = 0x002F3262; + ieee->aggregation = true; + ieee->enable_rx_imm_BA = 1; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + init_timer(&ieee->scan_timer); + ieee->scan_timer.data = (unsigned long)ieee; + ieee->scan_timer.function = ieee80211_softmac_scan_cb; +#endif + ieee->tx_pending.txb = NULL; + + init_timer(&ieee->associate_timer); + ieee->associate_timer.data = (unsigned long)ieee; + ieee->associate_timer.function = ieee80211_associate_abort_cb; + + init_timer(&ieee->beacon_timer); + ieee->beacon_timer.data = (unsigned long) ieee; + ieee->beacon_timer.function = ieee80211_send_beacon_cb; + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) +#ifdef PF_SYNCTHREAD + ieee->wq = create_workqueue(DRV_NAME,0); +#else + ieee->wq = create_workqueue(DRV_NAME); +#endif +#endif + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + INIT_DELAYED_WORK(&ieee->link_change_wq,ieee80211_link_change_wq); + INIT_DELAYED_WORK(&ieee->start_ibss_wq,ieee80211_start_ibss_wq); + INIT_WORK(&ieee->associate_complete_wq, ieee80211_associate_complete_wq); + INIT_WORK(&ieee->associate_procedure_wq, ieee80211_associate_procedure_wq); + INIT_DELAYED_WORK(&ieee->softmac_scan_wq,ieee80211_softmac_scan_wq); + INIT_DELAYED_WORK(&ieee->associate_retry_wq, ieee80211_associate_retry_wq); + INIT_WORK(&ieee->wx_sync_scan_wq,ieee80211_wx_sync_scan_wq); + +#else + INIT_WORK(&ieee->link_change_wq,(void(*)(void*)) ieee80211_link_change_wq,ieee); + INIT_WORK(&ieee->start_ibss_wq,(void(*)(void*)) ieee80211_start_ibss_wq,ieee); + INIT_WORK(&ieee->associate_retry_wq,(void(*)(void*)) ieee80211_associate_retry_wq,ieee); + INIT_WORK(&ieee->associate_complete_wq,(void(*)(void*)) ieee80211_associate_complete_wq,ieee); + INIT_WORK(&ieee->associate_procedure_wq,(void(*)(void*)) ieee80211_associate_procedure_wq,ieee); + INIT_WORK(&ieee->softmac_scan_wq,(void(*)(void*)) ieee80211_softmac_scan_wq,ieee); + INIT_WORK(&ieee->wx_sync_scan_wq,(void(*)(void*)) ieee80211_wx_sync_scan_wq,ieee); +#endif + +#else + tq_init(&ieee->link_change_wq,(void(*)(void*)) ieee80211_link_change_wq,ieee); + tq_init(&ieee->start_ibss_wq,(void(*)(void*)) ieee80211_start_ibss_wq,ieee); + tq_init(&ieee->associate_retry_wq,(void(*)(void*)) ieee80211_associate_retry_wq,ieee); + tq_init(&ieee->associate_complete_wq,(void(*)(void*)) ieee80211_associate_complete_wq,ieee); + tq_init(&ieee->associate_procedure_wq,(void(*)(void*)) ieee80211_associate_procedure_wq,ieee); + tq_init(&ieee->softmac_scan_wq,(void(*)(void*)) ieee80211_softmac_scan_wq,ieee); + tq_init(&ieee->wx_sync_scan_wq,(void(*)(void*)) ieee80211_wx_sync_scan_wq,ieee); +#endif + sema_init(&ieee->wx_sem, 1); + sema_init(&ieee->scan_sem, 1); + + spin_lock_init(&ieee->mgmt_tx_lock); + spin_lock_init(&ieee->beacon_lock); + + tasklet_init(&ieee->ps_task, + (void(*)(unsigned long)) ieee80211_sta_ps, + (unsigned long)ieee); + +} + +void ieee80211_softmac_free(struct ieee80211_device *ieee) +{ + down(&ieee->wx_sem); +#ifdef ENABLE_DOT11D + if(NULL != ieee->pDot11dInfo) + { + kfree(ieee->pDot11dInfo); + ieee->pDot11dInfo = NULL; + } +#endif + del_timer_sync(&ieee->associate_timer); + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + cancel_delayed_work(&ieee->associate_retry_wq); + destroy_workqueue(ieee->wq); +#endif + + up(&ieee->wx_sem); +} + +/******************************************************** + * Start of WPA code. * + * this is stolen from the ipw2200 driver * + ********************************************************/ + + +static int ieee80211_wpa_enable(struct ieee80211_device *ieee, int value) +{ + /* This is called when wpa_supplicant loads and closes the driver + * interface. */ + printk("%s WPA\n",value ? "enabling" : "disabling"); + ieee->wpa_enabled = value; + memset(ieee->ap_mac_addr, 0, 6); //reset ap_mac_addr everytime it starts wpa. + return 0; +} + + +void ieee80211_wpa_assoc_frame(struct ieee80211_device *ieee, char *wpa_ie, int wpa_ie_len) +{ + /* make sure WPA is enabled */ + ieee80211_wpa_enable(ieee, 1); + + ieee80211_disassociate(ieee); +} + + +static int ieee80211_wpa_mlme(struct ieee80211_device *ieee, int command, int reason) +{ + + int ret = 0; + + switch (command) { + case IEEE_MLME_STA_DEAUTH: + // silently ignore + break; + + case IEEE_MLME_STA_DISASSOC: + ieee80211_disassociate(ieee); + break; + + default: + printk("Unknown MLME request: %d\n", command); + ret = -EOPNOTSUPP; + } + + return ret; +} + + +static int ieee80211_wpa_set_wpa_ie(struct ieee80211_device *ieee, + struct ieee_param *param, int plen) +{ + u8 *buf; + + if (param->u.wpa_ie.len > MAX_WPA_IE_LEN || + (param->u.wpa_ie.len && param->u.wpa_ie.data == NULL)) + return -EINVAL; + + if (param->u.wpa_ie.len) { + buf = kmalloc(param->u.wpa_ie.len, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + memcpy(buf, param->u.wpa_ie.data, param->u.wpa_ie.len); + kfree(ieee->wpa_ie); + ieee->wpa_ie = buf; + ieee->wpa_ie_len = param->u.wpa_ie.len; + } else { + kfree(ieee->wpa_ie); + ieee->wpa_ie = NULL; + ieee->wpa_ie_len = 0; + } + + ieee80211_wpa_assoc_frame(ieee, ieee->wpa_ie, ieee->wpa_ie_len); + return 0; +} + +#define AUTH_ALG_OPEN_SYSTEM 0x1 +#define AUTH_ALG_SHARED_KEY 0x2 +#define AUTH_ALG_LEAP 0x4 +static int ieee80211_wpa_set_auth_algs(struct ieee80211_device *ieee, int value) +{ + + struct ieee80211_security sec = { + .flags = SEC_AUTH_MODE, + }; + int ret = 0; + + if (value & AUTH_ALG_SHARED_KEY) { + sec.auth_mode = WLAN_AUTH_SHARED_KEY; + ieee->open_wep = 0; + ieee->auth_mode = 1; + } else if (value & AUTH_ALG_OPEN_SYSTEM){ + sec.auth_mode = WLAN_AUTH_OPEN; + ieee->open_wep = 1; + ieee->auth_mode = 0; + } + else if (value & AUTH_ALG_LEAP){ + sec.auth_mode = WLAN_AUTH_LEAP; + ieee->open_wep = 1; + ieee->auth_mode = 2; + } + + + if (ieee->set_security) + ieee->set_security(ieee->dev, &sec); + //else + // ret = -EOPNOTSUPP; + + return ret; +} + +static int ieee80211_wpa_set_param(struct ieee80211_device *ieee, u8 name, u32 value) +{ + int ret=0; + unsigned long flags; + + switch (name) { + case IEEE_PARAM_WPA_ENABLED: + ret = ieee80211_wpa_enable(ieee, value); + break; + + case IEEE_PARAM_TKIP_COUNTERMEASURES: + ieee->tkip_countermeasures=value; + break; + + case IEEE_PARAM_DROP_UNENCRYPTED: { + /* HACK: + * + * wpa_supplicant calls set_wpa_enabled when the driver + * is loaded and unloaded, regardless of if WPA is being + * used. No other calls are made which can be used to + * determine if encryption will be used or not prior to + * association being expected. If encryption is not being + * used, drop_unencrypted is set to false, else true -- we + * can use this to determine if the CAP_PRIVACY_ON bit should + * be set. + */ + struct ieee80211_security sec = { + .flags = SEC_ENABLED, + .enabled = value, + }; + ieee->drop_unencrypted = value; + /* We only change SEC_LEVEL for open mode. Others + * are set by ipw_wpa_set_encryption. + */ + if (!value) { + sec.flags |= SEC_LEVEL; + sec.level = SEC_LEVEL_0; + } + else { + sec.flags |= SEC_LEVEL; + sec.level = SEC_LEVEL_1; + } + if (ieee->set_security) + ieee->set_security(ieee->dev, &sec); + break; + } + + case IEEE_PARAM_PRIVACY_INVOKED: + ieee->privacy_invoked=value; + break; + + case IEEE_PARAM_AUTH_ALGS: + ret = ieee80211_wpa_set_auth_algs(ieee, value); + break; + + case IEEE_PARAM_IEEE_802_1X: + ieee->ieee802_1x=value; + break; + case IEEE_PARAM_WPAX_SELECT: + // added for WPA2 mixed mode + spin_lock_irqsave(&ieee->wpax_suitlist_lock,flags); + ieee->wpax_type_set = 1; + ieee->wpax_type_notify = value; + spin_unlock_irqrestore(&ieee->wpax_suitlist_lock,flags); + break; + + default: + printk("Unknown WPA param: %d\n",name); + ret = -EOPNOTSUPP; + } + + return ret; +} + +/* implementation borrowed from hostap driver */ + +static int ieee80211_wpa_set_encryption(struct ieee80211_device *ieee, + struct ieee_param *param, int param_len) +{ + int ret = 0; + + struct ieee80211_crypto_ops *ops; + struct ieee80211_crypt_data **crypt; + + struct ieee80211_security sec = { + .flags = 0, + }; + + param->u.crypt.err = 0; + param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0'; + + if (param_len != + (int) ((char *) param->u.crypt.key - (char *) param) + + param->u.crypt.key_len) { + printk("Len mismatch %d, %d\n", param_len, + param->u.crypt.key_len); + return -EINVAL; + } + if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && + param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && + param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) { + if (param->u.crypt.idx >= WEP_KEYS) + return -EINVAL; + crypt = &ieee->crypt[param->u.crypt.idx]; + } else { + return -EINVAL; + } + + if (strcmp(param->u.crypt.alg, "none") == 0) { + if (crypt) { + sec.enabled = 0; + // FIXME FIXME + //sec.encrypt = 0; + sec.level = SEC_LEVEL_0; + sec.flags |= SEC_ENABLED | SEC_LEVEL; + ieee80211_crypt_delayed_deinit(ieee, crypt); + } + goto done; + } + sec.enabled = 1; +// FIXME FIXME +// sec.encrypt = 1; + sec.flags |= SEC_ENABLED; + + /* IPW HW cannot build TKIP MIC, host decryption still needed. */ + if (!(ieee->host_encrypt || ieee->host_decrypt) && + strcmp(param->u.crypt.alg, "TKIP")) + goto skip_host_crypt; + + ops = ieee80211_get_crypto_ops(param->u.crypt.alg); + if (ops == NULL && strcmp(param->u.crypt.alg, "WEP") == 0) { + request_module("ieee80211_crypt_wep"); + ops = ieee80211_get_crypto_ops(param->u.crypt.alg); + //set WEP40 first, it will be modified according to WEP104 or WEP40 at other place + } else if (ops == NULL && strcmp(param->u.crypt.alg, "TKIP") == 0) { + request_module("ieee80211_crypt_tkip"); + ops = ieee80211_get_crypto_ops(param->u.crypt.alg); + } else if (ops == NULL && strcmp(param->u.crypt.alg, "CCMP") == 0) { + request_module("ieee80211_crypt_ccmp"); + ops = ieee80211_get_crypto_ops(param->u.crypt.alg); + } + if (ops == NULL) { + printk("unknown crypto alg '%s'\n", param->u.crypt.alg); + param->u.crypt.err = IEEE_CRYPT_ERR_UNKNOWN_ALG; + ret = -EINVAL; + goto done; + } + + if (*crypt == NULL || (*crypt)->ops != ops) { + struct ieee80211_crypt_data *new_crypt; + + ieee80211_crypt_delayed_deinit(ieee, crypt); + + new_crypt = (struct ieee80211_crypt_data *) + kmalloc(sizeof(*new_crypt), GFP_KERNEL); + if (new_crypt == NULL) { + ret = -ENOMEM; + goto done; + } + memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data)); + new_crypt->ops = ops; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) +#else + if (new_crypt->ops && try_inc_mod_count(new_crypt->ops->owner)) +#endif + new_crypt->priv = + new_crypt->ops->init(param->u.crypt.idx); + + if (new_crypt->priv == NULL) { + kfree(new_crypt); + param->u.crypt.err = IEEE_CRYPT_ERR_CRYPT_INIT_FAILED; + ret = -EINVAL; + goto done; + } + + *crypt = new_crypt; + } + + if (param->u.crypt.key_len > 0 && (*crypt)->ops->set_key && + (*crypt)->ops->set_key(param->u.crypt.key, + param->u.crypt.key_len, param->u.crypt.seq, + (*crypt)->priv) < 0) { + printk("key setting failed\n"); + param->u.crypt.err = IEEE_CRYPT_ERR_KEY_SET_FAILED; + ret = -EINVAL; + goto done; + } + + skip_host_crypt: + if (param->u.crypt.set_tx) { + ieee->tx_keyidx = param->u.crypt.idx; + sec.active_key = param->u.crypt.idx; + sec.flags |= SEC_ACTIVE_KEY; + } else + sec.flags &= ~SEC_ACTIVE_KEY; + + if (param->u.crypt.alg != NULL) { + memcpy(sec.keys[param->u.crypt.idx], + param->u.crypt.key, + param->u.crypt.key_len); + sec.key_sizes[param->u.crypt.idx] = param->u.crypt.key_len; + sec.flags |= (1 << param->u.crypt.idx); + + if (strcmp(param->u.crypt.alg, "WEP") == 0) { + sec.flags |= SEC_LEVEL; + sec.level = SEC_LEVEL_1; + } else if (strcmp(param->u.crypt.alg, "TKIP") == 0) { + sec.flags |= SEC_LEVEL; + sec.level = SEC_LEVEL_2; + } else if (strcmp(param->u.crypt.alg, "CCMP") == 0) { + sec.flags |= SEC_LEVEL; + sec.level = SEC_LEVEL_3; + } + } + done: + if (ieee->set_security) + ieee->set_security(ieee->dev, &sec); + + /* Do not reset port if card is in Managed mode since resetting will + * generate new IEEE 802.11 authentication which may end up in looping + * with IEEE 802.1X. If your hardware requires a reset after WEP + * configuration (for example... Prism2), implement the reset_port in + * the callbacks structures used to initialize the 802.11 stack. */ + if (ieee->reset_on_keychange && + ieee->iw_mode != IW_MODE_INFRA && + ieee->reset_port && + ieee->reset_port(ieee->dev)) { + printk("reset_port failed\n"); + param->u.crypt.err = IEEE_CRYPT_ERR_CARD_CONF_FAILED; + return -EINVAL; + } + + return ret; +} + +inline struct sk_buff *ieee80211_disassociate_skb( + struct ieee80211_network *beacon, + struct ieee80211_device *ieee, + u8 asRsn) +{ + struct sk_buff *skb; + struct ieee80211_disassoc *disass; + + skb = dev_alloc_skb(sizeof(struct ieee80211_disassoc)); + if (!skb) + return NULL; + + disass = (struct ieee80211_disassoc *) skb_put(skb,sizeof(struct ieee80211_disassoc)); + disass->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_DISASSOC); + disass->header.duration_id = 0; + + memcpy(disass->header.addr1, beacon->bssid, ETH_ALEN); + memcpy(disass->header.addr2, ieee->dev->dev_addr, ETH_ALEN); + memcpy(disass->header.addr3, beacon->bssid, ETH_ALEN); + + disass->reason = asRsn; + return skb; +} + + +void +SendDisassociation( + struct ieee80211_device *ieee, + u8* asSta, + u8 asRsn +) +{ + struct ieee80211_network *beacon = &ieee->current_network; + struct sk_buff *skb; + skb = ieee80211_disassociate_skb(beacon,ieee,asRsn); + if (skb){ + softmac_mgmt_xmit(skb, ieee); + //dev_kfree_skb_any(skb);//edit by thomas + } +} + +int ieee80211_wpa_supplicant_ioctl(struct ieee80211_device *ieee, struct iw_point *p) +{ + struct ieee_param *param; + int ret=0; + + down(&ieee->wx_sem); + //IEEE_DEBUG_INFO("wpa_supplicant: len=%d\n", p->length); + + if (p->length < sizeof(struct ieee_param) || !p->pointer){ + ret = -EINVAL; + goto out; + } + + param = (struct ieee_param *)kmalloc(p->length, GFP_KERNEL); + if (param == NULL){ + ret = -ENOMEM; + goto out; + } + if (copy_from_user(param, p->pointer, p->length)) { + kfree(param); + ret = -EFAULT; + goto out; + } + + switch (param->cmd) { + + case IEEE_CMD_SET_WPA_PARAM: + ret = ieee80211_wpa_set_param(ieee, param->u.wpa_param.name, + param->u.wpa_param.value); + break; + + case IEEE_CMD_SET_WPA_IE: + ret = ieee80211_wpa_set_wpa_ie(ieee, param, p->length); + break; + + case IEEE_CMD_SET_ENCRYPTION: + ret = ieee80211_wpa_set_encryption(ieee, param, p->length); + break; + + case IEEE_CMD_MLME: + ret = ieee80211_wpa_mlme(ieee, param->u.mlme.command, + param->u.mlme.reason_code); + break; + + default: + printk("Unknown WPA supplicant request: %d\n",param->cmd); + ret = -EOPNOTSUPP; + break; + } + + if (ret == 0 && copy_to_user(p->pointer, param, p->length)) + ret = -EFAULT; + + kfree(param); +out: + up(&ieee->wx_sem); + + return ret; +} + +void notify_wx_assoc_event(struct ieee80211_device *ieee) +{ + union iwreq_data wrqu; + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + if (ieee->state == IEEE80211_LINKED) + memcpy(wrqu.ap_addr.sa_data, ieee->current_network.bssid, ETH_ALEN); + else + memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); + wireless_send_event(ieee->dev, SIOCGIWAP, &wrqu, NULL); +} + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) +EXPORT_SYMBOL(ieee80211_get_beacon); +EXPORT_SYMBOL(ieee80211_wake_queue); +EXPORT_SYMBOL(ieee80211_stop_queue); +EXPORT_SYMBOL(ieee80211_reset_queue); +EXPORT_SYMBOL(ieee80211_softmac_stop_protocol); +EXPORT_SYMBOL(ieee80211_softmac_start_protocol); +EXPORT_SYMBOL(ieee80211_is_shortslot); +EXPORT_SYMBOL(ieee80211_is_54g); +EXPORT_SYMBOL(ieee80211_wpa_supplicant_ioctl); +EXPORT_SYMBOL(ieee80211_ps_tx_ack); +EXPORT_SYMBOL(ieee80211_softmac_xmit); +EXPORT_SYMBOL(ieee80211_stop_send_beacons); +EXPORT_SYMBOL(notify_wx_assoc_event); +EXPORT_SYMBOL(SendDisassociation); +EXPORT_SYMBOL(ieee80211_disassociate); +EXPORT_SYMBOL(ieee80211_start_send_beacons); +EXPORT_SYMBOL(ieee80211_stop_scan); +EXPORT_SYMBOL(ieee80211_send_probe_requests); +EXPORT_SYMBOL(ieee80211_softmac_scan_syncro); +EXPORT_SYMBOL(ieee80211_start_scan_syncro); +#else +EXPORT_SYMBOL_NOVERS(ieee80211_get_beacon); +EXPORT_SYMBOL_NOVERS(ieee80211_wake_queue); +EXPORT_SYMBOL_NOVERS(ieee80211_stop_queue); +EXPORT_SYMBOL_NOVERS(ieee80211_reset_queue); +EXPORT_SYMBOL_NOVERS(ieee80211_softmac_stop_protocol); +EXPORT_SYMBOL_NOVERS(ieee80211_softmac_start_protocol); +EXPORT_SYMBOL_NOVERS(ieee80211_is_shortslot); +EXPORT_SYMBOL_NOVERS(ieee80211_is_54g); +EXPORT_SYMBOL_NOVERS(ieee80211_wpa_supplicant_ioctl); +EXPORT_SYMBOL_NOVERS(ieee80211_ps_tx_ack); +EXPORT_SYMBOL_NOVERS(ieee80211_softmac_xmit); +EXPORT_SYMBOL_NOVERS(ieee80211_stop_send_beacons); +EXPORT_SYMBOL_NOVERS(notify_wx_assoc_event); +EXPORT_SYMBOL_NOVERS(SendDisassociation); +EXPORT_SYMBOL_NOVERS(ieee80211_disassociate); +EXPORT_SYMBOL_NOVERS(ieee80211_start_send_beacons); +EXPORT_SYMBOL_NOVERS(ieee80211_stop_scan); +EXPORT_SYMBOL_NOVERS(ieee80211_send_probe_requests); +EXPORT_SYMBOL_NOVERS(ieee80211_softmac_scan_syncro); +EXPORT_SYMBOL_NOVERS(ieee80211_start_scan_syncro); +#endif +//EXPORT_SYMBOL(ieee80211_sta_ps_send_null_frame); diff --git a/drivers/staging/rtl8192su/ieee80211/ieee80211_softmac_wx.c b/drivers/staging/rtl8192su/ieee80211/ieee80211_softmac_wx.c new file mode 100644 index 000000000000..1f50c46dcb90 --- /dev/null +++ b/drivers/staging/rtl8192su/ieee80211/ieee80211_softmac_wx.c @@ -0,0 +1,711 @@ +/* IEEE 802.11 SoftMAC layer + * Copyright (c) 2005 Andrea Merello + * + * Mostly extracted from the rtl8180-sa2400 driver for the + * in-kernel generic ieee802.11 stack. + * + * Some pieces of code might be stolen from ipw2100 driver + * copyright of who own it's copyright ;-) + * + * PS wx handler mostly stolen from hostap, copyright who + * own it's copyright ;-) + * + * released under the GPL + */ + + +#include "ieee80211.h" +#ifdef ENABLE_DOT11D +#include "dot11d.h" +#endif +/* FIXME: add A freqs */ + +const long ieee80211_wlan_frequencies[] = { + 2412, 2417, 2422, 2427, + 2432, 2437, 2442, 2447, + 2452, 2457, 2462, 2467, + 2472, 2484 +}; + + +int ieee80211_wx_set_freq(struct ieee80211_device *ieee, struct iw_request_info *a, + union iwreq_data *wrqu, char *b) +{ + int ret; + struct iw_freq *fwrq = & wrqu->freq; + + down(&ieee->wx_sem); + + if(ieee->iw_mode == IW_MODE_INFRA){ + ret = -EOPNOTSUPP; + goto out; + } + + /* if setting by freq convert to channel */ + if (fwrq->e == 1) { + if ((fwrq->m >= (int) 2.412e8 && + fwrq->m <= (int) 2.487e8)) { + int f = fwrq->m / 100000; + int c = 0; + + while ((c < 14) && (f != ieee80211_wlan_frequencies[c])) + c++; + + /* hack to fall through */ + fwrq->e = 0; + fwrq->m = c + 1; + } + } + + if (fwrq->e > 0 || fwrq->m > 14 || fwrq->m < 1 ){ + ret = -EOPNOTSUPP; + goto out; + + }else { /* Set the channel */ + +#ifdef ENABLE_DOT11D + if (!(GET_DOT11D_INFO(ieee)->channel_map)[fwrq->m]) { + ret = -EINVAL; + goto out; + } +#endif + ieee->current_network.channel = fwrq->m; + ieee->set_chan(ieee->dev, ieee->current_network.channel); + + if(ieee->iw_mode == IW_MODE_ADHOC || ieee->iw_mode == IW_MODE_MASTER) + if(ieee->state == IEEE80211_LINKED){ + + ieee80211_stop_send_beacons(ieee); + ieee80211_start_send_beacons(ieee); + } + } + + ret = 0; +out: + up(&ieee->wx_sem); + return ret; +} + + +int ieee80211_wx_get_freq(struct ieee80211_device *ieee, + struct iw_request_info *a, + union iwreq_data *wrqu, char *b) +{ + struct iw_freq *fwrq = & wrqu->freq; + + if (ieee->current_network.channel == 0) + return -1; + //NM 0.7.0 will not accept channel any more. + fwrq->m = ieee80211_wlan_frequencies[ieee->current_network.channel-1] * 100000; + fwrq->e = 1; +// fwrq->m = ieee->current_network.channel; +// fwrq->e = 0; + + return 0; +} + +int ieee80211_wx_get_wap(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + unsigned long flags; + + wrqu->ap_addr.sa_family = ARPHRD_ETHER; + + if (ieee->iw_mode == IW_MODE_MONITOR) + return -1; + + /* We want avoid to give to the user inconsistent infos*/ + spin_lock_irqsave(&ieee->lock, flags); + + if (ieee->state != IEEE80211_LINKED && + ieee->state != IEEE80211_LINKED_SCANNING && + ieee->wap_set == 0) + + memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN); + else + memcpy(wrqu->ap_addr.sa_data, + ieee->current_network.bssid, ETH_ALEN); + + spin_unlock_irqrestore(&ieee->lock, flags); + + return 0; +} + + +int ieee80211_wx_set_wap(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *awrq, + char *extra) +{ + + int ret = 0; + u8 zero[] = {0,0,0,0,0,0}; + unsigned long flags; + + short ifup = ieee->proto_started;//dev->flags & IFF_UP; + struct sockaddr *temp = (struct sockaddr *)awrq; + + ieee->sync_scan_hurryup = 1; + + down(&ieee->wx_sem); + /* use ifconfig hw ether */ + if (ieee->iw_mode == IW_MODE_MASTER){ + ret = -1; + goto out; + } + + if (temp->sa_family != ARPHRD_ETHER){ + ret = -EINVAL; + goto out; + } + + if (ifup) + ieee80211_stop_protocol(ieee); + + /* just to avoid to give inconsistent infos in the + * get wx method. not really needed otherwise + */ + spin_lock_irqsave(&ieee->lock, flags); + + memcpy(ieee->current_network.bssid, temp->sa_data, ETH_ALEN); + ieee->wap_set = memcmp(temp->sa_data, zero,ETH_ALEN)!=0; + + spin_unlock_irqrestore(&ieee->lock, flags); + + if (ifup) + ieee80211_start_protocol(ieee); +out: + up(&ieee->wx_sem); + return ret; +} + + int ieee80211_wx_get_essid(struct ieee80211_device *ieee, struct iw_request_info *a,union iwreq_data *wrqu,char *b) +{ + int len,ret = 0; + unsigned long flags; + + if (ieee->iw_mode == IW_MODE_MONITOR) + return -1; + + /* We want avoid to give to the user inconsistent infos*/ + spin_lock_irqsave(&ieee->lock, flags); + + if (ieee->current_network.ssid[0] == '\0' || + ieee->current_network.ssid_len == 0){ + ret = -1; + goto out; + } + + if (ieee->state != IEEE80211_LINKED && + ieee->state != IEEE80211_LINKED_SCANNING && + ieee->ssid_set == 0){ + ret = -1; + goto out; + } + len = ieee->current_network.ssid_len; + wrqu->essid.length = len; + strncpy(b,ieee->current_network.ssid,len); + wrqu->essid.flags = 1; + +out: + spin_unlock_irqrestore(&ieee->lock, flags); + + return ret; + +} + +int ieee80211_wx_set_rate(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + + u32 target_rate = wrqu->bitrate.value; + + ieee->rate = target_rate/100000; + //FIXME: we might want to limit rate also in management protocols. + return 0; +} + + + +int ieee80211_wx_get_rate(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + u32 tmp_rate = 0; +#ifdef RTL8192SU + //printk("===>mode:%d, halfNmode:%d\n", ieee->mode, ieee->bHalfWirelessN24GMode); + if (ieee->mode & (IEEE_A | IEEE_B | IEEE_G)) + tmp_rate = ieee->rate; + else if (ieee->mode & IEEE_N_5G) + tmp_rate = 580; + else if (ieee->mode & IEEE_N_24G) + { + if (ieee->GetHalfNmodeSupportByAPsHandler(ieee->dev)) + tmp_rate = HTHalfMcsToDataRate(ieee, 15); + else + tmp_rate = HTMcsToDataRate(ieee, 15); + } +#else + tmp_rate = TxCountToDataRate(ieee, ieee->softmac_stats.CurrentShowTxate); + +#endif + wrqu->bitrate.value = tmp_rate * 500000; + + return 0; +} + + +int ieee80211_wx_set_rts(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + if (wrqu->rts.disabled || !wrqu->rts.fixed) + ieee->rts = DEFAULT_RTS_THRESHOLD; + else + { + if (wrqu->rts.value < MIN_RTS_THRESHOLD || + wrqu->rts.value > MAX_RTS_THRESHOLD) + return -EINVAL; + ieee->rts = wrqu->rts.value; + } + return 0; +} + +int ieee80211_wx_get_rts(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + wrqu->rts.value = ieee->rts; + wrqu->rts.fixed = 0; /* no auto select */ + wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD); + return 0; +} +int ieee80211_wx_set_mode(struct ieee80211_device *ieee, struct iw_request_info *a, + union iwreq_data *wrqu, char *b) +{ + + ieee->sync_scan_hurryup = 1; + + down(&ieee->wx_sem); + + if (wrqu->mode == ieee->iw_mode) + goto out; + + if (wrqu->mode == IW_MODE_MONITOR){ + + ieee->dev->type = ARPHRD_IEEE80211; + }else{ + ieee->dev->type = ARPHRD_ETHER; + } + + if (!ieee->proto_started){ + ieee->iw_mode = wrqu->mode; + }else{ + ieee80211_stop_protocol(ieee); + ieee->iw_mode = wrqu->mode; + ieee80211_start_protocol(ieee); + } + +out: + up(&ieee->wx_sem); + return 0; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) +void ieee80211_wx_sync_scan_wq(struct work_struct *work) +{ + struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, wx_sync_scan_wq); +#else +void ieee80211_wx_sync_scan_wq(struct ieee80211_device *ieee) +{ +#endif + short chan; + HT_EXTCHNL_OFFSET chan_offset=0; + HT_CHANNEL_WIDTH bandwidth=0; + int b40M = 0; + static int count = 0; + chan = ieee->current_network.channel; + netif_carrier_off(ieee->dev); + + if (ieee->data_hard_stop) + ieee->data_hard_stop(ieee->dev); + + ieee80211_stop_send_beacons(ieee); + + ieee->state = IEEE80211_LINKED_SCANNING; + ieee->link_change(ieee->dev); +#ifndef RTL8192SE + ieee->InitialGainHandler(ieee->dev,IG_Backup); +#endif +#if(RTL8192S_DISABLE_FW_DM == 0) + if (ieee->SetFwCmdHandler) + { + ieee->SetFwCmdHandler(ieee->dev, FW_CMD_DIG_HALT); + ieee->SetFwCmdHandler(ieee->dev, FW_CMD_HIGH_PWR_DISABLE); + } +#endif + if (ieee->pHTInfo->bCurrentHTSupport && ieee->pHTInfo->bEnableHT && ieee->pHTInfo->bCurBW40MHz) { + b40M = 1; + chan_offset = ieee->pHTInfo->CurSTAExtChnlOffset; + bandwidth = (HT_CHANNEL_WIDTH)ieee->pHTInfo->bCurBW40MHz; + printk("Scan in 40M, force to 20M first:%d, %d\n", chan_offset, bandwidth); + ieee->SetBWModeHandler(ieee->dev, HT_CHANNEL_WIDTH_20, HT_EXTCHNL_OFFSET_NO_EXT); + } + ieee80211_start_scan_syncro(ieee); + if (b40M) { + printk("Scan in 20M, back to 40M\n"); + if (chan_offset == HT_EXTCHNL_OFFSET_UPPER) + ieee->set_chan(ieee->dev, chan + 2); + else if (chan_offset == HT_EXTCHNL_OFFSET_LOWER) + ieee->set_chan(ieee->dev, chan - 2); + else + ieee->set_chan(ieee->dev, chan); + ieee->SetBWModeHandler(ieee->dev, bandwidth, chan_offset); + } else { + ieee->set_chan(ieee->dev, chan); + } + +#ifndef RTL8192SE + ieee->InitialGainHandler(ieee->dev,IG_Restore); +#endif +#if(RTL8192S_DISABLE_FW_DM == 0) + if (ieee->SetFwCmdHandler) + { + ieee->SetFwCmdHandler(ieee->dev, FW_CMD_DIG_RESUME); + ieee->SetFwCmdHandler(ieee->dev, FW_CMD_HIGH_PWR_ENABLE); + } +#endif + ieee->state = IEEE80211_LINKED; + ieee->link_change(ieee->dev); + // To prevent the immediately calling watch_dog after scan. + if(ieee->LinkDetectInfo.NumRecvBcnInPeriod==0||ieee->LinkDetectInfo.NumRecvDataInPeriod==0 ) + { + ieee->LinkDetectInfo.NumRecvBcnInPeriod = 1; + ieee->LinkDetectInfo.NumRecvDataInPeriod= 1; + } + if (ieee->data_hard_resume) + ieee->data_hard_resume(ieee->dev); + + if(ieee->iw_mode == IW_MODE_ADHOC || ieee->iw_mode == IW_MODE_MASTER) + ieee80211_start_send_beacons(ieee); + + netif_carrier_on(ieee->dev); + count = 0; + up(&ieee->wx_sem); + +} + +int ieee80211_wx_set_scan(struct ieee80211_device *ieee, struct iw_request_info *a, + union iwreq_data *wrqu, char *b) +{ + int ret = 0; + + down(&ieee->wx_sem); + + if (ieee->iw_mode == IW_MODE_MONITOR || !(ieee->proto_started)){ + ret = -1; + goto out; + } + + if ( ieee->state == IEEE80211_LINKED){ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + queue_work(ieee->wq, &ieee->wx_sync_scan_wq); +#else + schedule_task(&ieee->wx_sync_scan_wq); +#endif + /* intentionally forget to up sem */ + return 0; + } + +out: + up(&ieee->wx_sem); + return ret; +} + +int ieee80211_wx_set_essid(struct ieee80211_device *ieee, + struct iw_request_info *a, + union iwreq_data *wrqu, char *extra) +{ + + int ret=0,len; + short proto_started; + unsigned long flags; + + ieee->sync_scan_hurryup = 1; + down(&ieee->wx_sem); + + proto_started = ieee->proto_started; + + if (wrqu->essid.length > IW_ESSID_MAX_SIZE){ + ret= -E2BIG; + goto out; + } + + if (ieee->iw_mode == IW_MODE_MONITOR){ + ret= -1; + goto out; + } + + if(proto_started) + ieee80211_stop_protocol(ieee); + + + /* this is just to be sure that the GET wx callback + * has consisten infos. not needed otherwise + */ + spin_lock_irqsave(&ieee->lock, flags); + + if (wrqu->essid.flags && wrqu->essid.length) { + //first flush current network.ssid + len = ((wrqu->essid.length-1) < IW_ESSID_MAX_SIZE) ? (wrqu->essid.length-1) : IW_ESSID_MAX_SIZE; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + strncpy(ieee->current_network.ssid, extra, len); + ieee->current_network.ssid_len = len; +#if 0 + { + int i; + for (i=0; icurrent_network.ssid, extra, len+1); + ieee->current_network.ssid_len = len+1; +#if 0 + { + int i; + for (i=0; issid_set = 1; + } + else{ + ieee->ssid_set = 0; + ieee->current_network.ssid[0] = '\0'; + ieee->current_network.ssid_len = 0; + } + spin_unlock_irqrestore(&ieee->lock, flags); + + if (proto_started) + ieee80211_start_protocol(ieee); +out: + up(&ieee->wx_sem); + return ret; +} + + int ieee80211_wx_get_mode(struct ieee80211_device *ieee, struct iw_request_info *a, + union iwreq_data *wrqu, char *b) +{ + + wrqu->mode = ieee->iw_mode; + return 0; +} + + int ieee80211_wx_set_rawtx(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + + int *parms = (int *)extra; + int enable = (parms[0] > 0); + short prev = ieee->raw_tx; + + down(&ieee->wx_sem); + + if(enable) + ieee->raw_tx = 1; + else + ieee->raw_tx = 0; + + printk(KERN_INFO"raw TX is %s\n", + ieee->raw_tx ? "enabled" : "disabled"); + + if(ieee->iw_mode == IW_MODE_MONITOR) + { + if(prev == 0 && ieee->raw_tx){ + if (ieee->data_hard_resume) + ieee->data_hard_resume(ieee->dev); + + netif_carrier_on(ieee->dev); + } + + if(prev && ieee->raw_tx == 1) + netif_carrier_off(ieee->dev); + } + + up(&ieee->wx_sem); + + return 0; +} + +int ieee80211_wx_get_name(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + strcpy(wrqu->name, "802.11"); + if(ieee->modulation & IEEE80211_CCK_MODULATION){ + strcat(wrqu->name, "b"); + if(ieee->modulation & IEEE80211_OFDM_MODULATION) + strcat(wrqu->name, "/g"); + }else if(ieee->modulation & IEEE80211_OFDM_MODULATION) + strcat(wrqu->name, "g"); + if (ieee->mode & (IEEE_N_24G | IEEE_N_5G)) + strcat(wrqu->name, "/n"); + + if((ieee->state == IEEE80211_LINKED) || + (ieee->state == IEEE80211_LINKED_SCANNING)) + strcat(wrqu->name," linked"); + else if(ieee->state != IEEE80211_NOLINK) + strcat(wrqu->name," link.."); + + + return 0; +} + + +/* this is mostly stolen from hostap */ +int ieee80211_wx_set_power(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret = 0; +#if 1 + if( + (!ieee->sta_wake_up) || + // (!ieee->ps_request_tx_ack) || + (!ieee->enter_sleep_state) || + (!ieee->ps_is_queue_empty)){ + + // printk("ERROR. PS mode is tryied to be use but driver missed a callback\n\n"); + + return -1; + } +#endif + down(&ieee->wx_sem); + + if (wrqu->power.disabled){ + ieee->ps = IEEE80211_PS_DISABLED; + goto exit; + } + if (wrqu->power.flags & IW_POWER_TIMEOUT) { + //ieee->ps_period = wrqu->power.value / 1000; + ieee->ps_timeout = wrqu->power.value / 1000; + } + + if (wrqu->power.flags & IW_POWER_PERIOD) { + + //ieee->ps_timeout = wrqu->power.value / 1000; + ieee->ps_period = wrqu->power.value / 1000; + //wrq->value / 1024; + + } + switch (wrqu->power.flags & IW_POWER_MODE) { + case IW_POWER_UNICAST_R: + ieee->ps = IEEE80211_PS_UNICAST; + break; + case IW_POWER_MULTICAST_R: + ieee->ps = IEEE80211_PS_MBCAST; + break; + case IW_POWER_ALL_R: + ieee->ps = IEEE80211_PS_UNICAST | IEEE80211_PS_MBCAST; + break; + + case IW_POWER_ON: + // ieee->ps = IEEE80211_PS_DISABLED; + break; + + default: + ret = -EINVAL; + goto exit; + + } +exit: + up(&ieee->wx_sem); + return ret; + +} + +/* this is stolen from hostap */ +int ieee80211_wx_get_power(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret =0; + + down(&ieee->wx_sem); + + if(ieee->ps == IEEE80211_PS_DISABLED){ + wrqu->power.disabled = 1; + goto exit; + } + + wrqu->power.disabled = 0; + + if ((wrqu->power.flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { + wrqu->power.flags = IW_POWER_TIMEOUT; + wrqu->power.value = ieee->ps_timeout * 1000; + } else { +// ret = -EOPNOTSUPP; +// goto exit; + wrqu->power.flags = IW_POWER_PERIOD; + wrqu->power.value = ieee->ps_period * 1000; +//ieee->current_network.dtim_period * ieee->current_network.beacon_interval * 1024; + } + + if ((ieee->ps & (IEEE80211_PS_MBCAST | IEEE80211_PS_UNICAST)) == (IEEE80211_PS_MBCAST | IEEE80211_PS_UNICAST)) + wrqu->power.flags |= IW_POWER_ALL_R; + else if (ieee->ps & IEEE80211_PS_MBCAST) + wrqu->power.flags |= IW_POWER_MULTICAST_R; + else + wrqu->power.flags |= IW_POWER_UNICAST_R; + +exit: + up(&ieee->wx_sem); + return ret; + +} +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) +EXPORT_SYMBOL(ieee80211_wx_get_essid); +EXPORT_SYMBOL(ieee80211_wx_set_essid); +EXPORT_SYMBOL(ieee80211_wx_set_rate); +EXPORT_SYMBOL(ieee80211_wx_get_rate); +EXPORT_SYMBOL(ieee80211_wx_set_wap); +EXPORT_SYMBOL(ieee80211_wx_get_wap); +EXPORT_SYMBOL(ieee80211_wx_set_mode); +EXPORT_SYMBOL(ieee80211_wx_get_mode); +EXPORT_SYMBOL(ieee80211_wx_set_scan); +EXPORT_SYMBOL(ieee80211_wx_get_freq); +EXPORT_SYMBOL(ieee80211_wx_set_freq); +EXPORT_SYMBOL(ieee80211_wx_set_rawtx); +EXPORT_SYMBOL(ieee80211_wx_get_name); +EXPORT_SYMBOL(ieee80211_wx_set_power); +EXPORT_SYMBOL(ieee80211_wx_get_power); +EXPORT_SYMBOL(ieee80211_wlan_frequencies); +EXPORT_SYMBOL(ieee80211_wx_set_rts); +EXPORT_SYMBOL(ieee80211_wx_get_rts); +#else +EXPORT_SYMBOL_NOVERS(ieee80211_wx_get_essid); +EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_essid); +EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_rate); +EXPORT_SYMBOL_NOVERS(ieee80211_wx_get_rate); +EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_wap); +EXPORT_SYMBOL_NOVERS(ieee80211_wx_get_wap); +EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_mode); +EXPORT_SYMBOL_NOVERS(ieee80211_wx_get_mode); +EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_scan); +EXPORT_SYMBOL_NOVERS(ieee80211_wx_get_freq); +EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_freq); +EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_rawtx); +EXPORT_SYMBOL_NOVERS(ieee80211_wx_get_name); +EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_power); +EXPORT_SYMBOL_NOVERS(ieee80211_wx_get_power); +EXPORT_SYMBOL_NOVERS(ieee80211_wlan_frequencies); +EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_rts); +EXPORT_SYMBOL_NOVERS(ieee80211_wx_get_rts); +#endif diff --git a/drivers/staging/rtl8192su/ieee80211/ieee80211_tx.c b/drivers/staging/rtl8192su/ieee80211/ieee80211_tx.c new file mode 100644 index 000000000000..7294572b990f --- /dev/null +++ b/drivers/staging/rtl8192su/ieee80211/ieee80211_tx.c @@ -0,0 +1,947 @@ +/****************************************************************************** + + Copyright(c) 2003 - 2004 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., 59 + Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + The full GNU General Public License is included in this distribution in the + file called LICENSE. + + Contact Information: + James P. Ketrenos + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +****************************************************************************** + + Few modifications for Realtek's Wi-Fi drivers by + Andrea Merello + + A special thanks goes to Realtek for their support ! + +******************************************************************************/ + +#include +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ieee80211.h" + + +/* + + +802.11 Data Frame + + +802.11 frame_contorl for data frames - 2 bytes + ,-----------------------------------------------------------------------------------------. +bits | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | a | b | c | d | e | + |----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|------| +val | 0 | 0 | 0 | 1 | x | 0 | 0 | 0 | 1 | 0 | x | x | x | x | x | + |----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|------| +desc | ^-ver-^ | ^type-^ | ^-----subtype-----^ | to |from |more |retry| pwr |more |wep | + | | | x=0 data,x=1 data+ack | DS | DS |frag | | mgm |data | | + '-----------------------------------------------------------------------------------------' + /\ + | +802.11 Data Frame | + ,--------- 'ctrl' expands to >-----------' + | + ,--'---,-------------------------------------------------------------. +Bytes | 2 | 2 | 6 | 6 | 6 | 2 | 0..2312 | 4 | + |------|------|---------|---------|---------|------|---------|------| +Desc. | ctrl | dura | DA/RA | TA | SA | Sequ | Frame | fcs | + | | tion | (BSSID) | | | ence | data | | + `--------------------------------------------------| |------' +Total: 28 non-data bytes `----.----' + | + .- 'Frame data' expands to <---------------------------' + | + V + ,---------------------------------------------------. +Bytes | 1 | 1 | 1 | 3 | 2 | 0-2304 | + |------|------|---------|----------|------|---------| +Desc. | SNAP | SNAP | Control |Eth Tunnel| Type | IP | + | DSAP | SSAP | | | | Packet | + | 0xAA | 0xAA |0x03 (UI)|0x00-00-F8| | | + `-----------------------------------------| | +Total: 8 non-data bytes `----.----' + | + .- 'IP Packet' expands, if WEP enabled, to <--' + | + V + ,-----------------------. +Bytes | 4 | 0-2296 | 4 | + |-----|-----------|-----| +Desc. | IV | Encrypted | ICV | + | | IP Packet | | + `-----------------------' +Total: 8 non-data bytes + + +802.3 Ethernet Data Frame + + ,-----------------------------------------. +Bytes | 6 | 6 | 2 | Variable | 4 | + |-------|-------|------|-----------|------| +Desc. | Dest. | Source| Type | IP Packet | fcs | + | MAC | MAC | | | | + `-----------------------------------------' +Total: 18 non-data bytes + +In the event that fragmentation is required, the incoming payload is split into +N parts of size ieee->fts. The first fragment contains the SNAP header and the +remaining packets are just data. + +If encryption is enabled, each fragment payload size is reduced by enough space +to add the prefix and postfix (IV and ICV totalling 8 bytes in the case of WEP) +So if you have 1500 bytes of payload with ieee->fts set to 500 without +encryption it will take 3 frames. With WEP it will take 4 frames as the +payload of each frame is reduced to 492 bytes. + +* SKB visualization +* +* ,- skb->data +* | +* | ETHERNET HEADER ,-<-- PAYLOAD +* | | 14 bytes from skb->data +* | 2 bytes for Type --> ,T. | (sizeof ethhdr) +* | | | | +* |,-Dest.--. ,--Src.---. | | | +* | 6 bytes| | 6 bytes | | | | +* v | | | | | | +* 0 | v 1 | v | v 2 +* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 +* ^ | ^ | ^ | +* | | | | | | +* | | | | `T' <---- 2 bytes for Type +* | | | | +* | | '---SNAP--' <-------- 6 bytes for SNAP +* | | +* `-IV--' <-------------------- 4 bytes for IV (WEP) +* +* SNAP HEADER +* +*/ + +static u8 P802_1H_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0xf8 }; +static u8 RFC1042_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 }; + +static inline int ieee80211_put_snap(u8 *data, u16 h_proto) +{ + struct ieee80211_snap_hdr *snap; + u8 *oui; + + snap = (struct ieee80211_snap_hdr *)data; + snap->dsap = 0xaa; + snap->ssap = 0xaa; + snap->ctrl = 0x03; + + if (h_proto == 0x8137 || h_proto == 0x80f3) + oui = P802_1H_OUI; + else + oui = RFC1042_OUI; + snap->oui[0] = oui[0]; + snap->oui[1] = oui[1]; + snap->oui[2] = oui[2]; + + *(u16 *)(data + SNAP_SIZE) = htons(h_proto); + + return SNAP_SIZE + sizeof(u16); +} + +int ieee80211_encrypt_fragment( + struct ieee80211_device *ieee, + struct sk_buff *frag, + int hdr_len) +{ + struct ieee80211_crypt_data* crypt = ieee->crypt[ieee->tx_keyidx]; + int res; + + if (!(crypt && crypt->ops)) + { + printk("=========>%s(), crypt is null\n", __FUNCTION__); + return -1; + } +#ifdef CONFIG_IEEE80211_CRYPT_TKIP + struct ieee80211_hdr *header; + + if (ieee->tkip_countermeasures && + crypt && crypt->ops && strcmp(crypt->ops->name, "TKIP") == 0) { + header = (struct ieee80211_hdr *) frag->data; + if (net_ratelimit()) { + printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " + "TX packet to " MAC_FMT "\n", + ieee->dev->name, MAC_ARG(header->addr1)); + } + return -1; + } +#endif + /* To encrypt, frame format is: + * IV (4 bytes), clear payload (including SNAP), ICV (4 bytes) */ + + // PR: FIXME: Copied from hostap. Check fragmentation/MSDU/MPDU encryption. + /* Host-based IEEE 802.11 fragmentation for TX is not yet supported, so + * call both MSDU and MPDU encryption functions from here. */ + atomic_inc(&crypt->refcnt); + res = 0; + if (crypt->ops->encrypt_msdu) + res = crypt->ops->encrypt_msdu(frag, hdr_len, crypt->priv); + if (res == 0 && crypt->ops->encrypt_mpdu) + res = crypt->ops->encrypt_mpdu(frag, hdr_len, crypt->priv); + + atomic_dec(&crypt->refcnt); + if (res < 0) { + printk(KERN_INFO "%s: Encryption failed: len=%d.\n", + ieee->dev->name, frag->len); + ieee->ieee_stats.tx_discards++; + return -1; + } + + return 0; +} + + +void ieee80211_txb_free(struct ieee80211_txb *txb) { + //int i; + if (unlikely(!txb)) + return; +#if 0 + for (i = 0; i < txb->nr_frags; i++) + if (txb->fragments[i]) + dev_kfree_skb_any(txb->fragments[i]); +#endif + kfree(txb); +} + +struct ieee80211_txb *ieee80211_alloc_txb(int nr_frags, int txb_size, + int gfp_mask) +{ + struct ieee80211_txb *txb; + int i; + txb = kmalloc( + sizeof(struct ieee80211_txb) + (sizeof(u8*) * nr_frags), + gfp_mask); + if (!txb) + return NULL; + + memset(txb, 0, sizeof(struct ieee80211_txb)); + txb->nr_frags = nr_frags; + txb->frag_size = txb_size; + + for (i = 0; i < nr_frags; i++) { + txb->fragments[i] = dev_alloc_skb(txb_size); + if (unlikely(!txb->fragments[i])) { + i--; + break; + } + memset(txb->fragments[i]->cb, 0, sizeof(txb->fragments[i]->cb)); + } + if (unlikely(i != nr_frags)) { + while (i >= 0) + dev_kfree_skb_any(txb->fragments[i--]); + kfree(txb); + return NULL; + } + return txb; +} + +// Classify the to-be send data packet +// Need to acquire the sent queue index. +static int +ieee80211_classify(struct sk_buff *skb, struct ieee80211_network *network) +{ + struct ethhdr *eth; + struct iphdr *ip; + eth = (struct ethhdr *)skb->data; + if (eth->h_proto != htons(ETH_P_IP)) + return 0; + +// IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA, skb->data, skb->len); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)) + ip = ip_hdr(skb); +#else + ip = (struct iphdr*)(skb->data + sizeof(struct ether_header)); +#endif + switch (ip->tos & 0xfc) { + case 0x20: + return 2; + case 0x40: + return 1; + case 0x60: + return 3; + case 0x80: + return 4; + case 0xa0: + return 5; + case 0xc0: + return 6; + case 0xe0: + return 7; + default: + return 0; + } +} + +#define SN_LESS(a, b) (((a-b)&0x800)!=0) +void ieee80211_tx_query_agg_cap(struct ieee80211_device* ieee, struct sk_buff* skb, cb_desc* tcb_desc) +{ + PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; + PTX_TS_RECORD pTxTs = NULL; + struct ieee80211_hdr_1addr* hdr = (struct ieee80211_hdr_1addr*)skb->data; + + if (!pHTInfo->bCurrentHTSupport||!pHTInfo->bEnableHT) + return; + if (!IsQoSDataFrame(skb->data)) + return; + + if (is_multicast_ether_addr(hdr->addr1) || is_broadcast_ether_addr(hdr->addr1)) + return; + //check packet and mode later +#ifdef TO_DO_LIST + if(pTcb->PacketLength >= 4096) + return; + // For RTL819X, if pairwisekey = wep/tkip, we don't aggrregation. + if(!Adapter->HalFunc.GetNmodeSupportBySecCfgHandler(Adapter)) + return; +#endif + + if(pHTInfo->IOTAction & HT_IOT_ACT_TX_NO_AGGREGATION) + return; + +#if 1 + if(!ieee->GetNmodeSupportBySecCfg(ieee->dev)) + { + return; + } +#endif + if(pHTInfo->bCurrentAMPDUEnable) + { + if (!GetTs(ieee, (PTS_COMMON_INFO*)(&pTxTs), hdr->addr1, skb->priority, TX_DIR, true)) + { + printk("===>can't get TS\n"); + return; + } + if (pTxTs->TxAdmittedBARecord.bValid == false) + { + //as some AP will refuse our action frame until key handshake has been finished. WB + if (ieee->wpa_ie_len && (ieee->pairwise_key_type == KEY_TYPE_NA)) + ; + else + TsStartAddBaProcess(ieee, pTxTs); + goto FORCED_AGG_SETTING; + } + else if (pTxTs->bUsingBa == false) + { + if (SN_LESS(pTxTs->TxAdmittedBARecord.BaStartSeqCtrl.field.SeqNum, (pTxTs->TxCurSeq+1)%4096)) + pTxTs->bUsingBa = true; + else + goto FORCED_AGG_SETTING; + } + + if (ieee->iw_mode == IW_MODE_INFRA) + { + tcb_desc->bAMPDUEnable = true; + tcb_desc->ampdu_factor = pHTInfo->CurrentAMPDUFactor; + tcb_desc->ampdu_density = pHTInfo->CurrentMPDUDensity; + } + } +FORCED_AGG_SETTING: + switch(pHTInfo->ForcedAMPDUMode ) + { + case HT_AGG_AUTO: + break; + + case HT_AGG_FORCE_ENABLE: + tcb_desc->bAMPDUEnable = true; + tcb_desc->ampdu_density = pHTInfo->ForcedMPDUDensity; + tcb_desc->ampdu_factor = pHTInfo->ForcedAMPDUFactor; + break; + + case HT_AGG_FORCE_DISABLE: + tcb_desc->bAMPDUEnable = false; + tcb_desc->ampdu_density = 0; + tcb_desc->ampdu_factor = 0; + break; + + } + return; +} + +extern void ieee80211_qurey_ShortPreambleMode(struct ieee80211_device* ieee, cb_desc* tcb_desc) +{ + tcb_desc->bUseShortPreamble = false; + if (tcb_desc->data_rate == 2) + {//// 1M can only use Long Preamble. 11B spec + return; + } + else if (ieee->current_network.capability & WLAN_CAPABILITY_SHORT_PREAMBLE) + { + tcb_desc->bUseShortPreamble = true; + } + return; +} +extern void +ieee80211_query_HTCapShortGI(struct ieee80211_device *ieee, cb_desc *tcb_desc) +{ + PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; + + tcb_desc->bUseShortGI = false; + + if(!pHTInfo->bCurrentHTSupport||!pHTInfo->bEnableHT) + return; + + if(pHTInfo->bForcedShortGI) + { + tcb_desc->bUseShortGI = true; + return; + } + + if((pHTInfo->bCurBW40MHz==true) && pHTInfo->bCurShortGI40MHz) + tcb_desc->bUseShortGI = true; + else if((pHTInfo->bCurBW40MHz==false) && pHTInfo->bCurShortGI20MHz) + tcb_desc->bUseShortGI = true; +} + +void ieee80211_query_BandwidthMode(struct ieee80211_device* ieee, cb_desc *tcb_desc) +{ + PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; + + tcb_desc->bPacketBW = false; + + if(!pHTInfo->bCurrentHTSupport||!pHTInfo->bEnableHT) + return; + + if(tcb_desc->bMulticast || tcb_desc->bBroadcast) + return; + + if((tcb_desc->data_rate & 0x80)==0) // If using legacy rate, it shall use 20MHz channel. + return; + //BandWidthAutoSwitch is for auto switch to 20 or 40 in long distance + if(pHTInfo->bCurBW40MHz && pHTInfo->bCurTxBW40MHz && !ieee->bandwidth_auto_switch.bforced_tx20Mhz) + tcb_desc->bPacketBW = true; + return; +} + +void ieee80211_query_protectionmode(struct ieee80211_device* ieee, cb_desc* tcb_desc, struct sk_buff* skb) +{ + // Common Settings + tcb_desc->bRTSSTBC = false; + tcb_desc->bRTSUseShortGI = false; // Since protection frames are always sent by legacy rate, ShortGI will never be used. + tcb_desc->bCTSEnable = false; // Most of protection using RTS/CTS + tcb_desc->RTSSC = 0; // 20MHz: Don't care; 40MHz: Duplicate. + tcb_desc->bRTSBW = false; // RTS frame bandwidth is always 20MHz + + if(tcb_desc->bBroadcast || tcb_desc->bMulticast)//only unicast frame will use rts/cts + return; + + if (is_broadcast_ether_addr(skb->data+16)) //check addr3 as infrastructure add3 is DA. + return; + + if (ieee->mode < IEEE_N_24G) //b, g mode + { + // (1) RTS_Threshold is compared to the MPDU, not MSDU. + // (2) If there are more than one frag in this MSDU, only the first frag uses protection frame. + // Other fragments are protected by previous fragment. + // So we only need to check the length of first fragment. + if (skb->len > ieee->rts) + { + tcb_desc->bRTSEnable = true; + tcb_desc->rts_rate = MGN_24M; + } + else if (ieee->current_network.buseprotection) + { + // Use CTS-to-SELF in protection mode. + tcb_desc->bRTSEnable = true; + tcb_desc->bCTSEnable = true; + tcb_desc->rts_rate = MGN_24M; + } + //otherwise return; + return; + } + else + {// 11n High throughput case. + PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; + while (true) + { + //check IOT action + if(pHTInfo->IOTAction & HT_IOT_ACT_FORCED_CTS2SELF) + { + tcb_desc->bCTSEnable = true; + tcb_desc->rts_rate = MGN_24M; +#if defined(RTL8192SE) || defined(RTL8192SU) + tcb_desc->bRTSEnable = false; +#else + tcb_desc->bRTSEnable = true; +#endif + break; + } + else if(pHTInfo->IOTAction & (HT_IOT_ACT_FORCED_RTS|HT_IOT_ACT_PURE_N_MODE)) + { + tcb_desc->bRTSEnable = true; + tcb_desc->rts_rate = MGN_24M; + break; + } + //check ERP protection + if (ieee->current_network.buseprotection) + {// CTS-to-SELF + tcb_desc->bRTSEnable = true; + tcb_desc->bCTSEnable = true; + tcb_desc->rts_rate = MGN_24M; + break; + } + //check HT op mode + if(pHTInfo->bCurrentHTSupport && pHTInfo->bEnableHT) + { + u8 HTOpMode = pHTInfo->CurrentOpMode; + if((pHTInfo->bCurBW40MHz && (HTOpMode == 2 || HTOpMode == 3)) || + (!pHTInfo->bCurBW40MHz && HTOpMode == 3) ) + { + tcb_desc->rts_rate = MGN_24M; // Rate is 24Mbps. + tcb_desc->bRTSEnable = true; + break; + } + } + //check rts + if (skb->len > ieee->rts) + { + tcb_desc->rts_rate = MGN_24M; // Rate is 24Mbps. + tcb_desc->bRTSEnable = true; + break; + } + //to do list: check MIMO power save condition. + //check AMPDU aggregation for TXOP + if(tcb_desc->bAMPDUEnable) + { + tcb_desc->rts_rate = MGN_24M; // Rate is 24Mbps. + // According to 8190 design, firmware sends CF-End only if RTS/CTS is enabled. However, it degrads + // throughput around 10M, so we disable of this mechanism. 2007.08.03 by Emily + tcb_desc->bRTSEnable = false; + break; + } + // Totally no protection case!! + goto NO_PROTECTION; + } + } + // For test , CTS replace with RTS + if( 0 ) + { + tcb_desc->bCTSEnable = true; + tcb_desc->rts_rate = MGN_24M; + tcb_desc->bRTSEnable = true; + } + if (ieee->current_network.capability & WLAN_CAPABILITY_SHORT_PREAMBLE) + tcb_desc->bUseShortPreamble = true; + if (ieee->mode == IW_MODE_MASTER) + goto NO_PROTECTION; + return; +NO_PROTECTION: + tcb_desc->bRTSEnable = false; + tcb_desc->bCTSEnable = false; + tcb_desc->rts_rate = 0; + tcb_desc->RTSSC = 0; + tcb_desc->bRTSBW = false; +} + + +void ieee80211_txrate_selectmode(struct ieee80211_device* ieee, cb_desc* tcb_desc) +{ +#ifdef TO_DO_LIST + if(!IsDataFrame(pFrame)) + { + pTcb->bTxDisableRateFallBack = TRUE; + pTcb->bTxUseDriverAssingedRate = TRUE; + pTcb->RATRIndex = 7; + return; + } + + if(pMgntInfo->ForcedDataRate!= 0) + { + pTcb->bTxDisableRateFallBack = TRUE; + pTcb->bTxUseDriverAssingedRate = TRUE; + return; + } +#endif + if(ieee->bTxDisableRateFallBack) + tcb_desc->bTxDisableRateFallBack = true; + + if(ieee->bTxUseDriverAssingedRate) + tcb_desc->bTxUseDriverAssingedRate = true; + if(!tcb_desc->bTxDisableRateFallBack || !tcb_desc->bTxUseDriverAssingedRate) + { + if (ieee->iw_mode == IW_MODE_INFRA || ieee->iw_mode == IW_MODE_ADHOC) + tcb_desc->RATRIndex = 0; + } +} + +void ieee80211_query_seqnum(struct ieee80211_device*ieee, struct sk_buff* skb, u8* dst) +{ + if (is_multicast_ether_addr(dst) || is_broadcast_ether_addr(dst)) + return; + if (IsQoSDataFrame(skb->data)) //we deal qos data only + { + PTX_TS_RECORD pTS = NULL; + if (!GetTs(ieee, (PTS_COMMON_INFO*)(&pTS), dst, skb->priority, TX_DIR, true)) + { + return; + } + pTS->TxCurSeq = (pTS->TxCurSeq+1)%4096; + } +} + +int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)) + struct ieee80211_device *ieee = netdev_priv(dev); +#else + struct ieee80211_device *ieee = (struct ieee80211_device *)dev->priv; +#endif + struct ieee80211_txb *txb = NULL; + struct ieee80211_hdr_3addrqos *frag_hdr; + int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size; + unsigned long flags; + struct net_device_stats *stats = &ieee->stats; + int ether_type = 0, encrypt; + int bytes, fc, qos_ctl = 0, hdr_len; + struct sk_buff *skb_frag; + struct ieee80211_hdr_3addrqos header = { /* Ensure zero initialized */ + .duration_id = 0, + .seq_ctl = 0, + .qos_ctl = 0 + }; + u8 dest[ETH_ALEN], src[ETH_ALEN]; + int qos_actived = ieee->current_network.qos_data.active; + + struct ieee80211_crypt_data* crypt; + + cb_desc *tcb_desc; + + spin_lock_irqsave(&ieee->lock, flags); + + /* If there is no driver handler to take the TXB, dont' bother + * creating it... */ + if ((!ieee->hard_start_xmit && !(ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE))|| + ((!ieee->softmac_data_hard_start_xmit && (ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE)))) { + printk(KERN_WARNING "%s: No xmit handler.\n", + ieee->dev->name); + goto success; + } + + + if(likely(ieee->raw_tx == 0)){ + if (unlikely(skb->len < SNAP_SIZE + sizeof(u16))) { + printk(KERN_WARNING "%s: skb too small (%d).\n", + ieee->dev->name, skb->len); + goto success; + } + + memset(skb->cb, 0, sizeof(skb->cb)); + ether_type = ntohs(((struct ethhdr *)skb->data)->h_proto); + + crypt = ieee->crypt[ieee->tx_keyidx]; + + encrypt = !(ether_type == ETH_P_PAE && ieee->ieee802_1x) && + ieee->host_encrypt && crypt && crypt->ops; + + if (!encrypt && ieee->ieee802_1x && + ieee->drop_unencrypted && ether_type != ETH_P_PAE) { + stats->tx_dropped++; + goto success; + } + #ifdef CONFIG_IEEE80211_DEBUG + if (crypt && !encrypt && ether_type == ETH_P_PAE) { + struct eapol *eap = (struct eapol *)(skb->data + + sizeof(struct ethhdr) - SNAP_SIZE - sizeof(u16)); + IEEE80211_DEBUG_EAP("TX: IEEE 802.11 EAPOL frame: %s\n", + eap_get_type(eap->type)); + } + #endif + + /* Save source and destination addresses */ + memcpy(&dest, skb->data, ETH_ALEN); + memcpy(&src, skb->data+ETH_ALEN, ETH_ALEN); + + /* Advance the SKB to the start of the payload */ + skb_pull(skb, sizeof(struct ethhdr)); + + /* Determine total amount of storage required for TXB packets */ + bytes = skb->len + SNAP_SIZE + sizeof(u16); + + if (encrypt) + fc = IEEE80211_FTYPE_DATA | IEEE80211_FCTL_WEP; + else + + fc = IEEE80211_FTYPE_DATA; + + //if(ieee->current_network.QoS_Enable) + if(qos_actived) + fc |= IEEE80211_STYPE_QOS_DATA; + else + fc |= IEEE80211_STYPE_DATA; + + if (ieee->iw_mode == IW_MODE_INFRA) { + fc |= IEEE80211_FCTL_TODS; + /* To DS: Addr1 = BSSID, Addr2 = SA, + Addr3 = DA */ + memcpy(&header.addr1, ieee->current_network.bssid, ETH_ALEN); + memcpy(&header.addr2, &src, ETH_ALEN); + memcpy(&header.addr3, &dest, ETH_ALEN); + } else if (ieee->iw_mode == IW_MODE_ADHOC) { + /* not From/To DS: Addr1 = DA, Addr2 = SA, + Addr3 = BSSID */ + memcpy(&header.addr1, dest, ETH_ALEN); + memcpy(&header.addr2, src, ETH_ALEN); + memcpy(&header.addr3, ieee->current_network.bssid, ETH_ALEN); + } + + header.frame_ctl = cpu_to_le16(fc); + + /* Determine fragmentation size based on destination (multicast + * and broadcast are not fragmented) */ + if (is_multicast_ether_addr(header.addr1) || + is_broadcast_ether_addr(header.addr1)) { + frag_size = MAX_FRAG_THRESHOLD; + qos_ctl |= QOS_CTL_NOTCONTAIN_ACK; + } + else { + frag_size = ieee->fts;//default:392 + qos_ctl = 0; + } + + //if (ieee->current_network.QoS_Enable) + if(qos_actived) + { + hdr_len = IEEE80211_3ADDR_LEN + 2; + + skb->priority = ieee80211_classify(skb, &ieee->current_network); + qos_ctl |= skb->priority; //set in the ieee80211_classify + header.qos_ctl = cpu_to_le16(qos_ctl & IEEE80211_QOS_TID); + } else { + hdr_len = IEEE80211_3ADDR_LEN; + } + /* Determine amount of payload per fragment. Regardless of if + * this stack is providing the full 802.11 header, one will + * eventually be affixed to this fragment -- so we must account for + * it when determining the amount of payload space. */ + bytes_per_frag = frag_size - hdr_len; + if (ieee->config & + (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) + bytes_per_frag -= IEEE80211_FCS_LEN; + + /* Each fragment may need to have room for encryptiong pre/postfix */ + if (encrypt) + bytes_per_frag -= crypt->ops->extra_prefix_len + + crypt->ops->extra_postfix_len; + + /* Number of fragments is the total bytes_per_frag / + * payload_per_fragment */ + nr_frags = bytes / bytes_per_frag; + bytes_last_frag = bytes % bytes_per_frag; + if (bytes_last_frag) + nr_frags++; + else + bytes_last_frag = bytes_per_frag; + + /* 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(nr_frags, frag_size + ieee->tx_headroom, GFP_ATOMIC); + if (unlikely(!txb)) { + printk(KERN_WARNING "%s: Could not allocate TXB\n", + ieee->dev->name); + goto failed; + } + txb->encrypted = encrypt; + txb->payload_size = bytes; + + //if (ieee->current_network.QoS_Enable) + if(qos_actived) + { + txb->queue_index = UP2AC(skb->priority); + } else { + txb->queue_index = WME_AC_BK;; + } + + + + for (i = 0; i < nr_frags; i++) { + skb_frag = txb->fragments[i]; + tcb_desc = (cb_desc *)(skb_frag->cb + MAX_DEV_ADDR_SIZE); + if(qos_actived){ + skb_frag->priority = skb->priority;//UP2AC(skb->priority); + tcb_desc->queue_index = UP2AC(skb->priority); + } else { + skb_frag->priority = WME_AC_BK; + tcb_desc->queue_index = WME_AC_BK; + } + skb_reserve(skb_frag, ieee->tx_headroom); + + if (encrypt){ + if (ieee->hwsec_active) + tcb_desc->bHwSec = 1; + else + tcb_desc->bHwSec = 0; + skb_reserve(skb_frag, crypt->ops->extra_prefix_len); + } + else + { + tcb_desc->bHwSec = 0; + } + frag_hdr = (struct ieee80211_hdr_3addrqos *)skb_put(skb_frag, hdr_len); + memcpy(frag_hdr, &header, hdr_len); + + /* If this is not the last fragment, then add the MOREFRAGS + * bit to the frame control */ + if (i != nr_frags - 1) { + frag_hdr->frame_ctl = cpu_to_le16( + fc | IEEE80211_FCTL_MOREFRAGS); + bytes = bytes_per_frag; + + } else { + /* The last fragment takes the remaining length */ + bytes = bytes_last_frag; + } + //if(ieee->current_network.QoS_Enable) + if(qos_actived) + { + // add 1 only indicate to corresponding seq number control 2006/7/12 + frag_hdr->seq_ctl = cpu_to_le16(ieee->seq_ctrl[UP2AC(skb->priority)+1]<<4 | i); + } else { + frag_hdr->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0]<<4 | i); + } + + /* Put a SNAP header on the first fragment */ + if (i == 0) { + ieee80211_put_snap( + skb_put(skb_frag, SNAP_SIZE + sizeof(u16)), + ether_type); + bytes -= SNAP_SIZE + sizeof(u16); + } + + memcpy(skb_put(skb_frag, bytes), skb->data, bytes); + + /* Advance the SKB... */ + skb_pull(skb, bytes); + + /* Encryption routine will move the header forward in order + * to insert the IV between the header and the payload */ + if (encrypt) + ieee80211_encrypt_fragment(ieee, skb_frag, hdr_len); + if (ieee->config & + (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) + skb_put(skb_frag, 4); + } + + if(qos_actived) + { + if (ieee->seq_ctrl[UP2AC(skb->priority) + 1] == 0xFFF) + ieee->seq_ctrl[UP2AC(skb->priority) + 1] = 0; + else + ieee->seq_ctrl[UP2AC(skb->priority) + 1]++; + } else { + if (ieee->seq_ctrl[0] == 0xFFF) + ieee->seq_ctrl[0] = 0; + else + ieee->seq_ctrl[0]++; + } + }else{ + if (unlikely(skb->len < sizeof(struct ieee80211_hdr_3addr))) { + printk(KERN_WARNING "%s: skb too small (%d).\n", + ieee->dev->name, skb->len); + goto success; + } + + txb = ieee80211_alloc_txb(1, skb->len, GFP_ATOMIC); + if(!txb){ + printk(KERN_WARNING "%s: Could not allocate TXB\n", + ieee->dev->name); + goto failed; + } + + txb->encrypted = 0; + txb->payload_size = skb->len; + memcpy(skb_put(txb->fragments[0],skb->len), skb->data, skb->len); + } + + success: +//WB add to fill data tcb_desc here. only first fragment is considered, need to change, and you may remove to other place. + if (txb) + { +#if 1 + cb_desc *tcb_desc = (cb_desc *)(txb->fragments[0]->cb + MAX_DEV_ADDR_SIZE); + tcb_desc->bTxEnableFwCalcDur = 1; + if (is_multicast_ether_addr(header.addr1)) + tcb_desc->bMulticast = 1; + if (is_broadcast_ether_addr(header.addr1)) + tcb_desc->bBroadcast = 1; + ieee80211_txrate_selectmode(ieee, tcb_desc); + if ( tcb_desc->bMulticast || tcb_desc->bBroadcast) + tcb_desc->data_rate = ieee->basic_rate; + else + //tcb_desc->data_rate = CURRENT_RATE(ieee->current_network.mode, ieee->rate, ieee->HTCurrentOperaRate); + tcb_desc->data_rate = CURRENT_RATE(ieee->mode, ieee->rate, ieee->HTCurrentOperaRate); + ieee80211_qurey_ShortPreambleMode(ieee, tcb_desc); + ieee80211_tx_query_agg_cap(ieee, txb->fragments[0], tcb_desc); + ieee80211_query_HTCapShortGI(ieee, tcb_desc); + ieee80211_query_BandwidthMode(ieee, tcb_desc); + ieee80211_query_protectionmode(ieee, tcb_desc, txb->fragments[0]); + ieee80211_query_seqnum(ieee, txb->fragments[0], header.addr1); +// IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA, txb->fragments[0]->data, txb->fragments[0]->len); + //IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA, tcb_desc, sizeof(cb_desc)); +#endif + } + spin_unlock_irqrestore(&ieee->lock, flags); + dev_kfree_skb_any(skb); + if (txb) { + if (ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE){ + ieee80211_softmac_xmit(txb, ieee); + }else{ + if ((*ieee->hard_start_xmit)(txb, dev) == 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); + netif_stop_queue(dev); + stats->tx_errors++; + return 1; + +} + +EXPORT_SYMBOL(ieee80211_txb_free); diff --git a/drivers/staging/rtl8192su/ieee80211/ieee80211_wx.c b/drivers/staging/rtl8192su/ieee80211/ieee80211_wx.c new file mode 100644 index 000000000000..ae11e2576beb --- /dev/null +++ b/drivers/staging/rtl8192su/ieee80211/ieee80211_wx.c @@ -0,0 +1,1032 @@ +/****************************************************************************** + + Copyright(c) 2004 Intel Corporation. All rights reserved. + + Portions of this file are based on the WEP enablement code provided by the + Host AP project hostap-drivers v0.1.3 + Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen + + Copyright (c) 2002-2003, Jouni Malinen + + 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., 59 + Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + The full GNU General Public License is included in this distribution in the + file called LICENSE. + + Contact Information: + James P. Ketrenos + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +******************************************************************************/ +#include +#include +#include +#include + +#include "ieee80211.h" +#if 0 +static const char *ieee80211_modes[] = { + "?", "a", "b", "ab", "g", "ag", "bg", "abg" +}; +#endif +struct modes_unit { + char *mode_string; + int mode_size; +}; +struct modes_unit ieee80211_modes[] = { + {"a",1}, + {"b",1}, + {"g",1}, + {"?",1}, + {"N-24G",5}, + {"N-5G",4}, +}; + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,20)) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) +static inline char * +iwe_stream_add_event_rsl(char * stream, /* Stream of events */ + char * ends, /* End of stream */ + struct iw_event *iwe, /* Payload */ + int event_len) /* Real size of payload */ +{ + /* Check if it's possible */ + if((stream + event_len) < ends) { + iwe->len = event_len; + ndelay(1); //new + memcpy(stream, (char *) iwe, event_len); + stream += event_len; + } + return stream; +} +#else +#define iwe_stream_add_event_rsl iwe_stream_add_event +#endif + +#define MAX_CUSTOM_LEN 64 +static inline char *rtl819x_translate_scan(struct ieee80211_device *ieee, + char *start, char *stop, + struct ieee80211_network *network, + struct iw_request_info *info) +{ + char custom[MAX_CUSTOM_LEN]; + char proto_name[IFNAMSIZ]; + char *pname = proto_name; + char *p; + struct iw_event iwe; + int i, j; + u16 max_rate, rate; + static u8 EWC11NHTCap[] = {0x00, 0x90, 0x4c, 0x33}; + + /* First entry *MUST* be the AP MAC address */ + iwe.cmd = SIOCGIWAP; + iwe.u.ap_addr.sa_family = ARPHRD_ETHER; + memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) + start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_ADDR_LEN); +#else + start = iwe_stream_add_event_rsl(start, stop, &iwe, IW_EV_ADDR_LEN); +#endif + /* Remaining entries will be displayed in the order we provide them */ + + /* Add the ESSID */ + iwe.cmd = SIOCGIWESSID; + iwe.u.data.flags = 1; +// if (network->flags & NETWORK_EMPTY_ESSID) { + if (network->ssid_len == 0) { + iwe.u.data.length = sizeof(""); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) + start = iwe_stream_add_point(info, start, stop, &iwe, ""); +#else + start = iwe_stream_add_point(start, stop, &iwe, ""); +#endif + } else { + iwe.u.data.length = min(network->ssid_len, (u8)32); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) + start = iwe_stream_add_point(info, start, stop, &iwe, network->ssid); +#else + start = iwe_stream_add_point(start, stop, &iwe, network->ssid); +#endif + } + /* Add the protocol name */ + iwe.cmd = SIOCGIWNAME; + for(i=0; i<(sizeof(ieee80211_modes)/sizeof(ieee80211_modes[0])); i++) { + if(network->mode&(1<= KERNEL_VERSION(2,6,27) + start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_CHAR_LEN); +#else + start = iwe_stream_add_event_rsl(start, stop, &iwe, IW_EV_CHAR_LEN); +#endif + /* Add mode */ + iwe.cmd = SIOCGIWMODE; + if (network->capability & + (WLAN_CAPABILITY_BSS | WLAN_CAPABILITY_IBSS)) { + if (network->capability & WLAN_CAPABILITY_BSS) + iwe.u.mode = IW_MODE_MASTER; + else + iwe.u.mode = IW_MODE_ADHOC; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) + start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_UINT_LEN); +#else + start = iwe_stream_add_event_rsl(start, stop, &iwe, IW_EV_UINT_LEN); +#endif + } + + /* Add frequency/channel */ + iwe.cmd = SIOCGIWFREQ; +/* iwe.u.freq.m = ieee80211_frequency(network->channel, network->mode); + iwe.u.freq.e = 3; */ + iwe.u.freq.m = network->channel; + iwe.u.freq.e = 0; + iwe.u.freq.i = 0; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) + start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_FREQ_LEN); +#else + start = iwe_stream_add_event_rsl(start, stop, &iwe, IW_EV_FREQ_LEN); +#endif + /* Add encryption capability */ + iwe.cmd = SIOCGIWENCODE; + if (network->capability & WLAN_CAPABILITY_PRIVACY) + iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; + else + iwe.u.data.flags = IW_ENCODE_DISABLED; + iwe.u.data.length = 0; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) + start = iwe_stream_add_point(info, start, stop, &iwe, network->ssid); +#else + start = iwe_stream_add_point(start, stop, &iwe, network->ssid); +#endif + /* Add basic and extended rates */ + max_rate = 0; + p = custom; + p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Rates (Mb/s): "); + for (i = 0, j = 0; i < network->rates_len; ) { + if (j < network->rates_ex_len && + ((network->rates_ex[j] & 0x7F) < + (network->rates[i] & 0x7F))) + rate = network->rates_ex[j++] & 0x7F; + else + rate = network->rates[i++] & 0x7F; + if (rate > max_rate) + max_rate = rate; + p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), + "%d%s ", rate >> 1, (rate & 1) ? ".5" : ""); + } + for (; j < network->rates_ex_len; j++) { + rate = network->rates_ex[j] & 0x7F; + p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), + "%d%s ", rate >> 1, (rate & 1) ? ".5" : ""); + if (rate > max_rate) + max_rate = rate; + } + + if (network->mode >= IEEE_N_24G)//add N rate here; + { + PHT_CAPABILITY_ELE ht_cap = NULL; + bool is40M = false, isShortGI = false; + u8 max_mcs = 0; + if (!memcmp(network->bssht.bdHTCapBuf, EWC11NHTCap, 4)) + ht_cap = (PHT_CAPABILITY_ELE)&network->bssht.bdHTCapBuf[4]; + else + ht_cap = (PHT_CAPABILITY_ELE)&network->bssht.bdHTCapBuf[0]; + is40M = (ht_cap->ChlWidth)?1:0; + isShortGI = (ht_cap->ChlWidth)? + ((ht_cap->ShortGI40Mhz)?1:0): + ((ht_cap->ShortGI20Mhz)?1:0); + + max_mcs = HTGetHighestMCSRate(ieee, ht_cap->MCS, MCS_FILTER_ALL); + rate = MCS_DATA_RATE[is40M][isShortGI][max_mcs&0x7f]; + if (rate > max_rate) + max_rate = rate; + } +#if 0 + printk("max rate:%d ===basic rate:\n", max_rate); + for (i=0;irates_len;i++) + printk(" %x", network->rates[i]); + printk("\n=======extend rate\n"); + for (i=0; irates_ex_len; i++) + printk(" %x", network->rates_ex[i]); + printk("\n"); +#endif + iwe.cmd = SIOCGIWRATE; + iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; + iwe.u.bitrate.value = max_rate * 500000; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) + start = iwe_stream_add_event_rsl(info, start, stop, &iwe, + IW_EV_PARAM_LEN); +#else + start = iwe_stream_add_event_rsl(start, stop, &iwe, + IW_EV_PARAM_LEN); +#endif + iwe.cmd = IWEVCUSTOM; + iwe.u.data.length = p - custom; + if (iwe.u.data.length) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) + start = iwe_stream_add_point(info, start, stop, &iwe, custom); +#else + start = iwe_stream_add_point(start, stop, &iwe, custom); +#endif + /* Add quality statistics */ + /* TODO: Fix these values... */ + iwe.cmd = IWEVQUAL; + iwe.u.qual.qual = network->stats.signal; + iwe.u.qual.level = network->stats.rssi; + iwe.u.qual.noise = network->stats.noise; + iwe.u.qual.updated = network->stats.mask & IEEE80211_STATMASK_WEMASK; + if (!(network->stats.mask & IEEE80211_STATMASK_RSSI)) + iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID; + if (!(network->stats.mask & IEEE80211_STATMASK_NOISE)) + iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID; + if (!(network->stats.mask & IEEE80211_STATMASK_SIGNAL)) + iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID; + iwe.u.qual.updated = 7; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) + start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_QUAL_LEN); +#else + start = iwe_stream_add_event_rsl(start, stop, &iwe, IW_EV_QUAL_LEN); +#endif + iwe.cmd = IWEVCUSTOM; + p = custom; + + iwe.u.data.length = p - custom; + if (iwe.u.data.length) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) + start = iwe_stream_add_point(info, start, stop, &iwe, custom); +#else + start = iwe_stream_add_point(start, stop, &iwe, custom); +#endif +#if (WIRELESS_EXT < 18) + if (ieee->wpa_enabled && network->wpa_ie_len){ + char buf[MAX_WPA_IE_LEN * 2 + 30]; + // printk("WPA IE\n"); + u8 *p = buf; + p += sprintf(p, "wpa_ie="); + for (i = 0; i < network->wpa_ie_len; i++) { + p += sprintf(p, "%02x", network->wpa_ie[i]); + } + + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = IWEVCUSTOM; + iwe.u.data.length = strlen(buf); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) + start = iwe_stream_add_point(info, start, stop, &iwe, buf); +#else + start = iwe_stream_add_point(start, stop, &iwe, buf); +#endif + } + + if (ieee->wpa_enabled && network->rsn_ie_len){ + char buf[MAX_WPA_IE_LEN * 2 + 30]; + + u8 *p = buf; + p += sprintf(p, "rsn_ie="); + for (i = 0; i < network->rsn_ie_len; i++) { + p += sprintf(p, "%02x", network->rsn_ie[i]); + } + + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = IWEVCUSTOM; + iwe.u.data.length = strlen(buf); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) + start = iwe_stream_add_point(info, start, stop, &iwe, buf); +#else + start = iwe_stream_add_point(start, stop, &iwe, buf); +#endif + } +#else + memset(&iwe, 0, sizeof(iwe)); + if (network->wpa_ie_len) + { + char buf[MAX_WPA_IE_LEN]; + memcpy(buf, network->wpa_ie, network->wpa_ie_len); + iwe.cmd = IWEVGENIE; + iwe.u.data.length = network->wpa_ie_len; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) + start = iwe_stream_add_point(info, start, stop, &iwe, buf); +#else + start = iwe_stream_add_point(start, stop, &iwe, buf); +#endif + } + memset(&iwe, 0, sizeof(iwe)); + if (network->rsn_ie_len) + { + char buf[MAX_WPA_IE_LEN]; + memcpy(buf, network->rsn_ie, network->rsn_ie_len); + iwe.cmd = IWEVGENIE; + iwe.u.data.length = network->rsn_ie_len; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) + start = iwe_stream_add_point(info, start, stop, &iwe, buf); +#else + start = iwe_stream_add_point(start, stop, &iwe, buf); +#endif + } +#endif + + + /* Add EXTRA: Age to display seconds since last beacon/probe response + * for given network. */ + iwe.cmd = IWEVCUSTOM; + p = custom; + p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), + " Last beacon: %lums ago", (jiffies - network->last_scanned) / (HZ / 100)); + iwe.u.data.length = p - custom; + if (iwe.u.data.length) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) + start = iwe_stream_add_point(info, start, stop, &iwe, custom); +#else + start = iwe_stream_add_point(start, stop, &iwe, custom); +#endif + + return start; +} + +int ieee80211_wx_get_scan(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ieee80211_network *network; + unsigned long flags; + + char *ev = extra; +// char *stop = ev + IW_SCAN_MAX_DATA; + char *stop = ev + wrqu->data.length;//IW_SCAN_MAX_DATA; + //char *stop = ev + IW_SCAN_MAX_DATA; + int i = 0; + int err = 0; + IEEE80211_DEBUG_WX("Getting scan\n"); + down(&ieee->wx_sem); + spin_lock_irqsave(&ieee->lock, flags); + + list_for_each_entry(network, &ieee->network_list, list) { + i++; + if((stop-ev)<200) + { + err = -E2BIG; + break; + } + if (ieee->scan_age == 0 || + time_after(network->last_scanned + ieee->scan_age, jiffies)) + ev = rtl819x_translate_scan(ieee, ev, stop, network, info); + else + IEEE80211_DEBUG_SCAN( + "Not showing network '%s (" + MAC_FMT ")' due to age (%lums).\n", + escape_essid(network->ssid, + network->ssid_len), + MAC_ARG(network->bssid), + (jiffies - network->last_scanned) / (HZ / 100)); + } + + spin_unlock_irqrestore(&ieee->lock, flags); + up(&ieee->wx_sem); + wrqu->data.length = ev - extra; + wrqu->data.flags = 0; + + IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i); + + return err; +} + +int ieee80211_wx_set_encode(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *keybuf) +{ + struct iw_point *erq = &(wrqu->encoding); + struct net_device *dev = ieee->dev; + struct ieee80211_security sec = { + .flags = 0 + }; + int i, key, key_provided, len; + struct ieee80211_crypt_data **crypt; + + IEEE80211_DEBUG_WX("SET_ENCODE\n"); + + key = erq->flags & IW_ENCODE_INDEX; + if (key) { + if (key > WEP_KEYS) + return -EINVAL; + key--; + key_provided = 1; + } else { + key_provided = 0; + key = ieee->tx_keyidx; + } + + IEEE80211_DEBUG_WX("Key: %d [%s]\n", key, key_provided ? + "provided" : "default"); + crypt = &ieee->crypt[key]; + + if (erq->flags & IW_ENCODE_DISABLED) { + if (key_provided && *crypt) { + IEEE80211_DEBUG_WX("Disabling encryption on key %d.\n", + key); + ieee80211_crypt_delayed_deinit(ieee, crypt); + } else + IEEE80211_DEBUG_WX("Disabling encryption.\n"); + + /* Check all the keys to see if any are still configured, + * and if no key index was provided, de-init them all */ + for (i = 0; i < WEP_KEYS; i++) { + if (ieee->crypt[i] != NULL) { + if (key_provided) + break; + ieee80211_crypt_delayed_deinit( + ieee, &ieee->crypt[i]); + } + } + + if (i == WEP_KEYS) { + sec.enabled = 0; + sec.level = SEC_LEVEL_0; + sec.flags |= SEC_ENABLED | SEC_LEVEL; + } + + goto done; + } + + + + sec.enabled = 1; + sec.flags |= SEC_ENABLED; + + if (*crypt != NULL && (*crypt)->ops != NULL && + strcmp((*crypt)->ops->name, "WEP") != 0) { + /* changing to use WEP; deinit previously used algorithm + * on this key */ + ieee80211_crypt_delayed_deinit(ieee, crypt); + } + + if (*crypt == NULL) { + struct ieee80211_crypt_data *new_crypt; + + /* take WEP into use */ + new_crypt = kmalloc(sizeof(struct ieee80211_crypt_data), + GFP_KERNEL); + if (new_crypt == NULL) + return -ENOMEM; + memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data)); + new_crypt->ops = ieee80211_get_crypto_ops("WEP"); + if (!new_crypt->ops) { + request_module("ieee80211_crypt_wep"); + new_crypt->ops = ieee80211_get_crypto_ops("WEP"); + } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) +#else + if (new_crypt->ops && try_inc_mod_count(new_crypt->ops->owner)) +#endif + new_crypt->priv = new_crypt->ops->init(key); + + if (!new_crypt->ops || !new_crypt->priv) { + kfree(new_crypt); + new_crypt = NULL; + + printk(KERN_WARNING "%s: could not initialize WEP: " + "load module ieee80211_crypt_wep\n", + dev->name); + return -EOPNOTSUPP; + } + *crypt = new_crypt; + } + + /* If a new key was provided, set it up */ + if (erq->length > 0) { + len = erq->length <= 5 ? 5 : 13; + memcpy(sec.keys[key], keybuf, erq->length); + if (len > erq->length) + memset(sec.keys[key] + erq->length, 0, + len - erq->length); + IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n", + key, escape_essid(sec.keys[key], len), + erq->length, len); + sec.key_sizes[key] = len; + (*crypt)->ops->set_key(sec.keys[key], len, NULL, + (*crypt)->priv); + sec.flags |= (1 << key); + /* This ensures a key will be activated if no key is + * explicitely set */ + if (key == sec.active_key) + sec.flags |= SEC_ACTIVE_KEY; + ieee->tx_keyidx = key; + + } else { + len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN, + NULL, (*crypt)->priv); + if (len == 0) { + /* Set a default key of all 0 */ + printk("Setting key %d to all zero.\n", + key); + + IEEE80211_DEBUG_WX("Setting key %d to all zero.\n", + key); + memset(sec.keys[key], 0, 13); + (*crypt)->ops->set_key(sec.keys[key], 13, NULL, + (*crypt)->priv); + sec.key_sizes[key] = 13; + sec.flags |= (1 << key); + } + + /* No key data - just set the default TX key index */ + if (key_provided) { + IEEE80211_DEBUG_WX( + "Setting key %d to default Tx key.\n", key); + ieee->tx_keyidx = key; + sec.active_key = key; + sec.flags |= SEC_ACTIVE_KEY; + } + } + + done: + ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED); + ieee->auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY; + sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY; + sec.flags |= SEC_AUTH_MODE; + IEEE80211_DEBUG_WX("Auth: %s\n", sec.auth_mode == WLAN_AUTH_OPEN ? + "OPEN" : "SHARED KEY"); + + /* For now we just support WEP, so only set that security level... + * TODO: When WPA is added this is one place that needs to change */ + sec.flags |= SEC_LEVEL; + sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */ + + if (ieee->set_security) + ieee->set_security(dev, &sec); + + /* Do not reset port if card is in Managed mode since resetting will + * generate new IEEE 802.11 authentication which may end up in looping + * with IEEE 802.1X. If your hardware requires a reset after WEP + * configuration (for example... Prism2), implement the reset_port in + * the callbacks structures used to initialize the 802.11 stack. */ + if (ieee->reset_on_keychange && + ieee->iw_mode != IW_MODE_INFRA && + ieee->reset_port && ieee->reset_port(dev)) { + printk(KERN_DEBUG "%s: reset_port failed\n", dev->name); + return -EINVAL; + } + return 0; +} + +int ieee80211_wx_get_encode(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *keybuf) +{ + struct iw_point *erq = &(wrqu->encoding); + int len, key; + struct ieee80211_crypt_data *crypt; + + IEEE80211_DEBUG_WX("GET_ENCODE\n"); + + if(ieee->iw_mode == IW_MODE_MONITOR) + return -1; + + key = erq->flags & IW_ENCODE_INDEX; + if (key) { + if (key > WEP_KEYS) + return -EINVAL; + key--; + } else + key = ieee->tx_keyidx; + + crypt = ieee->crypt[key]; + erq->flags = key + 1; + + if (crypt == NULL || crypt->ops == NULL) { + erq->length = 0; + erq->flags |= IW_ENCODE_DISABLED; + return 0; + } +#if 0 + if (strcmp(crypt->ops->name, "WEP") != 0) { + /* only WEP is supported with wireless extensions, so just + * report that encryption is used */ + erq->length = 0; + erq->flags |= IW_ENCODE_ENABLED; + return 0; + } +#endif + len = crypt->ops->get_key(keybuf, SCM_KEY_LEN, NULL, crypt->priv); + erq->length = (len >= 0 ? len : 0); + + erq->flags |= IW_ENCODE_ENABLED; + + if (ieee->open_wep) + erq->flags |= IW_ENCODE_OPEN; + else + erq->flags |= IW_ENCODE_RESTRICTED; + + return 0; +} +#if (WIRELESS_EXT >= 18) +int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret = 0; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + struct net_device *dev = ieee->dev; + struct iw_point *encoding = &wrqu->encoding; + struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; + int i, idx; + int group_key = 0; + const char *alg, *module; + struct ieee80211_crypto_ops *ops; + struct ieee80211_crypt_data **crypt; + + struct ieee80211_security sec = { + .flags = 0, + }; + //printk("======>encoding flag:%x,ext flag:%x, ext alg:%d\n", encoding->flags,ext->ext_flags, ext->alg); + idx = encoding->flags & IW_ENCODE_INDEX; + if (idx) { + if (idx < 1 || idx > WEP_KEYS) + return -EINVAL; + idx--; + } else + idx = ieee->tx_keyidx; + + if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { + + crypt = &ieee->crypt[idx]; + + group_key = 1; + } else { + /* some Cisco APs use idx>0 for unicast in dynamic WEP */ + //printk("not group key, flags:%x, ext->alg:%d\n", ext->ext_flags, ext->alg); + if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP) + return -EINVAL; + if (ieee->iw_mode == IW_MODE_INFRA) + + crypt = &ieee->crypt[idx]; + + else + return -EINVAL; + } + + sec.flags |= SEC_ENABLED;// | SEC_ENCRYPT; + if ((encoding->flags & IW_ENCODE_DISABLED) || + ext->alg == IW_ENCODE_ALG_NONE) { + if (*crypt) + ieee80211_crypt_delayed_deinit(ieee, crypt); + + for (i = 0; i < WEP_KEYS; i++) + + if (ieee->crypt[i] != NULL) + + break; + + if (i == WEP_KEYS) { + sec.enabled = 0; + // sec.encrypt = 0; + sec.level = SEC_LEVEL_0; + sec.flags |= SEC_LEVEL; + } + //printk("disabled: flag:%x\n", encoding->flags); + goto done; + } + + sec.enabled = 1; + // sec.encrypt = 1; +#if 0 + if (group_key ? !ieee->host_mc_decrypt : + !(ieee->host_encrypt || ieee->host_decrypt || + ieee->host_encrypt_msdu)) + goto skip_host_crypt; +#endif + switch (ext->alg) { + case IW_ENCODE_ALG_WEP: + alg = "WEP"; + module = "ieee80211_crypt_wep"; + break; + case IW_ENCODE_ALG_TKIP: + alg = "TKIP"; + module = "ieee80211_crypt_tkip"; + break; + case IW_ENCODE_ALG_CCMP: + alg = "CCMP"; + module = "ieee80211_crypt_ccmp"; + break; + default: + IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n", + dev->name, ext->alg); + ret = -EINVAL; + goto done; + } + printk("alg name:%s\n",alg); + + ops = ieee80211_get_crypto_ops(alg); + if (ops == NULL) { + request_module("%s", module); + ops = ieee80211_get_crypto_ops(alg); + } + if (ops == NULL) { + IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n", + dev->name, ext->alg); + printk("========>unknown crypto alg %d\n", ext->alg); + ret = -EINVAL; + goto done; + } + + if (*crypt == NULL || (*crypt)->ops != ops) { + struct ieee80211_crypt_data *new_crypt; + + ieee80211_crypt_delayed_deinit(ieee, crypt); + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13)) + new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL); +#else + new_crypt = kmalloc(sizeof(*new_crypt), GFP_KERNEL); + memset(new_crypt,0,sizeof(*new_crypt)); +#endif + if (new_crypt == NULL) { + ret = -ENOMEM; + goto done; + } + new_crypt->ops = ops; + if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) + new_crypt->priv = new_crypt->ops->init(idx); + if (new_crypt->priv == NULL) { + kfree(new_crypt); + ret = -EINVAL; + goto done; + } + *crypt = new_crypt; + + } + + if (ext->key_len > 0 && (*crypt)->ops->set_key && + (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq, + (*crypt)->priv) < 0) { + IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name); + printk("key setting failed\n"); + ret = -EINVAL; + goto done; + } +#if 1 + //skip_host_crypt: + //printk("skip_host_crypt:ext_flags:%x\n", ext->ext_flags); + if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { + ieee->tx_keyidx = idx; + sec.active_key = idx; + sec.flags |= SEC_ACTIVE_KEY; + } + + if (ext->alg != IW_ENCODE_ALG_NONE) { + //memcpy(sec.keys[idx], ext->key, ext->key_len); + sec.key_sizes[idx] = ext->key_len; + sec.flags |= (1 << idx); + if (ext->alg == IW_ENCODE_ALG_WEP) { + // sec.encode_alg[idx] = SEC_ALG_WEP; + sec.flags |= SEC_LEVEL; + sec.level = SEC_LEVEL_1; + } else if (ext->alg == IW_ENCODE_ALG_TKIP) { + // sec.encode_alg[idx] = SEC_ALG_TKIP; + sec.flags |= SEC_LEVEL; + sec.level = SEC_LEVEL_2; + } else if (ext->alg == IW_ENCODE_ALG_CCMP) { + // sec.encode_alg[idx] = SEC_ALG_CCMP; + sec.flags |= SEC_LEVEL; + sec.level = SEC_LEVEL_3; + } + /* Don't set sec level for group keys. */ + if (group_key) + sec.flags &= ~SEC_LEVEL; + } +#endif +done: + if (ieee->set_security) + ieee->set_security(ieee->dev, &sec); + + if (ieee->reset_on_keychange && + ieee->iw_mode != IW_MODE_INFRA && + ieee->reset_port && ieee->reset_port(dev)) { + IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name); + return -EINVAL; + } +#endif + return ret; +} + +int ieee80211_wx_get_encode_ext(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct iw_point *encoding = &wrqu->encoding; + struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; + struct ieee80211_crypt_data *crypt; + int idx, max_key_len; + + max_key_len = encoding->length - sizeof(*ext); + if (max_key_len < 0) + return -EINVAL; + + idx = encoding->flags & IW_ENCODE_INDEX; + if (idx) { + if (idx < 1 || idx > WEP_KEYS) + return -EINVAL; + idx--; + } else + idx = ieee->tx_keyidx; + + if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) && + ext->alg != IW_ENCODE_ALG_WEP) + if (idx != 0 || ieee->iw_mode != IW_MODE_INFRA) + return -EINVAL; + + crypt = ieee->crypt[idx]; + encoding->flags = idx + 1; + memset(ext, 0, sizeof(*ext)); + + if (crypt == NULL || crypt->ops == NULL ) { + ext->alg = IW_ENCODE_ALG_NONE; + ext->key_len = 0; + encoding->flags |= IW_ENCODE_DISABLED; + } else { + if (strcmp(crypt->ops->name, "WEP") == 0 ) + ext->alg = IW_ENCODE_ALG_WEP; + else if (strcmp(crypt->ops->name, "TKIP")) + ext->alg = IW_ENCODE_ALG_TKIP; + else if (strcmp(crypt->ops->name, "CCMP")) + ext->alg = IW_ENCODE_ALG_CCMP; + else + return -EINVAL; + ext->key_len = crypt->ops->get_key(ext->key, SCM_KEY_LEN, NULL, crypt->priv); + encoding->flags |= IW_ENCODE_ENABLED; + if (ext->key_len && + (ext->alg == IW_ENCODE_ALG_TKIP || + ext->alg == IW_ENCODE_ALG_CCMP)) + ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID; + + } + + return 0; +} + +int ieee80211_wx_set_mlme(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + struct iw_mlme *mlme = (struct iw_mlme *) extra; + switch (mlme->cmd) { + case IW_MLME_DEAUTH: + case IW_MLME_DISASSOC: + ieee80211_disassociate(ieee); + break; + default: + return -EOPNOTSUPP; + } +#endif + return 0; +} + +int ieee80211_wx_set_auth(struct ieee80211_device *ieee, + struct iw_request_info *info, + struct iw_param *data, char *extra) +{ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + switch (data->flags & IW_AUTH_INDEX) { + case IW_AUTH_WPA_VERSION: + /*need to support wpa2 here*/ + //printk("wpa version:%x\n", data->value); + break; + 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: + ieee->tkip_countermeasures = data->value; + break; + case IW_AUTH_DROP_UNENCRYPTED: + ieee->drop_unencrypted = data->value; + break; + + case IW_AUTH_80211_AUTH_ALG: + //printk("======>%s():data->value is %d\n",__FUNCTION__,data->value); + // ieee->open_wep = (data->value&IW_AUTH_ALG_OPEN_SYSTEM)?1:0; + if(data->value & IW_AUTH_ALG_SHARED_KEY){ + ieee->open_wep = 0; + ieee->auth_mode = 1; + } + else if(data->value & IW_AUTH_ALG_OPEN_SYSTEM){ + ieee->open_wep = 1; + ieee->auth_mode = 0; + } + else if(data->value & IW_AUTH_ALG_LEAP){ + ieee->open_wep = 1; + ieee->auth_mode = 2; + //printk("hahahaa:LEAP\n"); + } + else + return -EINVAL; + //printk("open_wep:%d\n", ieee->open_wep); + break; + +#if 1 + case IW_AUTH_WPA_ENABLED: + ieee->wpa_enabled = (data->value)?1:0; + //printk("enalbe wpa:%d\n", ieee->wpa_enabled); + break; + +#endif + case IW_AUTH_RX_UNENCRYPTED_EAPOL: + ieee->ieee802_1x = data->value; + break; + case IW_AUTH_PRIVACY_INVOKED: + ieee->privacy_invoked = data->value; + break; + default: + return -EOPNOTSUPP; + } +#endif + return 0; +} +#endif +#if 1 +int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len) +{ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) +#if 0 + printk("====>%s()\n", __FUNCTION__); + { + int i; + for (i=0; iMAX_WPA_IE_LEN || (len && ie == NULL)) + { + // printk("return error out, len:%d\n", len); + return -EINVAL; + } + + + if (len) + { + if (len != ie[1]+2) + { + printk("len:%d, ie:%d\n", len, ie[1]); + return -EINVAL; + } + buf = kmalloc(len, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + memcpy(buf, ie, len); + kfree(ieee->wpa_ie); + ieee->wpa_ie = buf; + ieee->wpa_ie_len = len; + } + else{ + if (ieee->wpa_ie) + kfree(ieee->wpa_ie); + ieee->wpa_ie = NULL; + ieee->wpa_ie_len = 0; + } +#endif + return 0; + +} +#endif + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) +EXPORT_SYMBOL(ieee80211_wx_set_gen_ie); +#if (WIRELESS_EXT >= 18) +EXPORT_SYMBOL(ieee80211_wx_set_mlme); +EXPORT_SYMBOL(ieee80211_wx_set_auth); +EXPORT_SYMBOL(ieee80211_wx_set_encode_ext); +EXPORT_SYMBOL(ieee80211_wx_get_encode_ext); +#endif +EXPORT_SYMBOL(ieee80211_wx_get_scan); +EXPORT_SYMBOL(ieee80211_wx_set_encode); +EXPORT_SYMBOL(ieee80211_wx_get_encode); +#else +EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_gen_ie); +//EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_mlme); +//EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_auth); +//EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_encode_ext); +EXPORT_SYMBOL_NOVERS(ieee80211_wx_get_scan); +EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_encode); +EXPORT_SYMBOL_NOVERS(ieee80211_wx_get_encode); +#endif diff --git a/drivers/staging/rtl8192su/ieee80211/internal.h b/drivers/staging/rtl8192su/ieee80211/internal.h new file mode 100644 index 000000000000..ddc22350d006 --- /dev/null +++ b/drivers/staging/rtl8192su/ieee80211/internal.h @@ -0,0 +1,115 @@ +/* + * Cryptographic API. + * + * Copyright (c) 2002 James Morris + * + * 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 _CRYPTO_INTERNAL_H +#define _CRYPTO_INTERNAL_H + + +//#include +#include "rtl_crypto.h" +#include +#include +#include +#include +#include +#include + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,20)) +#define list_for_each_entry(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + prefetch(pos->member.next); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member), \ + prefetch(pos->member.next)) + +static inline void cond_resched(void) +{ + if (need_resched()) { + set_current_state(TASK_RUNNING); + schedule(); + } +} +#endif + +extern enum km_type crypto_km_types[]; + +static inline enum km_type crypto_kmap_type(int out) +{ + return crypto_km_types[(in_softirq() ? 2 : 0) + out]; +} + +static inline void *crypto_kmap(struct page *page, int out) +{ + return kmap_atomic(page, crypto_kmap_type(out)); +} + +static inline void crypto_kunmap(void *vaddr, int out) +{ + kunmap_atomic(vaddr, crypto_kmap_type(out)); +} + +static inline void crypto_yield(struct crypto_tfm *tfm) +{ + if (!in_softirq()) + cond_resched(); +} + +static inline void *crypto_tfm_ctx(struct crypto_tfm *tfm) +{ + return (void *)&tfm[1]; +} + +struct crypto_alg *crypto_alg_lookup(const char *name); + +#ifdef CONFIG_KMOD +void crypto_alg_autoload(const char *name); +struct crypto_alg *crypto_alg_mod_lookup(const char *name); +#else +static inline struct crypto_alg *crypto_alg_mod_lookup(const char *name) +{ + return crypto_alg_lookup(name); +} +#endif + +#ifdef CONFIG_CRYPTO_HMAC +int crypto_alloc_hmac_block(struct crypto_tfm *tfm); +void crypto_free_hmac_block(struct crypto_tfm *tfm); +#else +static inline int crypto_alloc_hmac_block(struct crypto_tfm *tfm) +{ + return 0; +} + +static inline void crypto_free_hmac_block(struct crypto_tfm *tfm) +{ } +#endif + +#ifdef CONFIG_PROC_FS +void __init crypto_init_proc(void); +#else +static inline void crypto_init_proc(void) +{ } +#endif + +int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags); +int crypto_init_cipher_flags(struct crypto_tfm *tfm, u32 flags); +int crypto_init_compress_flags(struct crypto_tfm *tfm, u32 flags); + +int crypto_init_digest_ops(struct crypto_tfm *tfm); +int crypto_init_cipher_ops(struct crypto_tfm *tfm); +int crypto_init_compress_ops(struct crypto_tfm *tfm); + +void crypto_exit_digest_ops(struct crypto_tfm *tfm); +void crypto_exit_cipher_ops(struct crypto_tfm *tfm); +void crypto_exit_compress_ops(struct crypto_tfm *tfm); + +#endif /* _CRYPTO_INTERNAL_H */ + diff --git a/drivers/staging/rtl8192su/ieee80211/kmap_types.h b/drivers/staging/rtl8192su/ieee80211/kmap_types.h new file mode 100644 index 000000000000..de67bb01b5f5 --- /dev/null +++ b/drivers/staging/rtl8192su/ieee80211/kmap_types.h @@ -0,0 +1,20 @@ +#ifndef __KMAP_TYPES_H + +#define __KMAP_TYPES_H + + +enum km_type { + KM_BOUNCE_READ, + KM_SKB_SUNRPC_DATA, + KM_SKB_DATA_SOFTIRQ, + KM_USER0, + KM_USER1, + KM_BH_IRQ, + KM_SOFTIRQ0, + KM_SOFTIRQ1, + KM_TYPE_NR +}; + +#define _ASM_KMAP_TYPES_H + +#endif diff --git a/drivers/staging/rtl8192su/ieee80211/michael_mic.c b/drivers/staging/rtl8192su/ieee80211/michael_mic.c new file mode 100644 index 000000000000..df256e487c20 --- /dev/null +++ b/drivers/staging/rtl8192su/ieee80211/michael_mic.c @@ -0,0 +1,194 @@ +/* + * Cryptographic API + * + * Michael MIC (IEEE 802.11i/TKIP) keyed digest + * + * Copyright (c) 2004 Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +//#include +#include "rtl_crypto.h" + + +struct michael_mic_ctx { + u8 pending[4]; + size_t pending_len; + + u32 l, r; +}; + + +static inline u32 rotl(u32 val, int bits) +{ + return (val << bits) | (val >> (32 - bits)); +} + + +static inline u32 rotr(u32 val, int bits) +{ + return (val >> bits) | (val << (32 - bits)); +} + + +static inline u32 xswap(u32 val) +{ + return ((val & 0x00ff00ff) << 8) | ((val & 0xff00ff00) >> 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 get_le32(const u8 *p) +{ + return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); +} + + +static inline void put_le32(u8 *p, u32 v) +{ + p[0] = v; + p[1] = v >> 8; + p[2] = v >> 16; + p[3] = v >> 24; +} + + +static void michael_init(void *ctx) +{ + struct michael_mic_ctx *mctx = ctx; + mctx->pending_len = 0; +} + + +static void michael_update(void *ctx, const u8 *data, unsigned int len) +{ + struct michael_mic_ctx *mctx = ctx; + + if (mctx->pending_len) { + int flen = 4 - mctx->pending_len; + if (flen > len) + flen = len; + memcpy(&mctx->pending[mctx->pending_len], data, flen); + mctx->pending_len += flen; + data += flen; + len -= flen; + + if (mctx->pending_len < 4) + return; + + mctx->l ^= get_le32(mctx->pending); + michael_block(mctx->l, mctx->r); + mctx->pending_len = 0; + } + + while (len >= 4) { + mctx->l ^= get_le32(data); + michael_block(mctx->l, mctx->r); + data += 4; + len -= 4; + } + + if (len > 0) { + mctx->pending_len = len; + memcpy(mctx->pending, data, len); + } +} + + +static void michael_final(void *ctx, u8 *out) +{ + struct michael_mic_ctx *mctx = ctx; + u8 *data = mctx->pending; + + /* Last block and padding (0x5a, 4..7 x 0) */ + switch (mctx->pending_len) { + case 0: + mctx->l ^= 0x5a; + break; + case 1: + mctx->l ^= data[0] | 0x5a00; + break; + case 2: + mctx->l ^= data[0] | (data[1] << 8) | 0x5a0000; + break; + case 3: + mctx->l ^= data[0] | (data[1] << 8) | (data[2] << 16) | + 0x5a000000; + break; + } + michael_block(mctx->l, mctx->r); + /* l ^= 0; */ + michael_block(mctx->l, mctx->r); + + put_le32(out, mctx->l); + put_le32(out + 4, mctx->r); +} + + +static int michael_setkey(void *ctx, const u8 *key, unsigned int keylen, + u32 *flags) +{ + struct michael_mic_ctx *mctx = ctx; + if (keylen != 8) { + if (flags) + *flags = CRYPTO_TFM_RES_BAD_KEY_LEN; + return -EINVAL; + } + mctx->l = get_le32(key); + mctx->r = get_le32(key + 4); + return 0; +} + + +static struct crypto_alg michael_mic_alg = { + .cra_name = "michael_mic", + .cra_flags = CRYPTO_ALG_TYPE_DIGEST, + .cra_blocksize = 8, + .cra_ctxsize = sizeof(struct michael_mic_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(michael_mic_alg.cra_list), + .cra_u = { .digest = { + .dia_digestsize = 8, + .dia_init = michael_init, + .dia_update = michael_update, + .dia_final = michael_final, + .dia_setkey = michael_setkey } } +}; + + +static int __init michael_mic_init(void) +{ + return crypto_register_alg(&michael_mic_alg); +} + + +static void __exit michael_mic_exit(void) +{ + crypto_unregister_alg(&michael_mic_alg); +} + + +module_init(michael_mic_init); +module_exit(michael_mic_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Michael MIC"); +MODULE_AUTHOR("Jouni Malinen "); diff --git a/drivers/staging/rtl8192su/ieee80211/proc.c b/drivers/staging/rtl8192su/ieee80211/proc.c new file mode 100644 index 000000000000..4f3f9ed7751a --- /dev/null +++ b/drivers/staging/rtl8192su/ieee80211/proc.c @@ -0,0 +1,116 @@ +/* + * Scatterlist Cryptographic API. + * + * Procfs information. + * + * Copyright (c) 2002 James Morris + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ +#include +//#include +#include "rtl_crypto.h" +#include +#include +#include +#include "internal.h" + +extern struct list_head crypto_alg_list; +extern struct rw_semaphore crypto_alg_sem; + +static void *c_start(struct seq_file *m, loff_t *pos) +{ + struct list_head *v; + loff_t n = *pos; + + down_read(&crypto_alg_sem); + list_for_each(v, &crypto_alg_list) + if (!n--) + return list_entry(v, struct crypto_alg, cra_list); + return NULL; +} + +static void *c_next(struct seq_file *m, void *p, loff_t *pos) +{ + struct list_head *v = p; + + (*pos)++; + v = v->next; + return (v == &crypto_alg_list) ? + NULL : list_entry(v, struct crypto_alg, cra_list); +} + +static void c_stop(struct seq_file *m, void *p) +{ + up_read(&crypto_alg_sem); +} + +static int c_show(struct seq_file *m, void *p) +{ + struct crypto_alg *alg = (struct crypto_alg *)p; + + seq_printf(m, "name : %s\n", alg->cra_name); + seq_printf(m, "module : %s\n", + (alg->cra_module ? + alg->cra_module->name : + "kernel")); + + switch (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) { + case CRYPTO_ALG_TYPE_CIPHER: + seq_printf(m, "type : cipher\n"); + seq_printf(m, "blocksize : %u\n", alg->cra_blocksize); + seq_printf(m, "min keysize : %u\n", + alg->cra_cipher.cia_min_keysize); + seq_printf(m, "max keysize : %u\n", + alg->cra_cipher.cia_max_keysize); + break; + + case CRYPTO_ALG_TYPE_DIGEST: + seq_printf(m, "type : digest\n"); + seq_printf(m, "blocksize : %u\n", alg->cra_blocksize); + seq_printf(m, "digestsize : %u\n", + alg->cra_digest.dia_digestsize); + break; + case CRYPTO_ALG_TYPE_COMPRESS: + seq_printf(m, "type : compression\n"); + break; + default: + seq_printf(m, "type : unknown\n"); + break; + } + + seq_putc(m, '\n'); + return 0; +} + +static struct seq_operations crypto_seq_ops = { + .start = c_start, + .next = c_next, + .stop = c_stop, + .show = c_show +}; + +static int crypto_info_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &crypto_seq_ops); +} + +static struct file_operations proc_crypto_ops = { + .open = crypto_info_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release +}; + +void __init crypto_init_proc(void) +{ + struct proc_dir_entry *proc; + + proc = create_proc_entry("crypto", 0, NULL); + if (proc) + proc->proc_fops = &proc_crypto_ops; +} diff --git a/drivers/staging/rtl8192su/ieee80211/readme b/drivers/staging/rtl8192su/ieee80211/readme new file mode 100644 index 000000000000..5764f2859286 --- /dev/null +++ b/drivers/staging/rtl8192su/ieee80211/readme @@ -0,0 +1,162 @@ +What this layer should do + +- It mantain the old mechanism as alternative, so the + ipw2100 driver works with really few changes. +- Encapsulate / Decapsulate ieee80211 packet +- Handle fragmentation +- Optionally provide an alterantive mechanism for netif queue stop/wake, + so that the ieee80211 layer will pass one fragment per time instead of + one txb struct per time. so the driver can stop the queue in the middle + of a packet. +- Provide two different TX interfaces for cards that can handle management + frames on one HW queue, and data on another, and for cards that have only + one HW queue (the latter untested and very, very rough). +- Optionally provide the logic for handling IBSS/MASTER/MONITOR/BSS modes + and for the channel, essid and wap get/set wireless extension requests. + so that the driver has only to change channel when the ieee stack tell it. +- Optionally provide a scanning mechanism so that the driver has not to + worry about this, just implement the set channel calback and pass + frames to the upper layer +- Optionally provide the bss client protocol handshaking (just with open + authentication) +- Optionally provide the probe request send mechanism +- Optionally provide the bss master mode logic to handle association + protocol (only open authentication) and probe responses. +- SW wep encryption (with open authentication) +- It collects some stats +- It provides beacons to the card when it ask for them + +What this layer doesn't do (yet) +- Perform shared authentication +- Have full support for master mode (the AP should loop back in the air + frames from an associated client to another. This could be done easily + with few lines of code, and it is done in my previous version of the + stach, but a table of association must be keept and a disassociation + policy must be decided and implemented. +- Handle cleanly the full ieee 802.11 protocol. In AP mode it never + disassociate clients, and it is really prone to always allow access. + In bss client mode it is a bit rough with AP deauth and disassoc requests. +- It has not any entry point to view the collected stats. +- Altought it takes care of the card supported rates in the management frame + it sends, support for rate changing on TXed packet is not complete. +- Give up once associated in bss client mode (it never detect a + signal loss condition to disassociate and restart scanning) +- Provide a mechanism for enabling the TX in monitor mode, so + userspace programs can TX raw packets. +- Provide a mechanism for cards that need that the SW take care of beacon + TX completely, in sense that the SW has to enqueue by itself beacons + to the card so it TX them (if any...) +APIs + +Callback functions in the original stack has been mantained. +following has been added (from ieee80211.h) + + /* Softmac-generated frames (mamagement) are TXed via this + * callback if the flag IEEE_SOFTMAC_SINGLE_QUEUE is + * not set. As some cards may have different HW queues that + * one might want to use for data and management frames + * the option to have two callbacks might be useful. + * This fucntion can't sleep. + */ + int (*softmac_hard_start_xmit)(struct sk_buff *skb, + struct net_device *dev); + + /* used instead of hard_start_xmit (not softmac_hard_start_xmit) + * if the IEEE_SOFTMAC_TX_QUEUE feature is used to TX data + * frames. I the option IEEE_SOFTMAC_SINGLE_QUEUE is also set + * then also management frames are sent via this callback. + * This function can't sleep. + */ + void (*softmac_data_hard_start_xmit)(struct sk_buff *skb, + struct net_device *dev); + + /* stops the HW queue for DATA frames. Useful to avoid + * waste time to TX data frame when we are reassociating + * This function can sleep. + */ + void (*data_hard_stop)(struct net_device *dev); + + /* OK this is complementar to data_poll_hard_stop */ + void (*data_hard_resume)(struct net_device *dev); + + /* ask to the driver to retune the radio . + * This function can sleep. the driver should ensure + * the radio has been swithced before return. + */ + void (*set_chan)(struct net_device *dev,short ch); + + /* These are not used if the ieee stack takes care of + * scanning (IEEE_SOFTMAC_SCAN feature set). + * In this case only the set_chan is used. + * + * The syncro version is similar to the start_scan but + * does not return until all channels has been scanned. + * this is called in user context and should sleep, + * it is called in a work_queue when swithcing to ad-hoc mode + * or in behalf of iwlist scan when the card is associated + * and root user ask for a scan. + * the fucntion stop_scan should stop both the syncro and + * background scanning and can sleep. + * The fucntion start_scan should initiate the background + * scanning and can't sleep. + */ + void (*scan_syncro)(struct net_device *dev); + void (*start_scan)(struct net_device *dev); + void (*stop_scan)(struct net_device *dev); + + /* indicate the driver that the link state is changed + * for example it may indicate the card is associated now. + * Driver might be interested in this to apply RX filter + * rules or simply light the LINK led + */ + void (*link_change)(struct net_device *dev); + +Functions hard_data_[resume/stop] are optional and should not be used +if the driver decides to uses data+management frames enqueue in a +single HQ queue (thus using just the softmac_hard_data_start_xmit +callback). + +Function that the driver can use are: + +ieee80211_get_beacon - this is called by the driver when + the HW needs a beacon. +ieee80211_softmac_start_protocol - this should normally be called in the + driver open function +ieee80211_softmac_stop_protocol - the opposite of the above +ieee80211_wake_queue - this is similar to netif_wake_queue +ieee80211_reset_queue - this throw away fragments pending(if any) +ieee80211_stop_queue - this is similar to netif_stop_queue + + +known BUGS: +- When performing syncro scan (possiblily when swithcing to ad-hoc mode + and when running iwlist scan when associated) there is still an odd + behaviour.. I have not looked in this more accurately (yet). + +locking: +locking is done by means of three structures. +1- ieee->lock (by means of spin_[un]lock_irq[save/restore] +2- ieee->wx_sem +3- ieee->scan_sem + +the lock 1 is what protect most of the critical sections in the ieee stack. +the lock 2 is used to avoid that more than one of the SET wireless extension +handlers (as well as start/stop protocol function) are running at the same time. +the lock 1 is used when we need to modify or read the shared data in the wx handlers. +In other words the lock 2 will prevent one SET action will run across another SET +action (by make sleep the 2nd one) but allow GET actions, while the lock 1 +make atomic those little shared data access in both GET and SET operation. +So get operation will be never be delayed really: they will never sleep.. +Furthermore in the top of some SET operations a flag is set before acquiring +the lock. This is an help to make the previous running SET operation to +finish faster if needed (just in case the second one will totally undo the +first, so there is not need to complete the 1st really.. ). +The background scanning mechaninsm is protected by the lock 1 except for the +workqueue. this wq is here just to let the set_chan callback sleep (I thinked it +might be appreciated by USB network card driver developer). In this case the lock 3 +take its turn. +Thus the stop function needs both the locks. +Funny in the syncro scan the lock 2 play its role (as both the syncro_scan +function and the stop scan function are called with this semaphore held). + + diff --git a/drivers/staging/rtl8192su/ieee80211/rtl819x_BA.h b/drivers/staging/rtl8192su/ieee80211/rtl819x_BA.h new file mode 100644 index 000000000000..8ddc8bf9dc26 --- /dev/null +++ b/drivers/staging/rtl8192su/ieee80211/rtl819x_BA.h @@ -0,0 +1,69 @@ +#ifndef _BATYPE_H_ +#define _BATYPE_H_ + +#define TOTAL_TXBA_NUM 16 +#define TOTAL_RXBA_NUM 16 + +#define BA_SETUP_TIMEOUT 200 +#define BA_INACT_TIMEOUT 60000 + +#define BA_POLICY_DELAYED 0 +#define BA_POLICY_IMMEDIATE 1 + +#define ADDBA_STATUS_SUCCESS 0 +#define ADDBA_STATUS_REFUSED 37 +#define ADDBA_STATUS_INVALID_PARAM 38 + +#define DELBA_REASON_QSTA_LEAVING 36 +#define DELBA_REASON_END_BA 37 +#define DELBA_REASON_UNKNOWN_BA 38 +#define DELBA_REASON_TIMEOUT 39 +/* whether need define BA Action frames here? +struct ieee80211_ADDBA_Req{ + struct ieee80211_header_data header; + u8 category; + u8 +} __attribute__ ((packed)); +*/ +//Is this need?I put here just to make it easier to define structure BA_RECORD //WB +typedef union _SEQUENCE_CONTROL{ + u16 ShortData; + struct + { + u16 FragNum:4; + u16 SeqNum:12; + }field; +}SEQUENCE_CONTROL, *PSEQUENCE_CONTROL; + +typedef union _BA_PARAM_SET { + u8 charData[2]; + u16 shortData; + struct { + u16 AMSDU_Support:1; + u16 BAPolicy:1; + u16 TID:4; + u16 BufferSize:10; + } field; +} BA_PARAM_SET, *PBA_PARAM_SET; + +typedef union _DELBA_PARAM_SET { + u8 charData[2]; + u16 shortData; + struct { + u16 Reserved:11; + u16 Initiator:1; + u16 TID:4; + } field; +} DELBA_PARAM_SET, *PDELBA_PARAM_SET; + +typedef struct _BA_RECORD { + struct timer_list Timer; + u8 bValid; + u8 DialogToken; + BA_PARAM_SET BaParamSet; + u16 BaTimeoutValue; + SEQUENCE_CONTROL BaStartSeqCtrl; +} BA_RECORD, *PBA_RECORD; + +#endif //end _BATYPE_H_ + diff --git a/drivers/staging/rtl8192su/ieee80211/rtl819x_BAProc.c b/drivers/staging/rtl8192su/ieee80211/rtl819x_BAProc.c new file mode 100644 index 000000000000..cc5623a94b42 --- /dev/null +++ b/drivers/staging/rtl8192su/ieee80211/rtl819x_BAProc.c @@ -0,0 +1,781 @@ +/******************************************************************************************************************************** + * This file is created to process BA Action Frame. According to 802.11 spec, there are 3 BA action types at all. And as BA is + * related to TS, this part need some struture defined in QOS side code. Also TX RX is going to be resturctured, so how to send + * ADDBAREQ ADDBARSP and DELBA packet is still on consideration. Temporarily use MANAGE QUEUE instead of Normal Queue. + * WB 2008-05-27 + * *****************************************************************************************************************************/ +#include "ieee80211.h" +#include "rtl819x_BA.h" + +/******************************************************************************************************************** + *function: Activate BA entry. And if Time is nozero, start timer. + * input: PBA_RECORD pBA //BA entry to be enabled + * u16 Time //indicate time delay. + * output: none +********************************************************************************************************************/ +void ActivateBAEntry(struct ieee80211_device* ieee, PBA_RECORD pBA, u16 Time) +{ + pBA->bValid = true; + if(Time != 0) + mod_timer(&pBA->Timer, jiffies + MSECS(Time)); +} + +/******************************************************************************************************************** + *function: deactivate BA entry, including its timer. + * input: PBA_RECORD pBA //BA entry to be disabled + * output: none +********************************************************************************************************************/ +void DeActivateBAEntry( struct ieee80211_device* ieee, PBA_RECORD pBA) +{ + pBA->bValid = false; + del_timer_sync(&pBA->Timer); +} +/******************************************************************************************************************** + *function: deactivete BA entry in Tx Ts, and send DELBA. + * input: + * PTX_TS_RECORD pTxTs //Tx Ts which is to deactivate BA entry. + * output: none + * notice: As PTX_TS_RECORD structure will be defined in QOS, so wait to be merged. //FIXME +********************************************************************************************************************/ +u8 TxTsDeleteBA( struct ieee80211_device* ieee, PTX_TS_RECORD pTxTs) +{ + PBA_RECORD pAdmittedBa = &pTxTs->TxAdmittedBARecord; //These two BA entries must exist in TS structure + PBA_RECORD pPendingBa = &pTxTs->TxPendingBARecord; + u8 bSendDELBA = false; + + // Delete pending BA + if(pPendingBa->bValid) + { + DeActivateBAEntry(ieee, pPendingBa); + bSendDELBA = true; + } + + // Delete admitted BA + if(pAdmittedBa->bValid) + { + DeActivateBAEntry(ieee, pAdmittedBa); + bSendDELBA = true; + } + + return bSendDELBA; +} + +/******************************************************************************************************************** + *function: deactivete BA entry in Tx Ts, and send DELBA. + * input: + * PRX_TS_RECORD pRxTs //Rx Ts which is to deactivate BA entry. + * output: none + * notice: As PRX_TS_RECORD structure will be defined in QOS, so wait to be merged. //FIXME, same with above +********************************************************************************************************************/ +u8 RxTsDeleteBA( struct ieee80211_device* ieee, PRX_TS_RECORD pRxTs) +{ + PBA_RECORD pBa = &pRxTs->RxAdmittedBARecord; + u8 bSendDELBA = false; + + if(pBa->bValid) + { + DeActivateBAEntry(ieee, pBa); + bSendDELBA = true; + } + + return bSendDELBA; +} + +/******************************************************************************************************************** + *function: reset BA entry + * input: + * PBA_RECORD pBA //entry to be reset + * output: none +********************************************************************************************************************/ +void ResetBaEntry( PBA_RECORD pBA) +{ + pBA->bValid = false; + pBA->BaParamSet.shortData = 0; + pBA->BaTimeoutValue = 0; + pBA->DialogToken = 0; + pBA->BaStartSeqCtrl.ShortData = 0; +} +//These functions need porting here or not? +/******************************************************************************************************************************* + *function: construct ADDBAREQ and ADDBARSP frame here together. + * input: u8* Dst //ADDBA frame's destination + * PBA_RECORD pBA //BA_RECORD entry which stores the necessary information for BA. + * u16 StatusCode //status code in RSP and I will use it to indicate whether it's RSP or REQ(will I?) + * u8 type //indicate whether it's RSP(ACT_ADDBARSP) ow REQ(ACT_ADDBAREQ) + * output: none + * return: sk_buff* skb //return constructed skb to xmit +*******************************************************************************************************************************/ +static struct sk_buff* ieee80211_ADDBA(struct ieee80211_device* ieee, u8* Dst, PBA_RECORD pBA, u16 StatusCode, u8 type) +{ + struct sk_buff *skb = NULL; + struct ieee80211_hdr_3addr* BAReq = NULL; + u8* tag = NULL; + u16 tmp = 0; + u16 len = ieee->tx_headroom + 9; + //category(1) + action field(1) + Dialog Token(1) + BA Parameter Set(2) + BA Timeout Value(2) + BA Start SeqCtrl(2)(or StatusCode(2)) + IEEE80211_DEBUG(IEEE80211_DL_TRACE | IEEE80211_DL_BA, "========>%s(), frame(%d) sentd to:"MAC_FMT", ieee->dev:%p\n", __FUNCTION__, type, MAC_ARG(Dst), ieee->dev); + if (pBA == NULL||ieee == NULL) + { + IEEE80211_DEBUG(IEEE80211_DL_ERR, "pBA(%p) is NULL or ieee(%p) is NULL\n", pBA, ieee); + return NULL; + } + skb = dev_alloc_skb(len + sizeof( struct ieee80211_hdr_3addr)); //need to add something others? FIXME + if (skb == NULL) + { + IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't alloc skb for ADDBA_REQ\n"); + return NULL; + } + + memset(skb->data, 0, sizeof( struct ieee80211_hdr_3addr)); //I wonder whether it's necessary. Apparently kernel will not do it when alloc a skb. + skb_reserve(skb, ieee->tx_headroom); + + BAReq = ( struct ieee80211_hdr_3addr *) skb_put(skb,sizeof( struct ieee80211_hdr_3addr)); + + memcpy(BAReq->addr1, Dst, ETH_ALEN); + memcpy(BAReq->addr2, ieee->dev->dev_addr, ETH_ALEN); + + memcpy(BAReq->addr3, ieee->current_network.bssid, ETH_ALEN); + + BAReq->frame_ctl = cpu_to_le16(IEEE80211_STYPE_MANAGE_ACT); //action frame + + //tag += sizeof( struct ieee80211_hdr_3addr); //move to action field + tag = (u8*)skb_put(skb, 9); + *tag ++= ACT_CAT_BA; + *tag ++= type; + // Dialog Token + *tag ++= pBA->DialogToken; + + if (ACT_ADDBARSP == type) + { + // Status Code + printk("=====>to send ADDBARSP\n"); + tmp = cpu_to_le16(StatusCode); + memcpy(tag, (u8*)&tmp, 2); + tag += 2; + } + // BA Parameter Set + tmp = cpu_to_le16(pBA->BaParamSet.shortData); + memcpy(tag, (u8*)&tmp, 2); + tag += 2; + // BA Timeout Value + tmp = cpu_to_le16(pBA->BaTimeoutValue); + memcpy(tag, (u8*)&tmp, 2); + tag += 2; + + if (ACT_ADDBAREQ == type) + { + // BA Start SeqCtrl + memcpy(tag,(u8*)&(pBA->BaStartSeqCtrl), 2); + tag += 2; + } + + IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA|IEEE80211_DL_BA, skb->data, skb->len); + return skb; + //return NULL; +} + +#if 0 //I try to merge ADDBA_REQ and ADDBA_RSP frames together.. +/******************************************************************************************************************** + *function: construct ADDBAREQ frame + * input: u8* dst //ADDBARsp frame's destination + * PBA_RECORD pBA //BA_RECORD entry which stores the necessary information for BA_RSP. + * u16 StatusCode //status code. + * output: none + * return: sk_buff* skb //return constructed skb to xmit +********************************************************************************************************************/ +static struct sk_buff* ieee80211_ADDBA_Rsp( IN struct ieee80211_device* ieee, u8* dst, PBA_RECORD pBA, u16 StatusCode) +{ + OCTET_STRING osADDBAFrame, tmp; + + FillOctetString(osADDBAFrame, Buffer, 0); + *pLength = 0; + + ConstructMaFrameHdr( + Adapter, + Addr, + ACT_CAT_BA, + ACT_ADDBARSP, + &osADDBAFrame ); + + // Dialog Token + FillOctetString(tmp, &pBA->DialogToken, 1); + PacketAppendData(&osADDBAFrame, tmp); + + // Status Code + FillOctetString(tmp, &StatusCode, 2); + PacketAppendData(&osADDBAFrame, tmp); + + // BA Parameter Set + FillOctetString(tmp, &pBA->BaParamSet, 2); + PacketAppendData(&osADDBAFrame, tmp); + + // BA Timeout Value + FillOctetString(tmp, &pBA->BaTimeoutValue, 2); + PacketAppendData(&osADDBAFrame, tmp); + + *pLength = osADDBAFrame.Length; +} +#endif + +/******************************************************************************************************************** + *function: construct DELBA frame + * input: u8* dst //DELBA frame's destination + * PBA_RECORD pBA //BA_RECORD entry which stores the necessary information for BA + * TR_SELECT TxRxSelect //TX RX direction + * u16 ReasonCode //status code. + * output: none + * return: sk_buff* skb //return constructed skb to xmit +********************************************************************************************************************/ +static struct sk_buff* ieee80211_DELBA( + struct ieee80211_device* ieee, + u8* dst, + PBA_RECORD pBA, + TR_SELECT TxRxSelect, + u16 ReasonCode + ) +{ + DELBA_PARAM_SET DelbaParamSet; + struct sk_buff *skb = NULL; + struct ieee80211_hdr_3addr* Delba = NULL; + u8* tag = NULL; + u16 tmp = 0; + //len = head len + DELBA Parameter Set(2) + Reason Code(2) + u16 len = 6 + ieee->tx_headroom; + + if (net_ratelimit()) + IEEE80211_DEBUG(IEEE80211_DL_TRACE | IEEE80211_DL_BA, "========>%s(), ReasonCode(%d) sentd to:"MAC_FMT"\n", __FUNCTION__, ReasonCode, MAC_ARG(dst)); + + memset(&DelbaParamSet, 0, 2); + + DelbaParamSet.field.Initiator = (TxRxSelect==TX_DIR)?1:0; + DelbaParamSet.field.TID = pBA->BaParamSet.field.TID; + + skb = dev_alloc_skb(len + sizeof( struct ieee80211_hdr_3addr)); //need to add something others? FIXME + if (skb == NULL) + { + IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't alloc skb for ADDBA_REQ\n"); + return NULL; + } +// memset(skb->data, 0, len+sizeof( struct ieee80211_hdr_3addr)); + skb_reserve(skb, ieee->tx_headroom); + + Delba = ( struct ieee80211_hdr_3addr *) skb_put(skb,sizeof( struct ieee80211_hdr_3addr)); + + memcpy(Delba->addr1, dst, ETH_ALEN); + memcpy(Delba->addr2, ieee->dev->dev_addr, ETH_ALEN); + memcpy(Delba->addr3, ieee->current_network.bssid, ETH_ALEN); + Delba->frame_ctl = cpu_to_le16(IEEE80211_STYPE_MANAGE_ACT); //action frame + + tag = (u8*)skb_put(skb, 6); + + *tag ++= ACT_CAT_BA; + *tag ++= ACT_DELBA; + + // DELBA Parameter Set + tmp = cpu_to_le16(DelbaParamSet.shortData); + memcpy(tag, (u8*)&tmp, 2); + tag += 2; + // Reason Code + tmp = cpu_to_le16(ReasonCode); + memcpy(tag, (u8*)&tmp, 2); + tag += 2; + + IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA|IEEE80211_DL_BA, skb->data, skb->len); + if (net_ratelimit()) + IEEE80211_DEBUG(IEEE80211_DL_TRACE | IEEE80211_DL_BA, "<=====%s()\n", __FUNCTION__); + return skb; +} + +/******************************************************************************************************************** + *function: send ADDBAReq frame out + * input: u8* dst //ADDBAReq frame's destination + * PBA_RECORD pBA //BA_RECORD entry which stores the necessary information for BA + * output: none + * notice: If any possible, please hide pBA in ieee. And temporarily use Manage Queue as softmac_mgmt_xmit() usually does +********************************************************************************************************************/ +void ieee80211_send_ADDBAReq(struct ieee80211_device* ieee, u8* dst, PBA_RECORD pBA) +{ + struct sk_buff *skb = NULL; + skb = ieee80211_ADDBA(ieee, dst, pBA, 0, ACT_ADDBAREQ); //construct ACT_ADDBAREQ frames so set statuscode zero. + + if (skb) + { + softmac_mgmt_xmit(skb, ieee); + //add statistic needed here. + //and skb will be freed in softmac_mgmt_xmit(), so omit all dev_kfree_skb_any() outside softmac_mgmt_xmit() + //WB + } + else + { + IEEE80211_DEBUG(IEEE80211_DL_ERR, "alloc skb error in function %s()\n", __FUNCTION__); + } + return; +} + +/******************************************************************************************************************** + *function: send ADDBARSP frame out + * input: u8* dst //DELBA frame's destination + * PBA_RECORD pBA //BA_RECORD entry which stores the necessary information for BA + * u16 StatusCode //RSP StatusCode + * output: none + * notice: If any possible, please hide pBA in ieee. And temporarily use Manage Queue as softmac_mgmt_xmit() usually does +********************************************************************************************************************/ +void ieee80211_send_ADDBARsp(struct ieee80211_device* ieee, u8* dst, PBA_RECORD pBA, u16 StatusCode) +{ + struct sk_buff *skb = NULL; + skb = ieee80211_ADDBA(ieee, dst, pBA, StatusCode, ACT_ADDBARSP); //construct ACT_ADDBARSP frames + if (skb) + { + softmac_mgmt_xmit(skb, ieee); + //same above + } + else + { + IEEE80211_DEBUG(IEEE80211_DL_ERR, "alloc skb error in function %s()\n", __FUNCTION__); + } + + return; + +} +/******************************************************************************************************************** + *function: send ADDBARSP frame out + * input: u8* dst //DELBA frame's destination + * PBA_RECORD pBA //BA_RECORD entry which stores the necessary information for BA + * TR_SELECT TxRxSelect //TX or RX + * u16 ReasonCode //DEL ReasonCode + * output: none + * notice: If any possible, please hide pBA in ieee. And temporarily use Manage Queue as softmac_mgmt_xmit() usually does +********************************************************************************************************************/ + +void ieee80211_send_DELBA(struct ieee80211_device* ieee, u8* dst, PBA_RECORD pBA, TR_SELECT TxRxSelect, u16 ReasonCode) +{ + struct sk_buff *skb = NULL; + skb = ieee80211_DELBA(ieee, dst, pBA, TxRxSelect, ReasonCode); //construct ACT_ADDBARSP frames + if (skb) + { + softmac_mgmt_xmit(skb, ieee); + //same above + } + else + { + IEEE80211_DEBUG(IEEE80211_DL_ERR, "alloc skb error in function %s()\n", __FUNCTION__); + } + return ; +} + +/******************************************************************************************************************** + *function: RX ADDBAReq + * input: struct sk_buff * skb //incoming ADDBAReq skb. + * return: 0(pass), other(fail) + * notice: As this function need support of QOS, I comment some code out. And when qos is ready, this code need to be support. +********************************************************************************************************************/ +int ieee80211_rx_ADDBAReq( struct ieee80211_device* ieee, struct sk_buff *skb) +{ + struct ieee80211_hdr_3addr* req = NULL; + u16 rc = 0; + u8 * dst = NULL, *pDialogToken = NULL, *tag = NULL; + PBA_RECORD pBA = NULL; + PBA_PARAM_SET pBaParamSet = NULL; + u16* pBaTimeoutVal = NULL; + PSEQUENCE_CONTROL pBaStartSeqCtrl = NULL; + PRX_TS_RECORD pTS = NULL; + + if (skb->len < sizeof( struct ieee80211_hdr_3addr) + 9) + { + IEEE80211_DEBUG(IEEE80211_DL_ERR, " Invalid skb len in BAREQ(%d / %d)\n", skb->len, (sizeof( struct ieee80211_hdr_3addr) + 9)); + return -1; + } + + IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA|IEEE80211_DL_BA, skb->data, skb->len); + + req = ( struct ieee80211_hdr_3addr*) skb->data; + tag = (u8*)req; + dst = (u8*)(&req->addr2[0]); + tag += sizeof( struct ieee80211_hdr_3addr); + pDialogToken = tag + 2; //category+action + pBaParamSet = (PBA_PARAM_SET)(tag + 3); //+DialogToken + pBaTimeoutVal = (u16*)(tag + 5); + pBaStartSeqCtrl = (PSEQUENCE_CONTROL)(req + 7); + + printk("====================>rx ADDBAREQ from :"MAC_FMT"\n", MAC_ARG(dst)); +//some other capability is not ready now. + if( (ieee->current_network.qos_data.active == 0) || + (ieee->pHTInfo->bCurrentHTSupport == false) || + (ieee->pHTInfo->IOTAction & HT_IOT_ACT_REJECT_ADDBA_REQ)) //|| + // (ieee->pStaQos->bEnableRxImmBA == false) ) + { + rc = ADDBA_STATUS_REFUSED; + IEEE80211_DEBUG(IEEE80211_DL_ERR, "Failed to reply on ADDBA_REQ as some capability is not ready(%d, %d)\n", ieee->current_network.qos_data.active, ieee->pHTInfo->bCurrentHTSupport); + goto OnADDBAReq_Fail; + } + // Search for related traffic stream. + // If there is no matched TS, reject the ADDBA request. + if( !GetTs( + ieee, + (PTS_COMMON_INFO*)(&pTS), + dst, + (u8)(pBaParamSet->field.TID), + RX_DIR, + true) ) + { + rc = ADDBA_STATUS_REFUSED; + IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't get TS in %s()\n", __FUNCTION__); + goto OnADDBAReq_Fail; + } + pBA = &pTS->RxAdmittedBARecord; + // To Determine the ADDBA Req content + // We can do much more check here, including BufferSize, AMSDU_Support, Policy, StartSeqCtrl... + // I want to check StartSeqCtrl to make sure when we start aggregation!!! + // + if(pBaParamSet->field.BAPolicy == BA_POLICY_DELAYED) + { + rc = ADDBA_STATUS_INVALID_PARAM; + IEEE80211_DEBUG(IEEE80211_DL_ERR, "BA Policy is not correct in %s()\n", __FUNCTION__); + goto OnADDBAReq_Fail; + } + // Admit the ADDBA Request + // + DeActivateBAEntry(ieee, pBA); + pBA->DialogToken = *pDialogToken; + pBA->BaParamSet = *pBaParamSet; + pBA->BaTimeoutValue = *pBaTimeoutVal; + pBA->BaStartSeqCtrl = *pBaStartSeqCtrl; + //for half N mode we only aggregate 1 frame + if (ieee->GetHalfNmodeSupportByAPsHandler(ieee->dev)|| + (ieee->pHTInfo->IOTAction & HT_IOT_ACT_ALLOW_PEER_AGG_ONE_PKT)) + pBA->BaParamSet.field.BufferSize = 1; + else + pBA->BaParamSet.field.BufferSize = 32; + ActivateBAEntry(ieee, pBA, 0);//pBA->BaTimeoutValue); + ieee80211_send_ADDBARsp(ieee, dst, pBA, ADDBA_STATUS_SUCCESS); + + // End of procedure. + return 0; + +OnADDBAReq_Fail: + { + BA_RECORD BA; + BA.BaParamSet = *pBaParamSet; + BA.BaTimeoutValue = *pBaTimeoutVal; + BA.DialogToken = *pDialogToken; + BA.BaParamSet.field.BAPolicy = BA_POLICY_IMMEDIATE; + ieee80211_send_ADDBARsp(ieee, dst, &BA, rc); + return 0; //we send RSP out. + } + +} + +/******************************************************************************************************************** + *function: RX ADDBARSP + * input: struct sk_buff * skb //incoming ADDBAReq skb. + * return: 0(pass), other(fail) + * notice: As this function need support of QOS, I comment some code out. And when qos is ready, this code need to be support. +********************************************************************************************************************/ +int ieee80211_rx_ADDBARsp( struct ieee80211_device* ieee, struct sk_buff *skb) +{ + struct ieee80211_hdr_3addr* rsp = NULL; + PBA_RECORD pPendingBA, pAdmittedBA; + PTX_TS_RECORD pTS = NULL; + u8* dst = NULL, *pDialogToken = NULL, *tag = NULL; + u16* pStatusCode = NULL, *pBaTimeoutVal = NULL; + PBA_PARAM_SET pBaParamSet = NULL; + u16 ReasonCode; + + if (skb->len < sizeof( struct ieee80211_hdr_3addr) + 9) + { + IEEE80211_DEBUG(IEEE80211_DL_ERR, " Invalid skb len in BARSP(%d / %d)\n", skb->len, (sizeof( struct ieee80211_hdr_3addr) + 9)); + return -1; + } + rsp = ( struct ieee80211_hdr_3addr*)skb->data; + tag = (u8*)rsp; + dst = (u8*)(&rsp->addr2[0]); + tag += sizeof( struct ieee80211_hdr_3addr); + pDialogToken = tag + 2; + pStatusCode = (u16*)(tag + 3); + pBaParamSet = (PBA_PARAM_SET)(tag + 5); + pBaTimeoutVal = (u16*)(tag + 7); + + // Check the capability + // Since we can always receive A-MPDU, we just check if it is under HT mode. + if( ieee->current_network.qos_data.active == 0 || + ieee->pHTInfo->bCurrentHTSupport == false || + ieee->pHTInfo->bCurrentAMPDUEnable == false ) + { + IEEE80211_DEBUG(IEEE80211_DL_ERR, "reject to ADDBA_RSP as some capability is not ready(%d, %d, %d)\n",ieee->current_network.qos_data.active, ieee->pHTInfo->bCurrentHTSupport, ieee->pHTInfo->bCurrentAMPDUEnable); + ReasonCode = DELBA_REASON_UNKNOWN_BA; + goto OnADDBARsp_Reject; + } + + + // + // Search for related TS. + // If there is no TS found, we wil reject ADDBA Rsp by sending DELBA frame. + // + if (!GetTs( + ieee, + (PTS_COMMON_INFO*)(&pTS), + dst, + (u8)(pBaParamSet->field.TID), + TX_DIR, + false) ) + { + IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't get TS in %s()\n", __FUNCTION__); + ReasonCode = DELBA_REASON_UNKNOWN_BA; + goto OnADDBARsp_Reject; + } + + pTS->bAddBaReqInProgress = false; + pPendingBA = &pTS->TxPendingBARecord; + pAdmittedBA = &pTS->TxAdmittedBARecord; + + + // + // Check if related BA is waiting for setup. + // If not, reject by sending DELBA frame. + // + if((pAdmittedBA->bValid==true)) + { + // Since BA is already setup, we ignore all other ADDBA Response. + IEEE80211_DEBUG(IEEE80211_DL_BA, "OnADDBARsp(): Recv ADDBA Rsp. Drop because already admit it! \n"); + return -1; + } + else if((pPendingBA->bValid == false) ||(*pDialogToken != pPendingBA->DialogToken)) + { + IEEE80211_DEBUG(IEEE80211_DL_ERR, "OnADDBARsp(): Recv ADDBA Rsp. BA invalid, DELBA! \n"); + ReasonCode = DELBA_REASON_UNKNOWN_BA; + goto OnADDBARsp_Reject; + } + else + { + IEEE80211_DEBUG(IEEE80211_DL_BA, "OnADDBARsp(): Recv ADDBA Rsp. BA is admitted! Status code:%X\n", *pStatusCode); + DeActivateBAEntry(ieee, pPendingBA); + } + + + if(*pStatusCode == ADDBA_STATUS_SUCCESS) + { + // + // Determine ADDBA Rsp content here. + // We can compare the value of BA parameter set that Peer returned and Self sent. + // If it is OK, then admitted. Or we can send DELBA to cancel BA mechanism. + // + if(pBaParamSet->field.BAPolicy == BA_POLICY_DELAYED) + { + // Since this is a kind of ADDBA failed, we delay next ADDBA process. + pTS->bAddBaReqDelayed = true; + DeActivateBAEntry(ieee, pAdmittedBA); + ReasonCode = DELBA_REASON_END_BA; + goto OnADDBARsp_Reject; + } + + + // + // Admitted condition + // + pAdmittedBA->DialogToken = *pDialogToken; + pAdmittedBA->BaTimeoutValue = *pBaTimeoutVal; + pAdmittedBA->BaStartSeqCtrl = pPendingBA->BaStartSeqCtrl; + pAdmittedBA->BaParamSet = *pBaParamSet; + DeActivateBAEntry(ieee, pAdmittedBA); + ActivateBAEntry(ieee, pAdmittedBA, *pBaTimeoutVal); + } + else + { + // Delay next ADDBA process. + pTS->bAddBaReqDelayed = true; + } + + // End of procedure + return 0; + +OnADDBARsp_Reject: + { + BA_RECORD BA; + BA.BaParamSet = *pBaParamSet; + ieee80211_send_DELBA(ieee, dst, &BA, TX_DIR, ReasonCode); + return 0; + } + +} + +/******************************************************************************************************************** + *function: RX DELBA + * input: struct sk_buff * skb //incoming ADDBAReq skb. + * return: 0(pass), other(fail) + * notice: As this function need support of QOS, I comment some code out. And when qos is ready, this code need to be support. +********************************************************************************************************************/ +int ieee80211_rx_DELBA(struct ieee80211_device* ieee,struct sk_buff *skb) +{ + struct ieee80211_hdr_3addr* delba = NULL; + PDELBA_PARAM_SET pDelBaParamSet = NULL; + u16* pReasonCode = NULL; + u8* dst = NULL; + + if (skb->len < sizeof( struct ieee80211_hdr_3addr) + 6) + { + IEEE80211_DEBUG(IEEE80211_DL_ERR, " Invalid skb len in DELBA(%d / %d)\n", skb->len, (sizeof( struct ieee80211_hdr_3addr) + 6)); + return -1; + } + + if(ieee->current_network.qos_data.active == 0 || + ieee->pHTInfo->bCurrentHTSupport == false ) + { + IEEE80211_DEBUG(IEEE80211_DL_ERR, "received DELBA while QOS or HT is not supported(%d, %d)\n",ieee->current_network.qos_data.active, ieee->pHTInfo->bCurrentHTSupport); + return -1; + } + + IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA|IEEE80211_DL_BA, skb->data, skb->len); + delba = ( struct ieee80211_hdr_3addr*)skb->data; + dst = (u8*)(&delba->addr2[0]); + delba += sizeof( struct ieee80211_hdr_3addr); + pDelBaParamSet = (PDELBA_PARAM_SET)(delba+2); + pReasonCode = (u16*)(delba+4); + + if(pDelBaParamSet->field.Initiator == 1) + { + PRX_TS_RECORD pRxTs; + + if( !GetTs( + ieee, + (PTS_COMMON_INFO*)&pRxTs, + dst, + (u8)pDelBaParamSet->field.TID, + RX_DIR, + false) ) + { + IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't get TS for RXTS in %s()\n", __FUNCTION__); + return -1; + } + + RxTsDeleteBA(ieee, pRxTs); + } + else + { + PTX_TS_RECORD pTxTs; + + if(!GetTs( + ieee, + (PTS_COMMON_INFO*)&pTxTs, + dst, + (u8)pDelBaParamSet->field.TID, + TX_DIR, + false) ) + { + IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't get TS for TXTS in %s()\n", __FUNCTION__); + return -1; + } + + pTxTs->bUsingBa = false; + pTxTs->bAddBaReqInProgress = false; + pTxTs->bAddBaReqDelayed = false; + del_timer_sync(&pTxTs->TsAddBaTimer); + //PlatformCancelTimer(Adapter, &pTxTs->TsAddBaTimer); + TxTsDeleteBA(ieee, pTxTs); + } + return 0; +} + +// +// ADDBA initiate. This can only be called by TX side. +// +void +TsInitAddBA( + struct ieee80211_device* ieee, + PTX_TS_RECORD pTS, + u8 Policy, + u8 bOverwritePending + ) +{ + PBA_RECORD pBA = &pTS->TxPendingBARecord; + + if(pBA->bValid==true && bOverwritePending==false) + return; + + // Set parameters to "Pending" variable set + DeActivateBAEntry(ieee, pBA); + + pBA->DialogToken++; // DialogToken: Only keep the latest dialog token + pBA->BaParamSet.field.AMSDU_Support = 0; // Do not support A-MSDU with A-MPDU now!! + pBA->BaParamSet.field.BAPolicy = Policy; // Policy: Delayed or Immediate + pBA->BaParamSet.field.TID = pTS->TsCommonInfo.TSpec.f.TSInfo.field.ucTSID; // TID + // BufferSize: This need to be set according to A-MPDU vector + pBA->BaParamSet.field.BufferSize = 32; // BufferSize: This need to be set according to A-MPDU vector + pBA->BaTimeoutValue = 0; // Timeout value: Set 0 to disable Timer + pBA->BaStartSeqCtrl.field.SeqNum = (pTS->TxCurSeq + 3) % 4096; // Block Ack will start after 3 packets later. + + ActivateBAEntry(ieee, pBA, BA_SETUP_TIMEOUT); + + ieee80211_send_ADDBAReq(ieee, pTS->TsCommonInfo.Addr, pBA); +} + +void +TsInitDelBA( struct ieee80211_device* ieee, PTS_COMMON_INFO pTsCommonInfo, TR_SELECT TxRxSelect) +{ + + if(TxRxSelect == TX_DIR) + { + PTX_TS_RECORD pTxTs = (PTX_TS_RECORD)pTsCommonInfo; + + if(TxTsDeleteBA(ieee, pTxTs)) + ieee80211_send_DELBA( + ieee, + pTsCommonInfo->Addr, + (pTxTs->TxAdmittedBARecord.bValid)?(&pTxTs->TxAdmittedBARecord):(&pTxTs->TxPendingBARecord), + TxRxSelect, + DELBA_REASON_END_BA); + } + else if(TxRxSelect == RX_DIR) + { + PRX_TS_RECORD pRxTs = (PRX_TS_RECORD)pTsCommonInfo; + if(RxTsDeleteBA(ieee, pRxTs)) + ieee80211_send_DELBA( + ieee, + pTsCommonInfo->Addr, + &pRxTs->RxAdmittedBARecord, + TxRxSelect, + DELBA_REASON_END_BA ); + } +} +/******************************************************************************************************************** + *function: BA setup timer + * input: unsigned long data //acturally we send TX_TS_RECORD or RX_TS_RECORD to these timer + * return: NULL + * notice: +********************************************************************************************************************/ +void BaSetupTimeOut(unsigned long data) +{ + PTX_TS_RECORD pTxTs = (PTX_TS_RECORD)data; + + pTxTs->bAddBaReqInProgress = false; + pTxTs->bAddBaReqDelayed = true; + pTxTs->TxPendingBARecord.bValid = false; +} + +void TxBaInactTimeout(unsigned long data) +{ + PTX_TS_RECORD pTxTs = (PTX_TS_RECORD)data; + struct ieee80211_device *ieee = container_of(pTxTs, struct ieee80211_device, TxTsRecord[pTxTs->num]); + TxTsDeleteBA(ieee, pTxTs); + ieee80211_send_DELBA( + ieee, + pTxTs->TsCommonInfo.Addr, + &pTxTs->TxAdmittedBARecord, + TX_DIR, + DELBA_REASON_TIMEOUT); +} + +void RxBaInactTimeout(unsigned long data) +{ + PRX_TS_RECORD pRxTs = (PRX_TS_RECORD)data; + struct ieee80211_device *ieee = container_of(pRxTs, struct ieee80211_device, RxTsRecord[pRxTs->num]); + + RxTsDeleteBA(ieee, pRxTs); + ieee80211_send_DELBA( + ieee, + pRxTs->TsCommonInfo.Addr, + &pRxTs->RxAdmittedBARecord, + RX_DIR, + DELBA_REASON_TIMEOUT); + return ; +} + diff --git a/drivers/staging/rtl8192su/ieee80211/rtl819x_HT.h b/drivers/staging/rtl8192su/ieee80211/rtl819x_HT.h new file mode 100644 index 000000000000..16a7462d7dfb --- /dev/null +++ b/drivers/staging/rtl8192su/ieee80211/rtl819x_HT.h @@ -0,0 +1,517 @@ +#ifndef _RTL819XU_HTTYPE_H_ +#define _RTL819XU_HTTYPE_H_ + +//------------------------------------------------------------ +// The HT Capability element is present in beacons, association request, +// reassociation request and probe response frames +//------------------------------------------------------------ + +// +// Operation mode value +// +#define HT_OPMODE_NO_PROTECT 0 +#define HT_OPMODE_OPTIONAL 1 +#define HT_OPMODE_40MHZ_PROTECT 2 +#define HT_OPMODE_MIXED 3 + +// +// MIMO Power Save Setings +// +#define MIMO_PS_STATIC 0 +#define MIMO_PS_DYNAMIC 1 +#define MIMO_PS_NOLIMIT 3 + + +// +// There should be 128 bits to cover all of the MCS rates. However, since +// 8190 does not support too much rates, one integer is quite enough. +// + +#define sHTCLng 4 + + +#define HT_SUPPORTED_MCS_1SS_BITMAP 0x000000ff +#define HT_SUPPORTED_MCS_2SS_BITMAP 0x0000ff00 +#define HT_SUPPORTED_MCS_1SS_2SS_BITMAP HT_MCS_1SS_BITMAP|HT_MCS_1SS_2SS_BITMAP + + +typedef enum _HT_MCS_RATE{ + HT_MCS0 = 0x00000001, + HT_MCS1 = 0x00000002, + HT_MCS2 = 0x00000004, + HT_MCS3 = 0x00000008, + HT_MCS4 = 0x00000010, + HT_MCS5 = 0x00000020, + HT_MCS6 = 0x00000040, + HT_MCS7 = 0x00000080, + HT_MCS8 = 0x00000100, + HT_MCS9 = 0x00000200, + HT_MCS10 = 0x00000400, + HT_MCS11 = 0x00000800, + HT_MCS12 = 0x00001000, + HT_MCS13 = 0x00002000, + HT_MCS14 = 0x00004000, + HT_MCS15 = 0x00008000, + // Do not define MCS32 here although 8190 support MCS32 +}HT_MCS_RATE,*PHT_MCS_RATE; + +// +// Represent Channel Width in HT Capabilities +// +typedef enum _HT_CHANNEL_WIDTH{ + HT_CHANNEL_WIDTH_20 = 0, + HT_CHANNEL_WIDTH_20_40 = 1, +}HT_CHANNEL_WIDTH, *PHT_CHANNEL_WIDTH; + +// +// Represent Extention Channel Offset in HT Capabilities +// This is available only in 40Mhz mode. +// +typedef enum _HT_EXTCHNL_OFFSET{ + HT_EXTCHNL_OFFSET_NO_EXT = 0, + HT_EXTCHNL_OFFSET_UPPER = 1, + HT_EXTCHNL_OFFSET_NO_DEF = 2, + HT_EXTCHNL_OFFSET_LOWER = 3, +}HT_EXTCHNL_OFFSET, *PHT_EXTCHNL_OFFSET; + +typedef enum _CHNLOP{ + CHNLOP_NONE = 0, // No Action now + CHNLOP_SCAN = 1, // Scan in progress + CHNLOP_SWBW = 2, // Bandwidth switching in progress + CHNLOP_SWCHNL = 3, // Software Channel switching in progress +} CHNLOP, *PCHNLOP; + +// Determine if the Channel Operation is in progress +#define CHHLOP_IN_PROGRESS(_pHTInfo) \ + ((_pHTInfo)->ChnlOp > CHNLOP_NONE) ? TRUE : FALSE + +/* +typedef union _HT_CAPABILITY{ + u16 ShortData; + u8 CharData[2]; + struct + { + u16 AdvCoding:1; + u16 ChlWidth:1; + u16 MimoPwrSave:2; + u16 GreenField:1; + u16 ShortGI20Mhz:1; + u16 ShortGI40Mhz:1; + u16 STBC:1; + u16 BeamForm:1; + u16 DelayBA:1; + u16 MaxAMSDUSize:1; + u16 DssCCk:1; + u16 PSMP:1; + u16 Rsvd:3; + }Field; +}HT_CAPABILITY, *PHT_CAPABILITY; + +typedef union _HT_CAPABILITY_MACPARA{ + u8 ShortData; + u8 CharData[1]; + struct + { + u8 MaxRxAMPDU:2; + u8 MPDUDensity:2; + u8 Rsvd:4; + }Field; +}HT_CAPABILITY_MACPARA, *PHT_CAPABILITY_MACPARA; +*/ + +typedef enum _HT_ACTION{ + ACT_RECOMMAND_WIDTH = 0, + ACT_MIMO_PWR_SAVE = 1, + ACT_PSMP = 2, + ACT_SET_PCO_PHASE = 3, + ACT_MIMO_CHL_MEASURE = 4, + ACT_RECIPROCITY_CORRECT = 5, + ACT_MIMO_CSI_MATRICS = 6, + ACT_MIMO_NOCOMPR_STEER = 7, + ACT_MIMO_COMPR_STEER = 8, + ACT_ANTENNA_SELECT = 9, +} HT_ACTION, *PHT_ACTION; + + +/* 2007/06/07 MH Define sub-carrier mode for 40MHZ. */ +typedef enum _HT_Bandwidth_40MHZ_Sub_Carrier{ + SC_MODE_DUPLICATE = 0, + SC_MODE_LOWER = 1, + SC_MODE_UPPER = 2, + SC_MODE_FULL40MHZ = 3, +}HT_BW40_SC_E; + +typedef struct _HT_CAPABILITY_ELE{ + + //HT capability info + u8 AdvCoding:1; + u8 ChlWidth:1; + u8 MimoPwrSave:2; + u8 GreenField:1; + u8 ShortGI20Mhz:1; + u8 ShortGI40Mhz:1; + u8 TxSTBC:1; + u8 RxSTBC:2; + u8 DelayBA:1; + u8 MaxAMSDUSize:1; + u8 DssCCk:1; + u8 PSMP:1; + u8 Rsvd1:1; + u8 LSigTxopProtect:1; + + //MAC HT parameters info + u8 MaxRxAMPDUFactor:2; + u8 MPDUDensity:3; + u8 Rsvd2:3; + + //Supported MCS set + u8 MCS[16]; + + + //Extended HT Capability Info + u16 ExtHTCapInfo; + + //TXBF Capabilities + u8 TxBFCap[4]; + + //Antenna Selection Capabilities + u8 ASCap; + +} __attribute__ ((packed)) HT_CAPABILITY_ELE, *PHT_CAPABILITY_ELE; + +//------------------------------------------------------------ +// The HT Information element is present in beacons +// Only AP is required to include this element +//------------------------------------------------------------ + +typedef struct _HT_INFORMATION_ELE{ + u8 ControlChl; + + u8 ExtChlOffset:2; + u8 RecommemdedTxWidth:1; + u8 RIFS:1; + u8 PSMPAccessOnly:1; + u8 SrvIntGranularity:3; + + u8 OptMode:2; + u8 NonGFDevPresent:1; + u8 Revd1:5; + u8 Revd2:8; + + u8 Rsvd3:6; + u8 DualBeacon:1; + u8 DualCTSProtect:1; + + u8 SecondaryBeacon:1; + u8 LSigTxopProtectFull:1; + u8 PcoActive:1; + u8 PcoPhase:1; + u8 Rsvd4:4; + + u8 BasicMSC[16]; +} __attribute__ ((packed)) HT_INFORMATION_ELE, *PHT_INFORMATION_ELE; + +// +// MIMO Power Save control field. +// This is appear in MIMO Power Save Action Frame +// +typedef struct _MIMOPS_CTRL{ + u8 MimoPsEnable:1; + u8 MimoPsMode:1; + u8 Reserved:6; +} MIMOPS_CTRL, *PMIMOPS_CTRL; + +typedef enum _HT_SPEC_VER{ + HT_SPEC_VER_IEEE = 0, + HT_SPEC_VER_EWC = 1, +}HT_SPEC_VER, *PHT_SPEC_VER; + +typedef enum _HT_AGGRE_MODE_E{ + HT_AGG_AUTO = 0, + HT_AGG_FORCE_ENABLE = 1, + HT_AGG_FORCE_DISABLE = 2, +}HT_AGGRE_MODE_E, *PHT_AGGRE_MODE_E; + +//------------------------------------------------------------ +// The Data structure is used to keep HT related variables when card is +// configured as non-AP STA mode. **Note** Current_xxx should be set +// to default value in HTInitializeHTInfo() +//------------------------------------------------------------ + +typedef struct _RT_HIGH_THROUGHPUT{ + u8 bEnableHT; + u8 bCurrentHTSupport; + + u8 bRegBW40MHz; // Tx 40MHz channel capablity + u8 bCurBW40MHz; // Tx 40MHz channel capability + + u8 bRegShortGI40MHz; // Tx Short GI for 40Mhz + u8 bCurShortGI40MHz; // Tx Short GI for 40MHz + + u8 bRegShortGI20MHz; // Tx Short GI for 20MHz + u8 bCurShortGI20MHz; // Tx Short GI for 20MHz + + u8 bRegSuppCCK; // Tx CCK rate capability + u8 bCurSuppCCK; // Tx CCK rate capability + + // 802.11n spec version for "peer" + HT_SPEC_VER ePeerHTSpecVer; + + + // HT related information for "Self" + HT_CAPABILITY_ELE SelfHTCap; // This is HT cap element sent to peer STA, which also indicate HT Rx capabilities. + HT_INFORMATION_ELE SelfHTInfo; // This is HT info element sent to peer STA, which also indicate HT Rx capabilities. + + // HT related information for "Peer" + u8 PeerHTCapBuf[32]; + u8 PeerHTInfoBuf[32]; + + + // A-MSDU related + u8 bAMSDU_Support; // This indicates Tx A-MSDU capability + u16 nAMSDU_MaxSize; // This indicates Tx A-MSDU capability + u8 bCurrent_AMSDU_Support; // This indicates Tx A-MSDU capability + u16 nCurrent_AMSDU_MaxSize; // This indicates Tx A-MSDU capability + + + // AMPDU related <2006.08.10 Emily> + u8 bAMPDUEnable; // This indicate Tx A-MPDU capability + u8 bCurrentAMPDUEnable; // This indicate Tx A-MPDU capability + u8 AMPDU_Factor; // This indicate Tx A-MPDU capability + u8 CurrentAMPDUFactor; // This indicate Tx A-MPDU capability + u8 MPDU_Density; // This indicate Tx A-MPDU capability + u8 CurrentMPDUDensity; // This indicate Tx A-MPDU capability + + // Forced A-MPDU enable + HT_AGGRE_MODE_E ForcedAMPDUMode; + u8 ForcedAMPDUFactor; + u8 ForcedMPDUDensity; + + // Forced A-MSDU enable + HT_AGGRE_MODE_E ForcedAMSDUMode; + u16 ForcedAMSDUMaxSize; + + u8 bForcedShortGI; + + u8 CurrentOpMode; + + // MIMO PS related + u8 SelfMimoPs; + u8 PeerMimoPs; + + // 40MHz Channel Offset settings. + HT_EXTCHNL_OFFSET CurSTAExtChnlOffset; + u8 bCurTxBW40MHz; // If we use 40 MHz to Tx + u8 PeerBandwidth; + + // For Bandwidth Switching + u8 bSwBwInProgress; + CHNLOP ChnlOp; // software switching channel in progress. By Bruce, 2008-02-15. + u8 SwBwStep; + //struct timer_list SwBwTimer; //moved to ieee80211_device. as timer_list need include some header file here. + + // For Realtek proprietary A-MPDU factor for aggregation + u8 bRegRT2RTAggregation; + u8 RT2RT_HT_Mode; + u8 bCurrentRT2RTAggregation; + u8 bCurrentRT2RTLongSlotTime; + u8 szRT2RTAggBuffer[10]; + + // Rx Reorder control + u8 bRegRxReorderEnable; + u8 bCurRxReorderEnable; + u8 RxReorderWinSize; + u8 RxReorderPendingTime; + u16 RxReorderDropCounter; + +#ifdef USB_TX_DRIVER_AGGREGATION_ENABLE + u8 UsbTxAggrNum; +#endif +#ifdef USB_RX_AGGREGATION_SUPPORT + u8 UsbRxFwAggrEn; + u8 UsbRxFwAggrPageNum; + u8 UsbRxFwAggrPacketNum; + u8 UsbRxFwAggrTimeout; +#endif + + // Add for Broadcom(Linksys) IOT. Joseph + u8 bIsPeerBcm; + + // For IOT issue. + u8 IOTPeer; + u32 IOTAction; + u8 IOTRaFunc; +} __attribute__ ((packed)) RT_HIGH_THROUGHPUT, *PRT_HIGH_THROUGHPUT; + + +//------------------------------------------------------------ +// The Data structure is used to keep HT related variable for "each Sta" +// when card is configured as "AP mode" +//------------------------------------------------------------ + +typedef struct _RT_HTINFO_STA_ENTRY{ + u8 bEnableHT; + + u8 bSupportCck; + + u16 AMSDU_MaxSize; + + u8 AMPDU_Factor; + u8 MPDU_Density; + + u8 HTHighestOperaRate; + + u8 bBw40MHz; + + u8 MimoPs; + + u8 McsRateSet[16]; + + +}RT_HTINFO_STA_ENTRY, *PRT_HTINFO_STA_ENTRY; + + + + + +//------------------------------------------------------------ +// The Data structure is used to keep HT related variable for "each AP" +// when card is configured as "STA mode" +//------------------------------------------------------------ + +typedef struct _BSS_HT{ + + u8 bdSupportHT; + + // HT related elements + u8 bdHTCapBuf[32]; + u16 bdHTCapLen; + u8 bdHTInfoBuf[32]; + u16 bdHTInfoLen; + + HT_SPEC_VER bdHTSpecVer; + //HT_CAPABILITY_ELE bdHTCapEle; + //HT_INFORMATION_ELE bdHTInfoEle; + + u8 bdRT2RTAggregation; + u8 bdRT2RTLongSlotTime; + u8 RT2RT_HT_Mode; + bool bdHT1R; +} __attribute__ ((packed)) BSS_HT, *PBSS_HT; + +typedef struct _MIMO_RSSI{ + u32 EnableAntenna; + u32 AntennaA; + u32 AntennaB; + u32 AntennaC; + u32 AntennaD; + u32 Average; +}MIMO_RSSI, *PMIMO_RSSI; + +typedef struct _MIMO_EVM{ + u32 EVM1; + u32 EVM2; +}MIMO_EVM, *PMIMO_EVM; + +typedef struct _FALSE_ALARM_STATISTICS{ + u32 Cnt_Parity_Fail; + u32 Cnt_Rate_Illegal; + u32 Cnt_Crc8_fail; + u32 Cnt_all; +}FALSE_ALARM_STATISTICS, *PFALSE_ALARM_STATISTICS; + + +extern u8 MCS_FILTER_ALL[16]; +extern u8 MCS_FILTER_1SS[16]; + +/* 2007/07/11 MH Modify the macro. Becaus STA may link with a N-AP. If we set + STA in A/B/G mode and AP is still in N mode. The macro will be wrong. We have + to add a macro to judge wireless mode. */ +#define PICK_RATE(_nLegacyRate, _nMcsRate) \ + (_nMcsRate==0)?(_nLegacyRate&0x7f):(_nMcsRate) +/* 2007/07/12 MH We only define legacy and HT wireless mode now. */ +#define LEGACY_WIRELESS_MODE IEEE_MODE_MASK + +#define CURRENT_RATE(WirelessMode, LegacyRate, HTRate) \ + ((WirelessMode & (LEGACY_WIRELESS_MODE))!=0)?\ + (LegacyRate):\ + (PICK_RATE(LegacyRate, HTRate)) + + + +// MCS Bw 40 {1~7, 12~15,32} +#define RATE_ADPT_1SS_MASK 0xFF +#define RATE_ADPT_2SS_MASK 0xF0 //Skip MCS8~11 because mcs7 > mcs6, 9, 10, 11. 2007.01.16 by Emily +#define RATE_ADPT_MCS32_MASK 0x01 + +#define IS_11N_MCS_RATE(rate) (rate&0x80) + +typedef enum _HT_AGGRE_SIZE{ + HT_AGG_SIZE_8K = 0, + HT_AGG_SIZE_16K = 1, + HT_AGG_SIZE_32K = 2, + HT_AGG_SIZE_64K = 3, +}HT_AGGRE_SIZE_E, *PHT_AGGRE_SIZE_E; + +/* Indicate different AP vendor for IOT issue */ +typedef enum _HT_IOT_PEER +{ + HT_IOT_PEER_UNKNOWN = 0, + HT_IOT_PEER_REALTEK = 1, + HT_IOT_PEER_REALTEK_92SE = 2, + HT_IOT_PEER_BROADCOM = 3, + HT_IOT_PEER_RALINK = 4, + HT_IOT_PEER_ATHEROS = 5, + HT_IOT_PEER_CISCO= 6, + HT_IOT_PEER_MARVELL=7, + HT_IOT_PEER_92U_SOFTAP = 8, + HT_IOT_PEER_SELF_SOFTAP = 9, + HT_IOT_PEER_MAX = 10, +}HT_IOT_PEER_E, *PHTIOT_PEER_E; + +// +// IOT Action for different AP +// +typedef enum _HT_IOT_ACTION{ + HT_IOT_ACT_TX_USE_AMSDU_4K = 0x00000001, + HT_IOT_ACT_TX_USE_AMSDU_8K = 0x00000002, + HT_IOT_ACT_DISABLE_MCS14 = 0x00000004, + HT_IOT_ACT_DISABLE_MCS15 = 0x00000008, + HT_IOT_ACT_DISABLE_ALL_2SS = 0x00000010, + HT_IOT_ACT_DISABLE_EDCA_TURBO = 0x00000020, + HT_IOT_ACT_MGNT_USE_CCK_6M = 0x00000040, + HT_IOT_ACT_CDD_FSYNC = 0x00000080, + HT_IOT_ACT_PURE_N_MODE = 0x00000100, + HT_IOT_ACT_FORCED_CTS2SELF = 0x00000200, + HT_IOT_ACT_FORCED_RTS = 0x00000400, + HT_IOT_ACT_AMSDU_ENABLE = 0x00000800, + HT_IOT_ACT_MID_HIGHPOWER = 0x00001000, + HT_IOT_ACT_REJECT_ADDBA_REQ = 0x00002000, + HT_IOT_ACT_ALLOW_PEER_AGG_ONE_PKT = 0x00004000, + HT_IOT_ACT_EDCA_BIAS_ON_RX = 0x00008000, + + HT_IOT_ACT_HYBRID_AGGREGATION = 0x00010000, + HT_IOT_ACT_DISABLE_SHORT_GI = 0x00020000, + HT_IOT_ACT_DISABLE_HIGH_POWER = 0x00040000, + HT_IOT_ACT_DISABLE_TX_40_MHZ = 0x00080000, + HT_IOT_ACT_TX_NO_AGGREGATION = 0x00100000, + HT_IOT_ACT_DISABLE_TX_2SS = 0x00200000, +}HT_IOT_ACTION_E, *PHT_IOT_ACTION_E; + +typedef enum _HT_IOT_RAFUNC{ + HT_IOT_RAFUNC_PEER_1R = 0x01, + HT_IOT_RAFUNC_TX_AMSDU = 0x02, + HT_IOT_RAFUNC_DISABLE_ALL = 0x80, +}HT_IOT_RAFUNC, *PHT_IOT_RAFUNC; + +typedef enum _RT_HT_CAP{ + RT_HT_CAP_USE_TURBO_AGGR = 0x01, + RT_HT_CAP_USE_LONG_PREAMBLE = 0x02, + RT_HT_CAP_USE_AMPDU = 0x04, + RT_HT_CAP_USE_WOW = 0x8, + RT_HT_CAP_USE_SOFTAP = 0x10, + RT_HT_CAP_USE_92SE = 0x20, +}RT_HT_CAPBILITY, *PRT_HT_CAPBILITY; + +#endif //_RTL819XU_HTTYPE_H_ + diff --git a/drivers/staging/rtl8192su/ieee80211/rtl819x_HTProc.c b/drivers/staging/rtl8192su/ieee80211/rtl819x_HTProc.c new file mode 100644 index 000000000000..f357085f6643 --- /dev/null +++ b/drivers/staging/rtl8192su/ieee80211/rtl819x_HTProc.c @@ -0,0 +1,2037 @@ + +//As this function is mainly ported from Windows driver, so leave the name little changed. If any confusion caused, tell me. Created by WB. 2008.05.08 +#include "ieee80211.h" +#include "rtl819x_HT.h" +u8 MCS_FILTER_ALL[16] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +u8 MCS_FILTER_1SS[16] = {0xff, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +u16 MCS_DATA_RATE[2][2][77] = + { { {13, 26, 39, 52, 78, 104, 117, 130, 26, 52, 78 ,104, 156, 208, 234, 260, + 39, 78, 117, 234, 312, 351, 390, 52, 104, 156, 208, 312, 416, 468, 520, + 0, 78, 104, 130, 117, 156, 195, 104, 130, 130, 156, 182, 182, 208, 156, 195, + 195, 234, 273, 273, 312, 130, 156, 181, 156, 181, 208, 234, 208, 234, 260, 260, + 286, 195, 234, 273, 234, 273, 312, 351, 312, 351, 390, 390, 429}, // Long GI, 20MHz + {14, 29, 43, 58, 87, 116, 130, 144, 29, 58, 87, 116, 173, 231, 260, 289, + 43, 87, 130, 173, 260, 347, 390, 433, 58, 116, 173, 231, 347, 462, 520, 578, + 0, 87, 116, 144, 130, 173, 217, 116, 144, 144, 173, 202, 202, 231, 173, 217, + 217, 260, 303, 303, 347, 144, 173, 202, 173, 202, 231, 260, 231, 260, 289, 289, + 318, 217, 260, 303, 260, 303, 347, 390, 347, 390, 433, 433, 477} }, // Short GI, 20MHz + { {27, 54, 81, 108, 162, 216, 243, 270, 54, 108, 162, 216, 324, 432, 486, 540, + 81, 162, 243, 324, 486, 648, 729, 810, 108, 216, 324, 432, 648, 864, 972, 1080, + 12, 162, 216, 270, 243, 324, 405, 216, 270, 270, 324, 378, 378, 432, 324, 405, + 405, 486, 567, 567, 648, 270, 324, 378, 324, 378, 432, 486, 432, 486, 540, 540, + 594, 405, 486, 567, 486, 567, 648, 729, 648, 729, 810, 810, 891}, // Long GI, 40MHz + {30, 60, 90, 120, 180, 240, 270, 300, 60, 120, 180, 240, 360, 480, 540, 600, + 90, 180, 270, 360, 540, 720, 810, 900, 120, 240, 360, 480, 720, 960, 1080, 1200, + 13, 180, 240, 300, 270, 360, 450, 240, 300, 300, 360, 420, 420, 480, 360, 450, + 450, 540, 630, 630, 720, 300, 360, 420, 360, 420, 480, 540, 480, 540, 600, 600, + 660, 450, 540, 630, 540, 630, 720, 810, 720, 810, 900, 900, 990} } // Short GI, 40MHz + }; + +static u8 UNKNOWN_BORADCOM[3] = {0x00, 0x14, 0xbf}; +static u8 LINKSYSWRT330_LINKSYSWRT300_BROADCOM[3] = {0x00, 0x1a, 0x70}; +static u8 LINKSYSWRT350_LINKSYSWRT150_BROADCOM[3] = {0x00, 0x1d, 0x7e}; +static u8 NETGEAR834Bv2_BROADCOM[3] = {0x00, 0x1b, 0x2f}; +static u8 BELKINF5D8233V1_RALINK[3] = {0x00, 0x17, 0x3f}; //cosa 03202008 +static u8 BELKINF5D82334V3_RALINK[3] = {0x00, 0x1c, 0xdf}; +static u8 PCI_RALINK[3] = {0x00, 0x90, 0xcc}; +static u8 EDIMAX_RALINK[3] = {0x00, 0x0e, 0x2e}; +static u8 AIRLINK_RALINK[3] = {0x00, 0x18, 0x02}; +static u8 DLINK_ATHEROS_1[3] = {0x00, 0x1c, 0xf0}; +static u8 DLINK_ATHEROS_2[3] = {0x00, 0x21, 0x91}; +static u8 CISCO_BROADCOM[3] = {0x00, 0x17, 0x94}; +static u8 LINKSYS_MARVELL_4400N[3] = {0x00, 0x14, 0xa4}; +// 2008/04/01 MH For Cisco G mode RX TP We need to change FW duration. Shoud we put the +// code in other place?? +//static u8 WIFI_CISCO_G_AP[3] = {0x00, 0x40, 0x96}; +/******************************************************************************************************************** + *function: This function update default settings in pHTInfo structure + * input: PRT_HIGH_THROUGHPUT pHTInfo + * output: none + * return: none + * notice: These value need be modified if any changes. + * *****************************************************************************************************************/ +void HTUpdateDefaultSetting(struct ieee80211_device* ieee) +{ + PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; + //const typeof( ((struct ieee80211_device *)0)->pHTInfo ) *__mptr = &pHTInfo; + + //printk("pHTinfo:%p, &pHTinfo:%p, mptr:%p, offsetof:%x\n", pHTInfo, &pHTInfo, __mptr, offsetof(struct ieee80211_device, pHTInfo)); + //printk("===>ieee:%p,\n", ieee); + // ShortGI support + pHTInfo->bRegShortGI20MHz= 1; + pHTInfo->bRegShortGI40MHz= 1; + + // 40MHz channel support + pHTInfo->bRegBW40MHz = 1; + + // CCK rate support in 40MHz channel + if(pHTInfo->bRegBW40MHz) + pHTInfo->bRegSuppCCK = 1; + else + pHTInfo->bRegSuppCCK = true; + + // AMSDU related + pHTInfo->nAMSDU_MaxSize = 7935UL; + pHTInfo->bAMSDU_Support = 0; + + // AMPDU related + pHTInfo->bAMPDUEnable = 1; //YJ,test,090311 + pHTInfo->AMPDU_Factor = 2; //// 0: 2n13(8K), 1:2n14(16K), 2:2n15(32K), 3:2n16(64k) + pHTInfo->MPDU_Density = 0;// 0: No restriction, 1: 1/8usec, 2: 1/4usec, 3: 1/2usec, 4: 1usec, 5: 2usec, 6: 4usec, 7:8usec + + // MIMO Power Save + pHTInfo->SelfMimoPs = 3;// 0: Static Mimo Ps, 1: Dynamic Mimo Ps, 3: No Limitation, 2: Reserved(Set to 3 automatically.) + if(pHTInfo->SelfMimoPs == 2) + pHTInfo->SelfMimoPs = 3; + // 8190 only. Assign rate operation mode to firmware + ieee->bTxDisableRateFallBack = 0; + ieee->bTxUseDriverAssingedRate = 0; + +#ifdef TO_DO_LIST + // 8190 only. Assign duration operation mode to firmware + pMgntInfo->bTxEnableFwCalcDur = (BOOLEAN)pNdisCommon->bRegTxEnableFwCalcDur; +#endif + // 8190 only, Realtek proprietary aggregation mode + // Set MPDUDensity=2, 1: Set MPDUDensity=2(32k) for Realtek AP and set MPDUDensity=0(8k) for others + pHTInfo->bRegRT2RTAggregation = 1;//0: Set MPDUDensity=2, 1: Set MPDUDensity=2(32k) for Realtek AP and set MPDUDensity=0(8k) for others + + // For Rx Reorder Control + pHTInfo->bRegRxReorderEnable = 1;//YJ,test,090311 + pHTInfo->RxReorderWinSize = 64; + pHTInfo->RxReorderPendingTime = 30; + +#ifdef USB_TX_DRIVER_AGGREGATION_ENABLE + pHTInfo->UsbTxAggrNum = 4; +#endif +#ifdef USB_RX_AGGREGATION_SUPPORT +#ifdef RTL8192SU + pHTInfo->UsbRxFwAggrEn = 1; + pHTInfo->UsbRxFwAggrPageNum = 16; + pHTInfo->UsbRxFwAggrPacketNum = 8; + pHTInfo->UsbRxFwAggrTimeout = 4; ////usb rx FW aggregation timeout threshold.It's in units of 64us + // For page size of receive packet buffer. + pHTInfo->UsbRxPageSize= 128; +#else + pHTInfo->UsbRxFwAggrEn = 1; + pHTInfo->UsbRxFwAggrPageNum = 24; + pHTInfo->UsbRxFwAggrPacketNum = 8; + pHTInfo->UsbRxFwAggrTimeout = 16; ////usb rx FW aggregation timeout threshold.It's in units of 64us +#endif +#endif + + +} +/******************************************************************************************************************** + *function: This function print out each field on HT capability IE mainly from (Beacon/ProbeRsp/AssocReq) + * input: u8* CapIE //Capability IE to be printed out + * u8* TitleString //mainly print out caller function + * output: none + * return: none + * notice: Driver should not print out this message by default. + * *****************************************************************************************************************/ +void HTDebugHTCapability(u8* CapIE, u8* TitleString ) +{ + + static u8 EWC11NHTCap[] = {0x00, 0x90, 0x4c, 0x33}; // For 11n EWC definition, 2007.07.17, by Emily + PHT_CAPABILITY_ELE pCapELE; + + if(!memcmp(CapIE, EWC11NHTCap, sizeof(EWC11NHTCap))) + { + //EWC IE + IEEE80211_DEBUG(IEEE80211_DL_HT, "EWC IE in %s()\n", __FUNCTION__); + pCapELE = (PHT_CAPABILITY_ELE)(&CapIE[4]); + }else + pCapELE = (PHT_CAPABILITY_ELE)(&CapIE[0]); + + IEEE80211_DEBUG(IEEE80211_DL_HT, ". Called by %s\n", TitleString ); + + IEEE80211_DEBUG(IEEE80211_DL_HT, "\tSupported Channel Width = %s\n", (pCapELE->ChlWidth)?"20MHz": "20/40MHz"); + IEEE80211_DEBUG(IEEE80211_DL_HT, "\tSupport Short GI for 20M = %s\n", (pCapELE->ShortGI20Mhz)?"YES": "NO"); + IEEE80211_DEBUG(IEEE80211_DL_HT, "\tSupport Short GI for 40M = %s\n", (pCapELE->ShortGI40Mhz)?"YES": "NO"); + IEEE80211_DEBUG(IEEE80211_DL_HT, "\tSupport TX STBC = %s\n", (pCapELE->TxSTBC)?"YES": "NO"); + IEEE80211_DEBUG(IEEE80211_DL_HT, "\tMax AMSDU Size = %s\n", (pCapELE->MaxAMSDUSize)?"3839": "7935"); + IEEE80211_DEBUG(IEEE80211_DL_HT, "\tSupport CCK in 20/40 mode = %s\n", (pCapELE->DssCCk)?"YES": "NO"); + IEEE80211_DEBUG(IEEE80211_DL_HT, "\tMax AMPDU Factor = %d\n", pCapELE->MaxRxAMPDUFactor); + IEEE80211_DEBUG(IEEE80211_DL_HT, "\tMPDU Density = %d\n", pCapELE->MPDUDensity); + IEEE80211_DEBUG(IEEE80211_DL_HT, "\tMCS Rate Set = [%x][%x][%x][%x][%x]\n", pCapELE->MCS[0],\ + pCapELE->MCS[1], pCapELE->MCS[2], pCapELE->MCS[3], pCapELE->MCS[4]); + return; + +} +/******************************************************************************************************************** + *function: This function print out each field on HT Information IE mainly from (Beacon/ProbeRsp) + * input: u8* InfoIE //Capability IE to be printed out + * u8* TitleString //mainly print out caller function + * output: none + * return: none + * notice: Driver should not print out this message by default. + * *****************************************************************************************************************/ +void HTDebugHTInfo(u8* InfoIE, u8* TitleString) +{ + + static u8 EWC11NHTInfo[] = {0x00, 0x90, 0x4c, 0x34}; // For 11n EWC definition, 2007.07.17, by Emily + PHT_INFORMATION_ELE pHTInfoEle; + + if(!memcmp(InfoIE, EWC11NHTInfo, sizeof(EWC11NHTInfo))) + { + // Not EWC IE + IEEE80211_DEBUG(IEEE80211_DL_HT, "EWC IE in %s()\n", __FUNCTION__); + pHTInfoEle = (PHT_INFORMATION_ELE)(&InfoIE[4]); + }else + pHTInfoEle = (PHT_INFORMATION_ELE)(&InfoIE[0]); + + + IEEE80211_DEBUG(IEEE80211_DL_HT, ". Called by %s\n", TitleString); + + IEEE80211_DEBUG(IEEE80211_DL_HT, "\tPrimary channel = %d\n", pHTInfoEle->ControlChl); + IEEE80211_DEBUG(IEEE80211_DL_HT, "\tSenondary channel ="); + switch(pHTInfoEle->ExtChlOffset) + { + case 0: + IEEE80211_DEBUG(IEEE80211_DL_HT, "Not Present\n"); + break; + case 1: + IEEE80211_DEBUG(IEEE80211_DL_HT, "Upper channel\n"); + break; + case 2: + IEEE80211_DEBUG(IEEE80211_DL_HT, "Reserved. Eooro!!!\n"); + break; + case 3: + IEEE80211_DEBUG(IEEE80211_DL_HT, "Lower Channel\n"); + break; + } + IEEE80211_DEBUG(IEEE80211_DL_HT, "\tRecommended channel width = %s\n", (pHTInfoEle->RecommemdedTxWidth)?"20Mhz": "40Mhz"); + + IEEE80211_DEBUG(IEEE80211_DL_HT, "\tOperation mode for protection = "); + switch(pHTInfoEle->OptMode) + { + case 0: + IEEE80211_DEBUG(IEEE80211_DL_HT, "No Protection\n"); + break; + case 1: + IEEE80211_DEBUG(IEEE80211_DL_HT, "HT non-member protection mode\n"); + break; + case 2: + IEEE80211_DEBUG(IEEE80211_DL_HT, "Suggest to open protection\n"); + break; + case 3: + IEEE80211_DEBUG(IEEE80211_DL_HT, "HT mixed mode\n"); + break; + } + + IEEE80211_DEBUG(IEEE80211_DL_HT, "\tBasic MCS Rate Set = [%x][%x][%x][%x][%x]\n", pHTInfoEle->BasicMSC[0],\ + pHTInfoEle->BasicMSC[1], pHTInfoEle->BasicMSC[2], pHTInfoEle->BasicMSC[3], pHTInfoEle->BasicMSC[4]); + return; +} + +/* +* Return: true if station in half n mode and AP supports 40 bw +*/ +bool IsHTHalfNmode40Bandwidth(struct ieee80211_device* ieee) +{ + bool retValue = false; + PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; + + if(pHTInfo->bCurrentHTSupport == false ) // wireless is n mode + retValue = false; + else if(pHTInfo->bRegBW40MHz == false) // station supports 40 bw + retValue = false; + else if(!ieee->GetHalfNmodeSupportByAPsHandler(ieee->dev)) // station in half n mode + retValue = false; + else if(((PHT_CAPABILITY_ELE)(pHTInfo->PeerHTCapBuf))->ChlWidth) // ap support 40 bw + retValue = true; + else + retValue = false; + + return retValue; +} + +bool IsHTHalfNmodeSGI(struct ieee80211_device* ieee, bool is40MHz) +{ + bool retValue = false; + PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; + + if(pHTInfo->bCurrentHTSupport == false ) // wireless is n mode + retValue = false; + else if(!ieee->GetHalfNmodeSupportByAPsHandler(ieee->dev)) // station in half n mode + retValue = false; + else if(is40MHz) // ap support 40 bw + { + if(((PHT_CAPABILITY_ELE)(pHTInfo->PeerHTCapBuf))->ShortGI40Mhz) // ap support 40 bw short GI + retValue = true; + else + retValue = false; + } + else + { + if(((PHT_CAPABILITY_ELE)(pHTInfo->PeerHTCapBuf))->ShortGI20Mhz) // ap support 40 bw short GI + retValue = true; + else + retValue = false; + } + + return retValue; +} + +u16 HTHalfMcsToDataRate(struct ieee80211_device* ieee, u8 nMcsRate) +{ + + u8 is40MHz; + u8 isShortGI; + + is40MHz = (IsHTHalfNmode40Bandwidth(ieee))?1:0; + isShortGI = (IsHTHalfNmodeSGI(ieee, is40MHz))? 1:0; + + return MCS_DATA_RATE[is40MHz][isShortGI][(nMcsRate&0x7f)]; +} + + +u16 HTMcsToDataRate( struct ieee80211_device* ieee, u8 nMcsRate) +{ + PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; + + u8 is40MHz = (pHTInfo->bCurBW40MHz)?1:0; + u8 isShortGI = (pHTInfo->bCurBW40MHz)? + ((pHTInfo->bCurShortGI40MHz)?1:0): + ((pHTInfo->bCurShortGI20MHz)?1:0); + return MCS_DATA_RATE[is40MHz][isShortGI][(nMcsRate&0x7f)]; +} + +/******************************************************************************************************************** + *function: This function returns current datarate. + * input: struct ieee80211_device* ieee + * u8 nDataRate + * output: none + * return: tx rate + * notice: quite unsure about how to use this function //wb + * *****************************************************************************************************************/ +u16 TxCountToDataRate( struct ieee80211_device* ieee, u8 nDataRate) +{ + //PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; + u16 CCKOFDMRate[12] = {0x02 , 0x04 , 0x0b , 0x16 , 0x0c , 0x12 , 0x18 , 0x24 , 0x30 , 0x48 , 0x60 , 0x6c}; + u8 is40MHz = 0; + u8 isShortGI = 0; + + if(nDataRate < 12) + { + return CCKOFDMRate[nDataRate]; + } + else + { + if (nDataRate >= 0x10 && nDataRate <= 0x1f)//if(nDataRate > 11 && nDataRate < 28 ) + { + is40MHz = 0; + isShortGI = 0; + + // nDataRate = nDataRate - 12; + } + else if(nDataRate >=0x20 && nDataRate <= 0x2f ) //(27, 44) + { + is40MHz = 1; + isShortGI = 0; + + //nDataRate = nDataRate - 28; + } + else if(nDataRate >= 0x30 && nDataRate <= 0x3f ) //(43, 60) + { + is40MHz = 0; + isShortGI = 1; + + //nDataRate = nDataRate - 44; + } + else if(nDataRate >= 0x40 && nDataRate <= 0x4f ) //(59, 76) + { + is40MHz = 1; + isShortGI = 1; + + //nDataRate = nDataRate - 60; + } + return MCS_DATA_RATE[is40MHz][isShortGI][nDataRate&0xf]; + } +} + + + +bool IsHTHalfNmodeAPs(struct ieee80211_device* ieee) +{ + bool retValue = false; + struct ieee80211_network* net = &ieee->current_network; +#if 0 + if(pMgntInfo->bHalfNMode == false) + retValue = false; + else +#endif + if((memcmp(net->bssid, BELKINF5D8233V1_RALINK, 3)==0) || + (memcmp(net->bssid, BELKINF5D82334V3_RALINK, 3)==0) || + (memcmp(net->bssid, PCI_RALINK, 3)==0) || + (memcmp(net->bssid, EDIMAX_RALINK, 3)==0) || + (memcmp(net->bssid, AIRLINK_RALINK, 3)==0) || + (net->ralink_cap_exist)) + retValue = true; + else if((memcmp(net->bssid, UNKNOWN_BORADCOM, 3)==0) || + (memcmp(net->bssid, LINKSYSWRT330_LINKSYSWRT300_BROADCOM, 3)==0)|| + (memcmp(net->bssid, LINKSYSWRT350_LINKSYSWRT150_BROADCOM, 3)==0)|| + (memcmp(net->bssid, NETGEAR834Bv2_BROADCOM, 3)==0) || + (net->broadcom_cap_exist)) + retValue = true; + else if(net->bssht.bdRT2RTAggregation) + retValue = true; + else + retValue = false; + + return retValue; +} + +/******************************************************************************************************************** + *function: This function returns peer IOT. + * input: struct ieee80211_device* ieee + * output: none + * return: + * notice: + * *****************************************************************************************************************/ +void HTIOTPeerDetermine(struct ieee80211_device* ieee) +{ + PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; + struct ieee80211_network* net = &ieee->current_network; + //FIXME: need to decide 92U_SOFTAP //LZM,090320 + if(net->bssht.bdRT2RTAggregation){ + pHTInfo->IOTPeer = HT_IOT_PEER_REALTEK; + if(net->bssht.RT2RT_HT_Mode & RT_HT_CAP_USE_92SE){ + pHTInfo->IOTPeer = HT_IOT_PEER_REALTEK_92SE; + } + } + else if(net->broadcom_cap_exist) + pHTInfo->IOTPeer = HT_IOT_PEER_BROADCOM; + else if((memcmp(net->bssid, UNKNOWN_BORADCOM, 3)==0) || + (memcmp(net->bssid, LINKSYSWRT330_LINKSYSWRT300_BROADCOM, 3)==0)|| + (memcmp(net->bssid, LINKSYSWRT350_LINKSYSWRT150_BROADCOM, 3)==0)|| + (memcmp(net->bssid, NETGEAR834Bv2_BROADCOM, 3)==0) ) + pHTInfo->IOTPeer = HT_IOT_PEER_BROADCOM; + else if((memcmp(net->bssid, BELKINF5D8233V1_RALINK, 3)==0) || + (memcmp(net->bssid, BELKINF5D82334V3_RALINK, 3)==0) || + (memcmp(net->bssid, PCI_RALINK, 3)==0) || + (memcmp(net->bssid, EDIMAX_RALINK, 3)==0) || + (memcmp(net->bssid, AIRLINK_RALINK, 3)==0) || + net->ralink_cap_exist) + pHTInfo->IOTPeer = HT_IOT_PEER_RALINK; + else if((net->atheros_cap_exist )|| + (memcmp(net->bssid, DLINK_ATHEROS_1, 3) == 0)|| + (memcmp(net->bssid, DLINK_ATHEROS_2, 3) == 0)) + pHTInfo->IOTPeer = HT_IOT_PEER_ATHEROS; + else if(memcmp(net->bssid, CISCO_BROADCOM, 3)==0) + pHTInfo->IOTPeer = HT_IOT_PEER_CISCO; + else if ((memcmp(net->bssid, LINKSYS_MARVELL_4400N, 3) == 0) || + net->marvell_cap_exist) + pHTInfo->IOTPeer = HT_IOT_PEER_MARVELL; + else + pHTInfo->IOTPeer = HT_IOT_PEER_UNKNOWN; + + IEEE80211_DEBUG(IEEE80211_DL_IOT, "Joseph debug!! IOTPEER: %x\n", pHTInfo->IOTPeer); +} +/******************************************************************************************************************** + *function: Check whether driver should declare received rate up to MCS13 only since some chipset is not good + * at receiving MCS14~15 frame from some AP. + * input: struct ieee80211_device* ieee + * u8 * PeerMacAddr + * output: none + * return: return 1 if driver should declare MCS13 only(otherwise return 0) + * *****************************************************************************************************************/ +u8 HTIOTActIsDisableMCS14(struct ieee80211_device* ieee, u8* PeerMacAddr) +{ + u8 ret = 0; +#if 0 + // Apply for 819u only +#if (HAL_CODE_BASE==RTL8192 && DEV_BUS_TYPE==USB_INTERFACE) + if((memcmp(PeerMacAddr, UNKNOWN_BORADCOM, 3)==0) || + (memcmp(PeerMacAddr, LINKSYSWRT330_LINKSYSWRT300_BROADCOM, 3)==0) + ) + { + ret = 1; + } + + + if(pHTInfo->bCurrentRT2RTAggregation) + { + // The parameter of pHTInfo->bCurrentRT2RTAggregation must be decided previously + ret = 1; + } +#endif +#endif + return ret; + } + + +/** +* Function: HTIOTActIsDisableMCS15 +* +* Overview: Check whether driver should declare capability of receving MCS15 +* +* Input: +* PADAPTER Adapter, +* +* Output: None +* Return: true if driver should disable MCS15 +* 2008.04.15 Emily +*/ +bool HTIOTActIsDisableMCS15(struct ieee80211_device* ieee) +{ + bool retValue = false; + +#ifdef TODO + // Apply for 819u only +#if (HAL_CODE_BASE==RTL8192) + +#if (DEV_BUS_TYPE == USB_INTERFACE) + // Alway disable MCS15 by Jerry Chang's request.by Emily, 2008.04.15 + retValue = true; +#elif (DEV_BUS_TYPE == PCI_INTERFACE) + // Enable MCS15 if the peer is Cisco AP. by Emily, 2008.05.12 +// if(pBssDesc->bCiscoCapExist) +// retValue = false; +// else + retValue = false; +#endif +#endif +#endif + // Jerry Chang suggest that 8190 1x2 does not need to disable MCS15 + + return retValue; +} + +/** +* Function: HTIOTActIsDisableMCSTwoSpatialStream +* +* Overview: Check whether driver should declare capability of receving All 2 ss packets +* +* Input: +* PADAPTER Adapter, +* +* Output: None +* Return: true if driver should disable all two spatial stream packet +* 2008.04.21 Emily +*/ +bool HTIOTActIsDisableMCSTwoSpatialStream(struct ieee80211_device* ieee) +{ + bool retValue = false; +#ifdef TODO + // Apply for 819u only +//#if (HAL_CODE_BASE==RTL8192) + + //This rule only apply to Belkin(Ralink) AP + if(IS_UNDER_11N_AES_MODE(Adapter)) + { + if((PlatformCompareMemory(PeerMacAddr, BELKINF5D8233V1_RALINK, 3)==0) || + (PlatformCompareMemory(PeerMacAddr, PCI_RALINK, 3)==0) || + (PlatformCompareMemory(PeerMacAddr, EDIMAX_RALINK, 3)==0)) + { + //Set True to disable this function. Disable by default, Emily, 2008.04.23 + retValue = false; + } + } + +//#endif +#endif +#if 1 +#if (defined(RTL8192SE) || (defined(RTL8192SU))) + PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; + if(ieee->is_ap_in_wep_tkip && ieee->is_ap_in_wep_tkip(ieee->dev)) + { + if( (pHTInfo->IOTPeer != HT_IOT_PEER_ATHEROS) && + (pHTInfo->IOTPeer != HT_IOT_PEER_UNKNOWN) && + (pHTInfo->IOTPeer != HT_IOT_PEER_MARVELL) ) + retValue = true; + } +#endif +#endif + return retValue; +} + +/******************************************************************************************************************** + *function: Check whether driver should disable EDCA turbo mode + * input: struct ieee80211_device* ieee + * u8* PeerMacAddr + * output: none + * return: return 1 if driver should disable EDCA turbo mode(otherwise return 0) + * *****************************************************************************************************************/ +u8 HTIOTActIsDisableEDCATurbo(struct ieee80211_device* ieee, u8* PeerMacAddr) +{ + u8 retValue = false; // default enable EDCA Turbo mode. + // Set specific EDCA parameter for different AP in DM handler. + + return retValue; +#if 0 + if((memcmp(PeerMacAddr, UNKNOWN_BORADCOM, 3)==0)|| + (memcmp(PeerMacAddr, LINKSYSWRT330_LINKSYSWRT300_BROADCOM, 3)==0)|| + (memcmp(PeerMacAddr, LINKSYSWRT350_LINKSYSWRT150_BROADCOM, 3)==0)|| + (memcmp(PeerMacAddr, NETGEAR834Bv2_BROADCOM, 3)==0)) + + { + retValue = 1; //Linksys disable EDCA turbo mode + } + + return retValue; +#endif +} + +/******************************************************************************************************************** + *function: Check whether we need to use OFDM to sned MGNT frame for broadcom AP + * input: struct ieee80211_network *network //current network we live + * output: none + * return: return 1 if true + * *****************************************************************************************************************/ +u8 HTIOTActIsMgntUseCCK6M(struct ieee80211_network *network) +{ + u8 retValue = 0; + + // 2008/01/25 MH Judeg if we need to use OFDM to sned MGNT frame for broadcom AP. + // 2008/01/28 MH We must prevent that we select null bssid to link. + + if(network->broadcom_cap_exist) + { + retValue = 1; + } + + return retValue; +} + +u8 HTIOTActIsForcedCTS2Self(struct ieee80211_network *network) +{ + u8 retValue = 0; + + if(network->marvell_cap_exist) + { + retValue = 1; + } + + return retValue; +} + +u8 HTIOTActIsForcedRTSCTS(struct ieee80211_device *ieee, struct ieee80211_network *network) +{ + u8 retValue = 0; + printk("============>%s(), %d\n", __FUNCTION__, network->realtek_cap_exit); + // Force protection +#if defined(RTL8192SE) || defined(RTL8192SU) + if(ieee->pHTInfo->bCurrentHTSupport) + { + //if(!network->realtek_cap_exit) + if((ieee->pHTInfo->IOTPeer != HT_IOT_PEER_REALTEK)&& + (ieee->pHTInfo->IOTPeer != HT_IOT_PEER_REALTEK_92SE)) + { + if((ieee->pHTInfo->IOTAction & HT_IOT_ACT_TX_NO_AGGREGATION) == 0) + retValue = 1; + } + } +#endif + return retValue; +} + +u8 +HTIOTActIsForcedAMSDU8K(struct ieee80211_device *ieee, struct ieee80211_network *network) +{ + u8 retValue = 0; + + return retValue; +} + +u8 HTIOTActIsCCDFsync(u8* PeerMacAddr) +{ + u8 retValue = 0; +#ifndef RTL8192SE + if( (memcmp(PeerMacAddr, UNKNOWN_BORADCOM, 3)==0) || + (memcmp(PeerMacAddr, LINKSYSWRT330_LINKSYSWRT300_BROADCOM, 3)==0) || + (memcmp(PeerMacAddr, LINKSYSWRT350_LINKSYSWRT150_BROADCOM, 3) ==0)) + { + retValue = 1; + } +#endif + return retValue; +} + +/* + * 819xS single chip b-cut series cannot handle BAR + */ +u8 +HTIOCActRejcectADDBARequest(struct ieee80211_network *network) +{ + u8 retValue = 0; + //if(IS_HARDWARE_TYPE_8192SE(Adapter) || + // IS_HARDWARE_TYPE_8192SU(Adapter) + //) +#if (defined RTL8192SE || defined RTL8192SU) + { + // Do not reject ADDBA REQ because some of the AP may + // keep on sending ADDBA REQ qhich cause DHCP fail or ping loss! + // by HPFan, 2008/12/30 + + //if(pBssDesc->Vender == HT_IOT_PEER_MARVELL) + // return FALSE; + + } +#endif + + return retValue; + +} + +/* + * EDCA parameters bias on downlink + */ + u8 + HTIOTActIsEDCABiasRx(struct ieee80211_device* ieee,struct ieee80211_network *network) +{ + u8 retValue = 0; + //if(IS_HARDWARE_TYPE_8192SU(Adapter)) +#ifdef RTL8192SU + PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; + { +//#if UNDER_VISTA +// if(pBssDesc->Vender==HT_IOT_PEER_ATHEROS || +// pBssDesc->Vender==HT_IOT_PEER_RALINK) +//#else + if(pHTInfo->IOTPeer==HT_IOT_PEER_ATHEROS || + pHTInfo->IOTPeer==HT_IOT_PEER_BROADCOM || + pHTInfo->IOTPeer==HT_IOT_PEER_RALINK) +//#endif + return 1; + + } +#endif + return retValue; +} + +u8 +HTIOTActDisableShortGI(struct ieee80211_device* ieee,struct ieee80211_network *network) +{ + u8 retValue = 0; + PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; + + if(pHTInfo->IOTPeer==HT_IOT_PEER_RALINK) + { + if(network->bssht.bdHT1R) + retValue = 1; + } + + return retValue; +} + +u8 +HTIOTActDisableHighPower(struct ieee80211_device* ieee,struct ieee80211_network *network) +{ + u8 retValue = 0; + PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; + + if(pHTInfo->IOTPeer==HT_IOT_PEER_RALINK) + { + if(network->bssht.bdHT1R) + retValue = 1; + } + + return retValue; +} + +void +HTIOTActDetermineRaFunc(struct ieee80211_device* ieee, bool bPeerRx2ss) +{ + PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; + pHTInfo->IOTRaFunc &= HT_IOT_RAFUNC_DISABLE_ALL; + + if(pHTInfo->IOTPeer == HT_IOT_PEER_RALINK && !bPeerRx2ss) + pHTInfo->IOTRaFunc |= HT_IOT_RAFUNC_PEER_1R; + + if(pHTInfo->IOTAction & HT_IOT_ACT_AMSDU_ENABLE) + pHTInfo->IOTRaFunc |= HT_IOT_RAFUNC_TX_AMSDU; + + printk("!!!!!!!!!!!!!!!!!!!!!!!!!!!IOTRaFunc = %8.8x\n", pHTInfo->IOTRaFunc); +} + + +u8 +HTIOTActIsDisableTx40MHz(struct ieee80211_device* ieee,struct ieee80211_network *network) +{ + u8 retValue = 0; + +#if (defined RTL8192SU || defined RTL8192SE) + PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; + if( (KEY_TYPE_WEP104 == ieee->pairwise_key_type) || + (KEY_TYPE_WEP40 == ieee->pairwise_key_type) || + (KEY_TYPE_WEP104 == ieee->group_key_type) || + (KEY_TYPE_WEP40 == ieee->group_key_type) || + (KEY_TYPE_TKIP == ieee->pairwise_key_type) ) + { + if((pHTInfo->IOTPeer==HT_IOT_PEER_REALTEK) && (network->bssht.bdSupportHT)) + retValue = 1; + } +#endif + + return retValue; +} + +u8 +HTIOTActIsTxNoAggregation(struct ieee80211_device* ieee,struct ieee80211_network *network) +{ + u8 retValue = 0; + +#if (defined RTL8192SU || defined RTL8192SE) + PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; + if( (KEY_TYPE_WEP104 == ieee->pairwise_key_type) || + (KEY_TYPE_WEP40 == ieee->pairwise_key_type) || + (KEY_TYPE_WEP104 == ieee->group_key_type) || + (KEY_TYPE_WEP40 == ieee->group_key_type) || + (KEY_TYPE_TKIP == ieee->pairwise_key_type) ) + { + if(pHTInfo->IOTPeer==HT_IOT_PEER_REALTEK || + pHTInfo->IOTPeer==HT_IOT_PEER_UNKNOWN) + retValue = 1; + } +#endif + + return retValue; +} + + +u8 +HTIOTActIsDisableTx2SS(struct ieee80211_device* ieee,struct ieee80211_network *network) +{ + u8 retValue = 0; + +#if (defined RTL8192SU || defined RTL8192SE) + PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; + if( (KEY_TYPE_WEP104 == ieee->pairwise_key_type) || + (KEY_TYPE_WEP40 == ieee->pairwise_key_type) || + (KEY_TYPE_WEP104 == ieee->group_key_type) || + (KEY_TYPE_WEP40 == ieee->group_key_type) || + (KEY_TYPE_TKIP == ieee->pairwise_key_type) ) + { + if((pHTInfo->IOTPeer==HT_IOT_PEER_REALTEK) && (network->bssht.bdSupportHT)) + retValue = 1; + } +#endif + + return retValue; +} + + +bool HTIOCActAllowPeerAggOnePacket(struct ieee80211_device* ieee,struct ieee80211_network *network) +{ + bool retValue = false; +#if defined(RTL8192SE) || defined(RTL8192SU) + PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; + { + if(pHTInfo->IOTPeer == HT_IOT_PEER_MARVELL) + return true; + + } +#endif + return retValue; +} + +void HTResetIOTSetting( + PRT_HIGH_THROUGHPUT pHTInfo +) +{ + pHTInfo->IOTAction = 0; + pHTInfo->IOTPeer = HT_IOT_PEER_UNKNOWN; + pHTInfo->IOTRaFunc = 0; +} + + +/******************************************************************************************************************** + *function: Construct Capablility Element in Beacon... if HTEnable is turned on + * input: struct ieee80211_device* ieee + * u8* posHTCap //pointer to store Capability Ele + * u8* len //store length of CE + * u8 IsEncrypt //whether encrypt, needed further + * output: none + * return: none + * notice: posHTCap can't be null and should be initialized before. + * *****************************************************************************************************************/ +void HTConstructCapabilityElement(struct ieee80211_device* ieee, u8* posHTCap, u8* len, u8 IsEncrypt) +{ + PRT_HIGH_THROUGHPUT pHT = ieee->pHTInfo; + PHT_CAPABILITY_ELE pCapELE = NULL; + //u8 bIsDeclareMCS13; + + if ((posHTCap == NULL) || (pHT == NULL)) + { + IEEE80211_DEBUG(IEEE80211_DL_ERR, "posHTCap or pHTInfo can't be null in HTConstructCapabilityElement()\n"); + return; + } + memset(posHTCap, 0, *len); + if(pHT->ePeerHTSpecVer == HT_SPEC_VER_EWC) + { + u8 EWC11NHTCap[] = {0x00, 0x90, 0x4c, 0x33}; // For 11n EWC definition, 2007.07.17, by Emily + memcpy(posHTCap, EWC11NHTCap, sizeof(EWC11NHTCap)); + pCapELE = (PHT_CAPABILITY_ELE)&(posHTCap[4]); + }else + { + pCapELE = (PHT_CAPABILITY_ELE)posHTCap; + } + + + //HT capability info + pCapELE->AdvCoding = 0; // This feature is not supported now!! + if(ieee->GetHalfNmodeSupportByAPsHandler(ieee->dev)) + { + pCapELE->ChlWidth = 0; + } + else + { + pCapELE->ChlWidth = (pHT->bRegBW40MHz?1:0); + } + +// pCapELE->ChlWidth = (pHT->bRegBW40MHz?1:0); + pCapELE->MimoPwrSave = pHT->SelfMimoPs; + pCapELE->GreenField = 0; // This feature is not supported now!! + pCapELE->ShortGI20Mhz = 1; // We can receive Short GI!! + pCapELE->ShortGI40Mhz = 1; // We can receive Short GI!! + //DbgPrint("TX HT cap/info ele BW=%d SG20=%d SG40=%d\n\r", + //pCapELE->ChlWidth, pCapELE->ShortGI20Mhz, pCapELE->ShortGI40Mhz); + pCapELE->TxSTBC = 1; + pCapELE->RxSTBC = 0; + pCapELE->DelayBA = 0; // Do not support now!! + pCapELE->MaxAMSDUSize = (MAX_RECEIVE_BUFFER_SIZE>=7935)?1:0; + pCapELE->DssCCk = ((pHT->bRegBW40MHz)?(pHT->bRegSuppCCK?1:0):0); + pCapELE->PSMP = 0; // Do not support now!! + pCapELE->LSigTxopProtect = 0; // Do not support now!! + + + //MAC HT parameters info + // TODO: Nedd to take care of this part + IEEE80211_DEBUG(IEEE80211_DL_HT, "TX HT cap/info ele BW=%d MaxAMSDUSize:%d DssCCk:%d\n", pCapELE->ChlWidth, pCapELE->MaxAMSDUSize, pCapELE->DssCCk); + + if( IsEncrypt) + { + pCapELE->MPDUDensity = 7; // 8us + pCapELE->MaxRxAMPDUFactor = 2; // 2 is for 32 K and 3 is 64K + } + else + { + pCapELE->MaxRxAMPDUFactor = 3; // 2 is for 32 K and 3 is 64K + pCapELE->MPDUDensity = 0; // no density + } + + //Supported MCS set + memcpy(pCapELE->MCS, ieee->Regdot11HTOperationalRateSet, 16); + if(pHT->IOTAction & HT_IOT_ACT_DISABLE_MCS15) + pCapELE->MCS[1] &= 0x7f; + + if(pHT->IOTAction & HT_IOT_ACT_DISABLE_MCS14) + pCapELE->MCS[1] &= 0xbf; + + if(pHT->IOTAction & HT_IOT_ACT_DISABLE_ALL_2SS) + pCapELE->MCS[1] &= 0x00; + + // 2008.06.12 + // For RTL819X, if pairwisekey = wep/tkip, ap is ralink, we support only MCS0~7. + if(ieee->GetHalfNmodeSupportByAPsHandler(ieee->dev)) + { + int i; + for(i = 1; i< 16; i++) + pCapELE->MCS[i] = 0; + } + + //Extended HT Capability Info + memset(&pCapELE->ExtHTCapInfo, 0, 2); + + + //TXBF Capabilities + memset(pCapELE->TxBFCap, 0, 4); + + //Antenna Selection Capabilities + pCapELE->ASCap = 0; +//add 2 to give space for element ID and len when construct frames + if(pHT->ePeerHTSpecVer == HT_SPEC_VER_EWC) + *len = 30 + 2; + else + *len = 26 + 2; + + + +// IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA | IEEE80211_DL_HT, posHTCap, *len -2); + + //Print each field in detail. Driver should not print out this message by default +// HTDebugHTCapability(posHTCap, (u8*)"HTConstructCapability()"); + return; + +} +/******************************************************************************************************************** + *function: Construct Information Element in Beacon... if HTEnable is turned on + * input: struct ieee80211_device* ieee + * u8* posHTCap //pointer to store Information Ele + * u8* len //store len of + * u8 IsEncrypt //whether encrypt, needed further + * output: none + * return: none + * notice: posHTCap can't be null and be initialized before. only AP and IBSS sta should do this + * *****************************************************************************************************************/ +void HTConstructInfoElement(struct ieee80211_device* ieee, u8* posHTInfo, u8* len, u8 IsEncrypt) +{ + PRT_HIGH_THROUGHPUT pHT = ieee->pHTInfo; + PHT_INFORMATION_ELE pHTInfoEle = (PHT_INFORMATION_ELE)posHTInfo; + if ((posHTInfo == NULL) || (pHTInfoEle == NULL)) + { + IEEE80211_DEBUG(IEEE80211_DL_ERR, "posHTInfo or pHTInfoEle can't be null in HTConstructInfoElement()\n"); + return; + } + + memset(posHTInfo, 0, *len); + if ( (ieee->iw_mode == IW_MODE_ADHOC) || (ieee->iw_mode == IW_MODE_MASTER)) //ap mode is not currently supported + { + pHTInfoEle->ControlChl = ieee->current_network.channel; + pHTInfoEle->ExtChlOffset = ((pHT->bRegBW40MHz == false)?HT_EXTCHNL_OFFSET_NO_EXT: + (ieee->current_network.channel<=6)? + HT_EXTCHNL_OFFSET_UPPER:HT_EXTCHNL_OFFSET_LOWER); + pHTInfoEle->RecommemdedTxWidth = pHT->bRegBW40MHz; + pHTInfoEle->RIFS = 0; + pHTInfoEle->PSMPAccessOnly = 0; + pHTInfoEle->SrvIntGranularity = 0; + pHTInfoEle->OptMode = pHT->CurrentOpMode; + pHTInfoEle->NonGFDevPresent = 0; + pHTInfoEle->DualBeacon = 0; + pHTInfoEle->SecondaryBeacon = 0; + pHTInfoEle->LSigTxopProtectFull = 0; + pHTInfoEle->PcoActive = 0; + pHTInfoEle->PcoPhase = 0; + + memset(pHTInfoEle->BasicMSC, 0, 16); + + + *len = 22 + 2; //same above + + } + else + { + //STA should not generate High Throughput Information Element + *len = 0; + } + //IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA | IEEE80211_DL_HT, posHTInfo, *len - 2); + //HTDebugHTInfo(posHTInfo, "HTConstructInforElement"); + return; +} + +/* + * According to experiment, Realtek AP to STA (based on rtl8190) may achieve best performance + * if both STA and AP set limitation of aggregation size to 32K, that is, set AMPDU density to 2 + * (Ref: IEEE 11n specification). However, if Realtek STA associates to other AP, STA should set + * limitation of aggregation size to 8K, otherwise, performance of traffic stream from STA to AP + * will be much less than the traffic stream from AP to STA if both of the stream runs concurrently + * at the same time. + * + * Frame Format + * Element ID Length OUI Type1 Reserved + * 1 byte 1 byte 3 bytes 1 byte 1 byte + * + * OUI = 0x00, 0xe0, 0x4c, + * Type = 0x02 + * Reserved = 0x00 + * + * 2007.8.21 by Emily +*/ +/******************************************************************************************************************** + *function: Construct Information Element in Beacon... in RT2RT condition + * input: struct ieee80211_device* ieee + * u8* posRT2RTAgg //pointer to store Information Ele + * u8* len //store len + * output: none + * return: none + * notice: + * *****************************************************************************************************************/ +void HTConstructRT2RTAggElement(struct ieee80211_device* ieee, u8* posRT2RTAgg, u8* len) +{ + if (posRT2RTAgg == NULL) { + IEEE80211_DEBUG(IEEE80211_DL_ERR, "posRT2RTAgg can't be null in HTConstructRT2RTAggElement()\n"); + return; + } + memset(posRT2RTAgg, 0, *len); + *posRT2RTAgg++ = 0x00; + *posRT2RTAgg++ = 0xe0; + *posRT2RTAgg++ = 0x4c; + *posRT2RTAgg++ = 0x02; + *posRT2RTAgg++ = 0x01; + *posRT2RTAgg = 0x10;//*posRT2RTAgg = 0x02; + + if(ieee->bSupportRemoteWakeUp) { + *posRT2RTAgg |= 0x08;//RT_HT_CAP_USE_WOW; + } + + *len = 6 + 2; + return; +#ifdef TODO +#if(HAL_CODE_BASE == RTL8192 && DEV_BUS_TYPE == USB_INTERFACE) + /* + //Emily. If it is required to Ask Realtek AP to send AMPDU during AES mode, enable this + section of code. + if(IS_UNDER_11N_AES_MODE(Adapter)) + { + posRT2RTAgg->Octet[5] |=RT_HT_CAP_USE_AMPDU; + }else + { + posRT2RTAgg->Octet[5] &= 0xfb; + } + */ + +#else + // Do Nothing +#endif + + posRT2RTAgg->Length = 6; +#endif + + + + +} + + +/******************************************************************************************************************** + *function: Pick the right Rate Adaptive table to use + * input: struct ieee80211_device* ieee + * u8* pOperateMCS //A pointer to MCS rate bitmap + * return: always we return true + * notice: + * *****************************************************************************************************************/ +u8 HT_PickMCSRate(struct ieee80211_device* ieee, u8* pOperateMCS) +{ + u8 i; + if (pOperateMCS == NULL) + { + IEEE80211_DEBUG(IEEE80211_DL_ERR, "pOperateMCS can't be null in HT_PickMCSRate()\n"); + return false; + } + + switch(ieee->mode) + { + case IEEE_A: + case IEEE_B: + case IEEE_G: + //legacy rate routine handled at selectedrate + + //no MCS rate + for(i=0;i<=15;i++){ + pOperateMCS[i] = 0; + } + break; + + case IEEE_N_24G: //assume CCK rate ok + case IEEE_N_5G: + // Legacy part we only use 6, 5.5,2,1 for N_24G and 6 for N_5G. + // Legacy part shall be handled at SelectRateSet(). + + //HT part + // TODO: may be different if we have different number of antenna + pOperateMCS[0] &=RATE_ADPT_1SS_MASK; //support MCS 0~7 + pOperateMCS[1] &=RATE_ADPT_2SS_MASK; + pOperateMCS[3] &=RATE_ADPT_MCS32_MASK; + break; + + //should never reach here + default: + + break; + + } + + return true; +} + +/* +* Description: +* This function will get the highest speed rate in input MCS set. +* +* /param Adapter Pionter to Adapter entity +* pMCSRateSet Pointer to MCS rate bitmap +* pMCSFilter Pointer to MCS rate filter +* +* /return Highest MCS rate included in pMCSRateSet and filtered by pMCSFilter. +* +*/ +/******************************************************************************************************************** + *function: This function will get the highest speed rate in input MCS set. + * input: struct ieee80211_device* ieee + * u8* pMCSRateSet //Pointer to MCS rate bitmap + * u8* pMCSFilter //Pointer to MCS rate filter + * return: Highest MCS rate included in pMCSRateSet and filtered by pMCSFilter + * notice: + * *****************************************************************************************************************/ +u8 HTGetHighestMCSRate(struct ieee80211_device* ieee, u8* pMCSRateSet, u8* pMCSFilter) +{ + u8 i, j; + u8 bitMap; + u8 mcsRate = 0; + u8 availableMcsRate[16]; + if (pMCSRateSet == NULL || pMCSFilter == NULL) + { + IEEE80211_DEBUG(IEEE80211_DL_ERR, "pMCSRateSet or pMCSFilter can't be null in HTGetHighestMCSRate()\n"); + return false; + } + for(i=0; i<16; i++) + availableMcsRate[i] = pMCSRateSet[i] & pMCSFilter[i]; + + for(i = 0; i < 16; i++) + { + if(availableMcsRate[i] != 0) + break; + } + if(i == 16) + return false; + + for(i = 0; i < 16; i++) + { + if(availableMcsRate[i] != 0) + { + bitMap = availableMcsRate[i]; + for(j = 0; j < 8; j++) + { + if((bitMap%2) != 0) + { + if(HTMcsToDataRate(ieee, (8*i+j)) > HTMcsToDataRate(ieee, mcsRate)) + mcsRate = (8*i+j); + } + bitMap = bitMap>>1; + } + } + } + return (mcsRate|0x80); +} + + + +/* +** +**1.Filter our operation rate set with AP's rate set +**2.shall reference channel bandwidth, STBC, Antenna number +**3.generate rate adative table for firmware +**David 20060906 +** +** \pHTSupportedCap: the connected STA's supported rate Capability element +*/ +u8 HTFilterMCSRate( struct ieee80211_device* ieee, u8* pSupportMCS, u8* pOperateMCS) +{ + + u8 i=0; + + // filter out operational rate set not supported by AP, the lenth of it is 16 + for(i=0;i<=15;i++){ + pOperateMCS[i] = ieee->Regdot11HTOperationalRateSet[i]&pSupportMCS[i]; + } + + + // TODO: adjust our operational rate set according to our channel bandwidth, STBC and Antenna number + + // TODO: fill suggested rate adaptive rate index and give firmware info using Tx command packet + // we also shall suggested the first start rate set according to our singal strength + HT_PickMCSRate(ieee, pOperateMCS); + + // For RTL819X, if pairwisekey = wep/tkip, we support only MCS0~7. + if(ieee->GetHalfNmodeSupportByAPsHandler(ieee->dev)) + pOperateMCS[1] = 0; + + // + // For RTL819X, we support only MCS0~15. + // And also, we do not know how to use MCS32 now. + // + for(i=2; i<=15; i++) + pOperateMCS[i] = 0; + + return true; +} +void HTSetConnectBwMode(struct ieee80211_device* ieee, HT_CHANNEL_WIDTH Bandwidth, HT_EXTCHNL_OFFSET Offset); +#if 0 +//I need move this function to other places, such as rx? +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) +void HTOnAssocRsp_wq(struct work_struct *work) +{ + struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, ht_onAssRsp); +#else +void HTOnAssocRsp_wq(struct ieee80211_device *ieee) +{ +#endif +#endif +void HTOnAssocRsp(struct ieee80211_device *ieee) +{ + PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; + PHT_CAPABILITY_ELE pPeerHTCap = NULL; + PHT_INFORMATION_ELE pPeerHTInfo = NULL; + u16 nMaxAMSDUSize = 0; + u8* pMcsFilter = NULL; + + static u8 EWC11NHTCap[] = {0x00, 0x90, 0x4c, 0x33}; // For 11n EWC definition, 2007.07.17, by Emily + static u8 EWC11NHTInfo[] = {0x00, 0x90, 0x4c, 0x34}; // For 11n EWC definition, 2007.07.17, by Emily + + if( pHTInfo->bCurrentHTSupport == false ) + { + IEEE80211_DEBUG(IEEE80211_DL_ERR, "<=== HTOnAssocRsp(): HT_DISABLE\n"); + return; + } + IEEE80211_DEBUG(IEEE80211_DL_HT, "===> HTOnAssocRsp_wq(): HT_ENABLE\n"); +// IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA, pHTInfo->PeerHTCapBuf, sizeof(HT_CAPABILITY_ELE)); +// IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA, pHTInfo->PeerHTInfoBuf, sizeof(HT_INFORMATION_ELE)); + +// HTDebugHTCapability(pHTInfo->PeerHTCapBuf,"HTOnAssocRsp_wq"); +// HTDebugHTInfo(pHTInfo->PeerHTInfoBuf,"HTOnAssocRsp_wq"); + // + if(!memcmp(pHTInfo->PeerHTCapBuf,EWC11NHTCap, sizeof(EWC11NHTCap))) + pPeerHTCap = (PHT_CAPABILITY_ELE)(&pHTInfo->PeerHTCapBuf[4]); + else + pPeerHTCap = (PHT_CAPABILITY_ELE)(pHTInfo->PeerHTCapBuf); + + if(!memcmp(pHTInfo->PeerHTInfoBuf, EWC11NHTInfo, sizeof(EWC11NHTInfo))) + pPeerHTInfo = (PHT_INFORMATION_ELE)(&pHTInfo->PeerHTInfoBuf[4]); + else + pPeerHTInfo = (PHT_INFORMATION_ELE)(pHTInfo->PeerHTInfoBuf); + + + //////////////////////////////////////////////////////// + // Configurations: + //////////////////////////////////////////////////////// + IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA|IEEE80211_DL_HT, pPeerHTCap, sizeof(HT_CAPABILITY_ELE)); +// IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA|IEEE80211_DL_HT, pPeerHTInfo, sizeof(HT_INFORMATION_ELE)); + // Config Supported Channel Width setting + // + HTSetConnectBwMode(ieee, (HT_CHANNEL_WIDTH)(pPeerHTCap->ChlWidth), (HT_EXTCHNL_OFFSET)(pPeerHTInfo->ExtChlOffset)); + +// if(pHTInfo->bCurBW40MHz == true) + pHTInfo->bCurTxBW40MHz = ((pPeerHTInfo->RecommemdedTxWidth == 1)?true:false); + + // + // Update short GI/ long GI setting + // + // TODO: + pHTInfo->bCurShortGI20MHz= + ((pHTInfo->bRegShortGI20MHz)?((pPeerHTCap->ShortGI20Mhz==1)?true:false):false); + pHTInfo->bCurShortGI40MHz= + ((pHTInfo->bRegShortGI40MHz)?((pPeerHTCap->ShortGI40Mhz==1)?true:false):false); + + // + // Config TX STBC setting + // + // TODO: + + // + // Config DSSS/CCK mode in 40MHz mode + // + // TODO: + pHTInfo->bCurSuppCCK = + ((pHTInfo->bRegSuppCCK)?((pPeerHTCap->DssCCk==1)?true:false):false); + + + // + // Config and configure A-MSDU setting + // + pHTInfo->bCurrent_AMSDU_Support = pHTInfo->bAMSDU_Support; + + nMaxAMSDUSize = (pPeerHTCap->MaxAMSDUSize==0)?3839:7935; + + if(pHTInfo->nAMSDU_MaxSize > nMaxAMSDUSize ) + pHTInfo->nCurrent_AMSDU_MaxSize = nMaxAMSDUSize; + else + pHTInfo->nCurrent_AMSDU_MaxSize = pHTInfo->nAMSDU_MaxSize; + + // + // Config A-MPDU setting + // + pHTInfo->bCurrentAMPDUEnable = pHTInfo->bAMPDUEnable; + if(ieee->is_ap_in_wep_tkip && ieee->is_ap_in_wep_tkip(ieee->dev)) + { + if( (pHTInfo->IOTPeer== HT_IOT_PEER_ATHEROS) || + (pHTInfo->IOTPeer == HT_IOT_PEER_UNKNOWN) ) + pHTInfo->bCurrentAMPDUEnable = false; + } + + // <1> Decide AMPDU Factor + + // By Emily + if(!pHTInfo->bRegRT2RTAggregation) + { + // Decide AMPDU Factor according to protocol handshake + if(pHTInfo->AMPDU_Factor > pPeerHTCap->MaxRxAMPDUFactor) + pHTInfo->CurrentAMPDUFactor = pPeerHTCap->MaxRxAMPDUFactor; + else + pHTInfo->CurrentAMPDUFactor = pHTInfo->AMPDU_Factor; + + }else + { + // Set MPDU density to 2 to Realtek AP, and set it to 0 for others + // Replace MPDU factor declared in original association response frame format. 2007.08.20 by Emily +#if 0 + osTmp= PacketGetElement( asocpdu, EID_Vendor, OUI_SUB_REALTEK_AGG, OUI_SUBTYPE_DONT_CARE); + if(osTmp.Length >= 5) //00:e0:4c:02:00 +#endif + if (ieee->current_network.bssht.bdRT2RTAggregation) + { + if( ieee->pairwise_key_type != KEY_TYPE_NA) + // Realtek may set 32k in security mode and 64k for others + pHTInfo->CurrentAMPDUFactor = pPeerHTCap->MaxRxAMPDUFactor; + else + pHTInfo->CurrentAMPDUFactor = HT_AGG_SIZE_64K; + }else + { + if(pPeerHTCap->MaxRxAMPDUFactor < HT_AGG_SIZE_32K) + pHTInfo->CurrentAMPDUFactor = pPeerHTCap->MaxRxAMPDUFactor; + else + pHTInfo->CurrentAMPDUFactor = HT_AGG_SIZE_32K; + } + } + + // <2> Set AMPDU Minimum MPDU Start Spacing + // 802.11n 3.0 section 9.7d.3 +#if 1 + if(pHTInfo->MPDU_Density > pPeerHTCap->MPDUDensity) + pHTInfo->CurrentMPDUDensity = pHTInfo->MPDU_Density; + else + pHTInfo->CurrentMPDUDensity = pPeerHTCap->MPDUDensity; + if(ieee->pairwise_key_type != KEY_TYPE_NA ) + pHTInfo->CurrentMPDUDensity = 7; // 8us +#else + if(pHTInfo->MPDU_Density > pPeerHTCap->MPDUDensity) + pHTInfo->CurrentMPDUDensity = pHTInfo->MPDU_Density; + else + pHTInfo->CurrentMPDUDensity = pPeerHTCap->MPDUDensity; +#endif + // Force TX AMSDU + + // Lanhsin: mark for tmp to avoid deauth by ap from s3 + //if(memcmp(pMgntInfo->Bssid, NETGEAR834Bv2_BROADCOM, 3)==0) + if(pHTInfo->IOTAction & HT_IOT_ACT_TX_USE_AMSDU_8K) + { + + pHTInfo->bCurrentAMPDUEnable = false; + pHTInfo->ForcedAMSDUMode = HT_AGG_FORCE_ENABLE; + pHTInfo->ForcedAMSDUMaxSize = 7935; + } + + // Rx Reorder Setting + pHTInfo->bCurRxReorderEnable = pHTInfo->bRegRxReorderEnable; + + // + // Filter out unsupported HT rate for this AP + // Update RATR table + // This is only for 8190 ,8192 or later product which using firmware to handle rate adaptive mechanism. + // + + // Handle Ralink AP bad MCS rate set condition. Joseph. + // This fix the bug of Ralink AP. This may be removed in the future. + if(pPeerHTCap->MCS[0] == 0) + pPeerHTCap->MCS[0] = 0xff; + + // Joseph test //LZM ADD 090318 + HTIOTActDetermineRaFunc(ieee, ((pPeerHTCap->MCS[1])!=0)); + + HTFilterMCSRate(ieee, pPeerHTCap->MCS, ieee->dot11HTOperationalRateSet); + + // + // Config MIMO Power Save setting + // + pHTInfo->PeerMimoPs = pPeerHTCap->MimoPwrSave; + if(pHTInfo->PeerMimoPs == MIMO_PS_STATIC) + pMcsFilter = MCS_FILTER_1SS; + else + pMcsFilter = MCS_FILTER_ALL; + //WB add for MCS8 bug +// pMcsFilter = MCS_FILTER_1SS; + ieee->HTHighestOperaRate = HTGetHighestMCSRate(ieee, ieee->dot11HTOperationalRateSet, pMcsFilter); + ieee->HTCurrentOperaRate = ieee->HTHighestOperaRate; + + // + // Config current operation mode. + // + pHTInfo->CurrentOpMode = pPeerHTInfo->OptMode; + + + +} + +void HTSetConnectBwModeCallback(struct ieee80211_device* ieee); +/******************************************************************************************************************** + *function: initialize HT info(struct PRT_HIGH_THROUGHPUT) + * input: struct ieee80211_device* ieee + * output: none + * return: none + * notice: This function is called when * (1) MPInitialization Phase * (2) Receiving of Deauthentication from AP +********************************************************************************************************************/ +// TODO: Should this funciton be called when receiving of Disassociation? +void HTInitializeHTInfo(struct ieee80211_device* ieee) +{ + PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; + + // + // These parameters will be reset when receiving deauthentication packet + // + IEEE80211_DEBUG(IEEE80211_DL_HT, "===========>%s()\n", __FUNCTION__); + pHTInfo->bCurrentHTSupport = false; + + // 40MHz channel support + pHTInfo->bCurBW40MHz = false; + pHTInfo->bCurTxBW40MHz = false; + + // Short GI support + pHTInfo->bCurShortGI20MHz = false; + pHTInfo->bCurShortGI40MHz = false; + pHTInfo->bForcedShortGI = false; + + // CCK rate support + // This flag is set to true to support CCK rate by default. + // It will be affected by "pHTInfo->bRegSuppCCK" and AP capabilities only when associate to + // 11N BSS. + pHTInfo->bCurSuppCCK = true; + + // AMSDU related + pHTInfo->bCurrent_AMSDU_Support = false; + pHTInfo->nCurrent_AMSDU_MaxSize = pHTInfo->nAMSDU_MaxSize; + + // AMPUD related + pHTInfo->CurrentMPDUDensity = pHTInfo->MPDU_Density; + pHTInfo->CurrentAMPDUFactor = pHTInfo->AMPDU_Factor; + + + + // Initialize all of the parameters related to 11n + memset((void*)(&(pHTInfo->SelfHTCap)), 0, sizeof(pHTInfo->SelfHTCap)); + memset((void*)(&(pHTInfo->SelfHTInfo)), 0, sizeof(pHTInfo->SelfHTInfo)); + memset((void*)(&(pHTInfo->PeerHTCapBuf)), 0, sizeof(pHTInfo->PeerHTCapBuf)); + memset((void*)(&(pHTInfo->PeerHTInfoBuf)), 0, sizeof(pHTInfo->PeerHTInfoBuf)); + + pHTInfo->bSwBwInProgress = false; + pHTInfo->ChnlOp = CHNLOP_NONE; + + // Set default IEEE spec for Draft N + pHTInfo->ePeerHTSpecVer = HT_SPEC_VER_IEEE; + + // Realtek proprietary aggregation mode + pHTInfo->bCurrentRT2RTAggregation = false; + pHTInfo->bCurrentRT2RTLongSlotTime = false; + pHTInfo->RT2RT_HT_Mode = (RT_HT_CAPBILITY)0; + + pHTInfo->IOTPeer = 0; + pHTInfo->IOTAction = 0; + pHTInfo->IOTRaFunc = 0; + + //MCS rate initialized here + { + u8* RegHTSuppRateSets = &(ieee->RegHTSuppRateSet[0]); + RegHTSuppRateSets[0] = 0xFF; //support MCS 0~7 + RegHTSuppRateSets[1] = 0xFF; //support MCS 8~15 + RegHTSuppRateSets[4] = 0x01; //support MCS 32 + } +} +/******************************************************************************************************************** + *function: initialize Bss HT structure(struct PBSS_HT) + * input: PBSS_HT pBssHT //to be initialized + * output: none + * return: none + * notice: This function is called when initialize network structure +********************************************************************************************************************/ +void HTInitializeBssDesc(PBSS_HT pBssHT) +{ + + pBssHT->bdSupportHT = false; + memset(pBssHT->bdHTCapBuf, 0, sizeof(pBssHT->bdHTCapBuf)); + pBssHT->bdHTCapLen = 0; + memset(pBssHT->bdHTInfoBuf, 0, sizeof(pBssHT->bdHTInfoBuf)); + pBssHT->bdHTInfoLen = 0; + + pBssHT->bdHTSpecVer= HT_SPEC_VER_IEEE; + + pBssHT->bdRT2RTAggregation = false; + pBssHT->bdRT2RTLongSlotTime = false; + pBssHT->RT2RT_HT_Mode = (RT_HT_CAPBILITY)0; +} +#if 0 +//below function has merged into ieee80211_network_init() in ieee80211_rx.c +void +HTParsingHTCapElement( + IN PADAPTER Adapter, + IN OCTET_STRING HTCapIE, + OUT PRT_WLAN_BSS pBssDesc +) +{ + PMGNT_INFO pMgntInfo = &Adapter->MgntInfo; + + if( HTCapIE.Length > sizeof(pBssDesc->BssHT.bdHTCapBuf) ) + { + RT_TRACE( COMP_HT, DBG_LOUD, ("HTParsingHTCapElement(): HT Capability Element length is too long!\n") ); + return; + } + + // TODO: Check the correctness of HT Cap + //Print each field in detail. Driver should not print out this message by default + if(!pMgntInfo->mActingAsAp && !pMgntInfo->mAssoc) + HTDebugHTCapability(DBG_TRACE, Adapter, &HTCapIE, (pu8)"HTParsingHTCapElement()"); + + HTCapIE.Length = HTCapIE.Length > sizeof(pBssDesc->BssHT.bdHTCapBuf)?\ + sizeof(pBssDesc->BssHT.bdHTCapBuf):HTCapIE.Length; //prevent from overflow + + CopyMem(pBssDesc->BssHT.bdHTCapBuf, HTCapIE.Octet, HTCapIE.Length); + pBssDesc->BssHT.bdHTCapLen = HTCapIE.Length; + +} + + +void +HTParsingHTInfoElement( + PADAPTER Adapter, + OCTET_STRING HTInfoIE, + PRT_WLAN_BSS pBssDesc +) +{ + PMGNT_INFO pMgntInfo = &Adapter->MgntInfo; + + if( HTInfoIE.Length > sizeof(pBssDesc->BssHT.bdHTInfoBuf)) + { + RT_TRACE( COMP_HT, DBG_LOUD, ("HTParsingHTInfoElement(): HT Information Element length is too long!\n") ); + return; + } + + // TODO: Check the correctness of HT Info + //Print each field in detail. Driver should not print out this message by default + if(!pMgntInfo->mActingAsAp && !pMgntInfo->mAssoc) + HTDebugHTInfo(DBG_TRACE, Adapter, &HTInfoIE, (pu8)"HTParsingHTInfoElement()"); + + HTInfoIE.Length = HTInfoIE.Length > sizeof(pBssDesc->BssHT.bdHTInfoBuf)?\ + sizeof(pBssDesc->BssHT.bdHTInfoBuf):HTInfoIE.Length; //prevent from overflow + + CopyMem( pBssDesc->BssHT.bdHTInfoBuf, HTInfoIE.Octet, HTInfoIE.Length); + pBssDesc->BssHT.bdHTInfoLen = HTInfoIE.Length; +} + +/* + * Get HT related information from beacon and save it in BssDesc + * + * (1) Parse HTCap, and HTInfo, and record whether it is 11n AP + * (2) If peer is HT, but not WMM, call QosSetLegacyWMMParamWithHT() + * (3) Check whether peer is Realtek AP (for Realtek proprietary aggregation mode). + * Input: + * PADAPTER Adapter + * + * Output: + * PRT_TCB BssDesc + * +*/ +void HTGetValueFromBeaconOrProbeRsp( + PADAPTER Adapter, + POCTET_STRING pSRCmmpdu, + PRT_WLAN_BSS bssDesc +) +{ + PMGNT_INFO pMgntInfo = &Adapter->MgntInfo; + PRT_HIGH_THROUGHPUT pHTInfo = GET_HT_INFO(pMgntInfo); + OCTET_STRING HTCapIE, HTInfoIE, HTRealtekAgg, mmpdu; + OCTET_STRING BroadcomElement, CiscoElement; + + mmpdu.Octet = pSRCmmpdu->Octet; + mmpdu.Length = pSRCmmpdu->Length; + + //2Note: + // Mark for IOT testing using Linksys WRT350N, This AP does not contain WMM IE when + // it is configured at pure-N mode. + // if(bssDesc->BssQos.bdQoSMode & QOS_WMM) + // + + HTInitializeBssDesc (&bssDesc->BssHT); + + //2<1> Parse HTCap, and HTInfo + // Get HT Capability IE: (1) Get IEEE Draft N IE or (2) Get EWC IE + HTCapIE = PacketGetElement(mmpdu, EID_HTCapability, OUI_SUB_DONT_CARE, OUI_SUBTYPE_DONT_CARE); + if(HTCapIE.Length == 0) + { + HTCapIE = PacketGetElement(mmpdu, EID_Vendor, OUI_SUB_11N_EWC_HT_CAP, OUI_SUBTYPE_DONT_CARE); + if(HTCapIE.Length != 0) + bssDesc->BssHT.bdHTSpecVer= HT_SPEC_VER_EWC; + } + if(HTCapIE.Length != 0) + HTParsingHTCapElement(Adapter, HTCapIE, bssDesc); + + // Get HT Information IE: (1) Get IEEE Draft N IE or (2) Get EWC IE + HTInfoIE = PacketGetElement(mmpdu, EID_HTInfo, OUI_SUB_DONT_CARE, OUI_SUBTYPE_DONT_CARE); + if(HTInfoIE.Length == 0) + { + HTInfoIE = PacketGetElement(mmpdu, EID_Vendor, OUI_SUB_11N_EWC_HT_INFO, OUI_SUBTYPE_DONT_CARE); + if(HTInfoIE.Length != 0) + bssDesc->BssHT.bdHTSpecVer = HT_SPEC_VER_EWC; + } + if(HTInfoIE.Length != 0) + HTParsingHTInfoElement(Adapter, HTInfoIE, bssDesc); + + //2<2>If peer is HT, but not WMM, call QosSetLegacyWMMParamWithHT() + if(HTCapIE.Length != 0) + { + bssDesc->BssHT.bdSupportHT = true; + if(bssDesc->BssQos.bdQoSMode == QOS_DISABLE) + QosSetLegacyWMMParamWithHT(Adapter, bssDesc); + } + else + { + bssDesc->BssHT.bdSupportHT = false; + } + + //2<3>Check whether the peer is Realtek AP/STA + if(pHTInfo->bRegRT2RTAggregation) + { + if(bssDesc->BssHT.bdSupportHT) + { + HTRealtekAgg = PacketGetElement(mmpdu, EID_Vendor, OUI_SUB_REALTEK_AGG, OUI_SUBTYPE_DONT_CARE); + if(HTRealtekAgg.Length >=5 ) + { + bssDesc->BssHT.bdRT2RTAggregation = true; + + if((HTRealtekAgg.Octet[4]==1) && (HTRealtekAgg.Octet[5] & 0x02)) + bssDesc->BssHT.bdRT2RTLongSlotTime = true; + } + } + } + + // + // 2008/01/25 MH Get Broadcom AP IE for manamgent frame CCK rate problem. + // AP can not receive CCK managemtn from from 92E. + // + + // Initialize every new bss broadcom cap exist as false.. + bssDesc->bBroadcomCapExist= false; + + if(HTCapIE.Length != 0 || HTInfoIE.Length != 0) + { + u4Byte Length = 0; + + FillOctetString(BroadcomElement, NULL, 0); + + BroadcomElement = PacketGetElement( mmpdu, EID_Vendor, OUI_SUB_BROADCOM_IE_1, OUI_SUBTYPE_DONT_CARE); + Length += BroadcomElement.Length; + BroadcomElement = PacketGetElement( mmpdu, EID_Vendor, OUI_SUB_BROADCOM_IE_2, OUI_SUBTYPE_DONT_CARE); + Length += BroadcomElement.Length; + BroadcomElement = PacketGetElement( mmpdu, EID_Vendor, OUI_SUB_BROADCOM_IE_3, OUI_SUBTYPE_DONT_CARE); + Length += BroadcomElement.Length; + + if(Length > 0) + bssDesc->bBroadcomCapExist = true; + } + + + // For Cisco IOT issue + CiscoElement = PacketGetElement( mmpdu, EID_Vendor, OUI_SUB_CISCO_IE, OUI_SUBTYPE_DONT_CARE); + if(CiscoElement.Length != 0){ // 3: 0x00, 0x40, 0x96 .... + bssDesc->bCiscoCapExist = true; + }else{ + bssDesc->bCiscoCapExist = false; + } +} + + +#endif +/******************************************************************************************************************** + *function: initialize Bss HT structure(struct PBSS_HT) + * input: struct ieee80211_device *ieee + * struct ieee80211_network *pNetwork //usually current network we are live in + * output: none + * return: none + * notice: This function should ONLY be called before association +********************************************************************************************************************/ +void HTResetSelfAndSavePeerSetting(struct ieee80211_device* ieee, struct ieee80211_network * pNetwork) +{ + PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; +// u16 nMaxAMSDUSize; +// PHT_CAPABILITY_ELE pPeerHTCap = (PHT_CAPABILITY_ELE)pNetwork->bssht.bdHTCapBuf; +// PHT_INFORMATION_ELE pPeerHTInfo = (PHT_INFORMATION_ELE)pNetwork->bssht.bdHTInfoBuf; +// u8* pMcsFilter; + u8 bIOTAction = 0; + + // + // Save Peer Setting before Association + // + IEEE80211_DEBUG(IEEE80211_DL_HT, "==============>%s()\n", __FUNCTION__); + /*unmark bEnableHT flag here is the same reason why unmarked in function ieee80211_softmac_new_net. WB 2008.09.10*/ +// if( pHTInfo->bEnableHT && pNetwork->bssht.bdSupportHT) + if (pNetwork->bssht.bdSupportHT) + { + pHTInfo->bCurrentHTSupport = true; + pHTInfo->ePeerHTSpecVer = pNetwork->bssht.bdHTSpecVer; + + // Save HTCap and HTInfo information Element + if(pNetwork->bssht.bdHTCapLen > 0 && pNetwork->bssht.bdHTCapLen <= sizeof(pHTInfo->PeerHTCapBuf)) + memcpy(pHTInfo->PeerHTCapBuf, pNetwork->bssht.bdHTCapBuf, pNetwork->bssht.bdHTCapLen); + + if(pNetwork->bssht.bdHTInfoLen > 0 && pNetwork->bssht.bdHTInfoLen <= sizeof(pHTInfo->PeerHTInfoBuf)) + memcpy(pHTInfo->PeerHTInfoBuf, pNetwork->bssht.bdHTInfoBuf, pNetwork->bssht.bdHTInfoLen); + + // Check whether RT to RT aggregation mode is enabled + if(pHTInfo->bRegRT2RTAggregation) + { + pHTInfo->bCurrentRT2RTAggregation = pNetwork->bssht.bdRT2RTAggregation; + pHTInfo->bCurrentRT2RTLongSlotTime = pNetwork->bssht.bdRT2RTLongSlotTime; + pHTInfo->RT2RT_HT_Mode = pNetwork->bssht.RT2RT_HT_Mode; + } + else + { + pHTInfo->bCurrentRT2RTAggregation = false; + pHTInfo->bCurrentRT2RTLongSlotTime = false; + pHTInfo->RT2RT_HT_Mode = (RT_HT_CAPBILITY)0; + } + + // Determine the IOT Peer Vendor. + HTIOTPeerDetermine(ieee); + + // Decide IOT Action + // Must be called after the parameter of pHTInfo->bCurrentRT2RTAggregation is decided + pHTInfo->IOTAction = 0; + bIOTAction = HTIOTActIsDisableMCS14(ieee, pNetwork->bssid); + if(bIOTAction) + pHTInfo->IOTAction |= HT_IOT_ACT_DISABLE_MCS14; + + bIOTAction = HTIOTActIsDisableMCS15(ieee); + if(bIOTAction) + pHTInfo->IOTAction |= HT_IOT_ACT_DISABLE_MCS15; + + bIOTAction = HTIOTActIsDisableMCSTwoSpatialStream(ieee); + if(bIOTAction) + pHTInfo->IOTAction |= HT_IOT_ACT_DISABLE_ALL_2SS; + + + bIOTAction = HTIOTActIsDisableEDCATurbo(ieee, pNetwork->bssid); + if(bIOTAction) + pHTInfo->IOTAction |= HT_IOT_ACT_DISABLE_EDCA_TURBO; + + bIOTAction = HTIOTActIsMgntUseCCK6M(pNetwork); + if(bIOTAction) + pHTInfo->IOTAction |= HT_IOT_ACT_MGNT_USE_CCK_6M; + + bIOTAction = HTIOTActIsCCDFsync(pNetwork->bssid); + if(bIOTAction) + pHTInfo->IOTAction |= HT_IOT_ACT_CDD_FSYNC; + + bIOTAction = HTIOTActIsForcedCTS2Self(pNetwork); + if(bIOTAction) + pHTInfo->IOTAction |= HT_IOT_ACT_FORCED_CTS2SELF; + + //bIOTAction = HTIOTActIsForcedRTSCTS(ieee, pNetwork); + //if(bIOTAction) + // pHTInfo->IOTAction |= HT_IOT_ACT_FORCED_RTS; + +#if defined(RTL8192SU) + bIOTAction = HTIOCActRejcectADDBARequest(pNetwork); + if(bIOTAction) + pHTInfo->IOTAction |= HT_IOT_ACT_REJECT_ADDBA_REQ; +#endif + + bIOTAction = HTIOCActAllowPeerAggOnePacket(ieee, pNetwork); + if(bIOTAction) + pHTInfo->IOTAction |= HT_IOT_ACT_ALLOW_PEER_AGG_ONE_PKT; + + bIOTAction = HTIOTActIsEDCABiasRx(ieee, pNetwork); + if(bIOTAction) + pHTInfo->IOTAction |= HT_IOT_ACT_EDCA_BIAS_ON_RX; + +#if defined(RTL8192SU) + bIOTAction = HTIOTActDisableShortGI(ieee, pNetwork); + if(bIOTAction) + pHTInfo->IOTAction |= HT_IOT_ACT_DISABLE_SHORT_GI; + + bIOTAction = HTIOTActDisableHighPower(ieee, pNetwork); + if(bIOTAction) + pHTInfo->IOTAction |= HT_IOT_ACT_DISABLE_HIGH_POWER; +#endif + + bIOTAction = HTIOTActIsForcedAMSDU8K(ieee, pNetwork); + if(bIOTAction) + pHTInfo->IOTAction |= HT_IOT_ACT_TX_USE_AMSDU_8K; + +#if defined(RTL8192SU) + bIOTAction = HTIOTActIsTxNoAggregation(ieee, pNetwork); + if(bIOTAction) + pHTInfo->IOTAction |= HT_IOT_ACT_TX_NO_AGGREGATION; + + bIOTAction = HTIOTActIsDisableTx40MHz(ieee, pNetwork); + if(bIOTAction) + pHTInfo->IOTAction |= HT_IOT_ACT_DISABLE_TX_40_MHZ; + + bIOTAction = HTIOTActIsDisableTx2SS(ieee, pNetwork); + if(bIOTAction) + pHTInfo->IOTAction |= HT_IOT_ACT_DISABLE_TX_2SS; +#endif + //must after HT_IOT_ACT_TX_NO_AGGREGATION + bIOTAction = HTIOTActIsForcedRTSCTS(ieee, pNetwork); + if(bIOTAction) + pHTInfo->IOTAction |= HT_IOT_ACT_FORCED_RTS; + + printk("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!IOTAction = %8.8x\n", pHTInfo->IOTAction); + } + else + { + pHTInfo->bCurrentHTSupport = false; + pHTInfo->bCurrentRT2RTAggregation = false; + pHTInfo->bCurrentRT2RTLongSlotTime = false; + pHTInfo->RT2RT_HT_Mode = (RT_HT_CAPBILITY)0; + + pHTInfo->IOTAction = 0; + pHTInfo->IOTRaFunc = 0; + } + +} + +void HTUpdateSelfAndPeerSetting(struct ieee80211_device* ieee, struct ieee80211_network * pNetwork) +{ + PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; +// PHT_CAPABILITY_ELE pPeerHTCap = (PHT_CAPABILITY_ELE)pNetwork->bssht.bdHTCapBuf; + PHT_INFORMATION_ELE pPeerHTInfo = (PHT_INFORMATION_ELE)pNetwork->bssht.bdHTInfoBuf; + + if(pHTInfo->bCurrentHTSupport) + { + // + // Config current operation mode. + // + if(pNetwork->bssht.bdHTInfoLen != 0) + pHTInfo->CurrentOpMode = pPeerHTInfo->OptMode; + + // + // + // + } +} + +void HTUseDefaultSetting(struct ieee80211_device* ieee) +{ + PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; +// u8 regBwOpMode; + + if(pHTInfo->bEnableHT) + { + pHTInfo->bCurrentHTSupport = true; + + pHTInfo->bCurSuppCCK = pHTInfo->bRegSuppCCK; + + pHTInfo->bCurBW40MHz = pHTInfo->bRegBW40MHz; + + pHTInfo->bCurShortGI20MHz= pHTInfo->bRegShortGI20MHz; + + pHTInfo->bCurShortGI40MHz= pHTInfo->bRegShortGI40MHz; + + pHTInfo->bCurrent_AMSDU_Support = pHTInfo->bAMSDU_Support; + + pHTInfo->nCurrent_AMSDU_MaxSize = pHTInfo->nAMSDU_MaxSize; + + pHTInfo->bCurrentAMPDUEnable = pHTInfo->bAMPDUEnable; + + pHTInfo->CurrentAMPDUFactor = pHTInfo->AMPDU_Factor; + + pHTInfo->CurrentMPDUDensity = pHTInfo->CurrentMPDUDensity; + + // Set BWOpMode register + + //update RATR index0 + HTFilterMCSRate(ieee, ieee->Regdot11HTOperationalRateSet, ieee->dot11HTOperationalRateSet); + //function below is not implemented at all. WB +#ifdef TODO + Adapter->HalFunc.InitHalRATRTableHandler( Adapter, &pMgntInfo->dot11OperationalRateSet, pMgntInfo->dot11HTOperationalRateSet); +#endif + ieee->HTHighestOperaRate = HTGetHighestMCSRate(ieee, ieee->dot11HTOperationalRateSet, MCS_FILTER_ALL); + ieee->HTCurrentOperaRate = ieee->HTHighestOperaRate; + + } + else + { + pHTInfo->bCurrentHTSupport = false; + } + return; +} +/******************************************************************************************************************** + *function: check whether HT control field exists + * input: struct ieee80211_device *ieee + * u8* pFrame //coming skb->data + * output: none + * return: return true if HT control field exists(false otherwise) + * notice: +********************************************************************************************************************/ +u8 HTCCheck(struct ieee80211_device* ieee, u8* pFrame) +{ + if(ieee->pHTInfo->bCurrentHTSupport) + { + if( (IsQoSDataFrame(pFrame) && Frame_Order(pFrame)) == 1) + { + IEEE80211_DEBUG(IEEE80211_DL_HT, "HT CONTROL FILED EXIST!!\n"); + return true; + } + } + return false; +} + +// +// This function set bandwidth mode in protocol layer. +// +void HTSetConnectBwMode(struct ieee80211_device* ieee, HT_CHANNEL_WIDTH Bandwidth, HT_EXTCHNL_OFFSET Offset) +{ + PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; +// u32 flags = 0; + + if(pHTInfo->bRegBW40MHz == false) + return; + + + + // To reduce dummy operation +// if((pHTInfo->bCurBW40MHz==false && Bandwidth==HT_CHANNEL_WIDTH_20) || +// (pHTInfo->bCurBW40MHz==true && Bandwidth==HT_CHANNEL_WIDTH_20_40 && Offset==pHTInfo->CurSTAExtChnlOffset)) +// return; + +// spin_lock_irqsave(&(ieee->bw_spinlock), flags); + if(pHTInfo->bSwBwInProgress) { +// spin_unlock_irqrestore(&(ieee->bw_spinlock), flags); + return; + } + //if in half N mode, set to 20M bandwidth please 09.08.2008 WB. + if(Bandwidth==HT_CHANNEL_WIDTH_20_40 && (!ieee->GetHalfNmodeSupportByAPsHandler(ieee->dev))) + { + // Handle Illegal extention channel offset!! + if(ieee->current_network.channel<2 && Offset==HT_EXTCHNL_OFFSET_LOWER) + Offset = HT_EXTCHNL_OFFSET_NO_EXT; + if(Offset==HT_EXTCHNL_OFFSET_UPPER || Offset==HT_EXTCHNL_OFFSET_LOWER) { + pHTInfo->bCurBW40MHz = true; + pHTInfo->CurSTAExtChnlOffset = Offset; + } else { + pHTInfo->bCurBW40MHz = false; + pHTInfo->CurSTAExtChnlOffset = HT_EXTCHNL_OFFSET_NO_EXT; + } + } else { + pHTInfo->bCurBW40MHz = false; + pHTInfo->CurSTAExtChnlOffset = HT_EXTCHNL_OFFSET_NO_EXT; + } + + pHTInfo->bSwBwInProgress = true; + + // TODO: 2007.7.13 by Emily Wait 2000ms in order to garantee that switching + // bandwidth is executed after scan is finished. It is a temporal solution + // because software should ganrantee the last operation of switching bandwidth + // is executed properlly. + HTSetConnectBwModeCallback(ieee); + +// spin_unlock_irqrestore(&(ieee->bw_spinlock), flags); +} + +void HTSetConnectBwModeCallback(struct ieee80211_device* ieee) +{ + PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; + + IEEE80211_DEBUG(IEEE80211_DL_HT, "======>%s()\n", __FUNCTION__); + if(pHTInfo->bCurBW40MHz) + { + if(pHTInfo->CurSTAExtChnlOffset==HT_EXTCHNL_OFFSET_UPPER) + ieee->set_chan(ieee->dev, ieee->current_network.channel+2); + else if(pHTInfo->CurSTAExtChnlOffset==HT_EXTCHNL_OFFSET_LOWER) + ieee->set_chan(ieee->dev, ieee->current_network.channel-2); + else + ieee->set_chan(ieee->dev, ieee->current_network.channel); + + ieee->SetBWModeHandler(ieee->dev, HT_CHANNEL_WIDTH_20_40, pHTInfo->CurSTAExtChnlOffset); + } else { + ieee->set_chan(ieee->dev, ieee->current_network.channel); + ieee->SetBWModeHandler(ieee->dev, HT_CHANNEL_WIDTH_20, HT_EXTCHNL_OFFSET_NO_EXT); + } + + pHTInfo->bSwBwInProgress = false; +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +EXPORT_SYMBOL_NOVERS(HTUpdateSelfAndPeerSetting); +#else +EXPORT_SYMBOL(HTUpdateSelfAndPeerSetting); +#endif diff --git a/drivers/staging/rtl8192su/ieee80211/rtl819x_Qos.h b/drivers/staging/rtl8192su/ieee80211/rtl819x_Qos.h new file mode 100644 index 000000000000..f7b882b99d14 --- /dev/null +++ b/drivers/staging/rtl8192su/ieee80211/rtl819x_Qos.h @@ -0,0 +1,749 @@ +#ifndef __INC_QOS_TYPE_H +#define __INC_QOS_TYPE_H + +//#include "EndianFree.h" +#define BIT0 0x00000001 +#define BIT1 0x00000002 +#define BIT2 0x00000004 +#define BIT3 0x00000008 +#define BIT4 0x00000010 +#define BIT5 0x00000020 +#define BIT6 0x00000040 +#define BIT7 0x00000080 +#define BIT8 0x00000100 +#define BIT9 0x00000200 +#define BIT10 0x00000400 +#define BIT11 0x00000800 +#define BIT12 0x00001000 +#define BIT13 0x00002000 +#define BIT14 0x00004000 +#define BIT15 0x00008000 +#define BIT16 0x00010000 +#define BIT17 0x00020000 +#define BIT18 0x00040000 +#define BIT19 0x00080000 +#define BIT20 0x00100000 +#define BIT21 0x00200000 +#define BIT22 0x00400000 +#define BIT23 0x00800000 +#define BIT24 0x01000000 +#define BIT25 0x02000000 +#define BIT26 0x04000000 +#define BIT27 0x08000000 +#define BIT28 0x10000000 +#define BIT29 0x20000000 +#define BIT30 0x40000000 +#define BIT31 0x80000000 + +#define MAX_WMMELE_LENGTH 64 + +// +// QoS mode. +// enum 0, 1, 2, 4: since we can use the OR(|) operation. +// +// QOS_MODE is redefined for enum can't be ++, | under C++ compiler, 2006.05.17, by rcnjko. +//typedef enum _QOS_MODE{ +// QOS_DISABLE = 0, +// QOS_WMM = 1, +// QOS_EDCA = 2, +// QOS_HCCA = 4, +//}QOS_MODE,*PQOS_MODE; +// +typedef u32 QOS_MODE, *PQOS_MODE; +#define QOS_DISABLE 0 +#define QOS_WMM 1 +#define QOS_WMMSA 2 +#define QOS_EDCA 4 +#define QOS_HCCA 8 +#define QOS_WMM_UAPSD 16 //WMM Power Save, 2006-06-14 Isaiah + +#define AC_PARAM_SIZE 4 +#define WMM_PARAM_ELE_BODY_LEN 18 + +// +// QoS ACK Policy Field Values +// Ref: WMM spec 2.1.6: QoS Control Field, p.10. +// +typedef enum _ACK_POLICY{ + eAckPlc0_ACK = 0x00, + eAckPlc1_NoACK = 0x01, +}ACK_POLICY,*PACK_POLICY; + +#define WMM_PARAM_ELEMENT_SIZE (8+(4*AC_PARAM_SIZE)) +#if 0 +#define GET_QOS_CTRL(_pStart) ReadEF2Byte((u8 *)(_pStart) + 24) +#define SET_QOS_CTRL(_pStart, _value) WriteEF2Byte((u8 *)(_pStart) + 24, _value) + +// WMM control field. +#define GET_QOS_CTRL_WMM_UP(_pStart) ((u8)LE_BITS_TO_2BYTE((u8 *)(_pStart)+24, 0, 3)) +#define SET_QOS_CTRL_WMM_UP(_pStart, _value) SET_BITS_TO_LE_2BYTE((u8 *)(_pStart)+24, 0, 3, (u8)(_value)) + +#define GET_QOS_CTRL_WMM_EOSP(_pStart) ((u8)LE_BITS_TO_2BYTE((u8 *)(_pStart)+24, 4, 1)) +#define SET_QOS_CTRL_WMM_EOSP(_pStart, _value) SET_BITS_TO_LE_2BYTE((u8 *)(_pStart)+24, 4, 1, (u8)(_value)) + +#define GET_QOS_CTRL_WMM_ACK_POLICY(_pStart) ((u8)LE_BITS_TO_2BYTE((u8 *)(_pStart)+24, 5, 2)) +#define SET_QOS_CTRL_WMM_ACK_POLICY(_pStart, _value) SET_BITS_TO_LE_2BYTE((u8 *)(_pStart)+24, 5, 2, (u8)(_value)) + +// 802.11e control field (by STA, data) +#define GET_QOS_CTRL_STA_DATA_TID(_pStart) ((u8)LE_BITS_TO_2BYTE((u8 *)(_pStart)+24, 0, 4)) +#define SET_QOS_CTRL_STA_DATA_TID(_pStart, _value) SET_BITS_TO_LE_2BYTE((u8 *)(_pStart)+24, 0, 4, (u8)(_value)) + +#define GET_QOS_CTRL_STA_DATA_QSIZE_FLAG(_pStart) ((u8)LE_BITS_TO_2BYTE((u8 *)(_pStart)+24, 4, 1)) +#define SET_QOS_CTRL_STA_DATA_QSIZE_FLAG(_pStart, _value) SET_BITS_TO_LE_2BYTE((u8 *)(_pStart)+24, 4, 1, (u8)(_value)) + +#define GET_QOS_CTRL_STA_DATA_ACK_POLICY(_pStart) ((u8)LE_BITS_TO_2BYTE((u8 *)(_pStart)+24, 5, 2)) +#define SET_QOS_CTRL_STA_DATA_ACK_POLICY(_pStart, _value) SET_BITS_TO_LE_2BYTE((u8 *)(_pStart)+24, 5, 2, (u8)(_value)) + +#define GET_QOS_CTRL_STA_DATA_TXOP(_pStart) ((u8)LE_BITS_TO_2BYTE((u8 *)(_pStart)+24, 8, 8)) +#define SET_QOS_CTRL_STA_DATA_TXOP(_pStart, _value) SET_BITS_TO_LE_2BYTE((u8 *)(_pStart)+24, 8, 8, (u8)(_value)) + +#define GET_QOS_CTRL_STA_DATA_QSIZE(_pStart) GET_QOS_CTRL_STA_DATA_TXOP(_pStart) +#define SET_QOS_CTRL_STA_DATA_QSIZE(_pStart, _value) SET_QOS_CTRL_STA_DATA_TXOP(_pStart) + +// 802.11e control field (by HC, data) +#define GET_QOS_CTRL_HC_DATA_TID(_pStart) ((u8)LE_BITS_TO_2BYTE((u8 *)(_pStart)+24, 0, 4)) +#define SET_QOS_CTRL_HC_DATA_TID(_pStart, _value) SET_BITS_TO_LE_2BYTE((u8 *)(_pStart)+24, 0, 4, (u8)(_value)) + +#define GET_QOS_CTRL_HC_DATA_EOSP(_pStart) ((u8)LE_BITS_TO_2BYTE((u8 *)(_pStart)+24, 4, 1)) +#define SET_QOS_CTRL_HC_DATA_EOSP(_pStart, _value) SET_BITS_TO_LE_2BYTE((u8 *)(_pStart)+24, 4, 1, (u8)(_value)) + +#define GET_QOS_CTRL_HC_DATA_ACK_POLICY(_pStart) ((u8)LE_BITS_TO_2BYTE((u8 *)(_pStart)+24, 5, 2)) +#define SET_QOS_CTRL_HC_DATA_ACK_POLICY(_pStart, _value) SET_BITS_TO_LE_2BYTE((u8 *)(_pStart)+24, 5, 2, (u8)(_value)) + +#define GET_QOS_CTRL_HC_DATA_PS_BUFSTATE(_pStart) ((u8)LE_BITS_TO_2BYTE((u8 *)(_pStart)+24, 8, 8)) +#define SET_QOS_CTRL_HC_DATA_PS_BUFSTATE(_pStart, _value) SET_BITS_TO_LE_2BYTE((u8 *)(_pStart)+24, 8, 8, (u8)(_value)) + +// 802.11e control field (by HC, CFP) +#define GET_QOS_CTRL_HC_CFP_TID(_pStart) ((u8)LE_BITS_TO_2BYTE((u8 *)(_pStart)+24, 0, 4)) +#define SET_QOS_CTRL_HC_CFP_TID(_pStart, _value) SET_BITS_TO_LE_2BYTE((u8 *)(_pStart)+24, 0, 4, (u8)(_value)) + +#define GET_QOS_CTRL_HC_CFP_EOSP(_pStart) ((u8)LE_BITS_TO_2BYTE((u8 *)(_pStart)+24, 4, 1)) +#define SET_QOS_CTRL_HC_CFP_EOSP(_pStart, _value) SET_BITS_TO_LE_2BYTE((u8 *)(_pStart)+24, 4, 1, (u8)(_value)) + +#define GET_QOS_CTRL_HC_CFP_ACK_POLICY(_pStart) ((u8)LE_BITS_TO_2BYTE((u8 *)(_pStart)+24, 5, 2)) +#define SET_QOS_CTRL_HC_CFP_ACK_POLICY(_pStart, _value) SET_BITS_TO_LE_2BYTE((u8 *)(_pStart)+24, 5, 2, (u8)(_value)) + +#define GET_QOS_CTRL_HC_CFP_TXOP_LIMIT(_pStart) ((u8)LE_BITS_TO_2BYTE((u8 *)(_pStart)+24, 8, 8)) +#define SET_QOS_CTRL_HC_CFP_TXOP_LIMIT(_pStart, _value) SET_BITS_TO_LE_2BYTE((u8 *)(_pStart)+24, 8, 8, (u8)(_value)) + +#define SET_WMM_QOS_INFO_FIELD(_pStart, _val) WriteEF1Byte(_pStart, _val) + +#define GET_WMM_QOS_INFO_FIELD_PARAMETERSET_COUNT(_pStart) LE_BITS_TO_1BYTE(_pStart, 0, 4) +#define SET_WMM_QOS_INFO_FIELD_PARAMETERSET_COUNT(_pStart, _val) SET_BITS_TO_LE_1BYTE(_pStart, 0, 4, _val) + +#define GET_WMM_QOS_INFO_FIELD_AP_UAPSD(_pStart) LE_BITS_TO_1BYTE(_pStart, 7, 1) +#define SET_WMM_QOS_INFO_FIELD_AP_UAPSD(_pStart, _val) SET_BITS_TO_LE_1BYTE(_pStart, 7, 1, _val) + +#define GET_WMM_QOS_INFO_FIELD_STA_AC_VO_UAPSD(_pStart) LE_BITS_TO_1BYTE(_pStart, 0, 1) +#define SET_WMM_QOS_INFO_FIELD_STA_AC_VO_UAPSD(_pStart, _val) SET_BITS_TO_LE_1BYTE(_pStart, 0, 1, _val) + +#define GET_WMM_QOS_INFO_FIELD_STA_AC_VI_UAPSD(_pStart) LE_BITS_TO_1BYTE(_pStart, 1, 1) +#define SET_WMM_QOS_INFO_FIELD_STA_AC_VI_UAPSD(_pStart, _val) SET_BITS_TO_LE_1BYTE(_pStart, 1, 1, _val) + +#define GET_WMM_QOS_INFO_FIELD_STA_AC_BE_UAPSD(_pStart) LE_BITS_TO_1BYTE(_pStart, 2, 1) +#define SET_WMM_QOS_INFO_FIELD_STA_AC_BE_UAPSD(_pStart, _val) SET_BITS_TO_LE_1BYTE(_pStart, 2, 1, _val) + +#define GET_WMM_QOS_INFO_FIELD_STA_AC_BK_UAPSD(_pStart) LE_BITS_TO_1BYTE(_pStart, 3, 1) +#define SET_WMM_QOS_INFO_FIELD_STA_AC_BK_UAPSD(_pStart, _val) SET_BITS_TO_LE_1BYTE(_pStart, 3, 1, _val) + +#define GET_WMM_QOS_INFO_FIELD_STA_MAX_SP_LEN(_pStart) LE_BITS_TO_1BYTE(_pStart, 5, 2) +#define SET_WMM_QOS_INFO_FIELD_STA_MAX_SP_LEN(_pStart, _val) SET_BITS_TO_LE_1BYTE(_pStart, 5, 2, _val) + + +#define WMM_INFO_ELEMENT_SIZE 7 + +#define GET_WMM_INFO_ELE_OUI(_pStart) ((u8 *)(_pStart)) +#define SET_WMM_INFO_ELE_OUI(_pStart, _pVal) PlatformMoveMemory(_pStart, _pVal, 3); + +#define GET_WMM_INFO_ELE_OUI_TYPE(_pStart) ( EF1Byte( *((u8 *)(_pStart)+3) ) ) +#define SET_WMM_INFO_ELE_OUI_TYPE(_pStart, _val) ( *((u8 *)(_pStart)+3) = EF1Byte(_val) ) + +#define GET_WMM_INFO_ELE_OUI_SUBTYPE(_pStart) ( EF1Byte( *((u8 *)(_pStart)+4) ) ) +#define SET_WMM_INFO_ELE_OUI_SUBTYPE(_pStart, _val) ( *((u8 *)(_pStart)+4) = EF1Byte(_val) ) + +#define GET_WMM_INFO_ELE_VERSION(_pStart) ( EF1Byte( *((u8 *)(_pStart)+5) ) ) +#define SET_WMM_INFO_ELE_VERSION(_pStart, _val) ( *((u8 *)(_pStart)+5) = EF1Byte(_val) ) + +#define GET_WMM_INFO_ELE_QOS_INFO_FIELD(_pStart) ( EF1Byte( *((u8 *)(_pStart)+6) ) ) +#define SET_WMM_INFO_ELE_QOS_INFO_FIELD(_pStart, _val) ( *((u8 *)(_pStart)+6) = EF1Byte(_val) ) + + + +#define GET_WMM_AC_PARAM_AIFSN(_pStart) ( (u8)LE_BITS_TO_4BYTE(_pStart, 0, 4) ) +#define SET_WMM_AC_PARAM_AIFSN(_pStart, _val) SET_BITS_TO_LE_4BYTE(_pStart, 0, 4, _val) + +#define GET_WMM_AC_PARAM_ACM(_pStart) ( (u8)LE_BITS_TO_4BYTE(_pStart, 4, 1) ) +#define SET_WMM_AC_PARAM_ACM(_pStart, _val) SET_BITS_TO_LE_4BYTE(_pStart, 4, 1, _val) + +#define GET_WMM_AC_PARAM_ACI(_pStart) ( (u8)LE_BITS_TO_4BYTE(_pStart, 5, 2) ) +#define SET_WMM_AC_PARAM_ACI(_pStart, _val) SET_BITS_TO_LE_4BYTE(_pStart, 5, 2, _val) + +#define GET_WMM_AC_PARAM_ACI_AIFSN(_pStart) ( (u8)LE_BITS_TO_4BYTE(_pStart, 0, 8) ) +#define SET_WMM_AC_PARAM_ACI_AIFSN(_pStart, _val) SET_BTIS_TO_LE_4BYTE(_pStart, 0, 8, _val) + +#define GET_WMM_AC_PARAM_ECWMIN(_pStart) ( (u8)LE_BITS_TO_4BYTE(_pStart, 8, 4) ) +#define SET_WMM_AC_PARAM_ECWMIN(_pStart, _val) SET_BITS_TO_LE_4BYTE(_pStart, 8, 4, _val) + +#define GET_WMM_AC_PARAM_ECWMAX(_pStart) ( (u8)LE_BITS_TO_4BYTE(_pStart, 12, 4) ) +#define SET_WMM_AC_PARAM_ECWMAX(_pStart, _val) SET_BITS_TO_LE_4BYTE(_pStart, 12, 4, _val) + +#define GET_WMM_AC_PARAM_TXOP_LIMIT(_pStart) ( (u16)LE_BITS_TO_4BYTE(_pStart, 16, 16) ) +#define SET_WMM_AC_PARAM_TXOP_LIMIT(_pStart, _val) SET_BITS_TO_LE_4BYTE(_pStart, 16, 16, _val) + + + + +#define GET_WMM_PARAM_ELE_OUI(_pStart) ((u8 *)(_pStart)) +#define SET_WMM_PARAM_ELE_OUI(_pStart, _pVal) PlatformMoveMemory(_pStart, _pVal, 3) + +#define GET_WMM_PARAM_ELE_OUI_TYPE(_pStart) ( EF1Byte( *((u8 *)(_pStart)+3) ) ) +#define SET_WMM_PARAM_ELE_OUI_TYPE(_pStart, _val) ( *((u8 *)(_pStart)+3) = EF1Byte(_val) ) + +#define GET_WMM_PARAM_ELE_OUI_SUBTYPE(_pStart) ( EF1Byte( *((u8 *)(_pStart)+4) ) ) +#define SET_WMM_PARAM_ELE_OUI_SUBTYPE(_pStart, _val) ( *((u8 *)(_pStart)+4) = EF1Byte(_val) ) + +#define GET_WMM_PARAM_ELE_VERSION(_pStart) ( EF1Byte( *((u8 *)(_pStart)+5) ) ) +#define SET_WMM_PARAM_ELE_VERSION(_pStart, _val) ( *((u8 *)(_pStart)+5) = EF1Byte(_val) ) + +#define GET_WMM_PARAM_ELE_QOS_INFO_FIELD(_pStart) ( EF1Byte( *((u8 *)(_pStart)+6) ) ) +#define SET_WMM_PARAM_ELE_QOS_INFO_FIELD(_pStart, _val) ( *((u8 *)(_pStart)+6) = EF1Byte(_val) ) + +#define GET_WMM_PARAM_ELE_AC_PARAM(_pStart) ( (u8 *)(_pStart)+8 ) +#define SET_WMM_PARAM_ELE_AC_PARAM(_pStart, _pVal) PlatformMoveMemory((_pStart)+8, _pVal, 16) +#endif + +// +// QoS Control Field +// Ref: +// 1. WMM spec 2.1.6: QoS Control Field, p.9. +// 2. 802.11e/D13.0 7.1.3.5, p.26. +// +typedef union _QOS_CTRL_FIELD{ + u8 charData[2]; + u16 shortData; + + // WMM spec + struct + { + u8 UP:3; + u8 usRsvd1:1; + u8 EOSP:1; + u8 AckPolicy:2; + u8 usRsvd2:1; + u8 ucRsvdByte; + }WMM; + + // 802.11e: QoS data type frame sent by non-AP QSTAs. + struct + { + u8 TID:4; + u8 bIsQsize:1;// 0: BIT[8:15] is TXOP Duration Requested, 1: BIT[8:15] is Queue Size. + u8 AckPolicy:2; + u8 usRsvd:1; + u8 TxopOrQsize; // (BIT4=0)TXOP Duration Requested or (BIT4=1)Queue Size. + }BySta; + + // 802.11e: QoS data, QoS Null, and QoS Data+CF-Ack frames sent by HC. + struct + { + u8 TID:4; + u8 EOSP:1; + u8 AckPolicy:2; + u8 usRsvd:1; + u8 PSBufState; // QAP PS Buffer State. + }ByHc_Data; + + // 802.11e: QoS (+) CF-Poll frames sent by HC. + struct + { + u8 TID:4; + u8 EOSP:1; + u8 AckPolicy:2; + u8 usRsvd:1; + u8 TxopLimit; // TXOP Limit. + }ByHc_CFP; + +}QOS_CTRL_FIELD, *PQOS_CTRL_FIELD; + + +// +// QoS Info Field +// Ref: +// 1. WMM spec 2.2.1: WME Information Element, p.11. +// 2. 8185 QoS code: QOS_INFO [def. in QoS_mp.h] +// +typedef union _QOS_INFO_FIELD{ + u8 charData; + + struct + { + u8 ucParameterSetCount:4; + u8 ucReserved:4; + }WMM; + + struct + { + //Ref WMM_Specification_1-1.pdf, 2006-06-13 Isaiah + u8 ucAC_VO_UAPSD:1; + u8 ucAC_VI_UAPSD:1; + u8 ucAC_BE_UAPSD:1; + u8 ucAC_BK_UAPSD:1; + u8 ucReserved1:1; + u8 ucMaxSPLen:2; + u8 ucReserved2:1; + + }ByWmmPsSta; + + struct + { + //Ref WMM_Specification_1-1.pdf, 2006-06-13 Isaiah + u8 ucParameterSetCount:4; + u8 ucReserved:3; + u8 ucApUapsd:1; + }ByWmmPsAp; + + struct + { + u8 ucAC3_UAPSD:1; + u8 ucAC2_UAPSD:1; + u8 ucAC1_UAPSD:1; + u8 ucAC0_UAPSD:1; + u8 ucQAck:1; + u8 ucMaxSPLen:2; + u8 ucMoreDataAck:1; + } By11eSta; + + struct + { + u8 ucParameterSetCount:4; + u8 ucQAck:1; + u8 ucQueueReq:1; + u8 ucTXOPReq:1; + u8 ucReserved:1; + } By11eAp; + + struct + { + u8 ucReserved1:4; + u8 ucQAck:1; + u8 ucReserved2:2; + u8 ucMoreDataAck:1; + } ByWmmsaSta; + + struct + { + u8 ucReserved1:4; + u8 ucQAck:1; + u8 ucQueueReq:1; + u8 ucTXOPReq:1; + u8 ucReserved2:1; + } ByWmmsaAp; + + struct + { + u8 ucAC3_UAPSD:1; + u8 ucAC2_UAPSD:1; + u8 ucAC1_UAPSD:1; + u8 ucAC0_UAPSD:1; + u8 ucQAck:1; + u8 ucMaxSPLen:2; + u8 ucMoreDataAck:1; + } ByAllSta; + + struct + { + u8 ucParameterSetCount:4; + u8 ucQAck:1; + u8 ucQueueReq:1; + u8 ucTXOPReq:1; + u8 ucApUapsd:1; + } ByAllAp; + +}QOS_INFO_FIELD, *PQOS_INFO_FIELD; + +#if 0 +// +// WMM Information Element +// Ref: WMM spec 2.2.1: WME Information Element, p.10. +// +typedef struct _WMM_INFO_ELEMENT{ +// u8 ElementID; +// u8 Length; + u8 OUI[3]; + u8 OUI_Type; + u8 OUI_SubType; + u8 Version; + QOS_INFO_FIELD QosInfo; +}WMM_INFO_ELEMENT, *PWMM_INFO_ELEMENT; +#endif + +// +// ACI to AC coding. +// Ref: WMM spec 2.2.2: WME Parameter Element, p.13. +// +// AC_CODING is redefined for enum can't be ++, | under C++ compiler, 2006.05.17, by rcnjko. +//typedef enum _AC_CODING{ +// AC0_BE = 0, // ACI: 0x00 // Best Effort +// AC1_BK = 1, // ACI: 0x01 // Background +// AC2_VI = 2, // ACI: 0x10 // Video +// AC3_VO = 3, // ACI: 0x11 // Voice +// AC_MAX = 4, // Max: define total number; Should not to be used as a real enum. +//}AC_CODING,*PAC_CODING; +// +typedef u32 AC_CODING; +#define AC0_BE 0 // ACI: 0x00 // Best Effort +#define AC1_BK 1 // ACI: 0x01 // Background +#define AC2_VI 2 // ACI: 0x10 // Video +#define AC3_VO 3 // ACI: 0x11 // Voice +#define AC_MAX 4 // Max: define total number; Should not to be used as a real enum. + +// +// ACI/AIFSN Field. +// Ref: WMM spec 2.2.2: WME Parameter Element, p.12. +// +typedef union _ACI_AIFSN{ + u8 charData; + + struct + { + u8 AIFSN:4; + u8 ACM:1; + u8 ACI:2; + u8 Reserved:1; + }f; // Field +}ACI_AIFSN, *PACI_AIFSN; + +// +// ECWmin/ECWmax field. +// Ref: WMM spec 2.2.2: WME Parameter Element, p.13. +// +typedef union _ECW{ + u8 charData; + struct + { + u8 ECWmin:4; + u8 ECWmax:4; + }f; // Field +}ECW, *PECW; + +// +// AC Parameters Record Format. +// Ref: WMM spec 2.2.2: WME Parameter Element, p.12. +// +typedef union _AC_PARAM{ + u32 longData; + u8 charData[4]; + + struct + { + ACI_AIFSN AciAifsn; + ECW Ecw; + u16 TXOPLimit; + }f; // Field +}AC_PARAM, *PAC_PARAM; + + + +// +// QoS element subtype +// +typedef enum _QOS_ELE_SUBTYPE{ + QOSELE_TYPE_INFO = 0x00, // 0x00: Information element + QOSELE_TYPE_PARAM = 0x01, // 0x01: parameter element +}QOS_ELE_SUBTYPE,*PQOS_ELE_SUBTYPE; + + +// +// Direction Field Values. +// Ref: WMM spec 2.2.11: WME TSPEC Element, p.18. +// +typedef enum _DIRECTION_VALUE{ + DIR_UP = 0, // 0x00 // UpLink + DIR_DOWN = 1, // 0x01 // DownLink + DIR_DIRECT = 2, // 0x10 // DirectLink + DIR_BI_DIR = 3, // 0x11 // Bi-Direction +}DIRECTION_VALUE,*PDIRECTION_VALUE; + + +// +// TS Info field in WMM TSPEC Element. +// Ref: +// 1. WMM spec 2.2.11: WME TSPEC Element, p.18. +// 2. 8185 QoS code: QOS_TSINFO [def. in QoS_mp.h] +// +typedef union _QOS_TSINFO{ + u8 charData[3]; + struct { + u8 ucTrafficType:1; //WMM is reserved + u8 ucTSID:4; + u8 ucDirection:2; + u8 ucAccessPolicy:2; //WMM: bit8=0, bit7=1 + u8 ucAggregation:1; //WMM is reserved + u8 ucPSB:1; //WMMSA is APSD + u8 ucUP:3; + u8 ucTSInfoAckPolicy:2; //WMM is reserved + u8 ucSchedule:1; //WMM is reserved + u8 ucReserved:7; + }field; +}QOS_TSINFO, *PQOS_TSINFO; + +// +// WMM TSPEC Body. +// Ref: WMM spec 2.2.11: WME TSPEC Element, p.16. +// +typedef union _TSPEC_BODY{ + u8 charData[55]; + + struct + { + QOS_TSINFO TSInfo; //u8 TSInfo[3]; + u16 NominalMSDUsize; + u16 MaxMSDUsize; + u32 MinServiceItv; + u32 MaxServiceItv; + u32 InactivityItv; + u32 SuspenItv; + u32 ServiceStartTime; + u32 MinDataRate; + u32 MeanDataRate; + u32 PeakDataRate; + u32 MaxBurstSize; + u32 DelayBound; + u32 MinPhyRate; + u16 SurplusBandwidthAllowance; + u16 MediumTime; + } f; // Field +}TSPEC_BODY, *PTSPEC_BODY; + + +// +// WMM TSPEC Element. +// Ref: WMM spec 2.2.11: WME TSPEC Element, p.16. +// +typedef struct _WMM_TSPEC{ + u8 ID; + u8 Length; + u8 OUI[3]; + u8 OUI_Type; + u8 OUI_SubType; + u8 Version; + TSPEC_BODY Body; +} WMM_TSPEC, *PWMM_TSPEC; + +// +// ACM implementation method. +// Annie, 2005-12-13. +// +typedef enum _ACM_METHOD{ + eAcmWay0_SwAndHw = 0, // By SW and HW. + eAcmWay1_HW = 1, // By HW. + eAcmWay2_SW = 2, // By SW. +}ACM_METHOD,*PACM_METHOD; + + +typedef struct _ACM{ +// u8 RegEnableACM; + u64 UsedTime; + u64 MediumTime; + u8 HwAcmCtl; // TRUE: UsedTime exceed => Do NOT USE this AC. It wll be written to ACM_CONTROL(0xBF BIT 0/1/2 in 8185B). +}ACM, *PACM; + +typedef u8 AC_UAPSD, *PAC_UAPSD; + +#define GET_VO_UAPSD(_apsd) ((_apsd) & BIT0) +#define SET_VO_UAPSD(_apsd) ((_apsd) |= BIT0) + +#define GET_VI_UAPSD(_apsd) ((_apsd) & BIT1) +#define SET_VI_UAPSD(_apsd) ((_apsd) |= BIT1) + +#define GET_BK_UAPSD(_apsd) ((_apsd) & BIT2) +#define SET_BK_UAPSD(_apsd) ((_apsd) |= BIT2) + +#define GET_BE_UAPSD(_apsd) ((_apsd) & BIT3) +#define SET_BE_UAPSD(_apsd) ((_apsd) |= BIT3) + + +//typedef struct _TCLASS{ +// TODO +//} TCLASS, *PTCLASS; +typedef union _QOS_TCLAS{ + + struct _TYPE_GENERAL{ + u8 Priority; + u8 ClassifierType; + u8 Mask; + } TYPE_GENERAL; + + struct _TYPE0_ETH{ + u8 Priority; + u8 ClassifierType; + u8 Mask; + u8 SrcAddr[6]; + u8 DstAddr[6]; + u16 Type; + } TYPE0_ETH; + + struct _TYPE1_IPV4{ + u8 Priority; + u8 ClassifierType; + u8 Mask; + u8 Version; + u8 SrcIP[4]; + u8 DstIP[4]; + u16 SrcPort; + u16 DstPort; + u8 DSCP; + u8 Protocol; + u8 Reserved; + } TYPE1_IPV4; + + struct _TYPE1_IPV6{ + u8 Priority; + u8 ClassifierType; + u8 Mask; + u8 Version; + u8 SrcIP[16]; + u8 DstIP[16]; + u16 SrcPort; + u16 DstPort; + u8 FlowLabel[3]; + } TYPE1_IPV6; + + struct _TYPE2_8021Q{ + u8 Priority; + u8 ClassifierType; + u8 Mask; + u16 TagType; + } TYPE2_8021Q; +} QOS_TCLAS, *PQOS_TCLAS; + +//typedef struct _WMM_TSTREAM{ +// +//- TSPEC +//- AC (which to mapping) +//} WMM_TSTREAM, *PWMM_TSTREAM; +typedef struct _QOS_TSTREAM{ + u8 AC; + WMM_TSPEC TSpec; + QOS_TCLAS TClass; +} QOS_TSTREAM, *PQOS_TSTREAM; + +//typedef struct _U_APSD{ +//- TriggerEnable [4] +//- MaxSPLength +//- HighestAcBuffered +//} U_APSD, *PU_APSD; + +//joseph TODO: +// UAPSD function should be implemented by 2 data structure +// "Qos control field" and "Qos info field" +//typedef struct _QOS_UAPSD{ +// u8 bTriggerEnable[4]; +// u8 MaxSPLength; +// u8 HighestBufAC; +//} QOS_UAPSD, *PQOS_APSD; + +//---------------------------------------------------------------------------- +// 802.11 Management frame Status Code field +//---------------------------------------------------------------------------- +typedef struct _OCTET_STRING{ + u8 *Octet; + u16 Length; +}OCTET_STRING, *POCTET_STRING; +#if 0 +#define FillOctetString(_os,_octet,_len) \ + (_os).Octet=(u8 *)(_octet); \ + (_os).Length=(_len); + +#define WMM_ELEM_HDR_LEN 6 +#define WMMElemSkipHdr(_osWMMElem) \ + (_osWMMElem).Octet += WMM_ELEM_HDR_LEN; \ + (_osWMMElem).Length -= WMM_ELEM_HDR_LEN; +#endif +// +// STA QoS data. +// Ref: DOT11_QOS in 8185 code. [def. in QoS_mp.h] +// +typedef struct _STA_QOS{ + //DECLARE_RT_OBJECT(STA_QOS); + u8 WMMIEBuf[MAX_WMMELE_LENGTH]; + u8* WMMIE; + + // Part 1. Self QoS Mode. + QOS_MODE QosCapability; //QoS Capability, 2006-06-14 Isaiah + QOS_MODE CurrentQosMode; + + // For WMM Power Save Mode : + // ACs are trigger/delivery enabled or legacy power save enabled. 2006-06-13 Isaiah + AC_UAPSD b4ac_Uapsd; //VoUapsd(bit0), ViUapsd(bit1), BkUapsd(bit2), BeUapsd(bit3), + AC_UAPSD Curr4acUapsd; + u8 bInServicePeriod; + u8 MaxSPLength; + int NumBcnBeforeTrigger; + + // Part 2. EDCA Parameter (perAC) + u8 * pWMMInfoEle; + u8 WMMParamEle[WMM_PARAM_ELEMENT_SIZE]; + u8 WMMPELength; + + // + //2 ToDo: remove the Qos Info Field and replace it by the above WMM Info element. + // By Bruce, 2008-01-30. + // Part 2. EDCA Parameter (perAC) + QOS_INFO_FIELD QosInfoField_STA; // Maintained by STA + QOS_INFO_FIELD QosInfoField_AP; // Retrieved from AP + + AC_PARAM CurAcParameters[4]; + + // Part 3. ACM + ACM acm[4]; + ACM_METHOD AcmMethod; + + // Part 4. Per TID (Part 5: TCLASS will be described by TStream) + QOS_TSTREAM TStream[16]; + WMM_TSPEC TSpec; + + u32 QBssWirelessMode; + + // No Ack Setting + u8 bNoAck; + + // Enable/Disable Rx immediate BA capability. + u8 bEnableRxImmBA; + +}STA_QOS, *PSTA_QOS; + +// +// BSS QOS data. +// Ref: BssDscr in 8185 code. [def. in BssDscr.h] +// +typedef struct _BSS_QOS{ + QOS_MODE bdQoSMode; + + u8 bdWMMIEBuf[MAX_WMMELE_LENGTH]; + u8* bdWMMIE; + + QOS_ELE_SUBTYPE EleSubType; + + u8 * pWMMInfoEle; + u8 * pWMMParamEle; + + QOS_INFO_FIELD QosInfoField; + AC_PARAM AcParameter[4]; +}BSS_QOS, *PBSS_QOS; + + +// +// Ref: sQoSCtlLng and QoSCtl definition in 8185 QoS code. +//#define QoSCtl (( (Adapter->bRegQoS) && (Adapter->dot11QoS.QoSMode &(QOS_EDCA|QOS_HCCA)) ) ?sQoSCtlLng:0) +// +#define sQoSCtlLng 2 +#define QOS_CTRL_LEN(_QosMode) ((_QosMode > QOS_DISABLE)? sQoSCtlLng : 0) + + +//Added by joseph +//UP Mapping to AC, using in MgntQuery_SequenceNumber() and maybe for DSCP +//#define UP2AC(up) ((up<3)?((up==0)?1:0):(up>>1)) +#define IsACValid(ac) ((ac<=7 )?true:false ) + +#endif // #ifndef __INC_QOS_TYPE_H diff --git a/drivers/staging/rtl8192su/ieee80211/rtl819x_TS.h b/drivers/staging/rtl8192su/ieee80211/rtl819x_TS.h new file mode 100644 index 000000000000..baaac2149de1 --- /dev/null +++ b/drivers/staging/rtl8192su/ieee80211/rtl819x_TS.h @@ -0,0 +1,56 @@ +#ifndef _TSTYPE_H_ +#define _TSTYPE_H_ +#include "rtl819x_Qos.h" +#define TS_SETUP_TIMEOUT 60 // In millisecond +#define TS_INACT_TIMEOUT 60 +#define TS_ADDBA_DELAY 60 + +#define TOTAL_TS_NUM 16 +#define TCLAS_NUM 4 + +// This define the Tx/Rx directions +typedef enum _TR_SELECT { + TX_DIR = 0, + RX_DIR = 1, +} TR_SELECT, *PTR_SELECT; + +typedef struct _TS_COMMON_INFO{ + struct list_head List; + struct timer_list SetupTimer; + struct timer_list InactTimer; + u8 Addr[6]; + TSPEC_BODY TSpec; + QOS_TCLAS TClass[TCLAS_NUM]; + u8 TClasProc; + u8 TClasNum; +} TS_COMMON_INFO, *PTS_COMMON_INFO; + +typedef struct _TX_TS_RECORD{ + TS_COMMON_INFO TsCommonInfo; + u16 TxCurSeq; + BA_RECORD TxPendingBARecord; // For BA Originator + BA_RECORD TxAdmittedBARecord; // For BA Originator +// QOS_DL_RECORD DLRecord; + u8 bAddBaReqInProgress; + u8 bAddBaReqDelayed; + u8 bUsingBa; + struct timer_list TsAddBaTimer; + u8 num; +} TX_TS_RECORD, *PTX_TS_RECORD; + +typedef struct _RX_TS_RECORD { + TS_COMMON_INFO TsCommonInfo; + u16 RxIndicateSeq; + u16 RxTimeoutIndicateSeq; + struct list_head RxPendingPktList; + struct timer_list RxPktPendingTimer; + BA_RECORD RxAdmittedBARecord; // For BA Recepient + u16 RxLastSeqNum; + u8 RxLastFragNum; + u8 num; +// QOS_DL_RECORD DLRecord; +} RX_TS_RECORD, *PRX_TS_RECORD; + + +#endif + diff --git a/drivers/staging/rtl8192su/ieee80211/rtl819x_TSProc.c b/drivers/staging/rtl8192su/ieee80211/rtl819x_TSProc.c new file mode 100644 index 000000000000..6fb7033ed360 --- /dev/null +++ b/drivers/staging/rtl8192su/ieee80211/rtl819x_TSProc.c @@ -0,0 +1,667 @@ +#include "ieee80211.h" +#include +#include "rtl819x_TS.h" + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +#define list_for_each_entry_safe(pos, n, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) +#endif +void TsSetupTimeOut(unsigned long data) +{ + // Not implement yet + // This is used for WMMSA and ACM , that would send ADDTSReq frame. +} + +void TsInactTimeout(unsigned long data) +{ + // Not implement yet + // This is used for WMMSA and ACM. + // This function would be call when TS is no Tx/Rx for some period of time. +} + +/******************************************************************************************************************** + *function: I still not understand this function, so wait for further implementation + * input: unsigned long data //acturally we send TX_TS_RECORD or RX_TS_RECORD to these timer + * return: NULL + * notice: +********************************************************************************************************************/ +#if 1 +void RxPktPendingTimeout(unsigned long data) +{ + PRX_TS_RECORD pRxTs = (PRX_TS_RECORD)data; + struct ieee80211_device *ieee = container_of(pRxTs, struct ieee80211_device, RxTsRecord[pRxTs->num]); + + PRX_REORDER_ENTRY pReorderEntry = NULL; + + //u32 flags = 0; + unsigned long flags = 0; + struct ieee80211_rxb *stats_IndicateArray[REORDER_WIN_SIZE]; + u8 index = 0; + bool bPktInBuf = false; + + + spin_lock_irqsave(&(ieee->reorder_spinlock), flags); + //PlatformAcquireSpinLock(Adapter, RT_RX_SPINLOCK); + IEEE80211_DEBUG(IEEE80211_DL_REORDER,"==================>%s()\n",__FUNCTION__); + if(pRxTs->RxTimeoutIndicateSeq != 0xffff) + { + // Indicate the pending packets sequentially according to SeqNum until meet the gap. + while(!list_empty(&pRxTs->RxPendingPktList)) + { + pReorderEntry = (PRX_REORDER_ENTRY)list_entry(pRxTs->RxPendingPktList.prev,RX_REORDER_ENTRY,List); + if(index == 0) + pRxTs->RxIndicateSeq = pReorderEntry->SeqNum; + + if( SN_LESS(pReorderEntry->SeqNum, pRxTs->RxIndicateSeq) || + SN_EQUAL(pReorderEntry->SeqNum, pRxTs->RxIndicateSeq) ) + { + list_del_init(&pReorderEntry->List); + + if(SN_EQUAL(pReorderEntry->SeqNum, pRxTs->RxIndicateSeq)) + pRxTs->RxIndicateSeq = (pRxTs->RxIndicateSeq + 1) % 4096; + + IEEE80211_DEBUG(IEEE80211_DL_REORDER,"RxPktPendingTimeout(): IndicateSeq: %d\n", pReorderEntry->SeqNum); + stats_IndicateArray[index] = pReorderEntry->prxb; + index++; + + list_add_tail(&pReorderEntry->List, &ieee->RxReorder_Unused_List); + } + else + { + bPktInBuf = true; + break; + } + } + } + + if(index>0) + { + // Set RxTimeoutIndicateSeq to 0xffff to indicate no pending packets in buffer now. + pRxTs->RxTimeoutIndicateSeq = 0xffff; + + // Indicate packets + if(index > REORDER_WIN_SIZE){ + IEEE80211_DEBUG(IEEE80211_DL_ERR, "RxReorderIndicatePacket(): Rx Reorer buffer full!! \n"); + spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags); + return; + } + ieee80211_indicate_packets(ieee, stats_IndicateArray, index); + bPktInBuf = false; + + } + + if(bPktInBuf && (pRxTs->RxTimeoutIndicateSeq==0xffff)) + { + pRxTs->RxTimeoutIndicateSeq = pRxTs->RxIndicateSeq; +#if 0 + if(timer_pending(&pTS->RxPktPendingTimer)) + del_timer_sync(&pTS->RxPktPendingTimer); + pTS->RxPktPendingTimer.expires = jiffies + MSECS(pHTInfo->RxReorderPendingTime); + add_timer(&pTS->RxPktPendingTimer); +#else + mod_timer(&pRxTs->RxPktPendingTimer, jiffies + MSECS(ieee->pHTInfo->RxReorderPendingTime)); +#endif + +#if 0 + if(timer_pending(&pRxTs->RxPktPendingTimer)) + del_timer_sync(&pRxTs->RxPktPendingTimer); + pRxTs->RxPktPendingTimer.expires = jiffies + ieee->pHTInfo->RxReorderPendingTime; + add_timer(&pRxTs->RxPktPendingTimer); +#endif + } + spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags); + //PlatformReleaseSpinLock(Adapter, RT_RX_SPINLOCK); +} +#endif + +/******************************************************************************************************************** + *function: Add BA timer function + * input: unsigned long data //acturally we send TX_TS_RECORD or RX_TS_RECORD to these timer + * return: NULL + * notice: +********************************************************************************************************************/ +void TsAddBaProcess(unsigned long data) +{ + PTX_TS_RECORD pTxTs = (PTX_TS_RECORD)data; + u8 num = pTxTs->num; + struct ieee80211_device *ieee = container_of(pTxTs, struct ieee80211_device, TxTsRecord[num]); + + TsInitAddBA(ieee, pTxTs, BA_POLICY_IMMEDIATE, false); + IEEE80211_DEBUG(IEEE80211_DL_BA, "TsAddBaProcess(): ADDBA Req is started!! \n"); +} + + +void ResetTsCommonInfo(PTS_COMMON_INFO pTsCommonInfo) +{ + memset(pTsCommonInfo->Addr, 0, 6); + memset(&pTsCommonInfo->TSpec, 0, sizeof(TSPEC_BODY)); + memset(&pTsCommonInfo->TClass, 0, sizeof(QOS_TCLAS)*TCLAS_NUM); + pTsCommonInfo->TClasProc = 0; + pTsCommonInfo->TClasNum = 0; +} + +void ResetTxTsEntry(PTX_TS_RECORD pTS) +{ + ResetTsCommonInfo(&pTS->TsCommonInfo); + pTS->TxCurSeq = 0; + pTS->bAddBaReqInProgress = false; + pTS->bAddBaReqDelayed = false; + pTS->bUsingBa = false; + ResetBaEntry(&pTS->TxAdmittedBARecord); //For BA Originator + ResetBaEntry(&pTS->TxPendingBARecord); +} + +void ResetRxTsEntry(PRX_TS_RECORD pTS) +{ + ResetTsCommonInfo(&pTS->TsCommonInfo); + pTS->RxIndicateSeq = 0xffff; // This indicate the RxIndicateSeq is not used now!! + pTS->RxTimeoutIndicateSeq = 0xffff; // This indicate the RxTimeoutIndicateSeq is not used now!! + ResetBaEntry(&pTS->RxAdmittedBARecord); // For BA Recepient +} + +void TSInitialize(struct ieee80211_device *ieee) +{ + PTX_TS_RECORD pTxTS = ieee->TxTsRecord; + PRX_TS_RECORD pRxTS = ieee->RxTsRecord; + PRX_REORDER_ENTRY pRxReorderEntry = ieee->RxReorderEntry; + u8 count = 0; + IEEE80211_DEBUG(IEEE80211_DL_TS, "==========>%s()\n", __FUNCTION__); + // Initialize Tx TS related info. + INIT_LIST_HEAD(&ieee->Tx_TS_Admit_List); + INIT_LIST_HEAD(&ieee->Tx_TS_Pending_List); + INIT_LIST_HEAD(&ieee->Tx_TS_Unused_List); + + for(count = 0; count < TOTAL_TS_NUM; count++) + { + // + pTxTS->num = count; + // The timers for the operation of Traffic Stream and Block Ack. + // DLS related timer will be add here in the future!! + init_timer(&pTxTS->TsCommonInfo.SetupTimer); + pTxTS->TsCommonInfo.SetupTimer.data = (unsigned long)pTxTS; + pTxTS->TsCommonInfo.SetupTimer.function = TsSetupTimeOut; + + init_timer(&pTxTS->TsCommonInfo.InactTimer); + pTxTS->TsCommonInfo.InactTimer.data = (unsigned long)pTxTS; + pTxTS->TsCommonInfo.InactTimer.function = TsInactTimeout; + + init_timer(&pTxTS->TsAddBaTimer); + pTxTS->TsAddBaTimer.data = (unsigned long)pTxTS; + pTxTS->TsAddBaTimer.function = TsAddBaProcess; + + init_timer(&pTxTS->TxPendingBARecord.Timer); + pTxTS->TxPendingBARecord.Timer.data = (unsigned long)pTxTS; + pTxTS->TxPendingBARecord.Timer.function = BaSetupTimeOut; + + init_timer(&pTxTS->TxAdmittedBARecord.Timer); + pTxTS->TxAdmittedBARecord.Timer.data = (unsigned long)pTxTS; + pTxTS->TxAdmittedBARecord.Timer.function = TxBaInactTimeout; + + ResetTxTsEntry(pTxTS); + list_add_tail(&pTxTS->TsCommonInfo.List, &ieee->Tx_TS_Unused_List); + pTxTS++; + } + + // Initialize Rx TS related info. + INIT_LIST_HEAD(&ieee->Rx_TS_Admit_List); + INIT_LIST_HEAD(&ieee->Rx_TS_Pending_List); + INIT_LIST_HEAD(&ieee->Rx_TS_Unused_List); + for(count = 0; count < TOTAL_TS_NUM; count++) + { + pRxTS->num = count; + INIT_LIST_HEAD(&pRxTS->RxPendingPktList); + + init_timer(&pRxTS->TsCommonInfo.SetupTimer); + pRxTS->TsCommonInfo.SetupTimer.data = (unsigned long)pRxTS; + pRxTS->TsCommonInfo.SetupTimer.function = TsSetupTimeOut; + + init_timer(&pRxTS->TsCommonInfo.InactTimer); + pRxTS->TsCommonInfo.InactTimer.data = (unsigned long)pRxTS; + pRxTS->TsCommonInfo.InactTimer.function = TsInactTimeout; + + init_timer(&pRxTS->RxAdmittedBARecord.Timer); + pRxTS->RxAdmittedBARecord.Timer.data = (unsigned long)pRxTS; + pRxTS->RxAdmittedBARecord.Timer.function = RxBaInactTimeout; + + init_timer(&pRxTS->RxPktPendingTimer); + pRxTS->RxPktPendingTimer.data = (unsigned long)pRxTS; + pRxTS->RxPktPendingTimer.function = RxPktPendingTimeout; + + ResetRxTsEntry(pRxTS); + list_add_tail(&pRxTS->TsCommonInfo.List, &ieee->Rx_TS_Unused_List); + pRxTS++; + } + // Initialize unused Rx Reorder List. + INIT_LIST_HEAD(&ieee->RxReorder_Unused_List); +//#ifdef TO_DO_LIST + for(count = 0; count < REORDER_ENTRY_NUM; count++) + { + list_add_tail( &pRxReorderEntry->List,&ieee->RxReorder_Unused_List); + if(count == (REORDER_ENTRY_NUM-1)) + break; + pRxReorderEntry = &ieee->RxReorderEntry[count+1]; + } +//#endif + +} + +void AdmitTS(struct ieee80211_device *ieee, PTS_COMMON_INFO pTsCommonInfo, u32 InactTime) +{ + del_timer_sync(&pTsCommonInfo->SetupTimer); + del_timer_sync(&pTsCommonInfo->InactTimer); + + if(InactTime!=0) + mod_timer(&pTsCommonInfo->InactTimer, jiffies + MSECS(InactTime)); +} + + +PTS_COMMON_INFO SearchAdmitTRStream(struct ieee80211_device *ieee, u8* Addr, u8 TID, TR_SELECT TxRxSelect) +{ + //DIRECTION_VALUE dir; + u8 dir; + bool search_dir[4] = {0, 0, 0, 0}; + struct list_head* psearch_list; //FIXME + PTS_COMMON_INFO pRet = NULL; + if(ieee->iw_mode == IW_MODE_MASTER) //ap mode + { + if(TxRxSelect == TX_DIR) + { + search_dir[DIR_DOWN] = true; + search_dir[DIR_BI_DIR]= true; + } + else + { + search_dir[DIR_UP] = true; + search_dir[DIR_BI_DIR]= true; + } + } + else if(ieee->iw_mode == IW_MODE_ADHOC) + { + if(TxRxSelect == TX_DIR) + search_dir[DIR_UP] = true; + else + search_dir[DIR_DOWN] = true; + } + else + { + if(TxRxSelect == TX_DIR) + { + search_dir[DIR_UP] = true; + search_dir[DIR_BI_DIR]= true; + search_dir[DIR_DIRECT]= true; + } + else + { + search_dir[DIR_DOWN] = true; + search_dir[DIR_BI_DIR]= true; + search_dir[DIR_DIRECT]= true; + } + } + + if(TxRxSelect == TX_DIR) + psearch_list = &ieee->Tx_TS_Admit_List; + else + psearch_list = &ieee->Rx_TS_Admit_List; + + //for(dir = DIR_UP; dir <= DIR_BI_DIR; dir++) + for(dir = 0; dir <= DIR_BI_DIR; dir++) + { + if(search_dir[dir] ==false ) + continue; + list_for_each_entry(pRet, psearch_list, List){ + // IEEE80211_DEBUG(IEEE80211_DL_TS, "ADD:"MAC_FMT", TID:%d, dir:%d\n", MAC_ARG(pRet->Addr), pRet->TSpec.f.TSInfo.field.ucTSID, pRet->TSpec.f.TSInfo.field.ucDirection); + if (memcmp(pRet->Addr, Addr, 6) == 0) + if (pRet->TSpec.f.TSInfo.field.ucTSID == TID) + if(pRet->TSpec.f.TSInfo.field.ucDirection == dir) + { + // printk("Bingo! got it\n"); + break; + } + + } + if(&pRet->List != psearch_list) + break; + } + + if(&pRet->List != psearch_list){ + return pRet ; + } + else + return NULL; +} + +void MakeTSEntry( + PTS_COMMON_INFO pTsCommonInfo, + u8* Addr, + PTSPEC_BODY pTSPEC, + PQOS_TCLAS pTCLAS, + u8 TCLAS_Num, + u8 TCLAS_Proc + ) +{ + u8 count; + + if(pTsCommonInfo == NULL) + return; + + memcpy(pTsCommonInfo->Addr, Addr, 6); + + if(pTSPEC != NULL) + memcpy((u8*)(&(pTsCommonInfo->TSpec)), (u8*)pTSPEC, sizeof(TSPEC_BODY)); + + for(count = 0; count < TCLAS_Num; count++) + memcpy((u8*)(&(pTsCommonInfo->TClass[count])), (u8*)pTCLAS, sizeof(QOS_TCLAS)); + + pTsCommonInfo->TClasProc = TCLAS_Proc; + pTsCommonInfo->TClasNum = TCLAS_Num; +} + + +bool GetTs( + struct ieee80211_device* ieee, + PTS_COMMON_INFO *ppTS, + u8* Addr, + u8 TID, + TR_SELECT TxRxSelect, //Rx:1, Tx:0 + bool bAddNewTs + ) +{ + u8 UP = 0; + // + // We do not build any TS for Broadcast or Multicast stream. + // So reject these kinds of search here. + // + if(is_broadcast_ether_addr(Addr) || is_multicast_ether_addr(Addr)) + { + IEEE80211_DEBUG(IEEE80211_DL_ERR, "get TS for Broadcast or Multicast\n"); + return false; + } +#if 0 + if(ieee->pStaQos->CurrentQosMode == QOS_DISABLE) + { UP = 0; } //only use one TS + else if(ieee->pStaQos->CurrentQosMode & QOS_WMM) + { +#else + if (ieee->current_network.qos_data.supported == 0) + UP = 0; + else + { +#endif + // In WMM case: we use 4 TID only + if (!IsACValid(TID)) + { + IEEE80211_DEBUG(IEEE80211_DL_ERR, " in %s(), TID(%d) is not valid\n", __FUNCTION__, TID); + return false; + } + + switch(TID) + { + case 0: + case 3: + UP = 0; + break; + + case 1: + case 2: + UP = 2; + break; + + case 4: + case 5: + UP = 5; + break; + + case 6: + case 7: + UP = 7; + break; + } + } + + *ppTS = SearchAdmitTRStream( + ieee, + Addr, + UP, + TxRxSelect); + if(*ppTS != NULL) + { + return true; + } + else + { + if(bAddNewTs == false) + { + IEEE80211_DEBUG(IEEE80211_DL_TS, "add new TS failed(tid:%d)\n", UP); + return false; + } + else + { + // + // Create a new Traffic stream for current Tx/Rx + // This is for EDCA and WMM to add a new TS. + // For HCCA or WMMSA, TS cannot be addmit without negotiation. + // + TSPEC_BODY TSpec; + PQOS_TSINFO pTSInfo = &TSpec.f.TSInfo; + struct list_head* pUnusedList = + (TxRxSelect == TX_DIR)? + (&ieee->Tx_TS_Unused_List): + (&ieee->Rx_TS_Unused_List); + + struct list_head* pAddmitList = + (TxRxSelect == TX_DIR)? + (&ieee->Tx_TS_Admit_List): + (&ieee->Rx_TS_Admit_List); + + DIRECTION_VALUE Dir = (ieee->iw_mode == IW_MODE_MASTER)? + ((TxRxSelect==TX_DIR)?DIR_DOWN:DIR_UP): + ((TxRxSelect==TX_DIR)?DIR_UP:DIR_DOWN); + IEEE80211_DEBUG(IEEE80211_DL_TS, "to add Ts\n"); + if(!list_empty(pUnusedList)) + { + (*ppTS) = list_entry(pUnusedList->next, TS_COMMON_INFO, List); + list_del_init(&(*ppTS)->List); + if(TxRxSelect==TX_DIR) + { + PTX_TS_RECORD tmp = container_of(*ppTS, TX_TS_RECORD, TsCommonInfo); + ResetTxTsEntry(tmp); + } + else{ + PRX_TS_RECORD tmp = container_of(*ppTS, RX_TS_RECORD, TsCommonInfo); + ResetRxTsEntry(tmp); + } + + IEEE80211_DEBUG(IEEE80211_DL_TS, "to init current TS, UP:%d, Dir:%d, addr:"MAC_FMT"\n", UP, Dir, MAC_ARG(Addr)); + // Prepare TS Info releated field + pTSInfo->field.ucTrafficType = 0; // Traffic type: WMM is reserved in this field + pTSInfo->field.ucTSID = UP; // TSID + pTSInfo->field.ucDirection = Dir; // Direction: if there is DirectLink, this need additional consideration. + pTSInfo->field.ucAccessPolicy = 1; // Access policy + pTSInfo->field.ucAggregation = 0; // Aggregation + pTSInfo->field.ucPSB = 0; // Aggregation + pTSInfo->field.ucUP = UP; // User priority + pTSInfo->field.ucTSInfoAckPolicy = 0; // Ack policy + pTSInfo->field.ucSchedule = 0; // Schedule + + MakeTSEntry(*ppTS, Addr, &TSpec, NULL, 0, 0); + AdmitTS(ieee, *ppTS, 0); + list_add_tail(&((*ppTS)->List), pAddmitList); + // if there is DirectLink, we need to do additional operation here!! + + return true; + } + else + { + IEEE80211_DEBUG(IEEE80211_DL_ERR, "in function %s() There is not enough TS record to be used!!", __FUNCTION__); + return false; + } + } + } +} + +void RemoveTsEntry( + struct ieee80211_device* ieee, + PTS_COMMON_INFO pTs, + TR_SELECT TxRxSelect + ) +{ + //u32 flags = 0; + unsigned long flags = 0; + del_timer_sync(&pTs->SetupTimer); + del_timer_sync(&pTs->InactTimer); + TsInitDelBA(ieee, pTs, TxRxSelect); + + if(TxRxSelect == RX_DIR) + { +//#ifdef TO_DO_LIST + PRX_REORDER_ENTRY pRxReorderEntry; + PRX_TS_RECORD pRxTS = (PRX_TS_RECORD)pTs; + if(timer_pending(&pRxTS->RxPktPendingTimer)) + del_timer_sync(&pRxTS->RxPktPendingTimer); + + while(!list_empty(&pRxTS->RxPendingPktList)) + { + // PlatformAcquireSpinLock(Adapter, RT_RX_SPINLOCK); + spin_lock_irqsave(&(ieee->reorder_spinlock), flags); + //pRxReorderEntry = list_entry(&pRxTS->RxPendingPktList.prev,RX_REORDER_ENTRY,List); + pRxReorderEntry = (PRX_REORDER_ENTRY)list_entry(pRxTS->RxPendingPktList.prev,RX_REORDER_ENTRY,List); + list_del_init(&pRxReorderEntry->List); + { + int i = 0; + struct ieee80211_rxb * prxb = pRxReorderEntry->prxb; + if (unlikely(!prxb)) + { + spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags); + return; + } + for(i =0; i < prxb->nr_subframes; i++) { + dev_kfree_skb(prxb->subframes[i]); + } + kfree(prxb); + prxb = NULL; + } + list_add_tail(&pRxReorderEntry->List,&ieee->RxReorder_Unused_List); + //PlatformReleaseSpinLock(Adapter, RT_RX_SPINLOCK); + spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags); + } + +//#endif + } + else + { + PTX_TS_RECORD pTxTS = (PTX_TS_RECORD)pTs; + del_timer_sync(&pTxTS->TsAddBaTimer); + } +} + +void RemovePeerTS(struct ieee80211_device* ieee, u8* Addr) +{ + PTS_COMMON_INFO pTS, pTmpTS; + printk("===========>RemovePeerTS,"MAC_FMT"\n", MAC_ARG(Addr)); +#if 1 + list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Pending_List, List) + { + if (memcmp(pTS->Addr, Addr, 6) == 0) + { + RemoveTsEntry(ieee, pTS, TX_DIR); + list_del_init(&pTS->List); + list_add_tail(&pTS->List, &ieee->Tx_TS_Unused_List); + } + } + + list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Admit_List, List) + { + if (memcmp(pTS->Addr, Addr, 6) == 0) + { + printk("====>remove Tx_TS_admin_list\n"); + RemoveTsEntry(ieee, pTS, TX_DIR); + list_del_init(&pTS->List); + list_add_tail(&pTS->List, &ieee->Tx_TS_Unused_List); + } + } + + list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Pending_List, List) + { + if (memcmp(pTS->Addr, Addr, 6) == 0) + { + RemoveTsEntry(ieee, pTS, RX_DIR); + list_del_init(&pTS->List); + list_add_tail(&pTS->List, &ieee->Rx_TS_Unused_List); + } + } + + list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Admit_List, List) + { + if (memcmp(pTS->Addr, Addr, 6) == 0) + { + RemoveTsEntry(ieee, pTS, RX_DIR); + list_del_init(&pTS->List); + list_add_tail(&pTS->List, &ieee->Rx_TS_Unused_List); + } + } +#endif +} + +void RemoveAllTS(struct ieee80211_device* ieee) +{ + PTS_COMMON_INFO pTS, pTmpTS; +#if 1 + list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Pending_List, List) + { + RemoveTsEntry(ieee, pTS, TX_DIR); + list_del_init(&pTS->List); + list_add_tail(&pTS->List, &ieee->Tx_TS_Unused_List); + } + + list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Admit_List, List) + { + RemoveTsEntry(ieee, pTS, TX_DIR); + list_del_init(&pTS->List); + list_add_tail(&pTS->List, &ieee->Tx_TS_Unused_List); + } + + list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Pending_List, List) + { + RemoveTsEntry(ieee, pTS, RX_DIR); + list_del_init(&pTS->List); + list_add_tail(&pTS->List, &ieee->Rx_TS_Unused_List); + } + + list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Admit_List, List) + { + RemoveTsEntry(ieee, pTS, RX_DIR); + list_del_init(&pTS->List); + list_add_tail(&pTS->List, &ieee->Rx_TS_Unused_List); + } +#endif +} + +void TsStartAddBaProcess(struct ieee80211_device* ieee, PTX_TS_RECORD pTxTS) +{ + if(pTxTS->bAddBaReqInProgress == false) + { + pTxTS->bAddBaReqInProgress = true; +#if 1 + if(pTxTS->bAddBaReqDelayed) + { + IEEE80211_DEBUG(IEEE80211_DL_BA, "TsStartAddBaProcess(): Delayed Start ADDBA after 60 sec!!\n"); + mod_timer(&pTxTS->TsAddBaTimer, jiffies + MSECS(TS_ADDBA_DELAY)); + } + else + { + IEEE80211_DEBUG(IEEE80211_DL_BA,"TsStartAddBaProcess(): Immediately Start ADDBA now!!\n"); + mod_timer(&pTxTS->TsAddBaTimer, jiffies+10); //set 10 ticks + } +#endif + } + else + IEEE80211_DEBUG(IEEE80211_DL_ERR, "%s()==>BA timer is already added\n", __FUNCTION__); +} +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +EXPORT_SYMBOL_NOVERS(RemovePeerTS); +#else +EXPORT_SYMBOL(RemovePeerTS); +#endif diff --git a/drivers/staging/rtl8192su/ieee80211/rtl_crypto.h b/drivers/staging/rtl8192su/ieee80211/rtl_crypto.h new file mode 100644 index 000000000000..ccf6ae763572 --- /dev/null +++ b/drivers/staging/rtl8192su/ieee80211/rtl_crypto.h @@ -0,0 +1,399 @@ +/* + * Scatterlist Cryptographic API. + * + * Copyright (c) 2002 James Morris + * Copyright (c) 2002 David S. Miller (davem@redhat.com) + * + * Portions derived from Cryptoapi, by Alexander Kjeldaas + * and Nettle, by Niels Mé°ˆler. + * + * 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 _LINUX_CRYPTO_H +#define _LINUX_CRYPTO_H + +#include +#include +#include +#include +#include +#include +#include + +#define crypto_register_alg crypto_register_alg_rsl +#define crypto_unregister_alg crypto_unregister_alg_rsl +#define crypto_alloc_tfm crypto_alloc_tfm_rsl +#define crypto_free_tfm crypto_free_tfm_rsl +#define crypto_alg_available crypto_alg_available_rsl + +/* + * Algorithm masks and types. + */ +#define CRYPTO_ALG_TYPE_MASK 0x000000ff +#define CRYPTO_ALG_TYPE_CIPHER 0x00000001 +#define CRYPTO_ALG_TYPE_DIGEST 0x00000002 +#define CRYPTO_ALG_TYPE_COMPRESS 0x00000004 + +/* + * Transform masks and values (for crt_flags). + */ +#define CRYPTO_TFM_MODE_MASK 0x000000ff +#define CRYPTO_TFM_REQ_MASK 0x000fff00 +#define CRYPTO_TFM_RES_MASK 0xfff00000 + +#define CRYPTO_TFM_MODE_ECB 0x00000001 +#define CRYPTO_TFM_MODE_CBC 0x00000002 +#define CRYPTO_TFM_MODE_CFB 0x00000004 +#define CRYPTO_TFM_MODE_CTR 0x00000008 + +#define CRYPTO_TFM_REQ_WEAK_KEY 0x00000100 +#define CRYPTO_TFM_RES_WEAK_KEY 0x00100000 +#define CRYPTO_TFM_RES_BAD_KEY_LEN 0x00200000 +#define CRYPTO_TFM_RES_BAD_KEY_SCHED 0x00400000 +#define CRYPTO_TFM_RES_BAD_BLOCK_LEN 0x00800000 +#define CRYPTO_TFM_RES_BAD_FLAGS 0x01000000 + +/* + * Miscellaneous stuff. + */ +#define CRYPTO_UNSPEC 0 +#define CRYPTO_MAX_ALG_NAME 64 + +struct scatterlist; + +/* + * Algorithms: modular crypto algorithm implementations, managed + * via crypto_register_alg() and crypto_unregister_alg(). + */ +struct cipher_alg { + unsigned int cia_min_keysize; + unsigned int cia_max_keysize; + int (*cia_setkey)(void *ctx, const u8 *key, + unsigned int keylen, u32 *flags); + void (*cia_encrypt)(void *ctx, u8 *dst, const u8 *src); + void (*cia_decrypt)(void *ctx, u8 *dst, const u8 *src); +}; + +struct digest_alg { + unsigned int dia_digestsize; + void (*dia_init)(void *ctx); + void (*dia_update)(void *ctx, const u8 *data, unsigned int len); + void (*dia_final)(void *ctx, u8 *out); + int (*dia_setkey)(void *ctx, const u8 *key, + unsigned int keylen, u32 *flags); +}; + +struct compress_alg { + int (*coa_init)(void *ctx); + void (*coa_exit)(void *ctx); + int (*coa_compress)(void *ctx, const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen); + int (*coa_decompress)(void *ctx, const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen); +}; + +#define cra_cipher cra_u.cipher +#define cra_digest cra_u.digest +#define cra_compress cra_u.compress + +struct crypto_alg { + struct list_head cra_list; + u32 cra_flags; + unsigned int cra_blocksize; + unsigned int cra_ctxsize; + const char cra_name[CRYPTO_MAX_ALG_NAME]; + + union { + struct cipher_alg cipher; + struct digest_alg digest; + struct compress_alg compress; + } cra_u; + + struct module *cra_module; +}; + +/* + * Algorithm registration interface. + */ +int crypto_register_alg(struct crypto_alg *alg); +int crypto_unregister_alg(struct crypto_alg *alg); + +/* + * Algorithm query interface. + */ +int crypto_alg_available(const char *name, u32 flags); + +/* + * Transforms: user-instantiated objects which encapsulate algorithms + * and core processing logic. Managed via crypto_alloc_tfm() and + * crypto_free_tfm(), as well as the various helpers below. + */ +struct crypto_tfm; + +struct cipher_tfm { + void *cit_iv; + unsigned int cit_ivsize; + u32 cit_mode; + int (*cit_setkey)(struct crypto_tfm *tfm, + const u8 *key, unsigned int keylen); + int (*cit_encrypt)(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes); + int (*cit_encrypt_iv)(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes, u8 *iv); + int (*cit_decrypt)(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes); + int (*cit_decrypt_iv)(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes, u8 *iv); + void (*cit_xor_block)(u8 *dst, const u8 *src); +}; + +struct digest_tfm { + void (*dit_init)(struct crypto_tfm *tfm); + void (*dit_update)(struct crypto_tfm *tfm, + struct scatterlist *sg, unsigned int nsg); + void (*dit_final)(struct crypto_tfm *tfm, u8 *out); + void (*dit_digest)(struct crypto_tfm *tfm, struct scatterlist *sg, + unsigned int nsg, u8 *out); + int (*dit_setkey)(struct crypto_tfm *tfm, + const u8 *key, unsigned int keylen); +#ifdef CONFIG_CRYPTO_HMAC + void *dit_hmac_block; +#endif +}; + +struct compress_tfm { + int (*cot_compress)(struct crypto_tfm *tfm, + const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen); + int (*cot_decompress)(struct crypto_tfm *tfm, + const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen); +}; + +#define crt_cipher crt_u.cipher +#define crt_digest crt_u.digest +#define crt_compress crt_u.compress + +struct crypto_tfm { + + u32 crt_flags; + + union { + struct cipher_tfm cipher; + struct digest_tfm digest; + struct compress_tfm compress; + } crt_u; + + struct crypto_alg *__crt_alg; +}; + +/* + * Transform user interface. + */ + +/* + * crypto_alloc_tfm() will first attempt to locate an already loaded algorithm. + * If that fails and the kernel supports dynamically loadable modules, it + * will then attempt to load a module of the same name or alias. A refcount + * is grabbed on the algorithm which is then associated with the new transform. + * + * crypto_free_tfm() frees up the transform and any associated resources, + * then drops the refcount on the associated algorithm. + */ +struct crypto_tfm *crypto_alloc_tfm(const char *alg_name, u32 tfm_flags); +void crypto_free_tfm(struct crypto_tfm *tfm); + +/* + * Transform helpers which query the underlying algorithm. + */ +static inline const char *crypto_tfm_alg_name(struct crypto_tfm *tfm) +{ + return tfm->__crt_alg->cra_name; +} + +static inline const char *crypto_tfm_alg_modname(struct crypto_tfm *tfm) +{ + struct crypto_alg *alg = tfm->__crt_alg; + + if (alg->cra_module) + return alg->cra_module->name; + else + return NULL; +} + +static inline u32 crypto_tfm_alg_type(struct crypto_tfm *tfm) +{ + return tfm->__crt_alg->cra_flags & CRYPTO_ALG_TYPE_MASK; +} + +static inline unsigned int crypto_tfm_alg_min_keysize(struct crypto_tfm *tfm) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); + return tfm->__crt_alg->cra_cipher.cia_min_keysize; +} + +static inline unsigned int crypto_tfm_alg_max_keysize(struct crypto_tfm *tfm) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); + return tfm->__crt_alg->cra_cipher.cia_max_keysize; +} + +static inline unsigned int crypto_tfm_alg_ivsize(struct crypto_tfm *tfm) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); + return tfm->crt_cipher.cit_ivsize; +} + +static inline unsigned int crypto_tfm_alg_blocksize(struct crypto_tfm *tfm) +{ + return tfm->__crt_alg->cra_blocksize; +} + +static inline unsigned int crypto_tfm_alg_digestsize(struct crypto_tfm *tfm) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST); + return tfm->__crt_alg->cra_digest.dia_digestsize; +} + +/* + * API wrappers. + */ +static inline void crypto_digest_init(struct crypto_tfm *tfm) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST); + tfm->crt_digest.dit_init(tfm); +} + +static inline void crypto_digest_update(struct crypto_tfm *tfm, + struct scatterlist *sg, + unsigned int nsg) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST); + tfm->crt_digest.dit_update(tfm, sg, nsg); +} + +static inline void crypto_digest_final(struct crypto_tfm *tfm, u8 *out) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST); + tfm->crt_digest.dit_final(tfm, out); +} + +static inline void crypto_digest_digest(struct crypto_tfm *tfm, + struct scatterlist *sg, + unsigned int nsg, u8 *out) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST); + tfm->crt_digest.dit_digest(tfm, sg, nsg, out); +} + +static inline int crypto_digest_setkey(struct crypto_tfm *tfm, + const u8 *key, unsigned int keylen) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST); + if (tfm->crt_digest.dit_setkey == NULL) + return -ENOSYS; + return tfm->crt_digest.dit_setkey(tfm, key, keylen); +} + +static inline int crypto_cipher_setkey(struct crypto_tfm *tfm, + const u8 *key, unsigned int keylen) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); + return tfm->crt_cipher.cit_setkey(tfm, key, keylen); +} + +static inline int crypto_cipher_encrypt(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); + return tfm->crt_cipher.cit_encrypt(tfm, dst, src, nbytes); +} + +static inline int crypto_cipher_encrypt_iv(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes, u8 *iv) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); + BUG_ON(tfm->crt_cipher.cit_mode == CRYPTO_TFM_MODE_ECB); + return tfm->crt_cipher.cit_encrypt_iv(tfm, dst, src, nbytes, iv); +} + +static inline int crypto_cipher_decrypt(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); + return tfm->crt_cipher.cit_decrypt(tfm, dst, src, nbytes); +} + +static inline int crypto_cipher_decrypt_iv(struct crypto_tfm *tfm, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes, u8 *iv) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); + BUG_ON(tfm->crt_cipher.cit_mode == CRYPTO_TFM_MODE_ECB); + return tfm->crt_cipher.cit_decrypt_iv(tfm, dst, src, nbytes, iv); +} + +static inline void crypto_cipher_set_iv(struct crypto_tfm *tfm, + const u8 *src, unsigned int len) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); + memcpy(tfm->crt_cipher.cit_iv, src, len); +} + +static inline void crypto_cipher_get_iv(struct crypto_tfm *tfm, + u8 *dst, unsigned int len) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); + memcpy(dst, tfm->crt_cipher.cit_iv, len); +} + +static inline int crypto_comp_compress(struct crypto_tfm *tfm, + const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_COMPRESS); + return tfm->crt_compress.cot_compress(tfm, src, slen, dst, dlen); +} + +static inline int crypto_comp_decompress(struct crypto_tfm *tfm, + const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen) +{ + BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_COMPRESS); + return tfm->crt_compress.cot_decompress(tfm, src, slen, dst, dlen); +} + +/* + * HMAC support. + */ +#ifdef CONFIG_CRYPTO_HMAC +void crypto_hmac_init(struct crypto_tfm *tfm, u8 *key, unsigned int *keylen); +void crypto_hmac_update(struct crypto_tfm *tfm, + struct scatterlist *sg, unsigned int nsg); +void crypto_hmac_final(struct crypto_tfm *tfm, u8 *key, + unsigned int *keylen, u8 *out); +void crypto_hmac(struct crypto_tfm *tfm, u8 *key, unsigned int *keylen, + struct scatterlist *sg, unsigned int nsg, u8 *out); +#endif /* CONFIG_CRYPTO_HMAC */ + +#endif /* _LINUX_CRYPTO_H */ + diff --git a/drivers/staging/rtl8192su/ieee80211/scatterwalk.c b/drivers/staging/rtl8192su/ieee80211/scatterwalk.c new file mode 100644 index 000000000000..49f401fbce88 --- /dev/null +++ b/drivers/staging/rtl8192su/ieee80211/scatterwalk.c @@ -0,0 +1,126 @@ +/* + * Cryptographic API. + * + * Cipher operations. + * + * Copyright (c) 2002 James Morris + * 2002 Adam J. Richter + * 2004 Jean-Luc Cooke + * + * 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 "kmap_types.h" + +#include +#include +#include +#include +#include +#include "internal.h" +#include "scatterwalk.h" + +enum km_type crypto_km_types[] = { + KM_USER0, + KM_USER1, + KM_SOFTIRQ0, + KM_SOFTIRQ1, +}; + +void *scatterwalk_whichbuf(struct scatter_walk *walk, unsigned int nbytes, void *scratch) +{ + if (nbytes <= walk->len_this_page && + (((unsigned long)walk->data) & (PAGE_CACHE_SIZE - 1)) + nbytes <= + PAGE_CACHE_SIZE) + return walk->data; + else + return scratch; +} + +static void memcpy_dir(void *buf, void *sgdata, size_t nbytes, int out) +{ + if (out) + memcpy(sgdata, buf, nbytes); + else + memcpy(buf, sgdata, nbytes); +} + +void scatterwalk_start(struct scatter_walk *walk, struct scatterlist *sg) +{ + unsigned int rest_of_page; + + walk->sg = sg; + + walk->page = sg->page; + walk->len_this_segment = sg->length; + + rest_of_page = PAGE_CACHE_SIZE - (sg->offset & (PAGE_CACHE_SIZE - 1)); + walk->len_this_page = min(sg->length, rest_of_page); + walk->offset = sg->offset; +} + +void scatterwalk_map(struct scatter_walk *walk, int out) +{ + walk->data = crypto_kmap(walk->page, out) + walk->offset; +} + +static void scatterwalk_pagedone(struct scatter_walk *walk, int out, + unsigned int more) +{ + /* walk->data may be pointing the first byte of the next page; + however, we know we transfered at least one byte. So, + walk->data - 1 will be a virtual address in the mapped page. */ + + if (out) + flush_dcache_page(walk->page); + + if (more) { + walk->len_this_segment -= walk->len_this_page; + + if (walk->len_this_segment) { + walk->page++; + walk->len_this_page = min(walk->len_this_segment, + (unsigned)PAGE_CACHE_SIZE); + walk->offset = 0; + } + else + scatterwalk_start(walk, sg_next(walk->sg)); + } +} + +void scatterwalk_done(struct scatter_walk *walk, int out, int more) +{ + crypto_kunmap(walk->data, out); + if (walk->len_this_page == 0 || !more) + scatterwalk_pagedone(walk, out, more); +} + +/* + * Do not call this unless the total length of all of the fragments + * has been verified as multiple of the block size. + */ +int scatterwalk_copychunks(void *buf, struct scatter_walk *walk, + size_t nbytes, int out) +{ + if (buf != walk->data) { + while (nbytes > walk->len_this_page) { + memcpy_dir(buf, walk->data, walk->len_this_page, out); + buf += walk->len_this_page; + nbytes -= walk->len_this_page; + + crypto_kunmap(walk->data, out); + scatterwalk_pagedone(walk, out, 1); + scatterwalk_map(walk, out); + } + + memcpy_dir(buf, walk->data, nbytes, out); + } + + walk->offset += nbytes; + walk->len_this_page -= nbytes; + walk->len_this_segment -= nbytes; + return 0; +} diff --git a/drivers/staging/rtl8192su/ieee80211/scatterwalk.h b/drivers/staging/rtl8192su/ieee80211/scatterwalk.h new file mode 100644 index 000000000000..b16446519017 --- /dev/null +++ b/drivers/staging/rtl8192su/ieee80211/scatterwalk.h @@ -0,0 +1,51 @@ +/* + * Cryptographic API. + * + * Copyright (c) 2002 James Morris + * Copyright (c) 2002 Adam J. Richter + * Copyright (c) 2004 Jean-Luc Cooke + * + * 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 _CRYPTO_SCATTERWALK_H +#define _CRYPTO_SCATTERWALK_H +#include +#include + +struct scatter_walk { + struct scatterlist *sg; + struct page *page; + void *data; + unsigned int len_this_page; + unsigned int len_this_segment; + unsigned int offset; +}; + +/* Define sg_next is an inline routine now in case we want to change + scatterlist to a linked list later. */ +static inline struct scatterlist *sg_next(struct scatterlist *sg) +{ + return sg + 1; +} + +static inline int scatterwalk_samebuf(struct scatter_walk *walk_in, + struct scatter_walk *walk_out, + void *src_p, void *dst_p) +{ + return walk_in->page == walk_out->page && + walk_in->offset == walk_out->offset && + walk_in->data == src_p && walk_out->data == dst_p; +} + +void *scatterwalk_whichbuf(struct scatter_walk *walk, unsigned int nbytes, void *scratch); +void scatterwalk_start(struct scatter_walk *walk, struct scatterlist *sg); +int scatterwalk_copychunks(void *buf, struct scatter_walk *walk, size_t nbytes, int out); +void scatterwalk_map(struct scatter_walk *walk, int out); +void scatterwalk_done(struct scatter_walk *walk, int out, int more); + +#endif /* _CRYPTO_SCATTERWALK_H */ diff --git a/drivers/staging/rtl8192su/ieee80211_crypt.h b/drivers/staging/rtl8192su/ieee80211_crypt.h new file mode 100644 index 000000000000..b58a3bcc0dc0 --- /dev/null +++ b/drivers/staging/rtl8192su/ieee80211_crypt.h @@ -0,0 +1,86 @@ +/* + * Original code based on Host AP (software wireless LAN access point) driver + * for Intersil Prism2/2.5/3. + * + * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen + * + * Copyright (c) 2002-2003, Jouni Malinen + * + * Adaption to a generic IEEE 802.11 stack by James Ketrenos + * + * + * Copyright (c) 2004, Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. See README and COPYING for + * more details. + */ + +/* + * This file defines the interface to the ieee80211 crypto module. + */ +#ifndef IEEE80211_CRYPT_H +#define IEEE80211_CRYPT_H + +#include + +struct ieee80211_crypto_ops { + const char *name; + + /* init new crypto context (e.g., allocate private data space, + * select IV, etc.); returns NULL on failure or pointer to allocated + * private data on success */ + void * (*init)(int keyidx); + + /* deinitialize crypto context and free allocated private data */ + void (*deinit)(void *priv); + + /* encrypt/decrypt return < 0 on error or >= 0 on success. The return + * value from decrypt_mpdu is passed as the keyidx value for + * decrypt_msdu. skb must have enough head and tail room for the + * encryption; if not, error will be returned; these functions are + * called for all MPDUs (i.e., fragments). + */ + int (*encrypt_mpdu)(struct sk_buff *skb, int hdr_len, void *priv); + int (*decrypt_mpdu)(struct sk_buff *skb, int hdr_len, void *priv); + + /* These functions are called for full MSDUs, i.e. full frames. + * These can be NULL if full MSDU operations are not needed. */ + int (*encrypt_msdu)(struct sk_buff *skb, int hdr_len, void *priv); + int (*decrypt_msdu)(struct sk_buff *skb, int keyidx, int hdr_len, + void *priv); + + int (*set_key)(void *key, int len, u8 *seq, void *priv); + int (*get_key)(void *key, int len, u8 *seq, void *priv); + + /* procfs handler for printing out key information and possible + * statistics */ + char * (*print_stats)(char *p, void *priv); + + /* maximum number of bytes added by encryption; encrypt buf is + * allocated with extra_prefix_len bytes, copy of in_buf, and + * extra_postfix_len; encrypt need not use all this space, but + * the result must start at the beginning of the buffer and correct + * length must be returned */ + int extra_prefix_len, extra_postfix_len; + + struct module *owner; +}; + +struct ieee80211_crypt_data { + struct list_head list; /* delayed deletion list */ + struct ieee80211_crypto_ops *ops; + void *priv; + atomic_t refcnt; +}; + +int ieee80211_register_crypto_ops(struct ieee80211_crypto_ops *ops); +int ieee80211_unregister_crypto_ops(struct ieee80211_crypto_ops *ops); +struct ieee80211_crypto_ops * ieee80211_get_crypto_ops(const char *name); +void ieee80211_crypt_deinit_entries(struct ieee80211_device *, int); +void ieee80211_crypt_deinit_handler(unsigned long); +void ieee80211_crypt_delayed_deinit(struct ieee80211_device *ieee, + struct ieee80211_crypt_data **crypt); + +#endif diff --git a/drivers/staging/rtl8192su/r8180_93cx6.c b/drivers/staging/rtl8192su/r8180_93cx6.c new file mode 100644 index 000000000000..8878cfeb0fbb --- /dev/null +++ b/drivers/staging/rtl8192su/r8180_93cx6.c @@ -0,0 +1,146 @@ +/* + This files contains card eeprom (93c46 or 93c56) programming routines, + memory is addressed by 16 bits words. + + This is part of rtl8180 OpenSource driver. + Copyright (C) Andrea Merello 2004 + Released under the terms of GPL (General Public Licence) + + Parts of this driver are based on the GPL part of the + official realtek driver. + + Parts of this driver are based on the rtl8180 driver skeleton + from Patric Schenke & Andres Salomon. + + Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver. + + We want to tanks the Authors of those projects and the Ndiswrapper + project Authors. +*/ + +#include "r8180_93cx6.h" + +void eprom_cs(struct net_device *dev, short bit) +{ + if(bit) + write_nic_byte_E(dev, EPROM_CMD, + (1<epromtype==EPROM_93c56){ + addr_str[7]=addr & 1; + addr_str[6]=addr & (1<<1); + addr_str[5]=addr & (1<<2); + addr_str[4]=addr & (1<<3); + addr_str[3]=addr & (1<<4); + addr_str[2]=addr & (1<<5); + addr_str[1]=addr & (1<<6); + addr_str[0]=addr & (1<<7); + addr_len=8; + }else{ + addr_str[5]=addr & 1; + addr_str[4]=addr & (1<<1); + addr_str[3]=addr & (1<<2); + addr_str[2]=addr & (1<<3); + addr_str[1]=addr & (1<<4); + addr_str[0]=addr & (1<<5); + addr_len=6; + } + eprom_cs(dev, 1); + eprom_ck_cycle(dev); + eprom_send_bits_string(dev, read_cmd, 3); + eprom_send_bits_string(dev, addr_str, addr_len); + + //keep chip pin D to low state while reading. + //I'm unsure if it is necessary, but anyway shouldn't hurt + eprom_w(dev, 0); + + for(i=0;i<16;i++){ + //eeprom needs a clk cycle between writing opcode&adr + //and reading data. (eeprom outs a dummy 0) + eprom_ck_cycle(dev); + ret |= (eprom_r(dev)<<(15-i)); + } + + eprom_cs(dev, 0); + eprom_ck_cycle(dev); + + //disable EPROM programming + write_nic_byte_E(dev, EPROM_CMD, + (EPROM_CMD_NORMAL< + Released under the terms of GPL (General Public Licence) + + Parts of this driver are based on the GPL part of the official realtek driver + Parts of this driver are based on the rtl8180 driver skeleton from Patric Schenke & Andres Salomon + Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver + + We want to tanks the Authors of such projects and the Ndiswrapper project Authors. +*/ + +/*This files contains card eeprom (93c46 or 93c56) programming routines*/ +/*memory is addressed by WORDS*/ + +#ifdef RTL8192SU +#include "r8192U.h" +#include "r8192S_hw.h" +#else +#include "r8192U.h" +#include "r8192U_hw.h" +#endif + +#define EPROM_DELAY 10 + +#define EPROM_ANAPARAM_ADDRLWORD 0xd +#define EPROM_ANAPARAM_ADDRHWORD 0xe + +#define EPROM_RFCHIPID 0x6 +#define EPROM_TXPW_BASE 0x05 +#define EPROM_RFCHIPID_RTL8225U 5 +#define EPROM_RF_PARAM 0x4 +#define EPROM_CONFIG2 0xc + +#define EPROM_VERSION 0x1E +#define MAC_ADR 0x7 + +#define CIS 0x18 + +#define EPROM_TXPW0 0x16 +#define EPROM_TXPW2 0x1b +#define EPROM_TXPW1 0x3d + + +u32 eprom_read(struct net_device *dev,u32 addr); //reads a 16 bits word diff --git a/drivers/staging/rtl8192su/r8190_rtl8256.c b/drivers/staging/rtl8192su/r8190_rtl8256.c new file mode 100644 index 000000000000..74ff337b0583 --- /dev/null +++ b/drivers/staging/rtl8192su/r8190_rtl8256.c @@ -0,0 +1,312 @@ +/* + This is part of the rtl8192 driver + released under the GPL (See file COPYING for details). + + This files contains programming code for the rtl8256 + radio frontend. + + *Many* thanks to Realtek Corp. for their great support! + +*/ + +#include "r8192U.h" +#include "r8192U_hw.h" +#include "r819xU_phyreg.h" +#include "r819xU_phy.h" +#include "r8190_rtl8256.h" + +/*-------------------------------------------------------------------------- + * Overview: set RF band width (20M or 40M) + * Input: struct net_device* dev + * WIRELESS_BANDWIDTH_E Bandwidth //20M or 40M + * Output: NONE + * Return: NONE + * Note: 8226 support both 20M and 40 MHz + *---------------------------------------------------------------------------*/ +void PHY_SetRF8256Bandwidth(struct net_device* dev , HT_CHANNEL_WIDTH Bandwidth) //20M or 40M +{ + u8 eRFPath; + struct r8192_priv *priv = ieee80211_priv(dev); + + //for(eRFPath = RF90_PATH_A; eRFPath NumTotalRFPath; eRFPath++) + for(eRFPath = 0; eRFPath card_8192_version == VERSION_819xU_A || priv->card_8192_version == VERSION_819xU_B)// 8256 D-cut, E-cut, xiong: consider it later! + { + rtl8192_phy_SetRFReg(dev, (RF90_RADIO_PATH_E)eRFPath, 0x0b, bMask12Bits, 0x100); //phy para:1ba + rtl8192_phy_SetRFReg(dev, (RF90_RADIO_PATH_E)eRFPath, 0x2c, bMask12Bits, 0x3d7); + rtl8192_phy_SetRFReg(dev, (RF90_RADIO_PATH_E)eRFPath, 0x0e, bMask12Bits, 0x021); + + //cosa add for sd3's request 01/23/2008 + rtl8192_phy_SetRFReg(dev, (RF90_RADIO_PATH_E)eRFPath, 0x14, bMask12Bits, 0x5ab); + } + else + { + RT_TRACE(COMP_ERR, "PHY_SetRF8256Bandwidth(): unknown hardware version\n"); + } + + break; + case HT_CHANNEL_WIDTH_20_40: + if(priv->card_8192_version == VERSION_819xU_A ||priv->card_8192_version == VERSION_819xU_B)// 8256 D-cut, E-cut, xiong: consider it later! + { + rtl8192_phy_SetRFReg(dev, (RF90_RADIO_PATH_E)eRFPath, 0x0b, bMask12Bits, 0x300); //phy para:3ba + rtl8192_phy_SetRFReg(dev, (RF90_RADIO_PATH_E)eRFPath, 0x2c, bMask12Bits, 0x3df); + rtl8192_phy_SetRFReg(dev, (RF90_RADIO_PATH_E)eRFPath, 0x0e, bMask12Bits, 0x0a1); + + //cosa add for sd3's request 01/23/2008 + if(priv->chan == 3 || priv->chan == 9) //I need to set priv->chan whenever current channel changes + rtl8192_phy_SetRFReg(dev, (RF90_RADIO_PATH_E)eRFPath, 0x14, bMask12Bits, 0x59b); + else + rtl8192_phy_SetRFReg(dev, (RF90_RADIO_PATH_E)eRFPath, 0x14, bMask12Bits, 0x5ab); + } + else + { + RT_TRACE(COMP_ERR, "PHY_SetRF8256Bandwidth(): unknown hardware version\n"); + } + + + break; + default: + RT_TRACE(COMP_ERR, "PHY_SetRF8256Bandwidth(): unknown Bandwidth: %#X\n",Bandwidth ); + break; + + } + } + return; +} +/*-------------------------------------------------------------------------- + * Overview: Interface to config 8256 + * Input: struct net_device* dev + * Output: NONE + * Return: NONE + *---------------------------------------------------------------------------*/ +void PHY_RF8256_Config(struct net_device* dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + // Initialize general global value + // + // TODO: Extend RF_PATH_C and RF_PATH_D in the future + priv->NumTotalRFPath = RTL819X_TOTAL_RF_PATH; + // Config BB and RF + phy_RF8256_Config_ParaFile(dev); + + return; +} +/*-------------------------------------------------------------------------- + * Overview: Interface to config 8256 + * Input: struct net_device* dev + * Output: NONE + * Return: NONE + *---------------------------------------------------------------------------*/ +void phy_RF8256_Config_ParaFile(struct net_device* dev) +{ + u32 u4RegValue = 0; + //static s1Byte szRadioAFile[] = RTL819X_PHY_RADIO_A; + //static s1Byte szRadioBFile[] = RTL819X_PHY_RADIO_B; + //static s1Byte szRadioCFile[] = RTL819X_PHY_RADIO_C; + //static s1Byte szRadioDFile[] = RTL819X_PHY_RADIO_D; + u8 eRFPath; + BB_REGISTER_DEFINITION_T *pPhyReg; + struct r8192_priv *priv = ieee80211_priv(dev); + u32 RegOffSetToBeCheck = 0x3; + u32 RegValueToBeCheck = 0x7f1; + u32 RF3_Final_Value = 0; + u8 ConstRetryTimes = 5, RetryTimes = 5; + u8 ret = 0; + //3//----------------------------------------------------------------- + //3// <2> Initialize RF + //3//----------------------------------------------------------------- + for(eRFPath = (RF90_RADIO_PATH_E)RF90_PATH_A; eRFPath NumTotalRFPath; eRFPath++) + { + if (!rtl8192_phy_CheckIsLegalRFPath(dev, eRFPath)) + continue; + + pPhyReg = &priv->PHYRegDef[eRFPath]; + + // Joseph test for shorten RF config + // pHalData->RfReg0Value[eRFPath] = rtl8192_phy_QueryRFReg(dev, (RF90_RADIO_PATH_E)eRFPath, rGlobalCtrl, bMaskDWord); + + /*----Store original RFENV control type----*/ + switch(eRFPath) + { + case RF90_PATH_A: + case RF90_PATH_C: + u4RegValue = rtl8192_QueryBBReg(dev, pPhyReg->rfintfs, bRFSI_RFENV); + break; + case RF90_PATH_B : + case RF90_PATH_D: + u4RegValue = rtl8192_QueryBBReg(dev, pPhyReg->rfintfs, bRFSI_RFENV<<16); + break; + } + + /*----Set RF_ENV enable----*/ + rtl8192_setBBreg(dev, pPhyReg->rfintfe, bRFSI_RFENV<<16, 0x1); + + /*----Set RF_ENV output high----*/ + rtl8192_setBBreg(dev, pPhyReg->rfintfo, bRFSI_RFENV, 0x1); + + /* Set bit number of Address and Data for RF register */ + rtl8192_setBBreg(dev, pPhyReg->rfHSSIPara2, b3WireAddressLength, 0x0); // Set 0 to 4 bits for Z-serial and set 1 to 6 bits for 8258 + rtl8192_setBBreg(dev, pPhyReg->rfHSSIPara2, b3WireDataLength, 0x0); // Set 0 to 12 bits for Z-serial and 8258, and set 1 to 14 bits for ??? + + rtl8192_phy_SetRFReg(dev, (RF90_RADIO_PATH_E) eRFPath, 0x0, bMask12Bits, 0xbf); + + /*----Check RF block (for FPGA platform only)----*/ + // TODO: this function should be removed on ASIC , Emily 2007.2.2 + if (rtl8192_phy_checkBBAndRF(dev, HW90_BLOCK_RF, (RF90_RADIO_PATH_E)eRFPath)) + { + RT_TRACE(COMP_ERR, "PHY_RF8256_Config():Check Radio[%d] Fail!!\n", eRFPath); + goto phy_RF8256_Config_ParaFile_Fail; + } + + RetryTimes = ConstRetryTimes; + RF3_Final_Value = 0; + /*----Initialize RF fom connfiguration file----*/ + switch(eRFPath) + { + case RF90_PATH_A: + while(RF3_Final_Value!=RegValueToBeCheck && RetryTimes!=0) + { + ret = rtl8192_phy_ConfigRFWithHeaderFile(dev,(RF90_RADIO_PATH_E)eRFPath); + RF3_Final_Value = rtl8192_phy_QueryRFReg(dev, (RF90_RADIO_PATH_E)eRFPath, RegOffSetToBeCheck, bMask12Bits); + RT_TRACE(COMP_RF, "RF %d %d register final value: %x\n", eRFPath, RegOffSetToBeCheck, RF3_Final_Value); + RetryTimes--; + } + break; + case RF90_PATH_B: + while(RF3_Final_Value!=RegValueToBeCheck && RetryTimes!=0) + { + ret = rtl8192_phy_ConfigRFWithHeaderFile(dev,(RF90_RADIO_PATH_E)eRFPath); + RF3_Final_Value = rtl8192_phy_QueryRFReg(dev, (RF90_RADIO_PATH_E)eRFPath, RegOffSetToBeCheck, bMask12Bits); + RT_TRACE(COMP_RF, "RF %d %d register final value: %x\n", eRFPath, RegOffSetToBeCheck, RF3_Final_Value); + RetryTimes--; + } + break; + case RF90_PATH_C: + while(RF3_Final_Value!=RegValueToBeCheck && RetryTimes!=0) + { + ret = rtl8192_phy_ConfigRFWithHeaderFile(dev,(RF90_RADIO_PATH_E)eRFPath); + RF3_Final_Value = rtl8192_phy_QueryRFReg(dev, (RF90_RADIO_PATH_E)eRFPath, RegOffSetToBeCheck, bMask12Bits); + RT_TRACE(COMP_RF, "RF %d %d register final value: %x\n", eRFPath, RegOffSetToBeCheck, RF3_Final_Value); + RetryTimes--; + } + break; + case RF90_PATH_D: + while(RF3_Final_Value!=RegValueToBeCheck && RetryTimes!=0) + { + ret = rtl8192_phy_ConfigRFWithHeaderFile(dev,(RF90_RADIO_PATH_E)eRFPath); + RF3_Final_Value = rtl8192_phy_QueryRFReg(dev, (RF90_RADIO_PATH_E)eRFPath, RegOffSetToBeCheck, bMask12Bits); + RT_TRACE(COMP_RF, "RF %d %d register final value: %x\n", eRFPath, RegOffSetToBeCheck, RF3_Final_Value); + RetryTimes--; + } + break; + } + + /*----Restore RFENV control type----*/; + switch(eRFPath) + { + case RF90_PATH_A: + case RF90_PATH_C: + rtl8192_setBBreg(dev, pPhyReg->rfintfs, bRFSI_RFENV, u4RegValue); + break; + case RF90_PATH_B : + case RF90_PATH_D: + rtl8192_setBBreg(dev, pPhyReg->rfintfs, bRFSI_RFENV<<16, u4RegValue); + break; + } + + if(ret){ + RT_TRACE(COMP_ERR, "phy_RF8256_Config_ParaFile():Radio[%d] Fail!!", eRFPath); + goto phy_RF8256_Config_ParaFile_Fail; + } + + } + + RT_TRACE(COMP_PHY, "PHY Initialization Success\n") ; + return ; + +phy_RF8256_Config_ParaFile_Fail: + RT_TRACE(COMP_ERR, "PHY Initialization failed\n") ; + return ; +} + + +void PHY_SetRF8256CCKTxPower(struct net_device* dev, u8 powerlevel) +{ + u32 TxAGC=0; + struct r8192_priv *priv = ieee80211_priv(dev); + //modified by vivi, 20080109 + TxAGC = powerlevel; + + if(priv->bDynamicTxLowPower == TRUE ) //cosa 05/22/2008 for scan + { + if(priv->CustomerID == RT_CID_819x_Netcore) + TxAGC = 0x22; + else + TxAGC += priv->CckPwEnl; + } + + if(TxAGC > 0x24) + TxAGC = 0x24; + rtl8192_setBBreg(dev, rTxAGC_CCK_Mcs32, bTxAGCRateCCK, TxAGC); +} + + +void PHY_SetRF8256OFDMTxPower(struct net_device* dev, u8 powerlevel) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + //Joseph TxPower for 8192 testing + u32 writeVal, powerBase0, powerBase1, writeVal_tmp; + u8 index = 0; + u16 RegOffset[6] = {0xe00, 0xe04, 0xe10, 0xe14, 0xe18, 0xe1c}; + u8 byte0, byte1, byte2, byte3; + + powerBase0 = powerlevel + priv->TxPowerDiff; //OFDM rates + powerBase0 = (powerBase0<<24) | (powerBase0<<16) |(powerBase0<<8) |powerBase0; + powerBase1 = powerlevel; //MCS rates + powerBase1 = (powerBase1<<24) | (powerBase1<<16) |(powerBase1<<8) |powerBase1; + + for(index=0; index<6; index++) + { + writeVal = priv->MCSTxPowerLevelOriginalOffset[index] + ((index<2)?powerBase0:powerBase1); + byte0 = (u8)(writeVal & 0x7f); + byte1 = (u8)((writeVal & 0x7f00)>>8); + byte2 = (u8)((writeVal & 0x7f0000)>>16); + byte3 = (u8)((writeVal & 0x7f000000)>>24); + if(byte0 > 0x24) // Max power index = 0x24 + byte0 = 0x24; + if(byte1 > 0x24) + byte1 = 0x24; + if(byte2 > 0x24) + byte2 = 0x24; + if(byte3 > 0x24) + byte3 = 0x24; + + //for tx power track + if(index == 3) + { + writeVal_tmp = (byte3<<24) | (byte2<<16) |(byte1<<8) |byte0; + priv->Pwr_Track = writeVal_tmp; + } + + if(priv->bDynamicTxHighPower == TRUE) //Add by Jacken 2008/03/06 + { + // Emily, 20080613. Set low tx power for both MCS and legacy OFDM + writeVal = 0x03030303; + } + else + { + writeVal = (byte3<<24) | (byte2<<16) |(byte1<<8) |byte0; + } + rtl8192_setBBreg(dev, RegOffset[index], 0x7f7f7f7f, writeVal); + } + return; + +} + diff --git a/drivers/staging/rtl8192su/r8190_rtl8256.h b/drivers/staging/rtl8192su/r8190_rtl8256.h new file mode 100644 index 000000000000..5c1f650fe824 --- /dev/null +++ b/drivers/staging/rtl8192su/r8190_rtl8256.h @@ -0,0 +1,27 @@ +/* + This is part of the rtl8180-sa2400 driver + released under the GPL (See file COPYING for details). + Copyright (c) 2005 Andrea Merello + + This files contains programming code for the rtl8256 + radio frontend. + + *Many* thanks to Realtek Corp. for their great support! + +*/ + +#ifndef RTL8225H +#define RTL8225H + +#ifdef RTL8190P +#define RTL819X_TOTAL_RF_PATH 4 //for 90P +#else +#define RTL819X_TOTAL_RF_PATH 2 //for 8192U +#endif +extern void PHY_SetRF8256Bandwidth(struct net_device* dev , HT_CHANNEL_WIDTH Bandwidth); +extern void PHY_RF8256_Config(struct net_device* dev); +extern void phy_RF8256_Config_ParaFile(struct net_device* dev); +extern void PHY_SetRF8256CCKTxPower(struct net_device* dev, u8 powerlevel); +extern void PHY_SetRF8256OFDMTxPower(struct net_device* dev, u8 powerlevel); + +#endif diff --git a/drivers/staging/rtl8192su/r8192SU_HWImg.c b/drivers/staging/rtl8192su/r8192SU_HWImg.c new file mode 100644 index 000000000000..cbb65795a302 --- /dev/null +++ b/drivers/staging/rtl8192su/r8192SU_HWImg.c @@ -0,0 +1,4902 @@ +/*Created on 2009/ 1/15, 3:10*/ + +#include "r8192SU_HWImg.h" + +u8 Rtl8192SUFwImgArray[ImgArrayLength] = { +0x92,0x81,0x2b,0x90,0x30,0x00,0x00,0x00,0x08,0x74,0x00,0x00,0x88,0x96,0x00,0x00, +0x30,0x00,0x00,0x00,0x00,0x95,0x00,0x00,0x00,0x00,0x2b,0x00,0x03,0x03,0x23,0x00, +0x92,0x81,0x02,0x01,0x00,0x00,0x12,0x04,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x00,0x01,0x01,0x01,0x00,0x00, +0x00,0x01,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x7f,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x1f,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x25,0xb0,0x1a,0x3c,0x80,0x03,0x5a,0x37,0x00,0x80,0x1b,0x3c,0x80,0x00,0x7b,0x37, +0x00,0x00,0x5b,0xaf,0x25,0xb0,0x1a,0x3c,0x18,0x03,0x5a,0x37,0x00,0x80,0x1b,0x3c, +0x80,0x00,0x7b,0x37,0x00,0x00,0x5b,0xaf,0x00,0x80,0x1a,0x3c,0x10,0x6d,0x5a,0x27, +0x08,0x00,0x40,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x04,0x00,0xa1,0xaf,0x08,0x00,0xa2,0xaf,0x0c,0x00,0xa3,0xaf,0x10,0x00,0xa4,0xaf, +0x14,0x00,0xa5,0xaf,0x18,0x00,0xa6,0xaf,0x1c,0x00,0xa7,0xaf,0x20,0x00,0xa8,0xaf, +0x24,0x00,0xa9,0xaf,0x28,0x00,0xaa,0xaf,0x2c,0x00,0xab,0xaf,0x30,0x00,0xac,0xaf, +0x34,0x00,0xad,0xaf,0x38,0x00,0xae,0xaf,0x3c,0x00,0xaf,0xaf,0x12,0x40,0x00,0x00, +0x10,0x48,0x00,0x00,0x00,0x70,0x0a,0x40,0x40,0x00,0xb0,0xaf,0x44,0x00,0xb1,0xaf, +0x48,0x00,0xb2,0xaf,0x4c,0x00,0xb3,0xaf,0x50,0x00,0xb4,0xaf,0x54,0x00,0xb5,0xaf, +0x58,0x00,0xb6,0xaf,0x5c,0x00,0xb7,0xaf,0x60,0x00,0xb8,0xaf,0x64,0x00,0xb9,0xaf, +0x68,0x00,0xbc,0xaf,0x6c,0x00,0xbd,0xaf,0x70,0x00,0xbe,0xaf,0x74,0x00,0xbf,0xaf, +0x78,0x00,0xa8,0xaf,0x7c,0x00,0xa9,0xaf,0x80,0x00,0xaa,0xaf,0xdf,0x1a,0x00,0x08, +0x21,0x20,0xa0,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x25,0xb0,0x06,0x3c,0x00,0x80,0x02,0x3c,0xe8,0xff,0xbd,0x27,0x18,0x03,0xc3,0x34, +0x00,0x03,0x42,0x24,0x14,0x00,0xbf,0xaf,0x10,0x00,0xb0,0xaf,0x00,0x00,0x62,0xac, +0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40,0x42,0xb0,0x03,0x3c, +0x03,0x00,0x63,0x34,0x00,0x00,0x62,0x90,0x02,0x80,0x0a,0x3c,0x02,0x80,0x10,0x3c, +0xff,0x00,0x42,0x30,0x00,0x46,0x02,0x00,0x10,0x00,0x42,0x30,0x13,0x00,0x40,0x10, +0x03,0x46,0x08,0x00,0xc4,0x7d,0x42,0x8d,0x68,0x15,0x05,0x26,0xd4,0x63,0xa4,0x94, +0x01,0x00,0x47,0x24,0x10,0x00,0x02,0x24,0xb0,0x03,0xc9,0x34,0x00,0x00,0x62,0xa0, +0x07,0x00,0x80,0x10,0x1c,0x03,0xc6,0x34,0xd8,0x63,0xa2,0x8c,0xd4,0x63,0xa0,0xa4, +0xd8,0x63,0xa0,0xac,0x00,0x00,0x04,0x24,0x00,0x00,0xc2,0xac,0x00,0x00,0x20,0xad, +0x01,0x00,0x82,0x24,0xc4,0x7d,0x47,0xad,0xd4,0x63,0xa2,0xa4,0x12,0x00,0x00,0x05, +0x42,0xb0,0x02,0x3c,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x01,0x00,0x21,0x38, +0x00,0x60,0x81,0x40,0x68,0x15,0x04,0x26,0x0c,0x4b,0x83,0x94,0x08,0x4b,0x85,0x94, +0x14,0x00,0xbf,0x8f,0x10,0x00,0xb0,0x8f,0x80,0x00,0x63,0x30,0x41,0xb0,0x02,0x3c, +0x25,0x18,0x65,0x00,0x08,0x00,0x42,0x34,0x18,0x00,0xbd,0x27,0x00,0x00,0x43,0xa4, +0x08,0x00,0xe0,0x03,0x08,0x4b,0x83,0xa4,0x80,0xff,0x03,0x24,0x03,0x00,0x42,0x34, +0x00,0x00,0x43,0xa0,0xc8,0x0e,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x60,0x01,0x40, +0x01,0x00,0x21,0x34,0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,0x68,0x15,0x04,0x26, +0x0c,0x4b,0x83,0x94,0x08,0x4b,0x85,0x94,0x14,0x00,0xbf,0x8f,0x10,0x00,0xb0,0x8f, +0x80,0x00,0x63,0x30,0x41,0xb0,0x02,0x3c,0x25,0x18,0x65,0x00,0x08,0x00,0x42,0x34, +0x18,0x00,0xbd,0x27,0x00,0x00,0x43,0xa4,0x08,0x00,0xe0,0x03,0x08,0x4b,0x83,0xa4, +0xff,0x00,0x84,0x30,0x0b,0x00,0x82,0x2c,0xff,0xff,0xe7,0x30,0x10,0x00,0xa8,0x93, +0x19,0x00,0x40,0x10,0x21,0x18,0x00,0x00,0x02,0x80,0x03,0x3c,0x80,0x10,0x04,0x00, +0xc0,0x91,0x63,0x24,0x21,0x10,0x43,0x00,0x00,0x00,0x44,0x8c,0x00,0x00,0x00,0x00, +0x08,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x43,0xb0,0x02,0x3c,0x78,0x00,0x44,0x34, +0x07,0x00,0xe2,0x30,0x00,0x00,0x85,0xac,0x04,0x00,0x86,0xac,0x04,0x00,0x40,0x18, +0x00,0x00,0x00,0x00,0xf8,0xff,0xe2,0x30,0x08,0x00,0x42,0x24,0xff,0xff,0x47,0x30, +0x21,0x10,0xe8,0x00,0x00,0x80,0x03,0x3c,0x08,0x00,0x82,0xac,0x25,0x10,0x43,0x00, +0x08,0x00,0x82,0xac,0x01,0x00,0x03,0x24,0x08,0x00,0xe0,0x03,0x21,0x10,0x60,0x00, +0x43,0xb0,0x02,0x3c,0x20,0x01,0x00,0x08,0x6c,0x00,0x44,0x34,0x43,0xb0,0x02,0x3c, +0x20,0x01,0x00,0x08,0x60,0x00,0x44,0x34,0x43,0xb0,0x02,0x3c,0x20,0x01,0x00,0x08, +0x54,0x00,0x44,0x34,0x43,0xb0,0x02,0x3c,0x20,0x01,0x00,0x08,0x48,0x00,0x44,0x34, +0x43,0xb0,0x02,0x3c,0x20,0x01,0x00,0x08,0x3c,0x00,0x44,0x34,0x43,0xb0,0x02,0x3c, +0x20,0x01,0x00,0x08,0x30,0x00,0x44,0x34,0x43,0xb0,0x02,0x3c,0x20,0x01,0x00,0x08, +0x24,0x00,0x44,0x34,0x43,0xb0,0x02,0x3c,0x20,0x01,0x00,0x08,0x18,0x00,0x44,0x34, +0x43,0xb0,0x02,0x3c,0x20,0x01,0x00,0x08,0x0c,0x00,0x44,0x34,0x20,0x01,0x00,0x08, +0x43,0xb0,0x04,0x3c,0x01,0x00,0x02,0x24,0x25,0xb0,0x03,0x3c,0x04,0x20,0x82,0x00, +0x18,0x03,0x67,0x34,0x00,0x80,0x02,0x3c,0x43,0xb0,0x03,0x3c,0x34,0x05,0x46,0x24, +0x88,0x00,0x65,0x34,0x21,0x10,0x00,0x00,0x01,0x00,0x42,0x24,0xff,0xff,0x42,0x30, +0x05,0x00,0x43,0x2c,0xfd,0xff,0x60,0x14,0x01,0x00,0x42,0x24,0x00,0x00,0xe6,0xac, +0x00,0x00,0xa2,0x94,0x00,0x00,0x00,0x00,0xff,0xff,0x42,0x30,0x24,0x10,0x44,0x00, +0xf4,0xff,0x40,0x1c,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00, +0x25,0xb0,0x08,0x3c,0x00,0x80,0x02,0x3c,0xc8,0xff,0xbd,0x27,0x18,0x03,0x03,0x35, +0x90,0x05,0x42,0x24,0x00,0x00,0x62,0xac,0x30,0x00,0xb6,0xaf,0x28,0x00,0xb4,0xaf, +0x24,0x00,0xb3,0xaf,0x1c,0x00,0xb1,0xaf,0x34,0x00,0xbf,0xaf,0x2c,0x00,0xb5,0xaf, +0x20,0x00,0xb2,0xaf,0x18,0x00,0xb0,0xaf,0x0c,0x00,0xf2,0x84,0x08,0x00,0xf5,0x8c, +0xff,0x00,0xc6,0x30,0x00,0x01,0x02,0x24,0x23,0x10,0x46,0x00,0xff,0xff,0x51,0x30, +0xd0,0x03,0x08,0x35,0xff,0x00,0x96,0x30,0x00,0x00,0x12,0xad,0x21,0xa0,0xa0,0x00, +0x21,0x30,0xc5,0x00,0x00,0x00,0x15,0xad,0x21,0x20,0xc0,0x02,0x21,0x28,0xa0,0x02, +0x21,0x38,0x20,0x02,0x10,0x01,0x00,0x0c,0x10,0x00,0xa0,0xaf,0x23,0x18,0x51,0x02, +0xff,0xff,0x82,0x32,0x00,0x94,0x03,0x00,0x03,0x94,0x12,0x00,0xa6,0x01,0x00,0x08, +0x02,0x9a,0x02,0x00,0x28,0xb0,0x03,0x3c,0xc0,0x10,0x13,0x00,0x21,0x10,0x43,0x00, +0x00,0x00,0x44,0x90,0x25,0xb0,0x10,0x3c,0x20,0x10,0x02,0x3c,0xff,0x00,0x93,0x30, +0x00,0x22,0x13,0x00,0xff,0xff,0x43,0x32,0x01,0x01,0x45,0x2a,0x21,0xa0,0x82,0x00, +0x21,0xa8,0xb1,0x02,0xd0,0x03,0x02,0x36,0x00,0x01,0x11,0x24,0x0b,0x88,0x65,0x00, +0x21,0x20,0xc0,0x02,0x00,0x00,0x53,0xac,0x4d,0x01,0x00,0x0c,0xb0,0x03,0x10,0x36, +0x21,0x30,0x80,0x02,0x21,0x20,0xc0,0x02,0x21,0x28,0xa0,0x02,0x21,0x38,0x20,0x02, +0x10,0x01,0x00,0x0c,0x10,0x00,0xa0,0xaf,0x23,0x18,0x51,0x02,0x00,0x94,0x03,0x00, +0x03,0x94,0x12,0x00,0x00,0x00,0x12,0xae,0xe2,0xff,0x40,0x1e,0x00,0x00,0x00,0x00, +0x34,0x00,0xbf,0x8f,0x30,0x00,0xb6,0x8f,0x2c,0x00,0xb5,0x8f,0x28,0x00,0xb4,0x8f, +0x24,0x00,0xb3,0x8f,0x20,0x00,0xb2,0x8f,0x1c,0x00,0xb1,0x8f,0x18,0x00,0xb0,0x8f, +0x08,0x00,0xe0,0x03,0x38,0x00,0xbd,0x27,0xc8,0xff,0xbd,0x27,0x02,0x80,0x02,0x3c, +0x25,0xb0,0x04,0x3c,0x20,0x00,0xb2,0xaf,0x68,0x15,0x52,0x24,0x00,0x80,0x02,0x3c, +0x18,0x03,0x83,0x34,0xc8,0x06,0x42,0x24,0x28,0x00,0xb4,0xaf,0x24,0x00,0xb3,0xaf, +0x30,0x00,0xbf,0xaf,0x2c,0x00,0xb5,0xaf,0x1c,0x00,0xb1,0xaf,0x18,0x00,0xb0,0xaf, +0x00,0x00,0x62,0xac,0xb0,0x03,0x93,0x34,0x21,0xa0,0x40,0x02,0x54,0x64,0x42,0x8e, +0xc0,0x64,0x50,0x8e,0x21,0x20,0x00,0x00,0x00,0x00,0x62,0xae,0x58,0x64,0x42,0xae, +0x00,0x00,0x70,0xae,0x4d,0x01,0x00,0x0c,0x00,0x00,0x00,0x00,0xc0,0x64,0x44,0x8e, +0xc4,0x64,0x43,0x8e,0x20,0x00,0x84,0x24,0x3f,0x00,0x62,0x24,0x2b,0x10,0x44,0x00, +0x0a,0x18,0x82,0x00,0xc0,0x64,0x43,0xae,0xc0,0x64,0x85,0x8e,0x00,0x00,0x00,0x00, +0x00,0x00,0x65,0xae,0x02,0x80,0x02,0x3c,0xff,0xff,0x10,0x32,0x25,0x80,0x02,0x02, +0x00,0x00,0x70,0xae,0x0c,0x00,0x02,0x92,0xff,0x00,0x15,0x24,0x21,0x20,0x00,0x00, +0x00,0x00,0x62,0xae,0x0c,0x00,0x11,0x92,0x20,0x10,0x02,0x3c,0x20,0x00,0x07,0x24, +0x00,0x1a,0x11,0x00,0x21,0x18,0x62,0x00,0x05,0x00,0x35,0x12,0x21,0x30,0x60,0x00, +0x08,0x64,0x91,0xa2,0x54,0x64,0x83,0xae,0x10,0x01,0x00,0x0c,0x10,0x00,0xa0,0xaf, +0x04,0x00,0x04,0x8e,0x08,0x00,0x03,0x8e,0xff,0xe0,0x02,0x3c,0xff,0xff,0x42,0x34, +0x1f,0x00,0x84,0x30,0x24,0x18,0x62,0x00,0x00,0x26,0x04,0x00,0xff,0xdf,0x02,0x3c, +0x25,0x18,0x64,0x00,0xff,0xff,0x42,0x34,0x24,0x18,0x62,0x00,0x00,0x40,0x04,0x3c, +0x25,0x18,0x64,0x00,0xc0,0xff,0x02,0x24,0x24,0x18,0x62,0x00,0x08,0x00,0x03,0xae, +0xc9,0x64,0x84,0x92,0x2a,0xb0,0x02,0x3c,0x01,0x00,0x03,0x24,0x01,0x00,0x84,0x24, +0x01,0x00,0x42,0x34,0x00,0x00,0x43,0xa0,0xc4,0xff,0x35,0x16,0xc9,0x64,0x84,0xa2, +0xfc,0x4a,0x82,0x8e,0x41,0xb0,0x03,0x3c,0x30,0x00,0xbf,0x8f,0x00,0x38,0x42,0x34, +0x00,0x00,0x62,0xac,0x2c,0x00,0xb5,0x8f,0xfc,0x4a,0x82,0xae,0x24,0x00,0xb3,0x8f, +0x28,0x00,0xb4,0x8f,0x20,0x00,0xb2,0x8f,0x1c,0x00,0xb1,0x8f,0x18,0x00,0xb0,0x8f, +0x08,0x00,0xe0,0x03,0x38,0x00,0xbd,0x27,0x25,0xb0,0x04,0x3c,0x00,0x80,0x02,0x3c, +0xc8,0xff,0xbd,0x27,0x18,0x03,0x83,0x34,0x38,0x08,0x42,0x24,0x34,0x00,0xbf,0xaf, +0x30,0x00,0xb6,0xaf,0x2c,0x00,0xb5,0xaf,0x28,0x00,0xb4,0xaf,0x24,0x00,0xb3,0xaf, +0x20,0x00,0xb2,0xaf,0x1c,0x00,0xb1,0xaf,0x18,0x00,0xb0,0xaf,0x00,0x00,0x62,0xac, +0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40,0x02,0x80,0x16,0x3c, +0x68,0x15,0xd2,0x26,0xb0,0x03,0x93,0x34,0x2d,0x02,0x00,0x08,0x21,0xa8,0x40,0x02, +0x2a,0xb0,0x02,0x3c,0x08,0x00,0x04,0xae,0x09,0x00,0x42,0x34,0x01,0x00,0x03,0x24, +0x02,0x00,0x04,0x24,0x00,0x00,0x43,0xa0,0x00,0x00,0x44,0xa0,0x42,0x00,0x34,0x12, +0x00,0x00,0x00,0x00,0x6c,0x64,0x42,0x8e,0xd8,0x64,0x50,0x8e,0x01,0x00,0x04,0x24, +0x00,0x00,0x62,0xae,0x70,0x64,0x42,0xae,0x00,0x00,0x70,0xae,0x4d,0x01,0x00,0x0c, +0x00,0x00,0x00,0x00,0xd8,0x64,0x44,0x8e,0xdc,0x64,0x43,0x8e,0x20,0x00,0x84,0x24, +0x3f,0x00,0x62,0x24,0x2b,0x10,0x44,0x00,0x0a,0x18,0x82,0x00,0xd8,0x64,0x43,0xae, +0xd8,0x64,0xa5,0x8e,0x00,0x00,0x00,0x00,0x00,0x00,0x65,0xae,0x02,0x80,0x02,0x3c, +0xff,0xff,0x10,0x32,0x25,0x80,0x02,0x02,0x00,0x00,0x70,0xae,0x0c,0x00,0x02,0x92, +0xff,0x00,0x14,0x24,0x01,0x00,0x04,0x24,0x00,0x00,0x62,0xae,0x0c,0x00,0x11,0x92, +0x20,0x10,0x02,0x3c,0x20,0x00,0x07,0x24,0x00,0x1a,0x11,0x00,0x21,0x18,0x62,0x00, +0x05,0x00,0x34,0x12,0x21,0x30,0x60,0x00,0x6c,0x64,0xa3,0xae,0x10,0x64,0xb1,0xa2, +0x10,0x01,0x00,0x0c,0x10,0x00,0xa0,0xaf,0x04,0x00,0x04,0x8e,0x08,0x00,0x03,0x8e, +0xff,0xe0,0x02,0x3c,0xff,0xff,0x42,0x34,0x1f,0x00,0x84,0x30,0x24,0x18,0x62,0x00, +0x00,0x26,0x04,0x00,0xff,0xdf,0x02,0x3c,0x25,0x18,0x64,0x00,0xff,0xff,0x42,0x34, +0x24,0x18,0x62,0x00,0x00,0x40,0x04,0x3c,0x25,0x18,0x64,0x00,0xc0,0xff,0x05,0x24, +0x82,0x11,0x03,0x00,0x24,0x20,0x65,0x00,0x01,0x00,0x42,0x30,0xc0,0xff,0x40,0x10, +0x04,0x00,0x84,0x34,0x2a,0xb0,0x02,0x3c,0x08,0x00,0x03,0xae,0x09,0x00,0x42,0x34, +0x01,0x00,0x03,0x24,0x02,0x00,0x04,0x24,0x00,0x00,0x43,0xa0,0x00,0x00,0x44,0xa0, +0xc0,0xff,0x34,0x16,0x00,0x00,0x00,0x00,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34, +0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,0x68,0x15,0xc2,0x26,0xfc,0x4a,0x43,0x8c, +0x34,0x00,0xbf,0x8f,0x30,0x00,0xb6,0x8f,0x2c,0x00,0xb5,0x8f,0x28,0x00,0xb4,0x8f, +0x24,0x00,0xb3,0x8f,0x20,0x00,0xb2,0x8f,0x1c,0x00,0xb1,0x8f,0x18,0x00,0xb0,0x8f, +0x00,0x38,0x63,0x34,0x41,0xb0,0x04,0x3c,0x38,0x00,0xbd,0x27,0x00,0x00,0x83,0xac, +0x08,0x00,0xe0,0x03,0xfc,0x4a,0x43,0xac,0x25,0xb0,0x04,0x3c,0x00,0x80,0x02,0x3c, +0xc0,0xff,0xbd,0x27,0x18,0x03,0x83,0x34,0x08,0x0a,0x42,0x24,0x38,0x00,0xbf,0xaf, +0x34,0x00,0xb7,0xaf,0x30,0x00,0xb6,0xaf,0x2c,0x00,0xb5,0xaf,0x28,0x00,0xb4,0xaf, +0x24,0x00,0xb3,0xaf,0x20,0x00,0xb2,0xaf,0x1c,0x00,0xb1,0xaf,0x18,0x00,0xb0,0xaf, +0x00,0x00,0x62,0xac,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40, +0x02,0x80,0x17,0x3c,0x68,0x15,0xf2,0x26,0xb0,0x03,0x93,0x34,0x02,0x80,0x14,0x3c, +0xab,0x02,0x00,0x08,0x21,0xb0,0x40,0x02,0x2a,0xb0,0x03,0x3c,0x08,0x00,0x04,0xae, +0x05,0x00,0x63,0x34,0x01,0x00,0x02,0x24,0x02,0x00,0x04,0x24,0x00,0x00,0x62,0xa0, +0x00,0x00,0x64,0xa0,0xca,0x7d,0x82,0x96,0x00,0x00,0x00,0x00,0x01,0x00,0x42,0x24, +0xca,0x7d,0x82,0xa6,0xca,0x7d,0x83,0x96,0x25,0xb0,0x02,0x3c,0x66,0x03,0x42,0x34, +0x00,0x00,0x43,0xa4,0x4a,0x00,0x35,0x12,0x00,0x00,0x00,0x00,0x60,0x64,0x42,0x8e, +0xcc,0x64,0x50,0x8e,0x01,0x00,0x04,0x24,0x00,0x00,0x62,0xae,0x64,0x64,0x42,0xae, +0x00,0x00,0x70,0xae,0x4d,0x01,0x00,0x0c,0x00,0x00,0x00,0x00,0xcc,0x64,0x44,0x8e, +0xd0,0x64,0x43,0x8e,0x20,0x00,0x84,0x24,0x3f,0x00,0x62,0x24,0x2b,0x10,0x44,0x00, +0x0a,0x18,0x82,0x00,0xcc,0x64,0x43,0xae,0xcc,0x64,0xc5,0x8e,0x00,0x00,0x00,0x00, +0x00,0x00,0x65,0xae,0x02,0x80,0x02,0x3c,0xff,0xff,0x10,0x32,0x25,0x80,0x02,0x02, +0x00,0x00,0x70,0xae,0x0c,0x00,0x02,0x92,0xff,0x00,0x15,0x24,0x01,0x00,0x04,0x24, +0x00,0x00,0x62,0xae,0x0c,0x00,0x11,0x92,0x20,0x10,0x02,0x3c,0x20,0x00,0x07,0x24, +0x00,0x1a,0x11,0x00,0x21,0x18,0x62,0x00,0x05,0x00,0x35,0x12,0x21,0x30,0x60,0x00, +0x60,0x64,0xc3,0xae,0x0c,0x64,0xd1,0xa2,0x10,0x01,0x00,0x0c,0x10,0x00,0xa0,0xaf, +0x04,0x00,0x04,0x8e,0x08,0x00,0x03,0x8e,0xff,0xe0,0x02,0x3c,0xff,0xff,0x42,0x34, +0x1f,0x00,0x84,0x30,0x24,0x18,0x62,0x00,0x00,0x26,0x04,0x00,0xff,0xdf,0x02,0x3c, +0x25,0x18,0x64,0x00,0xff,0xff,0x42,0x34,0x24,0x18,0x62,0x00,0x00,0x40,0x04,0x3c, +0x25,0x18,0x64,0x00,0xc0,0xff,0x05,0x24,0x82,0x11,0x03,0x00,0x24,0x20,0x65,0x00, +0x01,0x00,0x42,0x30,0xb8,0xff,0x40,0x10,0x04,0x00,0x84,0x34,0x08,0x00,0x03,0xae, +0x2a,0xb0,0x03,0x3c,0x05,0x00,0x63,0x34,0x01,0x00,0x02,0x24,0x02,0x00,0x04,0x24, +0x00,0x00,0x62,0xa0,0x00,0x00,0x64,0xa0,0xca,0x7d,0x82,0x96,0x00,0x00,0x00,0x00, +0x01,0x00,0x42,0x24,0xca,0x7d,0x82,0xa6,0xca,0x7d,0x83,0x96,0x25,0xb0,0x02,0x3c, +0x66,0x03,0x42,0x34,0x00,0x00,0x43,0xa4,0xb8,0xff,0x35,0x16,0x00,0x00,0x00,0x00, +0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40, +0x68,0x15,0xe2,0x26,0xfc,0x4a,0x43,0x8c,0x38,0x00,0xbf,0x8f,0x34,0x00,0xb7,0x8f, +0x30,0x00,0xb6,0x8f,0x2c,0x00,0xb5,0x8f,0x28,0x00,0xb4,0x8f,0x24,0x00,0xb3,0x8f, +0x20,0x00,0xb2,0x8f,0x1c,0x00,0xb1,0x8f,0x18,0x00,0xb0,0x8f,0x00,0x38,0x63,0x34, +0x41,0xb0,0x04,0x3c,0x40,0x00,0xbd,0x27,0x00,0x00,0x83,0xac,0x08,0x00,0xe0,0x03, +0xfc,0x4a,0x43,0xac,0xc0,0xff,0xbd,0x27,0x2c,0x00,0xb5,0xaf,0x38,0x00,0xbf,0xaf, +0x34,0x00,0xb7,0xaf,0x30,0x00,0xb6,0xaf,0x28,0x00,0xb4,0xaf,0x24,0x00,0xb3,0xaf, +0x20,0x00,0xb2,0xaf,0x1c,0x00,0xb1,0xaf,0x18,0x00,0xb0,0xaf,0x02,0x80,0x06,0x3c, +0x7c,0x7e,0xc5,0x90,0x00,0x80,0x03,0x3c,0x25,0xb0,0x02,0x3c,0x18,0x03,0x42,0x34, +0x24,0x0c,0x63,0x24,0x40,0x00,0xa4,0x30,0x00,0x00,0x43,0xac,0x21,0xa8,0x00,0x00, +0x03,0x00,0x80,0x10,0x7f,0x00,0xa2,0x30,0xbf,0x00,0xa2,0x30,0x01,0x00,0x15,0x24, +0x7c,0x7e,0xc2,0xa0,0x7c,0x7e,0xc2,0x90,0x25,0xb0,0x04,0x3c,0x88,0x02,0x83,0x34, +0x00,0x00,0x62,0xac,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40, +0x02,0x80,0x16,0x3c,0x68,0x15,0xd2,0x26,0xb0,0x03,0x93,0x34,0x02,0x80,0x14,0x3c, +0x43,0x03,0x00,0x08,0x21,0xb8,0x40,0x02,0x24,0x10,0xa2,0x00,0x04,0x00,0x42,0x34, +0x2a,0xb0,0x07,0x3c,0x08,0x00,0x02,0xae,0x0d,0x00,0xe2,0x34,0x04,0x00,0x43,0x24, +0x0b,0x10,0x75,0x00,0x01,0x00,0x04,0x24,0x02,0x00,0x03,0x24,0x00,0x00,0x44,0xa0, +0x00,0x00,0x43,0xa0,0xca,0x7d,0x84,0x96,0x25,0xb0,0x06,0x3c,0x66,0x03,0xc5,0x34, +0x01,0x00,0x84,0x24,0xca,0x7d,0x84,0xa6,0xca,0x7d,0x82,0x96,0xff,0x00,0x03,0x24, +0x00,0x00,0xa2,0xa4,0x5a,0x00,0x23,0x12,0x00,0x00,0x00,0x00,0x24,0x64,0x42,0x8e, +0x90,0x64,0x50,0x8e,0x03,0x00,0x04,0x24,0x00,0x00,0x62,0xae,0x28,0x64,0x42,0xae, +0x00,0x00,0x70,0xae,0x4d,0x01,0x00,0x0c,0x00,0x00,0x00,0x00,0x90,0x64,0x44,0x8e, +0x94,0x64,0x43,0x8e,0x20,0x00,0x84,0x24,0x3f,0x00,0x62,0x24,0x2b,0x10,0x44,0x00, +0x0a,0x18,0x82,0x00,0x90,0x64,0x43,0xae,0x90,0x64,0xe2,0x8e,0x00,0x00,0x00,0x00, +0x00,0x00,0x62,0xae,0x02,0x80,0x02,0x3c,0xff,0xff,0x10,0x32,0x25,0x80,0x02,0x02, +0x00,0x00,0x70,0xae,0x0c,0x00,0x02,0x92,0x00,0x00,0x00,0x00,0x00,0x00,0x62,0xae, +0x0c,0x00,0x11,0x92,0xff,0x00,0x02,0x24,0x0d,0x00,0x22,0x12,0x00,0x12,0x11,0x00, +0x20,0x10,0x03,0x3c,0x21,0x10,0x43,0x00,0x5a,0x00,0xa0,0x12,0x24,0x64,0xe2,0xae, +0xec,0x63,0xf1,0xa2,0x68,0x15,0xc2,0x26,0x24,0x64,0x46,0x8c,0x90,0x64,0x45,0x8c, +0x03,0x00,0x04,0x24,0x20,0x00,0x07,0x24,0x10,0x01,0x00,0x0c,0x10,0x00,0xa0,0xaf, +0x04,0x00,0x04,0x8e,0x14,0x00,0x03,0x8e,0x08,0x00,0x05,0x8e,0xff,0xe0,0x02,0x3c, +0x1f,0x00,0x84,0x30,0x42,0x1a,0x03,0x00,0xff,0xff,0x42,0x34,0x00,0x26,0x04,0x00, +0x24,0x28,0xa2,0x00,0x3f,0x00,0x63,0x30,0x25,0x28,0xa4,0x00,0x0c,0x00,0x63,0x28, +0x06,0x00,0x60,0x14,0x21,0x20,0xa0,0x00,0x00,0x00,0x02,0x96,0x00,0x00,0x00,0x00, +0xfd,0x0f,0x42,0x28,0x08,0x00,0x40,0x14,0x82,0x11,0x05,0x00,0xff,0xdf,0x02,0x3c, +0xff,0xff,0x42,0x34,0x24,0x28,0x82,0x00,0x00,0x40,0x03,0x3c,0x25,0x20,0xa3,0x00, +0x21,0x28,0x80,0x00,0x82,0x11,0x05,0x00,0x01,0x00,0x42,0x30,0xa6,0xff,0x40,0x10, +0xc0,0xff,0x02,0x24,0x2a,0xb0,0x07,0x3c,0x0d,0x00,0xe2,0x34,0x04,0x00,0x43,0x24, +0x08,0x00,0x04,0xae,0x0b,0x10,0x75,0x00,0x01,0x00,0x04,0x24,0x02,0x00,0x03,0x24, +0x00,0x00,0x44,0xa0,0x00,0x00,0x43,0xa0,0xca,0x7d,0x84,0x96,0x25,0xb0,0x06,0x3c, +0x66,0x03,0xc5,0x34,0x01,0x00,0x84,0x24,0xca,0x7d,0x84,0xa6,0xca,0x7d,0x82,0x96, +0xff,0x00,0x03,0x24,0x00,0x00,0xa2,0xa4,0xa8,0xff,0x23,0x16,0x00,0x00,0x00,0x00, +0x22,0x00,0xa0,0x12,0x68,0x15,0xc2,0x26,0xec,0x63,0x43,0x90,0x41,0x00,0xe4,0x34, +0xb0,0x03,0xc5,0x34,0x00,0x00,0x83,0xa0,0x00,0x00,0xa3,0xac,0x00,0x60,0x01,0x40, +0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34, +0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,0x68,0x15,0xc5,0x26,0xfc,0x4a,0xa4,0x8c, +0x01,0x00,0x02,0x3c,0x38,0x00,0xbf,0x8f,0x34,0x00,0xb7,0x8f,0x30,0x00,0xb6,0x8f, +0x2c,0x00,0xb5,0x8f,0x28,0x00,0xb4,0x8f,0x24,0x00,0xb3,0x8f,0x20,0x00,0xb2,0x8f, +0x1c,0x00,0xb1,0x8f,0x18,0x00,0xb0,0x8f,0x00,0x80,0x42,0x34,0x25,0x20,0x82,0x00, +0x41,0xb0,0x03,0x3c,0x40,0x00,0xbd,0x27,0x00,0x00,0x64,0xac,0x08,0x00,0xe0,0x03, +0xfc,0x4a,0xa4,0xac,0x65,0x03,0x00,0x08,0xe8,0x63,0xf1,0xa2,0xe8,0x63,0x43,0x90, +0x40,0x00,0xe4,0x34,0xb0,0x03,0xc5,0x34,0x00,0x00,0x83,0xa0,0x00,0x00,0xa3,0xac, +0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40,0x00,0x60,0x01,0x40, +0x01,0x00,0x21,0x34,0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,0x68,0x15,0xc5,0x26, +0xfc,0x4a,0xa4,0x8c,0x01,0x00,0x02,0x3c,0x38,0x00,0xbf,0x8f,0x34,0x00,0xb7,0x8f, +0x30,0x00,0xb6,0x8f,0x2c,0x00,0xb5,0x8f,0x28,0x00,0xb4,0x8f,0x24,0x00,0xb3,0x8f, +0x20,0x00,0xb2,0x8f,0x1c,0x00,0xb1,0x8f,0x18,0x00,0xb0,0x8f,0x00,0x80,0x42,0x34, +0x25,0x20,0x82,0x00,0x41,0xb0,0x03,0x3c,0x40,0x00,0xbd,0x27,0x00,0x00,0x64,0xac, +0x08,0x00,0xe0,0x03,0xfc,0x4a,0xa4,0xac,0xc0,0xff,0xbd,0x27,0x2c,0x00,0xb5,0xaf, +0x38,0x00,0xbf,0xaf,0x34,0x00,0xb7,0xaf,0x30,0x00,0xb6,0xaf,0x28,0x00,0xb4,0xaf, +0x24,0x00,0xb3,0xaf,0x20,0x00,0xb2,0xaf,0x1c,0x00,0xb1,0xaf,0x18,0x00,0xb0,0xaf, +0x02,0x80,0x06,0x3c,0x7c,0x7e,0xc5,0x90,0x00,0x80,0x03,0x3c,0x25,0xb0,0x02,0x3c, +0x18,0x03,0x42,0x34,0x78,0x0f,0x63,0x24,0x10,0x00,0xa4,0x30,0x00,0x00,0x43,0xac, +0x21,0xa8,0x00,0x00,0x03,0x00,0x80,0x10,0xdf,0x00,0xa2,0x30,0xef,0x00,0xa2,0x30, +0x01,0x00,0x15,0x24,0x7c,0x7e,0xc2,0xa0,0x7c,0x7e,0xc3,0x90,0x25,0xb0,0x02,0x3c, +0xb0,0x03,0x42,0x34,0x00,0x00,0x43,0xac,0x00,0x00,0x43,0xac,0x00,0x60,0x01,0x40, +0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40,0x02,0x80,0x16,0x3c,0x68,0x15,0xd2,0x26, +0x21,0x98,0x40,0x00,0x02,0x80,0x14,0x3c,0x19,0x04,0x00,0x08,0x21,0xb8,0x40,0x02, +0x24,0x10,0xa2,0x00,0x04,0x00,0x42,0x34,0x2a,0xb0,0x07,0x3c,0x08,0x00,0x02,0xae, +0x15,0x00,0xe2,0x34,0x04,0x00,0x43,0x24,0x0b,0x10,0x75,0x00,0x01,0x00,0x04,0x24, +0x02,0x00,0x03,0x24,0x00,0x00,0x44,0xa0,0x00,0x00,0x43,0xa0,0xca,0x7d,0x84,0x96, +0x25,0xb0,0x06,0x3c,0x66,0x03,0xc5,0x34,0x01,0x00,0x84,0x24,0xca,0x7d,0x84,0xa6, +0xca,0x7d,0x82,0x96,0xff,0x00,0x03,0x24,0x00,0x00,0xa2,0xa4,0x5a,0x00,0x23,0x12, +0x00,0x00,0x00,0x00,0x30,0x64,0x42,0x8e,0x9c,0x64,0x50,0x8e,0x04,0x00,0x04,0x24, +0x00,0x00,0x62,0xae,0x34,0x64,0x42,0xae,0x00,0x00,0x70,0xae,0x4d,0x01,0x00,0x0c, +0x00,0x00,0x00,0x00,0x9c,0x64,0x44,0x8e,0xa0,0x64,0x43,0x8e,0x20,0x00,0x84,0x24, +0x3f,0x00,0x62,0x24,0x2b,0x10,0x44,0x00,0x0a,0x18,0x82,0x00,0x9c,0x64,0x43,0xae, +0x9c,0x64,0xe2,0x8e,0x00,0x00,0x00,0x00,0x00,0x00,0x62,0xae,0x02,0x80,0x02,0x3c, +0xff,0xff,0x10,0x32,0x25,0x80,0x02,0x02,0x00,0x00,0x70,0xae,0x0c,0x00,0x02,0x92, +0x00,0x00,0x00,0x00,0x00,0x00,0x62,0xae,0x0c,0x00,0x11,0x92,0xff,0x00,0x02,0x24, +0x0d,0x00,0x22,0x12,0x00,0x12,0x11,0x00,0x20,0x10,0x03,0x3c,0x21,0x10,0x43,0x00, +0x59,0x00,0xa0,0x12,0x30,0x64,0xe2,0xae,0xf4,0x63,0xf1,0xa2,0x68,0x15,0xc2,0x26, +0x30,0x64,0x46,0x8c,0x9c,0x64,0x45,0x8c,0x04,0x00,0x04,0x24,0x20,0x00,0x07,0x24, +0x10,0x01,0x00,0x0c,0x10,0x00,0xa0,0xaf,0x04,0x00,0x04,0x8e,0x14,0x00,0x03,0x8e, +0x08,0x00,0x05,0x8e,0xff,0xe0,0x02,0x3c,0x1f,0x00,0x84,0x30,0x42,0x1a,0x03,0x00, +0xff,0xff,0x42,0x34,0x00,0x26,0x04,0x00,0x24,0x28,0xa2,0x00,0x3f,0x00,0x63,0x30, +0x25,0x28,0xa4,0x00,0x0c,0x00,0x63,0x28,0x06,0x00,0x60,0x14,0x21,0x20,0xa0,0x00, +0x00,0x00,0x02,0x96,0x00,0x00,0x00,0x00,0xfd,0x0f,0x42,0x28,0x08,0x00,0x40,0x14, +0x82,0x11,0x05,0x00,0xff,0xdf,0x02,0x3c,0xff,0xff,0x42,0x34,0x24,0x28,0x82,0x00, +0x00,0x40,0x03,0x3c,0x25,0x20,0xa3,0x00,0x21,0x28,0x80,0x00,0x82,0x11,0x05,0x00, +0x01,0x00,0x42,0x30,0xa6,0xff,0x40,0x10,0xc0,0xff,0x02,0x24,0x2a,0xb0,0x07,0x3c, +0x15,0x00,0xe2,0x34,0x04,0x00,0x43,0x24,0x08,0x00,0x04,0xae,0x0b,0x10,0x75,0x00, +0x01,0x00,0x04,0x24,0x02,0x00,0x03,0x24,0x00,0x00,0x44,0xa0,0x00,0x00,0x43,0xa0, +0xca,0x7d,0x84,0x96,0x25,0xb0,0x06,0x3c,0x66,0x03,0xc5,0x34,0x01,0x00,0x84,0x24, +0xca,0x7d,0x84,0xa6,0xca,0x7d,0x82,0x96,0xff,0x00,0x03,0x24,0x00,0x00,0xa2,0xa4, +0xa8,0xff,0x23,0x16,0x00,0x00,0x00,0x00,0x21,0x00,0xa0,0x12,0x68,0x15,0xc2,0x26, +0xf4,0x63,0x43,0x90,0x43,0x00,0xe4,0x34,0xb0,0x03,0xc5,0x34,0x00,0x00,0x83,0xa0, +0x00,0x00,0xa3,0xac,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40, +0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40, +0x68,0x15,0xc5,0x26,0xfc,0x4a,0xa2,0x8c,0x38,0x00,0xbf,0x8f,0x34,0x00,0xb7,0x8f, +0x30,0x00,0xb6,0x8f,0x2c,0x00,0xb5,0x8f,0x28,0x00,0xb4,0x8f,0x24,0x00,0xb3,0x8f, +0x20,0x00,0xb2,0x8f,0x1c,0x00,0xb1,0x8f,0x18,0x00,0xb0,0x8f,0x06,0x00,0x03,0x3c, +0x25,0x10,0x43,0x00,0x41,0xb0,0x04,0x3c,0x40,0x00,0xbd,0x27,0x00,0x00,0x82,0xac, +0x08,0x00,0xe0,0x03,0xfc,0x4a,0xa2,0xac,0x3b,0x04,0x00,0x08,0xf0,0x63,0xf1,0xa2, +0xf0,0x63,0x43,0x90,0x42,0x00,0xe4,0x34,0xb0,0x03,0xc5,0x34,0x00,0x00,0x83,0xa0, +0x00,0x00,0xa3,0xac,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40, +0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40, +0x68,0x15,0xc5,0x26,0xfc,0x4a,0xa2,0x8c,0x38,0x00,0xbf,0x8f,0x34,0x00,0xb7,0x8f, +0x30,0x00,0xb6,0x8f,0x2c,0x00,0xb5,0x8f,0x28,0x00,0xb4,0x8f,0x24,0x00,0xb3,0x8f, +0x20,0x00,0xb2,0x8f,0x1c,0x00,0xb1,0x8f,0x18,0x00,0xb0,0x8f,0x06,0x00,0x03,0x3c, +0x25,0x10,0x43,0x00,0x41,0xb0,0x04,0x3c,0x40,0x00,0xbd,0x27,0x00,0x00,0x82,0xac, +0x08,0x00,0xe0,0x03,0xfc,0x4a,0xa2,0xac,0xc0,0xff,0xbd,0x27,0x2c,0x00,0xb5,0xaf, +0x38,0x00,0xbf,0xaf,0x34,0x00,0xb7,0xaf,0x30,0x00,0xb6,0xaf,0x28,0x00,0xb4,0xaf, +0x24,0x00,0xb3,0xaf,0x20,0x00,0xb2,0xaf,0x1c,0x00,0xb1,0xaf,0x18,0x00,0xb0,0xaf, +0x02,0x80,0x06,0x3c,0x7c,0x7e,0xc5,0x90,0x00,0x80,0x03,0x3c,0x25,0xb0,0x02,0x3c, +0x18,0x03,0x42,0x34,0xc8,0x12,0x63,0x24,0x01,0x00,0xa4,0x30,0x00,0x00,0x43,0xac, +0x21,0xa8,0x00,0x00,0x03,0x00,0x80,0x10,0xf7,0x00,0xa2,0x30,0xfe,0x00,0xa2,0x30, +0x01,0x00,0x15,0x24,0x7c,0x7e,0xc2,0xa0,0x7c,0x7e,0xc3,0x90,0x25,0xb0,0x02,0x3c, +0xb0,0x03,0x42,0x34,0x00,0x00,0x43,0xac,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34, +0x00,0x60,0x81,0x40,0x02,0x80,0x16,0x3c,0x68,0x15,0xd2,0x26,0x21,0x98,0x40,0x00, +0x02,0x80,0x14,0x3c,0xf8,0x04,0x00,0x08,0x21,0xb8,0x40,0x02,0x00,0x00,0x02,0x96, +0x00,0x00,0x00,0x00,0xfd,0x0f,0x42,0x28,0x54,0x00,0x40,0x10,0xff,0xdf,0x02,0x3c, +0x00,0x20,0x02,0x3c,0x25,0x28,0xa2,0x00,0x82,0x11,0x05,0x00,0x01,0x00,0x42,0x30, +0x57,0x00,0x40,0x14,0x2a,0xb0,0x07,0x3c,0xc0,0xff,0x02,0x24,0x24,0x10,0xa2,0x00, +0x04,0x00,0x42,0x34,0x2a,0xb0,0x07,0x3c,0x08,0x00,0x02,0xae,0x1d,0x00,0xe2,0x34, +0x04,0x00,0x43,0x24,0x0b,0x10,0x75,0x00,0x01,0x00,0x04,0x24,0x02,0x00,0x03,0x24, +0x00,0x00,0x44,0xa0,0x00,0x00,0x43,0xa0,0xca,0x7d,0x84,0x96,0x25,0xb0,0x06,0x3c, +0x66,0x03,0xc5,0x34,0x01,0x00,0x84,0x24,0xca,0x7d,0x84,0xa6,0xca,0x7d,0x82,0x96, +0xff,0x00,0x03,0x24,0x00,0x00,0xa2,0xa4,0x53,0x00,0x23,0x12,0x00,0x00,0x00,0x00, +0x3c,0x64,0x42,0x8e,0xa8,0x64,0x50,0x8e,0x05,0x00,0x04,0x24,0x00,0x00,0x62,0xae, +0x40,0x64,0x42,0xae,0x00,0x00,0x70,0xae,0x4d,0x01,0x00,0x0c,0x00,0x00,0x00,0x00, +0xa8,0x64,0x44,0x8e,0xac,0x64,0x43,0x8e,0x20,0x00,0x84,0x24,0x3f,0x00,0x62,0x24, +0x2b,0x10,0x44,0x00,0x0a,0x18,0x82,0x00,0xa8,0x64,0x43,0xae,0xa8,0x64,0xe2,0x8e, +0x00,0x00,0x00,0x00,0x00,0x00,0x62,0xae,0x02,0x80,0x02,0x3c,0xff,0xff,0x10,0x32, +0x25,0x80,0x02,0x02,0x00,0x00,0x70,0xae,0x0c,0x00,0x02,0x92,0x00,0x00,0x00,0x00, +0x00,0x00,0x62,0xae,0x0c,0x00,0x11,0x92,0xff,0x00,0x02,0x24,0x0d,0x00,0x22,0x12, +0x00,0x12,0x11,0x00,0x20,0x10,0x03,0x3c,0x21,0x10,0x43,0x00,0x52,0x00,0xa0,0x12, +0x3c,0x64,0xe2,0xae,0x04,0x64,0xf1,0xa2,0x68,0x15,0xc2,0x26,0x3c,0x64,0x46,0x8c, +0xa8,0x64,0x45,0x8c,0x05,0x00,0x04,0x24,0x20,0x00,0x07,0x24,0x10,0x01,0x00,0x0c, +0x10,0x00,0xa0,0xaf,0x14,0x00,0x03,0x8e,0x04,0x00,0x04,0x8e,0x08,0x00,0x05,0x8e, +0x42,0x1a,0x03,0x00,0xff,0xe0,0x02,0x3c,0x1f,0x00,0x84,0x30,0x3f,0x00,0x63,0x30, +0xff,0xff,0x42,0x34,0x24,0x28,0xa2,0x00,0x00,0x26,0x04,0x00,0x0c,0x00,0x63,0x28, +0xaa,0xff,0x60,0x10,0x25,0x28,0xa4,0x00,0xff,0xdf,0x02,0x3c,0xff,0xff,0x42,0x34, +0x24,0x10,0xa2,0x00,0x00,0x40,0x03,0x3c,0x25,0x28,0x43,0x00,0x82,0x11,0x05,0x00, +0x01,0x00,0x42,0x30,0xad,0xff,0x40,0x10,0xc0,0xff,0x02,0x24,0x2a,0xb0,0x07,0x3c, +0x1d,0x00,0xe2,0x34,0x04,0x00,0x43,0x24,0x0b,0x10,0x75,0x00,0x01,0x00,0x04,0x24, +0x02,0x00,0x03,0x24,0x08,0x00,0x05,0xae,0x00,0x00,0x44,0xa0,0x00,0x00,0x43,0xa0, +0xca,0x7d,0x84,0x96,0x25,0xb0,0x06,0x3c,0x66,0x03,0xc5,0x34,0x01,0x00,0x84,0x24, +0xca,0x7d,0x84,0xa6,0xca,0x7d,0x82,0x96,0xff,0x00,0x03,0x24,0x00,0x00,0xa2,0xa4, +0xaf,0xff,0x23,0x16,0x00,0x00,0x00,0x00,0x21,0x00,0xa0,0x12,0x68,0x15,0xc2,0x26, +0x04,0x64,0x43,0x90,0x45,0x00,0xe4,0x34,0xb0,0x03,0xc5,0x34,0x00,0x00,0x83,0xa0, +0x00,0x00,0xa3,0xac,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40, +0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40, +0x68,0x15,0xc5,0x26,0xfc,0x4a,0xa2,0x8c,0x38,0x00,0xbf,0x8f,0x34,0x00,0xb7,0x8f, +0x30,0x00,0xb6,0x8f,0x2c,0x00,0xb5,0x8f,0x28,0x00,0xb4,0x8f,0x24,0x00,0xb3,0x8f, +0x20,0x00,0xb2,0x8f,0x1c,0x00,0xb1,0x8f,0x18,0x00,0xb0,0x8f,0x18,0x00,0x03,0x3c, +0x25,0x10,0x43,0x00,0x41,0xb0,0x04,0x3c,0x40,0x00,0xbd,0x27,0x00,0x00,0x82,0xac, +0x08,0x00,0xe0,0x03,0xfc,0x4a,0xa2,0xac,0x1a,0x05,0x00,0x08,0xf8,0x63,0xf1,0xa2, +0xf8,0x63,0x43,0x90,0x44,0x00,0xe4,0x34,0xb0,0x03,0xc5,0x34,0x00,0x00,0x83,0xa0, +0x00,0x00,0xa3,0xac,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40, +0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40, +0x68,0x15,0xc5,0x26,0xfc,0x4a,0xa2,0x8c,0x38,0x00,0xbf,0x8f,0x34,0x00,0xb7,0x8f, +0x30,0x00,0xb6,0x8f,0x2c,0x00,0xb5,0x8f,0x28,0x00,0xb4,0x8f,0x24,0x00,0xb3,0x8f, +0x20,0x00,0xb2,0x8f,0x1c,0x00,0xb1,0x8f,0x18,0x00,0xb0,0x8f,0x18,0x00,0x03,0x3c, +0x25,0x10,0x43,0x00,0x41,0xb0,0x04,0x3c,0x40,0x00,0xbd,0x27,0x00,0x00,0x82,0xac, +0x08,0x00,0xe0,0x03,0xfc,0x4a,0xa2,0xac,0xc0,0xff,0xbd,0x27,0x2c,0x00,0xb5,0xaf, +0x38,0x00,0xbf,0xaf,0x34,0x00,0xb7,0xaf,0x30,0x00,0xb6,0xaf,0x28,0x00,0xb4,0xaf, +0x24,0x00,0xb3,0xaf,0x20,0x00,0xb2,0xaf,0x1c,0x00,0xb1,0xaf,0x18,0x00,0xb0,0xaf, +0x02,0x80,0x06,0x3c,0x7c,0x7e,0xc5,0x90,0x00,0x80,0x03,0x3c,0x25,0xb0,0x02,0x3c, +0x18,0x03,0x42,0x34,0x28,0x16,0x63,0x24,0x02,0x00,0xa4,0x30,0x00,0x00,0x43,0xac, +0x21,0xa8,0x00,0x00,0x03,0x00,0x80,0x10,0xfb,0x00,0xa2,0x30,0xfd,0x00,0xa2,0x30, +0x01,0x00,0x15,0x24,0x7c,0x7e,0xc2,0xa0,0x7c,0x7e,0xc3,0x90,0x25,0xb0,0x02,0x3c, +0xb0,0x03,0x42,0x34,0x00,0x00,0x43,0xac,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34, +0x00,0x60,0x81,0x40,0x02,0x80,0x16,0x3c,0x68,0x15,0xd2,0x26,0x21,0x98,0x40,0x00, +0x02,0x80,0x14,0x3c,0xd0,0x05,0x00,0x08,0x21,0xb8,0x40,0x02,0x00,0x00,0x02,0x96, +0x00,0x00,0x00,0x00,0xfd,0x0f,0x42,0x28,0x54,0x00,0x40,0x10,0xff,0xdf,0x02,0x3c, +0x00,0x20,0x02,0x3c,0x25,0x28,0xa2,0x00,0x82,0x11,0x05,0x00,0x01,0x00,0x42,0x30, +0x57,0x00,0x40,0x14,0x2a,0xb0,0x07,0x3c,0xc0,0xff,0x02,0x24,0x24,0x10,0xa2,0x00, +0x04,0x00,0x42,0x34,0x2a,0xb0,0x07,0x3c,0x08,0x00,0x02,0xae,0x25,0x00,0xe2,0x34, +0x04,0x00,0x43,0x24,0x0b,0x10,0x75,0x00,0x01,0x00,0x04,0x24,0x02,0x00,0x03,0x24, +0x00,0x00,0x44,0xa0,0x00,0x00,0x43,0xa0,0xca,0x7d,0x84,0x96,0x25,0xb0,0x06,0x3c, +0x66,0x03,0xc5,0x34,0x01,0x00,0x84,0x24,0xca,0x7d,0x84,0xa6,0xca,0x7d,0x82,0x96, +0xff,0x00,0x03,0x24,0x00,0x00,0xa2,0xa4,0x53,0x00,0x23,0x12,0x00,0x00,0x00,0x00, +0x48,0x64,0x42,0x8e,0xb4,0x64,0x50,0x8e,0x06,0x00,0x04,0x24,0x00,0x00,0x62,0xae, +0x4c,0x64,0x42,0xae,0x00,0x00,0x70,0xae,0x4d,0x01,0x00,0x0c,0x00,0x00,0x00,0x00, +0xb4,0x64,0x44,0x8e,0xb8,0x64,0x43,0x8e,0x20,0x00,0x84,0x24,0x3f,0x00,0x62,0x24, +0x2b,0x10,0x44,0x00,0x0a,0x18,0x82,0x00,0xb4,0x64,0x43,0xae,0xb4,0x64,0xe2,0x8e, +0x00,0x00,0x00,0x00,0x00,0x00,0x62,0xae,0x02,0x80,0x02,0x3c,0xff,0xff,0x10,0x32, +0x25,0x80,0x02,0x02,0x00,0x00,0x70,0xae,0x0c,0x00,0x02,0x92,0x00,0x00,0x00,0x00, +0x00,0x00,0x62,0xae,0x0c,0x00,0x11,0x92,0xff,0x00,0x02,0x24,0x0d,0x00,0x22,0x12, +0x00,0x12,0x11,0x00,0x20,0x10,0x03,0x3c,0x21,0x10,0x43,0x00,0x52,0x00,0xa0,0x12, +0x48,0x64,0xe2,0xae,0x00,0x64,0xf1,0xa2,0x68,0x15,0xc2,0x26,0x48,0x64,0x46,0x8c, +0xb4,0x64,0x45,0x8c,0x06,0x00,0x04,0x24,0x20,0x00,0x07,0x24,0x10,0x01,0x00,0x0c, +0x10,0x00,0xa0,0xaf,0x14,0x00,0x03,0x8e,0x04,0x00,0x04,0x8e,0x08,0x00,0x05,0x8e, +0x42,0x1a,0x03,0x00,0xff,0xe0,0x02,0x3c,0x1f,0x00,0x84,0x30,0x3f,0x00,0x63,0x30, +0xff,0xff,0x42,0x34,0x24,0x28,0xa2,0x00,0x00,0x26,0x04,0x00,0x0c,0x00,0x63,0x28, +0xaa,0xff,0x60,0x10,0x25,0x28,0xa4,0x00,0xff,0xdf,0x02,0x3c,0xff,0xff,0x42,0x34, +0x24,0x10,0xa2,0x00,0x00,0x40,0x03,0x3c,0x25,0x28,0x43,0x00,0x82,0x11,0x05,0x00, +0x01,0x00,0x42,0x30,0xad,0xff,0x40,0x10,0xc0,0xff,0x02,0x24,0x2a,0xb0,0x07,0x3c, +0x25,0x00,0xe2,0x34,0x04,0x00,0x43,0x24,0x0b,0x10,0x75,0x00,0x01,0x00,0x04,0x24, +0x02,0x00,0x03,0x24,0x08,0x00,0x05,0xae,0x00,0x00,0x44,0xa0,0x00,0x00,0x43,0xa0, +0xca,0x7d,0x84,0x96,0x25,0xb0,0x06,0x3c,0x66,0x03,0xc5,0x34,0x01,0x00,0x84,0x24, +0xca,0x7d,0x84,0xa6,0xca,0x7d,0x82,0x96,0xff,0x00,0x03,0x24,0x00,0x00,0xa2,0xa4, +0xaf,0xff,0x23,0x16,0x00,0x00,0x00,0x00,0x21,0x00,0xa0,0x12,0x68,0x15,0xc2,0x26, +0x00,0x64,0x43,0x90,0x47,0x00,0xe4,0x34,0xb0,0x03,0xc5,0x34,0x00,0x00,0x83,0xa0, +0x00,0x00,0xa3,0xac,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40, +0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40, +0x68,0x15,0xc5,0x26,0xfc,0x4a,0xa2,0x8c,0x38,0x00,0xbf,0x8f,0x34,0x00,0xb7,0x8f, +0x30,0x00,0xb6,0x8f,0x2c,0x00,0xb5,0x8f,0x28,0x00,0xb4,0x8f,0x24,0x00,0xb3,0x8f, +0x20,0x00,0xb2,0x8f,0x1c,0x00,0xb1,0x8f,0x18,0x00,0xb0,0x8f,0x60,0x00,0x03,0x3c, +0x25,0x10,0x43,0x00,0x41,0xb0,0x04,0x3c,0x40,0x00,0xbd,0x27,0x00,0x00,0x82,0xac, +0x08,0x00,0xe0,0x03,0xfc,0x4a,0xa2,0xac,0xf2,0x05,0x00,0x08,0xfc,0x63,0xf1,0xa2, +0xfc,0x63,0x43,0x90,0x46,0x00,0xe4,0x34,0xb0,0x03,0xc5,0x34,0x00,0x00,0x83,0xa0, +0x00,0x00,0xa3,0xac,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40, +0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40, +0x68,0x15,0xc5,0x26,0xfc,0x4a,0xa2,0x8c,0x38,0x00,0xbf,0x8f,0x34,0x00,0xb7,0x8f, +0x30,0x00,0xb6,0x8f,0x2c,0x00,0xb5,0x8f,0x28,0x00,0xb4,0x8f,0x24,0x00,0xb3,0x8f, +0x20,0x00,0xb2,0x8f,0x1c,0x00,0xb1,0x8f,0x18,0x00,0xb0,0x8f,0x60,0x00,0x03,0x3c, +0x25,0x10,0x43,0x00,0x41,0xb0,0x04,0x3c,0x40,0x00,0xbd,0x27,0x00,0x00,0x82,0xac, +0x08,0x00,0xe0,0x03,0xfc,0x4a,0xa2,0xac,0x00,0x80,0x03,0x3c,0x25,0xb0,0x02,0x3c, +0x88,0x19,0x63,0x24,0x18,0x03,0x42,0x34,0x00,0x00,0x43,0xac,0x00,0x60,0x01,0x40, +0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34, +0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,0x02,0x80,0x05,0x3c,0x68,0x15,0xa5,0x24, +0x04,0x4b,0xa2,0x8c,0xfc,0x4a,0xa4,0x8c,0x00,0x08,0x03,0x3c,0x24,0x10,0x43,0x00, +0x25,0x20,0x82,0x00,0x41,0xb0,0x03,0x3c,0x00,0x00,0x64,0xac,0x08,0x00,0xe0,0x03, +0xfc,0x4a,0xa4,0xac,0x25,0xb0,0x04,0x3c,0x00,0x80,0x02,0x3c,0xc0,0xff,0xbd,0x27, +0x18,0x03,0x83,0x34,0xe4,0x19,0x42,0x24,0x3c,0x00,0xbf,0xaf,0x38,0x00,0xbe,0xaf, +0x34,0x00,0xb7,0xaf,0x30,0x00,0xb6,0xaf,0x2c,0x00,0xb5,0xaf,0x28,0x00,0xb4,0xaf, +0x24,0x00,0xb3,0xaf,0x20,0x00,0xb2,0xaf,0x1c,0x00,0xb1,0xaf,0x18,0x00,0xb0,0xaf, +0x00,0x00,0x62,0xac,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40, +0x02,0x80,0x02,0x3c,0x2a,0xb0,0x03,0x3c,0x68,0x15,0x51,0x24,0xb0,0x03,0x93,0x34, +0x2c,0x00,0x77,0x34,0x02,0x80,0x15,0x3c,0x02,0x80,0x16,0x3c,0x9c,0x06,0x00,0x08, +0x02,0x80,0x1e,0x3c,0x14,0x64,0x26,0x92,0xe4,0x64,0x25,0x8e,0x00,0x32,0x06,0x00, +0x21,0x30,0xc2,0x00,0x78,0x64,0x26,0xae,0x10,0x01,0x00,0x0c,0x10,0x00,0xa0,0xaf, +0xe4,0x64,0x30,0x8e,0x0a,0x00,0x04,0x24,0x21,0x90,0x00,0x00,0x00,0x00,0x70,0xae, +0x4d,0x01,0x00,0x0c,0xff,0xff,0x10,0x32,0x02,0x80,0x02,0x3c,0x25,0x80,0x02,0x02, +0x0c,0x00,0x05,0x92,0x02,0x00,0x04,0x92,0xff,0x00,0x02,0x24,0xff,0x00,0xa3,0x30, +0x04,0x00,0x62,0x10,0x21,0x80,0x04,0x02,0x00,0x00,0x63,0xae,0x01,0x00,0x12,0x24, +0x14,0x64,0x25,0xa2,0x88,0x96,0xb0,0xae,0x21,0x28,0x00,0x02,0x02,0x00,0xa2,0x90, +0x08,0x00,0x10,0x26,0x21,0x20,0x00,0x02,0xff,0x00,0x42,0x30,0x00,0x00,0x62,0xae, +0x03,0x00,0xa3,0x90,0x00,0x00,0x00,0x00,0x7f,0x00,0x63,0x30,0x00,0x00,0x63,0xae, +0x00,0x00,0x72,0xae,0x03,0x00,0xa2,0x90,0x84,0x96,0xc3,0x92,0x02,0x00,0xa2,0x90, +0x00,0x00,0x00,0x00,0xff,0x00,0x42,0x30,0x2c,0x00,0x42,0x28,0x11,0x00,0x40,0x10, +0x08,0x00,0x02,0x24,0x03,0x00,0xa2,0x90,0x00,0x00,0x00,0x00,0x7f,0x00,0x42,0x30, +0x84,0x96,0xc2,0xa2,0x02,0x00,0xa3,0x90,0x02,0x80,0x02,0x3c,0x74,0x84,0x42,0x24, +0xff,0x00,0x63,0x30,0xc0,0x18,0x03,0x00,0x21,0x18,0x62,0x00,0x04,0x00,0x62,0x8c, +0x00,0x00,0x00,0x00,0x09,0xf8,0x40,0x00,0x80,0x96,0xc2,0xaf,0x21,0xa0,0x40,0x00, +0x08,0x00,0x02,0x24,0x0a,0x00,0x04,0x24,0x05,0x00,0x82,0x12,0x00,0x01,0x07,0x24, +0x01,0x00,0x02,0x24,0x02,0x00,0x03,0x24,0x01,0x00,0xe2,0xa2,0x01,0x00,0xe3,0xa2, +0xbc,0xff,0x40,0x16,0x20,0x10,0x02,0x3c,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34, +0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,0xfc,0x4a,0x22,0x8e,0x00,0x04,0x03,0x3c, +0x41,0xb0,0x04,0x3c,0x25,0x10,0x43,0x00,0x00,0x00,0x82,0xac,0x3c,0x00,0xbf,0x8f, +0xfc,0x4a,0x22,0xae,0x38,0x00,0xbe,0x8f,0x34,0x00,0xb7,0x8f,0x30,0x00,0xb6,0x8f, +0x2c,0x00,0xb5,0x8f,0x28,0x00,0xb4,0x8f,0x24,0x00,0xb3,0x8f,0x20,0x00,0xb2,0x8f, +0x1c,0x00,0xb1,0x8f,0x18,0x00,0xb0,0x8f,0x08,0x00,0xe0,0x03,0x40,0x00,0xbd,0x27, +0xc8,0xff,0xbd,0x27,0xff,0xff,0xa8,0x30,0x02,0x80,0x02,0x3c,0x25,0x40,0x02,0x01, +0x30,0x00,0xb6,0xaf,0x20,0x00,0xb2,0xaf,0x34,0x00,0xbf,0xaf,0x2c,0x00,0xb5,0xaf, +0x28,0x00,0xb4,0xaf,0x24,0x00,0xb3,0xaf,0x1c,0x00,0xb1,0xaf,0x18,0x00,0xb0,0xaf, +0x00,0x00,0x03,0x8d,0xff,0xff,0xd2,0x30,0x21,0xb0,0xa0,0x00,0x00,0xc0,0x02,0x24, +0x08,0x00,0x45,0x26,0x04,0x00,0x06,0x8d,0x24,0x18,0x62,0x00,0xff,0x3f,0xa5,0x30, +0xf0,0xff,0x02,0x3c,0x25,0x18,0x65,0x00,0xff,0xff,0x42,0x34,0x24,0x18,0x62,0x00, +0x00,0x80,0x05,0x3c,0x25,0x18,0x65,0x00,0xff,0x01,0xc6,0x34,0x00,0x00,0x03,0xad, +0x04,0x00,0x06,0xad,0x21,0x48,0x80,0x00,0xff,0xff,0xe7,0x30,0x18,0x00,0x12,0xa5, +0x1a,0x00,0x07,0xa1,0x18,0x00,0x03,0x8d,0xff,0x7f,0x02,0x3c,0xff,0xff,0x42,0x34, +0x24,0x18,0x62,0x00,0x02,0x80,0x15,0x3c,0x18,0x00,0x03,0xad,0x68,0x15,0xa5,0x26, +0xd6,0x63,0xa3,0x90,0x00,0x00,0x00,0x00,0x01,0x00,0x62,0x24,0xd6,0x63,0xa2,0xa0, +0x18,0x00,0x04,0x8d,0xff,0x80,0x02,0x3c,0x20,0x00,0x45,0x26,0xff,0xff,0x42,0x34, +0x7f,0x00,0x63,0x30,0xff,0xff,0xb2,0x30,0x24,0x20,0x82,0x00,0x00,0x1e,0x03,0x00, +0x25,0xb0,0x02,0x3c,0xc0,0x00,0x42,0x34,0x25,0x20,0x83,0x00,0x07,0x00,0x45,0x32, +0x18,0x00,0x04,0xad,0x00,0x00,0x52,0xa4,0x03,0x00,0xa0,0x10,0xff,0xff,0x42,0x32, +0x08,0x00,0x42,0x26,0xff,0xff,0x42,0x30,0x68,0x15,0xb4,0x26,0x54,0x65,0x86,0x8e, +0x58,0x65,0x90,0x8e,0xf8,0xff,0x52,0x30,0x21,0x10,0xd2,0x00,0x2b,0x10,0x02,0x02, +0x31,0x00,0x40,0x10,0xff,0x00,0x33,0x31,0x23,0x80,0x06,0x02,0x21,0x28,0xc0,0x02, +0xff,0xff,0x07,0x32,0x01,0x00,0x11,0x24,0x21,0x20,0x60,0x02,0x10,0x01,0x00,0x0c, +0x10,0x00,0xb1,0xaf,0x23,0x18,0x50,0x02,0xff,0xff,0x72,0x30,0x22,0x10,0x02,0x3c, +0x21,0x10,0x42,0x02,0x21,0x20,0x60,0x02,0x4d,0x01,0x00,0x0c,0x54,0x65,0x82,0xae, +0x21,0x28,0xd0,0x02,0x21,0x38,0x40,0x02,0x21,0x20,0x60,0x02,0x10,0x00,0xb1,0xaf, +0x22,0x10,0x06,0x3c,0x10,0x01,0x00,0x0c,0x68,0x15,0xb1,0x26,0x54,0x65,0x23,0x8e, +0x25,0xb0,0x10,0x3c,0xb0,0x03,0x02,0x36,0x21,0x20,0x60,0x02,0x00,0x00,0x43,0xac, +0x4d,0x01,0x00,0x0c,0x00,0x00,0x00,0x00,0x54,0x65,0x25,0x8e,0xec,0x00,0x02,0x36, +0xbd,0x00,0x04,0x36,0x00,0x00,0x45,0xac,0x00,0x00,0x83,0x90,0xc2,0x00,0x10,0x36, +0x34,0x00,0xbf,0x8f,0x10,0x00,0x63,0x34,0x00,0x00,0x83,0xa0,0x30,0x00,0xb6,0x8f, +0x00,0x00,0x05,0xa6,0x2c,0x00,0xb5,0x8f,0x28,0x00,0xb4,0x8f,0x24,0x00,0xb3,0x8f, +0x20,0x00,0xb2,0x8f,0x1c,0x00,0xb1,0x8f,0x18,0x00,0xb0,0x8f,0x01,0x00,0x02,0x24, +0x08,0x00,0xe0,0x03,0x38,0x00,0xbd,0x27,0x21,0x28,0xc0,0x02,0x21,0x20,0x60,0x02, +0x21,0x38,0x40,0x02,0x01,0x00,0x02,0x24,0x10,0x01,0x00,0x0c,0x10,0x00,0xa2,0xaf, +0x54,0x65,0x83,0x8e,0x68,0x15,0xb1,0x26,0x25,0xb0,0x10,0x3c,0x21,0x18,0x72,0x00, +0x54,0x65,0x83,0xae,0x54,0x65,0x23,0x8e,0xb0,0x03,0x02,0x36,0x21,0x20,0x60,0x02, +0x00,0x00,0x43,0xac,0x4d,0x01,0x00,0x0c,0x00,0x00,0x00,0x00,0x54,0x65,0x25,0x8e, +0xec,0x00,0x02,0x36,0xbd,0x00,0x04,0x36,0x00,0x00,0x45,0xac,0x00,0x00,0x83,0x90, +0xc2,0x00,0x10,0x36,0x34,0x00,0xbf,0x8f,0x10,0x00,0x63,0x34,0x00,0x00,0x83,0xa0, +0x30,0x00,0xb6,0x8f,0x00,0x00,0x05,0xa6,0x2c,0x00,0xb5,0x8f,0x28,0x00,0xb4,0x8f, +0x24,0x00,0xb3,0x8f,0x20,0x00,0xb2,0x8f,0x1c,0x00,0xb1,0x8f,0x18,0x00,0xb0,0x8f, +0x01,0x00,0x02,0x24,0x08,0x00,0xe0,0x03,0x38,0x00,0xbd,0x27,0xe0,0xff,0xbd,0x27, +0x25,0xb0,0x02,0x3c,0x14,0x00,0xb1,0xaf,0x18,0x00,0xbf,0xaf,0x10,0x00,0xb0,0xaf, +0xbf,0x00,0x42,0x34,0x00,0x00,0x43,0x90,0x21,0x28,0x00,0x00,0x08,0x00,0x06,0x24, +0x04,0x00,0x63,0x2c,0x12,0x00,0x60,0x14,0x21,0x88,0x80,0x00,0x00,0x60,0x02,0x40, +0x01,0x00,0x41,0x34,0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,0x02,0x80,0x03,0x3c, +0x00,0x7b,0x63,0x24,0x04,0x00,0x64,0x8c,0x00,0x00,0x23,0xae,0x04,0x00,0x71,0xac, +0x00,0x00,0x91,0xac,0x04,0x00,0x24,0xae,0x00,0x60,0x82,0x40,0x18,0x00,0xbf,0x8f, +0x14,0x00,0xb1,0x8f,0x10,0x00,0xb0,0x8f,0x08,0x00,0xe0,0x03,0x20,0x00,0xbd,0x27, +0x08,0x00,0x82,0x94,0x02,0x80,0x04,0x3c,0x97,0x45,0x00,0x0c,0x25,0x20,0x44,0x00, +0x00,0x60,0x10,0x40,0x01,0x00,0x01,0x36,0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40, +0x08,0x00,0x25,0x8e,0x0c,0x00,0x26,0x96,0x14,0x00,0x27,0x96,0xf0,0x06,0x00,0x0c, +0x09,0x00,0x04,0x24,0x04,0x00,0x23,0x8e,0x00,0x00,0x22,0x8e,0x21,0x20,0x20,0x02, +0x00,0x00,0x62,0xac,0x04,0x00,0x43,0xac,0x00,0x00,0x31,0xae,0xbd,0x4e,0x00,0x0c, +0x04,0x00,0x31,0xae,0x00,0x60,0x90,0x40,0x18,0x00,0xbf,0x8f,0x14,0x00,0xb1,0x8f, +0x10,0x00,0xb0,0x8f,0x08,0x00,0xe0,0x03,0x20,0x00,0xbd,0x27,0x02,0x80,0x02,0x3c, +0x68,0x15,0x47,0x24,0x8c,0x64,0xe3,0x90,0xff,0xff,0xa5,0x30,0x09,0x00,0xa3,0x10, +0x21,0x20,0xc0,0x00,0xfc,0x64,0xe2,0x8c,0x00,0x00,0x00,0x00,0x08,0x00,0xc2,0xac, +0x06,0x65,0xe3,0x94,0x0e,0x00,0x02,0x24,0x14,0x00,0xc2,0xac,0x8b,0x07,0x00,0x08, +0x0c,0x00,0xc3,0xac,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x00,0x80,0x03,0x3c, +0x25,0xb0,0x02,0x3c,0xd0,0xff,0xbd,0x27,0x4c,0x1f,0x63,0x24,0x18,0x03,0x42,0x34, +0x28,0x00,0xbf,0xaf,0x24,0x00,0xb3,0xaf,0x20,0x00,0xb2,0xaf,0x1c,0x00,0xb1,0xaf, +0x18,0x00,0xb0,0xaf,0x00,0x00,0x43,0xac,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34, +0x00,0x60,0x81,0x40,0x2a,0xb0,0x02,0x3c,0x36,0x00,0x42,0x34,0x00,0x00,0x43,0x90, +0x02,0x80,0x13,0x3c,0x68,0x15,0x66,0x26,0xc0,0x18,0x03,0x00,0x5c,0x65,0xc5,0x8c, +0x23,0xb0,0x04,0x3c,0xf0,0x07,0x63,0x30,0xff,0x1f,0x02,0x3c,0x21,0x18,0x64,0x00, +0xff,0xff,0x42,0x34,0x24,0x20,0x62,0x00,0x23,0x88,0x85,0x00,0x2b,0x38,0x85,0x00, +0x00,0x04,0x22,0x26,0x00,0x65,0xc3,0x8c,0x0b,0x88,0x47,0x00,0x01,0x04,0x25,0x2e, +0xfc,0x64,0xc3,0xac,0x60,0x65,0xc4,0xac,0x06,0x65,0xc0,0xa4,0x11,0x00,0xa0,0x14, +0x05,0x65,0xc0,0xa0,0x00,0xfc,0x83,0x24,0x23,0x10,0x02,0x3c,0x0b,0x18,0x87,0x00, +0xff,0x03,0x42,0x34,0x2b,0x10,0x43,0x00,0x33,0x00,0x40,0x14,0x00,0x00,0x00,0x00, +0x23,0x88,0x83,0x00,0x2b,0x10,0x83,0x00,0x5c,0x65,0xc3,0xac,0x03,0x00,0x40,0x10, +0x01,0x04,0x25,0x2e,0x00,0x04,0x31,0x26,0x01,0x04,0x25,0x2e,0x0e,0x00,0xa0,0x10, +0x68,0x15,0x70,0x26,0x68,0x15,0x70,0x26,0x60,0x65,0x03,0x8e,0x5c,0x65,0x04,0x8e, +0x00,0x00,0x00,0x00,0x2b,0x10,0x83,0x00,0x25,0x00,0x40,0x14,0x2b,0x10,0x64,0x00, +0x51,0x00,0x40,0x14,0x25,0xb0,0x02,0x3c,0x80,0x00,0x03,0x24,0xd0,0x03,0x42,0x34, +0x00,0x00,0x43,0xac,0x68,0x15,0x70,0x26,0x5c,0x65,0x03,0x96,0x2a,0xb0,0x02,0x3c, +0x35,0x00,0x42,0x34,0xc2,0x88,0x03,0x00,0x00,0x00,0x51,0xa0,0x8f,0x10,0x00,0x0c, +0x00,0x00,0x00,0x00,0x06,0x65,0x03,0x96,0x25,0xb0,0x02,0x3c,0xb0,0x03,0x42,0x34, +0x00,0x00,0x43,0xac,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x01,0x00,0x21,0x38, +0x00,0x60,0x81,0x40,0xfc,0x4a,0x02,0x8e,0x80,0x00,0x03,0x3c,0x41,0xb0,0x04,0x3c, +0x25,0x10,0x43,0x00,0x00,0x00,0x82,0xac,0x28,0x00,0xbf,0x8f,0xfc,0x4a,0x02,0xae, +0x24,0x00,0xb3,0x8f,0x20,0x00,0xb2,0x8f,0x1c,0x00,0xb1,0x8f,0x18,0x00,0xb0,0x8f, +0x08,0x00,0xe0,0x03,0x30,0x00,0xbd,0x27,0x00,0x08,0x00,0x08,0x00,0xfc,0x63,0x24, +0xfc,0x64,0x05,0x8e,0x21,0x30,0x80,0x00,0xff,0xff,0x27,0x32,0x09,0x00,0x04,0x24, +0x10,0x01,0x00,0x0c,0x10,0x00,0xa0,0xaf,0xfc,0x64,0x03,0x8e,0x06,0x65,0x05,0x96, +0x5c,0x65,0x02,0x8e,0x21,0x18,0x71,0x00,0x21,0x28,0x25,0x02,0x21,0x10,0x51,0x00, +0x09,0x00,0x04,0x24,0x5c,0x65,0x02,0xae,0xfc,0x64,0x03,0xae,0x4d,0x01,0x00,0x0c, +0x06,0x65,0x05,0xa6,0x68,0x15,0x70,0x26,0x5c,0x65,0x03,0x96,0x2a,0xb0,0x02,0x3c, +0x35,0x00,0x42,0x34,0xc2,0x88,0x03,0x00,0x00,0x00,0x51,0xa0,0x8f,0x10,0x00,0x0c, +0x00,0x00,0x00,0x00,0x06,0x65,0x03,0x96,0x25,0xb0,0x02,0x3c,0xb0,0x03,0x42,0x34, +0x00,0x00,0x43,0xac,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x01,0x00,0x21,0x38, +0x00,0x60,0x81,0x40,0xfc,0x4a,0x02,0x8e,0x80,0x00,0x03,0x3c,0x41,0xb0,0x04,0x3c, +0x25,0x10,0x43,0x00,0x00,0x00,0x82,0xac,0x28,0x00,0xbf,0x8f,0xfc,0x4a,0x02,0xae, +0x24,0x00,0xb3,0x8f,0x20,0x00,0xb2,0x8f,0x1c,0x00,0xb1,0x8f,0x18,0x00,0xb0,0x8f, +0x08,0x00,0xe0,0x03,0x30,0x00,0xbd,0x27,0x64,0x65,0x02,0x8e,0xfc,0x64,0x05,0x8e, +0x21,0x30,0x80,0x00,0x23,0x88,0x44,0x00,0xff,0xff,0x27,0x32,0x09,0x00,0x04,0x24, +0x10,0x01,0x00,0x0c,0x10,0x00,0xa0,0xaf,0xfc,0x64,0x03,0x8e,0x06,0x65,0x02,0x96, +0x60,0x65,0x12,0x96,0x21,0x18,0x71,0x00,0x21,0x10,0x22,0x02,0x23,0x10,0x11,0x3c, +0xfc,0x64,0x03,0xae,0x06,0x65,0x02,0xa6,0x06,0x00,0x40,0x16,0x5c,0x65,0x11,0xae, +0x09,0x00,0x04,0x24,0x4d,0x01,0x00,0x0c,0x68,0x15,0x70,0x26,0x46,0x08,0x00,0x08, +0x00,0x00,0x00,0x00,0x4d,0x01,0x00,0x0c,0x09,0x00,0x04,0x24,0xfc,0x64,0x05,0x8e, +0x09,0x00,0x04,0x24,0x23,0x10,0x06,0x3c,0x21,0x38,0x40,0x02,0x10,0x01,0x00,0x0c, +0x10,0x00,0xa0,0xaf,0xfc,0x64,0x03,0x8e,0x06,0x65,0x02,0x96,0x21,0x20,0x51,0x02, +0x21,0x18,0x72,0x00,0x21,0x10,0x42,0x02,0x5c,0x65,0x04,0xae,0x09,0x00,0x04,0x24, +0xfc,0x64,0x03,0xae,0x75,0x08,0x00,0x08,0x06,0x65,0x02,0xa6,0x02,0x80,0x09,0x3c, +0x68,0x15,0x28,0x25,0xdc,0x63,0x06,0x8d,0xff,0xff,0x02,0x34,0x3f,0x00,0xc2,0x10, +0x21,0x38,0x80,0x00,0x2b,0x10,0xc7,0x00,0x30,0x00,0x40,0x10,0x02,0x19,0x06,0x00, +0x21,0x10,0xc7,0x00,0x23,0x10,0x43,0x00,0x10,0x00,0x46,0x24,0xdc,0x63,0x06,0xad, +0x68,0x15,0x26,0x25,0x04,0x40,0xc4,0x8c,0xe0,0x63,0x02,0xad,0xff,0xff,0x02,0x34, +0x2f,0x00,0x82,0x10,0x00,0x00,0x00,0x00,0x2b,0x10,0x87,0x00,0x1f,0x00,0x40,0x10, +0x02,0x19,0x04,0x00,0x21,0x10,0x87,0x00,0x23,0x10,0x43,0x00,0x10,0x00,0x44,0x24, +0x04,0x40,0xc4,0xac,0xe0,0x63,0xc2,0xac,0xc0,0x10,0x05,0x00,0x21,0x10,0x45,0x00, +0x80,0x10,0x02,0x00,0x21,0x10,0x45,0x00,0x68,0x15,0x23,0x25,0x80,0x10,0x02,0x00, +0x21,0x28,0x43,0x00,0x68,0x51,0xa6,0x8c,0x00,0x21,0x07,0x00,0xff,0xff,0xc2,0x38, +0x0a,0x30,0x82,0x00,0x2b,0x18,0xc7,0x00,0x07,0x00,0x60,0x10,0x21,0x10,0xc7,0x00, +0x02,0x19,0x06,0x00,0x23,0x10,0x43,0x00,0x10,0x00,0x46,0x24,0x68,0x51,0xa6,0xac, +0x08,0x00,0xe0,0x03,0x6c,0x51,0xa2,0xac,0x02,0x19,0x06,0x00,0x23,0x10,0x43,0x00, +0x68,0x51,0xa2,0xac,0x08,0x00,0xe0,0x03,0x6c,0x51,0xa2,0xac,0x21,0x10,0x87,0x00, +0x23,0x10,0x43,0x00,0xa5,0x08,0x00,0x08,0x04,0x40,0xc2,0xac,0x21,0x10,0xc7,0x00, +0x68,0x15,0x26,0x25,0x04,0x40,0xc4,0x8c,0x23,0x10,0x43,0x00,0xdc,0x63,0x02,0xad, +0xe0,0x63,0x02,0xad,0xff,0xff,0x02,0x34,0xd4,0xff,0x82,0x14,0x2b,0x10,0x87,0x00, +0x00,0x21,0x07,0x00,0x9e,0x08,0x00,0x08,0x04,0x40,0xc4,0xac,0x00,0x31,0x04,0x00, +0x91,0x08,0x00,0x08,0xdc,0x63,0x06,0xad,0x63,0x00,0x82,0x24,0x77,0x00,0x42,0x2c, +0x00,0x00,0x85,0x28,0x04,0x00,0x40,0x10,0x21,0x18,0x00,0x00,0x64,0x00,0x82,0x24, +0x64,0x00,0x03,0x24,0x0b,0x18,0x45,0x00,0x08,0x00,0xe0,0x03,0x21,0x10,0x60,0x00, +0x0c,0x00,0x82,0x8c,0x00,0x00,0x00,0x00,0x3f,0x00,0x42,0x30,0x04,0x00,0x42,0x28, +0x17,0x00,0x40,0x10,0x25,0xb0,0x02,0x3c,0x24,0x08,0x42,0x34,0x00,0x00,0x43,0x8c, +0x00,0x00,0x00,0x00,0x00,0x02,0x63,0x30,0x16,0x00,0x60,0x14,0x01,0x00,0x02,0x24, +0x05,0x00,0xa3,0x90,0x00,0x00,0x00,0x00,0x82,0x21,0x03,0x00,0x28,0x00,0x82,0x10, +0xf5,0xff,0x02,0x24,0x02,0x00,0x82,0x28,0x39,0x00,0x40,0x14,0x02,0x00,0x02,0x24, +0x2e,0x00,0x82,0x10,0xe9,0xff,0x02,0x24,0x03,0x00,0x02,0x24,0x24,0x00,0x82,0x10, +0x3e,0x00,0x63,0x30,0x05,0x00,0xc4,0x24,0xd2,0x08,0x00,0x08,0x00,0x00,0x00,0x00, +0x04,0x00,0xa4,0x90,0x00,0x00,0x00,0x00,0x42,0x20,0x04,0x00,0xd2,0x08,0x00,0x08, +0x96,0xff,0x84,0x24,0x05,0x00,0xa3,0x90,0x00,0x00,0x00,0x00,0x60,0x00,0x64,0x30, +0x42,0x21,0x04,0x00,0x0e,0x00,0x82,0x10,0x1f,0x00,0x62,0x30,0x02,0x00,0x82,0x28, +0x1d,0x00,0x40,0x14,0x02,0x00,0x02,0x24,0x14,0x00,0x82,0x10,0x1f,0x00,0x62,0x30, +0x03,0x00,0x02,0x24,0xeb,0xff,0x82,0x14,0x1f,0x00,0x62,0x30,0x40,0x10,0x02,0x00, +0xdd,0xff,0x03,0x24,0x23,0x30,0x62,0x00,0xf6,0x08,0x00,0x08,0x05,0x00,0xc4,0x24, +0x40,0x10,0x02,0x00,0xf5,0xff,0x03,0x24,0x0e,0x09,0x00,0x08,0x23,0x30,0x62,0x00, +0x3e,0x00,0x63,0x30,0x23,0x30,0x43,0x00,0xf6,0x08,0x00,0x08,0x05,0x00,0xc4,0x24, +0xdd,0xff,0x02,0x24,0x16,0x09,0x00,0x08,0x23,0x30,0x43,0x00,0x40,0x10,0x02,0x00, +0xe9,0xff,0x03,0x24,0x0e,0x09,0x00,0x08,0x23,0x30,0x62,0x00,0x3e,0x00,0x63,0x30, +0x16,0x09,0x00,0x08,0x23,0x30,0x43,0x00,0xd2,0xff,0x80,0x14,0x1f,0x00,0x62,0x30, +0x40,0x10,0x02,0x00,0xf8,0xff,0x03,0x24,0x0e,0x09,0x00,0x08,0x23,0x30,0x62,0x00, +0xcc,0xff,0x80,0x14,0x3e,0x00,0x63,0x30,0xf8,0xff,0x02,0x24,0x16,0x09,0x00,0x08, +0x23,0x30,0x43,0x00,0xa0,0xff,0xbd,0x27,0x02,0x80,0x02,0x3c,0x4c,0x00,0xb5,0xaf, +0x5c,0x00,0xbf,0xaf,0x58,0x00,0xbe,0xaf,0x54,0x00,0xb7,0xaf,0x50,0x00,0xb6,0xaf, +0x48,0x00,0xb4,0xaf,0x44,0x00,0xb3,0xaf,0x40,0x00,0xb2,0xaf,0x3c,0x00,0xb1,0xaf, +0x38,0x00,0xb0,0xaf,0x68,0x15,0x55,0x24,0x25,0xb0,0x03,0x3c,0x04,0x01,0x62,0x34, +0x00,0x00,0x43,0x8c,0x44,0x65,0xa7,0x8e,0x00,0x00,0x00,0x00,0x33,0x00,0xe3,0x10, +0x48,0x65,0xa3,0xae,0x2b,0x10,0x67,0x00,0xa8,0x00,0x40,0x14,0x2b,0x10,0xe3,0x00, +0xd1,0x00,0x40,0x14,0x02,0x80,0x02,0x3c,0x68,0x15,0x44,0x24,0x18,0x65,0x83,0x94, +0x02,0x80,0x02,0x3c,0x21,0x88,0x00,0x00,0x19,0x00,0x40,0x1a,0x25,0x98,0x62,0x00, +0x21,0xb8,0x80,0x00,0x21,0xb0,0x80,0x00,0x01,0x00,0x14,0x24,0x21,0x20,0x00,0x00, +0x21,0x80,0x93,0x00,0x00,0x00,0x05,0x8e,0x00,0x00,0x00,0x00,0x07,0x00,0xa0,0x10, +0x01,0x00,0x22,0x26,0x04,0x00,0x02,0x8e,0x00,0xf0,0x03,0x3c,0x00,0x20,0x04,0x3c, +0x24,0x10,0x43,0x00,0x1e,0x00,0x44,0x10,0x06,0x00,0x22,0x26,0xff,0xff,0x51,0x30, +0x82,0x16,0x05,0x00,0x01,0x00,0x42,0x30,0x34,0x00,0x54,0x10,0x00,0x00,0x00,0x00, +0x80,0x20,0x11,0x00,0x2a,0x10,0x92,0x00,0xed,0xff,0x40,0x14,0x00,0x00,0x00,0x00, +0xbd,0x4e,0x00,0x0c,0x21,0x20,0xc0,0x03,0x02,0x80,0x02,0x3c,0x08,0x04,0x44,0x24, +0x21,0x28,0x00,0x00,0x21,0x30,0x00,0x00,0x31,0x1c,0x00,0x0c,0x21,0x38,0x00,0x00, +0x25,0xb0,0x03,0x3c,0x04,0x01,0x62,0x34,0x00,0x00,0x43,0x8c,0x44,0x65,0xa7,0x8e, +0x00,0x00,0x00,0x00,0xcf,0xff,0xe3,0x14,0x48,0x65,0xa3,0xae,0x25,0xb0,0x03,0x3c, +0x00,0x01,0x62,0x34,0x00,0x00,0x47,0xac,0x66,0x09,0x00,0x08,0x44,0x65,0xa7,0xae, +0xb0,0x4c,0xe2,0x8e,0x00,0x00,0x00,0x00,0x01,0x00,0x42,0x24,0xb0,0x4c,0xe2,0xae, +0x0c,0x00,0x04,0x8e,0x0c,0x00,0x02,0x24,0x3f,0x00,0x83,0x30,0x64,0x00,0x62,0x10, +0x21,0x28,0xe0,0x02,0x3f,0x00,0x83,0x30,0x0d,0x00,0x02,0x24,0x59,0x00,0x62,0x10, +0x00,0x00,0x00,0x00,0x3f,0x00,0x83,0x30,0x0e,0x00,0x02,0x24,0x04,0x00,0x62,0x10, +0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x8e,0x5b,0x09,0x00,0x08,0x06,0x00,0x22,0x26, +0xbc,0x4c,0xe2,0x8e,0x00,0x00,0x00,0x00,0x01,0x00,0x42,0x24,0xbc,0x4c,0xe2,0xae, +0x00,0x00,0x05,0x8e,0x5b,0x09,0x00,0x08,0x06,0x00,0x22,0x26,0x00,0x40,0xc2,0x8e, +0x00,0x00,0x00,0x00,0x02,0x12,0x02,0x00,0x0f,0x00,0x42,0x30,0x05,0x00,0x54,0x10, +0xc2,0x13,0x05,0x00,0x1e,0x00,0x42,0x30,0x21,0x10,0x51,0x00,0x60,0x09,0x00,0x08, +0xff,0xff,0x51,0x30,0x02,0x40,0xc2,0x92,0x00,0x00,0x00,0x00,0x1e,0x00,0x40,0x14, +0x02,0x80,0x03,0x3c,0x04,0x00,0x03,0x8e,0x00,0x00,0x00,0x00,0x02,0x14,0x03,0x00, +0x0f,0x00,0x42,0x30,0x17,0x00,0x40,0x14,0x02,0x17,0x03,0x00,0x03,0x00,0x44,0x30, +0x08,0x00,0x80,0x10,0x00,0xc0,0x02,0x3c,0x24,0x10,0x62,0x00,0x11,0x00,0x40,0x14, +0x03,0x00,0x02,0x24,0x10,0x00,0x82,0x10,0x02,0x80,0x03,0x3c,0x0f,0x00,0x80,0x10, +0x68,0x15,0x63,0x24,0x80,0x10,0x11,0x00,0x21,0x28,0x53,0x00,0xec,0xff,0xa3,0x8c, +0x25,0xb0,0x02,0x3c,0xd4,0x02,0x42,0x34,0x21,0x20,0x00,0x02,0x00,0x00,0x43,0xac, +0xdc,0x08,0x00,0x0c,0x00,0x00,0x00,0x00,0x21,0x20,0x40,0x00,0x8b,0x08,0x00,0x0c, +0x21,0x28,0x00,0x00,0x02,0x80,0x03,0x3c,0x68,0x15,0x63,0x24,0x02,0x40,0x62,0x90, +0x00,0x00,0x00,0x00,0x85,0x00,0x54,0x10,0x00,0x00,0x00,0x00,0x02,0x80,0x04,0x3c, +0x68,0x15,0x84,0x24,0x02,0x40,0x83,0x90,0x02,0x00,0x02,0x24,0x68,0x00,0x62,0x10, +0x00,0x00,0x00,0x00,0x25,0xb0,0x03,0x3c,0x4c,0x00,0x63,0x34,0x00,0x00,0x62,0x90, +0x00,0x00,0x00,0x00,0x03,0x00,0x42,0x30,0x08,0x00,0x54,0x10,0x02,0x80,0x04,0x3c, +0x00,0x00,0x05,0x8e,0x00,0x00,0x00,0x00,0xc2,0x13,0x05,0x00,0x1e,0x00,0x42,0x30, +0x21,0x10,0x51,0x00,0x60,0x09,0x00,0x08,0xff,0xff,0x51,0x30,0xd0,0x02,0x02,0x24, +0x68,0x15,0x84,0x24,0xdc,0x63,0x82,0xac,0x00,0x00,0x05,0x8e,0xd3,0x09,0x00,0x08, +0xc2,0x13,0x05,0x00,0xb8,0x4c,0xa2,0x8c,0x00,0x00,0x00,0x00,0x01,0x00,0x42,0x24, +0xb8,0x4c,0xa2,0xac,0x0c,0x00,0x04,0x8e,0x86,0x09,0x00,0x08,0x3f,0x00,0x83,0x30, +0xb4,0x4c,0xe2,0x8e,0x00,0x00,0x00,0x00,0x01,0x00,0x42,0x24,0xb4,0x4c,0xe2,0xae, +0x0c,0x00,0x04,0x8e,0x82,0x09,0x00,0x08,0x3f,0x00,0x83,0x30,0x4c,0x65,0xa2,0x8e, +0xff,0xff,0x71,0x30,0x23,0x10,0x47,0x00,0xff,0xff,0x50,0x30,0x21,0x18,0x11,0x02, +0xff,0xff,0x72,0x30,0xa1,0x4e,0x00,0x0c,0x21,0x20,0x40,0x02,0x76,0x00,0x40,0x10, +0x21,0xf0,0x40,0x00,0x08,0x00,0x42,0x8c,0x44,0x65,0xa6,0x8e,0x21,0x38,0x00,0x02, +0x21,0x18,0x52,0x00,0x21,0x28,0x40,0x00,0x08,0x00,0x04,0x24,0x14,0x65,0xa3,0xae, +0x18,0x65,0xa2,0xae,0x10,0x01,0x00,0x0c,0x10,0x00,0xa0,0xaf,0x4d,0x01,0x00,0x0c, +0x08,0x00,0x04,0x24,0x18,0x65,0xa5,0x8e,0x25,0xb0,0x03,0x3c,0x24,0x10,0x02,0x3c, +0x21,0x28,0xb0,0x00,0x00,0x01,0x70,0x34,0x00,0x00,0x02,0xae,0x21,0x38,0x20,0x02, +0x08,0x00,0x04,0x24,0x24,0x10,0x06,0x3c,0x44,0x65,0xa2,0xae,0x10,0x01,0x00,0x0c, +0x10,0x00,0xa0,0xaf,0x48,0x65,0xa3,0x8e,0x08,0x00,0x04,0x24,0x4d,0x01,0x00,0x0c, +0x44,0x65,0xa3,0xae,0x44,0x65,0xa2,0x8e,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0xae, +0x46,0x09,0x00,0x08,0x02,0x80,0x02,0x3c,0x23,0x10,0x67,0x00,0xff,0xff,0x52,0x30, +0xa1,0x4e,0x00,0x0c,0x21,0x20,0x40,0x02,0x56,0x00,0x40,0x10,0x21,0xf0,0x40,0x00, +0x08,0x00,0x42,0x8c,0x44,0x65,0xa6,0x8e,0x08,0x00,0x04,0x24,0x21,0x18,0x52,0x00, +0x21,0x28,0x40,0x00,0x21,0x38,0x40,0x02,0x14,0x65,0xa3,0xae,0x18,0x65,0xa2,0xae, +0x10,0x01,0x00,0x0c,0x10,0x00,0xa0,0xaf,0x48,0x65,0xa3,0x8e,0x08,0x00,0x04,0x24, +0x4d,0x01,0x00,0x0c,0x44,0x65,0xa3,0xae,0x44,0x65,0xa3,0x8e,0x25,0xb0,0x04,0x3c, +0x00,0x01,0x82,0x34,0x00,0x00,0x43,0xac,0x46,0x09,0x00,0x08,0x02,0x80,0x02,0x3c, +0x04,0x00,0x03,0x8e,0x00,0x00,0x00,0x00,0x02,0x14,0x03,0x00,0x0f,0x00,0x42,0x30, +0x08,0x00,0x42,0x28,0x93,0xff,0x40,0x10,0x02,0x17,0x03,0x00,0x03,0x00,0x42,0x30, +0x90,0xff,0x40,0x14,0x80,0x10,0x11,0x00,0x21,0x28,0x53,0x00,0xec,0xff,0xa3,0x8c, +0x25,0xb0,0x02,0x3c,0xd4,0x02,0x42,0x34,0x21,0x20,0x00,0x02,0x00,0x00,0x43,0xac, +0xdc,0x08,0x00,0x0c,0x00,0x00,0x00,0x00,0x21,0x20,0x40,0x00,0x8b,0x08,0x00,0x0c, +0x21,0x28,0x00,0x00,0xca,0x09,0x00,0x08,0x25,0xb0,0x03,0x3c,0x04,0x00,0x03,0x8e, +0x00,0x00,0x00,0x00,0x02,0x14,0x03,0x00,0x0f,0x00,0x42,0x30,0x08,0x00,0x42,0x28, +0x06,0x00,0x40,0x10,0x00,0xc0,0x02,0x3c,0x02,0x17,0x03,0x00,0x03,0x00,0x42,0x30, +0x0c,0x00,0x40,0x10,0x80,0x10,0x11,0x00,0x00,0xc0,0x02,0x3c,0x24,0x10,0x62,0x00, +0x6f,0xff,0x40,0x14,0x02,0x80,0x04,0x3c,0x02,0x17,0x03,0x00,0x03,0x00,0x42,0x30, +0x03,0x00,0x03,0x24,0x6b,0xff,0x43,0x10,0x68,0x15,0x84,0x24,0x67,0xff,0x40,0x10, +0x80,0x10,0x11,0x00,0x21,0x28,0x53,0x00,0xec,0xff,0xa3,0x8c,0x25,0xb0,0x02,0x3c, +0xd4,0x02,0x42,0x34,0x21,0x20,0x00,0x02,0x00,0x00,0x43,0xac,0xdc,0x08,0x00,0x0c, +0x00,0x00,0x00,0x00,0x21,0x20,0x40,0x00,0x8b,0x08,0x00,0x0c,0x21,0x28,0x00,0x00, +0xc4,0x09,0x00,0x08,0x02,0x80,0x04,0x3c,0x25,0xb0,0x04,0x3c,0x44,0x44,0x02,0x3c, +0xbc,0x02,0x83,0x34,0x44,0x44,0x42,0x34,0x00,0x00,0x62,0xac,0x67,0x09,0x00,0x08, +0x02,0x80,0x02,0x3c,0x48,0x65,0xa5,0x8e,0x25,0xb0,0x04,0x3c,0x66,0x66,0x02,0x3c, +0x00,0x01,0x83,0x34,0x66,0x66,0x42,0x34,0xbc,0x02,0x84,0x34,0x00,0x00,0x65,0xac, +0x00,0x00,0x82,0xac,0x66,0x09,0x00,0x08,0x44,0x65,0xa5,0xae,0x00,0x60,0x02,0x40, +0x01,0x00,0x41,0x34,0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,0x02,0x80,0x03,0x3c, +0xd8,0x8c,0x64,0xac,0x00,0x60,0x82,0x40,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00, +0x02,0x80,0x02,0x3c,0xd8,0x8c,0x45,0x8c,0x00,0x80,0x03,0x3c,0x25,0xb0,0x02,0x3c, +0x18,0x03,0x42,0x34,0x10,0x2a,0x63,0x24,0x00,0x00,0x43,0xac,0x04,0x00,0x02,0x24, +0x1e,0x00,0xa2,0x10,0x05,0x00,0xa2,0x2c,0x10,0x00,0x40,0x10,0x05,0x00,0x02,0x24, +0x03,0x00,0x02,0x24,0x08,0x00,0xa2,0x10,0x00,0x19,0x04,0x00,0x80,0x10,0x04,0x00, +0x21,0x10,0x44,0x00,0xc0,0x10,0x02,0x00,0x23,0x10,0x44,0x00,0x00,0x11,0x02,0x00, +0x21,0x10,0x44,0x00,0x40,0x19,0x02,0x00,0xff,0xff,0x63,0x24,0xfe,0xff,0x60,0x14, +0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0xf3,0xff,0xa2,0x10, +0x06,0x00,0x02,0x24,0xf2,0xff,0xa2,0x14,0x80,0x10,0x04,0x00,0x40,0x11,0x04,0x00, +0x23,0x10,0x44,0x00,0x80,0x10,0x02,0x00,0x21,0x10,0x44,0x00,0x00,0x19,0x02,0x00, +0x23,0x18,0x62,0x00,0x9a,0x0a,0x00,0x08,0x00,0x19,0x03,0x00,0x80,0x10,0x04,0x00, +0x21,0x10,0x44,0x00,0xc0,0x10,0x02,0x00,0x23,0x10,0x44,0x00,0x00,0x11,0x02,0x00, +0x21,0x10,0x44,0x00,0x9a,0x0a,0x00,0x08,0x00,0x19,0x02,0x00,0x02,0x80,0x02,0x3c, +0xd8,0x8c,0x45,0x8c,0x00,0x80,0x03,0x3c,0x25,0xb0,0x02,0x3c,0x18,0x03,0x42,0x34, +0xcc,0x2a,0x63,0x24,0x00,0x00,0x43,0xac,0x05,0x00,0x02,0x24,0x10,0x00,0xa2,0x10, +0x06,0x00,0xa2,0x2c,0x09,0x00,0x40,0x14,0x04,0x00,0x02,0x24,0x06,0x00,0x02,0x24, +0x0f,0x00,0xa2,0x10,0x00,0x11,0x04,0x00,0xff,0xff,0x84,0x24,0xfe,0xff,0x80,0x14, +0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0xfa,0xff,0xa2,0x14, +0x80,0x10,0x04,0x00,0x21,0x10,0x44,0x00,0xc2,0x0a,0x00,0x08,0x40,0x20,0x02,0x00, +0x80,0x10,0x04,0x00,0x21,0x10,0x44,0x00,0xc2,0x0a,0x00,0x08,0x80,0x20,0x02,0x00, +0x23,0x10,0x44,0x00,0xc2,0x0a,0x00,0x08,0x40,0x20,0x02,0x00,0xff,0xff,0x85,0x30, +0x21,0x30,0x00,0x00,0x25,0xb0,0x03,0x3c,0x2a,0xb0,0x04,0x3c,0xb4,0x00,0x63,0x34, +0x01,0x00,0xa2,0x24,0x31,0x00,0x84,0x34,0x00,0x00,0x65,0xa0,0x00,0x00,0x85,0xa0, +0xff,0xff,0x45,0x30,0x12,0x00,0xa0,0x10,0x01,0x00,0x03,0x24,0x28,0xb0,0x07,0x3c, +0xe8,0x0a,0x00,0x08,0xff,0xff,0x08,0x24,0x00,0x00,0x83,0xa0,0x01,0x00,0x63,0x24, +0xff,0xff,0x63,0x30,0x2b,0x10,0xa3,0x00,0x09,0x00,0x40,0x14,0x08,0x00,0xc6,0x24, +0xf9,0xff,0x65,0x14,0x21,0x20,0xc7,0x00,0x01,0x00,0x63,0x24,0xff,0xff,0x63,0x30, +0x2b,0x10,0xa3,0x00,0x00,0x00,0x88,0xa0,0xf9,0xff,0x40,0x10,0x08,0x00,0xc6,0x24, +0x00,0x01,0xa2,0x2c,0x13,0x00,0x40,0x10,0x21,0x18,0xa0,0x00,0xff,0x00,0x08,0x24, +0x28,0xb0,0x07,0x3c,0xfc,0x0a,0x00,0x08,0xff,0xff,0x09,0x24,0xff,0xff,0x43,0x30, +0x00,0x00,0xa2,0xa0,0x00,0x01,0x62,0x2c,0x0a,0x00,0x40,0x10,0x08,0x00,0xc6,0x24, +0x01,0x00,0x62,0x24,0xf9,0xff,0x68,0x14,0x21,0x28,0xc7,0x00,0x00,0x01,0x02,0x24, +0xff,0xff,0x43,0x30,0x00,0x01,0x62,0x2c,0x00,0x00,0xa9,0xa0,0xf8,0xff,0x40,0x14, +0x08,0x00,0xc6,0x24,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0xd8,0xff,0xbd,0x27, +0x24,0x00,0xbf,0xaf,0x20,0x00,0xb4,0xaf,0x1c,0x00,0xb3,0xaf,0x18,0x00,0xb2,0xaf, +0x14,0x00,0xb1,0xaf,0x10,0x00,0xb0,0xaf,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34, +0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,0x25,0xb0,0x10,0x3c,0x42,0x00,0x14,0x36, +0xff,0xff,0x02,0x24,0x00,0x00,0x82,0xa2,0xd8,0x00,0x05,0x36,0x40,0x00,0x11,0x36, +0xa8,0x00,0x13,0x36,0xa0,0x00,0x12,0x36,0x00,0x10,0x03,0x24,0xa4,0x00,0x10,0x36, +0x00,0x80,0x02,0x3c,0x00,0x00,0x23,0xa6,0x00,0x00,0xa0,0xa0,0x00,0x00,0x40,0xae, +0x00,0x00,0x00,0xae,0x00,0x00,0x62,0xae,0x00,0x00,0xa3,0x90,0x80,0xff,0x02,0x24, +0xfd,0x00,0x04,0x24,0x25,0x18,0x62,0x00,0xfc,0x17,0x02,0x24,0x00,0x00,0xa3,0xa0, +0x00,0x00,0x22,0xa6,0xd3,0x0a,0x00,0x0c,0x00,0x00,0x00,0x00,0x02,0x80,0x02,0x3c, +0x68,0x15,0x42,0x24,0x68,0x4b,0x45,0x8c,0x60,0x4b,0x43,0x8c,0x64,0x4b,0x44,0x8c, +0xfc,0x37,0x02,0x24,0x00,0x00,0x43,0xae,0x00,0x00,0x04,0xae,0x00,0x00,0x65,0xae, +0x00,0x00,0x22,0xa6,0x00,0x00,0x80,0xa2,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34, +0x00,0x60,0x81,0x40,0x24,0x00,0xbf,0x8f,0x20,0x00,0xb4,0x8f,0x1c,0x00,0xb3,0x8f, +0x18,0x00,0xb2,0x8f,0x14,0x00,0xb1,0x8f,0x10,0x00,0xb0,0x8f,0x08,0x00,0xe0,0x03, +0x28,0x00,0xbd,0x27,0xd0,0xff,0xbd,0x27,0x2c,0x00,0xbf,0xaf,0x28,0x00,0xb6,0xaf, +0x24,0x00,0xb5,0xaf,0x20,0x00,0xb4,0xaf,0x1c,0x00,0xb3,0xaf,0x18,0x00,0xb2,0xaf, +0x14,0x00,0xb1,0xaf,0x10,0x00,0xb0,0xaf,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34, +0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,0x25,0xb0,0x10,0x3c,0x40,0x00,0x05,0x36, +0x00,0x00,0xa2,0x94,0x24,0xfa,0x03,0x24,0xa8,0x00,0x13,0x36,0x24,0x10,0x43,0x00, +0x00,0x00,0xa2,0xa4,0xa0,0x00,0x12,0x36,0xa4,0x00,0x10,0x36,0x00,0x00,0x55,0x8e, +0x00,0x00,0x16,0x8e,0x00,0x00,0x71,0x8e,0x00,0x80,0x14,0x3c,0xfc,0x37,0x02,0x24, +0x00,0x00,0x40,0xae,0xfd,0x00,0x04,0x24,0x00,0x00,0x00,0xae,0x21,0x88,0x34,0x02, +0x00,0x00,0x74,0xae,0x00,0x00,0xa2,0xa4,0xd3,0x0a,0x00,0x0c,0x00,0x00,0x00,0x00, +0x00,0x00,0x55,0xae,0x00,0x00,0x16,0xae,0x00,0x00,0x71,0xae,0x00,0x60,0x01,0x40, +0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40,0x2c,0x00,0xbf,0x8f,0x28,0x00,0xb6,0x8f, +0x24,0x00,0xb5,0x8f,0x20,0x00,0xb4,0x8f,0x1c,0x00,0xb3,0x8f,0x18,0x00,0xb2,0x8f, +0x14,0x00,0xb1,0x8f,0x10,0x00,0xb0,0x8f,0x08,0x00,0xe0,0x03,0x30,0x00,0xbd,0x27, +0xd0,0xff,0xbd,0x27,0x2c,0x00,0xbf,0xaf,0x28,0x00,0xb6,0xaf,0x24,0x00,0xb5,0xaf, +0x20,0x00,0xb4,0xaf,0x1c,0x00,0xb3,0xaf,0x18,0x00,0xb2,0xaf,0x14,0x00,0xb1,0xaf, +0x10,0x00,0xb0,0xaf,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x01,0x00,0x21,0x38, +0x00,0x60,0x81,0x40,0x25,0xb0,0x10,0x3c,0x40,0x00,0x05,0x36,0x00,0x00,0xa2,0x94, +0xaf,0xff,0x03,0x24,0xa8,0x00,0x13,0x36,0x24,0x10,0x43,0x00,0x00,0x00,0xa2,0xa4, +0xa0,0x00,0x12,0x36,0xa4,0x00,0x10,0x36,0x00,0x00,0x55,0x8e,0x00,0x00,0x16,0x8e, +0x00,0x00,0x71,0x8e,0x00,0x80,0x14,0x3c,0xfc,0x37,0x02,0x24,0x00,0x00,0x40,0xae, +0xfd,0x00,0x04,0x24,0x00,0x00,0x00,0xae,0x21,0x88,0x34,0x02,0x00,0x00,0x74,0xae, +0x00,0x00,0xa2,0xa4,0xd3,0x0a,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x55,0xae, +0x00,0x00,0x16,0xae,0x00,0x00,0x71,0xae,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34, +0x00,0x60,0x81,0x40,0x2c,0x00,0xbf,0x8f,0x28,0x00,0xb6,0x8f,0x24,0x00,0xb5,0x8f, +0x20,0x00,0xb4,0x8f,0x1c,0x00,0xb3,0x8f,0x18,0x00,0xb2,0x8f,0x14,0x00,0xb1,0x8f, +0x10,0x00,0xb0,0x8f,0x08,0x00,0xe0,0x03,0x30,0x00,0xbd,0x27,0x00,0x60,0x01,0x40, +0x01,0x00,0x21,0x34,0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,0x25,0xb0,0x04,0x3c, +0x40,0x00,0x84,0x34,0x00,0x00,0x82,0x94,0xd8,0xfd,0x03,0x24,0x24,0x10,0x43,0x00, +0xfc,0x37,0x03,0x24,0x00,0x00,0x82,0xa4,0x00,0x00,0x83,0xa4,0x00,0x60,0x01,0x40, +0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00, +0x00,0x00,0x82,0x8c,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0xff,0xff,0xc6,0x30, +0x10,0x00,0x02,0x24,0x0c,0x00,0xc2,0x10,0x11,0x00,0xc3,0x28,0x06,0x00,0x60,0x10, +0x20,0x00,0x02,0x24,0x08,0x00,0x02,0x24,0x0d,0x00,0xc2,0x10,0x00,0x00,0x00,0x00, +0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x06,0x00,0xc2,0x10,0x00,0x00,0x00,0x00, +0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x85,0xa4,0x08,0x00,0xe0,0x03, +0x00,0x00,0x00,0x00,0x00,0x00,0x85,0xac,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00, +0x00,0x00,0x85,0xa0,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03, +0x21,0x10,0x00,0x00,0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,0x25,0xb0,0x02,0x3c, +0x0a,0x00,0x42,0x34,0x00,0x00,0x43,0x90,0xff,0xff,0xa5,0x24,0x00,0x2c,0x05,0x00, +0xfd,0x00,0x63,0x30,0x03,0x2c,0x05,0x00,0xff,0xff,0x87,0x30,0x00,0x00,0x43,0xa0, +0x1a,0x00,0xa0,0x04,0x00,0x00,0x00,0x00,0x21,0x30,0x40,0x00,0x07,0x10,0xa7,0x00, +0x01,0x00,0x42,0x30,0xfd,0x00,0x64,0x30,0x00,0x00,0x42,0x38,0x02,0x00,0x63,0x34, +0x0a,0x18,0x82,0x00,0x00,0x00,0xc3,0xa0,0x04,0x00,0x63,0x34,0x00,0x00,0xc3,0xa0, +0x09,0x00,0x02,0x24,0xff,0xff,0x42,0x24,0xff,0xff,0x41,0x04,0xff,0xff,0x42,0x24, +0xfb,0x00,0x63,0x30,0x00,0x00,0xc3,0xa0,0x04,0x00,0x02,0x24,0xff,0xff,0x42,0x24, +0xff,0xff,0x41,0x04,0xff,0xff,0x42,0x24,0xff,0xff,0xa2,0x24,0x00,0x2c,0x02,0x00, +0x03,0x2c,0x05,0x00,0xea,0xff,0xa1,0x04,0x07,0x10,0xa7,0x00,0x08,0x00,0xe0,0x03, +0x00,0x00,0x00,0x00,0x25,0xb0,0x02,0x3c,0x0a,0x00,0x42,0x34,0x00,0x00,0x43,0x90, +0xff,0xff,0x84,0x24,0x00,0x24,0x04,0x00,0x03,0x24,0x04,0x00,0xff,0x00,0x65,0x30, +0x1d,0x00,0x80,0x04,0x21,0x38,0x00,0x00,0x21,0x30,0x40,0x00,0x01,0x00,0x08,0x24, +0x04,0x00,0xa5,0x34,0x00,0x00,0xc5,0xa0,0x00,0x00,0xc2,0x90,0x00,0x00,0x00,0x00, +0xff,0x00,0x45,0x30,0x01,0x00,0xa3,0x30,0x05,0x00,0x60,0x10,0x04,0x00,0x02,0x24, +0x04,0x10,0x88,0x00,0x25,0x10,0x47,0x00,0xff,0xff,0x47,0x30,0x04,0x00,0x02,0x24, +0xff,0xff,0x42,0x24,0xff,0xff,0x41,0x04,0xff,0xff,0x42,0x24,0xfb,0x00,0xa5,0x30, +0x00,0x00,0xc5,0xa0,0x09,0x00,0x02,0x24,0xff,0xff,0x42,0x24,0xff,0xff,0x41,0x04, +0xff,0xff,0x42,0x24,0xff,0xff,0x82,0x24,0x00,0x24,0x02,0x00,0x03,0x24,0x04,0x00, +0xe7,0xff,0x81,0x04,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x21,0x10,0xe0,0x00, +0xe0,0xff,0xbd,0x27,0x10,0x00,0xb0,0xaf,0x25,0xb0,0x10,0x3c,0x0a,0x00,0x10,0x36, +0x18,0x00,0xbf,0xaf,0x14,0x00,0xb1,0xaf,0x00,0x00,0x02,0x92,0xff,0xff,0x91,0x30, +0x03,0x00,0x05,0x24,0xc0,0x00,0x42,0x30,0x80,0x00,0x43,0x34,0x00,0x00,0x03,0xa2, +0x04,0x00,0x63,0x34,0x00,0x00,0x03,0xa2,0xfb,0x00,0x63,0x30,0x00,0x00,0x03,0xa2, +0x08,0x00,0x63,0x34,0x00,0x00,0x03,0xa2,0x04,0x00,0x63,0x34,0x00,0x00,0x03,0xa2, +0xfb,0x00,0x63,0x30,0x00,0x00,0x03,0xa2,0xd7,0x0b,0x00,0x0c,0x06,0x00,0x04,0x24, +0x42,0x20,0x11,0x00,0xd7,0x0b,0x00,0x0c,0x06,0x00,0x05,0x24,0xfd,0x0b,0x00,0x0c, +0x10,0x00,0x04,0x24,0x00,0x00,0x03,0x92,0x18,0x00,0xbf,0x8f,0x14,0x00,0xb1,0x8f, +0xc0,0x00,0x63,0x30,0x00,0x00,0x03,0xa2,0x10,0x00,0xb0,0x8f,0x08,0x00,0xe0,0x03, +0x20,0x00,0xbd,0x27,0xe0,0xff,0xbd,0x27,0x14,0x00,0xb1,0xaf,0xff,0xff,0xb1,0x30, +0x18,0x00,0xb2,0xaf,0x10,0x00,0xb0,0xaf,0x1c,0x00,0xbf,0xaf,0x21,0x90,0xc0,0x00, +0x0a,0x00,0x20,0x12,0xff,0xff,0x90,0x30,0x24,0x0c,0x00,0x0c,0x21,0x20,0x00,0x02, +0xfe,0xff,0x23,0x26,0x02,0x00,0x04,0x26,0x00,0x00,0x42,0xa6,0xff,0xff,0x71,0x30, +0xff,0xff,0x90,0x30,0xf8,0xff,0x20,0x16,0x02,0x00,0x52,0x26,0x1c,0x00,0xbf,0x8f, +0x18,0x00,0xb2,0x8f,0x14,0x00,0xb1,0x8f,0x10,0x00,0xb0,0x8f,0x08,0x00,0xe0,0x03, +0x20,0x00,0xbd,0x27,0x25,0xb0,0x03,0x3c,0x0a,0x00,0x68,0x34,0x00,0x00,0x02,0x91, +0xff,0xff,0xa5,0x30,0xff,0x00,0x84,0x30,0x1f,0x00,0xa0,0x10,0xff,0x00,0x47,0x30, +0x21,0x48,0x00,0x01,0x0c,0x00,0x6c,0x34,0x0b,0x00,0x6b,0x34,0xc0,0xff,0x0a,0x24, +0x21,0x68,0x00,0x01,0x25,0x10,0xea,0x00,0xff,0x00,0x47,0x30,0x00,0x00,0x64,0xa1, +0x00,0x00,0x27,0xa1,0x00,0x00,0x22,0x91,0x00,0x00,0x00,0x00,0xff,0x00,0x47,0x30, +0xc0,0x00,0xe3,0x30,0x08,0x00,0x60,0x10,0x00,0x00,0x00,0x00,0x21,0x40,0xa0,0x01, +0x00,0x00,0x02,0x91,0x00,0x00,0x00,0x00,0xff,0x00,0x47,0x30,0xc0,0x00,0xe3,0x30, +0xfb,0xff,0x60,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x82,0x8d,0xfc,0xff,0xa3,0x24, +0x04,0x00,0x84,0x24,0xff,0xff,0x65,0x30,0x00,0x00,0xc2,0xac,0xff,0x00,0x84,0x30, +0xe8,0xff,0xa0,0x14,0x04,0x00,0xc6,0x24,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00, +0xff,0x00,0x84,0x30,0x21,0x68,0xe0,0x00,0xff,0xff,0xa5,0x30,0xc0,0x50,0x04,0x00, +0x00,0x60,0x0c,0x40,0x01,0x00,0x81,0x35,0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40, +0x00,0x00,0xc2,0x90,0x01,0x00,0xc3,0x90,0x25,0xb0,0x07,0x3c,0x00,0x14,0x02,0x00, +0x25,0x28,0xa2,0x00,0x00,0x1e,0x03,0x00,0x01,0x80,0x08,0x3c,0x25,0x20,0xa3,0x00, +0x40,0x02,0xe9,0x34,0x25,0x18,0x48,0x01,0x44,0x02,0xe7,0x34,0x00,0x00,0xe4,0xac, +0x00,0x00,0x23,0xad,0x03,0x00,0xc2,0x90,0x02,0x00,0xc4,0x90,0x04,0x00,0xc3,0x90, +0x05,0x00,0xc5,0x90,0x00,0x12,0x02,0x00,0x25,0x20,0x82,0x00,0x00,0x1c,0x03,0x00, +0x01,0x00,0x4a,0x25,0x25,0x20,0x83,0x00,0x00,0x2e,0x05,0x00,0x25,0x40,0x48,0x01, +0x25,0x20,0x85,0x00,0x00,0x00,0xe4,0xac,0x01,0x00,0x4a,0x25,0x00,0x00,0x28,0xad, +0x01,0x80,0x0b,0x3c,0x21,0x40,0x00,0x00,0x21,0x10,0xa8,0x01,0x01,0x00,0x43,0x90, +0x00,0x00,0x45,0x90,0x02,0x00,0x44,0x90,0x03,0x00,0x46,0x90,0x00,0x1a,0x03,0x00, +0x25,0x28,0xa3,0x00,0x00,0x24,0x04,0x00,0x25,0x28,0xa4,0x00,0x00,0x36,0x06,0x00, +0x04,0x00,0x08,0x25,0x25,0x10,0x4b,0x01,0x25,0x20,0xa6,0x00,0x10,0x00,0x03,0x2d, +0x00,0x00,0xe4,0xac,0x01,0x00,0x4a,0x25,0x00,0x00,0x22,0xad,0xee,0xff,0x60,0x14, +0x00,0x00,0x00,0x00,0x00,0x60,0x8c,0x40,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00, +0xff,0xff,0x84,0x30,0x42,0xb0,0x08,0x3c,0x80,0x10,0x04,0x00,0x21,0x10,0x48,0x00, +0x04,0x00,0x46,0xac,0x00,0x00,0x07,0x91,0x40,0x18,0x04,0x00,0x03,0x00,0x06,0x24, +0xff,0x00,0xe7,0x30,0x04,0x30,0x66,0x00,0x01,0x00,0x02,0x24,0x04,0x10,0x62,0x00, +0x25,0x30,0xc7,0x00,0xff,0xff,0xa5,0x30,0x25,0x10,0x47,0x00,0x02,0x00,0xa0,0x14, +0xff,0x00,0xc7,0x30,0xff,0x00,0x47,0x30,0x42,0xb0,0x02,0x3c,0x00,0x00,0x47,0xa0, +0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x42,0xb0,0x02,0x3c,0x03,0x00,0x47,0x34, +0x00,0x00,0xe3,0x90,0xff,0x00,0x84,0x30,0x04,0x00,0x84,0x24,0xff,0x00,0x65,0x30, +0x01,0x00,0x02,0x24,0x04,0x30,0x82,0x00,0x07,0x18,0x85,0x00,0x25,0xb0,0x02,0x3c, +0xe8,0x03,0x42,0x34,0x01,0x00,0x63,0x30,0x21,0x20,0xc0,0x00,0x00,0x00,0x45,0xa0, +0x02,0x00,0x60,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0xe6,0xa0,0x08,0x00,0xe0,0x03, +0x24,0x10,0x85,0x00,0x00,0x60,0x03,0x40,0x01,0x00,0x61,0x34,0x01,0x00,0x21,0x38, +0x00,0x60,0x81,0x40,0x02,0x80,0x02,0x3c,0xdc,0x8c,0x42,0x24,0x04,0x00,0x45,0x8c, +0x00,0x00,0x82,0xac,0x04,0x00,0x44,0xac,0x00,0x00,0xa4,0xac,0x04,0x00,0x85,0xac, +0x00,0x60,0x83,0x40,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x14,0x00,0x83,0x90, +0x01,0x00,0x02,0x24,0x08,0x00,0x86,0xac,0x18,0x00,0x85,0xac,0x00,0x00,0x84,0xac, +0x03,0x00,0x62,0x10,0x04,0x00,0x84,0xac,0xed,0x0c,0x00,0x08,0x0c,0x00,0x80,0xac, +0x0c,0x00,0x82,0x8c,0xed,0x0c,0x00,0x08,0x10,0x00,0x82,0xac,0x00,0x60,0x03,0x40, +0x01,0x00,0x61,0x34,0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,0x04,0x00,0x85,0x8c, +0x00,0x00,0x82,0x8c,0x00,0x00,0x00,0x00,0x00,0x00,0xa2,0xac,0x04,0x00,0x45,0xac, +0x00,0x00,0x84,0xac,0x04,0x00,0x84,0xac,0x00,0x60,0x83,0x40,0x08,0x00,0xe0,0x03, +0x00,0x00,0x00,0x00,0xd0,0xff,0xbd,0x27,0x28,0x00,0xb6,0xaf,0x24,0x00,0xb5,0xaf, +0x20,0x00,0xb4,0xaf,0x14,0x00,0xb1,0xaf,0x2c,0x00,0xbf,0xaf,0x1c,0x00,0xb3,0xaf, +0x18,0x00,0xb2,0xaf,0x10,0x00,0xb0,0xaf,0x00,0x80,0x16,0x3c,0x02,0x80,0x14,0x3c, +0x02,0x80,0x11,0x3c,0x02,0x80,0x15,0x3c,0xc4,0x7d,0x24,0x8e,0x25,0xb0,0x02,0x3c, +0x54,0x34,0xc3,0x26,0x18,0x03,0x42,0x34,0x00,0x00,0x43,0xac,0xdc,0x8c,0x90,0x8e, +0x18,0x00,0x80,0x10,0xdc,0x8c,0x82,0x26,0x15,0x00,0x02,0x12,0x00,0x00,0x00,0x00, +0x21,0x98,0x40,0x00,0x01,0x00,0x12,0x24,0x14,0x00,0x02,0x92,0x00,0x00,0x00,0x00, +0x1d,0x00,0x52,0x10,0x00,0x00,0x00,0x00,0x09,0x00,0x40,0x14,0x00,0x00,0x00,0x00, +0x0c,0x00,0x03,0x8e,0xc4,0x7d,0x22,0x8e,0x00,0x00,0x00,0x00,0x23,0x20,0x62,0x00, +0x2b,0x10,0x43,0x00,0x0e,0x00,0x40,0x10,0x00,0x00,0x00,0x00,0x0c,0x00,0x04,0xae, +0x00,0x00,0x10,0x8e,0x00,0x00,0x00,0x00,0xef,0xff,0x13,0x16,0x00,0x00,0x00,0x00, +0xc4,0x7d,0x20,0xae,0x08,0x0c,0xa4,0x26,0x21,0x28,0x00,0x00,0x21,0x30,0x00,0x00, +0x31,0x1c,0x00,0x0c,0x21,0x38,0x00,0x00,0x22,0x0d,0x00,0x08,0x00,0x00,0x00,0x00, +0x08,0x00,0x02,0x8e,0x18,0x00,0x04,0x8e,0x09,0xf8,0x40,0x00,0x00,0x00,0x00,0x00, +0x3c,0x0d,0x00,0x08,0x0c,0x00,0x02,0xae,0x0c,0x00,0x03,0x8e,0xc4,0x7d,0x22,0x8e, +0x00,0x00,0x00,0x00,0x23,0x20,0x62,0x00,0x2b,0x10,0x43,0x00,0xe7,0xff,0x40,0x14, +0x00,0x00,0x00,0x00,0x08,0x00,0x02,0x8e,0x18,0x00,0x04,0x8e,0x09,0xf8,0x40,0x00, +0x00,0x00,0x00,0x00,0x10,0x00,0x03,0x8e,0x3c,0x0d,0x00,0x08,0x0c,0x00,0x03,0xae, +0xff,0x00,0xa5,0x30,0x25,0xb0,0x02,0x3c,0x21,0x28,0xa2,0x00,0xff,0x00,0x84,0x30, +0x60,0x01,0xa4,0xa0,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0xff,0x00,0x84,0x30, +0x01,0x00,0x03,0x24,0x10,0x00,0x02,0x3c,0x04,0x18,0x83,0x00,0xf0,0x70,0x42,0x34, +0x15,0x00,0x84,0x2c,0x06,0x00,0x80,0x10,0x24,0x28,0x62,0x00,0x0f,0x00,0x63,0x30, +0x04,0x00,0xa0,0x14,0x01,0x00,0x02,0x24,0x02,0x00,0x60,0x14,0x02,0x00,0x02,0x24, +0x21,0x10,0x00,0x00,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0xff,0x00,0xa5,0x30, +0x04,0x00,0xa2,0x2c,0x14,0x00,0x40,0x10,0xff,0x00,0x84,0x30,0x02,0x80,0x03,0x3c, +0x8e,0x7d,0x62,0x90,0x00,0x00,0x00,0x00,0xef,0xff,0x42,0x24,0xff,0x00,0x42,0x30, +0x02,0x00,0x42,0x2c,0x0e,0x00,0x40,0x10,0x02,0x00,0x03,0x24,0x24,0x00,0x83,0x10, +0x0f,0x10,0x02,0x3c,0x03,0x00,0x82,0x28,0x14,0x00,0x40,0x10,0x03,0x00,0x02,0x24, +0x01,0x00,0x02,0x24,0x2f,0x00,0x82,0x10,0x00,0x00,0x00,0x00,0xff,0x1f,0x02,0x3c, +0x08,0x00,0xe0,0x03,0xff,0xff,0x42,0x34,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00, +0x35,0x00,0x83,0x10,0x0f,0x1f,0x02,0x3c,0x03,0x00,0x82,0x28,0x16,0x00,0x40,0x10, +0x03,0x00,0x02,0x24,0x01,0x00,0x02,0x24,0xf4,0xff,0x82,0x14,0x00,0x00,0x00,0x00, +0x0f,0x1f,0x02,0x3c,0x08,0x00,0xe0,0x03,0x00,0x80,0x42,0x34,0xf0,0xff,0x82,0x14, +0xff,0x1f,0x02,0x3c,0x01,0x00,0x02,0x24,0x29,0x00,0xa2,0x10,0x0f,0x10,0x02,0x3c, +0x02,0x00,0xa2,0x28,0x1f,0x00,0x40,0x14,0x00,0x00,0x00,0x00,0x28,0x00,0xa3,0x10, +0x00,0x00,0x00,0x00,0xe5,0xff,0xa4,0x14,0x00,0x00,0x00,0x00,0x0f,0x10,0x02,0x3c, +0x08,0x00,0xe0,0x03,0x00,0xf0,0x42,0x34,0xe1,0xff,0x82,0x14,0xff,0x1f,0x02,0x3c, +0x01,0x00,0x02,0x24,0x1c,0x00,0xa2,0x10,0x0f,0x00,0x02,0x3c,0x02,0x00,0xa2,0x28, +0x0b,0x00,0x40,0x14,0x00,0x00,0x00,0x00,0x1c,0x00,0xa3,0x10,0x00,0x00,0x00,0x00, +0xd6,0xff,0xa4,0x14,0x00,0x00,0x00,0x00,0x0f,0x00,0x02,0x3c,0x08,0x00,0xe0,0x03, +0x00,0xf0,0x42,0x34,0x0f,0x10,0x02,0x3c,0x08,0x00,0xe0,0x03,0x00,0x80,0x42,0x34, +0xce,0xff,0xa0,0x14,0x00,0x00,0x00,0x00,0x0f,0x00,0x02,0x3c,0x08,0x00,0xe0,0x03, +0x15,0xf0,0x42,0x34,0xc9,0xff,0xa0,0x14,0x00,0x00,0x00,0x00,0x0f,0x10,0x02,0x3c, +0x08,0x00,0xe0,0x03,0x15,0xf0,0x42,0x34,0x08,0x00,0xe0,0x03,0x00,0xf0,0x42,0x34, +0x08,0x00,0xe0,0x03,0x10,0xf0,0x42,0x34,0x08,0x00,0xe0,0x03,0x10,0xf0,0x42,0x34, +0x0f,0x10,0x02,0x3c,0x08,0x00,0xe0,0x03,0x05,0xf0,0x42,0x34,0x0f,0x00,0x02,0x3c, +0x08,0x00,0xe0,0x03,0x05,0xf0,0x42,0x34,0xc0,0x40,0x04,0x00,0x21,0x18,0x04,0x01, +0x80,0x18,0x03,0x00,0x21,0x18,0x64,0x00,0x02,0x80,0x02,0x3c,0x80,0x18,0x03,0x00, +0x68,0x15,0x42,0x24,0x21,0x18,0x62,0x00,0x74,0x51,0x66,0x8c,0x21,0x38,0x60,0x00, +0x7a,0x51,0x60,0xa0,0x7b,0x51,0x60,0xa0,0x1c,0x00,0x05,0x24,0xdf,0x0d,0x00,0x08, +0x01,0x00,0x03,0x24,0x08,0x00,0xa0,0x04,0x21,0x10,0x04,0x01,0x04,0x10,0xa3,0x00, +0x24,0x10,0xc2,0x00,0xfb,0xff,0x40,0x10,0xff,0xff,0xa5,0x24,0x01,0x00,0xa5,0x24, +0x7a,0x51,0xe5,0xa0,0x21,0x10,0x04,0x01,0x80,0x10,0x02,0x00,0x21,0x10,0x44,0x00, +0x02,0x80,0x03,0x3c,0x80,0x10,0x02,0x00,0x68,0x15,0x63,0x24,0x21,0x18,0x43,0x00, +0x74,0x51,0x66,0x8c,0x21,0x28,0x00,0x00,0xf3,0x0d,0x00,0x08,0x01,0x00,0x07,0x24, +0x1d,0x00,0xa2,0x28,0x08,0x00,0x40,0x10,0x00,0x00,0x00,0x00,0x04,0x10,0xa7,0x00, +0x24,0x10,0xc2,0x00,0xfa,0xff,0x40,0x10,0x01,0x00,0xa5,0x24,0xff,0xff,0xa5,0x24, +0x08,0x00,0xe0,0x03,0x7b,0x51,0x65,0xa0,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00, +0xc8,0xff,0xbd,0x27,0x28,0x00,0xb6,0xaf,0x02,0x80,0x16,0x3c,0x30,0x00,0xbe,0xaf, +0x2c,0x00,0xb7,0xaf,0x24,0x00,0xb5,0xaf,0x20,0x00,0xb4,0xaf,0x18,0x00,0xb2,0xaf, +0x14,0x00,0xb1,0xaf,0x01,0x00,0x15,0x24,0x21,0x88,0x00,0x00,0x68,0x15,0xde,0x26, +0x21,0xa0,0x00,0x00,0x21,0x90,0x00,0x00,0x25,0xb0,0x17,0x3c,0x34,0x00,0xbf,0xaf, +0x1c,0x00,0xb3,0xaf,0x14,0x0e,0x00,0x08,0x10,0x00,0xb0,0xaf,0x01,0x00,0x31,0x26, +0x20,0x00,0x22,0x2e,0x94,0x00,0x52,0x26,0x2e,0x00,0x40,0x10,0x94,0x00,0x94,0x26, +0x68,0x15,0xc2,0x26,0x21,0x30,0x42,0x02,0x78,0x51,0xc5,0x8c,0x00,0x00,0x00,0x00, +0x02,0x13,0x05,0x00,0x01,0x00,0x42,0x30,0xf4,0xff,0x55,0x14,0x42,0x1a,0x05,0x00, +0x68,0x51,0xc2,0x8c,0x07,0x00,0x64,0x30,0x02,0x11,0x02,0x00,0x7f,0x00,0x43,0x30, +0x2d,0x00,0x95,0x10,0x07,0x00,0xb3,0x30,0x02,0x00,0x82,0x28,0x3a,0x00,0x40,0x14, +0x02,0x00,0x02,0x24,0x30,0x00,0x82,0x10,0x03,0x00,0x02,0x24,0x3c,0x00,0x82,0x10, +0x1a,0x00,0x62,0x2c,0x21,0x80,0x9e,0x02,0x78,0x51,0x02,0x8e,0x04,0x00,0x63,0x2e, +0x42,0x12,0x02,0x00,0x0a,0x00,0x60,0x10,0x07,0x00,0x44,0x30,0x73,0x0d,0x00,0x0c, +0x21,0x28,0x60,0x02,0x80,0x20,0x13,0x00,0x70,0x51,0x02,0xae,0x21,0x20,0x97,0x00, +0x84,0x01,0x83,0x8c,0x00,0x00,0x00,0x00,0x24,0x18,0x62,0x00,0x74,0x51,0x03,0xae, +0xce,0x0d,0x00,0x0c,0x21,0x20,0x20,0x02,0x21,0x10,0x37,0x02,0x01,0x00,0x31,0x26, +0x60,0x01,0x43,0x90,0x20,0x00,0x22,0x2e,0x94,0x00,0x52,0x26,0xd4,0xff,0x40,0x14, +0x94,0x00,0x94,0x26,0x34,0x00,0xbf,0x8f,0x30,0x00,0xbe,0x8f,0x2c,0x00,0xb7,0x8f, +0x28,0x00,0xb6,0x8f,0x24,0x00,0xb5,0x8f,0x20,0x00,0xb4,0x8f,0x1c,0x00,0xb3,0x8f, +0x18,0x00,0xb2,0x8f,0x14,0x00,0xb1,0x8f,0x10,0x00,0xb0,0x8f,0x21,0x10,0x00,0x00, +0x08,0x00,0xe0,0x03,0x38,0x00,0xbd,0x27,0x32,0x00,0x62,0x2c,0xda,0xff,0x40,0x10, +0x21,0x80,0x9e,0x02,0xff,0xf1,0x03,0x24,0x24,0x10,0xa3,0x00,0x00,0x04,0x42,0x34, +0x29,0x0e,0x00,0x08,0x78,0x51,0xc2,0xac,0x38,0x00,0x62,0x2c,0x12,0x00,0x40,0x14, +0x14,0x00,0x62,0x2c,0xff,0xf1,0x03,0x24,0x24,0x10,0xa3,0x00,0x00,0x02,0x42,0x34, +0x29,0x0e,0x00,0x08,0x78,0x51,0xc2,0xac,0xcb,0xff,0x80,0x14,0x21,0x80,0x9e,0x02, +0xff,0xf1,0x03,0x24,0x24,0x10,0xa3,0x00,0x2a,0x0e,0x00,0x08,0x78,0x51,0xc2,0xac, +0xc5,0xff,0x40,0x14,0x21,0x80,0x9e,0x02,0xff,0xf1,0x03,0x24,0x24,0x10,0xa3,0x00, +0x54,0x0e,0x00,0x08,0x00,0x04,0x42,0x34,0xbf,0xff,0x40,0x10,0x21,0x80,0x9e,0x02, +0xff,0xf1,0x03,0x24,0x24,0x10,0xa3,0x00,0x00,0x06,0x42,0x34,0x2a,0x0e,0x00,0x08, +0x78,0x51,0xc2,0xac,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0xd8,0xff,0xbd,0x27, +0x10,0x00,0xb0,0xaf,0xc0,0x80,0x04,0x00,0x21,0x80,0x04,0x02,0x80,0x80,0x10,0x00, +0x21,0x80,0x04,0x02,0x02,0x80,0x02,0x3c,0x68,0x15,0x42,0x24,0x80,0x80,0x10,0x00, +0x20,0x00,0xbf,0xaf,0x1c,0x00,0xb3,0xaf,0x18,0x00,0xb2,0xaf,0x21,0x80,0x02,0x02, +0x14,0x00,0xb1,0xaf,0x78,0x51,0x03,0x8e,0x25,0xb0,0x02,0x3c,0x80,0x01,0x53,0x34, +0x07,0x00,0x63,0x30,0x80,0x18,0x03,0x00,0x21,0x18,0x62,0x00,0x00,0x00,0x71,0x92, +0x70,0x51,0x05,0x8e,0x84,0x01,0x62,0x8c,0x21,0x90,0x80,0x00,0xff,0x00,0x31,0x32, +0x24,0x10,0x45,0x00,0xce,0x0d,0x00,0x0c,0x74,0x51,0x02,0xae,0x7a,0x51,0x04,0x92, +0x5c,0x0d,0x00,0x0c,0xff,0x00,0x45,0x32,0x7a,0x51,0x04,0x92,0x63,0x0d,0x00,0x0c, +0x00,0x00,0x00,0x00,0x01,0x00,0x42,0x38,0x04,0x00,0x03,0x24,0x0a,0x88,0x62,0x00, +0x00,0x00,0x71,0xa2,0x20,0x00,0xbf,0x8f,0x1c,0x00,0xb3,0x8f,0x18,0x00,0xb2,0x8f, +0x14,0x00,0xb1,0x8f,0x10,0x00,0xb0,0x8f,0x08,0x00,0xe0,0x03,0x28,0x00,0xbd,0x27, +0xff,0xff,0x84,0x30,0x00,0x02,0x82,0x30,0x07,0x00,0x03,0x24,0x0d,0x00,0x40,0x14, +0x0b,0x00,0x84,0x30,0x0c,0x00,0x82,0x2c,0x0a,0x00,0x40,0x10,0x00,0x00,0x00,0x00, +0x02,0x80,0x03,0x3c,0x80,0x10,0x04,0x00,0xf0,0x91,0x63,0x24,0x21,0x10,0x43,0x00, +0x00,0x00,0x44,0x8c,0x00,0x00,0x00,0x00,0x08,0x00,0x80,0x00,0x00,0x00,0x00,0x00, +0x07,0x00,0x03,0x24,0x08,0x00,0xe0,0x03,0x21,0x10,0x60,0x00,0x06,0x00,0x03,0x24, +0x08,0x00,0xe0,0x03,0x21,0x10,0x60,0x00,0x05,0x00,0x03,0x24,0x08,0x00,0xe0,0x03, +0x21,0x10,0x60,0x00,0x04,0x00,0x03,0x24,0x08,0x00,0xe0,0x03,0x21,0x10,0x60,0x00, +0x03,0x00,0x03,0x24,0x08,0x00,0xe0,0x03,0x21,0x10,0x60,0x00,0x02,0x00,0x03,0x24, +0x08,0x00,0xe0,0x03,0x21,0x10,0x60,0x00,0x01,0x00,0x03,0x24,0x08,0x00,0xe0,0x03, +0x21,0x10,0x60,0x00,0x21,0x18,0x00,0x00,0x08,0x00,0xe0,0x03,0x21,0x10,0x60,0x00, +0xa0,0xff,0xbd,0x27,0x02,0x80,0x02,0x3c,0x58,0x00,0xbe,0xaf,0x54,0x00,0xb7,0xaf, +0x50,0x00,0xb6,0xaf,0x4c,0x00,0xb5,0xaf,0x48,0x00,0xb4,0xaf,0x40,0x00,0xb2,0xaf, +0x3c,0x00,0xb1,0xaf,0x5c,0x00,0xbf,0xaf,0x44,0x00,0xb3,0xaf,0x38,0x00,0xb0,0xaf, +0x20,0x92,0x42,0x24,0x00,0x00,0x53,0x8c,0x08,0x00,0x03,0x24,0x02,0x80,0x0b,0x3c, +0x21,0x90,0x00,0x00,0x21,0xa0,0x00,0x00,0x21,0xb8,0x00,0x00,0x21,0xf0,0x00,0x00, +0x21,0xa8,0x00,0x00,0x21,0xb0,0x00,0x00,0x21,0x88,0x60,0x02,0x10,0x00,0xa3,0xaf, +0x14,0x00,0xa0,0xaf,0x18,0x00,0xa0,0xaf,0x1c,0x00,0xa0,0xaf,0x20,0x00,0xa0,0xaf, +0x24,0x00,0xa0,0xaf,0x28,0x00,0xa0,0xaf,0x7a,0x0f,0x00,0x08,0x2c,0x00,0xa0,0xaf, +0x44,0x51,0x22,0xae,0x60,0x51,0x24,0x8e,0x5c,0x51,0x27,0x8e,0x48,0x51,0x28,0x8e, +0x4c,0x51,0x25,0x8e,0x54,0x51,0x26,0x8e,0x58,0x51,0x23,0x8e,0x21,0x38,0xe4,0x00, +0x02,0x80,0x04,0x3c,0x68,0x15,0x84,0x24,0x21,0x10,0x04,0x02,0x21,0x40,0x05,0x01, +0x21,0x30,0xc3,0x00,0xca,0x44,0x42,0x90,0x44,0x51,0x2a,0x8e,0x0c,0x00,0xe0,0x10, +0x21,0x48,0x00,0x00,0x2b,0x48,0x47,0x00,0x0b,0x00,0x20,0x15,0x02,0x80,0x02,0x3c, +0x07,0x00,0x02,0x2e,0x59,0x01,0x40,0x14,0xc0,0x10,0x07,0x00,0x0c,0x00,0x02,0x24, +0x55,0x01,0x02,0x12,0x0d,0x00,0x02,0x24,0x54,0x01,0x02,0x12,0xc0,0x10,0x07,0x00, +0x92,0x00,0x20,0x11,0x02,0x80,0x02,0x3c,0x68,0x15,0x42,0x24,0x80,0x18,0x10,0x00, +0x21,0x18,0x62,0x00,0x21,0x20,0x30,0x02,0xb6,0x51,0x85,0x90,0xec,0x44,0x62,0x8c, +0x00,0x00,0x00,0x00,0x04,0x10,0xa2,0x00,0x2b,0x10,0x4a,0x00,0x87,0x00,0x40,0x10, +0x00,0x00,0x00,0x00,0xd4,0x51,0x22,0x8e,0x01,0x00,0x07,0x24,0x04,0x18,0x07,0x02, +0x24,0x10,0x43,0x00,0xf0,0x00,0x40,0x10,0x1c,0x00,0x02,0x2e,0x21,0x28,0x30,0x02, +0x7c,0x51,0xa6,0x90,0xb6,0x51,0xa2,0x90,0x0a,0x00,0x04,0x24,0xff,0x00,0xc3,0x30, +0x04,0x20,0x44,0x00,0x2a,0x18,0x64,0x00,0xe7,0x00,0x60,0x10,0x1c,0x00,0x02,0x2e, +0x01,0x00,0xc2,0x24,0xff,0x00,0x43,0x30,0x56,0x01,0x64,0x10,0x7c,0x51,0xa2,0xa0, +0x68,0x15,0x65,0x25,0x80,0x10,0x10,0x00,0x21,0x10,0x45,0x00,0x60,0x45,0x44,0x8c, +0xec,0x44,0x43,0x8c,0x21,0x30,0xc5,0x02,0x40,0x10,0x04,0x00,0x21,0x10,0x44,0x00, +0x21,0x18,0x62,0x00,0x82,0x50,0x03,0x00,0x44,0x51,0xca,0xac,0x8c,0x65,0xa3,0x8c, +0xff,0xff,0x02,0x34,0x07,0x00,0x62,0x10,0x21,0x20,0x00,0x02,0x21,0x20,0x00,0x02, +0xff,0x00,0x45,0x32,0x5c,0x0d,0x00,0x0c,0x30,0x00,0xab,0xaf,0x30,0x00,0xab,0x8f, +0x21,0x20,0x00,0x02,0x63,0x0d,0x00,0x0c,0x30,0x00,0xab,0xaf,0x10,0x00,0xa4,0x8f, +0x01,0x00,0x42,0x38,0x04,0x00,0x03,0x24,0x0a,0x20,0x62,0x00,0x10,0x00,0xa4,0xaf, +0x30,0x00,0xab,0x8f,0x11,0x00,0x40,0x16,0x68,0x15,0x62,0x25,0x58,0x51,0x47,0x8c, +0x54,0x51,0x43,0x8c,0x4c,0x51,0x44,0x94,0x48,0x51,0x45,0x94,0x50,0x51,0x46,0x94, +0x21,0x18,0x67,0x00,0x00,0x24,0x04,0x00,0x25,0xb0,0x02,0x3c,0x00,0x1c,0x03,0x00, +0x21,0x28,0xa4,0x00,0x21,0x30,0xc3,0x00,0x6c,0x0c,0x44,0x34,0x68,0x0c,0x42,0x34, +0x00,0x00,0x45,0xac,0x00,0x00,0x86,0xac,0x68,0x15,0x62,0x25,0x21,0x10,0x82,0x02, +0x58,0x51,0x40,0xac,0x5c,0x51,0x40,0xac,0x60,0x51,0x40,0xac,0x48,0x51,0x40,0xac, +0x4c,0x51,0x40,0xac,0x50,0x51,0x40,0xac,0x54,0x51,0x40,0xac,0x2c,0x00,0xa2,0x8f, +0x28,0x00,0xa4,0x8f,0x01,0x00,0x52,0x26,0x94,0x00,0x42,0x24,0x2c,0x00,0xa2,0xaf, +0x24,0x00,0xa2,0x8f,0x94,0x00,0x84,0x24,0x28,0x00,0xa4,0xaf,0x94,0x00,0x42,0x24, +0x20,0x00,0xa4,0x8f,0x24,0x00,0xa2,0xaf,0x1c,0x00,0xa2,0x8f,0x94,0x00,0x84,0x24, +0x20,0x00,0xa4,0xaf,0x94,0x00,0x42,0x24,0x18,0x00,0xa4,0x8f,0x1c,0x00,0xa2,0xaf, +0x14,0x00,0xa2,0x8f,0x94,0x00,0x84,0x24,0x20,0x00,0x43,0x2a,0x94,0x00,0x42,0x24, +0x94,0x00,0x31,0x26,0x94,0x00,0xd6,0x26,0x94,0x00,0xb5,0x26,0x18,0x00,0xa4,0xaf, +0x14,0x00,0xa2,0xaf,0x94,0x00,0xde,0x27,0x94,0x00,0x73,0x26,0x94,0x00,0xf7,0x26, +0xe5,0x00,0x60,0x10,0x94,0x00,0x94,0x26,0x78,0x51,0x22,0x8e,0x00,0x00,0x00,0x00, +0x02,0x13,0x02,0x00,0x01,0x00,0x42,0x30,0xd3,0xff,0x40,0x10,0x25,0xb0,0x02,0x3c, +0x21,0x10,0x42,0x02,0x60,0x01,0x44,0x90,0x60,0x51,0x23,0x8e,0x5c,0x51,0x26,0x8e, +0xff,0x00,0x90,0x30,0x02,0x80,0x04,0x3c,0x68,0x15,0x84,0x24,0x21,0x10,0x04,0x02, +0x73,0x44,0x44,0x90,0x56,0x44,0x45,0x90,0x44,0x51,0x27,0x8e,0x18,0x00,0x64,0x00, +0x12,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0xc5,0x00, +0x12,0x30,0x00,0x00,0x21,0x30,0xc3,0x00,0x2b,0x10,0xe6,0x00,0x54,0xff,0x40,0x10, +0x23,0x10,0xe6,0x00,0xe9,0x0e,0x00,0x08,0x44,0x51,0x20,0xae,0x62,0x00,0xe0,0x10, +0x00,0x00,0x00,0x00,0x63,0x00,0x20,0x15,0x68,0x15,0x62,0x25,0x40,0x10,0x07,0x00, +0x21,0x10,0x47,0x00,0x82,0x10,0x02,0x00,0x2b,0x10,0x46,0x00,0x99,0xff,0x40,0x10, +0x21,0x20,0x00,0x02,0x68,0x15,0x68,0x25,0x21,0x20,0xa8,0x02,0x21,0x30,0x90,0x00, +0xd4,0x51,0x83,0x8c,0x01,0x00,0x05,0x24,0x04,0x10,0x05,0x02,0x99,0x51,0xc7,0x90, +0x27,0x10,0x02,0x00,0x24,0x18,0x62,0x00,0xd4,0x51,0x83,0xac,0x09,0x00,0xe5,0x10, +0x7c,0x51,0xc0,0xa0,0x18,0x00,0xa2,0x8f,0x21,0x38,0x00,0x00,0x21,0x20,0x48,0x00, +0x21,0x18,0x87,0x00,0x01,0x00,0xe7,0x24,0x1d,0x00,0xe2,0x28,0xfc,0xff,0x40,0x14, +0xb6,0x51,0x60,0xa0,0x14,0x00,0xa4,0x8f,0x68,0x15,0x63,0x25,0x21,0x50,0x60,0x00, +0x21,0x10,0x83,0x00,0x21,0x10,0x50,0x00,0x99,0x51,0x40,0xa0,0x02,0x80,0x03,0x3c, +0x02,0x80,0x02,0x3c,0x4c,0x91,0x49,0x24,0xd8,0x90,0x68,0x24,0x21,0x38,0x00,0x00, +0x80,0x18,0x07,0x00,0x21,0x10,0x69,0x00,0x21,0x20,0x68,0x00,0x00,0x00,0x46,0x8c, +0x00,0x00,0x85,0x8c,0x01,0x00,0xe7,0x24,0x21,0x18,0x6a,0x00,0x1d,0x00,0xe2,0x28, +0xec,0x44,0x65,0xac,0xf6,0xff,0x40,0x14,0x60,0x45,0x66,0xac,0x14,0x00,0x00,0x12, +0x68,0x15,0x63,0x25,0x7b,0x51,0x62,0x92,0xff,0xff,0x07,0x26,0x2a,0x10,0xe2,0x00, +0x0e,0x00,0x40,0x14,0x02,0x80,0x0b,0x3c,0x68,0x15,0x62,0x25,0x21,0x10,0xc2,0x03, +0x7b,0x51,0x45,0x90,0x74,0x51,0x44,0x8c,0x01,0x00,0x06,0x24,0x04,0x18,0xe6,0x00, +0x24,0x10,0x83,0x00,0xb3,0x00,0x43,0x10,0x00,0x00,0x00,0x00,0xff,0xff,0xe7,0x24, +0x2a,0x10,0xe5,0x00,0xfa,0xff,0x40,0x10,0x04,0x18,0xe6,0x00,0x68,0x15,0x63,0x25, +0x80,0x10,0x10,0x00,0x21,0x10,0x43,0x00,0x60,0x45,0x45,0x8c,0xec,0x44,0x44,0x8c, +0x02,0x80,0x03,0x3c,0x40,0x10,0x05,0x00,0x8e,0x7d,0x66,0x90,0x21,0x10,0x45,0x00, +0x21,0x20,0x82,0x00,0x22,0x00,0x02,0x24,0x98,0x00,0xc2,0x10,0x82,0x50,0x04,0x00, +0xd4,0x51,0x63,0x8e,0x01,0x00,0x02,0x24,0x04,0x10,0x02,0x02,0x25,0x18,0x62,0x00, +0xd4,0x51,0x63,0xae,0x68,0x15,0x63,0x25,0x21,0x10,0xe3,0x02,0x44,0x51,0x4a,0xac, +0x8c,0x65,0x64,0x8c,0xff,0xff,0x02,0x34,0x3c,0xff,0x82,0x14,0x21,0x20,0x00,0x02, +0x39,0x0f,0x00,0x08,0x00,0x00,0x00,0x00,0x3e,0xff,0x20,0x11,0x21,0x20,0x00,0x02, +0x68,0x15,0x62,0x25,0x80,0x18,0x10,0x00,0x21,0x18,0x62,0x00,0x60,0x45,0x64,0x8c, +0x00,0x00,0x00,0x00,0x2b,0x20,0x44,0x01,0x36,0xff,0x80,0x10,0x21,0x20,0x00,0x02, +0xa2,0x0f,0x00,0x08,0x68,0x15,0x68,0x25,0x1e,0xff,0x40,0x10,0x68,0x15,0x65,0x25, +0x21,0x20,0x30,0x02,0x99,0x51,0x83,0x90,0x01,0x00,0x02,0x24,0x63,0x00,0x62,0x10, +0x02,0x80,0x02,0x3c,0x2c,0x00,0xa3,0x8f,0x68,0x15,0x42,0x24,0x21,0x38,0x00,0x00, +0x21,0x20,0x62,0x00,0x21,0x18,0x87,0x00,0x01,0x00,0xe7,0x24,0x1d,0x00,0xe2,0x28, +0xfc,0xff,0x40,0x14,0xb6,0x51,0x60,0xa0,0x28,0x00,0xa3,0x8f,0x02,0x80,0x0b,0x3c, +0x68,0x15,0x65,0x25,0x21,0x30,0x65,0x00,0xd4,0x51,0xc2,0x8c,0x01,0x00,0x03,0x24, +0x04,0x18,0x03,0x02,0x27,0x18,0x03,0x00,0x21,0x20,0xd0,0x00,0x24,0x10,0x43,0x00, +0x99,0x51,0x80,0xa0,0xd4,0x51,0xc2,0xac,0x12,0x00,0x00,0x16,0x7c,0x51,0x80,0xa0, +0x7a,0x51,0xc2,0x90,0x00,0x00,0x00,0x00,0x0e,0x00,0x40,0x10,0x01,0x00,0x07,0x24, +0x24,0x00,0xa4,0x8f,0x01,0x00,0x06,0x24,0x21,0x10,0x85,0x00,0x7a,0x51,0x44,0x90, +0x74,0x51,0x45,0x8c,0x04,0x18,0xe6,0x00,0x24,0x10,0xa3,0x00,0x5b,0x00,0x43,0x10, +0x00,0x00,0x00,0x00,0x01,0x00,0xe7,0x24,0x2a,0x10,0x87,0x00,0xfa,0xff,0x40,0x10, +0x04,0x18,0xe6,0x00,0x20,0x00,0xa2,0x8f,0x02,0x80,0x0b,0x3c,0x68,0x15,0x64,0x25, +0x21,0x18,0x44,0x00,0x7a,0x51,0x62,0x90,0x01,0x00,0x07,0x26,0x2a,0x10,0x47,0x00, +0x0e,0x00,0x40,0x14,0x01,0x00,0x06,0x24,0x1c,0x00,0xa3,0x8f,0x00,0x00,0x00,0x00, +0x21,0x10,0x64,0x00,0x7a,0x51,0x45,0x90,0x74,0x51,0x44,0x8c,0x04,0x18,0xe6,0x00, +0x24,0x10,0x83,0x00,0x42,0x00,0x43,0x10,0x00,0x00,0x00,0x00,0x01,0x00,0xe7,0x24, +0x2a,0x10,0xa7,0x00,0xfa,0xff,0x40,0x10,0x04,0x18,0xe6,0x00,0x02,0x80,0x02,0x3c, +0x8e,0x7d,0x44,0x90,0x22,0x00,0x03,0x24,0xd6,0xfe,0x83,0x14,0x68,0x15,0x65,0x25, +0xee,0xff,0x02,0x26,0xff,0x00,0x42,0x30,0x02,0x00,0x42,0x2c,0x18,0x00,0x03,0x24, +0x25,0x0f,0x00,0x08,0x0b,0x80,0x62,0x00,0xc0,0x10,0x07,0x00,0x23,0x10,0x47,0x00, +0xc2,0x10,0x02,0x00,0x2b,0x10,0x48,0x00,0xb6,0xfe,0x40,0x14,0x00,0x00,0x00,0x00, +0x04,0x0f,0x00,0x08,0x00,0x00,0x00,0x00,0x10,0x00,0xa3,0x8f,0x5c,0x00,0xbf,0x8f, +0x58,0x00,0xbe,0x8f,0x54,0x00,0xb7,0x8f,0x50,0x00,0xb6,0x8f,0x4c,0x00,0xb5,0x8f, +0x48,0x00,0xb4,0x8f,0x44,0x00,0xb3,0x8f,0x40,0x00,0xb2,0x8f,0x3c,0x00,0xb1,0x8f, +0x38,0x00,0xb0,0x8f,0x25,0xb0,0x02,0x3c,0x80,0x01,0x42,0x34,0x60,0x00,0xbd,0x27, +0x00,0x00,0x43,0xa0,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x18,0x00,0x02,0x2e, +0x0a,0x00,0x40,0x14,0x05,0x00,0x02,0x2e,0xb6,0x51,0x83,0x90,0x00,0x00,0x00,0x00, +0x05,0x00,0x62,0x2c,0xa0,0xff,0x40,0x10,0x01,0x00,0x62,0x24,0x16,0x10,0x00,0x08, +0xb6,0x51,0x82,0xa0,0x24,0x0f,0x00,0x08,0x99,0x51,0xa7,0xa0,0x04,0x00,0x40,0x10, +0x00,0x00,0x00,0x00,0xb6,0x51,0x83,0x90,0x75,0x10,0x00,0x08,0x03,0x00,0x62,0x2c, +0xb6,0x51,0x83,0x90,0x75,0x10,0x00,0x08,0x04,0x00,0x62,0x2c,0x13,0x00,0x02,0x24, +0x67,0xff,0x02,0x16,0x68,0x15,0x63,0x25,0xf3,0x0f,0x00,0x08,0x21,0x10,0xe3,0x02, +0xff,0x00,0xf0,0x30,0x4c,0x10,0x00,0x08,0x02,0x80,0x02,0x3c,0x35,0x10,0x00,0x08, +0xff,0x00,0xf0,0x30,0xdf,0x0f,0x00,0x08,0xff,0x00,0xf0,0x30,0xd8,0xff,0xbd,0x27, +0x02,0x80,0x02,0x3c,0x14,0x00,0xb1,0xaf,0x24,0x00,0xbf,0xaf,0x20,0x00,0xb4,0xaf, +0x1c,0x00,0xb3,0xaf,0x18,0x00,0xb2,0xaf,0x10,0x00,0xb0,0xaf,0x68,0x15,0x45,0x24, +0x05,0x65,0xa4,0x90,0x00,0x65,0xa3,0x8c,0xfc,0x64,0xa2,0x8c,0x21,0x88,0x64,0x00, +0x2b,0x10,0x22,0x02,0x60,0x00,0x40,0x10,0x21,0x80,0xa0,0x00,0x02,0x80,0x14,0x3c, +0x21,0x98,0xa0,0x00,0xa8,0x10,0x00,0x08,0x21,0x90,0xa0,0x00,0xfc,0x64,0x42,0x8e, +0x10,0x00,0x31,0x26,0x2b,0x10,0x22,0x02,0x57,0x00,0x40,0x10,0x21,0x80,0x40,0x02, +0x05,0x65,0x02,0x92,0xff,0xff,0x23,0x32,0x02,0x80,0x05,0x3c,0x10,0x00,0x42,0x24, +0x25,0x28,0x65,0x00,0x2c,0x79,0x84,0x26,0x10,0x00,0x06,0x24,0x9f,0x45,0x00,0x0c, +0x05,0x65,0x02,0xa2,0xc8,0x63,0x06,0x8e,0x00,0x00,0x00,0x00,0x42,0x24,0x06,0x00, +0x1f,0x00,0x84,0x30,0xc0,0x10,0x04,0x00,0x21,0x10,0x44,0x00,0x80,0x10,0x02,0x00, +0x21,0x10,0x44,0x00,0x80,0x10,0x02,0x00,0x21,0x38,0x50,0x00,0x78,0x51,0xe3,0x8c, +0x00,0x00,0x00,0x00,0x02,0x1b,0x03,0x00,0x01,0x00,0x63,0x30,0xe3,0xff,0x60,0x10, +0x25,0xb0,0x02,0x3c,0xc4,0x63,0x05,0x8e,0x21,0x10,0x82,0x00,0x60,0x01,0x44,0x90, +0x82,0x1d,0x05,0x00,0x3f,0x00,0x63,0x30,0x04,0x00,0x0a,0x24,0x05,0x00,0x62,0x28, +0x21,0x40,0x40,0x01,0x0b,0x40,0x62,0x00,0x07,0x00,0xa0,0x04,0xff,0x00,0x89,0x30, +0x64,0x51,0xe2,0x8c,0x04,0x00,0x08,0x24,0x01,0x00,0x42,0x24,0x64,0x51,0xe2,0xac, +0xc8,0x63,0x66,0x8e,0x00,0x00,0x00,0x00,0x02,0x13,0x06,0x00,0x1f,0x00,0x42,0x30, +0x08,0x00,0x42,0x28,0xcd,0xff,0x40,0x10,0x00,0x00,0x00,0x00,0xc4,0x63,0x62,0x8e, +0x00,0x00,0x00,0x00,0x3f,0x00,0x42,0x30,0xc8,0xff,0x49,0x14,0x00,0x00,0x00,0x00, +0x29,0x00,0x00,0x11,0x01,0x00,0x02,0x24,0x2e,0x00,0x02,0x11,0x02,0x00,0x02,0x24, +0x33,0x00,0x02,0x11,0x03,0x00,0x02,0x24,0x38,0x00,0x02,0x11,0x00,0x00,0x00,0x00, +0x3b,0x00,0x0a,0x11,0x00,0x00,0x00,0x00,0x68,0x51,0xe2,0x8c,0x21,0x18,0x33,0x01, +0x90,0x44,0x64,0x90,0x02,0x11,0x02,0x00,0x2b,0x10,0x44,0x00,0x3e,0x00,0x40,0x14, +0x00,0x00,0x00,0x00,0x5c,0x51,0xe3,0x8c,0x80,0x10,0x09,0x00,0x21,0x10,0x49,0x00, +0x01,0x00,0x63,0x24,0x21,0x10,0x53,0x00,0x5c,0x51,0xe3,0xac,0x21,0x10,0x48,0x00, +0x34,0x43,0x44,0x90,0x44,0x51,0xe3,0x8c,0x00,0x00,0x00,0x00,0x21,0x18,0x64,0x00, +0x44,0x51,0xe3,0xac,0xfc,0x64,0x42,0x8e,0x10,0x00,0x31,0x26,0x2b,0x10,0x22,0x02, +0xab,0xff,0x40,0x14,0x21,0x80,0x40,0x02,0x24,0x00,0xbf,0x8f,0x20,0x00,0xb4,0x8f, +0x1c,0x00,0xb3,0x8f,0x18,0x00,0xb2,0x8f,0x14,0x00,0xb1,0x8f,0x10,0x00,0xb0,0x8f, +0x08,0x00,0xe0,0x03,0x28,0x00,0xbd,0x27,0x48,0x51,0xe2,0x8c,0x00,0x00,0x00,0x00, +0x01,0x00,0x42,0x24,0x48,0x51,0xe2,0xac,0x01,0x00,0x02,0x24,0xd4,0xff,0x02,0x15, +0x02,0x00,0x02,0x24,0x4c,0x51,0xe2,0x8c,0x00,0x00,0x00,0x00,0x01,0x00,0x42,0x24, +0x4c,0x51,0xe2,0xac,0x02,0x00,0x02,0x24,0xcf,0xff,0x02,0x15,0x03,0x00,0x02,0x24, +0x50,0x51,0xe2,0x8c,0x00,0x00,0x00,0x00,0x01,0x00,0x42,0x24,0x50,0x51,0xe2,0xac, +0x03,0x00,0x02,0x24,0xca,0xff,0x02,0x15,0x00,0x00,0x00,0x00,0x54,0x51,0xe2,0x8c, +0x00,0x00,0x00,0x00,0x01,0x00,0x42,0x24,0xc7,0xff,0x0a,0x15,0x54,0x51,0xe2,0xac, +0x58,0x51,0xe2,0x8c,0x21,0x18,0x33,0x01,0x01,0x00,0x42,0x24,0x58,0x51,0xe2,0xac, +0x68,0x51,0xe2,0x8c,0x90,0x44,0x64,0x90,0x02,0x11,0x02,0x00,0x2b,0x10,0x44,0x00, +0xc4,0xff,0x40,0x10,0x00,0x00,0x00,0x00,0x60,0x51,0xe3,0x8c,0x80,0x10,0x09,0x00, +0x21,0x10,0x49,0x00,0x01,0x00,0x63,0x24,0x21,0x10,0x53,0x00,0x60,0x51,0xe3,0xac, +0x21,0x10,0x48,0x00,0xc5,0x43,0x44,0x90,0x44,0x51,0xe3,0x8c,0x00,0x00,0x00,0x00, +0x21,0x18,0x64,0x00,0xf9,0x10,0x00,0x08,0x44,0x51,0xe3,0xac,0x25,0xb0,0x02,0x3c, +0x25,0xb0,0x05,0x3c,0x02,0x80,0x03,0x3c,0x58,0x00,0x4a,0x34,0x5c,0x00,0x4b,0x34, +0x4c,0x00,0xa2,0x34,0x00,0x00,0x44,0x90,0x68,0x15,0x66,0x24,0xed,0x4a,0xc2,0x90, +0x29,0xb0,0x07,0x3c,0x03,0x00,0x84,0x30,0x21,0x18,0xc0,0x00,0x0f,0x00,0x44,0x10, +0x04,0x00,0xe8,0x34,0x07,0x00,0x80,0x14,0x58,0x0c,0xa9,0x34,0xe6,0x42,0xc2,0x90, +0x1c,0x00,0x06,0x24,0x03,0x00,0x40,0x14,0x50,0x0c,0xa5,0x34,0x00,0x00,0xa6,0xa0, +0x00,0x00,0x26,0xa1,0x00,0x00,0x42,0x8d,0xed,0x4a,0x64,0xa0,0x00,0x00,0xe2,0xac, +0x00,0x00,0x62,0x8d,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0xad,0x08,0x00,0xe0,0x03, +0x21,0x10,0x00,0x00,0x25,0xb0,0x0d,0x3c,0xe8,0xff,0xbd,0x27,0x10,0x00,0xbf,0xaf, +0x2d,0x0a,0xa7,0x35,0xa2,0x0d,0xa2,0x35,0xa4,0x0d,0xa3,0x35,0xa6,0x0d,0xa4,0x35, +0xa8,0x0d,0xa5,0x35,0x00,0x00,0x48,0x94,0x00,0x00,0x69,0x94,0x00,0x00,0x8a,0x94, +0x00,0x00,0xab,0x94,0x00,0x00,0xe3,0x90,0x5b,0x0a,0xa4,0x35,0x5c,0x0a,0xa6,0x35, +0x00,0x2e,0x03,0x00,0x03,0x2e,0x05,0x00,0x40,0x00,0xa2,0x34,0x00,0x00,0xe2,0xa0, +0x00,0x00,0x85,0x90,0x00,0x00,0xc3,0x90,0x02,0x80,0x0e,0x3c,0x68,0x15,0xcc,0x25, +0xff,0xff,0x22,0x31,0xff,0x00,0xa5,0x30,0xff,0xff,0x04,0x31,0x21,0x20,0x82,0x00, +0xff,0x00,0x63,0x30,0x00,0x40,0x87,0x8d,0x00,0x2a,0x05,0x00,0xff,0xff,0x46,0x31, +0x21,0x28,0xa3,0x00,0xff,0xff,0x62,0x31,0x21,0x20,0x86,0x00,0x21,0x20,0x82,0x00, +0xff,0xff,0xa3,0x30,0x64,0x0c,0xa2,0x35,0x00,0x00,0x45,0xa4,0x21,0x20,0x83,0x00, +0x0f,0x00,0xe7,0x30,0x01,0x00,0x02,0x24,0xe0,0x42,0x84,0xad,0xd8,0x42,0x88,0xa5, +0xda,0x42,0x89,0xa5,0xdc,0x42,0x8a,0xa5,0xde,0x42,0x8b,0xa5,0x07,0x00,0xe2,0x10, +0xe4,0x42,0x85,0xa5,0xa8,0x56,0x00,0x0c,0x00,0x00,0x00,0x00,0x10,0x00,0xbf,0x8f, +0x21,0x10,0x00,0x00,0x08,0x00,0xe0,0x03,0x18,0x00,0xbd,0x27,0x4c,0x00,0xa3,0x35, +0x00,0x00,0x62,0x90,0x00,0x00,0x00,0x00,0x03,0x00,0x42,0x30,0x67,0x00,0x47,0x10, +0x68,0x15,0xc4,0x25,0xe6,0x42,0x82,0x90,0x00,0x00,0x00,0x00,0x2d,0x00,0x40,0x10, +0x01,0x00,0x03,0x24,0x68,0x15,0xc5,0x25,0xe6,0x42,0xa3,0x90,0xff,0x00,0x02,0x24, +0xec,0xff,0x62,0x14,0x25,0xb0,0x03,0x3c,0xc8,0x42,0xa2,0x94,0xe0,0x42,0xa6,0x8c, +0x50,0x0c,0x63,0x34,0x00,0x00,0x64,0x90,0x2b,0x10,0xc2,0x00,0x5e,0x00,0x40,0x14, +0x7f,0x00,0x84,0x30,0xca,0x42,0xa2,0x94,0x00,0x00,0x00,0x00,0x2b,0x10,0xc2,0x00, +0x09,0x00,0x40,0x14,0x00,0x00,0x00,0x00,0xcc,0x42,0xa2,0x94,0x00,0x00,0x00,0x00, +0x2b,0x10,0xc2,0x00,0x02,0x00,0x40,0x10,0x02,0x00,0x82,0x24,0x01,0x00,0x82,0x24, +0xff,0x00,0x44,0x30,0x68,0x15,0xc5,0x25,0xd0,0x42,0xa3,0x90,0x00,0x00,0x00,0x00, +0x2b,0x10,0x64,0x00,0x4e,0x00,0x40,0x10,0x00,0x00,0x00,0x00,0x21,0x20,0x60,0x00, +0x68,0x15,0xc3,0x25,0xe0,0x42,0x62,0x8c,0x00,0x00,0x00,0x00,0xe9,0x03,0x42,0x2c, +0x02,0x00,0x40,0x14,0x25,0xb0,0x02,0x3c,0xd0,0x42,0x64,0x90,0x58,0x0c,0x43,0x34, +0x50,0x0c,0x42,0x34,0x00,0x00,0x44,0xa0,0x00,0x00,0x64,0xa0,0x85,0x11,0x00,0x08, +0x00,0x00,0x00,0x00,0x00,0x40,0x82,0x8c,0x00,0x00,0x00,0x00,0x02,0x12,0x02,0x00, +0x0f,0x00,0x42,0x30,0xd0,0xff,0x43,0x14,0x68,0x15,0xc5,0x25,0x25,0xb0,0x02,0x3c, +0x4c,0x00,0x42,0x34,0x00,0x00,0x43,0x90,0x00,0x00,0x00,0x00,0x03,0x00,0x63,0x30, +0xb8,0xff,0x60,0x10,0xff,0xff,0x02,0x34,0xdc,0x63,0x83,0x8c,0x00,0x00,0x00,0x00, +0xb4,0xff,0x62,0x10,0x00,0x00,0x00,0x00,0xe0,0x42,0x83,0x8c,0x00,0x00,0x00,0x00, +0x65,0x00,0x62,0x2c,0x3b,0x00,0x40,0x14,0x28,0x00,0x62,0x2c,0xd2,0x42,0x83,0x90, +0x00,0x00,0x00,0x00,0x00,0x16,0x03,0x00,0x03,0x16,0x02,0x00,0xfe,0xff,0x42,0x24, +0xfc,0xff,0x42,0x28,0x02,0x00,0x40,0x10,0xfe,0xff,0x62,0x24,0xfc,0xff,0x02,0x24, +0xd2,0x42,0x82,0xa0,0x68,0x15,0xc4,0x25,0xdc,0x63,0x82,0x8c,0xd2,0x42,0x83,0x90, +0xce,0x42,0x86,0x90,0x02,0x11,0x02,0x00,0x7f,0x00,0x42,0x30,0x0a,0x00,0x45,0x24, +0x23,0x18,0xa3,0x00,0x00,0x2e,0x03,0x00,0x03,0x2e,0x05,0x00,0xff,0x00,0xc2,0x30, +0x2a,0x10,0x45,0x00,0x17,0x00,0x40,0x10,0x25,0xb0,0x02,0x3c,0x00,0x2e,0x06,0x00, +0x03,0x2e,0x05,0x00,0x58,0x0c,0x43,0x34,0x50,0x0c,0x42,0x34,0x00,0x00,0x45,0xa0, +0x00,0x00,0x65,0xa0,0x85,0x11,0x00,0x08,0x00,0x00,0x00,0x00,0xe6,0x42,0x82,0x91, +0x00,0x00,0x00,0x00,0x97,0xff,0x40,0x14,0x00,0x00,0x00,0x00,0xff,0xff,0x02,0x24, +0x91,0x11,0x00,0x08,0xe6,0x42,0x82,0xa1,0xac,0x11,0x00,0x08,0xff,0xff,0x82,0x24, +0xd1,0x42,0xa3,0x90,0x00,0x00,0x00,0x00,0x2b,0x10,0x83,0x00,0xb4,0x11,0x00,0x08, +0x0b,0x20,0x62,0x00,0xcf,0x42,0x83,0x80,0x00,0x00,0x00,0x00,0xff,0x00,0x62,0x30, +0x2a,0x10,0xa2,0x00,0x0b,0x28,0x62,0x00,0x25,0xb0,0x02,0x3c,0x58,0x0c,0x43,0x34, +0x50,0x0c,0x42,0x34,0x00,0x00,0x45,0xa0,0x00,0x00,0x65,0xa0,0x85,0x11,0x00,0x08, +0x00,0x00,0x00,0x00,0xcf,0xff,0x40,0x10,0x00,0x00,0x00,0x00,0xd2,0x42,0x83,0x90, +0x00,0x00,0x00,0x00,0x00,0x16,0x03,0x00,0x03,0x16,0x02,0x00,0x02,0x00,0x42,0x24, +0x0d,0x00,0x42,0x28,0x03,0x00,0x40,0x14,0x00,0x00,0x00,0x00,0xe0,0x11,0x00,0x08, +0x0c,0x00,0x02,0x24,0xe0,0x11,0x00,0x08,0x02,0x00,0x62,0x24,0xc0,0xff,0xbd,0x27, +0x18,0x00,0xb0,0xaf,0x25,0xb0,0x10,0x3c,0x28,0x00,0xb4,0xaf,0x24,0x00,0xb3,0xaf, +0x1c,0x00,0xb1,0xaf,0x3c,0x00,0xbf,0xaf,0x38,0x00,0xbe,0xaf,0x34,0x00,0xb7,0xaf, +0x30,0x00,0xb6,0xaf,0x2c,0x00,0xb5,0xaf,0x20,0x00,0xb2,0xaf,0xd8,0x00,0x06,0x36, +0x00,0x00,0xc3,0x90,0x02,0x80,0x02,0x3c,0x68,0x15,0x54,0x24,0x2a,0xb0,0x11,0x3c, +0xa0,0xff,0x02,0x24,0x25,0x18,0x62,0x00,0x34,0x00,0x25,0x36,0xfe,0xff,0x02,0x24, +0xbc,0x42,0x92,0x92,0x40,0x00,0x04,0x24,0x00,0x00,0xc3,0xa0,0x00,0x00,0xa2,0xa0, +0xa1,0x4e,0x00,0x0c,0x00,0x96,0x12,0x00,0x21,0x98,0x40,0x00,0x6b,0x00,0x60,0x12, +0x00,0x40,0x02,0x3c,0x08,0x00,0x63,0x8e,0xb0,0x03,0x02,0x36,0x21,0x20,0x60,0x02, +0x00,0x00,0x43,0xac,0x3a,0x45,0x00,0x0c,0x21,0xb8,0x80,0x02,0x01,0x00,0x1e,0x24, +0x42,0x00,0x16,0x36,0x03,0x0c,0x11,0x36,0x17,0x0e,0x15,0x36,0x04,0x00,0x14,0x24, +0x2a,0xb0,0x03,0x3c,0x06,0x00,0x63,0x34,0x00,0x00,0x62,0x94,0x00,0x00,0x00,0x00, +0x00,0xff,0x42,0x30,0x0a,0x00,0x40,0x18,0x00,0x00,0x00,0x00,0x02,0x80,0x04,0x3c, +0xc8,0x94,0x84,0x24,0x00,0x00,0x83,0x8c,0x00,0x00,0x00,0x00,0x00,0x00,0x62,0x94, +0x00,0x00,0x00,0x00,0x00,0xff,0x42,0x30,0xfc,0xff,0x40,0x1c,0x00,0x00,0x00,0x00, +0x08,0x00,0x65,0x8e,0x20,0x10,0x06,0x3c,0x00,0xfe,0xc6,0x34,0x40,0x00,0x07,0x24, +0x01,0x00,0x04,0x24,0x10,0x01,0x00,0x0c,0x10,0x00,0xbe,0xaf,0x4d,0x01,0x00,0x0c, +0x01,0x00,0x04,0x24,0x2a,0xb0,0x02,0x3c,0x05,0x00,0x42,0x34,0xff,0xff,0x03,0x24, +0x00,0x00,0x5e,0xa0,0x00,0x00,0xc3,0xa2,0x00,0x00,0x22,0x92,0xc1,0x42,0xe5,0x92, +0x2a,0xb0,0x04,0x3c,0x02,0x00,0x03,0x24,0x40,0x00,0x42,0x34,0x05,0x00,0x84,0x34, +0x00,0x00,0x22,0xa2,0x00,0x00,0x83,0xa0,0xef,0xff,0x02,0x24,0x00,0x00,0xb0,0x92, +0x64,0x00,0x04,0x24,0x00,0x00,0xa5,0xa2,0x00,0x00,0xc2,0xa2,0xb3,0x0a,0x00,0x0c, +0x00,0x00,0x00,0x00,0x00,0x00,0x22,0x92,0xbf,0xff,0x03,0x24,0x84,0x03,0x04,0x24, +0x24,0x10,0x43,0x00,0x00,0x00,0x22,0xa2,0xb3,0x0a,0x00,0x0c,0xff,0x00,0x10,0x32, +0x25,0xb0,0x02,0x3c,0xf4,0x08,0x42,0x34,0x00,0x00,0x44,0x8c,0x00,0x00,0xb0,0xa2, +0x00,0x00,0xc0,0xa2,0x00,0x00,0x22,0x92,0xbe,0x42,0xe3,0x92,0x1f,0x00,0x85,0x30, +0x40,0x00,0x42,0x34,0x00,0x00,0x22,0xa2,0x00,0x80,0x02,0x3c,0xdf,0x07,0x42,0x34, +0x2b,0x18,0xa3,0x00,0x09,0x00,0x60,0x10,0x24,0x20,0x82,0x00,0xbf,0x42,0xe2,0x92, +0x00,0x00,0x00,0x00,0x2b,0x10,0x45,0x00,0x05,0x00,0x40,0x10,0x02,0x80,0x02,0x3c, +0x01,0x00,0x02,0x3c,0x25,0x10,0xa2,0x00,0x21,0x90,0x42,0x02,0x02,0x80,0x02,0x3c, +0x8e,0x7d,0x43,0x90,0x22,0x00,0x02,0x24,0x1c,0x00,0x62,0x10,0x92,0x00,0x02,0x24, +0x1b,0x00,0x62,0x10,0x02,0x80,0x03,0x3c,0xff,0xff,0x94,0x26,0xb3,0x0a,0x00,0x0c, +0xf4,0x01,0x04,0x24,0xab,0xff,0x81,0x06,0x2a,0xb0,0x03,0x3c,0x04,0x00,0x60,0x12, +0x25,0xb0,0x02,0x3c,0xbd,0x4e,0x00,0x0c,0x21,0x20,0x60,0x02,0x25,0xb0,0x02,0x3c, +0xd8,0x02,0x42,0x34,0x00,0x00,0x52,0xac,0x21,0x10,0x40,0x02,0x3c,0x00,0xbf,0x8f, +0x38,0x00,0xbe,0x8f,0x34,0x00,0xb7,0x8f,0x30,0x00,0xb6,0x8f,0x2c,0x00,0xb5,0x8f, +0x28,0x00,0xb4,0x8f,0x24,0x00,0xb3,0x8f,0x20,0x00,0xb2,0x8f,0x1c,0x00,0xb1,0x8f, +0x18,0x00,0xb0,0x8f,0x08,0x00,0xe0,0x03,0x40,0x00,0xbd,0x27,0x02,0x80,0x03,0x3c, +0x68,0x15,0x63,0x24,0xbe,0x42,0x62,0x90,0xc0,0x07,0x83,0x30,0x82,0x19,0x03,0x00, +0x2b,0x10,0x62,0x00,0xe0,0xff,0x40,0x10,0x02,0x80,0x04,0x3c,0x68,0x15,0x84,0x24, +0xbf,0x42,0x82,0x90,0x00,0x00,0x00,0x00,0x2b,0x10,0x43,0x00,0xda,0xff,0x40,0x10, +0x00,0x12,0x03,0x00,0x10,0x00,0x03,0x3c,0x25,0x10,0x43,0x00,0x9a,0x12,0x00,0x08, +0x21,0x90,0x42,0x02,0xe8,0xff,0xbd,0x27,0x10,0x00,0xb0,0xaf,0x0f,0x00,0x10,0x3c, +0xff,0xff,0x05,0x36,0xf0,0xf8,0x06,0x34,0x14,0x00,0xbf,0xaf,0xba,0x44,0x00,0x0c, +0x15,0x00,0x04,0x24,0xb3,0x0a,0x00,0x0c,0x64,0x00,0x04,0x24,0xff,0xff,0x05,0x36, +0x56,0x30,0x06,0x24,0xba,0x44,0x00,0x0c,0x1a,0x00,0x04,0x24,0xb3,0x0a,0x00,0x0c, +0x64,0x00,0x04,0x24,0x02,0x80,0x0b,0x3c,0x68,0x15,0x64,0x25,0x04,0x43,0x83,0x90, +0x04,0x00,0x02,0x24,0x19,0x00,0x62,0x10,0x25,0xb0,0x02,0x3c,0x14,0x43,0x8a,0x8c, +0x18,0x43,0x88,0x8c,0x25,0xb0,0x02,0x3c,0x1c,0x0e,0x49,0x34,0x00,0x0e,0x43,0x34, +0x04,0x0e,0x44,0x34,0x08,0x0e,0x45,0x34,0x10,0x0e,0x46,0x34,0x14,0x0e,0x47,0x34, +0x18,0x0e,0x42,0x34,0x00,0x00,0x6a,0xac,0x00,0x00,0x8a,0xac,0x00,0x00,0xa8,0xac, +0x00,0x00,0xca,0xac,0x00,0x00,0xea,0xac,0x00,0x00,0x4a,0xac,0x00,0x00,0x2a,0xad, +0x14,0x00,0xbf,0x8f,0x10,0x00,0xb0,0x8f,0x68,0x15,0x63,0x25,0x04,0x00,0x02,0x24, +0x18,0x00,0xbd,0x27,0x08,0x00,0xe0,0x03,0x04,0x43,0x62,0xa0,0x00,0x0e,0x42,0x34, +0x00,0x00,0x43,0x8c,0x14,0x43,0x8a,0x8c,0x00,0x00,0x00,0x00,0xe4,0xff,0x6a,0x14, +0x00,0x00,0x00,0x00,0xec,0x12,0x00,0x08,0x00,0x00,0x00,0x00,0xe8,0xff,0xbd,0x27, +0x10,0x00,0xb0,0xaf,0x0f,0x00,0x10,0x3c,0xff,0xff,0x05,0x36,0xf0,0xf8,0x06,0x34, +0x14,0x00,0xbf,0xaf,0xba,0x44,0x00,0x0c,0x15,0x00,0x04,0x24,0xb3,0x0a,0x00,0x0c, +0x64,0x00,0x04,0x24,0xff,0xff,0x05,0x36,0x56,0x30,0x06,0x24,0xba,0x44,0x00,0x0c, +0x1a,0x00,0x04,0x24,0xb3,0x0a,0x00,0x0c,0x64,0x00,0x04,0x24,0x02,0x80,0x04,0x3c, +0x68,0x15,0x83,0x24,0x04,0x43,0x65,0x90,0x21,0x70,0x60,0x00,0x10,0x10,0x03,0x3c, +0x25,0xb0,0x02,0x3c,0x10,0x10,0x66,0x34,0x01,0x00,0x03,0x24,0x1c,0x0e,0x4d,0x34, +0x00,0x0e,0x4a,0x34,0x04,0x0e,0x4b,0x34,0x08,0x0e,0x4c,0x34,0x10,0x0e,0x47,0x34, +0x14,0x0e,0x48,0x34,0x0f,0x00,0xa3,0x10,0x18,0x0e,0x49,0x34,0x10,0x10,0x02,0x24, +0x00,0x00,0x46,0xad,0x00,0x00,0x66,0xad,0x00,0x00,0x82,0xad,0x00,0x00,0xe6,0xac, +0x00,0x00,0x06,0xad,0x00,0x00,0x26,0xad,0x00,0x00,0xa6,0xad,0x14,0x00,0xbf,0x8f, +0x10,0x00,0xb0,0x8f,0x01,0x00,0x02,0x24,0x18,0x00,0xbd,0x27,0x08,0x00,0xe0,0x03, +0x04,0x43,0xc2,0xa1,0x00,0x00,0x44,0x8d,0x00,0x00,0x00,0x00,0xf0,0xff,0x86,0x14, +0x10,0x10,0x02,0x24,0x23,0x13,0x00,0x08,0x00,0x00,0x00,0x00,0xe0,0xff,0xbd,0x27, +0x14,0x00,0xb1,0xaf,0x10,0x00,0xb0,0xaf,0x01,0x00,0x11,0x3c,0x0f,0x00,0x10,0x3c, +0xff,0xff,0x05,0x36,0xf4,0x98,0x26,0x36,0x18,0x00,0xbf,0xaf,0xba,0x44,0x00,0x0c, +0x15,0x00,0x04,0x24,0xb3,0x0a,0x00,0x0c,0x64,0x00,0x04,0x24,0xff,0xff,0x05,0x36, +0x56,0x30,0x26,0x36,0xba,0x44,0x00,0x0c,0x1a,0x00,0x04,0x24,0x02,0x80,0x10,0x3c, +0xb3,0x0a,0x00,0x0c,0x64,0x00,0x04,0x24,0x68,0x15,0x04,0x26,0x04,0x43,0x82,0x90, +0x00,0x00,0x00,0x00,0x0d,0x00,0x40,0x14,0x25,0xb0,0x02,0x3c,0x00,0x0e,0x42,0x34, +0x00,0x00,0x43,0x8c,0xec,0x42,0x8f,0x8c,0x00,0x00,0x00,0x00,0x08,0x00,0x6f,0x14, +0x68,0x15,0x02,0x26,0x18,0x00,0xbf,0x8f,0x14,0x00,0xb1,0x8f,0x10,0x00,0xb0,0x8f, +0x20,0x00,0xbd,0x27,0x08,0x00,0xe0,0x03,0x04,0x43,0x40,0xa0,0xec,0x42,0x8f,0x8c, +0xe8,0x42,0x88,0x8c,0xf0,0x42,0x8a,0x8c,0xf4,0x42,0x8b,0x8c,0xf8,0x42,0x8c,0x8c, +0xfc,0x42,0x8d,0x8c,0x25,0xb0,0x02,0x3c,0x00,0x43,0x8e,0x8c,0x1c,0x0e,0x49,0x34, +0x08,0x0e,0x43,0x34,0x00,0x0e,0x44,0x34,0x04,0x0e,0x45,0x34,0x10,0x0e,0x46,0x34, +0x14,0x0e,0x47,0x34,0x18,0x0e,0x42,0x34,0x00,0x00,0x68,0xac,0x18,0x00,0xbf,0x8f, +0x00,0x00,0x8f,0xac,0x14,0x00,0xb1,0x8f,0x00,0x00,0xaa,0xac,0x00,0x00,0xcb,0xac, +0x00,0x00,0xec,0xac,0x00,0x00,0x4d,0xac,0x68,0x15,0x02,0x26,0x10,0x00,0xb0,0x8f, +0x20,0x00,0xbd,0x27,0x00,0x00,0x2e,0xad,0x08,0x00,0xe0,0x03,0x04,0x43,0x40,0xa0, +0xe0,0xff,0xbd,0x27,0x14,0x00,0xb1,0xaf,0x10,0x00,0xb0,0xaf,0x01,0x00,0x11,0x3c, +0x0f,0x00,0x10,0x3c,0xff,0xff,0x05,0x36,0xf4,0x98,0x26,0x36,0x18,0x00,0xbf,0xaf, +0xba,0x44,0x00,0x0c,0x15,0x00,0x04,0x24,0xb3,0x0a,0x00,0x0c,0x64,0x00,0x04,0x24, +0xff,0xff,0x05,0x36,0x56,0x30,0x26,0x36,0xba,0x44,0x00,0x0c,0x1a,0x00,0x04,0x24, +0xb3,0x0a,0x00,0x0c,0x64,0x00,0x04,0x24,0x02,0x80,0x18,0x3c,0x68,0x15,0x05,0x27, +0x04,0x43,0xa3,0x90,0x03,0x00,0x02,0x24,0x2a,0x00,0x62,0x10,0x25,0xb0,0x02,0x3c, +0xec,0x42,0xaf,0x8c,0x08,0x43,0xa3,0x8c,0xe8,0x42,0xa2,0x8c,0xf0,0x42,0xac,0x8c, +0xf4,0x42,0xad,0x8c,0xf8,0x42,0xa9,0x8c,0xfc,0x42,0xaa,0x8c,0x00,0x43,0xab,0x8c, +0x21,0x70,0x43,0x00,0xff,0xff,0x02,0x3c,0x25,0xb0,0x03,0x3c,0xff,0x00,0x42,0x34, +0x00,0xff,0xc4,0x31,0x04,0x0e,0x65,0x34,0x10,0x0e,0x66,0x34,0x14,0x0e,0x67,0x34, +0x18,0x0e,0x68,0x34,0x24,0x80,0xc2,0x01,0x08,0x0e,0x71,0x34,0x00,0x0e,0x62,0x34, +0x01,0x3f,0x84,0x2c,0x1c,0x0e,0x63,0x34,0x00,0x00,0x4f,0xac,0x00,0x00,0xac,0xac, +0x00,0x00,0xcd,0xac,0x00,0x00,0xe9,0xac,0x00,0x00,0x0a,0xad,0x00,0x00,0x6b,0xac, +0x0a,0x00,0x80,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x2e,0xae,0x18,0x00,0xbf,0x8f, +0x14,0x00,0xb1,0x8f,0x10,0x00,0xb0,0x8f,0x68,0x15,0x03,0x27,0x03,0x00,0x02,0x24, +0x20,0x00,0xbd,0x27,0x08,0x00,0xe0,0x03,0x04,0x43,0x62,0xa0,0xa6,0x13,0x00,0x08, +0x00,0x3f,0x0e,0x36,0x00,0x0e,0x42,0x34,0x00,0x00,0x43,0x8c,0xec,0x42,0xaf,0x8c, +0x00,0x00,0x00,0x00,0xd3,0xff,0x6f,0x14,0x00,0x00,0x00,0x00,0xa7,0x13,0x00,0x08, +0x00,0x00,0x00,0x00,0xd0,0xff,0xbd,0x27,0x18,0x00,0xb2,0xaf,0x02,0x80,0x12,0x3c, +0x24,0x00,0xb5,0xaf,0x20,0x00,0xb4,0xaf,0x28,0x00,0xbf,0xaf,0x1c,0x00,0xb3,0xaf, +0x14,0x00,0xb1,0xaf,0x10,0x00,0xb0,0xaf,0x68,0x15,0x44,0x26,0x02,0x80,0x14,0x3c, +0x00,0x40,0x85,0x8c,0xdc,0x63,0x83,0x8c,0x8e,0x7d,0x86,0x92,0x25,0xb0,0x02,0x3c, +0x0f,0x0c,0x42,0x34,0x00,0x00,0x46,0xa0,0x02,0x19,0x03,0x00,0xf0,0xf0,0xa5,0x30, +0x00,0x10,0x02,0x24,0x04,0x43,0x93,0x90,0x71,0x00,0xa2,0x10,0x7f,0x00,0x75,0x30, +0x25,0xb0,0x09,0x3c,0x4c,0x00,0x23,0x35,0x00,0x00,0x62,0x90,0x00,0x00,0x00,0x00, +0x03,0x00,0x42,0x30,0x09,0x00,0x40,0x10,0x68,0x15,0x45,0x26,0x68,0x15,0x4a,0x26, +0x00,0x40,0x42,0x8d,0x00,0x00,0x00,0x00,0x02,0x13,0x02,0x00,0x0f,0x00,0x42,0x30, +0x33,0x00,0x40,0x10,0x00,0x0e,0x25,0x35,0x68,0x15,0x45,0x26,0x04,0x43,0xa2,0x8c, +0x00,0x00,0x00,0x00,0x02,0x12,0x02,0x00,0x0f,0x00,0x40,0x14,0x68,0x15,0x4a,0x26, +0x25,0xb0,0x02,0x3c,0x84,0x01,0x42,0x34,0x00,0x00,0x44,0x8c,0x0d,0x00,0x03,0x24, +0x7e,0x00,0x83,0x10,0x3e,0x00,0x02,0x24,0x4a,0x00,0x03,0x24,0x1f,0x43,0xa2,0xa0, +0x1c,0x43,0xa3,0xa0,0x45,0x00,0x02,0x24,0x43,0x00,0x03,0x24,0x1d,0x43,0xa2,0xa0, +0x1e,0x43,0xa3,0xa0,0x68,0x15,0x4a,0x26,0xdc,0x63,0x4c,0x8d,0x04,0x40,0x42,0x8d, +0x00,0x40,0x4b,0x8d,0x1e,0x43,0x4d,0x91,0x1c,0x43,0x4e,0x91,0x25,0xb0,0x09,0x3c, +0x02,0x11,0x02,0x00,0x60,0x0c,0x27,0x35,0x02,0x19,0x0c,0x00,0x98,0x0c,0x24,0x35, +0x00,0x00,0xe3,0xa0,0x66,0x0c,0x25,0x35,0x00,0x00,0x82,0xa0,0x67,0x0c,0x26,0x35, +0xf0,0xf0,0x68,0x31,0x10,0x10,0x02,0x24,0x00,0x00,0xad,0xa0,0x00,0x00,0xce,0xa0, +0x43,0x00,0x02,0x11,0xff,0xff,0x02,0x34,0x28,0x00,0xbf,0x8f,0x24,0x00,0xb5,0x8f, +0x20,0x00,0xb4,0x8f,0x1c,0x00,0xb3,0x8f,0x18,0x00,0xb2,0x8f,0x14,0x00,0xb1,0x8f, +0x10,0x00,0xb0,0x8f,0x21,0x10,0x00,0x00,0x08,0x00,0xe0,0x03,0x30,0x00,0xbd,0x27, +0x00,0x00,0xa2,0x8c,0x00,0x00,0x00,0x00,0x5d,0x00,0x40,0x10,0x10,0x0e,0x28,0x35, +0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40, +0x08,0x0e,0x22,0x35,0x04,0x0e,0x24,0x35,0x00,0x00,0x43,0x8c,0x00,0x00,0xa5,0x8c, +0x00,0x00,0x82,0x8c,0xe8,0x42,0x43,0xad,0xec,0x42,0x45,0xad,0xf0,0x42,0x42,0xad, +0x14,0x0e,0x24,0x35,0x18,0x0e,0x22,0x35,0x1c,0x0e,0x25,0x35,0x00,0x00,0x08,0x8d, +0x8e,0x7d,0x8b,0x92,0x00,0x00,0x86,0x8c,0x00,0xff,0x63,0x30,0x00,0x00,0x47,0x8c, +0x00,0x00,0xa4,0x8c,0x9a,0x0c,0x22,0x35,0x02,0x1a,0x03,0x00,0x00,0x00,0x43,0xa0, +0x22,0x00,0x02,0x24,0xf4,0x42,0x48,0xad,0xf8,0x42,0x46,0xad,0xfc,0x42,0x47,0xad, +0x58,0x00,0x62,0x11,0x00,0x43,0x44,0xad,0x92,0x00,0x02,0x24,0x56,0x00,0x62,0x11, +0x0d,0x08,0x22,0x35,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40, +0x68,0x15,0x44,0x26,0x00,0x40,0x83,0x8c,0xff,0xff,0x02,0x3c,0xff,0x0f,0x42,0x34, +0x24,0x18,0x62,0x00,0x00,0x10,0x63,0x34,0xde,0x13,0x00,0x08,0x00,0x40,0x83,0xac, +0x01,0x00,0x02,0x24,0x35,0x00,0x62,0x12,0x04,0x00,0x02,0x24,0x33,0x00,0x62,0x12, +0x68,0x15,0x43,0x26,0xff,0xff,0x02,0x24,0xd0,0x13,0x00,0x08,0x04,0x43,0x62,0xa0, +0xbd,0xff,0x82,0x11,0x02,0x12,0x0b,0x00,0x0f,0x00,0x48,0x30,0x01,0x00,0x03,0x24, +0xb9,0xff,0x03,0x15,0x4c,0x00,0x23,0x35,0x00,0x00,0x62,0x90,0x00,0x00,0x00,0x00, +0x03,0x00,0x42,0x30,0xb4,0xff,0x40,0x10,0x03,0x00,0x02,0x24,0x5f,0x00,0x62,0x12, +0x04,0x00,0x62,0x2a,0x45,0x00,0x40,0x10,0x00,0x00,0x00,0x00,0x64,0x00,0x60,0x12, +0xff,0x00,0xa2,0x31,0xac,0xff,0x68,0x16,0xff,0x00,0xc2,0x31,0x2b,0x10,0xa2,0x02, +0x52,0x00,0x40,0x10,0x00,0x00,0x00,0x00,0x1f,0x43,0x42,0x91,0x00,0x00,0x00,0x00, +0x2b,0x10,0x55,0x00,0x44,0x00,0x40,0x14,0x00,0x00,0x00,0x00,0x2f,0x13,0x00,0x0c, +0x00,0x00,0x00,0x00,0x06,0x14,0x00,0x08,0x00,0x00,0x00,0x00,0x3b,0x00,0x02,0x24, +0x46,0x00,0x03,0x24,0x1f,0x43,0xa2,0xa0,0x1c,0x43,0xa3,0xa0,0x41,0x00,0x02,0x24, +0x40,0x00,0x03,0x24,0x1d,0x43,0xa2,0xa0,0xf1,0x13,0x00,0x08,0x1e,0x43,0xa3,0xa0, +0x00,0x00,0x03,0x8d,0x3f,0x3f,0x02,0x3c,0x3f,0x3f,0x42,0x34,0xa0,0xff,0x62,0x14, +0x00,0x00,0x00,0x00,0xdf,0x13,0x00,0x08,0x68,0x15,0x45,0x26,0x0f,0x00,0x10,0x3c, +0x01,0x00,0x11,0x3c,0xff,0xff,0x05,0x36,0xf4,0x98,0x26,0x36,0xba,0x44,0x00,0x0c, +0x15,0x00,0x04,0x24,0xb3,0x0a,0x00,0x0c,0x64,0x00,0x04,0x24,0xff,0xff,0x05,0x36, +0x56,0x30,0x26,0x36,0xba,0x44,0x00,0x0c,0x1a,0x00,0x04,0x24,0xb3,0x0a,0x00,0x0c, +0x64,0x00,0x04,0x24,0x68,0x15,0x43,0x26,0xff,0xff,0x02,0x24,0xd0,0x13,0x00,0x08, +0x04,0x43,0x62,0xa0,0x0d,0x08,0x22,0x35,0x00,0x00,0x43,0x90,0x00,0x00,0x00,0x00, +0x0f,0x00,0x63,0x30,0x08,0x00,0x62,0x2c,0x0f,0x00,0x63,0x38,0xa5,0xff,0x40,0x14, +0x01,0x00,0x65,0x24,0x00,0x16,0x05,0x00,0x00,0x24,0x05,0x00,0x00,0x1a,0x05,0x00, +0x25,0x10,0x44,0x00,0x25,0x10,0x43,0x00,0x25,0x10,0x45,0x00,0x25,0x18,0x65,0x00, +0x18,0x43,0x43,0xad,0x35,0x14,0x00,0x08,0x14,0x43,0x42,0xad,0x04,0x00,0x02,0x24, +0x0d,0x00,0x62,0x12,0xff,0x00,0x02,0x24,0x67,0xff,0x62,0x16,0xff,0x00,0xa2,0x31, +0x2b,0x10,0xa2,0x02,0x1d,0x00,0x40,0x14,0xff,0x00,0xc2,0x31,0x2b,0x10,0xa2,0x02, +0x0a,0x00,0x40,0x10,0x00,0x00,0x00,0x00,0xfb,0x12,0x00,0x0c,0x00,0x00,0x00,0x00, +0x06,0x14,0x00,0x08,0x00,0x00,0x00,0x00,0x1d,0x43,0x42,0x91,0x00,0x00,0x00,0x00, +0x2b,0x10,0x55,0x00,0xf8,0xff,0x40,0x10,0x00,0x00,0x00,0x00,0xc5,0x12,0x00,0x0c, +0x00,0x00,0x00,0x00,0x06,0x14,0x00,0x08,0x00,0x00,0x00,0x00,0x20,0x43,0x42,0x91, +0x00,0x00,0x00,0x00,0x2b,0x10,0xa2,0x02,0xac,0xff,0x40,0x10,0x00,0x00,0x00,0x00, +0x70,0x13,0x00,0x0c,0x00,0x00,0x00,0x00,0x06,0x14,0x00,0x08,0x00,0x00,0x00,0x00, +0x2b,0x10,0xa2,0x02,0xe8,0xff,0x40,0x10,0x00,0x00,0x00,0x00,0x21,0x43,0x42,0x91, +0x00,0x00,0x00,0x00,0x2b,0x10,0x55,0x00,0xa0,0xff,0x40,0x14,0x00,0x00,0x00,0x00, +0x70,0x13,0x00,0x0c,0x00,0x00,0x00,0x00,0x06,0x14,0x00,0x08,0x00,0x00,0x00,0x00, +0x02,0x80,0x08,0x3c,0x68,0x15,0x05,0x25,0xdc,0x63,0xa4,0x8c,0xe6,0x42,0xa3,0x90, +0x02,0x11,0x04,0x00,0x1f,0x00,0x60,0x14,0x7f,0x00,0x46,0x30,0x25,0xb0,0x07,0x3c, +0x4c,0x00,0xe2,0x34,0x00,0x00,0x43,0x90,0x00,0x00,0x00,0x00,0x19,0x00,0x60,0x10, +0x00,0x00,0x00,0x00,0xff,0xff,0x02,0x34,0x16,0x00,0x82,0x10,0x00,0x00,0x00,0x00, +0x00,0x08,0xe3,0x34,0x00,0x00,0x62,0x90,0x00,0x00,0x00,0x00,0x01,0x00,0x42,0x30, +0x12,0x00,0x40,0x10,0x4b,0x00,0xc2,0x2c,0x29,0x00,0x40,0x10,0x01,0x00,0x04,0x24, +0xd8,0xff,0xc2,0x24,0x1e,0x00,0x42,0x2c,0x2f,0x00,0x40,0x10,0x23,0x00,0xc2,0x2c, +0x68,0x15,0x04,0x25,0xd3,0x42,0x82,0x90,0x00,0x00,0x00,0x00,0x29,0x00,0x40,0x10, +0x25,0xb0,0x02,0x3c,0x20,0x00,0x03,0x24,0x87,0x0c,0x42,0x34,0x00,0x00,0x43,0xa0, +0xd3,0x42,0x80,0xa0,0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,0x0f,0x00,0x40,0x10, +0x01,0x00,0x04,0x24,0xd8,0xff,0xc2,0x24,0x1e,0x00,0x42,0x2c,0x2c,0x00,0x40,0x10, +0x23,0x00,0xc2,0x2c,0x68,0x15,0x04,0x25,0xd3,0x42,0x82,0x90,0x00,0x00,0x00,0x00, +0x26,0x00,0x40,0x10,0x25,0xb0,0x02,0x3c,0x44,0x00,0x03,0x24,0x30,0x0c,0x42,0x34, +0x00,0x00,0x43,0xa0,0xed,0x14,0x00,0x08,0xd3,0x42,0x80,0xa0,0xd3,0x42,0xa2,0x90, +0x00,0x00,0x00,0x00,0xef,0xff,0x44,0x10,0x30,0x0c,0xe3,0x34,0x43,0x00,0x02,0x24, +0xd3,0x42,0xa4,0xa0,0x00,0x00,0x62,0xa0,0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00, +0xd3,0x42,0xa2,0x90,0x00,0x00,0x00,0x00,0xd5,0xff,0x44,0x10,0x87,0x0c,0xe3,0x34, +0x10,0x00,0x02,0x24,0xd3,0x42,0xa4,0xa0,0x00,0x00,0x62,0xa0,0x06,0x15,0x00,0x08, +0x00,0x00,0x00,0x00,0x23,0x00,0xc2,0x2c,0xda,0xff,0x40,0x10,0x00,0x00,0x00,0x00, +0x68,0x15,0x04,0x25,0xd3,0x42,0x82,0x90,0x02,0x00,0x03,0x24,0xd5,0xff,0x43,0x10, +0x00,0x00,0x00,0x00,0x25,0xb0,0x02,0x3c,0x87,0x0c,0x42,0x34,0xd3,0x42,0x83,0xa0, +0x00,0x00,0x40,0xa0,0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,0x23,0x00,0xc2,0x2c, +0xcc,0xff,0x40,0x10,0x00,0x00,0x00,0x00,0x68,0x15,0x04,0x25,0xd3,0x42,0x82,0x90, +0x02,0x00,0x03,0x24,0xc7,0xff,0x43,0x10,0x00,0x00,0x00,0x00,0x25,0xb0,0x02,0x3c, +0xd3,0x42,0x83,0xa0,0x30,0x0c,0x42,0x34,0x42,0x00,0x03,0x24,0x00,0x00,0x43,0xa0, +0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,0x02,0x80,0x02,0x3c,0x68,0x15,0x45,0x24, +0xd5,0x42,0xa3,0x90,0x02,0x00,0x02,0x24,0x03,0x00,0x62,0x10,0x00,0x00,0x00,0x00, +0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,0xdc,0x63,0xa2,0x8c,0x25,0xb0,0x03,0x3c, +0x0a,0x0a,0x68,0x34,0x02,0x11,0x02,0x00,0x7f,0x00,0x42,0x30,0x1a,0x00,0x44,0x2c, +0x14,0x00,0x42,0x2c,0x01,0x0a,0x66,0x34,0x0b,0x00,0x40,0x14,0x2e,0x0a,0x67,0x34, +0xf3,0xff,0x80,0x14,0x00,0x00,0x00,0x00,0xd4,0x42,0xa4,0x90,0x01,0x00,0x02,0x24, +0x01,0x0a,0x67,0x34,0x0f,0x00,0x82,0x10,0x2e,0x0a,0x66,0x34,0xd4,0x42,0xa0,0xa0, +0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,0x40,0x00,0x02,0x24,0x00,0x00,0xc2,0xa0, +0x01,0x00,0x03,0x24,0xdf,0xff,0x02,0x24,0xd4,0x42,0xa3,0xa0,0x00,0x00,0xe2,0xa0, +0x03,0x00,0x03,0x24,0x21,0x10,0x00,0x00,0x00,0x00,0x03,0xa1,0x08,0x00,0xe0,0x03, +0x00,0x00,0x00,0x00,0x47,0x00,0x02,0x24,0x00,0x00,0xe2,0xa0,0xd3,0xff,0x03,0x24, +0x83,0xff,0x02,0x24,0x00,0x00,0xc3,0xa0,0x00,0x00,0x02,0xa1,0x48,0x15,0x00,0x08, +0xd4,0x42,0xa0,0xa0,0xd0,0xff,0xbd,0x27,0x1c,0x00,0xb1,0xaf,0x28,0x00,0xbf,0xaf, +0x24,0x00,0xb3,0xaf,0x20,0x00,0xb2,0xaf,0x18,0x00,0xb0,0xaf,0xff,0xff,0x11,0x24, +0x02,0x80,0x13,0x3c,0x41,0xb0,0x02,0x3c,0x68,0x15,0x66,0x26,0x04,0x00,0x42,0x34, +0x00,0x00,0x47,0x8c,0x00,0x4b,0xc5,0x8c,0x02,0x80,0x03,0x3c,0x96,0x7d,0x64,0x90, +0xfc,0x4a,0xc8,0x8c,0x02,0x80,0x02,0x3c,0xb8,0x7d,0x49,0x90,0x25,0xb0,0x0a,0x3c, +0x25,0x90,0xa7,0x00,0xb0,0x03,0x42,0x35,0x00,0x00,0x52,0xac,0x00,0x24,0x04,0x00, +0x00,0x00,0x48,0xac,0x84,0x02,0x43,0x35,0x8c,0x02,0x45,0x35,0x01,0x00,0x02,0x24, +0x00,0x00,0x72,0xac,0x00,0x00,0xa4,0xac,0xb9,0x04,0x22,0x11,0x00,0x4b,0xd2,0xac, +0x68,0x15,0x66,0x26,0xfc,0x4a,0xc2,0x8c,0x00,0x00,0x00,0x00,0x24,0x28,0x52,0x00, +0x01,0x00,0xa3,0x30,0x09,0x00,0x60,0x10,0x04,0x00,0xa2,0x30,0x00,0x4b,0xc2,0x8c, +0x25,0xb0,0x03,0x3c,0x01,0x00,0x04,0x24,0x01,0x00,0x42,0x38,0xb0,0x03,0x63,0x34, +0x00,0x00,0x64,0xac,0x00,0x4b,0xc2,0xac,0x04,0x00,0xa2,0x30,0x09,0x00,0x40,0x10, +0x08,0x00,0xa2,0x30,0x00,0x4b,0xc2,0x8c,0x25,0xb0,0x03,0x3c,0x04,0x00,0x04,0x24, +0x04,0x00,0x42,0x38,0xb0,0x03,0x63,0x34,0x00,0x00,0x64,0xac,0x00,0x4b,0xc2,0xac, +0x08,0x00,0xa2,0x30,0x0e,0x00,0x40,0x10,0x68,0x15,0x64,0x26,0xc9,0x64,0xc2,0x90, +0x00,0x00,0x00,0x00,0x05,0x00,0x40,0x18,0x2a,0xb0,0x02,0x3c,0x02,0x00,0x03,0x24, +0x01,0x00,0x42,0x34,0x00,0x00,0x43,0xa0,0xc9,0x64,0xc0,0xa0,0x00,0x4b,0xc2,0x8c, +0x00,0x00,0x00,0x00,0x08,0x00,0x42,0x38,0x00,0x4b,0xc2,0xac,0x68,0x15,0x64,0x26, +0xfc,0x4a,0x82,0x8c,0x00,0x00,0x00,0x00,0x24,0x10,0x52,0x00,0x10,0x00,0x42,0x30, +0x0d,0x00,0x40,0x10,0x00,0x00,0x00,0x00,0xc9,0x64,0x82,0x90,0x00,0x00,0x00,0x00, +0x05,0x00,0x40,0x18,0x2a,0xb0,0x02,0x3c,0x02,0x00,0x03,0x24,0x01,0x00,0x42,0x34, +0x00,0x00,0x43,0xa0,0xc9,0x64,0x80,0xa0,0x00,0x4b,0x82,0x8c,0x00,0x00,0x00,0x00, +0x10,0x00,0x42,0x38,0x00,0x4b,0x82,0xac,0x68,0x15,0x64,0x26,0xfc,0x4a,0x82,0x8c, +0x00,0x00,0x00,0x00,0x24,0x10,0x52,0x00,0x20,0x00,0x42,0x30,0x0e,0x00,0x40,0x10, +0x00,0x00,0x00,0x00,0xc9,0x64,0x82,0x90,0x00,0x00,0x00,0x00,0x05,0x00,0x40,0x18, +0x2a,0xb0,0x02,0x3c,0x02,0x00,0x03,0x24,0x01,0x00,0x42,0x34,0x00,0x00,0x43,0xa0, +0xc9,0x64,0x80,0xa0,0x00,0x4b,0x82,0x8c,0x00,0x00,0x00,0x00,0x20,0x00,0x42,0x38, +0x00,0x4b,0x82,0xac,0x68,0x15,0x64,0x26,0xfc,0x4a,0x82,0x8c,0x00,0x00,0x00,0x00, +0x24,0x10,0x52,0x00,0x40,0x00,0x42,0x30,0x0d,0x00,0x40,0x10,0x00,0x00,0x00,0x00, +0xc9,0x64,0x82,0x90,0x00,0x00,0x00,0x00,0x05,0x00,0x40,0x18,0x2a,0xb0,0x02,0x3c, +0x02,0x00,0x03,0x24,0x01,0x00,0x42,0x34,0x00,0x00,0x43,0xa0,0xc9,0x64,0x80,0xa0, +0x00,0x4b,0x82,0x8c,0x00,0x00,0x00,0x00,0x40,0x00,0x42,0x38,0x00,0x4b,0x82,0xac, +0x68,0x15,0x64,0x26,0xfc,0x4a,0x82,0x8c,0x00,0x00,0x00,0x00,0x24,0x10,0x52,0x00, +0x80,0x00,0x42,0x30,0x0e,0x00,0x40,0x10,0x00,0x00,0x00,0x00,0xc9,0x64,0x82,0x90, +0x00,0x00,0x00,0x00,0x05,0x00,0x40,0x18,0x2a,0xb0,0x02,0x3c,0x02,0x00,0x03,0x24, +0x01,0x00,0x42,0x34,0x00,0x00,0x43,0xa0,0xc9,0x64,0x80,0xa0,0x00,0x4b,0x82,0x8c, +0x00,0x00,0x00,0x00,0x80,0x00,0x42,0x38,0x00,0x4b,0x82,0xac,0x68,0x15,0x64,0x26, +0xfc,0x4a,0x82,0x8c,0x00,0x00,0x00,0x00,0x24,0x10,0x52,0x00,0x00,0x01,0x42,0x30, +0x0d,0x00,0x40,0x10,0x00,0x00,0x00,0x00,0xc9,0x64,0x82,0x90,0x00,0x00,0x00,0x00, +0x05,0x00,0x40,0x18,0x2a,0xb0,0x02,0x3c,0x02,0x00,0x03,0x24,0x01,0x00,0x42,0x34, +0x00,0x00,0x43,0xa0,0xc9,0x64,0x80,0xa0,0x00,0x4b,0x82,0x8c,0x00,0x00,0x00,0x00, +0x00,0x01,0x42,0x38,0x00,0x4b,0x82,0xac,0x68,0x15,0x64,0x26,0xfc,0x4a,0x82,0x8c, +0x00,0x00,0x00,0x00,0x24,0x10,0x52,0x00,0x00,0x02,0x42,0x30,0x0e,0x00,0x40,0x10, +0x00,0x00,0x00,0x00,0xc9,0x64,0x82,0x90,0x00,0x00,0x00,0x00,0x05,0x00,0x40,0x18, +0x2a,0xb0,0x02,0x3c,0x02,0x00,0x03,0x24,0x01,0x00,0x42,0x34,0x00,0x00,0x43,0xa0, +0xc9,0x64,0x80,0xa0,0x00,0x4b,0x82,0x8c,0x00,0x00,0x00,0x00,0x00,0x02,0x42,0x38, +0x00,0x4b,0x82,0xac,0x68,0x15,0x64,0x26,0xfc,0x4a,0x82,0x8c,0x00,0x00,0x00,0x00, +0x24,0x10,0x52,0x00,0x00,0x04,0x42,0x30,0x0d,0x00,0x40,0x10,0x00,0x00,0x00,0x00, +0xc9,0x64,0x82,0x90,0x00,0x00,0x00,0x00,0x05,0x00,0x40,0x18,0x2a,0xb0,0x02,0x3c, +0x02,0x00,0x03,0x24,0x01,0x00,0x42,0x34,0x00,0x00,0x43,0xa0,0xc9,0x64,0x80,0xa0, +0x00,0x4b,0x82,0x8c,0x00,0x00,0x00,0x00,0x00,0x04,0x42,0x38,0x00,0x4b,0x82,0xac, +0x68,0x15,0x63,0x26,0xfc,0x4a,0x62,0x8c,0x00,0x00,0x00,0x00,0x24,0x10,0x52,0x00, +0x00,0x08,0x42,0x30,0x3a,0x00,0x40,0x10,0x2a,0xb0,0x05,0x3c,0x00,0x00,0xa8,0x8c, +0xff,0x00,0x02,0x24,0xff,0x00,0x04,0x31,0x31,0x00,0x82,0x10,0x00,0x80,0x02,0x31, +0x08,0x04,0x40,0x14,0x00,0x80,0x02,0x3c,0x00,0xff,0x02,0x3c,0x24,0x10,0x02,0x01, +0x05,0x00,0x40,0x14,0x00,0x00,0x00,0x00,0xc9,0x64,0x62,0x90,0x00,0x00,0x00,0x00, +0x0b,0x00,0x40,0x18,0xff,0x00,0x02,0x24,0x08,0x64,0x62,0x90,0x20,0xb0,0x03,0x3c, +0x00,0x12,0x02,0x00,0x21,0x10,0x43,0x00,0x0c,0x00,0x48,0x8c,0x25,0xb0,0x03,0x3c, +0xb0,0x03,0x63,0x34,0x00,0x00,0x68,0xac,0xff,0x00,0x04,0x31,0xff,0x00,0x02,0x24, +0x1a,0x00,0x82,0x10,0x68,0x15,0x70,0x26,0xff,0x00,0x03,0x31,0xc0,0x64,0x05,0x8e, +0x20,0x10,0x02,0x3c,0x00,0x1a,0x03,0x00,0x21,0x18,0x62,0x00,0x21,0x30,0x60,0x00, +0x54,0x64,0x03,0xae,0x21,0x20,0x00,0x00,0x08,0x64,0x08,0xa2,0x20,0x00,0x07,0x24, +0x10,0x01,0x00,0x0c,0x10,0x00,0xa0,0xaf,0xfc,0x4a,0x05,0x8e,0x02,0x80,0x06,0x3c, +0x6c,0x7e,0xc4,0x8c,0xff,0xc7,0x02,0x24,0x24,0x28,0xa2,0x00,0x25,0xb0,0x02,0x3c, +0x04,0x00,0x84,0x34,0x80,0x03,0x42,0x34,0x41,0xb0,0x03,0x3c,0x00,0x00,0x44,0xac, +0x00,0x00,0x65,0xac,0x6c,0x7e,0xc4,0xac,0xfc,0x4a,0x05,0xae,0x68,0x15,0x63,0x26, +0x00,0x4b,0x62,0x8c,0x00,0x00,0x00,0x00,0x00,0x08,0x42,0x38,0x00,0x4b,0x62,0xac, +0x68,0x15,0x65,0x26,0xfc,0x4a,0xa2,0x8c,0x00,0x00,0x00,0x00,0x24,0x10,0x52,0x00, +0x00,0x10,0x42,0x30,0x38,0x00,0x40,0x10,0x2a,0xb0,0x02,0x3c,0x08,0x00,0x43,0x34, +0x00,0x00,0x68,0x8c,0xff,0x00,0x02,0x24,0xff,0x00,0x04,0x31,0x2c,0x00,0x82,0x10, +0x00,0x80,0x02,0x31,0xca,0x03,0x40,0x14,0x00,0x80,0x02,0x3c,0x00,0xff,0x02,0x3c, +0x24,0x10,0x02,0x01,0x0b,0x00,0x40,0x10,0xff,0x00,0x02,0x24,0x10,0x64,0xa2,0x90, +0x20,0xb0,0x03,0x3c,0x00,0x12,0x02,0x00,0x21,0x10,0x43,0x00,0x0c,0x00,0x48,0x8c, +0x25,0xb0,0x03,0x3c,0xb0,0x03,0x63,0x34,0x00,0x00,0x68,0xac,0xff,0x00,0x04,0x31, +0xff,0x00,0x02,0x24,0x1a,0x00,0x82,0x10,0x68,0x15,0x70,0x26,0xff,0x00,0x03,0x31, +0xd8,0x64,0x05,0x8e,0x20,0x10,0x02,0x3c,0x00,0x1a,0x03,0x00,0x21,0x18,0x62,0x00, +0x21,0x30,0x60,0x00,0x6c,0x64,0x03,0xae,0x01,0x00,0x04,0x24,0x10,0x64,0x08,0xa2, +0x20,0x00,0x07,0x24,0x10,0x01,0x00,0x0c,0x10,0x00,0xa0,0xaf,0xfc,0x4a,0x05,0x8e, +0x02,0x80,0x06,0x3c,0x6c,0x7e,0xc4,0x8c,0xff,0xc7,0x02,0x24,0x24,0x28,0xa2,0x00, +0x25,0xb0,0x02,0x3c,0x10,0x00,0x84,0x34,0x80,0x03,0x42,0x34,0x41,0xb0,0x03,0x3c, +0x00,0x00,0x44,0xac,0x00,0x00,0x65,0xac,0x6c,0x7e,0xc4,0xac,0xfc,0x4a,0x05,0xae, +0x68,0x15,0x63,0x26,0x00,0x4b,0x62,0x8c,0x00,0x00,0x00,0x00,0x00,0x10,0x42,0x38, +0x00,0x4b,0x62,0xac,0x68,0x15,0x65,0x26,0xfc,0x4a,0xa2,0x8c,0x00,0x00,0x00,0x00, +0x24,0x10,0x52,0x00,0x00,0x20,0x42,0x30,0x37,0x00,0x40,0x10,0x2a,0xb0,0x02,0x3c, +0x04,0x00,0x43,0x34,0x00,0x00,0x68,0x8c,0xff,0x00,0x02,0x24,0xff,0x00,0x04,0x31, +0xab,0x03,0x82,0x10,0x00,0x80,0x02,0x31,0x90,0x03,0x40,0x14,0x00,0x80,0x02,0x3c, +0x00,0xff,0x02,0x3c,0x24,0x10,0x02,0x01,0x0b,0x00,0x40,0x10,0xff,0x00,0x02,0x24, +0x0c,0x64,0xa2,0x90,0x20,0xb0,0x03,0x3c,0x00,0x12,0x02,0x00,0x21,0x10,0x43,0x00, +0x0c,0x00,0x48,0x8c,0x25,0xb0,0x03,0x3c,0xb0,0x03,0x63,0x34,0x00,0x00,0x68,0xac, +0xff,0x00,0x04,0x31,0xff,0x00,0x02,0x24,0x1a,0x00,0x82,0x10,0xff,0x00,0x03,0x31, +0x68,0x15,0x70,0x26,0xcc,0x64,0x05,0x8e,0x20,0x10,0x02,0x3c,0x00,0x1a,0x03,0x00, +0x21,0x18,0x62,0x00,0x21,0x30,0x60,0x00,0x60,0x64,0x03,0xae,0x01,0x00,0x04,0x24, +0x0c,0x64,0x08,0xa2,0x20,0x00,0x07,0x24,0x10,0x01,0x00,0x0c,0x10,0x00,0xa0,0xaf, +0xfc,0x4a,0x05,0x8e,0x02,0x80,0x06,0x3c,0x6c,0x7e,0xc4,0x8c,0xff,0xc7,0x02,0x24, +0x24,0x28,0xa2,0x00,0x25,0xb0,0x02,0x3c,0x20,0x00,0x84,0x34,0x80,0x03,0x42,0x34, +0x41,0xb0,0x03,0x3c,0x00,0x00,0x44,0xac,0x00,0x00,0x65,0xac,0x6c,0x7e,0xc4,0xac, +0xfc,0x4a,0x05,0xae,0x68,0x15,0x63,0x26,0x00,0x4b,0x62,0x8c,0x00,0x00,0x00,0x00, +0x00,0x20,0x42,0x38,0x00,0x4b,0x62,0xac,0x68,0x15,0x65,0x26,0xfc,0x4a,0xa2,0x8c, +0x00,0x00,0x00,0x00,0x24,0x10,0x52,0x00,0x00,0x80,0x42,0x30,0x59,0x00,0x40,0x10, +0x2a,0xb0,0x06,0x3c,0x0c,0x00,0xc3,0x34,0x00,0x00,0x68,0x8c,0xff,0x00,0x07,0x24, +0xff,0x00,0x04,0x31,0x78,0x03,0x87,0x10,0x00,0x80,0x02,0x31,0x24,0x00,0x40,0x14, +0x00,0x80,0x02,0x3c,0x00,0xff,0x02,0x3c,0x24,0x10,0x02,0x01,0x22,0x00,0x40,0x10, +0xff,0x00,0x02,0x24,0x40,0x00,0xc6,0x34,0x00,0x00,0xc2,0x90,0x00,0x00,0x00,0x00, +0xff,0x00,0x44,0x30,0x0f,0x00,0x87,0x10,0x68,0x15,0x62,0x26,0xe8,0x63,0xa4,0xa0, +0x00,0x00,0xc2,0x90,0xff,0x00,0x83,0x30,0xff,0x00,0x44,0x30,0x09,0x00,0x83,0x10, +0x68,0x15,0x62,0x26,0x21,0x38,0xa0,0x00,0x21,0x28,0xc0,0x00,0x00,0x00,0xa2,0x90, +0x21,0x18,0x80,0x00,0xfd,0xff,0x62,0x14,0xff,0x00,0x44,0x30,0xe8,0x63,0xe3,0xa0, +0x68,0x15,0x62,0x26,0xe8,0x63,0x43,0x90,0x20,0xb0,0x02,0x3c,0x00,0x1a,0x03,0x00, +0x21,0x18,0x62,0x00,0x0c,0x00,0x68,0x8c,0x25,0xb0,0x02,0x3c,0xb0,0x03,0x42,0x34, +0xff,0x00,0x04,0x31,0x00,0x00,0x48,0xac,0x16,0x17,0x00,0x08,0xff,0x00,0x02,0x24, +0x00,0x00,0x62,0xac,0xff,0x00,0x02,0x24,0x24,0x00,0x82,0x10,0x68,0x15,0x70,0x26, +0xff,0x00,0x03,0x31,0x90,0x64,0x05,0x8e,0x20,0x10,0x02,0x3c,0x00,0x1a,0x03,0x00, +0x21,0x18,0x62,0x00,0x21,0x30,0x60,0x00,0xe8,0x63,0x08,0xa2,0x24,0x64,0x03,0xae, +0x03,0x00,0x04,0x24,0x20,0x00,0x07,0x24,0x10,0x01,0x00,0x0c,0x10,0x00,0xa0,0xaf, +0x02,0x80,0x0a,0x3c,0x7c,0x7e,0x47,0x91,0x02,0x80,0x09,0x3c,0x6c,0x7e,0x25,0x8d, +0xfc,0x4a,0x06,0x8e,0x01,0x00,0x08,0x3c,0x80,0xff,0x02,0x24,0x25,0x38,0xe2,0x00, +0x00,0x80,0x03,0x35,0x80,0x00,0xa5,0x34,0x27,0x18,0x03,0x00,0x00,0x26,0x07,0x00, +0x25,0xb0,0x02,0x3c,0x24,0x30,0xc3,0x00,0x25,0x20,0x85,0x00,0x80,0x03,0x42,0x34, +0x41,0xb0,0x03,0x3c,0x00,0x00,0x44,0xac,0x27,0x88,0x08,0x00,0x00,0x00,0x66,0xac, +0x6c,0x7e,0x25,0xad,0x7c,0x7e,0x47,0xa1,0xfc,0x4a,0x06,0xae,0x68,0x15,0x63,0x26, +0x00,0x4b,0x62,0x8c,0x00,0x00,0x00,0x00,0x00,0x80,0x42,0x38,0x00,0x4b,0x62,0xac, +0x68,0x15,0x65,0x26,0xfc,0x4a,0xa2,0x8c,0x01,0x00,0x03,0x3c,0x24,0x10,0x52,0x00, +0x24,0x10,0x51,0x00,0x24,0x10,0x43,0x00,0x56,0x00,0x40,0x10,0x2a,0xb0,0x06,0x3c, +0x10,0x00,0xc3,0x34,0x00,0x00,0x68,0x8c,0xff,0x00,0x07,0x24,0xff,0x00,0x04,0x31, +0x23,0x03,0x87,0x10,0x25,0xb0,0x02,0x3c,0x00,0x80,0x02,0x31,0x23,0x00,0x40,0x14, +0x00,0x80,0x02,0x3c,0x00,0xff,0x02,0x3c,0x24,0x10,0x02,0x01,0x21,0x00,0x40,0x10, +0xff,0x00,0x02,0x24,0x41,0x00,0xc6,0x34,0x00,0x00,0xc2,0x90,0x00,0x00,0x00,0x00, +0xff,0x00,0x44,0x30,0x0e,0x00,0x87,0x10,0x68,0x15,0x62,0x26,0xec,0x63,0xa4,0xa0, +0x00,0x00,0xc2,0x90,0xff,0x00,0x83,0x30,0xff,0x00,0x44,0x30,0x07,0x00,0x83,0x10, +0x21,0x38,0xa0,0x00,0x21,0x28,0xc0,0x00,0x00,0x00,0xa2,0x90,0x21,0x18,0x80,0x00, +0xfd,0xff,0x62,0x14,0xff,0x00,0x44,0x30,0xec,0x63,0xe3,0xa0,0x68,0x15,0x62,0x26, +0xec,0x63,0x43,0x90,0x20,0xb0,0x02,0x3c,0x00,0x1a,0x03,0x00,0x21,0x18,0x62,0x00, +0x0c,0x00,0x68,0x8c,0x25,0xb0,0x02,0x3c,0xb0,0x03,0x42,0x34,0xff,0x00,0x04,0x31, +0x00,0x00,0x48,0xac,0x75,0x17,0x00,0x08,0xff,0x00,0x02,0x24,0x00,0x00,0x62,0xac, +0xff,0x00,0x02,0x24,0x22,0x00,0x82,0x10,0x68,0x15,0x70,0x26,0xff,0x00,0x03,0x31, +0x90,0x64,0x05,0x8e,0x20,0x10,0x02,0x3c,0x00,0x1a,0x03,0x00,0x21,0x18,0x62,0x00, +0x21,0x30,0x60,0x00,0xec,0x63,0x08,0xa2,0x24,0x64,0x03,0xae,0x03,0x00,0x04,0x24, +0x20,0x00,0x07,0x24,0x10,0x01,0x00,0x0c,0x10,0x00,0xa0,0xaf,0x02,0x80,0x09,0x3c, +0x7c,0x7e,0x27,0x91,0x02,0x80,0x08,0x3c,0x6c,0x7e,0x05,0x8d,0xfc,0x4a,0x06,0x8e, +0x01,0x00,0x02,0x3c,0x00,0x80,0x42,0x34,0x40,0x00,0xe7,0x34,0x27,0x10,0x02,0x00, +0x24,0x30,0xc2,0x00,0x80,0x00,0xa5,0x34,0x00,0x26,0x07,0x00,0x25,0xb0,0x02,0x3c, +0x25,0x20,0x85,0x00,0x80,0x03,0x42,0x34,0x41,0xb0,0x03,0x3c,0x00,0x00,0x44,0xac, +0x00,0x00,0x66,0xac,0x6c,0x7e,0x05,0xad,0x7c,0x7e,0x27,0xa1,0xfc,0x4a,0x06,0xae, +0x68,0x15,0x62,0x26,0x00,0x4b,0x43,0x8c,0x01,0x00,0x04,0x3c,0x26,0x18,0x64,0x00, +0x00,0x4b,0x43,0xac,0x68,0x15,0x65,0x26,0xfc,0x4a,0xa2,0x8c,0x02,0x00,0x03,0x3c, +0x24,0x10,0x52,0x00,0x24,0x10,0x43,0x00,0x5a,0x00,0x40,0x10,0x2a,0xb0,0x06,0x3c, +0x14,0x00,0xc3,0x34,0x00,0x00,0x68,0x8c,0xff,0x00,0x07,0x24,0xff,0x00,0x04,0x31, +0xcc,0x02,0x87,0x10,0x25,0xb0,0x02,0x3c,0x00,0x80,0x02,0x31,0x23,0x00,0x40,0x14, +0x00,0x80,0x02,0x3c,0x00,0xff,0x02,0x3c,0x24,0x10,0x02,0x01,0x21,0x00,0x40,0x10, +0xff,0x00,0x02,0x24,0x42,0x00,0xc6,0x34,0x00,0x00,0xc2,0x90,0x00,0x00,0x00,0x00, +0xff,0x00,0x44,0x30,0x0e,0x00,0x87,0x10,0x68,0x15,0x62,0x26,0xf0,0x63,0xa4,0xa0, +0x00,0x00,0xc2,0x90,0xff,0x00,0x83,0x30,0xff,0x00,0x44,0x30,0x07,0x00,0x83,0x10, +0x21,0x38,0xa0,0x00,0x21,0x28,0xc0,0x00,0x00,0x00,0xa2,0x90,0x21,0x18,0x80,0x00, +0xfd,0xff,0x62,0x14,0xff,0x00,0x44,0x30,0xf0,0x63,0xe3,0xa0,0x68,0x15,0x62,0x26, +0xf0,0x63,0x43,0x90,0x20,0xb0,0x02,0x3c,0x00,0x1a,0x03,0x00,0x21,0x18,0x62,0x00, +0x0c,0x00,0x68,0x8c,0x25,0xb0,0x02,0x3c,0xb0,0x03,0x42,0x34,0xff,0x00,0x04,0x31, +0x00,0x00,0x48,0xac,0xd1,0x17,0x00,0x08,0xff,0x00,0x02,0x24,0x00,0x00,0x62,0xac, +0xff,0x00,0x02,0x24,0x25,0x00,0x82,0x10,0x68,0x15,0x70,0x26,0xff,0x00,0x03,0x31, +0x9c,0x64,0x05,0x8e,0x20,0x10,0x02,0x3c,0x00,0x1a,0x03,0x00,0x21,0x18,0x62,0x00, +0x21,0x30,0x60,0x00,0xf0,0x63,0x08,0xa2,0x30,0x64,0x03,0xae,0x04,0x00,0x04,0x24, +0x20,0x00,0x07,0x24,0x10,0x01,0x00,0x0c,0x10,0x00,0xa0,0xaf,0x02,0x80,0x0a,0x3c, +0x7c,0x7e,0x47,0x91,0x02,0x80,0x09,0x3c,0x6c,0x7e,0x25,0x8d,0xfc,0x4a,0x06,0x8e, +0x06,0x00,0x02,0x3c,0x20,0x00,0xe7,0x34,0x27,0x10,0x02,0x00,0x24,0x30,0xc2,0x00, +0x00,0x01,0xa5,0x34,0x25,0xb0,0x03,0x3c,0x04,0x00,0x02,0x3c,0x00,0x26,0x07,0x00, +0x26,0x88,0x22,0x02,0xb0,0x03,0x68,0x34,0x25,0x20,0x85,0x00,0x80,0x03,0x63,0x34, +0x41,0xb0,0x02,0x3c,0x00,0x00,0x64,0xac,0x00,0x00,0x46,0xac,0x6c,0x7e,0x25,0xad, +0x7c,0x7e,0x47,0xa1,0xfc,0x4a,0x06,0xae,0x00,0x00,0x11,0xad,0x68,0x15,0x62,0x26, +0x00,0x4b,0x43,0x8c,0x02,0x00,0x04,0x3c,0x26,0x18,0x64,0x00,0x00,0x4b,0x43,0xac, +0x68,0x15,0x65,0x26,0xfc,0x4a,0xa2,0x8c,0x04,0x00,0x03,0x3c,0x24,0x10,0x52,0x00, +0x24,0x10,0x51,0x00,0x24,0x10,0x43,0x00,0x58,0x00,0x40,0x10,0x25,0xb0,0x03,0x3c, +0xb0,0x03,0x62,0x34,0x2a,0xb0,0x09,0x3c,0x00,0x00,0x51,0xac,0x18,0x00,0x26,0x35, +0x00,0x00,0xc8,0x8c,0xff,0x00,0x07,0x24,0xff,0x00,0x04,0x31,0x3a,0x02,0x87,0x10, +0x04,0x00,0x02,0x24,0x00,0x80,0x02,0x31,0x23,0x00,0x40,0x14,0x00,0x80,0x02,0x3c, +0x00,0xff,0x02,0x3c,0x24,0x10,0x02,0x01,0x21,0x00,0x40,0x10,0xff,0x00,0x02,0x24, +0x43,0x00,0x26,0x35,0x00,0x00,0xc2,0x90,0x00,0x00,0x00,0x00,0xff,0x00,0x44,0x30, +0x0e,0x00,0x87,0x10,0x68,0x15,0x62,0x26,0xf4,0x63,0xa4,0xa0,0x00,0x00,0xc2,0x90, +0xff,0x00,0x83,0x30,0xff,0x00,0x44,0x30,0x07,0x00,0x83,0x10,0x21,0x38,0xa0,0x00, +0x21,0x28,0xc0,0x00,0x00,0x00,0xa2,0x90,0x21,0x18,0x80,0x00,0xfd,0xff,0x62,0x14, +0xff,0x00,0x44,0x30,0xf4,0x63,0xe3,0xa0,0x68,0x15,0x62,0x26,0xf4,0x63,0x43,0x90, +0x20,0xb0,0x02,0x3c,0x00,0x1a,0x03,0x00,0x21,0x18,0x62,0x00,0x0c,0x00,0x68,0x8c, +0x25,0xb0,0x02,0x3c,0xb0,0x03,0x42,0x34,0xff,0x00,0x04,0x31,0x00,0x00,0x48,0xac, +0x34,0x18,0x00,0x08,0xff,0x00,0x02,0x24,0x00,0x00,0xc2,0xac,0xff,0x00,0x02,0x24, +0x21,0x00,0x82,0x10,0x68,0x15,0x70,0x26,0xff,0x00,0x03,0x31,0x9c,0x64,0x05,0x8e, +0x20,0x10,0x02,0x3c,0x00,0x1a,0x03,0x00,0x21,0x18,0x62,0x00,0x21,0x30,0x60,0x00, +0xf4,0x63,0x08,0xa2,0x30,0x64,0x03,0xae,0x04,0x00,0x04,0x24,0x20,0x00,0x07,0x24, +0x10,0x01,0x00,0x0c,0x10,0x00,0xa0,0xaf,0x02,0x80,0x09,0x3c,0x7c,0x7e,0x27,0x91, +0x02,0x80,0x08,0x3c,0x6c,0x7e,0x05,0x8d,0xfc,0x4a,0x06,0x8e,0x06,0x00,0x02,0x3c, +0x10,0x00,0xe7,0x34,0x27,0x10,0x02,0x00,0x24,0x30,0xc2,0x00,0x00,0x01,0xa5,0x34, +0x00,0x26,0x07,0x00,0x25,0xb0,0x02,0x3c,0x25,0x20,0x85,0x00,0x80,0x03,0x42,0x34, +0x41,0xb0,0x03,0x3c,0x00,0x00,0x44,0xac,0x00,0x00,0x66,0xac,0x6c,0x7e,0x05,0xad, +0x7c,0x7e,0x27,0xa1,0xfc,0x4a,0x06,0xae,0x68,0x15,0x62,0x26,0x00,0x4b,0x43,0x8c, +0x04,0x00,0x04,0x3c,0x26,0x18,0x64,0x00,0x00,0x4b,0x43,0xac,0x68,0x15,0x65,0x26, +0xfc,0x4a,0xa2,0x8c,0x08,0x00,0x03,0x3c,0x24,0x10,0x52,0x00,0x24,0x10,0x43,0x00, +0x5a,0x00,0x40,0x10,0x2a,0xb0,0x06,0x3c,0x1c,0x00,0xc3,0x34,0x00,0x00,0x68,0x8c, +0xff,0x00,0x07,0x24,0xff,0x00,0x04,0x31,0x13,0x02,0x87,0x10,0x25,0xb0,0x02,0x3c, +0x00,0x80,0x02,0x31,0x23,0x00,0x40,0x14,0x00,0x80,0x02,0x3c,0x00,0xff,0x02,0x3c, +0x24,0x10,0x02,0x01,0x21,0x00,0x40,0x10,0xff,0x00,0x02,0x24,0x44,0x00,0xc6,0x34, +0x00,0x00,0xc2,0x90,0x00,0x00,0x00,0x00,0xff,0x00,0x44,0x30,0x0e,0x00,0x87,0x10, +0x68,0x15,0x62,0x26,0xf8,0x63,0xa4,0xa0,0x00,0x00,0xc2,0x90,0xff,0x00,0x83,0x30, +0xff,0x00,0x44,0x30,0x07,0x00,0x83,0x10,0x21,0x38,0xa0,0x00,0x21,0x28,0xc0,0x00, +0x00,0x00,0xa2,0x90,0x21,0x18,0x80,0x00,0xfd,0xff,0x62,0x14,0xff,0x00,0x44,0x30, +0xf8,0x63,0xe3,0xa0,0x68,0x15,0x62,0x26,0xf8,0x63,0x43,0x90,0x20,0xb0,0x02,0x3c, +0x00,0x1a,0x03,0x00,0x21,0x18,0x62,0x00,0x0c,0x00,0x68,0x8c,0x25,0xb0,0x02,0x3c, +0xb0,0x03,0x42,0x34,0xff,0x00,0x04,0x31,0x00,0x00,0x48,0xac,0x8f,0x18,0x00,0x08, +0xff,0x00,0x02,0x24,0x00,0x00,0x62,0xac,0xff,0x00,0x02,0x24,0x25,0x00,0x82,0x10, +0x68,0x15,0x70,0x26,0xff,0x00,0x03,0x31,0xa8,0x64,0x05,0x8e,0x20,0x10,0x02,0x3c, +0x00,0x1a,0x03,0x00,0x21,0x18,0x62,0x00,0x21,0x30,0x60,0x00,0xf8,0x63,0x08,0xa2, +0x3c,0x64,0x03,0xae,0x05,0x00,0x04,0x24,0x20,0x00,0x07,0x24,0x10,0x01,0x00,0x0c, +0x10,0x00,0xa0,0xaf,0x02,0x80,0x0a,0x3c,0x7c,0x7e,0x47,0x91,0x02,0x80,0x09,0x3c, +0x6c,0x7e,0x25,0x8d,0xfc,0x4a,0x06,0x8e,0x18,0x00,0x02,0x3c,0x08,0x00,0xe7,0x34, +0x27,0x10,0x02,0x00,0x24,0x30,0xc2,0x00,0x00,0x02,0xa5,0x34,0x25,0xb0,0x03,0x3c, +0x10,0x00,0x02,0x3c,0x00,0x26,0x07,0x00,0x26,0x88,0x22,0x02,0xb0,0x03,0x68,0x34, +0x25,0x20,0x85,0x00,0x80,0x03,0x63,0x34,0x41,0xb0,0x02,0x3c,0x00,0x00,0x64,0xac, +0x00,0x00,0x46,0xac,0x6c,0x7e,0x25,0xad,0x7c,0x7e,0x47,0xa1,0xfc,0x4a,0x06,0xae, +0x00,0x00,0x11,0xad,0x68,0x15,0x62,0x26,0x00,0x4b,0x43,0x8c,0x08,0x00,0x04,0x3c, +0x26,0x18,0x64,0x00,0x00,0x4b,0x43,0xac,0x68,0x15,0x65,0x26,0xfc,0x4a,0xa2,0x8c, +0x10,0x00,0x03,0x3c,0x24,0x10,0x52,0x00,0x24,0x10,0x51,0x00,0x24,0x10,0x43,0x00, +0x58,0x00,0x40,0x10,0x25,0xb0,0x06,0x3c,0xb0,0x03,0xc2,0x34,0x2a,0xb0,0x09,0x3c, +0x00,0x00,0x51,0xac,0x20,0x00,0x23,0x35,0x00,0x00,0x68,0x8c,0xff,0x00,0x07,0x24, +0xff,0x00,0x04,0x31,0x80,0x01,0x87,0x10,0x90,0x03,0xc2,0x34,0x00,0x80,0x02,0x31, +0x23,0x00,0x40,0x14,0x00,0x80,0x02,0x3c,0x00,0xff,0x02,0x3c,0x24,0x10,0x02,0x01, +0x21,0x00,0x40,0x10,0xff,0x00,0x02,0x24,0x45,0x00,0x26,0x35,0x00,0x00,0xc2,0x90, +0x00,0x00,0x00,0x00,0xff,0x00,0x44,0x30,0x0e,0x00,0x87,0x10,0x68,0x15,0x62,0x26, +0x04,0x64,0xa4,0xa0,0x00,0x00,0xc2,0x90,0xff,0x00,0x83,0x30,0xff,0x00,0x44,0x30, +0x07,0x00,0x83,0x10,0x21,0x38,0xa0,0x00,0x21,0x28,0xc0,0x00,0x00,0x00,0xa2,0x90, +0x21,0x18,0x80,0x00,0xfd,0xff,0x62,0x14,0xff,0x00,0x44,0x30,0x04,0x64,0xe3,0xa0, +0x68,0x15,0x62,0x26,0x04,0x64,0x43,0x90,0x20,0xb0,0x02,0x3c,0x00,0x1a,0x03,0x00, +0x21,0x18,0x62,0x00,0x0c,0x00,0x68,0x8c,0x25,0xb0,0x02,0x3c,0xb0,0x03,0x42,0x34, +0xff,0x00,0x04,0x31,0x00,0x00,0x48,0xac,0xf2,0x18,0x00,0x08,0xff,0x00,0x02,0x24, +0x00,0x00,0x62,0xac,0xff,0x00,0x02,0x24,0x21,0x00,0x82,0x10,0x68,0x15,0x70,0x26, +0xff,0x00,0x03,0x31,0xa8,0x64,0x05,0x8e,0x20,0x10,0x02,0x3c,0x00,0x1a,0x03,0x00, +0x21,0x18,0x62,0x00,0x21,0x30,0x60,0x00,0x04,0x64,0x08,0xa2,0x3c,0x64,0x03,0xae, +0x05,0x00,0x04,0x24,0x20,0x00,0x07,0x24,0x10,0x01,0x00,0x0c,0x10,0x00,0xa0,0xaf, +0x02,0x80,0x09,0x3c,0x7c,0x7e,0x27,0x91,0x02,0x80,0x08,0x3c,0x6c,0x7e,0x05,0x8d, +0xfc,0x4a,0x06,0x8e,0x18,0x00,0x02,0x3c,0x01,0x00,0xe7,0x34,0x27,0x10,0x02,0x00, +0x24,0x30,0xc2,0x00,0x00,0x02,0xa5,0x34,0x00,0x26,0x07,0x00,0x25,0xb0,0x02,0x3c, +0x25,0x20,0x85,0x00,0x80,0x03,0x42,0x34,0x41,0xb0,0x03,0x3c,0x00,0x00,0x44,0xac, +0x00,0x00,0x66,0xac,0x6c,0x7e,0x05,0xad,0x7c,0x7e,0x27,0xa1,0xfc,0x4a,0x06,0xae, +0x68,0x15,0x62,0x26,0x00,0x4b,0x43,0x8c,0x10,0x00,0x04,0x3c,0x26,0x18,0x64,0x00, +0x00,0x4b,0x43,0xac,0x68,0x15,0x65,0x26,0xfc,0x4a,0xa2,0x8c,0x20,0x00,0x03,0x3c, +0x24,0x10,0x52,0x00,0x24,0x10,0x43,0x00,0x5a,0x00,0x40,0x10,0x2a,0xb0,0x06,0x3c, +0x24,0x00,0xc3,0x34,0x00,0x00,0x68,0x8c,0xff,0x00,0x07,0x24,0xff,0x00,0x04,0x31, +0x28,0x01,0x87,0x10,0x25,0xb0,0x02,0x3c,0x00,0x80,0x02,0x31,0x23,0x00,0x40,0x14, +0x00,0x80,0x02,0x3c,0x00,0xff,0x02,0x3c,0x24,0x10,0x02,0x01,0x21,0x00,0x40,0x10, +0xff,0x00,0x02,0x24,0x46,0x00,0xc6,0x34,0x00,0x00,0xc2,0x90,0x00,0x00,0x00,0x00, +0xff,0x00,0x44,0x30,0x0e,0x00,0x87,0x10,0x68,0x15,0x62,0x26,0xfc,0x63,0xa4,0xa0, +0x00,0x00,0xc2,0x90,0xff,0x00,0x83,0x30,0xff,0x00,0x44,0x30,0x07,0x00,0x83,0x10, +0x21,0x38,0xa0,0x00,0x21,0x28,0xc0,0x00,0x00,0x00,0xa2,0x90,0x21,0x18,0x80,0x00, +0xfd,0xff,0x62,0x14,0xff,0x00,0x44,0x30,0xfc,0x63,0xe3,0xa0,0x68,0x15,0x62,0x26, +0xfc,0x63,0x43,0x90,0x20,0xb0,0x02,0x3c,0x00,0x1a,0x03,0x00,0x21,0x18,0x62,0x00, +0x0c,0x00,0x68,0x8c,0x25,0xb0,0x02,0x3c,0xb0,0x03,0x42,0x34,0xff,0x00,0x04,0x31, +0x00,0x00,0x48,0xac,0x4d,0x19,0x00,0x08,0xff,0x00,0x02,0x24,0x00,0x00,0x62,0xac, +0xff,0x00,0x02,0x24,0x25,0x00,0x82,0x10,0x68,0x15,0x70,0x26,0xff,0x00,0x03,0x31, +0xb4,0x64,0x05,0x8e,0x20,0x10,0x02,0x3c,0x00,0x1a,0x03,0x00,0x21,0x18,0x62,0x00, +0x21,0x30,0x60,0x00,0xfc,0x63,0x08,0xa2,0x48,0x64,0x03,0xae,0x06,0x00,0x04,0x24, +0x20,0x00,0x07,0x24,0x10,0x01,0x00,0x0c,0x10,0x00,0xa0,0xaf,0x02,0x80,0x0a,0x3c, +0x7c,0x7e,0x47,0x91,0x02,0x80,0x09,0x3c,0x6c,0x7e,0x25,0x8d,0xfc,0x4a,0x06,0x8e, +0x60,0x00,0x02,0x3c,0x04,0x00,0xe7,0x34,0x27,0x10,0x02,0x00,0x24,0x30,0xc2,0x00, +0x00,0x04,0xa5,0x34,0x25,0xb0,0x03,0x3c,0x40,0x00,0x02,0x3c,0x00,0x26,0x07,0x00, +0x26,0x88,0x22,0x02,0xb0,0x03,0x68,0x34,0x25,0x20,0x85,0x00,0x80,0x03,0x63,0x34, +0x41,0xb0,0x02,0x3c,0x00,0x00,0x64,0xac,0x00,0x00,0x46,0xac,0x6c,0x7e,0x25,0xad, +0x7c,0x7e,0x47,0xa1,0xfc,0x4a,0x06,0xae,0x00,0x00,0x11,0xad,0x68,0x15,0x62,0x26, +0x00,0x4b,0x43,0x8c,0x20,0x00,0x04,0x3c,0x26,0x18,0x64,0x00,0x00,0x4b,0x43,0xac, +0x68,0x15,0x65,0x26,0xfc,0x4a,0xa2,0x8c,0x40,0x00,0x03,0x3c,0x24,0x10,0x52,0x00, +0x24,0x10,0x51,0x00,0x24,0x10,0x43,0x00,0x5a,0x00,0x40,0x10,0x68,0x15,0x70,0x26, +0x25,0xb0,0x02,0x3c,0x2a,0xb0,0x07,0x3c,0xb0,0x03,0x42,0x34,0x00,0x00,0x51,0xac, +0x28,0x00,0xe3,0x34,0x00,0x00,0x68,0x8c,0xff,0x00,0x06,0x24,0xff,0x00,0x04,0x31, +0xc9,0x00,0x86,0x10,0x25,0xbd,0x02,0x3c,0x00,0x80,0x02,0x31,0x23,0x00,0x40,0x14, +0x00,0x80,0x02,0x3c,0x00,0xff,0x02,0x3c,0x24,0x10,0x02,0x01,0x21,0x00,0x40,0x10, +0xff,0x00,0x02,0x24,0x47,0x00,0xe7,0x34,0x00,0x00,0xe2,0x90,0x00,0x00,0x00,0x00, +0xff,0x00,0x44,0x30,0x0e,0x00,0x86,0x10,0x68,0x15,0x62,0x26,0x00,0x64,0xa4,0xa0, +0x00,0x00,0xe2,0x90,0xff,0x00,0x83,0x30,0xff,0x00,0x44,0x30,0x07,0x00,0x83,0x10, +0x21,0x30,0xa0,0x00,0x21,0x28,0xe0,0x00,0x00,0x00,0xa2,0x90,0x21,0x18,0x80,0x00, +0xfd,0xff,0x62,0x14,0xff,0x00,0x44,0x30,0x00,0x64,0xc3,0xa0,0x68,0x15,0x62,0x26, +0x00,0x64,0x43,0x90,0x20,0xb0,0x02,0x3c,0x00,0x1a,0x03,0x00,0x21,0x18,0x62,0x00, +0x0c,0x00,0x68,0x8c,0x25,0xb0,0x02,0x3c,0xb0,0x03,0x42,0x34,0xff,0x00,0x04,0x31, +0x00,0x00,0x48,0xac,0xb1,0x19,0x00,0x08,0xff,0x00,0x02,0x24,0x00,0x00,0x62,0xac, +0xff,0x00,0x02,0x24,0x21,0x00,0x82,0x10,0x68,0x15,0x70,0x26,0xff,0x00,0x03,0x31, +0xb4,0x64,0x05,0x8e,0x20,0x10,0x02,0x3c,0x00,0x1a,0x03,0x00,0x21,0x18,0x62,0x00, +0x21,0x30,0x60,0x00,0x00,0x64,0x08,0xa2,0x48,0x64,0x03,0xae,0x06,0x00,0x04,0x24, +0x20,0x00,0x07,0x24,0x10,0x01,0x00,0x0c,0x10,0x00,0xa0,0xaf,0x02,0x80,0x09,0x3c, +0x7c,0x7e,0x27,0x91,0x02,0x80,0x08,0x3c,0x6c,0x7e,0x05,0x8d,0xfc,0x4a,0x06,0x8e, +0x60,0x00,0x02,0x3c,0x02,0x00,0xe7,0x34,0x27,0x10,0x02,0x00,0x24,0x30,0xc2,0x00, +0x00,0x04,0xa5,0x34,0x00,0x26,0x07,0x00,0x25,0xb0,0x02,0x3c,0x25,0x20,0x85,0x00, +0x80,0x03,0x42,0x34,0x41,0xb0,0x03,0x3c,0x00,0x00,0x44,0xac,0x00,0x00,0x66,0xac, +0x6c,0x7e,0x05,0xad,0x7c,0x7e,0x27,0xa1,0xfc,0x4a,0x06,0xae,0x68,0x15,0x62,0x26, +0x00,0x4b,0x43,0x8c,0x40,0x00,0x04,0x3c,0x26,0x18,0x64,0x00,0x00,0x4b,0x43,0xac, +0x68,0x15,0x70,0x26,0xfc,0x4a,0x06,0x8e,0x00,0x04,0x11,0x3c,0x24,0x10,0xd2,0x00, +0x24,0x10,0x51,0x00,0x4c,0x00,0x40,0x14,0x00,0x00,0x00,0x00,0x24,0x28,0xd2,0x00, +0x00,0x08,0x04,0x3c,0x24,0x10,0xa4,0x00,0x08,0x00,0x40,0x10,0x80,0x00,0x07,0x3c, +0x00,0x4b,0x03,0x8e,0x25,0xb0,0x02,0x3c,0xb0,0x03,0x42,0x34,0x26,0x18,0x64,0x00, +0x00,0x00,0x44,0xac,0x00,0x4b,0x03,0xae,0x80,0x00,0x07,0x3c,0x24,0x10,0xa7,0x00, +0x21,0x00,0x40,0x10,0x00,0x00,0x00,0x00,0x00,0x4b,0x03,0x8e,0x25,0xb0,0x08,0x3c, +0xb0,0x03,0x09,0x35,0x2a,0xb0,0x02,0x3c,0x00,0x00,0x23,0xad,0x36,0x00,0x42,0x34, +0x00,0x00,0x43,0x90,0x23,0xb0,0x04,0x3c,0xff,0x1f,0x02,0x3c,0xc0,0x18,0x03,0x00, +0xf0,0x07,0x63,0x30,0x5c,0x65,0x05,0x8e,0x21,0x18,0x64,0x00,0xff,0xff,0x42,0x34, +0x24,0x18,0x62,0x00,0x59,0x00,0x65,0x10,0x60,0x65,0x03,0xae,0x02,0x80,0x05,0x3c, +0x6c,0x7e,0xa3,0x8c,0x27,0x20,0x07,0x00,0x24,0x20,0xc4,0x00,0x00,0x08,0x63,0x34, +0x41,0xb0,0x02,0x3c,0x00,0x00,0x23,0xad,0x00,0x00,0x44,0xac,0x6c,0x7e,0xa3,0xac, +0xfc,0x4a,0x04,0xae,0x68,0x15,0x62,0x26,0x00,0x4b,0x43,0x8c,0x80,0x00,0x04,0x3c, +0x26,0x18,0x64,0x00,0x00,0x4b,0x43,0xac,0x68,0x15,0x66,0x26,0xfc,0x4a,0xc3,0x8c, +0x00,0x01,0x04,0x3c,0x24,0x28,0x72,0x00,0x24,0x10,0xa4,0x00,0x06,0x00,0x40,0x10, +0x25,0xb0,0x02,0x3c,0x00,0x4b,0xc3,0x8c,0xb0,0x03,0x42,0x34,0x26,0x18,0x64,0x00, +0x00,0x00,0x44,0xac,0x00,0x4b,0xc3,0xac,0x00,0x02,0x04,0x3c,0x24,0x10,0xa4,0x00, +0x06,0x00,0x40,0x10,0x25,0xb0,0x03,0x3c,0x00,0x4b,0xc2,0x8c,0xb0,0x03,0x63,0x34, +0x26,0x10,0x44,0x00,0x00,0x4b,0xc2,0xac,0x00,0x00,0x64,0xac,0x28,0x00,0xbf,0x8f, +0x24,0x00,0xb3,0x8f,0x20,0x00,0xb2,0x8f,0x1c,0x00,0xb1,0x8f,0x18,0x00,0xb0,0x8f, +0x08,0x00,0xe0,0x03,0x30,0x00,0xbd,0x27,0x5b,0x4e,0x00,0x0c,0x07,0x00,0x04,0x24, +0x00,0x4b,0x03,0x8e,0xfc,0x4a,0x06,0x8e,0x25,0xb0,0x02,0x3c,0x26,0x18,0x71,0x00, +0xb0,0x03,0x42,0x34,0x00,0x00,0x43,0xac,0xdf,0x19,0x00,0x08,0x00,0x4b,0x03,0xae, +0x56,0x01,0x42,0x35,0x00,0x00,0x43,0x94,0x00,0x00,0x00,0x00,0x44,0xfb,0x60,0x10, +0x00,0x00,0x00,0x00,0x5b,0x4e,0x00,0x0c,0x07,0x00,0x04,0x24,0x7d,0x15,0x00,0x08, +0x68,0x15,0x66,0x26,0x00,0x00,0xa2,0xac,0x48,0x16,0x00,0x08,0xff,0x00,0x02,0x24, +0x00,0x00,0x62,0xac,0x85,0x16,0x00,0x08,0xff,0x00,0x02,0x24,0x00,0x00,0x62,0xac, +0xc2,0x16,0x00,0x08,0xff,0x00,0x02,0x24,0x90,0x03,0x63,0x34,0x00,0x00,0x62,0xac, +0x57,0x18,0x00,0x08,0x68,0x15,0x62,0x26,0x00,0x00,0x40,0xac,0x15,0x19,0x00,0x08, +0x68,0x15,0x62,0x26,0x02,0x00,0x03,0x24,0x90,0x03,0x42,0x34,0x00,0x00,0x43,0xac, +0x74,0x19,0x00,0x08,0x68,0x15,0x62,0x26,0x01,0x00,0x03,0x24,0x90,0x03,0x42,0x34, +0x00,0x00,0x43,0xac,0xd4,0x19,0x00,0x08,0x68,0x15,0x62,0x26,0xd0,0x03,0x03,0x35, +0x80,0x00,0x02,0x24,0x00,0x00,0x62,0xac,0x0a,0x1a,0x00,0x08,0x68,0x15,0x62,0x26, +0x25,0xb0,0x02,0x3c,0x07,0x00,0x03,0x24,0x90,0x03,0x42,0x34,0x00,0x00,0x43,0xac, +0x68,0x15,0x63,0x26,0x00,0x4b,0x62,0x8c,0x00,0x00,0x00,0x00,0x00,0x20,0x42,0x38, +0xe2,0x16,0x00,0x08,0x00,0x4b,0x62,0xac,0x25,0xb0,0x02,0x3c,0x07,0x00,0x03,0x24, +0x90,0x03,0x42,0x34,0x00,0x00,0x43,0xac,0x68,0x15,0x63,0x26,0x00,0x4b,0x62,0x8c, +0x00,0x00,0x00,0x00,0x00,0x80,0x42,0x38,0x40,0x17,0x00,0x08,0x00,0x4b,0x62,0xac, +0x06,0x00,0x03,0x24,0x90,0x03,0x42,0x34,0x00,0x00,0x43,0xac,0x99,0x17,0x00,0x08, +0x68,0x15,0x62,0x26,0x05,0x00,0x03,0x24,0x90,0x03,0x42,0x34,0x00,0x00,0x43,0xac, +0xf8,0x17,0x00,0x08,0x68,0x15,0x62,0x26,0x03,0x00,0x03,0x24,0x90,0x03,0x42,0x34, +0x00,0x00,0x43,0xac,0xb6,0x18,0x00,0x08,0x68,0x15,0x62,0x26,0x25,0xb0,0x0d,0x3c, +0x00,0x80,0x02,0x3c,0x18,0x03,0xa4,0x35,0xfc,0x69,0x42,0x24,0x02,0x80,0x03,0x3c, +0x41,0xb0,0x08,0x3c,0x00,0x00,0x82,0xac,0x68,0x15,0x6a,0x24,0x0a,0x00,0x02,0x35, +0x00,0x00,0x44,0x94,0x0a,0x4b,0x43,0x95,0x08,0x4b,0x4b,0x95,0x25,0x18,0x64,0x00, +0xff,0xff,0x6c,0x30,0x24,0x10,0x8b,0x01,0x02,0x00,0x42,0x30,0x4d,0x00,0x40,0x10, +0x02,0x00,0x64,0x38,0x02,0x00,0x02,0x24,0xc0,0x03,0xa3,0x35,0x00,0x00,0x62,0xac, +0x0a,0x4b,0x44,0xa5,0x24,0x38,0x8b,0x01,0x04,0x00,0xe2,0x30,0x0a,0x00,0x40,0x10, +0x08,0x00,0xe2,0x30,0x0a,0x4b,0x43,0x95,0x0c,0x00,0x04,0x35,0xc0,0x03,0xa5,0x35, +0x04,0x00,0x63,0x38,0x04,0x00,0x02,0x24,0x00,0x00,0x86,0x8c,0x00,0x00,0xa2,0xac, +0x0a,0x4b,0x43,0xa5,0x08,0x00,0xe2,0x30,0x08,0x00,0x40,0x10,0x10,0x00,0xe2,0x30, +0x0a,0x4b,0x42,0x95,0xc0,0x03,0xa4,0x35,0x08,0x00,0x03,0x24,0x08,0x00,0x42,0x38, +0x00,0x00,0x83,0xac,0x0a,0x4b,0x42,0xa5,0x10,0x00,0xe2,0x30,0x08,0x00,0x40,0x10, +0x20,0x00,0xe2,0x30,0x0a,0x4b,0x42,0x95,0xc0,0x03,0xa4,0x35,0x10,0x00,0x03,0x24, +0x10,0x00,0x42,0x38,0x00,0x00,0x83,0xac,0x0a,0x4b,0x42,0xa5,0x20,0x00,0xe2,0x30, +0x08,0x00,0x40,0x10,0x80,0x00,0xe2,0x30,0x0a,0x4b,0x42,0x95,0xc0,0x03,0xa4,0x35, +0x20,0x00,0x03,0x24,0x20,0x00,0x42,0x38,0x00,0x00,0x83,0xac,0x0a,0x4b,0x42,0xa5, +0x80,0x00,0xe2,0x30,0x15,0x00,0x40,0x10,0x24,0x10,0x8b,0x01,0x02,0x80,0x09,0x3c, +0x0a,0x4b,0x46,0x95,0x6c,0x7e,0x25,0x8d,0x08,0x00,0x02,0x3c,0x7f,0xff,0x04,0x24, +0x24,0x20,0x64,0x01,0x25,0x28,0xa2,0x00,0x80,0x00,0xc6,0x38,0xb0,0x03,0xa7,0x35, +0x08,0x00,0x08,0x35,0xc0,0x03,0xa3,0x35,0x80,0x00,0x02,0x24,0x00,0x00,0x62,0xac, +0x21,0x58,0x80,0x00,0x00,0x00,0xe5,0xac,0x0a,0x4b,0x46,0xa5,0x6c,0x7e,0x25,0xad, +0x00,0x00,0x04,0xa5,0x08,0x4b,0x44,0xa5,0x24,0x10,0x8b,0x01,0x00,0x30,0x42,0x30, +0x06,0x00,0x40,0x10,0x00,0x00,0x00,0x00,0x0a,0x4b,0x42,0x95,0x00,0x00,0x00,0x00, +0x00,0x10,0x42,0x38,0x00,0x20,0x42,0x34,0x0a,0x4b,0x42,0xa5,0x08,0x00,0xe0,0x03, +0x00,0x00,0x00,0x00,0x95,0x1a,0x00,0x08,0x0a,0x4b,0x43,0xa5,0xf8,0xff,0xbd,0x27, +0x04,0x00,0xb1,0xaf,0x00,0x00,0xb0,0xaf,0x00,0x40,0x02,0x40,0x00,0x68,0x08,0x40, +0x00,0x70,0x02,0x40,0x00,0x60,0x09,0x40,0x25,0xb0,0x05,0x3c,0x00,0x80,0x02,0x3c, +0x18,0x03,0xa3,0x34,0x7c,0x6b,0x42,0x24,0x00,0x00,0x62,0xac,0x80,0x00,0x87,0x8c, +0x7c,0x02,0xa2,0x34,0x84,0x02,0xa3,0x34,0x88,0x02,0xa6,0x34,0x00,0x00,0x47,0xac, +0x00,0x00,0x68,0xac,0x00,0x00,0xc9,0xac,0x74,0x00,0x83,0x8c,0x8c,0x02,0xa2,0x34, +0x90,0x02,0xa7,0x34,0x00,0x00,0x43,0xac,0x08,0x00,0x86,0x8c,0x94,0x02,0xa8,0x34, +0x98,0x02,0xa9,0x34,0x00,0x00,0xe6,0xac,0x0c,0x00,0x82,0x8c,0x9c,0x02,0xa6,0x34, +0xa0,0x02,0xa7,0x34,0x00,0x00,0x02,0xad,0x10,0x00,0x83,0x8c,0xa4,0x02,0xa8,0x34, +0xa8,0x02,0xaa,0x34,0x00,0x00,0x23,0xad,0x14,0x00,0x82,0x8c,0xac,0x02,0xa9,0x34, +0xb0,0x02,0xab,0x34,0x00,0x00,0xc2,0xac,0x18,0x00,0x83,0x8c,0xb4,0x02,0xa6,0x34, +0xb8,0x02,0xac,0x34,0x00,0x00,0xe3,0xac,0x1c,0x00,0x82,0x8c,0xbc,0x02,0xa7,0x34, +0xc0,0x02,0xad,0x34,0x00,0x00,0x02,0xad,0x20,0x00,0x83,0x8c,0xc4,0x02,0xa8,0x34, +0xc8,0x02,0xae,0x34,0x00,0x00,0x43,0xad,0x24,0x00,0x82,0x8c,0xcc,0x02,0xaa,0x34, +0xd0,0x02,0xaf,0x34,0x00,0x00,0x22,0xad,0x28,0x00,0x83,0x8c,0xd4,0x02,0xa9,0x34, +0xd8,0x02,0xb0,0x34,0x00,0x00,0x63,0xad,0x2c,0x00,0x82,0x8c,0x70,0x02,0xab,0x34, +0x74,0x02,0xb1,0x34,0x00,0x00,0xc2,0xac,0x30,0x00,0x83,0x8c,0x78,0x02,0xa5,0x34, +0x00,0x00,0x83,0xad,0x34,0x00,0x82,0x8c,0x00,0x00,0x00,0x00,0x00,0x00,0xe2,0xac, +0x38,0x00,0x83,0x8c,0x00,0x00,0x00,0x00,0x00,0x00,0xa3,0xad,0x3c,0x00,0x82,0x8c, +0x00,0x00,0x00,0x00,0x00,0x00,0x02,0xad,0x40,0x00,0x83,0x8c,0x00,0x00,0x00,0x00, +0x00,0x00,0xc3,0xad,0x44,0x00,0x82,0x8c,0x00,0x00,0x00,0x00,0x00,0x00,0x42,0xad, +0x48,0x00,0x83,0x8c,0x00,0x00,0x00,0x00,0x00,0x00,0xe3,0xad,0x4c,0x00,0x82,0x8c, +0x00,0x00,0x00,0x00,0x00,0x00,0x22,0xad,0x50,0x00,0x83,0x8c,0x00,0x00,0x00,0x00, +0x00,0x00,0x03,0xae,0x54,0x00,0x82,0x8c,0x00,0x00,0x00,0x00,0x00,0x00,0x62,0xad, +0x58,0x00,0x83,0x8c,0x00,0x00,0x00,0x00,0x00,0x00,0x23,0xae,0x5c,0x00,0x82,0x8c, +0x00,0x00,0x00,0x00,0x00,0x00,0xa2,0xac,0x42,0x1b,0x00,0x08,0x00,0x00,0x00,0x00, +0x00,0x80,0x1b,0x3c,0x10,0x6d,0x7b,0x27,0x25,0xb0,0x1a,0x3c,0x18,0x03,0x5a,0x27, +0x00,0x00,0x5b,0xaf,0x21,0xd8,0xa0,0x03,0x82,0xda,0x1b,0x00,0x80,0xda,0x1b,0x00, +0x08,0x00,0x7b,0x27,0x04,0x00,0x61,0xaf,0x08,0x00,0x62,0xaf,0x0c,0x00,0x63,0xaf, +0x10,0x00,0x64,0xaf,0x14,0x00,0x65,0xaf,0x18,0x00,0x66,0xaf,0x1c,0x00,0x67,0xaf, +0x20,0x00,0x68,0xaf,0x24,0x00,0x69,0xaf,0x28,0x00,0x6a,0xaf,0x2c,0x00,0x6b,0xaf, +0x30,0x00,0x6c,0xaf,0x34,0x00,0x6d,0xaf,0x38,0x00,0x6e,0xaf,0x3c,0x00,0x6f,0xaf, +0x12,0x40,0x00,0x00,0x10,0x48,0x00,0x00,0x00,0x70,0x0a,0x40,0x40,0x00,0x70,0xaf, +0x44,0x00,0x71,0xaf,0x48,0x00,0x72,0xaf,0x4c,0x00,0x73,0xaf,0x50,0x00,0x74,0xaf, +0x54,0x00,0x75,0xaf,0x58,0x00,0x76,0xaf,0x5c,0x00,0x77,0xaf,0x60,0x00,0x78,0xaf, +0x64,0x00,0x79,0xaf,0x68,0x00,0x7c,0xaf,0x6c,0x00,0x7d,0xaf,0x70,0x00,0x7e,0xaf, +0x74,0x00,0x7f,0xaf,0x78,0x00,0x68,0xaf,0x7c,0x00,0x69,0xaf,0x80,0x00,0x6a,0xaf, +0x00,0x68,0x1a,0x40,0x25,0xb0,0x1b,0x3c,0x1c,0x03,0x7b,0x37,0x00,0x00,0x00,0x00, +0x00,0x00,0x7a,0xaf,0x7f,0x00,0x5b,0x33,0x30,0x00,0x60,0x13,0x00,0x00,0x00,0x00, +0x25,0xb0,0x1b,0x3c,0x30,0x03,0x7b,0x37,0x00,0x00,0x00,0x00,0x00,0x00,0x7a,0xaf, +0x00,0x00,0x00,0x00,0x21,0xd8,0xa0,0x03,0x82,0xda,0x1b,0x00,0x80,0xda,0x1b,0x00, +0x08,0x00,0x7b,0x27,0x04,0x00,0x61,0xaf,0x08,0x00,0x62,0xaf,0x0c,0x00,0x63,0xaf, +0x10,0x00,0x64,0xaf,0x14,0x00,0x65,0xaf,0x18,0x00,0x66,0xaf,0x1c,0x00,0x67,0xaf, +0x20,0x00,0x68,0xaf,0x24,0x00,0x69,0xaf,0x28,0x00,0x6a,0xaf,0x2c,0x00,0x6b,0xaf, +0x30,0x00,0x6c,0xaf,0x34,0x00,0x6d,0xaf,0x38,0x00,0x6e,0xaf,0x3c,0x00,0x6f,0xaf, +0x12,0x40,0x00,0x00,0x10,0x48,0x00,0x00,0x00,0x70,0x0a,0x40,0x40,0x00,0x70,0xaf, +0x44,0x00,0x71,0xaf,0x48,0x00,0x72,0xaf,0x4c,0x00,0x73,0xaf,0x50,0x00,0x74,0xaf, +0x54,0x00,0x75,0xaf,0x58,0x00,0x76,0xaf,0x5c,0x00,0x77,0xaf,0x60,0x00,0x78,0xaf, +0x64,0x00,0x79,0xaf,0x68,0x00,0x7c,0xaf,0x6c,0x00,0x7d,0xaf,0x70,0x00,0x7e,0xaf, +0x74,0x00,0x7f,0xaf,0x78,0x00,0x68,0xaf,0x7c,0x00,0x69,0xaf,0x80,0x00,0x6a,0xaf, +0xdf,0x1a,0x00,0x08,0x21,0x20,0x60,0x03,0x00,0x00,0x00,0x00,0x25,0xb0,0x08,0x3c, +0x20,0x03,0x08,0x35,0x00,0x00,0x00,0x00,0x00,0x00,0x1a,0xad,0x00,0x04,0x5b,0x33, +0x0a,0x00,0x60,0x13,0x00,0x00,0x00,0x00,0x00,0x80,0x08,0x3c,0x74,0x55,0x08,0x25, +0x00,0x00,0x00,0x00,0x25,0xb0,0x1b,0x3c,0x24,0x03,0x7b,0x37,0x00,0x00,0x00,0x00, +0x00,0x00,0x68,0xaf,0x09,0xf8,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x08,0x5b,0x33, +0x25,0xb0,0x08,0x3c,0x28,0x03,0x08,0x35,0x00,0x00,0x00,0x00,0x00,0x00,0x1b,0xad, +0x06,0x00,0x60,0x13,0x00,0x00,0x00,0x00,0x00,0x80,0x08,0x3c,0xfc,0x69,0x08,0x25, +0x00,0x00,0x00,0x00,0x09,0xf8,0x00,0x01,0x00,0x00,0x00,0x00,0x02,0x80,0x1a,0x3c, +0x6c,0x7e,0x5a,0x27,0x04,0x00,0x5b,0x97,0x25,0xb0,0x08,0x3c,0x30,0x03,0x08,0x35, +0x00,0x00,0x00,0x00,0x00,0x00,0x1b,0xad,0x18,0x00,0x60,0x13,0x00,0x00,0x00,0x00, +0x08,0xec,0x9b,0x27,0x00,0x00,0x00,0x00,0x04,0x00,0x61,0x8f,0xfc,0x03,0x70,0x7b, +0x7c,0x00,0x62,0x7b,0xbc,0x00,0x64,0x7b,0xfc,0x00,0x66,0x7b,0x3c,0x01,0x68,0x7b, +0x13,0x00,0x00,0x02,0x11,0x00,0x20,0x02,0x7c,0x01,0x6a,0x7b,0xbc,0x01,0x6c,0x7b, +0xfc,0x01,0x6e,0x7b,0x3c,0x02,0x70,0x7b,0x7c,0x02,0x72,0x7b,0xbc,0x02,0x74,0x7b, +0xfc,0x02,0x76,0x7b,0x3c,0x03,0x78,0x7b,0x7c,0x03,0x7c,0x7b,0xbc,0x03,0x7e,0x7b, +0x80,0x00,0x7b,0x8f,0x2f,0x1c,0x00,0x08,0x00,0x00,0x00,0x00,0x21,0xd8,0xa0,0x03, +0x82,0xda,0x1b,0x00,0x80,0xda,0x1b,0x00,0x08,0x00,0x7b,0x27,0x08,0x00,0x5b,0xaf, +0xfc,0xef,0x9d,0x27,0x00,0x00,0x4a,0x8f,0x00,0x00,0x00,0x00,0x21,0x00,0x40,0x11, +0x00,0x00,0x00,0x00,0x02,0x80,0x08,0x3c,0xcc,0x7d,0x08,0x25,0x21,0x48,0x00,0x00, +0x21,0x58,0x00,0x00,0x01,0x00,0x6b,0x25,0x1a,0x00,0x40,0x11,0x24,0x70,0x4b,0x01, +0x14,0x00,0xc0,0x11,0x01,0x00,0x04,0x24,0x00,0x00,0x00,0x00,0x04,0x00,0x44,0xa3, +0x26,0x50,0x4b,0x01,0x00,0x00,0x4a,0xaf,0x80,0x80,0x09,0x00,0x21,0x80,0x08,0x02, +0x00,0x00,0x10,0x8e,0x00,0x00,0x00,0x00,0x09,0xf8,0x00,0x02,0x00,0x00,0x00,0x00, +0x00,0x80,0x1b,0x3c,0xe8,0x6f,0x7b,0x27,0x25,0xb0,0x1a,0x3c,0x18,0x03,0x5a,0x27, +0x00,0x00,0x5b,0xaf,0x02,0x80,0x1a,0x3c,0x6c,0x7e,0x5a,0x27,0xe1,0xff,0x00,0x10, +0x00,0x00,0x00,0x00,0x01,0x00,0x29,0x25,0x40,0x58,0x0b,0x00,0xf2,0x1b,0x00,0x08, +0x00,0x00,0x00,0x00,0x02,0x80,0x1b,0x3c,0x6c,0x7e,0x7b,0x27,0x21,0x60,0x00,0x00, +0x04,0x00,0x6c,0xa7,0x08,0x00,0x7a,0x8f,0x00,0x00,0x00,0x00,0xf8,0xff,0x5a,0x27, +0x00,0x00,0x5a,0x8f,0x00,0x00,0x00,0x00,0x08,0x00,0x5a,0x27,0x84,0x00,0x44,0x8f, +0x00,0x00,0x00,0x00,0xf9,0xff,0x80,0x10,0x00,0x00,0x00,0x00,0x04,0x00,0x41,0x8f, +0xfc,0x03,0x50,0x7b,0x7c,0x00,0x42,0x7b,0xbc,0x00,0x44,0x7b,0xfc,0x00,0x46,0x7b, +0x3c,0x01,0x48,0x7b,0x13,0x00,0x00,0x02,0x11,0x00,0x20,0x02,0x7c,0x01,0x4a,0x7b, +0xbc,0x01,0x4c,0x7b,0xfc,0x01,0x4e,0x7b,0x3c,0x02,0x50,0x7b,0x7c,0x02,0x52,0x7b, +0xbc,0x02,0x54,0x7b,0xfc,0x02,0x56,0x7b,0x3c,0x03,0x58,0x7b,0x7c,0x03,0x5c,0x7b, +0xbc,0x03,0x5e,0x7b,0x80,0x00,0x5b,0x8f,0x00,0x00,0x00,0x00,0x08,0x00,0x60,0x03, +0x10,0x00,0x00,0x42,0x00,0x60,0x05,0x40,0x42,0x28,0x05,0x00,0x40,0x28,0x05,0x00, +0x00,0x60,0x85,0x40,0x04,0x00,0x81,0xac,0x08,0x00,0x82,0xac,0x0c,0x00,0x83,0xac, +0x20,0x00,0x88,0xac,0x24,0x00,0x89,0xac,0x28,0x00,0x8a,0xac,0x2c,0x00,0x8b,0xac, +0x30,0x00,0x8c,0xac,0x34,0x00,0x8d,0xac,0x38,0x00,0x8e,0xac,0x3c,0x00,0x8f,0xac, +0x12,0x40,0x00,0x00,0x10,0x48,0x00,0x00,0x40,0x00,0x90,0xac,0x44,0x00,0x91,0xac, +0x48,0x00,0x92,0xac,0x4c,0x00,0x93,0xac,0x50,0x00,0x94,0xac,0x54,0x00,0x95,0xac, +0x58,0x00,0x96,0xac,0x5c,0x00,0x97,0xac,0x60,0x00,0x98,0xac,0x64,0x00,0x99,0xac, +0x68,0x00,0x9c,0xac,0x6c,0x00,0x9d,0xac,0x70,0x00,0x9e,0xac,0x74,0x00,0x9f,0xac, +0x78,0x00,0x88,0xac,0x7c,0x00,0x89,0xac,0x80,0x00,0x9f,0xac,0xf8,0xff,0x84,0x24, +0x00,0x00,0x84,0x8c,0x00,0x00,0x00,0x00,0x08,0x00,0x84,0x24,0x84,0x00,0x86,0x8c, +0x00,0x00,0x00,0x00,0xf9,0xff,0xc0,0x10,0x00,0x00,0x00,0x00,0x21,0xd8,0x80,0x00, +0x01,0x00,0xba,0x24,0x04,0x00,0x61,0x8f,0xfc,0x03,0x70,0x7b,0x7c,0x00,0x62,0x7b, +0xbc,0x00,0x64,0x7b,0xfc,0x00,0x66,0x7b,0x3c,0x01,0x68,0x7b,0x13,0x00,0x00,0x02, +0x11,0x00,0x20,0x02,0x7c,0x01,0x6a,0x7b,0xbc,0x01,0x6c,0x7b,0xfc,0x01,0x6e,0x7b, +0x3c,0x02,0x70,0x7b,0x7c,0x02,0x72,0x7b,0xbc,0x02,0x74,0x7b,0xfc,0x02,0x76,0x7b, +0x3c,0x03,0x78,0x7b,0x7c,0x03,0x7c,0x7b,0xbc,0x03,0x7e,0x7b,0x80,0x00,0x7b,0x8f, +0x00,0x00,0x00,0x00,0x08,0x00,0x60,0x03,0x00,0x60,0x9a,0x40,0x00,0x60,0x05,0x40, +0x42,0x28,0x05,0x00,0x40,0x28,0x05,0x00,0x00,0x60,0x85,0x40,0x04,0x00,0x81,0xac, +0x08,0x00,0x82,0xac,0x0c,0x00,0x83,0xac,0x20,0x00,0x88,0xac,0x24,0x00,0x89,0xac, +0x28,0x00,0x8a,0xac,0x2c,0x00,0x8b,0xac,0x30,0x00,0x8c,0xac,0x34,0x00,0x8d,0xac, +0x38,0x00,0x8e,0xac,0x3c,0x00,0x8f,0xac,0x12,0x40,0x00,0x00,0x10,0x48,0x00,0x00, +0x40,0x00,0x90,0xac,0x44,0x00,0x91,0xac,0x48,0x00,0x92,0xac,0x4c,0x00,0x93,0xac, +0x50,0x00,0x94,0xac,0x54,0x00,0x94,0xac,0x58,0x00,0x96,0xac,0x5c,0x00,0x96,0xac, +0x60,0x00,0x98,0xac,0x64,0x00,0x99,0xac,0x68,0x00,0x9c,0xac,0x6c,0x00,0x9d,0xac, +0x70,0x00,0x9e,0xac,0x78,0x00,0x88,0xac,0x7c,0x00,0x89,0xac,0x80,0x00,0x9f,0xac, +0x84,0x00,0x80,0xac,0xf8,0xff,0x84,0x24,0x00,0x00,0x84,0x8c,0x00,0x00,0x00,0x00, +0x08,0x00,0x84,0x24,0x84,0x00,0x86,0x8c,0xfa,0xff,0xc0,0x10,0x00,0x00,0x00,0x00, +0x21,0xd8,0x80,0x00,0x01,0x00,0xba,0x24,0x04,0x00,0x61,0x8f,0xfc,0x03,0x70,0x7b, +0x7c,0x00,0x62,0x7b,0xbc,0x00,0x64,0x7b,0xfc,0x00,0x66,0x7b,0x3c,0x01,0x68,0x7b, +0x13,0x00,0x00,0x02,0x11,0x00,0x20,0x02,0x7c,0x01,0x6a,0x7b,0xbc,0x01,0x6c,0x7b, +0xfc,0x01,0x6e,0x7b,0x3c,0x02,0x70,0x7b,0x7c,0x02,0x72,0x7b,0xbc,0x02,0x74,0x7b, +0xfc,0x02,0x76,0x7b,0x3c,0x03,0x78,0x7b,0x7c,0x03,0x7c,0x7b,0xbc,0x03,0x7e,0x7b, +0x80,0x00,0x7b,0x8f,0x08,0x00,0x60,0x03,0x00,0x60,0x9a,0x40,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xc6,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80,0x1b,0x3c,0x00,0x00,0x7b,0x27, +0x25,0xb0,0x1a,0x3c,0x18,0x03,0x5a,0x27,0x00,0x00,0x5b,0xaf,0x00,0x00,0x05,0x24, +0x03,0x00,0xa4,0x24,0x00,0xa0,0x80,0x40,0x00,0xa0,0x84,0x40,0x01,0x80,0x04,0x3c, +0x98,0x03,0x84,0x24,0x08,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x01,0x80,0x1b,0x3c,0x98,0x03,0x7b,0x27,0x25,0xb0,0x1a,0x3c,0x18,0x03,0x5a,0x27, +0x00,0x00,0x5b,0xaf,0x02,0x80,0x1a,0x3c,0x00,0x00,0x5a,0x27,0xfc,0x03,0x5d,0x27, +0x02,0x80,0x1c,0x3c,0x00,0x14,0x9c,0x27,0x00,0xf0,0x08,0x3c,0x00,0x0c,0x08,0x35, +0x00,0x60,0x88,0x40,0x02,0x80,0x04,0x3c,0x00,0x00,0x84,0x24,0xff,0x7f,0x05,0x3c, +0xff,0xff,0xa5,0x34,0x24,0x20,0x85,0x00,0x00,0x20,0x84,0x4c,0xff,0xff,0x05,0x34, +0x21,0x28,0xa4,0x00,0x00,0x28,0x85,0x4c,0x00,0x80,0x04,0x3c,0x00,0x00,0x84,0x24, +0xff,0x7f,0x05,0x3c,0xff,0xff,0xa5,0x34,0x24,0x20,0x85,0x00,0x00,0x00,0x84,0x4c, +0xff,0x7f,0x06,0x24,0x21,0x30,0xc4,0x00,0x24,0x30,0xc5,0x00,0x00,0x08,0x86,0x4c, +0x00,0xa0,0x04,0x40,0x10,0x00,0x84,0x34,0x00,0xa0,0x84,0x40,0x01,0x80,0x1b,0x3c, +0x24,0x04,0x7b,0x27,0x25,0xb0,0x1a,0x3c,0x18,0x03,0x5a,0x27,0x00,0x00,0x5b,0xaf, +0x00,0x00,0x00,0x00,0x25,0xb0,0x04,0x3c,0x44,0x00,0x84,0x34,0x00,0x00,0x85,0x84, +0x20,0x00,0x06,0x24,0x25,0x28,0xa6,0x00,0x00,0x00,0x85,0xa4,0x01,0x80,0x1b,0x3c, +0x54,0x04,0x7b,0x27,0x25,0xb0,0x1a,0x3c,0x18,0x03,0x5a,0x27,0x00,0x00,0x5b,0xaf, +0x25,0xb0,0x04,0x3c,0x44,0x00,0x84,0x34,0x00,0x00,0x85,0x8c,0x00,0x00,0x00,0x00, +0x10,0x00,0xa5,0x30,0xfc,0xff,0xa0,0x10,0x00,0x00,0x00,0x00,0xff,0x1f,0x07,0x3c, +0xff,0xff,0xe7,0x34,0x02,0x80,0x05,0x3c,0x88,0x7d,0xa5,0x24,0xff,0xff,0xa5,0x30, +0x40,0xb0,0x04,0x3c,0x25,0x28,0xa4,0x00,0x24,0x28,0xa7,0x00,0x21,0x30,0x00,0x00, +0x43,0xb0,0x02,0x3c,0x00,0x80,0x04,0x3c,0x40,0x00,0x84,0x34,0x00,0x00,0x45,0xac, +0x04,0x00,0x46,0xac,0x08,0x00,0x44,0xac,0x4e,0x58,0x00,0x08,0x00,0x00,0x00,0x00, +0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x09,0x00,0x02,0x24,0xff,0xff,0x42,0x24, +0xff,0xff,0x41,0x04,0xff,0xff,0x42,0x24,0x08,0x00,0xe0,0x03,0x01,0x00,0x42,0x24, +0x00,0x60,0x02,0x40,0x01,0x00,0x41,0x34,0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40, +0x08,0x00,0xe0,0x03,0x00,0x00,0x82,0xac,0x00,0x00,0x82,0x8c,0x00,0x00,0x00,0x00, +0x21,0x18,0x40,0x00,0x00,0x60,0x83,0x40,0x08,0x00,0xe0,0x03,0x00,0x00,0x82,0xac, +0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40,0x08,0x00,0xe0,0x03, +0x00,0x00,0x00,0x00,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x01,0x00,0x21,0x38, +0x00,0x60,0x81,0x40,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x01,0x80,0x03,0x3c, +0x25,0xb0,0x02,0x3c,0x44,0x05,0x63,0x24,0x18,0x03,0x42,0x34,0x00,0x00,0x43,0xac, +0x04,0x00,0x85,0x8c,0x00,0x80,0x03,0x3c,0x01,0x00,0x02,0x24,0x25,0x28,0xa3,0x00, +0x00,0x00,0xa4,0x8c,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x01,0x80,0x03,0x3c, +0x25,0xb0,0x02,0x3c,0x74,0x05,0x63,0x24,0x18,0x03,0x42,0x34,0x00,0x00,0x43,0xac, +0x04,0x00,0x82,0x8c,0x02,0x00,0x83,0x94,0x00,0x80,0x07,0x3c,0x25,0x28,0x47,0x00, +0x00,0x00,0xa2,0x8c,0x10,0x00,0x02,0x24,0x13,0x00,0x62,0x10,0x11,0x00,0x66,0x28, +0x06,0x00,0xc0,0x10,0x20,0x00,0x02,0x24,0x08,0x00,0x02,0x24,0x17,0x00,0x62,0x10, +0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x01,0x00,0x02,0x24,0xfd,0xff,0x62,0x14, +0x00,0x00,0x00,0x00,0x08,0x00,0x83,0x8c,0x00,0x00,0x00,0x00,0x00,0x00,0xa3,0xac, +0x04,0x00,0x82,0x8c,0x00,0x00,0x00,0x00,0x25,0x10,0x47,0x00,0x00,0x00,0x42,0x8c, +0x08,0x00,0xe0,0x03,0x01,0x00,0x02,0x24,0x08,0x00,0x82,0x8c,0x00,0x00,0x00,0x00, +0x00,0x00,0xa2,0xa4,0x04,0x00,0x83,0x8c,0x00,0x00,0x00,0x00,0x25,0x18,0x67,0x00, +0x00,0x00,0x62,0x94,0x08,0x00,0xe0,0x03,0x01,0x00,0x02,0x24,0x08,0x00,0x82,0x8c, +0x00,0x00,0x00,0x00,0x00,0x00,0xa2,0xa0,0x04,0x00,0x83,0x8c,0x00,0x00,0x00,0x00, +0x25,0x18,0x67,0x00,0x00,0x00,0x62,0x90,0x08,0x00,0xe0,0x03,0x01,0x00,0x02,0x24, +0xe0,0xff,0xbd,0x27,0x14,0x00,0xb1,0xaf,0x02,0x80,0x11,0x3c,0x1c,0x00,0xbf,0xaf, +0x18,0x00,0xb2,0xaf,0x10,0x00,0xb0,0xaf,0x68,0x15,0x31,0x26,0xe4,0x64,0x30,0x96, +0x02,0x80,0x02,0x3c,0x01,0x80,0x03,0x3c,0x25,0x80,0x02,0x02,0x25,0xb0,0x02,0x3c, +0x38,0x06,0x63,0x24,0x18,0x03,0x42,0x34,0x60,0x00,0x04,0x26,0x80,0x00,0x05,0x26, +0x00,0x00,0x43,0xac,0xab,0x45,0x00,0x0c,0x03,0x00,0x06,0x24,0x21,0x20,0x00,0x02, +0x21,0x28,0x00,0x00,0x97,0x45,0x00,0x0c,0x08,0x00,0x06,0x24,0xe4,0x64,0x22,0x8e, +0x0c,0x00,0x03,0x24,0x0c,0x00,0x43,0xae,0x08,0x00,0x42,0xae,0x12,0x00,0x02,0x24, +0x14,0x00,0x42,0xae,0x21,0x20,0x40,0x02,0x1c,0x00,0xbf,0x8f,0x18,0x00,0xb2,0x8f, +0x14,0x00,0xb1,0x8f,0x10,0x00,0xb0,0x8f,0x8b,0x07,0x00,0x08,0x20,0x00,0xbd,0x27, +0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00, +0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00, +0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00, +0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00, +0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00, +0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00, +0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00, +0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00, +0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00, +0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,0x08,0x00,0xe0,0x03,0x01,0x00,0x02,0x24, +0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,0x08,0x00,0xe0,0x03,0x01,0x00,0x02,0x24, +0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00, +0x08,0x00,0xe0,0x03,0x01,0x00,0x02,0x24,0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00, +0x08,0x00,0xe0,0x03,0x01,0x00,0x02,0x24,0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00, +0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x01,0x00,0x02,0x24, +0x08,0x00,0xe0,0x03,0x01,0x00,0x02,0x24,0x02,0x80,0x02,0x3c,0x21,0x48,0x80,0x00, +0x68,0x15,0x48,0x24,0x21,0x38,0x00,0x00,0x21,0x28,0x27,0x01,0x00,0x00,0xa2,0x90, +0x21,0x20,0xe8,0x00,0x01,0x00,0xe7,0x24,0x38,0x4c,0x82,0xa0,0x1e,0x00,0xa3,0x90, +0x1e,0x00,0xe6,0x28,0x56,0x4c,0x83,0xa0,0x3c,0x00,0xa2,0x90,0x00,0x00,0x00,0x00, +0x74,0x4c,0x82,0xa0,0x5a,0x00,0xa3,0x90,0xf3,0xff,0xc0,0x14,0x92,0x4c,0x83,0xa0, +0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,0x08,0x00,0xe0,0x03,0x01,0x00,0x02,0x24, +0x20,0xbd,0x03,0x3c,0x58,0x00,0x63,0x34,0x00,0x00,0x62,0x90,0x0f,0x27,0x07,0x24, +0x20,0x00,0x42,0x34,0x00,0x00,0x62,0xa0,0xff,0xff,0xe7,0x24,0xff,0xff,0xe1,0x04, +0xff,0xff,0xe7,0x24,0x62,0xbd,0x04,0x3c,0x24,0x10,0x82,0x34,0x00,0x00,0x40,0xa0, +0x28,0x10,0x83,0x34,0x0c,0x11,0x86,0x34,0x0e,0x00,0x02,0x24,0x00,0x00,0x60,0xa0, +0x00,0x11,0x85,0x34,0x00,0x00,0xc2,0xa0,0x00,0x00,0xa7,0x8c,0xdf,0xff,0x02,0x24, +0x10,0x00,0x86,0x34,0x24,0x38,0xe2,0x00,0x49,0x0c,0x03,0x24,0xcf,0xff,0x02,0x24, +0x00,0x00,0xc3,0xac,0x04,0x00,0x84,0x34,0x00,0x00,0xa7,0xac,0x24,0x38,0xe2,0x00, +0x41,0x0c,0x02,0x24,0x00,0x00,0xa7,0xac,0x00,0x00,0x80,0xac,0x00,0x00,0xc2,0xac, +0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,0xd0,0xff,0xbd,0x27,0x25,0xb0,0x03,0x3c, +0x01,0x80,0x02,0x3c,0xb0,0x03,0x68,0x34,0x1c,0x00,0xb1,0xaf,0x18,0x03,0x63,0x34, +0xd8,0xff,0x91,0x24,0xa0,0x08,0x42,0x24,0x00,0x00,0x62,0xac,0x28,0x00,0xbf,0xaf, +0x00,0x00,0x11,0xad,0x24,0x00,0xb3,0xaf,0x20,0x00,0xb2,0xaf,0x18,0x00,0xb0,0xaf, +0x02,0x80,0x13,0x3c,0x00,0x00,0x23,0x96,0x68,0x15,0x73,0x26,0xff,0xff,0x32,0x32, +0x40,0x10,0x02,0x3c,0x78,0x64,0x65,0x8e,0x25,0x90,0x42,0x02,0x02,0x80,0x10,0x3c, +0x8c,0x96,0x10,0x26,0x20,0x00,0x42,0x26,0x00,0x00,0x03,0xad,0x20,0x00,0x06,0x24, +0x00,0x00,0x02,0xad,0x21,0x38,0x00,0x02,0x0c,0x00,0x03,0xae,0x0a,0x00,0x04,0x24, +0x64,0x01,0x00,0x0c,0x08,0x00,0x02,0xae,0x04,0x00,0x23,0x8e,0xff,0xe0,0x02,0x24, +0x28,0x00,0x04,0x24,0x24,0x18,0x62,0x00,0x00,0x10,0x63,0x34,0x02,0x00,0x24,0xa2, +0x04,0x00,0x23,0xae,0x0c,0x00,0x02,0x8e,0x0a,0x00,0x04,0x24,0xf8,0xff,0x42,0x24, +0x4d,0x01,0x00,0x0c,0x00,0x00,0x22,0xa6,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34, +0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,0x0c,0x00,0x07,0x8e,0x20,0x10,0x06,0x3c, +0x21,0x28,0x40,0x02,0x20,0x00,0xe7,0x24,0x00,0xfe,0xc6,0x34,0xff,0xff,0xe7,0x30, +0x01,0x00,0x11,0x24,0x0a,0x00,0x04,0x24,0x10,0x01,0x00,0x0c,0x10,0x00,0xb1,0xaf, +0xd5,0x4a,0x63,0x92,0x2a,0xb0,0x10,0x3c,0x32,0x00,0x02,0x36,0x01,0x00,0x63,0x24, +0x00,0x00,0x43,0xa0,0x4d,0x01,0x00,0x0c,0x0a,0x00,0x04,0x24,0xc9,0x64,0x62,0x92, +0x00,0x00,0x00,0x00,0x01,0x00,0x42,0x24,0xc9,0x64,0x62,0xa2,0x00,0x60,0x01,0x40, +0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40,0x01,0x00,0x10,0x36,0x00,0x00,0x11,0xa2, +0x28,0x00,0xbf,0x8f,0x24,0x00,0xb3,0x8f,0x20,0x00,0xb2,0x8f,0x1c,0x00,0xb1,0x8f, +0x18,0x00,0xb0,0x8f,0x21,0x10,0x00,0x00,0x08,0x00,0xe0,0x03,0x30,0x00,0xbd,0x27, +0x25,0xb0,0x05,0x3c,0x01,0x80,0x03,0x3c,0x21,0x38,0x80,0x00,0x18,0x03,0xa2,0x34, +0xe8,0x09,0x63,0x24,0x01,0x00,0x04,0x24,0x00,0x00,0x43,0xac,0x35,0x00,0xe4,0x10, +0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x10,0x20,0x08,0xa2,0x34,0x02,0x00,0x02,0x24, +0x83,0x00,0xe2,0x10,0x03,0x00,0x02,0x24,0x5a,0x00,0xe2,0x10,0x00,0x00,0x00,0x00, +0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x02,0x80,0x03,0x3c,0x00,0x00,0x44,0x8c, +0x68,0x15,0x66,0x24,0x70,0x08,0x02,0x24,0xe0,0x08,0x03,0x24,0x74,0x4b,0xc2,0xac, +0x40,0x08,0x02,0x24,0x78,0x4b,0xc3,0xac,0x84,0x4b,0xc2,0xac,0x78,0x08,0x03,0x24, +0x0c,0x08,0x02,0x24,0x88,0x4b,0xc3,0xac,0x8c,0x4b,0xc2,0xac,0x10,0x08,0x03,0x24, +0x20,0x08,0x02,0x24,0x90,0x4b,0xc3,0xac,0x94,0x4b,0xc2,0xac,0x24,0x08,0x03,0x24, +0x58,0x08,0x02,0x24,0x98,0x4b,0xc3,0xac,0x9c,0x4b,0xc2,0xac,0x50,0x0c,0x03,0x24, +0x54,0x0c,0x02,0x24,0xa0,0x4b,0xc3,0xac,0xa4,0x4b,0xc2,0xac,0x14,0x0c,0x03,0x24, +0x10,0x0c,0x02,0x24,0x60,0x08,0x05,0x24,0xa8,0x4b,0xc3,0xac,0xac,0x4b,0xc2,0xac, +0x80,0x0c,0x03,0x24,0x84,0x0c,0x02,0x24,0x00,0x01,0x84,0x30,0xb4,0x4b,0xc2,0xac, +0x80,0x4b,0xc5,0xac,0xb0,0x4b,0xc3,0xac,0x71,0x4b,0xc0,0xa0,0x7c,0x4b,0xc5,0xac, +0x02,0x00,0x80,0x10,0xa0,0x08,0x02,0x24,0xb8,0x08,0x02,0x24,0x08,0x00,0xe0,0x03, +0xb8,0x4b,0xc2,0xac,0x28,0x08,0xa2,0x34,0x02,0x80,0x03,0x3c,0x00,0x00,0x44,0x8c, +0x68,0x15,0x66,0x24,0x70,0x08,0x02,0x24,0xe0,0x08,0x03,0x24,0x74,0x4b,0xc2,0xac, +0x44,0x08,0x02,0x24,0x78,0x4b,0xc3,0xac,0x84,0x4b,0xc2,0xac,0x78,0x08,0x03,0x24, +0x0c,0x08,0x02,0x24,0x88,0x4b,0xc3,0xac,0x8c,0x4b,0xc2,0xac,0x14,0x08,0x03,0x24, +0x28,0x08,0x02,0x24,0x90,0x4b,0xc3,0xac,0x94,0x4b,0xc2,0xac,0x2c,0x08,0x03,0x24, +0x58,0x08,0x02,0x24,0x98,0x4b,0xc3,0xac,0x9c,0x4b,0xc2,0xac,0x58,0x0c,0x03,0x24, +0x5c,0x0c,0x02,0x24,0xa0,0x4b,0xc3,0xac,0xa4,0x4b,0xc2,0xac,0x1c,0x0c,0x03,0x24, +0x18,0x0c,0x02,0x24,0x64,0x08,0x05,0x24,0xa8,0x4b,0xc3,0xac,0xac,0x4b,0xc2,0xac, +0x88,0x0c,0x03,0x24,0x8c,0x0c,0x02,0x24,0x00,0x01,0x84,0x30,0xb4,0x4b,0xc2,0xac, +0x71,0x4b,0xc7,0xa0,0x80,0x4b,0xc5,0xac,0xb0,0x4b,0xc3,0xac,0x7c,0x4b,0xc5,0xac, +0xd6,0xff,0x80,0x10,0xa4,0x08,0x02,0x24,0xbc,0x08,0x02,0x24,0x08,0x00,0xe0,0x03, +0xb8,0x4b,0xc2,0xac,0x02,0x80,0x02,0x3c,0x68,0x15,0x42,0x24,0xac,0x08,0x03,0x24, +0xb8,0x4b,0x43,0xac,0x74,0x08,0x03,0x24,0xe4,0x08,0x04,0x24,0x74,0x4b,0x43,0xac, +0x4c,0x08,0x03,0x24,0x78,0x4b,0x44,0xac,0x84,0x4b,0x43,0xac,0x7c,0x08,0x04,0x24, +0x0c,0x08,0x03,0x24,0x88,0x4b,0x44,0xac,0x8c,0x4b,0x43,0xac,0x1c,0x08,0x04,0x24, +0x38,0x08,0x03,0x24,0x90,0x4b,0x44,0xac,0x94,0x4b,0x43,0xac,0x3c,0x08,0x04,0x24, +0x5c,0x08,0x03,0x24,0x98,0x4b,0x44,0xac,0x9c,0x4b,0x43,0xac,0x68,0x0c,0x04,0x24, +0x6c,0x0c,0x03,0x24,0xa0,0x4b,0x44,0xac,0xa4,0x4b,0x43,0xac,0x2c,0x0c,0x04,0x24, +0x28,0x0c,0x03,0x24,0x6c,0x08,0x05,0x24,0xa8,0x4b,0x44,0xac,0xac,0x4b,0x43,0xac, +0x98,0x0c,0x04,0x24,0x9c,0x0c,0x03,0x24,0x71,0x4b,0x47,0xa0,0x80,0x4b,0x45,0xac, +0xb0,0x4b,0x44,0xac,0xb4,0x4b,0x43,0xac,0x08,0x00,0xe0,0x03,0x7c,0x4b,0x45,0xac, +0x02,0x80,0x02,0x3c,0x68,0x15,0x42,0x24,0xa8,0x08,0x03,0x24,0xb8,0x4b,0x43,0xac, +0x74,0x08,0x03,0x24,0xe4,0x08,0x04,0x24,0x74,0x4b,0x43,0xac,0x48,0x08,0x03,0x24, +0x78,0x4b,0x44,0xac,0x84,0x4b,0x43,0xac,0x7c,0x08,0x04,0x24,0x0c,0x08,0x03,0x24, +0x88,0x4b,0x44,0xac,0x8c,0x4b,0x43,0xac,0x18,0x08,0x04,0x24,0x30,0x08,0x03,0x24, +0x90,0x4b,0x44,0xac,0x94,0x4b,0x43,0xac,0x34,0x08,0x04,0x24,0x5c,0x08,0x03,0x24, +0x98,0x4b,0x44,0xac,0x9c,0x4b,0x43,0xac,0x60,0x0c,0x04,0x24,0x64,0x0c,0x03,0x24, +0xa0,0x4b,0x44,0xac,0xa4,0x4b,0x43,0xac,0x24,0x0c,0x04,0x24,0x20,0x0c,0x03,0x24, +0x68,0x08,0x05,0x24,0xa8,0x4b,0x44,0xac,0xac,0x4b,0x43,0xac,0x90,0x0c,0x04,0x24, +0x94,0x0c,0x03,0x24,0x71,0x4b,0x47,0xa0,0x80,0x4b,0x45,0xac,0xb0,0x4b,0x44,0xac, +0xb4,0x4b,0x43,0xac,0x08,0x00,0xe0,0x03,0x7c,0x4b,0x45,0xac,0x36,0x43,0x00,0x08, +0x21,0x18,0x00,0x00,0x20,0x00,0x62,0x2c,0x06,0x00,0x40,0x10,0x00,0x00,0x00,0x00, +0x06,0x10,0x64,0x00,0x01,0x00,0x42,0x30,0xfa,0xff,0x40,0x10,0x01,0x00,0x63,0x24, +0xff,0xff,0x63,0x24,0x08,0x00,0xe0,0x03,0x21,0x10,0x60,0x00,0xd8,0xff,0xbd,0x27, +0x25,0xb0,0x02,0x3c,0x18,0x00,0xb2,0xaf,0x21,0x90,0x82,0x00,0xff,0xff,0x02,0x24, +0x1c,0x00,0xb3,0xaf,0x14,0x00,0xb1,0xaf,0x20,0x00,0xbf,0xaf,0x10,0x00,0xb0,0xaf, +0x21,0x88,0xa0,0x00,0x21,0x20,0xa0,0x00,0x21,0x18,0x40,0x02,0x10,0x00,0xa2,0x10, +0x21,0x98,0xc0,0x00,0x00,0x00,0x50,0x8e,0x31,0x43,0x00,0x0c,0x00,0x00,0x00,0x00, +0x04,0x10,0x53,0x00,0x27,0x18,0x11,0x00,0x25,0x18,0x62,0x00,0x24,0x18,0x70,0x00, +0x00,0x00,0x43,0xae,0x20,0x00,0xbf,0x8f,0x1c,0x00,0xb3,0x8f,0x18,0x00,0xb2,0x8f, +0x14,0x00,0xb1,0x8f,0x10,0x00,0xb0,0x8f,0x08,0x00,0xe0,0x03,0x28,0x00,0xbd,0x27, +0x20,0x00,0xbf,0x8f,0x1c,0x00,0xb3,0x8f,0x18,0x00,0xb2,0x8f,0x14,0x00,0xb1,0x8f, +0x10,0x00,0xb0,0x8f,0x28,0x00,0xbd,0x27,0x00,0x00,0x66,0xac,0x08,0x00,0xe0,0x03, +0x00,0x00,0x00,0x00,0x02,0x80,0x02,0x3c,0x21,0x30,0x80,0x00,0xec,0x60,0x44,0x8c, +0x3d,0x43,0x00,0x08,0xff,0xff,0x05,0x24,0xe0,0xff,0xbd,0x27,0x25,0xb0,0x02,0x3c, +0x18,0x00,0xbf,0xaf,0x14,0x00,0xb1,0xaf,0x10,0x00,0xb0,0xaf,0x21,0x20,0x82,0x00, +0x00,0x00,0x90,0x8c,0x21,0x88,0xa0,0x00,0x31,0x43,0x00,0x0c,0x21,0x20,0xa0,0x00, +0x24,0x80,0x11,0x02,0x06,0x10,0x50,0x00,0x18,0x00,0xbf,0x8f,0x14,0x00,0xb1,0x8f, +0x10,0x00,0xb0,0x8f,0x08,0x00,0xe0,0x03,0x20,0x00,0xbd,0x27,0xd0,0xff,0xbd,0x27, +0x14,0x00,0xb1,0xaf,0x02,0x80,0x11,0x3c,0x28,0x00,0xbf,0xaf,0x20,0x00,0xb4,0xaf, +0x1c,0x00,0xb3,0xaf,0x18,0x00,0xb2,0xaf,0x24,0x00,0xb5,0xaf,0x10,0x00,0xb0,0xaf, +0x68,0x15,0x31,0x26,0x98,0x4b,0x22,0x8e,0x25,0xb0,0x12,0x3c,0x24,0x08,0x53,0x36, +0x21,0x10,0x52,0x00,0x00,0x00,0x70,0x8e,0x00,0x00,0x55,0x8c,0x7f,0x80,0x03,0x3c, +0xff,0x7f,0x02,0x3c,0xff,0xff,0x63,0x34,0xff,0xff,0x42,0x34,0x24,0x10,0x02,0x02, +0x24,0x18,0xa3,0x02,0xc0,0x25,0x04,0x00,0x25,0x18,0x64,0x00,0x00,0x80,0x14,0x3c, +0x00,0x00,0x62,0xae,0x01,0x00,0x04,0x24,0x84,0x0a,0x00,0x0c,0x25,0xa8,0x74,0x00, +0x98,0x4b,0x22,0x8e,0x25,0x80,0x14,0x02,0x01,0x00,0x04,0x24,0x21,0x10,0x52,0x00, +0x00,0x00,0x55,0xac,0x84,0x0a,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0xae, +0x84,0x0a,0x00,0x0c,0x01,0x00,0x04,0x24,0xb8,0x4b,0x24,0x8e,0x0f,0x00,0x05,0x3c, +0x28,0x00,0xbf,0x8f,0x24,0x00,0xb5,0x8f,0x20,0x00,0xb4,0x8f,0x1c,0x00,0xb3,0x8f, +0x18,0x00,0xb2,0x8f,0x14,0x00,0xb1,0x8f,0x10,0x00,0xb0,0x8f,0xff,0xff,0xa5,0x34, +0x68,0x43,0x00,0x08,0x30,0x00,0xbd,0x27,0xe0,0xff,0xbd,0x27,0x14,0x00,0xb1,0xaf, +0x02,0x80,0x11,0x3c,0x10,0x00,0xb0,0xaf,0x18,0x00,0xbf,0xaf,0x68,0x15,0x27,0x26, +0x73,0x4b,0xe5,0x90,0x01,0x80,0x03,0x3c,0x25,0xb0,0x02,0x3c,0xb0,0x0e,0x63,0x24, +0x18,0x03,0x42,0x34,0x02,0x00,0x06,0x24,0x00,0x00,0x43,0xac,0x34,0x00,0xa6,0x10, +0x21,0x80,0x80,0x00,0x03,0x00,0x03,0x24,0x3a,0x00,0xa3,0x10,0x2e,0x00,0x02,0x2e, +0x10,0x00,0x02,0x2e,0x07,0x00,0x40,0x10,0x00,0x00,0x00,0x00,0xff,0x00,0x04,0x32, +0x18,0x00,0xbf,0x8f,0x14,0x00,0xb1,0x8f,0x10,0x00,0xb0,0x8f,0x79,0x43,0x00,0x08, +0x20,0x00,0xbd,0x27,0xfa,0xff,0xa6,0x14,0xff,0x00,0x04,0x32,0x71,0x4b,0xe4,0x90, +0x01,0x00,0x02,0x24,0x33,0x00,0x82,0x10,0x02,0x00,0x82,0x28,0x38,0x00,0x40,0x14, +0x00,0x00,0x00,0x00,0x38,0x00,0x85,0x10,0x68,0x15,0x22,0x26,0x2e,0x00,0x83,0x10, +0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x24,0x68,0x43,0x00,0x0c,0xff,0xff,0x05,0x24, +0xff,0xfc,0x06,0x3c,0xff,0xff,0xc6,0x34,0x24,0x30,0x46,0x00,0x00,0x08,0x04,0x24, +0x3d,0x43,0x00,0x0c,0xff,0xff,0x05,0x24,0x68,0x15,0x22,0x26,0x71,0x4b,0x44,0x90, +0x01,0x00,0x03,0x24,0x07,0x00,0x83,0x10,0x02,0x00,0x82,0x28,0x2c,0x00,0x40,0x14, +0x02,0x00,0x02,0x24,0x2c,0x00,0x82,0x10,0x03,0x00,0x02,0x24,0xdb,0xff,0x82,0x14, +0x00,0x00,0x00,0x00,0x68,0x15,0x22,0x26,0x74,0x4b,0x44,0x8c,0x0f,0x00,0x05,0x3c, +0x3d,0x43,0x00,0x0c,0x21,0x30,0x00,0x00,0xc2,0x43,0x00,0x08,0xff,0x00,0x04,0x32, +0x25,0x00,0x82,0x2c,0xcc,0xff,0x40,0x14,0x03,0x00,0x03,0x24,0x18,0x00,0xbf,0x8f, +0x14,0x00,0xb1,0x8f,0x10,0x00,0xb0,0x8f,0x21,0x10,0x00,0x00,0x08,0x00,0xe0,0x03, +0x20,0x00,0xbd,0x27,0xc7,0xff,0x40,0x14,0x10,0x00,0x02,0x2e,0x18,0x00,0xbf,0x8f, +0x14,0x00,0xb1,0x8f,0x10,0x00,0xb0,0x8f,0x21,0x10,0x00,0x00,0x08,0x00,0xe0,0x03, +0x20,0x00,0xbd,0x27,0x68,0x15,0x22,0x26,0x74,0x4b,0x44,0x8c,0x0f,0x00,0x05,0x3c, +0x3d,0x43,0x00,0x0c,0x0f,0x00,0x06,0x24,0xd4,0x43,0x00,0x08,0x00,0x08,0x04,0x24, +0xcc,0xff,0x80,0x14,0x68,0x15,0x22,0x26,0x74,0x4b,0x44,0x8c,0x0f,0x00,0x05,0x24, +0x3d,0x43,0x00,0x0c,0x0f,0x00,0x06,0x24,0xd4,0x43,0x00,0x08,0x00,0x08,0x04,0x24, +0xb2,0xff,0x80,0x14,0x00,0x00,0x00,0x00,0x68,0x15,0x22,0x26,0x74,0x4b,0x44,0x8c, +0x0f,0x00,0x05,0x24,0x3d,0x43,0x00,0x0c,0x21,0x30,0x00,0x00,0xc2,0x43,0x00,0x08, +0xff,0x00,0x04,0x32,0xe0,0xff,0xbd,0x27,0x14,0x00,0xb1,0xaf,0x02,0x80,0x11,0x3c, +0x68,0x15,0x28,0x26,0x73,0x4b,0x06,0x91,0x01,0x80,0x03,0x3c,0x25,0xb0,0x02,0x3c, +0x5c,0x10,0x63,0x24,0x18,0x03,0x42,0x34,0x02,0x00,0x07,0x24,0x18,0x00,0xb2,0xaf, +0x10,0x00,0xb0,0xaf,0x1c,0x00,0xbf,0xaf,0x00,0x00,0x43,0xac,0x21,0x90,0xa0,0x00, +0x39,0x00,0xc7,0x10,0xff,0x00,0x90,0x30,0x03,0x00,0x03,0x24,0x3f,0x00,0xc3,0x10, +0x2e,0x00,0x02,0x2e,0x10,0x00,0x02,0x2e,0x0c,0x00,0x40,0x10,0x00,0x00,0x00,0x00, +0x0f,0x00,0x04,0x3c,0xff,0xff,0x84,0x34,0x24,0x20,0x44,0x02,0x00,0x15,0x10,0x00, +0x1c,0x00,0xbf,0x8f,0x18,0x00,0xb2,0x8f,0x14,0x00,0xb1,0x8f,0x10,0x00,0xb0,0x8f, +0x25,0x20,0x44,0x00,0x63,0x43,0x00,0x08,0x20,0x00,0xbd,0x27,0xf5,0xff,0xc7,0x14, +0x0f,0x00,0x04,0x3c,0x71,0x4b,0x04,0x91,0x01,0x00,0x02,0x24,0x33,0x00,0x82,0x10, +0x02,0x00,0x82,0x28,0x38,0x00,0x40,0x14,0x00,0x00,0x00,0x00,0x38,0x00,0x86,0x10, +0x68,0x15,0x22,0x26,0x2e,0x00,0x83,0x10,0x00,0x00,0x00,0x00,0x00,0x08,0x04,0x24, +0x68,0x43,0x00,0x0c,0xff,0xff,0x05,0x24,0xff,0xfc,0x06,0x3c,0xff,0xff,0xc6,0x34, +0x24,0x30,0x46,0x00,0x00,0x08,0x04,0x24,0x3d,0x43,0x00,0x0c,0xff,0xff,0x05,0x24, +0x68,0x15,0x22,0x26,0x71,0x4b,0x44,0x90,0x01,0x00,0x03,0x24,0x07,0x00,0x83,0x10, +0x02,0x00,0x82,0x28,0x2c,0x00,0x40,0x14,0x02,0x00,0x02,0x24,0x2c,0x00,0x82,0x10, +0x03,0x00,0x02,0x24,0xd6,0xff,0x82,0x14,0x00,0x00,0x00,0x00,0x68,0x15,0x22,0x26, +0x74,0x4b,0x44,0x8c,0x0f,0x00,0x05,0x3c,0x3d,0x43,0x00,0x0c,0x21,0x30,0x00,0x00, +0x2f,0x44,0x00,0x08,0x0f,0x00,0x04,0x3c,0x25,0x00,0x02,0x2e,0xc7,0xff,0x40,0x14, +0x03,0x00,0x03,0x24,0x1c,0x00,0xbf,0x8f,0x18,0x00,0xb2,0x8f,0x14,0x00,0xb1,0x8f, +0x10,0x00,0xb0,0x8f,0x08,0x00,0xe0,0x03,0x20,0x00,0xbd,0x27,0xc1,0xff,0x40,0x14, +0x00,0x00,0x00,0x00,0x1c,0x00,0xbf,0x8f,0x18,0x00,0xb2,0x8f,0x14,0x00,0xb1,0x8f, +0x10,0x00,0xb0,0x8f,0x08,0x00,0xe0,0x03,0x20,0x00,0xbd,0x27,0x68,0x15,0x22,0x26, +0x74,0x4b,0x44,0x8c,0x0f,0x00,0x05,0x3c,0x3d,0x43,0x00,0x0c,0x0f,0x00,0x06,0x24, +0x46,0x44,0x00,0x08,0x00,0x08,0x04,0x24,0xcc,0xff,0x80,0x14,0x68,0x15,0x22,0x26, +0x74,0x4b,0x44,0x8c,0x0f,0x00,0x05,0x24,0x3d,0x43,0x00,0x0c,0x0f,0x00,0x06,0x24, +0x46,0x44,0x00,0x08,0x00,0x08,0x04,0x24,0xad,0xff,0x80,0x14,0x00,0x00,0x00,0x00, +0x68,0x15,0x22,0x26,0x74,0x4b,0x44,0x8c,0x0f,0x00,0x05,0x24,0x3d,0x43,0x00,0x0c, +0x21,0x30,0x00,0x00,0x2f,0x44,0x00,0x08,0x0f,0x00,0x04,0x3c,0xe8,0xff,0xbd,0x27, +0x10,0x00,0xb0,0xaf,0x21,0x80,0x80,0x00,0x14,0x00,0xbf,0xaf,0x79,0x43,0x00,0x0c, +0x21,0x20,0x00,0x00,0x40,0x01,0x44,0x34,0x21,0x18,0x40,0x00,0x1f,0x00,0x02,0x2e, +0x00,0x23,0x04,0x00,0x10,0x00,0x40,0x10,0x10,0x00,0x05,0x2e,0x00,0x01,0x64,0x34, +0x06,0x00,0xa0,0x10,0x00,0x23,0x04,0x00,0x21,0x10,0x00,0x02,0x14,0x00,0xbf,0x8f, +0x10,0x00,0xb0,0x8f,0x08,0x00,0xe0,0x03,0x18,0x00,0xbd,0x27,0x63,0x43,0x00,0x0c, +0xf1,0xff,0x10,0x26,0x21,0x10,0x00,0x02,0x14,0x00,0xbf,0x8f,0x10,0x00,0xb0,0x8f, +0x08,0x00,0xe0,0x03,0x18,0x00,0xbd,0x27,0x63,0x43,0x00,0x0c,0xe2,0xff,0x10,0x26, +0x21,0x10,0x00,0x02,0x14,0x00,0xbf,0x8f,0x10,0x00,0xb0,0x8f,0x08,0x00,0xe0,0x03, +0x18,0x00,0xbd,0x27,0x25,0xb0,0x02,0x3c,0x27,0x38,0x05,0x00,0x21,0x40,0x82,0x00, +0xff,0xff,0x02,0x24,0x07,0x00,0xa2,0x10,0x25,0x38,0xe6,0x00,0x00,0x00,0x02,0x8d, +0x00,0x00,0x00,0x00,0x24,0x10,0xe2,0x00,0x00,0x00,0x02,0xad,0x08,0x00,0xe0,0x03, +0x00,0x00,0x00,0x00,0x00,0x00,0x06,0xad,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00, +0x01,0x80,0x02,0x3c,0x25,0xb0,0x03,0x3c,0xe8,0x12,0x42,0x24,0x18,0x03,0x63,0x34, +0xd8,0xff,0xbd,0x27,0x00,0x00,0x62,0xac,0x0f,0x00,0x02,0x3c,0x14,0x00,0xb1,0xaf, +0xff,0xff,0x42,0x34,0x21,0x88,0xa0,0x00,0x1c,0x00,0xb3,0xaf,0x18,0x00,0xb2,0xaf, +0x20,0x00,0xbf,0xaf,0x10,0x00,0xb0,0xaf,0x21,0x90,0xc0,0x00,0x21,0x28,0xc0,0x00, +0x0a,0x00,0x22,0x12,0x21,0x98,0x80,0x00,0xac,0x43,0x00,0x0c,0x00,0x00,0x00,0x00, +0x21,0x20,0x20,0x02,0x31,0x43,0x00,0x0c,0x21,0x80,0x40,0x00,0x04,0x10,0x52,0x00, +0x27,0x28,0x11,0x00,0x25,0x28,0xa2,0x00,0x24,0x28,0xb0,0x00,0xff,0x00,0x64,0x32, +0x20,0x00,0xbf,0x8f,0x1c,0x00,0xb3,0x8f,0x18,0x00,0xb2,0x8f,0x14,0x00,0xb1,0x8f, +0x10,0x00,0xb0,0x8f,0x17,0x44,0x00,0x08,0x28,0x00,0xbd,0x27,0x01,0x80,0x03,0x3c, +0x25,0xb0,0x02,0x3c,0x74,0x13,0x63,0x24,0x18,0x03,0x42,0x34,0xe0,0xff,0xbd,0x27, +0x00,0x00,0x43,0xac,0x18,0x00,0xbf,0xaf,0x14,0x00,0xb1,0xaf,0x10,0x00,0xb0,0xaf, +0xac,0x43,0x00,0x0c,0x21,0x88,0xa0,0x00,0x21,0x80,0x40,0x00,0x31,0x43,0x00,0x0c, +0x21,0x20,0x20,0x02,0x24,0x80,0x11,0x02,0x06,0x10,0x50,0x00,0x18,0x00,0xbf,0x8f, +0x14,0x00,0xb1,0x8f,0x10,0x00,0xb0,0x8f,0x08,0x00,0xe0,0x03,0x20,0x00,0xbd,0x27, +0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00, +0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00, +0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00, +0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00, +0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00, +0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00, +0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00, +0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00, +0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00, +0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00, +0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00, +0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x01,0x00,0x02,0x24, +0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00, +0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00, +0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00, +0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00, +0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00, +0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00, +0xc8,0xff,0xbd,0x27,0x2c,0x00,0xb1,0xaf,0xff,0xff,0x05,0x24,0x21,0x88,0x80,0x00, +0x02,0x00,0x06,0x24,0x10,0x00,0xa4,0x27,0x34,0x00,0xbf,0xaf,0x30,0x00,0xb2,0xaf, +0x97,0x45,0x00,0x0c,0x28,0x00,0xb0,0xaf,0x08,0x00,0x30,0x96,0x02,0x80,0x02,0x3c, +0x21,0x28,0x00,0x00,0x25,0x80,0x02,0x02,0x21,0x20,0x00,0x02,0x97,0x45,0x00,0x0c, +0x10,0x00,0x06,0x24,0x20,0x00,0x02,0x96,0x24,0x00,0x04,0x26,0x10,0x00,0xa5,0x27, +0x03,0xff,0x42,0x30,0xc8,0x00,0x42,0x34,0x20,0x00,0x02,0xa6,0x9f,0x45,0x00,0x0c, +0x06,0x00,0x06,0x24,0x25,0xb0,0x03,0x3c,0x50,0x00,0x62,0x34,0x00,0x00,0x44,0x8c, +0x54,0x00,0x65,0x34,0x58,0x00,0x66,0x34,0x18,0x00,0xa4,0xaf,0x00,0x00,0xa2,0x8c, +0x5c,0x00,0x63,0x34,0x2a,0x00,0x04,0x26,0x1c,0x00,0xa2,0xaf,0x00,0x00,0xc7,0x8c, +0x18,0x00,0xa5,0x27,0x06,0x00,0x06,0x24,0x20,0x00,0xa7,0xaf,0x00,0x00,0x62,0x8c, +0x1a,0x00,0x12,0x24,0x9f,0x45,0x00,0x0c,0x24,0x00,0xa2,0xaf,0x30,0x00,0x04,0x26, +0x20,0x00,0xa5,0x27,0x9f,0x45,0x00,0x0c,0x06,0x00,0x06,0x24,0x13,0x00,0x03,0x24, +0x14,0x00,0x23,0xae,0x0c,0x00,0x32,0xae,0x08,0x00,0x05,0x8e,0x04,0x00,0x04,0x8e, +0xff,0xdf,0x02,0x3c,0x14,0x00,0x06,0x8e,0xff,0xff,0x42,0x34,0x10,0x00,0x07,0x8e, +0xff,0xe0,0x03,0x24,0x24,0x28,0xa2,0x00,0x00,0x40,0x02,0x3c,0x24,0x20,0x83,0x00, +0x25,0x28,0xa2,0x00,0xff,0x81,0x03,0x24,0xfe,0xff,0x02,0x3c,0x24,0x30,0xc3,0x00, +0xff,0xff,0x42,0x34,0x00,0x12,0x84,0x34,0x00,0x80,0x03,0x3c,0x24,0x20,0x82,0x00, +0x25,0x38,0xe3,0x00,0x00,0x26,0xc6,0x34,0x80,0x00,0xa5,0x34,0x20,0x00,0x02,0x24, +0x00,0x00,0x12,0xa6,0x10,0x00,0x07,0xae,0x02,0x00,0x02,0xa2,0x14,0x00,0x06,0xae, +0x04,0x00,0x04,0xae,0x08,0x00,0x05,0xae,0x34,0x00,0xbf,0x8f,0x30,0x00,0xb2,0x8f, +0x2c,0x00,0xb1,0x8f,0x28,0x00,0xb0,0x8f,0x08,0x00,0xe0,0x03,0x38,0x00,0xbd,0x27, +0x93,0x45,0x00,0x08,0xff,0x00,0xa5,0x30,0x00,0x00,0x85,0xa0,0xff,0xff,0xc6,0x24, +0x01,0x00,0x84,0x24,0xfc,0xff,0xc0,0x14,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03, +0x00,0x00,0x00,0x00,0x05,0x00,0xc0,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x85,0xac, +0xff,0xff,0xc6,0x24,0xfd,0xff,0xc0,0x14,0x04,0x00,0x84,0x24,0x08,0x00,0xe0,0x03, +0x00,0x00,0x00,0x00,0x21,0x38,0x80,0x00,0x08,0x00,0xc0,0x10,0xff,0xff,0xc3,0x24, +0xff,0xff,0x06,0x24,0x00,0x00,0xa2,0x90,0xff,0xff,0x63,0x24,0x01,0x00,0xa5,0x24, +0x00,0x00,0xe2,0xa0,0xfb,0xff,0x66,0x14,0x01,0x00,0xe7,0x24,0x08,0x00,0xe0,0x03, +0x21,0x10,0x80,0x00,0x21,0x38,0x80,0x00,0x08,0x00,0xc0,0x10,0xff,0xff,0xc3,0x24, +0xff,0xff,0x06,0x24,0x00,0x00,0xa2,0x8c,0xff,0xff,0x63,0x24,0x04,0x00,0xa5,0x24, +0x00,0x00,0xe2,0xac,0xfb,0xff,0x66,0x14,0x04,0x00,0xe7,0x24,0x08,0x00,0xe0,0x03, +0x21,0x10,0x80,0x00,0x2b,0x10,0xa4,0x00,0x0d,0x00,0x40,0x14,0xff,0xff,0x02,0x24, +0xff,0xff,0xc6,0x24,0x08,0x00,0xc2,0x10,0x21,0x18,0x80,0x00,0xff,0xff,0x07,0x24, +0x00,0x00,0xa2,0x90,0xff,0xff,0xc6,0x24,0x01,0x00,0xa5,0x24,0x00,0x00,0x62,0xa0, +0xfb,0xff,0xc7,0x14,0x01,0x00,0x63,0x24,0x08,0x00,0xe0,0x03,0x21,0x10,0x80,0x00, +0x21,0x28,0xa6,0x00,0x21,0x18,0x86,0x00,0xff,0xff,0xc6,0x24,0xfa,0xff,0xc2,0x10, +0x00,0x00,0x00,0x00,0xff,0xff,0x07,0x24,0xff,0xff,0xa5,0x24,0x00,0x00,0xa2,0x90, +0xff,0xff,0x63,0x24,0xff,0xff,0xc6,0x24,0xfb,0xff,0xc7,0x14,0x00,0x00,0x62,0xa0, +0x08,0x00,0xe0,0x03,0x21,0x10,0x80,0x00,0x0c,0x00,0xc0,0x10,0x00,0x00,0x00,0x00, +0x00,0x00,0x82,0x90,0x00,0x00,0xa3,0x90,0x01,0x00,0x84,0x24,0x23,0x10,0x43,0x00, +0x00,0x16,0x02,0x00,0x03,0x16,0x02,0x00,0x04,0x00,0x40,0x14,0x01,0x00,0xa5,0x24, +0xff,0xff,0xc6,0x24,0xf6,0xff,0xc0,0x14,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03, +0x21,0x10,0xc0,0x00,0xea,0x45,0x00,0x08,0x21,0x18,0x86,0x00,0x00,0x00,0x82,0x90, +0x00,0x00,0x00,0x00,0x04,0x00,0x45,0x10,0x00,0x00,0x00,0x00,0x01,0x00,0x84,0x24, +0xfa,0xff,0x83,0x14,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x21,0x10,0x80,0x00, +0x09,0x00,0xc0,0x10,0xff,0xff,0xc3,0x24,0xff,0x00,0xa5,0x30,0xff,0xff,0x06,0x24, +0x00,0x00,0x82,0x90,0xff,0xff,0x63,0x24,0x05,0x00,0x45,0x10,0x01,0x00,0x84,0x24, +0xfb,0xff,0x66,0x14,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00, +0x08,0x00,0xe0,0x03,0xff,0xff,0x82,0x24,0x21,0x38,0x00,0x00,0x1f,0x00,0xc0,0x10, +0x21,0x18,0x00,0x00,0x02,0x80,0x02,0x3c,0x80,0x95,0x4b,0x24,0x00,0x00,0x87,0x90, +0x00,0x00,0xa3,0x90,0xff,0xff,0xc6,0x24,0x01,0x00,0x84,0x24,0x21,0x10,0xeb,0x00, +0x16,0x00,0xe0,0x10,0x01,0x00,0xa5,0x24,0x14,0x00,0x60,0x10,0x21,0x48,0x6b,0x00, +0x10,0x00,0xe3,0x10,0x20,0x00,0xe8,0x24,0x00,0x00,0x42,0x90,0x00,0x00,0x00,0x00, +0x01,0x00,0x42,0x30,0x02,0x00,0x40,0x10,0x20,0x00,0x6a,0x24,0xff,0x00,0x07,0x31, +0x00,0x00,0x22,0x91,0x00,0x00,0x00,0x00,0x01,0x00,0x42,0x30,0x02,0x00,0x40,0x10, +0xff,0x00,0xe7,0x30,0xff,0x00,0x43,0x31,0xff,0x00,0x63,0x30,0x03,0x00,0xe3,0x14, +0x00,0x00,0x00,0x00,0xe5,0xff,0xc0,0x14,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03, +0x23,0x10,0xe3,0x00,0x21,0x18,0x80,0x00,0x00,0x00,0xa2,0x90,0x01,0x00,0xa5,0x24, +0x00,0x00,0x82,0xa0,0xfc,0xff,0x40,0x14,0x01,0x00,0x84,0x24,0x08,0x00,0xe0,0x03, +0x21,0x10,0x60,0x00,0x21,0x38,0x80,0x00,0xff,0xff,0x03,0x24,0xff,0xff,0xc6,0x24, +0x06,0x00,0xc3,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0xa2,0x90,0x01,0x00,0xa5,0x24, +0x00,0x00,0x82,0xa0,0xf9,0xff,0x40,0x14,0x01,0x00,0x84,0x24,0x08,0x00,0xe0,0x03, +0x21,0x10,0xe0,0x00,0x00,0x00,0x82,0x80,0x39,0x46,0x00,0x08,0x21,0x18,0x80,0x00, +0x01,0x00,0x84,0x24,0x00,0x00,0x82,0x80,0x00,0x00,0x00,0x00,0xfc,0xff,0x40,0x14, +0x00,0x00,0x00,0x00,0x00,0x00,0xa2,0x90,0x01,0x00,0xa5,0x24,0x00,0x00,0x82,0xa0, +0xfc,0xff,0x40,0x14,0x01,0x00,0x84,0x24,0x08,0x00,0xe0,0x03,0x21,0x10,0x60,0x00, +0x12,0x00,0xc0,0x10,0x21,0x18,0x80,0x00,0x00,0x00,0x82,0x80,0x4a,0x46,0x00,0x08, +0x00,0x00,0x00,0x00,0x01,0x00,0x84,0x24,0x00,0x00,0x82,0x80,0x00,0x00,0x00,0x00, +0xfc,0xff,0x40,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0xa2,0x90,0x01,0x00,0xa5,0x24, +0x00,0x00,0x82,0xa0,0x05,0x00,0x40,0x10,0x01,0x00,0x84,0x24,0xff,0xff,0xc6,0x24, +0xf9,0xff,0xc0,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xa0,0x08,0x00,0xe0,0x03, +0x21,0x10,0x60,0x00,0x00,0x00,0x83,0x90,0x00,0x00,0xa2,0x90,0x01,0x00,0x84,0x24, +0x23,0x10,0x62,0x00,0x00,0x16,0x02,0x00,0x03,0x16,0x02,0x00,0x03,0x00,0x40,0x14, +0x01,0x00,0xa5,0x24,0xf7,0xff,0x60,0x14,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03, +0x00,0x00,0x00,0x00,0x21,0x10,0x00,0x00,0x0b,0x00,0xc0,0x10,0x00,0x00,0x00,0x00, +0x00,0x00,0xa2,0x90,0x00,0x00,0x83,0x90,0xff,0xff,0xc6,0x24,0x23,0x10,0x62,0x00, +0x00,0x16,0x02,0x00,0x03,0x16,0x02,0x00,0x03,0x00,0x40,0x14,0x01,0x00,0xa5,0x24, +0xf5,0xff,0x60,0x14,0x01,0x00,0x84,0x24,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00, +0x00,0x00,0x83,0x80,0x00,0x2e,0x05,0x00,0x21,0x10,0x80,0x00,0x7b,0x46,0x00,0x08, +0x03,0x2e,0x05,0x00,0x07,0x00,0x60,0x10,0x01,0x00,0x42,0x24,0x00,0x00,0x43,0x80, +0x00,0x00,0x00,0x00,0xfb,0xff,0x65,0x14,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03, +0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x00,0x00,0x00,0x82,0x80, +0x87,0x46,0x00,0x08,0x21,0x18,0x80,0x00,0x01,0x00,0x63,0x24,0x00,0x00,0x62,0x80, +0x00,0x00,0x00,0x00,0xfc,0xff,0x40,0x14,0x23,0x10,0x64,0x00,0x08,0x00,0xe0,0x03, +0x00,0x00,0x00,0x00,0xe0,0xff,0xbd,0x27,0x10,0x00,0xb0,0xaf,0x21,0x80,0xa0,0x00, +0x14,0x00,0xb1,0xaf,0x18,0x00,0xbf,0xaf,0x21,0x88,0x80,0x00,0x81,0x46,0x00,0x0c, +0x00,0x86,0x10,0x00,0x21,0x18,0x51,0x00,0x03,0x86,0x10,0x00,0x00,0x00,0x62,0x80, +0x00,0x00,0x00,0x00,0x0a,0x00,0x50,0x10,0x21,0x10,0x60,0x00,0xff,0xff,0x63,0x24, +0x2b,0x10,0x71,0x00,0xf9,0xff,0x40,0x10,0x21,0x10,0x00,0x00,0x18,0x00,0xbf,0x8f, +0x14,0x00,0xb1,0x8f,0x10,0x00,0xb0,0x8f,0x08,0x00,0xe0,0x03,0x20,0x00,0xbd,0x27, +0x18,0x00,0xbf,0x8f,0x14,0x00,0xb1,0x8f,0x10,0x00,0xb0,0x8f,0x08,0x00,0xe0,0x03, +0x20,0x00,0xbd,0x27,0x21,0x30,0x80,0x00,0x0d,0x00,0xa0,0x10,0xff,0xff,0xa3,0x24, +0x00,0x00,0x82,0x80,0x00,0x00,0x00,0x00,0x09,0x00,0x40,0x10,0x00,0x00,0x00,0x00, +0xff,0xff,0x05,0x24,0xff,0xff,0x63,0x24,0x05,0x00,0x65,0x10,0x01,0x00,0xc6,0x24, +0x00,0x00,0xc2,0x80,0x00,0x00,0x00,0x00,0xfa,0xff,0x40,0x14,0x00,0x00,0x00,0x00, +0x08,0x00,0xe0,0x03,0x23,0x10,0xc4,0x00,0x00,0x00,0x82,0x90,0x00,0x00,0x00,0x00, +0x19,0x00,0x40,0x10,0x21,0x40,0x00,0x00,0x00,0x00,0xa9,0x80,0x00,0x00,0x00,0x00, +0x17,0x00,0x20,0x11,0x21,0x30,0xa0,0x00,0x00,0x3e,0x02,0x00,0x03,0x3e,0x07,0x00, +0x21,0x18,0x20,0x01,0x15,0x00,0xe3,0x10,0x00,0x00,0x00,0x00,0x01,0x00,0xc6,0x24, +0x00,0x00,0xc2,0x90,0x00,0x00,0x00,0x00,0x00,0x1e,0x02,0x00,0x03,0x1e,0x03,0x00, +0xf8,0xff,0x60,0x14,0x00,0x16,0x02,0x00,0x03,0x16,0x02,0x00,0x06,0x00,0x40,0x10, +0x00,0x00,0x00,0x00,0x01,0x00,0x84,0x24,0x00,0x00,0x82,0x90,0x00,0x00,0x00,0x00, +0xeb,0xff,0x40,0x14,0x01,0x00,0x08,0x25,0x08,0x00,0xe0,0x03,0x21,0x10,0x00,0x01, +0x00,0x00,0xa2,0x90,0xcc,0x46,0x00,0x08,0x00,0x16,0x02,0x00,0x00,0x00,0xc2,0x90, +0xcc,0x46,0x00,0x08,0x00,0x16,0x02,0x00,0x00,0x00,0x87,0x90,0x00,0x00,0x00,0x00, +0x14,0x00,0xe0,0x10,0x21,0x10,0x80,0x00,0x00,0x00,0xa4,0x90,0x00,0x00,0x00,0x00, +0x00,0x1e,0x04,0x00,0x03,0x1e,0x03,0x00,0x09,0x00,0x60,0x10,0x21,0x30,0xa0,0x00, +0x00,0x3e,0x07,0x00,0x03,0x3e,0x07,0x00,0x0b,0x00,0xe3,0x10,0x01,0x00,0xc6,0x24, +0x00,0x00,0xc3,0x80,0x00,0x00,0x00,0x00,0xfb,0xff,0x60,0x14,0x00,0x00,0x00,0x00, +0x01,0x00,0x42,0x24,0x00,0x00,0x47,0x90,0x00,0x00,0x00,0x00,0xf0,0xff,0xe0,0x14, +0x00,0x00,0x00,0x00,0x21,0x10,0x00,0x00,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00, +0xe0,0xff,0xbd,0x27,0x14,0x00,0xb1,0xaf,0x10,0x00,0xb0,0xaf,0x18,0x00,0xbf,0xaf, +0x21,0x80,0x80,0x00,0x1d,0x00,0x80,0x10,0x21,0x88,0xa0,0x00,0xb8,0x46,0x00,0x0c, +0x21,0x20,0x00,0x02,0x21,0x80,0x02,0x02,0x00,0x00,0x02,0x82,0x21,0x28,0x20,0x02, +0x21,0x20,0x00,0x02,0x22,0x00,0x40,0x10,0x21,0x18,0x00,0x00,0xdc,0x46,0x00,0x0c, +0x00,0x00,0x00,0x00,0x05,0x00,0x40,0x10,0x21,0x18,0x40,0x00,0x00,0x00,0x42,0x80, +0x00,0x00,0x00,0x00,0x0a,0x00,0x40,0x14,0x00,0x00,0x00,0x00,0x02,0x80,0x02,0x3c, +0xa8,0x96,0x43,0xac,0x21,0x18,0x00,0x02,0x18,0x00,0xbf,0x8f,0x14,0x00,0xb1,0x8f, +0x10,0x00,0xb0,0x8f,0x21,0x10,0x60,0x00,0x08,0x00,0xe0,0x03,0x20,0x00,0xbd,0x27, +0x00,0x00,0x60,0xa0,0x0d,0x47,0x00,0x08,0x01,0x00,0x63,0x24,0x02,0x80,0x02,0x3c, +0xa8,0x96,0x50,0x8c,0x00,0x00,0x00,0x00,0xf3,0xff,0x00,0x12,0x21,0x18,0x00,0x00, +0xb8,0x46,0x00,0x0c,0x21,0x20,0x00,0x02,0x21,0x80,0x02,0x02,0x00,0x00,0x02,0x82, +0x21,0x28,0x20,0x02,0x21,0x20,0x00,0x02,0xe0,0xff,0x40,0x14,0x21,0x18,0x00,0x00, +0x18,0x00,0xbf,0x8f,0x14,0x00,0xb1,0x8f,0x10,0x00,0xb0,0x8f,0x02,0x80,0x02,0x3c, +0xa8,0x96,0x40,0xac,0x20,0x00,0xbd,0x27,0x08,0x00,0xe0,0x03,0x21,0x10,0x60,0x00, +0xe0,0xff,0xbd,0x27,0x18,0x00,0xb2,0xaf,0x14,0x00,0xb1,0xaf,0x1c,0x00,0xbf,0xaf, +0x10,0x00,0xb0,0xaf,0x00,0x00,0x90,0x8c,0x21,0x90,0x80,0x00,0x21,0x88,0xa0,0x00, +0x21,0x18,0x00,0x00,0x0f,0x00,0x00,0x12,0x21,0x20,0x00,0x02,0xb8,0x46,0x00,0x0c, +0x00,0x00,0x00,0x00,0x21,0x80,0x02,0x02,0x00,0x00,0x02,0x82,0x21,0x28,0x20,0x02, +0x21,0x20,0x00,0x02,0x07,0x00,0x40,0x10,0x21,0x18,0x00,0x00,0xdc,0x46,0x00,0x0c, +0x00,0x00,0x00,0x00,0x21,0x18,0x40,0x00,0x09,0x00,0x40,0x14,0x00,0x00,0x42,0xae, +0x21,0x18,0x00,0x02,0x1c,0x00,0xbf,0x8f,0x18,0x00,0xb2,0x8f,0x14,0x00,0xb1,0x8f, +0x10,0x00,0xb0,0x8f,0x21,0x10,0x60,0x00,0x08,0x00,0xe0,0x03,0x20,0x00,0xbd,0x27, +0x00,0x00,0x42,0x80,0x00,0x00,0x00,0x00,0xf5,0xff,0x40,0x10,0x01,0x00,0x64,0x24, +0x00,0x00,0x60,0xa0,0x46,0x47,0x00,0x08,0x00,0x00,0x44,0xae,0xd8,0xff,0xbd,0x27, +0x14,0x00,0xb1,0xaf,0x21,0x88,0x80,0x00,0x21,0x20,0xa0,0x00,0x1c,0x00,0xb3,0xaf, +0x18,0x00,0xb2,0xaf,0x20,0x00,0xbf,0xaf,0x10,0x00,0xb0,0xaf,0x81,0x46,0x00,0x0c, +0x21,0x98,0xa0,0x00,0x21,0x90,0x40,0x00,0x08,0x00,0x40,0x16,0x21,0x10,0x20,0x02, +0x20,0x00,0xbf,0x8f,0x1c,0x00,0xb3,0x8f,0x18,0x00,0xb2,0x8f,0x14,0x00,0xb1,0x8f, +0x10,0x00,0xb0,0x8f,0x08,0x00,0xe0,0x03,0x28,0x00,0xbd,0x27,0x81,0x46,0x00,0x0c, +0x21,0x20,0x20,0x02,0x21,0x80,0x40,0x00,0x2a,0x10,0x52,0x00,0x0a,0x00,0x40,0x14, +0x00,0x00,0x00,0x00,0x21,0x20,0x20,0x02,0x21,0x28,0x60,0x02,0x21,0x30,0x40,0x02, +0xd4,0x45,0x00,0x0c,0xff,0xff,0x10,0x26,0x0b,0x00,0x40,0x10,0x2a,0x18,0x12,0x02, +0xf8,0xff,0x60,0x10,0x01,0x00,0x31,0x26,0x20,0x00,0xbf,0x8f,0x1c,0x00,0xb3,0x8f, +0x18,0x00,0xb2,0x8f,0x14,0x00,0xb1,0x8f,0x10,0x00,0xb0,0x8f,0x21,0x10,0x00,0x00, +0x08,0x00,0xe0,0x03,0x28,0x00,0xbd,0x27,0x62,0x47,0x00,0x08,0x21,0x10,0x20,0x02, +0x01,0x80,0x02,0x3c,0xc0,0xff,0xbd,0x27,0x08,0x1e,0x44,0x24,0x25,0xb0,0x02,0x3c, +0x28,0x00,0xb4,0xaf,0x02,0x80,0x03,0x3c,0x25,0xb0,0x14,0x3c,0x18,0x03,0x42,0x34, +0x38,0x00,0xbe,0xaf,0x34,0x00,0xb7,0xaf,0x30,0x00,0xb6,0xaf,0x2c,0x00,0xb5,0xaf, +0x24,0x00,0xb3,0xaf,0x3c,0x00,0xbf,0xaf,0x20,0x00,0xb2,0xaf,0x1c,0x00,0xb1,0xaf, +0x18,0x00,0xb0,0xaf,0x68,0x15,0x73,0x24,0x00,0x00,0x44,0xac,0x02,0x80,0x16,0x3c, +0x02,0x80,0x15,0x3c,0xc4,0x02,0x9e,0x36,0x64,0x03,0x97,0x36,0x01,0x80,0x04,0x3c, +0x08,0x1e,0x82,0x24,0x18,0x03,0x83,0x36,0x00,0x00,0x62,0xac,0xa0,0x02,0x87,0x36, +0x00,0x00,0xe4,0x8c,0xd8,0x63,0x63,0x8e,0xff,0x0f,0x02,0x3c,0xff,0xff,0x46,0x34, +0x24,0x80,0x86,0x00,0x01,0x00,0x05,0x3c,0x01,0x00,0x63,0x24,0x2b,0x10,0xb0,0x00, +0x07,0x00,0x40,0x10,0xd8,0x63,0x63,0xae,0xa4,0x02,0x82,0x36,0x00,0x00,0x51,0x8c, +0x00,0xb0,0x03,0x3c,0x25,0x80,0x03,0x02,0x00,0x00,0x11,0xae,0x00,0x00,0xe0,0xac, +0xb0,0x02,0x84,0x36,0x00,0x00,0x82,0x8c,0x00,0x00,0x00,0x00,0x24,0x80,0x46,0x00, +0x2b,0x18,0xb0,0x00,0x08,0x00,0x60,0x10,0xc0,0x02,0x82,0x36,0x00,0xb0,0x02,0x3c, +0x25,0x80,0x02,0x02,0x00,0x00,0x11,0x8e,0xb4,0x02,0x82,0x36,0x00,0x00,0x51,0xac, +0x00,0x00,0x80,0xac,0xc0,0x02,0x82,0x36,0x00,0x00,0x50,0x8c,0xff,0x00,0x08,0x3c, +0xff,0xff,0x02,0x35,0x2b,0x10,0x50,0x00,0x47,0x00,0x40,0x10,0x00,0x00,0x00,0x00, +0x00,0x00,0x82,0x8e,0x00,0xff,0x06,0x3c,0xac,0x02,0x84,0x36,0x01,0x00,0x45,0x24, +0xbc,0x02,0x83,0x36,0xff,0x00,0xc2,0x34,0x00,0xfd,0x07,0x3c,0x00,0x00,0x85,0xac, +0x00,0x00,0x70,0xac,0x24,0x18,0x02,0x02,0x07,0x00,0xe2,0x34,0x00,0x00,0x85,0x8c, +0x52,0x03,0x62,0x10,0x25,0xb0,0x12,0x3c,0x2b,0x10,0x43,0x00,0xa2,0x00,0x40,0x14, +0xa4,0x00,0xe2,0x34,0x00,0xf8,0x04,0x3c,0x15,0x00,0x82,0x34,0x57,0x03,0x62,0x10, +0x2b,0x10,0x43,0x00,0xc8,0x00,0x40,0x14,0x00,0xf9,0x05,0x3c,0x00,0xf0,0x05,0x3c, +0x20,0x00,0xa2,0x34,0x67,0x03,0x62,0x10,0x2b,0x10,0x43,0x00,0x20,0x01,0x40,0x14, +0x10,0x00,0x82,0x34,0x70,0x03,0x65,0x10,0x2b,0x10,0xa3,0x00,0xc8,0x01,0x40,0x14, +0x02,0x00,0xa2,0x34,0x00,0xd0,0x02,0x3c,0x2a,0x02,0x62,0x10,0x2b,0x10,0x43,0x00, +0xaf,0x02,0x40,0x14,0x00,0xe0,0x02,0x3c,0x00,0xc0,0x02,0x3c,0xbb,0x03,0x62,0x10, +0xff,0x00,0x03,0x3c,0x00,0xf0,0x02,0x3c,0x24,0x30,0x02,0x02,0x18,0x00,0xc2,0x10, +0x02,0x1d,0x10,0x00,0x00,0x70,0x05,0x3c,0x24,0x10,0x05,0x02,0x02,0x4f,0x02,0x00, +0x0f,0x00,0x02,0x3c,0xff,0xff,0x42,0x34,0x00,0x50,0x07,0x3c,0xff,0x00,0x68,0x30, +0xff,0x00,0x04,0x32,0x96,0x01,0xc7,0x10,0x24,0x18,0x02,0x02,0x2b,0x10,0xe6,0x00, +0x8a,0x01,0x40,0x14,0x00,0x80,0x02,0x3c,0x00,0x20,0x02,0x3c,0x1a,0x03,0xc2,0x10, +0x2b,0x10,0x46,0x00,0x82,0x02,0x40,0x14,0x00,0x30,0x02,0x3c,0x17,0x03,0xc0,0x10, +0x80,0x10,0x08,0x00,0x00,0x10,0x02,0x3c,0x14,0x03,0xc2,0x10,0x80,0x10,0x08,0x00, +0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34, +0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,0x00,0x00,0xe2,0x92,0x25,0xb0,0x07,0x3c, +0xc8,0x7d,0xc2,0xa2,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40, +0xc8,0x7d,0xc2,0x92,0x00,0x00,0x00,0x00,0x01,0x00,0x42,0x30,0x4e,0x00,0x40,0x10, +0x02,0x80,0x03,0x3c,0x00,0x40,0x62,0x8e,0xf0,0xff,0x03,0x24,0xd7,0x42,0x60,0xa2, +0x24,0x10,0x43,0x00,0x01,0x00,0x42,0x34,0x00,0x40,0x62,0xae,0xc8,0x7d,0xc2,0x92, +0x00,0x00,0x00,0x00,0x02,0x00,0x42,0x30,0x3d,0x00,0x40,0x10,0x0f,0xff,0x03,0x24, +0x00,0x40,0x62,0x8e,0x00,0x00,0x00,0x00,0x24,0x10,0x43,0x00,0x10,0x00,0x42,0x34, +0x00,0x40,0x62,0xae,0xc8,0x7d,0xc2,0x92,0x00,0x00,0x00,0x00,0x04,0x00,0x42,0x30, +0x30,0x00,0x40,0x10,0xff,0xf0,0x03,0x24,0x00,0x40,0x62,0x8e,0x00,0x00,0x00,0x00, +0x24,0x10,0x43,0x00,0x00,0x01,0x42,0x34,0x25,0xb0,0x05,0x3c,0x00,0x40,0x62,0xae, +0x4c,0x00,0xa3,0x34,0x00,0x00,0x62,0x90,0x00,0x00,0x00,0x00,0x03,0x00,0x42,0x30, +0x05,0x00,0x40,0x14,0xff,0xff,0x02,0x3c,0x00,0x40,0x63,0x8e,0xff,0x0f,0x42,0x34, +0x24,0x18,0x62,0x00,0x00,0x40,0x63,0xae,0x00,0x7b,0xa4,0x8e,0x01,0x80,0x06,0x3c, +0x08,0x1f,0xc2,0x24,0x18,0x03,0xa3,0x34,0x00,0x7b,0xa6,0x26,0x00,0x00,0x62,0xac, +0x10,0x00,0x86,0x10,0x02,0x80,0x02,0x3c,0xbf,0x00,0xb2,0x34,0x68,0x15,0x51,0x24, +0x21,0x80,0xc0,0x00,0x00,0x00,0x42,0x92,0x00,0x00,0x00,0x00,0x04,0x00,0x42,0x2c, +0x09,0x00,0x40,0x10,0x02,0x80,0x07,0x3c,0x98,0x65,0x24,0x8e,0x8b,0x07,0x00,0x0c, +0x00,0x00,0x00,0x00,0x00,0x7b,0xa2,0x8e,0x00,0x00,0x00,0x00,0xf5,0xff,0x50,0x14, +0x00,0x00,0x00,0x00,0x02,0x80,0x07,0x3c,0x08,0x08,0xe4,0x24,0x21,0x28,0x00,0x00, +0x21,0x30,0x00,0x00,0x31,0x1c,0x00,0x0c,0x21,0x38,0x00,0x00,0x9a,0x47,0x00,0x08, +0x01,0x80,0x04,0x3c,0x00,0x40,0x62,0x8e,0x30,0x48,0x00,0x08,0x24,0x10,0x43,0x00, +0x00,0x40,0x62,0x8e,0x04,0x43,0x64,0x92,0x24,0x10,0x43,0x00,0x00,0x40,0x62,0xae, +0x27,0x48,0x00,0x08,0x04,0x43,0x64,0xae,0x68,0x15,0x66,0x24,0x00,0x40,0xc2,0x8c, +0xd7,0x42,0xc4,0x90,0xf0,0xff,0x03,0x24,0x24,0x10,0x43,0x00,0xb3,0xff,0x80,0x14, +0x00,0x40,0xc2,0xac,0x1c,0x00,0x04,0x24,0x58,0x0c,0xe5,0x34,0x50,0x0c,0xe3,0x34, +0x01,0x00,0x02,0x24,0xd7,0x42,0xc2,0xa0,0x00,0x00,0x64,0xa0,0x00,0x00,0xa4,0xa0, +0x1d,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0xb2,0x02,0x62,0x10,0x2b,0x10,0x43,0x00, +0x3f,0x00,0x40,0x14,0xaf,0x00,0xe2,0x34,0x20,0x00,0xe2,0x34,0xc0,0x02,0x62,0x10, +0x2b,0x10,0x43,0x00,0xe3,0x00,0x40,0x14,0x29,0x00,0xe2,0x34,0x15,0x00,0xe2,0x34, +0x0c,0x03,0x62,0x10,0x2b,0x10,0x43,0x00,0x9d,0x01,0x40,0x14,0x17,0x00,0xe2,0x34, +0x09,0x00,0xe2,0x34,0xd8,0x03,0x62,0x10,0x2b,0x10,0x62,0x00,0x81,0x02,0x40,0x14, +0x14,0x00,0xe2,0x34,0x64,0xff,0x62,0x14,0x00,0xf0,0x02,0x3c,0xff,0x00,0x07,0x3c, +0x00,0xff,0xe7,0x34,0x24,0x10,0x07,0x02,0x7a,0xff,0x40,0x10,0xc0,0x02,0x82,0x36, +0x04,0x43,0x64,0x92,0xff,0x00,0x02,0x3c,0x24,0x10,0x02,0x02,0x00,0xff,0x03,0x32, +0x02,0x14,0x02,0x00,0x02,0x1a,0x03,0x00,0xfb,0xff,0x45,0x24,0x1c,0x43,0x62,0xa2, +0x00,0x01,0x84,0x34,0xfb,0xff,0x66,0x24,0xc0,0x02,0x82,0x36,0x04,0x43,0x64,0xae, +0x1d,0x43,0x65,0xa2,0x1f,0x43,0x66,0xa2,0x1e,0x43,0x63,0xa2,0x00,0x00,0x40,0xac, +0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0x05,0x00,0xa2,0x34,0x91,0x02,0x62,0x10, +0x2b,0x10,0x43,0x00,0x8e,0x00,0x40,0x14,0x00,0x00,0x00,0x00,0xde,0x02,0x65,0x10, +0x2b,0x10,0xa3,0x00,0x32,0x01,0x40,0x14,0x02,0x00,0xa2,0x34,0x17,0x00,0x82,0x34, +0x61,0x04,0x62,0x10,0x2b,0x10,0x62,0x00,0xa9,0x03,0x40,0x14,0x18,0x00,0x82,0x34, +0x3d,0xff,0x62,0x14,0x00,0xf0,0x02,0x3c,0x74,0x0b,0x00,0x0c,0x00,0x00,0x00,0x00, +0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00, +0xa8,0x02,0x62,0x10,0x2b,0x10,0x43,0x00,0x95,0x00,0x40,0x14,0x0c,0x00,0xc2,0x34, +0xaa,0x00,0xe2,0x34,0xdc,0x02,0x62,0x10,0x2b,0x10,0x43,0x00,0xd9,0x00,0x40,0x14, +0xac,0x00,0xe2,0x34,0xa6,0x00,0xe2,0x34,0x1c,0x04,0x62,0x10,0x2b,0x10,0x62,0x00, +0x69,0x03,0x40,0x14,0xa7,0x00,0xe2,0x34,0x27,0xff,0x62,0x14,0x00,0xf0,0x02,0x3c, +0x00,0xff,0x02,0x32,0xff,0x00,0x04,0x3c,0x02,0x8a,0x02,0x00,0x24,0x18,0x04,0x02, +0x01,0x00,0x02,0x24,0xa6,0x04,0x22,0x12,0x02,0x1c,0x03,0x00,0x02,0x00,0x02,0x24, +0xc9,0x04,0x22,0x12,0x03,0x00,0x02,0x24,0xdf,0x04,0x22,0x12,0x04,0x00,0x02,0x24, +0xd1,0x04,0x22,0x12,0x08,0x00,0x02,0x24,0x2e,0x05,0x22,0x12,0x09,0x00,0x02,0x24, +0x1e,0x05,0x22,0x12,0x0a,0x00,0x02,0x24,0x0e,0x05,0x22,0x12,0x0b,0x00,0x02,0x24, +0xfe,0x04,0x22,0x12,0x0c,0x00,0x02,0x24,0x5e,0x05,0x22,0x12,0x0d,0x00,0x02,0x24, +0x4e,0x05,0x22,0x12,0x0e,0x00,0x02,0x24,0x3e,0x05,0x22,0x12,0x0f,0x00,0x02,0x24, +0x2e,0x05,0x22,0x12,0x10,0x00,0x02,0x24,0x22,0xff,0x22,0x16,0xc0,0x02,0x82,0x36, +0xc0,0x10,0x03,0x00,0x21,0x10,0x43,0x00,0x80,0x10,0x02,0x00,0x21,0x10,0x43,0x00, +0x80,0x10,0x02,0x00,0x21,0x10,0x53,0x00,0x4c,0x51,0x43,0x94,0x48,0x51,0x44,0x94, +0x25,0xb0,0x06,0x3c,0x00,0x1c,0x03,0x00,0x21,0x20,0x83,0x00,0x00,0x00,0xc4,0xaf, +0x58,0x51,0x45,0x8c,0x54,0x51,0x43,0x8c,0x50,0x51,0x44,0x94,0xc8,0x02,0xc6,0x34, +0x21,0x18,0x65,0x00,0x00,0x1c,0x03,0x00,0x21,0x20,0x83,0x00,0xc0,0x02,0x82,0x36, +0x00,0x00,0xc4,0xac,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00, +0x66,0x02,0x62,0x10,0x2b,0x10,0x43,0x00,0xbf,0x00,0x40,0x14,0x12,0x00,0x82,0x34, +0x00,0xf1,0x04,0x3c,0x01,0x00,0x82,0x34,0xc1,0x02,0x62,0x10,0x2b,0x10,0x43,0x00, +0xb7,0x01,0x40,0x14,0x02,0x00,0x82,0x34,0xe3,0xfe,0x64,0x14,0x00,0xf0,0x02,0x3c, +0xff,0x00,0x04,0x3c,0x00,0xff,0x84,0x34,0x24,0x10,0x04,0x02,0x02,0x8a,0x02,0x00, +0x80,0x1a,0x11,0x00,0x00,0xf4,0x63,0x24,0x94,0x00,0x82,0x36,0x00,0x00,0x51,0xa4, +0x26,0xb0,0x04,0x3c,0x42,0x89,0x03,0x00,0x98,0x00,0x86,0x36,0xff,0x01,0x02,0x24, +0x10,0x00,0x03,0x24,0x9a,0x00,0x85,0x36,0x00,0x00,0xa2,0xa4,0x7c,0x00,0x89,0x34, +0x00,0x00,0xc3,0xa4,0x01,0x00,0x02,0x24,0x04,0x00,0x03,0x24,0x96,0x00,0x87,0x36, +0x7a,0x00,0x84,0x34,0xb0,0x03,0x88,0x36,0x25,0xb0,0x06,0x3c,0x00,0x00,0xe2,0xa4, +0x44,0x00,0xc6,0x34,0x00,0x00,0x83,0xa0,0x00,0x00,0x11,0xad,0x00,0x00,0x31,0xa5, +0x00,0x00,0xc3,0x94,0xff,0xfd,0x02,0x24,0x24,0x18,0x62,0x00,0x00,0x00,0xc3,0xa4, +0x00,0x00,0xc2,0x94,0x00,0x00,0x00,0x00,0x00,0x02,0x42,0x34,0x00,0x00,0xc2,0xa4, +0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00, +0x65,0x01,0x67,0x10,0x2b,0x10,0xe3,0x00,0xc5,0x00,0x40,0x14,0x02,0x00,0xe2,0x34, +0x07,0x00,0xa2,0x34,0xfc,0x02,0x62,0x10,0x2b,0x10,0x62,0x00,0xa9,0x01,0x40,0x14, +0x20,0x00,0xa2,0x34,0xb0,0xfe,0x62,0x14,0x00,0xf0,0x02,0x3c,0xff,0x00,0x03,0x3c, +0x00,0xff,0x63,0x34,0x24,0x10,0x03,0x02,0x02,0x3a,0x02,0x00,0x80,0x04,0xe0,0x10, +0x02,0x80,0x04,0x3c,0x05,0x00,0x02,0x24,0xc2,0xfe,0xe2,0x14,0xc0,0x02,0x82,0x36, +0x02,0x80,0x06,0x3c,0x8f,0x7d,0xc2,0x90,0x00,0x00,0x00,0x00,0x00,0x00,0xc2,0xaf, +0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00, +0x2e,0x02,0x62,0x10,0x2b,0x10,0x43,0x00,0x98,0x00,0x40,0x14,0x0e,0x00,0xc2,0x34, +0x01,0x00,0xc2,0x34,0xab,0x03,0x62,0x10,0x2b,0x10,0x43,0x00,0x48,0x01,0x40,0x14, +0x00,0xff,0x02,0x3c,0x94,0xfe,0x66,0x14,0x00,0xf0,0x02,0x3c,0x5b,0x4e,0x00,0x0c, +0x21,0x20,0x00,0x00,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08, +0x00,0x00,0x00,0x00,0x4c,0x02,0x62,0x10,0x2b,0x10,0x43,0x00,0xa6,0x00,0x40,0x14, +0xa1,0x00,0xe2,0x34,0x22,0x00,0xe2,0x34,0xbd,0x02,0x62,0x10,0x2b,0x10,0x62,0x00, +0x88,0x01,0x40,0x14,0x00,0x20,0x02,0x3c,0x28,0x00,0xe2,0x34,0x82,0xfe,0x62,0x14, +0x00,0xf0,0x02,0x3c,0x0f,0x00,0x04,0x3c,0xff,0xff,0x85,0x34,0x60,0x00,0x06,0x24, +0xba,0x44,0x00,0x0c,0x24,0x00,0x04,0x24,0x84,0x0a,0x00,0x0c,0xe8,0x03,0x04,0x24, +0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40, +0x0f,0x00,0x06,0x3c,0x24,0x00,0x04,0x24,0xdd,0x44,0x00,0x0c,0xff,0xff,0xc5,0x34, +0x1f,0x00,0x51,0x30,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40, +0xb3,0x0a,0x00,0x0c,0x64,0x00,0x04,0x24,0xc0,0x02,0x82,0x36,0x00,0x00,0xd1,0xa3, +0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0x18,0x02,0xc2,0x10, +0x2b,0x10,0x46,0x00,0x01,0x01,0x40,0x14,0x00,0xa0,0x02,0x3c,0x00,0x60,0x02,0x3c, +0x04,0x00,0xc2,0x10,0x80,0x10,0x08,0x00,0x7a,0xfe,0xc5,0x14,0xc0,0x02,0x82,0x36, +0x80,0x10,0x08,0x00,0x21,0x10,0x48,0x00,0x21,0x10,0x53,0x00,0x21,0x10,0x49,0x00, +0xc1,0x43,0x44,0xa0,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08, +0x00,0x00,0x00,0x00,0x3f,0x03,0x62,0x10,0x2b,0x10,0x62,0x00,0xb6,0x02,0x40,0x14, +0xad,0x00,0xe2,0x34,0xc7,0x03,0x62,0x10,0xae,0x00,0xe2,0x34,0x4e,0xfe,0x62,0x14, +0x00,0xf0,0x02,0x3c,0xff,0x00,0x02,0x3c,0x24,0x20,0x02,0x02,0x00,0xff,0x05,0x32, +0x02,0x24,0x04,0x00,0x69,0x4f,0x00,0x0c,0x02,0x2a,0x05,0x00,0x00,0x00,0xc2,0xa3, +0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00, +0x4b,0x02,0x62,0x10,0x2b,0x10,0x62,0x00,0x17,0x01,0x40,0x14,0x03,0x00,0xa2,0x34, +0x82,0x03,0x62,0x10,0x08,0x00,0xa2,0x34,0x3b,0xfe,0x62,0x14,0x00,0xf0,0x02,0x3c, +0x00,0xff,0x02,0x32,0x02,0x82,0x02,0x00,0xcc,0x02,0x83,0x36,0x00,0x00,0x70,0xac, +0x12,0x04,0x00,0x12,0x01,0x00,0x02,0x24,0x9c,0x04,0x02,0x12,0x00,0x00,0x00,0x00, +0x7a,0x42,0x00,0x0c,0x21,0x20,0x00,0x00,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac, +0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0x4e,0x02,0x62,0x10,0x2b,0x10,0x62,0x00, +0xe4,0x00,0x40,0x14,0x00,0xff,0x02,0x32,0x13,0x00,0x82,0x34,0x4c,0x03,0x62,0x10, +0x14,0x00,0x82,0x34,0x24,0xfe,0x62,0x14,0x00,0xf0,0x02,0x3c,0xd3,0x0a,0x00,0x0c, +0xfd,0x00,0x04,0x24,0x10,0x10,0x03,0x3c,0xa0,0x00,0x82,0x36,0x10,0x10,0x63,0x34, +0x00,0xc0,0x07,0x3c,0x25,0xb0,0x06,0x3c,0x00,0x00,0x43,0xac,0xa4,0x00,0x84,0x36, +0x00,0xa1,0xe7,0x34,0xa8,0x00,0xc6,0x34,0xc0,0x02,0x82,0x36,0x00,0x00,0x80,0xac, +0x00,0x00,0xc7,0xac,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00, +0x60,0x02,0x62,0x10,0x2b,0x10,0x62,0x00,0xf6,0x00,0x40,0x14,0x03,0x00,0xa2,0x34, +0x4b,0x03,0x62,0x10,0x04,0x00,0xa2,0x34,0x0b,0xfe,0x62,0x14,0x00,0xf0,0x02,0x3c, +0xf4,0x63,0x62,0x92,0x00,0x00,0x00,0x00,0x00,0x00,0xc2,0xaf,0xc0,0x02,0x82,0x36, +0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0x61,0x02,0x62,0x10, +0x2b,0x10,0x62,0x00,0xfe,0x00,0x40,0x14,0x01,0x00,0x02,0x24,0x0f,0x00,0xc2,0x34, +0x63,0x03,0x62,0x10,0x10,0x00,0xc2,0x34,0xfb,0xfd,0x62,0x14,0x00,0xf0,0x02,0x3c, +0x00,0xff,0x03,0x32,0x00,0xff,0x02,0x34,0x9d,0x03,0x62,0x10,0xc0,0x02,0x82,0x36, +0x8c,0x65,0x60,0xae,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00, +0x47,0x02,0x62,0x10,0x2b,0x10,0x62,0x00,0x02,0x01,0x40,0x14,0x03,0x00,0xe2,0x34, +0x8d,0x03,0x62,0x10,0x04,0x00,0xe2,0x34,0xeb,0xfd,0x62,0x14,0x00,0xf0,0x02,0x3c, +0x1e,0x57,0x00,0x0c,0x00,0x00,0x00,0x00,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac, +0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0x9b,0x01,0x62,0x10,0x2b,0x10,0x43,0x00, +0xcf,0x00,0x40,0x14,0xa2,0x00,0xe2,0x34,0xa0,0x00,0xe2,0x34,0xde,0xfd,0x62,0x14, +0x00,0xf0,0x02,0x3c,0x00,0x0f,0x02,0x32,0x02,0x22,0x02,0x00,0x01,0x00,0x03,0x24, +0x3c,0x04,0x83,0x10,0x02,0x00,0x02,0x24,0x34,0x04,0x82,0x10,0x03,0x00,0x02,0x24, +0x46,0x03,0x82,0x10,0x00,0x00,0x00,0x00,0xde,0x4f,0x00,0x0c,0x21,0x20,0x00,0x00, +0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00, +0x46,0x02,0x62,0x10,0x2b,0x10,0x62,0x00,0xe6,0xfd,0x40,0x14,0xc0,0x02,0x82,0x36, +0x18,0x00,0xe2,0x34,0x45,0x03,0x62,0x10,0x19,0x00,0xe2,0x34,0xc6,0xfd,0x62,0x14, +0x00,0xf0,0x02,0x3c,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x94,0x0e,0x83,0x36, +0x9c,0x0e,0x82,0x36,0xa4,0x0e,0x84,0x36,0xac,0x0e,0x87,0x36,0x00,0x00,0x65,0x8c, +0x00,0x00,0x48,0x8c,0x00,0x00,0x8a,0x8c,0x00,0x00,0xe6,0x8c,0x02,0x80,0x07,0x3c, +0x68,0x15,0xed,0x24,0xb4,0x0e,0x82,0x36,0x00,0x00,0x47,0x8c,0x0c,0x40,0xa3,0x8d, +0xff,0x03,0x02,0x3c,0x10,0x40,0xa4,0x8d,0x24,0x28,0xa2,0x00,0x24,0x30,0xc2,0x00, +0xbc,0x0e,0x82,0x36,0x00,0x00,0x4b,0x8c,0x00,0xfc,0x02,0x24,0x02,0x2c,0x05,0x00, +0x24,0x18,0x62,0x00,0x02,0x34,0x06,0x00,0x24,0x20,0x82,0x00,0xc4,0x0e,0x82,0x36, +0x25,0x18,0x65,0x00,0x25,0x20,0x86,0x00,0x00,0x00,0x45,0x8c,0xff,0x03,0x06,0x3c, +0xf0,0xff,0x02,0x3c,0xff,0x03,0x42,0x34,0x24,0x38,0xe6,0x00,0x82,0x39,0x07,0x00, +0x24,0x20,0x82,0x00,0x24,0x40,0x06,0x01,0x08,0x40,0xa9,0x8d,0x25,0x20,0x87,0x00, +0xcc,0x0e,0x8c,0x36,0xff,0x03,0x07,0x3c,0x00,0x00,0x86,0x8d,0x24,0x18,0x62,0x00, +0x24,0x50,0x47,0x01,0x24,0x58,0x67,0x01,0x82,0x41,0x08,0x00,0xff,0x9f,0x02,0x3c, +0x0f,0xc0,0x07,0x3c,0xff,0xff,0xe7,0x34,0xff,0xff,0x42,0x34,0x25,0x18,0x68,0x00, +0x24,0x48,0x22,0x01,0x24,0x18,0x67,0x00,0xff,0x03,0x02,0x3c,0x24,0x20,0x87,0x00, +0xff,0x00,0x07,0x3c,0x24,0x28,0xa2,0x00,0x24,0x30,0xc2,0x00,0x00,0x51,0x0a,0x00, +0x00,0x20,0x02,0x3c,0x00,0x59,0x0b,0x00,0x00,0xff,0xe7,0x34,0x25,0x48,0x22,0x01, +0x25,0x18,0x6a,0x00,0x25,0x20,0x8b,0x00,0x02,0x2c,0x05,0x00,0x02,0x34,0x06,0x00, +0x24,0x10,0x07,0x02,0x08,0x40,0xa9,0xad,0x0c,0x40,0xa3,0xad,0x10,0x40,0xa4,0xad, +0x14,0x40,0xa5,0xa5,0x4e,0x03,0x40,0x10,0x16,0x40,0xa6,0xa5,0xff,0x00,0x02,0x3c, +0x24,0x10,0x02,0x02,0x02,0x14,0x02,0x00,0x02,0x1a,0x10,0x00,0xc7,0x42,0xa2,0xa1, +0xc3,0x42,0xa3,0xa1,0xc3,0x42,0x62,0x92,0x25,0xb0,0x03,0x3c,0x61,0x0c,0x63,0x34, +0x10,0x00,0xa4,0x27,0x00,0x00,0x62,0xa0,0x7a,0x54,0x00,0x0c,0x00,0x00,0x00,0x00, +0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00, +0x95,0x00,0xc2,0x10,0x00,0x40,0x02,0x3c,0x09,0xff,0xc2,0x10,0xc0,0x02,0x82,0x36, +0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0x7b,0x02,0xc2,0x10, +0x2b,0x10,0x46,0x00,0x83,0x00,0x40,0x14,0x00,0xb0,0x02,0x3c,0x00,0x90,0x02,0x3c, +0x78,0xfd,0xc2,0x14,0xc0,0x02,0x82,0x36,0x21,0x10,0x13,0x01,0x73,0x44,0x44,0xa0, +0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00, +0x55,0xfd,0x62,0x14,0x00,0xf0,0x02,0x3c,0x6a,0x56,0x00,0x0c,0x21,0x20,0x00,0x02, +0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00, +0x07,0x00,0x42,0x34,0x4c,0xfd,0x62,0x14,0x00,0xf0,0x02,0x3c,0x5b,0x4e,0x00,0x0c, +0x07,0x00,0x04,0x24,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08, +0x00,0x00,0x00,0x00,0x02,0x1a,0x02,0x00,0x21,0x88,0x00,0x00,0xaf,0x4a,0x00,0x08, +0x27,0xb0,0x06,0x3c,0x01,0x00,0x31,0x26,0x00,0x01,0x22,0x2e,0x08,0x00,0x40,0x10, +0xff,0x00,0x22,0x2e,0x00,0x00,0xc2,0x94,0x00,0x00,0x00,0x00,0xff,0x00,0x42,0x30, +0xf8,0xff,0x43,0x14,0x08,0x00,0xc6,0x24,0x00,0x00,0xd1,0xa7,0xff,0x00,0x22,0x2e, +0x50,0xfd,0x40,0x14,0xc0,0x02,0x82,0x36,0x12,0x87,0x02,0x3c,0x00,0x00,0xc2,0xaf, +0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00, +0x2d,0xfd,0x62,0x14,0x00,0xf0,0x02,0x3c,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac, +0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0xff,0x00,0x03,0x3c,0x00,0xff,0x63,0x34, +0x24,0x10,0x03,0x02,0x02,0x82,0x02,0x00,0xcc,0x02,0x83,0x36,0x00,0x00,0x70,0xac, +0x00,0x00,0xd1,0x8f,0x21,0x10,0x14,0x02,0x00,0x00,0x51,0xac,0x00,0x00,0x51,0x8c, +0xc0,0x02,0x82,0x36,0x00,0x00,0xd1,0xaf,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08, +0x00,0x00,0x00,0x00,0x00,0x64,0x62,0x92,0x00,0x00,0x00,0x00,0x00,0x00,0xc2,0xaf, +0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00, +0xf4,0x02,0x62,0x10,0xa3,0x00,0xe2,0x34,0x0f,0xfd,0x62,0x14,0x00,0xf0,0x02,0x3c, +0xc0,0x02,0x82,0x36,0x8c,0x65,0x60,0xae,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08, +0x00,0x00,0x00,0x00,0xec,0x63,0x62,0x92,0x00,0x00,0x00,0x00,0x00,0x00,0xc2,0xaf, +0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00, +0xe6,0x63,0x62,0xa6,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08, +0x00,0x00,0x00,0x00,0x08,0x40,0x63,0x8e,0xff,0x9f,0x07,0x3c,0xff,0xff,0xe7,0x34, +0x02,0x2c,0x10,0x00,0x00,0x1f,0x04,0x32,0x24,0x18,0x67,0x00,0x25,0x18,0x62,0x00, +0x02,0x8a,0x04,0x00,0x3f,0x00,0xa5,0x30,0xc0,0x02,0x82,0x36,0x08,0x40,0x63,0xae, +0xbc,0x42,0x71,0xa2,0xc1,0x42,0x65,0xa2,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08, +0x00,0x00,0x00,0x00,0x00,0x00,0xe2,0x92,0x00,0x00,0x00,0x00,0xfa,0x00,0x42,0x30, +0x00,0x00,0xe2,0xa2,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08, +0x00,0x00,0x00,0x00,0x00,0x00,0xe2,0x92,0x00,0x00,0x00,0x00,0xfd,0x00,0x42,0x30, +0x00,0x00,0xe2,0xa2,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08, +0x00,0x00,0x00,0x00,0xf7,0xfc,0xc2,0x14,0xc0,0x02,0x82,0x36,0x80,0x10,0x08,0x00, +0x21,0x10,0x53,0x00,0x60,0x45,0x43,0xac,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac, +0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0x80,0x10,0x08,0x00,0x21,0x10,0x48,0x00, +0x21,0x10,0x53,0x00,0x21,0x10,0x49,0x00,0x34,0x43,0x44,0xa0,0xc0,0x02,0x82,0x36, +0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0x77,0x56,0x00,0x0c, +0x21,0x20,0x00,0x02,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08, +0x00,0x00,0x00,0x00,0xff,0xff,0x02,0x34,0x8c,0x65,0x62,0xae,0xc0,0x02,0x82,0x36, +0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0x07,0x0b,0x00,0x0c, +0x00,0x00,0x00,0x00,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08, +0x00,0x00,0x00,0x00,0xf0,0x63,0x62,0x92,0x00,0x00,0x00,0x00,0x00,0x00,0xc2,0xaf, +0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00, +0x08,0x40,0x62,0x8e,0xff,0x9f,0x03,0x3c,0xff,0xff,0x63,0x34,0x24,0x10,0x43,0x00, +0x08,0x40,0x62,0xae,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08, +0x00,0x00,0x00,0x00,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x01,0x00,0x21,0x38, +0x00,0x60,0x81,0x40,0x22,0x51,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x60,0x01,0x40, +0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac, +0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0xff,0x00,0x07,0x3c,0x00,0xff,0xe7,0x34, +0x24,0x10,0x07,0x02,0x02,0x82,0x02,0x00,0xcc,0x02,0x43,0x36,0x00,0x00,0x70,0xac, +0x21,0x10,0x12,0x02,0x00,0x00,0x51,0x8c,0x00,0x00,0x00,0x00,0x00,0x00,0xd1,0xaf, +0x00,0x00,0x51,0x8c,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08, +0x00,0x00,0x00,0x00,0xb7,0x4f,0x00,0x0c,0x00,0x00,0x00,0x00,0xc0,0x02,0x82,0x36, +0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0x21,0x88,0x00,0x00, +0x6c,0x4b,0x00,0x08,0x27,0xb0,0x04,0x3c,0x01,0x00,0x31,0x26,0x00,0x01,0x22,0x2e, +0x0a,0x00,0x40,0x10,0xff,0x00,0x22,0x2e,0x00,0x00,0x83,0x94,0x00,0x00,0x00,0x00, +0xff,0xff,0x67,0x30,0xff,0x00,0xe2,0x30,0xf0,0x00,0x42,0x28,0xf6,0xff,0x40,0x14, +0x08,0x00,0x84,0x24,0x00,0x00,0xc7,0xa7,0xff,0x00,0x22,0x2e,0x91,0xfc,0x40,0x14, +0xc0,0x02,0x82,0x36,0x12,0x87,0x02,0x3c,0x00,0x00,0xc2,0xaf,0xc0,0x02,0x82,0x36, +0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0xe4,0x63,0x62,0x96, +0x00,0x00,0x00,0x00,0x00,0x00,0xc2,0xa7,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac, +0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0x04,0x64,0x62,0x92,0x00,0x00,0x00,0x00, +0x00,0x00,0xc2,0xaf,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08, +0x00,0x00,0x00,0x00,0x00,0xff,0x02,0x32,0x02,0x12,0x02,0x00,0x03,0x00,0x43,0x2c, +0x02,0x00,0x60,0x10,0x00,0x00,0x00,0x00,0x02,0x40,0x62,0xa2,0x02,0x40,0x63,0x92, +0x90,0x0c,0x42,0x36,0x00,0x00,0x43,0xa0,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac, +0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0xd7,0x56,0x00,0x0c,0x00,0x00,0x00,0x00, +0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00, +0x21,0x10,0x13,0x01,0x56,0x44,0x44,0xa0,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac, +0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0xff,0x00,0x03,0x3c,0x24,0x20,0x03,0x02, +0x73,0x0e,0x00,0x0c,0x02,0x24,0x04,0x00,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac, +0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0x02,0x1c,0x10,0x00,0x00,0x1f,0x02,0x32, +0x02,0x8a,0x02,0x00,0x3f,0x00,0x65,0x30,0xc1,0x42,0x65,0xa2,0xbc,0x42,0x71,0xa2, +0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40, +0x1f,0x12,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0xc2,0xaf,0x00,0x60,0x01,0x40, +0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40,0x03,0x40,0x62,0x92,0x0e,0x0c,0x44,0x36, +0x01,0x00,0x42,0x24,0xff,0x00,0x43,0x30,0x00,0x00,0x83,0xa0,0x03,0x40,0x62,0xa2, +0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00, +0x00,0xff,0x02,0x32,0x02,0x3a,0x02,0x00,0x1a,0x01,0xe0,0x10,0x4f,0x00,0x82,0x36, +0x94,0x00,0x42,0x36,0x00,0x00,0x43,0x94,0xff,0xff,0xe2,0x24,0xb0,0x03,0x45,0x36, +0xff,0xff,0x71,0x30,0x1b,0x00,0x27,0x02,0x02,0x00,0xe0,0x14,0x00,0x00,0x00,0x00, +0x0d,0x00,0x07,0x00,0xff,0xff,0x47,0x30,0x00,0x00,0xb1,0xac,0x80,0xff,0x02,0x24, +0x00,0x19,0x07,0x00,0x25,0x18,0x62,0x00,0x4f,0x00,0x44,0x36,0x9e,0x00,0x46,0x36, +0x00,0x00,0xa7,0xac,0x00,0x00,0x83,0xa0,0x25,0xb0,0x04,0x3c,0x44,0x00,0x84,0x34, +0x12,0x88,0x00,0x00,0x80,0x12,0x11,0x00,0x00,0xfc,0x42,0x24,0x00,0x00,0xb1,0xac, +0x00,0x00,0xd1,0xa4,0x42,0x89,0x02,0x00,0x26,0xb0,0x02,0x3c,0x7c,0x00,0x42,0x34, +0x00,0x00,0xb1,0xac,0x00,0x00,0x51,0xa4,0x25,0xb0,0x02,0x3c,0x44,0x00,0x42,0x34, +0x00,0x00,0x43,0x94,0xff,0xfd,0x02,0x24,0x24,0x18,0x62,0x00,0x00,0x00,0x83,0xa4, +0x00,0x00,0x82,0x94,0x00,0x00,0x00,0x00,0x00,0x02,0x42,0x34,0x00,0x00,0x82,0xa4, +0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00, +0x24,0x10,0x08,0x02,0xcc,0x02,0x43,0x36,0x00,0xff,0x04,0x32,0x02,0x3c,0x02,0x00, +0x00,0x00,0x70,0xac,0x04,0x00,0xe0,0x10,0x02,0x82,0x04,0x00,0x01,0x00,0x02,0x24, +0x02,0x00,0xe2,0x10,0x01,0x00,0x04,0x24,0x21,0x20,0x00,0x00,0x7a,0x42,0x00,0x0c, +0x00,0x00,0x00,0x00,0x0f,0x00,0x06,0x3c,0x21,0x20,0x00,0x02,0xdd,0x44,0x00,0x0c, +0xff,0xff,0xc5,0x34,0x0f,0x00,0x07,0x3c,0xff,0xff,0xe7,0x34,0x24,0x88,0x47,0x00, +0xc0,0x02,0x82,0x36,0x00,0x00,0xd1,0xaf,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08, +0x00,0x00,0x00,0x00,0x28,0xb0,0x02,0x3c,0x00,0x00,0x43,0x90,0xff,0x00,0x02,0x24, +0xff,0x00,0x70,0x30,0xf3,0xfb,0x02,0x12,0xc0,0x02,0x82,0x36,0x28,0xb0,0x05,0x3c, +0xff,0x00,0x04,0x24,0xc0,0x10,0x10,0x00,0x21,0x10,0x45,0x00,0x00,0x00,0x43,0x90, +0x00,0x00,0x00,0x00,0xff,0x00,0x70,0x30,0xfb,0xff,0x04,0x16,0xc0,0x10,0x10,0x00, +0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00, +0x00,0x1f,0x02,0x32,0x02,0x1c,0x10,0x00,0x02,0x8a,0x02,0x00,0x3f,0x00,0x65,0x30, +0xc0,0x02,0x82,0x36,0xbc,0x42,0x71,0xa2,0xc1,0x42,0x65,0xa2,0x00,0x00,0x40,0xac, +0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0xff,0x00,0x07,0x3c,0x24,0x20,0x07,0x02, +0x15,0x51,0x00,0x0c,0x02,0x24,0x04,0x00,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac, +0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0xe8,0x63,0x62,0x92,0x00,0x00,0x00,0x00, +0x00,0x00,0xc2,0xaf,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08, +0x00,0x00,0x00,0x00,0xfc,0x63,0x62,0x92,0x00,0x00,0x00,0x00,0x00,0x00,0xc2,0xaf, +0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00, +0x00,0x00,0xe2,0x92,0x00,0x00,0x00,0x00,0xff,0x00,0x51,0x30,0x05,0x00,0x23,0x36, +0xc0,0x02,0x82,0x36,0x00,0x00,0xe3,0xa2,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08, +0x00,0x00,0x00,0x00,0xc0,0x02,0x82,0x36,0xe6,0x63,0x60,0xa6,0x00,0x00,0x40,0xac, +0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0xbd,0x56,0x00,0x0c,0x21,0x20,0x00,0x02, +0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00, +0x41,0x0b,0x00,0x0c,0x00,0x00,0x00,0x00,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac, +0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0xe2,0x92,0x00,0x00,0x00,0x00, +0xff,0x00,0x51,0x30,0x02,0x00,0x23,0x36,0xc0,0x02,0x82,0x36,0x00,0x00,0xe3,0xa2, +0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0x02,0x80,0x02,0x3c, +0xec,0x91,0x42,0x24,0x00,0x00,0x47,0x8c,0xc0,0x02,0x43,0x36,0x25,0xb0,0x0c,0x3c, +0x08,0x40,0xe4,0x8c,0x00,0x00,0x60,0xac,0x42,0x17,0x04,0x00,0x03,0x00,0x42,0x30, +0x60,0x00,0x40,0x14,0x03,0x0d,0x42,0x36,0x00,0x00,0x45,0x90,0x10,0x40,0xe6,0x8c, +0xff,0x9f,0x03,0x3c,0xff,0xff,0x63,0x34,0xff,0x3f,0x02,0x3c,0x24,0x20,0x83,0x00, +0xff,0xff,0x42,0x34,0x00,0x20,0x03,0x3c,0x24,0x58,0xc2,0x00,0x25,0x20,0x83,0x00, +0x00,0x40,0x02,0x3c,0x70,0x00,0xa5,0x30,0x25,0x58,0x62,0x01,0x08,0x01,0xa0,0x10, +0x08,0x40,0xe4,0xac,0x94,0x0e,0x82,0x35,0x9c,0x0e,0x83,0x35,0xa4,0x0e,0x86,0x35, +0x00,0x00,0x45,0x8c,0xac,0x0e,0x87,0x35,0x00,0x00,0x68,0x8c,0x00,0x00,0xca,0x8c, +0x02,0x80,0x06,0x3c,0x00,0x00,0xe4,0x8c,0x68,0x15,0xc6,0x24,0x0c,0x40,0xc3,0x8c, +0xb4,0x0e,0x82,0x35,0x00,0x00,0x47,0x8c,0xff,0x03,0x02,0x3c,0x00,0xfc,0x06,0x24, +0x24,0x28,0xa2,0x00,0x24,0x20,0x82,0x00,0xbc,0x0e,0x82,0x35,0x00,0x00,0x49,0x8c, +0x02,0x2c,0x05,0x00,0x24,0x10,0x66,0x01,0x24,0x18,0x66,0x00,0x02,0x24,0x04,0x00, +0xc4,0x0e,0x86,0x35,0x25,0x18,0x65,0x00,0x25,0x10,0x44,0x00,0x00,0x00,0xc5,0x8c, +0xff,0x03,0x04,0x3c,0xf0,0xff,0x06,0x3c,0xff,0x03,0xc6,0x34,0x24,0x38,0xe4,0x00, +0xcc,0x0e,0x8b,0x35,0x24,0x40,0x04,0x01,0x82,0x39,0x07,0x00,0x00,0x00,0x64,0x8d, +0x24,0x10,0x46,0x00,0x24,0x18,0x66,0x00,0x25,0x10,0x47,0x00,0x82,0x41,0x08,0x00, +0xff,0x03,0x07,0x3c,0x0f,0xc0,0x06,0x3c,0x24,0x50,0x47,0x01,0x24,0x48,0x27,0x01, +0xff,0xff,0xc6,0x34,0x25,0x18,0x68,0x00,0x24,0x28,0xa7,0x00,0x24,0x20,0x87,0x00, +0x00,0x51,0x0a,0x00,0x24,0x18,0x66,0x00,0x00,0x49,0x09,0x00,0x24,0x10,0x46,0x00, +0x02,0x80,0x07,0x3c,0x68,0x15,0xe7,0x24,0x25,0x18,0x6a,0x00,0x25,0x10,0x49,0x00, +0x02,0x2c,0x05,0x00,0x02,0x24,0x04,0x00,0x0c,0x40,0xe3,0xac,0x10,0x40,0xe2,0xac, +0x14,0x40,0xe5,0xa4,0x16,0x40,0xe4,0xa4,0x02,0x80,0x02,0x3c,0x68,0x15,0x43,0x24, +0x0c,0x40,0x62,0x8c,0x00,0x00,0x00,0x00,0xbd,0x00,0x40,0x04,0x00,0x00,0x00,0x00, +0x00,0xff,0x02,0x32,0xc6,0x00,0x40,0x10,0x00,0x00,0x00,0x00,0x02,0x12,0x02,0x00, +0xc3,0x42,0x62,0xa0,0x7a,0x54,0x00,0x0c,0x10,0x00,0xa4,0x27,0xc2,0x53,0x00,0x0c, +0x00,0x00,0x00,0x00,0x0c,0x40,0x62,0x8e,0x00,0x80,0x03,0x3c,0x25,0x10,0x43,0x00, +0x0c,0x40,0x62,0xae,0xc3,0x42,0x62,0x92,0x25,0xb0,0x03,0x3c,0x61,0x0c,0x63,0x34, +0x00,0x00,0x62,0xa0,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08, +0x00,0x00,0x00,0x00,0xcf,0x4e,0x00,0x0c,0x21,0x20,0x00,0x02,0xc0,0x02,0x82,0x36, +0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0x17,0x51,0x00,0x0c, +0x00,0x00,0x00,0x00,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08, +0x00,0x00,0x00,0x00,0x9e,0x00,0x83,0x36,0x00,0x00,0x40,0xa0,0x00,0x00,0x60,0xa4, +0x94,0x00,0x82,0x36,0x00,0x00,0x43,0x94,0x25,0xb0,0x06,0x3c,0x44,0x00,0xc6,0x34, +0xff,0xff,0x71,0x30,0x80,0x12,0x11,0x00,0x00,0xf8,0x42,0x24,0x42,0x89,0x02,0x00, +0x26,0xb0,0x02,0x3c,0xb0,0x03,0x83,0x36,0x7c,0x00,0x42,0x34,0x00,0x00,0x71,0xac, +0x00,0x00,0x51,0xa4,0x00,0x00,0xc3,0x94,0xff,0xfd,0x02,0x24,0x24,0x18,0x62,0x00, +0x00,0x00,0xc3,0xa4,0x00,0x00,0xc2,0x94,0x00,0x00,0x00,0x00,0x00,0x02,0x42,0x34, +0x00,0x00,0xc2,0xa4,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08, +0x00,0x00,0x00,0x00,0x5b,0x4e,0x00,0x0c,0x01,0x00,0x04,0x24,0xc0,0x02,0x82,0x36, +0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0x80,0x10,0x08,0x00, +0x21,0x10,0x53,0x00,0xec,0x44,0x43,0xac,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac, +0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0xa7,0x0b,0x00,0x0c,0x00,0x00,0x00,0x00, +0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00, +0x28,0xb0,0x11,0x3c,0x00,0x00,0x22,0x96,0xff,0x00,0x04,0x3c,0x24,0x18,0x04,0x02, +0x02,0x24,0x03,0x00,0xff,0x00,0x42,0x30,0x0a,0x00,0x82,0x10,0xff,0x7f,0x02,0x3c, +0x08,0x00,0x31,0x26,0x00,0x00,0x22,0x96,0xff,0xff,0x23,0x32,0xff,0x00,0x42,0x30, +0x03,0x00,0x82,0x10,0x00,0x08,0x63,0x2c,0xf9,0xff,0x60,0x14,0x00,0x00,0x00,0x00, +0xff,0x7f,0x02,0x3c,0xff,0xff,0x42,0x34,0x24,0x10,0x22,0x02,0x00,0x00,0xc2,0xaf, +0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00, +0xf8,0x63,0x62,0x92,0x00,0x00,0x00,0x00,0x00,0x00,0xc2,0xaf,0xc0,0x02,0x82,0x36, +0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0xff,0x00,0x03,0x3c, +0x24,0x10,0x03,0x02,0x00,0xff,0x04,0x32,0xcc,0x02,0x83,0x36,0x02,0x3c,0x02,0x00, +0x00,0x00,0x70,0xac,0x04,0x00,0xe0,0x10,0x02,0x82,0x04,0x00,0x01,0x00,0x02,0x24, +0x02,0x00,0xe2,0x10,0x01,0x00,0x04,0x24,0x21,0x20,0x00,0x00,0x7a,0x42,0x00,0x0c, +0x00,0x00,0x00,0x00,0x00,0x00,0xd1,0x8f,0x0f,0x00,0x06,0x3c,0xff,0xff,0xc5,0x34, +0x21,0x20,0x00,0x02,0xba,0x44,0x00,0x0c,0x21,0x30,0x20,0x02,0x0f,0x00,0x07,0x3c, +0x21,0x20,0x00,0x02,0xdd,0x44,0x00,0x0c,0xff,0xff,0xe5,0x34,0x00,0x00,0xc2,0xaf, +0x21,0x88,0x40,0x00,0x25,0xb0,0x02,0x3c,0xc8,0x02,0x42,0x34,0x00,0x00,0x51,0xac, +0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00, +0x25,0xb0,0x06,0x3c,0xff,0x00,0x02,0x24,0x56,0x01,0xc6,0x34,0x00,0x00,0xc2,0xa4, +0x01,0x00,0x03,0x24,0x02,0x80,0x07,0x3c,0xc0,0x02,0x82,0x36,0xb8,0x7d,0xe3,0xa0, +0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0xde,0x4f,0x00,0x0c, +0x03,0x00,0x04,0x24,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08, +0x00,0x00,0x00,0x00,0xde,0x4e,0x00,0x0c,0x21,0x20,0x00,0x02,0xc0,0x02,0x82,0x36, +0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0x08,0x40,0x62,0x8e, +0xff,0x9f,0x04,0x3c,0xff,0xff,0x84,0x34,0x24,0x10,0x44,0x00,0x08,0x40,0x62,0xae, +0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00, +0xc0,0x10,0x03,0x00,0x21,0x10,0x43,0x00,0x80,0x10,0x02,0x00,0x21,0x10,0x43,0x00, +0x80,0x10,0x02,0x00,0x21,0x10,0x53,0x00,0x70,0x51,0x43,0x8c,0xc0,0x02,0x82,0x36, +0x00,0x00,0xc3,0xaf,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00, +0x7a,0x54,0x00,0x0c,0x10,0x00,0xa4,0x27,0xc3,0x42,0x62,0x92,0x25,0xb0,0x03,0x3c, +0x61,0x0c,0x63,0x34,0x00,0x00,0x62,0xa0,0xd4,0x4c,0x00,0x08,0xc0,0x02,0x82,0x36, +0x22,0x51,0x00,0x0c,0x10,0x40,0xeb,0xac,0xbd,0x4c,0x00,0x08,0x02,0x80,0x02,0x3c, +0xc6,0x4c,0x00,0x08,0x12,0x00,0x02,0x24,0x1a,0x57,0x00,0x0c,0x00,0x00,0x00,0x00, +0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00, +0xff,0xff,0x02,0x34,0x8c,0x65,0x62,0xae,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac, +0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0xc0,0x10,0x03,0x00,0x21,0x10,0x43,0x00, +0x80,0x10,0x02,0x00,0x21,0x10,0x43,0x00,0x80,0x10,0x02,0x00,0x21,0x10,0x53,0x00, +0x74,0x51,0x43,0x8c,0xc0,0x02,0x82,0x36,0x00,0x00,0xc3,0xaf,0x00,0x00,0x40,0xac, +0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0xc0,0x10,0x03,0x00,0x21,0x10,0x43,0x00, +0x80,0x10,0x02,0x00,0x21,0x10,0x43,0x00,0x80,0x10,0x02,0x00,0x21,0x10,0x53,0x00, +0xd4,0x51,0x43,0x8c,0xc0,0x02,0x82,0x36,0x00,0x00,0xc3,0xaf,0x00,0x00,0x40,0xac, +0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0xc0,0x10,0x03,0x00,0x21,0x10,0x43,0x00, +0x80,0x10,0x02,0x00,0x21,0x10,0x43,0x00,0x02,0x80,0x06,0x3c,0x80,0x10,0x02,0x00, +0xe0,0x66,0xc3,0x24,0x21,0x10,0x43,0x00,0x00,0x00,0x44,0x8c,0xc0,0x02,0x82,0x36, +0x00,0x00,0xc4,0xaf,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00, +0x12,0x00,0x02,0x24,0xc7,0x42,0xa2,0xa1,0x77,0x4a,0x00,0x08,0xc3,0x42,0xa2,0xa1, +0x88,0x7d,0x82,0x94,0x00,0x00,0x00,0x00,0x00,0x00,0xc2,0xaf,0xc0,0x02,0x82,0x36, +0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0x7a,0x42,0x00,0x0c, +0x21,0x20,0x00,0x00,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08, +0x00,0x00,0x00,0x00,0xff,0x00,0x06,0x3c,0x00,0xff,0xc6,0x34,0x00,0x00,0xc5,0x8f, +0x24,0x20,0x06,0x02,0xe1,0x50,0x00,0x0c,0x02,0x22,0x04,0x00,0xc0,0x02,0x82,0x36, +0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0xc0,0x10,0x03,0x00, +0x21,0x10,0x43,0x00,0x80,0x10,0x02,0x00,0x21,0x10,0x43,0x00,0x02,0x80,0x07,0x3c, +0x80,0x10,0x02,0x00,0xf0,0x66,0xe3,0x24,0x21,0x10,0x43,0x00,0x00,0x00,0x44,0x8c, +0xc0,0x02,0x82,0x36,0x00,0x00,0xc4,0xaf,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08, +0x00,0x00,0x00,0x00,0xc0,0x10,0x03,0x00,0x21,0x10,0x43,0x00,0x80,0x10,0x02,0x00, +0x21,0x10,0x43,0x00,0x02,0x80,0x06,0x3c,0x80,0x10,0x02,0x00,0xec,0x66,0xc3,0x24, +0x21,0x10,0x43,0x00,0x00,0x00,0x44,0x8c,0xc0,0x02,0x82,0x36,0x00,0x00,0xc4,0xaf, +0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0xc0,0x10,0x03,0x00, +0x21,0x10,0x43,0x00,0x80,0x10,0x02,0x00,0x21,0x10,0x43,0x00,0x02,0x80,0x04,0x3c, +0xe8,0x66,0x83,0x24,0x80,0x10,0x02,0x00,0x21,0x10,0x43,0x00,0x00,0x00,0x44,0x8c, +0xc0,0x02,0x82,0x36,0x00,0x00,0xc4,0xaf,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08, +0x00,0x00,0x00,0x00,0xc0,0x10,0x03,0x00,0x21,0x10,0x43,0x00,0x80,0x10,0x02,0x00, +0x21,0x10,0x43,0x00,0x02,0x80,0x07,0x3c,0x80,0x10,0x02,0x00,0xe4,0x66,0xe3,0x24, +0x21,0x10,0x43,0x00,0x00,0x00,0x44,0x8c,0xc0,0x02,0x82,0x36,0x00,0x00,0xc4,0xaf, +0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0xc0,0x10,0x03,0x00, +0x21,0x10,0x43,0x00,0x80,0x10,0x02,0x00,0x21,0x10,0x43,0x00,0x02,0x80,0x04,0x3c, +0x00,0x67,0x83,0x24,0x80,0x10,0x02,0x00,0x21,0x10,0x43,0x00,0x00,0x00,0x44,0x8c, +0xc0,0x02,0x82,0x36,0x00,0x00,0xc4,0xaf,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08, +0x00,0x00,0x00,0x00,0xc0,0x10,0x03,0x00,0x21,0x10,0x43,0x00,0x80,0x10,0x02,0x00, +0x21,0x10,0x43,0x00,0x02,0x80,0x07,0x3c,0x80,0x10,0x02,0x00,0xfc,0x66,0xe3,0x24, +0x21,0x10,0x43,0x00,0x00,0x00,0x44,0x8c,0xc0,0x02,0x82,0x36,0x00,0x00,0xc4,0xaf, +0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0xc0,0x10,0x03,0x00, +0x21,0x10,0x43,0x00,0x80,0x10,0x02,0x00,0x21,0x10,0x43,0x00,0x02,0x80,0x06,0x3c, +0x80,0x10,0x02,0x00,0xf8,0x66,0xc3,0x24,0x21,0x10,0x43,0x00,0x00,0x00,0x44,0x8c, +0xc0,0x02,0x82,0x36,0x00,0x00,0xc4,0xaf,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08, +0x00,0x00,0x00,0x00,0xc0,0x10,0x03,0x00,0x21,0x10,0x43,0x00,0x80,0x10,0x02,0x00, +0x21,0x10,0x43,0x00,0x02,0x80,0x04,0x3c,0xf4,0x66,0x83,0x24,0x80,0x10,0x02,0x00, +0x21,0x10,0x43,0x00,0x00,0x00,0x44,0x8c,0xc0,0x02,0x82,0x36,0x00,0x00,0xc4,0xaf, +0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0xde,0x4f,0x00,0x0c, +0x02,0x00,0x04,0x24,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08, +0x00,0x00,0x00,0x00,0xde,0x4f,0x00,0x0c,0x01,0x00,0x04,0x24,0xc0,0x02,0x82,0x36, +0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08,0x00,0x00,0x00,0x00,0x7a,0x42,0x00,0x0c, +0x01,0x00,0x04,0x24,0xc0,0x02,0x82,0x36,0x00,0x00,0x40,0xac,0x08,0x48,0x00,0x08, +0x00,0x00,0x00,0x00,0x25,0xb0,0x05,0x3c,0x01,0x00,0x06,0x24,0x01,0x80,0x02,0x3c, +0x04,0x30,0x86,0x00,0xf1,0x02,0xa7,0x34,0xed,0x02,0xa4,0x34,0x6c,0x39,0x42,0x24, +0x18,0x03,0xa5,0x34,0x08,0x00,0x03,0x24,0x00,0x00,0xa2,0xac,0x00,0x00,0xe3,0xa0, +0x00,0x00,0x80,0xa0,0x00,0x00,0x86,0xa0,0x00,0x00,0x80,0xa0,0x00,0x00,0x86,0xa0, +0x00,0x00,0x80,0xa0,0x00,0x00,0x86,0xa0,0x00,0x00,0x80,0xa0,0x00,0x00,0x86,0xa0, +0x00,0x00,0x80,0xa0,0x00,0x00,0xe0,0xa0,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00, +0x01,0x80,0x02,0x3c,0x25,0xb0,0x03,0x3c,0xc8,0x39,0x42,0x24,0x18,0x03,0x63,0x34, +0x00,0x00,0x62,0xac,0x00,0x00,0x83,0x90,0x30,0x00,0x02,0x24,0x05,0x00,0x62,0x10, +0x21,0x20,0x00,0x00,0x31,0x00,0x02,0x24,0x02,0x00,0x62,0x10,0x01,0x00,0x04,0x24, +0x07,0x00,0x04,0x24,0x5b,0x4e,0x00,0x08,0x00,0x00,0x00,0x00,0x01,0x80,0x02,0x3c, +0x25,0xb0,0x03,0x3c,0x04,0x3a,0x42,0x24,0x18,0x03,0x63,0x34,0x02,0x80,0x04,0x3c, +0x00,0x00,0x62,0xac,0x08,0x00,0xe0,0x03,0xc4,0x7d,0x80,0xac,0x02,0x80,0x02,0x3c, +0x08,0x7b,0x42,0x24,0xc0,0x20,0x04,0x00,0x21,0x20,0x82,0x00,0x21,0x28,0x00,0x00, +0x00,0x60,0x06,0x40,0x01,0x00,0xc1,0x34,0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40, +0x00,0x00,0x82,0x8c,0x00,0x00,0x00,0x00,0x09,0x00,0x44,0x10,0x00,0x00,0x00,0x00, +0x04,0x00,0x43,0x8c,0x21,0x28,0x40,0x00,0x00,0x00,0x42,0x8c,0x00,0x00,0x00,0x00, +0x00,0x00,0x62,0xac,0x04,0x00,0x43,0xac,0x00,0x00,0xa5,0xac,0x04,0x00,0xa5,0xac, +0x00,0x60,0x86,0x40,0x08,0x00,0xe0,0x03,0x21,0x10,0xa0,0x00,0x21,0x18,0x80,0x00, +0xe8,0xff,0xbd,0x27,0x01,0x01,0x62,0x2c,0x10,0x00,0xbf,0xaf,0x01,0x00,0x04,0x24, +0x01,0x02,0x65,0x2c,0x0a,0x00,0x40,0x14,0x21,0x30,0x00,0x00,0x02,0x00,0x04,0x24, +0x07,0x00,0xa0,0x14,0x01,0x08,0x62,0x2c,0x05,0x00,0x40,0x14,0x03,0x00,0x04,0x24, +0x10,0x00,0xbf,0x8f,0x21,0x10,0xc0,0x00,0x08,0x00,0xe0,0x03,0x18,0x00,0xbd,0x27, +0x89,0x4e,0x00,0x0c,0x00,0x00,0x00,0x00,0x10,0x00,0xbf,0x8f,0x21,0x30,0x40,0x00, +0x21,0x10,0xc0,0x00,0x08,0x00,0xe0,0x03,0x18,0x00,0xbd,0x27,0x02,0x80,0x03,0x3c, +0x20,0x7b,0x62,0x8c,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x00,0x60,0x06,0x40, +0x01,0x00,0xc1,0x34,0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,0x10,0x00,0x83,0x8c, +0x02,0x80,0x02,0x3c,0x08,0x7b,0x42,0x24,0xc0,0x18,0x03,0x00,0x21,0x18,0x62,0x00, +0x00,0x00,0x65,0x8c,0x00,0x00,0x00,0x00,0x00,0x00,0x85,0xac,0x04,0x00,0xa4,0xac, +0x00,0x00,0x64,0xac,0x04,0x00,0x83,0xac,0x00,0x60,0x86,0x40,0x08,0x00,0xe0,0x03, +0x00,0x00,0x00,0x00,0x02,0x24,0x04,0x00,0xff,0x00,0x84,0x30,0xc0,0x18,0x04,0x00, +0x21,0x18,0x64,0x00,0x80,0x18,0x03,0x00,0x21,0x18,0x64,0x00,0x02,0x80,0x02,0x3c, +0x68,0x15,0x42,0x24,0x80,0x18,0x03,0x00,0x21,0x18,0x62,0x00,0x78,0x51,0x64,0x8c, +0xff,0xf1,0x02,0x24,0x24,0x20,0x82,0x00,0x08,0x00,0xe0,0x03,0x78,0x51,0x64,0xac, +0x02,0x24,0x04,0x00,0xff,0x00,0x84,0x30,0xc0,0x18,0x04,0x00,0x21,0x18,0x64,0x00, +0x80,0x18,0x03,0x00,0x21,0x18,0x64,0x00,0x02,0x80,0x02,0x3c,0x68,0x15,0x42,0x24, +0x80,0x18,0x03,0x00,0x21,0x18,0x62,0x00,0x78,0x51,0x64,0x8c,0xff,0xf1,0x02,0x24, +0x24,0x20,0x82,0x00,0x00,0x02,0x84,0x34,0x08,0x00,0xe0,0x03,0x78,0x51,0x64,0xac, +0xe0,0xff,0xbd,0x27,0x10,0x00,0xb0,0xaf,0xc0,0x80,0x04,0x00,0x21,0x80,0x04,0x02, +0x80,0x80,0x10,0x00,0x21,0x80,0x04,0x02,0x02,0x80,0x02,0x3c,0x68,0x15,0x42,0x24, +0x80,0x80,0x10,0x00,0x21,0x80,0x02,0x02,0x1c,0x00,0xbf,0xaf,0x18,0x00,0xb2,0xaf, +0x14,0x00,0xb1,0xaf,0x78,0x51,0x05,0x8e,0xff,0x1f,0x02,0x3c,0x25,0xb0,0x12,0x3c, +0xff,0xff,0x42,0x34,0x70,0x51,0x02,0xae,0x84,0x01,0x43,0x36,0xf8,0xff,0x02,0x24, +0x00,0x00,0x66,0x8c,0x24,0x28,0xa2,0x00,0xff,0xfe,0x02,0x24,0x24,0x28,0xa2,0x00, +0xff,0xef,0x03,0x24,0x24,0x28,0xa3,0x00,0x74,0x51,0x06,0xae,0x78,0x51,0x05,0xae, +0xce,0x0d,0x00,0x0c,0x21,0x88,0x80,0x00,0x7a,0x51,0x02,0x92,0x21,0x88,0x32,0x02, +0x1c,0x00,0xbf,0x8f,0x60,0x01,0x22,0xa2,0x18,0x00,0xb2,0x8f,0x64,0x51,0x00,0xae, +0x48,0x51,0x00,0xae,0x4c,0x51,0x00,0xae,0x50,0x51,0x00,0xae,0x54,0x51,0x00,0xae, +0x58,0x51,0x00,0xae,0x5c,0x51,0x00,0xae,0x60,0x51,0x00,0xae,0x14,0x00,0xb1,0x8f, +0x10,0x00,0xb0,0x8f,0x08,0x00,0xe0,0x03,0x20,0x00,0xbd,0x27,0xff,0x00,0xa5,0x30, +0xc0,0x10,0x05,0x00,0x21,0x10,0x45,0x00,0x80,0x10,0x02,0x00,0x21,0x10,0x45,0x00, +0x02,0x80,0x03,0x3c,0x68,0x15,0x63,0x24,0x80,0x10,0x02,0x00,0x21,0x10,0x43,0x00, +0x78,0x51,0x43,0x8c,0x25,0xb0,0x05,0x3c,0xff,0x00,0xc6,0x30,0x21,0x30,0xc5,0x00, +0xaf,0x01,0xc2,0x90,0x07,0x00,0x63,0x30,0x80,0x18,0x03,0x00,0x21,0x18,0x65,0x00, +0xff,0x00,0x88,0x30,0xff,0x00,0x49,0x30,0x84,0x01,0x66,0x8c,0x21,0x50,0x00,0x00, +0x21,0x58,0x00,0x00,0x2b,0x00,0x20,0x11,0x21,0x20,0x00,0x01,0x2b,0x00,0xc0,0x10, +0x2b,0x10,0x09,0x01,0x21,0x28,0x00,0x00,0x3e,0x4f,0x00,0x08,0x01,0x00,0x07,0x24, +0xff,0x00,0x65,0x30,0x1d,0x00,0xa2,0x2c,0x07,0x00,0x40,0x10,0xff,0xff,0x02,0x25, +0x04,0x10,0xa7,0x00,0x24,0x10,0x46,0x00,0xf9,0xff,0x40,0x10,0x01,0x00,0xa3,0x24, +0x21,0x58,0xa0,0x00,0xff,0xff,0x02,0x25,0xff,0x00,0x45,0x30,0x2b,0x18,0xab,0x00, +0x0f,0x00,0x60,0x14,0x2b,0x10,0x49,0x01,0x01,0x00,0x04,0x24,0x04,0x10,0xa4,0x00, +0x24,0x10,0x46,0x00,0xff,0xff,0xa7,0x24,0x04,0x00,0x40,0x10,0x01,0x00,0x43,0x25, +0x17,0x00,0x49,0x11,0xff,0x00,0x6a,0x30,0x21,0x40,0xa0,0x00,0xff,0x00,0xe5,0x30, +0x2b,0x10,0xab,0x00,0xf6,0xff,0x40,0x10,0x04,0x10,0xa4,0x00,0x2b,0x10,0x49,0x01, +0x08,0x00,0x40,0x10,0x21,0x20,0x00,0x01,0x23,0x10,0x2a,0x01,0x2a,0x10,0x62,0x01, +0x04,0x00,0x40,0x14,0x21,0x20,0x00,0x00,0x23,0x10,0x69,0x01,0x21,0x10,0x4a,0x00, +0xff,0x00,0x44,0x30,0x08,0x00,0xe0,0x03,0x21,0x10,0x80,0x00,0xfd,0xff,0x40,0x14, +0x21,0x20,0x00,0x00,0x23,0x10,0x09,0x01,0x5f,0x4f,0x00,0x08,0xff,0x00,0x44,0x30, +0x21,0x20,0x00,0x01,0x08,0x00,0xe0,0x03,0x21,0x10,0x80,0x00,0xff,0x00,0x84,0x30, +0xc0,0x10,0x04,0x00,0x21,0x10,0x44,0x00,0x80,0x10,0x02,0x00,0x21,0x10,0x44,0x00, +0x02,0x80,0x03,0x3c,0x68,0x15,0x63,0x24,0x80,0x10,0x02,0x00,0x21,0x10,0x43,0x00, +0x25,0xb0,0x06,0x3c,0x78,0x51,0x43,0x8c,0xff,0x00,0xa5,0x30,0x21,0x20,0x86,0x00, +0x21,0x28,0xa6,0x00,0x60,0x01,0x82,0x90,0xaf,0x01,0xa4,0x90,0x07,0x00,0x63,0x30, +0x80,0x18,0x03,0x00,0x21,0x18,0x66,0x00,0xff,0x00,0x48,0x30,0xff,0x00,0x89,0x30, +0x84,0x01,0x66,0x8c,0x21,0x50,0x00,0x00,0x21,0x58,0x00,0x00,0x2b,0x00,0x20,0x11, +0x21,0x20,0x00,0x01,0x2b,0x00,0xc0,0x10,0x2b,0x10,0x09,0x01,0x21,0x28,0x00,0x00, +0x8c,0x4f,0x00,0x08,0x01,0x00,0x07,0x24,0xff,0x00,0x65,0x30,0x1d,0x00,0xa2,0x2c, +0x07,0x00,0x40,0x10,0xff,0xff,0x02,0x25,0x04,0x10,0xa7,0x00,0x24,0x10,0x46,0x00, +0xf9,0xff,0x40,0x10,0x01,0x00,0xa3,0x24,0x21,0x58,0xa0,0x00,0xff,0xff,0x02,0x25, +0xff,0x00,0x45,0x30,0x2b,0x18,0xab,0x00,0x0f,0x00,0x60,0x14,0x2b,0x10,0x49,0x01, +0x01,0x00,0x04,0x24,0x04,0x10,0xa4,0x00,0x24,0x10,0x46,0x00,0xff,0xff,0xa7,0x24, +0x04,0x00,0x40,0x10,0x01,0x00,0x43,0x25,0x17,0x00,0x49,0x11,0xff,0x00,0x6a,0x30, +0x21,0x40,0xa0,0x00,0xff,0x00,0xe5,0x30,0x2b,0x10,0xab,0x00,0xf6,0xff,0x40,0x10, +0x04,0x10,0xa4,0x00,0x2b,0x10,0x49,0x01,0x08,0x00,0x40,0x10,0x21,0x20,0x00,0x01, +0x23,0x10,0x2a,0x01,0x2a,0x10,0x62,0x01,0x04,0x00,0x40,0x14,0x21,0x20,0x00,0x00, +0x23,0x10,0x69,0x01,0x21,0x10,0x4a,0x00,0xff,0x00,0x44,0x30,0x08,0x00,0xe0,0x03, +0x21,0x10,0x80,0x00,0xfd,0xff,0x40,0x14,0x21,0x20,0x00,0x00,0x23,0x10,0x09,0x01, +0xad,0x4f,0x00,0x08,0xff,0x00,0x44,0x30,0x21,0x20,0x00,0x01,0x08,0x00,0xe0,0x03, +0x21,0x10,0x80,0x00,0xe0,0xff,0xbd,0x27,0x02,0x80,0x02,0x3c,0x10,0x00,0xb0,0xaf, +0x68,0x15,0x50,0x24,0x18,0x00,0xb2,0xaf,0x14,0x00,0xb1,0xaf,0x1c,0x00,0xbf,0xaf, +0x21,0x88,0x00,0x00,0x21,0x90,0x00,0x02,0xee,0x4e,0x00,0x0c,0x21,0x20,0x20,0x02, +0x7a,0x51,0x02,0x92,0x21,0x28,0x00,0x00,0x80,0x10,0x02,0x00,0x21,0x10,0x52,0x00, +0xec,0x44,0x44,0x8c,0x60,0x45,0x43,0x8c,0x00,0x00,0x00,0x00,0x21,0x18,0x64,0x00, +0x42,0x18,0x03,0x00,0x44,0x51,0x03,0xae,0x21,0x10,0x05,0x02,0x01,0x00,0xa5,0x24, +0x1d,0x00,0xa3,0x28,0xb6,0x51,0x40,0xa0,0x7c,0x51,0x40,0xa0,0xfa,0xff,0x60,0x14, +0x99,0x51,0x40,0xa0,0x01,0x00,0x31,0x26,0x20,0x00,0x22,0x2a,0xd4,0x51,0x00,0xae, +0xe9,0xff,0x40,0x14,0x94,0x00,0x10,0x26,0x1c,0x00,0xbf,0x8f,0x18,0x00,0xb2,0x8f, +0x14,0x00,0xb1,0x8f,0x10,0x00,0xb0,0x8f,0x08,0x00,0xe0,0x03,0x20,0x00,0xbd,0x27, +0xc8,0xff,0xbd,0x27,0x02,0x80,0x02,0x3c,0x30,0x00,0xbe,0xaf,0x28,0x00,0xb6,0xaf, +0x68,0x15,0x46,0x24,0x34,0x00,0xbf,0xaf,0x2c,0x00,0xb7,0xaf,0x24,0x00,0xb5,0xaf, +0x20,0x00,0xb4,0xaf,0x1c,0x00,0xb3,0xaf,0x18,0x00,0xb2,0xaf,0x14,0x00,0xb1,0xaf, +0x10,0x00,0xb0,0xaf,0x8c,0x65,0xc2,0x8c,0xff,0x00,0x8d,0x30,0xff,0x00,0x03,0x24, +0xff,0xff,0x42,0x38,0x21,0xf0,0x00,0x00,0xff,0xff,0x04,0x34,0x0a,0xf0,0x62,0x00, +0x8c,0x65,0xc4,0xac,0xb0,0x00,0xa0,0x11,0x08,0x00,0x16,0x24,0x02,0x80,0x02,0x3c, +0xb8,0x90,0x45,0x24,0x90,0x44,0xc4,0x24,0xff,0x4f,0x00,0x08,0x21,0x88,0x00,0x00, +0x01,0x00,0x31,0x26,0x00,0x00,0x82,0xa0,0x1d,0x00,0x22,0x2a,0x0b,0x00,0x40,0x10, +0x01,0x00,0x84,0x24,0x21,0x10,0x25,0x02,0x00,0x00,0x42,0x90,0x00,0x00,0x00,0x00, +0xf7,0xff,0x40,0x10,0xfd,0xff,0x43,0x24,0x01,0x00,0x31,0x26,0x1d,0x00,0x22,0x2a, +0x00,0x00,0x83,0xa0,0xf7,0xff,0x40,0x14,0x01,0x00,0x84,0x24,0x02,0x80,0x02,0x3c, +0x68,0x15,0x4a,0x24,0x02,0x80,0x03,0x3c,0x02,0x80,0x02,0x3c,0x50,0x8e,0x6c,0x24, +0xd8,0x8d,0x4b,0x24,0x21,0x88,0x00,0x00,0x21,0x48,0x00,0x00,0x21,0x30,0x00,0x00, +0x21,0x40,0x2a,0x01,0x21,0x38,0x2c,0x01,0x21,0x10,0xe6,0x00,0x91,0x00,0x44,0x90, +0x00,0x00,0x45,0x90,0x21,0x18,0x06,0x01,0x01,0x00,0xc6,0x24,0x05,0x00,0xc2,0x28, +0xc5,0x43,0x64,0xa0,0xf8,0xff,0x40,0x14,0x34,0x43,0x65,0xa0,0x21,0x10,0x2b,0x02, +0x1d,0x00,0x44,0x90,0x00,0x00,0x45,0x90,0x21,0x18,0x2a,0x02,0x01,0x00,0x31,0x26, +0x1d,0x00,0x22,0x2a,0x73,0x44,0x64,0xa0,0x56,0x44,0x65,0xa0,0xeb,0xff,0x40,0x14, +0x05,0x00,0x29,0x25,0xa6,0x00,0xa0,0x11,0x02,0x80,0x02,0x3c,0x68,0x15,0x48,0x24, +0x02,0x80,0x03,0x3c,0x02,0x80,0x02,0x3c,0x4c,0x91,0x69,0x24,0xd8,0x90,0x47,0x24, +0x21,0x88,0x00,0x00,0x80,0x18,0x11,0x00,0x21,0x10,0x69,0x00,0x21,0x20,0x67,0x00, +0x00,0x00,0x46,0x8c,0x00,0x00,0x85,0x8c,0x01,0x00,0x31,0x26,0x21,0x18,0x68,0x00, +0x04,0x00,0x22,0x2a,0xec,0x44,0x65,0xac,0xf6,0xff,0x40,0x14,0x60,0x45,0x66,0xac, +0x02,0x80,0x02,0x3c,0x68,0x15,0x49,0x24,0x02,0x80,0x03,0x3c,0x02,0x80,0x02,0x3c, +0x4c,0x91,0x68,0x24,0xd8,0x90,0x47,0x24,0x04,0x00,0x11,0x24,0x80,0x20,0x11,0x00, +0x21,0x10,0x88,0x00,0x21,0x30,0x87,0x00,0x00,0x00,0x45,0x8c,0x00,0x00,0xc3,0x8c, +0x01,0x00,0x31,0x26,0x21,0x20,0x89,0x00,0x82,0x28,0x05,0x00,0x82,0x18,0x03,0x00, +0x1d,0x00,0x22,0x2a,0xec,0x44,0x83,0xac,0xf4,0xff,0x40,0x14,0x60,0x45,0x85,0xac, +0x02,0x80,0x02,0x3c,0x68,0x15,0x55,0x24,0x21,0x88,0x00,0x00,0x21,0xb8,0xa0,0x02, +0x21,0xa0,0x00,0x00,0x5a,0x50,0x00,0x08,0x21,0x90,0xa0,0x02,0x01,0x00,0x31,0x26, +0x20,0x00,0x22,0x2a,0x94,0x00,0x52,0x26,0x38,0x00,0x40,0x10,0x94,0x00,0x94,0x26, +0x78,0x51,0x44,0x8e,0x01,0x00,0x03,0x24,0x02,0x13,0x04,0x00,0x01,0x00,0x53,0x30, +0xf6,0xff,0x63,0x16,0x07,0x00,0x82,0x30,0x25,0xb0,0x03,0x3c,0x80,0x10,0x02,0x00, +0x21,0x10,0x43,0x00,0x84,0x01,0x45,0x8c,0x70,0x51,0x43,0x8e,0x21,0x20,0x20,0x02, +0x24,0x28,0xa3,0x00,0xce,0x0d,0x00,0x0c,0x74,0x51,0x45,0xae,0x7a,0x51,0x44,0x92, +0x5c,0x0d,0x00,0x0c,0xff,0x00,0x25,0x32,0x7a,0x51,0x50,0x92,0x00,0x00,0x00,0x00, +0x21,0x20,0x00,0x02,0x63,0x0d,0x00,0x0c,0x80,0x80,0x10,0x00,0x21,0x80,0x17,0x02, +0x48,0x51,0x40,0xae,0x4c,0x51,0x40,0xae,0x50,0x51,0x40,0xae,0x54,0x51,0x40,0xae, +0x58,0x51,0x40,0xae,0x5c,0x51,0x40,0xae,0x60,0x51,0x40,0xae,0x64,0x51,0x40,0xae, +0xec,0x44,0x04,0x8e,0x60,0x45,0x03,0x8e,0x26,0x10,0x53,0x00,0x21,0x30,0x00,0x00, +0x21,0x18,0x64,0x00,0x42,0x18,0x03,0x00,0x04,0x00,0x04,0x24,0x0a,0xb0,0x82,0x00, +0x44,0x51,0x43,0xae,0x21,0x20,0x95,0x02,0x21,0x10,0x86,0x00,0x01,0x00,0xc6,0x24, +0x1d,0x00,0xc3,0x28,0xb6,0x51,0x40,0xa0,0x7c,0x51,0x40,0xa0,0xfa,0xff,0x60,0x14, +0x99,0x51,0x40,0xa0,0x01,0x00,0x31,0x26,0x20,0x00,0x22,0x2a,0xd4,0x51,0x80,0xac, +0x94,0x00,0x52,0x26,0xca,0xff,0x40,0x14,0x94,0x00,0x94,0x26,0x25,0xb0,0x02,0x3c, +0x80,0x01,0x42,0x34,0x00,0x00,0x56,0xa0,0x03,0x00,0xc0,0x17,0x02,0x80,0x03,0x3c, +0x68,0x15,0x62,0x24,0x8c,0x65,0x40,0xac,0x34,0x00,0xbf,0x8f,0x30,0x00,0xbe,0x8f, +0x2c,0x00,0xb7,0x8f,0x28,0x00,0xb6,0x8f,0x24,0x00,0xb5,0x8f,0x20,0x00,0xb4,0x8f, +0x1c,0x00,0xb3,0x8f,0x18,0x00,0xb2,0x8f,0x14,0x00,0xb1,0x8f,0x10,0x00,0xb0,0x8f, +0x08,0x00,0xe0,0x03,0x38,0x00,0xbd,0x27,0x02,0x80,0x02,0x3c,0xb8,0x90,0x45,0x24, +0x90,0x44,0xc4,0x24,0x21,0x88,0x00,0x00,0x21,0x10,0x25,0x02,0x00,0x00,0x43,0x90, +0x01,0x00,0x31,0x26,0x1d,0x00,0x22,0x2a,0x00,0x00,0x83,0xa0,0xfa,0xff,0x40,0x14, +0x01,0x00,0x84,0x24,0x02,0x80,0x02,0x3c,0x68,0x15,0x4a,0x24,0x02,0x80,0x03,0x3c, +0x02,0x80,0x02,0x3c,0x74,0x8f,0x6c,0x24,0x14,0x8e,0x4b,0x24,0x21,0x88,0x00,0x00, +0x21,0x48,0x00,0x00,0x21,0x30,0x00,0x00,0x21,0x40,0x2a,0x01,0x21,0x38,0x2c,0x01, +0x21,0x10,0xe6,0x00,0x91,0x00,0x44,0x90,0x00,0x00,0x45,0x90,0x21,0x18,0x06,0x01, +0x01,0x00,0xc6,0x24,0x05,0x00,0xc2,0x28,0xc5,0x43,0x64,0xa0,0xf8,0xff,0x40,0x14, +0x34,0x43,0x65,0xa0,0x21,0x10,0x2b,0x02,0x1d,0x00,0x44,0x90,0x00,0x00,0x45,0x90, +0x21,0x18,0x2a,0x02,0x01,0x00,0x31,0x26,0x1d,0x00,0x22,0x2a,0x73,0x44,0x64,0xa0, +0x56,0x44,0x65,0xa0,0xeb,0xff,0x40,0x14,0x05,0x00,0x29,0x25,0x02,0x80,0x02,0x3c, +0x68,0x15,0x49,0x24,0x02,0x80,0x03,0x3c,0x02,0x80,0x02,0x3c,0x4c,0x91,0x68,0x24, +0xd8,0x90,0x47,0x24,0x21,0x88,0x00,0x00,0x80,0x18,0x11,0x00,0x21,0x10,0x68,0x00, +0x21,0x20,0x67,0x00,0x00,0x00,0x46,0x8c,0x00,0x00,0x85,0x8c,0x01,0x00,0x31,0x26, +0x21,0x18,0x69,0x00,0x1d,0x00,0x22,0x2a,0xec,0x44,0x65,0xac,0xf6,0xff,0x40,0x14, +0x60,0x45,0x66,0xac,0x4f,0x50,0x00,0x08,0x02,0x80,0x02,0x3c,0xd8,0xff,0xbd,0x27, +0xff,0xff,0x84,0x30,0x18,0x00,0xb2,0xaf,0xf0,0x01,0x92,0x30,0x02,0x91,0x12,0x00, +0x14,0x00,0xb1,0xaf,0xc0,0x88,0x12,0x00,0x21,0x88,0x32,0x02,0x80,0x88,0x11,0x00, +0x21,0x88,0x32,0x02,0x02,0x80,0x02,0x3c,0x68,0x15,0x42,0x24,0x80,0x88,0x11,0x00, +0x21,0x88,0x22,0x02,0x20,0x00,0xbf,0xaf,0x1c,0x00,0xb3,0xaf,0x10,0x00,0xb0,0xaf, +0x78,0x51,0x30,0x8e,0x00,0x02,0x82,0x30,0xff,0xfe,0x03,0x24,0x2b,0x10,0x02,0x00, +0x00,0x10,0x10,0x36,0x24,0x80,0x03,0x02,0x00,0x12,0x02,0x00,0x25,0x80,0x02,0x02, +0x70,0x51,0x25,0xae,0x78,0x51,0x30,0xae,0xa0,0x0e,0x00,0x0c,0x21,0x98,0xa0,0x00, +0xf8,0xff,0x03,0x24,0x24,0x80,0x03,0x02,0x07,0x00,0x42,0x30,0x25,0x80,0x02,0x02, +0x07,0x00,0x03,0x32,0x25,0xb0,0x02,0x3c,0x80,0x18,0x03,0x00,0x78,0x51,0x30,0xae, +0x21,0x18,0x62,0x00,0x84,0x01,0x62,0x8c,0x21,0x20,0x40,0x02,0x24,0x10,0x53,0x00, +0xce,0x0d,0x00,0x0c,0x74,0x51,0x22,0xae,0x7a,0x51,0x24,0x92,0x21,0x28,0x40,0x02, +0x20,0x00,0xbf,0x8f,0x1c,0x00,0xb3,0x8f,0x18,0x00,0xb2,0x8f,0x14,0x00,0xb1,0x8f, +0x10,0x00,0xb0,0x8f,0x5c,0x0d,0x00,0x08,0x28,0x00,0xbd,0x27,0xee,0x4e,0x00,0x08, +0xff,0x00,0x84,0x30,0x02,0x80,0x02,0x3c,0x68,0x15,0x43,0x24,0x1f,0x00,0x04,0x24, +0x78,0x51,0x62,0x8c,0xff,0xff,0x84,0x24,0x00,0x10,0x42,0x34,0x78,0x51,0x62,0xac, +0xfb,0xff,0x81,0x04,0x94,0x00,0x63,0x24,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00, +0x78,0xff,0xbd,0x27,0x60,0x00,0xb0,0xaf,0x25,0xb0,0x10,0x3c,0x70,0x00,0xb4,0xaf, +0xc4,0x02,0x14,0x36,0x00,0x00,0x80,0xae,0x74,0x00,0xb5,0xaf,0x6c,0x00,0xb3,0xaf, +0x68,0x00,0xb2,0xaf,0x64,0x00,0xb1,0xaf,0x84,0x00,0xbf,0xaf,0x80,0x00,0xbe,0xaf, +0x7c,0x00,0xb7,0xaf,0x78,0x00,0xb6,0xaf,0x04,0x00,0x02,0x36,0x04,0x0c,0x13,0x36, +0x00,0x00,0x43,0x8c,0x00,0x00,0x62,0x8e,0x0f,0x00,0x11,0x3c,0x24,0x18,0x71,0x00, +0x08,0x0c,0x12,0x36,0x4c,0x00,0xa2,0xaf,0x02,0xac,0x03,0x00,0x00,0x00,0x43,0x8e, +0x00,0x00,0x00,0x00,0x50,0x00,0xa3,0xaf,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34, +0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,0x21,0x20,0x00,0x00,0xdd,0x44,0x00,0x0c, +0xff,0xff,0x25,0x36,0x10,0x00,0xa2,0xaf,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34, +0x00,0x60,0x81,0x40,0xb3,0x0a,0x00,0x0c,0x64,0x00,0x04,0x24,0x7a,0x42,0x00,0x0c, +0x01,0x00,0x04,0x24,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x01,0x00,0x21,0x38, +0x00,0x60,0x81,0x40,0x21,0x20,0x00,0x00,0xdd,0x44,0x00,0x0c,0xff,0xff,0x25,0x36, +0x14,0x00,0xa2,0xaf,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40, +0xb3,0x0a,0x00,0x0c,0x64,0x00,0x04,0x24,0x7a,0x42,0x00,0x0c,0x21,0x20,0x00,0x00, +0xe0,0x0e,0x05,0x36,0x00,0x00,0xad,0x8c,0xdc,0x0e,0x06,0x36,0x70,0x0e,0x07,0x36, +0x18,0x00,0xad,0xaf,0x00,0x00,0xc2,0x8c,0x74,0x0e,0x08,0x36,0x78,0x0e,0x09,0x36, +0x1c,0x00,0xa2,0xaf,0x00,0x00,0xe3,0x8c,0x7c,0x0e,0x0a,0x36,0x80,0x0e,0x0b,0x36, +0x20,0x00,0xa3,0xaf,0x00,0x00,0x0d,0x8d,0x84,0x0e,0x0c,0x36,0x88,0x0e,0x17,0x36, +0x24,0x00,0xad,0xaf,0x00,0x00,0x22,0x8d,0x8c,0x0e,0x0e,0x36,0xd0,0x0e,0x18,0x36, +0x28,0x00,0xa2,0xaf,0x00,0x00,0x43,0x8d,0xd8,0x0e,0x11,0x36,0xd4,0x0e,0x10,0x36, +0x2c,0x00,0xa3,0xaf,0x00,0x00,0x6d,0x8d,0xed,0x3f,0x04,0x3c,0xfb,0x92,0x84,0x34, +0x30,0x00,0xad,0xaf,0x00,0x00,0x82,0x8d,0x25,0xb0,0x1e,0x3c,0x21,0xb0,0x00,0x00, +0x34,0x00,0xa2,0xaf,0x00,0x00,0xe3,0x8e,0xff,0x03,0x0f,0x3c,0x38,0x00,0xa3,0xaf, +0x00,0x00,0xcd,0x8d,0x00,0x00,0x00,0x00,0x3c,0x00,0xad,0xaf,0x00,0x00,0x02,0x8f, +0x00,0x00,0x00,0x00,0x40,0x00,0xa2,0xaf,0x00,0x00,0x03,0x8e,0x00,0x00,0x00,0x00, +0x44,0x00,0xa3,0xaf,0x00,0x00,0x2d,0x8e,0x00,0x00,0x00,0x00,0x48,0x00,0xad,0xaf, +0x00,0x00,0xa4,0xac,0x00,0x00,0xc4,0xac,0x00,0x00,0xe4,0xac,0x00,0x00,0x04,0xad, +0x00,0x00,0x24,0xad,0x00,0x00,0x44,0xad,0x00,0x00,0x64,0xad,0x00,0x00,0x84,0xad, +0x00,0x00,0xe4,0xae,0x00,0x00,0xc4,0xad,0x00,0x00,0x04,0xaf,0x00,0x00,0x04,0xae, +0x00,0x00,0x24,0xae,0xd0,0x51,0x00,0x08,0x00,0x00,0x00,0x00,0x7a,0x00,0xa2,0x12, +0x00,0x10,0x03,0x3c,0xac,0x0e,0xc2,0x37,0x94,0x0e,0xc3,0x37,0x25,0xb0,0x09,0x3c, +0x00,0x00,0x4a,0x8c,0xbc,0x0e,0x29,0x35,0x00,0x00,0x64,0x8c,0xb4,0x0e,0xc2,0x37, +0x9c,0x0e,0xc3,0x37,0x00,0x00,0x45,0x8c,0x00,0x00,0x66,0x8c,0x00,0x00,0x27,0x8d, +0x24,0x20,0x8f,0x00,0x00,0xd8,0x02,0x3c,0x24,0x10,0x42,0x01,0x24,0x28,0xaf,0x00, +0x24,0x30,0xcf,0x00,0x24,0x38,0xef,0x00,0x02,0x24,0x04,0x00,0x20,0x01,0x03,0x24, +0x01,0x00,0x42,0x2c,0x02,0x2c,0x05,0x00,0x02,0x34,0x06,0x00,0xf2,0x00,0x83,0x10, +0x02,0x3c,0x07,0x00,0xf0,0x00,0xa3,0x10,0x20,0x00,0x03,0x24,0xee,0x00,0xc3,0x10, +0x00,0x00,0x00,0x00,0xec,0x00,0xe3,0x10,0x01,0x00,0x08,0x24,0x80,0x00,0x03,0x24, +0x08,0x00,0x83,0x10,0x21,0x20,0x00,0x00,0x06,0x00,0xa3,0x10,0x21,0x20,0x00,0x00, +0xe0,0x03,0x03,0x24,0x03,0x00,0xc3,0x10,0x00,0x00,0x00,0x00,0xe5,0x00,0xe3,0x10, +0x01,0x00,0x04,0x24,0x06,0x00,0x40,0x10,0x09,0x00,0x02,0x24,0x04,0x00,0x00,0x11, +0x00,0x00,0x00,0x00,0x6d,0x01,0x80,0x14,0x25,0xb0,0x12,0x3c,0x09,0x00,0x02,0x24, +0xde,0x00,0xc2,0x12,0x25,0xb0,0x04,0x3c,0x01,0x00,0xd6,0x26,0x0a,0x00,0xc2,0x2e, +0x1d,0x01,0x40,0x10,0x00,0x00,0x00,0x00,0xc8,0xff,0xa0,0x16,0x01,0x00,0x02,0x24, +0xa0,0x00,0x03,0x3c,0x25,0xb0,0x09,0x3c,0x30,0x54,0x62,0x34,0x04,0x0c,0x29,0x35, +0x00,0x00,0x22,0xad,0x25,0xb0,0x0d,0x3c,0x08,0x00,0x02,0x3c,0xe4,0x00,0x42,0x34, +0x08,0x0c,0xad,0x35,0x25,0xb0,0x09,0x3c,0x00,0x00,0xa2,0xad,0x28,0x0e,0x29,0x35, +0x80,0x80,0x02,0x3c,0x00,0x00,0x22,0xad,0x14,0x02,0x04,0x3c,0x16,0x68,0x02,0x3c, +0x48,0x01,0x83,0x34,0x40,0x0e,0xc5,0x37,0x44,0x0e,0xc6,0x37,0xa2,0x04,0x42,0x34, +0x25,0xb0,0x0d,0x3c,0x00,0x00,0xa3,0xac,0x4c,0x0e,0xad,0x35,0x00,0x00,0xc2,0xac, +0xd1,0x28,0x02,0x24,0x00,0x00,0xa2,0xad,0x14,0x02,0x03,0x3c,0x16,0x28,0x02,0x3c, +0x4d,0x01,0x63,0x34,0x60,0x0e,0xc7,0x37,0x64,0x0e,0xc8,0x37,0xba,0x08,0x42,0x34, +0x00,0x00,0xe3,0xac,0x25,0xb0,0x06,0x3c,0x00,0x00,0x02,0xad,0x00,0xfb,0x0d,0x3c, +0x25,0xb0,0x09,0x3c,0x00,0xf8,0x02,0x3c,0xd1,0x28,0x07,0x24,0x6c,0x0e,0xc6,0x34, +0x48,0x0e,0x29,0x35,0x01,0x00,0x42,0x34,0x01,0x00,0xad,0x35,0x00,0x00,0xc7,0xac, +0x03,0x00,0x04,0x24,0x00,0x00,0x2d,0xad,0x00,0x00,0x22,0xad,0x84,0x0a,0x00,0x0c, +0x58,0x00,0xaf,0xaf,0xa0,0x00,0x04,0x3c,0x25,0xb0,0x03,0x3c,0x25,0xb0,0x06,0x3c, +0x25,0xb0,0x07,0x3c,0xe4,0x00,0x02,0x24,0x33,0x54,0x84,0x34,0x04,0x0c,0x63,0x34, +0x08,0x0c,0xc6,0x34,0x28,0x0e,0xe7,0x34,0x00,0x00,0x64,0xac,0x00,0x00,0xc2,0xac, +0x00,0x00,0xe0,0xac,0x01,0x00,0x02,0x24,0x58,0x00,0xaf,0x8f,0x8a,0xff,0xa2,0x16, +0xac,0x0e,0xc2,0x37,0x00,0x10,0x03,0x3c,0x1f,0xdc,0x79,0x34,0x1f,0x8c,0x7f,0x34, +0x23,0x8c,0x6d,0x34,0xa0,0x00,0x03,0x3c,0x30,0x54,0x65,0x34,0x00,0x01,0x17,0x3c, +0x25,0xb0,0x09,0x3c,0x25,0xb0,0x03,0x3c,0x00,0x01,0xe2,0x36,0x20,0x08,0x29,0x35, +0x20,0x08,0x63,0x34,0x00,0x00,0x30,0x8d,0x00,0x00,0x62,0xac,0x25,0xb0,0x03,0x3c, +0x28,0x08,0x63,0x34,0x00,0x00,0x62,0xac,0x25,0xb0,0x02,0x3c,0x04,0x0c,0x42,0x34, +0x00,0x00,0x45,0xac,0x25,0xb0,0x03,0x3c,0x08,0x00,0x02,0x3c,0xe4,0x00,0x42,0x34, +0x08,0x0c,0x63,0x34,0x00,0x00,0x62,0xac,0x25,0xb0,0x03,0x3c,0x00,0x7c,0xf3,0x36, +0x00,0x48,0xf4,0x36,0x30,0x0e,0xc6,0x37,0x34,0x0e,0xc7,0x37,0x80,0x80,0x02,0x3c, +0x28,0x0e,0x63,0x34,0x00,0x00,0x62,0xac,0x00,0x00,0xd3,0xac,0x00,0x00,0xf4,0xac, +0x14,0x02,0x06,0x3c,0x16,0x68,0x07,0x3c,0x38,0x0e,0xc8,0x37,0x40,0x0e,0xca,0x37, +0x44,0x0e,0xcb,0x37,0x3c,0x0e,0xc9,0x37,0x02,0x01,0xc6,0x34,0xc7,0x04,0xe7,0x34, +0x00,0x00,0x19,0xad,0x25,0xb0,0x03,0x3c,0x00,0x00,0x3f,0xad,0x00,0x00,0x46,0xad, +0x25,0xb0,0x09,0x3c,0x00,0x00,0x67,0xad,0x25,0xb0,0x06,0x3c,0x00,0x10,0x07,0x3c, +0x50,0x0e,0xcc,0x37,0x58,0x0e,0xce,0x37,0x5c,0x0e,0xd8,0x37,0xd1,0x28,0x02,0x24, +0x23,0xdc,0xe7,0x34,0x4c,0x0e,0x29,0x35,0x6c,0x0e,0x63,0x34,0x54,0x0e,0xc6,0x34, +0x00,0x00,0x22,0xad,0x00,0x00,0x62,0xac,0x14,0x02,0x09,0x3c,0x00,0x00,0x93,0xad, +0x25,0xb0,0x02,0x3c,0x00,0x00,0xd4,0xac,0x00,0x00,0xc7,0xad,0x00,0x00,0x0d,0xaf, +0x16,0x28,0x0d,0x3c,0x48,0x0e,0x42,0x34,0x00,0xf8,0x06,0x3c,0x02,0x01,0x29,0x35, +0x07,0x0d,0xad,0x35,0x00,0xfb,0x03,0x3c,0x60,0x0e,0xd1,0x37,0x64,0x0e,0xd2,0x37, +0x00,0x00,0x29,0xae,0x03,0x00,0x04,0x24,0x00,0x00,0x4d,0xae,0x00,0x00,0x43,0xac, +0x00,0x00,0x46,0xac,0x84,0x0a,0x00,0x0c,0x58,0x00,0xaf,0xaf,0x00,0x02,0x02,0x3c, +0x25,0xb0,0x07,0x3c,0x25,0xb0,0x09,0x3c,0xd1,0x28,0x42,0x34,0x4c,0x0e,0xe7,0x34, +0x6c,0x0e,0x29,0x35,0x25,0xb0,0x0d,0x3c,0x00,0x00,0xe2,0xac,0x48,0x0e,0xad,0x35, +0x00,0x00,0x22,0xad,0x00,0xf8,0x03,0x3c,0x00,0xfb,0x02,0x3c,0x00,0x00,0xa2,0xad, +0x03,0x00,0x04,0x24,0x00,0x00,0xa3,0xad,0x84,0x0a,0x00,0x0c,0x00,0x00,0x00,0x00, +0x4c,0x00,0xa6,0x8f,0x25,0xb0,0x04,0x3c,0x04,0x0c,0x84,0x34,0x00,0x00,0x86,0xac, +0x50,0x00,0xa9,0x8f,0x25,0xb0,0x07,0x3c,0x25,0xb0,0x0d,0x3c,0x00,0x01,0x10,0x32, +0x08,0x0c,0xe7,0x34,0x28,0x0e,0xad,0x35,0x00,0x00,0xe9,0xac,0x2b,0x80,0x10,0x00, +0x00,0x00,0xa0,0xad,0x58,0x00,0xaf,0x8f,0x17,0xff,0x00,0x16,0xac,0x0e,0xc2,0x37, +0x25,0xb0,0x02,0x3c,0x25,0xb0,0x03,0x3c,0x20,0x08,0x42,0x34,0x28,0x08,0x63,0x34, +0x00,0x00,0x57,0xac,0x25,0xb0,0x09,0x3c,0x00,0x00,0x77,0xac,0xac,0x0e,0xc2,0x37, +0x94,0x0e,0xc3,0x37,0x00,0x00,0x4a,0x8c,0xbc,0x0e,0x29,0x35,0x00,0x00,0x64,0x8c, +0xb4,0x0e,0xc2,0x37,0x9c,0x0e,0xc3,0x37,0x00,0x00,0x45,0x8c,0x00,0x00,0x66,0x8c, +0x00,0x00,0x27,0x8d,0x24,0x20,0x8f,0x00,0x00,0xd8,0x02,0x3c,0x24,0x10,0x42,0x01, +0x24,0x28,0xaf,0x00,0x24,0x30,0xcf,0x00,0x24,0x38,0xef,0x00,0x02,0x24,0x04,0x00, +0x20,0x01,0x03,0x24,0x01,0x00,0x42,0x2c,0x02,0x2c,0x05,0x00,0x02,0x34,0x06,0x00, +0x10,0xff,0x83,0x14,0x02,0x3c,0x07,0x00,0x80,0x00,0x03,0x24,0x16,0xff,0x83,0x14, +0x21,0x40,0x00,0x00,0xc3,0x51,0x00,0x08,0x21,0x20,0x00,0x00,0xff,0xff,0x02,0x34, +0xc4,0x02,0x84,0x34,0x00,0x00,0x82,0xac,0x94,0x0e,0xc3,0x37,0x9c,0x0e,0xc2,0x37, +0xa4,0x0e,0xc4,0x37,0xac,0x0e,0xc7,0x37,0x00,0x00,0x66,0x8c,0x00,0x00,0x49,0x8c, +0x00,0x00,0x8b,0x8c,0x00,0x00,0xe5,0x8c,0x02,0x80,0x07,0x3c,0x68,0x15,0xe7,0x24, +0x0c,0x40,0xe3,0x8c,0x10,0x40,0xe4,0x8c,0xb4,0x0e,0xc2,0x37,0x00,0x00,0x47,0x8c, +0x25,0xb0,0x0d,0x3c,0x00,0xfc,0x02,0x24,0x24,0x30,0xcf,0x00,0x24,0x28,0xaf,0x00, +0xbc,0x0e,0xad,0x35,0x00,0x00,0xa8,0x8d,0x24,0x20,0x82,0x00,0x02,0x34,0x06,0x00, +0x24,0x18,0x62,0x00,0x02,0x2c,0x05,0x00,0xc4,0x0e,0xca,0x37,0xcc,0x0e,0xcc,0x37, +0xf0,0xff,0x02,0x3c,0xff,0x03,0x42,0x34,0x25,0x18,0x66,0x00,0x25,0x20,0x85,0x00, +0x00,0x00,0x46,0x8d,0x24,0x48,0x2f,0x01,0x00,0x00,0x85,0x8d,0x24,0x38,0xef,0x00, +0x24,0x20,0x82,0x00,0x24,0x18,0x62,0x00,0x82,0x49,0x09,0x00,0x82,0x39,0x07,0x00, +0x0f,0xc0,0x02,0x3c,0xff,0xff,0x42,0x34,0x25,0x18,0x69,0x00,0x25,0x20,0x87,0x00, +0x24,0x58,0x6f,0x01,0x24,0x40,0x0f,0x01,0x24,0x20,0x82,0x00,0x24,0x18,0x62,0x00, +0x00,0x59,0x0b,0x00,0x00,0x41,0x08,0x00,0x24,0x30,0xcf,0x00,0x24,0x28,0xaf,0x00, +0x02,0x80,0x02,0x3c,0x68,0x15,0x42,0x24,0x25,0x18,0x6b,0x00,0x25,0x20,0x88,0x00, +0x02,0x34,0x06,0x00,0x02,0x2c,0x05,0x00,0x01,0x00,0xd6,0x26,0x0c,0x40,0x43,0xac, +0x10,0x40,0x44,0xac,0x14,0x40,0x46,0xa4,0x16,0x40,0x45,0xa4,0x0a,0x00,0xc2,0x2e, +0xe5,0xfe,0x40,0x14,0x00,0x00,0x00,0x00,0x18,0x00,0xad,0x8f,0x25,0xb0,0x02,0x3c, +0xe0,0x0e,0x43,0x34,0x10,0x00,0xa6,0x8f,0x00,0x00,0x6d,0xac,0x1c,0x00,0xa3,0x8f, +0xdc,0x0e,0x47,0x34,0x70,0x0e,0x48,0x34,0x00,0x00,0xe3,0xac,0x20,0x00,0xa7,0x8f, +0x74,0x0e,0x49,0x34,0x78,0x0e,0x4a,0x34,0x00,0x00,0x07,0xad,0x24,0x00,0xad,0x8f, +0x7c,0x0e,0x4b,0x34,0x80,0x0e,0x4c,0x34,0x00,0x00,0x2d,0xad,0x28,0x00,0xa3,0x8f, +0x25,0xb0,0x0d,0x3c,0x84,0x0e,0xad,0x35,0x00,0x00,0x43,0xad,0x2c,0x00,0xa7,0x8f, +0x88,0x0e,0x52,0x34,0x8c,0x0e,0x4e,0x34,0x00,0x00,0x67,0xad,0x30,0x00,0xa9,0x8f, +0xd4,0x0e,0x51,0x34,0xd0,0x0e,0x42,0x34,0x00,0x00,0x89,0xad,0x34,0x00,0xa3,0x8f, +0x0f,0x00,0x10,0x3c,0xff,0xff,0x05,0x36,0x00,0x00,0xa3,0xad,0x38,0x00,0xa7,0x8f, +0x21,0x20,0x00,0x00,0x00,0x00,0x47,0xae,0x3c,0x00,0xa9,0x8f,0x00,0x00,0x00,0x00, +0x00,0x00,0xc9,0xad,0x40,0x00,0xad,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x4d,0xac, +0x44,0x00,0xa2,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x22,0xae,0x48,0x00,0xa3,0x8f, +0x00,0x00,0x00,0x00,0x00,0x00,0x43,0xae,0xba,0x44,0x00,0x0c,0x00,0x00,0x00,0x00, +0xb3,0x0a,0x00,0x0c,0x64,0x00,0x04,0x24,0x7a,0x42,0x00,0x0c,0x01,0x00,0x04,0x24, +0x14,0x00,0xa6,0x8f,0xff,0xff,0x05,0x36,0xba,0x44,0x00,0x0c,0x21,0x20,0x00,0x00, +0xb3,0x0a,0x00,0x0c,0x64,0x00,0x04,0x24,0x84,0x00,0xbf,0x8f,0x80,0x00,0xbe,0x8f, +0x7c,0x00,0xb7,0x8f,0x78,0x00,0xb6,0x8f,0x74,0x00,0xb5,0x8f,0x70,0x00,0xb4,0x8f, +0x6c,0x00,0xb3,0x8f,0x68,0x00,0xb2,0x8f,0x64,0x00,0xb1,0x8f,0x60,0x00,0xb0,0x8f, +0x21,0x20,0x00,0x00,0x7a,0x42,0x00,0x08,0x88,0x00,0xbd,0x27,0x94,0x0e,0x42,0x36, +0x9c,0x0e,0x43,0x36,0xa4,0x0e,0x44,0x36,0xac,0x0e,0x45,0x36,0x02,0x80,0x0d,0x3c, +0x00,0x00,0x47,0x8c,0x68,0x15,0xad,0x25,0x00,0x00,0x6a,0x8c,0x00,0x00,0x8c,0x8c, +0x00,0x00,0xa3,0x8c,0x10,0x40,0xa4,0x8d,0xb4,0x0e,0x42,0x36,0x00,0x00,0x48,0x8c, +0x0c,0x40,0xa5,0x8d,0x25,0xb0,0x02,0x3c,0x00,0xfc,0x13,0x24,0xbc,0x0e,0x42,0x34, +0x24,0x18,0x6f,0x00,0x00,0x00,0x49,0x8c,0x02,0x1c,0x03,0x00,0x24,0x38,0xef,0x00, +0x24,0x20,0x93,0x00,0xf0,0xff,0x06,0x3c,0x25,0x20,0x83,0x00,0xff,0x03,0xc6,0x34, +0x02,0x3c,0x07,0x00,0xc4,0x0e,0x42,0x36,0x24,0x28,0xb3,0x00,0x24,0x40,0x0f,0x01, +0xcc,0x0e,0x4b,0x36,0x25,0x28,0xa7,0x00,0x24,0x20,0x86,0x00,0x00,0x00,0x47,0x8c, +0x24,0x50,0x4f,0x01,0x00,0x00,0x63,0x8d,0x82,0x41,0x08,0x00,0x0f,0xc0,0x02,0x3c, +0xff,0xff,0x42,0x34,0x25,0x20,0x88,0x00,0x82,0x51,0x0a,0x00,0x24,0x28,0xa6,0x00, +0x24,0x48,0x2f,0x01,0x24,0x88,0x82,0x00,0x25,0x28,0xaa,0x00,0x24,0x60,0x8f,0x01, +0x00,0x49,0x09,0x00,0x25,0x88,0x29,0x02,0x24,0x28,0xa2,0x00,0x24,0x18,0x6f,0x00, +0x00,0x61,0x0c,0x00,0x24,0x38,0xef,0x00,0x25,0x28,0xac,0x00,0x02,0x3c,0x07,0x00, +0x02,0x1c,0x03,0x00,0x82,0x27,0x11,0x00,0x01,0x00,0x02,0x24,0x16,0x40,0xa3,0xa5, +0x14,0x40,0xa7,0xa5,0x0c,0x40,0xa5,0xad,0x4a,0x00,0x82,0x10,0x10,0x40,0xb1,0xad, +0x80,0x0c,0x4c,0x36,0x00,0x00,0x8a,0x8d,0x82,0x72,0x05,0x00,0xff,0x03,0xce,0x31, +0x00,0x02,0xc3,0x31,0x25,0x10,0xd3,0x01,0x0b,0x70,0x43,0x00,0x82,0x85,0x0a,0x00, +0x18,0x00,0xd0,0x01,0xff,0x03,0xaf,0x30,0x00,0x02,0xa3,0x30,0x25,0x10,0xf3,0x01, +0x0b,0x78,0x43,0x00,0x02,0x75,0x11,0x00,0xff,0x03,0xce,0x31,0xc0,0xff,0x08,0x3c, +0x25,0x18,0xd3,0x01,0x00,0x02,0xc2,0x31,0x00,0xfc,0x06,0x35,0x0b,0x70,0x62,0x00, +0x24,0x38,0x46,0x01,0x94,0x0c,0x4a,0x36,0xff,0x0f,0x09,0x3c,0xff,0xff,0x29,0x35, +0x88,0x0c,0x54,0x36,0x12,0x20,0x00,0x00,0x02,0x22,0x04,0x00,0x3f,0x00,0x82,0x30, +0x18,0x00,0xf0,0x01,0x82,0x7a,0x11,0x00,0xff,0x03,0xef,0x31,0x00,0x14,0x02,0x00, +0x25,0x38,0xe2,0x00,0x00,0x02,0xe3,0x31,0x25,0x10,0xf3,0x01,0x0b,0x78,0x43,0x00, +0xc0,0x03,0x84,0x30,0x80,0x25,0x04,0x00,0x9c,0x0c,0x4b,0x36,0x12,0x28,0x00,0x00, +0x02,0x2a,0x05,0x00,0xff,0x03,0xa2,0x30,0x25,0x10,0xe2,0x00,0x00,0x00,0x82,0xad, +0x00,0x00,0x42,0x8d,0x00,0x00,0x00,0x00,0x24,0x10,0x49,0x00,0x25,0x10,0x44,0x00, +0x00,0x00,0x42,0xad,0x00,0x00,0x8a,0x8e,0x00,0x00,0x00,0x00,0x24,0x40,0x48,0x01, +0x82,0x85,0x08,0x00,0x18,0x00,0xd0,0x01,0x24,0x30,0x46,0x01,0x12,0x18,0x00,0x00, +0x02,0x1a,0x03,0x00,0x3f,0x00,0x62,0x30,0x18,0x00,0xf0,0x01,0x00,0x14,0x02,0x00, +0x25,0x30,0xc2,0x00,0xc0,0x03,0x63,0x30,0x80,0x1d,0x03,0x00,0x12,0x20,0x00,0x00, +0x02,0x22,0x04,0x00,0xff,0x03,0x82,0x30,0x25,0x10,0xc2,0x00,0x00,0x00,0x82,0xae, +0x00,0x00,0x62,0x8d,0x00,0x00,0x00,0x00,0x24,0x10,0x49,0x00,0x25,0x10,0x43,0x00, +0x00,0x00,0x62,0xad,0x00,0x17,0x16,0x00,0x25,0xb0,0x03,0x3c,0xdd,0xdd,0x42,0x34, +0xc4,0x02,0x63,0x34,0x00,0x00,0x62,0xac,0xec,0x52,0x00,0x08,0x00,0x00,0x00,0x00, +0xe0,0xff,0xbd,0x27,0x44,0x00,0x02,0x24,0x10,0x00,0xa2,0xa3,0x49,0x00,0x03,0x24, +0x47,0x00,0x02,0x24,0x02,0x80,0x07,0x3c,0x8c,0x97,0xe7,0x24,0x11,0x00,0xa3,0xa3, +0x12,0x00,0xa2,0xa3,0x10,0x27,0x03,0x24,0x01,0x00,0x02,0x24,0x01,0x80,0x06,0x3c, +0x10,0x00,0xa5,0x27,0x21,0x20,0xe0,0x00,0xe8,0x51,0xc6,0x24,0x0c,0x00,0xe3,0xac, +0x14,0x00,0xe2,0xa0,0x18,0x00,0xbf,0xaf,0xfb,0x0c,0x00,0x0c,0x13,0x00,0xa0,0xa3, +0x18,0x00,0xbf,0x8f,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x20,0x00,0xbd,0x27, +0xd0,0xff,0xbd,0x27,0x25,0xb0,0x02,0x3c,0x20,0x00,0xb4,0xaf,0x1c,0x00,0xb3,0xaf, +0x03,0x0d,0x44,0x34,0x2c,0x00,0xbf,0xaf,0x28,0x00,0xb6,0xaf,0x24,0x00,0xb5,0xaf, +0x18,0x00,0xb2,0xaf,0x14,0x00,0xb1,0xaf,0x10,0x00,0xb0,0xaf,0x00,0x00,0x83,0x90, +0x42,0x00,0x45,0x34,0xff,0x00,0x73,0x30,0x70,0x00,0x74,0x32,0x29,0x00,0x80,0x16, +0x8f,0x00,0x62,0x32,0xff,0xff,0x02,0x24,0x00,0x00,0xa2,0xa0,0x00,0x60,0x01,0x40, +0x01,0x00,0x21,0x34,0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,0x0f,0x00,0x11,0x3c, +0x18,0x00,0x04,0x24,0xdd,0x44,0x00,0x0c,0xff,0xff,0x25,0x36,0x21,0x80,0x40,0x00, +0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40,0xb3,0x0a,0x00,0x0c, +0x64,0x00,0x04,0x24,0x00,0x80,0x06,0x36,0xff,0xff,0x25,0x36,0xba,0x44,0x00,0x0c, +0x18,0x00,0x04,0x24,0x84,0x0a,0x00,0x0c,0x03,0x00,0x04,0x24,0x21,0x30,0xa0,0x02, +0xff,0xff,0x25,0x36,0x5c,0x00,0x80,0x16,0x21,0x20,0x00,0x00,0x2c,0x00,0xbf,0x8f, +0x28,0x00,0xb6,0x8f,0x24,0x00,0xb5,0x8f,0x20,0x00,0xb4,0x8f,0x1c,0x00,0xb3,0x8f, +0x18,0x00,0xb2,0x8f,0x14,0x00,0xb1,0x8f,0x10,0x00,0xb0,0x8f,0x25,0xb0,0x02,0x3c, +0x42,0x00,0x42,0x34,0x30,0x00,0xbd,0x27,0x00,0x00,0x40,0xa0,0x08,0x00,0xe0,0x03, +0x00,0x00,0x00,0x00,0x00,0x00,0x82,0xa0,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34, +0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,0x0f,0x00,0x11,0x3c,0x21,0x20,0x00,0x00, +0xdd,0x44,0x00,0x0c,0xff,0xff,0x25,0x36,0x21,0xa8,0x40,0x00,0x00,0x60,0x01,0x40, +0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40,0xb3,0x0a,0x00,0x0c,0x64,0x00,0x04,0x24, +0x7a,0x42,0x00,0x0c,0x01,0x00,0x04,0x24,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34, +0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,0x21,0x20,0x00,0x00,0xdd,0x44,0x00,0x0c, +0xff,0xff,0x25,0x36,0x21,0xb0,0x40,0x00,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34, +0x00,0x60,0x81,0x40,0x64,0x00,0x04,0x24,0xb3,0x0a,0x00,0x0c,0x08,0x00,0x10,0x3c, +0xff,0xff,0x10,0x36,0x7a,0x42,0x00,0x0c,0x21,0x20,0x00,0x00,0x01,0x00,0x12,0x3c, +0x24,0x30,0xb0,0x02,0x25,0x30,0xd2,0x00,0xff,0xff,0x25,0x36,0xba,0x44,0x00,0x0c, +0x21,0x20,0x00,0x00,0xb3,0x0a,0x00,0x0c,0x64,0x00,0x04,0x24,0x24,0x80,0xd0,0x02, +0x7a,0x42,0x00,0x0c,0x01,0x00,0x04,0x24,0x25,0x30,0x12,0x02,0xff,0xff,0x25,0x36, +0xba,0x44,0x00,0x0c,0x21,0x20,0x00,0x00,0xb3,0x0a,0x00,0x0c,0x64,0x00,0x04,0x24, +0x7a,0x42,0x00,0x0c,0x21,0x20,0x00,0x00,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34, +0x01,0x00,0x21,0x38,0x00,0x60,0x81,0x40,0x0f,0x00,0x11,0x3c,0x18,0x00,0x04,0x24, +0xdd,0x44,0x00,0x0c,0xff,0xff,0x25,0x36,0x21,0x80,0x40,0x00,0x00,0x60,0x01,0x40, +0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40,0xb3,0x0a,0x00,0x0c,0x64,0x00,0x04,0x24, +0x00,0x80,0x06,0x36,0xff,0xff,0x25,0x36,0xba,0x44,0x00,0x0c,0x18,0x00,0x04,0x24, +0x84,0x0a,0x00,0x0c,0x03,0x00,0x04,0x24,0x21,0x30,0xa0,0x02,0xff,0xff,0x25,0x36, +0xa6,0xff,0x80,0x12,0x21,0x20,0x00,0x00,0x25,0xb0,0x02,0x3c,0x03,0x0d,0x42,0x34, +0x00,0x00,0x53,0xa0,0xba,0x44,0x00,0x0c,0x00,0x00,0x00,0x00,0xb3,0x0a,0x00,0x0c, +0x64,0x00,0x04,0x24,0x7a,0x42,0x00,0x0c,0x01,0x00,0x04,0x24,0xff,0xff,0x25,0x36, +0x21,0x30,0xc0,0x02,0xba,0x44,0x00,0x0c,0x21,0x20,0x00,0x00,0xb3,0x0a,0x00,0x0c, +0x64,0x00,0x04,0x24,0x2c,0x00,0xbf,0x8f,0x28,0x00,0xb6,0x8f,0x24,0x00,0xb5,0x8f, +0x20,0x00,0xb4,0x8f,0x1c,0x00,0xb3,0x8f,0x18,0x00,0xb2,0x8f,0x14,0x00,0xb1,0x8f, +0x10,0x00,0xb0,0x8f,0x21,0x20,0x00,0x00,0x7a,0x42,0x00,0x08,0x30,0x00,0xbd,0x27, +0xd0,0xff,0xbd,0x27,0x28,0x00,0xb4,0xaf,0x02,0x80,0x14,0x3c,0x2c,0x00,0xbf,0xaf, +0x24,0x00,0xb3,0xaf,0x20,0x00,0xb2,0xaf,0x1c,0x00,0xb1,0xaf,0x18,0x00,0xb0,0xaf, +0x68,0x15,0x86,0x26,0x0c,0x40,0xc2,0x8c,0x00,0x00,0x00,0x00,0x82,0x17,0x02,0x00, +0x01,0x00,0x42,0x30,0x07,0x00,0x40,0x14,0x68,0x15,0x85,0x26,0x08,0x40,0xc2,0x8c, +0x01,0x00,0x03,0x24,0x42,0x17,0x02,0x00,0x03,0x00,0x42,0x30,0xf0,0x00,0x43,0x10, +0x25,0xb0,0x02,0x3c,0x0c,0x40,0xa2,0x8c,0x01,0x00,0x03,0x24,0x82,0x17,0x02,0x00, +0x01,0x00,0x44,0x30,0x0a,0x00,0x83,0x10,0x00,0x00,0x00,0x00,0x2c,0x00,0xbf,0x8f, +0x28,0x00,0xb4,0x8f,0x24,0x00,0xb3,0x8f,0x20,0x00,0xb2,0x8f,0x1c,0x00,0xb1,0x8f, +0x18,0x00,0xb0,0x8f,0x21,0x10,0x00,0x00,0x08,0x00,0xe0,0x03,0x30,0x00,0xbd,0x27, +0x08,0x40,0xa2,0x8c,0x00,0x00,0x00,0x00,0x42,0x17,0x02,0x00,0x03,0x00,0x42,0x30, +0xf2,0xff,0x44,0x14,0x25,0xb0,0x02,0x3c,0x0e,0x0c,0x44,0x34,0x00,0x00,0x83,0x90, +0x00,0x01,0x02,0x24,0xff,0x00,0x63,0x30,0x01,0x00,0x63,0x24,0x8b,0x01,0x62,0x10, +0x00,0x00,0x00,0x00,0x00,0x00,0x83,0xa0,0x68,0x15,0x84,0x26,0x10,0x40,0x82,0x8c, +0x01,0x00,0x03,0x24,0x82,0x17,0x02,0x00,0xa4,0x01,0x43,0x10,0x0f,0x00,0x10,0x3c, +0xc7,0x42,0x92,0x90,0x68,0x15,0x90,0x26,0xc6,0x42,0x03,0x92,0x25,0xb0,0x11,0x3c, +0x62,0x0c,0x22,0x36,0x00,0x00,0x52,0xa0,0x17,0x01,0x60,0x10,0x01,0x00,0x02,0x24, +0x03,0x0d,0x23,0x36,0x00,0x00,0x62,0x90,0x00,0x00,0x00,0x00,0x70,0x00,0x42,0x30, +0x3e,0x01,0x40,0x14,0x63,0x0c,0x23,0x36,0xc4,0x42,0x02,0x96,0x00,0x00,0x00,0x00, +0x23,0x20,0x52,0x00,0x2b,0x18,0x52,0x00,0x23,0x10,0x42,0x02,0x0a,0x10,0x83,0x00, +0x03,0x00,0x42,0x2c,0x0b,0x01,0x40,0x10,0x00,0x00,0x00,0x00,0xc4,0x42,0x03,0x96, +0x63,0x0c,0x22,0x36,0x00,0x00,0x43,0xa0,0x68,0x15,0x83,0x26,0xc3,0x42,0x62,0x90, +0x08,0x40,0x66,0x8c,0xc2,0x42,0x72,0xa0,0x23,0x20,0x52,0x00,0x2b,0x38,0x42,0x02, +0x23,0x50,0x42,0x02,0x02,0x2c,0x06,0x00,0x0b,0x50,0x87,0x00,0x3f,0x00,0xa5,0x30, +0x3f,0x00,0xc4,0x30,0x24,0x00,0x02,0x24,0x20,0x00,0x03,0x24,0x23,0x10,0x44,0x00, +0x2d,0x01,0x40,0x15,0x23,0x18,0x65,0x00,0x21,0x30,0x80,0x00,0x21,0x48,0xa0,0x00, +0x02,0x80,0x0b,0x3c,0x68,0x15,0x83,0x26,0x80,0x10,0x06,0x00,0x21,0x10,0x43,0x00, +0x0c,0x40,0x63,0x8c,0x18,0x40,0x44,0x8c,0xff,0x03,0x67,0x30,0x1b,0x01,0xe0,0x10, +0x82,0x2d,0x04,0x00,0x00,0x02,0x62,0x30,0x04,0x00,0x40,0x10,0x18,0x00,0xe5,0x00, +0x00,0xfc,0x02,0x24,0x25,0x38,0xe2,0x00,0x18,0x00,0xe5,0x00,0x82,0x22,0x03,0x00, +0xff,0x03,0x84,0x30,0x00,0x02,0x83,0x30,0x12,0x10,0x00,0x00,0x02,0x12,0x02,0x00, +0x03,0x00,0x60,0x10,0xff,0x03,0x48,0x30,0x00,0xfc,0x02,0x24,0x25,0x20,0x82,0x00, +0x18,0x00,0x85,0x00,0x80,0x2d,0x05,0x00,0x25,0xb0,0x06,0x3c,0x80,0x0c,0xc7,0x34, +0x94,0x0c,0xc6,0x34,0x12,0x20,0x00,0x00,0x02,0x22,0x04,0x00,0x3f,0x00,0x82,0x30, +0x00,0x14,0x02,0x00,0x25,0x28,0xa2,0x00,0x25,0x28,0xa8,0x00,0x10,0x00,0xa5,0xaf, +0x00,0x00,0xe5,0xac,0x00,0x00,0xc3,0x8c,0xff,0x0f,0x02,0x3c,0xc0,0x03,0x84,0x30, +0xff,0xff,0x42,0x34,0x80,0x25,0x04,0x00,0x24,0x18,0x62,0x00,0x25,0x18,0x64,0x00, +0x10,0x00,0xa3,0xaf,0x00,0x00,0xc3,0xac,0x68,0x15,0x83,0x26,0x08,0x40,0x62,0x8c, +0x00,0x00,0x00,0x00,0x08,0x01,0x40,0x04,0xc0,0x28,0x09,0x00,0x21,0x28,0xa3,0x00, +0xac,0x40,0xa3,0x90,0x25,0xb0,0x04,0x3c,0x22,0x0a,0x82,0x34,0x00,0x00,0x43,0xa0, +0xad,0x40,0xa6,0x90,0x23,0x0a,0x82,0x34,0x24,0x0a,0x87,0x34,0x00,0x00,0x46,0xa0, +0xae,0x40,0xa3,0x90,0x25,0x0a,0x86,0x34,0x26,0x0a,0x88,0x34,0x00,0x00,0xe3,0xa0, +0xaf,0x40,0xa2,0x90,0x27,0x0a,0x87,0x34,0x28,0x0a,0x89,0x34,0x00,0x00,0xc2,0xa0, +0xb0,0x40,0xa3,0x90,0x29,0x0a,0x84,0x34,0x00,0x00,0x03,0xa1,0xb1,0x40,0xa2,0x90, +0x00,0x00,0x00,0x00,0x00,0x00,0xe2,0xa0,0xb2,0x40,0xa3,0x90,0x00,0x00,0x00,0x00, +0x00,0x00,0x23,0xa1,0xb3,0x40,0xa2,0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x82,0xa0, +0x8e,0x7d,0x63,0x91,0x22,0x00,0x02,0x24,0x03,0x00,0x62,0x10,0x92,0x00,0x02,0x24, +0x62,0xff,0x62,0x14,0x00,0x00,0x00,0x00,0x68,0x15,0x82,0x26,0x08,0x40,0x43,0x8c, +0x01,0x00,0x44,0x39,0x24,0x00,0x02,0x24,0x02,0x1a,0x03,0x00,0x3f,0x00,0x63,0x30, +0x01,0x00,0x84,0x30,0x04,0x01,0x80,0x10,0x23,0x28,0x43,0x00,0x42,0x18,0x0a,0x00, +0x40,0x10,0x03,0x00,0x21,0x50,0x43,0x00,0x68,0x15,0x83,0x26,0xc3,0x42,0x62,0x90, +0x00,0x00,0x00,0x00,0x2b,0x10,0x42,0x02,0x08,0x01,0x40,0x10,0x21,0x20,0x00,0x00, +0x2b,0x10,0x45,0x01,0x07,0x00,0x40,0x10,0x24,0x00,0x04,0x24,0x08,0x40,0x62,0x8c, +0x00,0x00,0x00,0x00,0x02,0x12,0x02,0x00,0x3f,0x00,0x42,0x30,0x21,0x20,0x4a,0x00, +0x68,0x15,0x83,0x26,0x80,0x10,0x04,0x00,0x10,0x40,0x66,0x8c,0x21,0x10,0x43,0x00, +0x18,0x40,0x44,0x8c,0x82,0x3a,0x06,0x00,0xff,0x03,0xe7,0x30,0xf0,0x00,0xe0,0x10, +0x82,0x2d,0x04,0x00,0x00,0x02,0xe2,0x30,0x04,0x00,0x40,0x10,0x18,0x00,0xe5,0x00, +0x00,0xfc,0x02,0x24,0x25,0x38,0xe2,0x00,0x18,0x00,0xe5,0x00,0x02,0x25,0x06,0x00, +0xff,0x03,0x84,0x30,0x00,0x02,0x83,0x30,0x12,0x10,0x00,0x00,0x02,0x12,0x02,0x00, +0x03,0x00,0x60,0x10,0xff,0x03,0x48,0x30,0x00,0xfc,0x02,0x24,0x25,0x20,0x82,0x00, +0x18,0x00,0x85,0x00,0x80,0x2d,0x05,0x00,0x25,0xb0,0x06,0x3c,0x88,0x0c,0xc7,0x34, +0x9c,0x0c,0xc6,0x34,0x12,0x20,0x00,0x00,0x02,0x22,0x04,0x00,0x3f,0x00,0x82,0x30, +0x00,0x14,0x02,0x00,0x25,0x28,0xa2,0x00,0x25,0x28,0xa8,0x00,0x10,0x00,0xa5,0xaf, +0x00,0x00,0xe5,0xac,0x00,0x00,0xc3,0x8c,0xff,0x0f,0x02,0x3c,0xc0,0x03,0x84,0x30, +0xff,0xff,0x42,0x34,0x80,0x25,0x04,0x00,0x24,0x18,0x62,0x00,0x25,0x18,0x64,0x00, +0x10,0x00,0xa3,0xaf,0x00,0x00,0xc3,0xac,0x95,0x54,0x00,0x08,0x00,0x00,0x00,0x00, +0x80,0x0c,0x42,0x34,0x00,0x00,0x43,0x8c,0xc0,0xff,0x02,0x3c,0x21,0x88,0x00,0x00, +0x24,0x28,0x62,0x00,0xc0,0xff,0x04,0x3c,0x8a,0x55,0x00,0x08,0x18,0x40,0xc3,0x24, +0x01,0x00,0x31,0x26,0x25,0x00,0x22,0x2e,0x0d,0x00,0x40,0x10,0x02,0x80,0x0b,0x3c, +0x00,0x00,0x62,0x8c,0x00,0x00,0x00,0x00,0x24,0x10,0x44,0x00,0xf8,0xff,0x45,0x14, +0x04,0x00,0x63,0x24,0x08,0x40,0xc2,0x8c,0xc0,0xff,0x03,0x24,0x3f,0x00,0x24,0x32, +0x24,0x10,0x43,0x00,0x25,0x10,0x44,0x00,0x08,0x40,0xc2,0xac,0x02,0x80,0x0b,0x3c, +0x8e,0x7d,0x63,0x91,0x22,0x00,0x02,0x24,0x3e,0x00,0x62,0x10,0x92,0x00,0x02,0x24, +0x3d,0x00,0x62,0x10,0x25,0xb0,0x02,0x3c,0x25,0xb0,0x02,0x3c,0x24,0x0a,0x42,0x34, +0x00,0x00,0x44,0x8c,0x3f,0x3f,0x03,0x3c,0x3f,0x3f,0x63,0x34,0x24,0x20,0x83,0x00, +0x02,0x80,0x02,0x3c,0x02,0x80,0x03,0x3c,0x16,0x56,0x53,0x24,0x1e,0x57,0x72,0x24, +0x21,0x88,0x00,0x00,0xb1,0x55,0x00,0x08,0x10,0x00,0xa4,0xaf,0xd4,0x45,0x00,0x0c, +0x00,0x00,0x00,0x00,0x47,0x00,0x40,0x10,0x68,0x15,0x85,0x26,0x01,0x00,0x31,0x26, +0x21,0x00,0x22,0x2e,0x17,0x00,0x40,0x10,0x68,0x15,0x84,0x26,0xc0,0x80,0x11,0x00, +0x10,0x00,0xa4,0x27,0x21,0x28,0x13,0x02,0xd4,0x45,0x00,0x0c,0x04,0x00,0x06,0x24, +0x21,0x28,0x12,0x02,0x10,0x00,0xa4,0x27,0xf0,0xff,0x40,0x14,0x04,0x00,0x06,0x24, +0x68,0x15,0x85,0x26,0x08,0x40,0xa3,0x8c,0xc0,0xff,0x02,0x3c,0xff,0xff,0x42,0x34, +0x3f,0x00,0x24,0x32,0x24,0x18,0x62,0x00,0x00,0x24,0x04,0x00,0xff,0x7f,0x02,0x3c, +0x25,0x18,0x64,0x00,0xff,0xff,0x42,0x34,0x24,0x18,0x62,0x00,0x08,0x40,0xa3,0xac, +0x68,0x15,0x84,0x26,0x0c,0x40,0x83,0x8c,0x00,0x40,0x02,0x3c,0x25,0x18,0x62,0x00, +0x25,0xb0,0x02,0x3c,0x0e,0x0c,0x42,0x34,0x0c,0x40,0x83,0xac,0x00,0x00,0x40,0xa0, +0x8f,0x54,0x00,0x08,0x68,0x15,0x85,0x26,0xc6,0x42,0x02,0xa2,0xba,0x54,0x00,0x08, +0xc4,0x42,0x12,0xa6,0xda,0x53,0x00,0x0c,0x00,0x00,0x00,0x00,0xc9,0x54,0x00,0x08, +0xc4,0x42,0x12,0xa6,0x25,0xb0,0x02,0x3c,0x88,0x0c,0x42,0x34,0x00,0x00,0x44,0x8c, +0x02,0x80,0x03,0x3c,0x68,0x15,0x66,0x24,0xc0,0xff,0x02,0x3c,0x24,0x28,0x82,0x00, +0x21,0x88,0x00,0x00,0xc0,0xff,0x04,0x3c,0xe6,0x55,0x00,0x08,0x18,0x40,0xc3,0x24, +0x01,0x00,0x31,0x26,0x25,0x00,0x22,0x2e,0xb8,0xff,0x40,0x10,0x25,0xb0,0x02,0x3c, +0x00,0x00,0x62,0x8c,0x00,0x00,0x00,0x00,0x24,0x10,0x44,0x00,0xf8,0xff,0x45,0x14, +0x04,0x00,0x63,0x24,0x08,0x40,0xc2,0x8c,0x3f,0x00,0x23,0x32,0xff,0xc0,0x04,0x24, +0x24,0x10,0x44,0x00,0x00,0x1a,0x03,0x00,0x25,0x10,0x43,0x00,0x9c,0x55,0x00,0x08, +0x08,0x40,0xc2,0xac,0x08,0x40,0xa3,0x8c,0xc0,0xff,0x02,0x3c,0xff,0xff,0x42,0x34, +0x3f,0x00,0x24,0x32,0x24,0x18,0x62,0x00,0x00,0x24,0x04,0x00,0x25,0x18,0x64,0x00, +0x00,0x80,0x02,0x3c,0xc5,0x55,0x00,0x08,0x25,0x18,0x62,0x00,0xcc,0xff,0x02,0x24, +0x00,0x00,0x62,0xa0,0xcd,0x54,0x00,0x08,0x68,0x15,0x83,0x26,0x25,0xb0,0x02,0x3c, +0x94,0x0c,0x43,0x34,0x80,0x0c,0x42,0x34,0x00,0x00,0x44,0xac,0x00,0x00,0x60,0xac, +0x0d,0x55,0x00,0x08,0x68,0x15,0x83,0x26,0x2f,0x00,0xe0,0x10,0x21,0x30,0x00,0x00, +0x2b,0x10,0x42,0x01,0x21,0x20,0x8a,0x00,0x00,0x00,0x42,0x38,0x24,0x00,0x06,0x24, +0x2b,0x18,0x43,0x01,0x0b,0x30,0x82,0x00,0xcd,0xfe,0x60,0x10,0x20,0x00,0x09,0x24, +0x68,0x15,0x83,0x26,0x0a,0x40,0x62,0x94,0x02,0x80,0x0b,0x3c,0x3f,0x00,0x42,0x30, +0xe0,0x54,0x00,0x08,0x21,0x48,0x4a,0x00,0x21,0x28,0xa3,0x00,0xb4,0x41,0xa3,0x90, +0x25,0xb0,0x04,0x3c,0x22,0x0a,0x82,0x34,0x00,0x00,0x43,0xa0,0xb5,0x41,0xa6,0x90, +0x23,0x0a,0x82,0x34,0x24,0x0a,0x87,0x34,0x00,0x00,0x46,0xa0,0xb6,0x41,0xa3,0x90, +0x25,0x0a,0x86,0x34,0x26,0x0a,0x88,0x34,0x00,0x00,0xe3,0xa0,0xb7,0x41,0xa2,0x90, +0x27,0x0a,0x87,0x34,0x28,0x0a,0x89,0x34,0x00,0x00,0xc2,0xa0,0xb8,0x41,0xa3,0x90, +0x29,0x0a,0x84,0x34,0x00,0x00,0x03,0xa1,0xb9,0x41,0xa2,0x90,0x00,0x00,0x00,0x00, +0x00,0x00,0xe2,0xa0,0xba,0x41,0xa3,0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x23,0xa1, +0xbb,0x41,0xa2,0x90,0x2d,0x55,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xa0, +0xad,0x54,0x00,0x08,0x68,0x15,0x84,0x26,0x23,0x10,0x8a,0x00,0x2b,0x18,0x44,0x01, +0x2b,0x20,0x45,0x01,0x0b,0x30,0x43,0x00,0xa1,0xfe,0x80,0x14,0x23,0x48,0xaa,0x00, +0xde,0x54,0x00,0x08,0x21,0x48,0x00,0x00,0xff,0xff,0x43,0x25,0x42,0x18,0x03,0x00, +0x40,0x10,0x03,0x00,0x21,0x10,0x43,0x00,0x40,0x55,0x00,0x08,0x01,0x00,0x4a,0x24, +0x25,0xb0,0x02,0x3c,0x9c,0x0c,0x43,0x34,0x88,0x0c,0x42,0x34,0x00,0x00,0x44,0xac, +0x00,0x00,0x60,0xac,0x95,0x54,0x00,0x08,0x00,0x00,0x00,0x00,0x08,0x40,0x62,0x8c, +0x00,0x00,0x00,0x00,0x02,0x12,0x02,0x00,0x3f,0x00,0x42,0x30,0x23,0x18,0x4a,0x00, +0x2b,0x10,0x42,0x01,0x4e,0x55,0x00,0x08,0x0b,0x20,0x62,0x00,0xff,0xff,0x05,0x36, +0x60,0x00,0x06,0x24,0xba,0x44,0x00,0x0c,0x24,0x00,0x04,0x24,0x84,0x0a,0x00,0x0c, +0xe8,0x03,0x04,0x24,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x01,0x00,0x21,0x38, +0x00,0x60,0x81,0x40,0x24,0x00,0x04,0x24,0xdd,0x44,0x00,0x0c,0xff,0xff,0x05,0x36, +0x1f,0x00,0x52,0x30,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40, +0xb3,0x0a,0x00,0x0c,0x64,0x00,0x04,0x24,0xb4,0x54,0x00,0x08,0x68,0x15,0x90,0x26, +0x00,0xff,0x84,0x30,0x02,0x22,0x04,0x00,0x08,0x00,0x80,0x10,0x02,0x80,0x02,0x3c, +0xff,0x00,0x02,0x24,0x04,0x00,0x82,0x10,0xcc,0xff,0x03,0x24,0x02,0x80,0x02,0x3c, +0x08,0x00,0xe0,0x03,0x4e,0x58,0x43,0xa0,0x02,0x80,0x02,0x3c,0x08,0x00,0xe0,0x03, +0x4e,0x58,0x44,0xa0,0x02,0x24,0x04,0x00,0xff,0x00,0x84,0x30,0xc0,0x10,0x04,0x00, +0x21,0x10,0x44,0x00,0x80,0x10,0x02,0x00,0x21,0x10,0x44,0x00,0x02,0x80,0x03,0x3c, +0x80,0x10,0x02,0x00,0x68,0x15,0x63,0x24,0x20,0x00,0x84,0x2c,0x09,0x00,0x80,0x10, +0x21,0x10,0x43,0x00,0x68,0x51,0x43,0x8c,0x25,0xb0,0x02,0x3c,0xc4,0x02,0x42,0x34, +0x02,0x19,0x03,0x00,0x7f,0x00,0x63,0x30,0x00,0x00,0x43,0xac,0x08,0x00,0xe0,0x03, +0x00,0x00,0x00,0x00,0x02,0x80,0x02,0x3c,0x44,0x79,0x43,0x8c,0x25,0xb0,0x02,0x3c, +0xc4,0x02,0x42,0x34,0x02,0x19,0x03,0x00,0x7f,0x00,0x63,0x30,0x00,0x00,0x43,0xac, +0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0xff,0x00,0x85,0x30,0xd2,0xff,0xa3,0x24, +0xfe,0xff,0xa2,0x24,0xda,0xff,0xa4,0x24,0x04,0x00,0x63,0x2c,0x08,0x00,0x84,0x2c, +0x06,0x00,0x60,0x14,0xff,0x00,0x42,0x30,0xf0,0xff,0xa2,0x24,0xfc,0xff,0xa3,0x24, +0x16,0x00,0x46,0x2c,0x03,0x00,0x80,0x10,0xff,0x00,0x62,0x30,0x08,0x00,0xe0,0x03, +0x00,0x00,0x00,0x00,0xfa,0xff,0xa3,0x24,0xfc,0xff,0xc0,0x10,0x21,0x10,0xa0,0x00, +0x08,0x00,0xe0,0x03,0xff,0x00,0x62,0x30,0x25,0xb0,0x04,0x3c,0x03,0x0d,0x85,0x34, +0x00,0x00,0xa3,0x90,0x2d,0x0a,0x84,0x34,0xff,0x00,0x63,0x30,0x08,0x00,0x63,0x34, +0x00,0x00,0xa3,0xa0,0x00,0x00,0xa2,0x90,0x00,0x00,0x00,0x00,0xf7,0x00,0x42,0x30, +0x00,0x00,0xa2,0xa0,0x00,0x00,0x83,0x90,0x00,0x00,0x00,0x00,0x3f,0x00,0x63,0x30, +0x00,0x00,0x83,0xa0,0x00,0x00,0x82,0x90,0x80,0xff,0x03,0x24,0x25,0x10,0x43,0x00, +0x00,0x00,0x82,0xa0,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x25,0xb0,0x02,0x3c, +0xff,0x00,0x03,0x3c,0x82,0x01,0x49,0x34,0x81,0x01,0x48,0x34,0x24,0x10,0x83,0x00, +0x02,0x3c,0x02,0x00,0x00,0xff,0x63,0x34,0x02,0x80,0x02,0x3c,0x68,0x15,0x45,0x24, +0x02,0x32,0x04,0x00,0x01,0x00,0x02,0x24,0x24,0x20,0x83,0x00,0xc2,0x4c,0xa2,0xa0, +0xb0,0x4c,0xa0,0xac,0xb4,0x4c,0xa0,0xac,0xb8,0x4c,0xa0,0xac,0x06,0x00,0x80,0x14, +0xbc,0x4c,0xa0,0xac,0x00,0x00,0x02,0x91,0x00,0x00,0x23,0x91,0xc0,0x4c,0xa2,0xa0, +0x08,0x00,0xe0,0x03,0xc1,0x4c,0xa3,0xa0,0xc1,0x4c,0xa7,0xa0,0x08,0x00,0xe0,0x03, +0xc0,0x4c,0xa6,0xa0,0x02,0x80,0x03,0x3c,0x68,0x15,0x63,0x24,0xc1,0x4c,0x66,0x90, +0xc0,0x4c,0x65,0x90,0x25,0xb0,0x02,0x3c,0x82,0x01,0x44,0x34,0x81,0x01,0x42,0x34, +0x00,0x00,0x45,0xa0,0x00,0x00,0x86,0xa0,0x08,0x00,0xe0,0x03,0xc2,0x4c,0x60,0xa0, +0x02,0x80,0x08,0x3c,0x68,0x15,0x04,0x25,0xc2,0x4c,0x82,0x90,0x00,0x00,0x00,0x00, +0x15,0x00,0x40,0x10,0x21,0x18,0x00,0x00,0xb4,0x4c,0x82,0x8c,0xb0,0x4c,0x85,0x8c, +0x25,0xb0,0x03,0x3c,0x40,0x11,0x02,0x00,0x2b,0x10,0xa2,0x00,0x82,0x01,0x67,0x34, +0x0f,0x00,0x40,0x10,0x81,0x01,0x66,0x34,0xc1,0x4c,0x83,0x90,0xc0,0x4c,0x82,0x90, +0xf0,0x00,0x63,0x30,0x1f,0x00,0x42,0x30,0x00,0x00,0xc2,0xa0,0x00,0x00,0xe3,0xa0, +0x68,0x15,0x02,0x25,0x01,0x00,0x03,0x24,0xbc,0x4c,0x40,0xac,0xb0,0x4c,0x40,0xac, +0xb4,0x4c,0x40,0xac,0xb8,0x4c,0x40,0xac,0x08,0x00,0xe0,0x03,0x21,0x10,0x60,0x00, +0xb8,0x4c,0x82,0x8c,0x25,0xb0,0x03,0x3c,0x82,0x01,0x69,0x34,0x40,0x11,0x02,0x00, +0x2b,0x10,0xa2,0x00,0x0e,0x00,0x40,0x14,0x81,0x01,0x66,0x34,0xbc,0x4c,0x82,0x8c, +0x00,0x00,0x00,0x00,0x40,0x11,0x02,0x00,0x2b,0x10,0xa2,0x00,0x08,0x00,0x40,0x14, +0x00,0x00,0x00,0x00,0xc1,0x4c,0x83,0x90,0xc0,0x4c,0x82,0x90,0x00,0x00,0x00,0x00, +0x00,0x00,0xc2,0xa0,0x00,0x00,0x23,0xa1,0xf7,0x56,0x00,0x08,0x68,0x15,0x02,0x25, +0xc1,0x4c,0x83,0x90,0xc0,0x4c,0x82,0x90,0xf0,0x00,0x63,0x30,0x7f,0x00,0x42,0x30, +0x00,0x00,0xc2,0xa0,0x00,0x00,0x23,0xa1,0xf7,0x56,0x00,0x08,0x68,0x15,0x02,0x25, +0x02,0x00,0x03,0x24,0x02,0x80,0x02,0x3c,0x08,0x00,0xe0,0x03,0x3d,0x58,0x43,0xa0, +0xcc,0xff,0x03,0x24,0x02,0x80,0x02,0x3c,0x08,0x00,0xe0,0x03,0x3d,0x58,0x43,0xa0, +0x25,0xb0,0x03,0x3c,0x33,0x02,0x65,0x34,0x00,0x11,0x04,0x00,0x00,0x00,0xa2,0xa0, +0x30,0x02,0x63,0x34,0x00,0x00,0x65,0x8c,0x0f,0x00,0x02,0x3c,0xff,0xff,0x42,0x34, +0x24,0x28,0xa2,0x00,0x01,0x00,0x03,0x24,0x04,0x18,0x83,0x00,0x02,0x00,0xa0,0x10, +0x21,0x10,0x00,0x00,0xff,0xff,0x62,0x30,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00, +0xe0,0xff,0xbd,0x27,0x14,0x00,0xb1,0xaf,0x25,0xb0,0x11,0x3c,0x18,0x00,0xb2,0xaf, +0x4c,0x00,0x22,0x36,0x1c,0x00,0xbf,0xaf,0x10,0x00,0xb0,0xaf,0x00,0x00,0x44,0x90, +0x02,0x80,0x03,0x3c,0x02,0x00,0x02,0x24,0xff,0x00,0x84,0x30,0x07,0x00,0x82,0x10, +0x68,0x15,0x72,0x24,0x1c,0x00,0xbf,0x8f,0x18,0x00,0xb2,0x8f,0x14,0x00,0xb1,0x8f, +0x10,0x00,0xb0,0x8f,0x08,0x00,0xe0,0x03,0x20,0x00,0xbd,0x27,0xe6,0x63,0x43,0x96, +0x01,0x00,0x02,0x24,0xf7,0xff,0x62,0x14,0x21,0x20,0x00,0x00,0x22,0x57,0x00,0x0c, +0x00,0x00,0x00,0x00,0x04,0x00,0x04,0x24,0x22,0x57,0x00,0x0c,0x21,0x80,0x40,0x00, +0x25,0x80,0x02,0x02,0x33,0x02,0x23,0x36,0x08,0x00,0x02,0x24,0xff,0xff,0x10,0x32, +0x40,0x00,0x25,0x36,0x00,0x00,0x62,0xa0,0xea,0xff,0x00,0x16,0x00,0x00,0x00,0x00, +0x00,0x00,0xa2,0x94,0xe4,0x63,0x43,0x96,0xff,0xdf,0x42,0x30,0x00,0x20,0x44,0x34, +0x01,0x00,0x63,0x24,0xe4,0x63,0x43,0xa6,0x00,0x00,0xa2,0xa4,0x00,0x00,0xa4,0xa4, +0x3f,0x57,0x00,0x08,0x00,0x00,0x00,0x00,0x01,0x80,0x03,0x3c,0x25,0xb0,0x02,0x3c, +0x18,0x03,0x42,0x34,0x80,0x5d,0x63,0x24,0x00,0x00,0x43,0xac,0x63,0x00,0x02,0x24, +0xff,0xff,0x42,0x24,0xff,0xff,0x41,0x04,0xff,0xff,0x42,0x24,0x02,0x80,0x02,0x3c, +0x88,0x7d,0x45,0x94,0x02,0x80,0x03,0x3c,0x02,0x80,0x02,0x3c,0x8b,0x7d,0x66,0x90, +0x98,0x7d,0x47,0x90,0x02,0x80,0x03,0x3c,0x02,0x80,0x02,0x3c,0xa3,0x7d,0x69,0x90, +0xa5,0x7d,0x4a,0x90,0x02,0x80,0x03,0x3c,0x02,0x80,0x02,0x3c,0xa8,0x7d,0x6b,0x90, +0xaa,0x7d,0x4c,0x90,0x07,0x00,0x03,0x24,0x02,0x80,0x02,0x3c,0x25,0xb0,0x04,0x3c, +0x95,0x7d,0x43,0xa0,0xb0,0x03,0x84,0x34,0x02,0x80,0x02,0x3c,0x02,0x80,0x18,0x3c, +0x8a,0x7d,0x08,0x93,0x00,0x00,0x85,0xac,0x96,0x7d,0x40,0xa0,0x02,0x80,0x02,0x3c, +0x00,0x00,0x86,0xac,0x02,0x80,0x0f,0x3c,0x97,0x7d,0x40,0xa0,0x02,0x80,0x02,0x3c, +0x00,0x00,0x87,0xac,0x68,0x15,0xee,0x25,0xb8,0x7d,0x40,0xa0,0xfd,0xff,0x02,0x24, +0xd5,0x4a,0xc2,0xa1,0x01,0x00,0x03,0x24,0x00,0x78,0x02,0x24,0xd4,0x4a,0xc3,0xa1, +0xd8,0x4a,0xc2,0xa5,0xff,0x07,0x03,0x24,0x0f,0x00,0x0d,0x31,0x02,0x00,0x02,0x24, +0xda,0x4a,0xc3,0xa5,0x00,0x00,0x88,0xac,0x00,0x00,0x89,0xac,0x00,0x00,0x8a,0xac, +0x00,0x00,0x8b,0xac,0x00,0x00,0x8c,0xac,0x17,0x00,0xa2,0x11,0x02,0x80,0x02,0x3c, +0x8a,0x7d,0x02,0x93,0x01,0x00,0x03,0x24,0x0f,0x00,0x42,0x30,0x05,0x00,0x43,0x10, +0x00,0x00,0x00,0x00,0x02,0x80,0x02,0x3c,0xca,0x7d,0x40,0xa4,0x08,0x00,0xe0,0x03, +0x00,0x00,0x00,0x00,0x00,0x80,0x02,0x3c,0x68,0x15,0xe4,0x25,0x02,0xbc,0x42,0x34, +0x68,0x4b,0x82,0xac,0x15,0x15,0x03,0x3c,0x02,0x02,0x02,0x3c,0x07,0x07,0x63,0x34, +0x64,0x4b,0x82,0xac,0x02,0x80,0x02,0x3c,0x60,0x4b,0x83,0xac,0xca,0x7d,0x40,0xa4, +0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x8f,0x7d,0x44,0x90,0x06,0x00,0x03,0x24, +0x15,0x00,0x83,0x10,0x0b,0x00,0x02,0x24,0x0a,0x00,0x82,0x10,0x00,0xe0,0x02,0x3c, +0x68,0x15,0xe4,0x25,0x00,0xb2,0x42,0x34,0x00,0x1c,0x03,0x3c,0x68,0x4b,0x82,0xac, +0x00,0x1c,0x63,0x34,0x00,0x04,0x02,0x24,0x60,0x4b,0x83,0xac,0x9a,0x57,0x00,0x08, +0x64,0x4b,0x82,0xac,0x00,0x80,0x02,0x3c,0x00,0xbc,0x42,0x34,0x15,0x15,0x03,0x3c, +0x68,0x4b,0xc2,0xad,0x07,0x07,0x63,0x34,0x03,0x03,0x02,0x3c,0x60,0x4b,0xc3,0xad, +0x9a,0x57,0x00,0x08,0x64,0x4b,0xc2,0xad,0x00,0xc0,0x02,0x3c,0x00,0xb2,0x42,0x34, +0x1c,0x1c,0x03,0x3c,0x68,0x4b,0xc2,0xad,0x07,0x07,0x63,0x34,0x00,0x04,0x02,0x24, +0x60,0x4b,0xc3,0xad,0x9a,0x57,0x00,0x08,0x64,0x4b,0xc2,0xad,0x25,0xb0,0x02,0x3c, +0x4d,0x00,0x44,0x34,0xff,0x00,0x03,0x3c,0xec,0x02,0x42,0x34,0x00,0x00,0x43,0xac, +0x00,0x00,0x80,0xa0,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x01,0x80,0x03,0x3c, +0x25,0xb0,0x02,0x3c,0x64,0x5f,0x63,0x24,0x18,0x03,0x42,0x34,0x00,0x00,0x43,0xac, +0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x7f,0x00,0x02,0x3c,0xfd,0xbf,0x45,0x34, +0x80,0x04,0x03,0x3c,0x25,0x28,0xa3,0x00,0x00,0x08,0x04,0x3c,0x02,0x80,0x02,0x3c, +0x68,0x15,0x42,0x24,0x25,0x28,0xa4,0x00,0x41,0xb0,0x03,0x3c,0x00,0x00,0x65,0xac, +0x04,0x4b,0x45,0xac,0xfc,0x4a,0x45,0xac,0x08,0x00,0x63,0x34,0x86,0x00,0x05,0x24, +0x00,0x00,0x65,0xa4,0x08,0x4b,0x45,0xa4,0x00,0x4b,0x40,0xac,0x0a,0x4b,0x40,0xa4, +0x0c,0x4b,0x45,0xa4,0x00,0x60,0x01,0x40,0x01,0x00,0x21,0x34,0x00,0x60,0x81,0x40, +0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0xf8,0x57,0x00,0x08,0x00,0x00,0x00,0x00, +0x42,0xb0,0x02,0x3c,0xa0,0xff,0x03,0x24,0x01,0x00,0x42,0x34,0xe8,0xff,0xbd,0x27, +0x21,0x20,0x00,0x00,0x01,0x00,0x05,0x24,0x00,0x01,0x06,0x24,0x00,0x00,0x43,0xa0, +0x10,0x00,0xbf,0xaf,0xc4,0x0c,0x00,0x0c,0x00,0x00,0x00,0x00,0x10,0x00,0xbf,0x8f, +0x03,0x00,0x04,0x24,0x01,0x00,0x05,0x24,0x40,0x1f,0x06,0x24,0xc4,0x0c,0x00,0x08, +0x18,0x00,0xbd,0x27,0xe8,0xff,0xbd,0x27,0x10,0x00,0xb0,0xaf,0x14,0x00,0xbf,0xaf, +0x21,0x5b,0x00,0x0c,0x00,0x00,0x00,0x00,0x02,0x80,0x02,0x3c,0x68,0x15,0x42,0x24, +0x48,0x01,0x03,0x24,0xe0,0x63,0x43,0xac,0xdc,0x63,0x43,0xac,0x21,0x80,0x40,0x00, +0x1f,0x00,0x03,0x24,0xff,0xff,0x63,0x24,0xc4,0x4c,0x40,0xa4,0xc6,0x4c,0x40,0xa4, +0xc8,0x4c,0x40,0xa4,0xca,0x4c,0x40,0xa4,0xcc,0x4c,0x40,0xa4,0xce,0x4c,0x40,0xa4, +0xd0,0x4c,0x40,0xa4,0xd2,0x4c,0x40,0xa4,0xd4,0x4c,0x40,0xa4,0xf5,0xff,0x61,0x04, +0x24,0x00,0x42,0x24,0x25,0xb0,0x02,0x3c,0x10,0x00,0x03,0x24,0xb0,0x03,0x42,0x34, +0x02,0x80,0x04,0x3c,0x8c,0x58,0x84,0x24,0x00,0x00,0x43,0xac,0x21,0x28,0x00,0x00, +0x97,0x45,0x00,0x0c,0x04,0x00,0x06,0x24,0xef,0x5b,0x00,0x0c,0x00,0x00,0x00,0x00, +0x71,0x5c,0x00,0x0c,0x8c,0x65,0x00,0xae,0xa7,0x5d,0x00,0x0c,0x00,0x00,0x00,0x00, +0x4b,0x5e,0x00,0x0c,0x00,0x00,0x00,0x00,0x02,0x80,0x03,0x3c,0x8e,0x7d,0x64,0x90, +0x92,0x00,0x02,0x24,0x03,0x00,0x82,0x10,0x00,0x00,0x00,0x00,0xf7,0x5d,0x00,0x0c, +0x00,0x00,0x00,0x00,0xdd,0x5d,0x00,0x0c,0x00,0x00,0x00,0x00,0x8b,0x5c,0x00,0x0c, +0x00,0x00,0x00,0x00,0xe4,0x63,0x00,0xa6,0x67,0x5e,0x00,0x0c,0xe6,0x63,0x00,0xa6, +0x14,0x00,0xbf,0x8f,0x10,0x00,0xb0,0x8f,0x02,0x80,0x04,0x3c,0x02,0x80,0x05,0x3c, +0xf8,0x7a,0x82,0x24,0x00,0x7b,0xa3,0x24,0x18,0x00,0xbd,0x27,0x04,0x00,0x42,0xac, +0xf8,0x7a,0x82,0xac,0x00,0x7b,0xa3,0xac,0x08,0x00,0xe0,0x03,0x04,0x00,0x63,0xac, +0xe8,0xff,0xbd,0x27,0x10,0x00,0xb0,0xaf,0x01,0x80,0x02,0x3c,0x25,0xb0,0x10,0x3c, +0x18,0x03,0x03,0x36,0x38,0x61,0x42,0x24,0x00,0x00,0x62,0xac,0x14,0x00,0xbf,0xaf, +0x60,0x57,0x00,0x0c,0x00,0x00,0x00,0x00,0xd5,0x58,0x00,0x0c,0x00,0x00,0x00,0x00, +0x01,0x00,0x03,0x24,0x02,0x80,0x02,0x3c,0xfd,0x5a,0x00,0x0c,0xdb,0x60,0x43,0xa0, +0xd1,0x57,0x00,0x0c,0x00,0x00,0x00,0x00,0x32,0x41,0x00,0x0c,0x00,0x00,0x00,0x00, +0x0b,0x58,0x00,0x0c,0x00,0x00,0x00,0x00,0x44,0x00,0x03,0x36,0x00,0x00,0x62,0x94, +0x00,0x00,0x00,0x00,0x40,0x00,0x42,0x34,0x00,0x00,0x62,0xa4,0xd9,0x57,0x00,0x0c, +0x00,0x00,0x00,0x00,0xfa,0x57,0x00,0x0c,0x00,0x00,0x00,0x00,0xc9,0x5a,0x00,0x0c, +0x00,0x00,0x00,0x00,0x8e,0x5a,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x80,0x04,0x3c, +0xb4,0x24,0x84,0x24,0xe6,0x5a,0x00,0x0c,0x01,0x00,0x05,0x24,0x01,0x80,0x04,0x3c, +0x08,0x1e,0x84,0x24,0xe6,0x5a,0x00,0x0c,0x02,0x00,0x05,0x24,0x81,0x4e,0x00,0x0c, +0x00,0x00,0x00,0x00,0x00,0x80,0x04,0x3c,0x54,0x34,0x84,0x24,0xe6,0x5a,0x00,0x0c, +0x03,0x00,0x05,0x24,0x02,0x80,0x02,0x3c,0x98,0x7d,0x43,0x90,0x43,0x00,0x04,0x36, +0x29,0x00,0x60,0x10,0xd8,0x00,0x10,0x36,0x07,0x00,0x02,0x24,0x2b,0x00,0x62,0x10, +0x25,0xb0,0x04,0x3c,0x10,0x02,0x86,0x34,0x43,0x00,0x85,0x34,0x03,0x00,0x02,0x24, +0x10,0x00,0x03,0x24,0x00,0x00,0xa2,0xa0,0xd8,0x00,0x84,0x34,0x00,0x00,0xc3,0xa0, +0x00,0x00,0x82,0x90,0x80,0xff,0x03,0x24,0x42,0xb0,0x05,0x3c,0x25,0x10,0x43,0x00, +0x00,0x00,0x82,0xa0,0x25,0xb0,0x04,0x3c,0x44,0x00,0x84,0x34,0x00,0x00,0x82,0x94, +0x00,0x00,0x00,0x00,0xc0,0x00,0x42,0x34,0x00,0x00,0x82,0xa4,0x00,0x00,0xa3,0x90, +0x00,0x00,0x00,0x00,0x01,0x00,0x63,0x34,0x00,0x00,0xa3,0xa0,0xe0,0x57,0x00,0x0c, +0x00,0x00,0x00,0x00,0x02,0x80,0x04,0x3c,0x08,0x00,0x84,0x24,0x21,0x28,0x00,0x00, +0x21,0x30,0x00,0x00,0x31,0x1c,0x00,0x0c,0x21,0x38,0x00,0x00,0xf8,0x57,0x00,0x0c, +0x00,0x00,0x00,0x00,0x14,0x00,0xbf,0x8f,0x10,0x00,0xb0,0x8f,0x01,0x00,0x02,0x24, +0x08,0x00,0xe0,0x03,0x18,0x00,0xbd,0x27,0x00,0x00,0x80,0xa0,0x00,0x00,0x03,0x92, +0x80,0xff,0x02,0x24,0x25,0x18,0x62,0x00,0x00,0x00,0x03,0xa2,0x25,0xb0,0x04,0x3c, +0x44,0x00,0x84,0x34,0x00,0x00,0x82,0x94,0x42,0xb0,0x05,0x3c,0xc0,0x00,0x42,0x34, +0x00,0x00,0x82,0xa4,0x00,0x00,0xa3,0x90,0x00,0x00,0x00,0x00,0x01,0x00,0x63,0x34, +0x00,0x00,0xa3,0xa0,0xe0,0x57,0x00,0x0c,0x00,0x00,0x00,0x00,0x02,0x80,0x04,0x3c, +0x08,0x00,0x84,0x24,0x21,0x28,0x00,0x00,0x21,0x30,0x00,0x00,0x31,0x1c,0x00,0x0c, +0x21,0x38,0x00,0x00,0xf8,0x57,0x00,0x0c,0x00,0x00,0x00,0x00,0x14,0x00,0xbf,0x8f, +0x10,0x00,0xb0,0x8f,0x01,0x00,0x02,0x24,0x08,0x00,0xe0,0x03,0x18,0x00,0xbd,0x27, +0x21,0x20,0x00,0x00,0x20,0xb0,0x06,0x3c,0xff,0xff,0x05,0x34,0x21,0x18,0x86,0x00, +0x04,0x00,0x84,0x24,0x2a,0x10,0xa4,0x00,0x00,0x00,0x60,0xac,0xfb,0xff,0x40,0x10, +0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0xb8,0xff,0xbd,0x27, +0x25,0xb0,0x04,0x3c,0x44,0x00,0xbf,0xaf,0x40,0x00,0xbe,0xaf,0x3c,0x00,0xb7,0xaf, +0x38,0x00,0xb6,0xaf,0x34,0x00,0xb5,0xaf,0x30,0x00,0xb4,0xaf,0x2c,0x00,0xb3,0xaf, +0x28,0x00,0xb2,0xaf,0x24,0x00,0xb1,0xaf,0x20,0x00,0xb0,0xaf,0x0a,0x00,0x83,0x34, +0x00,0x00,0x62,0x90,0x00,0x00,0x00,0x00,0x20,0x00,0x42,0x30,0x0c,0x00,0x40,0x10, +0x4c,0x87,0x02,0x3c,0x00,0x00,0x62,0x90,0x00,0x00,0x00,0x00,0x10,0x00,0x42,0x30, +0x66,0x01,0x40,0x10,0x4c,0x87,0x02,0x3c,0x54,0x00,0x83,0x34,0x50,0x00,0x82,0x34, +0x00,0x00,0x45,0xac,0x00,0x00,0x65,0xa4,0xf9,0x58,0x00,0x08,0x02,0x80,0x03,0x3c, +0x54,0x00,0x85,0x34,0x00,0xe0,0x42,0x34,0x50,0x00,0x84,0x34,0x12,0x01,0x03,0x24, +0x00,0x00,0x82,0xac,0x00,0x00,0xa3,0xac,0x02,0x80,0x03,0x3c,0x68,0x15,0x62,0x24, +0xd5,0x4a,0x43,0x90,0xda,0x4a,0x45,0x94,0x25,0xb0,0x1e,0x3c,0x1c,0x00,0xa3,0xa3, +0x60,0x4b,0x43,0x8c,0x58,0x00,0xc6,0x37,0xff,0xff,0x04,0x24,0x10,0x00,0xa3,0xaf, +0x64,0x4b,0x43,0x8c,0x5c,0x00,0xc7,0x37,0x60,0x00,0xc8,0x37,0x14,0x00,0xa3,0xaf, +0x68,0x4b,0x42,0x8c,0x64,0x00,0xc9,0x37,0x8a,0x00,0xca,0x37,0x18,0x00,0xa2,0xaf, +0x24,0x10,0x02,0x3c,0x21,0x28,0xa2,0x00,0x4c,0x81,0x02,0x3c,0x00,0xe0,0x42,0x34, +0x00,0x00,0xc2,0xac,0x96,0x01,0x03,0x24,0x28,0x28,0x02,0x24,0x00,0x00,0xe3,0xac, +0x89,0x00,0xcb,0x37,0x00,0x00,0x04,0xad,0x8c,0x00,0xcc,0x37,0x00,0x00,0x24,0xad, +0x09,0x00,0x03,0x24,0x00,0x00,0x42,0xa5,0x10,0x10,0x02,0x24,0x00,0x00,0x63,0xa1, +0x8e,0x00,0xcd,0x37,0x00,0x00,0x82,0xa5,0x0a,0x0a,0x03,0x24,0x13,0x00,0x02,0x24, +0x90,0x00,0xce,0x37,0x00,0x00,0xa3,0xa5,0x00,0x00,0xc2,0xa1,0x25,0xb0,0x02,0x3c, +0x40,0x00,0x03,0x24,0x91,0x00,0x42,0x34,0x00,0x00,0x43,0xa0,0x25,0xb0,0x03,0x3c, +0x3a,0x01,0x02,0x24,0x92,0x00,0x63,0x34,0x00,0x00,0x62,0xa4,0xb5,0x00,0xd1,0x37, +0x21,0x00,0x03,0x24,0x00,0x00,0x23,0xa2,0x10,0x00,0xa2,0x8f,0xa0,0x00,0xd2,0x37, +0xa4,0x00,0xd3,0x37,0x00,0x00,0x42,0xae,0x14,0x00,0xa3,0x8f,0xa8,0x00,0xd4,0x37, +0xac,0x00,0xd5,0x37,0x00,0x00,0x63,0xae,0x18,0x00,0xa2,0x8f,0x25,0xb0,0x03,0x3c, +0xb0,0x00,0x63,0x34,0x00,0x00,0x82,0xae,0x21,0x10,0x02,0x3c,0xff,0x77,0x42,0x34, +0x00,0x00,0xa2,0xae,0x25,0xb0,0x02,0x3c,0xd8,0x00,0x42,0x34,0x00,0x00,0x65,0xac, +0x00,0x00,0x40,0xa0,0x1c,0x00,0xa2,0x93,0x25,0xb0,0x03,0x3c,0xb4,0x00,0x63,0x34, +0x00,0x00,0x62,0xa0,0x25,0xb0,0x03,0x3c,0x04,0x00,0x02,0x24,0xb6,0x00,0x63,0x34, +0x00,0x00,0x62,0xa0,0x25,0xb0,0x03,0x3c,0x0f,0x00,0x02,0x24,0xba,0x00,0x63,0x34, +0xb9,0x00,0xdf,0x37,0x00,0x00,0xe4,0xa3,0x00,0x00,0x62,0xa4,0x25,0xb0,0x02,0x3c, +0x1a,0x01,0x42,0x34,0x16,0x01,0xd0,0x37,0x18,0x01,0xcf,0x37,0x00,0x00,0x00,0xa6, +0x25,0xb0,0x03,0x3c,0x00,0x00,0xe0,0xa5,0x00,0x00,0x40,0xa4,0xff,0xff,0x02,0x3c, +0xff,0x0f,0x42,0x34,0xdc,0x00,0x63,0x34,0x00,0x00,0x62,0xac,0x2f,0x00,0x03,0x3c, +0x25,0xb0,0x02,0x3c,0x32,0x32,0x63,0x34,0xd0,0x01,0x42,0x34,0x00,0x00,0x43,0xac, +0x5e,0x00,0x02,0x3c,0x25,0xb0,0x03,0x3c,0x32,0x43,0x42,0x34,0xd4,0x01,0x63,0x34, +0x00,0x00,0x62,0xac,0x08,0x00,0x03,0x3c,0x25,0xb0,0x02,0x3c,0x30,0xa5,0x63,0x34, +0xd8,0x01,0x42,0x34,0x00,0x00,0x43,0xac,0xdc,0x01,0xc4,0x37,0x02,0x80,0x03,0x3c, +0x49,0xa5,0x02,0x34,0x8e,0x7d,0x6d,0x90,0x00,0x00,0x82,0xac,0xc2,0x00,0x02,0x3c, +0x1a,0x06,0x03,0x24,0x51,0x10,0x42,0x34,0xe0,0x01,0xc5,0x37,0xf4,0x01,0xc6,0x37, +0xf8,0x01,0xc7,0x37,0x07,0x07,0x04,0x24,0x00,0x00,0xa3,0xa4,0x00,0x02,0xc8,0x37, +0x00,0x00,0xc4,0xa4,0x26,0x00,0x03,0x24,0x00,0x00,0xe2,0xac,0x03,0x02,0xc9,0x37, +0x04,0x00,0x02,0x24,0x00,0x00,0x03,0xa5,0x36,0x02,0xca,0x37,0x00,0x00,0x22,0xa1, +0xc0,0x01,0x03,0x24,0x0c,0x00,0x02,0x24,0x34,0x02,0xcb,0x37,0x00,0x00,0x42,0xa1, +0x37,0x02,0xcc,0x37,0x00,0x00,0x63,0xa5,0x03,0x00,0x02,0x24,0x22,0x00,0x03,0x24, +0x00,0x00,0x82,0xa1,0xd6,0x00,0xa3,0x11,0x1b,0x1b,0x02,0x3c,0x13,0x13,0x02,0x3c, +0x13,0x13,0x42,0x34,0x60,0x01,0xc3,0x37,0x64,0x01,0xc4,0x37,0x68,0x01,0xc5,0x37, +0x7c,0x01,0xca,0x37,0x6c,0x01,0xc6,0x37,0x70,0x01,0xc7,0x37,0x74,0x01,0xc8,0x37, +0x78,0x01,0xc9,0x37,0x00,0x00,0x62,0xac,0x00,0x00,0x82,0xac,0x02,0x80,0x03,0x3c, +0x00,0x00,0xa2,0xac,0x00,0x00,0xc2,0xac,0x00,0x00,0xe2,0xac,0x00,0x00,0x02,0xad, +0x00,0x00,0x22,0xad,0x00,0x00,0x42,0xad,0x8e,0x7d,0x65,0x90,0x25,0xb0,0x0c,0x3c, +0x01,0x70,0x03,0x3c,0x80,0x01,0x82,0x35,0x08,0x5f,0x63,0x34,0x22,0x00,0x04,0x24, +0x00,0x00,0x43,0xac,0xb5,0x00,0xa4,0x10,0x0f,0x1f,0x02,0x3c,0x92,0x00,0x02,0x24, +0xb2,0x00,0xa2,0x10,0x0f,0x1f,0x02,0x3c,0x0f,0x10,0x02,0x3c,0x00,0xf0,0x51,0x34, +0xf7,0x01,0x92,0x35,0x15,0xf0,0x4d,0x34,0x77,0x00,0x0e,0x24,0x84,0x01,0x87,0x35, +0x88,0x01,0x88,0x35,0x10,0xf0,0x44,0x34,0x8c,0x01,0x85,0x35,0x05,0xf0,0x42,0x34, +0x00,0x00,0xed,0xac,0x90,0x01,0x83,0x35,0x00,0x00,0x04,0xad,0x94,0x01,0x86,0x35, +0x00,0x00,0xa2,0xac,0xf5,0x0f,0x02,0x24,0x00,0x00,0x71,0xac,0x25,0xb0,0x05,0x3c, +0x00,0x00,0xc2,0xac,0x98,0x01,0x89,0x35,0x9c,0x01,0x8a,0x35,0xf0,0x0f,0x03,0x24, +0x0d,0x00,0x02,0x24,0x00,0x00,0x23,0xad,0xa0,0x01,0x8b,0x35,0x00,0x00,0x42,0xad, +0xa7,0x01,0xb7,0x34,0xf6,0x01,0x8c,0x35,0xff,0xff,0x02,0x24,0x00,0x00,0x6d,0xad, +0x00,0x00,0x8e,0xa1,0x00,0x00,0x4e,0xa2,0x00,0x00,0xe2,0xa2,0x25,0xb0,0x02,0x3c, +0xa8,0x01,0xb6,0x34,0xff,0xff,0x09,0x24,0xac,0x01,0x42,0x34,0x00,0x00,0xc9,0xae, +0x03,0x04,0x04,0x3c,0x00,0x00,0x49,0xac,0x07,0x08,0x03,0x3c,0x25,0xb0,0x02,0x3c, +0x01,0x02,0x84,0x34,0x05,0x06,0x63,0x34,0xb4,0x01,0xb1,0x34,0xb8,0x01,0xb2,0x34, +0xbc,0x01,0xb3,0x34,0xb0,0x01,0x42,0x34,0x00,0x00,0x44,0xac,0x00,0x00,0x23,0xae, +0x25,0xb0,0x02,0x3c,0x00,0x00,0x44,0xae,0x00,0x00,0x63,0xae,0x25,0xb0,0x03,0x3c, +0x0c,0x00,0x06,0x24,0xc0,0x01,0xb4,0x34,0xc1,0x01,0xb5,0x34,0x0d,0x00,0x08,0x24, +0xc2,0x01,0x63,0x34,0xc3,0x01,0x42,0x34,0x00,0x00,0x86,0xa2,0xc4,0x01,0xab,0x34, +0x00,0x00,0xa6,0xa2,0xc5,0x01,0xac,0x34,0x00,0x00,0x66,0xa0,0x0e,0x00,0x07,0x24, +0x00,0x00,0x48,0xa0,0xc6,0x01,0xaa,0x34,0xc7,0x01,0xad,0x34,0x0f,0x00,0x02,0x24, +0x00,0x00,0x68,0xa1,0x00,0x00,0x87,0xa1,0x00,0x00,0x47,0xa1,0x00,0x00,0xa2,0xa1, +0x57,0x01,0x02,0x3c,0x48,0x00,0xbf,0x34,0x46,0x00,0xae,0x34,0x0e,0xe2,0x42,0x34, +0x00,0x00,0xc0,0xa5,0x4c,0x00,0xbe,0x34,0x00,0x00,0xe2,0xaf,0x4d,0x00,0xb9,0x34, +0x80,0xff,0x02,0x24,0x00,0x00,0xc0,0xa3,0x00,0x00,0x22,0xa3,0x25,0xb0,0x02,0x3c, +0xbc,0x00,0x03,0x24,0x40,0x00,0x42,0x34,0x00,0x00,0x43,0xa4,0x25,0xb0,0x03,0x3c, +0x64,0x03,0xb8,0x34,0xfc,0x37,0x02,0x24,0x40,0x00,0x63,0x34,0x00,0x00,0x00,0xa3, +0xd8,0x00,0xa7,0x34,0x00,0x00,0x62,0xa4,0x00,0x00,0xe3,0x90,0x2a,0xb0,0x04,0x3c, +0x80,0xff,0x02,0x24,0x26,0xb0,0x06,0x3c,0x25,0x18,0x62,0x00,0x30,0x00,0x89,0x34, +0x20,0x20,0x02,0x24,0x38,0x00,0x84,0x34,0x00,0x00,0xe3,0xa0,0x79,0x00,0xc8,0x34, +0x00,0x00,0x82,0xa4,0x40,0x00,0x03,0x24,0x16,0x00,0x02,0x24,0x00,0x00,0x23,0xa1, +0x94,0x00,0xaa,0x34,0x00,0x00,0x02,0xa1,0x98,0x00,0xab,0x34,0x64,0x00,0x03,0x24, +0x22,0x00,0x02,0x24,0x00,0x00,0x43,0xa5,0x7c,0x00,0xd1,0x34,0x00,0x00,0x62,0xa5, +0x04,0x00,0x12,0x24,0x9c,0x00,0xac,0x34,0x7a,0x00,0xc6,0x34,0x20,0x0c,0x02,0x24, +0x0a,0x00,0x03,0x24,0x00,0x00,0xd2,0xa0,0x9a,0x00,0xad,0x34,0x00,0x00,0x22,0xa6, +0x96,0x00,0xae,0x34,0x00,0x00,0x83,0xa1,0xff,0x03,0x02,0x24,0x02,0x00,0x03,0x24, +0x00,0x00,0xa2,0xa5,0x00,0x00,0xc3,0xa5,0x25,0xb0,0x03,0x3c,0x20,0x00,0x02,0x24, +0xb7,0x00,0x63,0x34,0x00,0x00,0x62,0xa0,0x25,0xb0,0x02,0x3c,0x09,0x00,0x03,0x24, +0x89,0x00,0x42,0x34,0x00,0x00,0x43,0xa0,0x44,0x00,0xa5,0x34,0x00,0x00,0xa2,0x94, +0x02,0x80,0x03,0x3c,0x68,0x15,0x66,0x24,0xff,0xfd,0x03,0x24,0x24,0x10,0x43,0x00, +0x00,0x00,0xa2,0xa4,0x00,0x00,0xa3,0x94,0xd5,0x4a,0xc4,0x90,0x29,0xb0,0x02,0x3c, +0x40,0x00,0x42,0x34,0x00,0x02,0x63,0x34,0x00,0x00,0xa3,0xa4,0x00,0x00,0x52,0xa0, +0xd3,0x0a,0x00,0x0c,0x00,0x00,0x00,0x00,0x44,0x00,0xbf,0x8f,0x40,0x00,0xbe,0x8f, +0x3c,0x00,0xb7,0x8f,0x38,0x00,0xb6,0x8f,0x34,0x00,0xb5,0x8f,0x30,0x00,0xb4,0x8f, +0x2c,0x00,0xb3,0x8f,0x28,0x00,0xb2,0x8f,0x24,0x00,0xb1,0x8f,0x20,0x00,0xb0,0x8f, +0x01,0x00,0x02,0x24,0x08,0x00,0xe0,0x03,0x48,0x00,0xbd,0x27,0x54,0x00,0x85,0x34, +0x00,0xe0,0x42,0x34,0x50,0x00,0x84,0x34,0x12,0x01,0x03,0x24,0x00,0x00,0x82,0xac, +0x00,0x00,0xa3,0xa4,0xf9,0x58,0x00,0x08,0x02,0x80,0x03,0x3c,0x00,0xf0,0x51,0x34, +0xf7,0x01,0x92,0x35,0x15,0xf0,0x4d,0x34,0xad,0x59,0x00,0x08,0xff,0xff,0x0e,0x24, +0x8b,0x59,0x00,0x08,0x1b,0x1b,0x42,0x34,0x25,0xb0,0x03,0x3c,0x25,0xb0,0x08,0x3c, +0xfc,0x37,0x02,0x24,0x40,0x00,0x63,0x34,0x02,0x80,0x04,0x3c,0x00,0x00,0x62,0xa4, +0x14,0x80,0x84,0x24,0xff,0x00,0x07,0x24,0xb0,0x03,0x06,0x35,0x00,0x00,0x83,0x94, +0x00,0x00,0x00,0x00,0xff,0x00,0x62,0x30,0x21,0x18,0x68,0x00,0x0a,0x00,0x47,0x10, +0xff,0x00,0x65,0x30,0x04,0x00,0x82,0x8c,0x00,0x00,0x00,0x00,0x00,0x00,0x62,0xac, +0x00,0x00,0xc3,0xac,0x04,0x00,0x82,0x8c,0x08,0x00,0x84,0x24,0x00,0x00,0xc2,0xac, +0xf2,0xff,0xa7,0x14,0x00,0x00,0x00,0x00,0x25,0xb0,0x08,0x3c,0x01,0x80,0x02,0x3c, +0x0c,0x7a,0x44,0x24,0xff,0x00,0x07,0x24,0xb0,0x03,0x06,0x35,0x00,0x00,0x83,0x94, +0x00,0x00,0x00,0x00,0xff,0x00,0x62,0x30,0x21,0x18,0x68,0x00,0x0a,0x00,0x47,0x10, +0xff,0x00,0x65,0x30,0x04,0x00,0x82,0x8c,0x00,0x00,0x00,0x00,0x00,0x00,0x62,0xac, +0x00,0x00,0xc3,0xac,0x04,0x00,0x82,0x8c,0x08,0x00,0x84,0x24,0x00,0x00,0xc2,0xac, +0xf2,0xff,0xa7,0x14,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00, +0x01,0x80,0x02,0x3c,0x02,0x80,0x05,0x3c,0x10,0x6b,0x42,0x24,0x02,0x80,0x03,0x3c, +0xcc,0x7d,0xa2,0xac,0x00,0x80,0x02,0x3c,0x6c,0x7e,0x60,0xac,0xcc,0x7d,0xa4,0x24, +0x02,0x80,0x03,0x3c,0xc8,0x06,0x42,0x24,0x70,0x7e,0x60,0xa4,0x08,0x00,0x82,0xac, +0x02,0x80,0x03,0x3c,0x00,0x80,0x02,0x3c,0x72,0x7e,0x60,0xa4,0x02,0x80,0x06,0x3c, +0x08,0x0a,0x42,0x24,0x00,0x80,0x03,0x3c,0x74,0x7e,0xc7,0x24,0x14,0x00,0x82,0xac, +0x38,0x08,0x63,0x24,0x02,0x80,0x02,0x3c,0x74,0x7e,0xc0,0xac,0x10,0x00,0x83,0xac, +0x04,0x00,0xe0,0xac,0x7c,0x7e,0x40,0xa0,0x00,0x80,0x02,0x3c,0x88,0x19,0x42,0x24, +0x3c,0x00,0x82,0xac,0x00,0x80,0x03,0x3c,0x00,0x80,0x02,0x3c,0x24,0x0c,0x63,0x24, +0x78,0x0f,0x42,0x24,0x1c,0x00,0x83,0xac,0x20,0x00,0x82,0xac,0x00,0x80,0x03,0x3c, +0x00,0x80,0x02,0x3c,0xc8,0x12,0x63,0x24,0x28,0x16,0x42,0x24,0x24,0x00,0x83,0xac, +0x28,0x00,0x82,0xac,0x00,0x80,0x03,0x3c,0x01,0x80,0x02,0x3c,0x4c,0x1f,0x63,0x24, +0xd0,0x04,0x42,0x24,0x2c,0x00,0x83,0xac,0x30,0x00,0x82,0xac,0x00,0x80,0x03,0x3c, +0x00,0x80,0x02,0x3c,0xe4,0x19,0x63,0x24,0x00,0x03,0x42,0x24,0x38,0x00,0x83,0xac, +0x08,0x00,0xe0,0x03,0x4c,0x00,0x82,0xac,0x25,0xb0,0x02,0x3c,0x08,0x00,0x42,0x34, +0x00,0x00,0x43,0x8c,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x02,0x80,0x0e,0x3c, +0x02,0x80,0x08,0x3c,0x02,0x80,0x02,0x3c,0x02,0x80,0x03,0x3c,0xf8,0x03,0x4d,0x24, +0x00,0x14,0x6c,0x24,0x01,0x00,0x07,0x24,0x00,0x00,0xcb,0x25,0xff,0xff,0x0a,0x24, +0x00,0x04,0x09,0x25,0x80,0x1a,0x07,0x00,0x21,0x10,0x6b,0x00,0x00,0x00,0x42,0xac, +0x90,0x00,0x4a,0xac,0x00,0x04,0x04,0x8d,0x01,0x00,0xe7,0x24,0x08,0x00,0x45,0x24, +0x21,0x18,0x6d,0x00,0x05,0x00,0xe6,0x28,0x04,0x00,0x82,0xac,0x00,0x00,0x44,0xac, +0x04,0x00,0x49,0xac,0x00,0x04,0x02,0xad,0x8c,0x00,0x40,0xac,0x6c,0x00,0xa3,0xac, +0xf0,0xff,0xc0,0x14,0x68,0x00,0xac,0xac,0x08,0x00,0xe0,0x03,0x00,0x00,0xc9,0xad, +0x05,0x00,0xa2,0x2c,0x13,0x00,0x40,0x10,0xff,0xff,0x07,0x24,0x02,0x80,0x02,0x3c, +0x80,0x1a,0x05,0x00,0x00,0x00,0x42,0x24,0x0e,0x00,0xa0,0x10,0x21,0x30,0x62,0x00, +0x90,0x00,0xc3,0x8c,0xff,0xff,0x02,0x24,0x0a,0x00,0x62,0x14,0x00,0x00,0x00,0x00, +0x8c,0x00,0xc2,0x8c,0x00,0x00,0x00,0x00,0x06,0x00,0x40,0x14,0x00,0x00,0x00,0x00, +0x01,0x00,0x02,0x24,0x88,0x00,0xc4,0xac,0x8c,0x00,0xc2,0xac,0x90,0x00,0xc5,0xac, +0x21,0x38,0xa0,0x00,0x08,0x00,0xe0,0x03,0x21,0x10,0xe0,0x00,0x25,0xb0,0x04,0x3c, +0x01,0x80,0x02,0x3c,0x18,0x03,0x85,0x34,0xf4,0x6b,0x42,0x24,0xe0,0xff,0xbd,0x27, +0x00,0x00,0xa2,0xac,0x1b,0x00,0x86,0x34,0xdb,0xff,0x03,0x24,0x27,0x00,0x84,0x34, +0x07,0x00,0x02,0x24,0x14,0x00,0xb1,0xaf,0x10,0x00,0xb0,0xaf,0x00,0x00,0x83,0xa0, +0x18,0x00,0xbf,0xaf,0x00,0x00,0xc2,0xa0,0x01,0x00,0x11,0x24,0x21,0x80,0x00,0x00, +0x7a,0x42,0x00,0x0c,0x21,0x20,0x00,0x02,0x01,0x00,0x02,0x26,0xff,0x00,0x50,0x30, +0x2b,0x18,0x30,0x02,0xfa,0xff,0x60,0x10,0x00,0x00,0x00,0x00,0x7a,0x42,0x00,0x0c, +0x21,0x20,0x00,0x00,0x18,0x00,0xbf,0x8f,0x14,0x00,0xb1,0x8f,0x10,0x00,0xb0,0x8f, +0x01,0x00,0x02,0x24,0x08,0x00,0xe0,0x03,0x20,0x00,0xbd,0x27,0x08,0x00,0xe0,0x03, +0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x02,0x80,0x02,0x3c, +0x68,0x15,0x42,0x24,0x40,0x10,0x03,0x3c,0xff,0xff,0x44,0x30,0x25,0xc0,0x83,0x00, +0x94,0x64,0x58,0xac,0x40,0x00,0x18,0x27,0xa0,0x64,0x58,0xac,0x40,0x00,0x18,0x27, +0xac,0x64,0x58,0xac,0x40,0x00,0x18,0x27,0xb8,0x64,0x58,0xac,0x40,0x00,0x18,0x27, +0xe0,0xff,0xbd,0x27,0xc4,0x64,0x58,0xac,0x40,0x00,0x18,0x27,0x1c,0x00,0xb7,0xaf, +0x18,0x00,0xb6,0xaf,0x14,0x00,0xb5,0xaf,0x10,0x00,0xb4,0xaf,0x0c,0x00,0xb3,0xaf, +0x08,0x00,0xb2,0xaf,0x04,0x00,0xb1,0xaf,0x00,0x00,0xb0,0xaf,0xd0,0x64,0x58,0xac, +0xa0,0x64,0x45,0x8c,0xac,0x64,0x46,0x8c,0xb8,0x64,0x47,0x8c,0xc4,0x64,0x48,0x8c, +0xd0,0x64,0x49,0x8c,0x40,0x00,0x18,0x27,0xdc,0x64,0x58,0xac,0x21,0x50,0x00,0x03, +0x25,0x20,0x83,0x00,0x40,0x00,0x18,0x27,0x20,0x10,0x03,0x3c,0x90,0x64,0x44,0xac, +0x9c,0x64,0x45,0xac,0xa8,0x64,0x46,0xac,0xb4,0x64,0x47,0xac,0xc0,0x64,0x48,0xac, +0xcc,0x64,0x49,0xac,0x25,0xb0,0x06,0x3c,0x28,0x64,0x43,0xac,0x24,0x64,0x43,0xac, +0x34,0x64,0x43,0xac,0x30,0x64,0x43,0xac,0x40,0x64,0x43,0xac,0x3c,0x64,0x43,0xac, +0x4c,0x64,0x43,0xac,0x48,0x64,0x43,0xac,0xe8,0x64,0x58,0xac,0x00,0x02,0x18,0x27, +0xd8,0x64,0x4a,0xac,0x00,0x65,0x58,0xac,0x58,0x64,0x43,0xac,0x54,0x64,0x43,0xac, +0x64,0x64,0x43,0xac,0x60,0x64,0x43,0xac,0x70,0x64,0x43,0xac,0x6c,0x64,0x43,0xac, +0xac,0x00,0xc4,0x34,0xb0,0x00,0xc5,0x34,0x00,0x00,0x92,0x8c,0xe8,0x64,0x50,0x8c, +0x00,0x00,0xb3,0x8c,0x21,0x10,0x04,0x3c,0x23,0x10,0x09,0x3c,0x22,0x10,0x0c,0x3c, +0x02,0x80,0x14,0x3c,0x02,0x80,0x15,0x3c,0x02,0x80,0x16,0x3c,0x02,0x80,0x17,0x3c, +0x24,0x10,0x05,0x3c,0x21,0x88,0x00,0x03,0x08,0x7b,0x87,0x26,0x00,0x04,0x18,0x27, +0x10,0x7b,0xa8,0x26,0x18,0x7b,0xca,0x26,0x20,0x7b,0xeb,0x26,0x00,0x04,0x2d,0x35, +0x00,0x40,0x8e,0x34,0x00,0x80,0x8f,0x35,0x00,0x01,0xc6,0x34,0xe4,0x64,0x50,0xac, +0xfc,0x64,0x51,0xac,0x64,0x65,0x4d,0xac,0x28,0x65,0x52,0xac,0x34,0x65,0x4e,0xac, +0x58,0x65,0x4f,0xac,0x4c,0x65,0x53,0xac,0x00,0x00,0xc5,0xac,0x48,0x65,0x45,0xac, +0x68,0x65,0x43,0xac,0x74,0x65,0x58,0xac,0x7c,0x64,0x43,0xac,0x78,0x64,0x43,0xac, +0x06,0x65,0x40,0xa4,0x05,0x65,0x40,0xa0,0x04,0x65,0x40,0xa0,0x5c,0x65,0x49,0xac, +0x60,0x65,0x49,0xac,0x20,0x65,0x44,0xac,0x24,0x65,0x44,0xac,0x2c,0x65,0x44,0xac, +0x30,0x65,0x44,0xac,0x50,0x65,0x4c,0xac,0x54,0x65,0x4c,0xac,0x44,0x65,0x45,0xac, +0x6c,0x65,0x43,0xac,0x78,0x65,0x58,0xac,0x04,0x00,0x08,0xad,0x08,0x7b,0x87,0xae, +0x04,0x00,0x4a,0xad,0x10,0x7b,0xa8,0xae,0x04,0x00,0x6b,0xad,0x18,0x7b,0xca,0xae, +0x20,0x7b,0xeb,0xae,0x04,0x00,0xe7,0xac,0x02,0x80,0x02,0x3c,0x00,0x14,0x43,0x24, +0x21,0x20,0xe0,0x00,0x03,0x00,0x06,0x24,0x21,0x10,0x80,0x00,0xff,0xff,0xc6,0x24, +0x08,0x00,0x78,0xac,0x00,0x00,0x63,0xac,0x10,0x00,0x60,0xac,0x00,0x00,0x67,0xac, +0x21,0x20,0x60,0x00,0x04,0x00,0x62,0xac,0x00,0x00,0x43,0xac,0x00,0x01,0x18,0x27, +0xf5,0xff,0xc1,0x04,0x18,0x00,0x63,0x24,0x02,0x80,0x02,0x3c,0x10,0x7b,0x49,0x24, +0x02,0x80,0x03,0x3c,0x02,0x80,0x02,0x3c,0x04,0x00,0x28,0x8d,0x60,0x14,0x4b,0x24, +0x04,0x00,0xe4,0xac,0x00,0x14,0x6a,0x24,0x01,0x00,0x07,0x24,0x21,0x28,0x00,0x00, +0x07,0x00,0x06,0x24,0x21,0x20,0xab,0x00,0x21,0x10,0xaa,0x00,0xff,0xff,0xc6,0x24, +0x68,0x00,0x58,0xac,0x70,0x00,0x47,0xac,0x18,0x00,0xa5,0x24,0x00,0x00,0x89,0xac, +0x04,0x00,0x88,0xac,0x00,0x00,0x04,0xad,0x00,0x01,0x18,0x27,0xf5,0xff,0xc1,0x04, +0x21,0x40,0x80,0x00,0x02,0x80,0x02,0x3c,0x18,0x7b,0x4a,0x24,0x02,0x80,0x03,0x3c, +0x02,0x80,0x02,0x3c,0x04,0x00,0x45,0x8d,0x20,0x15,0x4b,0x24,0x04,0x00,0x24,0xad, +0x02,0x00,0x07,0x24,0x00,0x14,0x69,0x24,0x21,0x20,0x00,0x00,0x01,0x00,0x06,0x24, +0x21,0x40,0x8b,0x00,0x21,0x10,0x89,0x00,0xff,0xff,0xc6,0x24,0x28,0x01,0x58,0xac, +0x30,0x01,0x47,0xac,0x18,0x00,0x84,0x24,0x00,0x00,0x0a,0xad,0x04,0x00,0x05,0xad, +0x00,0x00,0xa8,0xac,0x00,0x02,0x18,0x27,0xf5,0xff,0xc1,0x04,0x21,0x28,0x00,0x01, +0x02,0x80,0x05,0x3c,0x20,0x7b,0xa5,0x24,0x04,0x00,0xa6,0x8c,0x1c,0x00,0xb7,0x8f, +0x18,0x00,0xb6,0x8f,0x14,0x00,0xb5,0x8f,0x10,0x00,0xb4,0x8f,0x0c,0x00,0xb3,0x8f, +0x08,0x00,0xb2,0x8f,0x04,0x00,0xb1,0x8f,0x00,0x00,0xb0,0x8f,0x02,0x80,0x07,0x3c, +0x02,0x80,0x03,0x3c,0x50,0x15,0xe4,0x24,0x00,0x14,0x63,0x24,0x03,0x00,0x02,0x24, +0x20,0x00,0xbd,0x27,0x58,0x01,0x78,0xac,0x04,0x00,0x48,0xad,0x04,0x00,0xa4,0xac, +0x60,0x01,0x62,0xac,0x50,0x15,0xe5,0xac,0x04,0x00,0x86,0xac,0x08,0x00,0xe0,0x03, +0x00,0x00,0xc4,0xac,0xd0,0xff,0xbd,0x27,0x02,0x80,0x02,0x3c,0x20,0x00,0xb2,0xaf, +0x02,0x80,0x03,0x3c,0x4c,0x91,0x52,0x24,0x02,0x80,0x02,0x3c,0x28,0x00,0xb4,0xaf, +0x24,0x00,0xb3,0xaf,0x1c,0x00,0xb1,0xaf,0x18,0x00,0xb0,0xaf,0x2c,0x00,0xbf,0xaf, +0xd8,0x90,0x73,0x24,0x68,0x15,0x50,0x24,0x21,0x88,0x00,0x00,0x02,0x80,0x14,0x3c, +0xee,0x4e,0x00,0x0c,0x21,0x20,0x20,0x02,0x78,0x51,0x05,0x8e,0x6c,0x00,0x66,0x8e, +0xb8,0x90,0x82,0x26,0x6c,0x00,0x43,0x8e,0x1b,0x00,0x44,0x90,0xff,0xf1,0x02,0x24, +0x21,0x18,0x66,0x00,0x24,0x28,0xa2,0x00,0x00,0x21,0x04,0x00,0x42,0x18,0x03,0x00, +0x00,0x02,0xa5,0x34,0x44,0x51,0x03,0xae,0x68,0x51,0x04,0xae,0x78,0x51,0x05,0xae, +0x6c,0x51,0x04,0xae,0x21,0x30,0x00,0x00,0x21,0x10,0x06,0x02,0x01,0x00,0xc6,0x24, +0x1d,0x00,0xc3,0x28,0x99,0x51,0x40,0xa0,0x7c,0x51,0x40,0xa0,0xfa,0xff,0x60,0x14, +0xb6,0x51,0x40,0xa0,0x01,0x00,0x31,0x26,0x20,0x00,0x22,0x2a,0xd4,0x51,0x00,0xae, +0xe3,0xff,0x40,0x14,0x94,0x00,0x10,0x26,0x02,0x80,0x02,0x3c,0x02,0x80,0x03,0x3c, +0x68,0x15,0x4b,0x24,0x02,0x80,0x02,0x3c,0x4c,0x91,0x6f,0x24,0xd8,0x90,0x4d,0x24, +0x02,0x80,0x03,0x3c,0x02,0x80,0x02,0x3c,0xb8,0x90,0x6e,0x24,0x98,0x90,0x4c,0x24, +0x21,0x88,0x00,0x00,0x80,0x18,0x11,0x00,0x21,0x20,0x6d,0x00,0x21,0x10,0x6f,0x00, +0x21,0x28,0x2e,0x02,0x21,0x30,0x2c,0x02,0x00,0x00,0x88,0x8c,0x00,0x00,0xa9,0x90, +0x00,0x00,0xc7,0x90,0x00,0x00,0x4a,0x8c,0x21,0x10,0x2b,0x02,0x01,0x00,0x31,0x26, +0x21,0x18,0x6b,0x00,0x1d,0x00,0x24,0x2a,0xec,0x44,0x68,0xac,0xca,0x44,0x47,0xa0, +0x60,0x45,0x6a,0xac,0xef,0xff,0x80,0x14,0x90,0x44,0x49,0xa0,0x02,0x80,0x02,0x3c, +0x68,0x15,0x4a,0x24,0x02,0x80,0x03,0x3c,0x02,0x80,0x02,0x3c,0x74,0x8f,0x6b,0x24, +0x14,0x8e,0x4c,0x24,0x21,0x88,0x00,0x00,0x21,0x48,0x00,0x00,0x21,0x30,0x00,0x00, +0x21,0x40,0x2a,0x01,0x21,0x38,0x2b,0x01,0x21,0x10,0xe6,0x00,0x91,0x00,0x44,0x90, +0x00,0x00,0x45,0x90,0x21,0x18,0x06,0x01,0x01,0x00,0xc6,0x24,0x05,0x00,0xc2,0x28, +0xc5,0x43,0x64,0xa0,0xf8,0xff,0x40,0x14,0x34,0x43,0x65,0xa0,0x21,0x10,0x2c,0x02, +0x1d,0x00,0x44,0x90,0x00,0x00,0x45,0x90,0x21,0x18,0x2a,0x02,0x01,0x00,0x31,0x26, +0x1d,0x00,0x22,0x2a,0x73,0x44,0x64,0xa0,0x56,0x44,0x65,0xa0,0xeb,0xff,0x40,0x14, +0x05,0x00,0x29,0x25,0x52,0x00,0x02,0x24,0x10,0x00,0xa2,0xa3,0x41,0x00,0x03,0x24, +0x4d,0x00,0x02,0x24,0x02,0x80,0x07,0x3c,0x1c,0x97,0xe7,0x24,0x11,0x00,0xa3,0xa3, +0x12,0x00,0xa2,0xa3,0xe8,0x03,0x03,0x24,0x01,0x00,0x02,0x24,0x00,0x80,0x06,0x3c, +0x10,0x00,0xa5,0x27,0x21,0x20,0xe0,0x00,0xf0,0x37,0xc6,0x24,0x0c,0x00,0xe3,0xac, +0x14,0x00,0xe2,0xa0,0xfb,0x0c,0x00,0x0c,0x13,0x00,0xa0,0xa3,0x2c,0x00,0xbf,0x8f, +0x28,0x00,0xb4,0x8f,0x24,0x00,0xb3,0x8f,0x20,0x00,0xb2,0x8f,0x1c,0x00,0xb1,0x8f, +0x18,0x00,0xb0,0x8f,0x08,0x00,0xe0,0x03,0x30,0x00,0xbd,0x27,0xe0,0xff,0xbd,0x27, +0x02,0x80,0x02,0x3c,0x42,0x00,0x03,0x24,0x10,0x00,0xa3,0xa3,0x55,0x60,0x40,0xa0, +0x4e,0x00,0x03,0x24,0x43,0x00,0x02,0x24,0x02,0x80,0x07,0x3c,0x54,0x97,0xe7,0x24, +0x11,0x00,0xa2,0xa3,0x12,0x00,0xa3,0xa3,0xd0,0x07,0x02,0x24,0x01,0x00,0x03,0x24, +0x00,0x80,0x06,0x3c,0x10,0x00,0xa5,0x27,0x21,0x20,0xe0,0x00,0xdc,0x44,0xc6,0x24, +0x0c,0x00,0xe2,0xac,0x14,0x00,0xe3,0xa0,0x18,0x00,0xbf,0xaf,0xfb,0x0c,0x00,0x0c, +0x13,0x00,0xa0,0xa3,0x18,0x00,0xbf,0x8f,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03, +0x20,0x00,0xbd,0x27,0x48,0xfd,0xbd,0x27,0xb4,0x02,0xb3,0xaf,0x02,0x80,0x02,0x3c, +0x02,0x80,0x13,0x3c,0x24,0x92,0x46,0x24,0x68,0x15,0x63,0x26,0xb0,0x02,0xb2,0xaf, +0xac,0x02,0xb1,0xaf,0xa8,0x02,0xb0,0xaf,0x03,0x40,0x60,0xa0,0x21,0x38,0xa0,0x03, +0x90,0x00,0xc8,0x24,0x00,0x00,0xc2,0x8c,0x04,0x00,0xc3,0x8c,0x08,0x00,0xc4,0x8c, +0x0c,0x00,0xc5,0x8c,0x10,0x00,0xc6,0x24,0x00,0x00,0xe2,0xac,0x04,0x00,0xe3,0xac, +0x08,0x00,0xe4,0xac,0x0c,0x00,0xe5,0xac,0xf6,0xff,0xc8,0x14,0x10,0x00,0xe7,0x24, +0x00,0x00,0xc3,0x8c,0x02,0x80,0x02,0x3c,0xb8,0x92,0x58,0x24,0x00,0x00,0xe3,0xac, +0x98,0x00,0xb9,0x27,0x00,0x01,0x12,0x27,0x01,0x00,0x02,0x93,0x05,0x00,0x03,0x93, +0x09,0x00,0x04,0x93,0x0d,0x00,0x05,0x93,0x00,0x00,0x11,0x93,0x02,0x00,0x0d,0x93, +0x04,0x00,0x10,0x93,0x06,0x00,0x0c,0x93,0x08,0x00,0x0f,0x93,0x0a,0x00,0x07,0x93, +0x0c,0x00,0x0e,0x93,0x0e,0x00,0x06,0x93,0x03,0x00,0x08,0x93,0x07,0x00,0x09,0x93, +0x0b,0x00,0x0a,0x93,0x0f,0x00,0x0b,0x93,0x00,0x12,0x02,0x00,0x00,0x1a,0x03,0x00, +0x00,0x22,0x04,0x00,0x00,0x2a,0x05,0x00,0x25,0x10,0x51,0x00,0x25,0x18,0x70,0x00, +0x25,0x20,0x8f,0x00,0x25,0x28,0xae,0x00,0x00,0x6c,0x0d,0x00,0x00,0x64,0x0c,0x00, +0x00,0x3c,0x07,0x00,0x00,0x34,0x06,0x00,0x25,0x68,0xa2,0x01,0x25,0x60,0x83,0x01, +0x25,0x38,0xe4,0x00,0x25,0x30,0xc5,0x00,0x00,0x46,0x08,0x00,0x00,0x4e,0x09,0x00, +0x00,0x56,0x0a,0x00,0x00,0x5e,0x0b,0x00,0x25,0x40,0x0d,0x01,0x25,0x48,0x2c,0x01, +0x25,0x50,0x47,0x01,0x25,0x58,0x66,0x01,0x10,0x00,0x18,0x27,0x00,0x00,0x28,0xaf, +0x04,0x00,0x29,0xaf,0x08,0x00,0x2a,0xaf,0x0c,0x00,0x2b,0xaf,0xd2,0xff,0x12,0x17, +0x10,0x00,0x39,0x27,0x01,0x00,0x02,0x93,0x05,0x00,0x03,0x93,0x00,0x00,0x09,0x93, +0x02,0x00,0x04,0x93,0x04,0x00,0x08,0x93,0x06,0x00,0x05,0x93,0x07,0x00,0x06,0x93, +0x03,0x00,0x07,0x93,0x00,0x12,0x02,0x00,0x00,0x1a,0x03,0x00,0x25,0x10,0x49,0x00, +0x25,0x18,0x68,0x00,0x00,0x24,0x04,0x00,0x00,0x2c,0x05,0x00,0x25,0x20,0x82,0x00, +0x25,0x28,0xa3,0x00,0x00,0x3e,0x07,0x00,0x00,0x36,0x06,0x00,0x02,0x80,0x02,0x3c, +0x25,0x38,0xe4,0x00,0x25,0x30,0xc5,0x00,0xc0,0x93,0x58,0x24,0x04,0x00,0x26,0xaf, +0x00,0x00,0x27,0xaf,0x00,0x01,0x12,0x27,0xa0,0x01,0xb9,0x27,0x01,0x00,0x02,0x93, +0x05,0x00,0x03,0x93,0x09,0x00,0x04,0x93,0x0d,0x00,0x05,0x93,0x00,0x00,0x11,0x93, +0x02,0x00,0x0d,0x93,0x04,0x00,0x10,0x93,0x06,0x00,0x0c,0x93,0x08,0x00,0x0f,0x93, +0x0a,0x00,0x07,0x93,0x0c,0x00,0x0e,0x93,0x0e,0x00,0x06,0x93,0x03,0x00,0x08,0x93, +0x07,0x00,0x09,0x93,0x0b,0x00,0x0a,0x93,0x0f,0x00,0x0b,0x93,0x00,0x12,0x02,0x00, +0x00,0x1a,0x03,0x00,0x00,0x22,0x04,0x00,0x00,0x2a,0x05,0x00,0x25,0x10,0x51,0x00, +0x25,0x18,0x70,0x00,0x25,0x20,0x8f,0x00,0x25,0x28,0xae,0x00,0x00,0x6c,0x0d,0x00, +0x00,0x64,0x0c,0x00,0x00,0x3c,0x07,0x00,0x00,0x34,0x06,0x00,0x25,0x68,0xa2,0x01, +0x25,0x60,0x83,0x01,0x25,0x38,0xe4,0x00,0x25,0x30,0xc5,0x00,0x00,0x46,0x08,0x00, +0x00,0x4e,0x09,0x00,0x00,0x56,0x0a,0x00,0x00,0x5e,0x0b,0x00,0x25,0x40,0x0d,0x01, +0x25,0x48,0x2c,0x01,0x25,0x50,0x47,0x01,0x25,0x58,0x66,0x01,0x10,0x00,0x18,0x27, +0x00,0x00,0x28,0xaf,0x04,0x00,0x29,0xaf,0x08,0x00,0x2a,0xaf,0x0c,0x00,0x2b,0xaf, +0xd2,0xff,0x12,0x17,0x10,0x00,0x39,0x27,0x01,0x00,0x02,0x93,0x05,0x00,0x03,0x93, +0x00,0x00,0x09,0x93,0x02,0x00,0x04,0x93,0x04,0x00,0x08,0x93,0x06,0x00,0x05,0x93, +0x07,0x00,0x06,0x93,0x03,0x00,0x07,0x93,0x00,0x12,0x02,0x00,0x00,0x1a,0x03,0x00, +0x25,0x10,0x49,0x00,0x25,0x18,0x68,0x00,0x00,0x24,0x04,0x00,0x00,0x2c,0x05,0x00, +0x25,0x20,0x82,0x00,0x25,0x28,0xa3,0x00,0x00,0x3e,0x07,0x00,0x00,0x36,0x06,0x00, +0x25,0x30,0xc5,0x00,0x25,0x38,0xe4,0x00,0x02,0x80,0x02,0x3c,0x04,0x00,0x26,0xaf, +0x00,0x00,0x27,0xaf,0x68,0x15,0x46,0x24,0x21,0x50,0x00,0x00,0x80,0x20,0x0a,0x00, +0x21,0x10,0x9d,0x00,0x00,0x00,0x45,0x8c,0x01,0x00,0x43,0x25,0xff,0x00,0x6a,0x30, +0x21,0x20,0x86,0x00,0x25,0x00,0x42,0x2d,0xf8,0xff,0x40,0x14,0x18,0x40,0x85,0xac, +0x02,0x80,0x02,0x3c,0x68,0x15,0x4b,0x24,0x21,0x50,0x00,0x00,0xc0,0x10,0x0a,0x00, +0x21,0x48,0x5d,0x00,0x21,0x38,0x00,0x00,0x21,0x40,0x4b,0x00,0x21,0x10,0x27,0x01, +0xa0,0x01,0x46,0x90,0x98,0x00,0x45,0x90,0x01,0x00,0xe4,0x24,0x21,0x18,0x07,0x01, +0xff,0x00,0x87,0x30,0x08,0x00,0xe2,0x2c,0xb4,0x41,0x66,0xa0,0xf7,0xff,0x40,0x14, +0xac,0x40,0x65,0xa0,0x01,0x00,0x42,0x25,0xff,0x00,0x4a,0x30,0x21,0x00,0x43,0x2d, +0xef,0xff,0x60,0x14,0xc0,0x10,0x0a,0x00,0x25,0xb0,0x02,0x3c,0x0a,0x00,0x42,0x34, +0x00,0x00,0x43,0x90,0x00,0x00,0x00,0x00,0x20,0x00,0x63,0x30,0x42,0x00,0x60,0x10, +0x68,0x15,0x64,0x26,0x33,0x00,0x02,0x24,0xc1,0x42,0x62,0xa1,0x1c,0x00,0x03,0x24, +0x0f,0x00,0x02,0x24,0xbc,0x42,0x63,0xa1,0xbd,0x42,0x62,0xa1,0x68,0x15,0x65,0x26, +0x08,0x40,0xa4,0x8c,0xff,0x7f,0x08,0x3c,0xff,0xff,0x08,0x35,0xc0,0xff,0x02,0x24, +0x24,0x20,0x88,0x00,0x24,0x20,0x82,0x00,0x0c,0x00,0x84,0x34,0xff,0xc0,0x02,0x24, +0x24,0x20,0x82,0x00,0xc0,0xff,0x02,0x3c,0xff,0xff,0x42,0x34,0x00,0x18,0x84,0x34, +0xbf,0xff,0x03,0x3c,0x24,0x20,0x82,0x00,0xff,0xff,0x63,0x34,0x7f,0xff,0x02,0x3c, +0x24,0x20,0x83,0x00,0xff,0xff,0x42,0x34,0x24,0x20,0x82,0x00,0x0c,0x40,0xa6,0x8c, +0x7f,0xff,0x03,0x24,0x40,0x40,0x84,0x34,0xff,0xff,0x02,0x3c,0x24,0x20,0x83,0x00, +0xff,0x7f,0x42,0x34,0xff,0xbf,0x03,0x3c,0x10,0x40,0xa7,0x8c,0x24,0x20,0x82,0x00, +0xff,0xff,0x63,0x34,0xff,0x9f,0x02,0x3c,0x24,0x30,0xc3,0x00,0xff,0xff,0x42,0x34, +0xff,0x3f,0x03,0x3c,0x24,0x20,0x82,0x00,0xff,0xff,0x63,0x34,0x12,0x00,0x02,0x24, +0xb4,0x02,0xb3,0x8f,0xb0,0x02,0xb2,0x8f,0xac,0x02,0xb1,0x8f,0xa8,0x02,0xb0,0x8f, +0x24,0x38,0xe3,0x00,0xc7,0x42,0xa2,0xa0,0x1f,0x00,0x03,0x24,0x01,0x00,0x02,0x24, +0x24,0x30,0xc8,0x00,0xbe,0x42,0xa3,0xa0,0xc0,0x42,0xa2,0xa0,0xff,0x00,0x03,0x24, +0xff,0xff,0x02,0x24,0xb8,0x02,0xbd,0x27,0x08,0x40,0xa4,0xac,0x10,0x40,0xa7,0xac, +0x0c,0x40,0xa6,0xac,0xc2,0x42,0xa2,0xa0,0xc4,0x42,0xa3,0xa4,0xbf,0x42,0xa0,0xa0, +0x08,0x00,0xe0,0x03,0xc6,0x42,0xa0,0xa0,0x33,0x00,0x02,0x24,0xc1,0x42,0x82,0xa0, +0x0d,0x00,0x03,0x24,0x03,0x00,0x02,0x24,0xbc,0x42,0x83,0xa0,0x65,0x5d,0x00,0x08, +0xbd,0x42,0x82,0xa0,0xe0,0xff,0xbd,0x27,0x02,0x80,0x07,0x3c,0x68,0x15,0xe7,0x24, +0x18,0x00,0xbf,0xaf,0x00,0x40,0xe3,0x8c,0xf0,0xff,0x02,0x24,0x02,0x80,0x08,0x3c, +0x24,0x18,0x62,0x00,0xff,0xf0,0x02,0x24,0x24,0x18,0x62,0x00,0x00,0x40,0xe3,0xac, +0x1c,0x00,0x03,0x24,0x36,0x00,0x02,0x24,0xcf,0x42,0xe3,0xa0,0x20,0x00,0x03,0x24, +0xce,0x42,0xe2,0xa0,0xd1,0x42,0xe3,0xa0,0x32,0x00,0x02,0x24,0x20,0x00,0x03,0x24, +0xd0,0x42,0xe2,0xa0,0xc8,0x42,0xe3,0xa4,0x0a,0x00,0x02,0x24,0x00,0x02,0x03,0x24, +0xd2,0x42,0xe2,0xa0,0xcc,0x42,0xe3,0xa4,0x00,0x01,0x02,0x24,0x49,0x00,0x03,0x24, +0x38,0x97,0x08,0x25,0xff,0xff,0x0a,0x34,0x01,0x00,0x09,0x24,0x11,0x00,0xa3,0xa3, +0xca,0x42,0xe2,0xa4,0xd0,0x07,0x03,0x24,0x44,0x00,0x02,0x24,0x00,0x80,0x06,0x3c, +0x10,0x00,0xa2,0xa3,0x10,0x00,0xa5,0x27,0x47,0x00,0x02,0x24,0x21,0x20,0x00,0x01, +0x54,0x45,0xc6,0x24,0x04,0x40,0xea,0xac,0x02,0x40,0xe9,0xa0,0x0c,0x00,0x03,0xad, +0x14,0x00,0x09,0xa1,0xe6,0x42,0xe0,0xa0,0xdc,0x63,0xea,0xac,0xd7,0x42,0xe0,0xa0, +0x12,0x00,0xa2,0xa3,0xfb,0x0c,0x00,0x0c,0x13,0x00,0xa0,0xa3,0x18,0x00,0xbf,0x8f, +0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x20,0x00,0xbd,0x27,0xe0,0xff,0xbd,0x27, +0x02,0x80,0x02,0x3c,0x50,0x00,0x03,0x24,0x10,0x00,0xa3,0xa3,0x2a,0x62,0x40,0xa0, +0x41,0x00,0x03,0x24,0x52,0x00,0x02,0x24,0x02,0x80,0x07,0x3c,0xc4,0x97,0xe7,0x24, +0x11,0x00,0xa2,0xa3,0x12,0x00,0xa3,0xa3,0xd0,0x07,0x02,0x24,0x01,0x00,0x03,0x24, +0x01,0x80,0x06,0x3c,0x10,0x00,0xa5,0x27,0x21,0x20,0xe0,0x00,0x88,0x5b,0xc6,0x24, +0x0c,0x00,0xe2,0xac,0x14,0x00,0xe3,0xa0,0x18,0x00,0xbf,0xaf,0xfb,0x0c,0x00,0x0c, +0x13,0x00,0xa0,0xa3,0x18,0x00,0xbf,0x8f,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03, +0x20,0x00,0xbd,0x27,0xd8,0xff,0xbd,0x27,0x18,0x00,0xb0,0xaf,0x02,0x80,0x10,0x3c, +0x68,0x15,0x10,0x26,0x20,0x00,0xbf,0xaf,0x1c,0x00,0xb1,0xaf,0x00,0x40,0x09,0x8e, +0xff,0xff,0x02,0x24,0xff,0x00,0x4b,0x30,0x0f,0xff,0x02,0x24,0x24,0x48,0x22,0x01, +0xff,0xff,0x02,0x3c,0xff,0x0f,0x42,0x34,0x24,0x48,0x22,0x01,0x01,0x00,0x07,0x3c, +0x47,0x00,0x02,0x24,0x3b,0x00,0x03,0x24,0x02,0x80,0x08,0x3c,0x10,0x00,0xa2,0xa3, +0x11,0x00,0xa3,0xa3,0xe0,0x97,0x08,0x25,0x56,0x30,0xea,0x34,0xd0,0x07,0x02,0x24, +0x01,0x00,0x03,0x24,0xf4,0x98,0xe7,0x34,0x00,0x80,0x06,0x3c,0x04,0x43,0x0b,0xae, +0x00,0x40,0x09,0xae,0x43,0x00,0x11,0x24,0x10,0x00,0xa5,0x27,0x0c,0x43,0x07,0xae, +0x10,0x43,0x0a,0xae,0x0c,0x00,0x02,0xad,0x14,0x00,0x03,0xa1,0x08,0x43,0x00,0xae, +0x14,0x43,0x00,0xae,0x18,0x43,0x00,0xae,0x21,0x20,0x00,0x01,0xe4,0x4e,0xc6,0x24, +0x12,0x00,0xb1,0xa3,0xfb,0x0c,0x00,0x0c,0x13,0x00,0xa0,0xa3,0x1e,0x00,0x02,0x24, +0x21,0x43,0x02,0xa2,0x4a,0x00,0x03,0x24,0x45,0x00,0x02,0x24,0x1c,0x43,0x03,0xa2, +0x1d,0x43,0x02,0xa2,0x23,0x00,0x03,0x24,0x3e,0x00,0x02,0x24,0x1e,0x43,0x11,0xa2, +0x1f,0x43,0x02,0xa2,0x20,0x43,0x03,0xa2,0x20,0x00,0xbf,0x8f,0x1c,0x00,0xb1,0x8f, +0x18,0x00,0xb0,0x8f,0x08,0x00,0xe0,0x03,0x28,0x00,0xbd,0x27,0xe0,0xff,0xbd,0x27, +0x3b,0x00,0x02,0x24,0x43,0x00,0x03,0x24,0x10,0x00,0xa2,0xa3,0x11,0x00,0xa3,0xa3, +0x36,0x00,0x02,0x24,0x02,0x80,0x03,0x3c,0x02,0x80,0x07,0x3c,0xfc,0x97,0xe7,0x24, +0x12,0x00,0xa2,0xa3,0x3b,0x58,0x60,0xa0,0xd0,0x07,0x02,0x24,0x01,0x00,0x03,0x24, +0x00,0x80,0x06,0x3c,0x10,0x00,0xa5,0x27,0x21,0x20,0xe0,0x00,0x20,0x53,0xc6,0x24, +0x0c,0x00,0xe2,0xac,0x14,0x00,0xe3,0xa0,0x18,0x00,0xbf,0xaf,0xfb,0x0c,0x00,0x0c, +0x13,0x00,0xa0,0xa3,0x18,0x00,0xbf,0x8f,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03, +0x20,0x00,0xbd,0x27,0xff,0xff,0x07,0x24,0x02,0x80,0x02,0x3c,0xe0,0xff,0xbd,0x27, +0x3d,0x58,0x47,0xa0,0x3b,0x00,0x03,0x24,0x43,0x00,0x02,0x24,0x10,0x00,0xa3,0xa3, +0x11,0x00,0xa2,0xa3,0x36,0x00,0x03,0x24,0x16,0x00,0x02,0x24,0x02,0x80,0x08,0x3c, +0x18,0x98,0x08,0x25,0x12,0x00,0xa3,0xa3,0x13,0x00,0xa2,0xa3,0xd0,0x07,0x03,0x24, +0x01,0x00,0x02,0x24,0x00,0x80,0x06,0x3c,0x10,0x00,0xa5,0x27,0x21,0x20,0x00,0x01, +0x0c,0x00,0x03,0xad,0x14,0x00,0x02,0xa1,0x18,0x00,0xbf,0xaf,0xfb,0x0c,0x00,0x0c, +0xb8,0x54,0xc6,0x24,0x18,0x00,0xbf,0x8f,0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03, +0x20,0x00,0xbd,0x27,0xe0,0xff,0xbd,0x27,0x02,0x80,0x02,0x3c,0x52,0x00,0x03,0x24, +0x10,0x00,0xa3,0xa3,0x4c,0x79,0x40,0xa4,0x54,0x00,0x03,0x24,0x53,0x00,0x02,0x24, +0x02,0x80,0x07,0x3c,0x34,0x98,0xe7,0x24,0x11,0x00,0xa2,0xa3,0x12,0x00,0xa3,0xa3, +0xf4,0x01,0x02,0x24,0x01,0x00,0x03,0x24,0x01,0x80,0x06,0x3c,0x10,0x00,0xa5,0x27, +0x21,0x20,0xe0,0x00,0xc8,0x5c,0xc6,0x24,0x0c,0x00,0xe2,0xac,0x14,0x00,0xe3,0xa0, +0x18,0x00,0xbf,0xaf,0xfb,0x0c,0x00,0x0c,0x13,0x00,0xa0,0xa3,0x18,0x00,0xbf,0x8f, +0x00,0x00,0x00,0x00,0x08,0x00,0xe0,0x03,0x20,0x00,0xbd,0x27,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x78,0x0c,0x00,0x00,0x01,0x00,0x00,0x5e,0x78,0x0c,0x00,0x00, +0x01,0x00,0x01,0x5e,0x78,0x0c,0x00,0x00,0x01,0x00,0x02,0x5e,0x78,0x0c,0x00,0x00, +0x01,0x00,0x03,0x5e,0x78,0x0c,0x00,0x00,0x01,0x00,0x04,0x5d,0x78,0x0c,0x00,0x00, +0x01,0x00,0x05,0x5b,0x78,0x0c,0x00,0x00,0x01,0x00,0x06,0x59,0x78,0x0c,0x00,0x00, +0x01,0x00,0x07,0x57,0x78,0x0c,0x00,0x00,0x01,0x00,0x08,0x55,0x78,0x0c,0x00,0x00, +0x01,0x00,0x09,0x53,0x78,0x0c,0x00,0x00,0x01,0x00,0x0a,0x51,0x78,0x0c,0x00,0x00, +0x01,0x00,0x0b,0x4f,0x78,0x0c,0x00,0x00,0x01,0x00,0x0c,0x4d,0x78,0x0c,0x00,0x00, +0x01,0x00,0x0d,0x4b,0x78,0x0c,0x00,0x00,0x01,0x00,0x0e,0x49,0x78,0x0c,0x00,0x00, +0x01,0x00,0x0f,0x47,0x78,0x0c,0x00,0x00,0x01,0x00,0x10,0x45,0x78,0x0c,0x00,0x00, +0x01,0x00,0x11,0x43,0x78,0x0c,0x00,0x00,0x01,0x00,0x12,0x41,0x78,0x0c,0x00,0x00, +0x01,0x00,0x13,0x3f,0x78,0x0c,0x00,0x00,0x01,0x00,0x14,0x3d,0x78,0x0c,0x00,0x00, +0x01,0x00,0x15,0x3b,0x78,0x0c,0x00,0x00,0x01,0x00,0x16,0x39,0x78,0x0c,0x00,0x00, +0x01,0x00,0x17,0x37,0x78,0x0c,0x00,0x00,0x01,0x00,0x18,0x35,0x78,0x0c,0x00,0x00, +0x01,0x00,0x19,0x33,0x78,0x0c,0x00,0x00,0x01,0x00,0x1a,0x31,0x78,0x0c,0x00,0x00, +0x01,0x00,0x1b,0x2f,0x78,0x0c,0x00,0x00,0x01,0x00,0x1c,0x2d,0x78,0x0c,0x00,0x00, +0x01,0x00,0x1d,0x2b,0x78,0x0c,0x00,0x00,0x01,0x00,0x1e,0x29,0x78,0x0c,0x00,0x00, +0x01,0x00,0x1f,0x27,0x78,0x0c,0x00,0x00,0x01,0x00,0x20,0x25,0x78,0x0c,0x00,0x00, +0x01,0x00,0x21,0x23,0x78,0x0c,0x00,0x00,0x01,0x00,0x22,0x21,0x78,0x0c,0x00,0x00, +0x01,0x00,0x23,0x1f,0x78,0x0c,0x00,0x00,0x01,0x00,0x24,0x1d,0x78,0x0c,0x00,0x00, +0x01,0x00,0x25,0x1b,0x78,0x0c,0x00,0x00,0x01,0x00,0x26,0x19,0x78,0x0c,0x00,0x00, +0x01,0x00,0x27,0x17,0x78,0x0c,0x00,0x00,0x01,0x00,0x28,0x15,0x78,0x0c,0x00,0x00, +0x01,0x00,0x29,0x13,0x78,0x0c,0x00,0x00,0x01,0x00,0x2a,0x11,0x78,0x0c,0x00,0x00, +0x01,0x00,0x2b,0x0f,0x78,0x0c,0x00,0x00,0x01,0x00,0x2c,0x0d,0x78,0x0c,0x00,0x00, +0x01,0x00,0x2d,0x0b,0x78,0x0c,0x00,0x00,0x01,0x00,0x2e,0x09,0x78,0x0c,0x00,0x00, +0x01,0x00,0x2f,0x07,0x78,0x0c,0x00,0x00,0x01,0x00,0x30,0x05,0x78,0x0c,0x00,0x00, +0x01,0x00,0x31,0x03,0x78,0x0c,0x00,0x00,0x01,0x00,0x32,0x01,0x78,0x0c,0x00,0x00, +0x01,0x00,0x33,0x01,0x78,0x0c,0x00,0x00,0x01,0x00,0x34,0x01,0x78,0x0c,0x00,0x00, +0x01,0x00,0x35,0x01,0x78,0x0c,0x00,0x00,0x01,0x00,0x36,0x01,0x78,0x0c,0x00,0x00, +0x01,0x00,0x37,0x01,0x78,0x0c,0x00,0x00,0x01,0x00,0x38,0x01,0x78,0x0c,0x00,0x00, +0x01,0x00,0x39,0x01,0x78,0x0c,0x00,0x00,0x01,0x00,0x3a,0x01,0x78,0x0c,0x00,0x00, +0x01,0x00,0x3b,0x01,0x78,0x0c,0x00,0x00,0x01,0x00,0x3c,0x01,0x78,0x0c,0x00,0x00, +0x01,0x00,0x3d,0x01,0x78,0x0c,0x00,0x00,0x01,0x00,0x3e,0x01,0x78,0x0c,0x00,0x00, +0x01,0x00,0x3f,0x01,0x78,0x0c,0x00,0x00,0x01,0x00,0x40,0x5e,0x78,0x0c,0x00,0x00, +0x01,0x00,0x41,0x5e,0x78,0x0c,0x00,0x00,0x01,0x00,0x42,0x5e,0x78,0x0c,0x00,0x00, +0x01,0x00,0x43,0x5e,0x78,0x0c,0x00,0x00,0x01,0x00,0x44,0x5d,0x78,0x0c,0x00,0x00, +0x01,0x00,0x45,0x5b,0x78,0x0c,0x00,0x00,0x01,0x00,0x46,0x59,0x78,0x0c,0x00,0x00, +0x01,0x00,0x47,0x57,0x78,0x0c,0x00,0x00,0x01,0x00,0x48,0x55,0x78,0x0c,0x00,0x00, +0x01,0x00,0x49,0x53,0x78,0x0c,0x00,0x00,0x01,0x00,0x4a,0x51,0x78,0x0c,0x00,0x00, +0x01,0x00,0x4b,0x4f,0x78,0x0c,0x00,0x00,0x01,0x00,0x4c,0x4d,0x78,0x0c,0x00,0x00, +0x01,0x00,0x4d,0x4b,0x78,0x0c,0x00,0x00,0x01,0x00,0x4e,0x49,0x78,0x0c,0x00,0x00, +0x01,0x00,0x4f,0x47,0x78,0x0c,0x00,0x00,0x01,0x00,0x50,0x45,0x78,0x0c,0x00,0x00, +0x01,0x00,0x51,0x43,0x78,0x0c,0x00,0x00,0x01,0x00,0x52,0x41,0x78,0x0c,0x00,0x00, +0x01,0x00,0x53,0x3f,0x78,0x0c,0x00,0x00,0x01,0x00,0x54,0x3d,0x78,0x0c,0x00,0x00, +0x01,0x00,0x55,0x3b,0x78,0x0c,0x00,0x00,0x01,0x00,0x56,0x39,0x78,0x0c,0x00,0x00, +0x01,0x00,0x57,0x37,0x78,0x0c,0x00,0x00,0x01,0x00,0x58,0x35,0x78,0x0c,0x00,0x00, +0x01,0x00,0x59,0x33,0x78,0x0c,0x00,0x00,0x01,0x00,0x5a,0x31,0x78,0x0c,0x00,0x00, +0x01,0x00,0x5b,0x2f,0x78,0x0c,0x00,0x00,0x01,0x00,0x5c,0x2d,0x78,0x0c,0x00,0x00, +0x01,0x00,0x5d,0x2b,0x78,0x0c,0x00,0x00,0x01,0x00,0x5e,0x29,0x78,0x0c,0x00,0x00, +0x01,0x00,0x5f,0x27,0x78,0x0c,0x00,0x00,0x01,0x00,0x60,0x25,0x78,0x0c,0x00,0x00, +0x01,0x00,0x61,0x23,0x78,0x0c,0x00,0x00,0x01,0x00,0x62,0x21,0x78,0x0c,0x00,0x00, +0x01,0x00,0x63,0x1f,0x78,0x0c,0x00,0x00,0x01,0x00,0x64,0x1d,0x78,0x0c,0x00,0x00, +0x01,0x00,0x65,0x1b,0x78,0x0c,0x00,0x00,0x01,0x00,0x66,0x19,0x78,0x0c,0x00,0x00, +0x01,0x00,0x67,0x17,0x78,0x0c,0x00,0x00,0x01,0x00,0x68,0x15,0x78,0x0c,0x00,0x00, +0x01,0x00,0x69,0x13,0x78,0x0c,0x00,0x00,0x01,0x00,0x6a,0x11,0x78,0x0c,0x00,0x00, +0x01,0x00,0x6b,0x0f,0x78,0x0c,0x00,0x00,0x01,0x00,0x6c,0x0d,0x78,0x0c,0x00,0x00, +0x01,0x00,0x6d,0x0b,0x78,0x0c,0x00,0x00,0x01,0x00,0x6e,0x09,0x78,0x0c,0x00,0x00, +0x01,0x00,0x6f,0x07,0x78,0x0c,0x00,0x00,0x01,0x00,0x70,0x05,0x78,0x0c,0x00,0x00, +0x01,0x00,0x71,0x03,0x78,0x0c,0x00,0x00,0x01,0x00,0x72,0x01,0x78,0x0c,0x00,0x00, +0x01,0x00,0x73,0x01,0x78,0x0c,0x00,0x00,0x01,0x00,0x74,0x01,0x78,0x0c,0x00,0x00, +0x01,0x00,0x75,0x01,0x78,0x0c,0x00,0x00,0x01,0x00,0x76,0x01,0x78,0x0c,0x00,0x00, +0x01,0x00,0x77,0x01,0x78,0x0c,0x00,0x00,0x01,0x00,0x78,0x01,0x78,0x0c,0x00,0x00, +0x01,0x00,0x79,0x01,0x78,0x0c,0x00,0x00,0x01,0x00,0x7a,0x01,0x78,0x0c,0x00,0x00, +0x01,0x00,0x7b,0x01,0x78,0x0c,0x00,0x00,0x01,0x00,0x7c,0x01,0x78,0x0c,0x00,0x00, +0x01,0x00,0x7d,0x01,0x78,0x0c,0x00,0x00,0x01,0x00,0x7e,0x01,0x78,0x0c,0x00,0x00, +0x01,0x00,0x7f,0x01,0x78,0x0c,0x00,0x00,0x1e,0x00,0x00,0x30,0x78,0x0c,0x00,0x00, +0x1e,0x00,0x01,0x30,0x78,0x0c,0x00,0x00,0x1e,0x00,0x02,0x30,0x78,0x0c,0x00,0x00, +0x1e,0x00,0x03,0x30,0x78,0x0c,0x00,0x00,0x1e,0x00,0x04,0x30,0x78,0x0c,0x00,0x00, +0x1e,0x00,0x05,0x30,0x78,0x0c,0x00,0x00,0x1e,0x00,0x06,0x30,0x78,0x0c,0x00,0x00, +0x1e,0x00,0x07,0x30,0x78,0x0c,0x00,0x00,0x1e,0x00,0x08,0x3e,0x78,0x0c,0x00,0x00, +0x1e,0x00,0x09,0x40,0x78,0x0c,0x00,0x00,0x1e,0x00,0x0a,0x42,0x78,0x0c,0x00,0x00, +0x1e,0x00,0x0b,0x44,0x78,0x0c,0x00,0x00,0x1e,0x00,0x0c,0x46,0x78,0x0c,0x00,0x00, +0x1e,0x00,0x0d,0x48,0x78,0x0c,0x00,0x00,0x1e,0x00,0x0e,0x48,0x78,0x0c,0x00,0x00, +0x1e,0x00,0x0f,0x4a,0x78,0x0c,0x00,0x00,0x1e,0x00,0x10,0x4a,0x78,0x0c,0x00,0x00, +0x1e,0x00,0x11,0x4c,0x78,0x0c,0x00,0x00,0x1e,0x00,0x12,0x4c,0x78,0x0c,0x00,0x00, +0x1e,0x00,0x13,0x4e,0x78,0x0c,0x00,0x00,0x1e,0x00,0x14,0x50,0x78,0x0c,0x00,0x00, +0x1e,0x00,0x15,0x50,0x78,0x0c,0x00,0x00,0x1e,0x00,0x16,0x50,0x78,0x0c,0x00,0x00, +0x1e,0x00,0x17,0x52,0x78,0x0c,0x00,0x00,0x1e,0x00,0x18,0x52,0x78,0x0c,0x00,0x00, +0x1e,0x00,0x19,0x52,0x78,0x0c,0x00,0x00,0x1e,0x00,0x1a,0x54,0x78,0x0c,0x00,0x00, +0x1e,0x00,0x1b,0x54,0x78,0x0c,0x00,0x00,0x1e,0x00,0x1c,0x54,0x78,0x0c,0x00,0x00, +0x1e,0x00,0x1d,0x56,0x78,0x0c,0x00,0x00,0x1e,0x00,0x1e,0x56,0x78,0x0c,0x00,0x00, +0x1e,0x00,0x1f,0x56,0x78,0x0c,0x00,0x00,0x1e,0x00,0x20,0x56,0x78,0x0c,0x00,0x00, +0x1e,0x00,0x21,0x58,0x78,0x0c,0x00,0x00,0x1e,0x00,0x22,0x58,0x78,0x0c,0x00,0x00, +0x1e,0x00,0x23,0x58,0x78,0x0c,0x00,0x00,0x1e,0x00,0x24,0x58,0x78,0x0c,0x00,0x00, +0x1e,0x00,0x25,0x5a,0x78,0x0c,0x00,0x00,0x1e,0x00,0x26,0x5a,0x78,0x0c,0x00,0x00, +0x1e,0x00,0x27,0x5a,0x78,0x0c,0x00,0x00,0x1e,0x00,0x28,0x5c,0x78,0x0c,0x00,0x00, +0x1e,0x00,0x29,0x5c,0x78,0x0c,0x00,0x00,0x1e,0x00,0x2a,0x5e,0x78,0x0c,0x00,0x00, +0x1e,0x00,0x2b,0x5e,0x78,0x0c,0x00,0x00,0x1e,0x00,0x2c,0x5e,0x78,0x0c,0x00,0x00, +0x1e,0x00,0x2d,0x5e,0x78,0x0c,0x00,0x00,0x1e,0x00,0x2e,0x5e,0x78,0x0c,0x00,0x00, +0x1e,0x00,0x2f,0x5e,0x78,0x0c,0x00,0x00,0x1e,0x00,0x30,0x5e,0x78,0x0c,0x00,0x00, +0x1e,0x00,0x31,0x5e,0x78,0x0c,0x00,0x00,0x1e,0x00,0x32,0x5e,0x78,0x0c,0x00,0x00, +0x1e,0x00,0x33,0x5e,0x78,0x0c,0x00,0x00,0x1e,0x00,0x34,0x5e,0x78,0x0c,0x00,0x00, +0x1e,0x00,0x35,0x5e,0x78,0x0c,0x00,0x00,0x1e,0x00,0x36,0x5e,0x78,0x0c,0x00,0x00, +0x1e,0x00,0x37,0x5e,0x78,0x0c,0x00,0x00,0x1e,0x00,0x38,0x5e,0x78,0x0c,0x00,0x00, +0x1e,0x00,0x39,0x5e,0x78,0x0c,0x00,0x00,0x1e,0x00,0x3a,0x5e,0x78,0x0c,0x00,0x00, +0x1e,0x00,0x3b,0x5e,0x78,0x0c,0x00,0x00,0x1e,0x00,0x3c,0x5e,0x78,0x0c,0x00,0x00, +0x1e,0x00,0x3d,0x5e,0x78,0x0c,0x00,0x00,0x1e,0x00,0x3e,0x5e,0x78,0x0c,0x00,0x00, +0x1e,0x00,0x3f,0x5e,0xff,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x08,0x00,0x00, +0x00,0x00,0x04,0x03,0x04,0x08,0x00,0x00,0x03,0x00,0x00,0x00,0x08,0x08,0x00,0x00, +0x00,0xfc,0x00,0x00,0x0c,0x08,0x00,0x00,0x0a,0x00,0x00,0x04,0x10,0x08,0x00,0x00, +0xff,0x10,0x10,0x80,0x14,0x08,0x00,0x00,0x10,0x3d,0x0c,0x02,0x18,0x08,0x00,0x00, +0xc5,0x03,0x00,0x00,0x1c,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x08,0x00,0x00, +0x04,0x00,0x00,0x00,0x24,0x08,0x00,0x00,0x00,0x02,0x69,0x00,0x28,0x08,0x00,0x00, +0x04,0x00,0x00,0x00,0x2c,0x08,0x00,0x00,0x00,0x02,0x69,0x00,0x30,0x08,0x00,0x00, +0x04,0x00,0x00,0x00,0x34,0x08,0x00,0x00,0x00,0x02,0x69,0x00,0x38,0x08,0x00,0x00, +0x04,0x00,0x00,0x00,0x3c,0x08,0x00,0x00,0x00,0x02,0x69,0x00,0x40,0x08,0x00,0x00, +0x00,0x00,0x00,0x00,0x44,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x08,0x00,0x00, +0x00,0x00,0x00,0x00,0x4c,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x50,0x08,0x00,0x00, +0x00,0x00,0x00,0x00,0x54,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x08,0x00,0x00, +0x65,0xa9,0x65,0xa9,0x5c,0x08,0x00,0x00,0x65,0xa9,0x65,0xa9,0x60,0x08,0x00,0x00, +0x30,0x01,0x7f,0x0f,0x64,0x08,0x00,0x00,0x30,0x01,0x7f,0x0f,0x68,0x08,0x00,0x00, +0x30,0x01,0x7f,0x0f,0x6c,0x08,0x00,0x00,0x30,0x01,0x7f,0x0f,0x70,0x08,0x00,0x00, +0x00,0x03,0x00,0x03,0x74,0x08,0x00,0x00,0x00,0x03,0x00,0x03,0x78,0x08,0x00,0x00, +0x00,0x00,0x00,0x00,0x7c,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x90,0x08,0x00,0x00, +0x00,0x00,0x00,0x00,0x94,0x08,0x00,0x00,0xfe,0xff,0xff,0xff,0x98,0x08,0x00,0x00, +0x10,0x20,0x30,0x40,0x9c,0x08,0x00,0x00,0x50,0x60,0x70,0x00,0xb0,0x08,0x00,0x00, +0x00,0x00,0x00,0x00,0xe0,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0xe4,0x08,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x0e,0x00,0x00,0x03,0x03,0x03,0x03,0x04,0x0e,0x00,0x00, +0x03,0x03,0x03,0x03,0x08,0x0e,0x00,0x00,0x03,0x03,0x00,0x00,0x0c,0x0e,0x00,0x00, +0x00,0x00,0x00,0x00,0x10,0x0e,0x00,0x00,0x03,0x03,0x03,0x03,0x14,0x0e,0x00,0x00, +0x03,0x03,0x03,0x03,0x18,0x0e,0x00,0x00,0x03,0x03,0x03,0x03,0x1c,0x0e,0x00,0x00, +0x03,0x03,0x03,0x03,0x00,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x09,0x00,0x00, +0x23,0x00,0x00,0x00,0x08,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x09,0x00,0x00, +0x33,0x13,0x32,0x03,0x08,0x0a,0x00,0x00,0x00,0x86,0x88,0x8f,0x2c,0x0a,0x00,0x00, +0x00,0x00,0x92,0x00,0x00,0x0c,0x00,0x00,0x80,0x00,0x00,0x00,0x04,0x0c,0x00,0x00, +0x33,0x54,0x00,0x00,0x08,0x0c,0x00,0x00,0xe4,0x00,0x00,0x00,0x0c,0x0c,0x00,0x00, +0x6c,0x6c,0x6c,0x6c,0x10,0x0c,0x00,0x00,0x00,0x00,0x00,0x08,0x14,0x0c,0x00,0x00, +0x00,0x01,0x00,0x40,0x18,0x0c,0x00,0x00,0x00,0x00,0x00,0x08,0x1c,0x0c,0x00,0x00, +0x00,0x01,0x00,0x40,0x20,0x0c,0x00,0x00,0x00,0x00,0x00,0x08,0x24,0x0c,0x00,0x00, +0x00,0x01,0x00,0x40,0x28,0x0c,0x00,0x00,0x00,0x00,0x00,0x08,0x2c,0x0c,0x00,0x00, +0x00,0x01,0x00,0x40,0x30,0x0c,0x00,0x00,0x44,0x6a,0xe9,0x8d,0x34,0x0c,0x00,0x00, +0xcd,0x52,0x96,0x46,0x38,0x0c,0x00,0x00,0x90,0x5a,0x01,0x48,0x3c,0x0c,0x00,0x00, +0x64,0x97,0x97,0x1a,0x40,0x0c,0x00,0x00,0x3f,0x42,0x7c,0x1f,0x44,0x0c,0x00,0x00, +0xb7,0x00,0x01,0x00,0x48,0x0c,0x00,0x00,0x00,0x00,0x02,0xec,0x4c,0x0c,0x00,0x00, +0x03,0x03,0xfc,0x00,0x50,0x0c,0x00,0x00,0x1c,0x34,0x54,0x69,0x54,0x0c,0x00,0x00, +0x94,0x00,0x3c,0x43,0x58,0x0c,0x00,0x00,0x1c,0x34,0x54,0x69,0x5c,0x0c,0x00,0x00, +0x94,0x00,0x3c,0x43,0x60,0x0c,0x00,0x00,0x1c,0x34,0x54,0x69,0x64,0x0c,0x00,0x00, +0x94,0x00,0x3c,0x43,0x68,0x0c,0x00,0x00,0x1c,0x34,0x54,0x69,0x6c,0x0c,0x00,0x00, +0x94,0x00,0x3c,0x43,0x70,0x0c,0x00,0x00,0x0d,0x00,0x5a,0x2c,0x74,0x0c,0x00,0x00, +0x1b,0x15,0x86,0x01,0x78,0x0c,0x00,0x00,0x1f,0x00,0x00,0x00,0x7c,0x0c,0x00,0x00, +0x12,0x16,0xb9,0x00,0x80,0x0c,0x00,0x00,0x80,0x00,0x00,0x20,0x84,0x0c,0x00,0x00, +0x00,0x00,0x00,0x00,0x88,0x0c,0x00,0x00,0x80,0x00,0x00,0x20,0x8c,0x0c,0x00,0x00, +0x00,0x00,0x20,0x08,0x90,0x0c,0x00,0x00,0x00,0x01,0x00,0x40,0x94,0x0c,0x00,0x00, +0x00,0x00,0x00,0x00,0x98,0x0c,0x00,0x00,0x00,0x01,0x00,0x40,0x9c,0x0c,0x00,0x00, +0x00,0x00,0x00,0x00,0xa0,0x0c,0x00,0x00,0x92,0x24,0x49,0x00,0xa4,0x0c,0x00,0x00, +0x00,0x00,0x00,0x00,0xa8,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0xac,0x0c,0x00,0x00, +0x00,0x00,0x00,0x00,0xb0,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0xb4,0x0c,0x00,0x00, +0x00,0x00,0x00,0x00,0xb8,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0xbc,0x0c,0x00,0x00, +0x92,0x24,0x49,0x00,0xc0,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0xc4,0x0c,0x00,0x00, +0x00,0x00,0x00,0x00,0xc8,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0xcc,0x0c,0x00,0x00, +0x00,0x00,0x00,0x00,0xd0,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0xd4,0x0c,0x00,0x00, +0x00,0x00,0x00,0x00,0xd8,0x0c,0x00,0x00,0x27,0x24,0xb2,0x64,0xdc,0x0c,0x00,0x00, +0x32,0x69,0x76,0x00,0xe0,0x0c,0x00,0x00,0x22,0x22,0x22,0x00,0xe4,0x0c,0x00,0x00, +0x00,0x00,0x00,0x00,0xe8,0x0c,0x00,0x00,0x02,0x43,0x64,0x07,0x00,0x0d,0x00,0x00, +0x80,0x07,0x00,0x00,0x04,0x0d,0x00,0x00,0x03,0x04,0x00,0x00,0x08,0x0d,0x00,0x00, +0x7f,0x90,0x00,0x00,0x0c,0x0d,0x00,0x00,0x01,0x00,0x00,0x00,0x10,0x0d,0x00,0x00, +0x99,0x99,0x69,0xa0,0x14,0x0d,0x00,0x00,0x67,0x3c,0x99,0x99,0x18,0x0d,0x00,0x00, +0x6b,0x5b,0x8f,0x6a,0x1c,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x0d,0x00,0x00, +0x00,0x00,0x00,0x00,0x24,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x0d,0x00,0x00, +0x00,0x00,0x00,0x00,0x2c,0x0d,0x00,0x00,0x75,0x19,0x97,0xcc,0x30,0x0d,0x00,0x00, +0x00,0x00,0x00,0x00,0x34,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x0d,0x00,0x00, +0x00,0x00,0x00,0x00,0x3c,0x0d,0x00,0x00,0x93,0x72,0x02,0x00,0x40,0x0d,0x00,0x00, +0x00,0x00,0x00,0x00,0x44,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x0d,0x00,0x00, +0x00,0x00,0x00,0x00,0x50,0x0d,0x00,0x00,0x0a,0x14,0x37,0x64,0x54,0x0d,0x00,0x00, +0x02,0xbd,0x4d,0x02,0x58,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x5c,0x0d,0x00,0x00, +0x64,0x20,0x03,0x30,0x60,0x0d,0x00,0x00,0x68,0xde,0x53,0x46,0x64,0x0d,0x00,0x00, +0x3c,0x8a,0x51,0x00,0x68,0x0d,0x00,0x00,0x06,0x01,0x00,0x00,0xff,0x00,0x00,0x00, +0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00, +0x44,0x05,0x01,0x80,0x10,0x00,0x00,0x00,0x74,0x05,0x01,0x80,0x10,0x00,0x00,0x00, +0xe0,0x2e,0x00,0x80,0x10,0x00,0x00,0x00,0xec,0x2e,0x00,0x80,0x10,0x00,0x00,0x00, +0xa0,0x08,0x01,0x80,0x08,0x00,0x00,0x00,0x38,0x06,0x01,0x80,0x00,0xb7,0x00,0x00, +0x01,0xe0,0x0e,0x00,0x02,0x4d,0x04,0x00,0x03,0x41,0x04,0x00,0x04,0xc3,0x08,0x00, +0x05,0x72,0x0c,0x00,0x06,0xe6,0x00,0x00,0x07,0x2a,0x08,0x00,0x08,0x3f,0x00,0x00, +0x09,0x35,0x03,0x00,0x0a,0xd4,0x09,0x00,0x0b,0xbb,0x07,0x00,0x0c,0x50,0x08,0x00, +0x0d,0xdf,0x0c,0x00,0x0e,0x2b,0x00,0x00,0x0f,0x14,0x01,0x00,0x00,0xb7,0x01,0x00, +0x01,0x01,0x00,0x00,0x02,0x00,0x04,0x00,0x01,0x02,0x00,0x00,0x02,0x01,0x04,0x00, +0x01,0x03,0x00,0x00,0x02,0x02,0x04,0x00,0x01,0x04,0x00,0x00,0x02,0x03,0x04,0x00, +0x01,0x05,0x00,0x00,0x02,0x04,0x04,0x00,0x01,0x06,0x00,0x00,0x02,0x05,0x04,0x00, +0x01,0x07,0x00,0x00,0x02,0x08,0x04,0x00,0x01,0x08,0x00,0x00,0x02,0x09,0x04,0x00, +0x01,0x09,0x00,0x00,0x02,0x0a,0x04,0x00,0x01,0x0a,0x00,0x00,0x02,0x0b,0x04,0x00, +0x01,0x0b,0x00,0x00,0x02,0x02,0x05,0x00,0x01,0x0c,0x00,0x00,0x02,0x03,0x05,0x00, +0x01,0x0d,0x00,0x00,0x02,0x04,0x05,0x00,0x01,0x0e,0x00,0x00,0x02,0x05,0x05,0x00, +0x01,0x0f,0x00,0x00,0x02,0x40,0x05,0x00,0x01,0x10,0x00,0x00,0x02,0x41,0x05,0x00, +0x01,0x11,0x00,0x00,0x02,0x42,0x05,0x00,0x01,0x12,0x00,0x00,0x02,0x43,0x05,0x00, +0x01,0x13,0x00,0x00,0x02,0x44,0x05,0x00,0x01,0x14,0x00,0x00,0x02,0x45,0x05,0x00, +0x01,0x15,0x00,0x00,0x02,0x80,0x05,0x00,0x01,0x16,0x00,0x00,0x02,0x81,0x05,0x00, +0x01,0x17,0x00,0x00,0x02,0x82,0x05,0x00,0x01,0x18,0x00,0x00,0x02,0x83,0x05,0x00, +0x01,0x19,0x00,0x00,0x02,0x84,0x05,0x00,0x01,0x1a,0x00,0x00,0x02,0x85,0x05,0x00, +0x01,0x1b,0x00,0x00,0x02,0x88,0x05,0x00,0x01,0x1c,0x00,0x00,0x02,0x89,0x05,0x00, +0x01,0x1d,0x00,0x00,0x02,0x8a,0x05,0x00,0x01,0x1e,0x00,0x00,0x02,0x8b,0x05,0x00, +0x01,0x1f,0x00,0x00,0x02,0x43,0x06,0x00,0x01,0x20,0x00,0x00,0x02,0x44,0x06,0x00, +0x01,0x21,0x00,0x00,0x02,0x45,0x06,0x00,0x01,0x22,0x00,0x00,0x02,0x80,0x06,0x00, +0x01,0x23,0x00,0x00,0x02,0x81,0x06,0x00,0x01,0x24,0x00,0x00,0x02,0x82,0x06,0x00, +0x01,0x25,0x00,0x00,0x02,0x83,0x06,0x00,0x01,0x26,0x00,0x00,0x02,0x84,0x06,0x00, +0x01,0x27,0x00,0x00,0x02,0x85,0x06,0x00,0x01,0x28,0x00,0x00,0x02,0x88,0x06,0x00, +0x01,0x29,0x00,0x00,0x02,0x89,0x06,0x00,0x01,0x2a,0x00,0x00,0x02,0x8a,0x06,0x00, +0x01,0x2b,0x00,0x00,0x02,0x8b,0x06,0x00,0x01,0x2c,0x00,0x00,0x02,0x8c,0x06,0x00, +0x01,0x2d,0x00,0x00,0x02,0x42,0x07,0x00,0x01,0x2e,0x00,0x00,0x02,0x43,0x07,0x00, +0x01,0x2f,0x00,0x00,0x02,0x44,0x07,0x00,0x01,0x30,0x00,0x00,0x02,0x45,0x07,0x00, +0x01,0x31,0x00,0x00,0x02,0x80,0x07,0x00,0x01,0x32,0x00,0x00,0x02,0x81,0x07,0x00, +0x01,0x33,0x00,0x00,0x02,0x82,0x07,0x00,0x01,0x34,0x00,0x00,0x02,0x83,0x07,0x00, +0x01,0x35,0x00,0x00,0x02,0x84,0x07,0x00,0x01,0x36,0x00,0x00,0x02,0x85,0x07,0x00, +0x01,0x37,0x00,0x00,0x02,0x88,0x07,0x00,0x01,0x38,0x00,0x00,0x02,0x89,0x07,0x00, +0x01,0x39,0x00,0x00,0x02,0x8a,0x07,0x00,0x01,0x3a,0x00,0x00,0x02,0x8b,0x07,0x00, +0x01,0x3b,0x00,0x00,0x02,0x8c,0x07,0x00,0x01,0x3c,0x00,0x00,0x02,0x8d,0x07,0x00, +0x01,0x3d,0x00,0x00,0x02,0x90,0x07,0x00,0x01,0x3e,0x00,0x00,0x02,0x91,0x07,0x00, +0x01,0x3f,0x00,0x00,0x02,0x92,0x07,0x00,0x01,0x40,0x00,0x00,0x02,0x93,0x07,0x00, +0x01,0x41,0x00,0x00,0x02,0x94,0x07,0x00,0x01,0x42,0x00,0x00,0x02,0x95,0x07,0x00, +0x01,0x43,0x00,0x00,0x02,0x98,0x07,0x00,0x01,0x44,0x00,0x00,0x02,0x99,0x07,0x00, +0x01,0x45,0x00,0x00,0x02,0x9a,0x07,0x00,0x01,0x46,0x00,0x00,0x02,0x9b,0x07,0x00, +0x01,0x47,0x00,0x00,0x02,0x9c,0x07,0x00,0x01,0x48,0x00,0x00,0x02,0x9d,0x07,0x00, +0x01,0x49,0x00,0x00,0x02,0xa0,0x07,0x00,0x01,0x4a,0x00,0x00,0x02,0xa1,0x07,0x00, +0x01,0x4b,0x00,0x00,0x02,0xa2,0x07,0x00,0x01,0x4c,0x00,0x00,0x02,0xa3,0x07,0x00, +0x01,0x4d,0x00,0x00,0x02,0xa4,0x07,0x00,0x01,0x4e,0x00,0x00,0x02,0xa5,0x07,0x00, +0x01,0x4f,0x00,0x00,0x02,0xa8,0x07,0x00,0x01,0x50,0x00,0x00,0x02,0xa9,0x07,0x00, +0x01,0x51,0x00,0x00,0x02,0xaa,0x03,0x00,0x01,0x52,0x00,0x00,0x02,0xab,0x03,0x00, +0x01,0x53,0x00,0x00,0x02,0xac,0x03,0x00,0x01,0x54,0x00,0x00,0x02,0xad,0x03,0x00, +0x01,0x55,0x00,0x00,0x02,0xb0,0x03,0x00,0x01,0x56,0x00,0x00,0x02,0xb1,0x03,0x00, +0x01,0x57,0x00,0x00,0x02,0xb2,0x03,0x00,0x01,0x58,0x00,0x00,0x02,0xb3,0x03,0x00, +0x01,0x59,0x00,0x00,0x02,0xb4,0x03,0x00,0x01,0x5a,0x00,0x00,0x02,0xb5,0x03,0x00, +0x01,0x5b,0x00,0x00,0x02,0xb8,0x03,0x00,0x01,0x5c,0x00,0x00,0x02,0xb9,0x03,0x00, +0x01,0x5d,0x00,0x00,0x02,0xba,0x03,0x00,0x01,0x5e,0x00,0x00,0x02,0xbb,0x03,0x00, +0x01,0x5f,0x00,0x00,0x02,0xbb,0x03,0x00,0x03,0x80,0x00,0x00,0x05,0x04,0x00,0x00, +0x00,0xb7,0x00,0x00,0xfe,0x00,0x00,0x00,0xfe,0x00,0x00,0x00,0xfe,0x00,0x00,0x00, +0x02,0x4d,0x0c,0x00,0xfe,0x00,0x00,0x00,0xfe,0x00,0x00,0x00,0x02,0x4d,0x04,0x00, +0x00,0xbf,0x02,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0x00,0xb7,0x00,0x00, +0x01,0xe0,0x0e,0x00,0x02,0x4d,0x04,0x00,0x03,0x41,0x04,0x00,0x04,0xc3,0x08,0x00, +0x05,0x72,0x0c,0x00,0x06,0xe6,0x00,0x00,0x07,0x2a,0x08,0x00,0x08,0x3f,0x00,0x00, +0x09,0x35,0x03,0x00,0x0a,0xd4,0x09,0x00,0x0b,0xbb,0x07,0x00,0x0c,0x50,0x08,0x00, +0x0d,0xdf,0x0c,0x00,0x0e,0x2b,0x00,0x00,0x0f,0x14,0x01,0x00,0x00,0xb7,0x01,0x00, +0x01,0x01,0x00,0x00,0x02,0x00,0x04,0x00,0x01,0x02,0x00,0x00,0x02,0x01,0x04,0x00, +0x01,0x03,0x00,0x00,0x02,0x02,0x04,0x00,0x01,0x04,0x00,0x00,0x02,0x03,0x04,0x00, +0x01,0x05,0x00,0x00,0x02,0x04,0x04,0x00,0x01,0x06,0x00,0x00,0x02,0x05,0x04,0x00, +0x01,0x07,0x00,0x00,0x02,0x08,0x04,0x00,0x01,0x08,0x00,0x00,0x02,0x09,0x04,0x00, +0x01,0x09,0x00,0x00,0x02,0x0a,0x04,0x00,0x01,0x0a,0x00,0x00,0x02,0x0b,0x04,0x00, +0x01,0x0b,0x00,0x00,0x02,0x02,0x05,0x00,0x01,0x0c,0x00,0x00,0x02,0x03,0x05,0x00, +0x01,0x0d,0x00,0x00,0x02,0x04,0x05,0x00,0x01,0x0e,0x00,0x00,0x02,0x05,0x05,0x00, +0x01,0x0f,0x00,0x00,0x02,0x40,0x05,0x00,0x01,0x10,0x00,0x00,0x02,0x41,0x05,0x00, +0x01,0x11,0x00,0x00,0x02,0x42,0x05,0x00,0x01,0x12,0x00,0x00,0x02,0x43,0x05,0x00, +0x01,0x13,0x00,0x00,0x02,0x44,0x05,0x00,0x01,0x14,0x00,0x00,0x02,0x45,0x05,0x00, +0x01,0x15,0x00,0x00,0x02,0x80,0x05,0x00,0x01,0x16,0x00,0x00,0x02,0x81,0x05,0x00, +0x01,0x17,0x00,0x00,0x02,0x82,0x05,0x00,0x01,0x18,0x00,0x00,0x02,0x83,0x05,0x00, +0x01,0x19,0x00,0x00,0x02,0x84,0x05,0x00,0x01,0x1a,0x00,0x00,0x02,0x85,0x05,0x00, +0x01,0x1b,0x00,0x00,0x02,0x88,0x05,0x00,0x01,0x1c,0x00,0x00,0x02,0x89,0x05,0x00, +0x01,0x1d,0x00,0x00,0x02,0x8a,0x05,0x00,0x01,0x1e,0x00,0x00,0x02,0x8b,0x05,0x00, +0x01,0x1f,0x00,0x00,0x02,0x43,0x06,0x00,0x01,0x20,0x00,0x00,0x02,0x44,0x06,0x00, +0x01,0x21,0x00,0x00,0x02,0x45,0x06,0x00,0x01,0x22,0x00,0x00,0x02,0x80,0x06,0x00, +0x01,0x23,0x00,0x00,0x02,0x81,0x06,0x00,0x01,0x24,0x00,0x00,0x02,0x82,0x06,0x00, +0x01,0x25,0x00,0x00,0x02,0x83,0x06,0x00,0x01,0x26,0x00,0x00,0x02,0x84,0x06,0x00, +0x01,0x27,0x00,0x00,0x02,0x85,0x06,0x00,0x01,0x28,0x00,0x00,0x02,0x88,0x06,0x00, +0x01,0x29,0x00,0x00,0x02,0x89,0x06,0x00,0x01,0x2a,0x00,0x00,0x02,0x8a,0x06,0x00, +0x01,0x2b,0x00,0x00,0x02,0x8b,0x06,0x00,0x01,0x2c,0x00,0x00,0x02,0x8c,0x06,0x00, +0x01,0x2d,0x00,0x00,0x02,0x42,0x07,0x00,0x01,0x2e,0x00,0x00,0x02,0x43,0x07,0x00, +0x01,0x2f,0x00,0x00,0x02,0x44,0x07,0x00,0x01,0x30,0x00,0x00,0x02,0x45,0x07,0x00, +0x01,0x31,0x00,0x00,0x02,0x80,0x07,0x00,0x01,0x32,0x00,0x00,0x02,0x81,0x07,0x00, +0x01,0x33,0x00,0x00,0x02,0x82,0x07,0x00,0x01,0x34,0x00,0x00,0x02,0x83,0x07,0x00, +0x01,0x35,0x00,0x00,0x02,0x84,0x07,0x00,0x01,0x36,0x00,0x00,0x02,0x85,0x07,0x00, +0x01,0x37,0x00,0x00,0x02,0x88,0x07,0x00,0x01,0x38,0x00,0x00,0x02,0x89,0x07,0x00, +0x01,0x39,0x00,0x00,0x02,0x8a,0x07,0x00,0x01,0x3a,0x00,0x00,0x02,0x8b,0x07,0x00, +0x01,0x3b,0x00,0x00,0x02,0x8c,0x07,0x00,0x01,0x3c,0x00,0x00,0x02,0x8d,0x07,0x00, +0x01,0x3d,0x00,0x00,0x02,0x90,0x07,0x00,0x01,0x3e,0x00,0x00,0x02,0x91,0x07,0x00, +0x01,0x3f,0x00,0x00,0x02,0x92,0x07,0x00,0x01,0x40,0x00,0x00,0x02,0x93,0x07,0x00, +0x01,0x41,0x00,0x00,0x02,0x94,0x07,0x00,0x01,0x42,0x00,0x00,0x02,0x95,0x07,0x00, +0x01,0x43,0x00,0x00,0x02,0x98,0x07,0x00,0x01,0x44,0x00,0x00,0x02,0x99,0x07,0x00, +0x01,0x45,0x00,0x00,0x02,0x9a,0x07,0x00,0x01,0x46,0x00,0x00,0x02,0x9b,0x07,0x00, +0x01,0x47,0x00,0x00,0x02,0x9c,0x07,0x00,0x01,0x48,0x00,0x00,0x02,0x9d,0x07,0x00, +0x01,0x49,0x00,0x00,0x02,0xa0,0x07,0x00,0x01,0x4a,0x00,0x00,0x02,0xa1,0x07,0x00, +0x01,0x4b,0x00,0x00,0x02,0xa2,0x07,0x00,0x01,0x4c,0x00,0x00,0x02,0xa3,0x07,0x00, +0x01,0x4d,0x00,0x00,0x02,0xa4,0x07,0x00,0x01,0x4e,0x00,0x00,0x02,0xa5,0x07,0x00, +0x01,0x4f,0x00,0x00,0x02,0xa8,0x07,0x00,0x01,0x50,0x00,0x00,0x02,0xa9,0x07,0x00, +0x01,0x51,0x00,0x00,0x02,0xaa,0x03,0x00,0x01,0x52,0x00,0x00,0x02,0xab,0x03,0x00, +0x01,0x53,0x00,0x00,0x02,0xac,0x03,0x00,0x01,0x54,0x00,0x00,0x02,0xad,0x03,0x00, +0x01,0x55,0x00,0x00,0x02,0xb0,0x03,0x00,0x01,0x56,0x00,0x00,0x02,0xb1,0x03,0x00, +0x01,0x57,0x00,0x00,0x02,0xb2,0x03,0x00,0x01,0x58,0x00,0x00,0x02,0xb3,0x03,0x00, +0x01,0x59,0x00,0x00,0x02,0xb4,0x03,0x00,0x01,0x5a,0x00,0x00,0x02,0xb5,0x03,0x00, +0x01,0x5b,0x00,0x00,0x02,0xb8,0x03,0x00,0x01,0x5c,0x00,0x00,0x02,0xb9,0x03,0x00, +0x01,0x5d,0x00,0x00,0x02,0xba,0x03,0x00,0x01,0x5e,0x00,0x00,0x02,0xbb,0x03,0x00, +0x01,0x5f,0x00,0x00,0x02,0xbb,0x03,0x00,0x03,0x80,0x00,0x00,0x05,0x04,0x00,0x00, +0x00,0xb7,0x00,0x00,0xfe,0x00,0x00,0x00,0xfe,0x00,0x00,0x00,0xfe,0x00,0x00,0x00, +0x02,0x4d,0x0c,0x00,0xfe,0x00,0x00,0x00,0xfe,0x00,0x00,0x00,0x02,0x4d,0x04,0x00, +0x00,0xbf,0x02,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0x0a,0x00,0x00,0x00, +0x4f,0x6e,0x41,0x73,0x73,0x6f,0x63,0x52,0x65,0x71,0x00,0x00,0x4f,0x6e,0x41,0x73, +0x73,0x6f,0x63,0x52,0x73,0x70,0x00,0x00,0x4f,0x6e,0x52,0x65,0x41,0x73,0x73,0x6f, +0x63,0x52,0x65,0x71,0x00,0x00,0x00,0x00,0x4f,0x6e,0x52,0x65,0x41,0x73,0x73,0x6f, +0x63,0x52,0x73,0x70,0x00,0x00,0x00,0x00,0x4f,0x6e,0x50,0x72,0x6f,0x62,0x65,0x52, +0x65,0x71,0x00,0x00,0x4f,0x6e,0x50,0x72,0x6f,0x62,0x65,0x52,0x73,0x70,0x00,0x00, +0x44,0x6f,0x52,0x65,0x73,0x65,0x72,0x76,0x65,0x64,0x00,0x00,0x44,0x6f,0x52,0x65, +0x73,0x65,0x72,0x76,0x65,0x64,0x00,0x00,0x4f,0x6e,0x42,0x65,0x61,0x63,0x6f,0x6e, +0x00,0x00,0x00,0x00,0x4f,0x6e,0x41,0x54,0x49,0x4d,0x00,0x00,0x4f,0x6e,0x44,0x69, +0x73,0x61,0x73,0x73,0x6f,0x63,0x00,0x00,0x4f,0x6e,0x41,0x75,0x74,0x68,0x00,0x00, +0x4f,0x6e,0x44,0x65,0x41,0x75,0x74,0x68,0x00,0x00,0x00,0x00,0x4f,0x6e,0x41,0x63, +0x74,0x69,0x6f,0x6e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x88,0x8b,0x01,0x80, +0x28,0x14,0x01,0x80,0x10,0x00,0x00,0x00,0x94,0x8b,0x01,0x80,0x30,0x14,0x01,0x80, +0x20,0x00,0x00,0x00,0xa0,0x8b,0x01,0x80,0x28,0x14,0x01,0x80,0x30,0x00,0x00,0x00, +0xb0,0x8b,0x01,0x80,0x30,0x14,0x01,0x80,0x40,0x00,0x00,0x00,0xc0,0x8b,0x01,0x80, +0x38,0x14,0x01,0x80,0x50,0x00,0x00,0x00,0xcc,0x8b,0x01,0x80,0x40,0x14,0x01,0x80, +0x00,0x00,0x00,0x00,0xd8,0x8b,0x01,0x80,0xa8,0x14,0x01,0x80,0x00,0x00,0x00,0x00, +0xe4,0x8b,0x01,0x80,0xa8,0x14,0x01,0x80,0x80,0x00,0x00,0x00,0xf0,0x8b,0x01,0x80, +0x48,0x14,0x01,0x80,0x90,0x00,0x00,0x00,0xfc,0x8b,0x01,0x80,0x50,0x14,0x01,0x80, +0xa0,0x00,0x00,0x00,0x04,0x8c,0x01,0x80,0x58,0x14,0x01,0x80,0xb0,0x00,0x00,0x00, +0x10,0x8c,0x01,0x80,0x90,0x14,0x01,0x80,0xc0,0x00,0x00,0x00,0x18,0x8c,0x01,0x80, +0x98,0x14,0x01,0x80,0xd0,0x00,0x00,0x00,0x24,0x8c,0x01,0x80,0xa0,0x14,0x01,0x80, +0x00,0x00,0x00,0x00,0xdc,0x8c,0x01,0x80,0xdc,0x8c,0x01,0x80,0x31,0x10,0x10,0x00, +0x00,0x30,0x00,0x00,0x31,0x20,0x10,0x00,0x00,0x30,0x00,0x00,0x31,0x28,0x10,0x00, +0x00,0x30,0x00,0x00,0x31,0x2c,0x10,0x10,0x00,0x30,0x00,0x00,0x31,0x2f,0x10,0x10, +0x00,0x30,0x00,0x00,0x31,0x30,0x18,0x00,0x00,0x30,0x00,0x00,0x31,0x30,0x20,0x10, +0x00,0x30,0x00,0x00,0x22,0x20,0x18,0x08,0x00,0x20,0x00,0x00,0x22,0x21,0x14,0x08, +0x00,0x20,0x00,0x00,0x22,0x21,0x1c,0x08,0x00,0x20,0x00,0x00,0x22,0x21,0x20,0x08, +0x00,0x20,0x00,0x00,0x22,0x21,0x20,0x10,0x00,0x20,0x00,0x00,0x22,0x21,0x20,0x18, +0x00,0x20,0x00,0x00,0x1a,0x19,0x18,0x10,0x00,0x18,0x00,0x00,0x12,0x11,0x10,0x08, +0x00,0x10,0x00,0x00,0x0a,0x09,0x08,0x00,0x00,0x08,0x00,0x00,0x0a,0x09,0x08,0x02, +0x00,0x08,0x00,0x00,0x0a,0x09,0x08,0x04,0x00,0x08,0x00,0x00,0x0a,0x09,0x08,0x06, +0x00,0x08,0x00,0x00,0x08,0x07,0x06,0x04,0x00,0x06,0x00,0x00,0x06,0x05,0x04,0x02, +0x00,0x04,0x00,0x00,0x06,0x05,0x04,0x03,0x00,0x04,0x00,0x00,0x05,0x04,0x03,0x02, +0x00,0x03,0x00,0x00,0x09,0x08,0x07,0x06,0x07,0x06,0x06,0x05,0x05,0x04,0x04,0x03, +0x06,0x05,0x05,0x04,0x04,0x03,0x03,0x03,0x05,0x04,0x04,0x03,0x03,0x02,0x02,0x02, +0x00,0x09,0x08,0x07,0x06,0x07,0x06,0x06,0x05,0x05,0x04,0x04,0x03,0x05,0x04,0x04, +0x03,0x03,0x02,0x02,0x02,0x04,0x03,0x03,0x02,0x02,0x01,0x01,0x01,0x00,0x00,0x00, +0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x10,0x10,0x20,0x08,0x08,0x08,0x08, +0x20,0x20,0x20,0x20,0x08,0x08,0x08,0x08,0x08,0x20,0x20,0x20,0x30,0x08,0x08,0x08, +0x08,0x18,0x18,0x18,0x18,0x18,0x20,0x30,0x30,0x10,0x20,0x20,0x20,0x20,0x20,0x30, +0x30,0x08,0x10,0x20,0x30,0x30,0x30,0x30,0x30,0x30,0x00,0x00,0x08,0x08,0x08,0x08, +0x08,0x08,0x08,0x08,0x08,0x10,0x10,0x20,0x08,0x08,0x08,0x08,0x08,0x20,0x20,0x20, +0x08,0x08,0x08,0x08,0x08,0x20,0x20,0x20,0x20,0x08,0x08,0x08,0x08,0x18,0x18,0x18, +0x18,0x18,0x20,0x30,0x30,0x10,0x20,0x20,0x20,0x20,0x20,0x30,0x30,0x08,0x10,0x20, +0x30,0x30,0x30,0x30,0x30,0x30,0x00,0x00,0x0a,0x09,0x08,0x04,0x00,0x0a,0x09,0x08, +0x04,0x00,0x0a,0x09,0x08,0x04,0x00,0x0a,0x09,0x08,0x04,0x00,0x0a,0x09,0x08,0x00, +0x00,0x0a,0x09,0x08,0x00,0x00,0x0a,0x09,0x08,0x00,0x00,0x0a,0x09,0x08,0x00,0x00, +0x0a,0x09,0x08,0x00,0x00,0x12,0x11,0x10,0x08,0x00,0x12,0x11,0x10,0x08,0x00,0x22, +0x21,0x20,0x18,0x00,0x0a,0x09,0x08,0x00,0x00,0x0a,0x09,0x08,0x00,0x00,0x0a,0x09, +0x08,0x00,0x00,0x0a,0x09,0x08,0x00,0x00,0x22,0x21,0x20,0x18,0x00,0x22,0x21,0x20, +0x18,0x00,0x22,0x21,0x1c,0x08,0x00,0x22,0x20,0x18,0x08,0x00,0x0a,0x09,0x08,0x02, +0x00,0x0a,0x09,0x08,0x02,0x00,0x0a,0x09,0x08,0x02,0x00,0x0a,0x09,0x08,0x02,0x00, +0x0a,0x09,0x08,0x00,0x00,0x22,0x21,0x20,0x10,0x00,0x22,0x21,0x20,0x08,0x00,0x22, +0x21,0x1c,0x08,0x00,0x31,0x30,0x18,0x00,0x00,0x0a,0x09,0x08,0x04,0x00,0x0a,0x09, +0x08,0x04,0x00,0x0a,0x09,0x08,0x04,0x00,0x0a,0x09,0x08,0x04,0x00,0x1a,0x19,0x18, +0x10,0x00,0x1a,0x19,0x18,0x10,0x00,0x1a,0x19,0x18,0x10,0x00,0x1a,0x19,0x18,0x10, +0x00,0x1a,0x19,0x18,0x10,0x00,0x22,0x21,0x20,0x08,0x00,0x31,0x2c,0x10,0x10,0x00, +0x31,0x28,0x10,0x00,0x00,0x12,0x11,0x10,0x08,0x00,0x22,0x21,0x20,0x18,0x00,0x22, +0x21,0x20,0x18,0x00,0x22,0x21,0x20,0x08,0x00,0x22,0x21,0x14,0x08,0x00,0x22,0x20, +0x18,0x08,0x00,0x31,0x30,0x20,0x10,0x00,0x31,0x2c,0x10,0x10,0x00,0x0a,0x09,0x08, +0x00,0x00,0x12,0x11,0x10,0x08,0x00,0x22,0x21,0x20,0x18,0x00,0x22,0x21,0x20,0x18, +0x00,0x31,0x30,0x20,0x10,0x00,0x31,0x2f,0x10,0x10,0x00,0x31,0x2f,0x10,0x10,0x00, +0x31,0x10,0x10,0x00,0x00,0x31,0x2c,0x10,0x10,0x00,0x00,0x00,0x0a,0x09,0x08,0x04, +0x00,0x0a,0x09,0x08,0x04,0x00,0x0a,0x09,0x08,0x04,0x00,0x0a,0x09,0x08,0x04,0x00, +0x0a,0x09,0x08,0x00,0x00,0x0a,0x09,0x08,0x00,0x00,0x0a,0x09,0x08,0x00,0x00,0x0a, +0x09,0x08,0x00,0x00,0x0a,0x09,0x08,0x00,0x00,0x12,0x11,0x10,0x08,0x00,0x12,0x11, +0x10,0x08,0x00,0x22,0x21,0x20,0x18,0x00,0x0a,0x09,0x08,0x04,0x00,0x0a,0x09,0x08, +0x04,0x00,0x0a,0x09,0x08,0x02,0x00,0x0a,0x09,0x08,0x00,0x00,0x0a,0x09,0x08,0x00, +0x00,0x22,0x21,0x20,0x18,0x00,0x22,0x21,0x1c,0x08,0x00,0x22,0x21,0x14,0x08,0x00, +0x0a,0x09,0x08,0x02,0x00,0x0a,0x09,0x08,0x02,0x00,0x0a,0x09,0x08,0x02,0x00,0x0a, +0x09,0x08,0x02,0x00,0x0a,0x09,0x08,0x00,0x00,0x22,0x21,0x20,0x10,0x00,0x22,0x21, +0x20,0x08,0x00,0x22,0x21,0x14,0x08,0x00,0x22,0x21,0x14,0x08,0x00,0x0a,0x09,0x08, +0x04,0x00,0x0a,0x09,0x08,0x04,0x00,0x0a,0x09,0x08,0x04,0x00,0x0a,0x09,0x08,0x04, +0x00,0x1a,0x19,0x18,0x10,0x00,0x1a,0x19,0x18,0x10,0x00,0x1a,0x19,0x18,0x10,0x00, +0x1a,0x19,0x18,0x10,0x00,0x1a,0x19,0x18,0x10,0x00,0x22,0x21,0x20,0x08,0x00,0x31, +0x2c,0x10,0x10,0x00,0x31,0x28,0x10,0x00,0x00,0x12,0x11,0x10,0x08,0x00,0x22,0x21, +0x20,0x18,0x00,0x22,0x21,0x20,0x18,0x00,0x22,0x21,0x20,0x08,0x00,0x22,0x21,0x14, +0x08,0x00,0x22,0x20,0x18,0x08,0x00,0x31,0x30,0x20,0x10,0x00,0x31,0x2c,0x10,0x10, +0x00,0x0a,0x09,0x08,0x00,0x00,0x12,0x11,0x10,0x08,0x00,0x22,0x21,0x20,0x18,0x00, +0x22,0x21,0x20,0x18,0x00,0x31,0x30,0x20,0x10,0x00,0x31,0x2f,0x10,0x10,0x00,0x31, +0x2f,0x10,0x10,0x00,0x31,0x10,0x10,0x00,0x00,0x31,0x2c,0x10,0x10,0x00,0x00,0x00, +0x01,0x02,0x04,0x08,0x02,0x04,0x08,0x0c,0x10,0x18,0x20,0x30,0x02,0x04,0x08,0x0c, +0x10,0x18,0x20,0x30,0x06,0x0c,0x10,0x18,0x24,0x30,0x3c,0x48,0x48,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x25,0x27,0x2c,0x19,0x1b,0x1e,0x20, +0x23,0x29,0x2a,0x2b,0x00,0x00,0x00,0x00,0x25,0x29,0x2b,0x2e,0x2e,0x00,0x00,0x00, +0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x10,0x00,0x00,0x00, +0x18,0x00,0x00,0x00,0x24,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x48,0x00,0x00,0x00, +0x60,0x00,0x00,0x00,0x90,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0xd8,0x00,0x00,0x00, +0x50,0x00,0x00,0x00,0x78,0x00,0x00,0x00,0xa0,0x00,0x00,0x00,0xc8,0x00,0x00,0x00, +0x40,0x01,0x00,0x00,0x90,0x01,0x00,0x00,0xe0,0x01,0x00,0x00,0x30,0x02,0x00,0x00, +0x2c,0x01,0x00,0x00,0x40,0x01,0x00,0x00,0xe0,0x01,0x00,0x00,0xd0,0x02,0x00,0x00, +0x80,0x0c,0x00,0x00,0x80,0x0c,0x00,0x00,0x80,0x0c,0x00,0x00,0xa0,0x0f,0x00,0x00, +0xa0,0x0f,0x00,0x00,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x04,0x00,0x00,0x00, +0x08,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x18,0x00,0x00,0x00, +0x24,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x48,0x00,0x00,0x00,0x60,0x00,0x00,0x00, +0x6c,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x3c,0x00,0x00,0x00,0x50,0x00,0x00,0x00, +0x64,0x00,0x00,0x00,0xa0,0x00,0x00,0x00,0xc8,0x00,0x00,0x00,0xf0,0x00,0x00,0x00, +0x18,0x01,0x00,0x00,0x64,0x00,0x00,0x00,0xa0,0x00,0x00,0x00,0xf0,0x00,0x00,0x00, +0x68,0x01,0x00,0x00,0x40,0x06,0x00,0x00,0x40,0x06,0x00,0x00,0x40,0x06,0x00,0x00, +0xd0,0x07,0x00,0x00,0xd0,0x07,0x00,0x00,0x2c,0x05,0x00,0x80,0x20,0x05,0x00,0x80, +0x14,0x05,0x00,0x80,0x08,0x05,0x00,0x80,0xfc,0x04,0x00,0x80,0xf0,0x04,0x00,0x80, +0xe4,0x04,0x00,0x80,0xd8,0x04,0x00,0x80,0xcc,0x04,0x00,0x80,0xc0,0x04,0x00,0x80, +0x78,0x04,0x00,0x80,0x68,0x15,0x02,0x80,0xc0,0x3a,0x00,0x80,0xcc,0x3a,0x00,0x80, +0xd8,0x3a,0x00,0x80,0xe4,0x3a,0x00,0x80,0xc0,0x3a,0x00,0x80,0xc0,0x3a,0x00,0x80, +0xc0,0x3a,0x00,0x80,0xc0,0x3a,0x00,0x80,0xf0,0x3a,0x00,0x80,0xfc,0x3a,0x00,0x80, +0x08,0x3b,0x00,0x80,0x14,0x3b,0x00,0x80,0x68,0x15,0x02,0x80,0xfe,0x01,0x80,0x7f, +0xe2,0x01,0x80,0x78,0xc7,0x01,0xc0,0x71,0xae,0x01,0x80,0x6b,0x95,0x01,0x40,0x65, +0x7f,0x01,0xc0,0x5f,0x69,0x01,0x40,0x5a,0x55,0x01,0x40,0x55,0x42,0x01,0x80,0x50, +0x30,0x01,0x00,0x4c,0x1f,0x01,0xc0,0x47,0x0f,0x01,0xc0,0x43,0x00,0x01,0x00,0x40, +0xf2,0x00,0x80,0x3c,0xe4,0x00,0x00,0x39,0xd7,0x00,0xc0,0x35,0xcb,0x00,0xc0,0x32, +0xc0,0x00,0x00,0x30,0xb5,0x00,0x40,0x2d,0xab,0x00,0xc0,0x2a,0xa2,0x00,0x80,0x28, +0x98,0x00,0x00,0x26,0x90,0x00,0x00,0x24,0x88,0x00,0x00,0x22,0x80,0x00,0x00,0x20, +0x79,0x00,0x40,0x1e,0x72,0x00,0x80,0x1c,0x6c,0x00,0x00,0x1b,0x66,0x00,0x80,0x19, +0x60,0x00,0x00,0x18,0x5b,0x00,0xc0,0x16,0x56,0x00,0x80,0x15,0x51,0x00,0x40,0x14, +0x4c,0x00,0x00,0x13,0x48,0x00,0x00,0x12,0x44,0x00,0x00,0x11,0x40,0x00,0x00,0x10, +0x36,0x35,0x2e,0x25,0x1c,0x12,0x09,0x04,0x33,0x32,0x2b,0x23,0x1a,0x11,0x08,0x04, +0x30,0x2f,0x29,0x21,0x19,0x10,0x08,0x03,0x2d,0x2d,0x27,0x1f,0x18,0x0f,0x08,0x03, +0x2b,0x2a,0x25,0x1e,0x16,0x0e,0x07,0x03,0x28,0x28,0x22,0x1c,0x15,0x0d,0x07,0x03, +0x26,0x25,0x21,0x1b,0x14,0x0d,0x06,0x03,0x24,0x23,0x1f,0x19,0x13,0x0c,0x06,0x03, +0x22,0x21,0x1d,0x18,0x11,0x0b,0x06,0x02,0x20,0x20,0x1b,0x16,0x11,0x08,0x05,0x02, +0x1f,0x1e,0x1a,0x15,0x10,0x0a,0x05,0x02,0x1d,0x1c,0x18,0x14,0x0f,0x0a,0x05,0x02, +0x1b,0x1a,0x17,0x13,0x0e,0x09,0x04,0x02,0x1a,0x19,0x16,0x12,0x0d,0x09,0x04,0x02, +0x18,0x17,0x15,0x11,0x0c,0x08,0x04,0x02,0x17,0x16,0x13,0x10,0x0c,0x08,0x04,0x02, +0x16,0x15,0x12,0x0f,0x0b,0x07,0x04,0x01,0x14,0x14,0x11,0x0e,0x0b,0x07,0x03,0x02, +0x13,0x13,0x10,0x0d,0x0a,0x06,0x03,0x01,0x12,0x12,0x0f,0x0c,0x09,0x06,0x03,0x01, +0x11,0x11,0x0f,0x0c,0x09,0x06,0x03,0x01,0x10,0x10,0x0e,0x0b,0x08,0x05,0x03,0x01, +0x0f,0x0f,0x0d,0x0b,0x08,0x05,0x03,0x01,0x0e,0x0e,0x0c,0x0a,0x08,0x05,0x02,0x01, +0x0d,0x0d,0x0c,0x0a,0x07,0x05,0x02,0x01,0x0d,0x0c,0x0b,0x09,0x07,0x04,0x02,0x01, +0x0c,0x0c,0x0a,0x09,0x06,0x04,0x02,0x01,0x0b,0x0b,0x0a,0x08,0x06,0x04,0x02,0x01, +0x0b,0x0a,0x09,0x08,0x06,0x04,0x02,0x01,0x0a,0x0a,0x09,0x07,0x05,0x03,0x02,0x01, +0x0a,0x09,0x08,0x07,0x05,0x03,0x02,0x01,0x09,0x09,0x08,0x06,0x05,0x03,0x01,0x01, +0x09,0x08,0x07,0x06,0x04,0x03,0x01,0x01,0x36,0x35,0x2e,0x1b,0x00,0x00,0x00,0x00, +0x33,0x32,0x2b,0x19,0x00,0x00,0x00,0x00,0x30,0x2f,0x29,0x18,0x00,0x00,0x00,0x00, +0x2d,0x2d,0x17,0x17,0x00,0x00,0x00,0x00,0x2b,0x2a,0x25,0x15,0x00,0x00,0x00,0x00, +0x28,0x28,0x24,0x14,0x00,0x00,0x00,0x00,0x26,0x25,0x21,0x13,0x00,0x00,0x00,0x00, +0x24,0x23,0x1f,0x12,0x00,0x00,0x00,0x00,0x22,0x21,0x1d,0x11,0x00,0x00,0x00,0x00, +0x20,0x20,0x1b,0x10,0x00,0x00,0x00,0x00,0x1f,0x1e,0x1a,0x0f,0x00,0x00,0x00,0x00, +0x1d,0x1c,0x18,0x0e,0x00,0x00,0x00,0x00,0x1b,0x1a,0x17,0x0e,0x00,0x00,0x00,0x00, +0x1a,0x19,0x16,0x0d,0x00,0x00,0x00,0x00,0x18,0x17,0x15,0x0c,0x00,0x00,0x00,0x00, +0x17,0x16,0x13,0x0b,0x00,0x00,0x00,0x00,0x16,0x15,0x12,0x0b,0x00,0x00,0x00,0x00, +0x14,0x14,0x11,0x0a,0x00,0x00,0x00,0x00,0x13,0x13,0x10,0x0a,0x00,0x00,0x00,0x00, +0x12,0x12,0x0f,0x09,0x00,0x00,0x00,0x00,0x11,0x11,0x0f,0x09,0x00,0x00,0x00,0x00, +0x10,0x10,0x0e,0x08,0x00,0x00,0x00,0x00,0x0f,0x0f,0x0d,0x08,0x00,0x00,0x00,0x00, +0x0e,0x0e,0x0c,0x07,0x00,0x00,0x00,0x00,0x0d,0x0d,0x0c,0x07,0x00,0x00,0x00,0x00, +0x0d,0x0c,0x0b,0x06,0x00,0x00,0x00,0x00,0x0c,0x0c,0x0a,0x06,0x00,0x00,0x00,0x00, +0x0b,0x0b,0x0a,0x06,0x00,0x00,0x00,0x00,0x0b,0x0a,0x09,0x05,0x00,0x00,0x00,0x00, +0x0a,0x0a,0x09,0x05,0x00,0x00,0x00,0x00,0x0a,0x09,0x08,0x05,0x00,0x00,0x00,0x00, +0x09,0x09,0x08,0x05,0x00,0x00,0x00,0x00,0x09,0x08,0x07,0x04,0x00,0x00,0x00,0x00, +0x06,0x00,0x2a,0xb0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08, +0x08,0x28,0x28,0x28,0x28,0x28,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08, +0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0xa0,0x10,0x10,0x10,0x10,0x10,0x10,0x10, +0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x41,0x41,0x41,0x41,0x41,0x41,0x01, +0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, +0x01,0x01,0x01,0x10,0x10,0x10,0x10,0x10,0x10,0x42,0x42,0x42,0x42,0x42,0x42,0x02, +0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, +0x02,0x02,0x02,0x10,0x10,0x10,0x10,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x10,0x10,0x10,0x10,0x10,0x10,0x10, +0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, +0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, +0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x10, +0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, +0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x10, +0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x00,0x19,0x77,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x26,0x72,0xb0,0x00,0x26,0x72,0xb0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x26,0x65,0x60,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x02, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0xf2,0x30,0xb8,0xff,0xff,0xff,0xff, +}; + +u8 Rtl8192SUFwMainArray[MainArrayLength] = { +0x0, }; + +u8 Rtl8192SUFwDataArray[DataArrayLength] = { +0x0, }; + +u32 Rtl8192SUPHY_REG_2T2RArray[PHY_REG_2T2RArrayLength] = { +0x01c,0x07000000, +0x800,0x00040000, +0x804,0x00008003, +0x808,0x0000fc00, +0x80c,0x0000000a, +0x810,0x10005088, +0x814,0x020c3d10, +0x818,0x00200185, +0x81c,0x00000000, +0x820,0x01000000, +0x824,0x00390004, +0x828,0x01000000, +0x82c,0x00390004, +0x830,0x00000004, +0x834,0x00690200, +0x838,0x00000004, +0x83c,0x00690200, +0x840,0x00010000, +0x844,0x00010000, +0x848,0x00000000, +0x84c,0x00000000, +0x850,0x00000000, +0x854,0x00000000, +0x858,0x48484848, +0x85c,0x65a965a9, +0x860,0x0f7f0130, +0x864,0x0f7f0130, +0x868,0x0f7f0130, +0x86c,0x0f7f0130, +0x870,0x03000700, +0x874,0x03000300, +0x878,0x00020002, +0x87c,0x004f0201, +0x880,0xa8300ac1, +0x884,0x00000058, +0x888,0x00000008, +0x88c,0x00000004, +0x890,0x00000000, +0x894,0xfffffffe, +0x898,0x40302010, +0x89c,0x00706050, +0x8b0,0x00000000, +0x8e0,0x00000000, +0x8e4,0x00000000, +0xe00,0x30333333, +0xe04,0x2a2d2e2f, +0xe08,0x00003232, +0xe10,0x30333333, +0xe14,0x2a2d2e2f, +0xe18,0x30333333, +0xe1c,0x2a2d2e2f, +0xe30,0x01007c00, +0xe34,0x01004800, +0xe38,0x1000dc1f, +0xe3c,0x10008c1f, +0xe40,0x021400a0, +0xe44,0x281600a0, +0xe48,0xf8000001, +0xe4c,0x00002910, +0xe50,0x01007c00, +0xe54,0x01004800, +0xe58,0x1000dc1f, +0xe5c,0x10008c1f, +0xe60,0x021400a0, +0xe64,0x281600a0, +0xe6c,0x00002910, +0xe70,0x31ed92fb, +0xe74,0x361536fb, +0xe78,0x361536fb, +0xe7c,0x361536fb, +0xe80,0x361536fb, +0xe84,0x000d92fb, +0xe88,0x000d92fb, +0xe8c,0x31ed92fb, +0xed0,0x31ed92fb, +0xed4,0x31ed92fb, +0xed8,0x000d92fb, +0xedc,0x000d92fb, +0xee0,0x000d92fb, +0xee4,0x015e5448, +0xee8,0x21555448, +0x900,0x00000000, +0x904,0x00000023, +0x908,0x00000000, +0x90c,0x03321333, +0xa00,0x00d047c8, +0xa04,0x80ff0008, +0xa08,0x8ccd8300, +0xa0c,0x2e62120f, +0xa10,0x9500bb78, +0xa14,0x11144028, +0xa18,0x00881117, +0xa1c,0x89140f00, +0xa20,0x1a1b0000, +0xa24,0x090e1317, +0xa28,0x00000204, +0xa2c,0x10d30000, +0xc00,0x40071d40, +0xc04,0x00a05633, +0xc08,0x000000e4, +0xc0c,0x6c6c6c6c, +0xc10,0x08800000, +0xc14,0x40000100, +0xc18,0x08000000, +0xc1c,0x40000100, +0xc20,0x08000000, +0xc24,0x40000100, +0xc28,0x08000000, +0xc2c,0x40000100, +0xc30,0x6de9ac44, +0xc34,0x469652cf, +0xc38,0x49795994, +0xc3c,0x0a979764, +0xc40,0x1f7c403f, +0xc44,0x000100b7, +0xc48,0xec020000, +0xc4c,0x007f037f, +0xc50,0x69543420, +0xc54,0x433c0094, +0xc58,0x69543420, +0xc5c,0x433c0094, +0xc60,0x69543420, +0xc64,0x433c0094, +0xc68,0x69543420, +0xc6c,0x433c0094, +0xc70,0x2c7f000d, +0xc74,0x0186155b, +0xc78,0x0000001f, +0xc7c,0x00b91612, +0xc80,0x40000100, +0xc84,0x20f60000, +0xc88,0x20000080, +0xc8c,0x20200000, +0xc90,0x40000100, +0xc94,0x00000000, +0xc98,0x40000100, +0xc9c,0x00000000, +0xca0,0x00492492, +0xca4,0x00000000, +0xca8,0x00000000, +0xcac,0x00000000, +0xcb0,0x00000000, +0xcb4,0x00000000, +0xcb8,0x00000000, +0xcbc,0x28000000, +0xcc0,0x00000000, +0xcc4,0x00000000, +0xcc8,0x00000000, +0xccc,0x00000000, +0xcd0,0x00000000, +0xcd4,0x00000000, +0xcd8,0x64b22427, +0xcdc,0x00766932, +0xce0,0x00222222, +0xce4,0x00000000, +0xce8,0x37644302, +0xcec,0x2f97d40c, +0xd00,0x00000750, +0xd04,0x00000403, +0xd08,0x0000907f, +0xd0c,0x00000001, +0xd10,0xa0633333, +0xd14,0x33333c63, +0xd18,0x6a8f5b6b, +0xd1c,0x00000000, +0xd20,0x00000000, +0xd24,0x00000000, +0xd28,0x00000000, +0xd2c,0xcc979975, +0xd30,0x00000000, +0xd34,0x00000000, +0xd38,0x00000000, +0xd3c,0x00027293, +0xd40,0x00000000, +0xd44,0x00000000, +0xd48,0x00000000, +0xd50,0x6437140a, +0xd54,0x024dbd02, +0xd58,0x00000000, +0xd5c,0x30032064, +0xd60,0x4653de68, +0xd64,0x00518a3c, +0xd68,0x00002101, +0xf14,0x00000003, +0xf4c,0x00000000, +0xf00,0x00000300, +}; + +u32 Rtl8192SUPHY_REG_1T2RArray[PHY_REG_1T2RArrayLength] = { +0x0, }; + +u32 Rtl8192SUPHY_ChangeTo_1T1RArray[PHY_ChangeTo_1T1RArrayLength] = { +0x844,0xffffffff,0x00010000, +0x804,0x0000000f,0x00000001, +0x824,0x00f0000f,0x00300004, +0x82c,0x00f0000f,0x00100002, +0x870,0x04000000,0x00000001, +0x864,0x00000400,0x00000000, +0x878,0x000f000f,0x00000002, +0xe74,0x0f000000,0x00000002, +0xe78,0x0f000000,0x00000002, +0xe7c,0x0f000000,0x00000002, +0xe80,0x0f000000,0x00000002, +0x90c,0x000000ff,0x00000011, +0xc04,0x000000ff,0x00000011, +0xd04,0x0000000f,0x00000001, +0x1f4,0xffff0000,0x00007777, +0x234,0xf8000000,0x0000000a, +}; + +u32 Rtl8192SUPHY_ChangeTo_1T2RArray[PHY_ChangeTo_1T2RArrayLength] = { +0x804,0x0000000f,0x00000003, +0x824,0x00f0000f,0x00300004, +0x82c,0x00f0000f,0x00300002, +0x870,0x04000000,0x00000001, +0x864,0x00000400,0x00000000, +0x878,0x000f000f,0x00000002, +0xe74,0x0f000000,0x00000002, +0xe78,0x0f000000,0x00000002, +0xe7c,0x0f000000,0x00000002, +0xe80,0x0f000000,0x00000002, +0x90c,0x000000ff,0x00000011, +0xc04,0x000000ff,0x00000033, +0xd04,0x0000000f,0x00000003, +0x1f4,0xffff0000,0x00007777, +0x234,0xf8000000,0x0000000a, +}; + +u32 Rtl8192SUPHY_ChangeTo_2T2RArray[PHY_ChangeTo_2T2RArrayLength] = { +0x804,0x0000000f,0x00000003, +0x824,0x00f0000f,0x00300004, +0x82c,0x00f0000f,0x00300004, +0x870,0x04000000,0x00000001, +0x864,0x00000400,0x00000001, +0x878,0x000f000f,0x00020002, +0xe74,0x0f000000,0x00000006, +0xe78,0x0f000000,0x00000006, +0xe7c,0x0f000000,0x00000006, +0xe80,0x0f000000,0x00000006, +0x90c,0x000000ff,0x00000033, +0xc04,0x000000ff,0x00000033, +0xd04,0x0000000f,0x00000003, +0x1f4,0xffff0000,0x0000ffff, +0x234,0xf8000000,0x00000013, +}; + +u32 Rtl8192SUPHY_REG_Array_PG[PHY_REG_Array_PGLength] = { +0xe00,0xffffffff,0x06090909, +0xe04,0xffffffff,0x00030406, +0xe08,0x0000ff00,0x00000000, +0xe10,0xffffffff,0x0a0c0d0e, +0xe14,0xffffffff,0x04070809, +0xe18,0xffffffff,0x0a0c0d0e, +0xe1c,0xffffffff,0x04070809, +}; + +u32 Rtl8192SURadioA_1T_Array[RadioA_1T_ArrayLength] = { +0x000,0x00030159, +0x001,0x00030250, +0x002,0x00010000, +0x010,0x0008000f, +0x011,0x000231fc, +0x010,0x000c000f, +0x011,0x0003f9f8, +0x010,0x0002000f, +0x011,0x00020101, +0x014,0x0001093e, +0x014,0x0009093e, +0x015,0x000198f4, +0x017,0x000f6500, +0x01a,0x00013056, +0x01b,0x00060000, +0x01c,0x00000300, +0x01e,0x00031059, +0x021,0x00054000, +0x022,0x0000083c, +0x023,0x00001558, +0x024,0x00000060, +0x025,0x00022583, +0x026,0x0000f200, +0x027,0x000eacf1, +0x028,0x0009bd54, +0x029,0x00004582, +0x02a,0x00000001, +0x02b,0x00021334, +0x02a,0x00000000, +0x02b,0x0000000a, +0x02a,0x00000001, +0x02b,0x00000808, +0x02b,0x00053333, +0x02c,0x0000000c, +0x02a,0x00000002, +0x02b,0x00000808, +0x02b,0x0005b333, +0x02c,0x0000000d, +0x02a,0x00000003, +0x02b,0x00000808, +0x02b,0x00063333, +0x02c,0x0000000d, +0x02a,0x00000004, +0x02b,0x00000808, +0x02b,0x0006b333, +0x02c,0x0000000d, +0x02a,0x00000005, +0x02b,0x00000709, +0x02b,0x00053333, +0x02c,0x0000000d, +0x02a,0x00000006, +0x02b,0x00000709, +0x02b,0x0005b333, +0x02c,0x0000000d, +0x02a,0x00000007, +0x02b,0x00000709, +0x02b,0x00063333, +0x02c,0x0000000d, +0x02a,0x00000008, +0x02b,0x00000709, +0x02b,0x0006b333, +0x02c,0x0000000d, +0x02a,0x00000009, +0x02b,0x0000060a, +0x02b,0x00053333, +0x02c,0x0000000d, +0x02a,0x0000000a, +0x02b,0x0000060a, +0x02b,0x0005b333, +0x02c,0x0000000d, +0x02a,0x0000000b, +0x02b,0x0000060a, +0x02b,0x00063333, +0x02c,0x0000000d, +0x02a,0x0000000c, +0x02b,0x0000060a, +0x02b,0x0006b333, +0x02c,0x0000000d, +0x02a,0x0000000d, +0x02b,0x0000050b, +0x02b,0x00053333, +0x02c,0x0000000d, +0x02a,0x0000000e, +0x02b,0x0000050b, +0x02b,0x00066623, +0x02c,0x0000001a, +0x02a,0x000e4000, +0x030,0x00020000, +0x031,0x000b9631, +0x032,0x0000130d, +0x033,0x00000187, +0x013,0x00019e6c, +0x013,0x00015e94, +0x000,0x00010159, +0x018,0x0000f401, +0x0fe,0x00000000, +0x01e,0x0003105b, +0x0fe,0x00000000, +0x000,0x00030159, +0x010,0x0004000f, +0x011,0x000203f9, +}; + +u32 Rtl8192SURadioB_Array[RadioB_ArrayLength] = { +0x000,0x00030159, +0x001,0x00001041, +0x002,0x00011000, +0x005,0x00080fc0, +0x007,0x000fc803, +0x013,0x00017cb0, +0x013,0x00011cc0, +0x013,0x0000dc60, +0x013,0x00008c60, +0x013,0x00004450, +0x013,0x00000020, +}; + +u32 Rtl8192SURadioA_to1T_Array[RadioA_to1T_ArrayLength] = { +0x000,0x00000000, +}; + +u32 Rtl8192SURadioA_to2T_Array[RadioA_to2T_ArrayLength] = { +0x000,0x00000000, +}; + +u32 Rtl8192SURadioB_GM_Array[RadioB_GM_ArrayLength] = { +0x000,0x00030159, +0x001,0x00001041, +0x002,0x00011000, +0x005,0x00080fc0, +0x007,0x000fc803, +0x013,0x0000bef0, +0x013,0x00007e90, +0x013,0x00003e30, +}; + +u32 Rtl8192SUMAC_2T_Array[MAC_2T_ArrayLength] = { +0x020,0x00000035, +0x048,0x0000000e, +0x049,0x000000f0, +0x04a,0x00000077, +0x04b,0x00000083, +0x0b5,0x00000021, +0x0dc,0x000000ff, +0x0dd,0x000000ff, +0x0de,0x000000ff, +0x0df,0x000000ff, +0x116,0x00000000, +0x117,0x00000000, +0x118,0x00000000, +0x119,0x00000000, +0x11a,0x00000000, +0x11b,0x00000000, +0x11c,0x00000000, +0x11d,0x00000000, +0x160,0x0000000b, +0x161,0x0000000b, +0x162,0x0000000b, +0x163,0x0000000b, +0x164,0x0000000b, +0x165,0x0000000b, +0x166,0x0000000b, +0x167,0x0000000b, +0x168,0x0000000b, +0x169,0x0000000b, +0x16a,0x0000000b, +0x16b,0x0000000b, +0x16c,0x0000000b, +0x16d,0x0000000b, +0x16e,0x0000000b, +0x16f,0x0000000b, +0x170,0x0000000b, +0x171,0x0000000b, +0x172,0x0000000b, +0x173,0x0000000b, +0x174,0x0000000b, +0x175,0x0000000b, +0x176,0x0000000b, +0x177,0x0000000b, +0x178,0x0000000b, +0x179,0x0000000b, +0x17a,0x0000000b, +0x17b,0x0000000b, +0x17c,0x0000000b, +0x17d,0x0000000b, +0x17e,0x0000000b, +0x17f,0x0000000b, +0x236,0x0000000c, +0x503,0x00000022, +0x560,0x00000009, +}; + +u32 Rtl8192SUMACPHY_Array_PG[MACPHY_Array_PGLength] = { +0x0, }; + +u32 Rtl8192SUAGCTAB_Array[AGCTAB_ArrayLength] = { +0xc78,0x7f000001, +0xc78,0x7f010001, +0xc78,0x7e020001, +0xc78,0x7d030001, +0xc78,0x7c040001, +0xc78,0x7b050001, +0xc78,0x7a060001, +0xc78,0x79070001, +0xc78,0x78080001, +0xc78,0x77090001, +0xc78,0x760a0001, +0xc78,0x750b0001, +0xc78,0x740c0001, +0xc78,0x730d0001, +0xc78,0x720e0001, +0xc78,0x710f0001, +0xc78,0x70100001, +0xc78,0x6f110001, +0xc78,0x6f120001, +0xc78,0x6e130001, +0xc78,0x6d140001, +0xc78,0x6d150001, +0xc78,0x6c160001, +0xc78,0x6b170001, +0xc78,0x6a180001, +0xc78,0x6a190001, +0xc78,0x691a0001, +0xc78,0x681b0001, +0xc78,0x671c0001, +0xc78,0x661d0001, +0xc78,0x651e0001, +0xc78,0x641f0001, +0xc78,0x63200001, +0xc78,0x4c210001, +0xc78,0x4b220001, +0xc78,0x4a230001, +0xc78,0x49240001, +0xc78,0x48250001, +0xc78,0x47260001, +0xc78,0x46270001, +0xc78,0x45280001, +0xc78,0x44290001, +0xc78,0x2c2a0001, +0xc78,0x2b2b0001, +0xc78,0x2a2c0001, +0xc78,0x292d0001, +0xc78,0x282e0001, +0xc78,0x272f0001, +0xc78,0x26300001, +0xc78,0x25310001, +0xc78,0x24320001, +0xc78,0x23330001, +0xc78,0x22340001, +0xc78,0x09350001, +0xc78,0x08360001, +0xc78,0x07370001, +0xc78,0x06380001, +0xc78,0x05390001, +0xc78,0x043a0001, +0xc78,0x033b0001, +0xc78,0x023c0001, +0xc78,0x013d0001, +0xc78,0x003e0001, +0xc78,0x003f0001, +0xc78,0x7f400001, +0xc78,0x7f410001, +0xc78,0x7e420001, +0xc78,0x7d430001, +0xc78,0x7c440001, +0xc78,0x7b450001, +0xc78,0x7a460001, +0xc78,0x79470001, +0xc78,0x78480001, +0xc78,0x77490001, +0xc78,0x764a0001, +0xc78,0x754b0001, +0xc78,0x744c0001, +0xc78,0x734d0001, +0xc78,0x724e0001, +0xc78,0x714f0001, +0xc78,0x70500001, +0xc78,0x6f510001, +0xc78,0x6f520001, +0xc78,0x6e530001, +0xc78,0x6d540001, +0xc78,0x6d550001, +0xc78,0x6c560001, +0xc78,0x6b570001, +0xc78,0x6a580001, +0xc78,0x6a590001, +0xc78,0x695a0001, +0xc78,0x685b0001, +0xc78,0x675c0001, +0xc78,0x665d0001, +0xc78,0x655e0001, +0xc78,0x645f0001, +0xc78,0x63600001, +0xc78,0x4c610001, +0xc78,0x4b620001, +0xc78,0x4a630001, +0xc78,0x49640001, +0xc78,0x48650001, +0xc78,0x47660001, +0xc78,0x46670001, +0xc78,0x45680001, +0xc78,0x44690001, +0xc78,0x2c6a0001, +0xc78,0x2b6b0001, +0xc78,0x2a6c0001, +0xc78,0x296d0001, +0xc78,0x286e0001, +0xc78,0x276f0001, +0xc78,0x26700001, +0xc78,0x25710001, +0xc78,0x24720001, +0xc78,0x23730001, +0xc78,0x22740001, +0xc78,0x09750001, +0xc78,0x08760001, +0xc78,0x07770001, +0xc78,0x06780001, +0xc78,0x05790001, +0xc78,0x047a0001, +0xc78,0x037b0001, +0xc78,0x027c0001, +0xc78,0x017d0001, +0xc78,0x007e0001, +0xc78,0x007f0001, +0xc78,0x3000001e, +0xc78,0x3001001e, +0xc78,0x3002001e, +0xc78,0x3003001e, +0xc78,0x3004001e, +0xc78,0x3405001e, +0xc78,0x3806001e, +0xc78,0x3e07001e, +0xc78,0x3e08001e, +0xc78,0x4409001e, +0xc78,0x460a001e, +0xc78,0x480b001e, +0xc78,0x480c001e, +0xc78,0x4e0d001e, +0xc78,0x560e001e, +0xc78,0x5a0f001e, +0xc78,0x5e10001e, +0xc78,0x6211001e, +0xc78,0x6c12001e, +0xc78,0x7213001e, +0xc78,0x7214001e, +0xc78,0x7215001e, +0xc78,0x7216001e, +0xc78,0x7217001e, +0xc78,0x7218001e, +0xc78,0x7219001e, +0xc78,0x721a001e, +0xc78,0x721b001e, +0xc78,0x721c001e, +0xc78,0x721d001e, +0xc78,0x721e001e, +0xc78,0x721f001e, +}; + diff --git a/drivers/staging/rtl8192su/r8192SU_HWImg.h b/drivers/staging/rtl8192su/r8192SU_HWImg.h new file mode 100644 index 000000000000..96b15252ea86 --- /dev/null +++ b/drivers/staging/rtl8192su/r8192SU_HWImg.h @@ -0,0 +1,44 @@ +#ifndef __INC_HAL8192SU_FW_IMG_H +#define __INC_HAL8192SU_FW_IMG_H + +#include + +/*Created on 2009/ 3/ 6, 5:29*/ + +#define ImgArrayLength 68368 +extern u8 Rtl8192SUFwImgArray[ImgArrayLength]; +#define MainArrayLength 1 +extern u8 Rtl8192SUFwMainArray[MainArrayLength]; +#define DataArrayLength 1 +extern u8 Rtl8192SUFwDataArray[DataArrayLength]; +#define PHY_REG_2T2RArrayLength 372 +extern u32 Rtl8192SUPHY_REG_2T2RArray[PHY_REG_2T2RArrayLength]; +#define PHY_REG_1T2RArrayLength 1 +extern u32 Rtl8192SUPHY_REG_1T2RArray[PHY_REG_1T2RArrayLength]; +#define PHY_ChangeTo_1T1RArrayLength 48 +extern u32 Rtl8192SUPHY_ChangeTo_1T1RArray[PHY_ChangeTo_1T1RArrayLength]; +#define PHY_ChangeTo_1T2RArrayLength 45 +extern u32 Rtl8192SUPHY_ChangeTo_1T2RArray[PHY_ChangeTo_1T2RArrayLength]; +#define PHY_ChangeTo_2T2RArrayLength 45 +extern u32 Rtl8192SUPHY_ChangeTo_2T2RArray[PHY_ChangeTo_2T2RArrayLength]; +#define PHY_REG_Array_PGLength 21 +extern u32 Rtl8192SUPHY_REG_Array_PG[PHY_REG_Array_PGLength]; +#define RadioA_1T_ArrayLength 202 +extern u32 Rtl8192SURadioA_1T_Array[RadioA_1T_ArrayLength]; +#define RadioB_ArrayLength 22 +extern u32 Rtl8192SURadioB_Array[RadioB_ArrayLength]; +#define RadioA_to1T_ArrayLength 2 +extern u32 Rtl8192SURadioA_to1T_Array[RadioA_to1T_ArrayLength]; +#define RadioA_to2T_ArrayLength 2 +extern u32 Rtl8192SURadioA_to2T_Array[RadioA_to2T_ArrayLength]; +#define RadioB_GM_ArrayLength 16 +extern u32 Rtl8192SURadioB_GM_Array[RadioB_GM_ArrayLength]; +#define MAC_2T_ArrayLength 106 +extern u32 Rtl8192SUMAC_2T_Array[MAC_2T_ArrayLength]; +#define MACPHY_Array_PGLength 1 +extern u32 Rtl8192SUMACPHY_Array_PG[MACPHY_Array_PGLength]; +#define AGCTAB_ArrayLength 320 +extern u32 Rtl8192SUAGCTAB_Array[AGCTAB_ArrayLength]; + +#endif //__INC_HAL8192SU_FW_IMG_H + diff --git a/drivers/staging/rtl8192su/r8192S_Efuse.c b/drivers/staging/rtl8192su/r8192S_Efuse.c new file mode 100644 index 000000000000..394ab9674359 --- /dev/null +++ b/drivers/staging/rtl8192su/r8192S_Efuse.c @@ -0,0 +1,2442 @@ +/****************************************************************************** + * + * (c) Copyright 2008, RealTEK Technologies Inc. All Rights Reserved. + * + * Module: Efuse.c ( Source C File) + * + * Note: Copy from WMAC for the first version!!!! + * + * + * Function: + * + * Export: + * + * Abbrev: + * + * History: + * Data Who Remark + * + * 09/23/2008 MHC Porting Efuse R/W API from WMAC. + * 11/10/2008 MHC 1. Porting from 8712 EFUSE. + * 2. Add description and reorganize code arch. + * 11/16/2008 MHC 1. Reorganize code architecture. + * 2. Rename for some API and change extern or static type. + * +******************************************************************************/ +#include "r8192U.h" +#include "r8192S_hw.h" +#include "r8192S_phy.h" +#include "r8192S_phyreg.h" +#include "r8192S_Efuse.h" + +#include + +//typedef int INT32; +// +// In the future, we will always support EFUSE!! +// +#ifdef RTL8192SU +/*---------------------------Define Local Constant---------------------------*/ +#define _POWERON_DELAY_ +#define _PRE_EXECUTE_READ_CMD_ + +#define EFUSE_REPEAT_THRESHOLD_ 3 +#define EFUSE_ERROE_HANDLE 1 + + +// From 8712!!!!! +typedef struct _EFUSE_MAP_A{ + u8 offset; //0~15 + u8 word_start; //0~3 + u8 byte_start; //0 or 1 + u8 byte_cnts; + +}EFUSE_MAP, *PEFUSE_MAP; + +typedef struct PG_PKT_STRUCT_A{ + u8 offset; + u8 word_en; + u8 data[8]; +}PGPKT_STRUCT,*PPGPKT_STRUCT; + +typedef enum _EFUSE_DATA_ITEM{ + EFUSE_CHIP_ID=0, + EFUSE_LDO_SETTING, + EFUSE_CLK_SETTING, + EFUSE_SDIO_SETTING, + EFUSE_CCCR, + EFUSE_SDIO_MODE, + EFUSE_OCR, + EFUSE_F0CIS, + EFUSE_F1CIS, + EFUSE_MAC_ADDR, + EFUSE_EEPROM_VER, + EFUSE_CHAN_PLAN, + EFUSE_TXPW_TAB +} EFUSE_DATA_ITEM; + +struct efuse_priv +{ + u8 id[2]; + u8 ldo_setting[2]; + u8 clk_setting[2]; + u8 cccr; + u8 sdio_mode; + u8 ocr[3]; + u8 cis0[17]; + u8 cis1[48]; + u8 mac_addr[6]; + u8 eeprom_verno; + u8 channel_plan; + u8 tx_power_b[14]; + u8 tx_power_g[14]; +}; + +/*---------------------------Define Local Constant---------------------------*/ + + +/*------------------------Define global variable-----------------------------*/ +const u8 MAX_PGPKT_SIZE = 9; //header+ 2* 4 words (BYTES) +const u8 PGPKT_DATA_SIZE = 8; //BYTES sizeof(u8)*8 +const u32 EFUSE_MAX_SIZE = 512; + + +const EFUSE_MAP RTL8712_SDIO_EFUSE_TABLE[]={ + //offset word_s byte_start byte_cnts +/*ID*/ {0 ,0 ,0 ,2 }, // 00~01h +/*LDO Setting*/ {0 ,1 ,0 ,2 }, // 02~03h +/*CLK Setting*/ {0 ,2 ,0 ,2 }, // 04~05h +/*SDIO Setting*/ {1 ,0 ,0 ,1 }, // 08h +/*CCCR*/ {1 ,0 ,1 ,1 }, // 09h +/*SDIO MODE*/ {1 ,1 ,0 ,1 }, // 0Ah +/*OCR*/ {1 ,1 ,1 ,3 }, // 0B~0Dh +/*CCIS*/ {1 ,3 ,0 ,17 }, // 0E~1Eh 2...1 +/*F1CIS*/ {3 ,3 ,1 ,48 }, // 1F~4Eh 6...0 +/*MAC Addr*/ {10 ,0 ,0 ,6 }, // 50~55h +/*EEPROM ver*/ {10 ,3 ,0 ,1 }, // 56h +/*Channel plan*/ {10 ,3 ,1 ,1 }, // 57h +/*TxPwIndex */ {11 ,0 ,0 ,28 } // 58~73h 3...4 +}; + +/*------------------------Define global variable-----------------------------*/ + + +/*------------------------Define local variable------------------------------*/ + +/*------------------------Define local variable------------------------------*/ + + +/*--------------------Define function prototype-----------------------*/ +// +// From WMAC Efuse one byte R/W +// +extern void +EFUSE_Initialize(struct net_device* dev); +extern u8 +EFUSE_Read1Byte(struct net_device* dev, u16 Address); +extern void +EFUSE_Write1Byte(struct net_device* dev, u16 Address,u8 Value); + +// +// Efuse Shadow Area operation +// +static void +efuse_ShadowRead1Byte(struct net_device* dev,u16 Offset,u8 *Value); +static void +efuse_ShadowRead2Byte(struct net_device* dev, u16 Offset,u16 *Value ); +static void +efuse_ShadowRead4Byte(struct net_device* dev, u16 Offset,u32 *Value ); +static void +efuse_ShadowWrite1Byte(struct net_device* dev, u16 Offset, u8 Value); +static void +efuse_ShadowWrite2Byte(struct net_device* dev, u16 Offset,u16 Value); +static void +efuse_ShadowWrite4Byte(struct net_device* dev, u16 Offset,u32 Value); + +// +// Real Efuse operation +// +static u8 +efuse_OneByteRead(struct net_device* dev,u16 addr,u8 *data); +static u8 +efuse_OneByteWrite(struct net_device* dev,u16 addr, u8 data); + +// +// HW setting map file operation +// +static void +efuse_ReadAllMap(struct net_device* dev,u8 *Efuse); +#ifdef TO_DO_LIST +static void +efuse_WriteAllMap(struct net_device* dev,u8 *eeprom,u32 eeprom_size); +static bool +efuse_ParsingMap(char* szStr,u32* pu4bVal,u32* pu4bMove); +#endif +// +// Reald Efuse R/W or other operation API. +// +static u8 +efuse_PgPacketRead( struct net_device* dev,u8 offset,u8 *data); +static u8 +efuse_PgPacketWrite(struct net_device* dev,u8 offset,u8 word_en,u8 *data); +static void +efuse_WordEnableDataRead( u8 word_en,u8 *sourdata,u8 *targetdata); +static u8 +efuse_WordEnableDataWrite( struct net_device* dev, u16 efuse_addr, u8 word_en, u8 *data); +static void +efuse_PowerSwitch(struct net_device* dev,u8 PwrState); +static u16 +efuse_GetCurrentSize(struct net_device* dev); +static u8 +efuse_CalculateWordCnts(u8 word_en); +#if 0 +static void +efuse_ResetLoader(struct net_device* dev); +#endif +// +// API for power on power off!!! +// +#ifdef TO_DO_LIST +static void efuse_reg_ctrl(struct net_device* dev, u8 bPowerOn); +#endif +/*--------------------Define function prototype-----------------------*/ + + + +/*----------------------------------------------------------------------------- + * Function: EFUSE_Initialize + * + * Overview: Copy from WMAC fot EFUSE testing setting init. + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 09/23/2008 MHC Copy from WMAC. + * + *---------------------------------------------------------------------------*/ +extern void +EFUSE_Initialize(struct net_device* dev) +{ + u8 Bytetemp = {0x00}; + u8 temp = {0x00}; + + //Enable Digital Core Vdd : 0x2[13]=1 + Bytetemp = read_nic_byte(dev, SYS_FUNC_EN+1); + temp = Bytetemp | 0x20; + write_nic_byte(dev, SYS_FUNC_EN+1, temp); + + //EE loader to retention path1: attach 0x0[8]=0 + Bytetemp = read_nic_byte(dev, SYS_ISO_CTRL+1); + temp = Bytetemp & 0xFE; + write_nic_byte(dev, SYS_ISO_CTRL+1, temp); + + + //Enable E-fuse use 2.5V LDO : 0x37[7]=1 + Bytetemp = read_nic_byte(dev, EFUSE_TEST+3); + temp = Bytetemp | 0x80; + write_nic_byte(dev, EFUSE_TEST+3, temp); + + //E-fuse clk switch from 500k to 40M : 0x2F8[1:0]=11b + write_nic_byte(dev, 0x2F8, 0x3); + + //Set E-fuse program time & read time : 0x30[30:24]=1110010b + write_nic_byte(dev, EFUSE_CTRL+3, 0x72); + +} /* EFUSE_Initialize */ + + +/*----------------------------------------------------------------------------- + * Function: EFUSE_Read1Byte + * + * Overview: Copy from WMAC fot EFUSE read 1 byte. + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 09/23/2008 MHC Copy from WMAC. + * + *---------------------------------------------------------------------------*/ +extern u8 +EFUSE_Read1Byte(struct net_device* dev, u16 Address) +{ + u8 data; + u8 Bytetemp = {0x00}; + u8 temp = {0x00}; + u32 k=0; + + if (Address < EFUSE_MAC_LEN) //E-fuse 512Byte + { + //Write E-fuse Register address bit0~7 + temp = Address & 0xFF; + write_nic_byte(dev, EFUSE_CTRL+1, temp); + Bytetemp = read_nic_byte(dev, EFUSE_CTRL+2); + //Write E-fuse Register address bit8~9 + temp = ((Address >> 8) & 0x03) | (Bytetemp & 0xFC); + write_nic_byte(dev, EFUSE_CTRL+2, temp); + + //Write 0x30[31]=0 + Bytetemp = read_nic_byte(dev, EFUSE_CTRL+3); + temp = Bytetemp & 0x7F; + write_nic_byte(dev, EFUSE_CTRL+3, temp); + + //Wait Write-ready (0x30[31]=1) + Bytetemp = read_nic_byte(dev, EFUSE_CTRL+3); + while(!(Bytetemp & 0x80)) + { + Bytetemp = read_nic_byte(dev, EFUSE_CTRL+3); + k++; + if(k==1000) + { + k=0; + break; + } + } + data=read_nic_byte(dev, EFUSE_CTRL); + return data; + } + else + return 0xFF; + +} /* EFUSE_Read1Byte */ + + +/*----------------------------------------------------------------------------- + * Function: EFUSE_Write1Byte + * + * Overview: Copy from WMAC fot EFUSE write 1 byte. + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 09/23/2008 MHC Copy from WMAC. + * + *---------------------------------------------------------------------------*/ +extern void +EFUSE_Write1Byte(struct net_device* dev, u16 Address,u8 Value) +{ + //u8 data; + u8 Bytetemp = {0x00}; + u8 temp = {0x00}; + u32 k=0; + + //RT_TRACE(COMP_EFUSE, "Addr=%x Data =%x\n", Address, Value); + + if( Address < EFUSE_MAC_LEN) //E-fuse 512Byte + { + write_nic_byte(dev, EFUSE_CTRL, Value); + + //Write E-fuse Register address bit0~7 + temp = Address & 0xFF; + write_nic_byte(dev, EFUSE_CTRL+1, temp); + Bytetemp = read_nic_byte(dev, EFUSE_CTRL+2); + + //Write E-fuse Register address bit8~9 + temp = ((Address >> 8) & 0x03) | (Bytetemp & 0xFC); + write_nic_byte(dev, EFUSE_CTRL+2, temp); + + //Write 0x30[31]=1 + Bytetemp = read_nic_byte(dev, EFUSE_CTRL+3); + temp = Bytetemp | 0x80; + write_nic_byte(dev, EFUSE_CTRL+3, temp); + + //Wait Write-ready (0x30[31]=0) + Bytetemp = read_nic_byte(dev, EFUSE_CTRL+3); + while(Bytetemp & 0x80) + { + Bytetemp = read_nic_byte(dev, EFUSE_CTRL+3); + k++; + if(k==100) + { + k=0; + break; + } + } + } + +} /* EFUSE_Write1Byte */ + + +#ifdef EFUSE_FOR_92SU +// +// Description: +// 1. Process CR93C46 Data polling cycle. +// 2. Refered from SD1 Richard. +// +// Assumption: +// 1. Boot from E-Fuse and successfully auto-load. +// 2. PASSIVE_LEVEL (USB interface) +// +// Created by Roger, 2008.10.21. +// +void do_93c46(struct net_device* dev, u8 addorvalue) +{ + //u8 clear[1] = {0x0}; // cs=0 , sk=0 , di=0 , do=0 + u8 cs[1] = {0x88}; // cs=1 , sk=0 , di=0 , do=0 + u8 cssk[1] = {0x8c}; // cs=1 , sk=1 , di=0 , do=0 + u8 csdi[1] = {0x8a}; // cs=1 , sk=0 , di=1 , do=0 + u8 csskdi[1] = {0x8e}; // cs=1 , sk=1 , di=1 , do=0 + //u8 di[1] = {0x82}; // cs=0 , sk=0 , di=1 , do=0 + u8 count; + + for(count=0 ; count<8 ; count++) + { + if((addorvalue&0x80)!=0) + { + write_nic_byte(dev, EPROM_CMD, csdi[0]); + write_nic_byte(dev, EPROM_CMD, csskdi[0]); + } + else + { + write_nic_byte(dev, EPROM_CMD, cs[0]); + write_nic_byte(dev, EPROM_CMD, cssk[0]); + } + addorvalue = addorvalue << 1; + } +} + + +// +// Description: +// Process CR93C46 Data read polling cycle. +// Refered from SD1 Richard. +// +// Assumption: +// 1. Boot from E-Fuse and successfully auto-load. +// 2. PASSIVE_LEVEL (USB interface) +// +// Created by Roger, 2008.10.21. +// +u16 Read93C46(struct net_device* dev, u16 Reg ) +{ + + u8 clear[1] = {0x0}; // cs=0 , sk=0 , di=0 , do=0 + u8 cs[1] = {0x88}; // cs=1 , sk=0 , di=0 , do=0 + u8 cssk[1] = {0x8c}; // cs=1 , sk=1 , di=0 , do=0 + u8 csdi[1] = {0x8a}; // cs=1 , sk=0 , di=1 , do=0 + u8 csskdi[1] = {0x8e}; // cs=1 , sk=1 , di=1 , do=0 + //u8 di[1] = {0x82}; // cs=0 , sk=0 , di=1 , do=0 + u8 EepromSEL[1]={0x00}; + u8 address; + + u16 storedataF[1] = {0x0}; //93c46 data packet for 16bits + u8 t,data[1],storedata[1]; + + + address = (u8)Reg; + + // Suggested by SD1 Alex, 2008.10.20. Revised by Roger. + *EepromSEL= read_nic_byte(dev, EPROM_CMD); + + if((*EepromSEL & 0x10) == 0x10) // select 93c46 + { + address = address | 0x80; + + write_nic_byte(dev, EPROM_CMD, csdi[0]); + write_nic_byte(dev, EPROM_CMD, csskdi[0]); + do_93c46(dev, address); + } + + + for(t=0 ; t<16 ; t++) //if read 93c46 , t=16 + { + write_nic_byte(dev, EPROM_CMD, cs[0]); + write_nic_byte(dev, EPROM_CMD, cssk[0]); + *data= read_nic_byte(dev, EPROM_CMD); + + if(*data & 0x8d) //original code + { + *data = *data & 0x01; + *storedata = *data; + } + else + { + *data = *data & 0x01 ; + *storedata = *data; + } + *storedataF = (*storedataF << 1 ) + *storedata; + } + write_nic_byte(dev, EPROM_CMD, cs[0]); + write_nic_byte(dev, EPROM_CMD, clear[0]); + + return *storedataF; +} + + +// +// Description: +// Execute E-Fuse read byte operation. +// Refered from SD1 Richard. +// +// Assumption: +// 1. Boot from E-Fuse and successfully auto-load. +// 2. PASSIVE_LEVEL (USB interface) +// +// Created by Roger, 2008.10.21. +// +void +ReadEFuseByte(struct net_device* dev,u16 _offset, u8 *pbuf) +{ + + //u16 indexk=0; + u32 value32; + u8 readbyte; + u16 retry; + + + //Write Address + write_nic_byte(dev, EFUSE_CTRL+1, (_offset & 0xff)); + readbyte = read_nic_byte(dev, EFUSE_CTRL+2); + write_nic_byte(dev, EFUSE_CTRL+2, ((_offset >> 8) & 0x03) | (readbyte & 0xfc)); + + //Write bit 32 0 + readbyte = read_nic_byte(dev, EFUSE_CTRL+3); + write_nic_byte(dev, EFUSE_CTRL+3, (readbyte & 0x7f)); + + //Check bit 32 read-ready + retry = 0; + value32 = read_nic_dword(dev, EFUSE_CTRL); + //while(!(((value32 >> 24) & 0xff) & 0x80) && (retry<10)) + while(!(((value32 >> 24) & 0xff) & 0x80) && (retry<10000)) + { + value32 = read_nic_dword(dev, EFUSE_CTRL); + retry++; + } + *pbuf = (u8)(value32 & 0xff); +} + + +#define EFUSE_READ_SWITCH 1 +// +// Description: +// 1. Execute E-Fuse read byte operation according as map offset and +// save to E-Fuse table. +// 2. Refered from SD1 Richard. +// +// Assumption: +// 1. Boot from E-Fuse and successfully auto-load. +// 2. PASSIVE_LEVEL (USB interface) +// +// Created by Roger, 2008.10.21. +// +void +ReadEFuse(struct net_device* dev, u16 _offset, u16 _size_byte, u8 *pbuf) +{ + + u8 efuseTbl[128]; + u8 rtemp8[1]; + u16 eFuse_Addr = 0; + u8 offset, wren; + u16 i, j; + u16 eFuseWord[16][4];// = {0xFF};//FIXLZM + + for(i=0; i<16; i++) + for(j=0; j<4; j++) + eFuseWord[i][j]=0xFF; + + // Do NOT excess total size of EFuse table. Added by Roger, 2008.11.10. + if((_offset + _size_byte)>128) + {// total E-Fuse table is 128bytes + //RT_TRACE(COMP_EFUSE, "ReadEFuse(): Invalid offset(%#x) with read bytes(%#x)!!\n",_offset, _size_byte); + printk("ReadEFuse(): Invalid offset with read bytes!!\n"); + return; + } + + // Refresh efuse init map as all oxFF. + for (i = 0; i < 128; i++) + efuseTbl[i] = 0xFF; + +#if (EFUSE_READ_SWITCH == 1) + ReadEFuseByte(dev, eFuse_Addr, rtemp8); +#else + rtemp8[0] = EFUSE_Read1Byte(dev, eFuse_Addr); +#endif + if(*rtemp8 != 0xFF) eFuse_Addr++; + while((*rtemp8 != 0xFF) && (eFuse_Addr < 512)){ + offset = ((*rtemp8 >> 4) & 0x0f); + if(offset <= 0x0F){ + wren = (*rtemp8 & 0x0f); + for(i=0; i<4; i++){ + if(!(wren & 0x01)){ +#if (EFUSE_READ_SWITCH == 1) + ReadEFuseByte(dev, eFuse_Addr, rtemp8); eFuse_Addr++; +#else + rtemp8[0] = EFUSE_Read1Byte(dev, eFuse_Addr); eFuse_Addr++; +#endif + eFuseWord[offset][i] = (*rtemp8 & 0xff); + if(eFuse_Addr >= 512) break; +#if (EFUSE_READ_SWITCH == 1) + ReadEFuseByte(dev, eFuse_Addr, rtemp8); eFuse_Addr++; +#else + rtemp8[0] = EFUSE_Read1Byte(dev, eFuse_Addr); eFuse_Addr++; +#endif + eFuseWord[offset][i] |= (((u16)*rtemp8 << 8) & 0xff00); + if(eFuse_Addr >= 512) break; + } + wren >>= 1; + } + } +#if (EFUSE_READ_SWITCH == 1) + ReadEFuseByte(dev, eFuse_Addr, rtemp8); +#else + rtemp8[0] = EFUSE_Read1Byte(dev, eFuse_Addr); eFuse_Addr++; +#endif + if(*rtemp8 != 0xFF && (eFuse_Addr < 512)) eFuse_Addr++; + } + + for(i=0; i<16; i++){ + for(j=0; j<4; j++){ + efuseTbl[(i*8)+(j*2)]=(eFuseWord[i][j] & 0xff); + efuseTbl[(i*8)+((j*2)+1)]=((eFuseWord[i][j] >> 8) & 0xff); + } + } + for(i=0; i<_size_byte; i++) + pbuf[i] = efuseTbl[_offset+i]; +} +#endif // #if (EFUSE_FOR_92SU == 1) + + +/*----------------------------------------------------------------------------- + * Function: EFUSE_ShadowRead + * + * Overview: Read from efuse init map !!!!! + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 11/12/2008 MHC Create Version 0. + * + *---------------------------------------------------------------------------*/ +extern void +EFUSE_ShadowRead( struct net_device* dev, u8 Type, u16 Offset, u32 *Value) +{ + //HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + + if (Type == 1) + efuse_ShadowRead1Byte(dev, Offset, (u8 *)Value); + else if (Type == 2) + efuse_ShadowRead2Byte(dev, Offset, (u16 *)Value); + else if (Type == 4) + efuse_ShadowRead4Byte(dev, Offset, (u32 *)Value); + +} // EFUSE_ShadowRead + + +/*----------------------------------------------------------------------------- + * Function: EFUSE_ShadowWrite + * + * Overview: Write efuse modify map for later update operation to use!!!!! + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 11/12/2008 MHC Create Version 0. + * + *---------------------------------------------------------------------------*/ +extern void +EFUSE_ShadowWrite( struct net_device* dev, u8 Type, u16 Offset,u32 Value) +{ + //HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + + if (Offset >= 0x18 && Offset <= 0x1F) + return; + + if (Type == 1) + efuse_ShadowWrite1Byte(dev, Offset, (u8)Value); + else if (Type == 2) + efuse_ShadowWrite2Byte(dev, Offset, (u16)Value); + else if (Type == 4) + efuse_ShadowWrite4Byte(dev, Offset, (u32)Value); + +} // EFUSE_ShadowWrite + + +/*----------------------------------------------------------------------------- + * Function: EFUSE_ShadowUpdate + * + * Overview: Compare init and modify map to update Efuse!!!!! + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 11/12/2008 MHC Create Version 0. + * + *---------------------------------------------------------------------------*/ +extern void +EFUSE_ShadowUpdate(struct net_device* dev) +{ + //HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + struct r8192_priv *priv = ieee80211_priv(dev); + u16 i, offset, base = 0; + u8 word_en = 0x0F; + bool first_pg = false; + // For Efuse write action, we must enable LDO2.5V and 40MHZ clk. + efuse_PowerSwitch(dev, TRUE); + + // + // Efuse support 16 write are with PG header packet!!!! + // + for (offset = 0; offset < 16; offset++) + { + // Offset 0x18-1F are reserved now!!! +#ifdef RTL8192SE + if(priv->card_8192 == NIC_8192SE){ + if (offset == 3) + continue; + } +#endif + word_en = 0x0F; + base = offset * 8; + + // + // Decide Word Enable Bit for the Efuse section + // One section contain 4 words = 8 bytes!!!!! + // + for (i = 0; i < 8; i++) + { + if (offset == 0 && priv->EfuseMap[EFUSE_INIT_MAP][base+i] == 0xFF) + { + first_pg = TRUE; + } + + // 2008/12/11 MH HW autoload fail workaround for A/BCUT. +#ifdef RTL8192SE + if (first_pg == TRUE && offset == 1 && (priv->card_8192 == NIC_8192SE)) + { + continue; + } +#endif + + if (first_pg == TRUE) + { + word_en &= ~(1<<(i/2)); + priv->EfuseMap[EFUSE_INIT_MAP][base+i] = + priv->EfuseMap[EFUSE_MODIFY_MAP][base+i]; + }else + { + if ( priv->EfuseMap[EFUSE_INIT_MAP][base+i] != + priv->EfuseMap[EFUSE_MODIFY_MAP][base+i]) + { + word_en &= ~(EFUSE_BIT(i/2)); + //RT_TRACE(COMP_EFUSE, "Offset=%d Addr%x %x ==> %x Word_En=%02x\n", + //offset, base+i, priv->EfuseMap[0][base+i], priv->EfuseMap[1][base+i],word_en); + + // Update init table!!! + priv->EfuseMap[EFUSE_INIT_MAP][base+i] = + priv->EfuseMap[EFUSE_MODIFY_MAP][base+i]; + } + } + } + + // + // Call Efuse real write section !!!! + // + if (word_en != 0x0F) + { + u8 tmpdata[8]; + + //FIXLZM + memcpy(tmpdata, &(priv->EfuseMap[EFUSE_MODIFY_MAP][base]), 8); + //RT_PRINT_DATA(COMP_INIT, DBG_LOUD, ("U-EFUSE\n"), tmpdata, 8); + efuse_PgPacketWrite(dev,(u8)offset,word_en,tmpdata); + } + + } + // 2008/12/01 MH For Efuse HW load bug workarounf method!!!! + // We will force write 0x10EC into address 10&11 after all Efuse content. + // +#ifdef RTL8192SE + if (first_pg == TRUE && (priv->card_8192 == NIC_8192SE)) + { + // 2008/12/11 MH Use new method to prevent HW autoload fail. + u8 tmpdata[8]; + + memcpy(tmpdata, (&priv->EfuseMap[EFUSE_MODIFY_MAP][8]), 8); + efuse_PgPacketWrite(dev, 1, 0x0, tmpdata); +#if 0 + u1Byte tmpdata[8] = {0xFF, 0xFF, 0xEC, 0x10, 0xFF, 0xFF, 0xFF, 0xFF}; + + efuse_PgPacketWrite(pAdapter, 1, 0xD, tmpdata); +#endif + } +#endif + + + // For warm reboot, we must resume Efuse clock to 500K. + efuse_PowerSwitch(dev, FALSE); + // 2008/12/01 MH We update shadow content again!!!! + EFUSE_ShadowMapUpdate(dev); + +} // EFUSE_ShadowUpdate + + +/*----------------------------------------------------------------------------- + * Function: EFUSE_ShadowMapUpdate + * + * Overview: Transfer current EFUSE content to shadow init and modify map. + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 11/13/2008 MHC Create Version 0. + * + *---------------------------------------------------------------------------*/ +extern void EFUSE_ShadowMapUpdate(struct net_device* dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + + if (priv->AutoloadFailFlag == true){ + memset(&(priv->EfuseMap[EFUSE_INIT_MAP][0]), 0xff, 128); + }else{ + efuse_ReadAllMap(dev, &priv->EfuseMap[EFUSE_INIT_MAP][0]); + } + //PlatformMoveMemory(&priv->EfuseMap[EFUSE_MODIFY_MAP][0], + //&priv->EfuseMap[EFUSE_INIT_MAP][0], HWSET_MAX_SIZE_92S);//FIXLZM + memcpy(&priv->EfuseMap[EFUSE_MODIFY_MAP][0], + &priv->EfuseMap[EFUSE_INIT_MAP][0], HWSET_MAX_SIZE_92S); + +} // EFUSE_ShadowMapUpdate + +extern void +EFUSE_ForceWriteVendorId( struct net_device* dev) +{ + u8 tmpdata[8] = {0xFF, 0xFF, 0xEC, 0x10, 0xFF, 0xFF, 0xFF, 0xFF}; + + efuse_PowerSwitch(dev, TRUE); + + efuse_PgPacketWrite(dev, 1, 0xD, tmpdata); + + efuse_PowerSwitch(dev, FALSE); + +} // EFUSE_ForceWriteVendorId + +/*----------------------------------------------------------------------------- + * Function: efuse_ShadowRead1Byte + * efuse_ShadowRead2Byte + * efuse_ShadowRead4Byte + * + * Overview: Read from efuse init map by one/two/four bytes !!!!! + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 11/12/2008 MHC Create Version 0. + * + *---------------------------------------------------------------------------*/ +static void +efuse_ShadowRead1Byte(struct net_device* dev, u16 Offset, u8 *Value) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + + *Value = priv->EfuseMap[EFUSE_MODIFY_MAP][Offset]; + +} // EFUSE_ShadowRead1Byte + +//---------------Read Two Bytes +static void +efuse_ShadowRead2Byte(struct net_device* dev, u16 Offset, u16 *Value) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + + *Value = priv->EfuseMap[EFUSE_MODIFY_MAP][Offset]; + *Value |= priv->EfuseMap[EFUSE_MODIFY_MAP][Offset+1]<<8; + +} // EFUSE_ShadowRead2Byte + +//---------------Read Four Bytes +static void +efuse_ShadowRead4Byte(struct net_device* dev, u16 Offset, u32 *Value) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + + *Value = priv->EfuseMap[EFUSE_MODIFY_MAP][Offset]; + *Value |= priv->EfuseMap[EFUSE_MODIFY_MAP][Offset+1]<<8; + *Value |= priv->EfuseMap[EFUSE_MODIFY_MAP][Offset+2]<<16; + *Value |= priv->EfuseMap[EFUSE_MODIFY_MAP][Offset+3]<<24; + +} // efuse_ShadowRead4Byte + + + +/*----------------------------------------------------------------------------- + * Function: efuse_ShadowWrite1Byte + * efuse_ShadowWrite2Byte + * efuse_ShadowWrite4Byte + * + * Overview: Write efuse modify map by one/two/four byte. + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 11/12/2008 MHC Create Version 0. + * + *---------------------------------------------------------------------------*/ +static void +efuse_ShadowWrite1Byte(struct net_device* dev, u16 Offset, u8 Value) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + + priv->EfuseMap[EFUSE_MODIFY_MAP][Offset] = Value; + +} // efuse_ShadowWrite1Byte + +//---------------Write Two Bytes +static void +efuse_ShadowWrite2Byte(struct net_device* dev, u16 Offset, u16 Value) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + + priv->EfuseMap[EFUSE_MODIFY_MAP][Offset] = Value&0x00FF; + priv->EfuseMap[EFUSE_MODIFY_MAP][Offset+1] = Value>>8; + +} // efuse_ShadowWrite1Byte + +//---------------Write Four Bytes +static void +efuse_ShadowWrite4Byte(struct net_device* dev, u16 Offset, u32 Value) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + + priv->EfuseMap[EFUSE_MODIFY_MAP][Offset] = (u8)(Value&0x000000FF); + priv->EfuseMap[EFUSE_MODIFY_MAP][Offset+1] = (u8)((Value>>8)&0x0000FF); + priv->EfuseMap[EFUSE_MODIFY_MAP][Offset+2] = (u8)((Value>>16)&0x00FF); + priv->EfuseMap[EFUSE_MODIFY_MAP][Offset+3] = (u8)((Value>>24)&0xFF); + +} // efuse_ShadowWrite1Byte + + +/* 11/16/2008 MH Read one byte from real Efuse. */ +static u8 +efuse_OneByteRead(struct net_device* dev, u16 addr,u8 *data) +{ + u8 tmpidx = 0; + u8 bResult; + + // -----------------e-fuse reg ctrl --------------------------------- + //address + write_nic_byte(dev, EFUSE_CTRL+1, (u8)(addr&0xff)); + write_nic_byte(dev, EFUSE_CTRL+2, ((u8)((addr>>8) &0x03) ) | + (read_nic_byte(dev, EFUSE_CTRL+2)&0xFC )); + + write_nic_byte(dev, EFUSE_CTRL+3, 0x72);//read cmd + + while(!(0x80 &read_nic_byte(dev, EFUSE_CTRL+3))&&(tmpidx<100)) + { + tmpidx++; + } + if(tmpidx<100) + { + *data=read_nic_byte(dev, EFUSE_CTRL); + bResult = TRUE; + } + else + { + *data = 0xff; + bResult = FALSE; + } + return bResult; +} // efuse_OneByteRead + +/* 11/16/2008 MH Write one byte to reald Efuse. */ +static u8 +efuse_OneByteWrite(struct net_device* dev, u16 addr, u8 data) +{ + u8 tmpidx = 0; + u8 bResult; + + //RT_TRACE(COMP_EFUSE, "Addr = %x Data=%x\n", addr, data); + + //return 0; + + // -----------------e-fuse reg ctrl --------------------------------- + //address + write_nic_byte(dev, EFUSE_CTRL+1, (u8)(addr&0xff)); + write_nic_byte(dev, EFUSE_CTRL+2, + read_nic_byte(dev, EFUSE_CTRL+2)|(u8)((addr>>8)&0x03) ); + + write_nic_byte(dev, EFUSE_CTRL, data);//data + write_nic_byte(dev, EFUSE_CTRL+3, 0xF2);//write cmd + + while((0x80 & read_nic_byte(dev, EFUSE_CTRL+3)) && (tmpidx<100) ){ + tmpidx++; + } + + if(tmpidx<100) + { + bResult = TRUE; + } + else + { + bResult = FALSE; + } + + return bResult; +} // efuse_OneByteWrite + + +/*----------------------------------------------------------------------------- + * Function: efuse_ReadAllMap + * + * Overview: Read All Efuse content + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 11/11/2008 MHC Create Version 0. + * + *---------------------------------------------------------------------------*/ +static void +efuse_ReadAllMap(struct net_device* dev, u8 *Efuse) +{ + //u8 pg_data[8]; + //u8 offset = 0; + //u8 tmpidx; + //static u8 index = 0; + + // + // We must enable clock and LDO 2.5V otherwise, read all map will be fail!!!! + // + efuse_PowerSwitch(dev, TRUE); + ReadEFuse(dev, 0, 128, Efuse); + efuse_PowerSwitch(dev, FALSE); +#if 0 + // ==> Prevent efuse read error!!! + RT_TRACE(COMP_INIT, "efuse_ResetLoader\n"); + efuse_ResetLoader(dev); + + // Change Efuse Clock for write action to 40MHZ + write_nic_byte(dev, EFUSE_CLK, 0x03); + + ReadEFuse(dev, 0, 128, Efuse); + + // Change Efuse Clock for write action to 500K + write_nic_byte(dev, EFUSE_CLK, 0x02); +#if 0 // Error !!!!!! + for(offset = 0;offset<16;offset++) // For 8192SE + { + PlatformFillMemory((PVOID)pg_data, 8, 0xff); + efuse_PgPacketRead(pAdapter,offset,pg_data); + + PlatformMoveMemory((PVOID)&Efuse[offset*8], (PVOID)pg_data, 8); + } +#endif + + // + // Error Check and Reset Again!!!! + // + if (Efuse[0] != 0x29 || Efuse[1] != 0x81) + { + // SW autoload fail, we have to read again!!! + if (index ++ < 5) + { + RT_TRACE(COMP_INIT, "EFUSE R FAIL %d\n", index); + efuse_ReadAllMap(dev, Efuse); + // Wait a few time ???? Or need to do some setting ??? + // When we reload driver, efuse will be OK!! + } + } + else + { + index = 0; + } + + //efuse_PowerSwitch(pAdapter, FALSE); +#endif +} // efuse_ReadAllMap + + +/*----------------------------------------------------------------------------- + * Function: efuse_WriteAllMap + * + * Overview: Write All Efuse content + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 11/11/2008 MHC Create Version 0. + * + *---------------------------------------------------------------------------*/ +#ifdef TO_DO_LIST +static void +efuse_WriteAllMap(struct net_device* dev,u8 *eeprom, u32 eeprom_size) +{ + unsigned char word_en = 0x00; + + unsigned char tmpdata[8]; + unsigned char offset; + + // For Efuse write action, we must enable LDO2.5V and 40MHZ clk. + efuse_PowerSwitch(dev, TRUE); + + //sdio contents + for(offset=0 ; offset< eeprom_size/PGPKT_DATA_SIZE ; offset++) + { + // 92S will only reserv 0x18-1F 8 bytes now. The 3rd efuse write area! + if (IS_HARDWARE_TYPE_8192SE(dev)) + { + // Refer to + // 0x18-1f Reserve >0x50 Reserve for tx power + if (offset == 3/* || offset > 9*/) + continue;//word_en = 0x0F; + //else if (offset == 9) // 0x4c-4f Reserve + //word_en = 0x0C; + else + word_en = 0x00; + } + //RT_TRACE(COMP_EFUSE, ("Addr=%d size=%d Word_En=%02x\n", offset, eeprom_size, word_en)); + + //memcpy(tmpdata,eeprom+(offset*PGPKT_DATA_SIZE),8); + memcpy(tmpdata, (eeprom+(offset*PGPKT_DATA_SIZE)), 8); + + //RT_PRINT_DATA(COMP_INIT, DBG_LOUD, ("EFUSE\t"), tmpdata, 8); + + efuse_PgPacketWrite(dev,offset,word_en,tmpdata); + + + } + + // For warm reboot, we must resume Efuse clock to 500K. + efuse_PowerSwitch(dev, FALSE); + +} // efuse_WriteAllMap +#endif + +/*----------------------------------------------------------------------------- + * Function: efuse_PgPacketRead + * + * Overview: Receive dedicated Efuse are content. For92s, we support 16 + * area now. It will return 8 bytes content for every area. + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 11/16/2008 MHC Reorganize code Arch and assign as local API. + * + *---------------------------------------------------------------------------*/ +static u8 +efuse_PgPacketRead( struct net_device* dev, u8 offset, u8 *data) +{ + u8 ReadState = PG_STATE_HEADER; + + bool bContinual = TRUE; + bool bDataEmpty = TRUE ; + + u8 efuse_data,word_cnts=0; + u16 efuse_addr = 0; + u8 hoffset=0,hworden=0; + u8 tmpidx=0; + u8 tmpdata[8]; + + if(data==NULL) return FALSE; + if(offset>15) return FALSE; + + //FIXLZM + //PlatformFillMemory((PVOID)data, sizeof(u8)*PGPKT_DATA_SIZE, 0xff); + //PlatformFillMemory((PVOID)tmpdata, sizeof(u8)*PGPKT_DATA_SIZE, 0xff); + memset(data, 0xff, sizeof(u8)*PGPKT_DATA_SIZE); + memset(tmpdata, 0xff, sizeof(u8)*PGPKT_DATA_SIZE); + + //RT_PRINT_DATA(COMP_EFUSE, DBG_LOUD, ("efuse_PgPacketRead-1\n"), data, 8); + + //efuse_reg_ctrl(pAdapter,TRUE);//power on + while(bContinual && (efuse_addr < EFUSE_MAX_SIZE) ) + { + //------- Header Read ------------- + if(ReadState & PG_STATE_HEADER) + { + if(efuse_OneByteRead(dev, efuse_addr ,&efuse_data)&&(efuse_data!=0xFF)){ + hoffset = (efuse_data>>4) & 0x0F; + hworden = efuse_data & 0x0F; + word_cnts = efuse_CalculateWordCnts(hworden); + bDataEmpty = TRUE ; + + if(hoffset==offset){ + for(tmpidx = 0;tmpidx< word_cnts*2 ;tmpidx++){ + if(efuse_OneByteRead(dev, efuse_addr+1+tmpidx ,&efuse_data) ){ + tmpdata[tmpidx] = efuse_data; + if(efuse_data!=0xff){ + bDataEmpty = FALSE; + } + } + } + if(bDataEmpty==FALSE){ + ReadState = PG_STATE_DATA; + }else{//read next header + efuse_addr = efuse_addr + (word_cnts*2)+1; + ReadState = PG_STATE_HEADER; + } + } + else{//read next header + efuse_addr = efuse_addr + (word_cnts*2)+1; + ReadState = PG_STATE_HEADER; + } + + } + else{ + bContinual = FALSE ; + } + } + //------- Data section Read ------------- + else if(ReadState & PG_STATE_DATA) + { + efuse_WordEnableDataRead(hworden,tmpdata,data); + efuse_addr = efuse_addr + (word_cnts*2)+1; + ReadState = PG_STATE_HEADER; + } + + } + //efuse_reg_ctrl(pAdapter,FALSE);//power off + + //RT_PRINT_DATA(COMP_EFUSE, DBG_LOUD, ("efuse_PgPacketRead-2\n"), data, 8); + + if( (data[0]==0xff) &&(data[1]==0xff) && (data[2]==0xff) && (data[3]==0xff) && + (data[4]==0xff) &&(data[5]==0xff) && (data[6]==0xff) && (data[7]==0xff)) + return FALSE; + else + return TRUE; + +} // efuse_PgPacketRead + + +/*----------------------------------------------------------------------------- + * Function: efuse_PgPacketWrite + * + * Overview: Send A G package for different section in real efuse area. + * For 92S, One PG package contain 8 bytes content and 4 word + * unit. PG header = 0x[bit7-4=offset][bit3-0word enable] + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 11/16/2008 MHC Reorganize code Arch and assign as local API. + * + *---------------------------------------------------------------------------*/ +static u8 efuse_PgPacketWrite(struct net_device* dev, u8 offset, u8 word_en,u8 *data) +{ + u8 WriteState = PG_STATE_HEADER; + + bool bContinual = TRUE,bDataEmpty=TRUE, bResult = TRUE; + u16 efuse_addr = 0; + u8 efuse_data; + + u8 pg_header = 0; + + //u16 tmp_addr=0; + u8 tmp_word_cnts=0,target_word_cnts=0; + u8 tmp_header,match_word_en,tmp_word_en; + + //u8 efuse_clk_ori,efuse_clk_new; + + PGPKT_STRUCT target_pkt; + PGPKT_STRUCT tmp_pkt; + + u8 originaldata[sizeof(u8)*8]; + u8 tmpindex = 0,badworden = 0x0F; + + static u32 repeat_times = 0; + + if( efuse_GetCurrentSize(dev) >= EFUSE_MAX_SIZE) + { + printk("efuse_PgPacketWrite error \n"); + return FALSE; + } + + // Init the 8 bytes content as 0xff + target_pkt.offset = offset; + target_pkt.word_en= word_en; + + //PlatformFillMemory((PVOID)target_pkt.data, sizeof(u8)*8, 0xFF); + memset(target_pkt.data,0xFF,sizeof(u8)*8); + + efuse_WordEnableDataRead(word_en,data,target_pkt.data); + target_word_cnts = efuse_CalculateWordCnts(target_pkt.word_en); + + //efuse_reg_ctrl(pAdapter,TRUE);//power on + printk("EFUSE Power ON\n"); + + while( bContinual && (efuse_addr < EFUSE_MAX_SIZE) ) + { + + if(WriteState==PG_STATE_HEADER) + { + bDataEmpty=TRUE; + badworden = 0x0F; + //************ so ******************* + printk("EFUSE PG_STATE_HEADER\n"); + if ( efuse_OneByteRead(dev, efuse_addr ,&efuse_data) && + (efuse_data!=0xFF)) + { + tmp_header = efuse_data; + + tmp_pkt.offset = (tmp_header>>4) & 0x0F; + tmp_pkt.word_en = tmp_header & 0x0F; + tmp_word_cnts = efuse_CalculateWordCnts(tmp_pkt.word_en); + + //************ so-1 ******************* + if(tmp_pkt.offset != target_pkt.offset) + { + efuse_addr = efuse_addr + (tmp_word_cnts*2) +1; //Next pg_packet + #if (EFUSE_ERROE_HANDLE == 1) + WriteState = PG_STATE_HEADER; + #endif + } + else + { + //************ so-2 ******************* + for(tmpindex=0 ; tmpindex<(tmp_word_cnts*2) ; tmpindex++) + { + if(efuse_OneByteRead(dev, (efuse_addr+1+tmpindex) ,&efuse_data)&&(efuse_data != 0xFF)){ + bDataEmpty = FALSE; + } + } + //************ so-2-1 ******************* + if(bDataEmpty == FALSE) + { + efuse_addr = efuse_addr + (tmp_word_cnts*2) +1; //Next pg_packet + #if (EFUSE_ERROE_HANDLE == 1) + WriteState=PG_STATE_HEADER; + #endif + } + else + {//************ so-2-2 ******************* + match_word_en = 0x0F; + if( !( (target_pkt.word_en&BIT0)|(tmp_pkt.word_en&BIT0) )) + { + match_word_en &= (~BIT0); + } + if( !( (target_pkt.word_en&BIT1)|(tmp_pkt.word_en&BIT1) )) + { + match_word_en &= (~BIT1); + } + if( !( (target_pkt.word_en&BIT2)|(tmp_pkt.word_en&BIT2) )) + { + match_word_en &= (~BIT2); + } + if( !( (target_pkt.word_en&BIT3)|(tmp_pkt.word_en&BIT3) )) + { + match_word_en &= (~BIT3); + } + + //************ so-2-2-A ******************* + if((match_word_en&0x0F)!=0x0F) + { + badworden = efuse_WordEnableDataWrite(dev,efuse_addr+1, tmp_pkt.word_en ,target_pkt.data); + + //************ so-2-2-A-1 ******************* + //############################ + if(0x0F != (badworden&0x0F)) + { + u8 reorg_offset = offset; + u8 reorg_worden=badworden; + efuse_PgPacketWrite(dev,reorg_offset,reorg_worden,originaldata); + } + //############################ + + tmp_word_en = 0x0F; + if( (target_pkt.word_en&BIT0)^(match_word_en&BIT0) ) + { + tmp_word_en &= (~BIT0); + } + if( (target_pkt.word_en&BIT1)^(match_word_en&BIT1) ) + { + tmp_word_en &= (~BIT1); + } + if( (target_pkt.word_en&BIT2)^(match_word_en&BIT2) ) + { + tmp_word_en &= (~BIT2); + } + if( (target_pkt.word_en&BIT3)^(match_word_en&BIT3) ) + { + tmp_word_en &=(~BIT3); + } + + //************ so-2-2-A-2 ******************* + if((tmp_word_en&0x0F)!=0x0F){ + //reorganize other pg packet + //efuse_addr = efuse_addr + (2*tmp_word_cnts) +1;//next pg packet addr + efuse_addr = efuse_GetCurrentSize(dev); + //=========================== + target_pkt.offset = offset; + target_pkt.word_en= tmp_word_en; + //=========================== + }else{ + bContinual = FALSE; + } + #if (EFUSE_ERROE_HANDLE == 1) + WriteState=PG_STATE_HEADER; + repeat_times++; + if(repeat_times>EFUSE_REPEAT_THRESHOLD_){ + bContinual = FALSE; + bResult = FALSE; + } + #endif + } + else{//************ so-2-2-B ******************* + //reorganize other pg packet + efuse_addr = efuse_addr + (2*tmp_word_cnts) +1;//next pg packet addr + //=========================== + target_pkt.offset = offset; + target_pkt.word_en= target_pkt.word_en; + //=========================== + #if (EFUSE_ERROE_HANDLE == 1) + WriteState=PG_STATE_HEADER; + #endif + } + } + } + printk("EFUSE PG_STATE_HEADER-1\n"); + } + else //************ s1: header == oxff ******************* + { + pg_header = ((target_pkt.offset << 4)&0xf0) |target_pkt.word_en; + + efuse_OneByteWrite(dev,efuse_addr, pg_header); + efuse_OneByteRead(dev,efuse_addr, &tmp_header); + + if(tmp_header == pg_header) + { //************ s1-1******************* + WriteState = PG_STATE_DATA; + } + #if (EFUSE_ERROE_HANDLE == 1) + else if(tmp_header == 0xFF){//************ s1-3: if Write or read func doesn't work ******************* + //efuse_addr doesn't change + WriteState = PG_STATE_HEADER; + repeat_times++; + if(repeat_times>EFUSE_REPEAT_THRESHOLD_){ + bContinual = FALSE; + bResult = FALSE; + } + } + #endif + else + {//************ s1-2 : fixed the header procedure ******************* + tmp_pkt.offset = (tmp_header>>4) & 0x0F; + tmp_pkt.word_en= tmp_header & 0x0F; + tmp_word_cnts = efuse_CalculateWordCnts(tmp_pkt.word_en); + + //************ s1-2-A :cover the exist data ******************* + memset(originaldata,0xff,sizeof(u8)*8); + //PlatformFillMemory((PVOID)originaldata, sizeof(u8)*8, 0xff); + + if(efuse_PgPacketRead( dev, tmp_pkt.offset,originaldata)) + { //check if data exist + //efuse_reg_ctrl(pAdapter,TRUE);//power on + badworden = efuse_WordEnableDataWrite(dev,efuse_addr+1,tmp_pkt.word_en,originaldata); + //############################ + if(0x0F != (badworden&0x0F)) + { + u8 reorg_offset = tmp_pkt.offset; + u8 reorg_worden=badworden; + efuse_PgPacketWrite(dev,reorg_offset,reorg_worden,originaldata); + efuse_addr = efuse_GetCurrentSize(dev); + } + //############################ + else{ + efuse_addr = efuse_addr + (tmp_word_cnts*2) +1; //Next pg_packet + } + } + //************ s1-2-B: wrong address******************* + else + { + efuse_addr = efuse_addr + (tmp_word_cnts*2) +1; //Next pg_packet + } + + #if (EFUSE_ERROE_HANDLE == 1) + WriteState=PG_STATE_HEADER; + repeat_times++; + if(repeat_times>EFUSE_REPEAT_THRESHOLD_){ + bContinual = FALSE; + bResult = FALSE; + } + #endif + + printk("EFUSE PG_STATE_HEADER-2\n"); + } + + } + + } + //write data state + else if(WriteState==PG_STATE_DATA) + { //************ s1-1 ******************* + printk("EFUSE PG_STATE_DATA\n"); + badworden = 0x0f; + badworden = efuse_WordEnableDataWrite(dev,efuse_addr+1,target_pkt.word_en,target_pkt.data); + if((badworden&0x0F)==0x0F) + { //************ s1-1-A ******************* + bContinual = FALSE; + } + else + {//reorganize other pg packet //************ s1-1-B ******************* + efuse_addr = efuse_addr + (2*target_word_cnts) +1;//next pg packet addr + + //=========================== + target_pkt.offset = offset; + target_pkt.word_en= badworden; + target_word_cnts = efuse_CalculateWordCnts(target_pkt.word_en); + //=========================== + #if (EFUSE_ERROE_HANDLE == 1) + WriteState=PG_STATE_HEADER; + repeat_times++; + if(repeat_times>EFUSE_REPEAT_THRESHOLD_){ + bContinual = FALSE; + bResult = FALSE; + } + #endif + printk("EFUSE PG_STATE_HEADER-3\n"); + } + } + } + + //efuse_reg_ctrl(pAdapter,FALSE);//power off + + return TRUE; +} // efuse_PgPacketWrite + + +/*----------------------------------------------------------------------------- + * Function: efuse_WordEnableDataRead + * + * Overview: Read allowed word in current efuse section data. + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 11/16/2008 MHC Create Version 0. + * 11/21/2008 MHC Fix Write bug when we only enable late word. + * + *---------------------------------------------------------------------------*/ +static void +efuse_WordEnableDataRead( u8 word_en,u8 *sourdata,u8 *targetdata) +{ + //u8 tmpindex = 0; + + //DbgPrint("efuse_WordEnableDataRead word_en = %x\n", word_en); + + //RT_PRINT_DATA(COMP_EFUSE, DBG_LOUD, ("sourdata\n"), sourdata, 8); + //RT_PRINT_DATA(COMP_EFUSE, DBG_LOUD, ("targetdata\n"), targetdata, 8); + + if (!(word_en&BIT0)) + { + targetdata[0] = sourdata[0];//sourdata[tmpindex++]; + targetdata[1] = sourdata[1];//sourdata[tmpindex++]; + } + if (!(word_en&BIT1)) + { + targetdata[2] = sourdata[2];//sourdata[tmpindex++]; + targetdata[3] = sourdata[3];//sourdata[tmpindex++]; + } + if (!(word_en&BIT2)) + { + targetdata[4] = sourdata[4];//sourdata[tmpindex++]; + targetdata[5] = sourdata[5];//sourdata[tmpindex++]; + } + if (!(word_en&BIT3)) + { + targetdata[6] = sourdata[6];//sourdata[tmpindex++]; + targetdata[7] = sourdata[7];//sourdata[tmpindex++]; + } +} // efuse_WordEnableDataRead + + +/*----------------------------------------------------------------------------- + * Function: efuse_WordEnableDataWrite + * + * Overview: Write necessary word unit into current efuse section! + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 11/16/2008 MHC Reorganize Efuse operate flow!!. + * + *---------------------------------------------------------------------------*/ +static u8 +efuse_WordEnableDataWrite( struct net_device* dev, u16 efuse_addr, u8 word_en, u8 *data) +{ + u16 tmpaddr = 0; + u16 start_addr = efuse_addr; + u8 badworden = 0x0F; + //u8 NextState; + u8 tmpdata[8]; + + memset(tmpdata,0xff,PGPKT_DATA_SIZE); + //PlatformFillMemory((PVOID)tmpdata, PGPKT_DATA_SIZE, 0xff); + + //RT_TRACE(COMP_EFUSE, "word_en = %x efuse_addr=%x\n", word_en, efuse_addr); + + //RT_PRINT_DATA(COMP_EFUSE, DBG_LOUD, ("U-EFUSE\n"), data, 8); + + if(!(word_en&BIT0)) + { + tmpaddr = start_addr; + efuse_OneByteWrite(dev,start_addr++, data[0]); + efuse_OneByteWrite(dev,start_addr++, data[1]); + + efuse_OneByteRead(dev,tmpaddr, &tmpdata[0]); + efuse_OneByteRead(dev,tmpaddr+1, &tmpdata[1]); + if((data[0]!=tmpdata[0])||(data[1]!=tmpdata[1])){ + badworden &= (~BIT0); + } + } + if(!(word_en&BIT1)) + { + tmpaddr = start_addr; + efuse_OneByteWrite(dev,start_addr++, data[2]); + efuse_OneByteWrite(dev,start_addr++, data[3]); + + efuse_OneByteRead(dev,tmpaddr , &tmpdata[2]); + efuse_OneByteRead(dev,tmpaddr+1, &tmpdata[3]); + if((data[2]!=tmpdata[2])||(data[3]!=tmpdata[3])){ + badworden &=( ~BIT1); + } + } + if(!(word_en&BIT2)) + { + tmpaddr = start_addr; + efuse_OneByteWrite(dev,start_addr++, data[4]); + efuse_OneByteWrite(dev,start_addr++, data[5]); + + efuse_OneByteRead(dev,tmpaddr, &tmpdata[4]); + efuse_OneByteRead(dev,tmpaddr+1, &tmpdata[5]); + if((data[4]!=tmpdata[4])||(data[5]!=tmpdata[5])){ + badworden &=( ~BIT2); + } + } + if(!(word_en&BIT3)) + { + tmpaddr = start_addr; + efuse_OneByteWrite(dev,start_addr++, data[6]); + efuse_OneByteWrite(dev,start_addr++, data[7]); + + efuse_OneByteRead(dev,tmpaddr, &tmpdata[6]); + efuse_OneByteRead(dev,tmpaddr+1, &tmpdata[7]); + if((data[6]!=tmpdata[6])||(data[7]!=tmpdata[7])){ + badworden &=( ~BIT3); + } + } + return badworden; +} // efuse_WordEnableDataWrite + + +/*----------------------------------------------------------------------------- + * Function: efuse_PowerSwitch + * + * Overview: When we want to enable write operation, we should change to + * pwr on state. When we stop write, we should switch to 500k mode + * and disable LDO 2.5V. + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 11/17/2008 MHC Create Version 0. + * + *---------------------------------------------------------------------------*/ +static void +efuse_PowerSwitch(struct net_device* dev, u8 PwrState) +{ + u8 tempval; + if (PwrState == TRUE) + { + // Enable LDO 2.5V for write action + tempval = read_nic_byte(dev, EFUSE_TEST+3); + write_nic_byte(dev, EFUSE_TEST+3, (tempval | 0x80)); + + // Change Efuse Clock for write action to 40MHZ + write_nic_byte(dev, EFUSE_CLK, 0x03); + } + else + { + // Enable LDO 2.5V for write action + tempval = read_nic_byte(dev, EFUSE_TEST+3); + write_nic_byte(dev, EFUSE_TEST+3, (tempval & 0x7F)); + + // Change Efuse Clock for write action to 500K + write_nic_byte(dev, EFUSE_CLK, 0x02); + } + +} /* efuse_PowerSwitch */ + + +/*----------------------------------------------------------------------------- + * Function: efuse_GetCurrentSize + * + * Overview: Get current efuse size!!! + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 11/16/2008 MHC Create Version 0. + * + *---------------------------------------------------------------------------*/ +static u16 +efuse_GetCurrentSize(struct net_device* dev) +{ + bool bContinual = TRUE; + + u16 efuse_addr = 0; + u8 hoffset=0,hworden=0; + u8 efuse_data,word_cnts=0; + + //efuse_reg_ctrl(pAdapter,TRUE);//power on + + while ( bContinual && + efuse_OneByteRead(dev, efuse_addr ,&efuse_data) && + (efuse_addr < EFUSE_MAX_SIZE) ) + { + if(efuse_data!=0xFF) + { + hoffset = (efuse_data>>4) & 0x0F; + hworden = efuse_data & 0x0F; + word_cnts = efuse_CalculateWordCnts(hworden); + //read next header + efuse_addr = efuse_addr + (word_cnts*2)+1; + } + else + { + bContinual = FALSE ; + } + } + + //efuse_reg_ctrl(pAdapter,FALSE);//power off + + return efuse_addr; + +} // efuse_GetCurrentSize} + + +/* 11/16/2008 MH Add description. Get current efuse area enabled word!!. */ +static u8 +efuse_CalculateWordCnts(u8 word_en) +{ + u8 word_cnts = 0; + if(!(word_en & BIT0)) word_cnts++; // 0 : write enable + if(!(word_en & BIT1)) word_cnts++; + if(!(word_en & BIT2)) word_cnts++; + if(!(word_en & BIT3)) word_cnts++; + return word_cnts; +} // efuse_CalculateWordCnts + + +/*----------------------------------------------------------------------------- + * Function: efuse_ResetLoader + * + * Overview: When read Efuse Fail we must reset loader!!!! + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 11/22/2008 MHC Create Version 0. + * + *---------------------------------------------------------------------------*/ +#if 0 +static void efuse_ResetLoader(struct net_device* dev) +{ + u16 tmpU2b; + + // + // 2008/11/22 MH Sometimes, we may read efuse fail, for preventing the condition + // We have to reset loader. + // + tmpU2b = read_nic_word(dev, SYS_FUNC_EN); + write_nic_word(dev, SYS_FUNC_EN, (tmpU2b&~(BIT12))); + //PlatformStallExecution(10000); // How long should we delay!!! + mdelay(10); + write_nic_word(dev, SYS_FUNC_EN, (tmpU2b|BIT12)); + //PlatformStallExecution(10000); // How long should we delay!!! + mdelay(10); + +} // efuse_ResetLoader +#endif + +/*----------------------------------------------------------------------------- + * Function: EFUSE_ProgramMap + * + * Overview: Read EFUSE map file and execute PG. + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 11/10/2008 MHC Create Version 0. + * + *---------------------------------------------------------------------------*/ + #ifdef TO_DO_LIST +extern bool // 0=Shadow 1=Real Efuse +EFUSE_ProgramMap(struct net_device* dev, char* pFileName,u8 TableType) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + s4Byte nLinesRead, ithLine; + RT_STATUS rtStatus = RT_STATUS_SUCCESS; + char* szLine; + u32 u4bRegValue, u4RegMask; + u32 u4bMove; + u16 index = 0; + u16 i; + u8 eeprom[HWSET_MAX_SIZE_92S]; + + rtStatus = PlatformReadFile( + dev, + pFileName, + (u8*)(priv->BufOfLines), + MAX_LINES_HWCONFIG_TXT, + MAX_BYTES_LINE_HWCONFIG_TXT, + &nLinesRead + ); + + if(rtStatus == RT_STATUS_SUCCESS) + { + memcp(pHalData->BufOfLines3, pHalData->BufOfLines, + nLinesRead*MAX_BYTES_LINE_HWCONFIG_TXT); + pHalData->nLinesRead3 = nLinesRead; + } + + if(rtStatus == RT_STATUS_SUCCESS) + { + printk("szEepromFile(): read %s ok\n", pFileName); + for(ithLine = 0; ithLine < nLinesRead; ithLine++) + { + szLine = pHalData->BufOfLines[ithLine]; + printk("Line-%d String =%s\n", ithLine, szLine); + + if(!IsCommentString(szLine)) + { + // EEPROM map one line has 8 words content. + for (i = 0; i < 8; i++) + { + u32 j; + + //GetHexValueFromString(szLine, &u4bRegValue, &u4bMove); + efuse_ParsingMap(szLine, &u4bRegValue, &u4bMove); + + // Get next hex value as EEPROM value. + szLine += u4bMove; + //WriteEEprom(dev, (u16)(ithLine*8+i), (u16)u4bRegValue); + eeprom[index++] = (u8)(u4bRegValue&0xff); + eeprom[index++] = (u8)((u4bRegValue>>8)&0xff); + + printk("Addr-%d = %x\n", (ithLine*8+i), u4bRegValue); + } + } + + } + + } + else + { + printk("szEepromFile(): Fail read%s\n", pFileName); + return RT_STATUS_FAILURE; + } + + + //RT_PRINT_DATA(COMP_EFUSE, DBG_LOUD, ("EFUSE "), eeprom, HWSET_MAX_SIZE_92S); + + // Use map file to update real Efuse or shadow modify table. + if (TableType == 1) + { + efuse_WriteAllMap(dev, eeprom, HWSET_MAX_SIZE_92S); + } + else + { + // Modify shadow table. + for (i = 0; i < HWSET_MAX_SIZE_92S; i++) + EFUSE_ShadowWrite(dev, 1, i, (u32)eeprom[i]); + } + + return rtStatus; +} /* EFUSE_ProgramMap */ + +#endif + +// +// Description: +// Return TRUE if chTmp is represent for hex digit and +// FALSE otherwise. +// +// +bool IsHexDigit( char chTmp) +{ + if( (chTmp >= '0' && chTmp <= '9') || + (chTmp >= 'a' && chTmp <= 'f') || + (chTmp >= 'A' && chTmp <= 'F') ) + { + return TRUE; + } + else + { + return FALSE; + } +} + +// +// Description: +// Translate a character to hex digit. +// +u32 MapCharToHexDigit(char chTmp) +{ + if(chTmp >= '0' && chTmp <= '9') + return (chTmp - '0'); + else if(chTmp >= 'a' && chTmp <= 'f') + return (10 + (chTmp - 'a')); + else if(chTmp >= 'A' && chTmp <= 'F') + return (10 + (chTmp - 'A')); + else + return 0; +} + +/*----------------------------------------------------------------------------- + * Function: efuse_ParsingMap + * + * Overview: + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 11/08/2008 MHC Create Version 0. + * + *---------------------------------------------------------------------------*/ +#ifdef TO_DO_LIST +static bool +efuse_ParsingMap(char* szStr,u32* pu4bVal,u32* pu4bMove) +{ + char* szScan = szStr; + + // Check input parameter. + if(szStr == NULL || pu4bVal == NULL || pu4bMove == NULL) + { + //RT_TRACE(COMP_EFUSE, + //"eeprom_ParsingMap(): Invalid IN args! szStr: %p, pu4bVal: %p, pu4bMove: %p\n", + //szStr, pu4bVal, pu4bMove); + return FALSE; + } + + // Initialize output. + *pu4bMove = 0; + *pu4bVal = 0; + + // Skip leading space. + while( *szScan != '\0' && + (*szScan == ' ' || *szScan == '\t') ) + { + szScan++; + (*pu4bMove)++; + } + + // Check if szScan is now pointer to a character for hex digit, + // if not, it means this is not a valid hex number. + if(!IsHexDigit(*szScan)) + { + return FALSE; + } + + // Parse each digit. + do + { + (*pu4bVal) <<= 4; + *pu4bVal += MapCharToHexDigit(*szScan); + + szScan++; + (*pu4bMove)++; + } while(IsHexDigit(*szScan)); + + return TRUE; + +} /* efuse_ParsingMap */ +#endif + +// +// Useless Section Code Now!!!!!! +// +// Porting from 8712 SDIO +int efuse_one_byte_rw(struct net_device* dev, u8 bRead, u16 addr, u8 *data) +{ + u32 bResult; + //u8 efuse_ctlreg,tmpidx = 0; + u8 tmpidx = 0; + u8 tmpv8=0; + + // -----------------e-fuse reg ctrl --------------------------------- + + write_nic_byte(dev, EFUSE_CTRL+1, (u8)(addr&0xff)); //address + tmpv8 = ((u8)((addr>>8) &0x03) ) | (read_nic_byte(dev, EFUSE_CTRL+2)&0xFC ); + write_nic_byte(dev, EFUSE_CTRL+2, tmpv8); + + if(TRUE==bRead){ + + write_nic_byte(dev, EFUSE_CTRL+3, 0x72);//read cmd + + while(!(0x80 & read_nic_byte(dev, EFUSE_CTRL+3)) && (tmpidx<100) ){ + tmpidx++; + } + if(tmpidx<100){ + *data=read_nic_byte(dev, EFUSE_CTRL); + bResult = TRUE; + } + else + { + *data = 0; + bResult = FALSE; + } + + } + else{ + //return 0; + write_nic_byte(dev, EFUSE_CTRL, *data);//data + + write_nic_byte(dev, EFUSE_CTRL+3, 0xF2);//write cmd + + while((0x80 & read_nic_byte(dev, EFUSE_CTRL+3)) && (tmpidx<100) ){ + tmpidx++; + } + if(tmpidx<100) + { + *data=read_nic_byte(dev, EFUSE_CTRL); + bResult = TRUE; + } + else + { + *data = 0; + bResult = FALSE; + } + + } + return bResult; +} +//------------------------------------------------------------------------------ +void efuse_access(struct net_device* dev, u8 bRead,u16 start_addr, u8 cnts, u8 *data) +{ + u8 efuse_clk_ori,efuse_clk_new;//,tmp8; + u32 i = 0; + + if(start_addr>0x200) return; + //RT_TRACE(_module_rtl871x_mp_ioctl_c_,_drv_err_, + // ("\n ===> efuse_access [start_addr=0x%x cnts:%d dataarray:0x%08x Query Efuse].\n",start_addr,cnts,data)); + // -----------------SYS_FUNC_EN Digital Core Vdd enable --------------------------------- + efuse_clk_ori = read_nic_byte(dev,SYS_FUNC_EN+1); + efuse_clk_new = efuse_clk_ori|0x20; + + if(efuse_clk_new!= efuse_clk_ori){ + //RT_TRACE(_module_rtl871x_mp_ioctl_c_,_drv_err_,("====write 0x10250003=====\n")); + write_nic_byte(dev, SYS_FUNC_EN+1, efuse_clk_new); + } +#ifdef _POWERON_DELAY_ + mdelay(10); +#endif + // -----------------e-fuse pwr & clk reg ctrl --------------------------------- + write_nic_byte(dev, EFUSE_TEST+3, (read_nic_byte(dev, EFUSE_TEST+3)|0x80)); + write_nic_byte(dev, EFUSE_CLK_CTRL, (read_nic_byte(dev, EFUSE_CLK_CTRL)|0x03)); + +#ifdef _PRE_EXECUTE_READ_CMD_ + { + unsigned char tmpdata; + efuse_OneByteRead(dev, 0,&tmpdata); + } +#endif + + //-----------------e-fuse one byte read / write ------------------------------ + for(i=0;iefuse_access addr:0x%02x value:0x%02x\n",data+i,*(data+i))); + } + // -----------------e-fuse pwr & clk reg ctrl --------------------------------- + write_nic_byte(dev, EFUSE_TEST+3, read_nic_byte(dev, EFUSE_TEST+3)&0x7f); + write_nic_byte(dev, EFUSE_CLK_CTRL, read_nic_byte(dev, EFUSE_CLK_CTRL)&0xfd); + + // -----------------SYS_FUNC_EN Digital Core Vdd disable --------------------------------- + if(efuse_clk_new != efuse_clk_ori) write_nic_byte(dev, 0x10250003, efuse_clk_ori); + +} +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +#ifdef TO_DO_LIST +static void efuse_reg_ctrl(struct net_device* dev, u8 bPowerOn) +{ + if(TRUE==bPowerOn){ + // -----------------SYS_FUNC_EN Digital Core Vdd enable --------------------------------- + write_nic_byte(dev, SYS_FUNC_EN+1, read_nic_byte(dev,SYS_FUNC_EN+1)|0x20); +#ifdef _POWERON_DELAY_ + mdelay(10); +#endif + // -----------------e-fuse pwr & clk reg ctrl --------------------------------- + write_nic_byte(dev, EFUSE_TEST+4, (read_nic_byte(dev, EFUSE_TEST+4)|0x80)); + write_nic_byte(dev, EFUSE_CLK_CTRL, (read_nic_byte(dev, EFUSE_CLK_CTRL)|0x03)); +#ifdef _PRE_EXECUTE_READ_CMD_ + { + unsigned char tmpdata; + efuse_OneByteRead(dev, 0,&tmpdata); + } + +#endif + } + else{ + // -----------------e-fuse pwr & clk reg ctrl --------------------------------- + write_nic_byte(dev, EFUSE_TEST+4, read_nic_byte(dev, EFUSE_TEST+4)&0x7f); + write_nic_byte(dev, EFUSE_CLK_CTRL, read_nic_byte(dev, EFUSE_CLK_CTRL)&0xfd); + // -----------------SYS_FUNC_EN Digital Core Vdd disable --------------------------------- + + //write_nic_byte(pAdapter, SYS_FUNC_EN+1, read_nic_byte(pAdapter,SYS_FUNC_EN+1)&0xDF); + } + + +} +#endif +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void efuse_read_data(struct net_device* dev,u8 efuse_read_item,u8 *data,u32 data_size) +{ + u8 offset, word_start,byte_start,byte_cnts; + u8 efusedata[EFUSE_MAC_LEN]; + u8 *tmpdata = NULL; + + u8 pg_pkt_cnts ; + + u8 tmpidx; + u8 pg_data[8]; + //u8 temp_value[8] = {0xff}; + + if(efuse_read_item> (sizeof(RTL8712_SDIO_EFUSE_TABLE)/sizeof(EFUSE_MAP))){ + //error msg + return ; + } + + offset = RTL8712_SDIO_EFUSE_TABLE[efuse_read_item].offset ; + word_start = RTL8712_SDIO_EFUSE_TABLE[efuse_read_item].word_start; + byte_start = RTL8712_SDIO_EFUSE_TABLE[efuse_read_item].byte_start; + byte_cnts = RTL8712_SDIO_EFUSE_TABLE[efuse_read_item].byte_cnts; + + if(data_size!=byte_cnts){ + //error msg + return; + } + + pg_pkt_cnts = (byte_cnts /PGPKT_DATA_SIZE) +1; + + if(pg_pkt_cnts > 1){ + //tmpdata = _malloc(pg_pkt_cnts*PGPKT_DATA_SIZE); + tmpdata = efusedata; + + if(tmpdata!=NULL) + { + memset(tmpdata,0xff,pg_pkt_cnts*PGPKT_DATA_SIZE); + //PlatformFillMemory((PVOID)pg_data, pg_pkt_cnts*PGPKT_DATA_SIZE, 0xff); + + for(tmpidx=0;tmpidx (sizeof(RTL8712_SDIO_EFUSE_TABLE)/sizeof(EFUSE_MAP))){ + //error msg + return ; + } + + offset = RTL8712_SDIO_EFUSE_TABLE[efuse_write_item].offset ; + word_start = RTL8712_SDIO_EFUSE_TABLE[efuse_write_item].word_start; + byte_start = RTL8712_SDIO_EFUSE_TABLE[efuse_write_item].byte_start; + byte_cnts = RTL8712_SDIO_EFUSE_TABLE[efuse_write_item].byte_cnts; + + if(data_size > byte_cnts){ + //error msg + return; + } + pg_pkt_cnts = (byte_cnts /PGPKT_DATA_SIZE) +1; + word_cnts = byte_cnts /2 ; + + if(byte_cnts %2){ + word_cnts+=1; + } + if((byte_start==1)||((byte_cnts%2)==1)){//situation A + + if((efuse_write_item==EFUSE_F0CIS)||(efuse_write_item==EFUSE_F1CIS)){ + memset(pg_data,0xff,PGPKT_DATA_SIZE); + //PlatformFillMemory((PVOID)pg_data, PGPKT_DATA_SIZE, 0xff); + efuse_PgPacketRead(dev,offset,pg_data); + + if(efuse_write_item==EFUSE_F0CIS){ + word_en = 0x07; + memcpy(pg_data+word_start*2+byte_start,data,sizeof(u8)*2); + //PlatformMoveMemory((PVOID)(pg_data+word_start*2+byte_start), (PVOID)data, sizeof(u8)*2); + efuse_PgPacketWrite(dev,offset,word_en,pg_data+(word_start*2)); + + word_en = 0x00; + efuse_PgPacketWrite(dev,(offset+1),word_en,data+2); + + word_en = 0x00; + efuse_PgPacketRead(dev,offset+2,pg_data); + memcpy(pg_data,data+2+8,sizeof(u8)*7); + //PlatformMoveMemory((PVOID)(pg_data), (PVOID)(data+2+8), sizeof(u8)*7); + + efuse_PgPacketWrite(dev,(offset+2),word_en,pg_data); + } + else if(efuse_write_item==EFUSE_F1CIS){ + word_en = 0x07; + efuse_PgPacketRead(dev,offset,pg_data); + pg_data[7] = data[0]; + efuse_PgPacketWrite(dev,offset,word_en,pg_data+(word_start*2)); + + word_en = 0x00; + for(tmpidx = 0 ;tmpidx<(word_cnts/4);tmpidx++){ + efuse_PgPacketWrite(dev,(offset+1+tmpidx),word_en,data+1+(tmpidx*PGPKT_DATA_SIZE)); + } + } + + } + else{ + memset(pg_data,0xff,PGPKT_DATA_SIZE); + //PlatformFillMemory((PVOID)pg_data, PGPKT_DATA_SIZE, 0xff); + if((efuse_write_item==EFUSE_SDIO_SETTING)||(efuse_write_item==EFUSE_CCCR)){ + word_en = 0x0e ; + tmpbytes = 2; + } + else if(efuse_write_item == EFUSE_SDIO_MODE){ + word_en = 0x0d ; + tmpbytes = 2; + } + else if(efuse_write_item == EFUSE_OCR){ + word_en = 0x09 ; + tmpbytes = 4; + } + else if((efuse_write_item == EFUSE_EEPROM_VER)||(efuse_write_item==EFUSE_CHAN_PLAN)){ + word_en = 0x07 ; + tmpbytes = 2; + } + if(bWordUnit==TRUE){ + memcpy(pg_data+word_start*2 ,data,sizeof(u8)*tmpbytes); + //PlatformMoveMemory((PVOID)(pg_data+word_start*2), (PVOID)(data), sizeof(u8)*tmpbytes); + } + else{ + efuse_PgPacketRead(dev,offset,pg_data); + memcpy(pg_data+(2*word_start)+byte_start,data,sizeof(u8)*byte_cnts); + //PlatformMoveMemory((PVOID)(pg_data+(2*word_start)+byte_start), (PVOID)(data), sizeof(u8)*byte_cnts); + } + + efuse_PgPacketWrite(dev,offset,word_en,pg_data+(word_start*2)); + + } + + } + //======================================================================== + else if(pg_pkt_cnts>1){//situation B + if(word_start==0){ + word_en = 0x00; + for(tmpidx = 0 ;tmpidx<(word_cnts/4);tmpidx++) + { + efuse_PgPacketWrite(dev,(offset+tmpidx),word_en,data+(tmpidx*PGPKT_DATA_SIZE)); + } + word_en = 0x0f; + for(tmpidx= 0; tmpidx<(word_cnts%4) ; tmpidx++) + { + tmpbitmask =tmpidx; + word_en &= (~(EFUSE_BIT(tmpbitmask))); + //BIT0 + } + efuse_PgPacketWrite(dev,offset+(word_cnts/4),word_en,data+((word_cnts/4)*PGPKT_DATA_SIZE)); + }else + { + + } + } + //======================================================================== + else{//situation C + word_en = 0x0f; + for(tmpidx= 0; tmpidx + +#define MACPHY_ArrayLengthDTM 18 +#define MACPHY_Array_PGLengthDTM 30 +#define AGCTAB_ArrayLengthDTM 384 +#define AGCTAB_ArrayLength 384 + +#define BootArrayLengthDTM 344 +u8 Rtl8192PciEFwBootArrayDTM[BootArrayLengthDTM] = { +0x10,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x3c,0x08,0xbf,0xc0,0x25,0x08,0x00,0x08, +0x3c,0x09,0xb0,0x03,0xad,0x28,0x00,0x20,0x40,0x80,0x68,0x00,0x00,0x00,0x00,0x00, +0x3c,0x0a,0xd0,0x00,0x40,0x8a,0x60,0x00,0x00,0x00,0x00,0x00,0x3c,0x08,0x80,0x01, +0x25,0x08,0xbc,0xf0,0x24,0x09,0x00,0x01,0x3c,0x01,0x7f,0xff,0x34,0x21,0xff,0xff, +0x01,0x01,0x50,0x24,0x00,0x09,0x48,0x40,0x35,0x29,0x00,0x01,0x01,0x2a,0x10,0x2b, +0x14,0x40,0xff,0xfc,0x00,0x00,0x00,0x00,0x3c,0x0a,0x00,0x00,0x25,0x4a,0x00,0x00, +0x4c,0x8a,0x00,0x00,0x4c,0x89,0x08,0x00,0x00,0x00,0x00,0x00,0x3c,0x08,0x80,0x01, +0x25,0x08,0xbc,0xf0,0x3c,0x01,0x80,0x00,0x01,0x21,0x48,0x25,0x3c,0x0a,0xbf,0xc0, +0x25,0x4a,0x00,0x7c,0x3c,0x0b,0xb0,0x03,0xad,0x6a,0x00,0x20,0xad,0x00,0x00,0x00, +0x21,0x08,0x00,0x04,0x01,0x09,0x10,0x2b,0x14,0x40,0xff,0xf8,0x00,0x00,0x00,0x00, +0x3c,0x08,0x80,0x01,0x25,0x08,0x7f,0xff,0x24,0x09,0x00,0x01,0x3c,0x01,0x7f,0xff, +0x34,0x21,0xff,0xff,0x01,0x01,0x50,0x24,0x00,0x09,0x48,0x40,0x35,0x29,0x00,0x01, +0x01,0x2a,0x10,0x2b,0x14,0x40,0xff,0xfc,0x00,0x00,0x00,0x00,0x3c,0x0a,0x80,0x01, +0x25,0x4a,0x00,0x00,0x3c,0x01,0x7f,0xff,0x34,0x21,0xff,0xff,0x01,0x41,0x50,0x24, +0x3c,0x09,0x00,0x01,0x35,0x29,0x7f,0xff,0x4c,0x8a,0x20,0x00,0x4c,0x89,0x28,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x24,0x08,0x04,0x10, +0x00,0x00,0x00,0x00,0x40,0x88,0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x3c,0x08,0xbf,0xc0,0x00,0x00,0x00,0x00,0x8d,0x09,0x00,0x00,0x00,0x00,0x00,0x00, +0x3c,0x0a,0xbf,0xc0,0x25,0x4a,0x01,0x20,0x3c,0x0b,0xb0,0x03,0xad,0x6a,0x00,0x20, +0x3c,0x08,0xb0,0x03,0x8d,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x35,0x29,0x00,0x10, +0xad,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x3c,0x08,0x80,0x00,0x25,0x08,0x5f,0x84, +0x01,0x00,0x00,0x08,0x00,0x00,0x00,0x00,}; + +#define MainArrayLengthDTM 48368 +u8 Rtl8192PciEFwMainArrayDTM[MainArrayLengthDTM] = { +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x40,0x04,0x68,0x00,0x40,0x05,0x70,0x00,0x40,0x06,0x40,0x00,0x0c,0x00,0x17,0x50, +0x00,0x00,0x00,0x00,0x40,0x1a,0x68,0x00,0x33,0x5b,0x00,0x3c,0x17,0x60,0x00,0x09, +0x00,0x00,0x00,0x00,0x40,0x1b,0x60,0x00,0x00,0x00,0x00,0x00,0x03,0x5b,0xd0,0x24, +0x40,0x1a,0x70,0x00,0x03,0x40,0x00,0x08,0x42,0x00,0x00,0x10,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x3c,0x02,0xff,0xff,0x34,0x42,0xff,0xff,0x8c,0x43,0x00,0x00, +0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x34,0x63,0x00,0x20,0x24,0x42,0x00,0xd0, +0xac,0x62,0x00,0x00,0x00,0x00,0x20,0x21,0x27,0x85,0x91,0x50,0x00,0x85,0x18,0x21, +0x24,0x84,0x00,0x01,0x28,0x82,0x00,0x0a,0x14,0x40,0xff,0xfc,0xa0,0x60,0x00,0x00, +0x27,0x82,0x91,0x5a,0x24,0x04,0x00,0x06,0x24,0x84,0xff,0xff,0xa4,0x40,0x00,0x00, +0x04,0x81,0xff,0xfd,0x24,0x42,0x00,0x02,0x24,0x02,0x00,0x03,0xa3,0x82,0x91,0x50, +0x24,0x02,0x00,0x0a,0x24,0x03,0x09,0xc4,0xa3,0x82,0x91,0x52,0x24,0x02,0x00,0x04, +0x24,0x04,0x00,0x01,0x24,0x05,0x00,0x02,0xa7,0x83,0x91,0x66,0xa3,0x82,0x91,0x58, +0x24,0x03,0x04,0x00,0x24,0x02,0x02,0x00,0xaf,0x83,0x91,0x6c,0xa3,0x85,0x91,0x59, +0xa7,0x82,0x91,0x5a,0xa7,0x84,0x91,0x5c,0xaf,0x84,0x91,0x68,0xa3,0x84,0x91,0x51, +0xa3,0x80,0x91,0x53,0xa3,0x80,0x91,0x54,0xa3,0x80,0x91,0x55,0xa3,0x84,0x91,0x56, +0xa3,0x85,0x91,0x57,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03, +0x3c,0x02,0x80,0x00,0x24,0x42,0x01,0x7c,0x34,0x63,0x00,0x20,0xac,0x62,0x00,0x00, +0x27,0x84,0x91,0x78,0x00,0x00,0x10,0x21,0x24,0x42,0x00,0x01,0x00,0x02,0x16,0x00, +0x00,0x02,0x16,0x03,0x28,0x43,0x00,0x03,0xac,0x80,0xff,0xfc,0xa0,0x80,0x00,0x00, +0x14,0x60,0xff,0xf9,0x24,0x84,0x00,0x0c,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00, +0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x34,0x63,0x00,0x20,0x24,0x42,0x01,0xc0, +0x3c,0x08,0xb0,0x03,0xac,0x62,0x00,0x00,0x35,0x08,0x00,0x70,0x8d,0x02,0x00,0x00, +0x00,0xa0,0x48,0x21,0x00,0x04,0x26,0x00,0x00,0x02,0x2a,0x43,0x00,0x06,0x36,0x00, +0x00,0x07,0x3e,0x00,0x00,0x02,0x12,0x03,0x29,0x23,0x00,0x03,0x00,0x04,0x56,0x03, +0x00,0x06,0x36,0x03,0x00,0x07,0x3e,0x03,0x30,0x48,0x00,0x01,0x10,0x60,0x00,0x11, +0x30,0xa5,0x00,0x07,0x24,0x02,0x00,0x02,0x00,0x49,0x10,0x23,0x00,0x45,0x10,0x07, +0x30,0x42,0x00,0x01,0x10,0x40,0x00,0x66,0x00,0x00,0x00,0x00,0x8f,0xa2,0x00,0x10, +0x00,0x00,0x00,0x00,0x00,0x02,0x21,0x43,0x11,0x00,0x00,0x10,0x00,0x07,0x20,0x0b, +0x15,0x20,0x00,0x06,0x24,0x02,0x00,0x01,0x3c,0x02,0xb0,0x05,0x34,0x42,0x01,0x20, +0xa4,0x44,0x00,0x00,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x11,0x22,0x00,0x04, +0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x05,0x08,0x00,0x00,0x94,0x34,0x42,0x01,0x24, +0x3c,0x02,0xb0,0x05,0x08,0x00,0x00,0x94,0x34,0x42,0x01,0x22,0x15,0x20,0x00,0x54, +0x24,0x02,0x00,0x01,0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0x74,0x90,0x43,0x00,0x00, +0x00,0x00,0x00,0x00,0xaf,0x83,0x91,0x74,0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0x70, +0x90,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x6b,0x00,0x08,0x11,0x60,0x00,0x18, +0x00,0x09,0x28,0x40,0x00,0x00,0x40,0x21,0x27,0x85,0x91,0x70,0x8c,0xa3,0x00,0x00, +0x8c,0xa2,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x62,0x38,0x23,0x00,0x43,0x10,0x2a, +0x10,0x40,0x00,0x3d,0x00,0x00,0x00,0x00,0xac,0xa7,0x00,0x00,0x25,0x02,0x00,0x01, +0x00,0x02,0x16,0x00,0x00,0x02,0x46,0x03,0x29,0x03,0x00,0x03,0x14,0x60,0xff,0xf3, +0x24,0xa5,0x00,0x0c,0x3c,0x03,0xb0,0x03,0x34,0x63,0x00,0x70,0x90,0x62,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x4b,0x10,0x23,0xa0,0x62,0x00,0x00,0x00,0x09,0x28,0x40, +0x00,0xa9,0x10,0x21,0x00,0x02,0x10,0x80,0x27,0x83,0x91,0x78,0x00,0x0a,0x20,0x0b, +0x00,0x43,0x18,0x21,0x10,0xc0,0x00,0x05,0x00,0x00,0x38,0x21,0x80,0x62,0x00,0x01, +0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x05,0x00,0x00,0x00,0x00,0x80,0x62,0x00,0x00, +0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x03,0x00,0xa9,0x10,0x21,0x24,0x07,0x00,0x01, +0x00,0xa9,0x10,0x21,0x00,0x02,0x30,0x80,0x27,0x82,0x91,0x78,0xa0,0x67,0x00,0x01, +0x00,0xc2,0x38,0x21,0x80,0xe3,0x00,0x01,0x00,0x00,0x00,0x00,0x10,0x60,0x00,0x07, +0x00,0x00,0x00,0x00,0x27,0x83,0x91,0x70,0x00,0xc3,0x18,0x21,0x8c,0x62,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x44,0x10,0x21,0xac,0x62,0x00,0x00,0x27,0x85,0x91,0x74, +0x27,0x82,0x91,0x70,0x00,0xc5,0x28,0x21,0x00,0xc2,0x10,0x21,0x8c,0x43,0x00,0x00, +0x8c,0xa4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x64,0x18,0x2a,0x14,0x60,0x00,0x03, +0x24,0x02,0x00,0x01,0x03,0xe0,0x00,0x08,0xa0,0xe2,0x00,0x00,0xa0,0xe0,0x00,0x00, +0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0xb7,0xac,0xa0,0x00,0x00, +0x11,0x22,0x00,0x08,0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0x7c, +0x90,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0xaf,0x83,0x91,0x8c,0x08,0x00,0x00,0xa7, +0x3c,0x02,0xb0,0x03,0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0x78,0x90,0x43,0x00,0x00, +0x00,0x00,0x00,0x00,0xaf,0x83,0x91,0x80,0x08,0x00,0x00,0xa7,0x3c,0x02,0xb0,0x03, +0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x34,0x63,0x00,0x20,0x24,0x42,0x04,0x10, +0x3c,0x05,0xb0,0x03,0xac,0x62,0x00,0x00,0x34,0xa5,0x00,0x70,0x8c,0xa2,0x00,0x00, +0x90,0x84,0x00,0x08,0x3c,0x06,0xb0,0x03,0x00,0x02,0x16,0x00,0x2c,0x83,0x00,0x03, +0x34,0xc6,0x00,0x72,0x24,0x07,0x00,0x01,0x10,0x60,0x00,0x11,0x00,0x02,0x2f,0xc2, +0x90,0xc2,0x00,0x00,0x00,0x00,0x18,0x21,0x00,0x02,0x16,0x00,0x10,0xa7,0x00,0x09, +0x00,0x02,0x16,0x03,0x14,0x80,0x00,0x0c,0x30,0x43,0x00,0x03,0x83,0x82,0x91,0x78, +0x00,0x00,0x00,0x00,0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21,0x00,0x02,0x16,0x00, +0x00,0x02,0x1e,0x03,0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0x72,0xa0,0x43,0x00,0x00, +0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x30,0x45,0x00,0x05,0x10,0x87,0x00,0x04, +0x30,0x43,0x00,0x06,0x93,0x82,0x91,0x90,0x08,0x00,0x01,0x1f,0x00,0x43,0x10,0x21, +0x83,0x82,0x91,0x84,0x00,0x00,0x00,0x00,0x00,0x02,0x10,0x40,0x08,0x00,0x01,0x1f, +0x00,0x45,0x10,0x21,0x10,0x80,0x00,0x05,0x00,0x00,0x18,0x21,0x24,0x63,0x00,0x01, +0x00,0x64,0x10,0x2b,0x14,0x40,0xff,0xfd,0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08, +0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x24,0x42,0x04,0xe4, +0x3c,0x04,0xb0,0x02,0x34,0x63,0x00,0x20,0xac,0x62,0x00,0x00,0x34,0x84,0x00,0x08, +0x24,0x02,0x00,0x01,0xaf,0x84,0x91,0xa0,0xa3,0x82,0x91,0xb0,0xa7,0x80,0x91,0xa4, +0xa7,0x80,0x91,0xa6,0xaf,0x80,0x91,0xa8,0xaf,0x80,0x91,0xac,0x03,0xe0,0x00,0x08, +0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x34,0x63,0x00,0x20, +0x24,0x42,0x05,0x24,0x27,0xbd,0xff,0xe0,0xac,0x62,0x00,0x00,0xaf,0xb1,0x00,0x14, +0xaf,0xb0,0x00,0x10,0x00,0xa0,0x88,0x21,0xaf,0xbf,0x00,0x18,0x0c,0x00,0x01,0xe3, +0x00,0x80,0x80,0x21,0x02,0x00,0x20,0x21,0x10,0x40,0x00,0x05,0x02,0x20,0x28,0x21, +0x8f,0xbf,0x00,0x18,0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20, +0x0c,0x00,0x01,0xf9,0x00,0x00,0x00,0x00,0x08,0x00,0x01,0x58,0x00,0x00,0x00,0x00, +0x3c,0x02,0xb0,0x03,0x3c,0x03,0x80,0x00,0x34,0x42,0x00,0x20,0x24,0x63,0x05,0x80, +0x27,0xbd,0xff,0xe0,0xac,0x43,0x00,0x00,0xaf,0xb1,0x00,0x14,0xaf,0xb0,0x00,0x10, +0xaf,0xbf,0x00,0x18,0x8f,0x90,0x91,0xa0,0x0c,0x00,0x01,0xe3,0x00,0x80,0x88,0x21, +0x14,0x40,0x00,0x2a,0x3c,0x02,0x00,0x80,0x16,0x20,0x00,0x02,0x34,0x42,0x02,0x01, +0x24,0x02,0x02,0x01,0xae,0x02,0x00,0x00,0x97,0x84,0x91,0xa4,0x97,0x82,0x91,0xa6, +0x3c,0x03,0xb0,0x02,0x00,0x83,0x20,0x21,0x24,0x42,0x00,0x04,0xa7,0x82,0x91,0xa6, +0xa4,0x82,0x00,0x00,0x8f,0x84,0x91,0xa8,0x8f,0x82,0x91,0xa0,0x93,0x85,0x91,0x52, +0x24,0x84,0x00,0x01,0x24,0x42,0x00,0x04,0x24,0x03,0x8f,0xff,0x3c,0x07,0xb0,0x06, +0x3c,0x06,0xb0,0x03,0x00,0x43,0x10,0x24,0x00,0x85,0x28,0x2a,0x34,0xe7,0x80,0x18, +0xaf,0x82,0x91,0xa0,0xaf,0x84,0x91,0xa8,0x10,0xa0,0x00,0x08,0x34,0xc6,0x01,0x08, +0x8f,0x83,0x91,0xac,0x8f,0x84,0x91,0x6c,0x8c,0xc2,0x00,0x00,0x00,0x64,0x18,0x21, +0x00,0x43,0x10,0x2b,0x14,0x40,0x00,0x09,0x00,0x00,0x00,0x00,0x8c,0xe2,0x00,0x00, +0x3c,0x03,0x0f,0x00,0x3c,0x04,0x04,0x00,0x00,0x43,0x10,0x24,0x10,0x44,0x00,0x03, +0x00,0x00,0x00,0x00,0x0c,0x00,0x03,0x95,0x00,0x00,0x00,0x00,0x8f,0xbf,0x00,0x18, +0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20,0x27,0xbd,0xff,0xd8, +0x3c,0x02,0xb0,0x03,0x3c,0x03,0x80,0x00,0x24,0x63,0x06,0x6c,0xaf,0xb0,0x00,0x10, +0x34,0x42,0x00,0x20,0x8f,0x90,0x91,0xa0,0xac,0x43,0x00,0x00,0xaf,0xb3,0x00,0x1c, +0xaf,0xb2,0x00,0x18,0xaf,0xb1,0x00,0x14,0xaf,0xbf,0x00,0x20,0x00,0x80,0x88,0x21, +0x00,0xa0,0x90,0x21,0x0c,0x00,0x01,0xe3,0x00,0xc0,0x98,0x21,0x24,0x07,0x8f,0xff, +0x14,0x40,0x00,0x19,0x26,0x03,0x00,0x04,0x24,0x02,0x0e,0x03,0xae,0x02,0x00,0x00, +0x00,0x67,0x80,0x24,0x26,0x02,0x00,0x04,0xae,0x11,0x00,0x00,0x00,0x47,0x80,0x24, +0x97,0x86,0x91,0xa4,0x26,0x03,0x00,0x04,0xae,0x12,0x00,0x00,0x00,0x67,0x80,0x24, +0xae,0x13,0x00,0x00,0x8f,0x84,0x91,0xa0,0x3c,0x02,0xb0,0x02,0x97,0x85,0x91,0xa6, +0x00,0xc2,0x30,0x21,0x8f,0x82,0x91,0xa8,0x24,0x84,0x00,0x10,0x24,0xa5,0x00,0x10, +0x00,0x87,0x20,0x24,0x24,0x42,0x00,0x01,0xa7,0x85,0x91,0xa6,0xaf,0x84,0x91,0xa0, +0xaf,0x82,0x91,0xa8,0xa4,0xc5,0x00,0x00,0x8f,0xbf,0x00,0x20,0x7b,0xb2,0x00,0xfc, +0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x28,0x87,0x83,0x88,0x86, +0x93,0x82,0x80,0x11,0x00,0x00,0x00,0x00,0x10,0x62,0x00,0x08,0x00,0x00,0x00,0x00, +0x93,0x83,0x88,0x87,0x24,0x02,0x00,0x01,0xa3,0x82,0x80,0x10,0xa3,0x83,0x80,0x12, +0xa3,0x83,0x80,0x11,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x93,0x82,0x80,0x12, +0x00,0x00,0x00,0x00,0x14,0x62,0xff,0xf6,0x00,0x00,0x00,0x00,0x08,0x00,0x01,0xd5, +0x00,0x00,0x00,0x00,0x30,0x84,0x00,0xff,0x14,0x80,0x00,0x02,0x00,0x00,0x00,0x00, +0xa3,0x85,0x8b,0x6b,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x93,0x82,0x91,0xb0, +0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x11,0x24,0x06,0x00,0x01,0x8f,0x82,0x91,0xa8, +0x3c,0x05,0xb0,0x06,0x3c,0x04,0xb0,0x03,0x34,0xa5,0x80,0x18,0x34,0x84,0x01,0x08, +0x14,0x40,0x00,0x09,0x00,0x00,0x30,0x21,0x97,0x82,0x91,0xa4,0x8c,0x84,0x00,0x00, +0x3c,0x03,0xb0,0x02,0x00,0x43,0x10,0x21,0xaf,0x84,0x91,0xac,0xa7,0x80,0x91,0xa6, +0xac,0x40,0x00,0x00,0xac,0x40,0x00,0x04,0x8c,0xa2,0x00,0x00,0x03,0xe0,0x00,0x08, +0x00,0xc0,0x10,0x21,0x8f,0x86,0x91,0xa0,0x8f,0x82,0x91,0xa8,0x27,0xbd,0xff,0xe8, +0xaf,0xbf,0x00,0x10,0x00,0xc0,0x40,0x21,0x14,0x40,0x00,0x0a,0x00,0x40,0x50,0x21, +0x00,0x00,0x38,0x21,0x27,0x89,0x8b,0x40,0x24,0xe2,0x00,0x01,0x00,0x07,0x18,0x80, +0x30,0x47,0x00,0xff,0x00,0x69,0x18,0x21,0x2c,0xe2,0x00,0x0a,0x14,0x40,0xff,0xfa, +0xac,0x60,0x00,0x00,0x3c,0x02,0x00,0x80,0x10,0x82,0x00,0x6d,0x00,0x00,0x00,0x00, +0x97,0x82,0x8b,0x46,0x00,0x00,0x00,0x00,0x24,0x42,0x00,0x01,0xa7,0x82,0x8b,0x46, +0x90,0xa3,0x00,0x15,0x97,0x82,0x8b,0x48,0x00,0x03,0x1e,0x00,0x00,0x03,0x1e,0x03, +0x00,0x43,0x10,0x21,0xa7,0x82,0x8b,0x48,0x8c,0xa4,0x00,0x20,0x3c,0x02,0x00,0x60, +0x3c,0x03,0x00,0x20,0x00,0x82,0x20,0x24,0x10,0x83,0x00,0x52,0x00,0x00,0x00,0x00, +0x14,0x80,0x00,0x45,0x00,0x00,0x00,0x00,0x97,0x82,0x8b,0x4c,0x00,0x00,0x00,0x00, +0x24,0x42,0x00,0x01,0xa7,0x82,0x8b,0x4c,0x84,0xa3,0x00,0x06,0x8f,0x82,0x8b,0x5c, +0x00,0x00,0x00,0x00,0x00,0x43,0x10,0x21,0xaf,0x82,0x8b,0x5c,0x25,0x42,0x00,0x01, +0x28,0x43,0x27,0x10,0xaf,0x82,0x91,0xa8,0x10,0x60,0x00,0x09,0x24,0x02,0x00,0x04, +0x93,0x83,0x80,0x10,0x24,0x02,0x00,0x01,0x10,0x62,0x00,0x05,0x24,0x02,0x00,0x04, +0x8f,0xbf,0x00,0x10,0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18, +0x24,0x03,0x00,0x28,0xa3,0x83,0x8b,0x42,0xa3,0x82,0x8b,0x43,0x90,0xa2,0x00,0x18, +0x93,0x83,0x8b,0x6b,0x00,0x00,0x38,0x21,0x00,0x02,0x16,0x00,0x00,0x02,0x16,0x03, +0xa7,0x82,0x8b,0x56,0xa3,0x83,0x8b,0x64,0x27,0x89,0x8b,0x40,0x24,0x05,0x8f,0xff, +0x00,0x07,0x10,0x80,0x00,0x49,0x10,0x21,0x8c,0x44,0x00,0x00,0x24,0xe3,0x00,0x01, +0x30,0x67,0x00,0xff,0x25,0x02,0x00,0x04,0x2c,0xe3,0x00,0x0a,0xad,0x04,0x00,0x00, +0x14,0x60,0xff,0xf7,0x00,0x45,0x40,0x24,0x97,0x83,0x91,0xa6,0x97,0x85,0x91,0xa4, +0x3c,0x02,0xb0,0x02,0x24,0x63,0x00,0x28,0x00,0xa2,0x28,0x21,0x3c,0x04,0xb0,0x06, +0xa7,0x83,0x91,0xa6,0x34,0x84,0x80,0x18,0xa4,0xa3,0x00,0x00,0x8c,0x85,0x00,0x00, +0x24,0x02,0x8f,0xff,0x24,0xc6,0x00,0x28,0x3c,0x03,0x0f,0x00,0x00,0xc2,0x30,0x24, +0x00,0xa3,0x28,0x24,0x3c,0x02,0x04,0x00,0xaf,0x86,0x91,0xa0,0x10,0xa2,0xff,0xd4, +0x00,0x00,0x00,0x00,0xa3,0x80,0x80,0x10,0x0c,0x00,0x03,0x95,0x00,0x00,0x00,0x00, +0x08,0x00,0x02,0x30,0x00,0x00,0x00,0x00,0x97,0x82,0x8b,0x4e,0x00,0x00,0x00,0x00, +0x24,0x42,0x00,0x01,0xa7,0x82,0x8b,0x4e,0x84,0xa3,0x00,0x06,0x8f,0x82,0x8b,0x60, +0x00,0x00,0x00,0x00,0x00,0x43,0x10,0x21,0xaf,0x82,0x8b,0x60,0x08,0x00,0x02,0x28, +0x25,0x42,0x00,0x01,0x97,0x82,0x8b,0x4a,0x00,0x00,0x00,0x00,0x24,0x42,0x00,0x01, +0xa7,0x82,0x8b,0x4a,0x84,0xa3,0x00,0x06,0x8f,0x82,0x8b,0x58,0x00,0x00,0x00,0x00, +0x00,0x43,0x10,0x21,0xaf,0x82,0x8b,0x58,0x08,0x00,0x02,0x28,0x25,0x42,0x00,0x01, +0x97,0x82,0x8b,0x44,0x00,0x00,0x00,0x00,0x24,0x42,0x00,0x01,0xa7,0x82,0x8b,0x44, +0x08,0x00,0x02,0x10,0x00,0x00,0x00,0x00,0x3c,0x05,0xb0,0x03,0x3c,0x02,0x80,0x00, +0x27,0xbd,0xff,0xc8,0x00,0x04,0x22,0x00,0x34,0xa5,0x00,0x20,0x24,0x42,0x09,0xf8, +0x3c,0x03,0xb0,0x00,0xaf,0xb5,0x00,0x24,0xaf,0xb4,0x00,0x20,0xaf,0xb2,0x00,0x18, +0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x30,0x00,0x83,0x80,0x21,0xaf,0xb7,0x00,0x2c, +0xaf,0xb6,0x00,0x28,0xaf,0xb3,0x00,0x1c,0xaf,0xb1,0x00,0x14,0xac,0xa2,0x00,0x00, +0x8e,0x09,0x00,0x00,0x00,0x00,0x90,0x21,0x26,0x10,0x00,0x08,0x00,0x09,0xa6,0x02, +0x12,0x80,0x00,0x13,0x00,0x00,0xa8,0x21,0x24,0x13,0x00,0x02,0x3c,0x16,0x00,0xff, +0x3c,0x17,0xff,0x00,0x8e,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x09,0x12,0x02, +0x24,0x42,0x00,0x02,0x31,0x25,0x00,0xff,0x10,0xb3,0x00,0x76,0x30,0x51,0x00,0xff, +0x24,0x02,0x00,0x03,0x10,0xa2,0x00,0x18,0x00,0x00,0x00,0x00,0x02,0x51,0x10,0x21, +0x30,0x52,0xff,0xff,0x02,0x54,0x18,0x2b,0x14,0x60,0xff,0xf2,0x02,0x11,0x80,0x21, +0x12,0xa0,0x00,0x0a,0x3c,0x02,0xb0,0x06,0x34,0x42,0x80,0x18,0x8c,0x43,0x00,0x00, +0x3c,0x04,0x0f,0x00,0x3c,0x02,0x04,0x00,0x00,0x64,0x18,0x24,0x10,0x62,0x00,0x03, +0x00,0x00,0x00,0x00,0x0c,0x00,0x03,0x95,0x00,0x00,0x00,0x00,0x8f,0xbf,0x00,0x30, +0x7b,0xb6,0x01,0x7c,0x7b,0xb4,0x01,0x3c,0x7b,0xb2,0x00,0xfc,0x7b,0xb0,0x00,0xbc, +0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x38,0x8e,0x09,0x00,0x04,0x24,0x15,0x00,0x01, +0x8e,0x06,0x00,0x0c,0x00,0x09,0x11,0x42,0x00,0x09,0x18,0xc2,0x30,0x48,0x00,0x03, +0x00,0x09,0x14,0x02,0x30,0x6c,0x00,0x03,0x00,0x09,0x26,0x02,0x11,0x15,0x00,0x45, +0x30,0x43,0x00,0x0f,0x29,0x02,0x00,0x02,0x14,0x40,0x00,0x26,0x00,0x00,0x00,0x00, +0x11,0x13,0x00,0x0f,0x00,0x00,0x38,0x21,0x00,0x07,0x22,0x02,0x30,0x84,0xff,0x00, +0x3c,0x03,0x00,0xff,0x00,0x07,0x2e,0x02,0x00,0x07,0x12,0x00,0x00,0x43,0x10,0x24, +0x00,0xa4,0x28,0x25,0x00,0xa2,0x28,0x25,0x00,0x07,0x1e,0x00,0x00,0xa3,0x28,0x25, +0x0c,0x00,0x01,0x9b,0x01,0x20,0x20,0x21,0x08,0x00,0x02,0xa4,0x02,0x51,0x10,0x21, +0x11,0x95,0x00,0x0f,0x00,0x00,0x00,0x00,0x11,0x88,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x04,0x10,0x80,0x27,0x83,0x91,0x50,0x00,0x43,0x10,0x21,0x8c,0x47,0x00,0x18, +0x08,0x00,0x02,0xcb,0x00,0x07,0x22,0x02,0x00,0x04,0x10,0x40,0x27,0x83,0x91,0x58, +0x00,0x43,0x10,0x21,0x94,0x47,0x00,0x02,0x08,0x00,0x02,0xcb,0x00,0x07,0x22,0x02, +0x27,0x82,0x91,0x50,0x00,0x82,0x10,0x21,0x90,0x47,0x00,0x00,0x08,0x00,0x02,0xcb, +0x00,0x07,0x22,0x02,0x15,0x00,0xff,0xdc,0x00,0x00,0x38,0x21,0x10,0x75,0x00,0x05, +0x00,0x80,0x38,0x21,0x00,0x65,0x18,0x26,0x24,0x82,0x01,0x00,0x00,0x00,0x38,0x21, +0x00,0x43,0x38,0x0a,0x24,0x02,0x00,0x01,0x11,0x82,0x00,0x0e,0x3c,0x02,0xb0,0x03, +0x24,0x02,0x00,0x02,0x11,0x82,0x00,0x06,0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x03, +0x00,0xe2,0x10,0x21,0x8c,0x47,0x00,0x00,0x08,0x00,0x02,0xcb,0x00,0x07,0x22,0x02, +0x3c,0x02,0xb0,0x03,0x00,0xe2,0x10,0x21,0x94,0x43,0x00,0x00,0x08,0x00,0x02,0xca, +0x30,0x67,0xff,0xff,0x00,0xe2,0x10,0x21,0x90,0x43,0x00,0x00,0x08,0x00,0x02,0xca, +0x30,0x67,0x00,0xff,0x30,0x62,0x00,0x03,0x00,0x02,0x12,0x00,0x11,0x95,0x00,0x07, +0x00,0x44,0x38,0x21,0x11,0x93,0x00,0x03,0x00,0x00,0x00,0x00,0x08,0x00,0x02,0xfc, +0x3c,0x02,0xb0,0x0a,0x08,0x00,0x03,0x01,0x3c,0x02,0xb0,0x0a,0x08,0x00,0x03,0x05, +0x3c,0x02,0xb0,0x0a,0x8e,0x09,0x00,0x04,0x8e,0x02,0x00,0x08,0x8e,0x03,0x00,0x0c, +0x00,0x09,0x41,0x42,0x00,0x02,0x22,0x02,0x00,0x03,0x3a,0x02,0x30,0x84,0xff,0x00, +0x30,0xe7,0xff,0x00,0x00,0x02,0x5e,0x02,0x00,0x02,0x32,0x00,0x00,0x03,0x56,0x02, +0x00,0x03,0x2a,0x00,0x01,0x64,0x58,0x25,0x00,0xd6,0x30,0x24,0x01,0x47,0x50,0x25, +0x00,0x02,0x16,0x00,0x00,0xb6,0x28,0x24,0x00,0x03,0x1e,0x00,0x01,0x66,0x58,0x25, +0x01,0x45,0x50,0x25,0x00,0x57,0x10,0x24,0x00,0x77,0x18,0x24,0x01,0x62,0x38,0x25, +0x01,0x43,0x30,0x25,0x00,0x09,0x10,0xc2,0x00,0x09,0x1c,0x02,0x31,0x08,0x00,0x03, +0x30,0x4c,0x00,0x03,0x30,0x63,0x00,0x0f,0x00,0x09,0x26,0x02,0x00,0xe0,0x58,0x21, +0x15,0x00,0x00,0x28,0x00,0xc0,0x50,0x21,0x24,0x02,0x00,0x01,0x10,0x62,0x00,0x06, +0x00,0x80,0x28,0x21,0x24,0x02,0x00,0x03,0x14,0x62,0xff,0x69,0x02,0x51,0x10,0x21, +0x24,0x85,0x01,0x00,0x24,0x02,0x00,0x01,0x11,0x82,0x00,0x15,0x24,0x02,0x00,0x02, +0x11,0x82,0x00,0x0a,0x3c,0x03,0xb0,0x03,0x00,0xa3,0x18,0x21,0x8c,0x62,0x00,0x00, +0x00,0x0a,0x20,0x27,0x01,0x6a,0x28,0x24,0x00,0x44,0x10,0x24,0x00,0x45,0x10,0x25, +0xac,0x62,0x00,0x00,0x08,0x00,0x02,0xa4,0x02,0x51,0x10,0x21,0x00,0xa3,0x18,0x21, +0x94,0x62,0x00,0x00,0x00,0x0a,0x20,0x27,0x01,0x6a,0x28,0x24,0x00,0x44,0x10,0x24, +0x00,0x45,0x10,0x25,0xa4,0x62,0x00,0x00,0x08,0x00,0x02,0xa4,0x02,0x51,0x10,0x21, +0x3c,0x03,0xb0,0x03,0x00,0xa3,0x18,0x21,0x90,0x62,0x00,0x00,0x00,0x0a,0x20,0x27, +0x01,0x6a,0x28,0x24,0x00,0x44,0x10,0x24,0x00,0x45,0x10,0x25,0x08,0x00,0x02,0xa3, +0xa0,0x62,0x00,0x00,0x24,0x02,0x00,0x01,0x11,0x02,0x00,0x21,0x00,0x00,0x00,0x00, +0x15,0x13,0xff,0x42,0x00,0x00,0x00,0x00,0x11,0x82,0x00,0x17,0x00,0x00,0x00,0x00, +0x11,0x88,0x00,0x0b,0x00,0x00,0x00,0x00,0x27,0x83,0x91,0x50,0x00,0x04,0x20,0x80, +0x00,0x83,0x20,0x21,0x8c,0x82,0x00,0x18,0x00,0x06,0x18,0x27,0x00,0xe6,0x28,0x24, +0x00,0x43,0x10,0x24,0x00,0x45,0x10,0x25,0x08,0x00,0x02,0xa3,0xac,0x82,0x00,0x18, +0x27,0x83,0x91,0x58,0x00,0x04,0x20,0x40,0x00,0x83,0x20,0x21,0x94,0x82,0x00,0x02, +0x00,0x06,0x18,0x27,0x00,0xe6,0x28,0x24,0x00,0x43,0x10,0x24,0x00,0x45,0x10,0x25, +0x08,0x00,0x02,0xa3,0xa4,0x82,0x00,0x02,0x27,0x83,0x91,0x50,0x00,0x83,0x18,0x21, +0x90,0x62,0x00,0x00,0x00,0x06,0x20,0x27,0x08,0x00,0x03,0x59,0x00,0xe6,0x28,0x24, +0x30,0x62,0x00,0x07,0x00,0x02,0x12,0x00,0x11,0x88,0x00,0x0f,0x00,0x44,0x10,0x21, +0x11,0x93,0x00,0x07,0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x0a,0x00,0x43,0x18,0x21, +0x8c,0x62,0x00,0x00,0x00,0x06,0x20,0x27,0x08,0x00,0x03,0x46,0x00,0xe6,0x28,0x24, +0x3c,0x03,0xb0,0x0a,0x00,0x43,0x18,0x21,0x94,0x62,0x00,0x00,0x00,0x06,0x20,0x27, +0x08,0x00,0x03,0x4f,0x00,0xe6,0x28,0x24,0x3c,0x03,0xb0,0x0a,0x08,0x00,0x03,0x7c, +0x00,0x43,0x18,0x21,0x97,0x85,0x91,0xa4,0x3c,0x07,0xb0,0x02,0x3c,0x04,0xb0,0x03, +0x3c,0x02,0x80,0x00,0x00,0xa7,0x28,0x21,0x34,0x84,0x00,0x20,0x24,0x42,0x0e,0x54, +0x24,0x03,0xff,0x80,0xac,0x82,0x00,0x00,0xa0,0xa3,0x00,0x07,0x97,0x82,0x91,0xa6, +0x97,0x85,0x91,0xa4,0x3c,0x06,0xb0,0x06,0x30,0x42,0xff,0xf8,0x24,0x42,0x00,0x10, +0x00,0xa2,0x10,0x21,0x30,0x42,0x0f,0xff,0x24,0x44,0x00,0x08,0x30,0x84,0x0f,0xff, +0x00,0x05,0x28,0xc2,0x3c,0x03,0x00,0x40,0x00,0xa3,0x28,0x25,0x00,0x87,0x20,0x21, +0x34,0xc6,0x80,0x18,0xac,0xc5,0x00,0x00,0xaf,0x84,0x91,0xa0,0xa7,0x82,0x91,0xa4, +0xa7,0x80,0x91,0xa6,0xaf,0x80,0x91,0xa8,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00, +0x30,0xa5,0x00,0xff,0x30,0x84,0x00,0xff,0x24,0x02,0x00,0x01,0x00,0xe0,0x48,0x21, +0x30,0xc6,0x00,0xff,0x8f,0xa7,0x00,0x10,0x10,0x82,0x00,0x07,0x00,0xa0,0x40,0x21, +0x24,0x02,0x00,0x03,0x10,0x82,0x00,0x03,0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08, +0x00,0x00,0x00,0x00,0x24,0xa8,0x01,0x00,0x3c,0x03,0xb0,0x03,0x24,0x02,0x00,0x01, +0x00,0x07,0x20,0x27,0x01,0x27,0x28,0x24,0x10,0xc2,0x00,0x14,0x01,0x03,0x18,0x21, +0x24,0x02,0x00,0x02,0x10,0xc2,0x00,0x09,0x00,0x07,0x50,0x27,0x3c,0x03,0xb0,0x03, +0x01,0x03,0x18,0x21,0x8c,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4a,0x10,0x24, +0x00,0x45,0x10,0x25,0x08,0x00,0x03,0xe0,0xac,0x62,0x00,0x00,0x3c,0x03,0xb0,0x03, +0x01,0x03,0x18,0x21,0x94,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4a,0x10,0x24, +0x00,0x45,0x10,0x25,0x03,0xe0,0x00,0x08,0xa4,0x62,0x00,0x00,0x90,0x62,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x44,0x10,0x24,0x00,0x45,0x10,0x25,0xa0,0x62,0x00,0x00, +0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x30,0x84,0x00,0x07,0x00,0x04,0x22,0x00, +0x30,0xa5,0x00,0xff,0x00,0x85,0x28,0x21,0x3c,0x02,0xb0,0x0a,0x00,0xa2,0x40,0x21, +0x30,0xc6,0x00,0xff,0x24,0x02,0x00,0x01,0x8f,0xa4,0x00,0x10,0x10,0xc2,0x00,0x14, +0x24,0x02,0x00,0x02,0x00,0x04,0x50,0x27,0x10,0xc2,0x00,0x09,0x00,0xe4,0x48,0x24, +0x3c,0x03,0xb0,0x0a,0x00,0xa3,0x18,0x21,0x8c,0x62,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x4a,0x10,0x24,0x00,0x49,0x10,0x25,0x03,0xe0,0x00,0x08,0xac,0x62,0x00,0x00, +0x3c,0x03,0xb0,0x0a,0x00,0xa3,0x18,0x21,0x94,0x62,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x4a,0x10,0x24,0x00,0x49,0x10,0x25,0x03,0xe0,0x00,0x08,0xa4,0x62,0x00,0x00, +0x91,0x02,0x00,0x00,0x00,0x04,0x18,0x27,0x00,0xe4,0x20,0x24,0x00,0x43,0x10,0x24, +0x00,0x44,0x10,0x25,0x03,0xe0,0x00,0x08,0xa1,0x02,0x00,0x00,0x30,0xa9,0x00,0xff, +0x27,0x83,0x91,0x50,0x30,0x85,0x00,0xff,0x24,0x02,0x00,0x01,0x00,0x07,0x50,0x27, +0x00,0xc7,0x40,0x24,0x11,0x22,0x00,0x17,0x00,0xa3,0x18,0x21,0x00,0x05,0x20,0x40, +0x27,0x82,0x91,0x50,0x00,0x05,0x28,0x80,0x27,0x83,0x91,0x58,0x00,0x83,0x50,0x21, +0x00,0xa2,0x20,0x21,0x24,0x02,0x00,0x02,0x00,0x07,0x40,0x27,0x11,0x22,0x00,0x07, +0x00,0xc7,0x28,0x24,0x8c,0x82,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x48,0x10,0x24, +0x00,0x45,0x10,0x25,0x03,0xe0,0x00,0x08,0xac,0x82,0x00,0x18,0x95,0x42,0x00,0x02, +0x00,0x00,0x00,0x00,0x00,0x48,0x10,0x24,0x00,0x45,0x10,0x25,0x03,0xe0,0x00,0x08, +0xa5,0x42,0x00,0x02,0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4a,0x10,0x24, +0x00,0x48,0x10,0x25,0x03,0xe0,0x00,0x08,0xa0,0x62,0x00,0x00,0x00,0x04,0x32,0x02, +0x30,0xc6,0xff,0x00,0x00,0x04,0x16,0x02,0x00,0x04,0x1a,0x00,0x3c,0x05,0x00,0xff, +0x00,0x65,0x18,0x24,0x00,0x46,0x10,0x25,0x00,0x43,0x10,0x25,0x00,0x04,0x26,0x00, +0x03,0xe0,0x00,0x08,0x00,0x44,0x10,0x25,0x3c,0x02,0xb0,0x02,0x34,0x42,0x00,0x08, +0x3c,0x03,0xb0,0x02,0xaf,0x82,0x8b,0x78,0xaf,0x83,0x8b,0x7c,0xa7,0x80,0x8b,0x80, +0xa7,0x80,0x8b,0x82,0xaf,0x80,0x8b,0x84,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00, +0x27,0xbd,0xff,0xd8,0xaf,0xbf,0x00,0x20,0x94,0x82,0x00,0x04,0x00,0x00,0x00,0x00, +0x30,0x42,0xe0,0x00,0x10,0x40,0x00,0x05,0x00,0x80,0x18,0x21,0x8f,0xbf,0x00,0x20, +0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x28,0x90,0x84,0x00,0x02, +0x00,0x00,0x00,0x00,0x30,0x84,0x00,0xfc,0x0c,0x00,0x06,0xc9,0x00,0x64,0x20,0x21, +0x08,0x00,0x04,0x47,0x00,0x00,0x00,0x00,0x27,0xbd,0xff,0xd8,0xaf,0xb2,0x00,0x18, +0xaf,0xb1,0x00,0x14,0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x20,0xaf,0xb3,0x00,0x1c, +0x8f,0x90,0x91,0xa0,0x0c,0x00,0x2b,0xd1,0x00,0x80,0x90,0x21,0x00,0x40,0x88,0x21, +0x93,0x82,0x82,0x20,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x1b,0x24,0x02,0x00,0x01, +0xa3,0x82,0x82,0x20,0x24,0x03,0x00,0x05,0x24,0x02,0x00,0x04,0xa3,0x83,0x8b,0x73, +0xa3,0x82,0x8b,0x72,0xa7,0x80,0x82,0x22,0x00,0x00,0x28,0x21,0x27,0x86,0x8b,0x70, +0x00,0x05,0x10,0x80,0x00,0x46,0x10,0x21,0x8c,0x44,0x00,0x00,0x24,0xa3,0x00,0x01, +0x30,0x65,0xff,0xff,0xae,0x04,0x00,0x00,0x10,0xa0,0xff,0xfa,0x00,0x05,0x10,0x80, +0x8f,0x83,0x91,0xa0,0x97,0x82,0x91,0xa6,0x24,0x05,0x8f,0xff,0x24,0x63,0x00,0x04, +0x00,0x65,0x18,0x24,0x26,0x04,0x00,0x04,0x24,0x42,0x00,0x04,0xaf,0x83,0x91,0xa0, +0xa7,0x82,0x91,0xa6,0x00,0x85,0x80,0x24,0x97,0x84,0x82,0x22,0x27,0x93,0x80,0x2c, +0x02,0x40,0x28,0x21,0x00,0x93,0x20,0x21,0x0c,0x00,0x2c,0x55,0x02,0x20,0x30,0x21, +0x97,0x87,0x82,0x22,0x24,0x02,0x00,0x52,0x00,0xf1,0x18,0x21,0xa7,0x83,0x82,0x22, +0x82,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x82,0x00,0x06,0x00,0x60,0x38,0x21, +0x8f,0xbf,0x00,0x20,0x7b,0xb2,0x00,0xfc,0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08, +0x27,0xbd,0x00,0x28,0x82,0x43,0x00,0x01,0x24,0x02,0x00,0x54,0x14,0x62,0xff,0xf8, +0x24,0x02,0x00,0x4c,0x82,0x43,0x00,0x02,0x00,0x00,0x00,0x00,0x14,0x62,0xff,0xf4, +0x00,0x00,0x00,0x00,0x30,0xe6,0xff,0xff,0x10,0xc0,0x00,0x0c,0x00,0x00,0x28,0x21, +0x02,0x60,0x48,0x21,0x24,0x08,0x8f,0xff,0x00,0xa9,0x10,0x21,0x8c,0x44,0x00,0x00, +0x24,0xa3,0x00,0x04,0x30,0x65,0xff,0xff,0x26,0x02,0x00,0x04,0x00,0xa6,0x18,0x2b, +0xae,0x04,0x00,0x00,0x14,0x60,0xff,0xf8,0x00,0x48,0x80,0x24,0x97,0x83,0x91,0xa6, +0x97,0x85,0x91,0xa4,0x3c,0x02,0xb0,0x02,0x00,0x67,0x18,0x21,0x00,0xa2,0x28,0x21, +0x3c,0x04,0xb0,0x06,0xa7,0x83,0x91,0xa6,0x34,0x84,0x80,0x18,0xa4,0xa3,0x00,0x00, +0x8f,0x82,0x91,0xa0,0x8c,0x86,0x00,0x00,0x30,0xe5,0xff,0xff,0x24,0x03,0x8f,0xff, +0x00,0x45,0x10,0x21,0x3c,0x04,0x0f,0x00,0x00,0x43,0x10,0x24,0x00,0xc4,0x30,0x24, +0x3c,0x03,0x04,0x00,0xaf,0x82,0x91,0xa0,0x10,0xc3,0xff,0xd1,0x00,0x00,0x00,0x00, +0x0c,0x00,0x03,0x95,0x00,0x00,0x00,0x00,0xa3,0x80,0x82,0x20,0x08,0x00,0x04,0x88, +0x00,0x00,0x00,0x00,0x8f,0x82,0x8b,0x7c,0x97,0x83,0x8b,0x80,0x8f,0x87,0x8b,0x78, +0x3c,0x06,0xff,0xff,0xac,0x43,0x00,0x00,0x8f,0x82,0x8b,0x7c,0x3c,0x03,0x80,0x00, +0x24,0xe5,0x00,0x08,0xac,0x43,0x00,0x04,0x8f,0x82,0x8b,0x7c,0x34,0xc6,0x1f,0xff, +0x3c,0x03,0x00,0x40,0x30,0x42,0x0f,0xff,0x3c,0x04,0xb0,0x06,0x00,0x02,0x10,0xc2, +0x00,0x43,0x10,0x25,0x00,0xa6,0x28,0x24,0x34,0x84,0x80,0x18,0x27,0xbd,0xff,0xf8, +0xac,0x82,0x00,0x00,0xaf,0x85,0x8b,0x78,0xaf,0x87,0x8b,0x7c,0xa7,0x80,0x8b,0x80, +0xa7,0x80,0x8b,0x82,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x08,0x03,0xe0,0x00,0x08, +0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08, +0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x27,0xbd,0xff,0xe0, +0xaf,0xb2,0x00,0x18,0xaf,0xb1,0x00,0x14,0xaf,0xb0,0x00,0x10,0x8f,0x91,0x8b,0x78, +0x00,0x80,0x80,0x21,0xaf,0xbf,0x00,0x1c,0x0c,0x00,0x05,0x78,0x00,0xa0,0x90,0x21, +0x97,0x82,0x8b,0x80,0x36,0x10,0x12,0x00,0x26,0x2a,0x00,0x04,0x24,0x4c,0x00,0x14, +0x2c,0x42,0x04,0x01,0x14,0x40,0x00,0x0a,0x24,0x09,0x8f,0xff,0x8f,0x82,0x80,0x18, +0x00,0x00,0x00,0x00,0x24,0x42,0x00,0x01,0xaf,0x82,0x80,0x18,0x8f,0xbf,0x00,0x1c, +0x8f,0xb2,0x00,0x18,0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20, +0x8e,0x44,0x00,0x1c,0x86,0x47,0x00,0x06,0x97,0x86,0x8b,0x82,0x8c,0x82,0x00,0x08, +0x00,0x07,0x3c,0x00,0x8f,0x85,0x8b,0x78,0x00,0x02,0x11,0x02,0x30,0x42,0x40,0x00, +0x02,0x02,0x80,0x25,0xae,0x30,0x00,0x00,0x8c,0x82,0x00,0x04,0x82,0x43,0x00,0x15, +0x01,0x49,0x88,0x24,0x00,0x02,0x14,0xc2,0x00,0x03,0x1a,0x00,0x00,0x02,0x14,0x00, +0x00,0x62,0x80,0x25,0xae,0x30,0x00,0x00,0x92,0x43,0x00,0x13,0x92,0x44,0x00,0x10, +0x96,0x50,0x00,0x1a,0x00,0x03,0x1c,0x00,0x00,0x04,0x26,0x00,0x02,0x03,0x80,0x25, +0x26,0x22,0x00,0x04,0x00,0x49,0x88,0x24,0x02,0x04,0x80,0x25,0xae,0x30,0x00,0x00, +0x92,0x42,0x00,0x0f,0x92,0x43,0x00,0x11,0x26,0x24,0x00,0x04,0x00,0x02,0x12,0x00, +0x00,0x89,0x88,0x24,0x00,0x62,0x80,0x25,0x02,0x07,0x80,0x25,0x26,0x22,0x00,0x04, +0xae,0x30,0x00,0x00,0x00,0x49,0x88,0x24,0xae,0x20,0x00,0x00,0x8f,0x82,0x80,0x14, +0x24,0xc6,0x00,0x01,0x24,0xa5,0x00,0x14,0x30,0xc8,0xff,0xff,0x3c,0x0b,0xb0,0x03, +0x00,0xa9,0x28,0x24,0x24,0x42,0x00,0x01,0x2d,0x08,0x00,0x0a,0xaf,0x85,0x8b,0x78, +0xa7,0x8c,0x8b,0x80,0xaf,0x82,0x80,0x14,0xa7,0x86,0x8b,0x82,0x11,0x00,0x00,0x07, +0x35,0x6b,0x01,0x08,0x8f,0x82,0x8b,0x84,0x8d,0x63,0x00,0x00,0x24,0x42,0x04,0x00, +0x00,0x62,0x18,0x2b,0x14,0x60,0xff,0xc1,0x00,0x00,0x00,0x00,0x0c,0x00,0x04,0xbd, +0x00,0x00,0x00,0x00,0x08,0x00,0x04,0xf3,0x00,0x00,0x00,0x00,0x27,0xbd,0xff,0xe8, +0xaf,0xbf,0x00,0x10,0x0c,0x00,0x05,0x78,0x00,0x00,0x00,0x00,0x8f,0xbf,0x00,0x10, +0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18,0x27,0xbd,0xff,0xe0, +0xaf,0xb2,0x00,0x18,0xaf,0xb1,0x00,0x14,0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x1c, +0x8f,0x90,0x8b,0x78,0x0c,0x00,0x05,0x78,0x00,0x80,0x90,0x21,0x97,0x82,0x8b,0x80, +0x24,0x11,0x8f,0xff,0x2c,0x42,0x04,0x01,0x14,0x40,0x00,0x06,0x26,0x03,0x00,0x04, +0x8f,0xbf,0x00,0x1c,0x8f,0xb2,0x00,0x18,0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08, +0x27,0xbd,0x00,0x20,0x24,0x02,0x0e,0x03,0xae,0x02,0x00,0x00,0x00,0x71,0x80,0x24, +0xae,0x00,0x00,0x00,0x8e,0x44,0x00,0x08,0x26,0x02,0x00,0x04,0x0c,0x00,0x05,0x86, +0x00,0x51,0x80,0x24,0x97,0x86,0x8b,0x82,0x8f,0x83,0x8b,0x78,0xae,0x02,0x00,0x00, +0x97,0x82,0x8b,0x80,0x24,0xc6,0x00,0x01,0x8e,0x47,0x00,0x0c,0x24,0x63,0x00,0x10, +0x30,0xc5,0xff,0xff,0x26,0x04,0x00,0x04,0x3c,0x08,0xb0,0x03,0x00,0x71,0x18,0x24, +0x00,0x91,0x80,0x24,0x24,0x42,0x00,0x10,0x2c,0xa5,0x00,0x0a,0x35,0x08,0x01,0x08, +0xae,0x07,0x00,0x00,0xaf,0x83,0x8b,0x78,0xa7,0x82,0x8b,0x80,0xa7,0x86,0x8b,0x82, +0x10,0xa0,0x00,0x07,0x00,0x00,0x00,0x00,0x8f,0x82,0x8b,0x84,0x8d,0x03,0x00,0x00, +0x24,0x42,0x04,0x00,0x00,0x62,0x18,0x2b,0x14,0x60,0xff,0xd9,0x00,0x00,0x00,0x00, +0x0c,0x00,0x04,0xbd,0x00,0x00,0x00,0x00,0x08,0x00,0x05,0x4c,0x00,0x00,0x00,0x00, +0x97,0x82,0x8b,0x82,0x3c,0x03,0xb0,0x03,0x14,0x40,0x00,0x09,0x34,0x63,0x01,0x08, +0x8c,0x62,0x00,0x00,0x8f,0x83,0x8b,0x7c,0xa7,0x80,0x8b,0x80,0xaf,0x82,0x8b,0x84, +0xac,0x60,0x00,0x00,0x8f,0x82,0x8b,0x7c,0x00,0x00,0x00,0x00,0xac,0x40,0x00,0x04, +0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x04,0x32,0x02,0x30,0xc6,0xff,0x00, +0x00,0x04,0x16,0x02,0x00,0x04,0x1a,0x00,0x3c,0x05,0x00,0xff,0x00,0x65,0x18,0x24, +0x00,0x46,0x10,0x25,0x00,0x43,0x10,0x25,0x00,0x04,0x26,0x00,0x03,0xe0,0x00,0x08, +0x00,0x44,0x10,0x25,0x80,0x82,0x00,0x00,0x90,0x83,0x00,0x00,0x10,0x40,0x00,0x0c, +0x00,0x80,0x28,0x21,0x24,0x62,0xff,0x9f,0x30,0x42,0x00,0xff,0x2c,0x42,0x00,0x1a, +0x10,0x40,0x00,0x02,0x24,0x63,0xff,0xe0,0xa0,0xa3,0x00,0x00,0x24,0xa5,0x00,0x01, +0x90,0xa2,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x40,0xff,0xf6,0x00,0x40,0x18,0x21, +0x03,0xe0,0x00,0x08,0x00,0x80,0x10,0x21,0x80,0x82,0x00,0x00,0x90,0x83,0x00,0x00, +0x10,0x40,0x00,0x0c,0x00,0x80,0x28,0x21,0x24,0x62,0xff,0xbf,0x30,0x42,0x00,0xff, +0x2c,0x42,0x00,0x1a,0x10,0x40,0x00,0x02,0x24,0x63,0x00,0x20,0xa0,0xa3,0x00,0x00, +0x24,0xa5,0x00,0x01,0x90,0xa2,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x40,0xff,0xf6, +0x00,0x40,0x18,0x21,0x03,0xe0,0x00,0x08,0x00,0x80,0x10,0x21,0x27,0xbd,0xff,0xe8, +0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x14,0x24,0x10,0xff,0xff,0x0c,0x00,0x29,0x11, +0x00,0x00,0x00,0x00,0x10,0x50,0xff,0xfd,0x00,0x02,0x16,0x00,0x00,0x02,0x16,0x03, +0x8f,0xbf,0x00,0x14,0x8f,0xb0,0x00,0x10,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18, +0x27,0xbd,0xff,0xc8,0xaf,0xb3,0x00,0x1c,0x00,0x00,0x98,0x21,0xaf,0xb1,0x00,0x14, +0x02,0x65,0x88,0x2b,0xaf,0xb6,0x00,0x28,0xaf,0xb5,0x00,0x24,0xaf,0xb0,0x00,0x10, +0xaf,0xbf,0x00,0x34,0xaf,0xbe,0x00,0x30,0xaf,0xb7,0x00,0x2c,0xaf,0xb4,0x00,0x20, +0xaf,0xb2,0x00,0x18,0x00,0xa0,0xb0,0x21,0xaf,0xa4,0x00,0x38,0x00,0xc0,0xa8,0x21, +0x12,0x20,0x00,0x17,0x00,0x80,0x80,0x21,0x24,0x17,0xff,0xff,0x24,0x1e,0x00,0x0a, +0x0c,0x00,0x29,0x11,0x00,0x00,0x00,0x00,0x10,0x57,0x00,0x0f,0x00,0x02,0x16,0x00, +0x00,0x02,0x26,0x03,0x10,0x9e,0x00,0x0e,0x24,0x02,0x00,0x0d,0x10,0x82,0x00,0x34, +0x24,0x02,0x00,0x08,0x10,0x82,0x00,0x25,0x24,0x02,0x00,0x09,0x10,0x82,0x00,0x13, +0x00,0x00,0x90,0x21,0xa2,0x04,0x00,0x00,0x26,0x73,0x00,0x01,0x16,0xa0,0x00,0x0b, +0x26,0x10,0x00,0x01,0x02,0x76,0x88,0x2b,0x16,0x20,0xff,0xed,0x00,0x00,0x00,0x00, +0x7b,0xbe,0x01,0xbc,0x7b,0xb6,0x01,0x7c,0x7b,0xb4,0x01,0x3c,0x7b,0xb2,0x00,0xfc, +0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x38,0x0c,0x00,0x29,0x04, +0x02,0x76,0x88,0x2b,0x08,0x00,0x05,0xe6,0x00,0x00,0x00,0x00,0x24,0x14,0x00,0x20, +0xa2,0x14,0x00,0x00,0x26,0x52,0x00,0x01,0x24,0x04,0x00,0x20,0x26,0x73,0x00,0x01, +0x16,0xa0,0x00,0x06,0x26,0x10,0x00,0x01,0x2a,0x42,0x00,0x08,0x10,0x40,0xff,0xea, +0x02,0x76,0x88,0x2b,0x08,0x00,0x05,0xf5,0xa2,0x14,0x00,0x00,0x0c,0x00,0x29,0x04, +0x00,0x00,0x00,0x00,0x08,0x00,0x05,0xfb,0x2a,0x42,0x00,0x08,0x8f,0xa2,0x00,0x38, +0x00,0x00,0x00,0x00,0x12,0x02,0xff,0xe0,0x00,0x00,0x00,0x00,0x26,0x10,0xff,0xff, +0x12,0xa0,0xff,0xdc,0x26,0x73,0xff,0xff,0x0c,0x00,0x29,0x04,0x24,0x04,0x00,0x08, +0x0c,0x00,0x29,0x04,0x24,0x04,0x00,0x20,0x08,0x00,0x05,0xef,0x24,0x04,0x00,0x08, +0x08,0x00,0x05,0xe8,0xa2,0x00,0x00,0x00,0x90,0x82,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x02,0x1e,0x00,0x10,0x60,0x00,0x16,0x00,0x00,0x30,0x21,0x24,0x07,0x00,0x20, +0x00,0x03,0x1e,0x03,0x10,0x67,0x00,0x17,0x00,0x00,0x00,0x00,0x10,0x60,0x00,0x15, +0x00,0x00,0x00,0x00,0x10,0x67,0x00,0x0b,0x24,0xc6,0x00,0x01,0x10,0x60,0x00,0x0a, +0x00,0x02,0x1e,0x00,0x24,0x05,0x00,0x20,0x24,0x84,0x00,0x01,0x80,0x83,0x00,0x00, +0x90,0x82,0x00,0x00,0x10,0x65,0x00,0x03,0x00,0x00,0x00,0x00,0x14,0x60,0xff,0xfa, +0x00,0x00,0x00,0x00,0x00,0x02,0x1e,0x00,0x14,0x60,0xff,0xed,0x00,0x00,0x00,0x00, +0x28,0xc3,0x00,0x08,0x24,0x02,0x00,0x07,0x00,0x43,0x30,0x0a,0x03,0xe0,0x00,0x08, +0x00,0xc0,0x10,0x21,0x24,0x84,0x00,0x01,0x90,0x82,0x00,0x00,0x08,0x00,0x06,0x2a, +0x00,0x02,0x1e,0x00,0x27,0xbd,0xff,0xe0,0xaf,0xb1,0x00,0x14,0x27,0x91,0x8b,0x88, +0xaf,0xb0,0x00,0x10,0x24,0x06,0x00,0x20,0x00,0x80,0x80,0x21,0x00,0x00,0x28,0x21, +0xaf,0xbf,0x00,0x18,0x0c,0x00,0x2c,0x4b,0x02,0x20,0x20,0x21,0x82,0x02,0x00,0x00, +0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x1f,0x00,0x00,0x30,0x21,0x02,0x20,0x20,0x21, +0x24,0x09,0x00,0x20,0x24,0x08,0x00,0x20,0x24,0x07,0x00,0x08,0xac,0x90,0x00,0x00, +0x82,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x49,0x00,0x0a,0x00,0x00,0x00,0x00, +0x10,0x40,0x00,0x08,0x24,0x03,0x00,0x20,0x26,0x10,0x00,0x01,0x82,0x02,0x00,0x00, +0x00,0x00,0x00,0x00,0x10,0x43,0x00,0x03,0x00,0x00,0x00,0x00,0x14,0x40,0xff,0xfa, +0x00,0x00,0x00,0x00,0xa2,0x00,0x00,0x00,0x26,0x10,0x00,0x01,0x82,0x02,0x00,0x00, +0x92,0x03,0x00,0x00,0x10,0x48,0x00,0x0c,0x24,0x05,0x00,0x20,0x24,0xc6,0x00,0x01, +0x10,0xc7,0x00,0x04,0x24,0x84,0x00,0x04,0x00,0x03,0x16,0x00,0x14,0x40,0xff,0xe7, +0x00,0x00,0x00,0x00,0x8f,0xbf,0x00,0x18,0x7b,0xb0,0x00,0xbc,0x27,0x82,0x8b,0x88, +0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20,0x26,0x10,0x00,0x01,0x82,0x02,0x00,0x00, +0x92,0x03,0x00,0x00,0x10,0x45,0xff,0xfc,0x00,0x00,0x00,0x00,0x08,0x00,0x06,0x5c, +0x24,0xc6,0x00,0x01,0x00,0x80,0x30,0x21,0x90,0x84,0x00,0x00,0x00,0x00,0x38,0x21, +0x10,0x80,0x00,0x19,0x24,0xc6,0x00,0x01,0x24,0x82,0xff,0xd0,0x30,0x42,0x00,0xff, +0x2c,0x43,0x00,0x0a,0x14,0x60,0x00,0x0c,0x00,0x07,0x19,0x00,0x24,0x83,0xff,0x9f, +0x24,0x82,0xff,0xa9,0x24,0x88,0xff,0xc9,0x2c,0x63,0x00,0x06,0x24,0x84,0xff,0xbf, +0x2c,0x84,0x00,0x06,0x14,0x60,0x00,0x03,0x30,0x42,0x00,0xff,0x10,0x80,0x00,0x0e, +0x31,0x02,0x00,0xff,0x00,0x07,0x19,0x00,0x00,0x62,0x18,0x21,0x00,0x67,0x10,0x2b, +0x14,0x40,0x00,0x07,0x00,0x00,0x20,0x21,0x90,0xc4,0x00,0x00,0x00,0x60,0x38,0x21, +0x14,0x80,0xff,0xe9,0x24,0xc6,0x00,0x01,0xac,0xa7,0x00,0x00,0x24,0x04,0x00,0x01, +0x03,0xe0,0x00,0x08,0x00,0x80,0x10,0x21,0x08,0x00,0x06,0x8c,0x00,0x00,0x20,0x21, +0x00,0x00,0x20,0x21,0x27,0x85,0x91,0xc0,0x24,0x82,0x00,0x01,0x00,0x04,0x18,0x80, +0x30,0x44,0x00,0xff,0x00,0x65,0x18,0x21,0x2c,0x82,0x00,0x0b,0x14,0x40,0xff,0xfa, +0xac,0x60,0x00,0x00,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0xaf,0x84,0x8c,0x08, +0xaf,0x85,0x8c,0x0c,0xaf,0x86,0x8c,0x10,0xaf,0x87,0x8c,0x14,0x03,0xe0,0x00,0x08, +0x00,0x00,0x00,0x00,0x8f,0x82,0x84,0x90,0x27,0xbd,0xff,0xe8,0xaf,0xbf,0x00,0x10, +0x2c,0x43,0x00,0x64,0x24,0x42,0x00,0x01,0x27,0x84,0x8b,0xa8,0xaf,0x82,0x84,0x90, +0x10,0x60,0x00,0x05,0x00,0x00,0x00,0x00,0x8f,0xbf,0x00,0x10,0x00,0x00,0x00,0x00, +0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18,0xaf,0x80,0x84,0x90,0x0c,0x00,0x06,0xf6, +0x00,0x00,0x00,0x00,0x00,0x40,0x18,0x21,0x28,0x44,0x00,0x08,0x24,0x02,0x00,0x07, +0x10,0x62,0x00,0x08,0x00,0x00,0x00,0x00,0x14,0x80,0xff,0xf3,0x24,0x02,0x00,0x08, +0x27,0x84,0x8b,0xa8,0x14,0x62,0xff,0xf0,0x00,0x00,0x00,0x00,0x0c,0x00,0x17,0xb0, +0x00,0x00,0x00,0x00,0x27,0x84,0x8b,0xa8,0x0c,0x00,0x07,0x54,0x00,0x00,0x00,0x00, +0x8f,0x83,0x84,0x94,0x3c,0x04,0x80,0x01,0x00,0x60,0x28,0x21,0x24,0x63,0x00,0x01, +0xaf,0x83,0x84,0x94,0x0c,0x00,0x17,0x9d,0x24,0x84,0x04,0x88,0x08,0x00,0x06,0xaa, +0x00,0x00,0x00,0x00,0x27,0xbd,0xff,0xc0,0xaf,0xbf,0x00,0x38,0x8c,0x85,0x00,0x0c, +0x8c,0x88,0x00,0x08,0x18,0xa0,0x00,0x0e,0x00,0x00,0x30,0x21,0x24,0x87,0x00,0x08, +0x27,0xa9,0x00,0x10,0x00,0x06,0x10,0x80,0x00,0x06,0x19,0x00,0x00,0x49,0x10,0x21, +0x14,0xc0,0x00,0x1f,0x00,0x83,0x18,0x21,0xaf,0xa7,0x00,0x10,0x24,0xc2,0x00,0x01, +0x30,0x46,0x00,0xff,0x00,0xc5,0x18,0x2a,0x14,0x60,0xff,0xf7,0x00,0x06,0x10,0x80, +0x29,0x02,0x00,0x0a,0x14,0x40,0x00,0x05,0x00,0x08,0x18,0x40,0x8f,0xbf,0x00,0x38, +0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x40,0x00,0x68,0x18,0x21, +0x27,0x82,0x83,0x8c,0x00,0x03,0x18,0xc0,0x00,0x62,0x18,0x21,0x8c,0x62,0x00,0x10, +0x01,0x00,0x20,0x21,0x00,0x40,0xf8,0x09,0x27,0xa6,0x00,0x10,0x8f,0x83,0x84,0xa8, +0x3c,0x04,0x80,0x01,0x00,0x60,0x28,0x21,0x24,0x63,0x00,0x01,0xaf,0x83,0x84,0xa8, +0x0c,0x00,0x17,0x9d,0x24,0x84,0x04,0x9c,0x08,0x00,0x06,0xdf,0x00,0x00,0x00,0x00, +0x08,0x00,0x06,0xd7,0xac,0x43,0x00,0x00,0x27,0xbd,0xff,0xe0,0xaf,0xb1,0x00,0x14, +0xaf,0xbf,0x00,0x18,0x00,0x80,0x88,0x21,0x0c,0x00,0x17,0xd4,0xaf,0xb0,0x00,0x10, +0x00,0x40,0x20,0x21,0x24,0x02,0xff,0xff,0x10,0x82,0x00,0x1f,0x24,0x03,0x00,0x06, +0x8f,0x85,0x84,0xbc,0x00,0x00,0x00,0x00,0x14,0xa0,0x00,0x0a,0x24,0x02,0x00,0x08, +0x24,0x02,0x00,0x02,0x10,0x82,0x00,0x3b,0x28,0x82,0x00,0x03,0x10,0x40,0x00,0x32, +0x24,0x02,0x00,0x1b,0x24,0x02,0x00,0x01,0x10,0x82,0x00,0x13,0x24,0x03,0x00,0x08, +0x24,0x02,0x00,0x08,0x10,0x82,0x00,0x23,0x24,0x02,0x00,0x0d,0x10,0x82,0x00,0x18, +0x02,0x25,0x10,0x21,0x24,0xa3,0x00,0x01,0xa0,0x44,0x00,0x00,0xaf,0x83,0x84,0xbc, +0x18,0x60,0x00,0x08,0x24,0x02,0x00,0x43,0x82,0x23,0x00,0x00,0x00,0x00,0x00,0x00, +0x10,0x62,0x00,0x0a,0x00,0x00,0x00,0x00,0x30,0x84,0xff,0xff,0x0c,0x00,0x17,0xd0, +0x00,0x00,0x00,0x00,0x24,0x03,0x00,0x06,0x8f,0xbf,0x00,0x18,0x7b,0xb0,0x00,0xbc, +0x00,0x60,0x10,0x21,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20,0x3c,0x04,0x80,0x01, +0x0c,0x00,0x17,0xb0,0x24,0x84,0x04,0xb0,0x08,0x00,0x07,0x1e,0x24,0x03,0x00,0x06, +0xa0,0x40,0x00,0x00,0x24,0xa5,0x00,0x01,0xaf,0x85,0x84,0xbc,0x0c,0x00,0x17,0xd0, +0x24,0x04,0x00,0x0d,0x24,0x03,0x00,0x07,0xaf,0x80,0x84,0xbc,0x08,0x00,0x07,0x1e, +0x00,0x00,0x00,0x00,0x18,0xa0,0xff,0xeb,0x24,0xa5,0xff,0xff,0xaf,0x85,0x84,0xbc, +0x0c,0x00,0x17,0xd0,0x24,0x04,0x00,0x08,0x0c,0x00,0x17,0xd0,0x24,0x04,0x00,0x20, +0x08,0x00,0x07,0x1b,0x24,0x04,0x00,0x08,0x14,0x82,0xff,0xd2,0x24,0x02,0x00,0x08, +0x0c,0x00,0x06,0x90,0x00,0x00,0x00,0x00,0x8f,0x85,0x84,0xbc,0x08,0x00,0x07,0x0c, +0x24,0x04,0x00,0x0d,0x0c,0x00,0x2b,0xd1,0x02,0x20,0x20,0x21,0xaf,0x82,0x84,0xbc, +0x04,0x40,0x00,0x0d,0x00,0x00,0x80,0x21,0x02,0x30,0x10,0x21,0x90,0x44,0x00,0x00, +0x26,0x10,0x00,0x01,0x00,0x04,0x26,0x00,0x00,0x04,0x26,0x03,0x0c,0x00,0x17,0xd0, +0x30,0x84,0xff,0xff,0x8f,0x83,0x84,0xbc,0x00,0x00,0x00,0x00,0x00,0x70,0x18,0x2a, +0x10,0x60,0xff,0xf6,0x02,0x30,0x10,0x21,0x08,0x00,0x07,0x2e,0x24,0x03,0x00,0x06, +0x27,0xbd,0xff,0xe8,0xaf,0xbf,0x00,0x10,0x27,0x83,0x8b,0xe8,0x24,0x02,0x00,0x07, +0x24,0x42,0xff,0xff,0xac,0x60,0x00,0x00,0x04,0x41,0xff,0xfd,0x24,0x63,0x00,0x04, +0x0c,0x00,0x07,0x66,0x00,0x00,0x00,0x00,0x8f,0x84,0x8b,0xe8,0x27,0x86,0x8b,0xe8, +0x0c,0x00,0x07,0x83,0x00,0x40,0x28,0x21,0x8f,0xbf,0x00,0x10,0x00,0x00,0x00,0x00, +0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18,0x27,0xbd,0xff,0xe0,0x00,0x80,0x28,0x21, +0x27,0x84,0x8b,0xc8,0xaf,0xb1,0x00,0x14,0xaf,0xbf,0x00,0x18,0x0c,0x00,0x2c,0x62, +0xaf,0xb0,0x00,0x10,0x8f,0x85,0x83,0x2c,0x27,0x84,0x8b,0xc8,0x0c,0x00,0x2c,0x26, +0x00,0x00,0x88,0x21,0x10,0x40,0x00,0x0c,0x00,0x00,0x00,0x00,0x27,0x90,0x8b,0xe8, +0x8f,0x85,0x83,0x2c,0x00,0x00,0x20,0x21,0xae,0x02,0x00,0x00,0x0c,0x00,0x2c,0x26, +0x26,0x31,0x00,0x01,0x26,0x10,0x00,0x04,0x10,0x40,0x00,0x03,0x2a,0x23,0x00,0x64, +0x14,0x60,0xff,0xf7,0x00,0x00,0x00,0x00,0x02,0x20,0x10,0x21,0x8f,0xbf,0x00,0x18, +0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20,0x27,0xbd,0xff,0xd0, +0xaf,0xb6,0x00,0x28,0xaf,0xb5,0x00,0x24,0xaf,0xb4,0x00,0x20,0xaf,0xbf,0x00,0x2c, +0xaf,0xb3,0x00,0x1c,0xaf,0xb2,0x00,0x18,0xaf,0xb1,0x00,0x14,0xaf,0xb0,0x00,0x10, +0x00,0xa0,0xa8,0x21,0x00,0x80,0xa0,0x21,0x00,0xc0,0xb0,0x21,0x10,0xa0,0x00,0x1d, +0x24,0x02,0x00,0x05,0x3c,0x02,0x80,0x00,0x24,0x43,0x29,0x1c,0x8f,0x82,0x83,0x9c, +0x00,0x00,0x00,0x00,0x10,0x43,0x00,0x1e,0x00,0x00,0x88,0x21,0x00,0x60,0x98,0x21, +0x00,0x00,0x90,0x21,0x27,0x90,0x83,0x9c,0x8e,0x05,0xff,0xec,0x02,0x80,0x20,0x21, +0x0c,0x00,0x2c,0x6a,0x26,0x10,0x00,0x18,0x10,0x40,0x00,0x06,0x02,0x51,0x18,0x21, +0x8e,0x02,0x00,0x00,0x26,0x31,0x00,0x01,0x14,0x53,0xff,0xf7,0x00,0x11,0x90,0x40, +0x02,0x51,0x18,0x21,0x27,0x82,0x83,0x8c,0x00,0x03,0x18,0xc0,0x00,0x62,0x18,0x21, +0x8c,0x62,0x00,0x10,0x02,0x20,0x20,0x21,0x02,0xa0,0x28,0x21,0x00,0x40,0xf8,0x09, +0x02,0xc0,0x30,0x21,0x8f,0xbf,0x00,0x2c,0x8f,0xb6,0x00,0x28,0x7b,0xb4,0x01,0x3c, +0x7b,0xb2,0x00,0xfc,0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x30, +0x08,0x00,0x07,0xa4,0x00,0x00,0x90,0x21,0x27,0xbd,0xff,0xc0,0xaf,0xb5,0x00,0x34, +0xaf,0xb3,0x00,0x2c,0xaf,0xb1,0x00,0x24,0xaf,0xbf,0x00,0x38,0xaf,0xb4,0x00,0x30, +0xaf,0xb2,0x00,0x28,0xaf,0xb0,0x00,0x20,0x00,0xc0,0x98,0x21,0x30,0xa5,0x00,0xff, +0xac,0xc0,0x00,0x00,0x24,0x15,0x00,0x0a,0x00,0x00,0x88,0x21,0x27,0xa8,0x00,0x10, +0x00,0x91,0x18,0x21,0x80,0x62,0x00,0x00,0x26,0x27,0x00,0x01,0x10,0x40,0x00,0x0c, +0x01,0x11,0x30,0x21,0x90,0x63,0x00,0x00,0x30,0xf1,0x00,0xff,0x2e,0x22,0x00,0x0a, +0x14,0x40,0xff,0xf7,0xa0,0xc3,0x00,0x00,0x8f,0xbf,0x00,0x38,0x7b,0xb4,0x01,0xbc, +0x7b,0xb2,0x01,0x7c,0x7b,0xb0,0x01,0x3c,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x40, +0x24,0x02,0x00,0x01,0x10,0xa2,0x00,0x23,0x24,0x02,0x00,0x02,0x10,0xa2,0x00,0x1f, +0x24,0x02,0x00,0x03,0x10,0xa2,0x00,0x1a,0x00,0x00,0x00,0x00,0x02,0x20,0x90,0x21, +0x12,0x40,0xff,0xf1,0x00,0x00,0x88,0x21,0x27,0xb4,0x00,0x10,0x02,0x91,0x10,0x21, +0x90,0x44,0x00,0x00,0x0c,0x00,0x08,0x0a,0x00,0x00,0x00,0x00,0x02,0x51,0x20,0x23, +0x24,0x84,0xff,0xff,0x30,0x84,0x00,0xff,0x02,0xa0,0x28,0x21,0x0c,0x00,0x07,0xfb, +0x00,0x40,0x80,0x21,0x02,0x02,0x00,0x18,0x8e,0x63,0x00,0x00,0x26,0x22,0x00,0x01, +0x30,0x51,0x00,0xff,0x02,0x32,0x20,0x2b,0x00,0x00,0x80,0x12,0x00,0x70,0x18,0x21, +0x14,0x80,0xff,0xee,0xae,0x63,0x00,0x00,0x08,0x00,0x07,0xce,0x00,0x00,0x00,0x00, +0x80,0x82,0x00,0x00,0x08,0x00,0x07,0xce,0xae,0x62,0x00,0x00,0x08,0x00,0x07,0xdb, +0x24,0x15,0x00,0x10,0x08,0x00,0x07,0xdb,0x24,0x15,0x00,0x0a,0x30,0x84,0x00,0xff, +0x30,0xa5,0x00,0xff,0x24,0x06,0x00,0x01,0x10,0x80,0x00,0x09,0x00,0x00,0x10,0x21, +0x00,0xc5,0x00,0x18,0x24,0x42,0x00,0x01,0x30,0x42,0x00,0xff,0x00,0x44,0x18,0x2b, +0x00,0x00,0x30,0x12,0x00,0x00,0x00,0x00,0x14,0x60,0xff,0xfa,0x00,0xc5,0x00,0x18, +0x03,0xe0,0x00,0x08,0x00,0xc0,0x10,0x21,0x30,0x84,0x00,0xff,0x24,0x83,0xff,0xd0, +0x30,0x62,0x00,0xff,0x2c,0x42,0x00,0x0a,0x14,0x40,0x00,0x06,0x00,0x00,0x00,0x00, +0x24,0x82,0xff,0xbf,0x2c,0x42,0x00,0x06,0x14,0x40,0x00,0x02,0x24,0x83,0xff,0xc9, +0x24,0x83,0xff,0xa9,0x03,0xe0,0x00,0x08,0x00,0x60,0x10,0x21,0x27,0xbd,0xff,0xc8, +0x24,0x02,0x00,0x01,0xaf,0xbf,0x00,0x30,0xaf,0xb5,0x00,0x2c,0xaf,0xb4,0x00,0x28, +0xaf,0xb3,0x00,0x24,0xaf,0xb2,0x00,0x20,0xaf,0xb1,0x00,0x1c,0x10,0xa2,0x00,0x3e, +0xaf,0xb0,0x00,0x18,0x24,0x02,0x00,0x02,0x10,0xa2,0x00,0x08,0x24,0x05,0x00,0x01, +0x00,0x00,0x10,0x21,0x8f,0xbf,0x00,0x30,0x7b,0xb4,0x01,0x7c,0x7b,0xb2,0x01,0x3c, +0x7b,0xb0,0x00,0xfc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x38,0x8c,0xc4,0x00,0x04, +0x0c,0x00,0x07,0xb6,0x27,0xa6,0x00,0x10,0x8f,0xa2,0x00,0x10,0x00,0x00,0x00,0x00, +0x28,0x42,0x00,0x65,0x14,0x40,0x00,0x06,0x00,0x00,0x00,0x00,0x3c,0x04,0x80,0x01, +0x0c,0x00,0x17,0xb0,0x24,0x84,0x04,0xb4,0x08,0x00,0x08,0x25,0x24,0x02,0x00,0x01, +0x3c,0x04,0x80,0x01,0x0c,0x00,0x17,0xb0,0x24,0x84,0x04,0xc0,0x8f,0x83,0x83,0x9c, +0x3c,0x02,0x80,0x00,0x24,0x42,0x29,0x1c,0x10,0x62,0xff,0xe5,0x00,0x40,0x90,0x21, +0x3c,0x13,0x80,0x01,0x27,0x95,0x83,0x88,0x3c,0x14,0x80,0x01,0x27,0x90,0x83,0x8c, +0x00,0x00,0x88,0x21,0x8e,0x03,0x00,0x08,0x8f,0xa2,0x00,0x10,0x00,0x00,0x00,0x00, +0x10,0x62,0x00,0x08,0x26,0x64,0x04,0xcc,0x26,0x10,0x00,0x18,0x8e,0x02,0x00,0x10, +0x00,0x00,0x00,0x00,0x14,0x52,0xff,0xf7,0x26,0x31,0x00,0x18,0x08,0x00,0x08,0x25, +0x00,0x00,0x10,0x21,0x0c,0x00,0x17,0xb0,0x00,0x00,0x00,0x00,0x02,0x35,0x10,0x21, +0x8c,0x44,0x00,0x00,0x0c,0x00,0x17,0xb0,0x00,0x00,0x00,0x00,0x0c,0x00,0x17,0xb0, +0x26,0x84,0x04,0xd0,0x8e,0x04,0x00,0x00,0x0c,0x00,0x17,0xb0,0x26,0x10,0x00,0x18, +0x08,0x00,0x08,0x4b,0x00,0x00,0x00,0x00,0x3c,0x04,0x80,0x01,0x0c,0x00,0x17,0xb0, +0x24,0x84,0x04,0xd4,0x3c,0x04,0x80,0x01,0x0c,0x00,0x17,0x9d,0x24,0x84,0x04,0xe4, +0x24,0x11,0x00,0x05,0x3c,0x12,0x80,0x01,0x27,0x90,0x88,0x8e,0x86,0x05,0x00,0x00, +0x26,0x44,0x05,0x04,0x0c,0x00,0x17,0x9d,0x26,0x31,0xff,0xff,0x06,0x21,0xff,0xfb, +0x26,0x10,0xff,0xfe,0x08,0x00,0x08,0x25,0x00,0x00,0x10,0x21,0x27,0xbd,0xff,0xd0, +0x28,0xa2,0x00,0x02,0xaf,0xb1,0x00,0x1c,0xaf,0xb0,0x00,0x18,0xaf,0xbf,0x00,0x2c, +0xaf,0xb4,0x00,0x28,0xaf,0xb3,0x00,0x24,0xaf,0xb2,0x00,0x20,0x00,0xa0,0x80,0x21, +0x14,0x40,0x00,0x51,0x00,0xc0,0x88,0x21,0x8c,0xc4,0x00,0x04,0x24,0x05,0x00,0x02, +0x0c,0x00,0x07,0xb6,0x27,0xa6,0x00,0x10,0x24,0x02,0x00,0x02,0x12,0x02,0x00,0x48, +0x24,0x05,0x00,0x01,0x8e,0x24,0x00,0x08,0x0c,0x00,0x07,0xb6,0x27,0xa6,0x00,0x14, +0x8f,0xa2,0x00,0x14,0x00,0x00,0x00,0x00,0x30,0x42,0x0f,0xff,0xaf,0xa2,0x00,0x14, +0x7b,0xa4,0x00,0xbc,0x0c,0x00,0x09,0x06,0x24,0x06,0x00,0x04,0x24,0x03,0x00,0x04, +0x10,0x43,0x00,0x2a,0x24,0x04,0x00,0x04,0x8f,0xa2,0x00,0x10,0x3c,0x04,0x80,0x01, +0x24,0x84,0x05,0x08,0x00,0x02,0x19,0x02,0x00,0x03,0x81,0x00,0x8f,0xa3,0x00,0x14, +0x00,0x50,0x10,0x23,0x00,0x02,0x10,0x82,0x00,0x62,0x18,0x21,0x0c,0x00,0x17,0xb0, +0xaf,0xa3,0x00,0x14,0x3c,0x04,0x80,0x01,0x0c,0x00,0x17,0xb0,0x24,0x84,0x05,0x30, +0x8f,0xa2,0x00,0x14,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x17,0x00,0x00,0x88,0x21, +0x3c,0x13,0x80,0x01,0x3c,0x12,0x80,0x01,0x3c,0x14,0x80,0x01,0x0c,0x00,0x29,0xa1, +0x24,0x04,0x27,0x10,0x32,0x23,0x00,0x03,0x02,0x00,0x28,0x21,0x10,0x60,0x00,0x1c, +0x26,0x64,0x05,0x5c,0x8f,0xa2,0x00,0x10,0x00,0x00,0x00,0x00,0x02,0x02,0x10,0x23, +0x28,0x42,0xff,0xfd,0x10,0x40,0x00,0x10,0x26,0x44,0x05,0x68,0x0c,0x00,0x17,0xb0, +0x26,0x10,0x00,0x04,0x8f,0xa2,0x00,0x14,0x26,0x31,0x00,0x01,0x02,0x22,0x10,0x2b, +0x14,0x40,0xff,0xee,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x21,0x8f,0xbf,0x00,0x2c, +0x8f,0xb4,0x00,0x28,0x7b,0xb2,0x01,0x3c,0x7b,0xb0,0x00,0xfc,0x00,0x80,0x10,0x21, +0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x30,0x8e,0x05,0x00,0x00,0x26,0x84,0x05,0x6c, +0x0c,0x00,0x17,0x9d,0x26,0x10,0x00,0x04,0x08,0x00,0x08,0xb1,0x00,0x00,0x00,0x00, +0x0c,0x00,0x17,0x9d,0x00,0x00,0x00,0x00,0x08,0x00,0x08,0xa9,0x00,0x00,0x00,0x00, +0x08,0x00,0x08,0x87,0x24,0x02,0x00,0x01,0x0c,0x00,0x0a,0x52,0x00,0x00,0x00,0x00, +0x08,0x00,0x08,0xb7,0x24,0x04,0x00,0x04,0x27,0xbd,0xff,0xd0,0x28,0xa2,0x00,0x03, +0xaf,0xb1,0x00,0x24,0xaf,0xb0,0x00,0x20,0xaf,0xbf,0x00,0x28,0x00,0xa0,0x88,0x21, +0x10,0x40,0x00,0x09,0x00,0xc0,0x80,0x21,0x0c,0x00,0x0a,0x52,0x00,0x00,0x00,0x00, +0x24,0x04,0x00,0x04,0x8f,0xbf,0x00,0x28,0x7b,0xb0,0x01,0x3c,0x00,0x80,0x10,0x21, +0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x30,0x8c,0xc4,0x00,0x04,0x24,0x05,0x00,0x02, +0x0c,0x00,0x07,0xb6,0x27,0xa6,0x00,0x10,0x8e,0x04,0x00,0x08,0x24,0x05,0x00,0x02, +0x0c,0x00,0x07,0xb6,0x27,0xa6,0x00,0x14,0x24,0x02,0x00,0x03,0x12,0x22,0x00,0x1b, +0x24,0x05,0x00,0x01,0x8e,0x04,0x00,0x0c,0x0c,0x00,0x07,0xb6,0x27,0xa6,0x00,0x18, +0x8f,0xa4,0x00,0x10,0x8f,0xa5,0x00,0x18,0x0c,0x00,0x09,0x06,0x24,0x06,0x00,0x04, +0x24,0x03,0x00,0x04,0x10,0x43,0xff,0xe7,0x24,0x04,0x00,0x04,0x8f,0xa2,0x00,0x18, +0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x0b,0x00,0x00,0x28,0x21,0x8f,0xa2,0x00,0x10, +0x8f,0xa4,0x00,0x14,0x24,0xa5,0x00,0x01,0xac,0x44,0x00,0x00,0x8f,0xa3,0x00,0x10, +0x8f,0xa2,0x00,0x18,0x24,0x63,0x00,0x04,0x00,0xa2,0x10,0x2b,0x14,0x40,0xff,0xf7, +0xaf,0xa3,0x00,0x10,0x08,0x00,0x08,0xd9,0x00,0x00,0x20,0x21,0x24,0x02,0x00,0x01, +0x08,0x00,0x08,0xec,0xaf,0xa2,0x00,0x18,0x30,0xc6,0x00,0xff,0x00,0xa6,0x00,0x18, +0x00,0x00,0x28,0x12,0x04,0x81,0x00,0x07,0x00,0x00,0x30,0x21,0x3c,0x02,0x80,0x01, +0x00,0x85,0x18,0x21,0x34,0x42,0x7f,0xff,0x00,0x43,0x10,0x2b,0x10,0x40,0x00,0x0b, +0x3c,0x02,0xb0,0x03,0x3c,0x02,0xaf,0xff,0x34,0x42,0xff,0xff,0x00,0x44,0x10,0x2b, +0x10,0x40,0x00,0x17,0x3c,0x02,0xb0,0x0a,0x00,0x85,0x18,0x21,0x34,0x42,0xff,0xff, +0x00,0x43,0x10,0x2b,0x14,0x40,0x00,0x12,0x3c,0x02,0xb0,0x03,0x34,0x42,0xff,0xff, +0x00,0x44,0x10,0x2b,0x10,0x40,0x00,0x06,0x3c,0x02,0xb0,0x07,0x3c,0x02,0xb0,0x04, +0x34,0x42,0xff,0xff,0x00,0x43,0x10,0x2b,0x10,0x40,0x00,0x09,0x3c,0x02,0xb0,0x07, +0x34,0x42,0x00,0x3f,0x00,0x44,0x10,0x2b,0x10,0x40,0x00,0x06,0x3c,0x02,0xb0,0x07, +0x34,0x42,0xff,0xff,0x00,0x43,0x10,0x2b,0x14,0x40,0x00,0x02,0x00,0x00,0x00,0x00, +0x24,0x06,0x00,0x01,0x14,0xc0,0x00,0x11,0x24,0x02,0x00,0x04,0x3c,0x02,0xb0,0x08, +0x34,0x42,0x0f,0xff,0x00,0x44,0x10,0x2b,0x14,0x40,0x00,0x08,0x3c,0x02,0x4f,0xf7, +0x00,0x85,0x20,0x21,0x34,0x42,0xf0,0x00,0x00,0x82,0x20,0x21,0x34,0x03,0xef,0xff, +0x00,0x64,0x18,0x2b,0x14,0x60,0x00,0x02,0x00,0x00,0x00,0x00,0x24,0x06,0x00,0x02, +0x10,0xc0,0x00,0x02,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x04,0x03,0xe0,0x00,0x08, +0x00,0x00,0x00,0x00,0x27,0xbd,0xff,0xe0,0x24,0x02,0x00,0x02,0xaf,0xb0,0x00,0x18, +0xaf,0xbf,0x00,0x1c,0x10,0xa2,0x00,0x23,0x00,0xc0,0x80,0x21,0x28,0xa2,0x00,0x03, +0x10,0x40,0x00,0x0c,0x24,0x02,0x00,0x03,0x24,0x02,0x00,0x01,0x10,0xa2,0x00,0x04, +0x00,0x00,0x18,0x21,0x0c,0x00,0x0a,0x52,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x21, +0x8f,0xbf,0x00,0x1c,0x8f,0xb0,0x00,0x18,0x00,0x60,0x10,0x21,0x03,0xe0,0x00,0x08, +0x27,0xbd,0x00,0x20,0x14,0xa2,0xff,0xf7,0x24,0x05,0x00,0x01,0x8c,0xc4,0x00,0x04, +0x0c,0x00,0x07,0xb6,0x27,0xa6,0x00,0x10,0x8e,0x04,0x00,0x08,0x24,0x05,0x00,0x02, +0x0c,0x00,0x07,0xb6,0x27,0xa6,0x00,0x14,0x8f,0xa4,0x00,0x10,0x00,0x00,0x00,0x00, +0x2c,0x82,0x00,0x0b,0x10,0x40,0xff,0xee,0x24,0x03,0x00,0x04,0x00,0x04,0x10,0x80, +0x8f,0xa4,0x00,0x14,0x27,0x83,0x91,0xc0,0x00,0x43,0x10,0x21,0x08,0x00,0x09,0x4f, +0xac,0x44,0x00,0x00,0x8c,0xc4,0x00,0x04,0x24,0x05,0x00,0x01,0x0c,0x00,0x07,0xb6, +0x27,0xa6,0x00,0x10,0x8f,0xa5,0x00,0x10,0x27,0x83,0x91,0xc0,0x3c,0x04,0x80,0x01, +0x00,0x05,0x10,0x80,0x00,0x43,0x10,0x21,0x8c,0x46,0x00,0x00,0x0c,0x00,0x17,0x9d, +0x24,0x84,0x05,0x74,0x08,0x00,0x09,0x50,0x00,0x00,0x18,0x21,0x03,0xe0,0x00,0x08, +0x00,0x00,0x00,0x00,0x8f,0x82,0x92,0x10,0x27,0xbd,0xff,0xe8,0xaf,0xbf,0x00,0x10, +0x8c,0x45,0x00,0x24,0x3c,0x04,0x80,0x01,0x0c,0x00,0x17,0x9d,0x24,0x84,0x05,0x88, +0x8f,0x83,0x92,0x10,0x3c,0x04,0x80,0x01,0x8c,0x65,0x00,0x28,0x0c,0x00,0x17,0x9d, +0x24,0x84,0x05,0x9c,0x8f,0x83,0x92,0x10,0x3c,0x04,0x80,0x01,0x8c,0x65,0x00,0x2c, +0x0c,0x00,0x17,0x9d,0x24,0x84,0x05,0xb0,0x8f,0x83,0x92,0x10,0x3c,0x04,0x80,0x01, +0x8c,0x65,0x00,0x30,0x0c,0x00,0x17,0x9d,0x24,0x84,0x05,0xc4,0x8f,0x83,0x92,0x10, +0x3c,0x04,0x80,0x01,0x8c,0x65,0x00,0x34,0x0c,0x00,0x17,0x9d,0x24,0x84,0x05,0xd8, +0x8f,0x83,0x92,0x10,0x3c,0x04,0x80,0x01,0x8c,0x65,0x00,0x38,0x0c,0x00,0x17,0x9d, +0x24,0x84,0x05,0xec,0x8f,0x83,0x92,0x10,0x3c,0x04,0x80,0x01,0x8c,0x65,0x00,0x3c, +0x0c,0x00,0x17,0x9d,0x24,0x84,0x05,0xfc,0x8f,0xbf,0x00,0x10,0x00,0x00,0x00,0x00, +0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00, +0x27,0xbd,0xff,0xb8,0x28,0xa5,0x00,0x04,0xaf,0xb0,0x00,0x20,0xaf,0xbf,0x00,0x40, +0xaf,0xb7,0x00,0x3c,0xaf,0xb6,0x00,0x38,0xaf,0xb5,0x00,0x34,0xaf,0xb4,0x00,0x30, +0xaf,0xb3,0x00,0x2c,0xaf,0xb2,0x00,0x28,0xaf,0xb1,0x00,0x24,0x10,0xa0,0x00,0x0b, +0x00,0xc0,0x80,0x21,0x0c,0x00,0x0a,0x52,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x04, +0x8f,0xbf,0x00,0x40,0x7b,0xb6,0x01,0xfc,0x7b,0xb4,0x01,0xbc,0x7b,0xb2,0x01,0x7c, +0x7b,0xb0,0x01,0x3c,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x48,0x8c,0xc4,0x00,0x04, +0x24,0x05,0x00,0x01,0x0c,0x00,0x07,0xb6,0x27,0xa6,0x00,0x10,0x8e,0x04,0x00,0x08, +0x24,0x05,0x00,0x01,0x0c,0x00,0x07,0xb6,0x27,0xa6,0x00,0x14,0x8e,0x04,0x00,0x0c, +0x24,0x05,0x00,0x01,0x0c,0x00,0x07,0xb6,0x27,0xa6,0x00,0x18,0x8f,0xa3,0x00,0x18, +0x00,0x00,0x00,0x00,0x10,0x60,0x00,0x3a,0x24,0x02,0x00,0x01,0x10,0x62,0x00,0x33, +0x3c,0x04,0x80,0x01,0x97,0xb0,0x00,0x12,0x8f,0xa2,0x00,0x14,0x00,0x00,0x00,0x00, +0x02,0x02,0x10,0x2b,0x10,0x40,0xff,0xe2,0x3c,0x15,0x80,0x01,0x3c,0x02,0x80,0x01, +0x24,0x52,0x06,0x3c,0x3c,0x14,0xb0,0x06,0x24,0x13,0x00,0x01,0x3c,0x17,0xb0,0x08, +0x3c,0x16,0x80,0x01,0x32,0x02,0x00,0x01,0x02,0x00,0x28,0x21,0x10,0x40,0x00,0x1f, +0x26,0xa4,0x06,0x30,0x8f,0xa3,0x00,0x18,0x00,0x10,0x10,0xc0,0x00,0x54,0x10,0x21, +0x10,0x60,0x00,0x14,0x02,0x40,0x20,0x21,0x00,0x10,0x10,0xc0,0x00,0x57,0x10,0x21, +0x10,0x73,0x00,0x09,0x26,0xc4,0x06,0x44,0x8f,0xa2,0x00,0x14,0x26,0x03,0x00,0x01, +0x30,0x70,0xff,0xff,0x02,0x02,0x10,0x2b,0x14,0x40,0xff,0xee,0x00,0x00,0x00,0x00, +0x08,0x00,0x09,0xb4,0x00,0x00,0x00,0x00,0x8c,0x51,0x00,0x00,0x00,0x00,0x00,0x00, +0x32,0x25,0x00,0xff,0x0c,0x00,0x17,0x9d,0x00,0x00,0x00,0x00,0x08,0x00,0x09,0xe6, +0x00,0x00,0x00,0x00,0x8c,0x51,0x00,0x00,0x0c,0x00,0x17,0x9d,0x00,0x11,0x2c,0x02, +0x32,0x25,0x00,0xff,0x08,0x00,0x09,0xf1,0x02,0x40,0x20,0x21,0x0c,0x00,0x17,0x9d, +0x00,0x00,0x00,0x00,0x08,0x00,0x09,0xdd,0x00,0x00,0x00,0x00,0x24,0x84,0x06,0x10, +0x0c,0x00,0x17,0xb0,0x00,0x00,0x00,0x00,0x08,0x00,0x09,0xcd,0x00,0x00,0x00,0x00, +0x3c,0x04,0x80,0x01,0x08,0x00,0x0a,0x00,0x24,0x84,0x06,0x50,0x00,0xa0,0x10,0x21, +0x27,0xbd,0xff,0xd8,0x28,0x42,0x00,0x04,0xaf,0xb0,0x00,0x20,0xaf,0xbf,0x00,0x24, +0x00,0xc0,0x80,0x21,0x24,0x05,0x00,0x01,0x10,0x40,0x00,0x08,0x27,0xa6,0x00,0x10, +0x0c,0x00,0x0a,0x52,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x04,0x8f,0xbf,0x00,0x24, +0x8f,0xb0,0x00,0x20,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x28,0x8e,0x04,0x00,0x04, +0x0c,0x00,0x07,0xb6,0x00,0x00,0x00,0x00,0x8e,0x04,0x00,0x08,0x24,0x05,0x00,0x01, +0x0c,0x00,0x07,0xb6,0x27,0xa6,0x00,0x14,0x8e,0x04,0x00,0x0c,0x24,0x05,0x00,0x01, +0x0c,0x00,0x07,0xb6,0x27,0xa6,0x00,0x18,0x08,0x00,0x0a,0x13,0x24,0x02,0x00,0x01, +0x24,0x03,0x00,0x01,0x00,0x65,0x10,0x2a,0x27,0xbd,0xff,0xd8,0x00,0xa0,0x40,0x21, +0x10,0x40,0x00,0x0b,0x00,0xc0,0x38,0x21,0x00,0x03,0x20,0x80,0x00,0x87,0x10,0x21, +0x8c,0x45,0x00,0x00,0x24,0x63,0x00,0x01,0x30,0x63,0x00,0xff,0x8c,0xa6,0x00,0x00, +0x00,0x9d,0x20,0x21,0x00,0x68,0x10,0x2a,0x14,0x40,0xff,0xf7,0xac,0x86,0xff,0xfc, +0x8f,0xa3,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x60,0x00,0x0b,0x00,0x00,0x00,0x00, +0x24,0x02,0x00,0x02,0x10,0x62,0x00,0x03,0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08, +0x27,0xbd,0x00,0x28,0x93,0xa2,0x00,0x07,0x00,0x00,0x00,0x00,0xa3,0x82,0x87,0xec, +0x08,0x00,0x0a,0x3b,0x00,0x00,0x00,0x00,0x93,0xa2,0x00,0x07,0x00,0x00,0x00,0x00, +0xa3,0x82,0x91,0xb0,0x08,0x00,0x0a,0x3b,0x00,0x00,0x00,0x00,0x27,0xbd,0xff,0xe8, +0x3c,0x04,0x80,0x01,0xaf,0xbf,0x00,0x10,0x18,0xa0,0x00,0x03,0x24,0x84,0x06,0x78, +0x0c,0x00,0x17,0xb0,0x00,0x00,0x00,0x00,0x8f,0xbf,0x00,0x10,0x24,0x02,0x00,0x01, +0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18,0x27,0xbd,0xff,0xe8,0xaf,0xb0,0x00,0x10, +0x00,0x80,0x80,0x21,0x3c,0x04,0x80,0x01,0xaf,0xbf,0x00,0x14,0x0c,0x00,0x17,0xb0, +0x24,0x84,0x06,0x8c,0x00,0x10,0x10,0x40,0x00,0x50,0x10,0x21,0x27,0x83,0x83,0x88, +0x00,0x02,0x10,0xc0,0x00,0x43,0x10,0x21,0x8c,0x44,0x00,0x08,0x0c,0x00,0x17,0xb0, +0x00,0x00,0x00,0x00,0x8f,0xbf,0x00,0x14,0x8f,0xb0,0x00,0x10,0x03,0xe0,0x00,0x08, +0x27,0xbd,0x00,0x18,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x27,0xbd,0xff,0xe8, +0x34,0x63,0x00,0x20,0x24,0x42,0x29,0x94,0x3c,0x04,0xb0,0x03,0xaf,0xbf,0x00,0x14, +0xac,0x62,0x00,0x00,0xaf,0xb0,0x00,0x10,0x34,0x84,0x00,0x2c,0x8c,0x83,0x00,0x00, +0xa7,0x80,0xc2,0x40,0x00,0x03,0x12,0x02,0x00,0x03,0x2d,0x02,0x30,0x42,0x0f,0xff, +0xa3,0x83,0xc2,0x48,0xa7,0x85,0xc2,0x4c,0xa7,0x82,0xc2,0x4a,0xa7,0x80,0xc2,0x42, +0xa7,0x80,0xc2,0x44,0xa7,0x80,0xc2,0x46,0x0c,0x00,0x0b,0xfa,0x24,0x04,0x05,0x00, +0x3c,0x05,0x08,0x00,0x00,0x45,0x28,0x25,0x24,0x04,0x05,0x00,0x0c,0x00,0x0b,0xed, +0x00,0x40,0x80,0x21,0x3c,0x02,0xf7,0xff,0x34,0x42,0xff,0xff,0x02,0x02,0x80,0x24, +0x02,0x00,0x28,0x21,0x0c,0x00,0x0b,0xed,0x24,0x04,0x05,0x00,0x3c,0x02,0xb0,0x03, +0x3c,0x03,0xb0,0x03,0x34,0x42,0x01,0x08,0x34,0x63,0x01,0x18,0x8c,0x45,0x00,0x00, +0x8c,0x64,0x00,0x00,0x3c,0x02,0x00,0x0f,0x3c,0x03,0x00,0x4c,0x30,0x84,0x02,0x00, +0x34,0x63,0x4b,0x40,0xaf,0x85,0xc2,0x50,0x10,0x80,0x00,0x06,0x34,0x42,0x42,0x40, +0xaf,0x83,0xc2,0x54,0x8f,0xbf,0x00,0x14,0x8f,0xb0,0x00,0x10,0x03,0xe0,0x00,0x08, +0x27,0xbd,0x00,0x18,0xaf,0x82,0xc2,0x54,0x08,0x00,0x0a,0x95,0x00,0x00,0x00,0x00, +0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x27,0xbd,0xff,0xc8,0x34,0x63,0x00,0x20, +0x24,0x42,0x2a,0x70,0x30,0x84,0x00,0xff,0xaf,0xbf,0x00,0x30,0xaf,0xb7,0x00,0x2c, +0xaf,0xb6,0x00,0x28,0xaf,0xb5,0x00,0x24,0xaf,0xb4,0x00,0x20,0xaf,0xb3,0x00,0x1c, +0xaf,0xb2,0x00,0x18,0xaf,0xb1,0x00,0x14,0xaf,0xb0,0x00,0x10,0xac,0x62,0x00,0x00, +0x10,0x80,0x00,0x1c,0x24,0x02,0x00,0x02,0x10,0x82,0x00,0x08,0x00,0x00,0x00,0x00, +0x8f,0xbf,0x00,0x30,0x7b,0xb6,0x01,0x7c,0x7b,0xb4,0x01,0x3c,0x7b,0xb2,0x00,0xfc, +0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x38,0xa7,0x80,0xc2,0x40, +0xa7,0x80,0xc2,0x42,0xa7,0x80,0xc2,0x44,0xa7,0x80,0xc2,0x46,0x0c,0x00,0x0b,0xfa, +0x24,0x04,0x05,0x00,0x3c,0x05,0x08,0x00,0x00,0x45,0x28,0x25,0x24,0x04,0x05,0x00, +0x0c,0x00,0x0b,0xed,0x00,0x40,0x80,0x21,0x3c,0x05,0xf7,0xff,0x34,0xa5,0xff,0xff, +0x02,0x05,0x28,0x24,0x0c,0x00,0x0b,0xed,0x24,0x04,0x05,0x00,0x08,0x00,0x0a,0xb0, +0x00,0x00,0x00,0x00,0x0c,0x00,0x0b,0xfa,0x24,0x04,0x05,0xa0,0x24,0x04,0x05,0xa4, +0x0c,0x00,0x0b,0xfa,0x00,0x02,0xbc,0x02,0x24,0x04,0x05,0xa8,0x00,0x02,0xb4,0x02, +0x0c,0x00,0x0b,0xfa,0x30,0x55,0xff,0xff,0x00,0x40,0x80,0x21,0x97,0x84,0xc2,0x40, +0x97,0x82,0xc2,0x42,0x97,0x83,0xc2,0x46,0x02,0xe4,0x20,0x23,0x02,0xa2,0x10,0x23, +0x00,0x82,0x20,0x21,0x97,0x82,0xc2,0x44,0x32,0x14,0xff,0xff,0x02,0x83,0x18,0x23, +0x02,0xc2,0x10,0x23,0x00,0x82,0x20,0x21,0x93,0x82,0xc2,0x48,0x00,0x83,0x20,0x21, +0x30,0x84,0xff,0xff,0x00,0x82,0x10,0x2b,0x14,0x40,0x00,0xaa,0x00,0x00,0x00,0x00, +0x97,0x82,0xc2,0x4c,0x00,0x00,0x00,0x00,0x00,0x44,0x10,0x2b,0x14,0x40,0x00,0x7f, +0x00,0x00,0x00,0x00,0x97,0x82,0xc2,0x4a,0x00,0x00,0x00,0x00,0x00,0x44,0x10,0x2b, +0x10,0x40,0x00,0x3a,0x00,0x00,0x00,0x00,0x0c,0x00,0x0b,0xfa,0x24,0x04,0x04,0x50, +0x30,0x51,0x00,0x7f,0x00,0x40,0x80,0x21,0x2e,0x22,0x00,0x32,0x10,0x40,0x00,0x13, +0x24,0x02,0x00,0x20,0x12,0x22,0x00,0x17,0x24,0x02,0xff,0x80,0x02,0x02,0x10,0x24, +0x26,0x31,0x00,0x01,0x00,0x51,0x80,0x25,0x02,0x00,0x28,0x21,0x0c,0x00,0x0b,0xed, +0x24,0x04,0x04,0x50,0x02,0x00,0x28,0x21,0x0c,0x00,0x0b,0xed,0x24,0x04,0x04,0x58, +0x02,0x00,0x28,0x21,0x0c,0x00,0x0b,0xed,0x24,0x04,0x04,0x60,0x02,0x00,0x28,0x21, +0x24,0x04,0x04,0x68,0x0c,0x00,0x0b,0xed,0x00,0x00,0x00,0x00,0xa7,0x97,0xc2,0x40, +0xa7,0x95,0xc2,0x42,0xa7,0x96,0xc2,0x44,0xa7,0x94,0xc2,0x46,0x08,0x00,0x0a,0xb0, +0x00,0x00,0x00,0x00,0x0c,0x00,0x0b,0xfa,0x24,0x04,0x02,0x08,0x3c,0x04,0x00,0xc0, +0x00,0x40,0x28,0x21,0x00,0x44,0x10,0x24,0x00,0x02,0x15,0x82,0x24,0x03,0x00,0x03, +0x10,0x43,0x00,0x07,0x00,0x00,0x00,0x00,0x3c,0x02,0xff,0x3f,0x34,0x42,0xff,0xff, +0x00,0xa2,0x10,0x24,0x00,0x44,0x28,0x25,0x0c,0x00,0x0b,0xed,0x24,0x04,0x02,0x08, +0x0c,0x00,0x0b,0xfa,0x24,0x04,0x02,0x2c,0x00,0x40,0x90,0x21,0x3c,0x02,0xff,0xff, +0x34,0x42,0x3f,0xff,0x02,0x42,0x90,0x24,0x02,0x40,0x28,0x21,0x0c,0x00,0x0b,0xed, +0x24,0x04,0x02,0x2c,0x08,0x00,0x0a,0xf7,0x24,0x02,0xff,0x80,0x0c,0x00,0x0b,0xfa, +0x24,0x04,0x04,0x50,0x30,0x51,0x00,0x7f,0x24,0x02,0x00,0x20,0x16,0x22,0xff,0xdb, +0x00,0x00,0x00,0x00,0x0c,0x00,0x0b,0xfa,0x24,0x04,0x02,0x2c,0x34,0x52,0x40,0x00, +0x02,0x40,0x28,0x21,0x0c,0x00,0x0b,0xed,0x24,0x04,0x02,0x2c,0x0c,0x00,0x0b,0xfa, +0x24,0x04,0x02,0x58,0x24,0x04,0x02,0x5c,0x0c,0x00,0x0b,0xfa,0x00,0x02,0x9e,0x02, +0x30,0x43,0x00,0xff,0x00,0x13,0x12,0x00,0x00,0x43,0x10,0x25,0x2c,0x43,0x00,0x04, +0x14,0x60,0x00,0x1d,0x2c,0x42,0x00,0x11,0x10,0x40,0x00,0x0b,0x00,0x00,0x00,0x00, +0x3c,0x02,0xff,0xff,0x34,0x42,0x3f,0xff,0x02,0x42,0x90,0x24,0x02,0x40,0x28,0x21, +0x24,0x04,0x02,0x2c,0x0c,0x00,0x0b,0xed,0x36,0x52,0x80,0x00,0x02,0x40,0x28,0x21, +0x08,0x00,0x0b,0x05,0x24,0x04,0x02,0x2c,0x0c,0x00,0x0b,0xfa,0x24,0x04,0x02,0x08, +0x3c,0x04,0x00,0xc0,0x00,0x40,0x28,0x21,0x00,0x44,0x10,0x24,0x00,0x02,0x15,0x82, +0x24,0x03,0x00,0x02,0x14,0x43,0xff,0xee,0x3c,0x02,0xff,0x3f,0x34,0x42,0xff,0xff, +0x00,0xa2,0x10,0x24,0x00,0x44,0x28,0x25,0x0c,0x00,0x0b,0xed,0x24,0x04,0x02,0x08, +0x08,0x00,0x0b,0x41,0x3c,0x02,0xff,0xff,0x0c,0x00,0x0b,0xfa,0x24,0x04,0x02,0x08, +0x00,0x40,0x28,0x21,0x00,0x02,0x15,0x82,0x30,0x42,0x00,0x03,0x24,0x03,0x00,0x03, +0x14,0x43,0xff,0xdf,0x3c,0x02,0xff,0x3f,0x34,0x42,0xff,0xff,0x00,0xa2,0x10,0x24, +0x3c,0x03,0x00,0x80,0x08,0x00,0x0b,0x56,0x00,0x43,0x28,0x25,0x0c,0x00,0x0b,0xfa, +0x24,0x04,0x04,0x50,0x30,0x51,0x00,0x7f,0x00,0x40,0x80,0x21,0x2e,0x22,0x00,0x32, +0x10,0x40,0xff,0x9a,0x24,0x02,0x00,0x20,0x12,0x22,0x00,0x04,0x24,0x02,0xff,0x80, +0x02,0x02,0x10,0x24,0x08,0x00,0x0a,0xf9,0x26,0x31,0x00,0x02,0x0c,0x00,0x0b,0xfa, +0x24,0x04,0x02,0x08,0x3c,0x04,0x00,0xc0,0x00,0x40,0x28,0x21,0x00,0x44,0x10,0x24, +0x00,0x02,0x15,0x82,0x24,0x03,0x00,0x03,0x10,0x43,0x00,0x07,0x00,0x00,0x00,0x00, +0x3c,0x02,0xff,0x3f,0x34,0x42,0xff,0xff,0x00,0xa2,0x10,0x24,0x00,0x44,0x28,0x25, +0x0c,0x00,0x0b,0xed,0x24,0x04,0x02,0x08,0x0c,0x00,0x0b,0xfa,0x24,0x04,0x02,0x2c, +0x00,0x40,0x90,0x21,0x3c,0x02,0xff,0xff,0x34,0x42,0x3f,0xff,0x02,0x42,0x90,0x24, +0x02,0x40,0x28,0x21,0x0c,0x00,0x0b,0xed,0x24,0x04,0x02,0x2c,0x08,0x00,0x0b,0x70, +0x24,0x02,0xff,0x80,0x0c,0x00,0x0b,0xfa,0x24,0x04,0x04,0x50,0x00,0x40,0x80,0x21, +0x30,0x51,0x00,0x7f,0x24,0x02,0x00,0x20,0x12,0x22,0x00,0x1d,0x2e,0x22,0x00,0x21, +0x14,0x40,0xff,0x72,0x24,0x02,0xff,0x80,0x02,0x02,0x10,0x24,0x26,0x31,0xff,0xff, +0x00,0x51,0x80,0x25,0x24,0x04,0x04,0x50,0x0c,0x00,0x0b,0xed,0x02,0x00,0x28,0x21, +0x24,0x04,0x04,0x58,0x0c,0x00,0x0b,0xed,0x02,0x00,0x28,0x21,0x24,0x04,0x04,0x60, +0x0c,0x00,0x0b,0xed,0x02,0x00,0x28,0x21,0x02,0x00,0x28,0x21,0x0c,0x00,0x0b,0xed, +0x24,0x04,0x04,0x68,0x24,0x02,0x00,0x20,0x16,0x22,0xff,0x60,0x00,0x00,0x00,0x00, +0x0c,0x00,0x0b,0xfa,0x24,0x04,0x02,0x2c,0x00,0x40,0x90,0x21,0x3c,0x02,0xff,0xff, +0x34,0x42,0x3f,0xff,0x02,0x42,0x10,0x24,0x08,0x00,0x0b,0x47,0x34,0x52,0x80,0x00, +0x0c,0x00,0x0b,0xfa,0x24,0x04,0x02,0x2c,0x34,0x52,0x40,0x00,0x02,0x40,0x28,0x21, +0x0c,0x00,0x0b,0xed,0x24,0x04,0x02,0x2c,0x0c,0x00,0x0b,0xfa,0x24,0x04,0x02,0x58, +0x24,0x04,0x02,0x5c,0x0c,0x00,0x0b,0xfa,0x00,0x02,0x9e,0x02,0x30,0x43,0x00,0xff, +0x00,0x13,0x12,0x00,0x00,0x43,0x10,0x25,0x2c,0x43,0x00,0x04,0x14,0x60,0x00,0x20, +0x2c,0x42,0x00,0x11,0x10,0x40,0x00,0x0d,0x00,0x00,0x00,0x00,0x3c,0x02,0xff,0xff, +0x34,0x42,0x3f,0xff,0x02,0x42,0x90,0x24,0x02,0x40,0x28,0x21,0x24,0x04,0x02,0x2c, +0x0c,0x00,0x0b,0xed,0x36,0x52,0x80,0x00,0x02,0x40,0x28,0x21,0x0c,0x00,0x0b,0xed, +0x24,0x04,0x02,0x2c,0x08,0x00,0x0b,0x94,0x2e,0x22,0x00,0x21,0x0c,0x00,0x0b,0xfa, +0x24,0x04,0x02,0x08,0x3c,0x04,0x00,0xc0,0x00,0x40,0x28,0x21,0x00,0x44,0x10,0x24, +0x00,0x02,0x15,0x82,0x24,0x03,0x00,0x02,0x14,0x43,0xff,0xec,0x00,0x00,0x00,0x00, +0x3c,0x02,0xff,0x3f,0x34,0x42,0xff,0xff,0x00,0xa2,0x10,0x24,0x00,0x44,0x28,0x25, +0x0c,0x00,0x0b,0xed,0x24,0x04,0x02,0x08,0x08,0x00,0x0b,0xc4,0x3c,0x02,0xff,0xff, +0x0c,0x00,0x0b,0xfa,0x24,0x04,0x02,0x08,0x00,0x40,0x28,0x21,0x00,0x02,0x15,0x82, +0x30,0x42,0x00,0x03,0x24,0x03,0x00,0x03,0x14,0x43,0xff,0xdc,0x3c,0x03,0x00,0x80, +0x3c,0x02,0xff,0x3f,0x34,0x42,0xff,0xff,0x00,0xa2,0x10,0x24,0x08,0x00,0x0b,0xdc, +0x00,0x43,0x28,0x25,0x30,0x83,0x00,0x03,0x00,0x04,0x20,0x40,0x00,0x83,0x20,0x23, +0x3c,0x02,0xb0,0x0a,0x00,0x82,0x20,0x21,0xac,0x85,0x00,0x00,0x00,0x00,0x18,0x21, +0x24,0x63,0x00,0x01,0x2c,0x62,0x00,0x0a,0x14,0x40,0xff,0xfe,0x24,0x63,0x00,0x01, +0x03,0xe0,0x00,0x08,0x24,0x63,0xff,0xff,0x30,0x86,0x00,0x03,0x00,0x04,0x28,0x40, +0x3c,0x03,0xb0,0x0a,0x00,0xa6,0x10,0x23,0x00,0x43,0x10,0x21,0x24,0x04,0xff,0xff, +0xac,0x44,0x10,0x00,0x00,0x00,0x18,0x21,0x24,0x63,0x00,0x01,0x2c,0x62,0x00,0x0a, +0x14,0x40,0xff,0xfe,0x24,0x63,0x00,0x01,0x24,0x63,0xff,0xff,0x00,0xa6,0x18,0x23, +0x3c,0x02,0xb0,0x0a,0x00,0x62,0x18,0x21,0x8c,0x62,0x00,0x00,0x03,0xe0,0x00,0x08, +0x00,0x00,0x00,0x00,0x3c,0x05,0xb0,0x03,0x3c,0x02,0x80,0x00,0x24,0x42,0x30,0x34, +0x24,0x03,0x00,0x01,0x34,0xa5,0x00,0x20,0x3c,0x06,0xb0,0x03,0xac,0xa2,0x00,0x00, +0x34,0xc6,0x01,0x04,0xa0,0x83,0x00,0x48,0xa0,0x80,0x00,0x04,0xa0,0x80,0x00,0x05, +0xa0,0x80,0x00,0x06,0xa0,0x80,0x00,0x07,0xa0,0x80,0x00,0x08,0xa0,0x80,0x00,0x09, +0xa0,0x80,0x00,0x0a,0xa0,0x80,0x00,0x11,0xa0,0x80,0x00,0x13,0xa0,0x80,0x00,0x49, +0x94,0xc2,0x00,0x00,0xac,0x80,0x00,0x00,0xac,0x80,0x00,0x24,0x00,0x02,0x14,0x00, +0x00,0x02,0x14,0x03,0x30,0x43,0x00,0xff,0x30,0x42,0xff,0x00,0xa4,0x83,0x00,0x46, +0xa4,0x82,0x00,0x44,0xac,0x80,0x00,0x28,0xac,0x80,0x00,0x2c,0xac,0x80,0x00,0x30, +0xac,0x80,0x00,0x34,0xac,0x80,0x00,0x38,0xac,0x80,0x00,0x3c,0x03,0xe0,0x00,0x08, +0xac,0x80,0x00,0x40,0x84,0x83,0x00,0x0c,0x3c,0x07,0xb0,0x03,0x34,0xe7,0x00,0x20, +0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80,0x27,0x83,0x96,0x44, +0x00,0x43,0x10,0x21,0x8c,0x48,0x00,0x18,0x3c,0x02,0x80,0x00,0x24,0x42,0x30,0xc4, +0xac,0xe2,0x00,0x00,0x8d,0x03,0x00,0x08,0x80,0x82,0x00,0x13,0x00,0x05,0x2c,0x00, +0x00,0x03,0x1e,0x02,0x00,0x02,0x12,0x00,0x30,0x63,0x00,0x7e,0x00,0x62,0x18,0x21, +0x00,0x65,0x18,0x21,0x3c,0x02,0xc0,0x00,0x3c,0x05,0xb0,0x05,0x34,0x42,0x04,0x00, +0x24,0x63,0x00,0x01,0x3c,0x07,0xb0,0x05,0x3c,0x08,0xb0,0x05,0x34,0xa5,0x04,0x20, +0xac,0xa3,0x00,0x00,0x00,0xc2,0x30,0x21,0x34,0xe7,0x04,0x24,0x35,0x08,0x02,0x28, +0x24,0x02,0x00,0x01,0x24,0x03,0x00,0x20,0xac,0xe6,0x00,0x00,0xac,0x82,0x00,0x3c, +0x03,0xe0,0x00,0x08,0xa1,0x03,0x00,0x00,0x27,0xbd,0xff,0xc0,0x00,0x07,0x60,0x80, +0x27,0x82,0xba,0x40,0xaf,0xb7,0x00,0x34,0xaf,0xb5,0x00,0x2c,0xaf,0xb3,0x00,0x24, +0xaf,0xbf,0x00,0x3c,0xaf,0xbe,0x00,0x38,0xaf,0xb6,0x00,0x30,0xaf,0xb4,0x00,0x28, +0xaf,0xb2,0x00,0x20,0xaf,0xb1,0x00,0x1c,0xaf,0xb0,0x00,0x18,0x01,0x82,0x10,0x21, +0x8c,0x43,0x00,0x00,0x3c,0x07,0xb0,0x03,0x3c,0x02,0x80,0x00,0x94,0x71,0x00,0x14, +0x34,0xe7,0x00,0x20,0x24,0x42,0x31,0x58,0x3c,0x03,0xb0,0x05,0xac,0xe2,0x00,0x00, +0x34,0x63,0x01,0x28,0x90,0x67,0x00,0x00,0x00,0x11,0xa8,0xc0,0x02,0xb1,0x18,0x21, +0x27,0x82,0x96,0x44,0x00,0x03,0x18,0x80,0x00,0x62,0x18,0x21,0x00,0x05,0x2c,0x00, +0x00,0x07,0x3e,0x00,0x28,0xc2,0x00,0x03,0x00,0xc0,0x98,0x21,0xaf,0xa4,0x00,0x40, +0x00,0x05,0x6c,0x03,0x8c,0x68,0x00,0x18,0x02,0xa0,0x58,0x21,0x10,0x40,0x01,0x4f, +0x00,0x07,0xbe,0x03,0x00,0xd7,0x10,0x07,0x30,0x57,0x00,0x01,0x01,0x71,0x10,0x21, +0x27,0x83,0x96,0x48,0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21,0x80,0x4e,0x00,0x06, +0x8d,0x03,0x00,0x00,0x8d,0x0f,0x00,0x04,0x8d,0x0a,0x00,0x08,0x8d,0x10,0x00,0x0c, +0x11,0xc0,0x00,0x1c,0x00,0x00,0xa0,0x21,0x27,0x82,0xba,0x40,0x01,0x82,0x10,0x21, +0x8c,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x90,0x83,0x00,0x16,0x00,0x00,0x00,0x00, +0x30,0x63,0x00,0x04,0x14,0x60,0x00,0x13,0x3c,0x02,0xb0,0x09,0x34,0x42,0x01,0x46, +0x90,0x43,0x00,0x00,0x2a,0x64,0x00,0x04,0x10,0x80,0x01,0x26,0x30,0x65,0x00,0x01, +0x8f,0xa3,0x00,0x40,0x00,0x00,0x00,0x00,0x90,0x62,0x00,0x09,0x00,0x00,0x00,0x00, +0x12,0x62,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x21,0x14,0xa0,0x00,0x03, +0x00,0x00,0x38,0x21,0x12,0xe0,0x00,0x03,0x38,0xf4,0x00,0x01,0x24,0x07,0x00,0x01, +0x38,0xf4,0x00,0x01,0x01,0x71,0x10,0x21,0x00,0x02,0x38,0x80,0x27,0x83,0x96,0x50, +0x00,0xe3,0x48,0x21,0x91,0x25,0x00,0x00,0x00,0x0f,0x11,0xc3,0x2c,0xa3,0x00,0x04, +0x00,0x03,0xa0,0x0b,0x12,0x80,0x00,0xc7,0x30,0x52,0x00,0x01,0x93,0x88,0xc2,0x2a, +0x00,0x0a,0x16,0x42,0x30,0x4a,0x00,0x3f,0x2d,0x06,0x00,0x0c,0x10,0xc0,0x00,0xaf, +0x00,0xa0,0x20,0x21,0x2c,0xa2,0x00,0x10,0x14,0x40,0x00,0x04,0x00,0x88,0x10,0x2b, +0x30,0xa2,0x00,0x07,0x24,0x44,0x00,0x04,0x00,0x88,0x10,0x2b,0x10,0x40,0x00,0x0b, +0x01,0x71,0x10,0x21,0x27,0x85,0xc1,0x5c,0x00,0x08,0x10,0x40,0x00,0x48,0x10,0x21, +0x00,0x45,0x10,0x21,0x90,0x48,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x88,0x18,0x2b, +0x14,0x60,0xff,0xfa,0x00,0x08,0x10,0x40,0x01,0x71,0x10,0x21,0x00,0x02,0x10,0x80, +0x27,0x83,0x96,0x48,0x00,0x43,0x10,0x21,0x31,0xc4,0x00,0x01,0x10,0x80,0x00,0x94, +0xa0,0x48,0x00,0x07,0x24,0x0d,0x00,0x0e,0x24,0x11,0x01,0x06,0x27,0x82,0xba,0x40, +0x01,0x82,0x10,0x21,0x8c,0x43,0x00,0x00,0x24,0x16,0x00,0x01,0x00,0x11,0xa8,0xc0, +0x90,0x62,0x00,0x16,0x00,0x00,0x00,0x00,0x34,0x42,0x00,0x04,0xa0,0x62,0x00,0x16, +0x00,0x0f,0x1b,0x43,0x30,0x7e,0x00,0x01,0x00,0x0a,0x10,0x40,0x00,0x12,0x19,0xc0, +0x00,0x5e,0x10,0x21,0x00,0x08,0x22,0x00,0x00,0x43,0x10,0x21,0x00,0x44,0x10,0x21, +0x00,0x0d,0x1c,0x00,0x00,0x10,0x82,0x02,0x01,0x00,0x28,0x21,0x00,0x00,0x20,0x21, +0x00,0x43,0x90,0x21,0x0c,0x00,0x01,0xdd,0x32,0x10,0x07,0xff,0x00,0x16,0x12,0x80, +0x00,0x10,0x84,0x80,0x02,0x22,0x10,0x21,0x00,0x50,0x10,0x21,0x3c,0x03,0xc0,0x00, +0x16,0x60,0x00,0x2b,0x00,0x43,0x80,0x21,0x3c,0x02,0xb0,0x05,0x34,0x42,0x04,0x00, +0x3c,0x03,0xb0,0x05,0x3c,0x04,0xb0,0x05,0xac,0x52,0x00,0x00,0x34,0x63,0x04,0x04, +0x34,0x84,0x02,0x28,0x24,0x02,0x00,0x01,0xac,0x70,0x00,0x00,0xa0,0x82,0x00,0x00, +0x3c,0x02,0xb0,0x09,0x34,0x42,0x01,0x46,0x90,0x44,0x00,0x00,0x8f,0xa2,0x00,0x40, +0x30,0x86,0x00,0x01,0x90,0x43,0x00,0x09,0x00,0x00,0x00,0x00,0x02,0x63,0x18,0x26, +0x00,0x03,0x30,0x0b,0x14,0xc0,0x00,0x03,0x00,0x00,0x28,0x21,0x12,0xe0,0x00,0x03, +0x02,0xb1,0x10,0x21,0x24,0x05,0x00,0x01,0x02,0xb1,0x10,0x21,0x27,0x83,0x96,0x48, +0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21,0x84,0x48,0x00,0x04,0x00,0xa0,0x30,0x21, +0x03,0xc0,0x20,0x21,0x02,0x60,0x28,0x21,0x02,0x80,0x38,0x21,0x0c,0x00,0x00,0x70, +0xaf,0xa8,0x00,0x10,0x7b,0xbe,0x01,0xfc,0x7b,0xb6,0x01,0xbc,0x7b,0xb4,0x01,0x7c, +0x7b,0xb2,0x01,0x3c,0x7b,0xb0,0x00,0xfc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x40, +0x24,0x02,0x00,0x01,0x12,0x62,0x00,0x3d,0x3c,0x02,0xb0,0x05,0x24,0x02,0x00,0x02, +0x12,0x62,0x00,0x31,0x3c,0x02,0xb0,0x05,0x24,0x02,0x00,0x03,0x12,0x62,0x00,0x25, +0x3c,0x02,0xb0,0x05,0x24,0x02,0x00,0x10,0x12,0x62,0x00,0x19,0x3c,0x02,0xb0,0x05, +0x24,0x02,0x00,0x11,0x12,0x62,0x00,0x0d,0x3c,0x02,0xb0,0x05,0x24,0x02,0x00,0x12, +0x16,0x62,0xff,0xcf,0x3c,0x02,0xb0,0x05,0x3c,0x03,0xb0,0x05,0x34,0x42,0x04,0x20, +0x3c,0x04,0xb0,0x05,0x34,0x63,0x04,0x24,0xac,0x52,0x00,0x00,0x34,0x84,0x02,0x28, +0xac,0x70,0x00,0x00,0x08,0x00,0x0c,0xf7,0x24,0x02,0x00,0x20,0x34,0x42,0x04,0x40, +0x3c,0x03,0xb0,0x05,0x3c,0x04,0xb0,0x05,0xac,0x52,0x00,0x00,0x34,0x63,0x04,0x44, +0x34,0x84,0x02,0x28,0x24,0x02,0x00,0x40,0x08,0x00,0x0c,0xf7,0xac,0x70,0x00,0x00, +0x34,0x42,0x04,0x28,0x3c,0x03,0xb0,0x05,0x3c,0x04,0xb0,0x05,0xac,0x52,0x00,0x00, +0x34,0x63,0x04,0x2c,0x34,0x84,0x02,0x28,0x24,0x02,0xff,0x80,0x08,0x00,0x0c,0xf7, +0xac,0x70,0x00,0x00,0x34,0x42,0x04,0x18,0x3c,0x03,0xb0,0x05,0x3c,0x04,0xb0,0x05, +0xac,0x52,0x00,0x00,0x34,0x63,0x04,0x1c,0x34,0x84,0x02,0x28,0x24,0x02,0x00,0x08, +0x08,0x00,0x0c,0xf7,0xac,0x70,0x00,0x00,0x34,0x42,0x04,0x10,0x3c,0x03,0xb0,0x05, +0x3c,0x04,0xb0,0x05,0xac,0x52,0x00,0x00,0x34,0x63,0x04,0x14,0x34,0x84,0x02,0x28, +0x24,0x02,0x00,0x04,0x08,0x00,0x0c,0xf7,0xac,0x70,0x00,0x00,0x34,0x42,0x04,0x08, +0x3c,0x03,0xb0,0x05,0x3c,0x04,0xb0,0x05,0xac,0x52,0x00,0x00,0x34,0x63,0x04,0x0c, +0x34,0x84,0x02,0x28,0x24,0x02,0x00,0x02,0x08,0x00,0x0c,0xf7,0xac,0x70,0x00,0x00, +0x24,0x0d,0x00,0x14,0x08,0x00,0x0c,0xcf,0x24,0x11,0x01,0x02,0x30,0xa2,0x00,0x07, +0x24,0x44,0x00,0x0c,0x00,0x88,0x18,0x2b,0x10,0x60,0x00,0x0c,0x25,0x02,0x00,0x04, +0x27,0x85,0xc1,0x5c,0x00,0x08,0x10,0x40,0x00,0x48,0x10,0x21,0x00,0x45,0x10,0x21, +0x90,0x48,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x88,0x18,0x2b,0x14,0x60,0xff,0xfa, +0x00,0x08,0x10,0x40,0x2d,0x06,0x00,0x0c,0x25,0x02,0x00,0x04,0x08,0x00,0x0c,0xc6, +0x00,0x46,0x40,0x0a,0x27,0x82,0xba,0x40,0x01,0x82,0x20,0x21,0x8c,0x86,0x00,0x00, +0x00,0x00,0x00,0x00,0x90,0xc2,0x00,0x19,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x07, +0x00,0x00,0x00,0x00,0x27,0x82,0x96,0x60,0x00,0xe2,0x10,0x21,0x90,0x43,0x00,0x00, +0x00,0x00,0x00,0x00,0x10,0x60,0x00,0x12,0x00,0x00,0x00,0x00,0x90,0xc3,0x00,0x16, +0x27,0x82,0x96,0x48,0x00,0xe2,0x10,0x21,0x34,0x63,0x00,0x20,0x90,0x48,0x00,0x07, +0xa0,0xc3,0x00,0x16,0x8c,0x84,0x00,0x00,0x00,0x0a,0x16,0x42,0x30,0x4a,0x00,0x3f, +0x90,0x83,0x00,0x16,0x24,0x0d,0x00,0x18,0x24,0x11,0x01,0x03,0x30,0x63,0x00,0xfb, +0x24,0x16,0x00,0x01,0x24,0x15,0x08,0x18,0x08,0x00,0x0c,0xd8,0xa0,0x83,0x00,0x16, +0x8d,0x02,0x00,0x04,0x00,0x0a,0x1c,0x42,0x30,0x42,0x00,0x10,0x14,0x40,0x00,0x15, +0x30,0x6a,0x00,0x3f,0x81,0x22,0x00,0x05,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x11, +0x30,0x6a,0x00,0x3e,0x27,0x83,0x96,0x58,0x00,0xe3,0x18,0x21,0x80,0x64,0x00,0x00, +0x27,0x83,0xbb,0xb8,0x00,0x04,0x11,0x00,0x00,0x44,0x10,0x23,0x00,0x02,0x10,0x80, +0x00,0x44,0x10,0x23,0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21,0x90,0x44,0x00,0x05, +0x90,0x43,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x64,0x18,0x24,0x30,0x63,0x00,0x01, +0x01,0x43,0x50,0x25,0x27,0x85,0xba,0x40,0x01,0x85,0x28,0x21,0x8c,0xa6,0x00,0x00, +0x01,0x71,0x10,0x21,0x27,0x83,0x96,0x50,0x90,0xc4,0x00,0x16,0x00,0x02,0x10,0x80, +0x00,0x43,0x10,0x21,0x30,0x84,0x00,0xdf,0x90,0x48,0x00,0x00,0xa0,0xc4,0x00,0x16, +0x8c,0xa3,0x00,0x00,0x80,0xd6,0x00,0x12,0x90,0x62,0x00,0x16,0x08,0x00,0x0c,0xd7, +0x30,0x42,0x00,0xfb,0x3c,0x03,0xb0,0x05,0x34,0x63,0x02,0x42,0x90,0x62,0x00,0x00, +0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x0f,0x14,0x40,0xfe,0xdc,0x00,0x00,0x00,0x00, +0x8f,0xa3,0x00,0x40,0x00,0x00,0x00,0x00,0x90,0x62,0x00,0x09,0x00,0x00,0x00,0x00, +0x02,0x62,0x10,0x26,0x08,0x00,0x0c,0x9f,0x00,0x02,0x28,0x0b,0x24,0x02,0x00,0x10, +0x10,0xc2,0x00,0x08,0x24,0x02,0x00,0x11,0x10,0xc2,0xfe,0xaf,0x00,0x07,0x17,0x83, +0x24,0x02,0x00,0x12,0x14,0xc2,0xfe,0xad,0x00,0x07,0x17,0x43,0x08,0x00,0x0c,0x7f, +0x30,0x57,0x00,0x01,0x08,0x00,0x0c,0x7f,0x00,0x07,0xbf,0xc2,0x00,0x04,0x10,0x40, +0x27,0x83,0x86,0xb0,0x00,0x43,0x10,0x21,0x00,0x80,0x40,0x21,0x94,0x44,0x00,0x00, +0x2d,0x07,0x00,0x04,0x24,0xc2,0x00,0x03,0x00,0x47,0x30,0x0a,0x00,0x86,0x00,0x18, +0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x34,0x63,0x00,0x20,0x24,0x42,0x37,0x5c, +0xac,0x62,0x00,0x00,0x2d,0x06,0x00,0x10,0x00,0x00,0x20,0x12,0x00,0x04,0x22,0x42, +0x24,0x84,0x00,0x01,0x24,0x83,0x00,0xc0,0x10,0xe0,0x00,0x0b,0x24,0x82,0x00,0x60, +0x00,0x40,0x20,0x21,0x00,0x65,0x20,0x0a,0x3c,0x03,0xb0,0x03,0x34,0x63,0x01,0x00, +0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x01,0x00,0x44,0x20,0x04, +0x03,0xe0,0x00,0x08,0x00,0x80,0x10,0x21,0x24,0x85,0x00,0x28,0x24,0x83,0x00,0x24, +0x31,0x02,0x00,0x08,0x14,0xc0,0xff,0xf4,0x24,0x84,0x00,0x14,0x00,0x60,0x20,0x21, +0x08,0x00,0x0d,0xee,0x00,0xa2,0x20,0x0b,0x27,0xbd,0xff,0xe0,0x3c,0x03,0xb0,0x03, +0x3c,0x02,0x80,0x00,0xaf,0xb0,0x00,0x10,0x24,0x42,0x37,0xf8,0x00,0x80,0x80,0x21, +0x34,0x63,0x00,0x20,0x3c,0x04,0xb0,0x03,0xaf,0xb2,0x00,0x18,0xaf,0xb1,0x00,0x14, +0xaf,0xbf,0x00,0x1c,0x83,0xb1,0x00,0x33,0x83,0xa8,0x00,0x37,0x34,0x84,0x01,0x10, +0xac,0x62,0x00,0x00,0x2e,0x02,0x00,0x10,0x00,0xe0,0x90,0x21,0x8c,0x87,0x00,0x00, +0x14,0x40,0x00,0x0c,0x2e,0x02,0x00,0x0c,0x3c,0x02,0x00,0x0f,0x34,0x42,0xf0,0x00, +0x00,0xe2,0x10,0x24,0x14,0x40,0x00,0x37,0x32,0x02,0x00,0x08,0x32,0x02,0x00,0x07, +0x27,0x83,0x87,0x60,0x00,0x43,0x10,0x21,0x90,0x50,0x00,0x00,0x00,0x00,0x00,0x00, +0x2e,0x02,0x00,0x0c,0x14,0x40,0x00,0x03,0x02,0x00,0x20,0x21,0x32,0x02,0x00,0x0f, +0x24,0x44,0x00,0x0c,0x00,0x87,0x10,0x06,0x30,0x42,0x00,0x01,0x14,0x40,0x00,0x07, +0x2c,0x82,0x00,0x0c,0x00,0x04,0x10,0x80,0x27,0x83,0xba,0x90,0x00,0x43,0x10,0x21, +0x8c,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x2c,0x82,0x00,0x0c,0x14,0x40,0x00,0x05, +0x00,0x05,0x10,0x40,0x00,0x46,0x10,0x21,0x00,0x02,0x11,0x00,0x00,0x82,0x10,0x21, +0x24,0x44,0x00,0x04,0x15,0x00,0x00,0x02,0x24,0x06,0x00,0x20,0x24,0x06,0x00,0x0e, +0x0c,0x00,0x0d,0xd7,0x00,0x00,0x00,0x00,0x00,0x40,0x30,0x21,0x3c,0x02,0xb0,0x03, +0x34,0x42,0x01,0x00,0x90,0x43,0x00,0x00,0x2e,0x04,0x00,0x04,0x24,0x02,0x00,0x10, +0x24,0x05,0x00,0x0a,0x00,0x44,0x28,0x0a,0x30,0x63,0x00,0x01,0x14,0x60,0x00,0x02, +0x00,0x05,0x10,0x40,0x00,0xa0,0x10,0x21,0x30,0x45,0x00,0xff,0x00,0xc5,0x10,0x21, +0x24,0x46,0x00,0x46,0x02,0x26,0x18,0x04,0xa6,0x43,0x00,0x00,0x8f,0xbf,0x00,0x1c, +0x8f,0xb2,0x00,0x18,0x7b,0xb0,0x00,0xbc,0x00,0xc0,0x10,0x21,0x03,0xe0,0x00,0x08, +0x27,0xbd,0x00,0x20,0x10,0x40,0xff,0xcf,0x2e,0x02,0x00,0x0c,0x32,0x02,0x00,0x07, +0x27,0x83,0x87,0x58,0x00,0x43,0x10,0x21,0x90,0x44,0x00,0x00,0x08,0x00,0x0e,0x1c, +0x02,0x04,0x80,0x23,0x27,0xbd,0xff,0xb8,0x00,0x05,0x38,0x80,0x27,0x82,0xba,0x40, +0xaf,0xbe,0x00,0x40,0xaf,0xb6,0x00,0x38,0xaf,0xb4,0x00,0x30,0xaf,0xbf,0x00,0x44, +0xaf,0xb7,0x00,0x3c,0xaf,0xb5,0x00,0x34,0xaf,0xb3,0x00,0x2c,0xaf,0xb2,0x00,0x28, +0xaf,0xb1,0x00,0x24,0xaf,0xb0,0x00,0x20,0x00,0xe2,0x38,0x21,0x8c,0xe6,0x00,0x00, +0xaf,0xa5,0x00,0x4c,0x3c,0x02,0x80,0x00,0x3c,0x05,0xb0,0x03,0x34,0xa5,0x00,0x20, +0x24,0x42,0x39,0x54,0x24,0x03,0x00,0x01,0xac,0xa2,0x00,0x00,0xa0,0xc3,0x00,0x12, +0x8c,0xe5,0x00,0x00,0x94,0xc3,0x00,0x06,0x90,0xa2,0x00,0x16,0xa4,0xc3,0x00,0x14, +0x27,0x83,0x96,0x40,0x34,0x42,0x00,0x08,0xa0,0xa2,0x00,0x16,0x8c,0xe8,0x00,0x00, +0xaf,0xa4,0x00,0x48,0x27,0x82,0x96,0x44,0x95,0x11,0x00,0x14,0x00,0x00,0x00,0x00, +0x00,0x11,0xa0,0xc0,0x02,0x91,0x20,0x21,0x00,0x04,0x20,0x80,0x00,0x82,0x10,0x21, +0x8c,0x53,0x00,0x18,0x00,0x83,0x18,0x21,0x84,0x75,0x00,0x06,0x8e,0x65,0x00,0x08, +0x8e,0x66,0x00,0x04,0x8e,0x67,0x00,0x04,0x00,0x05,0x1c,0x82,0x00,0x06,0x31,0x42, +0x27,0x82,0x96,0x50,0x30,0x63,0x00,0x01,0x30,0xc6,0x00,0x01,0x00,0x82,0x20,0x21, +0xa5,0x15,0x00,0x1a,0x00,0x05,0x14,0x42,0xaf,0xa3,0x00,0x18,0xaf,0xa6,0x00,0x1c, +0x30,0xe7,0x00,0x10,0x30,0x56,0x00,0x01,0x80,0x97,0x00,0x06,0x14,0xe0,0x00,0x42, +0x00,0x05,0xf7,0xc2,0x80,0x82,0x00,0x05,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x3f, +0x02,0x91,0x10,0x21,0x93,0x90,0xc2,0x29,0x00,0x00,0x00,0x00,0x2e,0x02,0x00,0x0c, +0x14,0x40,0x00,0x06,0x02,0x00,0x20,0x21,0x00,0x16,0x10,0x40,0x00,0x43,0x10,0x21, +0x00,0x02,0x11,0x00,0x02,0x02,0x10,0x21,0x24,0x44,0x00,0x04,0x02,0x91,0x10,0x21, +0x00,0x02,0x10,0x80,0x27,0x83,0x96,0x50,0x00,0x43,0x10,0x21,0x00,0x80,0x80,0x21, +0xa0,0x44,0x00,0x03,0xa0,0x44,0x00,0x00,0x02,0x00,0x20,0x21,0x02,0xc0,0x28,0x21, +0x0c,0x00,0x0d,0xd7,0x02,0xa0,0x30,0x21,0x02,0x91,0x18,0x21,0x00,0x03,0x88,0x80, +0x00,0x40,0x90,0x21,0x27,0x82,0x96,0x60,0x02,0x22,0x10,0x21,0x8c,0x44,0x00,0x00, +0x26,0xe3,0x00,0x02,0x00,0x03,0x17,0xc2,0x00,0x62,0x18,0x21,0x00,0x04,0x25,0xc2, +0x00,0x03,0x18,0x43,0x30,0x84,0x00,0x01,0x00,0x03,0x18,0x40,0x03,0xc4,0x20,0x24, +0x14,0x80,0x00,0x10,0x02,0x63,0x38,0x21,0x8f,0xa6,0x00,0x4c,0x8f,0xa4,0x00,0x48, +0x27,0x82,0x96,0x48,0x02,0x22,0x10,0x21,0x02,0xa0,0x28,0x21,0xa4,0x52,0x00,0x04, +0x0c,0x00,0x0c,0x56,0x00,0xc0,0x38,0x21,0x7b,0xbe,0x02,0x3c,0x7b,0xb6,0x01,0xfc, +0x7b,0xb4,0x01,0xbc,0x7b,0xb2,0x01,0x7c,0x7b,0xb0,0x01,0x3c,0x03,0xe0,0x00,0x08, +0x27,0xbd,0x00,0x48,0x8f,0xa2,0x00,0x1c,0x8f,0xa6,0x00,0x18,0x02,0x00,0x20,0x21, +0x02,0xc0,0x28,0x21,0xaf,0xa2,0x00,0x10,0x0c,0x00,0x0d,0xfe,0xaf,0xa0,0x00,0x14, +0x08,0x00,0x0e,0xba,0x02,0x42,0x90,0x21,0x02,0x91,0x10,0x21,0x00,0x02,0x10,0x80, +0x27,0x83,0x96,0x50,0x00,0x43,0x10,0x21,0x90,0x50,0x00,0x00,0x08,0x00,0x0e,0xa6, +0xa0,0x50,0x00,0x03,0x27,0xbd,0xff,0xb8,0xaf,0xb1,0x00,0x24,0x8f,0xb1,0x00,0x5c, +0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x34,0x63,0x00,0x20,0x24,0x42,0x3b,0x64, +0xaf,0xbe,0x00,0x40,0xaf,0xb7,0x00,0x3c,0xaf,0xb6,0x00,0x38,0xaf,0xb5,0x00,0x34, +0xaf,0xb4,0x00,0x30,0xaf,0xa5,0x00,0x4c,0x8f,0xb5,0x00,0x58,0xaf,0xbf,0x00,0x44, +0xaf,0xb3,0x00,0x2c,0xaf,0xb2,0x00,0x28,0xaf,0xb0,0x00,0x20,0x00,0xe0,0xb0,0x21, +0xac,0x62,0x00,0x00,0x00,0x80,0xf0,0x21,0x00,0x00,0xb8,0x21,0x16,0x20,0x00,0x2b, +0x00,0x00,0xa0,0x21,0x27,0x85,0xba,0x40,0x00,0x07,0x10,0x80,0x00,0x45,0x10,0x21, +0x8c,0x53,0x00,0x00,0x00,0x15,0x18,0x80,0x00,0x65,0x18,0x21,0x92,0x62,0x00,0x16, +0x8c,0x72,0x00,0x00,0x30,0x42,0x00,0x03,0x14,0x40,0x00,0x2d,0x00,0x00,0x00,0x00, +0x92,0x42,0x00,0x16,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x03,0x14,0x40,0x00,0x28, +0x00,0x00,0x00,0x00,0x8c,0x82,0x00,0x34,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x18, +0x02,0x20,0x10,0x21,0x8c,0x82,0x00,0x38,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x14, +0x02,0x20,0x10,0x21,0x8c,0x82,0x00,0x3c,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x0f, +0x3c,0x03,0xb0,0x09,0x3c,0x05,0xb0,0x05,0x34,0x63,0x01,0x44,0x34,0xa5,0x02,0x52, +0x94,0x66,0x00,0x00,0x90,0xa2,0x00,0x00,0x8f,0xa3,0x00,0x4c,0x00,0x00,0x00,0x00, +0x00,0x62,0x10,0x06,0x30,0x42,0x00,0x01,0x10,0x40,0x00,0x04,0x30,0xc6,0xff,0xff, +0x2c,0xc2,0x00,0x41,0x10,0x40,0x00,0x09,0x24,0x05,0x00,0x14,0x02,0x20,0x10,0x21, +0x7b,0xbe,0x02,0x3c,0x7b,0xb6,0x01,0xfc,0x7b,0xb4,0x01,0xbc,0x7b,0xb2,0x01,0x7c, +0x7b,0xb0,0x01,0x3c,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x48,0x0c,0x00,0x0c,0x31, +0x24,0x06,0x01,0x07,0x24,0x02,0x00,0x01,0x08,0x00,0x0f,0x1b,0xa3,0xc2,0x00,0x11, +0x10,0xc0,0x00,0x1c,0x24,0x02,0x00,0x01,0x10,0xc2,0x00,0x17,0x00,0xc0,0x88,0x21, +0x96,0x54,0x00,0x1a,0x02,0xa0,0xb8,0x21,0x12,0x20,0xff,0xed,0x02,0x20,0x10,0x21, +0x27,0x83,0xba,0x40,0x00,0x17,0x10,0x80,0x00,0x43,0x10,0x21,0x8c,0x44,0x00,0x00, +0x3c,0x03,0xb0,0x03,0x34,0x63,0x00,0x28,0x80,0x86,0x00,0x12,0x8c,0x62,0x00,0x00, +0x00,0x14,0x2c,0x00,0x00,0x05,0x2c,0x03,0x00,0x46,0x10,0x21,0x8f,0xa6,0x00,0x4c, +0x02,0xe0,0x38,0x21,0x03,0xc0,0x20,0x21,0x0c,0x00,0x0c,0x56,0xac,0x62,0x00,0x00, +0x08,0x00,0x0f,0x1b,0xaf,0xd1,0x00,0x40,0x96,0x74,0x00,0x1a,0x08,0x00,0x0f,0x2e, +0x02,0xc0,0xb8,0x21,0x3c,0x02,0xb0,0x03,0x34,0x42,0x01,0x08,0x8c,0x50,0x00,0x00, +0x02,0x60,0x20,0x21,0x0c,0x00,0x23,0x25,0x02,0x00,0x28,0x21,0x30,0x42,0x00,0xff, +0x02,0x00,0x28,0x21,0x02,0x40,0x20,0x21,0x0c,0x00,0x23,0x25,0xaf,0xa2,0x00,0x18, +0x30,0x50,0x00,0xff,0x8f,0xa2,0x00,0x18,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0xc3, +0x00,0x00,0x00,0x00,0x12,0x00,0x00,0x18,0x24,0x11,0x00,0x01,0x96,0x63,0x00,0x14, +0x96,0x44,0x00,0x14,0x27,0x85,0x96,0x40,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21, +0x00,0x02,0x10,0x80,0x00,0x45,0x10,0x21,0x00,0x04,0x18,0xc0,0x8c,0x46,0x00,0x08, +0x00,0x64,0x18,0x21,0x00,0x03,0x18,0x80,0x00,0x65,0x18,0x21,0x00,0x06,0x17,0x02, +0x24,0x04,0x00,0xff,0x8c,0x63,0x00,0x08,0x10,0x44,0x00,0xac,0x00,0x03,0x17,0x02, +0x10,0x44,0x00,0xab,0x3c,0x02,0x80,0x00,0x00,0x66,0x18,0x2b,0x24,0x11,0x00,0x02, +0x24,0x02,0x00,0x01,0x00,0x43,0x88,0x0a,0x24,0x02,0x00,0x01,0x12,0x22,0x00,0x45, +0x24,0x02,0x00,0x02,0x16,0x22,0xff,0xbc,0x00,0x00,0x00,0x00,0x96,0x49,0x00,0x14, +0x27,0x82,0x96,0x44,0x02,0xa0,0xb8,0x21,0x00,0x09,0x50,0xc0,0x01,0x49,0x18,0x21, +0x00,0x03,0x40,0x80,0x01,0x02,0x10,0x21,0x8c,0x43,0x00,0x18,0x00,0x00,0x00,0x00, +0x8c,0x65,0x00,0x08,0x8c,0x62,0x00,0x0c,0x8c,0x62,0x00,0x04,0x00,0x05,0x24,0x42, +0x00,0x05,0x1c,0x82,0x30,0x42,0x00,0x10,0x30,0x66,0x00,0x01,0x14,0x40,0x00,0x2c, +0x30,0x87,0x00,0x01,0x27,0x83,0x96,0x58,0x01,0x03,0x18,0x21,0x80,0x64,0x00,0x00, +0x27,0x83,0xba,0xe0,0x00,0x04,0x11,0x00,0x00,0x44,0x10,0x23,0x00,0x02,0x10,0x80, +0x00,0x44,0x10,0x23,0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21,0x90,0x45,0x00,0x00, +0x00,0x00,0x00,0x00,0x2c,0xa3,0x00,0x0c,0x14,0x60,0x00,0x07,0x01,0x49,0x10,0x21, +0x00,0x07,0x10,0x40,0x00,0x46,0x10,0x21,0x00,0x02,0x11,0x00,0x00,0xa2,0x10,0x21, +0x24,0x45,0x00,0x04,0x01,0x49,0x10,0x21,0x00,0x02,0x10,0x80,0x27,0x83,0x96,0x50, +0x00,0x43,0x10,0x21,0xa0,0x45,0x00,0x03,0xa0,0x45,0x00,0x00,0x24,0x02,0x00,0x08, +0x12,0x02,0x00,0x0a,0x24,0x02,0x00,0x01,0x02,0x40,0x20,0x21,0x0c,0x00,0x23,0xa1, +0xaf,0xa2,0x00,0x10,0x30,0x54,0xff,0xff,0x92,0x42,0x00,0x16,0x00,0x00,0x00,0x00, +0x02,0x02,0x10,0x25,0x08,0x00,0x0f,0x2e,0xa2,0x42,0x00,0x16,0x02,0x40,0x20,0x21, +0x0c,0x00,0x23,0x52,0xaf,0xa0,0x00,0x10,0x08,0x00,0x0f,0xa6,0x30,0x54,0xff,0xff, +0x27,0x82,0x96,0x50,0x01,0x02,0x10,0x21,0x90,0x45,0x00,0x00,0x08,0x00,0x0f,0x9f, +0xa0,0x45,0x00,0x03,0x96,0x69,0x00,0x14,0x02,0xc0,0xb8,0x21,0x24,0x0b,0x00,0x01, +0x00,0x09,0x10,0xc0,0x00,0x49,0x18,0x21,0x00,0x03,0x40,0x80,0x00,0x40,0x50,0x21, +0x27,0x82,0x96,0x44,0x01,0x02,0x10,0x21,0x8c,0x43,0x00,0x18,0x00,0x00,0x00,0x00, +0x8c,0x65,0x00,0x08,0x8c,0x62,0x00,0x0c,0x8c,0x62,0x00,0x04,0x00,0x05,0x24,0x42, +0x00,0x05,0x1c,0x82,0x30,0x42,0x00,0x10,0x30,0x66,0x00,0x01,0x10,0x40,0x00,0x0d, +0x30,0x87,0x00,0x01,0x27,0x82,0x96,0x58,0x01,0x02,0x10,0x21,0x80,0x43,0x00,0x00, +0x00,0x00,0x58,0x21,0x00,0x03,0x11,0x00,0x00,0x43,0x10,0x23,0x00,0x02,0x10,0x80, +0x00,0x43,0x10,0x23,0x00,0x02,0x10,0x80,0x27,0x83,0xbb,0xb0,0x00,0x43,0x10,0x21, +0xa0,0x40,0x00,0x04,0x11,0x60,0x00,0x3a,0x00,0x00,0x00,0x00,0x01,0x49,0x10,0x21, +0x00,0x02,0x20,0x80,0x27,0x85,0x96,0x50,0x00,0x85,0x10,0x21,0x80,0x43,0x00,0x05, +0x00,0x00,0x00,0x00,0x14,0x60,0x00,0x2d,0x01,0x49,0x10,0x21,0x27,0x83,0x96,0x58, +0x00,0x83,0x18,0x21,0x80,0x64,0x00,0x00,0x27,0x83,0xba,0xe0,0x00,0x04,0x11,0x00, +0x00,0x44,0x10,0x23,0x00,0x02,0x10,0x80,0x00,0x44,0x10,0x23,0x00,0x02,0x10,0x80, +0x00,0x43,0x10,0x21,0x90,0x45,0x00,0x00,0x00,0x00,0x00,0x00,0x2c,0xa3,0x00,0x0c, +0x14,0x60,0x00,0x07,0x01,0x49,0x10,0x21,0x00,0x07,0x10,0x40,0x00,0x46,0x10,0x21, +0x00,0x02,0x11,0x00,0x00,0xa2,0x10,0x21,0x24,0x45,0x00,0x04,0x01,0x49,0x10,0x21, +0x00,0x02,0x10,0x80,0x27,0x83,0x96,0x50,0x00,0x43,0x10,0x21,0xa0,0x45,0x00,0x03, +0xa0,0x45,0x00,0x00,0x8f,0xa3,0x00,0x18,0x24,0x02,0x00,0x08,0x10,0x62,0x00,0x0b, +0x02,0x60,0x20,0x21,0x24,0x02,0x00,0x01,0x0c,0x00,0x23,0xa1,0xaf,0xa2,0x00,0x10, +0x8f,0xa3,0x00,0x18,0x30,0x54,0xff,0xff,0x92,0x62,0x00,0x16,0x00,0x00,0x00,0x00, +0x00,0x62,0x10,0x25,0x08,0x00,0x0f,0x2e,0xa2,0x62,0x00,0x16,0x0c,0x00,0x23,0x52, +0xaf,0xa0,0x00,0x10,0x08,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x10,0x80, +0x00,0x45,0x10,0x21,0x90,0x45,0x00,0x00,0x08,0x00,0x0f,0xf9,0xa0,0x45,0x00,0x03, +0x27,0x85,0x96,0x50,0x08,0x00,0x10,0x0b,0x01,0x49,0x10,0x21,0x3c,0x02,0x80,0x00, +0x00,0x62,0x18,0x26,0x08,0x00,0x0f,0x6a,0x00,0xc2,0x30,0x26,0x12,0x00,0xff,0x57, +0x24,0x02,0x00,0x01,0x08,0x00,0x0f,0x6f,0x24,0x11,0x00,0x02,0x3c,0x03,0xb0,0x03, +0x3c,0x02,0x80,0x00,0x27,0xbd,0xff,0xd0,0x24,0x42,0x40,0x6c,0x34,0x63,0x00,0x20, +0x3c,0x05,0xb0,0x05,0xaf,0xb3,0x00,0x24,0xaf,0xb2,0x00,0x20,0xaf,0xb1,0x00,0x1c, +0xaf,0xbf,0x00,0x28,0xaf,0xb0,0x00,0x18,0xac,0x62,0x00,0x00,0x34,0xa5,0x02,0x42, +0x90,0xa2,0x00,0x00,0x00,0x80,0x90,0x21,0x24,0x11,0x00,0x10,0x30,0x53,0x00,0xff, +0x24,0x02,0x00,0x10,0x12,0x22,0x00,0xcf,0x00,0x00,0x18,0x21,0x24,0x02,0x00,0x11, +0x12,0x22,0x00,0xc1,0x24,0x02,0x00,0x12,0x12,0x22,0x00,0xb4,0x00,0x00,0x00,0x00, +0x14,0x60,0x00,0xad,0xae,0x43,0x00,0x40,0x3c,0x02,0xb0,0x05,0x34,0x42,0x02,0x2c, +0x8c,0x44,0x00,0x00,0x3c,0x03,0x00,0x02,0x34,0x63,0x00,0xff,0x00,0x83,0x80,0x24, +0x00,0x10,0x14,0x43,0x10,0x40,0x00,0x05,0x00,0x00,0x00,0x00,0x8e,0x42,0x00,0x34, +0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x92,0x00,0x00,0x00,0x00,0x93,0x83,0x91,0x51, +0x00,0x00,0x00,0x00,0x30,0x62,0x00,0x02,0x10,0x40,0x00,0x04,0x32,0x10,0x00,0xff, +0x00,0x10,0x11,0xc3,0x14,0x40,0x00,0x86,0x00,0x00,0x00,0x00,0x16,0x00,0x00,0x15, +0x02,0x00,0x10,0x21,0x26,0x22,0x00,0x01,0x30,0x51,0x00,0xff,0x2e,0x23,0x00,0x13, +0x14,0x60,0xff,0xdb,0x24,0x03,0x00,0x02,0x12,0x63,0x00,0x73,0x24,0x02,0x00,0x05, +0x2a,0x62,0x00,0x03,0x10,0x40,0x00,0x58,0x24,0x02,0x00,0x04,0x24,0x02,0x00,0x01, +0x12,0x62,0x00,0x4b,0x02,0x40,0x20,0x21,0x3c,0x02,0xb0,0x05,0x34,0x42,0x02,0x2c, +0x8c,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x70,0x00,0xff,0x12,0x00,0x00,0x06, +0x02,0x00,0x10,0x21,0x8f,0xbf,0x00,0x28,0x7b,0xb2,0x01,0x3c,0x7b,0xb0,0x00,0xfc, +0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x30,0x92,0x46,0x00,0x04,0x8e,0x43,0x00,0x24, +0x24,0x02,0x00,0x07,0x02,0x40,0x20,0x21,0x00,0x00,0x28,0x21,0x24,0x07,0x00,0x06, +0xaf,0xa2,0x00,0x10,0x0c,0x00,0x0e,0xd9,0xaf,0xa3,0x00,0x14,0xae,0x42,0x00,0x24, +0x3c,0x02,0xb0,0x05,0x8c,0x42,0x02,0x2c,0x00,0x00,0x00,0x00,0x30,0x50,0x00,0xff, +0x16,0x00,0xff,0xec,0x02,0x00,0x10,0x21,0x92,0x46,0x00,0x05,0x8e,0x43,0x00,0x28, +0x24,0x02,0x00,0x05,0x02,0x40,0x20,0x21,0x24,0x05,0x00,0x01,0x24,0x07,0x00,0x04, +0xaf,0xa2,0x00,0x10,0x0c,0x00,0x0e,0xd9,0xaf,0xa3,0x00,0x14,0xae,0x42,0x00,0x28, +0x3c,0x02,0xb0,0x05,0x8c,0x42,0x02,0x2c,0x00,0x00,0x00,0x00,0x30,0x50,0x00,0xff, +0x16,0x00,0xff,0xdc,0x02,0x00,0x10,0x21,0x92,0x46,0x00,0x06,0x8e,0x43,0x00,0x2c, +0x24,0x02,0x00,0x03,0x02,0x40,0x20,0x21,0x24,0x05,0x00,0x02,0x00,0x00,0x38,0x21, +0xaf,0xa2,0x00,0x10,0x0c,0x00,0x0e,0xd9,0xaf,0xa3,0x00,0x14,0xae,0x42,0x00,0x2c, +0x3c,0x02,0xb0,0x05,0x8c,0x42,0x02,0x2c,0x00,0x00,0x00,0x00,0x30,0x50,0x00,0xff, +0x16,0x00,0xff,0xcc,0x02,0x00,0x10,0x21,0x92,0x46,0x00,0x07,0x8e,0x43,0x00,0x30, +0x24,0x02,0x00,0x02,0x02,0x40,0x20,0x21,0x24,0x05,0x00,0x03,0x24,0x07,0x00,0x01, +0xaf,0xa2,0x00,0x10,0x0c,0x00,0x0e,0xd9,0xaf,0xa3,0x00,0x14,0xae,0x42,0x00,0x30, +0x3c,0x02,0xb0,0x05,0x8c,0x42,0x02,0x2c,0x08,0x00,0x10,0x61,0x30,0x42,0x00,0xff, +0x92,0x46,0x00,0x04,0x8e,0x43,0x00,0x24,0x24,0x02,0x00,0x07,0x00,0x00,0x28,0x21, +0x24,0x07,0x00,0x06,0xaf,0xa2,0x00,0x10,0x0c,0x00,0x0e,0xd9,0xaf,0xa3,0x00,0x14, +0x08,0x00,0x10,0x5a,0xae,0x42,0x00,0x24,0x12,0x62,0x00,0x0d,0x24,0x02,0x00,0x03, +0x24,0x02,0x00,0x08,0x16,0x62,0xff,0xa8,0x02,0x40,0x20,0x21,0x92,0x46,0x00,0x07, +0x8e,0x42,0x00,0x30,0x24,0x05,0x00,0x03,0x24,0x07,0x00,0x01,0xaf,0xa3,0x00,0x10, +0x0c,0x00,0x0e,0xd9,0xaf,0xa2,0x00,0x14,0x08,0x00,0x10,0x5a,0xae,0x42,0x00,0x30, +0x92,0x46,0x00,0x06,0x8e,0x43,0x00,0x2c,0x02,0x40,0x20,0x21,0x24,0x05,0x00,0x02, +0x00,0x00,0x38,0x21,0xaf,0xa2,0x00,0x10,0x0c,0x00,0x0e,0xd9,0xaf,0xa3,0x00,0x14, +0x08,0x00,0x10,0x5a,0xae,0x42,0x00,0x2c,0x92,0x46,0x00,0x05,0x8e,0x43,0x00,0x28, +0x02,0x40,0x20,0x21,0x24,0x05,0x00,0x01,0x24,0x07,0x00,0x04,0xaf,0xa2,0x00,0x10, +0x0c,0x00,0x0e,0xd9,0xaf,0xa3,0x00,0x14,0x08,0x00,0x10,0x5a,0xae,0x42,0x00,0x28, +0x0c,0x00,0x01,0x60,0x24,0x04,0x00,0x01,0x08,0x00,0x10,0x4b,0x00,0x00,0x00,0x00, +0x8f,0x84,0xba,0x80,0xae,0x40,0x00,0x34,0x94,0x85,0x00,0x14,0x0c,0x00,0x1f,0xdd, +0x00,0x00,0x00,0x00,0x93,0x83,0x91,0x51,0x00,0x00,0x00,0x00,0x30,0x62,0x00,0x02, +0x10,0x40,0xff,0x69,0x00,0x00,0x00,0x00,0x0c,0x00,0x01,0x60,0x00,0x00,0x20,0x21, +0x08,0x00,0x10,0x43,0x00,0x00,0x00,0x00,0x02,0x40,0x20,0x21,0x0c,0x00,0x0e,0x55, +0x02,0x20,0x28,0x21,0x08,0x00,0x10,0x37,0x3c,0x02,0xb0,0x05,0x8e,0x42,0x00,0x3c, +0x00,0x00,0x00,0x00,0x14,0x40,0xff,0x4a,0x00,0x00,0x00,0x00,0x8f,0x82,0xba,0x88, +0x00,0x00,0x00,0x00,0x90,0x42,0x00,0x0a,0x00,0x00,0x00,0x00,0x00,0x02,0x18,0x2b, +0x08,0x00,0x10,0x34,0xae,0x43,0x00,0x3c,0x8e,0x42,0x00,0x38,0x00,0x00,0x00,0x00, +0x14,0x40,0xff,0x3d,0x24,0x02,0x00,0x12,0x8f,0x82,0xba,0x84,0x00,0x00,0x00,0x00, +0x90,0x42,0x00,0x0a,0x00,0x00,0x00,0x00,0x00,0x02,0x18,0x2b,0x08,0x00,0x10,0x34, +0xae,0x43,0x00,0x38,0x8e,0x42,0x00,0x34,0x00,0x00,0x00,0x00,0x14,0x40,0xff,0x30, +0x24,0x02,0x00,0x11,0x8f,0x82,0xba,0x80,0x00,0x00,0x00,0x00,0x90,0x42,0x00,0x0a, +0x00,0x00,0x00,0x00,0x00,0x02,0x18,0x2b,0x08,0x00,0x10,0x34,0xae,0x43,0x00,0x34, +0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x27,0xbd,0xff,0xe0,0x34,0x63,0x00,0x20, +0x24,0x42,0x44,0x20,0x3c,0x08,0xb0,0x03,0xaf,0xb1,0x00,0x14,0xac,0x62,0x00,0x00, +0x35,0x08,0x01,0x00,0xaf,0xbf,0x00,0x18,0xaf,0xb0,0x00,0x10,0x91,0x03,0x00,0x00, +0x00,0xa0,0x48,0x21,0x24,0x11,0x00,0x0a,0x2c,0xa5,0x00,0x04,0x24,0x02,0x00,0x10, +0x00,0x45,0x88,0x0a,0x30,0x63,0x00,0x01,0x00,0xc0,0x28,0x21,0x14,0x60,0x00,0x02, +0x00,0x11,0x40,0x40,0x02,0x20,0x40,0x21,0x84,0x83,0x00,0x0c,0x31,0x11,0x00,0xff, +0x01,0x20,0x20,0x21,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80, +0x27,0x83,0x96,0x48,0x00,0x43,0x10,0x21,0x84,0x43,0x00,0x04,0x24,0x06,0x00,0x0e, +0x10,0xe0,0x00,0x06,0x02,0x23,0x80,0x21,0x02,0x00,0x10,0x21,0x8f,0xbf,0x00,0x18, +0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20,0x0c,0x00,0x0d,0xd7, +0x00,0x00,0x00,0x00,0x02,0x11,0x18,0x21,0x08,0x00,0x11,0x2a,0x00,0x62,0x80,0x21, +0x27,0xbd,0xff,0xd0,0xaf,0xbf,0x00,0x28,0xaf,0xb5,0x00,0x24,0xaf,0xb4,0x00,0x20, +0xaf,0xb2,0x00,0x18,0xaf,0xb3,0x00,0x1c,0xaf,0xb1,0x00,0x14,0xaf,0xb0,0x00,0x10, +0x84,0x82,0x00,0x0c,0x3c,0x06,0xb0,0x03,0x34,0xc6,0x00,0x20,0x00,0x02,0x18,0xc0, +0x00,0x62,0x18,0x21,0x00,0x03,0x18,0x80,0x27,0x82,0x96,0x44,0x00,0x62,0x10,0x21, +0x8c,0x53,0x00,0x18,0x3c,0x02,0x80,0x00,0x24,0x42,0x44,0xd0,0xac,0xc2,0x00,0x00, +0x8e,0x70,0x00,0x08,0x27,0x82,0x96,0x48,0x00,0x62,0x18,0x21,0x90,0x71,0x00,0x07, +0x00,0x10,0x86,0x43,0x32,0x10,0x00,0x01,0x00,0xa0,0x38,0x21,0x02,0x00,0x30,0x21, +0x00,0xa0,0xa0,0x21,0x02,0x20,0x28,0x21,0x0c,0x00,0x11,0x08,0x00,0x80,0xa8,0x21, +0x02,0x20,0x20,0x21,0x02,0x00,0x28,0x21,0x24,0x06,0x00,0x14,0x0c,0x00,0x0d,0xd7, +0x00,0x40,0x90,0x21,0x3c,0x03,0xb0,0x05,0x34,0x63,0x02,0x40,0x94,0x64,0x00,0x00, +0x3c,0x0a,0xb0,0x09,0x3c,0x0b,0xb0,0x09,0x00,0x04,0x21,0x40,0x00,0x82,0x28,0x23, +0x35,0x4a,0x01,0x10,0x35,0x6b,0x01,0x14,0x3c,0x0c,0xb0,0x09,0x3c,0x08,0xb0,0x09, +0x3c,0x06,0xb0,0x09,0x00,0x44,0x10,0x2b,0x01,0x40,0x48,0x21,0x35,0x8c,0x01,0x20, +0x01,0x60,0x38,0x21,0x35,0x08,0x01,0x24,0x34,0xc6,0x01,0x02,0x10,0x40,0x00,0x02, +0x02,0x45,0x18,0x2b,0x00,0xa3,0x90,0x0b,0x86,0xa3,0x00,0x0c,0x27,0x84,0x96,0x50, +0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x44,0x10,0x21, +0x80,0x43,0x00,0x06,0xa4,0xd2,0x00,0x00,0x24,0x64,0x00,0x03,0x28,0x62,0x00,0x00, +0x00,0x82,0x18,0x0b,0x00,0x03,0x18,0x83,0x00,0x03,0x18,0x80,0x12,0x80,0x00,0x11, +0x02,0x63,0x28,0x21,0x8c,0xa2,0x00,0x0c,0x8c,0xa3,0x00,0x08,0x00,0x02,0x14,0x00, +0x00,0x03,0x1c,0x02,0x00,0x43,0x10,0x21,0xad,0x22,0x00,0x00,0x8c,0xa3,0x00,0x0c, +0x00,0x00,0x00,0x00,0x00,0x03,0x1c,0x02,0xa4,0xe3,0x00,0x00,0x8f,0xbf,0x00,0x28, +0x7b,0xb4,0x01,0x3c,0x7b,0xb2,0x00,0xfc,0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08, +0x27,0xbd,0x00,0x30,0x8c,0xa2,0x00,0x04,0x00,0x00,0x00,0x00,0xad,0x42,0x00,0x00, +0x8c,0xa4,0x00,0x08,0x00,0x00,0x00,0x00,0xa5,0x64,0x00,0x00,0x78,0xa2,0x00,0x7c, +0x00,0x00,0x00,0x00,0x00,0x03,0x1c,0x00,0x00,0x02,0x14,0x02,0x00,0x62,0x18,0x21, +0xad,0x83,0x00,0x00,0x8c,0xa2,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x02,0x14,0x02, +0x08,0x00,0x11,0x87,0xa5,0x02,0x00,0x00,0x27,0xbd,0xff,0xe0,0xaf,0xb2,0x00,0x18, +0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x1c,0xaf,0xb1,0x00,0x14,0x84,0x82,0x00,0x0c, +0x00,0x80,0x90,0x21,0x3c,0x05,0xb0,0x03,0x00,0x02,0x20,0xc0,0x00,0x82,0x20,0x21, +0x00,0x04,0x20,0x80,0x27,0x82,0x96,0x44,0x00,0x82,0x10,0x21,0x8c,0x51,0x00,0x18, +0x3c,0x02,0x80,0x00,0x34,0xa5,0x00,0x20,0x24,0x42,0x46,0x78,0x27,0x83,0x96,0x48, +0xac,0xa2,0x00,0x00,0x00,0x83,0x20,0x21,0x3c,0x02,0xb0,0x03,0x90,0x86,0x00,0x07, +0x34,0x42,0x01,0x00,0x8e,0x23,0x00,0x08,0x90,0x44,0x00,0x00,0x2c,0xc5,0x00,0x04, +0x24,0x02,0x00,0x10,0x24,0x10,0x00,0x0a,0x00,0x45,0x80,0x0a,0x00,0x03,0x1e,0x43, +0x30,0x84,0x00,0x01,0x30,0x65,0x00,0x01,0x14,0x80,0x00,0x02,0x00,0x10,0x10,0x40, +0x02,0x00,0x10,0x21,0x00,0xc0,0x20,0x21,0x24,0x06,0x00,0x20,0x0c,0x00,0x0d,0xd7, +0x30,0x50,0x00,0xff,0x86,0x44,0x00,0x0c,0x27,0x85,0x96,0x50,0x3c,0x06,0xb0,0x09, +0x00,0x04,0x18,0xc0,0x00,0x64,0x18,0x21,0x00,0x03,0x18,0x80,0x00,0x65,0x18,0x21, +0x80,0x64,0x00,0x06,0x00,0x50,0x10,0x21,0x34,0xc6,0x01,0x02,0x24,0x85,0x00,0x03, +0x28,0x83,0x00,0x00,0x00,0xa3,0x20,0x0b,0x00,0x04,0x20,0x83,0x00,0x04,0x20,0x80, +0xa4,0xc2,0x00,0x00,0x02,0x24,0x20,0x21,0x8c,0x83,0x00,0x04,0x3c,0x02,0xb0,0x09, +0x34,0x42,0x01,0x10,0xac,0x43,0x00,0x00,0x8c,0x86,0x00,0x08,0x3c,0x02,0xb0,0x09, +0x34,0x42,0x01,0x14,0xa4,0x46,0x00,0x00,0x8c,0x85,0x00,0x0c,0x8c,0x82,0x00,0x08, +0x3c,0x06,0xb0,0x09,0x00,0x05,0x2c,0x00,0x00,0x02,0x14,0x02,0x00,0xa2,0x28,0x21, +0x34,0xc6,0x01,0x20,0xac,0xc5,0x00,0x00,0x8c,0x83,0x00,0x0c,0x3c,0x05,0xb0,0x09, +0x34,0xa5,0x01,0x24,0x00,0x03,0x1c,0x02,0xa4,0xa3,0x00,0x00,0x92,0x42,0x00,0x0a, +0x3c,0x03,0xb0,0x09,0x34,0x63,0x01,0x30,0x00,0x02,0x13,0x00,0x24,0x42,0x00,0x04, +0x30,0x42,0xff,0xff,0xa4,0x62,0x00,0x00,0x86,0x44,0x00,0x0c,0x27,0x83,0x96,0x58, +0x8f,0xbf,0x00,0x1c,0x00,0x04,0x10,0xc0,0x00,0x44,0x10,0x21,0x00,0x02,0x10,0x80, +0x00,0x43,0x10,0x21,0x94,0x44,0x00,0x02,0x8f,0xb2,0x00,0x18,0x7b,0xb0,0x00,0xbc, +0x3c,0x05,0xb0,0x09,0x34,0xa5,0x01,0x32,0xa4,0xa4,0x00,0x00,0x03,0xe0,0x00,0x08, +0x27,0xbd,0x00,0x20,0x27,0xbd,0xff,0xe0,0x3c,0x02,0xb0,0x03,0x3c,0x03,0x80,0x00, +0xaf,0xb0,0x00,0x10,0x34,0x42,0x00,0x20,0x00,0xa0,0x80,0x21,0x24,0x63,0x48,0x04, +0x00,0x05,0x2c,0x43,0xaf,0xb1,0x00,0x14,0xaf,0xbf,0x00,0x18,0xac,0x43,0x00,0x00, +0x10,0xa0,0x00,0x05,0x00,0x80,0x88,0x21,0x8c,0x82,0x00,0x34,0x00,0x00,0x00,0x00, +0x14,0x40,0x00,0xaf,0x00,0x00,0x00,0x00,0x32,0x10,0x00,0xff,0x12,0x00,0x00,0x47, +0x00,0x00,0x10,0x21,0x24,0x02,0x00,0x08,0x12,0x02,0x00,0x9c,0x2a,0x02,0x00,0x09, +0x10,0x40,0x00,0x84,0x24,0x02,0x00,0x40,0x24,0x04,0x00,0x02,0x12,0x04,0x00,0x74, +0x2a,0x02,0x00,0x03,0x10,0x40,0x00,0x64,0x24,0x02,0x00,0x04,0x24,0x02,0x00,0x01, +0x12,0x02,0x00,0x55,0x00,0x00,0x00,0x00,0x82,0x22,0x00,0x11,0x92,0x27,0x00,0x11, +0x10,0x40,0x00,0x4e,0x00,0x00,0x00,0x00,0x92,0x26,0x00,0x0a,0x24,0x02,0x00,0x12, +0x10,0x46,0x00,0x09,0x30,0xc2,0x00,0xff,0x27,0x83,0xba,0x40,0x00,0x02,0x10,0x80, +0x00,0x43,0x10,0x21,0x8c,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x83,0x00,0x14, +0x00,0x00,0x00,0x00,0xa6,0x23,0x00,0x0c,0x3c,0x02,0xb0,0x09,0x34,0x42,0x00,0x40, +0x90,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x63,0x00,0x03,0xa2,0x23,0x00,0x10, +0x14,0x60,0x00,0x2b,0x30,0x65,0x00,0x01,0x30,0xc2,0x00,0xff,0x27,0x83,0xba,0x40, +0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21,0x8c,0x44,0x00,0x00,0x82,0x23,0x00,0x12, +0x90,0x82,0x00,0x16,0x00,0x00,0x00,0x00,0x00,0x02,0x11,0x42,0x30,0x42,0x00,0x01, +0x00,0x62,0x18,0x21,0x00,0x03,0x26,0x00,0x14,0x80,0x00,0x18,0xa2,0x23,0x00,0x12, +0x00,0x07,0x16,0x00,0x14,0x40,0x00,0x11,0x24,0x02,0x00,0x01,0x96,0x23,0x00,0x0c, +0x27,0x84,0x96,0x50,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80, +0x00,0x44,0x10,0x21,0x80,0x45,0x00,0x06,0x00,0x03,0x1a,0x00,0x3c,0x02,0xb0,0x00, +0x00,0x65,0x18,0x21,0x00,0x62,0x18,0x21,0x90,0x64,0x00,0x00,0x90,0x62,0x00,0x04, +0xa2,0x20,0x00,0x15,0xa3,0x80,0x92,0x15,0x24,0x02,0x00,0x01,0x8f,0xbf,0x00,0x18, +0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20,0x0c,0x00,0x11,0x9e, +0x02,0x20,0x20,0x21,0x92,0x27,0x00,0x11,0x08,0x00,0x12,0x49,0x00,0x07,0x16,0x00, +0x0c,0x00,0x11,0x34,0x02,0x20,0x20,0x21,0x86,0x23,0x00,0x0c,0x27,0x84,0x96,0x48, +0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x44,0x20,0x21, +0x90,0x85,0x00,0x07,0x27,0x83,0x96,0x50,0x00,0x43,0x10,0x21,0xa2,0x25,0x00,0x13, +0x90,0x83,0x00,0x07,0x08,0x00,0x12,0x61,0xa0,0x43,0x00,0x02,0x92,0x26,0x00,0x0a, +0x08,0x00,0x12,0x2a,0x30,0xc2,0x00,0xff,0x8e,0x22,0x00,0x24,0x00,0x00,0x00,0x00, +0x10,0x50,0x00,0x07,0xa2,0x20,0x00,0x08,0x24,0x02,0x00,0x07,0xa2,0x22,0x00,0x0a, +0x92,0x22,0x00,0x27,0xae,0x20,0x00,0x24,0x08,0x00,0x12,0x22,0xa2,0x22,0x00,0x04, +0x08,0x00,0x12,0x7b,0x24,0x02,0x00,0x06,0x16,0x02,0xff,0x9f,0x24,0x02,0x00,0x01, +0x8e,0x23,0x00,0x2c,0x00,0x00,0x00,0x00,0x10,0x62,0x00,0x07,0xa2,0x24,0x00,0x08, +0x24,0x02,0x00,0x03,0xa2,0x22,0x00,0x0a,0x92,0x22,0x00,0x2f,0xae,0x20,0x00,0x2c, +0x08,0x00,0x12,0x22,0xa2,0x22,0x00,0x06,0x08,0x00,0x12,0x8a,0xa2,0x20,0x00,0x0a, +0x8e,0x22,0x00,0x28,0x24,0x03,0x00,0x01,0x24,0x04,0x00,0x01,0x10,0x44,0x00,0x07, +0xa2,0x23,0x00,0x08,0x24,0x02,0x00,0x05,0xa2,0x22,0x00,0x0a,0x92,0x22,0x00,0x2b, +0xae,0x20,0x00,0x28,0x08,0x00,0x12,0x22,0xa2,0x22,0x00,0x05,0x08,0x00,0x12,0x96, +0x24,0x02,0x00,0x04,0x12,0x02,0x00,0x10,0x2a,0x02,0x00,0x41,0x10,0x40,0x00,0x08, +0x24,0x02,0x00,0x80,0x24,0x02,0x00,0x20,0x16,0x02,0xff,0x7f,0x24,0x02,0x00,0x12, +0xa2,0x22,0x00,0x0a,0xa2,0x22,0x00,0x08,0x08,0x00,0x12,0x22,0xae,0x20,0x00,0x3c, +0x16,0x02,0xff,0x79,0x24,0x02,0x00,0x10,0xa2,0x22,0x00,0x0a,0xa2,0x22,0x00,0x08, +0x08,0x00,0x12,0x22,0xae,0x20,0x00,0x34,0x24,0x02,0x00,0x11,0xa2,0x22,0x00,0x0a, +0xa2,0x22,0x00,0x08,0x08,0x00,0x12,0x22,0xae,0x20,0x00,0x38,0x8e,0x24,0x00,0x30, +0x24,0x02,0x00,0x03,0x24,0x03,0x00,0x01,0x10,0x83,0x00,0x07,0xa2,0x22,0x00,0x08, +0x24,0x02,0x00,0x02,0xa2,0x22,0x00,0x0a,0x92,0x22,0x00,0x33,0xae,0x20,0x00,0x30, +0x08,0x00,0x12,0x22,0xa2,0x22,0x00,0x07,0x08,0x00,0x12,0xba,0xa2,0x24,0x00,0x0a, +0x8f,0x84,0xba,0x80,0xae,0x20,0x00,0x34,0x94,0x85,0x00,0x14,0x0c,0x00,0x1f,0xdd, +0x32,0x10,0x00,0xff,0x08,0x00,0x12,0x13,0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03, +0x3c,0x02,0x80,0x00,0x24,0x42,0x4b,0x1c,0x34,0x63,0x00,0x20,0xac,0x62,0x00,0x00, +0x80,0xa2,0x00,0x15,0x3c,0x06,0xb0,0x05,0x10,0x40,0x00,0x0a,0x34,0xc6,0x02,0x54, +0x83,0x83,0x92,0x15,0x00,0x00,0x00,0x00,0xac,0x83,0x00,0x24,0x8c,0xc2,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x02,0x17,0x42,0x30,0x42,0x00,0x01,0x03,0xe0,0x00,0x08, +0xac,0x82,0x00,0x28,0x8c,0x82,0x00,0x2c,0x3c,0x06,0xb0,0x05,0x34,0xc6,0x04,0x50, +0x00,0x02,0x18,0x43,0x30,0x63,0x00,0x01,0x10,0x40,0x00,0x04,0x30,0x45,0x00,0x01, +0xac,0x83,0x00,0x28,0x03,0xe0,0x00,0x08,0xac,0x85,0x00,0x24,0x90,0xc2,0x00,0x00, +0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xff,0x30,0x43,0x00,0x02,0x30,0x42,0x00,0x01, +0xac,0x83,0x00,0x28,0x03,0xe0,0x00,0x08,0xac,0x82,0x00,0x24,0x3c,0x03,0xb0,0x03, +0x3c,0x02,0x80,0x00,0x27,0xbd,0xff,0xd8,0x34,0x63,0x00,0x20,0x24,0x42,0x4b,0xac, +0xac,0x62,0x00,0x00,0xaf,0xb1,0x00,0x1c,0xaf,0xbf,0x00,0x20,0xaf,0xb0,0x00,0x18, +0x90,0xa6,0x00,0x0a,0x27,0x83,0xba,0x40,0x00,0xa0,0x88,0x21,0x00,0x06,0x10,0x80, +0x00,0x43,0x10,0x21,0x8c,0x50,0x00,0x00,0x80,0xa5,0x00,0x11,0x92,0x03,0x00,0x12, +0x10,0xa0,0x00,0x04,0xa2,0x20,0x00,0x15,0x24,0x02,0x00,0x12,0x10,0xc2,0x00,0xd9, +0x00,0x00,0x00,0x00,0x82,0x22,0x00,0x12,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x67, +0x00,0x00,0x00,0x00,0xa2,0x20,0x00,0x12,0xa2,0x00,0x00,0x19,0x86,0x23,0x00,0x0c, +0x00,0x00,0x00,0x00,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80, +0x27,0x83,0x96,0x60,0x00,0x43,0x10,0x21,0xa0,0x40,0x00,0x00,0x92,0x03,0x00,0x16, +0x00,0x00,0x00,0x00,0x30,0x63,0x00,0xdf,0xa2,0x03,0x00,0x16,0x82,0x02,0x00,0x12, +0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x20,0x00,0x00,0x00,0x00,0x92,0x23,0x00,0x08, +0x00,0x00,0x00,0x00,0x14,0x60,0x00,0x45,0x24,0x02,0x00,0x01,0xa2,0x20,0x00,0x04, +0x92,0x08,0x00,0x04,0x00,0x00,0x00,0x00,0x15,0x00,0x00,0x1e,0x24,0x02,0x00,0x01, +0x92,0x07,0x00,0x0a,0xa2,0x02,0x00,0x17,0x92,0x02,0x00,0x16,0x30,0xe3,0x00,0xff, +0x30,0x42,0x00,0xe4,0x10,0x60,0x00,0x03,0xa2,0x02,0x00,0x16,0x34,0x42,0x00,0x01, +0xa2,0x02,0x00,0x16,0x11,0x00,0x00,0x05,0x00,0x00,0x00,0x00,0x92,0x02,0x00,0x16, +0x00,0x00,0x00,0x00,0x34,0x42,0x00,0x02,0xa2,0x02,0x00,0x16,0x92,0x02,0x00,0x17, +0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x08,0x00,0x00,0x00,0x00,0x96,0x02,0x00,0x06, +0x00,0x00,0x00,0x00,0xa6,0x02,0x00,0x14,0x8f,0xbf,0x00,0x20,0x7b,0xb0,0x00,0xfc, +0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x28,0x96,0x02,0x00,0x00,0x08,0x00,0x13,0x36, +0xa6,0x02,0x00,0x14,0x92,0x07,0x00,0x0a,0x00,0x00,0x00,0x00,0x14,0xe0,0x00,0x03, +0x00,0x00,0x00,0x00,0x08,0x00,0x13,0x22,0xa2,0x00,0x00,0x17,0x96,0x04,0x00,0x00, +0x96,0x05,0x00,0x06,0x27,0x86,0x96,0x40,0x00,0x04,0x18,0xc0,0x00,0x64,0x18,0x21, +0x00,0x05,0x10,0xc0,0x00,0x45,0x10,0x21,0x00,0x03,0x18,0x80,0x00,0x66,0x18,0x21, +0x00,0x02,0x10,0x80,0x00,0x46,0x10,0x21,0x8c,0x66,0x00,0x08,0x8c,0x45,0x00,0x08, +0x3c,0x03,0x80,0x00,0x00,0xc3,0x20,0x24,0x10,0x80,0x00,0x08,0x00,0xa3,0x10,0x24, +0x10,0x40,0x00,0x04,0x00,0x00,0x18,0x21,0x10,0x80,0x00,0x02,0x24,0x03,0x00,0x01, +0x00,0xa6,0x18,0x2b,0x08,0x00,0x13,0x22,0xa2,0x03,0x00,0x17,0x10,0x40,0xff,0xfd, +0x00,0xa6,0x18,0x2b,0x08,0x00,0x13,0x56,0x00,0x00,0x00,0x00,0x10,0x62,0x00,0x09, +0x24,0x02,0x00,0x02,0x10,0x62,0x00,0x05,0x24,0x02,0x00,0x03,0x14,0x62,0xff,0xb8, +0x00,0x00,0x00,0x00,0x08,0x00,0x13,0x1c,0xa2,0x20,0x00,0x07,0x08,0x00,0x13,0x1c, +0xa2,0x20,0x00,0x06,0x08,0x00,0x13,0x1c,0xa2,0x20,0x00,0x05,0x82,0x22,0x00,0x10, +0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x68,0x2c,0x62,0x00,0x02,0x10,0x40,0x00,0x48, +0x3c,0x02,0xb0,0x09,0x92,0x25,0x00,0x08,0x00,0x00,0x00,0x00,0x30,0xa6,0x00,0xff, +0x2c,0xc2,0x00,0x04,0x10,0x40,0x00,0x3a,0x2c,0xc2,0x00,0x10,0x3c,0x04,0xb0,0x05, +0x34,0x84,0x02,0x29,0x90,0x83,0x00,0x00,0x24,0x02,0x00,0x01,0x00,0xc2,0x10,0x04, +0x00,0x02,0x10,0x27,0x00,0x62,0x18,0x24,0xa0,0x83,0x00,0x00,0x86,0x23,0x00,0x0c, +0x96,0x26,0x00,0x0c,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x28,0x80, +0x27,0x83,0x96,0x44,0x00,0xa3,0x18,0x21,0x8c,0x64,0x00,0x18,0x00,0x00,0x00,0x00, +0x8c,0x82,0x00,0x04,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x10,0x10,0x40,0x00,0x18, +0x00,0x00,0x00,0x00,0x93,0x82,0x91,0x51,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x01, +0x14,0x40,0x00,0x0a,0x24,0x05,0x00,0x24,0x00,0x06,0x2c,0x00,0x00,0x05,0x2c,0x03, +0x0c,0x00,0x1f,0xdd,0x02,0x00,0x20,0x21,0x92,0x02,0x00,0x16,0xa2,0x00,0x00,0x12, +0x30,0x42,0x00,0xe7,0x08,0x00,0x13,0x13,0xa2,0x02,0x00,0x16,0xf0,0xc5,0x00,0x06, +0x00,0x00,0x28,0x12,0x27,0x82,0x96,0x40,0x00,0xa2,0x28,0x21,0x0c,0x00,0x01,0x49, +0x3c,0x04,0x00,0x80,0x96,0x26,0x00,0x0c,0x08,0x00,0x13,0x93,0x00,0x06,0x2c,0x00, +0x27,0x83,0x96,0x50,0x27,0x82,0x96,0x58,0x00,0xa2,0x10,0x21,0x00,0xa3,0x18,0x21, +0x90,0x44,0x00,0x00,0x90,0x65,0x00,0x05,0x00,0x00,0x30,0x21,0x0c,0x00,0x25,0xc4, +0x24,0x07,0x00,0x01,0x96,0x26,0x00,0x0c,0x08,0x00,0x13,0x8d,0x00,0x00,0x00,0x00, +0x14,0x40,0xff,0xce,0x3c,0x04,0xb0,0x05,0x34,0x84,0x02,0x29,0x90,0x83,0x00,0x00, +0x30,0xa5,0x00,0x0f,0x24,0x02,0x00,0x80,0x08,0x00,0x13,0x7c,0x00,0xa2,0x10,0x07, +0x86,0x26,0x00,0x0c,0x3c,0x03,0xb0,0x09,0x34,0x42,0x01,0x72,0x34,0x63,0x01,0x78, +0x94,0x47,0x00,0x00,0x8c,0x65,0x00,0x00,0x00,0x06,0x10,0xc0,0x00,0x46,0x10,0x21, +0x3c,0x04,0xb0,0x09,0xae,0x25,0x00,0x1c,0x34,0x84,0x01,0x7c,0x27,0x83,0x96,0x44, +0x00,0x02,0x10,0x80,0x8c,0x85,0x00,0x00,0x00,0x43,0x10,0x21,0x8c,0x43,0x00,0x18, +0xae,0x25,0x00,0x20,0xa6,0x27,0x00,0x18,0x8c,0x66,0x00,0x08,0x02,0x20,0x20,0x21, +0x0c,0x00,0x13,0xe2,0x00,0x00,0x28,0x21,0x86,0x25,0x00,0x18,0x8e,0x26,0x00,0x1c, +0x8e,0x27,0x00,0x20,0x02,0x20,0x20,0x21,0x0c,0x00,0x20,0xdf,0xaf,0xa2,0x00,0x10, +0x08,0x00,0x13,0x13,0xa2,0x02,0x00,0x12,0x92,0x22,0x00,0x08,0x08,0x00,0x13,0x13, +0xa2,0x22,0x00,0x09,0xa2,0x20,0x00,0x11,0x80,0x82,0x00,0x50,0x00,0x00,0x00,0x00, +0x10,0x40,0x00,0x03,0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0xd0,0xac,0x40,0x00,0x00, +0x08,0x00,0x13,0x13,0xa0,0x80,0x00,0x50,0x94,0x8a,0x00,0x0c,0x24,0x03,0x00,0x24, +0x00,0x80,0x70,0x21,0x3c,0x02,0x80,0x00,0x3c,0x04,0xb0,0x03,0x24,0x42,0x4f,0x88, +0xf1,0x43,0x00,0x06,0x34,0x84,0x00,0x20,0x00,0x00,0x18,0x12,0x00,0xa0,0x68,0x21, +0xac,0x82,0x00,0x00,0x27,0x85,0x96,0x50,0x27,0x82,0x96,0x4f,0x27,0xbd,0xff,0xf8, +0x00,0x62,0x60,0x21,0x00,0x65,0x58,0x21,0x00,0x00,0xc0,0x21,0x11,0xa0,0x00,0xcc, +0x00,0x00,0x78,0x21,0x00,0x0a,0x1c,0x00,0x00,0x03,0x1c,0x03,0x00,0x03,0x10,0xc0, +0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x45,0x10,0x21,0x91,0x87,0x00,0x00, +0x80,0x48,0x00,0x04,0x03,0xa0,0x60,0x21,0x00,0x0a,0x1c,0x00,0x00,0x03,0x1c,0x03, +0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x48,0x80,0x27,0x83,0x96,0x44, +0xa3,0xa7,0x00,0x00,0x01,0x23,0x18,0x21,0x8c,0x64,0x00,0x18,0x25,0x02,0xff,0xff, +0x00,0x48,0x40,0x0b,0x8c,0x83,0x00,0x04,0x2d,0x05,0x00,0x07,0x24,0x02,0x00,0x06, +0x30,0x63,0x00,0x08,0x14,0x60,0x00,0x35,0x00,0x45,0x40,0x0a,0x93,0xa7,0x00,0x00, +0x27,0x82,0x96,0x58,0x01,0x22,0x10,0x21,0x30,0xe3,0x00,0xf0,0x38,0x63,0x00,0x50, +0x30,0xe5,0x00,0xff,0x00,0x05,0x20,0x2b,0x00,0x03,0x18,0x2b,0x00,0x64,0x18,0x24, +0x90,0x49,0x00,0x00,0x10,0x60,0x00,0x16,0x30,0xe4,0x00,0x0f,0x24,0x02,0x00,0x04, +0x10,0xa2,0x00,0x9d,0x00,0x00,0x00,0x00,0x11,0xa0,0x00,0x3a,0x2c,0xa2,0x00,0x0c, +0x10,0x40,0x00,0x02,0x24,0x84,0x00,0x0c,0x00,0xe0,0x20,0x21,0x30,0x84,0x00,0xff, +0x00,0x04,0x10,0x40,0x27,0x83,0xc1,0x5c,0x00,0x44,0x10,0x21,0x00,0x43,0x10,0x21, +0x90,0x47,0x00,0x00,0x00,0x00,0x00,0x00,0x2c,0xe3,0x00,0x0c,0xa3,0xa7,0x00,0x00, +0x10,0x60,0x00,0x02,0x24,0xe2,0x00,0x04,0x00,0xe0,0x10,0x21,0xa3,0xa2,0x00,0x00, +0x91,0x65,0x00,0x00,0x91,0x82,0x00,0x00,0x30,0xa3,0x00,0xff,0x00,0x62,0x10,0x2b, +0x10,0x40,0x00,0x0e,0x2c,0x62,0x00,0x0c,0x14,0x40,0x00,0x03,0x00,0x60,0x20,0x21, +0x30,0xa2,0x00,0x0f,0x24,0x44,0x00,0x0c,0x00,0x04,0x10,0x40,0x00,0x44,0x20,0x21, +0x27,0x83,0xc1,0x5c,0x00,0x83,0x18,0x21,0x90,0x62,0x00,0x02,0x00,0x00,0x00,0x00, +0x10,0x40,0x00,0x05,0x00,0x09,0x11,0x00,0xa1,0x85,0x00,0x00,0x93,0xa2,0x00,0x00, +0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x08,0x00,0x49,0x10,0x23,0x00,0x02,0x10,0x80, +0x00,0x49,0x10,0x23,0x00,0x02,0x10,0x80,0x00,0x44,0x10,0x21,0x27,0x83,0xba,0xe8, +0x00,0x43,0x10,0x21,0x90,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x2c,0x83,0x00,0x0c, +0x14,0x60,0x00,0x06,0x00,0x80,0x10,0x21,0x00,0x18,0x10,0x40,0x00,0x4f,0x10,0x21, +0x00,0x02,0x11,0x00,0x00,0x82,0x10,0x21,0x24,0x42,0x00,0x04,0x08,0x00,0x14,0x43, +0xa1,0x82,0x00,0x00,0x8f,0x8d,0x87,0xf0,0x00,0x00,0x00,0x00,0x01,0xa8,0x10,0x21, +0x90,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x60,0xff,0xd1,0x00,0x00,0x28,0x21, +0x00,0x06,0x74,0x82,0x30,0xe2,0x00,0xff,0x2c,0x42,0x00,0x0c,0x14,0x40,0x00,0x03, +0x00,0xe0,0x10,0x21,0x30,0xe2,0x00,0x0f,0x24,0x42,0x00,0x0c,0x30,0x44,0x00,0xff, +0xa3,0xa2,0x00,0x00,0x24,0x02,0x00,0x0c,0x10,0x82,0x00,0x0d,0x00,0x09,0x11,0x00, +0x00,0x49,0x10,0x23,0x00,0x02,0x10,0x80,0x00,0x04,0x18,0x40,0x00,0x49,0x10,0x23, +0x00,0x64,0x18,0x21,0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21,0x27,0x84,0xba,0xe8, +0x00,0x44,0x10,0x21,0x90,0x47,0x00,0x00,0x00,0x00,0x00,0x00,0xa3,0xa7,0x00,0x00, +0x00,0x0a,0x1c,0x00,0x00,0x03,0x1c,0x03,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21, +0x00,0x02,0x10,0x80,0x27,0x83,0x96,0x44,0x00,0x43,0x10,0x21,0x8c,0x44,0x00,0x18, +0x00,0x00,0x00,0x00,0x8c,0x83,0x00,0x04,0x00,0x00,0x00,0x00,0x30,0x63,0x00,0x10, +0x14,0x60,0x00,0x33,0x00,0x06,0x14,0x42,0x00,0x09,0x11,0x00,0x00,0x49,0x10,0x23, +0x00,0x02,0x10,0x80,0x00,0x49,0x10,0x23,0x27,0x83,0xbb,0xb8,0x00,0x02,0x10,0x80, +0x00,0x43,0x10,0x21,0x90,0x44,0x00,0x04,0x90,0x43,0x00,0x05,0x00,0x00,0x00,0x00, +0x00,0x64,0xc0,0x24,0x93,0xa7,0x00,0x00,0x00,0x00,0x00,0x00,0x2c,0xe2,0x00,0x0f, +0x10,0x40,0x00,0x0f,0x31,0xcf,0x00,0x01,0x00,0x0a,0x1c,0x00,0x00,0x03,0x1c,0x03, +0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80,0x27,0x84,0x96,0x40, +0x00,0x44,0x10,0x21,0x84,0x43,0x00,0x06,0x00,0x00,0x00,0x00,0x28,0x63,0x06,0x41, +0x14,0x60,0x00,0x04,0x30,0xe2,0x00,0xff,0x24,0x07,0x00,0x0f,0xa3,0xa7,0x00,0x00, +0x30,0xe2,0x00,0xff,0x2c,0x42,0x00,0x0c,0x14,0x40,0x00,0x06,0x00,0xe0,0x10,0x21, +0x00,0x18,0x10,0x40,0x00,0x4f,0x10,0x21,0x00,0x02,0x11,0x00,0x00,0x47,0x10,0x21, +0x24,0x42,0x00,0x04,0xa3,0xa2,0x00,0x00,0x00,0x40,0x38,0x21,0x01,0xa8,0x10,0x21, +0x90,0x43,0x00,0x00,0x24,0xa4,0x00,0x01,0x30,0x85,0xff,0xff,0x00,0xa3,0x18,0x2b, +0x14,0x60,0xff,0xad,0x30,0xe2,0x00,0xff,0x08,0x00,0x14,0x30,0x00,0x00,0x00,0x00, +0x08,0x00,0x14,0x91,0x30,0x58,0x00,0x01,0x81,0xc2,0x00,0x48,0x00,0x00,0x00,0x00, +0x10,0x40,0xff,0x73,0x00,0x00,0x00,0x00,0x08,0x00,0x14,0x1e,0x00,0x00,0x00,0x00, +0x00,0x0a,0x1c,0x00,0x00,0x03,0x1c,0x03,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21, +0x00,0x02,0x10,0x80,0x00,0x45,0x10,0x21,0x80,0x48,0x00,0x05,0x91,0x67,0x00,0x00, +0x08,0x00,0x13,0xfe,0x03,0xa0,0x58,0x21,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00, +0x34,0x63,0x00,0x20,0x24,0x42,0x53,0x28,0x03,0xe0,0x00,0x08,0xac,0x62,0x00,0x00, +0x27,0xbd,0xff,0xc0,0xaf,0xb7,0x00,0x34,0xaf,0xb6,0x00,0x30,0xaf,0xb5,0x00,0x2c, +0xaf,0xb4,0x00,0x28,0xaf,0xb3,0x00,0x24,0xaf,0xb2,0x00,0x20,0xaf,0xbf,0x00,0x3c, +0xaf,0xbe,0x00,0x38,0xaf,0xb1,0x00,0x1c,0xaf,0xb0,0x00,0x18,0x84,0x82,0x00,0x0c, +0x27,0x93,0x96,0x44,0x3c,0x05,0xb0,0x03,0x00,0x02,0x18,0xc0,0x00,0x62,0x18,0x21, +0x00,0x03,0x18,0x80,0x00,0x73,0x10,0x21,0x8c,0x5e,0x00,0x18,0x3c,0x02,0x80,0x00, +0x34,0xa5,0x00,0x20,0x24,0x42,0x53,0x40,0xac,0xa2,0x00,0x00,0x8f,0xd0,0x00,0x08, +0x27,0x95,0x96,0x50,0x00,0x75,0x18,0x21,0x00,0x00,0x28,0x21,0x02,0x00,0x30,0x21, +0x90,0x71,0x00,0x00,0x0c,0x00,0x13,0xe2,0x00,0x80,0xb0,0x21,0x00,0x40,0x90,0x21, +0x00,0x10,0x14,0x42,0x30,0x54,0x00,0x01,0x02,0x40,0x20,0x21,0x00,0x10,0x14,0x82, +0x02,0x80,0x28,0x21,0x12,0x51,0x00,0x23,0x00,0x10,0xbf,0xc2,0x86,0xc3,0x00,0x0c, +0x30,0x50,0x00,0x01,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80, +0x00,0x55,0x10,0x21,0xa0,0x52,0x00,0x00,0x86,0xc3,0x00,0x0c,0x00,0x00,0x00,0x00, +0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x53,0x30,0x21, +0x8c,0xc7,0x00,0x18,0x27,0x83,0x96,0x40,0x00,0x43,0x10,0x21,0x8c,0xe3,0x00,0x04, +0x84,0x46,0x00,0x06,0x00,0x03,0x19,0x42,0x0c,0x00,0x0d,0xd7,0x30,0x73,0x00,0x01, +0x00,0x40,0x88,0x21,0x02,0x40,0x20,0x21,0x02,0x80,0x28,0x21,0x16,0xe0,0x00,0x10, +0x02,0x00,0x30,0x21,0x86,0xc2,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x02,0x18,0xc0, +0x00,0x62,0x18,0x21,0x00,0x03,0x18,0x80,0x27,0x82,0x96,0x48,0x00,0x62,0x18,0x21, +0xa4,0x71,0x00,0x04,0x7b,0xbe,0x01,0xfc,0x7b,0xb6,0x01,0xbc,0x7b,0xb4,0x01,0x7c, +0x7b,0xb2,0x01,0x3c,0x7b,0xb0,0x00,0xfc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x40, +0x86,0xc3,0x00,0x0c,0xaf,0xb3,0x00,0x10,0xaf,0xa0,0x00,0x14,0x00,0x03,0x10,0xc0, +0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x55,0x10,0x21,0x80,0x47,0x00,0x06, +0x00,0x00,0x00,0x00,0x24,0xe7,0x00,0x02,0x00,0x07,0x17,0xc2,0x00,0xe2,0x38,0x21, +0x00,0x07,0x38,0x43,0x00,0x07,0x38,0x40,0x0c,0x00,0x0d,0xfe,0x03,0xc7,0x38,0x21, +0x08,0x00,0x15,0x11,0x02,0x22,0x88,0x21,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00, +0x27,0xbd,0xff,0xd0,0x34,0x63,0x00,0x20,0x24,0x42,0x54,0xc8,0xaf,0xb2,0x00,0x20, +0xac,0x62,0x00,0x00,0xaf,0xbf,0x00,0x28,0xaf,0xb3,0x00,0x24,0xaf,0xb1,0x00,0x1c, +0xaf,0xb0,0x00,0x18,0x3c,0x02,0xb0,0x03,0x90,0x83,0x00,0x0a,0x34,0x42,0x01,0x04, +0x94,0x45,0x00,0x00,0x00,0x03,0x18,0x80,0x27,0x82,0xba,0x40,0x00,0x62,0x18,0x21, +0x30,0xa6,0xff,0xff,0x8c,0x71,0x00,0x00,0x80,0x85,0x00,0x12,0x30,0xc8,0x00,0xff, +0x00,0x06,0x32,0x02,0xa4,0x86,0x00,0x44,0xa4,0x88,0x00,0x46,0x82,0x22,0x00,0x12, +0x00,0x80,0x90,0x21,0x10,0xa0,0x00,0x1b,0xa0,0x80,0x00,0x15,0x00,0xc5,0x10,0x2a, +0x10,0x40,0x00,0x14,0x00,0x00,0x00,0x00,0xa2,0x20,0x00,0x19,0x84,0x83,0x00,0x0c, +0x00,0x00,0x00,0x00,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80, +0x27,0x83,0x96,0x60,0x00,0x43,0x10,0x21,0xa0,0x40,0x00,0x00,0xa0,0x80,0x00,0x12, +0x92,0x22,0x00,0x16,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xdf,0xa2,0x22,0x00,0x16, +0x8f,0xbf,0x00,0x28,0x7b,0xb2,0x01,0x3c,0x7b,0xb0,0x00,0xfc,0x03,0xe0,0x00,0x08, +0x27,0xbd,0x00,0x30,0x0c,0x00,0x14,0xca,0x00,0x00,0x00,0x00,0x08,0x00,0x15,0x60, +0x00,0x00,0x00,0x00,0x28,0x42,0x00,0x02,0x10,0x40,0x01,0x65,0x00,0x00,0x28,0x21, +0x84,0x83,0x00,0x0c,0x27,0x84,0x96,0x50,0x96,0x47,0x00,0x0c,0x00,0x03,0x10,0xc0, +0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80,0x27,0x83,0x96,0x48,0x00,0x43,0x18,0x21, +0x80,0x65,0x00,0x06,0x00,0x44,0x10,0x21,0x80,0x49,0x00,0x05,0x38,0xa5,0x00,0x00, +0x80,0x4a,0x00,0x04,0x15,0x20,0x00,0x27,0x01,0x05,0x30,0x0b,0x15,0x40,0x00,0x11, +0x30,0xe3,0xff,0xff,0x92,0x45,0x00,0x08,0x00,0x00,0x00,0x00,0x30,0xa8,0x00,0xff, +0x2d,0x02,0x00,0x04,0x10,0x40,0x01,0x45,0x2d,0x02,0x00,0x10,0x3c,0x04,0xb0,0x05, +0x34,0x84,0x02,0x29,0x90,0x83,0x00,0x00,0x24,0x02,0x00,0x01,0x01,0x02,0x10,0x04, +0x00,0x62,0x18,0x25,0xa0,0x83,0x00,0x00,0x96,0x47,0x00,0x0c,0x00,0x00,0x00,0x00, +0x30,0xe3,0xff,0xff,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x27,0x84,0x96,0x50, +0x00,0x02,0x10,0x80,0x00,0x44,0x10,0x21,0x80,0x45,0x00,0x06,0x00,0x03,0x1a,0x00, +0x3c,0x04,0xb0,0x00,0x00,0x65,0x18,0x21,0x00,0x64,0x28,0x21,0x94,0xa2,0x00,0x00, +0x82,0x43,0x00,0x10,0x00,0x02,0x14,0x00,0x14,0x60,0x00,0x06,0x00,0x02,0x24,0x03, +0x30,0x82,0x00,0x04,0x14,0x40,0x00,0x04,0x01,0x49,0x10,0x21,0x34,0x82,0x08,0x00, +0xa4,0xa2,0x00,0x00,0x01,0x49,0x10,0x21,0x00,0x02,0x16,0x00,0x00,0x02,0x16,0x03, +0x00,0x46,0x10,0x2a,0x10,0x40,0x00,0x7c,0x00,0x00,0x00,0x00,0x82,0x42,0x00,0x10, +0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x0e,0x00,0x00,0x00,0x00,0x86,0x43,0x00,0x0c, +0x25,0x44,0x00,0x01,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80, +0x27,0x83,0x96,0x50,0x00,0x43,0x10,0x21,0xa0,0x44,0x00,0x04,0x92,0x23,0x00,0x16, +0x02,0x40,0x20,0x21,0x30,0x63,0x00,0xfb,0x08,0x00,0x15,0x65,0xa2,0x23,0x00,0x16, +0x86,0x43,0x00,0x0c,0x25,0x24,0x00,0x01,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21, +0x00,0x02,0x10,0x80,0x27,0x83,0x96,0x50,0x00,0x43,0x10,0x21,0xa0,0x44,0x00,0x05, +0x86,0x45,0x00,0x0c,0x0c,0x00,0x23,0x1c,0x02,0x20,0x20,0x21,0x10,0x40,0x00,0x5a, +0x00,0x00,0x00,0x00,0x92,0x45,0x00,0x08,0x00,0x00,0x00,0x00,0x30,0xa6,0x00,0xff, +0x2c,0xc2,0x00,0x04,0x10,0x40,0x00,0x4c,0x2c,0xc2,0x00,0x10,0x3c,0x04,0xb0,0x05, +0x34,0x84,0x02,0x29,0x90,0x83,0x00,0x00,0x24,0x02,0x00,0x01,0x00,0xc2,0x10,0x04, +0x00,0x02,0x10,0x27,0x00,0x62,0x18,0x24,0xa0,0x83,0x00,0x00,0x92,0x45,0x00,0x08, +0x00,0x00,0x00,0x00,0x30,0xa5,0x00,0xff,0x14,0xa0,0x00,0x33,0x24,0x02,0x00,0x01, +0xa2,0x40,0x00,0x04,0x92,0x22,0x00,0x04,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x0c, +0x24,0x02,0x00,0x01,0xa2,0x22,0x00,0x17,0x92,0x22,0x00,0x17,0x00,0x00,0x00,0x00, +0x10,0x40,0x00,0x04,0x00,0x00,0x00,0x00,0x96,0x22,0x00,0x06,0x08,0x00,0x15,0x60, +0xa6,0x22,0x00,0x14,0x96,0x22,0x00,0x00,0x08,0x00,0x15,0x60,0xa6,0x22,0x00,0x14, +0x92,0x22,0x00,0x0a,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x03,0x00,0x00,0x00,0x00, +0x08,0x00,0x15,0xde,0xa2,0x20,0x00,0x17,0x96,0x24,0x00,0x00,0x96,0x25,0x00,0x06, +0x27,0x86,0x96,0x40,0x00,0x04,0x18,0xc0,0x00,0x64,0x18,0x21,0x00,0x05,0x10,0xc0, +0x00,0x45,0x10,0x21,0x00,0x03,0x18,0x80,0x00,0x66,0x18,0x21,0x00,0x02,0x10,0x80, +0x00,0x46,0x10,0x21,0x8c,0x65,0x00,0x08,0x8c,0x44,0x00,0x08,0x3c,0x03,0x80,0x00, +0x00,0xa3,0x30,0x24,0x10,0xc0,0x00,0x08,0x00,0x83,0x10,0x24,0x10,0x40,0x00,0x04, +0x00,0x00,0x18,0x21,0x10,0xc0,0x00,0x02,0x24,0x03,0x00,0x01,0x00,0x85,0x18,0x2b, +0x08,0x00,0x15,0xde,0xa2,0x23,0x00,0x17,0x10,0x40,0xff,0xfd,0x00,0x85,0x18,0x2b, +0x08,0x00,0x16,0x01,0x00,0x00,0x00,0x00,0x10,0xa2,0x00,0x09,0x24,0x02,0x00,0x02, +0x10,0xa2,0x00,0x05,0x24,0x02,0x00,0x03,0x14,0xa2,0xff,0xca,0x00,0x00,0x00,0x00, +0x08,0x00,0x15,0xd9,0xa2,0x40,0x00,0x07,0x08,0x00,0x15,0xd9,0xa2,0x40,0x00,0x06, +0x08,0x00,0x15,0xd9,0xa2,0x40,0x00,0x05,0x14,0x40,0xff,0xbe,0x3c,0x04,0xb0,0x05, +0x34,0x84,0x02,0x29,0x90,0x83,0x00,0x00,0x30,0xa5,0x00,0x0f,0x24,0x02,0x00,0x80, +0x08,0x00,0x15,0xd0,0x00,0xa2,0x10,0x07,0x0c,0x00,0x14,0xd0,0x02,0x40,0x20,0x21, +0x08,0x00,0x15,0x60,0x00,0x00,0x00,0x00,0x92,0x45,0x00,0x08,0x00,0x00,0x00,0x00, +0x30,0xa6,0x00,0xff,0x2c,0xc2,0x00,0x04,0x10,0x40,0x00,0x98,0x2c,0xc2,0x00,0x10, +0x3c,0x04,0xb0,0x05,0x34,0x84,0x02,0x29,0x90,0x83,0x00,0x00,0x24,0x02,0x00,0x01, +0x00,0xc2,0x10,0x04,0x00,0x02,0x10,0x27,0x00,0x62,0x18,0x24,0xa0,0x83,0x00,0x00, +0x92,0x45,0x00,0x08,0x00,0x00,0x00,0x00,0x30,0xa5,0x00,0xff,0x14,0xa0,0x00,0x7f, +0x24,0x02,0x00,0x01,0xa2,0x40,0x00,0x04,0x86,0x43,0x00,0x0c,0x27,0x93,0x96,0x44, +0x96,0x47,0x00,0x0c,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x28,0x80, +0x00,0xb3,0x18,0x21,0x8c,0x64,0x00,0x18,0x00,0x00,0x00,0x00,0x8c,0x82,0x00,0x04, +0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x10,0x10,0x40,0x00,0x64,0x00,0x00,0x00,0x00, +0x00,0x07,0x1c,0x00,0x00,0x03,0x1c,0x03,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21, +0x00,0x02,0x10,0x80,0x00,0x53,0x10,0x21,0x8c,0x43,0x00,0x18,0x93,0x82,0x91,0x51, +0x8c,0x64,0x00,0x04,0x30,0x42,0x00,0x01,0x00,0x04,0x21,0x42,0x14,0x40,0x00,0x4d, +0x30,0x90,0x00,0x01,0x00,0x07,0x2c,0x00,0x00,0x05,0x2c,0x03,0x0c,0x00,0x1f,0xdd, +0x02,0x20,0x20,0x21,0x96,0x26,0x00,0x06,0x12,0x00,0x00,0x14,0x30,0xc5,0xff,0xff, +0x02,0x60,0x90,0x21,0x00,0x05,0x10,0xc0,0x00,0x45,0x10,0x21,0x00,0x02,0x10,0x80, +0x00,0x52,0x18,0x21,0x92,0x22,0x00,0x0a,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x0b, +0x02,0x20,0x20,0x21,0x8c,0x63,0x00,0x18,0x00,0x00,0x00,0x00,0x8c,0x62,0x00,0x04, +0x00,0x00,0x00,0x00,0x00,0x02,0x11,0x42,0x0c,0x00,0x1f,0xdd,0x30,0x50,0x00,0x01, +0x96,0x26,0x00,0x06,0x16,0x00,0xff,0xef,0x30,0xc5,0xff,0xff,0x92,0x22,0x00,0x04, +0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x0d,0x24,0x02,0x00,0x01,0xa2,0x22,0x00,0x17, +0x92,0x22,0x00,0x17,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x05,0x00,0x00,0x00,0x00, +0xa6,0x26,0x00,0x14,0x92,0x22,0x00,0x16,0x08,0x00,0x15,0x5f,0x30,0x42,0x00,0xc3, +0x96,0x22,0x00,0x00,0x08,0x00,0x16,0x75,0xa6,0x22,0x00,0x14,0x92,0x22,0x00,0x0a, +0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x03,0x00,0x00,0x00,0x00,0x08,0x00,0x16,0x70, +0xa2,0x20,0x00,0x17,0x96,0x24,0x00,0x00,0x30,0xc5,0xff,0xff,0x00,0x05,0x18,0xc0, +0x00,0x04,0x10,0xc0,0x00,0x44,0x10,0x21,0x00,0x65,0x18,0x21,0x27,0x84,0x96,0x40, +0x00,0x02,0x10,0x80,0x00,0x44,0x10,0x21,0x00,0x03,0x18,0x80,0x8c,0x45,0x00,0x08, +0x00,0x64,0x18,0x21,0x8c,0x64,0x00,0x08,0x3c,0x02,0x80,0x00,0x00,0xa2,0x38,0x24, +0x10,0xe0,0x00,0x08,0x00,0x82,0x10,0x24,0x10,0x40,0x00,0x04,0x00,0x00,0x18,0x21, +0x10,0xe0,0x00,0x02,0x24,0x03,0x00,0x01,0x00,0x85,0x18,0x2b,0x08,0x00,0x16,0x70, +0xa2,0x23,0x00,0x17,0x10,0x40,0xff,0xfd,0x00,0x85,0x18,0x2b,0x08,0x00,0x16,0x94, +0x00,0x00,0x00,0x00,0x24,0x05,0x00,0x24,0xf0,0xe5,0x00,0x06,0x00,0x00,0x28,0x12, +0x27,0x82,0x96,0x40,0x00,0xa2,0x28,0x21,0x0c,0x00,0x01,0x49,0x00,0x00,0x20,0x21, +0x96,0x47,0x00,0x0c,0x08,0x00,0x16,0x52,0x00,0x07,0x2c,0x00,0x27,0x83,0x96,0x50, +0x27,0x82,0x96,0x58,0x00,0xa2,0x10,0x21,0x00,0xa3,0x18,0x21,0x90,0x44,0x00,0x00, +0x90,0x65,0x00,0x05,0x24,0x07,0x00,0x01,0x0c,0x00,0x25,0xc4,0x00,0x00,0x30,0x21, +0x96,0x47,0x00,0x0c,0x08,0x00,0x16,0x45,0x00,0x07,0x1c,0x00,0x10,0xa2,0x00,0x09, +0x24,0x02,0x00,0x02,0x10,0xa2,0x00,0x05,0x24,0x02,0x00,0x03,0x14,0xa2,0xff,0x7e, +0x00,0x00,0x00,0x00,0x08,0x00,0x16,0x36,0xa2,0x40,0x00,0x07,0x08,0x00,0x16,0x36, +0xa2,0x40,0x00,0x06,0x08,0x00,0x16,0x36,0xa2,0x40,0x00,0x05,0x14,0x40,0xff,0x72, +0x3c,0x04,0xb0,0x05,0x34,0x84,0x02,0x29,0x90,0x83,0x00,0x00,0x30,0xa5,0x00,0x0f, +0x24,0x02,0x00,0x80,0x08,0x00,0x16,0x2d,0x00,0xa2,0x10,0x07,0x14,0x40,0xfe,0xc4, +0x00,0x00,0x00,0x00,0x3c,0x04,0xb0,0x05,0x34,0x84,0x02,0x29,0x90,0x83,0x00,0x00, +0x30,0xa5,0x00,0x0f,0x24,0x02,0x00,0x80,0x08,0x00,0x15,0x88,0x00,0xa2,0x10,0x07, +0x84,0x83,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21, +0x00,0x02,0x10,0x80,0x27,0x83,0x96,0x44,0x00,0x43,0x10,0x21,0x8c,0x47,0x00,0x18, +0x00,0x00,0x00,0x00,0x8c,0xe6,0x00,0x08,0x0c,0x00,0x13,0xe2,0x00,0x00,0x00,0x00, +0x02,0x40,0x20,0x21,0x00,0x00,0x28,0x21,0x00,0x00,0x30,0x21,0x00,0x00,0x38,0x21, +0x0c,0x00,0x20,0xdf,0xaf,0xa2,0x00,0x10,0x00,0x02,0x1e,0x00,0x14,0x60,0xfe,0x7c, +0xa2,0x22,0x00,0x12,0x92,0x43,0x00,0x08,0x00,0x00,0x00,0x00,0x14,0x60,0x00,0x40, +0x24,0x02,0x00,0x01,0xa2,0x40,0x00,0x04,0x92,0x28,0x00,0x04,0x00,0x00,0x00,0x00, +0x15,0x00,0x00,0x19,0x24,0x02,0x00,0x01,0x92,0x27,0x00,0x0a,0xa2,0x22,0x00,0x17, +0x92,0x22,0x00,0x17,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x10,0x00,0x00,0x00,0x00, +0x96,0x22,0x00,0x06,0x00,0x00,0x00,0x00,0xa6,0x22,0x00,0x14,0x92,0x22,0x00,0x16, +0x30,0xe3,0x00,0xff,0x30,0x42,0x00,0xc0,0x10,0x60,0x00,0x03,0xa2,0x22,0x00,0x16, +0x34,0x42,0x00,0x01,0xa2,0x22,0x00,0x16,0x11,0x00,0xfe,0x61,0x00,0x00,0x00,0x00, +0x92,0x22,0x00,0x16,0x08,0x00,0x15,0x5f,0x34,0x42,0x00,0x02,0x96,0x22,0x00,0x00, +0x08,0x00,0x16,0xf7,0xa6,0x22,0x00,0x14,0x92,0x27,0x00,0x0a,0x00,0x00,0x00,0x00, +0x14,0xe0,0x00,0x03,0x00,0x00,0x00,0x00,0x08,0x00,0x16,0xf0,0xa2,0x20,0x00,0x17, +0x96,0x24,0x00,0x00,0x96,0x25,0x00,0x06,0x27,0x86,0x96,0x40,0x00,0x04,0x18,0xc0, +0x00,0x64,0x18,0x21,0x00,0x05,0x10,0xc0,0x00,0x45,0x10,0x21,0x00,0x03,0x18,0x80, +0x00,0x66,0x18,0x21,0x00,0x02,0x10,0x80,0x00,0x46,0x10,0x21,0x8c,0x65,0x00,0x08, +0x8c,0x44,0x00,0x08,0x3c,0x03,0x80,0x00,0x00,0xa3,0x30,0x24,0x10,0xc0,0x00,0x08, +0x00,0x83,0x10,0x24,0x10,0x40,0x00,0x04,0x00,0x00,0x18,0x21,0x10,0xc0,0x00,0x02, +0x24,0x03,0x00,0x01,0x00,0x85,0x18,0x2b,0x08,0x00,0x16,0xf0,0xa2,0x23,0x00,0x17, +0x10,0x40,0xff,0xfd,0x00,0x85,0x18,0x2b,0x08,0x00,0x17,0x1f,0x00,0x00,0x00,0x00, +0x10,0x62,0x00,0x09,0x24,0x02,0x00,0x02,0x10,0x62,0x00,0x05,0x24,0x02,0x00,0x03, +0x14,0x62,0xff,0xbd,0x00,0x00,0x00,0x00,0x08,0x00,0x16,0xea,0xa2,0x40,0x00,0x07, +0x08,0x00,0x16,0xea,0xa2,0x40,0x00,0x06,0x08,0x00,0x16,0xea,0xa2,0x40,0x00,0x05, +0x3c,0x02,0x80,0x00,0x00,0x82,0x30,0x24,0x10,0xc0,0x00,0x08,0x00,0xa2,0x18,0x24, +0x10,0x60,0x00,0x04,0x00,0x00,0x10,0x21,0x10,0xc0,0x00,0x02,0x24,0x02,0x00,0x01, +0x00,0xa4,0x10,0x2b,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x10,0x60,0xff,0xfd, +0x00,0xa4,0x10,0x2b,0x08,0x00,0x17,0x3a,0x00,0x00,0x00,0x00,0x30,0x82,0xff,0xff, +0x00,0x02,0x18,0xc0,0x00,0x62,0x18,0x21,0x27,0x84,0x96,0x50,0x00,0x03,0x18,0x80, +0x00,0x64,0x18,0x21,0x80,0x66,0x00,0x06,0x00,0x02,0x12,0x00,0x3c,0x03,0xb0,0x00, +0x00,0x46,0x10,0x21,0x00,0x45,0x10,0x21,0x03,0xe0,0x00,0x08,0x00,0x43,0x10,0x21, +0x27,0xbd,0xff,0xe0,0x30,0x82,0x00,0x7c,0x30,0x84,0xff,0x00,0xaf,0xbf,0x00,0x1c, +0xaf,0xb2,0x00,0x18,0xaf,0xb1,0x00,0x14,0xaf,0xb0,0x00,0x10,0x14,0x40,0x00,0x41, +0x00,0x04,0x22,0x03,0x24,0x02,0x00,0x04,0x3c,0x10,0xb0,0x03,0x8e,0x10,0x00,0x00, +0x10,0x82,0x00,0x32,0x24,0x02,0x00,0x08,0x10,0x82,0x00,0x03,0x32,0x02,0x00,0x20, +0x08,0x00,0x17,0x60,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x17,0x3c,0x02,0xb0,0x06, +0x34,0x42,0x80,0x24,0x8c,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x67,0x00,0xff, +0x10,0xe0,0x00,0x23,0x00,0x00,0x88,0x21,0x8f,0x85,0x96,0x20,0x00,0x40,0x30,0x21, +0x94,0xa2,0x00,0x08,0x8c,0xc3,0x00,0x00,0x26,0x31,0x00,0x01,0x24,0x42,0x00,0x02, +0x30,0x42,0x01,0xff,0x34,0x63,0x01,0x00,0x02,0x27,0x20,0x2a,0xa4,0xa2,0x00,0x08, +0x14,0x80,0xff,0xf7,0xac,0xc3,0x00,0x00,0x84,0xa3,0x00,0x08,0x3c,0x02,0xb0,0x03, +0x34,0x42,0x00,0x30,0xac,0x43,0x00,0x00,0x27,0x92,0xba,0x40,0x24,0x11,0x00,0x12, +0x8e,0x44,0x00,0x00,0x26,0x31,0xff,0xff,0x90,0x82,0x00,0x10,0x00,0x00,0x00,0x00, +0x10,0x40,0x00,0x03,0x26,0x52,0x00,0x04,0x0c,0x00,0x1d,0x55,0x00,0x00,0x00,0x00, +0x06,0x21,0xff,0xf7,0x24,0x02,0xff,0xdf,0x02,0x02,0x80,0x24,0x3c,0x01,0xb0,0x03, +0x0c,0x00,0x18,0x18,0xac,0x30,0x00,0x00,0x08,0x00,0x17,0x60,0x00,0x00,0x00,0x00, +0x8f,0x85,0x96,0x20,0x08,0x00,0x17,0x76,0x00,0x00,0x00,0x00,0x24,0x02,0xff,0x95, +0x3c,0x03,0xb0,0x03,0x02,0x02,0x80,0x24,0x34,0x63,0x00,0x30,0x3c,0x01,0xb0,0x03, +0xac,0x30,0x00,0x00,0x0c,0x00,0x17,0xe1,0xac,0x60,0x00,0x00,0x08,0x00,0x17,0x60, +0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0x50,0x08,0x00,0x17,0x60, +0xac,0x46,0x00,0x00,0xaf,0xa7,0x00,0x0c,0xaf,0xa4,0x00,0x00,0xaf,0xa5,0x00,0x04, +0xaf,0xa6,0x00,0x08,0x27,0xbd,0xfe,0xe8,0x00,0x80,0x28,0x21,0x27,0xa6,0x01,0x1c, +0x27,0xa4,0x00,0x10,0xaf,0xbf,0x01,0x14,0x0c,0x00,0x29,0xa9,0xaf,0xb0,0x01,0x10, +0x00,0x40,0x80,0x21,0x0c,0x00,0x17,0xb0,0x27,0xa4,0x00,0x10,0x02,0x00,0x10,0x21, +0x8f,0xbf,0x01,0x14,0x8f,0xb0,0x01,0x10,0x03,0xe0,0x00,0x08,0x27,0xbd,0x01,0x18, +0x93,0x83,0x87,0xec,0x27,0xbd,0xff,0xe8,0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x14, +0x14,0x60,0x00,0x14,0x00,0x80,0x80,0x21,0x80,0x82,0x00,0x00,0x90,0x84,0x00,0x00, +0x14,0x40,0x00,0x05,0x00,0x00,0x00,0x00,0x8f,0xbf,0x00,0x14,0x8f,0xb0,0x00,0x10, +0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18,0x00,0x04,0x26,0x00,0x00,0x04,0x26,0x03, +0x30,0x84,0xff,0xff,0x0c,0x00,0x17,0xd0,0x26,0x10,0x00,0x01,0x92,0x03,0x00,0x00, +0x00,0x00,0x00,0x00,0x14,0x60,0xff,0xf8,0x00,0x60,0x20,0x21,0x08,0x00,0x17,0xba, +0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0x14,0x43,0xff,0xef,0x00,0x00,0x00,0x00, +0x0c,0x00,0x04,0x52,0x00,0x00,0x00,0x00,0x08,0x00,0x17,0xba,0x00,0x00,0x00,0x00, +0x30,0x84,0xff,0xff,0x48,0x84,0x00,0x00,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00, +0x27,0xbd,0xff,0xe8,0xaf,0xbf,0x00,0x10,0x0c,0x00,0x29,0x11,0x00,0x00,0x00,0x00, +0x8f,0xbf,0x00,0x10,0x00,0x02,0x14,0x00,0x00,0x02,0x14,0x03,0x03,0xe0,0x00,0x08, +0x27,0xbd,0x00,0x18,0x03,0xe0,0x00,0x08,0x24,0x02,0x00,0x01,0x03,0xe0,0x00,0x08, +0x24,0x02,0x00,0x01,0x3c,0x0a,0x80,0x00,0x25,0x4a,0x5f,0x84,0x3c,0x0b,0xb0,0x03, +0xad,0x6a,0x00,0x20,0x3c,0x08,0x80,0x01,0x25,0x08,0x00,0x00,0x3c,0x09,0x80,0x01, +0x25,0x29,0x0b,0x2c,0x11,0x09,0x00,0x10,0x00,0x00,0x00,0x00,0x3c,0x0a,0x80,0x00, +0x25,0x4a,0x5f,0xac,0x3c,0x0b,0xb0,0x03,0xad,0x6a,0x00,0x20,0x3c,0x08,0xb0,0x06, +0x35,0x08,0x80,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x8d,0x09,0x00,0x00, +0x00,0x00,0x00,0x00,0x31,0x29,0x00,0x01,0x00,0x00,0x00,0x00,0x24,0x01,0x00,0x01, +0x15,0x21,0xff,0xf2,0x00,0x00,0x00,0x00,0x3c,0x0a,0x80,0x00,0x25,0x4a,0x5f,0xe8, +0x3c,0x0b,0xb0,0x03,0xad,0x6a,0x00,0x20,0x3c,0x02,0xb0,0x03,0x8c,0x43,0x00,0x00, +0x00,0x00,0x00,0x00,0x34,0x63,0x00,0x40,0x00,0x00,0x00,0x00,0xac,0x43,0x00,0x00, +0x00,0x00,0x00,0x00,0x3c,0x0a,0x80,0x00,0x25,0x4a,0x60,0x14,0x3c,0x0b,0xb0,0x03, +0xad,0x6a,0x00,0x20,0x3c,0x02,0x80,0x01,0x24,0x42,0x00,0x00,0x3c,0x03,0x80,0x01, +0x24,0x63,0x0b,0x2c,0x3c,0x04,0xb0,0x00,0x8c,0x85,0x00,0x00,0x00,0x00,0x00,0x00, +0xac,0x45,0x00,0x00,0x24,0x42,0x00,0x04,0x24,0x84,0x00,0x04,0x00,0x43,0x08,0x2a, +0x14,0x20,0xff,0xf9,0x00,0x00,0x00,0x00,0x0c,0x00,0x18,0x18,0x00,0x00,0x00,0x00, +0x3c,0x0a,0x80,0x00,0x25,0x4a,0x60,0x60,0x3c,0x0b,0xb0,0x03,0xad,0x6a,0x00,0x20, +0x3c,0x02,0x80,0x01,0x24,0x42,0x0b,0x30,0x3c,0x03,0x80,0x01,0x24,0x63,0x42,0x50, +0xac,0x40,0x00,0x00,0xac,0x40,0x00,0x04,0xac,0x40,0x00,0x08,0xac,0x40,0x00,0x0c, +0x24,0x42,0x00,0x10,0x00,0x43,0x08,0x2a,0x14,0x20,0xff,0xf9,0x00,0x00,0x00,0x00, +0x3c,0x0a,0x80,0x00,0x25,0x4a,0x60,0xa0,0x3c,0x0b,0xb0,0x03,0xad,0x6a,0x00,0x20, +0x3c,0x1c,0x80,0x01,0x27,0x9c,0x7f,0xf0,0x27,0x9d,0x92,0x20,0x00,0x00,0x00,0x00, +0x27,0x9d,0x96,0x08,0x3c,0x0a,0x80,0x00,0x25,0x4a,0x60,0xc4,0x3c,0x0b,0xb0,0x03, +0xad,0x6a,0x00,0x20,0x40,0x80,0x68,0x00,0x40,0x08,0x60,0x00,0x00,0x00,0x00,0x00, +0x35,0x08,0xff,0x01,0x40,0x88,0x60,0x00,0x00,0x00,0x00,0x00,0x0c,0x00,0x1a,0x4d, +0x00,0x00,0x00,0x00,0x24,0x84,0xf8,0x00,0x30,0x87,0x00,0x03,0x00,0x04,0x30,0x40, +0x00,0xc7,0x20,0x23,0x3c,0x02,0xb0,0x0a,0x27,0xbd,0xff,0xe0,0x24,0x03,0xff,0xff, +0x00,0x82,0x20,0x21,0xaf,0xb1,0x00,0x14,0xac,0x83,0x10,0x00,0xaf,0xbf,0x00,0x18, +0xaf,0xb0,0x00,0x10,0x00,0xa0,0x88,0x21,0x24,0x03,0x00,0x01,0x8c,0x82,0x10,0x00, +0x00,0x00,0x00,0x00,0x14,0x43,0xff,0xfd,0x00,0xc7,0x10,0x23,0x3c,0x03,0xb0,0x0a, +0x00,0x43,0x10,0x21,0x8c,0x50,0x00,0x00,0x0c,0x00,0x18,0x95,0x02,0x20,0x20,0x21, +0x02,0x11,0x80,0x24,0x00,0x50,0x80,0x06,0x02,0x00,0x10,0x21,0x8f,0xbf,0x00,0x18, +0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20,0x27,0xbd,0xff,0xd8, +0xaf,0xb2,0x00,0x18,0x00,0xa0,0x90,0x21,0x24,0x05,0xff,0xff,0xaf,0xb3,0x00,0x1c, +0xaf,0xbf,0x00,0x20,0xaf,0xb1,0x00,0x14,0xaf,0xb0,0x00,0x10,0x00,0xc0,0x98,0x21, +0x12,0x45,0x00,0x23,0x24,0x84,0xf8,0x00,0x30,0x83,0x00,0x03,0x00,0x04,0x10,0x40, +0x00,0x40,0x88,0x21,0x00,0x60,0x20,0x21,0x00,0x43,0x10,0x23,0x3c,0x03,0xb0,0x0a, +0x00,0x43,0x10,0x21,0xac,0x45,0x10,0x00,0x00,0x40,0x18,0x21,0x24,0x05,0x00,0x01, +0x8c,0x62,0x10,0x00,0x00,0x00,0x00,0x00,0x14,0x45,0xff,0xfd,0x3c,0x02,0xb0,0x0a, +0x02,0x24,0x88,0x23,0x02,0x22,0x88,0x21,0x8e,0x30,0x00,0x00,0x0c,0x00,0x18,0x95, +0x02,0x40,0x20,0x21,0x00,0x12,0x18,0x27,0x02,0x03,0x80,0x24,0x00,0x53,0x10,0x04, +0x02,0x02,0x80,0x25,0xae,0x30,0x00,0x00,0x24,0x03,0x00,0x01,0x8e,0x22,0x10,0x00, +0x00,0x00,0x00,0x00,0x14,0x43,0xff,0xfd,0x00,0x00,0x00,0x00,0x8f,0xbf,0x00,0x20, +0x7b,0xb2,0x00,0xfc,0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x28, +0x30,0x82,0x00,0x03,0x00,0x04,0x18,0x40,0x00,0x62,0x18,0x23,0x3c,0x04,0xb0,0x0a, +0x00,0x64,0x18,0x21,0xac,0x66,0x00,0x00,0x24,0x04,0x00,0x01,0x8c,0x62,0x10,0x00, +0x00,0x00,0x00,0x00,0x14,0x44,0xff,0xfd,0x00,0x00,0x00,0x00,0x08,0x00,0x18,0x83, +0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x21,0x00,0x64,0x10,0x06,0x30,0x42,0x00,0x01, +0x14,0x40,0x00,0x05,0x00,0x00,0x00,0x00,0x24,0x63,0x00,0x01,0x2c,0x62,0x00,0x20, +0x14,0x40,0xff,0xf9,0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x00,0x60,0x10,0x21, +0x27,0xbd,0xff,0xe0,0x3c,0x03,0xb0,0x05,0xaf,0xb2,0x00,0x18,0xaf,0xb1,0x00,0x14, +0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x1c,0x00,0x80,0x80,0x21,0x00,0xa0,0x88,0x21, +0x00,0xc0,0x90,0x21,0x34,0x63,0x02,0x2e,0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00, +0x30,0x42,0x00,0x01,0x14,0x40,0xff,0xfc,0x24,0x04,0x08,0x24,0x3c,0x05,0x00,0xc0, +0x0c,0x00,0x18,0x5b,0x24,0x06,0x00,0x03,0x24,0x04,0x08,0x34,0x3c,0x05,0x00,0xc0, +0x0c,0x00,0x18,0x5b,0x24,0x06,0x00,0x03,0x82,0x02,0x00,0x13,0x00,0x11,0x24,0x00, +0x3c,0x03,0xc0,0x00,0x00,0x02,0x12,0x00,0x00,0x44,0x10,0x21,0x3c,0x04,0xb0,0x05, +0x24,0x42,0x00,0x09,0x34,0x84,0x04,0x20,0x34,0x63,0x04,0x00,0x3c,0x05,0xb0,0x05, +0x3c,0x06,0xb0,0x05,0xac,0x82,0x00,0x00,0x24,0x07,0x00,0x01,0x02,0x43,0x18,0x21, +0x34,0xa5,0x04,0x24,0x34,0xc6,0x02,0x28,0x24,0x02,0x00,0x20,0xac,0xa3,0x00,0x00, +0xae,0x07,0x00,0x3c,0xa0,0xc2,0x00,0x00,0xa2,0x07,0x00,0x11,0x3c,0x02,0xb0,0x05, +0x34,0x42,0x02,0x2e,0x90,0x43,0x00,0x00,0x24,0x04,0x08,0x24,0x3c,0x05,0x00,0xc0, +0x0c,0x00,0x18,0x5b,0x24,0x06,0x00,0x01,0x24,0x04,0x08,0x34,0x3c,0x05,0x00,0xc0, +0x0c,0x00,0x18,0x5b,0x24,0x06,0x00,0x01,0x8f,0xbf,0x00,0x1c,0x8f,0xb2,0x00,0x18, +0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20,0x24,0x02,0x00,0x06, +0xac,0x82,0x00,0x0c,0xa0,0x80,0x00,0x50,0xac,0x80,0x00,0x00,0xac,0x80,0x00,0x04, +0xac,0x80,0x00,0x08,0xac,0x80,0x00,0x14,0xac,0x80,0x00,0x18,0xac,0x80,0x00,0x1c, +0xa4,0x80,0x00,0x20,0xac,0x80,0x00,0x24,0xac,0x80,0x00,0x28,0xac,0x80,0x00,0x2c, +0xa0,0x80,0x00,0x30,0xa0,0x80,0x00,0x31,0xac,0x80,0x00,0x34,0xac,0x80,0x00,0x38, +0xa0,0x80,0x00,0x3c,0xac,0x82,0x00,0x10,0xa0,0x80,0x00,0x44,0xac,0x80,0x00,0x48, +0x03,0xe0,0x00,0x08,0xac,0x80,0x00,0x4c,0x3c,0x04,0xb0,0x06,0x34,0x84,0x80,0x00, +0x8c,0x83,0x00,0x00,0x3c,0x02,0x12,0x00,0x3c,0x05,0xb0,0x03,0x00,0x62,0x18,0x25, +0x34,0xa5,0x00,0x8b,0x24,0x02,0xff,0x80,0xac,0x83,0x00,0x00,0x03,0xe0,0x00,0x08, +0xa0,0xa2,0x00,0x00,0x3c,0x04,0xb0,0x03,0x34,0x84,0x00,0x0b,0x24,0x02,0x00,0x22, +0x3c,0x05,0xb0,0x01,0x3c,0x06,0x45,0x67,0x3c,0x0a,0xb0,0x09,0xa0,0x82,0x00,0x00, +0x34,0xa5,0x00,0x04,0x34,0xc6,0x89,0xaa,0x35,0x4a,0x00,0x04,0x24,0x02,0x01,0x23, +0x3c,0x0b,0xb0,0x09,0x3c,0x07,0x01,0x23,0x3c,0x0c,0xb0,0x09,0x3c,0x01,0xb0,0x01, +0xac,0x20,0x00,0x00,0x27,0xbd,0xff,0xe0,0xac,0xa0,0x00,0x00,0x35,0x6b,0x00,0x08, +0x3c,0x01,0xb0,0x09,0xac,0x26,0x00,0x00,0x34,0xe7,0x45,0x66,0xa5,0x42,0x00,0x00, +0x35,0x8c,0x00,0x0c,0x24,0x02,0xcd,0xef,0x3c,0x0d,0xb0,0x09,0x3c,0x08,0xcd,0xef, +0x3c,0x0e,0xb0,0x09,0xad,0x67,0x00,0x00,0xaf,0xb7,0x00,0x1c,0xa5,0x82,0x00,0x00, +0xaf,0xb6,0x00,0x18,0xaf,0xb5,0x00,0x14,0xaf,0xb4,0x00,0x10,0xaf,0xb3,0x00,0x0c, +0xaf,0xb2,0x00,0x08,0xaf,0xb1,0x00,0x04,0xaf,0xb0,0x00,0x00,0x35,0xad,0x00,0x10, +0x35,0x08,0x01,0x22,0x35,0xce,0x00,0x14,0x24,0x02,0x89,0xab,0x3c,0x0f,0xb0,0x09, +0x3c,0x09,0x89,0xab,0x3c,0x10,0xb0,0x09,0x3c,0x11,0xb0,0x09,0x3c,0x12,0xb0,0x09, +0x3c,0x13,0xb0,0x09,0x3c,0x14,0xb0,0x09,0x3c,0x15,0xb0,0x09,0x3c,0x16,0xb0,0x09, +0x3c,0x17,0xb0,0x09,0xad,0xa8,0x00,0x00,0x24,0x03,0xff,0xff,0xa5,0xc2,0x00,0x00, +0x35,0xef,0x00,0x18,0x35,0x29,0xcd,0xee,0x36,0x10,0x00,0x1c,0x36,0x31,0x00,0x20, +0x36,0x52,0x00,0x24,0x36,0x73,0x00,0x28,0x36,0x94,0x00,0x2c,0x36,0xb5,0x00,0x30, +0x36,0xd6,0x00,0x34,0x36,0xf7,0x00,0x38,0x24,0x02,0x45,0x67,0xad,0xe9,0x00,0x00, +0xa6,0x02,0x00,0x00,0xae,0x23,0x00,0x00,0x8f,0xb0,0x00,0x00,0xa6,0x43,0x00,0x00, +0x8f,0xb1,0x00,0x04,0xae,0x63,0x00,0x00,0x8f,0xb2,0x00,0x08,0xa6,0x83,0x00,0x00, +0x8f,0xb3,0x00,0x0c,0xae,0xa3,0x00,0x00,0x8f,0xb4,0x00,0x10,0xa6,0xc3,0x00,0x00, +0x8f,0xb5,0x00,0x14,0xae,0xe3,0x00,0x00,0x7b,0xb6,0x00,0xfc,0x3c,0x18,0xb0,0x09, +0x37,0x18,0x00,0x3c,0xa7,0x03,0x00,0x00,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20, +0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x34,0x63,0x00,0x20,0x24,0x42,0x65,0x50, +0xac,0x62,0x00,0x00,0x8c,0x83,0x00,0x34,0x34,0x02,0xff,0xff,0x00,0x43,0x10,0x2a, +0x14,0x40,0x00,0xed,0x00,0x80,0x28,0x21,0x8c,0x84,0x00,0x08,0x24,0x02,0x00,0x03, +0x10,0x82,0x00,0xe0,0x00,0x00,0x00,0x00,0x8c,0xa2,0x00,0x2c,0x00,0x00,0x00,0x00, +0x14,0x40,0x00,0x38,0x24,0x02,0x00,0x06,0x3c,0x03,0xb0,0x05,0x34,0x63,0x04,0x50, +0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xff,0x14,0x40,0x00,0xc6, +0xac,0xa2,0x00,0x2c,0x24,0x02,0x00,0x01,0x10,0x82,0x00,0xc5,0x00,0x00,0x00,0x00, +0x24,0x02,0x00,0x02,0x10,0x82,0x00,0xb3,0x00,0x00,0x00,0x00,0x8c,0xa6,0x00,0x04, +0x24,0x02,0x00,0x02,0x10,0xc2,0x00,0xa9,0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x03, +0x34,0x42,0x00,0xd0,0x8c,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x61,0x00,0x16, +0x3c,0x03,0xb0,0x05,0x34,0x63,0x02,0x2e,0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00, +0x30,0x42,0x00,0x01,0x14,0x40,0x00,0x10,0x3c,0x02,0xb0,0x05,0x34,0x42,0x02,0x42, +0x90,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x60,0x00,0x0b,0x00,0x00,0x00,0x00, +0x80,0xa2,0x00,0x50,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x07,0x00,0x00,0x00,0x00, +0x14,0x80,0x00,0x05,0x24,0x02,0x00,0x0e,0x24,0x03,0x00,0x01,0xac,0xa2,0x00,0x00, +0x03,0xe0,0x00,0x08,0xa0,0xa3,0x00,0x50,0x80,0xa2,0x00,0x31,0x00,0x00,0x00,0x00, +0x10,0x40,0x00,0x0a,0x3c,0x02,0xb0,0x06,0x34,0x42,0x80,0x18,0x8c,0x43,0x00,0x00, +0x3c,0x04,0xf0,0x00,0x3c,0x02,0x80,0x00,0x00,0x64,0x18,0x24,0x10,0x62,0x00,0x03, +0x24,0x02,0x00,0x09,0x03,0xe0,0x00,0x08,0xac,0xa2,0x00,0x00,0x8c,0xa2,0x00,0x40, +0x00,0x00,0x00,0x00,0x8c,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x60,0x00,0x09, +0x3c,0x03,0xb0,0x03,0x3c,0x02,0xb0,0x05,0x34,0x42,0x02,0x2c,0x8c,0x43,0x00,0x00, +0x3c,0x04,0x00,0x02,0x00,0x64,0x18,0x24,0x14,0x60,0xff,0xf2,0x24,0x02,0x00,0x10, +0x3c,0x03,0xb0,0x03,0x34,0x63,0x02,0x01,0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00, +0x30,0x42,0x00,0x80,0x10,0x40,0x00,0x0e,0x00,0x00,0x00,0x00,0x8c,0xa3,0x00,0x0c, +0x00,0x00,0x00,0x00,0xac,0xa3,0x00,0x10,0x3c,0x02,0xb0,0x03,0x90,0x42,0x02,0x01, +0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x0f,0xac,0xa2,0x00,0x0c,0x90,0xa3,0x00,0x0f, +0x24,0x02,0x00,0x0d,0x3c,0x01,0xb0,0x03,0x08,0x00,0x19,0x9d,0xa0,0x23,0x02,0x01, +0x3c,0x02,0xb0,0x09,0x34,0x42,0x01,0x80,0x90,0x44,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x04,0x1e,0x00,0x00,0x03,0x1e,0x03,0x10,0x60,0x00,0x15,0xa0,0xa4,0x00,0x44, +0x24,0x02,0x00,0x01,0x10,0x62,0x00,0x0b,0x24,0x02,0x00,0x02,0x10,0x62,0x00,0x03, +0x24,0x03,0x00,0x0d,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x8c,0xa2,0x00,0x0c, +0xac,0xa3,0x00,0x00,0x24,0x03,0x00,0x04,0xac,0xa2,0x00,0x10,0x03,0xe0,0x00,0x08, +0xac,0xa3,0x00,0x0c,0x24,0x02,0x00,0x0d,0xac,0xa2,0x00,0x00,0x24,0x03,0x00,0x04, +0x24,0x02,0x00,0x06,0xac,0xa3,0x00,0x10,0x03,0xe0,0x00,0x08,0xac,0xa2,0x00,0x0c, +0x8c,0xa2,0x00,0x14,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x09,0x24,0x02,0x00,0x01, +0x3c,0x03,0xb0,0x09,0x34,0x63,0x01,0x60,0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00, +0x30,0x42,0x00,0xff,0x10,0x40,0x00,0x05,0xac,0xa2,0x00,0x14,0x24,0x02,0x00,0x01, +0xac,0xa2,0x00,0x00,0x03,0xe0,0x00,0x08,0xac,0xa0,0x00,0x14,0x8c,0xa3,0x00,0x38, +0x24,0x04,0x00,0x01,0x10,0x64,0x00,0x2d,0x24,0x02,0x00,0x02,0x10,0x60,0x00,0x19, +0x00,0x00,0x00,0x00,0x10,0x62,0x00,0x10,0x24,0x02,0x00,0x04,0x10,0x62,0x00,0x04, +0x00,0x00,0x00,0x00,0xac,0xa0,0x00,0x38,0x03,0xe0,0x00,0x08,0xac,0xa0,0x00,0x00, +0x10,0xc4,0x00,0x07,0x24,0x02,0x00,0x03,0x80,0xa2,0x00,0x30,0x00,0x00,0x00,0x00, +0x00,0x02,0x18,0x0b,0xac,0xa3,0x00,0x00,0x03,0xe0,0x00,0x08,0xac,0xa0,0x00,0x38, +0x08,0x00,0x19,0xfe,0xac,0xa2,0x00,0x00,0x10,0xc4,0x00,0x02,0x24,0x02,0x00,0x03, +0x24,0x02,0x00,0x0c,0xac,0xa2,0x00,0x00,0x24,0x02,0x00,0x04,0x03,0xe0,0x00,0x08, +0xac,0xa2,0x00,0x38,0x10,0xc4,0x00,0x0e,0x3c,0x03,0xb0,0x06,0x34,0x63,0x80,0x24, +0x8c,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xff,0x10,0x40,0x00,0x06, +0xac,0xa2,0x00,0x18,0x24,0x02,0x00,0x02,0xac,0xa2,0x00,0x00,0xac,0xa0,0x00,0x18, +0x08,0x00,0x1a,0x07,0x24,0x02,0x00,0x01,0x08,0x00,0x1a,0x14,0xac,0xa0,0x00,0x00, +0x24,0x02,0x00,0x03,0x08,0x00,0x1a,0x14,0xac,0xa2,0x00,0x00,0x24,0x03,0x00,0x0b, +0xac,0xa2,0x00,0x38,0x03,0xe0,0x00,0x08,0xac,0xa3,0x00,0x00,0x80,0xa2,0x00,0x30, +0x00,0x00,0x00,0x00,0x14,0x40,0xff,0x55,0x24,0x02,0x00,0x04,0x08,0x00,0x19,0x9d, +0x00,0x00,0x00,0x00,0x84,0xa2,0x00,0x20,0x00,0x00,0x00,0x00,0x10,0x40,0xff,0x75, +0x24,0x02,0x00,0x06,0x3c,0x02,0xb0,0x05,0x34,0x42,0x02,0x2e,0x90,0x43,0x00,0x00, +0x00,0x00,0x00,0x00,0x30,0x63,0x00,0x01,0x30,0x63,0x00,0xff,0x00,0x60,0x10,0x21, +0x14,0x40,0xff,0x42,0xa4,0xa3,0x00,0x20,0x08,0x00,0x19,0x9d,0x24,0x02,0x00,0x06, +0x8c,0xa2,0x00,0x1c,0x00,0x00,0x00,0x00,0x14,0x40,0xff,0x66,0x24,0x02,0x00,0x05, +0x3c,0x03,0xb0,0x05,0x34,0x63,0x02,0x2c,0x8c,0x62,0x00,0x00,0x00,0x00,0x00,0x00, +0x30,0x42,0x00,0xff,0x10,0x40,0xff,0x32,0xac,0xa2,0x00,0x1c,0x08,0x00,0x19,0x9d, +0x24,0x02,0x00,0x05,0x3c,0x02,0xb0,0x05,0x8c,0x42,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x02,0x17,0x42,0x30,0x42,0x00,0x01,0x14,0x40,0xff,0x56,0x24,0x02,0x00,0x06, +0x08,0x00,0x19,0x62,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x0a,0x03,0xe0,0x00,0x08, +0xac,0x82,0x00,0x00,0x27,0xbd,0xff,0xd8,0xaf,0xb1,0x00,0x14,0xaf,0xb0,0x00,0x10, +0x27,0x91,0x90,0xf8,0x27,0x90,0x8e,0x38,0xaf,0xbf,0x00,0x20,0xaf,0xb3,0x00,0x1c, +0x0c,0x00,0x28,0x9e,0xaf,0xb2,0x00,0x18,0x0c,0x00,0x06,0x90,0x00,0x00,0x00,0x00, +0xaf,0x91,0x92,0x10,0xaf,0x90,0x96,0x20,0x48,0x02,0x00,0x00,0x0c,0x00,0x18,0xf2, +0x00,0x00,0x00,0x00,0x0c,0x00,0x1c,0x9b,0x02,0x00,0x20,0x21,0x3c,0x02,0xb0,0x03, +0x34,0x42,0x00,0x3a,0x94,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0xa3,0x83,0x96,0x24, +0x0c,0x00,0x00,0x34,0x00,0x00,0x00,0x00,0x0c,0x00,0x18,0xfd,0x00,0x00,0x00,0x00, +0x27,0x84,0x8c,0x78,0x0c,0x00,0x2c,0x78,0x00,0x00,0x00,0x00,0x0c,0x00,0x25,0x71, +0x00,0x00,0x00,0x00,0x0c,0x00,0x0c,0x0d,0x02,0x20,0x20,0x21,0x0c,0x00,0x01,0x39, +0x00,0x00,0x00,0x00,0x27,0x84,0x8c,0x20,0x0c,0x00,0x18,0xdb,0x00,0x00,0x00,0x00, +0x27,0x82,0x91,0x2c,0xaf,0x82,0x8c,0x60,0x0c,0x00,0x00,0x5f,0x00,0x00,0x00,0x00, +0x3c,0x03,0xb0,0x03,0x34,0x63,0x01,0x08,0x3c,0x04,0xb0,0x09,0x3c,0x05,0xb0,0x09, +0x8c,0x66,0x00,0x00,0x34,0x84,0x01,0x68,0x24,0x02,0xd1,0x10,0x34,0xa5,0x01,0x40, +0x24,0x03,0x00,0x0a,0xa4,0x82,0x00,0x00,0xa4,0xa3,0x00,0x00,0x3c,0x04,0xb0,0x03, +0x8c,0x82,0x00,0x00,0xaf,0x86,0x8c,0x18,0x34,0x42,0x00,0x20,0xac,0x82,0x00,0x00, +0x0c,0x00,0x06,0xa1,0x00,0x00,0x00,0x00,0x3c,0x04,0xb0,0x05,0x0c,0x00,0x28,0xb6, +0x34,0x84,0x00,0x04,0x8f,0x83,0x8c,0x20,0x00,0x00,0x00,0x00,0x2c,0x62,0x00,0x11, +0x10,0x40,0xff,0xf7,0x00,0x03,0x10,0x80,0x3c,0x03,0x80,0x01,0x24,0x63,0x09,0x08, +0x00,0x43,0x10,0x21,0x8c,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x08, +0x00,0x00,0x00,0x00,0x27,0x84,0x8c,0x20,0x0c,0x00,0x19,0x54,0x00,0x00,0x00,0x00, +0x8f,0x82,0x8c,0x54,0x00,0x00,0x00,0x00,0x24,0x42,0x00,0x01,0xaf,0x82,0x8c,0x54, +0x08,0x00,0x1a,0x88,0x00,0x00,0x00,0x00,0x27,0x84,0x8c,0x78,0x0c,0x00,0x2d,0xe5, +0x00,0x00,0x00,0x00,0xa3,0x82,0x8c,0x51,0xaf,0x80,0x8c,0x20,0x08,0x00,0x1a,0x9c, +0x00,0x00,0x00,0x00,0x27,0x84,0x8e,0x38,0x0c,0x00,0x1d,0xe0,0x00,0x00,0x00,0x00, +0x30,0x42,0x00,0xff,0x14,0x40,0x00,0x05,0x3c,0x03,0xb0,0x05,0xaf,0x80,0x8c,0x20, +0xaf,0x80,0x8c,0x24,0x08,0x00,0x1a,0x9c,0x00,0x00,0x00,0x00,0x34,0x63,0x04,0x50, +0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xff,0xaf,0x82,0x8c,0x4c, +0x14,0x40,0x00,0x1e,0x24,0x02,0x00,0x01,0x8f,0x84,0x8c,0x28,0x00,0x00,0x00,0x00, +0x10,0x82,0x00,0x1d,0x3c,0x03,0xb0,0x09,0x34,0x63,0x01,0x60,0x90,0x62,0x00,0x00, +0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xff,0xaf,0x82,0x8c,0x34,0x14,0x40,0x00,0x13, +0x24,0x02,0x00,0x01,0x24,0x02,0x00,0x02,0x10,0x82,0x00,0x07,0x3c,0x02,0xb0,0x05, +0x24,0x02,0x00,0x01,0x24,0x03,0x00,0x03,0xaf,0x82,0x8c,0x24,0xaf,0x83,0x8c,0x20, +0x08,0x00,0x1a,0x9c,0x00,0x00,0x00,0x00,0x34,0x42,0x02,0x2e,0x90,0x43,0x00,0x00, +0x00,0x00,0x00,0x00,0x30,0x63,0x00,0x01,0x30,0x63,0x00,0xff,0x00,0x60,0x10,0x21, +0xa7,0x83,0x8c,0x40,0x14,0x40,0xff,0xf3,0x24,0x02,0x00,0x01,0xaf,0x82,0x8c,0x24, +0x08,0x00,0x1a,0xa6,0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x05,0x34,0x63,0x02,0x2c, +0x8c,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xff,0xaf,0x82,0x8c,0x3c, +0x14,0x40,0xff,0xf6,0x24,0x02,0x00,0x01,0x08,0x00,0x1a,0xbe,0x3c,0x03,0xb0,0x09, +0x27,0x84,0x8e,0x38,0x0c,0x00,0x1f,0x44,0x00,0x00,0x00,0x00,0x83,0x82,0x8c,0x50, +0x00,0x00,0x00,0x00,0x14,0x40,0xff,0xed,0x24,0x02,0x00,0x02,0x3c,0x03,0xb0,0x05, +0x34,0x63,0x04,0x50,0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xff, +0xaf,0x82,0x8c,0x4c,0x14,0x40,0xff,0xe5,0x24,0x02,0x00,0x02,0x8f,0x84,0x8c,0x28, +0x24,0x02,0x00,0x01,0x10,0x82,0x00,0x12,0x24,0x02,0x00,0x02,0x10,0x82,0x00,0x05, +0x3c,0x02,0xb0,0x05,0x24,0x02,0x00,0x02,0xaf,0x82,0x8c,0x24,0x08,0x00,0x1a,0xcb, +0x24,0x03,0x00,0x04,0x34,0x42,0x02,0x2e,0x90,0x43,0x00,0x00,0x00,0x00,0x00,0x00, +0x30,0x63,0x00,0x01,0x30,0x63,0x00,0xff,0x00,0x60,0x10,0x21,0xa7,0x83,0x8c,0x40, +0x14,0x40,0xff,0xf4,0x00,0x00,0x00,0x00,0x08,0x00,0x1a,0xd7,0x24,0x02,0x00,0x02, +0x3c,0x03,0xb0,0x05,0x34,0x63,0x02,0x2c,0x8c,0x62,0x00,0x00,0x00,0x00,0x00,0x00, +0x30,0x42,0x00,0xff,0xaf,0x82,0x8c,0x3c,0x14,0x40,0xff,0xf7,0x00,0x00,0x00,0x00, +0x08,0x00,0x1a,0xf7,0x24,0x02,0x00,0x02,0x27,0x84,0x90,0xf8,0x0c,0x00,0x10,0x1b, +0x00,0x00,0x00,0x00,0x8f,0x83,0x8c,0x24,0xaf,0x82,0x8c,0x3c,0x38,0x64,0x00,0x02, +0x00,0x04,0x18,0x0a,0xaf,0x83,0x8c,0x24,0x14,0x40,0x00,0x08,0x24,0x02,0x00,0x05, +0x8f,0x82,0x91,0x38,0xaf,0x80,0x8c,0x20,0x10,0x40,0xff,0x7d,0x24,0x04,0x00,0x01, +0xaf,0x84,0x8c,0x28,0x08,0x00,0x1a,0x9c,0x00,0x00,0x00,0x00,0xaf,0x82,0x8c,0x20, +0x08,0x00,0x1a,0x9c,0x00,0x00,0x00,0x00,0x83,0x82,0x8c,0x70,0x00,0x00,0x00,0x00, +0x10,0x40,0x00,0x02,0x24,0x02,0x00,0x20,0xaf,0x82,0x8c,0x3c,0x8f,0x85,0x8c,0x3c, +0x27,0x84,0x90,0xf8,0x0c,0x00,0x12,0x01,0x00,0x00,0x00,0x00,0x00,0x02,0x1e,0x00, +0xa3,0x82,0x8c,0x50,0xaf,0x80,0x8c,0x3c,0x10,0x60,0xff,0x73,0x3c,0x02,0xb0,0x05, +0x34,0x42,0x02,0x2e,0x90,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x63,0x00,0x01, +0x30,0x63,0x00,0xff,0x00,0x60,0x10,0x21,0xa7,0x83,0x8c,0x40,0x10,0x40,0xff,0xe7, +0x24,0x02,0x00,0x06,0x24,0x04,0x00,0x02,0xaf,0x84,0x8c,0x28,0x08,0x00,0x1a,0xa6, +0x00,0x00,0x00,0x00,0x27,0x84,0x8c,0x20,0x27,0x85,0x90,0xf8,0x0c,0x00,0x12,0xc7, +0x00,0x00,0x00,0x00,0x8f,0x82,0x8c,0x44,0xaf,0x80,0x8c,0x4c,0x14,0x40,0x00,0x18, +0x00,0x40,0x18,0x21,0x8f,0x82,0x8c,0x48,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x14, +0x24,0x02,0x00,0x02,0x8f,0x83,0x8c,0x28,0x00,0x00,0x00,0x00,0x10,0x62,0x00,0x09, +0x24,0x02,0x00,0x01,0x8f,0x83,0x8c,0x24,0x00,0x00,0x00,0x00,0x10,0x62,0x00,0x02, +0x24,0x02,0x00,0x03,0x24,0x02,0x00,0x06,0xaf,0x82,0x8c,0x20,0x08,0x00,0x1b,0x20, +0x24,0x04,0x00,0x03,0x3c,0x02,0x40,0x00,0x34,0x42,0x00,0x14,0x3c,0x01,0xb0,0x05, +0xac,0x22,0x00,0x00,0xaf,0x80,0x8c,0x20,0x08,0x00,0x1b,0x20,0x24,0x04,0x00,0x03, +0x10,0x60,0x00,0x10,0x00,0x00,0x00,0x00,0x27,0x84,0x8c,0x20,0x27,0x85,0x90,0xf8, +0x0c,0x00,0x12,0xeb,0x00,0x00,0x00,0x00,0x8f,0x83,0x8c,0x24,0x24,0x02,0x00,0x01, +0xa3,0x80,0x8c,0x50,0xaf,0x80,0x8c,0x28,0x10,0x62,0x00,0x02,0x24,0x02,0x00,0x03, +0x24,0x02,0x00,0x04,0xaf,0x82,0x8c,0x20,0xaf,0x80,0x8c,0x44,0x08,0x00,0x1a,0x9c, +0x00,0x00,0x00,0x00,0x83,0x82,0x8c,0x70,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x04, +0x00,0x00,0x00,0x00,0x27,0x84,0x90,0xf8,0x0c,0x00,0x15,0x32,0x00,0x00,0x00,0x00, +0x8f,0x82,0x8c,0x24,0xa3,0x80,0x8c,0x50,0xaf,0x80,0x8c,0x20,0xaf,0x80,0x8c,0x28, +0x14,0x40,0x00,0x02,0x24,0x02,0x00,0x02,0xaf,0x82,0x8c,0x24,0xaf,0x80,0x8c,0x48, +0x08,0x00,0x1a,0x9c,0x00,0x00,0x00,0x00,0x27,0x84,0x8c,0x20,0x27,0x85,0x90,0xf8, +0x0c,0x00,0x12,0xeb,0x00,0x00,0x00,0x00,0x8f,0x82,0x8c,0x24,0xa3,0x80,0x8c,0x50, +0xaf,0x80,0x8c,0x20,0xaf,0x80,0x8c,0x28,0x14,0x40,0xff,0x11,0x24,0x02,0x00,0x02, +0xaf,0x82,0x8c,0x24,0x08,0x00,0x1a,0x9c,0x00,0x00,0x00,0x00,0x27,0x84,0x90,0xf8, +0x0c,0x00,0x15,0x32,0x00,0x00,0x00,0x00,0x08,0x00,0x1b,0x86,0x00,0x00,0x00,0x00, +0x27,0x84,0x8c,0x78,0x0c,0x00,0x2e,0x70,0x00,0x00,0x00,0x00,0x08,0x00,0x1a,0xa5, +0x00,0x00,0x00,0x00,0x0c,0x00,0x27,0x0a,0x00,0x00,0x00,0x00,0x93,0x82,0x92,0x14, +0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x2b,0x3c,0x02,0xb0,0x03,0x34,0x42,0x01,0x08, +0x8c,0x44,0x00,0x00,0x8f,0x83,0xc2,0x50,0x8f,0x82,0xc2,0x54,0x00,0x83,0x18,0x23, +0x00,0x43,0x10,0x2b,0x10,0x40,0x00,0x23,0x3c,0x02,0xb0,0x03,0x24,0x04,0x05,0xa0, +0x34,0x42,0x01,0x18,0x8c,0x42,0x00,0x00,0x0c,0x00,0x0b,0xfa,0x00,0x00,0x00,0x00, +0x24,0x04,0x05,0xa4,0x0c,0x00,0x0b,0xfa,0x00,0x02,0x84,0x02,0x30,0x51,0xff,0xff, +0x24,0x04,0x05,0xa8,0x00,0x02,0x94,0x02,0x0c,0x00,0x0b,0xfa,0x3a,0x10,0xff,0xff, +0x3a,0x31,0xff,0xff,0x30,0x42,0xff,0xff,0x2e,0x10,0x00,0x01,0x2e,0x31,0x00,0x01, +0x3a,0x52,0xff,0xff,0x02,0x11,0x80,0x25,0x2e,0x52,0x00,0x01,0x38,0x42,0xff,0xff, +0x02,0x12,0x80,0x25,0x2c,0x42,0x00,0x01,0x02,0x02,0x80,0x25,0x16,0x00,0x00,0x02, +0x24,0x04,0x00,0x02,0x00,0x00,0x20,0x21,0x0c,0x00,0x0a,0x9c,0x00,0x00,0x00,0x00, +0x3c,0x02,0xb0,0x03,0x34,0x42,0x01,0x08,0x8c,0x43,0x00,0x00,0x00,0x00,0x00,0x00, +0xaf,0x83,0xc2,0x50,0x0c,0x00,0x01,0xcb,0x00,0x00,0x00,0x00,0xaf,0x80,0x8c,0x20, +0xaf,0x80,0x8c,0x54,0x08,0x00,0x1a,0x88,0x00,0x00,0x00,0x00,0x27,0x90,0xba,0x40, +0x24,0x11,0x00,0x12,0x8e,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x90,0x82,0x00,0x10, +0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x03,0x00,0x00,0x00,0x00,0x0c,0x00,0x1d,0x55, +0x00,0x00,0x00,0x00,0x26,0x31,0xff,0xff,0x06,0x21,0xff,0xf6,0x26,0x10,0x00,0x04, +0x08,0x00,0x1a,0xa6,0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x03,0x34,0x42,0x01,0x08, +0x8c,0x44,0x00,0x00,0x8f,0x82,0x8c,0x18,0x00,0x04,0x19,0xc2,0x00,0x02,0x11,0xc2, +0x10,0x62,0xfe,0xc1,0x3c,0x02,0xb0,0x03,0x34,0x42,0x01,0x02,0x90,0x43,0x00,0x00, +0x3c,0x12,0xb0,0x05,0xaf,0x84,0x8c,0x18,0x30,0x63,0x00,0xff,0x00,0x03,0x11,0x40, +0x00,0x43,0x10,0x23,0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21,0x00,0x02,0x99,0x00, +0x00,0x00,0x88,0x21,0x36,0x52,0x02,0x2c,0x27,0x90,0xba,0x40,0x8e,0x04,0x00,0x00, +0x00,0x00,0x00,0x00,0x90,0x83,0x00,0x16,0x00,0x00,0x00,0x00,0x30,0x62,0x00,0x03, +0x10,0x40,0x00,0x06,0x30,0x62,0x00,0x1c,0x14,0x40,0x00,0x04,0x00,0x00,0x00,0x00, +0x8f,0x85,0x8c,0x18,0x0c,0x00,0x22,0xc6,0x02,0x60,0x30,0x21,0x8e,0x42,0x00,0x00, +0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xff,0x14,0x40,0xfe,0xa3,0x00,0x00,0x00,0x00, +0x26,0x31,0x00,0x01,0x2a,0x22,0x00,0x13,0x14,0x40,0xff,0xec,0x26,0x10,0x00,0x04, +0x08,0x00,0x1a,0xa6,0x00,0x00,0x00,0x00,0x8f,0x84,0x8c,0x2c,0x27,0x85,0x90,0xf8, +0x0c,0x00,0x1c,0x2e,0x00,0x00,0x00,0x00,0x8f,0x83,0x8c,0x2c,0x24,0x02,0x00,0x04, +0x14,0x62,0xfe,0x95,0x24,0x02,0x00,0x05,0x08,0x00,0x1b,0x23,0x00,0x00,0x00,0x00, +0x27,0x84,0x90,0xf8,0x0c,0x00,0x27,0x2e,0x00,0x00,0x00,0x00,0x08,0x00,0x1a,0xcb, +0x24,0x03,0x00,0x05,0x8f,0x82,0x91,0x2c,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x0d, +0x00,0x00,0x00,0x00,0x8f,0x84,0xba,0x80,0xaf,0x80,0x91,0x2c,0x94,0x85,0x00,0x14, +0x0c,0x00,0x1f,0xdd,0x00,0x00,0x00,0x00,0x93,0x82,0x91,0x51,0x00,0x00,0x00,0x00, +0x30,0x42,0x00,0x02,0x10,0x40,0x00,0x03,0x00,0x00,0x00,0x00,0x0c,0x00,0x01,0x60, +0x00,0x00,0x20,0x21,0x8f,0x84,0xba,0x80,0x0c,0x00,0x1d,0x55,0x00,0x00,0x00,0x00, +0x08,0x00,0x1a,0xa6,0x00,0x00,0x00,0x00,0x27,0xbd,0xff,0xe0,0x3c,0x06,0xb0,0x03, +0xaf,0xb1,0x00,0x14,0xaf,0xb0,0x00,0x10,0x34,0xc6,0x00,0x5f,0xaf,0xbf,0x00,0x18, +0x90,0xc3,0x00,0x00,0x3c,0x07,0xb0,0x03,0x34,0xe7,0x00,0x5d,0x34,0x63,0x00,0x01, +0x3c,0x09,0xb0,0x03,0x24,0x02,0x00,0x01,0xa0,0xc3,0x00,0x00,0x00,0x80,0x80,0x21, +0xa0,0xe2,0x00,0x00,0x00,0xa0,0x88,0x21,0x35,0x29,0x00,0x5e,0x00,0xe0,0x40,0x21, +0x24,0x04,0x00,0x01,0x91,0x22,0x00,0x00,0x91,0x03,0x00,0x00,0x30,0x42,0x00,0x01, +0x14,0x83,0x00,0x03,0x30,0x42,0x00,0x01,0x14,0x40,0xff,0xfa,0x00,0x00,0x00,0x00, +0x24,0x02,0x00,0x04,0x12,0x02,0x00,0x2c,0x24,0x05,0x0f,0x00,0x24,0x02,0x00,0x06, +0x12,0x02,0x00,0x08,0x24,0x05,0x00,0x0f,0x3c,0x02,0xb0,0x03,0x34,0x42,0x02,0x00, +0xa0,0x50,0x00,0x00,0x8f,0xbf,0x00,0x18,0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08, +0x27,0xbd,0x00,0x20,0x24,0x04,0x0c,0x04,0x0c,0x00,0x18,0x5b,0x24,0x06,0x00,0x0f, +0x24,0x04,0x0d,0x04,0x24,0x05,0x00,0x0f,0x0c,0x00,0x18,0x5b,0x24,0x06,0x00,0x0f, +0x24,0x04,0x08,0x80,0x24,0x05,0x1e,0x00,0x0c,0x00,0x18,0x5b,0x24,0x06,0x00,0x0f, +0x24,0x04,0x08,0x8c,0x24,0x05,0x0f,0x00,0x0c,0x00,0x18,0x5b,0x24,0x06,0x00,0x0f, +0x24,0x04,0x08,0x24,0x3c,0x05,0x00,0x30,0x0c,0x00,0x18,0x5b,0x24,0x06,0x00,0x02, +0x24,0x04,0x08,0x2c,0x3c,0x05,0x00,0x30,0x0c,0x00,0x18,0x5b,0x24,0x06,0x00,0x02, +0x24,0x04,0x08,0x34,0x3c,0x05,0x00,0x30,0x0c,0x00,0x18,0x5b,0x24,0x06,0x00,0x02, +0x24,0x04,0x08,0x3c,0x3c,0x05,0x00,0x30,0x0c,0x00,0x18,0x5b,0x24,0x06,0x00,0x02, +0x08,0x00,0x1c,0x4f,0x3c,0x02,0xb0,0x03,0x24,0x04,0x08,0x8c,0x0c,0x00,0x18,0x5b, +0x24,0x06,0x00,0x04,0x24,0x04,0x08,0x80,0x24,0x05,0x1e,0x00,0x0c,0x00,0x18,0x5b, +0x24,0x06,0x00,0x04,0x24,0x04,0x0c,0x04,0x24,0x05,0x00,0x0f,0x0c,0x00,0x18,0x5b, +0x24,0x06,0x00,0x04,0x24,0x04,0x0d,0x04,0x24,0x05,0x00,0x0f,0x0c,0x00,0x18,0x5b, +0x24,0x06,0x00,0x04,0x24,0x04,0x08,0x24,0x3c,0x05,0x00,0x30,0x0c,0x00,0x18,0x5b, +0x24,0x06,0x00,0x03,0x24,0x04,0x08,0x2c,0x3c,0x05,0x00,0x30,0x0c,0x00,0x18,0x5b, +0x24,0x06,0x00,0x03,0x24,0x04,0x08,0x34,0x3c,0x05,0x00,0x30,0x0c,0x00,0x18,0x5b, +0x24,0x06,0x00,0x02,0x3c,0x05,0x00,0x30,0x24,0x06,0x00,0x03,0x0c,0x00,0x18,0x5b, +0x24,0x04,0x08,0x3c,0x02,0x20,0x20,0x21,0x24,0x05,0x00,0x14,0x0c,0x00,0x18,0xa0, +0x24,0x06,0x01,0x07,0x08,0x00,0x1c,0x4f,0x3c,0x02,0xb0,0x03,0x3c,0x03,0xb0,0x03, +0x3c,0x02,0x80,0x00,0x00,0x80,0x70,0x21,0x34,0x63,0x00,0x20,0x24,0x42,0x72,0x6c, +0x3c,0x04,0xb0,0x03,0xac,0x62,0x00,0x00,0x34,0x84,0x00,0x30,0xad,0xc0,0x02,0xb8, +0x8c,0x83,0x00,0x00,0x24,0x02,0x00,0xff,0xa5,0xc0,0x00,0x0a,0x00,0x00,0x30,0x21, +0xa7,0x82,0x96,0x30,0x27,0x88,0x96,0x40,0xa5,0xc3,0x00,0x08,0x3c,0x07,0xb0,0x08, +0x30,0xc2,0xff,0xff,0x00,0x02,0x20,0xc0,0x24,0xc3,0x00,0x01,0x00,0x82,0x10,0x21, +0x00,0x60,0x30,0x21,0x00,0x02,0x10,0x80,0x30,0x63,0xff,0xff,0x00,0x48,0x10,0x21, +0x00,0x87,0x20,0x21,0x28,0xc5,0x00,0xff,0xac,0x83,0x00,0x00,0x14,0xa0,0xff,0xf4, +0xa4,0x43,0x00,0x00,0x3c,0x02,0xb0,0x08,0x34,0x03,0xff,0xff,0x34,0x42,0x07,0xf8, +0x3c,0x04,0xb0,0x08,0xac,0x43,0x00,0x00,0xa7,0x83,0xba,0x1c,0x24,0x06,0x01,0x00, +0x34,0x84,0x08,0x00,0x24,0xc2,0x00,0x01,0x28,0x43,0x02,0x00,0xac,0x82,0x00,0x00, +0x00,0x40,0x30,0x21,0x14,0x60,0xff,0xfb,0x24,0x84,0x00,0x08,0x25,0xc2,0x00,0x0c, +0x24,0x0a,0x00,0x02,0x3c,0x06,0xb0,0x03,0xaf,0x82,0xba,0x40,0x34,0xc6,0x00,0x64, +0xa0,0x4a,0x00,0x18,0x94,0xc5,0x00,0x00,0x8f,0x82,0xba,0x40,0x25,0xc4,0x00,0x30, +0x24,0x08,0x00,0x03,0x3c,0x03,0xb0,0x03,0xa0,0x45,0x00,0x21,0x34,0x63,0x00,0x66, +0xaf,0x84,0xba,0x44,0xa0,0x88,0x00,0x18,0x94,0x65,0x00,0x00,0x8f,0x82,0xba,0x44, +0x25,0xc4,0x00,0x54,0x25,0xc7,0x00,0x78,0xa0,0x45,0x00,0x21,0xaf,0x84,0xba,0x48, +0xa0,0x88,0x00,0x18,0x94,0x65,0x00,0x00,0x8f,0x82,0xba,0x48,0x25,0xc8,0x00,0x9c, +0x24,0x09,0x00,0x01,0xa0,0x45,0x00,0x21,0xaf,0x87,0xba,0x4c,0xa0,0xea,0x00,0x18, +0x94,0xc4,0x00,0x00,0x8f,0x82,0xba,0x4c,0x3c,0x03,0xb0,0x03,0x34,0x63,0x00,0x62, +0xa0,0x44,0x00,0x21,0xaf,0x88,0xba,0x50,0xa1,0x09,0x00,0x18,0x94,0x65,0x00,0x00, +0x8f,0x82,0xba,0x50,0x25,0xc4,0x00,0xc0,0x25,0xc6,0x00,0xe4,0xa0,0x45,0x00,0x21, +0xaf,0x84,0xba,0x54,0xa0,0x89,0x00,0x18,0x94,0x65,0x00,0x00,0x8f,0x82,0xba,0x54, +0x3c,0x04,0xb0,0x03,0x34,0x84,0x00,0x60,0xa0,0x45,0x00,0x21,0xaf,0x86,0xba,0x58, +0xa0,0xc0,0x00,0x18,0x94,0x85,0x00,0x00,0x8f,0x82,0xba,0x58,0x25,0xc3,0x01,0x08, +0x25,0xc6,0x01,0x2c,0xa0,0x45,0x00,0x21,0xaf,0x83,0xba,0x5c,0xa0,0x60,0x00,0x18, +0x94,0x87,0x00,0x00,0x8f,0x82,0xba,0x5c,0x25,0xc5,0x01,0x50,0x25,0xc4,0x01,0x74, +0xa0,0x47,0x00,0x21,0x25,0xc8,0x01,0x98,0x25,0xc9,0x01,0xbc,0x25,0xca,0x01,0xe0, +0x25,0xcb,0x02,0x04,0x25,0xcc,0x02,0x28,0x25,0xcd,0x02,0x4c,0x24,0x02,0x00,0x10, +0x3c,0x03,0xb0,0x03,0xaf,0x86,0xba,0x60,0x34,0x63,0x00,0x38,0xa0,0xc0,0x00,0x18, +0xaf,0x85,0xba,0x64,0xa0,0xa0,0x00,0x18,0xaf,0x84,0xba,0x68,0xa0,0x80,0x00,0x18, +0xaf,0x88,0xba,0x6c,0xa1,0x00,0x00,0x18,0xaf,0x89,0xba,0x70,0xa1,0x20,0x00,0x18, +0xaf,0x8a,0xba,0x74,0xa1,0x40,0x00,0x18,0xaf,0x8b,0xba,0x78,0xa1,0x60,0x00,0x18, +0xaf,0x8c,0xba,0x7c,0xa1,0x80,0x00,0x18,0xaf,0x8d,0xba,0x80,0xa1,0xa2,0x00,0x18, +0x94,0x64,0x00,0x00,0x8f,0x82,0xba,0x80,0x25,0xc5,0x02,0x70,0x3c,0x03,0xb0,0x03, +0xa0,0x44,0x00,0x21,0x24,0x02,0x00,0x11,0xaf,0x85,0xba,0x84,0x34,0x63,0x00,0x6e, +0xa0,0xa2,0x00,0x18,0x94,0x64,0x00,0x00,0x8f,0x82,0xba,0x84,0x25,0xc5,0x02,0x94, +0x3c,0x03,0xb0,0x03,0xa0,0x44,0x00,0x21,0x24,0x02,0x00,0x12,0xaf,0x85,0xba,0x88, +0x34,0x63,0x00,0x6c,0xa0,0xa2,0x00,0x18,0x94,0x64,0x00,0x00,0x8f,0x82,0xba,0x88, +0x24,0x05,0xff,0xff,0x24,0x07,0x00,0x01,0xa0,0x44,0x00,0x21,0x24,0x06,0x00,0x12, +0x27,0x84,0xba,0x40,0x8c,0x82,0x00,0x00,0x24,0xc6,0xff,0xff,0xa0,0x40,0x00,0x04, +0x8c,0x83,0x00,0x00,0xa4,0x45,0x00,0x00,0xa4,0x45,0x00,0x02,0xa0,0x60,0x00,0x0a, +0x8c,0x82,0x00,0x00,0xa4,0x65,0x00,0x06,0xa4,0x65,0x00,0x08,0xa0,0x40,0x00,0x10, +0x8c,0x83,0x00,0x00,0xa4,0x45,0x00,0x0c,0xa4,0x45,0x00,0x0e,0xa0,0x60,0x00,0x12, +0x8c,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x40,0x00,0x16,0x8c,0x83,0x00,0x00, +0xa4,0x45,0x00,0x14,0xa0,0x67,0x00,0x17,0x8c,0x82,0x00,0x00,0x24,0x84,0x00,0x04, +0xa0,0x40,0x00,0x20,0x04,0xc1,0xff,0xe7,0xac,0x40,0x00,0x1c,0x03,0xe0,0x00,0x08, +0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x03,0x3c,0x03,0x80,0x00,0x34,0x42,0x00,0x20, +0x24,0x63,0x75,0x54,0xac,0x43,0x00,0x00,0x90,0x82,0x00,0x10,0x00,0x80,0x60,0x21, +0x10,0x40,0x00,0x56,0x00,0x00,0x70,0x21,0x97,0x82,0x96,0x30,0x94,0x8a,0x00,0x0c, +0x27,0x87,0x96,0x40,0x00,0x02,0x40,0xc0,0x01,0x02,0x10,0x21,0x00,0x02,0x10,0x80, +0x00,0x47,0x10,0x21,0x90,0x8b,0x00,0x18,0xa4,0x4a,0x00,0x00,0x94,0x83,0x00,0x0e, +0x39,0x64,0x00,0x10,0x2c,0x84,0x00,0x01,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21, +0x34,0x85,0x00,0x02,0x39,0x63,0x00,0x11,0x00,0x83,0x28,0x0b,0x34,0xa3,0x00,0x08, +0x39,0x64,0x00,0x12,0x00,0x02,0x10,0x80,0x00,0xa4,0x18,0x0b,0x00,0x47,0x10,0x21, +0x94,0x49,0x00,0x04,0x34,0x64,0x00,0x20,0x00,0x6b,0x20,0x0b,0x34,0x83,0x00,0x40, +0x39,0x62,0x00,0x01,0x00,0x82,0x18,0x0b,0x00,0x09,0x30,0xc0,0x34,0x64,0x00,0x80, +0x00,0xc9,0x28,0x21,0x39,0x62,0x00,0x02,0x00,0x60,0x68,0x21,0x00,0x82,0x68,0x0a, +0x00,0x05,0x28,0x80,0x3c,0x02,0xb0,0x08,0x00,0xa7,0x28,0x21,0x00,0xc2,0x30,0x21, +0x01,0x02,0x40,0x21,0x34,0x03,0xff,0xff,0x35,0xa4,0x01,0x00,0x39,0x62,0x00,0x03, +0x2d,0x67,0x00,0x13,0xad,0x0a,0x00,0x00,0xa4,0xa3,0x00,0x00,0xac,0xc3,0x00,0x00, +0xa7,0x89,0x96,0x30,0x10,0xe0,0x00,0x0f,0x00,0x82,0x68,0x0a,0x3c,0x03,0x80,0x01, +0x00,0x0b,0x10,0x80,0x24,0x63,0x09,0x4c,0x00,0x43,0x10,0x21,0x8c,0x44,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x08,0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03, +0x34,0x63,0x00,0x60,0x94,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x14,0x00, +0x00,0x02,0x74,0x03,0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0x3a,0x94,0x44,0x00,0x00, +0x93,0x83,0x96,0x24,0x91,0x82,0x00,0x21,0x01,0xc4,0x20,0x21,0x91,0x85,0x00,0x10, +0x00,0x04,0x24,0x00,0x00,0x62,0x18,0x21,0x00,0x04,0x74,0x03,0x00,0x6e,0x18,0x23, +0x00,0x65,0x10,0x2a,0x00,0xa2,0x18,0x0a,0x00,0x0d,0x24,0x00,0x3c,0x02,0xb0,0x06, +0x24,0x05,0xff,0xff,0x00,0x64,0x18,0x25,0x34,0x42,0x80,0x20,0xac,0x43,0x00,0x00, +0xa5,0x85,0x00,0x0e,0xa1,0x80,0x00,0x10,0xa5,0x85,0x00,0x0c,0x03,0xe0,0x00,0x08, +0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03,0x08,0x00,0x1d,0x99,0x34,0x63,0x00,0x62, +0x3c,0x03,0xb0,0x03,0x08,0x00,0x1d,0x99,0x34,0x63,0x00,0x64,0x3c,0x03,0xb0,0x03, +0x08,0x00,0x1d,0x99,0x34,0x63,0x00,0x66,0x3c,0x03,0xb0,0x03,0x08,0x00,0x1d,0x99, +0x34,0x63,0x00,0x38,0x3c,0x03,0xb0,0x03,0x08,0x00,0x1d,0x99,0x34,0x63,0x00,0x6e, +0x3c,0x03,0xb0,0x03,0x08,0x00,0x1d,0x99,0x34,0x63,0x00,0x6c,0x3c,0x03,0xb0,0x03, +0x3c,0x02,0x80,0x00,0x34,0x63,0x00,0x20,0x24,0x42,0x77,0x1c,0x00,0x05,0x28,0x40, +0xac,0x62,0x00,0x00,0x00,0xa6,0x28,0x21,0x2c,0xe2,0x00,0x10,0x14,0x80,0x00,0x06, +0x00,0x00,0x18,0x21,0x10,0x40,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0xe0,0x18,0x21, +0x03,0xe0,0x00,0x08,0x00,0x60,0x10,0x21,0x24,0x02,0x00,0x20,0x10,0xe2,0x00,0x06, +0x2c,0xe4,0x00,0x10,0x24,0xa2,0x00,0x01,0x10,0x80,0xff,0xf9,0x00,0x02,0x11,0x00, +0x08,0x00,0x1d,0xd4,0x00,0x47,0x18,0x21,0x08,0x00,0x1d,0xd4,0x24,0xa3,0x00,0x50, +0x27,0xbd,0xff,0xc0,0xaf,0xb7,0x00,0x34,0xaf,0xb5,0x00,0x2c,0xaf,0xb4,0x00,0x28, +0xaf,0xb2,0x00,0x20,0xaf,0xb1,0x00,0x1c,0xaf,0xbf,0x00,0x3c,0xaf,0xbe,0x00,0x38, +0xaf,0xb6,0x00,0x30,0xaf,0xb3,0x00,0x24,0xaf,0xb0,0x00,0x18,0x84,0x85,0x00,0x08, +0x00,0x80,0x90,0x21,0x3c,0x02,0x80,0x00,0x3c,0x04,0xb0,0x03,0x34,0x84,0x00,0x20, +0x24,0x42,0x77,0x80,0x3c,0x03,0xb0,0x06,0x00,0x05,0x28,0x80,0xac,0x82,0x00,0x00, +0x00,0xa3,0x28,0x21,0x3c,0x04,0xb0,0x06,0x8c,0xa3,0x00,0x00,0x34,0x84,0x80,0x24, +0x8c,0xa6,0x00,0x00,0x8c,0x82,0x00,0x00,0x30,0x71,0xff,0xff,0x00,0x11,0x2a,0x00, +0x34,0x42,0x01,0x00,0x3c,0x03,0xb0,0x00,0xac,0x82,0x00,0x00,0x00,0xa3,0x40,0x21, +0x8d,0x1e,0x00,0x00,0x8d,0x13,0x00,0x04,0x96,0x44,0x00,0x08,0x00,0x11,0xa0,0xc0, +0x02,0x91,0x10,0x21,0x00,0x02,0x38,0x80,0x00,0x13,0x12,0x02,0x30,0x42,0x00,0x1f, +0x24,0x84,0x00,0x02,0x27,0x83,0x96,0x50,0xa6,0x42,0x00,0x06,0x30,0x84,0x01,0xff, +0x24,0x02,0x00,0x10,0x00,0xe3,0x18,0x21,0xa6,0x44,0x00,0x08,0x8d,0x10,0x00,0x08, +0xa0,0x62,0x00,0x06,0x86,0x44,0x00,0x06,0x27,0x82,0x96,0x44,0x00,0xe2,0x10,0x21, +0xac,0x48,0x00,0x18,0x24,0x02,0x00,0x13,0x00,0x06,0xbc,0x02,0x10,0x82,0x00,0xe6, +0x00,0x00,0xa8,0x21,0x3c,0x03,0xb0,0x03,0x34,0x63,0x01,0x00,0xa6,0x40,0x00,0x02, +0x90,0x64,0x00,0x00,0x3c,0x02,0xb0,0x03,0x34,0x42,0x01,0x08,0x8c,0x45,0x00,0x00, +0x00,0x10,0x1b,0xc2,0x00,0x04,0x20,0x82,0x27,0x82,0x96,0x40,0x00,0xe2,0x10,0x21, +0x30,0x84,0x00,0x01,0x30,0x63,0x00,0x01,0xac,0x45,0x00,0x08,0x10,0x60,0x00,0xbc, +0xaf,0xa4,0x00,0x10,0x00,0x10,0x16,0x82,0x30,0x46,0x00,0x01,0x00,0x10,0x12,0x02, +0x00,0x10,0x19,0xc2,0x00,0x10,0x26,0x02,0x00,0x10,0x2e,0x42,0x30,0x47,0x00,0x7f, +0x24,0x02,0x00,0x01,0x30,0x76,0x00,0x01,0x30,0x84,0x00,0x01,0x10,0xc2,0x00,0xa7, +0x30,0xa3,0x00,0x01,0x0c,0x00,0x1d,0xc7,0x00,0x60,0x28,0x21,0x00,0x40,0xa8,0x21, +0x02,0x91,0x10,0x21,0x00,0x02,0x10,0x80,0x2e,0xa4,0x00,0x54,0x27,0x85,0x96,0x50, +0x27,0x83,0x96,0x48,0x00,0x04,0xa8,0x0a,0x00,0x45,0x28,0x21,0x26,0xc4,0x00,0x02, +0x00,0x43,0x10,0x21,0xa0,0x44,0x00,0x06,0xa0,0x55,0x00,0x07,0xa0,0xb5,0x00,0x02, +0xa0,0xb5,0x00,0x01,0x00,0x10,0x14,0x82,0x00,0x10,0x1d,0xc2,0x30,0x48,0x00,0x01, +0x00,0x13,0x15,0x82,0x00,0x13,0x21,0x82,0x30,0x63,0x00,0x01,0x00,0x10,0x2c,0x02, +0x00,0x10,0x34,0x42,0x30,0x49,0x00,0x03,0x24,0x02,0x00,0x01,0xa6,0x5e,0x00,0x04, +0xa6,0x43,0x00,0x00,0x30,0x8a,0x00,0x01,0x32,0x73,0x00,0x07,0x30,0xa5,0x00,0x01, +0x30,0xc6,0x00,0x01,0x11,0x02,0x00,0x77,0x32,0x07,0x00,0x7f,0x15,0x40,0x00,0x03, +0x00,0x00,0x00,0x00,0x15,0x20,0x00,0x68,0x24,0x02,0x00,0x01,0x96,0x42,0x00,0x04, +0x00,0x00,0x00,0x00,0x24,0x42,0x00,0x04,0xa6,0x42,0x00,0x04,0x00,0xa0,0x20,0x21, +0x00,0xc0,0x28,0x21,0x0c,0x00,0x1d,0xc7,0x01,0x00,0x30,0x21,0x02,0x91,0x18,0x21, +0x00,0x03,0x38,0x80,0x2e,0xa5,0x00,0x54,0x27,0x84,0x96,0x50,0x00,0xe4,0x20,0x21, +0x00,0x05,0x10,0x0a,0xa0,0x82,0x00,0x00,0xa0,0x80,0x00,0x04,0xa0,0x80,0x00,0x05, +0x96,0x45,0x00,0x04,0x27,0x82,0x96,0x40,0x00,0xe2,0x10,0x21,0xa4,0x45,0x00,0x06, +0x27,0x83,0x96,0x44,0x00,0xe3,0x18,0x21,0x92,0x45,0x00,0x01,0x8c,0x66,0x00,0x18, +0x27,0x82,0x96,0x60,0x00,0xe2,0x10,0x21,0xa0,0x40,0x00,0x00,0xa0,0x85,0x00,0x07, +0x94,0xc3,0x00,0x10,0x24,0x02,0x00,0x04,0x30,0x63,0x00,0x0f,0x10,0x62,0x00,0x42, +0x24,0xc6,0x00,0x10,0x94,0xc3,0x00,0x16,0x27,0x88,0x96,0x58,0x00,0xe8,0x10,0x21, +0xa4,0x43,0x00,0x02,0x94,0xc2,0x00,0x04,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x01, +0x14,0x40,0x00,0x30,0x02,0x91,0x20,0x21,0x94,0xc2,0x00,0x00,0x24,0x03,0x00,0xa4, +0x30,0x42,0x00,0xff,0x10,0x43,0x00,0x2b,0x00,0x00,0x00,0x00,0x94,0xc2,0x00,0x00, +0x24,0x03,0x00,0x88,0x30,0x42,0x00,0x88,0x10,0x43,0x00,0x20,0x02,0x91,0x18,0x21, +0x27,0x84,0x96,0x60,0x00,0x03,0x18,0x80,0x00,0x64,0x18,0x21,0x8c,0x62,0x00,0x00, +0x3c,0x04,0x00,0x80,0x00,0x44,0x10,0x25,0xac,0x62,0x00,0x00,0x00,0x17,0x10,0xc0, +0x00,0x57,0x10,0x21,0x27,0x84,0x96,0x40,0x00,0x02,0x10,0x80,0x00,0x44,0x10,0x21, +0x94,0x45,0x00,0x00,0x02,0x91,0x18,0x21,0x00,0x03,0x18,0x80,0x00,0x64,0x20,0x21, +0x24,0x02,0xff,0xff,0x00,0x68,0x18,0x21,0xa0,0x73,0x00,0x00,0xa4,0x82,0x00,0x02, +0xa4,0x97,0x00,0x04,0xae,0x51,0x02,0xb8,0xa6,0x45,0x00,0x0a,0x7b,0xbe,0x01,0xfc, +0x7b,0xb6,0x01,0xbc,0x7b,0xb4,0x01,0x7c,0x7b,0xb2,0x01,0x3c,0x7b,0xb0,0x00,0xfc, +0x24,0x02,0x00,0x01,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x40,0x94,0xc2,0x00,0x18, +0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x60,0x10,0x40,0xff,0xdd,0x02,0x91,0x18,0x21, +0x02,0x91,0x20,0x21,0x27,0x82,0x96,0x60,0x00,0x04,0x20,0x80,0x00,0x82,0x20,0x21, +0x8c,0x83,0x00,0x00,0x3c,0x02,0xff,0x7f,0x34,0x42,0xff,0xff,0x00,0x62,0x18,0x24, +0x08,0x00,0x1e,0x97,0xac,0x83,0x00,0x00,0x27,0x88,0x96,0x58,0x00,0xe8,0x10,0x21, +0x08,0x00,0x1e,0x81,0xa4,0x40,0x00,0x02,0x11,0x22,0x00,0x07,0x00,0x00,0x00,0x00, +0x2d,0x22,0x00,0x02,0x14,0x40,0xff,0x9a,0x00,0xa0,0x20,0x21,0x96,0x42,0x00,0x04, +0x08,0x00,0x1e,0x5e,0x24,0x42,0x00,0x0c,0x96,0x42,0x00,0x04,0x08,0x00,0x1e,0x5e, +0x24,0x42,0x00,0x08,0x8f,0xa2,0x00,0x10,0x00,0x00,0x00,0x00,0x14,0x48,0xff,0x87, +0x02,0x91,0x18,0x21,0x27,0x82,0x96,0x44,0x00,0x03,0x18,0x80,0x00,0x62,0x18,0x21, +0x8c,0x64,0x00,0x18,0x3c,0x02,0xff,0xfb,0x34,0x42,0xff,0xff,0x02,0x02,0x10,0x24, +0xac,0x82,0x00,0x08,0x08,0x00,0x1e,0x57,0x00,0x00,0x40,0x21,0x8f,0xa2,0x00,0x10, +0x00,0x00,0x00,0x00,0x14,0x46,0xff,0x57,0x3c,0x02,0xfb,0xff,0x34,0x42,0xff,0xff, +0x02,0x02,0x10,0x24,0xad,0x02,0x00,0x08,0x08,0x00,0x1e,0x35,0x00,0x00,0x30,0x21, +0x93,0x88,0xc1,0x54,0x00,0x10,0x1e,0x42,0x00,0x10,0x26,0x82,0x27,0x82,0x96,0x48, +0x2d,0x05,0x00,0x0c,0x00,0xe2,0x48,0x21,0x30,0x63,0x00,0x01,0x30,0x86,0x00,0x01, +0x14,0xa0,0x00,0x06,0x01,0x00,0x38,0x21,0x00,0x03,0x10,0x40,0x00,0x46,0x10,0x21, +0x00,0x02,0x11,0x00,0x01,0x02,0x10,0x21,0x24,0x47,0x00,0x04,0x02,0x91,0x10,0x21, +0x00,0x02,0x10,0x80,0x27,0x84,0x96,0x50,0x27,0x83,0x96,0x48,0x00,0x44,0x20,0x21, +0x00,0x43,0x10,0x21,0xa1,0x27,0x00,0x07,0xa0,0x40,0x00,0x06,0xa0,0x80,0x00,0x02, +0x08,0x00,0x1e,0x45,0xa0,0x80,0x00,0x01,0x24,0x02,0x00,0x01,0xa6,0x42,0x00,0x02, +0x0c,0x00,0x04,0x40,0x01,0x00,0x20,0x21,0x08,0x00,0x1e,0xa7,0x00,0x00,0x00,0x00, +0x30,0xa7,0xff,0xff,0x00,0x07,0x18,0xc0,0x00,0x67,0x18,0x21,0x3c,0x06,0xb0,0x03, +0x3c,0x02,0x80,0x00,0x24,0x42,0x7c,0x10,0x27,0x85,0x96,0x50,0x00,0x03,0x18,0x80, +0x34,0xc6,0x00,0x20,0x00,0x65,0x18,0x21,0xac,0xc2,0x00,0x00,0x80,0x62,0x00,0x07, +0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x29,0x00,0x80,0x28,0x21,0x90,0x82,0x00,0x16, +0x00,0x00,0x00,0x00,0x34,0x42,0x00,0x02,0x30,0x43,0x00,0x01,0x14,0x60,0x00,0x02, +0xa0,0x82,0x00,0x16,0xa0,0x80,0x00,0x17,0x90,0xa2,0x00,0x04,0x3c,0x03,0xb0,0x03, +0x27,0x86,0x96,0x40,0x14,0x40,0x00,0x06,0x34,0x63,0x00,0x20,0x24,0x02,0x00,0x01, +0xa0,0xa2,0x00,0x04,0xa4,0xa7,0x00,0x02,0x03,0xe0,0x00,0x08,0xa4,0xa7,0x00,0x00, +0x94,0xa4,0x00,0x02,0x3c,0x02,0x80,0x01,0x24,0x42,0x93,0x34,0xac,0x62,0x00,0x00, +0x00,0x04,0x18,0xc0,0x00,0x64,0x18,0x21,0x00,0x03,0x18,0x80,0x00,0x66,0x18,0x21, +0x94,0x62,0x00,0x04,0xa4,0x67,0x00,0x02,0x3c,0x03,0xb0,0x08,0x00,0x02,0x20,0xc0, +0x00,0x82,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x46,0x10,0x21,0x00,0x83,0x20,0x21, +0xa4,0x47,0x00,0x00,0xac,0x87,0x00,0x00,0x90,0xa2,0x00,0x04,0xa4,0xa7,0x00,0x02, +0x24,0x42,0x00,0x01,0x03,0xe0,0x00,0x08,0xa0,0xa2,0x00,0x04,0x90,0x82,0x00,0x16, +0x24,0x85,0x00,0x06,0x34,0x42,0x00,0x01,0x30,0x43,0x00,0x02,0x14,0x60,0xff,0xda, +0xa0,0x82,0x00,0x16,0x24,0x02,0x00,0x01,0x08,0x00,0x1f,0x1a,0xa0,0x82,0x00,0x17, +0x27,0xbd,0xff,0xe8,0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x14,0x00,0x80,0x80,0x21, +0x84,0x84,0x00,0x02,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x34,0x63,0x00,0x20, +0x24,0x42,0x7d,0x10,0x10,0x80,0x00,0x38,0xac,0x62,0x00,0x00,0x8e,0x04,0x02,0xb8, +0x0c,0x00,0x02,0x7e,0x00,0x00,0x00,0x00,0x97,0x88,0x96,0x30,0x96,0x0c,0x02,0xba, +0x3c,0x04,0xb0,0x08,0x00,0x08,0x30,0xc0,0x00,0xc4,0x10,0x21,0xac,0x4c,0x00,0x00, +0x8e,0x03,0x02,0xb8,0x27,0x89,0x96,0x40,0x34,0x0b,0xff,0xff,0x00,0x03,0x10,0xc0, +0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x49,0x10,0x21,0x94,0x4a,0x00,0x04, +0x00,0xc8,0x30,0x21,0x00,0x06,0x30,0x80,0x00,0x0a,0x28,0xc0,0x00,0xa4,0x20,0x21, +0xac,0x8b,0x00,0x00,0x8e,0x02,0x02,0xb8,0x27,0x84,0x96,0x50,0x00,0xaa,0x28,0x21, +0x00,0x02,0x18,0xc0,0x00,0x62,0x18,0x21,0x00,0x03,0x18,0x80,0x27,0x82,0x96,0x44, +0x00,0x62,0x10,0x21,0x8c,0x47,0x00,0x18,0x00,0x64,0x18,0x21,0x80,0x68,0x00,0x06, +0x8c,0xe4,0x00,0x00,0x00,0x05,0x28,0x80,0x3c,0x03,0xb0,0x06,0x30,0x84,0xff,0xff, +0x00,0x88,0x20,0x21,0x30,0x82,0x00,0xff,0x00,0x02,0x10,0x2b,0x00,0x04,0x22,0x02, +0x00,0x82,0x20,0x21,0x3c,0x02,0x00,0x04,0x00,0xa9,0x28,0x21,0x00,0x82,0x20,0x25, +0x00,0xc9,0x30,0x21,0x34,0x63,0x80,0x20,0xa4,0xcc,0x00,0x00,0xac,0x64,0x00,0x00, +0xa4,0xab,0x00,0x00,0xa7,0x8a,0x96,0x30,0x8f,0xbf,0x00,0x14,0x8f,0xb0,0x00,0x10, +0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18,0x86,0x03,0x00,0x06,0x27,0x82,0xba,0x40, +0x96,0x05,0x02,0xba,0x00,0x03,0x18,0x80,0x00,0x62,0x18,0x21,0x8c,0x64,0x00,0x00, +0x0c,0x00,0x1f,0x04,0x00,0x00,0x00,0x00,0x08,0x00,0x1f,0x82,0x00,0x00,0x00,0x00, +0x94,0x88,0x00,0x00,0x00,0x80,0x58,0x21,0x27,0x8a,0x96,0x40,0x00,0x08,0x18,0xc0, +0x00,0x68,0x18,0x21,0x3c,0x04,0xb0,0x03,0x00,0x03,0x18,0x80,0x3c,0x02,0x80,0x00, +0x00,0x6a,0x18,0x21,0x34,0x84,0x00,0x20,0x24,0x42,0x7e,0x40,0x30,0xa5,0xff,0xff, +0xac,0x82,0x00,0x00,0x94,0x67,0x00,0x02,0x11,0x05,0x00,0x35,0x24,0x04,0x00,0x01, +0x91,0x66,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x86,0x10,0x2a,0x10,0x40,0x00,0x10, +0x00,0xc0,0x48,0x21,0x3c,0x0d,0xb0,0x03,0x01,0x40,0x60,0x21,0x35,0xad,0x00,0x20, +0x10,0xe5,0x00,0x0d,0x24,0x84,0x00,0x01,0x00,0x07,0x10,0xc0,0x00,0x47,0x10,0x21, +0x00,0x02,0x10,0x80,0x01,0x20,0x30,0x21,0x00,0x4a,0x10,0x21,0x00,0x86,0x18,0x2a, +0x00,0xe0,0x40,0x21,0x94,0x47,0x00,0x02,0x14,0x60,0xff,0xf5,0x00,0x00,0x00,0x00, +0x03,0xe0,0x00,0x08,0x00,0x00,0x10,0x21,0x00,0x08,0x20,0xc0,0x00,0x88,0x20,0x21, +0x24,0xc2,0xff,0xff,0x00,0x04,0x20,0x80,0xa1,0x62,0x00,0x04,0x00,0x8c,0x20,0x21, +0x94,0x83,0x00,0x04,0x00,0x07,0x10,0xc0,0x00,0x47,0x10,0x21,0x00,0x02,0x10,0x80, +0x00,0x4c,0x10,0x21,0x00,0x03,0x28,0xc0,0x94,0x46,0x00,0x02,0x00,0xa3,0x18,0x21, +0x00,0x03,0x18,0x80,0x00,0x6c,0x18,0x21,0xa4,0x66,0x00,0x00,0xa4,0x86,0x00,0x02, +0x95,0x64,0x00,0x02,0x3c,0x03,0xb0,0x08,0x3c,0x02,0x80,0x01,0x00,0xa3,0x28,0x21, +0x24,0x42,0x93,0x34,0xad,0xa2,0x00,0x00,0x10,0x87,0x00,0x03,0xac,0xa6,0x00,0x00, +0x03,0xe0,0x00,0x08,0x24,0x02,0x00,0x01,0x08,0x00,0x1f,0xd0,0xa5,0x68,0x00,0x02, +0x91,0x62,0x00,0x04,0xa5,0x67,0x00,0x00,0x24,0x42,0xff,0xff,0x30,0x43,0x00,0xff, +0x14,0x60,0xff,0xf7,0xa1,0x62,0x00,0x04,0x24,0x02,0xff,0xff,0x08,0x00,0x1f,0xd0, +0xa5,0x62,0x00,0x02,0x00,0x05,0x40,0xc0,0x01,0x05,0x30,0x21,0x27,0xbd,0xff,0xd8, +0x00,0x06,0x30,0x80,0x27,0x82,0x96,0x44,0xaf,0xb2,0x00,0x18,0xaf,0xb1,0x00,0x14, +0xaf,0xbf,0x00,0x20,0xaf,0xb3,0x00,0x1c,0xaf,0xb0,0x00,0x10,0x00,0xc2,0x10,0x21, +0x8c,0x47,0x00,0x18,0x00,0xa0,0x90,0x21,0x3c,0x02,0x80,0x00,0x3c,0x05,0xb0,0x03, +0x34,0xa5,0x00,0x20,0x24,0x42,0x7f,0x74,0xac,0xa2,0x00,0x00,0x27,0x83,0x96,0x50, +0x00,0xc3,0x30,0x21,0x8c,0xe2,0x00,0x00,0x80,0xc5,0x00,0x06,0x00,0x80,0x88,0x21, +0x30,0x42,0xff,0xff,0x00,0x45,0x10,0x21,0x30,0x43,0x00,0xff,0x10,0x60,0x00,0x02, +0x00,0x02,0x12,0x02,0x24,0x42,0x00,0x01,0x30,0x53,0x00,0xff,0x01,0x12,0x10,0x21, +0x00,0x02,0x10,0x80,0x27,0x83,0x96,0x50,0x00,0x43,0x10,0x21,0x80,0x44,0x00,0x07, +0x00,0x00,0x00,0x00,0x10,0x80,0x00,0x4b,0x26,0x24,0x00,0x06,0x32,0x50,0xff,0xff, +0x02,0x20,0x20,0x21,0x0c,0x00,0x1f,0x90,0x02,0x00,0x28,0x21,0x92,0x22,0x00,0x10, +0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x2e,0x3c,0x03,0xb0,0x08,0x3c,0x09,0x80,0x01, +0x27,0x88,0x96,0x40,0xa6,0x32,0x00,0x0c,0x00,0x10,0x20,0xc0,0x00,0x90,0x20,0x21, +0x00,0x04,0x20,0x80,0x00,0x88,0x20,0x21,0x94,0x82,0x00,0x04,0x3c,0x03,0xb0,0x08, +0x3c,0x07,0xb0,0x03,0x00,0x02,0x28,0xc0,0x00,0xa2,0x10,0x21,0x00,0x02,0x10,0x80, +0x00,0x48,0x10,0x21,0x00,0xa3,0x28,0x21,0x25,0x26,0x93,0x34,0x34,0x03,0xff,0xff, +0x34,0xe7,0x00,0x20,0xac,0xe6,0x00,0x00,0xa4,0x83,0x00,0x02,0xa4,0x43,0x00,0x00, +0xac,0xa3,0x00,0x00,0x92,0x22,0x00,0x10,0x92,0x23,0x00,0x0a,0xa6,0x32,0x00,0x0e, +0x02,0x62,0x10,0x21,0x14,0x60,0x00,0x05,0xa2,0x22,0x00,0x10,0x92,0x22,0x00,0x16, +0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xfe,0xa2,0x22,0x00,0x16,0x92,0x22,0x00,0x04, +0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x05,0x00,0x00,0x00,0x00,0x92,0x22,0x00,0x16, +0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xfd,0xa2,0x22,0x00,0x16,0x8f,0xbf,0x00,0x20, +0x7b,0xb2,0x00,0xfc,0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x28, +0x96,0x22,0x00,0x0e,0x27,0x88,0x96,0x40,0x00,0x02,0x20,0xc0,0x00,0x82,0x20,0x21, +0x00,0x04,0x20,0x80,0x00,0x88,0x20,0x21,0x94,0x82,0x00,0x04,0x3c,0x06,0xb0,0x03, +0x3c,0x09,0x80,0x01,0x00,0x02,0x28,0xc0,0x00,0xa2,0x10,0x21,0x00,0x02,0x10,0x80, +0x00,0xa3,0x28,0x21,0x00,0x48,0x10,0x21,0x34,0xc6,0x00,0x20,0x25,0x23,0x93,0x34, +0xac,0xc3,0x00,0x00,0xa4,0x50,0x00,0x00,0xac,0xb0,0x00,0x00,0x08,0x00,0x20,0x0e, +0xa4,0x90,0x00,0x02,0x08,0x00,0x20,0x05,0x32,0x50,0xff,0xff,0x3c,0x03,0xb0,0x03, +0x3c,0x02,0x80,0x01,0x24,0x42,0x81,0x3c,0x34,0x63,0x00,0x20,0xac,0x62,0x00,0x00, +0x90,0x82,0x00,0x04,0x97,0xaa,0x00,0x12,0x00,0x80,0x60,0x21,0x30,0xa8,0xff,0xff, +0x00,0x4a,0x20,0x23,0x34,0x09,0xff,0xff,0x30,0xcf,0xff,0xff,0x30,0xee,0xff,0xff, +0x11,0x09,0x00,0x73,0xa1,0x84,0x00,0x04,0x00,0x0e,0xc0,0xc0,0x00,0x08,0x10,0xc0, +0x00,0x48,0x10,0x21,0x03,0x0e,0x20,0x21,0x27,0x8d,0x96,0x40,0x00,0x04,0x20,0x80, +0x00,0x02,0x10,0x80,0x00,0x4d,0x10,0x21,0x00,0x8d,0x20,0x21,0x94,0x86,0x00,0x02, +0x94,0x43,0x00,0x04,0x3c,0x19,0x80,0x01,0xa4,0x46,0x00,0x02,0x00,0x03,0x28,0xc0, +0x00,0xa3,0x18,0x21,0x94,0x87,0x00,0x02,0x3c,0x02,0xb0,0x08,0x00,0x03,0x18,0x80, +0x00,0xa2,0x28,0x21,0x00,0x6d,0x18,0x21,0x27,0x22,0x93,0x34,0x3c,0x01,0xb0,0x03, +0xac,0x22,0x00,0x20,0xa4,0x66,0x00,0x00,0x10,0xe9,0x00,0x57,0xac,0xa6,0x00,0x00, +0x01,0xe0,0x30,0x21,0x11,0x40,0x00,0x1d,0x00,0x00,0x48,0x21,0x01,0x40,0x38,0x21, +0x27,0x8b,0x96,0x44,0x27,0x8a,0x96,0x50,0x00,0x06,0x40,0xc0,0x01,0x06,0x18,0x21, +0x00,0x03,0x18,0x80,0x00,0x6b,0x10,0x21,0x8c,0x44,0x00,0x18,0x00,0x6a,0x18,0x21, +0x80,0x65,0x00,0x06,0x8c,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x42,0xff,0xff, +0x00,0x45,0x10,0x21,0x30,0x44,0x00,0xff,0x00,0x02,0x12,0x02,0x01,0x22,0x18,0x21, +0x24,0x62,0x00,0x01,0x14,0x80,0x00,0x02,0x30,0x49,0x00,0xff,0x30,0x69,0x00,0xff, +0x01,0x06,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x4d,0x10,0x21,0x24,0xe7,0xff,0xff, +0x94,0x46,0x00,0x02,0x14,0xe0,0xff,0xe9,0x00,0x06,0x40,0xc0,0x91,0x82,0x00,0x10, +0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x20,0x3c,0x06,0xb0,0x03,0xa5,0x8f,0x00,0x0c, +0x03,0x0e,0x20,0x21,0x00,0x04,0x20,0x80,0x00,0x8d,0x20,0x21,0x94,0x82,0x00,0x04, +0x3c,0x03,0xb0,0x08,0x3c,0x07,0xb0,0x03,0x00,0x02,0x28,0xc0,0x00,0xa2,0x10,0x21, +0x00,0x02,0x10,0x80,0x00,0x4d,0x10,0x21,0x00,0xa3,0x28,0x21,0x27,0x26,0x93,0x34, +0x34,0x03,0xff,0xff,0x34,0xe7,0x00,0x20,0xac,0xe6,0x00,0x00,0xa4,0x83,0x00,0x02, +0xa4,0x43,0x00,0x00,0xac,0xa3,0x00,0x00,0x91,0x82,0x00,0x10,0x91,0x83,0x00,0x04, +0xa5,0x8e,0x00,0x0e,0x01,0x22,0x10,0x21,0x14,0x60,0x00,0x05,0xa1,0x82,0x00,0x10, +0x91,0x82,0x00,0x16,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xfd,0xa1,0x82,0x00,0x16, +0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x95,0x82,0x00,0x0e,0x3c,0x03,0xb0,0x08, +0x00,0x02,0x20,0xc0,0x00,0x82,0x20,0x21,0x00,0x04,0x20,0x80,0x00,0x8d,0x20,0x21, +0x94,0x82,0x00,0x04,0x34,0xc6,0x00,0x20,0x27,0x27,0x93,0x34,0x00,0x02,0x28,0xc0, +0x00,0xa2,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0xa3,0x28,0x21,0x00,0x4d,0x10,0x21, +0xac,0xc7,0x00,0x00,0xa4,0x8f,0x00,0x02,0xa4,0x4f,0x00,0x00,0xac,0xaf,0x00,0x00, +0x08,0x00,0x20,0x9d,0x03,0x0e,0x20,0x21,0x08,0x00,0x20,0x78,0xa5,0x88,0x00,0x02, +0x00,0x0e,0xc0,0xc0,0x03,0x0e,0x10,0x21,0x00,0x02,0x10,0x80,0x27,0x8d,0x96,0x40, +0x00,0x4d,0x10,0x21,0x94,0x43,0x00,0x02,0x30,0x84,0x00,0xff,0x14,0x80,0x00,0x05, +0xa5,0x83,0x00,0x00,0x24,0x02,0xff,0xff,0x3c,0x19,0x80,0x01,0x08,0x00,0x20,0x78, +0xa5,0x82,0x00,0x02,0x08,0x00,0x20,0x78,0x3c,0x19,0x80,0x01,0x3c,0x08,0xb0,0x03, +0x3c,0x02,0x80,0x01,0x27,0xbd,0xff,0x80,0x24,0x42,0x83,0x7c,0x35,0x08,0x00,0x20, +0xaf,0xb2,0x00,0x60,0xaf,0xb1,0x00,0x5c,0xaf,0xbf,0x00,0x7c,0xaf,0xbe,0x00,0x78, +0xaf,0xb7,0x00,0x74,0xaf,0xb6,0x00,0x70,0xaf,0xb5,0x00,0x6c,0xaf,0xb4,0x00,0x68, +0xaf,0xb3,0x00,0x64,0xaf,0xb0,0x00,0x58,0xad,0x02,0x00,0x00,0xaf,0xa4,0x00,0x80, +0x90,0x83,0x00,0x0a,0x27,0x82,0xba,0x40,0xaf,0xa6,0x00,0x88,0x00,0x03,0x18,0x80, +0x00,0x62,0x18,0x21,0x8c,0x7e,0x00,0x00,0xaf,0xa7,0x00,0x8c,0x27,0x86,0x96,0x44, +0x97,0xc3,0x00,0x14,0x30,0xb1,0xff,0xff,0x00,0x03,0x20,0xc0,0xaf,0xa3,0x00,0x1c, +0x00,0x83,0x18,0x21,0xaf,0xa4,0x00,0x50,0x00,0x03,0x18,0x80,0x27,0x84,0x96,0x50, +0x00,0x64,0x20,0x21,0x80,0x82,0x00,0x06,0x00,0x66,0x18,0x21,0x8c,0x66,0x00,0x18, +0x24,0x42,0x00,0x02,0x00,0x02,0x1f,0xc2,0x8c,0xc4,0x00,0x08,0x00,0x43,0x10,0x21, +0x00,0x02,0x10,0x43,0x00,0x02,0x10,0x40,0x00,0x04,0x2f,0xc2,0x00,0x04,0x1c,0x82, +0x00,0x04,0x24,0x42,0x30,0x63,0x00,0x01,0x00,0xc2,0x38,0x21,0x30,0x84,0x00,0x01, +0x24,0x02,0x00,0x01,0xaf,0xa5,0x00,0x3c,0xaf,0xa3,0x00,0x34,0xaf,0xa4,0x00,0x38, +0xaf,0xa0,0x00,0x40,0xaf,0xa0,0x00,0x44,0xaf,0xa2,0x00,0x20,0x83,0xc3,0x00,0x12, +0x8f,0xb2,0x00,0x1c,0x8c,0xd0,0x00,0x0c,0x14,0xa0,0x01,0xa2,0xaf,0xa3,0x00,0x28, +0x00,0x10,0x10,0x82,0x30,0x45,0x00,0x07,0x10,0xa0,0x00,0x11,0xaf,0xa0,0x00,0x30, +0x8f,0xa4,0x00,0x90,0x27,0x82,0x86,0xb0,0x00,0x04,0x18,0x40,0x00,0x62,0x18,0x21, +0x24,0xa2,0x00,0x06,0x8f,0xa5,0x00,0x20,0x94,0x64,0x00,0x00,0x00,0x45,0x10,0x04, +0x00,0x44,0x00,0x1a,0x14,0x80,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x0d, +0x00,0x00,0x10,0x12,0x24,0x42,0x00,0x20,0x30,0x42,0xff,0xfc,0xaf,0xa2,0x00,0x30, +0x8f,0xa3,0x00,0x1c,0x8f,0xa4,0x00,0x28,0x34,0x02,0xff,0xff,0xaf,0xa0,0x00,0x2c, +0xaf,0xa2,0x00,0x48,0xaf,0xa3,0x00,0x4c,0x00,0x60,0xb0,0x21,0x00,0x00,0xb8,0x21, +0x18,0x80,0x00,0x3b,0xaf,0xa0,0x00,0x24,0x00,0x11,0x89,0x02,0xaf,0xb1,0x00,0x54, +0x00,0x80,0xa8,0x21,0x00,0x12,0xa0,0xc0,0x02,0x92,0x10,0x21,0x00,0x02,0x80,0x80, +0x27,0x85,0x96,0x40,0x02,0x05,0x18,0x21,0x94,0x63,0x00,0x02,0x02,0x40,0x20,0x21, +0x00,0x00,0x28,0x21,0x0c,0x00,0x17,0x43,0xaf,0xa3,0x00,0x18,0x90,0x42,0x00,0x00, +0x24,0x03,0x00,0x08,0x30,0x42,0x00,0x0c,0x10,0x43,0x01,0x5c,0x24,0x04,0x00,0x01, +0x24,0x02,0x00,0x01,0x10,0x82,0x01,0x3b,0x3c,0x03,0xb0,0x03,0x34,0x63,0x01,0x04, +0x02,0x92,0x20,0x21,0x94,0x66,0x00,0x00,0x00,0x04,0x20,0x80,0x27,0x82,0x96,0x48, +0x00,0x82,0x10,0x21,0x27,0x83,0x96,0x50,0x80,0x45,0x00,0x06,0x00,0x83,0x20,0x21, +0x30,0xd0,0xff,0xff,0x80,0x91,0x00,0x05,0x80,0x93,0x00,0x04,0x8f,0xa4,0x00,0x80, +0x32,0x03,0x00,0xff,0x00,0x10,0x12,0x03,0x38,0xa5,0x00,0x00,0x00,0x60,0x80,0x21, +0x00,0x45,0x80,0x0a,0xa4,0x82,0x00,0x44,0x12,0x20,0x01,0x1c,0xa4,0x83,0x00,0x46, +0x02,0x71,0x10,0x21,0x00,0x50,0x10,0x2a,0x14,0x40,0x00,0xbb,0x02,0x92,0x10,0x21, +0x93,0x82,0x91,0x51,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x01,0x14,0x40,0x00,0xae, +0x02,0x92,0x28,0x21,0x26,0xe2,0x00,0x01,0x30,0x57,0xff,0xff,0x02,0x40,0xb0,0x21, +0x26,0xb5,0xff,0xff,0x8f,0xb2,0x00,0x18,0x16,0xa0,0xff,0xca,0x00,0x00,0x00,0x00, +0x16,0xe0,0x00,0x9e,0x02,0xc0,0x38,0x21,0x8f,0xa5,0x00,0x90,0x00,0x00,0x00,0x00, +0x2c,0xa2,0x00,0x10,0x10,0x40,0x00,0x2e,0x00,0x00,0x00,0x00,0x8f,0xa2,0x00,0x24, +0x00,0x00,0x00,0x00,0x18,0x40,0x00,0x2a,0x24,0x03,0x00,0x01,0x97,0xd2,0x00,0x14, +0xa3,0xc3,0x00,0x12,0x00,0x12,0x10,0xc0,0x00,0x52,0x10,0x21,0x00,0x02,0x80,0x80, +0x27,0x82,0x96,0x50,0x02,0x02,0x10,0x21,0x80,0x43,0x00,0x06,0x27,0x84,0x96,0x44, +0x02,0x04,0x20,0x21,0x24,0x63,0x00,0x02,0x00,0x03,0x17,0xc2,0x00,0x62,0x18,0x21, +0x8c,0x85,0x00,0x18,0x00,0x03,0x18,0x43,0x00,0x03,0x18,0x40,0x00,0xa3,0x38,0x21, +0x8f,0xa3,0x00,0x3c,0x00,0x00,0x00,0x00,0x14,0x60,0x00,0x0d,0x00,0x00,0x00,0x00, +0x27,0x82,0x96,0x40,0x02,0x02,0x10,0x21,0x94,0x43,0x00,0x06,0x24,0x02,0x00,0x01, +0xa7,0xc3,0x00,0x1a,0x7b,0xbe,0x03,0xfc,0x7b,0xb6,0x03,0xbc,0x7b,0xb4,0x03,0x7c, +0x7b,0xb2,0x03,0x3c,0x7b,0xb0,0x02,0xfc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x80, +0x8f,0xa4,0x00,0x90,0x8f,0xa5,0x00,0x38,0x8f,0xa6,0x00,0x34,0xaf,0xa0,0x00,0x10, +0x0c,0x00,0x0d,0xfe,0xaf,0xa0,0x00,0x14,0x08,0x00,0x21,0x94,0x00,0x00,0x00,0x00, +0x8f,0xa4,0x00,0x44,0x8f,0xa3,0x00,0x24,0x8f,0xa5,0x00,0x2c,0x30,0x82,0x00,0x03, +0xa3,0xc3,0x00,0x12,0x00,0x02,0x10,0x23,0x8f,0xa4,0x00,0x80,0x30,0x42,0x00,0x03, +0x00,0xa2,0x10,0x23,0xa7,0xc2,0x00,0x1a,0x84,0x83,0x00,0x0c,0x00,0x00,0x00,0x00, +0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80,0x27,0x83,0x96,0x44, +0x00,0x43,0x10,0x21,0x8c,0x44,0x00,0x18,0x00,0x00,0x00,0x00,0x8c,0x83,0x00,0x04, +0x00,0x00,0x00,0x00,0x30,0x63,0x00,0x10,0x14,0x60,0x00,0x18,0x00,0x00,0x00,0x00, +0x8f,0xa5,0x00,0x50,0x8f,0xa2,0x00,0x1c,0x00,0x00,0x00,0x00,0x00,0xa2,0x18,0x21, +0x00,0x03,0x18,0x80,0x27,0x82,0x96,0x58,0x00,0x62,0x18,0x21,0x90,0x65,0x00,0x00, +0x27,0x83,0xba,0xe0,0x00,0x05,0x11,0x00,0x00,0x45,0x10,0x23,0x00,0x02,0x10,0x80, +0x00,0x45,0x10,0x23,0x00,0x02,0x30,0x80,0x00,0xc3,0x38,0x21,0x90,0xe4,0x00,0x00, +0x24,0x02,0x00,0x1b,0x10,0x82,0x00,0x0e,0x00,0x00,0x00,0x00,0x8f,0xa2,0x00,0x24, +0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x04,0x00,0xa0,0x20,0x21,0x8f,0xa2,0x00,0x24, +0x08,0x00,0x21,0x99,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x21,0x00,0x00,0x28,0x21, +0x0c,0x00,0x25,0xc4,0x00,0x00,0x38,0x21,0x08,0x00,0x21,0xd7,0x00,0x00,0x00,0x00, +0x27,0x82,0xbb,0xc0,0x00,0xc2,0x20,0x21,0x94,0x83,0x00,0x00,0x24,0x02,0x00,0x05, +0x10,0x43,0x00,0x25,0x24,0x62,0x00,0x01,0xa4,0x82,0x00,0x00,0x8f,0xa3,0x00,0x24, +0x8f,0xa4,0x00,0x28,0x00,0x00,0x00,0x00,0x10,0x64,0xff,0xec,0x00,0x00,0x00,0x00, +0x10,0x60,0xff,0xea,0x00,0x00,0x00,0x00,0x27,0x82,0xbb,0xb8,0x00,0xc2,0x20,0x21, +0x90,0x83,0x00,0x06,0x00,0x00,0x00,0x00,0x2c,0x62,0x00,0x02,0x10,0x40,0x00,0x03, +0x24,0x62,0x00,0x01,0xa0,0x82,0x00,0x06,0x00,0x40,0x18,0x21,0x30,0x63,0x00,0xff, +0x24,0x02,0x00,0x02,0x10,0x62,0x00,0x09,0x00,0x00,0x00,0x00,0x27,0x84,0xba,0xe4, +0x00,0xc4,0x18,0x21,0x8c,0x62,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x02,0x10,0x23, +0x24,0x42,0xff,0xc0,0x08,0x00,0x21,0xd7,0xac,0xe2,0x00,0xd0,0x3c,0x02,0xb0,0x03, +0x34,0x42,0x01,0x08,0x8c,0x43,0x00,0x00,0x27,0x84,0xba,0xe4,0x00,0xc4,0x10,0x21, +0x08,0x00,0x21,0xfc,0xac,0x43,0x00,0xe0,0x27,0x83,0xbb,0xb8,0x00,0xc3,0x18,0x21, +0x90,0x62,0x00,0x06,0x00,0x00,0x00,0x00,0x2c,0x42,0x00,0x02,0x10,0x40,0xff,0xc7, +0xa4,0x80,0x00,0x00,0x08,0x00,0x21,0xd7,0xa0,0x60,0x00,0x06,0x8f,0xa5,0x00,0x48, +0x8f,0xa6,0x00,0x4c,0x03,0xc0,0x20,0x21,0x0c,0x00,0x20,0x4f,0xaf,0xb7,0x00,0x10, +0x08,0x00,0x21,0x76,0x00,0x00,0x00,0x00,0x00,0x05,0x28,0x80,0x27,0x82,0x96,0x40, +0x00,0xa2,0x28,0x21,0x00,0x00,0x20,0x21,0x0c,0x00,0x01,0x49,0x00,0x00,0x00,0x00, +0x08,0x00,0x21,0x6e,0x26,0xe2,0x00,0x01,0x00,0x02,0x80,0x80,0x27,0x83,0x96,0x50, +0x02,0x03,0x18,0x21,0x26,0x31,0x00,0x01,0x03,0xc0,0x20,0x21,0x02,0x40,0x28,0x21, +0x0c,0x00,0x23,0x1c,0xa0,0x71,0x00,0x05,0x14,0x40,0xff,0x45,0x00,0x00,0x00,0x00, +0x16,0xe0,0x00,0x4b,0x02,0xc0,0x38,0x21,0x8f,0xa5,0x00,0x24,0x8f,0xb6,0x00,0x18, +0x8f,0xa3,0x00,0x20,0x24,0xa5,0x00,0x01,0x24,0x02,0x00,0x01,0xaf,0xb2,0x00,0x48, +0xaf,0xb6,0x00,0x4c,0x10,0x62,0x00,0x40,0xaf,0xa5,0x00,0x24,0x27,0x82,0x96,0x40, +0x02,0x02,0x10,0x21,0x94,0x42,0x00,0x06,0x8f,0xa5,0x00,0x30,0xaf,0xa0,0x00,0x20, +0xaf,0xa2,0x00,0x44,0x8f,0xa4,0x00,0x44,0x30,0x42,0x00,0x03,0x00,0x02,0x10,0x23, +0x30,0x42,0x00,0x03,0x00,0x82,0x10,0x21,0x24,0x42,0x00,0x04,0x30,0x42,0xff,0xff, +0x00,0x45,0x18,0x2b,0x10,0x60,0x00,0x29,0x00,0x00,0x00,0x00,0x8f,0xa4,0x00,0x2c, +0x00,0xa2,0x10,0x23,0x00,0x85,0x18,0x21,0x30,0x63,0xff,0xff,0x30,0x45,0xff,0xff, +0xaf,0xa3,0x00,0x2c,0x02,0x92,0x30,0x21,0x00,0x06,0x30,0x80,0x27,0x82,0x96,0x44, +0x00,0xc2,0x10,0x21,0x8c,0x47,0x00,0x18,0x3c,0x04,0x80,0xff,0x34,0x84,0xff,0xff, +0x8c,0xe3,0x00,0x04,0x3c,0x02,0x7f,0x00,0x00,0x05,0x2d,0x40,0x00,0xa2,0x28,0x24, +0x00,0x64,0x18,0x24,0x00,0x65,0x18,0x25,0xac,0xe3,0x00,0x04,0x8f,0xa3,0x00,0x90, +0x27,0x82,0x96,0x50,0x00,0xc2,0x10,0x21,0xa0,0x43,0x00,0x00,0x8c,0xe4,0x00,0x08, +0x00,0x00,0x00,0x00,0x00,0x04,0x27,0xc2,0x10,0x80,0xff,0x0d,0xaf,0xa4,0x00,0x3c, +0x80,0x42,0x00,0x06,0x8f,0xa4,0x00,0x40,0x24,0x42,0x00,0x02,0x00,0x02,0x1f,0xc2, +0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x43,0x00,0x02,0x10,0x40,0x00,0xe2,0x38,0x21, +0xa4,0xe4,0x00,0x00,0x08,0x00,0x21,0x71,0x26,0xb5,0xff,0xff,0x8f,0xa5,0x00,0x2c, +0x00,0x00,0x00,0x00,0x00,0xa2,0x10,0x21,0x30,0x42,0xff,0xff,0xaf,0xa2,0x00,0x2c, +0x08,0x00,0x22,0x4d,0x00,0x00,0x28,0x21,0x08,0x00,0x22,0x37,0xa7,0xd2,0x00,0x14, +0x8f,0xa5,0x00,0x48,0x8f,0xa6,0x00,0x4c,0x03,0xc0,0x20,0x21,0x0c,0x00,0x20,0x4f, +0xaf,0xb7,0x00,0x10,0x08,0x00,0x22,0x2e,0x00,0x00,0xb8,0x21,0x02,0x40,0x20,0x21, +0x0c,0x00,0x17,0x43,0x00,0x00,0x28,0x21,0x00,0x40,0x18,0x21,0x94,0x42,0x00,0x00, +0x00,0x00,0x00,0x00,0x34,0x42,0x08,0x00,0xa4,0x62,0x00,0x00,0x08,0x00,0x21,0x65, +0x02,0x71,0x10,0x21,0x02,0x92,0x18,0x21,0x00,0x03,0x80,0x80,0x27,0x82,0x96,0x44, +0x02,0x02,0x10,0x21,0x8c,0x44,0x00,0x18,0x00,0x00,0x00,0x00,0x8c,0x83,0x00,0x04, +0x00,0x00,0x00,0x00,0x30,0x63,0x00,0x10,0x10,0x60,0x00,0x0a,0x24,0x06,0x00,0x01, +0x93,0x82,0x91,0x51,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x01,0x10,0x40,0xfe,0xd5, +0x00,0x00,0x00,0x00,0x27,0x85,0x96,0x40,0x02,0x05,0x28,0x21,0x08,0x00,0x22,0x1e, +0x3c,0x04,0x00,0x80,0x27,0x83,0x96,0x58,0x27,0x82,0x96,0x50,0x02,0x03,0x18,0x21, +0x02,0x02,0x10,0x21,0x90,0x64,0x00,0x00,0x90,0x45,0x00,0x05,0x0c,0x00,0x25,0xc4, +0x00,0x00,0x38,0x21,0x08,0x00,0x22,0x94,0x00,0x00,0x00,0x00,0x27,0x82,0x96,0x58, +0x02,0x02,0x10,0x21,0x94,0x43,0x00,0x02,0x8f,0xa2,0x00,0x54,0x00,0x03,0x19,0x02, +0x00,0x62,0x18,0x23,0x30,0x63,0x0f,0xff,0x28,0x62,0x00,0x20,0x10,0x40,0x00,0x06, +0x28,0x62,0x00,0x40,0x8f,0xa4,0x00,0x88,0x00,0x00,0x00,0x00,0x00,0x64,0x10,0x06, +0x08,0x00,0x21,0x4c,0x30,0x44,0x00,0x01,0x10,0x40,0x00,0x04,0x00,0x00,0x00,0x00, +0x8f,0xa5,0x00,0x8c,0x08,0x00,0x22,0xb4,0x00,0x65,0x10,0x06,0x08,0x00,0x21,0x4c, +0x00,0x00,0x20,0x21,0x8f,0xa4,0x00,0x90,0x8f,0xa5,0x00,0x38,0x8f,0xa6,0x00,0x34, +0xaf,0xa0,0x00,0x10,0x0c,0x00,0x0d,0xfe,0xaf,0xa2,0x00,0x14,0x30,0x42,0xff,0xff, +0x08,0x00,0x21,0x1c,0xaf,0xa2,0x00,0x40,0x3c,0x02,0xb0,0x03,0x3c,0x03,0x80,0x01, +0x27,0xbd,0xff,0xe0,0x34,0x42,0x00,0x20,0x24,0x63,0x8b,0x18,0xaf,0xb1,0x00,0x14, +0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x18,0xac,0x43,0x00,0x00,0x90,0x82,0x00,0x0a, +0x00,0x80,0x80,0x21,0x14,0x40,0x00,0x45,0x00,0x00,0x88,0x21,0x92,0x02,0x00,0x04, +0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x3c,0x00,0x00,0x00,0x00,0x12,0x20,0x00,0x18, +0x00,0x00,0x00,0x00,0x92,0x02,0x00,0x16,0x92,0x05,0x00,0x0a,0x30,0x42,0x00,0xfc, +0x10,0xa0,0x00,0x03,0xa2,0x02,0x00,0x16,0x34,0x42,0x00,0x01,0xa2,0x02,0x00,0x16, +0x92,0x04,0x00,0x04,0x00,0x00,0x00,0x00,0x30,0x83,0x00,0xff,0x10,0x60,0x00,0x05, +0x00,0x00,0x00,0x00,0x92,0x02,0x00,0x16,0x00,0x00,0x00,0x00,0x34,0x42,0x00,0x02, +0xa2,0x02,0x00,0x16,0x10,0x60,0x00,0x0a,0x00,0x00,0x00,0x00,0x14,0xa0,0x00,0x08, +0x00,0x00,0x00,0x00,0x96,0x02,0x00,0x00,0xa2,0x00,0x00,0x17,0xa6,0x02,0x00,0x14, +0x8f,0xbf,0x00,0x18,0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20, +0x14,0x80,0x00,0x05,0x24,0x02,0x00,0x01,0x96,0x03,0x00,0x06,0xa2,0x02,0x00,0x17, +0x08,0x00,0x22,0xf0,0xa6,0x03,0x00,0x14,0x96,0x04,0x00,0x00,0x96,0x05,0x00,0x06, +0x27,0x86,0x96,0x40,0x00,0x04,0x10,0xc0,0x00,0x05,0x18,0xc0,0x00,0x44,0x10,0x21, +0x00,0x65,0x18,0x21,0x00,0x02,0x10,0x80,0x00,0x03,0x18,0x80,0x00,0x66,0x18,0x21, +0x00,0x46,0x10,0x21,0x8c,0x65,0x00,0x08,0x8c,0x44,0x00,0x08,0x0c,0x00,0x17,0x34, +0x00,0x00,0x00,0x00,0x30,0x43,0x00,0xff,0x10,0x60,0x00,0x04,0xa2,0x02,0x00,0x17, +0x96,0x02,0x00,0x06,0x08,0x00,0x22,0xf0,0xa6,0x02,0x00,0x14,0x96,0x02,0x00,0x00, +0x08,0x00,0x22,0xf0,0xa6,0x02,0x00,0x14,0x96,0x05,0x00,0x00,0x0c,0x00,0x23,0x1c, +0x02,0x00,0x20,0x21,0x08,0x00,0x22,0xd7,0x02,0x22,0x88,0x21,0x94,0x85,0x00,0x06, +0x0c,0x00,0x23,0x1c,0x00,0x00,0x00,0x00,0x08,0x00,0x22,0xd3,0x00,0x40,0x88,0x21, +0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x01,0x34,0x63,0x00,0x20,0x24,0x42,0x8c,0x70, +0x27,0xbd,0xff,0xf0,0xac,0x62,0x00,0x00,0x00,0x00,0x10,0x21,0x03,0xe0,0x00,0x08, +0x27,0xbd,0x00,0x10,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x01,0x34,0x63,0x00,0x20, +0x24,0x42,0x8c,0x94,0xac,0x62,0x00,0x00,0x90,0x89,0x00,0x0a,0x00,0x80,0x30,0x21, +0x11,0x20,0x00,0x05,0x00,0xa0,0x50,0x21,0x90,0x82,0x00,0x17,0x00,0x00,0x00,0x00, +0x14,0x40,0x00,0x1b,0x00,0x00,0x00,0x00,0x90,0xc7,0x00,0x04,0x00,0x00,0x00,0x00, +0x10,0xe0,0x00,0x1b,0x00,0x00,0x00,0x00,0x94,0xc8,0x00,0x00,0x27,0x83,0x96,0x40, +0x93,0x85,0x91,0x50,0x00,0x08,0x10,0xc0,0x00,0x48,0x10,0x21,0x00,0x02,0x10,0x80, +0x00,0x43,0x10,0x21,0x8c,0x44,0x00,0x08,0x00,0xe5,0x28,0x2b,0x10,0xa0,0x00,0x06, +0x01,0x44,0x18,0x23,0x8f,0x82,0x91,0x68,0x00,0x00,0x00,0x00,0x00,0x43,0x10,0x2b, +0x10,0x40,0x00,0x05,0x00,0x00,0x00,0x00,0x24,0x03,0x00,0x10,0xa4,0xc8,0x00,0x14, +0x03,0xe0,0x00,0x08,0x00,0x60,0x10,0x21,0x11,0x20,0x00,0x05,0x00,0x00,0x00,0x00, +0x94,0xc2,0x00,0x06,0x24,0x03,0x00,0x08,0x08,0x00,0x23,0x48,0xa4,0xc2,0x00,0x14, +0x08,0x00,0x23,0x48,0x00,0x00,0x18,0x21,0x27,0xbd,0xff,0xc8,0xaf,0xb5,0x00,0x2c, +0xaf,0xb4,0x00,0x28,0xaf,0xb3,0x00,0x24,0xaf,0xb0,0x00,0x18,0xaf,0xbf,0x00,0x30, +0xaf,0xb2,0x00,0x20,0xaf,0xb1,0x00,0x1c,0x94,0x91,0x00,0x06,0x00,0x80,0xa0,0x21, +0x3c,0x02,0x80,0x01,0x3c,0x04,0xb0,0x03,0x00,0x11,0xa8,0xc0,0x34,0x84,0x00,0x20, +0x24,0x42,0x8d,0x48,0x02,0xb1,0x48,0x21,0xac,0x82,0x00,0x00,0x00,0x09,0x48,0x80, +0x24,0x03,0x00,0x01,0x27,0x82,0x96,0x50,0xa2,0x83,0x00,0x12,0x01,0x22,0x10,0x21, +0x27,0x84,0x96,0x44,0x01,0x24,0x20,0x21,0x80,0x48,0x00,0x06,0x8c,0x8a,0x00,0x18, +0x27,0x83,0x96,0x60,0x01,0x23,0x48,0x21,0x8d,0x24,0x00,0x00,0x25,0x08,0x00,0x02, +0x8d,0x42,0x00,0x00,0x8d,0x49,0x00,0x04,0x00,0x08,0x17,0xc2,0x8d,0x43,0x00,0x08, +0x01,0x02,0x40,0x21,0x00,0x04,0x25,0xc2,0x00,0x08,0x40,0x43,0x30,0x84,0x00,0x01, +0x00,0x03,0x1f,0xc2,0x00,0x08,0x40,0x40,0x00,0xe0,0x80,0x21,0x00,0x64,0x18,0x24, +0x00,0x09,0x49,0x42,0x01,0x48,0x10,0x21,0x00,0xa0,0x98,0x21,0x00,0xa0,0x20,0x21, +0x00,0x40,0x38,0x21,0x02,0x00,0x28,0x21,0x14,0x60,0x00,0x19,0x31,0x29,0x00,0x01, +0x94,0x42,0x00,0x00,0x02,0xb1,0x88,0x21,0x02,0x00,0x28,0x21,0x00,0x11,0x88,0x80, +0x27,0x90,0x96,0x40,0x02,0x30,0x80,0x21,0x96,0x03,0x00,0x06,0x30,0x52,0xff,0xff, +0x02,0x60,0x20,0x21,0x00,0x60,0x30,0x21,0xa6,0x83,0x00,0x1a,0x27,0x82,0x96,0x48, +0x0c,0x00,0x0d,0xd7,0x02,0x22,0x88,0x21,0x00,0x52,0x10,0x21,0x96,0x03,0x00,0x06, +0xa6,0x22,0x00,0x04,0x8f,0xbf,0x00,0x30,0x7b,0xb4,0x01,0x7c,0x7b,0xb2,0x01,0x3c, +0x7b,0xb0,0x00,0xfc,0x00,0x60,0x10,0x21,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x38, +0xaf,0xa9,0x00,0x10,0x0c,0x00,0x0d,0xfe,0xaf,0xa0,0x00,0x14,0x08,0x00,0x23,0x86, +0x02,0xb1,0x88,0x21,0x27,0xbd,0xff,0xc0,0xaf,0xbe,0x00,0x38,0xaf,0xb7,0x00,0x34, +0xaf,0xb6,0x00,0x30,0xaf,0xb5,0x00,0x2c,0xaf,0xb3,0x00,0x24,0xaf,0xb1,0x00,0x1c, +0xaf,0xbf,0x00,0x3c,0xaf,0xb4,0x00,0x28,0xaf,0xb2,0x00,0x20,0xaf,0xb0,0x00,0x18, +0x94,0x90,0x00,0x00,0x3c,0x08,0xb0,0x03,0x35,0x08,0x00,0x20,0x00,0x10,0x10,0xc0, +0x00,0x50,0x18,0x21,0x00,0x40,0x88,0x21,0x3c,0x02,0x80,0x01,0x00,0x03,0x48,0x80, +0x24,0x42,0x8e,0x84,0x00,0x80,0x98,0x21,0x27,0x84,0x96,0x50,0x01,0x24,0x20,0x21, +0x93,0xb7,0x00,0x53,0xad,0x02,0x00,0x00,0x80,0x83,0x00,0x06,0x27,0x82,0x96,0x44, +0x01,0x22,0x10,0x21,0x8c,0x44,0x00,0x18,0x24,0x63,0x00,0x02,0x00,0x03,0x17,0xc2, +0x8c,0x88,0x00,0x08,0x00,0x62,0x18,0x21,0x00,0x03,0x18,0x43,0x00,0x03,0x18,0x40, +0xaf,0xa7,0x00,0x4c,0x2c,0xa2,0x00,0x10,0x00,0xa0,0xa8,0x21,0x00,0x83,0x50,0x21, +0x00,0x08,0x47,0xc2,0x00,0xc0,0x58,0x21,0x00,0x00,0xb0,0x21,0x8c,0x92,0x00,0x0c, +0x14,0x40,0x00,0x13,0x00,0x00,0xf0,0x21,0x92,0x67,0x00,0x04,0x24,0x14,0x00,0x01, +0x12,0x87,0x00,0x10,0x02,0x30,0x10,0x21,0x27,0x83,0x96,0x58,0x01,0x23,0x18,0x21, +0x80,0x64,0x00,0x00,0x27,0x83,0xbb,0xb0,0x00,0x04,0x11,0x00,0x00,0x44,0x10,0x23, +0x00,0x02,0x10,0x80,0x00,0x44,0x10,0x23,0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21, +0x90,0x44,0x00,0x04,0x00,0x00,0x00,0x00,0x10,0x80,0x00,0x23,0x00,0x00,0x00,0x00, +0x02,0x30,0x10,0x21,0x00,0x02,0x80,0x80,0x24,0x04,0x00,0x01,0x27,0x83,0x96,0x60, +0xa2,0x64,0x00,0x12,0x02,0x03,0x18,0x21,0x8c,0x62,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x02,0x15,0xc2,0x30,0x42,0x00,0x01,0x01,0x02,0x10,0x24,0x14,0x40,0x00,0x0e, +0x02,0xa0,0x20,0x21,0x27,0x82,0x96,0x40,0x02,0x02,0x10,0x21,0x94,0x43,0x00,0x06, +0x00,0x00,0x00,0x00,0xa6,0x63,0x00,0x1a,0x94,0x42,0x00,0x06,0x7b,0xbe,0x01,0xfc, +0x7b,0xb6,0x01,0xbc,0x7b,0xb4,0x01,0x7c,0x7b,0xb2,0x01,0x3c,0x7b,0xb0,0x00,0xfc, +0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x40,0x8f,0xa5,0x00,0x4c,0x01,0x60,0x30,0x21, +0x01,0x40,0x38,0x21,0xaf,0xa0,0x00,0x10,0x0c,0x00,0x0d,0xfe,0xaf,0xa0,0x00,0x14, +0x08,0x00,0x23,0xed,0x00,0x00,0x00,0x00,0x27,0x83,0x96,0x60,0x01,0x23,0x18,0x21, +0x8c,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x15,0xc2,0x30,0x42,0x00,0x01, +0x01,0x02,0x10,0x24,0x14,0x40,0x00,0xaf,0x00,0xa0,0x20,0x21,0x32,0x4f,0x00,0x03, +0x00,0x12,0x10,0x82,0x25,0xe3,0x00,0x0d,0x30,0x45,0x00,0x07,0x00,0x74,0x78,0x04, +0x10,0xa0,0x00,0x0e,0x00,0x00,0x90,0x21,0x27,0x82,0x86,0xb0,0x00,0x15,0x18,0x40, +0x00,0x62,0x18,0x21,0x94,0x64,0x00,0x00,0x24,0xa2,0x00,0x06,0x00,0x54,0x10,0x04, +0x00,0x44,0x00,0x1a,0x14,0x80,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x0d, +0x00,0x00,0x10,0x12,0x24,0x42,0x00,0x20,0x30,0x52,0xff,0xfc,0x02,0x30,0x10,0x21, +0x27,0x83,0x96,0x50,0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21,0x90,0x44,0x00,0x03, +0x00,0x00,0x00,0x00,0x30,0x83,0x00,0xff,0x2c,0x62,0x00,0x0c,0x14,0x40,0x00,0x04, +0x2c,0x62,0x00,0x19,0x30,0x82,0x00,0x0f,0x24,0x43,0x00,0x0c,0x2c,0x62,0x00,0x19, +0x10,0x40,0x00,0x19,0x24,0x0e,0x00,0x20,0x24,0x62,0xff,0xe9,0x2c,0x42,0x00,0x02, +0x14,0x40,0x00,0x15,0x24,0x0e,0x00,0x08,0x24,0x62,0xff,0xeb,0x2c,0x42,0x00,0x02, +0x14,0x40,0x00,0x11,0x24,0x0e,0x00,0x04,0x24,0x02,0x00,0x14,0x10,0x62,0x00,0x0e, +0x24,0x0e,0x00,0x02,0x24,0x62,0xff,0xef,0x2c,0x42,0x00,0x03,0x14,0x40,0x00,0x0a, +0x24,0x0e,0x00,0x10,0x24,0x62,0xff,0xf1,0x2c,0x42,0x00,0x02,0x14,0x40,0x00,0x06, +0x24,0x0e,0x00,0x04,0x24,0x62,0xff,0xf3,0x2c,0x42,0x00,0x02,0x24,0x0e,0x00,0x02, +0x24,0x03,0x00,0x01,0x00,0x62,0x70,0x0a,0x30,0xe2,0x00,0xff,0x00,0x00,0x48,0x21, +0x00,0x00,0x68,0x21,0x10,0x40,0x00,0x6d,0x00,0x00,0x58,0x21,0x3c,0x14,0x80,0xff, +0x27,0x99,0x96,0x40,0x01,0xf2,0xc0,0x23,0x36,0x94,0xff,0xff,0x01,0xc9,0x10,0x2a, +0x14,0x40,0x00,0x64,0x24,0x03,0x00,0x04,0x00,0x10,0x28,0xc0,0x00,0xb0,0x10,0x21, +0x00,0x02,0x10,0x80,0x00,0x59,0x10,0x21,0x94,0x56,0x00,0x06,0x00,0x00,0x00,0x00, +0x32,0xcc,0x00,0x03,0x00,0x6c,0x10,0x23,0x30,0x42,0x00,0x03,0x02,0xc2,0x10,0x21, +0x24,0x42,0x00,0x04,0x30,0x51,0xff,0xff,0x02,0x32,0x18,0x2b,0x10,0x60,0x00,0x4d, +0x01,0xf1,0x10,0x23,0x02,0x51,0x10,0x23,0x01,0x78,0x18,0x2b,0x10,0x60,0x00,0x34, +0x30,0x44,0xff,0xff,0x29,0x22,0x00,0x40,0x10,0x40,0x00,0x31,0x01,0x72,0x18,0x21, +0x25,0x22,0x00,0x01,0x00,0x02,0x16,0x00,0x00,0x02,0x4e,0x03,0x00,0xb0,0x10,0x21, +0x00,0x02,0x30,0x80,0x27,0x82,0x96,0x44,0x30,0x6b,0xff,0xff,0x00,0xc2,0x18,0x21, +0x8c,0x67,0x00,0x18,0x00,0x04,0x25,0x40,0x3c,0x03,0x7f,0x00,0x8c,0xe2,0x00,0x04, +0x00,0x83,0x20,0x24,0x27,0x83,0x96,0x50,0x00,0x54,0x10,0x24,0x00,0xc3,0x28,0x21, +0x00,0x44,0x10,0x25,0xac,0xe2,0x00,0x04,0x16,0xe0,0x00,0x02,0xa0,0xb5,0x00,0x00, +0xa0,0xb5,0x00,0x03,0x27,0x84,0x96,0x60,0x00,0xc4,0x18,0x21,0x8c,0x62,0x00,0x00, +0x8c,0xe8,0x00,0x08,0x00,0x02,0x15,0xc2,0x00,0x08,0x47,0xc2,0x30,0x42,0x00,0x01, +0x01,0x02,0x10,0x24,0x10,0x40,0x00,0x0a,0x00,0x00,0x00,0x00,0x80,0xa2,0x00,0x06, +0x00,0x00,0x00,0x00,0x24,0x42,0x00,0x02,0x00,0x02,0x1f,0xc2,0x00,0x43,0x10,0x21, +0x00,0x02,0x10,0x43,0x00,0x02,0x10,0x40,0x00,0xe2,0x50,0x21,0xa5,0x5e,0x00,0x00, +0x92,0x62,0x00,0x04,0x25,0xad,0x00,0x01,0x27,0x84,0x96,0x40,0x00,0xc4,0x18,0x21, +0x01,0xa2,0x10,0x2a,0x94,0x70,0x00,0x02,0x14,0x40,0xff,0xb8,0x00,0x00,0x00,0x00, +0x96,0x63,0x00,0x14,0x00,0x0c,0x10,0x23,0xa2,0x69,0x00,0x12,0x30,0x42,0x00,0x03, +0x01,0x62,0x10,0x23,0x00,0x03,0x80,0xc0,0x8f,0xa5,0x00,0x4c,0x30,0x4b,0xff,0xff, +0x02,0x03,0x80,0x21,0x27,0x82,0x96,0x48,0x00,0x10,0x80,0x80,0xa6,0x6b,0x00,0x1a, +0x02,0xa0,0x20,0x21,0x01,0x60,0x30,0x21,0x01,0x60,0x88,0x21,0x0c,0x00,0x0d,0xd7, +0x02,0x02,0x80,0x21,0x00,0x5e,0x10,0x21,0xa6,0x02,0x00,0x04,0x08,0x00,0x23,0xf3, +0x02,0x20,0x10,0x21,0x01,0x62,0x10,0x2b,0x10,0x40,0xff,0xe9,0x00,0x00,0x20,0x21, +0x29,0x22,0x00,0x40,0x10,0x40,0xff,0xe6,0x01,0x71,0x18,0x21,0x08,0x00,0x24,0x69, +0x25,0x22,0x00,0x01,0x08,0x00,0x24,0x98,0x32,0xcc,0x00,0x03,0x08,0x00,0x24,0x98, +0x00,0x00,0x60,0x21,0x8f,0xa5,0x00,0x4c,0x01,0x40,0x38,0x21,0xaf,0xa0,0x00,0x10, +0x0c,0x00,0x0d,0xfe,0xaf,0xb4,0x00,0x14,0x92,0x67,0x00,0x04,0x08,0x00,0x24,0x0b, +0x30,0x5e,0xff,0xff,0x30,0x84,0xff,0xff,0x00,0x04,0x30,0xc0,0x00,0xc4,0x20,0x21, +0x00,0x04,0x20,0x80,0x27,0x82,0x96,0x40,0x3c,0x03,0xb0,0x08,0x30,0xa5,0xff,0xff, +0x00,0x82,0x20,0x21,0x00,0xc3,0x30,0x21,0xac,0xc5,0x00,0x00,0x03,0xe0,0x00,0x08, +0xa4,0x85,0x00,0x00,0x30,0x84,0xff,0xff,0x00,0x04,0x30,0xc0,0x00,0xc4,0x30,0x21, +0x27,0x88,0x96,0x40,0x00,0x06,0x30,0x80,0x00,0xc8,0x30,0x21,0x94,0xc3,0x00,0x04, +0x3c,0x02,0xb0,0x08,0x3c,0x07,0xb0,0x03,0x00,0x03,0x20,0xc0,0x00,0x83,0x18,0x21, +0x00,0x03,0x18,0x80,0x00,0x82,0x20,0x21,0x3c,0x02,0x80,0x01,0x30,0xa5,0xff,0xff, +0x00,0x68,0x18,0x21,0x34,0xe7,0x00,0x20,0x24,0x42,0x93,0x34,0xac,0xe2,0x00,0x00, +0xa4,0xc5,0x00,0x02,0xa4,0x65,0x00,0x00,0x03,0xe0,0x00,0x08,0xac,0x85,0x00,0x00, +0x30,0x84,0xff,0xff,0x00,0x04,0x10,0xc0,0x00,0x44,0x10,0x21,0x27,0x89,0x96,0x40, +0x00,0x02,0x10,0x80,0x00,0x49,0x10,0x21,0x97,0x83,0x96,0x30,0x94,0x4a,0x00,0x04, +0x3c,0x02,0xb0,0x08,0x00,0x03,0x38,0xc0,0x00,0x0a,0x40,0xc0,0x00,0xe3,0x18,0x21, +0x01,0x0a,0x28,0x21,0x00,0xe2,0x38,0x21,0x01,0x02,0x40,0x21,0x00,0x03,0x18,0x80, +0x00,0x05,0x28,0x80,0x3c,0x06,0xb0,0x03,0x3c,0x02,0x80,0x01,0x00,0xa9,0x28,0x21, +0x00,0x69,0x18,0x21,0x34,0xc6,0x00,0x20,0x34,0x09,0xff,0xff,0x24,0x42,0x93,0x90, +0xac,0xc2,0x00,0x00,0xa4,0x64,0x00,0x00,0xac,0xe4,0x00,0x00,0xa4,0xa9,0x00,0x00, +0xad,0x09,0x00,0x00,0xa7,0x8a,0x96,0x30,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00, +0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x01,0x34,0x63,0x00,0x20,0x24,0x42,0x94,0x10, +0x3c,0x04,0xb0,0x03,0xac,0x62,0x00,0x00,0x34,0x84,0x01,0x10,0x8c,0x82,0x00,0x00, +0x97,0x83,0x87,0xf4,0x30,0x42,0xff,0xff,0x10,0x62,0x00,0x16,0x24,0x0a,0x00,0x01, +0xa7,0x82,0x87,0xf4,0xaf,0x80,0xba,0x90,0x00,0x40,0x28,0x21,0x24,0x06,0x00,0x01, +0x27,0x84,0xba,0x94,0x25,0x43,0xff,0xff,0x00,0x66,0x10,0x04,0x00,0xa2,0x10,0x24, +0x14,0x40,0x00,0x07,0x00,0x00,0x00,0x00,0x8c,0x83,0xff,0xfc,0x00,0x00,0x00,0x00, +0x00,0x66,0x10,0x04,0x00,0xa2,0x10,0x24,0x38,0x42,0x00,0x00,0x01,0x42,0x18,0x0a, +0x25,0x4a,0x00,0x01,0x2d,0x42,0x00,0x14,0xac,0x83,0x00,0x00,0x14,0x40,0xff,0xf1, +0x24,0x84,0x00,0x04,0x3c,0x0b,0xb0,0x03,0x00,0x00,0x50,0x21,0x3c,0x0c,0x80,0x00, +0x27,0x89,0xba,0xe0,0x35,0x6b,0x01,0x20,0x8d,0x68,0x00,0x00,0x8d,0x23,0x00,0x04, +0x01,0x0c,0x10,0x24,0x00,0x02,0x17,0xc2,0x11,0x03,0x00,0x37,0xa1,0x22,0x00,0xdc, +0xa1,0x20,0x00,0xd5,0xa1,0x20,0x00,0xd6,0x01,0x20,0x30,0x21,0x00,0x00,0x38,0x21, +0x00,0x00,0x28,0x21,0x01,0x20,0x20,0x21,0x00,0xa8,0x10,0x06,0x30,0x42,0x00,0x01, +0x10,0xe0,0x00,0x10,0xa0,0x82,0x00,0x0a,0x90,0x82,0x00,0x07,0x00,0x00,0x00,0x00, +0x10,0x40,0x00,0x31,0x24,0xa2,0xff,0xff,0xa0,0x82,0x00,0x08,0x90,0x82,0x00,0x0a, +0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x09,0x00,0x00,0x00,0x00,0x90,0x83,0x00,0x08, +0x00,0x00,0x00,0x00,0x00,0x03,0x10,0x40,0x00,0x43,0x10,0x21,0x00,0x46,0x10,0x21, +0xa0,0x45,0x00,0x09,0x90,0x82,0x00,0x0a,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x07, +0x00,0x00,0x00,0x00,0x14,0xe0,0x00,0x04,0x00,0x00,0x00,0x00,0xa0,0xc5,0x00,0xd5, +0x24,0x07,0x00,0x01,0xa0,0x85,0x00,0x08,0xa0,0xc5,0x00,0xd6,0x24,0xa5,0x00,0x01, +0x2c,0xa2,0x00,0x1c,0x14,0x40,0xff,0xe0,0x24,0x84,0x00,0x03,0x90,0xc4,0x00,0xd5, +0x00,0x00,0x28,0x21,0x00,0xa4,0x10,0x2b,0x10,0x40,0x00,0x0b,0x00,0x00,0x00,0x00, +0x00,0xc0,0x18,0x21,0xa0,0x64,0x00,0x08,0x90,0xc2,0x00,0xd5,0x24,0xa5,0x00,0x01, +0xa0,0x62,0x00,0x09,0x90,0xc4,0x00,0xd5,0x00,0x00,0x00,0x00,0x00,0xa4,0x10,0x2b, +0x14,0x40,0xff,0xf8,0x24,0x63,0x00,0x03,0x25,0x4a,0x00,0x01,0x2d,0x42,0x00,0x08, +0xad,0x28,0x00,0x04,0x25,0x6b,0x00,0x04,0x14,0x40,0xff,0xbf,0x25,0x29,0x00,0xec, +0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x90,0x82,0x00,0x05,0x08,0x00,0x25,0x3f, +0xa0,0x82,0x00,0x08,0x97,0x84,0x91,0x5a,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x01, +0x27,0xbd,0xff,0xe8,0x34,0x63,0x00,0x20,0x24,0x42,0x95,0xc4,0xaf,0xbf,0x00,0x10, +0xac,0x62,0x00,0x00,0x00,0x04,0x20,0x42,0x00,0x00,0x40,0x21,0x27,0x8f,0xba,0xe4, +0x00,0x00,0x50,0x21,0x00,0x00,0x58,0x21,0x27,0x98,0xbb,0xc4,0x27,0x99,0xbb,0xc0, +0x27,0x8e,0xbb,0xbe,0x27,0x8c,0xba,0xe8,0x27,0x8d,0xbb,0x40,0x27,0x89,0xbb,0xb8, +0x00,0x0a,0x18,0x80,0x01,0x6f,0x10,0x21,0xac,0x40,0x00,0x00,0xac,0x44,0x00,0x58, +0x00,0x6e,0x28,0x21,0x00,0x78,0x10,0x21,0xa1,0x20,0xff,0xfc,0xad,0x20,0x00,0x00, +0xa1,0x20,0x00,0x04,0xa1,0x20,0x00,0x05,0xad,0x20,0xff,0xf8,0x00,0x79,0x18,0x21, +0x24,0x06,0x00,0x01,0x24,0xc6,0xff,0xff,0xa0,0xa0,0x00,0x00,0xa4,0x60,0x00,0x00, +0xac,0x40,0x00,0x00,0x24,0x63,0x00,0x02,0x24,0x42,0x00,0x04,0x04,0xc1,0xff,0xf9, +0x24,0xa5,0x00,0x01,0x00,0x0a,0x10,0x80,0x00,0x4d,0x28,0x21,0x00,0x00,0x30,0x21, +0x00,0x4c,0x18,0x21,0x27,0x87,0x87,0xf8,0x8c,0xe2,0x00,0x00,0x24,0xe7,0x00,0x04, +0xac,0xa2,0x00,0x00,0xa0,0x66,0x00,0x00,0xa0,0x66,0x00,0x01,0x24,0xc6,0x00,0x01, +0x28,0xc2,0x00,0x1c,0xa0,0x60,0x00,0x02,0x24,0xa5,0x00,0x04,0x14,0x40,0xff,0xf6, +0x24,0x63,0x00,0x03,0x25,0x08,0x00,0x01,0x29,0x02,0x00,0x08,0x25,0x4a,0x00,0x3b, +0x25,0x29,0x00,0xec,0x14,0x40,0xff,0xd6,0x25,0x6b,0x00,0xec,0xa7,0x80,0x87,0xf4, +0x00,0x00,0x40,0x21,0x27,0x83,0xba,0x90,0xac,0x68,0x00,0x00,0x25,0x08,0x00,0x01, +0x29,0x02,0x00,0x0c,0x14,0x40,0xff,0xfc,0x24,0x63,0x00,0x04,0x0c,0x00,0x25,0x04, +0x00,0x00,0x00,0x00,0x27,0x83,0xba,0xe0,0x24,0x08,0x00,0x07,0x90,0x62,0x00,0xd6, +0x25,0x08,0xff,0xff,0xa0,0x62,0x00,0x00,0x05,0x01,0xff,0xfc,0x24,0x63,0x00,0xec, +0x8f,0xbf,0x00,0x10,0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18, +0x30,0x84,0x00,0xff,0x00,0x04,0x11,0x00,0x00,0x44,0x10,0x23,0x00,0x02,0x10,0x80, +0x00,0x44,0x10,0x23,0x00,0x02,0x10,0x80,0x27,0x83,0xba,0xe0,0x00,0x43,0x40,0x21, +0x3c,0x04,0xb0,0x03,0x3c,0x02,0x80,0x01,0x34,0x84,0x00,0x20,0x24,0x42,0x97,0x10, +0x30,0xc6,0x00,0xff,0xac,0x82,0x00,0x00,0x30,0xa5,0x00,0xff,0x30,0xe7,0x00,0xff, +0x10,0xc0,0x00,0x41,0x25,0x0f,0x00,0xd0,0x91,0x03,0x00,0x00,0x00,0x00,0x00,0x00, +0x24,0x62,0xff,0xee,0x2c,0x42,0x00,0x02,0x14,0x40,0x00,0x31,0x30,0x63,0x00,0xff, +0x24,0x02,0x00,0x1a,0x10,0x62,0x00,0x2e,0x24,0x02,0x00,0x1b,0x10,0x62,0x00,0x2c, +0x24,0x02,0x00,0x11,0x10,0x62,0x00,0x1e,0x24,0x02,0x00,0x18,0x10,0x62,0x00,0x1c, +0x24,0x02,0x00,0x19,0x10,0x62,0x00,0x1a,0x00,0x00,0x00,0x00,0x14,0xa0,0x00,0x06, +0x24,0x02,0x00,0x01,0x8d,0x02,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x42,0x00,0x02, +0x03,0xe0,0x00,0x08,0xad,0x02,0x00,0xd0,0x10,0xa2,0x00,0x0e,0x00,0x00,0x00,0x00, +0x24,0x02,0x00,0x02,0x10,0xa2,0x00,0x09,0x24,0x02,0x00,0x03,0x10,0xa2,0x00,0x04, +0x00,0x00,0x00,0x00,0x8d,0x02,0x00,0xd0,0x08,0x00,0x25,0xec,0x24,0x42,0xff,0xe0, +0x8d,0x02,0x00,0xd0,0x08,0x00,0x25,0xec,0x24,0x42,0xff,0xf8,0x03,0xe0,0x00,0x08, +0x00,0x00,0x00,0x00,0x8d,0x02,0x00,0xd0,0x08,0x00,0x25,0xec,0x24,0x42,0x00,0x01, +0x10,0xa0,0xff,0xe8,0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0xfa,0x00,0x00,0x00,0x00, +0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0xf5,0x24,0x02,0x00,0x03,0x14,0xa2,0xff,0xed, +0x00,0x00,0x00,0x00,0x8d,0x02,0x00,0xd0,0x08,0x00,0x25,0xec,0x24,0x42,0xff,0xe8, +0x10,0xa0,0xff,0xf0,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0xeb, +0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0xe6,0x00,0x00,0x00,0x00,0x8d,0x02,0x00,0xd0, +0x08,0x00,0x25,0xec,0x24,0x42,0xff,0xd0,0x91,0x06,0x00,0x00,0x91,0x03,0x00,0xd4, +0x25,0x0d,0x00,0x5c,0x30,0xc4,0x00,0xff,0x00,0x04,0x10,0x40,0x00,0x44,0x10,0x21, +0x00,0x04,0x50,0x80,0x01,0x02,0x58,0x21,0x01,0x0a,0x48,0x21,0x00,0xc0,0x60,0x21, +0x25,0x78,0x00,0x08,0x10,0x60,0x00,0x36,0x25,0x2e,0x00,0x60,0x10,0xa0,0x00,0x25, +0x00,0x00,0x00,0x00,0x91,0x02,0x00,0xdd,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x1e, +0x00,0x00,0x00,0x00,0x27,0x86,0x87,0xf8,0x01,0x46,0x10,0x21,0x8c,0x43,0x00,0x00, +0x00,0x00,0x00,0x00,0xad,0x23,0x00,0x60,0x91,0x62,0x00,0x08,0x00,0x00,0x00,0x00, +0x00,0x40,0x60,0x21,0xa1,0x02,0x00,0x00,0x31,0x82,0x00,0xff,0x00,0x02,0x10,0x80, +0x00,0x46,0x10,0x21,0x8c,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x18,0x42, +0xad,0xa3,0x00,0x00,0x91,0x04,0x00,0x00,0x8d,0xc5,0x00,0x00,0x00,0x04,0x20,0x80, +0x00,0x86,0x10,0x21,0x8c,0x43,0x00,0x00,0x00,0x05,0x28,0x40,0x00,0x88,0x20,0x21, +0x00,0x03,0x32,0x80,0x00,0xa6,0x10,0x2b,0x00,0xc2,0x28,0x0a,0xac,0x85,0x00,0x60, +0x03,0xe0,0x00,0x08,0xa1,0x00,0x00,0xd4,0x27,0x86,0x87,0xf8,0x08,0x00,0x26,0x32, +0xa1,0x00,0x00,0xdd,0x27,0x82,0x88,0x68,0x8d,0x03,0x00,0xd8,0x00,0x82,0x10,0x21, +0x90,0x44,0x00,0x00,0x24,0x63,0x00,0x01,0x00,0x64,0x20,0x2b,0x14,0x80,0xff,0xab, +0xad,0x03,0x00,0xd8,0x8d,0x22,0x00,0x60,0xa1,0x00,0x00,0xd4,0x00,0x02,0x1f,0xc2, +0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x43,0x03,0xe0,0x00,0x08,0xad,0x02,0x00,0x5c, +0x10,0xe0,0x00,0x14,0x24,0xc2,0xff,0xee,0x2c,0x42,0x00,0x02,0x14,0x40,0x00,0xa4, +0x24,0x02,0x00,0x1a,0x10,0x82,0x00,0xa2,0x24,0x02,0x00,0x1b,0x10,0x82,0x00,0xa0, +0x24,0x02,0x00,0x11,0x10,0x82,0x00,0x92,0x24,0x02,0x00,0x18,0x10,0x82,0x00,0x90, +0x24,0x02,0x00,0x19,0x10,0x82,0x00,0x8e,0x00,0x00,0x00,0x00,0x14,0xa0,0x00,0x7c, +0x24,0x02,0x00,0x01,0x8d,0x02,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x42,0x00,0x02, +0xad,0x02,0x00,0xd0,0x8d,0xe3,0x00,0x00,0x8d,0xa2,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x43,0x10,0x21,0xad,0xa2,0x00,0x00,0xad,0xe0,0x00,0x00,0x8d,0xa3,0x00,0x00, +0x8d,0xc4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x83,0x10,0x2a,0x10,0x40,0x00,0x4d, +0x24,0x02,0x00,0x1b,0x93,0x05,0x00,0x01,0x00,0x00,0x00,0x00,0x10,0x45,0x00,0x21, +0x00,0x00,0x00,0x00,0x91,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x45,0x00,0x05, +0x24,0x02,0x00,0x01,0xa1,0x05,0x00,0x00,0xa1,0x02,0x00,0xd4,0x03,0xe0,0x00,0x08, +0xad,0x00,0x00,0xd8,0x91,0x02,0x00,0xdd,0x24,0x03,0x00,0x01,0x10,0x43,0x00,0x05, +0x00,0x00,0x00,0x00,0xa1,0x03,0x00,0xd4,0xad,0x00,0x00,0xd8,0x03,0xe0,0x00,0x08, +0xa1,0x03,0x00,0xdd,0x00,0x04,0x17,0xc2,0x00,0x82,0x10,0x21,0x00,0x02,0x10,0x43, +0xad,0xa2,0x00,0x00,0x91,0x03,0x00,0x00,0x27,0x82,0x87,0xf8,0x8d,0xc5,0x00,0x00, +0x00,0x03,0x18,0x80,0x00,0x62,0x18,0x21,0x8c,0x64,0x00,0x00,0x00,0x05,0x28,0x40, +0x00,0x04,0x32,0x80,0x00,0xa6,0x10,0x2b,0x00,0xc2,0x28,0x0a,0x08,0x00,0x26,0x44, +0xad,0xc5,0x00,0x00,0x91,0x02,0x00,0xde,0x00,0x00,0x00,0x00,0x2c,0x42,0x00,0x02, +0x14,0x40,0xff,0xdc,0x00,0x04,0x17,0xc2,0x00,0x82,0x10,0x21,0x00,0x02,0x10,0x43, +0xad,0xa2,0x00,0x00,0x91,0x03,0x00,0x00,0x27,0x82,0x87,0xf8,0x8d,0xc5,0x00,0x00, +0x00,0x03,0x18,0x80,0x00,0x62,0x18,0x21,0x8c,0x64,0x00,0x00,0x00,0x05,0x28,0x40, +0x3c,0x03,0xb0,0x03,0x00,0x04,0x32,0x80,0x00,0xa6,0x10,0x2b,0x00,0xc2,0x28,0x0a, +0xad,0xc5,0x00,0x00,0x34,0x63,0x01,0x08,0x8c,0x64,0x00,0x00,0x8d,0x03,0x00,0xe4, +0x00,0x00,0x00,0x00,0x00,0x64,0x10,0x2b,0x14,0x40,0x00,0x03,0x00,0x83,0x28,0x23, +0x00,0x83,0x10,0x23,0x24,0x45,0xff,0xff,0x3c,0x02,0x00,0x98,0x34,0x42,0x96,0x80, +0x00,0x45,0x10,0x2b,0x10,0x40,0x00,0x04,0x00,0x00,0x00,0x00,0xa5,0x00,0x00,0xe0, +0x03,0xe0,0x00,0x08,0xa1,0x00,0x00,0xde,0x24,0x02,0x00,0x03,0x03,0xe0,0x00,0x08, +0xa1,0x02,0x00,0xde,0x97,0x82,0x91,0x5c,0x00,0x00,0x00,0x00,0x00,0x62,0x10,0x2a, +0x10,0x40,0xff,0x32,0x00,0x00,0x00,0x00,0x91,0x02,0x00,0xdd,0x00,0x00,0x00,0x00, +0x14,0x40,0x00,0x15,0x00,0x00,0x00,0x00,0x91,0x03,0x00,0x00,0x27,0x82,0x87,0xf8, +0x00,0x03,0x18,0x80,0x00,0x62,0x10,0x21,0x8c,0x44,0x00,0x00,0x00,0x68,0x18,0x21, +0xac,0x64,0x00,0x60,0x93,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x10,0x80, +0x01,0x02,0x10,0x21,0x24,0x4e,0x00,0x60,0xa1,0x05,0x00,0x00,0x8d,0xc2,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x02,0x1f,0xc2,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x43, +0x03,0xe0,0x00,0x08,0xad,0xa2,0x00,0x00,0x08,0x00,0x26,0xdb,0xa1,0x00,0x00,0xdd, +0x10,0xa2,0x00,0x0c,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0x85, +0x24,0x02,0x00,0x03,0x10,0xa2,0x00,0x04,0x00,0x00,0x00,0x00,0x8d,0x02,0x00,0xd0, +0x08,0x00,0x26,0x6c,0x24,0x42,0xff,0xe0,0x8d,0x02,0x00,0xd0,0x08,0x00,0x26,0x6c, +0x24,0x42,0xff,0xf8,0x8d,0x02,0x00,0xd0,0x08,0x00,0x26,0x6c,0x24,0x42,0x00,0x01, +0x10,0xa0,0xff,0x74,0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0xfa,0x00,0x00,0x00,0x00, +0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0x73,0x24,0x02,0x00,0x03,0x14,0xa2,0xff,0xef, +0x00,0x00,0x00,0x00,0x8d,0x02,0x00,0xd0,0x08,0x00,0x26,0x6c,0x24,0x42,0xff,0xe8, +0x10,0xa0,0xff,0xf0,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0x69, +0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0xe8,0x00,0x00,0x00,0x00,0x8d,0x02,0x00,0xd0, +0x08,0x00,0x26,0x6c,0x24,0x42,0xff,0xd0,0x27,0xbd,0xff,0xe8,0x3c,0x02,0xb0,0x03, +0xaf,0xbf,0x00,0x14,0xaf,0xb0,0x00,0x10,0x34,0x42,0x01,0x18,0x8c,0x50,0x00,0x00, +0x00,0x00,0x00,0x00,0x32,0x03,0x00,0x01,0x14,0x60,0x00,0x14,0x00,0x00,0x00,0x00, +0x32,0x02,0x01,0x00,0x14,0x40,0x00,0x09,0x00,0x00,0x00,0x00,0x32,0x02,0x08,0x00, +0x10,0x40,0x00,0x02,0x24,0x02,0x00,0x01,0xa3,0x82,0x92,0x14,0x8f,0xbf,0x00,0x14, +0x8f,0xb0,0x00,0x10,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18,0x0c,0x00,0x0a,0x65, +0x00,0x00,0x00,0x00,0x26,0x02,0xff,0x00,0xa3,0x80,0x92,0x14,0x3c,0x01,0xb0,0x03, +0xac,0x22,0x01,0x18,0x08,0x00,0x27,0x18,0x32,0x02,0x08,0x00,0x0c,0x00,0x25,0x71, +0x00,0x00,0x00,0x00,0x26,0x02,0xff,0xff,0x3c,0x01,0xb0,0x03,0xac,0x22,0x01,0x18, +0x08,0x00,0x27,0x15,0x32,0x02,0x01,0x00,0x27,0xbd,0xff,0xe0,0x3c,0x02,0xb0,0x03, +0x34,0x42,0x00,0xd0,0xaf,0xbf,0x00,0x18,0x8c,0x43,0x00,0x00,0x3c,0x02,0x00,0x40, +0x24,0x07,0x0f,0xff,0x00,0x03,0x33,0x02,0x00,0x03,0x2d,0x02,0x00,0x03,0x43,0x02, +0x30,0x69,0x0f,0xff,0x00,0x62,0x18,0x24,0x30,0xa5,0x00,0x03,0x30,0xc6,0x00,0xff, +0x10,0x60,0x00,0x08,0x31,0x08,0x00,0xff,0x01,0x00,0x30,0x21,0x0c,0x00,0x27,0x4b, +0xaf,0xa9,0x00,0x10,0x8f,0xbf,0x00,0x18,0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08, +0x27,0xbd,0x00,0x20,0x0c,0x00,0x27,0xae,0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03, +0x34,0x63,0x00,0xd4,0x08,0x00,0x27,0x41,0xac,0x62,0x00,0x00,0x27,0xbd,0xff,0xd8, +0xaf,0xb0,0x00,0x10,0x30,0xd0,0x00,0xff,0x2e,0x02,0x00,0x2e,0xaf,0xb4,0x00,0x20, +0xaf,0xb2,0x00,0x18,0xaf,0xb1,0x00,0x14,0xaf,0xbf,0x00,0x24,0xaf,0xb3,0x00,0x1c, +0x30,0xb1,0x00,0xff,0x8f,0xb4,0x00,0x38,0x14,0x40,0x00,0x07,0x00,0x80,0x90,0x21, +0x8f,0xbf,0x00,0x24,0x8f,0xb4,0x00,0x20,0x7b,0xb2,0x00,0xfc,0x7b,0xb0,0x00,0xbc, +0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x28,0x2e,0x13,0x00,0x10,0x24,0x05,0x00,0x14, +0x0c,0x00,0x18,0xa0,0x24,0x06,0x01,0x07,0x12,0x60,0x00,0x46,0x02,0x40,0x20,0x21, +0x02,0x00,0x90,0x21,0x00,0x14,0x1c,0x00,0x32,0x42,0x00,0x3f,0x24,0x04,0x00,0x50, +0x0c,0x00,0x01,0x31,0x00,0x62,0x80,0x25,0x24,0x03,0x00,0x01,0x12,0x23,0x00,0x3a, +0x2a,0x22,0x00,0x02,0x14,0x40,0x00,0x34,0x24,0x02,0x00,0x02,0x12,0x22,0x00,0x2f, +0x24,0x02,0x00,0x03,0x12,0x22,0x00,0x28,0x02,0x00,0x30,0x21,0x16,0x60,0xff,0xe4, +0x00,0x00,0x00,0x00,0x16,0x40,0x00,0x1f,0x02,0x80,0x80,0x21,0x0c,0x00,0x01,0x31, +0x24,0x04,0x00,0x50,0x24,0x03,0x00,0x01,0x12,0x23,0x00,0x16,0x2a,0x22,0x00,0x02, +0x14,0x40,0x00,0x0f,0x24,0x02,0x00,0x02,0x12,0x22,0x00,0x09,0x24,0x02,0x00,0x03, +0x16,0x22,0xff,0xd7,0x32,0x06,0x0e,0xbf,0x00,0x06,0x34,0x00,0x24,0x04,0x08,0x4c, +0x0c,0x00,0x18,0x5b,0x24,0x05,0xff,0xff,0x08,0x00,0x27,0x58,0x00,0x00,0x00,0x00, +0x32,0x06,0x0e,0xbf,0x00,0x06,0x34,0x00,0x08,0x00,0x27,0x84,0x24,0x04,0x08,0x48, +0x16,0x20,0xff,0xcb,0x32,0x06,0x0e,0xbf,0x00,0x06,0x34,0x00,0x08,0x00,0x27,0x84, +0x24,0x04,0x08,0x40,0x32,0x06,0x0e,0xbf,0x00,0x06,0x34,0x00,0x08,0x00,0x27,0x84, +0x24,0x04,0x08,0x44,0x02,0x20,0x20,0x21,0x0c,0x00,0x28,0x46,0x00,0x00,0x28,0x21, +0x08,0x00,0x27,0x77,0x00,0x40,0x80,0x21,0x24,0x04,0x08,0x4c,0x0c,0x00,0x18,0x5b, +0x24,0x05,0xff,0xff,0x08,0x00,0x27,0x73,0x00,0x00,0x00,0x00,0x02,0x00,0x30,0x21, +0x08,0x00,0x27,0x9b,0x24,0x04,0x08,0x48,0x16,0x20,0xff,0xd0,0x02,0x00,0x30,0x21, +0x08,0x00,0x27,0x9b,0x24,0x04,0x08,0x40,0x02,0x00,0x30,0x21,0x08,0x00,0x27,0x9b, +0x24,0x04,0x08,0x44,0x02,0x00,0x30,0x21,0x0c,0x00,0x27,0xf5,0x02,0x20,0x28,0x21, +0x08,0x00,0x27,0x65,0x00,0x40,0x90,0x21,0x27,0xbd,0xff,0xd8,0x2c,0xc2,0x00,0x2e, +0xaf,0xb3,0x00,0x1c,0xaf,0xb1,0x00,0x14,0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x20, +0xaf,0xb2,0x00,0x18,0x00,0xc0,0x80,0x21,0x30,0xb1,0x00,0xff,0x00,0x80,0x98,0x21, +0x14,0x40,0x00,0x07,0x00,0x00,0x18,0x21,0x8f,0xbf,0x00,0x20,0x7b,0xb2,0x00,0xfc, +0x7b,0xb0,0x00,0xbc,0x00,0x60,0x10,0x21,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x28, +0x2e,0x12,0x00,0x10,0x24,0x05,0x00,0x14,0x0c,0x00,0x18,0xa0,0x24,0x06,0x01,0x07, +0x12,0x40,0x00,0x2a,0x02,0x00,0x10,0x21,0x30,0x45,0x00,0x3f,0x0c,0x00,0x28,0x46, +0x02,0x20,0x20,0x21,0x12,0x40,0x00,0x03,0x00,0x40,0x98,0x21,0x08,0x00,0x27,0xba, +0x02,0x60,0x18,0x21,0x02,0x20,0x20,0x21,0x0c,0x00,0x28,0x46,0x00,0x00,0x28,0x21, +0x24,0x04,0x00,0x50,0x0c,0x00,0x01,0x31,0x00,0x40,0x80,0x21,0x24,0x03,0x00,0x01, +0x12,0x23,0x00,0x16,0x2a,0x22,0x00,0x02,0x14,0x40,0x00,0x0f,0x24,0x02,0x00,0x02, +0x12,0x22,0x00,0x09,0x24,0x02,0x00,0x03,0x16,0x22,0xff,0xf0,0x32,0x06,0x0e,0xbf, +0x00,0x06,0x34,0x00,0x24,0x04,0x08,0x4c,0x0c,0x00,0x18,0x5b,0x24,0x05,0xff,0xff, +0x08,0x00,0x27,0xba,0x02,0x60,0x18,0x21,0x32,0x06,0x0e,0xbf,0x00,0x06,0x34,0x00, +0x08,0x00,0x27,0xde,0x24,0x04,0x08,0x48,0x16,0x20,0xff,0xe4,0x32,0x06,0x0e,0xbf, +0x00,0x06,0x34,0x00,0x08,0x00,0x27,0xde,0x24,0x04,0x08,0x40,0x32,0x06,0x0e,0xbf, +0x00,0x06,0x34,0x00,0x08,0x00,0x27,0xde,0x24,0x04,0x08,0x44,0x02,0x60,0x20,0x21, +0x02,0x00,0x30,0x21,0x0c,0x00,0x27,0xf5,0x02,0x20,0x28,0x21,0x08,0x00,0x27,0xc7, +0x30,0x45,0x00,0x3f,0x27,0xbd,0xff,0xe0,0xaf,0xb0,0x00,0x10,0x30,0xb0,0x00,0xff, +0x02,0x00,0x20,0x21,0x00,0x00,0x28,0x21,0xaf,0xb1,0x00,0x14,0xaf,0xbf,0x00,0x1c, +0x00,0xc0,0x88,0x21,0x0c,0x00,0x28,0x46,0xaf,0xb2,0x00,0x18,0x00,0x40,0x18,0x21, +0x2e,0x22,0x00,0x1f,0x10,0x40,0x00,0x26,0x2e,0x22,0x00,0x10,0x10,0x40,0x00,0x07, +0x34,0x62,0x01,0x00,0x02,0x20,0x10,0x21,0x8f,0xbf,0x00,0x1c,0x8f,0xb2,0x00,0x18, +0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20,0x24,0x04,0x00,0x50, +0x0c,0x00,0x01,0x31,0x00,0x02,0x94,0x00,0x24,0x03,0x00,0x01,0x12,0x03,0x00,0x15, +0x2a,0x02,0x00,0x02,0x14,0x40,0x00,0x0f,0x24,0x02,0x00,0x02,0x12,0x02,0x00,0x0a, +0x24,0x02,0x00,0x03,0x12,0x02,0x00,0x03,0x02,0x40,0x30,0x21,0x08,0x00,0x28,0x05, +0x26,0x31,0xff,0xf1,0x24,0x04,0x08,0x4c,0x0c,0x00,0x18,0x5b,0x24,0x05,0xff,0xff, +0x08,0x00,0x28,0x05,0x26,0x31,0xff,0xf1,0x02,0x40,0x30,0x21,0x08,0x00,0x28,0x1a, +0x24,0x04,0x08,0x48,0x16,0x00,0xff,0xf5,0x02,0x40,0x30,0x21,0x08,0x00,0x28,0x1a, +0x24,0x04,0x08,0x40,0x02,0x40,0x30,0x21,0x08,0x00,0x28,0x1a,0x24,0x04,0x08,0x44, +0x34,0x62,0x01,0x40,0x24,0x04,0x00,0x50,0x0c,0x00,0x01,0x31,0x00,0x02,0x94,0x00, +0x24,0x03,0x00,0x01,0x12,0x03,0x00,0x15,0x2a,0x02,0x00,0x02,0x14,0x40,0x00,0x0f, +0x24,0x02,0x00,0x02,0x12,0x02,0x00,0x0a,0x24,0x02,0x00,0x03,0x12,0x02,0x00,0x03, +0x02,0x40,0x30,0x21,0x08,0x00,0x28,0x05,0x26,0x31,0xff,0xe2,0x24,0x04,0x08,0x4c, +0x0c,0x00,0x18,0x5b,0x24,0x05,0xff,0xff,0x08,0x00,0x28,0x05,0x26,0x31,0xff,0xe2, +0x02,0x40,0x30,0x21,0x08,0x00,0x28,0x38,0x24,0x04,0x08,0x48,0x16,0x00,0xff,0xf5, +0x02,0x40,0x30,0x21,0x08,0x00,0x28,0x38,0x24,0x04,0x08,0x40,0x02,0x40,0x30,0x21, +0x08,0x00,0x28,0x38,0x24,0x04,0x08,0x44,0x27,0xbd,0xff,0xe0,0x00,0x80,0x10,0x21, +0x24,0x04,0x00,0x50,0xaf,0xb1,0x00,0x14,0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x18, +0x00,0xa0,0x88,0x21,0x0c,0x00,0x01,0x31,0x30,0x50,0x00,0xff,0x24,0x03,0x00,0x01, +0x12,0x03,0x00,0x3e,0x02,0x20,0x30,0x21,0x2a,0x02,0x00,0x02,0x14,0x40,0x00,0x2a, +0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0x12,0x02,0x00,0x19,0x24,0x04,0x08,0x34, +0x24,0x02,0x00,0x03,0x12,0x02,0x00,0x05,0x24,0x04,0x08,0x3c,0x8f,0xbf,0x00,0x18, +0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20,0x0c,0x00,0x18,0x5b, +0x3c,0x05,0x3f,0x00,0x24,0x04,0x08,0x3c,0x3c,0x05,0x80,0x00,0x0c,0x00,0x18,0x5b, +0x00,0x00,0x30,0x21,0x3c,0x05,0x80,0x00,0x24,0x06,0x00,0x01,0x0c,0x00,0x18,0x5b, +0x24,0x04,0x08,0x3c,0x0c,0x00,0x01,0x31,0x24,0x04,0x00,0x28,0x24,0x04,0x08,0xac, +0x0c,0x00,0x18,0x3d,0x24,0x05,0x0f,0xff,0x08,0x00,0x28,0x5b,0x00,0x00,0x00,0x00, +0x0c,0x00,0x18,0x5b,0x3c,0x05,0x3f,0x00,0x24,0x04,0x08,0x34,0x3c,0x05,0x80,0x00, +0x0c,0x00,0x18,0x5b,0x00,0x00,0x30,0x21,0x3c,0x05,0x80,0x00,0x24,0x06,0x00,0x01, +0x0c,0x00,0x18,0x5b,0x24,0x04,0x08,0x34,0x0c,0x00,0x01,0x31,0x24,0x04,0x00,0x28, +0x08,0x00,0x28,0x6c,0x24,0x04,0x08,0xa8,0x16,0x00,0xff,0xdc,0x02,0x20,0x30,0x21, +0x24,0x04,0x08,0x24,0x0c,0x00,0x18,0x5b,0x3c,0x05,0x3f,0x00,0x24,0x04,0x08,0x24, +0x3c,0x05,0x80,0x00,0x0c,0x00,0x18,0x5b,0x00,0x00,0x30,0x21,0x3c,0x05,0x80,0x00, +0x24,0x06,0x00,0x01,0x0c,0x00,0x18,0x5b,0x24,0x04,0x08,0x24,0x0c,0x00,0x01,0x31, +0x24,0x04,0x00,0x28,0x08,0x00,0x28,0x6c,0x24,0x04,0x08,0xa0,0x24,0x04,0x08,0x2c, +0x0c,0x00,0x18,0x5b,0x3c,0x05,0x3f,0x00,0x24,0x04,0x08,0x2c,0x3c,0x05,0x80,0x00, +0x0c,0x00,0x18,0x5b,0x00,0x00,0x30,0x21,0x3c,0x05,0x80,0x00,0x24,0x06,0x00,0x01, +0x0c,0x00,0x18,0x5b,0x24,0x04,0x08,0x2c,0x0c,0x00,0x01,0x31,0x24,0x04,0x00,0x28, +0x08,0x00,0x28,0x6c,0x24,0x04,0x08,0xa4,0x27,0xbd,0xff,0xe8,0xaf,0xbf,0x00,0x10, +0x0c,0x00,0x29,0x4c,0x00,0x00,0x00,0x00,0x0c,0x00,0x29,0x4e,0x00,0x00,0x00,0x00, +0x0c,0x00,0x29,0x75,0x00,0x00,0x00,0x00,0x3c,0x04,0xb0,0x05,0x34,0x84,0x00,0x04, +0x0c,0x00,0x29,0x55,0x34,0x05,0x9c,0x40,0x8f,0xbf,0x00,0x10,0x00,0x00,0x00,0x00, +0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00, +0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x24,0x02,0x00,0x01, +0x03,0xe0,0x00,0x08,0x24,0x02,0x00,0x01,0x97,0x82,0x88,0x90,0x00,0x00,0x00,0x00, +0x2c,0x43,0x00,0x64,0x24,0x42,0x00,0x01,0xa7,0x82,0x88,0x90,0x14,0x60,0x00,0x28, +0x00,0x80,0x30,0x21,0x8c,0x82,0x00,0x00,0x3c,0x03,0x20,0x00,0xa7,0x80,0x88,0x90, +0x00,0x43,0x10,0x24,0x10,0x40,0x00,0x22,0x00,0x00,0x00,0x00,0x8c,0x82,0x00,0x00, +0x3c,0x03,0x80,0x00,0x00,0x43,0x10,0x25,0x97,0x83,0x88,0x84,0xac,0x82,0x00,0x00, +0x8c,0x85,0x00,0x00,0x24,0x63,0x00,0x01,0x3c,0x02,0x40,0x64,0x34,0x42,0x64,0x00, +0x00,0x03,0x24,0x00,0x00,0xa2,0x28,0x25,0x00,0x04,0x24,0x03,0x24,0x02,0x00,0x64, +0xac,0xc5,0x00,0x00,0xa7,0x83,0x88,0x84,0x10,0x82,0x00,0x2b,0x00,0x00,0x00,0x00, +0x87,0x82,0x88,0x86,0x24,0x03,0x00,0x3c,0x10,0x43,0x00,0x21,0x00,0x00,0x00,0x00, +0x87,0x82,0x88,0x88,0x00,0x00,0x00,0x00,0x10,0x43,0x00,0x17,0x00,0x00,0x00,0x00, +0x87,0x83,0x88,0x8a,0x24,0x02,0x00,0x18,0x10,0x62,0x00,0x0d,0x00,0x00,0x00,0x00, +0x87,0x83,0x88,0x8c,0x24,0x02,0x01,0x6d,0x10,0x62,0x00,0x03,0x00,0x00,0x00,0x00, +0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x97,0x82,0x88,0x8e,0xa7,0x80,0x88,0x8c, +0x24,0x42,0x00,0x01,0xa7,0x82,0x88,0x8e,0x08,0x00,0x28,0xe4,0x00,0x00,0x00,0x00, +0x97,0x82,0x88,0x8c,0xa7,0x80,0x88,0x8a,0x24,0x42,0x00,0x01,0xa7,0x82,0x88,0x8c, +0x08,0x00,0x28,0xe0,0x00,0x00,0x00,0x00,0x97,0x82,0x88,0x8a,0xa7,0x80,0x88,0x88, +0x24,0x42,0x00,0x01,0xa7,0x82,0x88,0x8a,0x08,0x00,0x28,0xdc,0x00,0x00,0x00,0x00, +0x97,0x82,0x88,0x88,0xa7,0x80,0x88,0x86,0x24,0x42,0x00,0x01,0xa7,0x82,0x88,0x88, +0x08,0x00,0x28,0xd8,0x00,0x00,0x00,0x00,0x97,0x82,0x88,0x86,0xa7,0x80,0x88,0x84, +0x24,0x42,0x00,0x01,0xa7,0x82,0x88,0x86,0x08,0x00,0x28,0xd4,0x00,0x00,0x00,0x00, +0x00,0x04,0x24,0x00,0x3c,0x03,0xb0,0x07,0x00,0x04,0x24,0x03,0x34,0x63,0x00,0x28, +0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x40,0x10,0x40,0xff,0xfc, +0x00,0x00,0x00,0x00,0x3c,0x01,0xb0,0x07,0xa0,0x24,0x00,0x00,0x03,0xe0,0x00,0x08, +0x00,0x00,0x10,0x21,0x3c,0x02,0xb0,0x07,0x34,0x42,0x00,0x28,0x90,0x43,0x00,0x00, +0x00,0x00,0x00,0x00,0x30,0x63,0x00,0x01,0x10,0x60,0x00,0x06,0x24,0x02,0xff,0xff, +0x3c,0x02,0xb0,0x07,0x90,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x16,0x00, +0x00,0x02,0x16,0x03,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x27,0xbd,0xff,0xe0, +0xaf,0xb0,0x00,0x10,0x3c,0x10,0x04,0xc4,0x00,0x04,0x11,0x00,0x36,0x10,0xb4,0x00, +0x02,0x02,0x00,0x1b,0xaf,0xb1,0x00,0x14,0x3c,0x11,0xb0,0x07,0x36,0x31,0x00,0x18, +0x24,0x04,0x00,0x0a,0xaf,0xbf,0x00,0x18,0x14,0x40,0x00,0x02,0x00,0x00,0x00,0x00, +0x00,0x07,0x00,0x0d,0x00,0x00,0x80,0x12,0x0c,0x00,0x29,0xa1,0x00,0x00,0x00,0x00, +0x92,0x22,0x00,0x00,0x24,0x03,0xff,0x80,0x24,0x04,0x00,0x0a,0x00,0x43,0x10,0x25, +0x0c,0x00,0x29,0xa1,0xa2,0x22,0x00,0x00,0x24,0x04,0x00,0x0a,0x3c,0x01,0xb0,0x07, +0xa0,0x30,0x00,0x00,0x0c,0x00,0x29,0xa1,0x00,0x10,0x82,0x03,0x3c,0x02,0xb0,0x07, +0x34,0x42,0x00,0x08,0xa0,0x50,0x00,0x00,0x0c,0x00,0x29,0xa1,0x24,0x04,0x00,0x0a, +0x92,0x22,0x00,0x00,0x8f,0xbf,0x00,0x18,0x8f,0xb0,0x00,0x10,0x30,0x42,0x00,0x7f, +0xa2,0x22,0x00,0x00,0x8f,0xb1,0x00,0x14,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20, +0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00, +0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03,0x34,0x63,0x00,0x58, +0x8c,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x34,0x42,0x07,0xa4,0x03,0xe0,0x00,0x08, +0xac,0x62,0x00,0x00,0x27,0xbd,0xff,0xf8,0x00,0x80,0x38,0x21,0x00,0xa0,0x30,0x21, +0x00,0x00,0x18,0x21,0x00,0x63,0x00,0x18,0x00,0x00,0x10,0x12,0x00,0xc2,0x10,0x2b, +0x14,0x40,0x00,0x05,0x00,0x00,0x00,0x00,0x24,0x63,0x00,0x01,0x2c,0x62,0x01,0x00, +0x14,0x40,0xff,0xf9,0x00,0x63,0x00,0x18,0x24,0x63,0xff,0xff,0x00,0x63,0x00,0x18, +0x30,0x63,0x00,0xff,0x8c,0xe4,0x00,0x00,0x00,0x03,0x2a,0x00,0x00,0x03,0x1c,0x00, +0x00,0x00,0x10,0x12,0x00,0xc2,0x10,0x23,0x30,0x42,0x00,0xff,0x00,0x45,0x10,0x21, +0x00,0x43,0x10,0x21,0x00,0x82,0x20,0x25,0xac,0xe4,0x00,0x00,0x8c,0xe2,0x00,0x00, +0x3c,0x03,0x40,0x00,0x00,0x43,0x10,0x25,0xac,0xe2,0x00,0x00,0x03,0xe0,0x00,0x08, +0x27,0xbd,0x00,0x08,0x27,0xbd,0xff,0xe0,0xaf,0xbf,0x00,0x18,0xaf,0xb1,0x00,0x14, +0xaf,0xb0,0x00,0x10,0x3c,0x04,0xb0,0x03,0x8c,0x82,0x00,0x00,0x3c,0x06,0xb0,0x03, +0x34,0xc6,0x00,0x08,0x34,0x42,0x40,0x00,0xac,0x82,0x00,0x00,0x8c,0x83,0x00,0x00, +0x24,0x02,0xcf,0xff,0x3c,0x11,0xb0,0x07,0x00,0x62,0x18,0x24,0xac,0x83,0x00,0x00, +0x8c,0xc5,0x00,0x00,0x3c,0x02,0x00,0xff,0x24,0x04,0x00,0x0a,0x00,0xa2,0x28,0x25, +0xac,0xc5,0x00,0x00,0x0c,0x00,0x29,0xa1,0x36,0x31,0x00,0x18,0x24,0x02,0xff,0x83, +0x3c,0x04,0x00,0x01,0xa2,0x22,0x00,0x00,0x0c,0x00,0x29,0x1f,0x34,0x84,0xc2,0x00, +0x0c,0x00,0x29,0xa1,0x24,0x04,0x00,0x0a,0x24,0x02,0x00,0x03,0xa2,0x22,0x00,0x00, +0x24,0x04,0x00,0x0a,0x0c,0x00,0x29,0xa1,0x3c,0x10,0xb0,0x07,0x36,0x10,0x00,0x10, +0x24,0x02,0x00,0x06,0xa2,0x02,0x00,0x00,0x0c,0x00,0x29,0xa1,0x24,0x04,0x00,0x0a, +0xa2,0x00,0x00,0x00,0x8f,0xbf,0x00,0x18,0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08, +0x27,0xbd,0x00,0x20,0x10,0x80,0x00,0x05,0x00,0x00,0x18,0x21,0x24,0x63,0x00,0x01, +0x00,0x64,0x10,0x2b,0x14,0x40,0xff,0xfd,0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08, +0x00,0x00,0x00,0x00,0x27,0xbd,0xff,0xc0,0xaf,0xb5,0x00,0x34,0xaf,0xb2,0x00,0x28, +0xaf,0xb0,0x00,0x20,0xaf,0xbf,0x00,0x38,0xaf,0xb4,0x00,0x30,0xaf,0xb3,0x00,0x2c, +0xaf,0xb1,0x00,0x24,0xaf,0xa5,0x00,0x44,0x90,0xa7,0x00,0x00,0x00,0x80,0xa8,0x21, +0x00,0xc0,0x90,0x21,0x00,0x07,0x1e,0x00,0x10,0x60,0x00,0x0f,0x00,0x80,0x80,0x21, +0x00,0x03,0x1e,0x03,0x24,0x02,0x00,0x25,0x10,0x62,0x00,0x13,0x00,0x00,0x88,0x21, +0xa2,0x07,0x00,0x00,0x8f,0xa5,0x00,0x44,0x26,0x10,0x00,0x01,0x24,0xa5,0x00,0x01, +0xaf,0xa5,0x00,0x44,0x90,0xa7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x1e,0x00, +0x14,0x60,0xff,0xf3,0x00,0x00,0x00,0x00,0x02,0x15,0x10,0x23,0xa2,0x00,0x00,0x00, +0x8f,0xbf,0x00,0x38,0x7b,0xb4,0x01,0xbc,0x7b,0xb2,0x01,0x7c,0x7b,0xb0,0x01,0x3c, +0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x40,0x24,0xa5,0x00,0x01,0xaf,0xa5,0x00,0x44, +0x80,0xa3,0x00,0x00,0x00,0x00,0x00,0x00,0x24,0x63,0xff,0xe0,0x2c,0x62,0x00,0x11, +0x10,0x40,0x00,0x11,0x00,0xa0,0x38,0x21,0x00,0x03,0x10,0x80,0x3c,0x03,0x80,0x01, +0x24,0x63,0x09,0x98,0x00,0x43,0x10,0x21,0x8c,0x44,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x80,0x00,0x08,0x00,0x00,0x00,0x00,0x08,0x00,0x29,0xce,0x36,0x31,0x00,0x10, +0x08,0x00,0x29,0xce,0x36,0x31,0x00,0x08,0x08,0x00,0x29,0xce,0x36,0x31,0x00,0x20, +0x08,0x00,0x29,0xce,0x36,0x31,0x00,0x04,0x90,0xe4,0x00,0x00,0x3c,0x02,0x80,0x01, +0x24,0x42,0x02,0x14,0x00,0x44,0x10,0x21,0x90,0x43,0x00,0x00,0x00,0x00,0x00,0x00, +0x30,0x63,0x00,0x04,0x14,0x60,0x00,0xfd,0x24,0x14,0xff,0xff,0x00,0x04,0x16,0x00, +0x00,0x02,0x16,0x03,0x24,0x03,0x00,0x2a,0x10,0x43,0x00,0xee,0x26,0x42,0x00,0x03, +0x80,0xa3,0x00,0x00,0x24,0x02,0x00,0x2e,0x10,0x62,0x00,0xcc,0x24,0x08,0xff,0xff, +0x80,0xa3,0x00,0x00,0x24,0x02,0x00,0x68,0x10,0x62,0x00,0xc4,0x24,0x06,0xff,0xff, +0x24,0x02,0x00,0x6c,0x10,0x62,0x00,0xc1,0x24,0x02,0x00,0x4c,0x10,0x62,0x00,0xbf, +0x24,0x02,0x00,0x5a,0x10,0x62,0x00,0xbd,0x00,0x00,0x00,0x00,0x80,0xa3,0x00,0x00, +0x00,0x00,0x00,0x00,0x24,0x63,0xff,0xdb,0x2c,0x62,0x00,0x54,0x10,0x40,0x00,0xaa, +0x24,0x09,0x00,0x0a,0x00,0x03,0x10,0x80,0x3c,0x03,0x80,0x01,0x24,0x63,0x09,0xdc, +0x00,0x43,0x10,0x21,0x8c,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x08, +0x00,0x00,0x00,0x00,0x32,0x22,0x00,0x10,0x14,0x40,0x00,0x09,0x24,0x02,0xff,0xfc, +0x26,0x94,0xff,0xff,0x1a,0x80,0x00,0x05,0x24,0x02,0x00,0x20,0x26,0x94,0xff,0xff, +0xa2,0x02,0x00,0x00,0x1e,0x80,0xff,0xfd,0x26,0x10,0x00,0x01,0x24,0x02,0xff,0xfc, +0x26,0x44,0x00,0x03,0x00,0x82,0x90,0x24,0x92,0x42,0x00,0x03,0x26,0x94,0xff,0xff, +0x26,0x52,0x00,0x04,0xa2,0x02,0x00,0x00,0x1a,0x80,0x00,0x06,0x26,0x10,0x00,0x01, +0x24,0x02,0x00,0x20,0x26,0x94,0xff,0xff,0xa2,0x02,0x00,0x00,0x1e,0x80,0xff,0xfd, +0x26,0x10,0x00,0x01,0x8f,0xa5,0x00,0x44,0x08,0x00,0x29,0xc0,0x24,0xa5,0x00,0x01, +0x24,0x02,0x00,0x25,0x08,0x00,0x29,0xbd,0xa2,0x02,0x00,0x00,0x36,0x31,0x00,0x40, +0x24,0x09,0x00,0x10,0x24,0x02,0x00,0x4c,0x10,0xc2,0x00,0x2a,0x24,0x02,0x00,0x6c, +0x10,0xc2,0x00,0x05,0x24,0x02,0x00,0x5a,0x10,0xc2,0x00,0x1f,0x24,0x02,0x00,0x68, +0x10,0xc2,0x00,0x13,0x24,0x02,0xff,0xfc,0x24,0x02,0xff,0xfc,0x26,0x43,0x00,0x03, +0x00,0x62,0x90,0x24,0x32,0x22,0x00,0x02,0x8e,0x47,0x00,0x00,0x00,0x00,0x30,0x21, +0x10,0x40,0x00,0x03,0x26,0x52,0x00,0x04,0x00,0xe0,0x10,0x21,0x00,0x02,0x37,0xc3, +0x02,0x00,0x20,0x21,0xaf,0xa9,0x00,0x10,0xaf,0xb4,0x00,0x14,0xaf,0xa8,0x00,0x18, +0x0c,0x00,0x2b,0x0e,0xaf,0xb1,0x00,0x1c,0x08,0x00,0x2a,0x29,0x00,0x40,0x80,0x21, +0x26,0x43,0x00,0x03,0x00,0x62,0x90,0x24,0x32,0x22,0x00,0x02,0x96,0x47,0x00,0x02, +0x00,0x00,0x30,0x21,0x10,0x40,0xff,0xf2,0x26,0x52,0x00,0x04,0x00,0x07,0x14,0x00, +0x08,0x00,0x2a,0x43,0x00,0x02,0x3c,0x03,0x26,0x42,0x00,0x03,0x24,0x03,0xff,0xfc, +0x00,0x43,0x90,0x24,0x8e,0x47,0x00,0x00,0x00,0x00,0x30,0x21,0x08,0x00,0x2a,0x44, +0x26,0x52,0x00,0x04,0x26,0x42,0x00,0x07,0x24,0x03,0xff,0xf8,0x00,0x43,0x90,0x24, +0x8e,0x46,0x00,0x00,0x8e,0x47,0x00,0x04,0x08,0x00,0x2a,0x44,0x26,0x52,0x00,0x08, +0x08,0x00,0x2a,0x31,0x36,0x31,0x00,0x02,0x26,0x44,0x00,0x03,0x24,0x02,0xff,0xfc, +0x00,0x82,0x90,0x24,0x8e,0x44,0x00,0x00,0x02,0x15,0x10,0x23,0x26,0x52,0x00,0x04, +0x08,0x00,0x29,0xbf,0xac,0x82,0x00,0x00,0x08,0x00,0x2a,0x31,0x24,0x09,0x00,0x08, +0x24,0x02,0xff,0xff,0x12,0x82,0x00,0x11,0x00,0x00,0x00,0x00,0x26,0x43,0x00,0x03, +0x24,0x02,0xff,0xfc,0x00,0x62,0x90,0x24,0x8e,0x47,0x00,0x00,0x02,0x00,0x20,0x21, +0x24,0x02,0x00,0x10,0x00,0x00,0x30,0x21,0xaf,0xa2,0x00,0x10,0xaf,0xb4,0x00,0x14, +0xaf,0xa8,0x00,0x18,0x0c,0x00,0x2b,0x0e,0xaf,0xb1,0x00,0x1c,0x8f,0xa5,0x00,0x44, +0x00,0x40,0x80,0x21,0x08,0x00,0x29,0xbf,0x26,0x52,0x00,0x04,0x24,0x14,0x00,0x08, +0x08,0x00,0x2a,0x73,0x36,0x31,0x00,0x01,0x26,0x42,0x00,0x03,0x24,0x03,0xff,0xfc, +0x00,0x43,0x90,0x24,0x8e,0x53,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x60,0x00,0x23, +0x26,0x52,0x00,0x04,0x02,0x60,0x20,0x21,0x0c,0x00,0x2b,0xdc,0x01,0x00,0x28,0x21, +0x00,0x40,0x20,0x21,0x32,0x22,0x00,0x10,0x14,0x40,0x00,0x09,0x00,0x94,0x10,0x2a, +0x10,0x40,0x00,0x07,0x26,0x94,0xff,0xff,0x24,0x03,0x00,0x20,0x00,0x94,0x10,0x2a, +0xa2,0x03,0x00,0x00,0x26,0x94,0xff,0xff,0x14,0x40,0xff,0xfc,0x26,0x10,0x00,0x01, +0x18,0x80,0x00,0x07,0x00,0x80,0x18,0x21,0x92,0x62,0x00,0x00,0x24,0x63,0xff,0xff, +0x26,0x73,0x00,0x01,0xa2,0x02,0x00,0x00,0x14,0x60,0xff,0xfb,0x26,0x10,0x00,0x01, +0x00,0x94,0x10,0x2a,0x10,0x40,0xff,0x83,0x26,0x94,0xff,0xff,0x24,0x03,0x00,0x20, +0x00,0x94,0x10,0x2a,0xa2,0x03,0x00,0x00,0x26,0x94,0xff,0xff,0x14,0x40,0xff,0xfc, +0x26,0x10,0x00,0x01,0x08,0x00,0x2a,0x29,0x00,0x00,0x00,0x00,0x3c,0x02,0x80,0x01, +0x08,0x00,0x2a,0x8d,0x24,0x53,0x08,0x84,0x24,0x02,0x00,0x25,0xa2,0x02,0x00,0x00, +0x8f,0xa5,0x00,0x44,0x00,0x00,0x00,0x00,0x80,0xa2,0x00,0x00,0x90,0xa3,0x00,0x00, +0x10,0x40,0x00,0x03,0x26,0x10,0x00,0x01,0x08,0x00,0x29,0xbd,0xa2,0x03,0x00,0x00, +0x24,0xa5,0xff,0xff,0x08,0x00,0x29,0xbf,0xaf,0xa5,0x00,0x44,0x80,0xa6,0x00,0x00, +0x24,0xa5,0x00,0x01,0x08,0x00,0x2a,0x03,0xaf,0xa5,0x00,0x44,0x24,0xa5,0x00,0x01, +0xaf,0xa5,0x00,0x44,0x90,0xa4,0x00,0x00,0x3c,0x02,0x80,0x01,0x24,0x42,0x02,0x14, +0x00,0x44,0x10,0x21,0x90,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x63,0x00,0x04, +0x14,0x60,0x00,0x0f,0x00,0x04,0x16,0x00,0x00,0x02,0x16,0x03,0x24,0x03,0x00,0x2a, +0x10,0x43,0x00,0x04,0x26,0x42,0x00,0x03,0x29,0x02,0x00,0x00,0x08,0x00,0x29,0xf8, +0x00,0x02,0x40,0x0b,0x24,0x03,0xff,0xfc,0x00,0x43,0x90,0x24,0x24,0xa5,0x00,0x01, +0x8e,0x48,0x00,0x00,0xaf,0xa5,0x00,0x44,0x08,0x00,0x2a,0xd2,0x26,0x52,0x00,0x04, +0x0c,0x00,0x2a,0xf2,0x27,0xa4,0x00,0x44,0x8f,0xa5,0x00,0x44,0x08,0x00,0x2a,0xd2, +0x00,0x40,0x40,0x21,0x24,0x03,0xff,0xfc,0x00,0x43,0x90,0x24,0x8e,0x54,0x00,0x00, +0x24,0xe5,0x00,0x01,0xaf,0xa5,0x00,0x44,0x06,0x81,0xff,0x0d,0x26,0x52,0x00,0x04, +0x00,0x14,0xa0,0x23,0x08,0x00,0x29,0xf4,0x36,0x31,0x00,0x10,0x0c,0x00,0x2a,0xf2, +0x27,0xa4,0x00,0x44,0x8f,0xa5,0x00,0x44,0x08,0x00,0x29,0xf4,0x00,0x40,0xa0,0x21, +0x08,0x00,0x29,0xce,0x36,0x31,0x00,0x01,0x8c,0x86,0x00,0x00,0x3c,0x02,0x80,0x01, +0x00,0x80,0x48,0x21,0x90,0xc3,0x00,0x00,0x24,0x44,0x02,0x14,0x00,0x64,0x18,0x21, +0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x04,0x10,0x40,0x00,0x10, +0x00,0x00,0x38,0x21,0x00,0x80,0x40,0x21,0x24,0xc2,0x00,0x01,0x80,0xc5,0x00,0x00, +0xad,0x22,0x00,0x00,0x90,0x43,0x00,0x00,0x00,0x40,0x30,0x21,0x00,0x07,0x10,0x80, +0x00,0x68,0x18,0x21,0x90,0x64,0x00,0x00,0x00,0x47,0x10,0x21,0x00,0x02,0x10,0x40, +0x00,0x45,0x10,0x21,0x30,0x84,0x00,0x04,0x14,0x80,0xff,0xf3,0x24,0x47,0xff,0xd0, +0x03,0xe0,0x00,0x08,0x00,0xe0,0x10,0x21,0x27,0xbd,0xff,0x98,0xaf,0xb2,0x00,0x50, +0x8f,0xb2,0x00,0x84,0x3c,0x02,0x80,0x01,0xaf,0xb4,0x00,0x58,0x32,0x43,0x00,0x40, +0xaf,0xb1,0x00,0x4c,0xaf,0xb0,0x00,0x48,0xaf,0xb7,0x00,0x64,0xaf,0xb6,0x00,0x60, +0xaf,0xb5,0x00,0x5c,0xaf,0xb3,0x00,0x54,0x00,0x80,0x68,0x21,0x00,0xc0,0x70,0x21, +0x00,0xe0,0x78,0x21,0x8f,0xb0,0x00,0x78,0x8f,0xb8,0x00,0x7c,0x8f,0xb1,0x00,0x80, +0x10,0x60,0x00,0x03,0x24,0x54,0x08,0x8c,0x3c,0x02,0x80,0x01,0x24,0x54,0x08,0xb4, +0x32,0x42,0x00,0x10,0x10,0x40,0x00,0x04,0x26,0x02,0xff,0xfe,0x24,0x02,0xff,0xfe, +0x02,0x42,0x90,0x24,0x26,0x02,0xff,0xfe,0x2c,0x42,0x00,0x23,0x10,0x40,0x00,0x5d, +0x00,0x00,0x18,0x21,0x32,0x42,0x00,0x01,0x24,0x15,0x00,0x30,0x24,0x03,0x00,0x20, +0x32,0x44,0x00,0x02,0x00,0x62,0xa8,0x0a,0x10,0x80,0x00,0x07,0x00,0x00,0xb8,0x21, +0x05,0xc0,0x00,0x96,0x32,0x42,0x00,0x04,0x10,0x40,0x00,0x90,0x32,0x42,0x00,0x08, +0x24,0x17,0x00,0x2b,0x27,0x18,0xff,0xff,0x32,0x56,0x00,0x20,0x12,0xc0,0x00,0x07, +0x01,0xcf,0x10,0x25,0x24,0x02,0x00,0x10,0x12,0x02,0x00,0x86,0x27,0x03,0xff,0xff, +0x3a,0x02,0x00,0x08,0x00,0x62,0xc0,0x0a,0x01,0xcf,0x10,0x25,0x14,0x40,0x00,0x55, +0x00,0x00,0xc8,0x21,0x24,0x02,0x00,0x30,0x24,0x19,0x00,0x01,0xa3,0xa2,0x00,0x00, +0x02,0x39,0x10,0x2a,0x03,0x22,0x88,0x0b,0x32,0x43,0x00,0x11,0x14,0x60,0x00,0x0a, +0x03,0x11,0xc0,0x23,0x03,0x00,0x10,0x21,0x18,0x40,0x00,0x07,0x27,0x18,0xff,0xff, +0x24,0x03,0x00,0x20,0x03,0x00,0x10,0x21,0xa1,0xa3,0x00,0x00,0x27,0x18,0xff,0xff, +0x1c,0x40,0xff,0xfc,0x25,0xad,0x00,0x01,0x12,0xe0,0x00,0x03,0x00,0x00,0x00,0x00, +0xa1,0xb7,0x00,0x00,0x25,0xad,0x00,0x01,0x12,0xc0,0x00,0x07,0x32,0x42,0x00,0x10, +0x24,0x02,0x00,0x08,0x12,0x02,0x00,0x38,0x24,0x02,0x00,0x10,0x12,0x02,0x00,0x30, +0x24,0x02,0x00,0x30,0x32,0x42,0x00,0x10,0x14,0x40,0x00,0x0a,0x03,0x31,0x10,0x2a, +0x03,0x00,0x10,0x21,0x18,0x40,0x00,0x06,0x27,0x18,0xff,0xff,0x03,0x00,0x10,0x21, +0xa1,0xb5,0x00,0x00,0x27,0x18,0xff,0xff,0x1c,0x40,0xff,0xfc,0x25,0xad,0x00,0x01, +0x03,0x31,0x10,0x2a,0x10,0x40,0x00,0x07,0x26,0x31,0xff,0xff,0x24,0x03,0x00,0x30, +0x03,0x31,0x10,0x2a,0xa1,0xa3,0x00,0x00,0x26,0x31,0xff,0xff,0x14,0x40,0xff,0xfc, +0x25,0xad,0x00,0x01,0x03,0x20,0x10,0x21,0x18,0x40,0x00,0x08,0x27,0x39,0xff,0xff, +0x03,0xb9,0x10,0x21,0x90,0x43,0x00,0x00,0x03,0x20,0x20,0x21,0x27,0x39,0xff,0xff, +0xa1,0xa3,0x00,0x00,0x1c,0x80,0xff,0xfa,0x25,0xad,0x00,0x01,0x03,0x00,0x10,0x21, +0x18,0x40,0x00,0x07,0x27,0x18,0xff,0xff,0x24,0x03,0x00,0x20,0x03,0x00,0x10,0x21, +0xa1,0xa3,0x00,0x00,0x27,0x18,0xff,0xff,0x1c,0x40,0xff,0xfc,0x25,0xad,0x00,0x01, +0x01,0xa0,0x18,0x21,0x7b,0xb6,0x03,0x3c,0x7b,0xb4,0x02,0xfc,0x7b,0xb2,0x02,0xbc, +0x7b,0xb0,0x02,0x7c,0x00,0x60,0x10,0x21,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x68, +0xa1,0xa2,0x00,0x00,0x92,0x83,0x00,0x21,0x25,0xad,0x00,0x01,0xa1,0xa3,0x00,0x00, +0x08,0x00,0x2b,0x61,0x25,0xad,0x00,0x01,0x24,0x02,0x00,0x30,0x08,0x00,0x2b,0x94, +0xa1,0xa2,0x00,0x00,0x01,0xcf,0x10,0x25,0x10,0x40,0xff,0xad,0x00,0x00,0x60,0x21, +0x00,0x0e,0x18,0x02,0x03,0x3d,0x98,0x21,0x00,0x60,0x20,0x21,0x01,0xe0,0x38,0x21, +0x10,0x60,0x00,0x04,0x27,0x39,0x00,0x01,0x00,0x70,0x00,0x1b,0x00,0x00,0x20,0x12, +0x00,0x00,0x18,0x10,0x00,0x80,0x48,0x21,0x00,0xe0,0x30,0x21,0x01,0x80,0x70,0x21, +0x01,0x80,0x28,0x21,0x10,0x00,0x00,0x06,0x24,0x04,0x00,0x21,0x00,0x03,0x08,0x40, +0x00,0x03,0x2f,0xc2,0x00,0x22,0x18,0x25,0x00,0x06,0x30,0x40,0x00,0x0e,0x70,0x40, +0x14,0xa0,0x00,0x02,0x00,0x70,0x10,0x2b,0x14,0x40,0x00,0x03,0x24,0x84,0xff,0xff, +0x00,0x70,0x18,0x23,0x25,0xce,0x00,0x01,0x14,0x80,0xff,0xf4,0x00,0x06,0x17,0xc2, +0x02,0x83,0x18,0x21,0x01,0xc0,0x38,0x21,0x00,0x00,0x50,0x21,0x00,0x09,0x20,0x00, +0x00,0x00,0x28,0x21,0x90,0x66,0x00,0x00,0x00,0x8a,0x70,0x25,0x00,0xa7,0x78,0x25, +0x01,0xcf,0x10,0x25,0x14,0x40,0xff,0xda,0xa2,0x66,0x00,0x00,0x08,0x00,0x2b,0x49, +0x02,0x39,0x10,0x2a,0x08,0x00,0x2b,0x42,0x27,0x18,0xff,0xfe,0x10,0x40,0xff,0x73, +0x32,0x56,0x00,0x20,0x08,0x00,0x2b,0x39,0x24,0x17,0x00,0x20,0x00,0x0f,0x78,0x23, +0x00,0x0e,0x70,0x23,0x00,0x0f,0x10,0x2b,0x01,0xc2,0x70,0x23,0x08,0x00,0x2b,0x39, +0x24,0x17,0x00,0x2d,0x80,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x06, +0x00,0x80,0x18,0x21,0x24,0x63,0x00,0x01,0x80,0x62,0x00,0x00,0x00,0x00,0x00,0x00, +0x14,0x40,0xff,0xfc,0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x00,0x64,0x10,0x23, +0x24,0xa5,0xff,0xff,0x24,0x02,0xff,0xff,0x10,0xa2,0x00,0x0d,0x00,0x80,0x18,0x21, +0x80,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x09,0x00,0x00,0x00,0x00, +0x24,0x06,0xff,0xff,0x24,0xa5,0xff,0xff,0x10,0xa6,0x00,0x05,0x24,0x63,0x00,0x01, +0x80,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x40,0xff,0xfa,0x00,0x00,0x00,0x00, +0x03,0xe0,0x00,0x08,0x00,0x64,0x10,0x23,0x80,0x82,0x00,0x00,0x90,0x88,0x00,0x00, +0x10,0x40,0x00,0x17,0x00,0x00,0x48,0x21,0x90,0xa3,0x00,0x00,0x00,0xa0,0x30,0x21, +0x10,0x60,0x00,0x0b,0x00,0x60,0x38,0x21,0x00,0x08,0x16,0x00,0x00,0x02,0x46,0x03, +0x00,0x07,0x16,0x00,0x00,0x02,0x16,0x03,0x11,0x02,0x00,0x05,0x24,0xc6,0x00,0x01, +0x90,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x60,0xff,0xf9,0x00,0x60,0x38,0x21, +0x00,0x03,0x16,0x00,0x10,0x40,0x00,0x06,0x00,0x00,0x00,0x00,0x24,0x84,0x00,0x01, +0x90,0x82,0x00,0x00,0x25,0x29,0x00,0x01,0x14,0x40,0xff,0xeb,0x00,0x40,0x40,0x21, +0x03,0xe0,0x00,0x08,0x01,0x20,0x10,0x21,0x80,0x82,0x00,0x00,0x90,0x87,0x00,0x00, +0x10,0x40,0x00,0x17,0x00,0x00,0x18,0x21,0x90,0xa2,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x02,0x1e,0x00,0x10,0x60,0x00,0x0c,0x00,0xa0,0x30,0x21,0x00,0x07,0x16,0x00, +0x00,0x02,0x3e,0x03,0x00,0x03,0x16,0x03,0x10,0xe2,0x00,0x0d,0x00,0x80,0x18,0x21, +0x24,0xc6,0x00,0x01,0x90,0xc2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x1e,0x00, +0x14,0x60,0xff,0xf9,0x00,0x03,0x16,0x03,0x24,0x84,0x00,0x01,0x90,0x82,0x00,0x00, +0x00,0x00,0x00,0x00,0x14,0x40,0xff,0xec,0x00,0x40,0x38,0x21,0x00,0x00,0x18,0x21, +0x03,0xe0,0x00,0x08,0x00,0x60,0x10,0x21,0x27,0xbd,0xff,0xe0,0xaf,0xb0,0x00,0x10, +0x8f,0x90,0xc2,0x58,0xaf,0xb1,0x00,0x14,0xaf,0xbf,0x00,0x18,0x00,0x84,0x80,0x0b, +0x00,0x00,0x30,0x21,0x12,0x00,0x00,0x0a,0x00,0xa0,0x88,0x21,0x0c,0x00,0x2b,0xee, +0x02,0x00,0x20,0x21,0x02,0x02,0x80,0x21,0x82,0x02,0x00,0x00,0x02,0x20,0x28,0x21, +0x02,0x00,0x20,0x21,0x14,0x40,0x00,0x07,0x00,0x00,0x30,0x21,0xaf,0x80,0xc2,0x58, +0x8f,0xbf,0x00,0x18,0x7b,0xb0,0x00,0xbc,0x00,0xc0,0x10,0x21,0x03,0xe0,0x00,0x08, +0x27,0xbd,0x00,0x20,0x0c,0x00,0x2c,0x0a,0x00,0x00,0x00,0x00,0x00,0x40,0x18,0x21, +0x10,0x40,0x00,0x07,0x02,0x00,0x30,0x21,0x80,0x42,0x00,0x00,0x00,0x00,0x00,0x00, +0x10,0x40,0x00,0x03,0x00,0x00,0x00,0x00,0xa0,0x60,0x00,0x00,0x24,0x63,0x00,0x01, +0xaf,0x83,0xc2,0x58,0x08,0x00,0x2c,0x38,0x00,0x00,0x00,0x00,0x24,0xc6,0xff,0xff, +0x24,0x02,0xff,0xff,0x10,0xc2,0x00,0x05,0x00,0x80,0x18,0x21,0x24,0xc6,0xff,0xff, +0xa0,0x65,0x00,0x00,0x14,0xc2,0xff,0xfd,0x24,0x63,0x00,0x01,0x03,0xe0,0x00,0x08, +0x00,0x80,0x10,0x21,0x24,0xc6,0xff,0xff,0x24,0x02,0xff,0xff,0x10,0xc2,0x00,0x08, +0x00,0x80,0x18,0x21,0x24,0x07,0xff,0xff,0x90,0xa2,0x00,0x00,0x24,0xc6,0xff,0xff, +0x24,0xa5,0x00,0x01,0xa0,0x62,0x00,0x00,0x14,0xc7,0xff,0xfb,0x24,0x63,0x00,0x01, +0x03,0xe0,0x00,0x08,0x00,0x80,0x10,0x21,0x00,0x80,0x18,0x21,0x90,0xa2,0x00,0x00, +0x24,0xa5,0x00,0x01,0xa0,0x82,0x00,0x00,0x14,0x40,0xff,0xfc,0x24,0x84,0x00,0x01, +0x03,0xe0,0x00,0x08,0x00,0x60,0x10,0x21,0x90,0x83,0x00,0x00,0x90,0xa2,0x00,0x00, +0x24,0x84,0x00,0x01,0x00,0x62,0x10,0x23,0x00,0x02,0x16,0x00,0x00,0x02,0x16,0x03, +0x14,0x40,0x00,0x03,0x24,0xa5,0x00,0x01,0x14,0x60,0xff,0xf7,0x00,0x00,0x00,0x00, +0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x00,0x00,0x10,0x21, +0x3c,0x05,0xb0,0x03,0x3c,0x02,0x80,0x01,0x34,0xa5,0x00,0x20,0x24,0x42,0xb1,0xe0, +0xac,0xa2,0x00,0x00,0x24,0x02,0x00,0x02,0x24,0x03,0x00,0x20,0xac,0x82,0x00,0x64, +0x3c,0x02,0x80,0x01,0xac,0x83,0x00,0x60,0xac,0x80,0x00,0x00,0xac,0x80,0x00,0x04, +0xac,0x80,0x00,0x08,0xac,0x80,0x00,0x4c,0xac,0x80,0x00,0x50,0xac,0x80,0x00,0x54, +0xac,0x80,0x00,0x0c,0xac,0x80,0x00,0x58,0xa0,0x80,0x00,0x5c,0x24,0x42,0xb2,0xb0, +0x24,0x83,0x00,0x68,0x24,0x05,0x00,0x0f,0x24,0xa5,0xff,0xff,0xac,0x62,0x00,0x00, +0x04,0xa1,0xff,0xfd,0x24,0x63,0x00,0x04,0x3c,0x02,0x80,0x01,0x3c,0x03,0x80,0x01, +0x24,0x42,0xb3,0xe0,0x24,0x63,0xb4,0x44,0xac,0x82,0x00,0x78,0xac,0x83,0x00,0x84, +0x3c,0x02,0x80,0x01,0x3c,0x03,0x80,0x01,0x24,0x42,0xb5,0x6c,0x24,0x63,0xb4,0xd8, +0xac,0x82,0x00,0x88,0xac,0x83,0x00,0x98,0x3c,0x02,0x80,0x01,0x3c,0x03,0x80,0x01, +0x24,0x42,0xb6,0x14,0x24,0x63,0xb6,0xd4,0xac,0x82,0x00,0xa0,0xac,0x83,0x00,0xa4, +0xa0,0x80,0x01,0xba,0xac,0x80,0x01,0xa8,0xac,0x80,0x01,0xac,0xac,0x80,0x01,0xb0, +0xac,0x80,0x01,0xb4,0xa0,0x80,0x01,0xb8,0x03,0xe0,0x00,0x08,0xa0,0x80,0x01,0xb9, +0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x01,0x34,0x63,0x00,0x20,0x24,0x42,0xb2,0xb0, +0x03,0xe0,0x00,0x08,0xac,0x62,0x00,0x00,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x01, +0x27,0xbd,0xff,0xe8,0x34,0x63,0x00,0x20,0x24,0x42,0xb2,0xc8,0xaf,0xb0,0x00,0x10, +0xac,0x62,0x00,0x00,0xaf,0xbf,0x00,0x14,0x8c,0x83,0x00,0x10,0x8f,0x82,0x91,0xe8, +0x00,0x80,0x80,0x21,0x3c,0x04,0x80,0x01,0x30,0x46,0x00,0x01,0x10,0x60,0x00,0x11, +0x24,0x84,0x08,0xdc,0x8e,0x02,0x00,0x14,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x0d, +0x00,0x00,0x00,0x00,0x8e,0x05,0x00,0x10,0x8e,0x03,0x00,0x14,0x8e,0x02,0x00,0x04, +0x00,0xa3,0x28,0x21,0x00,0x45,0x10,0x21,0x30,0x43,0x00,0xff,0x00,0x03,0x18,0x2b, +0x00,0x02,0x12,0x02,0x00,0x43,0x10,0x21,0x00,0x02,0x12,0x00,0x30,0x42,0x3f,0xff, +0xae,0x02,0x00,0x04,0x14,0xc0,0x00,0x0a,0x00,0x00,0x00,0x00,0xae,0x00,0x00,0x00, +0xae,0x00,0x00,0x4c,0xae,0x00,0x00,0x50,0xae,0x00,0x00,0x54,0xae,0x00,0x00,0x0c, +0x8f,0xbf,0x00,0x14,0x8f,0xb0,0x00,0x10,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18, +0x8e,0x05,0x00,0x10,0x8e,0x07,0x00,0x04,0x8e,0x06,0x00,0x14,0x0c,0x00,0x17,0x9d, +0x00,0x00,0x00,0x00,0x08,0x00,0x2c,0xd4,0xae,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03, +0x3c,0x02,0x80,0x01,0x34,0x63,0x00,0x20,0x24,0x42,0xb3,0x8c,0xac,0x62,0x00,0x00, +0x8c,0x86,0x00,0x04,0x3c,0x02,0xb0,0x01,0x24,0x03,0x00,0x01,0x00,0xc2,0x10,0x21, +0x8c,0x45,0x00,0x00,0xac,0x83,0x00,0x4c,0x00,0x05,0x14,0x02,0x30,0xa3,0x3f,0xff, +0x30,0x42,0x00,0xff,0xac,0x83,0x00,0x10,0xac,0x82,0x00,0x14,0x8c,0x83,0x00,0x14, +0xac,0x85,0x00,0x40,0x00,0xc3,0x30,0x21,0x03,0xe0,0x00,0x08,0xac,0x86,0x00,0x08, +0x3c,0x02,0xb0,0x03,0x3c,0x03,0x80,0x01,0x27,0xbd,0xff,0xe8,0x34,0x42,0x00,0x20, +0x24,0x63,0xb3,0xe0,0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x14,0xac,0x43,0x00,0x00, +0x8c,0x82,0x00,0x4c,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x0a,0x00,0x80,0x80,0x21, +0xae,0x00,0x00,0x00,0xae,0x00,0x00,0x4c,0xae,0x00,0x00,0x50,0xae,0x00,0x00,0x54, +0xae,0x00,0x00,0x0c,0x8f,0xbf,0x00,0x14,0x8f,0xb0,0x00,0x10,0x03,0xe0,0x00,0x08, +0x27,0xbd,0x00,0x18,0x0c,0x00,0x2c,0xe3,0x00,0x00,0x00,0x00,0x08,0x00,0x2d,0x05, +0xae,0x00,0x00,0x00,0x3c,0x02,0xb0,0x03,0x3c,0x03,0x80,0x01,0x27,0xbd,0xff,0xe8, +0x34,0x42,0x00,0x20,0x24,0x63,0xb4,0x44,0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x14, +0xac,0x43,0x00,0x00,0x8c,0x82,0x00,0x4c,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x16, +0x00,0x80,0x80,0x21,0x8e,0x03,0x00,0x08,0x3c,0x02,0xb0,0x01,0x8e,0x04,0x00,0x44, +0x00,0x62,0x18,0x21,0x90,0x65,0x00,0x00,0x24,0x02,0x00,0x01,0xae,0x02,0x00,0x50, +0x30,0xa3,0x00,0xff,0x00,0x03,0x10,0x82,0x00,0x04,0x23,0x02,0x30,0x84,0x00,0x0f, +0x30,0x42,0x00,0x03,0x00,0x03,0x19,0x02,0xae,0x04,0x00,0x34,0xae,0x02,0x00,0x2c, +0xae,0x03,0x00,0x30,0xa2,0x05,0x00,0x48,0x8f,0xbf,0x00,0x14,0x8f,0xb0,0x00,0x10, +0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18,0x0c,0x00,0x2c,0xe3,0x00,0x00,0x00,0x00, +0x08,0x00,0x2d,0x1d,0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x03,0x3c,0x03,0x80,0x01, +0x27,0xbd,0xff,0xe8,0x34,0x42,0x00,0x20,0x24,0x63,0xb4,0xd8,0xaf,0xb0,0x00,0x10, +0xaf,0xbf,0x00,0x14,0xac,0x43,0x00,0x00,0x8c,0x82,0x00,0x50,0x00,0x00,0x00,0x00, +0x10,0x40,0x00,0x16,0x00,0x80,0x80,0x21,0x92,0x03,0x00,0x44,0x8e,0x02,0x00,0x40, +0x83,0x85,0x92,0x15,0x92,0x04,0x00,0x41,0x30,0x63,0x00,0x01,0x00,0x02,0x16,0x02, +0xae,0x04,0x00,0x14,0x00,0x00,0x30,0x21,0xae,0x02,0x00,0x18,0x10,0xa0,0x00,0x04, +0xae,0x03,0x00,0x3c,0x10,0x60,0x00,0x03,0x24,0x02,0x00,0x01,0x24,0x06,0x00,0x01, +0x24,0x02,0x00,0x01,0xa3,0x86,0x92,0x15,0x8f,0xbf,0x00,0x14,0xae,0x02,0x00,0x54, +0x8f,0xb0,0x00,0x10,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18,0x0c,0x00,0x2d,0x11, +0x00,0x00,0x00,0x00,0x08,0x00,0x2d,0x42,0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x03, +0x3c,0x03,0x80,0x01,0x27,0xbd,0xff,0xe8,0x34,0x42,0x00,0x20,0x24,0x63,0xb5,0x6c, +0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x14,0xac,0x43,0x00,0x00,0x8c,0x82,0x00,0x50, +0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x1b,0x00,0x80,0x80,0x21,0x3c,0x02,0xb0,0x03, +0x8c,0x42,0x00,0x00,0x92,0x04,0x00,0x44,0x8e,0x03,0x00,0x40,0x83,0x86,0x92,0x15, +0x92,0x05,0x00,0x41,0x30,0x42,0x08,0x00,0x30,0x84,0x00,0x01,0x00,0x02,0x12,0xc2, +0x00,0x03,0x1e,0x02,0x00,0x82,0x20,0x25,0xae,0x05,0x00,0x14,0x00,0x00,0x38,0x21, +0xae,0x03,0x00,0x18,0x10,0xc0,0x00,0x04,0xae,0x04,0x00,0x3c,0x10,0x80,0x00,0x03, +0x24,0x02,0x00,0x01,0x24,0x07,0x00,0x01,0x24,0x02,0x00,0x01,0xa3,0x87,0x92,0x15, +0x8f,0xbf,0x00,0x14,0xae,0x02,0x00,0x54,0x8f,0xb0,0x00,0x10,0x03,0xe0,0x00,0x08, +0x27,0xbd,0x00,0x18,0x0c,0x00,0x2d,0x11,0x00,0x00,0x00,0x00,0x08,0x00,0x2d,0x67, +0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x03,0x3c,0x03,0x80,0x01,0x27,0xbd,0xff,0xe8, +0x34,0x42,0x00,0x20,0x24,0x63,0xb6,0x14,0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x14, +0xac,0x43,0x00,0x00,0x8c,0x82,0x00,0x54,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x21, +0x00,0x80,0x80,0x21,0x8e,0x05,0x00,0x04,0x8e,0x04,0x00,0x44,0x3c,0x03,0x80,0x00, +0x34,0x63,0x00,0x10,0x3c,0x02,0xb0,0x01,0x00,0xa2,0x28,0x21,0x00,0x83,0x20,0x25, +0xac,0xa4,0x00,0x04,0x8e,0x03,0x01,0xac,0x8e,0x08,0x00,0x04,0x3c,0x07,0xb0,0x03, +0x24,0x66,0x00,0x01,0x28,0xc5,0x00,0x00,0x24,0x62,0x00,0x40,0x00,0xc5,0x10,0x0a, +0x00,0x02,0x11,0x83,0x00,0x02,0x11,0x80,0x00,0x03,0x18,0x80,0x00,0xc2,0x30,0x23, +0x00,0x70,0x18,0x21,0xae,0x06,0x01,0xac,0x34,0xe7,0x00,0x30,0xac,0x68,0x00,0xa8, +0x8c,0xe2,0x00,0x00,0x02,0x00,0x20,0x21,0x24,0x42,0x00,0x01,0x0c,0x00,0x2c,0xb2, +0xac,0xe2,0x00,0x00,0x8f,0xbf,0x00,0x14,0x8f,0xb0,0x00,0x10,0x03,0xe0,0x00,0x08, +0x27,0xbd,0x00,0x18,0x0c,0x00,0x2d,0x5b,0x00,0x00,0x00,0x00,0x08,0x00,0x2d,0x91, +0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x03,0x3c,0x03,0x80,0x01,0x27,0xbd,0xff,0xe8, +0x34,0x42,0x00,0x20,0x24,0x63,0xb6,0xd4,0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x14, +0xac,0x43,0x00,0x00,0x8c,0x82,0x00,0x54,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x21, +0x00,0x80,0x80,0x21,0x8e,0x05,0x00,0x04,0x8e,0x04,0x00,0x44,0x3c,0x03,0x80,0x00, +0x34,0x63,0x00,0x10,0x3c,0x02,0xb0,0x01,0x00,0xa2,0x28,0x21,0x00,0x83,0x20,0x25, +0xac,0xa4,0x00,0x04,0x8e,0x03,0x01,0xac,0x8e,0x08,0x00,0x04,0x3c,0x07,0xb0,0x03, +0x24,0x66,0x00,0x01,0x28,0xc5,0x00,0x00,0x24,0x62,0x00,0x40,0x00,0xc5,0x10,0x0a, +0x00,0x02,0x11,0x83,0x00,0x02,0x11,0x80,0x00,0x03,0x18,0x80,0x00,0xc2,0x30,0x23, +0x00,0x70,0x18,0x21,0xae,0x06,0x01,0xac,0x34,0xe7,0x00,0x30,0xac,0x68,0x00,0xa8, +0x8c,0xe2,0x00,0x00,0x02,0x00,0x20,0x21,0x24,0x42,0x00,0x01,0x0c,0x00,0x2c,0xb2, +0xac,0xe2,0x00,0x00,0x8f,0xbf,0x00,0x14,0x8f,0xb0,0x00,0x10,0x03,0xe0,0x00,0x08, +0x27,0xbd,0x00,0x18,0x0c,0x00,0x2d,0x5b,0x00,0x00,0x00,0x00,0x08,0x00,0x2d,0xc1, +0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x03,0x3c,0x03,0x80,0x01,0x34,0x42,0x00,0x20, +0x24,0x63,0xb7,0x94,0x27,0xbd,0xff,0xe0,0xac,0x43,0x00,0x00,0x3c,0x02,0x80,0x01, +0xaf,0xb1,0x00,0x14,0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x18,0x00,0x80,0x80,0x21, +0x24,0x51,0xb2,0xb0,0x3c,0x03,0xb0,0x09,0x34,0x63,0x00,0x06,0x8e,0x07,0x00,0x04, +0x90,0x62,0x00,0x00,0x00,0x07,0x22,0x02,0x00,0x44,0x10,0x23,0x24,0x44,0x00,0x40, +0x28,0x83,0x00,0x00,0x24,0x42,0x00,0x7f,0x00,0x83,0x10,0x0a,0x00,0x02,0x11,0x83, +0x00,0x02,0x11,0x80,0x24,0x84,0xff,0xff,0x10,0x44,0x00,0x5f,0x00,0x00,0x40,0x21, +0x3c,0x02,0xb0,0x01,0x00,0xe2,0x10,0x21,0x8c,0x44,0x00,0x04,0x3c,0x03,0x7c,0x00, +0x34,0x63,0x00,0xf0,0x00,0x83,0x18,0x24,0xae,0x04,0x00,0x44,0x8c,0x44,0x00,0x00, +0x10,0x60,0x00,0x60,0x00,0x00,0x48,0x21,0x24,0xe2,0x01,0x00,0x30,0x45,0x3f,0xff, +0x3c,0x03,0xb0,0x01,0xae,0x05,0x00,0x04,0x00,0xa3,0x18,0x21,0x8c,0x64,0x00,0x04, +0x3c,0x02,0x7c,0x00,0x34,0x42,0x00,0xf0,0x00,0x82,0x30,0x24,0xae,0x04,0x00,0x44, +0x25,0x08,0x00,0x01,0x24,0x02,0x00,0x40,0x00,0xa0,0x38,0x21,0x8c,0x64,0x00,0x00, +0x11,0x02,0x00,0x30,0x24,0x09,0x00,0x01,0x3c,0x02,0xff,0xff,0x14,0xc0,0xff,0xee, +0x00,0x82,0x18,0x24,0x3c,0x02,0x28,0x38,0x14,0x62,0xff,0xec,0x24,0xe2,0x01,0x00, +0x24,0x02,0x00,0x01,0x11,0x22,0x00,0x2e,0x3c,0x03,0xb0,0x09,0x8e,0x02,0x00,0x44, +0x8e,0x04,0x00,0x60,0x00,0x02,0x1e,0x42,0x00,0x02,0x12,0x02,0x30,0x42,0x00,0x0f, +0x30,0x63,0x00,0x01,0xae,0x02,0x00,0x00,0x10,0x44,0x00,0x1a,0xae,0x03,0x00,0x58, +0x8e,0x02,0x00,0x64,0x8e,0x04,0x00,0x58,0x00,0x00,0x00,0x00,0x10,0x82,0x00,0x05, +0x00,0x00,0x00,0x00,0xae,0x00,0x00,0x4c,0xae,0x00,0x00,0x50,0xae,0x00,0x00,0x54, +0xae,0x00,0x00,0x0c,0x8e,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x10,0x80, +0x00,0x50,0x10,0x21,0x8c,0x42,0x00,0x68,0x00,0x00,0x00,0x00,0x10,0x51,0x00,0x06, +0x00,0x00,0x00,0x00,0x00,0x40,0xf8,0x09,0x02,0x00,0x20,0x21,0x8e,0x04,0x00,0x58, +0x8e,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0xae,0x03,0x00,0x60,0x08,0x00,0x2d,0xf1, +0xae,0x04,0x00,0x64,0x8e,0x02,0x00,0x64,0x00,0x00,0x00,0x00,0x14,0x62,0xff,0xe5, +0x00,0x00,0x00,0x00,0x7a,0x02,0x0d,0x7c,0x8f,0xbf,0x00,0x18,0x7b,0xb0,0x00,0xbc, +0x00,0x43,0x10,0x26,0x00,0x02,0x10,0x2b,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20, +0x34,0x63,0x00,0x06,0x8e,0x04,0x00,0x04,0x90,0x62,0x00,0x00,0x00,0x04,0x22,0x02, +0x00,0x44,0x10,0x23,0x24,0x44,0x00,0x40,0x28,0x83,0x00,0x00,0x24,0x42,0x00,0x7f, +0x00,0x83,0x10,0x0a,0x00,0x02,0x11,0x83,0x00,0x02,0x11,0x80,0x00,0x82,0x20,0x23, +0x14,0x89,0xff,0xc6,0x00,0x00,0x00,0x00,0x8e,0x03,0x00,0x00,0x00,0x00,0x00,0x00, +0x2c,0x62,0x00,0x03,0x14,0x40,0x00,0x05,0x24,0x02,0x00,0x0d,0x10,0x62,0x00,0x03, +0x24,0x02,0x00,0x01,0x08,0x00,0x2e,0x49,0xa2,0x02,0x00,0x5c,0x08,0x00,0x2e,0x49, +0xa2,0x00,0x00,0x5c,0x3c,0x02,0xff,0xff,0x00,0x82,0x10,0x24,0x3c,0x03,0x28,0x38, +0x14,0x43,0xff,0x9d,0x24,0x02,0x00,0x01,0x08,0x00,0x2e,0x21,0x00,0x00,0x00,0x00, +0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x01,0x34,0x63,0x00,0x20,0x24,0x42,0xb9,0xc0, +0xac,0x62,0x00,0x00,0x8c,0x83,0x01,0xa8,0x3c,0x05,0xb0,0x06,0x34,0xa5,0x80,0x18, +0x00,0x03,0x18,0x80,0x00,0x64,0x18,0x21,0x8c,0x62,0x00,0xa8,0x3c,0x03,0x00,0x80, +0x00,0x02,0x10,0xc2,0x00,0x02,0x12,0x00,0x00,0x43,0x10,0x25,0xac,0xa2,0x00,0x00, +0x8c,0x83,0x01,0xa8,0x8c,0x82,0x01,0xac,0x24,0x66,0x00,0x01,0x28,0xc5,0x00,0x00, +0x24,0x63,0x00,0x40,0x00,0xc5,0x18,0x0a,0x00,0x03,0x19,0x83,0x00,0x03,0x19,0x80, +0x00,0xc3,0x30,0x23,0x00,0xc2,0x10,0x26,0x00,0x02,0x10,0x2b,0x03,0xe0,0x00,0x08, +0xac,0x86,0x01,0xa8,0x90,0x87,0x00,0x00,0x3c,0x02,0x80,0x01,0x27,0xbd,0xff,0xe8, +0x24,0x48,0x02,0x14,0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x14,0x01,0x07,0x18,0x21, +0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x20,0x10,0x40,0x00,0x0a, +0x00,0x00,0x80,0x21,0x24,0x84,0x00,0x01,0x90,0x87,0x00,0x00,0x00,0x00,0x00,0x00, +0x01,0x07,0x18,0x21,0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x20, +0x14,0x40,0xff,0xf8,0x00,0x00,0x00,0x00,0x00,0x07,0x16,0x00,0x00,0x02,0x16,0x03, +0x24,0x03,0x00,0x2d,0x10,0x43,0x00,0x0f,0x00,0x00,0x00,0x00,0x0c,0x00,0x2e,0xb8, +0x00,0x00,0x00,0x00,0x00,0x40,0x18,0x21,0x00,0x02,0x10,0x23,0x04,0x61,0x00,0x05, +0x00,0x70,0x10,0x0a,0x16,0x00,0x00,0x03,0x3c,0x02,0x80,0x00,0x3c,0x02,0x7f,0xff, +0x34,0x42,0xff,0xff,0x8f,0xbf,0x00,0x14,0x8f,0xb0,0x00,0x10,0x03,0xe0,0x00,0x08, +0x27,0xbd,0x00,0x18,0x24,0x10,0xff,0xff,0x08,0x00,0x2e,0xa7,0x24,0x84,0x00,0x01, +0x00,0x80,0x38,0x21,0x90,0x84,0x00,0x00,0x3c,0x02,0x80,0x01,0x24,0x48,0x02,0x14, +0x01,0x04,0x18,0x21,0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x20, +0x10,0x40,0x00,0x0a,0x00,0x00,0x50,0x21,0x24,0xe7,0x00,0x01,0x90,0xe4,0x00,0x00, +0x00,0x00,0x00,0x00,0x01,0x04,0x18,0x21,0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00, +0x30,0x42,0x00,0x20,0x14,0x40,0xff,0xf8,0x00,0x00,0x00,0x00,0x00,0x04,0x16,0x00, +0x00,0x02,0x16,0x03,0x38,0x42,0x00,0x2b,0x24,0xe3,0x00,0x01,0x24,0x04,0x00,0x10, +0x10,0xc4,0x00,0x38,0x00,0x62,0x38,0x0a,0x90,0xe4,0x00,0x00,0x14,0xc0,0x00,0x07, +0x00,0x80,0x18,0x21,0x00,0x04,0x16,0x00,0x00,0x02,0x16,0x03,0x24,0x03,0x00,0x30, +0x10,0x43,0x00,0x25,0x24,0x06,0x00,0x0a,0x00,0x80,0x18,0x21,0x00,0x03,0x16,0x00, +0x10,0x40,0x00,0x1a,0x30,0x64,0x00,0xff,0x24,0x82,0xff,0xa9,0x2c,0x83,0x00,0x61, +0x30,0x48,0x00,0xff,0x10,0x60,0x00,0x09,0x2c,0x89,0x00,0x41,0x24,0x82,0xff,0xc9, +0x30,0x48,0x00,0xff,0x11,0x20,0x00,0x05,0x2c,0x83,0x00,0x3a,0x24,0x82,0xff,0xd0, +0x14,0x60,0x00,0x02,0x30,0x48,0x00,0xff,0x24,0x08,0x00,0xff,0x01,0x06,0x10,0x2a, +0x10,0x40,0x00,0x0a,0x01,0x46,0x00,0x18,0x24,0xe7,0x00,0x01,0x00,0x00,0x18,0x12, +0x00,0x6a,0x10,0x2b,0x14,0x40,0x00,0x0a,0x00,0x68,0x50,0x21,0x80,0xe2,0x00,0x00, +0x90,0xe3,0x00,0x00,0x14,0x40,0xff,0xe8,0x30,0x64,0x00,0xff,0x10,0xa0,0x00,0x02, +0x00,0x00,0x00,0x00,0xac,0xa7,0x00,0x00,0x03,0xe0,0x00,0x08,0x01,0x40,0x10,0x21, +0x03,0xe0,0x00,0x08,0x24,0x02,0xff,0xff,0x24,0x06,0x00,0x08,0x80,0xe3,0x00,0x01, +0x24,0x02,0x00,0x78,0x10,0x62,0x00,0x03,0x24,0x02,0x00,0x58,0x14,0x62,0xff,0xd7, +0x00,0x80,0x18,0x21,0x24,0xe7,0x00,0x02,0x90,0xe4,0x00,0x00,0x08,0x00,0x2e,0xda, +0x24,0x06,0x00,0x10,0x80,0xe3,0x00,0x00,0x24,0x02,0x00,0x30,0x90,0xe4,0x00,0x00, +0x10,0x62,0xff,0xf2,0x00,0x00,0x00,0x00,0x08,0x00,0x2e,0xd3,0x00,0x00,0x00,0x00, +0x3c,0x04,0xb0,0x03,0x3c,0x06,0xb0,0x07,0x3c,0x02,0x80,0x01,0x34,0xc6,0x00,0x18, +0x34,0x84,0x00,0x20,0x24,0x42,0xbc,0x40,0x24,0x03,0xff,0x83,0xac,0x82,0x00,0x00, +0xa0,0xc3,0x00,0x00,0x90,0xc4,0x00,0x00,0x27,0xbd,0xff,0xf8,0x3c,0x03,0xb0,0x07, +0x24,0x02,0xff,0x82,0xa3,0xa4,0x00,0x00,0xa0,0x62,0x00,0x00,0x90,0x64,0x00,0x00, +0x3c,0x02,0xb0,0x07,0x34,0x42,0x00,0x08,0xa3,0xa4,0x00,0x01,0xa0,0x40,0x00,0x00, +0x90,0x43,0x00,0x00,0x24,0x02,0x00,0x03,0x3c,0x05,0xb0,0x07,0xa3,0xa3,0x00,0x00, +0xa0,0xc2,0x00,0x00,0x90,0xc4,0x00,0x00,0x34,0xa5,0x00,0x10,0x24,0x02,0x00,0x06, +0x3c,0x03,0xb0,0x07,0xa3,0xa4,0x00,0x00,0x34,0x63,0x00,0x38,0xa0,0xa2,0x00,0x00, +0x90,0x64,0x00,0x00,0x3c,0x02,0xb0,0x07,0x34,0x42,0x00,0x20,0xa3,0xa4,0x00,0x00, +0xa0,0xa0,0x00,0x00,0x90,0xa3,0x00,0x00,0xaf,0x82,0xc2,0x5c,0xa3,0xa3,0x00,0x00, +0xa0,0x40,0x00,0x00,0x90,0x43,0x00,0x00,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x08, +}; + +#define DataArrayLengthDTM 2860 +u8 Rtl8192PciEFwDataArrayDTM[DataArrayLengthDTM] = { +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x0d,0x5b,0x43, +0x4d,0x50,0x4b,0x5d,0x00,0x00,0x00,0x00,0x80,0x01,0x00,0x0c,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x28,0x28,0x28, +0x28,0x28,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08, +0x08,0x08,0x08,0x08,0xa0,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, +0x10,0x10,0x10,0x10,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x10,0x10, +0x10,0x10,0x10,0x10,0x10,0x41,0x41,0x41,0x41,0x41,0x41,0x01,0x01,0x01,0x01,0x01, +0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x10, +0x10,0x10,0x10,0x10,0x10,0x42,0x42,0x42,0x42,0x42,0x42,0x02,0x02,0x02,0x02,0x02, +0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x10, +0x10,0x10,0x10,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0xa0,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, +0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, +0x10,0x10,0x10,0x10,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, +0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x10,0x01,0x01,0x01,0x01, +0x01,0x01,0x01,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, +0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x10,0x02,0x02,0x02,0x02, +0x02,0x02,0x02,0x02,0x20,0x09,0x0d,0x0a,0x00,0x00,0x00,0x00,0x80,0x01,0x03,0x14, +0x00,0x00,0x00,0x00,0x43,0x6e,0x73,0x64,0x31,0x00,0x00,0x00,0x68,0x65,0x6c,0x70, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x72,0x34,0x00,0x00,0x77,0x34,0x00,0x00, +0x64,0x62,0x67,0x00,0x72,0x61,0x63,0x74,0x72,0x6c,0x00,0x00,0x73,0x79,0x73,0x64, +0x00,0x00,0x00,0x00,0x73,0x79,0x73,0x63,0x74,0x72,0x6c,0x00,0x74,0x78,0x74,0x62, +0x6c,0x00,0x00,0x00,0x70,0x72,0x61,0x6e,0x67,0x65,0x00,0x00,0x64,0x6d,0x00,0x00, +0x75,0x6e,0x6b,0x6e,0x6f,0x77,0x00,0x00,0x80,0x01,0x03,0x2c,0x80,0x01,0x03,0x34, +0x80,0x01,0x03,0x34,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x80,0x00,0x20,0x5c, +0x80,0x01,0x03,0x38,0x80,0x01,0x03,0x34,0x80,0x01,0x03,0x34,0x00,0x00,0x00,0x01, +0x00,0x00,0x00,0x00,0x80,0x00,0x21,0xbc,0x80,0x01,0x03,0x3c,0x80,0x01,0x03,0x34, +0x80,0x01,0x03,0x34,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x80,0x00,0x23,0x38, +0x80,0x01,0x03,0x40,0x80,0x01,0x03,0x34,0x80,0x01,0x03,0x34,0x00,0x00,0x00,0x01, +0x00,0x00,0x00,0x00,0x80,0x00,0x25,0x04,0x80,0x01,0x03,0x44,0x80,0x01,0x03,0x34, +0x80,0x01,0x03,0x34,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x80,0x00,0x25,0xdc, +0x80,0x01,0x03,0x4c,0x80,0x01,0x03,0x34,0x80,0x01,0x03,0x34,0x00,0x00,0x00,0x01, +0x00,0x00,0x00,0x00,0x80,0x00,0x25,0xe4,0x80,0x01,0x03,0x54,0x80,0x01,0x03,0x34, +0x80,0x01,0x03,0x34,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x80,0x00,0x26,0x88, +0x80,0x01,0x03,0x5c,0x80,0x01,0x03,0x34,0x80,0x01,0x03,0x34,0x00,0x00,0x00,0x01, +0x00,0x00,0x00,0x00,0x80,0x00,0x26,0x90,0x80,0x01,0x03,0x64,0x80,0x01,0x03,0x34, +0x80,0x01,0x03,0x34,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x80,0x00,0x28,0x1c, +0x80,0x01,0x03,0x6c,0x80,0x01,0x03,0x34,0x80,0x01,0x03,0x34,0x00,0x00,0x00,0x01, +0x00,0x00,0x00,0x00,0x80,0x00,0x28,0x90,0x80,0x01,0x03,0x70,0x80,0x01,0x03,0x34, +0x80,0x01,0x03,0x34,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x01,0x80,0x00,0x29,0x1c, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x0d,0x52,0x54,0x4c,0x38,0x31,0x39, +0x58,0x2d,0x25,0x64,0x3e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x52,0x54,0x4c,0x38, +0x31,0x39,0x58,0x2d,0x25,0x64,0x3e,0x0a,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x2a,0x00,0x00,0x00,0x0a,0x0d,0x45,0x72,0x72,0x20,0x44,0x49,0x52,0x00,0x00,0x00, +0x0a,0x0d,0x44,0x42,0x47,0x20,0x43,0x4d,0x44,0x73,0x3a,0x00,0x0a,0x0d,0x5b,0x00, +0x5d,0x2d,0x00,0x00,0x0a,0x0d,0x3c,0x31,0x2e,0x43,0x4d,0x4e,0x3e,0x20,0x3c,0x32, +0x2e,0x3f,0x3e,0x00,0x0a,0x0d,0x20,0x79,0x65,0x61,0x72,0x2d,0x64,0x61,0x79,0x2d, +0x68,0x6f,0x75,0x72,0x2d,0x6d,0x69,0x6e,0x2d,0x73,0x65,0x63,0x2d,0x31,0x30,0x6d, +0x73,0x3d,0x00,0x00,0x25,0x64,0x2d,0x00,0x0a,0x0d,0x09,0x20,0x20,0x20,0x20,0x20, +0x30,0x30,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x30,0x34,0x20,0x20,0x20,0x20,0x20, +0x20,0x20,0x30,0x38,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x30,0x43,0x00,0x00,0x00, +0x0a,0x0d,0x09,0x20,0x20,0x20,0x20,0x20,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d, +0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d, +0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x00,0x0d,0x0a,0x20,0x30, +0x78,0x25,0x30,0x38,0x58,0x20,0x20,0x00,0x09,0x00,0x00,0x00,0x25,0x30,0x38,0x58, +0x20,0x00,0x00,0x00,0x0a,0x0d,0x44,0x62,0x67,0x5f,0x46,0x6c,0x61,0x67,0x25,0x64, +0x3d,0x30,0x78,0x25,0x30,0x38,0x78,0x00,0x0a,0x0d,0x20,0x76,0x6f,0x71,0x74,0x78, +0x72,0x65,0x71,0x20,0x3d,0x20,0x25,0x64,0x00,0x00,0x00,0x00,0x0a,0x0d,0x20,0x76, +0x69,0x71,0x74,0x78,0x72,0x65,0x71,0x20,0x3d,0x20,0x25,0x64,0x00,0x00,0x00,0x00, +0x0a,0x0d,0x20,0x62,0x65,0x71,0x74,0x78,0x72,0x65,0x71,0x20,0x3d,0x20,0x25,0x64, +0x00,0x00,0x00,0x00,0x0a,0x0d,0x20,0x62,0x6b,0x71,0x74,0x78,0x72,0x65,0x71,0x20, +0x3d,0x20,0x25,0x64,0x00,0x00,0x00,0x00,0x0a,0x0d,0x20,0x62,0x63,0x6e,0x71,0x74, +0x78,0x72,0x65,0x71,0x20,0x3d,0x20,0x25,0x64,0x00,0x00,0x00,0x0a,0x0d,0x20,0x68, +0x71,0x74,0x78,0x72,0x65,0x71,0x20,0x3d,0x20,0x25,0x64,0x00,0x0a,0x0d,0x20,0x6d, +0x67,0x71,0x74,0x78,0x72,0x65,0x71,0x20,0x3d,0x20,0x25,0x64,0x00,0x00,0x00,0x00, +0x0a,0x0d,0x54,0x58,0x4c,0x4c,0x54,0x09,0x09,0x4e,0x45,0x58,0x54,0x20,0x20,0x20, +0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x4e,0x45,0x58,0x54,0x0a,0x0d,0x00, +0x0a,0x0d,0x20,0x50,0x61,0x67,0x65,0x25,0x33,0x64,0x09,0x00,0x25,0x34,0x64,0x20, +0x20,0x20,0x20,0x00,0x25,0x34,0x64,0x20,0x20,0x20,0x20,0x09,0x00,0x00,0x00,0x00, +0x0a,0x0d,0x54,0x58,0x4f,0x51,0x54,0x09,0x09,0x48,0x65,0x61,0x64,0x20,0x20,0x20, +0x20,0x54,0x61,0x69,0x6c,0x20,0x20,0x20,0x20,0x48,0x65,0x61,0x64,0x20,0x20,0x20, +0x20,0x54,0x61,0x69,0x6c,0x0a,0x0d,0x00,0x0a,0x0d,0x55,0x6e,0x6b,0x6e,0x6f,0x77, +0x20,0x63,0x6f,0x6d,0x6d,0x61,0x6e,0x64,0x00,0x00,0x00,0x00,0x0a,0x0d,0x45,0x72, +0x72,0x20,0x41,0x72,0x67,0x0a,0x0d,0x55,0x53,0x41,0x47,0x45,0x3a,0x00,0x00,0x00, +0x10,0x00,0x08,0x00,0x02,0xe9,0x01,0x74,0x02,0xab,0x01,0xc7,0x01,0x55,0x00,0xe4, +0x00,0xab,0x00,0x72,0x00,0x55,0x00,0x4c,0x00,0x4c,0x00,0x4c,0x00,0x4c,0x00,0x4c, +0x02,0x76,0x01,0x3b,0x00,0xd2,0x00,0x9e,0x00,0x69,0x00,0x4f,0x00,0x46,0x00,0x3f, +0x01,0x3b,0x00,0x9e,0x00,0x69,0x00,0x4f,0x00,0x35,0x00,0x27,0x00,0x23,0x00,0x20, +0x01,0x2f,0x00,0x98,0x00,0x65,0x00,0x4c,0x00,0x33,0x00,0x26,0x00,0x22,0x00,0x1e, +0x00,0x98,0x00,0x4c,0x00,0x33,0x00,0x26,0x00,0x19,0x00,0x13,0x00,0x11,0x00,0x0f, +0x02,0x39,0x01,0x1c,0x00,0xbd,0x00,0x8e,0x00,0x5f,0x00,0x47,0x00,0x3f,0x00,0x39, +0x01,0x1c,0x00,0x8e,0x00,0x5f,0x00,0x47,0x00,0x2f,0x00,0x23,0x00,0x20,0x00,0x1c, +0x01,0x11,0x00,0x89,0x00,0x5b,0x00,0x44,0x00,0x2e,0x00,0x22,0x00,0x1e,0x00,0x1b, +0x00,0x89,0x00,0x44,0x00,0x2e,0x00,0x22,0x00,0x17,0x00,0x11,0x00,0x0f,0x00,0x0e, +0x02,0xab,0x02,0xab,0x02,0x66,0x02,0x66,0x07,0x06,0x06,0x06,0x05,0x06,0x07,0x08, +0x04,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0b,0x49,0x6e,0x74,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x54,0x4c,0x42,0x4d,0x4f,0x44,0x00,0x00,0x00,0x00,0x54,0x4c,0x42,0x4c, +0x5f,0x64,0x61,0x74,0x61,0x00,0x54,0x4c,0x42,0x53,0x00,0x00,0x00,0x00,0x00,0x00, +0x41,0x64,0x45,0x4c,0x5f,0x64,0x61,0x74,0x61,0x00,0x41,0x64,0x45,0x53,0x00,0x00, +0x00,0x00,0x00,0x00,0x45,0x78,0x63,0x43,0x6f,0x64,0x65,0x36,0x00,0x00,0x45,0x78, +0x63,0x43,0x6f,0x64,0x65,0x37,0x00,0x00,0x53,0x79,0x73,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x42,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x52,0x49,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x43,0x70,0x55,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x4f,0x76,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x80,0x01,0x11,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x10, +0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x50, +0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x90,0x00,0x00,0x00,0xc0,0x00,0x00,0x01,0x20, +0x00,0x00,0x01,0x80,0x00,0x00,0x01,0xb0,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0xd0, +0x00,0x00,0x01,0x30,0x00,0x00,0x01,0xa0,0x00,0x00,0x02,0x70,0x00,0x00,0x03,0x40, +0x00,0x00,0x03,0xa0,0x00,0x00,0x04,0x10,0x00,0x00,0x00,0xd0,0x00,0x00,0x01,0xa0, +0x00,0x00,0x02,0x70,0x00,0x00,0x03,0x40,0x00,0x00,0x04,0xe0,0x00,0x00,0x06,0x80, +0x00,0x00,0x07,0x50,0x00,0x00,0x07,0xf8,0x01,0x01,0x01,0x01,0x01,0x01,0x02,0x02, +0x02,0x02,0x02,0x02,0x01,0x01,0x02,0x02,0x04,0x05,0x06,0x06,0x02,0x02,0x04,0x06, +0x07,0x09,0x0a,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x3c,0x4e,0x55,0x4c,0x4c,0x3e,0x00,0x00,0x30,0x31,0x32,0x33, +0x34,0x35,0x36,0x37,0x38,0x39,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a, +0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a, +0x00,0x00,0x00,0x00,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x41,0x42, +0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50,0x51,0x52, +0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x00,0x00,0x00,0x00,0x5b,0x52,0x58,0x5d, +0x20,0x70,0x6b,0x74,0x5f,0x6c,0x65,0x6e,0x3d,0x25,0x64,0x20,0x6f,0x66,0x66,0x73, +0x65,0x74,0x3d,0x25,0x64,0x20,0x73,0x74,0x61,0x72,0x74,0x5f,0x61,0x64,0x64,0x72, +0x3d,0x25,0x30,0x38,0x78,0x0a,0x0d,0x00,0x80,0x00,0x6a,0x64,0x80,0x00,0x6a,0x88, +0x80,0x00,0x6a,0xa4,0x80,0x00,0x6b,0x90,0x80,0x00,0x6c,0x48,0x80,0x00,0x6c,0x98, +0x80,0x00,0x6d,0x04,0x80,0x00,0x6e,0x08,0x80,0x00,0x6e,0x3c,0x80,0x00,0x6e,0x50, +0x80,0x00,0x6e,0x64,0x80,0x00,0x6f,0x3c,0x80,0x00,0x6f,0x78,0x80,0x00,0x70,0x28, +0x80,0x00,0x70,0x50,0x80,0x00,0x6a,0x20,0x80,0x00,0x70,0x64,0x80,0x00,0x76,0x5c, +0x80,0x00,0x76,0xd4,0x80,0x00,0x76,0xe0,0x80,0x00,0x76,0xec,0x80,0x00,0x76,0x74, +0x80,0x00,0x76,0x74,0x80,0x00,0x76,0x74,0x80,0x00,0x76,0x74,0x80,0x00,0x76,0x74, +0x80,0x00,0x76,0x74,0x80,0x00,0x76,0x74,0x80,0x00,0x76,0x74,0x80,0x00,0x76,0x74, +0x80,0x00,0x76,0x74,0x80,0x00,0x76,0x74,0x80,0x00,0x76,0x74,0x80,0x00,0x76,0xf8, +0x80,0x00,0x77,0x04,0x80,0x00,0x77,0x10,0x80,0x00,0xa7,0x80,0x80,0x00,0xa7,0x98, +0x80,0x00,0xa7,0x98,0x80,0x00,0xa7,0x88,0x80,0x00,0xa7,0x98,0x80,0x00,0xa7,0x98, +0x80,0x00,0xa7,0x98,0x80,0x00,0xa7,0x98,0x80,0x00,0xa7,0x98,0x80,0x00,0xa7,0x98, +0x80,0x00,0xa7,0x98,0x80,0x00,0xa7,0x90,0x80,0x00,0xa7,0x98,0x80,0x00,0xa7,0x78, +0x80,0x00,0xa7,0x98,0x80,0x00,0xa7,0x98,0x80,0x00,0xab,0xc0,0x80,0x00,0xa8,0xb0, +0x80,0x00,0xaa,0xc8,0x80,0x00,0xaa,0xc8,0x80,0x00,0xaa,0xc8,0x80,0x00,0xaa,0xc8, +0x80,0x00,0xaa,0xc8,0x80,0x00,0xaa,0xc8,0x80,0x00,0xaa,0xc8,0x80,0x00,0xaa,0xc8, +0x80,0x00,0xaa,0xc8,0x80,0x00,0xaa,0xc8,0x80,0x00,0xaa,0xc8,0x80,0x00,0xaa,0xc8, +0x80,0x00,0xaa,0xc8,0x80,0x00,0xaa,0xc8,0x80,0x00,0xaa,0xc8,0x80,0x00,0xaa,0xc8, +0x80,0x00,0xaa,0xc8,0x80,0x00,0xaa,0xc8,0x80,0x00,0xaa,0xc8,0x80,0x00,0xaa,0xc8, +0x80,0x00,0xaa,0xc8,0x80,0x00,0xaa,0xc8,0x80,0x00,0xaa,0xc8,0x80,0x00,0xaa,0xc8, +0x80,0x00,0xaa,0xc8,0x80,0x00,0xaa,0xc8,0x80,0x00,0xaa,0xc8,0x80,0x00,0xaa,0xc8, +0x80,0x00,0xaa,0xc8,0x80,0x00,0xaa,0xc8,0x80,0x00,0xaa,0xc8,0x80,0x00,0xaa,0xc8, +0x80,0x00,0xaa,0xc8,0x80,0x00,0xaa,0xc8,0x80,0x00,0xaa,0xc8,0x80,0x00,0xaa,0xc8, +0x80,0x00,0xaa,0xc8,0x80,0x00,0xaa,0xc8,0x80,0x00,0xaa,0xc8,0x80,0x00,0xaa,0xc8, +0x80,0x00,0xaa,0xc8,0x80,0x00,0xaa,0xc8,0x80,0x00,0xaa,0xc8,0x80,0x00,0xaa,0xc8, +0x80,0x00,0xaa,0xc8,0x80,0x00,0xaa,0xc8,0x80,0x00,0xaa,0xc8,0x80,0x00,0xaa,0xc8, +0x80,0x00,0xaa,0xc8,0x80,0x00,0xaa,0xc8,0x80,0x00,0xa8,0xbc,0x80,0x00,0xaa,0xc8, +0x80,0x00,0xaa,0xc8,0x80,0x00,0xaa,0xc8,0x80,0x00,0xaa,0xc8,0x80,0x00,0xaa,0xc8, +0x80,0x00,0xaa,0xc8,0x80,0x00,0xaa,0xc8,0x80,0x00,0xaa,0xc8,0x80,0x00,0xaa,0xc8, +0x80,0x00,0xaa,0xc8,0x80,0x00,0xa8,0x44,0x80,0x00,0xa9,0x90,0x80,0x00,0xaa,0xc8, +0x80,0x00,0xaa,0xc8,0x80,0x00,0xaa,0xc8,0x80,0x00,0xaa,0xc8,0x80,0x00,0xa9,0x90, +0x80,0x00,0xaa,0xc8,0x80,0x00,0xaa,0xc8,0x80,0x00,0xaa,0xc8,0x80,0x00,0xaa,0xc8, +0x80,0x00,0xa9,0x98,0x80,0x00,0xa9,0xb8,0x80,0x00,0xa9,0xc0,0x80,0x00,0xaa,0xc8, +0x80,0x00,0xaa,0xc8,0x80,0x00,0xaa,0x18,0x80,0x00,0xaa,0xc8,0x80,0x00,0xa8,0xc4, +0x80,0x00,0xaa,0xc8,0x80,0x00,0xaa,0xc8,0x80,0x00,0xa8,0xc0,}; + +#define PHY_REGArrayLengthDTM 1 +u32 Rtl8192PciEPHY_REGArrayDTM[PHY_REGArrayLengthDTM] = { +0x0, }; + +#define PHY_REG_1T2RArrayLengthDTM 296 +u32 Rtl8192PciEPHY_REG_1T2RArrayDTM[PHY_REG_1T2RArrayLengthDTM] = { +0x800,0x00000000, +0x804,0x00000001, +0x808,0x0000fc00, +0x80c,0x0000001c, +0x810,0x801010aa, +0x814,0x008514d0, +0x818,0x00000040, +0x81c,0x00000000, +0x820,0x00000004, +0x824,0x00690000, +0x828,0x00000004, +0x82c,0x00e90000, +0x830,0x00000004, +0x834,0x00690000, +0x838,0x00000004, +0x83c,0x00e90000, +0x840,0x00000000, +0x844,0x00000000, +0x848,0x00000000, +0x84c,0x00000000, +0x850,0x00000000, +0x854,0x00000000, +0x858,0x65a965a9, +0x85c,0x65a965a9, +0x860,0x001f0010, +0x864,0x007f0010, +0x868,0x001f0010, +0x86c,0x007f0010, +0x870,0x0f100f70, +0x874,0x0f100f70, +0x878,0x00000000, +0x87c,0x00000000, +0x880,0x6870e36c, +0x884,0xe3573600, +0x888,0x4260c340, +0x88c,0x0000ff00, +0x890,0x00000000, +0x894,0xfffffffe, +0x898,0x40302010, +0x89c,0x00706050, +0x8b0,0x00000000, +0x8e0,0x00000000, +0x8e4,0x00000000, +0x900,0x00000000, +0x904,0x00000023, +0x908,0x00000000, +0x90c,0x31121311, +0xa00,0x00d0c7d8, +0xa04,0x811f0008, +0xa08,0x80cd8300, +0xa0c,0x2e62740f, +0xa10,0x95009b78, +0xa14,0x11145008, +0xa18,0x00881117, +0xa1c,0x89140fa0, +0xa20,0x1a1b0000, +0xa24,0x090e1317, +0xa28,0x00000204, +0xa2c,0x00000000, +0xc00,0x00000040, +0xc04,0x00005411, +0xc08,0x000000e4, +0xc0c,0x6c6c6c6c, +0xc10,0x08800000, +0xc14,0x40000100, +0xc18,0x08000000, +0xc1c,0x40000100, +0xc20,0x08000000, +0xc24,0x40000100, +0xc28,0x08000000, +0xc2c,0x40000100, +0xc30,0x6de98a44, +0xc34,0x469652cd, +0xc38,0x49475996, +0xc3c,0x0a9a9764, +0xc40,0x1f7c423f, +0xc44,0x000100b7, +0xc48,0xec020000, +0xc4c,0x00000300, +0xc50,0x69543430, +0xc54,0x433c0094, +0xc58,0x69543430, +0xc5c,0x433c0094, +0xc60,0x69543430, +0xc64,0x433c0094, +0xc68,0x69543430, +0xc6c,0x433c0094, +0xc70,0x2c7f000d, +0xc74,0x0186175b, +0xc78,0x0000001f, +0xc7c,0x00b91612, +0xc80,0x40000100, +0xc84,0x20000000, +0xc88,0x40000100, +0xc8c,0x08000000, +0xc90,0x40000100, +0xc94,0x00000000, +0xc98,0x40000100, +0xc9c,0x00000000, +0xca0,0x00492492, +0xca4,0x00000000, +0xca8,0x00000000, +0xcac,0x00000000, +0xcb0,0x00000000, +0xcb4,0x00000000, +0xcb8,0x00000000, +0xcbc,0x00492492, +0xcc0,0x00000000, +0xcc4,0x00000000, +0xcc8,0x00000000, +0xccc,0x00000000, +0xcd0,0x00000000, +0xcd4,0x00000000, +0xcd8,0x64b22427, +0xcdc,0x00766932, +0xce0,0x00222222, +0xd00,0x00000740, +0xd04,0x00000401, +0xd08,0x0000907f, +0xd0c,0x00000001, +0xd10,0xa0633333, +0xd14,0x33333c63, +0xd18,0x6a8f5b6b, +0xd1c,0x00000000, +0xd20,0x00000000, +0xd24,0x00000000, +0xd28,0x00000000, +0xd2c,0xcc979975, +0xd30,0x00000000, +0xd34,0x00000000, +0xd38,0x00000000, +0xd3c,0x00027293, +0xd40,0x00000000, +0xd44,0x00000000, +0xd48,0x00000000, +0xd4c,0x00000000, +0xd50,0x6437140a, +0xd54,0x024dbd02, +0xd58,0x00000000, +0xd5c,0x2d432064, +0xe00,0x161a1a1a, +0xe04,0x12121416, +0xe08,0x00001800, +0xe0c,0x00000000, +0xe10,0x161a1a1a, +0xe14,0x12121416, +0xe18,0x161a1a1a, +0xe1c,0x12121416, +}; + +#define RadioA_ArrayLengthDTM 246 +u32 Rtl8192PciERadioA_ArrayDTM[RadioA_ArrayLengthDTM] = { +0x019,0x00000003, +0x000,0x000000bf, +0x001,0x00000ee0, +0x002,0x0000004c, +0x003,0x000007f1, +0x004,0x00000975, +0x005,0x00000c58, +0x006,0x00000ae6, +0x007,0x000000ca, +0x008,0x00000e1c, +0x009,0x000007f0, +0x00a,0x000009d0, +0x00b,0x000001ba, +0x00c,0x00000240, +0x00e,0x00000020, +0x00f,0x00000ff0, +0x012,0x00000806, +0x014,0x000005ab, +0x015,0x00000f80, +0x016,0x00000020, +0x017,0x00000597, +0x018,0x0000050a, +0x01a,0x00000e00, +0x01b,0x00000f5e, +0x01c,0x00000008, +0x01d,0x00000607, +0x01e,0x000006cc, +0x01f,0x00000000, +0x020,0x00000096, +0x01f,0x00000001, +0x020,0x00000076, +0x01f,0x00000002, +0x020,0x00000056, +0x01f,0x00000003, +0x020,0x00000036, +0x01f,0x00000004, +0x020,0x00000016, +0x01f,0x00000005, +0x020,0x000001f6, +0x01f,0x00000006, +0x020,0x000001d6, +0x01f,0x00000007, +0x020,0x000001b6, +0x01f,0x00000008, +0x020,0x00000196, +0x01f,0x00000009, +0x020,0x00000176, +0x01f,0x0000000a, +0x020,0x000000f7, +0x01f,0x0000000b, +0x020,0x000000d7, +0x01f,0x0000000c, +0x020,0x000000b7, +0x01f,0x0000000d, +0x020,0x00000097, +0x01f,0x0000000e, +0x020,0x00000077, +0x01f,0x0000000f, +0x020,0x00000057, +0x01f,0x00000010, +0x020,0x00000037, +0x01f,0x00000011, +0x020,0x000000fb, +0x01f,0x00000012, +0x020,0x000000db, +0x01f,0x00000013, +0x020,0x000000bb, +0x01f,0x00000014, +0x020,0x000000ff, +0x01f,0x00000015, +0x020,0x000000e3, +0x01f,0x00000016, +0x020,0x000000c3, +0x01f,0x00000017, +0x020,0x000000a3, +0x01f,0x00000018, +0x020,0x00000083, +0x01f,0x00000019, +0x020,0x00000063, +0x01f,0x0000001a, +0x020,0x00000043, +0x01f,0x0000001b, +0x020,0x00000023, +0x01f,0x0000001c, +0x020,0x00000003, +0x01f,0x0000001d, +0x020,0x000001e3, +0x01f,0x0000001e, +0x020,0x000001c3, +0x01f,0x0000001f, +0x020,0x000001a3, +0x01f,0x00000020, +0x020,0x00000183, +0x01f,0x00000021, +0x020,0x00000163, +0x01f,0x00000022, +0x020,0x00000143, +0x01f,0x00000023, +0x020,0x00000123, +0x01f,0x00000024, +0x020,0x00000103, +0x023,0x00000203, +0x024,0x00000200, +0x00b,0x000001ba, +0x02c,0x000003d7, +0x02d,0x00000ff0, +0x000,0x00000037, +0x004,0x00000160, +0x007,0x00000080, +0x002,0x0000088d, +0x0fe,0x00000000, +0x0fe,0x00000000, +0x016,0x00000200, +0x016,0x00000380, +0x016,0x00000020, +0x016,0x000001a0, +0x000,0x000000bf, +0x00d,0x0000001f, +0x00d,0x00000c9f, +0x002,0x0000004d, +0x000,0x00000cbf, +0x004,0x00000975, +0x007,0x00000700, +}; + +#define RadioB_ArrayLengthDTM 78 +u32 Rtl8192PciERadioB_ArrayDTM[RadioB_ArrayLengthDTM] = { +0x019,0x00000003, +0x000,0x000000bf, +0x001,0x000006e0, +0x002,0x0000004c, +0x003,0x000007f1, +0x004,0x00000975, +0x005,0x00000c58, +0x006,0x00000ae6, +0x007,0x000000ca, +0x008,0x00000e1c, +0x000,0x000000b7, +0x00a,0x00000850, +0x000,0x000000bf, +0x00b,0x000001ba, +0x00c,0x00000240, +0x00e,0x00000020, +0x015,0x00000f80, +0x016,0x00000020, +0x017,0x00000597, +0x018,0x0000050a, +0x01a,0x00000e00, +0x01b,0x00000f5e, +0x01d,0x00000607, +0x01e,0x000006cc, +0x00b,0x000001ba, +0x023,0x00000203, +0x024,0x00000200, +0x000,0x00000037, +0x004,0x00000160, +0x016,0x00000200, +0x016,0x00000380, +0x016,0x00000020, +0x016,0x000001a0, +0x00d,0x00000ccc, +0x000,0x000000bf, +0x002,0x0000004d, +0x000,0x00000cbf, +0x004,0x00000975, +0x007,0x00000700, +}; + +#define RadioC_ArrayLengthDTM 1 +u32 Rtl8192PciERadioC_ArrayDTM[RadioC_ArrayLengthDTM] = { +0x0, }; + +#define RadioD_ArrayLengthDTM 1 +u32 Rtl8192PciERadioD_ArrayDTM[RadioD_ArrayLengthDTM] = { +0x0, }; + +u32 Rtl8192PciEMACPHY_ArrayDTM[] = { +0x03c,0xffff0000,0x00000f0f, +0x340,0xffffffff,0x161a1a1a, +0x344,0xffffffff,0x12121416, +0x348,0x0000ffff,0x00001818, +0x12c,0xffffffff,0x04000802, +0x318,0x00000fff,0x00000100, +}; + +u32 Rtl8192PciEMACPHY_Array_PGDTM[] = { +0x03c,0xffff0000,0x00000f0f, +0xe00,0xffffffff,0x06090909, +0xe04,0xffffffff,0x00030306, +0xe08,0x0000ff00,0x00000000, +0xe10,0xffffffff,0x050b0b0e, +0xe14,0xffffffff,0x00030305, +0xe18,0xffffffff,0x050b0b0e, +0xe1c,0xffffffff,0x00030305, +0x12c,0xffffffff,0x04000802, +0x318,0x00000fff,0x00000800, +}; + +u32 Rtl8192PciEAGCTAB_ArrayDTM[AGCTAB_ArrayLength] = { +0xc78,0x7d000001, +0xc78,0x7d010001, +0xc78,0x7d020001, +0xc78,0x7d030001, +0xc78,0x7d040001, +0xc78,0x7d050001, +0xc78,0x7c060001, +0xc78,0x7b070001, +0xc78,0x7a080001, +0xc78,0x79090001, +0xc78,0x780a0001, +0xc78,0x770b0001, +0xc78,0x760c0001, +0xc78,0x750d0001, +0xc78,0x740e0001, +0xc78,0x730f0001, +0xc78,0x72100001, +0xc78,0x71110001, +0xc78,0x70120001, +0xc78,0x6f130001, +0xc78,0x6e140001, +0xc78,0x6d150001, +0xc78,0x6c160001, +0xc78,0x6b170001, +0xc78,0x6a180001, +0xc78,0x69190001, +0xc78,0x681a0001, +0xc78,0x671b0001, +0xc78,0x661c0001, +0xc78,0x651d0001, +0xc78,0x641e0001, +0xc78,0x491f0001, +0xc78,0x48200001, +0xc78,0x47210001, +0xc78,0x46220001, +0xc78,0x45230001, +0xc78,0x44240001, +0xc78,0x43250001, +0xc78,0x28260001, +0xc78,0x27270001, +0xc78,0x26280001, +0xc78,0x25290001, +0xc78,0x242a0001, +0xc78,0x232b0001, +0xc78,0x222c0001, +0xc78,0x212d0001, +0xc78,0x202e0001, +0xc78,0x0a2f0001, +0xc78,0x08300001, +0xc78,0x06310001, +0xc78,0x05320001, +0xc78,0x04330001, +0xc78,0x03340001, +0xc78,0x02350001, +0xc78,0x01360001, +0xc78,0x00370001, +0xc78,0x00380001, +0xc78,0x00390001, +0xc78,0x003a0001, +0xc78,0x003b0001, +0xc78,0x003c0001, +0xc78,0x003d0001, +0xc78,0x003e0001, +0xc78,0x003f0001, +0xc78,0x7d400001, +0xc78,0x7d410001, +0xc78,0x7d420001, +0xc78,0x7d430001, +0xc78,0x7d440001, +0xc78,0x7d450001, +0xc78,0x7c460001, +0xc78,0x7b470001, +0xc78,0x7a480001, +0xc78,0x79490001, +0xc78,0x784a0001, +0xc78,0x774b0001, +0xc78,0x764c0001, +0xc78,0x754d0001, +0xc78,0x744e0001, +0xc78,0x734f0001, +0xc78,0x72500001, +0xc78,0x71510001, +0xc78,0x70520001, +0xc78,0x6f530001, +0xc78,0x6e540001, +0xc78,0x6d550001, +0xc78,0x6c560001, +0xc78,0x6b570001, +0xc78,0x6a580001, +0xc78,0x69590001, +0xc78,0x685a0001, +0xc78,0x675b0001, +0xc78,0x665c0001, +0xc78,0x655d0001, +0xc78,0x645e0001, +0xc78,0x495f0001, +0xc78,0x48600001, +0xc78,0x47610001, +0xc78,0x46620001, +0xc78,0x45630001, +0xc78,0x44640001, +0xc78,0x43650001, +0xc78,0x28660001, +0xc78,0x27670001, +0xc78,0x26680001, +0xc78,0x25690001, +0xc78,0x246a0001, +0xc78,0x236b0001, +0xc78,0x226c0001, +0xc78,0x216d0001, +0xc78,0x206e0001, +0xc78,0x0a6f0001, +0xc78,0x08700001, +0xc78,0x06710001, +0xc78,0x05720001, +0xc78,0x04730001, +0xc78,0x03740001, +0xc78,0x02750001, +0xc78,0x01760001, +0xc78,0x00770001, +0xc78,0x00780001, +0xc78,0x00790001, +0xc78,0x007a0001, +0xc78,0x007b0001, +0xc78,0x007c0001, +0xc78,0x007d0001, +0xc78,0x007e0001, +0xc78,0x007f0001, +0xc78,0x2e00001e, +0xc78,0x2e01001e, +0xc78,0x2e02001e, +0xc78,0x2e03001e, +0xc78,0x2e04001e, +0xc78,0x2e05001e, +0xc78,0x3006001e, +0xc78,0x3407001e, +0xc78,0x3908001e, +0xc78,0x3c09001e, +0xc78,0x3f0a001e, +0xc78,0x420b001e, +0xc78,0x440c001e, +0xc78,0x450d001e, +0xc78,0x460e001e, +0xc78,0x460f001e, +0xc78,0x4710001e, +0xc78,0x4811001e, +0xc78,0x4912001e, +0xc78,0x4a13001e, +0xc78,0x4b14001e, +0xc78,0x4b15001e, +0xc78,0x4c16001e, +0xc78,0x4d17001e, +0xc78,0x4e18001e, +0xc78,0x4f19001e, +0xc78,0x4f1a001e, +0xc78,0x501b001e, +0xc78,0x511c001e, +0xc78,0x521d001e, +0xc78,0x521e001e, +0xc78,0x531f001e, +0xc78,0x5320001e, +0xc78,0x5421001e, +0xc78,0x5522001e, +0xc78,0x5523001e, +0xc78,0x5624001e, +0xc78,0x5725001e, +0xc78,0x5726001e, +0xc78,0x5827001e, +0xc78,0x5828001e, +0xc78,0x5929001e, +0xc78,0x592a001e, +0xc78,0x5a2b001e, +0xc78,0x5b2c001e, +0xc78,0x5c2d001e, +0xc78,0x5c2e001e, +0xc78,0x5d2f001e, +0xc78,0x5e30001e, +0xc78,0x5f31001e, +0xc78,0x6032001e, +0xc78,0x6033001e, +0xc78,0x6134001e, +0xc78,0x6235001e, +0xc78,0x6336001e, +0xc78,0x6437001e, +0xc78,0x6438001e, +0xc78,0x6539001e, +0xc78,0x663a001e, +0xc78,0x673b001e, +0xc78,0x673c001e, +0xc78,0x683d001e, +0xc78,0x693e001e, +0xc78,0x6a3f001e, +}; + +#endif //__INC_HAL8192PciE_FW_IMG_DTM_H diff --git a/drivers/staging/rtl8192su/r8192S_firmware.c b/drivers/staging/rtl8192su/r8192S_firmware.c new file mode 100644 index 000000000000..b3d69b33acba --- /dev/null +++ b/drivers/staging/rtl8192su/r8192S_firmware.c @@ -0,0 +1,1023 @@ +/************************************************************************************************** + * Procedure: Init boot code/firmware code/data session + * + * Description: This routine will intialize firmware. If any error occurs during the initialization + * process, the routine shall terminate immediately and return fail. + * NIC driver should call NdisOpenFile only from MiniportInitialize. + * + * Arguments: The pointer of the adapter + + * Returns: + * NDIS_STATUS_FAILURE - the following initialization process should be terminated + * NDIS_STATUS_SUCCESS - if firmware initialization process success +**************************************************************************************************/ +//#include "ieee80211.h" +#if defined(RTL8192SE)||defined(RTL8192SU) +#include "r8192U.h" +#include "r8192S_firmware.h" +#include + +#ifdef RTL8192SU +#include "r8192S_hw.h" +#include "r8192SU_HWImg.h" +//#include "r8192S_FwImgDTM.h" +#else +//#include "r8192U_hw.h" +#include "r8192xU_firmware_img.h" +#endif + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) +#include +#endif + +#define byte(x,n) ( (x >> (8 * n)) & 0xff ) + +// +// Description: This routine will intialize firmware. If any error occurs during the initialization +// process, the routine shall terminate immediately and return fail. +// +// Arguments: The pointer of the adapter +// Code address (Virtual address, should fill descriptor with physical address) +// Code size +// Created by Roger, 2008.04.10. +// +bool FirmwareDownloadCode(struct net_device *dev, u8 * code_virtual_address,u32 buffer_len) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + bool rt_status = true; + u16 frag_threshold = MAX_FIRMWARE_CODE_SIZE; //Fragmentation might be required in 90/92 but not in 92S + u16 frag_length, frag_offset = 0; + struct sk_buff *skb; + unsigned char *seg_ptr; + cb_desc *tcb_desc; + u8 bLastIniPkt = 0; + u16 ExtraDescOffset = 0; + +#ifdef RTL8192SE + fw_SetRQPN(dev); // For 92SE only +#endif + + RT_TRACE(COMP_FIRMWARE, "--->FirmwareDownloadCode()\n" ); + + //MAX_TRANSMIT_BUFFER_SIZE + if(buffer_len >= MAX_FIRMWARE_CODE_SIZE-USB_HWDESC_HEADER_LEN) + { + RT_TRACE(COMP_ERR, "Size over MAX_FIRMWARE_CODE_SIZE! \n"); + goto cmdsend_downloadcode_fail; + } + + ExtraDescOffset = USB_HWDESC_HEADER_LEN; + + do { + if((buffer_len-frag_offset) > frag_threshold) + { + frag_length = frag_threshold + ExtraDescOffset; + } + else + { + frag_length = (u16)(buffer_len - frag_offset + ExtraDescOffset); + bLastIniPkt = 1; + } + + /* Allocate skb buffer to contain firmware info and tx descriptor info. */ + skb = dev_alloc_skb(frag_length); + memcpy((unsigned char *)(skb->cb),&dev,sizeof(dev)); + + tcb_desc = (cb_desc*)(skb->cb + MAX_DEV_ADDR_SIZE); + tcb_desc->queue_index = TXCMD_QUEUE; + tcb_desc->bCmdOrInit = DESC_PACKET_TYPE_INIT; + tcb_desc->bLastIniPkt = bLastIniPkt; + + skb_reserve(skb, ExtraDescOffset); + seg_ptr = (u8 *)skb_put(skb, (u32)(frag_length-ExtraDescOffset)); + memcpy(seg_ptr, code_virtual_address+frag_offset, (u32)(frag_length-ExtraDescOffset)); + + tcb_desc->txbuf_size= frag_length; + + if(!priv->ieee80211->check_nic_enough_desc(dev,tcb_desc->queue_index)|| + (!skb_queue_empty(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index]))||\ + (priv->ieee80211->queue_stop) ) + { + RT_TRACE(COMP_FIRMWARE,"=====================================================> tx full!\n"); + skb_queue_tail(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index], skb); + } + else + { + priv->ieee80211->softmac_hard_start_xmit(skb,dev); + } + + frag_offset += (frag_length - ExtraDescOffset); + + }while(frag_offset < buffer_len); + + return rt_status ; + + +cmdsend_downloadcode_fail: + rt_status = false; + RT_TRACE(COMP_ERR, "CmdSendDownloadCode fail !!\n"); + return rt_status; + +} + +#ifdef RTL8192SE +static void fw_SetRQPN(struct net_device *dev) +{ + // Only for 92SE HW bug, we have to set RAPN before every FW download + // We can remove the code later. + write_nic_dword(dev, RQPN, 0xffffffff); + write_nic_dword(dev, RQPN+4, 0xffffffff); + write_nic_byte(dev, RQPN+8, 0xff); + write_nic_byte(dev, RQPN+0xB, 0x80); + //#if ((HAL_CODE_BASE == RTL8192_S) && (PLATFORM != PLATFORM_WINDOWS_USB)) + +} /* fw_SetRQPN */ +#endif + +RT_STATUS +FirmwareEnableCPU(struct net_device *dev) +{ + + RT_STATUS rtStatus = RT_STATUS_SUCCESS; + u8 tmpU1b, CPUStatus = 0; + u16 tmpU2b; + u32 iCheckTime = 200; + + RT_TRACE(COMP_FIRMWARE, "-->FirmwareEnableCPU()\n" ); +#ifdef RTL8192SE + fw_SetRQPN(dev); // For 92SE only +#endif + // Enable CPU. + tmpU1b = read_nic_byte(dev, SYS_CLKR); + write_nic_byte(dev, SYS_CLKR, (tmpU1b|SYS_CPU_CLKSEL)); //AFE source + + tmpU2b = read_nic_word(dev, SYS_FUNC_EN); + write_nic_word(dev, SYS_FUNC_EN, (tmpU2b|FEN_CPUEN)); + + //Polling IMEM Ready after CPU has refilled. + do + { + CPUStatus = read_nic_byte(dev, TCR); + if(CPUStatus& IMEM_RDY) + { + RT_TRACE(COMP_FIRMWARE, "IMEM Ready after CPU has refilled.\n"); + break; + } + + //usleep(100); + udelay(100); + }while(iCheckTime--); + + if(!(CPUStatus & IMEM_RDY)) + return RT_STATUS_FAILURE; + + RT_TRACE(COMP_FIRMWARE, "<--FirmwareEnableCPU(): rtStatus(%#x)\n", rtStatus); + return rtStatus; +} + +FIRMWARE_8192S_STATUS +FirmwareGetNextStatus(FIRMWARE_8192S_STATUS FWCurrentStatus) +{ + FIRMWARE_8192S_STATUS NextFWStatus = 0; + + switch(FWCurrentStatus) + { + case FW_STATUS_INIT: + NextFWStatus = FW_STATUS_LOAD_IMEM; + break; + + case FW_STATUS_LOAD_IMEM: + NextFWStatus = FW_STATUS_LOAD_EMEM; + break; + + case FW_STATUS_LOAD_EMEM: + NextFWStatus = FW_STATUS_LOAD_DMEM; + break; + + case FW_STATUS_LOAD_DMEM: + NextFWStatus = FW_STATUS_READY; + break; + + default: + RT_TRACE(COMP_ERR,"Invalid FW Status(%#x)!!\n", FWCurrentStatus); + break; + } + return NextFWStatus; +} + +bool +FirmwareCheckReady(struct net_device *dev, u8 LoadFWStatus) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + RT_STATUS rtStatus = RT_STATUS_SUCCESS; + rt_firmware *pFirmware = priv->pFirmware; + int PollingCnt = 1000; + //u8 tmpU1b, CPUStatus = 0; + u8 CPUStatus = 0; + u32 tmpU4b; + //bool bOrgIMREnable; + + RT_TRACE(COMP_FIRMWARE, "--->FirmwareCheckReady(): LoadStaus(%d),", LoadFWStatus); + + pFirmware->FWStatus = (FIRMWARE_8192S_STATUS)LoadFWStatus; + if( LoadFWStatus == FW_STATUS_LOAD_IMEM) + { + do + {//Polling IMEM code done. + CPUStatus = read_nic_byte(dev, TCR); + if(CPUStatus& IMEM_CODE_DONE) + break; + + udelay(5); + }while(PollingCnt--); + if(!(CPUStatus & IMEM_CHK_RPT) || PollingCnt <= 0) + { + RT_TRACE(COMP_ERR, "FW_STATUS_LOAD_IMEM FAIL CPU, Status=%x\r\n", CPUStatus); + return false; + } + } + else if( LoadFWStatus == FW_STATUS_LOAD_EMEM) + {//Check Put Code OK and Turn On CPU + do + {//Polling EMEM code done. + CPUStatus = read_nic_byte(dev, TCR); + if(CPUStatus& EMEM_CODE_DONE) + break; + + udelay(5); + }while(PollingCnt--); + if(!(CPUStatus & EMEM_CHK_RPT)) + { + RT_TRACE(COMP_ERR, "FW_STATUS_LOAD_EMEM FAIL CPU, Status=%x\r\n", CPUStatus); + return false; + } + + // Turn On CPU + rtStatus = FirmwareEnableCPU(dev); + if(rtStatus != RT_STATUS_SUCCESS) + { + RT_TRACE(COMP_ERR, "Enable CPU fail ! \n" ); + return false; + } + } + else if( LoadFWStatus == FW_STATUS_LOAD_DMEM) + { + do + {//Polling DMEM code done + CPUStatus = read_nic_byte(dev, TCR); + if(CPUStatus& DMEM_CODE_DONE) + break; + + udelay(5); + }while(PollingCnt--); + + if(!(CPUStatus & DMEM_CODE_DONE)) + { + RT_TRACE(COMP_ERR, "Polling DMEM code done fail ! CPUStatus(%#x)\n", CPUStatus); + return false; + } + + RT_TRACE(COMP_FIRMWARE, "DMEM code download success, CPUStatus(%#x)\n", CPUStatus); + +// PollingCnt = 100; // Set polling cycle to 10ms. + PollingCnt = 10000; // Set polling cycle to 10ms. + + do + {//Polling Load Firmware ready + CPUStatus = read_nic_byte(dev, TCR); + if(CPUStatus & FWRDY) + break; + + udelay(100); + }while(PollingCnt--); + + RT_TRACE(COMP_FIRMWARE, "Polling Load Firmware ready, CPUStatus(%x)\n", CPUStatus); + + //if(!(CPUStatus & LOAD_FW_READY)) + //if((CPUStatus & LOAD_FW_READY) != 0xff) + if((CPUStatus & LOAD_FW_READY) != LOAD_FW_READY) + { + RT_TRACE(COMP_ERR, "Polling Load Firmware ready fail ! CPUStatus(%x)\n", CPUStatus); + return false; + } + + // + // USB interface will update reserved followings parameters later!! + // 2008.08.28. + // +#ifdef RTL8192SE + //write_nic_dword(dev, RQPN, 0x10101010); + //write_nic_byte(dev, 0xAB, 0x80); +#endif + + // + // If right here, we can set TCR/RCR to desired value + // and config MAC lookback mode to normal mode. 2008.08.28. + // + tmpU4b = read_nic_dword(dev,TCR); + write_nic_dword(dev, TCR, (tmpU4b&(~TCR_ICV))); + + tmpU4b = read_nic_dword(dev, RCR); + write_nic_dword(dev, RCR, + (tmpU4b|RCR_APPFCS|RCR_APP_ICV|RCR_APP_MIC)); + + RT_TRACE(COMP_FIRMWARE, "FirmwareCheckReady(): Current RCR settings(%#x)\n", tmpU4b); + +#if (defined (RTL8192SU_FPGA_2MAC_VERIFICATION) ||defined (RTL8192SU_ASIC_VERIFICATION)) +#ifdef NOT_YET //YJ,TMP + priv->TransmitConfig = read_nic_dword(dev, TCR); + RT_TRACE(COMP_FIRMWARE, "FirmwareCheckReady(): Current TCR settings(%x)\n", priv->TransmitConfig); + pHalData->FwRsvdTxPageCfg = read_nic_byte(dev, FW_RSVD_PG_CRTL); +#endif +#endif + + // Set to normal mode. + write_nic_byte(dev, LBKMD_SEL, LBK_NORMAL); + + } + + RT_TRACE(COMP_FIRMWARE, "<---FirmwareCheckReady(): LoadFWStatus(%d), rtStatus(%x)\n", LoadFWStatus, rtStatus); + return (rtStatus == RT_STATUS_SUCCESS) ? true:false; +} + +// +// Description: This routine is to update the RF types in FW header partially. +// +// Created by Roger, 2008.12.24. +// +u8 FirmwareHeaderMapRfType(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + switch(priv->rf_type) + { + case RF_1T1R: return 0x11; + case RF_1T2R: return 0x12; + case RF_2T2R: return 0x22; + case RF_2T2R_GREEN: return 0x92; + default: + RT_TRACE(COMP_INIT, "Unknown RF type(%x)\n",priv->rf_type); + break; + } + return 0x22; +} + + +// +// Description: This routine is to update the private parts in FW header partially. +// +// Created by Roger, 2008.12.18. +// +void FirmwareHeaderPriveUpdate(struct net_device *dev, PRT_8192S_FIRMWARE_PRIV pFwPriv) +{ + struct r8192_priv *priv = ieee80211_priv(dev); +#ifdef RTL8192SU + // Update USB endpoint number for RQPN settings. + pFwPriv->usb_ep_num = priv->EEPROMUsbEndPointNumber; // endpoint number: 4, 6 and 11. + RT_TRACE(COMP_INIT, "FirmwarePriveUpdate(): usb_ep_num(%#x)\n", pFwPriv->usb_ep_num); +#endif + + // Update RF types for RATR settings. + pFwPriv->rf_config = FirmwareHeaderMapRfType(dev); +} + + + +bool FirmwareDownload92S(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + bool rtStatus = true; + const char *pFwImageFileName[1] = {"RTL8192SU/rtl8192sfw.bin"}; + u8 *pucMappedFile = NULL; + u32 ulFileLength, ulInitStep = 0; + u8 FwHdrSize = RT_8192S_FIRMWARE_HDR_SIZE; + rt_firmware *pFirmware = priv->pFirmware; + u8 FwStatus = FW_STATUS_INIT; + PRT_8192S_FIRMWARE_HDR pFwHdr = NULL; + PRT_8192S_FIRMWARE_PRIV pFwPriv = NULL; + int rc; + const struct firmware *fw_entry; + u32 file_length = 0; + + pFirmware->FWStatus = FW_STATUS_INIT; + + RT_TRACE(COMP_FIRMWARE, " --->FirmwareDownload92S()\n"); + + //3// + //3 //<1> Open Image file, and map file to contineous memory if open file success. + //3 // or read image file from array. Default load from BIN file + //3// +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + priv->firmware_source = FW_SOURCE_HEADER_FILE; +#else + priv->firmware_source = FW_SOURCE_IMG_FILE;// We should decided by Reg. +#endif + + switch( priv->firmware_source ) + { + case FW_SOURCE_IMG_FILE: +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + if(pFirmware->szFwTmpBufferLen == 0) + { + + rc = request_firmware(&fw_entry, pFwImageFileName[ulInitStep],&priv->udev->dev);//===>1 + if(rc < 0 ) { + RT_TRACE(COMP_ERR, "request firmware fail!\n"); + goto DownloadFirmware_Fail; + } + + if(fw_entry->size > sizeof(pFirmware->szFwTmpBuffer)) + { + RT_TRACE(COMP_ERR, "img file size exceed the container buffer fail!\n"); + release_firmware(fw_entry); + goto DownloadFirmware_Fail; + } + + memcpy(pFirmware->szFwTmpBuffer,fw_entry->data,fw_entry->size); + pFirmware->szFwTmpBufferLen = fw_entry->size; + release_firmware(fw_entry); + + pucMappedFile = pFirmware->szFwTmpBuffer; + file_length = pFirmware->szFwTmpBufferLen; + + //Retrieve FW header. + pFirmware->pFwHeader = (PRT_8192S_FIRMWARE_HDR) pucMappedFile; + pFwHdr = pFirmware->pFwHeader; + RT_TRACE(COMP_FIRMWARE,"signature:%x, version:%x, size:%x, imemsize:%x, sram size:%x\n", \ + pFwHdr->Signature, pFwHdr->Version, pFwHdr->DMEMSize, \ + pFwHdr->IMG_IMEM_SIZE, pFwHdr->IMG_SRAM_SIZE); + pFirmware->FirmwareVersion = byte(pFwHdr->Version ,0); + if ((pFwHdr->IMG_IMEM_SIZE==0) || (pFwHdr->IMG_IMEM_SIZE > sizeof(pFirmware->FwIMEM))) + { + RT_TRACE(COMP_ERR, "%s: memory for data image is less than IMEM required\n",\ + __FUNCTION__); + goto DownloadFirmware_Fail; + } else { + pucMappedFile+=FwHdrSize; + + //Retrieve IMEM image. + memcpy(pFirmware->FwIMEM, pucMappedFile, pFwHdr->IMG_IMEM_SIZE); + pFirmware->FwIMEMLen = pFwHdr->IMG_IMEM_SIZE; + } + + if (pFwHdr->IMG_SRAM_SIZE > sizeof(pFirmware->FwEMEM)) + { + RT_TRACE(COMP_ERR, "%s: memory for data image is less than EMEM required\n",\ + __FUNCTION__); + goto DownloadFirmware_Fail; + } else { + pucMappedFile += pFirmware->FwIMEMLen; + + /* Retriecve EMEM image */ + memcpy(pFirmware->FwEMEM, pucMappedFile, pFwHdr->IMG_SRAM_SIZE);//===>6 + pFirmware->FwEMEMLen = pFwHdr->IMG_SRAM_SIZE; + } + + + } +#endif + break; + + case FW_SOURCE_HEADER_FILE: +#if 1 +#define Rtl819XFwImageArray Rtl8192SUFwImgArray + //2008.11.10 Add by tynli. + pucMappedFile = Rtl819XFwImageArray; + ulFileLength = ImgArrayLength; + + RT_TRACE(COMP_INIT,"Fw download from header.\n"); + /* Retrieve FW header*/ + pFirmware->pFwHeader = (PRT_8192S_FIRMWARE_HDR) pucMappedFile; + pFwHdr = pFirmware->pFwHeader; + RT_TRACE(COMP_FIRMWARE,"signature:%x, version:%x, size:%x, imemsize:%x, sram size:%x\n", \ + pFwHdr->Signature, pFwHdr->Version, pFwHdr->DMEMSize, \ + pFwHdr->IMG_IMEM_SIZE, pFwHdr->IMG_SRAM_SIZE); + pFirmware->FirmwareVersion = byte(pFwHdr->Version ,0); + + if ((pFwHdr->IMG_IMEM_SIZE==0) || (pFwHdr->IMG_IMEM_SIZE > sizeof(pFirmware->FwIMEM))) + { + printk("FirmwareDownload92S(): memory for data image is less than IMEM required\n"); + goto DownloadFirmware_Fail; + } else { + pucMappedFile+=FwHdrSize; + //Retrieve IMEM image. + memcpy(pFirmware->FwIMEM, pucMappedFile, pFwHdr->IMG_IMEM_SIZE); + pFirmware->FwIMEMLen = pFwHdr->IMG_IMEM_SIZE; + } + + if (pFwHdr->IMG_SRAM_SIZE > sizeof(pFirmware->FwEMEM)) + { + printk(" FirmwareDownload92S(): memory for data image is less than EMEM required\n"); + goto DownloadFirmware_Fail; + } else { + pucMappedFile+= pFirmware->FwIMEMLen; + + //Retriecve EMEM image. + memcpy(pFirmware->FwEMEM, pucMappedFile, pFwHdr->IMG_SRAM_SIZE); + pFirmware->FwEMEMLen = pFwHdr->IMG_SRAM_SIZE; + } +#endif + break; + default: + break; + } + + FwStatus = FirmwareGetNextStatus(pFirmware->FWStatus); + while(FwStatus!= FW_STATUS_READY) + { + // Image buffer redirection. + switch(FwStatus) + { + case FW_STATUS_LOAD_IMEM: + pucMappedFile = pFirmware->FwIMEM; + ulFileLength = pFirmware->FwIMEMLen; + break; + + case FW_STATUS_LOAD_EMEM: + pucMappedFile = pFirmware->FwEMEM; + ulFileLength = pFirmware->FwEMEMLen; + break; + + case FW_STATUS_LOAD_DMEM: + /* Partial update the content of header private. 2008.12.18 */ + pFwHdr = pFirmware->pFwHeader; + pFwPriv = (PRT_8192S_FIRMWARE_PRIV)&pFwHdr->FWPriv; + FirmwareHeaderPriveUpdate(dev, pFwPriv); + pucMappedFile = (u8*)(pFirmware->pFwHeader)+RT_8192S_FIRMWARE_HDR_EXCLUDE_PRI_SIZE; + ulFileLength = FwHdrSize-RT_8192S_FIRMWARE_HDR_EXCLUDE_PRI_SIZE; + break; + + default: + RT_TRACE(COMP_ERR, "Unexpected Download step!!\n"); + goto DownloadFirmware_Fail; + break; + } + + //3// + //3// <2> Download image file + //3 // + rtStatus = FirmwareDownloadCode(dev, pucMappedFile, ulFileLength); + + if(rtStatus != true) + { + RT_TRACE(COMP_ERR, "FirmwareDownloadCode() fail ! \n" ); + goto DownloadFirmware_Fail; + } + + //3// + //3// <3> Check whether load FW process is ready + //3 // + rtStatus = FirmwareCheckReady(dev, FwStatus); + + if(rtStatus != true) + { + RT_TRACE(COMP_ERR, "FirmwareDownloadCode() fail ! \n"); + goto DownloadFirmware_Fail; + } + + FwStatus = FirmwareGetNextStatus(pFirmware->FWStatus); + } + + RT_TRACE(COMP_FIRMWARE, "Firmware Download Success!!\n"); + return rtStatus; + + DownloadFirmware_Fail: + RT_TRACE(COMP_ERR, "Firmware Download Fail!!%x\n",read_nic_word(dev, TCR)); + rtStatus = false; + return rtStatus; +} +#else +void firmware_init_param(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + rt_firmware *pfirmware = priv->pFirmware; + + pfirmware->cmdpacket_frag_thresold = GET_COMMAND_PACKET_FRAG_THRESHOLD(MAX_TRANSMIT_BUFFER_SIZE); +} + +/* + * segment the img and use the ptr and length to remember info on each segment + * + */ +bool fw_download_code(struct net_device *dev, u8 *code_virtual_address, u32 buffer_len) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + bool rt_status = true; + //u16 frag_threshold; + u16 frag_length, frag_offset = 0; + //u16 total_size; + int i; + + //rt_firmware *pfirmware = priv->pFirmware; + struct sk_buff *skb; + unsigned char *seg_ptr; + cb_desc *tcb_desc; + u8 bLastIniPkt; +#ifdef RTL8192SE + fw_SetRQPN(dev); // For 92SE only +#endif + +#ifndef RTL8192SU + if(buffer_len >= 64000-USB_HWDESC_HEADER_LEN) + { + return rt_status; + } + firmware_init_param(dev); + //Fragmentation might be required + frag_threshold = pfirmware->cmdpacket_frag_thresold; +#endif + + do { +#ifndef RTL8192SU + if((buffer_len - frag_offset) > frag_threshold) { + frag_length = frag_threshold ; + bLastIniPkt = 0; + + } else +#endif + { + frag_length = buffer_len - frag_offset; + bLastIniPkt = 1; + + } + + /* Allocate skb buffer to contain firmware info and tx descriptor info + * add 4 to avoid packet appending overflow. + * */ + #ifdef RTL8192U + skb = dev_alloc_skb(USB_HWDESC_HEADER_LEN + frag_length + 4); + #else + skb = dev_alloc_skb(frag_length + 4); + #endif + memcpy((unsigned char *)(skb->cb),&dev,sizeof(dev)); + tcb_desc = (cb_desc*)(skb->cb + MAX_DEV_ADDR_SIZE); + tcb_desc->queue_index = TXCMD_QUEUE; + tcb_desc->bCmdOrInit = DESC_PACKET_TYPE_INIT; + tcb_desc->bLastIniPkt = bLastIniPkt; + + #ifdef RTL8192U + skb_reserve(skb, USB_HWDESC_HEADER_LEN); + #endif + seg_ptr = skb->data; + /* + * Transform from little endian to big endian + * and pending zero + */ + for(i=0 ; i < frag_length; i+=4) { + *seg_ptr++ = ((i+0)txbuf_size= (u16)i; + skb_put(skb, i); + + if(!priv->ieee80211->check_nic_enough_desc(dev,tcb_desc->queue_index)|| + (!skb_queue_empty(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index]))||\ + (priv->ieee80211->queue_stop) ) { + RT_TRACE(COMP_FIRMWARE,"=====================================================> tx full!\n"); + skb_queue_tail(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index], skb); + } else { + priv->ieee80211->softmac_hard_start_xmit(skb,dev); + } + + code_virtual_address += frag_length; + frag_offset += frag_length; + + }while(frag_offset < buffer_len); + + return rt_status; + +#if 0 +cmdsend_downloadcode_fail: + rt_status = false; + RT_TRACE(COMP_ERR, "CmdSendDownloadCode fail !!\n"); + return rt_status; +#endif +} + +bool +fwSendNullPacket( + struct net_device *dev, + u32 Length +) +{ + bool rtStatus = true; + struct r8192_priv *priv = ieee80211_priv(dev); + struct sk_buff *skb; + cb_desc *tcb_desc; + unsigned char *ptr_buf; + bool bLastInitPacket = false; + + //PlatformAcquireSpinLock(dev, RT_TX_SPINLOCK); + + //Get TCB and local buffer from common pool. (It is shared by CmdQ, MgntQ, and USB coalesce DataQ) + skb = dev_alloc_skb(Length+ 4); + memcpy((unsigned char *)(skb->cb),&dev,sizeof(dev)); + tcb_desc = (cb_desc*)(skb->cb + MAX_DEV_ADDR_SIZE); + tcb_desc->queue_index = TXCMD_QUEUE; + tcb_desc->bCmdOrInit = DESC_PACKET_TYPE_INIT; + tcb_desc->bLastIniPkt = bLastInitPacket; + ptr_buf = skb_put(skb, Length); + memset(ptr_buf,0,Length); + tcb_desc->txbuf_size= (u16)Length; + + if(!priv->ieee80211->check_nic_enough_desc(dev,tcb_desc->queue_index)|| + (!skb_queue_empty(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index]))||\ + (priv->ieee80211->queue_stop) ) { + RT_TRACE(COMP_FIRMWARE,"===================NULL packet==================================> tx full!\n"); + skb_queue_tail(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index], skb); + } else { + priv->ieee80211->softmac_hard_start_xmit(skb,dev); + } + + //PlatformReleaseSpinLock(dev, RT_TX_SPINLOCK); + return rtStatus; +} + +//----------------------------------------------------------------------------- +// Procedure: Check whether main code is download OK. If OK, turn on CPU +// +// Description: CPU register locates in different page against general register. +// Switch to CPU register in the begin and switch back before return +// +// +// Arguments: The pointer of the dev +// +// Returns: +// NDIS_STATUS_FAILURE - the following initialization process should be terminated +// NDIS_STATUS_SUCCESS - if firmware initialization process success +//----------------------------------------------------------------------------- +bool CPUcheck_maincodeok_turnonCPU(struct net_device *dev) +{ + bool rt_status = true; + int check_putcodeOK_time = 200000, check_bootOk_time = 200000; + u32 CPU_status = 0; + + /* Check whether put code OK */ + do { + CPU_status = read_nic_dword(dev, CPU_GEN); + + if(CPU_status&CPU_GEN_PUT_CODE_OK) + break; + + }while(check_putcodeOK_time--); + + if(!(CPU_status&CPU_GEN_PUT_CODE_OK)) { + RT_TRACE(COMP_ERR, "Download Firmware: Put code fail!\n"); + goto CPUCheckMainCodeOKAndTurnOnCPU_Fail; + } else { + RT_TRACE(COMP_FIRMWARE, "Download Firmware: Put code ok!\n"); + } + + /* Turn On CPU */ + CPU_status = read_nic_dword(dev, CPU_GEN); + write_nic_byte(dev, CPU_GEN, (u8)((CPU_status|CPU_GEN_PWR_STB_CPU)&0xff)); + mdelay(1000); + + /* Check whether CPU boot OK */ + do { + CPU_status = read_nic_dword(dev, CPU_GEN); + + if(CPU_status&CPU_GEN_BOOT_RDY) + break; + }while(check_bootOk_time--); + + if(!(CPU_status&CPU_GEN_BOOT_RDY)) { + goto CPUCheckMainCodeOKAndTurnOnCPU_Fail; + } else { + RT_TRACE(COMP_FIRMWARE, "Download Firmware: Boot ready!\n"); + } + + return rt_status; + +CPUCheckMainCodeOKAndTurnOnCPU_Fail: + RT_TRACE(COMP_ERR, "ERR in %s()\n", __FUNCTION__); + rt_status = FALSE; + return rt_status; +} + +bool CPUcheck_firmware_ready(struct net_device *dev) +{ + + bool rt_status = true; + int check_time = 200000; + u32 CPU_status = 0; + + /* Check Firmware Ready */ + do { + CPU_status = read_nic_dword(dev, CPU_GEN); + + if(CPU_status&CPU_GEN_FIRM_RDY) + break; + + }while(check_time--); + + if(!(CPU_status&CPU_GEN_FIRM_RDY)) + goto CPUCheckFirmwareReady_Fail; + else + RT_TRACE(COMP_FIRMWARE, "Download Firmware: Firmware ready!\n"); + + return rt_status; + +CPUCheckFirmwareReady_Fail: + RT_TRACE(COMP_ERR, "ERR in %s()\n", __FUNCTION__); + rt_status = false; + return rt_status; + +} + +bool init_firmware(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + bool rt_status = TRUE; + + u8 *firmware_img_buf[3] = { &rtl8190_fwboot_array[0], + &rtl8190_fwmain_array[0], + &rtl8190_fwdata_array[0]}; + + u32 firmware_img_len[3] = { sizeof(rtl8190_fwboot_array), + sizeof(rtl8190_fwmain_array), + sizeof(rtl8190_fwdata_array)}; + u32 file_length = 0; + u8 *mapped_file = NULL; + u32 init_step = 0; + opt_rst_type_e rst_opt = OPT_SYSTEM_RESET; + firmware_init_step_e starting_state = FW_INIT_STEP0_BOOT; + + rt_firmware *pfirmware = priv->pFirmware; + const struct firmware *fw_entry; + const char *fw_name[3] = { "RTL8192U/boot.img", + "RTL8192U/main.img", + "RTL8192U/data.img"}; + int rc; + + RT_TRACE(COMP_FIRMWARE, " PlatformInitFirmware()==>\n"); + + if (pfirmware->firmware_status == FW_STATUS_0_INIT ) { + /* it is called by reset */ + rst_opt = OPT_SYSTEM_RESET; + starting_state = FW_INIT_STEP0_BOOT; + // TODO: system reset + + }else if(pfirmware->firmware_status == FW_STATUS_5_READY) { + /* it is called by Initialize */ + rst_opt = OPT_FIRMWARE_RESET; + starting_state = FW_INIT_STEP2_DATA; + }else { + RT_TRACE(COMP_FIRMWARE, "PlatformInitFirmware: undefined firmware state\n"); + } + + /* + * Download boot, main, and data image for System reset. + * Download data image for firmware reseta + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + priv->firmware_source = FW_SOURCE_HEADER_FILE; +#else + priv->firmware_source = FW_SOURCE_IMG_FILE; +#endif + for(init_step = starting_state; init_step <= FW_INIT_STEP2_DATA; init_step++) { + /* + * Open Image file, and map file to contineous memory if open file success. + * or read image file from array. Default load from IMG file + */ + if(rst_opt == OPT_SYSTEM_RESET) { + switch(priv->firmware_source) { + case FW_SOURCE_IMG_FILE: + #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + rc = request_firmware(&fw_entry, fw_name[init_step],&priv->udev->dev); + if(rc < 0 ) { + RT_TRACE(COMP_ERR, "request firmware fail!\n"); + goto download_firmware_fail; + } + + if(fw_entry->size > sizeof(pfirmware->firmware_buf)) { + RT_TRACE(COMP_ERR, "img file size exceed the container buffer fail!\n"); + goto download_firmware_fail; + } + + if(init_step != FW_INIT_STEP1_MAIN) { + memcpy(pfirmware->firmware_buf,fw_entry->data,fw_entry->size); + mapped_file = pfirmware->firmware_buf; + file_length = fw_entry->size; + } else { + #ifdef RTL8190P + memcpy(pfirmware->firmware_buf,fw_entry->data,fw_entry->size); + mapped_file = pfirmware->firmware_buf; + file_length = fw_entry->size; + #else + memset(pfirmware->firmware_buf,0,128); + memcpy(&pfirmware->firmware_buf[128],fw_entry->data,fw_entry->size); + mapped_file = pfirmware->firmware_buf; + file_length = fw_entry->size + 128; + #endif + } + pfirmware->firmware_buf_size = file_length; + #endif + break; + + case FW_SOURCE_HEADER_FILE: + mapped_file = firmware_img_buf[init_step]; + file_length = firmware_img_len[init_step]; + if(init_step == FW_INIT_STEP2_DATA) { + memcpy(pfirmware->firmware_buf, mapped_file, file_length); + pfirmware->firmware_buf_size = file_length; + } + break; + + default: + break; + } + + + }else if(rst_opt == OPT_FIRMWARE_RESET ) { + /* we only need to download data.img here */ + mapped_file = pfirmware->firmware_buf; + file_length = pfirmware->firmware_buf_size; + } + + /* Download image file */ + /* The firmware download process is just as following, + * 1. that is each packet will be segmented and inserted to the wait queue. + * 2. each packet segment will be put in the skb_buff packet. + * 3. each skb_buff packet data content will already include the firmware info + * and Tx descriptor info + * */ + rt_status = fw_download_code(dev,mapped_file,file_length); + #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + if(rst_opt == OPT_SYSTEM_RESET) { + release_firmware(fw_entry); + } + #endif + + if(rt_status != TRUE) { + goto download_firmware_fail; + } + + switch(init_step) { + case FW_INIT_STEP0_BOOT: + /* Download boot + * initialize command descriptor. + * will set polling bit when firmware code is also configured + */ + pfirmware->firmware_status = FW_STATUS_1_MOVE_BOOT_CODE; +#ifdef RTL8190P + // To initialize IMEM, CPU move code from 0x80000080, hence, we send 0x80 byte packet + rt_status = fwSendNullPacket(dev, RTL8190_CPU_START_OFFSET); + if(rt_status != true) + { + RT_TRACE(COMP_INIT, "fwSendNullPacket() fail ! \n"); + goto download_firmware_fail; + } +#endif + //mdelay(1000); + /* + * To initialize IMEM, CPU move code from 0x80000080, + * hence, we send 0x80 byte packet + */ + break; + + case FW_INIT_STEP1_MAIN: + /* Download firmware code. Wait until Boot Ready and Turn on CPU */ + pfirmware->firmware_status = FW_STATUS_2_MOVE_MAIN_CODE; + + /* Check Put Code OK and Turn On CPU */ + rt_status = CPUcheck_maincodeok_turnonCPU(dev); + if(rt_status != TRUE) { + RT_TRACE(COMP_ERR, "CPUcheck_maincodeok_turnonCPU fail!\n"); + goto download_firmware_fail; + } + + pfirmware->firmware_status = FW_STATUS_3_TURNON_CPU; + break; + + case FW_INIT_STEP2_DATA: + /* download initial data code */ + pfirmware->firmware_status = FW_STATUS_4_MOVE_DATA_CODE; + mdelay(1); + + rt_status = CPUcheck_firmware_ready(dev); + if(rt_status != TRUE) { + RT_TRACE(COMP_ERR, "CPUcheck_firmware_ready fail(%d)!\n",rt_status); + goto download_firmware_fail; + } + + /* wait until data code is initialized ready.*/ + pfirmware->firmware_status = FW_STATUS_5_READY; + break; + } + } + + RT_TRACE(COMP_FIRMWARE, "Firmware Download Success\n"); + //assert(pfirmware->firmware_status == FW_STATUS_5_READY, ("Firmware Download Fail\n")); + + return rt_status; + +download_firmware_fail: + RT_TRACE(COMP_ERR, "ERR in %s()\n", __FUNCTION__); + rt_status = FALSE; + return rt_status; + +} +#endif + diff --git a/drivers/staging/rtl8192su/r8192S_firmware.h b/drivers/staging/rtl8192su/r8192S_firmware.h new file mode 100644 index 000000000000..047f8ae44740 --- /dev/null +++ b/drivers/staging/rtl8192su/r8192S_firmware.h @@ -0,0 +1,212 @@ +#ifndef __INC_FIRMWARE_H +#define __INC_FIRMWARE_H + + +//#define RTL8190_CPU_START_OFFSET 0x80 +/* TODO: this definition is TBD */ +//#define USB_HWDESC_HEADER_LEN 0 + +/* It should be double word alignment */ +//#if DEV_BUS_TYPE==PCI_INTERFACE +//#define GET_COMMAND_PACKET_FRAG_THRESHOLD(v) 4*(v/4) - 8 +//#else +//#define GET_COMMAND_PACKET_FRAG_THRESHOLD(v) (4*(v/4) - 8 - USB_HWDESC_HEADER_LEN) +//#endif + +//typedef enum _firmware_init_step{ +// FW_INIT_STEP0_BOOT = 0, +// FW_INIT_STEP1_MAIN = 1, +// FW_INIT_STEP2_DATA = 2, +//}firmware_init_step_e; + +//typedef enum _DESC_PACKET_TYPE{ +// DESC_PACKET_TYPE_INIT = 0, +// DESC_PACKET_TYPE_NORMAL = 1, +//}DESC_PACKET_TYPE; +#define RTL8192S_FW_PKT_FRAG_SIZE 0xFF00 // 64K + + +#define RTL8190_MAX_FIRMWARE_CODE_SIZE 64000 //64k +#define MAX_FIRMWARE_CODE_SIZE 0xFF00 // Firmware Local buffer size. +#define RTL8190_CPU_START_OFFSET 0x80 + +#ifdef RTL8192SE +//It should be double word alignment +#define GET_COMMAND_PACKET_FRAG_THRESHOLD(v) 4*(v/4) - 8 +#else +#define GET_COMMAND_PACKET_FRAG_THRESHOLD(v) (4*(v/4) - 8 - USB_HWDESC_HEADER_LEN) +#endif + +//typedef enum _DESC_PACKET_TYPE{ +// DESC_PACKET_TYPE_INIT = 0, +// DESC_PACKET_TYPE_NORMAL = 1, +//}DESC_PACKET_TYPE; + +// Forward declaration. +//typedef struct _ADAPTER ADAPTER, *PADAPTER; +#ifdef RTL8192S +typedef enum _firmware_init_step{ + FW_INIT_STEP0_IMEM = 0, + FW_INIT_STEP1_MAIN = 1, + FW_INIT_STEP2_DATA = 2, +}firmware_init_step_e; +#else +typedef enum _firmware_init_step{ + FW_INIT_STEP0_BOOT = 0, + FW_INIT_STEP1_MAIN = 1, + FW_INIT_STEP2_DATA = 2, +}firmware_init_step_e; +#endif + +/* due to rtl8192 firmware */ +typedef enum _desc_packet_type_e{ + DESC_PACKET_TYPE_INIT = 0, + DESC_PACKET_TYPE_NORMAL = 1, +}desc_packet_type_e; + +typedef enum _firmware_source{ + FW_SOURCE_IMG_FILE = 0, + FW_SOURCE_HEADER_FILE = 1, +}firmware_source_e, *pfirmware_source_e; + + +typedef enum _opt_rst_type{ + OPT_SYSTEM_RESET = 0, + OPT_FIRMWARE_RESET = 1, +}opt_rst_type_e; + +/*typedef enum _FIRMWARE_STATUS{ + FW_STATUS_0_INIT = 0, + FW_STATUS_1_MOVE_BOOT_CODE = 1, + FW_STATUS_2_MOVE_MAIN_CODE = 2, + FW_STATUS_3_TURNON_CPU = 3, + FW_STATUS_4_MOVE_DATA_CODE = 4, + FW_STATUS_5_READY = 5, +}FIRMWARE_STATUS; +*/ +//-------------------------------------------------------------------------------- +// RTL8192S Firmware related, Revised by Roger, 2008.12.18. +//-------------------------------------------------------------------------------- +typedef struct _RT_8192S_FIRMWARE_PRIV { //8-bytes alignment required + + //--- long word 0 ---- + u8 signature_0; //0x12: CE product, 0x92: IT product + u8 signature_1; //0x87: CE product, 0x81: IT product + u8 hci_sel; //0x81: PCI-AP, 01:PCIe, 02: 92S-U, 0x82: USB-AP, 0x12: 72S-U, 03:SDIO + u8 chip_version; //the same value as reigster value + u8 customer_ID_0; //customer ID low byte + u8 customer_ID_1; //customer ID high byte + u8 rf_config; //0x11: 1T1R, 0x12: 1T2R, 0x92: 1T2R turbo, 0x22: 2T2R + u8 usb_ep_num; // 4: 4EP, 6: 6EP, 11: 11EP + + //--- long word 1 ---- + u8 regulatory_class_0; //regulatory class bit map 0 + u8 regulatory_class_1; //regulatory class bit map 1 + u8 regulatory_class_2; //regulatory class bit map 2 + u8 regulatory_class_3; //regulatory class bit map 3 + u8 rfintfs; // 0:SWSI, 1:HWSI, 2:HWPI + u8 def_nettype; + u8 rsvd010; + u8 rsvd011; + + + //--- long word 2 ---- + u8 lbk_mode; //0x00: normal, 0x03: MACLBK, 0x01: PHYLBK + u8 mp_mode; // 1: for MP use, 0: for normal driver (to be discussed) + u8 rsvd020; + u8 rsvd021; + u8 rsvd022; + u8 rsvd023; + u8 rsvd024; + u8 rsvd025; + + //--- long word 3 ---- + u8 qos_en; // QoS enable + u8 bw_40MHz_en; // 40MHz BW enable + u8 AMSDU2AMPDU_en; // 4181 convert AMSDU to AMPDU, 0: disable + u8 AMPDU_en; // 11n AMPDU enable + u8 rate_control_offload;//FW offloads, 0: driver handles + u8 aggregation_offload; // FW offloads, 0: driver handles + u8 rsvd030; + u8 rsvd031; + + + //--- long word 4 ---- + unsigned char beacon_offload; // 1. FW offloads, 0: driver handles + unsigned char MLME_offload; // 2. FW offloads, 0: driver handles + unsigned char hwpc_offload; // 3. FW offloads, 0: driver handles + unsigned char tcp_checksum_offload; // 4. FW offloads, 0: driver handles + unsigned char tcp_offload; // 5. FW offloads, 0: driver handles + unsigned char ps_control_offload; // 6. FW offloads, 0: driver handles + unsigned char WWLAN_offload; // 7. FW offloads, 0: driver handles + unsigned char rsvd040; + + //--- long word 5 ---- + u8 tcp_tx_frame_len_L; //tcp tx packet length low byte + u8 tcp_tx_frame_len_H; //tcp tx packet length high byte + u8 tcp_rx_frame_len_L; //tcp rx packet length low byte + u8 tcp_rx_frame_len_H; //tcp rx packet length high byte + u8 rsvd050; + u8 rsvd051; + u8 rsvd052; + u8 rsvd053; +}RT_8192S_FIRMWARE_PRIV, *PRT_8192S_FIRMWARE_PRIV; + +typedef struct _RT_8192S_FIRMWARE_HDR {//8-byte alinment required + + //--- LONG WORD 0 ---- + u16 Signature; + u16 Version; //0x8000 ~ 0x8FFF for FPGA version, 0x0000 ~ 0x7FFF for ASIC version, + u32 DMEMSize; //define the size of boot loader + + + //--- LONG WORD 1 ---- + u32 IMG_IMEM_SIZE; //define the size of FW in IMEM + u32 IMG_SRAM_SIZE; //define the size of FW in SRAM + + //--- LONG WORD 2 ---- + u32 FW_PRIV_SIZE; //define the size of DMEM variable + u32 Rsvd0; + + //--- LONG WORD 3 ---- + u32 Rsvd1; + u32 Rsvd2; + + RT_8192S_FIRMWARE_PRIV FWPriv; + +}RT_8192S_FIRMWARE_HDR, *PRT_8192S_FIRMWARE_HDR; + +#define RT_8192S_FIRMWARE_HDR_SIZE 80 +#define RT_8192S_FIRMWARE_HDR_EXCLUDE_PRI_SIZE 32 + +typedef enum _FIRMWARE_8192S_STATUS{ + FW_STATUS_INIT = 0, + FW_STATUS_LOAD_IMEM = 1, + FW_STATUS_LOAD_EMEM = 2, + FW_STATUS_LOAD_DMEM = 3, + FW_STATUS_READY = 4, +}FIRMWARE_8192S_STATUS; + +#define RTL8190_MAX_FIRMWARE_CODE_SIZE 64000 //64k + +typedef struct _rt_firmware{ + firmware_source_e eFWSource; + PRT_8192S_FIRMWARE_HDR pFwHeader; + FIRMWARE_8192S_STATUS FWStatus; + u16 FirmwareVersion; + u8 FwIMEM[RTL8190_MAX_FIRMWARE_CODE_SIZE]; + u8 FwEMEM[RTL8190_MAX_FIRMWARE_CODE_SIZE]; + u32 FwIMEMLen; + u32 FwEMEMLen; + u8 szFwTmpBuffer[164000]; + u32 szFwTmpBufferLen; + u16 CmdPacketFragThresold; +}rt_firmware, *prt_firmware; + +//typedef struct _RT_FIRMWARE_INFO_8192SU{ +// u8 szInfo[16]; +//}RT_FIRMWARE_INFO_8192SU, *PRT_FIRMWARE_INFO_8192SU; +bool FirmwareDownload92S(struct net_device *dev); + +#endif + diff --git a/drivers/staging/rtl8192su/r8192S_hw.h b/drivers/staging/rtl8192su/r8192S_hw.h new file mode 100644 index 000000000000..7a3d850de0bf --- /dev/null +++ b/drivers/staging/rtl8192su/r8192S_hw.h @@ -0,0 +1,1677 @@ +/***************************************************************************** + * Copyright(c) 2008, RealTEK Technology Inc. All Right Reserved. + * + * Module: __INC_HAL8192SEREG_H + * + * + * Note: 1. Define Mac register address and corresponding bit mask map + * 2. CCX register + * 3. Backward compatible register with useless address. + * 4. Define 92SU required register address and definition. + * + * + * Export: Constants, macro, functions(API), global variables(None). + * + * Abbrev: + * + * History: + * Data Who Remark + * 08/07/2007 MHC 1. Porting from 9x series PHYCFG.h. + * 2. Reorganize code architecture. + * + *****************************************************************************/ +#ifndef R8192S_HW +#define R8192S_HW + +typedef enum _VERSION_8192S{ + VERSION_8192S_ACUT, + VERSION_8192S_BCUT, + VERSION_8192S_CCUT +}VERSION_8192S,*PVERSION_8192S; + +//#ifdef RTL8192SU +typedef enum _VERSION_8192SUsb{ + VERSION_8192SU_A, //A-Cut + VERSION_8192SU_B, //B-Cut + VERSION_8192SU_C, //C-Cut +}VERSION_8192SUsb, *PVERSION_8192SUsb; +//#else +typedef enum _VERSION_819xU{ + VERSION_819xU_A, // A-cut + VERSION_819xU_B, // B-cut + VERSION_819xU_C,// C-cut +}VERSION_819xU,*PVERSION_819xU; +//#endif + +/* 2007/11/15 MH Define different RF type. */ +typedef enum _RT_RF_TYPE_DEFINITION +{ + RF_1T2R = 0, + RF_2T4R, + RF_2T2R, +#ifdef RTL8192SU + RF_1T1R, + RF_2T2R_GREEN, +#endif + //RF_3T3R, + //RF_3T4R, + //RF_4T4R, + RF_819X_MAX_TYPE +}RT_RF_TYPE_DEF_E; + +typedef enum _BaseBand_Config_Type{ + BaseBand_Config_PHY_REG = 0, //Radio Path A + BaseBand_Config_AGC_TAB = 1, //Radio Path B +}BaseBand_Config_Type, *PBaseBand_Config_Type; + +#if 0 +typedef enum _RT_RF_TYPE_819xU{ + RF_TYPE_MIN = 0, + RF_8225, + RF_8256, + RF_8258, + RF_PSEUDO_11N = 4, +}RT_RF_TYPE_819xU, *PRT_RF_TYPE_819xU; +#endif + +#define RTL8187_REQT_READ 0xc0 +#define RTL8187_REQT_WRITE 0x40 +#define RTL8187_REQ_GET_REGS 0x05 +#define RTL8187_REQ_SET_REGS 0x05 + +#define MAX_TX_URB 5 +#define MAX_RX_URB 16 + +#define R8180_MAX_RETRY 255 +//#define MAX_RX_NORMAL_URB 3 +//#define MAX_RX_COMMAND_URB 2 +#define RX_URB_SIZE 9100 + +#define BB_ANTATTEN_CHAN14 0x0c +#define BB_ANTENNA_B 0x40 + +#define BB_HOST_BANG (1<<30) +#define BB_HOST_BANG_EN (1<<2) +#define BB_HOST_BANG_CLK (1<<1) +#define BB_HOST_BANG_RW (1<<3) +#define BB_HOST_BANG_DATA 1 + + +//============================================================ +// 8192S Regsiter bit +//============================================================ +#define BB_GLOBAL_RESET_BIT 0x1 + +#define CR_RST 0x10 +#define CR_RE 0x08 +#define CR_TE 0x04 +#define CR_MulRW 0x01 + +#define MAC_FILTER_MASK ((1<<0) | (1<<1) | (1<<2) | (1<<3) | (1<<5) | \ + (1<<12) | (1<<18) | (1<<19) | (1<<20) | (1<<21) | (1<<22) | (1<<23)) + +#define RX_FIFO_THRESHOLD_MASK ((1<<13) | (1<<14) | (1<<15)) +#define RX_FIFO_THRESHOLD_SHIFT 13 +#define RX_FIFO_THRESHOLD_128 3 +#define RX_FIFO_THRESHOLD_256 4 +#define RX_FIFO_THRESHOLD_512 5 +#define RX_FIFO_THRESHOLD_1024 6 +#define RX_FIFO_THRESHOLD_NONE 7 + +#define MAX_RX_DMA_MASK ((1<<8) | (1<<9) | (1<<10)) + +//---------------------------------------------------------------------------- +// 8190 CPU General Register (offset 0x100, 4 byte) +//---------------------------------------------------------------------------- +#define CPU_CCK_LOOPBACK 0x00030000 +#define CPU_GEN_SYSTEM_RESET 0x00000001 +#define CPU_GEN_FIRMWARE_RESET 0x00000008 +#define CPU_GEN_BOOT_RDY 0x00000010 +#define CPU_GEN_FIRM_RDY 0x00000020 +#define CPU_GEN_PUT_CODE_OK 0x00000080 +#define CPU_GEN_BB_RST 0x00000100 +#define CPU_GEN_PWR_STB_CPU 0x00000004 +#define CPU_GEN_NO_LOOPBACK_MSK 0xFFF8FFFF // Set bit18,17,16 to 0. Set bit19 +#define CPU_GEN_NO_LOOPBACK_SET 0x00080000 // Set BIT19 to 1 +//---------------------------------------------------------------------------- +//// +//// 8190 AcmHwCtrl bits (offset 0x171, 1 byte) +////---------------------------------------------------------------------------- +#define MSR_LINK_MASK ((1<<0)|(1<<1)) +#define MSR_LINK_MANAGED 2 +#define MSR_LINK_NONE 0 +#define MSR_LINK_SHIFT 0 +#define MSR_LINK_ADHOC 1 +#define MSR_LINK_MASTER 3 +#define MSR_LINK_ENEDCA (1<<4) + + +//#define Cmd9346CR_9356SEL (1<<4) +#define EPROM_CMD_RESERVED_MASK (1<<5) +#define EPROM_CMD_OPERATING_MODE_SHIFT 6 +#define EPROM_CMD_OPERATING_MODE_MASK ((1<<7)|(1<<6)) +#define EPROM_CMD_CONFIG 0x3 +#define EPROM_CMD_NORMAL 0 +#define EPROM_CMD_LOAD 1 +#define EPROM_CMD_PROGRAM 2 +#define EPROM_CS_SHIFT 3 +#define EPROM_CK_SHIFT 2 +#define EPROM_W_SHIFT 1 +#define EPROM_R_SHIFT 0 + +//#define MAC0 0x000, +//#define MAC1 0x001, +//#define MAC2 0x002, +//#define MAC3 0x003, +//#define MAC4 0x004, +//#define MAC5 0x005, + +//============================================================ +// 8192S Regsiter offset definition +//============================================================ + +// +// MAC register 0x0 - 0x5xx +// 1. System configuration registers. +// 2. Command Control Registers +// 3. MACID Setting Registers +// 4. Timing Control Registers +// 5. FIFO Control Registers +// 6. Adaptive Control Registers +// 7. EDCA Setting Registers +// 8. WMAC, BA and CCX related Register. +// 9. Security Control Registers +// 10. Power Save Control Registers +// 11. General Purpose Registers +// 12. Host Interrupt Status Registers +// 13. Test Mode and Debug Control Registers +// 14. PCIE config register +// + + +// +// 1. System Configuration Registers (Offset: 0x0000 - 0x003F) +// +#define SYS_ISO_CTRL 0x0000 // System Isolation Interface Control. +#define SYS_FUNC_EN 0x0002 // System Function Enable. +#define PMC_FSM 0x0004 // Power Sequence Control. +#define SYS_CLKR 0x0008 // System Clock. +#define EPROM_CMD 0x000A // 93C46/93C56 Command Register. (win CR93C46) +#define EE_VPD 0x000C // EEPROM VPD Data. +#define AFE_MISC 0x0010 // AFE Misc. +#define SPS0_CTRL 0x0011 // Switching Power Supply 0 Control. +#define SPS1_CTRL 0x0018 // Switching Power Supply 1 Control. +#define RF_CTRL 0x001F // RF Block Control. +#define LDOA15_CTRL 0x0020 // V15 Digital LDO Control. +#define LDOV12D_CTRL 0x0021 // V12 Digital LDO Control. +#define LDOHCI12_CTRL 0x0022 // V12 Digital LDO Control. +#define LDO_USB_SDIO 0x0023 // LDO USB Control. +#define LPLDO_CTRL 0x0024 // Low Power LDO Control. +#define AFE_XTAL_CTRL 0x0026 // AFE Crystal Control. +#define AFE_PLL_CTRL 0x0028 // System Function Enable. +#define EFUSE_CTRL 0x0030 // E-Fuse Control. +#define EFUSE_TEST 0x0034 // E-Fuse Test. +#define PWR_DATA 0x0038 // Power on date. +#define DBG_PORT 0x003A // MAC debug port select +#define DPS_TIMER 0x003C // Deep Power Save Timer Register. +#define RCLK_MON 0x003E // Retention Clock Monitor. + +// +// 2. Command Control Registers (Offset: 0x0040 - 0x004F) +// +#define CMDR 0x0040 // MAC Command Register. +#define TXPAUSE 0x0042 // Transmission Pause Register. +#define LBKMD_SEL 0x0043 // Loopback Mode Select Register. +#define TCR 0x0044 // Transmit Configuration Register +#define RCR 0x0048 // Receive Configuration Register +#define MSR 0x004C // Media Status register +#define SYSF_CFG 0x004D // System Function Configuration. +#define RX_PKY_LIMIT 0x004E // RX packet length limit +#define MBIDCTRL 0x004F // MBSSID Control. + +// +// 3. MACID Setting Registers (Offset: 0x0050 - 0x007F) +// +#define MACIDR 0x0050 // MAC ID Register, Offset 0x0050-0x0055 +#define MACIDR0 0x0050 // MAC ID Register, Offset 0x0050-0x0053 +#define MACIDR4 0x0054 // MAC ID Register, Offset 0x0054-0x0055 +#define BSSIDR 0x0058 // BSSID Register, Offset 0x0058-0x005D +#define HWVID 0x005E // HW Version ID. +#define MAR 0x0060 // Multicase Address. +#define MBIDCAMCONTENT 0x0068 // MBSSID CAM Content. +#define MBIDCAMCFG 0x0070 // MBSSID CAM Configuration. +#define BUILDTIME 0x0074 // Build Time Register. +#define BUILDUSER 0x0078 // Build User Register. + +// Redifine MACID register, to compatible prior ICs. +#define IDR0 MACIDR0 +#define IDR4 MACIDR4 + +// +// 4. Timing Control Registers (Offset: 0x0080 - 0x009F) +// +#define TSFR 0x0080 // Timing Sync Function Timer Register. +#define SLOT_TIME 0x0089 // Slot Time Register, in us. +#define USTIME 0x008A // EDCA/TSF clock unit time us unit. +#define SIFS_CCK 0x008C // SIFS for CCK, in us. +#define SIFS_OFDM 0x008E // SIFS for OFDM, in us. +#define PIFS_TIME 0x0090 // PIFS time register. +#define ACK_TIMEOUT 0x0091 // Ack Timeout Register +#define EIFSTR 0x0092 // EIFS time regiser. +#define BCN_INTERVAL 0x0094 // Beacon Interval, in TU. +#define ATIMWND 0x0096 // ATIM Window width, in TU. +#define BCN_DRV_EARLY_INT 0x0098 // Driver Early Interrupt. +#define BCN_DMATIME 0x009A // Beacon DMA and ATIM INT Time. +#define BCN_ERR_THRESH 0x009C // Beacon Error Threshold. +#define MLT 0x009D // MSDU Lifetime. +#define RSVD_MAC_TUNE_US 0x009E // MAC Internal USE. + +// +// 5. FIFO Control Registers (Offset: 0x00A0 - 0x015F) +// +#define RQPN 0x00A0 +#define RQPN1 0x00A0 // Reserved Queue Page Number for BK +#define RQPN2 0x00A1 // Reserved Queue Page Number for BE +#define RQPN3 0x00A2 // Reserved Queue Page Number for VI +#define RQPN4 0x00A3 // Reserved Queue Page Number for VO +#define RQPN5 0x00A4 // Reserved Queue Page Number for HCCA +#define RQPN6 0x00A5 // Reserved Queue Page Number for CMD +#define RQPN7 0x00A6 // Reserved Queue Page Number for MGNT +#define RQPN8 0x00A7 // Reserved Queue Page Number for HIGH +#define RQPN9 0x00A8 // Reserved Queue Page Number for Beacon +#define RQPN10 0x00A9 // Reserved Queue Page Number for Public +#define LD_RQPN 0x00AB // +#define RXFF_BNDY 0x00AC // +#define RXRPT_BNDY 0x00B0 // +#define TXPKTBUF_PGBNDY 0x00B4 // +#define PBP 0x00B5 // +#define RXDRVINFO_SZ 0x00B6 // +#define TXFF_STATUS 0x00B7 // +#define RXFF_STATUS 0x00B8 // +#define TXFF_EMPTY_TH 0x00B9 // +#define SDIO_RX_BLKSZ 0x00BC // +#define RXDMA 0x00BD // +#define RXPKT_NUM 0x00BE // +#define C2HCMD_UDT_SIZE 0x00C0 // +#define C2HCMD_UDT_ADDR 0x00C2 // +#define FIFOPAGE1 0x00C4 // Available public queue page number +#define FIFOPAGE2 0x00C8 // +#define FIFOPAGE3 0x00CC // +#define FIFOPAGE4 0x00D0 // +#define FIFOPAGE5 0x00D4 // +#define FW_RSVD_PG_CRTL 0x00D8 // +#define RXDMA_AGG_PG_TH 0x00D9 // +#define TXRPTFF_RDPTR 0x00E0 // +#define TXRPTFF_WTPTR 0x00E4 // +#define C2HFF_RDPTR 0x00E8 //FIFO Read pointer register. +#define C2HFF_WTPTR 0x00EC //FIFO Write pointer register. +#define RXFF0_RDPTR 0x00F0 // +#define RXFF0_WTPTR 0x00F4 // +#define RXFF1_RDPTR 0x00F8 // +#define RXFF1_WTPTR 0x00FC // +#define RXRPT0_RDPTR 0x0100 // +#define RXRPT0_WTPTR 0x0104 // +#define RXRPT1_RDPTR 0x0108 // +#define RXRPT1_WTPTR 0x010C // +#define RX0_UDT_SIZE 0x0110 // +#define RX1PKTNUM 0x0114 // +#define RXFILTERMAP 0x0116 // +#define RXFILTERMAP_GP1 0x0118 // +#define RXFILTERMAP_GP2 0x011A // +#define RXFILTERMAP_GP3 0x011C // +#define BCNQ_CTRL 0x0120 // +#define MGTQ_CTRL 0x0124 // +#define HIQ_CTRL 0x0128 // +#define VOTID7_CTRL 0x012c // +#define VOTID6_CTRL 0x0130 // +#define VITID5_CTRL 0x0134 // +#define VITID4_CTRL 0x0138 // +#define BETID3_CTRL 0x013c // +#define BETID0_CTRL 0x0140 // +#define BKTID2_CTRL 0x0144 // +#define BKTID1_CTRL 0x0148 // +#define CMDQ_CTRL 0x014c // +#define TXPKT_NUM_CTRL 0x0150 // +#define TXQ_PGADD 0x0152 // +#define TXFF_PG_NUM 0x0154 // +#define TRXDMA_STATUS 0x0156 // + +// +// 6. Adaptive Control Registers (Offset: 0x0160 - 0x01CF) +// +#define INIMCS_SEL 0x0160 // Init MCSrate for 32 MACID 0x160-17f +#define TX_RATE_REG INIMCS_SEL //Current Tx rate register +#define INIRTSMCS_SEL 0x0180 // Init RTSMCSrate +#define RRSR 0x0181 // Response rate setting. +#define ARFR0 0x0184 // Auto Rate Fallback 0 Register. +#define ARFR1 0x0188 // +#define ARFR2 0x018C // +#define ARFR3 0x0190 // +#define ARFR4 0x0194 // +#define ARFR5 0x0198 // +#define ARFR6 0x019C // +#define ARFR7 0x01A0 // +#define AGGLEN_LMT_H 0x01A7 // Aggregation Length Limit for High-MCS +#define AGGLEN_LMT_L 0x01A8 // Aggregation Length Limit for Low-MCS. +#define DARFRC 0x01B0 // Data Auto Rate Fallback Retry Count. +#define RARFRC 0x01B8 // Response Auto Rate Fallback Count. +#define MCS_TXAGC 0x01C0 +#define CCK_TXAGC 0x01C8 + +// +// 7. EDCA Setting Registers (Offset: 0x01D0 - 0x01FF) +// +#define EDCAPARA_VO 0x01D0 // EDCA Parameter Register for VO queue. +#define EDCAPARA_VI 0x01D4 // EDCA Parameter Register for VI queue. +#define EDCAPARA_BE 0x01D8 // EDCA Parameter Register for BE queue. +#define EDCAPARA_BK 0x01DC // EDCA Parameter Register for BK queue. +#define BCNTCFG 0x01E0 // Beacon Time Configuration Register. +#define CWRR 0x01E2 // Contention Window Report Register. +#define ACMAVG 0x01E4 // ACM Average Register. +#define AcmHwCtrl 0x01E7 +#define VO_ADMTM 0x01E8 // Admission Time Register. +#define VI_ADMTM 0x01EC +#define BE_ADMTM 0x01F0 +#define RETRY_LIMIT 0x01F4 // Retry Limit Registers[15:8]-short, [7:0]-long +#define SG_RATE 0x01F6 // Max MCS Rate Available Register, which we Set the hightst SG rate. + +// +// 8. WMAC, BA and CCX related Register. (Offset: 0x0200 - 0x023F) +// +#define NAV_CTRL 0x0200 +#define BW_OPMODE 0x0203 +#define BACAMCMD 0x0204 +#define BACAMCONTENT 0x0208 // Block ACK CAM R/W Register. + +// Roger had defined the 0x2xx register WMAC definition +#define LBDLY 0x0210 // Loopback Delay Register. +#define FWDLY 0x0211 // FW Delay Register. +#define HWPC_RX_CTRL 0x0218 // HW Packet Conversion RX Control Reg +#define MQIR 0x0220 // Mesh Qos Type Indication Register. +#define MAIR 0x0222 // Mesh ACK. +#define MSIR 0x0224 // Mesh HW Security Requirement Indication Reg +#define CLM_RESULT 0x0227 // CCA Busy Fraction(Channel Load) +#define NHM_RPI_CNT 0x0228 // Noise Histogram Measurement (NHM) RPI Report. +#define RXERR_RPT 0x0230 // Rx Error Report. +#define NAV_PROT_LEN 0x0234 // NAV Protection Length. +#define CFEND_TH 0x0236 // CF-End Threshold. +#define AMPDU_MIN_SPACE 0x0237 // AMPDU Min Space. +#define TXOP_STALL_CTRL 0x0238 + +// +// 9. Security Control Registers (Offset: 0x0240 - 0x025F) +// +#define RWCAM 0x0240 //IN 8190 Data Sheet is called CAMcmd +#define WCAMI 0x0244 // Software write CAM input content +#define RCAMO 0x0248 // Software read/write CAM config +#define CAMDBG 0x024C +#define SECR 0x0250 //Security Configuration Register + +// +// 10. Power Save Control Registers (Offset: 0x0260 - 0x02DF) +// +#define WOW_CTRL 0x0260 //Wake On WLAN Control. +#define PSSTATUS 0x0261 // Power Save Status. +#define PSSWITCH 0x0262 // Power Save Switch. +#define MIMOPS_WAIT_PERIOD 0x0263 +#define LPNAV_CTRL 0x0264 +#define WFM0 0x0270 // Wakeup Frame Mask. +#define WFM1 0x0280 // +#define WFM2 0x0290 // +#define WFM3 0x02A0 // +#define WFM4 0x02B0 // +#define WFM5 0x02C0 // FW Control register. +#define WFCRC 0x02D0 // Wakeup Frame CRC. +#define RPWM 0x02DC // Host Request Power Mode. +#define CPWM 0x02DD // Current Power Mode. +#define FW_RPT_REG 0x02c4 + +// +// 11. General Purpose Registers (Offset: 0x02E0 - 0x02FF) +// +#define PSTIME 0x02E0 // Power Save Timer Register +#define TIMER0 0x02E4 // +#define TIMER1 0x02E8 // +#define GPIO_CTRL 0x02EC // GPIO Control Register +#define GPIO_IN 0x02EC // GPIO pins input value +#define GPIO_OUT 0x02ED // GPIO pins output value +#define GPIO_IO_SEL 0x02EE // GPIO pins output enable when a bit is set to "1"; otherwise, input is configured. +#define GPIO_MOD 0x02EF // +#define GPIO_INTCTRL 0x02F0 // GPIO Interrupt Control Register[7:0] +#define MAC_PINMUX_CFG 0x02F1 // MAC PINMUX Configuration Reg[7:0] +#define LEDCFG 0x02F2 // System PINMUX Configuration Reg[7:0] +#define PHY_REG 0x02F3 // RPT: PHY REG Access Report Reg[7:0] +#define PHY_REG_DATA 0x02F4 // PHY REG Read DATA Register [31:0] +#define EFUSE_CLK 0x02F8 // CTRL: E-FUSE Clock Control Reg[7:0] +//#define GPIO_INTCTRL 0x02F9 // GPIO Interrupt Control Register[7:0] + +// +// 12. Host Interrupt Status Registers (Offset: 0x0300 - 0x030F) +// +#define IMR 0x0300 // Interrupt Mask Register +#define ISR 0x0308 // Interrupt Status Register + +// +// 13. Test Mode and Debug Control Registers (Offset: 0x0310 - 0x034F) +// +#define DBG_PORT_SWITCH 0x003A +#define BIST 0x0310 // Bist reg definition +#define DBS 0x0314 // Debug Select ??? +#define CPUINST 0x0318 // CPU Instruction Read Register +#define CPUCAUSE 0x031C // CPU Cause Register +#define LBUS_ERR_ADDR 0x0320 // Lexra Bus Error Address Register +#define LBUS_ERR_CMD 0x0324 // Lexra Bus Error Command Register +#define LBUS_ERR_DATA_L 0x0328 // Lexra Bus Error Data Low DW Register +#define LBUS_ERR_DATA_H 0x032C // +#define LX_EXCEPTION_ADDR 0x0330 // Lexra Bus Exception Address Register +#define WDG_CTRL 0x0334 // Watch Dog Control Register +#define INTMTU 0x0338 // Interrupt Mitigation Time Unit Reg +#define INTM 0x033A // Interrupt Mitigation Register +#define FDLOCKTURN0 0x033C // FW/DRV Lock Turn 0 Register +#define FDLOCKTURN1 0x033D // FW/DRV Lock Turn 1 Register +#define TRXPKTBUF_DBG_DATA 0x0340 // TRX Packet Buffer Debug Data Register +#define TRXPKTBUF_DBG_CTRL 0x0348 // TRX Packet Buffer Debug Control Reg +#define DPLL 0x034A // DPLL Monitor Register [15:0] +#define CBUS_ERR_ADDR 0x0350 // CPU Bus Error Address Register +#define CBUS_ERR_CMD 0x0354 // CPU Bus Error Command Register +#define CBUS_ERR_DATA_L 0x0358 // CPU Bus Error Data Low DW Register +#define CBUS_ERR_DATA_H 0x035C // +#define USB_SIE_INTF_ADDR 0x0360 // USB SIE Access Interface Address Reg +#define USB_SIE_INTF_WD 0x0361 // USB SIE Access Interface WData Reg +#define USB_SIE_INTF_RD 0x0362 // USB SIE Access Interface RData Reg +#define USB_SIE_INTF_CTRL 0x0363 // USB SIE Access Interface Control Reg + +// Boundary is 0x37F + +// +// 14. PCIE config register (Offset 0x500-) +// +#define TPPoll 0x0500 // Transmit Polling +#define PM_CTRL 0x0502 // PCIE power management control Register +#define PCIF 0x0503 // PCI Function Register 0x0009h~0x000bh + +#define THPDA 0x0514 // Transmit High Priority Desc Addr +#define TMDA 0x0518 // Transmit Management Desc Addr +#define TCDA 0x051C // Transmit Command Desc Addr +#define HDA 0x0520 // HCCA Desc Addr +#define TVODA 0x0524 // Transmit VO Desc Addr +#define TVIDA 0x0528 // Transmit VI Desc Addr +#define TBEDA 0x052C // Transmit BE Desc Addr +#define TBKDA 0x0530 // Transmit BK Desc Addr +#define TBDA 0x0534 // Transmit Beacon Desc Addr +#define RCDA 0x0538 // Receive Command Desc Addr +#define RDSA 0x053C // Receive Desc Starting Addr +#define DBI_WDATA 0x0540 // DBI write data Register +#define DBI_RDATA 0x0544 // DBI read data Register +#define DBI_CTRL 0x0548 // PCIE DBI control Register +#define MDIO_DATA 0x0550 // PCIE MDIO data Register +#define MDIO_CTRL 0x0554 // PCIE MDIO control Register +#define PCI_RPWM 0x0561 // PCIE RPWM register +#define PCI_CPWM 0x0563 // Current Power Mode. + +// +// Config register (Offset 0x800-) +// +#define PHY_CCA 0x803 // CCA related register + +//============================================================================ +// 8192S USB specific Regsiter Offset and Content definition, +// 2008.08.28, added by Roger. +//============================================================================ +// Rx Aggregation time-out reg. +#define USB_RX_AGG_TIMEOUT 0xFE5B + +// Firware reserved Tx page control. +#define FW_OFFLOAD_EN BIT7 + +// Min Spacing related settings. +#define MAX_MSS_DENSITY 0x13 +#define MAX_MSS_DENSITY_2T 0x13 +#define MAX_MSS_DENSITY_1T 0x0A + +// Rx DMA Control related settings +#define RXDMA_AGG_EN BIT7 + +// USB Rx Aggregation TimeOut settings +#define RXDMA_AGG_TIMEOUT_DISABLE 0x00 +#define RXDMA_AGG_TIMEOUT_17MS 0x01 +#define RXDMA_AGG_TIMEOUT_17_2_MS 0x02 +#define RXDMA_AGG_TIMEOUT_17_4_MS 0x04 +#define RXDMA_AGG_TIMEOUT_17_10_MS 0x0A +// USB RPWM register +#define USB_RPWM 0xFE58 + +//FIXLZM SVN_BRACH NOT MOD HERE, IF MOD RX IS LITTLE LOW +//#if ((HAL_CODE_BASE == RTL8192_S) && (DEV_BUS_TYPE==PCI_INTERFACE)) +//#define RPWM PCI_RPWM +//#elif ((HAL_CODE_BASE == RTL8192_S) && (DEV_BUS_TYPE==USB_INTERFACE)) +//#define RPWM USB_RPWM +//#endif + + +//============================================================================ +// 8190 Regsiter offset definition +//============================================================================ +#if 1 // Delete the register later +#define AFR 0x010 // AutoLoad Function Register +#define BCN_TCFG 0x062 // Beacon Time Configuration +#define RATR0 0x320 // Rate Adaptive Table register1 +#endif +// TODO: Remove unused register, We must declare backward compatiable +//Undefined register set in 8192S. 0x320/350 DW is useless +#define UnusedRegister 0x0320 +#define PSR UnusedRegister // Page Select Register +//Security Related +#define DCAM UnusedRegister // Debug CAM Interface +//PHY Configuration related +#define BBAddr UnusedRegister // Phy register address register +#define PhyDataR UnusedRegister // Phy register data read +#define UFWP UnusedRegister + + +//============================================================================ +// 8192S Regsiter Bit and Content definition +//============================================================================ + +// +// 1. System Configuration Registers (Offset: 0x0000 - 0x003F) +// +//---------------------------------------------------------------------------- +// 8192S SYS_ISO_CTRL bits (Offset 0x0, 16bit) +//---------------------------------------------------------------------------- +#define ISO_MD2PP BIT0 // MACTOP/BB/PCIe Digital to Power On. +#define ISO_PA2PCIE BIT3 // PCIe Analog 1.2V to PCIe 3.3V +#define ISO_PLL2MD BIT4 // AFE PLL to MACTOP/BB/PCIe Digital. +#define ISO_PWC_DV2RP BIT11 // Digital Vdd to Retention Path +#define ISO_PWC_RV2RP BIT12 // LPLDOR12 to Retenrion Path, 1: isolation, 0: attach. + +//---------------------------------------------------------------------------- +// 8192S SYS_FUNC_EN bits (Offset 0x2, 16bit) +//---------------------------------------------------------------------------- +#define FEN_MREGEN BIT15 // MAC I/O Registers Enable. +#define FEN_DCORE BIT11 // Enable Core Digital. +#define FEN_CPUEN BIT10 // Enable CPU Core Digital. +// 8192S PMC_FSM bits (Offset 0x4, 32bit) +//---------------------------------------------------------------------------- +#define PAD_HWPD_IDN BIT22 // HWPDN PAD status Indicator + +//---------------------------------------------------------------------------- + +//---------------------------------------------------------------------------- +// 8192S SYS_CLKR bits (Offset 0x8, 16bit) +//---------------------------------------------------------------------------- +#define SYS_CLKSEL_80M BIT0 // System Clock 80MHz +#define SYS_PS_CLKSEL BIT1 //System power save clock select. +#define SYS_CPU_CLKSEL BIT2 // System Clock select, 1: AFE source, 0: System clock(L-Bus) +#define SYS_MAC_CLK_EN BIT11 // MAC Clock Enable. +#define SYS_SWHW_SEL BIT14 // Load done, control path seitch. +#define SYS_FWHW_SEL BIT15 // Sleep exit, control path swith. + + +//---------------------------------------------------------------------------- +// 8192S Cmd9346CR bits (Offset 0xA, 16bit) +//---------------------------------------------------------------------------- +#define CmdEEPROM_En BIT5 // EEPROM enable when set 1 +#define CmdEERPOMSEL BIT4 // System EEPROM select, 0: boot from E-FUSE, 1: The EEPROM used is 9346 +#define Cmd9346CR_9356SEL BIT4 +#define AutoLoadEEPROM (CmdEEPROM_En|CmdEERPOMSEL) +#define AutoLoadEFUSE CmdEEPROM_En + + +//---------------------------------------------------------------------------- +// 8192S AFE_MISC bits AFE Misc (Offset 0x10, 8bits) +//---------------------------------------------------------------------------- +#define AFE_MBEN BIT1 // Enable AFE Macro Block's Mbias. +#define AFE_BGEN BIT0 // Enable AFE Macro Block's Bandgap. + +//---------------------------------------------------------------------------- +// 8192S SPS1_CTRL bits (Offset 0x18-1E, 56bits) +//---------------------------------------------------------------------------- +#define SPS1_SWEN BIT1 // Enable vsps18 SW Macro Block. +#define SPS1_LDEN BIT0 // Enable VSPS12 LDO Macro block. + +//---------------------------------------------------------------------------- +// 8192S RF_CTRL bits (Offset 0x1F, 8bits) +//---------------------------------------------------------------------------- +#define RF_EN BIT0 // Enable RF module. +#define RF_RSTB BIT1 // Reset RF module. +#define RF_SDMRSTB BIT2 // Reset RF SDM module. + +//---------------------------------------------------------------------------- +// 8192S LDOA15_CTRL bits (Offset 0x20, 8bits) +//---------------------------------------------------------------------------- +#define LDA15_EN BIT0 // Enable LDOA15 Macro Block + +//---------------------------------------------------------------------------- +// 8192S LDOV12D_CTRL bits (Offset 0x21, 8bits) +//---------------------------------------------------------------------------- +#define LDV12_EN BIT0 // Enable LDOVD12 Macro Block +#define LDV12_SDBY BIT1 // LDOVD12 standby mode + +//---------------------------------------------------------------------------- +// 8192S AFE_XTAL_CTRL bits AFE Crystal Control. (Offset 0x26,16bits) +//---------------------------------------------------------------------------- +#define XTAL_GATE_AFE BIT10 +// Gated Control. 1: AFE Clock source gated, 0: Clock enable. + +//---------------------------------------------------------------------------- +// 8192S AFE_PLL_CTRL bits System Function Enable (Offset 0x28,64bits) +//---------------------------------------------------------------------------- +#define APLL_EN BIT0 // Enable AFE PLL Macro Block. + +// Find which card bus type +#define AFR_CardBEn BIT0 +#define AFR_CLKRUN_SEL BIT1 +#define AFR_FuncRegEn BIT2 + +// +// 2. Command Control Registers (Offset: 0x0040 - 0x004F) +// +//---------------------------------------------------------------------------- +// 8192S (CMD) command register bits (Offset 0x40, 16 bits) +//---------------------------------------------------------------------------- +#define APSDOFF_STATUS BIT15 // +#define APSDOFF BIT14 // +#define BBRSTn BIT13 //Enable OFDM/CCK +#define BB_GLB_RSTn BIT12 //Enable BB +#define SCHEDULE_EN BIT10 //Enable MAC scheduler +#define MACRXEN BIT9 // +#define MACTXEN BIT8 // +#define DDMA_EN BIT7 //FW off load function enable +#define FW2HW_EN BIT6 //MAC every module reset as below +#define RXDMA_EN BIT5 // +#define TXDMA_EN BIT4 // +#define HCI_RXDMA_EN BIT3 // +#define HCI_TXDMA_EN BIT2 // + +//---------------------------------------------------------------------------- +// 8192S (TXPAUSE) transmission pause (Offset 0x42, 8 bits) +//---------------------------------------------------------------------------- +#define StopHCCA BIT6 +#define StopHigh BIT5 +#define StopMgt BIT4 +#define StopVO BIT3 +#define StopVI BIT2 +#define StopBE BIT1 +#define StopBK BIT0 + +//---------------------------------------------------------------------------- +// 8192S (LBKMD) LoopBack Mode Select (Offset 0x43, 8 bits) +//---------------------------------------------------------------------------- +// +// [3] no buffer, 1: no delay, 0: delay; [2] dmalbk, [1] no_txphy, [0] diglbk. +// 0000: Normal +// 1011: MAC loopback (involving CPU) +// 0011: MAC Delay Loopback +// 0001: PHY loopback (not yet implemented) +// 0111: DMA loopback (only uses TxPktBuffer and DMA engine) +// All other combinations are reserved. +// Default: 0000b. +// +#define LBK_NORMAL 0x00 +#define LBK_MAC_LB (BIT0|BIT1|BIT3) +#define LBK_MAC_DLB (BIT0|BIT1) +#define LBK_DMA_LB (BIT0|BIT1|BIT2) + +//---------------------------------------------------------------------------- +// 8192S (TCR) transmission Configuration Register (Offset 0x44, 32 bits) +//---------------------------------------------------------------------------- +#define TCP_OFDL_EN BIT25 //For CE packet conversion +#define HWPC_TX_EN BIT24 //"" +#define TXDMAPRE2FULL BIT23 //TXDMA enable pre2full sync +#define DISCW BIT20 //CW disable +#define TCRICV BIT19 //Append ICV or not +#define CfendForm BIT17 //AP mode +#define TCRCRC BIT16 //Append CRC32 +#define FAKE_IMEM_EN BIT15 // +#define TSFRST BIT9 // +#define TSFEN BIT8 // +// For TCR FW download ready --> write by FW Bit0-7 must all one +#define FWALLRDY (BIT0|BIT1|BIT2|BIT3|BIT4|BIT5|BIT6|BIT7) +#define FWRDY BIT7 +#define BASECHG BIT6 +#define IMEM BIT5 +#define DMEM_CODE_DONE BIT4 +#define EXT_IMEM_CHK_RPT BIT3 +#define EXT_IMEM_CODE_DONE BIT2 +#define IMEM_CHK_RPT BIT1 +#define IMEM_CODE_DONE BIT0 +// Copy fomr 92SU definition +#define IMEM_CODE_DONE BIT0 +#define IMEM_CHK_RPT BIT1 +#define EMEM_CODE_DONE BIT2 +#define EMEM_CHK_RPT BIT3 +#define DMEM_CODE_DONE BIT4 +#define IMEM_RDY BIT5 +#define BASECHG BIT6 +#define FWRDY BIT7 +#define LOAD_FW_READY (IMEM_CODE_DONE|IMEM_CHK_RPT|EMEM_CODE_DONE|\ + EMEM_CHK_RPT|DMEM_CODE_DONE|IMEM_RDY|BASECHG|\ + FWRDY) +#define TCR_TSFEN BIT8 // TSF function on or off. +#define TCR_TSFRST BIT9 // Reset TSF function to zero. +#define TCR_FAKE_IMEM_EN BIT15 +#define TCR_CRC BIT16 +#define TCR_ICV BIT19 // Integrity Check Value. +#define TCR_DISCW BIT20 // Disable Contention Windows Backoff. +#define TCR_HWPC_TX_EN BIT24 +#define TCR_TCP_OFDL_EN BIT25 +#define TXDMA_INIT_VALUE (IMEM_CHK_RPT|EXT_IMEM_CHK_RPT) +//---------------------------------------------------------------------------- +// 8192S (RCR) Receive Configuration Register (Offset 0x48, 32 bits) +//---------------------------------------------------------------------------- +#define RCR_APPFCS BIT31 //WMAC append FCS after pauload +#define RCR_DIS_ENC_2BYTE BIT30 //HW encrypt 2 or 1 byte mode +#define RCR_DIS_AES_2BYTE BIT29 // +#define RCR_HTC_LOC_CTRL BIT28 //MFC<--HTC=1 MFC-->HTC=0 +#define RCR_ENMBID BIT27 //Enable Multiple BssId. +#define RCR_RX_TCPOFDL_EN BIT26 // +#define RCR_APP_PHYST_RXFF BIT25 // +#define RCR_APP_PHYST_STAFF BIT24 // +#define RCR_CBSSID BIT23 //Accept BSSID match packet +#define RCR_APWRMGT BIT22 //Accept power management packet +#define RCR_ADD3 BIT21 //Accept address 3 match packet +#define RCR_AMF BIT20 //Accept management type frame +#define RCR_ACF BIT19 //Accept control type frame +#define RCR_ADF BIT18 //Accept data type frame +#define RCR_APP_MIC BIT17 // +#define RCR_APP_ICV BIT16 // +#define RCR_RXFTH BIT13 //Rx FIFO Threshold Bot 13 - 15 +#define RCR_AICV BIT12 //Accept ICV error packet +#define RCR_RXDESC_LK_EN BIT11 //Accept to update rx desc length +#define RCR_APP_BA_SSN BIT6 //Accept BA SSN +#define RCR_ACRC32 BIT5 //Accept CRC32 error packet +#define RCR_RXSHFT_EN BIT4 //Accept broadcast packet +#define RCR_AB BIT3 //Accept broadcast packet +#define RCR_AM BIT2 //Accept multicast packet +#define RCR_APM BIT1 //Accept physical match packet +#define RCR_AAP BIT0 //Accept all unicast packet +#define RCR_MXDMA_OFFSET 8 +#define RCR_FIFO_OFFSET 13 + +//in 92U FIXLZM +//#ifdef RTL8192U +#define RCR_ONLYERLPKT BIT31 // Early Receiving based on Packet Size. +#define RCR_ENCS2 BIT30 // Enable Carrier Sense Detection Method 2 +#define RCR_ENCS1 BIT29 // Enable Carrier Sense Detection Method 1 +#define RCR_ACKTXBW (BIT24|BIT25) // TXBW Setting of ACK frames +//#endif +//---------------------------------------------------------------------------- +// 8192S (MSR) Media Status Register (Offset 0x4C, 8 bits) +//---------------------------------------------------------------------------- +/* +Network Type +00: No link +01: Link in ad hoc network +10: Link in infrastructure network +11: AP mode +Default: 00b. +*/ +#define MSR_NOLINK 0x00 +#define MSR_ADHOC 0x01 +#define MSR_INFRA 0x02 +#define MSR_AP 0x03 + +//---------------------------------------------------------------------------- +// 8192S (SYSF_CFG) system Fucntion Config Reg (Offset 0x4D, 8 bits) +//---------------------------------------------------------------------------- +#define ENUART BIT7 +#define ENJTAG BIT3 +#define BTMODE (BIT2|BIT1) +#define ENBT BIT0 + +//---------------------------------------------------------------------------- +// 8192S (MBIDCTRL) MBSSID Control Register (Offset 0x4F, 8 bits) +//---------------------------------------------------------------------------- +#define ENMBID BIT7 +#define BCNUM (BIT6|BIT5|BIT4) + +// +// 3. MACID Setting Registers (Offset: 0x0050 - 0x007F) +// + +// +// 4. Timing Control Registers (Offset: 0x0080 - 0x009F) +// +//---------------------------------------------------------------------------- +// 8192S (USTIME) US Time Tunning Register (Offset 0x8A, 16 bits) +//---------------------------------------------------------------------------- +#define USTIME_EDCA 0xFF00 +#define USTIME_TSF 0x00FF + +//---------------------------------------------------------------------------- +// 8192S (SIFS_CCK/OFDM) US Time Tunning Register (Offset 0x8C/8E,16 bits) +//---------------------------------------------------------------------------- +#define SIFS_TRX 0xFF00 +#define SIFS_CTX 0x00FF + +//---------------------------------------------------------------------------- +// 8192S (DRVERLYINT) Driver Early Interrupt Reg (Offset 0x98, 16bit) +//---------------------------------------------------------------------------- +#define ENSWBCN BIT15 +#define DRVERLY_TU 0x0FF0 +#define DRVERLY_US 0x000F +#define BCN_TCFG_CW_SHIFT 8 +#define BCN_TCFG_IFS 0 + +// +// 5. FIFO Control Registers (Offset: 0x00A0 - 0x015F) +// + +// +// 6. Adaptive Control Registers (Offset: 0x0160 - 0x01CF) +// +//---------------------------------------------------------------------------- +// 8192S Response Rate Set Register (offset 0x181, 24bits) +//---------------------------------------------------------------------------- +#define RRSR_RSC_OFFSET 21 +#define RRSR_SHORT_OFFSET 23 +#define RRSR_RSC_BW_40M 0x600000 +#define RRSR_RSC_UPSUBCHNL 0x400000 +#define RRSR_RSC_LOWSUBCHNL 0x200000 +#define RRSR_SHORT 0x800000 +#define RRSR_1M BIT0 +#define RRSR_2M BIT1 +#define RRSR_5_5M BIT2 +#define RRSR_11M BIT3 +#define RRSR_6M BIT4 +#define RRSR_9M BIT5 +#define RRSR_12M BIT6 +#define RRSR_18M BIT7 +#define RRSR_24M BIT8 +#define RRSR_36M BIT9 +#define RRSR_48M BIT10 +#define RRSR_54M BIT11 +#define RRSR_MCS0 BIT12 +#define RRSR_MCS1 BIT13 +#define RRSR_MCS2 BIT14 +#define RRSR_MCS3 BIT15 +#define RRSR_MCS4 BIT16 +#define RRSR_MCS5 BIT17 +#define RRSR_MCS6 BIT18 +#define RRSR_MCS7 BIT19 +#define BRSR_AckShortPmb BIT23 + +#define RRSR_RSC_UPSUBCHANL 0x200000 +// CCK ACK: use Short Preamble or not + +//---------------------------------------------------------------------------- +// 8192S Rate Definition +//---------------------------------------------------------------------------- +//CCK +#define RATR_1M 0x00000001 +#define RATR_2M 0x00000002 +#define RATR_55M 0x00000004 +#define RATR_11M 0x00000008 +//OFDM +#define RATR_6M 0x00000010 +#define RATR_9M 0x00000020 +#define RATR_12M 0x00000040 +#define RATR_18M 0x00000080 +#define RATR_24M 0x00000100 +#define RATR_36M 0x00000200 +#define RATR_48M 0x00000400 +#define RATR_54M 0x00000800 +//MCS 1 Spatial Stream +#define RATR_MCS0 0x00001000 +#define RATR_MCS1 0x00002000 +#define RATR_MCS2 0x00004000 +#define RATR_MCS3 0x00008000 +#define RATR_MCS4 0x00010000 +#define RATR_MCS5 0x00020000 +#define RATR_MCS6 0x00040000 +#define RATR_MCS7 0x00080000 +//MCS 2 Spatial Stream +#define RATR_MCS8 0x00100000 +#define RATR_MCS9 0x00200000 +#define RATR_MCS10 0x00400000 +#define RATR_MCS11 0x00800000 +#define RATR_MCS12 0x01000000 +#define RATR_MCS13 0x02000000 +#define RATR_MCS14 0x04000000 +#define RATR_MCS15 0x08000000 +// ALL CCK Rate +#define RATE_ALL_CCK RATR_1M|RATR_2M|RATR_55M|RATR_11M +#define RATE_ALL_OFDM_AG RATR_6M|RATR_9M|RATR_12M|RATR_18M|RATR_24M|\ + RATR_36M|RATR_48M|RATR_54M +#define RATE_ALL_OFDM_1SS RATR_MCS0|RATR_MCS1|RATR_MCS2|RATR_MCS3 |\ + RATR_MCS4|RATR_MCS5|RATR_MCS6 |RATR_MCS7 +#define RATE_ALL_OFDM_2SS RATR_MCS8|RATR_MCS9 |RATR_MCS10|RATR_MCS11|\ + RATR_MCS12|RATR_MCS13|RATR_MCS14|RATR_MCS15 + +// +// 7. EDCA Setting Registers (Offset: 0x01D0 - 0x01FF) +// +//---------------------------------------------------------------------------- +// 8192S EDCA Setting (offset 0x1D0-1DF, 4DW VO/VI/BE/BK) +//---------------------------------------------------------------------------- +#define AC_PARAM_TXOP_LIMIT_OFFSET 16 +#define AC_PARAM_ECW_MAX_OFFSET 12 +#define AC_PARAM_ECW_MIN_OFFSET 8 +#define AC_PARAM_AIFS_OFFSET 0 + +//---------------------------------------------------------------------------- +// 8192S AcmHwCtrl bits (offset 0x1E7, 1 byte) +//---------------------------------------------------------------------------- +#define AcmHw_HwEn BIT0 +#define AcmHw_BeqEn BIT1 +#define AcmHw_ViqEn BIT2 +#define AcmHw_VoqEn BIT3 +#define AcmHw_BeqStatus BIT4 +#define AcmHw_ViqStatus BIT5 +#define AcmHw_VoqStatus BIT6 + +//---------------------------------------------------------------------------- +// 8192S Retry Limit (Offset 0x1F4, 16bit) +//---------------------------------------------------------------------------- +#define RETRY_LIMIT_SHORT_SHIFT 8 +#define RETRY_LIMIT_LONG_SHIFT 0 + +// +// 8. WMAC, BA and CCX related Register. (Offset: 0x0200 - 0x023F) +// +//---------------------------------------------------------------------------- +// 8192S NAV_CTRL bits (Offset 0x200, 24bit) +//---------------------------------------------------------------------------- +#define NAV_UPPER_EN BIT16 +#define NAV_UPPER 0xFF00 +#define NAV_RTSRST 0xFF +//---------------------------------------------------------------------------- +// 8192S BW_OPMODE bits (Offset 0x203, 8bit) +//---------------------------------------------------------------------------- +#define BW_OPMODE_20MHZ BIT2 +#define BW_OPMODE_5G BIT1 +#define BW_OPMODE_11J BIT0 +//---------------------------------------------------------------------------- +// 8192S BW_OPMODE bits (Offset 0x230, 4 Byte) +//---------------------------------------------------------------------------- +#define RXERR_RPT_RST BIT27 // Write "one" to set the counter to zero. +// RXERR_RPT_SEL +#define RXERR_OFDM_PPDU 0 +#define RXERR_OFDM_FALSE_ALARM 1 +#define RXERR_OFDM_MPDU_OK 2 +#define RXERR_OFDM_MPDU_FAIL 3 +#define RXERR_CCK_PPDU 4 +#define RXERR_CCK_FALSE_ALARM 5 +#define RXERR_CCK_MPDU_OK 6 +#define RXERR_CCK_MPDU_FAIL 7 +#define RXERR_HT_PPDU 8 +#define RXERR_HT_FALSE_ALARM 9 +#define RXERR_HT_MPDU_TOTAL 10 +#define RXERR_HT_MPDU_OK 11 +#define RXERR_HT_MPDU_FAIL 12 +#define RXERR_RX_FULL_DROP 15 + +// +// 9. Security Control Registers (Offset: 0x0240 - 0x025F) +// +//---------------------------------------------------------------------------- +// 8192S RWCAM CAM Command Register (offset 0x240, 4 byte) +//---------------------------------------------------------------------------- +#define CAM_CM_SecCAMPolling BIT31 //Security CAM Polling +#define CAM_CM_SecCAMClr BIT30 //Clear all bits in CAM +#define CAM_CM_SecCAMWE BIT16 //Security CAM enable +#define CAM_ADDR 0xFF //CAM Address Offset + +//---------------------------------------------------------------------------- +// 8192S CAMDBG Debug CAM Register (offset 0x24C, 4 byte) +//---------------------------------------------------------------------------- +#define Dbg_CAM_TXSecCAMInfo BIT31 //Retrieve lastest Tx Info +#define Dbg_CAM_SecKeyFound BIT30 //Security KEY Found + + +//---------------------------------------------------------------------------- +// 8192S SECR Security Configuration Register (offset 0x250, 1 byte) +//---------------------------------------------------------------------------- +#define SCR_TxUseDK BIT0 //Force Tx Use Default Key +#define SCR_RxUseDK BIT1 //Force Rx Use Default Key +#define SCR_TxEncEnable BIT2 //Enable Tx Encryption +#define SCR_RxDecEnable BIT3 //Enable Rx Decryption +#define SCR_SKByA2 BIT4 //Search kEY BY A2 +#define SCR_NoSKMC BIT5 //No Key Search Multicast +//---------------------------------------------------------------------------- +// 8192S CAM Config Setting (offset 0x250, 1 byte) +//---------------------------------------------------------------------------- +#define CAM_VALID BIT15 +#define CAM_NOTVALID 0x0000 +#define CAM_USEDK BIT5 + +#define CAM_NONE 0x0 +#define CAM_WEP40 0x01 +#define CAM_TKIP 0x02 +#define CAM_AES 0x04 +#define CAM_WEP104 0x05 + +#define TOTAL_CAM_ENTRY 32 + +#define CAM_CONFIG_USEDK TRUE +#define CAM_CONFIG_NO_USEDK FALSE + +#define CAM_WRITE BIT16 +#define CAM_READ 0x00000000 +#define CAM_POLLINIG BIT31 + +#define SCR_UseDK 0x01 +#define SCR_TxSecEnable 0x02 +#define SCR_RxSecEnable 0x04 + +// +// 10. Power Save Control Registers (Offset: 0x0260 - 0x02DF) +// +#define WOW_PMEN BIT0 // Power management Enable. +#define WOW_WOMEN BIT1 // WoW function on or off. +#define WOW_MAGIC BIT2 // Magic packet +#define WOW_UWF BIT3 // Unicast Wakeup frame. + +// +// 11. General Purpose Registers (Offset: 0x02E0 - 0x02FF) +// 8192S GPIO Config Setting (offset 0x2F1, 1 byte) +//---------------------------------------------------------------------------- +#define GPIOMUX_EN BIT3 // When this bit is set to "1", GPIO PINs will switch to MAC GPIO Function +#define GPIOSEL_GPIO 0 // UART or JTAG or pure GPIO +#define GPIOSEL_PHYDBG 1 // PHYDBG +#define GPIOSEL_BT 2 // BT_coex +#define GPIOSEL_WLANDBG 3 // WLANDBG +#define GPIOSEL_GPIO_MASK ~(BIT0|BIT1) + +//---------------------------------------------------------------------------- + +//---------------------------------------------------------------------------- +// PHY REG Access Report Register definition +//---------------------------------------------------------------------------- +#define HST_RDBUSY BIT0 +#define CPU_WTBUSY BIT1 + +// +// 12. Host Interrupt Status Registers (Offset: 0x0300 - 0x030F) +// +//---------------------------------------------------------------------------- +// 8190 IMR/ISR bits (offset 0xfd, 8bits) +//---------------------------------------------------------------------------- +#define IMR8190_DISABLED 0x0 + +// IMR DW1 Bit 0-31 +#define IMR_CPUERR BIT5 // CPU error interrupt +#define IMR_ATIMEND BIT4 // ATIM Window End Interrupt +#define IMR_TBDOK BIT3 // Transmit Beacon OK Interrupt +#define IMR_TBDER BIT2 // Transmit Beacon Error Interrupt +#define IMR_BCNDMAINT8 BIT1 // Beacon DMA Interrupt 8 +#define IMR_BCNDMAINT7 BIT0 // Beacon DMA Interrupt 7 +// IMR DW0 Bit 0-31 + +#define IMR_BCNDMAINT6 BIT31 // Beacon DMA Interrupt 6 +#define IMR_BCNDMAINT5 BIT30 // Beacon DMA Interrupt 5 +#define IMR_BCNDMAINT4 BIT29 // Beacon DMA Interrupt 4 +#define IMR_BCNDMAINT3 BIT28 // Beacon DMA Interrupt 3 +#define IMR_BCNDMAINT2 BIT27 // Beacon DMA Interrupt 2 +#define IMR_BCNDMAINT1 BIT26 // Beacon DMA Interrupt 1 +#define IMR_BCNDOK8 BIT25 // Beacon Queue DMA OK Interrup 8 +#define IMR_BCNDOK7 BIT24 // Beacon Queue DMA OK Interrup 7 +#define IMR_BCNDOK6 BIT23 // Beacon Queue DMA OK Interrup 6 +#define IMR_BCNDOK5 BIT22 // Beacon Queue DMA OK Interrup 5 +#define IMR_BCNDOK4 BIT21 // Beacon Queue DMA OK Interrup 4 +#define IMR_BCNDOK3 BIT20 // Beacon Queue DMA OK Interrup 3 +#define IMR_BCNDOK2 BIT19 // Beacon Queue DMA OK Interrup 2 +#define IMR_BCNDOK1 BIT18 // Beacon Queue DMA OK Interrup 1 +#define IMR_TIMEOUT2 BIT17 // Timeout interrupt 2 +#define IMR_TIMEOUT1 BIT16 // Timeout interrupt 1 +#define IMR_TXFOVW BIT15 // Transmit FIFO Overflow +#define IMR_PSTIMEOUT BIT14 // Power save time out interrupt +#define IMR_BcnInt BIT13 // Beacon DMA Interrupt 0 +#define IMR_RXFOVW BIT12 // Receive FIFO Overflow +#define IMR_RDU BIT11 // Receive Descriptor Unavailable +#define IMR_RXCMDOK BIT10 // Receive Command Packet OK +#define IMR_BDOK BIT9 // Beacon Queue DMA OK Interrup +#define IMR_HIGHDOK BIT8 // High Queue DMA OK Interrupt +#define IMR_COMDOK BIT7 // Command Queue DMA OK Interrupt +#define IMR_MGNTDOK BIT6 // Management Queue DMA OK Interrupt +#define IMR_HCCADOK BIT5 // HCCA Queue DMA OK Interrupt +#define IMR_BKDOK BIT4 // AC_BK DMA OK Interrupt +#define IMR_BEDOK BIT3 // AC_BE DMA OK Interrupt +#define IMR_VIDOK BIT2 // AC_VI DMA OK Interrupt +#define IMR_VODOK BIT1 // AC_VO DMA Interrupt +#define IMR_ROK BIT0 // Receive DMA OK Interrupt + +// +// 13. Test Mode and Debug Control Registers (Offset: 0x0310 - 0x034F) +// + +// +// 14. PCIE config register (Offset 0x500-) +// +//---------------------------------------------------------------------------- +// 8190 TPPool bits (offset 0xd9, 2 byte) +//---------------------------------------------------------------------------- +#define TPPoll_BKQ BIT0 // BK queue polling +#define TPPoll_BEQ BIT1 // BE queue polling +#define TPPoll_VIQ BIT2 // VI queue polling +#define TPPoll_VOQ BIT3 // VO queue polling +#define TPPoll_BQ BIT4 // Beacon queue polling +#define TPPoll_CQ BIT5 // Command queue polling +#define TPPoll_MQ BIT6 // Management queue polling +#define TPPoll_HQ BIT7 // High queue polling +#define TPPoll_HCCAQ BIT8 // HCCA queue polling +#define TPPoll_StopBK BIT9 // Stop BK queue +#define TPPoll_StopBE BIT10 // Stop BE queue +#define TPPoll_StopVI BIT11 // Stop VI queue +#define TPPoll_StopVO BIT12 // Stop VO queue +#define TPPoll_StopMgt BIT13 // Stop Mgnt queue +#define TPPoll_StopHigh BIT14 // Stop High queue +#define TPPoll_StopHCCA BIT15 // Stop HCCA queue +#define TPPoll_SHIFT 8 // Queue ID mapping + +//---------------------------------------------------------------------------- +// 8192S PCIF (Offset 0x500, 32bit) +//---------------------------------------------------------------------------- +#define MXDMA2_16bytes 0x000 +#define MXDMA2_32bytes 0x001 +#define MXDMA2_64bytes 0x010 +#define MXDMA2_128bytes 0x011 +#define MXDMA2_256bytes 0x100 +#define MXDMA2_512bytes 0x101 +#define MXDMA2_1024bytes 0x110 +#define MXDMA2_NoLimit 0x7 + +#define MULRW_SHIFT 3 +#define MXDMA2_RX_SHIFT 4 +#define MXDMA2_TX_SHIFT 0 + +//---------------------------------------------------------------------------- +// 8190 CCX_COMMAND_REG Setting (offset 0x25A, 1 byte) +//---------------------------------------------------------------------------- +#define CCX_CMD_CLM_ENABLE BIT0 // Enable Channel Load +#define CCX_CMD_NHM_ENABLE BIT1 // Enable Noise Histogram +#define CCX_CMD_FUNCTION_ENABLE BIT8 +// CCX function (Channel Load/RPI/Noise Histogram). +#define CCX_CMD_IGNORE_CCA BIT9 +// Treat CCA period as IDLE time for NHM. +#define CCX_CMD_IGNORE_TXON BIT10 +// Treat TXON period as IDLE time for NHM. +#define CCX_CLM_RESULT_READY BIT16 +// 1: Indicate the result of Channel Load is ready. +#define CCX_NHM_RESULT_READY BIT16 +// 1: Indicate the result of Noise histogram is ready. +#define CCX_CMD_RESET 0x0 +// Clear all the result of CCX measurement and disable the CCX function. + + +//---------------------------------------------------------------------------- +// 8192S EFUSE +//---------------------------------------------------------------------------- +//#define HWSET_MAX_SIZE_92S 128 + + +//---------------------------------------------------------------------------- +// 8192S EEPROM/EFUSE share register definition. +//---------------------------------------------------------------------------- + +#ifdef RTL8192SE +// +// 2008/11/05 MH Redefine EEPROM address for 8192SE +// 92SE/SU EEPROM definition seems not the same!!!!!! +// EEPROM MAP REgister Definition!!!! Please refer to 8192SE EEPROM V0.5 2008/10/21 +// Update to 8192SE EEPROM V0.6 2008/11/11 +// +#define RTL8190_EEPROM_ID 0x8129 // 0-1 +#define EEPROM_HPON 0x02 // LDO settings.2-5 +#define EEPROM_CLK 0x06 // Clock settings.6-7 +#define EEPROM_TESTR 0x08 // SE Test mode.8 + +#define EEPROM_VID 0x0A // SE Vendor ID.A-B +#define EEPROM_DID 0x0C // SE Device ID. C-D +#define EEPROM_SVID 0x0E // SE Vendor ID.E-F +#define EEPROM_SMID 0x10 // SE PCI Subsystem ID. 10-11 + +#define EEPROM_MAC_ADDR 0x12 // SEMAC Address. 12-17 +#define EEPROM_NODE_ADDRESS_BYTE_0 0x12 // MAC address. + +#define EEPROM_PwDiff 0x54 // Difference of gain index between legacy and high throughput OFDM. + +// +// 0x20 - 4B EPHY parameter!!! +// +// +#define EEPROM_TxPowerBase 0x50 // Tx Power of serving station. +#define EEPROM_TxPwIndex_CCK_24G 0x5D // 0x50~0x5D Range = 0~0x24//FIXLZM +#define EEPROM_TxPwIndex_OFDM_24G 0x6B // 0x5E~0x6B Range = 0~0x24//FIXLZM +#define EEPROM_TX_PWR_INDEX_RANGE 28 // CCK and OFDM 14 channel + + +// 2009/01/21 MH Add for SD3 requirement +#define EEPROM_TX_PWR_HT20_DIFF 0x62// HT20 Tx Power Index Difference +#define DEFAULT_HT20_TXPWR_DIFF 2 // HT20<->40 default Tx Power Index Difference +#define EEPROM_TX_PWR_OFDM_DIFF 0x65// OFDM Tx Power Index Difference +#define EEPROM_TX_PWR_BAND_EDGE 0x67// TX Power offset at band-edge channel +#define TX_PWR_BAND_EDGE_CHK 0x6D// Check if band-edge scheme is enabled + +// Oly old EEPROM format support the definition============================= +// +#define EEPROM_TxPwIndex_CCK_24G 0x5D // 0x50~0x5D Range = 0~0x24 +#define EEPROM_TxPwIndex_OFDM_24G 0x6B // 0x5E~0x6B Range = 0~0x24 +#define EEPROM_HT2T_CH1_A 0x6c //HT 2T path A channel 1 Power Index. +#define EEPROM_HT2T_CH7_A 0x6d //HT 2T path A channel 7 Power Index. +#define EEPROM_HT2T_CH13_A 0x6e //HT 2T path A channel 13 Power Index. +#define EEPROM_HT2T_CH1_B 0x6f //HT 2T path B channel 1 Power Index. +#define EEPROM_HT2T_CH7_B 0x70 //HT 2T path B channel 7 Power Index. +#define EEPROM_HT2T_CH13_B 0x71 //HT 2T path B channel 13 Power Index. +// +#define EEPROM_TSSI_A 0x74 //TSSI value of path A. +#define EEPROM_TSSI_B 0x75 //TSSI value of path B. +// +#define EEPROM_RFInd_PowerDiff 0x76 +#define EEPROM_Default_LegacyHTTxPowerDiff 0x3 +// +#define EEPROM_ThermalMeter 0x77 // Thermal meter default value. +#define EEPROM_CrystalCap 0x79 // Crystal Cap. +#define EEPROM_ChannelPlan 0x7B // Map of supported channels. +#define EEPROM_Version 0x7C // The EEPROM content version +#define EEPROM_CustomID 0x7A +#define EEPROM_BoardType 0x7E +// 0: 2x2 Green RTL8192GE miniCard (QFN68) +// 1: 1x2 RTL8191SE miniCard (QFN64) +// 2: 2x2 RTL8192SE miniCard (QFN68) +// 3: 1x2 RTL8191SR minicCard(QFN64) + +// +// Default Value for EEPROM or EFUSE!!! +// +#define EEPROM_Default_TSSI 0x0 +#define EEPROM_Default_TxPowerDiff 0x0 +#define EEPROM_Default_CrystalCap 0x5 +#define EEPROM_Default_BoardType 0x02 // Default: 2X2, RTL8192SE(QFPN68) +#define EEPROM_Default_TxPower 0x1010 +#define EEPROM_Default_HT2T_TxPwr 0x10 + +#ifdef EEPROM_OLD_FORMAT_SUPPORT +#define EEPROM_Default_TxPowerBase 0x0 +#define EEPROM_Default_ThermalMeter 0x12 +#define EEPROM_Default_PwDiff 0x4 +#else +#define EEPROM_Default_LegacyHTTxPowerDiff 0x3 +#define EEPROM_Default_ThermalMeter 0x12 +#define EEPROM_Default_AntTxPowerDiff 0x0 +#define EEPROM_Default_TxPwDiff_CrystalCap 0x5 +#define EEPROM_Default_TxPowerLevel 0x22 +#endif + +#define EEPROM_CHANNEL_PLAN_FCC 0x0 +#define EEPROM_CHANNEL_PLAN_IC 0x1 +#define EEPROM_CHANNEL_PLAN_ETSI 0x2 +#define EEPROM_CHANNEL_PLAN_SPAIN 0x3 +#define EEPROM_CHANNEL_PLAN_FRANCE 0x4 +#define EEPROM_CHANNEL_PLAN_MKK 0x5 +#define EEPROM_CHANNEL_PLAN_MKK1 0x6 +#define EEPROM_CHANNEL_PLAN_ISRAEL 0x7 +#define EEPROM_CHANNEL_PLAN_TELEC 0x8 +#define EEPROM_CHANNEL_PLAN_GLOBAL_DOMAIN 0x9 +#define EEPROM_CHANNEL_PLAN_WORLD_WIDE_13 0xA +#define EEPROM_CHANNEL_PLAN_BY_HW_MASK 0x80 + + +#define EEPROM_CID_DEFAULT 0x0 +#define EEPROM_CID_TOSHIBA 0x4 +#else +//---------------------------------------------------------------------------- +// 8192S EEROM and Compatible E-Fuse definition. Added by Roger, 2008.10.21. +//---------------------------------------------------------------------------- +#define RTL8190_EEPROM_ID 0x8129 +#define EEPROM_HPON 0x02 // LDO settings. +#define EEPROM_VID 0x08 // USB Vendor ID. +#define EEPROM_PID 0x0A // USB Product ID. +#define EEPROM_USB_OPTIONAL 0x0C // For optional function. +#define EEPROM_USB_PHY_PARA1 0x0D // For fine tune USB PHY. +#define EEPROM_NODE_ADDRESS_BYTE_0 0x12 // MAC address. +#define EEPROM_TxPowerDiff 0x1F + +#define EEPROM_Version 0x50 +#define EEPROM_ChannelPlan 0x51 // Map of supported channels. +#define EEPROM_CustomID 0x52 +#define EEPROM_SubCustomID 0x53 // Reserved for customer use. + + + // The followin are for different version of EEPROM contents purpose. 2008.11.22. +#ifdef EEPROM_OLD_FORMAT_SUPPORT +#define EEPROM_PwDiff 0x54 // Difference of gain index between legacy and high throughput OFDM. +#define EEPROM_ThermalMeter 0x55 // Thermal meter default value. +#define EEPROM_Reserved 0x56 // Reserved. +#define EEPROM_CrystalCap 0x57 // Crystal Cap. +#define EEPROM_TxPowerBase 0x58 // Tx Power of serving station. +#define EEPROM_TxPwIndex_CCK_24G 0x59 // 0x59~0x66 +#define EEPROM_TxPwIndex_OFDM_24G 0x67 // 0x67~0x74 +#define EEPROM_TSSI_A 0x75 //TSSI value of path A. +#define EEPROM_TSSI_B 0x76 //TSSI value of path B. +#define EEPROM_TxPwTkMode 0x77 //Tx Power tracking mode. +#define EEPROM_HT2T_CH1_A 0x78 //HT 2T path A channel 1 Power Index. +#define EEPROM_HT2T_CH7_A 0x79 //HT 2T path A channel 7 Power Index. +#define EEPROM_HT2T_CH13_A 0x7a //HT 2T path A channel 13 Power Index. +#define EEPROM_HT2T_CH1_B 0x7b //HT 2T path B channel 1 Power Index. +#define EEPROM_HT2T_CH7_B 0x7c //HT 2T path B channel 7 Power Index. +#define EEPROM_HT2T_CH13_B 0x7d //HT 2T path B channel 13 Power Index. +#define EEPROM_BoardType 0x7e //0x0: RTL8188SU, 0x1: RTL8191SU, 0x2: RTL8192SU, 0x3: RTL8191GU +#else +#define EEPROM_BoardType 0x54 //0x0: RTL8188SU, 0x1: RTL8191SU, 0x2: RTL8192SU, 0x3: RTL8191GU +#define EEPROM_TxPwIndex 0x55 //0x55-0x66, Tx Power index. +#define EEPROM_PwDiff 0x67 // Difference of gain index between legacy and high throughput OFDM. +#define EEPROM_ThermalMeter 0x68 // Thermal meter default value. +#define EEPROM_CrystalCap 0x69 // Crystal Cap. +#define EEPROM_TxPowerBase 0x6a // Tx Power of serving station. +#define EEPROM_TSSI_A 0x6b //TSSI value of path A. +#define EEPROM_TSSI_B 0x6c //TSSI value of path B. +#define EEPROM_TxPwTkMode 0x6d //Tx Power tracking mode. +//#define EEPROM_Reserved 0x6e //0x6e-0x7f, reserved. + +// 2009/02/09 Cosa Add for SD3 requirement +#define EEPROM_TX_PWR_HT20_DIFF 0x6e// HT20 Tx Power Index Difference +#define DEFAULT_HT20_TXPWR_DIFF 2 // HT20<->40 default Tx Power Index Difference +#define EEPROM_TX_PWR_OFDM_DIFF 0x71// OFDM Tx Power Index Difference +#define EEPROM_TX_PWR_BAND_EDGE 0x73// TX Power offset at band-edge channel +#define TX_PWR_BAND_EDGE_CHK 0x79// Check if band-edge scheme is enabled +#endif +#define EEPROM_Default_LegacyHTTxPowerDiff 0x3 +#define EEPROM_USB_Default_OPTIONAL_FUNC 0x8 +#define EEPROM_USB_Default_PHY_PARAM 0x0 +#define EEPROM_Default_TSSI 0x0 +#define EEPROM_Default_TxPwrTkMode 0x0 +#define EEPROM_Default_TxPowerDiff 0x0 +#define EEPROM_Default_TxPowerBase 0x0 +#define EEPROM_Default_ThermalMeter 0x7 +#define EEPROM_Default_PwDiff 0x4 +#define EEPROM_Default_CrystalCap 0x5 +#define EEPROM_Default_TxPower 0x1010 +#define EEPROM_Default_BoardType 0x02 // Default: 2X2, RTL8192SU(QFPN68) +#define EEPROM_Default_HT2T_TxPwr 0x10 +#define EEPROM_USB_SN BIT0 +#define EEPROM_USB_REMOTE_WAKEUP BIT1 +#define EEPROM_USB_DEVICE_PWR BIT2 +#define EEPROM_EP_NUMBER (BIT3|BIT4) + +#define EEPROM_CHANNEL_PLAN_FCC 0x0 +#define EEPROM_CHANNEL_PLAN_IC 0x1 +#define EEPROM_CHANNEL_PLAN_ETSI 0x2 +#define EEPROM_CHANNEL_PLAN_SPAIN 0x3 +#define EEPROM_CHANNEL_PLAN_FRANCE 0x4 +#define EEPROM_CHANNEL_PLAN_MKK 0x5 +#define EEPROM_CHANNEL_PLAN_MKK1 0x6 +#define EEPROM_CHANNEL_PLAN_ISRAEL 0x7 +#define EEPROM_CHANNEL_PLAN_TELEC 0x8 +#define EEPROM_CHANNEL_PLAN_GLOBAL_DOMAIN 0x9 +#define EEPROM_CHANNEL_PLAN_WORLD_WIDE_13 0xA +#define EEPROM_CHANNEL_PLAN_BY_HW_MASK 0x80 + +#define EEPROM_CID_DEFAULT 0x0 +#define EEPROM_CID_ALPHA 0x1 +#define EEPROM_CID_CAMEO 0X8 +#define EEPROM_CID_SITECOM 0x9 + +//#define EEPROM_CID_RUNTOP 0x2 +//#define EEPROM_CID_Senao 0x3 +//#define EEPROM_CID_TOSHIBA 0x4 +//#define EEPROM_CID_NetCore 0x5 +#define EEPROM_CID_WHQL 0xFE // added by chiyoko for dtm, 20090108 +#endif + +//----------------------------------------------------------------- +// 0x2c0 FW Command Control register definition, added by Roger, 2008.11.27. +//----------------------------------------------------------------- +#define FW_DIG_DISABLE 0xfd00cc00 +#define FW_DIG_ENABLE 0xfd000000 +#define FW_DIG_HALT 0xfd000001 +#define FW_DIG_RESUME 0xfd000002 +#define FW_HIGH_PWR_DISABLE 0xfd000008 +#define FW_HIGH_PWR_ENABLE 0xfd000009 +#define FW_TXPWR_TRACK_ENABLE 0xfd000017 +#define FW_TXPWR_TRACK_DISABLE 0xfd000018 +#define FW_RA_RESET 0xfd0000af +#define FW_RA_ACTIVE 0xfd0000a6 +#define FW_RA_REFRESH 0xfd0000a0 +#define FW_RA_ENABLE_BG 0xfd0000ac +#define FW_IQK_ENABLE 0xf0000020 +#define FW_IQK_SUCCESS 0x0000dddd +#define FW_IQK_FAIL 0x0000ffff +#define FW_OP_FAILURE 0xffffffff +#define FW_DM_DISABLE 0xfd00aa00 +#define FW_BB_RESET_ENABLE 0xff00000d +#define FW_BB_RESET_DISABLE 0xff00000e +#if 0 +//---------------------------------------------------------------------------- +// 8190 EEROM +//---------------------------------------------------------------------------- +#define RTL8190_EEPROM_ID 0x8129 +//#define EEPROM_NODE_ADDRESS_BYTE_0 0x0C + +#define EEPROM_RFInd_PowerDiff 0x28 +#define EEPROM_ThermalMeter 0x29 +#define EEPROM_TxPwDiff_CrystalCap 0x2A //0x2A~0x2B +#define EEPROM_TxPwIndex_CCK 0x2C //0x2C~0x39 +#define EEPROM_TxPwIndex_OFDM_24G 0x3A //0x3A~0x47 +#define EEPROM_TxPwIndex_OFDM_5G 0x34 //0x34~0x7B + +//The following definition is for eeprom 93c56......modified 20080220 +#define EEPROM_C56_CrystalCap 0x17 //0x17 +#define EEPROM_C56_RfA_CCK_Chnl1_TxPwIndex 0x80 //0x80 +#define EEPROM_C56_RfA_HT_OFDM_TxPwIndex 0x81 //0x81~0x83 +#define EEPROM_C56_RfC_CCK_Chnl1_TxPwIndex 0xbc //0xb8 +#define EEPROM_C56_RfC_HT_OFDM_TxPwIndex 0xb9 //0xb9~0xbb +#define EEPROM_Customer_ID 0x7B //0x7B:CustomerID +#define EEPROM_ICVersion_ChannelPlan 0x7C //0x7C:ChnlPlan, + //0x7D:IC_Ver +#define EEPROM_CRC 0x7E //0x7E~0x7F + +#define EEPROM_Default_LegacyHTTxPowerDiff 0x4 +#define EEPROM_Default_ThermalMeter 0x77 +#define EEPROM_Default_AntTxPowerDiff 0x0 +#define EEPROM_Default_TxPwDiff_CrystalCap 0x5 +#define EEPROM_Default_TxPower 0x1010 +#define EEPROM_Default_TxPowerLevel 0x10 + +// +// Define Different EEPROM type for customer +// +#define EEPROM_CID_DEFAULT 0x0 +#define EEPROM_CID_CAMEO 0x1 +#define EEPROM_CID_RUNTOP 0x2 +#define EEPROM_CID_Senao 0x3 +#define EEPROM_CID_TOSHIBA 0x4 +#define EEPROM_CID_NetCore 0x5 +#define EEPROM_CID_Nettronix 0x6 +#define EEPROM_CID_Pronet 0x7 + +#endif + +// +//--------------92SU require delete or move to other place later +// + + + +// +// +// 2008/08/06 MH For share the same 92S source/header files, we copy some +// definition to pass 92SU compiler. But we must delete thm later. +// +// + +//============================================================================ +// 819xUsb Regsiter offset definition +//============================================================================ + +//2 define it temp!!! +#define RFPC 0x5F // Rx FIFO Packet Count +#define RCR_9356SEL BIT6 +#define TCR_LRL_OFFSET 0 +#define TCR_SRL_OFFSET 8 +#define TCR_MXDMA_OFFSET 21 +#define TCR_MXDMA_2048 7 +#define TCR_SAT BIT24 // Enable Rate depedent ack timeout timer +#define RCR_MXDMA_OFFSET 8 +#define RCR_FIFO_OFFSET 13 +#define RCR_OnlyErlPkt BIT31 // Rx Early mode is performed for packet size greater than 1536 +#define CWR 0xDC // Contention window register +#define RetryCTR 0xDE // Retry Count register + + +// For backward compatible for 9xUSB +#define LED1Cfg UnusedRegister // LED1 Configuration Register +#define LED0Cfg UnusedRegister // LED0 Configuration Register +#define GPI UnusedRegister // LED0 Configuration Register +#define BRSR UnusedRegister // LED0 Configuration Register +#define CPU_GEN UnusedRegister // LED0 Configuration Register +#define SIFS UnusedRegister // LED0 Configuration Register + +//---------------------------------------------------------------------------- +// 8190 CPU General Register (offset 0x100, 4 byte) +//---------------------------------------------------------------------------- +//#define CPU_CCK_LOOPBACK 0x00030000 +#define CPU_GEN_SYSTEM_RESET 0x00000001 +//#define CPU_GEN_FIRMWARE_RESET 0x00000008 +//#define CPU_GEN_BOOT_RDY 0x00000010 +//#define CPU_GEN_FIRM_RDY 0x00000020 +//#define CPU_GEN_PUT_CODE_OK 0x00000080 +//#define CPU_GEN_BB_RST 0x00000100 +//#define CPU_GEN_PWR_STB_CPU 0x00000004 +//#define CPU_GEN_NO_LOOPBACK_MSK 0xFFF8FFFF // Set bit18,17,16 to 0. Set bit19 +//#define CPU_GEN_NO_LOOPBACK_SET 0x00080000 // Set BIT19 to 1 + +//---------------------------------------------------------------------------- +// 8192S EEROM +//---------------------------------------------------------------------------- + +//#define RTL8190_EEPROM_ID 0x8129 +//#define EEPROM_VID 0x08 +//#define EEPROM_PID 0x0A +//#define EEPROM_USB_OPTIONAL 0x0C +//#define EEPROM_NODE_ADDRESS_BYTE_0 0x12 +// +//#define EEPROM_TxPowerDiff 0x1F +//#define EEPROM_ThermalMeter 0x20 +//#define EEPROM_PwDiff 0x21 //0x21 +//#define EEPROM_CrystalCap 0x22 //0x22 +// +//#define EEPROM_TxPwIndex_CCK 0x23 //0x23 +//#define EEPROM_TxPwIndex_OFDM_24G 0x24 //0x24~0x26 +#define EEPROM_TxPwIndex_CCK_V1 0x29 //0x29~0x2B +#define EEPROM_TxPwIndex_OFDM_24G_V1 0x2C //0x2C~0x2E +#define EEPROM_TxPwIndex_Ver 0x27 //0x27 +// +//#define EEPROM_Default_TxPowerDiff 0x0 +//#define EEPROM_Default_ThermalMeter 0x7 +//#define EEPROM_Default_PwDiff 0x4 +//#define EEPROM_Default_CrystalCap 0x5 +//#define EEPROM_Default_TxPower 0x1010 +//#define EEPROM_Customer_ID 0x7B //0x7B:CustomerID +//#define EEPROM_Version 0x50 // 0x50 +//#define EEPROM_CustomID 0x52 +//#define EEPROM_ChannelPlan 0x7c //0x7C +//#define EEPROM_IC_VER 0x7d //0x7D +//#define EEPROM_CRC 0x7e //0x7E~0x7F +// +// +//#define EEPROM_CID_DEFAULT 0x0 +//#define EEPROM_CID_CAMEO 0x1 +//#define EEPROM_CID_RUNTOP 0x2 +//#define EEPROM_CID_Senao 0x3 +//#define EEPROM_CID_TOSHIBA 0x4 // Toshiba setting, Merge by Jacken, 2008/01/31 +//#define EEPROM_CID_NetCore 0x5 + + +// +//--------------92SU require delete or move to other place later +// + +//============================================================ +// CCX Related Register +//============================================================ +#define CCX_COMMAND_REG 0x890 +// CCX Measurement Command Register. 4 Bytes. +// Bit[0]: R_CLM_En, 1=enable, 0=disable. Enable or disable "Channel Load +// Measurement (CLM)". +// Bit[1]: R_NHM_En, 1=enable, 0=disable. Enable or disalbe "Noise Histogram +// Measurement (NHM)". +// Bit[2~7]: Reserved +// Bit[8]: R_CCX_En: 1=enable, 0=disable. Enable or disable CCX function. +// Note: After clearing this bit, all the result of all NHM_Result and CLM_ +// Result are cleared concurrently. +// Bit[9]: R_Ignore_CCA: 1=enable, 0=disable. Enable means that treat CCA +// period as idle time for NHM. +// Bit[10]: R_Ignore_TXON: 1=enable, 0=disable. Enable means that treat TXON +// period as idle time for NHM. +// Bit[11~31]: Reserved. +#define CLM_PERIOD_REG 0x894 +// CCX Measurement Period Register, in unit of 4us. 2 Bytes. +#define NHM_PERIOD_REG 0x896 +// Noise Histogram Measurement Period Register, in unit of 4us. 2Bytes. +#define NHM_THRESHOLD0 0x898 // Noise Histogram Meashorement0 +#define NHM_THRESHOLD1 0x899 // Noise Histogram Meashorement1 +#define NHM_THRESHOLD2 0x89A // Noise Histogram Meashorement2 +#define NHM_THRESHOLD3 0x89B // Noise Histogram Meashorement3 +#define NHM_THRESHOLD4 0x89C // Noise Histogram Meashorement4 +#define NHM_THRESHOLD5 0x89D // Noise Histogram Meashorement5 +#define NHM_THRESHOLD6 0x89E // Noise Histogram Meashorement6 +#define CLM_RESULT_REG 0x8D0 +// Channel Load result register. 4 Bytes. +// Bit[0~15]: Total measured duration of CLM. The CCA busy fraction is caculate +// by CLM_RESULT_REG/CLM_PERIOD_REG. +// Bit[16]: Indicate the CLM result is ready. +// Bit[17~31]: Reserved. +#define NHM_RESULT_REG 0x8D4 +// Noise Histogram result register. 4 Bytes. +// Bit[0~15]: Total measured duration of NHM. If R_Ignore_CCA=1 or +// R_Ignore_TXON=1, this value will be less than NHM_PERIOD_REG. +// Bit[16]: Indicate the NHM result is ready. +// Bit[17~31]: Reserved. +#define NHM_RPI_COUNTER0 0x8D8 +// NHM RPI counter0, the fraction of signal strength < NHM_THRESHOLD0. +#define NHM_RPI_COUNTER1 0x8D9 +// NHM RPI counter1, the fraction of signal stren in NHM_THRESH0, NHM_THRESH1 +#define NHM_RPI_COUNTER2 0x8DA +// NHM RPI counter2, the fraction of signal stren in NHM_THRESH2, NHM_THRESH3 +#define NHM_RPI_COUNTER3 0x8DB +// NHM RPI counter3, the fraction of signal stren in NHM_THRESH4, NHM_THRESH5 +#define NHM_RPI_COUNTER4 0x8DC +// NHM RPI counter4, the fraction of signal stren in NHM_THRESH6, NHM_THRESH7 +#define NHM_RPI_COUNTER5 0x8DD +// NHM RPI counter5, the fraction of signal stren in NHM_THRESH8, NHM_THRESH9 +#define NHM_RPI_COUNTER6 0x8DE +// NHM RPI counter6, the fraction of signal stren in NHM_THRESH10, NHM_THRESH11 +#define NHM_RPI_COUNTER7 0x8DF +// NHM RPI counter7, the fraction of signal stren in NHM_THRESH12, NHM_THRESH13 + +#define HAL_RETRY_LIMIT_INFRA 48 +#define HAL_RETRY_LIMIT_AP_ADHOC 7 + +// HW Readio OFF switch (GPIO BIT) +#define HAL_8192S_HW_GPIO_OFF_BIT BIT3 +#define HAL_8192S_HW_GPIO_OFF_MASK 0xF7 +#define HAL_8192S_HW_GPIO_WPS_BIT BIT4 + +#endif //R8192S_HW + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/drivers/staging/rtl8192su/r8192S_phy.c b/drivers/staging/rtl8192su/r8192S_phy.c new file mode 100644 index 000000000000..99a4051a8458 --- /dev/null +++ b/drivers/staging/rtl8192su/r8192S_phy.c @@ -0,0 +1,5028 @@ +/****************************************************************************** + + (c) Copyright 2008, RealTEK Technologies Inc. All Rights Reserved. + + Module: hal8192sphy.c + + Note: Merge 92SE/SU PHY config as below + 1. BB register R/W API + 2. RF register R/W API + 3. Initial BB/RF/MAC config by reading BB/MAC/RF txt. + 3. Power setting API + 4. Channel switch API + 5. Initial gain switch API. + 6. Other BB/MAC/RF API. + + Function: PHY: Extern function, phy: local function + + Export: PHY_FunctionName + + Abbrev: NONE + + History: + Data Who Remark + 08/08/2008 MHC 1. Port from 9x series phycfg.c + 2. Reorganize code arch and ad description. + 3. Collect similar function. + 4. Seperate extern/local API. + 08/12/2008 MHC We must merge or move USB PHY relative function later. + 10/07/2008 MHC Add IQ calibration for PHY.(Only 1T2R mode now!!!) + 11/06/2008 MHC Add TX Power index PG file to config in 0xExx register + area to map with EEPROM/EFUSE tx pwr index. + +******************************************************************************/ +#include "r8192U.h" +#include "r8192U_dm.h" +#include "r8192S_rtl6052.h" + +#ifdef RTL8192SU +#include "r8192S_hw.h" +#include "r8192S_phy.h" +#include "r8192S_phyreg.h" +#include "r8192SU_HWImg.h" +//#include "r8192S_FwImgDTM.h" +#else +#include "r8192U_hw.h" +#include "r819xU_phy.h" +#include "r819xU_phyreg.h" +#endif + +#ifdef ENABLE_DOT11D +#include "dot11d.h" +#endif + +/*---------------------------Define Local Constant---------------------------*/ +/* Channel switch:The size of command tables for switch channel*/ +#define MAX_PRECMD_CNT 16 +#define MAX_RFDEPENDCMD_CNT 16 +#define MAX_POSTCMD_CNT 16 +#define MAX_DOZE_WAITING_TIMES_9x 64 + +/*------------------------Define local variable------------------------------*/ +// 2004-05-11 +#ifndef RTL8192SU +static u32 RF_CHANNEL_TABLE_ZEBRA[]={ + 0, + 0x085c,//2412 1 + 0x08dc,//2417 2 + 0x095c,//2422 3 + 0x09dc,//2427 4 + 0x0a5c,//2432 5 + 0x0adc,//2437 6 + 0x0b5c,//2442 7 + 0x0bdc,//2447 8 + 0x0c5c,//2452 9 + 0x0cdc,//2457 10 + 0x0d5c,//2462 11 + 0x0ddc,//2467 12 + 0x0e5c,//2472 13 + //0x0f5c,//2484 + 0x0f72,//2484 //20040810 +}; +#endif + +static u32 +phy_CalculateBitShift(u32 BitMask); +static RT_STATUS +phy_ConfigMACWithHeaderFile(struct net_device* dev); +static void +phy_InitBBRFRegisterDefinition(struct net_device* dev); +static RT_STATUS +phy_BB8192S_Config_ParaFile(struct net_device* dev); +static RT_STATUS +phy_ConfigBBWithHeaderFile(struct net_device* dev,u8 ConfigType); +static bool +phy_SetRFPowerState8192SU(struct net_device* dev,RT_RF_POWER_STATE eRFPowerState); +void +SetBWModeCallback8192SUsbWorkItem(struct net_device *dev); +void +SetBWModeCallback8192SUsbWorkItem(struct net_device *dev); +void +SwChnlCallback8192SUsbWorkItem(struct net_device *dev ); +static void +phy_FinishSwChnlNow(struct net_device* dev,u8 channel); +static bool +phy_SwChnlStepByStep( + struct net_device* dev, + u8 channel, + u8 *stage, + u8 *step, + u32 *delay + ); +static RT_STATUS +phy_ConfigBBWithPgHeaderFile(struct net_device* dev,u8 ConfigType); +#ifdef RTL8192SE +static u32 phy_FwRFSerialRead( struct net_device* dev, RF90_RADIO_PATH_E eRFPath, u32 Offset); +static u32 phy_RFSerialRead(struct net_device* dev,RF90_RADIO_PATH_E eRFPath,u32 Offset); +static void phy_FwRFSerialWrite( struct net_device* dev, RF90_RADIO_PATH_E eRFPath, u32 Offset, u32 Data); +static void phy_RFSerialWrite( struct net_device* dev, RF90_RADIO_PATH_E eRFPath, u32 Offset, u32 Data); +#endif +static long phy_TxPwrIdxToDbm( struct net_device* dev, WIRELESS_MODE WirelessMode, u8 TxPwrIdx); +static u8 phy_DbmToTxPwrIdx( struct net_device* dev, WIRELESS_MODE WirelessMode, long PowerInDbm); +void phy_SetFwCmdIOCallback(struct net_device* dev); + +//#if ((HAL_CODE_BASE == RTL8192_S) && (DEV_BUS_TYPE==USB_INTERFACE)) +#ifdef RTL8192SU +// +// Description: +// Base Band read by 4181 to make sure that operation could be done in unlimited cycle. +// +// Assumption: +// - Only use on RTL8192S USB interface. +// - PASSIVE LEVEL +// +// Created by Roger, 2008.09.06. +// +//use in phy only +u32 phy_QueryUsbBBReg(struct net_device* dev, u32 RegAddr) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + u32 ReturnValue = 0xffffffff; + u8 PollingCnt = 50; + u8 BBWaitCounter = 0; + + + // + // Due to PASSIVE_LEVEL, so we ONLY simply busy waiting for a while here. + // We have to make sure that previous BB I/O has been done. + // 2008.08.20. + // + while(priv->bChangeBBInProgress) + { + BBWaitCounter ++; + RT_TRACE(COMP_RF, "phy_QueryUsbBBReg(): Wait 1 ms (%d times)...\n", BBWaitCounter); + msleep(1); // 1 ms + + // Wait too long, return FALSE to avoid to be stuck here. + if((BBWaitCounter > 100) )//||RT_USB_CANNOT_IO(Adapter)) + { + RT_TRACE(COMP_RF, "phy_QueryUsbBBReg(): (%d) Wait too logn to query BB!!\n", BBWaitCounter); + return ReturnValue; + } + } + + priv->bChangeBBInProgress = true; + + read_nic_dword(dev, RegAddr); + + do + {// Make sure that access could be done. + if((read_nic_byte(dev, PHY_REG)&HST_RDBUSY) == 0) + break; + }while( --PollingCnt ); + + if(PollingCnt == 0) + { + RT_TRACE(COMP_RF, "Fail!!!phy_QueryUsbBBReg(): RegAddr(%#x) = %#x\n", RegAddr, ReturnValue); + } + else + { + // Data FW read back. + ReturnValue = read_nic_dword(dev, PHY_REG_DATA); + RT_TRACE(COMP_RF, "phy_QueryUsbBBReg(): RegAddr(%#x) = %#x, PollingCnt(%d)\n", RegAddr, ReturnValue, PollingCnt); + } + + priv->bChangeBBInProgress = false; + + return ReturnValue; +} + + + +// +// Description: +// Base Band wrote by 4181 to make sure that operation could be done in unlimited cycle. +// +// Assumption: +// - Only use on RTL8192S USB interface. +// - PASSIVE LEVEL +// +// Created by Roger, 2008.09.06. +// +//use in phy only +void +phy_SetUsbBBReg(struct net_device* dev,u32 RegAddr,u32 Data) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + u8 BBWaitCounter = 0; + + RT_TRACE(COMP_RF, "phy_SetUsbBBReg(): RegAddr(%#x) <= %#x\n", RegAddr, Data); + + // + // Due to PASSIVE_LEVEL, so we ONLY simply busy waiting for a while here. + // We have to make sure that previous BB I/O has been done. + // 2008.08.20. + // + while(priv->bChangeBBInProgress) + { + BBWaitCounter ++; + RT_TRACE(COMP_RF, "phy_SetUsbBBReg(): Wait 1 ms (%d times)...\n", BBWaitCounter); + msleep(1); // 1 ms + + if((BBWaitCounter > 100))// || RT_USB_CANNOT_IO(Adapter)) + { + RT_TRACE(COMP_RF, "phy_SetUsbBBReg(): (%d) Wait too logn to query BB!!\n", BBWaitCounter); + return; + } + } + + priv->bChangeBBInProgress = true; + //printk("**************%s: RegAddr:%x Data:%x\n", __FUNCTION__,RegAddr, Data); + write_nic_dword(dev, RegAddr, Data); + + priv->bChangeBBInProgress = false; +} + + + +// +// Description: +// RF read by 4181 to make sure that operation could be done in unlimited cycle. +// +// Assumption: +// - Only use on RTL8192S USB interface. +// - PASSIVE LEVEL +// - RT_RF_OPERATE_SPINLOCK is acquired and keep on holding to the end.FIXLZM +// +// Created by Roger, 2008.09.06. +// +//use in phy only +u32 phy_QueryUsbRFReg( struct net_device* dev, RF90_RADIO_PATH_E eRFPath, u32 Offset) +{ + + struct r8192_priv *priv = ieee80211_priv(dev); + //u32 value = 0, ReturnValue = 0; + u32 ReturnValue = 0; + //u32 tmplong,tmplong2; + u8 PollingCnt = 50; + u8 RFWaitCounter = 0; + + + // + // Due to PASSIVE_LEVEL, so we ONLY simply busy waiting for a while here. + // We have to make sure that previous RF I/O has been done. + // 2008.08.20. + // + while(priv->bChangeRFInProgress) + { + //PlatformReleaseSpinLock(Adapter, RT_RF_OPERATE_SPINLOCK); + //spin_lock_irqsave(&priv->rf_lock, flags); //LZM,090318 + down(&priv->rf_sem); + + RFWaitCounter ++; + RT_TRACE(COMP_RF, "phy_QueryUsbRFReg(): Wait 1 ms (%d times)...\n", RFWaitCounter); + msleep(1); // 1 ms + + if((RFWaitCounter > 100)) //|| RT_USB_CANNOT_IO(Adapter)) + { + RT_TRACE(COMP_RF, "phy_QueryUsbRFReg(): (%d) Wait too logn to query BB!!\n", RFWaitCounter); + return 0xffffffff; + } + else + { + //PlatformAcquireSpinLock(Adapter, RT_RF_OPERATE_SPINLOCK); + } + } + + priv->bChangeRFInProgress = true; + //PlatformReleaseSpinLock(Adapter, RT_RF_OPERATE_SPINLOCK); + + + Offset &= 0x3f; //RF_Offset= 0x00~0x3F + + write_nic_dword(dev, RF_BB_CMD_ADDR, 0xF0000002| + (Offset<<8)| //RF_Offset= 0x00~0x3F + (eRFPath<<16)); //RF_Path = 0(A) or 1(B) + + do + {// Make sure that access could be done. + if(read_nic_dword(dev, RF_BB_CMD_ADDR) == 0) + break; + }while( --PollingCnt ); + + // Data FW read back. + ReturnValue = read_nic_dword(dev, RF_BB_CMD_DATA); + + //PlatformAcquireSpinLock(Adapter, RT_RF_OPERATE_SPINLOCK); + //spin_unlock_irqrestore(&priv->rf_lock, flags); //LZM,090318 + up(&priv->rf_sem); + priv->bChangeRFInProgress = false; + + RT_TRACE(COMP_RF, "phy_QueryUsbRFReg(): eRFPath(%d), Offset(%#x) = %#x\n", eRFPath, Offset, ReturnValue); + + return ReturnValue; + +} + + +// +// Description: +// RF wrote by 4181 to make sure that operation could be done in unlimited cycle. +// +// Assumption: +// - Only use on RTL8192S USB interface. +// - PASSIVE LEVEL +// - RT_RF_OPERATE_SPINLOCK is acquired and keep on holding to the end.FIXLZM +// +// Created by Roger, 2008.09.06. +// +//use in phy only +void phy_SetUsbRFReg(struct net_device* dev,RF90_RADIO_PATH_E eRFPath,u32 RegAddr,u32 Data) +{ + + struct r8192_priv *priv = ieee80211_priv(dev); + u8 PollingCnt = 50; + u8 RFWaitCounter = 0; + + + // + // Due to PASSIVE_LEVEL, so we ONLY simply busy waiting for a while here. + // We have to make sure that previous BB I/O has been done. + // 2008.08.20. + // + while(priv->bChangeRFInProgress) + { + //PlatformReleaseSpinLock(Adapter, RT_RF_OPERATE_SPINLOCK); + //spin_lock_irqsave(&priv->rf_lock, flags); //LZM,090318 + down(&priv->rf_sem); + + RFWaitCounter ++; + RT_TRACE(COMP_RF, "phy_SetUsbRFReg(): Wait 1 ms (%d times)...\n", RFWaitCounter); + msleep(1); // 1 ms + + if((RFWaitCounter > 100))// || RT_USB_CANNOT_IO(Adapter)) + { + RT_TRACE(COMP_RF, "phy_SetUsbRFReg(): (%d) Wait too logn to query BB!!\n", RFWaitCounter); + return; + } + else + { + //PlatformAcquireSpinLock(Adapter, RT_RF_OPERATE_SPINLOCK); + } + } + + priv->bChangeRFInProgress = true; + //PlatformReleaseSpinLock(Adapter, RT_RF_OPERATE_SPINLOCK); + + + RegAddr &= 0x3f; //RF_Offset= 0x00~0x3F + + write_nic_dword(dev, RF_BB_CMD_DATA, Data); + write_nic_dword(dev, RF_BB_CMD_ADDR, 0xF0000003| + (RegAddr<<8)| //RF_Offset= 0x00~0x3F + (eRFPath<<16)); //RF_Path = 0(A) or 1(B) + + do + {// Make sure that access could be done. + if(read_nic_dword(dev, RF_BB_CMD_ADDR) == 0) + break; + }while( --PollingCnt ); + + if(PollingCnt == 0) + { + RT_TRACE(COMP_RF, "phy_SetUsbRFReg(): Set RegAddr(%#x) = %#x Fail!!!\n", RegAddr, Data); + } + + //PlatformAcquireSpinLock(Adapter, RT_RF_OPERATE_SPINLOCK); + //spin_unlock_irqrestore(&priv->rf_lock, flags); //LZM,090318 + up(&priv->rf_sem); + priv->bChangeRFInProgress = false; + +} + +#endif + +/*---------------------Define local function prototype-----------------------*/ + + +/*----------------------------Function Body----------------------------------*/ +// +// 1. BB register R/W API +// +/** +* Function: PHY_QueryBBReg +* +* OverView: Read "sepcific bits" from BB register +* +* Input: +* PADAPTER Adapter, +* u32 RegAddr, //The target address to be readback +* u32 BitMask //The target bit position in the target address +* //to be readback +* Output: None +* Return: u32 Data //The readback register value +* Note: This function is equal to "GetRegSetting" in PHY programming guide +*/ +//use phy dm core 8225 8256 6052 +//u32 PHY_QueryBBReg(struct net_device* dev,u32 RegAddr, u32 BitMask) +u32 rtl8192_QueryBBReg(struct net_device* dev, u32 RegAddr, u32 BitMask) +{ + + u32 ReturnValue = 0, OriginalValue, BitShift; + +#if (DISABLE_BB_RF == 1) + return 0; +#endif + + RT_TRACE(COMP_RF, "--->PHY_QueryBBReg(): RegAddr(%#x), BitMask(%#x)\n", RegAddr, BitMask); + + // + // Due to 8051 operation cycle (limitation cycle: 6us) and 1-Byte access issue, we should use + // 4181 to access Base Band instead of 8051 on USB interface to make sure that access could be done in + // infinite cycle. + // 2008.09.06. + // +//#if ((HAL_CODE_BASE == RTL8192_S) && (DEV_BUS_TYPE==USB_INTERFACE)) +#ifdef RTL8192SU + if(IS_BB_REG_OFFSET_92S(RegAddr)) + { + //if(RT_USB_CANNOT_IO(Adapter)) return FALSE; + + if((RegAddr & 0x03) != 0) + { + printk("%s: Not DWORD alignment!!\n", __FUNCTION__); + return 0; + } + + OriginalValue = phy_QueryUsbBBReg(dev, RegAddr); + } + else +#endif + { + OriginalValue = read_nic_dword(dev, RegAddr); + } + + BitShift = phy_CalculateBitShift(BitMask); + ReturnValue = (OriginalValue & BitMask) >> BitShift; + + //RTPRINT(FPHY, PHY_BBR, ("BBR MASK=0x%x Addr[0x%x]=0x%x\n", BitMask, RegAddr, OriginalValue)); + RT_TRACE(COMP_RF, "<---PHY_QueryBBReg(): RegAddr(%#x), BitMask(%#x), OriginalValue(%#x)\n", RegAddr, BitMask, OriginalValue); + return (ReturnValue); +} + +/** +* Function: PHY_SetBBReg +* +* OverView: Write "Specific bits" to BB register (page 8~) +* +* Input: +* PADAPTER Adapter, +* u32 RegAddr, //The target address to be modified +* u32 BitMask //The target bit position in the target address +* //to be modified +* u32 Data //The new register value in the target bit position +* //of the target address +* +* Output: None +* Return: None +* Note: This function is equal to "PutRegSetting" in PHY programming guide +*/ +//use phy dm core 8225 8256 +//void PHY_SetBBReg(struct net_device* dev,u32 RegAddr, u32 BitMask, u32 Data ) +void rtl8192_setBBreg(struct net_device* dev, u32 RegAddr, u32 BitMask, u32 Data) +{ + u32 OriginalValue, BitShift, NewValue; + +#if (DISABLE_BB_RF == 1) + return; +#endif + + RT_TRACE(COMP_RF, "--->PHY_SetBBReg(): RegAddr(%#x), BitMask(%#x), Data(%#x)\n", RegAddr, BitMask, Data); + + // + // Due to 8051 operation cycle (limitation cycle: 6us) and 1-Byte access issue, we should use + // 4181 to access Base Band instead of 8051 on USB interface to make sure that access could be done in + // infinite cycle. + // 2008.09.06. + // +//#if ((HAL_CODE_BASE == RTL8192_S) && (DEV_BUS_TYPE==USB_INTERFACE)) +#ifdef RTL8192SU + if(IS_BB_REG_OFFSET_92S(RegAddr)) + { + if((RegAddr & 0x03) != 0) + { + printk("%s: Not DWORD alignment!!\n", __FUNCTION__); + return; + } + + if(BitMask!= bMaskDWord) + {//if not "double word" write + OriginalValue = phy_QueryUsbBBReg(dev, RegAddr); + BitShift = phy_CalculateBitShift(BitMask); + NewValue = (((OriginalValue) & (~BitMask))|(Data << BitShift)); + phy_SetUsbBBReg(dev, RegAddr, NewValue); + }else + phy_SetUsbBBReg(dev, RegAddr, Data); + } + else +#endif + { + if(BitMask!= bMaskDWord) + {//if not "double word" write + OriginalValue = read_nic_dword(dev, RegAddr); + BitShift = phy_CalculateBitShift(BitMask); + NewValue = (((OriginalValue) & (~BitMask)) | (Data << BitShift)); + write_nic_dword(dev, RegAddr, NewValue); + }else + write_nic_dword(dev, RegAddr, Data); + } + + //RT_TRACE(COMP_RF, "<---PHY_SetBBReg(): RegAddr(%#x), BitMask(%#x), Data(%#x)\n", RegAddr, BitMask, Data); + + return; +} + + +// +// 2. RF register R/W API +// +/** +* Function: PHY_QueryRFReg +* +* OverView: Query "Specific bits" to RF register (page 8~) +* +* Input: +* PADAPTER Adapter, +* RF90_RADIO_PATH_E eRFPath, //Radio path of A/B/C/D +* u32 RegAddr, //The target address to be read +* u32 BitMask //The target bit position in the target address +* //to be read +* +* Output: None +* Return: u32 Readback value +* Note: This function is equal to "GetRFRegSetting" in PHY programming guide +*/ +//in dm 8256 and phy +//u32 PHY_QueryRFReg(struct net_device* dev, RF90_RADIO_PATH_E eRFPath, u32 RegAddr, u32 BitMask) +u32 rtl8192_phy_QueryRFReg(struct net_device* dev, RF90_RADIO_PATH_E eRFPath, u32 RegAddr, u32 BitMask) +{ + u32 Original_Value, Readback_Value, BitShift;//, flags; + struct r8192_priv *priv = ieee80211_priv(dev); + +#if (DISABLE_BB_RF == 1) + return 0; +#endif + + RT_TRACE(COMP_RF, "--->PHY_QueryRFReg(): RegAddr(%#x), eRFPath(%#x), BitMask(%#x)\n", RegAddr, eRFPath,BitMask); + + if (!((priv->rf_pathmap >> eRFPath) & 0x1)) + { + printk("EEEEEError: rfpath off! rf_pathmap=%x eRFPath=%x\n", priv->rf_pathmap, eRFPath); + return 0; + } + + if (!rtl8192_phy_CheckIsLegalRFPath(dev, eRFPath)) + { + printk("EEEEEError: not legal rfpath! eRFPath=%x\n", eRFPath); + return 0; + } + + /* 2008/01/17 MH We get and release spin lock when reading RF register. */ + //PlatformAcquireSpinLock(dev, RT_RF_OPERATE_SPINLOCK);FIXLZM + //spin_lock_irqsave(&priv->rf_lock, flags); //YJ,test,090113 + down(&priv->rf_sem); + // + // Due to 8051 operation cycle (limitation cycle: 6us) and 1-Byte access issue, we should use + // 4181 to access Base Band instead of 8051 on USB interface to make sure that access could be done in + // infinite cycle. + // 2008.09.06. + // +//#if (HAL_CODE_BASE == RTL8192_S && DEV_BUS_TYPE==USB_INTERFACE) +#ifdef RTL8192SU + //if(RT_USB_CANNOT_IO(Adapter)) return FALSE; + Original_Value = phy_QueryUsbRFReg(dev, eRFPath, RegAddr); +#else + if (priv->Rf_Mode == RF_OP_By_FW) + { + Original_Value = phy_FwRFSerialRead(dev, eRFPath, RegAddr); + } + else + { + Original_Value = phy_RFSerialRead(dev, eRFPath, RegAddr); + } +#endif + + BitShift = phy_CalculateBitShift(BitMask); + Readback_Value = (Original_Value & BitMask) >> BitShift; + //spin_unlock_irqrestore(&priv->rf_lock, flags); //YJ,test,090113 + up(&priv->rf_sem); + //PlatformReleaseSpinLock(dev, RT_RF_OPERATE_SPINLOCK); + + //RTPRINT(FPHY, PHY_RFR, ("RFR-%d MASK=0x%x Addr[0x%x]=0x%x\n", eRFPath, BitMask, RegAddr, Original_Value)); + + return (Readback_Value); +} + +/** +* Function: PHY_SetRFReg +* +* OverView: Write "Specific bits" to RF register (page 8~) +* +* Input: +* PADAPTER Adapter, +* RF90_RADIO_PATH_E eRFPath, //Radio path of A/B/C/D +* u32 RegAddr, //The target address to be modified +* u32 BitMask //The target bit position in the target address +* //to be modified +* u32 Data //The new register Data in the target bit position +* //of the target address +* +* Output: None +* Return: None +* Note: This function is equal to "PutRFRegSetting" in PHY programming guide +*/ +//use phy 8225 8256 +//void PHY_SetRFReg(struct net_device* dev,RF90_RADIO_PATH_E eRFPath, u32 RegAddr, u32 BitMask,u32 Data ) +void rtl8192_phy_SetRFReg(struct net_device* dev, RF90_RADIO_PATH_E eRFPath, u32 RegAddr, u32 BitMask, u32 Data) +{ + + struct r8192_priv *priv = ieee80211_priv(dev); + u32 Original_Value, BitShift, New_Value;//, flags; +#if (DISABLE_BB_RF == 1) + return; +#endif + + RT_TRACE(COMP_RF, "--->PHY_SetRFReg(): RegAddr(%#x), BitMask(%#x), Data(%#x), eRFPath(%#x)\n", + RegAddr, BitMask, Data, eRFPath); + + if (!((priv->rf_pathmap >> eRFPath) & 0x1)) + { + printk("EEEEEError: rfpath off! rf_pathmap=%x eRFPath=%x\n", priv->rf_pathmap, eRFPath); + return ; + } + if (!rtl8192_phy_CheckIsLegalRFPath(dev, eRFPath)) + { + printk("EEEEEError: not legal rfpath! eRFPath=%x\n", eRFPath); + return; + } + + /* 2008/01/17 MH We get and release spin lock when writing RF register. */ + //PlatformAcquireSpinLock(dev, RT_RF_OPERATE_SPINLOCK); + //spin_lock_irqsave(&priv->rf_lock, flags); //YJ,test,090113 + down(&priv->rf_sem); + // + // Due to 8051 operation cycle (limitation cycle: 6us) and 1-Byte access issue, we should use + // 4181 to access Base Band instead of 8051 on USB interface to make sure that access could be done in + // infinite cycle. + // 2008.09.06. + // +//#if (HAL_CODE_BASE == RTL8192_S && DEV_BUS_TYPE==USB_INTERFACE) +#ifdef RTL8192SU + //if(RT_USB_CANNOT_IO(Adapter)) return; + + if (BitMask != bRFRegOffsetMask) // RF data is 12 bits only + { + Original_Value = phy_QueryUsbRFReg(dev, eRFPath, RegAddr); + BitShift = phy_CalculateBitShift(BitMask); + New_Value = (((Original_Value)&(~BitMask))|(Data<< BitShift)); + phy_SetUsbRFReg(dev, eRFPath, RegAddr, New_Value); + } + else + phy_SetUsbRFReg(dev, eRFPath, RegAddr, Data); +#else + if (priv->Rf_Mode == RF_OP_By_FW) + { + //DbgPrint("eRFPath-%d Addr[%02x] = %08x\n", eRFPath, RegAddr, Data); + if (BitMask != bRFRegOffsetMask) // RF data is 12 bits only + { + Original_Value = phy_FwRFSerialRead(dev, eRFPath, RegAddr); + BitShift = phy_CalculateBitShift(BitMask); + New_Value = (((Original_Value) & (~BitMask)) | (Data<< BitShift)); + + phy_FwRFSerialWrite(dev, eRFPath, RegAddr, New_Value); + } + else + phy_FwRFSerialWrite(dev, eRFPath, RegAddr, Data); + } + else + { + //DbgPrint("eRFPath-%d Addr[%02x] = %08x\n", eRFPath, RegAddr, Data); + if (BitMask != bRFRegOffsetMask) // RF data is 12 bits only + { + Original_Value = phy_RFSerialRead(dev, eRFPath, RegAddr); + BitShift = phy_CalculateBitShift(BitMask); + New_Value = (((Original_Value) & (~BitMask)) | (Data<< BitShift)); + + phy_RFSerialWrite(dev, eRFPath, RegAddr, New_Value); + } + else + phy_RFSerialWrite(dev, eRFPath, RegAddr, Data); + + } +#endif + //PlatformReleaseSpinLock(dev, RT_RF_OPERATE_SPINLOCK); + //spin_unlock_irqrestore(&priv->rf_lock, flags); //YJ,test,090113 + up(&priv->rf_sem); + //RTPRINT(FPHY, PHY_RFW, ("RFW-%d MASK=0x%x Addr[0x%x]=0x%x\n", eRFPath, BitMask, RegAddr, Data)); + RT_TRACE(COMP_RF, "<---PHY_SetRFReg(): RegAddr(%#x), BitMask(%#x), Data(%#x), eRFPath(%#x)\n", + RegAddr, BitMask, Data, eRFPath); + +} + +#ifdef RTL8192SE +/*----------------------------------------------------------------------------- + * Function: phy_FwRFSerialRead() + * + * Overview: We support firmware to execute RF-R/W. + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 01/21/2008 MHC Create Version 0. + * + *---------------------------------------------------------------------------*/ +//use in phy only +static u32 +phy_FwRFSerialRead( + struct net_device* dev, + RF90_RADIO_PATH_E eRFPath, + u32 Offset ) +{ + u32 retValue = 0; + //u32 Data = 0; + //u8 time = 0; +#if 0 + //DbgPrint("FW RF CTRL\n\r"); + /* 2007/11/02 MH Firmware RF Write control. By Francis' suggestion, we can + not execute the scheme in the initial step. Otherwise, RF-R/W will waste + much time. This is only for site survey. */ + // 1. Read operation need not insert data. bit 0-11 + //Data &= bMask12Bits; + // 2. Write RF register address. Bit 12-19 + Data |= ((Offset&0xFF)<<12); + // 3. Write RF path. bit 20-21 + Data |= ((eRFPath&0x3)<<20); + // 4. Set RF read indicator. bit 22=0 + //Data |= 0x00000; + // 5. Trigger Fw to operate the command. bit 31 + Data |= 0x80000000; + // 6. We can not execute read operation if bit 31 is 1. + while (PlatformIORead4Byte(dev, QPNR)&0x80000000) + { + // If FW can not finish RF-R/W for more than ?? times. We must reset FW. + if (time++ < 100) + { + //DbgPrint("FW not finish RF-R Time=%d\n\r", time); + delay_us(10); + } + else + break; + } + // 7. Execute read operation. + PlatformIOWrite4Byte(dev, QPNR, Data); + // 8. Check if firmawre send back RF content. + while (PlatformIORead4Byte(dev, QPNR)&0x80000000) + { + // If FW can not finish RF-R/W for more than ?? times. We must reset FW. + if (time++ < 100) + { + //DbgPrint("FW not finish RF-W Time=%d\n\r", time); + delay_us(10); + } + else + return (0); + } + retValue = PlatformIORead4Byte(dev, RF_DATA); +#endif + return (retValue); + +} /* phy_FwRFSerialRead */ + +/*----------------------------------------------------------------------------- + * Function: phy_FwRFSerialWrite() + * + * Overview: We support firmware to execute RF-R/W. + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 01/21/2008 MHC Create Version 0. + * + *---------------------------------------------------------------------------*/ +//use in phy only +static void +phy_FwRFSerialWrite( + struct net_device* dev, + RF90_RADIO_PATH_E eRFPath, + u32 Offset, + u32 Data ) +{ +#if 0 + u8 time = 0; + DbgPrint("N FW RF CTRL RF-%d OF%02x DATA=%03x\n\r", eRFPath, Offset, Data); + /* 2007/11/02 MH Firmware RF Write control. By Francis' suggestion, we can + not execute the scheme in the initial step. Otherwise, RF-R/W will waste + much time. This is only for site survey. */ + + // 1. Set driver write bit and 12 bit data. bit 0-11 + //Data &= bMask12Bits; // Done by uper layer. + // 2. Write RF register address. bit 12-19 + Data |= ((Offset&0xFF)<<12); + // 3. Write RF path. bit 20-21 + Data |= ((eRFPath&0x3)<<20); + // 4. Set RF write indicator. bit 22=1 + Data |= 0x400000; + // 5. Trigger Fw to operate the command. bit 31=1 + Data |= 0x80000000; + + // 6. Write operation. We can not write if bit 31 is 1. + while (PlatformIORead4Byte(dev, QPNR)&0x80000000) + { + // If FW can not finish RF-R/W for more than ?? times. We must reset FW. + if (time++ < 100) + { + //DbgPrint("FW not finish RF-W Time=%d\n\r", time); + delay_us(10); + } + else + break; + } + // 7. No matter check bit. We always force the write. Because FW will + // not accept the command. + PlatformIOWrite4Byte(dev, QPNR, Data); + /* 2007/11/02 MH Acoording to test, we must delay 20us to wait firmware + to finish RF write operation. */ + /* 2008/01/17 MH We support delay in firmware side now. */ + //delay_us(20); +#endif +} /* phy_FwRFSerialWrite */ + +/** +* Function: phy_RFSerialRead +* +* OverView: Read regster from RF chips +* +* Input: +* PADAPTER Adapter, +* RF90_RADIO_PATH_E eRFPath, //Radio path of A/B/C/D +* u32 Offset, //The target address to be read +* +* Output: None +* Return: u32 reback value +* Note: Threre are three types of serial operations: +* 1. Software serial write +* 2. Hardware LSSI-Low Speed Serial Interface +* 3. Hardware HSSI-High speed +* serial write. Driver need to implement (1) and (2). +* This function is equal to the combination of RF_ReadReg() and RFLSSIRead() +*/ +//use in phy only +static u32 phy_RFSerialRead(struct net_device* dev,RF90_RADIO_PATH_E eRFPath,u32 Offset) +{ + + u32 retValue = 0; + struct r8192_priv *priv = ieee80211_priv(dev); + BB_REGISTER_DEFINITION_T *pPhyReg = &priv->PHYRegDef[eRFPath]; + u32 NewOffset; + u8 RfPiEnable=0; + + + // + // Make sure RF register offset is correct + // + Offset &= 0x3f; + + // + // Switch page for 8256 RF IC + // + if( priv->rf_chip == RF_8256 || + priv->rf_chip == RF_8225 || + priv->rf_chip == RF_6052) + { + //analog to digital off, for protection + rtl8192_setBBreg(dev, rFPGA0_AnalogParameter4, 0xf00, 0x0);// 0x88c[11:8] + + if(Offset>=31) + { + priv->RFReadPageCnt[2]++;//cosa add for debug + priv->RfReg0Value[eRFPath] |= 0x140; + + // Switch to Reg_Mode2 for Reg31~45 + rtl8192_setBBreg(dev, + pPhyReg->rf3wireOffset, + bMaskDWord, + (priv->RfReg0Value[eRFPath] << 16) ); + + // Modified Offset + NewOffset = Offset - 30; + + }else if(Offset>=16) + { + priv->RFReadPageCnt[1]++;//cosa add for debug + priv->RfReg0Value[eRFPath] |= 0x100; + priv->RfReg0Value[eRFPath] &= (~0x40); + + // Switch to Reg_Mode1 for Reg16~30 + rtl8192_setBBreg(dev, + pPhyReg->rf3wireOffset, + bMaskDWord, + (priv->RfReg0Value[eRFPath] << 16) ); + + // Modified Offset + NewOffset = Offset - 15; + } + else + { + priv->RFReadPageCnt[0]++;//cosa add for debug + NewOffset = Offset; + } + } + else + NewOffset = Offset; + + // + // Put desired read address to LSSI control register + // + rtl8192_setBBreg(dev, pPhyReg->rfHSSIPara2, bLSSIReadAddress, NewOffset); + + // + // Issue a posedge trigger + // + rtl8192_setBBreg(dev, pPhyReg->rfHSSIPara2, bLSSIReadEdge, 0x0); + rtl8192_setBBreg(dev, pPhyReg->rfHSSIPara2, bLSSIReadEdge, 0x1); + + // TODO: we should not delay such a long time. Ask help from SD3 + mdelay(1); + + retValue = rtl8192_QueryBBReg(dev, pPhyReg->rfLSSIReadBack, bLSSIReadBackData); + + // Switch back to Reg_Mode0; + if( priv->rf_chip == RF_8256 || + priv->rf_chip == RF_8225 || + priv->rf_chip == RF_0222D) + { + if (Offset >= 0x10) + { + priv->RfReg0Value[eRFPath] &= 0xebf; + + rtl8192_setBBreg( + dev, + pPhyReg->rf3wireOffset, + bMaskDWord, + (priv->RfReg0Value[eRFPath] << 16) ); + } + + //analog to digital on + rtl8192_setBBreg(dev, rFPGA0_AnalogParameter4, 0xf00, 0xf);// 0x88c[11:8] + } + + return retValue; +} + + + +/** +* Function: phy_RFSerialWrite +* +* OverView: Write data to RF register (page 8~) +* +* Input: +* PADAPTER Adapter, +* RF90_RADIO_PATH_E eRFPath, //Radio path of A/B/C/D +* u32 Offset, //The target address to be read +* u32 Data //The new register Data in the target bit position +* //of the target to be read +* +* Output: None +* Return: None +* Note: Threre are three types of serial operations: +* 1. Software serial write +* 2. Hardware LSSI-Low Speed Serial Interface +* 3. Hardware HSSI-High speed +* serial write. Driver need to implement (1) and (2). +* This function is equal to the combination of RF_ReadReg() and RFLSSIRead() + * + * Note: For RF8256 only + * The total count of RTL8256(Zebra4) register is around 36 bit it only employs + * 4-bit RF address. RTL8256 uses "register mode control bit" (Reg00[12], Reg00[10]) + * to access register address bigger than 0xf. See "Appendix-4 in PHY Configuration + * programming guide" for more details. + * Thus, we define a sub-finction for RTL8526 register address conversion + * =========================================================== + * Register Mode RegCTL[1] RegCTL[0] Note + * (Reg00[12]) (Reg00[10]) + * =========================================================== + * Reg_Mode0 0 x Reg 0 ~15(0x0 ~ 0xf) + * ------------------------------------------------------------------ + * Reg_Mode1 1 0 Reg 16 ~30(0x1 ~ 0xf) + * ------------------------------------------------------------------ + * Reg_Mode2 1 1 Reg 31 ~ 45(0x1 ~ 0xf) + * ------------------------------------------------------------------ +*/ +////use in phy only +static void +phy_RFSerialWrite( + struct net_device* dev, + RF90_RADIO_PATH_E eRFPath, + u32 Offset, + u32 Data + ) +{ + u32 DataAndAddr = 0; + struct r8192_priv *priv = ieee80211_priv(dev); + BB_REGISTER_DEFINITION_T *pPhyReg = &priv->PHYRegDef[eRFPath]; + u32 NewOffset; + + Offset &= 0x3f; + + // Shadow Update + PHY_RFShadowWrite(dev, eRFPath, Offset, Data); + + + // Switch page for 8256 RF IC + if( priv->rf_chip == RF_8256 || + priv->rf_chip == RF_8225 || + priv->rf_chip == RF_0222D) + { + //analog to digital off, for protection + rtl8192_setBBreg(dev, rFPGA0_AnalogParameter4, 0xf00, 0x0);// 0x88c[11:8] + + if(Offset>=31) + { + priv->RFWritePageCnt[2]++;//cosa add for debug + priv->RfReg0Value[eRFPath] |= 0x140; + + rtl8192_setBBreg(dev, + pPhyReg->rf3wireOffset, + bMaskDWord, + (priv->RfReg0Value[eRFPath] << 16) ); + + NewOffset = Offset - 30; + + }else if(Offset>=16) + { + priv->RFWritePageCnt[1]++;//cosa add for debug + priv->RfReg0Value[eRFPath] |= 0x100; + priv->RfReg0Value[eRFPath] &= (~0x40); + + + rtl8192_setBBreg(dev, + pPhyReg->rf3wireOffset, + bMaskDWord, + (priv->RfReg0Value[eRFPath] << 16) ); + + NewOffset = Offset - 15; + } + else + { + priv->RFWritePageCnt[0]++;//cosa add for debug + NewOffset = Offset; + } + } + else + NewOffset = Offset; + + // + // Put write addr in [5:0] and write data in [31:16] + // + DataAndAddr = (Data<<16) | (NewOffset&0x3f); + + // + // Write Operation + // + rtl8192_setBBreg(dev, pPhyReg->rf3wireOffset, bMaskDWord, DataAndAddr); + + + if(Offset==0x0) + priv->RfReg0Value[eRFPath] = Data; + + // Switch back to Reg_Mode0; + if( priv->rf_chip == RF_8256 || + priv->rf_chip == RF_8225 || + priv->rf_chip == RF_0222D) + { + if (Offset >= 0x10) + { + if(Offset != 0) + { + priv->RfReg0Value[eRFPath] &= 0xebf; + rtl8192_setBBreg( + dev, + pPhyReg->rf3wireOffset, + bMaskDWord, + (priv->RfReg0Value[eRFPath] << 16) ); + } + } + //analog to digital on + rtl8192_setBBreg(dev, rFPGA0_AnalogParameter4, 0xf00, 0xf);// 0x88c[11:8] + } + +} +#else +/** +* Function: phy_RFSerialRead +* +* OverView: Read regster from RF chips +* +* Input: +* PADAPTER Adapter, +* RF90_RADIO_PATH_E eRFPath, //Radio path of A/B/C/D +* u4Byte Offset, //The target address to be read +* +* Output: None +* Return: u4Byte reback value +* Note: Threre are three types of serial operations: +* 1. Software serial write +* 2. Hardware LSSI-Low Speed Serial Interface +* 3. Hardware HSSI-High speed +* serial write. Driver need to implement (1) and (2). +* This function is equal to the combination of RF_ReadReg() and RFLSSIRead() +*/ +#if 0 +static u32 +phy_RFSerialRead(struct net_device* dev,RF90_RADIO_PATH_E eRFPath,u32 Offset) +{ + + u32 retValue = 0; + struct r8192_priv *priv = ieee80211_priv(dev); + BB_REGISTER_DEFINITION_T *pPhyReg = &priv->PHYRegDef[eRFPath]; + u32 NewOffset; + //u32 value = 0; + u32 tmplong,tmplong2; + u32 RfPiEnable=0; +#if 0 + if(pHalData->RFChipID == RF_8225 && Offset > 0x24) //36 valid regs + return retValue; + if(pHalData->RFChipID == RF_8256 && Offset > 0x2D) //45 valid regs + return retValue; +#endif + // + // Make sure RF register offset is correct + // + Offset &= 0x3f; + + // + // Switch page for 8256 RF IC + // + NewOffset = Offset; + + // For 92S LSSI Read RFLSSIRead + // For RF A/B write 0x824/82c(does not work in the future) + // We must use 0x824 for RF A and B to execute read trigger + tmplong = rtl8192_QueryBBReg(dev, rFPGA0_XA_HSSIParameter2, bMaskDWord); + tmplong2 = rtl8192_QueryBBReg(dev, pPhyReg->rfHSSIPara2, bMaskDWord); + tmplong2 = (tmplong2 & (~bLSSIReadAddress)) | (NewOffset<<23) | bLSSIReadEdge; //T65 RF + + rtl8192_setBBreg(dev, rFPGA0_XA_HSSIParameter2, bMaskDWord, tmplong&(~bLSSIReadEdge)); + mdelay(1); + + rtl8192_setBBreg(dev, pPhyReg->rfHSSIPara2, bMaskDWord, tmplong2); + mdelay(1); + + rtl8192_setBBreg(dev, rFPGA0_XA_HSSIParameter2, bMaskDWord, tmplong|bLSSIReadEdge); + mdelay(1); + + if(eRFPath == RF90_PATH_A) + RfPiEnable = (u8)rtl8192_QueryBBReg(dev, rFPGA0_XA_HSSIParameter1, BIT8); + else if(eRFPath == RF90_PATH_B) + RfPiEnable = (u8)rtl8192_QueryBBReg(dev, rFPGA0_XB_HSSIParameter1, BIT8); + + if(RfPiEnable) + { // Read from BBreg8b8, 12 bits for 8190, 20bits for T65 RF + retValue = rtl8192_QueryBBReg(dev, pPhyReg->rfLSSIReadBackPi, bLSSIReadBackData); + //DbgPrint("Readback from RF-PI : 0x%x\n", retValue); + } + else + { //Read from BBreg8a0, 12 bits for 8190, 20 bits for T65 RF + retValue = rtl8192_QueryBBReg(dev, pPhyReg->rfLSSIReadBack, bLSSIReadBackData); + //DbgPrint("Readback from RF-SI : 0x%x\n", retValue); + } + //RTPRINT(FPHY, PHY_RFR, ("RFR-%d Addr[0x%x]=0x%x\n", eRFPath, pPhyReg->rfLSSIReadBack, retValue)); + + return retValue; + +} +4 + + +/** +* Function: phy_RFSerialWrite +* +* OverView: Write data to RF register (page 8~) +* +* Input: +* PADAPTER Adapter, +* RF90_RADIO_PATH_E eRFPath, //Radio path of A/B/C/D +* u4Byte Offset, //The target address to be read +* u4Byte Data //The new register Data in the target bit position +* //of the target to be read +* +* Output: None +* Return: None +* Note: Threre are three types of serial operations: +* 1. Software serial write +* 2. Hardware LSSI-Low Speed Serial Interface +* 3. Hardware HSSI-High speed +* serial write. Driver need to implement (1) and (2). +* This function is equal to the combination of RF_ReadReg() and RFLSSIRead() + * + * Note: For RF8256 only + * The total count of RTL8256(Zebra4) register is around 36 bit it only employs + * 4-bit RF address. RTL8256 uses "register mode control bit" (Reg00[12], Reg00[10]) + * to access register address bigger than 0xf. See "Appendix-4 in PHY Configuration + * programming guide" for more details. + * Thus, we define a sub-finction for RTL8526 register address conversion + * =========================================================== + * Register Mode RegCTL[1] RegCTL[0] Note + * (Reg00[12]) (Reg00[10]) + * =========================================================== + * Reg_Mode0 0 x Reg 0 ~15(0x0 ~ 0xf) + * ------------------------------------------------------------------ + * Reg_Mode1 1 0 Reg 16 ~30(0x1 ~ 0xf) + * ------------------------------------------------------------------ + * Reg_Mode2 1 1 Reg 31 ~ 45(0x1 ~ 0xf) + * ------------------------------------------------------------------ + * + * 2008/09/02 MH Add 92S RF definition + * + * + * +*/ +static void +phy_RFSerialWrite(struct net_device* dev,RF90_RADIO_PATH_E eRFPath,u32 Offset,u32 Data) +{ + u32 DataAndAddr = 0; + struct r8192_priv *priv = ieee80211_priv(dev); + BB_REGISTER_DEFINITION_T *pPhyReg = &priv->PHYRegDef[eRFPath]; + u32 NewOffset; + +#if 0 + // We should check valid regs for RF_6052 case. + if(pHalData->RFChipID == RF_8225 && Offset > 0x24) //36 valid regs + return; + if(pHalData->RFChipID == RF_8256 && Offset > 0x2D) //45 valid regs + return; +#endif + + Offset &= 0x3f; + + // + // Shadow Update + // + PHY_RFShadowWrite(dev, eRFPath, Offset, Data); + + // + // Switch page for 8256 RF IC + // + NewOffset = Offset; + + // + // Put write addr in [5:0] and write data in [31:16] + // + //DataAndAddr = (Data<<16) | (NewOffset&0x3f); + DataAndAddr = ((NewOffset<<20) | (Data&0x000fffff)) & 0x0fffffff; // T65 RF + + // + // Write Operation + // + rtl8192_setBBreg(dev, pPhyReg->rf3wireOffset, bMaskDWord, DataAndAddr); + //RTPRINT(FPHY, PHY_RFW, ("RFW-%d Addr[0x%x]=0x%x\n", eRFPath, pPhyReg->rf3wireOffset, DataAndAddr)); + +} +#endif +#endif + +/** +* Function: phy_CalculateBitShift +* +* OverView: Get shifted position of the BitMask +* +* Input: +* u32 BitMask, +* +* Output: none +* Return: u32 Return the shift bit bit position of the mask +*/ +//use in phy only +static u32 phy_CalculateBitShift(u32 BitMask) +{ + u32 i; + + for(i=0; i<=31; i++) + { + if ( ((BitMask>>i) & 0x1 ) == 1) + break; + } + + return (i); +} + + +// +// 3. Initial MAC/BB/RF config by reading MAC/BB/RF txt. +// +/*----------------------------------------------------------------------------- + * Function: PHY_MACConfig8192S + * + * Overview: Condig MAC by header file or parameter file. + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 08/12/2008 MHC Create Version 0. + * + *---------------------------------------------------------------------------*/ +//adapter_start +extern bool PHY_MACConfig8192S(struct net_device* dev) +{ + RT_STATUS rtStatus = RT_STATUS_SUCCESS; + + // + // Config MAC + // +#if RTL8190_Download_Firmware_From_Header + rtStatus = phy_ConfigMACWithHeaderFile(dev); +#else + // Not make sure EEPROM, add later + RT_TRACE(COMP_INIT, "Read MACREG.txt\n"); + //rtStatus = phy_ConfigMACWithParaFile(dev, RTL819X_PHY_MACREG);// lzm del it temp +#endif + return (rtStatus == RT_STATUS_SUCCESS) ? true:false; + +} + +//adapter_start +extern bool +PHY_BBConfig8192S(struct net_device* dev) +{ + RT_STATUS rtStatus = RT_STATUS_SUCCESS; + + u8 PathMap = 0, index = 0, rf_num = 0; + struct r8192_priv *priv = ieee80211_priv(dev); + phy_InitBBRFRegisterDefinition(dev); + + // + // Config BB and AGC + // + //switch( Adapter->MgntInfo.bRegHwParaFile ) + //{ + // case 0: + // phy_BB8190_Config_HardCode(dev); + // break; + + // case 1: + rtStatus = phy_BB8192S_Config_ParaFile(dev); + // break; + + // case 2: + // Partial Modify. + // phy_BB8190_Config_HardCode(dev); + // phy_BB8192S_Config_ParaFile(dev); + // break; + + // default: + // phy_BB8190_Config_HardCode(dev); + // break; + //} + PathMap = (u8)(rtl8192_QueryBBReg(dev, rFPGA0_TxInfo, 0xf) | + rtl8192_QueryBBReg(dev, rOFDM0_TRxPathEnable, 0xf)); + priv->rf_pathmap = PathMap; + for(index = 0; index<4; index++) + { + if((PathMap>>index)&0x1) + rf_num++; + } + + if((priv->rf_type==RF_1T1R && rf_num!=1) || + (priv->rf_type==RF_1T2R && rf_num!=2) || + (priv->rf_type==RF_2T2R && rf_num!=2) || + (priv->rf_type==RF_2T2R_GREEN && rf_num!=2) || + (priv->rf_type==RF_2T4R && rf_num!=4)) + { + RT_TRACE( COMP_INIT, "PHY_BBConfig8192S: RF_Type(%x) does not match RF_Num(%x)!!\n", priv->rf_type, rf_num); + } + return (rtStatus == RT_STATUS_SUCCESS) ? 1:0; +} + +//adapter_start +extern bool +PHY_RFConfig8192S(struct net_device* dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + RT_STATUS rtStatus = RT_STATUS_SUCCESS; + + //Set priv->rf_chip = RF_8225 to do real PHY FPGA initilization + + // We assign RF type here temporally. 2008.09.12. + priv->rf_chip = RF_6052; + + // + // RF config + // + switch(priv->rf_chip) + { + case RF_8225: + case RF_6052: + rtStatus = PHY_RF6052_Config(dev); + break; + + case RF_8256: + //rtStatus = PHY_RF8256_Config(dev); + break; + + case RF_8258: + break; + + case RF_PSEUDO_11N: + //rtStatus = PHY_RF8225_Config(dev); + break; + default: + break; + } + + return (rtStatus == RT_STATUS_SUCCESS) ? 1:0; +} + + +// Joseph test: new initialize order!! +// Test only!! This part need to be re-organized. +// Now it is just for 8256. +//use in phy only +#ifdef TO_DO_LIST +static RT_STATUS +phy_BB8190_Config_HardCode(struct net_device* dev) +{ + //RT_ASSERT(FALSE, ("This function is not implement yet!! \n")); + return RT_STATUS_SUCCESS; +} +#endif + +/*----------------------------------------------------------------------------- + * Function: phy_SetBBtoDiffRFWithHeaderFile() + * + * Overview: This function + * + * + * Input: PADAPTER Adapter + * u1Byte ConfigType 0 => PHY_CONFIG + * + * Output: NONE + * + * Return: RT_STATUS_SUCCESS: configuration file exist + * When Who Remark + * 2008/11/10 tynli + * use in phy only + *---------------------------------------------------------------------------*/ +static RT_STATUS +phy_SetBBtoDiffRFWithHeaderFile(struct net_device* dev, u8 ConfigType) +{ + int i; + struct r8192_priv *priv = ieee80211_priv(dev); + u32* Rtl819XPHY_REGArraytoXTXR_Table; + u16 PHY_REGArraytoXTXRLen; + +//#if (HAL_CODE_BASE != RTL8192_S) + + if(priv->rf_type == RF_1T1R) + { + Rtl819XPHY_REGArraytoXTXR_Table = Rtl819XPHY_REG_to1T1R_Array; + PHY_REGArraytoXTXRLen = PHY_ChangeTo_1T1RArrayLength; + } + else if(priv->rf_type == RF_1T2R) + { + Rtl819XPHY_REGArraytoXTXR_Table = Rtl819XPHY_REG_to1T2R_Array; + PHY_REGArraytoXTXRLen = PHY_ChangeTo_1T2RArrayLength; + } + //else if(priv->rf_type == RF_2T2R || priv->rf_type == RF_2T2R_GREEN) + //{ + // Rtl819XPHY_REGArraytoXTXR_Table = Rtl819XPHY_REG_to2T2R_Array; + // PHY_REGArraytoXTXRLen = PHY_ChangeTo_2T2RArrayLength; + //} + else + { + return RT_STATUS_FAILURE; + } + + if(ConfigType == BaseBand_Config_PHY_REG) + { + for(i=0;iphy_BB8192S_Config_ParaFile\n"); + + // + // 1. Read PHY_REG.TXT BB INIT!! + // We will seperate as 1T1R/1T2R/1T2R_GREEN/2T2R + // +#if RTL8190_Download_Firmware_From_Header + if (priv->rf_type == RF_1T2R || priv->rf_type == RF_2T2R || + priv->rf_type == RF_1T1R ||priv->rf_type == RF_2T2R_GREEN) + { + rtStatus = phy_ConfigBBWithHeaderFile(dev,BaseBand_Config_PHY_REG); + if(priv->rf_type != RF_2T2R && priv->rf_type != RF_2T2R_GREEN) + {//2008.11.10 Added by tynli. The default PHY_REG.txt we read is for 2T2R, + //so we should reconfig BB reg with the right PHY parameters. + rtStatus = phy_SetBBtoDiffRFWithHeaderFile(dev,BaseBand_Config_PHY_REG); + } + }else + rtStatus = RT_STATUS_FAILURE; +#else + RT_TRACE(COMP_INIT, "RF_Type == %d\n", priv->rf_type); + // No matter what kind of RF we always read PHY_REG.txt. We must copy different + // type of parameter files to phy_reg.txt at first. + if (priv->rf_type == RF_1T2R || priv->rf_type == RF_2T2R || + priv->rf_type == RF_1T1R ||priv->rf_type == RF_2T2R_GREEN) + { + rtStatus = phy_ConfigBBWithParaFile(dev, (char* )&szBBRegFile); + if(priv->rf_type != RF_2T2R && priv->rf_type != RF_2T2R_GREEN) + {//2008.11.10 Added by tynli. The default PHY_REG.txt we read is for 2T2R, + //so we should reconfig BB reg with the right PHY parameters. + if(priv->rf_type == RF_1T1R) + rtStatus = phy_SetBBtoDiffRFWithParaFile(dev, (char* )&szBBRegto1T1RFile); + else if(priv->rf_type == RF_1T2R) + rtStatus = phy_SetBBtoDiffRFWithParaFile(dev, (char* )&szBBRegto1T2RFile); + } + + }else + rtStatus = RT_STATUS_FAILURE; +#endif + + if(rtStatus != RT_STATUS_SUCCESS){ + RT_TRACE(COMP_INIT, "phy_BB8192S_Config_ParaFile():Write BB Reg Fail!!"); + goto phy_BB8190_Config_ParaFile_Fail; + } + + // + // 2. If EEPROM or EFUSE autoload OK, We must config by PHY_REG_PG.txt + // + if (priv->AutoloadFailFlag == false) + { +#if RTL8190_Download_Firmware_From_Header + rtStatus = phy_ConfigBBWithPgHeaderFile(dev,BaseBand_Config_PHY_REG); +#else + rtStatus = phy_ConfigBBWithPgParaFile(dev, (char* )&szBBRegPgFile); +#endif + } + if(rtStatus != RT_STATUS_SUCCESS){ + RT_TRACE(COMP_INIT, "phy_BB8192S_Config_ParaFile():BB_PG Reg Fail!!"); + goto phy_BB8190_Config_ParaFile_Fail; + } + + // + // 3. BB AGC table Initialization + // +#if RTL8190_Download_Firmware_From_Header + rtStatus = phy_ConfigBBWithHeaderFile(dev,BaseBand_Config_AGC_TAB); +#else + RT_TRACE(COMP_INIT, "phy_BB8192S_Config_ParaFile AGC_TAB.txt\n"); + rtStatus = phy_ConfigBBWithParaFile(Adapter, (char* )&szAGCTableFile); +#endif + + if(rtStatus != RT_STATUS_SUCCESS){ + printk( "phy_BB8192S_Config_ParaFile():AGC Table Fail\n"); + goto phy_BB8190_Config_ParaFile_Fail; + } + + +#if 0 // 2008/08/18 MH Disable for 92SE + if(pHalData->VersionID > VERSION_8190_BD) + { + //if(pHalData->RF_Type == RF_2T4R) + //{ + // Antenna gain offset from B/C/D to A + u4RegValue = ( pHalData->AntennaTxPwDiff[2]<<8 | + pHalData->AntennaTxPwDiff[1]<<4 | + pHalData->AntennaTxPwDiff[0]); + //} + //else + //u4RegValue = 0; + + PHY_SetBBReg(dev, rFPGA0_TxGainStage, + (bXBTxAGC|bXCTxAGC|bXDTxAGC), u4RegValue); + + // CrystalCap + // Simulate 8192??? + u4RegValue = pHalData->CrystalCap; + PHY_SetBBReg(dev, rFPGA0_AnalogParameter1, bXtalCap92x, u4RegValue); + // Simulate 8190?? + //u4RegValue = ((pHalData->CrystalCap & 0xc)>>2); // bit2~3 of crystal cap + //PHY_SetBBReg(Adapter, rFPGA0_AnalogParameter2, bXtalCap23, u4RegValue); + + } +#endif + + // Check if the CCK HighPower is turned ON. + // This is used to calculate PWDB. + priv->bCckHighPower = (bool)(rtl8192_QueryBBReg(dev, rFPGA0_XA_HSSIParameter2, 0x200)); + + +phy_BB8190_Config_ParaFile_Fail: + return rtStatus; +} + +/*----------------------------------------------------------------------------- + * Function: phy_ConfigMACWithHeaderFile() + * + * Overview: This function read BB parameters from Header file we gen, and do register + * Read/Write + * + * Input: PADAPTER Adapter + * char* pFileName + * + * Output: NONE + * + * Return: RT_STATUS_SUCCESS: configuration file exist + * + * Note: The format of MACPHY_REG.txt is different from PHY and RF. + * [Register][Mask][Value] + *---------------------------------------------------------------------------*/ +//use in phy only +static RT_STATUS +phy_ConfigMACWithHeaderFile(struct net_device* dev) +{ + u32 i = 0; + u32 ArrayLength = 0; + u32* ptrArray; + //struct r8192_priv *priv = ieee80211_priv(dev); + +//#if (HAL_CODE_BASE != RTL8192_S) + /*if(Adapter->bInHctTest) + { + RT_TRACE(COMP_INIT, DBG_LOUD, ("Rtl819XMACPHY_ArrayDTM\n")); + ArrayLength = MACPHY_ArrayLengthDTM; + ptrArray = Rtl819XMACPHY_ArrayDTM; + } + else if(pHalData->bTXPowerDataReadFromEEPORM) + { +// RT_TRACE(COMP_INIT, DBG_LOUD, ("Rtl819XMACPHY_Array_PG\n")); +// ArrayLength = MACPHY_Array_PGLength; +// ptrArray = Rtl819XMACPHY_Array_PG; + + }else*/ + { //2008.11.06 Modified by tynli. + RT_TRACE(COMP_INIT, "Read Rtl819XMACPHY_Array\n"); + ArrayLength = MAC_2T_ArrayLength; + ptrArray = Rtl819XMAC_Array; + } + + /*for(i = 0 ;i < ArrayLength;i=i+3){ + RT_TRACE(COMP_SEND, DBG_LOUD, ("The Rtl819XMACPHY_Array[0] is %lx Rtl819XMACPHY_Array[1] is %lx Rtl819XMACPHY_Array[2] is %lx\n",ptrArray[i], ptrArray[i+1], ptrArray[i+2])); + if(ptrArray[i] == 0x318) + { + ptrArray[i+2] = 0x00000800; + //DbgPrint("ptrArray[i], ptrArray[i+1], ptrArray[i+2] = %x, %x, %x\n", + // ptrArray[i], ptrArray[i+1], ptrArray[i+2]); + } + PHY_SetBBReg(Adapter, ptrArray[i], ptrArray[i+1], ptrArray[i+2]); + }*/ + for(i = 0 ;i < ArrayLength;i=i+2){ // Add by tynli for 2 column + write_nic_byte(dev, ptrArray[i], (u8)ptrArray[i+1]); + } +//#endif + return RT_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------- + * Function: phy_ConfigBBWithHeaderFile() + * + * Overview: This function read BB parameters from general file format, and do register + * Read/Write + * + * Input: PADAPTER Adapter + * u8 ConfigType 0 => PHY_CONFIG + * 1 =>AGC_TAB + * + * Output: NONE + * + * Return: RT_STATUS_SUCCESS: configuration file exist + * + *---------------------------------------------------------------------------*/ +//use in phy only +static RT_STATUS +phy_ConfigBBWithHeaderFile(struct net_device* dev,u8 ConfigType) +{ + int i; + //u8 ArrayLength; + u32* Rtl819XPHY_REGArray_Table; + u32* Rtl819XAGCTAB_Array_Table; + u16 PHY_REGArrayLen, AGCTAB_ArrayLen; + //struct r8192_priv *priv = ieee80211_priv(dev); +//#if (HAL_CODE_BASE != RTL8192_S) + /*if(Adapter->bInHctTest) + { + + AGCTAB_ArrayLen = AGCTAB_ArrayLengthDTM; + Rtl819XAGCTAB_Array_Table = Rtl819XAGCTAB_ArrayDTM; + + if(pHalData->RF_Type == RF_2T4R) + { + PHY_REGArrayLen = PHY_REGArrayLengthDTM; + Rtl819XPHY_REGArray_Table = Rtl819XPHY_REGArrayDTM; + } + else if (pHalData->RF_Type == RF_1T2R) + { + PHY_REGArrayLen = PHY_REG_1T2RArrayLengthDTM; + Rtl819XPHY_REGArray_Table = Rtl819XPHY_REG_1T2RArrayDTM; + } + + } + else + */ + //{ + // + // 2008.11.06 Modified by tynli. + // + AGCTAB_ArrayLen = AGCTAB_ArrayLength; + Rtl819XAGCTAB_Array_Table = Rtl819XAGCTAB_Array; + PHY_REGArrayLen = PHY_REG_2T2RArrayLength; // Default RF_type: 2T2R + Rtl819XPHY_REGArray_Table = Rtl819XPHY_REG_Array; + //} + + if(ConfigType == BaseBand_Config_PHY_REG) + { + for(i=0;iRF_Type = RF_2T2R. + + PHY_REGArrayPGLen = PHY_REG_Array_PGLength; + Rtl819XPHY_REGArray_Table_PG = Rtl819XPHY_REG_Array_PG; + + if(ConfigType == BaseBand_Config_PHY_REG) + { + for(i=0;irf_type == RF_2T2R_GREEN ) + { + Rtl819XRadioB_Array_Table = Rtl819XRadioB_GM_Array; + RadioB_ArrayLen = RadioB_GM_ArrayLength; + } + else + { + Rtl819XRadioB_Array_Table = Rtl819XRadioB_Array; + RadioB_ArrayLen = RadioB_ArrayLength; + } + + rtStatus = RT_STATUS_SUCCESS; + + // When initialization, we want the delay function(mdelay(), delay_us() + // ==> actually we call PlatformStallExecution()) to do NdisStallExecution() + // [busy wait] instead of NdisMSleep(). So we acquire RT_INITIAL_SPINLOCK + // to run at Dispatch level to achive it. + //cosa PlatformAcquireSpinLock(Adapter, RT_INITIAL_SPINLOCK); + + switch(eRFPath){ + case RF90_PATH_A: + for(i = 0;i actually we call PlatformStallExecution()) to do NdisStallExecution() + // [busy wait] instead of NdisMSleep(). So we acquire RT_INITIAL_SPINLOCK + // to run at Dispatch level to achive it. + //cosa PlatformAcquireSpinLock(dev, RT_INITIAL_SPINLOCK); + WriteData[i] &= 0xfff; + rtl8192_phy_SetRFReg(dev, eRFPath, WriteAddr[HW90_BLOCK_RF], bRFRegOffsetMask, WriteData[i]); + // TODO: we should not delay for such a long time. Ask SD3 + mdelay(10); + ulRegRead = rtl8192_phy_QueryRFReg(dev, eRFPath, WriteAddr[HW90_BLOCK_RF], bMaskDWord); + mdelay(10); + //cosa PlatformReleaseSpinLock(dev, RT_INITIAL_SPINLOCK); + break; + + default: + rtStatus = RT_STATUS_FAILURE; + break; + } + + + // + // Check whether readback data is correct + // + if(ulRegRead != WriteData[i]) + { + //RT_TRACE(COMP_FPGA, ("ulRegRead: %x, WriteData: %x \n", ulRegRead, WriteData[i])); + RT_TRACE(COMP_ERR, "read back error(read:%x, write:%x)\n", ulRegRead, WriteData[i]); + rtStatus = RT_STATUS_FAILURE; + break; + } + } + + return rtStatus; +} + +//no use temp in windows driver +#ifdef TO_DO_LIST +void +PHY_SetRFPowerState8192SUsb( + struct net_device* dev, + RF_POWER_STATE RFPowerState + ) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + bool WaitShutDown = FALSE; + u32 DWordContent; + //RF90_RADIO_PATH_E eRFPath; + u8 eRFPath; + BB_REGISTER_DEFINITION_T *pPhyReg; + + if(priv->SetRFPowerStateInProgress == TRUE) + return; + + priv->SetRFPowerStateInProgress = TRUE; + + // TODO: Emily, 2006.11.21, we should rewrite this function + + if(RFPowerState==RF_SHUT_DOWN) + { + RFPowerState=RF_OFF; + WaitShutDown=TRUE; + } + + + priv->RFPowerState = RFPowerState; + switch( priv->rf_chip ) + { + case RF_8225: + case RF_6052: + switch( RFPowerState ) + { + case RF_ON: + break; + + case RF_SLEEP: + break; + + case RF_OFF: + break; + } + break; + + case RF_8256: + switch( RFPowerState ) + { + case RF_ON: + break; + + case RF_SLEEP: + break; + + case RF_OFF: + for(eRFPath=(RF90_RADIO_PATH_E)RF90_PATH_A; eRFPath < RF90_PATH_MAX; eRFPath++) + { + if (!rtl8192_phy_CheckIsLegalRFPath(dev, eRFPath)) + continue; + + pPhyReg = &priv->PHYRegDef[eRFPath]; + rtl8192_setBBreg(dev, pPhyReg->rfintfs, bRFSI_RFENV, bRFSI_RFENV); + rtl8192_setBBreg(dev, pPhyReg->rfintfo, bRFSI_RFENV, 0); + } + break; + } + break; + + case RF_8258: + break; + }// switch( priv->rf_chip ) + + priv->SetRFPowerStateInProgress = FALSE; +} +#endif + +#ifdef RTL8192U +//no use temp in windows driver +void +PHY_UpdateInitialGain( + struct net_device* dev + ) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + //unsigned char *IGTable; + //u8 DIG_CurrentInitialGain = 4; + + switch(priv->rf_chip) + { + case RF_8225: + break; + case RF_8256: + break; + case RF_8258: + break; + case RF_PSEUDO_11N: + break; + case RF_6052: + break; + default: + RT_TRACE(COMP_DBG, "PHY_UpdateInitialGain(): unknown rf_chip: %#X\n", priv->rf_chip); + break; + } +} +#endif + +//YJ,modified,090107 +void PHY_GetHWRegOriginalValue(struct net_device* dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + + // read tx power offset + // Simulate 8192 + priv->MCSTxPowerLevelOriginalOffset[0] = + rtl8192_QueryBBReg(dev, rTxAGC_Rate18_06, bMaskDWord); + priv->MCSTxPowerLevelOriginalOffset[1] = + rtl8192_QueryBBReg(dev, rTxAGC_Rate54_24, bMaskDWord); + priv->MCSTxPowerLevelOriginalOffset[2] = + rtl8192_QueryBBReg(dev, rTxAGC_Mcs03_Mcs00, bMaskDWord); + priv->MCSTxPowerLevelOriginalOffset[3] = + rtl8192_QueryBBReg(dev, rTxAGC_Mcs07_Mcs04, bMaskDWord); + priv->MCSTxPowerLevelOriginalOffset[4] = + rtl8192_QueryBBReg(dev, rTxAGC_Mcs11_Mcs08, bMaskDWord); + priv->MCSTxPowerLevelOriginalOffset[5] = + rtl8192_QueryBBReg(dev, rTxAGC_Mcs15_Mcs12, bMaskDWord); + + // Read CCK offset + priv->MCSTxPowerLevelOriginalOffset[6] = + rtl8192_QueryBBReg(dev, rTxAGC_CCK_Mcs32, bMaskDWord); + RT_TRACE(COMP_INIT, "Legacy OFDM =%08x/%08x HT_OFDM=%08x/%08x/%08x/%08x\n", + priv->MCSTxPowerLevelOriginalOffset[0], priv->MCSTxPowerLevelOriginalOffset[1] , + priv->MCSTxPowerLevelOriginalOffset[2], priv->MCSTxPowerLevelOriginalOffset[3] , + priv->MCSTxPowerLevelOriginalOffset[4], priv->MCSTxPowerLevelOriginalOffset[5] ); + + // read rx initial gain + priv->DefaultInitialGain[0] = rtl8192_QueryBBReg(dev, rOFDM0_XAAGCCore1, bMaskByte0); + priv->DefaultInitialGain[1] = rtl8192_QueryBBReg(dev, rOFDM0_XBAGCCore1, bMaskByte0); + priv->DefaultInitialGain[2] = rtl8192_QueryBBReg(dev, rOFDM0_XCAGCCore1, bMaskByte0); + priv->DefaultInitialGain[3] = rtl8192_QueryBBReg(dev, rOFDM0_XDAGCCore1, bMaskByte0); + RT_TRACE(COMP_INIT, "Default initial gain (c50=0x%x, c58=0x%x, c60=0x%x, c68=0x%x) \n", + priv->DefaultInitialGain[0], priv->DefaultInitialGain[1], + priv->DefaultInitialGain[2], priv->DefaultInitialGain[3]); + + // read framesync + priv->framesync = rtl8192_QueryBBReg(dev, rOFDM0_RxDetector3, bMaskByte0); + priv->framesyncC34 = rtl8192_QueryBBReg(dev, rOFDM0_RxDetector2, bMaskDWord); + RT_TRACE(COMP_INIT, "Default framesync (0x%x) = 0x%x \n", + rOFDM0_RxDetector3, priv->framesync); +} +//YJ,modified,090107,end + + + +/** +* Function: phy_InitBBRFRegisterDefinition +* +* OverView: Initialize Register definition offset for Radio Path A/B/C/D +* +* Input: +* PADAPTER Adapter, +* +* Output: None +* Return: None +* Note: The initialization value is constant and it should never be changes +*/ +//use in phy only +static void phy_InitBBRFRegisterDefinition( struct net_device* dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + + // RF Interface Sowrtware Control + priv->PHYRegDef[RF90_PATH_A].rfintfs = rFPGA0_XAB_RFInterfaceSW; // 16 LSBs if read 32-bit from 0x870 + priv->PHYRegDef[RF90_PATH_B].rfintfs = rFPGA0_XAB_RFInterfaceSW; // 16 MSBs if read 32-bit from 0x870 (16-bit for 0x872) + priv->PHYRegDef[RF90_PATH_C].rfintfs = rFPGA0_XCD_RFInterfaceSW;// 16 LSBs if read 32-bit from 0x874 + priv->PHYRegDef[RF90_PATH_D].rfintfs = rFPGA0_XCD_RFInterfaceSW;// 16 MSBs if read 32-bit from 0x874 (16-bit for 0x876) + + // RF Interface Readback Value + priv->PHYRegDef[RF90_PATH_A].rfintfi = rFPGA0_XAB_RFInterfaceRB; // 16 LSBs if read 32-bit from 0x8E0 + priv->PHYRegDef[RF90_PATH_B].rfintfi = rFPGA0_XAB_RFInterfaceRB;// 16 MSBs if read 32-bit from 0x8E0 (16-bit for 0x8E2) + priv->PHYRegDef[RF90_PATH_C].rfintfi = rFPGA0_XCD_RFInterfaceRB;// 16 LSBs if read 32-bit from 0x8E4 + priv->PHYRegDef[RF90_PATH_D].rfintfi = rFPGA0_XCD_RFInterfaceRB;// 16 MSBs if read 32-bit from 0x8E4 (16-bit for 0x8E6) + + // RF Interface Output (and Enable) + priv->PHYRegDef[RF90_PATH_A].rfintfo = rFPGA0_XA_RFInterfaceOE; // 16 LSBs if read 32-bit from 0x860 + priv->PHYRegDef[RF90_PATH_B].rfintfo = rFPGA0_XB_RFInterfaceOE; // 16 LSBs if read 32-bit from 0x864 + priv->PHYRegDef[RF90_PATH_C].rfintfo = rFPGA0_XC_RFInterfaceOE;// 16 LSBs if read 32-bit from 0x868 + priv->PHYRegDef[RF90_PATH_D].rfintfo = rFPGA0_XD_RFInterfaceOE;// 16 LSBs if read 32-bit from 0x86C + + // RF Interface (Output and) Enable + priv->PHYRegDef[RF90_PATH_A].rfintfe = rFPGA0_XA_RFInterfaceOE; // 16 MSBs if read 32-bit from 0x860 (16-bit for 0x862) + priv->PHYRegDef[RF90_PATH_B].rfintfe = rFPGA0_XB_RFInterfaceOE; // 16 MSBs if read 32-bit from 0x864 (16-bit for 0x866) + priv->PHYRegDef[RF90_PATH_C].rfintfe = rFPGA0_XC_RFInterfaceOE;// 16 MSBs if read 32-bit from 0x86A (16-bit for 0x86A) + priv->PHYRegDef[RF90_PATH_D].rfintfe = rFPGA0_XD_RFInterfaceOE;// 16 MSBs if read 32-bit from 0x86C (16-bit for 0x86E) + + //Addr of LSSI. Wirte RF register by driver + priv->PHYRegDef[RF90_PATH_A].rf3wireOffset = rFPGA0_XA_LSSIParameter; //LSSI Parameter + priv->PHYRegDef[RF90_PATH_B].rf3wireOffset = rFPGA0_XB_LSSIParameter; + priv->PHYRegDef[RF90_PATH_C].rf3wireOffset = rFPGA0_XC_LSSIParameter; + priv->PHYRegDef[RF90_PATH_D].rf3wireOffset = rFPGA0_XD_LSSIParameter; + + // RF parameter + priv->PHYRegDef[RF90_PATH_A].rfLSSI_Select = rFPGA0_XAB_RFParameter; //BB Band Select + priv->PHYRegDef[RF90_PATH_B].rfLSSI_Select = rFPGA0_XAB_RFParameter; + priv->PHYRegDef[RF90_PATH_C].rfLSSI_Select = rFPGA0_XCD_RFParameter; + priv->PHYRegDef[RF90_PATH_D].rfLSSI_Select = rFPGA0_XCD_RFParameter; + + // Tx AGC Gain Stage (same for all path. Should we remove this?) + priv->PHYRegDef[RF90_PATH_A].rfTxGainStage = rFPGA0_TxGainStage; //Tx gain stage + priv->PHYRegDef[RF90_PATH_B].rfTxGainStage = rFPGA0_TxGainStage; //Tx gain stage + priv->PHYRegDef[RF90_PATH_C].rfTxGainStage = rFPGA0_TxGainStage; //Tx gain stage + priv->PHYRegDef[RF90_PATH_D].rfTxGainStage = rFPGA0_TxGainStage; //Tx gain stage + + // Tranceiver A~D HSSI Parameter-1 + priv->PHYRegDef[RF90_PATH_A].rfHSSIPara1 = rFPGA0_XA_HSSIParameter1; //wire control parameter1 + priv->PHYRegDef[RF90_PATH_B].rfHSSIPara1 = rFPGA0_XB_HSSIParameter1; //wire control parameter1 + priv->PHYRegDef[RF90_PATH_C].rfHSSIPara1 = rFPGA0_XC_HSSIParameter1; //wire control parameter1 + priv->PHYRegDef[RF90_PATH_D].rfHSSIPara1 = rFPGA0_XD_HSSIParameter1; //wire control parameter1 + + // Tranceiver A~D HSSI Parameter-2 + priv->PHYRegDef[RF90_PATH_A].rfHSSIPara2 = rFPGA0_XA_HSSIParameter2; //wire control parameter2 + priv->PHYRegDef[RF90_PATH_B].rfHSSIPara2 = rFPGA0_XB_HSSIParameter2; //wire control parameter2 + priv->PHYRegDef[RF90_PATH_C].rfHSSIPara2 = rFPGA0_XC_HSSIParameter2; //wire control parameter2 + priv->PHYRegDef[RF90_PATH_D].rfHSSIPara2 = rFPGA0_XD_HSSIParameter2; //wire control parameter1 + + // RF switch Control + priv->PHYRegDef[RF90_PATH_A].rfSwitchControl = rFPGA0_XAB_SwitchControl; //TR/Ant switch control + priv->PHYRegDef[RF90_PATH_B].rfSwitchControl = rFPGA0_XAB_SwitchControl; + priv->PHYRegDef[RF90_PATH_C].rfSwitchControl = rFPGA0_XCD_SwitchControl; + priv->PHYRegDef[RF90_PATH_D].rfSwitchControl = rFPGA0_XCD_SwitchControl; + + // AGC control 1 + priv->PHYRegDef[RF90_PATH_A].rfAGCControl1 = rOFDM0_XAAGCCore1; + priv->PHYRegDef[RF90_PATH_B].rfAGCControl1 = rOFDM0_XBAGCCore1; + priv->PHYRegDef[RF90_PATH_C].rfAGCControl1 = rOFDM0_XCAGCCore1; + priv->PHYRegDef[RF90_PATH_D].rfAGCControl1 = rOFDM0_XDAGCCore1; + + // AGC control 2 + priv->PHYRegDef[RF90_PATH_A].rfAGCControl2 = rOFDM0_XAAGCCore2; + priv->PHYRegDef[RF90_PATH_B].rfAGCControl2 = rOFDM0_XBAGCCore2; + priv->PHYRegDef[RF90_PATH_C].rfAGCControl2 = rOFDM0_XCAGCCore2; + priv->PHYRegDef[RF90_PATH_D].rfAGCControl2 = rOFDM0_XDAGCCore2; + + // RX AFE control 1 + priv->PHYRegDef[RF90_PATH_A].rfRxIQImbalance = rOFDM0_XARxIQImbalance; + priv->PHYRegDef[RF90_PATH_B].rfRxIQImbalance = rOFDM0_XBRxIQImbalance; + priv->PHYRegDef[RF90_PATH_C].rfRxIQImbalance = rOFDM0_XCRxIQImbalance; + priv->PHYRegDef[RF90_PATH_D].rfRxIQImbalance = rOFDM0_XDRxIQImbalance; + + // RX AFE control 1 + priv->PHYRegDef[RF90_PATH_A].rfRxAFE = rOFDM0_XARxAFE; + priv->PHYRegDef[RF90_PATH_B].rfRxAFE = rOFDM0_XBRxAFE; + priv->PHYRegDef[RF90_PATH_C].rfRxAFE = rOFDM0_XCRxAFE; + priv->PHYRegDef[RF90_PATH_D].rfRxAFE = rOFDM0_XDRxAFE; + + // Tx AFE control 1 + priv->PHYRegDef[RF90_PATH_A].rfTxIQImbalance = rOFDM0_XATxIQImbalance; + priv->PHYRegDef[RF90_PATH_B].rfTxIQImbalance = rOFDM0_XBTxIQImbalance; + priv->PHYRegDef[RF90_PATH_C].rfTxIQImbalance = rOFDM0_XCTxIQImbalance; + priv->PHYRegDef[RF90_PATH_D].rfTxIQImbalance = rOFDM0_XDTxIQImbalance; + + // Tx AFE control 2 + priv->PHYRegDef[RF90_PATH_A].rfTxAFE = rOFDM0_XATxAFE; + priv->PHYRegDef[RF90_PATH_B].rfTxAFE = rOFDM0_XBTxAFE; + priv->PHYRegDef[RF90_PATH_C].rfTxAFE = rOFDM0_XCTxAFE; + priv->PHYRegDef[RF90_PATH_D].rfTxAFE = rOFDM0_XDTxAFE; + + // Tranceiver LSSI Readback SI mode + priv->PHYRegDef[RF90_PATH_A].rfLSSIReadBack = rFPGA0_XA_LSSIReadBack; + priv->PHYRegDef[RF90_PATH_B].rfLSSIReadBack = rFPGA0_XB_LSSIReadBack; + priv->PHYRegDef[RF90_PATH_C].rfLSSIReadBack = rFPGA0_XC_LSSIReadBack; + priv->PHYRegDef[RF90_PATH_D].rfLSSIReadBack = rFPGA0_XD_LSSIReadBack; + + // Tranceiver LSSI Readback PI mode + priv->PHYRegDef[RF90_PATH_A].rfLSSIReadBackPi = TransceiverA_HSPI_Readback; + priv->PHYRegDef[RF90_PATH_B].rfLSSIReadBackPi = TransceiverB_HSPI_Readback; + //pHalData->PHYRegDef[RF90_PATH_C].rfLSSIReadBackPi = rFPGA0_XC_LSSIReadBack; + //pHalData->PHYRegDef[RF90_PATH_D].rfLSSIReadBackPi = rFPGA0_XD_LSSIReadBack; + +} + + +// +// Description: Change RF power state. +// +// Assumption: This function must be executed in re-schdulable context, +// ie. PASSIVE_LEVEL. +// +// 050823, by rcnjko. +//not understand it seem's use in init +//SetHwReg8192SUsb--->HalFunc.SetHwRegHandler +bool PHY_SetRFPowerState(struct net_device* dev, RT_RF_POWER_STATE eRFPowerState) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + bool bResult = FALSE; + + RT_TRACE(COMP_RF, "---------> PHY_SetRFPowerState(): eRFPowerState(%d)\n", eRFPowerState); + + if(eRFPowerState == priv->ieee80211->eRFPowerState) + { + RT_TRACE(COMP_RF, "<--------- PHY_SetRFPowerState(): discard the request for eRFPowerState(%d) is the same.\n", eRFPowerState); + return bResult; + } + + bResult = phy_SetRFPowerState8192SU(dev, eRFPowerState); + + RT_TRACE(COMP_RF, "<--------- PHY_SetRFPowerState(): bResult(%d)\n", bResult); + + return bResult; +} + +//use in phy only +static bool phy_SetRFPowerState8192SU(struct net_device* dev,RT_RF_POWER_STATE eRFPowerState) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + bool bResult = TRUE; + //u8 eRFPath; + //u8 i, QueueID; + u8 u1bTmp; + + if(priv->SetRFPowerStateInProgress == TRUE) + return FALSE; + + priv->SetRFPowerStateInProgress = TRUE; + + switch(priv->rf_chip ) + { + default: + switch( eRFPowerState ) + { + case eRfOn: + write_nic_dword(dev, WFM5, FW_BB_RESET_ENABLE); + write_nic_word(dev, CMDR, 0x37FC); + write_nic_byte(dev, PHY_CCA, 0x3); + write_nic_byte(dev, TXPAUSE, 0x00); + write_nic_byte(dev, SPS1_CTRL, 0x64); + break; + + // + // In current solution, RFSleep=RFOff in order to save power under 802.11 power save. + // By Bruce, 2008-01-16. + // + case eRfSleep: + case eRfOff: + if (priv->ieee80211->eRFPowerState == eRfSleep || priv->ieee80211->eRFPowerState == eRfOff) + break; +#ifdef NOT_YET + // Make sure BusyQueue is empty befor turn off RFE pwoer. + for(QueueID = 0, i = 0; QueueID < MAX_TX_QUEUE; ) + { + if(RTIsListEmpty(&Adapter->TcbBusyQueue[QueueID])) + { + QueueID++; + continue; + } + else + { + RT_TRACE(COMP_POWER, "eRf Off/Sleep: %d times TcbBusyQueue[%d] !=0 before doze!\n", (i+1), QueueID); + udelay(10); + i++; + } + + if(i >= MAX_DOZE_WAITING_TIMES_9x) + { + RT_TRACE(COMP_POWER, "\n\n\n SetZebraRFPowerState8185B(): eRfOff: %d times TcbBusyQueue[%d] != 0 !!!\n\n\n", MAX_DOZE_WAITING_TIMES_9x, QueueID); + break; + } + } +#endif + // + //RF Off/Sleep sequence. Designed/tested from SD4 Scott, SD1 Grent and Jonbon. + // Added by Bruce, 2008-11-22. + // + //================================================================== + // (0) Disable FW BB reset checking + write_nic_dword(dev, WFM5, FW_BB_RESET_DISABLE); + + // (1) Switching Power Supply Register : Disable LD12 & SW12 (for IT) + u1bTmp = read_nic_byte(dev, LDOV12D_CTRL); + u1bTmp |= BIT0; + write_nic_byte(dev, LDOV12D_CTRL, u1bTmp); + + write_nic_byte(dev, SPS1_CTRL, 0x0); + write_nic_byte(dev, TXPAUSE, 0xFF); + + // (2) MAC Tx/Rx enable, BB enable, CCK/OFDM enable + write_nic_word(dev, CMDR, 0x77FC); + write_nic_byte(dev, PHY_CCA, 0x0); + udelay(100); + + write_nic_word(dev, CMDR, 0x37FC); + udelay(10); + + write_nic_word(dev, CMDR, 0x77FC); + udelay(10); + + // (3) Reset BB TRX blocks + write_nic_word(dev, CMDR, 0x57FC); + break; + + default: + bResult = FALSE; + //RT_ASSERT(FALSE, ("phy_SetRFPowerState8192SU(): unknow state to set: 0x%X!!!\n", eRFPowerState)); + break; + } + break; + + } + priv->ieee80211->eRFPowerState = eRFPowerState; +#ifdef TO_DO_LIST + if(bResult) + { + // Update current RF state variable. + priv->ieee80211->eRFPowerState = eRFPowerState; + + switch(priv->rf_chip ) + { + case RF_8256: + switch(priv->ieee80211->eRFPowerState) + { + case eRfOff: + // + //If Rf off reason is from IPS, Led should blink with no link, by Maddest 071015 + // + if(pMgntInfo->RfOffReason==RF_CHANGE_BY_IPS ) + { + dev->HalFunc.LedControlHandler(dev,LED_CTL_NO_LINK); + } + else + { + // Turn off LED if RF is not ON. + dev->HalFunc.LedControlHandler(dev, LED_CTL_POWER_OFF); + } + break; + + case eRfOn: + // Turn on RF we are still linked, which might happen when + // we quickly turn off and on HW RF. 2006.05.12, by rcnjko. + if( pMgntInfo->bMediaConnect == TRUE ) + { + dev->HalFunc.LedControlHandler(dev, LED_CTL_LINK); + } + else + { + // Turn off LED if RF is not ON. + dev->HalFunc.LedControlHandler(dev, LED_CTL_NO_LINK); + } + break; + + default: + // do nothing. + break; + }// Switch RF state + + break; + + default: + RT_TRACE(COMP_RF, "phy_SetRFPowerState8192SU(): Unknown RF type\n"); + break; + }// Switch rf_chip + } +#endif + priv->SetRFPowerStateInProgress = FALSE; + + return bResult; +} + +/*----------------------------------------------------------------------------- + * Function: GetTxPowerLevel8190() + * + * Overview: This function is export to "common" moudule + * + * Input: PADAPTER Adapter + * psByte Power Level + * + * Output: NONE + * + * Return: NONE + * + *---------------------------------------------------------------------------*/ + // no use temp + void +PHY_GetTxPowerLevel8192S( + struct net_device* dev, + long* powerlevel + ) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + u8 TxPwrLevel = 0; + long TxPwrDbm; + // + // Because the Tx power indexes are different, we report the maximum of them to + // meet the CCX TPC request. By Bruce, 2008-01-31. + // + + // CCK + TxPwrLevel = priv->CurrentCckTxPwrIdx; + TxPwrDbm = phy_TxPwrIdxToDbm(dev, WIRELESS_MODE_B, TxPwrLevel); + + // Legacy OFDM + TxPwrLevel = priv->CurrentOfdm24GTxPwrIdx + priv->LegacyHTTxPowerDiff; + + // Compare with Legacy OFDM Tx power. + if(phy_TxPwrIdxToDbm(dev, WIRELESS_MODE_G, TxPwrLevel) > TxPwrDbm) + TxPwrDbm = phy_TxPwrIdxToDbm(dev, WIRELESS_MODE_G, TxPwrLevel); + + // HT OFDM + TxPwrLevel = priv->CurrentOfdm24GTxPwrIdx; + + // Compare with HT OFDM Tx power. + if(phy_TxPwrIdxToDbm(dev, WIRELESS_MODE_N_24G, TxPwrLevel) > TxPwrDbm) + TxPwrDbm = phy_TxPwrIdxToDbm(dev, WIRELESS_MODE_N_24G, TxPwrLevel); + + *powerlevel = TxPwrDbm; +} + +/*----------------------------------------------------------------------------- + * Function: SetTxPowerLevel8190() + * + * Overview: This function is export to "HalCommon" moudule + * + * Input: PADAPTER Adapter + * u1Byte channel + * + * Output: NONE + * + * Return: NONE + * 2008/11/04 MHC We remove EEPROM_93C56. + * We need to move CCX relative code to independet file. +* 2009/01/21 MHC Support new EEPROM format from SD3 requirement. + *---------------------------------------------------------------------------*/ + void PHY_SetTxPowerLevel8192S(struct net_device* dev, u8 channel) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + //HAL_DATA_TYPE *pHalData = GET_HAL_DATA(dev); + u8 powerlevel = (u8)EEPROM_Default_TxPower, powerlevelOFDM24G = 0x10; + s8 ant_pwr_diff = 0; + u32 u4RegValue; + u8 index = (channel -1); + // 2009/01/22 MH Add for new EEPROM format from SD3 + u8 pwrdiff[2] = {0}; + u8 ht20pwr[2] = {0}, ht40pwr[2] = {0}; + u8 rfpath = 0, rfpathnum = 2; + + if(priv->bTXPowerDataReadFromEEPORM == FALSE) + return; + + // + // Read predefined TX power index in EEPROM + // +// if(priv->epromtype == EPROM_93c46) + { +#ifdef EEPROM_OLD_FORMAT_SUPPORT + powerlevel = priv->TxPowerLevelCCK[index]; + powerlevelOFDM24G = priv->TxPowerLevelOFDM24G[index]; +#else + // + // Mainly we use RF-A Tx Power to write the Tx Power registers, but the RF-B Tx + // Power must be calculated by the antenna diff. + // So we have to rewrite Antenna gain offset register here. + // Please refer to BB register 0x80c + // 1. For CCK. + // 2. For OFDM 1T or 2T + // + + // 1. CCK + powerlevel = priv->RfTxPwrLevelCck[0][index]; + + if (priv->rf_type == RF_1T2R || priv->rf_type == RF_1T1R) + { + // Read HT 40 OFDM TX power + powerlevelOFDM24G = priv->RfTxPwrLevelOfdm1T[0][index]; + // RF B HT OFDM pwr-RFA HT OFDM pwr + // Only one RF we need not to decide B <-> A pwr diff + + // Legacy<->HT pwr diff, we only care about path A. + + // We only assume 1T as RF path A + rfpathnum = 1; + ht20pwr[0] = ht40pwr[0] = priv->RfTxPwrLevelOfdm1T[0][index]; + } + else if (priv->rf_type == RF_2T2R) + { + // Read HT 40 OFDM TX power + powerlevelOFDM24G = priv->RfTxPwrLevelOfdm2T[0][index]; + // RF B HT OFDM pwr-RFA HT OFDM pwr + ant_pwr_diff = priv->RfTxPwrLevelOfdm2T[1][index] - + priv->RfTxPwrLevelOfdm2T[0][index]; + // RF B (HT OFDM pwr+legacy-ht-diff) -(RFA HT OFDM pwr+legacy-ht-diff) + // We can not handle Path B&A HT/Legacy pwr diff for 92S now. + + //RTPRINT(FPHY, PHY_TXPWR, ("CH-%d HT40 A/B Pwr index = %x/%x(%d/%d)\n", + //channel, priv->RfTxPwrLevelOfdm2T[0][index], + //priv->RfTxPwrLevelOfdm2T[1][index], + //priv->RfTxPwrLevelOfdm2T[0][index], + //priv->RfTxPwrLevelOfdm2T[1][index])); + + ht20pwr[0] = ht40pwr[0] = priv->RfTxPwrLevelOfdm2T[0][index]; + ht20pwr[1] = ht40pwr[1] = priv->RfTxPwrLevelOfdm2T[1][index]; + } + + // + // 2009/01/21 MH Support new EEPROM format from SD3 requirement + // 2009/02/10 Cosa, Here is only for reg B/C/D to A gain diff. + // + if (priv->EEPROMVersion == 2) // Defined by SD1 Jong + { + if (priv->CurrentChannelBW == HT_CHANNEL_WIDTH_20) + { + for (rfpath = 0; rfpath < rfpathnum; rfpath++) + { + // HT 20<->40 pwr diff + pwrdiff[rfpath] = priv->TxPwrHt20Diff[rfpath][index]; + + // Calculate Antenna pwr diff + if (pwrdiff[rfpath] < 8) // 0~+7 + { + #if 0//cosa, it doesn't need to add the offset here + if (rfpath == 0) + powerlevelOFDM24G += pwrdiff[rfpath]; + #endif + ht20pwr[rfpath] += pwrdiff[rfpath]; + } + else // index8-15=-8~-1 + { + #if 0//cosa, it doesn't need to add the offset here + if (rfpath == 0) + powerlevelOFDM24G -= (15-pwrdiff[rfpath]); + #endif + ht20pwr[rfpath] -= (15-pwrdiff[rfpath]); + } + } + + // RF B HT OFDM pwr-RFA HT OFDM pwr + if (priv->rf_type == RF_2T2R) + ant_pwr_diff = ht20pwr[1] - ht20pwr[0]; + + //RTPRINT(FPHY, PHY_TXPWR, + //("HT20 to HT40 pwrdiff[A/B]=%d/%d, ant_pwr_diff=%d(B-A=%d-%d)\n", + //pwrdiff[0], pwrdiff[1], ant_pwr_diff, ht20pwr[1], ht20pwr[0])); + } + + // Band Edge scheme is enabled for FCC mode + if (priv->TxPwrbandEdgeFlag == 1/* && pHalData->ChannelPlan == 0*/) + { + for (rfpath = 0; rfpath < rfpathnum; rfpath++) + { + pwrdiff[rfpath] = 0; + if (priv->CurrentChannelBW == HT_CHANNEL_WIDTH_20_40) + { + if (channel <= 3) + pwrdiff[rfpath] = priv->TxPwrbandEdgeHt40[rfpath][0]; + else if (channel >= 9) + pwrdiff[rfpath] = priv->TxPwrbandEdgeHt40[rfpath][1]; + else + pwrdiff[rfpath] = 0; + + ht40pwr[rfpath] -= pwrdiff[rfpath]; + } + else if (priv->CurrentChannelBW == HT_CHANNEL_WIDTH_20) + { + if (channel == 1) + pwrdiff[rfpath] = priv->TxPwrbandEdgeHt20[rfpath][0]; + else if (channel >= 11) + pwrdiff[rfpath] = priv->TxPwrbandEdgeHt20[rfpath][1]; + else + pwrdiff[rfpath] = 0; + + ht20pwr[rfpath] -= pwrdiff[rfpath]; + } + #if 0//cosa, it doesn't need to add the offset here + if (rfpath == 0) + powerlevelOFDM24G -= pwrdiff[rfpath]; + #endif + } + + if (priv->rf_type == RF_2T2R) + { + // HT 20/40 must decide if they need to minus BD pwr offset + if (priv->CurrentChannelBW == HT_CHANNEL_WIDTH_20_40) + ant_pwr_diff = ht40pwr[1] - ht40pwr[0]; + else + ant_pwr_diff = ht20pwr[1] - ht20pwr[0]; + } + if (priv->CurrentChannelBW == HT_CHANNEL_WIDTH_20) + { + if (channel <= 1 || channel >= 11) + { + //RTPRINT(FPHY, PHY_TXPWR, + //("HT20 Band-edge pwrdiff[A/B]=%d/%d, ant_pwr_diff=%d(B-A=%d-%d)\n", + //pwrdiff[0], pwrdiff[1], ant_pwr_diff, ht20pwr[1], ht20pwr[0])); + } + } + else + { + if (channel <= 3 || channel >= 9) + { + //RTPRINT(FPHY, PHY_TXPWR, + //("HT40 Band-edge pwrdiff[A/B]=%d/%d, ant_pwr_diff=%d(B-A=%d-%d)\n", + //pwrdiff[0], pwrdiff[1], ant_pwr_diff, ht40pwr[1], ht40pwr[0])); + } + } + } +#if 0//cosa, useless + // Read HT/Legacy OFDM diff + legacy_ant_pwr_diff= pHalData->TxPwrLegacyHtDiff[RF90_PATH_A][index]; +#endif + } + + //Cosa added for protection, the reg rFPGA0_TxGainStage + // range is from 7~-8, index = 0x0~0xf + if(ant_pwr_diff > 7) + ant_pwr_diff = 7; + if(ant_pwr_diff < -8) + ant_pwr_diff = -8; + + //RTPRINT(FPHY, PHY_TXPWR, + //("CCK/HT Power index = %x/%x(%d/%d), ant_pwr_diff=%d\n", + //powerlevel, powerlevelOFDM24G, powerlevel, powerlevelOFDM24G, ant_pwr_diff)); + + ant_pwr_diff &= 0xf; + + // Antenna TX power difference + priv->AntennaTxPwDiff[2] = 0;// RF-D, don't care + priv->AntennaTxPwDiff[1] = 0;// RF-C, don't care + priv->AntennaTxPwDiff[0] = (u8)(ant_pwr_diff); // RF-B + + // Antenna gain offset from B/C/D to A + u4RegValue = ( priv->AntennaTxPwDiff[2]<<8 | + priv->AntennaTxPwDiff[1]<<4 | + priv->AntennaTxPwDiff[0] ); + + // Notify Tx power difference for B/C/D to A!!! + rtl8192_setBBreg(dev, rFPGA0_TxGainStage, (bXBTxAGC|bXCTxAGC|bXDTxAGC), u4RegValue); +#endif + } + + // + // CCX 2 S31, AP control of client transmit power: + // 1. We shall not exceed Cell Power Limit as possible as we can. + // 2. Tolerance is +/- 5dB. + // 3. 802.11h Power Contraint takes higher precedence over CCX Cell Power Limit. + // + // TODO: + // 1. 802.11h power contraint + // + // 071011, by rcnjko. + // +#ifdef TODO //WB, 11h has not implemented now. + if( priv->ieee80211->iw_mode != IW_MODE_INFRA && priv->bWithCcxCellPwr && + channel == priv->ieee80211->current_network.channel)// & priv->ieee80211->mAssoc ) + { + u8 CckCellPwrIdx = phy_DbmToTxPwrIdx(dev, WIRELESS_MODE_B, priv->CcxCellPwr); + u8 LegacyOfdmCellPwrIdx = phy_DbmToTxPwrIdx(dev, WIRELESS_MODE_G, priv->CcxCellPwr); + u8 OfdmCellPwrIdx = phy_DbmToTxPwrIdx(dev, WIRELESS_MODE_N_24G, priv->CcxCellPwr); + + RT_TRACE(COMP_TXAGC, + ("CCX Cell Limit: %d dbm => CCK Tx power index : %d, Legacy OFDM Tx power index : %d, OFDM Tx power index: %d\n", + priv->CcxCellPwr, CckCellPwrIdx, LegacyOfdmCellPwrIdx, OfdmCellPwrIdx)); + RT_TRACE(COMP_TXAGC, + ("EEPROM channel(%d) => CCK Tx power index: %d, Legacy OFDM Tx power index : %d, OFDM Tx power index: %d\n", + channel, powerlevel, powerlevelOFDM24G + priv->LegacyHTTxPowerDiff, powerlevelOFDM24G)); + + // CCK + if(powerlevel > CckCellPwrIdx) + powerlevel = CckCellPwrIdx; + // Legacy OFDM, HT OFDM + if(powerlevelOFDM24G + priv->LegacyHTTxPowerDiff > LegacyOfdmCellPwrIdx) + { + if((OfdmCellPwrIdx - priv->LegacyHTTxPowerDiff) > 0) + { + powerlevelOFDM24G = OfdmCellPwrIdx - priv->LegacyHTTxPowerDiff; + } + else + { + powerlevelOFDM24G = 0; + } + } + + RT_TRACE(COMP_TXAGC, + ("Altered CCK Tx power index : %d, Legacy OFDM Tx power index: %d, OFDM Tx power index: %d\n", + powerlevel, powerlevelOFDM24G + priv->LegacyHTTxPowerDiff, powerlevelOFDM24G)); + } +#endif + + priv->CurrentCckTxPwrIdx = powerlevel; + priv->CurrentOfdm24GTxPwrIdx = powerlevelOFDM24G; + + switch(priv->rf_chip) + { + case RF_8225: + //PHY_SetRF8225CckTxPower(dev, powerlevel); + //PHY_SetRF8225OfdmTxPower(dev, powerlevelOFDM24G); + break; + + case RF_8256: +#if 0 + PHY_SetRF8256CCKTxPower(dev, powerlevel); + PHY_SetRF8256OFDMTxPower(dev, powerlevelOFDM24G); +#endif + break; + + case RF_6052: + PHY_RF6052SetCckTxPower(dev, powerlevel); + PHY_RF6052SetOFDMTxPower(dev, powerlevelOFDM24G); + break; + + case RF_8258: + break; + default: + break; + } + +} + +// +// Description: +// Update transmit power level of all channel supported. +// +// TODO: +// A mode. +// By Bruce, 2008-02-04. +// no use temp +bool PHY_UpdateTxPowerDbm8192S(struct net_device* dev, long powerInDbm) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + u8 idx; + u8 rf_path; + + // TODO: A mode Tx power. + u8 CckTxPwrIdx = phy_DbmToTxPwrIdx(dev, WIRELESS_MODE_B, powerInDbm); + u8 OfdmTxPwrIdx = phy_DbmToTxPwrIdx(dev, WIRELESS_MODE_N_24G, powerInDbm); + + if(OfdmTxPwrIdx - priv->LegacyHTTxPowerDiff > 0) + OfdmTxPwrIdx -= priv->LegacyHTTxPowerDiff; + else + OfdmTxPwrIdx = 0; + + for(idx = 0; idx < 14; idx++) + { + priv->TxPowerLevelCCK[idx] = CckTxPwrIdx; + priv->TxPowerLevelCCK_A[idx] = CckTxPwrIdx; + priv->TxPowerLevelCCK_C[idx] = CckTxPwrIdx; + priv->TxPowerLevelOFDM24G[idx] = OfdmTxPwrIdx; + priv->TxPowerLevelOFDM24G_A[idx] = OfdmTxPwrIdx; + priv->TxPowerLevelOFDM24G_C[idx] = OfdmTxPwrIdx; + + for (rf_path = 0; rf_path < 2; rf_path++) + { + priv->RfTxPwrLevelCck[rf_path][idx] = CckTxPwrIdx; + priv->RfTxPwrLevelOfdm1T[rf_path][idx] = \ + priv->RfTxPwrLevelOfdm2T[rf_path][idx] = OfdmTxPwrIdx; + } + } + + PHY_SetTxPowerLevel8192S(dev, priv->chan); + + return TRUE; +} + +/* + Description: + When beacon interval is changed, the values of the + hw registers should be modified. + By tynli, 2008.10.24. + +*/ + +extern void PHY_SetBeaconHwReg( struct net_device* dev, u16 BeaconInterval) +{ + u32 NewBeaconNum; + + NewBeaconNum = BeaconInterval *32 - 64; + //PlatformEFIOWrite4Byte(Adapter, WFM3+4, NewBeaconNum); + //PlatformEFIOWrite4Byte(Adapter, WFM3, 0xB026007C); + write_nic_dword(dev, WFM3+4, NewBeaconNum); + write_nic_dword(dev, WFM3, 0xB026007C); +} + +// +// Description: +// Map dBm into Tx power index according to +// current HW model, for example, RF and PA, and +// current wireless mode. +// By Bruce, 2008-01-29. +// use in phy only +static u8 phy_DbmToTxPwrIdx( + struct net_device* dev, + WIRELESS_MODE WirelessMode, + long PowerInDbm + ) +{ + //struct r8192_priv *priv = ieee80211_priv(dev); + u8 TxPwrIdx = 0; + long Offset = 0; + + + // + // Tested by MP, we found that CCK Index 0 equals to -7dbm, OFDM legacy equals to + // 3dbm, and OFDM HT equals to 0dbm repectively. + // Note: + // The mapping may be different by different NICs. Do not use this formula for what needs accurate result. + // By Bruce, 2008-01-29. + // + switch(WirelessMode) + { + case WIRELESS_MODE_B: + Offset = -7; + break; + + case WIRELESS_MODE_G: + case WIRELESS_MODE_N_24G: + Offset = -8; + break; + default: + break; + } + + if((PowerInDbm - Offset) > 0) + { + TxPwrIdx = (u8)((PowerInDbm - Offset) * 2); + } + else + { + TxPwrIdx = 0; + } + + // Tx Power Index is too large. + if(TxPwrIdx > MAX_TXPWR_IDX_NMODE_92S) + TxPwrIdx = MAX_TXPWR_IDX_NMODE_92S; + + return TxPwrIdx; +} +// +// Description: +// Map Tx power index into dBm according to +// current HW model, for example, RF and PA, and +// current wireless mode. +// By Bruce, 2008-01-29. +// use in phy only +static long phy_TxPwrIdxToDbm( + struct net_device* dev, + WIRELESS_MODE WirelessMode, + u8 TxPwrIdx + ) +{ + //struct r8192_priv *priv = ieee80211_priv(dev); + long Offset = 0; + long PwrOutDbm = 0; + + // + // Tested by MP, we found that CCK Index 0 equals to -7dbm, OFDM legacy equals to + // 3dbm, and OFDM HT equals to 0dbm repectively. + // Note: + // The mapping may be different by different NICs. Do not use this formula for what needs accurate result. + // By Bruce, 2008-01-29. + // + switch(WirelessMode) + { + case WIRELESS_MODE_B: + Offset = -7; + break; + + case WIRELESS_MODE_G: + case WIRELESS_MODE_N_24G: + Offset = -8; + break; + default: + break; + } + + PwrOutDbm = TxPwrIdx / 2 + Offset; // Discard the decimal part. + + return PwrOutDbm; +} + +#ifdef TO_DO_LIST +extern VOID +PHY_ScanOperationBackup8192S( + IN PADAPTER Adapter, + IN u1Byte Operation + ) +{ + + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + PMGNT_INFO pMgntInfo = &(Adapter->MgntInfo); + u4Byte BitMask; + u1Byte initial_gain; + + + + +#if(RTL8192S_DISABLE_FW_DM == 0) + + if(!Adapter->bDriverStopped) + { + switch(Operation) + { + case SCAN_OPT_BACKUP: + // + // We halt FW DIG and disable high ppower both two DMs here + // and resume both two DMs while scan complete. + // 2008.11.27. + // + Adapter->HalFunc.SetFwCmdHandler(Adapter, FW_CMD_PAUSE_DM_BY_SCAN); + break; + + case SCAN_OPT_RESTORE: + // + // We resume DIG and enable high power both two DMs here and + // recover earlier DIG settings. + // 2008.11.27. + // + Adapter->HalFunc.SetFwCmdHandler(Adapter, FW_CMD_RESUME_DM_BY_SCAN); + break; + + default: + RT_TRACE(COMP_SCAN, DBG_LOUD, ("Unknown Scan Backup Operation. \n")); + break; + } + } +#endif +} +#endif + +//nouse temp +void PHY_InitialGain8192S(struct net_device* dev,u8 Operation ) +{ + + //struct r8192_priv *priv = ieee80211_priv(dev); + //u32 BitMask; + //u8 initial_gain; + +#if 0 // For 8192s test disable + if(!dev->bDriverStopped) + { + switch(Operation) + { + case IG_Backup: + RT_TRACE(COMP_SCAN, DBG_LOUD, ("IG_Backup, backup the initial gain.\n")); + initial_gain = priv->DefaultInitialGain[0]; + BitMask = bMaskByte0; + if(DM_DigTable.Dig_Algorithm == DIG_ALGO_BY_FALSE_ALARM) + PHY_SetMacReg(dev, UFWP, bMaskByte1, 0x8); // FW DIG OFF + pMgntInfo->InitGain_Backup.XAAGCCore1 = (u8)rtl8192_QueryBBReg(dev, rOFDM0_XAAGCCore1, BitMask); + pMgntInfo->InitGain_Backup.XBAGCCore1 = (u8)rtl8192_QueryBBReg(dev, rOFDM0_XBAGCCore1, BitMask); + pMgntInfo->InitGain_Backup.XCAGCCore1 = (u8)rtl8192_QueryBBReg(dev, rOFDM0_XCAGCCore1, BitMask); + pMgntInfo->InitGain_Backup.XDAGCCore1 = (u8)rtl8192_QueryBBReg(dev, rOFDM0_XDAGCCore1, BitMask); + BitMask = bMaskByte2; + pMgntInfo->InitGain_Backup.CCA = (u8)rtl8192_QueryBBReg(dev, rCCK0_CCA, BitMask); + + RT_TRACE(COMP_SCAN, DBG_LOUD, ("Scan InitialGainBackup 0xc50 is %x\n",pMgntInfo->InitGain_Backup.XAAGCCore1)); + RT_TRACE(COMP_SCAN, DBG_LOUD, ("Scan InitialGainBackup 0xc58 is %x\n",pMgntInfo->InitGain_Backup.XBAGCCore1)); + RT_TRACE(COMP_SCAN, DBG_LOUD, ("Scan InitialGainBackup 0xc60 is %x\n",pMgntInfo->InitGain_Backup.XCAGCCore1)); + RT_TRACE(COMP_SCAN, DBG_LOUD, ("Scan InitialGainBackup 0xc68 is %x\n",pMgntInfo->InitGain_Backup.XDAGCCore1)); + RT_TRACE(COMP_SCAN, DBG_LOUD, ("Scan InitialGainBackup 0xa0a is %x\n",pMgntInfo->InitGain_Backup.CCA)); + + RT_TRACE(COMP_SCAN, DBG_LOUD, ("Write scan initial gain = 0x%x \n", initial_gain)); + write_nic_byte(dev, rOFDM0_XAAGCCore1, initial_gain); + write_nic_byte(dev, rOFDM0_XBAGCCore1, initial_gain); + write_nic_byte(dev, rOFDM0_XCAGCCore1, initial_gain); + write_nic_byte(dev, rOFDM0_XDAGCCore1, initial_gain); + break; + case IG_Restore: + RT_TRACE(COMP_SCAN, DBG_LOUD, ("IG_Restore, restore the initial gain.\n")); + BitMask = 0x7f; //Bit0~ Bit6 + if(DM_DigTable.Dig_Algorithm == DIG_ALGO_BY_FALSE_ALARM) + PHY_SetMacReg(dev, UFWP, bMaskByte1, 0x8); // FW DIG OFF + + rtl8192_setBBreg(dev, rOFDM0_XAAGCCore1, BitMask, (u32)pMgntInfo->InitGain_Backup.XAAGCCore1); + rtl8192_setBBreg(dev, rOFDM0_XBAGCCore1, BitMask, (u32)pMgntInfo->InitGain_Backup.XBAGCCore1); + rtl8192_setBBreg(dev, rOFDM0_XCAGCCore1, BitMask, (u32)pMgntInfo->InitGain_Backup.XCAGCCore1); + rtl8192_setBBreg(dev, rOFDM0_XDAGCCore1, BitMask, (u32)pMgntInfo->InitGain_Backup.XDAGCCore1); + BitMask = (BIT22|BIT23); + rtl8192_setBBreg(dev, rCCK0_CCA, BitMask, (u32)pMgntInfo->InitGain_Backup.CCA); + + RT_TRACE(COMP_SCAN, DBG_LOUD, ("Scan BBInitialGainRestore 0xc50 is %x\n",pMgntInfo->InitGain_Backup.XAAGCCore1)); + RT_TRACE(COMP_SCAN, DBG_LOUD, ("Scan BBInitialGainRestore 0xc58 is %x\n",pMgntInfo->InitGain_Backup.XBAGCCore1)); + RT_TRACE(COMP_SCAN, DBG_LOUD, ("Scan BBInitialGainRestore 0xc60 is %x\n",pMgntInfo->InitGain_Backup.XCAGCCore1)); + RT_TRACE(COMP_SCAN, DBG_LOUD, ("Scan BBInitialGainRestore 0xc68 is %x\n",pMgntInfo->InitGain_Backup.XDAGCCore1)); + RT_TRACE(COMP_SCAN, DBG_LOUD, ("Scan BBInitialGainRestore 0xa0a is %x\n",pMgntInfo->InitGain_Backup.CCA)); + + if(DM_DigTable.Dig_Algorithm == DIG_ALGO_BY_FALSE_ALARM) + PHY_SetMacReg(dev, UFWP, bMaskByte1, 0x1); // FW DIG ON + break; + default: + RT_TRACE(COMP_SCAN, DBG_LOUD, ("Unknown IG Operation. \n")); + break; + } + } +#endif +} + +/*----------------------------------------------------------------------------- + * Function: SetBWModeCallback8190Pci() + * + * Overview: Timer callback function for SetSetBWMode + * + * Input: PRT_TIMER pTimer + * + * Output: NONE + * + * Return: NONE + * + * Note: (1) We do not take j mode into consideration now + * (2) Will two workitem of "switch channel" and "switch channel bandwidth" run + * concurrently? + *---------------------------------------------------------------------------*/ +// use in phy only (in win it's timer) +void PHY_SetBWModeCallback8192S(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + u8 regBwOpMode; + + //return; + + // Added it for 20/40 mhz switch time evaluation by guangan 070531 + //u32 NowL, NowH; + //u8Byte BeginTime, EndTime; + u8 regRRSR_RSC; + + RT_TRACE(COMP_SWBW, "==>SetBWModeCallback8190Pci() Switch to %s bandwidth\n", \ + priv->CurrentChannelBW == HT_CHANNEL_WIDTH_20?"20MHz":"40MHz"); + + if(priv->rf_chip == RF_PSEUDO_11N) + { + priv->SetBWModeInProgress= FALSE; + return; + } + + if(!priv->up) + return; + + // Added it for 20/40 mhz switch time evaluation by guangan 070531 + //NowL = read_nic_dword(dev, TSFR); + //NowH = read_nic_dword(dev, TSFR+4); + //BeginTime = ((u8Byte)NowH << 32) + NowL; + + //3// + //3//<1>Set MAC register + //3// + regBwOpMode = read_nic_byte(dev, BW_OPMODE); + regRRSR_RSC = read_nic_byte(dev, RRSR+2); + + switch(priv->CurrentChannelBW) + { + case HT_CHANNEL_WIDTH_20: + //if(priv->card_8192_version >= VERSION_8192S_BCUT) + // write_nic_byte(dev, rFPGA0_AnalogParameter2, 0x58); + + regBwOpMode |= BW_OPMODE_20MHZ; + // 2007/02/07 Mark by Emily becasue we have not verify whether this register works + write_nic_byte(dev, BW_OPMODE, regBwOpMode); + break; + + case HT_CHANNEL_WIDTH_20_40: + //if(priv->card_8192_version >= VERSION_8192S_BCUT) + // write_nic_byte(dev, rFPGA0_AnalogParameter2, 0x18); + + regBwOpMode &= ~BW_OPMODE_20MHZ; + // 2007/02/07 Mark by Emily becasue we have not verify whether this register works + write_nic_byte(dev, BW_OPMODE, regBwOpMode); + regRRSR_RSC = (regRRSR_RSC&0x90) |(priv->nCur40MhzPrimeSC<<5); + write_nic_byte(dev, RRSR+2, regRRSR_RSC); + break; + + default: + RT_TRACE(COMP_DBG, "SetBWModeCallback8190Pci():\ + unknown Bandwidth: %#X\n",priv->CurrentChannelBW); + break; + } + + //3// + //3//<2>Set PHY related register + //3// + switch(priv->CurrentChannelBW) + { + /* 20 MHz channel*/ + case HT_CHANNEL_WIDTH_20: + rtl8192_setBBreg(dev, rFPGA0_RFMOD, bRFMOD, 0x0); + rtl8192_setBBreg(dev, rFPGA1_RFMOD, bRFMOD, 0x0); + + // Correct the tx power for CCK rate in 40M. Suggest by YN, 20071207 + // It is set in Tx descriptor for 8192x series + //write_nic_dword(dev, rCCK0_TxFilter1, 0x1a1b0000); + //write_nic_dword(dev, rCCK0_TxFilter2, 0x090e1317); + //write_nic_dword(dev, rCCK0_DebugPort, 0x00000204); + #if 0 //LZM 090219 + rtl8192_setBBreg(dev, rCCK0_TxFilter1, bMaskDWord, 0x1a1b0000); + rtl8192_setBBreg(dev, rCCK0_TxFilter2, bMaskDWord, 0x090e1317); + rtl8192_setBBreg(dev, rCCK0_DebugPort, bMaskDWord, 0x00000204); + rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x00300000, 3); + #endif + + if (priv->card_8192_version >= VERSION_8192S_BCUT) + write_nic_byte(dev, rFPGA0_AnalogParameter2, 0x58); + + + break; + + /* 40 MHz channel*/ + case HT_CHANNEL_WIDTH_20_40: + rtl8192_setBBreg(dev, rFPGA0_RFMOD, bRFMOD, 0x1); + rtl8192_setBBreg(dev, rFPGA1_RFMOD, bRFMOD, 0x1); + + // Correct the tx power for CCK rate in 40M. Suggest by YN, 20071207 + //write_nic_dword(dev, rCCK0_TxFilter1, 0x35360000); + //write_nic_dword(dev, rCCK0_TxFilter2, 0x121c252e); + //write_nic_dword(dev, rCCK0_DebugPort, 0x00000409); + #if 0 //LZM 090219 + rtl8192_setBBreg(dev, rCCK0_TxFilter1, bMaskDWord, 0x35360000); + rtl8192_setBBreg(dev, rCCK0_TxFilter2, bMaskDWord, 0x121c252e); + rtl8192_setBBreg(dev, rCCK0_DebugPort, bMaskDWord, 0x00000409); + #endif + + // Set Control channel to upper or lower. These settings are required only for 40MHz + rtl8192_setBBreg(dev, rCCK0_System, bCCKSideBand, (priv->nCur40MhzPrimeSC>>1)); + rtl8192_setBBreg(dev, rOFDM1_LSTF, 0xC00, priv->nCur40MhzPrimeSC); + + //rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x00300000, 3); + if (priv->card_8192_version >= VERSION_8192S_BCUT) + write_nic_byte(dev, rFPGA0_AnalogParameter2, 0x18); + + break; + + default: + RT_TRACE(COMP_DBG, "SetBWModeCallback8190Pci(): unknown Bandwidth: %#X\n"\ + ,priv->CurrentChannelBW); + break; + + } + //Skip over setting of J-mode in BB register here. Default value is "None J mode". Emily 20070315 + + // Added it for 20/40 mhz switch time evaluation by guangan 070531 + //NowL = read_nic_dword(dev, TSFR); + //NowH = read_nic_dword(dev, TSFR+4); + //EndTime = ((u8Byte)NowH << 32) + NowL; + //RT_TRACE(COMP_SCAN, DBG_LOUD, ("SetBWModeCallback8190Pci: time of SetBWMode = %I64d us!\n", (EndTime - BeginTime))); + + //3<3>Set RF related register + switch( priv->rf_chip ) + { + case RF_8225: + //PHY_SetRF8225Bandwidth(dev, priv->CurrentChannelBW); + break; + + case RF_8256: + // Please implement this function in Hal8190PciPhy8256.c + //PHY_SetRF8256Bandwidth(dev, priv->CurrentChannelBW); + break; + + case RF_8258: + // Please implement this function in Hal8190PciPhy8258.c + // PHY_SetRF8258Bandwidth(); + break; + + case RF_PSEUDO_11N: + // Do Nothing + break; + + case RF_6052: + PHY_RF6052SetBandwidth(dev, priv->CurrentChannelBW); + break; + default: + printk("Unknown rf_chip: %d\n", priv->rf_chip); + break; + } + + priv->SetBWModeInProgress= FALSE; + + RT_TRACE(COMP_SWBW, "<==SetBWModeCallback8190Pci() \n" ); +} + + + /*----------------------------------------------------------------------------- + * Function: SetBWMode8190Pci() + * + * Overview: This function is export to "HalCommon" moudule + * + * Input: PADAPTER Adapter + * HT_CHANNEL_WIDTH Bandwidth //20M or 40M + * + * Output: NONE + * + * Return: NONE + * + * Note: We do not take j mode into consideration now + *---------------------------------------------------------------------------*/ +//extern void PHY_SetBWMode8192S( struct net_device* dev, +// HT_CHANNEL_WIDTH Bandwidth, // 20M or 40M +// HT_EXTCHNL_OFFSET Offset // Upper, Lower, or Don't care +void rtl8192_SetBWMode(struct net_device *dev, HT_CHANNEL_WIDTH Bandwidth, HT_EXTCHNL_OFFSET Offset) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + HT_CHANNEL_WIDTH tmpBW = priv->CurrentChannelBW; + + + // Modified it for 20/40 mhz switch by guangan 070531 + + //return; + + //if(priv->SwChnlInProgress) +// if(pMgntInfo->bScanInProgress) +// { +// RT_TRACE(COMP_SCAN, DBG_LOUD, ("SetBWMode8190Pci() %s Exit because bScanInProgress!\n", +// Bandwidth == HT_CHANNEL_WIDTH_20?"20MHz":"40MHz")); +// return; +// } + +// if(priv->SetBWModeInProgress) +// { +// // Modified it for 20/40 mhz switch by guangan 070531 +// RT_TRACE(COMP_SCAN, DBG_LOUD, ("SetBWMode8190Pci() %s cancel last timer because SetBWModeInProgress!\n", +// Bandwidth == HT_CHANNEL_WIDTH_20?"20MHz":"40MHz")); +// PlatformCancelTimer(dev, &priv->SetBWModeTimer); +// //return; +// } + + if(priv->SetBWModeInProgress) + return; + + priv->SetBWModeInProgress= TRUE; + + priv->CurrentChannelBW = Bandwidth; + + if(Offset==HT_EXTCHNL_OFFSET_LOWER) + priv->nCur40MhzPrimeSC = HAL_PRIME_CHNL_OFFSET_UPPER; + else if(Offset==HT_EXTCHNL_OFFSET_UPPER) + priv->nCur40MhzPrimeSC = HAL_PRIME_CHNL_OFFSET_LOWER; + else + priv->nCur40MhzPrimeSC = HAL_PRIME_CHNL_OFFSET_DONT_CARE; + +#if 0 + if(!priv->bDriverStopped) + { +#ifdef USE_WORKITEM + PlatformScheduleWorkItem(&(priv->SetBWModeWorkItem));//SetBWModeCallback8192SUsbWorkItem +#else + PlatformSetTimer(dev, &(priv->SetBWModeTimer), 0);//PHY_SetBWModeCallback8192S +#endif + } +#endif + if((priv->up) )// && !(RT_CANNOT_IO(Adapter) && Adapter->bInSetPower) ) + { +#ifdef RTL8192SE + PHY_SetBWModeCallback8192S(dev); +#elif defined(RTL8192SU) + SetBWModeCallback8192SUsbWorkItem(dev); +#endif + } + else + { + RT_TRACE(COMP_SCAN, "PHY_SetBWMode8192S() SetBWModeInProgress FALSE driver sleep or unload\n"); + priv->SetBWModeInProgress= FALSE; + priv->CurrentChannelBW = tmpBW; + } +} + +// use in phy only (in win it's timer) +void PHY_SwChnlCallback8192S(struct net_device *dev) +{ + + struct r8192_priv *priv = ieee80211_priv(dev); + u32 delay; + //bool ret; + + RT_TRACE(COMP_CH, "==>SwChnlCallback8190Pci(), switch to channel %d\n", priv->chan); + + if(!priv->up) + return; + + if(priv->rf_chip == RF_PSEUDO_11N) + { + priv->SwChnlInProgress=FALSE; + return; //return immediately if it is peudo-phy + } + + do{ + if(!priv->SwChnlInProgress) + break; + + //if(!phy_SwChnlStepByStep(dev, priv->CurrentChannel, &priv->SwChnlStage, &priv->SwChnlStep, &delay)) + if(!phy_SwChnlStepByStep(dev, priv->chan, &priv->SwChnlStage, &priv->SwChnlStep, &delay)) + { + if(delay>0) + { + mdelay(delay); + //PlatformSetTimer(dev, &priv->SwChnlTimer, delay); + //mod_timer(&priv->SwChnlTimer, jiffies + MSECS(delay)); + //==>PHY_SwChnlCallback8192S(dev); for 92se + //==>SwChnlCallback8192SUsb(dev) for 92su + } + else + continue; + } + else + { + priv->SwChnlInProgress=FALSE; + break; + } + }while(true); +} + +// Call after initialization +//extern void PHY_SwChnl8192S(struct net_device* dev, u8 channel) +u8 rtl8192_phy_SwChnl(struct net_device* dev, u8 channel) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + //u8 tmpchannel =channel; + //bool bResult = false; + + if(!priv->up) + return false; + + if(priv->SwChnlInProgress) + return false; + + if(priv->SetBWModeInProgress) + return false; + + //-------------------------------------------- + switch(priv->ieee80211->mode) + { + case WIRELESS_MODE_A: + case WIRELESS_MODE_N_5G: + if (channel<=14){ + RT_TRACE(COMP_ERR, "WIRELESS_MODE_A but channel<=14"); + return false; + } + break; + + case WIRELESS_MODE_B: + if (channel>14){ + RT_TRACE(COMP_ERR, "WIRELESS_MODE_B but channel>14"); + return false; + } + break; + + case WIRELESS_MODE_G: + case WIRELESS_MODE_N_24G: + if (channel>14){ + RT_TRACE(COMP_ERR, "WIRELESS_MODE_G but channel>14"); + return false; + } + break; + + default: + ;//RT_TRACE(COMP_ERR, "Invalid WirelessMode(%#x)!!\n", priv->ieee80211->mode); + break; + } + //-------------------------------------------- + + priv->SwChnlInProgress = TRUE; + if( channel == 0) + channel = 1; + + priv->chan=channel; + + priv->SwChnlStage=0; + priv->SwChnlStep=0; + + if((priv->up))// && !(RT_CANNOT_IO(Adapter) && Adapter->bInSetPower)) + { +#ifdef RTL8192SE + PHY_SwChnlCallback8192S(dev); +#elif defined(RTL8192SU) + SwChnlCallback8192SUsbWorkItem(dev); +#endif +#ifdef TO_DO_LIST + if(bResult) + { + RT_TRACE(COMP_SCAN, "PHY_SwChnl8192S SwChnlInProgress TRUE schdule workitem done\n"); + } + else + { + RT_TRACE(COMP_SCAN, "PHY_SwChnl8192S SwChnlInProgress FALSE schdule workitem error\n"); + priv->SwChnlInProgress = false; + priv->CurrentChannel = tmpchannel; + } +#endif + } + else + { + RT_TRACE(COMP_SCAN, "PHY_SwChnl8192S SwChnlInProgress FALSE driver sleep or unload\n"); + priv->SwChnlInProgress = false; + //priv->CurrentChannel = tmpchannel; + } + return true; +} + + +// +// Description: +// Switch channel synchronously. Called by SwChnlByDelayHandler. +// +// Implemented by Bruce, 2008-02-14. +// The following procedure is operted according to SwChanlCallback8190Pci(). +// However, this procedure is performed synchronously which should be running under +// passive level. +// +//not understant it +void PHY_SwChnlPhy8192S( // Only called during initialize + struct net_device* dev, + u8 channel + ) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + + RT_TRACE(COMP_SCAN, "==>PHY_SwChnlPhy8192S(), switch to channel %d.\n", priv->chan); + +#ifdef TO_DO_LIST + // Cannot IO. + if(RT_CANNOT_IO(dev)) + return; +#endif + + // Channel Switching is in progress. + if(priv->SwChnlInProgress) + return; + + //return immediately if it is peudo-phy + if(priv->rf_chip == RF_PSEUDO_11N) + { + priv->SwChnlInProgress=FALSE; + return; + } + + priv->SwChnlInProgress = TRUE; + if( channel == 0) + channel = 1; + + priv->chan=channel; + + priv->SwChnlStage = 0; + priv->SwChnlStep = 0; + + phy_FinishSwChnlNow(dev,channel); + + priv->SwChnlInProgress = FALSE; +} + +// use in phy only +static bool +phy_SetSwChnlCmdArray( + SwChnlCmd* CmdTable, + u32 CmdTableIdx, + u32 CmdTableSz, + SwChnlCmdID CmdID, + u32 Para1, + u32 Para2, + u32 msDelay + ) +{ + SwChnlCmd* pCmd; + + if(CmdTable == NULL) + { + //RT_ASSERT(FALSE, ("phy_SetSwChnlCmdArray(): CmdTable cannot be NULL.\n")); + return FALSE; + } + if(CmdTableIdx >= CmdTableSz) + { + //RT_ASSERT(FALSE, + // ("phy_SetSwChnlCmdArray(): Access invalid index, please check size of the table, CmdTableIdx:%d, CmdTableSz:%d\n", + //CmdTableIdx, CmdTableSz)); + return FALSE; + } + + pCmd = CmdTable + CmdTableIdx; + pCmd->CmdID = CmdID; + pCmd->Para1 = Para1; + pCmd->Para2 = Para2; + pCmd->msDelay = msDelay; + + return TRUE; +} + +// use in phy only +static bool +phy_SwChnlStepByStep( + struct net_device* dev, + u8 channel, + u8 *stage, + u8 *step, + u32 *delay + ) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + //PCHANNEL_ACCESS_SETTING pChnlAccessSetting; + SwChnlCmd PreCommonCmd[MAX_PRECMD_CNT]; + u32 PreCommonCmdCnt; + SwChnlCmd PostCommonCmd[MAX_POSTCMD_CNT]; + u32 PostCommonCmdCnt; + SwChnlCmd RfDependCmd[MAX_RFDEPENDCMD_CNT]; + u32 RfDependCmdCnt; + SwChnlCmd *CurrentCmd = NULL; + u8 eRFPath; + + //RT_ASSERT((dev != NULL), ("Adapter should not be NULL\n")); + //RT_ASSERT(IsLegalChannel(dev, channel), ("illegal channel: %d\n", channel)); + RT_TRACE(COMP_CH, "===========>%s(), channel:%d, stage:%d, step:%d\n", __FUNCTION__, channel, *stage, *step); + //RT_ASSERT((pHalData != NULL), ("pHalData should not be NULL\n")); +#ifdef ENABLE_DOT11D + if (!IsLegalChannel(priv->ieee80211, channel)) + { + RT_TRACE(COMP_ERR, "=============>set to illegal channel:%d\n", channel); + return true; //return true to tell upper caller function this channel setting is finished! Or it will in while loop. + } +#endif + + //pChnlAccessSetting = &Adapter->MgntInfo.Info8185.ChannelAccessSetting; + //RT_ASSERT((pChnlAccessSetting != NULL), ("pChnlAccessSetting should not be NULL\n")); + + //for(eRFPath = RF90_PATH_A; eRFPath NumTotalRFPath; eRFPath++) + //for(eRFPath = 0; eRFPath NumTotalRFPath; eRFPath++) + //{ + // <1> Fill up pre common command. + PreCommonCmdCnt = 0; + phy_SetSwChnlCmdArray(PreCommonCmd, PreCommonCmdCnt++, MAX_PRECMD_CNT, + CmdID_SetTxPowerLevel, 0, 0, 0); + phy_SetSwChnlCmdArray(PreCommonCmd, PreCommonCmdCnt++, MAX_PRECMD_CNT, + CmdID_End, 0, 0, 0); + + // <2> Fill up post common command. + PostCommonCmdCnt = 0; + + phy_SetSwChnlCmdArray(PostCommonCmd, PostCommonCmdCnt++, MAX_POSTCMD_CNT, + CmdID_End, 0, 0, 0); + + // <3> Fill up RF dependent command. + RfDependCmdCnt = 0; + switch( priv->rf_chip ) + { + case RF_8225: + if (channel < 1 || channel > 14) + RT_TRACE(COMP_ERR, "illegal channel for zebra:%d\n", channel); + //RT_ASSERT((channel >= 1 && channel <= 14), ("illegal channel for Zebra: %d\n", channel)); + // 2008/09/04 MH Change channel. + phy_SetSwChnlCmdArray(RfDependCmd, RfDependCmdCnt++, MAX_RFDEPENDCMD_CNT, + CmdID_RF_WriteReg, rRfChannel, channel, 10); + phy_SetSwChnlCmdArray(RfDependCmd, RfDependCmdCnt++, MAX_RFDEPENDCMD_CNT, + CmdID_End, 0, 0, 0); + break; + + case RF_8256: + if (channel < 1 || channel > 14) + RT_TRACE(COMP_ERR, "illegal channel for zebra:%d\n", channel); + // TEST!! This is not the table for 8256!! + //RT_ASSERT((channel >= 1 && channel <= 14), ("illegal channel for Zebra: %d\n", channel)); + phy_SetSwChnlCmdArray(RfDependCmd, RfDependCmdCnt++, MAX_RFDEPENDCMD_CNT, + CmdID_RF_WriteReg, rRfChannel, channel, 10); + phy_SetSwChnlCmdArray(RfDependCmd, RfDependCmdCnt++, MAX_RFDEPENDCMD_CNT, + CmdID_End, 0, 0, 0); + break; + + case RF_6052: + if (channel < 1 || channel > 14) + RT_TRACE(COMP_ERR, "illegal channel for zebra:%d\n", channel); + phy_SetSwChnlCmdArray(RfDependCmd, RfDependCmdCnt++, MAX_RFDEPENDCMD_CNT, + CmdID_RF_WriteReg, RF_CHNLBW, channel, 10); + phy_SetSwChnlCmdArray(RfDependCmd, RfDependCmdCnt++, MAX_RFDEPENDCMD_CNT, + CmdID_End, 0, 0, 0); + break; + + case RF_8258: + break; + + default: + //RT_ASSERT(FALSE, ("Unknown rf_chip: %d\n", priv->rf_chip)); + return FALSE; + break; + } + + + do{ + switch(*stage) + { + case 0: + CurrentCmd=&PreCommonCmd[*step]; + break; + case 1: + CurrentCmd=&RfDependCmd[*step]; + break; + case 2: + CurrentCmd=&PostCommonCmd[*step]; + break; + } + + if(CurrentCmd->CmdID==CmdID_End) + { + if((*stage)==2) + { + return TRUE; + } + else + { + (*stage)++; + (*step)=0; + continue; + } + } + + switch(CurrentCmd->CmdID) + { + case CmdID_SetTxPowerLevel: + //if(priv->card_8192_version > VERSION_8190_BD) + PHY_SetTxPowerLevel8192S(dev,channel); + break; + case CmdID_WritePortUlong: + write_nic_dword(dev, CurrentCmd->Para1, CurrentCmd->Para2); + break; + case CmdID_WritePortUshort: + write_nic_word(dev, CurrentCmd->Para1, (u16)CurrentCmd->Para2); + break; + case CmdID_WritePortUchar: + write_nic_byte(dev, CurrentCmd->Para1, (u8)CurrentCmd->Para2); + break; + case CmdID_RF_WriteReg: // Only modify channel for the register now !!!!! + for(eRFPath = 0; eRFPath NumTotalRFPath; eRFPath++) + { +#if (defined RTL8192SE ||defined RTL8192SU ) + // For new T65 RF 0222d register 0x18 bit 0-9 = channel number. + rtl8192_phy_SetRFReg(dev, (RF90_RADIO_PATH_E)eRFPath, CurrentCmd->Para1, 0x1f, (CurrentCmd->Para2)); + //printk("====>%x, %x, read_back:%x\n", CurrentCmd->Para2,CurrentCmd->Para1, rtl8192_phy_QueryRFReg(dev, (RF90_RADIO_PATH_E)eRFPath, CurrentCmd->Para1, 0x1f)); +#else + rtl8192_phy_SetRFReg(dev, (RF90_RADIO_PATH_E)eRFPath, CurrentCmd->Para1, bRFRegOffsetMask, ((CurrentCmd->Para2)<<7)); +#endif + } + break; + default: + break; + } + + break; + }while(TRUE); + //cosa }/*for(Number of RF paths)*/ + + (*delay)=CurrentCmd->msDelay; + (*step)++; + RT_TRACE(COMP_CH, "<===========%s(), channel:%d, stage:%d, step:%d\n", __FUNCTION__, channel, *stage, *step); + return FALSE; +} + +//called PHY_SwChnlPhy8192S, SwChnlCallback8192SUsbWorkItem +// use in phy only +static void +phy_FinishSwChnlNow( // We should not call this function directly + struct net_device* dev, + u8 channel + ) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + u32 delay; + + while(!phy_SwChnlStepByStep(dev,channel,&priv->SwChnlStage,&priv->SwChnlStep,&delay)) + { + if(delay>0) + mdelay(delay); + if(!priv->up) + break; + } +} + + +/*----------------------------------------------------------------------------- + * Function: PHYCheckIsLegalRfPath8190Pci() + * + * Overview: Check different RF type to execute legal judgement. If RF Path is illegal + * We will return false. + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 11/15/2007 MHC Create Version 0. + * + *---------------------------------------------------------------------------*/ + //called by rtl8192_phy_QueryRFReg, rtl8192_phy_SetRFReg, PHY_SetRFPowerState8192SUsb +//extern bool +//PHY_CheckIsLegalRfPath8192S( +// struct net_device* dev, +// u32 eRFPath) +u8 rtl8192_phy_CheckIsLegalRFPath(struct net_device* dev, u32 eRFPath) +{ +// struct r8192_priv *priv = ieee80211_priv(dev); + bool rtValue = TRUE; + + // NOt check RF Path now.! +#if 0 + if (priv->rf_type == RF_1T2R && eRFPath != RF90_PATH_A) + { + rtValue = FALSE; + } + if (priv->rf_type == RF_1T2R && eRFPath != RF90_PATH_A) + { + + } +#endif + return rtValue; + +} /* PHY_CheckIsLegalRfPath8192S */ + + + +/*----------------------------------------------------------------------------- + * Function: PHY_IQCalibrate8192S() + * + * Overview: After all MAC/PHY/RF is configued. We must execute IQ calibration + * to improve RF EVM!!? + * + * Input: IN PADAPTER pAdapter + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 10/07/2008 MHC Create. Document from SD3 RFSI Jenyu. + * + *---------------------------------------------------------------------------*/ + //called by InitializeAdapter8192SE +void +PHY_IQCalibrate( struct net_device* dev) +{ + //struct r8192_priv *priv = ieee80211_priv(dev); + u32 i, reg; + u32 old_value; + long X, Y, TX0[4]; + u32 TXA[4]; + + // 1. Check QFN68 or 64 92S (Read from EEPROM) + + // + // 2. QFN 68 + // + // For 1T2R IQK only now !!! + for (i = 0; i < 10; i++) + { + // IQK + rtl8192_setBBreg(dev, 0xc04, bMaskDWord, 0x00a05430); + //PlatformStallExecution(5); + udelay(5); + rtl8192_setBBreg(dev, 0xc08, bMaskDWord, 0x000800e4); + udelay(5); + rtl8192_setBBreg(dev, 0xe28, bMaskDWord, 0x80800000); + udelay(5); + rtl8192_setBBreg(dev, 0xe40, bMaskDWord, 0x02140148); + udelay(5); + rtl8192_setBBreg(dev, 0xe44, bMaskDWord, 0x681604a2); + udelay(5); + rtl8192_setBBreg(dev, 0xe4c, bMaskDWord, 0x000028d1); + udelay(5); + rtl8192_setBBreg(dev, 0xe60, bMaskDWord, 0x0214014d); + udelay(5); + rtl8192_setBBreg(dev, 0xe64, bMaskDWord, 0x281608ba); + udelay(5); + rtl8192_setBBreg(dev, 0xe6c, bMaskDWord, 0x000028d1); + udelay(5); + rtl8192_setBBreg(dev, 0xe48, bMaskDWord, 0xfb000001); + udelay(5); + rtl8192_setBBreg(dev, 0xe48, bMaskDWord, 0xf8000001); + udelay(2000); + rtl8192_setBBreg(dev, 0xc04, bMaskDWord, 0x00a05433); + udelay(5); + rtl8192_setBBreg(dev, 0xc08, bMaskDWord, 0x000000e4); + udelay(5); + rtl8192_setBBreg(dev, 0xe28, bMaskDWord, 0x0); + + + reg = rtl8192_QueryBBReg(dev, 0xeac, bMaskDWord); + + // Readback IQK value and rewrite + if (!(reg&(BIT27|BIT28|BIT30|BIT31))) + { + old_value = (rtl8192_QueryBBReg(dev, 0xc80, bMaskDWord) & 0x3FF); + + // Calibrate init gain for A path for TX0 + X = (rtl8192_QueryBBReg(dev, 0xe94, bMaskDWord) & 0x03FF0000)>>16; + TXA[RF90_PATH_A] = (X * old_value)/0x100; + reg = rtl8192_QueryBBReg(dev, 0xc80, bMaskDWord); + reg = (reg & 0xFFFFFC00) | (u32)TXA[RF90_PATH_A]; + rtl8192_setBBreg(dev, 0xc80, bMaskDWord, reg); + udelay(5); + + // Calibrate init gain for C path for TX0 + Y = ( rtl8192_QueryBBReg(dev, 0xe9C, bMaskDWord) & 0x03FF0000)>>16; + TX0[RF90_PATH_C] = ((Y * old_value)/0x100); + reg = rtl8192_QueryBBReg(dev, 0xc80, bMaskDWord); + reg = (reg & 0xffc0ffff) |((u32) (TX0[RF90_PATH_C]&0x3F)<<16); + rtl8192_setBBreg(dev, 0xc80, bMaskDWord, reg); + reg = rtl8192_QueryBBReg(dev, 0xc94, bMaskDWord); + reg = (reg & 0x0fffffff) |(((Y&0x3c0)>>6)<<28); + rtl8192_setBBreg(dev, 0xc94, bMaskDWord, reg); + udelay(5); + + // Calibrate RX A and B for RX0 + reg = rtl8192_QueryBBReg(dev, 0xc14, bMaskDWord); + X = (rtl8192_QueryBBReg(dev, 0xea4, bMaskDWord) & 0x03FF0000)>>16; + reg = (reg & 0xFFFFFC00) |X; + rtl8192_setBBreg(dev, 0xc14, bMaskDWord, reg); + Y = (rtl8192_QueryBBReg(dev, 0xeac, bMaskDWord) & 0x003F0000)>>16; + reg = (reg & 0xFFFF03FF) |Y<<10; + rtl8192_setBBreg(dev, 0xc14, bMaskDWord, reg); + udelay(5); + old_value = (rtl8192_QueryBBReg(dev, 0xc88, bMaskDWord) & 0x3FF); + + // Calibrate init gain for A path for TX1 !!!!!! + X = (rtl8192_QueryBBReg(dev, 0xeb4, bMaskDWord) & 0x03FF0000)>>16; + reg = rtl8192_QueryBBReg(dev, 0xc88, bMaskDWord); + TXA[RF90_PATH_A] = (X * old_value) / 0x100; + reg = (reg & 0xFFFFFC00) | TXA[RF90_PATH_A]; + rtl8192_setBBreg(dev, 0xc88, bMaskDWord, reg); + udelay(5); + + // Calibrate init gain for C path for TX1 + Y = (rtl8192_QueryBBReg(dev, 0xebc, bMaskDWord)& 0x03FF0000)>>16; + TX0[RF90_PATH_C] = ((Y * old_value)/0x100); + reg = rtl8192_QueryBBReg(dev, 0xc88, bMaskDWord); + reg = (reg & 0xffc0ffff) |( (TX0[RF90_PATH_C]&0x3F)<<16); + rtl8192_setBBreg(dev, 0xc88, bMaskDWord, reg); + reg = rtl8192_QueryBBReg(dev, 0xc9c, bMaskDWord); + reg = (reg & 0x0fffffff) |(((Y&0x3c0)>>6)<<28); + rtl8192_setBBreg(dev, 0xc9c, bMaskDWord, reg); + udelay(5); + + // Calibrate RX A and B for RX1 + reg = rtl8192_QueryBBReg(dev, 0xc1c, bMaskDWord); + X = (rtl8192_QueryBBReg(dev, 0xec4, bMaskDWord) & 0x03FF0000)>>16; + reg = (reg & 0xFFFFFC00) |X; + rtl8192_setBBreg(dev, 0xc1c, bMaskDWord, reg); + + Y = (rtl8192_QueryBBReg(dev, 0xecc, bMaskDWord) & 0x003F0000)>>16; + reg = (reg & 0xFFFF03FF) |Y<<10; + rtl8192_setBBreg(dev, 0xc1c, bMaskDWord, reg); + udelay(5); + + RT_TRACE(COMP_INIT, "PHY_IQCalibrate OK\n"); + break; + } + + } + + + // + // 3. QFN64. Not enabled now !!! We must use different gain table for 1T2R. + // + + +} + +/*----------------------------------------------------------------------------- + * Function: PHY_IQCalibrateBcut() + * + * Overview: After all MAC/PHY/RF is configued. We must execute IQ calibration + * to improve RF EVM!!? + * + * Input: IN PADAPTER pAdapter + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 11/18/2008 MHC Create. Document from SD3 RFSI Jenyu. + * 92S B-cut QFN 68 pin IQ calibration procedure.doc + * + *---------------------------------------------------------------------------*/ +extern void PHY_IQCalibrateBcut(struct net_device* dev) +{ + //struct r8192_priv *priv = ieee80211_priv(dev); + //PMGNT_INFO pMgntInfo = &pAdapter->MgntInfo; + u32 i, reg; + u32 old_value; + long X, Y, TX0[4]; + u32 TXA[4]; + u32 calibrate_set[13] = {0}; + u32 load_value[13]; + u8 RfPiEnable=0; + + // 0. Check QFN68 or 64 92S (Read from EEPROM/EFUSE) + + // + // 1. Save e70~ee0 register setting, and load calibration setting + // + /* + 0xee0[31:0]=0x3fed92fb; + 0xedc[31:0] =0x3fed92fb; + 0xe70[31:0] =0x3fed92fb; + 0xe74[31:0] =0x3fed92fb; + 0xe78[31:0] =0x3fed92fb; + 0xe7c[31:0]= 0x3fed92fb; + 0xe80[31:0]= 0x3fed92fb; + 0xe84[31:0]= 0x3fed92fb; + 0xe88[31:0]= 0x3fed92fb; + 0xe8c[31:0]= 0x3fed92fb; + 0xed0[31:0]= 0x3fed92fb; + 0xed4[31:0]= 0x3fed92fb; + 0xed8[31:0]= 0x3fed92fb; + */ + calibrate_set [0] = 0xee0; + calibrate_set [1] = 0xedc; + calibrate_set [2] = 0xe70; + calibrate_set [3] = 0xe74; + calibrate_set [4] = 0xe78; + calibrate_set [5] = 0xe7c; + calibrate_set [6] = 0xe80; + calibrate_set [7] = 0xe84; + calibrate_set [8] = 0xe88; + calibrate_set [9] = 0xe8c; + calibrate_set [10] = 0xed0; + calibrate_set [11] = 0xed4; + calibrate_set [12] = 0xed8; + //RT_TRACE(COMP_INIT, DBG_LOUD, ("Save e70~ee0 register setting\n")); + for (i = 0; i < 13; i++) + { + load_value[i] = rtl8192_QueryBBReg(dev, calibrate_set[i], bMaskDWord); + rtl8192_setBBreg(dev, calibrate_set[i], bMaskDWord, 0x3fed92fb); + + } + + RfPiEnable = (u8)rtl8192_QueryBBReg(dev, rFPGA0_XA_HSSIParameter1, BIT8); + + // + // 2. QFN 68 + // + // For 1T2R IQK only now !!! + for (i = 0; i < 10; i++) + { + RT_TRACE(COMP_INIT, "IQK -%d\n", i); + //BB switch to PI mode. If default is PI mode, ignoring 2 commands below. + if (!RfPiEnable) //if original is SI mode, then switch to PI mode. + { + //DbgPrint("IQK Switch to PI mode\n"); + rtl8192_setBBreg(dev, 0x820, bMaskDWord, 0x01000100); + rtl8192_setBBreg(dev, 0x828, bMaskDWord, 0x01000100); + } + + // IQK + // 2. IQ calibration & LO leakage calibration + rtl8192_setBBreg(dev, 0xc04, bMaskDWord, 0x00a05430); + udelay(5); + rtl8192_setBBreg(dev, 0xc08, bMaskDWord, 0x000800e4); + udelay(5); + rtl8192_setBBreg(dev, 0xe28, bMaskDWord, 0x80800000); + udelay(5); + //path-A IQ K and LO K gain setting + rtl8192_setBBreg(dev, 0xe40, bMaskDWord, 0x02140102); + udelay(5); + rtl8192_setBBreg(dev, 0xe44, bMaskDWord, 0x681604c2); + udelay(5); + //set LO calibration + rtl8192_setBBreg(dev, 0xe4c, bMaskDWord, 0x000028d1); + udelay(5); + //path-B IQ K and LO K gain setting + rtl8192_setBBreg(dev, 0xe60, bMaskDWord, 0x02140102); + udelay(5); + rtl8192_setBBreg(dev, 0xe64, bMaskDWord, 0x28160d05); + udelay(5); + //K idac_I & IQ + rtl8192_setBBreg(dev, 0xe48, bMaskDWord, 0xfb000000); + udelay(5); + rtl8192_setBBreg(dev, 0xe48, bMaskDWord, 0xf8000000); + udelay(5); + + // delay 2ms + udelay(2000); + + //idac_Q setting + rtl8192_setBBreg(dev, 0xe6c, bMaskDWord, 0x020028d1); + udelay(5); + //K idac_Q & IQ + rtl8192_setBBreg(dev, 0xe48, bMaskDWord, 0xfb000000); + udelay(5); + rtl8192_setBBreg(dev, 0xe48, bMaskDWord, 0xf8000000); + + // delay 2ms + udelay(2000); + + rtl8192_setBBreg(dev, 0xc04, bMaskDWord, 0x00a05433); + udelay(5); + rtl8192_setBBreg(dev, 0xc08, bMaskDWord, 0x000000e4); + udelay(5); + rtl8192_setBBreg(dev, 0xe28, bMaskDWord, 0x0); + + if (!RfPiEnable) //if original is SI mode, then switch to PI mode. + { + //DbgPrint("IQK Switch back to SI mode\n"); + rtl8192_setBBreg(dev, 0x820, bMaskDWord, 0x01000000); + rtl8192_setBBreg(dev, 0x828, bMaskDWord, 0x01000000); + } + + + reg = rtl8192_QueryBBReg(dev, 0xeac, bMaskDWord); + + // 3. check fail bit, and fill BB IQ matrix + // Readback IQK value and rewrite + if (!(reg&(BIT27|BIT28|BIT30|BIT31))) + { + old_value = (rtl8192_QueryBBReg(dev, 0xc80, bMaskDWord) & 0x3FF); + + // Calibrate init gain for A path for TX0 + X = (rtl8192_QueryBBReg(dev, 0xe94, bMaskDWord) & 0x03FF0000)>>16; + TXA[RF90_PATH_A] = (X * old_value)/0x100; + reg = rtl8192_QueryBBReg(dev, 0xc80, bMaskDWord); + reg = (reg & 0xFFFFFC00) | (u32)TXA[RF90_PATH_A]; + rtl8192_setBBreg(dev, 0xc80, bMaskDWord, reg); + udelay(5); + + // Calibrate init gain for C path for TX0 + Y = ( rtl8192_QueryBBReg(dev, 0xe9C, bMaskDWord) & 0x03FF0000)>>16; + TX0[RF90_PATH_C] = ((Y * old_value)/0x100); + reg = rtl8192_QueryBBReg(dev, 0xc80, bMaskDWord); + reg = (reg & 0xffc0ffff) |((u32) (TX0[RF90_PATH_C]&0x3F)<<16); + rtl8192_setBBreg(dev, 0xc80, bMaskDWord, reg); + reg = rtl8192_QueryBBReg(dev, 0xc94, bMaskDWord); + reg = (reg & 0x0fffffff) |(((Y&0x3c0)>>6)<<28); + rtl8192_setBBreg(dev, 0xc94, bMaskDWord, reg); + udelay(5); + + // Calibrate RX A and B for RX0 + reg = rtl8192_QueryBBReg(dev, 0xc14, bMaskDWord); + X = (rtl8192_QueryBBReg(dev, 0xea4, bMaskDWord) & 0x03FF0000)>>16; + reg = (reg & 0xFFFFFC00) |X; + rtl8192_setBBreg(dev, 0xc14, bMaskDWord, reg); + Y = (rtl8192_QueryBBReg(dev, 0xeac, bMaskDWord) & 0x003F0000)>>16; + reg = (reg & 0xFFFF03FF) |Y<<10; + rtl8192_setBBreg(dev, 0xc14, bMaskDWord, reg); + udelay(5); + old_value = (rtl8192_QueryBBReg(dev, 0xc88, bMaskDWord) & 0x3FF); + + // Calibrate init gain for A path for TX1 !!!!!! + X = (rtl8192_QueryBBReg(dev, 0xeb4, bMaskDWord) & 0x03FF0000)>>16; + reg = rtl8192_QueryBBReg(dev, 0xc88, bMaskDWord); + TXA[RF90_PATH_A] = (X * old_value) / 0x100; + reg = (reg & 0xFFFFFC00) | TXA[RF90_PATH_A]; + rtl8192_setBBreg(dev, 0xc88, bMaskDWord, reg); + udelay(5); + + // Calibrate init gain for C path for TX1 + Y = (rtl8192_QueryBBReg(dev, 0xebc, bMaskDWord)& 0x03FF0000)>>16; + TX0[RF90_PATH_C] = ((Y * old_value)/0x100); + reg = rtl8192_QueryBBReg(dev, 0xc88, bMaskDWord); + reg = (reg & 0xffc0ffff) |( (TX0[RF90_PATH_C]&0x3F)<<16); + rtl8192_setBBreg(dev, 0xc88, bMaskDWord, reg); + reg = rtl8192_QueryBBReg(dev, 0xc9c, bMaskDWord); + reg = (reg & 0x0fffffff) |(((Y&0x3c0)>>6)<<28); + rtl8192_setBBreg(dev, 0xc9c, bMaskDWord, reg); + udelay(5); + + // Calibrate RX A and B for RX1 + reg = rtl8192_QueryBBReg(dev, 0xc1c, bMaskDWord); + X = (rtl8192_QueryBBReg(dev, 0xec4, bMaskDWord) & 0x03FF0000)>>16; + reg = (reg & 0xFFFFFC00) |X; + rtl8192_setBBreg(dev, 0xc1c, bMaskDWord, reg); + + Y = (rtl8192_QueryBBReg(dev, 0xecc, bMaskDWord) & 0x003F0000)>>16; + reg = (reg & 0xFFFF03FF) |Y<<10; + rtl8192_setBBreg(dev, 0xc1c, bMaskDWord, reg); + udelay(5); + + RT_TRACE(COMP_INIT, "PHY_IQCalibrate OK\n"); + break; + } + + } + + // + // 4. Reload e70~ee0 register setting. + // + //RT_TRACE(COMP_INIT, DBG_LOUD, ("Reload e70~ee0 register setting.\n")); + for (i = 0; i < 13; i++) + rtl8192_setBBreg(dev, calibrate_set[i], bMaskDWord, load_value[i]); + + + // + // 3. QFN64. Not enabled now !!! We must use different gain table for 1T2R. + // + + + +} // PHY_IQCalibrateBcut + + +// +// Move from phycfg.c to gen.c to be code independent later +// +//-------------------------Move to other DIR later----------------------------*/ +//#if (DEV_BUS_TYPE == USB_INTERFACE) +#ifdef RTL8192SU + +// use in phy only (in win it's timer) +void SwChnlCallback8192SUsb(struct net_device *dev) +{ + + struct r8192_priv *priv = ieee80211_priv(dev); + u32 delay; +// bool ret; + + RT_TRACE(COMP_SCAN, "==>SwChnlCallback8190Pci(), switch to channel\ + %d\n", priv->chan); + + + if(!priv->up) + return; + + if(priv->rf_chip == RF_PSEUDO_11N) + { + priv->SwChnlInProgress=FALSE; + return; //return immediately if it is peudo-phy + } + + do{ + if(!priv->SwChnlInProgress) + break; + + if(!phy_SwChnlStepByStep(dev, priv->chan, &priv->SwChnlStage, &priv->SwChnlStep, &delay)) + { + if(delay>0) + { + //PlatformSetTimer(dev, &priv->SwChnlTimer, delay); + + } + else + continue; + } + else + { + priv->SwChnlInProgress=FALSE; + } + break; + }while(TRUE); +} + + +// +// Callback routine of the work item for switch channel. +// +// use in phy only (in win it's work) +void SwChnlCallback8192SUsbWorkItem(struct net_device *dev ) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + + RT_TRACE(COMP_TRACE, "==> SwChnlCallback8192SUsbWorkItem()\n"); +#ifdef TO_DO_LIST + if(pAdapter->bInSetPower && RT_USB_CANNOT_IO(pAdapter)) + { + RT_TRACE(COMP_SCAN, DBG_LOUD, ("<== SwChnlCallback8192SUsbWorkItem() SwChnlInProgress FALSE driver sleep or unload\n")); + + pHalData->SwChnlInProgress = FALSE; + return; + } +#endif + phy_FinishSwChnlNow(dev, priv->chan); + priv->SwChnlInProgress = FALSE; + + RT_TRACE(COMP_TRACE, "<== SwChnlCallback8192SUsbWorkItem()\n"); +} + + +/*----------------------------------------------------------------------------- + * Function: SetBWModeCallback8192SUsb() + * + * Overview: Timer callback function for SetSetBWMode + * + * Input: PRT_TIMER pTimer + * + * Output: NONE + * + * Return: NONE + * + * Note: (1) We do not take j mode into consideration now + * (2) Will two workitem of "switch channel" and "switch channel bandwidth" run + * concurrently? + *---------------------------------------------------------------------------*/ +//====>//rtl8192_SetBWMode +// use in phy only (in win it's timer) +void SetBWModeCallback8192SUsb(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + u8 regBwOpMode; + + // Added it for 20/40 mhz switch time evaluation by guangan 070531 + //u32 NowL, NowH; + //u8Byte BeginTime, EndTime; + u8 regRRSR_RSC; + + RT_TRACE(COMP_SCAN, "==>SetBWModeCallback8190Pci() Switch to %s bandwidth\n", \ + priv->CurrentChannelBW == HT_CHANNEL_WIDTH_20?"20MHz":"40MHz"); + + if(priv->rf_chip == RF_PSEUDO_11N) + { + priv->SetBWModeInProgress= FALSE; + return; + } + + if(!priv->up) + return; + + // Added it for 20/40 mhz switch time evaluation by guangan 070531 + //NowL = read_nic_dword(dev, TSFR); + //NowH = read_nic_dword(dev, TSFR+4); + //BeginTime = ((u8Byte)NowH << 32) + NowL; + + //3<1>Set MAC register + regBwOpMode = read_nic_byte(dev, BW_OPMODE); + regRRSR_RSC = read_nic_byte(dev, RRSR+2); + + switch(priv->CurrentChannelBW) + { + case HT_CHANNEL_WIDTH_20: + regBwOpMode |= BW_OPMODE_20MHZ; + // 2007/02/07 Mark by Emily becasue we have not verify whether this register works + write_nic_byte(dev, BW_OPMODE, regBwOpMode); + break; + + case HT_CHANNEL_WIDTH_20_40: + regBwOpMode &= ~BW_OPMODE_20MHZ; + // 2007/02/07 Mark by Emily becasue we have not verify whether this register works + write_nic_byte(dev, BW_OPMODE, regBwOpMode); + + regRRSR_RSC = (regRRSR_RSC&0x90) |(priv->nCur40MhzPrimeSC<<5); + write_nic_byte(dev, RRSR+2, regRRSR_RSC); + break; + + default: + RT_TRACE(COMP_DBG, "SetChannelBandwidth8190Pci():\ + unknown Bandwidth: %#X\n",priv->CurrentChannelBW); + break; + } + + //3 <2>Set PHY related register + switch(priv->CurrentChannelBW) + { + case HT_CHANNEL_WIDTH_20: + rtl8192_setBBreg(dev, rFPGA0_RFMOD, bRFMOD, 0x0); + rtl8192_setBBreg(dev, rFPGA1_RFMOD, bRFMOD, 0x0); + #if 0 //LZM090219 + rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x00300000, 3); + + // Correct the tx power for CCK rate in 20M. Suggest by YN, 20071207 + //write_nic_dword(dev, rCCK0_TxFilter1, 0x1a1b0000); + //write_nic_dword(dev, rCCK0_TxFilter2, 0x090e1317); + //write_nic_dword(dev, rCCK0_DebugPort, 0x00000204); + rtl8192_setBBreg(dev, rCCK0_TxFilter1, bMaskDWord, 0x1a1b0000); + rtl8192_setBBreg(dev, rCCK0_TxFilter2, bMaskDWord, 0x090e1317); + rtl8192_setBBreg(dev, rCCK0_DebugPort, bMaskDWord, 0x00000204); + rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x00300000, 3); + #endif + + if (priv->card_8192_version >= VERSION_8192S_BCUT) + rtl8192_setBBreg(dev, rFPGA0_AnalogParameter2, 0xff, 0x58); + + break; + case HT_CHANNEL_WIDTH_20_40: + rtl8192_setBBreg(dev, rFPGA0_RFMOD, bRFMOD, 0x1); + rtl8192_setBBreg(dev, rFPGA1_RFMOD, bRFMOD, 0x1); + rtl8192_setBBreg(dev, rCCK0_System, bCCKSideBand, (priv->nCur40MhzPrimeSC>>1)); + rtl8192_setBBreg(dev, rOFDM1_LSTF, 0xC00, priv->nCur40MhzPrimeSC); + + // Correct the tx power for CCK rate in 40M. Suggest by YN, 20071207 + //PHY_SetBBReg(Adapter, rCCK0_TxFilter1, bMaskDWord, 0x35360000); + //PHY_SetBBReg(Adapter, rCCK0_TxFilter2, bMaskDWord, 0x121c252e); + //PHY_SetBBReg(Adapter, rCCK0_DebugPort, bMaskDWord, 0x00000409); + //PHY_SetBBReg(Adapter, rFPGA0_AnalogParameter1, bADClkPhase, 0); + + if (priv->card_8192_version >= VERSION_8192S_BCUT) + rtl8192_setBBreg(dev, rFPGA0_AnalogParameter2, 0xff, 0x18); + + break; + default: + RT_TRACE(COMP_DBG, "SetChannelBandwidth8190Pci(): unknown Bandwidth: %#X\n"\ + ,priv->CurrentChannelBW); + break; + + } + //Skip over setting of J-mode in BB register here. Default value is "None J mode". Emily 20070315 + + // Added it for 20/40 mhz switch time evaluation by guangan 070531 + //NowL = read_nic_dword(dev, TSFR); + //NowH = read_nic_dword(dev, TSFR+4); + //EndTime = ((u8Byte)NowH << 32) + NowL; + //RT_TRACE(COMP_SCAN, DBG_LOUD, ("SetBWModeCallback8190Pci: time of SetBWMode = %I64d us!\n", (EndTime - BeginTime))); + +#if 1 + //3<3>Set RF related register + switch( priv->rf_chip ) + { + case RF_8225: + PHY_SetRF8225Bandwidth(dev, priv->CurrentChannelBW); + break; + + case RF_8256: + // Please implement this function in Hal8190PciPhy8256.c + //PHY_SetRF8256Bandwidth(dev, priv->CurrentChannelBW); + break; + + case RF_6052: + PHY_RF6052SetBandwidth(dev, priv->CurrentChannelBW); + break; + + case RF_8258: + // Please implement this function in Hal8190PciPhy8258.c + // PHY_SetRF8258Bandwidth(); + break; + + case RF_PSEUDO_11N: + // Do Nothing + break; + + default: + //RT_ASSERT(FALSE, ("Unknown rf_chip: %d\n", priv->rf_chip)); + break; + } +#endif + priv->SetBWModeInProgress= FALSE; + + RT_TRACE(COMP_SCAN, "<==SetBWMode8190Pci()" ); +} + +// +// Callback routine of the work item for set bandwidth mode. +// +// use in phy only (in win it's work) +void SetBWModeCallback8192SUsbWorkItem(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + u8 regBwOpMode; + + // Added it for 20/40 mhz switch time evaluation by guangan 070531 + //u32 NowL, NowH; + //u8Byte BeginTime, EndTime; + u8 regRRSR_RSC; + + RT_TRACE(COMP_SCAN, "==>SetBWModeCallback8192SUsbWorkItem() Switch to %s bandwidth\n", \ + priv->CurrentChannelBW == HT_CHANNEL_WIDTH_20?"20MHz":"40MHz"); + + if(priv->rf_chip == RF_PSEUDO_11N) + { + priv->SetBWModeInProgress= FALSE; + return; + } + + if(!priv->up) + return; + + // Added it for 20/40 mhz switch time evaluation by guangan 070531 + //NowL = read_nic_dword(dev, TSFR); + //NowH = read_nic_dword(dev, TSFR+4); + //BeginTime = ((u8Byte)NowH << 32) + NowL; + + //3<1>Set MAC register + regBwOpMode = read_nic_byte(dev, BW_OPMODE); + regRRSR_RSC = read_nic_byte(dev, RRSR+2); + + switch(priv->CurrentChannelBW) + { + case HT_CHANNEL_WIDTH_20: + regBwOpMode |= BW_OPMODE_20MHZ; + // 2007/02/07 Mark by Emily becasue we have not verify whether this register works + write_nic_byte(dev, BW_OPMODE, regBwOpMode); + break; + + case HT_CHANNEL_WIDTH_20_40: + regBwOpMode &= ~BW_OPMODE_20MHZ; + // 2007/02/07 Mark by Emily becasue we have not verify whether this register works + write_nic_byte(dev, BW_OPMODE, regBwOpMode); + regRRSR_RSC = (regRRSR_RSC&0x90) |(priv->nCur40MhzPrimeSC<<5); + write_nic_byte(dev, RRSR+2, regRRSR_RSC); + + break; + + default: + RT_TRACE(COMP_DBG, "SetBWModeCallback8192SUsbWorkItem():\ + unknown Bandwidth: %#X\n",priv->CurrentChannelBW); + break; + } + + //3 <2>Set PHY related register + switch(priv->CurrentChannelBW) + { + case HT_CHANNEL_WIDTH_20: + rtl8192_setBBreg(dev, rFPGA0_RFMOD, bRFMOD, 0x0); + rtl8192_setBBreg(dev, rFPGA1_RFMOD, bRFMOD, 0x0); + + #if 0 //LZM 090219 + rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, bADClkPhase, 1); + + // Correct the tx power for CCK rate in 20M. Suggest by YN, 20071207 + rtl8192_setBBreg(dev, rCCK0_TxFilter1, bMaskDWord, 0x1a1b0000); + rtl8192_setBBreg(dev, rCCK0_TxFilter2, bMaskDWord, 0x090e1317); + rtl8192_setBBreg(dev, rCCK0_DebugPort, bMaskDWord, 0x00000204); + rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x00100000, 1); + #endif + + rtl8192_setBBreg(dev, rFPGA0_AnalogParameter2, 0xff, 0x58); + + break; + case HT_CHANNEL_WIDTH_20_40: + rtl8192_setBBreg(dev, rFPGA0_RFMOD, bRFMOD, 0x1); + rtl8192_setBBreg(dev, rFPGA1_RFMOD, bRFMOD, 0x1); + #if 0 //LZM 090219 + rtl8192_setBBreg(dev, rCCK0_System, bCCKSideBand, (priv->nCur40MhzPrimeSC>>1)); + + rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, bADClkPhase, 0); + + rtl8192_setBBreg(dev, rOFDM1_LSTF, 0xC00, priv->nCur40MhzPrimeSC); + // Correct the tx power for CCK rate in 40M. Suggest by YN, 20071207 + rtl8192_setBBreg(dev, rCCK0_TxFilter1, bMaskDWord, 0x35360000); + rtl8192_setBBreg(dev, rCCK0_TxFilter2, bMaskDWord, 0x121c252e); + rtl8192_setBBreg(dev, rCCK0_DebugPort, bMaskDWord, 0x00000409); + #endif + + // Set Control channel to upper or lower. These settings are required only for 40MHz + rtl8192_setBBreg(dev, rCCK0_System, bCCKSideBand, (priv->nCur40MhzPrimeSC>>1)); + rtl8192_setBBreg(dev, rOFDM1_LSTF, 0xC00, priv->nCur40MhzPrimeSC); + + rtl8192_setBBreg(dev, rFPGA0_AnalogParameter2, 0xff, 0x18); + + break; + + + default: + RT_TRACE(COMP_DBG, "SetBWModeCallback8192SUsbWorkItem(): unknown Bandwidth: %#X\n"\ + ,priv->CurrentChannelBW); + break; + + } + //Skip over setting of J-mode in BB register here. Default value is "None J mode". Emily 20070315 + + //3<3>Set RF related register + switch( priv->rf_chip ) + { + case RF_8225: + PHY_SetRF8225Bandwidth(dev, priv->CurrentChannelBW); + break; + + case RF_8256: + // Please implement this function in Hal8190PciPhy8256.c + //PHY_SetRF8256Bandwidth(dev, priv->CurrentChannelBW); + break; + + case RF_6052: + PHY_RF6052SetBandwidth(dev, priv->CurrentChannelBW); + break; + + case RF_8258: + // Please implement this function in Hal8190PciPhy8258.c + // PHY_SetRF8258Bandwidth(); + break; + + case RF_PSEUDO_11N: + // Do Nothing + break; + + default: + //RT_ASSERT(FALSE, ("Unknown rf_chip: %d\n", priv->rf_chip)); + break; + } + + priv->SetBWModeInProgress= FALSE; + + RT_TRACE(COMP_SCAN, "<==SetBWModeCallback8192SUsbWorkItem()" ); +} + +//--------------------------Move to oter DIR later-------------------------------*/ +#ifdef RTL8192SU +void InitialGain8192S(struct net_device *dev, u8 Operation) +{ +#ifdef TO_DO_LIST + struct r8192_priv *priv = ieee80211_priv(dev); +#endif + +} +#endif + +void InitialGain819xUsb(struct net_device *dev, u8 Operation) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + + priv->InitialGainOperateType = Operation; + + if(priv->up) + { + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + queue_delayed_work(priv->priv_wq,&priv->initialgain_operate_wq,0); + #else + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + schedule_task(&priv->initialgain_operate_wq); + #else + queue_work(priv->priv_wq,&priv->initialgain_operate_wq); + #endif + #endif + } +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) +extern void InitialGainOperateWorkItemCallBack(struct work_struct *work) +{ + struct delayed_work *dwork = container_of(work,struct delayed_work,work); + struct r8192_priv *priv = container_of(dwork,struct r8192_priv,initialgain_operate_wq); + struct net_device *dev = priv->ieee80211->dev; +#else +extern void InitialGainOperateWorkItemCallBack(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); +#endif +#define SCAN_RX_INITIAL_GAIN 0x17 +#define POWER_DETECTION_TH 0x08 + u32 BitMask; + u8 initial_gain; + u8 Operation; + + Operation = priv->InitialGainOperateType; + + switch(Operation) + { + case IG_Backup: + RT_TRACE(COMP_SCAN, "IG_Backup, backup the initial gain.\n"); + initial_gain = SCAN_RX_INITIAL_GAIN;//priv->DefaultInitialGain[0];// + BitMask = bMaskByte0; + if(dm_digtable.dig_algorithm == DIG_ALGO_BY_FALSE_ALARM) + rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x8); // FW DIG OFF + priv->initgain_backup.xaagccore1 = (u8)rtl8192_QueryBBReg(dev, rOFDM0_XAAGCCore1, BitMask); + priv->initgain_backup.xbagccore1 = (u8)rtl8192_QueryBBReg(dev, rOFDM0_XBAGCCore1, BitMask); + priv->initgain_backup.xcagccore1 = (u8)rtl8192_QueryBBReg(dev, rOFDM0_XCAGCCore1, BitMask); + priv->initgain_backup.xdagccore1 = (u8)rtl8192_QueryBBReg(dev, rOFDM0_XDAGCCore1, BitMask); + BitMask = bMaskByte2; + priv->initgain_backup.cca = (u8)rtl8192_QueryBBReg(dev, rCCK0_CCA, BitMask); + + RT_TRACE(COMP_SCAN, "Scan InitialGainBackup 0xc50 is %x\n",priv->initgain_backup.xaagccore1); + RT_TRACE(COMP_SCAN, "Scan InitialGainBackup 0xc58 is %x\n",priv->initgain_backup.xbagccore1); + RT_TRACE(COMP_SCAN, "Scan InitialGainBackup 0xc60 is %x\n",priv->initgain_backup.xcagccore1); + RT_TRACE(COMP_SCAN, "Scan InitialGainBackup 0xc68 is %x\n",priv->initgain_backup.xdagccore1); + RT_TRACE(COMP_SCAN, "Scan InitialGainBackup 0xa0a is %x\n",priv->initgain_backup.cca); + + RT_TRACE(COMP_SCAN, "Write scan initial gain = 0x%x \n", initial_gain); + write_nic_byte(dev, rOFDM0_XAAGCCore1, initial_gain); + write_nic_byte(dev, rOFDM0_XBAGCCore1, initial_gain); + write_nic_byte(dev, rOFDM0_XCAGCCore1, initial_gain); + write_nic_byte(dev, rOFDM0_XDAGCCore1, initial_gain); + RT_TRACE(COMP_SCAN, "Write scan 0xa0a = 0x%x \n", POWER_DETECTION_TH); + write_nic_byte(dev, 0xa0a, POWER_DETECTION_TH); + break; + case IG_Restore: + RT_TRACE(COMP_SCAN, "IG_Restore, restore the initial gain.\n"); + BitMask = 0x7f; //Bit0~ Bit6 + if(dm_digtable.dig_algorithm == DIG_ALGO_BY_FALSE_ALARM) + rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x8); // FW DIG OFF + + rtl8192_setBBreg(dev, rOFDM0_XAAGCCore1, BitMask, (u32)priv->initgain_backup.xaagccore1); + rtl8192_setBBreg(dev, rOFDM0_XBAGCCore1, BitMask, (u32)priv->initgain_backup.xbagccore1); + rtl8192_setBBreg(dev, rOFDM0_XCAGCCore1, BitMask, (u32)priv->initgain_backup.xcagccore1); + rtl8192_setBBreg(dev, rOFDM0_XDAGCCore1, BitMask, (u32)priv->initgain_backup.xdagccore1); + BitMask = bMaskByte2; + rtl8192_setBBreg(dev, rCCK0_CCA, BitMask, (u32)priv->initgain_backup.cca); + + RT_TRACE(COMP_SCAN, "Scan BBInitialGainRestore 0xc50 is %x\n",priv->initgain_backup.xaagccore1); + RT_TRACE(COMP_SCAN, "Scan BBInitialGainRestore 0xc58 is %x\n",priv->initgain_backup.xbagccore1); + RT_TRACE(COMP_SCAN, "Scan BBInitialGainRestore 0xc60 is %x\n",priv->initgain_backup.xcagccore1); + RT_TRACE(COMP_SCAN, "Scan BBInitialGainRestore 0xc68 is %x\n",priv->initgain_backup.xdagccore1); + RT_TRACE(COMP_SCAN, "Scan BBInitialGainRestore 0xa0a is %x\n",priv->initgain_backup.cca); + + PHY_SetTxPowerLevel8192S(dev,priv->ieee80211->current_network.channel); + + if(dm_digtable.dig_algorithm == DIG_ALGO_BY_FALSE_ALARM) + rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x1); // FW DIG ON + break; + default: + RT_TRACE(COMP_SCAN, "Unknown IG Operation. \n"); + break; + } +} + +#endif // #if (DEV_BUS_TYPE == USB_INTERFACE) + +//----------------------------------------------------------------------------- +// Description: +// Schedule workitem to send specific CMD IO to FW. +// Added by Roger, 2008.12.03. +// +//----------------------------------------------------------------------------- +bool HalSetFwCmd8192S(struct net_device* dev, FW_CMD_IO_TYPE FwCmdIO) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + u16 FwCmdWaitCounter = 0; + + u16 FwCmdWaitLimit = 1000; + + //if(IS_HARDWARE_TYPE_8192SU(Adapter) && Adapter->bInHctTest) + if(priv->bInHctTest) + return true; + + RT_TRACE(COMP_CMD, "-->HalSetFwCmd8192S(): Set FW Cmd(%x), SetFwCmdInProgress(%d)\n", (u32)FwCmdIO, priv->SetFwCmdInProgress); + + // Will be done by high power respectively. + if(FwCmdIO==FW_CMD_DIG_HALT || FwCmdIO==FW_CMD_DIG_RESUME) + { + RT_TRACE(COMP_CMD, "<--HalSetFwCmd8192S(): Set FW Cmd(%x)\n", (u32)FwCmdIO); + return false; + } + +#if 1 + while(priv->SetFwCmdInProgress && FwCmdWaitCounterSetFwCmdInProgress) + { + RT_TRACE(COMP_ERR, "<--HalSetFwCmd8192S(): Set FW Cmd(%#x)\n", FwCmdIO); + return false; + } + priv->SetFwCmdInProgress = TRUE; + priv->CurrentFwCmdIO = FwCmdIO; // Update current FW Cmd for callback use. + + phy_SetFwCmdIOCallback(dev); + return true; +} +void ChkFwCmdIoDone(struct net_device* dev) +{ + u16 PollingCnt = 1000; + u32 tmpValue; + + do + {// Make sure that CMD IO has be accepted by FW. +#ifdef TO_DO_LIST + if(RT_USB_CANNOT_IO(Adapter)) + { + RT_TRACE(COMP_CMD, "ChkFwCmdIoDone(): USB can NOT IO!!\n"); + return; + } +#endif + udelay(10); // sleep 20us + tmpValue = read_nic_dword(dev, WFM5); + if(tmpValue == 0) + { + RT_TRACE(COMP_CMD, "[FW CMD] Set FW Cmd success!!\n"); + break; + } + else + { + RT_TRACE(COMP_CMD, "[FW CMD] Polling FW Cmd PollingCnt(%d)!!\n", PollingCnt); + } + }while( --PollingCnt ); + + if(PollingCnt == 0) + { + RT_TRACE(COMP_ERR, "[FW CMD] Set FW Cmd fail!!\n"); + } +} +// Callback routine of the timer callback for FW Cmd IO. +// +// Description: +// This routine will send specific CMD IO to FW and check whether it is done. +// +void phy_SetFwCmdIOCallback(struct net_device* dev) +{ + //struct net_device* dev = (struct net_device*) data; + u32 input; + static u32 ScanRegister; + struct r8192_priv *priv = ieee80211_priv(dev); + if(!priv->up) + { + RT_TRACE(COMP_CMD, "SetFwCmdIOTimerCallback(): driver is going to unload\n"); + return; + } + + RT_TRACE(COMP_CMD, "--->SetFwCmdIOTimerCallback(): Cmd(%#x), SetFwCmdInProgress(%d)\n", priv->CurrentFwCmdIO, priv->SetFwCmdInProgress); + + switch(priv->CurrentFwCmdIO) + { + case FW_CMD_HIGH_PWR_ENABLE: + if((priv->ieee80211->pHTInfo->IOTAction & HT_IOT_ACT_DISABLE_HIGH_POWER)==0) + write_nic_dword(dev, WFM5, FW_HIGH_PWR_ENABLE); + break; + + case FW_CMD_HIGH_PWR_DISABLE: + write_nic_dword(dev, WFM5, FW_HIGH_PWR_DISABLE); + break; + + case FW_CMD_DIG_RESUME: + write_nic_dword(dev, WFM5, FW_DIG_RESUME); + break; + + case FW_CMD_DIG_HALT: + write_nic_dword(dev, WFM5, FW_DIG_HALT); + break; + + // + // The following FW CMD IO was combined into single operation + // (i.e., to prevent number of system workitem out of resource!!). + // 2008.12.04. + // + case FW_CMD_RESUME_DM_BY_SCAN: + RT_TRACE(COMP_CMD, "[FW CMD] Set HIGHPWR enable and DIG resume!!\n"); + if((priv->ieee80211->pHTInfo->IOTAction & HT_IOT_ACT_DISABLE_HIGH_POWER)==0) + { + write_nic_dword(dev, WFM5, FW_HIGH_PWR_ENABLE); //break; + ChkFwCmdIoDone(dev); + } + write_nic_dword(dev, WFM5, FW_DIG_RESUME); + break; + + case FW_CMD_PAUSE_DM_BY_SCAN: + RT_TRACE(COMP_CMD, "[FW CMD] Set HIGHPWR disable and DIG halt!!\n"); + write_nic_dword(dev, WFM5, FW_HIGH_PWR_DISABLE); //break; + ChkFwCmdIoDone(dev); + write_nic_dword(dev, WFM5, FW_DIG_HALT); + break; + + // + // The following FW CMD IO should be checked + // (i.e., workitem schedule timing issue!!). + // 2008.12.04. + // + case FW_CMD_DIG_DISABLE: + RT_TRACE(COMP_CMD, "[FW CMD] Set DIG disable!!\n"); + write_nic_dword(dev, WFM5, FW_DIG_DISABLE); + break; + + case FW_CMD_DIG_ENABLE: + RT_TRACE(COMP_CMD, "[FW CMD] Set DIG enable!!\n"); + write_nic_dword(dev, WFM5, FW_DIG_ENABLE); + break; + + case FW_CMD_RA_RESET: + write_nic_dword(dev, WFM5, FW_RA_RESET); + break; + + case FW_CMD_RA_ACTIVE: + write_nic_dword(dev, WFM5, FW_RA_ACTIVE); + break; + + case FW_CMD_RA_REFRESH_N: + RT_TRACE(COMP_CMD, "[FW CMD] Set RA refresh!! N\n"); + if(priv->ieee80211->pHTInfo->IOTRaFunc & HT_IOT_RAFUNC_DISABLE_ALL) + input = FW_RA_REFRESH; + else + input = FW_RA_REFRESH | (priv->ieee80211->pHTInfo->IOTRaFunc << 8); + write_nic_dword(dev, WFM5, input); + break; + case FW_CMD_RA_REFRESH_BG: + RT_TRACE(COMP_CMD, "[FW CMD] Set RA refresh!! B/G\n"); + write_nic_dword(dev, WFM5, FW_RA_REFRESH); + ChkFwCmdIoDone(dev); + write_nic_dword(dev, WFM5, FW_RA_ENABLE_BG); + break; + + case FW_CMD_IQK_ENABLE: + write_nic_dword(dev, WFM5, FW_IQK_ENABLE); + break; + + case FW_CMD_TXPWR_TRACK_ENABLE: + write_nic_dword(dev, WFM5, FW_TXPWR_TRACK_ENABLE); + break; + + case FW_CMD_TXPWR_TRACK_DISABLE: + write_nic_dword(dev, WFM5, FW_TXPWR_TRACK_DISABLE); + break; + + default: + RT_TRACE(COMP_CMD,"Unknown FW Cmd IO(%#x)\n", priv->CurrentFwCmdIO); + break; + } + + ChkFwCmdIoDone(dev); + + switch(priv->CurrentFwCmdIO) + { + case FW_CMD_HIGH_PWR_DISABLE: + //if(pMgntInfo->bTurboScan) + { + //Lower initial gain + rtl8192_setBBreg(dev, rOFDM0_XAAGCCore1, bMaskByte0, 0x17); + rtl8192_setBBreg(dev, rOFDM0_XBAGCCore1, bMaskByte0, 0x17); + // CCA threshold + rtl8192_setBBreg(dev, rCCK0_CCA, bMaskByte2, 0x40); + // Disable OFDM Part + rtl8192_setBBreg(dev, rOFDM0_TRMuxPar, bMaskByte2, 0x1); + ScanRegister = rtl8192_QueryBBReg(dev, rOFDM0_RxDetector1,bMaskDWord); + rtl8192_setBBreg(dev, rOFDM0_RxDetector1, 0xf, 0xf); + rtl8192_setBBreg(dev, rOFDM1_TRxPathEnable, 0xf, 0x0); + } + break; + + case FW_CMD_HIGH_PWR_ENABLE: + //if(pMgntInfo->bTurboScan) + { + rtl8192_setBBreg(dev, rOFDM0_XAAGCCore1, bMaskByte0, 0x36); + rtl8192_setBBreg(dev, rOFDM0_XBAGCCore1, bMaskByte0, 0x36); + + // CCA threshold + rtl8192_setBBreg(dev, rCCK0_CCA, bMaskByte2, 0x83); + // Enable OFDM Part + rtl8192_setBBreg(dev, rOFDM0_TRMuxPar, bMaskByte2, 0x0); + + //LZM ADD because sometimes there is no FW_CMD_HIGH_PWR_DISABLE, this value will be 0. + if(ScanRegister != 0){ + rtl8192_setBBreg(dev, rOFDM0_RxDetector1, bMaskDWord, ScanRegister); + } + + if(priv->rf_type == RF_1T2R || priv->rf_type == RF_2T2R) + rtl8192_setBBreg(dev, rOFDM1_TRxPathEnable, 0xf, 0x3); + else + rtl8192_setBBreg(dev, rOFDM1_TRxPathEnable, 0xf, 0x1); + } + break; + } + + priv->SetFwCmdInProgress = false;// Clear FW CMD operation flag. + RT_TRACE(COMP_CMD, "<---SetFwCmdIOWorkItemCallback()\n"); + +} + diff --git a/drivers/staging/rtl8192su/r8192S_phy.h b/drivers/staging/rtl8192su/r8192S_phy.h new file mode 100644 index 000000000000..580a7c6a7609 --- /dev/null +++ b/drivers/staging/rtl8192su/r8192S_phy.h @@ -0,0 +1,138 @@ +/***************************************************************************** + * Copyright(c) 2008, RealTEK Technology Inc. All Right Reserved. + * + * Module: __INC_HAL8192SPHYCFG_H + * + * + * Note: + * + * + * Export: Constants, macro, functions(API), global variables(None). + * + * Abbrev: + * + * History: + * Data Who Remark + * 08/07/2007 MHC 1. Porting from 9x series PHYCFG.h. + * 2. Reorganize code architecture. + * + *****************************************************************************/ + /* Check to see if the file has been included already. */ +#ifndef _R8192S_PHY_H +#define _R8192S_PHY_H + + +/*--------------------------Define Parameters-------------------------------*/ +#define LOOP_LIMIT 5 +#define MAX_STALL_TIME 50 //us +#define AntennaDiversityValue 0x80 //(dev->bSoftwareAntennaDiversity ? 0x00:0x80) +#define MAX_TXPWR_IDX_NMODE_92S 63 + +//#define delay_ms(_t) PlatformStallExecution(1000*(_t)) +//#define delay_us(_t) PlatformStallExecution(_t) + +/* Channel switch:The size of command tables for switch channel*/ +#define MAX_PRECMD_CNT 16 +#define MAX_RFDEPENDCMD_CNT 16 +#define MAX_POSTCMD_CNT 16 + + +/*------------------------------Define structure----------------------------*/ +typedef enum _SwChnlCmdID{ + CmdID_End, + CmdID_SetTxPowerLevel, + CmdID_BBRegWrite10, + CmdID_WritePortUlong, + CmdID_WritePortUshort, + CmdID_WritePortUchar, + CmdID_RF_WriteReg, +}SwChnlCmdID; + + +/* 1. Switch channel related */ +typedef struct _SwChnlCmd{ + SwChnlCmdID CmdID; + u32 Para1; + u32 Para2; + u32 msDelay; +}__attribute__ ((packed)) SwChnlCmd; + +extern u32 rtl819XMACPHY_Array_PG[]; +extern u32 rtl819XPHY_REG_1T2RArray[]; +extern u32 rtl819XAGCTAB_Array[]; +extern u32 rtl819XRadioA_Array[]; +extern u32 rtl819XRadioB_Array[]; +extern u32 rtl819XRadioC_Array[]; +extern u32 rtl819XRadioD_Array[]; + +typedef enum _HW90_BLOCK{ + HW90_BLOCK_MAC = 0, + HW90_BLOCK_PHY0 = 1, + HW90_BLOCK_PHY1 = 2, + HW90_BLOCK_RF = 3, + HW90_BLOCK_MAXIMUM = 4, // Never use this +}HW90_BLOCK_E, *PHW90_BLOCK_E; + +typedef enum _RF90_RADIO_PATH{ + RF90_PATH_A = 0, //Radio Path A + RF90_PATH_B = 1, //Radio Path B + RF90_PATH_C = 2, //Radio Path C + RF90_PATH_D = 3, //Radio Path D + RF90_PATH_MAX = 4, //Max RF number 90 support +}RF90_RADIO_PATH_E, *PRF90_RADIO_PATH_E; + +#define bMaskByte0 0xff +#define bMaskByte1 0xff00 +#define bMaskByte2 0xff0000 +#define bMaskByte3 0xff000000 +#define bMaskHWord 0xffff0000 +#define bMaskLWord 0x0000ffff +#define bMaskDWord 0xffffffff + +typedef enum _VERSION_8190{ + // RTL8190 + VERSION_8190_BD=0x3, + VERSION_8190_BE +}VERSION_8190,*PVERSION_8190; + +// +// BB and RF register read/write +// + +extern u32 rtl8192_QueryBBReg(struct net_device* dev,u32 RegAddr, u32 BitMask); +extern void rtl8192_setBBreg(struct net_device* dev,u32 RegAddr, u32 BitMask,u32 Data); +extern u32 rtl8192_phy_QueryRFReg(struct net_device* dev,RF90_RADIO_PATH_E eRFPath, u32 RegAddr, u32 BitMask); +extern void rtl8192_phy_SetRFReg(struct net_device* dev,RF90_RADIO_PATH_E eRFPath, u32 RegAddr,u32 BitMask,u32 Data); + +bool rtl8192_phy_checkBBAndRF(struct net_device* dev, HW90_BLOCK_E CheckBlock, RF90_RADIO_PATH_E eRFPath); + + +/* MAC/BB/RF HAL config */ +extern bool PHY_MACConfig8192S(struct net_device* dev); +extern bool PHY_BBConfig8192S(struct net_device* dev); +extern bool PHY_RFConfig8192S(struct net_device* dev); + +extern u8 rtl8192_phy_ConfigRFWithHeaderFile(struct net_device* dev,RF90_RADIO_PATH_E eRFPath); +extern void rtl8192_SetBWMode(struct net_device* dev,HT_CHANNEL_WIDTH ChnlWidth,HT_EXTCHNL_OFFSET Offset ); +extern u8 rtl8192_phy_SwChnl(struct net_device* dev,u8 channel); +extern u8 rtl8192_phy_CheckIsLegalRFPath(struct net_device* dev,u32 eRFPath ); +extern void rtl8192_BBConfig(struct net_device* dev); +extern void PHY_IQCalibrateBcut(struct net_device* dev); +extern void PHY_IQCalibrate(struct net_device* dev); +extern void PHY_GetHWRegOriginalValue(struct net_device* dev); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) +extern void InitialGainOperateWorkItemCallBack(struct work_struct *work); +#else +extern void InitialGainOperateWorkItemCallBack(struct net_device *dev); +#endif +void PHY_SetTxPowerLevel8192S(struct net_device* dev, u8 channel); +void PHY_InitialGain8192S(struct net_device* dev,u8 Operation ); + +/*--------------------------Exported Function prototype---------------------*/ +bool HalSetFwCmd8192S(struct net_device* dev, FW_CMD_IO_TYPE FwCmdIO); +extern void PHY_SetBeaconHwReg( struct net_device* dev, u16 BeaconInterval); +void ChkFwCmdIoDone(struct net_device* dev); + +#endif // __INC_HAL8192SPHYCFG_H + diff --git a/drivers/staging/rtl8192su/r8192S_phyreg.h b/drivers/staging/rtl8192su/r8192S_phyreg.h new file mode 100644 index 000000000000..96c7cfa92542 --- /dev/null +++ b/drivers/staging/rtl8192su/r8192S_phyreg.h @@ -0,0 +1,1033 @@ +/***************************************************************************** + * Copyright(c) 2008, RealTEK Technology Inc. All Right Reserved. + * + * Module: __INC_HAL8192SPHYREG_H + * + * + * Note: 1. Define PMAC/BB register map + * 2. Define RF register map + * 3. PMAC/BB register bit mask. + * 4. RF reg bit mask. + * 5. Other BB/RF relative definition. + * + * + * Export: Constants, macro, functions(API), global variables(None). + * + * Abbrev: + * + * History: + * Data Who Remark + * 08/07/2007 MHC 1. Porting from 9x series PHYCFG.h. + * 2. Reorganize code architecture. + * 09/25/2008 MH 1. Add RL6052 register definition + * + *****************************************************************************/ +#ifndef __INC_HAL8192SPHYREG_H +#define __INC_HAL8192SPHYREG_H + + +/*--------------------------Define Parameters-------------------------------*/ + +//============================================================ +// 8192S Regsiter offset definition +//============================================================ + +// +// BB-PHY register PMAC 0x100 PHY 0x800 - 0xEFF +// 1. PMAC duplicate register due to connection: RF_Mode, TRxRN, NumOf L-STF +// 2. 0x800/0x900/0xA00/0xC00/0xD00/0xE00 +// 3. RF register 0x00-2E +// 4. Bit Mask for BB/RF register +// 5. Other defintion for BB/RF R/W +// + + +// +// 1. PMAC duplicate register due to connection: RF_Mode, TRxRN, NumOf L-STF +// 1. Page1(0x100) +// +#define rPMAC_Reset 0x100 +#define rPMAC_TxStart 0x104 +#define rPMAC_TxLegacySIG 0x108 +#define rPMAC_TxHTSIG1 0x10c +#define rPMAC_TxHTSIG2 0x110 +#define rPMAC_PHYDebug 0x114 +#define rPMAC_TxPacketNum 0x118 +#define rPMAC_TxIdle 0x11c +#define rPMAC_TxMACHeader0 0x120 +#define rPMAC_TxMACHeader1 0x124 +#define rPMAC_TxMACHeader2 0x128 +#define rPMAC_TxMACHeader3 0x12c +#define rPMAC_TxMACHeader4 0x130 +#define rPMAC_TxMACHeader5 0x134 +#define rPMAC_TxDataType 0x138 +#define rPMAC_TxRandomSeed 0x13c +#define rPMAC_CCKPLCPPreamble 0x140 +#define rPMAC_CCKPLCPHeader 0x144 +#define rPMAC_CCKCRC16 0x148 +#define rPMAC_OFDMRxCRC32OK 0x170 +#define rPMAC_OFDMRxCRC32Er 0x174 +#define rPMAC_OFDMRxParityEr 0x178 +#define rPMAC_OFDMRxCRC8Er 0x17c +#define rPMAC_CCKCRxRC16Er 0x180 +#define rPMAC_CCKCRxRC32Er 0x184 +#define rPMAC_CCKCRxRC32OK 0x188 +#define rPMAC_TxStatus 0x18c + +// +// 2. Page2(0x200) +// +// The following two definition are only used for USB interface. +#define RF_BB_CMD_ADDR 0x02c0 // RF/BB read/write command address. +#define RF_BB_CMD_DATA 0x02c4 // RF/BB read/write command data. + +// +// 3. Page8(0x800) +// +#define rFPGA0_RFMOD 0x800 //RF mode & CCK TxSC // RF BW Setting?? + +#define rFPGA0_TxInfo 0x804 // Status report?? +#define rFPGA0_PSDFunction 0x808 + +#define rFPGA0_TxGainStage 0x80c // Set TX PWR init gain? + +#define rFPGA0_RFTiming1 0x810 // Useless now +#define rFPGA0_RFTiming2 0x814 +//#define rFPGA0_XC_RFTiming 0x818 +//#define rFPGA0_XD_RFTiming 0x81c + +#define rFPGA0_XA_HSSIParameter1 0x820 // RF 3 wire register +#define rFPGA0_XA_HSSIParameter2 0x824 +#define rFPGA0_XB_HSSIParameter1 0x828 +#define rFPGA0_XB_HSSIParameter2 0x82c +#define rFPGA0_XC_HSSIParameter1 0x830 +#define rFPGA0_XC_HSSIParameter2 0x834 +#define rFPGA0_XD_HSSIParameter1 0x838 +#define rFPGA0_XD_HSSIParameter2 0x83c +#define rFPGA0_XA_LSSIParameter 0x840 +#define rFPGA0_XB_LSSIParameter 0x844 +#define rFPGA0_XC_LSSIParameter 0x848 +#define rFPGA0_XD_LSSIParameter 0x84c + +#define rFPGA0_RFWakeUpParameter 0x850 // Useless now +#define rFPGA0_RFSleepUpParameter 0x854 + +#define rFPGA0_XAB_SwitchControl 0x858 // RF Channel switch +#define rFPGA0_XCD_SwitchControl 0x85c + +#define rFPGA0_XA_RFInterfaceOE 0x860 // RF Channel switch +#define rFPGA0_XB_RFInterfaceOE 0x864 +#define rFPGA0_XC_RFInterfaceOE 0x868 +#define rFPGA0_XD_RFInterfaceOE 0x86c + +#define rFPGA0_XAB_RFInterfaceSW 0x870 // RF Interface Software Control +#define rFPGA0_XCD_RFInterfaceSW 0x874 + +#define rFPGA0_XAB_RFParameter 0x878 // RF Parameter +#define rFPGA0_XCD_RFParameter 0x87c + +#define rFPGA0_AnalogParameter1 0x880 // Crystal cap setting RF-R/W protection for parameter4?? +#define rFPGA0_AnalogParameter2 0x884 +#define rFPGA0_AnalogParameter3 0x888 // Useless now +#define rFPGA0_AnalogParameter4 0x88c + +#define rFPGA0_XA_LSSIReadBack 0x8a0 // Tranceiver LSSI Readback +#define rFPGA0_XB_LSSIReadBack 0x8a4 +#define rFPGA0_XC_LSSIReadBack 0x8a8 +#define rFPGA0_XD_LSSIReadBack 0x8ac + +#define rFPGA0_PSDReport 0x8b4 // Useless now +#define TransceiverA_HSPI_Readback 0x8b8 // Transceiver A HSPI Readback +#define TransceiverB_HSPI_Readback 0x8bc // Transceiver B HSPI Readback +#define rFPGA0_XAB_RFInterfaceRB 0x8e0 // Useless now // RF Interface Readback Value +#define rFPGA0_XCD_RFInterfaceRB 0x8e4 // Useless now + +// +// 4. Page9(0x900) +// +#define rFPGA1_RFMOD 0x900 //RF mode & OFDM TxSC // RF BW Setting?? + +#define rFPGA1_TxBlock 0x904 // Useless now +#define rFPGA1_DebugSelect 0x908 // Useless now +#define rFPGA1_TxInfo 0x90c // Useless now // Status report?? + +// +// 5. PageA(0xA00) +// +// Set Control channel to upper or lower. These settings are required only for 40MHz +#define rCCK0_System 0xa00 + +#define rCCK0_AFESetting 0xa04 // Disable init gain now // Select RX path by RSSI +#define rCCK0_CCA 0xa08 // Disable init gain now // Init gain + +#define rCCK0_RxAGC1 0xa0c //AGC default value, saturation level // Antenna Diversity, RX AGC, LNA Threshold, RX LNA Threshold useless now. Not the same as 90 series +#define rCCK0_RxAGC2 0xa10 //AGC & DAGC + +#define rCCK0_RxHP 0xa14 + +#define rCCK0_DSPParameter1 0xa18 //Timing recovery & Channel estimation threshold +#define rCCK0_DSPParameter2 0xa1c //SQ threshold + +#define rCCK0_TxFilter1 0xa20 +#define rCCK0_TxFilter2 0xa24 +#define rCCK0_DebugPort 0xa28 //debug port and Tx filter3 +#define rCCK0_FalseAlarmReport 0xa2c //0xa2d useless now 0xa30-a4f channel report +#define rCCK0_TRSSIReport 0xa50 +#define rCCK0_RxReport 0xa54 //0xa57 +#define rCCK0_FACounterLower 0xa5c //0xa5b +#define rCCK0_FACounterUpper 0xa58 //0xa5c + +// +// 6. PageC(0xC00) +// +#define rOFDM0_LSTF 0xc00 + +#define rOFDM0_TRxPathEnable 0xc04 +#define rOFDM0_TRMuxPar 0xc08 +#define rOFDM0_TRSWIsolation 0xc0c + +#define rOFDM0_XARxAFE 0xc10 //RxIQ DC offset, Rx digital filter, DC notch filter +#define rOFDM0_XARxIQImbalance 0xc14 //RxIQ imblance matrix +#define rOFDM0_XBRxAFE 0xc18 +#define rOFDM0_XBRxIQImbalance 0xc1c +#define rOFDM0_XCRxAFE 0xc20 +#define rOFDM0_XCRxIQImbalance 0xc24 +#define rOFDM0_XDRxAFE 0xc28 +#define rOFDM0_XDRxIQImbalance 0xc2c + +#define rOFDM0_RxDetector1 0xc30 //PD,BW & SBD // DM tune init gain +#define rOFDM0_RxDetector2 0xc34 //SBD & Fame Sync. +#define rOFDM0_RxDetector3 0xc38 //Frame Sync. +#define rOFDM0_RxDetector4 0xc3c //PD, SBD, Frame Sync & Short-GI + +#define rOFDM0_RxDSP 0xc40 //Rx Sync Path +#define rOFDM0_CFOandDAGC 0xc44 //CFO & DAGC +#define rOFDM0_CCADropThreshold 0xc48 //CCA Drop threshold +#define rOFDM0_ECCAThreshold 0xc4c // energy CCA + +#define rOFDM0_XAAGCCore1 0xc50 // DIG +#define rOFDM0_XAAGCCore2 0xc54 +#define rOFDM0_XBAGCCore1 0xc58 +#define rOFDM0_XBAGCCore2 0xc5c +#define rOFDM0_XCAGCCore1 0xc60 +#define rOFDM0_XCAGCCore2 0xc64 +#define rOFDM0_XDAGCCore1 0xc68 +#define rOFDM0_XDAGCCore2 0xc6c + +#define rOFDM0_AGCParameter1 0xc70 +#define rOFDM0_AGCParameter2 0xc74 +#define rOFDM0_AGCRSSITable 0xc78 +#define rOFDM0_HTSTFAGC 0xc7c + +#define rOFDM0_XATxIQImbalance 0xc80 // TX PWR TRACK and DIG +#define rOFDM0_XATxAFE 0xc84 +#define rOFDM0_XBTxIQImbalance 0xc88 +#define rOFDM0_XBTxAFE 0xc8c +#define rOFDM0_XCTxIQImbalance 0xc90 +#define rOFDM0_XCTxAFE 0xc94 +#define rOFDM0_XDTxIQImbalance 0xc98 +#define rOFDM0_XDTxAFE 0xc9c + +#define rOFDM0_RxHPParameter 0xce0 +#define rOFDM0_TxPseudoNoiseWgt 0xce4 +#define rOFDM0_FrameSync 0xcf0 +#define rOFDM0_DFSReport 0xcf4 +#define rOFDM0_TxCoeff1 0xca4 +#define rOFDM0_TxCoeff2 0xca8 +#define rOFDM0_TxCoeff3 0xcac +#define rOFDM0_TxCoeff4 0xcb0 +#define rOFDM0_TxCoeff5 0xcb4 +#define rOFDM0_TxCoeff6 0xcb8 + + +// +// 7. PageD(0xD00) +// +#define rOFDM1_LSTF 0xd00 +#define rOFDM1_TRxPathEnable 0xd04 +#define rOFDM1_CFO 0xd08 // No setting now +#define rOFDM1_CSI1 0xd10 +#define rOFDM1_SBD 0xd14 +#define rOFDM1_CSI2 0xd18 +#define rOFDM1_CFOTracking 0xd2c +#define rOFDM1_TRxMesaure1 0xd34 +#define rOFDM1_IntfDet 0xd3c +#define rOFDM1_PseudoNoiseStateAB 0xd50 +#define rOFDM1_PseudoNoiseStateCD 0xd54 +#define rOFDM1_RxPseudoNoiseWgt 0xd58 + +#define rOFDM_PHYCounter1 0xda0 //cca, parity fail +#define rOFDM_PHYCounter2 0xda4 //rate illegal, crc8 fail +#define rOFDM_PHYCounter3 0xda8 //MCS not support +#define rOFDM_ShortCFOAB 0xdac // No setting now +#define rOFDM_ShortCFOCD 0xdb0 +#define rOFDM_LongCFOAB 0xdb4 +#define rOFDM_LongCFOCD 0xdb8 +#define rOFDM_TailCFOAB 0xdbc +#define rOFDM_TailCFOCD 0xdc0 +#define rOFDM_PWMeasure1 0xdc4 +#define rOFDM_PWMeasure2 0xdc8 +#define rOFDM_BWReport 0xdcc +#define rOFDM_AGCReport 0xdd0 +#define rOFDM_RxSNR 0xdd4 +#define rOFDM_RxEVMCSI 0xdd8 +#define rOFDM_SIGReport 0xddc + + +// +// 8. PageE(0xE00) +// +#define rTxAGC_Rate18_06 0xe00 +#define rTxAGC_Rate54_24 0xe04 +#define rTxAGC_CCK_Mcs32 0xe08 +#define rTxAGC_Mcs03_Mcs00 0xe10 +#define rTxAGC_Mcs07_Mcs04 0xe14 +#define rTxAGC_Mcs11_Mcs08 0xe18 +#define rTxAGC_Mcs15_Mcs12 0xe1c + +// +// 7. RF Register 0x00-0x2E (RF 8256) +// RF-0222D 0x00-3F +// +//Zebra1 +#define rZebra1_HSSIEnable 0x0 // Useless now +#define rZebra1_TRxEnable1 0x1 +#define rZebra1_TRxEnable2 0x2 +#define rZebra1_AGC 0x4 +#define rZebra1_ChargePump 0x5 +//#if (RTL92SE_FPGA_VERIFY == 1) +#define rZebra1_Channel 0x7 // RF channel switch +//#else + +//#endif +#define rZebra1_TxGain 0x8 // Useless now +#define rZebra1_TxLPF 0x9 +#define rZebra1_RxLPF 0xb +#define rZebra1_RxHPFCorner 0xc + +//Zebra4 +#define rGlobalCtrl 0 // Useless now +#define rRTL8256_TxLPF 19 +#define rRTL8256_RxLPF 11 + +//RTL8258 +#define rRTL8258_TxLPF 0x11 // Useless now +#define rRTL8258_RxLPF 0x13 +#define rRTL8258_RSSILPF 0xa + +// +// RL6052 Register definition +// +#define RF_AC 0x00 // + +#define RF_IQADJ_G1 0x01 // +#define RF_IQADJ_G2 0x02 // +#define RF_POW_TRSW 0x05 // + +#define RF_GAIN_RX 0x06 // +#define RF_GAIN_TX 0x07 // + +#define RF_TXM_IDAC 0x08 // +#define RF_BS_IQGEN 0x0F // + +#define RF_MODE1 0x10 // +#define RF_MODE2 0x11 // + +#define RF_RX_AGC_HP 0x12 // +#define RF_TX_AGC 0x13 // +#define RF_BIAS 0x14 // +#define RF_IPA 0x15 // +#define RF_POW_ABILITY 0x17 // +#define RF_MODE_AG 0x18 // +#define rRfChannel 0x18 // RF channel and BW switch +#define RF_CHNLBW 0x18 // RF channel and BW switch +#define RF_TOP 0x19 // + +#define RF_RX_G1 0x1A // +#define RF_RX_G2 0x1B // + +#define RF_RX_BB2 0x1C // +#define RF_RX_BB1 0x1D // + +#define RF_RCK1 0x1E // +#define RF_RCK2 0x1F // + +#define RF_TX_G1 0x20 // +#define RF_TX_G2 0x21 // +#define RF_TX_G3 0x22 // + +#define RF_TX_BB1 0x23 // + +#define RF_T_METER 0x24 // + +#define RF_SYN_G1 0x25 // RF TX Power control +#define RF_SYN_G2 0x26 // RF TX Power control +#define RF_SYN_G3 0x27 // RF TX Power control +#define RF_SYN_G4 0x28 // RF TX Power control +#define RF_SYN_G5 0x29 // RF TX Power control +#define RF_SYN_G6 0x2A // RF TX Power control +#define RF_SYN_G7 0x2B // RF TX Power control +#define RF_SYN_G8 0x2C // RF TX Power control + +#define RF_RCK_OS 0x30 // RF TX PA control + +#define RF_TXPA_G1 0x31 // RF TX PA control +#define RF_TXPA_G2 0x32 // RF TX PA control +#define RF_TXPA_G3 0x33 // RF TX PA control + +// +//Bit Mask +// +// 1. Page1(0x100) +#define bBBResetB 0x100 // Useless now? +#define bGlobalResetB 0x200 +#define bOFDMTxStart 0x4 +#define bCCKTxStart 0x8 +#define bCRC32Debug 0x100 +#define bPMACLoopback 0x10 +#define bTxLSIG 0xffffff +#define bOFDMTxRate 0xf +#define bOFDMTxReserved 0x10 +#define bOFDMTxLength 0x1ffe0 +#define bOFDMTxParity 0x20000 +#define bTxHTSIG1 0xffffff +#define bTxHTMCSRate 0x7f +#define bTxHTBW 0x80 +#define bTxHTLength 0xffff00 +#define bTxHTSIG2 0xffffff +#define bTxHTSmoothing 0x1 +#define bTxHTSounding 0x2 +#define bTxHTReserved 0x4 +#define bTxHTAggreation 0x8 +#define bTxHTSTBC 0x30 +#define bTxHTAdvanceCoding 0x40 +#define bTxHTShortGI 0x80 +#define bTxHTNumberHT_LTF 0x300 +#define bTxHTCRC8 0x3fc00 +#define bCounterReset 0x10000 +#define bNumOfOFDMTx 0xffff +#define bNumOfCCKTx 0xffff0000 +#define bTxIdleInterval 0xffff +#define bOFDMService 0xffff0000 +#define bTxMACHeader 0xffffffff +#define bTxDataInit 0xff +#define bTxHTMode 0x100 +#define bTxDataType 0x30000 +#define bTxRandomSeed 0xffffffff +#define bCCKTxPreamble 0x1 +#define bCCKTxSFD 0xffff0000 +#define bCCKTxSIG 0xff +#define bCCKTxService 0xff00 +#define bCCKLengthExt 0x8000 +#define bCCKTxLength 0xffff0000 +#define bCCKTxCRC16 0xffff +#define bCCKTxStatus 0x1 +#define bOFDMTxStatus 0x2 + +#define IS_BB_REG_OFFSET_92S(_Offset) ((_Offset >= 0x800) && (_Offset <= 0xfff)) + +// 2. Page8(0x800) +#define bRFMOD 0x1 // Reg 0x800 rFPGA0_RFMOD +#define bJapanMode 0x2 +#define bCCKTxSC 0x30 +#define bCCKEn 0x1000000 +#define bOFDMEn 0x2000000 + +#define bOFDMRxADCPhase 0x10000 // Useless now +#define bOFDMTxDACPhase 0x40000 +#define bXATxAGC 0x3f + +#define bXBTxAGC 0xf00 // Reg 80c rFPGA0_TxGainStage +#define bXCTxAGC 0xf000 +#define bXDTxAGC 0xf0000 + +#define bPAStart 0xf0000000 // Useless now +#define bTRStart 0x00f00000 +#define bRFStart 0x0000f000 +#define bBBStart 0x000000f0 +#define bBBCCKStart 0x0000000f +#define bPAEnd 0xf //Reg0x814 +#define bTREnd 0x0f000000 +#define bRFEnd 0x000f0000 +#define bCCAMask 0x000000f0 //T2R +#define bR2RCCAMask 0x00000f00 +#define bHSSI_R2TDelay 0xf8000000 +#define bHSSI_T2RDelay 0xf80000 +#define bContTxHSSI 0x400 //chane gain at continue Tx +#define bIGFromCCK 0x200 +#define bAGCAddress 0x3f +#define bRxHPTx 0x7000 +#define bRxHPT2R 0x38000 +#define bRxHPCCKIni 0xc0000 +#define bAGCTxCode 0xc00000 +#define bAGCRxCode 0x300000 + +#define b3WireDataLength 0x800 // Reg 0x820~84f rFPGA0_XA_HSSIParameter1 +#define b3WireAddressLength 0x400 + +#define b3WireRFPowerDown 0x1 // Useless now +//#define bHWSISelect 0x8 +#define b5GPAPEPolarity 0x40000000 +#define b2GPAPEPolarity 0x80000000 +#define bRFSW_TxDefaultAnt 0x3 +#define bRFSW_TxOptionAnt 0x30 +#define bRFSW_RxDefaultAnt 0x300 +#define bRFSW_RxOptionAnt 0x3000 +#define bRFSI_3WireData 0x1 +#define bRFSI_3WireClock 0x2 +#define bRFSI_3WireLoad 0x4 +#define bRFSI_3WireRW 0x8 +#define bRFSI_3Wire 0xf + +#define bRFSI_RFENV 0x10 // Reg 0x870 rFPGA0_XAB_RFInterfaceSW + +#define bRFSI_TRSW 0x20 // Useless now +#define bRFSI_TRSWB 0x40 +#define bRFSI_ANTSW 0x100 +#define bRFSI_ANTSWB 0x200 +#define bRFSI_PAPE 0x400 +#define bRFSI_PAPE5G 0x800 +#define bBandSelect 0x1 +#define bHTSIG2_GI 0x80 +#define bHTSIG2_Smoothing 0x01 +#define bHTSIG2_Sounding 0x02 +#define bHTSIG2_Aggreaton 0x08 +#define bHTSIG2_STBC 0x30 +#define bHTSIG2_AdvCoding 0x40 +#define bHTSIG2_NumOfHTLTF 0x300 +#define bHTSIG2_CRC8 0x3fc +#define bHTSIG1_MCS 0x7f +#define bHTSIG1_BandWidth 0x80 +#define bHTSIG1_HTLength 0xffff +#define bLSIG_Rate 0xf +#define bLSIG_Reserved 0x10 +#define bLSIG_Length 0x1fffe +#define bLSIG_Parity 0x20 +#define bCCKRxPhase 0x4 +#define bLSSIReadAddress 0x7f800000 // T65 RF +#define bLSSIReadEdge 0x80000000 //LSSI "Read" edge signal +#define bLSSIReadBackData 0xfffff // T65 RF +#define bLSSIReadOKFlag 0x1000 // Useless now +#define bCCKSampleRate 0x8 //0: 44MHz, 1:88MHz +#define bRegulator0Standby 0x1 +#define bRegulatorPLLStandby 0x2 +#define bRegulator1Standby 0x4 +#define bPLLPowerUp 0x8 +#define bDPLLPowerUp 0x10 +#define bDA10PowerUp 0x20 +#define bAD7PowerUp 0x200 +#define bDA6PowerUp 0x2000 +#define bXtalPowerUp 0x4000 +#define b40MDClkPowerUP 0x8000 +#define bDA6DebugMode 0x20000 +#define bDA6Swing 0x380000 + +#define bADClkPhase 0x4000000 // Reg 0x880 rFPGA0_AnalogParameter1 20/40 CCK support switch 40/80 BB MHZ + +#define b80MClkDelay 0x18000000 // Useless +#define bAFEWatchDogEnable 0x20000000 + +#define bXtalCap01 0xc0000000 // Reg 0x884 rFPGA0_AnalogParameter2 Crystal cap +#define bXtalCap23 0x3 +#define bXtalCap92x 0x0f000000 +#define bXtalCap 0x0f000000 + +#define bIntDifClkEnable 0x400 // Useless +#define bExtSigClkEnable 0x800 +#define bBandgapMbiasPowerUp 0x10000 +#define bAD11SHGain 0xc0000 +#define bAD11InputRange 0x700000 +#define bAD11OPCurrent 0x3800000 +#define bIPathLoopback 0x4000000 +#define bQPathLoopback 0x8000000 +#define bAFELoopback 0x10000000 +#define bDA10Swing 0x7e0 +#define bDA10Reverse 0x800 +#define bDAClkSource 0x1000 +#define bAD7InputRange 0x6000 +#define bAD7Gain 0x38000 +#define bAD7OutputCMMode 0x40000 +#define bAD7InputCMMode 0x380000 +#define bAD7Current 0xc00000 +#define bRegulatorAdjust 0x7000000 +#define bAD11PowerUpAtTx 0x1 +#define bDA10PSAtTx 0x10 +#define bAD11PowerUpAtRx 0x100 +#define bDA10PSAtRx 0x1000 +#define bCCKRxAGCFormat 0x200 +#define bPSDFFTSamplepPoint 0xc000 +#define bPSDAverageNum 0x3000 +#define bIQPathControl 0xc00 +#define bPSDFreq 0x3ff +#define bPSDAntennaPath 0x30 +#define bPSDIQSwitch 0x40 +#define bPSDRxTrigger 0x400000 +#define bPSDTxTrigger 0x80000000 +#define bPSDSineToneScale 0x7f000000 +#define bPSDReport 0xffff + +// 3. Page9(0x900) +#define bOFDMTxSC 0x30000000 // Useless +#define bCCKTxOn 0x1 +#define bOFDMTxOn 0x2 +#define bDebugPage 0xfff //reset debug page and also HWord, LWord +#define bDebugItem 0xff //reset debug page and LWord +#define bAntL 0x10 +#define bAntNonHT 0x100 +#define bAntHT1 0x1000 +#define bAntHT2 0x10000 +#define bAntHT1S1 0x100000 +#define bAntNonHTS1 0x1000000 + +// 4. PageA(0xA00) +#define bCCKBBMode 0x3 // Useless +#define bCCKTxPowerSaving 0x80 +#define bCCKRxPowerSaving 0x40 + +#define bCCKSideBand 0x10 // Reg 0xa00 rCCK0_System 20/40 switch + +#define bCCKScramble 0x8 // Useless +#define bCCKAntDiversity 0x8000 +#define bCCKCarrierRecovery 0x4000 +#define bCCKTxRate 0x3000 +#define bCCKDCCancel 0x0800 +#define bCCKISICancel 0x0400 +#define bCCKMatchFilter 0x0200 +#define bCCKEqualizer 0x0100 +#define bCCKPreambleDetect 0x800000 +#define bCCKFastFalseCCA 0x400000 +#define bCCKChEstStart 0x300000 +#define bCCKCCACount 0x080000 +#define bCCKcs_lim 0x070000 +#define bCCKBistMode 0x80000000 +#define bCCKCCAMask 0x40000000 +#define bCCKTxDACPhase 0x4 +#define bCCKRxADCPhase 0x20000000 //r_rx_clk +#define bCCKr_cp_mode0 0x0100 +#define bCCKTxDCOffset 0xf0 +#define bCCKRxDCOffset 0xf +#define bCCKCCAMode 0xc000 +#define bCCKFalseCS_lim 0x3f00 +#define bCCKCS_ratio 0xc00000 +#define bCCKCorgBit_sel 0x300000 +#define bCCKPD_lim 0x0f0000 +#define bCCKNewCCA 0x80000000 +#define bCCKRxHPofIG 0x8000 +#define bCCKRxIG 0x7f00 +#define bCCKLNAPolarity 0x800000 +#define bCCKRx1stGain 0x7f0000 +#define bCCKRFExtend 0x20000000 //CCK Rx Iinital gain polarity +#define bCCKRxAGCSatLevel 0x1f000000 +#define bCCKRxAGCSatCount 0xe0 +#define bCCKRxRFSettle 0x1f //AGCsamp_dly +#define bCCKFixedRxAGC 0x8000 +//#define bCCKRxAGCFormat 0x4000 //remove to HSSI register 0x824 +#define bCCKAntennaPolarity 0x2000 +#define bCCKTxFilterType 0x0c00 +#define bCCKRxAGCReportType 0x0300 +#define bCCKRxDAGCEn 0x80000000 +#define bCCKRxDAGCPeriod 0x20000000 +#define bCCKRxDAGCSatLevel 0x1f000000 +#define bCCKTimingRecovery 0x800000 +#define bCCKTxC0 0x3f0000 +#define bCCKTxC1 0x3f000000 +#define bCCKTxC2 0x3f +#define bCCKTxC3 0x3f00 +#define bCCKTxC4 0x3f0000 +#define bCCKTxC5 0x3f000000 +#define bCCKTxC6 0x3f +#define bCCKTxC7 0x3f00 +#define bCCKDebugPort 0xff0000 +#define bCCKDACDebug 0x0f000000 +#define bCCKFalseAlarmEnable 0x8000 +#define bCCKFalseAlarmRead 0x4000 +#define bCCKTRSSI 0x7f +#define bCCKRxAGCReport 0xfe +#define bCCKRxReport_AntSel 0x80000000 +#define bCCKRxReport_MFOff 0x40000000 +#define bCCKRxRxReport_SQLoss 0x20000000 +#define bCCKRxReport_Pktloss 0x10000000 +#define bCCKRxReport_Lockedbit 0x08000000 +#define bCCKRxReport_RateError 0x04000000 +#define bCCKRxReport_RxRate 0x03000000 +#define bCCKRxFACounterLower 0xff +#define bCCKRxFACounterUpper 0xff000000 +#define bCCKRxHPAGCStart 0xe000 +#define bCCKRxHPAGCFinal 0x1c00 +#define bCCKRxFalseAlarmEnable 0x8000 +#define bCCKFACounterFreeze 0x4000 +#define bCCKTxPathSel 0x10000000 +#define bCCKDefaultRxPath 0xc000000 +#define bCCKOptionRxPath 0x3000000 + +// 5. PageC(0xC00) +#define bNumOfSTF 0x3 // Useless +#define bShift_L 0xc0 +#define bGI_TH 0xc +#define bRxPathA 0x1 +#define bRxPathB 0x2 +#define bRxPathC 0x4 +#define bRxPathD 0x8 +#define bTxPathA 0x1 +#define bTxPathB 0x2 +#define bTxPathC 0x4 +#define bTxPathD 0x8 +#define bTRSSIFreq 0x200 +#define bADCBackoff 0x3000 +#define bDFIRBackoff 0xc000 +#define bTRSSILatchPhase 0x10000 +#define bRxIDCOffset 0xff +#define bRxQDCOffset 0xff00 +#define bRxDFIRMode 0x1800000 +#define bRxDCNFType 0xe000000 +#define bRXIQImb_A 0x3ff +#define bRXIQImb_B 0xfc00 +#define bRXIQImb_C 0x3f0000 +#define bRXIQImb_D 0xffc00000 +#define bDC_dc_Notch 0x60000 +#define bRxNBINotch 0x1f000000 +#define bPD_TH 0xf +#define bPD_TH_Opt2 0xc000 +#define bPWED_TH 0x700 +#define bIfMF_Win_L 0x800 +#define bPD_Option 0x1000 +#define bMF_Win_L 0xe000 +#define bBW_Search_L 0x30000 +#define bwin_enh_L 0xc0000 +#define bBW_TH 0x700000 +#define bED_TH2 0x3800000 +#define bBW_option 0x4000000 +#define bRatio_TH 0x18000000 +#define bWindow_L 0xe0000000 +#define bSBD_Option 0x1 +#define bFrame_TH 0x1c +#define bFS_Option 0x60 +#define bDC_Slope_check 0x80 +#define bFGuard_Counter_DC_L 0xe00 +#define bFrame_Weight_Short 0x7000 +#define bSub_Tune 0xe00000 +#define bFrame_DC_Length 0xe000000 +#define bSBD_start_offset 0x30000000 +#define bFrame_TH_2 0x7 +#define bFrame_GI2_TH 0x38 +#define bGI2_Sync_en 0x40 +#define bSarch_Short_Early 0x300 +#define bSarch_Short_Late 0xc00 +#define bSarch_GI2_Late 0x70000 +#define bCFOAntSum 0x1 +#define bCFOAcc 0x2 +#define bCFOStartOffset 0xc +#define bCFOLookBack 0x70 +#define bCFOSumWeight 0x80 +#define bDAGCEnable 0x10000 +#define bTXIQImb_A 0x3ff +#define bTXIQImb_B 0xfc00 +#define bTXIQImb_C 0x3f0000 +#define bTXIQImb_D 0xffc00000 +#define bTxIDCOffset 0xff +#define bTxQDCOffset 0xff00 +#define bTxDFIRMode 0x10000 +#define bTxPesudoNoiseOn 0x4000000 +#define bTxPesudoNoise_A 0xff +#define bTxPesudoNoise_B 0xff00 +#define bTxPesudoNoise_C 0xff0000 +#define bTxPesudoNoise_D 0xff000000 +#define bCCADropOption 0x20000 +#define bCCADropThres 0xfff00000 +#define bEDCCA_H 0xf +#define bEDCCA_L 0xf0 +#define bLambda_ED 0x300 +#define bRxInitialGain 0x7f +#define bRxAntDivEn 0x80 +#define bRxAGCAddressForLNA 0x7f00 +#define bRxHighPowerFlow 0x8000 +#define bRxAGCFreezeThres 0xc0000 +#define bRxFreezeStep_AGC1 0x300000 +#define bRxFreezeStep_AGC2 0xc00000 +#define bRxFreezeStep_AGC3 0x3000000 +#define bRxFreezeStep_AGC0 0xc000000 +#define bRxRssi_Cmp_En 0x10000000 +#define bRxQuickAGCEn 0x20000000 +#define bRxAGCFreezeThresMode 0x40000000 +#define bRxOverFlowCheckType 0x80000000 +#define bRxAGCShift 0x7f +#define bTRSW_Tri_Only 0x80 +#define bPowerThres 0x300 +#define bRxAGCEn 0x1 +#define bRxAGCTogetherEn 0x2 +#define bRxAGCMin 0x4 +#define bRxHP_Ini 0x7 +#define bRxHP_TRLNA 0x70 +#define bRxHP_RSSI 0x700 +#define bRxHP_BBP1 0x7000 +#define bRxHP_BBP2 0x70000 +#define bRxHP_BBP3 0x700000 +#define bRSSI_H 0x7f0000 //the threshold for high power +#define bRSSI_Gen 0x7f000000 //the threshold for ant diversity +#define bRxSettle_TRSW 0x7 +#define bRxSettle_LNA 0x38 +#define bRxSettle_RSSI 0x1c0 +#define bRxSettle_BBP 0xe00 +#define bRxSettle_RxHP 0x7000 +#define bRxSettle_AntSW_RSSI 0x38000 +#define bRxSettle_AntSW 0xc0000 +#define bRxProcessTime_DAGC 0x300000 +#define bRxSettle_HSSI 0x400000 +#define bRxProcessTime_BBPPW 0x800000 +#define bRxAntennaPowerShift 0x3000000 +#define bRSSITableSelect 0xc000000 +#define bRxHP_Final 0x7000000 +#define bRxHTSettle_BBP 0x7 +#define bRxHTSettle_HSSI 0x8 +#define bRxHTSettle_RxHP 0x70 +#define bRxHTSettle_BBPPW 0x80 +#define bRxHTSettle_Idle 0x300 +#define bRxHTSettle_Reserved 0x1c00 +#define bRxHTRxHPEn 0x8000 +#define bRxHTAGCFreezeThres 0x30000 +#define bRxHTAGCTogetherEn 0x40000 +#define bRxHTAGCMin 0x80000 +#define bRxHTAGCEn 0x100000 +#define bRxHTDAGCEn 0x200000 +#define bRxHTRxHP_BBP 0x1c00000 +#define bRxHTRxHP_Final 0xe0000000 +#define bRxPWRatioTH 0x3 +#define bRxPWRatioEn 0x4 +#define bRxMFHold 0x3800 +#define bRxPD_Delay_TH1 0x38 +#define bRxPD_Delay_TH2 0x1c0 +#define bRxPD_DC_COUNT_MAX 0x600 +//#define bRxMF_Hold 0x3800 +#define bRxPD_Delay_TH 0x8000 +#define bRxProcess_Delay 0xf0000 +#define bRxSearchrange_GI2_Early 0x700000 +#define bRxFrame_Guard_Counter_L 0x3800000 +#define bRxSGI_Guard_L 0xc000000 +#define bRxSGI_Search_L 0x30000000 +#define bRxSGI_TH 0xc0000000 +#define bDFSCnt0 0xff +#define bDFSCnt1 0xff00 +#define bDFSFlag 0xf0000 +#define bMFWeightSum 0x300000 +#define bMinIdxTH 0x7f000000 +#define bDAFormat 0x40000 +#define bTxChEmuEnable 0x01000000 +#define bTRSWIsolation_A 0x7f +#define bTRSWIsolation_B 0x7f00 +#define bTRSWIsolation_C 0x7f0000 +#define bTRSWIsolation_D 0x7f000000 +#define bExtLNAGain 0x7c00 + +// 6. PageE(0xE00) +#define bSTBCEn 0x4 // Useless +#define bAntennaMapping 0x10 +#define bNss 0x20 +#define bCFOAntSumD 0x200 +#define bPHYCounterReset 0x8000000 +#define bCFOReportGet 0x4000000 +#define bOFDMContinueTx 0x10000000 +#define bOFDMSingleCarrier 0x20000000 +#define bOFDMSingleTone 0x40000000 +//#define bRxPath1 0x01 +//#define bRxPath2 0x02 +//#define bRxPath3 0x04 +//#define bRxPath4 0x08 +//#define bTxPath1 0x10 +//#define bTxPath2 0x20 +#define bHTDetect 0x100 +#define bCFOEn 0x10000 +#define bCFOValue 0xfff00000 +#define bSigTone_Re 0x3f +#define bSigTone_Im 0x7f00 +#define bCounter_CCA 0xffff +#define bCounter_ParityFail 0xffff0000 +#define bCounter_RateIllegal 0xffff +#define bCounter_CRC8Fail 0xffff0000 +#define bCounter_MCSNoSupport 0xffff +#define bCounter_FastSync 0xffff +#define bShortCFO 0xfff +#define bShortCFOTLength 12 //total +#define bShortCFOFLength 11 //fraction +#define bLongCFO 0x7ff +#define bLongCFOTLength 11 +#define bLongCFOFLength 11 +#define bTailCFO 0x1fff +#define bTailCFOTLength 13 +#define bTailCFOFLength 12 +#define bmax_en_pwdB 0xffff +#define bCC_power_dB 0xffff0000 +#define bnoise_pwdB 0xffff +#define bPowerMeasTLength 10 +#define bPowerMeasFLength 3 +#define bRx_HT_BW 0x1 +#define bRxSC 0x6 +#define bRx_HT 0x8 +#define bNB_intf_det_on 0x1 +#define bIntf_win_len_cfg 0x30 +#define bNB_Intf_TH_cfg 0x1c0 +#define bRFGain 0x3f +#define bTableSel 0x40 +#define bTRSW 0x80 +#define bRxSNR_A 0xff +#define bRxSNR_B 0xff00 +#define bRxSNR_C 0xff0000 +#define bRxSNR_D 0xff000000 +#define bSNREVMTLength 8 +#define bSNREVMFLength 1 +#define bCSI1st 0xff +#define bCSI2nd 0xff00 +#define bRxEVM1st 0xff0000 +#define bRxEVM2nd 0xff000000 +#define bSIGEVM 0xff +#define bPWDB 0xff00 +#define bSGIEN 0x10000 + +#define bSFactorQAM1 0xf // Useless +#define bSFactorQAM2 0xf0 +#define bSFactorQAM3 0xf00 +#define bSFactorQAM4 0xf000 +#define bSFactorQAM5 0xf0000 +#define bSFactorQAM6 0xf0000 +#define bSFactorQAM7 0xf00000 +#define bSFactorQAM8 0xf000000 +#define bSFactorQAM9 0xf0000000 +#define bCSIScheme 0x100000 + +#define bNoiseLvlTopSet 0x3 // Useless +#define bChSmooth 0x4 +#define bChSmoothCfg1 0x38 +#define bChSmoothCfg2 0x1c0 +#define bChSmoothCfg3 0xe00 +#define bChSmoothCfg4 0x7000 +#define bMRCMode 0x800000 +#define bTHEVMCfg 0x7000000 + +#define bLoopFitType 0x1 // Useless +#define bUpdCFO 0x40 +#define bUpdCFOOffData 0x80 +#define bAdvUpdCFO 0x100 +#define bAdvTimeCtrl 0x800 +#define bUpdClko 0x1000 +#define bFC 0x6000 +#define bTrackingMode 0x8000 +#define bPhCmpEnable 0x10000 +#define bUpdClkoLTF 0x20000 +#define bComChCFO 0x40000 +#define bCSIEstiMode 0x80000 +#define bAdvUpdEqz 0x100000 +#define bUChCfg 0x7000000 +#define bUpdEqz 0x8000000 + +#define bTxAGCRate18_06 0x7f7f7f7f // Useless +#define bTxAGCRate54_24 0x7f7f7f7f +#define bTxAGCRateMCS32 0x7f +#define bTxAGCRateCCK 0x7f00 +#define bTxAGCRateMCS3_MCS0 0x7f7f7f7f +#define bTxAGCRateMCS7_MCS4 0x7f7f7f7f +#define bTxAGCRateMCS11_MCS8 0x7f7f7f7f +#define bTxAGCRateMCS15_MCS12 0x7f7f7f7f + +//Rx Pseduo noise +#define bRxPesudoNoiseOn 0x20000000 // Useless +#define bRxPesudoNoise_A 0xff +#define bRxPesudoNoise_B 0xff00 +#define bRxPesudoNoise_C 0xff0000 +#define bRxPesudoNoise_D 0xff000000 +#define bPesudoNoiseState_A 0xffff +#define bPesudoNoiseState_B 0xffff0000 +#define bPesudoNoiseState_C 0xffff +#define bPesudoNoiseState_D 0xffff0000 + +//7. RF Register +//Zebra1 +#define bZebra1_HSSIEnable 0x8 // Useless +#define bZebra1_TRxControl 0xc00 +#define bZebra1_TRxGainSetting 0x07f +#define bZebra1_RxCorner 0xc00 +#define bZebra1_TxChargePump 0x38 +#define bZebra1_RxChargePump 0x7 +#define bZebra1_ChannelNum 0xf80 +#define bZebra1_TxLPFBW 0x400 +#define bZebra1_RxLPFBW 0x600 + +//Zebra4 +#define bRTL8256RegModeCtrl1 0x100 // Useless +#define bRTL8256RegModeCtrl0 0x40 +#define bRTL8256_TxLPFBW 0x18 +#define bRTL8256_RxLPFBW 0x600 + +//RTL8258 +#define bRTL8258_TxLPFBW 0xc // Useless +#define bRTL8258_RxLPFBW 0xc00 +#define bRTL8258_RSSILPFBW 0xc0 + + +// +// Other Definition +// + +//byte endable for sb_write +#define bByte0 0x1 // Useless +#define bByte1 0x2 +#define bByte2 0x4 +#define bByte3 0x8 +#define bWord0 0x3 +#define bWord1 0xc +#define bDWord 0xf + +//for PutRegsetting & GetRegSetting BitMask +#define bMaskByte0 0xff // Reg 0xc50 rOFDM0_XAAGCCore~0xC6f +#define bMaskByte1 0xff00 +#define bMaskByte2 0xff0000 +#define bMaskByte3 0xff000000 +#define bMaskHWord 0xffff0000 +#define bMaskLWord 0x0000ffff +#define bMaskDWord 0xffffffff + +//for PutRFRegsetting & GetRFRegSetting BitMask +#define bMask12Bits 0xfffff // RF Reg mask bits +#define bMask20Bits 0xfffff // RF Reg mask bits T65 RF +#define bRFRegOffsetMask 0xfffff + +#define bEnable 0x1 // Useless +#define bDisable 0x0 + +#define LeftAntenna 0x0 // Useless +#define RightAntenna 0x1 + +#define tCheckTxStatus 500 //500ms // Useless +#define tUpdateRxCounter 100 //100ms + +#define rateCCK 0 // Useless +#define rateOFDM 1 +#define rateHT 2 + +//define Register-End +#define bPMAC_End 0x1ff // Useless +#define bFPGAPHY0_End 0x8ff +#define bFPGAPHY1_End 0x9ff +#define bCCKPHY0_End 0xaff +#define bOFDMPHY0_End 0xcff +#define bOFDMPHY1_End 0xdff + +//define max debug item in each debug page +//#define bMaxItem_FPGA_PHY0 0x9 +//#define bMaxItem_FPGA_PHY1 0x3 +//#define bMaxItem_PHY_11B 0x16 +//#define bMaxItem_OFDM_PHY0 0x29 +//#define bMaxItem_OFDM_PHY1 0x0 + +#define bPMACControl 0x0 // Useless +#define bWMACControl 0x1 +#define bWNICControl 0x2 + +#define PathA 0x0 // Useless +#define PathB 0x1 +#define PathC 0x2 +#define PathD 0x3 + +/*--------------------------Define Parameters-------------------------------*/ + + +#endif //__INC_HAL8192SPHYREG_H + diff --git a/drivers/staging/rtl8192su/r8192S_rtl6052.c b/drivers/staging/rtl8192su/r8192S_rtl6052.c new file mode 100644 index 000000000000..71caf81a6e10 --- /dev/null +++ b/drivers/staging/rtl8192su/r8192S_rtl6052.c @@ -0,0 +1,946 @@ +/****************************************************************************** + * + * (c) Copyright 2008, RealTEK Technologies Inc. All Rights Reserved. + * + * Module: HalRf6052.c ( Source C File) + * + * Note: Provide RF 6052 series relative API. + * + * Function: + * + * Export: + * + * Abbrev: + * + * History: + * Data Who Remark + * + * 09/25/2008 MHC Create initial version. + * 11/05/2008 MHC Add API for tw power setting. + * + * +******************************************************************************/ +#include "r8192U.h" +#include "r8192S_rtl6052.h" + +#ifdef RTL8192SU +#include "r8192S_hw.h" +#include "r8192S_phyreg.h" +#include "r8192S_phy.h" +#else +#include "r8192U_hw.h" +#include "r819xU_phyreg.h" +#include "r819xU_phy.h" +#endif + + +/*---------------------------Define Local Constant---------------------------*/ +// Define local structure for debug!!!!! +typedef struct RF_Shadow_Compare_Map { + // Shadow register value + u32 Value; + // Compare or not flag + u8 Compare; + // Record If it had ever modified unpredicted + u8 ErrorOrNot; + // Recorver Flag + u8 Recorver; + // + u8 Driver_Write; +}RF_SHADOW_T; +/*---------------------------Define Local Constant---------------------------*/ + + +/*------------------------Define global variable-----------------------------*/ +/*------------------------Define global variable-----------------------------*/ + + + + +/*---------------------Define local function prototype-----------------------*/ +void phy_RF6052_Config_HardCode(struct net_device* dev); + +RT_STATUS phy_RF6052_Config_ParaFile(struct net_device* dev); +/*---------------------Define local function prototype-----------------------*/ + +/*------------------------Define function prototype--------------------------*/ +extern void RF_ChangeTxPath(struct net_device* dev, u16 DataRate); + +/*------------------------Define function prototype--------------------------*/ + +/*------------------------Define local variable------------------------------*/ +// 2008/11/20 MH For Debug only, RF +static RF_SHADOW_T RF_Shadow[RF6052_MAX_PATH][RF6052_MAX_REG];// = {{0}};//FIXLZM +/*------------------------Define local variable------------------------------*/ + +/*------------------------Define function prototype--------------------------*/ +/*----------------------------------------------------------------------------- + * Function: RF_ChangeTxPath + * + * Overview: For RL6052, we must change some RF settign for 1T or 2T. + * + * Input: u16 DataRate // 0x80-8f, 0x90-9f + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 09/25/2008 MHC Create Version 0. + * Firmwaer support the utility later. + * + *---------------------------------------------------------------------------*/ +extern void RF_ChangeTxPath(struct net_device* dev, u16 DataRate) +{ +// We do not support gain table change inACUT now !!!! Delete later !!! +#if 0//(RTL92SE_FPGA_VERIFY == 0) + static u1Byte RF_Path_Type = 2; // 1 = 1T 2= 2T + static u4Byte tx_gain_tbl1[6] + = {0x17f50, 0x11f40, 0x0cf30, 0x08720, 0x04310, 0x00100}; + static u4Byte tx_gain_tbl2[6] + = {0x15ea0, 0x10e90, 0x0c680, 0x08250, 0x04040, 0x00030}; + u1Byte i; + + if (RF_Path_Type == 2 && (DataRate&0xF) <= 0x7) + { + // Set TX SYNC power G2G3 loop filter + PHY_SetRFReg(dev, (RF90_RADIO_PATH_E)RF90_PATH_A, + RF_TXPA_G2, bMask20Bits, 0x0f000); + PHY_SetRFReg(dev, (RF90_RADIO_PATH_E)RF90_PATH_A, + RF_TXPA_G3, bMask20Bits, 0xeacf1); + + // Change TX AGC gain table + for (i = 0; i < 6; i++) + PHY_SetRFReg(dev, (RF90_RADIO_PATH_E)RF90_PATH_A, + RF_TX_AGC, bMask20Bits, tx_gain_tbl1[i]); + + // Set PA to high value + PHY_SetRFReg(dev, (RF90_RADIO_PATH_E)RF90_PATH_A, + RF_TXPA_G2, bMask20Bits, 0x01e39); + } + else if (RF_Path_Type == 1 && (DataRate&0xF) >= 0x8) + { + // Set TX SYNC power G2G3 loop filter + PHY_SetRFReg(dev, (RF90_RADIO_PATH_E)RF90_PATH_A, + RF_TXPA_G2, bMask20Bits, 0x04440); + PHY_SetRFReg(dev, (RF90_RADIO_PATH_E)RF90_PATH_A, + RF_TXPA_G3, bMask20Bits, 0xea4f1); + + // Change TX AGC gain table + for (i = 0; i < 6; i++) + PHY_SetRFReg(dev, (RF90_RADIO_PATH_E)RF90_PATH_A, + RF_TX_AGC, bMask20Bits, tx_gain_tbl2[i]); + + // Set PA low gain + PHY_SetRFReg(dev, (RF90_RADIO_PATH_E)RF90_PATH_A, + RF_TXPA_G2, bMask20Bits, 0x01e19); + } +#endif + +} /* RF_ChangeTxPath */ + + +/*----------------------------------------------------------------------------- + * Function: PHY_RF6052SetBandwidth() + * + * Overview: This function is called by SetBWModeCallback8190Pci() only + * + * Input: PADAPTER Adapter + * WIRELESS_BANDWIDTH_E Bandwidth //20M or 40M + * + * Output: NONE + * + * Return: NONE + * + * Note: For RF type 0222D + *---------------------------------------------------------------------------*/ +void PHY_RF6052SetBandwidth(struct net_device* dev, HT_CHANNEL_WIDTH Bandwidth) //20M or 40M +{ + //u8 eRFPath; + //struct r8192_priv *priv = ieee80211_priv(dev); + + + //if (priv->card_8192 == NIC_8192SE) +#ifdef RTL8192SU //YJ,test,090113 + { + switch(Bandwidth) + { + case HT_CHANNEL_WIDTH_20: + //if (priv->card_8192_version >= VERSION_8192S_BCUT) + // rtl8192_setBBreg(dev, rFPGA0_AnalogParameter2, 0xff, 0x58); + + rtl8192_phy_SetRFReg(dev, (RF90_RADIO_PATH_E)RF90_PATH_A, RF_CHNLBW, BIT10|BIT11, 0x01); + break; + case HT_CHANNEL_WIDTH_20_40: + //if (priv->card_8192_version >= VERSION_8192S_BCUT) + // rtl8192_setBBreg(dev, rFPGA0_AnalogParameter2, 0xff, 0x18); + + rtl8192_phy_SetRFReg(dev, (RF90_RADIO_PATH_E)RF90_PATH_A, RF_CHNLBW, BIT10|BIT11, 0x00); + break; + default: + RT_TRACE(COMP_DBG, "PHY_SetRF6052Bandwidth(): unknown Bandwidth: %#X\n",Bandwidth); + break; + } + } +// else +#else + { + for(eRFPath = 0; eRFPath NumTotalRFPath; eRFPath++) + { + switch(Bandwidth) + { + case HT_CHANNEL_WIDTH_20: + //PHY_SetRFReg(Adapter, (RF90_RADIO_PATH_E)RF90_PATH_A, RF_CHNLBW, (BIT10|BIT11), 0x01); + break; + case HT_CHANNEL_WIDTH_20_40: + //PHY_SetRFReg(Adapter, (RF90_RADIO_PATH_E)RF90_PATH_A, RF_CHNLBW, (BIT10|BIT11), 0x00); + break; + default: + RT_TRACE(COMP_DBG, "PHY_SetRF8225Bandwidth(): unknown Bandwidth: %#X\n",Bandwidth ); + break; + + } + } + } +#endif +} + + +/*----------------------------------------------------------------------------- + * Function: PHY_RF6052SetCckTxPower + * + * Overview: + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 11/05/2008 MHC Simulate 8192series.. + * + *---------------------------------------------------------------------------*/ +extern void PHY_RF6052SetCckTxPower(struct net_device* dev, u8 powerlevel) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + u32 TxAGC=0; + + if(priv->ieee80211->scanning == 1) + TxAGC = 0x3f; + else if(priv->bDynamicTxLowPower == true)//cosa 04282008 for cck long range + TxAGC = 0x22; + else + TxAGC = powerlevel; + + //cosa add for lenovo, to pass the safety spec, don't increase power index for different rates. + if(priv->bIgnoreDiffRateTxPowerOffset) + TxAGC = powerlevel; + + if(TxAGC > RF6052_MAX_TX_PWR) + TxAGC = RF6052_MAX_TX_PWR; + + //printk("CCK PWR= %x\n", TxAGC); + rtl8192_setBBreg(dev, rTxAGC_CCK_Mcs32, bTxAGCRateCCK, TxAGC); + +} /* PHY_RF6052SetCckTxPower */ + + + +/*----------------------------------------------------------------------------- + * Function: PHY_RF6052SetOFDMTxPower + * + * Overview: For legacy and HY OFDM, we must read EEPROM TX power index for + * different channel and read original value in TX power register area from + * 0xe00. We increase offset and original value to be correct tx pwr. + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 11/05/2008 MHC Simulate 8192 series method. +* 01/06/2009 MHC 1. Prevent Path B tx power overflow or underflow dure to + * A/B pwr difference or legacy/HT pwr diff. + * 2. We concern with path B legacy/HT OFDM difference. + * 01/22/2009 MHC Support new EPRO format from SD3. + *---------------------------------------------------------------------------*/ + #if 1 +extern void PHY_RF6052SetOFDMTxPower(struct net_device* dev, u8 powerlevel) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + u32 writeVal, powerBase0, powerBase1; + u8 index = 0; + u16 RegOffset[6] = {0xe00, 0xe04, 0xe10, 0xe14, 0xe18, 0xe1c}; + //u8 byte0, byte1, byte2, byte3; + u8 Channel = priv->ieee80211->current_network.channel; + u8 rfa_pwr[4]; + u8 rfa_lower_bound = 0, rfa_upper_bound = 0 /*, rfa_htpwr, rfa_legacypwr*/; + u8 i; + u8 rf_pwr_diff = 0; + u8 Legacy_pwrdiff=0, HT20_pwrdiff=0, BandEdge_Pwrdiff=0; + u8 ofdm_bandedge_chnl_low=0, ofdm_bandedge_chnl_high=0; + + + // We only care about the path A for legacy. + if (priv->EEPROMVersion != 2) + powerBase0 = powerlevel + (priv->LegacyHTTxPowerDiff & 0xf); + else if (priv->EEPROMVersion == 2) // Defined by SD1 Jong + { + // + // 2009/01/21 MH Support new EEPROM format from SD3 requirement + // + Legacy_pwrdiff = priv->TxPwrLegacyHtDiff[RF90_PATH_A][Channel-1]; + // For legacy OFDM, tx pwr always > HT OFDM pwr. We do not care Path B + // legacy OFDM pwr diff. NO BB register to notify HW. + powerBase0 = powerlevel + Legacy_pwrdiff; + //RTPRINT(FPHY, PHY_TXPWR, (" [LagacyToHT40 pwr diff = %d]\n", Legacy_pwrdiff)); + + // Band Edge scheme is enabled for FCC mode + if (priv->TxPwrbandEdgeFlag == 1/* && pHalData->ChannelPlan == 0*/) + { + ofdm_bandedge_chnl_low = 1; + ofdm_bandedge_chnl_high = 11; + #if 0//cosa, Todo: check ofdm 40MHz, when lower and duplicate, the bandedge chnl low=3, high=9 + if (pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_20_40) + { // Is it the same with the document? + if(pHalData->nCur40MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_UPPER) + else if(pHalData->nCur40MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_LOWER; + else + pHalData->nCur40MhzPrimeSC = HAL_PRIME_CHNL_OFFSET_DONT_CARE; + } + #endif + BandEdge_Pwrdiff = 0; + if (Channel <= ofdm_bandedge_chnl_low) + BandEdge_Pwrdiff = priv->TxPwrbandEdgeLegacyOfdm[RF90_PATH_A][0]; + else if (Channel >= ofdm_bandedge_chnl_high) + { + BandEdge_Pwrdiff = priv->TxPwrbandEdgeLegacyOfdm[RF90_PATH_A][1]; + } + powerBase0 -= BandEdge_Pwrdiff; + if (Channel <= ofdm_bandedge_chnl_low || Channel >= ofdm_bandedge_chnl_high) + { + //RTPRINT(FPHY, PHY_TXPWR, (" [OFDM band-edge channel = %d, pwr diff = %d]\n", + //Channel, BandEdge_Pwrdiff)); + } + } + //RTPRINT(FPHY, PHY_TXPWR, (" [OFDM power base index = 0x%x]\n", powerBase0)); + } + powerBase0 = (powerBase0<<24) | (powerBase0<<16) |(powerBase0<<8) |powerBase0; + + //MCS rates + if(priv->EEPROMVersion == 2) + { + //Cosa add for new EEPROM content. 02102009 + + //Check HT20 to HT40 diff + if (priv->CurrentChannelBW == HT_CHANNEL_WIDTH_20) + { + // HT 20<->40 pwr diff + HT20_pwrdiff = priv->TxPwrHt20Diff[RF90_PATH_A][Channel-1]; + + // Calculate Antenna pwr diff + if (HT20_pwrdiff < 8) // 0~+7 + powerlevel += HT20_pwrdiff; + else // index8-15=-8~-1 + powerlevel -= (16-HT20_pwrdiff); + + //RTPRINT(FPHY, PHY_TXPWR, (" [HT20 to HT40 pwrdiff = %d]\n", HT20_pwrdiff)); + //RTPRINT(FPHY, PHY_TXPWR, (" [MCS power base index = 0x%x]\n", powerlevel)); + } + + // Band Edge scheme is enabled for FCC mode + if (priv->TxPwrbandEdgeFlag == 1/* && pHalData->ChannelPlan == 0*/) + { + BandEdge_Pwrdiff = 0; + if (priv->CurrentChannelBW == HT_CHANNEL_WIDTH_20_40) + { + if (Channel <= 3) + BandEdge_Pwrdiff = priv->TxPwrbandEdgeHt40[RF90_PATH_A][0]; + else if (Channel >= 9) + BandEdge_Pwrdiff = priv->TxPwrbandEdgeHt40[RF90_PATH_A][1]; + if (Channel <= 3 || Channel >= 9) + { + //RTPRINT(FPHY, PHY_TXPWR, (" [HT40 band-edge channel = %d, pwr diff = %d]\n", + //Channel, BandEdge_Pwrdiff)); + } + } + else if (priv->CurrentChannelBW == HT_CHANNEL_WIDTH_20) + { + if (Channel <= 1) + BandEdge_Pwrdiff = priv->TxPwrbandEdgeHt20[RF90_PATH_A][0]; + else if (Channel >= 11) + BandEdge_Pwrdiff = priv->TxPwrbandEdgeHt20[RF90_PATH_A][1]; + if (Channel <= 1 || Channel >= 11) + { + //RTPRINT(FPHY, PHY_TXPWR, (" [HT20 band-edge channel = %d, pwr diff = %d]\n", + //Channel, BandEdge_Pwrdiff)); + } + } + powerlevel -= BandEdge_Pwrdiff; + //RTPRINT(FPHY, PHY_TXPWR, (" [MCS power base index = 0x%x]\n", powerlevel)); + } + } + powerBase1 = powerlevel; + powerBase1 = (powerBase1<<24) | (powerBase1<<16) |(powerBase1<<8) |powerBase1; + + //RTPRINT(FPHY, PHY_TXPWR, (" [Legacy/HT power index= %x/%x]\n", powerBase0, powerBase1)); + + for(index=0; index<6; index++) + { + // + // Index 0 & 1= legacy OFDM, 2-5=HT_MCS rate + // + //cosa add for lenovo, to pass the safety spec, don't increase power index for different rates. + if(priv->bIgnoreDiffRateTxPowerOffset) + writeVal = ((index<2)?powerBase0:powerBase1); + else + writeVal = priv->MCSTxPowerLevelOriginalOffset[index] + ((index<2)?powerBase0:powerBase1); + + //RTPRINT(FPHY, PHY_TXPWR, ("Reg 0x%x, Original=%x writeVal=%x\n", + //RegOffset[index], priv->MCSTxPowerLevelOriginalOffset[index], writeVal)); + + // + // If path A and Path B coexist, we must limit Path A tx power. + // Protect Path B pwr over or under flow. We need to calculate upper and + // lower bound of path A tx power. + // + if (priv->rf_type == RF_2T2R) + { + #if 0//cosa, we have only one AntennaTxPwDiff + // HT OFDM + if (index > 1) + { + rf_pwr_diff = pHalData->AntennaTxPwDiff[0]; + } + // Legacy OFDM + else + { + rf_pwr_diff = pHalData->AntTxPwDiffLegacy[0]; + } + #endif + rf_pwr_diff = priv->AntennaTxPwDiff[0]; + //RTPRINT(FPHY, PHY_TXPWR, ("2T2R RF-B to RF-A PWR DIFF=%d\n", rf_pwr_diff)); + + if (rf_pwr_diff >= 8) // Diff=-8~-1 + { // Prevent underflow!! + rfa_lower_bound = 0x10-rf_pwr_diff; + //RTPRINT(FPHY, PHY_TXPWR, ("rfa_lower_bound= %d\n", rfa_lower_bound)); + } + else if (rf_pwr_diff >= 0) // Diff = 0-7 + { + rfa_upper_bound = RF6052_MAX_TX_PWR-rf_pwr_diff; + //RTPRINT(FPHY, PHY_TXPWR, ("rfa_upper_bound= %d\n", rfa_upper_bound)); + } + } + + for (i= 0; i <4; i++) + { + rfa_pwr[i] = (u8)((writeVal & (0x7f<<(i*8)))>>(i*8)); + if (rfa_pwr[i] > RF6052_MAX_TX_PWR) + rfa_pwr[i] = RF6052_MAX_TX_PWR; + + // + // If path A and Path B coexist, we must limit Path A tx power. + // Protect Path B pwr over or under flow. We need to calculate upper and + // lower bound of path A tx power. + // + if (priv->rf_type == RF_2T2R) + { + if (rf_pwr_diff >= 8) // Diff=-8~-1 + { // Prevent underflow!! + if (rfa_pwr[i] = 1) // Diff = 0-7 + { // Prevent overflow + if (rfa_pwr[i] > rfa_upper_bound) + { + //RTPRINT(FPHY, PHY_TXPWR, ("Overflow")); + rfa_pwr[i] = rfa_upper_bound; + } + } + //RTPRINT(FPHY, PHY_TXPWR, ("rfa_pwr[%d]=%x\n", i, rfa_pwr[i])); + } + + } + + // + // Add description: PWDB > threshold!!!High power issue!! + // We must decrease tx power !! Why is the value ??? + // + if(priv->bDynamicTxHighPower == TRUE) + { + // For MCS rate + if(index > 1) + { + writeVal = 0x03030303; + } + // For Legacy rate + else + { + writeVal = (rfa_pwr[3]<<24) | (rfa_pwr[2]<<16) |(rfa_pwr[1]<<8) |rfa_pwr[0]; + } + //RTPRINT(FPHY, PHY_TXPWR, ("HighPower=%08x\n", writeVal)); + } + else + { + writeVal = (rfa_pwr[3]<<24) | (rfa_pwr[2]<<16) |(rfa_pwr[1]<<8) |rfa_pwr[0]; + //RTPRINT(FPHY, PHY_TXPWR, ("NormalPower=%08x\n", writeVal)); + } + + // + // Write different rate set tx power index. + // + //if (DCMD_Test_Flag == 0) + rtl8192_setBBreg(dev, RegOffset[index], 0x7f7f7f7f, writeVal); + } + +} /* PHY_RF6052SetOFDMTxPower */ +#else +extern void PHY_RF6052SetOFDMTxPower(struct net_device* dev, u8 powerlevel) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + u32 writeVal, powerBase0, powerBase1; + u8 index = 0; + u16 RegOffset[6] = {0xe00, 0xe04, 0xe10, 0xe14, 0xe18, 0xe1c}; + u8 byte0, byte1, byte2, byte3; + u8 channel = priv->ieee80211->current_network.channel; + + //Legacy OFDM rates + powerBase0 = powerlevel + (priv->LegacyHTTxPowerDiff & 0xf); + powerBase0 = (powerBase0<<24) | (powerBase0<<16) |(powerBase0<<8) |powerBase0; + + //MCS rates HT OFDM + powerBase1 = powerlevel; + powerBase1 = (powerBase1<<24) | (powerBase1<<16) |(powerBase1<<8) |powerBase1; + + //printk("Legacy/HT PWR= %x/%x\n", powerBase0, powerBase1); + + for(index=0; index<6; index++) + { + // + // Index 0 & 1= legacy OFDM, 2-5=HT_MCS rate + // + writeVal = priv->MCSTxPowerLevelOriginalOffset[index] + ((index<2)?powerBase0:powerBase1); + + //printk("Index = %d Original=%x writeVal=%x\n", index, priv->MCSTxPowerLevelOriginalOffset[index], writeVal); + + byte0 = (u8)(writeVal & 0x7f); + byte1 = (u8)((writeVal & 0x7f00)>>8); + byte2 = (u8)((writeVal & 0x7f0000)>>16); + byte3 = (u8)((writeVal & 0x7f000000)>>24); + + // Max power index = 0x3F Range = 0-0x3F + if(byte0 > RF6052_MAX_TX_PWR) + byte0 = RF6052_MAX_TX_PWR; + if(byte1 > RF6052_MAX_TX_PWR) + byte1 = RF6052_MAX_TX_PWR; + if(byte2 > RF6052_MAX_TX_PWR) + byte2 = RF6052_MAX_TX_PWR; + if(byte3 > RF6052_MAX_TX_PWR) + byte3 = RF6052_MAX_TX_PWR; + + // + // Add description: PWDB > threshold!!!High power issue!! + // We must decrease tx power !! Why is the value ??? + // + if(priv->bDynamicTxHighPower == true) + { + // For MCS rate + if(index > 1) + { + writeVal = 0x03030303; + } + // For Legacy rate + else + { + writeVal = (byte3<<24) | (byte2<<16) |(byte1<<8) |byte0; + } + } + else + { + writeVal = (byte3<<24) | (byte2<<16) |(byte1<<8) |byte0; + } + + // + // Write different rate set tx power index. + // + rtl8192_setBBreg(dev, RegOffset[index], 0x7f7f7f7f, writeVal); + } + +} /* PHY_RF6052SetOFDMTxPower */ +#endif + +RT_STATUS PHY_RF6052_Config(struct net_device* dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + RT_STATUS rtStatus = RT_STATUS_SUCCESS; + //RF90_RADIO_PATH_E eRFPath; + //BB_REGISTER_DEFINITION_T *pPhyReg; + //u32 OrgStoreRFIntSW[RF90_PATH_D+1]; + + // + // Initialize general global value + // + // TODO: Extend RF_PATH_C and RF_PATH_D in the future + if(priv->rf_type == RF_1T1R) + priv->NumTotalRFPath = 1; + else + priv->NumTotalRFPath = 2; + + // + // Config BB and RF + // +// switch( priv->bRegHwParaFile ) +// { +// case 0: +// phy_RF6052_Config_HardCode(dev); +// break; + +// case 1: + rtStatus = phy_RF6052_Config_ParaFile(dev); +// break; + +// case 2: + // Partial Modify. +// phy_RF6052_Config_HardCode(dev); +// phy_RF6052_Config_ParaFile(dev); +// break; + +// default: +// phy_RF6052_Config_HardCode(dev); +// break; +// } + return rtStatus; + +} + +void phy_RF6052_Config_HardCode(struct net_device* dev) +{ + + // Set Default Bandwidth to 20M + //Adapter->HalFunc .SetBWModeHandler(Adapter, HT_CHANNEL_WIDTH_20); + + // TODO: Set Default Channel to channel one for RTL8225 + +} + +RT_STATUS phy_RF6052_Config_ParaFile(struct net_device* dev) +{ + u32 u4RegValue = 0; + //static s1Byte szRadioAFile[] = RTL819X_PHY_RADIO_A; + //static s1Byte szRadioBFile[] = RTL819X_PHY_RADIO_B; + //static s1Byte szRadioBGMFile[] = RTL819X_PHY_RADIO_B_GM; + u8 eRFPath; + RT_STATUS rtStatus = RT_STATUS_SUCCESS; + struct r8192_priv *priv = ieee80211_priv(dev); + BB_REGISTER_DEFINITION_T *pPhyReg; + //u8 eCheckItem; + + + //3//----------------------------------------------------------------- + //3// <2> Initialize RF + //3//----------------------------------------------------------------- + //for(eRFPath = RF90_PATH_A; eRFPath NumTotalRFPath; eRFPath++) + for(eRFPath = 0; eRFPath NumTotalRFPath; eRFPath++) + { + + pPhyReg = &priv->PHYRegDef[eRFPath]; + + /*----Store original RFENV control type----*/ + switch(eRFPath) + { + case RF90_PATH_A: + case RF90_PATH_C: + u4RegValue = rtl8192_QueryBBReg(dev, pPhyReg->rfintfs, bRFSI_RFENV); + break; + case RF90_PATH_B : + case RF90_PATH_D: + u4RegValue = rtl8192_QueryBBReg(dev, pPhyReg->rfintfs, bRFSI_RFENV<<16); + break; + } + + /*----Set RF_ENV enable----*/ + rtl8192_setBBreg(dev, pPhyReg->rfintfe, bRFSI_RFENV<<16, 0x1); + + /*----Set RF_ENV output high----*/ + rtl8192_setBBreg(dev, pPhyReg->rfintfo, bRFSI_RFENV, 0x1); + + /* Set bit number of Address and Data for RF register */ + rtl8192_setBBreg(dev, pPhyReg->rfHSSIPara2, b3WireAddressLength, 0x0); // Set 1 to 4 bits for 8255 + rtl8192_setBBreg(dev, pPhyReg->rfHSSIPara2, b3WireDataLength, 0x0); // Set 0 to 12 bits for 8255 + + + /*----Initialize RF fom connfiguration file----*/ + switch(eRFPath) + { + case RF90_PATH_A: +#if RTL8190_Download_Firmware_From_Header + rtStatus= rtl8192_phy_ConfigRFWithHeaderFile(dev,(RF90_RADIO_PATH_E)eRFPath); +#else + rtStatus = PHY_ConfigRFWithParaFile(Adapter, (char* )&szRadioAFile, (RF90_RADIO_PATH_E)eRFPath); +#endif + break; + case RF90_PATH_B: +#if RTL8190_Download_Firmware_From_Header + rtStatus= rtl8192_phy_ConfigRFWithHeaderFile(dev,(RF90_RADIO_PATH_E)eRFPath); +#else + if(priv->rf_type == RF_2T2R_GREEN) + rtStatus = PHY_ConfigRFWithParaFile(Adapter, (ps1Byte)&szRadioBGMFile, (RF90_RADIO_PATH_E)eRFPath); + else + rtStatus = PHY_ConfigRFWithParaFile(Adapter, (char* )&szRadioBFile, (RF90_RADIO_PATH_E)eRFPath); +#endif + break; + case RF90_PATH_C: + break; + case RF90_PATH_D: + break; + } + + /*----Restore RFENV control type----*/; + switch(eRFPath) + { + case RF90_PATH_A: + case RF90_PATH_C: + rtl8192_setBBreg(dev, pPhyReg->rfintfs, bRFSI_RFENV, u4RegValue); + break; + case RF90_PATH_B : + case RF90_PATH_D: + rtl8192_setBBreg(dev, pPhyReg->rfintfs, bRFSI_RFENV<<16, u4RegValue); + break; + } + + if(rtStatus != RT_STATUS_SUCCESS){ + printk("phy_RF6052_Config_ParaFile():Radio[%d] Fail!!", eRFPath); + goto phy_RF6052_Config_ParaFile_Fail; + } + + } + + RT_TRACE(COMP_INIT, "<---phy_RF6052_Config_ParaFile()\n"); + return rtStatus; + +phy_RF6052_Config_ParaFile_Fail: + return rtStatus; +} + + +// +// ==> RF shadow Operation API Code Section!!! +// +/*----------------------------------------------------------------------------- + * Function: PHY_RFShadowRead + * PHY_RFShadowWrite + * PHY_RFShadowCompare + * PHY_RFShadowRecorver + * PHY_RFShadowCompareAll + * PHY_RFShadowRecorverAll + * PHY_RFShadowCompareFlagSet + * PHY_RFShadowRecorverFlagSet + * + * Overview: When we set RF register, we must write shadow at first. + * When we are running, we must compare shadow abd locate error addr. + * Decide to recorver or not. + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 11/20/2008 MHC Create Version 0. + * + *---------------------------------------------------------------------------*/ +extern u32 PHY_RFShadowRead( + struct net_device * dev, + RF90_RADIO_PATH_E eRFPath, + u32 Offset) +{ + return RF_Shadow[eRFPath][Offset].Value; + +} /* PHY_RFShadowRead */ + + +extern void PHY_RFShadowWrite( + struct net_device * dev, + u32 eRFPath, + u32 Offset, + u32 Data) +{ + //RF_Shadow[eRFPath][Offset].Value = (Data & bMask20Bits); + RF_Shadow[eRFPath][Offset].Value = (Data & bRFRegOffsetMask); + RF_Shadow[eRFPath][Offset].Driver_Write = true; + +} /* PHY_RFShadowWrite */ + + +extern void PHY_RFShadowCompare( + struct net_device * dev, + RF90_RADIO_PATH_E eRFPath, + u32 Offset) +{ + u32 reg; + + // Check if we need to check the register + if (RF_Shadow[eRFPath][Offset].Compare == true) + { + reg = rtl8192_phy_QueryRFReg(dev, eRFPath, Offset, bRFRegOffsetMask); + // Compare shadow and real rf register for 20bits!! + if (RF_Shadow[eRFPath][Offset].Value != reg) + { + // Locate error position. + RF_Shadow[eRFPath][Offset].ErrorOrNot = true; + RT_TRACE(COMP_INIT, "PHY_RFShadowCompare RF-%d Addr%02xErr = %05x", eRFPath, Offset, reg); + } + } + +} /* PHY_RFShadowCompare */ + +extern void PHY_RFShadowRecorver( + struct net_device * dev, + RF90_RADIO_PATH_E eRFPath, + u32 Offset) +{ + // Check if the address is error + if (RF_Shadow[eRFPath][Offset].ErrorOrNot == true) + { + // Check if we need to recorver the register. + if (RF_Shadow[eRFPath][Offset].Recorver == true) + { + rtl8192_phy_SetRFReg(dev, eRFPath, Offset, bRFRegOffsetMask, RF_Shadow[eRFPath][Offset].Value); + RT_TRACE(COMP_INIT, "PHY_RFShadowRecorver RF-%d Addr%02x=%05x", + eRFPath, Offset, RF_Shadow[eRFPath][Offset].Value); + } + } + +} /* PHY_RFShadowRecorver */ + + +extern void PHY_RFShadowCompareAll(struct net_device * dev) +{ + u32 eRFPath; + u32 Offset; + + for (eRFPath = 0; eRFPath < RF6052_MAX_PATH; eRFPath++) + { + for (Offset = 0; Offset <= RF6052_MAX_REG; Offset++) + { + PHY_RFShadowCompare(dev, (RF90_RADIO_PATH_E)eRFPath, Offset); + } + } + +} /* PHY_RFShadowCompareAll */ + + +extern void PHY_RFShadowRecorverAll(struct net_device * dev) +{ + u32 eRFPath; + u32 Offset; + + for (eRFPath = 0; eRFPath < RF6052_MAX_PATH; eRFPath++) + { + for (Offset = 0; Offset <= RF6052_MAX_REG; Offset++) + { + PHY_RFShadowRecorver(dev, (RF90_RADIO_PATH_E)eRFPath, Offset); + } + } + +} /* PHY_RFShadowRecorverAll */ + + +extern void PHY_RFShadowCompareFlagSet( + struct net_device * dev, + RF90_RADIO_PATH_E eRFPath, + u32 Offset, + u8 Type) +{ + // Set True or False!!! + RF_Shadow[eRFPath][Offset].Compare = Type; + +} /* PHY_RFShadowCompareFlagSet */ + + +extern void PHY_RFShadowRecorverFlagSet( + struct net_device * dev, + RF90_RADIO_PATH_E eRFPath, + u32 Offset, + u8 Type) +{ + // Set True or False!!! + RF_Shadow[eRFPath][Offset].Recorver= Type; + +} /* PHY_RFShadowRecorverFlagSet */ + + +extern void PHY_RFShadowCompareFlagSetAll(struct net_device * dev) +{ + u32 eRFPath; + u32 Offset; + + for (eRFPath = 0; eRFPath < RF6052_MAX_PATH; eRFPath++) + { + for (Offset = 0; Offset <= RF6052_MAX_REG; Offset++) + { + // 2008/11/20 MH For S3S4 test, we only check reg 26/27 now!!!! + if (Offset != 0x26 && Offset != 0x27) + PHY_RFShadowCompareFlagSet(dev, (RF90_RADIO_PATH_E)eRFPath, Offset, FALSE); + else + PHY_RFShadowCompareFlagSet(dev, (RF90_RADIO_PATH_E)eRFPath, Offset, TRUE); + } + } + +} /* PHY_RFShadowCompareFlagSetAll */ + + +extern void PHY_RFShadowRecorverFlagSetAll(struct net_device * dev) +{ + u32 eRFPath; + u32 Offset; + + for (eRFPath = 0; eRFPath < RF6052_MAX_PATH; eRFPath++) + { + for (Offset = 0; Offset <= RF6052_MAX_REG; Offset++) + { + // 2008/11/20 MH For S3S4 test, we only check reg 26/27 now!!!! + if (Offset != 0x26 && Offset != 0x27) + PHY_RFShadowRecorverFlagSet(dev, (RF90_RADIO_PATH_E)eRFPath, Offset, FALSE); + else + PHY_RFShadowRecorverFlagSet(dev, (RF90_RADIO_PATH_E)eRFPath, Offset, TRUE); + } + } + +} /* PHY_RFShadowCompareFlagSetAll */ + + + +extern void PHY_RFShadowRefresh(struct net_device * dev) +{ + u32 eRFPath; + u32 Offset; + + for (eRFPath = 0; eRFPath < RF6052_MAX_PATH; eRFPath++) + { + for (Offset = 0; Offset <= RF6052_MAX_REG; Offset++) + { + RF_Shadow[eRFPath][Offset].Value = 0; + RF_Shadow[eRFPath][Offset].Compare = false; + RF_Shadow[eRFPath][Offset].Recorver = false; + RF_Shadow[eRFPath][Offset].ErrorOrNot = false; + RF_Shadow[eRFPath][Offset].Driver_Write = false; + } + } + +} /* PHY_RFShadowRead */ + +/* End of HalRf6052.c */ diff --git a/drivers/staging/rtl8192su/r8192S_rtl6052.h b/drivers/staging/rtl8192su/r8192S_rtl6052.h new file mode 100644 index 000000000000..916603ceaae0 --- /dev/null +++ b/drivers/staging/rtl8192su/r8192S_rtl6052.h @@ -0,0 +1,134 @@ +/****************************************************************************** + * + * (c) Copyright 2008, RealTEK Technologies Inc. All Rights Reserved. + * + * Module: HalRf.h ( Header File) + * + * Note: Collect every HAL RF type exter API or constant. + * + * Function: + * + * Export: + * + * Abbrev: + * + * History: + * Data Who Remark + * + * 09/25/2008 MHC Create initial version. + * + * +******************************************************************************/ +/* Check to see if the file has been included already. */ + + +/*--------------------------Define Parameters-------------------------------*/ + +// +// For RF 6052 Series +// +#define RF6052_MAX_TX_PWR 0x3F +#define RF6052_MAX_REG 0x3F +#define RF6052_MAX_PATH 4 +/*--------------------------Define Parameters-------------------------------*/ + + +/*------------------------------Define structure----------------------------*/ + +/*------------------------------Define structure----------------------------*/ + + +/*------------------------Export global variable----------------------------*/ +/*------------------------Export global variable----------------------------*/ + +/*------------------------Export Marco Definition---------------------------*/ + +/*------------------------Export Marco Definition---------------------------*/ + + +/*--------------------------Exported Function prototype---------------------*/ +//====================================================== +#if 1 +// Function prototypes for HalPhy8225.c +//1====================================================== +extern void PHY_SetRF0222DBandwidth(struct net_device* dev , HT_CHANNEL_WIDTH Bandwidth); //20M or 40M; +extern void PHY_SetRF8225Bandwidth( struct net_device* dev , HT_CHANNEL_WIDTH Bandwidth); +extern bool PHY_RF8225_Config(struct net_device* dev ); +extern void phy_RF8225_Config_HardCode(struct net_device* dev); +extern bool phy_RF8225_Config_ParaFile(struct net_device* dev); +extern void PHY_SetRF8225CckTxPower(struct net_device* dev ,u8 powerlevel); +extern void PHY_SetRF8225OfdmTxPower(struct net_device* dev ,u8 powerlevel); +extern void PHY_SetRF0222DOfdmTxPower(struct net_device* dev ,u8 powerlevel); +extern void PHY_SetRF0222DCckTxPower(struct net_device* dev ,u8 powerlevel); + +//1====================================================== +// Function prototypes for HalPhy8256.c +//1====================================================== +extern void PHY_SetRF8256Bandwidth(struct net_device* dev , HT_CHANNEL_WIDTH Bandwidth); +extern void PHY_RF8256_Config(struct net_device* dev); +extern void phy_RF8256_Config_ParaFile(struct net_device* dev); +extern void PHY_SetRF8256CCKTxPower(struct net_device* dev, u8 powerlevel); +extern void PHY_SetRF8256OFDMTxPower(struct net_device* dev, u8 powerlevel); +#endif + +// +// RF RL6052 Series API +// +extern void RF_ChangeTxPath(struct net_device * dev, u16 DataRate); +extern void PHY_RF6052SetBandwidth(struct net_device * dev,HT_CHANNEL_WIDTH Bandwidth); +extern void PHY_RF6052SetCckTxPower(struct net_device * dev, u8 powerlevel); +extern void PHY_RF6052SetOFDMTxPower(struct net_device * dev, u8 powerlevel); +extern RT_STATUS PHY_RF6052_Config(struct net_device * dev); +extern void PHY_RFShadowRefresh( struct net_device * dev); +extern void PHY_RFShadowWrite( struct net_device* dev, u32 eRFPath, u32 Offset, u32 Data); +#if 0 +// +// RF Shadow operation relative API +// +extern u32 +PHY_RFShadowRead( + struct net_device * dev, + RF90_RADIO_PATH_E eRFPath, + u32 Offset); +extern void +PHY_RFShadowCompare( + struct net_device * dev, + RF90_RADIO_PATH_E eRFPath, + u32 Offset); +extern void +PHY_RFShadowRecorver( + struct net_device * dev, + RF90_RADIO_PATH_E eRFPath, + u32 Offset); +extern void +PHY_RFShadowCompareAll( + struct net_device * dev); +extern void +PHY_RFShadowRecorverAll( + struct net_device * dev); +extern void +PHY_RFShadowCompareFlagSet( + struct net_device * dev, + RF90_RADIO_PATH_E eRFPath, + u32 Offset, + u8 Type); +extern void +PHY_RFShadowRecorverFlagSet( + struct net_device * dev, + RF90_RADIO_PATH_E eRFPath, + u32 Offset, + u8 Type); +extern void +PHY_RFShadowCompareFlagSetAll( + struct net_device * dev); +extern void +PHY_RFShadowRecorverFlagSetAll( + struct net_device * dev); +extern void +PHY_RFShadowRefresh( + struct net_device * dev); +#endif +/*--------------------------Exported Function prototype---------------------*/ + + +/* End of HalRf.h */ diff --git a/drivers/staging/rtl8192su/r8192S_rtl8225.c b/drivers/staging/rtl8192su/r8192S_rtl8225.c new file mode 100644 index 000000000000..09465df2def6 --- /dev/null +++ b/drivers/staging/rtl8192su/r8192S_rtl8225.c @@ -0,0 +1,292 @@ + +#include "r8192U.h" +#include "r8192S_hw.h" +#include "r8192S_phyreg.h" +#include "r8192S_phy.h" +#include "r8192S_rtl8225.h" + +/*---------------------Define local function prototype-----------------------*/ +void phy_RF8225_Config_HardCode(struct net_device* dev ); +bool phy_RF8225_Config_ParaFile(struct net_device* dev ); +/*---------------------Define local function prototype-----------------------*/ +void PHY_SetRF8225OfdmTxPower(struct net_device* dev ,u8 powerlevel) +{ + +} + + + +void PHY_SetRF8225CckTxPower( struct net_device* dev , u8 powerlevel) +{ + +} + + +// TODO: The following RF 022D related function should be removed to HalPhy0222D.c. +void PHY_SetRF0222DOfdmTxPower(struct net_device* dev ,u8 powerlevel) +{ + //TODO: We should set RF TxPower for RF 0222D here!! +} + + + +void PHY_SetRF0222DCckTxPower(struct net_device* dev ,u8 powerlevel) +{ + //TODO: We should set RF TxPower for RF 0222D here!! +} + + +/*----------------------------------------------------------------------------- + * Function: PHY_SetRF0222DBandwidth() + * + * Overview: This function is called by SetBWModeCallback8190Pci() only + * + * Input: PADAPTER Adapter + * WIRELESS_BANDWIDTH_E Bandwidth //20M or 40M + * + * Output: NONE + * + * Return: NONE + * + * Note: For RF type 0222D + *---------------------------------------------------------------------------*/ + //just in phy +void PHY_SetRF0222DBandwidth(struct net_device* dev , HT_CHANNEL_WIDTH Bandwidth) //20M or 40M +{ + u8 eRFPath; + struct r8192_priv *priv = ieee80211_priv(dev); + + + //if (IS_HARDWARE_TYPE_8192S(dev)) + if (1) + { +#ifndef RTL92SE_FPGA_VERIFY + switch(Bandwidth) + { + case HT_CHANNEL_WIDTH_20: +#ifdef FIB_MODIFICATION + write_nic_byte(dev, rFPGA0_AnalogParameter2, 0x58); +#endif + rtl8192_phy_SetRFReg(dev, (RF90_RADIO_PATH_E)RF90_PATH_A, RF_CHNLBW, BIT10|BIT11, 0x01); + break; + case HT_CHANNEL_WIDTH_20_40: +#ifdef FIB_MODIFICATION + write_nic_byte(dev, rFPGA0_AnalogParameter2, 0x18); +#endif + rtl8192_phy_SetRFReg(dev, (RF90_RADIO_PATH_E)RF90_PATH_A, RF_CHNLBW, BIT10|BIT11, 0x00); + break; + default: + ;//RT_TRACE(COMP_DBG, DBG_LOUD, ("PHY_SetRF8225Bandwidth(): unknown Bandwidth: %#X\n",Bandwidth )); + break; + } +#endif + } + else + { + for(eRFPath = 0; eRFPath NumTotalRFPath; eRFPath++) + { + switch(Bandwidth) + { + case HT_CHANNEL_WIDTH_20: + //rtl8192_phy_SetRFReg(Adapter, (RF90_RADIO_PATH_E)RF90_PATH_A, RF_CHNLBW, (BIT10|BIT11), 0x01); + break; + case HT_CHANNEL_WIDTH_20_40: + //rtl8192_phy_SetRFReg(Adapter, (RF90_RADIO_PATH_E)RF90_PATH_A, RF_CHNLBW, (BIT10|BIT11), 0x00); + break; + default: + ;//RT_TRACE(COMP_DBG, DBG_LOUD, ("PHY_SetRF8225Bandwidth(): unknown Bandwidth: %#X\n",Bandwidth )); + break; + + } + } + } + +} + +// TODO: Aabove RF 022D related function should be removed to HalPhy0222D.c. + +/*----------------------------------------------------------------------------- + * Function: PHY_SetRF8225Bandwidth() + * + * Overview: This function is called by SetBWModeCallback8190Pci() only + * + * Input: PADAPTER Adapter + * WIRELESS_BANDWIDTH_E Bandwidth //20M or 40M + * + * Output: NONE + * + * Return: NONE + * + * Note: 8225(zebra1) support 20M only + *---------------------------------------------------------------------------*/ + //just in phy +void PHY_SetRF8225Bandwidth(struct net_device* dev ,HT_CHANNEL_WIDTH Bandwidth) //20M or 40M +{ + u8 eRFPath; + struct r8192_priv *priv = ieee80211_priv(dev); + + //for(eRFPath = RF90_PATH_A; eRFPath NumTotalRFPath; eRFPath++) + for(eRFPath = 0; eRFPath NumTotalRFPath; eRFPath++) + { + switch(Bandwidth) + { + case HT_CHANNEL_WIDTH_20: + // TODO: Update the parameters here + break; + case HT_CHANNEL_WIDTH_20_40: + RT_TRACE(COMP_DBG, "SetChannelBandwidth8190Pci():8225 does not support 40M mode\n"); + break; + default: + RT_TRACE(COMP_DBG, "PHY_SetRF8225Bandwidth(): unknown Bandwidth: %#X\n",Bandwidth ); + break; + + } + } + +} + +//just in phy +bool PHY_RF8225_Config(struct net_device* dev ) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + bool rtStatus = true; + //RF90_RADIO_PATH_E eRFPath; + //BB_REGISTER_DEFINITION_T *pPhyReg; + //u32 OrgStoreRFIntSW[RF90_PATH_D+1]; + + // + // Initialize general global value + // + // TODO: Extend RF_PATH_C and RF_PATH_D in the future + priv->NumTotalRFPath = 2; + + // + // Config BB and RF + // + //switch( Adapter->MgntInfo.bRegHwParaFile ) + //{ + // case 0: + // phy_RF8225_Config_HardCode(dev); + // break; + + // case 1: + // rtStatus = phy_RF8225_Config_ParaFile(dev); + // break; + + // case 2: + // Partial Modify. + phy_RF8225_Config_HardCode(dev); + phy_RF8225_Config_ParaFile(dev); + // break; + + // default: + // phy_RF8225_Config_HardCode(dev); + // break; + //} + return rtStatus; + +} + +//just in 8225 +void phy_RF8225_Config_HardCode(struct net_device* dev) +{ + + // Set Default Bandwidth to 20M + //Adapter->HalFunc .SetBWModeHandler(Adapter, HT_CHANNEL_WIDTH_20); + + // TODO: Set Default Channel to channel one for RTL8225 + +} + +//just in 8225 +bool phy_RF8225_Config_ParaFile(struct net_device* dev) +{ + u32 u4RegValue = 0; + //static char szRadioAFile[] = RTL819X_PHY_RADIO_A; + //static char szRadioBFile[] = RTL819X_PHY_RADIO_B; + u8 eRFPath; + bool rtStatus = true; + struct r8192_priv *priv = ieee80211_priv(dev); + BB_REGISTER_DEFINITION_T *pPhyReg; + //u8 eCheckItem; + +#if 1 + //3//----------------------------------------------------------------- + //3// <2> Initialize RF + //3//----------------------------------------------------------------- + //for(eRFPath = RF90_PATH_A; eRFPath NumTotalRFPath; eRFPath++) + for(eRFPath = 0; eRFPath NumTotalRFPath; eRFPath++) + { + + pPhyReg = &priv->PHYRegDef[eRFPath]; + + /*----Store original RFENV control type----*/ + switch(eRFPath) + { + case RF90_PATH_A: + case RF90_PATH_C: + u4RegValue = rtl8192_QueryBBReg(dev, pPhyReg->rfintfs, bRFSI_RFENV); + break; + case RF90_PATH_B : + case RF90_PATH_D: + u4RegValue = rtl8192_QueryBBReg(dev, pPhyReg->rfintfs, bRFSI_RFENV<<16); + break; + } + + /*----Set RF_ENV enable----*/ + rtl8192_setBBreg(dev, pPhyReg->rfintfe, bRFSI_RFENV<<16, 0x1); + + /*----Set RF_ENV output high----*/ + rtl8192_setBBreg(dev, pPhyReg->rfintfo, bRFSI_RFENV, 0x1); + + /* Set bit number of Address and Data for RF register */ + rtl8192_setBBreg(dev, pPhyReg->rfHSSIPara2, b3WireAddressLength, 0x0); // Set 1 to 4 bits for 8255 + rtl8192_setBBreg(dev, pPhyReg->rfHSSIPara2, b3WireDataLength, 0x0); // Set 0 to 12 bits for 8255 + + + /*----Initialize RF fom connfiguration file----*/ + switch(eRFPath) + { + case RF90_PATH_A: + //rtStatus = PHY_ConfigRFWithParaFile(dev, (char* )&szRadioAFile, (RF90_RADIO_PATH_E)eRFPath); + rtStatus = rtl8192_phy_ConfigRFWithHeaderFile(dev,(RF90_RADIO_PATH_E)eRFPath); + break; + case RF90_PATH_B: + //rtStatus = PHY_ConfigRFWithParaFile(dev, (char* )&szRadioBFile, (RF90_RADIO_PATH_E)eRFPath); + rtStatus = rtl8192_phy_ConfigRFWithHeaderFile(dev,(RF90_RADIO_PATH_E)eRFPath); + break; + case RF90_PATH_C: + break; + case RF90_PATH_D: + break; + } + + /*----Restore RFENV control type----*/; + switch(eRFPath) + { + case RF90_PATH_A: + case RF90_PATH_C: + rtl8192_setBBreg(dev, pPhyReg->rfintfs, bRFSI_RFENV, u4RegValue); + break; + case RF90_PATH_B : + case RF90_PATH_D: + rtl8192_setBBreg(dev, pPhyReg->rfintfs, bRFSI_RFENV<<16, u4RegValue); + break; + } + + if(rtStatus == false){ + //RT_TRACE(COMP_FPGA, DBG_LOUD, ("phy_RF8225_Config_ParaFile():Radio[%d] Fail!!", eRFPath)); + goto phy_RF8225_Config_ParaFile_Fail; + } + + } + + //RT_TRACE(COMP_INIT, DBG_LOUD, ("<---phy_RF8225_Config_ParaFile()\n")); + return rtStatus; + +phy_RF8225_Config_ParaFile_Fail: +#endif + return rtStatus; +} + + diff --git a/drivers/staging/rtl8192su/r8192S_rtl8225.h b/drivers/staging/rtl8192su/r8192S_rtl8225.h new file mode 100644 index 000000000000..8a647284af35 --- /dev/null +++ b/drivers/staging/rtl8192su/r8192S_rtl8225.h @@ -0,0 +1,30 @@ +/* + This is part of the rtl8180-sa2400 driver + released under the GPL (See file COPYING for details). + Copyright (c) 2005 Andrea Merello + + This files contains programming code for the rtl8256 + radio frontend. + + *Many* thanks to Realtek Corp. for their great support! + +*/ + +#ifndef RTL8225H +#define RTL8225H + +#ifdef RTL8190P +#define RTL819X_TOTAL_RF_PATH 4 //for 90P +#else +#define RTL819X_TOTAL_RF_PATH 2 //for 8192U +#endif +extern void PHY_SetRF0222DBandwidth(struct net_device* dev , HT_CHANNEL_WIDTH Bandwidth); //20M or 40M; +extern void PHY_SetRF8225Bandwidth( struct net_device* dev , HT_CHANNEL_WIDTH Bandwidth); +extern bool PHY_RF8225_Config(struct net_device* dev ); +extern void phy_RF8225_Config_HardCode(struct net_device* dev); +extern bool phy_RF8225_Config_ParaFile(struct net_device* dev); +extern void PHY_SetRF8225CckTxPower(struct net_device* dev ,u8 powerlevel); +extern void PHY_SetRF8225OfdmTxPower(struct net_device* dev ,u8 powerlevel); +extern void PHY_SetRF0222DOfdmTxPower(struct net_device* dev ,u8 powerlevel); +extern void PHY_SetRF0222DCckTxPower(struct net_device* dev ,u8 powerlevel); +#endif diff --git a/drivers/staging/rtl8192su/r8192U.h b/drivers/staging/rtl8192su/r8192U.h new file mode 100644 index 000000000000..a2365587b1c7 --- /dev/null +++ b/drivers/staging/rtl8192su/r8192U.h @@ -0,0 +1,2112 @@ +/* + This is part of rtl8187 OpenSource driver. + Copyright (C) Andrea Merello 2004-2005 + Released under the terms of GPL (General Public Licence) + + Parts of this driver are based on the GPL part of the + official realtek driver + + Parts of this driver are based on the rtl8192 driver skeleton + from Patric Schenke & Andres Salomon + + Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver + + We want to tanks the Authors of those projects and the Ndiswrapper + project Authors. +*/ + +#ifndef R819xU_H +#define R819xU_H + +#include +#include +//#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include //for rtnl_lock() +#include +#include +#include // Necessary because we use the proc fs +#include +#include +#include +#include +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)) +#include +#endif +#include "ieee80211.h" + +#ifdef RTL8192SU +#include "r8192S_firmware.h" +#else +#include "r819xU_firmware.h" +#endif + +//#define RTL8192U +#define RTL819xU_MODULE_NAME "rtl819xU" +//added for HW security, john.0629 +#define FALSE 0 +#define TRUE 1 +#define MAX_KEY_LEN 61 +#define KEY_BUF_SIZE 5 + +#define BIT0 0x00000001 +#define BIT1 0x00000002 +#define BIT2 0x00000004 +#define BIT3 0x00000008 +#define BIT4 0x00000010 +#define BIT5 0x00000020 +#define BIT6 0x00000040 +#define BIT7 0x00000080 +#define BIT8 0x00000100 +#define BIT9 0x00000200 +#define BIT10 0x00000400 +#define BIT11 0x00000800 +#define BIT12 0x00001000 +#define BIT13 0x00002000 +#define BIT14 0x00004000 +#define BIT15 0x00008000 +#define BIT16 0x00010000 +#define BIT17 0x00020000 +#define BIT18 0x00040000 +#define BIT19 0x00080000 +#define BIT20 0x00100000 +#define BIT21 0x00200000 +#define BIT22 0x00400000 +#define BIT23 0x00800000 +#define BIT24 0x01000000 +#define BIT25 0x02000000 +#define BIT26 0x04000000 +#define BIT27 0x08000000 +#define BIT28 0x10000000 +#define BIT29 0x20000000 +#define BIT30 0x40000000 +#define BIT31 0x80000000 + +// Rx smooth factor +#define Rx_Smooth_Factor 20 +#if 0 //we need to use RT_TRACE instead DMESG as RT_TRACE will clearly show debug level wb. +#define DMESG(x,a...) printk(KERN_INFO RTL819xU_MODULE_NAME ": " x "\n", ## a) +#define DMESGW(x,a...) printk(KERN_WARNING RTL819xU_MODULE_NAME ": WW:" x "\n", ## a) +#define DMESGE(x,a...) printk(KERN_WARNING RTL819xU_MODULE_NAME ": EE:" x "\n", ## a) +#else +#define DMESG(x,a...) +#define DMESGW(x,a...) +#define DMESGE(x,a...) +extern u32 rt_global_debug_component; +#define RT_TRACE(component, x, args...) \ +do { if(rt_global_debug_component & component) \ + printk(KERN_DEBUG RTL819xU_MODULE_NAME ":" x "\n" , \ + ##args);\ +}while(0); +//---------------------------------------------------------------------- +//// Get 8192SU Rx descriptor. Added by Roger, 2008.04.15. +////---------------------------------------------------------------------- +#define RX_DESC_SIZE 24 +#define RX_DRV_INFO_SIZE_UNIT 8 + +#define IS_UNDER_11N_AES_MODE(_ieee) ((_ieee->pHTInfo->bCurrentHTSupport==TRUE) &&\ + (_ieee->pairwise_key_type==KEY_TYPE_CCMP)) + +#define COMP_TRACE BIT0 // For function call tracing. +#define COMP_DBG BIT1 // Only for temporary debug message. +#define COMP_INIT BIT2 // during driver initialization / halt / reset. + + +#define COMP_RECV BIT3 // Reveive part data path. +#define COMP_SEND BIT4 // Send part path. +#define COMP_IO BIT5 // I/O Related. Added by Annie, 2006-03-02. +#define COMP_POWER BIT6 // 802.11 Power Save mode or System/Device Power state related. +#define COMP_EPROM BIT7 // 802.11 link related: join/start BSS, leave BSS. +#define COMP_SWBW BIT8 // For bandwidth switch. +#define COMP_POWER_TRACKING BIT9 //FOR 8190 TX POWER TRACKING +#define COMP_TURBO BIT10 // For Turbo Mode related. By Annie, 2005-10-21. +#define COMP_QOS BIT11 // For QoS. +#define COMP_RATE BIT12 // For Rate Adaptive mechanism, 2006.07.02, by rcnjko. +#define COMP_LPS BIT13 // For Radio Measurement. +#define COMP_DIG BIT14 // For DIG, 2006.09.25, by rcnjko. +#define COMP_PHY BIT15 +#define COMP_CH BIT16 //channel setting debug +#define COMP_TXAGC BIT17 // For Tx power, 060928, by rcnjko. +#define COMP_HIPWR BIT18 // For High Power Mechanism, 060928, by rcnjko. +#define COMP_HALDM BIT19 // For HW Dynamic Mechanism, 061010, by rcnjko. +#define COMP_SEC BIT20 // Event handling +#define COMP_LED BIT21 // For LED. +#define COMP_RF BIT22 // For RF. +//1!!!!!!!!!!!!!!!!!!!!!!!!!!! +#define COMP_RXDESC BIT23 // Show Rx desc information for SD3 debug. Added by Annie, 2006-07-15. +//1//1Attention Please!!!<11n or 8190 specific code should be put below this line> +//1!!!!!!!!!!!!!!!!!!!!!!!!!!! + +#define COMP_FIRMWARE BIT24 //for firmware downloading +#define COMP_HT BIT25 // For 802.11n HT related information. by Emily 2006-8-11 +#define COMP_AMSDU BIT26 // For A-MSDU Debugging + +#define COMP_SCAN BIT27 +#define COMP_CMD BIT28 +#define COMP_DOWN BIT29 //for rm driver module +#define COMP_RESET BIT30 //for silent reset +#define COMP_ERR BIT31 //for error out, always on +#endif + +#define RTL819x_DEBUG +#ifdef RTL819x_DEBUG +#define assert(expr) \ + if (!(expr)) { \ + printk( "Assertion failed! %s,%s,%s,line=%d\n", \ + #expr,__FILE__,__FUNCTION__,__LINE__); \ + } +//wb added to debug out data buf +//if you want print DATA buffer related BA, please set ieee80211_debug_level to DATA|BA +#define RT_DEBUG_DATA(level, data, datalen) \ + do{ if ((rt_global_debug_component & (level)) == (level)) \ + { \ + int i; \ + u8* pdata = (u8*) data; \ + printk(KERN_DEBUG RTL819xU_MODULE_NAME ": %s()\n", __FUNCTION__); \ + for(i=0; i<(int)(datalen); i++) \ + { \ + printk("%2x ", pdata[i]); \ + if ((i+1)%16 == 0) printk("\n"); \ + } \ + printk("\n"); \ + } \ + } while (0) +#else +#define assert(expr) do {} while (0) +#define RT_DEBUG_DATA(level, data, datalen) do {} while(0) +#endif /* RTL8169_DEBUG */ + +//#ifdef RTL8192SU + //2TODO: We should define 8192S firmware related macro settings here!! + #define RTL819X_DEFAULT_RF_TYPE RF_1T2R + #define RTL819X_TOTAL_RF_PATH 2 + + //#define Rtl819XFwBootArray Rtl8192UsbFwBootArray + //#define Rtl819XFwMainArray Rtl8192UsbFwMainArray + //#define Rtl819XFwDataArray Rtl8192UsbFwDataArray + + #define Rtl819XMACPHY_Array_PG Rtl8192UsbMACPHY_Array_PG + #define Rtl819XMACPHY_Array Rtl8192UsbMACPHY_Array + #define Rtl819XPHY_REGArray Rtl8192UsbPHY_REGArray + #define Rtl819XPHY_REG_1T2RArray Rtl8192UsbPHY_REG_1T2RArray + //#define Rtl819XRadioA_Array Rtl8192UsbRadioA_Array + //#define Rtl819XRadioB_Array Rtl8192UsbRadioB_Array + #define Rtl819XRadioC_Array Rtl8192UsbRadioC_Array + #define Rtl819XRadioD_Array Rtl8192UsbRadioD_Array + + //2008.11.06 Add. + #define Rtl819XFwImageArray Rtl8192SUFwImgArray + #define Rtl819XMAC_Array Rtl8192SUMAC_2T_Array + #define Rtl819XAGCTAB_Array Rtl8192SUAGCTAB_Array + #define Rtl819XPHY_REG_Array Rtl8192SUPHY_REG_2T2RArray + #define Rtl819XPHY_REG_to1T1R_Array Rtl8192SUPHY_ChangeTo_1T1RArray + #define Rtl819XPHY_REG_to1T2R_Array Rtl8192SUPHY_ChangeTo_1T2RArray + #define Rtl819XPHY_REG_to2T2R_Array Rtl8192SUPHY_ChangeTo_2T2RArray + #define Rtl819XPHY_REG_Array_PG Rtl8192SUPHY_REG_Array_PG + #define Rtl819XRadioA_Array Rtl8192SURadioA_1T_Array + #define Rtl819XRadioB_Array Rtl8192SURadioB_Array + #define Rtl819XRadioB_GM_Array Rtl8192SURadioB_GM_Array + #define Rtl819XRadioA_to1T_Array Rtl8192SURadioA_to1T_Array + #define Rtl819XRadioA_to2T_Array Rtl8192SURadioA_to2T_Array +//#endif + +// +// Queue Select Value in TxDesc +// +#define QSLT_BK 0x1 +#define QSLT_BE 0x0 +#define QSLT_VI 0x4 +#define QSLT_VO 0x6 +#define QSLT_BEACON 0x10 +#define QSLT_HIGH 0x11 +#define QSLT_MGNT 0x12 +#define QSLT_CMD 0x13 + +#define DESC90_RATE1M 0x00 +#define DESC90_RATE2M 0x01 +#define DESC90_RATE5_5M 0x02 +#define DESC90_RATE11M 0x03 +#define DESC90_RATE6M 0x04 +#define DESC90_RATE9M 0x05 +#define DESC90_RATE12M 0x06 +#define DESC90_RATE18M 0x07 +#define DESC90_RATE24M 0x08 +#define DESC90_RATE36M 0x09 +#define DESC90_RATE48M 0x0a +#define DESC90_RATE54M 0x0b +#define DESC90_RATEMCS0 0x00 +#define DESC90_RATEMCS1 0x01 +#define DESC90_RATEMCS2 0x02 +#define DESC90_RATEMCS3 0x03 +#define DESC90_RATEMCS4 0x04 +#define DESC90_RATEMCS5 0x05 +#define DESC90_RATEMCS6 0x06 +#define DESC90_RATEMCS7 0x07 +#define DESC90_RATEMCS8 0x08 +#define DESC90_RATEMCS9 0x09 +#define DESC90_RATEMCS10 0x0a +#define DESC90_RATEMCS11 0x0b +#define DESC90_RATEMCS12 0x0c +#define DESC90_RATEMCS13 0x0d +#define DESC90_RATEMCS14 0x0e +#define DESC90_RATEMCS15 0x0f +#define DESC90_RATEMCS32 0x20 + +//#ifdef RTL8192SU +// CCK Rates, TxHT = 0 +#define DESC92S_RATE1M 0x00 +#define DESC92S_RATE2M 0x01 +#define DESC92S_RATE5_5M 0x02 +#define DESC92S_RATE11M 0x03 + +// OFDM Rates, TxHT = 0 +#define DESC92S_RATE6M 0x04 +#define DESC92S_RATE9M 0x05 +#define DESC92S_RATE12M 0x06 +#define DESC92S_RATE18M 0x07 +#define DESC92S_RATE24M 0x08 +#define DESC92S_RATE36M 0x09 +#define DESC92S_RATE48M 0x0a +#define DESC92S_RATE54M 0x0b + +// MCS Rates, TxHT = 1 +#define DESC92S_RATEMCS0 0x0c +#define DESC92S_RATEMCS1 0x0d +#define DESC92S_RATEMCS2 0x0e +#define DESC92S_RATEMCS3 0x0f +#define DESC92S_RATEMCS4 0x10 +#define DESC92S_RATEMCS5 0x11 +#define DESC92S_RATEMCS6 0x12 +#define DESC92S_RATEMCS7 0x13 +#define DESC92S_RATEMCS8 0x14 +#define DESC92S_RATEMCS9 0x15 +#define DESC92S_RATEMCS10 0x16 +#define DESC92S_RATEMCS11 0x17 +#define DESC92S_RATEMCS12 0x18 +#define DESC92S_RATEMCS13 0x19 +#define DESC92S_RATEMCS14 0x1a +#define DESC92S_RATEMCS15 0x1b +#define DESC92S_RATEMCS15_SG 0x1c +#define DESC92S_RATEMCS32 0x20 +//#endif + +#define RTL819X_DEFAULT_RF_TYPE RF_1T2R + +#define IEEE80211_WATCH_DOG_TIME 2000 +#define PHY_Beacon_RSSI_SLID_WIN_MAX 10 +//for txpowertracking by amy +#define OFDM_Table_Length 19 +#define CCK_Table_length 12 + +#ifdef RTL8192SU +// +//Tx Descriptor for RLT8192SU(Normal mode) +// +typedef struct _tx_desc_819x_usb { + // DWORD 0 + u16 PktSize;//:16; + u8 Offset;//:8; + u8 Type:2; // Reserved for MAC header Frame Type subfield. + u8 LastSeg:1; + u8 FirstSeg:1; + u8 LINIP:1; + u8 AMSDU:1; + u8 GF:1; + u8 OWN:1; + + // DWORD 1 + u8 MacID:5; + u8 MoreData:1; + u8 MOREFRAG:1; + u8 PIFS:1; + u8 QueueSelect:5; + u8 AckPolicy:2; + u8 NoACM:1; + u8 NonQos:1; + u8 KeyID:2; + u8 OUI:1; + u8 PktType:1; + u8 EnDescID:1; + u8 SecType:2; + u8 HTC:1; //padding0 + u8 WDS:1; //padding1 + u8 PktOffset:5; //padding_len (hw) + u8 HWPC:1; + + // DWORD 2 + u32 DataRetryLmt:6; + u32 RetryLmtEn:1; + u32 TSFL:5; + u32 RTSRC:6; // Reserved for HW RTS Retry Count. + u32 DATARC:6; // Reserved for HW DATA Retry Count. + u32 Rsvd1:5; + u32 AllowAggregation:1; + u32 BK:1; //Aggregation break. + u32 OwnMAC:1; + + // DWORD 3 + u8 NextHeadPage;//:8; + u8 TailPage;//:8; + u16 Seq:12; + u16 Frag:4; + + // DWORD 4 + u32 RTSRate:6; + u32 DisRTSFB:1; + u32 RTSRateFBLmt:4; + u32 CTS2Self:1; + u32 RTSEn:1; + u32 RaBRSRID:3; //Rate adaptive BRSR ID. + u32 TxHT:1; + u32 TxShort:1;//for data + u32 TxBandwidth:1; + u32 TxSubCarrier:2; + u32 STBC:2; + u32 RD:1; + u32 RTSHT:1; + u32 RTSShort:1; + u32 RTSBW:1; + u32 RTSSubcarrier:2; + u32 RTSSTBC:2; + u32 USERATE:1; + // DWORD 5 + u32 PktID:9; + u32 TxRate:6; + u32 DISFB:1; + u32 DataRateFBLmt:5; + u32 TxAGC:11; + + // DWORD 6 + u16 IPChkSum;//:16; + u16 TCPChkSum;//:16; + + // DWORD 7 + //u16 TxBuffSize;//:16;//pcie + u16 TxBufferSize; + u16 IPHdrOffset:8; + u16 Rsvd2:7; + u16 TCPEn:1; +}tx_desc_819x_usb, *ptx_desc_819x_usb; +typedef struct _tx_status_desc_8192s_usb{ + + //DWORD 0 + u8 TxRate:6; + u8 Rsvd1:1; + u8 BandWidth:1; + u8 RTSRate:6; + u8 AGGLS:1; + u8 AGG:1; + u8 RTSRC:6; + u8 DataRC:6; + u8 FailCause:2; + u8 TxOK:1; + u8 Own:1; + + //DWORD 1 + u16 Seq:12; + u8 QueueSel:5; + u8 MACID:5; + u8 PwrMgt:1; + u8 MoreData:1; + u8 Rsvd2; + + //DWORD 2 + u8 RxAGC1; + u8 RxAGC2; + u8 RxAGC3; + u8 RxAGC4; +}tx_status_desc_8192s_usb, *ptx_status_desc_8192s_usb; +#else +/* for rtl819x */ +typedef struct _tx_desc_819x_usb { + //DWORD 0 + u16 PktSize; + u8 Offset; + u8 Reserved0:3; + u8 CmdInit:1; + u8 LastSeg:1; + u8 FirstSeg:1; + u8 LINIP:1; + u8 OWN:1; + + //DWORD 1 + u8 TxFWInfoSize; + u8 RATid:3; + u8 DISFB:1; + u8 USERATE:1; + u8 MOREFRAG:1; + u8 NoEnc:1; + u8 PIFS:1; + u8 QueueSelect:5; + u8 NoACM:1; + u8 Reserved1:2; + u8 SecCAMID:5; + u8 SecDescAssign:1; + u8 SecType:2; + + //DWORD 2 + u16 TxBufferSize; + //u16 Reserved2; + u8 ResvForPaddingLen:7; + u8 Reserved3:1; + u8 Reserved4; + + //DWORD 3, 4, 5 + u32 Reserved5; + u32 Reserved6; + u32 Reserved7; +}tx_desc_819x_usb, *ptx_desc_819x_usb; +#endif + +#ifdef USB_TX_DRIVER_AGGREGATION_ENABLE +typedef struct _tx_desc_819x_usb_aggr_subframe { + //DWORD 0 + u16 PktSize; + u8 Offset; + u8 TxFWInfoSize; + + //DWORD 1 + u8 RATid:3; + u8 DISFB:1; + u8 USERATE:1; + u8 MOREFRAG:1; + u8 NoEnc:1; + u8 PIFS:1; + u8 QueueSelect:5; + u8 NoACM:1; + u8 Reserved1:2; + u8 SecCAMID:5; + u8 SecDescAssign:1; + u8 SecType:2; + u8 PacketID:7; + u8 OWN:1; +}tx_desc_819x_usb_aggr_subframe, *ptx_desc_819x_usb_aggr_subframe; +#endif + + +#ifdef RTL8192SU +// +//Tx Descriptor for RLT8192SU(Load FW mode) +// +typedef struct _tx_desc_cmd_819x_usb{ + // DWORD 0 + u16 PktSize; + u8 Offset; + u8 Rsvd0:4; + u8 LINIP:1; + u8 Rsvd1:2; + u8 OWN:1; + + // DWORD 1, 2, 3, 4, 5, 6 are all reserved. + u32 Rsvd2; + u32 Rsvd3; + u32 Rsvd4; + u32 Rsvd5; + u32 Rsvd6; + u32 Rsvd7; + + // DWORD 7 + u16 TxBuffSize;//pcie + u16 Rsvd8; +}tx_desc_cmd_819x_usb, *ptx_desc_cmd_819x_usb; +// +//H2C Command for RLT8192SU(Host TxCmd) +// +typedef struct _tx_h2c_desc_cmd_8192s_usb{ + // DWORD 0 + u32 PktSize:16; + u32 Offset:8; + u32 Rsvd0:7; + u32 OWN:1; + + // DWORD 1 + u32 Rsvd1:8; + u32 QSEL:5; + u32 Rsvd2:19; + + // DWORD 2 + u32 Rsvd3; + + // DWORD 3 + u32 NextHeadPage:8; + u32 TailPage:8; + u32 Rsvd4:16; + + // DWORD 4, 5, 6, 7 + u32 Rsvd5; + u32 Rsvd6; + u32 Rsvd7; + u32 Rsvd8; +}tx_h2c_desc_cmd_8192s_usb, *ptx_h2c_desc_cmd_8192s_usb; + + +typedef struct _tx_h2c_cmd_hdr_8192s_usb{ + // DWORD 0 + u32 CmdLen:16; + u32 ElementID:8; + u32 CmdSeq:8; + + // DWORD 1 + u32 Rsvd0; +}tx_h2c_cmd_hdr_8192s_usb, *ptx_h2c_cmd_hdr_8192s_usb; +#else +typedef struct _tx_desc_cmd_819x_usb { + //DWORD 0 + u16 Reserved0; + u8 Reserved1; + u8 Reserved2:3; + u8 CmdInit:1; + u8 LastSeg:1; + u8 FirstSeg:1; + u8 LINIP:1; + u8 OWN:1; + + //DOWRD 1 + //u32 Reserved3; + u8 TxFWInfoSize; + u8 Reserved3; + u8 QueueSelect; + u8 Reserved4; + + //DOWRD 2 + u16 TxBufferSize; + u16 Reserved5; + + //DWORD 3,4,5 + //u32 TxBufferAddr; + //u32 NextDescAddress; + u32 Reserved6; + u32 Reserved7; + u32 Reserved8; +}tx_desc_cmd_819x_usb, *ptx_desc_cmd_819x_usb; +#endif + +#ifdef RTL8192SU +typedef struct _tx_fwinfo_819x_usb{ + //DWORD 0 + u8 TxRate:7; + u8 CtsEnable:1; + u8 RtsRate:7; + u8 RtsEnable:1; + u8 TxHT:1; + u8 Short:1; //Short PLCP for CCK, or short GI for 11n MCS + u8 TxBandwidth:1; // This is used for HT MCS rate only. + u8 TxSubCarrier:2; // This is used for legacy OFDM rate only. + u8 STBC:2; + u8 AllowAggregation:1; + u8 RtsHT:1; //Interpre RtsRate field as high throughput data rate + u8 RtsShort:1; //Short PLCP for CCK, or short GI for 11n MCS + u8 RtsBandwidth:1; // This is used for HT MCS rate only. + u8 RtsSubcarrier:2; // This is used for legacy OFDM rate only. + u8 RtsSTBC:2; + u8 EnableCPUDur:1; //Enable firmware to recalculate and assign packet duration + + //DWORD 1 + u32 RxMF:2; + u32 RxAMD:3; + u32 Reserved1:3; + u32 TxAGCOffSet:4;//TxAGCOffset:4; + u32 TxAGCSign:1; + u32 Tx_INFO_RSVD:6; + u32 PacketID:13; +}tx_fwinfo_819x_usb, *ptx_fwinfo_819x_usb; +#else +typedef struct _tx_fwinfo_819x_usb { + //DOWRD 0 + u8 TxRate:7; + u8 CtsEnable:1; + u8 RtsRate:7; + u8 RtsEnable:1; + u8 TxHT:1; + u8 Short:1; //Short PLCP for CCK, or short GI for 11n MCS + u8 TxBandwidth:1; // This is used for HT MCS rate only. + u8 TxSubCarrier:2; // This is used for legacy OFDM rate only. + u8 STBC:2; + u8 AllowAggregation:1; + u8 RtsHT:1; //Interpre RtsRate field as high throughput data rate + u8 RtsShort:1; //Short PLCP for CCK, or short GI for 11n MCS + u8 RtsBandwidth:1; // This is used for HT MCS rate only. + u8 RtsSubcarrier:2; // This is used for legacy OFDM rate only. + u8 RtsSTBC:2; + u8 EnableCPUDur:1; //Enable firmware to recalculate and assign packet duration + + //DWORD 1 + u32 RxMF:2; + u32 RxAMD:3; + u32 TxPerPktInfoFeedback:1;//1 indicate Tx info gathtered by firmware and returned by Rx Cmd + u32 Reserved1:2; + u32 TxAGCOffSet:4; + u32 TxAGCSign:1; + u32 Tx_INFO_RSVD:6; + u32 PacketID:13; + //u32 Reserved; +}tx_fwinfo_819x_usb, *ptx_fwinfo_819x_usb; +#endif + +typedef struct rtl8192_rx_info { + struct urb *urb; + struct net_device *dev; + u8 out_pipe; +}rtl8192_rx_info ; + +#ifdef RTL8192SU +//typedef struct _RX_DESC_STATUS_8192SU{ +typedef struct rx_desc_819x_usb{ + //DWORD 0 + u16 Length:14; + u16 CRC32:1; + u16 ICV:1; + u8 RxDrvInfoSize:4; + u8 Security:3; + u8 Qos:1; + u8 Shift:2; + u8 PHYStatus:1; + u8 SWDec:1; + u8 LastSeg:1; + u8 FirstSeg:1; + u8 EOR:1; + u8 Own:1; + + //DWORD 1 + u16 MACID:5; + u16 TID:4; + u16 HwRsvd:5; + u16 PAGGR:1; + u16 FAGGR:1; + u8 A1_FIT:4; + u8 A2_FIT:4; + u8 PAM:1; + u8 PWR:1; + u8 MoreData:1; + u8 MoreFrag:1; + u8 Type:2; + u8 MC:1; + u8 BC:1; + + //DWORD 2 + u16 Seq:12; + u16 Frag:4; +#ifdef USB_RX_AGGREGATION_SUPPORT + u8 UsbAggPktNum;//:8; +#else + u8 NextPktLen;//:8; +#endif + u8 Rsvd0:6; + u8 NextIND:1; + u8 Rsvd1:1; + + //DWORD 3 + u8 RxMCS:6; + u8 RxHT:1; + u8 AMSDU:1; + u8 SPLCP:1; + u8 BW:1; + u8 HTC:1; + u8 TCPChkRpt:1; + u8 IPChkRpt:1; + u8 TCPChkValID:1; + u8 HwPCErr:1; + u8 HwPCInd:1; + u16 IV0;//:16; + + //DWORD 4 + u32 IV1; + + //DWORD 5 + u32 TSFL; +//}RX_DESC_STATUS_8192SU, *PRX_DESC_STATUS_8192SU; +}rx_desc_819x_usb, *prx_desc_819x_usb; +#else +typedef struct rx_desc_819x_usb{ + //DOWRD 0 + u16 Length:14; + u16 CRC32:1; + u16 ICV:1; + u8 RxDrvInfoSize; + u8 Shift:2; + u8 PHYStatus:1; + u8 SWDec:1; + //u8 LastSeg:1; + //u8 FirstSeg:1; + //u8 EOR:1; + //u8 OWN:1; + u8 Reserved1:4; + + //DWORD 1 + u32 Reserved2; + + //DWORD 2 + //u32 Reserved3; + + //DWORD 3 + //u32 BufferAddress; + +}rx_desc_819x_usb, *prx_desc_819x_usb; +#endif + +#ifdef USB_RX_AGGREGATION_SUPPORT +typedef struct _rx_desc_819x_usb_aggr_subframe{ + //DOWRD 0 + u16 Length:14; + u16 CRC32:1; + u16 ICV:1; + u8 Offset; + u8 RxDrvInfoSize; + //DOWRD 1 + u8 Shift:2; + u8 PHYStatus:1; + u8 SWDec:1; + u8 Reserved1:4; + u8 Reserved2; + u16 Reserved3; + //DWORD 2 + //u4Byte Reserved3; + //DWORD 3 + //u4Byte BufferAddress; +}rx_desc_819x_usb_aggr_subframe, *prx_desc_819x_usb_aggr_subframe; +#endif + +#ifdef RTL8192SU +// +// Driver info are written to the begining of the RxBuffer +// +//typedef struct _RX_DRIVER_INFO_8192S{ +typedef struct rx_drvinfo_819x_usb{ + // + // Driver info contain PHY status and other variabel size info + // PHY Status content as below + // + + //DWORD 0 + /*u4Byte gain_0:7; + u4Byte trsw_0:1; + u4Byte gain_1:7; + u4Byte trsw_1:1; + u4Byte gain_2:7; + u4Byte trsw_2:1; + u4Byte gain_3:7; + u4Byte trsw_3:1; */ + u8 gain_trsw[4]; + + //DWORD 1 + /*u4Byte pwdb_all:8; + u4Byte cfosho_0:8; + u4Byte cfosho_1:8; + u4Byte cfosho_2:8;*/ + u8 pwdb_all; + u8 cfosho[4]; + + //DWORD 2 + /*u4Byte cfosho_3:8; + u4Byte cfotail_0:8; + u4Byte cfotail_1:8; + u4Byte cfotail_2:8;*/ + u8 cfotail[4]; + + //DWORD 3 + /*u4Byte cfotail_3:8; + u4Byte rxevm_0:8; + u4Byte rxevm_1:8; + u4Byte rxsnr_0:8;*/ + char rxevm[2]; + char rxsnr[4]; + + //DWORD 4 + /*u4Byte rxsnr_1:8; + u4Byte rxsnr_2:8; + u4Byte rxsnr_3:8; + u4Byte pdsnr_0:8;*/ + u8 pdsnr[2]; + + //DWORD 5 + /*u4Byte pdsnr_1:8; + u4Byte csi_current_0:8; + u4Byte csi_current_1:8; + u4Byte csi_target_0:8;*/ + u8 csi_current[2]; + u8 csi_target[2]; + + //DWORD 6 + /*u4Byte csi_target_1:8; + u4Byte sigevm:8; + u4Byte max_ex_pwr:8; + u4Byte ex_intf_flag:1; + u4Byte sgi_en:1; + u4Byte rxsc:2; + u4Byte reserve:4;*/ + u8 sigevm; + u8 max_ex_pwr; + u8 ex_intf_flag:1; + u8 sgi_en:1; + u8 rxsc:2; + u8 reserve:4; + +}rx_drvinfo_819x_usb, *prx_drvinfo_819x_usb; +#else +typedef struct rx_drvinfo_819x_usb{ + //DWORD 0 + u16 Reserved1:12; + u16 PartAggr:1; + u16 FirstAGGR:1; + u16 Reserved2:2; + + u8 RxRate:7; + u8 RxHT:1; + + u8 BW:1; + u8 SPLCP:1; + u8 Reserved3:2; + u8 PAM:1; + u8 Mcast:1; + u8 Bcast:1; + u8 Reserved4:1; + + //DWORD 1 + u32 TSFL; + +}rx_drvinfo_819x_usb, *prx_drvinfo_819x_usb; +#endif + + #define HWSET_MAX_SIZE_92S 128 +#ifdef RTL8192SU + #define MAX_802_11_HEADER_LENGTH 40 + #define MAX_PKT_AGG_NUM 256 + #define TX_PACKET_SHIFT_BYTES USB_HWDESC_HEADER_LEN +#else + #define MAX_802_11_HEADER_LENGTH (40 + MAX_FIRMWARE_INFORMATION_SIZE) + #define MAX_PKT_AGG_NUM 64 + #define TX_PACKET_SHIFT_BYTES (USB_HWDESC_HEADER_LEN + sizeof(tx_fwinfo_819x_usb)) +#endif + +#define MAX_DEV_ADDR_SIZE 8 /* support till 64 bit bus width OS */ +#define MAX_FIRMWARE_INFORMATION_SIZE 32 /*2006/04/30 by Emily forRTL8190*/ +//#define MAX_802_11_HEADER_LENGTH (40 + MAX_FIRMWARE_INFORMATION_SIZE) +#define ENCRYPTION_MAX_OVERHEAD 128 +#define USB_HWDESC_HEADER_LEN sizeof(tx_desc_819x_usb) +//#define TX_PACKET_SHIFT_BYTES (USB_HWDESC_HEADER_LEN + sizeof(tx_fwinfo_819x_usb)) +#define MAX_FRAGMENT_COUNT 8 +#ifdef RTL8192U +#ifdef USB_TX_DRIVER_AGGREGATION_ENABLE +#define MAX_TRANSMIT_BUFFER_SIZE 32000 +#else +#define MAX_TRANSMIT_BUFFER_SIZE 8000 +#endif +#else +#define MAX_TRANSMIT_BUFFER_SIZE (1600+(MAX_802_11_HEADER_LENGTH+ENCRYPTION_MAX_OVERHEAD)*MAX_FRAGMENT_COUNT) +#endif +#ifdef USB_TX_DRIVER_AGGREGATION_ENABLE +#define TX_PACKET_DRVAGGR_SUBFRAME_SHIFT_BYTES (sizeof(tx_desc_819x_usb_aggr_subframe) + sizeof(tx_fwinfo_819x_usb)) +#endif +#define scrclng 4 // octets for crc32 (FCS, ICV) + +typedef enum rf_optype +{ + RF_OP_By_SW_3wire = 0, + RF_OP_By_FW, + RF_OP_MAX +}rf_op_type; +/* 8190 Loopback Mode definition */ +typedef enum _rtl819xUsb_loopback{ + RTL819xU_NO_LOOPBACK = 0, + RTL819xU_MAC_LOOPBACK = 1, + RTL819xU_DMA_LOOPBACK = 2, + RTL819xU_CCK_LOOPBACK = 3, +}rtl819xUsb_loopback_e; + +/* for rtl819x */ +typedef enum _RT_STATUS{ + RT_STATUS_SUCCESS = 0, + RT_STATUS_FAILURE = 1, + RT_STATUS_PENDING = 2, + RT_STATUS_RESOURCE = 3 +}RT_STATUS,*PRT_STATUS; + +//#ifdef RTL8192SU +typedef enum _RTL8192SUSB_LOOPBACK{ + RTL8192SU_NO_LOOPBACK = 0, + RTL8192SU_MAC_LOOPBACK = 1, + RTL8192SU_DMA_LOOPBACK = 2, + RTL8192SU_CCK_LOOPBACK = 3, +}RTL8192SUSB_LOOPBACK_E; +//#endif + + +#if 0 +/* due to rtl8192 firmware */ +typedef enum _desc_packet_type_e{ + DESC_PACKET_TYPE_INIT = 0, + DESC_PACKET_TYPE_NORMAL = 1, +}desc_packet_type_e; + +typedef enum _firmware_source{ + FW_SOURCE_IMG_FILE = 0, + FW_SOURCE_HEADER_FILE = 1, //from header file +}firmware_source_e, *pfirmware_source_e; + +typedef enum _firmware_status{ + FW_STATUS_0_INIT = 0, + FW_STATUS_1_MOVE_BOOT_CODE = 1, + FW_STATUS_2_MOVE_MAIN_CODE = 2, + FW_STATUS_3_TURNON_CPU = 3, + FW_STATUS_4_MOVE_DATA_CODE = 4, + FW_STATUS_5_READY = 5, +}firmware_status_e; + +typedef struct _rt_firmare_seg_container { + u16 seg_size; + u8 *seg_ptr; +}fw_seg_container, *pfw_seg_container; + +#ifdef RTL8192SU +//-------------------------------------------------------------------------------- +// 8192S Firmware related +//-------------------------------------------------------------------------------- +typedef struct _RT_8192S_FIRMWARE_PRIV { //8-bytes alignment required + + //--- LONG WORD 0 ---- + u32 RegulatoryClass; + u32 Rfintfs; + + //--- LONG WORD 1 ---- + u32 ChipVer; + u32 HCISel; + + //--- LONG WORD 2 ---- + u32 IBKMode; + u32 Rsvd00; + + //--- LONG WORD 3 ---- + u32 Rsvd01; + u8 Qos_En; // QoS enable + u8 En40MHz; // 40MHz BW enable + u8 AMSDU2AMPDU_En; //14181 convert AMSDU to AMPDU, 0: disable + u8 AMPDU_En; //111n AMPDU/AMSDU enable + + //--- LONG WORD 4 ---- + u8 rate_control_offload;//FW offloads, 0: driver handles + u8 aggregation_offload; // FW offloads, 0: driver handles + u8 beacon_offload; //FW offloads, 0: driver handles + u8 MLME_offload; // FW offloads, 0: driver handles + u8 hwpc_offload; // FW offloads, 0: driver handles + u8 tcp_checksum_offload; //FW offloads, 0: driver handles + u8 tcp_offload; //FW offloads, 0: driver handles + u8 ps_control_offload; //FW offloads, 0: driver handles + + //--- LONG WORD 5 ---- + u8 WWLAN_Offload; // FW offloads, 0: driver handles + u8 MPMode; // normal mode, 0: MP mode; + u16 Version; //0x8000 ~ 0x8FFF for FPGA version, 0x0000 ~ 0x7FFF for ASIC version, + u16 Signature; //0x12: 8712, 0x92: 8192S + u16 Rsvd11; + +// u32 rsvd1; +// u32 wireless_band; //no A-band exists in 8712 +}RT_8192S_FIRMWARE_PRIV, *PRT_8192S_FIRMWARE_PRIV; + +typedef struct _RT_8192S_FIRMWARE_HDR {//8-byte alinment required + + //--- LONG WORD 0 ---- + u16 Signature; + u16 Version; //0x8000 ~ 0x8FFF for FPGA version, 0x0000 ~ 0x7FFF for ASIC version, + u32 DMEMSize; //define the size of boot loader + + + //--- LONG WORD 1 ---- + u32 IMG_IMEM_SIZE; //define the size of FW in IMEM + u32 IMG_SRAM_SIZE; //define the size of FW in SRAM + + //--- LONG WORD 2 ---- + u32 FW_PRIV_SIZE; //define the size of DMEM variable + u32 Rsvd0; + + //--- LONG WORD 3 ---- + u32 Rsvd1; + u32 Rsvd2; + + RT_8192S_FIRMWARE_PRIV FWPriv; + +}RT_8192S_FIRMWARE_HDR, *PRT_8192S_FIRMWARE_HDR; + +#define RT_8192S_FIRMWARE_HDR_SIZE 80 + +typedef enum _FIRMWARE_8192S_STATUS{ + FW_STATUS_INIT = 0, + FW_STATUS_LOAD_IMEM = 1, + FW_STATUS_LOAD_EMEM = 2, + FW_STATUS_LOAD_DMEM = 3, + FW_STATUS_READY = 4, +}FIRMWARE_8192S_STATUS; + +#define RTL8190_MAX_FIRMWARE_CODE_SIZE 64000 //64k + +typedef struct _rt_firmware{ + firmware_source_e eFWSource; + PRT_8192S_FIRMWARE_HDR pFwHeader; + FIRMWARE_8192S_STATUS FWStatus; + u8 FwIMEM[64000]; + u8 FwEMEM[64000]; + u32 FwIMEMLen; + u32 FwEMEMLen; + u8 szFwTmpBuffer[164000]; + u16 CmdPacketFragThresold; + //firmware_status_e firmware_status;//in 92u temp FIXLZM + //u16 cmdpacket_frag_thresold;//in 92u temp FIXLZM + //u8 firmware_buf[RTL8190_MAX_FIRMWARE_CODE_SIZE];//in 92u temp FIXLZM + //u16 firmware_buf_size;//in 92u temp FIXLZM + +}rt_firmware, *prt_firmware; +#else +typedef struct _rt_firmware{ + firmware_status_e firmware_status; + u16 cmdpacket_frag_thresold; +#define RTL8190_MAX_FIRMWARE_CODE_SIZE 64000 //64k +#define MAX_FW_INIT_STEP 3 + u8 firmware_buf[MAX_FW_INIT_STEP][RTL8190_MAX_FIRMWARE_CODE_SIZE]; + u16 firmware_buf_size[MAX_FW_INIT_STEP]; +}rt_firmware, *prt_firmware; +#endif +typedef struct _rt_firmware_info_819xUsb{ + u8 sz_info[16]; +}rt_firmware_info_819xUsb, *prt_firmware_info_819xUsb; +#endif + +//+by amy 080507 +#define MAX_RECEIVE_BUFFER_SIZE 9100 // Add this to 9100 bytes to receive A-MSDU from RT-AP + + +/* Firmware Queue Layout */ +#define NUM_OF_FIRMWARE_QUEUE 10 +#define NUM_OF_PAGES_IN_FW 0x100 + +#ifdef USE_ONE_PIPE +#define NUM_OF_PAGE_IN_FW_QUEUE_BE 0x000 +#define NUM_OF_PAGE_IN_FW_QUEUE_BK 0x000 +#define NUM_OF_PAGE_IN_FW_QUEUE_VI 0x0ff +#define NUM_OF_PAGE_IN_FW_QUEUE_VO 0x000 +#define NUM_OF_PAGE_IN_FW_QUEUE_HCCA 0 +#define NUM_OF_PAGE_IN_FW_QUEUE_CMD 0x0 +#define NUM_OF_PAGE_IN_FW_QUEUE_MGNT 0x00 +#define NUM_OF_PAGE_IN_FW_QUEUE_HIGH 0 +#define NUM_OF_PAGE_IN_FW_QUEUE_BCN 0x0 +#define NUM_OF_PAGE_IN_FW_QUEUE_PUB 0x00 +#else + +#define NUM_OF_PAGE_IN_FW_QUEUE_BE 0x020 +#define NUM_OF_PAGE_IN_FW_QUEUE_BK 0x020 +#define NUM_OF_PAGE_IN_FW_QUEUE_VI 0x040 +#define NUM_OF_PAGE_IN_FW_QUEUE_VO 0x040 +#define NUM_OF_PAGE_IN_FW_QUEUE_HCCA 0 +#define NUM_OF_PAGE_IN_FW_QUEUE_CMD 0x4 +#define NUM_OF_PAGE_IN_FW_QUEUE_MGNT 0x20 +#define NUM_OF_PAGE_IN_FW_QUEUE_HIGH 0 +#define NUM_OF_PAGE_IN_FW_QUEUE_BCN 0x4 +#define NUM_OF_PAGE_IN_FW_QUEUE_PUB 0x18 + +#endif + +#define APPLIED_RESERVED_QUEUE_IN_FW 0x80000000 +#define RSVD_FW_QUEUE_PAGE_BK_SHIFT 0x00 +#define RSVD_FW_QUEUE_PAGE_BE_SHIFT 0x08 +#define RSVD_FW_QUEUE_PAGE_VI_SHIFT 0x10 +#define RSVD_FW_QUEUE_PAGE_VO_SHIFT 0x18 +#define RSVD_FW_QUEUE_PAGE_MGNT_SHIFT 0x10 +#define RSVD_FW_QUEUE_PAGE_CMD_SHIFT 0x08 +#define RSVD_FW_QUEUE_PAGE_BCN_SHIFT 0x00 +#define RSVD_FW_QUEUE_PAGE_PUB_SHIFT 0x08 +//================================================================= +//================================================================= + +#define EPROM_93c46 0 +#define EPROM_93c56 1 + +#define DEFAULT_FRAG_THRESHOLD 2342U +#define MIN_FRAG_THRESHOLD 256U +#define DEFAULT_BEACONINTERVAL 0x64U +#define DEFAULT_BEACON_ESSID "Rtl819xU" + +#define DEFAULT_SSID "" +#define DEFAULT_RETRY_RTS 7 +#define DEFAULT_RETRY_DATA 7 +#define PRISM_HDR_SIZE 64 + +#define PHY_RSSI_SLID_WIN_MAX 100 + + +typedef enum _WIRELESS_MODE { + WIRELESS_MODE_UNKNOWN = 0x00, + WIRELESS_MODE_A = 0x01, + WIRELESS_MODE_B = 0x02, + WIRELESS_MODE_G = 0x04, + WIRELESS_MODE_AUTO = 0x08, + WIRELESS_MODE_N_24G = 0x10, + WIRELESS_MODE_N_5G = 0x20 +} WIRELESS_MODE; + + +#define RTL_IOCTL_WPA_SUPPLICANT SIOCIWFIRSTPRIV+30 + +typedef struct buffer +{ + struct buffer *next; + u32 *buf; + +} buffer; + +typedef struct rtl_reg_debug{ + unsigned int cmd; + struct { + unsigned char type; + unsigned char addr; + unsigned char page; + unsigned char length; + } head; + unsigned char buf[0xff]; +}rtl_reg_debug; + + + + + +#if 0 + +typedef struct tx_pendingbuf +{ + struct ieee80211_txb *txb; + short ispending; + short descfrag; +} tx_pendigbuf; + +#endif + +typedef struct _rt_9x_tx_rate_history { + u32 cck[4]; + u32 ofdm[8]; + // HT_MCS[0][]: BW=0 SG=0 + // HT_MCS[1][]: BW=1 SG=0 + // HT_MCS[2][]: BW=0 SG=1 + // HT_MCS[3][]: BW=1 SG=1 + u32 ht_mcs[4][16]; +}rt_tx_rahis_t, *prt_tx_rahis_t; +typedef struct _RT_SMOOTH_DATA_4RF { + char elements[4][100];//array to store values + u32 index; //index to current array to store + u32 TotalNum; //num of valid elements + u32 TotalVal[4]; //sum of valid elements +}RT_SMOOTH_DATA_4RF, *PRT_SMOOTH_DATA_4RF; + +#define MAX_8192U_RX_SIZE 8192 // This maybe changed for D-cut larger aggregation size +//stats seems messed up, clean it ASAP +typedef struct Stats +{ + unsigned long txrdu; +// unsigned long rxrdu; + //unsigned long rxnolast; + //unsigned long rxnodata; +// unsigned long rxreset; +// unsigned long rxnopointer; + unsigned long rxok; + unsigned long rxframgment; + unsigned long rxcmdpkt[4]; //08/05/08 amy rx cmd element txfeedback/bcn report/cfg set/query + unsigned long rxurberr; + unsigned long rxstaterr; + unsigned long received_rate_histogram[4][32]; //0: Total, 1:OK, 2:CRC, 3:ICV, 2007 07 03 cosa + unsigned long received_preamble_GI[2][32]; //0: Long preamble/GI, 1:Short preamble/GI + unsigned long rx_AMPDUsize_histogram[5]; // level: (<4K), (4K~8K), (8K~16K), (16K~32K), (32K~64K) + unsigned long rx_AMPDUnum_histogram[5]; // level: (<5), (5~10), (10~20), (20~40), (>40) + unsigned long numpacket_matchbssid; // debug use only. + unsigned long numpacket_toself; // debug use only. + unsigned long num_process_phyinfo; // debug use only. + unsigned long numqry_phystatus; + unsigned long numqry_phystatusCCK; + unsigned long numqry_phystatusHT; + unsigned long received_bwtype[5]; //0: 20M, 1: funn40M, 2: upper20M, 3: lower20M, 4: duplicate + unsigned long txnperr; + unsigned long txnpdrop; + unsigned long txresumed; +// unsigned long rxerr; +// unsigned long rxoverflow; +// unsigned long rxint; + unsigned long txnpokint; +// unsigned long txhpokint; +// unsigned long txhperr; +// unsigned long ints; +// unsigned long shints; + unsigned long txoverflow; +// unsigned long rxdmafail; +// unsigned long txbeacon; +// unsigned long txbeaconerr; + unsigned long txlpokint; + unsigned long txlpdrop; + unsigned long txlperr; + unsigned long txbeokint; + unsigned long txbedrop; + unsigned long txbeerr; + unsigned long txbkokint; + unsigned long txbkdrop; + unsigned long txbkerr; + unsigned long txviokint; + unsigned long txvidrop; + unsigned long txvierr; + unsigned long txvookint; + unsigned long txvodrop; + unsigned long txvoerr; + unsigned long txbeaconokint; + unsigned long txbeacondrop; + unsigned long txbeaconerr; + unsigned long txmanageokint; + unsigned long txmanagedrop; + unsigned long txmanageerr; + unsigned long txdatapkt; + unsigned long txfeedback; + unsigned long txfeedbackok; + + unsigned long txoktotal; + unsigned long txokbytestotal; + unsigned long txokinperiod; + unsigned long txmulticast; + unsigned long txbytesmulticast; + unsigned long txbroadcast; + unsigned long txbytesbroadcast; + unsigned long txunicast; + unsigned long txbytesunicast; + + unsigned long rxoktotal; + unsigned long rxbytesunicast; + unsigned long txfeedbackfail; + unsigned long txerrtotal; + unsigned long txerrbytestotal; + unsigned long txerrmulticast; + unsigned long txerrbroadcast; + unsigned long txerrunicast; + unsigned long txretrycount; + unsigned long txfeedbackretry; + u8 last_packet_rate; + unsigned long slide_signal_strength[100]; + unsigned long slide_evm[100]; + unsigned long slide_rssi_total; // For recording sliding window's RSSI value + unsigned long slide_evm_total; // For recording sliding window's EVM value + long signal_strength; // Transformed, in dbm. Beautified signal strength for UI, not correct. + long signal_quality; + long last_signal_strength_inpercent; + long recv_signal_power; // Correct smoothed ss in Dbm, only used in driver to report real power now. + u8 rx_rssi_percentage[4]; + u8 rx_evm_percentage[2]; + long rxSNRdB[4]; + rt_tx_rahis_t txrate; + u32 Slide_Beacon_pwdb[100]; //cosa add for beacon rssi + u32 Slide_Beacon_Total; //cosa add for beacon rssi + RT_SMOOTH_DATA_4RF cck_adc_pwdb; + + u32 CurrentShowTxate; +} Stats; + + +// Bandwidth Offset +#define HAL_PRIME_CHNL_OFFSET_DONT_CARE 0 +#define HAL_PRIME_CHNL_OFFSET_LOWER 1 +#define HAL_PRIME_CHNL_OFFSET_UPPER 2 + +//+by amy 080507 + +typedef struct ChnlAccessSetting { + u16 SIFS_Timer; + u16 DIFS_Timer; + u16 SlotTimeTimer; + u16 EIFS_Timer; + u16 CWminIndex; + u16 CWmaxIndex; +}*PCHANNEL_ACCESS_SETTING,CHANNEL_ACCESS_SETTING; + +typedef struct _BB_REGISTER_DEFINITION{ + u32 rfintfs; // set software control: // 0x870~0x877[8 bytes] + u32 rfintfi; // readback data: // 0x8e0~0x8e7[8 bytes] + u32 rfintfo; // output data: // 0x860~0x86f [16 bytes] + u32 rfintfe; // output enable: // 0x860~0x86f [16 bytes] + u32 rf3wireOffset; // LSSI data: // 0x840~0x84f [16 bytes] + u32 rfLSSI_Select; // BB Band Select: // 0x878~0x87f [8 bytes] + u32 rfTxGainStage; // Tx gain stage: // 0x80c~0x80f [4 bytes] + u32 rfHSSIPara1; // wire parameter control1 : // 0x820~0x823,0x828~0x82b, 0x830~0x833, 0x838~0x83b [16 bytes] + u32 rfHSSIPara2; // wire parameter control2 : // 0x824~0x827,0x82c~0x82f, 0x834~0x837, 0x83c~0x83f [16 bytes] + u32 rfSwitchControl; //Tx Rx antenna control : // 0x858~0x85f [16 bytes] + u32 rfAGCControl1; //AGC parameter control1 : // 0xc50~0xc53,0xc58~0xc5b, 0xc60~0xc63, 0xc68~0xc6b [16 bytes] + u32 rfAGCControl2; //AGC parameter control2 : // 0xc54~0xc57,0xc5c~0xc5f, 0xc64~0xc67, 0xc6c~0xc6f [16 bytes] + u32 rfRxIQImbalance; //OFDM Rx IQ imbalance matrix : // 0xc14~0xc17,0xc1c~0xc1f, 0xc24~0xc27, 0xc2c~0xc2f [16 bytes] + u32 rfRxAFE; //Rx IQ DC ofset and Rx digital filter, Rx DC notch filter : // 0xc10~0xc13,0xc18~0xc1b, 0xc20~0xc23, 0xc28~0xc2b [16 bytes] + u32 rfTxIQImbalance; //OFDM Tx IQ imbalance matrix // 0xc80~0xc83,0xc88~0xc8b, 0xc90~0xc93, 0xc98~0xc9b [16 bytes] + u32 rfTxAFE; //Tx IQ DC Offset and Tx DFIR type // 0xc84~0xc87,0xc8c~0xc8f, 0xc94~0xc97, 0xc9c~0xc9f [16 bytes] + u32 rfLSSIReadBack; //LSSI RF readback data // 0x8a0~0x8af [16 bytes] + u32 rfLSSIReadBackPi; //LSSI RF readback data PI mode 0x8b8-8bc for Path A and B +}BB_REGISTER_DEFINITION_T, *PBB_REGISTER_DEFINITION_T; + +typedef enum _RT_RF_TYPE_819xU{ + RF_TYPE_MIN = 0, + RF_8225, + RF_8256, + RF_8258, + RF_6052=4, // 4 11b/g/n RF + RF_PSEUDO_11N = 5, +}RT_RF_TYPE_819xU, *PRT_RF_TYPE_819xU; + +//#ifdef RTL8192SU +typedef enum _RF_POWER_STATE{ + RF_ON, + RF_SLEEP, + RF_OFF, + RF_SHUT_DOWN, +}RF_POWER_STATE, *PRF_POWER_STATE; +//#endif + +typedef struct _rate_adaptive +{ + u8 rate_adaptive_disabled; + u8 ratr_state; + u16 reserve; + + u32 high_rssi_thresh_for_ra; + u32 high2low_rssi_thresh_for_ra; + u8 low2high_rssi_thresh_for_ra40M; + u32 low_rssi_thresh_for_ra40M; + u8 low2high_rssi_thresh_for_ra20M; + u32 low_rssi_thresh_for_ra20M; + u32 upper_rssi_threshold_ratr; + u32 middle_rssi_threshold_ratr; + u32 low_rssi_threshold_ratr; + u32 low_rssi_threshold_ratr_40M; + u32 low_rssi_threshold_ratr_20M; + u8 ping_rssi_enable; //cosa add for test + u32 ping_rssi_ratr; //cosa add for test + u32 ping_rssi_thresh_for_ra;//cosa add for test + u32 last_ratr; + +} rate_adaptive, *prate_adaptive; + +#define TxBBGainTableLength 37 +#define CCKTxBBGainTableLength 23 + +typedef struct _txbbgain_struct +{ + long txbb_iq_amplifygain; + u32 txbbgain_value; +} txbbgain_struct, *ptxbbgain_struct; + +typedef struct _ccktxbbgain_struct +{ + //The Value is from a22 to a29 one Byte one time is much Safer + u8 ccktxbb_valuearray[8]; +} ccktxbbgain_struct,*pccktxbbgain_struct; + + +typedef struct _init_gain +{ + u8 xaagccore1; + u8 xbagccore1; + u8 xcagccore1; + u8 xdagccore1; + u8 cca; + +} init_gain, *pinit_gain; +//by amy 0606 + +typedef struct _phy_ofdm_rx_status_report_819xusb +{ + u8 trsw_gain_X[4]; + u8 pwdb_all; + u8 cfosho_X[4]; + u8 cfotail_X[4]; + u8 rxevm_X[2]; + u8 rxsnr_X[4]; + u8 pdsnr_X[2]; + u8 csi_current_X[2]; + u8 csi_target_X[2]; + u8 sigevm; + u8 max_ex_pwr; + u8 sgi_en; + u8 rxsc_sgien_exflg; +}phy_sts_ofdm_819xusb_t; + +typedef struct _phy_cck_rx_status_report_819xusb +{ + /* For CCK rate descriptor. This is a unsigned 8:1 variable. LSB bit presend + 0.5. And MSB 7 bts presend a signed value. Range from -64~+63.5. */ + u8 adc_pwdb_X[4]; + u8 sq_rpt; + u8 cck_agc_rpt; +}phy_sts_cck_819xusb_t; + + +typedef struct _phy_ofdm_rx_status_rxsc_sgien_exintfflag{ + u8 reserved:4; + u8 rxsc:2; + u8 sgi_en:1; + u8 ex_intf_flag:1; +}phy_ofdm_rx_status_rxsc_sgien_exintfflag; + +typedef enum _RT_CUSTOMER_ID +{ + RT_CID_DEFAULT = 0, + RT_CID_8187_ALPHA0 = 1, + RT_CID_8187_SERCOMM_PS = 2, + RT_CID_8187_HW_LED = 3, + RT_CID_8187_NETGEAR = 4, + RT_CID_WHQL = 5, + RT_CID_819x_CAMEO = 6, + RT_CID_819x_RUNTOP = 7, + RT_CID_819x_Senao = 8, + RT_CID_TOSHIBA = 9, // Merge by Jacken, 2008/01/31. + RT_CID_819x_Netcore = 10, + RT_CID_Nettronix = 11, + RT_CID_DLINK = 12, + RT_CID_PRONET = 13, +}RT_CUSTOMER_ID, *PRT_CUSTOMER_ID; + +//================================================================================ +// LED customization. +//================================================================================ + +typedef enum _LED_STRATEGY_8190{ + SW_LED_MODE0, // SW control 1 LED via GPIO0. It is default option. + SW_LED_MODE1, // SW control for PCI Express + SW_LED_MODE2, // SW control for Cameo. + SW_LED_MODE3, // SW contorl for RunTop. + SW_LED_MODE4, // SW control for Netcore + HW_LED, // HW control 2 LEDs, LED0 and LED1 (there are 4 different control modes) +}LED_STRATEGY_8190, *PLED_STRATEGY_8190; + +typedef enum _RESET_TYPE { + RESET_TYPE_NORESET = 0x00, + RESET_TYPE_NORMAL = 0x01, + RESET_TYPE_SILENT = 0x02 +} RESET_TYPE; + +/* The simple tx command OP code. */ +typedef enum _tag_TxCmd_Config_Index{ + TXCMD_TXRA_HISTORY_CTRL = 0xFF900000, + TXCMD_RESET_TX_PKT_BUFF = 0xFF900001, + TXCMD_RESET_RX_PKT_BUFF = 0xFF900002, + TXCMD_SET_TX_DURATION = 0xFF900003, + TXCMD_SET_RX_RSSI = 0xFF900004, + TXCMD_SET_TX_PWR_TRACKING = 0xFF900005, + TXCMD_XXXX_CTRL, +}DCMD_TXCMD_OP; + +typedef enum{ + NIC_8192U = 1, + NIC_8190P = 2, + NIC_8192E = 3, + NIC_8192SE = 4, + NIC_8192SU = 5, + } nic_t; + +//definded by WB. Ready to fill handlers for different NIC types. +//add handle here when necessary. +struct rtl819x_ops{ + nic_t nic_type; + void (* rtl819x_read_eeprom_info)(struct net_device *dev); + short (* rtl819x_tx)(struct net_device *dev, struct sk_buff* skb); + short (* rtl819x_tx_cmd)(struct net_device *dev, struct sk_buff *skb); + void (* rtl819x_rx_nomal)(struct sk_buff* skb); + void (* rtl819x_rx_cmd)(struct sk_buff *skb); + bool (* rtl819x_adapter_start)(struct net_device *dev); + void (* rtl819x_link_change)(struct net_device *dev); + void (* rtl819x_initial_gain)(struct net_device *dev,u8 Operation); + void (* rtl819x_query_rxdesc_status)(struct sk_buff *skb, struct ieee80211_rx_stats *stats, bool bIsRxAggrSubframe); +}; + +typedef struct r8192_priv +{ + struct rtl819x_ops* ops; + struct usb_device *udev; + //added for maintain info from eeprom + short epromtype; + u16 eeprom_vid; + u16 eeprom_pid; + u8 eeprom_CustomerID; + u8 eeprom_SubCustomerID; + u8 eeprom_ChannelPlan; + RT_CUSTOMER_ID CustomerID; + LED_STRATEGY_8190 LedStrategy; + u8 txqueue_to_outpipemap[9]; + u8 RtOutPipes[16]; + u8 RtInPipes[16]; + u8 ep_in_num; + u8 ep_out_num; + u8 ep_num; + int irq; + struct ieee80211_device *ieee80211; + + short card_8192; /* O: rtl8192, 1:rtl8185 V B/C, 2:rtl8185 V D */ + u8 card_8192_version; /* if TCR reports card V B/C this discriminates */ +// short phy_ver; /* meaningful for rtl8225 1:A 2:B 3:C */ + short enable_gpio0; + enum card_type {PCI,MINIPCI,CARDBUS,USB}card_type; + short hw_plcp_len; + short plcp_preamble_mode; + + spinlock_t irq_lock; +// spinlock_t irq_th_lock; + spinlock_t tx_lock; + spinlock_t ps_lock; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)) + struct semaphore mutex; +#else + struct mutex mutex; +#endif + spinlock_t rf_lock; //used to lock rf write operation added by wb + + u16 irq_mask; +// short irq_enabled; +// struct net_device *dev; //comment this out. + short chan; + short sens; + short max_sens; + + + // u8 chtxpwr[15]; //channels from 1 to 14, 0 not used +// u8 chtxpwr_ofdm[15]; //channels from 1 to 14, 0 not used +// u8 cck_txpwr_base; +// u8 ofdm_txpwr_base; +// u8 challow[15]; //channels from 1 to 14, 0 not used + short up; + short crcmon; //if 1 allow bad crc frame reception in monitor mode +// short prism_hdr; + +// struct timer_list scan_timer; + /*short scanpending; + short stopscan;*/ +// spinlock_t scan_lock; +// u8 active_probe; + //u8 active_scan_num; + struct semaphore wx_sem; + struct semaphore rf_sem; //used to lock rf write operation added by wb, modified by david +// short hw_wep; + +// short digphy; +// short antb; +// short diversity; +// u8 cs_treshold; +// short rcr_csense; + u8 rf_type; //0 means 1T2R, 1 means 2T4R + RT_RF_TYPE_819xU rf_chip; + +// u32 key0[4]; + short (*rf_set_sens)(struct net_device *dev,short sens); + u8 (*rf_set_chan)(struct net_device *dev,u8 ch); + void (*rf_close)(struct net_device *dev); + void (*rf_init)(struct net_device *dev); + //short rate; + short promisc; + /*stats*/ + struct Stats stats; + struct iw_statistics wstats; + struct proc_dir_entry *dir_dev; + + /*RX stuff*/ +// u32 *rxring; +// u32 *rxringtail; +// dma_addr_t rxringdma; + struct urb **rx_urb; + struct urb **rx_cmd_urb; + +/* modified by davad for Rx process */ + struct sk_buff_head rx_queue; + struct sk_buff_head skb_queue; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) + struct tq_struct qos_activate; +#else + struct work_struct qos_activate; +#endif + short tx_urb_index; + atomic_t tx_pending[0x10];//UART_PRIORITY+1 + + + struct tasklet_struct irq_rx_tasklet; + struct urb *rxurb_task; + + //2 Tx Related variables + u16 ShortRetryLimit; + u16 LongRetryLimit; + u32 TransmitConfig; + u8 RegCWinMin; // For turbo mode CW adaptive. Added by Annie, 2005-10-27. + + u32 LastRxDescTSFHigh; + u32 LastRxDescTSFLow; + + + //2 Rx Related variables + u16 EarlyRxThreshold; + u32 ReceiveConfig; + u8 AcmControl; + + u8 RFProgType; + + u8 retry_data; + u8 retry_rts; + u16 rts; + + struct ChnlAccessSetting ChannelAccessSetting; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + struct work_struct reset_wq; +#else + struct tq_struct reset_wq; +#endif + +/**********************************************************/ + //for rtl819xUsb + u16 basic_rate; + u8 short_preamble; + u8 slot_time; + bool bDcut; + bool bCurrentRxAggrEnable; + u8 Rf_Mode; //add for Firmware RF -R/W switch + prt_firmware pFirmware; + rtl819xUsb_loopback_e LoopbackMode; + firmware_source_e firmware_source; + bool usb_error; + + u16 EEPROMTxPowerDiff; + u8 EEPROMThermalMeter; + u8 EEPROMPwDiff; + u8 EEPROMCrystalCap; + u8 EEPROM_Def_Ver; + u8 EEPROMTxPowerLevelCCK;// CCK channel 1~14 + u8 EEPROMTxPowerLevelCCK_V1[3]; + u8 EEPROMTxPowerLevelOFDM24G[3]; // OFDM 2.4G channel 1~14 + u8 EEPROMTxPowerLevelOFDM5G[24]; // OFDM 5G + +//RTL8192SU + bool bDmDisableProtect; + bool bIgnoreDiffRateTxPowerOffset; + +#ifdef EEPROM_OLD_FORMAT_SUPPORT + u8 EEPROMTxPowerLevelCCK24G[14]; // CCK 2.4G channel 1~14 + //u8 EEPROMTxPowerLevelOFDM24G[14]; // OFDM 2.4G channel 1~14 + //u8 EEPROMTxPowerLevelOFDM5G[24]; // OFDM 5G +#else + // For EEPROM TX Power Index like 8190 series + u8 EEPROMRfACCKChnl1TxPwLevel[3]; //RF-A CCK Tx Power Level at channel 7 + u8 EEPROMRfAOfdmChnlTxPwLevel[3];//RF-A CCK Tx Power Level at [0],[1],[2] = channel 1,7,13 + u8 EEPROMRfCCCKChnl1TxPwLevel[3]; //RF-C CCK Tx Power Level at channel 7 + u8 EEPROMRfCOfdmChnlTxPwLevel[3];//RF-C CCK Tx Power Level at [0],[1],[2] = channel 1,7,13 + + // F92S new definition + //RF-A&B CCK/OFDM Tx Power Level at three channel are [1-3] [4-9] [10-14] + u8 RfCckChnlAreaTxPwr[2][3]; + u8 RfOfdmChnlAreaTxPwr1T[2][3]; + u8 RfOfdmChnlAreaTxPwr2T[2][3]; +#endif + + // Add For EEPROM Efuse switch and Efuse Shadow map Setting + bool EepromOrEfuse; + bool bBootFromEfuse; // system boot form EFUSE + u8 EfuseMap[2][HWSET_MAX_SIZE_92S]; + + u8 EEPROMUsbOption; + u8 EEPROMUsbPhyParam[5]; + u8 EEPROMTxPwrBase; + u8 EEPROMBoardType; + bool bBootFromEEPROM; // system boot from EEPROM + u8 EEPROMTSSI_A; + u8 EEPROMTSSI_B; + u8 EEPROMHT2T_TxPwr[6]; // For channel 1, 7 and 13 on path A/B. + u8 EEPROMTxPwrTkMode; + + u8 bTXPowerDataReadFromEEPORM; + + u8 EEPROMVersion; + u8 EEPROMUsbEndPointNumber; + + bool AutoloadFailFlag; + u8 RfTxPwrLevelCck[2][14]; + u8 RfTxPwrLevelOfdm1T[2][14]; + u8 RfTxPwrLevelOfdm2T[2][14]; + // 2009/01/20 MH Add for new EEPROM format. + u8 TxPwrHt20Diff[2][14]; // HT 20<->40 Pwr diff + u8 TxPwrLegacyHtDiff[2][14]; // For HT<->legacy pwr diff + u8 TxPwrbandEdgeHt40[2][2]; // Band edge for HY 40MHZlow/up channel + u8 TxPwrbandEdgeHt20[2][2]; // Band edge for HY 40MHZ low/up channel + u8 TxPwrbandEdgeLegacyOfdm[2][2]; // Band edge for legacy ofdm low/up channel + u8 TxPwrbandEdgeFlag; // Band edge enable flag + + // L1 and L2 high power threshold. + u8 MidHighPwrTHR_L1; + u8 MidHighPwrTHR_L2; + u8 TxPwrSafetyFlag; // for Tx power safety spec +//RTL8192SU + +/*PHY related*/ + BB_REGISTER_DEFINITION_T PHYRegDef[4]; //Radio A/B/C/D + // Read/write are allow for following hardware information variables +#ifdef RTL8192SU + u32 MCSTxPowerLevelOriginalOffset[7];//FIXLZM +#else + u32 MCSTxPowerLevelOriginalOffset[6]; +#endif + u32 CCKTxPowerLevelOriginalOffset; + u8 TxPowerLevelCCK[14]; // CCK channel 1~14 + u8 TxPowerLevelOFDM24G[14]; // OFDM 2.4G channel 1~14 + u8 TxPowerLevelOFDM5G[14]; // OFDM 5G + u32 Pwr_Track; + u8 TxPowerDiff; + u8 AntennaTxPwDiff[2]; // Antenna gain offset, index 0 for B, 1 for C, and 2 for D + u8 CrystalCap; // CrystalCap. + u8 ThermalMeter[2]; // ThermalMeter, index 0 for RFIC0, and 1 for RFIC1 + + u8 CckPwEnl; + // Use to calculate PWBD. + u8 bCckHighPower; + long undecorated_smoothed_pwdb; + + //for set channel + u8 SwChnlInProgress; + u8 SwChnlStage; + u8 SwChnlStep; + u8 SetBWModeInProgress; + HT_CHANNEL_WIDTH CurrentChannelBW; + u8 ChannelPlan; + u8 pwrGroupCnt; + // 8190 40MHz mode + // + u8 nCur40MhzPrimeSC; // Control channel sub-carrier + // Joseph test for shorten RF configuration time. + // We save RF reg0 in this variable to reduce RF reading. + // + u32 RfReg0Value[4]; + u8 NumTotalRFPath; + bool brfpath_rxenable[4]; + //RF set related + bool SetRFPowerStateInProgress; +//+by amy 080507 + struct timer_list watch_dog_timer; + +//+by amy 080515 for dynamic mechenism + //Add by amy Tx Power Control for Near/Far Range 2008/05/15 + bool bdynamic_txpower; //bDynamicTxPower + bool bDynamicTxHighPower; // Tx high power state + bool bDynamicTxLowPower; // Tx low power state + bool bLastDTPFlag_High; + bool bLastDTPFlag_Low; + + bool bstore_last_dtpflag; + bool bstart_txctrl_bydtp; //Define to discriminate on High power State or on sitesuvey to change Tx gain index + //Add by amy for Rate Adaptive + rate_adaptive rate_adaptive; + //Add by amy for TX power tracking + //2008/05/15 Mars OPEN/CLOSE TX POWER TRACKING + txbbgain_struct txbbgain_table[TxBBGainTableLength]; + u8 EEPROMTxPowerTrackEnable; + u8 txpower_count;//For 6 sec do tracking again + bool btxpower_trackingInit; + u8 OFDM_index; + u8 CCK_index; + //2007/09/10 Mars Add CCK TX Power Tracking + ccktxbbgain_struct cck_txbbgain_table[CCKTxBBGainTableLength]; + ccktxbbgain_struct cck_txbbgain_ch14_table[CCKTxBBGainTableLength]; + u8 rfa_txpowertrackingindex; + u8 rfa_txpowertrackingindex_real; + u8 rfa_txpowertracking_default; + u8 rfc_txpowertrackingindex; + u8 rfc_txpowertrackingindex_real; + + s8 cck_present_attentuation; + u8 cck_present_attentuation_20Mdefault; + u8 cck_present_attentuation_40Mdefault; + char cck_present_attentuation_difference; + bool btxpower_tracking; + bool bcck_in_ch14; + bool btxpowerdata_readfromEEPORM; + u16 TSSI_13dBm; + //For Backup Initial Gain + init_gain initgain_backup; + u8 DefaultInitialGain[4]; + // For EDCA Turbo mode, Added by amy 080515. + bool bis_any_nonbepkts; + bool bcurrent_turbo_EDCA; + bool bis_cur_rdlstate; + struct timer_list fsync_timer; + bool bfsync_processing; // 500ms Fsync timer is active or not + u32 rate_record; + u32 rateCountDiffRecord; + u32 ContiuneDiffCount; + bool bswitch_fsync; + + u8 framesync; + u32 framesyncC34; + u8 framesyncMonitor; + //Added by amy 080516 for RX related + u16 nrxAMPDU_size; + u8 nrxAMPDU_aggr_num; + + //by amy for gpio + bool bHwRadioOff; + + //by amy for reset_count + u32 reset_count; + bool bpbc_pressed; + //by amy for debug + u32 txpower_checkcnt; + u32 txpower_tracking_callback_cnt; + u8 thermal_read_val[40]; + u8 thermal_readback_index; + u32 ccktxpower_adjustcnt_not_ch14; + u32 ccktxpower_adjustcnt_ch14; + u8 tx_fwinfo_force_subcarriermode; + u8 tx_fwinfo_force_subcarrierval; + //by amy for silent reset + RESET_TYPE ResetProgress; + bool bForcedSilentReset; + bool bDisableNormalResetCheck; + u16 TxCounter; + u16 RxCounter; + int IrpPendingCount; + bool bResetInProgress; + bool force_reset; + u8 InitialGainOperateType; + + u16 SifsTime; + + //define work item by amy 080526 +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + struct delayed_work update_beacon_wq; + struct delayed_work watch_dog_wq; + struct delayed_work txpower_tracking_wq; + struct delayed_work rfpath_check_wq; + struct delayed_work gpio_change_rf_wq; + struct delayed_work initialgain_operate_wq; +#else + struct work_struct update_beacon_wq; + struct work_struct watch_dog_wq; + struct work_struct txpower_tracking_wq; + struct work_struct rfpath_check_wq; + struct work_struct gpio_change_rf_wq; + struct work_struct initialgain_operate_wq; +#endif + struct workqueue_struct *priv_wq; +#else + /* used for periodly scan */ + struct tq_struct update_beacon_wq; + struct tq_struct txpower_tracking_wq; + struct tq_struct rfpath_check_wq; + struct tq_struct watch_dog_wq; + struct tq_struct gpio_change_rf_wq; + struct tq_struct initialgain_operate_wq; +#endif +//#ifdef RTL8192SU + //lzm add for 8192S + u32 IntrMask; + // RF and BB access related synchronization flags. + bool bChangeBBInProgress; // BaseBand RW is still in progress. + bool bChangeRFInProgress; // RF RW is still in progress. + + u32 CCKTxPowerAdjustCntCh14; //debug only + u32 CCKTxPowerAdjustCntNotCh14; //debug only + u32 TXPowerTrackingCallbackCnt; //debug only + u32 TxPowerCheckCnt; //debug only + u32 RFWritePageCnt[3]; //debug only + u32 RFReadPageCnt[3]; //debug only + u8 ThermalReadBackIndex; //debug only + u8 ThermalReadVal[40]; //debug only + + // For HCT test, 2005.07.15, by rcnjko. + // not realize true, just define it, set it 0 default, because some func use it + bool bInHctTest; + + // The current Tx Power Level + u8 CurrentCckTxPwrIdx; + u8 CurrentOfdm24GTxPwrIdx; + + // For pass 92S common phycfg.c compiler + u8 TxPowerLevelCCK_A[14]; // RF-A, CCK channel 1~14 + u8 TxPowerLevelOFDM24G_A[14]; // RF-A, OFDM 2.4G channel 1~14 + u8 TxPowerLevelCCK_C[14]; // RF-C, CCK channel 1~14 + u8 TxPowerLevelOFDM24G_C[14]; // RF-C, OFDM 2.4G channel 1~14 + u8 LegacyHTTxPowerDiff; // Legacy to HT rate power diff + char RF_C_TxPwDiff; // Antenna gain offset, rf-c to rf-a + + bool bRFSiOrPi;//0=si, 1=pi. + //lzm add for 8192S + + bool SetFwCmdInProgress; //is set FW CMD in Progress? 92S only + u8 CurrentFwCmdIO; + + u8 MinSpaceCfg; + + u16 rf_pathmap; +//#endif + + +#ifdef USB_RX_AGGREGATION_SUPPORT + bool bCurrentRxAggrEnable; + bool bForcedUsbRxAggr; + u32 ForcedUsbRxAggrInfo; + u32 LastUsbRxAggrInfoSetting; + u32 RegUsbRxAggrInfo; +#endif + + + +}r8192_priv; + +// for rtl8187 +// now mirging to rtl8187B +/* +typedef enum{ + LOW_PRIORITY = 0x02, + NORM_PRIORITY + } priority_t; +*/ +//for rtl8187B +typedef enum{ + BULK_PRIORITY = 0x01, + //RSVD0, + //RSVD1, + LOW_PRIORITY, + NORM_PRIORITY, + VO_PRIORITY, + VI_PRIORITY, //0x05 + BE_PRIORITY, + BK_PRIORITY, + RSVD2, + RSVD3, + BEACON_PRIORITY, //0x0A + HIGH_PRIORITY, + MANAGE_PRIORITY, + RSVD4, + RSVD5, + UART_PRIORITY //0x0F +} priority_t; + +#if 0 +typedef enum{ + NIC_8192U = 1, + NIC_8190P = 2, + NIC_8192E = 3, + NIC_8192SE = 4, + NIC_8192SU = 5, + } nic_t; +#endif + +#if 0 //defined in Qos.h +//typedef u32 AC_CODING; +#define AC0_BE 0 // ACI: 0x00 // Best Effort +#define AC1_BK 1 // ACI: 0x01 // Background +#define AC2_VI 2 // ACI: 0x10 // Video +#define AC3_VO 3 // ACI: 0x11 // Voice +#define AC_MAX 4 // Max: define total number; Should not to be used as a real enum. + +// +// ECWmin/ECWmax field. +// Ref: WMM spec 2.2.2: WME Parameter Element, p.13. +// +typedef union _ECW{ + u8 charData; + struct + { + u8 ECWmin:4; + u8 ECWmax:4; + }f; // Field +}ECW, *PECW; + +// +// ACI/AIFSN Field. +// Ref: WMM spec 2.2.2: WME Parameter Element, p.12. +// +typedef union _ACI_AIFSN{ + u8 charData; + + struct + { + u8 AIFSN:4; + u8 ACM:1; + u8 ACI:2; + u8 Reserved:1; + }f; // Field +}ACI_AIFSN, *PACI_AIFSN; + +// +// AC Parameters Record Format. +// Ref: WMM spec 2.2.2: WME Parameter Element, p.12. +// +typedef union _AC_PARAM{ + u32 longData; + u8 charData[4]; + + struct + { + ACI_AIFSN AciAifsn; + ECW Ecw; + u16 TXOPLimit; + }f; // Field +}AC_PARAM, *PAC_PARAM; + +#endif +#ifdef JOHN_HWSEC +struct ssid_thread { + struct net_device *dev; + u8 name[IW_ESSID_MAX_SIZE + 1]; +}; +#endif + +#ifdef RTL8192SU +short rtl8192SU_tx_cmd(struct net_device *dev, struct sk_buff *skb); +short rtl8192SU_tx(struct net_device *dev, struct sk_buff* skb); +bool FirmwareDownload92S(struct net_device *dev); +#else +short rtl8192_tx(struct net_device *dev, struct sk_buff* skb); +bool init_firmware(struct net_device *dev); +#endif + +short rtl819xU_tx_cmd(struct net_device *dev, struct sk_buff *skb); +short rtl8192_tx(struct net_device *dev, struct sk_buff* skb); + +u32 read_cam(struct net_device *dev, u8 addr); +void write_cam(struct net_device *dev, u8 addr, u32 data); + +u8 read_nic_byte(struct net_device *dev, int x); +u8 read_nic_byte_E(struct net_device *dev, int x); +u32 read_nic_dword(struct net_device *dev, int x); +u16 read_nic_word(struct net_device *dev, int x) ; +void write_nic_byte(struct net_device *dev, int x,u8 y); +void write_nic_byte_E(struct net_device *dev, int x,u8 y); +void write_nic_word(struct net_device *dev, int x,u16 y); +void write_nic_dword(struct net_device *dev, int x,u32 y); +void force_pci_posting(struct net_device *dev); + +void rtl8192_rtx_disable(struct net_device *); +void rtl8192_rx_enable(struct net_device *); +void rtl8192_tx_enable(struct net_device *); + +void rtl8192_disassociate(struct net_device *dev); +//void fix_rx_fifo(struct net_device *dev); +void rtl8185_set_rf_pins_enable(struct net_device *dev,u32 a); + +void rtl8192_set_anaparam(struct net_device *dev,u32 a); +void rtl8185_set_anaparam2(struct net_device *dev,u32 a); +void rtl8192_update_msr(struct net_device *dev); +int rtl8192_down(struct net_device *dev); +int rtl8192_up(struct net_device *dev); +void rtl8192_commit(struct net_device *dev); +void rtl8192_set_chan(struct net_device *dev,short ch); +void write_phy(struct net_device *dev, u8 adr, u8 data); +void write_phy_cck(struct net_device *dev, u8 adr, u32 data); +void write_phy_ofdm(struct net_device *dev, u8 adr, u32 data); +void rtl8185_tx_antenna(struct net_device *dev, u8 ant); +void rtl8192_set_rxconf(struct net_device *dev); +//short check_nic_enough_desc(struct net_device *dev, priority_t priority); +extern void rtl819xusb_beacon_tx(struct net_device *dev,u16 tx_rate); +void CamResetAllEntry(struct net_device* dev); +void EnableHWSecurityConfig8192(struct net_device *dev); +void setKey(struct net_device *dev, u8 EntryNo, u8 KeyIndex, u16 KeyType, u8 *MacAddr, u8 DefaultKey, u32 *KeyContent ); +short rtl8192_is_tx_queue_empty(struct net_device *dev); + +#endif diff --git a/drivers/staging/rtl8192su/r8192U_core.c b/drivers/staging/rtl8192su/r8192U_core.c new file mode 100644 index 000000000000..f1423d714496 --- /dev/null +++ b/drivers/staging/rtl8192su/r8192U_core.c @@ -0,0 +1,12460 @@ +/****************************************************************************** + * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. + * Linux device driver for RTL8192U + * + * Based on the r8187 driver, which is: + * Copyright 2004-2005 Andrea Merello , et al. + * 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: + * Jerry chuang + */ + +#ifndef CONFIG_FORCE_HARD_FLOAT +double __floatsidf (int i) { return i; } +unsigned int __fixunsdfsi (double d) { return d; } +double __adddf3(double a, double b) { return a+b; } +double __addsf3(float a, float b) { return a+b; } +double __subdf3(double a, double b) { return a-b; } +double __extendsfdf2(float a) {return a;} +#endif + +#undef LOOP_TEST +#undef DUMP_RX +#undef DUMP_TX +#undef DEBUG_TX_DESC2 +#undef RX_DONT_PASS_UL +#undef DEBUG_EPROM +#undef DEBUG_RX_VERBOSE +#undef DUMMY_RX +#undef DEBUG_ZERO_RX +#undef DEBUG_RX_SKB +#undef DEBUG_TX_FRAG +#undef DEBUG_RX_FRAG +#undef DEBUG_TX_FILLDESC +#undef DEBUG_TX +#undef DEBUG_IRQ +#undef DEBUG_RX +#undef DEBUG_RXALLOC +#undef DEBUG_REGISTERS +#undef DEBUG_RING +#undef DEBUG_IRQ_TASKLET +#undef DEBUG_TX_ALLOC +#undef DEBUG_TX_DESC + +#define CONFIG_RTL8192_IO_MAP + +#ifdef RTL8192SU +#include +#include "r8192U.h" +//#include "r8190_rtl8256.h" /* RTL8225 Radio frontend */ +#include "r8180_93cx6.h" /* Card EEPROM */ +#include "r8192U_wx.h" + +#include "r8192S_rtl8225.h" +#include "r8192S_hw.h" +#include "r8192S_phy.h" +#include "r8192S_phyreg.h" +#include "r8192S_Efuse.h" + +#include "r819xU_cmdpkt.h" +#include "r8192U_dm.h" +//#include "r8192xU_phyreg.h" +#include +// FIXME: check if 2.6.7 is ok +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,7)) +#define usb_kill_urb usb_unlink_urb +#endif + +#ifdef CONFIG_RTL8192_PM +#include "r8192U_pm.h" +#endif + +#ifdef ENABLE_DOT11D +#include "dot11d.h" +#endif + +#else + +#include +#include "r8192U_hw.h" +#include "r8192U.h" +#include "r8190_rtl8256.h" /* RTL8225 Radio frontend */ +#include "r8180_93cx6.h" /* Card EEPROM */ +#include "r8192U_wx.h" +#include "r819xU_phy.h" //added by WB 4.30.2008 +#include "r819xU_phyreg.h" +#include "r819xU_cmdpkt.h" +#include "r8192U_dm.h" +//#include "r8192xU_phyreg.h" +#include +// FIXME: check if 2.6.7 is ok +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,7)) +#define usb_kill_urb usb_unlink_urb +#endif + +#ifdef CONFIG_RTL8192_PM +#include "r8192U_pm.h" +#endif + +#ifdef ENABLE_DOT11D +#include "dot11d.h" +#endif + +#endif + + +#ifdef RTL8192SU +u32 rt_global_debug_component = \ +// COMP_TRACE | +// COMP_DBG | +// COMP_INIT | +// COMP_RECV | +// COMP_SEND | +// COMP_IO | + COMP_POWER | +// COMP_EPROM | + COMP_SWBW | + COMP_POWER_TRACKING | + COMP_TURBO | + COMP_QOS | +// COMP_RATE | +// COMP_RM | + COMP_DIG | +// COMP_EFUSE | +// COMP_CH | +// COMP_TXAGC | + COMP_HIPWR | +// COMP_HALDM | + COMP_SEC | + COMP_LED | +// COMP_RF | +// COMP_RXDESC | + COMP_FIRMWARE | + COMP_HT | + COMP_AMSDU | + COMP_SCAN | +// COMP_CMD | + COMP_DOWN | + COMP_RESET | + COMP_ERR; //always open err flags on +#else +//set here to open your trace code. //WB +u32 rt_global_debug_component = \ + // COMP_INIT | +// COMP_DBG | + // COMP_EPROM | +// COMP_PHY | + // COMP_RF | +// COMP_FIRMWARE | +// COMP_CH | + // COMP_POWER_TRACKING | +// COMP_RATE | + // COMP_TXAGC | + // COMP_TRACE | + COMP_DOWN | + // COMP_RECV | + // COMP_SWBW | + COMP_SEC | + // COMP_RESET | + // COMP_SEND | + // COMP_EVENTS | + COMP_ERR ; //always open err flags on +#endif + +#define TOTAL_CAM_ENTRY 32 +#define CAM_CONTENT_COUNT 8 + +static struct usb_device_id rtl8192_usb_id_tbl[] = { + /* Realtek */ + {USB_DEVICE(0x0bda, 0x8192)}, + {USB_DEVICE(0x0bda, 0x8709)}, + /* Corega */ + {USB_DEVICE(0x07aa, 0x0043)}, + /* Belkin */ + {USB_DEVICE(0x050d, 0x805E)}, + /* Sitecom */ + {USB_DEVICE(0x0df6, 0x0031)}, + /* EnGenius */ + {USB_DEVICE(0x1740, 0x9201)}, + /* Dlink */ + {USB_DEVICE(0x2001, 0x3301)}, + /* Zinwell */ + {USB_DEVICE(0x5a57, 0x0290)}, + //92SU + {USB_DEVICE(0x0bda, 0x8172)}, + {} +}; + +MODULE_LICENSE("GPL"); +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) +MODULE_VERSION("V 1.1"); +#endif +MODULE_DEVICE_TABLE(usb, rtl8192_usb_id_tbl); +MODULE_DESCRIPTION("Linux driver for Realtek RTL8192 USB WiFi cards"); + +static char* ifname = "wlan%d"; +#if 0 +static int hwseqnum = 0; +static int hwwep = 0; +#endif +static int hwwep = 1; //default use hw. set 0 to use software security +static int channels = 0x3fff; + + + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 9) +module_param(ifname, charp, S_IRUGO|S_IWUSR ); +//module_param(hwseqnum,int, S_IRUGO|S_IWUSR); +module_param(hwwep,int, S_IRUGO|S_IWUSR); +module_param(channels,int, S_IRUGO|S_IWUSR); +#else +MODULE_PARM(ifname, "s"); +//MODULE_PARM(hwseqnum,"i"); +MODULE_PARM(hwwep,"i"); +MODULE_PARM(channels,"i"); +#endif + +MODULE_PARM_DESC(ifname," Net interface name, wlan%d=default"); +//MODULE_PARM_DESC(hwseqnum," Try to use hardware 802.11 header sequence numbers. Zero=default"); +MODULE_PARM_DESC(hwwep," Try to use hardware security support. "); +MODULE_PARM_DESC(channels," Channel bitmask for specific locales. NYI"); + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) +static int __devinit rtl8192_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id); +static void __devexit rtl8192_usb_disconnect(struct usb_interface *intf); +#else +static void *__devinit rtl8192_usb_probe(struct usb_device *udev,unsigned int ifnum, + const struct usb_device_id *id); +static void __devexit rtl8192_usb_disconnect(struct usb_device *udev, void *ptr); +#endif + + +static struct usb_driver rtl8192_usb_driver = { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 15) + .owner = THIS_MODULE, +#endif + .name = RTL819xU_MODULE_NAME, /* Driver name */ + .id_table = rtl8192_usb_id_tbl, /* PCI_ID table */ + .probe = rtl8192_usb_probe, /* probe fn */ + .disconnect = rtl8192_usb_disconnect, /* remove fn */ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) +#ifdef CONFIG_RTL8192_PM + .suspend = rtl8192U_suspend, /* PM suspend fn */ + .resume = rtl8192U_resume, /* PM resume fn */ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22) + .reset_resume = rtl8192U_resume, /* PM reset resume fn */ +#endif +#else + .suspend = NULL, /* PM suspend fn */ + .resume = NULL, /* PM resume fn */ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22) + .reset_resume = NULL, /* PM reset resume fn */ +#endif +#endif +#endif +}; + + +#ifdef RTL8192SU +static void rtl8192SU_read_eeprom_info(struct net_device *dev); +short rtl8192SU_tx(struct net_device *dev, struct sk_buff* skb); +void rtl8192SU_rx_nomal(struct sk_buff* skb); +void rtl8192SU_rx_cmd(struct sk_buff *skb); +bool rtl8192SU_adapter_start(struct net_device *dev); +short rtl8192SU_tx_cmd(struct net_device *dev, struct sk_buff *skb); +void rtl8192SU_link_change(struct net_device *dev); +void InitialGain8192S(struct net_device *dev,u8 Operation); +void rtl8192SU_query_rxdesc_status(struct sk_buff *skb, struct ieee80211_rx_stats *stats, bool bIsRxAggrSubframe); + +struct rtl819x_ops rtl8192su_ops = { + .nic_type = NIC_8192SU, + .rtl819x_read_eeprom_info = rtl8192SU_read_eeprom_info, + .rtl819x_tx = rtl8192SU_tx, + .rtl819x_tx_cmd = rtl8192SU_tx_cmd, + .rtl819x_rx_nomal = rtl8192SU_rx_nomal, + .rtl819x_rx_cmd = rtl8192SU_rx_cmd, + .rtl819x_adapter_start = rtl8192SU_adapter_start, + .rtl819x_link_change = rtl8192SU_link_change, + .rtl819x_initial_gain = InitialGain8192S, + .rtl819x_query_rxdesc_status = rtl8192SU_query_rxdesc_status, +}; +#else +static void rtl8192_read_eeprom_info(struct net_device *dev); +short rtl8192_tx(struct net_device *dev, struct sk_buff* skb); +void rtl8192_rx_nomal(struct sk_buff* skb); +void rtl8192_rx_cmd(struct sk_buff *skb); +bool rtl8192_adapter_start(struct net_device *dev); +short rtl819xU_tx_cmd(struct net_device *dev, struct sk_buff *skb); +void rtl8192_link_change(struct net_device *dev); +void InitialGain819xUsb(struct net_device *dev,u8 Operation); +void query_rxdesc_status(struct sk_buff *skb, struct ieee80211_rx_stats *stats, bool bIsRxAggrSubframe); + +struct rtl819x_ops rtl8192u_ops = { + .nic_type = NIC_8192U, + .rtl819x_read_eeprom_info = rtl8192_read_eeprom_info, + .rtl819x_tx = rtl8192_tx, + .rtl819x_tx_cmd = rtl819xU_tx_cmd, + .rtl819x_rx_nomal = rtl8192_rx_nomal, + .rtl819x_rx_cmd = rtl8192_rx_cmd, + .rtl819x_adapter_start = rtl8192_adapter_start, + .rtl819x_link_change = rtl8192_link_change, + .rtl819x_initial_gain = InitialGain819xUsb, + .rtl819x_query_rxdesc_status = query_rxdesc_status, +}; +#endif + +#ifdef ENABLE_DOT11D + +typedef struct _CHANNEL_LIST +{ + u8 Channel[32]; + u8 Len; +}CHANNEL_LIST, *PCHANNEL_LIST; + +static CHANNEL_LIST ChannelPlan[] = { + {{1,2,3,4,5,6,7,8,9,10,11,36,40,44,48,52,56,60,64,149,153,157,161,165},24}, //FCC + {{1,2,3,4,5,6,7,8,9,10,11},11}, //IC + {{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64},21}, //ETSI + {{1,2,3,4,5,6,7,8,9,10,11,12,13},13}, //Spain. Change to ETSI. + {{1,2,3,4,5,6,7,8,9,10,11,12,13},13}, //France. Change to ETSI. + {{1,2,3,4,5,6,7,8,9,10,11,12,13,14,36,40,44,48,52,56,60,64},22}, //MKK //MKK + {{1,2,3,4,5,6,7,8,9,10,11,12,13,14,36,40,44,48,52,56,60,64},22},//MKK1 + {{1,2,3,4,5,6,7,8,9,10,11,12,13},13}, //Israel. + {{1,2,3,4,5,6,7,8,9,10,11,12,13,14,36,40,44,48,52,56,60,64},22}, // For 11a , TELEC + {{1,2,3,4,5,6,7,8,9,10,11,12,13,14,36,40,44,48,52,56,60,64}, 22}, //MIC + {{1,2,3,4,5,6,7,8,9,10,11,12,13,14},14} //For Global Domain. 1-11:active scan, 12-14 passive scan. //+YJ, 080626 +}; + +static void rtl819x_set_channel_map(u8 channel_plan, struct r8192_priv* priv) +{ + int i, max_chan=-1, min_chan=-1; + struct ieee80211_device* ieee = priv->ieee80211; + switch (channel_plan) + { + case COUNTRY_CODE_FCC: + case COUNTRY_CODE_IC: + case COUNTRY_CODE_ETSI: + case COUNTRY_CODE_SPAIN: + case COUNTRY_CODE_FRANCE: + case COUNTRY_CODE_MKK: + case COUNTRY_CODE_MKK1: + case COUNTRY_CODE_ISRAEL: + case COUNTRY_CODE_TELEC: + case COUNTRY_CODE_MIC: + { + Dot11d_Init(ieee); + ieee->bGlobalDomain = false; + //acturally 8225 & 8256 rf chip only support B,G,24N mode + if ((priv->rf_chip == RF_8225) || (priv->rf_chip == RF_8256) || (priv->rf_chip == RF_6052)) + { + min_chan = 1; + max_chan = 14; + } + else + { + RT_TRACE(COMP_ERR, "unknown rf chip, can't set channel map in function:%s()\n", __FUNCTION__); + } + if (ChannelPlan[channel_plan].Len != 0){ + // Clear old channel map + memset(GET_DOT11D_INFO(ieee)->channel_map, 0, sizeof(GET_DOT11D_INFO(ieee)->channel_map)); + // Set new channel map + for (i=0;i max_chan) + break; + GET_DOT11D_INFO(ieee)->channel_map[ChannelPlan[channel_plan].Channel[i]] = 1; + } + } + break; + } + case COUNTRY_CODE_GLOBAL_DOMAIN: + { + GET_DOT11D_INFO(ieee)->bEnabled = 0;//this flag enabled to follow 11d country IE setting, otherwise, it shall follow global domain settings. + Dot11d_Reset(ieee); + ieee->bGlobalDomain = true; + break; + } + default: + break; + } + return; +} +#endif + +#define eqMacAddr(a,b) ( ((a)[0]==(b)[0] && (a)[1]==(b)[1] && (a)[2]==(b)[2] && (a)[3]==(b)[3] && (a)[4]==(b)[4] && (a)[5]==(b)[5]) ? 1:0 ) + +#ifdef RTL8192SU +#define rx_hal_is_cck_rate(_pDesc)\ + ((_pDesc->RxMCS == DESC92S_RATE1M ||\ + _pDesc->RxMCS == DESC92S_RATE2M ||\ + _pDesc->RxMCS == DESC92S_RATE5_5M ||\ + _pDesc->RxMCS == DESC92S_RATE11M) &&\ + !_pDesc->RxHT) + +#define tx_hal_is_cck_rate(_DataRate)\ + ( _DataRate == MGN_1M ||\ + _DataRate == MGN_2M ||\ + _DataRate == MGN_5_5M ||\ + _DataRate == MGN_11M ) + +#else +#define rx_hal_is_cck_rate(_pdrvinfo)\ + ((_pdrvinfo->RxRate == DESC90_RATE1M ||\ + _pdrvinfo->RxRate == DESC90_RATE2M ||\ + _pdrvinfo->RxRate == DESC90_RATE5_5M ||\ + _pdrvinfo->RxRate == DESC90_RATE11M) &&\ + !_pdrvinfo->RxHT) +#endif + + + +void CamResetAllEntry(struct net_device *dev) +{ +#if 1 + u32 ulcommand = 0; + //2004/02/11 In static WEP, OID_ADD_KEY or OID_ADD_WEP are set before STA associate to AP. + // However, ResetKey is called on OID_802_11_INFRASTRUCTURE_MODE and MlmeAssociateRequest + // In this condition, Cam can not be reset because upper layer will not set this static key again. + //if(Adapter->EncAlgorithm == WEP_Encryption) + // return; +//debug + //DbgPrint("========================================\n"); + //DbgPrint(" Call ResetAllEntry \n"); + //DbgPrint("========================================\n\n"); + ulcommand |= BIT31|BIT30; + write_nic_dword(dev, RWCAM, ulcommand); +#else + for(ucIndex=0;ucIndexudev; + + status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + RTL8187_REQ_SET_REGS, RTL8187_REQT_WRITE, + indx|0xfe00, 0, &data, 1, HZ / 2); + + if (status < 0) + { + printk("write_nic_byte_E TimeOut! status:%d\n", status); + } +} + +u8 read_nic_byte_E(struct net_device *dev, int indx) +{ + int status; + u8 data; + struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); + struct usb_device *udev = priv->udev; + + status = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + RTL8187_REQ_GET_REGS, RTL8187_REQT_READ, + indx|0xfe00, 0, &data, 1, HZ / 2); + + if (status < 0) + { + printk("read_nic_byte_E TimeOut! status:%d\n", status); + } + + return data; +} +//as 92U has extend page from 4 to 16, so modify functions below. +void write_nic_byte(struct net_device *dev, int indx, u8 data) +{ + int status; + + struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); + struct usb_device *udev = priv->udev; + + status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + RTL8187_REQ_SET_REGS, RTL8187_REQT_WRITE, +#ifdef RTL8192SU + indx, 0, &data, 1, HZ / 2); +#else + (indx&0xff)|0xff00, (indx>>8)&0x0f, &data, 1, HZ / 2); +#endif + + if (status < 0) + { + printk("write_nic_byte TimeOut! status:%d\n", status); + } + + +} + + +void write_nic_word(struct net_device *dev, int indx, u16 data) +{ + + int status; + + struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); + struct usb_device *udev = priv->udev; + + status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + RTL8187_REQ_SET_REGS, RTL8187_REQT_WRITE, +#ifdef RTL8192SU + indx, 0, &data, 2, HZ / 2); +#else + (indx&0xff)|0xff00, (indx>>8)&0x0f, &data, 2, HZ / 2); +#endif + + if (status < 0) + { + printk("write_nic_word TimeOut! status:%d\n", status); + } + +} + + +void write_nic_dword(struct net_device *dev, int indx, u32 data) +{ + + int status; + + struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); + struct usb_device *udev = priv->udev; + + status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + RTL8187_REQ_SET_REGS, RTL8187_REQT_WRITE, +#ifdef RTL8192SU + indx, 0, &data, 4, HZ / 2); +#else + (indx&0xff)|0xff00, (indx>>8)&0x0f, &data, 4, HZ / 2); +#endif + + + if (status < 0) + { + printk("write_nic_dword TimeOut! status:%d\n", status); + } + +} + + + +u8 read_nic_byte(struct net_device *dev, int indx) +{ + u8 data; + int status; + struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); + struct usb_device *udev = priv->udev; + + status = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + RTL8187_REQ_GET_REGS, RTL8187_REQT_READ, +#ifdef RTL8192SU + indx, 0, &data, 1, HZ / 2); +#else + (indx&0xff)|0xff00, (indx>>8)&0x0f, &data, 1, HZ / 2); +#endif + + if (status < 0) + { + printk("read_nic_byte TimeOut! status:%d\n", status); + } + + return data; +} + + + +u16 read_nic_word(struct net_device *dev, int indx) +{ + u16 data; + int status; + struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); + struct usb_device *udev = priv->udev; + + status = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + RTL8187_REQ_GET_REGS, RTL8187_REQT_READ, +#ifdef RTL8192SU + indx, 0, &data, 2, HZ / 2); +#else + (indx&0xff)|0xff00, (indx>>8)&0x0f, &data, 2, HZ / 2); +#endif + + if (status < 0) + { + printk("read_nic_word TimeOut! status:%d\n", status); + } + + + return data; +} + +u16 read_nic_word_E(struct net_device *dev, int indx) +{ + u16 data; + int status; + struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); + struct usb_device *udev = priv->udev; + + status = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + RTL8187_REQ_GET_REGS, RTL8187_REQT_READ, + indx|0xfe00, 0, &data, 2, HZ / 2); + + if (status < 0) + { + printk("read_nic_word TimeOut! status:%d\n", status); + } + + + return data; +} + +u32 read_nic_dword(struct net_device *dev, int indx) +{ + u32 data; + int status; +// int result; + + struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); + struct usb_device *udev = priv->udev; + + status = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + RTL8187_REQ_GET_REGS, RTL8187_REQT_READ, +#ifdef RTL8192SU + indx, 0, &data, 4, HZ / 2); +#else + (indx&0xff)|0xff00, (indx>>8)&0x0f, &data, 4, HZ / 2); +#endif +// if(0 != result) { +// printk(KERN_WARNING "read size of data = %d\, date = %d\n", result, data); +// } + + if (status < 0) + { + printk("read_nic_dword TimeOut! status:%d\n", status); + if(status == -ENODEV) { + priv->usb_error = true; + } + } + + + + return data; +} + + +//u8 read_phy_cck(struct net_device *dev, u8 adr); +//u8 read_phy_ofdm(struct net_device *dev, u8 adr); +/* this might still called in what was the PHY rtl8185/rtl8192 common code + * plans are to possibilty turn it again in one common code... + */ +inline void force_pci_posting(struct net_device *dev) +{ +} + + +static struct net_device_stats *rtl8192_stats(struct net_device *dev); +void rtl8192_commit(struct net_device *dev); +//void rtl8192_restart(struct net_device *dev); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) +void rtl8192_restart(struct work_struct *work); +//void rtl8192_rq_tx_ack(struct work_struct *work); +#else + void rtl8192_restart(struct net_device *dev); +// //void rtl8192_rq_tx_ack(struct net_device *dev); + #endif + +void watch_dog_timer_callback(unsigned long data); + +/**************************************************************************** + -----------------------------PROCFS STUFF------------------------- +*****************************************************************************/ + +static struct proc_dir_entry *rtl8192_proc = NULL; + + + +static int proc_get_stats_ap(char *page, char **start, + off_t offset, int count, + int *eof, void *data) +{ + struct net_device *dev = data; + struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); + struct ieee80211_device *ieee = priv->ieee80211; + struct ieee80211_network *target; + + int len = 0; + + list_for_each_entry(target, &ieee->network_list, list) { + + len += snprintf(page + len, count - len, + "%s ", target->ssid); + + if(target->wpa_ie_len>0 || target->rsn_ie_len>0){ + len += snprintf(page + len, count - len, + "WPA\n"); + } + else{ + len += snprintf(page + len, count - len, + "non_WPA\n"); + } + + } + + *eof = 1; + return len; +} + +#ifdef RTL8192SU +static int proc_get_registers(char *page, char **start, + off_t offset, int count, + int *eof, void *data) +{ + struct net_device *dev = data; +// struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); + + int len = 0; + int i,n,page0,page1,page2; + + int max=0xff; + page0 = 0x000; + page1 = 0x100; + page2 = 0x800; + + /* This dump the current register page */ + if(!IS_BB_REG_OFFSET_92S(page0)){ + len += snprintf(page + len, count - len, + "\n####################page %x##################\n ", (page0>>8)); + for(n=0;n<=max;) + { + len += snprintf(page + len, count - len, + "\nD: %2x > ",n); + for(i=0;i<16 && n<=max;i++,n++) + len += snprintf(page + len, count - len, + "%2.2x ",read_nic_byte(dev,(page0|n))); + } + }else{ + len += snprintf(page + len, count - len, + "\n####################page %x##################\n ", (page0>>8)); + for(n=0;n<=max;) + { + len += snprintf(page + len, count - len, "\nD: %2x > ",n); + for(i=0;i<4 && n<=max;n+=4,i++) + len += snprintf(page + len, count - len, + "%8.8x ",rtl8192_QueryBBReg(dev,(page0|n), bMaskDWord)); + } + } + len += snprintf(page + len, count - len,"\n"); + *eof = 1; + return len; + +} +static int proc_get_registers_1(char *page, char **start, + off_t offset, int count, + int *eof, void *data) +{ + struct net_device *dev = data; +// struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); + + int len = 0; + int i,n,page0; + + int max=0xff; + page0 = 0x100; + + /* This dump the current register page */ + len += snprintf(page + len, count - len, + "\n####################page %x##################\n ", (page0>>8)); + for(n=0;n<=max;) + { + len += snprintf(page + len, count - len, + "\nD: %2x > ",n); + for(i=0;i<16 && n<=max;i++,n++) + len += snprintf(page + len, count - len, + "%2.2x ",read_nic_byte(dev,(page0|n))); + } + len += snprintf(page + len, count - len,"\n"); + *eof = 1; + return len; + +} +static int proc_get_registers_2(char *page, char **start, + off_t offset, int count, + int *eof, void *data) +{ + struct net_device *dev = data; +// struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); + + int len = 0; + int i,n,page0; + + int max=0xff; + page0 = 0x200; + + /* This dump the current register page */ + len += snprintf(page + len, count - len, + "\n####################page %x##################\n ", (page0>>8)); + for(n=0;n<=max;) + { + len += snprintf(page + len, count - len, + "\nD: %2x > ",n); + for(i=0;i<16 && n<=max;i++,n++) + len += snprintf(page + len, count - len, + "%2.2x ",read_nic_byte(dev,(page0|n))); + } + len += snprintf(page + len, count - len,"\n"); + *eof = 1; + return len; + +} +static int proc_get_registers_8(char *page, char **start, + off_t offset, int count, + int *eof, void *data) +{ + struct net_device *dev = data; + + int len = 0; + int i,n,page0; + + int max=0xff; + page0 = 0x800; + + /* This dump the current register page */ + len += snprintf(page + len, count - len, + "\n####################page %x##################\n ", (page0>>8)); + for(n=0;n<=max;) + { + len += snprintf(page + len, count - len, "\nD: %2x > ",n); + for(i=0;i<4 && n<=max;n+=4,i++) + len += snprintf(page + len, count - len, + "%8.8x ",rtl8192_QueryBBReg(dev,(page0|n), bMaskDWord)); + } + len += snprintf(page + len, count - len,"\n"); + *eof = 1; + return len; + + } +static int proc_get_registers_9(char *page, char **start, + off_t offset, int count, + int *eof, void *data) +{ + struct net_device *dev = data; +// struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); + + int len = 0; + int i,n,page0; + + int max=0xff; + page0 = 0x900; + + /* This dump the current register page */ + len += snprintf(page + len, count - len, + "\n####################page %x##################\n ", (page0>>8)); + for(n=0;n<=max;) + { + len += snprintf(page + len, count - len, "\nD: %2x > ",n); + for(i=0;i<4 && n<=max;n+=4,i++) + len += snprintf(page + len, count - len, + "%8.8x ",rtl8192_QueryBBReg(dev,(page0|n), bMaskDWord)); + } + len += snprintf(page + len, count - len,"\n"); + *eof = 1; + return len; +} +static int proc_get_registers_a(char *page, char **start, + off_t offset, int count, + int *eof, void *data) +{ + struct net_device *dev = data; +// struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); + + int len = 0; + int i,n,page0; + + int max=0xff; + page0 = 0xa00; + + /* This dump the current register page */ + len += snprintf(page + len, count - len, + "\n####################page %x##################\n ", (page0>>8)); + for(n=0;n<=max;) + { + len += snprintf(page + len, count - len, "\nD: %2x > ",n); + for(i=0;i<4 && n<=max;n+=4,i++) + len += snprintf(page + len, count - len, + "%8.8x ",rtl8192_QueryBBReg(dev,(page0|n), bMaskDWord)); + } + len += snprintf(page + len, count - len,"\n"); + *eof = 1; + return len; +} +static int proc_get_registers_b(char *page, char **start, + off_t offset, int count, + int *eof, void *data) +{ + struct net_device *dev = data; +// struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); + + int len = 0; + int i,n,page0; + + int max=0xff; + page0 = 0xb00; + + /* This dump the current register page */ + len += snprintf(page + len, count - len, + "\n####################page %x##################\n ", (page0>>8)); + for(n=0;n<=max;) + { + len += snprintf(page + len, count - len, "\nD: %2x > ",n); + for(i=0;i<4 && n<=max;n+=4,i++) + len += snprintf(page + len, count - len, + "%8.8x ",rtl8192_QueryBBReg(dev,(page0|n), bMaskDWord)); + } + len += snprintf(page + len, count - len,"\n"); + *eof = 1; + return len; + } +static int proc_get_registers_c(char *page, char **start, + off_t offset, int count, + int *eof, void *data) +{ + struct net_device *dev = data; +// struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); + + int len = 0; + int i,n,page0; + + int max=0xff; + page0 = 0xc00; + + /* This dump the current register page */ + len += snprintf(page + len, count - len, + "\n####################page %x##################\n ", (page0>>8)); + for(n=0;n<=max;) + { + len += snprintf(page + len, count - len, "\nD: %2x > ",n); + for(i=0;i<4 && n<=max;n+=4,i++) + len += snprintf(page + len, count - len, + "%8.8x ",rtl8192_QueryBBReg(dev,(page0|n), bMaskDWord)); + } + len += snprintf(page + len, count - len,"\n"); + *eof = 1; + return len; +} +static int proc_get_registers_d(char *page, char **start, + off_t offset, int count, + int *eof, void *data) +{ + struct net_device *dev = data; +// struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); + + int len = 0; + int i,n,page0; + + int max=0xff; + page0 = 0xd00; + + /* This dump the current register page */ + len += snprintf(page + len, count - len, + "\n####################page %x##################\n ", (page0>>8)); + for(n=0;n<=max;) + { + len += snprintf(page + len, count - len, "\nD: %2x > ",n); + for(i=0;i<4 && n<=max;n+=4,i++) + len += snprintf(page + len, count - len, + "%8.8x ",rtl8192_QueryBBReg(dev,(page0|n), bMaskDWord)); + } + len += snprintf(page + len, count - len,"\n"); + *eof = 1; + return len; +} +static int proc_get_registers_e(char *page, char **start, + off_t offset, int count, + int *eof, void *data) +{ + struct net_device *dev = data; +// struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); + + int len = 0; + int i,n,page0; + + int max=0xff; + page0 = 0xe00; + + /* This dump the current register page */ + len += snprintf(page + len, count - len, + "\n####################page %x##################\n ", (page0>>8)); + for(n=0;n<=max;) + { + len += snprintf(page + len, count - len, "\nD: %2x > ",n); + for(i=0;i<4 && n<=max;n+=4,i++) + len += snprintf(page + len, count - len, + "%8.8x ",rtl8192_QueryBBReg(dev,(page0|n), bMaskDWord)); + } + len += snprintf(page + len, count - len,"\n"); + *eof = 1; + return len; +} +#else +static int proc_get_registers(char *page, char **start, + off_t offset, int count, + int *eof, void *data) +{ + struct net_device *dev = data; +// struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); + + int len = 0; + int i,n; + + int max=0xff; + + /* This dump the current register page */ +len += snprintf(page + len, count - len, + "\n####################page 0##################\n "); + + for(n=0;n<=max;) + { + //printk( "\nD: %2x> ", n); + len += snprintf(page + len, count - len, + "\nD: %2x > ",n); + + for(i=0;i<16 && n<=max;i++,n++) + len += snprintf(page + len, count - len, + "%2x ",read_nic_byte(dev,0x000|n)); + + // printk("%2x ",read_nic_byte(dev,n)); + } +#if 1 +len += snprintf(page + len, count - len, + "\n####################page 1##################\n "); + for(n=0;n<=max;) + { + //printk( "\nD: %2x> ", n); + len += snprintf(page + len, count - len, + "\nD: %2x > ",n); + + for(i=0;i<16 && n<=max;i++,n++) + len += snprintf(page + len, count - len, + "%2x ",read_nic_byte(dev,0x100|n)); + + // printk("%2x ",read_nic_byte(dev,n)); + } +len += snprintf(page + len, count - len, + "\n####################page 3##################\n "); + for(n=0;n<=max;) + { + //printk( "\nD: %2x> ", n); + len += snprintf(page + len, count - len, + "\nD: %2x > ",n); + + for(i=0;i<16 && n<=max;i++,n++) + len += snprintf(page + len, count - len, + "%2x ",read_nic_byte(dev,0x300|n)); + + // printk("%2x ",read_nic_byte(dev,n)); + } + +#endif + + len += snprintf(page + len, count - len,"\n"); + *eof = 1; + return len; + +} +#endif + +#if 0 +static int proc_get_cck_reg(char *page, char **start, + off_t offset, int count, + int *eof, void *data) +{ + struct net_device *dev = data; +// struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); + + int len = 0; + int i,n; + + int max = 0x5F; + + /* This dump the current register page */ + for(n=0;n<=max;) + { + //printk( "\nD: %2x> ", n); + len += snprintf(page + len, count - len, + "\nD: %2x > ",n); + + for(i=0;i<16 && n<=max;i++,n++) + len += snprintf(page + len, count - len, + "%2x ",read_phy_cck(dev,n)); + + // printk("%2x ",read_nic_byte(dev,n)); + } + len += snprintf(page + len, count - len,"\n"); + + + *eof = 1; + return len; +} + +#endif + +#if 0 +static int proc_get_ofdm_reg(char *page, char **start, + off_t offset, int count, + int *eof, void *data) +{ + struct net_device *dev = data; +// struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); + + int len = 0; + int i,n; + + //int max=0xff; + int max = 0x40; + + /* This dump the current register page */ + for(n=0;n<=max;) + { + //printk( "\nD: %2x> ", n); + len += snprintf(page + len, count - len, + "\nD: %2x > ",n); + + for(i=0;i<16 && n<=max;i++,n++) + len += snprintf(page + len, count - len, + "%2x ",read_phy_ofdm(dev,n)); + + // printk("%2x ",read_nic_byte(dev,n)); + } + len += snprintf(page + len, count - len,"\n"); + + + + *eof = 1; + return len; +} + +#endif + +#if 0 +static int proc_get_stats_hw(char *page, char **start, + off_t offset, int count, + int *eof, void *data) +{ + struct net_device *dev = data; + struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); + + int len = 0; + + len += snprintf(page + len, count - len, + "NIC int: %lu\n" + "Total int: %lu\n", + priv->stats.ints, + priv->stats.shints); + + *eof = 1; + return len; +} +#endif + +static int proc_get_stats_tx(char *page, char **start, + off_t offset, int count, + int *eof, void *data) +{ + struct net_device *dev = data; + struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); + + int len = 0; + + len += snprintf(page + len, count - len, + "TX VI priority ok int: %lu\n" + "TX VI priority error int: %lu\n" + "TX VO priority ok int: %lu\n" + "TX VO priority error int: %lu\n" + "TX BE priority ok int: %lu\n" + "TX BE priority error int: %lu\n" + "TX BK priority ok int: %lu\n" + "TX BK priority error int: %lu\n" + "TX MANAGE priority ok int: %lu\n" + "TX MANAGE priority error int: %lu\n" + "TX BEACON priority ok int: %lu\n" + "TX BEACON priority error int: %lu\n" +// "TX high priority ok int: %lu\n" +// "TX high priority failed error int: %lu\n" + "TX queue resume: %lu\n" + "TX queue stopped?: %d\n" + "TX fifo overflow: %lu\n" +// "TX beacon: %lu\n" + "TX VI queue: %d\n" + "TX VO queue: %d\n" + "TX BE queue: %d\n" + "TX BK queue: %d\n" +// "TX HW queue: %d\n" + "TX VI dropped: %lu\n" + "TX VO dropped: %lu\n" + "TX BE dropped: %lu\n" + "TX BK dropped: %lu\n" + "TX total data packets %lu\n", +// "TX beacon aborted: %lu\n", + priv->stats.txviokint, + priv->stats.txvierr, + priv->stats.txvookint, + priv->stats.txvoerr, + priv->stats.txbeokint, + priv->stats.txbeerr, + priv->stats.txbkokint, + priv->stats.txbkerr, + priv->stats.txmanageokint, + priv->stats.txmanageerr, + priv->stats.txbeaconokint, + priv->stats.txbeaconerr, +// priv->stats.txhpokint, +// priv->stats.txhperr, + priv->stats.txresumed, + netif_queue_stopped(dev), + priv->stats.txoverflow, +// priv->stats.txbeacon, + atomic_read(&(priv->tx_pending[VI_PRIORITY])), + atomic_read(&(priv->tx_pending[VO_PRIORITY])), + atomic_read(&(priv->tx_pending[BE_PRIORITY])), + atomic_read(&(priv->tx_pending[BK_PRIORITY])), +// read_nic_byte(dev, TXFIFOCOUNT), + priv->stats.txvidrop, + priv->stats.txvodrop, + priv->stats.txbedrop, + priv->stats.txbkdrop, + priv->stats.txdatapkt +// priv->stats.txbeaconerr + ); + + *eof = 1; + return len; +} + + + +static int proc_get_stats_rx(char *page, char **start, + off_t offset, int count, + int *eof, void *data) +{ + struct net_device *dev = data; + struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); + + int len = 0; + + len += snprintf(page + len, count - len, + "RX packets: %lu\n" + "RX urb status error: %lu\n" + "RX invalid urb error: %lu\n", + priv->stats.rxoktotal, + priv->stats.rxstaterr, + priv->stats.rxurberr); + + *eof = 1; + return len; +} +#if 0 +#if WIRELESS_EXT >= 12 && WIRELESS_EXT < 17 + +static struct iw_statistics *r8192_get_wireless_stats(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + + return &priv->wstats; +} +#endif +#endif +void rtl8192_proc_module_init(void) +{ + RT_TRACE(COMP_INIT, "Initializing proc filesystem"); +#if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) + rtl8192_proc=create_proc_entry(RTL819xU_MODULE_NAME, S_IFDIR, proc_net); +#else + rtl8192_proc=create_proc_entry(RTL819xU_MODULE_NAME, S_IFDIR, init_net.proc_net); +#endif +} + + +void rtl8192_proc_module_remove(void) +{ +#if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) + remove_proc_entry(RTL819xU_MODULE_NAME, proc_net); +#else + remove_proc_entry(RTL819xU_MODULE_NAME, init_net.proc_net); +#endif +} + + +void rtl8192_proc_remove_one(struct net_device *dev) +{ + struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); + + + if (priv->dir_dev) { + // remove_proc_entry("stats-hw", priv->dir_dev); + remove_proc_entry("stats-tx", priv->dir_dev); + remove_proc_entry("stats-rx", priv->dir_dev); + // remove_proc_entry("stats-ieee", priv->dir_dev); + remove_proc_entry("stats-ap", priv->dir_dev); + remove_proc_entry("registers", priv->dir_dev); + remove_proc_entry("registers-1", priv->dir_dev); + remove_proc_entry("registers-2", priv->dir_dev); + remove_proc_entry("registers-8", priv->dir_dev); + remove_proc_entry("registers-9", priv->dir_dev); + remove_proc_entry("registers-a", priv->dir_dev); + remove_proc_entry("registers-b", priv->dir_dev); + remove_proc_entry("registers-c", priv->dir_dev); + remove_proc_entry("registers-d", priv->dir_dev); + remove_proc_entry("registers-e", priv->dir_dev); + // remove_proc_entry("cck-registers",priv->dir_dev); + // remove_proc_entry("ofdm-registers",priv->dir_dev); + //remove_proc_entry(dev->name, rtl8192_proc); + remove_proc_entry("wlan0", rtl8192_proc); + priv->dir_dev = NULL; + } +} + + +void rtl8192_proc_init_one(struct net_device *dev) +{ + struct proc_dir_entry *e; + struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); + priv->dir_dev = create_proc_entry(dev->name, + S_IFDIR | S_IRUGO | S_IXUGO, + rtl8192_proc); + if (!priv->dir_dev) { + RT_TRACE(COMP_ERR, "Unable to initialize /proc/net/rtl8192/%s\n", + dev->name); + return; + } + #if 0 + e = create_proc_read_entry("stats-hw", S_IFREG | S_IRUGO, + priv->dir_dev, proc_get_stats_hw, dev); + + if (!e) { + DMESGE("Unable to initialize " + "/proc/net/rtl8192/%s/stats-hw\n", + dev->name); + } + #endif + e = create_proc_read_entry("stats-rx", S_IFREG | S_IRUGO, + priv->dir_dev, proc_get_stats_rx, dev); + + if (!e) { + RT_TRACE(COMP_ERR,"Unable to initialize " + "/proc/net/rtl8192/%s/stats-rx\n", + dev->name); + } + + + e = create_proc_read_entry("stats-tx", S_IFREG | S_IRUGO, + priv->dir_dev, proc_get_stats_tx, dev); + + if (!e) { + RT_TRACE(COMP_ERR, "Unable to initialize " + "/proc/net/rtl8192/%s/stats-tx\n", + dev->name); + } + #if 0 + e = create_proc_read_entry("stats-ieee", S_IFREG | S_IRUGO, + priv->dir_dev, proc_get_stats_ieee, dev); + + if (!e) { + DMESGE("Unable to initialize " + "/proc/net/rtl8192/%s/stats-ieee\n", + dev->name); + } + + #endif + + e = create_proc_read_entry("stats-ap", S_IFREG | S_IRUGO, + priv->dir_dev, proc_get_stats_ap, dev); + + if (!e) { + RT_TRACE(COMP_ERR, "Unable to initialize " + "/proc/net/rtl8192/%s/stats-ap\n", + dev->name); + } + + e = create_proc_read_entry("registers", S_IFREG | S_IRUGO, + priv->dir_dev, proc_get_registers, dev); + if (!e) { + RT_TRACE(COMP_ERR, "Unable to initialize " + "/proc/net/rtl8192/%s/registers\n", + dev->name); + } +#ifdef RTL8192SU + e = create_proc_read_entry("registers-1", S_IFREG | S_IRUGO, + priv->dir_dev, proc_get_registers_1, dev); + if (!e) { + RT_TRACE(COMP_ERR, "Unable to initialize " + "/proc/net/rtl8192/%s/registers-1\n", + dev->name); + } + e = create_proc_read_entry("registers-2", S_IFREG | S_IRUGO, + priv->dir_dev, proc_get_registers_2, dev); + if (!e) { + RT_TRACE(COMP_ERR, "Unable to initialize " + "/proc/net/rtl8192/%s/registers-2\n", + dev->name); + } + e = create_proc_read_entry("registers-8", S_IFREG | S_IRUGO, + priv->dir_dev, proc_get_registers_8, dev); + if (!e) { + RT_TRACE(COMP_ERR, "Unable to initialize " + "/proc/net/rtl8192/%s/registers-8\n", + dev->name); + } + e = create_proc_read_entry("registers-9", S_IFREG | S_IRUGO, + priv->dir_dev, proc_get_registers_9, dev); + if (!e) { + RT_TRACE(COMP_ERR, "Unable to initialize " + "/proc/net/rtl8192/%s/registers-9\n", + dev->name); + } + e = create_proc_read_entry("registers-a", S_IFREG | S_IRUGO, + priv->dir_dev, proc_get_registers_a, dev); + if (!e) { + RT_TRACE(COMP_ERR, "Unable to initialize " + "/proc/net/rtl8192/%s/registers-a\n", + dev->name); + } + e = create_proc_read_entry("registers-b", S_IFREG | S_IRUGO, + priv->dir_dev, proc_get_registers_b, dev); + if (!e) { + RT_TRACE(COMP_ERR, "Unable to initialize " + "/proc/net/rtl8192/%s/registers-b\n", + dev->name); + } + e = create_proc_read_entry("registers-c", S_IFREG | S_IRUGO, + priv->dir_dev, proc_get_registers_c, dev); + if (!e) { + RT_TRACE(COMP_ERR, "Unable to initialize " + "/proc/net/rtl8192/%s/registers-c\n", + dev->name); + } + e = create_proc_read_entry("registers-d", S_IFREG | S_IRUGO, + priv->dir_dev, proc_get_registers_d, dev); + if (!e) { + RT_TRACE(COMP_ERR, "Unable to initialize " + "/proc/net/rtl8192/%s/registers-d\n", + dev->name); + } + e = create_proc_read_entry("registers-e", S_IFREG | S_IRUGO, + priv->dir_dev, proc_get_registers_e, dev); + if (!e) { + RT_TRACE(COMP_ERR, "Unable to initialize " + "/proc/net/rtl8192/%s/registers-e\n", + dev->name); + } +#endif +#if 0 + e = create_proc_read_entry("cck-registers", S_IFREG | S_IRUGO, + priv->dir_dev, proc_get_cck_reg, dev); + if (!e) { + RT_TRACE(COMP_ERR, "Unable to initialize " + "/proc/net/rtl8192/%s/cck-registers\n", + dev->name); + } + + e = create_proc_read_entry("ofdm-registers", S_IFREG | S_IRUGO, + priv->dir_dev, proc_get_ofdm_reg, dev); + if (!e) { + RT_TRACE(COMP_ERR, "Unable to initialize " + "/proc/net/rtl8192/%s/ofdm-registers\n", + dev->name); + } +#endif +} +/**************************************************************************** + -----------------------------MISC STUFF------------------------- +*****************************************************************************/ + +/* this is only for debugging */ +void print_buffer(u32 *buffer, int len) +{ + int i; + u8 *buf =(u8*)buffer; + + printk("ASCII BUFFER DUMP (len: %x):\n",len); + + for(i=0;itx_pending[queue_index]); + + return (used < MAX_TX_URB); +} + +void tx_timeout(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + //rtl8192_commit(dev); + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) + schedule_work(&priv->reset_wq); +#else + schedule_task(&priv->reset_wq); +#endif + //DMESG("TXTIMEOUT"); +} + + +/* this is only for debug */ +void dump_eprom(struct net_device *dev) +{ + int i; + for(i=0; i<63; i++) + RT_TRACE(COMP_EPROM, "EEPROM addr %x : %x", i, eprom_read(dev,i)); +} + +/* this is only for debug */ +void rtl8192_dump_reg(struct net_device *dev) +{ + int i; + int n; + int max=0x1ff; + + RT_TRACE(COMP_PHY, "Dumping NIC register map"); + + for(n=0;n<=max;) + { + printk( "\nD: %2x> ", n); + for(i=0;i<16 && n<=max;i++,n++) + printk("%2x ",read_nic_byte(dev,n)); + } + printk("\n"); +} + +/**************************************************************************** + ------------------------------HW STUFF--------------------------- +*****************************************************************************/ + +#if 0 +void rtl8192_irq_enable(struct net_device *dev) +{ + struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); + //priv->irq_enabled = 1; +/* + write_nic_word(dev,INTA_MASK,INTA_RXOK | INTA_RXDESCERR | INTA_RXOVERFLOW |\ + INTA_TXOVERFLOW | INTA_HIPRIORITYDESCERR | INTA_HIPRIORITYDESCOK |\ + INTA_NORMPRIORITYDESCERR | INTA_NORMPRIORITYDESCOK |\ + INTA_LOWPRIORITYDESCERR | INTA_LOWPRIORITYDESCOK | INTA_TIMEOUT); +*/ + write_nic_word(dev,INTA_MASK, priv->irq_mask); +} + + +void rtl8192_irq_disable(struct net_device *dev) +{ +// struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); + + write_nic_word(dev,INTA_MASK,0); + force_pci_posting(dev); +// priv->irq_enabled = 0; +} +#endif + +void rtl8192_set_mode(struct net_device *dev,int mode) +{ + u8 ecmd; + ecmd=read_nic_byte(dev, EPROM_CMD); + ecmd=ecmd &~ EPROM_CMD_OPERATING_MODE_MASK; + ecmd=ecmd | (mode<ieee80211->state == IEEE80211_LINKED){ + + if (priv->ieee80211->iw_mode == IW_MODE_INFRA) + msr |= (MSR_LINK_MANAGED<ieee80211->iw_mode == IW_MODE_ADHOC) + msr |= (MSR_LINK_ADHOC<ieee80211->iw_mode == IW_MODE_MASTER) + msr |= (MSR_LINK_MASTER<%s()====ch:%d\n", __FUNCTION__, ch); + //printk("=====>%s()====ch:%d\n", __FUNCTION__, ch); + priv->chan=ch; + #if 0 + if(priv->ieee80211->iw_mode == IW_MODE_ADHOC || + priv->ieee80211->iw_mode == IW_MODE_MASTER){ + + priv->ieee80211->link_state = WLAN_LINK_ASSOCIATED; + priv->ieee80211->master_chan = ch; + rtl8192_update_beacon_ch(dev); + } + #endif + + /* this hack should avoid frame TX during channel setting*/ + + +// tx = read_nic_dword(dev,TX_CONF); +// tx &= ~TX_LOOPBACK_MASK; + +#ifndef LOOP_TEST +// write_nic_dword(dev,TX_CONF, tx |( TX_LOOPBACK_MAC<rf_set_chan) + priv->rf_set_chan(dev,priv->chan); + mdelay(10); +// write_nic_dword(dev,TX_CONF,tx | (TX_LOOPBACK_NONE<bisrxaggrsubframe) + return (sizeof(rx_desc_819x_usb) + pstats->RxDrvInfoSize + + pstats->RxBufShift + 8); + else +#endif + return (sizeof(rx_desc_819x_usb) + pstats->RxDrvInfoSize + + pstats->RxBufShift); + +} +static int rtl8192_rx_initiate(struct net_device*dev) +{ + struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); + struct urb *entry; + struct sk_buff *skb; + struct rtl8192_rx_info *info; + + /* nomal packet rx procedure */ + while (skb_queue_len(&priv->rx_queue) < MAX_RX_URB) { + skb = __dev_alloc_skb(RX_URB_SIZE, GFP_KERNEL); + if (!skb) + break; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + entry = usb_alloc_urb(0, GFP_KERNEL); +#else + entry = usb_alloc_urb(0); +#endif + if (!entry) { + kfree_skb(skb); + break; + } +// printk("nomal packet IN request!\n"); + usb_fill_bulk_urb(entry, priv->udev, + usb_rcvbulkpipe(priv->udev, 3), skb->tail, + RX_URB_SIZE, rtl8192_rx_isr, skb); + info = (struct rtl8192_rx_info *) skb->cb; + info->urb = entry; + info->dev = dev; + info->out_pipe = 3; //denote rx normal packet queue + skb_queue_tail(&priv->rx_queue, skb); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + usb_submit_urb(entry, GFP_KERNEL); +#else + usb_submit_urb(entry); +#endif + } + + /* command packet rx procedure */ + while (skb_queue_len(&priv->rx_queue) < MAX_RX_URB + 3) { +// printk("command packet IN request!\n"); + skb = __dev_alloc_skb(RX_URB_SIZE ,GFP_KERNEL); + if (!skb) + break; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + entry = usb_alloc_urb(0, GFP_KERNEL); +#else + entry = usb_alloc_urb(0); +#endif + if (!entry) { + kfree_skb(skb); + break; + } + usb_fill_bulk_urb(entry, priv->udev, + usb_rcvbulkpipe(priv->udev, 9), skb->tail, + RX_URB_SIZE, rtl8192_rx_isr, skb); + info = (struct rtl8192_rx_info *) skb->cb; + info->urb = entry; + info->dev = dev; + info->out_pipe = 9; //denote rx cmd packet queue + skb_queue_tail(&priv->rx_queue, skb); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + usb_submit_urb(entry, GFP_KERNEL); +#else + usb_submit_urb(entry); +#endif + } + + return 0; +} + +void rtl8192_set_rxconf(struct net_device *dev) +{ + struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); + u32 rxconf; + + rxconf=read_nic_dword(dev,RCR); + rxconf = rxconf &~ MAC_FILTER_MASK; + rxconf = rxconf | RCR_AMF; + rxconf = rxconf | RCR_ADF; + rxconf = rxconf | RCR_AB; + rxconf = rxconf | RCR_AM; + //rxconf = rxconf | RCR_ACF; + + if (dev->flags & IFF_PROMISC) {DMESG ("NIC in promisc mode");} + + if(priv->ieee80211->iw_mode == IW_MODE_MONITOR || \ + dev->flags & IFF_PROMISC){ + rxconf = rxconf | RCR_AAP; + } /*else if(priv->ieee80211->iw_mode == IW_MODE_MASTER){ + rxconf = rxconf | (1<ieee80211->iw_mode == IW_MODE_MONITOR){ + rxconf = rxconf | RCR_AICV; + rxconf = rxconf | RCR_APWRMGT; + } + + if( priv->crcmon == 1 && priv->ieee80211->iw_mode == IW_MODE_MONITOR) + rxconf = rxconf | RCR_ACRC32; + + + rxconf = rxconf &~ RX_FIFO_THRESHOLD_MASK; + rxconf = rxconf | (RX_FIFO_THRESHOLD_NONE<card_8187) { + cmd=read_nic_byte(dev,CMD); + write_nic_byte(dev,CMD,cmd | (1<ReceiveConfig); + } +#endif +} + + +void rtl8192_tx_enable(struct net_device *dev) +{ +#if 0 + u8 cmd; + u8 byte; + u32 txconf; + struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); + //test loopback + // priv->TransmitConfig |= (TX_LOOPBACK_BASEBAND<card_8187){ + write_nic_dword(dev, TX_CONF, priv->TransmitConfig); + byte = read_nic_byte(dev, MSR); + byte |= MSR_LINK_ENEDCA; + write_nic_byte(dev, MSR, byte); + } else { + byte = read_nic_byte(dev,CW_CONF); + byte &= ~(1<retry_data<retry_rts<dma_poll_mask &=~(1<dma_poll_mask); + rtl8192_set_mode(dev,EPROM_CMD_NORMAL); +} + + +void rtl8192_ +_disable(struct net_device *dev) +{ + struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); + priv->dma_poll_mask |= (1<dma_poll_mask); + rtl8192_set_mode(dev,EPROM_CMD_NORMAL); +} + +#endif + + +void rtl8192_rtx_disable(struct net_device *dev) +{ + u8 cmd; + struct r8192_priv *priv = ieee80211_priv(dev); + struct sk_buff *skb; + struct rtl8192_rx_info *info; + + cmd=read_nic_byte(dev,CMDR); + write_nic_byte(dev, CMDR, cmd &~ \ + (CR_TE|CR_RE)); + force_pci_posting(dev); + mdelay(10); + + while ((skb = __skb_dequeue(&priv->rx_queue))) { + info = (struct rtl8192_rx_info *) skb->cb; + if (!info->urb) + continue; + + usb_kill_urb(info->urb); + kfree_skb(skb); + } + + if (skb_queue_len(&priv->skb_queue)) { + printk(KERN_WARNING "skb_queue not empty\n"); + } + + skb_queue_purge(&priv->skb_queue); + return; +} + + +int alloc_tx_beacon_desc_ring(struct net_device *dev, int count) +{ + #if 0 + int i; + u32 *tmp; + struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); + + priv->txbeaconring = (u32*)pci_alloc_consistent(priv->pdev, + sizeof(u32)*8*count, + &priv->txbeaconringdma); + if (!priv->txbeaconring) return -1; + for (tmp=priv->txbeaconring,i=0;itxbeaconringdma+((i+1)*8*4); + else + *(tmp+4) = (u32)priv->txbeaconringdma; + + tmp=tmp+8; + } + #endif + return 0; +} + +#if 0 +void rtl8192_reset(struct net_device *dev) +{ + + //struct r8192_priv *priv = ieee80211_priv(dev); + //u8 cr; + + + /* make sure the analog power is on before + * reset, otherwise reset may fail + */ +#if 0 + if(NIC_8187 == priv->card_8187) { + rtl8192_set_anaparam(dev, RTL8225_ANAPARAM_ON); + rtl8185_set_anaparam2(dev, RTL8225_ANAPARAM2_ON); + rtl8192_irq_disable(dev); + mdelay(200); + write_nic_byte_E(dev,0x18,0x10); + write_nic_byte_E(dev,0x18,0x11); + write_nic_byte_E(dev,0x18,0x00); + mdelay(200); + } +#endif + printk("=====>reset?\n"); +#if 0 + cr=read_nic_byte(dev,CMD); + cr = cr & 2; + cr = cr | (1<card_8187) { + + printk("This is RTL8187 Reset procedure\n"); + rtl8192_set_mode(dev,EPROM_CMD_LOAD); + force_pci_posting(dev); + mdelay(200); + + /* after the eeprom load cycle, make sure we have + * correct anaparams + */ + rtl8192_set_anaparam(dev, RTL8225_ANAPARAM_ON); + rtl8185_set_anaparam2(dev, RTL8225_ANAPARAM2_ON); + } + else +#endif + printk("This is RTL8187B Reset procedure\n"); + +} +#endif +inline u16 ieeerate2rtlrate(int rate) +{ + switch(rate){ + case 10: + return 0; + case 20: + return 1; + case 55: + return 2; + case 110: + return 3; + case 60: + return 4; + case 90: + return 5; + case 120: + return 6; + case 180: + return 7; + case 240: + return 8; + case 360: + return 9; + case 480: + return 10; + case 540: + return 11; + default: + return 3; + + } +} +static u16 rtl_rate[] = {10,20,55,110,60,90,120,180,240,360,480,540}; +inline u16 rtl8192_rate2rate(short rate) +{ + if (rate >11) return 0; + return rtl_rate[rate]; +} + + +/* The protype of rx_isr has changed since one verion of Linux Kernel */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) +static void rtl8192_rx_isr(struct urb *urb, struct pt_regs *regs) +#else +static void rtl8192_rx_isr(struct urb *urb) +#endif +{ + struct sk_buff *skb = (struct sk_buff *) urb->context; + struct rtl8192_rx_info *info = (struct rtl8192_rx_info *)skb->cb; + struct net_device *dev = info->dev; + struct r8192_priv *priv = ieee80211_priv(dev); + int out_pipe = info->out_pipe; + int err; + if(!priv->up) + return; + if (unlikely(urb->status)) { + info->urb = NULL; + priv->stats.rxstaterr++; + priv->ieee80211->stats.rx_errors++; + usb_free_urb(urb); + // printk("%s():rx status err\n",__FUNCTION__); + return; + } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14) + skb_unlink(skb, &priv->rx_queue); +#else + /* + * __skb_unlink before linux2.6.14 does not use spinlock to protect list head. + * add spinlock function manually. john,2008/12/03 + */ + { + unsigned long flags; + spin_lock_irqsave(&(priv->rx_queue.lock), flags); + __skb_unlink(skb,&priv->rx_queue); + spin_unlock_irqrestore(&(priv->rx_queue.lock), flags); + } +#endif + skb_put(skb, urb->actual_length); + + skb_queue_tail(&priv->skb_queue, skb); + tasklet_schedule(&priv->irq_rx_tasklet); + + skb = dev_alloc_skb(RX_URB_SIZE); + if (unlikely(!skb)) { + usb_free_urb(urb); + printk("%s():can,t alloc skb\n",__FUNCTION__); + /* TODO check rx queue length and refill *somewhere* */ + return; + } + + usb_fill_bulk_urb(urb, priv->udev, + usb_rcvbulkpipe(priv->udev, out_pipe), skb->tail, + RX_URB_SIZE, rtl8192_rx_isr, skb); + + info = (struct rtl8192_rx_info *) skb->cb; + info->urb = urb; + info->dev = dev; + info->out_pipe = out_pipe; + + urb->transfer_buffer = skb->tail; + urb->context = skb; + skb_queue_tail(&priv->rx_queue, skb); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + err = usb_submit_urb(urb, GFP_ATOMIC); +#else + err = usb_submit_urb(urb); +#endif + if(err && err != EPERM) + printk("can not submit rxurb, err is %x,URB status is %x\n",err,urb->status); +} + +u32 +rtl819xusb_rx_command_packet( + struct net_device *dev, + struct ieee80211_rx_stats *pstats + ) +{ + u32 status; + + //RT_TRACE(COMP_RECV, DBG_TRACE, ("---> RxCommandPacketHandle819xUsb()\n")); + + status = cmpk_message_handle_rx(dev, pstats); + if (status) + { + DMESG("rxcommandpackethandle819xusb: It is a command packet\n"); + } + else + { + //RT_TRACE(COMP_RECV, DBG_TRACE, ("RxCommandPacketHandle819xUsb: It is not a command packet\n")); + } + + //RT_TRACE(COMP_RECV, DBG_TRACE, ("<--- RxCommandPacketHandle819xUsb()\n")); + return status; +} + +#if 0 +void rtl8192_tx_queues_stop(struct net_device *dev) +{ + //struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); + u8 dma_poll_mask = (1<dma_poll_mask |= (1<dma_poll_mask); + rtl8192_set_mode(dev,EPROM_CMD_NORMAL); + #endif +} + + +void rtl8192_data_hard_resume(struct net_device *dev) +{ + // FIXME !! + #if 0 + struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); + priv->dma_poll_mask &= ~(1<dma_poll_mask); + rtl8192_set_mode(dev,EPROM_CMD_NORMAL); + #endif +} + +/* this function TX data frames when the ieee80211 stack requires this. + * It checks also if we need to stop the ieee tx queue, eventually do it + */ +void rtl8192_hard_data_xmit(struct sk_buff *skb, struct net_device *dev, int rate) +{ + struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); + int ret; + unsigned long flags; + cb_desc *tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE); + u8 queue_index = tcb_desc->queue_index; + + /* shall not be referred by command packet */ + assert(queue_index != TXCMD_QUEUE); + + spin_lock_irqsave(&priv->tx_lock,flags); + + memcpy((unsigned char *)(skb->cb),&dev,sizeof(dev)); +// tcb_desc->RATRIndex = 7; +// tcb_desc->bTxDisableRateFallBack = 1; +// tcb_desc->bTxUseDriverAssingedRate = 1; + tcb_desc->bTxEnableFwCalcDur = 1; + skb_push(skb, priv->ieee80211->tx_headroom); + ret = priv->ops->rtl819x_tx(dev, skb); + + //priv->ieee80211->stats.tx_bytes+=(skb->len - priv->ieee80211->tx_headroom); + //priv->ieee80211->stats.tx_packets++; + + spin_unlock_irqrestore(&priv->tx_lock,flags); + +// return ret; + return; +} + +/* This is a rough attempt to TX a frame + * This is called by the ieee 80211 stack to TX management frames. + * If the ring is full packet are dropped (for data frame the queue + * is stopped before this can happen). + */ +int rtl8192_hard_start_xmit(struct sk_buff *skb,struct net_device *dev) +{ + struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); + int ret; + unsigned long flags; + cb_desc *tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE); + u8 queue_index = tcb_desc->queue_index; + + + spin_lock_irqsave(&priv->tx_lock,flags); + + memcpy((unsigned char *)(skb->cb),&dev,sizeof(dev)); + if(queue_index == TXCMD_QUEUE) { + skb_push(skb, USB_HWDESC_HEADER_LEN); + priv->ops->rtl819x_tx_cmd(dev, skb); + ret = 1; + spin_unlock_irqrestore(&priv->tx_lock,flags); + return ret; + } else { + skb_push(skb, priv->ieee80211->tx_headroom); + ret = priv->ops->rtl819x_tx(dev, skb); + } + + spin_unlock_irqrestore(&priv->tx_lock,flags); + + return ret; +} + + +void rtl8192_try_wake_queue(struct net_device *dev, int pri); + +#ifdef USB_TX_DRIVER_AGGREGATION_ENABLE +u16 DrvAggr_PaddingAdd(struct net_device *dev, struct sk_buff *skb) +{ + u16 PaddingNum = 256 - ((skb->len + TX_PACKET_DRVAGGR_SUBFRAME_SHIFT_BYTES) % 256); + return (PaddingNum&0xff); +} + +u8 MRateToHwRate8190Pci(u8 rate); +u8 QueryIsShort(u8 TxHT, u8 TxRate, cb_desc *tcb_desc); +u8 MapHwQueueToFirmwareQueue(u8 QueueID); +struct sk_buff *DrvAggr_Aggregation(struct net_device *dev, struct ieee80211_drv_agg_txb *pSendList) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + struct ieee80211_device *ieee = netdev_priv(dev); +#else + struct ieee80211_device *ieee = (struct ieee80211_device *)dev->priv; +#endif + struct r8192_priv *priv = ieee80211_priv(dev); + cb_desc *tcb_desc = NULL; + u8 i; + u32 TotalLength; + struct sk_buff *skb; + struct sk_buff *agg_skb; + tx_desc_819x_usb_aggr_subframe *tx_agg_desc = NULL; + tx_fwinfo_819x_usb *tx_fwinfo = NULL; + + // + // Local variable initialization. + // + /* first skb initialization */ + skb = pSendList->tx_agg_frames[0]; + TotalLength = skb->len; + + /* Get the total aggregation length including the padding space and + * sub frame header. + */ + for(i = 1; i < pSendList->nr_drv_agg_frames; i++) { + TotalLength += DrvAggr_PaddingAdd(dev, skb); + skb = pSendList->tx_agg_frames[i]; + TotalLength += (skb->len + TX_PACKET_DRVAGGR_SUBFRAME_SHIFT_BYTES); + } + + /* allocate skb to contain the aggregated packets */ + agg_skb = dev_alloc_skb(TotalLength + ieee->tx_headroom); + memset(agg_skb->data, 0, agg_skb->len); + skb_reserve(agg_skb, ieee->tx_headroom); + +// RT_DEBUG_DATA(COMP_SEND, skb->cb, sizeof(skb->cb)); + /* reserve info for first subframe Tx descriptor to be set in the tx function */ + skb = pSendList->tx_agg_frames[0]; + tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE); + tcb_desc->drv_agg_enable = 1; + tcb_desc->pkt_size = skb->len; + tcb_desc->DrvAggrNum = pSendList->nr_drv_agg_frames; + printk("DrvAggNum = %d\n", tcb_desc->DrvAggrNum); +// RT_DEBUG_DATA(COMP_SEND, skb->cb, sizeof(skb->cb)); +// printk("========>skb->data ======> \n"); +// RT_DEBUG_DATA(COMP_SEND, skb->data, skb->len); + memcpy(agg_skb->cb, skb->cb, sizeof(skb->cb)); + memcpy(skb_put(agg_skb,skb->len),skb->data,skb->len); + + for(i = 1; i < pSendList->nr_drv_agg_frames; i++) { + /* push the next sub frame to be 256 byte aline */ + skb_put(agg_skb,DrvAggr_PaddingAdd(dev,skb)); + + /* Subframe drv Tx descriptor and firmware info setting */ + skb = pSendList->tx_agg_frames[i]; + tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE); + tx_agg_desc = (tx_desc_819x_usb_aggr_subframe *)agg_skb->tail; + tx_fwinfo = (tx_fwinfo_819x_usb *)(agg_skb->tail + sizeof(tx_desc_819x_usb_aggr_subframe)); + + memset(tx_fwinfo,0,sizeof(tx_fwinfo_819x_usb)); + /* DWORD 0 */ + tx_fwinfo->TxHT = (tcb_desc->data_rate&0x80)?1:0; + tx_fwinfo->TxRate = MRateToHwRate8190Pci(tcb_desc->data_rate); + tx_fwinfo->EnableCPUDur = tcb_desc->bTxEnableFwCalcDur; + tx_fwinfo->Short = QueryIsShort(tx_fwinfo->TxHT, tx_fwinfo->TxRate, tcb_desc); + if(tcb_desc->bAMPDUEnable) {//AMPDU enabled + tx_fwinfo->AllowAggregation = 1; + /* DWORD 1 */ + tx_fwinfo->RxMF = tcb_desc->ampdu_factor; + tx_fwinfo->RxAMD = tcb_desc->ampdu_density&0x07;//ampdudensity + } else { + tx_fwinfo->AllowAggregation = 0; + /* DWORD 1 */ + tx_fwinfo->RxMF = 0; + tx_fwinfo->RxAMD = 0; + } + + /* Protection mode related */ + tx_fwinfo->RtsEnable = (tcb_desc->bRTSEnable)?1:0; + tx_fwinfo->CtsEnable = (tcb_desc->bCTSEnable)?1:0; + tx_fwinfo->RtsSTBC = (tcb_desc->bRTSSTBC)?1:0; + tx_fwinfo->RtsHT = (tcb_desc->rts_rate&0x80)?1:0; + tx_fwinfo->RtsRate = MRateToHwRate8190Pci((u8)tcb_desc->rts_rate); + tx_fwinfo->RtsSubcarrier = (tx_fwinfo->RtsHT==0)?(tcb_desc->RTSSC):0; + tx_fwinfo->RtsBandwidth = (tx_fwinfo->RtsHT==1)?((tcb_desc->bRTSBW)?1:0):0; + tx_fwinfo->RtsShort = (tx_fwinfo->RtsHT==0)?(tcb_desc->bRTSUseShortPreamble?1:0):\ + (tcb_desc->bRTSUseShortGI?1:0); + + /* Set Bandwidth and sub-channel settings. */ + if(priv->CurrentChannelBW == HT_CHANNEL_WIDTH_20_40) + { + if(tcb_desc->bPacketBW) { + tx_fwinfo->TxBandwidth = 1; + tx_fwinfo->TxSubCarrier = 0; //By SD3's Jerry suggestion, use duplicated mode + } else { + tx_fwinfo->TxBandwidth = 0; + tx_fwinfo->TxSubCarrier = priv->nCur40MhzPrimeSC; + } + } else { + tx_fwinfo->TxBandwidth = 0; + tx_fwinfo->TxSubCarrier = 0; + } + + /* Fill Tx descriptor */ + memset(tx_agg_desc, 0, sizeof(tx_desc_819x_usb_aggr_subframe)); + /* DWORD 0 */ + //tx_agg_desc->LINIP = 0; + //tx_agg_desc->CmdInit = 1; + tx_agg_desc->Offset = sizeof(tx_fwinfo_819x_usb) + 8; + /* already raw data, need not to substract header length */ + tx_agg_desc->PktSize = skb->len & 0xffff; + + /*DWORD 1*/ + tx_agg_desc->SecCAMID= 0; + tx_agg_desc->RATid = tcb_desc->RATRIndex; +#if 0 + /* Fill security related */ + if( pTcb->bEncrypt && !Adapter->MgntInfo.SecurityInfo.SWTxEncryptFlag) + { + EncAlg = SecGetEncryptionOverhead( + Adapter, + &EncryptionMPDUHeadOverhead, + &EncryptionMPDUTailOverhead, + NULL, + NULL, + FALSE, + FALSE); + //2004/07/22, kcwu, EncryptionMPDUHeadOverhead has been added in previous code + //MPDUOverhead = EncryptionMPDUHeadOverhead + EncryptionMPDUTailOverhead; + MPDUOverhead = EncryptionMPDUTailOverhead; + tx_agg_desc->NoEnc = 0; + RT_TRACE(COMP_SEC, DBG_LOUD, ("******We in the loop SecCAMID is %d SecDescAssign is %d The Sec is %d********\n",tx_agg_desc->SecCAMID,tx_agg_desc->SecDescAssign,EncAlg)); + //CamDumpAll(Adapter); + } + else +#endif + { + //MPDUOverhead = 0; + tx_agg_desc->NoEnc = 1; + } +#if 0 + switch(EncAlg){ + case NO_Encryption: + tx_agg_desc->SecType = 0x0; + break; + case WEP40_Encryption: + case WEP104_Encryption: + tx_agg_desc->SecType = 0x1; + break; + case TKIP_Encryption: + tx_agg_desc->SecType = 0x2; + break; + case AESCCMP_Encryption: + tx_agg_desc->SecType = 0x3; + break; + default: + tx_agg_desc->SecType = 0x0; + break; + } +#else + tx_agg_desc->SecType = 0x0; +#endif + + if (tcb_desc->bHwSec) { + switch (priv->ieee80211->pairwise_key_type) + { + case KEY_TYPE_WEP40: + case KEY_TYPE_WEP104: + tx_agg_desc->SecType = 0x1; + tx_agg_desc->NoEnc = 0; + break; + case KEY_TYPE_TKIP: + tx_agg_desc->SecType = 0x2; + tx_agg_desc->NoEnc = 0; + break; + case KEY_TYPE_CCMP: + tx_agg_desc->SecType = 0x3; + tx_agg_desc->NoEnc = 0; + break; + case KEY_TYPE_NA: + tx_agg_desc->SecType = 0x0; + tx_agg_desc->NoEnc = 1; + break; + } + } + + tx_agg_desc->QueueSelect = MapHwQueueToFirmwareQueue(tcb_desc->queue_index); + tx_agg_desc->TxFWInfoSize = sizeof(tx_fwinfo_819x_usb); + + tx_agg_desc->DISFB = tcb_desc->bTxDisableRateFallBack; + tx_agg_desc->USERATE = tcb_desc->bTxUseDriverAssingedRate; + + tx_agg_desc->OWN = 1; + + //DWORD 2 + /* According windows driver, it seems that there no need to fill this field */ + //tx_agg_desc->TxBufferSize= (u32)(skb->len - USB_HWDESC_HEADER_LEN); + + /* to fill next packet */ + skb_put(agg_skb,TX_PACKET_DRVAGGR_SUBFRAME_SHIFT_BYTES); + memcpy(skb_put(agg_skb,skb->len),skb->data,skb->len); + } + + for(i = 0; i < pSendList->nr_drv_agg_frames; i++) { + dev_kfree_skb_any(pSendList->tx_agg_frames[i]); + } + + return agg_skb; +} + +/* NOTE: + This function return a list of PTCB which is proper to be aggregate with the input TCB. + If no proper TCB is found to do aggregation, SendList will only contain the input TCB. +*/ +u8 DrvAggr_GetAggregatibleList(struct net_device *dev, struct sk_buff *skb, + struct ieee80211_drv_agg_txb *pSendList) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + struct ieee80211_device *ieee = netdev_priv(dev); +#else + struct ieee80211_device *ieee = (struct ieee80211_device *)dev->priv; +#endif + PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; + u16 nMaxAggrNum = pHTInfo->UsbTxAggrNum; + cb_desc *tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE); + u8 QueueID = tcb_desc->queue_index; + + do { + pSendList->tx_agg_frames[pSendList->nr_drv_agg_frames++] = skb; + if(pSendList->nr_drv_agg_frames >= nMaxAggrNum) { + break; + } + + } while((skb = skb_dequeue(&ieee->skb_drv_aggQ[QueueID]))); + + RT_TRACE(COMP_AMSDU, "DrvAggr_GetAggregatibleList, nAggrTcbNum = %d \n", pSendList->nr_drv_agg_frames); + return pSendList->nr_drv_agg_frames; +} +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) +static void rtl8192_tx_isr(struct urb *tx_urb, struct pt_regs *reg) +#else +static void rtl8192_tx_isr(struct urb *tx_urb) +#endif +{ + struct sk_buff *skb = (struct sk_buff*)tx_urb->context; + struct net_device *dev = NULL; + struct r8192_priv *priv = NULL; + cb_desc *tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE); + u8 queue_index = tcb_desc->queue_index; +// bool bToSend0Byte; +// u16 BufLen = skb->len; + + memcpy(&dev,(struct net_device*)(skb->cb),sizeof(struct net_device*)); + priv = ieee80211_priv(dev); + + if(tcb_desc->queue_index != TXCMD_QUEUE) { + if(tx_urb->status == 0) { + // dev->trans_start = jiffies; + // As act as station mode, destion shall be unicast address. + //priv->ieee80211->stats.tx_bytes+=(skb->len - priv->ieee80211->tx_headroom); + //priv->ieee80211->stats.tx_packets++; + priv->stats.txoktotal++; + priv->ieee80211->LinkDetectInfo.NumTxOkInPeriod++; + priv->stats.txbytesunicast += (skb->len - priv->ieee80211->tx_headroom); + } else { + priv->ieee80211->stats.tx_errors++; + //priv->stats.txmanageerr++; + /* TODO */ + } + } + + /* free skb and tx_urb */ + if(skb != NULL) { + dev_kfree_skb_any(skb); + usb_free_urb(tx_urb); + atomic_dec(&priv->tx_pending[queue_index]); + } + +#if 0 //we need to send zero byte packet just after 512 byte(64 byte)packet is transmitted, or we will halt. It will greatly reduced available page in FW, and ruin our throughput. WB 2008.08.27 + if(BufLen > 0 && ((BufLen % 512 == 0)||(BufLen % 64 == 0))) { + bToSend0Byte = true; + } + + bToSend0Byte = false; + // + // Note that, we at most handle 1 MPDU to send here, either + // fragment or MPDU in wait queue. + // + if(!bToSend0Byte) +#endif + { + // + // Handle HW Beacon: + // We had transfer our beacon frame to host controler at this moment. + // +#if 0 + if(tcb_desc->tx_queue == BEACON_QUEUE) + { + priv->bSendingBeacon = FALSE; + } +#endif + // + // Caution: + // Handling the wait queue of command packets. + // For Tx command packets, we must not do TCB fragment because it is not handled right now. + // We must cut the packets to match the size of TX_CMD_PKT before we send it. + // + if (queue_index == MGNT_QUEUE){ + if (priv->ieee80211->ack_tx_to_ieee){ + if (rtl8192_is_tx_queue_empty(dev)){ + priv->ieee80211->ack_tx_to_ieee = 0; + ieee80211_ps_tx_ack(priv->ieee80211, 1); + } + } + } + /* Handle MPDU in wait queue. */ + if(queue_index != BEACON_QUEUE) { + /* Don't send data frame during scanning.*/ + if((skb_queue_len(&priv->ieee80211->skb_waitQ[queue_index]) != 0)&&\ + (!(priv->ieee80211->queue_stop))) { + if(NULL != (skb = skb_dequeue(&(priv->ieee80211->skb_waitQ[queue_index])))) + priv->ieee80211->softmac_hard_start_xmit(skb, dev); + + return; //modified by david to avoid further processing AMSDU + } +#ifdef USB_TX_DRIVER_AGGREGATION_ENABLE + else if ((skb_queue_len(&priv->ieee80211->skb_drv_aggQ[queue_index])!= 0)&&\ + (!(priv->ieee80211->queue_stop))) { + // Tx Driver Aggregation process + /* The driver will aggregation the packets according to the following stets + * 1. check whether there's tx irq available, for it's a completion return + * function, it should contain enough tx irq; + * 2. check pakcet type; + * 3. intialize sendlist, check whether the to-be send packet no greater than 1 + * 4. aggregation the packets, and fill firmware info and tx desc to it, etc. + * 5. check whehter the packet could be sent, otherwise just insert to wait head + * */ + skb = skb_dequeue(&priv->ieee80211->skb_drv_aggQ[queue_index]); + if(!check_nic_enough_desc(dev, queue_index)) { + skb_queue_head(&(priv->ieee80211->skb_drv_aggQ[queue_index]), skb); + return; + } + + { + /*TODO*/ + /* + u8* pHeader = skb->data; + + if(IsMgntQosData(pHeader) || + IsMgntQData_Ack(pHeader) || + IsMgntQData_Poll(pHeader) || + IsMgntQData_Poll_Ack(pHeader) + ) + */ + { + struct ieee80211_drv_agg_txb SendList; + + memset(&SendList, 0, sizeof(struct ieee80211_drv_agg_txb)); + if(DrvAggr_GetAggregatibleList(dev, skb, &SendList) > 1) { + skb = DrvAggr_Aggregation(dev, &SendList); + +#if 0 + printk("=============>to send aggregated packet!\n"); + RT_DEBUG_DATA(COMP_SEND, skb->cb, sizeof(skb->cb)); + printk("\n=================skb->len = %d\n", skb->len); + RT_DEBUG_DATA(COMP_SEND, skb->data, skb->len); +#endif + } + } + priv->ieee80211->softmac_hard_start_xmit(skb, dev); + } + } +#endif + } + } + +#if 0 + else + { + RT_TRACE( COMP_SEND,"HalUsbOutComplete(%d): bToSend0Byte.\n", PipeIndex); + + // + // In this case, we don't return skb now. + // It will be returned when the 0-byte request completed. + // + + // + // Bulk out an 0-byte padding transfer. + // + HalUsbOut0Byte(pAdapter, PipeIndex, skb); + } + +#endif +} + +void rtl8192_beacon_stop(struct net_device *dev) +{ + u8 msr, msrm, msr2; + struct r8192_priv *priv = ieee80211_priv(dev); + + msr = read_nic_byte(dev, MSR); + msrm = msr & MSR_LINK_MASK; + msr2 = msr & ~MSR_LINK_MASK; + + if(NIC_8192U == priv->card_8192) { + usb_kill_urb(priv->rx_urb[MAX_RX_URB]); + } + if ((msrm == (MSR_LINK_ADHOC<ieee80211->current_network; + + for (i=0; irates_len; i++) + { + basic_rate = net->rates[i]&0x7f; + switch(basic_rate) + { + case MGN_1M: *rate_config |= RRSR_1M; break; + case MGN_2M: *rate_config |= RRSR_2M; break; + case MGN_5_5M: *rate_config |= RRSR_5_5M; break; + case MGN_11M: *rate_config |= RRSR_11M; break; + case MGN_6M: *rate_config |= RRSR_6M; break; + case MGN_9M: *rate_config |= RRSR_9M; break; + case MGN_12M: *rate_config |= RRSR_12M; break; + case MGN_18M: *rate_config |= RRSR_18M; break; + case MGN_24M: *rate_config |= RRSR_24M; break; + case MGN_36M: *rate_config |= RRSR_36M; break; + case MGN_48M: *rate_config |= RRSR_48M; break; + case MGN_54M: *rate_config |= RRSR_54M; break; + } + } + for (i=0; irates_ex_len; i++) + { + basic_rate = net->rates_ex[i]&0x7f; + switch(basic_rate) + { + case MGN_1M: *rate_config |= RRSR_1M; break; + case MGN_2M: *rate_config |= RRSR_2M; break; + case MGN_5_5M: *rate_config |= RRSR_5_5M; break; + case MGN_11M: *rate_config |= RRSR_11M; break; + case MGN_6M: *rate_config |= RRSR_6M; break; + case MGN_9M: *rate_config |= RRSR_9M; break; + case MGN_12M: *rate_config |= RRSR_12M; break; + case MGN_18M: *rate_config |= RRSR_18M; break; + case MGN_24M: *rate_config |= RRSR_24M; break; + case MGN_36M: *rate_config |= RRSR_36M; break; + case MGN_48M: *rate_config |= RRSR_48M; break; + case MGN_54M: *rate_config |= RRSR_54M; break; + } + } +} + + +#define SHORT_SLOT_TIME 9 +#define NON_SHORT_SLOT_TIME 20 + +void rtl8192_update_cap(struct net_device* dev, u16 cap) +{ + //u32 tmp = 0; + struct r8192_priv *priv = ieee80211_priv(dev); + struct ieee80211_network *net = &priv->ieee80211->current_network; + priv->short_preamble = cap & WLAN_CAPABILITY_SHORT_PREAMBLE; + + //LZM MOD 090303 HW_VAR_ACK_PREAMBLE +#ifdef RTL8192SU + if(0) + { + u8 tmp = 0; + tmp = ((priv->nCur40MhzPrimeSC) << 5); + if (priv->short_preamble) + tmp |= 0x80; + write_nic_byte(dev, RRSR+2, tmp); + } +#else + { + u32 tmp = 0; + tmp = priv->basic_rate; + if (priv->short_preamble) + tmp |= BRSR_AckShortPmb; + write_nic_dword(dev, RRSR, tmp); + } +#endif + + if (net->mode & (IEEE_G|IEEE_N_24G)) + { + u8 slot_time = 0; + if ((cap & WLAN_CAPABILITY_SHORT_SLOT)&&(!priv->ieee80211->pHTInfo->bCurrentRT2RTLongSlotTime)) + {//short slot time + slot_time = SHORT_SLOT_TIME; + } + else //long slot time + slot_time = NON_SHORT_SLOT_TIME; + priv->slot_time = slot_time; + write_nic_byte(dev, SLOT_TIME, slot_time); + } + +} +void rtl8192_net_update(struct net_device *dev) +{ + + struct r8192_priv *priv = ieee80211_priv(dev); + struct ieee80211_network *net; + u16 BcnTimeCfg = 0, BcnCW = 6, BcnIFS = 0xf; + u16 rate_config = 0; + net = & priv->ieee80211->current_network; + + rtl8192_config_rate(dev, &rate_config); + priv->basic_rate = rate_config &= 0x15f; + + write_nic_dword(dev,BSSIDR,((u32*)net->bssid)[0]); + write_nic_word(dev,BSSIDR+4,((u16*)net->bssid)[2]); + //for(i=0;ibssid[i]); + + rtl8192_update_msr(dev); +// rtl8192_update_cap(dev, net->capability); + if (priv->ieee80211->iw_mode == IW_MODE_ADHOC) + { + write_nic_word(dev, ATIMWND, 2); + write_nic_word(dev, BCN_DMATIME, 1023); + write_nic_word(dev, BCN_INTERVAL, net->beacon_interval); +// write_nic_word(dev, BcnIntTime, 100); + write_nic_word(dev, BCN_DRV_EARLY_INT, 1); + write_nic_byte(dev, BCN_ERR_THRESH, 100); + BcnTimeCfg |= (BcnCW<ieee80211); + if(!skb){ + DMESG("not enought memory for allocating beacon"); + return; + } + + + write_nic_byte(dev, BQREQ, read_nic_byte(dev, BQREQ) | (1<<7)); + + i=0; + //while(!read_nic_byte(dev,BQREQ & (1<<7))) + while( (read_nic_byte(dev, BQREQ) & (1<<7)) == 0 ) + { + msleep_interruptible_rtl(HZ/2); + if(i++ > 10){ + DMESGW("get stuck to wait HW beacon to be ready"); + return ; + } + } + skb->cb[0] = NORM_PRIORITY; + skb->cb[1] = 0; //morefragment = 0 + skb->cb[2] = ieeerate2rtlrate(tx_rate); + + rtl8192_tx(dev,skb); + +#endif +} +#endif +inline u8 rtl8192_IsWirelessBMode(u16 rate) +{ + if( ((rate <= 110) && (rate != 60) && (rate != 90)) || (rate == 220) ) + return 1; + else return 0; +} + +u16 N_DBPSOfRate(u16 DataRate); + +u16 ComputeTxTime( + u16 FrameLength, + u16 DataRate, + u8 bManagementFrame, + u8 bShortPreamble +) +{ + u16 FrameTime; + u16 N_DBPS; + u16 Ceiling; + + if( rtl8192_IsWirelessBMode(DataRate) ) + { + if( bManagementFrame || !bShortPreamble || DataRate == 10 ) + { // long preamble + FrameTime = (u16)(144+48+(FrameLength*8/(DataRate/10))); + } + else + { // Short preamble + FrameTime = (u16)(72+24+(FrameLength*8/(DataRate/10))); + } + if( ( FrameLength*8 % (DataRate/10) ) != 0 ) //Get the Ceilling + FrameTime ++; + } else { //802.11g DSSS-OFDM PLCP length field calculation. + N_DBPS = N_DBPSOfRate(DataRate); + Ceiling = (16 + 8*FrameLength + 6) / N_DBPS + + (((16 + 8*FrameLength + 6) % N_DBPS) ? 1 : 0); + FrameTime = (u16)(16 + 4 + 4*Ceiling + 6); + } + return FrameTime; +} + +u16 N_DBPSOfRate(u16 DataRate) +{ + u16 N_DBPS = 24; + + switch(DataRate) + { + case 60: + N_DBPS = 24; + break; + + case 90: + N_DBPS = 36; + break; + + case 120: + N_DBPS = 48; + break; + + case 180: + N_DBPS = 72; + break; + + case 240: + N_DBPS = 96; + break; + + case 360: + N_DBPS = 144; + break; + + case 480: + N_DBPS = 192; + break; + + case 540: + N_DBPS = 216; + break; + + default: + break; + } + + return N_DBPS; +} + +void rtl819xU_cmd_isr(struct urb *tx_cmd_urb, struct pt_regs *regs) +{ +#if 0 + struct net_device *dev = (struct net_device*)tx_cmd_urb->context; + struct r8192_priv *priv = ieee80211_priv(dev); + int last_init_packet = 0; + u8 *ptr_cmd_buf; + u16 cmd_buf_len; + + if(tx_cmd_urb->status != 0) { + priv->pFirmware.firmware_seg_index = 0; //only begin transter, should it can be set to 1 + } + + /* Free the urb and the corresponding buf for common Tx cmd packet, or + * last segment of each firmware img. + */ + if((priv->pFirmware.firmware_seg_index == 0) ||(priv->pFirmware.firmware_seg_index == priv->pFirmware.firmware_seg_maxnum)) { + priv->pFirmware.firmware_seg_index = 0;//only begin transter, should it can be set to 1 + } else { + /* prepare for last transfer */ + /* update some infomation for */ + /* last segment of the firmware img need indicate to device */ + priv->pFirmware.firmware_seg_index++; + if(priv->pFirmware.firmware_seg_index == priv->pFirmware.firmware_seg_maxnum) { + last_init_packet = 1; + } + + cmd_buf_len = priv->pFirmware.firmware_seg_container[priv->pFirmware.firmware_seg_index-1].seg_size; + ptr_cmd_buf = priv->pFfirmware.firmware_seg_container[priv->pFfirmware.firmware_seg_index-1].seg_ptr; + rtl819xU_tx_cmd(dev, ptr_cmd_buf, cmd_buf_len, last_init_packet, DESC_PACKET_TYPE_INIT); + } + + kfree(tx_cmd_urb->transfer_buffer); +#endif + usb_free_urb(tx_cmd_urb); +} + +unsigned int txqueue2outpipe(struct r8192_priv* priv,unsigned int tx_queue) { + + if(tx_queue >= 9) + { + RT_TRACE(COMP_ERR,"%s():Unknown queue ID!!!\n",__FUNCTION__); + return 0x04; + } + return priv->txqueue_to_outpipemap[tx_queue]; +} + +#ifdef RTL8192SU +short rtl8192SU_tx_cmd(struct net_device *dev, struct sk_buff *skb) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + int status; + struct urb *tx_urb; + unsigned int idx_pipe; + tx_desc_cmd_819x_usb *pdesc = (tx_desc_cmd_819x_usb *)skb->data; + cb_desc *tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE); + u8 queue_index = tcb_desc->queue_index; + u32 PktSize = 0; + + //printk("\n %s::::::::::::::::::::::queue_index = %d\n",__FUNCTION__, queue_index); + atomic_inc(&priv->tx_pending[queue_index]); + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + tx_urb = usb_alloc_urb(0,GFP_ATOMIC); +#else + tx_urb = usb_alloc_urb(0); +#endif + if(!tx_urb){ + dev_kfree_skb(skb); + return -ENOMEM; + } + + memset(pdesc, 0, USB_HWDESC_HEADER_LEN); + + /* Tx descriptor ought to be set according to the skb->cb */ + pdesc->LINIP = tcb_desc->bLastIniPkt; + PktSize = (u16)(skb->len - USB_HWDESC_HEADER_LEN); + pdesc->PktSize = PktSize; + //printk("PKTSize = %d %x\n",pdesc->PktSize,pdesc->PktSize); + //---------------------------------------------------------------------------- + // Fill up USB_OUT_CONTEXT. + //---------------------------------------------------------------------------- + // Get index to out pipe from specified QueueID. + idx_pipe = txqueue2outpipe(priv,queue_index); + //printk("=============>%s queue_index:%d, outpipe:%d\n", __func__,queue_index,priv->RtOutPipes[idx_pipe]); + +#ifdef JOHN_DUMP_TXDESC + int i; + printk("Len = %d\n", skb->len); + for (i = 0; i < 8; i++) + printk("%2.2x ", *((u8*)skb->data+i)); + printk("\n"); +#endif + + usb_fill_bulk_urb(tx_urb, + priv->udev, + usb_sndbulkpipe(priv->udev,priv->RtOutPipes[idx_pipe]), + skb->data, + skb->len, + rtl8192_tx_isr, + skb); + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + status = usb_submit_urb(tx_urb, GFP_ATOMIC); +#else + status = usb_submit_urb(tx_urb); +#endif + + if (!status){ + return 0; + }else{ + printk("Error TX CMD URB, error %d", + status); + return -1; + } +} +#else +short rtl819xU_tx_cmd(struct net_device *dev, struct sk_buff *skb) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + //u8 *tx; + int status; + struct urb *tx_urb; + //int urb_buf_len; + unsigned int idx_pipe; + tx_desc_cmd_819x_usb *pdesc = (tx_desc_cmd_819x_usb *)skb->data; + cb_desc *tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE); + u8 queue_index = tcb_desc->queue_index; + + //printk("\n %s::queue_index = %d\n",__FUNCTION__, queue_index); + atomic_inc(&priv->tx_pending[queue_index]); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + tx_urb = usb_alloc_urb(0,GFP_ATOMIC); +#else + tx_urb = usb_alloc_urb(0); +#endif + if(!tx_urb){ + dev_kfree_skb(skb); + return -ENOMEM; + } + + memset(pdesc, 0, USB_HWDESC_HEADER_LEN); + /* Tx descriptor ought to be set according to the skb->cb */ + pdesc->FirstSeg = 1;//bFirstSeg; + pdesc->LastSeg = 1;//bLastSeg; + pdesc->CmdInit = tcb_desc->bCmdOrInit; + pdesc->TxBufferSize = tcb_desc->txbuf_size; + pdesc->OWN = 1; + pdesc->LINIP = tcb_desc->bLastIniPkt; + + //---------------------------------------------------------------------------- + // Fill up USB_OUT_CONTEXT. + //---------------------------------------------------------------------------- + // Get index to out pipe from specified QueueID. +#ifndef USE_ONE_PIPE + idx_pipe = txqueue2outpipe(priv,queue_index); +#else + idx_pipe = 0x04; +#endif +#ifdef JOHN_DUMP_TXDESC + int i; + printk("--rate %x---",rate); + for (i = 0; i < 8; i++) + printk("%8x ", tx[i]); + printk("\n"); +#endif + usb_fill_bulk_urb(tx_urb,priv->udev, usb_sndbulkpipe(priv->udev,idx_pipe), \ + skb->data, skb->len, rtl8192_tx_isr, skb); + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + status = usb_submit_urb(tx_urb, GFP_ATOMIC); +#else + status = usb_submit_urb(tx_urb); +#endif + + if (!status){ + return 0; + }else{ + DMESGE("Error TX CMD URB, error %d", + status); + return -1; + } +} +#endif + +/* + * Mapping Software/Hardware descriptor queue id to "Queue Select Field" + * in TxFwInfo data structure + * 2006.10.30 by Emily + * + * \param QUEUEID Software Queue +*/ +u8 MapHwQueueToFirmwareQueue(u8 QueueID) +{ + u8 QueueSelect = 0x0; //defualt set to + + switch(QueueID) { + case BE_QUEUE: + QueueSelect = QSLT_BE; //or QSelect = pTcb->priority; + break; + + case BK_QUEUE: + QueueSelect = QSLT_BK; //or QSelect = pTcb->priority; + break; + + case VO_QUEUE: + QueueSelect = QSLT_VO; //or QSelect = pTcb->priority; + break; + + case VI_QUEUE: + QueueSelect = QSLT_VI; //or QSelect = pTcb->priority; + break; + case MGNT_QUEUE: + QueueSelect = QSLT_MGNT; + break; + + case BEACON_QUEUE: + QueueSelect = QSLT_BEACON; + break; + + // TODO: 2006.10.30 mark other queue selection until we verify it is OK + // TODO: Remove Assertions +//#if (RTL819X_FPGA_VER & RTL819X_FPGA_GUANGAN_070502) + case TXCMD_QUEUE: + QueueSelect = QSLT_CMD; + break; +//#endif + case HIGH_QUEUE: + QueueSelect = QSLT_HIGH; + break; + + default: + RT_TRACE(COMP_ERR, "TransmitTCB(): Impossible Queue Selection: %d \n", QueueID); + break; + } + return QueueSelect; +} + +#ifdef RTL8192SU +u8 MRateToHwRate8190Pci(u8 rate) +{ + u8 ret = DESC92S_RATE1M; + + switch(rate) + { + // CCK and OFDM non-HT rates + case MGN_1M: ret = DESC92S_RATE1M; break; + case MGN_2M: ret = DESC92S_RATE2M; break; + case MGN_5_5M: ret = DESC92S_RATE5_5M; break; + case MGN_11M: ret = DESC92S_RATE11M; break; + case MGN_6M: ret = DESC92S_RATE6M; break; + case MGN_9M: ret = DESC92S_RATE9M; break; + case MGN_12M: ret = DESC92S_RATE12M; break; + case MGN_18M: ret = DESC92S_RATE18M; break; + case MGN_24M: ret = DESC92S_RATE24M; break; + case MGN_36M: ret = DESC92S_RATE36M; break; + case MGN_48M: ret = DESC92S_RATE48M; break; + case MGN_54M: ret = DESC92S_RATE54M; break; + + // HT rates since here + case MGN_MCS0: ret = DESC92S_RATEMCS0; break; + case MGN_MCS1: ret = DESC92S_RATEMCS1; break; + case MGN_MCS2: ret = DESC92S_RATEMCS2; break; + case MGN_MCS3: ret = DESC92S_RATEMCS3; break; + case MGN_MCS4: ret = DESC92S_RATEMCS4; break; + case MGN_MCS5: ret = DESC92S_RATEMCS5; break; + case MGN_MCS6: ret = DESC92S_RATEMCS6; break; + case MGN_MCS7: ret = DESC92S_RATEMCS7; break; + case MGN_MCS8: ret = DESC92S_RATEMCS8; break; + case MGN_MCS9: ret = DESC92S_RATEMCS9; break; + case MGN_MCS10: ret = DESC92S_RATEMCS10; break; + case MGN_MCS11: ret = DESC92S_RATEMCS11; break; + case MGN_MCS12: ret = DESC92S_RATEMCS12; break; + case MGN_MCS13: ret = DESC92S_RATEMCS13; break; + case MGN_MCS14: ret = DESC92S_RATEMCS14; break; + case MGN_MCS15: ret = DESC92S_RATEMCS15; break; + + // Set the highest SG rate + case MGN_MCS0_SG: + case MGN_MCS1_SG: + case MGN_MCS2_SG: + case MGN_MCS3_SG: + case MGN_MCS4_SG: + case MGN_MCS5_SG: + case MGN_MCS6_SG: + case MGN_MCS7_SG: + case MGN_MCS8_SG: + case MGN_MCS9_SG: + case MGN_MCS10_SG: + case MGN_MCS11_SG: + case MGN_MCS12_SG: + case MGN_MCS13_SG: + case MGN_MCS14_SG: + case MGN_MCS15_SG: + { + ret = DESC92S_RATEMCS15_SG; + break; + } + + default: break; + } + return ret; +} +#else +u8 MRateToHwRate8190Pci(u8 rate) +{ + u8 ret = DESC90_RATE1M; + + switch(rate) { + case MGN_1M: ret = DESC90_RATE1M; break; + case MGN_2M: ret = DESC90_RATE2M; break; + case MGN_5_5M: ret = DESC90_RATE5_5M; break; + case MGN_11M: ret = DESC90_RATE11M; break; + case MGN_6M: ret = DESC90_RATE6M; break; + case MGN_9M: ret = DESC90_RATE9M; break; + case MGN_12M: ret = DESC90_RATE12M; break; + case MGN_18M: ret = DESC90_RATE18M; break; + case MGN_24M: ret = DESC90_RATE24M; break; + case MGN_36M: ret = DESC90_RATE36M; break; + case MGN_48M: ret = DESC90_RATE48M; break; + case MGN_54M: ret = DESC90_RATE54M; break; + + // HT rate since here + case MGN_MCS0: ret = DESC90_RATEMCS0; break; + case MGN_MCS1: ret = DESC90_RATEMCS1; break; + case MGN_MCS2: ret = DESC90_RATEMCS2; break; + case MGN_MCS3: ret = DESC90_RATEMCS3; break; + case MGN_MCS4: ret = DESC90_RATEMCS4; break; + case MGN_MCS5: ret = DESC90_RATEMCS5; break; + case MGN_MCS6: ret = DESC90_RATEMCS6; break; + case MGN_MCS7: ret = DESC90_RATEMCS7; break; + case MGN_MCS8: ret = DESC90_RATEMCS8; break; + case MGN_MCS9: ret = DESC90_RATEMCS9; break; + case MGN_MCS10: ret = DESC90_RATEMCS10; break; + case MGN_MCS11: ret = DESC90_RATEMCS11; break; + case MGN_MCS12: ret = DESC90_RATEMCS12; break; + case MGN_MCS13: ret = DESC90_RATEMCS13; break; + case MGN_MCS14: ret = DESC90_RATEMCS14; break; + case MGN_MCS15: ret = DESC90_RATEMCS15; break; + case (0x80|0x20): ret = DESC90_RATEMCS32; break; + + default: break; + } + return ret; +} +#endif + +u8 QueryIsShort(u8 TxHT, u8 TxRate, cb_desc *tcb_desc) +{ + u8 tmp_Short; + + tmp_Short = (TxHT==1)?((tcb_desc->bUseShortGI)?1:0):((tcb_desc->bUseShortPreamble)?1:0); + + if(TxHT==1 && TxRate != DESC90_RATEMCS15) + tmp_Short = 0; + + return tmp_Short; +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) +static void tx_zero_isr(struct urb *tx_urb, struct pt_regs *reg) +#else +static void tx_zero_isr(struct urb *tx_urb) +#endif +{ + return; +} + + +#ifdef RTL8192SU +/* + * The tx procedure is just as following, skb->cb will contain all the following + *information: * priority, morefrag, rate, &dev. + * */ + // Buffer format for 8192S Usb bulk out: +// +// -------------------------------------------------- +// | 8192S Usb Tx Desc | 802_11_MAC_header | data | +// -------------------------------------------------- +// | 32 bytes | 24 bytes |0-2318 bytes| +// -------------------------------------------------- +// |<------------ BufferLen ------------------------->| + +short rtl8192SU_tx(struct net_device *dev, struct sk_buff* skb) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + cb_desc *tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE); + tx_desc_819x_usb *tx_desc = (tx_desc_819x_usb *)skb->data; + //tx_fwinfo_819x_usb *tx_fwinfo = (tx_fwinfo_819x_usb *)(skb->data + USB_HWDESC_HEADER_LEN);//92su del + struct usb_device *udev = priv->udev; + int pend; + int status; + struct urb *tx_urb = NULL, *tx_urb_zero = NULL; + //int urb_len; + unsigned int idx_pipe; + u16 MPDUOverhead = 0; + //RT_DEBUG_DATA(COMP_SEND, tcb_desc, sizeof(cb_desc)); + +#if 0 + /* Added by Annie for filling Len_Adjust field. 2005-12-14. */ + RT_ENC_ALG EncAlg = NO_Encryption; +#endif + + + pend = atomic_read(&priv->tx_pending[tcb_desc->queue_index]); + /* we are locked here so the two atomic_read and inc are executed + * without interleaves * !!! For debug purpose */ + if( pend > MAX_TX_URB){ + switch (tcb_desc->queue_index) { + case VO_PRIORITY: + priv->stats.txvodrop++; + break; + case VI_PRIORITY: + priv->stats.txvidrop++; + break; + case BE_PRIORITY: + priv->stats.txbedrop++; + break; + default://BK_PRIORITY + priv->stats.txbkdrop++; + break; + } + printk("To discard skb packet!\n"); + dev_kfree_skb_any(skb); + return -1; + } + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + tx_urb = usb_alloc_urb(0,GFP_ATOMIC); +#else + tx_urb = usb_alloc_urb(0); +#endif + if(!tx_urb){ + dev_kfree_skb_any(skb); + return -ENOMEM; + } + + memset(tx_desc, 0, sizeof(tx_desc_819x_usb)); + + +#if RTL8192SU_FPGA_UNSPECIFIED_NETWORK + if(IsQoSDataFrame(skb->data)) + { + tcb_desc->bAMPDUEnable = TRUE; + tx_desc->NonQos = 0; + } + else + tcb_desc->bAMPDUEnable = FALSE; + + tcb_desc->bPacketBW = TRUE; + priv->CurrentChannelBW = HT_CHANNEL_WIDTH_20_40; +#endif + +#if (defined (RTL8192SU_FPGA_2MAC_VERIFICATION)||defined (RTL8192SU_ASIC_VERIFICATION)) + tx_desc->NonQos = (IsQoSDataFrame(skb->data)==TRUE)? 0:1; +#endif + + /* Fill Tx descriptor */ + //memset(tx_fwinfo,0,sizeof(tx_fwinfo_819x_usb)); + + // This part can just fill to the first descriptor of the frame. + /* DWORD 0 */ + tx_desc->TxHT = (tcb_desc->data_rate&0x80)?1:0; + +#ifdef RTL8192SU_DISABLE_CCK_RATE + if(tx_hal_is_cck_rate(tcb_desc->data_rate)) + tcb_desc->data_rate = MGN_6M; +#endif + + tx_desc->TxRate = MRateToHwRate8190Pci(tcb_desc->data_rate); + //tx_desc->EnableCPUDur = tcb_desc->bTxEnableFwCalcDur; + tx_desc->TxShort = QueryIsShort(tx_desc->TxHT, tx_desc->TxRate, tcb_desc); + + + // Aggregation related + if(tcb_desc->bAMPDUEnable) {//AMPDU enabled + tx_desc->AllowAggregation = 1; + /* DWORD 1 */ + //tx_fwinfo->RxMF = tcb_desc->ampdu_factor; + //tx_fwinfo->RxAMD = tcb_desc->ampdu_density&0x07;//ampdudensity + } else { + tx_desc->AllowAggregation = 0; + /* DWORD 1 */ + //tx_fwinfo->RxMF = 0; + //tx_fwinfo->RxAMD = 0; + } + + // + // For AMPDU case, we must insert SSN into TX_DESC, + // FW according as this SSN to do necessary packet retry. + // 2008.06.06. + // + { + u8 *pSeq; + u16 Temp; + //pSeq = (u8 *)(VirtualAddress+USB_HWDESC_HEADER_LEN + FRAME_OFFSET_SEQUENCE); + pSeq = (u8 *)(skb->data+USB_HWDESC_HEADER_LEN + 22); + Temp = pSeq[0]; + Temp <<= 12; + Temp |= (*(u16 *)pSeq)>>4; + tx_desc->Seq = Temp; + } + + /* Protection mode related */ + tx_desc->RTSEn = (tcb_desc->bRTSEnable)?1:0; + tx_desc->CTS2Self = (tcb_desc->bCTSEnable)?1:0; + tx_desc->RTSSTBC = (tcb_desc->bRTSSTBC)?1:0; + tx_desc->RTSHT = (tcb_desc->rts_rate&0x80)?1:0; + tx_desc->RTSRate = MRateToHwRate8190Pci((u8)tcb_desc->rts_rate); + tx_desc->RTSSubcarrier = (tx_desc->RTSHT==0)?(tcb_desc->RTSSC):0; + tx_desc->RTSBW = (tx_desc->RTSHT==1)?((tcb_desc->bRTSBW)?1:0):0; + tx_desc->RTSShort = (tx_desc->RTSHT==0)?(tcb_desc->bRTSUseShortPreamble?1:0):\ + (tcb_desc->bRTSUseShortGI?1:0); + //LZM 090219 + tx_desc->DisRTSFB = 0; + tx_desc->RTSRateFBLmt = 0xf; + + // 2008.09.22. We disable RTS rate fallback temporarily. + //tx_desc->DisRTSFB = 0x01; + + /* Set Bandwidth and sub-channel settings. */ + if(priv->CurrentChannelBW == HT_CHANNEL_WIDTH_20_40) + { + if(tcb_desc->bPacketBW) { + tx_desc->TxBandwidth = 1; + tx_desc->TxSubCarrier = 0; //By SD3's Jerry suggestion, use duplicated mode + } else { + tx_desc->TxBandwidth = 0; + tx_desc->TxSubCarrier = priv->nCur40MhzPrimeSC; + } + } else { + tx_desc->TxBandwidth = 0; + tx_desc->TxSubCarrier = 0; + } + +#ifdef USB_TX_DRIVER_AGGREGATION_ENABLE + if (tcb_desc->drv_agg_enable) + { + //tx_desc->Tx_INFO_RSVD = (tcb_desc->DrvAggrNum & 0x1f) << 1; //92su del + } +#endif + + //memset(tx_desc, 0, sizeof(tx_desc_819x_usb)); + /* DWORD 0 */ + tx_desc->LINIP = 0; + //tx_desc->CmdInit = 1; //92su del + tx_desc->Offset = USB_HWDESC_HEADER_LEN; + +#ifdef USB_TX_DRIVER_AGGREGATION_ENABLE + if (tcb_desc->drv_agg_enable) { + tx_desc->PktSize = tcb_desc->pkt_size;//FIXLZM + } else +#endif + { + tx_desc->PktSize = (skb->len - USB_HWDESC_HEADER_LEN) & 0xffff; + } + + /*DWORD 1*/ + //tx_desc->SecCAMID= 0;//92su del + tx_desc->RaBRSRID= tcb_desc->RATRIndex; +//#ifdef RTL8192S_PREPARE_FOR_NORMAL_RELEASE +#if 0//LZM 090219 + tx_desc->RaBRSRID= 1; +#endif + +#if 0 + /* Fill security related */ + if( pTcb->bEncrypt && !Adapter->MgntInfo.SecurityInfo.SWTxEncryptFlag) + { + EncAlg = SecGetEncryptionOverhead( + Adapter, + &EncryptionMPDUHeadOverhead, + &EncryptionMPDUTailOverhead, + NULL, + NULL, + FALSE, + FALSE); + //2004/07/22, kcwu, EncryptionMPDUHeadOverhead has been added in previous code + //MPDUOverhead = EncryptionMPDUHeadOverhead + EncryptionMPDUTailOverhead; + MPDUOverhead = EncryptionMPDUTailOverhead; + tx_desc->NoEnc = 0; + RT_TRACE(COMP_SEC, DBG_LOUD, ("******We in the loop SecCAMID is %d SecDescAssign is %d The Sec is %d********\n",tx_desc->SecCAMID,tx_desc->SecDescAssign,EncAlg)); + //CamDumpAll(Adapter); + } + else +#endif + { + MPDUOverhead = 0; + //tx_desc->NoEnc = 1;//92su del + } +#if 0 + switch(EncAlg){ + case NO_Encryption: + tx_desc->SecType = 0x0; + break; + case WEP40_Encryption: + case WEP104_Encryption: + tx_desc->SecType = 0x1; + break; + case TKIP_Encryption: + tx_desc->SecType = 0x2; + break; + case AESCCMP_Encryption: + tx_desc->SecType = 0x3; + break; + default: + tx_desc->SecType = 0x0; + break; + } +#else + tx_desc->SecType = 0x0; +#endif + if (tcb_desc->bHwSec) + { + switch (priv->ieee80211->pairwise_key_type) + { + case KEY_TYPE_WEP40: + case KEY_TYPE_WEP104: + tx_desc->SecType = 0x1; + //tx_desc->NoEnc = 0;//92su del + break; + case KEY_TYPE_TKIP: + tx_desc->SecType = 0x2; + //tx_desc->NoEnc = 0;//92su del + break; + case KEY_TYPE_CCMP: + tx_desc->SecType = 0x3; + //tx_desc->NoEnc = 0;//92su del + break; + case KEY_TYPE_NA: + tx_desc->SecType = 0x0; + //tx_desc->NoEnc = 1;//92su del + break; + default: + tx_desc->SecType = 0x0; + //tx_desc->NoEnc = 1;//92su del + break; + } + } + + //tx_desc->TxFWInfoSize = sizeof(tx_fwinfo_819x_usb);//92su del + + + tx_desc->USERATE = tcb_desc->bTxUseDriverAssingedRate; + tx_desc->DISFB = tcb_desc->bTxDisableRateFallBack; + tx_desc->DataRateFBLmt = 0x1F;// Alwasy enable all rate fallback range + + tx_desc->QueueSelect = MapHwQueueToFirmwareQueue(tcb_desc->queue_index); + + + /* Fill fields that are required to be initialized in all of the descriptors */ + //DWORD 0 +#if 0 + tx_desc->FirstSeg = (tcb_desc->bFirstSeg)? 1:0; + tx_desc->LastSeg = (tcb_desc->bLastSeg)?1:0; +#else + tx_desc->FirstSeg = 1; + tx_desc->LastSeg = 1; +#endif + tx_desc->OWN = 1; + +#ifdef USB_TX_DRIVER_AGGREGATION_ENABLE + if (tcb_desc->drv_agg_enable) { + tx_desc->TxBufferSize = tcb_desc->pkt_size + sizeof(tx_fwinfo_819x_usb); + } else +#endif + { + //DWORD 2 + //tx_desc->TxBufferSize = (u32)(skb->len - USB_HWDESC_HEADER_LEN); + tx_desc->TxBufferSize = (u32)(skb->len);//92su mod FIXLZM + } + +#if 0 + RT_TRACE(COMP_FPGA, DBG_LOUD, ("(1)TxFillDescriptor8192SUsb(): DataRate(%#x)\n", pTcb->DataRate)); + RT_TRACE(COMP_FPGA, DBG_LOUD, ("(2)TxFillDescriptor8192SUsb(): bTxUseDriverAssingedRate(%#x)\n", pTcb->bTxUseDriverAssingedRate)); + RT_TRACE(COMP_FPGA, DBG_LOUD, ("(3)TxFillDescriptor8192SUsb(): bAMPDUEnable(%d)\n", pTcb->bAMPDUEnable)); + RT_TRACE(COMP_FPGA, DBG_LOUD, ("(4)TxFillDescriptor8192SUsb(): bRTSEnable(%d)\n", pTcb->bRTSEnable)); + RT_TRACE(COMP_FPGA, DBG_LOUD, ("(5)TxFillDescriptor8192SUsb(): RTSRate(%#x)\n", pTcb->RTSRate)); + RT_TRACE(COMP_FPGA, DBG_LOUD, ("(6)TxFillDescriptor8192SUsb(): bCTSEnable(%d)\n", pTcb->bCTSEnable)); + RT_TRACE(COMP_FPGA, DBG_LOUD, ("(7)TxFillDescriptor8192SUsb(): bUseShortGI(%d)\n", pTcb->bUseShortGI)); + RT_TRACE(COMP_FPGA, DBG_LOUD, ("(8)TxFillDescriptor8192SUsb(): bPacketBW(%d)\n", pTcb->bPacketBW)); + RT_TRACE(COMP_FPGA, DBG_LOUD, ("(9)TxFillDescriptor8192SUsb(): CurrentChannelBW(%d)\n", pHalData->CurrentChannelBW)); + RT_TRACE(COMP_FPGA, DBG_LOUD, ("(10)TxFillDescriptor8192SUsb(): bTxDisableRateFallBack(%d)\n", pTcb->bTxDisableRateFallBack)); + RT_TRACE(COMP_FPGA, DBG_LOUD, ("(11)TxFillDescriptor8192SUsb(): RATRIndex(%d)\n", pTcb->RATRIndex)); +#endif + + /* Get index to out pipe from specified QueueID */ + idx_pipe = txqueue2outpipe(priv,tcb_desc->queue_index); + //printk("=============>%s queue_index:%d, outpipe:%d\n", __func__,tcb_desc->queue_index,priv->RtOutPipes[idx_pipe]); + + //RT_DEBUG_DATA(COMP_SEND,tx_fwinfo,sizeof(tx_fwinfo_819x_usb)); + //RT_DEBUG_DATA(COMP_SEND,tx_desc,sizeof(tx_desc_819x_usb)); + + /* To submit bulk urb */ + usb_fill_bulk_urb(tx_urb, + udev, + usb_sndbulkpipe(udev,priv->RtOutPipes[idx_pipe]), + skb->data, + skb->len, rtl8192_tx_isr, skb); + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + status = usb_submit_urb(tx_urb, GFP_ATOMIC); +#else + status = usb_submit_urb(tx_urb); +#endif + if (!status){ +//we need to send 0 byte packet whenever 512N bytes/64N(HIGN SPEED/NORMAL SPEED) bytes packet has been transmitted. Otherwise, it will be halt to wait for another packet. WB. 2008.08.27 + bool bSend0Byte = false; + u8 zero = 0; + if(udev->speed == USB_SPEED_HIGH) + { + if (skb->len > 0 && skb->len % 512 == 0) + bSend0Byte = true; + } + else + { + if (skb->len > 0 && skb->len % 64 == 0) + bSend0Byte = true; + } + if (bSend0Byte) + { +#if 1 +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + tx_urb_zero = usb_alloc_urb(0,GFP_ATOMIC); +#else + tx_urb_zero = usb_alloc_urb(0); +#endif + if(!tx_urb_zero){ + RT_TRACE(COMP_ERR, "can't alloc urb for zero byte\n"); + return -ENOMEM; + } + usb_fill_bulk_urb(tx_urb_zero,udev, + usb_sndbulkpipe(udev,idx_pipe), &zero, + 0, tx_zero_isr, dev); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + status = usb_submit_urb(tx_urb_zero, GFP_ATOMIC); +#else + status = usb_submit_urb(tx_urb_zero); +#endif + if (status){ + RT_TRACE(COMP_ERR, "Error TX URB for zero byte %d, error %d", atomic_read(&priv->tx_pending[tcb_desc->queue_index]), status); + return -1; + } +#endif + } + dev->trans_start = jiffies; + atomic_inc(&priv->tx_pending[tcb_desc->queue_index]); + return 0; + }else{ + RT_TRACE(COMP_ERR, "Error TX URB %d, error %d", atomic_read(&priv->tx_pending[tcb_desc->queue_index]), + status); + return -1; + } +} +#else + +/* + * The tx procedure is just as following, + * skb->cb will contain all the following information, + * priority, morefrag, rate, &dev. + * */ +short rtl8192_tx(struct net_device *dev, struct sk_buff* skb) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + cb_desc *tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE); + tx_desc_819x_usb *tx_desc = (tx_desc_819x_usb *)skb->data; + tx_fwinfo_819x_usb *tx_fwinfo = (tx_fwinfo_819x_usb *)(skb->data + USB_HWDESC_HEADER_LEN); + struct usb_device *udev = priv->udev; + int pend; + int status; + struct urb *tx_urb = NULL, *tx_urb_zero = NULL; + //int urb_len; + unsigned int idx_pipe; +// RT_DEBUG_DATA(COMP_SEND, tcb_desc, sizeof(cb_desc)); +#if 0 + /* Added by Annie for filling Len_Adjust field. 2005-12-14. */ + RT_ENC_ALG EncAlg = NO_Encryption; +#endif +// printk("=============> %s\n", __FUNCTION__); + pend = atomic_read(&priv->tx_pending[tcb_desc->queue_index]); + /* we are locked here so the two atomic_read and inc are executed + * without interleaves + * !!! For debug purpose + */ + if( pend > MAX_TX_URB){ +#if 0 + switch (tcb_desc->queue_index) { + case VO_PRIORITY: + priv->stats.txvodrop++; + break; + case VI_PRIORITY: + priv->stats.txvidrop++; + break; + case BE_PRIORITY: + priv->stats.txbedrop++; + break; + default://BK_PRIORITY + priv->stats.txbkdrop++; + break; + } +#endif + printk("To discard skb packet!\n"); + dev_kfree_skb_any(skb); + return -1; + } + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + tx_urb = usb_alloc_urb(0,GFP_ATOMIC); +#else + tx_urb = usb_alloc_urb(0); +#endif + if(!tx_urb){ + dev_kfree_skb_any(skb); + return -ENOMEM; + } + + /* Fill Tx firmware info */ + memset(tx_fwinfo,0,sizeof(tx_fwinfo_819x_usb)); + /* DWORD 0 */ + tx_fwinfo->TxHT = (tcb_desc->data_rate&0x80)?1:0; + tx_fwinfo->TxRate = MRateToHwRate8190Pci(tcb_desc->data_rate); + tx_fwinfo->EnableCPUDur = tcb_desc->bTxEnableFwCalcDur; + tx_fwinfo->Short = QueryIsShort(tx_fwinfo->TxHT, tx_fwinfo->TxRate, tcb_desc); + if(tcb_desc->bAMPDUEnable) {//AMPDU enabled + tx_fwinfo->AllowAggregation = 1; + /* DWORD 1 */ + tx_fwinfo->RxMF = tcb_desc->ampdu_factor; + tx_fwinfo->RxAMD = tcb_desc->ampdu_density&0x07;//ampdudensity + } else { + tx_fwinfo->AllowAggregation = 0; + /* DWORD 1 */ + tx_fwinfo->RxMF = 0; + tx_fwinfo->RxAMD = 0; + } + + /* Protection mode related */ + tx_fwinfo->RtsEnable = (tcb_desc->bRTSEnable)?1:0; + tx_fwinfo->CtsEnable = (tcb_desc->bCTSEnable)?1:0; + tx_fwinfo->RtsSTBC = (tcb_desc->bRTSSTBC)?1:0; + tx_fwinfo->RtsHT = (tcb_desc->rts_rate&0x80)?1:0; + tx_fwinfo->RtsRate = MRateToHwRate8190Pci((u8)tcb_desc->rts_rate); + tx_fwinfo->RtsSubcarrier = (tx_fwinfo->RtsHT==0)?(tcb_desc->RTSSC):0; + tx_fwinfo->RtsBandwidth = (tx_fwinfo->RtsHT==1)?((tcb_desc->bRTSBW)?1:0):0; + tx_fwinfo->RtsShort = (tx_fwinfo->RtsHT==0)?(tcb_desc->bRTSUseShortPreamble?1:0):\ + (tcb_desc->bRTSUseShortGI?1:0); + + /* Set Bandwidth and sub-channel settings. */ + if(priv->CurrentChannelBW == HT_CHANNEL_WIDTH_20_40) + { + if(tcb_desc->bPacketBW) { + tx_fwinfo->TxBandwidth = 1; + tx_fwinfo->TxSubCarrier = 0; //By SD3's Jerry suggestion, use duplicated mode + } else { + tx_fwinfo->TxBandwidth = 0; + tx_fwinfo->TxSubCarrier = priv->nCur40MhzPrimeSC; + } + } else { + tx_fwinfo->TxBandwidth = 0; + tx_fwinfo->TxSubCarrier = 0; + } + +#ifdef USB_TX_DRIVER_AGGREGATION_ENABLE + if (tcb_desc->drv_agg_enable) + { + tx_fwinfo->Tx_INFO_RSVD = (tcb_desc->DrvAggrNum & 0x1f) << 1; + } +#endif + /* Fill Tx descriptor */ + memset(tx_desc, 0, sizeof(tx_desc_819x_usb)); + /* DWORD 0 */ + tx_desc->LINIP = 0; + tx_desc->CmdInit = 1; + tx_desc->Offset = sizeof(tx_fwinfo_819x_usb) + 8; + +#ifdef USB_TX_DRIVER_AGGREGATION_ENABLE + if (tcb_desc->drv_agg_enable) { + tx_desc->PktSize = tcb_desc->pkt_size; + } else +#endif + { + tx_desc->PktSize = (skb->len - TX_PACKET_SHIFT_BYTES) & 0xffff; + } + + /*DWORD 1*/ + tx_desc->SecCAMID= 0; + tx_desc->RATid = tcb_desc->RATRIndex; +#if 0 + /* Fill security related */ + if( pTcb->bEncrypt && !Adapter->MgntInfo.SecurityInfo.SWTxEncryptFlag) + { + EncAlg = SecGetEncryptionOverhead( + Adapter, + &EncryptionMPDUHeadOverhead, + &EncryptionMPDUTailOverhead, + NULL, + NULL, + FALSE, + FALSE); + //2004/07/22, kcwu, EncryptionMPDUHeadOverhead has been added in previous code + //MPDUOverhead = EncryptionMPDUHeadOverhead + EncryptionMPDUTailOverhead; + MPDUOverhead = EncryptionMPDUTailOverhead; + tx_desc->NoEnc = 0; + RT_TRACE(COMP_SEC, DBG_LOUD, ("******We in the loop SecCAMID is %d SecDescAssign is %d The Sec is %d********\n",tx_desc->SecCAMID,tx_desc->SecDescAssign,EncAlg)); + //CamDumpAll(Adapter); + } + else +#endif + { + //MPDUOverhead = 0; + tx_desc->NoEnc = 1; + } +#if 0 + switch(EncAlg){ + case NO_Encryption: + tx_desc->SecType = 0x0; + break; + case WEP40_Encryption: + case WEP104_Encryption: + tx_desc->SecType = 0x1; + break; + case TKIP_Encryption: + tx_desc->SecType = 0x2; + break; + case AESCCMP_Encryption: + tx_desc->SecType = 0x3; + break; + default: + tx_desc->SecType = 0x0; + break; + } +#else + tx_desc->SecType = 0x0; +#endif + if (tcb_desc->bHwSec) + { + switch (priv->ieee80211->pairwise_key_type) + { + case KEY_TYPE_WEP40: + case KEY_TYPE_WEP104: + tx_desc->SecType = 0x1; + tx_desc->NoEnc = 0; + break; + case KEY_TYPE_TKIP: + tx_desc->SecType = 0x2; + tx_desc->NoEnc = 0; + break; + case KEY_TYPE_CCMP: + tx_desc->SecType = 0x3; + tx_desc->NoEnc = 0; + break; + case KEY_TYPE_NA: + tx_desc->SecType = 0x0; + tx_desc->NoEnc = 1; + break; + } + } + + tx_desc->QueueSelect = MapHwQueueToFirmwareQueue(tcb_desc->queue_index); + tx_desc->TxFWInfoSize = sizeof(tx_fwinfo_819x_usb); + + tx_desc->DISFB = tcb_desc->bTxDisableRateFallBack; + tx_desc->USERATE = tcb_desc->bTxUseDriverAssingedRate; + + /* Fill fields that are required to be initialized in all of the descriptors */ + //DWORD 0 +#if 0 + tx_desc->FirstSeg = (tcb_desc->bFirstSeg)? 1:0; + tx_desc->LastSeg = (tcb_desc->bLastSeg)?1:0; +#else + tx_desc->FirstSeg = 1; + tx_desc->LastSeg = 1; +#endif + tx_desc->OWN = 1; + +#ifdef USB_TX_DRIVER_AGGREGATION_ENABLE + if (tcb_desc->drv_agg_enable) { + tx_desc->TxBufferSize = tcb_desc->pkt_size + sizeof(tx_fwinfo_819x_usb); + } else +#endif + { + //DWORD 2 + tx_desc->TxBufferSize = (u32)(skb->len - USB_HWDESC_HEADER_LEN); + } + /* Get index to out pipe from specified QueueID */ +#ifndef USE_ONE_PIPE + idx_pipe = txqueue2outpipe(priv,tcb_desc->queue_index); +#else + idx_pipe = 0x5; +#endif + + //RT_DEBUG_DATA(COMP_SEND,tx_fwinfo,sizeof(tx_fwinfo_819x_usb)); + //RT_DEBUG_DATA(COMP_SEND,tx_desc,sizeof(tx_desc_819x_usb)); + + /* To submit bulk urb */ + usb_fill_bulk_urb(tx_urb,udev, + usb_sndbulkpipe(udev,idx_pipe), skb->data, + skb->len, rtl8192_tx_isr, skb); + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + status = usb_submit_urb(tx_urb, GFP_ATOMIC); +#else + status = usb_submit_urb(tx_urb); +#endif + if (!status){ +//we need to send 0 byte packet whenever 512N bytes/64N(HIGN SPEED/NORMAL SPEED) bytes packet has been transmitted. Otherwise, it will be halt to wait for another packet. WB. 2008.08.27 + bool bSend0Byte = false; + u8 zero = 0; + if(udev->speed == USB_SPEED_HIGH) + { + if (skb->len > 0 && skb->len % 512 == 0) + bSend0Byte = true; + } + else + { + if (skb->len > 0 && skb->len % 64 == 0) + bSend0Byte = true; + } + if (bSend0Byte) + { +#if 1 +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + tx_urb_zero = usb_alloc_urb(0,GFP_ATOMIC); +#else + tx_urb_zero = usb_alloc_urb(0); +#endif + if(!tx_urb_zero){ + RT_TRACE(COMP_ERR, "can't alloc urb for zero byte\n"); + return -ENOMEM; + } + usb_fill_bulk_urb(tx_urb_zero,udev, + usb_sndbulkpipe(udev,idx_pipe), &zero, + 0, tx_zero_isr, dev); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + status = usb_submit_urb(tx_urb_zero, GFP_ATOMIC); +#else + status = usb_submit_urb(tx_urb_zero); +#endif + if (status){ + RT_TRACE(COMP_ERR, "Error TX URB for zero byte %d, error %d", atomic_read(&priv->tx_pending[tcb_desc->queue_index]), status); + return -1; + } +#endif + } + dev->trans_start = jiffies; + atomic_inc(&priv->tx_pending[tcb_desc->queue_index]); + return 0; + }else{ + RT_TRACE(COMP_ERR, "Error TX URB %d, error %d", atomic_read(&priv->tx_pending[tcb_desc->queue_index]), + status); + return -1; + } +} +#endif + +#if 0 +void rtl8192_set_rate(struct net_device *dev) +{ + int i; + u16 word; + int basic_rate,min_rr_rate,max_rr_rate; + +// struct r8192_priv *priv = ieee80211_priv(dev); + + //if (ieee80211_is_54g(priv->ieee80211->current_network) && +// priv->ieee80211->state == IEEE80211_LINKED){ + basic_rate = ieeerate2rtlrate(240); + min_rr_rate = ieeerate2rtlrate(60); + max_rr_rate = ieeerate2rtlrate(240); + +// +// }else{ +// basic_rate = ieeerate2rtlrate(20); +// min_rr_rate = ieeerate2rtlrate(10); +// max_rr_rate = ieeerate2rtlrate(110); +// } + + write_nic_byte(dev, RESP_RATE, + max_rr_rate<ieee80211; + struct ieee80211_network *net = &priv->ieee80211->current_network; + //u16 BcnTimeCfg = 0, BcnCW = 6, BcnIFS = 0xf; + u16 rate_config = 0; + u32 regTmp = 0; + u8 rateIndex = 0; + u8 retrylimit = 0x30; + u16 cap = net->capability; + + priv->short_preamble = cap & WLAN_CAPABILITY_SHORT_PREAMBLE; + +//HW_VAR_BASIC_RATE + //update Basic rate: RR, BRSR + rtl8192_config_rate(dev, &rate_config); //HalSetBrateCfg + +#ifdef RTL8192SU_DISABLE_CCK_RATE + priv->basic_rate = rate_config = rate_config & 0x150; // Disable CCK 11M, 5.5M, 2M, and 1M rates. +#else + priv->basic_rate = rate_config = rate_config & 0x15f; +#endif + + // Set RRSR rate table. + write_nic_byte(dev, RRSR, rate_config&0xff); + write_nic_byte(dev, RRSR+1, (rate_config>>8)&0xff); + + // Set RTS initial rate + while(rate_config > 0x1) + { + rate_config = (rate_config>> 1); + rateIndex++; + } + write_nic_byte(dev, INIRTSMCS_SEL, rateIndex); +//HW_VAR_BASIC_RATE + + //set ack preample + regTmp = (priv->nCur40MhzPrimeSC) << 5; + if (priv->short_preamble) + regTmp |= 0x80; + write_nic_byte(dev, RRSR+2, regTmp); + + write_nic_dword(dev,BSSIDR,((u32*)net->bssid)[0]); + write_nic_word(dev,BSSIDR+4,((u16*)net->bssid)[2]); + + write_nic_word(dev, BCN_INTERVAL, net->beacon_interval); + //2008.10.24 added by tynli for beacon changed. + PHY_SetBeaconHwReg( dev, net->beacon_interval); + + rtl8192_update_cap(dev, cap); + + if (ieee->iw_mode == IW_MODE_ADHOC){ + retrylimit = 7; + //we should enable ibss interrupt here, but disable it temporarily + if (0){ + priv->irq_mask |= (IMR_BcnInt | IMR_BcnInt | IMR_TBDOK | IMR_TBDER); + //rtl8192_irq_disable(dev); + //rtl8192_irq_enable(dev); + } + } + else{ + if (0){ + priv->irq_mask &= ~(IMR_BcnInt | IMR_BcnInt | IMR_TBDOK | IMR_TBDER); + //rtl8192_irq_disable(dev); + //rtl8192_irq_enable(dev); + } + } + + priv->ShortRetryLimit = priv->LongRetryLimit = retrylimit; + + write_nic_word(dev, RETRY_LIMIT, + retrylimit << RETRY_LIMIT_SHORT_SHIFT | \ + retrylimit << RETRY_LIMIT_LONG_SHIFT); +} + +void rtl8192SU_update_ratr_table(struct net_device* dev) +{ + struct r8192_priv* priv = ieee80211_priv(dev); + struct ieee80211_device* ieee = priv->ieee80211; + u8* pMcsRate = ieee->dot11HTOperationalRateSet; + //struct ieee80211_network *net = &ieee->current_network; + u32 ratr_value = 0; + + u8 rate_index = 0; + int WirelessMode = ieee->mode; + u8 MimoPs = ieee->pHTInfo->PeerMimoPs; + + u8 bNMode = 0; + + rtl8192_config_rate(dev, (u16*)(&ratr_value)); + ratr_value |= (*(u16*)(pMcsRate)) << 12; + + //switch (ieee->mode) + switch (WirelessMode) + { + case IEEE_A: + ratr_value &= 0x00000FF0; + break; + case IEEE_B: + ratr_value &= 0x0000000D; + break; + case IEEE_G: + ratr_value &= 0x00000FF5; + break; + case IEEE_N_24G: + case IEEE_N_5G: + { + bNMode = 1; + + if (MimoPs == 0) //MIMO_PS_STATIC + { + ratr_value &= 0x0007F005; + } + else + { // MCS rate only => for 11N mode. + u32 ratr_mask; + + // 1T2R or 1T1R, Spatial Stream 2 should be disabled + if ( priv->rf_type == RF_1T2R || + priv->rf_type == RF_1T1R || + (ieee->pHTInfo->IOTAction & HT_IOT_ACT_DISABLE_TX_2SS) ) + ratr_mask = 0x000ff005; + else + ratr_mask = 0x0f0ff005; + + if((ieee->pHTInfo->bCurTxBW40MHz) && + !(ieee->pHTInfo->IOTAction & HT_IOT_ACT_DISABLE_TX_40_MHZ)) + ratr_mask |= 0x00000010; // Set 6MBps + + // Select rates for rate adaptive mechanism. + ratr_value &= ratr_mask; + } + } + break; + default: + if(0) + { + if(priv->rf_type == RF_1T2R) // 1T2R, Spatial Stream 2 should be disabled + { + ratr_value &= 0x000ff0f5; + } + else + { + ratr_value &= 0x0f0ff0f5; + } + } + //printk("====>%s(), mode is not correct:%x\n", __FUNCTION__, ieee->mode); + break; + } + +#ifdef RTL8192SU_DISABLE_CCK_RATE + ratr_value &= 0x0FFFFFF0; +#else + ratr_value &= 0x0FFFFFFF; +#endif + + // Get MAX MCS available. + if ( (bNMode && ((ieee->pHTInfo->IOTAction & HT_IOT_ACT_DISABLE_SHORT_GI)==0)) && + ((ieee->pHTInfo->bCurBW40MHz && ieee->pHTInfo->bCurShortGI40MHz) || + (!ieee->pHTInfo->bCurBW40MHz && ieee->pHTInfo->bCurShortGI20MHz))) + { + u8 shortGI_rate = 0; + u32 tmp_ratr_value = 0; + ratr_value |= 0x10000000;//??? + tmp_ratr_value = (ratr_value>>12); + for(shortGI_rate=15; shortGI_rate>0; shortGI_rate--) + { + if((1<SG_RATE:%x\n", read_nic_byte(dev, SG_RATE)); + } + write_nic_dword(dev, ARFR0+rate_index*4, ratr_value); + printk("=============>ARFR0+rate_index*4:%#x\n", ratr_value); + + //2 UFWP + if (ratr_value & 0xfffff000){ + //printk("===>set to N mode\n"); + HalSetFwCmd8192S(dev, FW_CMD_RA_REFRESH_N); + } + else { + //printk("===>set to B/G mode\n"); + HalSetFwCmd8192S(dev, FW_CMD_RA_REFRESH_BG); + } +} + +void rtl8192SU_link_change(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + struct ieee80211_device* ieee = priv->ieee80211; + //unsigned long flags; + u32 reg = 0; + + printk("=====>%s 1\n", __func__); + reg = read_nic_dword(dev, RCR); + + if (ieee->state == IEEE80211_LINKED) + { + + rtl8192SU_net_update(dev); + rtl8192SU_update_ratr_table(dev); + ieee->SetFwCmdHandler(dev, FW_CMD_HIGH_PWR_ENABLE); + priv->ReceiveConfig = reg |= RCR_CBSSID; + + }else{ + priv->ReceiveConfig = reg &= ~RCR_CBSSID; + + } + + write_nic_dword(dev, RCR, reg); + rtl8192_update_msr(dev); + + printk("<=====%s 2\n", __func__); +} +#else +extern void rtl8192_update_ratr_table(struct net_device* dev); +void rtl8192_link_change(struct net_device *dev) +{ +// int i; + + struct r8192_priv *priv = ieee80211_priv(dev); + struct ieee80211_device* ieee = priv->ieee80211; + //write_nic_word(dev, BCN_INTR_ITV, net->beacon_interval); + if (ieee->state == IEEE80211_LINKED) + { + rtl8192_net_update(dev); + rtl8192_update_ratr_table(dev); +#if 1 + //add this as in pure N mode, wep encryption will use software way, but there is no chance to set this as wep will not set group key in wext. WB.2008.07.08 + if ((KEY_TYPE_WEP40 == ieee->pairwise_key_type) || (KEY_TYPE_WEP104 == ieee->pairwise_key_type)) + EnableHWSecurityConfig8192(dev); +#endif + } + /*update timing params*/ +// RT_TRACE(COMP_CH, "========>%s(), chan:%d\n", __FUNCTION__, priv->chan); +// rtl8192_set_chan(dev, priv->chan); + if (ieee->iw_mode == IW_MODE_INFRA || ieee->iw_mode == IW_MODE_ADHOC) + { + u32 reg = 0; + reg = read_nic_dword(dev, RCR); + if (priv->ieee80211->state == IEEE80211_LINKED) + priv->ReceiveConfig = reg |= RCR_CBSSID; + else + priv->ReceiveConfig = reg &= ~RCR_CBSSID; + write_nic_dword(dev, RCR, reg); + } + +// rtl8192_set_rxconf(dev); +} +#endif + +static struct ieee80211_qos_parameters def_qos_parameters = { + {3,3,3,3},/* cw_min */ + {7,7,7,7},/* cw_max */ + {2,2,2,2},/* aifs */ + {0,0,0,0},/* flags */ + {0,0,0,0} /* tx_op_limit */ +}; + + +#if LINUX_VERSION_CODE >=KERNEL_VERSION(2,6,20) +void rtl8192_update_beacon(struct work_struct * work) +{ + struct r8192_priv *priv = container_of(work, struct r8192_priv, update_beacon_wq.work); + struct net_device *dev = priv->ieee80211->dev; +#else +void rtl8192_update_beacon(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); +#endif + struct ieee80211_device* ieee = priv->ieee80211; + struct ieee80211_network* net = &ieee->current_network; + + if (ieee->pHTInfo->bCurrentHTSupport) + HTUpdateSelfAndPeerSetting(ieee, net); + ieee->pHTInfo->bCurrentRT2RTLongSlotTime = net->bssht.bdRT2RTLongSlotTime; + // Joseph test for turbo mode with AP + ieee->pHTInfo->RT2RT_HT_Mode = net->bssht.RT2RT_HT_Mode; + rtl8192_update_cap(dev, net->capability); +} +/* +* background support to run QoS activate functionality +*/ +int WDCAPARA_ADD[] = {EDCAPARA_BE,EDCAPARA_BK,EDCAPARA_VI,EDCAPARA_VO}; +#if LINUX_VERSION_CODE >=KERNEL_VERSION(2,6,20) +void rtl8192_qos_activate(struct work_struct * work) +{ + struct r8192_priv *priv = container_of(work, struct r8192_priv, qos_activate); + struct net_device *dev = priv->ieee80211->dev; +#else +void rtl8192_qos_activate(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); +#endif + struct ieee80211_qos_parameters *qos_parameters = &priv->ieee80211->current_network.qos_data.parameters; + u8 mode = priv->ieee80211->current_network.mode; + //u32 size = sizeof(struct ieee80211_qos_parameters); + u8 u1bAIFS; + u32 u4bAcParam; + int i; + + if (priv == NULL) + return; + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)) + down(&priv->mutex); +#else + mutex_lock(&priv->mutex); +#endif + if(priv->ieee80211->state != IEEE80211_LINKED) + goto success; + RT_TRACE(COMP_QOS,"qos active process with associate response received\n"); + /* It better set slot time at first */ + /* For we just support b/g mode at present, let the slot time at 9/20 selection */ + /* update the ac parameter to related registers */ + for(i = 0; i < QOS_QUEUE_NUM; i++) { + //Mode G/A: slotTimeTimer = 9; Mode B: 20 + u1bAIFS = qos_parameters->aifs[i] * ((mode&(IEEE_G|IEEE_N_24G)) ?9:20) + aSifsTime; + u4bAcParam = ((((u32)(qos_parameters->tx_op_limit[i]))<< AC_PARAM_TXOP_LIMIT_OFFSET)| + (((u32)(qos_parameters->cw_max[i]))<< AC_PARAM_ECW_MAX_OFFSET)| + (((u32)(qos_parameters->cw_min[i]))<< AC_PARAM_ECW_MIN_OFFSET)| + ((u32)u1bAIFS << AC_PARAM_AIFS_OFFSET)); + + write_nic_dword(dev, WDCAPARA_ADD[i], u4bAcParam); + //write_nic_dword(dev, WDCAPARA_ADD[i], 0x005e4322); + } + +success: +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)) + up(&priv->mutex); +#else + mutex_unlock(&priv->mutex); +#endif +} + +static int rtl8192_qos_handle_probe_response(struct r8192_priv *priv, + int active_network, + struct ieee80211_network *network) +{ + int ret = 0; + u32 size = sizeof(struct ieee80211_qos_parameters); + + if(priv->ieee80211->state !=IEEE80211_LINKED) + return ret; + + if ((priv->ieee80211->iw_mode != IW_MODE_INFRA)) + return ret; + + if (network->flags & NETWORK_HAS_QOS_MASK) { + if (active_network && + (network->flags & NETWORK_HAS_QOS_PARAMETERS)) + network->qos_data.active = network->qos_data.supported; + + if ((network->qos_data.active == 1) && (active_network == 1) && + (network->flags & NETWORK_HAS_QOS_PARAMETERS) && + (network->qos_data.old_param_count != + network->qos_data.param_count)) { + network->qos_data.old_param_count = + network->qos_data.param_count; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + queue_work(priv->priv_wq, &priv->qos_activate); +#else + schedule_task(&priv->qos_activate); +#endif + RT_TRACE (COMP_QOS, "QoS parameters change call " + "qos_activate\n"); + } + } else { + memcpy(&priv->ieee80211->current_network.qos_data.parameters,\ + &def_qos_parameters, size); + + if ((network->qos_data.active == 1) && (active_network == 1)) { +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + queue_work(priv->priv_wq, &priv->qos_activate); +#else + schedule_task(&priv->qos_activate); +#endif + RT_TRACE(COMP_QOS, "QoS was disabled call qos_activate \n"); + } + network->qos_data.active = 0; + network->qos_data.supported = 0; + } + + return 0; +} + +/* handle manage frame frame beacon and probe response */ +static int rtl8192_handle_beacon(struct net_device * dev, + struct ieee80211_beacon * beacon, + struct ieee80211_network * network) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + + rtl8192_qos_handle_probe_response(priv,1,network); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + queue_delayed_work(priv->priv_wq, &priv->update_beacon_wq, 0); +#else +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + schedule_task(&priv->update_beacon_wq); +#else + queue_work(priv->priv_wq, &priv->update_beacon_wq); +#endif + +#endif + return 0; + +} + +/* +* handling the beaconing responses. if we get different QoS setting +* off the network from the associated setting, adjust the QoS +* setting +*/ +static int rtl8192_qos_association_resp(struct r8192_priv *priv, + struct ieee80211_network *network) +{ + int ret = 0; + unsigned long flags; + u32 size = sizeof(struct ieee80211_qos_parameters); + int set_qos_param = 0; + + if ((priv == NULL) || (network == NULL)) + return ret; + + if(priv->ieee80211->state !=IEEE80211_LINKED) + return ret; + + if ((priv->ieee80211->iw_mode != IW_MODE_INFRA)) + return ret; + + spin_lock_irqsave(&priv->ieee80211->lock, flags); + if(network->flags & NETWORK_HAS_QOS_PARAMETERS) { + memcpy(&priv->ieee80211->current_network.qos_data.parameters,\ + &network->qos_data.parameters,\ + sizeof(struct ieee80211_qos_parameters)); + priv->ieee80211->current_network.qos_data.active = 1; +#if 0 + if((priv->ieee80211->current_network.qos_data.param_count != \ + network->qos_data.param_count)) +#endif + { + set_qos_param = 1; + /* update qos parameter for current network */ + priv->ieee80211->current_network.qos_data.old_param_count = \ + priv->ieee80211->current_network.qos_data.param_count; + priv->ieee80211->current_network.qos_data.param_count = \ + network->qos_data.param_count; + } + } else { + memcpy(&priv->ieee80211->current_network.qos_data.parameters,\ + &def_qos_parameters, size); + priv->ieee80211->current_network.qos_data.active = 0; + priv->ieee80211->current_network.qos_data.supported = 0; + set_qos_param = 1; + } + + spin_unlock_irqrestore(&priv->ieee80211->lock, flags); + + RT_TRACE(COMP_QOS, "%s: network->flags = %d,%d\n",__FUNCTION__,network->flags ,priv->ieee80211->current_network.qos_data.active); + if (set_qos_param == 1) +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + queue_work(priv->priv_wq, &priv->qos_activate); +#else + schedule_task(&priv->qos_activate); +#endif + + + return ret; +} + + +static int rtl8192_handle_assoc_response(struct net_device *dev, + struct ieee80211_assoc_response_frame *resp, + struct ieee80211_network *network) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + rtl8192_qos_association_resp(priv, network); + return 0; +} + + +void rtl8192_update_ratr_table(struct net_device* dev) + // POCTET_STRING posLegacyRate, + // u8* pMcsRate) + // PRT_WLAN_STA pEntry) +{ + struct r8192_priv* priv = ieee80211_priv(dev); + struct ieee80211_device* ieee = priv->ieee80211; + u8* pMcsRate = ieee->dot11HTOperationalRateSet; + //struct ieee80211_network *net = &ieee->current_network; + u32 ratr_value = 0; + u8 rate_index = 0; + rtl8192_config_rate(dev, (u16*)(&ratr_value)); + ratr_value |= (*(u16*)(pMcsRate)) << 12; +// switch (net->mode) + switch (ieee->mode) + { + case IEEE_A: + ratr_value &= 0x00000FF0; + break; + case IEEE_B: + ratr_value &= 0x0000000F; + break; + case IEEE_G: + ratr_value &= 0x00000FF7; + break; + case IEEE_N_24G: + case IEEE_N_5G: + if (ieee->pHTInfo->PeerMimoPs == 0) //MIMO_PS_STATIC + ratr_value &= 0x0007F007; + else{ + if (priv->rf_type == RF_1T2R) + ratr_value &= 0x000FF007; + else + ratr_value &= 0x0F81F007; + } + break; + default: + break; + } + ratr_value &= 0x0FFFFFFF; + if(ieee->pHTInfo->bCurTxBW40MHz && ieee->pHTInfo->bCurShortGI40MHz){ + ratr_value |= 0x80000000; + }else if(!ieee->pHTInfo->bCurTxBW40MHz && ieee->pHTInfo->bCurShortGI20MHz){ + ratr_value |= 0x80000000; + } + write_nic_dword(dev, RATR0+rate_index*4, ratr_value); + write_nic_byte(dev, UFWP, 1); +} + +static u8 ccmp_ie[4] = {0x00,0x50,0xf2,0x04}; +static u8 ccmp_rsn_ie[4] = {0x00, 0x0f, 0xac, 0x04}; +bool GetNmodeSupportBySecCfg8192(struct net_device*dev) +{ +#if 1 + struct r8192_priv* priv = ieee80211_priv(dev); + struct ieee80211_device* ieee = priv->ieee80211; + struct ieee80211_network * network = &ieee->current_network; + int wpa_ie_len= ieee->wpa_ie_len; + struct ieee80211_crypt_data* crypt; + int encrypt; +#if (defined (RTL8192SU_FPGA_2MAC_VERIFICATION)||defined (RTL8192SU_ASIC_VERIFICATION)) + return TRUE; +#endif + + crypt = ieee->crypt[ieee->tx_keyidx]; + //we use connecting AP's capability instead of only security config on our driver to distinguish whether it should use N mode or G mode + encrypt = (network->capability & WLAN_CAPABILITY_PRIVACY) || (ieee->host_encrypt && crypt && crypt->ops && (0 == strcmp(crypt->ops->name,"WEP"))); + + /* simply judge */ + if(encrypt && (wpa_ie_len == 0)) { + /* wep encryption, no N mode setting */ + return false; +// } else if((wpa_ie_len != 0)&&(memcmp(&(ieee->wpa_ie[14]),ccmp_ie,4))) { + } else if((wpa_ie_len != 0)) { + /* parse pairwise key type */ + //if((pairwisekey = WEP40)||(pairwisekey = WEP104)||(pairwisekey = TKIP)) + if (((ieee->wpa_ie[0] == 0xdd) && (!memcmp(&(ieee->wpa_ie[14]),ccmp_ie,4))) || ((ieee->wpa_ie[0] == 0x30) && (!memcmp(&ieee->wpa_ie[10],ccmp_rsn_ie, 4)))) + return true; + else + return false; + } else { + return true; + } + +#if 0 + //In here we discuss with SD4 David. He think we still can send TKIP in broadcast group key in MCS rate. + //We can't force in G mode if Pairwie key is AES and group key is TKIP + if((pSecInfo->GroupEncAlgorithm == WEP104_Encryption) || (pSecInfo->GroupEncAlgorithm == WEP40_Encryption) || + (pSecInfo->PairwiseEncAlgorithm == WEP104_Encryption) || + (pSecInfo->PairwiseEncAlgorithm == WEP40_Encryption) || (pSecInfo->PairwiseEncAlgorithm == TKIP_Encryption)) + { + return false; + } + else + return true; +#endif + return true; +#endif +} + +bool GetHalfNmodeSupportByAPs819xUsb(struct net_device* dev) +{ + bool Reval; + struct r8192_priv* priv = ieee80211_priv(dev); + struct ieee80211_device* ieee = priv->ieee80211; + +// Added by Roger, 2008.08.29. +#ifdef RTL8192SU + return false; +#endif + + if(ieee->bHalfWirelessN24GMode == true) + Reval = true; + else + Reval = false; + + return Reval; +} + +void rtl8192_refresh_supportrate(struct r8192_priv* priv) +{ + struct ieee80211_device* ieee = priv->ieee80211; + //we donot consider set support rate for ABG mode, only HT MCS rate is set here. + if (ieee->mode == WIRELESS_MODE_N_24G || ieee->mode == WIRELESS_MODE_N_5G) + { + memcpy(ieee->Regdot11HTOperationalRateSet, ieee->RegHTSuppRateSet, 16); + //RT_DEBUG_DATA(COMP_INIT, ieee->RegHTSuppRateSet, 16); + //RT_DEBUG_DATA(COMP_INIT, ieee->Regdot11HTOperationalRateSet, 16); + } + else + memset(ieee->Regdot11HTOperationalRateSet, 0, 16); + return; +} + +u8 rtl8192_getSupportedWireleeMode(struct net_device*dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + u8 ret = 0; + switch(priv->rf_chip) + { + case RF_8225: + case RF_8256: + case RF_PSEUDO_11N: + case RF_6052: + ret = (WIRELESS_MODE_N_24G|WIRELESS_MODE_G|WIRELESS_MODE_B); + break; + case RF_8258: + ret = (WIRELESS_MODE_A|WIRELESS_MODE_N_5G); + break; + default: + ret = WIRELESS_MODE_B; + break; + } + return ret; +} +void rtl8192_SetWirelessMode(struct net_device* dev, u8 wireless_mode) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + u8 bSupportMode = rtl8192_getSupportedWireleeMode(dev); + +#if 1 + if ((wireless_mode == WIRELESS_MODE_AUTO) || ((wireless_mode&bSupportMode)==0)) + { + if(bSupportMode & WIRELESS_MODE_N_24G) + { + wireless_mode = WIRELESS_MODE_N_24G; + } + else if(bSupportMode & WIRELESS_MODE_N_5G) + { + wireless_mode = WIRELESS_MODE_N_5G; + } + else if((bSupportMode & WIRELESS_MODE_A)) + { + wireless_mode = WIRELESS_MODE_A; + } + else if((bSupportMode & WIRELESS_MODE_G)) + { + wireless_mode = WIRELESS_MODE_G; + } + else if((bSupportMode & WIRELESS_MODE_B)) + { + wireless_mode = WIRELESS_MODE_B; + } + else{ + RT_TRACE(COMP_ERR, "%s(), No valid wireless mode supported, SupportedWirelessMode(%x)!!!\n", __FUNCTION__,bSupportMode); + wireless_mode = WIRELESS_MODE_B; + } + } +#ifdef TO_DO_LIST //// TODO: this function doesn't work well at this time, we shoud wait for FPGA + ActUpdateChannelAccessSetting( pAdapter, pHalData->CurrentWirelessMode, &pAdapter->MgntInfo.Info8185.ChannelAccessSetting ); +#endif +#ifdef RTL8192SU + //LZM 090306 usb crash here, mark it temp + //write_nic_word(dev, SIFS_OFDM, 0x0e0e); +#endif + priv->ieee80211->mode = wireless_mode; + + if ((wireless_mode == WIRELESS_MODE_N_24G) || (wireless_mode == WIRELESS_MODE_N_5G)) + priv->ieee80211->pHTInfo->bEnableHT = 1; + else + priv->ieee80211->pHTInfo->bEnableHT = 0; + RT_TRACE(COMP_INIT, "Current Wireless Mode is %x\n", wireless_mode); + rtl8192_refresh_supportrate(priv); +#endif + +} + + +short rtl8192_is_tx_queue_empty(struct net_device *dev) +{ + int i=0; + struct r8192_priv *priv = ieee80211_priv(dev); + //struct ieee80211_device* ieee = priv->ieee80211; + for (i=0; i<=MGNT_QUEUE; i++) + { + if ((i== TXCMD_QUEUE) || (i == HCCA_QUEUE) ) + continue; + if (atomic_read(&priv->tx_pending[i])) + { + printk("===>tx queue is not empty:%d, %d\n", i, atomic_read(&priv->tx_pending[i])); + return 0; + } + } + return 1; +} +#if 0 +void rtl8192_rq_tx_ack(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + priv->ieee80211->ack_tx_to_ieee = 1; +} +#endif +void rtl8192_hw_sleep_down(struct net_device *dev) +{ + RT_TRACE(COMP_POWER, "%s()============>come to sleep down\n", __FUNCTION__); +#ifdef TODO +// MgntActSet_RF_State(dev, eRfSleep, RF_CHANGE_BY_PS); +#endif +} +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) +void rtl8192_hw_sleep_wq (struct work_struct *work) +{ +// struct r8180_priv *priv = container_of(work, struct r8180_priv, watch_dog_wq); +// struct ieee80211_device * ieee = (struct ieee80211_device*) +// container_of(work, struct ieee80211_device, watch_dog_wq); + struct delayed_work *dwork = container_of(work,struct delayed_work,work); + struct ieee80211_device *ieee = container_of(dwork,struct ieee80211_device,hw_sleep_wq); + struct net_device *dev = ieee->dev; +#else +void rtl8192_hw_sleep_wq(struct net_device* dev) +{ +#endif + //printk("=========>%s()\n", __FUNCTION__); + rtl8192_hw_sleep_down(dev); +} +// printk("dev is %d\n",dev); +// printk("&*&(^*(&(&=========>%s()\n", __FUNCTION__); +void rtl8192_hw_wakeup(struct net_device* dev) +{ +// u32 flags = 0; + +// spin_lock_irqsave(&priv->ps_lock,flags); + RT_TRACE(COMP_POWER, "%s()============>come to wake up\n", __FUNCTION__); +#ifdef TODO +// MgntActSet_RF_State(dev, eRfSleep, RF_CHANGE_BY_PS); +#endif + //FIXME: will we send package stored while nic is sleep? +// spin_unlock_irqrestore(&priv->ps_lock,flags); +} +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) +void rtl8192_hw_wakeup_wq (struct work_struct *work) +{ +// struct r8180_priv *priv = container_of(work, struct r8180_priv, watch_dog_wq); +// struct ieee80211_device * ieee = (struct ieee80211_device*) +// container_of(work, struct ieee80211_device, watch_dog_wq); + struct delayed_work *dwork = container_of(work,struct delayed_work,work); + struct ieee80211_device *ieee = container_of(dwork,struct ieee80211_device,hw_wakeup_wq); + struct net_device *dev = ieee->dev; +#else +void rtl8192_hw_wakeup_wq(struct net_device* dev) +{ +#endif + rtl8192_hw_wakeup(dev); + +} + +#define MIN_SLEEP_TIME 50 +#define MAX_SLEEP_TIME 10000 +void rtl8192_hw_to_sleep(struct net_device *dev, u32 th, u32 tl) +{ + + struct r8192_priv *priv = ieee80211_priv(dev); + + u32 rb = jiffies; + unsigned long flags; + + spin_lock_irqsave(&priv->ps_lock,flags); + + /* Writing HW register with 0 equals to disable + * the timer, that is not really what we want + */ + tl -= MSECS(4+16+7); + + //if(tl == 0) tl = 1; + + /* FIXME HACK FIXME HACK */ +// force_pci_posting(dev); + //mdelay(1); + +// rb = read_nic_dword(dev, TSFTR); + + /* If the interval in witch we are requested to sleep is too + * short then give up and remain awake + */ + if(((tl>=rb)&& (tl-rb) <= MSECS(MIN_SLEEP_TIME)) + ||((rb>tl)&& (rb-tl) < MSECS(MIN_SLEEP_TIME))) { + spin_unlock_irqrestore(&priv->ps_lock,flags); + printk("too short to sleep\n"); + return; + } + +// write_nic_dword(dev, TimerInt, tl); +// rb = read_nic_dword(dev, TSFTR); + { + u32 tmp = (tl>rb)?(tl-rb):(rb-tl); + // if (tlieee80211->hw_wakeup_wq); +#else + queue_delayed_work(priv->ieee80211->wq, &priv->ieee80211->hw_wakeup_wq, tmp); //as tl may be less than rb +#endif + } + /* if we suspect the TimerInt is gone beyond tl + * while setting it, then give up + */ +#if 1 + if(((tl > rb) && ((tl-rb) > MSECS(MAX_SLEEP_TIME)))|| + ((tl < rb) && ((rb-tl) > MSECS(MAX_SLEEP_TIME)))) { + printk("========>too long to sleep:%x, %x, %lx\n", tl, rb, MSECS(MAX_SLEEP_TIME)); + spin_unlock_irqrestore(&priv->ps_lock,flags); + return; + } +#endif +// if(priv->rf_sleep) +// priv->rf_sleep(dev); + + //printk("<=========%s()\n", __FUNCTION__); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + schedule_task(&priv->ieee80211->hw_sleep_wq); +#else + queue_delayed_work(priv->ieee80211->wq, (void *)&priv->ieee80211->hw_sleep_wq,0); +#endif + spin_unlock_irqrestore(&priv->ps_lock,flags); +} +//init priv variables here. only non_zero value should be initialized here. +static void rtl8192_init_priv_variable(struct net_device* dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + u8 i; + priv->card_8192 = NIC_8192U; + priv->chan = 1; //set to channel 1 + priv->ieee80211->mode = WIRELESS_MODE_AUTO; //SET AUTO + priv->ieee80211->iw_mode = IW_MODE_INFRA; + priv->ieee80211->ieee_up=0; + priv->retry_rts = DEFAULT_RETRY_RTS; + priv->retry_data = DEFAULT_RETRY_DATA; + priv->ieee80211->rts = DEFAULT_RTS_THRESHOLD; + priv->ieee80211->rate = 110; //11 mbps + priv->ieee80211->short_slot = 1; + priv->promisc = (dev->flags & IFF_PROMISC) ? 1:0; + priv->CckPwEnl = 6; + //for silent reset + priv->IrpPendingCount = 1; + priv->ResetProgress = RESET_TYPE_NORESET; + priv->bForcedSilentReset = 0; + priv->bDisableNormalResetCheck = false; + priv->force_reset = false; + + priv->ieee80211->FwRWRF = 0; //we don't use FW read/write RF until stable firmware is available. + priv->ieee80211->current_network.beacon_interval = DEFAULT_BEACONINTERVAL; + priv->ieee80211->iw_mode = IW_MODE_INFRA; + priv->ieee80211->softmac_features = IEEE_SOFTMAC_SCAN | + IEEE_SOFTMAC_ASSOCIATE | IEEE_SOFTMAC_PROBERQ | + IEEE_SOFTMAC_PROBERS | IEEE_SOFTMAC_TX_QUEUE | + IEEE_SOFTMAC_BEACONS;//added by amy 080604 //| //IEEE_SOFTMAC_SINGLE_QUEUE; + + priv->ieee80211->active_scan = 1; + priv->ieee80211->modulation = IEEE80211_CCK_MODULATION | IEEE80211_OFDM_MODULATION; + priv->ieee80211->host_encrypt = 1; + priv->ieee80211->host_decrypt = 1; + priv->ieee80211->start_send_beacons = NULL;//rtl819xusb_beacon_tx;//-by amy 080604 + priv->ieee80211->stop_send_beacons = NULL;//rtl8192_beacon_stop;//-by amy 080604 + priv->ieee80211->softmac_hard_start_xmit = rtl8192_hard_start_xmit; + priv->ieee80211->set_chan = rtl8192_set_chan; + priv->ieee80211->link_change = priv->ops->rtl819x_link_change; + priv->ieee80211->softmac_data_hard_start_xmit = rtl8192_hard_data_xmit; + priv->ieee80211->data_hard_stop = rtl8192_data_hard_stop; + priv->ieee80211->data_hard_resume = rtl8192_data_hard_resume; + priv->ieee80211->init_wmmparam_flag = 0; + priv->ieee80211->fts = DEFAULT_FRAG_THRESHOLD; + priv->ieee80211->check_nic_enough_desc = check_nic_enough_desc; + priv->ieee80211->tx_headroom = TX_PACKET_SHIFT_BYTES; + priv->ieee80211->qos_support = 1; + + //added by WB +// priv->ieee80211->SwChnlByTimerHandler = rtl8192_phy_SwChnl; + priv->ieee80211->SetBWModeHandler = rtl8192_SetBWMode; + priv->ieee80211->handle_assoc_response = rtl8192_handle_assoc_response; + priv->ieee80211->handle_beacon = rtl8192_handle_beacon; + //for LPS + priv->ieee80211->sta_wake_up = rtl8192_hw_wakeup; +// priv->ieee80211->ps_request_tx_ack = rtl8192_rq_tx_ack; + priv->ieee80211->enter_sleep_state = rtl8192_hw_to_sleep; + priv->ieee80211->ps_is_queue_empty = rtl8192_is_tx_queue_empty; + //added by david + priv->ieee80211->GetNmodeSupportBySecCfg = GetNmodeSupportBySecCfg8192; + priv->ieee80211->GetHalfNmodeSupportByAPsHandler = GetHalfNmodeSupportByAPs819xUsb; + priv->ieee80211->SetWirelessMode = rtl8192_SetWirelessMode; + //added by amy + priv->ieee80211->InitialGainHandler = priv->ops->rtl819x_initial_gain; + priv->card_type = USB; + +#ifdef RTL8192SU +//1 RTL8192SU/ + priv->ieee80211->current_network.beacon_interval = DEFAULT_BEACONINTERVAL; + priv->ieee80211->SetFwCmdHandler = HalSetFwCmd8192S; + priv->bRFSiOrPi = 0;//o=si,1=pi; + //lzm add + priv->bInHctTest = false; + + priv->MidHighPwrTHR_L1 = 0x3B; + priv->MidHighPwrTHR_L2 = 0x40; + + if(priv->bInHctTest) + { + priv->ShortRetryLimit = HAL_RETRY_LIMIT_AP_ADHOC; + priv->LongRetryLimit = HAL_RETRY_LIMIT_AP_ADHOC; + } + else + { + priv->ShortRetryLimit = HAL_RETRY_LIMIT_INFRA; + priv->LongRetryLimit = HAL_RETRY_LIMIT_INFRA; + } + + priv->SetFwCmdInProgress = false; //is set FW CMD in Progress? 92S only + priv->CurrentFwCmdIO = 0; + + priv->MinSpaceCfg = 0; + + priv->EarlyRxThreshold = 7; + priv->enable_gpio0 = 0; + priv->TransmitConfig = + ((u32)TCR_MXDMA_2048<ShortRetryLimit<LongRetryLimit<bInHctTest) + priv->ReceiveConfig = //priv->CSMethod | + RCR_AMF | RCR_ADF | //RCR_AAP | //accept management/data + RCR_ACF |RCR_APPFCS| //accept control frame for SW AP needs PS-poll, 2005.07.07, by rcnjko. + RCR_AB | RCR_AM | RCR_APM | //accept BC/MC/UC + RCR_AICV | RCR_ACRC32 | //accept ICV/CRC error packet + RCR_APP_PHYST_STAFF | RCR_APP_PHYST_RXFF | // Accept PHY status + ((u32)7<EarlyRxThreshold<EarlyRxThreshold == 7 ? RCR_OnlyErlPkt:0); + else + priv->ReceiveConfig = //priv->CSMethod | + RCR_AMF | RCR_ADF | RCR_AB | + RCR_AM | RCR_APM |RCR_AAP |RCR_ADD3|RCR_APP_ICV| + RCR_APP_PHYST_STAFF | RCR_APP_PHYST_RXFF | // Accept PHY status + RCR_APP_MIC | RCR_APPFCS; + + // 2008.06.16. + priv->IntrMask = (u16)(IMR_ROK | IMR_VODOK | IMR_VIDOK | IMR_BEDOK | IMR_BKDOK | \ + IMR_HCCADOK | IMR_MGNTDOK | IMR_COMDOK | IMR_HIGHDOK | \ + IMR_BDOK | IMR_RXCMDOK | /*IMR_TIMEOUT0 |*/ IMR_RDU | IMR_RXFOVW | \ + IMR_TXFOVW | IMR_BcnInt | IMR_TBDOK | IMR_TBDER); + +//1 End + +#else + +#ifdef TO_DO_LIST + if(Adapter->bInHctTest) + { + pHalData->ShortRetryLimit = 7; + pHalData->LongRetryLimit = 7; + } +#endif + { + priv->ShortRetryLimit = 0x30; + priv->LongRetryLimit = 0x30; + } + priv->EarlyRxThreshold = 7; + priv->enable_gpio0 = 0; + priv->TransmitConfig = + // TCR_DurProcMode | //for RTL8185B, duration setting by HW + //? TCR_DISReqQsize | + (TCR_MXDMA_2048<ShortRetryLimit<LongRetryLimit<bInHctTest) + pHalData->ReceiveConfig = pHalData->CSMethod | + RCR_AMF | RCR_ADF | //RCR_AAP | //accept management/data + //guangan200710 + RCR_ACF | //accept control frame for SW AP needs PS-poll, 2005.07.07, by rcnjko. + RCR_AB | RCR_AM | RCR_APM | //accept BC/MC/UC + RCR_AICV | RCR_ACRC32 | //accept ICV/CRC error packet + ((u32)7<EarlyRxThreshold<EarlyRxThreshold == 7 ? RCR_OnlyErlPkt:0); + else + +#endif + priv->ReceiveConfig = + RCR_AMF | RCR_ADF | //accept management/data + RCR_ACF | //accept control frame for SW AP needs PS-poll, 2005.07.07, by rcnjko. + RCR_AB | RCR_AM | RCR_APM | //accept BC/MC/UC + //RCR_AICV | RCR_ACRC32 | //accept ICV/CRC error packet + ((u32)7<EarlyRxThreshold<EarlyRxThreshold == 7 ? RCR_ONLYERLPKT:0); +#endif + + priv->AcmControl = 0; + priv->pFirmware = (rt_firmware*)vmalloc(sizeof(rt_firmware)); + if (priv->pFirmware) + memset(priv->pFirmware, 0, sizeof(rt_firmware)); + + /* rx related queue */ + skb_queue_head_init(&priv->rx_queue); + skb_queue_head_init(&priv->skb_queue); + + /* Tx related queue */ + for(i = 0; i < MAX_QUEUE_SIZE; i++) { + skb_queue_head_init(&priv->ieee80211->skb_waitQ [i]); + } + for(i = 0; i < MAX_QUEUE_SIZE; i++) { + skb_queue_head_init(&priv->ieee80211->skb_aggQ [i]); + } + for(i = 0; i < MAX_QUEUE_SIZE; i++) { + skb_queue_head_init(&priv->ieee80211->skb_drv_aggQ [i]); + } + priv->rf_set_chan = rtl8192_phy_SwChnl; +} + +//init lock here +static void rtl8192_init_priv_lock(struct r8192_priv* priv) +{ + spin_lock_init(&priv->tx_lock); + spin_lock_init(&priv->irq_lock);//added by thomas + //spin_lock_init(&priv->rf_lock);//use rf_sem, or will crash in some OS. + sema_init(&priv->wx_sem,1); + sema_init(&priv->rf_sem,1); + spin_lock_init(&priv->ps_lock); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)) + sema_init(&priv->mutex, 1); +#else + mutex_init(&priv->mutex); +#endif +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) +extern void rtl819x_watchdog_wqcallback(struct work_struct *work); +#else +extern void rtl819x_watchdog_wqcallback(struct net_device *dev); +#endif + +void rtl8192_irq_rx_tasklet(struct r8192_priv *priv); +//init tasklet and wait_queue here. only 2.6 above kernel is considered +#define DRV_NAME "wlan0" +static void rtl8192_init_priv_task(struct net_device* dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) +#ifdef PF_SYNCTHREAD + priv->priv_wq = create_workqueue(DRV_NAME,0); +#else + priv->priv_wq = create_workqueue(DRV_NAME); +#endif +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) + INIT_WORK(&priv->reset_wq, rtl8192_restart); + + //INIT_DELAYED_WORK(&priv->watch_dog_wq, hal_dm_watchdog); + INIT_DELAYED_WORK(&priv->watch_dog_wq, rtl819x_watchdog_wqcallback); + INIT_DELAYED_WORK(&priv->txpower_tracking_wq, dm_txpower_trackingcallback); +// INIT_DELAYED_WORK(&priv->gpio_change_rf_wq, dm_gpio_change_rf_callback); + INIT_DELAYED_WORK(&priv->rfpath_check_wq, dm_rf_pathcheck_workitemcallback); + INIT_DELAYED_WORK(&priv->update_beacon_wq, rtl8192_update_beacon); + INIT_DELAYED_WORK(&priv->initialgain_operate_wq, InitialGainOperateWorkItemCallBack); + //INIT_WORK(&priv->SwChnlWorkItem, rtl8192_SwChnl_WorkItem); + //INIT_WORK(&priv->SetBWModeWorkItem, rtl8192_SetBWModeWorkItem); + INIT_WORK(&priv->qos_activate, rtl8192_qos_activate); + INIT_DELAYED_WORK(&priv->ieee80211->hw_wakeup_wq,(void*) rtl8192_hw_wakeup_wq); + INIT_DELAYED_WORK(&priv->ieee80211->hw_sleep_wq,(void*) rtl8192_hw_sleep_wq); + +#else +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) + tq_init(&priv->reset_wq, (void*)rtl8192_restart, dev); + tq_init(&priv->watch_dog_wq, (void*)rtl819x_watchdog_wqcallback, dev); + tq_init(&priv->txpower_tracking_wq, (void*)dm_txpower_trackingcallback, dev); + tq_init(&priv->rfpath_check_wq, (void*)dm_rf_pathcheck_workitemcallback, dev); + tq_init(&priv->update_beacon_wq, (void*)rtl8192_update_beacon, dev); + //tq_init(&priv->SwChnlWorkItem, (void*) rtl8192_SwChnl_WorkItem, dev); + //tq_init(&priv->SetBWModeWorkItem, (void*)rtl8192_SetBWModeWorkItem, dev); + tq_init(&priv->qos_activate, (void *)rtl8192_qos_activate, dev); + tq_init(&priv->ieee80211->hw_wakeup_wq,(void*) rtl8192_hw_wakeup_wq, dev); + tq_init(&priv->ieee80211->hw_sleep_wq,(void*) rtl8192_hw_sleep_wq, dev); + +#else + INIT_WORK(&priv->reset_wq,(void(*)(void*)) rtl8192_restart,dev); + //INIT_WORK(&priv->watch_dog_wq, (void(*)(void*)) hal_dm_watchdog,dev); + INIT_WORK(&priv->watch_dog_wq, (void(*)(void*)) rtl819x_watchdog_wqcallback,dev); + INIT_WORK(&priv->txpower_tracking_wq, (void(*)(void*)) dm_txpower_trackingcallback,dev); +// INIT_WORK(&priv->gpio_change_rf_wq, (void(*)(void*)) dm_gpio_change_rf_callback,dev); + INIT_WORK(&priv->rfpath_check_wq, (void(*)(void*)) dm_rf_pathcheck_workitemcallback,dev); + INIT_WORK(&priv->update_beacon_wq, (void(*)(void*))rtl8192_update_beacon,dev); + INIT_WORK(&priv->initialgain_operate_wq, (void(*)(void*))InitialGainOperateWorkItemCallBack,dev); + //INIT_WORK(&priv->SwChnlWorkItem, (void(*)(void*)) rtl8192_SwChnl_WorkItem, dev); + //INIT_WORK(&priv->SetBWModeWorkItem, (void(*)(void*)) rtl8192_SetBWModeWorkItem, dev); + INIT_WORK(&priv->qos_activate, (void(*)(void *))rtl8192_qos_activate, dev); + INIT_WORK(&priv->ieee80211->hw_wakeup_wq,(void*) rtl8192_hw_wakeup_wq, dev); + INIT_WORK(&priv->ieee80211->hw_sleep_wq,(void*) rtl8192_hw_sleep_wq, dev); +#endif +#endif + + tasklet_init(&priv->irq_rx_tasklet, + (void(*)(unsigned long))rtl8192_irq_rx_tasklet, + (unsigned long)priv); +} + +static void rtl8192_get_eeprom_size(struct net_device* dev) +{ + u16 curCR = 0; + struct r8192_priv *priv = ieee80211_priv(dev); + RT_TRACE(COMP_EPROM, "===========>%s()\n", __FUNCTION__); + curCR = read_nic_word_E(dev,EPROM_CMD); + RT_TRACE(COMP_EPROM, "read from Reg EPROM_CMD(%x):%x\n", EPROM_CMD, curCR); + //whether need I consider BIT5? + priv->epromtype = (curCR & Cmd9346CR_9356SEL) ? EPROM_93c56 : EPROM_93c46; + RT_TRACE(COMP_EPROM, "<===========%s(), epromtype:%d\n", __FUNCTION__, priv->epromtype); +} + +//used to swap endian. as ntohl & htonl are not neccessary to swap endian, so use this instead. +static inline u16 endian_swap(u16* data) +{ + u16 tmp = *data; + *data = (tmp >> 8) | (tmp << 8); + return *data; +} + +#ifdef RTL8192SU +u8 rtl8192SU_UsbOptionToEndPointNumber(u8 UsbOption) +{ + u8 nEndPoint = 0; + switch(UsbOption) + { + case 0: + nEndPoint = 6; + break; + case 1: + nEndPoint = 11; + break; + case 2: + nEndPoint = 4; + break; + default: + RT_TRACE(COMP_INIT, "UsbOptionToEndPointNumber(): Invalid UsbOption(%#x)\n", UsbOption); + break; + } + return nEndPoint; +} + +u8 rtl8192SU_BoardTypeToRFtype(struct net_device* dev, u8 Boardtype) +{ + u8 RFtype = RF_1T2R; + + switch(Boardtype) + { + case 0: + RFtype = RF_1T1R; + break; + case 1: + RFtype = RF_1T2R; + break; + case 2: + RFtype = RF_2T2R; + break; + case 3: + RFtype = RF_2T2R_GREEN; + break; + default: + break; + } + + return RFtype; +} + +// +// Description: +// Config HW adapter information into initial value. +// +// Assumption: +// 1. After Auto load fail(i.e, check CR9346 fail) +// +// Created by Roger, 2008.10.21. +// +void +rtl8192SU_ConfigAdapterInfo8192SForAutoLoadFail(struct net_device* dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + //u16 i,usValue; + //u8 sMacAddr[6] = {0x00, 0xE0, 0x4C, 0x81, 0x92, 0x00}; + u8 rf_path, index; // For EEPROM/EFUSE After V0.6_1117 + int i; + + RT_TRACE(COMP_INIT, "====> ConfigAdapterInfo8192SForAutoLoadFail\n"); + + write_nic_byte(dev, SYS_ISO_CTRL+1, 0xE8); // Isolation signals from Loader + //PlatformStallExecution(10000); + mdelay(10); + write_nic_byte(dev, PMC_FSM, 0x02); // Enable Loader Data Keep + + //RT_ASSERT(priv->AutoloadFailFlag==TRUE, ("ReadAdapterInfo8192SEEPROM(): AutoloadFailFlag !=TRUE\n")); + + // Initialize IC Version && Channel Plan + priv->eeprom_vid = 0; + priv->eeprom_pid = 0; + priv->card_8192_version = 0; + priv->eeprom_ChannelPlan = 0; + priv->eeprom_CustomerID = 0; + priv->eeprom_SubCustomerID = 0; + priv->bIgnoreDiffRateTxPowerOffset = false; + + RT_TRACE(COMP_INIT, "EEPROM VID = 0x%4x\n", priv->eeprom_vid); + RT_TRACE(COMP_INIT, "EEPROM PID = 0x%4x\n", priv->eeprom_pid); + RT_TRACE(COMP_INIT, "EEPROM Customer ID: 0x%2x\n", priv->eeprom_CustomerID); + RT_TRACE(COMP_INIT, "EEPROM SubCustomer ID: 0x%2x\n", priv->eeprom_SubCustomerID); + RT_TRACE(COMP_INIT, "EEPROM ChannelPlan = 0x%4x\n", priv->eeprom_ChannelPlan); + RT_TRACE(COMP_INIT, "IgnoreDiffRateTxPowerOffset = %d\n", priv->bIgnoreDiffRateTxPowerOffset); + + + + priv->EEPROMUsbOption = EEPROM_USB_Default_OPTIONAL_FUNC; + RT_TRACE(COMP_INIT, "USB Option = %#x\n", priv->EEPROMUsbOption); + + for(i=0; i<5; i++) + priv->EEPROMUsbPhyParam[i] = EEPROM_USB_Default_PHY_PARAM; + + //RT_PRINT_DATA(COMP_INIT|COMP_EFUSE, DBG_LOUD, ("EFUSE USB PHY Param: \n"), priv->EEPROMUsbPhyParam, 5); + + { + // In this case, we random assigh MAC address here. 2008.10.15. + static u8 sMacAddr[6] = {0x00, 0xE0, 0x4C, 0x81, 0x92, 0x00}; + u8 i; + + //sMacAddr[5] = (u8)GetRandomNumber(1, 254); + + for(i = 0; i < 6; i++) + dev->dev_addr[i] = sMacAddr[i]; + } + //NicIFSetMacAddress(Adapter, Adapter->PermanentAddress); + write_nic_dword(dev, IDR0, ((u32*)dev->dev_addr)[0]); + write_nic_word(dev, IDR4, ((u16*)(dev->dev_addr + 4))[0]); + + RT_TRACE(COMP_INIT, "ReadAdapterInfo8192SEFuse(), Permanent Address = %02x-%02x-%02x-%02x-%02x-%02x\n", + dev->dev_addr[0], dev->dev_addr[1], + dev->dev_addr[2], dev->dev_addr[3], + dev->dev_addr[4], dev->dev_addr[5]); + + priv->EEPROMBoardType = EEPROM_Default_BoardType; + priv->rf_type = RF_1T2R; //RF_2T2R + priv->EEPROMTxPowerDiff = EEPROM_Default_PwDiff; + priv->EEPROMThermalMeter = EEPROM_Default_ThermalMeter; + priv->EEPROMCrystalCap = EEPROM_Default_CrystalCap; + priv->EEPROMTxPwrBase = EEPROM_Default_TxPowerBase; + priv->EEPROMTSSI_A = EEPROM_Default_TSSI; + priv->EEPROMTSSI_B = EEPROM_Default_TSSI; + priv->EEPROMTxPwrTkMode = EEPROM_Default_TxPwrTkMode; + + +#ifdef EEPROM_OLD_FORMAT_SUPPORT + for(i=0; i<6; i++) + { + priv->EEPROMHT2T_TxPwr[i] = EEPROM_Default_HT2T_TxPwr; + } + + for(i=0; i<14; i++) + { + priv->EEPROMTxPowerLevelCCK24G[i] = (u8)(EEPROM_Default_TxPower & 0xff); + priv->EEPROMTxPowerLevelOFDM24G[i] = (u8)(EEPROM_Default_TxPower & 0xff); + } + + // + // Update HAL variables. + // + memcpy( priv->TxPowerLevelOFDM24G, priv->EEPROMTxPowerLevelOFDM24G, 14); + memcpy( priv->TxPowerLevelCCK, priv->EEPROMTxPowerLevelCCK24G, 14); + //RT_PRINT_DATA(COMP_INIT|COMP_EFUSE, DBG_LOUD, ("HAL CCK 2.4G TxPwr: \n"), priv->TxPowerLevelCCK, 14); + //RT_PRINT_DATA(COMP_INIT|COMP_EFUSE, DBG_LOUD, ("HAL OFDM 2.4G TxPwr: \n"), priv->TxPowerLevelOFDM24G, 14); +#else + + for (rf_path = 0; rf_path < 2; rf_path++) + { + for (i = 0; i < 3; i++) + { + // Read CCK RF A & B Tx power + priv->RfCckChnlAreaTxPwr[rf_path][i] = + priv->RfOfdmChnlAreaTxPwr1T[rf_path][i] = + priv->RfOfdmChnlAreaTxPwr2T[rf_path][i] = + (u8)(EEPROM_Default_TxPower & 0xff); + } + } + + for (i = 0; i < 3; i++) + { + //RT_TRACE((COMP_EFUSE), "CCK RF-%d CHan_Area-%d = 0x%x\n", rf_path, i, + //priv->RfCckChnlAreaTxPwr[rf_path][i]); + //RT_TRACE((COMP_EFUSE), "OFDM-1T RF-%d CHan_Area-%d = 0x%x\n", rf_path, i, + //priv->RfOfdmChnlAreaTxPwr1T[rf_path][i]); + //RT_TRACE((COMP_EFUSE), "OFDM-2T RF-%d CHan_Area-%d = 0x%x\n", rf_path, i, + //priv->RfOfdmChnlAreaTxPwr2T[rf_path][i]); + } + + // Assign dedicated channel tx power + for(i=0; i<14; i++) // channel 1~3 use the same Tx Power Level. + { + if (i < 3) // Cjanel 1-3 + index = 0; + else if (i < 9) // Channel 4-9 + index = 1; + else // Channel 10-14 + index = 2; + + // Record A & B CCK /OFDM - 1T/2T Channel area tx power + priv->RfTxPwrLevelCck[rf_path][i] = + priv->RfCckChnlAreaTxPwr[rf_path][index]; + priv->RfTxPwrLevelOfdm1T[rf_path][i] = + priv->RfOfdmChnlAreaTxPwr1T[rf_path][index]; + priv->RfTxPwrLevelOfdm2T[rf_path][i] = + priv->RfOfdmChnlAreaTxPwr2T[rf_path][index]; + } + + for(i=0; i<14; i++) + { + //RT_TRACE((COMP_EFUSE), "Rf-%d TxPwr CH-%d CCK OFDM_1T OFDM_2T= 0x%x/0x%x/0x%x\n", + //rf_path, i, priv->RfTxPwrLevelCck[0][i], + //priv->RfTxPwrLevelOfdm1T[0][i] , + //priv->RfTxPwrLevelOfdm2T[0][i] ); + } +#endif + + // + // Update remained HAL variables. + // + priv->TSSI_13dBm = priv->EEPROMThermalMeter *100; + priv->LegacyHTTxPowerDiff = priv->EEPROMTxPowerDiff;//new + priv->TxPowerDiff = priv->EEPROMTxPowerDiff; + //priv->AntennaTxPwDiff[0] = (priv->EEPROMTxPowerDiff & 0xf);// Antenna B gain offset to antenna A, bit0~3 + //priv->AntennaTxPwDiff[1] = ((priv->EEPROMTxPowerDiff & 0xf0)>>4);// Antenna C gain offset to antenna A, bit4~7 + priv->CrystalCap = priv->EEPROMCrystalCap; // CrystalCap, bit12~15 + priv->ThermalMeter[0] = priv->EEPROMThermalMeter;// ThermalMeter, bit0~3 for RFIC1, bit4~7 for RFIC2 + priv->LedStrategy = SW_LED_MODE0; + + init_rate_adaptive(dev); + + RT_TRACE(COMP_INIT, "<==== ConfigAdapterInfo8192SForAutoLoadFail\n"); + +} + +#if 0 +static void rtl8192SU_ReadAdapterInfo8192SEEPROM(struct net_device* dev) +{ + u16 EEPROMId = 0; + u8 bLoad_From_EEPOM = false; + struct r8192_priv *priv = ieee80211_priv(dev); + u16 tmpValue = 0; + u8 tmpBuffer[30]; + int i; + + RT_TRACE(COMP_EPROM, "===========>%s()\n", __FUNCTION__); + + + write_nic_byte(dev, SYS_ISO_CTRL+1, 0xE8); // Isolation signals from Loader + udelay(10000); + write_nic_byte(dev, PMC_FSM, 0x02); // Enable Loader Data Keep + + + EEPROMId = eprom_read(dev, 0); //first read EEPROM ID out; + RT_TRACE(COMP_EPROM, "EEPROM ID is 0x%x\n", EEPROMId); + + if (EEPROMId != RTL8190_EEPROM_ID) + { + priv->AutoloadFailFlag = true; + RT_TRACE(COMP_ERR, "EEPROM ID is invalid(is 0x%x(should be 0x%x)\n", EEPROMId, RTL8190_EEPROM_ID); + } + else + { + priv->AutoloadFailFlag = false; + bLoad_From_EEPOM = true; + } + + if (bLoad_From_EEPOM) + { + tmpValue = eprom_read(dev, (EEPROM_VID>>1)); + priv->eeprom_vid = endian_swap(&tmpValue); + priv->eeprom_pid = eprom_read(dev, (EEPROM_PID>>1)); + + // Version ID, Channel plan + tmpValue = eprom_read(dev, (EEPROM_Version>>1)); + //pHalData->card_8192_version = (VERSION_8192S)((usValue&0x00ff)); + priv->eeprom_ChannelPlan =(tmpValue&0xff00)>>8; + priv->bTXPowerDataReadFromEEPORM = true; + + // Customer ID, 0x00 and 0xff are reserved for Realtek. + tmpValue = eprom_read(dev, (u16)(EEPROM_CustomID>>1)) ; + priv->eeprom_CustomerID = (u8)( tmpValue & 0xff); + priv->eeprom_SubCustomerID = (u8)((tmpValue & 0xff00)>>8); + } + else + { + priv->eeprom_vid = 0; + priv->eeprom_pid = 0; + //priv->card_8192_version = VERSION_8192SU_A; + priv->eeprom_ChannelPlan = 0; + priv->eeprom_CustomerID = 0; + priv->eeprom_SubCustomerID = 0; + } + RT_TRACE(COMP_EPROM, "vid:0x%4x, pid:0x%4x, CustomID:0x%2x, ChanPlan:0x%x\n", priv->eeprom_vid, priv->eeprom_pid, priv->eeprom_CustomerID, priv->eeprom_ChannelPlan); + //set channelplan from eeprom + priv->ChannelPlan = priv->eeprom_ChannelPlan;// FIXLZM + + RT_TRACE(COMP_INIT, "EEPROMId = 0x%4x\n", EEPROMId); + RT_TRACE(COMP_INIT, "EEPROM VID = 0x%4x\n", priv->eeprom_vid); + RT_TRACE(COMP_INIT, "EEPROM PID = 0x%4x\n", priv->eeprom_pid); + //RT_TRACE(COMP_INIT, DBG_LOUD, ("EEPROM Version ID: 0x%2x\n", pHalData->VersionID)); + RT_TRACE(COMP_INIT, "EEPROM Customer ID: 0x%2x\n", priv->eeprom_CustomerID); + RT_TRACE(COMP_INIT, "EEPROM SubCustomer ID: 0x%2x\n", priv->eeprom_SubCustomerID); + RT_TRACE(COMP_INIT, "EEPROM ChannelPlan = 0x%4x\n", priv->eeprom_ChannelPlan); + + // Read USB optional function. + if(bLoad_From_EEPOM) + { + tmpValue = eprom_read(dev, (EEPROM_USB_OPTIONAL>>1)); + priv->EEPROMUsbOption = (u8)(tmpValue&0xff); + } + else + { + priv->EEPROMUsbOption = EEPROM_USB_Default_OPTIONAL_FUNC; + } + + RT_TRACE(COMP_INIT, "USB Option = %#x\n", priv->EEPROMUsbOption); + + + if (bLoad_From_EEPOM) + { + int i; + for (i=0; i<6; i+=2) + { + u16 tmp = 0; + tmp = eprom_read(dev, (u16)((EEPROM_NODE_ADDRESS_BYTE_0 + i)>>1)); + *(u16*)(&dev->dev_addr[i]) = tmp; + } + } + else + { + // In this case, we random assigh MAC address here. 2008.10.15. + static u8 sMacAddr[6] = {0x00, 0xE0, 0x4C, 0x81, 0x92, 0x00}; + u8 i; + + //sMacAddr[5] = (u8)GetRandomNumber(1, 254); + + for(i = 0; i < 6; i++) + dev->dev_addr[i] = sMacAddr[i]; + + //memcpy(dev->dev_addr, sMacAddr, 6); + //should I set IDR0 here? + } + write_nic_dword(dev, IDR0, ((u32*)dev->dev_addr)[0]); + write_nic_word(dev, IDR4, ((u16*)(dev->dev_addr + 4))[0]); + RT_TRACE(COMP_EPROM, "MAC addr:"MAC_FMT"\n", MAC_ARG(dev->dev_addr)); + + priv->rf_type = RTL819X_DEFAULT_RF_TYPE; //default 1T2R +#if (defined (RTL8192SU_FPGA_2MAC_VERIFICATION)||defined (RTL8192SU_ASIC_VERIFICATION)) + priv->rf_chip = RF_6052; + priv->rf_type = RTL819X_DEFAULT_RF_TYPE; + //priv->card_8192_version = VERSION_8192SU_A; //Over write for temporally experiment. 2008.10.16. By Roger. +#else + priv->rf_chip = RF_8256; +#endif + + { +#if 0 + if(bLoad_From_EEPOM) + { + tempval = (ReadEEprom(Adapter, (EEPROM_RFInd_PowerDiff>>1))) & 0xff; + if (tempval&0x80) //RF-indication, bit[7] + pHalData->RF_Type = RF_1T2R; + else + pHalData->RF_Type = RF_2T4R; + } +#endif + + priv->EEPROMTxPowerDiff = EEPROM_Default_TxPowerDiff; + RT_TRACE(COMP_INIT, "TxPowerDiff = %#x\n", priv->EEPROMTxPowerDiff); + + + // + // Read antenna tx power offset of B/C/D to A from EEPROM + // and read ThermalMeter from EEPROM + // + if(bLoad_From_EEPOM) + { + tmpValue = eprom_read(dev, (EEPROM_PwDiff>>1)); + priv->EEPROMPwDiff = tmpValue&0x00ff; + priv->EEPROMThermalMeter = (tmpValue&0xff00)>>8; + } + else + { + priv->EEPROMPwDiff = EEPROM_Default_PwDiff; + priv->EEPROMThermalMeter = EEPROM_Default_ThermalMeter; + } + RT_TRACE(COMP_INIT, "PwDiff = %#x\n", priv->EEPROMPwDiff); + RT_TRACE(COMP_INIT, "ThermalMeter = %#x\n", priv->EEPROMThermalMeter); + + priv->TSSI_13dBm = priv->EEPROMThermalMeter *100; + + + // Read CrystalCap from EEPROM + if(bLoad_From_EEPOM) + { + priv->EEPROMCrystalCap =(u8) (((eprom_read(dev, (EEPROM_CrystalCap>>1)))&0xf000)>>12); + } + else + { + priv->EEPROMCrystalCap = EEPROM_Default_CrystalCap; + } + RT_TRACE(COMP_INIT, "CrystalCap = %#x\n", priv->EEPROMCrystalCap); + + + //if(pHalData->EEPROM_Def_Ver == 0) // old eeprom definition + { + + // + // Get Tx Power Base.//===> + // + if(bLoad_From_EEPOM) + { + priv->EEPROMTxPwrBase =(u8) ((eprom_read(dev, (EEPROM_TxPowerBase>>1)))&0xff); + } + else + { + priv->EEPROMTxPwrBase = EEPROM_Default_TxPowerBase; + } + + RT_TRACE(COMP_INIT, "TxPwrBase = %#x\n", priv->EEPROMTxPwrBase); + + // + // Get CustomerID(Boad Type) + // i.e., 0x0: RTL8188SU, 0x1: RTL8191SU, 0x2: RTL8192SU, 0x3: RTL8191GU. + // Others: Reserved. Default is 0x2: RTL8192SU. + // + if(bLoad_From_EEPOM) + { + tmpValue = eprom_read(dev, (u16) (EEPROM_BoardType>>1)); + priv->EEPROMBoardType = (u8)(tmpValue&0xff); + } + else + { + priv->EEPROMBoardType = EEPROM_Default_BoardType; + } + + RT_TRACE(COMP_INIT, "BoardType = %#x\n", priv->EEPROMBoardType); + +#ifdef EEPROM_OLD_FORMAT_SUPPORT + + // + // Buffer TxPwIdx(i.e., from offset 0x58~0x75, total 30Bytes) + // + if(bLoad_From_EEPOM) + { + for(i = 0; i < 30; i += 2) + { + tmpValue = eprom_read(dev, (u16) ((EEPROM_TxPowerBase+i)>>1)); + *((u16 *)(&tmpBuffer[i])) = tmpValue; + } + } + + // + // Update CCK, OFDM Tx Power Index from above buffer. + // + if(bLoad_From_EEPOM) + { + for(i=0; i<14; i++) + { + priv->EEPROMTxPowerLevelCCK24G[i] = (u8)tmpBuffer[i+1]; + priv->EEPROMTxPowerLevelOFDM24G[i] = (u8)tmpBuffer[i+15]; + } + + } + else + { + for(i=0; i<14; i++) + { + priv->EEPROMTxPowerLevelCCK24G[i] = (u8)(EEPROM_Default_TxPower & 0xff); + priv->EEPROMTxPowerLevelOFDM24G[i] = (u8)(EEPROM_Default_TxPower & 0xff); + } + } + + for(i=0; i<14; i++) + { + RT_TRACE(COMP_INIT, "CCK 2.4G Tx Power Level, Index %d = 0x%02x\n", i, priv->EEPROMTxPowerLevelCCK24G[i]); + RT_TRACE(COMP_INIT, "OFDM 2.4G Tx Power Level, Index %d = 0x%02x\n", i, priv->EEPROMTxPowerLevelOFDM24G[i]); + } +#else + // Please add code in the section!!!! + // And merge tx power difference section. +#endif + + // + // Get TSSI value for each path. + // + if(bLoad_From_EEPOM) + { + tmpValue = eprom_read(dev, (u16) ((EEPROM_TSSI_A)>>1)); + priv->EEPROMTSSI_A = (u8)((tmpValue&0xff00)>>8); + } + else + { // Default setting for Empty EEPROM + priv->EEPROMTSSI_A = EEPROM_Default_TSSI; + } + + if(bLoad_From_EEPOM) + { + tmpValue = eprom_read(dev, (u16) ((EEPROM_TSSI_B)>>1)); + priv->EEPROMTSSI_B = (u8)(tmpValue&0xff); + priv->EEPROMTxPwrTkMode = (u8)((tmpValue&0xff00)>>8); + } + else + { // Default setting for Empty EEPROM + priv->EEPROMTSSI_B = EEPROM_Default_TSSI; + priv->EEPROMTxPwrTkMode = EEPROM_Default_TxPwrTkMode; + } + + RT_TRACE(COMP_INIT, "TSSI_A = %#x, TSSI_B = %#x\n", priv->EEPROMTSSI_A, priv->EEPROMTSSI_B); + RT_TRACE(COMP_INIT, "TxPwrTkMod = %#x\n", priv->EEPROMTxPwrTkMode); + +#ifdef EEPROM_OLD_FORMAT_SUPPORT + // + // Get HT 2T Path A and B Power Index. + // + if(bLoad_From_EEPOM) + { + for(i = 0; i < 6; i += 2) + { + tmpValue = eprom_read(dev, (u16) ((EEPROM_HT2T_CH1_A+i)>>1)); + *((u16*)(&priv->EEPROMHT2T_TxPwr[i])) = tmpValue; + } + } + else + { // Default setting for Empty EEPROM + for(i=0; i<6; i++) + { + priv->EEPROMHT2T_TxPwr[i] = EEPROM_Default_HT2T_TxPwr; + } + } + + for(i=0; i<6; i++) + { + RT_TRACE(COMP_INIT, "EEPROMHT2T_TxPwr, Index %d = 0x%02x\n", i, priv->EEPROMHT2T_TxPwr[i]); + } +#else + +#endif + } + +#ifdef EEPROM_OLD_FORMAT_SUPPORT + // + // Update HAL variables. + // + for(i=0; i<14; i++) + { + priv->TxPowerLevelOFDM24G[i] = priv->EEPROMTxPowerLevelOFDM24G[i]; + priv->TxPowerLevelCCK[i] = priv->EEPROMTxPowerLevelCCK24G[i]; + } +#else + +#endif + priv->TxPowerDiff = priv->EEPROMPwDiff; + // Antenna B gain offset to antenna A, bit0~3 + priv->AntennaTxPwDiff[0] = (priv->EEPROMTxPowerDiff & 0xf); + // Antenna C gain offset to antenna A, bit4~7 + priv->AntennaTxPwDiff[1] = ((priv->EEPROMTxPowerDiff & 0xf0)>>4); + // CrystalCap, bit12~15 + priv->CrystalCap = priv->EEPROMCrystalCap; + // ThermalMeter, bit0~3 for RFIC1, bit4~7 for RFIC2 + // 92U does not enable TX power tracking. + priv->ThermalMeter[0] = priv->EEPROMThermalMeter; + } + + priv->LedStrategy = SW_LED_MODE0; + + if(priv->rf_type == RF_1T2R) + { + RT_TRACE(COMP_EPROM, "\n1T2R config\n"); + } + else + { + RT_TRACE(COMP_EPROM, "\n2T4R config\n"); + } + + // 2008/01/16 MH We can only know RF type in the function. So we have to init + // DIG RATR table again. + init_rate_adaptive(dev); + //we need init DIG RATR table here again. + + RT_TRACE(COMP_EPROM, "<===========%s()\n", __FUNCTION__); + return; +} + +// +// Description: +// 1. Read HW adapter information by E-Fuse. +// 2. Refered from SD1 Richard. +// +// Assumption: +// 1. Boot from E-Fuse and CR9346 regiser has verified. +// 2. PASSIVE_LEVEL (USB interface) +// +// Created by Roger, 2008.10.21. +// +void +rtl8192SU_ReadAdapterInfo8192SEFuse(struct net_device* dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + u16 i,usValue; + u16 EEPROMId; + u8 readbyte; + u8 OFDMTxPwr[14]; + u8 CCKTxPwr[14]; + u8 HT2T_TxPwr[6]; + u8 UsbPhyParam[5]; + u8 hwinfo[HWSET_MAX_SIZE_92S]; + + + RT_TRACE(COMP_INIT, "====> ReadAdapterInfo8192SEFuse\n"); + + // + // We set Isolation signals from Loader and reset EEPROM after system resuming + // from suspend mode. + // 2008.10.21. + // + write_nic_byte(dev, SYS_ISO_CTRL+1, 0xE8); // Isolation signals from Loader + //PlatformStallExecution(10000); + mdelay(10); + write_nic_byte(dev, SYS_FUNC_EN+1, 0x40); + write_nic_byte(dev, SYS_FUNC_EN+1, 0x50); + + readbyte = read_nic_byte(dev, EFUSE_TEST+3); + write_nic_byte(dev, EFUSE_TEST+3, (readbyte | 0x80)); + write_nic_byte(dev, EFUSE_TEST+3, 0x72); + write_nic_byte(dev, EFUSE_CLK, 0x03); + + // + // Dump EFUSe at init time for later use + // + // Read EFUSE real map to shadow!! + EFUSE_ShadowMapUpdate(dev); + + memcpy(hwinfo, (void*)&priv->EfuseMap[EFUSE_INIT_MAP][0], HWSET_MAX_SIZE_92S); + //RT_PRINT_DATA(COMP_INIT, DBG_LOUD, ("MAP \n"), hwinfo, HWSET_MAX_SIZE_92S); + + // + // Event though CR9346 regiser can verify whether Autoload is success or not, but we still + // double check ID codes for 92S here(e.g., due to HW GPIO polling fail issue). + // 2008.10.21. + // + ReadEFuse(dev, 0, 2, (unsigned char*) &EEPROMId); + + if( EEPROMId != RTL8190_EEPROM_ID ) + { + RT_TRACE(COMP_INIT, "EEPROM ID(%#x) is invalid!!\n", EEPROMId); + priv->AutoloadFailFlag=true; + } + else + { + priv->AutoloadFailFlag=false; + } + + // Read IC Version && Channel Plan + if(!priv->AutoloadFailFlag) + { + + // VID, PID + ReadEFuse(dev, EEPROM_VID, 2, (unsigned char*) &priv->eeprom_vid); + ReadEFuse(dev, EEPROM_PID, 2, (unsigned char*) &priv->eeprom_pid); + + // Version ID, Channel plan + ReadEFuse(dev, EEPROM_Version, 2, (unsigned char*) &usValue); + //pHalData->VersionID = (VERSION_8192S)(usValue&0x00ff); + priv->eeprom_ChannelPlan = (usValue&0xff00>>8); + priv->bTXPowerDataReadFromEEPORM = true; + + // Customer ID, 0x00 and 0xff are reserved for Realtek. + ReadEFuse(dev, EEPROM_CustomID, 2, (unsigned char*) &usValue); + priv->eeprom_CustomerID = (u8)( usValue & 0xff); + priv->eeprom_SubCustomerID = (u8)((usValue & 0xff00)>>8); + } + else + { + priv->eeprom_vid = 0; + priv->eeprom_pid = 0; + priv->eeprom_ChannelPlan = 0; + priv->eeprom_CustomerID = 0; + priv->eeprom_SubCustomerID = 0; + } + + RT_TRACE(COMP_INIT, "EEPROM Id = 0x%4x\n", EEPROMId); + RT_TRACE(COMP_INIT, "EEPROM VID = 0x%4x\n", priv->eeprom_vid); + RT_TRACE(COMP_INIT, "EEPROM PID = 0x%4x\n", priv->eeprom_pid); + //RT_TRACE(COMP_INIT, DBG_LOUD, ("EEPROM Version ID: 0x%2x\n", pHalData->VersionID)); + RT_TRACE(COMP_INIT, "EEPROM Customer ID: 0x%2x\n", priv->eeprom_CustomerID); + RT_TRACE(COMP_INIT, "EEPROM SubCustomer ID: 0x%2x\n", priv->eeprom_SubCustomerID); + RT_TRACE(COMP_INIT, "EEPROM ChannelPlan = 0x%4x\n", priv->eeprom_ChannelPlan); + + + // Read USB optional function. + if(!priv->AutoloadFailFlag) + { + ReadEFuse(dev, EEPROM_USB_OPTIONAL, 1, (unsigned char*) &priv->EEPROMUsbOption); + } + else + { + priv->EEPROMUsbOption = EEPROM_USB_Default_OPTIONAL_FUNC; + } + + RT_TRACE(COMP_INIT, "USB Option = %#x\n", priv->EEPROMUsbOption); + + + // Read USB PHY parameters. + if(!priv->AutoloadFailFlag) + { + ReadEFuse(dev, EEPROM_USB_PHY_PARA1, 5, (unsigned char*)UsbPhyParam); + for(i=0; i<5; i++) + { + priv->EEPROMUsbPhyParam[i] = UsbPhyParam[i]; + RT_TRACE(COMP_INIT, "USB Param = index(%d) = %#x\n", i, priv->EEPROMUsbPhyParam[i]); + } + } + else + { + for(i=0; i<5; i++) + { + priv->EEPROMUsbPhyParam[i] = EEPROM_USB_Default_PHY_PARAM; + RT_TRACE(COMP_INIT, "USB Param = index(%d) = %#x\n", i, priv->EEPROMUsbPhyParam[i]); + } + } + + + //Read Permanent MAC address + if(!priv->AutoloadFailFlag) + { + u8 macaddr[6] = {0x00, 0xe1, 0x86, 0x4c, 0x92, 0x00}; + + ReadEFuse(dev, EEPROM_NODE_ADDRESS_BYTE_0, 6, (unsigned char*)macaddr); + for(i=0; i<6; i++) + dev->dev_addr[i] = macaddr[i]; + } + else + {//Auto load fail + + // In this case, we random assigh MAC address here. 2008.10.15. + static u8 sMacAddr[6] = {0x00, 0xE0, 0x4C, 0x81, 0x92, 0x00}; + u8 i; + + //if(!Adapter->bInHctTest) + //sMacAddr[5] = (u8)GetRandomNumber(1, 254); + + for(i = 0; i < 6; i++) + dev->dev_addr[i] = sMacAddr[i]; + } + + //NicIFSetMacAddress(Adapter, Adapter->PermanentAddress); + write_nic_dword(dev, IDR0, ((u32*)dev->dev_addr)[0]); + write_nic_word(dev, IDR4, ((u16*)(dev->dev_addr + 4))[0]); + + RT_TRACE(COMP_INIT, "ReadAdapterInfo8192SEFuse(), Permanent Address = %02x-%02x-%02x-%02x-%02x-%02x\n", + dev->dev_addr[0], dev->dev_addr[1], + dev->dev_addr[2], dev->dev_addr[3], + dev->dev_addr[4], dev->dev_addr[5]); + + // 2007/11/15 MH For RTL8192USB we assign as 1T2R now. + priv->rf_type = RTL819X_DEFAULT_RF_TYPE; // default : 1T2R + +#if (defined (RTL8192SU_FPGA_2MAC_VERIFICATION)||defined (RTL8192SU_ASIC_VERIFICATION)) + priv->rf_chip = RF_6052; + priv->rf_type = RTL819X_DEFAULT_RF_TYPE; +#else + priv->rf_chip = RF_8256; +#endif + + { + // + // Read antenna tx power offset of B/C/D to A from EEPROM + // and read ThermalMeter from EEPROM + // + if(!priv->AutoloadFailFlag) + { + ReadEFuse(dev, EEPROM_PwDiff, 2, (unsigned char*) &usValue); + priv->EEPROMPwDiff = usValue&0x00ff; + priv->EEPROMThermalMeter = (usValue&0xff00)>>8; + } + else + { + priv->EEPROMPwDiff = EEPROM_Default_PwDiff; + priv->EEPROMThermalMeter = EEPROM_Default_ThermalMeter; + } + + RT_TRACE(COMP_INIT, "PwDiff = %#x\n", priv->EEPROMPwDiff); + RT_TRACE(COMP_INIT, "ThermalMeter = %#x\n", priv->EEPROMThermalMeter); + + priv->TSSI_13dBm = priv->EEPROMThermalMeter *100; + + // + // Read Tx Power gain offset of legacy OFDM to HT rate. + // Read CrystalCap from EEPROM + // + if(!priv->AutoloadFailFlag) + { + ReadEFuse(dev, EEPROM_CrystalCap, 1, (unsigned char*) &usValue); + priv->EEPROMCrystalCap = (u8)((usValue&0xf0)>>4); + } + else + { + priv->EEPROMCrystalCap = EEPROM_Default_CrystalCap; + } + + RT_TRACE(COMP_INIT, "CrystalCap = %#x\n", priv->EEPROMCrystalCap); + + priv->EEPROMTxPowerDiff = EEPROM_Default_TxPowerDiff; + RT_TRACE(COMP_INIT, "TxPowerDiff = %d\n", priv->EEPROMTxPowerDiff); + + + // + // Get Tx Power Base. + // + if(!priv->AutoloadFailFlag) + { + ReadEFuse(dev, EEPROM_TxPowerBase, 1, (unsigned char*) &priv->EEPROMTxPwrBase ); + } + else + { + priv->EEPROMTxPwrBase = EEPROM_Default_TxPowerBase; + } + + RT_TRACE(COMP_INIT, "TxPwrBase = %#x\n", priv->EEPROMTxPwrBase); + + // + // Get CustomerID(Boad Type) + // i.e., 0x0: RTL8188SU, 0x1: RTL8191SU, 0x2: RTL8192SU, 0x3: RTL8191GU. + // Others: Reserved. Default is 0x2: RTL8192SU. + // + if(!priv->AutoloadFailFlag) + { + ReadEFuse(dev, EEPROM_BoardType, 1, (unsigned char*) &priv->EEPROMBoardType ); + } + else + { + priv->EEPROMBoardType = EEPROM_Default_BoardType; + } + + RT_TRACE(COMP_INIT, "BoardType = %#x\n", priv->EEPROMBoardType); + + //if(pHalData->EEPROM_Def_Ver == 0) + { +#ifdef EEPROM_OLD_FORMAT_SUPPORT + // + // Get CCK Tx Power Index. + // + if(!priv->AutoloadFailFlag) + { + ReadEFuse(dev, EEPROM_TxPwIndex_CCK_24G, 14, (unsigned char*)CCKTxPwr); + for(i=0; i<14; i++) + { + RT_TRACE(COMP_INIT, "CCK 2.4G Tx Power Level, Index %d = 0x%02x\n", i, CCKTxPwr[i]); + priv->EEPROMTxPowerLevelCCK24G[i] = CCKTxPwr[i]; + } + } + else + { // Default setting for Empty EEPROM + for(i=0; i<14; i++) + priv->EEPROMTxPowerLevelCCK24G[i] = (u8)(EEPROM_Default_TxPower & 0xff); + } + + // + // Get OFDM Tx Power Index. + // + if(!priv->AutoloadFailFlag) + { + ReadEFuse(dev, EEPROM_TxPwIndex_OFDM_24G, 14, (unsigned char*)OFDMTxPwr); + for(i=0; i<14; i++) + { + RT_TRACE(COMP_INIT, "OFDM 2.4G Tx Power Level, Index %d = 0x%02x\n", i, OFDMTxPwr[i]); + priv->EEPROMTxPowerLevelOFDM24G[i] = OFDMTxPwr[i]; + } + } + else + { // Default setting for Empty EEPROM + usValue = 0x10; + for(i=0; i<14; i++) + priv->EEPROMTxPowerLevelOFDM24G[i] = (u8)usValue; + } +#else + // Please add code in the section!!!! + // And merge tx power difference section. +#endif + + // + // Get TSSI value for each path. + // + if(!priv->AutoloadFailFlag) + { + ReadEFuse(dev, EEPROM_TSSI_A, 2, (unsigned char*)&usValue); + priv->EEPROMTSSI_A = (u8)(usValue&0xff); + priv->EEPROMTSSI_B = (u8)((usValue&0xff00)>>8); + } + else + { // Default setting for Empty EEPROM + priv->EEPROMTSSI_A = EEPROM_Default_TSSI; + priv->EEPROMTSSI_B = EEPROM_Default_TSSI; + } + + RT_TRACE(COMP_INIT, "TSSI_A = %#x, TSSI_B = %#x\n", + priv->EEPROMTSSI_A, priv->EEPROMTSSI_B); + + // + // Get Tx Power tracking mode. + // + if(!priv->AutoloadFailFlag) + { + ReadEFuse(dev, EEPROM_TxPwTkMode, 1, (unsigned char*)&priv->EEPROMTxPwrTkMode); + } + else + { // Default setting for Empty EEPROM + priv->EEPROMTxPwrTkMode = EEPROM_Default_TxPwrTkMode; + } + + RT_TRACE(COMP_INIT, "TxPwrTkMod = %#x\n", priv->EEPROMTxPwrTkMode); + + + // TODO: The following HT 2T Path A and B Power Index should be updated.!! Added by Roger, 2008.20.23. + + // + // Get HT 2T Path A and B Power Index. + // + if(!priv->AutoloadFailFlag) + { + ReadEFuse(dev, EEPROM_HT2T_CH1_A, 6, (unsigned char*)HT2T_TxPwr); + for(i=0; i<6; i++) + { + priv->EEPROMHT2T_TxPwr[i] = HT2T_TxPwr[i]; + } + } + else + { // Default setting for Empty EEPROM + for(i=0; i<6; i++) + { + priv->EEPROMHT2T_TxPwr[i] = EEPROM_Default_HT2T_TxPwr; + } + } + + for(i=0; i<6; i++) + { + RT_TRACE(COMP_INIT, "EEPROMHT2T_TxPwr, Index %d = 0x%02x\n", + i, priv->EEPROMHT2T_TxPwr[i]); + } + } + +#ifdef EEPROM_OLD_FORMAT_SUPPORT + // + // Update HAL variables. + // + for(i=0; i<14; i++) + { + priv->TxPowerLevelOFDM24G[i] = priv->EEPROMTxPowerLevelOFDM24G[i]; + priv->TxPowerLevelCCK[i] = priv->EEPROMTxPowerLevelCCK24G[i]; + } +#else + +#endif + priv->TxPowerDiff = priv->EEPROMPwDiff; + // Antenna B gain offset to antenna A, bit0~3 + priv->AntennaTxPwDiff[0] = (priv->EEPROMTxPowerDiff & 0xf); + // Antenna C gain offset to antenna A, bit4~7 + priv->AntennaTxPwDiff[1] = ((priv->EEPROMTxPowerDiff & 0xf0)>>4); + // CrystalCap, bit12~15 + priv->CrystalCap = priv->EEPROMCrystalCap; + // ThermalMeter, bit0~3 for RFIC1, bit4~7 for RFIC2 + // 92U does not enable TX power tracking. + priv->ThermalMeter[0] = priv->EEPROMThermalMeter; + } + + priv->LedStrategy = SW_LED_MODE0; + + init_rate_adaptive(dev); + + RT_TRACE(COMP_INIT, "<==== ReadAdapterInfo8192SEFuse\n"); + +} +#endif + +// +// Description: +// Read HW adapter information by E-Fuse or EEPROM according CR9346 reported. +// +// Assumption: +// 1. CR9346 regiser has verified. +// 2. PASSIVE_LEVEL (USB interface) +// +// Created by Roger, 2008.10.21. +// +void +rtl8192SU_ReadAdapterInfo8192SUsb(struct net_device* dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + u16 i,usValue; + u8 tmpU1b, tempval; + u16 EEPROMId; + u8 hwinfo[HWSET_MAX_SIZE_92S]; + u8 rf_path, index; // For EEPROM/EFUSE After V0.6_1117 + + + RT_TRACE(COMP_INIT, "====> ReadAdapterInfo8192SUsb\n"); + + // + // The following operation are prevent Efuse leakage by turn on 2.5V. + // 2008.11.25. + // + tmpU1b = read_nic_byte(dev, EFUSE_TEST+3); + write_nic_byte(dev, EFUSE_TEST+3, tmpU1b|0x80); + //PlatformStallExecution(1000); + mdelay(10); + write_nic_byte(dev, EFUSE_TEST+3, (tmpU1b&(~BIT7))); + + // Retrieve Chip version. + priv->card_8192_version = (VERSION_8192S)((read_nic_dword(dev, PMC_FSM)>>16)&0xF); + RT_TRACE(COMP_INIT, "Chip Version ID: 0x%2x\n", priv->card_8192_version); + + switch(priv->card_8192_version) + { + case 0: + RT_TRACE(COMP_INIT, "Chip Version ID: VERSION_8192S_ACUT.\n"); + break; + case 1: + RT_TRACE(COMP_INIT, "Chip Version ID: VERSION_8192S_BCUT.\n"); + break; + case 2: + RT_TRACE(COMP_INIT, "Chip Version ID: VERSION_8192S_CCUT.\n"); + break; + default: + RT_TRACE(COMP_INIT, "Unknown Chip Version!!\n"); + priv->card_8192_version = VERSION_8192S_BCUT; + break; + } + + //if (IS_BOOT_FROM_EEPROM(Adapter)) + if(priv->EepromOrEfuse) + { // Read frin EEPROM + write_nic_byte(dev, SYS_ISO_CTRL+1, 0xE8); // Isolation signals from Loader + //PlatformStallExecution(10000); + mdelay(10); + write_nic_byte(dev, PMC_FSM, 0x02); // Enable Loader Data Keep + // Read all Content from EEPROM or EFUSE. + for(i = 0; i < HWSET_MAX_SIZE_92S; i += 2) + { + usValue = eprom_read(dev, (u16) (i>>1)); + *((u16*)(&hwinfo[i])) = usValue; + } + } + else if (!(priv->EepromOrEfuse)) + { // Read from EFUSE + + // + // We set Isolation signals from Loader and reset EEPROM after system resuming + // from suspend mode. + // 2008.10.21. + // + //PlatformEFIOWrite1Byte(Adapter, SYS_ISO_CTRL+1, 0xE8); // Isolation signals from Loader + //PlatformStallExecution(10000); + //PlatformEFIOWrite1Byte(Adapter, SYS_FUNC_EN+1, 0x40); + //PlatformEFIOWrite1Byte(Adapter, SYS_FUNC_EN+1, 0x50); + + //tmpU1b = PlatformEFIORead1Byte(Adapter, EFUSE_TEST+3); + //PlatformEFIOWrite1Byte(Adapter, EFUSE_TEST+3, (tmpU1b | 0x80)); + //PlatformEFIOWrite1Byte(Adapter, EFUSE_TEST+3, 0x72); + //PlatformEFIOWrite1Byte(Adapter, EFUSE_CLK, 0x03); + + // Read EFUSE real map to shadow. + EFUSE_ShadowMapUpdate(dev); + memcpy(hwinfo, &priv->EfuseMap[EFUSE_INIT_MAP][0], HWSET_MAX_SIZE_92S); + } + else + { + RT_TRACE(COMP_INIT, "ReadAdapterInfo8192SUsb(): Invalid boot type!!\n"); + } + + //YJ,test,090106 + //dump_buf(hwinfo,HWSET_MAX_SIZE_92S); + // + // The following are EFUSE/EEPROM independent operations!! + // + //RT_PRINT_DATA(COMP_EFUSE, DBG_LOUD, ("MAP: \n"), hwinfo, HWSET_MAX_SIZE_92S); + + // + // Event though CR9346 regiser can verify whether Autoload is success or not, but we still + // double check ID codes for 92S here(e.g., due to HW GPIO polling fail issue). + // 2008.10.21. + // + EEPROMId = *((u16 *)&hwinfo[0]); + + if( EEPROMId != RTL8190_EEPROM_ID ) + { + RT_TRACE(COMP_INIT, "ID(%#x) is invalid!!\n", EEPROMId); + priv->bTXPowerDataReadFromEEPORM = FALSE; + priv->AutoloadFailFlag=TRUE; + } + else + { + priv->AutoloadFailFlag=FALSE; +#if RTL8192SU_USE_PARAM_TXPWR + priv->bTXPowerDataReadFromEEPORM = FALSE; +#else + priv->bTXPowerDataReadFromEEPORM = TRUE; +#endif + + } + // Read IC Version && Channel Plan + if(!priv->AutoloadFailFlag) + { + // VID, PID + priv->eeprom_vid = *(u16 *)&hwinfo[EEPROM_VID]; + priv->eeprom_pid = *(u16 *)&hwinfo[EEPROM_PID]; + priv->bIgnoreDiffRateTxPowerOffset = false; //cosa for test + + + // EEPROM Version ID, Channel plan + priv->EEPROMVersion = *(u8 *)&hwinfo[EEPROM_Version]; + priv->eeprom_ChannelPlan = *(u8 *)&hwinfo[EEPROM_ChannelPlan]; + + // Customer ID, 0x00 and 0xff are reserved for Realtek. + priv->eeprom_CustomerID = *(u8 *)&hwinfo[EEPROM_CustomID]; + priv->eeprom_SubCustomerID = *(u8 *)&hwinfo[EEPROM_SubCustomID]; + } + else + { + //priv->eeprom_vid = 0; + //priv->eeprom_pid = 0; + //priv->EEPROMVersion = 0; + //priv->eeprom_ChannelPlan = 0; + //priv->eeprom_CustomerID = 0; + //priv->eeprom_SubCustomerID = 0; + + rtl8192SU_ConfigAdapterInfo8192SForAutoLoadFail(dev); + return; + } + + + RT_TRACE(COMP_INIT, "EEPROM Id = 0x%4x\n", EEPROMId); + RT_TRACE(COMP_INIT, "EEPROM VID = 0x%4x\n", priv->eeprom_vid); + RT_TRACE(COMP_INIT, "EEPROM PID = 0x%4x\n", priv->eeprom_pid); + RT_TRACE(COMP_INIT, "EEPROM Version ID: 0x%2x\n", priv->EEPROMVersion); + RT_TRACE(COMP_INIT, "EEPROM Customer ID: 0x%2x\n", priv->eeprom_CustomerID); + RT_TRACE(COMP_INIT, "EEPROM SubCustomer ID: 0x%2x\n", priv->eeprom_SubCustomerID); + RT_TRACE(COMP_INIT, "EEPROM ChannelPlan = 0x%4x\n", priv->eeprom_ChannelPlan); + RT_TRACE(COMP_INIT, "bIgnoreDiffRateTxPowerOffset = %d\n", priv->bIgnoreDiffRateTxPowerOffset); + + + // Read USB optional function. + if(!priv->AutoloadFailFlag) + { + priv->EEPROMUsbOption = *(u8 *)&hwinfo[EEPROM_USB_OPTIONAL]; + } + else + { + priv->EEPROMUsbOption = EEPROM_USB_Default_OPTIONAL_FUNC; + } + + + priv->EEPROMUsbEndPointNumber = rtl8192SU_UsbOptionToEndPointNumber((priv->EEPROMUsbOption&EEPROM_EP_NUMBER)>>3); + + RT_TRACE(COMP_INIT, "USB Option = %#x\n", priv->EEPROMUsbOption); + RT_TRACE(COMP_INIT, "EndPoint Number = %#x\n", priv->EEPROMUsbEndPointNumber); + +#ifdef TO_DO_LIST + // + // Decide CustomerID according to VID/DID or EEPROM + // + switch(pHalData->EEPROMCustomerID) + { + case EEPROM_CID_ALPHA: + pMgntInfo->CustomerID = RT_CID_819x_ALPHA; + break; + + case EEPROM_CID_CAMEO: + pMgntInfo->CustomerID = RT_CID_819x_CAMEO; + break; + + case EEPROM_CID_SITECOM: + pMgntInfo->CustomerID = RT_CID_819x_Sitecom; + RT_TRACE(COMP_INIT, DBG_LOUD, ("CustomerID = 0x%4x\n", pMgntInfo->CustomerID)); + + break; + + case EEPROM_CID_WHQL: + Adapter->bInHctTest = TRUE; + + pMgntInfo->bSupportTurboMode = FALSE; + pMgntInfo->bAutoTurboBy8186 = FALSE; + + pMgntInfo->PowerSaveControl.bInactivePs = FALSE; + pMgntInfo->PowerSaveControl.bIPSModeBackup = FALSE; + pMgntInfo->PowerSaveControl.bLeisurePs = FALSE; + pMgntInfo->keepAliveLevel = 0; + break; + + default: + pMgntInfo->CustomerID = RT_CID_DEFAULT; + break; + + } + + // + // Led mode + // + switch(pMgntInfo->CustomerID) + { + case RT_CID_DEFAULT: + case RT_CID_819x_ALPHA: + pHalData->LedStrategy = SW_LED_MODE1; + pHalData->bRegUseLed = TRUE; + pHalData->SwLed1.bLedOn = TRUE; + break; + case RT_CID_819x_CAMEO: + pHalData->LedStrategy = SW_LED_MODE1; + pHalData->bRegUseLed = TRUE; + break; + + case RT_CID_819x_Sitecom: + pHalData->LedStrategy = SW_LED_MODE2; + pHalData->bRegUseLed = TRUE; + break; + + default: + pHalData->LedStrategy = SW_LED_MODE0; + break; + } +#endif + + // Read USB PHY parameters. + for(i=0; i<5; i++) + priv->EEPROMUsbPhyParam[i] = *(u8 *)&hwinfo[EEPROM_USB_PHY_PARA1+i]; + + //RT_PRINT_DATA(COMP_EFUSE, DBG_LOUD, ("USB PHY Param: \n"), pHalData->EEPROMUsbPhyParam, 5); + + + //Read Permanent MAC address + for(i=0; i<6; i++) + dev->dev_addr[i] = *(u8 *)&hwinfo[EEPROM_NODE_ADDRESS_BYTE_0+i]; + + //NicIFSetMacAddress(Adapter, Adapter->PermanentAddress); + write_nic_dword(dev, IDR0, ((u32*)dev->dev_addr)[0]); + write_nic_word(dev, IDR4, ((u16*)(dev->dev_addr + 4))[0]); + + RT_TRACE(COMP_INIT, "ReadAdapterInfo8192SEFuse(), Permanent Address = %02x-%02x-%02x-%02x-%02x-%02x\n", + dev->dev_addr[0], dev->dev_addr[1], + dev->dev_addr[2], dev->dev_addr[3], + dev->dev_addr[4], dev->dev_addr[5]); + + // + // Get CustomerID(Boad Type) + // i.e., 0x0: RTL8188SU, 0x1: RTL8191SU, 0x2: RTL8192SU, 0x3: RTL8191GU. + // Others: Reserved. Default is 0x2: RTL8192SU. + // + //if(!priv->AutoloadFailFlag) + //{ + priv->EEPROMBoardType = *(u8 *)&hwinfo[EEPROM_BoardType]; + priv->rf_type = rtl8192SU_BoardTypeToRFtype(dev, priv->EEPROMBoardType); + //} + //else + //{ + // priv->EEPROMBoardType = EEPROM_Default_BoardType; + // priv->rf_type = RF_1T2R; + //} + +#if (defined (RTL8192SU_FPGA_2MAC_VERIFICATION)||defined (RTL8192SU_ASIC_VERIFICATION)) + priv->rf_chip = RF_6052; +#else + priv->rf_chip = RF_8256; +#endif + + priv->rf_chip = RF_6052;//lzm test + RT_TRACE(COMP_INIT, "BoardType = 0x%2x\n", priv->EEPROMBoardType); + RT_TRACE(COMP_INIT, "RF_Type = 0x%2x\n", priv->rf_type); + + // + // Read antenna tx power offset of B/C/D to A from EEPROM + // and read ThermalMeter from EEPROM + // + //if(!priv->AutoloadFailFlag) + { + priv->EEPROMTxPowerDiff = *(u8 *)&hwinfo[EEPROM_PwDiff]; + priv->EEPROMThermalMeter = *(u8 *)&hwinfo[EEPROM_ThermalMeter]; + } + //else + //{ + // priv->EEPROMTxPowerDiff = EEPROM_Default_PwDiff; + // priv->EEPROMThermalMeter = EEPROM_Default_ThermalMeter; + //} + + RT_TRACE(COMP_INIT, "PwDiff = %#x\n", priv->EEPROMTxPowerDiff); + RT_TRACE(COMP_INIT, "ThermalMeter = %#x\n", priv->EEPROMThermalMeter); + + // + // Read Tx Power gain offset of legacy OFDM to HT rate. + // Read CrystalCap from EEPROM + // + //if(!priv->AutoloadFailFlag) + { + priv->EEPROMCrystalCap = *(u8 *)&hwinfo[EEPROM_CrystalCap]; + } + //else + //{ + // priv->EEPROMCrystalCap = EEPROM_Default_CrystalCap; + //} + + RT_TRACE(COMP_INIT, "CrystalCap = %#x\n", priv->EEPROMCrystalCap); + + // + // Get Tx Power Base. + // + //if(!priv->AutoloadFailFlag) + { + priv->EEPROMTxPwrBase = *(u8 *)&hwinfo[EEPROM_TxPowerBase]; + } + //else + //{ + // priv->EEPROMTxPwrBase = EEPROM_Default_TxPowerBase; + //} + + RT_TRACE(COMP_INIT, "TxPwrBase = %#x\n", priv->EEPROMTxPwrBase); + + + // + // Get TSSI value for each path. + // + //if(!priv->AutoloadFailFlag) + { + priv->EEPROMTSSI_A = *(u8 *)&hwinfo[EEPROM_TSSI_A]; + priv->EEPROMTSSI_B = *(u8 *)&hwinfo[EEPROM_TSSI_B]; + } + //else + //{ // Default setting for Empty EEPROM + // priv->EEPROMTSSI_A = EEPROM_Default_TSSI; + // priv->EEPROMTSSI_B = EEPROM_Default_TSSI; + //} + + RT_TRACE(COMP_INIT, "TSSI_A = %#x, TSSI_B = %#x\n", priv->EEPROMTSSI_A, priv->EEPROMTSSI_B); + + // + // Get Tx Power tracking mode. + // + //if(!priv->AutoloadFailFlag) + { + priv->EEPROMTxPwrTkMode = *(u8 *)&hwinfo[EEPROM_TxPwTkMode]; + } + + RT_TRACE(COMP_INIT, "TxPwrTkMod = %#x\n", priv->EEPROMTxPwrTkMode); + + +#ifdef EEPROM_OLD_FORMAT_SUPPORT + + // + // The following settings are EFUSE version dependence. + // So we need to adjust reading offset. + // 2008.11.22. + // + { + // + // Get HT 2T Path A and B Power Index. + // + //if(!priv->AutoloadFailFlag) + { + for(i=0; i<6; i++) + { + priv->EEPROMHT2T_TxPwr[i] = *(u8 *)&hwinfo[EEPROM_HT2T_CH1_A+i]; + } + } + + //RT_PRINT_DATA(COMP_EFUSE, "HT2T TxPwr: \n"), pHalData->EEPROMHT2T_TxPwr, 6); + + // + // Get CCK and OFDM Tx Power Index. + // + //if(!priv->AutoloadFailFlag) + { + for(i=0; i<14; i++) + { + priv->EEPROMTxPowerLevelCCK24G[i] = *(u8 *)&hwinfo[EEPROM_TxPwIndex_CCK_24G+i]; + priv->EEPROMTxPowerLevelOFDM24G[i] = *(u8 *)&hwinfo[EEPROM_TxPwIndex_OFDM_24G+i]; + } + } + + //RT_PRINT_DATA(COMP_EFUSE, DBG_LOUD, ("CCK 2.4G TxPwr: \n"), pHalData->EEPROMTxPowerLevelCCK24G, 14); + //RT_PRINT_DATA(COMP_EFUSE, DBG_LOUD, ("OFDM 2.4G TxPwr: \n"), pHalData->EEPROMTxPowerLevelOFDM24G, 14); + + // + // Update HAL variables. + // + memcpy( priv->TxPowerLevelOFDM24G, priv->EEPROMTxPowerLevelOFDM24G, 14); + memcpy( priv->TxPowerLevelCCK, priv->EEPROMTxPowerLevelCCK24G, 14); + //RT_PRINT_DATA(COMP_EFUSE, DBG_LOUD, ("HAL CCK 2.4G TxPwr: \n"), pHalData->TxPowerLevelCCK, 14); + //RT_PRINT_DATA(COMP_EFUSE, DBG_LOUD, ("HAL OFDM 2.4G TxPwr: \n"), pHalData->TxPowerLevelOFDM24G, 14); + + } +#else // Support new version of EFUSE content, 2008.11.22. + { + // + // Buffer TxPwIdx(i.e., from offset 0x55~0x66, total 18Bytes) + // Update CCK, OFDM (1T/2T)Tx Power Index from above buffer. + // + + // + // Get Tx Power Level by Channel + // + //if(!priv->AutoloadFailFlag) + { + // Read Tx power of Channel 1 ~ 14 from EFUSE. + // 92S suupport RF A & B + for (rf_path = 0; rf_path < 2; rf_path++) + { + for (i = 0; i < 3; i++) + { + // Read CCK RF A & B Tx power + priv->RfCckChnlAreaTxPwr[rf_path][i] = + hwinfo[EEPROM_TxPwIndex+rf_path*3+i]; + + // Read OFDM RF A & B Tx power for 1T + priv->RfOfdmChnlAreaTxPwr1T[rf_path][i] = + hwinfo[EEPROM_TxPwIndex+6+rf_path*3+i]; + + // Read OFDM RF A & B Tx power for 2T + priv->RfOfdmChnlAreaTxPwr2T[rf_path][i] = + hwinfo[EEPROM_TxPwIndex+12+rf_path*3+i]; + } + } + + } +// + // Update Tx Power HAL variables. +// + for (rf_path = 0; rf_path < 2; rf_path++) + { + for (i = 0; i < 3; i++) + { + RT_TRACE((COMP_INIT), "CCK RF-%d CHan_Area-%d = 0x%x\n", rf_path, i, + priv->RfCckChnlAreaTxPwr[rf_path][i]); + RT_TRACE((COMP_INIT), "OFDM-1T RF-%d CHan_Area-%d = 0x%x\n", rf_path, i, + priv->RfOfdmChnlAreaTxPwr1T[rf_path][i]); + RT_TRACE((COMP_INIT), "OFDM-2T RF-%d CHan_Area-%d = 0x%x\n", rf_path, i, priv->RfOfdmChnlAreaTxPwr2T[rf_path][i]); + } + + // Assign dedicated channel tx power + for(i=0; i<14; i++) // channel 1~3 use the same Tx Power Level. + { + if (i < 3) // Cjanel 1-3 + index = 0; + else if (i < 9) // Channel 4-9 + index = 1; + else // Channel 10-14 + index = 2; + + // Record A & B CCK /OFDM - 1T/2T Channel area tx power + priv->RfTxPwrLevelCck[rf_path][i] = + priv->RfCckChnlAreaTxPwr[rf_path][index]; + priv->RfTxPwrLevelOfdm1T[rf_path][i] = + priv->RfOfdmChnlAreaTxPwr1T[rf_path][index]; + priv->RfTxPwrLevelOfdm2T[rf_path][i] = + priv->RfOfdmChnlAreaTxPwr2T[rf_path][index]; + if (rf_path == 0) + { + priv->TxPowerLevelOFDM24G[i] = priv->RfTxPwrLevelOfdm1T[rf_path][i] ; + priv->TxPowerLevelCCK[i] = priv->RfTxPwrLevelCck[rf_path][i]; + } + } + + for(i=0; i<14; i++) + { + RT_TRACE((COMP_INIT), + "Rf-%d TxPwr CH-%d CCK OFDM_1T OFDM_2T= 0x%x/0x%x/0x%x\n", + rf_path, i, priv->RfTxPwrLevelCck[rf_path][i], + priv->RfTxPwrLevelOfdm1T[rf_path][i] , + priv->RfTxPwrLevelOfdm2T[rf_path][i] ); + } + } + } + + // + // 2009/02/09 Cosa add for new EEPROM format + // + for(i=0; i<14; i++) // channel 1~3 use the same Tx Power Level. + { + // Read tx power difference between HT OFDM 20/40 MHZ + if (i < 3) // Cjanel 1-3 + index = 0; + else if (i < 9) // Channel 4-9 + index = 1; + else // Channel 10-14 + index = 2; + + tempval = (*(u8 *)&hwinfo[EEPROM_TX_PWR_HT20_DIFF+index])&0xff; + priv->TxPwrHt20Diff[RF90_PATH_A][i] = (tempval&0xF); + priv->TxPwrHt20Diff[RF90_PATH_B][i] = ((tempval>>4)&0xF); + + // Read OFDM<->HT tx power diff + if (i < 3) // Cjanel 1-3 + tempval = (*(u8 *)&hwinfo[EEPROM_TX_PWR_OFDM_DIFF])&0xff; + else if (i < 9) // Channel 4-9 + tempval = (*(u8 *)&hwinfo[EEPROM_PwDiff])&0xff; + else // Channel 10-14 + tempval = (*(u8 *)&hwinfo[EEPROM_TX_PWR_OFDM_DIFF+1])&0xff; + + //cosa tempval = (*(u1Byte *)&hwinfo[EEPROM_TX_PWR_OFDM_DIFF+index])&0xff; + priv->TxPwrLegacyHtDiff[RF90_PATH_A][i] = (tempval&0xF); + priv->TxPwrLegacyHtDiff[RF90_PATH_B][i] = ((tempval>>4)&0xF); + + // + // Read Band Edge tx power offset and check if user enable the ability + // + // HT 40 band edge channel + tempval = (*(u8 *)&hwinfo[EEPROM_TX_PWR_BAND_EDGE])&0xff; + priv->TxPwrbandEdgeHt40[RF90_PATH_A][0] = (tempval&0xF); // Band edge low channel + priv->TxPwrbandEdgeHt40[RF90_PATH_A][1] = ((tempval>>4)&0xF); // Band edge high channel + tempval = (*(u8 *)&hwinfo[EEPROM_TX_PWR_BAND_EDGE+1])&0xff; + priv->TxPwrbandEdgeHt40[RF90_PATH_B][0] = (tempval&0xF); // Band edge low channel + priv->TxPwrbandEdgeHt40[RF90_PATH_B][1] = ((tempval>>4)&0xF); // Band edge high channel + // HT 20 band edge channel + tempval = (*(u8 *)&hwinfo[EEPROM_TX_PWR_BAND_EDGE+2])&0xff; + priv->TxPwrbandEdgeHt20[RF90_PATH_A][0] = (tempval&0xF); // Band edge low channel + priv->TxPwrbandEdgeHt20[RF90_PATH_A][1] = ((tempval>>4)&0xF); // Band edge high channel + tempval = (*(u8 *)&hwinfo[EEPROM_TX_PWR_BAND_EDGE+3])&0xff; + priv->TxPwrbandEdgeHt20[RF90_PATH_B][0] = (tempval&0xF); // Band edge low channel + priv->TxPwrbandEdgeHt20[RF90_PATH_B][1] = ((tempval>>4)&0xF); // Band edge high channel + // OFDM band edge channel + tempval = (*(u8 *)&hwinfo[EEPROM_TX_PWR_BAND_EDGE+4])&0xff; + priv->TxPwrbandEdgeLegacyOfdm[RF90_PATH_A][0] = (tempval&0xF); // Band edge low channel + priv->TxPwrbandEdgeLegacyOfdm[RF90_PATH_A][1] = ((tempval>>4)&0xF); // Band edge high channel + tempval = (*(u8 *)&hwinfo[EEPROM_TX_PWR_BAND_EDGE+5])&0xff; + priv->TxPwrbandEdgeLegacyOfdm[RF90_PATH_B][0] = (tempval&0xF); // Band edge low channel + priv->TxPwrbandEdgeLegacyOfdm[RF90_PATH_B][1] = ((tempval>>4)&0xF); // Band edge high channel + + priv->TxPwrbandEdgeFlag = (*(u8 *)&hwinfo[TX_PWR_BAND_EDGE_CHK]); + } + + for(i=0; i<14; i++) + RT_TRACE(COMP_INIT, "RF-A Ht20 to HT40 Diff[%d] = 0x%x\n", i, priv->TxPwrHt20Diff[RF90_PATH_A][i]); + for(i=0; i<14; i++) + RT_TRACE(COMP_INIT, "RF-A Legacy to Ht40 Diff[%d] = 0x%x\n", i, priv->TxPwrLegacyHtDiff[RF90_PATH_A][i]); + for(i=0; i<14; i++) + RT_TRACE(COMP_INIT, "RF-B Ht20 to HT40 Diff[%d] = 0x%x\n", i, priv->TxPwrHt20Diff[RF90_PATH_B][i]); + for(i=0; i<14; i++) + RT_TRACE(COMP_INIT, "RF-B Legacy to HT40 Diff[%d] = 0x%x\n", i, priv->TxPwrLegacyHtDiff[RF90_PATH_B][i]); + RT_TRACE(COMP_INIT, "RF-A HT40 band-edge low/high power diff = 0x%x/0x%x\n", + priv->TxPwrbandEdgeHt40[RF90_PATH_A][0], + priv->TxPwrbandEdgeHt40[RF90_PATH_A][1]); + RT_TRACE((COMP_INIT&COMP_DBG), "RF-B HT40 band-edge low/high power diff = 0x%x/0x%x\n", + priv->TxPwrbandEdgeHt40[RF90_PATH_B][0], + priv->TxPwrbandEdgeHt40[RF90_PATH_B][1]); + + RT_TRACE((COMP_INIT&COMP_DBG), "RF-A HT20 band-edge low/high power diff = 0x%x/0x%x\n", + priv->TxPwrbandEdgeHt20[RF90_PATH_A][0], + priv->TxPwrbandEdgeHt20[RF90_PATH_A][1]); + RT_TRACE((COMP_INIT&COMP_DBG), "RF-B HT20 band-edge low/high power diff = 0x%x/0x%x\n", + priv->TxPwrbandEdgeHt20[RF90_PATH_B][0], + priv->TxPwrbandEdgeHt20[RF90_PATH_B][1]); + + RT_TRACE((COMP_INIT&COMP_DBG), "RF-A OFDM band-edge low/high power diff = 0x%x/0x%x\n", + priv->TxPwrbandEdgeLegacyOfdm[RF90_PATH_A][0], + priv->TxPwrbandEdgeLegacyOfdm[RF90_PATH_A][1]); + RT_TRACE((COMP_INIT&COMP_DBG), "RF-B OFDM band-edge low/high power diff = 0x%x/0x%x\n", + priv->TxPwrbandEdgeLegacyOfdm[RF90_PATH_B][0], + priv->TxPwrbandEdgeLegacyOfdm[RF90_PATH_B][1]); + RT_TRACE((COMP_INIT&COMP_DBG), "Band-edge enable flag = %d\n", priv->TxPwrbandEdgeFlag); +#endif + + // + // Update remained HAL variables. + // + priv->TSSI_13dBm = priv->EEPROMThermalMeter *100; + priv->LegacyHTTxPowerDiff = priv->EEPROMTxPowerDiff; + priv->TxPowerDiff = priv->EEPROMTxPowerDiff; + //priv->AntennaTxPwDiff[0] = (priv->EEPROMTxPowerDiff & 0xf);// Antenna B gain offset to antenna A, bit[3:0] + //priv->AntennaTxPwDiff[1] = ((priv->EEPROMTxPowerDiff & 0xf0)>>4);// Antenna C gain offset to antenna A, bit[7:4] + priv->CrystalCap = priv->EEPROMCrystalCap; // CrystalCap, bit[15:12] + priv->ThermalMeter[0] = (priv->EEPROMThermalMeter&0x1f);// ThermalMeter, bit0~3 for RFIC1, bit4~7 for RFIC2 + priv->LedStrategy = SW_LED_MODE0; + + init_rate_adaptive(dev); + + RT_TRACE(COMP_INIT, "<==== ReadAdapterInfo8192SUsb\n"); + + //return RT_STATUS_SUCCESS; +} + + +// +// Description: +// Read HW adapter information by E-Fuse or EEPROM according CR9346 reported. +// +// Assumption: +// 1. CR9346 regiser has verified. +// 2. PASSIVE_LEVEL (USB interface) +// +// Created by Roger, 2008.10.21. +// +static void rtl8192SU_read_eeprom_info(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + u8 tmpU1b; + + RT_TRACE(COMP_INIT, "====> ReadAdapterInfo8192SUsb\n"); + + // Retrieve Chip version. + priv->card_8192_version = (VERSION_8192S)((read_nic_dword(dev, PMC_FSM)>>16)&0xF); + RT_TRACE(COMP_INIT, "Chip Version ID: 0x%2x\n", priv->card_8192_version); + + tmpU1b = read_nic_byte(dev, EPROM_CMD);//CR9346 + + // To check system boot selection. + if (tmpU1b & CmdEERPOMSEL) + { + RT_TRACE(COMP_INIT, "Boot from EEPROM\n"); + priv->EepromOrEfuse = TRUE; + } + else + { + RT_TRACE(COMP_INIT, "Boot from EFUSE\n"); + priv->EepromOrEfuse = FALSE; + } + + // To check autoload success or not. + if (tmpU1b & CmdEEPROM_En) + { + RT_TRACE(COMP_INIT, "Autoload OK!!\n"); + priv->AutoloadFailFlag=FALSE; + rtl8192SU_ReadAdapterInfo8192SUsb(dev);//eeprom or e-fuse + } + else + { // Auto load fail. + RT_TRACE(COMP_INIT, "AutoLoad Fail reported from CR9346!!\n"); + priv->AutoloadFailFlag=TRUE; + rtl8192SU_ConfigAdapterInfo8192SForAutoLoadFail(dev); + + //if (IS_BOOT_FROM_EFUSE(Adapter)) + if(!priv->EepromOrEfuse) + { + RT_TRACE(COMP_INIT, "Update shadow map for EFuse future use!!\n"); + EFUSE_ShadowMapUpdate(dev); + } + } +#ifdef TO_DO_LIST + if((priv->RegChannelPlan >= RT_CHANNEL_DOMAIN_MAX) || (pHalData->EEPROMChannelPlan & EEPROM_CHANNEL_PLAN_BY_HW_MASK)) + { + pMgntInfo->ChannelPlan = HalMapChannelPlan8192S(Adapter, (pHalData->EEPROMChannelPlan & (~(EEPROM_CHANNEL_PLAN_BY_HW_MASK)))); + pMgntInfo->bChnlPlanFromHW = (pHalData->EEPROMChannelPlan & EEPROM_CHANNEL_PLAN_BY_HW_MASK) ? TRUE : FALSE; // User cannot change channel plan. + } + else + { + pMgntInfo->ChannelPlan = (RT_CHANNEL_DOMAIN)pMgntInfo->RegChannelPlan; + } + + switch(pMgntInfo->ChannelPlan) + { + case RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN: + { + PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(pMgntInfo); + + pDot11dInfo->bEnabled = TRUE; + } + RT_TRACE(COMP_INIT, DBG_LOUD, ("ReadAdapterInfo8187(): Enable dot11d when RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN!\n")); + break; + } + + RT_TRACE(COMP_INIT, DBG_LOUD, ("RegChannelPlan(%d) EEPROMChannelPlan(%d)", pMgntInfo->RegChannelPlan, pHalData->EEPROMChannelPlan)); + RT_TRACE(COMP_INIT, DBG_LOUD, ("ChannelPlan = %d\n" , pMgntInfo->ChannelPlan)); + + RT_TRACE(COMP_INIT, DBG_LOUD, ("<==== ReadAdapterInfo8192S\n")); +#endif + + RT_TRACE(COMP_INIT, "<==== ReadAdapterInfo8192SUsb\n"); + + //return RT_STATUS_SUCCESS; +} +#else +static void rtl8192_read_eeprom_info(struct net_device* dev) +{ + u16 wEPROM_ID = 0; + u8 bMac_Tmp_Addr[6] = {0x00, 0xe0, 0x4c, 0x00, 0x00, 0x02}; + u8 bLoad_From_EEPOM = false; + struct r8192_priv *priv = ieee80211_priv(dev); + u16 tmpValue = 0; + RT_TRACE(COMP_EPROM, "===========>%s()\n", __FUNCTION__); + wEPROM_ID = eprom_read(dev, 0); //first read EEPROM ID out; + RT_TRACE(COMP_EPROM, "EEPROM ID is 0x%x\n", wEPROM_ID); + + if (wEPROM_ID != RTL8190_EEPROM_ID) + { + RT_TRACE(COMP_ERR, "EEPROM ID is invalid(is 0x%x(should be 0x%x)\n", wEPROM_ID, RTL8190_EEPROM_ID); + } + else + bLoad_From_EEPOM = true; + + if (bLoad_From_EEPOM) + { + tmpValue = eprom_read(dev, (EEPROM_VID>>1)); + priv->eeprom_vid = endian_swap(&tmpValue); + priv->eeprom_pid = eprom_read(dev, (EEPROM_PID>>1)); + tmpValue = eprom_read(dev, (EEPROM_ChannelPlan>>1)); + priv->eeprom_ChannelPlan =((tmpValue&0xff00)>>8); + priv->btxpowerdata_readfromEEPORM = true; + priv->eeprom_CustomerID = eprom_read(dev, (EEPROM_Customer_ID>>1)) >>8; + } + else + { + priv->eeprom_vid = 0; + priv->eeprom_pid = 0; + priv->card_8192_version = VERSION_819xU_B; + priv->eeprom_ChannelPlan = 0; + priv->eeprom_CustomerID = 0; + } + RT_TRACE(COMP_EPROM, "vid:0x%4x, pid:0x%4x, CustomID:0x%2x, ChanPlan:0x%x\n", priv->eeprom_vid, priv->eeprom_pid, priv->eeprom_CustomerID, priv->eeprom_ChannelPlan); + //set channelplan from eeprom + priv->ChannelPlan = priv->eeprom_ChannelPlan; + if (bLoad_From_EEPOM) + { + int i; + for (i=0; i<6; i+=2) + { + u16 tmp = 0; + tmp = eprom_read(dev, (u16)((EEPROM_NODE_ADDRESS_BYTE_0 + i)>>1)); + *(u16*)(&dev->dev_addr[i]) = tmp; + } + } + else + { + memcpy(dev->dev_addr, bMac_Tmp_Addr, 6); + //should I set IDR0 here? + } + RT_TRACE(COMP_EPROM, "MAC addr:"MAC_FMT"\n", MAC_ARG(dev->dev_addr)); + priv->rf_type = RTL819X_DEFAULT_RF_TYPE; //default 1T2R + priv->rf_chip = RF_8256; + + if (priv->card_8192_version == (u8)VERSION_819xU_A) + { + //read Tx power gain offset of legacy OFDM to HT rate + if (bLoad_From_EEPOM) + priv->EEPROMTxPowerDiff = (eprom_read(dev, (EEPROM_TxPowerDiff>>1))&0xff00) >> 8; + else + priv->EEPROMTxPowerDiff = EEPROM_Default_TxPower; + RT_TRACE(COMP_EPROM, "TxPowerDiff:%d\n", priv->EEPROMTxPowerDiff); + //read ThermalMeter from EEPROM + if (bLoad_From_EEPOM) + priv->EEPROMThermalMeter = (u8)(eprom_read(dev, (EEPROM_ThermalMeter>>1))&0x00ff); + else + priv->EEPROMThermalMeter = EEPROM_Default_ThermalMeter; + RT_TRACE(COMP_EPROM, "ThermalMeter:%d\n", priv->EEPROMThermalMeter); + //vivi, for tx power track + priv->TSSI_13dBm = priv->EEPROMThermalMeter *100; + //read antenna tx power offset of B/C/D to A from EEPROM + if (bLoad_From_EEPOM) + priv->EEPROMPwDiff = (eprom_read(dev, (EEPROM_PwDiff>>1))&0x0f00)>>8; + else + priv->EEPROMPwDiff = EEPROM_Default_PwDiff; + RT_TRACE(COMP_EPROM, "TxPwDiff:%d\n", priv->EEPROMPwDiff); + // Read CrystalCap from EEPROM + if (bLoad_From_EEPOM) + priv->EEPROMCrystalCap = (eprom_read(dev, (EEPROM_CrystalCap>>1))&0x0f); + else + priv->EEPROMCrystalCap = EEPROM_Default_CrystalCap; + RT_TRACE(COMP_EPROM, "CrystalCap = %d\n", priv->EEPROMCrystalCap); + //get per-channel Tx power level + if (bLoad_From_EEPOM) + priv->EEPROM_Def_Ver = (eprom_read(dev, (EEPROM_TxPwIndex_Ver>>1))&0xff00)>>8; + else + priv->EEPROM_Def_Ver = 1; + RT_TRACE(COMP_EPROM, "EEPROM_DEF_VER:%d\n", priv->EEPROM_Def_Ver); + if (priv->EEPROM_Def_Ver == 0) //old eeprom definition + { + int i; + if (bLoad_From_EEPOM) + priv->EEPROMTxPowerLevelCCK = (eprom_read(dev, (EEPROM_TxPwIndex_CCK>>1))&0xff) >> 8; + else + priv->EEPROMTxPowerLevelCCK = 0x10; + RT_TRACE(COMP_EPROM, "CCK Tx Power Levl: 0x%02x\n", priv->EEPROMTxPowerLevelCCK); + for (i=0; i<3; i++) + { + if (bLoad_From_EEPOM) + { + tmpValue = eprom_read(dev, (EEPROM_TxPwIndex_OFDM_24G+i)>>1); + if (((EEPROM_TxPwIndex_OFDM_24G+i) % 2) == 0) + tmpValue = tmpValue & 0x00ff; + else + tmpValue = (tmpValue & 0xff00) >> 8; + } + else + tmpValue = 0x10; + priv->EEPROMTxPowerLevelOFDM24G[i] = (u8) tmpValue; + RT_TRACE(COMP_EPROM, "OFDM 2.4G Tx Power Level, Index %d = 0x%02x\n", i, priv->EEPROMTxPowerLevelCCK); + } + }//end if EEPROM_DEF_VER == 0 + else if (priv->EEPROM_Def_Ver == 1) + { + if (bLoad_From_EEPOM) + { + tmpValue = eprom_read(dev, (EEPROM_TxPwIndex_CCK_V1>>1)); + tmpValue = (tmpValue & 0xff00) >> 8; + } + else + tmpValue = 0x10; + priv->EEPROMTxPowerLevelCCK_V1[0] = (u8)tmpValue; + + if (bLoad_From_EEPOM) + tmpValue = eprom_read(dev, (EEPROM_TxPwIndex_CCK_V1 + 2)>>1); + else + tmpValue = 0x1010; + *((u16*)(&priv->EEPROMTxPowerLevelCCK_V1[1])) = tmpValue; + if (bLoad_From_EEPOM) + tmpValue = eprom_read(dev, (EEPROM_TxPwIndex_OFDM_24G_V1>>1)); + else + tmpValue = 0x1010; + *((u16*)(&priv->EEPROMTxPowerLevelOFDM24G[0])) = tmpValue; + if (bLoad_From_EEPOM) + tmpValue = eprom_read(dev, (EEPROM_TxPwIndex_OFDM_24G_V1+2)>>1); + else + tmpValue = 0x10; + priv->EEPROMTxPowerLevelOFDM24G[2] = (u8)tmpValue; + }//endif EEPROM_Def_Ver == 1 + + //update HAL variables + // + { + int i; + for (i=0; i<14; i++) + { + if (i<=3) + priv->TxPowerLevelOFDM24G[i] = priv->EEPROMTxPowerLevelOFDM24G[0]; + else if (i>=4 && i<=9) + priv->TxPowerLevelOFDM24G[i] = priv->EEPROMTxPowerLevelOFDM24G[1]; + else + priv->TxPowerLevelOFDM24G[i] = priv->EEPROMTxPowerLevelOFDM24G[2]; + } + + for (i=0; i<14; i++) + { + if (priv->EEPROM_Def_Ver == 0) + { + if (i<=3) + priv->TxPowerLevelCCK[i] = priv->EEPROMTxPowerLevelOFDM24G[0] + (priv->EEPROMTxPowerLevelCCK - priv->EEPROMTxPowerLevelOFDM24G[1]); + else if (i>=4 && i<=9) + priv->TxPowerLevelCCK[i] = priv->EEPROMTxPowerLevelCCK; + else + priv->TxPowerLevelCCK[i] = priv->EEPROMTxPowerLevelOFDM24G[2] + (priv->EEPROMTxPowerLevelCCK - priv->EEPROMTxPowerLevelOFDM24G[1]); + } + else if (priv->EEPROM_Def_Ver == 1) + { + if (i<=3) + priv->TxPowerLevelCCK[i] = priv->EEPROMTxPowerLevelCCK_V1[0]; + else if (i>=4 && i<=9) + priv->TxPowerLevelCCK[i] = priv->EEPROMTxPowerLevelCCK_V1[1]; + else + priv->TxPowerLevelCCK[i] = priv->EEPROMTxPowerLevelCCK_V1[2]; + } + } + }//end update HAL variables + priv->TxPowerDiff = priv->EEPROMPwDiff; +// Antenna B gain offset to antenna A, bit0~3 + priv->AntennaTxPwDiff[0] = (priv->EEPROMTxPowerDiff & 0xf); + // Antenna C gain offset to antenna A, bit4~7 + priv->AntennaTxPwDiff[1] = ((priv->EEPROMTxPowerDiff & 0xf0)>>4); + // CrystalCap, bit12~15 + priv->CrystalCap = priv->EEPROMCrystalCap; + // ThermalMeter, bit0~3 for RFIC1, bit4~7 for RFIC2 + // 92U does not enable TX power tracking. + priv->ThermalMeter[0] = priv->EEPROMThermalMeter; + }//end if VersionID == VERSION_819xU_A + +//added by vivi, for dlink led, 20080416 + switch(priv->eeprom_CustomerID) + { + case EEPROM_CID_RUNTOP: + priv->CustomerID = RT_CID_819x_RUNTOP; + break; + + case EEPROM_CID_DLINK: + priv->CustomerID = RT_CID_DLINK; + break; + + default: + priv->CustomerID = RT_CID_DEFAULT; + break; + + } + + switch(priv->CustomerID) + { + case RT_CID_819x_RUNTOP: + priv->LedStrategy = SW_LED_MODE2; + break; + + case RT_CID_DLINK: + priv->LedStrategy = SW_LED_MODE4; + break; + + default: + priv->LedStrategy = SW_LED_MODE0; + break; + + } + + + if(priv->rf_type == RF_1T2R) + { + RT_TRACE(COMP_EPROM, "\n1T2R config\n"); + } + else + { + RT_TRACE(COMP_EPROM, "\n2T4R config\n"); + } + + // 2008/01/16 MH We can only know RF type in the function. So we have to init + // DIG RATR table again. + init_rate_adaptive(dev); + //we need init DIG RATR table here again. + + RT_TRACE(COMP_EPROM, "<===========%s()\n", __FUNCTION__); + return; +} +#endif + +short rtl8192_get_channel_map(struct net_device * dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); +#ifdef ENABLE_DOT11D + if(priv->ChannelPlan > COUNTRY_CODE_GLOBAL_DOMAIN){ + printk("rtl8180_init:Error channel plan! Set to default.\n"); + priv->ChannelPlan= 0; + } + RT_TRACE(COMP_INIT, "Channel plan is %d\n",priv->ChannelPlan); + + rtl819x_set_channel_map(priv->ChannelPlan, priv); +#else + int ch,i; + //Set Default Channel Plan + if(!channels){ + DMESG("No channels, aborting"); + return -1; + } + ch=channels; + priv->ChannelPlan= 0;//hikaru + // set channels 1..14 allowed in given locale + for (i=1; i<=14; i++) { + (priv->ieee80211->channel_map)[i] = (u8)(ch & 0x01); + ch >>= 1; + } +#endif + return 0; +} + +short rtl8192_init(struct net_device *dev) +{ + + struct r8192_priv *priv = ieee80211_priv(dev); + +#ifndef RTL8192SU + memset(&(priv->stats),0,sizeof(struct Stats)); + memset(priv->txqueue_to_outpipemap,0,9); +#ifdef PIPE12 + { + int i=0; + u8 queuetopipe[]={3,2,1,0,4,8,7,6,5}; + memcpy(priv->txqueue_to_outpipemap,queuetopipe,9); +/* for(i=0;i<9;i++) + printk("%d ",priv->txqueue_to_outpipemap[i]); + printk("\n");*/ + } +#else + { + u8 queuetopipe[]={3,2,1,0,4,4,0,4,4}; + memcpy(priv->txqueue_to_outpipemap,queuetopipe,9); +/* for(i=0;i<9;i++) + printk("%d ",priv->txqueue_to_outpipemap[i]); + printk("\n");*/ + } +#endif +#endif + rtl8192_init_priv_variable(dev); + rtl8192_init_priv_lock(priv); + rtl8192_init_priv_task(dev); + rtl8192_get_eeprom_size(dev); + priv->ops->rtl819x_read_eeprom_info(dev); + rtl8192_get_channel_map(dev); + init_hal_dm(dev); + init_timer(&priv->watch_dog_timer); + priv->watch_dog_timer.data = (unsigned long)dev; + priv->watch_dog_timer.function = watch_dog_timer_callback; + + //rtl8192_adapter_start(dev); +#ifdef DEBUG_EPROM + dump_eprom(dev); +#endif + return 0; +} + +/****************************************************************************** + *function: This function actually only set RRSR, RATR and BW_OPMODE registers + * not to do all the hw config as its name says + * input: net_device dev + * output: none + * return: none + * notice: This part need to modified according to the rate set we filtered + * ****************************************************************************/ +void rtl8192_hwconfig(struct net_device* dev) +{ + u32 regRATR = 0, regRRSR = 0; + u8 regBwOpMode = 0, regTmp = 0; + struct r8192_priv *priv = ieee80211_priv(dev); + +// Set RRSR, RATR, and BW_OPMODE registers + // + switch(priv->ieee80211->mode) + { + case WIRELESS_MODE_B: + regBwOpMode = BW_OPMODE_20MHZ; + regRATR = RATE_ALL_CCK; + regRRSR = RATE_ALL_CCK; + break; + case WIRELESS_MODE_A: + regBwOpMode = BW_OPMODE_5G |BW_OPMODE_20MHZ; + regRATR = RATE_ALL_OFDM_AG; + regRRSR = RATE_ALL_OFDM_AG; + break; + case WIRELESS_MODE_G: + regBwOpMode = BW_OPMODE_20MHZ; + regRATR = RATE_ALL_CCK | RATE_ALL_OFDM_AG; + regRRSR = RATE_ALL_CCK | RATE_ALL_OFDM_AG; + break; + case WIRELESS_MODE_AUTO: +#ifdef TO_DO_LIST + if (Adapter->bInHctTest) + { + regBwOpMode = BW_OPMODE_20MHZ; + regRATR = RATE_ALL_CCK | RATE_ALL_OFDM_AG; + regRRSR = RATE_ALL_CCK | RATE_ALL_OFDM_AG; + } + else +#endif + { + regBwOpMode = BW_OPMODE_20MHZ; + regRATR = RATE_ALL_CCK | RATE_ALL_OFDM_AG | RATE_ALL_OFDM_1SS | RATE_ALL_OFDM_2SS; + regRRSR = RATE_ALL_CCK | RATE_ALL_OFDM_AG; + } + break; + case WIRELESS_MODE_N_24G: + // It support CCK rate by default. + // CCK rate will be filtered out only when associated AP does not support it. + regBwOpMode = BW_OPMODE_20MHZ; + regRATR = RATE_ALL_CCK | RATE_ALL_OFDM_AG | RATE_ALL_OFDM_1SS | RATE_ALL_OFDM_2SS; + regRRSR = RATE_ALL_CCK | RATE_ALL_OFDM_AG; + break; + case WIRELESS_MODE_N_5G: + regBwOpMode = BW_OPMODE_5G; + regRATR = RATE_ALL_OFDM_AG | RATE_ALL_OFDM_1SS | RATE_ALL_OFDM_2SS; + regRRSR = RATE_ALL_OFDM_AG; + break; + } + + write_nic_byte(dev, BW_OPMODE, regBwOpMode); + { + u32 ratr_value = 0; + ratr_value = regRATR; + if (priv->rf_type == RF_1T2R) + { + ratr_value &= ~(RATE_ALL_OFDM_2SS); + } + write_nic_dword(dev, RATR0, ratr_value); + write_nic_byte(dev, UFWP, 1); + } + regTmp = read_nic_byte(dev, 0x313); + regRRSR = ((regTmp) << 24) | (regRRSR & 0x00ffffff); + write_nic_dword(dev, RRSR, regRRSR); + + // + // Set Retry Limit here + // + write_nic_word(dev, RETRY_LIMIT, + priv->ShortRetryLimit << RETRY_LIMIT_SHORT_SHIFT | \ + priv->LongRetryLimit << RETRY_LIMIT_LONG_SHIFT); + // Set Contention Window here + + // Set Tx AGC + + // Set Tx Antenna including Feedback control + + // Set Auto Rate fallback control + + +} + +#ifdef RTL8192SU +#ifdef USB_RX_AGGREGATION_SUPPORT +u8 rtl8192SU_MapRxPageSizeToIdx(u16 RxPktSize ) +{ + switch(RxPktSize) + { + case 64: return 0; break; + case 128 : return 1; break; + case 256: return 2; break; + case 512: return 3; break; + case 1024: return 4; break; + default: return 0; // We use 64bytes in defult. + } +} +#endif + +// +// Description: +// Initial HW relted registers. +// +// Assumption: +// Config RTL8192S USB MAC, we should config MAC before download FW. +// +// 2008.09.03, Added by Roger. +// +static void rtl8192SU_MacConfigBeforeFwDownloadASIC(struct net_device *dev) +{ + u8 tmpU1b;// i; +// u16 tmpU2b; +// u32 tmpU4b; + u8 PollingCnt = 20; + + RT_TRACE(COMP_INIT, "--->MacConfigBeforeFwDownloadASIC()\n"); + + //2MAC Initialization for power on sequence, Revised by Roger. 2008.09.03. + + // + // Set control path switch to HW control and reset Digital Core, CPU Core and + // MAC I/O to solve FW download fail when system from resume sate. + // 2008.11.04. + // + tmpU1b = read_nic_byte(dev, SYS_CLKR+1); + if(tmpU1b & 0x80) + { + tmpU1b &= 0x3f; + write_nic_byte(dev, SYS_CLKR+1, tmpU1b); + } + // Clear FW RPWM for FW control LPS. by tynli. 2009.02.23 + write_nic_byte(dev, RPWM, 0x0); + + tmpU1b = read_nic_byte(dev, SYS_FUNC_EN+1); + tmpU1b &= 0x73; + write_nic_byte(dev, SYS_FUNC_EN+1, tmpU1b); + udelay(1000); + + //Revised POS, suggested by SD1 Alex, 2008.09.27. + write_nic_byte(dev, SPS0_CTRL+1, 0x53); + write_nic_byte(dev, SPS0_CTRL, 0x57); + + //Enable AFE Macro Block's Bandgap adn Enable AFE Macro Block's Mbias + tmpU1b = read_nic_byte(dev, AFE_MISC); + write_nic_byte(dev, AFE_MISC, (tmpU1b|AFE_BGEN|AFE_MBEN)); + + //Enable PLL Power (LDOA15V) + tmpU1b = read_nic_byte(dev, LDOA15_CTRL); + write_nic_byte(dev, LDOA15_CTRL, (tmpU1b|LDA15_EN)); + + //Enable LDOV12D block + tmpU1b = read_nic_byte(dev, LDOV12D_CTRL); + write_nic_byte(dev, LDOV12D_CTRL, (tmpU1b|LDV12_EN)); + + //mpU1b = read_nic_byte(Adapter, SPS1_CTRL); + //write_nic_byte(dev, SPS1_CTRL, (tmpU1b|SPS1_LDEN)); + + //PlatformSleepUs(2000); + + //Enable Switch Regulator Block + //tmpU1b = read_nic_byte(Adapter, SPS1_CTRL); + //write_nic_byte(dev, SPS1_CTRL, (tmpU1b|SPS1_SWEN)); + + //write_nic_dword(Adapter, SPS1_CTRL, 0x00a7b267); + + tmpU1b = read_nic_byte(dev, SYS_ISO_CTRL+1); + write_nic_byte(dev, SYS_ISO_CTRL+1, (tmpU1b|0x08)); + + //Engineer Packet CP test Enable + tmpU1b = read_nic_byte(dev, SYS_FUNC_EN+1); + write_nic_byte(dev, SYS_FUNC_EN+1, (tmpU1b|0x20)); + + //Support 64k IMEM, suggested by SD1 Alex. + tmpU1b = read_nic_byte(dev, SYS_ISO_CTRL+1); + write_nic_byte(dev, SYS_ISO_CTRL+1, (tmpU1b& 0x68)); + + //Enable AFE clock + tmpU1b = read_nic_byte(dev, AFE_XTAL_CTRL+1); + write_nic_byte(dev, AFE_XTAL_CTRL+1, (tmpU1b& 0xfb)); + + //Enable AFE PLL Macro Block + tmpU1b = read_nic_byte(dev, AFE_PLL_CTRL); + write_nic_byte(dev, AFE_PLL_CTRL, (tmpU1b|0x11)); + + //Attatch AFE PLL to MACTOP/BB/PCIe Digital + tmpU1b = read_nic_byte(dev, SYS_ISO_CTRL); + write_nic_byte(dev, SYS_ISO_CTRL, (tmpU1b&0xEE)); + + // Switch to 40M clock + write_nic_byte(dev, SYS_CLKR, 0x00); + + //SSC Disable + tmpU1b = read_nic_byte(dev, SYS_CLKR); + //write_nic_byte(dev, SYS_CLKR, (tmpU1b&0x5f)); + write_nic_byte(dev, SYS_CLKR, (tmpU1b|0xa0)); + + //Enable MAC clock + tmpU1b = read_nic_byte(dev, SYS_CLKR+1); + write_nic_byte(dev, SYS_CLKR+1, (tmpU1b|0x18)); + + //Revised POS, suggested by SD1 Alex, 2008.09.27. + write_nic_byte(dev, PMC_FSM, 0x02); + + //Enable Core digital and enable IOREG R/W + tmpU1b = read_nic_byte(dev, SYS_FUNC_EN+1); + write_nic_byte(dev, SYS_FUNC_EN+1, (tmpU1b|0x08)); + + //Enable REG_EN + tmpU1b = read_nic_byte(dev, SYS_FUNC_EN+1); + write_nic_byte(dev, SYS_FUNC_EN+1, (tmpU1b|0x80)); + + //Switch the control path to FW + tmpU1b = read_nic_byte(dev, SYS_CLKR+1); + write_nic_byte(dev, SYS_CLKR+1, (tmpU1b|0x80)& 0xBF); + + write_nic_byte(dev, CMDR, 0xFC); + write_nic_byte(dev, CMDR+1, 0x37); + + //Fix the RX FIFO issue(usb error), 970410 + tmpU1b = read_nic_byte_E(dev, 0x5c); + write_nic_byte_E(dev, 0x5c, (tmpU1b|BIT7)); + + //For power save, used this in the bit file after 970621 + tmpU1b = read_nic_byte(dev, SYS_CLKR); + write_nic_byte(dev, SYS_CLKR, tmpU1b&(~SYS_CPU_CLKSEL)); + + // Revised for 8051 ROM code wrong operation. Added by Roger. 2008.10.16. + write_nic_byte_E(dev, 0x1c, 0x80); + + // + // To make sure that TxDMA can ready to download FW. + // We should reset TxDMA if IMEM RPT was not ready. + // Suggested by SD1 Alex. 2008.10.23. + // + do + { + tmpU1b = read_nic_byte(dev, TCR); + if((tmpU1b & TXDMA_INIT_VALUE) == TXDMA_INIT_VALUE) + break; + //PlatformStallExecution(5); + udelay(5); + }while(PollingCnt--); // Delay 1ms + + if(PollingCnt <= 0 ) + { + RT_TRACE(COMP_INIT, "MacConfigBeforeFwDownloadASIC(): Polling TXDMA_INIT_VALUE timeout!! Current TCR(%#x)\n", tmpU1b); + tmpU1b = read_nic_byte(dev, CMDR); + write_nic_byte(dev, CMDR, tmpU1b&(~TXDMA_EN)); + udelay(2); + write_nic_byte(dev, CMDR, tmpU1b|TXDMA_EN);// Reset TxDMA + } + + + RT_TRACE(COMP_INIT, "<---MacConfigBeforeFwDownloadASIC()\n"); +} +#ifdef USB_RX_AGGREGATION_SUPPORT +void rtl8192SU_HalUsbRxAggr8192SUsb(struct net_device *dev, bool Value) +{ + struct r8192_priv *priv = ieee80211_priv((struct net_device *)dev); + PRT_HIGH_THROUGHPUT pHTInfo = priv->ieee80211->pHTInfo;; + + + // + // We decrease Rx page aggregated threshold in B/G mode. + // 2008.10.29 + // + if(priv->ieee80211->mode == WIRELESS_MODE_B || priv->ieee80211->mode == WIRELESS_MODE_G) + {// Overwrite current settings to disable Rx Aggregation. + Value = false; + } + + // Alway set Rx Aggregation to Disable if current platform is Win2K USB 1.1, by Emily + //if(PLATFORM_LIMITED_RX_BUF_SIZE(Adapter)) + // Value = FALSE; + + // Always set Rx Aggregation to Disable if connected AP is Realtek AP, by Joseph + //if(pHTInfo->bCurrentRT2RTAggregation) + // Value = FALSE; + + // The RX aggregation may be enabled/disabled dynamically according current traffic stream. + //Enable Rx aggregation if downlink traffic is busier than uplink traffic. by Guangan + if(priv->bCurrentRxAggrEnable != Value) + { + priv->bCurrentRxAggrEnable = Value; + //Adapter->HalFunc.SetHwRegHandler(Adapter, HW_VAR_USB_RX_AGGR, (pu1Byte)&pHalData->bCurrentRxAggrEnable); + { + //u8 Setting = ((pu1Byte)(val))[0]; + u8 Setting = priv->bCurrentRxAggrEnable + u32 ulValue; + + if(Setting==0) + { + // + // Reduce aggregated page threshold to 0x01 and set minimal threshold 0x0a. + // i.e., disable Rx aggregation. + // + ulValue = 0x0001000a; + } + else + { + //PRT_HIGH_THROUGHPUT pHTInfo = priv->ieee80211->pHTInfo; + //HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + + if (priv->bForcedUsbRxAggr) + {// Using forced settings. + ulValue = priv->ForcedUsbRxAggrInfo; + } + else + {// Using default settings. + + ulValue = (pHTInfo->UsbRxFwAggrEn<<24) | (pHTInfo->UsbRxFwAggrPageNum<<16) | + (pHTInfo->UsbRxFwAggrPacketNum<<8) | (pHTInfo->UsbRxFwAggrTimeout); + } + } + + write_nic_byte(dev, RXDMA_AGG_PG_TH, (u8)((ulValue&0xff0000)>>16)); + write_nic_byte_E(dev, USB_RX_AGG_TIMEOUT, (u8)(ulValue&0xff)); + + priv->LastUsbRxAggrInfoSetting = ulValue; + + RT_TRACE(COMP_HT|COMP_RECV, "Set HW_VAR_USB_RX_AGGR: ulValue(%#x)\n", ulValue); + } + RT_TRACE(COMP_RECV, "HalUsbRxAggr8192SUsb() : Set RxAggregation to %s\n", Value?"ON":"OFF"); + } + +} +#endif + +#ifdef USB_RX_AGGREGATION_SUPPORT +void rtl8192SU_HalUsbRxAggr8192SUsb(struct net_device *dev, bool Value) +{ + struct r8192_priv *priv = ieee80211_priv((struct net_device *)dev); + PRT_HIGH_THROUGHPUT pHTInfo = priv->ieee80211->pHTInfo;; + + + // + // We decrease Rx page aggregated threshold in B/G mode. + // 2008.10.29 + // + if((priv->ieee80211->mode & WIRELESS_MODE_B) || (priv->ieee80211->mode & WIRELESS_MODE_G)) + {// Overwrite current settings to disable Rx Aggregation. + Value = false; + } + + // Alway set Rx Aggregation to Disable if current platform is Win2K USB 1.1, by Emily + //if(PLATFORM_LIMITED_RX_BUF_SIZE(Adapter)) + // Value = FALSE; + + // Always set Rx Aggregation to Disable if connected AP is Realtek AP, by Joseph + //if(pHTInfo->bCurrentRT2RTAggregation) + // Value = FALSE; + + // The RX aggregation may be enabled/disabled dynamically according current traffic stream. + //Enable Rx aggregation if downlink traffic is busier than uplink traffic. by Guangan + if(priv->bCurrentRxAggrEnable != Value) + { + priv->bCurrentRxAggrEnable = Value; + //Adapter->HalFunc.SetHwRegHandler(Adapter, HW_VAR_USB_RX_AGGR, (pu1Byte)&pHalData->bCurrentRxAggrEnable); + { + //u8 Setting = ((pu1Byte)(val))[0]; + u8 Setting = priv->bCurrentRxAggrEnable + u32 ulValue; + + if(Setting==0) + { + // + // Reduce aggregated page threshold to 0x01 and set minimal threshold 0x0a. + // i.e., disable Rx aggregation. + // + ulValue = 0x0001000a; + } + else + { + //PRT_HIGH_THROUGHPUT pHTInfo = priv->ieee80211->pHTInfo; + //HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + + if (priv->bForcedUsbRxAggr) + {// Using forced settings. + ulValue = priv->ForcedUsbRxAggrInfo; + } + else + {// Using default settings. + + ulValue = (pHTInfo->UsbRxFwAggrEn<<24) | (pHTInfo->UsbRxFwAggrPageNum<<16) | + (pHTInfo->UsbRxFwAggrPacketNum<<8) | (pHTInfo->UsbRxFwAggrTimeout); + } + } + + write_nic_byte(dev, RXDMA_AGG_PG_TH, (u8)((ulValue&0xff0000)>>16)); + write_nic_byte_E(dev, USB_RX_AGG_TIMEOUT, (u8)(ulValue&0xff)); + + priv->LastUsbRxAggrInfoSetting = ulValue; + + RT_TRACE(COMP_HT|COMP_RECV, "Set HW_VAR_USB_RX_AGGR: ulValue(%#x)\n", ulValue); + } + RT_TRACE(COMP_RECV, "HalUsbRxAggr8192SUsb() : Set RxAggregation to %s\n", Value?"ON":"OFF"); + } + +} + +u8 rtl8192SU_MapRxPageSizeToIdx(u16 RxPktSize ) +{ + switch(RxPktSize) + { + case 64: return 0; break; + case 128 : return 1; break; + case 256: return 2; break; + case 512: return 3; break; + case 1024: return 4; break; + default: return 0; // We use 64bytes in defult. + } +} +#endif + +#if 0 +static void rtl8192SU_SetHwRegAmpduMinSpace(struct net_device *dev, u8 MinSpaceCfg) +{ + struct r8192_priv *priv = ieee80211_priv((struct net_device *)dev); + struct ieee80211_device* ieee = priv->ieee80211; + u8 MinSpacingToSet; + u8 SecMinSpace; + +#ifdef RTL8192S_PREPARE_FOR_NORMAL_RELEASE + MinSpacingToSet = MinSpaceCfg; + if(MinSpacingToSet <= 7) + { + switch(ieee->pairwise_key_type) + { + case KEY_TYPE_NA: SecMinSpace = 0; break; + case KEY_TYPE_CCMP: + case KEY_TYPE_WEP40: + case KEY_TYPE_WEP104: + case KEY_TYPE_TKIP: SecMinSpace = 6; break; + default: SecMinSpace = 7; break; + } + + if(MinSpacingToSet < SecMinSpace) + MinSpacingToSet = SecMinSpace; + priv->MinSpaceCfg = ((priv->MinSpaceCfg&0xf8) |MinSpacingToSet); + RT_TRACE(COMP_SEC, "Set AMPDU_MIN_SPACE: %x\n", priv->MinSpaceCfg); + write_nic_byte(dev, AMPDU_MIN_SPACE, priv->MinSpaceCfg); + } + +#else + MinSpacingToSet = MinSpaceCfg; + MinSpacingToSet &= 0x07; // We only care about bit[2:0] + priv->MinSpaceCfg |= MinSpacingToSet; + RT_TRACE(COMP_SEC, "Set AMPDU_MIN_SPACE: %x\n", priv->MinSpaceCfg); + write_nic_byte(dev, AMPDU_MIN_SPACE, priv->MinSpaceCfg);//FIXLZM +#endif +} +#endif + +// +// Description: +// Initial HW relted registers. +// +// Assumption: +// 1. This function is only invoked at driver intialization once. +// 2. PASSIVE LEVEL. +// +// 2008.06.10, Added by Roger. +// +static void rtl8192SU_MacConfigAfterFwDownload(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv((struct net_device *)dev); + //PRT_HIGH_THROUGHPUT pHTInfo = priv->ieee80211->pHTInfo; + //u8 tmpU1b, RxPageCfg, i; + u16 tmpU2b; + u8 tmpU1b;//, i; + + + RT_TRACE(COMP_INIT, "--->MacConfigAfterFwDownload()\n"); + + // Enable Tx/Rx + tmpU2b = (BBRSTn|BB_GLB_RSTn|SCHEDULE_EN|MACRXEN|MACTXEN|DDMA_EN| + FW2HW_EN|RXDMA_EN|TXDMA_EN|HCI_RXDMA_EN|HCI_TXDMA_EN); //3 + //Adapter->HalFunc.SetHwRegHandler( Adapter, HW_VAR_COMMAND, &tmpU1b ); + write_nic_word(dev, CMDR, tmpU2b); //LZM REGISTER COM 090305 + + // Loopback mode or not + priv->LoopbackMode = RTL8192SU_NO_LOOPBACK; // Set no loopback as default. + if(priv->LoopbackMode == RTL8192SU_NO_LOOPBACK) + tmpU1b = LBK_NORMAL; + else if (priv->LoopbackMode == RTL8192SU_MAC_LOOPBACK ) + tmpU1b = LBK_MAC_DLB; + else + RT_TRACE(COMP_INIT, "Serious error: wrong loopback mode setting\n"); + + //Adapter->HalFunc.SetHwRegHandler( Adapter, HW_VAR_LBK_MODE, &tmpU1b); + write_nic_byte(dev, LBKMD_SEL, tmpU1b); + + // Set RCR + write_nic_dword(dev, RCR, priv->ReceiveConfig); + RT_TRACE(COMP_INIT, "MacConfigAfterFwDownload(): Current RCR settings(%#x)\n", priv->ReceiveConfig); + + + // Set RQPN + // + // 2008.08.18. + // 6 endpoints: + // (1) Page number on CMDQ is 0x03. + // (2) Page number on BCNQ, HQ and MGTQ is 0. + // (3) Page number on BKQ, BEQ, VIQ and VOQ are 0x07. + // (4) Page number on PUBQ is 0xdd + // + // 11 endpoints: + // (1) Page number on CMDQ is 0x00. + // (2) Page number on BCNQ is 0x02, HQ and MGTQ are 0x03. + // (3) Page number on BKQ, BEQ, VIQ and VOQ are 0x07. + // (4) Page number on PUBQ is 0xd8 + // + //write_nic_dword(Adapter, 0xa0, 0x07070707); //BKQ, BEQ, VIQ and VOQ + //write_nic_byte(dev, 0xa4, 0x00); // HCCAQ +#if 0 //LZM 090219 +#ifdef USE_SIX_USB_ENDPOINT + //write_nic_dword(Adapter, 0xa5, 0x00000003); //CMDQ, MGTQ, HQ and BCNQ + //write_nic_byte(dev, 0xa9, 0xdd); // PUBQ + tmpU1b = read_nic_byte(dev, 0xab); // RQPN + write_nic_byte(dev, 0xab, tmpU1b|BIT7|BIT6);// reduce to 6 endpoints. +#else + write_nic_dword(dev, 0xa5, 0x02030300); //CMDQ, MGTQ, HQ and BCNQ + write_nic_byte(dev, 0xa9, 0xd8); // PUBQ + tmpU1b = read_nic_byte(dev, 0xab); // RQPN + write_nic_byte(dev, 0xab, (tmpU1b&(~BIT6))|BIT7); // Disable reduced endpoint. +#endif +#endif + +#ifdef USB_RX_AGGREGATION_SUPPORT + // Size of Tx/Rx packet buffer. + tmpU1b = read_nic_byte(dev, PBP); + RxPageCfg = rtl8192SU_MapRxPageSizeToIdx(priv->ieee80211->pHTInfo.UsbRxPageSize); + write_nic_byte(dev, PBP, tmpU1b|RxPageCfg); // Set page size of Rx packet buffer to 128 bytes. + tmpU1b = read_nic_byte(dev, RXDMA); + + write_nic_byte(dev, RXDMA, tmpU1b|RXDMA_AGG_EN); // Rx aggregation enable. + //PlatformIOWrite1Byte(Adapter, RXDMA_AGG_PG_TH, 0x14); // Set page size of RxDMA aggregation threshold, default: 20. + //write_nic_byte(dev, RXDMA_AGG_PG_TH, 0x40); // By Scott's suggestion, 2008.09.30.//92su del + //write_nic_byte(dev, USB_RX_AGG_TIMEOUT, RXDMA_AGG_TIMEOUT_17_4_MS); // Set aggregation time-out to 17ms/4. + rtl8192SU_HalUsbRxAggr8192SUsb(dev, true); +#endif + + // Fix the RX FIFO issue(USB error), Rivesed by Roger, 2008-06-14 + tmpU1b = read_nic_byte_E(dev, 0x5C); + write_nic_byte_E(dev, 0x5C, tmpU1b|BIT7); + + // + // Revise USB PHY to solve the issue of Rx payload error, Rivesed by Roger, 2008-04-10 + // Suggest by SD1 Alex. + // + // The following operation are ONLY for USB PHY test chip. + // 2008.10.07. + // +#if RTL8192SU_USB_PHY_TEST + write_nic_byte(dev, 0x41,0xf4); + write_nic_byte(dev, 0x40,0x00); + write_nic_byte(dev, 0x42,0x00); + write_nic_byte(dev, 0x42,0x01); + write_nic_byte(dev, 0x40,0x0f); + write_nic_byte(dev, 0x42,0x00); + write_nic_byte(dev, 0x42,0x01); +#endif + +#if 0 //LZM 090219 + // + // Suggested by SD1 Alex, 2008-06-14. + // + write_nic_byte(dev, TXOP_STALL_CTRL, 0x80);//NAV + + + // + // Set Data Auto Rate Fallback Retry Count register. + // + write_nic_dword(dev, DARFRC, 0x04010000); + write_nic_dword(dev, DARFRC+4, 0x09070605); + write_nic_dword(dev, RARFRC, 0x04010000); + write_nic_dword(dev, RARFRC+4, 0x09070605); + + // Set Data Auto Rate Fallback Reg. Added by Roger, 2008.09.22. + for (i = 0; i < 8; i++) +#ifdef RTL8192SU_DISABLE_CCK_RATE + write_nic_dword(dev, ARFR0+i*4, 0x1f0ff0f0); +#else + write_nic_dword(dev, ARFR0+i*4, 0x1f0ffff0); +#endif + + // + // Set driver info, we only accept PHY status now. + // + //write_nic_byte(dev, RXDRVINFO_SZ, 4); + + // + // Aggregation length limit. Revised by Roger. 2008.09.22. + // + write_nic_dword(dev, AGGLEN_LMT_L, 0x66666666); // Long GI + write_nic_byte(dev, AGGLEN_LMT_H, 0x06); // Set AMPDU length to 12Kbytes for ShortGI case. + + // + // For Min Spacing configuration. + // + //Adapter->HalFunc.SetHwRegHandler(Adapter, HW_VAR_AMPDU_MIN_SPACE, (u8*)(&Adapter->MgntInfo.MinSpaceCfg)); + rtl8192SU_SetHwRegAmpduMinSpace(dev,priv->MinSpaceCfg); +#endif + + // For EFUSE init configuration. + //if (IS_BOOT_FROM_EFUSE(Adapter)) // We may R/W EFUSE in EFUSE mode + if (priv->bBootFromEfuse) + { + u8 tempval; + + tempval = read_nic_byte(dev, SYS_ISO_CTRL+1); + tempval &= 0xFE; + write_nic_byte(dev, SYS_ISO_CTRL+1, tempval); + + // Enable LDO 2.5V for write action + //tempval = read_nic_byte(Adapter, EFUSE_TEST+3); + //write_nic_byte(Adapter, EFUSE_TEST+3, (tempval | 0x80)); + + // Change Efuse Clock for write action + //write_nic_byte(Adapter, EFUSE_CLK, 0x03); + + // Change Program timing + write_nic_byte(dev, EFUSE_CTRL+3, 0x72); + //printk("!!!!!!!!!!!!!!!!!!!!!%s: write 0x33 with 0x72\n",__FUNCTION__); + RT_TRACE(COMP_INIT, "EFUSE CONFIG OK\n"); + } + + + RT_TRACE(COMP_INIT, "<---MacConfigAfterFwDownload()\n"); +} + +void rtl8192SU_HwConfigureRTL8192SUsb(struct net_device *dev) +{ + + struct r8192_priv *priv = ieee80211_priv(dev); + u8 regBwOpMode = 0; + u32 regRATR = 0, regRRSR = 0; + u8 regTmp = 0; + u32 i = 0; + + //1 This part need to modified according to the rate set we filtered!! + // + // Set RRSR, RATR, and BW_OPMODE registers + // + switch(priv->ieee80211->mode) + { + case WIRELESS_MODE_B: + regBwOpMode = BW_OPMODE_20MHZ; + regRATR = RATE_ALL_CCK; + regRRSR = RATE_ALL_CCK; + break; + case WIRELESS_MODE_A: + regBwOpMode = BW_OPMODE_5G |BW_OPMODE_20MHZ; + regRATR = RATE_ALL_OFDM_AG; + regRRSR = RATE_ALL_OFDM_AG; + break; + case WIRELESS_MODE_G: + regBwOpMode = BW_OPMODE_20MHZ; + regRATR = RATE_ALL_CCK | RATE_ALL_OFDM_AG; + regRRSR = RATE_ALL_CCK | RATE_ALL_OFDM_AG; + break; + case WIRELESS_MODE_AUTO: + if (priv->bInHctTest) + { + regBwOpMode = BW_OPMODE_20MHZ; + regRATR = RATE_ALL_CCK | RATE_ALL_OFDM_AG; + regRRSR = RATE_ALL_CCK | RATE_ALL_OFDM_AG; + } + else + { + regBwOpMode = BW_OPMODE_20MHZ; + regRATR = RATE_ALL_CCK | RATE_ALL_OFDM_AG | RATE_ALL_OFDM_1SS | RATE_ALL_OFDM_2SS; + regRRSR = RATE_ALL_CCK | RATE_ALL_OFDM_AG; + } + break; + case WIRELESS_MODE_N_24G: + // It support CCK rate by default. + // CCK rate will be filtered out only when associated AP does not support it. + regBwOpMode = BW_OPMODE_20MHZ; + regRATR = RATE_ALL_CCK | RATE_ALL_OFDM_AG | RATE_ALL_OFDM_1SS | RATE_ALL_OFDM_2SS; + regRRSR = RATE_ALL_CCK | RATE_ALL_OFDM_AG; + break; + case WIRELESS_MODE_N_5G: + regBwOpMode = BW_OPMODE_5G; + regRATR = RATE_ALL_OFDM_AG | RATE_ALL_OFDM_1SS | RATE_ALL_OFDM_2SS; + regRRSR = RATE_ALL_OFDM_AG; + break; + } + + // + // We disable CCK response rate until FIB CCK rate IC's back. + // 2008.09.23. + // + regTmp = read_nic_byte(dev, INIRTSMCS_SEL); +#ifdef RTL8192SU_DISABLE_CCK_RATE + regRRSR = ((regRRSR & 0x000ffff0)<<8) | regTmp; +#else + regRRSR = ((regRRSR & 0x000fffff)<<8) | regTmp; +#endif + + // + // Update SIFS timing. + // + //priv->SifsTime = 0x0e0e0a0a; + //Adapter->HalFunc.SetHwRegHandler( Adapter, HW_VAR_SIFS, (pu1Byte)&pHalData->SifsTime); + { u8 val[4] = {0x0e, 0x0e, 0x0a, 0x0a}; + // SIFS for CCK Data ACK + write_nic_byte(dev, SIFS_CCK, val[0]); + // SIFS for CCK consecutive tx like CTS data! + write_nic_byte(dev, SIFS_CCK+1, val[1]); + + // SIFS for OFDM Data ACK + write_nic_byte(dev, SIFS_OFDM, val[2]); + // SIFS for OFDM consecutive tx like CTS data! + write_nic_byte(dev, SIFS_OFDM+1, val[3]); + } + + write_nic_dword(dev, INIRTSMCS_SEL, regRRSR); + write_nic_byte(dev, BW_OPMODE, regBwOpMode); + + // + // Suggested by SD1 Alex, 2008-06-14. + // + //PlatformEFIOWrite1Byte(Adapter, TXOP_STALL_CTRL, 0x80);//NAV to protect all TXOP. + + // + // Set Data Auto Rate Fallback Retry Count register. + // + write_nic_dword(dev, DARFRC, 0x02010000); + write_nic_dword(dev, DARFRC+4, 0x06050403); + write_nic_dword(dev, RARFRC, 0x02010000); + write_nic_dword(dev, RARFRC+4, 0x06050403); + + // Set Data Auto Rate Fallback Reg. Added by Roger, 2008.09.22. + for (i = 0; i < 8; i++) +#ifdef RTL8192SU_DISABLE_CCK_RATE + write_nic_dword(dev, ARFR0+i*4, 0x1f0ff0f0); +#else + write_nic_dword(dev, ARFR0+i*4, 0x1f0ffff0); +#endif + + // + // Aggregation length limit. Revised by Roger. 2008.09.22. + // + write_nic_byte(dev, AGGLEN_LMT_H, 0x0f); // Set AMPDU length to 12Kbytes for ShortGI case. + write_nic_dword(dev, AGGLEN_LMT_L, 0xddd77442); // Long GI + write_nic_dword(dev, AGGLEN_LMT_L+4, 0xfffdd772); + + // Set NAV protection length + write_nic_word(dev, NAV_PROT_LEN, 0x0080); + + // Set TXOP stall control for several queue/HI/BCN/MGT/ + write_nic_byte(dev, TXOP_STALL_CTRL, 0x00); // NAV Protect next packet. + + // Set MSDU lifetime. + write_nic_byte(dev, MLT, 0x8f); + + // Set CCK/OFDM SIFS + write_nic_word(dev, SIFS_CCK, 0x0a0a); // CCK SIFS shall always be 10us. + write_nic_word(dev, SIFS_OFDM, 0x0e0e); + + write_nic_byte(dev, ACK_TIMEOUT, 0x40); + + // CF-END Threshold + write_nic_byte(dev, CFEND_TH, 0xFF); + + // + // For Min Spacing configuration. + // + switch(priv->rf_type) + { + case RF_1T2R: + case RF_1T1R: + RT_TRACE(COMP_INIT, "Initializeadapter: RF_Type%s\n", (priv->rf_type==RF_1T1R? "(1T1R)":"(1T2R)")); + priv->MinSpaceCfg = (MAX_MSS_DENSITY_1T<<3); + break; + case RF_2T2R: + case RF_2T2R_GREEN: + RT_TRACE(COMP_INIT, "Initializeadapter:RF_Type(2T2R)\n"); + priv->MinSpaceCfg = (MAX_MSS_DENSITY_2T<<3); + break; + } + write_nic_byte(dev, AMPDU_MIN_SPACE, priv->MinSpaceCfg); + + //LZM 090219 + // + // For Min Spacing configuration. + // + //priv->MinSpaceCfg = 0x00; + //rtl8192SU_SetHwRegAmpduMinSpace(dev, priv->MinSpaceCfg); +} + +#endif + +#ifdef RTL8192SU +// Description: Initial HW relted registers. +// +// Assumption: This function is only invoked at driver intialization once. +// +// 2008.06.10, Added by Roger. +bool rtl8192SU_adapter_start(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + //u32 dwRegRead = 0; + //bool init_status = true; + //u32 ulRegRead; + bool rtStatus = true; + //u8 PipeIndex; + //u8 eRFPath, tmpU1b; + u8 fw_download_times = 1; + + + RT_TRACE(COMP_INIT, "--->InitializeAdapter8192SUsb()\n"); + + //pHalData->bGPIOChangeRF = FALSE; + + + // + // 2008.06.15. + // + // Initialization Steps on RTL8192SU: + // a. MAC initialization prior to sending down firmware code. + // b. Download firmware code step by step(i.e., IMEM, EMEM, DMEM). + // c. MAC configuration after firmware has been download successfully. + // d. Initialize BB related configurations. + // e. Initialize RF related configurations. + // f. Start to BulkIn transfer. + // + + // + //a. MAC initialization prior to send down firmware code. + // +start: + rtl8192SU_MacConfigBeforeFwDownloadASIC(dev); + + // + //b. Download firmware code step by step(i.e., IMEM, EMEM, DMEM). + // + rtStatus = FirmwareDownload92S(dev); + if(rtStatus != true) + { + if(fw_download_times == 1){ + RT_TRACE(COMP_INIT, "InitializeAdapter8192SUsb(): Download Firmware failed once, Download again!!\n"); + fw_download_times = fw_download_times + 1; + goto start; + }else{ + RT_TRACE(COMP_INIT, "InitializeAdapter8192SUsb(): Download Firmware failed twice, end!!\n"); + goto end; + } + } + // + //c. MAC configuration after firmware has been download successfully. + // + rtl8192SU_MacConfigAfterFwDownload(dev); + +#if (RTL8192S_DISABLE_FW_DM == 1) + write_nic_dword(dev, WFM5, FW_DM_DISABLE); +#endif + //priv->bLbusEnable = TRUE; + //if(priv->RegRfOff == TRUE) + // priv->eRFPowerState = eRfOff; + + // Save target channel + // Current Channel will be updated again later. + //priv->CurrentChannel = Channel; + rtStatus = PHY_MACConfig8192S(dev);//===>ok + if(rtStatus != true) + { + RT_TRACE(COMP_INIT, "InitializeAdapter8192SUsb(): Fail to configure MAC!!\n"); + goto end; + } + if (1){ + int i; + for (i=0; i<4; i++) + write_nic_dword(dev,WDCAPARA_ADD[i], 0x5e4322); + write_nic_byte(dev,AcmHwCtrl, 0x01); + } + + + // + //d. Initialize BB related configurations. + // + + rtStatus = PHY_BBConfig8192S(dev);//===>ok + if(rtStatus != true) + { + RT_TRACE(COMP_INIT, "InitializeAdapter8192SUsb(): Fail to configure BB!!\n"); + goto end; + } + + rtl8192_setBBreg(dev, rFPGA0_AnalogParameter2, 0xff, 0x58);//===>ok + + // + // e. Initialize RF related configurations. + // + // 2007/11/02 MH Before initalizing RF. We can not use FW to do RF-R/W. + priv->Rf_Mode = RF_OP_By_SW_3wire; + + // For RF test only from Scott's suggestion + //write_nic_byte(dev, 0x27, 0xDB); + //write_nic_byte(dev, 0x1B, 0x07); + + + write_nic_byte(dev, AFE_XTAL_CTRL+1, 0xDB); + + // The following IOs are configured for each RF modules. + // Enable RF module and reset RF and SDM module. 2008.11.17. + if(priv->card_8192_version == VERSION_8192S_ACUT) + write_nic_byte(dev, SPS1_CTRL+3, (u8)(RF_EN|RF_RSTB|RF_SDMRSTB)); // Fix A-Cut bug. + else + write_nic_byte(dev, RF_CTRL, (u8)(RF_EN|RF_RSTB|RF_SDMRSTB)); + + rtStatus = PHY_RFConfig8192S(dev);//===>ok + if(rtStatus != true) + { + RT_TRACE(COMP_INIT, "InitializeAdapter8192SUsb(): Fail to configure RF!!\n"); + goto end; + } + + + // Set CCK and OFDM Block "ON" + rtl8192_setBBreg(dev, rFPGA0_RFMOD, bCCKEn, 0x1); + rtl8192_setBBreg(dev, rFPGA0_RFMOD, bOFDMEn, 0x1); + + // + // Turn off Radio B while RF type is 1T1R by SD3 Wilsion's request. + // Revised by Roger, 2008.12.18. + // + if(priv->rf_type == RF_1T1R) + { + // This is needed for PHY_REG after 20081219 + rtl8192_setBBreg(dev, rFPGA0_RFMOD, 0xff000000, 0x03); + // This is needed for PHY_REG before 20081219 + //PHY_SetBBReg(Adapter, rOFDM0_TRxPathEnable, bMaskByte0, 0x11); + } + +#if (RTL8192SU_DISABLE_IQK==0) + // For 1T2R IQK only currently. + if (priv->card_8192_version == VERSION_8192S_BCUT) + { + PHY_IQCalibrateBcut(dev); + } + else if (priv->card_8192_version == VERSION_8192S_ACUT) + { + PHY_IQCalibrate(dev); + } +#endif + + //LZM 090219 + // Set CCK and OFDM Block "ON" + //rtl8192_setBBreg(dev, rFPGA0_RFMOD, bCCKEn, 0x1); + //rtl8192_setBBreg(dev, rFPGA0_RFMOD, bOFDMEn, 0x1); + + + //3//Get hardware version, do it in read eeprom? + //GetHardwareVersion819xUsb(Adapter); + + //3// + //3 //Set Hardware + //3// + rtl8192SU_HwConfigureRTL8192SUsb(dev);//==>ok + + // + // We set MAC address here if autoload was failed before, + // otherwise IDR0 will NOT contain any value. + // + write_nic_dword(dev, IDR0, ((u32*)dev->dev_addr)[0]); + write_nic_word(dev, IDR4, ((u16*)(dev->dev_addr + 4))[0]); + if(!priv->bInHctTest) + { + if(priv->ResetProgress == RESET_TYPE_NORESET) + { + //RT_TRACE(COMP_MLME, DBG_LOUD, ("Initializeadapter8192SUsb():RegWirelessMode(%#x) \n", Adapter->RegWirelessMode)); + //Adapter->HalFunc.SetWirelessModeHandler(Adapter, Adapter->RegWirelessMode); + rtl8192_SetWirelessMode(dev, priv->ieee80211->mode);//===>ok + } + } + else + { + priv->ieee80211->mode = WIRELESS_MODE_G; + rtl8192_SetWirelessMode(dev, WIRELESS_MODE_G); + } + + //Security related. + //----------------------------------------------------------------------------- + // Set up security related. 070106, by rcnjko: + // 1. Clear all H/W keys. + // 2. Enable H/W encryption/decryption. + //----------------------------------------------------------------------------- + //CamResetAllEntry(Adapter); + //Adapter->HalFunc.EnableHWSecCfgHandler(Adapter); + + //SecClearAllKeys(Adapter); + CamResetAllEntry(dev); + //SecInit(Adapter); + { + u8 SECR_value = 0x0; + SECR_value |= SCR_TxEncEnable; + SECR_value |= SCR_RxDecEnable; + SECR_value |= SCR_NoSKMC; + write_nic_byte(dev, SECR, SECR_value); + } + +#if 0 + + if(pHalData->VersionID == VERSION_8192SU_A) + { + // cosa add for tx power level initialization. + GetTxPowerOriginalOffset(Adapter); + SetTxPowerLevel819xUsb(Adapter, Channel); + } +#endif + + +#ifdef TO_DO_LIST + + //PHY_UpdateInitialGain(dev); + + if(priv->RegRfOff == true) + { // User disable RF via registry. + u8 eRFPath = 0; + + RT_TRACE((COMP_INIT|COMP_RF), "InitializeAdapter8192SUsb(): Turn off RF for RegRfOff ----------\n"); + MgntActSet_RF_State(dev, eRfOff, RF_CHANGE_BY_SW); + // Those action will be discard in MgntActSet_RF_State because off the same state + for(eRFPath = 0; eRFPath NumTotalRFPath; eRFPath++) + rtl8192_setBBreg(dev, (RF90_RADIO_PATH_E)eRFPath, 0x4, 0xC00, 0x0); + } + else if(priv->RfOffReason > RF_CHANGE_BY_PS) + { // H/W or S/W RF OFF before sleep. + RT_TRACE((COMP_INIT|COMP_RF), "InitializeAdapter8192SUsb(): Turn off RF for RfOffReason(%d) ----------\n", priv->RfOffReason); + MgntActSet_RF_State(dev, eRfOff, priv->RfOffReason); + } + else + { + priv->eRFPowerState = eRfOn; + priv->RfOffReason = 0; + RT_TRACE((COMP_INIT|COMP_RF), "InitializeAdapter8192SUsb(): RF is on ----------\n"); + } + +#endif + + +// +// f. Start to BulkIn transfer. +// +#ifdef TO_DO_LIST + +#ifndef UNDER_VISTA + { + u8 i; + PlatformAcquireSpinLock(Adapter, RT_RX_SPINLOCK); + + for(PipeIndex=0; PipeIndex < MAX_RX_QUEUE; PipeIndex++) + { + if (PipeIndex == 0) + { + for(i=0; i<32; i++) + HalUsbInMpdu(Adapter, PipeIndex); + } + else + { + //HalUsbInMpdu(Adapter, PipeIndex); + //HalUsbInMpdu(Adapter, PipeIndex); + //HalUsbInMpdu(Adapter, PipeIndex); + } + } + PlatformReleaseSpinLock(Adapter, RT_RX_SPINLOCK); + } +#else + // Joseph add to 819X code base for Vista USB platform. + // This part may need to be add to Hal819xU code base. too. + PlatformUsbEnableInPipes(Adapter); +#endif + + RT_TRACE(COMP_INIT, "HighestOperaRate = %x\n", Adapter->MgntInfo.HighestOperaRate); + + PlatformStartWorkItem( &(pHalData->RtUsbCheckForHangWorkItem) ); + + // + // The following configurations are for ASIC verification temporally. + // 2008.07.10. + // + +#endif + + // + // Read EEPROM TX power index and PHY_REG_PG.txt to capture correct + // TX power index for different rate set. + // + //if(priv->card_8192_version >= VERSION_8192S_ACUT) + { + // Get original hw reg values + PHY_GetHWRegOriginalValue(dev); + + // Write correct tx power index//FIXLZM + PHY_SetTxPowerLevel8192S(dev, priv->chan); + } + + { + u8 tmpU1b = 0; + // EEPROM R/W workaround + tmpU1b = read_nic_byte(dev, MAC_PINMUX_CFG); + write_nic_byte(dev, MAC_PINMUX_CFG, tmpU1b&(~GPIOMUX_EN)); + } + +// +// 2008.08.19. +// We return status here for temporal FPGA verification, 2008.08.19. + +#ifdef RTL8192SU_FW_IQK + write_nic_dword(dev, WFM5, FW_IQK_ENABLE); + ChkFwCmdIoDone(dev); +#endif + + // + // We enable high power mechanism after NIC initialized. + // 2008.11.27. + // + write_nic_dword(dev, WFM5, FW_RA_RESET); + ChkFwCmdIoDone(dev); + write_nic_dword(dev, WFM5, FW_RA_ACTIVE); + ChkFwCmdIoDone(dev); + write_nic_dword(dev, WFM5, FW_RA_REFRESH); + ChkFwCmdIoDone(dev); + write_nic_dword(dev, WFM5, FW_BB_RESET_ENABLE); + +// We return status here for temporal FPGA verification. 2008.05.12. +// +#if RTL8192SU_FPGA_UNSPECIFIED_NETWORK + // + // To send specific number of packets to verify MAC Lookback mode. + // + //SendRandomTxPkt(Adapter, 0); // Burst mode for verification. + //rtStatus = RT_STATUS_FAILURE; + rtStatus = true; + goto end; +#endif + +// The following IO was for FPGA verification purpose. Added by Roger, 2008.09.11. +#if 0 + // 2008/08/19 MH From SD1 Jong, we must write some register for true PHY/MAC FPGA. + write_nic_byte(dev, rOFDM0_XAAGCCore1, 0x30); + write_nic_byte(dev, rOFDM0_XBAGCCore1, 0x30); + + write_nic_byte(dev, rOFDM0_RxDetector1, 0x42); + + //write_nic_dword(Adapter, RCR, 0x817FF02F); + + write_nic_dword(Adapter, rTxAGC_Mcs15_Mcs12, 0x06060606); +#endif +end: +return rtStatus; +} + +#else + +//InitializeAdapter and PhyCfg +bool rtl8192_adapter_start(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + u32 dwRegRead = 0; + bool init_status = true; + RT_TRACE(COMP_INIT, "====>%s()\n", __FUNCTION__); + priv->Rf_Mode = RF_OP_By_SW_3wire; + //for ASIC power on sequence + write_nic_byte_E(dev, 0x5f, 0x80); + mdelay(50); + write_nic_byte_E(dev, 0x5f, 0xf0); + write_nic_byte_E(dev, 0x5d, 0x00); + write_nic_byte_E(dev, 0x5e, 0x80); + write_nic_byte(dev, 0x17, 0x37); + mdelay(10); +//#ifdef TO_DO_LIST + priv->pFirmware->firmware_status = FW_STATUS_0_INIT; + //config CPUReset Register + //Firmware Reset or not? + dwRegRead = read_nic_dword(dev, CPU_GEN); + if (priv->pFirmware->firmware_status == FW_STATUS_0_INIT) + dwRegRead |= CPU_GEN_SYSTEM_RESET; //do nothing here? + else if (priv->pFirmware->firmware_status == FW_STATUS_5_READY) + dwRegRead |= CPU_GEN_FIRMWARE_RESET; + else + RT_TRACE(COMP_ERR, "ERROR in %s(): undefined firmware state(%d)\n", __FUNCTION__, priv->pFirmware->firmware_status); + + write_nic_dword(dev, CPU_GEN, dwRegRead); + //mdelay(30); + //config BB. + rtl8192_BBConfig(dev); + +#if 1 + //Loopback mode or not + priv->LoopbackMode = RTL819xU_NO_LOOPBACK; +// priv->LoopbackMode = RTL819xU_MAC_LOOPBACK; + + dwRegRead = read_nic_dword(dev, CPU_GEN); + if (priv->LoopbackMode == RTL819xU_NO_LOOPBACK) + dwRegRead = ((dwRegRead & CPU_GEN_NO_LOOPBACK_MSK) | CPU_GEN_NO_LOOPBACK_SET); + else if (priv->LoopbackMode == RTL819xU_MAC_LOOPBACK) + dwRegRead |= CPU_CCK_LOOPBACK; + else + RT_TRACE(COMP_ERR, "Serious error in %s(): wrong loopback mode setting(%d)\n", __FUNCTION__, priv->LoopbackMode); + + write_nic_dword(dev, CPU_GEN, dwRegRead); + + //after reset cpu, we need wait for a seconds to write in register. + udelay(500); + + //xiong add for new bitfile:usb suspend reset pin set to 1. //do we need? + write_nic_byte_E(dev, 0x5f, (read_nic_byte_E(dev, 0x5f)|0x20)); + + //Set Hardware + rtl8192_hwconfig(dev); + + //turn on Tx/Rx + write_nic_byte(dev, CMDR, CR_RE|CR_TE); + + //set IDR0 here + write_nic_dword(dev, MAC0, ((u32*)dev->dev_addr)[0]); + write_nic_word(dev, MAC4, ((u16*)(dev->dev_addr + 4))[0]); + + //set RCR + write_nic_dword(dev, RCR, priv->ReceiveConfig); + + //Initialize Number of Reserved Pages in Firmware Queue + write_nic_dword(dev, RQPN1, NUM_OF_PAGE_IN_FW_QUEUE_BK << RSVD_FW_QUEUE_PAGE_BK_SHIFT |\ + NUM_OF_PAGE_IN_FW_QUEUE_BE << RSVD_FW_QUEUE_PAGE_BE_SHIFT | \ + NUM_OF_PAGE_IN_FW_QUEUE_VI << RSVD_FW_QUEUE_PAGE_VI_SHIFT | \ + NUM_OF_PAGE_IN_FW_QUEUE_VO <ResetProgress is %d\n", __FUNCTION__,priv->ResetProgress); + if(priv->ResetProgress == RESET_TYPE_NORESET) + rtl8192_SetWirelessMode(dev, priv->ieee80211->mode); + if(priv->ResetProgress == RESET_TYPE_NORESET){ + CamResetAllEntry(dev); + { + u8 SECR_value = 0x0; + SECR_value |= SCR_TxEncEnable; + SECR_value |= SCR_RxDecEnable; + SECR_value |= SCR_NoSKMC; + write_nic_byte(dev, SECR, SECR_value); + } + } + + //Beacon related + write_nic_word(dev, ATIMWND, 2); + write_nic_word(dev, BCN_INTERVAL, 100); + + { +#define DEFAULT_EDCA 0x005e4332 + int i; + for (i=0; iResetProgress == RESET_TYPE_NORESET) + { + u32 ulValue; + PRT_HIGH_THROUGHPUT pHTInfo = priv->ieee80211->pHTInfo; + ulValue = (pHTInfo->UsbRxFwAggrEn<<24) | (pHTInfo->UsbRxFwAggrPageNum<<16) | + (pHTInfo->UsbRxFwAggrPacketNum<<8) | (pHTInfo->UsbRxFwAggrTimeout); + /* + * If usb rx firmware aggregation is enabled, + * when anyone of three threshold conditions above is reached, + * firmware will send aggregated packet to driver. + */ + write_nic_dword(dev, 0x1a8, ulValue); + priv->bCurrentRxAggrEnable = true; + } +#endif + + rtl8192_phy_configmac(dev); + + if (priv->card_8192_version == (u8) VERSION_819xU_A) + { + rtl8192_phy_getTxPower(dev); + rtl8192_phy_setTxPower(dev, priv->chan); + } + + + priv->usb_error = false; + //Firmware download + init_status = init_firmware(dev); + if(!init_status) + { + RT_TRACE(COMP_ERR,"ERR!!! %s(): Firmware download is failed\n", __FUNCTION__); + return init_status; + } + RT_TRACE(COMP_INIT, "%s():after firmware download\n", __FUNCTION__); + // +#ifdef TO_DO_LIST +if(Adapter->ResetProgress == RESET_TYPE_NORESET) + { + if(pMgntInfo->RegRfOff == TRUE) + { // User disable RF via registry. + RT_TRACE((COMP_INIT|COMP_RF), DBG_LOUD, ("InitializeAdapter819xUsb(): Turn off RF for RegRfOff ----------\n")); + MgntActSet_RF_State(Adapter, eRfOff, RF_CHANGE_BY_SW); + // Those action will be discard in MgntActSet_RF_State because off the same state + for(eRFPath = 0; eRFPath NumTotalRFPath; eRFPath++) + PHY_SetRFReg(Adapter, (RF90_RADIO_PATH_E)eRFPath, 0x4, 0xC00, 0x0); + } + else if(pMgntInfo->RfOffReason > RF_CHANGE_BY_PS) + { // H/W or S/W RF OFF before sleep. + RT_TRACE((COMP_INIT|COMP_RF), DBG_LOUD, ("InitializeAdapter819xUsb(): Turn off RF for RfOffReason(%d) ----------\n", pMgntInfo->RfOffReason)); + MgntActSet_RF_State(Adapter, eRfOff, pMgntInfo->RfOffReason); + } + else + { + pHalData->eRFPowerState = eRfOn; + pMgntInfo->RfOffReason = 0; + RT_TRACE((COMP_INIT|COMP_RF), DBG_LOUD, ("InitializeAdapter819xUsb(): RF is on ----------\n")); + } + } + else + { + if(pHalData->eRFPowerState == eRfOff) + { + MgntActSet_RF_State(Adapter, eRfOff, pMgntInfo->RfOffReason); + // Those action will be discard in MgntActSet_RF_State because off the same state + for(eRFPath = 0; eRFPath NumTotalRFPath; eRFPath++) + PHY_SetRFReg(Adapter, (RF90_RADIO_PATH_E)eRFPath, 0x4, 0xC00, 0x0); + } + } +#endif + //config RF. + if(priv->ResetProgress == RESET_TYPE_NORESET){ + rtl8192_phy_RFConfig(dev); + RT_TRACE(COMP_INIT, "%s():after phy RF config\n", __FUNCTION__); + } + + + if(priv->ieee80211->FwRWRF) + // We can force firmware to do RF-R/W + priv->Rf_Mode = RF_OP_By_FW; + else + priv->Rf_Mode = RF_OP_By_SW_3wire; + + + rtl8192_phy_updateInitGain(dev); + /*--set CCK and OFDM Block "ON"--*/ + rtl8192_setBBreg(dev, rFPGA0_RFMOD, bCCKEn, 0x1); + rtl8192_setBBreg(dev, rFPGA0_RFMOD, bOFDMEn, 0x1); + + if(priv->ResetProgress == RESET_TYPE_NORESET) + { + //if D or C cut + u8 tmpvalue = read_nic_byte(dev, 0x301); + if(tmpvalue ==0x03) + { + priv->bDcut = TRUE; + RT_TRACE(COMP_POWER_TRACKING, "D-cut\n"); + } + else + { + priv->bDcut = FALSE; + RT_TRACE(COMP_POWER_TRACKING, "C-cut\n"); + } + dm_initialize_txpower_tracking(dev); + + if(priv->bDcut == TRUE) + { + u32 i, TempCCk; + u32 tmpRegA= rtl8192_QueryBBReg(dev,rOFDM0_XATxIQImbalance,bMaskDWord); + // u32 tmpRegC= rtl8192_QueryBBReg(dev,rOFDM0_XCTxIQImbalance,bMaskDWord); + for(i = 0; itxbbgain_table[i].txbbgain_value) + { + priv->rfa_txpowertrackingindex= (u8)i; + priv->rfa_txpowertrackingindex_real= (u8)i; + priv->rfa_txpowertracking_default= priv->rfa_txpowertrackingindex; + break; + } + } + + TempCCk = rtl8192_QueryBBReg(dev, rCCK0_TxFilter1, bMaskByte2); + + for(i=0 ; icck_txbbgain_table[i].ccktxbb_valuearray[0]) + { + priv->cck_present_attentuation_20Mdefault=(u8) i; + break; + } + } + priv->cck_present_attentuation_40Mdefault= 0; + priv->cck_present_attentuation_difference= 0; + priv->cck_present_attentuation = priv->cck_present_attentuation_20Mdefault; + + // pMgntInfo->bTXPowerTracking = FALSE;//TEMPLY DISABLE + } + } + write_nic_byte(dev, 0x87, 0x0); + + +#endif + return init_status; +} + +#endif +/* this configures registers for beacon tx and enables it via + * rtl8192_beacon_tx_enable(). rtl8192_beacon_tx_disable() might + * be used to stop beacon transmission + */ +#if 0 +void rtl8192_start_tx_beacon(struct net_device *dev) +{ + int i; + struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); + u16 word; + DMESG("Enabling beacon TX"); + //write_nic_byte(dev, TX_CONF,0xe6);// TX_CONF + //rtl8192_init_beacon(dev); + //set_nic_txring(dev); +// rtl8192_prepare_beacon(dev); + rtl8192_irq_disable(dev); +// rtl8192_beacon_tx_enable(dev); + rtl8192_set_mode(dev,EPROM_CMD_CONFIG); + //write_nic_byte(dev,0x9d,0x20); //DMA Poll + //write_nic_word(dev,0x7a,0); + //write_nic_word(dev,0x7a,0x8000); + + + word = read_nic_word(dev, BcnItv); + word &= ~BcnItv_BcnItv; // clear Bcn_Itv + write_nic_word(dev, BcnItv, word); + + write_nic_word(dev, AtimWnd, + read_nic_word(dev, AtimWnd) &~ AtimWnd_AtimWnd); + + word = read_nic_word(dev, BCN_INTR_ITV); + word &= ~BCN_INTR_ITV_MASK; + + //word |= priv->ieee80211->beacon_interval * + // ((priv->txbeaconcount > 1)?(priv->txbeaconcount-1):1); + // FIXME:FIXME check if correct ^^ worked with 0x3e8; + + write_nic_word(dev, BCN_INTR_ITV, word); + + //write_nic_word(dev,0x2e,0xe002); + //write_nic_dword(dev,0x30,0xb8c7832e); + for(i=0; iieee80211->beacon_cell_ssid[i]); + +// rtl8192_update_msr(dev); + + + //write_nic_byte(dev,CONFIG4,3); /* !!!!!!!!!! */ + + rtl8192_set_mode(dev, EPROM_CMD_NORMAL); + + rtl8192_irq_enable(dev); + + /* VV !!!!!!!!!! VV*/ + /* + rtl8192_set_mode(dev,EPROM_CMD_CONFIG); + write_nic_byte(dev,0x9d,0x00); + rtl8192_set_mode(dev,EPROM_CMD_NORMAL); +*/ +} +#endif +/*************************************************************************** + -------------------------------NET STUFF--------------------------- +***************************************************************************/ + +static struct net_device_stats *rtl8192_stats(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + + return &priv->ieee80211->stats; +} + +bool +HalTxCheckStuck819xUsb( + struct net_device *dev + ) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + u16 RegTxCounter = read_nic_word(dev, 0x128); + bool bStuck = FALSE; + RT_TRACE(COMP_RESET,"%s():RegTxCounter is %d,TxCounter is %d\n",__FUNCTION__,RegTxCounter,priv->TxCounter); + if(priv->TxCounter==RegTxCounter) + bStuck = TRUE; + + priv->TxCounter = RegTxCounter; + + return bStuck; +} + +/* +* +* First added: 2006.11.19 by emily +*/ +RESET_TYPE +TxCheckStuck(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + u8 QueueID; +// PRT_TCB pTcb; +// u8 ResetThreshold; + bool bCheckFwTxCnt = false; + //unsigned long flags; + + // + // Decide Stuch threshold according to current power save mode + // + +// RT_TRACE(COMP_RESET, " ==> TxCheckStuck()\n"); +// PlatformAcquireSpinLock(Adapter, RT_TX_SPINLOCK); +// spin_lock_irqsave(&priv->ieee80211->lock,flags); + for (QueueID = 0; QueueID<=BEACON_QUEUE;QueueID ++) + { + if(QueueID == TXCMD_QUEUE) + continue; +#if 1 +#ifdef USB_TX_DRIVER_AGGREGATION_ENABLE + if((skb_queue_len(&priv->ieee80211->skb_waitQ[QueueID]) == 0) && (skb_queue_len(&priv->ieee80211->skb_aggQ[QueueID]) == 0) && (skb_queue_len(&priv->ieee80211->skb_drv_aggQ[QueueID]) == 0)) +#else + if((skb_queue_len(&priv->ieee80211->skb_waitQ[QueueID]) == 0) && (skb_queue_len(&priv->ieee80211->skb_aggQ[QueueID]) == 0)) +#endif + continue; +#endif + + bCheckFwTxCnt = true; + } +// PlatformReleaseSpinLock(Adapter, RT_TX_SPINLOCK); +// spin_unlock_irqrestore(&priv->ieee80211->lock,flags); +// RT_TRACE(COMP_RESET,"bCheckFwTxCnt is %d\n",bCheckFwTxCnt); +#if 1 + if(bCheckFwTxCnt) + { + if(HalTxCheckStuck819xUsb(dev)) + { + RT_TRACE(COMP_RESET, "TxCheckStuck(): Fw indicates no Tx condition! \n"); + return RESET_TYPE_SILENT; + } + } +#endif + return RESET_TYPE_NORESET; +} + +bool +HalRxCheckStuck819xUsb(struct net_device *dev) +{ + u16 RegRxCounter = read_nic_word(dev, 0x130); + struct r8192_priv *priv = ieee80211_priv(dev); + bool bStuck = FALSE; +//#ifdef RTL8192SU + +//#else + static u8 rx_chk_cnt = 0; + RT_TRACE(COMP_RESET,"%s(): RegRxCounter is %d,RxCounter is %d\n",__FUNCTION__,RegRxCounter,priv->RxCounter); + // If rssi is small, we should check rx for long time because of bad rx. + // or maybe it will continuous silent reset every 2 seconds. + rx_chk_cnt++; + if(priv->undecorated_smoothed_pwdb >= (RateAdaptiveTH_High+5)) + { + rx_chk_cnt = 0; //high rssi, check rx stuck right now. + } + else if(priv->undecorated_smoothed_pwdb < (RateAdaptiveTH_High+5) && + ((priv->CurrentChannelBW!=HT_CHANNEL_WIDTH_20&&priv->undecorated_smoothed_pwdb>=RateAdaptiveTH_Low_40M) || + (priv->CurrentChannelBW==HT_CHANNEL_WIDTH_20&&priv->undecorated_smoothed_pwdb>=RateAdaptiveTH_Low_20M)) ) + { + if(rx_chk_cnt < 2) + { + return bStuck; + } + else + { + rx_chk_cnt = 0; + } + } + else if(((priv->CurrentChannelBW!=HT_CHANNEL_WIDTH_20&&priv->undecorated_smoothed_pwdbCurrentChannelBW==HT_CHANNEL_WIDTH_20&&priv->undecorated_smoothed_pwdbundecorated_smoothed_pwdb >= VeryLowRSSI) + { + if(rx_chk_cnt < 4) + { + //DbgPrint("RSSI < %d && RSSI >= %d, no check this time \n", RateAdaptiveTH_Low, VeryLowRSSI); + return bStuck; + } + else + { + rx_chk_cnt = 0; + //DbgPrint("RSSI < %d && RSSI >= %d, check this time \n", RateAdaptiveTH_Low, VeryLowRSSI); + } + } + else + { + if(rx_chk_cnt < 8) + { + //DbgPrint("RSSI <= %d, no check this time \n", VeryLowRSSI); + return bStuck; + } + else + { + rx_chk_cnt = 0; + //DbgPrint("RSSI <= %d, check this time \n", VeryLowRSSI); + } + } +//#endif + + if(priv->RxCounter==RegRxCounter) + bStuck = TRUE; + + priv->RxCounter = RegRxCounter; + + return bStuck; +} + +RESET_TYPE +RxCheckStuck(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + //int i; + bool bRxCheck = FALSE; + +// RT_TRACE(COMP_RESET," ==> RxCheckStuck()\n"); + //PlatformAcquireSpinLock(Adapter, RT_RX_SPINLOCK); + + if(priv->IrpPendingCount > 1) + bRxCheck = TRUE; + //PlatformReleaseSpinLock(Adapter, RT_RX_SPINLOCK); + +// RT_TRACE(COMP_RESET,"bRxCheck is %d \n",bRxCheck); + if(bRxCheck) + { + if(HalRxCheckStuck819xUsb(dev)) + { + RT_TRACE(COMP_RESET, "RxStuck Condition\n"); + return RESET_TYPE_SILENT; + } + } + return RESET_TYPE_NORESET; +} + + +/** +* This function is called by Checkforhang to check whether we should ask OS to reset driver +* +* \param pAdapter The adapter context for this miniport +* +* Note:NIC with USB interface sholud not call this function because we cannot scan descriptor +* to judge whether there is tx stuck. +* Note: This function may be required to be rewrite for Vista OS. +* <<>> +* +* 8185 and 8185b does not implement this function. This is added by Emily at 2006.11.24 +*/ +RESET_TYPE +rtl819x_ifcheck_resetornot(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + RESET_TYPE TxResetType = RESET_TYPE_NORESET; + RESET_TYPE RxResetType = RESET_TYPE_NORESET; + RT_RF_POWER_STATE rfState; + +#if (defined (RTL8192SU_FPGA_2MAC_VERIFICATION)||defined (RTL8192SU_ASIC_VERIFICATION)) + return RESET_TYPE_NORESET; +#endif + + rfState = priv->ieee80211->eRFPowerState; + + TxResetType = TxCheckStuck(dev); +#if 1 + if( rfState != eRfOff || + /*ADAPTER_TEST_STATUS_FLAG(Adapter, ADAPTER_STATUS_FW_DOWNLOAD_FAILURE)) &&*/ + (priv->ieee80211->iw_mode != IW_MODE_ADHOC)) + { + // If driver is in the status of firmware download failure , driver skips RF initialization and RF is + // in turned off state. Driver should check whether Rx stuck and do silent reset. And + // if driver is in firmware download failure status, driver should initialize RF in the following + // silent reset procedure Emily, 2008.01.21 + + // Driver should not check RX stuck in IBSS mode because it is required to + // set Check BSSID in order to send beacon, however, if check BSSID is + // set, STA cannot hear any packet a all. Emily, 2008.04.12 + RxResetType = RxCheckStuck(dev); + } +#endif + if(TxResetType==RESET_TYPE_NORMAL || RxResetType==RESET_TYPE_NORMAL) + return RESET_TYPE_NORMAL; + else if(TxResetType==RESET_TYPE_SILENT || RxResetType==RESET_TYPE_SILENT){ + RT_TRACE(COMP_RESET,"%s():silent reset\n",__FUNCTION__); + return RESET_TYPE_SILENT; + } + else + return RESET_TYPE_NORESET; + +} + +void rtl8192_cancel_deferred_work(struct r8192_priv* priv); +int _rtl8192_up(struct net_device *dev); +int rtl8192_close(struct net_device *dev); + + + +void +CamRestoreAllEntry( struct net_device *dev) +{ + u8 EntryId = 0; + struct r8192_priv *priv = ieee80211_priv(dev); + u8* MacAddr = priv->ieee80211->current_network.bssid; + + static u8 CAM_CONST_ADDR[4][6] = { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x03}}; + static u8 CAM_CONST_BROAD[] = + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + + RT_TRACE(COMP_SEC, "CamRestoreAllEntry: \n"); + + + if ((priv->ieee80211->pairwise_key_type == KEY_TYPE_WEP40)|| + (priv->ieee80211->pairwise_key_type == KEY_TYPE_WEP104)) + { + + for(EntryId=0; EntryId<4; EntryId++) + { + { + MacAddr = CAM_CONST_ADDR[EntryId]; + setKey(dev, + EntryId , + EntryId, + priv->ieee80211->pairwise_key_type, + MacAddr, + 0, + NULL); + } + } + + } + else if(priv->ieee80211->pairwise_key_type == KEY_TYPE_TKIP) + { + + { + if(priv->ieee80211->iw_mode == IW_MODE_ADHOC) + setKey(dev, + 4, + 0, + priv->ieee80211->pairwise_key_type, + (u8*)dev->dev_addr, + 0, + NULL); + else + setKey(dev, + 4, + 0, + priv->ieee80211->pairwise_key_type, + MacAddr, + 0, + NULL); + } + } + else if(priv->ieee80211->pairwise_key_type == KEY_TYPE_CCMP) + { + + { + if(priv->ieee80211->iw_mode == IW_MODE_ADHOC) + setKey(dev, + 4, + 0, + priv->ieee80211->pairwise_key_type, + (u8*)dev->dev_addr, + 0, + NULL); + else + setKey(dev, + 4, + 0, + priv->ieee80211->pairwise_key_type, + MacAddr, + 0, + NULL); + } + } + + + + if(priv->ieee80211->group_key_type == KEY_TYPE_TKIP) + { + MacAddr = CAM_CONST_BROAD; + for(EntryId=1 ; EntryId<4 ; EntryId++) + { + { + setKey(dev, + EntryId, + EntryId, + priv->ieee80211->group_key_type, + MacAddr, + 0, + NULL); + } + } + if(priv->ieee80211->iw_mode == IW_MODE_ADHOC) + setKey(dev, + 0, + 0, + priv->ieee80211->group_key_type, + CAM_CONST_ADDR[0], + 0, + NULL); + } + else if(priv->ieee80211->group_key_type == KEY_TYPE_CCMP) + { + MacAddr = CAM_CONST_BROAD; + for(EntryId=1; EntryId<4 ; EntryId++) + { + { + setKey(dev, + EntryId , + EntryId, + priv->ieee80211->group_key_type, + MacAddr, + 0, + NULL); + } + } + + if(priv->ieee80211->iw_mode == IW_MODE_ADHOC) + setKey(dev, + 0 , + 0, + priv->ieee80211->group_key_type, + CAM_CONST_ADDR[0], + 0, + NULL); + } +} +////////////////////////////////////////////////////////////// +// This function is used to fix Tx/Rx stop bug temporarily. +// This function will do "system reset" to NIC when Tx or Rx is stuck. +// The method checking Tx/Rx stuck of this function is supported by FW, +// which reports Tx and Rx counter to register 0x128 and 0x130. +////////////////////////////////////////////////////////////// +void +rtl819x_ifsilentreset(struct net_device *dev) +{ + //OCTET_STRING asocpdu; + struct r8192_priv *priv = ieee80211_priv(dev); + u8 reset_times = 0; + int reset_status = 0; + struct ieee80211_device *ieee = priv->ieee80211; + + + // 2007.07.20. If we need to check CCK stop, please uncomment this line. + //bStuck = Adapter->HalFunc.CheckHWStopHandler(Adapter); + + if(priv->ResetProgress==RESET_TYPE_NORESET) + { +RESET_START: + + RT_TRACE(COMP_RESET,"=========>Reset progress!! \n"); + + // Set the variable for reset. + priv->ResetProgress = RESET_TYPE_SILENT; +// rtl8192_close(dev); +#if 1 + down(&priv->wx_sem); + if(priv->up == 0) + { + RT_TRACE(COMP_ERR,"%s():the driver is not up! return\n",__FUNCTION__); + up(&priv->wx_sem); + return ; + } + priv->up = 0; + RT_TRACE(COMP_RESET,"%s():======>start to down the driver\n",__FUNCTION__); +// if(!netif_queue_stopped(dev)) +// netif_stop_queue(dev); + + rtl8192_rtx_disable(dev); + rtl8192_cancel_deferred_work(priv); + deinit_hal_dm(dev); + del_timer_sync(&priv->watch_dog_timer); + + ieee->sync_scan_hurryup = 1; + if(ieee->state == IEEE80211_LINKED) + { + down(&ieee->wx_sem); + printk("ieee->state is IEEE80211_LINKED\n"); + ieee80211_stop_send_beacons(priv->ieee80211); + del_timer_sync(&ieee->associate_timer); + #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + cancel_delayed_work(&ieee->associate_retry_wq); + #endif + ieee80211_stop_scan(ieee); + netif_carrier_off(dev); + up(&ieee->wx_sem); + } + else{ + printk("ieee->state is NOT LINKED\n"); + ieee80211_softmac_stop_protocol(priv->ieee80211); } + up(&priv->wx_sem); + RT_TRACE(COMP_RESET,"%s():<==========down process is finished\n",__FUNCTION__); + //rtl8192_irq_disable(dev); + RT_TRACE(COMP_RESET,"%s():===========>start to up the driver\n",__FUNCTION__); + reset_status = _rtl8192_up(dev); + + RT_TRACE(COMP_RESET,"%s():<===========up process is finished\n",__FUNCTION__); + if(reset_status == -EAGAIN) + { + if(reset_times < 3) + { + reset_times++; + goto RESET_START; + } + else + { + RT_TRACE(COMP_ERR," ERR!!! %s(): Reset Failed!!\n", __FUNCTION__); + } + } +#endif + ieee->is_silent_reset = 1; +#if 1 + EnableHWSecurityConfig8192(dev); +#if 1 + if(ieee->state == IEEE80211_LINKED && ieee->iw_mode == IW_MODE_INFRA) + { + ieee->set_chan(ieee->dev, ieee->current_network.channel); + +#if 1 +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + queue_work(ieee->wq, &ieee->associate_complete_wq); +#else + schedule_task(&ieee->associate_complete_wq); +#endif +#endif + + } + else if(ieee->state == IEEE80211_LINKED && ieee->iw_mode == IW_MODE_ADHOC) + { + ieee->set_chan(ieee->dev, ieee->current_network.channel); + ieee->link_change(ieee->dev); + + // notify_wx_assoc_event(ieee); + + ieee80211_start_send_beacons(ieee); + + if (ieee->data_hard_resume) + ieee->data_hard_resume(ieee->dev); + netif_carrier_on(ieee->dev); + } +#endif + + CamRestoreAllEntry(dev); + + priv->ResetProgress = RESET_TYPE_NORESET; + priv->reset_count++; + + priv->bForcedSilentReset =false; + priv->bResetInProgress = false; + + // For test --> force write UFWP. + write_nic_byte(dev, UFWP, 1); + RT_TRACE(COMP_RESET, "Reset finished!! ====>[%d]\n", priv->reset_count); +#endif + } +} + +void CAM_read_entry( + struct net_device *dev, + u32 iIndex +) +{ + u32 target_command=0; + u32 target_content=0; + u8 entry_i=0; + u32 ulStatus; + s32 i=100; +// printk("=======>start read CAM\n"); + for(entry_i=0;entry_i=0) + { + ulStatus = read_nic_dword(dev, RWCAM); + if(ulStatus & BIT31){ + continue; + } + else{ + break; + } + } +#endif + write_nic_dword(dev, RWCAM, target_command); + RT_TRACE(COMP_SEC,"CAM_read_entry(): WRITE A0: %x \n",target_command); + // printk("CAM_read_entry(): WRITE A0: %lx \n",target_command); + target_content = read_nic_dword(dev, RCAMO); + RT_TRACE(COMP_SEC, "CAM_read_entry(): WRITE A8: %x \n",target_content); + // printk("CAM_read_entry(): WRITE A8: %lx \n",target_content); + } + printk("\n"); +} + +void rtl819x_update_rxcounts( + struct r8192_priv *priv, + u32* TotalRxBcnNum, + u32* TotalRxDataNum +) +{ + u16 SlotIndex; + u8 i; + + *TotalRxBcnNum = 0; + *TotalRxDataNum = 0; + + SlotIndex = (priv->ieee80211->LinkDetectInfo.SlotIndex++)%(priv->ieee80211->LinkDetectInfo.SlotNum); + priv->ieee80211->LinkDetectInfo.RxBcnNum[SlotIndex] = priv->ieee80211->LinkDetectInfo.NumRecvBcnInPeriod; + priv->ieee80211->LinkDetectInfo.RxDataNum[SlotIndex] = priv->ieee80211->LinkDetectInfo.NumRecvDataInPeriod; + for( i=0; iieee80211->LinkDetectInfo.SlotNum; i++ ){ + *TotalRxBcnNum += priv->ieee80211->LinkDetectInfo.RxBcnNum[i]; + *TotalRxDataNum += priv->ieee80211->LinkDetectInfo.RxDataNum[i]; + } +} + + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) +extern void rtl819x_watchdog_wqcallback(struct work_struct *work) +{ + struct delayed_work *dwork = container_of(work,struct delayed_work,work); + struct r8192_priv *priv = container_of(dwork,struct r8192_priv,watch_dog_wq); + struct net_device *dev = priv->ieee80211->dev; +#else +extern void rtl819x_watchdog_wqcallback(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); +#endif + struct ieee80211_device* ieee = priv->ieee80211; + RESET_TYPE ResetType = RESET_TYPE_NORESET; + static u8 check_reset_cnt=0; + bool bBusyTraffic = false; + + if(!priv->up) + return; + hal_dm_watchdog(dev); + + {//to get busy traffic condition + if(ieee->state == IEEE80211_LINKED) + { + //windows mod 666 to 100. + //if( ieee->LinkDetectInfo.NumRxOkInPeriod> 666 || + // ieee->LinkDetectInfo.NumTxOkInPeriod> 666 ) { + if( ieee->LinkDetectInfo.NumRxOkInPeriod> 100 || + ieee->LinkDetectInfo.NumTxOkInPeriod> 100 ) { + bBusyTraffic = true; + } + ieee->LinkDetectInfo.NumRxOkInPeriod = 0; + ieee->LinkDetectInfo.NumTxOkInPeriod = 0; + ieee->LinkDetectInfo.bBusyTraffic = bBusyTraffic; + } + } + //added by amy for AP roaming + { + if(priv->ieee80211->state == IEEE80211_LINKED && priv->ieee80211->iw_mode == IW_MODE_INFRA) + { + u32 TotalRxBcnNum = 0; + u32 TotalRxDataNum = 0; + + rtl819x_update_rxcounts(priv, &TotalRxBcnNum, &TotalRxDataNum); + if((TotalRxBcnNum+TotalRxDataNum) == 0) + { + #ifdef TODO + if(rfState == eRfOff) + RT_TRACE(COMP_ERR,"========>%s()\n",__FUNCTION__); + #endif + printk("===>%s(): AP is power off,connect another one\n",__FUNCTION__); + // Dot11d_Reset(dev); + priv->ieee80211->state = IEEE80211_ASSOCIATING; + notify_wx_assoc_event(priv->ieee80211); + RemovePeerTS(priv->ieee80211,priv->ieee80211->current_network.bssid); + ieee->is_roaming = true; + priv->ieee80211->link_change(dev); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + queue_work(priv->ieee80211->wq, &priv->ieee80211->associate_procedure_wq); +#else + schedule_task(&priv->ieee80211->associate_procedure_wq); +#endif + + } + } + priv->ieee80211->LinkDetectInfo.NumRecvBcnInPeriod=0; + priv->ieee80211->LinkDetectInfo.NumRecvDataInPeriod=0; + } +// CAM_read_entry(dev,4); + //check if reset the driver + if(check_reset_cnt++ >= 3 && !ieee->is_roaming) + { + ResetType = rtl819x_ifcheck_resetornot(dev); + check_reset_cnt = 3; + //DbgPrint("Start to check silent reset\n"); + } + // RT_TRACE(COMP_RESET,"%s():priv->force_reset is %d,priv->ResetProgress is %d, priv->bForcedSilentReset is %d,priv->bDisableNormalResetCheck is %d,ResetType is %d\n",__FUNCTION__,priv->force_reset,priv->ResetProgress,priv->bForcedSilentReset,priv->bDisableNormalResetCheck,ResetType); +#if 1 + if( (priv->force_reset) || (priv->ResetProgress==RESET_TYPE_NORESET && + (priv->bForcedSilentReset || + (!priv->bDisableNormalResetCheck && ResetType==RESET_TYPE_SILENT)))) // This is control by OID set in Pomelo + { + RT_TRACE(COMP_RESET,"%s():priv->force_reset is %d,priv->ResetProgress is %d, priv->bForcedSilentReset is %d,priv->bDisableNormalResetCheck is %d,ResetType is %d\n",__FUNCTION__,priv->force_reset,priv->ResetProgress,priv->bForcedSilentReset,priv->bDisableNormalResetCheck,ResetType); + rtl819x_ifsilentreset(dev); + } +#endif + priv->force_reset = false; + priv->bForcedSilentReset = false; + priv->bResetInProgress = false; + RT_TRACE(COMP_TRACE, " <==RtUsbCheckForHangWorkItemCallback()\n"); + +} + +void watch_dog_timer_callback(unsigned long data) +{ + struct r8192_priv *priv = ieee80211_priv((struct net_device *) data); + //printk("===============>watch_dog timer\n"); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + queue_delayed_work(priv->priv_wq,&priv->watch_dog_wq, 0); +#else +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + schedule_task(&priv->watch_dog_wq); +#else + queue_work(priv->priv_wq,&priv->watch_dog_wq); +#endif +#endif + mod_timer(&priv->watch_dog_timer, jiffies + MSECS(IEEE80211_WATCH_DOG_TIME)); +#if 0 + priv->watch_dog_timer.expires = jiffies + MSECS(IEEE80211_WATCH_DOG_TIME); + add_timer(&priv->watch_dog_timer); +#endif +} +int _rtl8192_up(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + //int i; + int init_status = 0; + priv->up=1; + priv->ieee80211->ieee_up=1; + RT_TRACE(COMP_INIT, "Bringing up iface"); + init_status = priv->ops->rtl819x_adapter_start(dev); + if(!init_status) + { + RT_TRACE(COMP_ERR,"ERR!!! %s(): initialization is failed!\n", __FUNCTION__); + priv->up=priv->ieee80211->ieee_up = 0; + return -EAGAIN; + } + RT_TRACE(COMP_INIT, "start adapter finished\n"); + rtl8192_rx_enable(dev); +// rtl8192_tx_enable(dev); + if(priv->ieee80211->state != IEEE80211_LINKED) + ieee80211_softmac_start_protocol(priv->ieee80211); + ieee80211_reset_queue(priv->ieee80211); + watch_dog_timer_callback((unsigned long) dev); + if(!netif_queue_stopped(dev)) + netif_start_queue(dev); + else + netif_wake_queue(dev); + + /* + * Make sure that drop_unencrypted is initialized as "0" + * No packets will be sent in non-security mode if we had set drop_unencrypted. + * ex, After kill wpa_supplicant process, make the driver up again. + * drop_unencrypted remains as "1", which is set by wpa_supplicant. 2008/12/04.john + */ + priv->ieee80211->drop_unencrypted = 0; + + return 0; +} + + +int rtl8192_open(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + int ret; + down(&priv->wx_sem); + ret = rtl8192_up(dev); + up(&priv->wx_sem); + return ret; + +} + + +int rtl8192_up(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + + if (priv->up == 1) return -1; + + return _rtl8192_up(dev); +} + + +int rtl8192_close(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + int ret; + + down(&priv->wx_sem); + + ret = rtl8192_down(dev); + + up(&priv->wx_sem); + + return ret; + +} + +int rtl8192_down(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + int i; + + if (priv->up == 0) return -1; + + priv->up=0; + priv->ieee80211->ieee_up = 0; + RT_TRACE(COMP_DOWN, "==========>%s()\n", __FUNCTION__); +/* FIXME */ + if (!netif_queue_stopped(dev)) + netif_stop_queue(dev); + + rtl8192_rtx_disable(dev); + //rtl8192_irq_disable(dev); + + /* Tx related queue release */ + for(i = 0; i < MAX_QUEUE_SIZE; i++) { + skb_queue_purge(&priv->ieee80211->skb_waitQ [i]); + } + for(i = 0; i < MAX_QUEUE_SIZE; i++) { + skb_queue_purge(&priv->ieee80211->skb_aggQ [i]); + } + + for(i = 0; i < MAX_QUEUE_SIZE; i++) { + skb_queue_purge(&priv->ieee80211->skb_drv_aggQ [i]); + } + + //as cancel_delayed_work will del work->timer, so if work is not definedas struct delayed_work, it will corrupt +// flush_scheduled_work(); + rtl8192_cancel_deferred_work(priv); + deinit_hal_dm(dev); + del_timer_sync(&priv->watch_dog_timer); + + + ieee80211_softmac_stop_protocol(priv->ieee80211); + memset(&priv->ieee80211->current_network, 0 , offsetof(struct ieee80211_network, list)); + RT_TRACE(COMP_DOWN, "<==========%s()\n", __FUNCTION__); + + return 0; +} + + +void rtl8192_commit(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + int reset_status = 0; + //u8 reset_times = 0; + if (priv->up == 0) return ; + priv->up = 0; + + rtl8192_cancel_deferred_work(priv); + del_timer_sync(&priv->watch_dog_timer); + //cancel_delayed_work(&priv->SwChnlWorkItem); + + ieee80211_softmac_stop_protocol(priv->ieee80211); + + //rtl8192_irq_disable(dev); + rtl8192_rtx_disable(dev); + reset_status = _rtl8192_up(dev); + +} + +/* +void rtl8192_restart(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); +*/ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) +void rtl8192_restart(struct work_struct *work) +{ + struct r8192_priv *priv = container_of(work, struct r8192_priv, reset_wq); + struct net_device *dev = priv->ieee80211->dev; +#else +void rtl8192_restart(struct net_device *dev) +{ + + struct r8192_priv *priv = ieee80211_priv(dev); +#endif + + down(&priv->wx_sem); + + rtl8192_commit(dev); + + up(&priv->wx_sem); +} + +static void r8192_set_multicast(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + short promisc; + + //down(&priv->wx_sem); + + /* FIXME FIXME */ + + promisc = (dev->flags & IFF_PROMISC) ? 1:0; + + if (promisc != priv->promisc) + // rtl8192_commit(dev); + + priv->promisc = promisc; + + //schedule_work(&priv->reset_wq); + //up(&priv->wx_sem); +} + + +int r8192_set_mac_adr(struct net_device *dev, void *mac) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + struct sockaddr *addr = mac; + + down(&priv->wx_sem); + + memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) + schedule_work(&priv->reset_wq); +#else + schedule_task(&priv->reset_wq); +#endif + up(&priv->wx_sem); + + return 0; +} + +/* based on ipw2200 driver */ +int rtl8192_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); + struct iwreq *wrq = (struct iwreq *)rq; + int ret=-1; + struct ieee80211_device *ieee = priv->ieee80211; + u32 key[4]; + u8 broadcast_addr[6] = {0xff,0xff,0xff,0xff,0xff,0xff}; + u8 zero_addr[6] = {0}; + struct iw_point *p = &wrq->u.data; + struct ieee_param *ipw = NULL;//(struct ieee_param *)wrq->u.data.pointer; + + down(&priv->wx_sem); + + + if (p->length < sizeof(struct ieee_param) || !p->pointer){ + ret = -EINVAL; + goto out; + } + + ipw = (struct ieee_param *)kmalloc(p->length, GFP_KERNEL); + if (ipw == NULL){ + ret = -ENOMEM; + goto out; + } + if (copy_from_user(ipw, p->pointer, p->length)) { + kfree(ipw); + ret = -EFAULT; + goto out; + } + + switch (cmd) { + case RTL_IOCTL_WPA_SUPPLICANT: + //parse here for HW security + if (ipw->cmd == IEEE_CMD_SET_ENCRYPTION) + { + if (ipw->u.crypt.set_tx) + { + if (strcmp(ipw->u.crypt.alg, "CCMP") == 0) + ieee->pairwise_key_type = KEY_TYPE_CCMP; + else if (strcmp(ipw->u.crypt.alg, "TKIP") == 0) + ieee->pairwise_key_type = KEY_TYPE_TKIP; + else if (strcmp(ipw->u.crypt.alg, "WEP") == 0) + { + if (ipw->u.crypt.key_len == 13) + ieee->pairwise_key_type = KEY_TYPE_WEP104; + else if (ipw->u.crypt.key_len == 5) + ieee->pairwise_key_type = KEY_TYPE_WEP40; + } + else + ieee->pairwise_key_type = KEY_TYPE_NA; + + if (ieee->pairwise_key_type) + { + // FIXME:these two lines below just to fix ipw interface bug, that is, it will never set mode down to driver. So treat it as ADHOC mode, if no association procedure. WB. 2009.02.04 + if (memcmp(ieee->ap_mac_addr, zero_addr, 6) == 0) + ieee->iw_mode = IW_MODE_ADHOC; + memcpy((u8*)key, ipw->u.crypt.key, 16); + EnableHWSecurityConfig8192(dev); + //we fill both index entry and 4th entry for pairwise key as in IPW interface, adhoc will only get here, so we need index entry for its default key serching! + //added by WB. + setKey(dev, 4, ipw->u.crypt.idx, ieee->pairwise_key_type, (u8*)ieee->ap_mac_addr, 0, key); + if (ieee->iw_mode == IW_MODE_ADHOC) + setKey(dev, ipw->u.crypt.idx, ipw->u.crypt.idx, ieee->pairwise_key_type, (u8*)ieee->ap_mac_addr, 0, key); + } + } + else //if (ipw->u.crypt.idx) //group key use idx > 0 + { + memcpy((u8*)key, ipw->u.crypt.key, 16); + if (strcmp(ipw->u.crypt.alg, "CCMP") == 0) + ieee->group_key_type= KEY_TYPE_CCMP; + else if (strcmp(ipw->u.crypt.alg, "TKIP") == 0) + ieee->group_key_type = KEY_TYPE_TKIP; + else if (strcmp(ipw->u.crypt.alg, "WEP") == 0) + { + if (ipw->u.crypt.key_len == 13) + ieee->group_key_type = KEY_TYPE_WEP104; + else if (ipw->u.crypt.key_len == 5) + ieee->group_key_type = KEY_TYPE_WEP40; + } + else + ieee->group_key_type = KEY_TYPE_NA; + + if (ieee->group_key_type) + { + setKey( dev, + ipw->u.crypt.idx, + ipw->u.crypt.idx, //KeyIndex + ieee->group_key_type, //KeyType + broadcast_addr, //MacAddr + 0, //DefaultKey + key); //KeyContent + } + } + } +#ifdef JOHN_HWSEC_DEBUG + //john's test 0711 + printk("@@ wrq->u pointer = "); + for(i=0;iu.data.length;i++){ + if(i%10==0) printk("\n"); + printk( "%8x|", ((u32*)wrq->u.data.pointer)[i] ); + } + printk("\n"); +#endif /*JOHN_HWSEC_DEBUG*/ + ret = ieee80211_wpa_supplicant_ioctl(priv->ieee80211, &wrq->u.data); + break; + + default: + ret = -EOPNOTSUPP; + break; + } + kfree(ipw); + ipw = NULL; +out: + up(&priv->wx_sem); + return ret; +} + +#ifdef RTL8192SU +u8 rtl8192SU_HwRateToMRate(bool bIsHT, u8 rate,bool bFirstAMPDU) +{ + + u8 ret_rate = 0x02; + + if( bFirstAMPDU ) + { + if(!bIsHT) + { + switch(rate) + { + + case DESC92S_RATE1M: ret_rate = MGN_1M; break; + case DESC92S_RATE2M: ret_rate = MGN_2M; break; + case DESC92S_RATE5_5M: ret_rate = MGN_5_5M; break; + case DESC92S_RATE11M: ret_rate = MGN_11M; break; + case DESC92S_RATE6M: ret_rate = MGN_6M; break; + case DESC92S_RATE9M: ret_rate = MGN_9M; break; + case DESC92S_RATE12M: ret_rate = MGN_12M; break; + case DESC92S_RATE18M: ret_rate = MGN_18M; break; + case DESC92S_RATE24M: ret_rate = MGN_24M; break; + case DESC92S_RATE36M: ret_rate = MGN_36M; break; + case DESC92S_RATE48M: ret_rate = MGN_48M; break; + case DESC92S_RATE54M: ret_rate = MGN_54M; break; + + default: + RT_TRACE(COMP_RECV, "HwRateToMRate90(): Non supported Rate [%x], bIsHT = %d!!!\n", rate, bIsHT); + break; + } + } + else + { + switch(rate) + { + + case DESC92S_RATEMCS0: ret_rate = MGN_MCS0; break; + case DESC92S_RATEMCS1: ret_rate = MGN_MCS1; break; + case DESC92S_RATEMCS2: ret_rate = MGN_MCS2; break; + case DESC92S_RATEMCS3: ret_rate = MGN_MCS3; break; + case DESC92S_RATEMCS4: ret_rate = MGN_MCS4; break; + case DESC92S_RATEMCS5: ret_rate = MGN_MCS5; break; + case DESC92S_RATEMCS6: ret_rate = MGN_MCS6; break; + case DESC92S_RATEMCS7: ret_rate = MGN_MCS7; break; + case DESC92S_RATEMCS8: ret_rate = MGN_MCS8; break; + case DESC92S_RATEMCS9: ret_rate = MGN_MCS9; break; + case DESC92S_RATEMCS10: ret_rate = MGN_MCS10; break; + case DESC92S_RATEMCS11: ret_rate = MGN_MCS11; break; + case DESC92S_RATEMCS12: ret_rate = MGN_MCS12; break; + case DESC92S_RATEMCS13: ret_rate = MGN_MCS13; break; + case DESC92S_RATEMCS14: ret_rate = MGN_MCS14; break; + case DESC92S_RATEMCS15: ret_rate = MGN_MCS15; break; + case DESC92S_RATEMCS32: ret_rate = (0x80|0x20); break; + + default: + RT_TRACE(COMP_RECV, "HwRateToMRate92S(): Non supported Rate [%x], bIsHT = %d!!!\n",rate, bIsHT ); + break; + } + + } + } + else + { + switch(rate) + { + + case DESC92S_RATE1M: ret_rate = MGN_1M; break; + case DESC92S_RATE2M: ret_rate = MGN_2M; break; + case DESC92S_RATE5_5M: ret_rate = MGN_5_5M; break; + case DESC92S_RATE11M: ret_rate = MGN_11M; break; + case DESC92S_RATE6M: ret_rate = MGN_6M; break; + case DESC92S_RATE9M: ret_rate = MGN_9M; break; + case DESC92S_RATE12M: ret_rate = MGN_12M; break; + case DESC92S_RATE18M: ret_rate = MGN_18M; break; + case DESC92S_RATE24M: ret_rate = MGN_24M; break; + case DESC92S_RATE36M: ret_rate = MGN_36M; break; + case DESC92S_RATE48M: ret_rate = MGN_48M; break; + case DESC92S_RATE54M: ret_rate = MGN_54M; break; + case DESC92S_RATEMCS0: ret_rate = MGN_MCS0; break; + case DESC92S_RATEMCS1: ret_rate = MGN_MCS1; break; + case DESC92S_RATEMCS2: ret_rate = MGN_MCS2; break; + case DESC92S_RATEMCS3: ret_rate = MGN_MCS3; break; + case DESC92S_RATEMCS4: ret_rate = MGN_MCS4; break; + case DESC92S_RATEMCS5: ret_rate = MGN_MCS5; break; + case DESC92S_RATEMCS6: ret_rate = MGN_MCS6; break; + case DESC92S_RATEMCS7: ret_rate = MGN_MCS7; break; + case DESC92S_RATEMCS8: ret_rate = MGN_MCS8; break; + case DESC92S_RATEMCS9: ret_rate = MGN_MCS9; break; + case DESC92S_RATEMCS10: ret_rate = MGN_MCS10; break; + case DESC92S_RATEMCS11: ret_rate = MGN_MCS11; break; + case DESC92S_RATEMCS12: ret_rate = MGN_MCS12; break; + case DESC92S_RATEMCS13: ret_rate = MGN_MCS13; break; + case DESC92S_RATEMCS14: ret_rate = MGN_MCS14; break; + case DESC92S_RATEMCS15: ret_rate = MGN_MCS15; break; + case DESC92S_RATEMCS32: ret_rate = (0x80|0x20); break; + + default: + RT_TRACE(COMP_RECV, "HwRateToMRate92S(): Non supported Rate [%x], bIsHT = %d!!!\n",rate, bIsHT ); + break; + } + } + return ret_rate; +} +#endif + +u8 HwRateToMRate90(bool bIsHT, u8 rate) +{ + u8 ret_rate = 0xff; + + if(!bIsHT) { + switch(rate) { + case DESC90_RATE1M: ret_rate = MGN_1M; break; + case DESC90_RATE2M: ret_rate = MGN_2M; break; + case DESC90_RATE5_5M: ret_rate = MGN_5_5M; break; + case DESC90_RATE11M: ret_rate = MGN_11M; break; + case DESC90_RATE6M: ret_rate = MGN_6M; break; + case DESC90_RATE9M: ret_rate = MGN_9M; break; + case DESC90_RATE12M: ret_rate = MGN_12M; break; + case DESC90_RATE18M: ret_rate = MGN_18M; break; + case DESC90_RATE24M: ret_rate = MGN_24M; break; + case DESC90_RATE36M: ret_rate = MGN_36M; break; + case DESC90_RATE48M: ret_rate = MGN_48M; break; + case DESC90_RATE54M: ret_rate = MGN_54M; break; + + default: + ret_rate = 0xff; + RT_TRACE(COMP_RECV, "HwRateToMRate90(): Non supported Rate [%x], bIsHT = %d!!!\n", rate, bIsHT); + break; + } + + } else { + switch(rate) { + case DESC90_RATEMCS0: ret_rate = MGN_MCS0; break; + case DESC90_RATEMCS1: ret_rate = MGN_MCS1; break; + case DESC90_RATEMCS2: ret_rate = MGN_MCS2; break; + case DESC90_RATEMCS3: ret_rate = MGN_MCS3; break; + case DESC90_RATEMCS4: ret_rate = MGN_MCS4; break; + case DESC90_RATEMCS5: ret_rate = MGN_MCS5; break; + case DESC90_RATEMCS6: ret_rate = MGN_MCS6; break; + case DESC90_RATEMCS7: ret_rate = MGN_MCS7; break; + case DESC90_RATEMCS8: ret_rate = MGN_MCS8; break; + case DESC90_RATEMCS9: ret_rate = MGN_MCS9; break; + case DESC90_RATEMCS10: ret_rate = MGN_MCS10; break; + case DESC90_RATEMCS11: ret_rate = MGN_MCS11; break; + case DESC90_RATEMCS12: ret_rate = MGN_MCS12; break; + case DESC90_RATEMCS13: ret_rate = MGN_MCS13; break; + case DESC90_RATEMCS14: ret_rate = MGN_MCS14; break; + case DESC90_RATEMCS15: ret_rate = MGN_MCS15; break; + case DESC90_RATEMCS32: ret_rate = (0x80|0x20); break; + + default: + ret_rate = 0xff; + RT_TRACE(COMP_RECV, "HwRateToMRate90(): Non supported Rate [%x], bIsHT = %d!!!\n",rate, bIsHT); + break; + } + } + + return ret_rate; +} + +/** + * Function: UpdateRxPktTimeStamp + * Overview: Recored down the TSF time stamp when receiving a packet + * + * Input: + * PADAPTER Adapter + * PRT_RFD pRfd, + * + * Output: + * PRT_RFD pRfd + * (pRfd->Status.TimeStampHigh is updated) + * (pRfd->Status.TimeStampLow is updated) + * Return: + * None + */ +void UpdateRxPktTimeStamp8190 (struct net_device *dev, struct ieee80211_rx_stats *stats) +{ + struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); + + if(stats->bIsAMPDU && !stats->bFirstMPDU) { + stats->mac_time[0] = priv->LastRxDescTSFLow; + stats->mac_time[1] = priv->LastRxDescTSFHigh; + } else { + priv->LastRxDescTSFLow = stats->mac_time[0]; + priv->LastRxDescTSFHigh = stats->mac_time[1]; + } +} + +//by amy 080606 + +long rtl819x_translate_todbm(u8 signal_strength_index )// 0-100 index. +{ + long signal_power; // in dBm. + + // Translate to dBm (x=0.5y-95). + signal_power = (long)((signal_strength_index + 1) >> 1); + signal_power -= 95; + + return signal_power; +} + + +/* 2008/01/22 MH We can not delcare RSSI/EVM total value of sliding window to + be a local static. Otherwise, it may increase when we return from S3/S4. The + value will be kept in memory or disk. We must delcare the value in adapter + and it will be reinitialized when return from S3/S4. */ +void rtl8192_process_phyinfo(struct r8192_priv * priv,u8* buffer, struct ieee80211_rx_stats * pprevious_stats, struct ieee80211_rx_stats * pcurrent_stats) +{ + bool bcheck = false; + u8 rfpath; + u32 nspatial_stream, tmp_val; + //u8 i; + static u32 slide_rssi_index=0, slide_rssi_statistics=0; + static u32 slide_evm_index=0, slide_evm_statistics=0; + static u32 last_rssi=0, last_evm=0; + + static u32 slide_beacon_adc_pwdb_index=0, slide_beacon_adc_pwdb_statistics=0; + static u32 last_beacon_adc_pwdb=0; + + struct ieee80211_hdr_3addr *hdr; + u16 sc ; + unsigned int frag,seq; + hdr = (struct ieee80211_hdr_3addr *)buffer; + sc = le16_to_cpu(hdr->seq_ctl); + frag = WLAN_GET_SEQ_FRAG(sc); + seq = WLAN_GET_SEQ_SEQ(sc); + //cosa add 04292008 to record the sequence number + pcurrent_stats->Seq_Num = seq; + // + // Check whether we should take the previous packet into accounting + // + if(!pprevious_stats->bIsAMPDU) + { + // if previous packet is not aggregated packet + bcheck = true; + }else + { + #if 0 + // if previous packet is aggregated packet, and current packet + // (1) is not AMPDU + // (2) is the first packet of one AMPDU + // that means the previous packet is the last one aggregated packet + if( !pcurrent_stats->bIsAMPDU || pcurrent_stats->bFirstMPDU) + bcheck = true; + #endif + } + + + if(slide_rssi_statistics++ >= PHY_RSSI_SLID_WIN_MAX) + { + slide_rssi_statistics = PHY_RSSI_SLID_WIN_MAX; + last_rssi = priv->stats.slide_signal_strength[slide_rssi_index]; + priv->stats.slide_rssi_total -= last_rssi; + } + priv->stats.slide_rssi_total += pprevious_stats->SignalStrength; + + priv->stats.slide_signal_strength[slide_rssi_index++] = pprevious_stats->SignalStrength; + if(slide_rssi_index >= PHY_RSSI_SLID_WIN_MAX) + slide_rssi_index = 0; + + // <1> Showed on UI for user, in dbm + tmp_val = priv->stats.slide_rssi_total/slide_rssi_statistics; + priv->stats.signal_strength = rtl819x_translate_todbm((u8)tmp_val); + pcurrent_stats->rssi = priv->stats.signal_strength; + // + // If the previous packet does not match the criteria, neglect it + // + if(!pprevious_stats->bPacketMatchBSSID) + { + if(!pprevious_stats->bToSelfBA) + return; + } + + if(!bcheck) + return; + + + //rtl8190_process_cck_rxpathsel(priv,pprevious_stats);//only rtl8190 supported + + // + // Check RSSI + // + priv->stats.num_process_phyinfo++; + + /* record the general signal strength to the sliding window. */ + + + // <2> Showed on UI for engineering + // hardware does not provide rssi information for each rf path in CCK + if(!pprevious_stats->bIsCCK && (pprevious_stats->bPacketToSelf || pprevious_stats->bToSelfBA)) + { + for (rfpath = RF90_PATH_A; rfpath < priv->NumTotalRFPath; rfpath++) + { + if (!rtl8192_phy_CheckIsLegalRFPath(priv->ieee80211->dev, rfpath)) + continue; + + //Fixed by Jacken 2008-03-20 + if(priv->stats.rx_rssi_percentage[rfpath] == 0) + { + priv->stats.rx_rssi_percentage[rfpath] = pprevious_stats->RxMIMOSignalStrength[rfpath]; + //DbgPrint("MIMO RSSI initialize \n"); + } + if(pprevious_stats->RxMIMOSignalStrength[rfpath] > priv->stats.rx_rssi_percentage[rfpath]) + { + priv->stats.rx_rssi_percentage[rfpath] = + ( (priv->stats.rx_rssi_percentage[rfpath]*(Rx_Smooth_Factor-1)) + + (pprevious_stats->RxMIMOSignalStrength[rfpath])) /(Rx_Smooth_Factor); + priv->stats.rx_rssi_percentage[rfpath] = priv->stats.rx_rssi_percentage[rfpath] + 1; + } + else + { + priv->stats.rx_rssi_percentage[rfpath] = + ( (priv->stats.rx_rssi_percentage[rfpath]*(Rx_Smooth_Factor-1)) + + (pprevious_stats->RxMIMOSignalStrength[rfpath])) /(Rx_Smooth_Factor); + } + RT_TRACE(COMP_DBG,"priv->stats.rx_rssi_percentage[rfPath] = %d \n" ,priv->stats.rx_rssi_percentage[rfpath] ); + } + } + + + // + // Check PWDB. + // + RT_TRACE(COMP_RXDESC, "Smooth %s PWDB = %d\n", + pprevious_stats->bIsCCK? "CCK": "OFDM", + pprevious_stats->RxPWDBAll); + + if(pprevious_stats->bPacketBeacon) + { +/* record the beacon pwdb to the sliding window. */ + if(slide_beacon_adc_pwdb_statistics++ >= PHY_Beacon_RSSI_SLID_WIN_MAX) + { + slide_beacon_adc_pwdb_statistics = PHY_Beacon_RSSI_SLID_WIN_MAX; + last_beacon_adc_pwdb = priv->stats.Slide_Beacon_pwdb[slide_beacon_adc_pwdb_index]; + priv->stats.Slide_Beacon_Total -= last_beacon_adc_pwdb; + //DbgPrint("slide_beacon_adc_pwdb_index = %d, last_beacon_adc_pwdb = %d, Adapter->RxStats.Slide_Beacon_Total = %d\n", + // slide_beacon_adc_pwdb_index, last_beacon_adc_pwdb, Adapter->RxStats.Slide_Beacon_Total); + } + priv->stats.Slide_Beacon_Total += pprevious_stats->RxPWDBAll; + priv->stats.Slide_Beacon_pwdb[slide_beacon_adc_pwdb_index] = pprevious_stats->RxPWDBAll; + //DbgPrint("slide_beacon_adc_pwdb_index = %d, pPreviousRfd->Status.RxPWDBAll = %d\n", slide_beacon_adc_pwdb_index, pPreviousRfd->Status.RxPWDBAll); + slide_beacon_adc_pwdb_index++; + if(slide_beacon_adc_pwdb_index >= PHY_Beacon_RSSI_SLID_WIN_MAX) + slide_beacon_adc_pwdb_index = 0; + pprevious_stats->RxPWDBAll = priv->stats.Slide_Beacon_Total/slide_beacon_adc_pwdb_statistics; + if(pprevious_stats->RxPWDBAll >= 3) + pprevious_stats->RxPWDBAll -= 3; + } + + RT_TRACE(COMP_RXDESC, "Smooth %s PWDB = %d\n", + pprevious_stats->bIsCCK? "CCK": "OFDM", + pprevious_stats->RxPWDBAll); + + + if(pprevious_stats->bPacketToSelf || pprevious_stats->bPacketBeacon || pprevious_stats->bToSelfBA) + { + if(priv->undecorated_smoothed_pwdb < 0) // initialize + { + priv->undecorated_smoothed_pwdb = pprevious_stats->RxPWDBAll; + //DbgPrint("First pwdb initialize \n"); + } +#if 1 + if(pprevious_stats->RxPWDBAll > (u32)priv->undecorated_smoothed_pwdb) + { + priv->undecorated_smoothed_pwdb = + ( ((priv->undecorated_smoothed_pwdb)*(Rx_Smooth_Factor-1)) + + (pprevious_stats->RxPWDBAll)) /(Rx_Smooth_Factor); + priv->undecorated_smoothed_pwdb = priv->undecorated_smoothed_pwdb + 1; + } + else + { + priv->undecorated_smoothed_pwdb = + ( ((priv->undecorated_smoothed_pwdb)*(Rx_Smooth_Factor-1)) + + (pprevious_stats->RxPWDBAll)) /(Rx_Smooth_Factor); + } +#else + //Fixed by Jacken 2008-03-20 + if(pPreviousRfd->Status.RxPWDBAll > (u32)pHalData->UndecoratedSmoothedPWDB) + { + pHalData->UndecoratedSmoothedPWDB = + ( ((pHalData->UndecoratedSmoothedPWDB)* 5) + (pPreviousRfd->Status.RxPWDBAll)) / 6; + pHalData->UndecoratedSmoothedPWDB = pHalData->UndecoratedSmoothedPWDB + 1; + } + else + { + pHalData->UndecoratedSmoothedPWDB = + ( ((pHalData->UndecoratedSmoothedPWDB)* 5) + (pPreviousRfd->Status.RxPWDBAll)) / 6; + } +#endif + + } + + // + // Check EVM + // + /* record the general EVM to the sliding window. */ + if(pprevious_stats->SignalQuality == 0) + { + } + else + { + if(pprevious_stats->bPacketToSelf || pprevious_stats->bPacketBeacon || pprevious_stats->bToSelfBA){ + if(slide_evm_statistics++ >= PHY_RSSI_SLID_WIN_MAX){ + slide_evm_statistics = PHY_RSSI_SLID_WIN_MAX; + last_evm = priv->stats.slide_evm[slide_evm_index]; + priv->stats.slide_evm_total -= last_evm; + } + + priv->stats.slide_evm_total += pprevious_stats->SignalQuality; + + priv->stats.slide_evm[slide_evm_index++] = pprevious_stats->SignalQuality; + if(slide_evm_index >= PHY_RSSI_SLID_WIN_MAX) + slide_evm_index = 0; + + // <1> Showed on UI for user, in percentage. + tmp_val = priv->stats.slide_evm_total/slide_evm_statistics; + priv->stats.signal_quality = tmp_val; + //cosa add 10/11/2007, Showed on UI for user in Windows Vista, for Link quality. + priv->stats.last_signal_strength_inpercent = tmp_val; + } + + // <2> Showed on UI for engineering + if(pprevious_stats->bPacketToSelf || pprevious_stats->bPacketBeacon || pprevious_stats->bToSelfBA) + { + for(nspatial_stream = 0; nspatial_stream<2 ; nspatial_stream++) // 2 spatial stream + { + if(pprevious_stats->RxMIMOSignalQuality[nspatial_stream] != -1) + { + if(priv->stats.rx_evm_percentage[nspatial_stream] == 0) // initialize + { + priv->stats.rx_evm_percentage[nspatial_stream] = pprevious_stats->RxMIMOSignalQuality[nspatial_stream]; + } + priv->stats.rx_evm_percentage[nspatial_stream] = + ( (priv->stats.rx_evm_percentage[nspatial_stream]* (Rx_Smooth_Factor-1)) + + (pprevious_stats->RxMIMOSignalQuality[nspatial_stream]* 1)) / (Rx_Smooth_Factor); + } + } + } + } + + +} + +/*----------------------------------------------------------------------------- + * Function: rtl819x_query_rxpwrpercentage() + * + * Overview: + * + * Input: char antpower + * + * Output: NONE + * + * Return: 0-100 percentage + * + * Revised History: + * When Who Remark + * 05/26/2008 amy Create Version 0 porting from windows code. + * + *---------------------------------------------------------------------------*/ +static u8 rtl819x_query_rxpwrpercentage( + char antpower + ) +{ + if ((antpower <= -100) || (antpower >= 20)) + { + return 0; + } + else if (antpower >= 0) + { + return 100; + } + else + { + return (100+antpower); + } + +} /* QueryRxPwrPercentage */ + +static u8 +rtl819x_evm_dbtopercentage( + char value + ) +{ + char ret_val; + + ret_val = value; + + if(ret_val >= 0) + ret_val = 0; + if(ret_val <= -33) + ret_val = -33; + ret_val = 0 - ret_val; + ret_val*=3; + if(ret_val == 99) + ret_val = 100; + return(ret_val); +} +// +// Description: +// We want good-looking for signal strength/quality +// 2007/7/19 01:09, by cosa. +// +long +rtl819x_signal_scale_mapping( + long currsig + ) +{ + long retsig; + + // Step 1. Scale mapping. + if(currsig >= 61 && currsig <= 100) + { + retsig = 90 + ((currsig - 60) / 4); + } + else if(currsig >= 41 && currsig <= 60) + { + retsig = 78 + ((currsig - 40) / 2); + } + else if(currsig >= 31 && currsig <= 40) + { + retsig = 66 + (currsig - 30); + } + else if(currsig >= 21 && currsig <= 30) + { + retsig = 54 + (currsig - 20); + } + else if(currsig >= 5 && currsig <= 20) + { + retsig = 42 + (((currsig - 5) * 2) / 3); + } + else if(currsig == 4) + { + retsig = 36; + } + else if(currsig == 3) + { + retsig = 27; + } + else if(currsig == 2) + { + retsig = 18; + } + else if(currsig == 1) + { + retsig = 9; + } + else + { + retsig = currsig; + } + + return retsig; +} + +#ifdef RTL8192SU +/*----------------------------------------------------------------------------- + * Function: QueryRxPhyStatus8192S() + * + * Overview: + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 06/01/2007 MHC Create Version 0. + * 06/05/2007 MHC Accordign to HW's new data sheet, we add CCK and OFDM + * descriptor definition. + * 07/04/2007 MHC According to Jerry and Bryant's document. We read + * ir_isolation and ext_lna for RF's init value and use + * to compensate RSSI after receiving packets. + * 09/10/2008 MHC Modify name and PHY status field for 92SE. + * 09/19/2008 MHC Add CCK/OFDM SS/SQ for 92S series. + * + *---------------------------------------------------------------------------*/ +static void rtl8192SU_query_rxphystatus( + struct r8192_priv * priv, + struct ieee80211_rx_stats * pstats, + rx_desc_819x_usb *pDesc, + rx_drvinfo_819x_usb * pdrvinfo, + struct ieee80211_rx_stats * precord_stats, + bool bpacket_match_bssid, + bool bpacket_toself, + bool bPacketBeacon, + bool bToSelfBA + ) +{ + //PRT_RFD_STATUS pRtRfdStatus = &(pRfd->Status); + //PHY_STS_CCK_8192S_T *pCck_buf; + phy_sts_cck_819xusb_t * pcck_buf; + phy_ofdm_rx_status_rxsc_sgien_exintfflag* prxsc; + //u8 *prxpkt; + //u8 i, max_spatial_stream, tmp_rxsnr, tmp_rxevm, rxsc_sgien_exflg; + u8 i, max_spatial_stream, rxsc_sgien_exflg; + char rx_pwr[4], rx_pwr_all=0; + //long rx_avg_pwr = 0; + //char rx_snrX, rx_evmX; + u8 evm, pwdb_all; + u32 RSSI, total_rssi=0;//, total_evm=0; +// long signal_strength_index = 0; + u8 is_cck_rate=0; + u8 rf_rx_num = 0; + + + + priv->stats.numqry_phystatus++; + + is_cck_rate = rx_hal_is_cck_rate(pDesc); + + // Record it for next packet processing + memset(precord_stats, 0, sizeof(struct ieee80211_rx_stats)); + pstats->bPacketMatchBSSID = precord_stats->bPacketMatchBSSID = bpacket_match_bssid; + pstats->bPacketToSelf = precord_stats->bPacketToSelf = bpacket_toself; + pstats->bIsCCK = precord_stats->bIsCCK = is_cck_rate;//RX_HAL_IS_CCK_RATE(pDrvInfo); + pstats->bPacketBeacon = precord_stats->bPacketBeacon = bPacketBeacon; + pstats->bToSelfBA = precord_stats->bToSelfBA = bToSelfBA; + +#ifndef RTL8192SU + phy_sts_ofdm_819xusb_t* pofdm_buf = NULL; + prxpkt = (u8*)pdrvinfo; + + /* Move pointer to the 16th bytes. Phy status start address. */ + prxpkt += sizeof(rx_drvinfo_819x_usb); + + /* Initial the cck and ofdm buffer pointer */ + pcck_buf = (phy_sts_cck_819xusb_t *)prxpkt; + pofdm_buf = (phy_sts_ofdm_819xusb_t *)prxpkt; +#endif + + pstats->RxMIMOSignalQuality[0] = -1; + pstats->RxMIMOSignalQuality[1] = -1; + precord_stats->RxMIMOSignalQuality[0] = -1; + precord_stats->RxMIMOSignalQuality[1] = -1; + + if(is_cck_rate) + { + u8 report;//, tmp_pwdb; + //char cck_adc_pwdb[4]; + + // CCK Driver info Structure is not the same as OFDM packet. + pcck_buf = (phy_sts_cck_819xusb_t *)pdrvinfo; + + // + // (1)Hardware does not provide RSSI for CCK + // + + // + // (2)PWDB, Average PWDB cacluated by hardware (for rate adaptive) + // + + priv->stats.numqry_phystatusCCK++; + + if(!priv->bCckHighPower) + { + report = pcck_buf->cck_agc_rpt & 0xc0; + report = report>>6; + switch(report) + { + //Fixed by Jacken from Bryant 2008-03-20 + //Original value is -38 , -26 , -14 , -2 + //Fixed value is -35 , -23 , -11 , 6 + case 0x3: + rx_pwr_all = -35 - (pcck_buf->cck_agc_rpt & 0x3e); + break; + case 0x2: + rx_pwr_all = -23 - (pcck_buf->cck_agc_rpt & 0x3e); + break; + case 0x1: + rx_pwr_all = -11 - (pcck_buf->cck_agc_rpt & 0x3e); + break; + case 0x0: + rx_pwr_all = 8 - (pcck_buf->cck_agc_rpt & 0x3e);//6->8 + break; + } + } + else + { + report = pdrvinfo->cfosho[0] & 0x60; + report = report>>5; + switch(report) + { + case 0x3: + rx_pwr_all = -35 - ((pcck_buf->cck_agc_rpt & 0x1f)<<1) ; + break; + case 0x2: + rx_pwr_all = -23 - ((pcck_buf->cck_agc_rpt & 0x1f)<<1); + break; + case 0x1: + rx_pwr_all = -11 - ((pcck_buf->cck_agc_rpt & 0x1f)<<1) ; + break; + case 0x0: + rx_pwr_all = -8 - ((pcck_buf->cck_agc_rpt & 0x1f)<<1) ;//6->-8 + break; + } + } + + pwdb_all = rtl819x_query_rxpwrpercentage(rx_pwr_all);//check it + pstats->RxPWDBAll = precord_stats->RxPWDBAll = pwdb_all; + //pstats->RecvSignalPower = pwdb_all; + pstats->RecvSignalPower = rx_pwr_all; + + // + // (3) Get Signal Quality (EVM) + // + //if(bpacket_match_bssid) + { + u8 sq; + + if(pstats->RxPWDBAll > 40) + { + sq = 100; + }else + { + sq = pcck_buf->sq_rpt; + + if(pcck_buf->sq_rpt > 64) + sq = 0; + else if (pcck_buf->sq_rpt < 20) + sq = 100; + else + sq = ((64-sq) * 100) / 44; + } + pstats->SignalQuality = precord_stats->SignalQuality = sq; + pstats->RxMIMOSignalQuality[0] = precord_stats->RxMIMOSignalQuality[0] = sq; + pstats->RxMIMOSignalQuality[1] = precord_stats->RxMIMOSignalQuality[1] = -1; + } + } + else + { + priv->stats.numqry_phystatusHT++; + + // 2008/09/19 MH For 92S debug, RX RF path always enable!! + priv->brfpath_rxenable[0] = priv->brfpath_rxenable[1] = TRUE; + + // + // (1)Get RSSI for HT rate + // + //for(i=RF90_PATH_A; iNumTotalRFPath; i++) + for(i=RF90_PATH_A; ibrfpath_rxenable[i]) + rf_rx_num++; + //else + // continue; + + //if (!rtl8192_phy_CheckIsLegalRFPath(priv->ieee80211->dev, i)) + // continue; + + //Fixed by Jacken from Bryant 2008-03-20 + //Original value is 106 + //rx_pwr[i] = ((pofdm_buf->trsw_gain_X[i]&0x3F)*2) - 106; + rx_pwr[i] = ((pdrvinfo->gain_trsw[i]&0x3F)*2) - 110; + + /* Translate DBM to percentage. */ + RSSI = rtl819x_query_rxpwrpercentage(rx_pwr[i]); //check ok + total_rssi += RSSI; + RT_TRACE(COMP_RF, "RF-%d RXPWR=%x RSSI=%d\n", i, rx_pwr[i], RSSI); + + //Get Rx snr value in DB + //tmp_rxsnr = pofdm_buf->rxsnr_X[i]; + //rx_snrX = (char)(tmp_rxsnr); + //rx_snrX /= 2; + //priv->stats.rxSNRdB[i] = (long)rx_snrX; + priv->stats.rxSNRdB[i] = (long)(pdrvinfo->rxsnr[i]/2); + + /* Translate DBM to percentage. */ + //RSSI = rtl819x_query_rxpwrpercentage(rx_pwr[i]); + //total_rssi += RSSI; + + /* Record Signal Strength for next packet */ + //if(bpacket_match_bssid) + { + pstats->RxMIMOSignalStrength[i] =(u8) RSSI; + precord_stats->RxMIMOSignalStrength[i] =(u8) RSSI; + } + } + + + // + // (2)PWDB, Average PWDB cacluated by hardware (for rate adaptive) + // + //Fixed by Jacken from Bryant 2008-03-20 + //Original value is 106 + //rx_pwr_all = (((pofdm_buf->pwdb_all ) >> 1 )& 0x7f) -106; + rx_pwr_all = (((pdrvinfo->pwdb_all ) >> 1 )& 0x7f) -106; + pwdb_all = rtl819x_query_rxpwrpercentage(rx_pwr_all); + + pstats->RxPWDBAll = precord_stats->RxPWDBAll = pwdb_all; + pstats->RxPower = precord_stats->RxPower = rx_pwr_all; + pstats->RecvSignalPower = rx_pwr_all; + + // + // (3)EVM of HT rate + // + //if(pdrvinfo->RxHT && pdrvinfo->RxRate>=DESC90_RATEMCS8 && + // pdrvinfo->RxRate<=DESC90_RATEMCS15) + if(pDesc->RxHT && pDesc->RxMCS>=DESC92S_RATEMCS8 && + pDesc->RxMCS<=DESC92S_RATEMCS15) + max_spatial_stream = 2; //both spatial stream make sense + else + max_spatial_stream = 1; //only spatial stream 1 makes sense + + for(i=0; irxevm_X[i]; + //rx_evmX = (char)(tmp_rxevm); + + // Do not use shift operation like "rx_evmX >>= 1" because the compilor of free build environment + // fill most significant bit to "zero" when doing shifting operation which may change a negative + // value to positive one, then the dbm value (which is supposed to be negative) is not correct anymore. + //rx_evmX /= 2; //dbm + + //evm = rtl819x_evm_dbtopercentage(rx_evmX); + evm = rtl819x_evm_dbtopercentage( (pdrvinfo->rxevm[i] /*/ 2*/)); //dbm + RT_TRACE(COMP_RF, "RXRATE=%x RXEVM=%x EVM=%s%d\n", pDesc->RxMCS, pdrvinfo->rxevm[i], "%", evm); +#if 0 + EVM = SignalScaleMapping(EVM);//make it good looking, from 0~100//=====>from here +#endif + + //if(bpacket_match_bssid) + { + if(i==0) // Fill value in RFD, Get the first spatial stream only + pstats->SignalQuality = precord_stats->SignalQuality = (u8)(evm & 0xff); + pstats->RxMIMOSignalQuality[i] = precord_stats->RxMIMOSignalQuality[i] = (u8)(evm & 0xff); + } + } + + + /* record rx statistics for debug */ + //rxsc_sgien_exflg = pofdm_buf->rxsc_sgien_exflg; + prxsc = (phy_ofdm_rx_status_rxsc_sgien_exintfflag *)&rxsc_sgien_exflg; + //if(pdrvinfo->BW) //40M channel + if(pDesc->BW) //40M channel + priv->stats.received_bwtype[1+pdrvinfo->rxsc]++; + else //20M channel + priv->stats.received_bwtype[0]++; + } + + //UI BSS List signal strength(in percentage), make it good looking, from 0~100. + //It is assigned to the BSS List in GetValueFromBeaconOrProbeRsp(). + if(is_cck_rate) + { + pstats->SignalStrength = precord_stats->SignalStrength = (u8)(rtl819x_signal_scale_mapping((long)pwdb_all));//PWDB_ALL;//check ok + + } + else + { + //pRfd->Status.SignalStrength = pRecordRfd->Status.SignalStrength = (u8)(SignalScaleMapping(total_rssi/=RF90_PATH_MAX));//(u8)(total_rssi/=RF90_PATH_MAX); + // We can judge RX path number now. + if (rf_rx_num != 0) + pstats->SignalStrength = precord_stats->SignalStrength = (u8)(rtl819x_signal_scale_mapping((long)(total_rssi/=rf_rx_num))); + } +}/* QueryRxPhyStatus8192S */ +#else +static void rtl8192_query_rxphystatus( + struct r8192_priv * priv, + struct ieee80211_rx_stats * pstats, + rx_drvinfo_819x_usb * pdrvinfo, + struct ieee80211_rx_stats * precord_stats, + bool bpacket_match_bssid, + bool bpacket_toself, + bool bPacketBeacon, + bool bToSelfBA + ) +{ + //PRT_RFD_STATUS pRtRfdStatus = &(pRfd->Status); + phy_sts_ofdm_819xusb_t* pofdm_buf; + phy_sts_cck_819xusb_t * pcck_buf; + phy_ofdm_rx_status_rxsc_sgien_exintfflag* prxsc; + u8 *prxpkt; + u8 i, max_spatial_stream, tmp_rxsnr, tmp_rxevm, rxsc_sgien_exflg; + char rx_pwr[4], rx_pwr_all=0; + //long rx_avg_pwr = 0; + char rx_snrX, rx_evmX; + u8 evm, pwdb_all; + u32 RSSI, total_rssi=0;//, total_evm=0; +// long signal_strength_index = 0; + u8 is_cck_rate=0; + u8 rf_rx_num = 0; + + + priv->stats.numqry_phystatus++; + + is_cck_rate = rx_hal_is_cck_rate(pdrvinfo); + + // Record it for next packet processing + memset(precord_stats, 0, sizeof(struct ieee80211_rx_stats)); + pstats->bPacketMatchBSSID = precord_stats->bPacketMatchBSSID = bpacket_match_bssid; + pstats->bPacketToSelf = precord_stats->bPacketToSelf = bpacket_toself; + pstats->bIsCCK = precord_stats->bIsCCK = is_cck_rate;//RX_HAL_IS_CCK_RATE(pDrvInfo); + pstats->bPacketBeacon = precord_stats->bPacketBeacon = bPacketBeacon; + pstats->bToSelfBA = precord_stats->bToSelfBA = bToSelfBA; + + prxpkt = (u8*)pdrvinfo; + + /* Move pointer to the 16th bytes. Phy status start address. */ + prxpkt += sizeof(rx_drvinfo_819x_usb); + + /* Initial the cck and ofdm buffer pointer */ + pcck_buf = (phy_sts_cck_819xusb_t *)prxpkt; + pofdm_buf = (phy_sts_ofdm_819xusb_t *)prxpkt; + + pstats->RxMIMOSignalQuality[0] = -1; + pstats->RxMIMOSignalQuality[1] = -1; + precord_stats->RxMIMOSignalQuality[0] = -1; + precord_stats->RxMIMOSignalQuality[1] = -1; + + if(is_cck_rate) + { + // + // (1)Hardware does not provide RSSI for CCK + // + + // + // (2)PWDB, Average PWDB cacluated by hardware (for rate adaptive) + // + u8 report;//, cck_agc_rpt; + + priv->stats.numqry_phystatusCCK++; + + if(!priv->bCckHighPower) + { + report = pcck_buf->cck_agc_rpt & 0xc0; + report = report>>6; + switch(report) + { + //Fixed by Jacken from Bryant 2008-03-20 + //Original value is -38 , -26 , -14 , -2 + //Fixed value is -35 , -23 , -11 , 6 + case 0x3: + rx_pwr_all = -35 - (pcck_buf->cck_agc_rpt & 0x3e); + break; + case 0x2: + rx_pwr_all = -23 - (pcck_buf->cck_agc_rpt & 0x3e); + break; + case 0x1: + rx_pwr_all = -11 - (pcck_buf->cck_agc_rpt & 0x3e); + break; + case 0x0: + rx_pwr_all = 6 - (pcck_buf->cck_agc_rpt & 0x3e); + break; + } + } + else + { + report = pcck_buf->cck_agc_rpt & 0x60; + report = report>>5; + switch(report) + { + case 0x3: + rx_pwr_all = -35 - ((pcck_buf->cck_agc_rpt & 0x1f)<<1) ; + break; + case 0x2: + rx_pwr_all = -23 - ((pcck_buf->cck_agc_rpt & 0x1f)<<1); + break; + case 0x1: + rx_pwr_all = -11 - ((pcck_buf->cck_agc_rpt & 0x1f)<<1) ; + break; + case 0x0: + rx_pwr_all = 6 - ((pcck_buf->cck_agc_rpt & 0x1f)<<1) ; + break; + } + } + + pwdb_all = rtl819x_query_rxpwrpercentage(rx_pwr_all); + pstats->RxPWDBAll = precord_stats->RxPWDBAll = pwdb_all; + pstats->RecvSignalPower = pwdb_all; + + // + // (3) Get Signal Quality (EVM) + // + //if(bpacket_match_bssid) + { + u8 sq; + + if(pstats->RxPWDBAll > 40) + { + sq = 100; + }else + { + sq = pcck_buf->sq_rpt; + + if(pcck_buf->sq_rpt > 64) + sq = 0; + else if (pcck_buf->sq_rpt < 20) + sq = 100; + else + sq = ((64-sq) * 100) / 44; + } + pstats->SignalQuality = precord_stats->SignalQuality = sq; + pstats->RxMIMOSignalQuality[0] = precord_stats->RxMIMOSignalQuality[0] = sq; + pstats->RxMIMOSignalQuality[1] = precord_stats->RxMIMOSignalQuality[1] = -1; + } + } + else + { + priv->stats.numqry_phystatusHT++; + // + // (1)Get RSSI for HT rate + // + for(i=RF90_PATH_A; iNumTotalRFPath; i++) + { + // 2008/01/30 MH we will judge RF RX path now. + if (priv->brfpath_rxenable[i]) + rf_rx_num++; + else + continue; + + if (!rtl8192_phy_CheckIsLegalRFPath(priv->ieee80211->dev, i)) + continue; + + //Fixed by Jacken from Bryant 2008-03-20 + //Original value is 106 + rx_pwr[i] = ((pofdm_buf->trsw_gain_X[i]&0x3F)*2) - 106; + + //Get Rx snr value in DB + tmp_rxsnr = pofdm_buf->rxsnr_X[i]; + rx_snrX = (char)(tmp_rxsnr); + //rx_snrX >>= 1;; + rx_snrX /= 2; + priv->stats.rxSNRdB[i] = (long)rx_snrX; + + /* Translate DBM to percentage. */ + RSSI = rtl819x_query_rxpwrpercentage(rx_pwr[i]); + total_rssi += RSSI; + + /* Record Signal Strength for next packet */ + //if(bpacket_match_bssid) + { + pstats->RxMIMOSignalStrength[i] =(u8) RSSI; + precord_stats->RxMIMOSignalStrength[i] =(u8) RSSI; + } + } + + + // + // (2)PWDB, Average PWDB cacluated by hardware (for rate adaptive) + // + //Fixed by Jacken from Bryant 2008-03-20 + //Original value is 106 + rx_pwr_all = (((pofdm_buf->pwdb_all ) >> 1 )& 0x7f) -106; + pwdb_all = rtl819x_query_rxpwrpercentage(rx_pwr_all); + + pstats->RxPWDBAll = precord_stats->RxPWDBAll = pwdb_all; + pstats->RxPower = precord_stats->RxPower = rx_pwr_all; + + // + // (3)EVM of HT rate + // + if(pdrvinfo->RxHT && pdrvinfo->RxRate>=DESC90_RATEMCS8 && + pdrvinfo->RxRate<=DESC90_RATEMCS15) + max_spatial_stream = 2; //both spatial stream make sense + else + max_spatial_stream = 1; //only spatial stream 1 makes sense + + for(i=0; irxevm_X[i]; + rx_evmX = (char)(tmp_rxevm); + + // Do not use shift operation like "rx_evmX >>= 1" because the compilor of free build environment + // fill most significant bit to "zero" when doing shifting operation which may change a negative + // value to positive one, then the dbm value (which is supposed to be negative) is not correct anymore. + rx_evmX /= 2; //dbm + + evm = rtl819x_evm_dbtopercentage(rx_evmX); +#if 0 + EVM = SignalScaleMapping(EVM);//make it good looking, from 0~100 +#endif + //if(bpacket_match_bssid) + { + if(i==0) // Fill value in RFD, Get the first spatial stream only + pstats->SignalQuality = precord_stats->SignalQuality = (u8)(evm & 0xff); + pstats->RxMIMOSignalQuality[i] = precord_stats->RxMIMOSignalQuality[i] = (u8)(evm & 0xff); + } + } + + + /* record rx statistics for debug */ + rxsc_sgien_exflg = pofdm_buf->rxsc_sgien_exflg; + prxsc = (phy_ofdm_rx_status_rxsc_sgien_exintfflag *)&rxsc_sgien_exflg; + if(pdrvinfo->BW) //40M channel + priv->stats.received_bwtype[1+prxsc->rxsc]++; + else //20M channel + priv->stats.received_bwtype[0]++; + } + + //UI BSS List signal strength(in percentage), make it good looking, from 0~100. + //It is assigned to the BSS List in GetValueFromBeaconOrProbeRsp(). + if(is_cck_rate) + { + pstats->SignalStrength = precord_stats->SignalStrength = (u8)(rtl819x_signal_scale_mapping((long)pwdb_all));//PWDB_ALL; + + } + else + { + //pRfd->Status.SignalStrength = pRecordRfd->Status.SignalStrength = (u8)(SignalScaleMapping(total_rssi/=RF90_PATH_MAX));//(u8)(total_rssi/=RF90_PATH_MAX); + // We can judge RX path number now. + if (rf_rx_num != 0) + pstats->SignalStrength = precord_stats->SignalStrength = (u8)(rtl819x_signal_scale_mapping((long)(total_rssi/=rf_rx_num))); + } +} /* QueryRxPhyStatus8190Pci */ +#endif + +void +rtl8192_record_rxdesc_forlateruse( + struct ieee80211_rx_stats * psrc_stats, + struct ieee80211_rx_stats * ptarget_stats +) +{ + ptarget_stats->bIsAMPDU = psrc_stats->bIsAMPDU; + ptarget_stats->bFirstMPDU = psrc_stats->bFirstMPDU; + ptarget_stats->Seq_Num = psrc_stats->Seq_Num; +} + +#ifdef RTL8192SU +static void rtl8192SU_query_rxphystatus( + struct r8192_priv * priv, + struct ieee80211_rx_stats * pstats, + rx_desc_819x_usb *pDesc, + rx_drvinfo_819x_usb * pdrvinfo, + struct ieee80211_rx_stats * precord_stats, + bool bpacket_match_bssid, + bool bpacket_toself, + bool bPacketBeacon, + bool bToSelfBA + ); +void rtl8192SU_TranslateRxSignalStuff(struct sk_buff *skb, + struct ieee80211_rx_stats * pstats, + rx_desc_819x_usb *pDesc, + rx_drvinfo_819x_usb *pdrvinfo) +{ + // TODO: We must only check packet for current MAC address. Not finish + rtl8192_rx_info *info = (struct rtl8192_rx_info *)skb->cb; + struct net_device *dev=info->dev; + struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); + bool bpacket_match_bssid, bpacket_toself; + bool bPacketBeacon=FALSE, bToSelfBA=FALSE; + static struct ieee80211_rx_stats previous_stats; + struct ieee80211_hdr_3addr *hdr;//by amy + u16 fc,type; + + // Get Signal Quality for only RX data queue (but not command queue) + + u8* tmp_buf; + //u16 tmp_buf_len = 0; + u8 *praddr; + + /* Get MAC frame start address. */ + tmp_buf = (u8*)skb->data;// + get_rxpacket_shiftbytes_819xusb(pstats); + + hdr = (struct ieee80211_hdr_3addr *)tmp_buf; + fc = le16_to_cpu(hdr->frame_ctl); + type = WLAN_FC_GET_TYPE(fc); + praddr = hdr->addr1; + + /* Check if the received packet is acceptabe. */ + bpacket_match_bssid = ((IEEE80211_FTYPE_CTL != type) && + (eqMacAddr(priv->ieee80211->current_network.bssid, (fc & IEEE80211_FCTL_TODS)? hdr->addr1 : (fc & IEEE80211_FCTL_FROMDS )? hdr->addr2 : hdr->addr3)) + && (!pstats->bHwError) && (!pstats->bCRC)&& (!pstats->bICV)); + bpacket_toself = bpacket_match_bssid & (eqMacAddr(praddr, priv->ieee80211->dev->dev_addr)); + +#if 1//cosa + if(WLAN_FC_GET_FRAMETYPE(fc)== IEEE80211_STYPE_BEACON) + { + bPacketBeacon = true; + //DbgPrint("Beacon 2, MatchBSSID = %d, ToSelf = %d \n", bPacketMatchBSSID, bPacketToSelf); + } + if(WLAN_FC_GET_FRAMETYPE(fc) == IEEE80211_STYPE_BLOCKACK) + { + if((eqMacAddr(praddr,dev->dev_addr))) + bToSelfBA = true; + //DbgPrint("BlockAck, MatchBSSID = %d, ToSelf = %d \n", bPacketMatchBSSID, bPacketToSelf); + } + +#endif + + + if(bpacket_match_bssid) + { + priv->stats.numpacket_matchbssid++; + } + if(bpacket_toself){ + priv->stats.numpacket_toself++; + } + // + // Process PHY information for previous packet (RSSI/PWDB/EVM) + // + // Because phy information is contained in the last packet of AMPDU only, so driver + // should process phy information of previous packet + rtl8192_process_phyinfo(priv, tmp_buf, &previous_stats, pstats); + rtl8192SU_query_rxphystatus(priv, pstats, pDesc, pdrvinfo, &previous_stats, bpacket_match_bssid,bpacket_toself,bPacketBeacon,bToSelfBA); + rtl8192_record_rxdesc_forlateruse(pstats, &previous_stats); + +} +#else +void TranslateRxSignalStuff819xUsb(struct sk_buff *skb, + struct ieee80211_rx_stats * pstats, + rx_drvinfo_819x_usb *pdrvinfo) +{ + // TODO: We must only check packet for current MAC address. Not finish + rtl8192_rx_info *info = (struct rtl8192_rx_info *)skb->cb; + struct net_device *dev=info->dev; + struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); + bool bpacket_match_bssid, bpacket_toself; + bool bPacketBeacon=FALSE, bToSelfBA=FALSE; + static struct ieee80211_rx_stats previous_stats; + struct ieee80211_hdr_3addr *hdr;//by amy + u16 fc,type; + + // Get Signal Quality for only RX data queue (but not command queue) + + u8* tmp_buf; + //u16 tmp_buf_len = 0; + u8 *praddr; + + /* Get MAC frame start address. */ + tmp_buf = (u8*)skb->data;// + get_rxpacket_shiftbytes_819xusb(pstats); + + hdr = (struct ieee80211_hdr_3addr *)tmp_buf; + fc = le16_to_cpu(hdr->frame_ctl); + type = WLAN_FC_GET_TYPE(fc); + praddr = hdr->addr1; + + /* Check if the received packet is acceptabe. */ + bpacket_match_bssid = ((IEEE80211_FTYPE_CTL != type) && + (eqMacAddr(priv->ieee80211->current_network.bssid, (fc & IEEE80211_FCTL_TODS)? hdr->addr1 : (fc & IEEE80211_FCTL_FROMDS )? hdr->addr2 : hdr->addr3)) + && (!pstats->bHwError) && (!pstats->bCRC)&& (!pstats->bICV)); + bpacket_toself = bpacket_match_bssid & (eqMacAddr(praddr, priv->ieee80211->dev->dev_addr)); + +#if 1//cosa + if(WLAN_FC_GET_FRAMETYPE(fc)== IEEE80211_STYPE_BEACON) + { + bPacketBeacon = true; + //DbgPrint("Beacon 2, MatchBSSID = %d, ToSelf = %d \n", bPacketMatchBSSID, bPacketToSelf); + } + if(WLAN_FC_GET_FRAMETYPE(fc) == IEEE80211_STYPE_BLOCKACK) + { + if((eqMacAddr(praddr,dev->dev_addr))) + bToSelfBA = true; + //DbgPrint("BlockAck, MatchBSSID = %d, ToSelf = %d \n", bPacketMatchBSSID, bPacketToSelf); + } + +#endif + + + if(bpacket_match_bssid) + { + priv->stats.numpacket_matchbssid++; + } + if(bpacket_toself){ + priv->stats.numpacket_toself++; + } + // + // Process PHY information for previous packet (RSSI/PWDB/EVM) + // + // Because phy information is contained in the last packet of AMPDU only, so driver + // should process phy information of previous packet + rtl8192_process_phyinfo(priv, tmp_buf, &previous_stats, pstats); + rtl8192_query_rxphystatus(priv, pstats, pdrvinfo, &previous_stats, bpacket_match_bssid,bpacket_toself,bPacketBeacon,bToSelfBA); + rtl8192_record_rxdesc_forlateruse(pstats, &previous_stats); + +} +#endif + +/** +* Function: UpdateReceivedRateHistogramStatistics +* Overview: Recored down the received data rate +* +* Input: +* struct net_device *dev +* struct ieee80211_rx_stats *stats +* +* Output: +* +* (priv->stats.ReceivedRateHistogram[] is updated) +* Return: +* None +*/ +void +UpdateReceivedRateHistogramStatistics8190( + struct net_device *dev, + struct ieee80211_rx_stats *stats + ) +{ + struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); + u32 rcvType=1; //0: Total, 1:OK, 2:CRC, 3:ICV + u32 rateIndex; + u32 preamble_guardinterval; //1: short preamble/GI, 0: long preamble/GI + + + if(stats->bCRC) + rcvType = 2; + else if(stats->bICV) + rcvType = 3; + + if(stats->bShortPreamble) + preamble_guardinterval = 1;// short + else + preamble_guardinterval = 0;// long + + switch(stats->rate) + { + // + // CCK rate + // + case MGN_1M: rateIndex = 0; break; + case MGN_2M: rateIndex = 1; break; + case MGN_5_5M: rateIndex = 2; break; + case MGN_11M: rateIndex = 3; break; + // + // Legacy OFDM rate + // + case MGN_6M: rateIndex = 4; break; + case MGN_9M: rateIndex = 5; break; + case MGN_12M: rateIndex = 6; break; + case MGN_18M: rateIndex = 7; break; + case MGN_24M: rateIndex = 8; break; + case MGN_36M: rateIndex = 9; break; + case MGN_48M: rateIndex = 10; break; + case MGN_54M: rateIndex = 11; break; + // + // 11n High throughput rate + // + case MGN_MCS0: rateIndex = 12; break; + case MGN_MCS1: rateIndex = 13; break; + case MGN_MCS2: rateIndex = 14; break; + case MGN_MCS3: rateIndex = 15; break; + case MGN_MCS4: rateIndex = 16; break; + case MGN_MCS5: rateIndex = 17; break; + case MGN_MCS6: rateIndex = 18; break; + case MGN_MCS7: rateIndex = 19; break; + case MGN_MCS8: rateIndex = 20; break; + case MGN_MCS9: rateIndex = 21; break; + case MGN_MCS10: rateIndex = 22; break; + case MGN_MCS11: rateIndex = 23; break; + case MGN_MCS12: rateIndex = 24; break; + case MGN_MCS13: rateIndex = 25; break; + case MGN_MCS14: rateIndex = 26; break; + case MGN_MCS15: rateIndex = 27; break; + default: rateIndex = 28; break; + } + priv->stats.received_preamble_GI[preamble_guardinterval][rateIndex]++; + priv->stats.received_rate_histogram[0][rateIndex]++; //total + priv->stats.received_rate_histogram[rcvType][rateIndex]++; +} + +#ifdef RTL8192SU +void rtl8192SU_query_rxdesc_status(struct sk_buff *skb, struct ieee80211_rx_stats *stats, bool bIsRxAggrSubframe) +{ + rtl8192_rx_info *info = (struct rtl8192_rx_info *)skb->cb; + struct net_device *dev=info->dev; + struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); + //rx_desc_819x_usb *desc = (rx_desc_819x_usb *)skb->data; + rx_drvinfo_819x_usb *driver_info = NULL; + + //PRT_RFD_STATUS pRtRfdStatus = &pRfd->Status; + //PHAL_DATA_8192SUSB pHalData = GET_HAL_DATA(Adapter); + //pu1Byte pDesc = (pu1Byte)pDescIn; + //PRX_DRIVER_INFO_8192S pDrvInfo; + +#ifdef USB_RX_AGGREGATION_SUPPORT//FIXLZM + //if (bIsRxAggrSubframe) + rx_desc_819x_usb_aggr_subframe *desc = (rx_desc_819x_usb_aggr_subframe *)skb->data; + else +#endif + rx_desc_819x_usb *desc = (rx_desc_819x_usb *)skb->data; + + if(0) + { + int m = 0; + printk("========================"); + for(m=0; mlen; m++){ + if((m%32) == 0) + printk("\n"); + printk("%2x ",((u8*)skb->data)[m]); + } + printk("\n========================\n"); + + } + + + // + //Get Rx Descriptor Raw Information + // + stats->Length = desc->Length ; + stats->RxDrvInfoSize = desc->RxDrvInfoSize*RX_DRV_INFO_SIZE_UNIT; + stats->RxBufShift = (desc->Shift)&0x03; + stats->bICV = desc->ICV; + stats->bCRC = desc->CRC32; + stats->bHwError = stats->bCRC|stats->bICV; + stats->Decrypted = !desc->SWDec;//RTL8190 set this bit to indicate that Hw does not decrypt packet + stats->bIsAMPDU = (desc->AMSDU==1); + stats->bFirstMPDU = (desc->PAGGR==1) && (desc->FAGGR==1); + stats->bShortPreamble = desc->SPLCP; + stats->RxIs40MHzPacket = (desc->BW==1); + stats->TimeStampLow = desc->TSFL; + + if((desc->FAGGR==1) || (desc->PAGGR==1)) + {// Rx A-MPDU + RT_TRACE(COMP_RXDESC, "FirstAGGR = %d, PartAggr = %d\n", desc->FAGGR, desc->PAGGR); + } +//YJ,test,090310 +if(stats->bHwError) +{ + if(stats->bICV) + printk("%s: Receive ICV error!!!!!!!!!!!!!!!!!!!!!!\n", __FUNCTION__); + if(stats->bCRC) + printk("%s: Receive CRC error!!!!!!!!!!!!!!!!!!!!!!\n", __FUNCTION__); +} + + if(IS_UNDER_11N_AES_MODE(priv->ieee80211)) + { + // Always received ICV error packets in AES mode. + // This fixed HW later MIC write bug. + if(stats->bICV && !stats->bCRC) + { + stats->bICV = FALSE; + stats->bHwError = FALSE; + } + } + + // Transform HwRate to MRate + if(!stats->bHwError) + //stats->DataRate = HwRateToMRate( + // (BOOLEAN)GET_RX_DESC_RXHT(pDesc), + // (u1Byte)GET_RX_DESC_RXMCS(pDesc), + // (BOOLEAN)GET_RX_DESC_PAGGR(pDesc)); + stats->rate = rtl8192SU_HwRateToMRate(desc->RxHT, desc->RxMCS, desc->PAGGR); + else + stats->rate = MGN_1M; + + // + // Collect Rx rate/AMPDU/TSFL + // + //UpdateRxdRateHistogramStatistics8192S(Adapter, pRfd); + //UpdateRxAMPDUHistogramStatistics8192S(Adapter, pRfd); + //UpdateRxPktTimeStamp8192S(Adapter, pRfd); + UpdateReceivedRateHistogramStatistics8190(dev, stats); + //UpdateRxAMPDUHistogramStatistics8192S(dev, stats); //FIXLZM + UpdateRxPktTimeStamp8190(dev, stats); + + // + // Get PHY Status and RSVD parts. + // It only appears on last aggregated packet. + // + if (desc->PHYStatus) + { + //driver_info = (rx_drvinfo_819x_usb *)(skb->data + RX_DESC_SIZE + stats->RxBufShift); + driver_info = (rx_drvinfo_819x_usb *)(skb->data + sizeof(rx_desc_819x_usb) + \ + stats->RxBufShift); + if(0) + { + int m = 0; + printk("========================\n"); + printk("RX_DESC_SIZE:%d, RxBufShift:%d, RxDrvInfoSize:%d\n", + RX_DESC_SIZE, stats->RxBufShift, stats->RxDrvInfoSize); + for(m=0; m<32; m++){ + printk("%2x ",((u8*)driver_info)[m]); + } + printk("\n========================\n"); + + } + + } + + //YJ,add,090107 + skb_pull(skb, sizeof(rx_desc_819x_usb)); + //YJ,add,090107,end + + // + // Get Total offset of MPDU Frame Body + // + if((stats->RxBufShift + stats->RxDrvInfoSize) > 0) + { + stats->bShift = 1; + //YJ,add,090107 + skb_pull(skb, stats->RxBufShift + stats->RxDrvInfoSize); + //YJ,add,090107,end + } + + // + // Get PHY Status and RSVD parts. + // It only appears on last aggregated packet. + // + if (desc->PHYStatus) + { + rtl8192SU_TranslateRxSignalStuff(skb, stats, desc, driver_info); + } +} +#else +void query_rxdesc_status(struct sk_buff *skb, struct ieee80211_rx_stats *stats, bool bIsRxAggrSubframe) +{ + rtl8192_rx_info *info = (struct rtl8192_rx_info *)skb->cb; + struct net_device *dev=info->dev; + struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); + //rx_desc_819x_usb *desc = (rx_desc_819x_usb *)skb->data; + rx_drvinfo_819x_usb *driver_info = NULL; + + // + //Get Rx Descriptor Information + // +#ifdef USB_RX_AGGREGATION_SUPPORT + if (bIsRxAggrSubframe) + { + rx_desc_819x_usb_aggr_subframe *desc = (rx_desc_819x_usb_aggr_subframe *)skb->data; + stats->Length = desc->Length ; + stats->RxDrvInfoSize = desc->RxDrvInfoSize; + stats->RxBufShift = 0; //RxBufShift = 2 in RxDesc, but usb didn't shift bytes in fact. + stats->bICV = desc->ICV; + stats->bCRC = desc->CRC32; + stats->bHwError = stats->bCRC|stats->bICV; + stats->Decrypted = !desc->SWDec;//RTL8190 set this bit to indicate that Hw does not decrypt packet + } else +#endif + { + rx_desc_819x_usb *desc = (rx_desc_819x_usb *)skb->data; + + stats->Length = desc->Length; + stats->RxDrvInfoSize = desc->RxDrvInfoSize; + stats->RxBufShift = 0;//desc->Shift&0x03; + stats->bICV = desc->ICV; + stats->bCRC = desc->CRC32; + stats->bHwError = stats->bCRC|stats->bICV; + //RTL8190 set this bit to indicate that Hw does not decrypt packet + stats->Decrypted = !desc->SWDec; + } + + if((priv->ieee80211->pHTInfo->bCurrentHTSupport == true) && (priv->ieee80211->pairwise_key_type == KEY_TYPE_CCMP)) + { + stats->bHwError = false; + } + else + { + stats->bHwError = stats->bCRC|stats->bICV; + } + + if(stats->Length < 24 || stats->Length > MAX_8192U_RX_SIZE) + stats->bHwError |= 1; + // + //Get Driver Info + // + // TODO: Need to verify it on FGPA platform + //Driver info are written to the RxBuffer following rx desc + if (stats->RxDrvInfoSize != 0) { + driver_info = (rx_drvinfo_819x_usb *)(skb->data + sizeof(rx_desc_819x_usb) + \ + stats->RxBufShift); + /* unit: 0.5M */ + /* TODO */ + if(!stats->bHwError){ + u8 ret_rate; + ret_rate = HwRateToMRate90(driver_info->RxHT, driver_info->RxRate); + if(ret_rate == 0xff) + { + // Abnormal Case: Receive CRC OK packet with Rx descriptor indicating non supported rate. + // Special Error Handling here, 2008.05.16, by Emily + + stats->bHwError = 1; + stats->rate = MGN_1M; //Set 1M rate by default + }else + { + stats->rate = ret_rate; + } + } + else + stats->rate = 0x02; + + stats->bShortPreamble = driver_info->SPLCP; + + + UpdateReceivedRateHistogramStatistics8190(dev, stats); + + stats->bIsAMPDU = (driver_info->PartAggr==1); + stats->bFirstMPDU = (driver_info->PartAggr==1) && (driver_info->FirstAGGR==1); +#if 0 + // TODO: it is debug only. It should be disabled in released driver. 2007.1.12 by Joseph + UpdateRxAMPDUHistogramStatistics8190(Adapter, pRfd); +#endif + stats->TimeStampLow = driver_info->TSFL; + // xiong mask it, 070514 + //pRfd->Status.TimeStampHigh = PlatformEFIORead4Byte(Adapter, TSFR+4); + // stats->TimeStampHigh = read_nic_dword(dev, TSFR+4); + + UpdateRxPktTimeStamp8190(dev, stats); + + // + // Rx A-MPDU + // + if(driver_info->FirstAGGR==1 || driver_info->PartAggr == 1) + RT_TRACE(COMP_RXDESC, "driver_info->FirstAGGR = %d, driver_info->PartAggr = %d\n", + driver_info->FirstAGGR, driver_info->PartAggr); + + } + + skb_pull(skb,sizeof(rx_desc_819x_usb)); + // + // Get Total offset of MPDU Frame Body + // + if((stats->RxBufShift + stats->RxDrvInfoSize) > 0) { + stats->bShift = 1; + skb_pull(skb,stats->RxBufShift + stats->RxDrvInfoSize); + } + +#ifdef USB_RX_AGGREGATION_SUPPORT + /* for the rx aggregated sub frame, the redundant space truelly contained in the packet */ + if(bIsRxAggrSubframe) { + skb_pull(skb, 8); + } +#endif + /* for debug 2008.5.29 */ +#if 0 + { + int i; + printk("\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); + for(i = 0; i < skb->len; i++) { + if(i % 10 == 0) printk("\n"); + printk("%02x ", skb->data[i]); + } + printk("\n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); + } +#endif + + //added by vivi, for MP, 20080108 + stats->RxIs40MHzPacket = driver_info->BW; + if(stats->RxDrvInfoSize != 0) + TranslateRxSignalStuff819xUsb(skb, stats, driver_info); + +} +#endif + +#ifdef RTL8192SU +#if 0 +/*----------------------------------------------------------------------------- + * Function: UpdateRxAMPDUHistogramStatistics8192S + * + * Overview: Recored down the received A-MPDU aggregation size and pkt number + * + * Input: Adapter + * + * Output: Adapter + * (Adapter->RxStats.RxAMPDUSizeHistogram[] is updated) + * (Adapter->RxStats.RxAMPDUNumHistogram[] is updated) + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 09/18/2008 MHC Create Version 0. + * + *---------------------------------------------------------------------------*/ +static void +UpdateRxAMPDUHistogramStatistics8192S( + struct net_device *dev, + struct ieee80211_rx_stats *stats + ) +{ + //HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + u8 size_index; + u8 num_index; + u16 update_size = 0; + u8 update_num = 0; + + if(stats->bIsAMPDU) + { + if(stats->bFirstMPDU) + { + if(stats->nRxAMPDU_Size!=0 && stats->nRxAMPDU_AggrNum!=0) + { + update_size = stats->nRxAMPDU_Size; + update_num = stats->nRxAMPDU_AggrNum; + } + stats->nRxAMPDU_Size = stats->Length; + stats->nRxAMPDU_AggrNum = 1; + } + else + { + stats->nRxAMPDU_Size += stats->Length; + stats->nRxAMPDU_AggrNum++; + } + } + else + { + if(stats->nRxAMPDU_Size!=0 && stats->nRxAMPDU_AggrNum!=0) + { + update_size = stats->nRxAMPDU_Size; + update_num = stats->nRxAMPDU_AggrNum; + } + stats->nRxAMPDU_Size = 0; + stats->nRxAMPDU_AggrNum = 0; + } + + if(update_size!=0 && update_num!= 0) + { + if(update_size < 4096) + size_index = 0; + else if(update_size < 8192) + size_index = 1; + else if(update_size < 16384) + size_index = 2; + else if(update_size < 32768) + size_index = 3; + else if(update_size < 65536) + size_index = 4; + else + { + RT_TRACE(COMP_RXDESC, + ("UpdateRxAMPDUHistogramStatistics8192S(): A-MPDU too large\n"); + } + + Adapter->RxStats.RxAMPDUSizeHistogram[size_index]++; + + if(update_num < 5) + num_index = 0; + else if(update_num < 10) + num_index = 1; + else if(update_num < 20) + num_index = 2; + else if(update_num < 40) + num_index = 3; + else + num_index = 4; + + Adapter->RxStats.RxAMPDUNumHistogram[num_index]++; + } +} // UpdateRxAMPDUHistogramStatistics8192S +#endif + +#endif + + +#ifdef RTL8192SU +// +// Description: +// The strarting address of wireless lan header will shift 1 or 2 or 3 or "more" bytes for the following reason : +// (1) QoS control : shift 2 bytes +// (2) Mesh Network : shift 1 or 3 bytes +// (3) RxDriverInfo occupies the front parts of Rx Packets buffer(shift units is in 8Bytes) +// +// It is because Lextra CPU used by 8186 or 865x series assert exception if the statrting address +// of IP header is not double word alignment. +// This features is supported in 818xb and 8190 only, but not 818x. +// +// parameter: PRT_RFD, Pointer of Reeceive frame descriptor which is initialized according to +// Rx Descriptor +// return value: unsigned int, number of total shifted bytes +// +// Notes: 2008/06/28, created by Roger +// +u32 GetRxPacketShiftBytes8192SU(struct ieee80211_rx_stats *Status, bool bIsRxAggrSubframe) +{ + //PRT_RFD_STATUS pRtRfdStatus = &pRfd->Status; + + return (sizeof(rx_desc_819x_usb) + Status->RxDrvInfoSize + Status->RxBufShift); +} + +void rtl8192SU_rx_nomal(struct sk_buff* skb) +{ + rtl8192_rx_info *info = (struct rtl8192_rx_info *)skb->cb; + struct net_device *dev=info->dev; + struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); + struct ieee80211_rx_stats stats = { + .signal = 0, + .noise = -98, + .rate = 0, + // .mac_time = jiffies, + .freq = IEEE80211_24GHZ_BAND, + }; + u32 rx_pkt_len = 0; + struct ieee80211_hdr_1addr *ieee80211_hdr = NULL; + bool unicast_packet = false; + +#ifdef USB_RX_AGGREGATION_SUPPORT + struct sk_buff *agg_skb = NULL; + u32 TotalLength = 0;//Total packet length for all aggregated packets. + u32 TempDWord = 0; + u32 PacketLength = 0;// Per-packet length include size of RxDesc. + u32 PacketOccupiedLendth = 0; + u8 TempByte = 0; + u32 PacketShiftBytes = 0; + rx_desc_819x_usb_aggr_subframe *RxDescr = NULL; + u8 PaddingBytes = 0; + //add just for testing + u8 testing; + + u8 TotalAggPkt = 0; + PRT_HIGH_THROUGHPUT pHTInfo =priv-> ieee80211->pHTInfo; + u16 RxPageSize = pHTInfo->UsbRxPageSize; + + stats->nTotalAggPkt = 0; + //stats->bIsRxAggrSubframe = FALSE; + +#endif + //printk("**********skb->len = %d\n", skb->len); + /* 20 is for ps-poll */ + if((skb->len >=(20 + sizeof(rx_desc_819x_usb))) && (skb->len < RX_URB_SIZE)) { + + /* first packet should not contain Rx aggregation header */ + rtl8192SU_query_rxdesc_status(skb, &stats, false); + /* TODO */ + + /* hardware related info */ +#ifdef USB_RX_AGGREGATION_SUPPORT + TotalAggPkt = stats->nTotalAggPkt; + PacketLength = stats->Length + GetRxPacketShiftBytes8192SU(&stats, false); + + agg_skb = skb; + skb = dev_alloc_skb(PacketLength); + memcpy(skb_put(skb,PacketLength),agg_skb->data,PacketLength); +#endif + priv->stats.rxoktotal++; //YJ,test,090108 + + /* Process the MPDU recevied */ + skb_trim(skb, skb->len - 4/*sCrcLng*/);//FIXLZM + + rx_pkt_len = skb->len; + ieee80211_hdr = (struct ieee80211_hdr_1addr *)skb->data; + unicast_packet = false; + if(is_broadcast_ether_addr(ieee80211_hdr->addr1)) { + //TODO + }else if(is_multicast_ether_addr(ieee80211_hdr->addr1)){ + //TODO + }else { + /* unicast packet */ + unicast_packet = true; + } + + if(!ieee80211_rx(priv->ieee80211,skb, &stats)) { + dev_kfree_skb_any(skb); + } else { + // priv->stats.rxoktotal++; //YJ,test,090108 + if(unicast_packet) { + priv->stats.rxbytesunicast += rx_pkt_len; + } + } + + //up is firs pkt, follow is next and next +#ifdef USB_RX_AGGREGATION_SUPPORT + // + // The following operations are for processing Rx aggregated packets. + // + if(TotalAggPkt>0) + TotalAggPkt--; + + while ( TotalAggPkt>0 ) + {// More aggregated packets need to process. + + u8 tmpCRC = 0, tmpICV = 0; + + //Page size must align to multiple of 128-Bytes. + if((PacketLength%RxPageSize) != 0) + //PacketLength = ((PacketLength/RxPageSize)+1)*RxPageSize; + PacketLength = ((PacketLength>>7)+1)*RxPageSize; // RxPageSize is 128bytes as default. + + // Current total packet occupied length in this buffer. + PacketOccupiedLendth += PacketLength; + +#if (defined (RTL8192SU_FPGA_2MAC_VERIFICATION)||defined (RTL8192SU_ASIC_VERIFICATION)) + //if(PacketOccupiedLendth>pContext->BufLenUsed) + if(PacketOccupiedLendth>skb->len) + { + RT_TRACE(COMP_RECV, "(1)HalUsbInMpduComplete8192SUsb(): pRtRfdStatus->Length(%#x)!!\n", stats->Length); + RT_TRACE(COMP_RECV, "(1)HalUsbInMpduComplete8192SUsb(): Invalid PacketOccupiedLendth(%#x)!!, BufLenUsed(%#x)\n", PacketOccupiedLendth, stats->BufLenUsed); + break; + } +#endif + + skb_pull(agg_skb, PacketLength); + + // + // Process the MPDU recevied. + // + //RT_TRACE(COMP_RECV,"%s:aggred pkt,total_len = %d\n",__FUNCTION__,agg_skb->len); + RxDescr = (rx_desc_819x_usb_aggr_subframe *)(agg_skb->data); + +#if 0//92SU del + tmpCRC = RxDescr->CRC32; + tmpICV = RxDescr->ICV; + memcpy(agg_skb->data, &agg_skb->data[44], 2); + RxDescr->CRC32 = tmpCRC; + RxDescr->ICV = tmpICV; +#endif + memset(&stats, 0, sizeof(struct ieee80211_rx_stats)); + stats.signal = 0; + stats.noise = -98; + stats.rate = 0; + stats.freq = IEEE80211_24GHZ_BAND; + + rtl8192SU_query_rxdesc_status(agg_skb, &stats, true); + //PacketLength = stats.Length; + PacketLength = stats.Length + GetRxPacketShiftBytes8192SU(&stats, true); + +#if (defined (RTL8192SU_FPGA_2MAC_VERIFICATION)||defined (RTL8192SU_ASIC_VERIFICATION)) + if((PacketOccupiedLendth+PacketLength)>skb->len) + { + RT_TRACE(COMP_RECV, "(2)HalUsbInMpduComplete8192SUsb(): Invalid PacketOccupiedLendth(%#x)+PacketLength(%#x)!!, BufLenUsed(%#x)\n", + PacketOccupiedLendth, PacketLength, pContext->BufLenUsed); + break; + } +#endif + + if(PacketLength > agg_skb->len) { + break; + } + + /* Process the MPDU recevied */ + skb = dev_alloc_skb(PacketLength); + memcpy(skb_put(skb,PacketLength),agg_skb->data, PacketLength); + skb_trim(skb, skb->len - 4/*sCrcLng*/); + + rx_pkt_len = skb->len; + ieee80211_hdr = (struct ieee80211_hdr_1addr *)skb->data; + unicast_packet = false; + if(is_broadcast_ether_addr(ieee80211_hdr->addr1)) { + //TODO + }else if(is_multicast_ether_addr(ieee80211_hdr->addr1)){ + //TODO + }else { + /* unicast packet */ + unicast_packet = true; + } + if(!ieee80211_rx(priv->ieee80211,skb, &stats)) { + dev_kfree_skb_any(skb); + } else { + priv->stats.rxoktotal++; + if(unicast_packet) { + priv->stats.rxbytesunicast += rx_pkt_len; + } + } + + TotalAggPkt--; + + skb_pull(agg_skb, TempDWord); + } + + dev_kfree_skb(agg_skb); +#endif + } + else + { + priv->stats.rxurberr++; + printk("actual_length:%d\n", skb->len); + dev_kfree_skb_any(skb); + } + +} +#else +u32 GetRxPacketShiftBytes819xUsb(struct ieee80211_rx_stats *Status, bool bIsRxAggrSubframe) +{ +#ifdef USB_RX_AGGREGATION_SUPPORT + if (bIsRxAggrSubframe) + return (sizeof(rx_desc_819x_usb) + Status->RxDrvInfoSize + + Status->RxBufShift + 8); + else +#endif + return (sizeof(rx_desc_819x_usb) + Status->RxDrvInfoSize + + Status->RxBufShift); +} + +void rtl8192_rx_nomal(struct sk_buff* skb) +{ + rtl8192_rx_info *info = (struct rtl8192_rx_info *)skb->cb; + struct net_device *dev=info->dev; + struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); + struct ieee80211_rx_stats stats = { + .signal = 0, + .noise = -98, + .rate = 0, + // .mac_time = jiffies, + .freq = IEEE80211_24GHZ_BAND, + }; + u32 rx_pkt_len = 0; + struct ieee80211_hdr_1addr *ieee80211_hdr = NULL; + bool unicast_packet = false; +#ifdef USB_RX_AGGREGATION_SUPPORT + struct sk_buff *agg_skb = NULL; + u32 TotalLength = 0; + u32 TempDWord = 0; + u32 PacketLength = 0; + u32 PacketOccupiedLendth = 0; + u8 TempByte = 0; + u32 PacketShiftBytes = 0; + rx_desc_819x_usb_aggr_subframe *RxDescr = NULL; + u8 PaddingBytes = 0; + //add just for testing + u8 testing; + +#endif + + /* 20 is for ps-poll */ + if((skb->len >=(20 + sizeof(rx_desc_819x_usb))) && (skb->len < RX_URB_SIZE)) { +#ifdef USB_RX_AGGREGATION_SUPPORT + TempByte = *(skb->data + sizeof(rx_desc_819x_usb)); +#endif + /* first packet should not contain Rx aggregation header */ + query_rxdesc_status(skb, &stats, false); + /* TODO */ + /* hardware related info */ +#ifdef USB_RX_AGGREGATION_SUPPORT + if (TempByte & BIT0) { + agg_skb = skb; + //TotalLength = agg_skb->len - 4; /*sCrcLng*/ + TotalLength = stats.Length - 4; /*sCrcLng*/ + //RT_TRACE(COMP_RECV, "%s:first aggregated packet!Length=%d\n",__FUNCTION__,TotalLength); + /* though the head pointer has passed this position */ + TempDWord = *(u32 *)(agg_skb->data - 4); + PacketLength = (u16)(TempDWord & 0x3FFF); /*sCrcLng*/ + skb = dev_alloc_skb(PacketLength); + memcpy(skb_put(skb,PacketLength),agg_skb->data,PacketLength); + PacketShiftBytes = GetRxPacketShiftBytes819xUsb(&stats, false); + } +#endif + /* Process the MPDU recevied */ + skb_trim(skb, skb->len - 4/*sCrcLng*/); + + rx_pkt_len = skb->len; + ieee80211_hdr = (struct ieee80211_hdr_1addr *)skb->data; + unicast_packet = false; + if(is_broadcast_ether_addr(ieee80211_hdr->addr1)) { + //TODO + }else if(is_multicast_ether_addr(ieee80211_hdr->addr1)){ + //TODO + }else { + /* unicast packet */ + unicast_packet = true; + } + + if(!ieee80211_rx(priv->ieee80211,skb, &stats)) { + dev_kfree_skb_any(skb); + } else { + priv->stats.rxoktotal++; + if(unicast_packet) { + priv->stats.rxbytesunicast += rx_pkt_len; + } + } +#ifdef USB_RX_AGGREGATION_SUPPORT + testing = 1; + // (PipeIndex == 0) && (TempByte & BIT0) => TotalLength > 0. + if (TotalLength > 0) { + PacketOccupiedLendth = PacketLength + (PacketShiftBytes + 8); + if ((PacketOccupiedLendth & 0xFF) != 0) + PacketOccupiedLendth = (PacketOccupiedLendth & 0xFFFFFF00) + 256; + PacketOccupiedLendth -= 8; + TempDWord = PacketOccupiedLendth - PacketShiftBytes; /*- PacketLength */ + if (agg_skb->len > TempDWord) + skb_pull(agg_skb, TempDWord); + else + agg_skb->len = 0; + + while (agg_skb->len>=GetRxPacketShiftBytes819xUsb(&stats, true)) { + u8 tmpCRC = 0, tmpICV = 0; + //RT_TRACE(COMP_RECV,"%s:aggred pkt,total_len = %d\n",__FUNCTION__,agg_skb->len); + RxDescr = (rx_desc_819x_usb_aggr_subframe *)(agg_skb->data); + tmpCRC = RxDescr->CRC32; + tmpICV = RxDescr->ICV; + memcpy(agg_skb->data, &agg_skb->data[44], 2); + RxDescr->CRC32 = tmpCRC; + RxDescr->ICV = tmpICV; + + memset(&stats, 0, sizeof(struct ieee80211_rx_stats)); + stats.signal = 0; + stats.noise = -98; + stats.rate = 0; + stats.freq = IEEE80211_24GHZ_BAND; + query_rxdesc_status(agg_skb, &stats, true); + PacketLength = stats.Length; + + if(PacketLength > agg_skb->len) { + break; + } + /* Process the MPDU recevied */ + skb = dev_alloc_skb(PacketLength); + memcpy(skb_put(skb,PacketLength),agg_skb->data, PacketLength); + skb_trim(skb, skb->len - 4/*sCrcLng*/); + + rx_pkt_len = skb->len; + ieee80211_hdr = (struct ieee80211_hdr_1addr *)skb->data; + unicast_packet = false; + if(is_broadcast_ether_addr(ieee80211_hdr->addr1)) { + //TODO + }else if(is_multicast_ether_addr(ieee80211_hdr->addr1)){ + //TODO + }else { + /* unicast packet */ + unicast_packet = true; + } + if(!ieee80211_rx(priv->ieee80211,skb, &stats)) { + dev_kfree_skb_any(skb); + } else { + priv->stats.rxoktotal++; + if(unicast_packet) { + priv->stats.rxbytesunicast += rx_pkt_len; + } + } + /* should trim the packet which has been copied to target skb */ + skb_pull(agg_skb, PacketLength); + PacketShiftBytes = GetRxPacketShiftBytes819xUsb(&stats, true); + PacketOccupiedLendth = PacketLength + PacketShiftBytes; + if ((PacketOccupiedLendth & 0xFF) != 0) { + PaddingBytes = 256 - (PacketOccupiedLendth & 0xFF); + if (agg_skb->len > PaddingBytes) + skb_pull(agg_skb, PaddingBytes); + else + agg_skb->len = 0; + } + } + dev_kfree_skb(agg_skb); + } +#endif + } else { + priv->stats.rxurberr++; + printk("actual_length:%d\n", skb->len); + dev_kfree_skb_any(skb); + } + +} + +#endif + +void +rtl819xusb_process_received_packet( + struct net_device *dev, + struct ieee80211_rx_stats *pstats + ) +{ +// bool bfreerfd=false, bqueued=false; + u8* frame; + u16 frame_len=0; + struct r8192_priv *priv = ieee80211_priv(dev); +// u8 index = 0; +// u8 TID = 0; + //u16 seqnum = 0; + //PRX_TS_RECORD pts = NULL; + + // Get shifted bytes of Starting address of 802.11 header. 2006.09.28, by Emily + //porting by amy 080508 + pstats->virtual_address += get_rxpacket_shiftbytes_819xusb(pstats); + frame = pstats->virtual_address; + frame_len = pstats->packetlength; +#ifdef TODO // by amy about HCT + if(!Adapter->bInHctTest) + CountRxErrStatistics(Adapter, pRfd); +#endif + { + #ifdef ENABLE_PS //by amy for adding ps function in future + RT_RF_POWER_STATE rtState; + // When RF is off, we should not count the packet for hw/sw synchronize + // reason, ie. there may be a duration while sw switch is changed and hw + // switch is being changed. 2006.12.04, by shien chang. + Adapter->HalFunc.GetHwRegHandler(Adapter, HW_VAR_RF_STATE, (u8* )(&rtState)); + if (rtState == eRfOff) + { + return; + } + #endif + priv->stats.rxframgment++; + + } +#ifdef TODO + RmMonitorSignalStrength(Adapter, pRfd); +#endif + /* 2007/01/16 MH Add RX command packet handle here. */ + /* 2007/03/01 MH We have to release RFD and return if rx pkt is cmd pkt. */ + if (rtl819xusb_rx_command_packet(dev, pstats)) + { + return; + } + +#ifdef SW_CRC_CHECK + SwCrcCheck(); +#endif + + +} + +void query_rx_cmdpkt_desc_status(struct sk_buff *skb, struct ieee80211_rx_stats *stats) +{ +// rtl8192_rx_info *info = (struct rtl8192_rx_info *)skb->cb; +// struct net_device *dev=info->dev; +// struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); + rx_desc_819x_usb *desc = (rx_desc_819x_usb *)skb->data; +// rx_drvinfo_819x_usb *driver_info; + + // + //Get Rx Descriptor Information + // + stats->virtual_address = (u8*)skb->data; + stats->Length = desc->Length; + stats->RxDrvInfoSize = 0; + stats->RxBufShift = 0; + stats->packetlength = stats->Length-scrclng; + stats->fraglength = stats->packetlength; + stats->fragoffset = 0; + stats->ntotalfrag = 1; +} + +#ifdef RTL8192SU +void rtl8192SU_rx_cmd(struct sk_buff *skb) +{ + struct rtl8192_rx_info *info = (struct rtl8192_rx_info *)skb->cb; + struct net_device *dev = info->dev; + + /* TODO */ + struct ieee80211_rx_stats stats = { + .signal = 0, + .noise = -98, + .rate = 0, + // .mac_time = jiffies, + .freq = IEEE80211_24GHZ_BAND, + }; + + // + // Check buffer length to determine if this is a valid MPDU. + // + if( (skb->len >= sizeof(rx_desc_819x_usb)) && (skb->len <= RX_URB_SIZE) )//&& + //(pHalData->SwChnlInProgress == FALSE)) + { + // + // Collection information in Rx descriptor. + // +#if 0 + pRxDesc = pContext->Buffer; + + pRfd->Buffer.VirtualAddress = pContext->Buffer; // 061109, rcnjko, for multi-platform consideration.. + + pRtRfdStatus->Length = (u2Byte)GET_RX_DESC_PKT_LEN(pRxDesc); + pRtRfdStatus->RxDrvInfoSize = 0; + pRtRfdStatus->RxBufShift = 0; + + pRfd->PacketLength = pRfd->Status.Length - sCrcLng; + pRfd->FragLength = pRfd->PacketLength; + pRfd->FragOffset = 0; + pRfd->nTotalFrag = 1; + pRfd->queue_id = PipeIndex; +#endif + query_rx_cmdpkt_desc_status(skb,&stats); + // this is to be done by amy 080508 prfd->queue_id = 1; + + // + // Process the MPDU recevied. + // + rtl819xusb_process_received_packet(dev,&stats); + + dev_kfree_skb_any(skb); + } + else + { + //RTInsertTailListWithCnt(&pAdapter->RfdIdleQueue, &pRfd->List, &pAdapter->NumIdleRfd); + //RT_ASSERT(pAdapter->NumIdleRfd <= pAdapter->NumRfd, ("HalUsbInCommandComplete8192SUsb(): Adapter->NumIdleRfd(%d)\n", pAdapter->NumIdleRfd)); + //RT_TRACE(COMP_RECV, DBG_LOUD, ("HalUsbInCommandComplete8192SUsb(): NOT enough Resources!! BufLenUsed(%d), NumIdleRfd(%d)\n", + //pContext->BufLenUsed, pAdapter->NumIdleRfd)); + } + + // + // Reuse USB_IN_CONTEXT since we had finished processing the + // buffer in USB_IN_CONTEXT. + // + //HalUsbReturnInContext(pAdapter, pContext); + + // + // Issue another bulk IN transfer. + // + //HalUsbInMpdu(pAdapter, PipeIndex); + + RT_TRACE(COMP_RECV, "<--- HalUsbInCommandComplete8192SUsb()\n"); + +} +#else +void rtl8192_rx_cmd(struct sk_buff *skb) +{ + struct rtl8192_rx_info *info = (struct rtl8192_rx_info *)skb->cb; + struct net_device *dev = info->dev; + //int ret; +// struct urb *rx_urb = info->urb; + /* TODO */ + struct ieee80211_rx_stats stats = { + .signal = 0, + .noise = -98, + .rate = 0, + // .mac_time = jiffies, + .freq = IEEE80211_24GHZ_BAND, + }; + + if((skb->len >=(20 + sizeof(rx_desc_819x_usb))) && (skb->len < RX_URB_SIZE)) + { + + query_rx_cmdpkt_desc_status(skb,&stats); + // this is to be done by amy 080508 prfd->queue_id = 1; + + + // + // Process the command packet received. + // + + rtl819xusb_process_received_packet(dev,&stats); + + dev_kfree_skb_any(skb); + } + else + ; + + +#if 0 + desc = (u32*)(skb->data); + cmd = (desc[0] >> 30) & 0x03; + + if(cmd == 0x00) {//beacon interrupt + //send beacon packet + skb = ieee80211_get_beacon(priv->ieee80211); + + if(!skb){ + DMESG("not enought memory for allocating beacon"); + return; + } + skb->cb[0] = BEACON_PRIORITY; + skb->cb[1] = 0; + skb->cb[2] = ieeerate2rtlrate(priv->ieee80211->basic_rate); + ret = rtl8192_tx(dev, skb); + + if( ret != 0 ){ + printk(KERN_ALERT "tx beacon packet error : %d !\n", ret); + } + dev_kfree_skb_any(skb); + } else {//0x00 + //{ log the device information + // At present, It is not implemented just now. + //} + } +#endif +} +#endif + +void rtl8192_irq_rx_tasklet(struct r8192_priv *priv) +{ + struct sk_buff *skb; + struct rtl8192_rx_info *info; + + while (NULL != (skb = skb_dequeue(&priv->skb_queue))) { + info = (struct rtl8192_rx_info *)skb->cb; + switch (info->out_pipe) { + /* Nomal packet pipe */ + case 3: + //RT_TRACE(COMP_RECV, "normal in-pipe index(%d)\n",info->out_pipe); + priv->IrpPendingCount--; + priv->ops->rtl819x_rx_nomal(skb); + break; + + /* Command packet pipe */ + case 9: + RT_TRACE(COMP_RECV, "command in-pipe index(%d)\n",\ + info->out_pipe); + priv->ops->rtl819x_rx_cmd(skb); + break; + + default: /* should never get here! */ + RT_TRACE(COMP_ERR, "Unknown in-pipe index(%d)\n",\ + info->out_pipe); + dev_kfree_skb(skb); + break; + + } + } +} + + + +/**************************************************************************** + ---------------------------- USB_STUFF--------------------------- +*****************************************************************************/ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) +//LZM Merge from windows HalUsbSetQueuePipeMapping8192SUsb 090319 +static void HalUsbSetQueuePipeMapping8192SUsb(struct usb_interface *intf, struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + struct usb_host_interface *iface_desc; + struct usb_endpoint_descriptor *endpoint; + u8 i = 0; + + priv->ep_in_num = 0; + priv->ep_out_num = 0; + memset(priv->RtOutPipes,0,16); + memset(priv->RtInPipes,0,16); + +#ifndef USE_ONE_PIPE + iface_desc = intf->cur_altsetting; + priv->ep_num = iface_desc->desc.bNumEndpoints; + + for (i = 0; i < priv->ep_num; ++i) { + endpoint = &iface_desc->endpoint[i].desc; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,23) + if (usb_endpoint_is_bulk_in(endpoint)) { + priv->RtInPipes[priv->ep_in_num] = usb_endpoint_num(endpoint); + priv->ep_in_num ++; + //printk("in_endpoint_idx = %d\n", usb_endpoint_num(endpoint)); + } else if (usb_endpoint_is_bulk_out(endpoint)) { + priv->RtOutPipes[priv->ep_out_num] = usb_endpoint_num(endpoint); + priv->ep_out_num ++; + //printk("out_endpoint_idx = %d\n", usb_endpoint_num(endpoint)); + } +#else + if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) && + ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK)) { + /* we found a bulk in endpoint */ + priv->RtInPipes[priv->ep_in_num] = (endpoint->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); + priv->ep_in_num ++; + } else if (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) && + ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK)) { + /* We found bulk out endpoint */ + priv->RtOutPipes[priv->ep_out_num] = endpoint->bEndpointAddress; + priv->ep_out_num ++; + } +#endif + } + { + memset(priv->txqueue_to_outpipemap,0,9); + if (priv->ep_num == 6) { + // BK, BE, VI, VO, HCCA, TXCMD, MGNT, HIGH, BEACON + u8 queuetopipe[] = {3, 2, 1, 0, 4, 4, 4, 4, 4}; + + memcpy(priv->txqueue_to_outpipemap,queuetopipe,9); + } else if (priv->ep_num == 4) { + // BK, BE, VI, VO, HCCA, TXCMD, MGNT, HIGH, BEACON + u8 queuetopipe[] = {1, 1, 0, 0, 2, 2, 2, 2, 2}; + + memcpy(priv->txqueue_to_outpipemap,queuetopipe,9); + } else if (priv->ep_num > 9) { + // BK, BE, VI, VO, HCCA, TXCMD, MGNT, HIGH, BEACON + u8 queuetopipe[] = {3, 2, 1, 0, 4, 8, 7, 6, 5}; + + memcpy(priv->txqueue_to_outpipemap,queuetopipe,9); + } else {//use sigle pipe + // BK, BE, VI, VO, HCCA, TXCMD, MGNT, HIGH, BEACON + u8 queuetopipe[] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; + memcpy(priv->txqueue_to_outpipemap,queuetopipe,9); + } + } + printk("==>ep_num:%d, in_ep_num:%d, out_ep_num:%d\n", priv->ep_num, priv->ep_in_num, priv->ep_out_num); + + printk("==>RtInPipes:"); + for(i=0; i < priv->ep_in_num; i++) + printk("%d ", priv->RtInPipes[i]); + printk("\n"); + + printk("==>RtOutPipes:"); + for(i=0; i < priv->ep_out_num; i++) + printk("%d ", priv->RtOutPipes[i]); + printk("\n"); + + printk("==>txqueue_to_outpipemap for BK, BE, VI, VO, HCCA, TXCMD, MGNT, HIGH, BEACON:\n"); + for(i=0; i < 9; i++) + printk("%d ", priv->txqueue_to_outpipemap[i]); + printk("\n"); +#else + { + memset(priv->txqueue_to_outpipemap,0,9); + memset(priv->RtOutPipes,4,16);//all use endpoint 4 for out + } +#endif + + return; +} +#endif + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) +static int __devinit rtl8192_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +#else +static void * __devinit rtl8192_usb_probe(struct usb_device *udev, + unsigned int ifnum, + const struct usb_device_id *id) +#endif +{ +// unsigned long ioaddr = 0; + struct net_device *dev = NULL; + struct r8192_priv *priv= NULL; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + struct usb_device *udev = interface_to_usbdev(intf); +#endif + RT_TRACE(COMP_INIT, "Oops: i'm coming\n"); + + dev = alloc_ieee80211(sizeof(struct r8192_priv)); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) + SET_MODULE_OWNER(dev); +#endif + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + usb_set_intfdata(intf, dev); + SET_NETDEV_DEV(dev, &intf->dev); +#endif + priv = ieee80211_priv(dev); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + priv->ieee80211 = netdev_priv(dev); +#else + priv->ieee80211 = (struct net_device *)dev->priv; +#endif + priv->udev=udev; + +#ifdef RTL8192SU +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + HalUsbSetQueuePipeMapping8192SUsb(intf, dev); +#else//use one pipe + { + memset(priv->txqueue_to_outpipemap,0,9); + memset(priv->RtOutPipes,4,16);//all use endpoint 4 for out + } +#endif +#endif + +#ifdef RTL8192SU + //printk("===============>NIC 8192SU\n"); + priv->ops = &rtl8192su_ops; +#else + //printk("===============>NIC 8192U\n"); + priv->ops = &rtl8192u_ops; +#endif + + dev->open = rtl8192_open; + dev->stop = rtl8192_close; + //dev->hard_start_xmit = rtl8192_8023_hard_start_xmit; + dev->tx_timeout = tx_timeout; + //dev->wireless_handlers = &r8192_wx_handlers_def; + dev->do_ioctl = rtl8192_ioctl; + dev->set_multicast_list = r8192_set_multicast; + dev->set_mac_address = r8192_set_mac_adr; + dev->get_stats = rtl8192_stats; + + //DMESG("Oops: i'm coming\n"); +#if WIRELESS_EXT >= 12 +#if WIRELESS_EXT < 17 + dev->get_wireless_stats = r8192_get_wireless_stats; +#endif + dev->wireless_handlers = (struct iw_handler_def *) &r8192_wx_handlers_def; +#endif + dev->type=ARPHRD_ETHER; + + dev->watchdog_timeo = HZ*3; //modified by john, 0805 + + if (dev_alloc_name(dev, ifname) < 0){ + RT_TRACE(COMP_INIT, "Oops: devname already taken! Trying wlan%%d...\n"); + ifname = "wlan%d"; + dev_alloc_name(dev, ifname); + } + + RT_TRACE(COMP_INIT, "Driver probe completed1\n"); +#if 1 + if(rtl8192_init(dev)!=0){ + RT_TRACE(COMP_ERR, "Initialization failed"); + goto fail; + } +#endif + netif_carrier_off(dev); + netif_stop_queue(dev); + + register_netdev(dev); + RT_TRACE(COMP_INIT, "dev name=======> %s\n",dev->name); + rtl8192_proc_init_one(dev); + + + RT_TRACE(COMP_INIT, "Driver probe completed\n"); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + return dev; +#else + return 0; +#endif + + +fail: + free_ieee80211(dev); + + RT_TRACE(COMP_ERR, "wlan driver load failed\n"); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + return NULL; +#else + return -ENODEV; +#endif + +} + +//detach all the work and timer structure declared or inititialize in r8192U_init function. +void rtl8192_cancel_deferred_work(struct r8192_priv* priv) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) + cancel_work_sync(&priv->reset_wq); + cancel_work_sync(&priv->qos_activate); + cancel_delayed_work(&priv->watch_dog_wq); + cancel_delayed_work(&priv->update_beacon_wq); + cancel_delayed_work(&priv->ieee80211->hw_wakeup_wq); + cancel_delayed_work(&priv->ieee80211->hw_sleep_wq); + //cancel_work_sync(&priv->SetBWModeWorkItem); + //cancel_work_sync(&priv->SwChnlWorkItem); +#else +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + cancel_delayed_work(&priv->reset_wq); + cancel_delayed_work(&priv->qos_activate); + cancel_delayed_work(&priv->watch_dog_wq); + cancel_delayed_work(&priv->update_beacon_wq); + cancel_delayed_work(&priv->ieee80211->hw_wakeup_wq); + cancel_delayed_work(&priv->ieee80211->hw_sleep_wq); + + //cancel_delayed_work(&priv->SetBWModeWorkItem); + //cancel_delayed_work(&priv->SwChnlWorkItem); +#endif +#endif + +} + + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) +static void __devexit rtl8192_usb_disconnect(struct usb_interface *intf) +#else +static void __devexit rtl8192_usb_disconnect(struct usb_device *udev, void *ptr) +#endif +{ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + struct net_device *dev = usb_get_intfdata(intf); +#else + struct net_device *dev = (struct net_device *)ptr; +#endif + + struct r8192_priv *priv = ieee80211_priv(dev); + if(dev){ + + unregister_netdev(dev); + + RT_TRACE(COMP_DOWN, "=============>wlan driver to be removed\n"); + rtl8192_proc_remove_one(dev); + + rtl8192_down(dev); + if (priv->pFirmware) + { + vfree(priv->pFirmware); + priv->pFirmware = NULL; + } + // priv->rf_close(dev); +// rtl8192_SetRFPowerState(dev, eRfOff); +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) + destroy_workqueue(priv->priv_wq); +#endif + //rtl8192_irq_disable(dev); + //rtl8192_reset(dev); + mdelay(10); + + } + free_ieee80211(dev); + RT_TRACE(COMP_DOWN, "wlan driver removed\n"); +} + +static int __init rtl8192_usb_module_init(void) +{ + printk(KERN_INFO "\nLinux kernel driver for RTL8192 based WLAN cards\n"); + printk(KERN_INFO "Copyright (c) 2007-2008, Realsil Wlan\n"); + RT_TRACE(COMP_INIT, "Initializing module"); + RT_TRACE(COMP_INIT, "Wireless extensions version %d", WIRELESS_EXT); + rtl8192_proc_module_init(); + return usb_register(&rtl8192_usb_driver); +} + + +static void __exit rtl8192_usb_module_exit(void) +{ + usb_deregister(&rtl8192_usb_driver); + + RT_TRACE(COMP_DOWN, "Exiting"); + rtl8192_proc_module_remove(); +} + + +void rtl8192_try_wake_queue(struct net_device *dev, int pri) +{ + unsigned long flags; + short enough_desc; + struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); + + spin_lock_irqsave(&priv->tx_lock,flags); + enough_desc = check_nic_enough_desc(dev,pri); + spin_unlock_irqrestore(&priv->tx_lock,flags); + + if(enough_desc) + ieee80211_wake_queue(priv->ieee80211); +} + +#if 0 +void DisableHWSecurityConfig8192SUsb(struct net_device *dev) +{ + u8 SECR_value = 0x0; + write_nic_byte(dev, SECR, SECR_value);//SECR_value | SCR_UseDK ); +} +#endif + +void EnableHWSecurityConfig8192(struct net_device *dev) +{ + u8 SECR_value = 0x0; + struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); + struct ieee80211_device* ieee = priv->ieee80211; + + SECR_value = SCR_TxEncEnable | SCR_RxDecEnable; +#if 1 + if (((KEY_TYPE_WEP40 == ieee->pairwise_key_type) || (KEY_TYPE_WEP104 == ieee->pairwise_key_type)) && (priv->ieee80211->auth_mode != 2)) + { + SECR_value |= SCR_RxUseDK; + SECR_value |= SCR_TxUseDK; + } + else if ((ieee->iw_mode == IW_MODE_ADHOC) && (ieee->pairwise_key_type & (KEY_TYPE_CCMP | KEY_TYPE_TKIP))) + { + SECR_value |= SCR_RxUseDK; + SECR_value |= SCR_TxUseDK; + } +#endif + //add HWSec active enable here. +//default using hwsec. when peer AP is in N mode only and pairwise_key_type is none_aes(which HT_IOT_ACT_PURE_N_MODE indicates it), use software security. when peer AP is in b,g,n mode mixed and pairwise_key_type is none_aes, use g mode hw security. WB on 2008.7.4 + + ieee->hwsec_active = 1; + + if ((ieee->pHTInfo->IOTAction&HT_IOT_ACT_PURE_N_MODE) || !hwwep)//!ieee->hwsec_support) //add hwsec_support flag to totol control hw_sec on/off + { + ieee->hwsec_active = 0; + SECR_value &= ~SCR_RxDecEnable; + } + + RT_TRACE(COMP_SEC,"%s:, hwsec:%d, pairwise_key:%d, SECR_value:%x\n", __FUNCTION__, \ + ieee->hwsec_active, ieee->pairwise_key_type, SECR_value); + { + write_nic_byte(dev, SECR, SECR_value);//SECR_value | SCR_UseDK ); + } +} + + +void setKey( struct net_device *dev, + u8 EntryNo, + u8 KeyIndex, + u16 KeyType, + u8 *MacAddr, + u8 DefaultKey, + u32 *KeyContent ) +{ + u32 TargetCommand = 0; + u32 TargetContent = 0; + u16 usConfig = 0; + u8 i; + if (EntryNo >= TOTAL_CAM_ENTRY) + RT_TRACE(COMP_ERR, "cam entry exceeds in setKey()\n"); + + RT_TRACE(COMP_SEC, "====>to setKey(), dev:%p, EntryNo:%d, KeyIndex:%d, KeyType:%d, MacAddr"MAC_FMT"\n", dev,EntryNo, KeyIndex, KeyType, MAC_ARG(MacAddr)); + + if (DefaultKey) + usConfig |= BIT15 | (KeyType<<2); + else + usConfig |= BIT15 | (KeyType<<2) | KeyIndex; +// usConfig |= BIT15 | (KeyType<<2) | (DefaultKey<<5) | KeyIndex; + + + for(i=0 ; i= KERNEL_VERSION(2,6,20)) +extern void dm_txpower_trackingcallback(struct work_struct *work); +#else +extern void dm_txpower_trackingcallback(struct net_device *dev); +#endif + +extern void dm_cck_txpower_adjust(struct net_device *dev,bool binch14); +extern void dm_restore_dynamic_mechanism_state(struct net_device *dev); +extern void dm_backup_dynamic_mechanism_state(struct net_device *dev); +extern void dm_change_dynamic_initgain_thresh(struct net_device *dev, + u32 dm_type, + u32 dm_value); +extern void DM_ChangeFsyncSetting(struct net_device *dev, + s32 DM_Type, + s32 DM_Value); +extern void dm_force_tx_fw_info(struct net_device *dev, + u32 force_type, + u32 force_value); +extern void dm_init_edca_turbo(struct net_device *dev); +extern void dm_rf_operation_test_callback(unsigned long data); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) +extern void dm_rf_pathcheck_workitemcallback(struct work_struct *work); +#else +extern void dm_rf_pathcheck_workitemcallback(struct net_device *dev); +#endif +extern void dm_fsync_timer_callback(unsigned long data); +#if 0 +extern bool dm_check_lbus_status(struct net_device *dev); +#endif +extern void dm_check_fsync(struct net_device *dev); +extern void dm_shadow_init(struct net_device *dev); + + +/*--------------------Define export function prototype-----------------------*/ + + +/*---------------------Define local function prototype-----------------------*/ +// DM --> Rate Adaptive +static void dm_check_rate_adaptive(struct net_device *dev); + +// DM --> Bandwidth switch +static void dm_init_bandwidth_autoswitch(struct net_device *dev); +static void dm_bandwidth_autoswitch( struct net_device *dev); + +// DM --> TX power control +//static void dm_initialize_txpower_tracking(struct net_device *dev); + +static void dm_check_txpower_tracking(struct net_device *dev); + + + +//static void dm_txpower_reset_recovery(struct net_device *dev); + + +// DM --> BB init gain restore +#ifndef RTL8192U +static void dm_bb_initialgain_restore(struct net_device *dev); + + +// DM --> BB init gain backup +static void dm_bb_initialgain_backup(struct net_device *dev); +#endif +// DM --> Dynamic Init Gain by RSSI +static void dm_dig_init(struct net_device *dev); +static void dm_ctrl_initgain_byrssi(struct net_device *dev); +static void dm_ctrl_initgain_byrssi_highpwr(struct net_device *dev); +static void dm_ctrl_initgain_byrssi_by_driverrssi( struct net_device *dev); +static void dm_ctrl_initgain_byrssi_by_fwfalse_alarm(struct net_device *dev); +static void dm_initial_gain(struct net_device *dev); +static void dm_pd_th(struct net_device *dev); +static void dm_cs_ratio(struct net_device *dev); + +static void dm_init_ctstoself(struct net_device *dev); +// DM --> EDCA turboe mode control +static void dm_check_edca_turbo(struct net_device *dev); + +// DM --> HW RF control +static void dm_check_rfctrl_gpio(struct net_device *dev); + +#ifndef RTL8190P +//static void dm_gpio_change_rf(struct net_device *dev); +#endif +// DM --> Check PBC +static void dm_check_pbc_gpio(struct net_device *dev); + + +// DM --> Check current RX RF path state +static void dm_check_rx_path_selection(struct net_device *dev); +static void dm_init_rxpath_selection(struct net_device *dev); +static void dm_rxpath_sel_byrssi(struct net_device *dev); + + +// DM --> Fsync for broadcom ap +static void dm_init_fsync(struct net_device *dev); +static void dm_deInit_fsync(struct net_device *dev); + +//Added by vivi, 20080522 +static void dm_check_txrateandretrycount(struct net_device *dev); + +/*---------------------Define local function prototype-----------------------*/ + +/*---------------------Define of Tx Power Control For Near/Far Range --------*/ //Add by Jacken 2008/02/18 +static void dm_init_dynamic_txpower(struct net_device *dev); +static void dm_dynamic_txpower(struct net_device *dev); + + +// DM --> For rate adaptive and DIG, we must send RSSI to firmware +static void dm_send_rssi_tofw(struct net_device *dev); +static void dm_ctstoself(struct net_device *dev); +/*---------------------------Define function prototype------------------------*/ +//================================================================================ +// HW Dynamic mechanism interface. +//================================================================================ +#ifdef RTL8192SU +static void dm_CheckAggrPolicy(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + PRT_HIGH_THROUGHPUT pHTInfo = priv->ieee80211->pHTInfo; + //u8 QueueId; + //PRT_TCB pTcb; + bool bAmsduEnable = false; + + static u8 lastTxOkCnt = 0; + static u8 lastRxOkCnt = 0; + u8 curTxOkCnt = 0; + u8 curRxOkCnt = 0; + + // Determine if A-MSDU policy. + if(priv->ieee80211->pHTInfo->IOTAction & HT_IOT_ACT_HYBRID_AGGREGATION) + { + if(read_nic_byte(dev, INIMCS_SEL) > DESC92S_RATE54M) + bAmsduEnable = true; + } + else if(priv->ieee80211->pHTInfo->IOTAction & HT_IOT_ACT_AMSDU_ENABLE) + { + if(read_nic_byte(dev, INIMCS_SEL) > DESC92S_RATE54M) + { + curTxOkCnt = priv->stats.txbytesunicast - lastTxOkCnt; + curRxOkCnt = priv->stats.rxbytesunicast - lastRxOkCnt; + + if(curRxOkCnt <= 4*curTxOkCnt) + bAmsduEnable = true; + } + } + else + { + // Do not need to switch aggregation policy. + return; + } + + // Switch A-MSDU + if(bAmsduEnable && !pHTInfo->bCurrent_AMSDU_Support) + { + pHTInfo->bCurrent_AMSDU_Support = true; + } + else if(!bAmsduEnable && pHTInfo->bCurrent_AMSDU_Support) + { +#ifdef TO_DO_LIST + //PlatformAcquireSpinLock(Adapter, RT_TX_SPINLOCK); + for(QueueId = 0; QueueId < MAX_TX_QUEUE; QueueId++) + { + while(!RTIsListEmpty(&dev->TcbAggrQueue[QueueId])) + { + pTcb = (PRT_TCB)RTRemoveHeadList(&dev->TcbAggrQueue[QueueId]); + dev->TcbCountInAggrQueue[QueueId]--; + PreTransmitTCB(dev, pTcb); + } + } + //PlatformReleaseSpinLock(Adapter, RT_TX_SPINLOCK); + pHTInfo->bCurrent_AMSDU_Support = false; +#endif + } + + // Determine A-MPDU policy + if(priv->ieee80211->pHTInfo->IOTAction & HT_IOT_ACT_AMSDU_ENABLE) + { + if(!bAmsduEnable) + pHTInfo->bCurrentAMPDUEnable = true; + } + + // Update local static variables. + lastTxOkCnt = priv->stats.txbytesunicast; + lastRxOkCnt = priv->stats.rxbytesunicast; +} +#endif +// +// Description: +// Prepare SW resource for HW dynamic mechanism. +// +// Assumption: +// This function is only invoked at driver intialization once. +// +// +extern void +init_hal_dm(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + + // Undecorated Smoothed Signal Strength, it can utilized to dynamic mechanism. + priv->undecorated_smoothed_pwdb = -1; + + //Initial TX Power Control for near/far range , add by amy 2008/05/15, porting from windows code. + dm_init_dynamic_txpower(dev); + init_rate_adaptive(dev); +#ifdef RTL8192SU + dm_initialize_txpower_tracking(dev); +#else + //dm_initialize_txpower_tracking(dev); +#endif + dm_dig_init(dev); + dm_init_edca_turbo(dev); + dm_init_bandwidth_autoswitch(dev); + dm_init_fsync(dev); + dm_init_rxpath_selection(dev); + dm_init_ctstoself(dev); + +} // InitHalDm + +extern void deinit_hal_dm(struct net_device *dev) +{ + + dm_deInit_fsync(dev); + +} + + +#ifdef USB_RX_AGGREGATION_SUPPORT +void dm_CheckRxAggregation(struct net_device *dev) { + struct r8192_priv *priv = ieee80211_priv((struct net_device *)dev); + PRT_HIGH_THROUGHPUT pHTInfo = priv->ieee80211->pHTInfo; + static unsigned long lastTxOkCnt = 0; + static unsigned long lastRxOkCnt = 0; + unsigned long curTxOkCnt = 0; + unsigned long curRxOkCnt = 0; + +/* + if (pHalData->bForcedUsbRxAggr) { + if (pHalData->ForcedUsbRxAggrInfo == 0) { + if (pHalData->bCurrentRxAggrEnable) { + Adapter->HalFunc.HalUsbRxAggrHandler(Adapter, FALSE); + } + } else { + if (!pHalData->bCurrentRxAggrEnable || (pHalData->ForcedUsbRxAggrInfo != pHalData->LastUsbRxAggrInfoSetting)) { + Adapter->HalFunc.HalUsbRxAggrHandler(Adapter, TRUE); + } + } + return; + } + +*/ +#ifdef RTL8192SU + if (priv->bForcedUsbRxAggr) { + if (priv->ForcedUsbRxAggrInfo == 0) { + if (priv->bCurrentRxAggrEnable) { + //Adapter->HalFunc.HalUsbRxAggrHandler(Adapter, FALSE); + write_nic_dword(dev, 0x1a8, 0); + priv->bCurrentRxAggrEnable = false; + } + } else { + if (!priv->bCurrentRxAggrEnable || (priv->ForcedUsbRxAggrInfo != priv->LastUsbRxAggrInfoSetting)) { + u32 ulValue; + ulValue = (pHTInfo->UsbRxFwAggrEn<<24) | (pHTInfo->UsbRxFwAggrPageNum<<16) | + (pHTInfo->UsbRxFwAggrPacketNum<<8) | (pHTInfo->UsbRxFwAggrTimeout); + /* + * If usb rx firmware aggregation is enabled, + * when anyone of three threshold conditions above is reached, + * firmware will send aggregated packet to driver. + */ + write_nic_dword(dev, 0x1a8, ulValue); + priv->bCurrentRxAggrEnable = true; + } + } + return; + } + + if((priv->ieee80211->mode & WIRELESS_MODE_B) || (priv->ieee80211->mode & WIRELESS_MODE_G)) + { + if (priv->bCurrentRxAggrEnable) + { + RT_TRACE(COMP_RECV, "dm_CheckRxAggregation() : Disable Rx Aggregation!!\n"); + write_nic_dword(dev, 0x1a8, 0); + priv->bCurrentRxAggrEnable = false; + return; + } + } +#endif + + curTxOkCnt = priv->stats.txbytesunicast - lastTxOkCnt; + curRxOkCnt = priv->stats.rxbytesunicast - lastRxOkCnt; + + if((curTxOkCnt + curRxOkCnt) < 15000000) { + return; + } + + if(curTxOkCnt > 4*curRxOkCnt) { + if (priv->bCurrentRxAggrEnable) { + write_nic_dword(dev, 0x1a8, 0); + priv->bCurrentRxAggrEnable = false; + } + }else{ + if (!priv->bCurrentRxAggrEnable && !pHTInfo->bCurrentRT2RTAggregation) { + u32 ulValue; + ulValue = (pHTInfo->UsbRxFwAggrEn<<24) | (pHTInfo->UsbRxFwAggrPageNum<<16) | + (pHTInfo->UsbRxFwAggrPacketNum<<8) | (pHTInfo->UsbRxFwAggrTimeout); + /* + * If usb rx firmware aggregation is enabled, + * when anyone of three threshold conditions above is reached, + * firmware will send aggregated packet to driver. + */ + write_nic_dword(dev, 0x1a8, ulValue); + priv->bCurrentRxAggrEnable = true; + } + } + + lastTxOkCnt = priv->stats.txbytesunicast; + lastRxOkCnt = priv->stats.rxbytesunicast; +} // dm_CheckEdcaTurbo +#endif + + +#ifdef RTL8192SU +//#if 0 +extern void hal_dm_watchdog(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + + if(priv->bInHctTest) + return; + + + dm_check_rfctrl_gpio(dev); + + // Add by hpfan 2008-03-11 + dm_check_pbc_gpio(dev); + dm_check_txrateandretrycount(dev); //moved by tynli + dm_check_edca_turbo(dev); + + dm_CheckAggrPolicy(dev); + +#ifdef TO_DO_LIST + dm_CheckProtection(dev); +#endif + + // ==================================================== + // If any dynamic mechanism is ready, put it above this return; + // ==================================================== + //if (IS_HARDWARE_TYPE_8192S(dev)) + return; + +#ifdef USB_RX_AGGREGATION_SUPPORT + dm_CheckRxAggregation(dev); +#endif +#ifdef TO_DO_LIST + if(Adapter->MgntInfo.mActingAsAp) + { + AP_dm_CheckRateAdaptive(dev); + //return; + } + else +#endif + { + dm_check_rate_adaptive(dev); + } + dm_dynamic_txpower(dev); + + dm_check_txpower_tracking(dev); + dm_ctrl_initgain_byrssi(dev);//LZM TMP 090302 + + dm_bandwidth_autoswitch(dev); + + dm_check_rx_path_selection(dev);//LZM TMP 090302 + dm_check_fsync(dev); + + dm_send_rssi_tofw(dev); + + dm_ctstoself(dev); + +} //HalDmWatchDog +#else +extern void hal_dm_watchdog(struct net_device *dev) +{ + //struct r8192_priv *priv = ieee80211_priv(dev); + + //static u8 previous_bssid[6] ={0}; + + /*Add by amy 2008/05/15 ,porting from windows code.*/ + dm_check_rate_adaptive(dev); + dm_dynamic_txpower(dev); + dm_check_txrateandretrycount(dev); + dm_check_txpower_tracking(dev); + dm_ctrl_initgain_byrssi(dev); + dm_check_edca_turbo(dev); + dm_bandwidth_autoswitch(dev); + dm_check_rfctrl_gpio(dev); + dm_check_rx_path_selection(dev); + dm_check_fsync(dev); + + // Add by amy 2008-05-15 porting from windows code. + dm_check_pbc_gpio(dev); + dm_send_rssi_tofw(dev); + dm_ctstoself(dev); +#ifdef USB_RX_AGGREGATION_SUPPORT + dm_CheckRxAggregation(dev); +#endif +} //HalDmWatchDog +#endif + +/* + * Decide Rate Adaptive Set according to distance (signal strength) + * 01/11/2008 MHC Modify input arguments and RATR table level. + * 01/16/2008 MHC RF_Type is assigned in ReadAdapterInfo(). We must call + * the function after making sure RF_Type. + */ +extern void init_rate_adaptive(struct net_device * dev) +{ + + struct r8192_priv *priv = ieee80211_priv(dev); + prate_adaptive pra = (prate_adaptive)&priv->rate_adaptive; + + pra->ratr_state = DM_RATR_STA_MAX; + pra->high2low_rssi_thresh_for_ra = RateAdaptiveTH_High; + pra->low2high_rssi_thresh_for_ra20M = RateAdaptiveTH_Low_20M+5; + pra->low2high_rssi_thresh_for_ra40M = RateAdaptiveTH_Low_40M+5; + + pra->high_rssi_thresh_for_ra = RateAdaptiveTH_High+5; + pra->low_rssi_thresh_for_ra20M = RateAdaptiveTH_Low_20M; + pra->low_rssi_thresh_for_ra40M = RateAdaptiveTH_Low_40M; + + if(priv->CustomerID == RT_CID_819x_Netcore) + pra->ping_rssi_enable = 1; + else + pra->ping_rssi_enable = 0; + pra->ping_rssi_thresh_for_ra = 15; + + + if (priv->rf_type == RF_2T4R) + { + // 07/10/08 MH Modify for RA smooth scheme. + /* 2008/01/11 MH Modify 2T RATR table for different RSSI. 080515 porting by amy from windows code.*/ + pra->upper_rssi_threshold_ratr = 0x8f0f0000; + pra->middle_rssi_threshold_ratr = 0x8f0ff000; + pra->low_rssi_threshold_ratr = 0x8f0ff001; + pra->low_rssi_threshold_ratr_40M = 0x8f0ff005; + pra->low_rssi_threshold_ratr_20M = 0x8f0ff001; + pra->ping_rssi_ratr = 0x0000000d;//cosa add for test + } + else if (priv->rf_type == RF_1T2R) + { + pra->upper_rssi_threshold_ratr = 0x000f0000; + pra->middle_rssi_threshold_ratr = 0x000ff000; + pra->low_rssi_threshold_ratr = 0x000ff001; + pra->low_rssi_threshold_ratr_40M = 0x000ff005; + pra->low_rssi_threshold_ratr_20M = 0x000ff001; + pra->ping_rssi_ratr = 0x0000000d;//cosa add for test + } + +} // InitRateAdaptive + + +/*----------------------------------------------------------------------------- + * Function: dm_check_rate_adaptive() + * + * Overview: + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 05/26/08 amy Create version 0 proting from windows code. + * + *---------------------------------------------------------------------------*/ +static void dm_check_rate_adaptive(struct net_device * dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + PRT_HIGH_THROUGHPUT pHTInfo = priv->ieee80211->pHTInfo; + prate_adaptive pra = (prate_adaptive)&priv->rate_adaptive; + u32 currentRATR, targetRATR = 0; + u32 LowRSSIThreshForRA = 0, HighRSSIThreshForRA = 0; + bool bshort_gi_enabled = false; + static u8 ping_rssi_state=0; + + + if(!priv->up) + { + RT_TRACE(COMP_RATE, "<---- dm_check_rate_adaptive(): driver is going to unload\n"); + return; + } + + if(pra->rate_adaptive_disabled)//this variable is set by ioctl. + return; + + // TODO: Only 11n mode is implemented currently, + if( !(priv->ieee80211->mode == WIRELESS_MODE_N_24G || + priv->ieee80211->mode == WIRELESS_MODE_N_5G)) + return; + + if( priv->ieee80211->state == IEEE80211_LINKED ) + { + // RT_TRACE(COMP_RATE, "dm_CheckRateAdaptive(): \t"); + + // + // Check whether Short GI is enabled + // + bshort_gi_enabled = (pHTInfo->bCurTxBW40MHz && pHTInfo->bCurShortGI40MHz) || + (!pHTInfo->bCurTxBW40MHz && pHTInfo->bCurShortGI20MHz); + + + pra->upper_rssi_threshold_ratr = + (pra->upper_rssi_threshold_ratr & (~BIT31)) | ((bshort_gi_enabled)? BIT31:0) ; + + pra->middle_rssi_threshold_ratr = + (pra->middle_rssi_threshold_ratr & (~BIT31)) | ((bshort_gi_enabled)? BIT31:0) ; + + if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) + { + pra->low_rssi_threshold_ratr = + (pra->low_rssi_threshold_ratr_40M & (~BIT31)) | ((bshort_gi_enabled)? BIT31:0) ; + } + else + { + pra->low_rssi_threshold_ratr = + (pra->low_rssi_threshold_ratr_20M & (~BIT31)) | ((bshort_gi_enabled)? BIT31:0) ; + } + //cosa add for test + pra->ping_rssi_ratr = + (pra->ping_rssi_ratr & (~BIT31)) | ((bshort_gi_enabled)? BIT31:0) ; + + /* 2007/10/08 MH We support RA smooth scheme now. When it is the first + time to link with AP. We will not change upper/lower threshold. If + STA stay in high or low level, we must change two different threshold + to prevent jumping frequently. */ + if (pra->ratr_state == DM_RATR_STA_HIGH) + { + HighRSSIThreshForRA = pra->high2low_rssi_thresh_for_ra; + LowRSSIThreshForRA = (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20)? + (pra->low_rssi_thresh_for_ra40M):(pra->low_rssi_thresh_for_ra20M); + } + else if (pra->ratr_state == DM_RATR_STA_LOW) + { + HighRSSIThreshForRA = pra->high_rssi_thresh_for_ra; + LowRSSIThreshForRA = (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20)? + (pra->low2high_rssi_thresh_for_ra40M):(pra->low2high_rssi_thresh_for_ra20M); + } + else + { + HighRSSIThreshForRA = pra->high_rssi_thresh_for_ra; + LowRSSIThreshForRA = (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20)? + (pra->low_rssi_thresh_for_ra40M):(pra->low_rssi_thresh_for_ra20M); + } + + //DbgPrint("[DM] THresh H/L=%d/%d\n\r", RATR.HighRSSIThreshForRA, RATR.LowRSSIThreshForRA); + if(priv->undecorated_smoothed_pwdb >= (long)HighRSSIThreshForRA) + { + //DbgPrint("[DM] RSSI=%d STA=HIGH\n\r", pHalData->UndecoratedSmoothedPWDB); + pra->ratr_state = DM_RATR_STA_HIGH; + targetRATR = pra->upper_rssi_threshold_ratr; + }else if(priv->undecorated_smoothed_pwdb >= (long)LowRSSIThreshForRA) + { + //DbgPrint("[DM] RSSI=%d STA=Middle\n\r", pHalData->UndecoratedSmoothedPWDB); + pra->ratr_state = DM_RATR_STA_MIDDLE; + targetRATR = pra->middle_rssi_threshold_ratr; + }else + { + //DbgPrint("[DM] RSSI=%d STA=LOW\n\r", pHalData->UndecoratedSmoothedPWDB); + pra->ratr_state = DM_RATR_STA_LOW; + targetRATR = pra->low_rssi_threshold_ratr; + } + + //cosa add for test + if(pra->ping_rssi_enable) + { + //pHalData->UndecoratedSmoothedPWDB = 19; + if(priv->undecorated_smoothed_pwdb < (long)(pra->ping_rssi_thresh_for_ra+5)) + { + if( (priv->undecorated_smoothed_pwdb < (long)pra->ping_rssi_thresh_for_ra) || + ping_rssi_state ) + { + //DbgPrint("TestRSSI = %d, set RATR to 0x%x \n", pHalData->UndecoratedSmoothedPWDB, pRA->TestRSSIRATR); + pra->ratr_state = DM_RATR_STA_LOW; + targetRATR = pra->ping_rssi_ratr; + ping_rssi_state = 1; + } + //else + // DbgPrint("TestRSSI is between the range. \n"); + } + else + { + //DbgPrint("TestRSSI Recover to 0x%x \n", targetRATR); + ping_rssi_state = 0; + } + } + + // 2008.04.01 +#if 1 + // For RTL819X, if pairwisekey = wep/tkip, we support only MCS0~7. + if(priv->ieee80211->GetHalfNmodeSupportByAPsHandler(dev)) + targetRATR &= 0xf00fffff; +#endif + + // + // Check whether updating of RATR0 is required + // + currentRATR = read_nic_dword(dev, RATR0); + if( targetRATR != currentRATR ) + { + u32 ratr_value; + ratr_value = targetRATR; + RT_TRACE(COMP_RATE,"currentRATR = %x, targetRATR = %x\n", currentRATR, targetRATR); + if(priv->rf_type == RF_1T2R) + { + ratr_value &= ~(RATE_ALL_OFDM_2SS); + } + write_nic_dword(dev, RATR0, ratr_value); + write_nic_byte(dev, UFWP, 1); + + pra->last_ratr = targetRATR; + } + + } + else + { + pra->ratr_state = DM_RATR_STA_MAX; + } + +} // dm_CheckRateAdaptive + + +static void dm_init_bandwidth_autoswitch(struct net_device * dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + + priv->ieee80211->bandwidth_auto_switch.threshold_20Mhzto40Mhz = BW_AUTO_SWITCH_LOW_HIGH; + priv->ieee80211->bandwidth_auto_switch.threshold_40Mhzto20Mhz = BW_AUTO_SWITCH_HIGH_LOW; + priv->ieee80211->bandwidth_auto_switch.bforced_tx20Mhz = false; + priv->ieee80211->bandwidth_auto_switch.bautoswitch_enable = false; + +} // dm_init_bandwidth_autoswitch + + +static void dm_bandwidth_autoswitch(struct net_device * dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + + if(priv->CurrentChannelBW == HT_CHANNEL_WIDTH_20 ||!priv->ieee80211->bandwidth_auto_switch.bautoswitch_enable){ + return; + }else{ + if(priv->ieee80211->bandwidth_auto_switch.bforced_tx20Mhz == false){//If send packets in 40 Mhz in 20/40 + if(priv->undecorated_smoothed_pwdb <= priv->ieee80211->bandwidth_auto_switch.threshold_40Mhzto20Mhz) + priv->ieee80211->bandwidth_auto_switch.bforced_tx20Mhz = true; + }else{//in force send packets in 20 Mhz in 20/40 + if(priv->undecorated_smoothed_pwdb >= priv->ieee80211->bandwidth_auto_switch.threshold_20Mhzto40Mhz) + priv->ieee80211->bandwidth_auto_switch.bforced_tx20Mhz = false; + + } + } +} // dm_BandwidthAutoSwitch + +//OFDM default at 0db, index=6. +static u32 OFDMSwingTable[OFDM_Table_Length] = { + 0x7f8001fe, // 0, +6db + 0x71c001c7, // 1, +5db + 0x65400195, // 2, +4db + 0x5a400169, // 3, +3db + 0x50800142, // 4, +2db + 0x47c0011f, // 5, +1db + 0x40000100, // 6, +0db ===> default, upper for higher temprature, lower for low temprature + 0x390000e4, // 7, -1db + 0x32c000cb, // 8, -2db + 0x2d4000b5, // 9, -3db + 0x288000a2, // 10, -4db + 0x24000090, // 11, -5db + 0x20000080, // 12, -6db + 0x1c800072, // 13, -7db + 0x19800066, // 14, -8db + 0x26c0005b, // 15, -9db + 0x24400051, // 16, -10db + 0x12000048, // 17, -11db + 0x10000040 // 18, -12db +}; + +static u8 CCKSwingTable_Ch1_Ch13[CCK_Table_length][8] = { + {0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04}, // 0, +0db ===> CCK40M default + {0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03}, // 1, -1db + {0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03}, // 2, -2db + {0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03}, // 3, -3db + {0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02}, // 4, -4db + {0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02}, // 5, -5db + {0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02}, // 6, -6db ===> CCK20M default + {0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02}, // 7, -7db + {0x16, 0x15, 0x12, 0x0f, 0x0b, 0x07, 0x04, 0x01}, // 8, -8db + {0x13, 0x13, 0x10, 0x0d, 0x0a, 0x06, 0x03, 0x01}, // 9, -9db + {0x11, 0x11, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, // 10, -10db + {0x0f, 0x0f, 0x0d, 0x0b, 0x08, 0x05, 0x03, 0x01} // 11, -11db +}; + +static u8 CCKSwingTable_Ch14[CCK_Table_length][8] = { + {0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00}, // 0, +0db ===> CCK40M default + {0x30, 0x2f, 0x29, 0x18, 0x00, 0x00, 0x00, 0x00}, // 1, -1db + {0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00}, // 2, -2db + {0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00}, // 3, -3db + {0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00}, // 4, -4db + {0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00}, // 5, -5db + {0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00}, // 6, -6db ===> CCK20M default + {0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00}, // 7, -7db + {0x16, 0x15, 0x12, 0x0b, 0x00, 0x00, 0x00, 0x00}, // 8, -8db + {0x13, 0x13, 0x10, 0x0a, 0x00, 0x00, 0x00, 0x00}, // 9, -9db + {0x11, 0x11, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, // 10, -10db + {0x0f, 0x0f, 0x0d, 0x08, 0x00, 0x00, 0x00, 0x00} // 11, -11db +}; + +static void dm_TXPowerTrackingCallback_TSSI(struct net_device * dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + bool bHighpowerstate, viviflag = FALSE; + DCMD_TXCMD_T tx_cmd; + u8 powerlevelOFDM24G; + int i =0, j = 0, k = 0; + u8 RF_Type, tmp_report[5]={0, 0, 0, 0, 0}; + u32 Value; + u8 Pwr_Flag; + u16 Avg_TSSI_Meas, TSSI_13dBm, Avg_TSSI_Meas_from_driver=0; + //RT_STATUS rtStatus = RT_STATUS_SUCCESS; +#ifdef RTL8192U + bool rtStatus = true; +#endif + u32 delta=0; + + write_nic_byte(dev, 0x1ba, 0); + + priv->ieee80211->bdynamic_txpower_enable = false; + bHighpowerstate = priv->bDynamicTxHighPower; + + powerlevelOFDM24G = (u8)(priv->Pwr_Track>>24); + RF_Type = priv->rf_type; + Value = (RF_Type<<8) | powerlevelOFDM24G; + + RT_TRACE(COMP_POWER_TRACKING, "powerlevelOFDM24G = %x\n", powerlevelOFDM24G); + + for(j = 0; j<=30; j++) +{ //fill tx_cmd + + tx_cmd.Op = TXCMD_SET_TX_PWR_TRACKING; + tx_cmd.Length = 4; + tx_cmd.Value = Value; +#ifdef RTL8192U + rtStatus = SendTxCommandPacket(dev, &tx_cmd, 12); + if (rtStatus == false) + { + RT_TRACE(COMP_POWER_TRACKING, "Set configuration with tx cmd queue fail!\n"); + } +#else + cmpk_message_handle_tx(dev, (u8*)&tx_cmd, + DESC_PACKET_TYPE_INIT, sizeof(DCMD_TXCMD_T)); +#endif + mdelay(1); + //DbgPrint("hi, vivi, strange\n"); + for(i = 0;i <= 30; i++) + { + Pwr_Flag = read_nic_byte(dev, 0x1ba); + + if (Pwr_Flag == 0) + { + mdelay(1); + continue; + } +#ifdef RTL8190P + Avg_TSSI_Meas = read_nic_word(dev, 0x1bc); +#else + Avg_TSSI_Meas = read_nic_word(dev, 0x13c); +#endif + if(Avg_TSSI_Meas == 0) + { + write_nic_byte(dev, 0x1ba, 0); + break; + } + + for(k = 0;k < 5; k++) + { +#ifdef RTL8190P + tmp_report[k] = read_nic_byte(dev, 0x1d8+k); +#else + if(k !=4) + tmp_report[k] = read_nic_byte(dev, 0x134+k); + else + tmp_report[k] = read_nic_byte(dev, 0x13e); +#endif + RT_TRACE(COMP_POWER_TRACKING, "TSSI_report_value = %d\n", tmp_report[k]); + } + + //check if the report value is right + for(k = 0;k < 5; k++) + { + if(tmp_report[k] <= 20) + { + viviflag =TRUE; + break; + } + } + if(viviflag ==TRUE) + { + write_nic_byte(dev, 0x1ba, 0); + viviflag = FALSE; + RT_TRACE(COMP_POWER_TRACKING, "we filted this data\n"); + for(k = 0;k < 5; k++) + tmp_report[k] = 0; + break; + } + + for(k = 0;k < 5; k++) + { + Avg_TSSI_Meas_from_driver += tmp_report[k]; + } + + Avg_TSSI_Meas_from_driver = Avg_TSSI_Meas_from_driver*100/5; + RT_TRACE(COMP_POWER_TRACKING, "Avg_TSSI_Meas_from_driver = %d\n", Avg_TSSI_Meas_from_driver); + TSSI_13dBm = priv->TSSI_13dBm; + RT_TRACE(COMP_POWER_TRACKING, "TSSI_13dBm = %d\n", TSSI_13dBm); + + //if(abs(Avg_TSSI_Meas_from_driver - TSSI_13dBm) <= E_FOR_TX_POWER_TRACK) + // For MacOS-compatible + if(Avg_TSSI_Meas_from_driver > TSSI_13dBm) + delta = Avg_TSSI_Meas_from_driver - TSSI_13dBm; + else + delta = TSSI_13dBm - Avg_TSSI_Meas_from_driver; + + if(delta <= E_FOR_TX_POWER_TRACK) + { + priv->ieee80211->bdynamic_txpower_enable = TRUE; + write_nic_byte(dev, 0x1ba, 0); + RT_TRACE(COMP_POWER_TRACKING, "tx power track is done\n"); + RT_TRACE(COMP_POWER_TRACKING, "priv->rfa_txpowertrackingindex = %d\n", priv->rfa_txpowertrackingindex); + RT_TRACE(COMP_POWER_TRACKING, "priv->rfa_txpowertrackingindex_real = %d\n", priv->rfa_txpowertrackingindex_real); +#ifdef RTL8190P + RT_TRACE(COMP_POWER_TRACKING, "priv->rfc_txpowertrackingindex = %d\n", priv->rfc_txpowertrackingindex); + RT_TRACE(COMP_POWER_TRACKING, "priv->rfc_txpowertrackingindex_real = %d\n", priv->rfc_txpowertrackingindex_real); +#endif + RT_TRACE(COMP_POWER_TRACKING, "priv->cck_present_attentuation_difference = %d\n", priv->cck_present_attentuation_difference); + RT_TRACE(COMP_POWER_TRACKING, "priv->cck_present_attentuation = %d\n", priv->cck_present_attentuation); + return; + } + else + { + if(Avg_TSSI_Meas_from_driver < TSSI_13dBm - E_FOR_TX_POWER_TRACK) + { + if((priv->rfa_txpowertrackingindex > 0) +#ifdef RTL8190P + &&(priv->rfc_txpowertrackingindex > 0) +#endif + ) + { + priv->rfa_txpowertrackingindex--; + if(priv->rfa_txpowertrackingindex_real > 4) + { + priv->rfa_txpowertrackingindex_real--; + rtl8192_setBBreg(dev, rOFDM0_XATxIQImbalance, bMaskDWord, priv->txbbgain_table[priv->rfa_txpowertrackingindex_real].txbbgain_value); + } +#ifdef RTL8190P + priv->rfc_txpowertrackingindex--; + if(priv->rfc_txpowertrackingindex_real > 4) + { + priv->rfc_txpowertrackingindex_real--; + rtl8192_setBBreg(dev, rOFDM0_XCTxIQImbalance, bMaskDWord, priv->txbbgain_table[priv->rfc_txpowertrackingindex_real].txbbgain_value); + } +#endif + } + } + else + { + if((priv->rfa_txpowertrackingindex < 36) +#ifdef RTL8190P + &&(priv->rfc_txpowertrackingindex < 36) +#endif + ) + { + priv->rfa_txpowertrackingindex++; + priv->rfa_txpowertrackingindex_real++; + rtl8192_setBBreg(dev, rOFDM0_XATxIQImbalance, bMaskDWord, priv->txbbgain_table[priv->rfa_txpowertrackingindex_real].txbbgain_value); + +#ifdef RTL8190P + priv->rfc_txpowertrackingindex++; + priv->rfc_txpowertrackingindex_real++; + rtl8192_setBBreg(dev, rOFDM0_XCTxIQImbalance, bMaskDWord, priv->txbbgain_table[priv->rfc_txpowertrackingindex_real].txbbgain_value); +#endif + } + } + priv->cck_present_attentuation_difference + = priv->rfa_txpowertrackingindex - priv->rfa_txpowertracking_default; + + if(priv->CurrentChannelBW == HT_CHANNEL_WIDTH_20) + priv->cck_present_attentuation + = priv->cck_present_attentuation_20Mdefault + priv->cck_present_attentuation_difference; + else + priv->cck_present_attentuation + = priv->cck_present_attentuation_40Mdefault + priv->cck_present_attentuation_difference; + + if(priv->cck_present_attentuation > -1&&priv->cck_present_attentuation <23) + { + if(priv->ieee80211->current_network.channel == 14 && !priv->bcck_in_ch14) + { + priv->bcck_in_ch14 = TRUE; + dm_cck_txpower_adjust(dev,priv->bcck_in_ch14); + } + else if(priv->ieee80211->current_network.channel != 14 && priv->bcck_in_ch14) + { + priv->bcck_in_ch14 = FALSE; + dm_cck_txpower_adjust(dev,priv->bcck_in_ch14); + } + else + dm_cck_txpower_adjust(dev,priv->bcck_in_ch14); + } + RT_TRACE(COMP_POWER_TRACKING, "priv->rfa_txpowertrackingindex = %d\n", priv->rfa_txpowertrackingindex); + RT_TRACE(COMP_POWER_TRACKING, "priv->rfa_txpowertrackingindex_real = %d\n", priv->rfa_txpowertrackingindex_real); +#ifdef RTL8190P + RT_TRACE(COMP_POWER_TRACKING, "priv->rfc_txpowertrackingindex = %d\n", priv->rfc_txpowertrackingindex); + RT_TRACE(COMP_POWER_TRACKING, "priv->rfc_txpowertrackingindex_real = %d\n", priv->rfc_txpowertrackingindex_real); +#endif + RT_TRACE(COMP_POWER_TRACKING, "priv->cck_present_attentuation_difference = %d\n", priv->cck_present_attentuation_difference); + RT_TRACE(COMP_POWER_TRACKING, "priv->cck_present_attentuation = %d\n", priv->cck_present_attentuation); + + if (priv->cck_present_attentuation_difference <= -12||priv->cck_present_attentuation_difference >= 24) + { + priv->ieee80211->bdynamic_txpower_enable = TRUE; + write_nic_byte(dev, 0x1ba, 0); + RT_TRACE(COMP_POWER_TRACKING, "tx power track--->limited\n"); + return; + } + + + } + write_nic_byte(dev, 0x1ba, 0); + Avg_TSSI_Meas_from_driver = 0; + for(k = 0;k < 5; k++) + tmp_report[k] = 0; + break; + } +} + priv->ieee80211->bdynamic_txpower_enable = TRUE; + write_nic_byte(dev, 0x1ba, 0); +} + +static void dm_TXPowerTrackingCallback_ThermalMeter(struct net_device * dev) +{ +#define ThermalMeterVal 9 + struct r8192_priv *priv = ieee80211_priv(dev); + u32 tmpRegA, TempCCk; + u8 tmpOFDMindex, tmpCCKindex, tmpCCK20Mindex, tmpCCK40Mindex, tmpval; + int i =0, CCKSwingNeedUpdate=0; + + if(!priv->btxpower_trackingInit) + { + //Query OFDM default setting + tmpRegA= rtl8192_QueryBBReg(dev, rOFDM0_XATxIQImbalance, bMaskDWord); + for(i=0; iOFDM_index= (u8)i; + RT_TRACE(COMP_POWER_TRACKING, "Initial reg0x%x = 0x%x, OFDM_index=0x%x\n", + rOFDM0_XATxIQImbalance, tmpRegA, priv->OFDM_index); + } + } + + //Query CCK default setting From 0xa22 + TempCCk = rtl8192_QueryBBReg(dev, rCCK0_TxFilter1, bMaskByte2); + for(i=0 ; iCCK_index =(u8) i; + RT_TRACE(COMP_POWER_TRACKING, "Initial reg0x%x = 0x%x, CCK_index=0x%x\n", + rCCK0_TxFilter1, TempCCk, priv->CCK_index); + break; + } + } + priv->btxpower_trackingInit = TRUE; + //pHalData->TXPowercount = 0; + return; + } + + //========================== + // this is only for test, should be masked +#if 0 +{ + //UINT32 eRFPath; + //UINT32 start_rf, end_rf; + UINT32 curr_addr; + //UINT32 reg_addr; + //UINT32 reg_addr_end; + UINT32 reg_value; + //start_rf = RF90_PATH_A; + //end_rf = RF90_PATH_B;//RF90_PATH_MAX; + //reg_addr = 0x0; + //reg_addr_end = 0x2F; + + for (curr_addr = 0; curr_addr < 0x2d; curr_addr++) + { + reg_value = PHY_QueryRFReg( Adapter, (RF90_RADIO_PATH_E)RF90_PATH_A, + curr_addr, bMaskDWord); + } + + pHalData->TXPowercount = 0; + return; +} +#endif + //========================== + + // read and filter out unreasonable value + tmpRegA = rtl8192_phy_QueryRFReg(dev, RF90_PATH_A, 0x12, 0x078); // 0x12: RF Reg[10:7] + RT_TRACE(COMP_POWER_TRACKING, "Readback ThermalMeterA = %d \n", tmpRegA); + if(tmpRegA < 3 || tmpRegA > 13) + return; + if(tmpRegA >= 12) // if over 12, TP will be bad when high temprature + tmpRegA = 12; + RT_TRACE(COMP_POWER_TRACKING, "Valid ThermalMeterA = %d \n", tmpRegA); + priv->ThermalMeter[0] = ThermalMeterVal; //We use fixed value by Bryant's suggestion + priv->ThermalMeter[1] = ThermalMeterVal; //We use fixed value by Bryant's suggestion + + //Get current RF-A temprature index + if(priv->ThermalMeter[0] >= (u8)tmpRegA) //lower temprature + { + tmpOFDMindex = tmpCCK20Mindex = 6+(priv->ThermalMeter[0]-(u8)tmpRegA); + tmpCCK40Mindex = tmpCCK20Mindex - 6; + if(tmpOFDMindex >= OFDM_Table_Length) + tmpOFDMindex = OFDM_Table_Length-1; + if(tmpCCK20Mindex >= CCK_Table_length) + tmpCCK20Mindex = CCK_Table_length-1; + if(tmpCCK40Mindex >= CCK_Table_length) + tmpCCK40Mindex = CCK_Table_length-1; + } + else + { + tmpval = ((u8)tmpRegA - priv->ThermalMeter[0]); + if(tmpval >= 6) // higher temprature + tmpOFDMindex = tmpCCK20Mindex = 0; // max to +6dB + else + tmpOFDMindex = tmpCCK20Mindex = 6 - tmpval; + tmpCCK40Mindex = 0; + } + //DbgPrint("%ddb, tmpOFDMindex = %d, tmpCCK20Mindex = %d, tmpCCK40Mindex = %d", + //((u1Byte)tmpRegA - pHalData->ThermalMeter[0]), + //tmpOFDMindex, tmpCCK20Mindex, tmpCCK40Mindex); + if(priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) //40M + tmpCCKindex = tmpCCK40Mindex; + else + tmpCCKindex = tmpCCK20Mindex; + + if(priv->ieee80211->current_network.channel == 14 && !priv->bcck_in_ch14) + { + priv->bcck_in_ch14 = TRUE; + CCKSwingNeedUpdate = 1; + } + else if(priv->ieee80211->current_network.channel != 14 && priv->bcck_in_ch14) + { + priv->bcck_in_ch14 = FALSE; + CCKSwingNeedUpdate = 1; + } + + if(priv->CCK_index != tmpCCKindex) + { + priv->CCK_index = tmpCCKindex; + CCKSwingNeedUpdate = 1; + } + + if(CCKSwingNeedUpdate) + { + //DbgPrint("Update CCK Swing, CCK_index = %d\n", pHalData->CCK_index); + dm_cck_txpower_adjust(dev, priv->bcck_in_ch14); + } + if(priv->OFDM_index != tmpOFDMindex) + { + priv->OFDM_index = tmpOFDMindex; + rtl8192_setBBreg(dev, rOFDM0_XATxIQImbalance, bMaskDWord, OFDMSwingTable[priv->OFDM_index]); + RT_TRACE(COMP_POWER_TRACKING, "Update OFDMSwing[%d] = 0x%x\n", + priv->OFDM_index, OFDMSwingTable[priv->OFDM_index]); + } + priv->txpower_count = 0; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) +extern void dm_txpower_trackingcallback(struct work_struct *work) +{ + struct delayed_work *dwork = container_of(work,struct delayed_work,work); + struct r8192_priv *priv = container_of(dwork,struct r8192_priv,txpower_tracking_wq); + struct net_device *dev = priv->ieee80211->dev; +#else +extern void dm_txpower_trackingcallback(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); +#endif + +#ifdef RTL8190P + dm_TXPowerTrackingCallback_TSSI(dev); +#else + if(priv->bDcut == TRUE) + dm_TXPowerTrackingCallback_TSSI(dev); + else + dm_TXPowerTrackingCallback_ThermalMeter(dev); +#endif +} + + +static void dm_InitializeTXPowerTracking_TSSI(struct net_device *dev) +{ + + struct r8192_priv *priv = ieee80211_priv(dev); + + //Initial the Tx BB index and mapping value + priv->txbbgain_table[0].txbb_iq_amplifygain = 12; + priv->txbbgain_table[0].txbbgain_value=0x7f8001fe; + priv->txbbgain_table[1].txbb_iq_amplifygain = 11; + priv->txbbgain_table[1].txbbgain_value=0x788001e2; + priv->txbbgain_table[2].txbb_iq_amplifygain = 10; + priv->txbbgain_table[2].txbbgain_value=0x71c001c7; + priv->txbbgain_table[3].txbb_iq_amplifygain = 9; + priv->txbbgain_table[3].txbbgain_value=0x6b8001ae; + priv->txbbgain_table[4].txbb_iq_amplifygain = 8; + priv->txbbgain_table[4].txbbgain_value=0x65400195; + priv->txbbgain_table[5].txbb_iq_amplifygain = 7; + priv->txbbgain_table[5].txbbgain_value=0x5fc0017f; + priv->txbbgain_table[6].txbb_iq_amplifygain = 6; + priv->txbbgain_table[6].txbbgain_value=0x5a400169; + priv->txbbgain_table[7].txbb_iq_amplifygain = 5; + priv->txbbgain_table[7].txbbgain_value=0x55400155; + priv->txbbgain_table[8].txbb_iq_amplifygain = 4; + priv->txbbgain_table[8].txbbgain_value=0x50800142; + priv->txbbgain_table[9].txbb_iq_amplifygain = 3; + priv->txbbgain_table[9].txbbgain_value=0x4c000130; + priv->txbbgain_table[10].txbb_iq_amplifygain = 2; + priv->txbbgain_table[10].txbbgain_value=0x47c0011f; + priv->txbbgain_table[11].txbb_iq_amplifygain = 1; + priv->txbbgain_table[11].txbbgain_value=0x43c0010f; + priv->txbbgain_table[12].txbb_iq_amplifygain = 0; + priv->txbbgain_table[12].txbbgain_value=0x40000100; + priv->txbbgain_table[13].txbb_iq_amplifygain = -1; + priv->txbbgain_table[13].txbbgain_value=0x3c8000f2; + priv->txbbgain_table[14].txbb_iq_amplifygain = -2; + priv->txbbgain_table[14].txbbgain_value=0x390000e4; + priv->txbbgain_table[15].txbb_iq_amplifygain = -3; + priv->txbbgain_table[15].txbbgain_value=0x35c000d7; + priv->txbbgain_table[16].txbb_iq_amplifygain = -4; + priv->txbbgain_table[16].txbbgain_value=0x32c000cb; + priv->txbbgain_table[17].txbb_iq_amplifygain = -5; + priv->txbbgain_table[17].txbbgain_value=0x300000c0; + priv->txbbgain_table[18].txbb_iq_amplifygain = -6; + priv->txbbgain_table[18].txbbgain_value=0x2d4000b5; + priv->txbbgain_table[19].txbb_iq_amplifygain = -7; + priv->txbbgain_table[19].txbbgain_value=0x2ac000ab; + priv->txbbgain_table[20].txbb_iq_amplifygain = -8; + priv->txbbgain_table[20].txbbgain_value=0x288000a2; + priv->txbbgain_table[21].txbb_iq_amplifygain = -9; + priv->txbbgain_table[21].txbbgain_value=0x26000098; + priv->txbbgain_table[22].txbb_iq_amplifygain = -10; + priv->txbbgain_table[22].txbbgain_value=0x24000090; + priv->txbbgain_table[23].txbb_iq_amplifygain = -11; + priv->txbbgain_table[23].txbbgain_value=0x22000088; + priv->txbbgain_table[24].txbb_iq_amplifygain = -12; + priv->txbbgain_table[24].txbbgain_value=0x20000080; + priv->txbbgain_table[25].txbb_iq_amplifygain = -13; + priv->txbbgain_table[25].txbbgain_value=0x1a00006c; + priv->txbbgain_table[26].txbb_iq_amplifygain = -14; + priv->txbbgain_table[26].txbbgain_value=0x1c800072; + priv->txbbgain_table[27].txbb_iq_amplifygain = -15; + priv->txbbgain_table[27].txbbgain_value=0x18000060; + priv->txbbgain_table[28].txbb_iq_amplifygain = -16; + priv->txbbgain_table[28].txbbgain_value=0x19800066; + priv->txbbgain_table[29].txbb_iq_amplifygain = -17; + priv->txbbgain_table[29].txbbgain_value=0x15800056; + priv->txbbgain_table[30].txbb_iq_amplifygain = -18; + priv->txbbgain_table[30].txbbgain_value=0x26c0005b; + priv->txbbgain_table[31].txbb_iq_amplifygain = -19; + priv->txbbgain_table[31].txbbgain_value=0x14400051; + priv->txbbgain_table[32].txbb_iq_amplifygain = -20; + priv->txbbgain_table[32].txbbgain_value=0x24400051; + priv->txbbgain_table[33].txbb_iq_amplifygain = -21; + priv->txbbgain_table[33].txbbgain_value=0x1300004c; + priv->txbbgain_table[34].txbb_iq_amplifygain = -22; + priv->txbbgain_table[34].txbbgain_value=0x12000048; + priv->txbbgain_table[35].txbb_iq_amplifygain = -23; + priv->txbbgain_table[35].txbbgain_value=0x11000044; + priv->txbbgain_table[36].txbb_iq_amplifygain = -24; + priv->txbbgain_table[36].txbbgain_value=0x10000040; + + //ccktxbb_valuearray[0] is 0xA22 [1] is 0xA24 ...[7] is 0xA29 + //This Table is for CH1~CH13 + priv->cck_txbbgain_table[0].ccktxbb_valuearray[0] = 0x36; + priv->cck_txbbgain_table[0].ccktxbb_valuearray[1] = 0x35; + priv->cck_txbbgain_table[0].ccktxbb_valuearray[2] = 0x2e; + priv->cck_txbbgain_table[0].ccktxbb_valuearray[3] = 0x25; + priv->cck_txbbgain_table[0].ccktxbb_valuearray[4] = 0x1c; + priv->cck_txbbgain_table[0].ccktxbb_valuearray[5] = 0x12; + priv->cck_txbbgain_table[0].ccktxbb_valuearray[6] = 0x09; + priv->cck_txbbgain_table[0].ccktxbb_valuearray[7] = 0x04; + + priv->cck_txbbgain_table[1].ccktxbb_valuearray[0] = 0x33; + priv->cck_txbbgain_table[1].ccktxbb_valuearray[1] = 0x32; + priv->cck_txbbgain_table[1].ccktxbb_valuearray[2] = 0x2b; + priv->cck_txbbgain_table[1].ccktxbb_valuearray[3] = 0x23; + priv->cck_txbbgain_table[1].ccktxbb_valuearray[4] = 0x1a; + priv->cck_txbbgain_table[1].ccktxbb_valuearray[5] = 0x11; + priv->cck_txbbgain_table[1].ccktxbb_valuearray[6] = 0x08; + priv->cck_txbbgain_table[1].ccktxbb_valuearray[7] = 0x04; + + priv->cck_txbbgain_table[2].ccktxbb_valuearray[0] = 0x30; + priv->cck_txbbgain_table[2].ccktxbb_valuearray[1] = 0x2f; + priv->cck_txbbgain_table[2].ccktxbb_valuearray[2] = 0x29; + priv->cck_txbbgain_table[2].ccktxbb_valuearray[3] = 0x21; + priv->cck_txbbgain_table[2].ccktxbb_valuearray[4] = 0x19; + priv->cck_txbbgain_table[2].ccktxbb_valuearray[5] = 0x10; + priv->cck_txbbgain_table[2].ccktxbb_valuearray[6] = 0x08; + priv->cck_txbbgain_table[2].ccktxbb_valuearray[7] = 0x03; + + priv->cck_txbbgain_table[3].ccktxbb_valuearray[0] = 0x2d; + priv->cck_txbbgain_table[3].ccktxbb_valuearray[1] = 0x2d; + priv->cck_txbbgain_table[3].ccktxbb_valuearray[2] = 0x27; + priv->cck_txbbgain_table[3].ccktxbb_valuearray[3] = 0x1f; + priv->cck_txbbgain_table[3].ccktxbb_valuearray[4] = 0x18; + priv->cck_txbbgain_table[3].ccktxbb_valuearray[5] = 0x0f; + priv->cck_txbbgain_table[3].ccktxbb_valuearray[6] = 0x08; + priv->cck_txbbgain_table[3].ccktxbb_valuearray[7] = 0x03; + + priv->cck_txbbgain_table[4].ccktxbb_valuearray[0] = 0x2b; + priv->cck_txbbgain_table[4].ccktxbb_valuearray[1] = 0x2a; + priv->cck_txbbgain_table[4].ccktxbb_valuearray[2] = 0x25; + priv->cck_txbbgain_table[4].ccktxbb_valuearray[3] = 0x1e; + priv->cck_txbbgain_table[4].ccktxbb_valuearray[4] = 0x16; + priv->cck_txbbgain_table[4].ccktxbb_valuearray[5] = 0x0e; + priv->cck_txbbgain_table[4].ccktxbb_valuearray[6] = 0x07; + priv->cck_txbbgain_table[4].ccktxbb_valuearray[7] = 0x03; + + priv->cck_txbbgain_table[5].ccktxbb_valuearray[0] = 0x28; + priv->cck_txbbgain_table[5].ccktxbb_valuearray[1] = 0x28; + priv->cck_txbbgain_table[5].ccktxbb_valuearray[2] = 0x22; + priv->cck_txbbgain_table[5].ccktxbb_valuearray[3] = 0x1c; + priv->cck_txbbgain_table[5].ccktxbb_valuearray[4] = 0x15; + priv->cck_txbbgain_table[5].ccktxbb_valuearray[5] = 0x0d; + priv->cck_txbbgain_table[5].ccktxbb_valuearray[6] = 0x07; + priv->cck_txbbgain_table[5].ccktxbb_valuearray[7] = 0x03; + + priv->cck_txbbgain_table[6].ccktxbb_valuearray[0] = 0x26; + priv->cck_txbbgain_table[6].ccktxbb_valuearray[1] = 0x25; + priv->cck_txbbgain_table[6].ccktxbb_valuearray[2] = 0x21; + priv->cck_txbbgain_table[6].ccktxbb_valuearray[3] = 0x1b; + priv->cck_txbbgain_table[6].ccktxbb_valuearray[4] = 0x14; + priv->cck_txbbgain_table[6].ccktxbb_valuearray[5] = 0x0d; + priv->cck_txbbgain_table[6].ccktxbb_valuearray[6] = 0x06; + priv->cck_txbbgain_table[6].ccktxbb_valuearray[7] = 0x03; + + priv->cck_txbbgain_table[7].ccktxbb_valuearray[0] = 0x24; + priv->cck_txbbgain_table[7].ccktxbb_valuearray[1] = 0x23; + priv->cck_txbbgain_table[7].ccktxbb_valuearray[2] = 0x1f; + priv->cck_txbbgain_table[7].ccktxbb_valuearray[3] = 0x19; + priv->cck_txbbgain_table[7].ccktxbb_valuearray[4] = 0x13; + priv->cck_txbbgain_table[7].ccktxbb_valuearray[5] = 0x0c; + priv->cck_txbbgain_table[7].ccktxbb_valuearray[6] = 0x06; + priv->cck_txbbgain_table[7].ccktxbb_valuearray[7] = 0x03; + + priv->cck_txbbgain_table[8].ccktxbb_valuearray[0] = 0x22; + priv->cck_txbbgain_table[8].ccktxbb_valuearray[1] = 0x21; + priv->cck_txbbgain_table[8].ccktxbb_valuearray[2] = 0x1d; + priv->cck_txbbgain_table[8].ccktxbb_valuearray[3] = 0x18; + priv->cck_txbbgain_table[8].ccktxbb_valuearray[4] = 0x11; + priv->cck_txbbgain_table[8].ccktxbb_valuearray[5] = 0x0b; + priv->cck_txbbgain_table[8].ccktxbb_valuearray[6] = 0x06; + priv->cck_txbbgain_table[8].ccktxbb_valuearray[7] = 0x02; + + priv->cck_txbbgain_table[9].ccktxbb_valuearray[0] = 0x20; + priv->cck_txbbgain_table[9].ccktxbb_valuearray[1] = 0x20; + priv->cck_txbbgain_table[9].ccktxbb_valuearray[2] = 0x1b; + priv->cck_txbbgain_table[9].ccktxbb_valuearray[3] = 0x16; + priv->cck_txbbgain_table[9].ccktxbb_valuearray[4] = 0x11; + priv->cck_txbbgain_table[9].ccktxbb_valuearray[5] = 0x08; + priv->cck_txbbgain_table[9].ccktxbb_valuearray[6] = 0x05; + priv->cck_txbbgain_table[9].ccktxbb_valuearray[7] = 0x02; + + priv->cck_txbbgain_table[10].ccktxbb_valuearray[0] = 0x1f; + priv->cck_txbbgain_table[10].ccktxbb_valuearray[1] = 0x1e; + priv->cck_txbbgain_table[10].ccktxbb_valuearray[2] = 0x1a; + priv->cck_txbbgain_table[10].ccktxbb_valuearray[3] = 0x15; + priv->cck_txbbgain_table[10].ccktxbb_valuearray[4] = 0x10; + priv->cck_txbbgain_table[10].ccktxbb_valuearray[5] = 0x0a; + priv->cck_txbbgain_table[10].ccktxbb_valuearray[6] = 0x05; + priv->cck_txbbgain_table[10].ccktxbb_valuearray[7] = 0x02; + + priv->cck_txbbgain_table[11].ccktxbb_valuearray[0] = 0x1d; + priv->cck_txbbgain_table[11].ccktxbb_valuearray[1] = 0x1c; + priv->cck_txbbgain_table[11].ccktxbb_valuearray[2] = 0x18; + priv->cck_txbbgain_table[11].ccktxbb_valuearray[3] = 0x14; + priv->cck_txbbgain_table[11].ccktxbb_valuearray[4] = 0x0f; + priv->cck_txbbgain_table[11].ccktxbb_valuearray[5] = 0x0a; + priv->cck_txbbgain_table[11].ccktxbb_valuearray[6] = 0x05; + priv->cck_txbbgain_table[11].ccktxbb_valuearray[7] = 0x02; + + priv->cck_txbbgain_table[12].ccktxbb_valuearray[0] = 0x1b; + priv->cck_txbbgain_table[12].ccktxbb_valuearray[1] = 0x1a; + priv->cck_txbbgain_table[12].ccktxbb_valuearray[2] = 0x17; + priv->cck_txbbgain_table[12].ccktxbb_valuearray[3] = 0x13; + priv->cck_txbbgain_table[12].ccktxbb_valuearray[4] = 0x0e; + priv->cck_txbbgain_table[12].ccktxbb_valuearray[5] = 0x09; + priv->cck_txbbgain_table[12].ccktxbb_valuearray[6] = 0x04; + priv->cck_txbbgain_table[12].ccktxbb_valuearray[7] = 0x02; + + priv->cck_txbbgain_table[13].ccktxbb_valuearray[0] = 0x1a; + priv->cck_txbbgain_table[13].ccktxbb_valuearray[1] = 0x19; + priv->cck_txbbgain_table[13].ccktxbb_valuearray[2] = 0x16; + priv->cck_txbbgain_table[13].ccktxbb_valuearray[3] = 0x12; + priv->cck_txbbgain_table[13].ccktxbb_valuearray[4] = 0x0d; + priv->cck_txbbgain_table[13].ccktxbb_valuearray[5] = 0x09; + priv->cck_txbbgain_table[13].ccktxbb_valuearray[6] = 0x04; + priv->cck_txbbgain_table[13].ccktxbb_valuearray[7] = 0x02; + + priv->cck_txbbgain_table[14].ccktxbb_valuearray[0] = 0x18; + priv->cck_txbbgain_table[14].ccktxbb_valuearray[1] = 0x17; + priv->cck_txbbgain_table[14].ccktxbb_valuearray[2] = 0x15; + priv->cck_txbbgain_table[14].ccktxbb_valuearray[3] = 0x11; + priv->cck_txbbgain_table[14].ccktxbb_valuearray[4] = 0x0c; + priv->cck_txbbgain_table[14].ccktxbb_valuearray[5] = 0x08; + priv->cck_txbbgain_table[14].ccktxbb_valuearray[6] = 0x04; + priv->cck_txbbgain_table[14].ccktxbb_valuearray[7] = 0x02; + + priv->cck_txbbgain_table[15].ccktxbb_valuearray[0] = 0x17; + priv->cck_txbbgain_table[15].ccktxbb_valuearray[1] = 0x16; + priv->cck_txbbgain_table[15].ccktxbb_valuearray[2] = 0x13; + priv->cck_txbbgain_table[15].ccktxbb_valuearray[3] = 0x10; + priv->cck_txbbgain_table[15].ccktxbb_valuearray[4] = 0x0c; + priv->cck_txbbgain_table[15].ccktxbb_valuearray[5] = 0x08; + priv->cck_txbbgain_table[15].ccktxbb_valuearray[6] = 0x04; + priv->cck_txbbgain_table[15].ccktxbb_valuearray[7] = 0x02; + + priv->cck_txbbgain_table[16].ccktxbb_valuearray[0] = 0x16; + priv->cck_txbbgain_table[16].ccktxbb_valuearray[1] = 0x15; + priv->cck_txbbgain_table[16].ccktxbb_valuearray[2] = 0x12; + priv->cck_txbbgain_table[16].ccktxbb_valuearray[3] = 0x0f; + priv->cck_txbbgain_table[16].ccktxbb_valuearray[4] = 0x0b; + priv->cck_txbbgain_table[16].ccktxbb_valuearray[5] = 0x07; + priv->cck_txbbgain_table[16].ccktxbb_valuearray[6] = 0x04; + priv->cck_txbbgain_table[16].ccktxbb_valuearray[7] = 0x01; + + priv->cck_txbbgain_table[17].ccktxbb_valuearray[0] = 0x14; + priv->cck_txbbgain_table[17].ccktxbb_valuearray[1] = 0x14; + priv->cck_txbbgain_table[17].ccktxbb_valuearray[2] = 0x11; + priv->cck_txbbgain_table[17].ccktxbb_valuearray[3] = 0x0e; + priv->cck_txbbgain_table[17].ccktxbb_valuearray[4] = 0x0b; + priv->cck_txbbgain_table[17].ccktxbb_valuearray[5] = 0x07; + priv->cck_txbbgain_table[17].ccktxbb_valuearray[6] = 0x03; + priv->cck_txbbgain_table[17].ccktxbb_valuearray[7] = 0x02; + + priv->cck_txbbgain_table[18].ccktxbb_valuearray[0] = 0x13; + priv->cck_txbbgain_table[18].ccktxbb_valuearray[1] = 0x13; + priv->cck_txbbgain_table[18].ccktxbb_valuearray[2] = 0x10; + priv->cck_txbbgain_table[18].ccktxbb_valuearray[3] = 0x0d; + priv->cck_txbbgain_table[18].ccktxbb_valuearray[4] = 0x0a; + priv->cck_txbbgain_table[18].ccktxbb_valuearray[5] = 0x06; + priv->cck_txbbgain_table[18].ccktxbb_valuearray[6] = 0x03; + priv->cck_txbbgain_table[18].ccktxbb_valuearray[7] = 0x01; + + priv->cck_txbbgain_table[19].ccktxbb_valuearray[0] = 0x12; + priv->cck_txbbgain_table[19].ccktxbb_valuearray[1] = 0x12; + priv->cck_txbbgain_table[19].ccktxbb_valuearray[2] = 0x0f; + priv->cck_txbbgain_table[19].ccktxbb_valuearray[3] = 0x0c; + priv->cck_txbbgain_table[19].ccktxbb_valuearray[4] = 0x09; + priv->cck_txbbgain_table[19].ccktxbb_valuearray[5] = 0x06; + priv->cck_txbbgain_table[19].ccktxbb_valuearray[6] = 0x03; + priv->cck_txbbgain_table[19].ccktxbb_valuearray[7] = 0x01; + + priv->cck_txbbgain_table[20].ccktxbb_valuearray[0] = 0x11; + priv->cck_txbbgain_table[20].ccktxbb_valuearray[1] = 0x11; + priv->cck_txbbgain_table[20].ccktxbb_valuearray[2] = 0x0f; + priv->cck_txbbgain_table[20].ccktxbb_valuearray[3] = 0x0c; + priv->cck_txbbgain_table[20].ccktxbb_valuearray[4] = 0x09; + priv->cck_txbbgain_table[20].ccktxbb_valuearray[5] = 0x06; + priv->cck_txbbgain_table[20].ccktxbb_valuearray[6] = 0x03; + priv->cck_txbbgain_table[20].ccktxbb_valuearray[7] = 0x01; + + priv->cck_txbbgain_table[21].ccktxbb_valuearray[0] = 0x10; + priv->cck_txbbgain_table[21].ccktxbb_valuearray[1] = 0x10; + priv->cck_txbbgain_table[21].ccktxbb_valuearray[2] = 0x0e; + priv->cck_txbbgain_table[21].ccktxbb_valuearray[3] = 0x0b; + priv->cck_txbbgain_table[21].ccktxbb_valuearray[4] = 0x08; + priv->cck_txbbgain_table[21].ccktxbb_valuearray[5] = 0x05; + priv->cck_txbbgain_table[21].ccktxbb_valuearray[6] = 0x03; + priv->cck_txbbgain_table[21].ccktxbb_valuearray[7] = 0x01; + + priv->cck_txbbgain_table[22].ccktxbb_valuearray[0] = 0x0f; + priv->cck_txbbgain_table[22].ccktxbb_valuearray[1] = 0x0f; + priv->cck_txbbgain_table[22].ccktxbb_valuearray[2] = 0x0d; + priv->cck_txbbgain_table[22].ccktxbb_valuearray[3] = 0x0b; + priv->cck_txbbgain_table[22].ccktxbb_valuearray[4] = 0x08; + priv->cck_txbbgain_table[22].ccktxbb_valuearray[5] = 0x05; + priv->cck_txbbgain_table[22].ccktxbb_valuearray[6] = 0x03; + priv->cck_txbbgain_table[22].ccktxbb_valuearray[7] = 0x01; + + //ccktxbb_valuearray[0] is 0xA22 [1] is 0xA24 ...[7] is 0xA29 + //This Table is for CH14 + priv->cck_txbbgain_ch14_table[0].ccktxbb_valuearray[0] = 0x36; + priv->cck_txbbgain_ch14_table[0].ccktxbb_valuearray[1] = 0x35; + priv->cck_txbbgain_ch14_table[0].ccktxbb_valuearray[2] = 0x2e; + priv->cck_txbbgain_ch14_table[0].ccktxbb_valuearray[3] = 0x1b; + priv->cck_txbbgain_ch14_table[0].ccktxbb_valuearray[4] = 0x00; + priv->cck_txbbgain_ch14_table[0].ccktxbb_valuearray[5] = 0x00; + priv->cck_txbbgain_ch14_table[0].ccktxbb_valuearray[6] = 0x00; + priv->cck_txbbgain_ch14_table[0].ccktxbb_valuearray[7] = 0x00; + + priv->cck_txbbgain_ch14_table[1].ccktxbb_valuearray[0] = 0x33; + priv->cck_txbbgain_ch14_table[1].ccktxbb_valuearray[1] = 0x32; + priv->cck_txbbgain_ch14_table[1].ccktxbb_valuearray[2] = 0x2b; + priv->cck_txbbgain_ch14_table[1].ccktxbb_valuearray[3] = 0x19; + priv->cck_txbbgain_ch14_table[1].ccktxbb_valuearray[4] = 0x00; + priv->cck_txbbgain_ch14_table[1].ccktxbb_valuearray[5] = 0x00; + priv->cck_txbbgain_ch14_table[1].ccktxbb_valuearray[6] = 0x00; + priv->cck_txbbgain_ch14_table[1].ccktxbb_valuearray[7] = 0x00; + + priv->cck_txbbgain_ch14_table[2].ccktxbb_valuearray[0] = 0x30; + priv->cck_txbbgain_ch14_table[2].ccktxbb_valuearray[1] = 0x2f; + priv->cck_txbbgain_ch14_table[2].ccktxbb_valuearray[2] = 0x29; + priv->cck_txbbgain_ch14_table[2].ccktxbb_valuearray[3] = 0x18; + priv->cck_txbbgain_ch14_table[2].ccktxbb_valuearray[4] = 0x00; + priv->cck_txbbgain_ch14_table[2].ccktxbb_valuearray[5] = 0x00; + priv->cck_txbbgain_ch14_table[2].ccktxbb_valuearray[6] = 0x00; + priv->cck_txbbgain_ch14_table[2].ccktxbb_valuearray[7] = 0x00; + + priv->cck_txbbgain_ch14_table[3].ccktxbb_valuearray[0] = 0x2d; + priv->cck_txbbgain_ch14_table[3].ccktxbb_valuearray[1] = 0x2d; + priv->cck_txbbgain_ch14_table[3].ccktxbb_valuearray[2] = 0x27; + priv->cck_txbbgain_ch14_table[3].ccktxbb_valuearray[3] = 0x17; + priv->cck_txbbgain_ch14_table[3].ccktxbb_valuearray[4] = 0x00; + priv->cck_txbbgain_ch14_table[3].ccktxbb_valuearray[5] = 0x00; + priv->cck_txbbgain_ch14_table[3].ccktxbb_valuearray[6] = 0x00; + priv->cck_txbbgain_ch14_table[3].ccktxbb_valuearray[7] = 0x00; + + priv->cck_txbbgain_ch14_table[4].ccktxbb_valuearray[0] = 0x2b; + priv->cck_txbbgain_ch14_table[4].ccktxbb_valuearray[1] = 0x2a; + priv->cck_txbbgain_ch14_table[4].ccktxbb_valuearray[2] = 0x25; + priv->cck_txbbgain_ch14_table[4].ccktxbb_valuearray[3] = 0x15; + priv->cck_txbbgain_ch14_table[4].ccktxbb_valuearray[4] = 0x00; + priv->cck_txbbgain_ch14_table[4].ccktxbb_valuearray[5] = 0x00; + priv->cck_txbbgain_ch14_table[4].ccktxbb_valuearray[6] = 0x00; + priv->cck_txbbgain_ch14_table[4].ccktxbb_valuearray[7] = 0x00; + + priv->cck_txbbgain_ch14_table[5].ccktxbb_valuearray[0] = 0x28; + priv->cck_txbbgain_ch14_table[5].ccktxbb_valuearray[1] = 0x28; + priv->cck_txbbgain_ch14_table[5].ccktxbb_valuearray[2] = 0x22; + priv->cck_txbbgain_ch14_table[5].ccktxbb_valuearray[3] = 0x14; + priv->cck_txbbgain_ch14_table[5].ccktxbb_valuearray[4] = 0x00; + priv->cck_txbbgain_ch14_table[5].ccktxbb_valuearray[5] = 0x00; + priv->cck_txbbgain_ch14_table[5].ccktxbb_valuearray[6] = 0x00; + priv->cck_txbbgain_ch14_table[5].ccktxbb_valuearray[7] = 0x00; + + priv->cck_txbbgain_ch14_table[6].ccktxbb_valuearray[0] = 0x26; + priv->cck_txbbgain_ch14_table[6].ccktxbb_valuearray[1] = 0x25; + priv->cck_txbbgain_ch14_table[6].ccktxbb_valuearray[2] = 0x21; + priv->cck_txbbgain_ch14_table[6].ccktxbb_valuearray[3] = 0x13; + priv->cck_txbbgain_ch14_table[6].ccktxbb_valuearray[4] = 0x00; + priv->cck_txbbgain_ch14_table[6].ccktxbb_valuearray[5] = 0x00; + priv->cck_txbbgain_ch14_table[6].ccktxbb_valuearray[6] = 0x00; + priv->cck_txbbgain_ch14_table[6].ccktxbb_valuearray[7] = 0x00; + + priv->cck_txbbgain_ch14_table[7].ccktxbb_valuearray[0] = 0x24; + priv->cck_txbbgain_ch14_table[7].ccktxbb_valuearray[1] = 0x23; + priv->cck_txbbgain_ch14_table[7].ccktxbb_valuearray[2] = 0x1f; + priv->cck_txbbgain_ch14_table[7].ccktxbb_valuearray[3] = 0x12; + priv->cck_txbbgain_ch14_table[7].ccktxbb_valuearray[4] = 0x00; + priv->cck_txbbgain_ch14_table[7].ccktxbb_valuearray[5] = 0x00; + priv->cck_txbbgain_ch14_table[7].ccktxbb_valuearray[6] = 0x00; + priv->cck_txbbgain_ch14_table[7].ccktxbb_valuearray[7] = 0x00; + + priv->cck_txbbgain_ch14_table[8].ccktxbb_valuearray[0] = 0x22; + priv->cck_txbbgain_ch14_table[8].ccktxbb_valuearray[1] = 0x21; + priv->cck_txbbgain_ch14_table[8].ccktxbb_valuearray[2] = 0x1d; + priv->cck_txbbgain_ch14_table[8].ccktxbb_valuearray[3] = 0x11; + priv->cck_txbbgain_ch14_table[8].ccktxbb_valuearray[4] = 0x00; + priv->cck_txbbgain_ch14_table[8].ccktxbb_valuearray[5] = 0x00; + priv->cck_txbbgain_ch14_table[8].ccktxbb_valuearray[6] = 0x00; + priv->cck_txbbgain_ch14_table[8].ccktxbb_valuearray[7] = 0x00; + + priv->cck_txbbgain_ch14_table[9].ccktxbb_valuearray[0] = 0x20; + priv->cck_txbbgain_ch14_table[9].ccktxbb_valuearray[1] = 0x20; + priv->cck_txbbgain_ch14_table[9].ccktxbb_valuearray[2] = 0x1b; + priv->cck_txbbgain_ch14_table[9].ccktxbb_valuearray[3] = 0x10; + priv->cck_txbbgain_ch14_table[9].ccktxbb_valuearray[4] = 0x00; + priv->cck_txbbgain_ch14_table[9].ccktxbb_valuearray[5] = 0x00; + priv->cck_txbbgain_ch14_table[9].ccktxbb_valuearray[6] = 0x00; + priv->cck_txbbgain_ch14_table[9].ccktxbb_valuearray[7] = 0x00; + + priv->cck_txbbgain_ch14_table[10].ccktxbb_valuearray[0] = 0x1f; + priv->cck_txbbgain_ch14_table[10].ccktxbb_valuearray[1] = 0x1e; + priv->cck_txbbgain_ch14_table[10].ccktxbb_valuearray[2] = 0x1a; + priv->cck_txbbgain_ch14_table[10].ccktxbb_valuearray[3] = 0x0f; + priv->cck_txbbgain_ch14_table[10].ccktxbb_valuearray[4] = 0x00; + priv->cck_txbbgain_ch14_table[10].ccktxbb_valuearray[5] = 0x00; + priv->cck_txbbgain_ch14_table[10].ccktxbb_valuearray[6] = 0x00; + priv->cck_txbbgain_ch14_table[10].ccktxbb_valuearray[7] = 0x00; + + priv->cck_txbbgain_ch14_table[11].ccktxbb_valuearray[0] = 0x1d; + priv->cck_txbbgain_ch14_table[11].ccktxbb_valuearray[1] = 0x1c; + priv->cck_txbbgain_ch14_table[11].ccktxbb_valuearray[2] = 0x18; + priv->cck_txbbgain_ch14_table[11].ccktxbb_valuearray[3] = 0x0e; + priv->cck_txbbgain_ch14_table[11].ccktxbb_valuearray[4] = 0x00; + priv->cck_txbbgain_ch14_table[11].ccktxbb_valuearray[5] = 0x00; + priv->cck_txbbgain_ch14_table[11].ccktxbb_valuearray[6] = 0x00; + priv->cck_txbbgain_ch14_table[11].ccktxbb_valuearray[7] = 0x00; + + priv->cck_txbbgain_ch14_table[12].ccktxbb_valuearray[0] = 0x1b; + priv->cck_txbbgain_ch14_table[12].ccktxbb_valuearray[1] = 0x1a; + priv->cck_txbbgain_ch14_table[12].ccktxbb_valuearray[2] = 0x17; + priv->cck_txbbgain_ch14_table[12].ccktxbb_valuearray[3] = 0x0e; + priv->cck_txbbgain_ch14_table[12].ccktxbb_valuearray[4] = 0x00; + priv->cck_txbbgain_ch14_table[12].ccktxbb_valuearray[5] = 0x00; + priv->cck_txbbgain_ch14_table[12].ccktxbb_valuearray[6] = 0x00; + priv->cck_txbbgain_ch14_table[12].ccktxbb_valuearray[7] = 0x00; + + priv->cck_txbbgain_ch14_table[13].ccktxbb_valuearray[0] = 0x1a; + priv->cck_txbbgain_ch14_table[13].ccktxbb_valuearray[1] = 0x19; + priv->cck_txbbgain_ch14_table[13].ccktxbb_valuearray[2] = 0x16; + priv->cck_txbbgain_ch14_table[13].ccktxbb_valuearray[3] = 0x0d; + priv->cck_txbbgain_ch14_table[13].ccktxbb_valuearray[4] = 0x00; + priv->cck_txbbgain_ch14_table[13].ccktxbb_valuearray[5] = 0x00; + priv->cck_txbbgain_ch14_table[13].ccktxbb_valuearray[6] = 0x00; + priv->cck_txbbgain_ch14_table[13].ccktxbb_valuearray[7] = 0x00; + + priv->cck_txbbgain_ch14_table[14].ccktxbb_valuearray[0] = 0x18; + priv->cck_txbbgain_ch14_table[14].ccktxbb_valuearray[1] = 0x17; + priv->cck_txbbgain_ch14_table[14].ccktxbb_valuearray[2] = 0x15; + priv->cck_txbbgain_ch14_table[14].ccktxbb_valuearray[3] = 0x0c; + priv->cck_txbbgain_ch14_table[14].ccktxbb_valuearray[4] = 0x00; + priv->cck_txbbgain_ch14_table[14].ccktxbb_valuearray[5] = 0x00; + priv->cck_txbbgain_ch14_table[14].ccktxbb_valuearray[6] = 0x00; + priv->cck_txbbgain_ch14_table[14].ccktxbb_valuearray[7] = 0x00; + + priv->cck_txbbgain_ch14_table[15].ccktxbb_valuearray[0] = 0x17; + priv->cck_txbbgain_ch14_table[15].ccktxbb_valuearray[1] = 0x16; + priv->cck_txbbgain_ch14_table[15].ccktxbb_valuearray[2] = 0x13; + priv->cck_txbbgain_ch14_table[15].ccktxbb_valuearray[3] = 0x0b; + priv->cck_txbbgain_ch14_table[15].ccktxbb_valuearray[4] = 0x00; + priv->cck_txbbgain_ch14_table[15].ccktxbb_valuearray[5] = 0x00; + priv->cck_txbbgain_ch14_table[15].ccktxbb_valuearray[6] = 0x00; + priv->cck_txbbgain_ch14_table[15].ccktxbb_valuearray[7] = 0x00; + + priv->cck_txbbgain_ch14_table[16].ccktxbb_valuearray[0] = 0x16; + priv->cck_txbbgain_ch14_table[16].ccktxbb_valuearray[1] = 0x15; + priv->cck_txbbgain_ch14_table[16].ccktxbb_valuearray[2] = 0x12; + priv->cck_txbbgain_ch14_table[16].ccktxbb_valuearray[3] = 0x0b; + priv->cck_txbbgain_ch14_table[16].ccktxbb_valuearray[4] = 0x00; + priv->cck_txbbgain_ch14_table[16].ccktxbb_valuearray[5] = 0x00; + priv->cck_txbbgain_ch14_table[16].ccktxbb_valuearray[6] = 0x00; + priv->cck_txbbgain_ch14_table[16].ccktxbb_valuearray[7] = 0x00; + + priv->cck_txbbgain_ch14_table[17].ccktxbb_valuearray[0] = 0x14; + priv->cck_txbbgain_ch14_table[17].ccktxbb_valuearray[1] = 0x14; + priv->cck_txbbgain_ch14_table[17].ccktxbb_valuearray[2] = 0x11; + priv->cck_txbbgain_ch14_table[17].ccktxbb_valuearray[3] = 0x0a; + priv->cck_txbbgain_ch14_table[17].ccktxbb_valuearray[4] = 0x00; + priv->cck_txbbgain_ch14_table[17].ccktxbb_valuearray[5] = 0x00; + priv->cck_txbbgain_ch14_table[17].ccktxbb_valuearray[6] = 0x00; + priv->cck_txbbgain_ch14_table[17].ccktxbb_valuearray[7] = 0x00; + + priv->cck_txbbgain_ch14_table[18].ccktxbb_valuearray[0] = 0x13; + priv->cck_txbbgain_ch14_table[18].ccktxbb_valuearray[1] = 0x13; + priv->cck_txbbgain_ch14_table[18].ccktxbb_valuearray[2] = 0x10; + priv->cck_txbbgain_ch14_table[18].ccktxbb_valuearray[3] = 0x0a; + priv->cck_txbbgain_ch14_table[18].ccktxbb_valuearray[4] = 0x00; + priv->cck_txbbgain_ch14_table[18].ccktxbb_valuearray[5] = 0x00; + priv->cck_txbbgain_ch14_table[18].ccktxbb_valuearray[6] = 0x00; + priv->cck_txbbgain_ch14_table[18].ccktxbb_valuearray[7] = 0x00; + + priv->cck_txbbgain_ch14_table[19].ccktxbb_valuearray[0] = 0x12; + priv->cck_txbbgain_ch14_table[19].ccktxbb_valuearray[1] = 0x12; + priv->cck_txbbgain_ch14_table[19].ccktxbb_valuearray[2] = 0x0f; + priv->cck_txbbgain_ch14_table[19].ccktxbb_valuearray[3] = 0x09; + priv->cck_txbbgain_ch14_table[19].ccktxbb_valuearray[4] = 0x00; + priv->cck_txbbgain_ch14_table[19].ccktxbb_valuearray[5] = 0x00; + priv->cck_txbbgain_ch14_table[19].ccktxbb_valuearray[6] = 0x00; + priv->cck_txbbgain_ch14_table[19].ccktxbb_valuearray[7] = 0x00; + + priv->cck_txbbgain_ch14_table[20].ccktxbb_valuearray[0] = 0x11; + priv->cck_txbbgain_ch14_table[20].ccktxbb_valuearray[1] = 0x11; + priv->cck_txbbgain_ch14_table[20].ccktxbb_valuearray[2] = 0x0f; + priv->cck_txbbgain_ch14_table[20].ccktxbb_valuearray[3] = 0x09; + priv->cck_txbbgain_ch14_table[20].ccktxbb_valuearray[4] = 0x00; + priv->cck_txbbgain_ch14_table[20].ccktxbb_valuearray[5] = 0x00; + priv->cck_txbbgain_ch14_table[20].ccktxbb_valuearray[6] = 0x00; + priv->cck_txbbgain_ch14_table[20].ccktxbb_valuearray[7] = 0x00; + + priv->cck_txbbgain_ch14_table[21].ccktxbb_valuearray[0] = 0x10; + priv->cck_txbbgain_ch14_table[21].ccktxbb_valuearray[1] = 0x10; + priv->cck_txbbgain_ch14_table[21].ccktxbb_valuearray[2] = 0x0e; + priv->cck_txbbgain_ch14_table[21].ccktxbb_valuearray[3] = 0x08; + priv->cck_txbbgain_ch14_table[21].ccktxbb_valuearray[4] = 0x00; + priv->cck_txbbgain_ch14_table[21].ccktxbb_valuearray[5] = 0x00; + priv->cck_txbbgain_ch14_table[21].ccktxbb_valuearray[6] = 0x00; + priv->cck_txbbgain_ch14_table[21].ccktxbb_valuearray[7] = 0x00; + + priv->cck_txbbgain_ch14_table[22].ccktxbb_valuearray[0] = 0x0f; + priv->cck_txbbgain_ch14_table[22].ccktxbb_valuearray[1] = 0x0f; + priv->cck_txbbgain_ch14_table[22].ccktxbb_valuearray[2] = 0x0d; + priv->cck_txbbgain_ch14_table[22].ccktxbb_valuearray[3] = 0x08; + priv->cck_txbbgain_ch14_table[22].ccktxbb_valuearray[4] = 0x00; + priv->cck_txbbgain_ch14_table[22].ccktxbb_valuearray[5] = 0x00; + priv->cck_txbbgain_ch14_table[22].ccktxbb_valuearray[6] = 0x00; + priv->cck_txbbgain_ch14_table[22].ccktxbb_valuearray[7] = 0x00; + + priv->btxpower_tracking = TRUE; + priv->txpower_count = 0; + priv->btxpower_trackingInit = FALSE; + +} + +#ifndef RTL8192SU +static void dm_InitializeTXPowerTracking_ThermalMeter(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + + // Tx Power tracking by Theremal Meter require Firmware R/W 3-wire. This mechanism + // can be enabled only when Firmware R/W 3-wire is enabled. Otherwise, frequent r/w + // 3-wire by driver cause RF goes into wrong state. + if(priv->ieee80211->FwRWRF) + priv->btxpower_tracking = TRUE; + else + priv->btxpower_tracking = FALSE; + priv->txpower_count = 0; + priv->btxpower_trackingInit = FALSE; +} +#endif + +void dm_initialize_txpower_tracking(struct net_device *dev) +{ +#if (defined RTL8190P) + dm_InitializeTXPowerTracking_TSSI(dev); +#elif (defined RTL8192SU) + // 2009/01/12 MH Enable for 92S series channel 1-14 CCK tx pwer setting for MP. + // + dm_InitializeTXPowerTracking_TSSI(dev); +#else + struct r8192_priv *priv = ieee80211_priv(dev); + if(priv->bDcut == TRUE) + dm_InitializeTXPowerTracking_TSSI(dev); + else + dm_InitializeTXPowerTracking_ThermalMeter(dev); +#endif +}// dm_InitializeTXPowerTracking + + +static void dm_CheckTXPowerTracking_TSSI(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + static u32 tx_power_track_counter = 0; + + if(!priv->btxpower_tracking) + return; + else + { + if((tx_power_track_counter % 30 == 0)&&(tx_power_track_counter != 0)) + { + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + queue_delayed_work(priv->priv_wq,&priv->txpower_tracking_wq,0); + #else + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + schedule_task(&priv->txpower_tracking_wq); + #else + queue_work(priv->priv_wq,&priv->txpower_tracking_wq); + #endif + #endif + } + tx_power_track_counter++; + } + +} + + +static void dm_CheckTXPowerTracking_ThermalMeter(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + static u8 TM_Trigger=0; +#if 0 + u1Byte i; + u4Byte tmpRegA; + for(i=0; i<50; i++) + { + tmpRegA = PHY_QueryRFReg(Adapter, RF90_PATH_A, 0x12, 0x078); // 0x12: RF Reg[10:7] + PHY_SetRFReg(Adapter, RF90_PATH_A, 0x02, bMask12Bits, 0x4d); + //delay_us(100); + PHY_SetRFReg(Adapter, RF90_PATH_A, 0x02, bMask12Bits, 0x4f); + //delay_us(100); + } + DbgPrint("Trigger and readback ThermalMeter, write RF reg0x2 = 0x4d to 0x4f for 50 times\n"); +#else + //DbgPrint("dm_CheckTXPowerTracking() \n"); + if(!priv->btxpower_tracking) + return; + else + { + if(priv->txpower_count <= 2) + { + priv->txpower_count++; + return; + } + } + + if(!TM_Trigger) + { + //Attention!! You have to wirte all 12bits data to RF, or it may cause RF to crash + //actually write reg0x02 bit1=0, then bit1=1. + //DbgPrint("Trigger ThermalMeter, write RF reg0x2 = 0x4d to 0x4f\n"); +#ifdef RTL8192SU + rtl8192_phy_SetRFReg(dev, RF90_PATH_A, 0x02, bRFRegOffsetMask, 0x4d); + rtl8192_phy_SetRFReg(dev, RF90_PATH_A, 0x02, bRFRegOffsetMask, 0x4f); + rtl8192_phy_SetRFReg(dev, RF90_PATH_A, 0x02, bRFRegOffsetMask, 0x4d); + rtl8192_phy_SetRFReg(dev, RF90_PATH_A, 0x02, bRFRegOffsetMask, 0x4f); +#else + rtl8192_phy_SetRFReg(dev, RF90_PATH_A, 0x02, bMask12Bits, 0x4d); + rtl8192_phy_SetRFReg(dev, RF90_PATH_A, 0x02, bMask12Bits, 0x4f); + rtl8192_phy_SetRFReg(dev, RF90_PATH_A, 0x02, bMask12Bits, 0x4d); + rtl8192_phy_SetRFReg(dev, RF90_PATH_A, 0x02, bMask12Bits, 0x4f); +#endif + TM_Trigger = 1; + return; + } + else + { + //DbgPrint("Schedule TxPowerTrackingWorkItem\n"); + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + queue_delayed_work(priv->priv_wq,&priv->txpower_tracking_wq,0); + #else + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + schedule_task(&priv->txpower_tracking_wq); + #else + queue_work(priv->priv_wq,&priv->txpower_tracking_wq); + #endif + #endif + TM_Trigger = 0; + } +#endif +} + + +static void dm_check_txpower_tracking(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + //static u32 tx_power_track_counter = 0; + +#ifdef RTL8190P + dm_CheckTXPowerTracking_TSSI(dev); +#else + if(priv->bDcut == TRUE) + dm_CheckTXPowerTracking_TSSI(dev); + else + dm_CheckTXPowerTracking_ThermalMeter(dev); +#endif + +} // dm_CheckTXPowerTracking + + +static void dm_CCKTxPowerAdjust_TSSI(struct net_device *dev, bool bInCH14) +{ + u32 TempVal; + struct r8192_priv *priv = ieee80211_priv(dev); + //Write 0xa22 0xa23 + TempVal = 0; + if(!bInCH14){ + //Write 0xa22 0xa23 + TempVal = priv->cck_txbbgain_table[priv->cck_present_attentuation].ccktxbb_valuearray[0] + + (priv->cck_txbbgain_table[priv->cck_present_attentuation].ccktxbb_valuearray[1]<<8) ; + + rtl8192_setBBreg(dev, rCCK0_TxFilter1,bMaskHWord, TempVal); + //Write 0xa24 ~ 0xa27 + TempVal = 0; + TempVal = priv->cck_txbbgain_table[priv->cck_present_attentuation].ccktxbb_valuearray[2] + + (priv->cck_txbbgain_table[priv->cck_present_attentuation].ccktxbb_valuearray[3]<<8) + + (priv->cck_txbbgain_table[priv->cck_present_attentuation].ccktxbb_valuearray[4]<<16 )+ + (priv->cck_txbbgain_table[priv->cck_present_attentuation].ccktxbb_valuearray[5]<<24); + rtl8192_setBBreg(dev, rCCK0_TxFilter2,bMaskDWord, TempVal); + //Write 0xa28 0xa29 + TempVal = 0; + TempVal = priv->cck_txbbgain_table[priv->cck_present_attentuation].ccktxbb_valuearray[6] + + (priv->cck_txbbgain_table[priv->cck_present_attentuation].ccktxbb_valuearray[7]<<8) ; + + rtl8192_setBBreg(dev, rCCK0_DebugPort,bMaskLWord, TempVal); + } + else + { + TempVal = priv->cck_txbbgain_ch14_table[priv->cck_present_attentuation].ccktxbb_valuearray[0] + + (priv->cck_txbbgain_ch14_table[priv->cck_present_attentuation].ccktxbb_valuearray[1]<<8) ; + + rtl8192_setBBreg(dev, rCCK0_TxFilter1,bMaskHWord, TempVal); + //Write 0xa24 ~ 0xa27 + TempVal = 0; + TempVal = priv->cck_txbbgain_ch14_table[priv->cck_present_attentuation].ccktxbb_valuearray[2] + + (priv->cck_txbbgain_ch14_table[priv->cck_present_attentuation].ccktxbb_valuearray[3]<<8) + + (priv->cck_txbbgain_ch14_table[priv->cck_present_attentuation].ccktxbb_valuearray[4]<<16 )+ + (priv->cck_txbbgain_ch14_table[priv->cck_present_attentuation].ccktxbb_valuearray[5]<<24); + rtl8192_setBBreg(dev, rCCK0_TxFilter2,bMaskDWord, TempVal); + //Write 0xa28 0xa29 + TempVal = 0; + TempVal = priv->cck_txbbgain_ch14_table[priv->cck_present_attentuation].ccktxbb_valuearray[6] + + (priv->cck_txbbgain_ch14_table[priv->cck_present_attentuation].ccktxbb_valuearray[7]<<8) ; + + rtl8192_setBBreg(dev, rCCK0_DebugPort,bMaskLWord, TempVal); + } + + +} + +static void dm_CCKTxPowerAdjust_ThermalMeter(struct net_device *dev, bool bInCH14) +{ + u32 TempVal; + struct r8192_priv *priv = ieee80211_priv(dev); + + TempVal = 0; + if(!bInCH14) + { + //Write 0xa22 0xa23 + TempVal = CCKSwingTable_Ch1_Ch13[priv->CCK_index][0] + + (CCKSwingTable_Ch1_Ch13[priv->CCK_index][1]<<8) ; + rtl8192_setBBreg(dev, rCCK0_TxFilter1, bMaskHWord, TempVal); + RT_TRACE(COMP_POWER_TRACKING, "CCK not chnl 14, reg 0x%x = 0x%x\n", + rCCK0_TxFilter1, TempVal); + //Write 0xa24 ~ 0xa27 + TempVal = 0; + TempVal = CCKSwingTable_Ch1_Ch13[priv->CCK_index][2] + + (CCKSwingTable_Ch1_Ch13[priv->CCK_index][3]<<8) + + (CCKSwingTable_Ch1_Ch13[priv->CCK_index][4]<<16 )+ + (CCKSwingTable_Ch1_Ch13[priv->CCK_index][5]<<24); + rtl8192_setBBreg(dev, rCCK0_TxFilter2, bMaskDWord, TempVal); + RT_TRACE(COMP_POWER_TRACKING, "CCK not chnl 14, reg 0x%x = 0x%x\n", + rCCK0_TxFilter2, TempVal); + //Write 0xa28 0xa29 + TempVal = 0; + TempVal = CCKSwingTable_Ch1_Ch13[priv->CCK_index][6] + + (CCKSwingTable_Ch1_Ch13[priv->CCK_index][7]<<8) ; + + rtl8192_setBBreg(dev, rCCK0_DebugPort, bMaskLWord, TempVal); + RT_TRACE(COMP_POWER_TRACKING, "CCK not chnl 14, reg 0x%x = 0x%x\n", + rCCK0_DebugPort, TempVal); + } + else + { +// priv->CCKTxPowerAdjustCntNotCh14++; //cosa add for debug. + //Write 0xa22 0xa23 + TempVal = CCKSwingTable_Ch14[priv->CCK_index][0] + + (CCKSwingTable_Ch14[priv->CCK_index][1]<<8) ; + + rtl8192_setBBreg(dev, rCCK0_TxFilter1, bMaskHWord, TempVal); + RT_TRACE(COMP_POWER_TRACKING, "CCK chnl 14, reg 0x%x = 0x%x\n", + rCCK0_TxFilter1, TempVal); + //Write 0xa24 ~ 0xa27 + TempVal = 0; + TempVal = CCKSwingTable_Ch14[priv->CCK_index][2] + + (CCKSwingTable_Ch14[priv->CCK_index][3]<<8) + + (CCKSwingTable_Ch14[priv->CCK_index][4]<<16 )+ + (CCKSwingTable_Ch14[priv->CCK_index][5]<<24); + rtl8192_setBBreg(dev, rCCK0_TxFilter2, bMaskDWord, TempVal); + RT_TRACE(COMP_POWER_TRACKING, "CCK chnl 14, reg 0x%x = 0x%x\n", + rCCK0_TxFilter2, TempVal); + //Write 0xa28 0xa29 + TempVal = 0; + TempVal = CCKSwingTable_Ch14[priv->CCK_index][6] + + (CCKSwingTable_Ch14[priv->CCK_index][7]<<8) ; + + rtl8192_setBBreg(dev, rCCK0_DebugPort, bMaskLWord, TempVal); + RT_TRACE(COMP_POWER_TRACKING,"CCK chnl 14, reg 0x%x = 0x%x\n", + rCCK0_DebugPort, TempVal); + } +} + + + +extern void dm_cck_txpower_adjust( + struct net_device *dev, + bool binch14 +) +{ // dm_CCKTxPowerAdjust + + struct r8192_priv *priv = ieee80211_priv(dev); +#ifdef RTL8190P + dm_CCKTxPowerAdjust_TSSI(dev, binch14); +#else + if(priv->bDcut == TRUE) + dm_CCKTxPowerAdjust_TSSI(dev, binch14); + else + dm_CCKTxPowerAdjust_ThermalMeter(dev, binch14); +#endif +} + + +#ifndef RTL8192U +static void dm_txpower_reset_recovery( + struct net_device *dev +) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + + RT_TRACE(COMP_POWER_TRACKING, "Start Reset Recovery ==>\n"); + rtl8192_setBBreg(dev, rOFDM0_XATxIQImbalance, bMaskDWord, priv->txbbgain_table[priv->rfa_txpowertrackingindex].txbbgain_value); + RT_TRACE(COMP_POWER_TRACKING, "Reset Recovery: Fill in 0xc80 is %08x\n",priv->txbbgain_table[priv->rfa_txpowertrackingindex].txbbgain_value); + RT_TRACE(COMP_POWER_TRACKING, "Reset Recovery: Fill in RFA_txPowerTrackingIndex is %x\n",priv->rfa_txpowertrackingindex); + RT_TRACE(COMP_POWER_TRACKING, "Reset Recovery : RF A I/Q Amplify Gain is %ld\n",priv->txbbgain_table[priv->rfa_txpowertrackingindex].txbb_iq_amplifygain); + RT_TRACE(COMP_POWER_TRACKING, "Reset Recovery: CCK Attenuation is %d dB\n",priv->cck_present_attentuation); + dm_cck_txpower_adjust(dev,priv->bcck_in_ch14); + + rtl8192_setBBreg(dev, rOFDM0_XCTxIQImbalance, bMaskDWord, priv->txbbgain_table[priv->rfc_txpowertrackingindex].txbbgain_value); + RT_TRACE(COMP_POWER_TRACKING, "Reset Recovery: Fill in 0xc90 is %08x\n",priv->txbbgain_table[priv->rfc_txpowertrackingindex].txbbgain_value); + RT_TRACE(COMP_POWER_TRACKING, "Reset Recovery: Fill in RFC_txPowerTrackingIndex is %x\n",priv->rfc_txpowertrackingindex); + RT_TRACE(COMP_POWER_TRACKING, "Reset Recovery : RF C I/Q Amplify Gain is %ld\n",priv->txbbgain_table[priv->rfc_txpowertrackingindex].txbb_iq_amplifygain); + +} // dm_TXPowerResetRecovery + +extern void dm_restore_dynamic_mechanism_state(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + u32 reg_ratr = priv->rate_adaptive.last_ratr; + + if(!priv->up) + { + RT_TRACE(COMP_RATE, "<---- dm_restore_dynamic_mechanism_state(): driver is going to unload\n"); + return; + } + + // + // Restore previous state for rate adaptive + // + if(priv->rate_adaptive.rate_adaptive_disabled) + return; + // TODO: Only 11n mode is implemented currently, + if( !(priv->ieee80211->mode==WIRELESS_MODE_N_24G || + priv->ieee80211->mode==WIRELESS_MODE_N_5G)) + return; + { + /* 2007/11/15 MH Copy from 8190PCI. */ + u32 ratr_value; + ratr_value = reg_ratr; + if(priv->rf_type == RF_1T2R) // 1T2R, Spatial Stream 2 should be disabled + { + ratr_value &=~ (RATE_ALL_OFDM_2SS); + //DbgPrint("HW_VAR_TATR_0 from 0x%x ==> 0x%x\n", ((pu4Byte)(val))[0], ratr_value); + } + //DbgPrint("set HW_VAR_TATR_0 = 0x%x\n", ratr_value); + //cosa PlatformEFIOWrite4Byte(Adapter, RATR0, ((pu4Byte)(val))[0]); + write_nic_dword(dev, RATR0, ratr_value); + write_nic_byte(dev, UFWP, 1); +#if 0 // Disable old code. + u1Byte index; + u4Byte input_value; + index = (u1Byte)((((pu4Byte)(val))[0]) >> 28); + input_value = (((pu4Byte)(val))[0]) & 0x0fffffff; + // TODO: Correct it. Emily 2007.01.11 + PlatformEFIOWrite4Byte(Adapter, RATR0+index*4, input_value); +#endif + } + //Resore TX Power Tracking Index + if(priv->btxpower_trackingInit && priv->btxpower_tracking){ + dm_txpower_reset_recovery(dev); + } + + // + //Restore BB Initial Gain + // + dm_bb_initialgain_restore(dev); + +} // DM_RestoreDynamicMechanismState + +static void dm_bb_initialgain_restore(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + u32 bit_mask = 0x7f; //Bit0~ Bit6 + + if(dm_digtable.dig_algorithm == DIG_ALGO_BY_RSSI) + return; + + //Disable Initial Gain + //PHY_SetBBReg(Adapter, UFWP, bMaskLWord, 0x800); + rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x8); // Only clear byte 1 and rewrite. + rtl8192_setBBreg(dev, rOFDM0_XAAGCCore1, bit_mask, (u32)priv->initgain_backup.xaagccore1); + rtl8192_setBBreg(dev, rOFDM0_XBAGCCore1, bit_mask, (u32)priv->initgain_backup.xbagccore1); + rtl8192_setBBreg(dev, rOFDM0_XCAGCCore1, bit_mask, (u32)priv->initgain_backup.xcagccore1); + rtl8192_setBBreg(dev, rOFDM0_XDAGCCore1, bit_mask, (u32)priv->initgain_backup.xdagccore1); + bit_mask = bMaskByte2; + rtl8192_setBBreg(dev, rCCK0_CCA, bit_mask, (u32)priv->initgain_backup.cca); + + RT_TRACE(COMP_DIG, "dm_BBInitialGainRestore 0xc50 is %x\n",priv->initgain_backup.xaagccore1); + RT_TRACE(COMP_DIG, "dm_BBInitialGainRestore 0xc58 is %x\n",priv->initgain_backup.xbagccore1); + RT_TRACE(COMP_DIG, "dm_BBInitialGainRestore 0xc60 is %x\n",priv->initgain_backup.xcagccore1); + RT_TRACE(COMP_DIG, "dm_BBInitialGainRestore 0xc68 is %x\n",priv->initgain_backup.xdagccore1); + RT_TRACE(COMP_DIG, "dm_BBInitialGainRestore 0xa0a is %x\n",priv->initgain_backup.cca); + //Enable Initial Gain + //PHY_SetBBReg(Adapter, UFWP, bMaskLWord, 0x100); + rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x1); // Only clear byte 1 and rewrite. + +} // dm_BBInitialGainRestore + + +extern void dm_backup_dynamic_mechanism_state(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + + // Fsync to avoid reset + priv->bswitch_fsync = false; + priv->bfsync_processing = false; + //Backup BB InitialGain + dm_bb_initialgain_backup(dev); + +} // DM_BackupDynamicMechanismState + + +static void dm_bb_initialgain_backup(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + u32 bit_mask = bMaskByte0; //Bit0~ Bit6 + + if(dm_digtable.dig_algorithm == DIG_ALGO_BY_RSSI) + return; + + //PHY_SetBBReg(Adapter, UFWP, bMaskLWord, 0x800); + rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x8); // Only clear byte 1 and rewrite. + priv->initgain_backup.xaagccore1 = (u8)rtl8192_QueryBBReg(dev, rOFDM0_XAAGCCore1, bit_mask); + priv->initgain_backup.xbagccore1 = (u8)rtl8192_QueryBBReg(dev, rOFDM0_XBAGCCore1, bit_mask); + priv->initgain_backup.xcagccore1 = (u8)rtl8192_QueryBBReg(dev, rOFDM0_XCAGCCore1, bit_mask); + priv->initgain_backup.xdagccore1 = (u8)rtl8192_QueryBBReg(dev, rOFDM0_XDAGCCore1, bit_mask); + bit_mask = bMaskByte2; + priv->initgain_backup.cca = (u8)rtl8192_QueryBBReg(dev, rCCK0_CCA, bit_mask); + + RT_TRACE(COMP_DIG, "BBInitialGainBackup 0xc50 is %x\n",priv->initgain_backup.xaagccore1); + RT_TRACE(COMP_DIG, "BBInitialGainBackup 0xc58 is %x\n",priv->initgain_backup.xbagccore1); + RT_TRACE(COMP_DIG, "BBInitialGainBackup 0xc60 is %x\n",priv->initgain_backup.xcagccore1); + RT_TRACE(COMP_DIG, "BBInitialGainBackup 0xc68 is %x\n",priv->initgain_backup.xdagccore1); + RT_TRACE(COMP_DIG, "BBInitialGainBackup 0xa0a is %x\n",priv->initgain_backup.cca); + +} // dm_BBInitialGainBakcup + +#endif +/*----------------------------------------------------------------------------- + * Function: dm_change_dynamic_initgain_thresh() + * + * Overview: + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 05/29/2008 amy Create Version 0 porting from windows code. + * + *---------------------------------------------------------------------------*/ +extern void dm_change_dynamic_initgain_thresh(struct net_device *dev, + u32 dm_type, + u32 dm_value) +{ +#ifdef RTL8192SU + struct r8192_priv *priv = ieee80211_priv(dev); + if(dm_type == DIG_TYPE_THRESH_HIGHPWR_HIGH) + priv->MidHighPwrTHR_L2 = (u8)dm_value; + else if(dm_type == DIG_TYPE_THRESH_HIGHPWR_LOW) + priv->MidHighPwrTHR_L1 = (u8)dm_value; + return; +#endif + if (dm_type == DIG_TYPE_THRESH_HIGH) + { + dm_digtable.rssi_high_thresh = dm_value; + } + else if (dm_type == DIG_TYPE_THRESH_LOW) + { + dm_digtable.rssi_low_thresh = dm_value; + } + else if (dm_type == DIG_TYPE_THRESH_HIGHPWR_HIGH) + { + dm_digtable.rssi_high_power_highthresh = dm_value; + } + else if (dm_type == DIG_TYPE_THRESH_HIGHPWR_HIGH) + { + dm_digtable.rssi_high_power_highthresh = dm_value; + } + else if (dm_type == DIG_TYPE_ENABLE) + { + dm_digtable.dig_state = DM_STA_DIG_MAX; + dm_digtable.dig_enable_flag = true; + } + else if (dm_type == DIG_TYPE_DISABLE) + { + dm_digtable.dig_state = DM_STA_DIG_MAX; + dm_digtable.dig_enable_flag = false; + } + else if (dm_type == DIG_TYPE_DBG_MODE) + { + if(dm_value >= DM_DBG_MAX) + dm_value = DM_DBG_OFF; + dm_digtable.dbg_mode = (u8)dm_value; + } + else if (dm_type == DIG_TYPE_RSSI) + { + if(dm_value > 100) + dm_value = 30; + dm_digtable.rssi_val = (long)dm_value; + } + else if (dm_type == DIG_TYPE_ALGORITHM) + { + if (dm_value >= DIG_ALGO_MAX) + dm_value = DIG_ALGO_BY_FALSE_ALARM; + if(dm_digtable.dig_algorithm != (u8)dm_value) + dm_digtable.dig_algorithm_switch = 1; + dm_digtable.dig_algorithm = (u8)dm_value; + } + else if (dm_type == DIG_TYPE_BACKOFF) + { + if(dm_value > 30) + dm_value = 30; + dm_digtable.backoff_val = (u8)dm_value; + } + else if(dm_type == DIG_TYPE_RX_GAIN_MIN) + { + if(dm_value == 0) + dm_value = 0x1; + dm_digtable.rx_gain_range_min = (u8)dm_value; + } + else if(dm_type == DIG_TYPE_RX_GAIN_MAX) + { + if(dm_value > 0x50) + dm_value = 0x50; + dm_digtable.rx_gain_range_max = (u8)dm_value; + } +} /* DM_ChangeDynamicInitGainThresh */ +extern void +dm_change_fsync_setting( + struct net_device *dev, + s32 DM_Type, + s32 DM_Value) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + + if (DM_Type == 0) // monitor 0xc38 register + { + if(DM_Value > 1) + DM_Value = 1; + priv->framesyncMonitor = (u8)DM_Value; + //DbgPrint("pHalData->framesyncMonitor = %d", pHalData->framesyncMonitor); + } +} + +extern void +dm_change_rxpath_selection_setting( + struct net_device *dev, + s32 DM_Type, + s32 DM_Value) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + prate_adaptive pRA = (prate_adaptive)&(priv->rate_adaptive); + + + if(DM_Type == 0) + { + if(DM_Value > 1) + DM_Value = 1; + DM_RxPathSelTable.Enable = (u8)DM_Value; + } + else if(DM_Type == 1) + { + if(DM_Value > 1) + DM_Value = 1; + DM_RxPathSelTable.DbgMode = (u8)DM_Value; + } + else if(DM_Type == 2) + { + if(DM_Value > 40) + DM_Value = 40; + DM_RxPathSelTable.SS_TH_low = (u8)DM_Value; + } + else if(DM_Type == 3) + { + if(DM_Value > 25) + DM_Value = 25; + DM_RxPathSelTable.diff_TH = (u8)DM_Value; + } + else if(DM_Type == 4) + { + if(DM_Value >= CCK_Rx_Version_MAX) + DM_Value = CCK_Rx_Version_1; + DM_RxPathSelTable.cck_method= (u8)DM_Value; + } + else if(DM_Type == 10) + { + if(DM_Value > 100) + DM_Value = 50; + DM_RxPathSelTable.rf_rssi[0] = (u8)DM_Value; + } + else if(DM_Type == 11) + { + if(DM_Value > 100) + DM_Value = 50; + DM_RxPathSelTable.rf_rssi[1] = (u8)DM_Value; + } + else if(DM_Type == 12) + { + if(DM_Value > 100) + DM_Value = 50; + DM_RxPathSelTable.rf_rssi[2] = (u8)DM_Value; + } + else if(DM_Type == 13) + { + if(DM_Value > 100) + DM_Value = 50; + DM_RxPathSelTable.rf_rssi[3] = (u8)DM_Value; + } + else if(DM_Type == 20) + { + if(DM_Value > 1) + DM_Value = 1; + pRA->ping_rssi_enable = (u8)DM_Value; + } + else if(DM_Type == 21) + { + if(DM_Value > 30) + DM_Value = 30; + pRA->ping_rssi_thresh_for_ra = DM_Value; + } +} + +#if 0 +extern void dm_force_tx_fw_info(struct net_device *dev, + u32 force_type, + u32 force_value) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + + if (force_type == 0) // don't force TxSC + { + //DbgPrint("Set Force SubCarrier Off\n"); + priv->tx_fwinfo_force_subcarriermode = 0; + } + else if(force_type == 1) //force + { + //DbgPrint("Set Force SubCarrier On\n"); + priv->tx_fwinfo_force_subcarriermode = 1; + if(force_value > 3) + force_value = 3; + priv->tx_fwinfo_force_subcarrierval = (u8)force_value; + } +} +#endif + +/*----------------------------------------------------------------------------- + * Function: dm_dig_init() + * + * Overview: Set DIG scheme init value. + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 05/15/2008 amy Create Version 0 porting from windows code. + * + *---------------------------------------------------------------------------*/ +static void dm_dig_init(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + /* 2007/10/05 MH Disable DIG scheme now. Not tested. */ + dm_digtable.dig_enable_flag = true; + dm_digtable.dig_algorithm = DIG_ALGO_BY_RSSI; + dm_digtable.dbg_mode = DM_DBG_OFF; //off=by real rssi value, on=by DM_DigTable.Rssi_val for new dig + dm_digtable.dig_algorithm_switch = 0; + + /* 2007/10/04 MH Define init gain threshol. */ + dm_digtable.dig_state = DM_STA_DIG_MAX; + dm_digtable.dig_highpwr_state = DM_STA_DIG_MAX; + dm_digtable.initialgain_lowerbound_state = false; + + dm_digtable.rssi_low_thresh = DM_DIG_THRESH_LOW; + dm_digtable.rssi_high_thresh = DM_DIG_THRESH_HIGH; + + dm_digtable.rssi_high_power_lowthresh = DM_DIG_HIGH_PWR_THRESH_LOW; + dm_digtable.rssi_high_power_highthresh = DM_DIG_HIGH_PWR_THRESH_HIGH; + + dm_digtable.rssi_val = 50; //for new dig debug rssi value + dm_digtable.backoff_val = DM_DIG_BACKOFF; + dm_digtable.rx_gain_range_max = DM_DIG_MAX; + if(priv->CustomerID == RT_CID_819x_Netcore) + dm_digtable.rx_gain_range_min = DM_DIG_MIN_Netcore; + else + dm_digtable.rx_gain_range_min = DM_DIG_MIN; + +} /* dm_dig_init */ + + +/*----------------------------------------------------------------------------- + * Function: dm_ctrl_initgain_byrssi() + * + * Overview: Driver must monitor RSSI and notify firmware to change initial + * gain according to different threshold. BB team provide the + * suggested solution. + * + * Input: struct net_device *dev + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 05/27/2008 amy Create Version 0 porting from windows code. + *---------------------------------------------------------------------------*/ +static void dm_ctrl_initgain_byrssi(struct net_device *dev) +{ + + if (dm_digtable.dig_enable_flag == false) + return; + + if(dm_digtable.dig_algorithm == DIG_ALGO_BY_FALSE_ALARM) + dm_ctrl_initgain_byrssi_by_fwfalse_alarm(dev); + else if(dm_digtable.dig_algorithm == DIG_ALGO_BY_RSSI) + dm_ctrl_initgain_byrssi_by_driverrssi(dev); +// ; + else + return; +} + + +static void dm_ctrl_initgain_byrssi_by_driverrssi( + struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + u8 i; + static u8 fw_dig=0; + + if (dm_digtable.dig_enable_flag == false) + return; + + //DbgPrint("Dig by Sw Rssi \n"); + if(dm_digtable.dig_algorithm_switch) // if swithed algorithm, we have to disable FW Dig. + fw_dig = 0; + if(fw_dig <= 3) // execute several times to make sure the FW Dig is disabled + {// FW DIG Off + for(i=0; i<3; i++) + rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x8); // Only clear byte 1 and rewrite. + fw_dig++; + dm_digtable.dig_state = DM_STA_DIG_OFF; //fw dig off. + } + + if(priv->ieee80211->state == IEEE80211_LINKED) + dm_digtable.cur_connect_state = DIG_CONNECT; + else + dm_digtable.cur_connect_state = DIG_DISCONNECT; + + //DbgPrint("DM_DigTable.PreConnectState = %d, DM_DigTable.CurConnectState = %d \n", + //DM_DigTable.PreConnectState, DM_DigTable.CurConnectState); + + if(dm_digtable.dbg_mode == DM_DBG_OFF) + dm_digtable.rssi_val = priv->undecorated_smoothed_pwdb; + //DbgPrint("DM_DigTable.Rssi_val = %d \n", DM_DigTable.Rssi_val); + dm_initial_gain(dev); + dm_pd_th(dev); + dm_cs_ratio(dev); + if(dm_digtable.dig_algorithm_switch) + dm_digtable.dig_algorithm_switch = 0; + dm_digtable.pre_connect_state = dm_digtable.cur_connect_state; + +} /* dm_CtrlInitGainByRssi */ + +static void dm_ctrl_initgain_byrssi_by_fwfalse_alarm( + struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + static u32 reset_cnt = 0; + u8 i; + + if (dm_digtable.dig_enable_flag == false) + return; + + if(dm_digtable.dig_algorithm_switch) + { + dm_digtable.dig_state = DM_STA_DIG_MAX; + // Fw DIG On. + for(i=0; i<3; i++) + rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x1); // Only clear byte 1 and rewrite. + dm_digtable.dig_algorithm_switch = 0; + } + + if (priv->ieee80211->state != IEEE80211_LINKED) + return; + + // For smooth, we can not change DIG state. + if ((priv->undecorated_smoothed_pwdb > dm_digtable.rssi_low_thresh) && + (priv->undecorated_smoothed_pwdb < dm_digtable.rssi_high_thresh)) + { + return; + } + //DbgPrint("Dig by Fw False Alarm\n"); + //if (DM_DigTable.Dig_State == DM_STA_DIG_OFF) + /*DbgPrint("DIG Check\n\r RSSI=%d LOW=%d HIGH=%d STATE=%d", + pHalData->UndecoratedSmoothedPWDB, DM_DigTable.RssiLowThresh, + DM_DigTable.RssiHighThresh, DM_DigTable.Dig_State);*/ + /* 1. When RSSI decrease, We have to judge if it is smaller than a treshold + and then execute below step. */ + if ((priv->undecorated_smoothed_pwdb <= dm_digtable.rssi_low_thresh)) + { + /* 2008/02/05 MH When we execute silent reset, the DIG PHY parameters + will be reset to init value. We must prevent the condition. */ + if (dm_digtable.dig_state == DM_STA_DIG_OFF && + (priv->reset_count == reset_cnt)) + { + return; + } + else + { + reset_cnt = priv->reset_count; + } + + // If DIG is off, DIG high power state must reset. + dm_digtable.dig_highpwr_state = DM_STA_DIG_MAX; + dm_digtable.dig_state = DM_STA_DIG_OFF; + + // 1.1 DIG Off. + rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x8); // Only clear byte 1 and rewrite. + + // 1.2 Set initial gain. + write_nic_byte(dev, rOFDM0_XAAGCCore1, 0x17); + write_nic_byte(dev, rOFDM0_XBAGCCore1, 0x17); + write_nic_byte(dev, rOFDM0_XCAGCCore1, 0x17); + write_nic_byte(dev, rOFDM0_XDAGCCore1, 0x17); + + // 1.3 Lower PD_TH for OFDM. + if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) + { + /* 2008/01/11 MH 40MHZ 90/92 register are not the same. */ + // 2008/02/05 MH SD3-Jerry 92U/92E PD_TH are the same. +#ifdef RTL8192SU + rtl8192_setBBreg(dev, (rOFDM0_XATxAFE+3), bMaskByte0, 0x00); +#else + #ifdef RTL8190P + write_nic_byte(dev, rOFDM0_RxDetector1, 0x40); + #else + write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x00); + #endif +#endif + /*else if (priv->card_8192 == HARDWARE_TYPE_RTL8190P) + write_nic_byte(pAdapter, rOFDM0_RxDetector1, 0x40); + */ + //else if (pAdapter->HardwareType == HARDWARE_TYPE_RTL8192E) + + + //else + //PlatformEFIOWrite1Byte(pAdapter, rOFDM0_RxDetector1, 0x40); + } + else + write_nic_byte(dev, rOFDM0_RxDetector1, 0x42); + + // 1.4 Lower CS ratio for CCK. + write_nic_byte(dev, 0xa0a, 0x08); + + // 1.5 Higher EDCCA. + //PlatformEFIOWrite4Byte(pAdapter, rOFDM0_ECCAThreshold, 0x325); + return; + + } + + /* 2. When RSSI increase, We have to judge if it is larger than a treshold + and then execute below step. */ + if ((priv->undecorated_smoothed_pwdb >= dm_digtable.rssi_high_thresh) ) + { + u8 reset_flag = 0; + + if (dm_digtable.dig_state == DM_STA_DIG_ON && + (priv->reset_count == reset_cnt)) + { + dm_ctrl_initgain_byrssi_highpwr(dev); + return; + } + else + { + if (priv->reset_count != reset_cnt) + reset_flag = 1; + + reset_cnt = priv->reset_count; + } + + dm_digtable.dig_state = DM_STA_DIG_ON; + //DbgPrint("DIG ON\n\r"); + + // 2.1 Set initial gain. + // 2008/02/26 MH SD3-Jerry suggest to prevent dirty environment. + if (reset_flag == 1) + { + write_nic_byte(dev, rOFDM0_XAAGCCore1, 0x2c); + write_nic_byte(dev, rOFDM0_XBAGCCore1, 0x2c); + write_nic_byte(dev, rOFDM0_XCAGCCore1, 0x2c); + write_nic_byte(dev, rOFDM0_XDAGCCore1, 0x2c); + } + else + { + write_nic_byte(dev, rOFDM0_XAAGCCore1, 0x20); + write_nic_byte(dev, rOFDM0_XBAGCCore1, 0x20); + write_nic_byte(dev, rOFDM0_XCAGCCore1, 0x20); + write_nic_byte(dev, rOFDM0_XDAGCCore1, 0x20); + } + + // 2.2 Higher PD_TH for OFDM. + if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) + { + /* 2008/01/11 MH 40MHZ 90/92 register are not the same. */ + // 2008/02/05 MH SD3-Jerry 92U/92E PD_TH are the same. + #ifdef RTL8190P + write_nic_byte(dev, rOFDM0_RxDetector1, 0x42); + #else + write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x20); + #endif + /* + else if (priv->card_8192 == HARDWARE_TYPE_RTL8190P) + write_nic_byte(dev, rOFDM0_RxDetector1, 0x42); + */ + //else if (pAdapter->HardwareType == HARDWARE_TYPE_RTL8192E) + + //else + //PlatformEFIOWrite1Byte(pAdapter, rOFDM0_RxDetector1, 0x42); + } + else + write_nic_byte(dev, rOFDM0_RxDetector1, 0x44); + + // 2.3 Higher CS ratio for CCK. + write_nic_byte(dev, 0xa0a, 0xcd); + + // 2.4 Lower EDCCA. + /* 2008/01/11 MH 90/92 series are the same. */ + //PlatformEFIOWrite4Byte(pAdapter, rOFDM0_ECCAThreshold, 0x346); + + // 2.5 DIG On. + rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x1); // Only clear byte 1 and rewrite. + + } + + dm_ctrl_initgain_byrssi_highpwr(dev); + +} /* dm_CtrlInitGainByRssi */ + + +/*----------------------------------------------------------------------------- + * Function: dm_ctrl_initgain_byrssi_highpwr() + * + * Overview: + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 05/28/2008 amy Create Version 0 porting from windows code. + * + *---------------------------------------------------------------------------*/ +static void dm_ctrl_initgain_byrssi_highpwr( + struct net_device * dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + static u32 reset_cnt_highpwr = 0; + + // For smooth, we can not change high power DIG state in the range. + if ((priv->undecorated_smoothed_pwdb > dm_digtable.rssi_high_power_lowthresh) && + (priv->undecorated_smoothed_pwdb < dm_digtable.rssi_high_power_highthresh)) + { + return; + } + + /* 3. When RSSI >75% or <70%, it is a high power issue. We have to judge if + it is larger than a treshold and then execute below step. */ + // 2008/02/05 MH SD3-Jerry Modify PD_TH for high power issue. + if (priv->undecorated_smoothed_pwdb >= dm_digtable.rssi_high_power_highthresh) + { + if (dm_digtable.dig_highpwr_state == DM_STA_DIG_ON && + (priv->reset_count == reset_cnt_highpwr)) + return; + else + dm_digtable.dig_highpwr_state = DM_STA_DIG_ON; + + // 3.1 Higher PD_TH for OFDM for high power state. + if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) + { +#ifdef RTL8192SU + rtl8192_setBBreg(dev, (rOFDM0_XATxAFE+3), bMaskByte0, 0x10); +#else + #ifdef RTL8190P + write_nic_byte(dev, rOFDM0_RxDetector1, 0x41); + #else + write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x10); + #endif +#endif + /*else if (priv->card_8192 == HARDWARE_TYPE_RTL8190P) + write_nic_byte(dev, rOFDM0_RxDetector1, 0x41); + */ + + } + else + write_nic_byte(dev, rOFDM0_RxDetector1, 0x43); + } + else + { + if (dm_digtable.dig_highpwr_state == DM_STA_DIG_OFF&& + (priv->reset_count == reset_cnt_highpwr)) + return; + else + dm_digtable.dig_highpwr_state = DM_STA_DIG_OFF; + + if (priv->undecorated_smoothed_pwdb < dm_digtable.rssi_high_power_lowthresh && + priv->undecorated_smoothed_pwdb >= dm_digtable.rssi_high_thresh) + { + // 3.2 Recover PD_TH for OFDM for normal power region. + if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) + { + #ifdef RTL8190P + write_nic_byte(dev, rOFDM0_RxDetector1, 0x42); + #else + write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x20); + #endif + /*else if (priv->card_8192 == HARDWARE_TYPE_RTL8190P) + write_nic_byte(dev, rOFDM0_RxDetector1, 0x42); + */ + + } + else + write_nic_byte(dev, rOFDM0_RxDetector1, 0x44); + } + } + + reset_cnt_highpwr = priv->reset_count; + +} /* dm_CtrlInitGainByRssiHighPwr */ + + +static void dm_initial_gain( + struct net_device * dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + u8 initial_gain=0; + static u8 initialized=0, force_write=0; + static u32 reset_cnt=0; + + if(dm_digtable.dig_algorithm_switch) + { + initialized = 0; + reset_cnt = 0; + } + + if(dm_digtable.pre_connect_state == dm_digtable.cur_connect_state) + { + if(dm_digtable.cur_connect_state == DIG_CONNECT) + { + if((dm_digtable.rssi_val+10-dm_digtable.backoff_val) > dm_digtable.rx_gain_range_max) + dm_digtable.cur_ig_value = dm_digtable.rx_gain_range_max; + else if((dm_digtable.rssi_val+10-dm_digtable.backoff_val) < dm_digtable.rx_gain_range_min) + dm_digtable.cur_ig_value = dm_digtable.rx_gain_range_min; + else + dm_digtable.cur_ig_value = dm_digtable.rssi_val+10-dm_digtable.backoff_val; + } + else //current state is disconnected + { + if(dm_digtable.cur_ig_value == 0) + dm_digtable.cur_ig_value = priv->DefaultInitialGain[0]; + else + dm_digtable.cur_ig_value = dm_digtable.pre_ig_value; + } + } + else // disconnected -> connected or connected -> disconnected + { + dm_digtable.cur_ig_value = priv->DefaultInitialGain[0]; + dm_digtable.pre_ig_value = 0; + } + //DbgPrint("DM_DigTable.CurIGValue = 0x%x, DM_DigTable.PreIGValue = 0x%x\n", DM_DigTable.CurIGValue, DM_DigTable.PreIGValue); + + // if silent reset happened, we should rewrite the values back + if(priv->reset_count != reset_cnt) + { + force_write = 1; + reset_cnt = priv->reset_count; + } + + if(dm_digtable.pre_ig_value != read_nic_byte(dev, rOFDM0_XAAGCCore1)) + force_write = 1; + + { + if((dm_digtable.pre_ig_value != dm_digtable.cur_ig_value) + || !initialized || force_write) + { + initial_gain = (u8)dm_digtable.cur_ig_value; + //DbgPrint("Write initial gain = 0x%x\n", initial_gain); + // Set initial gain. + write_nic_byte(dev, rOFDM0_XAAGCCore1, initial_gain); + write_nic_byte(dev, rOFDM0_XBAGCCore1, initial_gain); + write_nic_byte(dev, rOFDM0_XCAGCCore1, initial_gain); + write_nic_byte(dev, rOFDM0_XDAGCCore1, initial_gain); + dm_digtable.pre_ig_value = dm_digtable.cur_ig_value; + initialized = 1; + force_write = 0; + } + } +} + +static void dm_pd_th( + struct net_device * dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + static u8 initialized=0, force_write=0; + static u32 reset_cnt = 0; + + if(dm_digtable.dig_algorithm_switch) + { + initialized = 0; + reset_cnt = 0; + } + + if(dm_digtable.pre_connect_state == dm_digtable.cur_connect_state) + { + if(dm_digtable.cur_connect_state == DIG_CONNECT) + { + if (dm_digtable.rssi_val >= dm_digtable.rssi_high_power_highthresh) + dm_digtable.curpd_thstate = DIG_PD_AT_HIGH_POWER; + else if ((dm_digtable.rssi_val <= dm_digtable.rssi_low_thresh)) + dm_digtable.curpd_thstate = DIG_PD_AT_LOW_POWER; + else if ((dm_digtable.rssi_val >= dm_digtable.rssi_high_thresh) && + (dm_digtable.rssi_val < dm_digtable.rssi_high_power_lowthresh)) + dm_digtable.curpd_thstate = DIG_PD_AT_NORMAL_POWER; + else + dm_digtable.curpd_thstate = dm_digtable.prepd_thstate; + } + else + { + dm_digtable.curpd_thstate = DIG_PD_AT_LOW_POWER; + } + } + else // disconnected -> connected or connected -> disconnected + { + dm_digtable.curpd_thstate = DIG_PD_AT_LOW_POWER; + } + + // if silent reset happened, we should rewrite the values back + if(priv->reset_count != reset_cnt) + { + force_write = 1; + reset_cnt = priv->reset_count; + } + + { + if((dm_digtable.prepd_thstate != dm_digtable.curpd_thstate) || + (initialized<=3) || force_write) + { + //DbgPrint("Write PD_TH state = %d\n", DM_DigTable.CurPD_THState); + if(dm_digtable.curpd_thstate == DIG_PD_AT_LOW_POWER) + { + // Lower PD_TH for OFDM. + if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) + { + /* 2008/01/11 MH 40MHZ 90/92 register are not the same. */ + // 2008/02/05 MH SD3-Jerry 92U/92E PD_TH are the same. +#ifdef RTL8192SU + rtl8192_setBBreg(dev, (rOFDM0_XATxAFE+3), bMaskByte0, 0x00); +#else + #ifdef RTL8190P + write_nic_byte(dev, rOFDM0_RxDetector1, 0x40); + #else + write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x00); + #endif +#endif + /*else if (priv->card_8192 == HARDWARE_TYPE_RTL8190P) + write_nic_byte(dev, rOFDM0_RxDetector1, 0x40); + */ + } + else + write_nic_byte(dev, rOFDM0_RxDetector1, 0x42); + } + else if(dm_digtable.curpd_thstate == DIG_PD_AT_NORMAL_POWER) + { + // Higher PD_TH for OFDM. + if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) + { + /* 2008/01/11 MH 40MHZ 90/92 register are not the same. */ + // 2008/02/05 MH SD3-Jerry 92U/92E PD_TH are the same. + #ifdef RTL8190P + write_nic_byte(dev, rOFDM0_RxDetector1, 0x42); + #else + write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x20); + #endif + /*else if (priv->card_8192 == HARDWARE_TYPE_RTL8190P) + write_nic_byte(dev, rOFDM0_RxDetector1, 0x42); + */ + } + else + write_nic_byte(dev, rOFDM0_RxDetector1, 0x44); + } + else if(dm_digtable.curpd_thstate == DIG_PD_AT_HIGH_POWER) + { + // Higher PD_TH for OFDM for high power state. + if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) + { + #ifdef RTL8190P + write_nic_byte(dev, rOFDM0_RxDetector1, 0x41); + #else + write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x10); + #endif + /*else if (priv->card_8192 == HARDWARE_TYPE_RTL8190P) + write_nic_byte(dev, rOFDM0_RxDetector1, 0x41); + */ + } + else + write_nic_byte(dev, rOFDM0_RxDetector1, 0x43); + } + dm_digtable.prepd_thstate = dm_digtable.curpd_thstate; + if(initialized <= 3) + initialized++; + force_write = 0; + } + } +} + +static void dm_cs_ratio( + struct net_device * dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + static u8 initialized=0,force_write=0; + static u32 reset_cnt = 0; + + if(dm_digtable.dig_algorithm_switch) + { + initialized = 0; + reset_cnt = 0; + } + + if(dm_digtable.pre_connect_state == dm_digtable.cur_connect_state) + { + if(dm_digtable.cur_connect_state == DIG_CONNECT) + { + if ((dm_digtable.rssi_val <= dm_digtable.rssi_low_thresh)) + dm_digtable.curcs_ratio_state = DIG_CS_RATIO_LOWER; + else if ((dm_digtable.rssi_val >= dm_digtable.rssi_high_thresh) ) + dm_digtable.curcs_ratio_state = DIG_CS_RATIO_HIGHER; + else + dm_digtable.curcs_ratio_state = dm_digtable.precs_ratio_state; + } + else + { + dm_digtable.curcs_ratio_state = DIG_CS_RATIO_LOWER; + } + } + else // disconnected -> connected or connected -> disconnected + { + dm_digtable.curcs_ratio_state = DIG_CS_RATIO_LOWER; + } + + // if silent reset happened, we should rewrite the values back + if(priv->reset_count != reset_cnt) + { + force_write = 1; + reset_cnt = priv->reset_count; + } + + + { + if((dm_digtable.precs_ratio_state != dm_digtable.curcs_ratio_state) || + !initialized || force_write) + { + //DbgPrint("Write CS_ratio state = %d\n", DM_DigTable.CurCS_ratioState); + if(dm_digtable.curcs_ratio_state == DIG_CS_RATIO_LOWER) + { + // Lower CS ratio for CCK. + write_nic_byte(dev, 0xa0a, 0x08); + } + else if(dm_digtable.curcs_ratio_state == DIG_CS_RATIO_HIGHER) + { + // Higher CS ratio for CCK. + write_nic_byte(dev, 0xa0a, 0xcd); + } + dm_digtable.precs_ratio_state = dm_digtable.curcs_ratio_state; + initialized = 1; + force_write = 0; + } + } +} + +extern void dm_init_edca_turbo(struct net_device * dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + + priv->bcurrent_turbo_EDCA = false; + priv->ieee80211->bis_any_nonbepkts = false; + priv->bis_cur_rdlstate = false; +} // dm_init_edca_turbo + +#if 1 +static void dm_check_edca_turbo( + struct net_device * dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + PRT_HIGH_THROUGHPUT pHTInfo = priv->ieee80211->pHTInfo; + //PSTA_QOS pStaQos = pMgntInfo->pStaQos; + + // Keep past Tx/Rx packet count for RT-to-RT EDCA turbo. + static unsigned long lastTxOkCnt = 0; + static unsigned long lastRxOkCnt = 0; + unsigned long curTxOkCnt = 0; + unsigned long curRxOkCnt = 0; + + // + // Do not be Turbo if it's under WiFi config and Qos Enabled, because the EDCA parameters + // should follow the settings from QAP. By Bruce, 2007-12-07. + // + #if 1 + if(priv->ieee80211->state != IEEE80211_LINKED) + goto dm_CheckEdcaTurbo_EXIT; + #endif + // We do not turn on EDCA turbo mode for some AP that has IOT issue + if(priv->ieee80211->pHTInfo->IOTAction & HT_IOT_ACT_DISABLE_EDCA_TURBO) + goto dm_CheckEdcaTurbo_EXIT; + + { + u8* peername[11] = {"unknown", "realtek", "realtek_92se", "broadcom", "ralink", "atheros", "cisco", "marvell", "92u_softap", "self_softap"}; + static int wb_tmp = 0; + if (wb_tmp == 0){ + printk("%s():iot peer is %#x:%s, bssid:"MAC_FMT"\n",__FUNCTION__,pHTInfo->IOTPeer,peername[pHTInfo->IOTPeer], MAC_ARG(priv->ieee80211->current_network.bssid)); + wb_tmp = 1; + } + } + // Check the status for current condition. + if(!priv->ieee80211->bis_any_nonbepkts) + { + curTxOkCnt = priv->stats.txbytesunicast - lastTxOkCnt; + curRxOkCnt = priv->stats.rxbytesunicast - lastRxOkCnt; +#ifdef RTL8192SU + // Modify EDCA parameters selection bias + // For some APs, use downlink EDCA parameters for uplink+downlink + if(priv->ieee80211->pHTInfo->IOTAction & HT_IOT_ACT_EDCA_BIAS_ON_RX) + { + if(curTxOkCnt > 4*curRxOkCnt) + { + if(priv->bis_cur_rdlstate || !priv->bcurrent_turbo_EDCA) + { + write_nic_dword(dev, EDCAPARA_BE, edca_setting_UL[pHTInfo->IOTPeer]); + priv->bis_cur_rdlstate = false; + } + } + else + { + if(!priv->bis_cur_rdlstate || !priv->bcurrent_turbo_EDCA) + { + write_nic_dword(dev, EDCAPARA_BE, edca_setting_DL[pHTInfo->IOTPeer]); + priv->bis_cur_rdlstate = true; + } + } + priv->bcurrent_turbo_EDCA = true; + } + else + { + if(curRxOkCnt > 4*curTxOkCnt) + { + if(!priv->bis_cur_rdlstate || !priv->bcurrent_turbo_EDCA) + { + write_nic_dword(dev, EDCAPARA_BE, edca_setting_DL[pHTInfo->IOTPeer]); + priv->bis_cur_rdlstate = true; + } + } + else + { + if(priv->bis_cur_rdlstate || !priv->bcurrent_turbo_EDCA) + { + write_nic_dword(dev, EDCAPARA_BE, edca_setting_UL[pHTInfo->IOTPeer]); + priv->bis_cur_rdlstate = false; + } + } + priv->bcurrent_turbo_EDCA = true; + } +#else + // For RT-AP, we needs to turn it on when Rx>Tx + if(curRxOkCnt > 4*curTxOkCnt) + { + //printk("%s():curRxOkCnt > 4*curTxOkCnt\n"); + if(!priv->bis_cur_rdlstate || !priv->bcurrent_turbo_EDCA) + { + write_nic_dword(dev, EDCAPARA_BE, edca_setting_DL[pHTInfo->IOTPeer]); + priv->bis_cur_rdlstate = true; + } + } + else + { + + //printk("%s():curRxOkCnt < 4*curTxOkCnt\n"); + if(priv->bis_cur_rdlstate || !priv->bcurrent_turbo_EDCA) + { + write_nic_dword(dev, EDCAPARA_BE, edca_setting_UL[pHTInfo->IOTPeer]); + priv->bis_cur_rdlstate = false; + } + + } + + priv->bcurrent_turbo_EDCA = true; +#endif + } + else + { + // + // Turn Off EDCA turbo here. + // Restore original EDCA according to the declaration of AP. + // + if(priv->bcurrent_turbo_EDCA) + { + + { + u8 u1bAIFS; + u32 u4bAcParam; + struct ieee80211_qos_parameters *qos_parameters = &priv->ieee80211->current_network.qos_data.parameters; + u8 mode = priv->ieee80211->mode; + + // For Each time updating EDCA parameter, reset EDCA turbo mode status. + dm_init_edca_turbo(dev); + u1bAIFS = qos_parameters->aifs[0] * ((mode&(IEEE_G|IEEE_N_24G)) ?9:20) + aSifsTime; + u4bAcParam = ((((u32)(qos_parameters->tx_op_limit[0]))<< AC_PARAM_TXOP_LIMIT_OFFSET)| + (((u32)(qos_parameters->cw_max[0]))<< AC_PARAM_ECW_MAX_OFFSET)| + (((u32)(qos_parameters->cw_min[0]))<< AC_PARAM_ECW_MIN_OFFSET)| + ((u32)u1bAIFS << AC_PARAM_AIFS_OFFSET)); + //write_nic_dword(dev, WDCAPARA_ADD[i], u4bAcParam); + write_nic_dword(dev, EDCAPARA_BE, u4bAcParam); + + // Check ACM bit. + // If it is set, immediately set ACM control bit to downgrading AC for passing WMM testplan. Annie, 2005-12-13. + { + // TODO: Modified this part and try to set acm control in only 1 IO processing!! + + PACI_AIFSN pAciAifsn = (PACI_AIFSN)&(qos_parameters->aifs[0]); + u8 AcmCtrl = read_nic_byte( dev, AcmHwCtrl ); + if( pAciAifsn->f.ACM ) + { // ACM bit is 1. + AcmCtrl |= AcmHw_BeqEn; + } + else + { // ACM bit is 0. + AcmCtrl &= (~AcmHw_BeqEn); + } + + RT_TRACE( COMP_QOS,"SetHwReg8190pci(): [HW_VAR_ACM_CTRL] Write 0x%X\n", AcmCtrl ) ; + write_nic_byte(dev, AcmHwCtrl, AcmCtrl ); + } + } + priv->bcurrent_turbo_EDCA = false; + } + } + + +dm_CheckEdcaTurbo_EXIT: + // Set variables for next time. + priv->ieee80211->bis_any_nonbepkts = false; + lastTxOkCnt = priv->stats.txbytesunicast; + lastRxOkCnt = priv->stats.rxbytesunicast; +} // dm_CheckEdcaTurbo +#endif + +extern void DM_CTSToSelfSetting(struct net_device * dev,u32 DM_Type, u32 DM_Value) +{ + struct r8192_priv *priv = ieee80211_priv((struct net_device *)dev); + + if (DM_Type == 0) // CTS to self disable/enable + { + if(DM_Value > 1) + DM_Value = 1; + priv->ieee80211->bCTSToSelfEnable = (bool)DM_Value; + //DbgPrint("pMgntInfo->bCTSToSelfEnable = %d\n", pMgntInfo->bCTSToSelfEnable); + } + else if(DM_Type == 1) //CTS to self Th + { + if(DM_Value >= 50) + DM_Value = 50; + priv->ieee80211->CTSToSelfTH = (u8)DM_Value; + //DbgPrint("pMgntInfo->CTSToSelfTH = %d\n", pMgntInfo->CTSToSelfTH); + } +} + +static void dm_init_ctstoself(struct net_device * dev) +{ + struct r8192_priv *priv = ieee80211_priv((struct net_device *)dev); + + priv->ieee80211->bCTSToSelfEnable = TRUE; + priv->ieee80211->CTSToSelfTH = CTSToSelfTHVal; +} + +static void dm_ctstoself(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv((struct net_device *)dev); + PRT_HIGH_THROUGHPUT pHTInfo = priv->ieee80211->pHTInfo; + static unsigned long lastTxOkCnt = 0; + static unsigned long lastRxOkCnt = 0; + unsigned long curTxOkCnt = 0; + unsigned long curRxOkCnt = 0; + + if(priv->ieee80211->bCTSToSelfEnable != TRUE) + { + pHTInfo->IOTAction &= ~HT_IOT_ACT_FORCED_CTS2SELF; + return; + } + /* + 1. Uplink + 2. Linksys350/Linksys300N + 3. <50 disable, >55 enable + */ + + if(pHTInfo->IOTPeer == HT_IOT_PEER_BROADCOM) + { + curTxOkCnt = priv->stats.txbytesunicast - lastTxOkCnt; + curRxOkCnt = priv->stats.rxbytesunicast - lastRxOkCnt; + if(curRxOkCnt > 4*curTxOkCnt) //downlink, disable CTS to self + { + pHTInfo->IOTAction &= ~HT_IOT_ACT_FORCED_CTS2SELF; + //DbgPrint("dm_CTSToSelf() ==> CTS to self disabled -- downlink\n"); + } + else //uplink + { + #if 1 + pHTInfo->IOTAction |= HT_IOT_ACT_FORCED_CTS2SELF; + #else + if(priv->undecorated_smoothed_pwdb < priv->ieee80211->CTSToSelfTH) // disable CTS to self + { + pHTInfo->IOTAction &= ~HT_IOT_ACT_FORCED_CTS2SELF; + //DbgPrint("dm_CTSToSelf() ==> CTS to self disabled\n"); + } + else if(priv->undecorated_smoothed_pwdb >= (priv->ieee80211->CTSToSelfTH+5)) // enable CTS to self + { + pHTInfo->IOTAction |= HT_IOT_ACT_FORCED_CTS2SELF; + //DbgPrint("dm_CTSToSelf() ==> CTS to self enabled\n"); + } + #endif + } + + lastTxOkCnt = priv->stats.txbytesunicast; + lastRxOkCnt = priv->stats.rxbytesunicast; + } +} + + +#if 0 +/*----------------------------------------------------------------------------- + * Function: dm_rf_operation_test_callback() + * + * Overview: Only for RF operation test now. + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 05/29/2008 amy Create Version 0 porting from windows code. + * + *---------------------------------------------------------------------------*/ +extern void dm_rf_operation_test_callback(unsigned long dev) +{ +// struct r8192_priv *priv = ieee80211_priv((struct net_device *)dev); + u8 erfpath; + + + for(erfpath=0; erfpath<4; erfpath++) + { + //DbgPrint("Set RF-%d\n\r", eRFPath); + //PHY_SetRFReg(Adapter, (RF90_RADIO_PATH_E)eRFPath, 0x2c, bMask12Bits, 0x3d7); + udelay(100); + } + + { + //PlatformSetPeriodicTimer(Adapter, &pHalData->RfTest1Timer, 500); + } + + // For test + { + //u8 i; + //PlatformSetPeriodicTimer(Adapter, &pHalData->RfTest1Timer, 500); +#if 0 + for(i=0; i<50; i++) + { + // Write Test + PHY_SetRFReg(Adapter, RF90_PATH_A, 0x02, bMask12Bits, 0x4d); + //delay_us(100); + PHY_SetRFReg(Adapter, RF90_PATH_A, 0x02, bMask12Bits, 0x4f); + //delay_us(100); + PHY_SetRFReg(Adapter, RF90_PATH_C, 0x02, bMask12Bits, 0x4d); + //delay_us(100); + PHY_SetRFReg(Adapter, RF90_PATH_C, 0x02, bMask12Bits, 0x4f); + //delay_us(100); + +#if 0 + // Read test + PHY_QueryRFReg(Adapter, RF90_PATH_A, 0x02, bMask12Bits); + //delay_us(100); + PHY_QueryRFReg(Adapter, RF90_PATH_A, 0x02, bMask12Bits); + //delay_us(100); + PHY_QueryRFReg(Adapter, RF90_PATH_A, 0x12, bMask12Bits); + //delay_us(100); + PHY_QueryRFReg(Adapter, RF90_PATH_A, 0x12, bMask12Bits); + //delay_us(100); + PHY_QueryRFReg(Adapter, RF90_PATH_A, 0x21, bMask12Bits); + //delay_us(100); + PHY_QueryRFReg(Adapter, RF90_PATH_A, 0x21, bMask12Bits); + //delay_us(100); +#endif + } +#endif + } + +} /* DM_RfOperationTestCallBack */ +#endif + +/*----------------------------------------------------------------------------- + * Function: dm_check_rfctrl_gpio() + * + * Overview: Copy 8187B template for 9xseries. + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 05/28/2008 amy Create Version 0 porting from windows code. + * + *---------------------------------------------------------------------------*/ +#if 1 +static void dm_check_rfctrl_gpio(struct net_device * dev) +{ + //struct r8192_priv *priv = ieee80211_priv(dev); + + // Walk around for DTM test, we will not enable HW - radio on/off because r/w + // page 1 register before Lextra bus is enabled cause system fails when resuming + // from S4. 20080218, Emily + + // Stop to execute workitem to prevent S3/S4 bug. +#ifdef RTL8190P + return; +#endif +#ifdef RTL8192U + return; +#endif +#ifdef RTL8192SU + return; +#endif +#ifdef RTL8192E + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + queue_delayed_work(priv->priv_wq,&priv->gpio_change_rf_wq,0); + #else + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + schedule_task(&priv->gpio_change_rf_wq); + #else + queue_work(priv->priv_wq,&priv->gpio_change_rf_wq); + #endif + #endif +#endif + +} /* dm_CheckRfCtrlGPIO */ + +#endif +/*----------------------------------------------------------------------------- + * Function: dm_check_pbc_gpio() + * + * Overview: Check if PBC button is pressed. + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 05/28/2008 amy Create Version 0 porting from windows code. + * + *---------------------------------------------------------------------------*/ +static void dm_check_pbc_gpio(struct net_device *dev) +{ +#ifdef RTL8192U + struct r8192_priv *priv = ieee80211_priv(dev); + u8 tmp1byte; + + + tmp1byte = read_nic_byte(dev,GPI); + if(tmp1byte == 0xff) + return; + + if (tmp1byte&BIT6 || tmp1byte&BIT0) + { + // Here we only set bPbcPressed to TRUE + // After trigger PBC, the variable will be set to FALSE + RT_TRACE(COMP_IO, "CheckPbcGPIO - PBC is pressed\n"); + priv->bpbc_pressed = true; + } +#endif +#ifdef RTL8192SU + struct r8192_priv *priv = ieee80211_priv(dev); + u8 tmp1byte; + + write_nic_byte(dev, MAC_PINMUX_CFG, (GPIOMUX_EN | GPIOSEL_GPIO)); + + tmp1byte = read_nic_byte(dev, GPIO_IO_SEL); + tmp1byte &= ~(HAL_8192S_HW_GPIO_WPS_BIT); + write_nic_byte(dev, GPIO_IO_SEL, tmp1byte); + + tmp1byte = read_nic_byte(dev, GPIO_IN); + + RT_TRACE(COMP_IO, "CheckPbcGPIO - %x\n", tmp1byte); + + // Add by hpfan 2008.07.07 to fix read GPIO error from S3 + if (tmp1byte == 0xff) + return ; + + if (tmp1byte&HAL_8192S_HW_GPIO_WPS_BIT) + { + // Here we only set bPbcPressed to TRUE + // After trigger PBC, the variable will be set to FALSE + RT_TRACE(COMP_IO, "CheckPbcGPIO - PBC is pressed\n"); + priv->bpbc_pressed = true; + } + +#endif + + +} + +#ifdef RTL8192E + +/*----------------------------------------------------------------------------- + * Function: dm_GPIOChangeRF + * Overview: PCI will not support workitem call back HW radio on-off control. + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 02/21/2008 MHC Create Version 0. + * + *---------------------------------------------------------------------------*/ + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) +extern void dm_gpio_change_rf_callback(struct work_struct *work) +{ + struct delayed_work *dwork = container_of(work,struct delayed_work,work); + struct r8192_priv *priv = container_of(dwork,struct r8192_priv,gpio_change_rf_wq); + struct net_device *dev = priv->ieee80211->dev; +#else +extern void dm_gpio_change_rf_callback(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); +#endif + u8 tmp1byte; + RT_RF_POWER_STATE eRfPowerStateToSet; + bool bActuallySet = false; + + do{ + bActuallySet=false; + + if(!priv->up) + { + RT_TRACE((COMP_INIT | COMP_POWER | COMP_RF),"dm_gpio_change_rf_callback(): Callback function breaks out!!\n"); + } + else + { + // 0x108 GPIO input register is read only + //set 0x108 B1= 1: RF-ON; 0: RF-OFF. + tmp1byte = read_nic_byte(dev,GPI); + + eRfPowerStateToSet = (tmp1byte&BIT1) ? eRfOn : eRfOff; + + if( (priv->bHwRadioOff == true) && (eRfPowerStateToSet == eRfOn)) + { + RT_TRACE(COMP_RF, "gpiochangeRF - HW Radio ON\n"); + + priv->bHwRadioOff = false; + bActuallySet = true; + } + else if ( (priv->bHwRadioOff == false) && (eRfPowerStateToSet == eRfOff)) + { + RT_TRACE(COMP_RF, "gpiochangeRF - HW Radio OFF\n"); + priv->bHwRadioOff = true; + bActuallySet = true; + } + + if(bActuallySet) + { + #ifdef TO_DO + MgntActSet_RF_State(dev, eRfPowerStateToSet, RF_CHANGE_BY_HW); + //DrvIFIndicateCurrentPhyStatus(pAdapter); + #endif + } + else + { + msleep(2000); + } + + } + }while(TRUE) + +} /* dm_GPIOChangeRF */ + +#endif +/*----------------------------------------------------------------------------- + * Function: DM_RFPathCheckWorkItemCallBack() + * + * Overview: Check if Current RF RX path is enabled + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 01/30/2008 MHC Create Version 0. + * + *---------------------------------------------------------------------------*/ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) +extern void dm_rf_pathcheck_workitemcallback(struct work_struct *work) +{ + struct delayed_work *dwork = container_of(work,struct delayed_work,work); + struct r8192_priv *priv = container_of(dwork,struct r8192_priv,rfpath_check_wq); + struct net_device *dev =priv->ieee80211->dev; +#else +extern void dm_rf_pathcheck_workitemcallback(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); +#endif + //bool bactually_set = false; + u8 rfpath = 0, i; + + + /* 2008/01/30 MH After discussing with SD3 Jerry, 0xc04/0xd04 register will + always be the same. We only read 0xc04 now. */ + rfpath = read_nic_byte(dev, 0xc04); + + // Check Bit 0-3, it means if RF A-D is enabled. + for (i = 0; i < RF90_PATH_MAX; i++) + { + if (rfpath & (0x01<brfpath_rxenable[i] = 1; + else + priv->brfpath_rxenable[i] = 0; + } + if(!DM_RxPathSelTable.Enable) + return; + + dm_rxpath_sel_byrssi(dev); +} /* DM_RFPathCheckWorkItemCallBack */ + +static void dm_init_rxpath_selection(struct net_device * dev) +{ + u8 i; + struct r8192_priv *priv = ieee80211_priv(dev); + DM_RxPathSelTable.Enable = 1; //default enabled + DM_RxPathSelTable.SS_TH_low = RxPathSelection_SS_TH_low; + DM_RxPathSelTable.diff_TH = RxPathSelection_diff_TH; + if(priv->CustomerID == RT_CID_819x_Netcore) + DM_RxPathSelTable.cck_method = CCK_Rx_Version_2; + else + DM_RxPathSelTable.cck_method = CCK_Rx_Version_1; + DM_RxPathSelTable.DbgMode = DM_DBG_OFF; + DM_RxPathSelTable.disabledRF = 0; + for(i=0; i<4; i++) + { + DM_RxPathSelTable.rf_rssi[i] = 50; + DM_RxPathSelTable.cck_pwdb_sta[i] = -64; + DM_RxPathSelTable.rf_enable_rssi_th[i] = 100; + } +} + +static void dm_rxpath_sel_byrssi(struct net_device * dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + u8 i, max_rssi_index=0, min_rssi_index=0, sec_rssi_index=0, rf_num=0; + u8 tmp_max_rssi=0, tmp_min_rssi=0, tmp_sec_rssi=0; + u8 cck_default_Rx=0x2; //RF-C + u8 cck_optional_Rx=0x3;//RF-D + long tmp_cck_max_pwdb=0, tmp_cck_min_pwdb=0, tmp_cck_sec_pwdb=0; + u8 cck_rx_ver2_max_index=0, cck_rx_ver2_min_index=0, cck_rx_ver2_sec_index=0; + u8 cur_rf_rssi; + long cur_cck_pwdb; + static u8 disabled_rf_cnt=0, cck_Rx_Path_initialized=0; + u8 update_cck_rx_path; + + if(priv->rf_type != RF_2T4R) + return; + + if(!cck_Rx_Path_initialized) + { + DM_RxPathSelTable.cck_Rx_path = (read_nic_byte(dev, 0xa07)&0xf); + cck_Rx_Path_initialized = 1; + } + + DM_RxPathSelTable.disabledRF = 0xf; + DM_RxPathSelTable.disabledRF &=~ (read_nic_byte(dev, 0xc04)); + + if(priv->ieee80211->mode == WIRELESS_MODE_B) + { + DM_RxPathSelTable.cck_method = CCK_Rx_Version_2; //pure B mode, fixed cck version2 + //DbgPrint("Pure B mode, use cck rx version2 \n"); + } + + //decide max/sec/min rssi index + for (i=0; istats.rx_rssi_percentage[i]; + + if(priv->brfpath_rxenable[i]) + { + rf_num++; + cur_rf_rssi = DM_RxPathSelTable.rf_rssi[i]; + + if(rf_num == 1) // find first enabled rf path and the rssi values + { //initialize, set all rssi index to the same one + max_rssi_index = min_rssi_index = sec_rssi_index = i; + tmp_max_rssi = tmp_min_rssi = tmp_sec_rssi = cur_rf_rssi; + } + else if(rf_num == 2) + { // we pick up the max index first, and let sec and min to be the same one + if(cur_rf_rssi >= tmp_max_rssi) + { + tmp_max_rssi = cur_rf_rssi; + max_rssi_index = i; + } + else + { + tmp_sec_rssi = tmp_min_rssi = cur_rf_rssi; + sec_rssi_index = min_rssi_index = i; + } + } + else + { + if(cur_rf_rssi > tmp_max_rssi) + { + tmp_sec_rssi = tmp_max_rssi; + sec_rssi_index = max_rssi_index; + tmp_max_rssi = cur_rf_rssi; + max_rssi_index = i; + } + else if(cur_rf_rssi == tmp_max_rssi) + { // let sec and min point to the different index + tmp_sec_rssi = cur_rf_rssi; + sec_rssi_index = i; + } + else if((cur_rf_rssi < tmp_max_rssi) &&(cur_rf_rssi > tmp_sec_rssi)) + { + tmp_sec_rssi = cur_rf_rssi; + sec_rssi_index = i; + } + else if(cur_rf_rssi == tmp_sec_rssi) + { + if(tmp_sec_rssi == tmp_min_rssi) + { // let sec and min point to the different index + tmp_sec_rssi = cur_rf_rssi; + sec_rssi_index = i; + } + else + { + // This case we don't need to set any index + } + } + else if((cur_rf_rssi < tmp_sec_rssi) && (cur_rf_rssi > tmp_min_rssi)) + { + // This case we don't need to set any index + } + else if(cur_rf_rssi == tmp_min_rssi) + { + if(tmp_sec_rssi == tmp_min_rssi) + { // let sec and min point to the different index + tmp_min_rssi = cur_rf_rssi; + min_rssi_index = i; + } + else + { + // This case we don't need to set any index + } + } + else if(cur_rf_rssi < tmp_min_rssi) + { + tmp_min_rssi = cur_rf_rssi; + min_rssi_index = i; + } + } + } + } + + rf_num = 0; + // decide max/sec/min cck pwdb index + if(DM_RxPathSelTable.cck_method == CCK_Rx_Version_2) + { + for (i=0; ibrfpath_rxenable[i]) + { + rf_num++; + cur_cck_pwdb = DM_RxPathSelTable.cck_pwdb_sta[i]; + + if(rf_num == 1) // find first enabled rf path and the rssi values + { //initialize, set all rssi index to the same one + cck_rx_ver2_max_index = cck_rx_ver2_min_index = cck_rx_ver2_sec_index = i; + tmp_cck_max_pwdb = tmp_cck_min_pwdb = tmp_cck_sec_pwdb = cur_cck_pwdb; + } + else if(rf_num == 2) + { // we pick up the max index first, and let sec and min to be the same one + if(cur_cck_pwdb >= tmp_cck_max_pwdb) + { + tmp_cck_max_pwdb = cur_cck_pwdb; + cck_rx_ver2_max_index = i; + } + else + { + tmp_cck_sec_pwdb = tmp_cck_min_pwdb = cur_cck_pwdb; + cck_rx_ver2_sec_index = cck_rx_ver2_min_index = i; + } + } + else + { + if(cur_cck_pwdb > tmp_cck_max_pwdb) + { + tmp_cck_sec_pwdb = tmp_cck_max_pwdb; + cck_rx_ver2_sec_index = cck_rx_ver2_max_index; + tmp_cck_max_pwdb = cur_cck_pwdb; + cck_rx_ver2_max_index = i; + } + else if(cur_cck_pwdb == tmp_cck_max_pwdb) + { // let sec and min point to the different index + tmp_cck_sec_pwdb = cur_cck_pwdb; + cck_rx_ver2_sec_index = i; + } + else if((cur_cck_pwdb < tmp_cck_max_pwdb) &&(cur_cck_pwdb > tmp_cck_sec_pwdb)) + { + tmp_cck_sec_pwdb = cur_cck_pwdb; + cck_rx_ver2_sec_index = i; + } + else if(cur_cck_pwdb == tmp_cck_sec_pwdb) + { + if(tmp_cck_sec_pwdb == tmp_cck_min_pwdb) + { // let sec and min point to the different index + tmp_cck_sec_pwdb = cur_cck_pwdb; + cck_rx_ver2_sec_index = i; + } + else + { + // This case we don't need to set any index + } + } + else if((cur_cck_pwdb < tmp_cck_sec_pwdb) && (cur_cck_pwdb > tmp_cck_min_pwdb)) + { + // This case we don't need to set any index + } + else if(cur_cck_pwdb == tmp_cck_min_pwdb) + { + if(tmp_cck_sec_pwdb == tmp_cck_min_pwdb) + { // let sec and min point to the different index + tmp_cck_min_pwdb = cur_cck_pwdb; + cck_rx_ver2_min_index = i; + } + else + { + // This case we don't need to set any index + } + } + else if(cur_cck_pwdb < tmp_cck_min_pwdb) + { + tmp_cck_min_pwdb = cur_cck_pwdb; + cck_rx_ver2_min_index = i; + } + } + + } + } + } + + + // Set CCK Rx path + // reg0xA07[3:2]=cck default rx path, reg0xa07[1:0]=cck optional rx path. + update_cck_rx_path = 0; + if(DM_RxPathSelTable.cck_method == CCK_Rx_Version_2) + { + cck_default_Rx = cck_rx_ver2_max_index; + cck_optional_Rx = cck_rx_ver2_sec_index; + if(tmp_cck_max_pwdb != -64) + update_cck_rx_path = 1; + } + + if(tmp_min_rssi < DM_RxPathSelTable.SS_TH_low && disabled_rf_cnt < 2) + { + if((tmp_max_rssi - tmp_min_rssi) >= DM_RxPathSelTable.diff_TH) + { + //record the enabled rssi threshold + DM_RxPathSelTable.rf_enable_rssi_th[min_rssi_index] = tmp_max_rssi+5; + //disable the BB Rx path, OFDM + rtl8192_setBBreg(dev, rOFDM0_TRxPathEnable, 0x1<>i) & 0x1) //disabled rf + { + if(tmp_max_rssi >= DM_RxPathSelTable.rf_enable_rssi_th[i]) + { + //enable the BB Rx path + //DbgPrint("RF-%d is enabled. \n", 0x1<= KERNEL_VERSION(2,6,20) + queue_delayed_work(priv->priv_wq,&priv->rfpath_check_wq,0); +#else +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + schedule_task(&priv->rfpath_check_wq); +#else + queue_work(priv->priv_wq,&priv->rfpath_check_wq); +#endif +#endif +} /* dm_CheckRxRFPath */ + + +static void dm_init_fsync (struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + + priv->ieee80211->fsync_time_interval = 500; + priv->ieee80211->fsync_rate_bitmap = 0x0f000800; + priv->ieee80211->fsync_rssi_threshold = 30; +#ifdef RTL8190P + priv->ieee80211->bfsync_enable = true; +#else + priv->ieee80211->bfsync_enable = false; +#endif + priv->ieee80211->fsync_multiple_timeinterval = 3; + priv->ieee80211->fsync_firstdiff_ratethreshold= 100; + priv->ieee80211->fsync_seconddiff_ratethreshold= 200; + priv->ieee80211->fsync_state = Default_Fsync; + priv->framesyncMonitor = 1; // current default 0xc38 monitor on + + init_timer(&priv->fsync_timer); + priv->fsync_timer.data = (unsigned long)dev; + priv->fsync_timer.function = dm_fsync_timer_callback; +} + + +static void dm_deInit_fsync(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + del_timer_sync(&priv->fsync_timer); +} + +extern void dm_fsync_timer_callback(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct r8192_priv *priv = ieee80211_priv((struct net_device *)data); + u32 rate_index, rate_count = 0, rate_count_diff=0; + bool bSwitchFromCountDiff = false; + bool bDoubleTimeInterval = false; + + if( priv->ieee80211->state == IEEE80211_LINKED && + priv->ieee80211->bfsync_enable && + (priv->ieee80211->pHTInfo->IOTAction & HT_IOT_ACT_CDD_FSYNC)) + { + // Count rate 54, MCS [7], [12, 13, 14, 15] + u32 rate_bitmap; + for(rate_index = 0; rate_index <= 27; rate_index++) + { + rate_bitmap = 1 << rate_index; + if(priv->ieee80211->fsync_rate_bitmap & rate_bitmap) + rate_count+= priv->stats.received_rate_histogram[1][rate_index]; + } + + if(rate_count < priv->rate_record) + rate_count_diff = 0xffffffff - rate_count + priv->rate_record; + else + rate_count_diff = rate_count - priv->rate_record; + if(rate_count_diff < priv->rateCountDiffRecord) + { + + u32 DiffNum = priv->rateCountDiffRecord - rate_count_diff; + // Contiune count + if(DiffNum >= priv->ieee80211->fsync_seconddiff_ratethreshold) + priv->ContiuneDiffCount++; + else + priv->ContiuneDiffCount = 0; + + // Contiune count over + if(priv->ContiuneDiffCount >=2) + { + bSwitchFromCountDiff = true; + priv->ContiuneDiffCount = 0; + } + } + else + { + // Stop contiune count + priv->ContiuneDiffCount = 0; + } + + //If Count diff <= FsyncRateCountThreshold + if(rate_count_diff <= priv->ieee80211->fsync_firstdiff_ratethreshold) + { + bSwitchFromCountDiff = true; + priv->ContiuneDiffCount = 0; + } + priv->rate_record = rate_count; + priv->rateCountDiffRecord = rate_count_diff; + RT_TRACE(COMP_HALDM, "rateRecord %d rateCount %d, rateCountdiff %d bSwitchFsync %d\n", priv->rate_record, rate_count, rate_count_diff , priv->bswitch_fsync); + // if we never receive those mcs rate and rssi > 30 % then switch fsyn + if(priv->undecorated_smoothed_pwdb > priv->ieee80211->fsync_rssi_threshold && bSwitchFromCountDiff) + { + bDoubleTimeInterval = true; + priv->bswitch_fsync = !priv->bswitch_fsync; + if(priv->bswitch_fsync) + { + #ifdef RTL8190P + write_nic_byte(dev, 0xC36, 0x00); + #else + write_nic_byte(dev,0xC36, 0x1c); + #endif + write_nic_byte(dev, 0xC3e, 0x90); + } + else + { + #ifdef RTL8190P + write_nic_byte(dev, 0xC36, 0x40); + #else + write_nic_byte(dev, 0xC36, 0x5c); + #endif + write_nic_byte(dev, 0xC3e, 0x96); + } + } + else if(priv->undecorated_smoothed_pwdb <= priv->ieee80211->fsync_rssi_threshold) + { + if(priv->bswitch_fsync) + { + priv->bswitch_fsync = false; + #ifdef RTL8190P + write_nic_byte(dev, 0xC36, 0x40); + #else + write_nic_byte(dev, 0xC36, 0x5c); + #endif + write_nic_byte(dev, 0xC3e, 0x96); + } + } + if(bDoubleTimeInterval){ + if(timer_pending(&priv->fsync_timer)) + del_timer_sync(&priv->fsync_timer); + priv->fsync_timer.expires = jiffies + MSECS(priv->ieee80211->fsync_time_interval*priv->ieee80211->fsync_multiple_timeinterval); + add_timer(&priv->fsync_timer); + } + else{ + if(timer_pending(&priv->fsync_timer)) + del_timer_sync(&priv->fsync_timer); + priv->fsync_timer.expires = jiffies + MSECS(priv->ieee80211->fsync_time_interval); + add_timer(&priv->fsync_timer); + } + } + else + { + // Let Register return to default value; + if(priv->bswitch_fsync) + { + priv->bswitch_fsync = false; + #ifdef RTL8190P + write_nic_byte(dev, 0xC36, 0x40); + #else + write_nic_byte(dev, 0xC36, 0x5c); + #endif + write_nic_byte(dev, 0xC3e, 0x96); + } + priv->ContiuneDiffCount = 0; +#ifdef RTL8192SU + rtl8192_setBBreg(dev, rOFDM0_RxDetector2, bMaskDWord, 0x164052cd); +#else + #ifdef RTL8190P + write_nic_dword(dev, rOFDM0_RxDetector2, 0x164052cd); + #else + write_nic_dword(dev, rOFDM0_RxDetector2, 0x465c52cd); + #endif +#endif + } + RT_TRACE(COMP_HALDM, "ContiuneDiffCount %d\n", priv->ContiuneDiffCount); + RT_TRACE(COMP_HALDM, "rateRecord %d rateCount %d, rateCountdiff %d bSwitchFsync %d\n", priv->rate_record, rate_count, rate_count_diff , priv->bswitch_fsync); +} + +static void dm_StartHWFsync(struct net_device *dev) +{ + RT_TRACE(COMP_HALDM, "%s\n", __FUNCTION__); + write_nic_dword(dev, rOFDM0_RxDetector2, 0x465c12cf); + write_nic_byte(dev, 0xc3b, 0x41); +} + +static void dm_EndSWFsync(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + + RT_TRACE(COMP_HALDM, "%s\n", __FUNCTION__); + del_timer_sync(&(priv->fsync_timer)); + + // Let Register return to default value; + if(priv->bswitch_fsync) + { + priv->bswitch_fsync = false; + + #ifdef RTL8190P + write_nic_byte(dev, 0xC36, 0x40); + #else + write_nic_byte(dev, 0xC36, 0x5c); + #endif + + write_nic_byte(dev, 0xC3e, 0x96); + } + + priv->ContiuneDiffCount = 0; +#ifndef RTL8190P + write_nic_dword(dev, rOFDM0_RxDetector2, 0x465c52cd); +#endif + +} + +static void dm_StartSWFsync(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + u32 rateIndex; + u32 rateBitmap; + + RT_TRACE(COMP_HALDM,"%s\n", __FUNCTION__); + // Initial rate record to zero, start to record. + priv->rate_record = 0; + // Initial contiune diff count to zero, start to record. + priv->ContiuneDiffCount = 0; + priv->rateCountDiffRecord = 0; + priv->bswitch_fsync = false; + + if(priv->ieee80211->mode == WIRELESS_MODE_N_24G) + { + priv->ieee80211->fsync_firstdiff_ratethreshold= 600; + priv->ieee80211->fsync_seconddiff_ratethreshold = 0xffff; + } + else + { + priv->ieee80211->fsync_firstdiff_ratethreshold= 200; + priv->ieee80211->fsync_seconddiff_ratethreshold = 200; + } + for(rateIndex = 0; rateIndex <= 27; rateIndex++) + { + rateBitmap = 1 << rateIndex; + if(priv->ieee80211->fsync_rate_bitmap & rateBitmap) + priv->rate_record += priv->stats.received_rate_histogram[1][rateIndex]; + } + if(timer_pending(&priv->fsync_timer)) + del_timer_sync(&priv->fsync_timer); + priv->fsync_timer.expires = jiffies + MSECS(priv->ieee80211->fsync_time_interval); + add_timer(&priv->fsync_timer); + +#ifndef RTL8190P + write_nic_dword(dev, rOFDM0_RxDetector2, 0x465c12cd); +#endif + +} + +static void dm_EndHWFsync(struct net_device *dev) +{ + RT_TRACE(COMP_HALDM,"%s\n", __FUNCTION__); + write_nic_dword(dev, rOFDM0_RxDetector2, 0x465c52cd); + write_nic_byte(dev, 0xc3b, 0x49); + +} + +void dm_check_fsync(struct net_device *dev) +{ +#define RegC38_Default 0 +#define RegC38_NonFsync_Other_AP 1 +#define RegC38_Fsync_AP_BCM 2 + struct r8192_priv *priv = ieee80211_priv(dev); + //u32 framesyncC34; + static u8 reg_c38_State=RegC38_Default; + static u32 reset_cnt=0; + + RT_TRACE(COMP_HALDM, "RSSI %d TimeInterval %d MultipleTimeInterval %d\n", priv->ieee80211->fsync_rssi_threshold, priv->ieee80211->fsync_time_interval, priv->ieee80211->fsync_multiple_timeinterval); + RT_TRACE(COMP_HALDM, "RateBitmap 0x%x FirstDiffRateThreshold %d SecondDiffRateThreshold %d\n", priv->ieee80211->fsync_rate_bitmap, priv->ieee80211->fsync_firstdiff_ratethreshold, priv->ieee80211->fsync_seconddiff_ratethreshold); + + if( priv->ieee80211->state == IEEE80211_LINKED && + (priv->ieee80211->pHTInfo->IOTAction & HT_IOT_ACT_CDD_FSYNC)) + { + if(priv->ieee80211->bfsync_enable == 0) + { + switch(priv->ieee80211->fsync_state) + { + case Default_Fsync: + dm_StartHWFsync(dev); + priv->ieee80211->fsync_state = HW_Fsync; + break; + case SW_Fsync: + dm_EndSWFsync(dev); + dm_StartHWFsync(dev); + priv->ieee80211->fsync_state = HW_Fsync; + break; + case HW_Fsync: + default: + break; + } + } + else + { + switch(priv->ieee80211->fsync_state) + { + case Default_Fsync: + dm_StartSWFsync(dev); + priv->ieee80211->fsync_state = SW_Fsync; + break; + case HW_Fsync: + dm_EndHWFsync(dev); + dm_StartSWFsync(dev); + priv->ieee80211->fsync_state = SW_Fsync; + break; + case SW_Fsync: + default: + break; + + } + } + if(priv->framesyncMonitor) + { + if(reg_c38_State != RegC38_Fsync_AP_BCM) + { //For broadcom AP we write different default value + #ifdef RTL8190P + write_nic_byte(dev, rOFDM0_RxDetector3, 0x15); + #else + write_nic_byte(dev, rOFDM0_RxDetector3, 0x95); + #endif + + reg_c38_State = RegC38_Fsync_AP_BCM; + } + } + } + else + { + switch(priv->ieee80211->fsync_state) + { + case HW_Fsync: + dm_EndHWFsync(dev); + priv->ieee80211->fsync_state = Default_Fsync; + break; + case SW_Fsync: + dm_EndSWFsync(dev); + priv->ieee80211->fsync_state = Default_Fsync; + break; + case Default_Fsync: + default: + break; + } + + if(priv->framesyncMonitor) + { + if(priv->ieee80211->state == IEEE80211_LINKED) + { + if(priv->undecorated_smoothed_pwdb <= RegC38_TH) + { + if(reg_c38_State != RegC38_NonFsync_Other_AP) + { + #ifdef RTL8190P + write_nic_byte(dev, rOFDM0_RxDetector3, 0x10); + #else + write_nic_byte(dev, rOFDM0_RxDetector3, 0x90); + #endif + + reg_c38_State = RegC38_NonFsync_Other_AP; + #if 0//cosa + if (Adapter->HardwareType == HARDWARE_TYPE_RTL8190P) + DbgPrint("Fsync is idle, rssi<=35, write 0xc38 = 0x%x \n", 0x10); + else + DbgPrint("Fsync is idle, rssi<=35, write 0xc38 = 0x%x \n", 0x90); + #endif + } + } + else if(priv->undecorated_smoothed_pwdb >= (RegC38_TH+5)) + { + if(reg_c38_State) + { + write_nic_byte(dev, rOFDM0_RxDetector3, priv->framesync); + reg_c38_State = RegC38_Default; + //DbgPrint("Fsync is idle, rssi>=40, write 0xc38 = 0x%x \n", pHalData->framesync); + } + } + } + else + { + if(reg_c38_State) + { + write_nic_byte(dev, rOFDM0_RxDetector3, priv->framesync); + reg_c38_State = RegC38_Default; + //DbgPrint("Fsync is idle, not connected, write 0xc38 = 0x%x \n", pHalData->framesync); + } + } + } + } + if(priv->framesyncMonitor) + { + if(priv->reset_count != reset_cnt) + { //After silent reset, the reg_c38_State will be returned to default value + write_nic_byte(dev, rOFDM0_RxDetector3, priv->framesync); + reg_c38_State = RegC38_Default; + reset_cnt = priv->reset_count; + //DbgPrint("reg_c38_State = 0 for silent reset. \n"); + } + } + else + { + if(reg_c38_State) + { + write_nic_byte(dev, rOFDM0_RxDetector3, priv->framesync); + reg_c38_State = RegC38_Default; + //DbgPrint("framesync no monitor, write 0xc38 = 0x%x \n", pHalData->framesync); + } + } +} + +#if 0 +/*----------------------------------------------------------------------------- + * Function: DM_CheckLBusStatus() + * + * Overview: For 9x series, we must make sure LBUS is active for IO. + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 02/22/2008 MHC Create Version 0. + * + *---------------------------------------------------------------------------*/ +extern s1Byte DM_CheckLBusStatus(IN PADAPTER Adapter) +{ + PMGNT_INFO pMgntInfo=&Adapter->MgntInfo; + +#if (HAL_CODE_BASE & RTL819X) + +#if (HAL_CODE_BASE == RTL8192) + +#if( DEV_BUS_TYPE==PCI_INTERFACE) + //return (pMgntInfo->bLbusEnable); // For debug only + return TRUE; +#endif + +#if( DEV_BUS_TYPE==USB_INTERFACE) + return TRUE; +#endif + +#endif // #if (HAL_CODE_BASE == RTL8192) + +#if (HAL_CODE_BASE == RTL8190) + return TRUE; +#endif // #if (HAL_CODE_BASE == RTL8190) + +#endif // #if (HAL_CODE_BASE & RTL819X) +} /* DM_CheckLBusStatus */ + +#endif + +/*----------------------------------------------------------------------------- + * Function: dm_shadow_init() + * + * Overview: Store all NIC MAC/BB register content. + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 05/29/2008 amy Create Version 0 porting from windows code. + * + *---------------------------------------------------------------------------*/ +extern void dm_shadow_init(struct net_device *dev) +{ + u8 page; + u16 offset; + + for (page = 0; page < 5; page++) + for (offset = 0; offset < 256; offset++) + { + dm_shadow[page][offset] = read_nic_byte(dev, offset+page*256); + //DbgPrint("P-%d/O-%02x=%02x\r\n", page, offset, DM_Shadow[page][offset]); + } + + for (page = 8; page < 11; page++) + for (offset = 0; offset < 256; offset++) + dm_shadow[page][offset] = read_nic_byte(dev, offset+page*256); + + for (page = 12; page < 15; page++) + for (offset = 0; offset < 256; offset++) + dm_shadow[page][offset] = read_nic_byte(dev, offset+page*256); + +} /* dm_shadow_init */ + +/*---------------------------Define function prototype------------------------*/ +/*----------------------------------------------------------------------------- + * Function: DM_DynamicTxPower() + * + * Overview: Detect Signal strength to control TX Registry + Tx Power Control For Near/Far Range + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 03/06/2008 Jacken Create Version 0. + * + *---------------------------------------------------------------------------*/ +static void dm_init_dynamic_txpower(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + + //Initial TX Power Control for near/far range , add by amy 2008/05/15, porting from windows code. + priv->ieee80211->bdynamic_txpower_enable = true; //Default to enable Tx Power Control + priv->bLastDTPFlag_High = false; + priv->bLastDTPFlag_Low = false; + priv->bDynamicTxHighPower = false; + priv->bDynamicTxLowPower = false; +} + +static void dm_dynamic_txpower(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + unsigned int txhipower_threshhold=0; + unsigned int txlowpower_threshold=0; + if(priv->ieee80211->bdynamic_txpower_enable != true) + { + priv->bDynamicTxHighPower = false; + priv->bDynamicTxLowPower = false; + return; + } + //printk("priv->ieee80211->current_network.unknown_cap_exist is %d ,priv->ieee80211->current_network.broadcom_cap_exist is %d\n",priv->ieee80211->current_network.unknown_cap_exist,priv->ieee80211->current_network.broadcom_cap_exist); + if((priv->ieee80211->current_network.atheros_cap_exist ) && (priv->ieee80211->mode == IEEE_G)){ + txhipower_threshhold = TX_POWER_ATHEROAP_THRESH_HIGH; + txlowpower_threshold = TX_POWER_ATHEROAP_THRESH_LOW; + } + else + { + txhipower_threshhold = TX_POWER_NEAR_FIELD_THRESH_HIGH; + txlowpower_threshold = TX_POWER_NEAR_FIELD_THRESH_LOW; + } + +// printk("=======>%s(): txhipower_threshhold is %d,txlowpower_threshold is %d\n",__FUNCTION__,txhipower_threshhold,txlowpower_threshold); + RT_TRACE(COMP_TXAGC,"priv->undecorated_smoothed_pwdb = %ld \n" , priv->undecorated_smoothed_pwdb); + + if(priv->ieee80211->state == IEEE80211_LINKED) + { + if(priv->undecorated_smoothed_pwdb >= txhipower_threshhold) + { + priv->bDynamicTxHighPower = true; + priv->bDynamicTxLowPower = false; + } + else + { + // high power state check + if(priv->undecorated_smoothed_pwdb < txlowpower_threshold && priv->bDynamicTxHighPower == true) + { + priv->bDynamicTxHighPower = false; + } + // low power state check + if(priv->undecorated_smoothed_pwdb < 35) + { + priv->bDynamicTxLowPower = true; + } + else if(priv->undecorated_smoothed_pwdb >= 40) + { + priv->bDynamicTxLowPower = false; + } + } + } + else + { + //pHalData->bTXPowerCtrlforNearFarRange = !pHalData->bTXPowerCtrlforNearFarRange; + priv->bDynamicTxHighPower = false; + priv->bDynamicTxLowPower = false; + } + + if( (priv->bDynamicTxHighPower != priv->bLastDTPFlag_High ) || + (priv->bDynamicTxLowPower != priv->bLastDTPFlag_Low ) ) + { + RT_TRACE(COMP_TXAGC,"SetTxPowerLevel8190() channel = %d \n" , priv->ieee80211->current_network.channel); +#ifndef RTL8192SU +#if defined(RTL8190P) || defined(RTL8192E) + SetTxPowerLevel8190(Adapter,pHalData->CurrentChannel); +#endif + +#ifdef RTL8192U + rtl8192_phy_setTxPower(dev,priv->ieee80211->current_network.channel); + //pHalData->bStartTxCtrlByTPCNFR = FALSE; //Clear th flag of Set TX Power from Sitesurvey +#endif +#endif + } + priv->bLastDTPFlag_High = priv->bDynamicTxHighPower; + priv->bLastDTPFlag_Low = priv->bDynamicTxLowPower; + +} /* dm_dynamic_txpower */ + +//added by vivi, for read tx rate and retrycount +static void dm_check_txrateandretrycount(struct net_device * dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + struct ieee80211_device* ieee = priv->ieee80211; + //for 11n tx rate +// priv->stats.CurrentShowTxate = read_nic_byte(dev, Current_Tx_Rate_Reg); +#ifdef RTL8192SU + ieee->softmac_stats.CurrentShowTxate = read_nic_byte(dev, TX_RATE_REG); +#else + ieee->softmac_stats.CurrentShowTxate = read_nic_byte(dev, Current_Tx_Rate_Reg); +#endif + //printk("=============>tx_rate_reg:%x\n", ieee->softmac_stats.CurrentShowTxate); + //for initial tx rate +// priv->stats.last_packet_rate = read_nic_byte(dev, Initial_Tx_Rate_Reg); + ieee->softmac_stats.last_packet_rate = read_nic_byte(dev ,Initial_Tx_Rate_Reg); + //for tx tx retry count +// priv->stats.txretrycount = read_nic_dword(dev, Tx_Retry_Count_Reg); + ieee->softmac_stats.txretrycount = read_nic_dword(dev, Tx_Retry_Count_Reg); +} + +static void dm_send_rssi_tofw(struct net_device *dev) +{ +#ifndef RTL8192SU + DCMD_TXCMD_T tx_cmd; + struct r8192_priv *priv = ieee80211_priv(dev); + + // If we test chariot, we should stop the TX command ? + // Because 92E will always silent reset when we send tx command. We use register + // 0x1e0(byte) to botify driver. + write_nic_byte(dev, DRIVER_RSSI, (u8)priv->undecorated_smoothed_pwdb); + return; +#if 1 + tx_cmd.Op = TXCMD_SET_RX_RSSI; + tx_cmd.Length = 4; + tx_cmd.Value = priv->undecorated_smoothed_pwdb; + + cmpk_message_handle_tx(dev, (u8*)&tx_cmd, + DESC_PACKET_TYPE_INIT, sizeof(DCMD_TXCMD_T)); +#endif +#endif +} + +#ifdef TO_DO_LIST +static void +dm_CheckProtection(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + //PMGNT_INFO pMgntInfo = &(Adapter->MgntInfo); + u8 CurRate; + + if(priv->ieee80211->pHTInfo->IOTAction & (HT_IOT_ACT_FORCED_RTS|HT_IOT_ACT_FORCED_CTS2SELF)) + { + CurRate = read_nic_byte(dev, INIMCS_SEL); + if(CurRate <= DESC92S_RATE11M) + priv->bDmDisableProtect = true; + else + priv->bDmDisableProtect = fasle; + } +} +#endif + +/*---------------------------Define function prototype------------------------*/ + diff --git a/drivers/staging/rtl8192su/r8192U_dm.h b/drivers/staging/rtl8192su/r8192U_dm.h new file mode 100644 index 000000000000..1e05d7579882 --- /dev/null +++ b/drivers/staging/rtl8192su/r8192U_dm.h @@ -0,0 +1,309 @@ +/***************************************************************************** + * Copyright(c) 2007, RealTEK Technology Inc. All Right Reserved. + * + * Module: Hal819xUsbDM.h (RTL8192 Header H File) + * + * + * Note: For dynamic control definition constant structure. + * + * + * Export: + * + * Abbrev: + * + * History: + * Data Who Remark + * 10/04/2007 MHC Create initial version. + * + *****************************************************************************/ + /* Check to see if the file has been included already. */ +#ifndef __R8192UDM_H__ +#define __R8192UDM_H__ + + +/*--------------------------Define Parameters-------------------------------*/ +#define DM_DIG_THRESH_HIGH 40 +#define DM_DIG_THRESH_LOW 35 + +#define DM_DIG_HIGH_PWR_THRESH_HIGH 75 +#define DM_DIG_HIGH_PWR_THRESH_LOW 70 + +#define BW_AUTO_SWITCH_HIGH_LOW 25 +#define BW_AUTO_SWITCH_LOW_HIGH 30 + +#define DM_check_fsync_time_interval 500 + + +#define DM_DIG_BACKOFF 12 +#define DM_DIG_MAX 0x36 +#define DM_DIG_MIN 0x1c +#define DM_DIG_MIN_Netcore 0x12 + +#define RxPathSelection_SS_TH_low 30 +#define RxPathSelection_diff_TH 18 + +#define RateAdaptiveTH_High 50 +#define RateAdaptiveTH_Low_20M 30 +#define RateAdaptiveTH_Low_40M 10 +#define VeryLowRSSI 15 +#define CTSToSelfTHVal 30 + +//defined by vivi, for tx power track +#define E_FOR_TX_POWER_TRACK 300 +//Dynamic Tx Power Control Threshold +#define TX_POWER_NEAR_FIELD_THRESH_HIGH 68 +#define TX_POWER_NEAR_FIELD_THRESH_LOW 62 +//added by amy for atheros AP +#define TX_POWER_ATHEROAP_THRESH_HIGH 78 +#define TX_POWER_ATHEROAP_THRESH_LOW 72 + +//defined by vivi, for showing on UI +#define Current_Tx_Rate_Reg 0x1b8 +#define Initial_Tx_Rate_Reg 0x1b9 +#define Tx_Retry_Count_Reg 0x1ac +#define RegC38_TH 20 +#if 0 +//---------------------------------------------------------------------------- +// 8190 Rate Adaptive Table Register (offset 0x320, 4 byte) +//---------------------------------------------------------------------------- + +//CCK +#define RATR_1M 0x00000001 +#define RATR_2M 0x00000002 +#define RATR_55M 0x00000004 +#define RATR_11M 0x00000008 +//OFDM +#define RATR_6M 0x00000010 +#define RATR_9M 0x00000020 +#define RATR_12M 0x00000040 +#define RATR_18M 0x00000080 +#define RATR_24M 0x00000100 +#define RATR_36M 0x00000200 +#define RATR_48M 0x00000400 +#define RATR_54M 0x00000800 +//MCS 1 Spatial Stream +#define RATR_MCS0 0x00001000 +#define RATR_MCS1 0x00002000 +#define RATR_MCS2 0x00004000 +#define RATR_MCS3 0x00008000 +#define RATR_MCS4 0x00010000 +#define RATR_MCS5 0x00020000 +#define RATR_MCS6 0x00040000 +#define RATR_MCS7 0x00080000 +//MCS 2 Spatial Stream +#define RATR_MCS8 0x00100000 +#define RATR_MCS9 0x00200000 +#define RATR_MCS10 0x00400000 +#define RATR_MCS11 0x00800000 +#define RATR_MCS12 0x01000000 +#define RATR_MCS13 0x02000000 +#define RATR_MCS14 0x04000000 +#define RATR_MCS15 0x08000000 +// ALL CCK Rate +#define RATE_ALL_CCK RATR_1M|RATR_2M|RATR_55M|RATR_11M +#define RATE_ALL_OFDM_AG RATR_6M|RATR_9M|RATR_12M|RATR_18M|RATR_24M\ + |RATR_36M|RATR_48M|RATR_54M +#define RATE_ALL_OFDM_2SS RATR_MCS8|RATR_MCS9 |RATR_MCS10|RATR_MCS11| \ + RATR_MCS12|RATR_MCS13|RATR_MCS14|RATR_MCS15 +#endif +/*--------------------------Define Parameters-------------------------------*/ + + +/*------------------------------Define structure----------------------------*/ +/* 2007/10/04 MH Define upper and lower threshold of DIG enable or disable. */ +typedef struct _dynamic_initial_gain_threshold_ +{ + u8 dig_enable_flag; + u8 dig_algorithm; + u8 dbg_mode; + u8 dig_algorithm_switch; + + long rssi_low_thresh; + long rssi_high_thresh; + + long rssi_high_power_lowthresh; + long rssi_high_power_highthresh; + + u8 dig_state; + u8 dig_highpwr_state; + u8 cur_connect_state; + u8 pre_connect_state; + + u8 curpd_thstate; + u8 prepd_thstate; + u8 curcs_ratio_state; + u8 precs_ratio_state; + + u32 pre_ig_value; + u32 cur_ig_value; + + u8 backoff_val; + u8 rx_gain_range_max; + u8 rx_gain_range_min; + bool initialgain_lowerbound_state; + + long rssi_val; +}dig_t; + +typedef enum tag_dynamic_init_gain_state_definition +{ + DM_STA_DIG_OFF = 0, + DM_STA_DIG_ON, + DM_STA_DIG_MAX +}dm_dig_sta_e; + + +/* 2007/10/08 MH Define RATR state. */ +typedef enum tag_dynamic_ratr_state_definition +{ + DM_RATR_STA_HIGH = 0, + DM_RATR_STA_MIDDLE = 1, + DM_RATR_STA_LOW = 2, + DM_RATR_STA_MAX +}dm_ratr_sta_e; + +/* 2007/10/11 MH Define DIG operation type. */ +typedef enum tag_dynamic_init_gain_operation_type_definition +{ + DIG_TYPE_THRESH_HIGH = 0, + DIG_TYPE_THRESH_LOW = 1, + DIG_TYPE_THRESH_HIGHPWR_HIGH = 2, + DIG_TYPE_THRESH_HIGHPWR_LOW = 3, + DIG_TYPE_DBG_MODE = 4, + DIG_TYPE_RSSI = 5, + DIG_TYPE_ALGORITHM = 6, + DIG_TYPE_BACKOFF = 7, + DIG_TYPE_PWDB_FACTOR = 8, + DIG_TYPE_RX_GAIN_MIN = 9, + DIG_TYPE_RX_GAIN_MAX = 10, + DIG_TYPE_ENABLE = 20, + DIG_TYPE_DISABLE = 30, + DIG_OP_TYPE_MAX +}dm_dig_op_e; + +typedef enum tag_dig_algorithm_definition +{ + DIG_ALGO_BY_FALSE_ALARM = 0, + DIG_ALGO_BY_RSSI = 1, + DIG_ALGO_MAX +}dm_dig_alg_e; + +typedef enum tag_dig_dbgmode_definition +{ + DIG_DBG_OFF = 0, + DIG_DBG_ON = 1, + DIG_DBG_MAX +}dm_dig_dbg_e; + +typedef enum tag_dig_connect_definition +{ + DIG_DISCONNECT = 0, + DIG_CONNECT = 1, + DIG_CONNECT_MAX +}dm_dig_connect_e; + +typedef enum tag_dig_packetdetection_threshold_definition +{ + DIG_PD_AT_LOW_POWER = 0, + DIG_PD_AT_NORMAL_POWER = 1, + DIG_PD_AT_HIGH_POWER = 2, + DIG_PD_MAX +}dm_dig_pd_th_e; + +typedef enum tag_dig_cck_cs_ratio_state_definition +{ + DIG_CS_RATIO_LOWER = 0, + DIG_CS_RATIO_HIGHER = 1, + DIG_CS_MAX +}dm_dig_cs_ratio_e; +typedef struct _Dynamic_Rx_Path_Selection_ +{ + u8 Enable; + u8 DbgMode; + u8 cck_method; + u8 cck_Rx_path; + + u8 SS_TH_low; + u8 diff_TH; + u8 disabledRF; + u8 reserved; + + u8 rf_rssi[4]; + u8 rf_enable_rssi_th[4]; + long cck_pwdb_sta[4]; +}DRxPathSel; + +typedef enum tag_CCK_Rx_Path_Method_Definition +{ + CCK_Rx_Version_1 = 0, + CCK_Rx_Version_2= 1, + CCK_Rx_Version_MAX +}DM_CCK_Rx_Path_Method; + +typedef enum tag_DM_DbgMode_Definition +{ + DM_DBG_OFF = 0, + DM_DBG_ON = 1, + DM_DBG_MAX +}DM_DBG_E; + +typedef struct tag_Tx_Config_Cmd_Format +{ + u32 Op; /* Command packet type. */ + u32 Length; /* Command packet length. */ + u32 Value; +}DCMD_TXCMD_T, *PDCMD_TXCMD_T; +/*------------------------------Define structure----------------------------*/ + + +/*------------------------Export global variable----------------------------*/ +extern dig_t dm_digtable; +extern u8 dm_shadow[16][256]; +extern DRxPathSel DM_RxPathSelTable; +/*------------------------Export global variable----------------------------*/ + + +/*------------------------Export Marco Definition---------------------------*/ + +/*------------------------Export Marco Definition---------------------------*/ + + +/*--------------------------Exported Function prototype---------------------*/ +extern void init_hal_dm(struct net_device *dev); +extern void deinit_hal_dm(struct net_device *dev); + +extern void hal_dm_watchdog(struct net_device *dev); + +extern void init_rate_adaptive(struct net_device *dev); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) +extern void dm_txpower_trackingcallback(struct work_struct *work); +#else +extern void dm_txpower_trackingcallback(struct net_device *dev); +#endif +extern void dm_restore_dynamic_mechanism_state(struct net_device *dev); +extern void dm_backup_dynamic_mechanism_state(struct net_device *dev); +extern void dm_change_dynamic_initgain_thresh(struct net_device *dev, + u32 dm_type, u32 dm_value); +extern void dm_force_tx_fw_info(struct net_device *dev,u32 force_type, u32 force_value); +extern void dm_init_edca_turbo(struct net_device *dev); +extern void dm_rf_operation_test_callback(unsigned long data); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) +extern void dm_rf_pathcheck_workitemcallback(struct work_struct *work); +#else +extern void dm_rf_pathcheck_workitemcallback(struct net_device *dev); +#endif +extern void dm_fsync_timer_callback(unsigned long data); +extern void dm_cck_txpower_adjust(struct net_device *dev,bool binch14); +#if 0 +extern char dm_check_lbus_status(IN PADAPTER Adapter); +#endif +extern void dm_shadow_init(struct net_device *dev); +extern void dm_initialize_txpower_tracking(struct net_device *dev); +/*--------------------------Exported Function prototype---------------------*/ + + +#endif /*__R8192UDM_H__ */ + + +/* End of r8192U_dm.h */ + diff --git a/drivers/staging/rtl8192su/r8192U_hw.h b/drivers/staging/rtl8192su/r8192U_hw.h new file mode 100644 index 000000000000..f2500e654a79 --- /dev/null +++ b/drivers/staging/rtl8192su/r8192U_hw.h @@ -0,0 +1,746 @@ +/* + This is part of rtl8187 OpenSource driver. + Copyright (C) Andrea Merello 2004-2005 + Released under the terms of GPL (General Public Licence) + + Parts of this driver are based on the GPL part of the + official Realtek driver. + Parts of this driver are based on the rtl8180 driver skeleton + from Patric Schenke & Andres Salomon. + Parts of this driver are based on the Intel Pro Wireless + 2100 GPL driver. + + We want to tanks the Authors of those projects + and the Ndiswrapper project Authors. +*/ + +/* Mariusz Matuszek added full registers definition with Realtek's name */ + +/* this file contains register definitions for the rtl8187 MAC controller */ +#ifndef R8192_HW +#define R8192_HW + +typedef enum _VERSION_819xU{ + VERSION_819xU_A, // A-cut + VERSION_819xU_B, // B-cut + VERSION_819xU_C,// C-cut +}VERSION_819xU,*PVERSION_819xU; +//added for different RF type +typedef enum _RT_RF_TYPE_DEF +{ + RF_1T2R = 0, + RF_2T4R, + + RF_819X_MAX_TYPE +}RT_RF_TYPE_DEF; + + +typedef enum _BaseBand_Config_Type{ + BaseBand_Config_PHY_REG = 0, //Radio Path A + BaseBand_Config_AGC_TAB = 1, //Radio Path B +}BaseBand_Config_Type, *PBaseBand_Config_Type; +#if 0 +typedef enum _RT_RF_TYPE_819xU{ + RF_TYPE_MIN = 0, + RF_8225, + RF_8256, + RF_8258, + RF_PSEUDO_11N = 4, +}RT_RF_TYPE_819xU, *PRT_RF_TYPE_819xU; +#endif +#define RTL8187_REQT_READ 0xc0 +#define RTL8187_REQT_WRITE 0x40 +#define RTL8187_REQ_GET_REGS 0x05 +#define RTL8187_REQ_SET_REGS 0x05 + +#define MAX_TX_URB 16 //less URB will cause 2.4.31 crash, need to fix it further +#define MAX_RX_URB 16 + +#define R8180_MAX_RETRY 255 +//#define MAX_RX_NORMAL_URB 3 +//#define MAX_RX_COMMAND_URB 2 +#define RX_URB_SIZE 9100 + +#define BB_ANTATTEN_CHAN14 0x0c +#define BB_ANTENNA_B 0x40 + +#define BB_HOST_BANG (1<<30) +#define BB_HOST_BANG_EN (1<<2) +#define BB_HOST_BANG_CLK (1<<1) +#define BB_HOST_BANG_RW (1<<3) +#define BB_HOST_BANG_DATA 1 + +//#if (RTL819X_FPGA_VER & RTL819X_FPGA_VIVI_070920) +#define AFR 0x010 +#define AFR_CardBEn (1<<0) +#define AFR_CLKRUN_SEL (1<<1) +#define AFR_FuncRegEn (1<<2) +#define RTL8190_EEPROM_ID 0x8129 +#define EEPROM_VID 0x02 +#define EEPROM_PID 0x04 +#define EEPROM_NODE_ADDRESS_BYTE_0 0x0C + +#define EEPROM_TxPowerDiff 0x1F +#define EEPROM_ThermalMeter 0x20 +#define EEPROM_PwDiff 0x21 //0x21 +#define EEPROM_CrystalCap 0x22 //0x22 + +#define EEPROM_TxPwIndex_CCK 0x23 //0x23 +#define EEPROM_TxPwIndex_OFDM_24G 0x24 //0x24~0x26 +#define EEPROM_TxPwIndex_CCK_V1 0x29 //0x29~0x2B +#define EEPROM_TxPwIndex_OFDM_24G_V1 0x2C //0x2C~0x2E +#define EEPROM_TxPwIndex_Ver 0x27 //0x27 + +#define EEPROM_Default_TxPowerDiff 0x0 +#define EEPROM_Default_ThermalMeter 0x7 +#define EEPROM_Default_PwDiff 0x4 +#define EEPROM_Default_CrystalCap 0x5 +#define EEPROM_Default_TxPower 0x1010 +#define EEPROM_Customer_ID 0x7B //0x7B:CustomerID +#define EEPROM_ChannelPlan 0x16 //0x7C +#define EEPROM_IC_VER 0x7d //0x7D +#define EEPROM_CRC 0x7e //0x7E~0x7F + +#define EEPROM_CID_DEFAULT 0x0 +#define EEPROM_CID_CAMEO 0x1 +#define EEPROM_CID_RUNTOP 0x2 +#define EEPROM_CID_Senao 0x3 +#define EEPROM_CID_TOSHIBA 0x4 // Toshiba setting, Merge by Jacken, 2008/01/31 +#define EEPROM_CID_NetCore 0x5 +#define EEPROM_CID_Nettronix 0x6 +#define EEPROM_CID_Pronet 0x7 +#define EEPROM_CID_DLINK 0x8 + +#define AC_PARAM_TXOP_LIMIT_OFFSET 16 +#define AC_PARAM_ECW_MAX_OFFSET 12 +#define AC_PARAM_ECW_MIN_OFFSET 8 +#define AC_PARAM_AIFS_OFFSET 0 + +//#endif +enum _RTL8192Usb_HW { + + PCIF = 0x009, // PCI Function Register 0x0009h~0x000bh +#define BB_GLOBAL_RESET_BIT 0x1 + BB_GLOBAL_RESET = 0x020, // BasebandGlobal Reset Register + BSSIDR = 0x02E, // BSSID Register + CMDR = 0x037, // Command register +#define CR_RST 0x10 +#define CR_RE 0x08 +#define CR_TE 0x04 +#define CR_MulRW 0x01 + SIFS = 0x03E, // SIFS register + TCR = 0x040, // Transmit Configuration Register + +#define TCR_MXDMA_2048 7 +#define TCR_LRL_OFFSET 0 +#define TCR_SRL_OFFSET 8 +#define TCR_MXDMA_OFFSET 21 +#define TCR_SAT BIT24 // Enable Rate depedent ack timeout timer + RCR = 0x044, // Receive Configuration Register +#define MAC_FILTER_MASK ((1<<0) | (1<<1) | (1<<2) | (1<<3) | (1<<5) | \ + (1<<12) | (1<<18) | (1<<19) | (1<<20) | (1<<21) | (1<<22) | (1<<23)) +#define RX_FIFO_THRESHOLD_MASK ((1<<13) | (1<<14) | (1<<15)) +#define RX_FIFO_THRESHOLD_SHIFT 13 +#define RX_FIFO_THRESHOLD_128 3 +#define RX_FIFO_THRESHOLD_256 4 +#define RX_FIFO_THRESHOLD_512 5 +#define RX_FIFO_THRESHOLD_1024 6 +#define RX_FIFO_THRESHOLD_NONE 7 +#define MAX_RX_DMA_MASK ((1<<8) | (1<<9) | (1<<10)) +#define RCR_MXDMA_OFFSET 8 +#define RCR_FIFO_OFFSET 13 +#define RCR_ONLYERLPKT BIT31 // Early Receiving based on Packet Size. +#define RCR_ENCS2 BIT30 // Enable Carrier Sense Detection Method 2 +#define RCR_ENCS1 BIT29 // Enable Carrier Sense Detection Method 1 +#define RCR_ENMBID BIT27 // Enable Multiple BssId. +#define RCR_ACKTXBW (BIT24|BIT25) // TXBW Setting of ACK frames +#define RCR_CBSSID BIT23 // Accept BSSID match packet +#define RCR_APWRMGT BIT22 // Accept power management packet +#define RCR_ADD3 BIT21 // Accept address 3 match packet +#define RCR_AMF BIT20 // Accept management type frame +#define RCR_ACF BIT19 // Accept control type frame +#define RCR_ADF BIT18 // Accept data type frame +#define RCR_RXFTH BIT13 // Rx FIFO Threshold +#define RCR_AICV BIT12 // Accept ICV error packet +#define RCR_ACRC32 BIT5 // Accept CRC32 error packet +#define RCR_AB BIT3 // Accept broadcast packet +#define RCR_AM BIT2 // Accept multicast packet +#define RCR_APM BIT1 // Accept physical match packet +#define RCR_AAP BIT0 // Accept all unicast packet + SLOT_TIME = 0x049, // Slot Time Register + ACK_TIMEOUT = 0x04c, // Ack Timeout Register + PIFS_TIME = 0x04d, // PIFS time + USTIME = 0x04e, // Microsecond Tuning Register, Sets the microsecond time unit used by MAC clock. + EDCAPARA_BE = 0x050, // EDCA Parameter of AC BE + EDCAPARA_BK = 0x054, // EDCA Parameter of AC BK + EDCAPARA_VO = 0x058, // EDCA Parameter of AC VO + EDCAPARA_VI = 0x05C, // EDCA Parameter of AC VI + RFPC = 0x05F, // Rx FIFO Packet Count + CWRR = 0x060, // Contention Window Report Register + BCN_TCFG = 0x062, // Beacon Time Configuration +#define BCN_TCFG_CW_SHIFT 8 +#define BCN_TCFG_IFS 0 + BCN_INTERVAL = 0x070, // Beacon Interval (TU) + ATIMWND = 0x072, // ATIM Window Size (TU) + BCN_DRV_EARLY_INT = 0x074, // Driver Early Interrupt Time (TU). Time to send interrupt to notify to change beacon content before TBTT + BCN_DMATIME = 0x076, // Beacon DMA and ATIM interrupt time (US). Indicates the time before TBTT to perform beacon queue DMA + BCN_ERR_THRESH = 0x078, // Beacon Error Threshold + RWCAM = 0x0A0, //IN 8190 Data Sheet is called CAMcmd + WCAMI = 0x0A4, // Software write CAM input content + RCAMO = 0x0A8, // Software read/write CAM config + SECR = 0x0B0, //Security Configuration Register +#define SCR_TxUseDK BIT0 //Force Tx Use Default Key +#define SCR_RxUseDK BIT1 //Force Rx Use Default Key +#define SCR_TxEncEnable BIT2 //Enable Tx Encryption +#define SCR_RxDecEnable BIT3 //Enable Rx Decryption +#define SCR_SKByA2 BIT4 //Search kEY BY A2 +#define SCR_NoSKMC BIT5 //No Key Search for Multicast +#define SCR_UseDK 0x01 +#define SCR_TxSecEnable 0x02 +#define SCR_RxSecEnable 0x04 + TPPoll = 0x0fd, // Transmit priority polling register + PSR = 0x0ff, // Page Select Register +#define CPU_CCK_LOOPBACK 0x00030000 +#define CPU_GEN_SYSTEM_RESET 0x00000001 +#define CPU_GEN_FIRMWARE_RESET 0x00000008 +#define CPU_GEN_BOOT_RDY 0x00000010 +#define CPU_GEN_FIRM_RDY 0x00000020 +#define CPU_GEN_PUT_CODE_OK 0x00000080 +#define CPU_GEN_BB_RST 0x00000100 +#define CPU_GEN_PWR_STB_CPU 0x00000004 +#define CPU_GEN_NO_LOOPBACK_MSK 0xFFF8FFFF // Set bit18,17,16 to 0. Set bit19 +#define CPU_GEN_NO_LOOPBACK_SET 0x00080000 // Set BIT19 to 1 + +//---------------------------------------------------------------------------- +// 8190 CPU General Register (offset 0x100, 4 byte) +//---------------------------------------------------------------------------- +#define CPU_CCK_LOOPBACK 0x00030000 +#define CPU_GEN_SYSTEM_RESET 0x00000001 +#define CPU_GEN_FIRMWARE_RESET 0x00000008 +#define CPU_GEN_BOOT_RDY 0x00000010 +#define CPU_GEN_FIRM_RDY 0x00000020 +#define CPU_GEN_PUT_CODE_OK 0x00000080 +#define CPU_GEN_BB_RST 0x00000100 +#define CPU_GEN_PWR_STB_CPU 0x00000004 +#define CPU_GEN_NO_LOOPBACK_MSK 0xFFF8FFFF // Set bit18,17,16 to 0. Set bit19 +#define CPU_GEN_NO_LOOPBACK_SET 0x00080000 // Set BIT19 to 1 + CPU_GEN = 0x100, // CPU Reset Register + LED1Cfg = 0x154,// LED1 Configuration Register + LED0Cfg = 0x155,// LED0 Configuration Register + + AcmAvg = 0x170, // ACM Average Period Register + AcmHwCtrl = 0x171, // ACM Hardware Control Register +//---------------------------------------------------------------------------- +//// +//// 8190 AcmHwCtrl bits (offset 0x171, 1 byte) +////---------------------------------------------------------------------------- +// +#define AcmHw_HwEn BIT0 +#define AcmHw_BeqEn BIT1 +#define AcmHw_ViqEn BIT2 +#define AcmHw_VoqEn BIT3 +#define AcmHw_BeqStatus BIT4 +#define AcmHw_ViqStatus BIT5 +#define AcmHw_VoqStatus BIT6 + + AcmFwCtrl = 0x172, // ACM Firmware Control Register + AES_11N_FIX = 0x173, + VOAdmTime = 0x174, // VO Queue Admitted Time Register + VIAdmTime = 0x178, // VI Queue Admitted Time Register + BEAdmTime = 0x17C, // BE Queue Admitted Time Register + RQPN1 = 0x180, // Reserved Queue Page Number , Vo Vi, Be, Bk + RQPN2 = 0x184, // Reserved Queue Page Number, HCCA, Cmd, Mgnt, High + RQPN3 = 0x188, // Reserved Queue Page Number, Bcn, Public, +// QPRR = 0x1E0, // Queue Page Report per TID + QPNR = 0x1D0, //0x1F0, // Queue Packet Number report per TID + BQDA = 0x200, // Beacon Queue Descriptor Address + HQDA = 0x204, // High Priority Queue Descriptor Address + CQDA = 0x208, // Command Queue Descriptor Address + MQDA = 0x20C, // Management Queue Descriptor Address + HCCAQDA = 0x210, // HCCA Queue Descriptor Address + VOQDA = 0x214, // VO Queue Descriptor Address + VIQDA = 0x218, // VI Queue Descriptor Address + BEQDA = 0x21C, // BE Queue Descriptor Address + BKQDA = 0x220, // BK Queue Descriptor Address + RCQDA = 0x224, // Receive command Queue Descriptor Address + RDQDA = 0x228, // Receive Queue Descriptor Start Address + + MAR0 = 0x240, // Multicast filter. + MAR4 = 0x244, + + CCX_PERIOD = 0x250, // CCX Measurement Period Register, in unit of TU. + CLM_RESULT = 0x251, // CCA Busy fraction register. + NHM_PERIOD = 0x252, // NHM Measurement Period register, in unit of TU. + + NHM_THRESHOLD0 = 0x253, // Noise Histogram Meashorement0. + NHM_THRESHOLD1 = 0x254, // Noise Histogram Meashorement1. + NHM_THRESHOLD2 = 0x255, // Noise Histogram Meashorement2. + NHM_THRESHOLD3 = 0x256, // Noise Histogram Meashorement3. + NHM_THRESHOLD4 = 0x257, // Noise Histogram Meashorement4. + NHM_THRESHOLD5 = 0x258, // Noise Histogram Meashorement5. + NHM_THRESHOLD6 = 0x259, // Noise Histogram Meashorement6 + + MCTRL = 0x25A, // Measurement Control + + NHM_RPI_COUNTER0 = 0x264, // Noise Histogram RPI counter0, the fraction of signal strength < NHM_THRESHOLD0. + NHM_RPI_COUNTER1 = 0x265, // Noise Histogram RPI counter1, the fraction of signal strength in (NHM_THRESHOLD0, NHM_THRESHOLD1]. + NHM_RPI_COUNTER2 = 0x266, // Noise Histogram RPI counter2, the fraction of signal strength in (NHM_THRESHOLD1, NHM_THRESHOLD2]. + NHM_RPI_COUNTER3 = 0x267, // Noise Histogram RPI counter3, the fraction of signal strength in (NHM_THRESHOLD2, NHM_THRESHOLD3]. + NHM_RPI_COUNTER4 = 0x268, // Noise Histogram RPI counter4, the fraction of signal strength in (NHM_THRESHOLD3, NHM_THRESHOLD4]. + NHM_RPI_COUNTER5 = 0x269, // Noise Histogram RPI counter5, the fraction of signal strength in (NHM_THRESHOLD4, NHM_THRESHOLD5]. + NHM_RPI_COUNTER6 = 0x26A, // Noise Histogram RPI counter6, the fraction of signal strength in (NHM_THRESHOLD5, NHM_THRESHOLD6]. + NHM_RPI_COUNTER7 = 0x26B, // Noise Histogram RPI counter7, the fraction of signal strength in (NHM_THRESHOLD6, NHM_THRESHOLD7]. +#define BW_OPMODE_11J BIT0 +#define BW_OPMODE_5G BIT1 +#define BW_OPMODE_20MHZ BIT2 + BW_OPMODE = 0x300, // Bandwidth operation mode + MSR = 0x303, // Media Status register +#define MSR_LINK_MASK ((1<<0)|(1<<1)) +#define MSR_LINK_MANAGED 2 +#define MSR_LINK_NONE 0 +#define MSR_LINK_SHIFT 0 +#define MSR_LINK_ADHOC 1 +#define MSR_LINK_MASTER 3 +#define MSR_LINK_ENEDCA (1<<4) + RETRY_LIMIT = 0x304, // Retry Limit [15:8]-short, [7:0]-long +#define RETRY_LIMIT_SHORT_SHIFT 8 +#define RETRY_LIMIT_LONG_SHIFT 0 + TSFR = 0x308, + RRSR = 0x310, // Response Rate Set +#define RRSR_RSC_OFFSET 21 +#define RRSR_SHORT_OFFSET 23 +#define RRSR_RSC_DUPLICATE 0x600000 +#define RRSR_RSC_LOWSUBCHNL 0x400000 +#define RRSR_RSC_UPSUBCHANL 0x200000 +#define RRSR_SHORT 0x800000 +#define RRSR_1M BIT0 +#define RRSR_2M BIT1 +#define RRSR_5_5M BIT2 +#define RRSR_11M BIT3 +#define RRSR_6M BIT4 +#define RRSR_9M BIT5 +#define RRSR_12M BIT6 +#define RRSR_18M BIT7 +#define RRSR_24M BIT8 +#define RRSR_36M BIT9 +#define RRSR_48M BIT10 +#define RRSR_54M BIT11 +#define RRSR_MCS0 BIT12 +#define RRSR_MCS1 BIT13 +#define RRSR_MCS2 BIT14 +#define RRSR_MCS3 BIT15 +#define RRSR_MCS4 BIT16 +#define RRSR_MCS5 BIT17 +#define RRSR_MCS6 BIT18 +#define RRSR_MCS7 BIT19 +#define BRSR_AckShortPmb BIT23 // CCK ACK: use Short Preamble or not. + RATR0 = 0x320, // Rate Adaptive Table register1 + UFWP = 0x318, + DRIVER_RSSI = 0x32c, // Driver tell Firmware current RSSI +//---------------------------------------------------------------------------- +// 8190 Rate Adaptive Table Register (offset 0x320, 4 byte) +//---------------------------------------------------------------------------- +//CCK +#define RATR_1M 0x00000001 +#define RATR_2M 0x00000002 +#define RATR_55M 0x00000004 +#define RATR_11M 0x00000008 +//OFDM +#define RATR_6M 0x00000010 +#define RATR_9M 0x00000020 +#define RATR_12M 0x00000040 +#define RATR_18M 0x00000080 +#define RATR_24M 0x00000100 +#define RATR_36M 0x00000200 +#define RATR_48M 0x00000400 +#define RATR_54M 0x00000800 +//MCS 1 Spatial Stream +#define RATR_MCS0 0x00001000 +#define RATR_MCS1 0x00002000 +#define RATR_MCS2 0x00004000 +#define RATR_MCS3 0x00008000 +#define RATR_MCS4 0x00010000 +#define RATR_MCS5 0x00020000 +#define RATR_MCS6 0x00040000 +#define RATR_MCS7 0x00080000 +//MCS 2 Spatial Stream +#define RATR_MCS8 0x00100000 +#define RATR_MCS9 0x00200000 +#define RATR_MCS10 0x00400000 +#define RATR_MCS11 0x00800000 +#define RATR_MCS12 0x01000000 +#define RATR_MCS13 0x02000000 +#define RATR_MCS14 0x04000000 +#define RATR_MCS15 0x08000000 +// ALL CCK Rate +#define RATE_ALL_CCK RATR_1M|RATR_2M|RATR_55M|RATR_11M +#define RATE_ALL_OFDM_AG RATR_6M|RATR_9M|RATR_12M|RATR_18M|RATR_24M\ + |RATR_36M|RATR_48M|RATR_54M +#define RATE_ALL_OFDM_1SS RATR_MCS0|RATR_MCS1|RATR_MCS2|RATR_MCS3 | \ + RATR_MCS4|RATR_MCS5|RATR_MCS6|RATR_MCS7 +#define RATE_ALL_OFDM_2SS RATR_MCS8|RATR_MCS9 |RATR_MCS10|RATR_MCS11| \ + RATR_MCS12|RATR_MCS13|RATR_MCS14|RATR_MCS15 + + MCS_TXAGC = 0x340, // MCS AGC + CCK_TXAGC = 0x348, // CCK AGC +// ISR = 0x350, // Interrupt Status Register +// IMR = 0x354, // Interrupt Mask Register +// IMR_POLL = 0x360, + MacBlkCtrl = 0x403, // Mac block on/off control register + + EPROM_CMD = 0xfe58, +#define Cmd9346CR_9356SEL (1<<4) +#define EPROM_CMD_RESERVED_MASK (1<<5) +#define EPROM_CMD_OPERATING_MODE_SHIFT 6 +#define EPROM_CMD_OPERATING_MODE_MASK ((1<<7)|(1<<6)) +#define EPROM_CMD_CONFIG 0x3 +#define EPROM_CMD_NORMAL 0 +#define EPROM_CMD_LOAD 1 +#define EPROM_CMD_PROGRAM 2 +#define EPROM_CS_SHIFT 3 +#define EPROM_CK_SHIFT 2 +#define EPROM_W_SHIFT 1 +#define EPROM_R_SHIFT 0 + MAC0 = 0x000, + MAC1 = 0x001, + MAC2 = 0x002, + MAC3 = 0x003, + MAC4 = 0x004, + MAC5 = 0x005, + +#if 0 +/* 0x0006 - 0x0007 - reserved */ + RXFIFOCOUNT = 0x010, + TXFIFOCOUNT = 0x012, + BQREQ = 0x013, +/* 0x0010 - 0x0017 - reserved */ + TSFTR = 0x018, + TLPDA = 0x020, + TNPDA = 0x024, + THPDA = 0x028, + BSSID = 0x02E, + RESP_RATE = 0x034, + CMD = 0x037, +#define CMD_RST_SHIFT 4 +#define CMD_RESERVED_MASK ((1<<1) | (1<<5) | (1<<6) | (1<<7)) +#define CMD_RX_ENABLE_SHIFT 3 +#define CMD_TX_ENABLE_SHIFT 2 +#define CR_RST ((1<< 4)) +#define CR_RE ((1<< 3)) +#define CR_TE ((1<< 2)) +#define CR_MulRW ((1<< 0)) + + INTA_MASK = 0x03c, + INTA = 0x03e, +#define INTA_TXOVERFLOW (1<<15) +#define INTA_TIMEOUT (1<<14) +#define INTA_BEACONTIMEOUT (1<<13) +#define INTA_ATIM (1<<12) +#define INTA_BEACONDESCERR (1<<11) +#define INTA_BEACONDESCOK (1<<10) +#define INTA_HIPRIORITYDESCERR (1<<9) +#define INTA_HIPRIORITYDESCOK (1<<8) +#define INTA_NORMPRIORITYDESCERR (1<<7) +#define INTA_NORMPRIORITYDESCOK (1<<6) +#define INTA_RXOVERFLOW (1<<5) +#define INTA_RXDESCERR (1<<4) +#define INTA_LOWPRIORITYDESCERR (1<<3) +#define INTA_LOWPRIORITYDESCOK (1<<2) +#define INTA_RXCRCERR (1<<1) +#define INTA_RXOK (1) + TX_CONF = 0x040, +#define TX_CONF_HEADER_AUTOICREMENT_SHIFT 30 +#define TX_LOOPBACK_SHIFT 17 +#define TX_LOOPBACK_MAC 1 +#define TX_LOOPBACK_BASEBAND 2 +#define TX_LOOPBACK_NONE 0 +#define TX_LOOPBACK_CONTINUE 3 +#define TX_LOOPBACK_MASK ((1<<17)|(1<<18)) +#define TX_LRLRETRY_SHIFT 0 +#define TX_SRLRETRY_SHIFT 8 +#define TX_NOICV_SHIFT 19 +#define TX_NOCRC_SHIFT 16 +#define TCR_DurProcMode ((1<<30)) +#define TCR_DISReqQsize ((1<<28)) +#define TCR_HWVERID_MASK ((1<<27)|(1<<26)|(1<<25)) +#define TCR_HWVERID_SHIFT 25 +#define TCR_SWPLCPLEN ((1<<24)) +#define TCR_PLCP_LEN TCR_SAT // rtl8180 +#define TCR_MXDMA_MASK ((1<<23)|(1<<22)|(1<<21)) +#define TCR_MXDMA_1024 6 +#define TCR_MXDMA_2048 7 +#define TCR_MXDMA_SHIFT 21 +#define TCR_DISCW ((1<<20)) +#define TCR_ICV ((1<<19)) +#define TCR_LBK ((1<<18)|(1<<17)) +#define TCR_LBK1 ((1<<18)) +#define TCR_LBK0 ((1<<17)) +#define TCR_CRC ((1<<16)) +#define TCR_SRL_MASK ((1<<15)|(1<<14)|(1<<13)|(1<<12)|(1<<11)|(1<<10)|(1<<9)|(1<<8)) +#define TCR_LRL_MASK ((1<<0)|(1<<1)|(1<<2)|(1<<3)|(1<<4)|(1<<5)|(1<<6)|(1<<7)) +#define TCR_PROBE_NOTIMESTAMP_SHIFT 29 //rtl8185 + RX_CONF = 0x044, +#define MAC_FILTER_MASK ((1<<0) | (1<<1) | (1<<2) | (1<<3) | (1<<5) | \ +(1<<12) | (1<<18) | (1<<19) | (1<<20) | (1<<21) | (1<<22) | (1<<23)) +#define RX_CHECK_BSSID_SHIFT 23 +#define ACCEPT_PWR_FRAME_SHIFT 22 +#define ACCEPT_MNG_FRAME_SHIFT 20 +#define ACCEPT_CTL_FRAME_SHIFT 19 +#define ACCEPT_DATA_FRAME_SHIFT 18 +#define ACCEPT_ICVERR_FRAME_SHIFT 12 +#define ACCEPT_CRCERR_FRAME_SHIFT 5 +#define ACCEPT_BCAST_FRAME_SHIFT 3 +#define ACCEPT_MCAST_FRAME_SHIFT 2 +#define ACCEPT_ALLMAC_FRAME_SHIFT 0 +#define ACCEPT_NICMAC_FRAME_SHIFT 1 +#define RX_FIFO_THRESHOLD_MASK ((1<<13) | (1<<14) | (1<<15)) +#define RX_FIFO_THRESHOLD_SHIFT 13 +#define RX_FIFO_THRESHOLD_128 3 +#define RX_FIFO_THRESHOLD_256 4 +#define RX_FIFO_THRESHOLD_512 5 +#define RX_FIFO_THRESHOLD_1024 6 +#define RX_FIFO_THRESHOLD_NONE 7 +#define RX_AUTORESETPHY_SHIFT 28 +#define MAX_RX_DMA_MASK ((1<<8) | (1<<9) | (1<<10)) +#define MAX_RX_DMA_2048 7 +#define MAX_RX_DMA_1024 6 +#define MAX_RX_DMA_SHIFT 10 +#define RCR_ONLYERLPKT ((1<<31)) +#define RCR_CS_SHIFT 29 +#define RCR_CS_MASK ((1<<30) | (1<<29)) +#define RCR_ENMARP ((1<<28)) +#define RCR_CBSSID ((1<<23)) +#define RCR_APWRMGT ((1<<22)) +#define RCR_ADD3 ((1<<21)) +#define RCR_AMF ((1<<20)) +#define RCR_ACF ((1<<19)) +#define RCR_ADF ((1<<18)) +#define RCR_RXFTH ((1<<15)|(1<<14)|(1<<13)) +#define RCR_RXFTH2 ((1<<15)) +#define RCR_RXFTH1 ((1<<14)) +#define RCR_RXFTH0 ((1<<13)) +#define RCR_AICV ((1<<12)) +#define RCR_MXDMA ((1<<10)|(1<< 9)|(1<< 8)) +#define RCR_MXDMA2 ((1<<10)) +#define RCR_MXDMA1 ((1<< 9)) +#define RCR_MXDMA0 ((1<< 8)) +#define RCR_9356SEL ((1<< 6)) +#define RCR_ACRC32 ((1<< 5)) +#define RCR_AB ((1<< 3)) +#define RCR_AM ((1<< 2)) +#define RCR_APM ((1<< 1)) +#define RCR_AAP ((1<< 0)) + INT_TIMEOUT = 0x048, + TX_BEACON_RING_ADDR = 0x04c, + EPROM_CMD = 0x58, +#define EPROM_CMD_RESERVED_MASK ((1<<5)|(1<<4)) +#define EPROM_CMD_OPERATING_MODE_SHIFT 6 +#define EPROM_CMD_OPERATING_MODE_MASK ((1<<7)|(1<<6)) +#define EPROM_CMD_CONFIG 0x3 +#define EPROM_CMD_NORMAL 0 +#define EPROM_CMD_LOAD 1 +#define EPROM_CMD_PROGRAM 2 +#define EPROM_CS_SHIFT 3 +#define EPROM_CK_SHIFT 2 +#define EPROM_W_SHIFT 1 +#define EPROM_R_SHIFT 0 + CONFIG0 = 0x051, +#define CONFIG0_WEP104 ((1<<6)) +#define CONFIG0_LEDGPO_En ((1<<4)) +#define CONFIG0_Aux_Status ((1<<3)) +#define CONFIG0_GL ((1<<1)|(1<<0)) +#define CONFIG0_GL1 ((1<<1)) +#define CONFIG0_GL0 ((1<<0)) + CONFIG1 = 0x052, +#define CONFIG1_LEDS ((1<<7)|(1<<6)) +#define CONFIG1_LEDS1 ((1<<7)) +#define CONFIG1_LEDS0 ((1<<6)) +#define CONFIG1_LWACT ((1<<4)) +#define CONFIG1_MEMMAP ((1<<3)) +#define CONFIG1_IOMAP ((1<<2)) +#define CONFIG1_VPD ((1<<1)) +#define CONFIG1_PMEn ((1<<0)) + CONFIG2 = 0x053, +#define CONFIG2_LCK ((1<<7)) +#define CONFIG2_ANT ((1<<6)) +#define CONFIG2_DPS ((1<<3)) +#define CONFIG2_PAPE_sign ((1<<2)) +#define CONFIG2_PAPE_time ((1<<1)|(1<<0)) +#define CONFIG2_PAPE_time1 ((1<<1)) +#define CONFIG2_PAPE_time0 ((1<<0)) + ANA_PARAM = 0x054, + CONFIG3 = 0x059, +#define CONFIG3_GNTSel ((1<<7)) +#define CONFIG3_PARM_En ((1<<6)) +#define CONFIG3_Magic ((1<<5)) +#define CONFIG3_CardB_En ((1<<3)) +#define CONFIG3_CLKRUN_En ((1<<2)) +#define CONFIG3_FuncRegEn ((1<<1)) +#define CONFIG3_FBtbEn ((1<<0)) +#define CONFIG3_CLKRUN_SHIFT 2 +#define CONFIG3_ANAPARAM_W_SHIFT 6 + CONFIG4 = 0x05a, +#define CONFIG4_VCOPDN ((1<<7)) +#define CONFIG4_PWROFF ((1<<6)) +#define CONFIG4_PWRMGT ((1<<5)) +#define CONFIG4_LWPME ((1<<4)) +#define CONFIG4_LWPTN ((1<<2)) +#define CONFIG4_RFTYPE ((1<<1)|(1<<0)) +#define CONFIG4_RFTYPE1 ((1<<1)) +#define CONFIG4_RFTYPE0 ((1<<0)) + TESTR = 0x05b, +#define TFPC_AC 0x05C + +#define SCR 0x05F + PGSELECT = 0x05e, +#define PGSELECT_PG_SHIFT 0 + SECURITY = 0x05f, +#define SECURITY_WEP_TX_ENABLE_SHIFT 1 +#define SECURITY_WEP_RX_ENABLE_SHIFT 0 +#define SECURITY_ENCRYP_104 1 +#define SECURITY_ENCRYP_SHIFT 4 +#define SECURITY_ENCRYP_MASK ((1<<4)|(1<<5)) + ANA_PARAM2 = 0x060, + BEACON_INTERVAL = 0x070, +#define BEACON_INTERVAL_MASK ((1<<0)|(1<<1)|(1<<2)|(1<<3)|(1<<4)|(1<<5)| \ +(1<<6)|(1<<7)|(1<<8)|(1<<9)) + ATIM_WND = 0x072, +#define ATIM_WND_MASK (0x01FF) + BCN_INTR_ITV = 0x074, +#define BCN_INTR_ITV_MASK (0x01FF) + ATIM_INTR_ITV = 0x076, +#define ATIM_INTR_ITV_MASK (0x01FF) + AckTimeOutReg = 0x079, //ACK timeout register, in unit of 4 us. + PHY_ADR = 0x07c, + PHY_READ = 0x07e, + RFPinsOutput = 0x080, + RFPinsEnable = 0x082, + +//Page 0 + RFPinsSelect = 0x084, +#define SW_CONTROL_GPIO 0x400 + RFPinsInput = 0x086, + RF_PARA = 0x088, + RF_TIMING = 0x08c, + GP_ENABLE = 0x090, + GPIO = 0x091, + TX_AGC_CTL = 0x09c, +#define TX_AGC_CTL_PER_PACKET_TXAGC 0x01 +#define TX_AGC_CTL_PERPACKET_GAIN_SHIFT 0 +#define TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT 1 +#define TX_AGC_CTL_FEEDBACK_ANT 2 +#define TXAGC_CTL_PER_PACKET_ANT_SEL 0x02 + OFDM_TXAGC = 0x09e, + ANTSEL = 0x09f, + WPA_CONFIG = 0x0b0, + SIFS = 0x0b4, + DIFS = 0x0b5, + SLOT = 0x0b6, + CW_CONF = 0x0bc, +#define CW_CONF_PERPACKET_RETRY_LIMIT 0x02 +#define CW_CONF_PERPACKET_CW 0x01 +#define CW_CONF_PERPACKET_RETRY_SHIFT 1 +#define CW_CONF_PERPACKET_CW_SHIFT 0 + CW_VAL = 0x0bd, + RATE_FALLBACK = 0x0be, +#define MAX_RESP_RATE_SHIFT 4 +#define MIN_RESP_RATE_SHIFT 0 +#define RATE_FALLBACK_CTL_ENABLE 0x80 +#define RATE_FALLBACK_CTL_AUTO_STEP0 0x00 + ACM_CONTROL = 0x0BF, // ACM Control Registe +//---------------------------------------------------------------------------- +// 8187B ACM_CONTROL bits (Offset 0xBF, 1 Byte) +//---------------------------------------------------------------------------- +#define VOQ_ACM_EN (0x01 << 7) //BIT7 +#define VIQ_ACM_EN (0x01 << 6) //BIT6 +#define BEQ_ACM_EN (0x01 << 5) //BIT5 +#define ACM_HW_EN (0x01 << 4) //BIT4 +#define TXOPSEL (0x01 << 3) //BIT3 +#define VOQ_ACM_CTL (0x01 << 2) //BIT2 // Set to 1 when AC_VO used time reaches or exceeds the admitted time +#define VIQ_ACM_CTL (0x01 << 1) //BIT1 // Set to 1 when AC_VI used time reaches or exceeds the admitted time +#define BEQ_ACM_CTL (0x01 << 0) //BIT0 // Set to 1 when AC_BE used time reaches or exceeds the admitted time + CONFIG5 = 0x0D8, +#define CONFIG5_TX_FIFO_OK ((1<<7)) +#define CONFIG5_RX_FIFO_OK ((1<<6)) +#define CONFIG5_CALON ((1<<5)) +#define CONFIG5_EACPI ((1<<2)) +#define CONFIG5_LANWake ((1<<1)) +#define CONFIG5_PME_STS ((1<<0)) + TX_DMA_POLLING = 0x0d9, +#define TX_DMA_POLLING_BEACON_SHIFT 7 +#define TX_DMA_POLLING_HIPRIORITY_SHIFT 6 +#define TX_DMA_POLLING_NORMPRIORITY_SHIFT 5 +#define TX_DMA_POLLING_LOWPRIORITY_SHIFT 4 +#define TX_DMA_STOP_BEACON_SHIFT 3 +#define TX_DMA_STOP_HIPRIORITY_SHIFT 2 +#define TX_DMA_STOP_NORMPRIORITY_SHIFT 1 +#define TX_DMA_STOP_LOWPRIORITY_SHIFT 0 + CWR = 0x0DC, + RetryCTR = 0x0DE, + INT_MIG = 0x0E2, // Interrupt Migration (0xE2 ~ 0xE3) + TID_AC_MAP = 0x0E8, // TID to AC Mapping Register + ANA_PARAM3 = 0x0EE, + + +//page 1 + Wakeup0 = 0x084, + Wakeup1 = 0x08C, + Wakeup2LD = 0x094, + Wakeup2HD = 0x09C, + Wakeup3LD = 0x0A4, + Wakeup3HD = 0x0AC, + Wakeup4LD = 0x0B4, + Wakeup4HD = 0x0BC, + CRC0 = 0x0C4, + CRC1 = 0x0C6, + CRC2 = 0x0C8, + CRC3 = 0x0CA, + CRC4 = 0x0CC, +/* 0x00CE - 0x00D3 - reserved */ + + RFSW_CTRL = 0x272, // 0x272-0x273. + +//Reg Diff between rtl8187 and rtl8187B +/**************************************************************************/ + BRSR_8187 = 0x02C, + BRSR_8187B = 0x034, +#define BRSR_BPLCP ((1<< 8)) +#define BRSR_MBR ((1<< 1)|(1<< 0)) +#define BRSR_MBR_8185 ((1<< 11)|(1<< 10)|(1<< 9)|(1<< 8)|(1<< 7)|(1<< 6)|(1<< 5)|(1<< 4)|(1<< 3)|(1<< 2)|(1<< 1)|(1<< 0)) +#define BRSR_MBR0 ((1<< 0)) +#define BRSR_MBR1 ((1<< 1)) + +/**************************************************************************/ + EIFS_8187 = 0x035, + EIFS_8187B = 0x02D, + +/**************************************************************************/ + FER = 0x0F0, + FEMR = 0x0F4, + FPSR = 0x0F8, + FFER = 0x0FC, + + AC_VO_PARAM = 0x0F0, // AC_VO Parameters Record + AC_VI_PARAM = 0x0F4, // AC_VI Parameters Record + AC_BE_PARAM = 0x0F8, // AC_BE Parameters Record + AC_BK_PARAM = 0x0FC, // AC_BK Parameters Record + TALLY_SEL = 0x0fc, +//---------------------------------------------------------------------------- +// 8187B AC_XX_PARAM bits +//---------------------------------------------------------------------------- +#define AC_PARAM_TXOP_LIMIT_OFFSET 16 +#define AC_PARAM_ECW_MAX_OFFSET 12 +#define AC_PARAM_ECW_MIN_OFFSET 8 +#define AC_PARAM_AIFS_OFFSET 0 + +#endif +}; +//---------------------------------------------------------------------------- +// 818xB AnaParm & AnaParm2 Register +//---------------------------------------------------------------------------- +//#define ANAPARM_ASIC_ON 0x45090658 +//#define ANAPARM2_ASIC_ON 0x727f3f52 +#define GPI 0x108 +#define GPO 0x109 +#define GPE 0x10a +#endif diff --git a/drivers/staging/rtl8192su/r8192U_pm.c b/drivers/staging/rtl8192su/r8192U_pm.c new file mode 100644 index 000000000000..92c95aa36638 --- /dev/null +++ b/drivers/staging/rtl8192su/r8192U_pm.c @@ -0,0 +1,77 @@ +/* + Power management interface routines. + Written by Mariusz Matuszek. + This code is currently just a placeholder for later work and + does not do anything useful. + + This is part of rtl8180 OpenSource driver. + Copyright (C) Andrea Merello 2004 + Released under the terms of GPL (General Public Licence) +*/ + +#ifdef CONFIG_RTL8192_PM +#include "r8192U.h" +#include "r8192U_pm.h" + +/*****************************************************************************/ +int rtl8192U_save_state (struct pci_dev *dev, u32 state) +{ + printk(KERN_NOTICE "r8192U save state call (state %u).\n", state); + return(-EAGAIN); +} + +int rtl8192U_suspend(struct usb_interface *intf, pm_message_t state) +{ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + struct net_device *dev = usb_get_intfdata(intf); +#else + //struct net_device *dev = (struct net_device *)ptr; +#endif + RT_TRACE(COMP_POWER, "============> r8192U suspend call.\n"); + + if(dev) { + if (!netif_running(dev)) { + printk(KERN_WARNING "netif not running, go out suspend function\n"); + return 0; + } + + dev->stop(dev); + mdelay(10); + + netif_device_detach(dev); + } + + return 0; +} + +int rtl8192U_resume (struct usb_interface *intf) +{ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + struct net_device *dev = usb_get_intfdata(intf); +#else + //struct net_device *dev = (struct net_device *)ptr; +#endif + + RT_TRACE(COMP_POWER, "================>r8192U resume call."); + + if(dev) { + if (!netif_running(dev)){ + printk(KERN_WARNING "netif not running, go out resume function\n"); + return 0; + } + + netif_device_attach(dev); + dev->open(dev); + } + + return 0; +} + +int rtl8192U_enable_wake (struct pci_dev *dev, u32 state, int enable) +{ + printk(KERN_NOTICE "r8192U enable wake call (state %u, enable %d).\n", + state, enable); + return(-EAGAIN); +} + +#endif //CONFIG_RTL8192_PM diff --git a/drivers/staging/rtl8192su/r8192U_pm.h b/drivers/staging/rtl8192su/r8192U_pm.h new file mode 100644 index 000000000000..ab025d64f5e2 --- /dev/null +++ b/drivers/staging/rtl8192su/r8192U_pm.h @@ -0,0 +1,27 @@ +/* + Power management interface routines. + Written by Mariusz Matuszek. + This code is currently just a placeholder for later work and + does not do anything useful. + + This is part of rtl8180 OpenSource driver. + Copyright (C) Andrea Merello 2004 + Released under the terms of GPL (General Public Licence) + +*/ + +#ifdef CONFIG_RTL8192_PM + +#ifndef R8192_PM_H +#define R8192_PM_H + +#include +#include + +int rtl8192U_save_tate (struct pci_dev *dev, u32 state); +int rtl8192U_suspend(struct usb_interface *intf, pm_message_t state); +int rtl8192U_resume (struct usb_interface *intf); +int rtl8192U_enable_wake (struct pci_dev *dev, u32 state, int enable); + +#endif //R8192U_PM_H +#endif // CONFIG_RTL8192_PM diff --git a/drivers/staging/rtl8192su/r8192U_wx.c b/drivers/staging/rtl8192su/r8192U_wx.c new file mode 100644 index 000000000000..f9eafb16dbb7 --- /dev/null +++ b/drivers/staging/rtl8192su/r8192U_wx.c @@ -0,0 +1,1350 @@ +/* + This file contains wireless extension handlers. + + This is part of rtl8180 OpenSource driver. + Copyright (C) Andrea Merello 2004-2005 + Released under the terms of GPL (General Public Licence) + + Parts of this driver are based on the GPL part + of the official realtek driver. + + Parts of this driver are based on the rtl8180 driver skeleton + from Patric Schenke & Andres Salomon. + + Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver. + + We want to tanks the Authors of those projects and the Ndiswrapper + project Authors. +*/ + +#ifdef RTL8192SU +#include +#include "r8192U.h" +#include "r8192S_hw.h" +#else +#include +#include "r8192U.h" +#include "r8192U_hw.h" +#endif + +#ifdef ENABLE_DOT11D +#include "dot11d.h" +#endif + +#define RATE_COUNT 12 +u32 rtl8180_rates[] = {1000000,2000000,5500000,11000000, + 6000000,9000000,12000000,18000000,24000000,36000000,48000000,54000000}; + + +#ifndef ENETDOWN +#define ENETDOWN 1 +#endif + +static int r8192_wx_get_freq(struct net_device *dev, + struct iw_request_info *a, + union iwreq_data *wrqu, char *b) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + + return ieee80211_wx_get_freq(priv->ieee80211,a,wrqu,b); +} + + +#if 0 + +static int r8192_wx_set_beaconinterval(struct net_device *dev, struct iw_request_info *aa, + union iwreq_data *wrqu, char *b) +{ + int *parms = (int *)b; + int bi = parms[0]; + + struct r8192_priv *priv = ieee80211_priv(dev); + + down(&priv->wx_sem); + DMESG("setting beacon interval to %x",bi); + + priv->ieee80211->beacon_interval=bi; + rtl8180_commit(dev); + up(&priv->wx_sem); + + return 0; +} + + +static int r8192_wx_set_forceassociate(struct net_device *dev, struct iw_request_info *aa, + union iwreq_data *wrqu, char *extra) +{ + struct r8192_priv *priv=ieee80211_priv(dev); + int *parms = (int *)extra; + + priv->ieee80211->force_associate = (parms[0] > 0); + + + return 0; +} + +#endif +static int r8192_wx_get_mode(struct net_device *dev, struct iw_request_info *a, + union iwreq_data *wrqu, char *b) +{ + struct r8192_priv *priv=ieee80211_priv(dev); + + return ieee80211_wx_get_mode(priv->ieee80211,a,wrqu,b); +} + + + +static int r8192_wx_get_rate(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + return ieee80211_wx_get_rate(priv->ieee80211,info,wrqu,extra); +} + + + +static int r8192_wx_set_rate(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + struct r8192_priv *priv = ieee80211_priv(dev); + + down(&priv->wx_sem); + + ret = ieee80211_wx_set_rate(priv->ieee80211,info,wrqu,extra); + + up(&priv->wx_sem); + + return ret; +} + + +static int r8192_wx_set_rts(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + struct r8192_priv *priv = ieee80211_priv(dev); + + down(&priv->wx_sem); + + ret = ieee80211_wx_set_rts(priv->ieee80211,info,wrqu,extra); + + up(&priv->wx_sem); + + return ret; +} + +static int r8192_wx_get_rts(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + return ieee80211_wx_get_rts(priv->ieee80211,info,wrqu,extra); +} + +static int r8192_wx_set_power(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + struct r8192_priv *priv = ieee80211_priv(dev); + + down(&priv->wx_sem); + + ret = ieee80211_wx_set_power(priv->ieee80211,info,wrqu,extra); + + up(&priv->wx_sem); + + return ret; +} + +static int r8192_wx_get_power(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + return ieee80211_wx_get_power(priv->ieee80211,info,wrqu,extra); +} + +#ifdef JOHN_IOCTL +u16 read_rtl8225(struct net_device *dev, u8 addr); +void write_rtl8225(struct net_device *dev, u8 adr, u16 data); +u32 john_read_rtl8225(struct net_device *dev, u8 adr); +void _write_rtl8225(struct net_device *dev, u8 adr, u16 data); + +static int r8192_wx_read_regs(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + u8 addr; + u16 data1; + + down(&priv->wx_sem); + + + get_user(addr,(u8*)wrqu->data.pointer); + data1 = read_rtl8225(dev, addr); + wrqu->data.length = data1; + + up(&priv->wx_sem); + return 0; + +} + +static int r8192_wx_write_regs(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + u8 addr; + + down(&priv->wx_sem); + + get_user(addr, (u8*)wrqu->data.pointer); + write_rtl8225(dev, addr, wrqu->data.length); + + up(&priv->wx_sem); + return 0; + +} + +void rtl8187_write_phy(struct net_device *dev, u8 adr, u32 data); +u8 rtl8187_read_phy(struct net_device *dev,u8 adr, u32 data); + +static int r8192_wx_read_bb(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + u8 databb; +#if 0 + int i; + for(i=0;i<12;i++) printk("%8x\n", read_cam(dev, i) ); +#endif + + down(&priv->wx_sem); + + databb = rtl8187_read_phy(dev, (u8)wrqu->data.length, 0x00000000); + wrqu->data.length = databb; + + up(&priv->wx_sem); + return 0; +} + +void rtl8187_write_phy(struct net_device *dev, u8 adr, u32 data); +static int r8192_wx_write_bb(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + u8 databb; + + down(&priv->wx_sem); + + get_user(databb, (u8*)wrqu->data.pointer); + rtl8187_write_phy(dev, wrqu->data.length, databb); + + up(&priv->wx_sem); + return 0; + +} + + +static int r8192_wx_write_nicb(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + u32 addr; + + down(&priv->wx_sem); + + get_user(addr, (u32*)wrqu->data.pointer); + write_nic_byte(dev, addr, wrqu->data.length); + + up(&priv->wx_sem); + return 0; + +} +static int r8192_wx_read_nicb(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + u32 addr; + u16 data1; + + down(&priv->wx_sem); + + get_user(addr,(u32*)wrqu->data.pointer); + data1 = read_nic_byte(dev, addr); + wrqu->data.length = data1; + + up(&priv->wx_sem); + return 0; +} + +static int r8192_wx_get_ap_status(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + struct ieee80211_device *ieee = priv->ieee80211; + struct ieee80211_network *target; + int name_len; + + down(&priv->wx_sem); + + //count the length of input ssid + for(name_len=0 ; ((char*)wrqu->data.pointer)[name_len]!='\0' ; name_len++); + + //search for the correspoding info which is received + list_for_each_entry(target, &ieee->network_list, list) { + if ( (target->ssid_len == name_len) && + (strncmp(target->ssid, (char*)wrqu->data.pointer, name_len)==0)){ + if(target->wpa_ie_len>0 || target->rsn_ie_len>0 ) + //set flags=1 to indicate this ap is WPA + wrqu->data.flags = 1; + else wrqu->data.flags = 0; + + + break; + } + } + + up(&priv->wx_sem); + return 0; +} + + + +#endif +#if 0 +static int r8192_wx_null(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + return 0; +} +#endif +static int r8192_wx_force_reset(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + + down(&priv->wx_sem); + + printk("%s(): force reset ! extra is %d\n",__FUNCTION__, *extra); + priv->force_reset = *extra; + up(&priv->wx_sem); + return 0; + +} + +#ifdef RTL8192SU +static int r8191su_wx_get_firm_version(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *wrqu, char *extra) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + u16 firmware_version; + + down(&priv->wx_sem); + firmware_version = priv->pFirmware->FirmwareVersion; + wrqu->value = firmware_version; + wrqu->fixed = 1; + + up(&priv->wx_sem); + return 0; +} +#endif + + + +static int r8192_wx_set_rawtx(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + int ret; + + down(&priv->wx_sem); + + ret = ieee80211_wx_set_rawtx(priv->ieee80211, info, wrqu, extra); + + up(&priv->wx_sem); + + return ret; + +} + +static int r8192_wx_set_crcmon(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + int *parms = (int *)extra; + int enable = (parms[0] > 0); + short prev = priv->crcmon; + + down(&priv->wx_sem); + + if(enable) + priv->crcmon=1; + else + priv->crcmon=0; + + DMESG("bad CRC in monitor mode are %s", + priv->crcmon ? "accepted" : "rejected"); + + if(prev != priv->crcmon && priv->up){ + //rtl8180_down(dev); + //rtl8180_up(dev); + } + + up(&priv->wx_sem); + + return 0; +} + +static int r8192_wx_set_mode(struct net_device *dev, struct iw_request_info *a, + union iwreq_data *wrqu, char *b) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + int ret; + down(&priv->wx_sem); + + ret = ieee80211_wx_set_mode(priv->ieee80211,a,wrqu,b); + + rtl8192_set_rxconf(dev); + + up(&priv->wx_sem); + return ret; +} + +struct iw_range_with_scan_capa +{ + /* Informative stuff (to choose between different interface) */ + __u32 throughput; /* To give an idea... */ + /* In theory this value should be the maximum benchmarked + * TCP/IP throughput, because with most of these devices the + * bit rate is meaningless (overhead an co) to estimate how + * fast the connection will go and pick the fastest one. + * I suggest people to play with Netperf or any benchmark... + */ + + /* NWID (or domain id) */ + __u32 min_nwid; /* Minimal NWID we are able to set */ + __u32 max_nwid; /* Maximal NWID we are able to set */ + + /* Old Frequency (backward compat - moved lower ) */ + __u16 old_num_channels; + __u8 old_num_frequency; + + /* Scan capabilities */ + __u8 scan_capa; +}; +static int rtl8180_wx_get_range(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct iw_range *range = (struct iw_range *)extra; + struct iw_range_with_scan_capa* tmp = (struct iw_range_with_scan_capa*)range; + struct r8192_priv *priv = ieee80211_priv(dev); + u16 val; + int i; + + wrqu->data.length = sizeof(*range); + memset(range, 0, sizeof(*range)); + + /* Let's try to keep this struct in the same order as in + * linux/include/wireless.h + */ + + /* TODO: See what values we can set, and remove the ones we can't + * set, or fill them with some default data. + */ + + /* ~5 Mb/s real (802.11b) */ + range->throughput = 5 * 1000 * 1000; + + // TODO: Not used in 802.11b? +// range->min_nwid; /* Minimal NWID we are able to set */ + // TODO: Not used in 802.11b? +// range->max_nwid; /* Maximal NWID we are able to set */ + + /* Old Frequency (backward compat - moved lower ) */ +// range->old_num_channels; +// range->old_num_frequency; +// range->old_freq[6]; /* Filler to keep "version" at the same offset */ + if(priv->rf_set_sens != NULL) + range->sensitivity = priv->max_sens; /* signal level threshold range */ + + range->max_qual.qual = 100; + /* TODO: Find real max RSSI and stick here */ + range->max_qual.level = 0; + range->max_qual.noise = -98; + range->max_qual.updated = 7; /* Updated all three */ + + range->avg_qual.qual = 92; /* > 8% missed beacons is 'bad' */ + /* TODO: Find real 'good' to 'bad' threshol value for RSSI */ + range->avg_qual.level = 20 + -98; + range->avg_qual.noise = 0; + range->avg_qual.updated = 7; /* Updated all three */ + + range->num_bitrates = RATE_COUNT; + + for (i = 0; i < RATE_COUNT && i < IW_MAX_BITRATES; i++) { + range->bitrate[i] = rtl8180_rates[i]; + } + + range->min_frag = MIN_FRAG_THRESHOLD; + range->max_frag = MAX_FRAG_THRESHOLD; + + range->min_pmp=0; + range->max_pmp = 5000000; + range->min_pmt = 0; + range->max_pmt = 65535*1000; + range->pmp_flags = IW_POWER_PERIOD; + range->pmt_flags = IW_POWER_TIMEOUT; + range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R; + + range->we_version_compiled = WIRELESS_EXT; + range->we_version_source = 16; + +// range->retry_capa; /* What retry options are supported */ +// range->retry_flags; /* How to decode max/min retry limit */ +// range->r_time_flags; /* How to decode max/min retry life */ +// range->min_retry; /* Minimal number of retries */ +// range->max_retry; /* Maximal number of retries */ +// range->min_r_time; /* Minimal retry lifetime */ +// range->max_r_time; /* Maximal retry lifetime */ + + + for (i = 0, val = 0; i < 14; i++) { + + // Include only legal frequencies for some countries +#ifdef ENABLE_DOT11D + if ((GET_DOT11D_INFO(priv->ieee80211)->channel_map)[i+1]) { +#else + if ((priv->ieee80211->channel_map)[i+1]) { +#endif + range->freq[val].i = i + 1; + range->freq[val].m = ieee80211_wlan_frequencies[i] * 100000; + range->freq[val].e = 1; + val++; + } else { + // FIXME: do we need to set anything for channels + // we don't use ? + } + + if (val == IW_MAX_FREQUENCIES) + break; + } + range->num_frequency = val; + range->num_channels = val; +#if WIRELESS_EXT > 17 + range->enc_capa = IW_ENC_CAPA_WPA|IW_ENC_CAPA_WPA2| + IW_ENC_CAPA_CIPHER_TKIP|IW_ENC_CAPA_CIPHER_CCMP; +#endif + tmp->scan_capa = 0x01; + return 0; +} + + +static int r8192_wx_set_scan(struct net_device *dev, struct iw_request_info *a, + union iwreq_data *wrqu, char *b) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + struct ieee80211_device* ieee = priv->ieee80211; + int ret = 0; + + if(!priv->up) return -ENETDOWN; + + if (priv->ieee80211->LinkDetectInfo.bBusyTraffic == true) + return -EAGAIN; +#if WIRELESS_EXT > 17 + if (wrqu->data.flags & IW_SCAN_THIS_ESSID) + { + struct iw_scan_req* req = (struct iw_scan_req*)b; + if (req->essid_len) + { + //printk("==**&*&*&**===>scan set ssid:%s\n", req->essid); + ieee->current_network.ssid_len = req->essid_len; + memcpy(ieee->current_network.ssid, req->essid, req->essid_len); + //printk("=====>network ssid:%s\n", ieee->current_network.ssid); + } + } +#endif + + down(&priv->wx_sem); + if(priv->ieee80211->state != IEEE80211_LINKED){ + priv->ieee80211->scanning = 0; + ieee80211_softmac_scan_syncro(priv->ieee80211); + ret = 0; + } + else + ret = ieee80211_wx_set_scan(priv->ieee80211,a,wrqu,b); + up(&priv->wx_sem); + return ret; +} + + +static int r8192_wx_get_scan(struct net_device *dev, struct iw_request_info *a, + union iwreq_data *wrqu, char *b) +{ + + int ret; + struct r8192_priv *priv = ieee80211_priv(dev); + + if(!priv->up) return -ENETDOWN; + + down(&priv->wx_sem); + + ret = ieee80211_wx_get_scan(priv->ieee80211,a,wrqu,b); + + up(&priv->wx_sem); + + return ret; +} + +static int r8192_wx_set_essid(struct net_device *dev, + struct iw_request_info *a, + union iwreq_data *wrqu, char *b) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + int ret; + down(&priv->wx_sem); + + ret = ieee80211_wx_set_essid(priv->ieee80211,a,wrqu,b); + + up(&priv->wx_sem); + + return ret; +} + + + + +static int r8192_wx_get_essid(struct net_device *dev, + struct iw_request_info *a, + union iwreq_data *wrqu, char *b) +{ + int ret; + struct r8192_priv *priv = ieee80211_priv(dev); + + down(&priv->wx_sem); + + ret = ieee80211_wx_get_essid(priv->ieee80211, a, wrqu, b); + + up(&priv->wx_sem); + + return ret; +} + + +static int r8192_wx_set_freq(struct net_device *dev, struct iw_request_info *a, + union iwreq_data *wrqu, char *b) +{ + int ret; + struct r8192_priv *priv = ieee80211_priv(dev); + + down(&priv->wx_sem); + + ret = ieee80211_wx_set_freq(priv->ieee80211, a, wrqu, b); + + up(&priv->wx_sem); + return ret; +} + +static int r8192_wx_get_name(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + return ieee80211_wx_get_name(priv->ieee80211, info, wrqu, extra); +} + + +static int r8192_wx_set_frag(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + + if (wrqu->frag.disabled) + priv->ieee80211->fts = DEFAULT_FRAG_THRESHOLD; + else { + if (wrqu->frag.value < MIN_FRAG_THRESHOLD || + wrqu->frag.value > MAX_FRAG_THRESHOLD) + return -EINVAL; + + priv->ieee80211->fts = wrqu->frag.value & ~0x1; + } + + return 0; +} + + +static int r8192_wx_get_frag(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + + wrqu->frag.value = priv->ieee80211->fts; + wrqu->frag.fixed = 0; /* no auto select */ + wrqu->frag.disabled = (wrqu->frag.value == DEFAULT_FRAG_THRESHOLD); + + return 0; +} + + +static int r8192_wx_set_wap(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *awrq, + char *extra) +{ + + int ret; + struct r8192_priv *priv = ieee80211_priv(dev); +// struct sockaddr *temp = (struct sockaddr *)awrq; + down(&priv->wx_sem); + + ret = ieee80211_wx_set_wap(priv->ieee80211,info,awrq,extra); + + up(&priv->wx_sem); + + return ret; + +} + + +static int r8192_wx_get_wap(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + + return ieee80211_wx_get_wap(priv->ieee80211,info,wrqu,extra); +} + + +static int r8192_wx_get_enc(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *key) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + + return ieee80211_wx_get_encode(priv->ieee80211, info, wrqu, key); +} + +static int r8192_wx_set_enc(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *key) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + struct ieee80211_device *ieee = priv->ieee80211; + int ret; + + //u32 TargetContent; + u32 hwkey[4]={0,0,0,0}; + u8 mask=0xff; + u32 key_idx=0; + //u8 broadcast_addr[6] ={ 0xff,0xff,0xff,0xff,0xff,0xff}; + u8 zero_addr[4][6] ={ {0x00,0x00,0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x01}, + {0x00,0x00,0x00,0x00,0x00,0x02}, + {0x00,0x00,0x00,0x00,0x00,0x03} }; + int i; + + if(!priv->up) return -ENETDOWN; + + down(&priv->wx_sem); + + RT_TRACE(COMP_SEC, "Setting SW wep key"); + ret = ieee80211_wx_set_encode(priv->ieee80211,info,wrqu,key); + + up(&priv->wx_sem); + + + + //sometimes, the length is zero while we do not type key value + if(wrqu->encoding.length!=0){ + + for(i=0 ; i<4 ; i++){ + hwkey[i] |= key[4*i+0]&mask; + if(i==1&&(4*i+1)==wrqu->encoding.length) mask=0x00; + if(i==3&&(4*i+1)==wrqu->encoding.length) mask=0x00; + hwkey[i] |= (key[4*i+1]&mask)<<8; + hwkey[i] |= (key[4*i+2]&mask)<<16; + hwkey[i] |= (key[4*i+3]&mask)<<24; + } + + #define CONF_WEP40 0x4 + #define CONF_WEP104 0x14 + + switch(wrqu->encoding.flags & IW_ENCODE_INDEX){ + case 0: key_idx = ieee->tx_keyidx; break; + case 1: key_idx = 0; break; + case 2: key_idx = 1; break; + case 3: key_idx = 2; break; + case 4: key_idx = 3; break; + default: break; + } + + if(wrqu->encoding.length==0x5){ + ieee->pairwise_key_type = KEY_TYPE_WEP40; + EnableHWSecurityConfig8192(dev); + + setKey( dev, + key_idx, //EntryNo + key_idx, //KeyIndex + KEY_TYPE_WEP40, //KeyType + zero_addr[key_idx], + 0, //DefaultKey + hwkey); //KeyContent + + } + + else if(wrqu->encoding.length==0xd){ + ieee->pairwise_key_type = KEY_TYPE_WEP104; + EnableHWSecurityConfig8192(dev); + + setKey( dev, + key_idx, //EntryNo + key_idx, //KeyIndex + KEY_TYPE_WEP104, //KeyType + zero_addr[key_idx], + 0, //DefaultKey + hwkey); //KeyContent + + } + else printk("wrong type in WEP, not WEP40 and WEP104\n"); + + } + + return ret; +} + + +static int r8192_wx_set_scan_type(struct net_device *dev, struct iw_request_info *aa, union + iwreq_data *wrqu, char *p){ + + struct r8192_priv *priv = ieee80211_priv(dev); + int *parms=(int*)p; + int mode=parms[0]; + + priv->ieee80211->active_scan = mode; + + return 1; +} + + + +static int r8192_wx_set_retry(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + int err = 0; + + down(&priv->wx_sem); + + if (wrqu->retry.flags & IW_RETRY_LIFETIME || + wrqu->retry.disabled){ + err = -EINVAL; + goto exit; + } + if (!(wrqu->retry.flags & IW_RETRY_LIMIT)){ + err = -EINVAL; + goto exit; + } + + if(wrqu->retry.value > R8180_MAX_RETRY){ + err= -EINVAL; + goto exit; + } + if (wrqu->retry.flags & IW_RETRY_MAX) { + priv->retry_rts = wrqu->retry.value; + DMESG("Setting retry for RTS/CTS data to %d", wrqu->retry.value); + + }else { + priv->retry_data = wrqu->retry.value; + DMESG("Setting retry for non RTS/CTS data to %d", wrqu->retry.value); + } + + /* FIXME ! + * We might try to write directly the TX config register + * or to restart just the (R)TX process. + * I'm unsure if whole reset is really needed + */ + + rtl8192_commit(dev); + /* + if(priv->up){ + rtl8180_rtx_disable(dev); + rtl8180_rx_enable(dev); + rtl8180_tx_enable(dev); + + } + */ +exit: + up(&priv->wx_sem); + + return err; +} + +static int r8192_wx_get_retry(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + + + wrqu->retry.disabled = 0; /* can't be disabled */ + + if ((wrqu->retry.flags & IW_RETRY_TYPE) == + IW_RETRY_LIFETIME) + return -EINVAL; + + if (wrqu->retry.flags & IW_RETRY_MAX) { + wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX; + wrqu->retry.value = priv->retry_rts; + } else { + wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MIN; + wrqu->retry.value = priv->retry_data; + } + //printk("returning %d",wrqu->retry.value); + + + return 0; +} + +static int r8192_wx_get_sens(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + if(priv->rf_set_sens == NULL) + return -1; /* we have not this support for this radio */ + wrqu->sens.value = priv->sens; + return 0; +} + + +static int r8192_wx_set_sens(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + + struct r8192_priv *priv = ieee80211_priv(dev); + + short err = 0; + down(&priv->wx_sem); + //DMESG("attempt to set sensivity to %ddb",wrqu->sens.value); + if(priv->rf_set_sens == NULL) { + err= -1; /* we have not this support for this radio */ + goto exit; + } + if(priv->rf_set_sens(dev, wrqu->sens.value) == 0) + priv->sens = wrqu->sens.value; + else + err= -EINVAL; + +exit: + up(&priv->wx_sem); + + return err; +} + +#if (WIRELESS_EXT >= 18) +#if 0 +static int r8192_wx_get_enc_ext(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + int ret = 0; + ret = ieee80211_wx_get_encode_ext(priv->ieee80211, info, wrqu, extra); + return ret; +} +#endif +//hw security need to reorganized. +static int r8192_wx_set_enc_ext(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret=0; + #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + struct r8192_priv *priv = ieee80211_priv(dev); + struct ieee80211_device* ieee = priv->ieee80211; + //printk("===>%s()\n", __FUNCTION__); + + + down(&priv->wx_sem); + ret = ieee80211_wx_set_encode_ext(priv->ieee80211, info, wrqu, extra); + + { + u8 broadcast_addr[6] = {0xff,0xff,0xff,0xff,0xff,0xff}; + u8 zero[6] = {0}; + u32 key[4] = {0}; + struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; + struct iw_point *encoding = &wrqu->encoding; +#if 0 + static u8 CAM_CONST_ADDR[4][6] = { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x03}}; +#endif + u8 idx = 0, alg = 0, group = 0; + if ((encoding->flags & IW_ENCODE_DISABLED) || + ext->alg == IW_ENCODE_ALG_NONE) //none is not allowed to use hwsec WB 2008.07.01 + { + ieee->pairwise_key_type = ieee->group_key_type = KEY_TYPE_NA; + CamResetAllEntry(dev); + goto end_hw_sec; + } + alg = (ext->alg == IW_ENCODE_ALG_CCMP)?KEY_TYPE_CCMP:ext->alg; // as IW_ENCODE_ALG_CCMP is defined to be 3 and KEY_TYPE_CCMP is defined to 4; + idx = encoding->flags & IW_ENCODE_INDEX; + if (idx) + idx --; + group = ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY; + + if ((!group) || (IW_MODE_ADHOC == ieee->iw_mode) || (alg == KEY_TYPE_WEP40)) + { + if ((ext->key_len == 13) && (alg == KEY_TYPE_WEP40) ) + alg = KEY_TYPE_WEP104; + ieee->pairwise_key_type = alg; + EnableHWSecurityConfig8192(dev); + } + memcpy((u8*)key, ext->key, 16); //we only get 16 bytes key.why? WB 2008.7.1 + + if ((alg & KEY_TYPE_WEP40) && (ieee->auth_mode !=2) ) + { + + setKey( dev, + idx,//EntryNo + idx, //KeyIndex + alg, //KeyType + zero, //MacAddr + 0, //DefaultKey + key); //KeyContent + } + else if (group) + { + ieee->group_key_type = alg; + setKey( dev, + idx,//EntryNo + idx, //KeyIndex + alg, //KeyType + broadcast_addr, //MacAddr + 0, //DefaultKey + key); //KeyContent + } + else //pairwise key + { + setKey( dev, + 4,//EntryNo + idx, //KeyIndex + alg, //KeyType + (u8*)ieee->ap_mac_addr, //MacAddr + 0, //DefaultKey + key); //KeyContent + } + + + } + +end_hw_sec: + + up(&priv->wx_sem); +#endif + return ret; + +} +static int r8192_wx_set_auth(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *data, char *extra) +{ + int ret=0; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + //printk("====>%s()\n", __FUNCTION__); + struct r8192_priv *priv = ieee80211_priv(dev); + down(&priv->wx_sem); + ret = ieee80211_wx_set_auth(priv->ieee80211, info, &(data->param), extra); + up(&priv->wx_sem); +#endif + return ret; +} + +static int r8192_wx_set_mlme(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + //printk("====>%s()\n", __FUNCTION__); + + int ret=0; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + struct r8192_priv *priv = ieee80211_priv(dev); + down(&priv->wx_sem); + ret = ieee80211_wx_set_mlme(priv->ieee80211, info, wrqu, extra); + + up(&priv->wx_sem); +#endif + return ret; +} +#endif +static int r8192_wx_set_gen_ie(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *data, char *extra) +{ + //printk("====>%s(), len:%d\n", __FUNCTION__, data->length); + int ret=0; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + struct r8192_priv *priv = ieee80211_priv(dev); + down(&priv->wx_sem); +#if 1 + ret = ieee80211_wx_set_gen_ie(priv->ieee80211, extra, data->data.length); +#endif + up(&priv->wx_sem); + //printk("<======%s(), ret:%d\n", __FUNCTION__, ret); +#endif + return ret; + + +} + +static int dummy(struct net_device *dev, struct iw_request_info *a, + union iwreq_data *wrqu,char *b) +{ + return -1; +} + + +static iw_handler r8192_wx_handlers[] = +{ + NULL, /* SIOCSIWCOMMIT */ + r8192_wx_get_name, /* SIOCGIWNAME */ + dummy, /* SIOCSIWNWID */ + dummy, /* SIOCGIWNWID */ + r8192_wx_set_freq, /* SIOCSIWFREQ */ + r8192_wx_get_freq, /* SIOCGIWFREQ */ + r8192_wx_set_mode, /* SIOCSIWMODE */ + r8192_wx_get_mode, /* SIOCGIWMODE */ + r8192_wx_set_sens, /* SIOCSIWSENS */ + r8192_wx_get_sens, /* SIOCGIWSENS */ + NULL, /* SIOCSIWRANGE */ + rtl8180_wx_get_range, /* SIOCGIWRANGE */ + NULL, /* SIOCSIWPRIV */ + NULL, /* SIOCGIWPRIV */ + NULL, /* SIOCSIWSTATS */ + NULL, /* SIOCGIWSTATS */ + dummy, /* SIOCSIWSPY */ + dummy, /* SIOCGIWSPY */ + NULL, /* SIOCGIWTHRSPY */ + NULL, /* SIOCWIWTHRSPY */ + r8192_wx_set_wap, /* SIOCSIWAP */ + r8192_wx_get_wap, /* SIOCGIWAP */ +#if (WIRELESS_EXT >= 18) + r8192_wx_set_mlme, /* MLME-- */ +#else + NULL, +#endif + dummy, /* SIOCGIWAPLIST -- depricated */ + r8192_wx_set_scan, /* SIOCSIWSCAN */ + r8192_wx_get_scan, /* SIOCGIWSCAN */ + r8192_wx_set_essid, /* SIOCSIWESSID */ + r8192_wx_get_essid, /* SIOCGIWESSID */ + dummy, /* SIOCSIWNICKN */ + dummy, /* SIOCGIWNICKN */ + NULL, /* -- hole -- */ + NULL, /* -- hole -- */ + r8192_wx_set_rate, /* SIOCSIWRATE */ + r8192_wx_get_rate, /* SIOCGIWRATE */ + r8192_wx_set_rts, /* SIOCSIWRTS */ + r8192_wx_get_rts, /* SIOCGIWRTS */ + r8192_wx_set_frag, /* SIOCSIWFRAG */ + r8192_wx_get_frag, /* SIOCGIWFRAG */ + dummy, /* SIOCSIWTXPOW */ + dummy, /* SIOCGIWTXPOW */ + r8192_wx_set_retry, /* SIOCSIWRETRY */ + r8192_wx_get_retry, /* SIOCGIWRETRY */ + r8192_wx_set_enc, /* SIOCSIWENCODE */ + r8192_wx_get_enc, /* SIOCGIWENCODE */ + r8192_wx_set_power, /* SIOCSIWPOWER */ + r8192_wx_get_power, /* SIOCGIWPOWER */ + NULL, /*---hole---*/ + NULL, /*---hole---*/ + r8192_wx_set_gen_ie,//NULL, /* SIOCSIWGENIE */ + NULL, /* SIOCSIWGENIE */ + +#if (WIRELESS_EXT >= 18) + r8192_wx_set_auth,//NULL, /* SIOCSIWAUTH */ + NULL,//r8192_wx_get_auth,//NULL, /* SIOCSIWAUTH */ + r8192_wx_set_enc_ext, /* SIOCSIWENCODEEXT */ + NULL,//r8192_wx_get_enc_ext,//NULL, /* SIOCSIWENCODEEXT */ +#else + NULL, + NULL, + NULL, + NULL, +#endif + NULL, /* SIOCSIWPMKSA */ + NULL, /*---hole---*/ + +}; + + +static const struct iw_priv_args r8192_private_args[] = { + + { + SIOCIWFIRSTPRIV + 0x0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "badcrc" + }, + + { + SIOCIWFIRSTPRIV + 0x1, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "activescan" + + }, + { + SIOCIWFIRSTPRIV + 0x2, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "rawtx" + } +#ifdef JOHN_IOCTL + , + { + SIOCIWFIRSTPRIV + 0x3, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "readRF" + } + , + { + SIOCIWFIRSTPRIV + 0x4, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "writeRF" + } + , + { + SIOCIWFIRSTPRIV + 0x5, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "readBB" + } + , + { + SIOCIWFIRSTPRIV + 0x6, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "writeBB" + } + , + { + SIOCIWFIRSTPRIV + 0x7, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "readnicb" + } + , + { + SIOCIWFIRSTPRIV + 0x8, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "writenicb" + } + , + { + SIOCIWFIRSTPRIV + 0x9, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "apinfo" + } + +#endif + , + { + SIOCIWFIRSTPRIV + 0x3, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "forcereset" + } + +#ifdef RTL8192SU + , + { + SIOCIWFIRSTPRIV + 0x5, + IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_INT|IW_PRIV_SIZE_FIXED|1, + "firm_ver" + } +#endif +}; + + +static iw_handler r8192_private_handler[] = { +// r8192_wx_set_monitor, /* SIOCIWFIRSTPRIV */ + r8192_wx_set_crcmon, /*SIOCIWSECONDPRIV*/ +// r8192_wx_set_forceassociate, +// r8192_wx_set_beaconinterval, +// r8192_wx_set_monitor_type, + r8192_wx_set_scan_type, + r8192_wx_set_rawtx, +#ifdef JOHN_IOCTL + r8192_wx_read_regs, + r8192_wx_write_regs, + r8192_wx_read_bb, + r8192_wx_write_bb, + r8192_wx_read_nicb, + r8192_wx_write_nicb, + r8192_wx_get_ap_status, +#endif + r8192_wx_force_reset, + (iw_handler)NULL, +#ifdef RTL8192SU + (iw_handler)r8191su_wx_get_firm_version, +#endif +}; + +//#if WIRELESS_EXT >= 17 +struct iw_statistics *r8192_get_wireless_stats(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + struct ieee80211_device* ieee = priv->ieee80211; + struct iw_statistics* wstats = &priv->wstats; + int tmp_level = 0; + int tmp_qual = 0; + int tmp_noise = 0; + if(ieee->state < IEEE80211_LINKED) + { + wstats->qual.qual = 0; + wstats->qual.level = 0; + wstats->qual.noise = 0; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)) + wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; +#else + wstats->qual.updated = 0x0f; +#endif + return wstats; + } + + tmp_level = (&ieee->current_network)->stats.rssi; + tmp_qual = (&ieee->current_network)->stats.signal; + tmp_noise = (&ieee->current_network)->stats.noise; + //printk("level:%d, qual:%d, noise:%d\n", tmp_level, tmp_qual, tmp_noise); + + wstats->qual.level = tmp_level; + wstats->qual.qual = tmp_qual; + wstats->qual.noise = tmp_noise; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)) + wstats->qual.updated = IW_QUAL_ALL_UPDATED| IW_QUAL_DBM; +#else + wstats->qual.updated = 0x0f; +#endif + return wstats; +} +//#endif + + +struct iw_handler_def r8192_wx_handlers_def={ + .standard = r8192_wx_handlers, + .num_standard = sizeof(r8192_wx_handlers) / sizeof(iw_handler), + .private = r8192_private_handler, + .num_private = sizeof(r8192_private_handler) / sizeof(iw_handler), + .num_private_args = sizeof(r8192_private_args) / sizeof(struct iw_priv_args), +#if WIRELESS_EXT >= 17 + .get_wireless_stats = r8192_get_wireless_stats, +#endif + .private_args = (struct iw_priv_args *)r8192_private_args, +}; diff --git a/drivers/staging/rtl8192su/r8192U_wx.h b/drivers/staging/rtl8192su/r8192U_wx.h new file mode 100644 index 000000000000..b2f7a571b1c8 --- /dev/null +++ b/drivers/staging/rtl8192su/r8192U_wx.h @@ -0,0 +1,23 @@ +/* + This is part of rtl8180 OpenSource driver - v 0.3 + Copyright (C) Andrea Merello 2004 + Released under the terms of GPL (General Public Licence) + + Parts of this driver are based on the GPL part of the official realtek driver + Parts of this driver are based on the rtl8180 driver skeleton from Patric Schenke & Andres Salomon + Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver + + We want to tanks the Authors of such projects and the Ndiswrapper project Authors. +*/ + +/* this file (will) contains wireless extension handlers*/ + +#ifndef R8180_WX_H +#define R8180_WX_H +//#include +//#include "ieee80211.h" +extern struct iw_handler_def r8192_wx_handlers_def; +/* Enable the rtl819x_core.c to share this function, david 2008.9.22 */ +extern struct iw_statistics *r8192_get_wireless_stats(struct net_device *dev); + +#endif diff --git a/drivers/staging/rtl8192su/r819xU_HTGen.h b/drivers/staging/rtl8192su/r819xU_HTGen.h new file mode 100644 index 000000000000..7a60480c4b8e --- /dev/null +++ b/drivers/staging/rtl8192su/r819xU_HTGen.h @@ -0,0 +1,22 @@ +// +// IOT Action for different AP +// +typedef enum _HT_IOT_ACTION{ + HT_IOT_ACT_TX_USE_AMSDU_4K = 0x00000001, + HT_IOT_ACT_TX_USE_AMSDU_8K = 0x00000002, + HT_IOT_ACT_DECLARE_MCS13 = 0x00000004, + HT_IOT_ACT_DISABLE_EDCA_TURBO = 0x00000008, + HT_IOT_ACT_MGNT_USE_CCK_6M = 0x00000010, + HT_IOT_ACT_CDD_FSYNC = 0x00000020, + HT_IOT_ACT_PURE_N_MODE = 0x00000040, + + //LZM ADD 090224 + HT_IOT_ACT_EDCA_BIAS_ON_RX = 0x00004000, + HT_IOT_ACT_HYBRID_AGGREGATION = 0x00010000, + HT_IOT_ACT_AMSDU_ENABLE = 0x00000800, + HT_IOT_ACT_DISABLE_SHORT_GI = 0x00020000, + HT_IOT_ACT_DISABLE_HIGH_POWER = 0x00040000, + HT_IOT_ACT_DISABLE_TX_2SS = 0x00200000, + HT_IOT_ACT_DISABLE_TX_40_MHZ = 0x00080000, +}HT_IOT_ACTION_E, *PHT_IOT_ACTION_E; + diff --git a/drivers/staging/rtl8192su/r819xU_HTType.h b/drivers/staging/rtl8192su/r819xU_HTType.h new file mode 100644 index 000000000000..2994aa0876ad --- /dev/null +++ b/drivers/staging/rtl8192su/r819xU_HTType.h @@ -0,0 +1,392 @@ +#ifndef _R819XU_HTTYPE_H_ +#define _R819XU_HTTYPE_H_ + + +//------------------------------------------------------------ +// The HT Capability element is present in beacons, association request, +// reassociation request and probe response frames +//------------------------------------------------------------ + +// +// Operation mode value +// +#define HT_OPMODE_NO_PROTECT 0 +#define HT_OPMODE_OPTIONAL 1 +#define HT_OPMODE_40MHZ_PROTECT 2 +#define HT_OPMODE_MIXED 3 + +// +// MIMO Power Save Setings +// +#define MIMO_PS_STATIC 0 +#define MIMO_PS_DYNAMIC 1 +#define MIMO_PS_NOLIMIT 3 + + +// +// There should be 128 bits to cover all of the MCS rates. However, since +// 8190 does not support too much rates, one integer is quite enough. +// + +#define sHTCLng 4 + + +#define HT_SUPPORTED_MCS_1SS_BITMAP 0x000000ff +#define HT_SUPPORTED_MCS_2SS_BITMAP 0x0000ff00 +#define HT_SUPPORTED_MCS_1SS_2SS_BITMAP HT_MCS_1SS_BITMAP|HT_MCS_1SS_2SS_BITMAP + + +typedef enum _HT_MCS_RATE{ + HT_MCS0 = 0x00000001, + HT_MCS1 = 0x00000002, + HT_MCS2 = 0x00000004, + HT_MCS3 = 0x00000008, + HT_MCS4 = 0x00000010, + HT_MCS5 = 0x00000020, + HT_MCS6 = 0x00000040, + HT_MCS7 = 0x00000080, + HT_MCS8 = 0x00000100, + HT_MCS9 = 0x00000200, + HT_MCS10 = 0x00000400, + HT_MCS11 = 0x00000800, + HT_MCS12 = 0x00001000, + HT_MCS13 = 0x00002000, + HT_MCS14 = 0x00004000, + HT_MCS15 = 0x00008000, + // Do not define MCS32 here although 8190 support MCS32 +}HT_MCS_RATE,*PHT_MCS_RATE; + +// +// Represent Channel Width in HT Capabilities +// +typedef enum _HT_CHANNEL_WIDTH{ + HT_CHANNEL_WIDTH_20 = 0, + HT_CHANNEL_WIDTH_20_40 = 1, +}HT_CHANNEL_WIDTH, *PHT_CHANNEL_WIDTH; + +// +// Represent Extention Channel Offset in HT Capabilities +// This is available only in 40Mhz mode. +// +typedef enum _HT_EXTCHNL_OFFSET{ + HT_EXTCHNL_OFFSET_NO_EXT = 0, + HT_EXTCHNL_OFFSET_UPPER = 1, + HT_EXTCHNL_OFFSET_NO_DEF = 2, + HT_EXTCHNL_OFFSET_LOWER = 3, +}HT_EXTCHNL_OFFSET, *PHT_EXTCHNL_OFFSET; + +typedef enum _CHNLOP{ + CHNLOP_NONE = 0, // No Action now + CHNLOP_SCAN = 1, // Scan in progress + CHNLOP_SWBW = 2, // Bandwidth switching in progress + CHNLOP_SWCHNL = 3, // Software Channel switching in progress +} CHNLOP, *PCHNLOP; + +// Determine if the Channel Operation is in progress +#define CHHLOP_IN_PROGRESS(_pHTInfo) \ + ((_pHTInfo)->ChnlOp > CHNLOP_NONE) ? TRUE : FALSE + + +typedef enum _HT_ACTION{ + ACT_RECOMMAND_WIDTH = 0, + ACT_MIMO_PWR_SAVE = 1, + ACT_PSMP = 2, + ACT_SET_PCO_PHASE = 3, + ACT_MIMO_CHL_MEASURE = 4, + ACT_RECIPROCITY_CORRECT = 5, + ACT_MIMO_CSI_MATRICS = 6, + ACT_MIMO_NOCOMPR_STEER = 7, + ACT_MIMO_COMPR_STEER = 8, + ACT_ANTENNA_SELECT = 9, +} HT_ACTION, *PHT_ACTION; + + +/* 2007/06/07 MH Define sub-carrier mode for 40MHZ. */ +typedef enum _HT_Bandwidth_40MHZ_Sub_Carrier{ + SC_MODE_DUPLICATE = 0, + SC_MODE_LOWER = 1, + SC_MODE_UPPER = 2, + SC_MODE_FULL40MHZ = 3, +}HT_BW40_SC_E; + +typedef struct _HT_CAPABILITY_ELE{ + + //HT capability info + u8 AdvCoding:1; + u8 ChlWidth:1; + u8 MimoPwrSave:2; + u8 GreenField:1; + u8 ShortGI20Mhz:1; + u8 ShortGI40Mhz:1; + u8 TxSTBC:1; + u8 RxSTBC:2; + u8 DelayBA:1; + u8 MaxAMSDUSize:1; + u8 DssCCk:1; + u8 PSMP:1; + u8 Rsvd1:1; + u8 LSigTxopProtect:1; + + //MAC HT parameters info + u8 MaxRxAMPDUFactor:2; + u8 MPDUDensity:3; + u8 Rsvd2:3; + + //Supported MCS set + u8 MCS[16]; + + + //Extended HT Capability Info + u16 ExtHTCapInfo; + + //TXBF Capabilities + u8 TxBFCap[4]; + + //Antenna Selection Capabilities + u8 ASCap; + +}__attribute__((packed)) HT_CAPABILITY_ELE, *PHT_CAPABILITY_ELE; + +//------------------------------------------------------------ +// The HT Information element is present in beacons +// Only AP is required to include this element +//------------------------------------------------------------ + +typedef struct _HT_INFORMATION_ELE{ + u8 ControlChl; + + u8 ExtChlOffset:2; + u8 RecommemdedTxWidth:1; + u8 RIFS:1; + u8 PSMPAccessOnly:1; + u8 SrvIntGranularity:3; + + u8 OptMode:2; + u8 NonGFDevPresent:1; + u8 Revd1:5; + u8 Revd2:8; + + u8 Rsvd3:6; + u8 DualBeacon:1; + u8 DualCTSProtect:1; + + u8 SecondaryBeacon:1; + u8 LSigTxopProtectFull:1; + u8 PcoActive:1; + u8 PcoPhase:1; + u8 Rsvd4:4; + + u8 BasicMSC[16]; +}__attribute__((packed)) HT_INFORMATION_ELE, *PHT_INFORMATION_ELE; + +// +// MIMO Power Save control field. +// This is appear in MIMO Power Save Action Frame +// +typedef struct _MIMOPS_CTRL{ + u8 MimoPsEnable:1; + u8 MimoPsMode:1; + u8 Reserved:6; +} MIMOPS_CTRL, *PMIMOPS_CTRL; + +typedef enum _HT_SPEC_VER{ + HT_SPEC_VER_IEEE = 0, + HT_SPEC_VER_EWC = 1, +}HT_SPEC_VER, *PHT_SPEC_VER; + +typedef enum _HT_AGGRE_MODE_E{ + HT_AGG_AUTO = 0, + HT_AGG_FORCE_ENABLE = 1, + HT_AGG_FORCE_DISABLE = 2, +}HT_AGGRE_MODE_E, *PHT_AGGRE_MODE_E; + +//------------------------------------------------------------ +// The Data structure is used to keep HT related variables when card is +// configured as non-AP STA mode. **Note** Current_xxx should be set +// to default value in HTInitializeHTInfo() +//------------------------------------------------------------ + +typedef struct _RT_HIGH_THROUGHPUT{ +// DECLARE_RT_OBJECT(_RT_HIGH_THROUGHPUT); + u8 bEnableHT; + u8 bCurrentHTSupport; + + u8 bRegBW40MHz; // Tx 40MHz channel capablity + u8 bCurBW40MHz; // Tx 40MHz channel capability + + u8 bRegShortGI40MHz; // Tx Short GI for 40Mhz + u8 bCurShortGI40MHz; // Tx Short GI for 40MHz + + u8 bRegShortGI20MHz; // Tx Short GI for 20MHz + u8 bCurShortGI20MHz; // Tx Short GI for 20MHz + + u8 bRegSuppCCK; // Tx CCK rate capability + u8 bCurSuppCCK; // Tx CCK rate capability + + // 802.11n spec version for "peer" + HT_SPEC_VER ePeerHTSpecVer; + + + // HT related information for "Self" + HT_CAPABILITY_ELE SelfHTCap; // This is HT cap element sent to peer STA, which also indicate HT Rx capabilities. + HT_INFORMATION_ELE SelfHTInfo; // This is HT info element sent to peer STA, which also indicate HT Rx capabilities. + + // HT related information for "Peer" + u8 PeerHTCapBuf[32]; + u8 PeerHTInfoBuf[32]; + + + // A-MSDU related + u8 bAMSDU_Support; // This indicates Tx A-MSDU capability + u16 nAMSDU_MaxSize; // This indicates Tx A-MSDU capability + u8 bCurrent_AMSDU_Support; // This indicates Tx A-MSDU capability + u16 nCurrent_AMSDU_MaxSize; // This indicates Tx A-MSDU capability + + + // AMPDU related <2006.08.10 Emily> + u8 bAMPDUEnable; // This indicate Tx A-MPDU capability + u8 bCurrentAMPDUEnable; // This indicate Tx A-MPDU capability + u8 AMPDU_Factor; // This indicate Tx A-MPDU capability + u8 CurrentAMPDUFactor; // This indicate Tx A-MPDU capability + u8 MPDU_Density; // This indicate Tx A-MPDU capability + u8 CurrentMPDUDensity; // This indicate Tx A-MPDU capability + + // Forced A-MPDU enable + HT_AGGRE_MODE_E ForcedAMPDUMode; + u8 ForcedAMPDUFactor; + u8 ForcedMPDUDensity; + + // Forced A-MSDU enable + HT_AGGRE_MODE_E ForcedAMSDUMode; + u16 ForcedAMSDUMaxSize; + + u8 bForcedShortGI; + + u8 CurrentOpMode; + + // MIMO PS related + u8 SelfMimoPs; + u8 PeerMimoPs; + + // 40MHz Channel Offset settings. + HT_EXTCHNL_OFFSET CurSTAExtChnlOffset; + u8 bCurTxBW40MHz; // If we use 40 MHz to Tx + u8 PeerBandwidth; + + // For Bandwidth Switching + u8 bSwBwInProgress; + CHNLOP ChnlOp; // software switching channel in progress. By Bruce, 2008-02-15. + u8 SwBwStep; + //RT_TIMER SwBwTimer; + struct timer_list SwBwTimer; + + // For Realtek proprietary A-MPDU factor for aggregation + u8 bRegRT2RTAggregation; + u8 bCurrentRT2RTAggregation; + u8 bCurrentRT2RTLongSlotTime; + u8 szRT2RTAggBuffer[10]; + + // Rx Reorder control + u8 bRegRxReorderEnable; + u8 bCurRxReorderEnable; + u8 RxReorderWinSize; + u8 RxReorderPendingTime; + u16 RxReorderDropCounter; + +#ifdef USB_TX_DRIVER_AGGREGATION_ENABLE + u8 UsbTxAggrNum; +#endif +#ifdef USB_RX_AGGREGATION_SUPPORT + u8 UsbRxFwAggrEn; + u8 UsbRxFwAggrPageNum; + u8 UsbRxFwAggrPacketNum; + u8 UsbRxFwAggrTimeout; +#endif + + // Add for Broadcom(Linksys) IOT. Joseph + u8 bIsPeerBcm; + + // For IOT issue. + u32 IOTAction; +}RT_HIGH_THROUGHPUT, *PRT_HIGH_THROUGHPUT; + + +//------------------------------------------------------------ +// The Data structure is used to keep HT related variable for "each Sta" +// when card is configured as "AP mode" +//------------------------------------------------------------ + +typedef struct _RT_HTINFO_STA_ENTRY{ + u8 bEnableHT; + + u8 bSupportCck; + + u16 AMSDU_MaxSize; + + u8 AMPDU_Factor; + u8 MPDU_Density; + + u8 HTHighestOperaRate; + + u8 bBw40MHz; + + u8 MimoPs; + + u8 McsRateSet[16]; + + +}RT_HTINFO_STA_ENTRY, *PRT_HTINFO_STA_ENTRY; + + + + + +//------------------------------------------------------------ +// The Data structure is used to keep HT related variable for "each AP" +// when card is configured as "STA mode" +//------------------------------------------------------------ + +typedef struct _BSS_HT{ + + u8 bdSupportHT; + + // HT related elements + u8 bdHTCapBuf[32]; + u16 bdHTCapLen; + u8 bdHTInfoBuf[32]; + u16 bdHTInfoLen; + + HT_SPEC_VER bdHTSpecVer; + //HT_CAPABILITY_ELE bdHTCapEle; + //HT_INFORMATION_ELE bdHTInfoEle; + + u8 bdRT2RTAggregation; + u8 bdRT2RTLongSlotTime; + bool bdHT1R; +}BSS_HT, *PBSS_HT; + +typedef struct _MIMO_RSSI{ + u32 EnableAntenna; + u32 AntennaA; + u32 AntennaB; + u32 AntennaC; + u32 AntennaD; + u32 Average; +}MIMO_RSSI, *PMIMO_RSSI; + +typedef struct _MIMO_EVM{ + u32 EVM1; + u32 EVM2; +}MIMO_EVM, *PMIMO_EVM; + +typedef struct _FALSE_ALARM_STATISTICS{ + u32 Cnt_Parity_Fail; + u32 Cnt_Rate_Illegal; + u32 Cnt_Crc8_fail; + u32 Cnt_all; +}FALSE_ALARM_STATISTICS, *PFALSE_ALARM_STATISTICS; + + + +#endif //__INC_HTTYPE_H + diff --git a/drivers/staging/rtl8192su/r819xU_cmdpkt.c b/drivers/staging/rtl8192su/r819xU_cmdpkt.c new file mode 100644 index 000000000000..c1149c6f77bc --- /dev/null +++ b/drivers/staging/rtl8192su/r819xU_cmdpkt.c @@ -0,0 +1,826 @@ +/****************************************************************************** + + (c) Copyright 2008, RealTEK Technologies Inc. All Rights Reserved. + + Module: r819xusb_cmdpkt.c (RTL8190 TX/RX command packet handler Source C File) + + Note: The module is responsible for handling TX and RX command packet. + 1. TX : Send set and query configuration command packet. + 2. RX : Receive tx feedback, beacon state, query configuration + command packet. + + Function: + + Export: + + Abbrev: + + History: + Data Who Remark + + 05/06/2008 amy Create initial version porting from windows driver. + +******************************************************************************/ +#include "r8192U.h" +#include "r819xU_cmdpkt.h" +/*---------------------------Define Local Constant---------------------------*/ +/* Debug constant*/ +#define CMPK_DEBOUNCE_CNT 1 +/* 2007/10/24 MH Add for printing a range of data. */ +#define CMPK_PRINT(Address)\ +{\ + unsigned char i;\ + u32 temp[10];\ + \ + memcpy(temp, Address, 40);\ + for (i = 0; i <40; i+=4)\ + printk("\r\n %08x", temp[i]);\ +}\ +/*---------------------------Define functions---------------------------------*/ + +bool +SendTxCommandPacket( + struct net_device *dev, + void* pData, + u32 DataLen + ) +{ + bool rtStatus = true; + struct r8192_priv *priv = ieee80211_priv(dev); + struct sk_buff *skb; + cb_desc *tcb_desc; + unsigned char *ptr_buf; + //bool bLastInitPacket = false; + + //PlatformAcquireSpinLock(Adapter, RT_TX_SPINLOCK); + + //Get TCB and local buffer from common pool. (It is shared by CmdQ, MgntQ, and USB coalesce DataQ) + skb = dev_alloc_skb(USB_HWDESC_HEADER_LEN + DataLen + 4); + memcpy((unsigned char *)(skb->cb),&dev,sizeof(dev)); + tcb_desc = (cb_desc*)(skb->cb + MAX_DEV_ADDR_SIZE); + tcb_desc->queue_index = TXCMD_QUEUE; + tcb_desc->bCmdOrInit = DESC_PACKET_TYPE_NORMAL; + tcb_desc->bLastIniPkt = 0; + skb_reserve(skb, USB_HWDESC_HEADER_LEN); + ptr_buf = skb_put(skb, DataLen); + memset(ptr_buf,0,DataLen); + memcpy(ptr_buf,pData,DataLen); + tcb_desc->txbuf_size= (u16)DataLen; + + if(!priv->ieee80211->check_nic_enough_desc(dev,tcb_desc->queue_index)|| + (!skb_queue_empty(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index]))||\ + (priv->ieee80211->queue_stop) ) { + RT_TRACE(COMP_FIRMWARE,"===================NULL packet==================================> tx full!\n"); + skb_queue_tail(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index], skb); + } else { + priv->ieee80211->softmac_hard_start_xmit(skb,dev); + } + + //PlatformReleaseSpinLock(Adapter, RT_TX_SPINLOCK); + return rtStatus; +} + +/*----------------------------------------------------------------------------- + * Function: cmpk_message_handle_tx() + * + * Overview: Driver internal module can call the API to send message to + * firmware side. For example, you can send a debug command packet. + * Or you can send a request for FW to modify RLX4181 LBUS HW bank. + * Otherwise, you can change MAC/PHT/RF register by firmware at + * run time. We do not support message more than one segment now. + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 05/06/2008 amy porting from windows code. + * + *---------------------------------------------------------------------------*/ + extern bool cmpk_message_handle_tx( + struct net_device *dev, + u8* codevirtualaddress, + u32 packettype, + u32 buffer_len) +{ + + bool rt_status = true; +#ifdef RTL8192SU + return rt_status; +#else +#ifdef RTL8192U + return rt_status; +#else + struct r8192_priv *priv = ieee80211_priv(dev); + u16 frag_threshold; + u16 frag_length, frag_offset = 0; + //u16 total_size; + //int i; + + rt_firmware *pfirmware = priv->pFirmware; + struct sk_buff *skb; + unsigned char *seg_ptr; + cb_desc *tcb_desc; + u8 bLastIniPkt; + + firmware_init_param(dev); + //Fragmentation might be required + frag_threshold = pfirmware->cmdpacket_frag_thresold; + do { + if((buffer_len - frag_offset) > frag_threshold) { + frag_length = frag_threshold ; + bLastIniPkt = 0; + + } else { + frag_length = buffer_len - frag_offset; + bLastIniPkt = 1; + + } + + /* Allocate skb buffer to contain firmware info and tx descriptor info + * add 4 to avoid packet appending overflow. + * */ + #ifdef RTL8192U + skb = dev_alloc_skb(USB_HWDESC_HEADER_LEN + frag_length + 4); + #else + skb = dev_alloc_skb(frag_length + 4); + #endif + memcpy((unsigned char *)(skb->cb),&dev,sizeof(dev)); + tcb_desc = (cb_desc*)(skb->cb + MAX_DEV_ADDR_SIZE); + tcb_desc->queue_index = TXCMD_QUEUE; + tcb_desc->bCmdOrInit = packettype; + tcb_desc->bLastIniPkt = bLastIniPkt; + + #ifdef RTL8192U + skb_reserve(skb, USB_HWDESC_HEADER_LEN); + #endif + + seg_ptr = skb_put(skb, buffer_len); + /* + * Transform from little endian to big endian + * and pending zero + */ + memcpy(seg_ptr,codevirtualaddress,buffer_len); + tcb_desc->txbuf_size= (u16)buffer_len; + + + if(!priv->ieee80211->check_nic_enough_desc(dev,tcb_desc->queue_index)|| + (!skb_queue_empty(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index]))||\ + (priv->ieee80211->queue_stop) ) { + RT_TRACE(COMP_FIRMWARE,"=====================================================> tx full!\n"); + skb_queue_tail(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index], skb); + } else { + priv->ieee80211->softmac_hard_start_xmit(skb,dev); + } + + codevirtualaddress += frag_length; + frag_offset += frag_length; + + }while(frag_offset < buffer_len); + + return rt_status; + + +#endif +#endif +} /* CMPK_Message_Handle_Tx */ + +/*----------------------------------------------------------------------------- + * Function: cmpk_counttxstatistic() + * + * Overview: + * + * Input: PADAPTER pAdapter - . + * CMPK_TXFB_T *psTx_FB - . + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 05/12/2008 amy Create Version 0 porting from windows code. + * + *---------------------------------------------------------------------------*/ +static void +cmpk_count_txstatistic( + struct net_device *dev, + cmpk_txfb_t *pstx_fb) +{ + struct r8192_priv *priv = ieee80211_priv(dev); +#ifdef ENABLE_PS + RT_RF_POWER_STATE rtState; + + pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE, (pu1Byte)(&rtState)); + + // When RF is off, we should not count the packet for hw/sw synchronize + // reason, ie. there may be a duration while sw switch is changed and hw + // switch is being changed. 2006.12.04, by shien chang. + if (rtState == eRfOff) + { + return; + } +#endif + +#ifdef TODO + if(pAdapter->bInHctTest) + return; +#endif + /* We can not know the packet length and transmit type: broadcast or uni + or multicast. So the relative statistics must be collected in tx + feedback info. */ + if (pstx_fb->tok) + { + priv->stats.txfeedbackok++; + priv->stats.txoktotal++; + priv->stats.txokbytestotal += pstx_fb->pkt_length; + priv->stats.txokinperiod++; + + /* We can not make sure broadcast/multicast or unicast mode. */ + if (pstx_fb->pkt_type == PACKET_MULTICAST) + { + priv->stats.txmulticast++; + priv->stats.txbytesmulticast += pstx_fb->pkt_length; + } + else if (pstx_fb->pkt_type == PACKET_BROADCAST) + { + priv->stats.txbroadcast++; + priv->stats.txbytesbroadcast += pstx_fb->pkt_length; + } + else + { + priv->stats.txunicast++; + priv->stats.txbytesunicast += pstx_fb->pkt_length; + } + } + else + { + priv->stats.txfeedbackfail++; + priv->stats.txerrtotal++; + priv->stats.txerrbytestotal += pstx_fb->pkt_length; + + /* We can not make sure broadcast/multicast or unicast mode. */ + if (pstx_fb->pkt_type == PACKET_MULTICAST) + { + priv->stats.txerrmulticast++; + } + else if (pstx_fb->pkt_type == PACKET_BROADCAST) + { + priv->stats.txerrbroadcast++; + } + else + { + priv->stats.txerrunicast++; + } + } + + priv->stats.txretrycount += pstx_fb->retry_cnt; + priv->stats.txfeedbackretry += pstx_fb->retry_cnt; + +} /* cmpk_CountTxStatistic */ + + + +/*----------------------------------------------------------------------------- + * Function: cmpk_handle_tx_feedback() + * + * Overview: The function is responsible for extract the message inside TX + * feedbck message from firmware. It will contain dedicated info in + * ws-06-0063-rtl8190-command-packet-specification. Please + * refer to chapter "TX Feedback Element". We have to read 20 bytes + * in the command packet. + * + * Input: struct net_device * dev + * u8 * pmsg - Msg Ptr of the command packet. + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 05/08/2008 amy Create Version 0 porting from windows code. + * + *---------------------------------------------------------------------------*/ +static void +cmpk_handle_tx_feedback( + struct net_device *dev, + u8 * pmsg) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + cmpk_txfb_t rx_tx_fb; /* */ + + priv->stats.txfeedback++; + + /* 0. Display received message. */ + //cmpk_Display_Message(CMPK_RX_TX_FB_SIZE, pMsg); + + /* 1. Extract TX feedback info from RFD to temp structure buffer. */ + /* It seems that FW use big endian(MIPS) and DRV use little endian in + windows OS. So we have to read the content byte by byte or transfer + endian type before copy the message copy. */ +#if 0 // The TX FEEDBACK packet element address + //rx_tx_fb.Element_ID = pMsg[0]; + //rx_tx_fb.Length = pMsg[1]; + rx_tx_fb.TOK = pMsg[2]>>7; + rx_tx_fb.Fail_Reason = (pMsg[2] & 0x70) >> 4; + rx_tx_fb.TID = (pMsg[2] & 0x0F); + rx_tx_fb.Qos_Pkt = pMsg[3] >> 7; + rx_tx_fb.Bandwidth = (pMsg[3] & 0x40) >> 6; + rx_tx_fb.Retry_Cnt = pMsg[5]; + rx_tx_fb.Pkt_ID = (pMsg[6] << 8) | pMsg[7]; + rx_tx_fb.Seq_Num = (pMsg[8] << 8) | pMsg[9]; + rx_tx_fb.S_Rate = pMsg[10]; + rx_tx_fb.F_Rate = pMsg[11]; + rx_tx_fb.S_RTS_Rate = pMsg[12]; + rx_tx_fb.F_RTS_Rate = pMsg[13]; + rx_tx_fb.pkt_length = (pMsg[14] << 8) | pMsg[15]; +#endif + /* 2007/07/05 MH Use pointer to transfer structure memory. */ + //memcpy((UINT8 *)&rx_tx_fb, pMsg, sizeof(CMPK_TXFB_T)); + memcpy((u8*)&rx_tx_fb, pmsg, sizeof(cmpk_txfb_t)); + /* 2. Use tx feedback info to count TX statistics. */ + cmpk_count_txstatistic(dev, &rx_tx_fb); +#if 0 + /* 2007/07/11 MH Assign current operate rate. */ + if (pAdapter->RegWirelessMode == WIRELESS_MODE_A || + pAdapter->RegWirelessMode == WIRELESS_MODE_B || + pAdapter->RegWirelessMode == WIRELESS_MODE_G) + { + pMgntInfo->CurrentOperaRate = (rx_tx_fb.F_Rate & 0x7F); + } + else if (pAdapter->RegWirelessMode == WIRELESS_MODE_N_24G || + pAdapter->RegWirelessMode == WIRELESS_MODE_N_5G) + { + pMgntInfo->HTCurrentOperaRate = (rx_tx_fb.F_Rate & 0x8F); + } +#endif + /* 2007/01/17 MH Comment previous method for TX statistic function. */ + /* Collect info TX feedback packet to fill TCB. */ + /* We can not know the packet length and transmit type: broadcast or uni + or multicast. */ + //CountTxStatistics( pAdapter, &tcb ); + +} /* cmpk_Handle_Tx_Feedback */ + +void +cmdpkt_beacontimerinterrupt_819xusb( + struct net_device *dev +) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + u16 tx_rate; + { + // + // 070117, rcnjko: 87B have to S/W beacon for DTM encryption_cmn. + // + if(priv->ieee80211->current_network.mode == IEEE_A || + priv->ieee80211->current_network.mode == IEEE_N_5G || + (priv->ieee80211->current_network.mode == IEEE_N_24G && (!priv->ieee80211->pHTInfo->bCurSuppCCK))) + { + tx_rate = 60; + DMESG("send beacon frame tx rate is 6Mbpm\n"); + } + else + { + tx_rate =10; + DMESG("send beacon frame tx rate is 1Mbpm\n"); + } + + rtl819xusb_beacon_tx(dev,tx_rate); // HW Beacon + + } + +} + + + + +/*----------------------------------------------------------------------------- + * Function: cmpk_handle_interrupt_status() + * + * Overview: The function is responsible for extract the message from + * firmware. It will contain dedicated info in + * ws-07-0063-v06-rtl819x-command-packet-specification-070315.doc. + * Please refer to chapter "Interrupt Status Element". + * + * Input: struct net_device *dev, + * u8* pmsg - Message Pointer of the command packet. + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 05/12/2008 amy Add this for rtl8192 porting from windows code. + * + *---------------------------------------------------------------------------*/ +static void +cmpk_handle_interrupt_status( + struct net_device *dev, + u8* pmsg) +{ + cmpk_intr_sta_t rx_intr_status; /* */ + struct r8192_priv *priv = ieee80211_priv(dev); + + DMESG("---> cmpk_Handle_Interrupt_Status()\n"); + + /* 0. Display received message. */ + //cmpk_Display_Message(CMPK_RX_BEACON_STATE_SIZE, pMsg); + + /* 1. Extract TX feedback info from RFD to temp structure buffer. */ + /* It seems that FW use big endian(MIPS) and DRV use little endian in + windows OS. So we have to read the content byte by byte or transfer + endian type before copy the message copy. */ + //rx_bcn_state.Element_ID = pMsg[0]; + //rx_bcn_state.Length = pMsg[1]; + rx_intr_status.length = pmsg[1]; + if (rx_intr_status.length != (sizeof(cmpk_intr_sta_t) - 2)) + { + DMESG("cmpk_Handle_Interrupt_Status: wrong length!\n"); + return; + } + + + // Statistics of beacon for ad-hoc mode. + if( priv->ieee80211->iw_mode == IW_MODE_ADHOC) + { + //2 maybe need endian transform? + rx_intr_status.interrupt_status = *((u32 *)(pmsg + 4)); + //rx_intr_status.InterruptStatus = N2H4BYTE(*((UINT32 *)(pMsg + 4))); + + DMESG("interrupt status = 0x%x\n", rx_intr_status.interrupt_status); + + if (rx_intr_status.interrupt_status & ISR_TxBcnOk) + { + priv->ieee80211->bibsscoordinator = true; + priv->stats.txbeaconokint++; + } + else if (rx_intr_status.interrupt_status & ISR_TxBcnErr) + { + priv->ieee80211->bibsscoordinator = false; + priv->stats.txbeaconerr++; + } + + if (rx_intr_status.interrupt_status & ISR_BcnTimerIntr) + { + cmdpkt_beacontimerinterrupt_819xusb(dev); + } + + } + + // Other informations in interrupt status we need? + + + DMESG("<---- cmpk_handle_interrupt_status()\n"); + +} /* cmpk_handle_interrupt_status */ + + +/*----------------------------------------------------------------------------- + * Function: cmpk_handle_query_config_rx() + * + * Overview: The function is responsible for extract the message from + * firmware. It will contain dedicated info in + * ws-06-0063-rtl8190-command-packet-specification. Please + * refer to chapter "Beacon State Element". + * + * Input: u8 * pmsg - Message Pointer of the command packet. + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 05/12/2008 amy Create Version 0 porting from windows code. + * + *---------------------------------------------------------------------------*/ +static void +cmpk_handle_query_config_rx( + struct net_device *dev, + u8* pmsg) +{ + cmpk_query_cfg_t rx_query_cfg; /* */ + + /* 0. Display received message. */ + //cmpk_Display_Message(CMPK_RX_BEACON_STATE_SIZE, pMsg); + + /* 1. Extract TX feedback info from RFD to temp structure buffer. */ + /* It seems that FW use big endian(MIPS) and DRV use little endian in + windows OS. So we have to read the content byte by byte or transfer + endian type before copy the message copy. */ + //rx_query_cfg.Element_ID = pMsg[0]; + //rx_query_cfg.Length = pMsg[1]; + rx_query_cfg.cfg_action = (pmsg[4] & 0x80000000)>>31; + rx_query_cfg.cfg_type = (pmsg[4] & 0x60) >> 5; + rx_query_cfg.cfg_size = (pmsg[4] & 0x18) >> 3; + rx_query_cfg.cfg_page = (pmsg[6] & 0x0F) >> 0; + rx_query_cfg.cfg_offset = pmsg[7]; + rx_query_cfg.value = (pmsg[8] << 24) | (pmsg[9] << 16) | + (pmsg[10] << 8) | (pmsg[11] << 0); + rx_query_cfg.mask = (pmsg[12] << 24) | (pmsg[13] << 16) | + (pmsg[14] << 8) | (pmsg[15] << 0); + +} /* cmpk_Handle_Query_Config_Rx */ + + +/*----------------------------------------------------------------------------- + * Function: cmpk_count_tx_status() + * + * Overview: Count aggregated tx status from firmwar of one type rx command + * packet element id = RX_TX_STATUS. + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 05/12/2008 amy Create Version 0 porting from windows code. + * + *---------------------------------------------------------------------------*/ +static void cmpk_count_tx_status( struct net_device *dev, + cmpk_tx_status_t *pstx_status) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + +#ifdef ENABLE_PS + + RT_RF_POWER_STATE rtstate; + + pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE, (pu1Byte)(&rtState)); + + // When RF is off, we should not count the packet for hw/sw synchronize + // reason, ie. there may be a duration while sw switch is changed and hw + // switch is being changed. 2006.12.04, by shien chang. + if (rtState == eRfOff) + { + return; + } +#endif + + priv->stats.txfeedbackok += pstx_status->txok; + priv->stats.txoktotal += pstx_status->txok; + + priv->stats.txfeedbackfail += pstx_status->txfail; + priv->stats.txerrtotal += pstx_status->txfail; + + priv->stats.txretrycount += pstx_status->txretry; + priv->stats.txfeedbackretry += pstx_status->txretry; + + //pAdapter->TxStats.NumTxOkBytesTotal += psTx_FB->pkt_length; + //pAdapter->TxStats.NumTxErrBytesTotal += psTx_FB->pkt_length; + //pAdapter->MgntInfo.LinkDetectInfo.NumTxOkInPeriod++; + + priv->stats.txmulticast += pstx_status->txmcok; + priv->stats.txbroadcast += pstx_status->txbcok; + priv->stats.txunicast += pstx_status->txucok; + + priv->stats.txerrmulticast += pstx_status->txmcfail; + priv->stats.txerrbroadcast += pstx_status->txbcfail; + priv->stats.txerrunicast += pstx_status->txucfail; + + priv->stats.txbytesmulticast += pstx_status->txmclength; + priv->stats.txbytesbroadcast += pstx_status->txbclength; + priv->stats.txbytesunicast += pstx_status->txuclength; + + priv->stats.last_packet_rate = pstx_status->rate; +} /* cmpk_CountTxStatus */ + + + +/*----------------------------------------------------------------------------- + * Function: cmpk_handle_tx_status() + * + * Overview: Firmware add a new tx feedback status to reduce rx command + * packet buffer operation load. + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 05/12/2008 amy Create Version 0 porting from windows code. + * + *---------------------------------------------------------------------------*/ +static void +cmpk_handle_tx_status( + struct net_device *dev, + u8* pmsg) +{ + cmpk_tx_status_t rx_tx_sts; /* */ + + memcpy((void*)&rx_tx_sts, (void*)pmsg, sizeof(cmpk_tx_status_t)); + /* 2. Use tx feedback info to count TX statistics. */ + cmpk_count_tx_status(dev, &rx_tx_sts); + +} /* cmpk_Handle_Tx_Status */ + + +/*----------------------------------------------------------------------------- + * Function: cmpk_handle_tx_rate_history() + * + * Overview: Firmware add a new tx rate history + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 05/12/2008 amy Create Version 0 porting from windows code. + * + *---------------------------------------------------------------------------*/ +static void +cmpk_handle_tx_rate_history( + struct net_device *dev, + u8* pmsg) +{ + cmpk_tx_rahis_t *ptxrate; +// RT_RF_POWER_STATE rtState; + u8 i, j; + u16 length = sizeof(cmpk_tx_rahis_t); + u32 *ptemp; + struct r8192_priv *priv = ieee80211_priv(dev); + + +#ifdef ENABLE_PS + pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE, (pu1Byte)(&rtState)); + + // When RF is off, we should not count the packet for hw/sw synchronize + // reason, ie. there may be a duration while sw switch is changed and hw + // switch is being changed. 2006.12.04, by shien chang. + if (rtState == eRfOff) + { + return; + } +#endif + + ptemp = (u32 *)pmsg; + + // + // Do endian transfer to word alignment(16 bits) for windows system. + // You must do different endian transfer for linux and MAC OS + // + for (i = 0; i < (length/4); i++) + { + u16 temp1, temp2; + + temp1 = ptemp[i]&0x0000FFFF; + temp2 = ptemp[i]>>16; + ptemp[i] = (temp1<<16)|temp2; + } + + ptxrate = (cmpk_tx_rahis_t *)pmsg; + + if (ptxrate == NULL ) + { + return; + } + + for (i = 0; i < 16; i++) + { + // Collect CCK rate packet num + if (i < 4) + priv->stats.txrate.cck[i] += ptxrate->cck[i]; + + // Collect OFDM rate packet num + if (i< 8) + priv->stats.txrate.ofdm[i] += ptxrate->ofdm[i]; + + for (j = 0; j < 4; j++) + priv->stats.txrate.ht_mcs[j][i] += ptxrate->ht_mcs[j][i]; + } + +} /* cmpk_Handle_Tx_Rate_History */ + + +/*----------------------------------------------------------------------------- + * Function: cmpk_message_handle_rx() + * + * Overview: In the function, we will capture different RX command packet + * info. Every RX command packet element has different message + * length and meaning in content. We only support three type of RX + * command packet now. Please refer to document + * ws-06-0063-rtl8190-command-packet-specification. + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 05/06/2008 amy Create Version 0 porting from windows code. + * + *---------------------------------------------------------------------------*/ +extern u32 +cmpk_message_handle_rx( + struct net_device *dev, + struct ieee80211_rx_stats *pstats) +{ +// u32 debug_level = DBG_LOUD; + struct r8192_priv *priv = ieee80211_priv(dev); + int total_length; + u8 cmd_length, exe_cnt = 0; + u8 element_id; + u8 *pcmd_buff; + + /* 0. Check inpt arguments. If is is a command queue message or pointer is + null. */ + if (/*(prfd->queue_id != CMPK_RX_QUEUE_ID) || */(pstats== NULL)) + { + /* Print error message. */ + /*RT_TRACE(COMP_SEND, DebugLevel, + ("\n\r[CMPK]-->Err queue id or pointer"));*/ + return 0; /* This is not a command packet. */ + } + + /* 1. Read received command packet message length from RFD. */ + total_length = pstats->Length; + + /* 2. Read virtual address from RFD. */ + pcmd_buff = pstats->virtual_address; + + /* 3. Read command pakcet element id and length. */ + element_id = pcmd_buff[0]; + /*RT_TRACE(COMP_SEND, DebugLevel, + ("\n\r[CMPK]-->element ID=%d Len=%d", element_id, total_length));*/ + + /* 4. Check every received command packet conent according to different + element type. Because FW may aggregate RX command packet to minimize + transmit time between DRV and FW.*/ + // Add a counter to prevent to locked in the loop too long + while (total_length > 0 || exe_cnt++ >100) + { + /* 2007/01/17 MH We support aggregation of different cmd in the same packet. */ + element_id = pcmd_buff[0]; + + switch(element_id) + { + case RX_TX_FEEDBACK: + cmpk_handle_tx_feedback (dev, pcmd_buff); + cmd_length = CMPK_RX_TX_FB_SIZE; + break; + + case RX_INTERRUPT_STATUS: + cmpk_handle_interrupt_status(dev, pcmd_buff); + cmd_length = sizeof(cmpk_intr_sta_t); + break; + + case BOTH_QUERY_CONFIG: + cmpk_handle_query_config_rx(dev, pcmd_buff); + cmd_length = CMPK_BOTH_QUERY_CONFIG_SIZE; + break; + + case RX_TX_STATUS: + cmpk_handle_tx_status(dev, pcmd_buff); + cmd_length = CMPK_RX_TX_STS_SIZE; + break; + + case RX_TX_PER_PKT_FEEDBACK: + // You must at lease add a switch case element here, + // Otherwise, we will jump to default case. + //DbgPrint("CCX Test\r\n"); + cmd_length = CMPK_RX_TX_FB_SIZE; + break; + + case RX_TX_RATE_HISTORY: + //DbgPrint(" rx tx rate history\r\n"); + cmpk_handle_tx_rate_history(dev, pcmd_buff); + cmd_length = CMPK_TX_RAHIS_SIZE; + break; + + default: + + RT_TRACE(COMP_ERR, "---->cmpk_message_handle_rx():unknow CMD Element\n"); + return 1; /* This is a command packet. */ + } + // 2007/01/22 MH Display received rx command packet info. + //cmpk_Display_Message(cmd_length, pcmd_buff); + + // 2007/01/22 MH Add to display tx statistic. + //cmpk_DisplayTxStatistic(pAdapter); + + /* 2007/03/09 MH Collect sidderent cmd element pkt num. */ + priv->stats.rxcmdpkt[element_id]++; + + total_length -= cmd_length; + pcmd_buff += cmd_length; + } /* while (total_length > 0) */ + return 1; /* This is a command packet. */ + +} /* CMPK_Message_Handle_Rx */ diff --git a/drivers/staging/rtl8192su/r819xU_cmdpkt.h b/drivers/staging/rtl8192su/r819xU_cmdpkt.h new file mode 100644 index 000000000000..f67af6cfd201 --- /dev/null +++ b/drivers/staging/rtl8192su/r819xU_cmdpkt.h @@ -0,0 +1,219 @@ +#ifndef R819XUSB_CMDPKT_H +#define R819XUSB_CMDPKT_H +/* Different command packet have dedicated message length and definition. */ +#define CMPK_RX_TX_FB_SIZE sizeof(cmpk_txfb_t) //20 +#define CMPK_TX_SET_CONFIG_SIZE sizeof(cmpk_set_cfg_t) //16 +#define CMPK_BOTH_QUERY_CONFIG_SIZE sizeof(cmpk_set_cfg_t) //16 +#define CMPK_RX_TX_STS_SIZE sizeof(cmpk_tx_status_t)// +#define CMPK_RX_DBG_MSG_SIZE sizeof(cmpk_rx_dbginfo_t)// +#define CMPK_TX_RAHIS_SIZE sizeof(cmpk_tx_rahis_t) + +/* 2008/05/08 amy For USB constant. */ +#define ISR_TxBcnOk BIT27 // Transmit Beacon OK +#define ISR_TxBcnErr BIT26 // Transmit Beacon Error +#define ISR_BcnTimerIntr BIT13 // Beacon Timer Interrupt + +#if 0 +/* Define packet type. */ +typedef enum tag_packet_type +{ + PACKET_BROADCAST, + PACKET_MULTICAST, + PACKET_UNICAST, + PACKET_TYPE_MAX +}cmpk_pkt_type_e; +#endif + +/* Define element ID of command packet. */ + +/*------------------------------Define structure----------------------------*/ +/* Define different command packet structure. */ +/* 1. RX side: TX feedback packet. */ +typedef struct tag_cmd_pkt_tx_feedback +{ + // DWORD 0 + u8 element_id; /* Command packet type. */ + u8 length; /* Command packet length. */ + /* 2007/07/05 MH Change tx feedback info field. */ + /*------TX Feedback Info Field */ + u8 TID:4; /* */ + u8 fail_reason:3; /* */ + u8 tok:1; /* Transmit ok. */ + u8 reserve1:4; /* */ + u8 pkt_type:2; /* */ + u8 bandwidth:1; /* */ + u8 qos_pkt:1; /* */ + + // DWORD 1 + u8 reserve2; /* */ + /*------TX Feedback Info Field */ + u8 retry_cnt; /* */ + u16 pkt_id; /* */ + + // DWORD 3 + u16 seq_num; /* */ + u8 s_rate; /* Start rate. */ + u8 f_rate; /* Final rate. */ + + // DWORD 4 + u8 s_rts_rate; /* */ + u8 f_rts_rate; /* */ + u16 pkt_length; /* */ + + // DWORD 5 + u16 reserve3; /* */ + u16 duration; /* */ +}cmpk_txfb_t; + +/* 2. RX side: Interrupt status packet. It includes Beacon State, + Beacon Timer Interrupt and other useful informations in MAC ISR Reg. */ +typedef struct tag_cmd_pkt_interrupt_status +{ + u8 element_id; /* Command packet type. */ + u8 length; /* Command packet length. */ + u16 reserve; + u32 interrupt_status; /* Interrupt Status. */ +}cmpk_intr_sta_t; + + +/* 3. TX side: Set configuration packet. */ +typedef struct tag_cmd_pkt_set_configuration +{ + u8 element_id; /* Command packet type. */ + u8 length; /* Command packet length. */ + u16 reserve1; /* */ + u8 cfg_reserve1:3; + u8 cfg_size:2; /* Configuration info. */ + u8 cfg_type:2; /* Configuration info. */ + u8 cfg_action:1; /* Configuration info. */ + u8 cfg_reserve2; /* Configuration info. */ + u8 cfg_page:4; /* Configuration info. */ + u8 cfg_reserve3:4; /* Configuration info. */ + u8 cfg_offset; /* Configuration info. */ + u32 value; /* */ + u32 mask; /* */ +}cmpk_set_cfg_t; + +/* 4. Both side : TX/RX query configuraton packet. The query structure is the + same as set configuration. */ +#define cmpk_query_cfg_t cmpk_set_cfg_t + +/* 5. Multi packet feedback status. */ +typedef struct tag_tx_stats_feedback // PJ quick rxcmd 09042007 +{ + // For endian transfer --> Driver will not the same as firmware structure. + // DW 0 + u16 reserve1; + u8 length; // Command packet length + u8 element_id; // Command packet type + + // DW 1 + u16 txfail; // Tx Fail count + u16 txok; // Tx ok count + + // DW 2 + u16 txmcok; // tx multicast + u16 txretry; // Tx Retry count + + // DW 3 + u16 txucok; // tx unicast + u16 txbcok; // tx broadcast + + // DW 4 + u16 txbcfail; // + u16 txmcfail; // + + // DW 5 + u16 reserve2; // + u16 txucfail; // + + // DW 6-8 + u32 txmclength; + u32 txbclength; + u32 txuclength; + + // DW 9 + u16 reserve3_23; + u8 reserve3_1; + u8 rate; +}__attribute__((packed)) cmpk_tx_status_t; + +/* 6. Debug feedback message. */ +/* 2007/10/23 MH Define RX debug message */ +typedef struct tag_rx_debug_message_feedback +{ + // For endian transfer --> for driver + // DW 0 + u16 reserve1; + u8 length; // Command packet length + u8 element_id; // Command packet type + + // DW 1-?? + // Variable debug message. + +}cmpk_rx_dbginfo_t; + +/* 2008/03/20 MH Define transmit rate history. For big endian format. */ +typedef struct tag_tx_rate_history +{ + // For endian transfer --> for driver + // DW 0 + u8 element_id; // Command packet type + u8 length; // Command packet length + u16 reserved1; + + // DW 1-2 CCK rate counter + u16 cck[4]; + + // DW 3-6 + u16 ofdm[8]; + + // DW 7-14 + //UINT16 MCS_BW0_SG0[16]; + + // DW 15-22 + //UINT16 MCS_BW1_SG0[16]; + + // DW 23-30 + //UINT16 MCS_BW0_SG1[16]; + + // DW 31-38 + //UINT16 MCS_BW1_SG1[16]; + + // DW 7-14 BW=0 SG=0 + // DW 15-22 BW=1 SG=0 + // DW 23-30 BW=0 SG=1 + // DW 31-38 BW=1 SG=1 + u16 ht_mcs[4][16]; + +}__attribute__((packed)) cmpk_tx_rahis_t; + +typedef enum tag_command_packet_directories +{ + RX_TX_FEEDBACK = 0, + RX_INTERRUPT_STATUS = 1, + TX_SET_CONFIG = 2, + BOTH_QUERY_CONFIG = 3, + RX_TX_STATUS = 4, + RX_DBGINFO_FEEDBACK = 5, + RX_TX_PER_PKT_FEEDBACK = 6, + RX_TX_RATE_HISTORY = 7, + RX_CMD_ELE_MAX +}cmpk_element_e; + +#if 0 +typedef enum _rt_status{ + RT_STATUS_SUCCESS, + RT_STATUS_FAILURE, + RT_STATUS_PENDING, + RT_STATUS_RESOURCE +}rt_status,*prt_status; +#endif + +extern bool cmpk_message_handle_tx(struct net_device *dev, u8* codevirtualaddress, u32 packettype, u32 buffer_len); + +extern u32 cmpk_message_handle_rx(struct net_device *dev, struct ieee80211_rx_stats * pstats); +extern bool SendTxCommandPacket( struct net_device *dev, void* pData, u32 DataLen); + + +#endif diff --git a/drivers/staging/rtl8192su/r819xU_firmware.c b/drivers/staging/rtl8192su/r819xU_firmware.c new file mode 100644 index 000000000000..219f71e8cda7 --- /dev/null +++ b/drivers/staging/rtl8192su/r819xU_firmware.c @@ -0,0 +1,707 @@ +/************************************************************************************************** + * Procedure: Init boot code/firmware code/data session + * + * Description: This routine will intialize firmware. If any error occurs during the initialization + * process, the routine shall terminate immediately and return fail. + * NIC driver should call NdisOpenFile only from MiniportInitialize. + * + * Arguments: The pointer of the adapter + + * Returns: + * NDIS_STATUS_FAILURE - the following initialization process should be terminated + * NDIS_STATUS_SUCCESS - if firmware initialization process success +**************************************************************************************************/ +//#include "ieee80211.h" +#include "r8192U.h" +#include "r8192U_hw.h" +#include "r819xU_firmware_img.h" +#include "r819xU_firmware.h" +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) +#include +#endif +void firmware_init_param(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + rt_firmware *pfirmware = priv->pFirmware; + + pfirmware->cmdpacket_frag_thresold = GET_COMMAND_PACKET_FRAG_THRESHOLD(MAX_TRANSMIT_BUFFER_SIZE); +} + +/* + * segment the img and use the ptr and length to remember info on each segment + * + */ +bool fw_download_code(struct net_device *dev, u8 *code_virtual_address, u32 buffer_len) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + bool rt_status = true; + u16 frag_threshold; + u16 frag_length, frag_offset = 0; + //u16 total_size; + int i; + + rt_firmware *pfirmware = priv->pFirmware; + struct sk_buff *skb; + unsigned char *seg_ptr; + cb_desc *tcb_desc; + u8 bLastIniPkt; + + firmware_init_param(dev); + //Fragmentation might be required + frag_threshold = pfirmware->cmdpacket_frag_thresold; + do { + if((buffer_len - frag_offset) > frag_threshold) { + frag_length = frag_threshold ; + bLastIniPkt = 0; + + } else { + frag_length = buffer_len - frag_offset; + bLastIniPkt = 1; + + } + + /* Allocate skb buffer to contain firmware info and tx descriptor info + * add 4 to avoid packet appending overflow. + * */ + #ifdef RTL8192U + skb = dev_alloc_skb(USB_HWDESC_HEADER_LEN + frag_length + 4); + #else + skb = dev_alloc_skb(frag_length + 4); + #endif + memcpy((unsigned char *)(skb->cb),&dev,sizeof(dev)); + tcb_desc = (cb_desc*)(skb->cb + MAX_DEV_ADDR_SIZE); + tcb_desc->queue_index = TXCMD_QUEUE; + tcb_desc->bCmdOrInit = DESC_PACKET_TYPE_INIT; + tcb_desc->bLastIniPkt = bLastIniPkt; + + #ifdef RTL8192U + skb_reserve(skb, USB_HWDESC_HEADER_LEN); + #endif + seg_ptr = skb->data; + /* + * Transform from little endian to big endian + * and pending zero + */ + for(i=0 ; i < frag_length; i+=4) { + *seg_ptr++ = ((i+0)txbuf_size= (u16)i; + skb_put(skb, i); + + if(!priv->ieee80211->check_nic_enough_desc(dev,tcb_desc->queue_index)|| + (!skb_queue_empty(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index]))||\ + (priv->ieee80211->queue_stop) ) { + RT_TRACE(COMP_FIRMWARE,"=====================================================> tx full!\n"); + skb_queue_tail(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index], skb); + } else { + priv->ieee80211->softmac_hard_start_xmit(skb,dev); + } + + code_virtual_address += frag_length; + frag_offset += frag_length; + + }while(frag_offset < buffer_len); + + return rt_status; + +#if 0 +cmdsend_downloadcode_fail: + rt_status = false; + RT_TRACE(COMP_ERR, "CmdSendDownloadCode fail !!\n"); + return rt_status; +#endif +} + +bool +fwSendNullPacket( + struct net_device *dev, + u32 Length +) +{ + bool rtStatus = true; + struct r8192_priv *priv = ieee80211_priv(dev); + struct sk_buff *skb; + cb_desc *tcb_desc; + unsigned char *ptr_buf; + bool bLastInitPacket = false; + + //PlatformAcquireSpinLock(Adapter, RT_TX_SPINLOCK); + + //Get TCB and local buffer from common pool. (It is shared by CmdQ, MgntQ, and USB coalesce DataQ) + skb = dev_alloc_skb(Length+ 4); + memcpy((unsigned char *)(skb->cb),&dev,sizeof(dev)); + tcb_desc = (cb_desc*)(skb->cb + MAX_DEV_ADDR_SIZE); + tcb_desc->queue_index = TXCMD_QUEUE; + tcb_desc->bCmdOrInit = DESC_PACKET_TYPE_INIT; + tcb_desc->bLastIniPkt = bLastInitPacket; + ptr_buf = skb_put(skb, Length); + memset(ptr_buf,0,Length); + tcb_desc->txbuf_size= (u16)Length; + + if(!priv->ieee80211->check_nic_enough_desc(dev,tcb_desc->queue_index)|| + (!skb_queue_empty(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index]))||\ + (priv->ieee80211->queue_stop) ) { + RT_TRACE(COMP_FIRMWARE,"===================NULL packet==================================> tx full!\n"); + skb_queue_tail(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index], skb); + } else { + priv->ieee80211->softmac_hard_start_xmit(skb,dev); + } + + //PlatformReleaseSpinLock(Adapter, RT_TX_SPINLOCK); + return rtStatus; +} + +#if 0 +/* + * Procedure : Download code into IMEM or DMEM + * Description: This routine will intialize firmware. If any error occurs during the initialization + * process, the routine shall terminate immediately and return fail. + * The routine copy virtual address get from opening of file into shared memory + * allocated during initialization. If code size larger than a conitneous shared + * memory may contain, the code should be divided into several section. + * !!!NOTES This finction should only be called during MPInitialization because + * A NIC driver should call NdisOpenFile only from MiniportInitialize. + * Arguments : The pointer of the adapter + * Code address (Virtual address, should fill descriptor with physical address) + * Code size + * Returns : + * RT_STATUS_FAILURE - the following initialization process should be terminated + * RT_STATUS_SUCCESS - if firmware initialization process success + */ +bool fwsend_download_code(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + rt_firmware *pfirmware = (rt_firmware*)(&priv->firmware); + + bool rt_status = true; + u16 length = 0; + u16 offset = 0; + u16 frag_threhold; + bool last_init_packet = false; + u32 check_txcmdwait_queueemptytime = 100000; + u16 cmd_buf_len; + u8 *ptr_cmd_buf; + + /* reset to 0 for first segment of img download */ + pfirmware->firmware_seg_index = 1; + + if(pfirmware->firmware_seg_index == pfirmware->firmware_seg_maxnum) { + last_init_packet = 1; + } + + cmd_buf_len = pfirmware->firmware_seg_container[pfirmware->firmware_seg_index-1].seg_size; + ptr_cmd_buf = pfirmware->firmware_seg_container[pfirmware->firmware_seg_index-1].seg_ptr; + rtl819xU_tx_cmd(dev, ptr_cmd_buf, cmd_buf_len, last_init_packet, DESC_PACKET_TYPE_INIT); + + rt_status = true; + return rt_status; +} +#endif + +//----------------------------------------------------------------------------- +// Procedure: Check whether main code is download OK. If OK, turn on CPU +// +// Description: CPU register locates in different page against general register. +// Switch to CPU register in the begin and switch back before return +// +// +// Arguments: The pointer of the adapter +// +// Returns: +// NDIS_STATUS_FAILURE - the following initialization process should be terminated +// NDIS_STATUS_SUCCESS - if firmware initialization process success +//----------------------------------------------------------------------------- +bool CPUcheck_maincodeok_turnonCPU(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + bool rt_status = true; + int check_putcodeOK_time = 200000, check_bootOk_time = 200000; + u32 CPU_status = 0; + + /* Check whether put code OK */ + do { + CPU_status = read_nic_dword(dev, CPU_GEN); + + if((CPU_status&CPU_GEN_PUT_CODE_OK) || (priv->usb_error==true)) + break; + + }while(check_putcodeOK_time--); + + if(!(CPU_status&CPU_GEN_PUT_CODE_OK)) { + RT_TRACE(COMP_ERR, "Download Firmware: Put code fail!\n"); + goto CPUCheckMainCodeOKAndTurnOnCPU_Fail; + } else { + RT_TRACE(COMP_FIRMWARE, "Download Firmware: Put code ok!\n"); + } + + /* Turn On CPU */ + CPU_status = read_nic_dword(dev, CPU_GEN); + write_nic_byte(dev, CPU_GEN, (u8)((CPU_status|CPU_GEN_PWR_STB_CPU)&0xff)); + mdelay(1000); + + /* Check whether CPU boot OK */ + do { + CPU_status = read_nic_dword(dev, CPU_GEN); + + if((CPU_status&CPU_GEN_BOOT_RDY)||(priv->usb_error == true)) + break; + }while(check_bootOk_time--); + + if(!(CPU_status&CPU_GEN_BOOT_RDY)) { + goto CPUCheckMainCodeOKAndTurnOnCPU_Fail; + } else { + RT_TRACE(COMP_FIRMWARE, "Download Firmware: Boot ready!\n"); + } + + return rt_status; + +CPUCheckMainCodeOKAndTurnOnCPU_Fail: + RT_TRACE(COMP_ERR, "ERR in %s()\n", __FUNCTION__); + rt_status = FALSE; + return rt_status; +} + +bool CPUcheck_firmware_ready(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + bool rt_status = true; + int check_time = 200000; + u32 CPU_status = 0; + + /* Check Firmware Ready */ + do { + CPU_status = read_nic_dword(dev, CPU_GEN); + + if((CPU_status&CPU_GEN_FIRM_RDY)||(priv->usb_error == true)) + break; + + }while(check_time--); + + if(!(CPU_status&CPU_GEN_FIRM_RDY)) + goto CPUCheckFirmwareReady_Fail; + else + RT_TRACE(COMP_FIRMWARE, "Download Firmware: Firmware ready!\n"); + + return rt_status; + +CPUCheckFirmwareReady_Fail: + RT_TRACE(COMP_ERR, "ERR in %s()\n", __FUNCTION__); + rt_status = false; + return rt_status; + +} + +bool init_firmware(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + bool rt_status = TRUE; + + u8 *firmware_img_buf[3] = { &rtl8190_fwboot_array[0], + &rtl8190_fwmain_array[0], + &rtl8190_fwdata_array[0]}; + + u32 firmware_img_len[3] = { sizeof(rtl8190_fwboot_array), + sizeof(rtl8190_fwmain_array), + sizeof(rtl8190_fwdata_array)}; + u32 file_length = 0; + u8 *mapped_file = NULL; + u32 init_step = 0; + opt_rst_type_e rst_opt = OPT_SYSTEM_RESET; + firmware_init_step_e starting_state = FW_INIT_STEP0_BOOT; + + rt_firmware *pfirmware = priv->pFirmware; + const struct firmware *fw_entry; + const char *fw_name[3] = { "RTL8192U/boot.img", + "RTL8192U/main.img", + "RTL8192U/data.img"}; + int rc; + + RT_TRACE(COMP_FIRMWARE, " PlatformInitFirmware()==>\n"); + + if (pfirmware->firmware_status == FW_STATUS_0_INIT ) { + /* it is called by reset */ + rst_opt = OPT_SYSTEM_RESET; + starting_state = FW_INIT_STEP0_BOOT; + // TODO: system reset + + }else if(pfirmware->firmware_status == FW_STATUS_5_READY) { + /* it is called by Initialize */ + rst_opt = OPT_FIRMWARE_RESET; + starting_state = FW_INIT_STEP2_DATA; + }else { + RT_TRACE(COMP_FIRMWARE, "PlatformInitFirmware: undefined firmware state\n"); + } + + /* + * Download boot, main, and data image for System reset. + * Download data image for firmware reseta + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + priv->firmware_source = FW_SOURCE_HEADER_FILE; +#else + priv->firmware_source = FW_SOURCE_IMG_FILE; +#endif + for(init_step = starting_state; init_step <= FW_INIT_STEP2_DATA; init_step++) { + /* + * Open Image file, and map file to contineous memory if open file success. + * or read image file from array. Default load from IMG file + */ + if(rst_opt == OPT_SYSTEM_RESET) { + switch(priv->firmware_source) { + case FW_SOURCE_IMG_FILE: +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + if(pfirmware->firmware_buf_size[init_step] == 0) { + rc = request_firmware(&fw_entry, fw_name[init_step],&priv->udev->dev); + if(rc < 0 ) { + RT_TRACE(COMP_ERR, "request firmware fail!\n"); + goto download_firmware_fail; + } + + if(fw_entry->size > sizeof(pfirmware->firmware_buf[init_step])) { + //RT_TRACE(COMP_ERR, "img file size exceed the container buffer fail!\n"); + RT_TRACE(COMP_FIRMWARE, "img file size exceed the container buffer fail!, entry_size = %d, buf_size = %d\n",fw_entry->size,sizeof(pfirmware->firmware_buf[init_step])); + + goto download_firmware_fail; + } + + if(init_step != FW_INIT_STEP1_MAIN) { + memcpy(pfirmware->firmware_buf[init_step],fw_entry->data,fw_entry->size); + pfirmware->firmware_buf_size[init_step] = fw_entry->size; + } else { +#ifdef RTL8190P + memcpy(pfirmware->firmware_buf[init_step],fw_entry->data,fw_entry->size); + pfirmware->firmware_buf_size[init_step] = fw_entry->size; +#else + memset(pfirmware->firmware_buf[init_step],0,128); + memcpy(&pfirmware->firmware_buf[init_step][128],fw_entry->data,fw_entry->size); + mapped_file = pfirmware->firmware_buf[init_step]; + pfirmware->firmware_buf_size[init_step] = fw_entry->size+128; +#endif + } + //pfirmware->firmware_buf_size = file_length; + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + if(rst_opt == OPT_SYSTEM_RESET) { + release_firmware(fw_entry); + } +#endif + } + mapped_file = pfirmware->firmware_buf[init_step]; + file_length = pfirmware->firmware_buf_size[init_step]; +#endif + + break; + + case FW_SOURCE_HEADER_FILE: + mapped_file = firmware_img_buf[init_step]; + file_length = firmware_img_len[init_step]; + if(init_step == FW_INIT_STEP2_DATA) { + memcpy(pfirmware->firmware_buf[init_step], mapped_file, file_length); + pfirmware->firmware_buf_size[init_step] = file_length; + } + break; + + default: + break; + } + + + }else if(rst_opt == OPT_FIRMWARE_RESET ) { + /* we only need to download data.img here */ + mapped_file = pfirmware->firmware_buf[init_step]; + file_length = pfirmware->firmware_buf_size[init_step]; + } + + /* Download image file */ + /* The firmware download process is just as following, + * 1. that is each packet will be segmented and inserted to the wait queue. + * 2. each packet segment will be put in the skb_buff packet. + * 3. each skb_buff packet data content will already include the firmware info + * and Tx descriptor info + * */ + rt_status = fw_download_code(dev,mapped_file,file_length); + + if(rt_status != TRUE) { + goto download_firmware_fail; + } + + switch(init_step) { + case FW_INIT_STEP0_BOOT: + /* Download boot + * initialize command descriptor. + * will set polling bit when firmware code is also configured + */ + pfirmware->firmware_status = FW_STATUS_1_MOVE_BOOT_CODE; +#ifdef RTL8190P + // To initialize IMEM, CPU move code from 0x80000080, hence, we send 0x80 byte packet + rt_status = fwSendNullPacket(dev, RTL8190_CPU_START_OFFSET); + if(rt_status != true) + { + RT_TRACE(COMP_INIT, "fwSendNullPacket() fail ! \n"); + goto download_firmware_fail; + } +#endif + //mdelay(1000); + /* + * To initialize IMEM, CPU move code from 0x80000080, + * hence, we send 0x80 byte packet + */ + break; + + case FW_INIT_STEP1_MAIN: + /* Download firmware code. Wait until Boot Ready and Turn on CPU */ + pfirmware->firmware_status = FW_STATUS_2_MOVE_MAIN_CODE; + + /* Check Put Code OK and Turn On CPU */ + rt_status = CPUcheck_maincodeok_turnonCPU(dev); + if(rt_status != TRUE) { + RT_TRACE(COMP_ERR, "CPUcheck_maincodeok_turnonCPU fail!\n"); + goto download_firmware_fail; + } + + pfirmware->firmware_status = FW_STATUS_3_TURNON_CPU; + break; + + case FW_INIT_STEP2_DATA: + /* download initial data code */ + pfirmware->firmware_status = FW_STATUS_4_MOVE_DATA_CODE; + mdelay(1); + + rt_status = CPUcheck_firmware_ready(dev); + if(rt_status != TRUE) { + RT_TRACE(COMP_ERR, "CPUcheck_firmware_ready fail(%d)!\n",rt_status); + goto download_firmware_fail; + } + + /* wait until data code is initialized ready.*/ + pfirmware->firmware_status = FW_STATUS_5_READY; + break; + } + } + + RT_TRACE(COMP_FIRMWARE, "Firmware Download Success\n"); + //assert(pfirmware->firmware_status == FW_STATUS_5_READY, ("Firmware Download Fail\n")); + + return rt_status; + +download_firmware_fail: + RT_TRACE(COMP_ERR, "ERR in %s()\n", __FUNCTION__); + rt_status = FALSE; + return rt_status; + +} + +#if 0 +/* + * Procedure: (1) Transform firmware code from little endian to big endian if required. + * (2) Number of bytes in Firmware downloading should be multiple + * of 4 bytes. If length is not multiple of 4 bytes, appending of zeros is required + * + */ +void CmdAppendZeroAndEndianTransform( + u1Byte *pDst, + u1Byte *pSrc, + u2Byte *pLength) +{ + + u2Byte ulAppendBytes = 0, i; + u2Byte ulLength = *pLength; + +//test only + //memset(pDst, 0xcc, 12); + + + /* Transform from little endian to big endian */ +//#if DEV_BUS_TYPE==PCI_INTERFACE +#if 0 + for( i=0 ; i<(*pLength) ; i+=4) + { + if((i+3) < (*pLength)) pDst[i+0] = pSrc[i+3]; + if((i+2) < (*pLength)) pDst[i+1] = pSrc[i+2]; + if((i+1) < (*pLength)) pDst[i+2] = pSrc[i+1]; + if((i+0) < (*pLength)) pDst[i+3] = pSrc[i+0]; + } +#else + pDst += USB_HWDESC_HEADER_LEN; + ulLength -= USB_HWDESC_HEADER_LEN; + + for( i=0 ; i0) + { + ulAppendBytes = 4-((*pLength) % 4); + + for(i=0 ; iFragLength[0] = (u2Byte)pTcb->BufferList[0].Length; + + QueueID=pTcb->SpecifiedQueueID; +#if DEV_BUS_TYPE!=USB_INTERFACE + firstDesc=curDesc=Adapter->NextTxDescToFill[QueueID]; +#endif + +#if DEV_BUS_TYPE!=USB_INTERFACE + if(VacancyTxDescNum(Adapter, QueueID) > pTcb->BufferCount) +#else + if(PlatformIsTxQueueAvailable(Adapter, QueueID, pTcb->BufferCount) && + RTIsListEmpty(&Adapter->TcbWaitQueue[QueueID])) +#endif + { + pTcb->nDescUsed=0; + + for(i=0 ; iBufferCount ; i++) + { + Adapter->HalFunc.TxFillCmdDescHandler( + Adapter, + pTcb, + QueueID, //QueueIndex + curDesc, //index + FragBufferIndex==0, //bFirstSeg + FragBufferIndex==(pTcb->FragBufCount[FragIndex]-1), //bLastSeg + pTcb->BufferList[i].VirtualAddress, //VirtualAddress + pTcb->BufferList[i].PhysicalAddressLow, //PhyAddressLow + pTcb->BufferList[i].Length, //BufferLen + i!=0, //bSetOwnBit + (i==(pTcb->BufferCount-1)) && bLastInitPacket, //bLastInitPacket + PacketType, //DescPacketType + pTcb->FragLength[FragIndex] //PktLen + ); + + if(FragBufferIndex==(pTcb->FragBufCount[FragIndex]-1)) + { // Last segment of the fragment. + pTcb->nFragSent++; + } + + FragBufferIndex++; + if(FragBufferIndex==pTcb->FragBufCount[FragIndex]) + { + FragIndex++; + FragBufferIndex=0; + } + +#if DEV_BUS_TYPE!=USB_INTERFACE + curDesc=(curDesc+1)%Adapter->NumTxDesc[QueueID]; +#endif + pTcb->nDescUsed++; + } + +#if DEV_BUS_TYPE!=USB_INTERFACE + RTInsertTailList(&Adapter->TcbBusyQueue[QueueID], &pTcb->List); + IncrementTxDescToFill(Adapter, QueueID, pTcb->nDescUsed); + Adapter->HalFunc.SetTxDescOWNHandler(Adapter, QueueID, firstDesc); + // TODO: should call poll use QueueID + Adapter->HalFunc.TxPollingHandler(Adapter, TXCMD_QUEUE); +#endif + } + else +#if DEV_BUS_TYPE!=USB_INTERFACE + goto CmdSendPacket_Fail; +#else + { + pTcb->bLastInitPacket = bLastInitPacket; + RTInsertTailList(&Adapter->TcbWaitQueue[pTcb->SpecifiedQueueID], &pTcb->List); + } +#endif + + return rtStatus; + +#if DEV_BUS_TYPE!=USB_INTERFACE +CmdSendPacket_Fail: + rtStatus = RT_STATUS_FAILURE; + return rtStatus; +#endif + +} +#endif + + + + +#if 0 +RT_STATUS +FWSendNullPacket( + IN PADAPTER Adapter, + IN u4Byte Length +) +{ + RT_STATUS rtStatus = RT_STATUS_SUCCESS; + + + PRT_TCB pTcb; + PRT_TX_LOCAL_BUFFER pBuf; + BOOLEAN bLastInitPacket = FALSE; + + PlatformAcquireSpinLock(Adapter, RT_TX_SPINLOCK); + +#if DEV_BUS_TYPE==USB_INTERFACE + Length += USB_HWDESC_HEADER_LEN; +#endif + + //Get TCB and local buffer from common pool. (It is shared by CmdQ, MgntQ, and USB coalesce DataQ) + if(MgntGetBuffer(Adapter, &pTcb, &pBuf)) + { + PlatformZeroMemory(pBuf->Buffer.VirtualAddress, Length); + rtStatus = CmdSendPacket(Adapter, pTcb, pBuf, Length, DESC_PACKET_TYPE_INIT, bLastInitPacket); //0 : always set LastInitPacket to zero +//#if HAL_CODE_BASE != RTL8190HW +// // TODO: for test only +// ReturnTCB(Adapter, pTcb, RT_STATUS_SUCCESS); +//#endif + if(rtStatus == RT_STATUS_FAILURE) + goto CmdSendNullPacket_Fail; + }else + goto CmdSendNullPacket_Fail; + + PlatformReleaseSpinLock(Adapter, RT_TX_SPINLOCK); + return rtStatus; + + +CmdSendNullPacket_Fail: + PlatformReleaseSpinLock(Adapter, RT_TX_SPINLOCK); + rtStatus = RT_STATUS_FAILURE; + RT_ASSERT(rtStatus == RT_STATUS_SUCCESS, ("CmdSendDownloadCode fail !!\n")); + return rtStatus; +} +#endif + + diff --git a/drivers/staging/rtl8192su/r819xU_firmware.h b/drivers/staging/rtl8192su/r819xU_firmware.h new file mode 100644 index 000000000000..10801be014e0 --- /dev/null +++ b/drivers/staging/rtl8192su/r819xU_firmware.h @@ -0,0 +1,106 @@ +#ifndef __INC_FIRMWARE_H +#define __INC_FIRMWARE_H + +#define RTL8190_CPU_START_OFFSET 0x80 +/* TODO: this definition is TBD */ +//#define USB_HWDESC_HEADER_LEN 0 + +/* It should be double word alignment */ +//#if DEV_BUS_TYPE==PCI_INTERFACE +//#define GET_COMMAND_PACKET_FRAG_THRESHOLD(v) 4*(v/4) - 8 +//#else +#define GET_COMMAND_PACKET_FRAG_THRESHOLD(v) (4*(v/4) - 8 - USB_HWDESC_HEADER_LEN) +//#endif + +typedef enum _firmware_init_step{ + FW_INIT_STEP0_BOOT = 0, + FW_INIT_STEP1_MAIN = 1, + FW_INIT_STEP2_DATA = 2, +}firmware_init_step_e; + +typedef enum _opt_rst_type{ + OPT_SYSTEM_RESET = 0, + OPT_FIRMWARE_RESET = 1, +}opt_rst_type_e; + +/* due to rtl8192 firmware */ +typedef enum _desc_packet_type_e{ + DESC_PACKET_TYPE_INIT = 0, + DESC_PACKET_TYPE_NORMAL = 1, +}desc_packet_type_e; + +typedef enum _firmware_source{ + FW_SOURCE_IMG_FILE = 0, + FW_SOURCE_HEADER_FILE = 1, //from header file +}firmware_source_e, *pfirmware_source_e; + +typedef enum _firmware_status{ + FW_STATUS_0_INIT = 0, + FW_STATUS_1_MOVE_BOOT_CODE = 1, + FW_STATUS_2_MOVE_MAIN_CODE = 2, + FW_STATUS_3_TURNON_CPU = 3, + FW_STATUS_4_MOVE_DATA_CODE = 4, + FW_STATUS_5_READY = 5, +}firmware_status_e; + +typedef struct _rt_firmare_seg_container { + u16 seg_size; + u8 *seg_ptr; +}fw_seg_container, *pfw_seg_container; + +#define RTL8190_MAX_FIRMWARE_CODE_SIZE 64000 //64k +#define MAX_FW_INIT_STEP 3 +typedef struct _rt_firmware{ + firmware_status_e firmware_status; + u16 cmdpacket_frag_thresold; + u8 firmware_buf[MAX_FW_INIT_STEP][RTL8190_MAX_FIRMWARE_CODE_SIZE]; + u16 firmware_buf_size[MAX_FW_INIT_STEP]; +}rt_firmware, *prt_firmware; + +typedef struct _rt_firmware_info_819xUsb{ + u8 sz_info[16]; +}rt_firmware_info_819xUsb, *prt_firmware_info_819xUsb; + +#if 0 +/* CPU related */ +RT_STATUS +CPUCheckMainCodeOKAndTurnOnCPU( + IN PADAPTER Adapter + ); + +RT_STATUS +CPUCheckFirmwareReady( + IN PADAPTER Adapter + ); + +/* Firmware related */ +VOID +FWInitializeParameters( + IN PADAPTER Adapter + ); + +RT_STATUS +FWSendDownloadCode( + IN PADAPTER Adapter, + IN pu1Byte CodeVirtualAddrress, + IN u4Byte BufferLen + ); + +RT_STATUS +FWSendNullPacket( + IN PADAPTER Adapter, + IN u4Byte Length + ); + +RT_STATUS +CmdSendPacket( + PADAPTER Adapter, + PRT_TCB pTcb, + PRT_TX_LOCAL_BUFFER pBuf, + u4Byte BufferLen, + u4Byte PacketType, + BOOLEAN bLastInitPacket + ); +#endif +#endif + diff --git a/drivers/staging/rtl8192su/r819xU_firmware_img.c b/drivers/staging/rtl8192su/r819xU_firmware_img.c new file mode 100644 index 000000000000..29b656d7d82b --- /dev/null +++ b/drivers/staging/rtl8192su/r819xU_firmware_img.c @@ -0,0 +1,3447 @@ +/*Created on 2008/ 7/16, 5:31*/ +#include + +u8 rtl8190_fwboot_array[] = { +0x10,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x3c,0x08,0xbf,0xc0,0x25,0x08,0x00,0x08, +0x3c,0x09,0xb0,0x03,0xad,0x28,0x00,0x20,0x40,0x80,0x68,0x00,0x00,0x00,0x00,0x00, +0x3c,0x0a,0xd0,0x00,0x40,0x8a,0x60,0x00,0x00,0x00,0x00,0x00,0x3c,0x08,0x80,0x01, +0x25,0x08,0xb0,0x50,0x24,0x09,0x00,0x01,0x3c,0x01,0x7f,0xff,0x34,0x21,0xff,0xff, +0x01,0x01,0x50,0x24,0x00,0x09,0x48,0x40,0x35,0x29,0x00,0x01,0x01,0x2a,0x10,0x2b, +0x14,0x40,0xff,0xfc,0x00,0x00,0x00,0x00,0x3c,0x0a,0x00,0x00,0x25,0x4a,0x00,0x00, +0x4c,0x8a,0x00,0x00,0x4c,0x89,0x08,0x00,0x00,0x00,0x00,0x00,0x3c,0x08,0x80,0x01, +0x25,0x08,0xb0,0x50,0x3c,0x01,0x80,0x00,0x01,0x21,0x48,0x25,0x3c,0x0a,0xbf,0xc0, +0x25,0x4a,0x00,0x7c,0x3c,0x0b,0xb0,0x03,0xad,0x6a,0x00,0x20,0xad,0x00,0x00,0x00, +0x21,0x08,0x00,0x04,0x01,0x09,0x10,0x2b,0x14,0x40,0xff,0xf8,0x00,0x00,0x00,0x00, +0x3c,0x08,0x80,0x01,0x25,0x08,0x7f,0xff,0x24,0x09,0x00,0x01,0x3c,0x01,0x7f,0xff, +0x34,0x21,0xff,0xff,0x01,0x01,0x50,0x24,0x00,0x09,0x48,0x40,0x35,0x29,0x00,0x01, +0x01,0x2a,0x10,0x2b,0x14,0x40,0xff,0xfc,0x00,0x00,0x00,0x00,0x3c,0x0a,0x80,0x01, +0x25,0x4a,0x00,0x00,0x3c,0x01,0x7f,0xff,0x34,0x21,0xff,0xff,0x01,0x41,0x50,0x24, +0x3c,0x09,0x00,0x01,0x35,0x29,0x7f,0xff,0x4c,0x8a,0x20,0x00,0x4c,0x89,0x28,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x24,0x08,0x04,0x10, +0x00,0x00,0x00,0x00,0x40,0x88,0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x3c,0x08,0xbf,0xc0,0x00,0x00,0x00,0x00,0x8d,0x09,0x00,0x00,0x00,0x00,0x00,0x00, +0x3c,0x0a,0xbf,0xc0,0x25,0x4a,0x01,0x20,0x3c,0x0b,0xb0,0x03,0xad,0x6a,0x00,0x20, +0x3c,0x08,0xb0,0x03,0x8d,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x35,0x29,0x00,0x10, +0xad,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x3c,0x08,0x80,0x00,0x25,0x08,0x4b,0x84, +0x01,0x00,0x00,0x08,0x00,0x00,0x00,0x00,}; + +u8 rtl8190_fwmain_array[] = { +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x40,0x04,0x68,0x00,0x40,0x05,0x70,0x00,0x40,0x06,0x40,0x00,0x0c,0x00,0x12,0x94, +0x00,0x00,0x00,0x00,0x40,0x1a,0x68,0x00,0x33,0x5b,0x00,0x3c,0x17,0x60,0x00,0x09, +0x00,0x00,0x00,0x00,0x40,0x1b,0x60,0x00,0x00,0x00,0x00,0x00,0x03,0x5b,0xd0,0x24, +0x40,0x1a,0x70,0x00,0x03,0x40,0x00,0x08,0x42,0x00,0x00,0x10,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x3c,0x02,0xff,0xff,0x34,0x42,0xff,0xff,0x8c,0x43,0x00,0x00, +0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x34,0x63,0x00,0x20,0x24,0x42,0x00,0xd0, +0xac,0x62,0x00,0x00,0x00,0x00,0x20,0x21,0x27,0x85,0x8b,0x60,0x00,0x85,0x18,0x21, +0x24,0x84,0x00,0x01,0x28,0x82,0x00,0x0a,0x14,0x40,0xff,0xfc,0xa0,0x60,0x00,0x00, +0x27,0x82,0x8b,0x6a,0x24,0x04,0x00,0x06,0x24,0x84,0xff,0xff,0xa4,0x40,0x00,0x00, +0x04,0x81,0xff,0xfd,0x24,0x42,0x00,0x02,0x24,0x02,0x00,0x03,0xa3,0x82,0x8b,0x60, +0x24,0x02,0x09,0xc4,0x24,0x03,0x01,0x00,0xa7,0x82,0x8b,0x76,0x24,0x02,0x04,0x00, +0xaf,0x83,0x8b,0x78,0xaf,0x82,0x8b,0x7c,0x24,0x03,0x00,0x0a,0x24,0x02,0x00,0x04, +0x24,0x05,0x00,0x02,0x24,0x04,0x00,0x01,0xa3,0x83,0x8b,0x62,0xa3,0x82,0x8b,0x68, +0x24,0x03,0x00,0x01,0x24,0x02,0x02,0x00,0xa3,0x84,0x8b,0x66,0xa3,0x85,0x8b,0x69, +0xa7,0x82,0x8b,0x6a,0xa7,0x83,0x8b,0x6c,0xa3,0x84,0x8b,0x61,0xa3,0x80,0x8b,0x63, +0xa3,0x80,0x8b,0x64,0xa3,0x80,0x8b,0x65,0xa3,0x85,0x8b,0x67,0x03,0xe0,0x00,0x08, +0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x24,0x42,0x01,0x84, +0x34,0x63,0x00,0x20,0xac,0x62,0x00,0x00,0x27,0x84,0x8b,0x88,0x00,0x00,0x10,0x21, +0x24,0x42,0x00,0x01,0x00,0x02,0x16,0x00,0x00,0x02,0x16,0x03,0x28,0x43,0x00,0x03, +0xac,0x80,0xff,0xfc,0xa0,0x80,0x00,0x00,0x14,0x60,0xff,0xf9,0x24,0x84,0x00,0x0c, +0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00, +0x34,0x63,0x00,0x20,0x24,0x42,0x01,0xc8,0x3c,0x08,0xb0,0x03,0xac,0x62,0x00,0x00, +0x35,0x08,0x00,0x70,0x8d,0x02,0x00,0x00,0x00,0xa0,0x48,0x21,0x00,0x04,0x26,0x00, +0x00,0x02,0x2a,0x43,0x00,0x06,0x36,0x00,0x00,0x07,0x3e,0x00,0x00,0x02,0x12,0x03, +0x29,0x23,0x00,0x03,0x00,0x04,0x56,0x03,0x00,0x06,0x36,0x03,0x00,0x07,0x3e,0x03, +0x30,0x48,0x00,0x01,0x10,0x60,0x00,0x11,0x30,0xa5,0x00,0x07,0x24,0x02,0x00,0x02, +0x00,0x49,0x10,0x23,0x00,0x45,0x10,0x07,0x30,0x42,0x00,0x01,0x10,0x40,0x00,0x66, +0x00,0x00,0x00,0x00,0x8f,0xa2,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x02,0x21,0x43, +0x11,0x00,0x00,0x10,0x00,0x07,0x20,0x0b,0x15,0x20,0x00,0x06,0x24,0x02,0x00,0x01, +0x3c,0x02,0xb0,0x05,0x34,0x42,0x01,0x20,0xa4,0x44,0x00,0x00,0x03,0xe0,0x00,0x08, +0x00,0x00,0x00,0x00,0x11,0x22,0x00,0x04,0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x05, +0x08,0x00,0x00,0x96,0x34,0x42,0x01,0x24,0x3c,0x02,0xb0,0x05,0x08,0x00,0x00,0x96, +0x34,0x42,0x01,0x22,0x15,0x20,0x00,0x54,0x24,0x02,0x00,0x01,0x3c,0x02,0xb0,0x03, +0x34,0x42,0x00,0x74,0x90,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0xaf,0x83,0x8b,0x84, +0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0x70,0x90,0x43,0x00,0x00,0x00,0x00,0x00,0x00, +0x30,0x6b,0x00,0x08,0x11,0x60,0x00,0x18,0x00,0x09,0x28,0x40,0x00,0x00,0x40,0x21, +0x27,0x85,0x8b,0x80,0x8c,0xa3,0x00,0x00,0x8c,0xa2,0x00,0x04,0x00,0x00,0x00,0x00, +0x00,0x62,0x38,0x23,0x00,0x43,0x10,0x2a,0x10,0x40,0x00,0x3d,0x00,0x00,0x00,0x00, +0xac,0xa7,0x00,0x00,0x25,0x02,0x00,0x01,0x00,0x02,0x16,0x00,0x00,0x02,0x46,0x03, +0x29,0x03,0x00,0x03,0x14,0x60,0xff,0xf3,0x24,0xa5,0x00,0x0c,0x3c,0x03,0xb0,0x03, +0x34,0x63,0x00,0x70,0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4b,0x10,0x23, +0xa0,0x62,0x00,0x00,0x00,0x09,0x28,0x40,0x00,0xa9,0x10,0x21,0x00,0x02,0x10,0x80, +0x27,0x83,0x8b,0x88,0x00,0x0a,0x20,0x0b,0x00,0x43,0x18,0x21,0x10,0xc0,0x00,0x05, +0x00,0x00,0x38,0x21,0x80,0x62,0x00,0x01,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x05, +0x00,0x00,0x00,0x00,0x80,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x03, +0x00,0xa9,0x10,0x21,0x24,0x07,0x00,0x01,0x00,0xa9,0x10,0x21,0x00,0x02,0x30,0x80, +0x27,0x82,0x8b,0x88,0xa0,0x67,0x00,0x01,0x00,0xc2,0x38,0x21,0x80,0xe3,0x00,0x01, +0x00,0x00,0x00,0x00,0x10,0x60,0x00,0x07,0x00,0x00,0x00,0x00,0x27,0x83,0x8b,0x80, +0x00,0xc3,0x18,0x21,0x8c,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x44,0x10,0x21, +0xac,0x62,0x00,0x00,0x27,0x85,0x8b,0x84,0x27,0x82,0x8b,0x80,0x00,0xc5,0x28,0x21, +0x00,0xc2,0x10,0x21,0x8c,0x43,0x00,0x00,0x8c,0xa4,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x64,0x18,0x2a,0x14,0x60,0x00,0x03,0x24,0x02,0x00,0x01,0x03,0xe0,0x00,0x08, +0xa0,0xe2,0x00,0x00,0xa0,0xe0,0x00,0x00,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00, +0x08,0x00,0x00,0xb9,0xac,0xa0,0x00,0x00,0x11,0x22,0x00,0x08,0x00,0x00,0x00,0x00, +0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0x7c,0x90,0x43,0x00,0x00,0x00,0x00,0x00,0x00, +0xaf,0x83,0x8b,0x9c,0x08,0x00,0x00,0xa9,0x3c,0x02,0xb0,0x03,0x3c,0x02,0xb0,0x03, +0x34,0x42,0x00,0x78,0x90,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0xaf,0x83,0x8b,0x90, +0x08,0x00,0x00,0xa9,0x3c,0x02,0xb0,0x03,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00, +0x34,0x63,0x00,0x20,0x24,0x42,0x04,0x18,0x3c,0x05,0xb0,0x03,0xac,0x62,0x00,0x00, +0x34,0xa5,0x00,0x70,0x8c,0xa2,0x00,0x00,0x90,0x84,0x00,0x08,0x3c,0x06,0xb0,0x03, +0x00,0x02,0x16,0x00,0x2c,0x83,0x00,0x03,0x34,0xc6,0x00,0x72,0x24,0x07,0x00,0x01, +0x10,0x60,0x00,0x11,0x00,0x02,0x2f,0xc2,0x90,0xc2,0x00,0x00,0x00,0x00,0x18,0x21, +0x00,0x02,0x16,0x00,0x10,0xa7,0x00,0x09,0x00,0x02,0x16,0x03,0x14,0x80,0x00,0x0c, +0x30,0x43,0x00,0x03,0x83,0x82,0x8b,0x88,0x00,0x00,0x00,0x00,0x00,0x02,0x10,0x80, +0x00,0x43,0x10,0x21,0x00,0x02,0x16,0x00,0x00,0x02,0x1e,0x03,0x3c,0x02,0xb0,0x03, +0x34,0x42,0x00,0x72,0xa0,0x43,0x00,0x00,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00, +0x30,0x45,0x00,0x05,0x10,0x87,0x00,0x04,0x30,0x43,0x00,0x06,0x93,0x82,0x8b,0xa0, +0x08,0x00,0x01,0x21,0x00,0x43,0x10,0x21,0x83,0x82,0x8b,0x94,0x00,0x00,0x00,0x00, +0x00,0x02,0x10,0x40,0x08,0x00,0x01,0x21,0x00,0x45,0x10,0x21,0x10,0x80,0x00,0x05, +0x00,0x00,0x18,0x21,0x24,0x63,0x00,0x01,0x00,0x64,0x10,0x2b,0x14,0x40,0xff,0xfd, +0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03, +0x3c,0x02,0x80,0x00,0x24,0x42,0x04,0xec,0x3c,0x04,0xb0,0x02,0x34,0x63,0x00,0x20, +0xac,0x62,0x00,0x00,0x34,0x84,0x00,0x08,0x24,0x02,0x00,0x01,0xaf,0x84,0x8b,0xb0, +0xa3,0x82,0x8b,0xc0,0xa7,0x80,0x8b,0xb4,0xa7,0x80,0x8b,0xb6,0xaf,0x80,0x8b,0xb8, +0xaf,0x80,0x8b,0xbc,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03, +0x3c,0x02,0x80,0x00,0x34,0x63,0x00,0x20,0x24,0x42,0x05,0x2c,0x3c,0x04,0xb0,0x03, +0xac,0x62,0x00,0x00,0x34,0x84,0x00,0xac,0x80,0xa2,0x00,0x15,0x8c,0x83,0x00,0x00, +0x27,0xbd,0xff,0xf0,0x00,0x43,0x10,0x21,0xac,0x82,0x00,0x00,0x03,0xe0,0x00,0x08, +0x27,0xbd,0x00,0x10,0x3c,0x02,0xb0,0x03,0x3c,0x03,0x80,0x00,0x34,0x42,0x00,0x20, +0x24,0x63,0x05,0x64,0x27,0xbd,0xff,0xe0,0xac,0x43,0x00,0x00,0xaf,0xb1,0x00,0x14, +0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x18,0x8f,0x90,0x8b,0xb0,0x0c,0x00,0x02,0x9a, +0x00,0x80,0x88,0x21,0x14,0x40,0x00,0x2a,0x3c,0x02,0x00,0x80,0x16,0x20,0x00,0x02, +0x34,0x42,0x02,0x01,0x24,0x02,0x02,0x01,0xae,0x02,0x00,0x00,0x97,0x84,0x8b,0xb4, +0x97,0x82,0x8b,0xb6,0x3c,0x03,0xb0,0x02,0x00,0x83,0x20,0x21,0x24,0x42,0x00,0x04, +0xa7,0x82,0x8b,0xb6,0xa4,0x82,0x00,0x00,0x8f,0x84,0x8b,0xb8,0x8f,0x82,0x8b,0xb0, +0x93,0x85,0x8b,0x62,0x24,0x84,0x00,0x01,0x24,0x42,0x00,0x04,0x24,0x03,0x8f,0xff, +0x3c,0x07,0xb0,0x06,0x3c,0x06,0xb0,0x03,0x00,0x43,0x10,0x24,0x00,0x85,0x28,0x2a, +0x34,0xe7,0x80,0x18,0xaf,0x82,0x8b,0xb0,0xaf,0x84,0x8b,0xb8,0x10,0xa0,0x00,0x08, +0x34,0xc6,0x01,0x08,0x8f,0x83,0x8b,0xbc,0x8f,0x84,0x8b,0x7c,0x8c,0xc2,0x00,0x00, +0x00,0x64,0x18,0x21,0x00,0x43,0x10,0x2b,0x14,0x40,0x00,0x09,0x00,0x00,0x00,0x00, +0x8c,0xe2,0x00,0x00,0x3c,0x03,0x0f,0x00,0x3c,0x04,0x04,0x00,0x00,0x43,0x10,0x24, +0x10,0x44,0x00,0x03,0x00,0x00,0x00,0x00,0x0c,0x00,0x04,0x98,0x00,0x00,0x00,0x00, +0x8f,0xbf,0x00,0x18,0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20, +0x27,0xbd,0xff,0xd8,0x3c,0x02,0xb0,0x03,0x3c,0x03,0x80,0x00,0x24,0x63,0x06,0x50, +0xaf,0xb0,0x00,0x10,0x34,0x42,0x00,0x20,0x8f,0x90,0x8b,0xb0,0xac,0x43,0x00,0x00, +0xaf,0xb3,0x00,0x1c,0xaf,0xb2,0x00,0x18,0xaf,0xb1,0x00,0x14,0xaf,0xbf,0x00,0x20, +0x00,0x80,0x88,0x21,0x00,0xa0,0x90,0x21,0x0c,0x00,0x02,0x9a,0x00,0xc0,0x98,0x21, +0x24,0x07,0x8f,0xff,0x14,0x40,0x00,0x19,0x26,0x03,0x00,0x04,0x24,0x02,0x0e,0x03, +0xae,0x02,0x00,0x00,0x00,0x67,0x80,0x24,0x26,0x02,0x00,0x04,0xae,0x11,0x00,0x00, +0x00,0x47,0x80,0x24,0x97,0x86,0x8b,0xb4,0x26,0x03,0x00,0x04,0xae,0x12,0x00,0x00, +0x00,0x67,0x80,0x24,0xae,0x13,0x00,0x00,0x8f,0x84,0x8b,0xb0,0x3c,0x02,0xb0,0x02, +0x97,0x85,0x8b,0xb6,0x00,0xc2,0x30,0x21,0x8f,0x82,0x8b,0xb8,0x24,0x84,0x00,0x10, +0x24,0xa5,0x00,0x10,0x00,0x87,0x20,0x24,0x24,0x42,0x00,0x01,0xa7,0x85,0x8b,0xb6, +0xaf,0x84,0x8b,0xb0,0xaf,0x82,0x8b,0xb8,0xa4,0xc5,0x00,0x00,0x8f,0xbf,0x00,0x20, +0x7b,0xb2,0x00,0xfc,0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x28, +0x27,0xbd,0xff,0xe8,0xaf,0xbf,0x00,0x10,0x94,0x82,0x00,0x04,0x00,0x00,0x00,0x00, +0x30,0x42,0xe0,0x00,0x14,0x40,0x00,0x14,0x00,0x00,0x00,0x00,0x90,0x82,0x00,0x02, +0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xfc,0x00,0x82,0x28,0x21,0x8c,0xa4,0x00,0x00, +0x3c,0x02,0x00,0x70,0x8c,0xa6,0x00,0x08,0x00,0x82,0x10,0x21,0x2c,0x43,0x00,0x06, +0x10,0x60,0x00,0x09,0x3c,0x03,0x80,0x01,0x00,0x02,0x10,0x80,0x24,0x63,0x01,0xe8, +0x00,0x43,0x10,0x21,0x8c,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x08, +0x00,0x00,0x00,0x00,0xaf,0x86,0x80,0x14,0x8f,0xbf,0x00,0x10,0x00,0x00,0x00,0x00, +0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18,0x8c,0xa4,0x00,0x00,0x0c,0x00,0x17,0xb3, +0x00,0x00,0x00,0x00,0x08,0x00,0x01,0xde,0x00,0x00,0x00,0x00,0x0c,0x00,0x24,0xaa, +0x00,0xc0,0x20,0x21,0x08,0x00,0x01,0xde,0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x03, +0x34,0x42,0x01,0x08,0x8c,0x44,0x00,0x00,0x8f,0x82,0x80,0x18,0x3c,0x03,0x00,0x0f, +0x34,0x63,0x42,0x40,0x00,0x43,0x10,0x21,0x00,0x82,0x20,0x2b,0x10,0x80,0x00,0x09, +0x24,0x03,0x00,0x05,0x8f,0x82,0x83,0x30,0x00,0x00,0x00,0x00,0x24,0x42,0x00,0x01, +0xaf,0x82,0x83,0x30,0x10,0x43,0x00,0x03,0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08, +0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03,0x8c,0x63,0x01,0x08,0x24,0x02,0x00,0x01, +0xa3,0x82,0x80,0x11,0xaf,0x80,0x83,0x30,0xaf,0x83,0x80,0x18,0x08,0x00,0x01,0xfb, +0x00,0x00,0x00,0x00,0x30,0x84,0x00,0xff,0x14,0x80,0x00,0x2f,0x00,0x00,0x00,0x00, +0x8f,0x82,0x80,0x14,0xa3,0x85,0x83,0x63,0x10,0x40,0x00,0x2b,0x2c,0xa2,0x00,0x04, +0x14,0x40,0x00,0x06,0x00,0x05,0x10,0x40,0x24,0xa2,0xff,0xfc,0x2c,0x42,0x00,0x08, +0x10,0x40,0x00,0x09,0x24,0xa2,0xff,0xf0,0x00,0x05,0x10,0x40,0x27,0x84,0x83,0x6c, +0x00,0x44,0x10,0x21,0x94,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x24,0x63,0x00,0x01, +0x03,0xe0,0x00,0x08,0xa4,0x43,0x00,0x00,0x2c,0x42,0x00,0x10,0x14,0x40,0x00,0x0a, +0x00,0x05,0x10,0x40,0x24,0xa2,0xff,0xe0,0x2c,0x42,0x00,0x10,0x14,0x40,0x00,0x06, +0x00,0x05,0x10,0x40,0x24,0xa2,0xff,0xd0,0x2c,0x42,0x00,0x10,0x10,0x40,0x00,0x09, +0x24,0xa2,0xff,0xc0,0x00,0x05,0x10,0x40,0x27,0x84,0x83,0x6c,0x00,0x44,0x10,0x21, +0x94,0x43,0xff,0xf8,0x00,0x00,0x00,0x00,0x24,0x63,0x00,0x01,0x03,0xe0,0x00,0x08, +0xa4,0x43,0xff,0xf8,0x2c,0x42,0x00,0x10,0x10,0x40,0x00,0x07,0x00,0x05,0x10,0x40, +0x27,0x84,0x83,0x6c,0x00,0x44,0x10,0x21,0x94,0x43,0xff,0xf8,0x00,0x00,0x00,0x00, +0x24,0x63,0x00,0x01,0xa4,0x43,0xff,0xf8,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00, +0x8f,0x86,0x8b,0xb0,0x8f,0x82,0x80,0x14,0x27,0xbd,0xff,0xe8,0xaf,0xbf,0x00,0x10, +0x10,0x40,0x00,0x2a,0x00,0xc0,0x38,0x21,0x24,0x02,0x00,0x07,0x24,0x03,0xff,0x9c, +0xa3,0x82,0x83,0x6b,0xa3,0x83,0x83,0x6a,0x27,0x8a,0x83,0x68,0x00,0x00,0x20,0x21, +0x24,0x09,0x8f,0xff,0x00,0x04,0x10,0x80,0x00,0x4a,0x28,0x21,0x8c,0xa2,0x00,0x00, +0x24,0xe3,0x00,0x04,0x24,0x88,0x00,0x01,0xac,0xe2,0x00,0x00,0x10,0x80,0x00,0x02, +0x00,0x69,0x38,0x24,0xac,0xa0,0x00,0x00,0x31,0x04,0x00,0xff,0x2c,0x82,0x00,0x27, +0x14,0x40,0xff,0xf5,0x00,0x04,0x10,0x80,0x97,0x83,0x8b,0xb6,0x97,0x85,0x8b,0xb4, +0x3c,0x02,0xb0,0x02,0x24,0x63,0x00,0x9c,0x00,0xa2,0x28,0x21,0x3c,0x04,0xb0,0x06, +0xa7,0x83,0x8b,0xb6,0x34,0x84,0x80,0x18,0xa4,0xa3,0x00,0x00,0x8c,0x85,0x00,0x00, +0x24,0x02,0x8f,0xff,0x24,0xc6,0x00,0x9c,0x3c,0x03,0x0f,0x00,0x00,0xc2,0x30,0x24, +0x00,0xa3,0x28,0x24,0x3c,0x02,0x04,0x00,0xaf,0x86,0x8b,0xb0,0x10,0xa2,0x00,0x03, +0x00,0x00,0x00,0x00,0x0c,0x00,0x04,0x98,0x00,0x00,0x00,0x00,0x8f,0xbf,0x00,0x10, +0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18,0x8f,0x86,0x8b,0xb0, +0x27,0xbd,0xff,0xc8,0x24,0x02,0x00,0x08,0x24,0x03,0x00,0x20,0xaf,0xbf,0x00,0x30, +0xa3,0xa2,0x00,0x13,0xa3,0xa3,0x00,0x12,0xa7,0xa4,0x00,0x10,0x00,0xc0,0x28,0x21, +0x27,0xa9,0x00,0x10,0x00,0x00,0x38,0x21,0x24,0x08,0x8f,0xff,0x00,0x07,0x10,0x80, +0x00,0x49,0x10,0x21,0x8c,0x44,0x00,0x00,0x24,0xe3,0x00,0x01,0x30,0x67,0x00,0xff, +0x24,0xa2,0x00,0x04,0x2c,0xe3,0x00,0x08,0xac,0xa4,0x00,0x00,0x14,0x60,0xff,0xf7, +0x00,0x48,0x28,0x24,0x97,0x83,0x8b,0xb6,0x97,0x85,0x8b,0xb4,0x3c,0x02,0xb0,0x02, +0x24,0x63,0x00,0x20,0x00,0xa2,0x28,0x21,0x3c,0x04,0xb0,0x06,0xa7,0x83,0x8b,0xb6, +0x34,0x84,0x80,0x18,0xa4,0xa3,0x00,0x00,0x8c,0x85,0x00,0x00,0x24,0x02,0x8f,0xff, +0x24,0xc6,0x00,0x20,0x3c,0x03,0x0f,0x00,0x00,0xc2,0x30,0x24,0x00,0xa3,0x28,0x24, +0x3c,0x02,0x04,0x00,0xaf,0x86,0x8b,0xb0,0x10,0xa2,0x00,0x03,0x00,0x00,0x00,0x00, +0x0c,0x00,0x04,0x98,0x00,0x00,0x00,0x00,0x8f,0xbf,0x00,0x30,0x00,0x00,0x00,0x00, +0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x38,0x93,0x82,0x8b,0xc0,0x00,0x00,0x00,0x00, +0x10,0x40,0x00,0x11,0x24,0x06,0x00,0x01,0x8f,0x82,0x8b,0xb8,0x3c,0x05,0xb0,0x06, +0x3c,0x04,0xb0,0x03,0x34,0xa5,0x80,0x18,0x34,0x84,0x01,0x08,0x14,0x40,0x00,0x09, +0x00,0x00,0x30,0x21,0x97,0x82,0x8b,0xb4,0x8c,0x84,0x00,0x00,0x3c,0x03,0xb0,0x02, +0x00,0x43,0x10,0x21,0xaf,0x84,0x8b,0xbc,0xa7,0x80,0x8b,0xb6,0xac,0x40,0x00,0x00, +0xac,0x40,0x00,0x04,0x8c,0xa2,0x00,0x00,0x03,0xe0,0x00,0x08,0x00,0xc0,0x10,0x21, +0x8f,0x86,0x8b,0xb0,0x8f,0x82,0x8b,0xb8,0x27,0xbd,0xff,0xe8,0xaf,0xbf,0x00,0x10, +0x00,0xc0,0x40,0x21,0x14,0x40,0x00,0x0a,0x00,0x40,0x50,0x21,0x00,0x00,0x38,0x21, +0x27,0x89,0x83,0x38,0x24,0xe2,0x00,0x01,0x00,0x07,0x18,0x80,0x30,0x47,0x00,0xff, +0x00,0x69,0x18,0x21,0x2c,0xe2,0x00,0x0a,0x14,0x40,0xff,0xfa,0xac,0x60,0x00,0x00, +0x3c,0x02,0x00,0x80,0x10,0x82,0x00,0x6f,0x00,0x00,0x00,0x00,0x97,0x82,0x83,0x3e, +0x00,0x00,0x00,0x00,0x24,0x42,0x00,0x01,0xa7,0x82,0x83,0x3e,0x90,0xa3,0x00,0x15, +0x97,0x82,0x83,0x40,0x00,0x03,0x1e,0x00,0x00,0x03,0x1e,0x03,0x00,0x43,0x10,0x21, +0xa7,0x82,0x83,0x40,0x8c,0xa4,0x00,0x20,0x3c,0x02,0x00,0x60,0x3c,0x03,0x00,0x20, +0x00,0x82,0x20,0x24,0x10,0x83,0x00,0x54,0x00,0x00,0x00,0x00,0x14,0x80,0x00,0x47, +0x00,0x00,0x00,0x00,0x97,0x82,0x83,0x44,0x00,0x00,0x00,0x00,0x24,0x42,0x00,0x01, +0xa7,0x82,0x83,0x44,0x84,0xa3,0x00,0x06,0x8f,0x82,0x83,0x54,0x00,0x00,0x00,0x00, +0x00,0x43,0x10,0x21,0xaf,0x82,0x83,0x54,0x25,0x42,0x00,0x01,0x28,0x43,0x27,0x10, +0xaf,0x82,0x8b,0xb8,0x10,0x60,0x00,0x09,0x24,0x02,0x00,0x04,0x93,0x83,0x80,0x11, +0x24,0x02,0x00,0x01,0x10,0x62,0x00,0x05,0x24,0x02,0x00,0x04,0x8f,0xbf,0x00,0x10, +0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18,0x24,0x03,0x00,0x28, +0xa3,0x83,0x83,0x3a,0xa3,0x82,0x83,0x3b,0x90,0xa2,0x00,0x18,0x93,0x83,0x83,0x63, +0x00,0x00,0x38,0x21,0x00,0x02,0x16,0x00,0x00,0x02,0x16,0x03,0xa7,0x82,0x83,0x4e, +0xa3,0x83,0x83,0x5c,0x27,0x89,0x83,0x38,0x24,0x05,0x8f,0xff,0x00,0x07,0x10,0x80, +0x00,0x49,0x10,0x21,0x8c,0x44,0x00,0x00,0x24,0xe3,0x00,0x01,0x30,0x67,0x00,0xff, +0x25,0x02,0x00,0x04,0x2c,0xe3,0x00,0x0a,0xad,0x04,0x00,0x00,0x14,0x60,0xff,0xf7, +0x00,0x45,0x40,0x24,0x97,0x83,0x8b,0xb6,0x97,0x85,0x8b,0xb4,0x3c,0x02,0xb0,0x02, +0x24,0x63,0x00,0x28,0x00,0xa2,0x28,0x21,0x3c,0x04,0xb0,0x06,0xa7,0x83,0x8b,0xb6, +0x34,0x84,0x80,0x18,0xa4,0xa3,0x00,0x00,0x8c,0x85,0x00,0x00,0x24,0x02,0x8f,0xff, +0x24,0xc6,0x00,0x28,0x3c,0x03,0x0f,0x00,0x00,0xc2,0x30,0x24,0x00,0xa3,0x28,0x24, +0x3c,0x02,0x04,0x00,0xaf,0x86,0x8b,0xb0,0x10,0xa2,0x00,0x03,0x00,0x00,0x00,0x00, +0x0c,0x00,0x04,0x98,0x00,0x00,0x00,0x00,0x0c,0x00,0x02,0x38,0x00,0x00,0x00,0x00, +0xa3,0x80,0x80,0x11,0x08,0x00,0x02,0xe7,0x00,0x00,0x00,0x00,0x97,0x82,0x83,0x46, +0x00,0x00,0x00,0x00,0x24,0x42,0x00,0x01,0xa7,0x82,0x83,0x46,0x84,0xa3,0x00,0x06, +0x8f,0x82,0x83,0x58,0x00,0x00,0x00,0x00,0x00,0x43,0x10,0x21,0xaf,0x82,0x83,0x58, +0x08,0x00,0x02,0xdf,0x25,0x42,0x00,0x01,0x97,0x82,0x83,0x42,0x00,0x00,0x00,0x00, +0x24,0x42,0x00,0x01,0xa7,0x82,0x83,0x42,0x84,0xa3,0x00,0x06,0x8f,0x82,0x83,0x50, +0x00,0x00,0x00,0x00,0x00,0x43,0x10,0x21,0xaf,0x82,0x83,0x50,0x08,0x00,0x02,0xdf, +0x25,0x42,0x00,0x01,0x97,0x82,0x83,0x3c,0x00,0x00,0x00,0x00,0x24,0x42,0x00,0x01, +0xa7,0x82,0x83,0x3c,0x08,0x00,0x02,0xc7,0x00,0x00,0x00,0x00,0x27,0xbd,0xff,0xd0, +0xaf,0xbf,0x00,0x28,0x8c,0xa3,0x00,0x20,0x8f,0x8a,0x8b,0xb0,0x3c,0x02,0x00,0x10, +0x00,0x62,0x10,0x24,0x00,0xa0,0x38,0x21,0x01,0x40,0x48,0x21,0x10,0x40,0x00,0x3d, +0x00,0x80,0x28,0x21,0x8c,0xe4,0x00,0x1c,0x34,0xa5,0x12,0x06,0xaf,0xa5,0x00,0x10, +0x8c,0x82,0x00,0x08,0x00,0x03,0x1c,0x42,0x30,0x63,0x00,0x30,0x00,0x02,0x13,0x02, +0x30,0x42,0x00,0x40,0x00,0x43,0x10,0x25,0x90,0xe6,0x00,0x10,0x90,0xe4,0x00,0x13, +0x94,0xe8,0x00,0x0c,0x94,0xe3,0x00,0x1a,0x00,0x02,0x16,0x00,0x90,0xe7,0x00,0x12, +0x00,0xa2,0x28,0x25,0x24,0x02,0x12,0x34,0xa7,0xa2,0x00,0x1c,0x24,0x02,0x56,0x78, +0xaf,0xa5,0x00,0x10,0xa3,0xa6,0x00,0x18,0xa3,0xa7,0x00,0x1f,0xa7,0xa3,0x00,0x1a, +0xa3,0xa4,0x00,0x19,0xa7,0xa8,0x00,0x20,0xa7,0xa2,0x00,0x22,0x00,0x00,0x28,0x21, +0x27,0xa7,0x00,0x10,0x24,0x06,0x8f,0xff,0x00,0x05,0x10,0x80,0x00,0x47,0x10,0x21, +0x8c,0x44,0x00,0x00,0x24,0xa3,0x00,0x01,0x30,0x65,0x00,0xff,0x25,0x22,0x00,0x04, +0x2c,0xa3,0x00,0x05,0xad,0x24,0x00,0x00,0x14,0x60,0xff,0xf7,0x00,0x46,0x48,0x24, +0x97,0x83,0x8b,0xb6,0x97,0x85,0x8b,0xb4,0x3c,0x02,0xb0,0x02,0x24,0x63,0x00,0x14, +0x00,0xa2,0x28,0x21,0x3c,0x04,0xb0,0x06,0xa7,0x83,0x8b,0xb6,0x34,0x84,0x80,0x18, +0xa4,0xa3,0x00,0x00,0x8c,0x85,0x00,0x00,0x24,0x02,0x8f,0xff,0x25,0x46,0x00,0x14, +0x3c,0x03,0x0f,0x00,0x00,0xc2,0x50,0x24,0x00,0xa3,0x28,0x24,0x3c,0x02,0x04,0x00, +0xaf,0x8a,0x8b,0xb0,0x10,0xa2,0x00,0x03,0x00,0x00,0x00,0x00,0x0c,0x00,0x04,0x98, +0x00,0x00,0x00,0x00,0x8f,0xbf,0x00,0x28,0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08, +0x27,0xbd,0x00,0x30,0x3c,0x05,0xb0,0x03,0x3c,0x02,0x80,0x00,0x27,0xbd,0xff,0xc8, +0x00,0x04,0x22,0x00,0x34,0xa5,0x00,0x20,0x24,0x42,0x0e,0x04,0x3c,0x03,0xb0,0x00, +0xaf,0xb5,0x00,0x24,0xaf,0xb4,0x00,0x20,0xaf,0xb2,0x00,0x18,0xaf,0xb0,0x00,0x10, +0xaf,0xbf,0x00,0x30,0x00,0x83,0x80,0x21,0xaf,0xb7,0x00,0x2c,0xaf,0xb6,0x00,0x28, +0xaf,0xb3,0x00,0x1c,0xaf,0xb1,0x00,0x14,0xac,0xa2,0x00,0x00,0x8e,0x09,0x00,0x00, +0x00,0x00,0x90,0x21,0x26,0x10,0x00,0x08,0x00,0x09,0xa6,0x02,0x12,0x80,0x00,0x13, +0x00,0x00,0xa8,0x21,0x24,0x13,0x00,0x02,0x3c,0x16,0x00,0xff,0x3c,0x17,0xff,0x00, +0x8e,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x09,0x12,0x02,0x24,0x42,0x00,0x02, +0x31,0x25,0x00,0xff,0x10,0xb3,0x00,0x76,0x30,0x51,0x00,0xff,0x24,0x02,0x00,0x03, +0x10,0xa2,0x00,0x18,0x00,0x00,0x00,0x00,0x02,0x51,0x10,0x21,0x30,0x52,0xff,0xff, +0x02,0x54,0x18,0x2b,0x14,0x60,0xff,0xf2,0x02,0x11,0x80,0x21,0x12,0xa0,0x00,0x0a, +0x3c,0x02,0xb0,0x06,0x34,0x42,0x80,0x18,0x8c,0x43,0x00,0x00,0x3c,0x04,0x0f,0x00, +0x3c,0x02,0x04,0x00,0x00,0x64,0x18,0x24,0x10,0x62,0x00,0x03,0x00,0x00,0x00,0x00, +0x0c,0x00,0x04,0x98,0x00,0x00,0x00,0x00,0x8f,0xbf,0x00,0x30,0x7b,0xb6,0x01,0x7c, +0x7b,0xb4,0x01,0x3c,0x7b,0xb2,0x00,0xfc,0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08, +0x27,0xbd,0x00,0x38,0x8e,0x09,0x00,0x04,0x24,0x15,0x00,0x01,0x8e,0x06,0x00,0x0c, +0x00,0x09,0x11,0x42,0x00,0x09,0x18,0xc2,0x30,0x48,0x00,0x03,0x00,0x09,0x14,0x02, +0x30,0x6c,0x00,0x03,0x00,0x09,0x26,0x02,0x11,0x15,0x00,0x45,0x30,0x43,0x00,0x0f, +0x29,0x02,0x00,0x02,0x14,0x40,0x00,0x26,0x00,0x00,0x00,0x00,0x11,0x13,0x00,0x0f, +0x00,0x00,0x38,0x21,0x00,0x07,0x22,0x02,0x30,0x84,0xff,0x00,0x3c,0x03,0x00,0xff, +0x00,0x07,0x2e,0x02,0x00,0x07,0x12,0x00,0x00,0x43,0x10,0x24,0x00,0xa4,0x28,0x25, +0x00,0xa2,0x28,0x25,0x00,0x07,0x1e,0x00,0x00,0xa3,0x28,0x25,0x0c,0x00,0x01,0x94, +0x01,0x20,0x20,0x21,0x08,0x00,0x03,0xa7,0x02,0x51,0x10,0x21,0x11,0x95,0x00,0x0f, +0x00,0x00,0x00,0x00,0x11,0x88,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x80, +0x27,0x83,0x8b,0x60,0x00,0x43,0x10,0x21,0x8c,0x47,0x00,0x18,0x08,0x00,0x03,0xce, +0x00,0x07,0x22,0x02,0x00,0x04,0x10,0x40,0x27,0x83,0x8b,0x68,0x00,0x43,0x10,0x21, +0x94,0x47,0x00,0x02,0x08,0x00,0x03,0xce,0x00,0x07,0x22,0x02,0x27,0x82,0x8b,0x60, +0x00,0x82,0x10,0x21,0x90,0x47,0x00,0x00,0x08,0x00,0x03,0xce,0x00,0x07,0x22,0x02, +0x15,0x00,0xff,0xdc,0x00,0x00,0x38,0x21,0x10,0x75,0x00,0x05,0x00,0x80,0x38,0x21, +0x00,0x65,0x18,0x26,0x24,0x82,0x01,0x00,0x00,0x00,0x38,0x21,0x00,0x43,0x38,0x0a, +0x24,0x02,0x00,0x01,0x11,0x82,0x00,0x0e,0x3c,0x02,0xb0,0x03,0x24,0x02,0x00,0x02, +0x11,0x82,0x00,0x06,0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x03,0x00,0xe2,0x10,0x21, +0x8c,0x47,0x00,0x00,0x08,0x00,0x03,0xce,0x00,0x07,0x22,0x02,0x3c,0x02,0xb0,0x03, +0x00,0xe2,0x10,0x21,0x94,0x43,0x00,0x00,0x08,0x00,0x03,0xcd,0x30,0x67,0xff,0xff, +0x00,0xe2,0x10,0x21,0x90,0x43,0x00,0x00,0x08,0x00,0x03,0xcd,0x30,0x67,0x00,0xff, +0x30,0x62,0x00,0x03,0x00,0x02,0x12,0x00,0x11,0x95,0x00,0x07,0x00,0x44,0x38,0x21, +0x11,0x93,0x00,0x03,0x00,0x00,0x00,0x00,0x08,0x00,0x03,0xff,0x3c,0x02,0xb0,0x0a, +0x08,0x00,0x04,0x04,0x3c,0x02,0xb0,0x0a,0x08,0x00,0x04,0x08,0x3c,0x02,0xb0,0x0a, +0x8e,0x09,0x00,0x04,0x8e,0x02,0x00,0x08,0x8e,0x03,0x00,0x0c,0x00,0x09,0x41,0x42, +0x00,0x02,0x22,0x02,0x00,0x03,0x3a,0x02,0x30,0x84,0xff,0x00,0x30,0xe7,0xff,0x00, +0x00,0x02,0x5e,0x02,0x00,0x02,0x32,0x00,0x00,0x03,0x56,0x02,0x00,0x03,0x2a,0x00, +0x01,0x64,0x58,0x25,0x00,0xd6,0x30,0x24,0x01,0x47,0x50,0x25,0x00,0x02,0x16,0x00, +0x00,0xb6,0x28,0x24,0x00,0x03,0x1e,0x00,0x01,0x66,0x58,0x25,0x01,0x45,0x50,0x25, +0x00,0x57,0x10,0x24,0x00,0x77,0x18,0x24,0x01,0x62,0x38,0x25,0x01,0x43,0x30,0x25, +0x00,0x09,0x10,0xc2,0x00,0x09,0x1c,0x02,0x31,0x08,0x00,0x03,0x30,0x4c,0x00,0x03, +0x30,0x63,0x00,0x0f,0x00,0x09,0x26,0x02,0x00,0xe0,0x58,0x21,0x15,0x00,0x00,0x28, +0x00,0xc0,0x50,0x21,0x24,0x02,0x00,0x01,0x10,0x62,0x00,0x06,0x00,0x80,0x28,0x21, +0x24,0x02,0x00,0x03,0x14,0x62,0xff,0x69,0x02,0x51,0x10,0x21,0x24,0x85,0x01,0x00, +0x24,0x02,0x00,0x01,0x11,0x82,0x00,0x15,0x24,0x02,0x00,0x02,0x11,0x82,0x00,0x0a, +0x3c,0x03,0xb0,0x03,0x00,0xa3,0x18,0x21,0x8c,0x62,0x00,0x00,0x00,0x0a,0x20,0x27, +0x01,0x6a,0x28,0x24,0x00,0x44,0x10,0x24,0x00,0x45,0x10,0x25,0xac,0x62,0x00,0x00, +0x08,0x00,0x03,0xa7,0x02,0x51,0x10,0x21,0x00,0xa3,0x18,0x21,0x94,0x62,0x00,0x00, +0x00,0x0a,0x20,0x27,0x01,0x6a,0x28,0x24,0x00,0x44,0x10,0x24,0x00,0x45,0x10,0x25, +0xa4,0x62,0x00,0x00,0x08,0x00,0x03,0xa7,0x02,0x51,0x10,0x21,0x3c,0x03,0xb0,0x03, +0x00,0xa3,0x18,0x21,0x90,0x62,0x00,0x00,0x00,0x0a,0x20,0x27,0x01,0x6a,0x28,0x24, +0x00,0x44,0x10,0x24,0x00,0x45,0x10,0x25,0x08,0x00,0x03,0xa6,0xa0,0x62,0x00,0x00, +0x24,0x02,0x00,0x01,0x11,0x02,0x00,0x21,0x00,0x00,0x00,0x00,0x15,0x13,0xff,0x42, +0x00,0x00,0x00,0x00,0x11,0x82,0x00,0x17,0x00,0x00,0x00,0x00,0x11,0x88,0x00,0x0b, +0x00,0x00,0x00,0x00,0x27,0x83,0x8b,0x60,0x00,0x04,0x20,0x80,0x00,0x83,0x20,0x21, +0x8c,0x82,0x00,0x18,0x00,0x06,0x18,0x27,0x00,0xe6,0x28,0x24,0x00,0x43,0x10,0x24, +0x00,0x45,0x10,0x25,0x08,0x00,0x03,0xa6,0xac,0x82,0x00,0x18,0x27,0x83,0x8b,0x68, +0x00,0x04,0x20,0x40,0x00,0x83,0x20,0x21,0x94,0x82,0x00,0x02,0x00,0x06,0x18,0x27, +0x00,0xe6,0x28,0x24,0x00,0x43,0x10,0x24,0x00,0x45,0x10,0x25,0x08,0x00,0x03,0xa6, +0xa4,0x82,0x00,0x02,0x27,0x83,0x8b,0x60,0x00,0x83,0x18,0x21,0x90,0x62,0x00,0x00, +0x00,0x06,0x20,0x27,0x08,0x00,0x04,0x5c,0x00,0xe6,0x28,0x24,0x30,0x62,0x00,0x07, +0x00,0x02,0x12,0x00,0x11,0x88,0x00,0x0f,0x00,0x44,0x10,0x21,0x11,0x93,0x00,0x07, +0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x0a,0x00,0x43,0x18,0x21,0x8c,0x62,0x00,0x00, +0x00,0x06,0x20,0x27,0x08,0x00,0x04,0x49,0x00,0xe6,0x28,0x24,0x3c,0x03,0xb0,0x0a, +0x00,0x43,0x18,0x21,0x94,0x62,0x00,0x00,0x00,0x06,0x20,0x27,0x08,0x00,0x04,0x52, +0x00,0xe6,0x28,0x24,0x3c,0x03,0xb0,0x0a,0x08,0x00,0x04,0x7f,0x00,0x43,0x18,0x21, +0x97,0x85,0x8b,0xb4,0x3c,0x07,0xb0,0x02,0x3c,0x04,0xb0,0x03,0x3c,0x02,0x80,0x00, +0x00,0xa7,0x28,0x21,0x34,0x84,0x00,0x20,0x24,0x42,0x12,0x60,0x24,0x03,0xff,0x80, +0xac,0x82,0x00,0x00,0xa0,0xa3,0x00,0x07,0x97,0x82,0x8b,0xb6,0x97,0x85,0x8b,0xb4, +0x3c,0x06,0xb0,0x06,0x30,0x42,0xff,0xf8,0x24,0x42,0x00,0x10,0x00,0xa2,0x10,0x21, +0x30,0x42,0x0f,0xff,0x24,0x44,0x00,0x08,0x30,0x84,0x0f,0xff,0x00,0x05,0x28,0xc2, +0x3c,0x03,0x00,0x40,0x00,0xa3,0x28,0x25,0x00,0x87,0x20,0x21,0x34,0xc6,0x80,0x18, +0xac,0xc5,0x00,0x00,0xaf,0x84,0x8b,0xb0,0xa7,0x82,0x8b,0xb4,0xa7,0x80,0x8b,0xb6, +0xaf,0x80,0x8b,0xb8,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x30,0xa5,0x00,0xff, +0x30,0x84,0x00,0xff,0x24,0x02,0x00,0x01,0x00,0xe0,0x48,0x21,0x30,0xc6,0x00,0xff, +0x8f,0xa7,0x00,0x10,0x10,0x82,0x00,0x07,0x00,0xa0,0x40,0x21,0x24,0x02,0x00,0x03, +0x10,0x82,0x00,0x03,0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00, +0x24,0xa8,0x01,0x00,0x3c,0x03,0xb0,0x03,0x24,0x02,0x00,0x01,0x00,0x07,0x20,0x27, +0x01,0x27,0x28,0x24,0x10,0xc2,0x00,0x14,0x01,0x03,0x18,0x21,0x24,0x02,0x00,0x02, +0x10,0xc2,0x00,0x09,0x00,0x07,0x50,0x27,0x3c,0x03,0xb0,0x03,0x01,0x03,0x18,0x21, +0x8c,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4a,0x10,0x24,0x00,0x45,0x10,0x25, +0x08,0x00,0x04,0xe3,0xac,0x62,0x00,0x00,0x3c,0x03,0xb0,0x03,0x01,0x03,0x18,0x21, +0x94,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4a,0x10,0x24,0x00,0x45,0x10,0x25, +0x03,0xe0,0x00,0x08,0xa4,0x62,0x00,0x00,0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x44,0x10,0x24,0x00,0x45,0x10,0x25,0xa0,0x62,0x00,0x00,0x03,0xe0,0x00,0x08, +0x00,0x00,0x00,0x00,0x30,0x84,0x00,0x07,0x00,0x04,0x22,0x00,0x30,0xa5,0x00,0xff, +0x00,0x85,0x28,0x21,0x3c,0x02,0xb0,0x0a,0x00,0xa2,0x40,0x21,0x30,0xc6,0x00,0xff, +0x24,0x02,0x00,0x01,0x8f,0xa4,0x00,0x10,0x10,0xc2,0x00,0x14,0x24,0x02,0x00,0x02, +0x00,0x04,0x50,0x27,0x10,0xc2,0x00,0x09,0x00,0xe4,0x48,0x24,0x3c,0x03,0xb0,0x0a, +0x00,0xa3,0x18,0x21,0x8c,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4a,0x10,0x24, +0x00,0x49,0x10,0x25,0x03,0xe0,0x00,0x08,0xac,0x62,0x00,0x00,0x3c,0x03,0xb0,0x0a, +0x00,0xa3,0x18,0x21,0x94,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4a,0x10,0x24, +0x00,0x49,0x10,0x25,0x03,0xe0,0x00,0x08,0xa4,0x62,0x00,0x00,0x91,0x02,0x00,0x00, +0x00,0x04,0x18,0x27,0x00,0xe4,0x20,0x24,0x00,0x43,0x10,0x24,0x00,0x44,0x10,0x25, +0x03,0xe0,0x00,0x08,0xa1,0x02,0x00,0x00,0x30,0xa9,0x00,0xff,0x27,0x83,0x8b,0x60, +0x30,0x85,0x00,0xff,0x24,0x02,0x00,0x01,0x00,0x07,0x50,0x27,0x00,0xc7,0x40,0x24, +0x11,0x22,0x00,0x17,0x00,0xa3,0x18,0x21,0x00,0x05,0x20,0x40,0x27,0x82,0x8b,0x60, +0x00,0x05,0x28,0x80,0x27,0x83,0x8b,0x68,0x00,0x83,0x50,0x21,0x00,0xa2,0x20,0x21, +0x24,0x02,0x00,0x02,0x00,0x07,0x40,0x27,0x11,0x22,0x00,0x07,0x00,0xc7,0x28,0x24, +0x8c,0x82,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x48,0x10,0x24,0x00,0x45,0x10,0x25, +0x03,0xe0,0x00,0x08,0xac,0x82,0x00,0x18,0x95,0x42,0x00,0x02,0x00,0x00,0x00,0x00, +0x00,0x48,0x10,0x24,0x00,0x45,0x10,0x25,0x03,0xe0,0x00,0x08,0xa5,0x42,0x00,0x02, +0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4a,0x10,0x24,0x00,0x48,0x10,0x25, +0x03,0xe0,0x00,0x08,0xa0,0x62,0x00,0x00,0x00,0x04,0x32,0x02,0x30,0xc6,0xff,0x00, +0x00,0x04,0x16,0x02,0x00,0x04,0x1a,0x00,0x3c,0x05,0x00,0xff,0x00,0x65,0x18,0x24, +0x00,0x46,0x10,0x25,0x00,0x43,0x10,0x25,0x00,0x04,0x26,0x00,0x03,0xe0,0x00,0x08, +0x00,0x44,0x10,0x25,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x27,0xbd,0xff,0xe8, +0x34,0x63,0x00,0x20,0x24,0x42,0x14,0xe4,0x3c,0x04,0xb0,0x03,0xaf,0xbf,0x00,0x14, +0xac,0x62,0x00,0x00,0xaf,0xb0,0x00,0x10,0x34,0x84,0x00,0x2c,0x8c,0x83,0x00,0x00, +0xa7,0x80,0xbb,0xf0,0x00,0x03,0x12,0x02,0x00,0x03,0x2d,0x02,0x30,0x42,0x0f,0xff, +0xa3,0x83,0xbb,0xf8,0xa7,0x85,0xbb,0xfc,0xa7,0x82,0xbb,0xfa,0xa7,0x80,0xbb,0xf2, +0xa7,0x80,0xbb,0xf4,0xa7,0x80,0xbb,0xf6,0x0c,0x00,0x06,0xce,0x24,0x04,0x05,0x00, +0x3c,0x05,0x08,0x00,0x00,0x45,0x28,0x25,0x24,0x04,0x05,0x00,0x0c,0x00,0x06,0xc1, +0x00,0x40,0x80,0x21,0x3c,0x02,0xf7,0xff,0x34,0x42,0xff,0xff,0x02,0x02,0x80,0x24, +0x02,0x00,0x28,0x21,0x0c,0x00,0x06,0xc1,0x24,0x04,0x05,0x00,0x3c,0x02,0xb0,0x03, +0x3c,0x03,0xb0,0x03,0x34,0x42,0x01,0x08,0x34,0x63,0x01,0x18,0x8c,0x45,0x00,0x00, +0x8c,0x64,0x00,0x00,0x3c,0x02,0x00,0x0f,0x3c,0x03,0x00,0x4c,0x30,0x84,0x02,0x00, +0x34,0x63,0x4b,0x40,0xaf,0x85,0xbc,0x00,0x10,0x80,0x00,0x06,0x34,0x42,0x42,0x40, +0xaf,0x83,0xbc,0x04,0x8f,0xbf,0x00,0x14,0x8f,0xb0,0x00,0x10,0x03,0xe0,0x00,0x08, +0x27,0xbd,0x00,0x18,0xaf,0x82,0xbc,0x04,0x08,0x00,0x05,0x69,0x00,0x00,0x00,0x00, +0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x27,0xbd,0xff,0xc8,0x34,0x63,0x00,0x20, +0x24,0x42,0x15,0xc0,0x30,0x84,0x00,0xff,0xaf,0xbf,0x00,0x30,0xaf,0xb7,0x00,0x2c, +0xaf,0xb6,0x00,0x28,0xaf,0xb5,0x00,0x24,0xaf,0xb4,0x00,0x20,0xaf,0xb3,0x00,0x1c, +0xaf,0xb2,0x00,0x18,0xaf,0xb1,0x00,0x14,0xaf,0xb0,0x00,0x10,0xac,0x62,0x00,0x00, +0x10,0x80,0x00,0x1c,0x24,0x02,0x00,0x02,0x10,0x82,0x00,0x08,0x00,0x00,0x00,0x00, +0x8f,0xbf,0x00,0x30,0x7b,0xb6,0x01,0x7c,0x7b,0xb4,0x01,0x3c,0x7b,0xb2,0x00,0xfc, +0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x38,0xa7,0x80,0xbb,0xf0, +0xa7,0x80,0xbb,0xf2,0xa7,0x80,0xbb,0xf4,0xa7,0x80,0xbb,0xf6,0x0c,0x00,0x06,0xce, +0x24,0x04,0x05,0x00,0x3c,0x05,0x08,0x00,0x00,0x45,0x28,0x25,0x24,0x04,0x05,0x00, +0x0c,0x00,0x06,0xc1,0x00,0x40,0x80,0x21,0x3c,0x05,0xf7,0xff,0x34,0xa5,0xff,0xff, +0x02,0x05,0x28,0x24,0x0c,0x00,0x06,0xc1,0x24,0x04,0x05,0x00,0x08,0x00,0x05,0x84, +0x00,0x00,0x00,0x00,0x0c,0x00,0x06,0xce,0x24,0x04,0x05,0xa0,0x24,0x04,0x05,0xa4, +0x0c,0x00,0x06,0xce,0x00,0x02,0xbc,0x02,0x24,0x04,0x05,0xa8,0x00,0x02,0xb4,0x02, +0x0c,0x00,0x06,0xce,0x30,0x55,0xff,0xff,0x00,0x40,0x80,0x21,0x97,0x84,0xbb,0xf0, +0x97,0x82,0xbb,0xf2,0x97,0x83,0xbb,0xf6,0x02,0xe4,0x20,0x23,0x02,0xa2,0x10,0x23, +0x00,0x82,0x20,0x21,0x97,0x82,0xbb,0xf4,0x32,0x14,0xff,0xff,0x02,0x83,0x18,0x23, +0x02,0xc2,0x10,0x23,0x00,0x82,0x20,0x21,0x93,0x82,0xbb,0xf8,0x00,0x83,0x20,0x21, +0x30,0x84,0xff,0xff,0x00,0x82,0x10,0x2b,0x14,0x40,0x00,0xaa,0x00,0x00,0x00,0x00, +0x97,0x82,0xbb,0xfc,0x00,0x00,0x00,0x00,0x00,0x44,0x10,0x2b,0x14,0x40,0x00,0x7f, +0x00,0x00,0x00,0x00,0x97,0x82,0xbb,0xfa,0x00,0x00,0x00,0x00,0x00,0x44,0x10,0x2b, +0x10,0x40,0x00,0x3a,0x00,0x00,0x00,0x00,0x0c,0x00,0x06,0xce,0x24,0x04,0x04,0x50, +0x30,0x51,0x00,0x7f,0x00,0x40,0x80,0x21,0x2e,0x22,0x00,0x32,0x10,0x40,0x00,0x13, +0x24,0x02,0x00,0x20,0x12,0x22,0x00,0x17,0x24,0x02,0xff,0x80,0x02,0x02,0x10,0x24, +0x26,0x31,0x00,0x01,0x00,0x51,0x80,0x25,0x02,0x00,0x28,0x21,0x0c,0x00,0x06,0xc1, +0x24,0x04,0x04,0x50,0x02,0x00,0x28,0x21,0x0c,0x00,0x06,0xc1,0x24,0x04,0x04,0x58, +0x02,0x00,0x28,0x21,0x0c,0x00,0x06,0xc1,0x24,0x04,0x04,0x60,0x02,0x00,0x28,0x21, +0x24,0x04,0x04,0x68,0x0c,0x00,0x06,0xc1,0x00,0x00,0x00,0x00,0xa7,0x97,0xbb,0xf0, +0xa7,0x95,0xbb,0xf2,0xa7,0x96,0xbb,0xf4,0xa7,0x94,0xbb,0xf6,0x08,0x00,0x05,0x84, +0x00,0x00,0x00,0x00,0x0c,0x00,0x06,0xce,0x24,0x04,0x02,0x08,0x3c,0x04,0x00,0xc0, +0x00,0x40,0x28,0x21,0x00,0x44,0x10,0x24,0x00,0x02,0x15,0x82,0x24,0x03,0x00,0x03, +0x10,0x43,0x00,0x07,0x00,0x00,0x00,0x00,0x3c,0x02,0xff,0x3f,0x34,0x42,0xff,0xff, +0x00,0xa2,0x10,0x24,0x00,0x44,0x28,0x25,0x0c,0x00,0x06,0xc1,0x24,0x04,0x02,0x08, +0x0c,0x00,0x06,0xce,0x24,0x04,0x02,0x2c,0x00,0x40,0x90,0x21,0x3c,0x02,0xff,0xff, +0x34,0x42,0x3f,0xff,0x02,0x42,0x90,0x24,0x02,0x40,0x28,0x21,0x0c,0x00,0x06,0xc1, +0x24,0x04,0x02,0x2c,0x08,0x00,0x05,0xcb,0x24,0x02,0xff,0x80,0x0c,0x00,0x06,0xce, +0x24,0x04,0x04,0x50,0x30,0x51,0x00,0x7f,0x24,0x02,0x00,0x20,0x16,0x22,0xff,0xdb, +0x00,0x00,0x00,0x00,0x0c,0x00,0x06,0xce,0x24,0x04,0x02,0x2c,0x34,0x52,0x40,0x00, +0x02,0x40,0x28,0x21,0x0c,0x00,0x06,0xc1,0x24,0x04,0x02,0x2c,0x0c,0x00,0x06,0xce, +0x24,0x04,0x02,0x58,0x24,0x04,0x02,0x5c,0x0c,0x00,0x06,0xce,0x00,0x02,0x9e,0x02, +0x30,0x43,0x00,0xff,0x00,0x13,0x12,0x00,0x00,0x43,0x10,0x25,0x2c,0x43,0x00,0x04, +0x14,0x60,0x00,0x1d,0x2c,0x42,0x00,0x11,0x10,0x40,0x00,0x0b,0x00,0x00,0x00,0x00, +0x3c,0x02,0xff,0xff,0x34,0x42,0x3f,0xff,0x02,0x42,0x90,0x24,0x02,0x40,0x28,0x21, +0x24,0x04,0x02,0x2c,0x0c,0x00,0x06,0xc1,0x36,0x52,0x80,0x00,0x02,0x40,0x28,0x21, +0x08,0x00,0x05,0xd9,0x24,0x04,0x02,0x2c,0x0c,0x00,0x06,0xce,0x24,0x04,0x02,0x08, +0x3c,0x04,0x00,0xc0,0x00,0x40,0x28,0x21,0x00,0x44,0x10,0x24,0x00,0x02,0x15,0x82, +0x24,0x03,0x00,0x02,0x14,0x43,0xff,0xee,0x3c,0x02,0xff,0x3f,0x34,0x42,0xff,0xff, +0x00,0xa2,0x10,0x24,0x00,0x44,0x28,0x25,0x0c,0x00,0x06,0xc1,0x24,0x04,0x02,0x08, +0x08,0x00,0x06,0x15,0x3c,0x02,0xff,0xff,0x0c,0x00,0x06,0xce,0x24,0x04,0x02,0x08, +0x00,0x40,0x28,0x21,0x00,0x02,0x15,0x82,0x30,0x42,0x00,0x03,0x24,0x03,0x00,0x03, +0x14,0x43,0xff,0xdf,0x3c,0x02,0xff,0x3f,0x34,0x42,0xff,0xff,0x00,0xa2,0x10,0x24, +0x3c,0x03,0x00,0x80,0x08,0x00,0x06,0x2a,0x00,0x43,0x28,0x25,0x0c,0x00,0x06,0xce, +0x24,0x04,0x04,0x50,0x30,0x51,0x00,0x7f,0x00,0x40,0x80,0x21,0x2e,0x22,0x00,0x32, +0x10,0x40,0xff,0x9a,0x24,0x02,0x00,0x20,0x12,0x22,0x00,0x04,0x24,0x02,0xff,0x80, +0x02,0x02,0x10,0x24,0x08,0x00,0x05,0xcd,0x26,0x31,0x00,0x02,0x0c,0x00,0x06,0xce, +0x24,0x04,0x02,0x08,0x3c,0x04,0x00,0xc0,0x00,0x40,0x28,0x21,0x00,0x44,0x10,0x24, +0x00,0x02,0x15,0x82,0x24,0x03,0x00,0x03,0x10,0x43,0x00,0x07,0x00,0x00,0x00,0x00, +0x3c,0x02,0xff,0x3f,0x34,0x42,0xff,0xff,0x00,0xa2,0x10,0x24,0x00,0x44,0x28,0x25, +0x0c,0x00,0x06,0xc1,0x24,0x04,0x02,0x08,0x0c,0x00,0x06,0xce,0x24,0x04,0x02,0x2c, +0x00,0x40,0x90,0x21,0x3c,0x02,0xff,0xff,0x34,0x42,0x3f,0xff,0x02,0x42,0x90,0x24, +0x02,0x40,0x28,0x21,0x0c,0x00,0x06,0xc1,0x24,0x04,0x02,0x2c,0x08,0x00,0x06,0x44, +0x24,0x02,0xff,0x80,0x0c,0x00,0x06,0xce,0x24,0x04,0x04,0x50,0x00,0x40,0x80,0x21, +0x30,0x51,0x00,0x7f,0x24,0x02,0x00,0x20,0x12,0x22,0x00,0x1d,0x2e,0x22,0x00,0x21, +0x14,0x40,0xff,0x72,0x24,0x02,0xff,0x80,0x02,0x02,0x10,0x24,0x26,0x31,0xff,0xff, +0x00,0x51,0x80,0x25,0x24,0x04,0x04,0x50,0x0c,0x00,0x06,0xc1,0x02,0x00,0x28,0x21, +0x24,0x04,0x04,0x58,0x0c,0x00,0x06,0xc1,0x02,0x00,0x28,0x21,0x24,0x04,0x04,0x60, +0x0c,0x00,0x06,0xc1,0x02,0x00,0x28,0x21,0x02,0x00,0x28,0x21,0x0c,0x00,0x06,0xc1, +0x24,0x04,0x04,0x68,0x24,0x02,0x00,0x20,0x16,0x22,0xff,0x60,0x00,0x00,0x00,0x00, +0x0c,0x00,0x06,0xce,0x24,0x04,0x02,0x2c,0x00,0x40,0x90,0x21,0x3c,0x02,0xff,0xff, +0x34,0x42,0x3f,0xff,0x02,0x42,0x10,0x24,0x08,0x00,0x06,0x1b,0x34,0x52,0x80,0x00, +0x0c,0x00,0x06,0xce,0x24,0x04,0x02,0x2c,0x34,0x52,0x40,0x00,0x02,0x40,0x28,0x21, +0x0c,0x00,0x06,0xc1,0x24,0x04,0x02,0x2c,0x0c,0x00,0x06,0xce,0x24,0x04,0x02,0x58, +0x24,0x04,0x02,0x5c,0x0c,0x00,0x06,0xce,0x00,0x02,0x9e,0x02,0x30,0x43,0x00,0xff, +0x00,0x13,0x12,0x00,0x00,0x43,0x10,0x25,0x2c,0x43,0x00,0x04,0x14,0x60,0x00,0x20, +0x2c,0x42,0x00,0x11,0x10,0x40,0x00,0x0d,0x00,0x00,0x00,0x00,0x3c,0x02,0xff,0xff, +0x34,0x42,0x3f,0xff,0x02,0x42,0x90,0x24,0x02,0x40,0x28,0x21,0x24,0x04,0x02,0x2c, +0x0c,0x00,0x06,0xc1,0x36,0x52,0x80,0x00,0x02,0x40,0x28,0x21,0x0c,0x00,0x06,0xc1, +0x24,0x04,0x02,0x2c,0x08,0x00,0x06,0x68,0x2e,0x22,0x00,0x21,0x0c,0x00,0x06,0xce, +0x24,0x04,0x02,0x08,0x3c,0x04,0x00,0xc0,0x00,0x40,0x28,0x21,0x00,0x44,0x10,0x24, +0x00,0x02,0x15,0x82,0x24,0x03,0x00,0x02,0x14,0x43,0xff,0xec,0x00,0x00,0x00,0x00, +0x3c,0x02,0xff,0x3f,0x34,0x42,0xff,0xff,0x00,0xa2,0x10,0x24,0x00,0x44,0x28,0x25, +0x0c,0x00,0x06,0xc1,0x24,0x04,0x02,0x08,0x08,0x00,0x06,0x98,0x3c,0x02,0xff,0xff, +0x0c,0x00,0x06,0xce,0x24,0x04,0x02,0x08,0x00,0x40,0x28,0x21,0x00,0x02,0x15,0x82, +0x30,0x42,0x00,0x03,0x24,0x03,0x00,0x03,0x14,0x43,0xff,0xdc,0x3c,0x03,0x00,0x80, +0x3c,0x02,0xff,0x3f,0x34,0x42,0xff,0xff,0x00,0xa2,0x10,0x24,0x08,0x00,0x06,0xb0, +0x00,0x43,0x28,0x25,0x30,0x83,0x00,0x03,0x00,0x04,0x20,0x40,0x00,0x83,0x20,0x23, +0x3c,0x02,0xb0,0x0a,0x00,0x82,0x20,0x21,0xac,0x85,0x00,0x00,0x00,0x00,0x18,0x21, +0x24,0x63,0x00,0x01,0x2c,0x62,0x00,0x0a,0x14,0x40,0xff,0xfe,0x24,0x63,0x00,0x01, +0x03,0xe0,0x00,0x08,0x24,0x63,0xff,0xff,0x30,0x86,0x00,0x03,0x00,0x04,0x28,0x40, +0x3c,0x03,0xb0,0x0a,0x00,0xa6,0x10,0x23,0x00,0x43,0x10,0x21,0x24,0x04,0xff,0xff, +0xac,0x44,0x10,0x00,0x00,0x00,0x18,0x21,0x24,0x63,0x00,0x01,0x2c,0x62,0x00,0x0a, +0x14,0x40,0xff,0xfe,0x24,0x63,0x00,0x01,0x24,0x63,0xff,0xff,0x00,0xa6,0x18,0x23, +0x3c,0x02,0xb0,0x0a,0x00,0x62,0x18,0x21,0x8c,0x62,0x00,0x00,0x03,0xe0,0x00,0x08, +0x00,0x00,0x00,0x00,0x3c,0x05,0xb0,0x03,0x3c,0x02,0x80,0x00,0x24,0x42,0x1b,0x84, +0x24,0x03,0x00,0x01,0x34,0xa5,0x00,0x20,0x3c,0x06,0xb0,0x03,0xac,0xa2,0x00,0x00, +0x34,0xc6,0x01,0x04,0xa0,0x83,0x00,0x48,0xa0,0x80,0x00,0x04,0xa0,0x80,0x00,0x05, +0xa0,0x80,0x00,0x06,0xa0,0x80,0x00,0x07,0xa0,0x80,0x00,0x08,0xa0,0x80,0x00,0x09, +0xa0,0x80,0x00,0x0a,0xa0,0x80,0x00,0x11,0xa0,0x80,0x00,0x13,0xa0,0x80,0x00,0x49, +0x94,0xc2,0x00,0x00,0xac,0x80,0x00,0x00,0xa0,0x80,0x00,0x4e,0x00,0x02,0x14,0x00, +0x00,0x02,0x14,0x03,0x30,0x43,0x00,0xff,0x30,0x42,0xff,0x00,0xa4,0x82,0x00,0x44, +0xa4,0x83,0x00,0x46,0xac,0x80,0x00,0x24,0xac,0x80,0x00,0x28,0xac,0x80,0x00,0x2c, +0xac,0x80,0x00,0x30,0xac,0x80,0x00,0x34,0xac,0x80,0x00,0x38,0xac,0x80,0x00,0x3c, +0x03,0xe0,0x00,0x08,0xac,0x80,0x00,0x40,0x84,0x83,0x00,0x0c,0x3c,0x07,0xb0,0x03, +0x34,0xe7,0x00,0x20,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80, +0x27,0x83,0x8f,0xf4,0x00,0x43,0x10,0x21,0x8c,0x48,0x00,0x18,0x3c,0x02,0x80,0x00, +0x24,0x42,0x1c,0x18,0xac,0xe2,0x00,0x00,0x8d,0x03,0x00,0x08,0x80,0x82,0x00,0x13, +0x00,0x05,0x2c,0x00,0x00,0x03,0x1e,0x02,0x00,0x02,0x12,0x00,0x30,0x63,0x00,0x7e, +0x00,0x62,0x18,0x21,0x00,0x65,0x18,0x21,0x3c,0x02,0xc0,0x00,0x3c,0x05,0xb0,0x05, +0x34,0x42,0x04,0x00,0x24,0x63,0x00,0x01,0x3c,0x07,0xb0,0x05,0x3c,0x08,0xb0,0x05, +0x34,0xa5,0x04,0x20,0xac,0xa3,0x00,0x00,0x00,0xc2,0x30,0x21,0x34,0xe7,0x04,0x24, +0x35,0x08,0x02,0x28,0x24,0x02,0x00,0x01,0x24,0x03,0x00,0x20,0xac,0xe6,0x00,0x00, +0xac,0x82,0x00,0x3c,0x03,0xe0,0x00,0x08,0xa1,0x03,0x00,0x00,0x27,0xbd,0xff,0xa8, +0x00,0x07,0x60,0x80,0x27,0x82,0xb3,0xf0,0xaf,0xbe,0x00,0x50,0xaf,0xb7,0x00,0x4c, +0xaf,0xb5,0x00,0x44,0xaf,0xb4,0x00,0x40,0xaf,0xbf,0x00,0x54,0xaf,0xb6,0x00,0x48, +0xaf,0xb3,0x00,0x3c,0xaf,0xb2,0x00,0x38,0xaf,0xb1,0x00,0x34,0xaf,0xb0,0x00,0x30, +0x01,0x82,0x10,0x21,0x8c,0x43,0x00,0x00,0x00,0xe0,0x70,0x21,0x3c,0x02,0x80,0x00, +0x94,0x73,0x00,0x14,0x3c,0x07,0xb0,0x03,0x34,0xe7,0x00,0x20,0x24,0x42,0x1c,0xac, +0x3c,0x03,0xb0,0x05,0xac,0xe2,0x00,0x00,0x34,0x63,0x01,0x28,0x90,0x67,0x00,0x00, +0x00,0x13,0xa8,0xc0,0x02,0xb3,0x18,0x21,0x27,0x82,0x8f,0xf4,0x00,0x03,0x18,0x80, +0x00,0x62,0x18,0x21,0x00,0x05,0x2c,0x00,0x00,0x07,0x3e,0x00,0x28,0xc2,0x00,0x03, +0x00,0xc0,0xa0,0x21,0x00,0x80,0x78,0x21,0x00,0x05,0xbc,0x03,0x8c,0x68,0x00,0x18, +0x02,0xa0,0x58,0x21,0x10,0x40,0x01,0x81,0x00,0x07,0xf6,0x03,0x00,0xde,0x10,0x07, +0x30,0x5e,0x00,0x01,0x01,0x73,0x10,0x21,0x27,0x83,0x8f,0xf8,0x00,0x02,0x10,0x80, +0x00,0x43,0x10,0x21,0x80,0x4d,0x00,0x06,0x8d,0x03,0x00,0x00,0x8d,0x02,0x00,0x04, +0x8d,0x0a,0x00,0x08,0x8d,0x03,0x00,0x0c,0xaf,0xa2,0x00,0x20,0x11,0xa0,0x01,0x71, +0xaf,0xa3,0x00,0x18,0x27,0x82,0xb3,0xf0,0x01,0x82,0x10,0x21,0x8c,0x44,0x00,0x00, +0x00,0x00,0x00,0x00,0x90,0x83,0x00,0x16,0x00,0x00,0x00,0x00,0x30,0x63,0x00,0x04, +0x14,0x60,0x00,0x12,0x00,0x00,0xb0,0x21,0x3c,0x02,0xb0,0x09,0x34,0x42,0x01,0x46, +0x90,0x43,0x00,0x00,0x2a,0x84,0x00,0x04,0x10,0x80,0x01,0x56,0x30,0x65,0x00,0x01, +0x91,0xe2,0x00,0x09,0x00,0x00,0x00,0x00,0x12,0x82,0x00,0x02,0x00,0x00,0x00,0x00, +0x00,0x00,0x28,0x21,0x14,0xa0,0x00,0x03,0x00,0x00,0x38,0x21,0x13,0xc0,0x00,0x03, +0x38,0xf6,0x00,0x01,0x24,0x07,0x00,0x01,0x38,0xf6,0x00,0x01,0x01,0x73,0x10,0x21, +0x00,0x02,0x30,0x80,0x27,0x83,0x90,0x00,0x00,0xc3,0x48,0x21,0x91,0x25,0x00,0x00, +0x8f,0xa4,0x00,0x20,0x2c,0xa3,0x00,0x04,0x00,0x04,0x11,0xc3,0x30,0x42,0x00,0x01, +0x00,0x03,0xb0,0x0b,0x12,0xc0,0x00,0xd8,0xaf,0xa2,0x00,0x24,0x93,0x90,0xbb,0xda, +0x00,0x0a,0x16,0x42,0x30,0x52,0x00,0x3f,0x2e,0x06,0x00,0x0c,0x10,0xc0,0x00,0xc0, +0x00,0xa0,0x20,0x21,0x2c,0xa2,0x00,0x10,0x14,0x40,0x00,0x04,0x00,0x90,0x10,0x2b, +0x30,0xa2,0x00,0x07,0x24,0x44,0x00,0x04,0x00,0x90,0x10,0x2b,0x10,0x40,0x00,0x0b, +0x01,0x73,0x10,0x21,0x27,0x85,0xbb,0x0c,0x00,0x10,0x10,0x40,0x00,0x50,0x10,0x21, +0x00,0x45,0x10,0x21,0x90,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x90,0x18,0x2b, +0x14,0x60,0xff,0xfa,0x00,0x10,0x10,0x40,0x01,0x73,0x10,0x21,0x00,0x02,0x10,0x80, +0x27,0x83,0x8f,0xf8,0x00,0x43,0x10,0x21,0x31,0xa4,0x00,0x01,0x10,0x80,0x00,0xa5, +0xa0,0x50,0x00,0x07,0x3c,0x04,0xb0,0x05,0x34,0x84,0x00,0x08,0x24,0x02,0x00,0x01, +0x3c,0x03,0x80,0x00,0xa1,0xe2,0x00,0x4e,0xac,0x83,0x00,0x00,0x8c,0x85,0x00,0x00, +0x3c,0x02,0x00,0xf0,0x3c,0x03,0x40,0xf0,0x34,0x42,0xf0,0x00,0x34,0x63,0xf0,0x00, +0x24,0x17,0x00,0x0e,0x24,0x13,0x01,0x06,0xac,0x82,0x00,0x00,0xac,0x83,0x00,0x00, +0x27,0x82,0xb3,0xf0,0x01,0x82,0x10,0x21,0x8c,0x43,0x00,0x00,0x24,0x05,0x00,0x01, +0xaf,0xa5,0x00,0x1c,0x90,0x62,0x00,0x16,0x00,0x13,0xa8,0xc0,0x32,0x51,0x00,0x02, +0x34,0x42,0x00,0x04,0xa0,0x62,0x00,0x16,0x8f,0xa3,0x00,0x20,0x8f,0xa4,0x00,0x18, +0x00,0x03,0x13,0x43,0x00,0x04,0x1a,0x02,0x30,0x47,0x00,0x01,0x12,0x20,0x00,0x04, +0x30,0x64,0x07,0xff,0x2e,0x03,0x00,0x04,0x32,0x42,0x00,0x33,0x00,0x43,0x90,0x0b, +0x8f,0xa5,0x00,0x24,0x8f,0xa6,0x00,0x1c,0x00,0x12,0x10,0x40,0x00,0x05,0x19,0xc0, +0x00,0x47,0x10,0x21,0x00,0x06,0x2a,0x80,0x00,0x43,0x10,0x21,0x00,0x10,0x32,0x00, +0x00,0x04,0x24,0x80,0x02,0x65,0x28,0x21,0x00,0xa4,0x28,0x21,0x00,0x46,0x10,0x21, +0x00,0x17,0x1c,0x00,0x3c,0x04,0xc0,0x00,0x00,0x43,0x30,0x21,0x16,0x80,0x00,0x29, +0x00,0xa4,0x28,0x21,0x3c,0x02,0xb0,0x05,0x34,0x42,0x04,0x00,0x3c,0x03,0xb0,0x05, +0x3c,0x04,0xb0,0x05,0xac,0x46,0x00,0x00,0x34,0x63,0x04,0x04,0x34,0x84,0x02,0x28, +0x24,0x02,0x00,0x01,0xac,0x65,0x00,0x00,0xa0,0x82,0x00,0x00,0x3c,0x02,0xb0,0x09, +0x34,0x42,0x01,0x46,0x90,0x44,0x00,0x00,0x91,0xe3,0x00,0x09,0x30,0x86,0x00,0x01, +0x02,0x83,0x18,0x26,0x00,0x03,0x30,0x0b,0x14,0xc0,0x00,0x03,0x00,0x00,0x28,0x21, +0x13,0xc0,0x00,0x03,0x02,0xb3,0x10,0x21,0x24,0x05,0x00,0x01,0x02,0xb3,0x10,0x21, +0x27,0x83,0x8f,0xf8,0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21,0x84,0x48,0x00,0x04, +0x00,0xa0,0x30,0x21,0x00,0xe0,0x20,0x21,0x02,0x80,0x28,0x21,0x02,0xc0,0x38,0x21, +0x0c,0x00,0x00,0x72,0xaf,0xa8,0x00,0x10,0x7b,0xbe,0x02,0xbc,0x7b,0xb6,0x02,0x7c, +0x7b,0xb4,0x02,0x3c,0x7b,0xb2,0x01,0xfc,0x7b,0xb0,0x01,0xbc,0x03,0xe0,0x00,0x08, +0x27,0xbd,0x00,0x58,0x24,0x02,0x00,0x01,0x12,0x82,0x00,0x3d,0x3c,0x02,0xb0,0x05, +0x24,0x02,0x00,0x02,0x12,0x82,0x00,0x31,0x3c,0x02,0xb0,0x05,0x24,0x02,0x00,0x03, +0x12,0x82,0x00,0x25,0x3c,0x02,0xb0,0x05,0x24,0x02,0x00,0x10,0x12,0x82,0x00,0x19, +0x3c,0x02,0xb0,0x05,0x24,0x02,0x00,0x11,0x12,0x82,0x00,0x0d,0x3c,0x02,0xb0,0x05, +0x24,0x02,0x00,0x12,0x16,0x82,0xff,0xd1,0x3c,0x02,0xb0,0x05,0x3c,0x03,0xb0,0x05, +0x34,0x42,0x04,0x20,0x3c,0x04,0xb0,0x05,0x34,0x63,0x04,0x24,0xac,0x46,0x00,0x00, +0x34,0x84,0x02,0x28,0xac,0x65,0x00,0x00,0x08,0x00,0x07,0xe2,0x24,0x02,0x00,0x20, +0x34,0x42,0x04,0x40,0x3c,0x03,0xb0,0x05,0x3c,0x04,0xb0,0x05,0xac,0x46,0x00,0x00, +0x34,0x63,0x04,0x44,0x34,0x84,0x02,0x28,0x24,0x02,0x00,0x40,0x08,0x00,0x07,0xe2, +0xac,0x65,0x00,0x00,0x34,0x42,0x04,0x28,0x3c,0x03,0xb0,0x05,0x3c,0x04,0xb0,0x05, +0xac,0x46,0x00,0x00,0x34,0x63,0x04,0x2c,0x34,0x84,0x02,0x28,0x24,0x02,0xff,0x80, +0x08,0x00,0x07,0xe2,0xac,0x65,0x00,0x00,0x34,0x42,0x04,0x18,0x3c,0x03,0xb0,0x05, +0x3c,0x04,0xb0,0x05,0xac,0x46,0x00,0x00,0x34,0x63,0x04,0x1c,0x34,0x84,0x02,0x28, +0x24,0x02,0x00,0x08,0x08,0x00,0x07,0xe2,0xac,0x65,0x00,0x00,0x34,0x42,0x04,0x10, +0x3c,0x03,0xb0,0x05,0x3c,0x04,0xb0,0x05,0xac,0x46,0x00,0x00,0x34,0x63,0x04,0x14, +0x34,0x84,0x02,0x28,0x24,0x02,0x00,0x04,0x08,0x00,0x07,0xe2,0xac,0x65,0x00,0x00, +0x34,0x42,0x04,0x08,0x3c,0x03,0xb0,0x05,0x3c,0x04,0xb0,0x05,0xac,0x46,0x00,0x00, +0x34,0x63,0x04,0x0c,0x34,0x84,0x02,0x28,0x24,0x02,0x00,0x02,0x08,0x00,0x07,0xe2, +0xac,0x65,0x00,0x00,0x24,0x17,0x00,0x14,0x08,0x00,0x07,0xb4,0x24,0x13,0x01,0x02, +0x30,0xa2,0x00,0x07,0x24,0x44,0x00,0x0c,0x00,0x90,0x18,0x2b,0x10,0x60,0x00,0x0c, +0x26,0x02,0x00,0x04,0x27,0x85,0xbb,0x0c,0x00,0x10,0x10,0x40,0x00,0x50,0x10,0x21, +0x00,0x45,0x10,0x21,0x90,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x90,0x18,0x2b, +0x14,0x60,0xff,0xfa,0x00,0x10,0x10,0x40,0x2e,0x06,0x00,0x0c,0x26,0x02,0x00,0x04, +0x08,0x00,0x07,0x9e,0x00,0x46,0x80,0x0a,0x27,0x82,0xb3,0xf0,0x01,0x82,0x20,0x21, +0x8c,0x87,0x00,0x00,0x00,0x00,0x00,0x00,0x90,0xe2,0x00,0x19,0x00,0x00,0x00,0x00, +0x14,0x40,0x00,0x07,0x00,0x00,0x00,0x00,0x27,0x82,0x90,0x10,0x00,0xc2,0x10,0x21, +0x90,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x60,0x00,0x14,0x00,0x00,0x00,0x00, +0x90,0xe3,0x00,0x16,0x27,0x82,0x8f,0xf8,0x00,0xc2,0x10,0x21,0x34,0x63,0x00,0x20, +0x90,0x50,0x00,0x07,0xa0,0xe3,0x00,0x16,0x8c,0x84,0x00,0x00,0x00,0x0a,0x1e,0x42, +0x24,0x06,0x00,0x01,0x90,0x82,0x00,0x16,0x30,0x71,0x00,0x02,0x30,0x72,0x00,0x3f, +0x30,0x42,0x00,0xfb,0x24,0x17,0x00,0x18,0x24,0x13,0x01,0x03,0x24,0x15,0x08,0x18, +0xaf,0xa6,0x00,0x1c,0x08,0x00,0x07,0xbe,0xa0,0x82,0x00,0x16,0x8d,0x02,0x00,0x04, +0x00,0x0a,0x1c,0x42,0x30,0x42,0x00,0x10,0x14,0x40,0x00,0x15,0x30,0x72,0x00,0x3f, +0x81,0x22,0x00,0x05,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x11,0x30,0x72,0x00,0x3e, +0x27,0x83,0x90,0x08,0x00,0xc3,0x18,0x21,0x80,0x64,0x00,0x00,0x27,0x83,0xb5,0x68, +0x00,0x04,0x11,0x00,0x00,0x44,0x10,0x23,0x00,0x02,0x10,0x80,0x00,0x44,0x10,0x23, +0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21,0x90,0x44,0x00,0x05,0x90,0x43,0x00,0x04, +0x00,0x00,0x00,0x00,0x00,0x64,0x18,0x24,0x30,0x63,0x00,0x01,0x02,0x43,0x90,0x25, +0x27,0x85,0xb3,0xf0,0x01,0x85,0x28,0x21,0x8c,0xa6,0x00,0x00,0x01,0x73,0x10,0x21, +0x27,0x83,0x90,0x00,0x90,0xc4,0x00,0x16,0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21, +0x30,0x84,0x00,0xdf,0x90,0x50,0x00,0x00,0xa0,0xc4,0x00,0x16,0x80,0xc6,0x00,0x12, +0x8c,0xa3,0x00,0x00,0x2d,0xc4,0x00,0x02,0xaf,0xa6,0x00,0x1c,0x90,0x62,0x00,0x16, +0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xfb,0x14,0x80,0x00,0x06,0xa0,0x62,0x00,0x16, +0x24,0x02,0x00,0x06,0x11,0xc2,0x00,0x03,0x24,0x02,0x00,0x04,0x15,0xc2,0xff,0x0e, +0x32,0x51,0x00,0x02,0x32,0x51,0x00,0x02,0x2e,0x02,0x00,0x0c,0x14,0x40,0x00,0x0f, +0x00,0x11,0x18,0x2b,0x32,0x02,0x00,0x0f,0x34,0x42,0x00,0x10,0x00,0x03,0x19,0x00, +0x00,0x43,0x18,0x21,0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0xb8,0xa0,0x43,0x00,0x00, +0x00,0x00,0x20,0x21,0x02,0x00,0x28,0x21,0x0c,0x00,0x02,0x05,0xaf,0xaf,0x00,0x28, +0x8f,0xaf,0x00,0x28,0x08,0x00,0x07,0xbe,0x00,0x00,0x00,0x00,0x08,0x00,0x08,0xb9, +0x32,0x03,0x00,0xff,0x3c,0x03,0xb0,0x05,0x34,0x63,0x02,0x42,0x90,0x62,0x00,0x00, +0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x0f,0x14,0x40,0xfe,0xaa,0x00,0x00,0x00,0x00, +0x91,0xe2,0x00,0x09,0x00,0x00,0x00,0x00,0x02,0x82,0x10,0x26,0x08,0x00,0x07,0x75, +0x00,0x02,0x28,0x0b,0x08,0x00,0x07,0x7b,0x00,0x00,0xb0,0x21,0x24,0x02,0x00,0x10, +0x10,0xc2,0x00,0x08,0x24,0x02,0x00,0x11,0x10,0xc2,0xfe,0x7d,0x00,0x07,0x17,0x83, +0x24,0x02,0x00,0x12,0x14,0xc2,0xfe,0x7b,0x00,0x07,0x17,0x43,0x08,0x00,0x07,0x55, +0x30,0x5e,0x00,0x01,0x08,0x00,0x07,0x55,0x00,0x07,0xf7,0xc2,0x00,0x04,0x10,0x40, +0x27,0x83,0x80,0x1c,0x00,0x43,0x10,0x21,0x00,0x80,0x40,0x21,0x94,0x44,0x00,0x00, +0x2d,0x07,0x00,0x04,0x24,0xc2,0x00,0x03,0x00,0x47,0x30,0x0a,0x00,0x86,0x00,0x18, +0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x34,0x63,0x00,0x20,0x24,0x42,0x23,0x7c, +0xac,0x62,0x00,0x00,0x2d,0x06,0x00,0x10,0x00,0x00,0x20,0x12,0x00,0x04,0x22,0x42, +0x24,0x84,0x00,0x01,0x24,0x83,0x00,0xc0,0x10,0xe0,0x00,0x0b,0x24,0x82,0x00,0x60, +0x00,0x40,0x20,0x21,0x00,0x65,0x20,0x0a,0x3c,0x03,0xb0,0x03,0x34,0x63,0x01,0x00, +0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x01,0x00,0x44,0x20,0x04, +0x03,0xe0,0x00,0x08,0x00,0x80,0x10,0x21,0x24,0x85,0x00,0x28,0x24,0x83,0x00,0x24, +0x31,0x02,0x00,0x08,0x14,0xc0,0xff,0xf4,0x24,0x84,0x00,0x14,0x00,0x60,0x20,0x21, +0x08,0x00,0x08,0xf6,0x00,0xa2,0x20,0x0b,0x27,0xbd,0xff,0xe0,0x3c,0x03,0xb0,0x03, +0x3c,0x02,0x80,0x00,0xaf,0xb0,0x00,0x10,0x24,0x42,0x24,0x18,0x00,0x80,0x80,0x21, +0x34,0x63,0x00,0x20,0x3c,0x04,0xb0,0x03,0xaf,0xb2,0x00,0x18,0xaf,0xb1,0x00,0x14, +0xaf,0xbf,0x00,0x1c,0x83,0xb1,0x00,0x33,0x83,0xa8,0x00,0x37,0x34,0x84,0x01,0x10, +0xac,0x62,0x00,0x00,0x2e,0x02,0x00,0x10,0x00,0xe0,0x90,0x21,0x8c,0x87,0x00,0x00, +0x14,0x40,0x00,0x0c,0x2e,0x02,0x00,0x0c,0x3c,0x02,0x00,0x0f,0x34,0x42,0xf0,0x00, +0x00,0xe2,0x10,0x24,0x14,0x40,0x00,0x37,0x32,0x02,0x00,0x08,0x32,0x02,0x00,0x07, +0x27,0x83,0x80,0xcc,0x00,0x43,0x10,0x21,0x90,0x50,0x00,0x00,0x00,0x00,0x00,0x00, +0x2e,0x02,0x00,0x0c,0x14,0x40,0x00,0x03,0x02,0x00,0x20,0x21,0x32,0x02,0x00,0x0f, +0x24,0x44,0x00,0x0c,0x00,0x87,0x10,0x06,0x30,0x42,0x00,0x01,0x14,0x40,0x00,0x07, +0x2c,0x82,0x00,0x0c,0x00,0x04,0x10,0x80,0x27,0x83,0xb4,0x40,0x00,0x43,0x10,0x21, +0x8c,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x2c,0x82,0x00,0x0c,0x14,0x40,0x00,0x05, +0x00,0x05,0x10,0x40,0x00,0x46,0x10,0x21,0x00,0x02,0x11,0x00,0x00,0x82,0x10,0x21, +0x24,0x44,0x00,0x04,0x15,0x00,0x00,0x02,0x24,0x06,0x00,0x20,0x24,0x06,0x00,0x0e, +0x0c,0x00,0x08,0xdf,0x00,0x00,0x00,0x00,0x00,0x40,0x30,0x21,0x3c,0x02,0xb0,0x03, +0x34,0x42,0x01,0x00,0x90,0x43,0x00,0x00,0x2e,0x04,0x00,0x04,0x24,0x02,0x00,0x10, +0x24,0x05,0x00,0x0a,0x00,0x44,0x28,0x0a,0x30,0x63,0x00,0x01,0x14,0x60,0x00,0x02, +0x00,0x05,0x10,0x40,0x00,0xa0,0x10,0x21,0x30,0x45,0x00,0xff,0x00,0xc5,0x10,0x21, +0x24,0x46,0x00,0x46,0x02,0x26,0x18,0x04,0xa6,0x43,0x00,0x00,0x8f,0xbf,0x00,0x1c, +0x8f,0xb2,0x00,0x18,0x7b,0xb0,0x00,0xbc,0x00,0xc0,0x10,0x21,0x03,0xe0,0x00,0x08, +0x27,0xbd,0x00,0x20,0x10,0x40,0xff,0xcf,0x2e,0x02,0x00,0x0c,0x32,0x02,0x00,0x07, +0x27,0x83,0x80,0xc4,0x00,0x43,0x10,0x21,0x90,0x44,0x00,0x00,0x08,0x00,0x09,0x24, +0x02,0x04,0x80,0x23,0x27,0xbd,0xff,0xb8,0x00,0x05,0x38,0x80,0x27,0x82,0xb3,0xf0, +0xaf,0xbe,0x00,0x40,0xaf,0xb6,0x00,0x38,0xaf,0xb3,0x00,0x2c,0xaf,0xbf,0x00,0x44, +0xaf,0xb7,0x00,0x3c,0xaf,0xb5,0x00,0x34,0xaf,0xb4,0x00,0x30,0xaf,0xb2,0x00,0x28, +0xaf,0xb1,0x00,0x24,0xaf,0xb0,0x00,0x20,0x00,0xe2,0x38,0x21,0x8c,0xe6,0x00,0x00, +0xaf,0xa5,0x00,0x4c,0x3c,0x02,0x80,0x00,0x3c,0x05,0xb0,0x03,0x34,0xa5,0x00,0x20, +0x24,0x42,0x25,0x74,0x24,0x03,0x00,0x01,0xac,0xa2,0x00,0x00,0xa0,0xc3,0x00,0x12, +0x8c,0xe5,0x00,0x00,0x94,0xc3,0x00,0x06,0x90,0xa2,0x00,0x16,0xa4,0xc3,0x00,0x14, +0x27,0x83,0x8f,0xf0,0x34,0x42,0x00,0x08,0xa0,0xa2,0x00,0x16,0x8c,0xe8,0x00,0x00, +0xaf,0xa4,0x00,0x48,0x27,0x82,0x8f,0xf4,0x95,0x11,0x00,0x14,0x00,0x00,0x00,0x00, +0x00,0x11,0x98,0xc0,0x02,0x71,0x20,0x21,0x00,0x04,0x20,0x80,0x00,0x82,0x10,0x21, +0x8c,0x52,0x00,0x18,0x00,0x83,0x18,0x21,0x84,0x75,0x00,0x06,0x8e,0x45,0x00,0x08, +0x8e,0x46,0x00,0x04,0x8e,0x47,0x00,0x04,0x00,0x05,0x1c,0x82,0x00,0x06,0x31,0x42, +0x27,0x82,0x90,0x00,0x30,0x63,0x00,0x01,0x30,0xc6,0x00,0x01,0x00,0x82,0x20,0x21, +0xa5,0x15,0x00,0x1a,0x00,0x05,0x14,0x42,0xaf,0xa3,0x00,0x18,0xaf,0xa6,0x00,0x1c, +0x30,0xe7,0x00,0x10,0x30,0x56,0x00,0x01,0x80,0x97,0x00,0x06,0x14,0xe0,0x00,0x47, +0x00,0x05,0xf7,0xc2,0x80,0x82,0x00,0x05,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x44, +0x02,0x71,0x10,0x21,0x93,0x90,0xbb,0xd9,0x00,0x00,0x00,0x00,0x2e,0x02,0x00,0x0c, +0x14,0x40,0x00,0x06,0x02,0x00,0x20,0x21,0x00,0x16,0x10,0x40,0x00,0x43,0x10,0x21, +0x00,0x02,0x11,0x00,0x02,0x02,0x10,0x21,0x24,0x44,0x00,0x04,0x02,0x71,0x10,0x21, +0x00,0x02,0x10,0x80,0x27,0x83,0x90,0x00,0x00,0x43,0x10,0x21,0x00,0x80,0x80,0x21, +0xa0,0x44,0x00,0x03,0xa0,0x44,0x00,0x00,0x02,0x00,0x20,0x21,0x02,0xc0,0x28,0x21, +0x0c,0x00,0x08,0xdf,0x02,0xa0,0x30,0x21,0x02,0x71,0x18,0x21,0x00,0x03,0x88,0x80, +0x00,0x40,0xa0,0x21,0x27,0x82,0x90,0x10,0x02,0x22,0x10,0x21,0x8c,0x44,0x00,0x00, +0x26,0xe3,0x00,0x02,0x00,0x03,0x17,0xc2,0x00,0x62,0x18,0x21,0x00,0x04,0x25,0xc2, +0x00,0x03,0x18,0x43,0x30,0x84,0x00,0x01,0x00,0x03,0x18,0x40,0x03,0xc4,0x20,0x24, +0x14,0x80,0x00,0x15,0x02,0x43,0x38,0x21,0x3c,0x08,0xb0,0x03,0x35,0x08,0x00,0x28, +0x8d,0x03,0x00,0x00,0x8f,0xa6,0x00,0x4c,0x8f,0xa4,0x00,0x48,0x27,0x82,0x8f,0xf8, +0x02,0x22,0x10,0x21,0x24,0x63,0x00,0x01,0x02,0xa0,0x28,0x21,0xa4,0x54,0x00,0x04, +0x00,0xc0,0x38,0x21,0x0c,0x00,0x07,0x2b,0xad,0x03,0x00,0x00,0x7b,0xbe,0x02,0x3c, +0x7b,0xb6,0x01,0xfc,0x7b,0xb4,0x01,0xbc,0x7b,0xb2,0x01,0x7c,0x7b,0xb0,0x01,0x3c, +0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x48,0x8f,0xa2,0x00,0x1c,0x8f,0xa6,0x00,0x18, +0x02,0x00,0x20,0x21,0x02,0xc0,0x28,0x21,0xaf,0xa2,0x00,0x10,0x0c,0x00,0x09,0x06, +0xaf,0xa0,0x00,0x14,0x08,0x00,0x09,0xc2,0x02,0x82,0xa0,0x21,0x02,0x71,0x10,0x21, +0x00,0x02,0x10,0x80,0x27,0x83,0x90,0x00,0x00,0x43,0x10,0x21,0x90,0x50,0x00,0x00, +0x08,0x00,0x09,0xae,0xa0,0x50,0x00,0x03,0x27,0xbd,0xff,0xb8,0xaf,0xb1,0x00,0x24, +0x8f,0xb1,0x00,0x5c,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x34,0x63,0x00,0x20, +0x24,0x42,0x27,0x98,0xaf,0xbe,0x00,0x40,0xaf,0xb7,0x00,0x3c,0xaf,0xb6,0x00,0x38, +0xaf,0xb5,0x00,0x34,0xaf,0xb4,0x00,0x30,0xaf,0xa5,0x00,0x4c,0x8f,0xb5,0x00,0x58, +0xaf,0xbf,0x00,0x44,0xaf,0xb3,0x00,0x2c,0xaf,0xb2,0x00,0x28,0xaf,0xb0,0x00,0x20, +0x00,0xe0,0xb0,0x21,0xac,0x62,0x00,0x00,0x00,0x80,0xf0,0x21,0x00,0x00,0xb8,0x21, +0x16,0x20,0x00,0x2b,0x00,0x00,0xa0,0x21,0x27,0x85,0xb3,0xf0,0x00,0x07,0x10,0x80, +0x00,0x45,0x10,0x21,0x8c,0x53,0x00,0x00,0x00,0x15,0x18,0x80,0x00,0x65,0x18,0x21, +0x92,0x62,0x00,0x16,0x8c,0x72,0x00,0x00,0x30,0x42,0x00,0x03,0x14,0x40,0x00,0x2d, +0x00,0x00,0x00,0x00,0x92,0x42,0x00,0x16,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x03, +0x14,0x40,0x00,0x28,0x00,0x00,0x00,0x00,0x8c,0x82,0x00,0x34,0x00,0x00,0x00,0x00, +0x14,0x40,0x00,0x18,0x02,0x20,0x10,0x21,0x8c,0x82,0x00,0x38,0x00,0x00,0x00,0x00, +0x14,0x40,0x00,0x14,0x02,0x20,0x10,0x21,0x8c,0x82,0x00,0x3c,0x00,0x00,0x00,0x00, +0x14,0x40,0x00,0x0f,0x3c,0x03,0xb0,0x09,0x3c,0x05,0xb0,0x05,0x34,0x63,0x01,0x44, +0x34,0xa5,0x02,0x52,0x94,0x66,0x00,0x00,0x90,0xa2,0x00,0x00,0x8f,0xa3,0x00,0x4c, +0x00,0x00,0x00,0x00,0x00,0x62,0x10,0x06,0x30,0x42,0x00,0x01,0x10,0x40,0x00,0x04, +0x30,0xc6,0xff,0xff,0x2c,0xc2,0x00,0x41,0x10,0x40,0x00,0x09,0x24,0x05,0x00,0x14, +0x02,0x20,0x10,0x21,0x7b,0xbe,0x02,0x3c,0x7b,0xb6,0x01,0xfc,0x7b,0xb4,0x01,0xbc, +0x7b,0xb2,0x01,0x7c,0x7b,0xb0,0x01,0x3c,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x48, +0x0c,0x00,0x07,0x06,0x24,0x06,0x01,0x07,0x24,0x02,0x00,0x01,0x08,0x00,0x0a,0x28, +0xa3,0xc2,0x00,0x11,0x10,0xc0,0x00,0x1c,0x24,0x02,0x00,0x01,0x10,0xc2,0x00,0x17, +0x00,0xc0,0x88,0x21,0x96,0x54,0x00,0x1a,0x02,0xa0,0xb8,0x21,0x12,0x20,0xff,0xed, +0x02,0x20,0x10,0x21,0x27,0x83,0xb3,0xf0,0x00,0x17,0x10,0x80,0x00,0x43,0x10,0x21, +0x8c,0x44,0x00,0x00,0x3c,0x03,0xb0,0x03,0x34,0x63,0x00,0x28,0x80,0x86,0x00,0x12, +0x8c,0x62,0x00,0x00,0x00,0x14,0x2c,0x00,0x00,0x05,0x2c,0x03,0x00,0x46,0x10,0x21, +0x8f,0xa6,0x00,0x4c,0x02,0xe0,0x38,0x21,0x03,0xc0,0x20,0x21,0x0c,0x00,0x07,0x2b, +0xac,0x62,0x00,0x00,0x08,0x00,0x0a,0x28,0xaf,0xd1,0x00,0x40,0x96,0x74,0x00,0x1a, +0x08,0x00,0x0a,0x3b,0x02,0xc0,0xb8,0x21,0x3c,0x02,0xb0,0x03,0x34,0x42,0x01,0x08, +0x8c,0x50,0x00,0x00,0x02,0x60,0x20,0x21,0x0c,0x00,0x1f,0x11,0x02,0x00,0x28,0x21, +0x30,0x42,0x00,0xff,0x02,0x00,0x28,0x21,0x02,0x40,0x20,0x21,0x0c,0x00,0x1f,0x11, +0xaf,0xa2,0x00,0x18,0x8f,0xa4,0x00,0x18,0x00,0x00,0x00,0x00,0x10,0x80,0x00,0xed, +0x30,0x50,0x00,0xff,0x12,0x00,0x00,0x18,0x24,0x11,0x00,0x01,0x96,0x63,0x00,0x14, +0x96,0x44,0x00,0x14,0x27,0x85,0x8f,0xf0,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21, +0x00,0x02,0x10,0x80,0x00,0x45,0x10,0x21,0x00,0x04,0x18,0xc0,0x8c,0x46,0x00,0x08, +0x00,0x64,0x18,0x21,0x00,0x03,0x18,0x80,0x00,0x65,0x18,0x21,0x00,0x06,0x17,0x02, +0x24,0x04,0x00,0xff,0x8c,0x63,0x00,0x08,0x10,0x44,0x00,0xd6,0x00,0x03,0x17,0x02, +0x10,0x44,0x00,0xd5,0x3c,0x02,0x80,0x00,0x00,0x66,0x18,0x2b,0x24,0x11,0x00,0x02, +0x24,0x02,0x00,0x01,0x00,0x43,0x88,0x0a,0x24,0x02,0x00,0x01,0x12,0x22,0x00,0x5a, +0x24,0x02,0x00,0x02,0x16,0x22,0xff,0xbd,0x00,0x00,0x00,0x00,0x96,0x49,0x00,0x14, +0x27,0x82,0x8f,0xf4,0x02,0xa0,0xb8,0x21,0x00,0x09,0x50,0xc0,0x01,0x49,0x18,0x21, +0x00,0x03,0x40,0x80,0x01,0x02,0x10,0x21,0x8c,0x43,0x00,0x18,0x00,0x00,0x00,0x00, +0x8c,0x65,0x00,0x08,0x8c,0x62,0x00,0x0c,0x8c,0x62,0x00,0x04,0x00,0x05,0x24,0x42, +0x00,0x05,0x1c,0x82,0x30,0x42,0x00,0x10,0x30,0x66,0x00,0x01,0x14,0x40,0x00,0x41, +0x30,0x87,0x00,0x01,0x27,0x82,0x90,0x08,0x01,0x02,0x10,0x21,0x80,0x44,0x00,0x00, +0x27,0x82,0xb5,0x68,0x00,0x04,0x19,0x00,0x00,0x64,0x18,0x23,0x00,0x03,0x18,0x80, +0x00,0x64,0x18,0x23,0x00,0x03,0x18,0x80,0x00,0x62,0x10,0x21,0x90,0x45,0x00,0x05, +0x27,0x84,0xb4,0x90,0x00,0x64,0x18,0x21,0x90,0x63,0x00,0x00,0x10,0xa0,0x00,0x2b, +0x2c,0x64,0x00,0x0c,0x14,0x80,0x00,0x04,0x00,0x60,0x10,0x21,0x00,0x06,0x11,0x00, +0x00,0x62,0x10,0x21,0x24,0x42,0x00,0x24,0x3c,0x01,0xb0,0x03,0xa0,0x22,0x00,0xb9, +0x14,0x80,0x00,0x06,0x00,0x60,0x28,0x21,0x00,0x07,0x10,0x40,0x00,0x46,0x10,0x21, +0x00,0x02,0x11,0x00,0x00,0x62,0x10,0x21,0x24,0x45,0x00,0x04,0x01,0x49,0x10,0x21, +0x27,0x83,0x90,0x00,0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21,0x00,0xa0,0x18,0x21, +0xa0,0x45,0x00,0x03,0xa0,0x45,0x00,0x00,0x24,0x02,0x00,0x08,0x12,0x02,0x00,0x0b, +0x24,0x02,0x00,0x01,0x00,0x60,0x28,0x21,0x02,0x40,0x20,0x21,0x0c,0x00,0x1f,0x8d, +0xaf,0xa2,0x00,0x10,0x30,0x54,0xff,0xff,0x92,0x42,0x00,0x16,0x00,0x00,0x00,0x00, +0x02,0x02,0x10,0x25,0x08,0x00,0x0a,0x3b,0xa2,0x42,0x00,0x16,0x00,0x60,0x28,0x21, +0x02,0x40,0x20,0x21,0x0c,0x00,0x1f,0x3e,0xaf,0xa0,0x00,0x10,0x08,0x00,0x0a,0xbe, +0x30,0x54,0xff,0xff,0x08,0x00,0x0a,0xa6,0x00,0x60,0x10,0x21,0x14,0x80,0xff,0xfd, +0x00,0x00,0x00,0x00,0x00,0x06,0x11,0x00,0x00,0x62,0x10,0x21,0x08,0x00,0x0a,0xa6, +0x24,0x42,0x00,0x04,0x27,0x82,0x90,0x00,0x01,0x02,0x10,0x21,0x90,0x43,0x00,0x00, +0x08,0x00,0x0a,0xb6,0xa0,0x43,0x00,0x03,0x96,0x69,0x00,0x14,0x02,0xc0,0xb8,0x21, +0x24,0x0b,0x00,0x01,0x00,0x09,0x10,0xc0,0x00,0x49,0x18,0x21,0x00,0x03,0x40,0x80, +0x00,0x40,0x50,0x21,0x27,0x82,0x8f,0xf4,0x01,0x02,0x10,0x21,0x8c,0x43,0x00,0x18, +0x00,0x00,0x00,0x00,0x8c,0x65,0x00,0x08,0x8c,0x62,0x00,0x0c,0x8c,0x62,0x00,0x04, +0x00,0x05,0x24,0x42,0x00,0x05,0x1c,0x82,0x30,0x42,0x00,0x10,0x30,0x66,0x00,0x01, +0x10,0x40,0x00,0x0d,0x30,0x87,0x00,0x01,0x27,0x82,0x90,0x08,0x01,0x02,0x10,0x21, +0x80,0x43,0x00,0x00,0x00,0x00,0x58,0x21,0x00,0x03,0x11,0x00,0x00,0x43,0x10,0x23, +0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x23,0x00,0x02,0x10,0x80,0x27,0x83,0xb5,0x60, +0x00,0x43,0x10,0x21,0xa0,0x40,0x00,0x04,0x11,0x60,0x00,0x4f,0x00,0x00,0x00,0x00, +0x01,0x49,0x10,0x21,0x00,0x02,0x20,0x80,0x27,0x85,0x90,0x00,0x00,0x85,0x10,0x21, +0x80,0x43,0x00,0x05,0x00,0x00,0x00,0x00,0x14,0x60,0x00,0x42,0x01,0x49,0x10,0x21, +0x27,0x82,0x90,0x08,0x00,0x82,0x10,0x21,0x80,0x44,0x00,0x00,0x27,0x82,0xb5,0x68, +0x00,0x04,0x19,0x00,0x00,0x64,0x18,0x23,0x00,0x03,0x18,0x80,0x00,0x64,0x18,0x23, +0x00,0x03,0x18,0x80,0x00,0x62,0x10,0x21,0x90,0x45,0x00,0x05,0x27,0x84,0xb4,0x90, +0x00,0x64,0x18,0x21,0x90,0x63,0x00,0x00,0x10,0xa0,0x00,0x2c,0x2c,0x64,0x00,0x0c, +0x14,0x80,0x00,0x04,0x00,0x60,0x10,0x21,0x00,0x06,0x11,0x00,0x00,0x62,0x10,0x21, +0x24,0x42,0x00,0x24,0x3c,0x01,0xb0,0x03,0xa0,0x22,0x00,0xb9,0x14,0x80,0x00,0x06, +0x00,0x60,0x28,0x21,0x00,0x07,0x10,0x40,0x00,0x46,0x10,0x21,0x00,0x02,0x11,0x00, +0x00,0x62,0x10,0x21,0x24,0x45,0x00,0x04,0x01,0x49,0x10,0x21,0x27,0x83,0x90,0x00, +0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21,0x00,0xa0,0x18,0x21,0xa0,0x45,0x00,0x03, +0xa0,0x45,0x00,0x00,0x8f,0xa4,0x00,0x18,0x24,0x02,0x00,0x08,0x10,0x82,0x00,0x0c, +0x00,0x60,0x28,0x21,0x24,0x02,0x00,0x01,0x02,0x60,0x20,0x21,0x0c,0x00,0x1f,0x8d, +0xaf,0xa2,0x00,0x10,0x8f,0xa3,0x00,0x18,0x30,0x54,0xff,0xff,0x92,0x62,0x00,0x16, +0x00,0x00,0x00,0x00,0x00,0x62,0x10,0x25,0x08,0x00,0x0a,0x3b,0xa2,0x62,0x00,0x16, +0x02,0x60,0x20,0x21,0x0c,0x00,0x1f,0x3e,0xaf,0xa0,0x00,0x10,0x08,0x00,0x0b,0x2d, +0x00,0x00,0x00,0x00,0x08,0x00,0x0b,0x15,0x00,0x60,0x10,0x21,0x14,0x80,0xff,0xfd, +0x00,0x00,0x00,0x00,0x00,0x06,0x11,0x00,0x00,0x62,0x10,0x21,0x08,0x00,0x0b,0x15, +0x24,0x42,0x00,0x04,0x00,0x02,0x10,0x80,0x00,0x45,0x10,0x21,0x90,0x43,0x00,0x00, +0x08,0x00,0x0b,0x25,0xa0,0x43,0x00,0x03,0x27,0x85,0x90,0x00,0x08,0x00,0x0b,0x41, +0x01,0x49,0x10,0x21,0x3c,0x02,0x80,0x00,0x00,0x62,0x18,0x26,0x08,0x00,0x0a,0x76, +0x00,0xc2,0x30,0x26,0x12,0x00,0xff,0x2d,0x24,0x02,0x00,0x01,0x08,0x00,0x0a,0x7b, +0x24,0x11,0x00,0x02,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x27,0xbd,0xff,0xd0, +0x24,0x42,0x2d,0x44,0x34,0x63,0x00,0x20,0x3c,0x05,0xb0,0x05,0xaf,0xb3,0x00,0x24, +0xaf,0xb2,0x00,0x20,0xaf,0xb1,0x00,0x1c,0xaf,0xbf,0x00,0x28,0xaf,0xb0,0x00,0x18, +0xac,0x62,0x00,0x00,0x34,0xa5,0x02,0x42,0x90,0xa2,0x00,0x00,0x00,0x80,0x90,0x21, +0x24,0x11,0x00,0x10,0x30,0x53,0x00,0xff,0x24,0x02,0x00,0x10,0x12,0x22,0x00,0xcf, +0x00,0x00,0x18,0x21,0x24,0x02,0x00,0x11,0x12,0x22,0x00,0xc1,0x24,0x02,0x00,0x12, +0x12,0x22,0x00,0xb4,0x00,0x00,0x00,0x00,0x14,0x60,0x00,0xad,0xae,0x43,0x00,0x40, +0x3c,0x02,0xb0,0x05,0x34,0x42,0x02,0x2c,0x8c,0x44,0x00,0x00,0x3c,0x03,0x00,0x02, +0x34,0x63,0x00,0xff,0x00,0x83,0x80,0x24,0x00,0x10,0x14,0x43,0x10,0x40,0x00,0x05, +0x00,0x00,0x00,0x00,0x8e,0x42,0x00,0x34,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x92, +0x00,0x00,0x00,0x00,0x93,0x83,0x8b,0x61,0x00,0x00,0x00,0x00,0x30,0x62,0x00,0x02, +0x10,0x40,0x00,0x04,0x32,0x10,0x00,0xff,0x00,0x10,0x11,0xc3,0x14,0x40,0x00,0x86, +0x00,0x00,0x00,0x00,0x16,0x00,0x00,0x15,0x02,0x00,0x10,0x21,0x26,0x22,0x00,0x01, +0x30,0x51,0x00,0xff,0x2e,0x23,0x00,0x13,0x14,0x60,0xff,0xdb,0x24,0x03,0x00,0x02, +0x12,0x63,0x00,0x73,0x24,0x02,0x00,0x05,0x2a,0x62,0x00,0x03,0x10,0x40,0x00,0x58, +0x24,0x02,0x00,0x04,0x24,0x02,0x00,0x01,0x12,0x62,0x00,0x4b,0x02,0x40,0x20,0x21, +0x3c,0x02,0xb0,0x05,0x34,0x42,0x02,0x2c,0x8c,0x43,0x00,0x00,0x00,0x00,0x00,0x00, +0x30,0x70,0x00,0xff,0x12,0x00,0x00,0x06,0x02,0x00,0x10,0x21,0x8f,0xbf,0x00,0x28, +0x7b,0xb2,0x01,0x3c,0x7b,0xb0,0x00,0xfc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x30, +0x92,0x46,0x00,0x04,0x8e,0x43,0x00,0x24,0x24,0x02,0x00,0x07,0x02,0x40,0x20,0x21, +0x00,0x00,0x28,0x21,0x24,0x07,0x00,0x06,0xaf,0xa2,0x00,0x10,0x0c,0x00,0x09,0xe6, +0xaf,0xa3,0x00,0x14,0xae,0x42,0x00,0x24,0x3c,0x02,0xb0,0x05,0x8c,0x42,0x02,0x2c, +0x00,0x00,0x00,0x00,0x30,0x50,0x00,0xff,0x16,0x00,0xff,0xec,0x02,0x00,0x10,0x21, +0x92,0x46,0x00,0x05,0x8e,0x43,0x00,0x28,0x24,0x02,0x00,0x05,0x02,0x40,0x20,0x21, +0x24,0x05,0x00,0x01,0x24,0x07,0x00,0x04,0xaf,0xa2,0x00,0x10,0x0c,0x00,0x09,0xe6, +0xaf,0xa3,0x00,0x14,0xae,0x42,0x00,0x28,0x3c,0x02,0xb0,0x05,0x8c,0x42,0x02,0x2c, +0x00,0x00,0x00,0x00,0x30,0x50,0x00,0xff,0x16,0x00,0xff,0xdc,0x02,0x00,0x10,0x21, +0x92,0x46,0x00,0x06,0x8e,0x43,0x00,0x2c,0x24,0x02,0x00,0x03,0x02,0x40,0x20,0x21, +0x24,0x05,0x00,0x02,0x00,0x00,0x38,0x21,0xaf,0xa2,0x00,0x10,0x0c,0x00,0x09,0xe6, +0xaf,0xa3,0x00,0x14,0xae,0x42,0x00,0x2c,0x3c,0x02,0xb0,0x05,0x8c,0x42,0x02,0x2c, +0x00,0x00,0x00,0x00,0x30,0x50,0x00,0xff,0x16,0x00,0xff,0xcc,0x02,0x00,0x10,0x21, +0x92,0x46,0x00,0x07,0x8e,0x43,0x00,0x30,0x24,0x02,0x00,0x02,0x02,0x40,0x20,0x21, +0x24,0x05,0x00,0x03,0x24,0x07,0x00,0x01,0xaf,0xa2,0x00,0x10,0x0c,0x00,0x09,0xe6, +0xaf,0xa3,0x00,0x14,0xae,0x42,0x00,0x30,0x3c,0x02,0xb0,0x05,0x8c,0x42,0x02,0x2c, +0x08,0x00,0x0b,0x97,0x30,0x42,0x00,0xff,0x92,0x46,0x00,0x04,0x8e,0x43,0x00,0x24, +0x24,0x02,0x00,0x07,0x00,0x00,0x28,0x21,0x24,0x07,0x00,0x06,0xaf,0xa2,0x00,0x10, +0x0c,0x00,0x09,0xe6,0xaf,0xa3,0x00,0x14,0x08,0x00,0x0b,0x90,0xae,0x42,0x00,0x24, +0x12,0x62,0x00,0x0d,0x24,0x02,0x00,0x03,0x24,0x02,0x00,0x08,0x16,0x62,0xff,0xa8, +0x02,0x40,0x20,0x21,0x92,0x46,0x00,0x07,0x8e,0x42,0x00,0x30,0x24,0x05,0x00,0x03, +0x24,0x07,0x00,0x01,0xaf,0xa3,0x00,0x10,0x0c,0x00,0x09,0xe6,0xaf,0xa2,0x00,0x14, +0x08,0x00,0x0b,0x90,0xae,0x42,0x00,0x30,0x92,0x46,0x00,0x06,0x8e,0x43,0x00,0x2c, +0x02,0x40,0x20,0x21,0x24,0x05,0x00,0x02,0x00,0x00,0x38,0x21,0xaf,0xa2,0x00,0x10, +0x0c,0x00,0x09,0xe6,0xaf,0xa3,0x00,0x14,0x08,0x00,0x0b,0x90,0xae,0x42,0x00,0x2c, +0x92,0x46,0x00,0x05,0x8e,0x43,0x00,0x28,0x02,0x40,0x20,0x21,0x24,0x05,0x00,0x01, +0x24,0x07,0x00,0x04,0xaf,0xa2,0x00,0x10,0x0c,0x00,0x09,0xe6,0xaf,0xa3,0x00,0x14, +0x08,0x00,0x0b,0x90,0xae,0x42,0x00,0x28,0x0c,0x00,0x01,0x59,0x24,0x04,0x00,0x01, +0x08,0x00,0x0b,0x81,0x00,0x00,0x00,0x00,0x8f,0x84,0xb4,0x30,0xae,0x40,0x00,0x34, +0x94,0x85,0x00,0x14,0x0c,0x00,0x1b,0x84,0x00,0x00,0x00,0x00,0x93,0x83,0x8b,0x61, +0x00,0x00,0x00,0x00,0x30,0x62,0x00,0x02,0x10,0x40,0xff,0x69,0x00,0x00,0x00,0x00, +0x0c,0x00,0x01,0x59,0x00,0x00,0x20,0x21,0x08,0x00,0x0b,0x79,0x00,0x00,0x00,0x00, +0x02,0x40,0x20,0x21,0x0c,0x00,0x09,0x5d,0x02,0x20,0x28,0x21,0x08,0x00,0x0b,0x6d, +0x3c,0x02,0xb0,0x05,0x8e,0x42,0x00,0x3c,0x00,0x00,0x00,0x00,0x14,0x40,0xff,0x4a, +0x00,0x00,0x00,0x00,0x8f,0x82,0xb4,0x38,0x00,0x00,0x00,0x00,0x90,0x42,0x00,0x0a, +0x00,0x00,0x00,0x00,0x00,0x02,0x18,0x2b,0x08,0x00,0x0b,0x6a,0xae,0x43,0x00,0x3c, +0x8e,0x42,0x00,0x38,0x00,0x00,0x00,0x00,0x14,0x40,0xff,0x3d,0x24,0x02,0x00,0x12, +0x8f,0x82,0xb4,0x34,0x00,0x00,0x00,0x00,0x90,0x42,0x00,0x0a,0x00,0x00,0x00,0x00, +0x00,0x02,0x18,0x2b,0x08,0x00,0x0b,0x6a,0xae,0x43,0x00,0x38,0x8e,0x42,0x00,0x34, +0x00,0x00,0x00,0x00,0x14,0x40,0xff,0x30,0x24,0x02,0x00,0x11,0x8f,0x82,0xb4,0x30, +0x00,0x00,0x00,0x00,0x90,0x42,0x00,0x0a,0x00,0x00,0x00,0x00,0x00,0x02,0x18,0x2b, +0x08,0x00,0x0b,0x6a,0xae,0x43,0x00,0x34,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00, +0x27,0xbd,0xff,0xe0,0x34,0x63,0x00,0x20,0x24,0x42,0x30,0xf8,0x3c,0x08,0xb0,0x03, +0xaf,0xb1,0x00,0x14,0xac,0x62,0x00,0x00,0x35,0x08,0x01,0x00,0xaf,0xbf,0x00,0x18, +0xaf,0xb0,0x00,0x10,0x91,0x03,0x00,0x00,0x00,0xa0,0x48,0x21,0x24,0x11,0x00,0x0a, +0x2c,0xa5,0x00,0x04,0x24,0x02,0x00,0x10,0x00,0x45,0x88,0x0a,0x30,0x63,0x00,0x01, +0x00,0xc0,0x28,0x21,0x14,0x60,0x00,0x02,0x00,0x11,0x40,0x40,0x02,0x20,0x40,0x21, +0x84,0x83,0x00,0x0c,0x31,0x11,0x00,0xff,0x01,0x20,0x20,0x21,0x00,0x03,0x10,0xc0, +0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80,0x27,0x83,0x8f,0xf8,0x00,0x43,0x10,0x21, +0x84,0x43,0x00,0x04,0x24,0x06,0x00,0x0e,0x10,0xe0,0x00,0x06,0x02,0x23,0x80,0x21, +0x02,0x00,0x10,0x21,0x8f,0xbf,0x00,0x18,0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08, +0x27,0xbd,0x00,0x20,0x0c,0x00,0x08,0xdf,0x00,0x00,0x00,0x00,0x02,0x11,0x18,0x21, +0x08,0x00,0x0c,0x60,0x00,0x62,0x80,0x21,0x27,0xbd,0xff,0xd0,0xaf,0xbf,0x00,0x28, +0xaf,0xb4,0x00,0x20,0xaf,0xb3,0x00,0x1c,0xaf,0xb2,0x00,0x18,0xaf,0xb5,0x00,0x24, +0xaf,0xb1,0x00,0x14,0xaf,0xb0,0x00,0x10,0x84,0x82,0x00,0x0c,0x3c,0x06,0xb0,0x03, +0x34,0xc6,0x00,0x20,0x00,0x02,0x18,0xc0,0x00,0x62,0x18,0x21,0x00,0x03,0x18,0x80, +0x27,0x82,0x8f,0xf4,0x00,0x62,0x10,0x21,0x8c,0x55,0x00,0x18,0x3c,0x02,0x80,0x00, +0x24,0x42,0x31,0xa8,0xac,0xc2,0x00,0x00,0x8e,0xb0,0x00,0x08,0x27,0x82,0x8f,0xf8, +0x00,0x62,0x18,0x21,0x90,0x71,0x00,0x07,0x00,0x10,0x86,0x43,0x32,0x10,0x00,0x01, +0x00,0xa0,0x38,0x21,0x02,0x00,0x30,0x21,0x00,0xa0,0x98,0x21,0x02,0x20,0x28,0x21, +0x0c,0x00,0x0c,0x3e,0x00,0x80,0x90,0x21,0x02,0x20,0x20,0x21,0x02,0x00,0x28,0x21, +0x24,0x06,0x00,0x14,0x0c,0x00,0x08,0xdf,0x00,0x40,0xa0,0x21,0x86,0x43,0x00,0x0c, +0x3c,0x09,0xb0,0x09,0x3c,0x08,0xb0,0x09,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21, +0x00,0x02,0x10,0x80,0x27,0x83,0x90,0x00,0x00,0x43,0x10,0x21,0x80,0x43,0x00,0x06, +0x3c,0x07,0xb0,0x09,0x3c,0x05,0xb0,0x09,0x28,0x62,0x00,0x00,0x24,0x64,0x00,0x03, +0x00,0x82,0x18,0x0b,0x00,0x03,0x18,0x83,0x3c,0x02,0xb0,0x09,0x00,0x03,0x18,0x80, +0x34,0x42,0x01,0x02,0x35,0x29,0x01,0x10,0x35,0x08,0x01,0x14,0x34,0xe7,0x01,0x20, +0x34,0xa5,0x01,0x24,0xa4,0x54,0x00,0x00,0x12,0x60,0x00,0x11,0x02,0xa3,0xa8,0x21, +0x8e,0xa2,0x00,0x0c,0x8e,0xa3,0x00,0x08,0x00,0x02,0x14,0x00,0x00,0x03,0x1c,0x02, +0x00,0x43,0x10,0x21,0xad,0x22,0x00,0x00,0x8e,0xa3,0x00,0x0c,0x00,0x00,0x00,0x00, +0x00,0x03,0x1c,0x02,0xa5,0x03,0x00,0x00,0x8f,0xbf,0x00,0x28,0x7b,0xb4,0x01,0x3c, +0x7b,0xb2,0x00,0xfc,0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x30, +0x8e,0xa2,0x00,0x04,0x00,0x00,0x00,0x00,0xad,0x22,0x00,0x00,0x8e,0xa4,0x00,0x08, +0x00,0x00,0x00,0x00,0xa5,0x04,0x00,0x00,0x7a,0xa2,0x00,0x7c,0x00,0x00,0x00,0x00, +0x00,0x03,0x1c,0x00,0x00,0x02,0x14,0x02,0x00,0x62,0x18,0x21,0xac,0xe3,0x00,0x00, +0x8e,0xa2,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x02,0x14,0x02,0x08,0x00,0x0c,0xb2, +0xa4,0xa2,0x00,0x00,0x27,0xbd,0xff,0xe0,0xaf,0xb2,0x00,0x18,0xaf,0xb0,0x00,0x10, +0xaf,0xbf,0x00,0x1c,0xaf,0xb1,0x00,0x14,0x84,0x82,0x00,0x0c,0x00,0x80,0x90,0x21, +0x3c,0x05,0xb0,0x03,0x00,0x02,0x20,0xc0,0x00,0x82,0x20,0x21,0x00,0x04,0x20,0x80, +0x27,0x82,0x8f,0xf4,0x00,0x82,0x10,0x21,0x8c,0x51,0x00,0x18,0x3c,0x02,0x80,0x00, +0x34,0xa5,0x00,0x20,0x24,0x42,0x33,0x24,0x27,0x83,0x8f,0xf8,0xac,0xa2,0x00,0x00, +0x00,0x83,0x20,0x21,0x3c,0x02,0xb0,0x03,0x90,0x86,0x00,0x07,0x34,0x42,0x01,0x00, +0x8e,0x23,0x00,0x08,0x90,0x44,0x00,0x00,0x2c,0xc5,0x00,0x04,0x24,0x02,0x00,0x10, +0x24,0x10,0x00,0x0a,0x00,0x45,0x80,0x0a,0x00,0x03,0x1e,0x43,0x30,0x84,0x00,0x01, +0x30,0x65,0x00,0x01,0x14,0x80,0x00,0x02,0x00,0x10,0x10,0x40,0x02,0x00,0x10,0x21, +0x00,0xc0,0x20,0x21,0x24,0x06,0x00,0x20,0x0c,0x00,0x08,0xdf,0x30,0x50,0x00,0xff, +0x86,0x44,0x00,0x0c,0x27,0x85,0x90,0x00,0x3c,0x06,0xb0,0x09,0x00,0x04,0x18,0xc0, +0x00,0x64,0x18,0x21,0x00,0x03,0x18,0x80,0x00,0x65,0x18,0x21,0x80,0x64,0x00,0x06, +0x00,0x50,0x10,0x21,0x34,0xc6,0x01,0x02,0x24,0x85,0x00,0x03,0x28,0x83,0x00,0x00, +0x00,0xa3,0x20,0x0b,0x00,0x04,0x20,0x83,0x00,0x04,0x20,0x80,0xa4,0xc2,0x00,0x00, +0x02,0x24,0x20,0x21,0x8c,0x83,0x00,0x04,0x3c,0x02,0xb0,0x09,0x34,0x42,0x01,0x10, +0xac,0x43,0x00,0x00,0x8c,0x86,0x00,0x08,0x3c,0x02,0xb0,0x09,0x34,0x42,0x01,0x14, +0xa4,0x46,0x00,0x00,0x8c,0x85,0x00,0x0c,0x8c,0x82,0x00,0x08,0x3c,0x06,0xb0,0x09, +0x00,0x05,0x2c,0x00,0x00,0x02,0x14,0x02,0x00,0xa2,0x28,0x21,0x34,0xc6,0x01,0x20, +0xac,0xc5,0x00,0x00,0x8c,0x83,0x00,0x0c,0x3c,0x05,0xb0,0x09,0x34,0xa5,0x01,0x24, +0x00,0x03,0x1c,0x02,0xa4,0xa3,0x00,0x00,0x92,0x42,0x00,0x0a,0x3c,0x03,0xb0,0x09, +0x34,0x63,0x01,0x30,0x00,0x02,0x13,0x00,0x24,0x42,0x00,0x04,0x30,0x42,0xff,0xff, +0xa4,0x62,0x00,0x00,0x86,0x44,0x00,0x0c,0x27,0x83,0x90,0x08,0x8f,0xbf,0x00,0x1c, +0x00,0x04,0x10,0xc0,0x00,0x44,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21, +0x94,0x44,0x00,0x02,0x8f,0xb2,0x00,0x18,0x7b,0xb0,0x00,0xbc,0x3c,0x05,0xb0,0x09, +0x34,0xa5,0x01,0x32,0xa4,0xa4,0x00,0x00,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20, +0x27,0xbd,0xff,0xe0,0x3c,0x02,0xb0,0x03,0x3c,0x03,0x80,0x00,0xaf,0xb0,0x00,0x10, +0x34,0x42,0x00,0x20,0x00,0xa0,0x80,0x21,0x24,0x63,0x34,0xb0,0x00,0x05,0x2c,0x43, +0xaf,0xb1,0x00,0x14,0xaf,0xbf,0x00,0x18,0xac,0x43,0x00,0x00,0x10,0xa0,0x00,0x05, +0x00,0x80,0x88,0x21,0x8c,0x82,0x00,0x34,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0xb6, +0x00,0x00,0x00,0x00,0x32,0x10,0x00,0xff,0x12,0x00,0x00,0x4c,0x00,0x00,0x10,0x21, +0x24,0x02,0x00,0x08,0x12,0x02,0x00,0xa3,0x2a,0x02,0x00,0x09,0x10,0x40,0x00,0x89, +0x24,0x02,0x00,0x40,0x24,0x04,0x00,0x02,0x12,0x04,0x00,0x79,0x2a,0x02,0x00,0x03, +0x10,0x40,0x00,0x69,0x24,0x02,0x00,0x04,0x24,0x02,0x00,0x01,0x12,0x02,0x00,0x5a, +0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x05,0x34,0x42,0x00,0x08,0x3c,0x03,0x80,0x00, +0xa2,0x20,0x00,0x4e,0xac,0x43,0x00,0x00,0x82,0x24,0x00,0x11,0x92,0x27,0x00,0x11, +0x10,0x80,0x00,0x4e,0x00,0x00,0x00,0x00,0x92,0x26,0x00,0x0a,0x24,0x02,0x00,0x12, +0x10,0x46,0x00,0x09,0x30,0xc2,0x00,0xff,0x27,0x83,0xb3,0xf0,0x00,0x02,0x10,0x80, +0x00,0x43,0x10,0x21,0x8c,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x83,0x00,0x14, +0x00,0x00,0x00,0x00,0xa6,0x23,0x00,0x0c,0x3c,0x02,0xb0,0x09,0x34,0x42,0x00,0x40, +0x90,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x63,0x00,0x03,0xa2,0x23,0x00,0x10, +0x14,0x60,0x00,0x2b,0x30,0x65,0x00,0x01,0x30,0xc2,0x00,0xff,0x27,0x83,0xb3,0xf0, +0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21,0x8c,0x44,0x00,0x00,0x82,0x23,0x00,0x12, +0x90,0x82,0x00,0x16,0x00,0x00,0x00,0x00,0x00,0x02,0x11,0x42,0x30,0x42,0x00,0x01, +0x00,0x62,0x18,0x21,0x00,0x03,0x26,0x00,0x14,0x80,0x00,0x18,0xa2,0x23,0x00,0x12, +0x00,0x07,0x16,0x00,0x14,0x40,0x00,0x11,0x24,0x02,0x00,0x01,0x96,0x23,0x00,0x0c, +0x27,0x84,0x90,0x00,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80, +0x00,0x44,0x10,0x21,0x80,0x45,0x00,0x06,0x00,0x03,0x1a,0x00,0x3c,0x02,0xb0,0x00, +0x00,0x65,0x18,0x21,0x00,0x62,0x18,0x21,0x90,0x64,0x00,0x00,0x90,0x62,0x00,0x04, +0xa2,0x20,0x00,0x15,0xa3,0x80,0x8b,0xc4,0x24,0x02,0x00,0x01,0x8f,0xbf,0x00,0x18, +0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20,0x0c,0x00,0x0c,0xc9, +0x02,0x20,0x20,0x21,0x92,0x27,0x00,0x11,0x08,0x00,0x0d,0x79,0x00,0x07,0x16,0x00, +0x0c,0x00,0x0c,0x6a,0x02,0x20,0x20,0x21,0x86,0x23,0x00,0x0c,0x27,0x84,0x8f,0xf8, +0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x44,0x20,0x21, +0x90,0x85,0x00,0x07,0x27,0x83,0x90,0x00,0x00,0x43,0x10,0x21,0xa2,0x25,0x00,0x13, +0x90,0x83,0x00,0x07,0x08,0x00,0x0d,0x91,0xa0,0x43,0x00,0x02,0x92,0x26,0x00,0x0a, +0x08,0x00,0x0d,0x5a,0x30,0xc2,0x00,0xff,0x8e,0x22,0x00,0x24,0x00,0x00,0x00,0x00, +0x10,0x50,0x00,0x07,0xa2,0x20,0x00,0x08,0x24,0x02,0x00,0x07,0xa2,0x22,0x00,0x0a, +0x92,0x22,0x00,0x27,0xae,0x20,0x00,0x24,0x08,0x00,0x0d,0x4d,0xa2,0x22,0x00,0x04, +0x08,0x00,0x0d,0xab,0x24,0x02,0x00,0x06,0x16,0x02,0xff,0x9b,0x3c,0x02,0xb0,0x05, +0x8e,0x23,0x00,0x2c,0x24,0x02,0x00,0x01,0x10,0x62,0x00,0x07,0xa2,0x24,0x00,0x08, +0x24,0x02,0x00,0x03,0xa2,0x22,0x00,0x0a,0x92,0x22,0x00,0x2f,0xae,0x20,0x00,0x2c, +0x08,0x00,0x0d,0x4d,0xa2,0x22,0x00,0x06,0x08,0x00,0x0d,0xba,0xa2,0x20,0x00,0x0a, +0x8e,0x22,0x00,0x28,0x24,0x03,0x00,0x01,0x24,0x04,0x00,0x01,0x10,0x44,0x00,0x07, +0xa2,0x23,0x00,0x08,0x24,0x02,0x00,0x05,0xa2,0x22,0x00,0x0a,0x92,0x22,0x00,0x2b, +0xae,0x20,0x00,0x28,0x08,0x00,0x0d,0x4d,0xa2,0x22,0x00,0x05,0x08,0x00,0x0d,0xc6, +0x24,0x02,0x00,0x04,0x12,0x02,0x00,0x12,0x2a,0x02,0x00,0x41,0x10,0x40,0x00,0x09, +0x24,0x02,0x00,0x80,0x24,0x02,0x00,0x20,0x16,0x02,0xff,0x7b,0x3c,0x02,0xb0,0x05, +0x24,0x02,0x00,0x12,0xa2,0x22,0x00,0x0a,0xa2,0x22,0x00,0x08,0x08,0x00,0x0d,0x4d, +0xae,0x20,0x00,0x3c,0x16,0x02,0xff,0x74,0x3c,0x02,0xb0,0x05,0x24,0x02,0x00,0x10, +0xa2,0x22,0x00,0x0a,0xa2,0x22,0x00,0x08,0x08,0x00,0x0d,0x4d,0xae,0x20,0x00,0x34, +0x24,0x02,0x00,0x11,0xa2,0x22,0x00,0x0a,0xa2,0x22,0x00,0x08,0x08,0x00,0x0d,0x4d, +0xae,0x20,0x00,0x38,0x8e,0x24,0x00,0x30,0x24,0x02,0x00,0x03,0x24,0x03,0x00,0x01, +0x10,0x83,0x00,0x07,0xa2,0x22,0x00,0x08,0x24,0x02,0x00,0x02,0xa2,0x22,0x00,0x0a, +0x92,0x22,0x00,0x33,0xae,0x20,0x00,0x30,0x08,0x00,0x0d,0x4d,0xa2,0x22,0x00,0x07, +0x08,0x00,0x0d,0xec,0xa2,0x24,0x00,0x0a,0x8f,0x84,0xb4,0x30,0xae,0x20,0x00,0x34, +0x94,0x85,0x00,0x14,0x0c,0x00,0x1b,0x84,0x32,0x10,0x00,0xff,0x08,0x00,0x0d,0x3e, +0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x24,0x42,0x37,0xe4, +0x34,0x63,0x00,0x20,0xac,0x62,0x00,0x00,0x80,0xa2,0x00,0x15,0x3c,0x06,0xb0,0x05, +0x10,0x40,0x00,0x0a,0x34,0xc6,0x02,0x54,0x83,0x83,0x8b,0xc4,0x00,0x00,0x00,0x00, +0xac,0x83,0x00,0x24,0x8c,0xc2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x17,0x42, +0x30,0x42,0x00,0x01,0x03,0xe0,0x00,0x08,0xac,0x82,0x00,0x28,0x8c,0x82,0x00,0x2c, +0x3c,0x06,0xb0,0x05,0x34,0xc6,0x04,0x50,0x00,0x02,0x18,0x43,0x30,0x63,0x00,0x01, +0x10,0x40,0x00,0x04,0x30,0x45,0x00,0x01,0xac,0x83,0x00,0x28,0x03,0xe0,0x00,0x08, +0xac,0x85,0x00,0x24,0x90,0xc2,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xff, +0x30,0x43,0x00,0x02,0x30,0x42,0x00,0x01,0xac,0x83,0x00,0x28,0x03,0xe0,0x00,0x08, +0xac,0x82,0x00,0x24,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x27,0xbd,0xff,0xd8, +0x34,0x63,0x00,0x20,0x24,0x42,0x38,0x74,0xac,0x62,0x00,0x00,0xaf,0xb1,0x00,0x1c, +0xaf,0xbf,0x00,0x20,0xaf,0xb0,0x00,0x18,0x90,0xa6,0x00,0x0a,0x27,0x83,0xb3,0xf0, +0x00,0xa0,0x88,0x21,0x00,0x06,0x10,0x80,0x00,0x43,0x10,0x21,0x8c,0x50,0x00,0x00, +0x80,0xa5,0x00,0x11,0x92,0x03,0x00,0x12,0x10,0xa0,0x00,0x04,0xa2,0x20,0x00,0x15, +0x24,0x02,0x00,0x12,0x10,0xc2,0x00,0xda,0x00,0x00,0x00,0x00,0x82,0x22,0x00,0x12, +0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x67,0x00,0x00,0x00,0x00,0xa2,0x20,0x00,0x12, +0xa2,0x00,0x00,0x19,0x86,0x23,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x03,0x10,0xc0, +0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80,0x27,0x83,0x90,0x10,0x00,0x43,0x10,0x21, +0xa0,0x40,0x00,0x00,0x92,0x03,0x00,0x16,0x00,0x00,0x00,0x00,0x30,0x63,0x00,0xdf, +0xa2,0x03,0x00,0x16,0x82,0x02,0x00,0x12,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x20, +0x00,0x00,0x00,0x00,0x92,0x23,0x00,0x08,0x00,0x00,0x00,0x00,0x14,0x60,0x00,0x45, +0x24,0x02,0x00,0x01,0xa2,0x20,0x00,0x04,0x92,0x08,0x00,0x04,0x00,0x00,0x00,0x00, +0x15,0x00,0x00,0x1e,0x24,0x02,0x00,0x01,0x92,0x07,0x00,0x0a,0xa2,0x02,0x00,0x17, +0x92,0x02,0x00,0x16,0x30,0xe3,0x00,0xff,0x30,0x42,0x00,0xe4,0x10,0x60,0x00,0x03, +0xa2,0x02,0x00,0x16,0x34,0x42,0x00,0x01,0xa2,0x02,0x00,0x16,0x11,0x00,0x00,0x05, +0x00,0x00,0x00,0x00,0x92,0x02,0x00,0x16,0x00,0x00,0x00,0x00,0x34,0x42,0x00,0x02, +0xa2,0x02,0x00,0x16,0x92,0x02,0x00,0x17,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x08, +0x00,0x00,0x00,0x00,0x96,0x02,0x00,0x06,0x00,0x00,0x00,0x00,0xa6,0x02,0x00,0x14, +0x8f,0xbf,0x00,0x20,0x7b,0xb0,0x00,0xfc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x28, +0x96,0x02,0x00,0x00,0x08,0x00,0x0e,0x68,0xa6,0x02,0x00,0x14,0x92,0x07,0x00,0x0a, +0x00,0x00,0x00,0x00,0x14,0xe0,0x00,0x03,0x00,0x00,0x00,0x00,0x08,0x00,0x0e,0x54, +0xa2,0x00,0x00,0x17,0x96,0x04,0x00,0x00,0x96,0x05,0x00,0x06,0x27,0x86,0x8f,0xf0, +0x00,0x04,0x18,0xc0,0x00,0x64,0x18,0x21,0x00,0x05,0x10,0xc0,0x00,0x45,0x10,0x21, +0x00,0x03,0x18,0x80,0x00,0x66,0x18,0x21,0x00,0x02,0x10,0x80,0x00,0x46,0x10,0x21, +0x8c,0x66,0x00,0x08,0x8c,0x45,0x00,0x08,0x3c,0x03,0x80,0x00,0x00,0xc3,0x20,0x24, +0x10,0x80,0x00,0x08,0x00,0xa3,0x10,0x24,0x10,0x40,0x00,0x04,0x00,0x00,0x18,0x21, +0x10,0x80,0x00,0x02,0x24,0x03,0x00,0x01,0x00,0xa6,0x18,0x2b,0x08,0x00,0x0e,0x54, +0xa2,0x03,0x00,0x17,0x10,0x40,0xff,0xfd,0x00,0xa6,0x18,0x2b,0x08,0x00,0x0e,0x88, +0x00,0x00,0x00,0x00,0x10,0x62,0x00,0x09,0x24,0x02,0x00,0x02,0x10,0x62,0x00,0x05, +0x24,0x02,0x00,0x03,0x14,0x62,0xff,0xb8,0x00,0x00,0x00,0x00,0x08,0x00,0x0e,0x4e, +0xa2,0x20,0x00,0x07,0x08,0x00,0x0e,0x4e,0xa2,0x20,0x00,0x06,0x08,0x00,0x0e,0x4e, +0xa2,0x20,0x00,0x05,0x82,0x22,0x00,0x10,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x69, +0x2c,0x62,0x00,0x02,0x10,0x40,0x00,0x49,0x3c,0x02,0xb0,0x09,0x92,0x25,0x00,0x08, +0x00,0x00,0x00,0x00,0x30,0xa6,0x00,0xff,0x2c,0xc2,0x00,0x04,0x10,0x40,0x00,0x3b, +0x2c,0xc2,0x00,0x10,0x3c,0x04,0xb0,0x05,0x34,0x84,0x02,0x29,0x90,0x83,0x00,0x00, +0x24,0x02,0x00,0x01,0x00,0xc2,0x10,0x04,0x00,0x02,0x10,0x27,0x00,0x62,0x18,0x24, +0xa0,0x83,0x00,0x00,0x86,0x23,0x00,0x0c,0x96,0x26,0x00,0x0c,0x00,0x03,0x10,0xc0, +0x00,0x43,0x10,0x21,0x00,0x02,0x28,0x80,0x27,0x83,0x8f,0xf4,0x00,0xa3,0x18,0x21, +0x8c,0x64,0x00,0x18,0x00,0x00,0x00,0x00,0x8c,0x82,0x00,0x04,0x00,0x00,0x00,0x00, +0x30,0x42,0x00,0x10,0x10,0x40,0x00,0x18,0x24,0x07,0x00,0x01,0x93,0x82,0x8b,0x61, +0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x01,0x14,0x40,0x00,0x0a,0x24,0x05,0x00,0x24, +0x00,0x06,0x2c,0x00,0x00,0x05,0x2c,0x03,0x0c,0x00,0x1b,0x84,0x02,0x00,0x20,0x21, +0x92,0x02,0x00,0x16,0xa2,0x00,0x00,0x12,0x30,0x42,0x00,0xe7,0x08,0x00,0x0e,0x45, +0xa2,0x02,0x00,0x16,0xf0,0xc5,0x00,0x06,0x00,0x00,0x28,0x12,0x27,0x82,0x8f,0xf0, +0x00,0xa2,0x28,0x21,0x0c,0x00,0x01,0x4b,0x3c,0x04,0x00,0x80,0x96,0x26,0x00,0x0c, +0x08,0x00,0x0e,0xc5,0x00,0x06,0x2c,0x00,0x27,0x83,0x90,0x00,0x27,0x82,0x90,0x08, +0x00,0xa2,0x10,0x21,0x00,0xa3,0x18,0x21,0x90,0x44,0x00,0x00,0x90,0x65,0x00,0x05, +0x93,0x82,0x80,0x10,0x00,0x00,0x30,0x21,0x0c,0x00,0x21,0xf5,0xaf,0xa2,0x00,0x10, +0x96,0x26,0x00,0x0c,0x08,0x00,0x0e,0xbf,0x00,0x00,0x00,0x00,0x14,0x40,0xff,0xcd, +0x3c,0x04,0xb0,0x05,0x34,0x84,0x02,0x29,0x90,0x83,0x00,0x00,0x30,0xa5,0x00,0x0f, +0x24,0x02,0x00,0x80,0x08,0x00,0x0e,0xae,0x00,0xa2,0x10,0x07,0x86,0x26,0x00,0x0c, +0x3c,0x03,0xb0,0x09,0x34,0x42,0x01,0x72,0x34,0x63,0x01,0x78,0x94,0x47,0x00,0x00, +0x8c,0x65,0x00,0x00,0x00,0x06,0x10,0xc0,0x00,0x46,0x10,0x21,0x3c,0x04,0xb0,0x09, +0xae,0x25,0x00,0x1c,0x34,0x84,0x01,0x7c,0x27,0x83,0x8f,0xf4,0x00,0x02,0x10,0x80, +0x8c,0x85,0x00,0x00,0x00,0x43,0x10,0x21,0x8c,0x43,0x00,0x18,0xae,0x25,0x00,0x20, +0xa6,0x27,0x00,0x18,0x8c,0x66,0x00,0x08,0x02,0x20,0x20,0x21,0x0c,0x00,0x0f,0x15, +0x00,0x00,0x28,0x21,0x86,0x25,0x00,0x18,0x8e,0x26,0x00,0x1c,0x8e,0x27,0x00,0x20, +0x02,0x20,0x20,0x21,0x0c,0x00,0x1c,0x86,0xaf,0xa2,0x00,0x10,0x08,0x00,0x0e,0x45, +0xa2,0x02,0x00,0x12,0x92,0x22,0x00,0x08,0x08,0x00,0x0e,0x45,0xa2,0x22,0x00,0x09, +0xa2,0x20,0x00,0x11,0x80,0x82,0x00,0x50,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x03, +0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0xd0,0xac,0x40,0x00,0x00,0x08,0x00,0x0e,0x45, +0xa0,0x80,0x00,0x50,0x94,0x8a,0x00,0x0c,0x24,0x03,0x00,0x24,0x00,0x80,0x70,0x21, +0x3c,0x02,0x80,0x00,0x3c,0x04,0xb0,0x03,0x24,0x42,0x3c,0x54,0xf1,0x43,0x00,0x06, +0x34,0x84,0x00,0x20,0x00,0x00,0x18,0x12,0x00,0xa0,0x68,0x21,0xac,0x82,0x00,0x00, +0x27,0x85,0x90,0x00,0x27,0x82,0x8f,0xff,0x27,0xbd,0xff,0xf8,0x00,0x62,0x60,0x21, +0x00,0x65,0x58,0x21,0x00,0x00,0xc0,0x21,0x11,0xa0,0x00,0xcc,0x00,0x00,0x78,0x21, +0x00,0x0a,0x1c,0x00,0x00,0x03,0x1c,0x03,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21, +0x00,0x02,0x10,0x80,0x00,0x45,0x10,0x21,0x91,0x87,0x00,0x00,0x80,0x48,0x00,0x04, +0x03,0xa0,0x60,0x21,0x00,0x0a,0x1c,0x00,0x00,0x03,0x1c,0x03,0x00,0x03,0x10,0xc0, +0x00,0x43,0x10,0x21,0x00,0x02,0x48,0x80,0x27,0x83,0x8f,0xf4,0xa3,0xa7,0x00,0x00, +0x01,0x23,0x18,0x21,0x8c,0x64,0x00,0x18,0x25,0x02,0xff,0xff,0x00,0x48,0x40,0x0b, +0x8c,0x83,0x00,0x04,0x2d,0x05,0x00,0x07,0x24,0x02,0x00,0x06,0x30,0x63,0x00,0x08, +0x14,0x60,0x00,0x35,0x00,0x45,0x40,0x0a,0x93,0xa7,0x00,0x00,0x27,0x82,0x90,0x08, +0x01,0x22,0x10,0x21,0x30,0xe3,0x00,0xf0,0x38,0x63,0x00,0x50,0x30,0xe5,0x00,0xff, +0x00,0x05,0x20,0x2b,0x00,0x03,0x18,0x2b,0x00,0x64,0x18,0x24,0x90,0x49,0x00,0x00, +0x10,0x60,0x00,0x16,0x30,0xe4,0x00,0x0f,0x24,0x02,0x00,0x04,0x10,0xa2,0x00,0x9d, +0x00,0x00,0x00,0x00,0x11,0xa0,0x00,0x3a,0x2c,0xa2,0x00,0x0c,0x10,0x40,0x00,0x02, +0x24,0x84,0x00,0x0c,0x00,0xe0,0x20,0x21,0x30,0x84,0x00,0xff,0x00,0x04,0x10,0x40, +0x27,0x83,0xbb,0x0c,0x00,0x44,0x10,0x21,0x00,0x43,0x10,0x21,0x90,0x47,0x00,0x00, +0x00,0x00,0x00,0x00,0x2c,0xe3,0x00,0x0c,0xa3,0xa7,0x00,0x00,0x10,0x60,0x00,0x02, +0x24,0xe2,0x00,0x04,0x00,0xe0,0x10,0x21,0xa3,0xa2,0x00,0x00,0x91,0x65,0x00,0x00, +0x91,0x82,0x00,0x00,0x30,0xa3,0x00,0xff,0x00,0x62,0x10,0x2b,0x10,0x40,0x00,0x0e, +0x2c,0x62,0x00,0x0c,0x14,0x40,0x00,0x03,0x00,0x60,0x20,0x21,0x30,0xa2,0x00,0x0f, +0x24,0x44,0x00,0x0c,0x00,0x04,0x10,0x40,0x00,0x44,0x20,0x21,0x27,0x83,0xbb,0x0c, +0x00,0x83,0x18,0x21,0x90,0x62,0x00,0x02,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x05, +0x00,0x09,0x11,0x00,0xa1,0x85,0x00,0x00,0x93,0xa2,0x00,0x00,0x03,0xe0,0x00,0x08, +0x27,0xbd,0x00,0x08,0x00,0x49,0x10,0x23,0x00,0x02,0x10,0x80,0x00,0x49,0x10,0x23, +0x00,0x02,0x10,0x80,0x00,0x44,0x10,0x21,0x27,0x83,0xb4,0x98,0x00,0x43,0x10,0x21, +0x90,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x2c,0x83,0x00,0x0c,0x14,0x60,0x00,0x06, +0x00,0x80,0x10,0x21,0x00,0x18,0x10,0x40,0x00,0x4f,0x10,0x21,0x00,0x02,0x11,0x00, +0x00,0x82,0x10,0x21,0x24,0x42,0x00,0x04,0x08,0x00,0x0f,0x76,0xa1,0x82,0x00,0x00, +0x8f,0x8d,0x81,0x5c,0x00,0x00,0x00,0x00,0x01,0xa8,0x10,0x21,0x90,0x43,0x00,0x00, +0x00,0x00,0x00,0x00,0x10,0x60,0xff,0xd1,0x00,0x00,0x28,0x21,0x00,0x06,0x74,0x82, +0x30,0xe2,0x00,0xff,0x2c,0x42,0x00,0x0c,0x14,0x40,0x00,0x03,0x00,0xe0,0x10,0x21, +0x30,0xe2,0x00,0x0f,0x24,0x42,0x00,0x0c,0x30,0x44,0x00,0xff,0xa3,0xa2,0x00,0x00, +0x24,0x02,0x00,0x0c,0x10,0x82,0x00,0x0d,0x00,0x09,0x11,0x00,0x00,0x49,0x10,0x23, +0x00,0x02,0x10,0x80,0x00,0x04,0x18,0x40,0x00,0x49,0x10,0x23,0x00,0x64,0x18,0x21, +0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21,0x27,0x84,0xb4,0x98,0x00,0x44,0x10,0x21, +0x90,0x47,0x00,0x00,0x00,0x00,0x00,0x00,0xa3,0xa7,0x00,0x00,0x00,0x0a,0x1c,0x00, +0x00,0x03,0x1c,0x03,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80, +0x27,0x83,0x8f,0xf4,0x00,0x43,0x10,0x21,0x8c,0x44,0x00,0x18,0x00,0x00,0x00,0x00, +0x8c,0x83,0x00,0x04,0x00,0x00,0x00,0x00,0x30,0x63,0x00,0x10,0x14,0x60,0x00,0x33, +0x00,0x06,0x14,0x42,0x00,0x09,0x11,0x00,0x00,0x49,0x10,0x23,0x00,0x02,0x10,0x80, +0x00,0x49,0x10,0x23,0x27,0x83,0xb5,0x68,0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21, +0x90,0x44,0x00,0x04,0x90,0x43,0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x64,0xc0,0x24, +0x93,0xa7,0x00,0x00,0x00,0x00,0x00,0x00,0x2c,0xe2,0x00,0x0f,0x10,0x40,0x00,0x0f, +0x31,0xcf,0x00,0x01,0x00,0x0a,0x1c,0x00,0x00,0x03,0x1c,0x03,0x00,0x03,0x10,0xc0, +0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80,0x27,0x84,0x8f,0xf0,0x00,0x44,0x10,0x21, +0x84,0x43,0x00,0x06,0x00,0x00,0x00,0x00,0x28,0x63,0x06,0x41,0x14,0x60,0x00,0x04, +0x30,0xe2,0x00,0xff,0x24,0x07,0x00,0x0f,0xa3,0xa7,0x00,0x00,0x30,0xe2,0x00,0xff, +0x2c,0x42,0x00,0x0c,0x14,0x40,0x00,0x06,0x00,0xe0,0x10,0x21,0x00,0x18,0x10,0x40, +0x00,0x4f,0x10,0x21,0x00,0x02,0x11,0x00,0x00,0x47,0x10,0x21,0x24,0x42,0x00,0x04, +0xa3,0xa2,0x00,0x00,0x00,0x40,0x38,0x21,0x01,0xa8,0x10,0x21,0x90,0x43,0x00,0x00, +0x24,0xa4,0x00,0x01,0x30,0x85,0xff,0xff,0x00,0xa3,0x18,0x2b,0x14,0x60,0xff,0xad, +0x30,0xe2,0x00,0xff,0x08,0x00,0x0f,0x63,0x00,0x00,0x00,0x00,0x08,0x00,0x0f,0xc4, +0x30,0x58,0x00,0x01,0x81,0xc2,0x00,0x48,0x00,0x00,0x00,0x00,0x10,0x40,0xff,0x73, +0x00,0x00,0x00,0x00,0x08,0x00,0x0f,0x51,0x00,0x00,0x00,0x00,0x00,0x0a,0x1c,0x00, +0x00,0x03,0x1c,0x03,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80, +0x00,0x45,0x10,0x21,0x80,0x48,0x00,0x05,0x91,0x67,0x00,0x00,0x08,0x00,0x0f,0x31, +0x03,0xa0,0x58,0x21,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x34,0x63,0x00,0x20, +0x24,0x42,0x3f,0xf4,0x03,0xe0,0x00,0x08,0xac,0x62,0x00,0x00,0x27,0xbd,0xff,0xc0, +0xaf,0xb7,0x00,0x34,0xaf,0xb6,0x00,0x30,0xaf,0xb5,0x00,0x2c,0xaf,0xb4,0x00,0x28, +0xaf,0xb3,0x00,0x24,0xaf,0xb2,0x00,0x20,0xaf,0xbf,0x00,0x3c,0xaf,0xbe,0x00,0x38, +0xaf,0xb1,0x00,0x1c,0xaf,0xb0,0x00,0x18,0x84,0x82,0x00,0x0c,0x27,0x93,0x8f,0xf4, +0x3c,0x05,0xb0,0x03,0x00,0x02,0x18,0xc0,0x00,0x62,0x18,0x21,0x00,0x03,0x18,0x80, +0x00,0x73,0x10,0x21,0x8c,0x5e,0x00,0x18,0x3c,0x02,0x80,0x00,0x34,0xa5,0x00,0x20, +0x24,0x42,0x40,0x0c,0xac,0xa2,0x00,0x00,0x8f,0xd0,0x00,0x08,0x27,0x95,0x90,0x00, +0x00,0x75,0x18,0x21,0x00,0x00,0x28,0x21,0x02,0x00,0x30,0x21,0x90,0x71,0x00,0x00, +0x0c,0x00,0x0f,0x15,0x00,0x80,0xb0,0x21,0x00,0x40,0x90,0x21,0x00,0x10,0x14,0x42, +0x30,0x54,0x00,0x01,0x02,0x40,0x20,0x21,0x00,0x10,0x14,0x82,0x02,0x80,0x28,0x21, +0x12,0x51,0x00,0x23,0x00,0x10,0xbf,0xc2,0x86,0xc3,0x00,0x0c,0x30,0x50,0x00,0x01, +0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x55,0x10,0x21, +0xa0,0x52,0x00,0x00,0x86,0xc3,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x03,0x10,0xc0, +0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x53,0x30,0x21,0x8c,0xc7,0x00,0x18, +0x27,0x83,0x8f,0xf0,0x00,0x43,0x10,0x21,0x8c,0xe3,0x00,0x04,0x84,0x46,0x00,0x06, +0x00,0x03,0x19,0x42,0x0c,0x00,0x08,0xdf,0x30,0x73,0x00,0x01,0x00,0x40,0x88,0x21, +0x02,0x40,0x20,0x21,0x02,0x80,0x28,0x21,0x16,0xe0,0x00,0x10,0x02,0x00,0x30,0x21, +0x86,0xc2,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x02,0x18,0xc0,0x00,0x62,0x18,0x21, +0x00,0x03,0x18,0x80,0x27,0x82,0x8f,0xf8,0x00,0x62,0x18,0x21,0xa4,0x71,0x00,0x04, +0x7b,0xbe,0x01,0xfc,0x7b,0xb6,0x01,0xbc,0x7b,0xb4,0x01,0x7c,0x7b,0xb2,0x01,0x3c, +0x7b,0xb0,0x00,0xfc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x40,0x86,0xc3,0x00,0x0c, +0xaf,0xb3,0x00,0x10,0xaf,0xa0,0x00,0x14,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21, +0x00,0x02,0x10,0x80,0x00,0x55,0x10,0x21,0x80,0x47,0x00,0x06,0x00,0x00,0x00,0x00, +0x24,0xe7,0x00,0x02,0x00,0x07,0x17,0xc2,0x00,0xe2,0x38,0x21,0x00,0x07,0x38,0x43, +0x00,0x07,0x38,0x40,0x0c,0x00,0x09,0x06,0x03,0xc7,0x38,0x21,0x08,0x00,0x10,0x44, +0x02,0x22,0x88,0x21,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x27,0xbd,0xff,0xd0, +0x34,0x63,0x00,0x20,0x24,0x42,0x41,0x94,0xaf,0xb2,0x00,0x20,0xac,0x62,0x00,0x00, +0xaf,0xbf,0x00,0x28,0xaf,0xb3,0x00,0x24,0xaf,0xb1,0x00,0x1c,0xaf,0xb0,0x00,0x18, +0x3c,0x02,0xb0,0x03,0x90,0x83,0x00,0x0a,0x34,0x42,0x01,0x04,0x94,0x45,0x00,0x00, +0x00,0x03,0x18,0x80,0x27,0x82,0xb3,0xf0,0x00,0x62,0x18,0x21,0x30,0xa6,0xff,0xff, +0x8c,0x71,0x00,0x00,0x80,0x85,0x00,0x12,0x30,0xc9,0x00,0xff,0x00,0x06,0x32,0x02, +0xa4,0x86,0x00,0x44,0xa4,0x89,0x00,0x46,0x82,0x22,0x00,0x12,0x00,0x80,0x90,0x21, +0x10,0xa0,0x00,0x1b,0xa0,0x80,0x00,0x15,0x00,0xc5,0x10,0x2a,0x10,0x40,0x00,0x14, +0x00,0x00,0x00,0x00,0xa2,0x20,0x00,0x19,0x84,0x83,0x00,0x0c,0x00,0x00,0x00,0x00, +0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80,0x27,0x83,0x90,0x10, +0x00,0x43,0x10,0x21,0xa0,0x40,0x00,0x00,0xa0,0x80,0x00,0x12,0x92,0x22,0x00,0x16, +0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xdf,0xa2,0x22,0x00,0x16,0x8f,0xbf,0x00,0x28, +0x7b,0xb2,0x01,0x3c,0x7b,0xb0,0x00,0xfc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x30, +0x0c,0x00,0x0f,0xfd,0x00,0x00,0x00,0x00,0x08,0x00,0x10,0x93,0x00,0x00,0x00,0x00, +0x28,0x42,0x00,0x02,0x10,0x40,0x01,0x76,0x00,0x00,0x28,0x21,0x94,0x87,0x00,0x0c, +0x00,0x00,0x00,0x00,0x00,0xe0,0x10,0x21,0x00,0x02,0x14,0x00,0x00,0x02,0x14,0x03, +0x00,0x07,0x24,0x00,0x00,0x04,0x24,0x03,0x00,0x02,0x18,0xc0,0x00,0x62,0x18,0x21, +0x00,0x04,0x28,0xc0,0x00,0xa4,0x28,0x21,0x27,0x82,0x90,0x10,0x00,0x03,0x18,0x80, +0x00,0x62,0x18,0x21,0x00,0x05,0x28,0x80,0x27,0x82,0x8f,0xf8,0x00,0xa2,0x10,0x21, +0x8c,0x68,0x00,0x00,0x80,0x44,0x00,0x06,0x27,0x82,0x90,0x00,0x00,0x08,0x1d,0x02, +0x00,0xa2,0x28,0x21,0x38,0x84,0x00,0x00,0x30,0x63,0x00,0x01,0x01,0x24,0x30,0x0b, +0x80,0xaa,0x00,0x04,0x80,0xa9,0x00,0x05,0x10,0x60,0x00,0x02,0x00,0x08,0x14,0x02, +0x30,0x46,0x00,0x0f,0x15,0x20,0x00,0x28,0x01,0x49,0x10,0x21,0x15,0x40,0x00,0x11, +0x30,0xe3,0xff,0xff,0x92,0x45,0x00,0x08,0x00,0x00,0x00,0x00,0x30,0xa8,0x00,0xff, +0x2d,0x02,0x00,0x04,0x10,0x40,0x01,0x46,0x2d,0x02,0x00,0x10,0x3c,0x04,0xb0,0x05, +0x34,0x84,0x02,0x29,0x90,0x83,0x00,0x00,0x24,0x02,0x00,0x01,0x01,0x02,0x10,0x04, +0x00,0x62,0x18,0x25,0xa0,0x83,0x00,0x00,0x96,0x47,0x00,0x0c,0x00,0x00,0x00,0x00, +0x30,0xe3,0xff,0xff,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x27,0x84,0x90,0x00, +0x00,0x02,0x10,0x80,0x00,0x44,0x10,0x21,0x80,0x45,0x00,0x06,0x00,0x03,0x1a,0x00, +0x3c,0x04,0xb0,0x00,0x00,0x65,0x18,0x21,0x00,0x64,0x20,0x21,0x94,0x82,0x00,0x00, +0x82,0x43,0x00,0x10,0x00,0x02,0x14,0x00,0x14,0x60,0x00,0x06,0x00,0x02,0x3c,0x03, +0x30,0xe2,0x00,0x04,0x14,0x40,0x00,0x04,0x01,0x49,0x10,0x21,0x34,0xe2,0x08,0x00, +0xa4,0x82,0x00,0x00,0x01,0x49,0x10,0x21,0x00,0x02,0x16,0x00,0x00,0x02,0x16,0x03, +0x00,0x46,0x10,0x2a,0x10,0x40,0x00,0x7c,0x00,0x00,0x00,0x00,0x82,0x42,0x00,0x10, +0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x0e,0x00,0x00,0x00,0x00,0x86,0x43,0x00,0x0c, +0x25,0x44,0x00,0x01,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80, +0x27,0x83,0x90,0x00,0x00,0x43,0x10,0x21,0xa0,0x44,0x00,0x04,0x92,0x23,0x00,0x16, +0x02,0x40,0x20,0x21,0x30,0x63,0x00,0xfb,0x08,0x00,0x10,0x98,0xa2,0x23,0x00,0x16, +0x86,0x43,0x00,0x0c,0x25,0x24,0x00,0x01,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21, +0x00,0x02,0x10,0x80,0x27,0x83,0x90,0x00,0x00,0x43,0x10,0x21,0xa0,0x44,0x00,0x05, +0x86,0x45,0x00,0x0c,0x0c,0x00,0x1f,0x08,0x02,0x20,0x20,0x21,0x10,0x40,0x00,0x5a, +0x00,0x00,0x00,0x00,0x92,0x45,0x00,0x08,0x00,0x00,0x00,0x00,0x30,0xa6,0x00,0xff, +0x2c,0xc2,0x00,0x04,0x10,0x40,0x00,0x4c,0x2c,0xc2,0x00,0x10,0x3c,0x04,0xb0,0x05, +0x34,0x84,0x02,0x29,0x90,0x83,0x00,0x00,0x24,0x02,0x00,0x01,0x00,0xc2,0x10,0x04, +0x00,0x02,0x10,0x27,0x00,0x62,0x18,0x24,0xa0,0x83,0x00,0x00,0x92,0x45,0x00,0x08, +0x00,0x00,0x00,0x00,0x30,0xa5,0x00,0xff,0x14,0xa0,0x00,0x33,0x24,0x02,0x00,0x01, +0xa2,0x40,0x00,0x04,0x92,0x22,0x00,0x04,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x0c, +0x24,0x02,0x00,0x01,0xa2,0x22,0x00,0x17,0x92,0x22,0x00,0x17,0x00,0x00,0x00,0x00, +0x10,0x40,0x00,0x04,0x00,0x00,0x00,0x00,0x96,0x22,0x00,0x06,0x08,0x00,0x10,0x93, +0xa6,0x22,0x00,0x14,0x96,0x22,0x00,0x00,0x08,0x00,0x10,0x93,0xa6,0x22,0x00,0x14, +0x92,0x22,0x00,0x0a,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x03,0x00,0x00,0x00,0x00, +0x08,0x00,0x11,0x22,0xa2,0x20,0x00,0x17,0x96,0x24,0x00,0x00,0x96,0x25,0x00,0x06, +0x27,0x86,0x8f,0xf0,0x00,0x04,0x18,0xc0,0x00,0x64,0x18,0x21,0x00,0x05,0x10,0xc0, +0x00,0x45,0x10,0x21,0x00,0x03,0x18,0x80,0x00,0x66,0x18,0x21,0x00,0x02,0x10,0x80, +0x00,0x46,0x10,0x21,0x8c,0x65,0x00,0x08,0x8c,0x44,0x00,0x08,0x3c,0x03,0x80,0x00, +0x00,0xa3,0x30,0x24,0x10,0xc0,0x00,0x08,0x00,0x83,0x10,0x24,0x10,0x40,0x00,0x04, +0x00,0x00,0x18,0x21,0x10,0xc0,0x00,0x02,0x24,0x03,0x00,0x01,0x00,0x85,0x18,0x2b, +0x08,0x00,0x11,0x22,0xa2,0x23,0x00,0x17,0x10,0x40,0xff,0xfd,0x00,0x85,0x18,0x2b, +0x08,0x00,0x11,0x45,0x00,0x00,0x00,0x00,0x10,0xa2,0x00,0x09,0x24,0x02,0x00,0x02, +0x10,0xa2,0x00,0x05,0x24,0x02,0x00,0x03,0x14,0xa2,0xff,0xca,0x00,0x00,0x00,0x00, +0x08,0x00,0x11,0x1d,0xa2,0x40,0x00,0x07,0x08,0x00,0x11,0x1d,0xa2,0x40,0x00,0x06, +0x08,0x00,0x11,0x1d,0xa2,0x40,0x00,0x05,0x14,0x40,0xff,0xbe,0x3c,0x04,0xb0,0x05, +0x34,0x84,0x02,0x29,0x90,0x83,0x00,0x00,0x30,0xa5,0x00,0x0f,0x24,0x02,0x00,0x80, +0x08,0x00,0x11,0x14,0x00,0xa2,0x10,0x07,0x0c,0x00,0x10,0x03,0x02,0x40,0x20,0x21, +0x08,0x00,0x10,0x93,0x00,0x00,0x00,0x00,0x92,0x45,0x00,0x08,0x00,0x00,0x00,0x00, +0x30,0xa6,0x00,0xff,0x2c,0xc2,0x00,0x04,0x10,0x40,0x00,0x99,0x2c,0xc2,0x00,0x10, +0x3c,0x04,0xb0,0x05,0x34,0x84,0x02,0x29,0x90,0x83,0x00,0x00,0x24,0x02,0x00,0x01, +0x00,0xc2,0x10,0x04,0x00,0x02,0x10,0x27,0x00,0x62,0x18,0x24,0xa0,0x83,0x00,0x00, +0x92,0x45,0x00,0x08,0x00,0x00,0x00,0x00,0x30,0xa5,0x00,0xff,0x14,0xa0,0x00,0x80, +0x24,0x02,0x00,0x01,0xa2,0x40,0x00,0x04,0x86,0x43,0x00,0x0c,0x27,0x93,0x8f,0xf4, +0x96,0x47,0x00,0x0c,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x28,0x80, +0x00,0xb3,0x18,0x21,0x8c,0x64,0x00,0x18,0x00,0x00,0x00,0x00,0x8c,0x82,0x00,0x04, +0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x10,0x10,0x40,0x00,0x64,0x00,0x00,0x30,0x21, +0x00,0x07,0x1c,0x00,0x00,0x03,0x1c,0x03,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21, +0x00,0x02,0x10,0x80,0x00,0x53,0x10,0x21,0x8c,0x43,0x00,0x18,0x93,0x82,0x8b,0x61, +0x8c,0x64,0x00,0x04,0x30,0x42,0x00,0x01,0x00,0x04,0x21,0x42,0x14,0x40,0x00,0x4d, +0x30,0x90,0x00,0x01,0x00,0x07,0x2c,0x00,0x00,0x05,0x2c,0x03,0x0c,0x00,0x1b,0x84, +0x02,0x20,0x20,0x21,0x96,0x26,0x00,0x06,0x12,0x00,0x00,0x14,0x30,0xc5,0xff,0xff, +0x02,0x60,0x90,0x21,0x00,0x05,0x10,0xc0,0x00,0x45,0x10,0x21,0x00,0x02,0x10,0x80, +0x00,0x52,0x18,0x21,0x92,0x22,0x00,0x0a,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x0b, +0x02,0x20,0x20,0x21,0x8c,0x63,0x00,0x18,0x00,0x00,0x00,0x00,0x8c,0x62,0x00,0x04, +0x00,0x00,0x00,0x00,0x00,0x02,0x11,0x42,0x0c,0x00,0x1b,0x84,0x30,0x50,0x00,0x01, +0x96,0x26,0x00,0x06,0x16,0x00,0xff,0xef,0x30,0xc5,0xff,0xff,0x92,0x22,0x00,0x04, +0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x0d,0x24,0x02,0x00,0x01,0xa2,0x22,0x00,0x17, +0x92,0x22,0x00,0x17,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x05,0x00,0x00,0x00,0x00, +0xa6,0x26,0x00,0x14,0x92,0x22,0x00,0x16,0x08,0x00,0x10,0x92,0x30,0x42,0x00,0xc3, +0x96,0x22,0x00,0x00,0x08,0x00,0x11,0xb9,0xa6,0x22,0x00,0x14,0x92,0x22,0x00,0x0a, +0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x03,0x00,0x00,0x00,0x00,0x08,0x00,0x11,0xb4, +0xa2,0x20,0x00,0x17,0x96,0x24,0x00,0x00,0x30,0xc5,0xff,0xff,0x00,0x05,0x18,0xc0, +0x00,0x04,0x10,0xc0,0x00,0x44,0x10,0x21,0x00,0x65,0x18,0x21,0x27,0x84,0x8f,0xf0, +0x00,0x02,0x10,0x80,0x00,0x44,0x10,0x21,0x00,0x03,0x18,0x80,0x8c,0x45,0x00,0x08, +0x00,0x64,0x18,0x21,0x8c,0x64,0x00,0x08,0x3c,0x02,0x80,0x00,0x00,0xa2,0x38,0x24, +0x10,0xe0,0x00,0x08,0x00,0x82,0x10,0x24,0x10,0x40,0x00,0x04,0x00,0x00,0x18,0x21, +0x10,0xe0,0x00,0x02,0x24,0x03,0x00,0x01,0x00,0x85,0x18,0x2b,0x08,0x00,0x11,0xb4, +0xa2,0x23,0x00,0x17,0x10,0x40,0xff,0xfd,0x00,0x85,0x18,0x2b,0x08,0x00,0x11,0xd8, +0x00,0x00,0x00,0x00,0x24,0x05,0x00,0x24,0xf0,0xe5,0x00,0x06,0x00,0x00,0x28,0x12, +0x27,0x82,0x8f,0xf0,0x00,0xa2,0x28,0x21,0x0c,0x00,0x01,0x4b,0x00,0x00,0x20,0x21, +0x96,0x47,0x00,0x0c,0x08,0x00,0x11,0x96,0x00,0x07,0x2c,0x00,0x27,0x83,0x90,0x00, +0x27,0x82,0x90,0x08,0x00,0xa2,0x10,0x21,0x00,0xa3,0x18,0x21,0x90,0x44,0x00,0x00, +0x90,0x65,0x00,0x05,0x93,0x82,0x80,0x10,0x24,0x07,0x00,0x01,0x0c,0x00,0x21,0xf5, +0xaf,0xa2,0x00,0x10,0x96,0x47,0x00,0x0c,0x08,0x00,0x11,0x89,0x00,0x07,0x1c,0x00, +0x10,0xa2,0x00,0x09,0x24,0x02,0x00,0x02,0x10,0xa2,0x00,0x05,0x24,0x02,0x00,0x03, +0x14,0xa2,0xff,0x7d,0x00,0x00,0x00,0x00,0x08,0x00,0x11,0x7a,0xa2,0x40,0x00,0x07, +0x08,0x00,0x11,0x7a,0xa2,0x40,0x00,0x06,0x08,0x00,0x11,0x7a,0xa2,0x40,0x00,0x05, +0x14,0x40,0xff,0x71,0x3c,0x04,0xb0,0x05,0x34,0x84,0x02,0x29,0x90,0x83,0x00,0x00, +0x30,0xa5,0x00,0x0f,0x24,0x02,0x00,0x80,0x08,0x00,0x11,0x71,0x00,0xa2,0x10,0x07, +0x14,0x40,0xfe,0xc3,0x3c,0x04,0xb0,0x05,0x34,0x84,0x02,0x29,0x90,0x83,0x00,0x00, +0x30,0xa5,0x00,0x0f,0x24,0x02,0x00,0x80,0x08,0x00,0x10,0xcc,0x00,0xa2,0x10,0x07, +0x84,0x83,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21, +0x00,0x02,0x10,0x80,0x27,0x83,0x8f,0xf4,0x00,0x43,0x10,0x21,0x8c,0x47,0x00,0x18, +0x00,0x00,0x00,0x00,0x8c,0xe6,0x00,0x08,0x0c,0x00,0x0f,0x15,0x00,0x00,0x00,0x00, +0x02,0x40,0x20,0x21,0x00,0x00,0x28,0x21,0x00,0x00,0x30,0x21,0x00,0x00,0x38,0x21, +0x0c,0x00,0x1c,0x86,0xaf,0xa2,0x00,0x10,0x00,0x02,0x1e,0x00,0x14,0x60,0xfe,0x6b, +0xa2,0x22,0x00,0x12,0x92,0x43,0x00,0x08,0x00,0x00,0x00,0x00,0x14,0x60,0x00,0x40, +0x24,0x02,0x00,0x01,0xa2,0x40,0x00,0x04,0x92,0x28,0x00,0x04,0x00,0x00,0x00,0x00, +0x15,0x00,0x00,0x19,0x24,0x02,0x00,0x01,0x92,0x27,0x00,0x0a,0xa2,0x22,0x00,0x17, +0x92,0x22,0x00,0x17,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x10,0x00,0x00,0x00,0x00, +0x96,0x22,0x00,0x06,0x00,0x00,0x00,0x00,0xa6,0x22,0x00,0x14,0x92,0x22,0x00,0x16, +0x30,0xe3,0x00,0xff,0x30,0x42,0x00,0xc0,0x10,0x60,0x00,0x03,0xa2,0x22,0x00,0x16, +0x34,0x42,0x00,0x01,0xa2,0x22,0x00,0x16,0x11,0x00,0xfe,0x50,0x00,0x00,0x00,0x00, +0x92,0x22,0x00,0x16,0x08,0x00,0x10,0x92,0x34,0x42,0x00,0x02,0x96,0x22,0x00,0x00, +0x08,0x00,0x12,0x3b,0xa6,0x22,0x00,0x14,0x92,0x27,0x00,0x0a,0x00,0x00,0x00,0x00, +0x14,0xe0,0x00,0x03,0x00,0x00,0x00,0x00,0x08,0x00,0x12,0x34,0xa2,0x20,0x00,0x17, +0x96,0x24,0x00,0x00,0x96,0x25,0x00,0x06,0x27,0x86,0x8f,0xf0,0x00,0x04,0x18,0xc0, +0x00,0x64,0x18,0x21,0x00,0x05,0x10,0xc0,0x00,0x45,0x10,0x21,0x00,0x03,0x18,0x80, +0x00,0x66,0x18,0x21,0x00,0x02,0x10,0x80,0x00,0x46,0x10,0x21,0x8c,0x65,0x00,0x08, +0x8c,0x44,0x00,0x08,0x3c,0x03,0x80,0x00,0x00,0xa3,0x30,0x24,0x10,0xc0,0x00,0x08, +0x00,0x83,0x10,0x24,0x10,0x40,0x00,0x04,0x00,0x00,0x18,0x21,0x10,0xc0,0x00,0x02, +0x24,0x03,0x00,0x01,0x00,0x85,0x18,0x2b,0x08,0x00,0x12,0x34,0xa2,0x23,0x00,0x17, +0x10,0x40,0xff,0xfd,0x00,0x85,0x18,0x2b,0x08,0x00,0x12,0x63,0x00,0x00,0x00,0x00, +0x10,0x62,0x00,0x09,0x24,0x02,0x00,0x02,0x10,0x62,0x00,0x05,0x24,0x02,0x00,0x03, +0x14,0x62,0xff,0xbd,0x00,0x00,0x00,0x00,0x08,0x00,0x12,0x2e,0xa2,0x40,0x00,0x07, +0x08,0x00,0x12,0x2e,0xa2,0x40,0x00,0x06,0x08,0x00,0x12,0x2e,0xa2,0x40,0x00,0x05, +0x3c,0x02,0x80,0x00,0x00,0x82,0x30,0x24,0x10,0xc0,0x00,0x08,0x00,0xa2,0x18,0x24, +0x10,0x60,0x00,0x04,0x00,0x00,0x10,0x21,0x10,0xc0,0x00,0x02,0x24,0x02,0x00,0x01, +0x00,0xa4,0x10,0x2b,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x10,0x60,0xff,0xfd, +0x00,0xa4,0x10,0x2b,0x08,0x00,0x12,0x7e,0x00,0x00,0x00,0x00,0x30,0x82,0xff,0xff, +0x00,0x02,0x18,0xc0,0x00,0x62,0x18,0x21,0x27,0x84,0x90,0x00,0x00,0x03,0x18,0x80, +0x00,0x64,0x18,0x21,0x80,0x66,0x00,0x06,0x00,0x02,0x12,0x00,0x3c,0x03,0xb0,0x00, +0x00,0x46,0x10,0x21,0x00,0x45,0x10,0x21,0x03,0xe0,0x00,0x08,0x00,0x43,0x10,0x21, +0x27,0xbd,0xff,0xe0,0x30,0x82,0x00,0x7c,0x30,0x84,0xff,0x00,0xaf,0xbf,0x00,0x1c, +0xaf,0xb2,0x00,0x18,0xaf,0xb1,0x00,0x14,0xaf,0xb0,0x00,0x10,0x14,0x40,0x00,0x41, +0x00,0x04,0x22,0x03,0x24,0x02,0x00,0x04,0x3c,0x10,0xb0,0x03,0x8e,0x10,0x00,0x00, +0x10,0x82,0x00,0x32,0x24,0x02,0x00,0x08,0x10,0x82,0x00,0x03,0x32,0x02,0x00,0x20, +0x08,0x00,0x12,0xa4,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x17,0x3c,0x02,0xb0,0x06, +0x34,0x42,0x80,0x24,0x8c,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x67,0x00,0xff, +0x10,0xe0,0x00,0x23,0x00,0x00,0x88,0x21,0x8f,0x85,0x8f,0xd0,0x00,0x40,0x30,0x21, +0x94,0xa2,0x00,0x08,0x8c,0xc3,0x00,0x00,0x26,0x31,0x00,0x01,0x24,0x42,0x00,0x02, +0x30,0x42,0x01,0xff,0x34,0x63,0x01,0x00,0x02,0x27,0x20,0x2a,0xa4,0xa2,0x00,0x08, +0x14,0x80,0xff,0xf7,0xac,0xc3,0x00,0x00,0x84,0xa3,0x00,0x08,0x3c,0x02,0xb0,0x03, +0x34,0x42,0x00,0x30,0xac,0x43,0x00,0x00,0x27,0x92,0xb3,0xf0,0x24,0x11,0x00,0x12, +0x8e,0x44,0x00,0x00,0x26,0x31,0xff,0xff,0x90,0x82,0x00,0x10,0x00,0x00,0x00,0x00, +0x10,0x40,0x00,0x03,0x26,0x52,0x00,0x04,0x0c,0x00,0x20,0xd0,0x00,0x00,0x00,0x00, +0x06,0x21,0xff,0xf7,0x24,0x02,0xff,0xdf,0x02,0x02,0x80,0x24,0x3c,0x01,0xb0,0x03, +0x0c,0x00,0x13,0x18,0xac,0x30,0x00,0x00,0x08,0x00,0x12,0xa4,0x00,0x00,0x00,0x00, +0x8f,0x85,0x8f,0xd0,0x08,0x00,0x12,0xba,0x00,0x00,0x00,0x00,0x24,0x02,0xff,0x95, +0x3c,0x03,0xb0,0x03,0x02,0x02,0x80,0x24,0x34,0x63,0x00,0x30,0x3c,0x01,0xb0,0x03, +0xac,0x30,0x00,0x00,0x0c,0x00,0x12,0xe1,0xac,0x60,0x00,0x00,0x08,0x00,0x12,0xa4, +0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0x50,0x08,0x00,0x12,0xa4, +0xac,0x46,0x00,0x00,0x3c,0x0a,0x80,0x00,0x25,0x4a,0x4b,0x84,0x3c,0x0b,0xb0,0x03, +0xad,0x6a,0x00,0x20,0x3c,0x08,0x80,0x01,0x25,0x08,0x00,0x00,0x3c,0x09,0x80,0x01, +0x25,0x29,0x03,0x1c,0x11,0x09,0x00,0x10,0x00,0x00,0x00,0x00,0x3c,0x0a,0x80,0x00, +0x25,0x4a,0x4b,0xac,0x3c,0x0b,0xb0,0x03,0xad,0x6a,0x00,0x20,0x3c,0x08,0xb0,0x06, +0x35,0x08,0x80,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x8d,0x09,0x00,0x00, +0x00,0x00,0x00,0x00,0x31,0x29,0x00,0x01,0x00,0x00,0x00,0x00,0x24,0x01,0x00,0x01, +0x15,0x21,0xff,0xf2,0x00,0x00,0x00,0x00,0x3c,0x0a,0x80,0x00,0x25,0x4a,0x4b,0xe8, +0x3c,0x0b,0xb0,0x03,0xad,0x6a,0x00,0x20,0x3c,0x02,0xb0,0x03,0x8c,0x43,0x00,0x00, +0x00,0x00,0x00,0x00,0x34,0x63,0x00,0x40,0x00,0x00,0x00,0x00,0xac,0x43,0x00,0x00, +0x00,0x00,0x00,0x00,0x3c,0x0a,0x80,0x00,0x25,0x4a,0x4c,0x14,0x3c,0x0b,0xb0,0x03, +0xad,0x6a,0x00,0x20,0x3c,0x02,0x80,0x01,0x24,0x42,0x00,0x00,0x3c,0x03,0x80,0x01, +0x24,0x63,0x03,0x1c,0x3c,0x04,0xb0,0x00,0x8c,0x85,0x00,0x00,0x00,0x00,0x00,0x00, +0xac,0x45,0x00,0x00,0x24,0x42,0x00,0x04,0x24,0x84,0x00,0x04,0x00,0x43,0x08,0x2a, +0x14,0x20,0xff,0xf9,0x00,0x00,0x00,0x00,0x0c,0x00,0x13,0x18,0x00,0x00,0x00,0x00, +0x3c,0x0a,0x80,0x00,0x25,0x4a,0x4c,0x60,0x3c,0x0b,0xb0,0x03,0xad,0x6a,0x00,0x20, +0x3c,0x02,0x80,0x01,0x24,0x42,0x03,0x20,0x3c,0x03,0x80,0x01,0x24,0x63,0x3f,0x14, +0xac,0x40,0x00,0x00,0xac,0x40,0x00,0x04,0xac,0x40,0x00,0x08,0xac,0x40,0x00,0x0c, +0x24,0x42,0x00,0x10,0x00,0x43,0x08,0x2a,0x14,0x20,0xff,0xf9,0x00,0x00,0x00,0x00, +0x3c,0x0a,0x80,0x00,0x25,0x4a,0x4c,0xa0,0x3c,0x0b,0xb0,0x03,0xad,0x6a,0x00,0x20, +0x3c,0x1c,0x80,0x01,0x27,0x9c,0x7f,0xf0,0x27,0x9d,0x8b,0xd0,0x00,0x00,0x00,0x00, +0x27,0x9d,0x8f,0xb8,0x3c,0x0a,0x80,0x00,0x25,0x4a,0x4c,0xc4,0x3c,0x0b,0xb0,0x03, +0xad,0x6a,0x00,0x20,0x40,0x80,0x68,0x00,0x40,0x08,0x60,0x00,0x00,0x00,0x00,0x00, +0x35,0x08,0xff,0x01,0x40,0x88,0x60,0x00,0x00,0x00,0x00,0x00,0x0c,0x00,0x15,0x65, +0x00,0x00,0x00,0x00,0x24,0x84,0xf8,0x00,0x30,0x87,0x00,0x03,0x00,0x04,0x30,0x40, +0x00,0xc7,0x20,0x23,0x3c,0x02,0xb0,0x0a,0x27,0xbd,0xff,0xe0,0x24,0x03,0xff,0xff, +0x00,0x82,0x20,0x21,0xaf,0xb1,0x00,0x14,0xac,0x83,0x10,0x00,0xaf,0xbf,0x00,0x18, +0xaf,0xb0,0x00,0x10,0x00,0xa0,0x88,0x21,0x24,0x03,0x00,0x01,0x8c,0x82,0x10,0x00, +0x00,0x00,0x00,0x00,0x14,0x43,0xff,0xfd,0x00,0xc7,0x10,0x23,0x3c,0x03,0xb0,0x0a, +0x00,0x43,0x10,0x21,0x8c,0x50,0x00,0x00,0x0c,0x00,0x13,0x95,0x02,0x20,0x20,0x21, +0x02,0x11,0x80,0x24,0x00,0x50,0x80,0x06,0x02,0x00,0x10,0x21,0x8f,0xbf,0x00,0x18, +0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20,0x27,0xbd,0xff,0xd8, +0xaf,0xb2,0x00,0x18,0x00,0xa0,0x90,0x21,0x24,0x05,0xff,0xff,0xaf,0xb3,0x00,0x1c, +0xaf,0xbf,0x00,0x20,0xaf,0xb1,0x00,0x14,0xaf,0xb0,0x00,0x10,0x00,0xc0,0x98,0x21, +0x12,0x45,0x00,0x23,0x24,0x84,0xf8,0x00,0x30,0x83,0x00,0x03,0x00,0x04,0x10,0x40, +0x00,0x40,0x88,0x21,0x00,0x60,0x20,0x21,0x00,0x43,0x10,0x23,0x3c,0x03,0xb0,0x0a, +0x00,0x43,0x10,0x21,0xac,0x45,0x10,0x00,0x00,0x40,0x18,0x21,0x24,0x05,0x00,0x01, +0x8c,0x62,0x10,0x00,0x00,0x00,0x00,0x00,0x14,0x45,0xff,0xfd,0x3c,0x02,0xb0,0x0a, +0x02,0x24,0x88,0x23,0x02,0x22,0x88,0x21,0x8e,0x30,0x00,0x00,0x0c,0x00,0x13,0x95, +0x02,0x40,0x20,0x21,0x00,0x12,0x18,0x27,0x02,0x03,0x80,0x24,0x00,0x53,0x10,0x04, +0x02,0x02,0x80,0x25,0xae,0x30,0x00,0x00,0x24,0x03,0x00,0x01,0x8e,0x22,0x10,0x00, +0x00,0x00,0x00,0x00,0x14,0x43,0xff,0xfd,0x00,0x00,0x00,0x00,0x8f,0xbf,0x00,0x20, +0x7b,0xb2,0x00,0xfc,0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x28, +0x30,0x82,0x00,0x03,0x00,0x04,0x18,0x40,0x00,0x62,0x18,0x23,0x3c,0x04,0xb0,0x0a, +0x00,0x64,0x18,0x21,0xac,0x66,0x00,0x00,0x24,0x04,0x00,0x01,0x8c,0x62,0x10,0x00, +0x00,0x00,0x00,0x00,0x14,0x44,0xff,0xfd,0x00,0x00,0x00,0x00,0x08,0x00,0x13,0x83, +0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x21,0x00,0x64,0x10,0x06,0x30,0x42,0x00,0x01, +0x14,0x40,0x00,0x05,0x00,0x00,0x00,0x00,0x24,0x63,0x00,0x01,0x2c,0x62,0x00,0x20, +0x14,0x40,0xff,0xf9,0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x00,0x60,0x10,0x21, +0x27,0xbd,0xff,0xe0,0x3c,0x03,0xb0,0x05,0xaf,0xb2,0x00,0x18,0xaf,0xb1,0x00,0x14, +0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x1c,0x00,0x80,0x90,0x21,0x00,0xa0,0x80,0x21, +0x00,0xc0,0x88,0x21,0x34,0x63,0x02,0x2e,0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00, +0x30,0x42,0x00,0x01,0x14,0x40,0xff,0xfc,0x24,0x04,0x08,0x24,0x3c,0x05,0x00,0xc0, +0x0c,0x00,0x13,0x5b,0x24,0x06,0x00,0x03,0x24,0x04,0x08,0x34,0x3c,0x05,0x00,0xc0, +0x0c,0x00,0x13,0x5b,0x24,0x06,0x00,0x03,0x3c,0x02,0xc0,0x00,0x00,0x10,0x1c,0x00, +0x34,0x42,0x04,0x00,0x3c,0x04,0xb0,0x05,0x3c,0x05,0xb0,0x05,0x24,0x63,0x16,0x09, +0x02,0x22,0x10,0x21,0x34,0x84,0x04,0x20,0x34,0xa5,0x04,0x24,0x3c,0x06,0xb0,0x05, +0xac,0x83,0x00,0x00,0x24,0x07,0x00,0x01,0xac,0xa2,0x00,0x00,0x34,0xc6,0x02,0x28, +0x24,0x02,0x00,0x20,0xae,0x47,0x00,0x3c,0x24,0x04,0x08,0x24,0xa0,0xc2,0x00,0x00, +0x3c,0x05,0x00,0xc0,0xa2,0x47,0x00,0x11,0x0c,0x00,0x13,0x5b,0x24,0x06,0x00,0x01, +0x24,0x04,0x08,0x34,0x3c,0x05,0x00,0xc0,0x0c,0x00,0x13,0x5b,0x24,0x06,0x00,0x01, +0x8f,0xbf,0x00,0x1c,0x8f,0xb2,0x00,0x18,0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08, +0x27,0xbd,0x00,0x20,0x24,0x02,0x00,0x06,0xac,0x82,0x00,0x0c,0xa0,0x80,0x00,0x50, +0xac,0x80,0x00,0x00,0xac,0x80,0x00,0x04,0xac,0x80,0x00,0x08,0xac,0x80,0x00,0x14, +0xac,0x80,0x00,0x18,0xac,0x80,0x00,0x1c,0xa4,0x80,0x00,0x20,0xac,0x80,0x00,0x24, +0xac,0x80,0x00,0x28,0xac,0x80,0x00,0x2c,0xa0,0x80,0x00,0x30,0xa0,0x80,0x00,0x31, +0xac,0x80,0x00,0x34,0xac,0x80,0x00,0x38,0xa0,0x80,0x00,0x3c,0xac,0x82,0x00,0x10, +0xa0,0x80,0x00,0x44,0xac,0x80,0x00,0x48,0x03,0xe0,0x00,0x08,0xac,0x80,0x00,0x4c, +0x3c,0x04,0xb0,0x06,0x34,0x84,0x80,0x00,0x8c,0x83,0x00,0x00,0x3c,0x02,0x12,0x00, +0x3c,0x05,0xb0,0x03,0x00,0x62,0x18,0x25,0x34,0xa5,0x00,0x8b,0x24,0x02,0xff,0x80, +0xac,0x83,0x00,0x00,0x03,0xe0,0x00,0x08,0xa0,0xa2,0x00,0x00,0x3c,0x04,0xb0,0x03, +0x34,0x84,0x00,0x0b,0x24,0x02,0x00,0x22,0x3c,0x05,0xb0,0x01,0x3c,0x06,0x45,0x67, +0x3c,0x0a,0xb0,0x09,0xa0,0x82,0x00,0x00,0x34,0xa5,0x00,0x04,0x34,0xc6,0x89,0xaa, +0x35,0x4a,0x00,0x04,0x24,0x02,0x01,0x23,0x3c,0x0b,0xb0,0x09,0x3c,0x07,0x01,0x23, +0x3c,0x0c,0xb0,0x09,0x3c,0x01,0xb0,0x01,0xac,0x20,0x00,0x00,0x27,0xbd,0xff,0xe0, +0xac,0xa0,0x00,0x00,0x35,0x6b,0x00,0x08,0x3c,0x01,0xb0,0x09,0xac,0x26,0x00,0x00, +0x34,0xe7,0x45,0x66,0xa5,0x42,0x00,0x00,0x35,0x8c,0x00,0x0c,0x24,0x02,0xcd,0xef, +0x3c,0x0d,0xb0,0x09,0x3c,0x08,0xcd,0xef,0x3c,0x0e,0xb0,0x09,0xad,0x67,0x00,0x00, +0xaf,0xb7,0x00,0x1c,0xa5,0x82,0x00,0x00,0xaf,0xb6,0x00,0x18,0xaf,0xb5,0x00,0x14, +0xaf,0xb4,0x00,0x10,0xaf,0xb3,0x00,0x0c,0xaf,0xb2,0x00,0x08,0xaf,0xb1,0x00,0x04, +0xaf,0xb0,0x00,0x00,0x35,0xad,0x00,0x10,0x35,0x08,0x01,0x22,0x35,0xce,0x00,0x14, +0x24,0x02,0x89,0xab,0x3c,0x0f,0xb0,0x09,0x3c,0x09,0x89,0xab,0x3c,0x10,0xb0,0x09, +0x3c,0x11,0xb0,0x09,0x3c,0x12,0xb0,0x09,0x3c,0x13,0xb0,0x09,0x3c,0x14,0xb0,0x09, +0x3c,0x15,0xb0,0x09,0x3c,0x16,0xb0,0x09,0x3c,0x17,0xb0,0x09,0xad,0xa8,0x00,0x00, +0x24,0x03,0xff,0xff,0xa5,0xc2,0x00,0x00,0x35,0xef,0x00,0x18,0x35,0x29,0xcd,0xee, +0x36,0x10,0x00,0x1c,0x36,0x31,0x00,0x20,0x36,0x52,0x00,0x24,0x36,0x73,0x00,0x28, +0x36,0x94,0x00,0x2c,0x36,0xb5,0x00,0x30,0x36,0xd6,0x00,0x34,0x36,0xf7,0x00,0x38, +0x24,0x02,0x45,0x67,0xad,0xe9,0x00,0x00,0xa6,0x02,0x00,0x00,0xae,0x23,0x00,0x00, +0x8f,0xb0,0x00,0x00,0xa6,0x43,0x00,0x00,0x8f,0xb1,0x00,0x04,0xae,0x63,0x00,0x00, +0x8f,0xb2,0x00,0x08,0xa6,0x83,0x00,0x00,0x8f,0xb3,0x00,0x0c,0xae,0xa3,0x00,0x00, +0x8f,0xb4,0x00,0x10,0xa6,0xc3,0x00,0x00,0x8f,0xb5,0x00,0x14,0xae,0xe3,0x00,0x00, +0x7b,0xb6,0x00,0xfc,0x3c,0x18,0xb0,0x09,0x37,0x18,0x00,0x3c,0xa7,0x03,0x00,0x00, +0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00, +0x34,0x63,0x00,0x20,0x24,0x42,0x51,0x38,0xac,0x62,0x00,0x00,0x8c,0x83,0x00,0x34, +0x34,0x02,0xff,0xff,0x00,0x43,0x10,0x2a,0x14,0x40,0x01,0x0b,0x00,0x80,0x30,0x21, +0x8c,0x84,0x00,0x08,0x24,0x02,0x00,0x03,0x10,0x82,0x00,0xfe,0x00,0x00,0x00,0x00, +0x8c,0xc2,0x00,0x2c,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x47,0x24,0x02,0x00,0x06, +0x3c,0x03,0xb0,0x05,0x34,0x63,0x04,0x50,0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00, +0x30,0x42,0x00,0xff,0x14,0x40,0x00,0xe4,0xac,0xc2,0x00,0x2c,0x24,0x02,0x00,0x01, +0x10,0x82,0x00,0xe3,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0x10,0x82,0x00,0xd1, +0x00,0x00,0x00,0x00,0x8c,0xc7,0x00,0x04,0x24,0x02,0x00,0x02,0x10,0xe2,0x00,0xc7, +0x00,0x00,0x00,0x00,0x8c,0xc2,0x00,0x14,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x09, +0x24,0x02,0x00,0x01,0x3c,0x03,0xb0,0x09,0x34,0x63,0x01,0x60,0x90,0x62,0x00,0x00, +0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xff,0x10,0x40,0x00,0x05,0xac,0xc2,0x00,0x14, +0x24,0x02,0x00,0x01,0xac,0xc2,0x00,0x00,0x03,0xe0,0x00,0x08,0xac,0xc0,0x00,0x14, +0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0xd0,0x8c,0x43,0x00,0x00,0x00,0x00,0x00,0x00, +0x04,0x61,0x00,0x16,0x3c,0x03,0xb0,0x05,0x34,0x63,0x02,0x2e,0x90,0x62,0x00,0x00, +0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x01,0x14,0x40,0x00,0x10,0x3c,0x02,0xb0,0x05, +0x34,0x42,0x02,0x42,0x90,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x60,0x00,0x0b, +0x00,0x00,0x00,0x00,0x80,0xc2,0x00,0x50,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x07, +0x00,0x00,0x00,0x00,0x14,0x80,0x00,0x05,0x24,0x02,0x00,0x0e,0x24,0x03,0x00,0x01, +0xac,0xc2,0x00,0x00,0x03,0xe0,0x00,0x08,0xa0,0xc3,0x00,0x50,0x80,0xc2,0x00,0x31, +0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x0a,0x3c,0x02,0xb0,0x06,0x34,0x42,0x80,0x18, +0x8c,0x43,0x00,0x00,0x3c,0x04,0xf0,0x00,0x3c,0x02,0x80,0x00,0x00,0x64,0x18,0x24, +0x10,0x62,0x00,0x03,0x24,0x02,0x00,0x09,0x03,0xe0,0x00,0x08,0xac,0xc2,0x00,0x00, +0x8c,0xc2,0x00,0x40,0x00,0x00,0x00,0x00,0x8c,0x43,0x00,0x00,0x00,0x00,0x00,0x00, +0x10,0x60,0x00,0x09,0x3c,0x03,0xb0,0x03,0x3c,0x02,0xb0,0x05,0x34,0x42,0x02,0x2c, +0x8c,0x43,0x00,0x00,0x3c,0x04,0x00,0x02,0x00,0x64,0x18,0x24,0x14,0x60,0xff,0xf2, +0x24,0x02,0x00,0x10,0x3c,0x03,0xb0,0x03,0x34,0x63,0x02,0x01,0x90,0x62,0x00,0x00, +0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x80,0x10,0x40,0x00,0x0e,0x00,0x00,0x00,0x00, +0x8c,0xc3,0x00,0x0c,0x00,0x00,0x00,0x00,0xac,0xc3,0x00,0x10,0x3c,0x02,0xb0,0x03, +0x90,0x42,0x02,0x01,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x0f,0xac,0xc2,0x00,0x0c, +0x90,0xc3,0x00,0x0f,0x24,0x02,0x00,0x0d,0x3c,0x01,0xb0,0x03,0x08,0x00,0x14,0xa6, +0xa0,0x23,0x02,0x01,0x3c,0x02,0xb0,0x09,0x34,0x42,0x01,0x80,0x90,0x44,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x04,0x1e,0x00,0x00,0x03,0x1e,0x03,0x10,0x60,0x00,0x15, +0xa0,0xc4,0x00,0x44,0x24,0x02,0x00,0x01,0x10,0x62,0x00,0x0b,0x24,0x02,0x00,0x02, +0x10,0x62,0x00,0x03,0x24,0x03,0x00,0x0d,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00, +0x8c,0xc2,0x00,0x0c,0xac,0xc3,0x00,0x00,0x24,0x03,0x00,0x04,0xac,0xc2,0x00,0x10, +0x03,0xe0,0x00,0x08,0xac,0xc3,0x00,0x0c,0x24,0x02,0x00,0x0d,0xac,0xc2,0x00,0x00, +0x24,0x03,0x00,0x04,0x24,0x02,0x00,0x06,0xac,0xc3,0x00,0x10,0x03,0xe0,0x00,0x08, +0xac,0xc2,0x00,0x0c,0x8c,0xc3,0x00,0x38,0x00,0x00,0x00,0x00,0x2c,0x62,0x00,0x06, +0x10,0x40,0x00,0x2e,0x00,0x03,0x10,0x80,0x3c,0x03,0x80,0x01,0x24,0x63,0x02,0x00, +0x00,0x43,0x10,0x21,0x8c,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x08, +0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xe2,0x00,0x06,0x24,0x02,0x00,0x03, +0x8c,0xa2,0x02,0xbc,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x06,0x3c,0x03,0xb0,0x06, +0x24,0x02,0x00,0x02,0xac,0xc2,0x00,0x00,0x24,0x02,0x00,0x01,0x03,0xe0,0x00,0x08, +0xac,0xc2,0x00,0x38,0x34,0x63,0x80,0x24,0x8c,0x62,0x00,0x00,0x00,0x00,0x00,0x00, +0x30,0x42,0x00,0xff,0x10,0x40,0x00,0x05,0xac,0xc2,0x00,0x18,0x24,0x02,0x00,0x02, +0xac,0xc2,0x00,0x00,0x08,0x00,0x14,0xfa,0xac,0xc0,0x00,0x18,0x08,0x00,0x14,0xfa, +0xac,0xc0,0x00,0x00,0x24,0x02,0x00,0x02,0x24,0x03,0x00,0x0b,0xac,0xc2,0x00,0x38, +0x03,0xe0,0x00,0x08,0xac,0xc3,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xe2,0x00,0x05, +0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x0c,0xac,0xc2,0x00,0x00,0x08,0x00,0x14,0xfb, +0x24,0x02,0x00,0x04,0x08,0x00,0x15,0x12,0x24,0x02,0x00,0x03,0xac,0xc0,0x00,0x38, +0x03,0xe0,0x00,0x08,0xac,0xc0,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xe2,0x00,0x05, +0x24,0x02,0x00,0x03,0x80,0xc2,0x00,0x30,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x08, +0x24,0x02,0x00,0x04,0xac,0xc2,0x00,0x00,0x93,0x82,0x86,0x3c,0x00,0x00,0x00,0x00, +0x14,0x40,0xff,0xd6,0x24,0x02,0x00,0x05,0x03,0xe0,0x00,0x08,0xac,0xc0,0x00,0x38, +0x08,0x00,0x15,0x22,0xac,0xc0,0x00,0x00,0x3c,0x02,0xb0,0x06,0x34,0x42,0x80,0x18, +0x8c,0x43,0x00,0x00,0x3c,0x04,0xf0,0x00,0x3c,0x02,0x80,0x00,0x00,0x64,0x18,0x24, +0x10,0x62,0x00,0x03,0x24,0x02,0x00,0x09,0x08,0x00,0x15,0x26,0xac,0xc2,0x00,0x00, +0x24,0x02,0x00,0x05,0x08,0x00,0x15,0x18,0xac,0xc2,0x00,0x38,0x80,0xc2,0x00,0x30, +0x00,0x00,0x00,0x00,0x14,0x40,0xff,0x37,0x24,0x02,0x00,0x04,0x08,0x00,0x14,0xa6, +0x00,0x00,0x00,0x00,0x84,0xc2,0x00,0x20,0x00,0x00,0x00,0x00,0x10,0x40,0xff,0x66, +0x24,0x02,0x00,0x06,0x3c,0x02,0xb0,0x05,0x34,0x42,0x02,0x2e,0x90,0x43,0x00,0x00, +0x00,0x00,0x00,0x00,0x30,0x63,0x00,0x01,0x30,0x63,0x00,0xff,0x00,0x60,0x10,0x21, +0x14,0x40,0xff,0x24,0xa4,0xc3,0x00,0x20,0x08,0x00,0x14,0xa6,0x24,0x02,0x00,0x06, +0x8c,0xc2,0x00,0x1c,0x00,0x00,0x00,0x00,0x14,0x40,0xff,0x57,0x24,0x02,0x00,0x05, +0x3c,0x03,0xb0,0x05,0x34,0x63,0x02,0x2c,0x8c,0x62,0x00,0x00,0x00,0x00,0x00,0x00, +0x30,0x42,0x00,0xff,0x10,0x40,0xff,0x14,0xac,0xc2,0x00,0x1c,0x08,0x00,0x14,0xa6, +0x24,0x02,0x00,0x05,0x3c,0x02,0xb0,0x05,0x8c,0x42,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x02,0x17,0x42,0x30,0x42,0x00,0x01,0x14,0x40,0xff,0x47,0x24,0x02,0x00,0x06, +0x08,0x00,0x14,0x5c,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x0a,0x03,0xe0,0x00,0x08, +0xac,0x82,0x00,0x00,0x27,0xbd,0xff,0xd8,0xaf,0xb0,0x00,0x10,0x27,0x90,0x86,0x48, +0xaf,0xbf,0x00,0x20,0xaf,0xb3,0x00,0x1c,0xaf,0xb2,0x00,0x18,0x0c,0x00,0x2b,0xe8, +0xaf,0xb1,0x00,0x14,0xaf,0x90,0x8f,0xd0,0x48,0x02,0x00,0x00,0x0c,0x00,0x13,0xec, +0x00,0x00,0x00,0x00,0x0c,0x00,0x18,0x4e,0x02,0x00,0x20,0x21,0x0c,0x00,0x00,0x34, +0x00,0x00,0x00,0x00,0x0c,0x00,0x13,0xf7,0x00,0x00,0x00,0x00,0x27,0x84,0x84,0x68, +0x0c,0x00,0x27,0xc1,0x00,0x00,0x00,0x00,0x93,0x84,0x80,0x10,0x0c,0x00,0x21,0x9a, +0x00,0x00,0x00,0x00,0x27,0x84,0x89,0x08,0x0c,0x00,0x06,0xe1,0x00,0x00,0x00,0x00, +0x0c,0x00,0x01,0x3b,0x00,0x00,0x00,0x00,0x27,0x84,0x84,0x10,0x0c,0x00,0x13,0xd5, +0x00,0x00,0x00,0x00,0x27,0x82,0x89,0x3c,0xaf,0x82,0x84,0x50,0x0c,0x00,0x00,0x61, +0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03,0x34,0x63,0x01,0x08,0x3c,0x04,0xb0,0x09, +0x3c,0x05,0xb0,0x09,0x8c,0x66,0x00,0x00,0x34,0x84,0x01,0x68,0x24,0x02,0xc8,0x80, +0x34,0xa5,0x01,0x40,0x24,0x03,0x00,0x0a,0xa4,0x82,0x00,0x00,0xa4,0xa3,0x00,0x00, +0x3c,0x04,0xb0,0x03,0x8c,0x82,0x00,0x00,0x8f,0x87,0x84,0x10,0xaf,0x86,0x84,0x08, +0x34,0x42,0x00,0x20,0xac,0x82,0x00,0x00,0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0x58, +0x8c,0x43,0x00,0x00,0x2c,0xe4,0x00,0x11,0x34,0x63,0x01,0x00,0xac,0x43,0x00,0x00, +0x10,0x80,0xff,0xfa,0x3c,0x02,0xb0,0x03,0x3c,0x03,0x80,0x01,0x00,0x07,0x10,0x80, +0x24,0x63,0x02,0x18,0x00,0x43,0x10,0x21,0x8c,0x44,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x80,0x00,0x08,0x00,0x00,0x00,0x00,0x27,0x84,0x84,0x68,0x0c,0x00,0x26,0xe5, +0x00,0x00,0x00,0x00,0x27,0x84,0x84,0x10,0x27,0x85,0x86,0x48,0x0c,0x00,0x14,0x4e, +0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x09,0x34,0x42,0x00,0x07,0x3c,0x03,0xb0,0x06, +0x90,0x44,0x00,0x00,0x34,0x63,0x80,0x18,0x8c,0x65,0x00,0x00,0x3c,0x02,0xb0,0x03, +0x34,0x42,0x00,0xec,0x3c,0x03,0xb0,0x03,0x30,0x86,0x00,0xff,0xa0,0x46,0x00,0x00, +0x00,0x05,0x2f,0x02,0x34,0x63,0x00,0xed,0x24,0x02,0x00,0x01,0x10,0xc2,0x00,0x2c, +0xa0,0x65,0x00,0x00,0xa3,0x80,0x81,0x58,0x93,0x83,0x81,0xf1,0x24,0x02,0x00,0x01, +0x10,0x62,0x00,0x08,0x00,0x00,0x00,0x00,0x8f,0x87,0x84,0x10,0x8f,0x82,0x84,0x44, +0x00,0x00,0x00,0x00,0x24,0x42,0x00,0x01,0xaf,0x82,0x84,0x44,0x08,0x00,0x15,0x9b, +0x3c,0x02,0xb0,0x03,0x8f,0x87,0x84,0x10,0x00,0x00,0x00,0x00,0x24,0xe2,0xff,0xfc, +0x2c,0x42,0x00,0x03,0x14,0x40,0x00,0x0a,0x3c,0x03,0xb0,0x06,0x93,0x82,0x86,0x3c, +0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x07,0x34,0x63,0x80,0x18,0x27,0x84,0x84,0x68, +0x0c,0x00,0x27,0x75,0x00,0x00,0x00,0x00,0x8f,0x87,0x84,0x10,0x3c,0x03,0xb0,0x06, +0x34,0x63,0x80,0x18,0x8c,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x17,0x02, +0x10,0x40,0xff,0xe6,0x00,0x00,0x00,0x00,0x8f,0x82,0xbc,0x10,0x8f,0x84,0xbc,0x18, +0x3c,0x05,0xb0,0x01,0x00,0x45,0x10,0x21,0xac,0x44,0x00,0x00,0x8f,0x83,0xbc,0x10, +0x8f,0x82,0xbc,0x14,0x00,0x65,0x18,0x21,0x08,0x00,0x15,0xc7,0xac,0x62,0x00,0x04, +0x14,0xa0,0xff,0xd4,0x3c,0x02,0xb0,0x03,0x93,0x83,0x81,0x58,0x34,0x42,0x00,0xee, +0x24,0x63,0x00,0x01,0x30,0x64,0x00,0xff,0x2c,0x84,0x00,0xf1,0xa0,0x43,0x00,0x00, +0xa3,0x83,0x81,0x58,0x14,0x80,0xff,0xcc,0x00,0x00,0x00,0x00,0xaf,0x86,0x84,0x24, +0xa3,0x86,0x86,0x23,0x08,0x00,0x15,0xc1,0x00,0x00,0x00,0x00,0x27,0x84,0x84,0x68, +0x0c,0x00,0x29,0x6e,0x00,0x00,0x00,0x00,0xa3,0x82,0x84,0x41,0x8f,0x82,0x84,0x44, +0xaf,0x80,0x84,0x10,0x24,0x42,0x00,0x01,0xaf,0x82,0x84,0x44,0x08,0x00,0x15,0x9a, +0x00,0x00,0x38,0x21,0x27,0x84,0x86,0x48,0x0c,0x00,0x19,0x19,0x00,0x00,0x00,0x00, +0x30,0x42,0x00,0xff,0x14,0x40,0x00,0x05,0x3c,0x03,0xb0,0x05,0xaf,0x80,0x84,0x10, +0xaf,0x80,0x84,0x14,0x08,0x00,0x15,0xc6,0x00,0x00,0x00,0x00,0x34,0x63,0x04,0x50, +0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xff,0xaf,0x82,0x84,0x3c, +0x14,0x40,0x00,0x20,0x24,0x02,0x00,0x01,0x8f,0x84,0x84,0x18,0x00,0x00,0x00,0x00, +0x10,0x82,0x00,0x20,0x3c,0x03,0xb0,0x09,0x34,0x63,0x01,0x60,0x90,0x62,0x00,0x00, +0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xff,0xaf,0x82,0x84,0x24,0x14,0x40,0x00,0x15, +0x24,0x02,0x00,0x01,0x24,0x02,0x00,0x02,0x10,0x82,0x00,0x07,0x00,0x00,0x00,0x00, +0x24,0x07,0x00,0x03,0x24,0x02,0x00,0x01,0xaf,0x82,0x84,0x14,0xaf,0x87,0x84,0x10, +0x08,0x00,0x15,0xc6,0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x05,0x34,0x42,0x02,0x2e, +0x90,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x63,0x00,0x01,0x30,0x63,0x00,0xff, +0x00,0x60,0x10,0x21,0xa7,0x83,0x84,0x30,0x14,0x40,0xff,0xf1,0x00,0x00,0x00,0x00, +0x24,0x02,0x00,0x01,0xaf,0x82,0x84,0x14,0xaf,0x80,0x84,0x10,0x08,0x00,0x15,0xc6, +0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x05,0x34,0x63,0x02,0x2c,0x8c,0x62,0x00,0x00, +0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xff,0xaf,0x82,0x84,0x2c,0x14,0x40,0xff,0xf5, +0x24,0x02,0x00,0x01,0x08,0x00,0x16,0x1a,0x3c,0x03,0xb0,0x09,0x27,0x84,0x86,0x48, +0x0c,0x00,0x1a,0xde,0x00,0x00,0x00,0x00,0x83,0x82,0x84,0x40,0x00,0x00,0x00,0x00, +0x14,0x40,0xff,0xec,0x24,0x02,0x00,0x02,0x3c,0x03,0xb0,0x05,0x34,0x63,0x04,0x50, +0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xff,0xaf,0x82,0x84,0x3c, +0x14,0x40,0xff,0xe4,0x24,0x02,0x00,0x02,0x8f,0x84,0x84,0x18,0x24,0x02,0x00,0x01, +0x10,0x82,0x00,0x12,0x24,0x02,0x00,0x02,0x10,0x82,0x00,0x04,0x00,0x00,0x00,0x00, +0x24,0x07,0x00,0x04,0x08,0x00,0x16,0x26,0x24,0x02,0x00,0x02,0x3c,0x02,0xb0,0x05, +0x34,0x42,0x02,0x2e,0x90,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x63,0x00,0x01, +0x30,0x63,0x00,0xff,0x00,0x60,0x10,0x21,0xa7,0x83,0x84,0x30,0x14,0x40,0xff,0xf4, +0x00,0x00,0x00,0x00,0x08,0x00,0x16,0x35,0x24,0x02,0x00,0x02,0x3c,0x03,0xb0,0x05, +0x34,0x63,0x02,0x2c,0x8c,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xff, +0xaf,0x82,0x84,0x2c,0x14,0x40,0xff,0xf7,0x00,0x00,0x00,0x00,0x08,0x00,0x16,0x56, +0x24,0x02,0x00,0x02,0x27,0x84,0x89,0x08,0x0c,0x00,0x0b,0x51,0x00,0x00,0x00,0x00, +0x8f,0x83,0x84,0x14,0xaf,0x82,0x84,0x2c,0x38,0x64,0x00,0x02,0x00,0x04,0x18,0x0a, +0xaf,0x83,0x84,0x14,0x14,0x40,0xff,0xad,0x24,0x07,0x00,0x05,0x8f,0x82,0x89,0x48, +0xaf,0x80,0x84,0x10,0x10,0x40,0x00,0x02,0x24,0x04,0x00,0x01,0xaf,0x84,0x84,0x18, +0x93,0x82,0x89,0x56,0x00,0x00,0x00,0x00,0x10,0x40,0xff,0x43,0x00,0x00,0x00,0x00, +0x3c,0x02,0xb0,0x05,0x34,0x42,0x00,0x08,0x8c,0x43,0x00,0x00,0x3c,0x04,0x20,0x00, +0x00,0x64,0x18,0x24,0x10,0x60,0xff,0x3c,0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x03, +0x34,0x42,0x00,0xa0,0x8c,0x43,0x00,0x00,0x3c,0x04,0x80,0x00,0xaf,0x80,0x89,0x30, +0x24,0x63,0x00,0x01,0xac,0x43,0x00,0x00,0x3c,0x01,0xb0,0x05,0xac,0x24,0x00,0x08, +0xaf,0x80,0x89,0x2c,0xaf,0x80,0x89,0x34,0xaf,0x80,0x89,0x38,0xaf,0x80,0x89,0x44, +0xaf,0x80,0x89,0x3c,0x08,0x00,0x15,0xc6,0x00,0x00,0x00,0x00,0x83,0x82,0x84,0x60, +0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x02,0x24,0x02,0x00,0x20,0xaf,0x82,0x84,0x2c, +0x8f,0x85,0x84,0x2c,0x27,0x84,0x89,0x08,0x0c,0x00,0x0d,0x2c,0x00,0x00,0x00,0x00, +0x00,0x02,0x1e,0x00,0xa3,0x82,0x84,0x40,0xaf,0x80,0x84,0x2c,0x10,0x60,0xff,0x8e, +0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x05,0x34,0x42,0x02,0x2e,0x90,0x43,0x00,0x00, +0x00,0x00,0x00,0x00,0x30,0x63,0x00,0x01,0x30,0x63,0x00,0xff,0x00,0x60,0x10,0x21, +0xa7,0x83,0x84,0x30,0x10,0x40,0x00,0x04,0x24,0x04,0x00,0x02,0xaf,0x84,0x84,0x18, +0x08,0x00,0x16,0x36,0x00,0x00,0x00,0x00,0x08,0x00,0x16,0x27,0x24,0x07,0x00,0x06, +0x27,0x84,0x84,0x10,0x27,0x85,0x89,0x08,0x0c,0x00,0x0d,0xf9,0x00,0x00,0x00,0x00, +0x8f,0x82,0x84,0x34,0xaf,0x80,0x84,0x3c,0x14,0x40,0x00,0x19,0x00,0x40,0x18,0x21, +0x8f,0x82,0x84,0x38,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x15,0x24,0x02,0x00,0x02, +0x8f,0x83,0x84,0x18,0x00,0x00,0x00,0x00,0x10,0x62,0x00,0x0b,0x3c,0x02,0x40,0x00, +0x8f,0x83,0x84,0x14,0x24,0x02,0x00,0x01,0x10,0x62,0x00,0x02,0x24,0x07,0x00,0x03, +0x24,0x07,0x00,0x06,0xaf,0x87,0x84,0x10,0x24,0x04,0x00,0x03,0xaf,0x84,0x84,0x18, +0x08,0x00,0x15,0xc6,0x00,0x00,0x00,0x00,0x34,0x42,0x00,0x14,0x3c,0x01,0xb0,0x05, +0xac,0x22,0x00,0x00,0xaf,0x80,0x84,0x10,0x08,0x00,0x16,0xcf,0x24,0x04,0x00,0x03, +0x10,0x60,0x00,0x10,0x00,0x00,0x00,0x00,0x27,0x84,0x84,0x10,0x27,0x85,0x89,0x08, +0x0c,0x00,0x0e,0x1d,0x00,0x00,0x00,0x00,0x8f,0x83,0x84,0x14,0x24,0x02,0x00,0x01, +0xa3,0x80,0x84,0x40,0xaf,0x80,0x84,0x18,0x10,0x62,0x00,0x02,0x24,0x07,0x00,0x03, +0x24,0x07,0x00,0x04,0xaf,0x87,0x84,0x10,0xaf,0x80,0x84,0x34,0x08,0x00,0x15,0xc6, +0x00,0x00,0x00,0x00,0x83,0x82,0x84,0x60,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x04, +0x00,0x00,0x00,0x00,0x27,0x84,0x89,0x08,0x0c,0x00,0x10,0x65,0x00,0x00,0x00,0x00, +0x8f,0x82,0x84,0x14,0xa3,0x80,0x84,0x40,0xaf,0x80,0x84,0x10,0xaf,0x80,0x84,0x18, +0x14,0x40,0x00,0x03,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0xaf,0x82,0x84,0x14, +0xaf,0x80,0x84,0x38,0x08,0x00,0x15,0xc6,0x00,0x00,0x00,0x00,0x27,0x84,0x84,0x10, +0x27,0x85,0x89,0x08,0x0c,0x00,0x0e,0x1d,0x00,0x00,0x00,0x00,0x8f,0x82,0x84,0x14, +0xa3,0x80,0x84,0x40,0xaf,0x80,0x84,0x10,0xaf,0x80,0x84,0x18,0x14,0x40,0xfe,0xc2, +0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0xaf,0x82,0x84,0x14,0x08,0x00,0x15,0xc6, +0x00,0x00,0x00,0x00,0x27,0x84,0x89,0x08,0x0c,0x00,0x10,0x65,0x00,0x00,0x00,0x00, +0x08,0x00,0x16,0xff,0x00,0x00,0x00,0x00,0x27,0x84,0x84,0x68,0x0c,0x00,0x2a,0x96, +0x00,0x00,0x00,0x00,0x08,0x00,0x15,0xfe,0x00,0x00,0x00,0x00,0x0c,0x00,0x24,0x66, +0x00,0x00,0x00,0x00,0x0c,0x00,0x27,0x56,0x00,0x00,0x00,0x00,0x0c,0x00,0x18,0x40, +0x00,0x00,0x00,0x00,0x27,0x84,0x84,0x68,0x0c,0x00,0x27,0x64,0x00,0x00,0x00,0x00, +0x93,0x83,0xbc,0x08,0x00,0x00,0x00,0x00,0x14,0x60,0x00,0x2b,0x3c,0x02,0xb0,0x03, +0x34,0x42,0x01,0x08,0x8c,0x44,0x00,0x00,0x8f,0x83,0xbc,0x00,0x8f,0x82,0xbc,0x04, +0x00,0x83,0x18,0x23,0x00,0x43,0x10,0x2b,0x10,0x40,0x00,0x23,0x3c,0x02,0xb0,0x03, +0x24,0x04,0x05,0xa0,0x34,0x42,0x01,0x18,0x8c,0x42,0x00,0x00,0x0c,0x00,0x06,0xce, +0x00,0x00,0x00,0x00,0x24,0x04,0x05,0xa4,0x0c,0x00,0x06,0xce,0x00,0x02,0x84,0x02, +0x30,0x51,0xff,0xff,0x24,0x04,0x05,0xa8,0x00,0x02,0x94,0x02,0x0c,0x00,0x06,0xce, +0x3a,0x10,0xff,0xff,0x3a,0x31,0xff,0xff,0x30,0x42,0xff,0xff,0x2e,0x10,0x00,0x01, +0x2e,0x31,0x00,0x01,0x3a,0x52,0xff,0xff,0x02,0x11,0x80,0x25,0x2e,0x52,0x00,0x01, +0x38,0x42,0xff,0xff,0x02,0x12,0x80,0x25,0x2c,0x42,0x00,0x01,0x02,0x02,0x80,0x25, +0x16,0x00,0x00,0x02,0x24,0x04,0x00,0x02,0x00,0x00,0x20,0x21,0x0c,0x00,0x05,0x70, +0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x03,0x34,0x42,0x01,0x08,0x8c,0x43,0x00,0x00, +0x00,0x00,0x00,0x00,0xaf,0x83,0xbc,0x00,0x0c,0x00,0x01,0xeb,0x00,0x00,0x00,0x00, +0xaf,0x80,0x84,0x10,0xaf,0x80,0x84,0x44,0x08,0x00,0x15,0x9a,0x00,0x00,0x38,0x21, +0x27,0x90,0xb3,0xf0,0x24,0x11,0x00,0x12,0x8e,0x04,0x00,0x00,0x00,0x00,0x00,0x00, +0x90,0x82,0x00,0x10,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x03,0x00,0x00,0x00,0x00, +0x0c,0x00,0x20,0xd0,0x00,0x00,0x00,0x00,0x26,0x31,0xff,0xff,0x06,0x21,0xff,0xf6, +0x26,0x10,0x00,0x04,0xaf,0x80,0x84,0x10,0x08,0x00,0x15,0xc7,0x00,0x00,0x38,0x21, +0x3c,0x02,0xb0,0x03,0x34,0x42,0x01,0x08,0x8c,0x44,0x00,0x00,0x8f,0x82,0x84,0x08, +0x00,0x04,0x19,0xc2,0x00,0x02,0x11,0xc2,0x10,0x62,0xff,0xf6,0x00,0x00,0x00,0x00, +0x3c,0x02,0xb0,0x03,0x34,0x42,0x01,0x02,0x90,0x43,0x00,0x00,0x3c,0x12,0xb0,0x05, +0xaf,0x84,0x84,0x08,0x30,0x63,0x00,0xff,0x00,0x03,0x11,0x40,0x00,0x43,0x10,0x23, +0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21,0x00,0x02,0x99,0x00,0x00,0x00,0x88,0x21, +0x36,0x52,0x02,0x2c,0x27,0x90,0xb3,0xf0,0x8e,0x04,0x00,0x00,0x00,0x00,0x00,0x00, +0x90,0x83,0x00,0x16,0x00,0x00,0x00,0x00,0x30,0x62,0x00,0x03,0x10,0x40,0x00,0x06, +0x30,0x62,0x00,0x1c,0x14,0x40,0x00,0x04,0x00,0x00,0x00,0x00,0x8f,0x85,0x84,0x08, +0x0c,0x00,0x1e,0xb2,0x02,0x60,0x30,0x21,0x8e,0x42,0x00,0x00,0x00,0x00,0x00,0x00, +0x30,0x42,0x00,0xff,0x14,0x40,0xff,0xd7,0x00,0x00,0x00,0x00,0x26,0x31,0x00,0x01, +0x2a,0x22,0x00,0x13,0x14,0x40,0xff,0xec,0x26,0x10,0x00,0x04,0x08,0x00,0x17,0x5d, +0x00,0x00,0x00,0x00,0x8f,0x84,0x84,0x1c,0x27,0x85,0x89,0x08,0x0c,0x00,0x17,0xd3, +0x00,0x00,0x00,0x00,0x8f,0x83,0x84,0x1c,0x24,0x02,0x00,0x04,0x14,0x62,0xfe,0xa2, +0x00,0x00,0x00,0x00,0x08,0x00,0x16,0x27,0x24,0x07,0x00,0x05,0x27,0x84,0x89,0x08, +0x0c,0x00,0x24,0x8d,0x00,0x00,0x00,0x00,0x24,0x07,0x00,0x05,0xaf,0x87,0x84,0x10, +0x08,0x00,0x15,0xc7,0x00,0x00,0x00,0x00,0x8f,0x82,0x89,0x3c,0x00,0x00,0x00,0x00, +0x10,0x40,0x00,0x0d,0x00,0x00,0x00,0x00,0x8f,0x84,0xb4,0x30,0xaf,0x80,0x89,0x3c, +0x94,0x85,0x00,0x14,0x0c,0x00,0x1b,0x84,0x00,0x00,0x00,0x00,0x93,0x82,0x8b,0x61, +0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x02,0x10,0x40,0x00,0x03,0x00,0x00,0x00,0x00, +0x0c,0x00,0x01,0x59,0x00,0x00,0x20,0x21,0x8f,0x84,0xb4,0x30,0x0c,0x00,0x20,0xd0, +0x00,0x00,0x00,0x00,0x08,0x00,0x17,0x5d,0x00,0x00,0x00,0x00,0x3c,0x02,0xff,0x90, +0x27,0xbd,0xff,0xe8,0x00,0x80,0x18,0x21,0x34,0x42,0x00,0x01,0x27,0x84,0x89,0x08, +0x10,0x62,0x00,0x05,0xaf,0xbf,0x00,0x10,0x8f,0xbf,0x00,0x10,0x00,0x00,0x00,0x00, +0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18,0x0c,0x00,0x06,0xe1,0x00,0x00,0x00,0x00, +0x27,0x84,0x86,0x48,0x0c,0x00,0x18,0x4e,0x00,0x00,0x00,0x00,0x27,0x84,0x84,0x10, +0x0c,0x00,0x13,0xd5,0x00,0x00,0x00,0x00,0x08,0x00,0x17,0xba,0x00,0x00,0x00,0x00, +0x8f,0x82,0x89,0x48,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x05,0x00,0x00,0x18,0x21, +0x8f,0x82,0x84,0x18,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x02,0x00,0x00,0x00,0x00, +0x24,0x03,0x00,0x01,0x03,0xe0,0x00,0x08,0x00,0x60,0x10,0x21,0x27,0xbd,0xff,0xe0, +0x3c,0x06,0xb0,0x03,0xaf,0xb1,0x00,0x14,0xaf,0xb0,0x00,0x10,0x34,0xc6,0x00,0x5f, +0xaf,0xbf,0x00,0x18,0x90,0xc3,0x00,0x00,0x3c,0x07,0xb0,0x03,0x34,0xe7,0x00,0x5d, +0x34,0x63,0x00,0x01,0x3c,0x09,0xb0,0x03,0x24,0x02,0x00,0x01,0xa0,0xc3,0x00,0x00, +0x00,0x80,0x80,0x21,0xa0,0xe2,0x00,0x00,0x00,0xa0,0x88,0x21,0x35,0x29,0x00,0x5e, +0x00,0xe0,0x40,0x21,0x24,0x04,0x00,0x01,0x91,0x22,0x00,0x00,0x91,0x03,0x00,0x00, +0x30,0x42,0x00,0x01,0x14,0x83,0x00,0x03,0x30,0x42,0x00,0x01,0x14,0x40,0xff,0xfa, +0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x04,0x12,0x02,0x00,0x2c,0x24,0x05,0x0f,0x00, +0x24,0x02,0x00,0x06,0x12,0x02,0x00,0x08,0x24,0x05,0x00,0x0f,0x3c,0x02,0xb0,0x03, +0x34,0x42,0x02,0x00,0xa0,0x50,0x00,0x00,0x8f,0xbf,0x00,0x18,0x7b,0xb0,0x00,0xbc, +0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20,0x24,0x04,0x0c,0x04,0x0c,0x00,0x13,0x5b, +0x24,0x06,0x00,0x0f,0x24,0x04,0x0d,0x04,0x24,0x05,0x00,0x0f,0x0c,0x00,0x13,0x5b, +0x24,0x06,0x00,0x0f,0x24,0x04,0x08,0x80,0x24,0x05,0x1e,0x00,0x0c,0x00,0x13,0x5b, +0x24,0x06,0x00,0x0f,0x24,0x04,0x08,0x8c,0x24,0x05,0x0f,0x00,0x0c,0x00,0x13,0x5b, +0x24,0x06,0x00,0x0f,0x24,0x04,0x08,0x24,0x3c,0x05,0x00,0x30,0x0c,0x00,0x13,0x5b, +0x24,0x06,0x00,0x02,0x24,0x04,0x08,0x2c,0x3c,0x05,0x00,0x30,0x0c,0x00,0x13,0x5b, +0x24,0x06,0x00,0x02,0x24,0x04,0x08,0x34,0x3c,0x05,0x00,0x30,0x0c,0x00,0x13,0x5b, +0x24,0x06,0x00,0x02,0x24,0x04,0x08,0x3c,0x3c,0x05,0x00,0x30,0x0c,0x00,0x13,0x5b, +0x24,0x06,0x00,0x02,0x08,0x00,0x17,0xf4,0x3c,0x02,0xb0,0x03,0x24,0x04,0x08,0x8c, +0x0c,0x00,0x13,0x5b,0x24,0x06,0x00,0x04,0x24,0x04,0x08,0x80,0x24,0x05,0x1e,0x00, +0x0c,0x00,0x13,0x5b,0x24,0x06,0x00,0x04,0x24,0x04,0x0c,0x04,0x24,0x05,0x00,0x0f, +0x0c,0x00,0x13,0x5b,0x24,0x06,0x00,0x04,0x24,0x04,0x0d,0x04,0x24,0x05,0x00,0x0f, +0x0c,0x00,0x13,0x5b,0x24,0x06,0x00,0x04,0x24,0x04,0x08,0x24,0x3c,0x05,0x00,0x30, +0x0c,0x00,0x13,0x5b,0x24,0x06,0x00,0x03,0x24,0x04,0x08,0x2c,0x3c,0x05,0x00,0x30, +0x0c,0x00,0x13,0x5b,0x24,0x06,0x00,0x03,0x24,0x04,0x08,0x34,0x3c,0x05,0x00,0x30, +0x0c,0x00,0x13,0x5b,0x24,0x06,0x00,0x02,0x3c,0x05,0x00,0x30,0x24,0x06,0x00,0x03, +0x0c,0x00,0x13,0x5b,0x24,0x04,0x08,0x3c,0x02,0x20,0x20,0x21,0x24,0x05,0x00,0x14, +0x0c,0x00,0x13,0xa0,0x24,0x06,0x01,0x07,0x08,0x00,0x17,0xf4,0x3c,0x02,0xb0,0x03, +0x3c,0x03,0xb0,0x03,0x34,0x63,0x00,0x73,0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00, +0x30,0x42,0x00,0x02,0x14,0x40,0x00,0x04,0x00,0x00,0x00,0x00,0xa3,0x80,0x81,0x59, +0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0xa3,0x82,0x81,0x59, +0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00, +0x00,0x80,0x70,0x21,0x34,0x63,0x00,0x20,0x24,0x42,0x61,0x38,0x3c,0x04,0xb0,0x03, +0xac,0x62,0x00,0x00,0x34,0x84,0x00,0x30,0xad,0xc0,0x02,0xbc,0xad,0xc0,0x02,0xb8, +0x8c,0x83,0x00,0x00,0x24,0x02,0x00,0xff,0xa5,0xc0,0x00,0x0a,0x00,0x00,0x30,0x21, +0xa7,0x82,0x8f,0xe0,0x27,0x88,0x8f,0xf0,0xa5,0xc3,0x00,0x08,0x3c,0x07,0xb0,0x08, +0x30,0xc2,0xff,0xff,0x00,0x02,0x20,0xc0,0x24,0xc3,0x00,0x01,0x00,0x82,0x10,0x21, +0x00,0x60,0x30,0x21,0x00,0x02,0x10,0x80,0x30,0x63,0xff,0xff,0x00,0x48,0x10,0x21, +0x00,0x87,0x20,0x21,0x28,0xc5,0x00,0xff,0xac,0x83,0x00,0x00,0x14,0xa0,0xff,0xf4, +0xa4,0x43,0x00,0x00,0x3c,0x02,0xb0,0x08,0x34,0x03,0xff,0xff,0x25,0xc4,0x00,0x0c, +0x24,0x0a,0x00,0x02,0x34,0x42,0x07,0xf8,0x3c,0x06,0xb0,0x03,0xa7,0x83,0xb3,0xcc, +0xac,0x43,0x00,0x00,0xaf,0x84,0xb3,0xf0,0x34,0xc6,0x00,0x64,0xa0,0x8a,0x00,0x18, +0x94,0xc5,0x00,0x00,0x8f,0x82,0xb3,0xf0,0x25,0xc4,0x00,0x30,0x24,0x08,0x00,0x03, +0x3c,0x03,0xb0,0x03,0xa0,0x45,0x00,0x21,0x34,0x63,0x00,0x66,0xaf,0x84,0xb3,0xf4, +0xa0,0x88,0x00,0x18,0x94,0x65,0x00,0x00,0x8f,0x82,0xb3,0xf4,0x25,0xc4,0x00,0x54, +0x25,0xc7,0x00,0x78,0xa0,0x45,0x00,0x21,0xaf,0x84,0xb3,0xf8,0xa0,0x88,0x00,0x18, +0x94,0x65,0x00,0x00,0x8f,0x82,0xb3,0xf8,0x25,0xc8,0x00,0x9c,0x24,0x09,0x00,0x01, +0xa0,0x45,0x00,0x21,0xaf,0x87,0xb3,0xfc,0xa0,0xea,0x00,0x18,0x94,0xc4,0x00,0x00, +0x8f,0x82,0xb3,0xfc,0x3c,0x03,0xb0,0x03,0x34,0x63,0x00,0x62,0xa0,0x44,0x00,0x21, +0xaf,0x88,0xb4,0x00,0xa1,0x09,0x00,0x18,0x94,0x65,0x00,0x00,0x8f,0x82,0xb4,0x00, +0x25,0xc4,0x00,0xc0,0x3c,0x06,0xb0,0x03,0xa0,0x45,0x00,0x21,0xaf,0x84,0xb4,0x04, +0xa0,0x89,0x00,0x18,0x94,0x65,0x00,0x00,0x8f,0x82,0xb4,0x04,0x25,0xc4,0x00,0xe4, +0x34,0xc6,0x00,0x60,0xa0,0x45,0x00,0x21,0xaf,0x84,0xb4,0x08,0xa0,0x80,0x00,0x18, +0x94,0xc5,0x00,0x00,0x8f,0x82,0xb4,0x08,0x25,0xc3,0x01,0x08,0x25,0xc7,0x01,0x2c, +0xa0,0x45,0x00,0x21,0xaf,0x83,0xb4,0x0c,0xa0,0x60,0x00,0x18,0x94,0xc8,0x00,0x00, +0x8f,0x82,0xb4,0x0c,0x25,0xc4,0x01,0x50,0x25,0xc5,0x01,0x74,0xa0,0x48,0x00,0x21, +0x25,0xc6,0x01,0x98,0x25,0xc9,0x01,0xbc,0x25,0xca,0x01,0xe0,0x25,0xcb,0x02,0x04, +0x25,0xcc,0x02,0x28,0x25,0xcd,0x02,0x4c,0x24,0x02,0x00,0x10,0x3c,0x03,0xb0,0x03, +0xaf,0x87,0xb4,0x10,0x34,0x63,0x00,0x38,0xa0,0xe0,0x00,0x18,0xaf,0x84,0xb4,0x14, +0xa0,0x80,0x00,0x18,0xaf,0x85,0xb4,0x18,0xa0,0xa0,0x00,0x18,0xaf,0x86,0xb4,0x1c, +0xa0,0xc0,0x00,0x18,0xaf,0x89,0xb4,0x20,0xa1,0x20,0x00,0x18,0xaf,0x8a,0xb4,0x24, +0xa1,0x40,0x00,0x18,0xaf,0x8b,0xb4,0x28,0xa1,0x60,0x00,0x18,0xaf,0x8c,0xb4,0x2c, +0xa1,0x80,0x00,0x18,0xaf,0x8d,0xb4,0x30,0xa1,0xa2,0x00,0x18,0x94,0x64,0x00,0x00, +0x8f,0x82,0xb4,0x30,0x25,0xc5,0x02,0x70,0x3c,0x03,0xb0,0x03,0xa0,0x44,0x00,0x21, +0x24,0x02,0x00,0x11,0xaf,0x85,0xb4,0x34,0x34,0x63,0x00,0x6e,0xa0,0xa2,0x00,0x18, +0x94,0x64,0x00,0x00,0x8f,0x82,0xb4,0x34,0x25,0xc5,0x02,0x94,0x3c,0x03,0xb0,0x03, +0xa0,0x44,0x00,0x21,0x24,0x02,0x00,0x12,0xaf,0x85,0xb4,0x38,0x34,0x63,0x00,0x6c, +0xa0,0xa2,0x00,0x18,0x94,0x64,0x00,0x00,0x8f,0x82,0xb4,0x38,0x24,0x05,0xff,0xff, +0x24,0x07,0x00,0x01,0xa0,0x44,0x00,0x21,0x24,0x06,0x00,0x12,0x27,0x84,0xb3,0xf0, +0x8c,0x82,0x00,0x00,0x24,0xc6,0xff,0xff,0xa0,0x40,0x00,0x04,0x8c,0x83,0x00,0x00, +0xa4,0x45,0x00,0x00,0xa4,0x45,0x00,0x02,0xa0,0x60,0x00,0x0a,0x8c,0x82,0x00,0x00, +0xa4,0x65,0x00,0x06,0xa4,0x65,0x00,0x08,0xa0,0x40,0x00,0x10,0x8c,0x83,0x00,0x00, +0xa4,0x45,0x00,0x0c,0xa4,0x45,0x00,0x0e,0xa0,0x60,0x00,0x12,0x8c,0x82,0x00,0x00, +0x00,0x00,0x00,0x00,0xa0,0x40,0x00,0x16,0x8c,0x83,0x00,0x00,0xa4,0x45,0x00,0x14, +0xa0,0x67,0x00,0x17,0x8c,0x82,0x00,0x00,0x24,0x84,0x00,0x04,0xa0,0x40,0x00,0x20, +0x04,0xc1,0xff,0xe7,0xac,0x40,0x00,0x1c,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00, +0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x34,0x63,0x00,0x20,0x24,0x42,0x64,0x00, +0x00,0x05,0x28,0x40,0xac,0x62,0x00,0x00,0x00,0xa6,0x28,0x21,0x2c,0xe2,0x00,0x10, +0x14,0x80,0x00,0x06,0x00,0x00,0x18,0x21,0x10,0x40,0x00,0x02,0x00,0x00,0x00,0x00, +0x00,0xe0,0x18,0x21,0x03,0xe0,0x00,0x08,0x00,0x60,0x10,0x21,0x24,0x02,0x00,0x20, +0x10,0xe2,0x00,0x06,0x2c,0xe4,0x00,0x10,0x24,0xa2,0x00,0x01,0x10,0x80,0xff,0xf9, +0x00,0x02,0x11,0x00,0x08,0x00,0x19,0x0d,0x00,0x47,0x18,0x21,0x08,0x00,0x19,0x0d, +0x24,0xa3,0x00,0x50,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x27,0xbd,0xff,0xc8, +0x34,0x63,0x00,0x20,0x24,0x42,0x64,0x64,0xaf,0xb2,0x00,0x18,0xaf,0xbf,0x00,0x34, +0xaf,0xbe,0x00,0x30,0xaf,0xb7,0x00,0x2c,0xaf,0xb6,0x00,0x28,0xaf,0xb5,0x00,0x24, +0xaf,0xb4,0x00,0x20,0xaf,0xb3,0x00,0x1c,0xaf,0xb1,0x00,0x14,0xaf,0xb0,0x00,0x10, +0xac,0x62,0x00,0x00,0x8c,0x86,0x02,0xbc,0x00,0x80,0x90,0x21,0x14,0xc0,0x01,0x66, +0x00,0xc0,0x38,0x21,0x84,0x82,0x00,0x08,0x3c,0x03,0xb0,0x06,0x94,0x84,0x00,0x08, +0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21,0x8c,0x45,0x00,0x00,0x8c,0x43,0x00,0x00, +0x24,0x84,0x00,0x02,0x30,0x84,0x01,0xff,0x30,0xb1,0xff,0xff,0x00,0x03,0x44,0x02, +0xa6,0x44,0x00,0x08,0x14,0xe0,0x00,0x08,0x3c,0x03,0xb0,0x06,0x34,0x63,0x80,0x24, +0x8c,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x34,0x42,0x01,0x00,0xac,0x62,0x00,0x00, +0x8e,0x46,0x02,0xbc,0x00,0x00,0x00,0x00,0x14,0xc0,0x01,0x4c,0x00,0x11,0x98,0xc0, +0x00,0x11,0x3a,0x00,0x3c,0x04,0xb0,0x00,0x00,0xe4,0x20,0x21,0x8c,0x83,0x00,0x0c, +0x00,0x11,0x98,0xc0,0x02,0x71,0x10,0x21,0x00,0x03,0x1b,0x82,0x30,0x63,0x00,0x1f, +0x00,0x02,0x10,0x80,0x27,0x9e,0x8f,0xf4,0x00,0x5e,0x10,0x21,0x00,0x60,0x30,0x21, +0xac,0x44,0x00,0x18,0xae,0x43,0x02,0xbc,0x14,0xc0,0x00,0x10,0x3c,0x02,0xb0,0x00, +0x00,0x08,0x10,0xc0,0x00,0x48,0x10,0x21,0x27,0x84,0x8f,0xf0,0x00,0x02,0x10,0x80, +0x00,0x44,0x10,0x21,0x94,0x45,0x00,0x00,0x02,0x71,0x18,0x21,0x00,0x03,0x18,0x80, +0x00,0x64,0x18,0x21,0x24,0x02,0xff,0xff,0xa4,0x62,0x00,0x02,0xa4,0x68,0x00,0x04, +0xae,0x51,0x02,0xb8,0xa6,0x45,0x00,0x0a,0x3c,0x02,0xb0,0x00,0x00,0xe2,0x40,0x21, +0x8d,0x16,0x00,0x00,0x8d,0x14,0x00,0x04,0x02,0x71,0x10,0x21,0x00,0x02,0x38,0x80, +0x00,0x14,0x1a,0x02,0x27,0x84,0x90,0x00,0x30,0x63,0x00,0x1f,0x24,0x02,0x00,0x10, +0x00,0xe4,0x20,0x21,0xa6,0x43,0x00,0x06,0x8d,0x10,0x00,0x08,0xa0,0x82,0x00,0x06, +0x86,0x45,0x00,0x06,0x00,0xfe,0x10,0x21,0x24,0x03,0x00,0x13,0x10,0xa3,0x01,0x15, +0xac,0x48,0x00,0x18,0x3c,0x03,0xb0,0x03,0x34,0x63,0x01,0x00,0xa6,0x40,0x00,0x02, +0x3c,0x02,0xb0,0x03,0x90,0x64,0x00,0x00,0x34,0x42,0x01,0x08,0x8c,0x45,0x00,0x00, +0x00,0x10,0x1b,0xc2,0x27,0x82,0x8f,0xf0,0x00,0x04,0x20,0x82,0x00,0xe2,0x10,0x21, +0x30,0x63,0x00,0x01,0xac,0x45,0x00,0x08,0x10,0x60,0x00,0xec,0x30,0x97,0x00,0x01, +0x00,0x10,0x16,0x82,0x30,0x46,0x00,0x01,0x00,0x10,0x12,0x02,0x00,0x10,0x19,0xc2, +0x00,0x10,0x26,0x02,0x00,0x10,0x2e,0x42,0x30,0x47,0x00,0x7f,0x24,0x02,0x00,0x01, +0x30,0x75,0x00,0x01,0x30,0x84,0x00,0x01,0x10,0xc2,0x00,0xd9,0x30,0xa3,0x00,0x01, +0x0c,0x00,0x19,0x00,0x00,0x60,0x28,0x21,0x02,0x71,0x18,0x21,0x00,0x03,0x18,0x80, +0x2c,0x46,0x00,0x54,0x27,0x85,0x90,0x00,0x27,0x84,0x8f,0xf8,0x00,0x06,0x10,0x0a, +0x00,0x65,0x28,0x21,0x26,0xa6,0x00,0x02,0x00,0x64,0x18,0x21,0xa0,0xa2,0x00,0x02, +0xa0,0x66,0x00,0x06,0xa0,0x62,0x00,0x07,0xa0,0xa2,0x00,0x01,0x02,0x71,0x20,0x21, +0x00,0x04,0x20,0x80,0x00,0x9e,0x60,0x21,0x8d,0x85,0x00,0x18,0x00,0x10,0x15,0xc2, +0x30,0x42,0x00,0x01,0x8c,0xa3,0x00,0x0c,0xa6,0x42,0x00,0x00,0x27,0x82,0x90,0x10, +0x00,0x82,0x50,0x21,0xa6,0x56,0x00,0x04,0x8d,0x45,0x00,0x00,0x00,0x03,0x19,0x42, +0x3c,0x02,0xff,0xef,0x34,0x42,0xff,0xff,0x30,0x63,0x00,0x01,0x00,0xa2,0x48,0x24, +0x00,0x03,0x1d,0x00,0x01,0x23,0x48,0x25,0x00,0x09,0x15,0x02,0x26,0xc5,0x00,0x10, +0x00,0x14,0x19,0x82,0x00,0x14,0x25,0x82,0x00,0x10,0x34,0x02,0x00,0x10,0x3c,0x42, +0x00,0x10,0x44,0x82,0x30,0x42,0x00,0x01,0x30,0xb5,0xff,0xff,0x30,0xce,0x00,0x01, +0x30,0xe5,0x00,0x01,0x30,0x6d,0x00,0x01,0x30,0x8b,0x00,0x03,0x32,0x94,0x00,0x07, +0x31,0x06,0x00,0x01,0xad,0x49,0x00,0x00,0x10,0x40,0x00,0x0b,0x32,0x07,0x00,0x7f, +0x8d,0x84,0x00,0x18,0x3c,0x03,0xff,0xf0,0x34,0x63,0xff,0xff,0x8c,0x82,0x00,0x0c, +0x01,0x23,0x18,0x24,0x00,0x02,0x13,0x82,0x30,0x42,0x00,0x0f,0x00,0x02,0x14,0x00, +0x00,0x62,0x18,0x25,0xad,0x43,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xc2,0x00,0x90, +0x00,0x00,0x00,0x00,0x15,0xa0,0x00,0x03,0x00,0x00,0x00,0x00,0x15,0x60,0x00,0x81, +0x24,0x02,0x00,0x01,0x96,0x42,0x00,0x04,0x00,0x00,0x00,0x00,0x24,0x42,0x00,0x04, +0xa6,0x42,0x00,0x04,0x0c,0x00,0x19,0x00,0x01,0xc0,0x20,0x21,0x02,0x71,0x18,0x21, +0x00,0x03,0x38,0x80,0x2c,0x45,0x00,0x54,0x27,0x84,0x90,0x00,0x00,0xe4,0x20,0x21, +0x00,0x05,0x10,0x0a,0xa0,0x82,0x00,0x00,0xa0,0x80,0x00,0x04,0xa0,0x80,0x00,0x05, +0x96,0x45,0x00,0x04,0x27,0x82,0x8f,0xf0,0x00,0xe2,0x10,0x21,0xa4,0x45,0x00,0x06, +0x00,0xfe,0x18,0x21,0x92,0x45,0x00,0x01,0x8c,0x66,0x00,0x18,0x27,0x82,0x90,0x10, +0x00,0xe2,0x10,0x21,0xa0,0x40,0x00,0x00,0xa0,0x85,0x00,0x07,0x94,0xc3,0x00,0x10, +0x24,0x02,0x00,0x04,0x30,0x63,0x00,0x0f,0x10,0x62,0x00,0x5e,0x24,0xc6,0x00,0x10, +0x94,0xc3,0x00,0x16,0x27,0x85,0x90,0x08,0x00,0xe5,0x10,0x21,0xa4,0x43,0x00,0x02, +0x94,0xc2,0x00,0x04,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x01,0x14,0x40,0x00,0x4c, +0x02,0x71,0x20,0x21,0x94,0xc2,0x00,0x00,0x24,0x03,0x00,0xa4,0x30,0x42,0x00,0xff, +0x10,0x43,0x00,0x47,0x00,0x00,0x00,0x00,0x94,0xc2,0x00,0x00,0x24,0x03,0x00,0x88, +0x30,0x42,0x00,0x88,0x10,0x43,0x00,0x3c,0x02,0x71,0x18,0x21,0x27,0x84,0x90,0x10, +0x00,0x03,0x18,0x80,0x00,0x64,0x18,0x21,0x8c,0x62,0x00,0x00,0x3c,0x04,0x00,0x80, +0x00,0x44,0x10,0x25,0xac,0x62,0x00,0x00,0x02,0x71,0x10,0x21,0x00,0x02,0x10,0x80, +0x00,0x45,0x10,0x21,0xa0,0x54,0x00,0x00,0x92,0x43,0x02,0xbf,0x3c,0x02,0xb0,0x03, +0x34,0x42,0x00,0xc3,0xa0,0x43,0x00,0x00,0x8e,0x4b,0x02,0xbc,0x00,0x00,0x00,0x00, +0x11,0x60,0x00,0x1c,0x32,0xa2,0x00,0xff,0x00,0x15,0x1a,0x02,0x30,0x64,0xff,0xff, +0x38,0x42,0x00,0x00,0x24,0x65,0x00,0x01,0x00,0x82,0x28,0x0a,0x02,0x20,0x30,0x21, +0x10,0xa0,0x00,0x12,0x00,0x00,0x38,0x21,0x02,0x71,0x10,0x21,0x00,0x02,0x10,0x80, +0x27,0x83,0x8f,0xf0,0x00,0x43,0x20,0x21,0x24,0xa9,0xff,0xff,0x3c,0x0a,0xb0,0x08, +0x24,0x0c,0xff,0xff,0x00,0x06,0x10,0xc0,0x00,0x4a,0x10,0x21,0x8c,0x43,0x00,0x00, +0x24,0xe8,0x00,0x01,0x10,0xe9,0x00,0x0f,0x30,0x63,0x00,0xff,0x31,0x07,0xff,0xff, +0x00,0xe5,0x10,0x2b,0x14,0x40,0xff,0xf7,0x00,0x60,0x30,0x21,0x25,0x62,0xff,0xff, +0xae,0x42,0x02,0xbc,0x7b,0xbe,0x01,0xbc,0x7b,0xb6,0x01,0x7c,0x7b,0xb4,0x01,0x3c, +0x7b,0xb2,0x00,0xfc,0x7b,0xb0,0x00,0xbc,0x24,0x02,0x00,0x01,0x03,0xe0,0x00,0x08, +0x27,0xbd,0x00,0x38,0xa4,0x86,0x00,0x04,0xa4,0x8c,0x00,0x02,0xae,0x51,0x02,0xb8, +0x08,0x00,0x1a,0x2f,0xa6,0x43,0x00,0x0a,0x94,0xc2,0x00,0x18,0x00,0x00,0x00,0x00, +0x30,0x42,0x00,0x60,0x10,0x40,0xff,0xc1,0x02,0x71,0x18,0x21,0x02,0x71,0x20,0x21, +0x27,0x82,0x90,0x10,0x00,0x04,0x20,0x80,0x00,0x82,0x20,0x21,0x8c,0x83,0x00,0x00, +0x3c,0x02,0xff,0x7f,0x34,0x42,0xff,0xff,0x00,0x62,0x18,0x24,0x08,0x00,0x1a,0x0e, +0xac,0x83,0x00,0x00,0x27,0x85,0x90,0x08,0x00,0xe5,0x10,0x21,0x08,0x00,0x19,0xf8, +0xa4,0x40,0x00,0x02,0x11,0x62,0x00,0x07,0x00,0x00,0x00,0x00,0x2d,0x62,0x00,0x02, +0x14,0x40,0xff,0x80,0x00,0x00,0x00,0x00,0x96,0x42,0x00,0x04,0x08,0x00,0x19,0xd8, +0x24,0x42,0x00,0x0c,0x96,0x42,0x00,0x04,0x08,0x00,0x19,0xd8,0x24,0x42,0x00,0x08, +0x16,0xe6,0xff,0x70,0x3c,0x02,0xff,0xfb,0x8d,0x83,0x00,0x18,0x34,0x42,0xff,0xff, +0x02,0x02,0x10,0x24,0xac,0x62,0x00,0x08,0x08,0x00,0x19,0xd1,0x00,0x00,0x30,0x21, +0x16,0xe6,0xff,0x27,0x3c,0x02,0xfb,0xff,0x34,0x42,0xff,0xff,0x02,0x02,0x10,0x24, +0xad,0x02,0x00,0x08,0x08,0x00,0x19,0x90,0x00,0x00,0x30,0x21,0x93,0x88,0xbb,0x04, +0x00,0x10,0x1e,0x42,0x00,0x10,0x26,0x82,0x27,0x82,0x8f,0xf8,0x2d,0x05,0x00,0x0c, +0x00,0xe2,0x48,0x21,0x30,0x63,0x00,0x01,0x30,0x86,0x00,0x01,0x14,0xa0,0x00,0x06, +0x01,0x00,0x38,0x21,0x00,0x03,0x10,0x40,0x00,0x46,0x10,0x21,0x00,0x02,0x11,0x00, +0x01,0x02,0x10,0x21,0x24,0x47,0x00,0x04,0x02,0x71,0x10,0x21,0x00,0x02,0x10,0x80, +0x27,0x84,0x90,0x00,0x27,0x83,0x8f,0xf8,0x00,0x44,0x20,0x21,0x00,0x43,0x10,0x21, +0xa1,0x27,0x00,0x07,0xa0,0x40,0x00,0x06,0xa0,0x80,0x00,0x02,0x08,0x00,0x19,0x9f, +0xa0,0x80,0x00,0x01,0x24,0x02,0x00,0x01,0xa6,0x42,0x00,0x02,0x0c,0x00,0x01,0xc4, +0x01,0x00,0x20,0x21,0x08,0x00,0x1a,0x35,0x00,0x00,0x00,0x00,0x27,0x9e,0x8f,0xf4, +0x08,0x00,0x19,0x52,0x00,0x11,0x3a,0x00,0x94,0x91,0x00,0x0a,0x08,0x00,0x19,0x39, +0x00,0x00,0x00,0x00,0x30,0xa9,0xff,0xff,0x00,0x09,0x18,0xc0,0x00,0x69,0x18,0x21, +0x3c,0x06,0xb0,0x03,0x3c,0x02,0x80,0x00,0x24,0x42,0x6a,0x54,0x00,0x03,0x18,0x80, +0x34,0xc6,0x00,0x20,0x27,0x85,0x90,0x00,0xac,0xc2,0x00,0x00,0x00,0x65,0x18,0x21, +0x80,0x62,0x00,0x07,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x32,0x24,0x88,0x00,0x06, +0x90,0x82,0x00,0x16,0x00,0x80,0x40,0x21,0x34,0x42,0x00,0x02,0x30,0x43,0x00,0x01, +0x14,0x60,0x00,0x02,0xa0,0x82,0x00,0x16,0xa0,0x80,0x00,0x17,0x95,0x03,0x00,0x02, +0x00,0x00,0x00,0x00,0x10,0x69,0x00,0x22,0x3c,0x02,0x34,0x34,0x91,0x02,0x00,0x04, +0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x06,0x00,0x03,0x20,0xc0,0x24,0x02,0x00,0x01, +0xa1,0x02,0x00,0x04,0xa5,0x09,0x00,0x02,0x03,0xe0,0x00,0x08,0xa5,0x09,0x00,0x00, +0x00,0x83,0x20,0x21,0x27,0x87,0x8f,0xf0,0x00,0x04,0x20,0x80,0x00,0x87,0x20,0x21, +0x94,0x83,0x00,0x04,0x3c,0x02,0xb0,0x08,0x3c,0x06,0xb0,0x03,0x00,0x03,0x28,0xc0, +0x00,0xa3,0x18,0x21,0x00,0x03,0x18,0x80,0x00,0xa2,0x28,0x21,0x3c,0x02,0x80,0x01, +0x24,0x42,0x82,0xe4,0x00,0x67,0x18,0x21,0x34,0xc6,0x00,0x20,0xac,0xc2,0x00,0x00, +0xa4,0x69,0x00,0x00,0xa4,0x89,0x00,0x02,0xac,0xa9,0x00,0x00,0x91,0x02,0x00,0x04, +0xa5,0x09,0x00,0x02,0x24,0x42,0x00,0x01,0x03,0xe0,0x00,0x08,0xa1,0x02,0x00,0x04, +0x3c,0x03,0xb0,0x03,0x34,0x63,0x00,0xb0,0x34,0x42,0x34,0x34,0x03,0xe0,0x00,0x08, +0xac,0x62,0x00,0x00,0x90,0x82,0x00,0x16,0x00,0x00,0x00,0x00,0x34,0x42,0x00,0x01, +0x30,0x43,0x00,0x02,0x14,0x60,0xff,0xd1,0xa0,0x82,0x00,0x16,0x24,0x02,0x00,0x01, +0x08,0x00,0x1a,0xab,0xa0,0x82,0x00,0x17,0x27,0xbd,0xff,0xe8,0xaf,0xbf,0x00,0x10, +0x00,0x80,0x38,0x21,0x84,0x84,0x00,0x02,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00, +0x3c,0x0a,0xb0,0x06,0x34,0x63,0x00,0x20,0x24,0x42,0x6b,0x78,0x3c,0x0b,0xb0,0x08, +0x27,0x89,0x8f,0xf0,0x34,0x0c,0xff,0xff,0x35,0x4a,0x80,0x20,0x10,0x80,0x00,0x30, +0xac,0x62,0x00,0x00,0x97,0x82,0x8f,0xe0,0x94,0xe6,0x02,0xba,0x00,0x02,0x18,0xc0, +0x00,0x6b,0x28,0x21,0xac,0xa6,0x00,0x00,0x8c,0xe4,0x02,0xb8,0x00,0x62,0x18,0x21, +0x00,0x03,0x18,0x80,0x00,0x04,0x10,0xc0,0x00,0x44,0x10,0x21,0x00,0x02,0x10,0x80, +0x00,0x49,0x10,0x21,0x94,0x48,0x00,0x04,0x00,0x69,0x18,0x21,0xa4,0x66,0x00,0x00, +0x00,0x08,0x28,0xc0,0x00,0xab,0x10,0x21,0xac,0x4c,0x00,0x00,0x8c,0xe4,0x02,0xb8, +0x27,0x82,0x8f,0xf4,0x00,0xa8,0x28,0x21,0x00,0x04,0x18,0xc0,0x00,0x64,0x18,0x21, +0x00,0x03,0x18,0x80,0x00,0x62,0x10,0x21,0x8c,0x46,0x00,0x18,0x27,0x84,0x90,0x00, +0x00,0x64,0x18,0x21,0x8c,0xc2,0x00,0x00,0x80,0x67,0x00,0x06,0x00,0x05,0x28,0x80, +0x30,0x42,0xff,0xff,0x00,0x47,0x10,0x21,0x30,0x43,0x00,0xff,0x00,0x03,0x18,0x2b, +0x00,0x02,0x12,0x02,0x00,0x43,0x10,0x21,0x3c,0x04,0x00,0x04,0x00,0xa9,0x28,0x21, +0x00,0x44,0x10,0x25,0xa4,0xac,0x00,0x00,0xad,0x42,0x00,0x00,0xa7,0x88,0x8f,0xe0, +0x8f,0xbf,0x00,0x10,0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18, +0x84,0xe3,0x00,0x06,0x27,0x82,0xb3,0xf0,0x94,0xe5,0x02,0xba,0x00,0x03,0x18,0x80, +0x00,0x62,0x18,0x21,0x8c,0x64,0x00,0x00,0x0c,0x00,0x1a,0x95,0x00,0x00,0x00,0x00, +0x08,0x00,0x1b,0x18,0x00,0x00,0x00,0x00,0x94,0x88,0x00,0x00,0x00,0x80,0x58,0x21, +0x27,0x8a,0x8f,0xf0,0x00,0x08,0x18,0xc0,0x00,0x68,0x18,0x21,0x3c,0x04,0xb0,0x03, +0x00,0x03,0x18,0x80,0x3c,0x02,0x80,0x00,0x00,0x6a,0x18,0x21,0x34,0x84,0x00,0x20, +0x24,0x42,0x6c,0x98,0x30,0xa5,0xff,0xff,0xac,0x82,0x00,0x00,0x94,0x67,0x00,0x02, +0x11,0x05,0x00,0x35,0x24,0x04,0x00,0x01,0x91,0x66,0x00,0x04,0x00,0x00,0x00,0x00, +0x00,0x86,0x10,0x2a,0x10,0x40,0x00,0x10,0x00,0xc0,0x48,0x21,0x3c,0x0d,0xb0,0x03, +0x01,0x40,0x60,0x21,0x35,0xad,0x00,0x20,0x10,0xe5,0x00,0x0d,0x24,0x84,0x00,0x01, +0x00,0x07,0x10,0xc0,0x00,0x47,0x10,0x21,0x00,0x02,0x10,0x80,0x01,0x20,0x30,0x21, +0x00,0x4a,0x10,0x21,0x00,0x86,0x18,0x2a,0x00,0xe0,0x40,0x21,0x94,0x47,0x00,0x02, +0x14,0x60,0xff,0xf5,0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x00,0x00,0x10,0x21, +0x00,0x08,0x20,0xc0,0x00,0x88,0x20,0x21,0x24,0xc2,0xff,0xff,0x00,0x04,0x20,0x80, +0xa1,0x62,0x00,0x04,0x00,0x8c,0x20,0x21,0x94,0x83,0x00,0x04,0x00,0x07,0x10,0xc0, +0x00,0x47,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x4c,0x10,0x21,0x00,0x03,0x28,0xc0, +0x94,0x46,0x00,0x02,0x00,0xa3,0x18,0x21,0x00,0x03,0x18,0x80,0x00,0x6c,0x18,0x21, +0xa4,0x66,0x00,0x00,0xa4,0x86,0x00,0x02,0x95,0x64,0x00,0x02,0x3c,0x03,0xb0,0x08, +0x3c,0x02,0x80,0x01,0x00,0xa3,0x28,0x21,0x24,0x42,0x82,0xe4,0xad,0xa2,0x00,0x00, +0x10,0x87,0x00,0x03,0xac,0xa6,0x00,0x00,0x03,0xe0,0x00,0x08,0x24,0x02,0x00,0x01, +0x08,0x00,0x1b,0x66,0xa5,0x68,0x00,0x02,0x91,0x62,0x00,0x04,0xa5,0x67,0x00,0x00, +0x24,0x42,0xff,0xff,0x30,0x43,0x00,0xff,0x14,0x60,0x00,0x03,0xa1,0x62,0x00,0x04, +0x24,0x02,0xff,0xff,0xa5,0x62,0x00,0x02,0x91,0x65,0x00,0x04,0x00,0x00,0x00,0x00, +0x10,0xa0,0xff,0xf1,0x00,0x00,0x00,0x00,0x95,0x66,0x00,0x00,0x34,0x02,0xff,0xff, +0x14,0xc2,0xff,0xed,0x3c,0x03,0xb0,0x03,0x95,0x64,0x00,0x02,0x3c,0x02,0xee,0xee, +0x00,0xa2,0x10,0x25,0x34,0x63,0x00,0xbc,0xac,0x62,0x00,0x00,0x10,0x86,0xff,0xe6, +0xa1,0x60,0x00,0x04,0x24,0x02,0xff,0xff,0x08,0x00,0x1b,0x66,0xa5,0x62,0x00,0x02, +0x00,0x05,0x40,0xc0,0x01,0x05,0x30,0x21,0x27,0xbd,0xff,0xd8,0x00,0x06,0x30,0x80, +0x27,0x82,0x8f,0xf4,0xaf,0xb2,0x00,0x18,0xaf,0xb1,0x00,0x14,0xaf,0xbf,0x00,0x20, +0xaf,0xb3,0x00,0x1c,0xaf,0xb0,0x00,0x10,0x00,0xc2,0x10,0x21,0x8c,0x47,0x00,0x18, +0x00,0xa0,0x90,0x21,0x3c,0x02,0x80,0x00,0x3c,0x05,0xb0,0x03,0x34,0xa5,0x00,0x20, +0x24,0x42,0x6e,0x10,0xac,0xa2,0x00,0x00,0x27,0x83,0x90,0x00,0x00,0xc3,0x30,0x21, +0x8c,0xe2,0x00,0x00,0x80,0xc5,0x00,0x06,0x00,0x80,0x88,0x21,0x30,0x42,0xff,0xff, +0x00,0x45,0x10,0x21,0x30,0x43,0x00,0xff,0x10,0x60,0x00,0x02,0x00,0x02,0x12,0x02, +0x24,0x42,0x00,0x01,0x30,0x53,0x00,0xff,0x01,0x12,0x10,0x21,0x00,0x02,0x10,0x80, +0x27,0x83,0x90,0x00,0x00,0x43,0x10,0x21,0x80,0x44,0x00,0x07,0x00,0x00,0x00,0x00, +0x10,0x80,0x00,0x4b,0x26,0x24,0x00,0x06,0x32,0x50,0xff,0xff,0x02,0x20,0x20,0x21, +0x0c,0x00,0x1b,0x26,0x02,0x00,0x28,0x21,0x92,0x22,0x00,0x10,0x00,0x00,0x00,0x00, +0x14,0x40,0x00,0x2e,0x3c,0x03,0xb0,0x08,0x3c,0x09,0x80,0x01,0x27,0x88,0x8f,0xf0, +0xa6,0x32,0x00,0x0c,0x00,0x10,0x20,0xc0,0x00,0x90,0x20,0x21,0x00,0x04,0x20,0x80, +0x00,0x88,0x20,0x21,0x94,0x82,0x00,0x04,0x3c,0x03,0xb0,0x08,0x3c,0x07,0xb0,0x03, +0x00,0x02,0x28,0xc0,0x00,0xa2,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x48,0x10,0x21, +0x00,0xa3,0x28,0x21,0x25,0x26,0x82,0xe4,0x34,0x03,0xff,0xff,0x34,0xe7,0x00,0x20, +0xac,0xe6,0x00,0x00,0xa4,0x83,0x00,0x02,0xa4,0x43,0x00,0x00,0xac,0xa3,0x00,0x00, +0x92,0x22,0x00,0x10,0x92,0x23,0x00,0x0a,0xa6,0x32,0x00,0x0e,0x02,0x62,0x10,0x21, +0x14,0x60,0x00,0x05,0xa2,0x22,0x00,0x10,0x92,0x22,0x00,0x16,0x00,0x00,0x00,0x00, +0x30,0x42,0x00,0xfe,0xa2,0x22,0x00,0x16,0x92,0x22,0x00,0x04,0x00,0x00,0x00,0x00, +0x14,0x40,0x00,0x05,0x00,0x00,0x00,0x00,0x92,0x22,0x00,0x16,0x00,0x00,0x00,0x00, +0x30,0x42,0x00,0xfd,0xa2,0x22,0x00,0x16,0x8f,0xbf,0x00,0x20,0x7b,0xb2,0x00,0xfc, +0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x28,0x96,0x22,0x00,0x0e, +0x27,0x88,0x8f,0xf0,0x00,0x02,0x20,0xc0,0x00,0x82,0x20,0x21,0x00,0x04,0x20,0x80, +0x00,0x88,0x20,0x21,0x94,0x82,0x00,0x04,0x3c,0x06,0xb0,0x03,0x3c,0x09,0x80,0x01, +0x00,0x02,0x28,0xc0,0x00,0xa2,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0xa3,0x28,0x21, +0x00,0x48,0x10,0x21,0x34,0xc6,0x00,0x20,0x25,0x23,0x82,0xe4,0xac,0xc3,0x00,0x00, +0xa4,0x50,0x00,0x00,0xac,0xb0,0x00,0x00,0x08,0x00,0x1b,0xb5,0xa4,0x90,0x00,0x02, +0x08,0x00,0x1b,0xac,0x32,0x50,0xff,0xff,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00, +0x24,0x42,0x6f,0xd8,0x34,0x63,0x00,0x20,0xac,0x62,0x00,0x00,0x90,0x82,0x00,0x04, +0x97,0xaa,0x00,0x12,0x00,0x80,0x60,0x21,0x30,0xa8,0xff,0xff,0x00,0x4a,0x20,0x23, +0x34,0x09,0xff,0xff,0x30,0xcf,0xff,0xff,0x30,0xee,0xff,0xff,0x11,0x09,0x00,0x73, +0xa1,0x84,0x00,0x04,0x00,0x0e,0xc0,0xc0,0x00,0x08,0x10,0xc0,0x00,0x48,0x10,0x21, +0x03,0x0e,0x20,0x21,0x27,0x8d,0x8f,0xf0,0x00,0x04,0x20,0x80,0x00,0x02,0x10,0x80, +0x00,0x4d,0x10,0x21,0x00,0x8d,0x20,0x21,0x94,0x86,0x00,0x02,0x94,0x43,0x00,0x04, +0x3c,0x19,0x80,0x01,0xa4,0x46,0x00,0x02,0x00,0x03,0x28,0xc0,0x00,0xa3,0x18,0x21, +0x94,0x87,0x00,0x02,0x3c,0x02,0xb0,0x08,0x00,0x03,0x18,0x80,0x00,0xa2,0x28,0x21, +0x00,0x6d,0x18,0x21,0x27,0x22,0x82,0xe4,0x3c,0x01,0xb0,0x03,0xac,0x22,0x00,0x20, +0xa4,0x66,0x00,0x00,0x10,0xe9,0x00,0x57,0xac,0xa6,0x00,0x00,0x01,0xe0,0x30,0x21, +0x11,0x40,0x00,0x1d,0x00,0x00,0x48,0x21,0x01,0x40,0x38,0x21,0x27,0x8b,0x8f,0xf4, +0x27,0x8a,0x90,0x00,0x00,0x06,0x40,0xc0,0x01,0x06,0x18,0x21,0x00,0x03,0x18,0x80, +0x00,0x6b,0x10,0x21,0x8c,0x44,0x00,0x18,0x00,0x6a,0x18,0x21,0x80,0x65,0x00,0x06, +0x8c,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x42,0xff,0xff,0x00,0x45,0x10,0x21, +0x30,0x44,0x00,0xff,0x00,0x02,0x12,0x02,0x01,0x22,0x18,0x21,0x24,0x62,0x00,0x01, +0x14,0x80,0x00,0x02,0x30,0x49,0x00,0xff,0x30,0x69,0x00,0xff,0x01,0x06,0x10,0x21, +0x00,0x02,0x10,0x80,0x00,0x4d,0x10,0x21,0x24,0xe7,0xff,0xff,0x94,0x46,0x00,0x02, +0x14,0xe0,0xff,0xe9,0x00,0x06,0x40,0xc0,0x91,0x82,0x00,0x10,0x00,0x00,0x00,0x00, +0x14,0x40,0x00,0x20,0x3c,0x06,0xb0,0x03,0xa5,0x8f,0x00,0x0c,0x03,0x0e,0x20,0x21, +0x00,0x04,0x20,0x80,0x00,0x8d,0x20,0x21,0x94,0x82,0x00,0x04,0x3c,0x03,0xb0,0x08, +0x3c,0x07,0xb0,0x03,0x00,0x02,0x28,0xc0,0x00,0xa2,0x10,0x21,0x00,0x02,0x10,0x80, +0x00,0x4d,0x10,0x21,0x00,0xa3,0x28,0x21,0x27,0x26,0x82,0xe4,0x34,0x03,0xff,0xff, +0x34,0xe7,0x00,0x20,0xac,0xe6,0x00,0x00,0xa4,0x83,0x00,0x02,0xa4,0x43,0x00,0x00, +0xac,0xa3,0x00,0x00,0x91,0x82,0x00,0x10,0x91,0x83,0x00,0x04,0xa5,0x8e,0x00,0x0e, +0x01,0x22,0x10,0x21,0x14,0x60,0x00,0x05,0xa1,0x82,0x00,0x10,0x91,0x82,0x00,0x16, +0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xfd,0xa1,0x82,0x00,0x16,0x03,0xe0,0x00,0x08, +0x00,0x00,0x00,0x00,0x95,0x82,0x00,0x0e,0x3c,0x03,0xb0,0x08,0x00,0x02,0x20,0xc0, +0x00,0x82,0x20,0x21,0x00,0x04,0x20,0x80,0x00,0x8d,0x20,0x21,0x94,0x82,0x00,0x04, +0x34,0xc6,0x00,0x20,0x27,0x27,0x82,0xe4,0x00,0x02,0x28,0xc0,0x00,0xa2,0x10,0x21, +0x00,0x02,0x10,0x80,0x00,0xa3,0x28,0x21,0x00,0x4d,0x10,0x21,0xac,0xc7,0x00,0x00, +0xa4,0x8f,0x00,0x02,0xa4,0x4f,0x00,0x00,0xac,0xaf,0x00,0x00,0x08,0x00,0x1c,0x44, +0x03,0x0e,0x20,0x21,0x08,0x00,0x1c,0x1f,0xa5,0x88,0x00,0x02,0x00,0x0e,0xc0,0xc0, +0x03,0x0e,0x10,0x21,0x00,0x02,0x10,0x80,0x27,0x8d,0x8f,0xf0,0x00,0x4d,0x10,0x21, +0x94,0x43,0x00,0x02,0x30,0x84,0x00,0xff,0x14,0x80,0x00,0x05,0xa5,0x83,0x00,0x00, +0x24,0x02,0xff,0xff,0x3c,0x19,0x80,0x01,0x08,0x00,0x1c,0x1f,0xa5,0x82,0x00,0x02, +0x08,0x00,0x1c,0x1f,0x3c,0x19,0x80,0x01,0x3c,0x08,0xb0,0x03,0x3c,0x02,0x80,0x00, +0x27,0xbd,0xff,0x78,0x35,0x08,0x00,0x20,0x24,0x42,0x72,0x18,0xaf,0xb2,0x00,0x68, +0xaf,0xb1,0x00,0x64,0xaf,0xb0,0x00,0x60,0xad,0x02,0x00,0x00,0xaf,0xbf,0x00,0x84, +0xaf,0xbe,0x00,0x80,0xaf,0xb7,0x00,0x7c,0xaf,0xb6,0x00,0x78,0xaf,0xb5,0x00,0x74, +0xaf,0xb4,0x00,0x70,0xaf,0xb3,0x00,0x6c,0xaf,0xa4,0x00,0x88,0x90,0x83,0x00,0x0a, +0x27,0x82,0xb3,0xf0,0xaf,0xa6,0x00,0x90,0x00,0x03,0x18,0x80,0x00,0x62,0x18,0x21, +0x8c,0x63,0x00,0x00,0xaf,0xa7,0x00,0x94,0x27,0x86,0x8f,0xf4,0xaf,0xa3,0x00,0x1c, +0x94,0x63,0x00,0x14,0x30,0xb1,0xff,0xff,0x24,0x08,0x00,0x01,0x00,0x03,0x20,0xc0, +0xaf,0xa3,0x00,0x18,0x00,0x83,0x18,0x21,0xaf,0xa4,0x00,0x54,0x00,0x03,0x18,0x80, +0x27,0x84,0x90,0x00,0x00,0x64,0x20,0x21,0x80,0x82,0x00,0x06,0x00,0x66,0x18,0x21, +0x8c,0x66,0x00,0x18,0x24,0x42,0x00,0x02,0x00,0x02,0x1f,0xc2,0x8c,0xc4,0x00,0x08, +0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x43,0x00,0x02,0x10,0x40,0x00,0x04,0x2f,0xc2, +0x00,0x04,0x1c,0x82,0x00,0xc2,0x38,0x21,0x00,0x04,0x24,0x42,0x8f,0xa2,0x00,0x1c, +0x30,0x63,0x00,0x01,0x30,0x84,0x00,0x01,0xaf,0xa5,0x00,0x3c,0xaf,0xa3,0x00,0x34, +0xaf,0xa4,0x00,0x38,0xaf,0xa0,0x00,0x40,0xaf,0xa0,0x00,0x44,0xaf,0xa0,0x00,0x50, +0xaf,0xa8,0x00,0x20,0x80,0x42,0x00,0x12,0x8f,0xb2,0x00,0x18,0xaf,0xa2,0x00,0x28, +0x8c,0xd0,0x00,0x0c,0x14,0xa0,0x01,0xe4,0x00,0x60,0x30,0x21,0x00,0x10,0x10,0x82, +0x30,0x45,0x00,0x07,0x10,0xa0,0x00,0x11,0xaf,0xa0,0x00,0x30,0x8f,0xa4,0x00,0x98, +0x27,0x82,0x80,0x1c,0x00,0x04,0x18,0x40,0x00,0x62,0x18,0x21,0x24,0xa2,0x00,0x06, +0x8f,0xa5,0x00,0x20,0x94,0x64,0x00,0x00,0x00,0x45,0x10,0x04,0x00,0x44,0x00,0x1a, +0x14,0x80,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x0d,0x00,0x00,0x10,0x12, +0x24,0x42,0x00,0x20,0x30,0x42,0xff,0xfc,0xaf,0xa2,0x00,0x30,0x8f,0xa3,0x00,0x18, +0x8f,0xa4,0x00,0x28,0x34,0x02,0xff,0xff,0xaf,0xa0,0x00,0x2c,0xaf,0xa2,0x00,0x48, +0xaf,0xa3,0x00,0x4c,0x00,0x60,0xf0,0x21,0x00,0x00,0xb8,0x21,0x18,0x80,0x00,0x48, +0xaf,0xa0,0x00,0x24,0x00,0x11,0x89,0x02,0xaf,0xb1,0x00,0x58,0x00,0x80,0xa8,0x21, +0x00,0x12,0x10,0xc0,0x00,0x52,0x18,0x21,0x00,0x03,0x80,0x80,0x27,0x85,0x8f,0xf0, +0x02,0x40,0x20,0x21,0x00,0x40,0xa0,0x21,0x02,0x05,0x10,0x21,0x94,0x56,0x00,0x02, +0x0c,0x00,0x12,0x87,0x00,0x00,0x28,0x21,0x90,0x42,0x00,0x00,0x24,0x03,0x00,0x08, +0x30,0x42,0x00,0x0c,0x10,0x43,0x01,0x9e,0x24,0x04,0x00,0x01,0x24,0x02,0x00,0x01, +0x10,0x82,0x01,0x7c,0x3c,0x02,0xb0,0x03,0x8f,0xa6,0x00,0x88,0x34,0x42,0x01,0x04, +0x84,0xc5,0x00,0x0c,0x02,0x92,0x18,0x21,0x94,0x46,0x00,0x00,0x00,0x05,0x20,0xc0, +0x00,0x85,0x20,0x21,0x00,0x03,0x18,0x80,0x27,0x82,0x90,0x00,0x27,0x85,0x8f,0xf8, +0x00,0x65,0x28,0x21,0x00,0x62,0x18,0x21,0x80,0x71,0x00,0x05,0x80,0x73,0x00,0x04, +0x8f,0xa3,0x00,0x88,0x30,0xd0,0xff,0xff,0x00,0x10,0x3a,0x03,0x32,0x08,0x00,0xff, +0x27,0x82,0x90,0x10,0x00,0x04,0x20,0x80,0x80,0xa6,0x00,0x06,0x00,0x82,0x20,0x21, +0xa4,0x67,0x00,0x44,0xa4,0x68,0x00,0x46,0x8c,0x84,0x00,0x00,0x38,0xc6,0x00,0x00, +0x01,0x00,0x80,0x21,0x00,0x04,0x15,0x02,0x30,0x42,0x00,0x01,0x10,0x40,0x00,0x03, +0x00,0xe6,0x80,0x0a,0x00,0x04,0x14,0x02,0x30,0x50,0x00,0x0f,0x12,0x20,0x01,0x50, +0x02,0x40,0x20,0x21,0x02,0x71,0x10,0x21,0x00,0x50,0x10,0x2a,0x14,0x40,0x00,0xed, +0x02,0x92,0x10,0x21,0x93,0x82,0x8b,0x61,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x01, +0x14,0x40,0x00,0xe0,0x02,0x92,0x28,0x21,0x26,0xe2,0x00,0x01,0x30,0x57,0xff,0xff, +0x02,0x40,0xf0,0x21,0x26,0xb5,0xff,0xff,0x16,0xa0,0xff,0xbd,0x02,0xc0,0x90,0x21, +0x16,0xe0,0x00,0xd0,0x00,0x00,0x00,0x00,0x8f,0xa3,0x00,0x98,0x00,0x00,0x00,0x00, +0x2c,0x62,0x00,0x10,0x10,0x40,0x00,0x2e,0x00,0x00,0x00,0x00,0x8f,0xa4,0x00,0x24, +0x00,0x00,0x00,0x00,0x18,0x80,0x00,0x2a,0x24,0x03,0x00,0x01,0x8f,0xa5,0x00,0x1c, +0x27,0x84,0x8f,0xf4,0x94,0xb2,0x00,0x14,0xa0,0xa3,0x00,0x12,0x8f,0xa6,0x00,0x3c, +0x00,0x12,0x10,0xc0,0x00,0x52,0x10,0x21,0x00,0x02,0x80,0x80,0x27,0x82,0x90,0x00, +0x02,0x02,0x10,0x21,0x80,0x43,0x00,0x06,0x02,0x04,0x20,0x21,0x8c,0x85,0x00,0x18, +0x24,0x63,0x00,0x02,0x00,0x03,0x17,0xc2,0x00,0x62,0x18,0x21,0x00,0x03,0x18,0x43, +0x00,0x03,0x18,0x40,0x14,0xc0,0x00,0x0e,0x00,0xa3,0x38,0x21,0x27,0x82,0x8f,0xf0, +0x02,0x02,0x10,0x21,0x94,0x43,0x00,0x06,0x8f,0xa8,0x00,0x1c,0x24,0x02,0x00,0x01, +0xa5,0x03,0x00,0x1a,0x7b,0xbe,0x04,0x3c,0x7b,0xb6,0x03,0xfc,0x7b,0xb4,0x03,0xbc, +0x7b,0xb2,0x03,0x7c,0x7b,0xb0,0x03,0x3c,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x88, +0x8f,0xa4,0x00,0x98,0x8f,0xa5,0x00,0x38,0x8f,0xa6,0x00,0x34,0xaf,0xa0,0x00,0x10, +0x0c,0x00,0x09,0x06,0xaf,0xa0,0x00,0x14,0x08,0x00,0x1d,0x4b,0x00,0x00,0x00,0x00, +0x8f,0xa3,0x00,0x44,0x93,0x82,0x81,0x59,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x61, +0x30,0x69,0x00,0x03,0x8f,0xa4,0x00,0x24,0x8f,0xa5,0x00,0x28,0x00,0x00,0x00,0x00, +0x00,0x85,0x10,0x2a,0x10,0x40,0x00,0x8f,0x00,0x00,0x00,0x00,0x8f,0xa6,0x00,0x1c, +0x00,0x00,0x00,0x00,0x90,0xc4,0x00,0x04,0x00,0x00,0x00,0x00,0x30,0x83,0x00,0xff, +0x00,0xa3,0x10,0x2a,0x10,0x40,0x00,0x87,0x00,0x00,0x00,0x00,0x8f,0xa8,0x00,0x24, +0x00,0x00,0x00,0x00,0x11,0x00,0x00,0x83,0x00,0x65,0x10,0x23,0x00,0xa8,0x18,0x23, +0x00,0x62,0x10,0x2a,0x14,0x40,0x00,0x7d,0x30,0x63,0x00,0xff,0x00,0x85,0x10,0x23, +0x30,0x42,0x00,0xff,0xaf,0xa2,0x00,0x50,0x8f,0xa2,0x00,0x50,0x00,0x00,0x00,0x00, +0x10,0x40,0x00,0x73,0x00,0x00,0xa8,0x21,0x27,0x8c,0x8f,0xf0,0x3c,0x0b,0x80,0xff, +0x24,0x10,0x00,0x04,0x27,0x91,0x8f,0xf4,0x35,0x6b,0xff,0xff,0x3c,0x0d,0x7f,0x00, +0x27,0x8e,0x90,0x00,0x01,0x80,0x78,0x21,0x00,0x12,0x30,0xc0,0x00,0xd2,0x10,0x21, +0x00,0x02,0x10,0x80,0x00,0x4c,0x10,0x21,0x94,0x42,0x00,0x06,0x8f,0xa3,0x00,0x2c, +0x8f,0xa4,0x00,0x30,0xaf,0xa2,0x00,0x44,0x8f,0xa5,0x00,0x44,0x30,0x49,0x00,0x03, +0x02,0x09,0x10,0x23,0x30,0x42,0x00,0x03,0x00,0xa2,0x10,0x21,0x8f,0xa8,0x00,0x30, +0x24,0x42,0x00,0x04,0x30,0x42,0xff,0xff,0x00,0x64,0x38,0x21,0x01,0x02,0x28,0x23, +0x00,0x62,0x18,0x21,0x00,0x48,0x10,0x2b,0x10,0x40,0x00,0x52,0x00,0x00,0x20,0x21, +0x30,0xe7,0xff,0xff,0x30,0xa4,0xff,0xff,0xaf,0xa7,0x00,0x2c,0x00,0xd2,0x10,0x21, +0x00,0x02,0x10,0x80,0x00,0x51,0x18,0x21,0x8c,0x65,0x00,0x18,0x00,0x04,0x25,0x40, +0x00,0x8d,0x20,0x24,0x8c,0xa8,0x00,0x04,0x00,0x4e,0x18,0x21,0x00,0x4f,0x50,0x21, +0x01,0x0b,0x40,0x24,0x01,0x04,0x40,0x25,0xac,0xa8,0x00,0x04,0x8f,0xa4,0x00,0x98, +0x8f,0xa2,0x00,0x50,0x26,0xb5,0x00,0x01,0xa0,0x64,0x00,0x00,0x8c,0xa4,0x00,0x08, +0x00,0x00,0x00,0x00,0x04,0x81,0x00,0x0c,0x02,0xa2,0x30,0x2a,0x80,0x62,0x00,0x06, +0x00,0x00,0x00,0x00,0x24,0x42,0x00,0x02,0x00,0x02,0x1f,0xc2,0x00,0x43,0x10,0x21, +0x00,0x02,0x10,0x43,0x00,0x02,0x10,0x40,0x00,0xa2,0x38,0x21,0x8f,0xa5,0x00,0x40, +0x00,0x00,0x00,0x00,0xa4,0xe5,0x00,0x00,0x95,0x52,0x00,0x02,0x14,0xc0,0xff,0xc7, +0x00,0x12,0x30,0xc0,0x8f,0xa4,0x00,0x24,0x8f,0xa5,0x00,0x50,0x8f,0xa6,0x00,0x1c, +0x8f,0xa3,0x00,0x2c,0x00,0x85,0x80,0x21,0xa0,0xd0,0x00,0x12,0x00,0x09,0x10,0x23, +0x30,0x42,0x00,0x03,0x8f,0xa8,0x00,0x88,0x00,0x62,0x10,0x23,0xa4,0xc2,0x00,0x1a, +0x85,0x03,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21, +0x00,0x02,0x10,0x80,0x27,0x83,0x8f,0xf4,0x00,0x43,0x10,0x21,0x8c,0x44,0x00,0x18, +0x00,0x00,0x00,0x00,0x8c,0x83,0x00,0x04,0x00,0x00,0x00,0x00,0x30,0x63,0x00,0x10, +0x14,0x60,0xff,0x74,0x02,0x00,0x10,0x21,0x8f,0xa3,0x00,0x54,0x8f,0xa4,0x00,0x18, +0x8f,0xa5,0x00,0x24,0x00,0x64,0x10,0x21,0x00,0x02,0x10,0x80,0x27,0x83,0x90,0x08, +0x00,0x43,0x10,0x21,0x90,0x44,0x00,0x00,0x10,0xa0,0x00,0x03,0x00,0x00,0x30,0x21, +0x08,0x00,0x1d,0x51,0x02,0x00,0x10,0x21,0x93,0x82,0x80,0x10,0x00,0x00,0x28,0x21, +0x00,0x00,0x38,0x21,0x0c,0x00,0x21,0xf5,0xaf,0xa2,0x00,0x10,0x08,0x00,0x1d,0x51, +0x02,0x00,0x10,0x21,0x30,0x63,0xff,0xff,0x08,0x00,0x1d,0xa3,0xaf,0xa3,0x00,0x2c, +0x8f,0xa8,0x00,0x44,0x08,0x00,0x1d,0xc5,0x31,0x09,0x00,0x03,0x08,0x00,0x1d,0x7e, +0xaf,0xa3,0x00,0x50,0x8f,0xa6,0x00,0x44,0xaf,0xa0,0x00,0x50,0x08,0x00,0x1d,0xc5, +0x30,0xc9,0x00,0x03,0x8f,0xa5,0x00,0x48,0x8f,0xa6,0x00,0x4c,0x8f,0xa4,0x00,0x1c, +0x03,0xc0,0x38,0x21,0x0c,0x00,0x1b,0xf6,0xaf,0xb7,0x00,0x10,0x08,0x00,0x1d,0x2e, +0x00,0x00,0x00,0x00,0x00,0x05,0x28,0x80,0x27,0x82,0x8f,0xf0,0x00,0xa2,0x28,0x21, +0x00,0x00,0x20,0x21,0x0c,0x00,0x01,0x4b,0x00,0x00,0x00,0x00,0x08,0x00,0x1d,0x27, +0x26,0xe2,0x00,0x01,0x00,0x02,0x80,0x80,0x27,0x83,0x90,0x00,0x8f,0xa4,0x00,0x1c, +0x02,0x03,0x18,0x21,0x26,0x31,0x00,0x01,0x02,0x40,0x28,0x21,0x0c,0x00,0x1f,0x08, +0xa0,0x71,0x00,0x05,0x14,0x40,0xff,0x13,0x00,0x00,0x00,0x00,0x16,0xe0,0x00,0x4d, +0x03,0xc0,0x38,0x21,0x8f,0xa4,0x00,0x24,0x8f,0xa5,0x00,0x20,0x24,0x02,0x00,0x01, +0x24,0x84,0x00,0x01,0xaf,0xb2,0x00,0x48,0xaf,0xb6,0x00,0x4c,0x02,0xc0,0xf0,0x21, +0x10,0xa2,0x00,0x41,0xaf,0xa4,0x00,0x24,0x27,0x82,0x8f,0xf0,0x02,0x02,0x10,0x21, +0x94,0x42,0x00,0x06,0x8f,0xa4,0x00,0x30,0xaf,0xa0,0x00,0x20,0xaf,0xa2,0x00,0x44, +0x30,0x49,0x00,0x03,0x8f,0xa8,0x00,0x44,0x00,0x09,0x10,0x23,0x30,0x42,0x00,0x03, +0x01,0x02,0x10,0x21,0x24,0x42,0x00,0x04,0x30,0x42,0xff,0xff,0x00,0x44,0x18,0x2b, +0x10,0x60,0x00,0x2b,0x00,0x00,0x00,0x00,0x8f,0xa5,0x00,0x2c,0x00,0x82,0x10,0x23, +0x00,0xa4,0x18,0x21,0x30,0x63,0xff,0xff,0x30,0x44,0xff,0xff,0xaf,0xa3,0x00,0x2c, +0x02,0x92,0x28,0x21,0x00,0x05,0x28,0x80,0x27,0x82,0x8f,0xf4,0x00,0xa2,0x10,0x21, +0x8c,0x46,0x00,0x18,0x3c,0x03,0x80,0xff,0x3c,0x02,0x7f,0x00,0x8c,0xc8,0x00,0x04, +0x00,0x04,0x25,0x40,0x34,0x63,0xff,0xff,0x00,0x82,0x20,0x24,0x01,0x03,0x40,0x24, +0x01,0x04,0x40,0x25,0xac,0xc8,0x00,0x04,0x8f,0xa8,0x00,0x98,0x27,0x82,0x90,0x00, +0x00,0xa2,0x10,0x21,0xa0,0x48,0x00,0x00,0x8c,0xc4,0x00,0x08,0x00,0x00,0x00,0x00, +0x00,0x04,0x27,0xc2,0x10,0x80,0xfe,0xdb,0xaf,0xa4,0x00,0x3c,0x80,0x42,0x00,0x06, +0x00,0x00,0x00,0x00,0x24,0x42,0x00,0x02,0x00,0x02,0x1f,0xc2,0x00,0x43,0x10,0x21, +0x00,0x02,0x10,0x43,0x00,0x02,0x10,0x40,0x00,0xc2,0x38,0x21,0x8f,0xa2,0x00,0x40, +0x00,0x00,0x00,0x00,0xa4,0xe2,0x00,0x00,0x08,0x00,0x1d,0x2a,0x26,0xb5,0xff,0xff, +0x8f,0xa6,0x00,0x2c,0x00,0x00,0x20,0x21,0x00,0xc2,0x10,0x21,0x30,0x42,0xff,0xff, +0x08,0x00,0x1e,0x38,0xaf,0xa2,0x00,0x2c,0x8f,0xa6,0x00,0x1c,0x08,0x00,0x1e,0x22, +0xa4,0xd2,0x00,0x14,0x8f,0xa5,0x00,0x48,0x8f,0xa6,0x00,0x4c,0x8f,0xa4,0x00,0x1c, +0x0c,0x00,0x1b,0xf6,0xaf,0xb7,0x00,0x10,0x08,0x00,0x1e,0x19,0x00,0x00,0xb8,0x21, +0x0c,0x00,0x12,0x87,0x00,0x00,0x28,0x21,0x00,0x40,0x18,0x21,0x94,0x42,0x00,0x00, +0x00,0x00,0x00,0x00,0x34,0x42,0x08,0x00,0xa4,0x62,0x00,0x00,0x08,0x00,0x1d,0x1e, +0x02,0x71,0x10,0x21,0x02,0x92,0x18,0x21,0x00,0x03,0x80,0x80,0x27,0x82,0x8f,0xf4, +0x02,0x02,0x10,0x21,0x8c,0x44,0x00,0x18,0x00,0x00,0x00,0x00,0x8c,0x83,0x00,0x04, +0x00,0x00,0x00,0x00,0x30,0x63,0x00,0x10,0x10,0x60,0x00,0x09,0x24,0x06,0x00,0x01, +0x93,0x82,0x8b,0x61,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x01,0x10,0x40,0xfe,0xa2, +0x3c,0x04,0x00,0x80,0x27,0x85,0x8f,0xf0,0x08,0x00,0x1e,0x09,0x02,0x05,0x28,0x21, +0x27,0x83,0x90,0x08,0x27,0x82,0x90,0x00,0x02,0x03,0x18,0x21,0x02,0x02,0x10,0x21, +0x90,0x64,0x00,0x00,0x90,0x45,0x00,0x05,0x93,0x83,0x80,0x10,0x00,0x00,0x38,0x21, +0x0c,0x00,0x21,0xf5,0xaf,0xa3,0x00,0x10,0x08,0x00,0x1e,0x80,0x00,0x00,0x00,0x00, +0x27,0x82,0x90,0x08,0x02,0x02,0x10,0x21,0x94,0x43,0x00,0x02,0x8f,0xa6,0x00,0x58, +0x00,0x03,0x19,0x02,0x00,0x66,0x18,0x23,0x30,0x63,0x0f,0xff,0x28,0x62,0x00,0x20, +0x10,0x40,0x00,0x06,0x28,0x62,0x00,0x40,0x8f,0xa8,0x00,0x90,0x00,0x00,0x00,0x00, +0x00,0x68,0x10,0x06,0x08,0x00,0x1c,0xf7,0x30,0x44,0x00,0x01,0x10,0x40,0x00,0x04, +0x00,0x00,0x00,0x00,0x8f,0xa4,0x00,0x94,0x08,0x00,0x1e,0xa1,0x00,0x64,0x10,0x06, +0x08,0x00,0x1c,0xf7,0x00,0x00,0x20,0x21,0x8f,0xa4,0x00,0x98,0x8f,0xa5,0x00,0x38, +0xaf,0xa0,0x00,0x10,0x0c,0x00,0x09,0x06,0xaf,0xa8,0x00,0x14,0x30,0x42,0xff,0xff, +0x08,0x00,0x1c,0xc7,0xaf,0xa2,0x00,0x40,0x3c,0x02,0xb0,0x03,0x3c,0x03,0x80,0x00, +0x27,0xbd,0xff,0xe0,0x34,0x42,0x00,0x20,0x24,0x63,0x7a,0xc8,0xaf,0xb1,0x00,0x14, +0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x18,0xac,0x43,0x00,0x00,0x90,0x82,0x00,0x0a, +0x00,0x80,0x80,0x21,0x14,0x40,0x00,0x45,0x00,0x00,0x88,0x21,0x92,0x02,0x00,0x04, +0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x3c,0x00,0x00,0x00,0x00,0x12,0x20,0x00,0x18, +0x00,0x00,0x00,0x00,0x92,0x02,0x00,0x16,0x92,0x05,0x00,0x0a,0x30,0x42,0x00,0xfc, +0x10,0xa0,0x00,0x03,0xa2,0x02,0x00,0x16,0x34,0x42,0x00,0x01,0xa2,0x02,0x00,0x16, +0x92,0x04,0x00,0x04,0x00,0x00,0x00,0x00,0x30,0x83,0x00,0xff,0x10,0x60,0x00,0x05, +0x00,0x00,0x00,0x00,0x92,0x02,0x00,0x16,0x00,0x00,0x00,0x00,0x34,0x42,0x00,0x02, +0xa2,0x02,0x00,0x16,0x10,0x60,0x00,0x0a,0x00,0x00,0x00,0x00,0x14,0xa0,0x00,0x08, +0x00,0x00,0x00,0x00,0x96,0x02,0x00,0x00,0xa2,0x00,0x00,0x17,0xa6,0x02,0x00,0x14, +0x8f,0xbf,0x00,0x18,0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20, +0x14,0x80,0x00,0x05,0x24,0x02,0x00,0x01,0x96,0x03,0x00,0x06,0xa2,0x02,0x00,0x17, +0x08,0x00,0x1e,0xdc,0xa6,0x03,0x00,0x14,0x96,0x04,0x00,0x00,0x96,0x05,0x00,0x06, +0x27,0x86,0x8f,0xf0,0x00,0x04,0x10,0xc0,0x00,0x05,0x18,0xc0,0x00,0x44,0x10,0x21, +0x00,0x65,0x18,0x21,0x00,0x02,0x10,0x80,0x00,0x03,0x18,0x80,0x00,0x66,0x18,0x21, +0x00,0x46,0x10,0x21,0x8c,0x65,0x00,0x08,0x8c,0x44,0x00,0x08,0x0c,0x00,0x12,0x78, +0x00,0x00,0x00,0x00,0x30,0x43,0x00,0xff,0x10,0x60,0x00,0x04,0xa2,0x02,0x00,0x17, +0x96,0x02,0x00,0x06,0x08,0x00,0x1e,0xdc,0xa6,0x02,0x00,0x14,0x96,0x02,0x00,0x00, +0x08,0x00,0x1e,0xdc,0xa6,0x02,0x00,0x14,0x96,0x05,0x00,0x00,0x0c,0x00,0x1f,0x08, +0x02,0x00,0x20,0x21,0x08,0x00,0x1e,0xc3,0x02,0x22,0x88,0x21,0x94,0x85,0x00,0x06, +0x0c,0x00,0x1f,0x08,0x00,0x00,0x00,0x00,0x08,0x00,0x1e,0xbf,0x00,0x40,0x88,0x21, +0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x34,0x63,0x00,0x20,0x24,0x42,0x7c,0x20, +0x27,0xbd,0xff,0xf0,0xac,0x62,0x00,0x00,0x00,0x00,0x10,0x21,0x03,0xe0,0x00,0x08, +0x27,0xbd,0x00,0x10,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x34,0x63,0x00,0x20, +0x24,0x42,0x7c,0x44,0xac,0x62,0x00,0x00,0x90,0x89,0x00,0x0a,0x00,0x80,0x30,0x21, +0x11,0x20,0x00,0x05,0x00,0xa0,0x50,0x21,0x90,0x82,0x00,0x17,0x00,0x00,0x00,0x00, +0x14,0x40,0x00,0x1b,0x00,0x00,0x00,0x00,0x90,0xc7,0x00,0x04,0x00,0x00,0x00,0x00, +0x10,0xe0,0x00,0x1b,0x00,0x00,0x00,0x00,0x94,0xc8,0x00,0x00,0x27,0x83,0x8f,0xf0, +0x93,0x85,0x8b,0x60,0x00,0x08,0x10,0xc0,0x00,0x48,0x10,0x21,0x00,0x02,0x10,0x80, +0x00,0x43,0x10,0x21,0x8c,0x44,0x00,0x08,0x00,0xe5,0x28,0x2b,0x10,0xa0,0x00,0x06, +0x01,0x44,0x18,0x23,0x8f,0x82,0x8b,0x78,0x00,0x00,0x00,0x00,0x00,0x43,0x10,0x2b, +0x10,0x40,0x00,0x05,0x00,0x00,0x00,0x00,0x24,0x03,0x00,0x10,0xa4,0xc8,0x00,0x14, +0x03,0xe0,0x00,0x08,0x00,0x60,0x10,0x21,0x11,0x20,0x00,0x05,0x00,0x00,0x00,0x00, +0x94,0xc2,0x00,0x06,0x24,0x03,0x00,0x08,0x08,0x00,0x1f,0x34,0xa4,0xc2,0x00,0x14, +0x08,0x00,0x1f,0x34,0x00,0x00,0x18,0x21,0x27,0xbd,0xff,0xc8,0xaf,0xb5,0x00,0x2c, +0xaf,0xb4,0x00,0x28,0xaf,0xb3,0x00,0x24,0xaf,0xb0,0x00,0x18,0xaf,0xbf,0x00,0x30, +0xaf,0xb2,0x00,0x20,0xaf,0xb1,0x00,0x1c,0x94,0x91,0x00,0x06,0x00,0x80,0xa0,0x21, +0x3c,0x02,0x80,0x00,0x3c,0x04,0xb0,0x03,0x00,0x11,0xa8,0xc0,0x34,0x84,0x00,0x20, +0x24,0x42,0x7c,0xf8,0x02,0xb1,0x48,0x21,0xac,0x82,0x00,0x00,0x00,0x09,0x48,0x80, +0x24,0x03,0x00,0x01,0x27,0x82,0x90,0x00,0xa2,0x83,0x00,0x12,0x01,0x22,0x10,0x21, +0x27,0x84,0x8f,0xf4,0x01,0x24,0x20,0x21,0x80,0x48,0x00,0x06,0x8c,0x8a,0x00,0x18, +0x27,0x83,0x90,0x10,0x01,0x23,0x48,0x21,0x8d,0x24,0x00,0x00,0x25,0x08,0x00,0x02, +0x8d,0x42,0x00,0x00,0x8d,0x49,0x00,0x04,0x00,0x08,0x17,0xc2,0x8d,0x43,0x00,0x08, +0x01,0x02,0x40,0x21,0x00,0x04,0x25,0xc2,0x00,0x08,0x40,0x43,0x30,0x84,0x00,0x01, +0x00,0x03,0x1f,0xc2,0x00,0x08,0x40,0x40,0x00,0xe0,0x80,0x21,0x00,0x64,0x18,0x24, +0x00,0x09,0x49,0x42,0x01,0x48,0x10,0x21,0x00,0xa0,0x98,0x21,0x00,0xa0,0x20,0x21, +0x00,0x40,0x38,0x21,0x02,0x00,0x28,0x21,0x14,0x60,0x00,0x19,0x31,0x29,0x00,0x01, +0x94,0x42,0x00,0x00,0x02,0xb1,0x88,0x21,0x02,0x00,0x28,0x21,0x00,0x11,0x88,0x80, +0x27,0x90,0x8f,0xf0,0x02,0x30,0x80,0x21,0x96,0x03,0x00,0x06,0x30,0x52,0xff,0xff, +0x02,0x60,0x20,0x21,0x00,0x60,0x30,0x21,0xa6,0x83,0x00,0x1a,0x27,0x82,0x8f,0xf8, +0x0c,0x00,0x08,0xdf,0x02,0x22,0x88,0x21,0x00,0x52,0x10,0x21,0x96,0x03,0x00,0x06, +0xa6,0x22,0x00,0x04,0x8f,0xbf,0x00,0x30,0x7b,0xb4,0x01,0x7c,0x7b,0xb2,0x01,0x3c, +0x7b,0xb0,0x00,0xfc,0x00,0x60,0x10,0x21,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x38, +0xaf,0xa9,0x00,0x10,0x0c,0x00,0x09,0x06,0xaf,0xa0,0x00,0x14,0x08,0x00,0x1f,0x72, +0x02,0xb1,0x88,0x21,0x27,0xbd,0xff,0xc0,0xaf,0xbe,0x00,0x38,0xaf,0xb7,0x00,0x34, +0xaf,0xb6,0x00,0x30,0xaf,0xb5,0x00,0x2c,0xaf,0xb3,0x00,0x24,0xaf,0xb1,0x00,0x1c, +0xaf,0xbf,0x00,0x3c,0xaf,0xb4,0x00,0x28,0xaf,0xb2,0x00,0x20,0xaf,0xb0,0x00,0x18, +0x94,0x90,0x00,0x00,0x3c,0x08,0xb0,0x03,0x35,0x08,0x00,0x20,0x00,0x10,0x10,0xc0, +0x00,0x50,0x18,0x21,0x00,0x40,0x88,0x21,0x3c,0x02,0x80,0x00,0x00,0x03,0x48,0x80, +0x24,0x42,0x7e,0x34,0x00,0x80,0x98,0x21,0x27,0x84,0x90,0x00,0x01,0x24,0x20,0x21, +0x93,0xb7,0x00,0x53,0xad,0x02,0x00,0x00,0x80,0x83,0x00,0x06,0x27,0x82,0x8f,0xf4, +0x01,0x22,0x10,0x21,0x8c,0x44,0x00,0x18,0x24,0x63,0x00,0x02,0x00,0x03,0x17,0xc2, +0x8c,0x88,0x00,0x08,0x00,0x62,0x18,0x21,0x00,0x03,0x18,0x43,0x00,0x03,0x18,0x40, +0xaf,0xa7,0x00,0x4c,0x2c,0xa2,0x00,0x10,0x00,0xa0,0xa8,0x21,0x00,0x83,0x50,0x21, +0x00,0x08,0x47,0xc2,0x00,0xc0,0x58,0x21,0x00,0x00,0xb0,0x21,0x8c,0x92,0x00,0x0c, +0x14,0x40,0x00,0x13,0x00,0x00,0xf0,0x21,0x92,0x67,0x00,0x04,0x24,0x14,0x00,0x01, +0x12,0x87,0x00,0x10,0x02,0x30,0x10,0x21,0x27,0x83,0x90,0x08,0x01,0x23,0x18,0x21, +0x80,0x64,0x00,0x00,0x27,0x83,0xb5,0x60,0x00,0x04,0x11,0x00,0x00,0x44,0x10,0x23, +0x00,0x02,0x10,0x80,0x00,0x44,0x10,0x23,0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21, +0x90,0x44,0x00,0x04,0x00,0x00,0x00,0x00,0x10,0x80,0x00,0x23,0x00,0x00,0x00,0x00, +0x02,0x30,0x10,0x21,0x00,0x02,0x80,0x80,0x24,0x04,0x00,0x01,0x27,0x83,0x90,0x10, +0xa2,0x64,0x00,0x12,0x02,0x03,0x18,0x21,0x8c,0x62,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x02,0x15,0xc2,0x30,0x42,0x00,0x01,0x01,0x02,0x10,0x24,0x14,0x40,0x00,0x0e, +0x02,0xa0,0x20,0x21,0x27,0x82,0x8f,0xf0,0x02,0x02,0x10,0x21,0x94,0x43,0x00,0x06, +0x00,0x00,0x00,0x00,0xa6,0x63,0x00,0x1a,0x94,0x42,0x00,0x06,0x7b,0xbe,0x01,0xfc, +0x7b,0xb6,0x01,0xbc,0x7b,0xb4,0x01,0x7c,0x7b,0xb2,0x01,0x3c,0x7b,0xb0,0x00,0xfc, +0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x40,0x8f,0xa5,0x00,0x4c,0x01,0x60,0x30,0x21, +0x01,0x40,0x38,0x21,0xaf,0xa0,0x00,0x10,0x0c,0x00,0x09,0x06,0xaf,0xa0,0x00,0x14, +0x08,0x00,0x1f,0xd9,0x00,0x00,0x00,0x00,0x27,0x83,0x90,0x10,0x01,0x23,0x18,0x21, +0x8c,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x15,0xc2,0x30,0x42,0x00,0x01, +0x01,0x02,0x10,0x24,0x14,0x40,0x00,0xaf,0x00,0xa0,0x20,0x21,0x32,0x4f,0x00,0x03, +0x00,0x12,0x10,0x82,0x25,0xe3,0x00,0x0d,0x30,0x45,0x00,0x07,0x00,0x74,0x78,0x04, +0x10,0xa0,0x00,0x0e,0x00,0x00,0x90,0x21,0x27,0x82,0x80,0x1c,0x00,0x15,0x18,0x40, +0x00,0x62,0x18,0x21,0x94,0x64,0x00,0x00,0x24,0xa2,0x00,0x06,0x00,0x54,0x10,0x04, +0x00,0x44,0x00,0x1a,0x14,0x80,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x0d, +0x00,0x00,0x10,0x12,0x24,0x42,0x00,0x20,0x30,0x52,0xff,0xfc,0x02,0x30,0x10,0x21, +0x27,0x83,0x90,0x00,0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21,0x90,0x44,0x00,0x03, +0x00,0x00,0x00,0x00,0x30,0x83,0x00,0xff,0x2c,0x62,0x00,0x0c,0x14,0x40,0x00,0x04, +0x2c,0x62,0x00,0x19,0x30,0x82,0x00,0x0f,0x24,0x43,0x00,0x0c,0x2c,0x62,0x00,0x19, +0x10,0x40,0x00,0x19,0x24,0x0e,0x00,0x20,0x24,0x62,0xff,0xe9,0x2c,0x42,0x00,0x02, +0x14,0x40,0x00,0x15,0x24,0x0e,0x00,0x10,0x24,0x62,0xff,0xeb,0x2c,0x42,0x00,0x02, +0x14,0x40,0x00,0x11,0x24,0x0e,0x00,0x08,0x24,0x02,0x00,0x14,0x10,0x62,0x00,0x0e, +0x24,0x0e,0x00,0x02,0x24,0x62,0xff,0xef,0x2c,0x42,0x00,0x03,0x14,0x40,0x00,0x0a, +0x24,0x0e,0x00,0x10,0x24,0x62,0xff,0xf1,0x2c,0x42,0x00,0x02,0x14,0x40,0x00,0x06, +0x24,0x0e,0x00,0x08,0x24,0x62,0xff,0xf3,0x2c,0x42,0x00,0x02,0x24,0x0e,0x00,0x04, +0x24,0x03,0x00,0x02,0x00,0x62,0x70,0x0a,0x30,0xe2,0x00,0xff,0x00,0x00,0x48,0x21, +0x00,0x00,0x68,0x21,0x10,0x40,0x00,0x6d,0x00,0x00,0x58,0x21,0x3c,0x14,0x80,0xff, +0x27,0x99,0x8f,0xf0,0x01,0xf2,0xc0,0x23,0x36,0x94,0xff,0xff,0x01,0xc9,0x10,0x2a, +0x14,0x40,0x00,0x64,0x24,0x03,0x00,0x04,0x00,0x10,0x28,0xc0,0x00,0xb0,0x10,0x21, +0x00,0x02,0x10,0x80,0x00,0x59,0x10,0x21,0x94,0x56,0x00,0x06,0x00,0x00,0x00,0x00, +0x32,0xcc,0x00,0x03,0x00,0x6c,0x10,0x23,0x30,0x42,0x00,0x03,0x02,0xc2,0x10,0x21, +0x24,0x42,0x00,0x04,0x30,0x51,0xff,0xff,0x02,0x32,0x18,0x2b,0x10,0x60,0x00,0x4d, +0x01,0xf1,0x10,0x23,0x02,0x51,0x10,0x23,0x01,0x78,0x18,0x2b,0x10,0x60,0x00,0x34, +0x30,0x44,0xff,0xff,0x29,0x22,0x00,0x40,0x10,0x40,0x00,0x31,0x01,0x72,0x18,0x21, +0x25,0x22,0x00,0x01,0x00,0x02,0x16,0x00,0x00,0x02,0x4e,0x03,0x00,0xb0,0x10,0x21, +0x00,0x02,0x30,0x80,0x27,0x82,0x8f,0xf4,0x30,0x6b,0xff,0xff,0x00,0xc2,0x18,0x21, +0x8c,0x67,0x00,0x18,0x00,0x04,0x25,0x40,0x3c,0x03,0x7f,0x00,0x8c,0xe2,0x00,0x04, +0x00,0x83,0x20,0x24,0x27,0x83,0x90,0x00,0x00,0x54,0x10,0x24,0x00,0xc3,0x28,0x21, +0x00,0x44,0x10,0x25,0xac,0xe2,0x00,0x04,0x16,0xe0,0x00,0x02,0xa0,0xb5,0x00,0x00, +0xa0,0xb5,0x00,0x03,0x27,0x84,0x90,0x10,0x00,0xc4,0x18,0x21,0x8c,0x62,0x00,0x00, +0x8c,0xe8,0x00,0x08,0x00,0x02,0x15,0xc2,0x00,0x08,0x47,0xc2,0x30,0x42,0x00,0x01, +0x01,0x02,0x10,0x24,0x10,0x40,0x00,0x0a,0x00,0x00,0x00,0x00,0x80,0xa2,0x00,0x06, +0x00,0x00,0x00,0x00,0x24,0x42,0x00,0x02,0x00,0x02,0x1f,0xc2,0x00,0x43,0x10,0x21, +0x00,0x02,0x10,0x43,0x00,0x02,0x10,0x40,0x00,0xe2,0x50,0x21,0xa5,0x5e,0x00,0x00, +0x92,0x62,0x00,0x04,0x25,0xad,0x00,0x01,0x27,0x84,0x8f,0xf0,0x00,0xc4,0x18,0x21, +0x01,0xa2,0x10,0x2a,0x94,0x70,0x00,0x02,0x14,0x40,0xff,0xb8,0x00,0x00,0x00,0x00, +0x96,0x63,0x00,0x14,0x00,0x0c,0x10,0x23,0xa2,0x69,0x00,0x12,0x30,0x42,0x00,0x03, +0x01,0x62,0x10,0x23,0x00,0x03,0x80,0xc0,0x8f,0xa5,0x00,0x4c,0x30,0x4b,0xff,0xff, +0x02,0x03,0x80,0x21,0x27,0x82,0x8f,0xf8,0x00,0x10,0x80,0x80,0xa6,0x6b,0x00,0x1a, +0x02,0xa0,0x20,0x21,0x01,0x60,0x30,0x21,0x01,0x60,0x88,0x21,0x0c,0x00,0x08,0xdf, +0x02,0x02,0x80,0x21,0x00,0x5e,0x10,0x21,0xa6,0x02,0x00,0x04,0x08,0x00,0x1f,0xdf, +0x02,0x20,0x10,0x21,0x01,0x62,0x10,0x2b,0x10,0x40,0xff,0xe9,0x00,0x00,0x20,0x21, +0x29,0x22,0x00,0x40,0x10,0x40,0xff,0xe6,0x01,0x71,0x18,0x21,0x08,0x00,0x20,0x55, +0x25,0x22,0x00,0x01,0x08,0x00,0x20,0x84,0x32,0xcc,0x00,0x03,0x08,0x00,0x20,0x84, +0x00,0x00,0x60,0x21,0x8f,0xa5,0x00,0x4c,0x01,0x40,0x38,0x21,0xaf,0xa0,0x00,0x10, +0x0c,0x00,0x09,0x06,0xaf,0xb4,0x00,0x14,0x92,0x67,0x00,0x04,0x08,0x00,0x1f,0xf7, +0x30,0x5e,0xff,0xff,0x30,0x84,0xff,0xff,0x00,0x04,0x30,0xc0,0x00,0xc4,0x20,0x21, +0x00,0x04,0x20,0x80,0x27,0x82,0x8f,0xf0,0x3c,0x03,0xb0,0x08,0x30,0xa5,0xff,0xff, +0x00,0x82,0x20,0x21,0x00,0xc3,0x30,0x21,0xac,0xc5,0x00,0x00,0x03,0xe0,0x00,0x08, +0xa4,0x85,0x00,0x00,0x30,0x84,0xff,0xff,0x00,0x04,0x30,0xc0,0x00,0xc4,0x30,0x21, +0x27,0x88,0x8f,0xf0,0x00,0x06,0x30,0x80,0x00,0xc8,0x30,0x21,0x94,0xc3,0x00,0x04, +0x3c,0x02,0xb0,0x08,0x3c,0x07,0xb0,0x03,0x00,0x03,0x20,0xc0,0x00,0x83,0x18,0x21, +0x00,0x03,0x18,0x80,0x00,0x82,0x20,0x21,0x3c,0x02,0x80,0x01,0x30,0xa5,0xff,0xff, +0x00,0x68,0x18,0x21,0x34,0xe7,0x00,0x20,0x24,0x42,0x82,0xe4,0xac,0xe2,0x00,0x00, +0xa4,0xc5,0x00,0x02,0xa4,0x65,0x00,0x00,0x03,0xe0,0x00,0x08,0xac,0x85,0x00,0x00, +0x3c,0x02,0xb0,0x03,0x3c,0x03,0x80,0x01,0x34,0x42,0x00,0x20,0x24,0x63,0x83,0x40, +0xac,0x43,0x00,0x00,0x90,0x82,0x00,0x10,0x3c,0x08,0xb0,0x03,0x3c,0x09,0xb0,0x06, +0x27,0x87,0x8f,0xf0,0x3c,0x0d,0xb0,0x08,0x34,0x0e,0xff,0xff,0x35,0x08,0x00,0x62, +0x00,0x80,0x30,0x21,0x24,0x0c,0xff,0xff,0x10,0x40,0x00,0x2c,0x35,0x29,0x80,0x20, +0x97,0x82,0x8f,0xe0,0x94,0x85,0x00,0x0c,0x3c,0x0b,0xb0,0x03,0x00,0x02,0x18,0xc0, +0x00,0x62,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x47,0x10,0x21,0xa4,0x45,0x00,0x00, +0x94,0x84,0x00,0x0e,0x00,0x6d,0x18,0x21,0xac,0x65,0x00,0x00,0x00,0x04,0x10,0xc0, +0x00,0x44,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x47,0x10,0x21,0x94,0x45,0x00,0x04, +0x3c,0x0a,0x77,0x77,0x35,0x6b,0x00,0xb4,0x00,0x05,0x10,0xc0,0x00,0x45,0x18,0x21, +0x00,0x03,0x18,0x80,0x00,0x67,0x18,0x21,0x00,0x4d,0x10,0x21,0xac,0x4e,0x00,0x00, +0xa4,0x6e,0x00,0x00,0x95,0x04,0x00,0x00,0x90,0xc3,0x00,0x10,0x24,0x02,0x00,0xff, +0x00,0x44,0x10,0x23,0x00,0x43,0x10,0x2a,0xa7,0x85,0x8f,0xe0,0x10,0x40,0x00,0x04, +0x35,0x4a,0x88,0x88,0xad,0x6a,0x00,0x00,0x90,0xc3,0x00,0x10,0x00,0x00,0x00,0x00, +0x30,0x63,0x00,0xff,0x3c,0x02,0x00,0x40,0x00,0x62,0x18,0x25,0xad,0x23,0x00,0x00, +0xa4,0xcc,0x00,0x0e,0xa4,0xcc,0x00,0x0c,0xa0,0xc0,0x00,0x10,0x03,0xe0,0x00,0x08, +0x00,0x00,0x00,0x00,0x30,0x84,0xff,0xff,0x00,0x04,0x10,0xc0,0x00,0x44,0x10,0x21, +0x27,0x89,0x8f,0xf0,0x00,0x02,0x10,0x80,0x00,0x49,0x10,0x21,0x97,0x83,0x8f,0xe0, +0x94,0x4a,0x00,0x04,0x3c,0x02,0xb0,0x08,0x00,0x03,0x38,0xc0,0x00,0x0a,0x40,0xc0, +0x00,0xe3,0x18,0x21,0x01,0x0a,0x28,0x21,0x00,0xe2,0x38,0x21,0x01,0x02,0x40,0x21, +0x00,0x03,0x18,0x80,0x00,0x05,0x28,0x80,0x3c,0x06,0xb0,0x03,0x3c,0x02,0x80,0x01, +0x00,0xa9,0x28,0x21,0x00,0x69,0x18,0x21,0x34,0xc6,0x00,0x20,0x34,0x09,0xff,0xff, +0x24,0x42,0x84,0x34,0xac,0xc2,0x00,0x00,0xa4,0x64,0x00,0x00,0xac,0xe4,0x00,0x00, +0xa4,0xa9,0x00,0x00,0xad,0x09,0x00,0x00,0xa7,0x8a,0x8f,0xe0,0x03,0xe0,0x00,0x08, +0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x01,0x34,0x63,0x00,0x20, +0x24,0x42,0x84,0xb4,0x3c,0x04,0xb0,0x03,0xac,0x62,0x00,0x00,0x34,0x84,0x01,0x10, +0x8c,0x82,0x00,0x00,0x97,0x83,0x81,0x60,0x30,0x42,0xff,0xff,0x10,0x62,0x00,0x16, +0x24,0x0a,0x00,0x01,0xa7,0x82,0x81,0x60,0xaf,0x80,0xb4,0x40,0x00,0x40,0x28,0x21, +0x24,0x06,0x00,0x01,0x27,0x84,0xb4,0x44,0x25,0x43,0xff,0xff,0x00,0x66,0x10,0x04, +0x00,0xa2,0x10,0x24,0x14,0x40,0x00,0x07,0x00,0x00,0x00,0x00,0x8c,0x83,0xff,0xfc, +0x00,0x00,0x00,0x00,0x00,0x66,0x10,0x04,0x00,0xa2,0x10,0x24,0x38,0x42,0x00,0x00, +0x01,0x42,0x18,0x0a,0x25,0x4a,0x00,0x01,0x2d,0x42,0x00,0x14,0xac,0x83,0x00,0x00, +0x14,0x40,0xff,0xf1,0x24,0x84,0x00,0x04,0x3c,0x0b,0xb0,0x03,0x00,0x00,0x50,0x21, +0x3c,0x0c,0x80,0x00,0x27,0x89,0xb4,0x90,0x35,0x6b,0x01,0x20,0x8d,0x68,0x00,0x00, +0x8d,0x23,0x00,0x04,0x01,0x0c,0x10,0x24,0x00,0x02,0x17,0xc2,0x11,0x03,0x00,0x37, +0xa1,0x22,0x00,0xdc,0xa1,0x20,0x00,0xd5,0xa1,0x20,0x00,0xd6,0x01,0x20,0x30,0x21, +0x00,0x00,0x38,0x21,0x00,0x00,0x28,0x21,0x01,0x20,0x20,0x21,0x00,0xa8,0x10,0x06, +0x30,0x42,0x00,0x01,0x10,0xe0,0x00,0x10,0xa0,0x82,0x00,0x0a,0x90,0x82,0x00,0x07, +0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x31,0x24,0xa2,0xff,0xff,0xa0,0x82,0x00,0x08, +0x90,0x82,0x00,0x0a,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x09,0x00,0x00,0x00,0x00, +0x90,0x83,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x03,0x10,0x40,0x00,0x43,0x10,0x21, +0x00,0x46,0x10,0x21,0xa0,0x45,0x00,0x09,0x90,0x82,0x00,0x0a,0x00,0x00,0x00,0x00, +0x10,0x40,0x00,0x07,0x00,0x00,0x00,0x00,0x14,0xe0,0x00,0x04,0x00,0x00,0x00,0x00, +0xa0,0xc5,0x00,0xd5,0x24,0x07,0x00,0x01,0xa0,0x85,0x00,0x08,0xa0,0xc5,0x00,0xd6, +0x24,0xa5,0x00,0x01,0x2c,0xa2,0x00,0x1c,0x14,0x40,0xff,0xe0,0x24,0x84,0x00,0x03, +0x90,0xc4,0x00,0xd5,0x00,0x00,0x28,0x21,0x00,0xa4,0x10,0x2b,0x10,0x40,0x00,0x0b, +0x00,0x00,0x00,0x00,0x00,0xc0,0x18,0x21,0xa0,0x64,0x00,0x08,0x90,0xc2,0x00,0xd5, +0x24,0xa5,0x00,0x01,0xa0,0x62,0x00,0x09,0x90,0xc4,0x00,0xd5,0x00,0x00,0x00,0x00, +0x00,0xa4,0x10,0x2b,0x14,0x40,0xff,0xf8,0x24,0x63,0x00,0x03,0x25,0x4a,0x00,0x01, +0x2d,0x42,0x00,0x08,0xad,0x28,0x00,0x04,0x25,0x6b,0x00,0x04,0x14,0x40,0xff,0xbf, +0x25,0x29,0x00,0xec,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x90,0x82,0x00,0x05, +0x08,0x00,0x21,0x68,0xa0,0x82,0x00,0x08,0x97,0x85,0x8b,0x6a,0x3c,0x03,0xb0,0x03, +0x3c,0x02,0x80,0x01,0x27,0xbd,0xff,0xe8,0x34,0x63,0x00,0x20,0x24,0x42,0x86,0x68, +0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x14,0xac,0x62,0x00,0x00,0x30,0x90,0x00,0xff, +0x00,0x05,0x28,0x42,0x00,0x00,0x48,0x21,0x27,0x8f,0xb4,0x94,0x00,0x00,0x50,0x21, +0x00,0x00,0x58,0x21,0x27,0x98,0xb5,0x74,0x27,0x99,0xb5,0x70,0x27,0x8e,0xb5,0x6e, +0x27,0x8c,0xb4,0x98,0x27,0x8d,0xb4,0xf0,0x27,0x88,0xb5,0x68,0x00,0x0a,0x18,0x80, +0x01,0x6f,0x10,0x21,0xac,0x40,0x00,0x00,0xac,0x45,0x00,0x58,0x00,0x6e,0x20,0x21, +0x00,0x78,0x10,0x21,0xa1,0x00,0xff,0xfc,0xad,0x00,0x00,0x00,0xa1,0x00,0x00,0x04, +0xa1,0x00,0x00,0x05,0xad,0x00,0xff,0xf8,0x00,0x79,0x18,0x21,0x24,0x06,0x00,0x01, +0x24,0xc6,0xff,0xff,0xa0,0x80,0x00,0x00,0xa4,0x60,0x00,0x00,0xac,0x40,0x00,0x00, +0x24,0x63,0x00,0x02,0x24,0x42,0x00,0x04,0x04,0xc1,0xff,0xf9,0x24,0x84,0x00,0x01, +0x00,0x0a,0x10,0x80,0x00,0x4d,0x20,0x21,0x00,0x00,0x30,0x21,0x00,0x4c,0x18,0x21, +0x27,0x87,0x81,0x64,0x8c,0xe2,0x00,0x00,0x24,0xe7,0x00,0x04,0xac,0x82,0x00,0x00, +0xa0,0x66,0x00,0x00,0xa0,0x66,0x00,0x01,0x24,0xc6,0x00,0x01,0x28,0xc2,0x00,0x1c, +0xa0,0x60,0x00,0x02,0x24,0x84,0x00,0x04,0x14,0x40,0xff,0xf6,0x24,0x63,0x00,0x03, +0x25,0x29,0x00,0x01,0x29,0x22,0x00,0x08,0x25,0x4a,0x00,0x3b,0x25,0x08,0x00,0xec, +0x14,0x40,0xff,0xd6,0x25,0x6b,0x00,0xec,0xa7,0x80,0x81,0x60,0x00,0x00,0x48,0x21, +0x27,0x83,0xb4,0x40,0xac,0x69,0x00,0x00,0x25,0x29,0x00,0x01,0x29,0x22,0x00,0x0c, +0x14,0x40,0xff,0xfc,0x24,0x63,0x00,0x04,0x0c,0x00,0x21,0x2d,0x00,0x00,0x00,0x00, +0x2e,0x04,0x00,0x14,0x27,0x83,0xb4,0x90,0x24,0x09,0x00,0x07,0x10,0x80,0x00,0x0a, +0x00,0x00,0x00,0x00,0x90,0x62,0x00,0xd5,0x25,0x29,0xff,0xff,0xa0,0x62,0x00,0x00, +0x05,0x21,0xff,0xfa,0x24,0x63,0x00,0xec,0x8f,0xbf,0x00,0x14,0x8f,0xb0,0x00,0x10, +0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18,0x90,0x62,0x00,0xd6,0x08,0x00,0x21,0xeb, +0x25,0x29,0xff,0xff,0x30,0x84,0x00,0xff,0x00,0x04,0x11,0x00,0x00,0x44,0x10,0x23, +0x00,0x02,0x10,0x80,0x00,0x44,0x10,0x23,0x00,0x02,0x10,0x80,0x27,0x83,0xb4,0x90, +0x00,0x43,0x60,0x21,0x3c,0x04,0xb0,0x03,0x3c,0x02,0x80,0x01,0x34,0x84,0x00,0x20, +0x24,0x42,0x87,0xd4,0x30,0xc6,0x00,0xff,0x93,0xa9,0x00,0x13,0x30,0xa5,0x00,0xff, +0x30,0xe7,0x00,0xff,0xac,0x82,0x00,0x00,0x10,0xc0,0x00,0xeb,0x25,0x8f,0x00,0xd0, +0x91,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x24,0x42,0xff,0xfc,0x2c,0x43,0x00,0x18, +0x10,0x60,0x00,0xcf,0x3c,0x03,0x80,0x01,0x00,0x02,0x10,0x80,0x24,0x63,0x02,0x5c, +0x00,0x43,0x10,0x21,0x8c,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x08, +0x00,0x00,0x00,0x00,0x2d,0x22,0x00,0x2d,0x10,0x40,0x00,0x14,0x00,0x00,0x00,0x00, +0x10,0xa0,0x00,0x0f,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xa2,0x00,0x09, +0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0x10,0xa2,0x00,0x06,0x00,0x00,0x00,0x00, +0x8d,0x82,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x42,0xff,0xd0,0x03,0xe0,0x00,0x08, +0xad,0x82,0x00,0xd0,0x8d,0x82,0x00,0xd0,0x08,0x00,0x22,0x23,0x24,0x42,0xff,0xe0, +0x8d,0x82,0x00,0xd0,0x08,0x00,0x22,0x23,0x24,0x42,0x00,0x01,0x10,0xa0,0x00,0x0f, +0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0xf9,0x00,0x00,0x00,0x00, +0x24,0x02,0x00,0x02,0x10,0xa2,0x00,0x07,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x03, +0x14,0xa2,0xff,0xf0,0x00,0x00,0x00,0x00,0x8d,0x82,0x00,0xd0,0x08,0x00,0x22,0x23, +0x24,0x42,0xff,0xe8,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x8d,0x82,0x00,0xd0, +0x08,0x00,0x22,0x23,0x24,0x42,0x00,0x02,0x10,0xa0,0xff,0xfc,0x00,0x00,0x00,0x00, +0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0xe6,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02, +0x10,0xa2,0xff,0xf4,0x24,0x02,0x00,0x03,0x14,0xa2,0xff,0xef,0x00,0x00,0x00,0x00, +0x8d,0x82,0x00,0xd0,0x08,0x00,0x22,0x23,0x24,0x42,0xff,0xf8,0x2d,0x22,0x00,0x19, +0x14,0x40,0xff,0xde,0x00,0x00,0x00,0x00,0x10,0xa0,0xff,0xec,0x00,0x00,0x00,0x00, +0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0xd6,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02, +0x10,0xa2,0xff,0xe4,0x24,0x02,0x00,0x03,0x10,0xa2,0xff,0xf1,0x00,0x00,0x00,0x00, +0x8d,0x82,0x00,0xd0,0x08,0x00,0x22,0x23,0x24,0x42,0xff,0xf0,0x2d,0x22,0x00,0x1b, +0x10,0x40,0xff,0xf1,0x00,0x00,0x00,0x00,0x10,0xa0,0xff,0xdc,0x00,0x00,0x00,0x00, +0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0xc6,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02, +0x14,0xa2,0xff,0xce,0x00,0x00,0x00,0x00,0x8d,0x82,0x00,0xd0,0x08,0x00,0x22,0x23, +0x24,0x42,0xff,0xf4,0x2d,0x22,0x00,0x1e,0x10,0x40,0xff,0xe3,0x00,0x00,0x00,0x00, +0x10,0xa0,0xff,0xce,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0xc9, +0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0xd6,0x00,0x00,0x00,0x00,0x08,0x00,0x22,0x34, +0x24,0x02,0x00,0x03,0x2d,0x22,0x00,0x23,0x10,0x40,0xff,0xd7,0x00,0x00,0x00,0x00, +0x10,0xa0,0xff,0xaf,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0xbd, +0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0xda,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x03, +0x14,0xa2,0xff,0x9f,0x00,0x00,0x00,0x00,0x08,0x00,0x22,0x25,0x00,0x00,0x00,0x00, +0x2d,0x22,0x00,0x25,0x10,0x40,0xff,0xc8,0x00,0x00,0x00,0x00,0x10,0xa0,0xff,0xa0, +0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xa2,0x00,0x06,0x00,0x00,0x00,0x00, +0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0x97,0x00,0x00,0x00,0x00,0x08,0x00,0x22,0x80, +0x24,0x02,0x00,0x03,0x8d,0x82,0x00,0xd0,0x08,0x00,0x22,0x23,0x24,0x42,0xff,0xfc, +0x2d,0x22,0x00,0x16,0x14,0x40,0x00,0x0e,0x00,0x00,0x00,0x00,0x10,0xa0,0xff,0xa3, +0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0x8d,0x00,0x00,0x00,0x00, +0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0x9b,0x24,0x02,0x00,0x03,0x14,0xa2,0xff,0xa8, +0x00,0x00,0x00,0x00,0x8d,0x82,0x00,0xd0,0x08,0x00,0x22,0x23,0x24,0x42,0xff,0xfa, +0x10,0xa0,0xff,0x96,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0x80, +0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0x8e,0x00,0x00,0x00,0x00, +0x08,0x00,0x22,0x48,0x00,0x00,0x00,0x00,0x2d,0x22,0x00,0x17,0x14,0x40,0xff,0x9e, +0x00,0x00,0x00,0x00,0x08,0x00,0x22,0x97,0x00,0x00,0x00,0x00,0x2d,0x22,0x00,0x19, +0x10,0x40,0xff,0xe2,0x00,0x00,0x00,0x00,0x10,0xa0,0xff,0x84,0x00,0x00,0x00,0x00, +0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0x6e,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02, +0x10,0xa2,0xff,0x7c,0x24,0x02,0x00,0x03,0x10,0xa2,0xff,0x89,0x00,0x00,0x00,0x00, +0x08,0x00,0x22,0x25,0x00,0x00,0x00,0x00,0x08,0x00,0x22,0xb4,0x2d,0x22,0x00,0x1b, +0x2d,0x22,0x00,0x1e,0x10,0x40,0xff,0xde,0x00,0x00,0x00,0x00,0x10,0xa0,0xff,0x73, +0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0x5d,0x00,0x00,0x00,0x00, +0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0x6b,0x24,0x02,0x00,0x03,0x10,0xa2,0xff,0x88, +0x00,0x00,0x00,0x00,0x08,0x00,0x22,0x25,0x00,0x00,0x00,0x00,0x2d,0x22,0x00,0x23, +0x14,0x40,0xff,0xf2,0x00,0x00,0x00,0x00,0x08,0x00,0x22,0x4e,0x00,0x00,0x00,0x00, +0x08,0x00,0x22,0x4c,0x2d,0x22,0x00,0x25,0x08,0x00,0x22,0x85,0x2d,0x22,0x00,0x27, +0x10,0xa0,0xff,0x5e,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0x48, +0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0x56,0x24,0x02,0x00,0x03, +0x14,0xa2,0xff,0x63,0x00,0x00,0x00,0x00,0x08,0x00,0x22,0x91,0x00,0x00,0x00,0x00, +0x2d,0x22,0x00,0x27,0x14,0x40,0xff,0x8e,0x00,0x00,0x00,0x00,0x08,0x00,0x22,0x3e, +0x00,0x00,0x00,0x00,0x2d,0x22,0x00,0x29,0x14,0x40,0xff,0x89,0x00,0x00,0x00,0x00, +0x08,0x00,0x22,0x2b,0x00,0x00,0x00,0x00,0x91,0x86,0x00,0x00,0x91,0x83,0x00,0xd4, +0x25,0x8d,0x00,0x5c,0x30,0xc4,0x00,0xff,0x00,0x04,0x10,0x40,0x00,0x44,0x10,0x21, +0x00,0x04,0x50,0x80,0x01,0x82,0x58,0x21,0x01,0x8a,0x40,0x21,0x25,0x78,0x00,0x08, +0x10,0x60,0x00,0x37,0x25,0x0e,0x00,0x60,0x2c,0xa2,0x00,0x03,0x14,0x40,0x00,0x25, +0x00,0x00,0x00,0x00,0x91,0x82,0x00,0xdd,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x1e, +0x00,0x00,0x00,0x00,0x27,0x87,0x81,0x64,0x01,0x47,0x10,0x21,0x8c,0x43,0x00,0x00, +0x00,0x00,0x00,0x00,0xad,0x03,0x00,0x60,0x91,0x62,0x00,0x08,0x00,0x00,0x00,0x00, +0x00,0x40,0x30,0x21,0xa1,0x82,0x00,0x00,0x30,0xc2,0x00,0xff,0x00,0x02,0x10,0x80, +0x00,0x47,0x10,0x21,0x8c,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x18,0x42, +0xad,0xa3,0x00,0x00,0x91,0x84,0x00,0x00,0x8d,0xc5,0x00,0x00,0x00,0x04,0x20,0x80, +0x00,0x87,0x10,0x21,0x8c,0x43,0x00,0x00,0x00,0x05,0x28,0x40,0x00,0x8c,0x20,0x21, +0x00,0x03,0x18,0x80,0x00,0xa3,0x10,0x2b,0x00,0x62,0x28,0x0a,0xac,0x85,0x00,0x60, +0x03,0xe0,0x00,0x08,0xa1,0x80,0x00,0xd4,0x27,0x87,0x81,0x64,0x08,0x00,0x23,0x0e, +0xa1,0x80,0x00,0xdd,0x27,0x82,0x81,0xd4,0x8d,0x83,0x00,0xd8,0x00,0x82,0x10,0x21, +0x90,0x44,0x00,0x00,0x24,0x63,0x00,0x01,0x00,0x64,0x20,0x2b,0x14,0x80,0xff,0x0d, +0xad,0x83,0x00,0xd8,0x8d,0x02,0x00,0x60,0xa1,0x80,0x00,0xd4,0x00,0x02,0x1f,0xc2, +0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x43,0x03,0xe0,0x00,0x08,0xad,0x82,0x00,0x5c, +0x10,0xe0,0x00,0x1a,0x24,0x83,0xff,0xfc,0x2c,0x62,0x00,0x18,0x10,0x40,0x01,0x18, +0x00,0x03,0x10,0x80,0x3c,0x03,0x80,0x01,0x24,0x63,0x02,0xbc,0x00,0x43,0x10,0x21, +0x8c,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x08,0x00,0x00,0x00,0x00, +0x2d,0x22,0x00,0x2d,0x10,0x40,0x00,0x5f,0x00,0x00,0x00,0x00,0x10,0xa0,0x00,0x5a, +0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xa2,0x00,0x54,0x00,0x00,0x00,0x00, +0x24,0x02,0x00,0x02,0x10,0xa2,0x00,0x51,0x00,0x00,0x00,0x00,0x8d,0x82,0x00,0xd0, +0x00,0x00,0x00,0x00,0x24,0x42,0xff,0xd0,0xad,0x82,0x00,0xd0,0x8d,0xe3,0x00,0x00, +0x8d,0xa2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x43,0x10,0x21,0xad,0xa2,0x00,0x00, +0xad,0xe0,0x00,0x00,0x8d,0xa3,0x00,0x00,0x8d,0xc4,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x83,0x10,0x2a,0x10,0x40,0x00,0x22,0x00,0x00,0x00,0x00,0x93,0x05,0x00,0x01, +0x91,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x45,0x00,0x05,0x24,0x02,0x00,0x01, +0xa1,0x85,0x00,0x00,0xa1,0x82,0x00,0xd4,0x03,0xe0,0x00,0x08,0xad,0x80,0x00,0xd8, +0x91,0x82,0x00,0xdd,0x24,0x03,0x00,0x01,0x10,0x43,0x00,0x05,0x00,0x00,0x00,0x00, +0xa1,0x83,0x00,0xd4,0xad,0x80,0x00,0xd8,0x03,0xe0,0x00,0x08,0xa1,0x83,0x00,0xdd, +0x00,0x04,0x17,0xc2,0x00,0x82,0x10,0x21,0x00,0x02,0x10,0x43,0xad,0xa2,0x00,0x00, +0x91,0x83,0x00,0x00,0x27,0x82,0x81,0x64,0x8d,0xc5,0x00,0x00,0x00,0x03,0x18,0x80, +0x00,0x62,0x18,0x21,0x8c,0x64,0x00,0x00,0x00,0x05,0x28,0x40,0x00,0x04,0x18,0x80, +0x00,0xa3,0x10,0x2b,0x00,0x62,0x28,0x0a,0x08,0x00,0x23,0x20,0xad,0xc5,0x00,0x00, +0x97,0x82,0x8b,0x6c,0x00,0x00,0x00,0x00,0x00,0x62,0x10,0x2a,0x10,0x40,0xfe,0xb9, +0x00,0x00,0x00,0x00,0x91,0x82,0x00,0xdd,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x15, +0x00,0x00,0x00,0x00,0x91,0x83,0x00,0x00,0x27,0x82,0x81,0x64,0x00,0x03,0x18,0x80, +0x00,0x62,0x10,0x21,0x8c,0x44,0x00,0x00,0x00,0x6c,0x18,0x21,0xac,0x64,0x00,0x60, +0x93,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x10,0x80,0x01,0x82,0x10,0x21, +0x24,0x4e,0x00,0x60,0xa1,0x85,0x00,0x00,0x8d,0xc2,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x02,0x1f,0xc2,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x43,0x03,0xe0,0x00,0x08, +0xad,0xa2,0x00,0x00,0x08,0x00,0x23,0x92,0xa1,0x80,0x00,0xdd,0x8d,0x82,0x00,0xd0, +0x08,0x00,0x23,0x4e,0x24,0x42,0xff,0xe0,0x8d,0x82,0x00,0xd0,0x08,0x00,0x23,0x4e, +0x24,0x42,0x00,0x01,0x10,0xa0,0x00,0x0d,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01, +0x10,0xa2,0xff,0xf9,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0xa7, +0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x03,0x14,0xa2,0xff,0xf0,0x00,0x00,0x00,0x00, +0x8d,0x82,0x00,0xd0,0x08,0x00,0x23,0x4e,0x24,0x42,0xff,0xe8,0x8d,0x82,0x00,0xd0, +0x08,0x00,0x23,0x4e,0x24,0x42,0x00,0x02,0x10,0xa0,0xff,0xfc,0x00,0x00,0x00,0x00, +0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0xe8,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02, +0x10,0xa2,0xff,0x96,0x24,0x02,0x00,0x03,0x14,0xa2,0xff,0xf1,0x00,0x00,0x00,0x00, +0x8d,0x82,0x00,0xd0,0x08,0x00,0x23,0x4e,0x24,0x42,0xff,0xf8,0x2d,0x22,0x00,0x19, +0x14,0x40,0xff,0xe0,0x00,0x00,0x00,0x00,0x10,0xa0,0xff,0xec,0x00,0x00,0x00,0x00, +0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0xd8,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02, +0x10,0xa2,0xff,0x86,0x24,0x02,0x00,0x03,0x10,0xa2,0xff,0xf1,0x00,0x00,0x00,0x00, +0x8d,0x82,0x00,0xd0,0x08,0x00,0x23,0x4e,0x24,0x42,0xff,0xf0,0x2d,0x22,0x00,0x1b, +0x10,0x40,0xff,0xf1,0x00,0x00,0x00,0x00,0x10,0xa0,0xff,0xdc,0x00,0x00,0x00,0x00, +0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0xc8,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02, +0x14,0xa2,0xff,0xd0,0x00,0x00,0x00,0x00,0x8d,0x82,0x00,0xd0,0x08,0x00,0x23,0x4e, +0x24,0x42,0xff,0xf4,0x2d,0x22,0x00,0x1e,0x10,0x40,0xff,0xe3,0x00,0x00,0x00,0x00, +0x10,0xa0,0xff,0xce,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0x6b, +0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0xd6,0x00,0x00,0x00,0x00,0x08,0x00,0x23,0xaa, +0x24,0x02,0x00,0x03,0x2d,0x22,0x00,0x23,0x10,0x40,0xff,0xd7,0x00,0x00,0x00,0x00, +0x10,0xa0,0xff,0xb1,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0x5f, +0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0xda,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x03, +0x14,0xa2,0xff,0x56,0x00,0x00,0x00,0x00,0x08,0x00,0x23,0x9b,0x00,0x00,0x00,0x00, +0x2d,0x22,0x00,0x25,0x10,0x40,0xff,0xc8,0x00,0x00,0x00,0x00,0x10,0xa0,0xff,0xa2, +0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xa2,0x00,0x06,0x00,0x00,0x00,0x00, +0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0x99,0x00,0x00,0x00,0x00,0x08,0x00,0x23,0xf4, +0x24,0x02,0x00,0x03,0x8d,0x82,0x00,0xd0,0x08,0x00,0x23,0x4e,0x24,0x42,0xff,0xfc, +0x2d,0x22,0x00,0x16,0x14,0x40,0x00,0x0e,0x00,0x00,0x00,0x00,0x10,0xa0,0xff,0xa3, +0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0x8f,0x00,0x00,0x00,0x00, +0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0x3d,0x24,0x02,0x00,0x03,0x14,0xa2,0xff,0xa8, +0x00,0x00,0x00,0x00,0x8d,0x82,0x00,0xd0,0x08,0x00,0x23,0x4e,0x24,0x42,0xff,0xfa, +0x10,0xa0,0xff,0x96,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0x82, +0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0x30,0x00,0x00,0x00,0x00, +0x08,0x00,0x23,0xbc,0x00,0x00,0x00,0x00,0x2d,0x22,0x00,0x17,0x14,0x40,0xff,0x9e, +0x00,0x00,0x00,0x00,0x08,0x00,0x24,0x0b,0x00,0x00,0x00,0x00,0x2d,0x22,0x00,0x19, +0x10,0x40,0xff,0xe2,0x00,0x00,0x00,0x00,0x10,0xa0,0xff,0x84,0x00,0x00,0x00,0x00, +0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0x70,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02, +0x10,0xa2,0xff,0x1e,0x24,0x02,0x00,0x03,0x10,0xa2,0xff,0x89,0x00,0x00,0x00,0x00, +0x08,0x00,0x23,0x9b,0x00,0x00,0x00,0x00,0x08,0x00,0x24,0x28,0x2d,0x22,0x00,0x1b, +0x2d,0x22,0x00,0x1e,0x10,0x40,0xff,0xde,0x00,0x00,0x00,0x00,0x10,0xa0,0xff,0x73, +0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0x5f,0x00,0x00,0x00,0x00, +0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0x0d,0x24,0x02,0x00,0x03,0x10,0xa2,0xff,0x88, +0x00,0x00,0x00,0x00,0x08,0x00,0x23,0x9b,0x00,0x00,0x00,0x00,0x2d,0x22,0x00,0x23, +0x14,0x40,0xff,0xf2,0x00,0x00,0x00,0x00,0x08,0x00,0x23,0xc2,0x00,0x00,0x00,0x00, +0x08,0x00,0x23,0xc0,0x2d,0x22,0x00,0x25,0x08,0x00,0x23,0xf9,0x2d,0x22,0x00,0x27, +0x10,0xa0,0xff,0x5e,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0x4a, +0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0x10,0xa2,0xfe,0xf8,0x24,0x02,0x00,0x03, +0x14,0xa2,0xff,0x63,0x00,0x00,0x00,0x00,0x08,0x00,0x24,0x05,0x00,0x00,0x00,0x00, +0x2d,0x22,0x00,0x27,0x14,0x40,0xff,0x8e,0x00,0x00,0x00,0x00,0x08,0x00,0x23,0xb2, +0x00,0x00,0x00,0x00,0x2d,0x22,0x00,0x29,0x14,0x40,0xff,0x89,0x00,0x00,0x00,0x00, +0x08,0x00,0x23,0xa1,0x00,0x00,0x00,0x00,0x27,0xbd,0xff,0xe8,0x3c,0x02,0xb0,0x03, +0xaf,0xbf,0x00,0x14,0xaf,0xb0,0x00,0x10,0x34,0x42,0x01,0x18,0x3c,0x03,0xb0,0x03, +0x8c,0x50,0x00,0x00,0x34,0x63,0x01,0x2c,0x90,0x62,0x00,0x00,0x32,0x05,0x00,0x01, +0xa3,0x82,0x80,0x10,0x14,0xa0,0x00,0x14,0x30,0x44,0x00,0xff,0x32,0x02,0x01,0x00, +0x14,0x40,0x00,0x09,0x00,0x00,0x00,0x00,0x32,0x02,0x08,0x00,0x10,0x40,0x00,0x02, +0x24,0x02,0x00,0x01,0xa3,0x82,0xbc,0x08,0x8f,0xbf,0x00,0x14,0x8f,0xb0,0x00,0x10, +0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18,0x0c,0x00,0x05,0x39,0x00,0x00,0x00,0x00, +0x26,0x02,0xff,0x00,0xa3,0x80,0xbc,0x08,0x3c,0x01,0xb0,0x03,0xac,0x22,0x01,0x18, +0x08,0x00,0x24,0x77,0x32,0x02,0x08,0x00,0x0c,0x00,0x21,0x9a,0x00,0x00,0x00,0x00, +0x26,0x02,0xff,0xff,0x3c,0x01,0xb0,0x03,0xac,0x22,0x01,0x18,0x08,0x00,0x24,0x74, +0x32,0x02,0x01,0x00,0x27,0xbd,0xff,0xe0,0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0xd0, +0xaf,0xbf,0x00,0x18,0x8c,0x43,0x00,0x00,0x3c,0x02,0x00,0x40,0x24,0x07,0x0f,0xff, +0x00,0x03,0x33,0x02,0x00,0x03,0x2d,0x02,0x00,0x03,0x43,0x02,0x30,0x69,0x0f,0xff, +0x00,0x62,0x18,0x24,0x30,0xa5,0x00,0x03,0x30,0xc6,0x00,0xff,0x10,0x60,0x00,0x08, +0x31,0x08,0x00,0xff,0x01,0x00,0x30,0x21,0x0c,0x00,0x25,0x38,0xaf,0xa9,0x00,0x10, +0x8f,0xbf,0x00,0x18,0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20, +0x0c,0x00,0x25,0x8a,0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03,0x34,0x63,0x00,0xd4, +0x08,0x00,0x24,0xa0,0xac,0x62,0x00,0x00,0x27,0xbd,0xff,0xc0,0xaf,0xb6,0x00,0x30, +0xaf,0xb3,0x00,0x24,0xaf,0xb1,0x00,0x1c,0xaf,0xb0,0x00,0x18,0xaf,0xbf,0x00,0x3c, +0xaf,0xbe,0x00,0x38,0xaf,0xb7,0x00,0x34,0xaf,0xb5,0x00,0x2c,0xaf,0xb4,0x00,0x28, +0xaf,0xb2,0x00,0x20,0x0c,0x00,0x17,0xc8,0x00,0x80,0x80,0x21,0x00,0x00,0xb0,0x21, +0x00,0x00,0x88,0x21,0x10,0x40,0x00,0x12,0x00,0x00,0x98,0x21,0x3c,0x02,0xb0,0x03, +0x3c,0x03,0xb0,0x03,0x3c,0x04,0xb0,0x03,0x24,0x05,0x00,0x01,0x34,0x42,0x00,0xbc, +0x34,0x63,0x00,0xbb,0x34,0x84,0x00,0xba,0xa4,0x40,0x00,0x00,0xa0,0x65,0x00,0x00, +0xa0,0x85,0x00,0x00,0x7b,0xbe,0x01,0xfc,0x7b,0xb6,0x01,0xbc,0x7b,0xb4,0x01,0x7c, +0x7b,0xb2,0x01,0x3c,0x7b,0xb0,0x00,0xfc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x40, +0x3c,0x02,0xb0,0x03,0x34,0x42,0x01,0x47,0x90,0x44,0x00,0x00,0x00,0x10,0x1a,0x02, +0x3c,0x15,0xfd,0xff,0x30,0x84,0x00,0xff,0xa0,0x50,0x00,0x00,0x30,0x74,0x00,0x0f, +0xaf,0xa4,0x00,0x10,0x00,0x00,0x90,0x21,0x3c,0x17,0x02,0x00,0x36,0xb5,0xff,0xff, +0x3c,0x1e,0xb0,0x03,0x0c,0x00,0x06,0xce,0x24,0x04,0x04,0x00,0x00,0x57,0x10,0x25, +0x00,0x40,0x28,0x21,0x0c,0x00,0x06,0xc1,0x24,0x04,0x04,0x00,0x00,0x00,0x80,0x21, +0x0c,0x00,0x26,0x52,0x00,0x00,0x00,0x00,0x26,0x03,0x00,0x01,0x30,0x70,0x00,0xff, +0x10,0x40,0x00,0x47,0x2e,0x03,0x00,0x02,0x14,0x60,0xff,0xf9,0x00,0x00,0x00,0x00, +0x0c,0x00,0x06,0xce,0x24,0x04,0x04,0x00,0x00,0x55,0x10,0x24,0x00,0x40,0x28,0x21, +0x0c,0x00,0x06,0xc1,0x24,0x04,0x04,0x00,0x24,0x02,0x00,0x01,0x12,0x82,0x00,0x38, +0x00,0x00,0x00,0x00,0x12,0x80,0x00,0x36,0x00,0x00,0x00,0x00,0x32,0x22,0x00,0x60, +0x32,0x23,0x0c,0x00,0x00,0x03,0x1a,0x02,0x3c,0x05,0x00,0x60,0x00,0x02,0x11,0x42, +0x02,0x25,0x20,0x24,0x00,0x43,0x10,0x25,0x3c,0x03,0x04,0x00,0x02,0x23,0x28,0x24, +0x00,0x04,0x24,0x42,0x00,0x44,0x10,0x25,0x00,0x05,0x2d,0x02,0x00,0x45,0x88,0x25, +0x12,0x20,0x00,0x05,0x26,0x42,0x00,0x01,0x26,0xc2,0x00,0x01,0x30,0x56,0x00,0xff, +0x02,0x71,0x98,0x21,0x26,0x42,0x00,0x01,0x02,0x5e,0x20,0x21,0x30,0x52,0x00,0xff, +0x2e,0x43,0x00,0x05,0xa0,0x91,0x00,0xd8,0x14,0x60,0xff,0xce,0x3c,0x02,0xb0,0x03, +0x8f,0xa5,0x00,0x10,0x34,0x42,0x01,0x47,0xa0,0x45,0x00,0x00,0x12,0x60,0x00,0x0e, +0x3c,0x02,0xb0,0x03,0x12,0xc0,0x00,0x0d,0x34,0x42,0x00,0xbc,0x00,0x13,0x10,0x40, +0x00,0x53,0x10,0x21,0x00,0x02,0x10,0xc0,0x00,0x53,0x10,0x21,0x00,0x02,0x98,0x80, +0x02,0x76,0x00,0x1b,0x16,0xc0,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x0d, +0x00,0x00,0x98,0x12,0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0xbc,0x3c,0x03,0xb0,0x03, +0x3c,0x04,0xb0,0x03,0xa4,0x53,0x00,0x00,0x34,0x63,0x00,0xbb,0x34,0x84,0x00,0xba, +0x24,0x02,0x00,0x01,0xa0,0x60,0x00,0x00,0x08,0x00,0x24,0xc5,0xa0,0x82,0x00,0x00, +0x0c,0x00,0x06,0xce,0x24,0x04,0x04,0xfc,0x08,0x00,0x24,0xf3,0x00,0x40,0x88,0x21, +0x3c,0x03,0xb0,0x03,0x34,0x63,0x00,0xbc,0x3c,0x04,0xb0,0x03,0x3c,0x05,0xb0,0x03, +0xa4,0x60,0x00,0x00,0x34,0x84,0x00,0xbb,0x34,0xa5,0x00,0xba,0x24,0x02,0x00,0x02, +0x24,0x03,0x00,0x01,0xa0,0x82,0x00,0x00,0x08,0x00,0x24,0xc5,0xa0,0xa3,0x00,0x00, +0x27,0xbd,0xff,0xd8,0xaf,0xb0,0x00,0x10,0x30,0xd0,0x00,0xff,0x2e,0x02,0x00,0x2e, +0xaf,0xb2,0x00,0x18,0xaf,0xb1,0x00,0x14,0xaf,0xbf,0x00,0x20,0xaf,0xb3,0x00,0x1c, +0x30,0xb1,0x00,0xff,0x14,0x40,0x00,0x06,0x00,0x80,0x90,0x21,0x8f,0xbf,0x00,0x20, +0x7b,0xb2,0x00,0xfc,0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x28, +0x2e,0x13,0x00,0x10,0x24,0x05,0x00,0x14,0x0c,0x00,0x13,0xa0,0x24,0x06,0x01,0x07, +0x12,0x60,0x00,0x38,0x02,0x00,0x30,0x21,0x8f,0xa2,0x00,0x38,0x30,0xc3,0x00,0x3f, +0x3c,0x04,0xb0,0x09,0x00,0x02,0x14,0x00,0x00,0x43,0x30,0x25,0x34,0x84,0x01,0x60, +0x90,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x40,0xff,0xfd,0x24,0x02,0x00,0x01, +0x12,0x22,0x00,0x2a,0x2a,0x22,0x00,0x02,0x14,0x40,0x00,0x24,0x24,0x02,0x00,0x02, +0x12,0x22,0x00,0x20,0x24,0x02,0x00,0x03,0x12,0x22,0x00,0x19,0x00,0x00,0x00,0x00, +0x16,0x60,0xff,0xe2,0x24,0x02,0x00,0x01,0x12,0x22,0x00,0x13,0x2a,0x22,0x00,0x02, +0x14,0x40,0x00,0x0d,0x24,0x02,0x00,0x02,0x12,0x22,0x00,0x09,0x24,0x02,0x00,0x03, +0x16,0x22,0xff,0xda,0x00,0x00,0x00,0x00,0x24,0x04,0x08,0x4c,0x24,0x05,0xff,0xff, +0x0c,0x00,0x13,0x5b,0x3c,0x06,0x0c,0xb8,0x08,0x00,0x25,0x43,0x00,0x00,0x00,0x00, +0x08,0x00,0x25,0x6b,0x24,0x04,0x08,0x48,0x16,0x20,0xff,0xd0,0x00,0x00,0x00,0x00, +0x08,0x00,0x25,0x6b,0x24,0x04,0x08,0x40,0x08,0x00,0x25,0x6b,0x24,0x04,0x08,0x44, +0x24,0x04,0x08,0x4c,0x0c,0x00,0x13,0x5b,0x24,0x05,0xff,0xff,0x08,0x00,0x25,0x60, +0x00,0x00,0x00,0x00,0x08,0x00,0x25,0x79,0x24,0x04,0x08,0x48,0x16,0x20,0xff,0xe0, +0x00,0x00,0x00,0x00,0x08,0x00,0x25,0x79,0x24,0x04,0x08,0x40,0x08,0x00,0x25,0x79, +0x24,0x04,0x08,0x44,0x02,0x40,0x20,0x21,0x0c,0x00,0x25,0xca,0x02,0x20,0x28,0x21, +0x08,0x00,0x25,0x4e,0x00,0x40,0x30,0x21,0x27,0xbd,0xff,0xd8,0x2c,0xc2,0x00,0x2e, +0xaf,0xb2,0x00,0x18,0xaf,0xb1,0x00,0x14,0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x20, +0xaf,0xb3,0x00,0x1c,0x00,0xc0,0x80,0x21,0x30,0xb1,0x00,0xff,0x00,0x80,0x90,0x21, +0x14,0x40,0x00,0x07,0x00,0x00,0x18,0x21,0x8f,0xbf,0x00,0x20,0x7b,0xb2,0x00,0xfc, +0x7b,0xb0,0x00,0xbc,0x00,0x60,0x10,0x21,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x28, +0x2e,0x13,0x00,0x10,0x24,0x05,0x00,0x14,0x0c,0x00,0x13,0xa0,0x24,0x06,0x01,0x07, +0x12,0x60,0x00,0x24,0x02,0x00,0x30,0x21,0x3c,0x03,0xb0,0x09,0x34,0x63,0x01,0x60, +0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x40,0xff,0xfd,0x30,0xc5,0x00,0x3f, +0x0c,0x00,0x26,0x07,0x02,0x20,0x20,0x21,0x16,0x60,0x00,0x0a,0x00,0x40,0x80,0x21, +0x24,0x02,0x00,0x01,0x12,0x22,0x00,0x15,0x2a,0x22,0x00,0x02,0x14,0x40,0x00,0x0f, +0x24,0x02,0x00,0x02,0x12,0x22,0x00,0x0b,0x24,0x02,0x00,0x03,0x12,0x22,0x00,0x03, +0x00,0x00,0x00,0x00,0x08,0x00,0x25,0x96,0x02,0x00,0x18,0x21,0x24,0x04,0x08,0x4c, +0x24,0x05,0xff,0xff,0x0c,0x00,0x13,0x5b,0x3c,0x06,0x0c,0xb8,0x08,0x00,0x25,0x96, +0x02,0x00,0x18,0x21,0x08,0x00,0x25,0xb8,0x24,0x04,0x08,0x48,0x16,0x20,0xff,0xf5, +0x00,0x00,0x00,0x00,0x08,0x00,0x25,0xb8,0x24,0x04,0x08,0x40,0x08,0x00,0x25,0xb8, +0x24,0x04,0x08,0x44,0x02,0x40,0x20,0x21,0x0c,0x00,0x25,0xca,0x02,0x20,0x28,0x21, +0x08,0x00,0x25,0xa2,0x00,0x40,0x30,0x21,0x27,0xbd,0xff,0xe8,0x2c,0xc2,0x00,0x1f, +0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x14,0x00,0xc0,0x80,0x21,0x14,0x40,0x00,0x1d, +0x30,0xa5,0x00,0xff,0x24,0x02,0x00,0x01,0x10,0xa2,0x00,0x18,0x28,0xa2,0x00,0x02, +0x14,0x40,0x00,0x12,0x24,0x02,0x00,0x02,0x10,0xa2,0x00,0x0e,0x24,0x02,0x00,0x03, +0x10,0xa2,0x00,0x07,0x24,0x04,0x08,0x4c,0x26,0x10,0xff,0xe2,0x02,0x00,0x10,0x21, +0x8f,0xbf,0x00,0x14,0x8f,0xb0,0x00,0x10,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18, +0x24,0x05,0xff,0xff,0x0c,0x00,0x13,0x5b,0x3c,0x06,0x0d,0xf8,0x08,0x00,0x25,0xdb, +0x26,0x10,0xff,0xe2,0x08,0x00,0x25,0xe0,0x24,0x04,0x08,0x48,0x14,0xa0,0xff,0xf2, +0x24,0x04,0x08,0x40,0x08,0x00,0x25,0xe1,0x24,0x05,0xff,0xff,0x08,0x00,0x25,0xe0, +0x24,0x04,0x08,0x44,0x2c,0xc2,0x00,0x10,0x14,0x40,0xff,0xec,0x24,0x02,0x00,0x01, +0x10,0xa2,0x00,0x14,0x28,0xa2,0x00,0x02,0x14,0x40,0x00,0x0e,0x24,0x02,0x00,0x02, +0x10,0xa2,0x00,0x0a,0x24,0x02,0x00,0x03,0x10,0xa2,0x00,0x03,0x24,0x04,0x08,0x4c, +0x08,0x00,0x25,0xdb,0x26,0x10,0xff,0xf1,0x24,0x05,0xff,0xff,0x0c,0x00,0x13,0x5b, +0x3c,0x06,0x0d,0xb8,0x08,0x00,0x25,0xdb,0x26,0x10,0xff,0xf1,0x08,0x00,0x25,0xfa, +0x24,0x04,0x08,0x48,0x14,0xa0,0xff,0xf6,0x24,0x04,0x08,0x40,0x08,0x00,0x25,0xfb, +0x24,0x05,0xff,0xff,0x08,0x00,0x25,0xfa,0x24,0x04,0x08,0x44,0x27,0xbd,0xff,0xe8, +0x30,0x84,0x00,0xff,0x24,0x02,0x00,0x01,0x10,0x82,0x00,0x39,0xaf,0xbf,0x00,0x10, +0x28,0x82,0x00,0x02,0x14,0x40,0x00,0x27,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02, +0x10,0x82,0x00,0x17,0x00,0xa0,0x30,0x21,0x24,0x02,0x00,0x03,0x10,0x82,0x00,0x05, +0x24,0x04,0x08,0x3c,0x8f,0xbf,0x00,0x10,0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08, +0x27,0xbd,0x00,0x18,0x0c,0x00,0x13,0x5b,0x3c,0x05,0x3f,0x00,0x24,0x04,0x08,0x3c, +0x3c,0x05,0x80,0x00,0x0c,0x00,0x13,0x5b,0x00,0x00,0x30,0x21,0x24,0x04,0x08,0x3c, +0x3c,0x05,0x80,0x00,0x0c,0x00,0x13,0x5b,0x24,0x06,0x00,0x01,0x24,0x04,0x08,0xac, +0x0c,0x00,0x13,0x3d,0x24,0x05,0x0f,0xff,0x08,0x00,0x26,0x15,0x00,0x00,0x00,0x00, +0x24,0x04,0x08,0x34,0x0c,0x00,0x13,0x5b,0x3c,0x05,0x3f,0x00,0x24,0x04,0x08,0x34, +0x3c,0x05,0x80,0x00,0x0c,0x00,0x13,0x5b,0x00,0x00,0x30,0x21,0x24,0x04,0x08,0x34, +0x3c,0x05,0x80,0x00,0x0c,0x00,0x13,0x5b,0x24,0x06,0x00,0x01,0x08,0x00,0x26,0x24, +0x24,0x04,0x08,0xa8,0x14,0x80,0xff,0xdf,0x00,0xa0,0x30,0x21,0x24,0x04,0x08,0x24, +0x0c,0x00,0x13,0x5b,0x3c,0x05,0x3f,0x00,0x24,0x04,0x08,0x24,0x3c,0x05,0x80,0x00, +0x0c,0x00,0x13,0x5b,0x00,0x00,0x30,0x21,0x24,0x04,0x08,0x24,0x3c,0x05,0x80,0x00, +0x0c,0x00,0x13,0x5b,0x24,0x06,0x00,0x01,0x08,0x00,0x26,0x24,0x24,0x04,0x08,0xa0, +0x00,0xa0,0x30,0x21,0x24,0x04,0x08,0x2c,0x0c,0x00,0x13,0x5b,0x3c,0x05,0x3f,0x00, +0x24,0x04,0x08,0x2c,0x3c,0x05,0x80,0x00,0x0c,0x00,0x13,0x5b,0x00,0x00,0x30,0x21, +0x24,0x04,0x08,0x2c,0x3c,0x05,0x80,0x00,0x0c,0x00,0x13,0x5b,0x24,0x06,0x00,0x01, +0x08,0x00,0x26,0x24,0x24,0x04,0x08,0xa4,0x3c,0x05,0x00,0x14,0x3c,0x02,0xb0,0x05, +0x34,0x42,0x04,0x20,0x3c,0x06,0xc0,0x00,0x3c,0x03,0xb0,0x05,0x3c,0x04,0xb0,0x05, +0x34,0xa5,0x17,0x09,0xac,0x45,0x00,0x00,0x34,0xc6,0x05,0x07,0x34,0x63,0x04,0x24, +0x34,0x84,0x02,0x28,0x3c,0x07,0xb0,0x05,0x24,0x02,0x00,0x20,0xac,0x66,0x00,0x00, +0x34,0xe7,0x04,0x50,0xa0,0x82,0x00,0x00,0x90,0xe2,0x00,0x00,0x00,0x00,0x00,0x00, +0x30,0x42,0x00,0x03,0x10,0x40,0xff,0xfc,0x24,0x02,0x00,0x01,0x03,0xe0,0x00,0x08, +0x00,0x00,0x00,0x00,0x93,0x85,0x81,0xf1,0x24,0x02,0x00,0x01,0x14,0xa2,0x00,0x51, +0x00,0x80,0x40,0x21,0x8c,0x89,0x00,0x04,0x3c,0x03,0xb0,0x01,0x01,0x23,0x30,0x21, +0x8c,0xc2,0x00,0x04,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x08,0x10,0x45,0x00,0x59, +0x00,0x00,0x00,0x00,0x94,0xc2,0x00,0x38,0x24,0x03,0x00,0xb4,0x30,0x44,0x00,0xff, +0x10,0x83,0x00,0x61,0x24,0x02,0x00,0xc4,0x10,0x82,0x00,0x54,0x24,0x02,0x00,0x94, +0x10,0x82,0x00,0x45,0x00,0x00,0x00,0x00,0x94,0xc2,0x00,0x38,0x00,0x00,0x00,0x00, +0x30,0x47,0xff,0xff,0x30,0xe3,0x40,0xff,0x24,0x02,0x40,0x88,0x14,0x62,0x00,0x39, +0x30,0xe3,0x03,0x00,0x24,0x02,0x03,0x00,0x10,0x62,0x00,0x38,0x00,0x00,0x00,0x00, +0x94,0xc2,0x00,0x56,0x00,0x00,0x00,0x00,0x30,0x47,0xff,0xff,0x30,0xe2,0x00,0x80, +0x14,0x40,0x00,0x30,0x3c,0x02,0xb0,0x01,0x01,0x22,0x30,0x21,0x94,0xc3,0x00,0x60, +0x24,0x02,0x00,0x08,0x14,0x43,0x00,0x3b,0x00,0x00,0x00,0x00,0x90,0xc2,0x00,0x62, +0x24,0x03,0x00,0x04,0x00,0x02,0x39,0x02,0x10,0xe3,0x00,0x15,0x24,0x02,0x00,0x06, +0x14,0xe2,0x00,0x34,0x00,0x00,0x00,0x00,0x8d,0x05,0x01,0xac,0x94,0xc4,0x00,0x66, +0x27,0x82,0x89,0x58,0x00,0x05,0x28,0x80,0x30,0x87,0xff,0xff,0x00,0xa2,0x28,0x21, +0x00,0x07,0x1a,0x00,0x8c,0xa4,0x00,0x00,0x00,0x07,0x12,0x02,0x00,0x43,0x10,0x25, +0x24,0x42,0x00,0x5e,0x24,0x03,0xc0,0x00,0x30,0x47,0xff,0xff,0x00,0x83,0x20,0x24, +0x00,0x87,0x20,0x25,0xac,0xa4,0x00,0x00,0x08,0x00,0x26,0xcd,0xad,0x07,0x00,0x10, +0x8d,0x05,0x01,0xac,0x94,0xc4,0x00,0x64,0x27,0x82,0x89,0x58,0x00,0x05,0x28,0x80, +0x30,0x87,0xff,0xff,0x00,0xa2,0x28,0x21,0x00,0x07,0x1a,0x00,0x8c,0xa4,0x00,0x00, +0x00,0x07,0x12,0x02,0x00,0x43,0x10,0x25,0x24,0x42,0x00,0x36,0x3c,0x03,0xff,0xff, +0x30,0x47,0xff,0xff,0x00,0x83,0x20,0x24,0x00,0x87,0x20,0x25,0xac,0xa4,0x00,0x00, +0xad,0x07,0x00,0x10,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x94,0xc2,0x00,0x50, +0x08,0x00,0x26,0x8b,0x30,0x47,0xff,0xff,0x8d,0x04,0x01,0xac,0x27,0x83,0x89,0x58, +0x00,0x04,0x20,0x80,0x00,0x83,0x20,0x21,0x8c,0x82,0x00,0x00,0x3c,0x03,0xff,0xff, +0x00,0x43,0x10,0x24,0x34,0x42,0x00,0x2e,0xac,0x82,0x00,0x00,0x24,0x03,0x00,0x2e, +0xad,0x03,0x00,0x10,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x8d,0x04,0x01,0xac, +0x27,0x83,0x89,0x58,0x00,0x04,0x20,0x80,0x00,0x83,0x20,0x21,0x8c,0x82,0x00,0x00, +0x3c,0x03,0xff,0xff,0x00,0x43,0x10,0x24,0x34,0x42,0x00,0x0e,0x24,0x03,0x00,0x0e, +0x08,0x00,0x26,0xcc,0xac,0x82,0x00,0x00,0x8d,0x04,0x01,0xac,0x27,0x83,0x89,0x58, +0x00,0x04,0x20,0x80,0x00,0x83,0x20,0x21,0x8c,0x82,0x00,0x00,0x3c,0x03,0xff,0xff, +0x00,0x43,0x10,0x24,0x34,0x42,0x00,0x14,0x24,0x03,0x00,0x14,0x08,0x00,0x26,0xcc, +0xac,0x82,0x00,0x00,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x30,0xc6,0x00,0xff, +0x00,0x06,0x48,0x40,0x01,0x26,0x10,0x21,0x00,0x02,0x10,0x80,0x27,0x8b,0xbc,0x20, +0x27,0x83,0xbc,0x26,0x00,0x4b,0x40,0x21,0x00,0x43,0x10,0x21,0x94,0x47,0x00,0x00, +0x30,0xa2,0x3f,0xff,0x10,0xe2,0x00,0x29,0x30,0x8a,0xff,0xff,0x95,0x02,0x00,0x02, +0x24,0x03,0x00,0x01,0x00,0x02,0x11,0x82,0x30,0x42,0x00,0x01,0x10,0x43,0x00,0x18, +0x00,0x00,0x00,0x00,0x01,0x26,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x4b,0x30,0x21, +0x94,0xc4,0x00,0x02,0x27,0x83,0xbc,0x26,0x27,0x85,0xbc,0x24,0x00,0x45,0x28,0x21, +0x30,0x84,0xff,0xdf,0x00,0x43,0x10,0x21,0xa4,0xc4,0x00,0x02,0xa4,0x40,0x00,0x00, +0xa4,0xa0,0x00,0x00,0x94,0xc3,0x00,0x02,0x3c,0x04,0xb0,0x01,0x01,0x44,0x20,0x21, +0x30,0x63,0xff,0xbf,0xa4,0xc3,0x00,0x02,0xa0,0xc0,0x00,0x00,0x8c,0x82,0x00,0x04, +0x24,0x03,0xf0,0xff,0x00,0x43,0x10,0x24,0x03,0xe0,0x00,0x08,0xac,0x82,0x00,0x04, +0x24,0x02,0xc0,0x00,0x91,0x04,0x00,0x01,0x00,0xa2,0x10,0x24,0x00,0x47,0x28,0x25, +0x3c,0x03,0xb0,0x01,0x24,0x02,0x00,0x02,0x14,0x82,0xff,0xe2,0x01,0x43,0x18,0x21, +0xac,0x65,0x00,0x00,0x08,0x00,0x26,0xfa,0x01,0x26,0x10,0x21,0x08,0x00,0x26,0xfa, +0x01,0x26,0x10,0x21,0x93,0x83,0x81,0xf1,0x24,0x02,0x00,0x01,0x14,0x62,0x00,0x0d, +0x3c,0x02,0xb0,0x01,0x8c,0x84,0x00,0x04,0x3c,0x06,0xb0,0x09,0x00,0x82,0x20,0x21, +0x8c,0x85,0x00,0x08,0x8c,0x83,0x00,0x04,0x3c,0x02,0x01,0x00,0x34,0xc6,0x01,0x00, +0x00,0x62,0x18,0x24,0x14,0x60,0x00,0x05,0x30,0xa5,0x20,0x00,0x24,0x02,0x00,0x06, +0xa0,0xc2,0x00,0x00,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x09, +0x10,0xa0,0xff,0xfc,0x34,0x63,0x01,0x00,0x24,0x02,0x00,0x0e,0x08,0x00,0x27,0x2d, +0xa0,0x62,0x00,0x00,0x3c,0x02,0xb0,0x01,0x30,0xa5,0xff,0xff,0x00,0xa2,0x28,0x21, +0x8c,0xa3,0x00,0x00,0x3c,0x02,0x10,0x00,0x00,0x80,0x30,0x21,0x00,0x62,0x18,0x24, +0x8c,0xa2,0x00,0x04,0x10,0x60,0x00,0x04,0x00,0x00,0x00,0x00,0x30,0x42,0x80,0x00, +0x10,0x40,0x00,0x13,0x00,0x00,0x00,0x00,0x8c,0xc2,0x01,0xa8,0x00,0x00,0x00,0x00, +0x24,0x44,0x00,0x01,0x28,0x83,0x00,0x00,0x24,0x42,0x00,0x40,0x00,0x83,0x10,0x0a, +0x93,0x83,0x81,0xf0,0x00,0x02,0x11,0x83,0x00,0x02,0x11,0x80,0x00,0x82,0x20,0x23, +0x24,0x63,0xff,0xff,0xac,0xc4,0x01,0xa8,0xa3,0x83,0x81,0xf0,0x8c,0xc4,0x01,0xac, +0x8c,0xc2,0x01,0xa8,0x00,0x00,0x00,0x00,0x00,0x44,0x10,0x26,0x00,0x02,0x10,0x2b, +0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03,0x34,0x63,0x00,0x73, +0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x01,0x14,0x40,0x00,0x04, +0x00,0x00,0x00,0x00,0xa3,0x80,0x81,0xf1,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00, +0x24,0x02,0x00,0x01,0xa3,0x82,0x81,0xf1,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00, +0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0xa8,0x8c,0x43,0x00,0x00,0x00,0x00,0x00,0x00, +0x30,0x62,0x00,0xff,0x00,0x03,0x2e,0x02,0x00,0x02,0x39,0x80,0x2c,0xa2,0x00,0x02, +0x00,0x03,0x34,0x02,0x10,0x40,0x00,0x05,0x00,0x03,0x1a,0x02,0xa4,0x87,0x01,0xd8, +0xa0,0x85,0x01,0xd4,0xa0,0x86,0x01,0xd5,0xa0,0x83,0x01,0xd6,0x03,0xe0,0x00,0x08, +0x00,0x00,0x00,0x00,0x8c,0x82,0x00,0x04,0x3c,0x05,0xb0,0x01,0x00,0x80,0x50,0x21, +0x00,0x45,0x10,0x21,0x8c,0x43,0x00,0x04,0x24,0x02,0x00,0x05,0x00,0x03,0x1a,0x02, +0x30,0x69,0x00,0x0f,0x11,0x22,0x00,0x0b,0x24,0x02,0x00,0x07,0x11,0x22,0x00,0x09, +0x24,0x02,0x00,0x0a,0x11,0x22,0x00,0x07,0x24,0x02,0x00,0x0b,0x11,0x22,0x00,0x05, +0x24,0x02,0x00,0x01,0x93,0x83,0x81,0xf0,0x3c,0x04,0xb0,0x06,0x10,0x62,0x00,0x03, +0x34,0x84,0x80,0x18,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x8c,0x82,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x02,0x17,0x02,0x14,0x40,0xff,0xfa,0x00,0x00,0x00,0x00, +0x8d,0x43,0x01,0xa8,0x27,0x82,0x89,0x58,0x00,0x03,0x18,0x80,0x00,0x6a,0x20,0x21, +0x8c,0x87,0x00,0xa8,0x00,0x62,0x18,0x21,0x8c,0x68,0x00,0x00,0x00,0xe5,0x28,0x21, +0x8c,0xa9,0x00,0x00,0x3c,0x02,0xff,0xff,0x27,0x83,0x8a,0x58,0x01,0x22,0x10,0x24, +0x00,0x48,0x10,0x25,0xac,0xa2,0x00,0x00,0x8d,0x44,0x01,0xa8,0x00,0x07,0x30,0xc2, +0x3c,0x02,0x00,0x80,0x00,0x04,0x20,0x80,0x00,0x83,0x20,0x21,0x00,0x06,0x32,0x00, +0x8c,0xa9,0x00,0x04,0x00,0xc2,0x30,0x25,0x8c,0x82,0x00,0x00,0x3c,0x03,0x80,0x00, +0x01,0x22,0x10,0x25,0x00,0x43,0x10,0x25,0xac,0xa2,0x00,0x04,0xaf,0x87,0xbc,0x10, +0x8c,0xa2,0x00,0x00,0x00,0x00,0x00,0x00,0xaf,0x82,0xbc,0x18,0x8c,0xa3,0x00,0x04, +0x3c,0x01,0xb0,0x07,0xac,0x26,0x80,0x18,0x8d,0x42,0x01,0xa8,0xaf,0x83,0xbc,0x14, +0x93,0x85,0x81,0xf0,0x24,0x44,0x00,0x01,0x28,0x83,0x00,0x00,0x24,0x42,0x00,0x40, +0x00,0x83,0x10,0x0a,0x00,0x02,0x11,0x83,0x00,0x02,0x11,0x80,0x24,0xa5,0xff,0xff, +0x00,0x82,0x20,0x23,0xad,0x44,0x01,0xa8,0xa3,0x85,0x81,0xf0,0x08,0x00,0x27,0x89, +0x00,0x00,0x00,0x00,0x3c,0x05,0xb0,0x03,0x3c,0x02,0x80,0x01,0x24,0x42,0x9f,0x04, +0x34,0xa5,0x00,0x20,0xac,0xa2,0x00,0x00,0x24,0x02,0x00,0x02,0x24,0x03,0x00,0x20, +0xac,0x82,0x00,0x64,0x3c,0x02,0x80,0x01,0xac,0x83,0x00,0x60,0x00,0x80,0x38,0x21, +0xac,0x80,0x00,0x00,0xac,0x80,0x00,0x04,0xac,0x80,0x00,0x08,0xac,0x80,0x00,0x4c, +0xac,0x80,0x00,0x50,0xac,0x80,0x00,0x54,0xac,0x80,0x00,0x0c,0xac,0x80,0x00,0x58, +0xa0,0x80,0x00,0x5c,0x24,0x83,0x00,0x68,0x24,0x42,0xa0,0x14,0x24,0x04,0x00,0x0f, +0x24,0x84,0xff,0xff,0xac,0x62,0x00,0x00,0x04,0x81,0xff,0xfd,0x24,0x63,0x00,0x04, +0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0xa8,0xac,0xe0,0x01,0xa8,0xac,0xe0,0x01,0xac, +0xac,0xe0,0x01,0xb0,0xac,0xe0,0x01,0xb4,0xa0,0xe0,0x01,0xb8,0xa0,0xe0,0x01,0xb9, +0xa0,0xe0,0x01,0xba,0xa0,0xe0,0x01,0xc0,0xa0,0xe0,0x01,0xc1,0xac,0xe0,0x01,0xc4, +0xac,0xe0,0x01,0xc8,0xac,0xe0,0x01,0xcc,0xac,0xe0,0x01,0xd0,0x8c,0x44,0x00,0x00, +0x3c,0x02,0x80,0x01,0x24,0x42,0xa0,0xfc,0x30,0x83,0x00,0xff,0x00,0x03,0x19,0x80, +0xa4,0xe3,0x01,0xd8,0xac,0xe2,0x00,0x78,0x3c,0x03,0x80,0x01,0x3c,0x02,0x80,0x01, +0x24,0x63,0xa2,0x88,0x24,0x42,0xa1,0xf4,0xac,0xe3,0x00,0x88,0xac,0xe2,0x00,0x98, +0x3c,0x03,0x80,0x01,0x3c,0x02,0x80,0x01,0x00,0x04,0x2e,0x03,0x00,0x04,0x34,0x03, +0x24,0x63,0xa3,0x30,0x00,0x04,0x22,0x03,0x24,0x42,0xa4,0x74,0xac,0xe3,0x00,0xa0, +0xac,0xe2,0x00,0xa4,0xa0,0xe5,0x01,0xd4,0xa0,0xe6,0x01,0xd5,0x03,0xe0,0x00,0x08, +0xa0,0xe4,0x01,0xd6,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x01,0x34,0x63,0x00,0x20, +0x24,0x42,0xa0,0x14,0x03,0xe0,0x00,0x08,0xac,0x62,0x00,0x00,0x3c,0x02,0xb0,0x03, +0x3c,0x03,0x80,0x01,0x34,0x42,0x00,0x20,0x24,0x63,0xa0,0x2c,0xac,0x43,0x00,0x00, +0x8c,0x82,0x00,0x10,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x11,0x00,0x80,0x28,0x21, +0x8c,0x82,0x00,0x14,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x0d,0x00,0x00,0x00,0x00, +0x8c,0x84,0x00,0x10,0x8c,0xa3,0x00,0x14,0x8c,0xa2,0x00,0x04,0x00,0x83,0x20,0x21, +0x00,0x44,0x10,0x21,0x30,0x43,0x00,0xff,0x00,0x03,0x18,0x2b,0x00,0x02,0x12,0x02, +0x00,0x43,0x10,0x21,0x00,0x02,0x12,0x00,0x30,0x42,0x3f,0xff,0xac,0xa2,0x00,0x04, +0xac,0xa0,0x00,0x00,0xac,0xa0,0x00,0x4c,0xac,0xa0,0x00,0x50,0xac,0xa0,0x00,0x54, +0x03,0xe0,0x00,0x08,0xac,0xa0,0x00,0x0c,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x01, +0x34,0x63,0x00,0x20,0x24,0x42,0xa0,0xa8,0xac,0x62,0x00,0x00,0x8c,0x86,0x00,0x04, +0x3c,0x02,0xb0,0x01,0x24,0x03,0x00,0x01,0x00,0xc2,0x10,0x21,0x8c,0x45,0x00,0x00, +0xac,0x83,0x00,0x4c,0x00,0x05,0x14,0x02,0x30,0xa3,0x3f,0xff,0x30,0x42,0x00,0xff, +0xac,0x83,0x00,0x10,0xac,0x82,0x00,0x14,0x8c,0x83,0x00,0x14,0xac,0x85,0x00,0x40, +0x00,0xc3,0x30,0x21,0x03,0xe0,0x00,0x08,0xac,0x86,0x00,0x08,0x3c,0x02,0xb0,0x03, +0x3c,0x03,0x80,0x01,0x27,0xbd,0xff,0xe8,0x34,0x42,0x00,0x20,0x24,0x63,0xa0,0xfc, +0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x14,0xac,0x43,0x00,0x00,0x8c,0x82,0x00,0x4c, +0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x0a,0x00,0x80,0x80,0x21,0xae,0x00,0x00,0x00, +0xae,0x00,0x00,0x4c,0xae,0x00,0x00,0x50,0xae,0x00,0x00,0x54,0xae,0x00,0x00,0x0c, +0x8f,0xbf,0x00,0x14,0x8f,0xb0,0x00,0x10,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18, +0x0c,0x00,0x28,0x2a,0x00,0x00,0x00,0x00,0x08,0x00,0x28,0x4c,0xae,0x00,0x00,0x00, +0x3c,0x02,0xb0,0x03,0x3c,0x03,0x80,0x01,0x27,0xbd,0xff,0xe8,0x34,0x42,0x00,0x20, +0x24,0x63,0xa1,0x60,0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x14,0xac,0x43,0x00,0x00, +0x8c,0x82,0x00,0x4c,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x16,0x00,0x80,0x80,0x21, +0x8e,0x03,0x00,0x08,0x3c,0x02,0xb0,0x01,0x8e,0x04,0x00,0x44,0x00,0x62,0x18,0x21, +0x90,0x65,0x00,0x00,0x24,0x02,0x00,0x01,0xae,0x02,0x00,0x50,0x30,0xa3,0x00,0xff, +0x00,0x03,0x10,0x82,0x00,0x04,0x23,0x02,0x30,0x84,0x00,0x0f,0x30,0x42,0x00,0x03, +0x00,0x03,0x19,0x02,0xae,0x04,0x00,0x34,0xae,0x02,0x00,0x2c,0xae,0x03,0x00,0x30, +0xa2,0x05,0x00,0x48,0x8f,0xbf,0x00,0x14,0x8f,0xb0,0x00,0x10,0x03,0xe0,0x00,0x08, +0x27,0xbd,0x00,0x18,0x0c,0x00,0x28,0x2a,0x00,0x00,0x00,0x00,0x08,0x00,0x28,0x64, +0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x03,0x3c,0x03,0x80,0x01,0x27,0xbd,0xff,0xe8, +0x34,0x42,0x00,0x20,0x24,0x63,0xa1,0xf4,0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x14, +0xac,0x43,0x00,0x00,0x8c,0x82,0x00,0x50,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x16, +0x00,0x80,0x80,0x21,0x92,0x03,0x00,0x44,0x8e,0x02,0x00,0x40,0x83,0x85,0x8b,0xc4, +0x92,0x04,0x00,0x41,0x30,0x63,0x00,0x01,0x00,0x02,0x16,0x02,0xae,0x04,0x00,0x14, +0x00,0x00,0x30,0x21,0xae,0x02,0x00,0x18,0x10,0xa0,0x00,0x04,0xae,0x03,0x00,0x3c, +0x10,0x60,0x00,0x03,0x24,0x02,0x00,0x01,0x24,0x06,0x00,0x01,0x24,0x02,0x00,0x01, +0xa3,0x86,0x8b,0xc4,0x8f,0xbf,0x00,0x14,0xae,0x02,0x00,0x54,0x8f,0xb0,0x00,0x10, +0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18,0x0c,0x00,0x28,0x58,0x00,0x00,0x00,0x00, +0x08,0x00,0x28,0x89,0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x03,0x3c,0x03,0x80,0x01, +0x27,0xbd,0xff,0xe8,0x34,0x42,0x00,0x20,0x24,0x63,0xa2,0x88,0xaf,0xb0,0x00,0x10, +0xaf,0xbf,0x00,0x14,0xac,0x43,0x00,0x00,0x8c,0x82,0x00,0x50,0x00,0x00,0x00,0x00, +0x10,0x40,0x00,0x1b,0x00,0x80,0x80,0x21,0x3c,0x02,0xb0,0x03,0x8c,0x42,0x00,0x00, +0x92,0x04,0x00,0x44,0x8e,0x03,0x00,0x40,0x83,0x86,0x8b,0xc4,0x92,0x05,0x00,0x41, +0x30,0x42,0x08,0x00,0x30,0x84,0x00,0x01,0x00,0x02,0x12,0xc2,0x00,0x03,0x1e,0x02, +0x00,0x82,0x20,0x25,0xae,0x05,0x00,0x14,0x00,0x00,0x38,0x21,0xae,0x03,0x00,0x18, +0x10,0xc0,0x00,0x04,0xae,0x04,0x00,0x3c,0x10,0x80,0x00,0x03,0x24,0x02,0x00,0x01, +0x24,0x07,0x00,0x01,0x24,0x02,0x00,0x01,0xa3,0x87,0x8b,0xc4,0x8f,0xbf,0x00,0x14, +0xae,0x02,0x00,0x54,0x8f,0xb0,0x00,0x10,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18, +0x0c,0x00,0x28,0x58,0x00,0x00,0x00,0x00,0x08,0x00,0x28,0xae,0x00,0x00,0x00,0x00, +0x3c,0x02,0xb0,0x03,0x3c,0x03,0x80,0x01,0x27,0xbd,0xff,0xe8,0x34,0x42,0x00,0x20, +0x24,0x63,0xa3,0x30,0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x14,0xac,0x43,0x00,0x00, +0x8c,0x82,0x00,0x54,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x42,0x00,0x80,0x80,0x21, +0x8e,0x04,0x00,0x04,0x8e,0x03,0x00,0x44,0x3c,0x02,0x80,0x00,0x3c,0x08,0xb0,0x01, +0x34,0x42,0x00,0x10,0x00,0x88,0x20,0x21,0x00,0x62,0x18,0x25,0xac,0x83,0x00,0x04, +0x8e,0x02,0x00,0x04,0x8e,0x03,0x01,0xac,0x27,0x89,0x89,0x58,0x00,0x48,0x10,0x21, +0x8c,0x45,0x00,0x00,0x00,0x03,0x18,0x80,0x00,0x69,0x18,0x21,0xac,0x65,0x00,0x00, +0x8e,0x02,0x00,0x04,0x8e,0x03,0x01,0xac,0x27,0x87,0x8a,0x58,0x00,0x48,0x10,0x21, +0x8c,0x45,0x00,0x04,0x00,0x03,0x18,0x80,0x00,0x67,0x18,0x21,0xac,0x65,0x00,0x00, +0x8e,0x02,0x01,0xac,0x8e,0x06,0x00,0x04,0x02,0x00,0x20,0x21,0x00,0x02,0x10,0x80, +0x00,0x47,0x38,0x21,0x94,0xe3,0x00,0x02,0x00,0x49,0x10,0x21,0x90,0x45,0x00,0x00, +0x00,0x03,0x1a,0x00,0x00,0xc8,0x30,0x21,0x00,0xa3,0x28,0x25,0x0c,0x00,0x26,0x69, +0xa4,0xc5,0x00,0x2e,0x8e,0x03,0x01,0xac,0x8e,0x07,0x00,0x04,0x3c,0x06,0xb0,0x03, +0x24,0x65,0x00,0x01,0x28,0xa4,0x00,0x00,0x24,0x62,0x00,0x40,0x00,0xa4,0x10,0x0a, +0x00,0x02,0x11,0x83,0x00,0x02,0x11,0x80,0x00,0x03,0x18,0x80,0x00,0xa2,0x28,0x23, +0x00,0x70,0x18,0x21,0xae,0x05,0x01,0xac,0xac,0x67,0x00,0xa8,0x34,0xc6,0x00,0x30, +0x8c,0xc3,0x00,0x00,0x93,0x82,0x81,0xf0,0x02,0x00,0x20,0x21,0x24,0x63,0x00,0x01, +0x24,0x42,0x00,0x01,0xac,0xc3,0x00,0x00,0xa3,0x82,0x81,0xf0,0x0c,0x00,0x28,0x0b, +0x00,0x00,0x00,0x00,0x8f,0xbf,0x00,0x14,0x8f,0xb0,0x00,0x10,0x03,0xe0,0x00,0x08, +0x27,0xbd,0x00,0x18,0x0c,0x00,0x28,0xa2,0x00,0x00,0x00,0x00,0x08,0x00,0x28,0xd8, +0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x03,0x3c,0x03,0x80,0x01,0x27,0xbd,0xff,0xe8, +0x34,0x42,0x00,0x20,0x24,0x63,0xa4,0x74,0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x14, +0xac,0x43,0x00,0x00,0x8c,0x82,0x00,0x54,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x42, +0x00,0x80,0x80,0x21,0x8e,0x04,0x00,0x04,0x8e,0x03,0x00,0x44,0x3c,0x02,0x80,0x00, +0x3c,0x08,0xb0,0x01,0x34,0x42,0x00,0x10,0x00,0x88,0x20,0x21,0x00,0x62,0x18,0x25, +0xac,0x83,0x00,0x04,0x8e,0x02,0x00,0x04,0x8e,0x03,0x01,0xac,0x27,0x89,0x89,0x58, +0x00,0x48,0x10,0x21,0x8c,0x45,0x00,0x00,0x00,0x03,0x18,0x80,0x00,0x69,0x18,0x21, +0xac,0x65,0x00,0x00,0x8e,0x02,0x00,0x04,0x8e,0x03,0x01,0xac,0x27,0x87,0x8a,0x58, +0x00,0x48,0x10,0x21,0x8c,0x45,0x00,0x04,0x00,0x03,0x18,0x80,0x00,0x67,0x18,0x21, +0xac,0x65,0x00,0x00,0x8e,0x02,0x01,0xac,0x8e,0x06,0x00,0x04,0x02,0x00,0x20,0x21, +0x00,0x02,0x10,0x80,0x00,0x47,0x38,0x21,0x94,0xe3,0x00,0x02,0x00,0x49,0x10,0x21, +0x90,0x45,0x00,0x00,0x00,0x03,0x1a,0x00,0x00,0xc8,0x30,0x21,0x00,0xa3,0x28,0x25, +0x0c,0x00,0x26,0x69,0xa4,0xc5,0x00,0x2e,0x8e,0x03,0x01,0xac,0x8e,0x07,0x00,0x04, +0x3c,0x06,0xb0,0x03,0x24,0x65,0x00,0x01,0x28,0xa4,0x00,0x00,0x24,0x62,0x00,0x40, +0x00,0xa4,0x10,0x0a,0x00,0x02,0x11,0x83,0x00,0x02,0x11,0x80,0x00,0x03,0x18,0x80, +0x00,0xa2,0x28,0x23,0x00,0x70,0x18,0x21,0xae,0x05,0x01,0xac,0xac,0x67,0x00,0xa8, +0x34,0xc6,0x00,0x30,0x8c,0xc3,0x00,0x00,0x93,0x82,0x81,0xf0,0x02,0x00,0x20,0x21, +0x24,0x63,0x00,0x01,0x24,0x42,0x00,0x01,0xac,0xc3,0x00,0x00,0xa3,0x82,0x81,0xf0, +0x0c,0x00,0x28,0x0b,0x00,0x00,0x00,0x00,0x8f,0xbf,0x00,0x14,0x8f,0xb0,0x00,0x10, +0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18,0x0c,0x00,0x28,0xa2,0x00,0x00,0x00,0x00, +0x08,0x00,0x29,0x29,0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x03,0x3c,0x03,0x80,0x01, +0x27,0xbd,0xff,0xd8,0x34,0x42,0x00,0x20,0x24,0x63,0xa5,0xb8,0xaf,0xb2,0x00,0x18, +0xac,0x43,0x00,0x00,0x3c,0x12,0xb0,0x03,0x3c,0x02,0x80,0x01,0xaf,0xb4,0x00,0x20, +0xaf,0xb3,0x00,0x1c,0xaf,0xb1,0x00,0x14,0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x24, +0x00,0x80,0x80,0x21,0x24,0x54,0xa0,0x14,0x00,0x00,0x88,0x21,0x3c,0x13,0xb0,0x01, +0x36,0x52,0x00,0xef,0x3c,0x02,0xb0,0x09,0x34,0x42,0x00,0x06,0x90,0x43,0x00,0x00, +0x8e,0x04,0x00,0x04,0x92,0x02,0x01,0xbb,0x30,0x69,0x00,0xff,0x00,0x04,0x42,0x02, +0x10,0x40,0x00,0x1e,0x00,0x00,0x38,0x21,0x8e,0x03,0x01,0xa8,0x3c,0x06,0x28,0x38, +0x34,0xc6,0x00,0x20,0x24,0x64,0x00,0x3d,0x28,0x82,0x00,0x00,0x24,0x63,0x00,0x7c, +0x00,0x82,0x18,0x0a,0x00,0x03,0x19,0x83,0x00,0x03,0x19,0x80,0x00,0x83,0x20,0x23, +0x00,0x04,0x10,0x80,0x00,0x50,0x10,0x21,0x8c,0x45,0x00,0xa8,0xae,0x04,0x01,0xac, +0xae,0x04,0x01,0xa8,0x00,0xb3,0x18,0x21,0xae,0x05,0x00,0x04,0xac,0x66,0x00,0x00, +0x8e,0x02,0x00,0x04,0x3c,0x03,0x80,0x00,0x34,0x63,0x4e,0x00,0x00,0x53,0x10,0x21, +0xac,0x43,0x00,0x04,0xa2,0x00,0x01,0xbb,0x93,0x83,0x81,0xf7,0x00,0x00,0x00,0x00, +0x24,0x62,0x00,0x01,0xa3,0x82,0x81,0xf7,0xa2,0x43,0x00,0x00,0x01,0x28,0x10,0x23, +0x24,0x44,0x00,0x40,0x28,0x83,0x00,0x00,0x24,0x42,0x00,0x7f,0x00,0x83,0x10,0x0a, +0x00,0x02,0x11,0x83,0x00,0x02,0x11,0x80,0x24,0x84,0xff,0xff,0x10,0x44,0x00,0x6b, +0x3c,0x02,0xb0,0x01,0x8e,0x03,0x00,0x04,0x3c,0x04,0x7c,0x00,0x00,0x62,0x18,0x21, +0x8c,0x65,0x00,0x04,0x34,0x84,0x00,0xf0,0x00,0x00,0x30,0x21,0xae,0x05,0x00,0x44, +0x00,0xa4,0x20,0x24,0x8c,0x63,0x00,0x00,0x10,0x80,0x00,0x6b,0x3c,0x02,0xff,0xff, +0x3c,0x09,0xb0,0x03,0x3c,0x05,0x7c,0x00,0x35,0x29,0x00,0x99,0x3c,0x0a,0xb0,0x01, +0x24,0x08,0x00,0x40,0x34,0xa5,0x00,0xf0,0x3c,0x0b,0xff,0xff,0x3c,0x0c,0x28,0x38, +0x16,0x20,0x00,0x06,0x24,0xe7,0x00,0x01,0x93,0x82,0x81,0xf6,0x24,0x11,0x00,0x01, +0x24,0x42,0x00,0x01,0xa1,0x22,0x00,0x00,0xa3,0x82,0x81,0xf6,0x8e,0x02,0x00,0x04, +0x24,0x06,0x00,0x01,0x24,0x42,0x01,0x00,0x30,0x42,0x3f,0xff,0xae,0x02,0x00,0x04, +0x00,0x4a,0x10,0x21,0x8c,0x43,0x00,0x04,0x00,0x00,0x00,0x00,0xae,0x03,0x00,0x44, +0x00,0x65,0x20,0x24,0x8c,0x43,0x00,0x00,0x10,0xe8,0x00,0x2d,0x00,0x00,0x00,0x00, +0x14,0x80,0xff,0xeb,0x00,0x6b,0x10,0x24,0x14,0x4c,0xff,0xe9,0x24,0x02,0x00,0x01, +0x10,0xc2,0x00,0x30,0x3c,0x03,0xb0,0x09,0x8e,0x02,0x00,0x44,0x8e,0x04,0x00,0x60, +0x00,0x02,0x1e,0x42,0x00,0x02,0x12,0x02,0x30,0x42,0x00,0x0f,0x30,0x63,0x00,0x01, +0xae,0x02,0x00,0x00,0x10,0x44,0x00,0x1a,0xae,0x03,0x00,0x58,0x8e,0x02,0x00,0x64, +0x8e,0x04,0x00,0x58,0x00,0x00,0x00,0x00,0x10,0x82,0x00,0x05,0x00,0x00,0x00,0x00, +0xae,0x00,0x00,0x4c,0xae,0x00,0x00,0x50,0xae,0x00,0x00,0x54,0xae,0x00,0x00,0x0c, +0x8e,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x10,0x80,0x00,0x50,0x10,0x21, +0x8c,0x42,0x00,0x68,0x00,0x00,0x00,0x00,0x10,0x54,0x00,0x06,0x00,0x00,0x00,0x00, +0x00,0x40,0xf8,0x09,0x02,0x00,0x20,0x21,0x8e,0x04,0x00,0x58,0x8e,0x03,0x00,0x00, +0x00,0x00,0x00,0x00,0xae,0x03,0x00,0x60,0x08,0x00,0x29,0x81,0xae,0x04,0x00,0x64, +0x8e,0x02,0x00,0x64,0x00,0x00,0x00,0x00,0x14,0x62,0xff,0xe5,0x00,0x00,0x00,0x00, +0x7a,0x02,0x0d,0x7c,0x8f,0xbf,0x00,0x24,0x8f,0xb4,0x00,0x20,0x7b,0xb2,0x00,0xfc, +0x7b,0xb0,0x00,0xbc,0x00,0x43,0x10,0x26,0x00,0x02,0x10,0x2b,0x03,0xe0,0x00,0x08, +0x27,0xbd,0x00,0x28,0x8e,0x04,0x00,0x04,0x34,0x63,0x00,0x06,0x90,0x62,0x00,0x00, +0x00,0x04,0x42,0x02,0x00,0x48,0x10,0x23,0x24,0x44,0x00,0x40,0x28,0x83,0x00,0x00, +0x24,0x42,0x00,0x7f,0x00,0x83,0x10,0x0a,0x00,0x02,0x11,0x83,0x00,0x02,0x11,0x80, +0x00,0x82,0x20,0x23,0x14,0x86,0xff,0xc4,0x00,0x00,0x00,0x00,0x8e,0x03,0x00,0x00, +0x00,0x00,0x00,0x00,0x2c,0x62,0x00,0x03,0x14,0x40,0x00,0x05,0x24,0x02,0x00,0x0d, +0x10,0x62,0x00,0x03,0x24,0x02,0x00,0x01,0x08,0x00,0x2a,0x04,0xa2,0x02,0x00,0x5c, +0x08,0x00,0x2a,0x04,0xa2,0x00,0x00,0x5c,0x00,0x62,0x10,0x24,0x3c,0x03,0x28,0x38, +0x14,0x43,0xff,0x93,0x24,0x02,0x00,0x01,0x08,0x00,0x29,0xdc,0x00,0x00,0x00,0x00, +0x3c,0x02,0xb0,0x01,0x00,0xa2,0x40,0x21,0x00,0xa0,0x48,0x21,0x8d,0x05,0x00,0x00, +0x24,0x02,0xc0,0x00,0x00,0x09,0x38,0xc2,0x00,0xa2,0x28,0x24,0x24,0xc2,0xff,0xff, +0x00,0x07,0x3a,0x00,0x3c,0x0a,0xb0,0x06,0x3c,0x03,0x00,0x80,0x00,0xa6,0x28,0x25, +0x2c,0x42,0x1f,0xff,0x00,0xe3,0x38,0x25,0x35,0x4a,0x80,0x18,0x10,0x40,0x00,0x0e, +0xad,0x05,0x00,0x00,0xaf,0x89,0xbc,0x10,0x8d,0x02,0x00,0x00,0x00,0x00,0x00,0x00, +0xaf,0x82,0xbc,0x18,0x8d,0x03,0x00,0x04,0xad,0x47,0x00,0x00,0xaf,0x83,0xbc,0x14, +0xac,0x80,0x01,0xd0,0xac,0x80,0x01,0xc4,0xa0,0x80,0x01,0xc0,0xa0,0x80,0x01,0xc1, +0xac,0x80,0x01,0xc8,0xac,0x80,0x01,0xcc,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00, +0x27,0xbd,0xff,0xe8,0xaf,0xbf,0x00,0x10,0x8c,0x83,0x01,0xc4,0x00,0x80,0x38,0x21, +0x90,0x84,0x01,0xc0,0x00,0x03,0x18,0x80,0x00,0x67,0x18,0x21,0x8c,0x65,0x00,0xa8, +0x3c,0x02,0xb0,0x01,0x24,0x03,0x00,0x01,0x00,0xa2,0x10,0x21,0x8c,0x42,0x00,0x00, +0x10,0x83,0x00,0x18,0x00,0x02,0x14,0x02,0x8c,0xe9,0x01,0xcc,0x8c,0xea,0x01,0xc8, +0x30,0x46,0x00,0xff,0x01,0x2a,0x18,0x21,0x30,0x64,0x00,0xff,0x00,0x03,0x1a,0x02, +0x24,0x62,0x00,0x01,0x14,0x80,0x00,0x02,0x30,0x48,0x00,0xff,0x30,0x68,0x00,0xff, +0x90,0xe2,0x01,0xc1,0x00,0x00,0x00,0x00,0x00,0x48,0x10,0x23,0x00,0x02,0x12,0x00, +0x00,0x49,0x10,0x21,0x00,0x4a,0x10,0x21,0x00,0x46,0x30,0x23,0x0c,0x00,0x2a,0x2c, +0x00,0xe0,0x20,0x21,0x8f,0xbf,0x00,0x10,0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08, +0x27,0xbd,0x00,0x18,0x8c,0xe6,0x01,0xc8,0x08,0x00,0x2a,0x6b,0x00,0x00,0x00,0x00, +0x27,0xbd,0xff,0xe8,0xaf,0xbf,0x00,0x14,0xaf,0xb0,0x00,0x10,0x8c,0x82,0x01,0xc4, +0x90,0x87,0x01,0xc1,0x00,0x80,0x80,0x21,0x00,0x02,0x10,0x80,0x00,0x44,0x10,0x21, +0x8c,0x48,0x00,0xa8,0x3c,0x02,0xb0,0x01,0x00,0x07,0x3a,0x00,0x01,0x02,0x10,0x21, +0x8c,0x43,0x00,0x00,0x00,0xe5,0x38,0x21,0x00,0xe6,0x38,0x21,0x00,0x03,0x1c,0x02, +0x30,0x63,0x00,0xff,0x00,0xe3,0x38,0x23,0x01,0x00,0x28,0x21,0x0c,0x00,0x2a,0x2c, +0x00,0xe0,0x30,0x21,0x8e,0x02,0x01,0xa8,0x8f,0xbf,0x00,0x14,0x24,0x44,0x00,0x01, +0x28,0x83,0x00,0x00,0x24,0x42,0x00,0x40,0x00,0x83,0x10,0x0a,0x00,0x02,0x11,0x83, +0x00,0x02,0x11,0x80,0x00,0x82,0x20,0x23,0xae,0x04,0x01,0xa8,0x8f,0xb0,0x00,0x10, +0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18,0x3c,0x02,0xb0,0x03,0x3c,0x03,0x80,0x01, +0x27,0xbd,0xff,0xe8,0x34,0x42,0x00,0x20,0x24,0x63,0xaa,0x58,0xaf,0xb0,0x00,0x10, +0xaf,0xbf,0x00,0x14,0xac,0x43,0x00,0x00,0x90,0x82,0x01,0xd4,0x00,0x00,0x00,0x00, +0x14,0x40,0x00,0x6a,0x00,0x80,0x80,0x21,0x90,0x82,0x01,0xc0,0x00,0x00,0x00,0x00, +0x14,0x40,0x00,0x61,0x00,0x00,0x00,0x00,0x8c,0x83,0x01,0xa8,0x8c,0x82,0x01,0xac, +0x00,0x00,0x00,0x00,0x10,0x62,0x00,0x22,0x00,0x00,0x28,0x21,0x93,0x82,0x81,0xf1, +0x00,0x03,0x30,0x80,0x00,0xc4,0x18,0x21,0x24,0x04,0x00,0x01,0x8c,0x67,0x00,0xa8, +0x10,0x44,0x00,0x20,0x3c,0x04,0xb0,0x01,0xaf,0x87,0xbc,0x10,0x00,0xe4,0x20,0x21, +0x8c,0x86,0x00,0x00,0x00,0x07,0x18,0xc2,0x3c,0x02,0x00,0x80,0xaf,0x86,0xbc,0x18, +0x8c,0x86,0x00,0x04,0x00,0x03,0x1a,0x00,0x3c,0x05,0xb0,0x06,0x00,0x62,0x18,0x25, +0x34,0xa5,0x80,0x18,0xac,0xa3,0x00,0x00,0x8e,0x02,0x01,0xa8,0x8e,0x09,0x01,0xac, +0xaf,0x86,0xbc,0x14,0x24,0x44,0x00,0x01,0x28,0x83,0x00,0x00,0x24,0x42,0x00,0x40, +0x00,0x83,0x10,0x0a,0x00,0x02,0x11,0x83,0x00,0x02,0x11,0x80,0x00,0x82,0x20,0x23, +0x00,0x80,0x30,0x21,0xae,0x04,0x01,0xa8,0x00,0xc9,0x10,0x26,0x00,0x02,0x28,0x2b, +0x8f,0xbf,0x00,0x14,0x8f,0xb0,0x00,0x10,0x00,0xa0,0x10,0x21,0x03,0xe0,0x00,0x08, +0x27,0xbd,0x00,0x18,0x93,0x82,0x81,0xf0,0x00,0x00,0x00,0x00,0x2c,0x42,0x00,0x02, +0x14,0x40,0xff,0xf7,0x00,0x00,0x28,0x21,0x3c,0x05,0xb0,0x01,0x00,0xe5,0x28,0x21, +0x27,0x83,0x89,0x58,0x00,0xc3,0x18,0x21,0x8c,0xa6,0x00,0x00,0x8c,0x64,0x00,0x00, +0x24,0x02,0xc0,0x00,0x00,0xc2,0x10,0x24,0x00,0x44,0x10,0x25,0xac,0xa2,0x00,0x00, +0x8e,0x03,0x01,0xa8,0x27,0x84,0x8a,0x58,0x8c,0xa6,0x00,0x04,0x00,0x03,0x18,0x80, +0x00,0x64,0x18,0x21,0x8c,0x62,0x00,0x00,0x3c,0x03,0x80,0x00,0x00,0x07,0x20,0xc2, +0x00,0xc2,0x10,0x25,0x00,0x43,0x10,0x25,0xac,0xa2,0x00,0x04,0xaf,0x87,0xbc,0x10, +0x8c,0xa6,0x00,0x00,0x3c,0x02,0x00,0x80,0x00,0x04,0x22,0x00,0x3c,0x03,0xb0,0x06, +0xaf,0x86,0xbc,0x18,0x00,0x82,0x20,0x25,0x34,0x63,0x80,0x18,0x8c,0xa6,0x00,0x04, +0xac,0x64,0x00,0x00,0x8e,0x02,0x01,0xa8,0xaf,0x86,0xbc,0x14,0x24,0x44,0x00,0x01, +0x28,0x83,0x00,0x00,0x24,0x42,0x00,0x40,0x00,0x83,0x10,0x0a,0x93,0x83,0x81,0xf0, +0x00,0x02,0x11,0x83,0x00,0x02,0x11,0x80,0x00,0x82,0x20,0x23,0x24,0x63,0xff,0xff, +0xae,0x04,0x01,0xa8,0xa3,0x83,0x81,0xf0,0x8e,0x04,0x01,0xac,0x8e,0x02,0x01,0xa8, +0x08,0x00,0x2a,0xcb,0x00,0x44,0x10,0x26,0x0c,0x00,0x2a,0x4c,0x00,0x00,0x00,0x00, +0x7a,0x02,0x0d,0x7c,0x08,0x00,0x2a,0xcb,0x00,0x43,0x10,0x26,0x8c,0x86,0x01,0xa8, +0x8c,0x89,0x01,0xac,0x00,0x00,0x00,0x00,0x10,0xc9,0x00,0xb4,0x00,0xc0,0x68,0x21, +0x00,0x06,0x10,0x80,0x27,0x83,0x89,0x58,0x00,0x43,0x18,0x21,0x00,0x44,0x10,0x21, +0x8c,0x47,0x00,0xa8,0x94,0x65,0x00,0x02,0x3c,0x02,0xb0,0x01,0x00,0xe2,0x10,0x21, +0x30,0xa5,0x3f,0xff,0xa4,0x45,0x00,0x2c,0x90,0x8a,0x01,0xc0,0x00,0x00,0x00,0x00, +0x11,0x40,0x00,0x0c,0x00,0x07,0x32,0x02,0x8c,0x83,0x01,0xc4,0x90,0x85,0x01,0xc1, +0x00,0x03,0x18,0x80,0x00,0x64,0x18,0x21,0x8c,0x62,0x00,0xa8,0x00,0x00,0x00,0x00, +0x00,0x02,0x12,0x02,0x00,0x45,0x10,0x21,0x30,0x42,0x00,0x3f,0x14,0xc2,0xff,0xde, +0x00,0x00,0x00,0x00,0x3c,0x04,0xb0,0x01,0x00,0xe4,0x40,0x21,0x8d,0x06,0x00,0x00, +0x00,0x0d,0x28,0x80,0x00,0x06,0x14,0x02,0x30,0x4b,0x00,0xff,0x00,0xeb,0x70,0x21, +0x01,0xc4,0x20,0x21,0x90,0x83,0x00,0x00,0x27,0x82,0x89,0x58,0x00,0xa2,0x28,0x21, +0x8c,0xa4,0x00,0x00,0x00,0x03,0x18,0x82,0x30,0x63,0x00,0x03,0x2c,0x62,0x00,0x02, +0x14,0x40,0x00,0x66,0x30,0x8c,0x3f,0xff,0x24,0x02,0x00,0x02,0x10,0x62,0x00,0x61, +0x2d,0x82,0x08,0x00,0x15,0x40,0x00,0x36,0x01,0x6c,0x10,0x21,0x01,0x6c,0x18,0x21, +0x30,0x62,0x00,0xff,0x00,0x02,0x10,0x2b,0x00,0x03,0x1a,0x02,0x3c,0x04,0xb0,0x01, +0x00,0x62,0x18,0x21,0x00,0xe4,0x20,0x21,0x24,0x02,0x00,0x01,0xa2,0x03,0x01,0xc1, +0xa0,0x82,0x00,0x08,0x8e,0x06,0x01,0xa8,0x3c,0x03,0xb0,0x00,0x34,0x63,0xff,0xf4, +0x24,0xc5,0x00,0x01,0x28,0xa4,0x00,0x00,0x24,0xc2,0x00,0x40,0x00,0xa4,0x10,0x0a, +0x01,0xc3,0x18,0x21,0xa4,0x6c,0x00,0x00,0x00,0x02,0x11,0x83,0x00,0x02,0x11,0x80, +0x92,0x04,0x01,0xc0,0x00,0xa2,0x38,0x23,0x3c,0x03,0xb0,0x03,0xae,0x0b,0x01,0xcc, +0xae,0x0c,0x01,0xc8,0xae,0x06,0x01,0xc4,0xae,0x07,0x01,0xa8,0x34,0x63,0x01,0x08, +0x92,0x05,0x01,0xd6,0x8c,0x66,0x00,0x00,0x24,0x84,0x00,0x01,0x30,0x82,0x00,0xff, +0x00,0x45,0x10,0x2b,0xae,0x06,0x01,0xd0,0x10,0x40,0x00,0x07,0xa2,0x04,0x01,0xc0, +0x92,0x02,0x01,0xd5,0x92,0x03,0x01,0xc1,0x24,0x42,0xff,0xfc,0x00,0x62,0x18,0x2a, +0x14,0x60,0x00,0x08,0x00,0x00,0x00,0x00,0x02,0x00,0x20,0x21,0x0c,0x00,0x2a,0x4c, +0x00,0x00,0x00,0x00,0x8e,0x09,0x01,0xac,0x8e,0x06,0x01,0xa8,0x08,0x00,0x2a,0xcb, +0x00,0xc9,0x10,0x26,0x8e,0x09,0x01,0xac,0x08,0x00,0x2a,0xca,0x00,0xe0,0x30,0x21, +0x30,0x43,0x00,0xff,0x92,0x07,0x01,0xc1,0x00,0x02,0x12,0x02,0x30,0x44,0x00,0xff, +0x38,0x63,0x00,0x00,0x24,0x46,0x00,0x01,0x92,0x05,0x01,0xd5,0x00,0x83,0x30,0x0a, +0x00,0xc7,0x18,0x21,0x00,0xa3,0x10,0x2a,0x14,0x40,0xff,0xeb,0x00,0x00,0x00,0x00, +0x24,0xa2,0xff,0xfc,0x00,0x62,0x10,0x2a,0x10,0x40,0x00,0x07,0x01,0x80,0x28,0x21, +0x92,0x03,0x01,0xd6,0x25,0x42,0x00,0x01,0x00,0x43,0x10,0x2a,0x14,0x40,0x00,0x07, +0x25,0xa4,0x00,0x01,0x01,0x80,0x28,0x21,0x01,0x60,0x30,0x21,0x0c,0x00,0x2a,0x74, +0x02,0x00,0x20,0x21,0x08,0x00,0x2b,0x6d,0x00,0x00,0x00,0x00,0x28,0x83,0x00,0x00, +0x25,0xa2,0x00,0x40,0x00,0x83,0x10,0x0a,0x00,0x02,0x11,0x83,0x00,0x02,0x11,0x80, +0x00,0x82,0x20,0x23,0x00,0xc7,0x18,0x21,0x25,0x42,0x00,0x01,0x00,0x80,0x30,0x21, +0xa2,0x03,0x01,0xc1,0xae,0x0b,0x01,0xcc,0xae,0x0c,0x01,0xc8,0x08,0x00,0x2a,0xc9, +0xa2,0x02,0x01,0xc0,0x14,0x40,0xff,0x9f,0x00,0x00,0x00,0x00,0x15,0x40,0x00,0x14, +0x24,0x02,0xc0,0x00,0x00,0xc2,0x10,0x24,0x00,0x4c,0x10,0x25,0xad,0x02,0x00,0x00, +0xaf,0x87,0xbc,0x10,0x8d,0x05,0x00,0x00,0x00,0x07,0x18,0xc2,0x3c,0x02,0x00,0x80, +0x00,0x03,0x1a,0x00,0x3c,0x04,0xb0,0x06,0xaf,0x85,0xbc,0x18,0x00,0x62,0x18,0x25, +0x34,0x84,0x80,0x18,0x8d,0x05,0x00,0x04,0xac,0x83,0x00,0x00,0x8e,0x02,0x01,0xa8, +0x8e,0x09,0x01,0xac,0xaf,0x85,0xbc,0x14,0x08,0x00,0x2a,0xc2,0x24,0x44,0x00,0x01, +0x01,0x6c,0x10,0x21,0x30,0x45,0x00,0xff,0x92,0x04,0x01,0xc1,0x00,0x02,0x12,0x02, +0x30,0x46,0x00,0xff,0x38,0xa5,0x00,0x00,0x24,0x42,0x00,0x01,0x92,0x03,0x01,0xd5, +0x00,0xc5,0x10,0x0a,0x00,0x82,0x20,0x21,0x00,0x64,0x18,0x2a,0x10,0x60,0xff,0xca, +0x01,0x80,0x28,0x21,0x08,0x00,0x2b,0x6b,0x02,0x00,0x20,0x21,0x90,0x87,0x01,0xc0, +0x00,0x00,0x00,0x00,0x10,0xe0,0xff,0x06,0x00,0x00,0x28,0x21,0x3c,0x02,0xb0,0x03, +0x34,0x42,0x01,0x08,0x94,0x83,0x01,0xd8,0x8c,0x88,0x01,0xd0,0x8c,0x45,0x00,0x00, +0x01,0x03,0x18,0x21,0x00,0xa3,0x10,0x2b,0x10,0x40,0x00,0x0b,0x2c,0xe2,0x00,0x02, +0x00,0xa8,0x10,0x2b,0x10,0x40,0xfe,0xf9,0x00,0xc9,0x10,0x26,0x3c,0x02,0x80,0x00, +0x00,0x62,0x18,0x21,0x00,0xa2,0x10,0x21,0x00,0x43,0x10,0x2b,0x14,0x40,0xfe,0xf3, +0x00,0xc9,0x10,0x26,0x2c,0xe2,0x00,0x02,0x10,0x40,0xff,0x90,0x00,0x00,0x00,0x00, +0x24,0x02,0x00,0x01,0x14,0xe2,0xfe,0xed,0x00,0xc9,0x10,0x26,0x3c,0x03,0xb0,0x06, +0x34,0x63,0x80,0x18,0x8c,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x17,0x02, +0x14,0x40,0xfe,0xe5,0x00,0x00,0x00,0x00,0x08,0x00,0x2b,0x6b,0x00,0x00,0x00,0x00, +0x3c,0x04,0xb0,0x03,0x3c,0x06,0xb0,0x07,0x3c,0x02,0x80,0x01,0x34,0xc6,0x00,0x18, +0x34,0x84,0x00,0x20,0x24,0x42,0xaf,0xa0,0x24,0x03,0xff,0x83,0xac,0x82,0x00,0x00, +0xa0,0xc3,0x00,0x00,0x90,0xc4,0x00,0x00,0x27,0xbd,0xff,0xf8,0x3c,0x03,0xb0,0x07, +0x24,0x02,0xff,0x82,0xa3,0xa4,0x00,0x00,0xa0,0x62,0x00,0x00,0x90,0x64,0x00,0x00, +0x3c,0x02,0xb0,0x07,0x34,0x42,0x00,0x08,0xa3,0xa4,0x00,0x01,0xa0,0x40,0x00,0x00, +0x90,0x43,0x00,0x00,0x24,0x02,0x00,0x03,0x3c,0x05,0xb0,0x07,0xa3,0xa3,0x00,0x00, +0xa0,0xc2,0x00,0x00,0x90,0xc4,0x00,0x00,0x34,0xa5,0x00,0x10,0x24,0x02,0x00,0x06, +0x3c,0x03,0xb0,0x07,0xa3,0xa4,0x00,0x00,0x34,0x63,0x00,0x38,0xa0,0xa2,0x00,0x00, +0x90,0x64,0x00,0x00,0x3c,0x02,0xb0,0x07,0x34,0x42,0x00,0x20,0xa3,0xa4,0x00,0x00, +0xa0,0xa0,0x00,0x00,0x90,0xa3,0x00,0x00,0xaf,0x82,0xbf,0x20,0xa3,0xa3,0x00,0x00, +0xa0,0x40,0x00,0x00,0x90,0x43,0x00,0x00,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x08, +}; + +u8 rtl8190_fwdata_array[] ={ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x10,0x00,0x08,0x00, +0x02,0xe9,0x01,0x74,0x02,0xab,0x01,0xc7,0x01,0x55,0x00,0xe4,0x00,0xab,0x00,0x72, +0x00,0x55,0x00,0x4c,0x00,0x4c,0x00,0x4c,0x00,0x4c,0x00,0x4c,0x02,0x76,0x01,0x3b, +0x00,0xd2,0x00,0x9e,0x00,0x69,0x00,0x4f,0x00,0x46,0x00,0x3f,0x01,0x3b,0x00,0x9e, +0x00,0x69,0x00,0x4f,0x00,0x35,0x00,0x27,0x00,0x23,0x00,0x20,0x01,0x2f,0x00,0x98, +0x00,0x65,0x00,0x4c,0x00,0x33,0x00,0x26,0x00,0x22,0x00,0x1e,0x00,0x98,0x00,0x4c, +0x00,0x33,0x00,0x26,0x00,0x19,0x00,0x13,0x00,0x11,0x00,0x0f,0x02,0x39,0x01,0x1c, +0x00,0xbd,0x00,0x8e,0x00,0x5f,0x00,0x47,0x00,0x3f,0x00,0x39,0x01,0x1c,0x00,0x8e, +0x00,0x5f,0x00,0x47,0x00,0x2f,0x00,0x23,0x00,0x20,0x00,0x1c,0x01,0x11,0x00,0x89, +0x00,0x5b,0x00,0x44,0x00,0x2e,0x00,0x22,0x00,0x1e,0x00,0x1b,0x00,0x89,0x00,0x44, +0x00,0x2e,0x00,0x22,0x00,0x17,0x00,0x11,0x00,0x0f,0x00,0x0e,0x02,0xab,0x02,0xab, +0x02,0x66,0x02,0x66,0x07,0x06,0x06,0x06,0x05,0x06,0x07,0x08,0x04,0x06,0x07,0x08, +0x09,0x0a,0x0b,0x0b,0x49,0x6e,0x74,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x54,0x4c, +0x42,0x4d,0x4f,0x44,0x00,0x00,0x00,0x00,0x54,0x4c,0x42,0x4c,0x5f,0x64,0x61,0x74, +0x61,0x00,0x54,0x4c,0x42,0x53,0x00,0x00,0x00,0x00,0x00,0x00,0x41,0x64,0x45,0x4c, +0x5f,0x64,0x61,0x74,0x61,0x00,0x41,0x64,0x45,0x53,0x00,0x00,0x00,0x00,0x00,0x00, +0x45,0x78,0x63,0x43,0x6f,0x64,0x65,0x36,0x00,0x00,0x45,0x78,0x63,0x43,0x6f,0x64, +0x65,0x37,0x00,0x00,0x53,0x79,0x73,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x42,0x70, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x52,0x49,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x43,0x70,0x55,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4f,0x76,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x01,0x0b,0x53, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x2c, +0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x48,0x00,0x00,0x00,0x60, +0x00,0x00,0x00,0x90,0x00,0x00,0x00,0xc0,0x00,0x00,0x01,0x20,0x00,0x00,0x01,0x80, +0x00,0x00,0x01,0xb0,0x00,0x00,0x00,0x34,0x00,0x00,0x00,0x68,0x00,0x00,0x00,0x9c, +0x00,0x00,0x00,0xd0,0x00,0x00,0x01,0x38,0x00,0x00,0x01,0xa0,0x00,0x00,0x01,0xd4, +0x00,0x00,0x02,0x08,0x00,0x00,0x00,0x68,0x00,0x00,0x00,0xd0,0x00,0x00,0x01,0x38, +0x00,0x00,0x01,0xa0,0x00,0x00,0x02,0x6f,0x00,0x00,0x03,0x40,0x00,0x00,0x03,0xa8, +0x00,0x00,0x04,0x10,0x01,0x01,0x01,0x02,0x01,0x01,0x02,0x02,0x03,0x03,0x04,0x04, +0x01,0x01,0x02,0x02,0x03,0x03,0x04,0x04,0x02,0x03,0x03,0x04,0x05,0x06,0x07,0x08, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x07,0x74,0x80,0x00,0x07,0x88, +0x80,0x00,0x07,0x88,0x80,0x00,0x07,0x78,0x80,0x00,0x07,0x78,0x80,0x00,0x07,0x9c, +0x80,0x00,0x53,0xc4,0x80,0x00,0x54,0x24,0x80,0x00,0x54,0x38,0x80,0x00,0x54,0x5c, +0x80,0x00,0x54,0x68,0x80,0x00,0x54,0xa8,0x80,0x00,0x56,0xa8,0x80,0x00,0x57,0xec, +0x80,0x00,0x58,0x14,0x80,0x00,0x59,0x0c,0x80,0x00,0x59,0xc4,0x80,0x00,0x5a,0x6c, +0x80,0x00,0x5a,0xe0,0x80,0x00,0x5b,0xec,0x80,0x00,0x5c,0x24,0x80,0x00,0x5c,0x38, +0x80,0x00,0x5c,0x4c,0x80,0x00,0x5d,0x40,0x80,0x00,0x5d,0x80,0x80,0x00,0x5e,0x34, +0x80,0x00,0x5e,0x5c,0x80,0x00,0x56,0x68,0x80,0x00,0x5e,0x78,0x80,0x00,0x88,0xf8, +0x80,0x00,0x88,0xf8,0x80,0x00,0x88,0xf8,0x80,0x00,0x89,0x2c,0x80,0x00,0x89,0x6c, +0x80,0x00,0x89,0xa4,0x80,0x00,0x89,0xd4,0x80,0x00,0x8a,0x10,0x80,0x00,0x8a,0x50, +0x80,0x00,0x8a,0xb8,0x80,0x00,0x8a,0xcc,0x80,0x00,0x8b,0x08,0x80,0x00,0x8b,0x10, +0x80,0x00,0x8b,0x4c,0x80,0x00,0x8b,0x60,0x80,0x00,0x8b,0x68,0x80,0x00,0x8b,0x70, +0x80,0x00,0x8b,0x70,0x80,0x00,0x8b,0x70,0x80,0x00,0x8b,0x70,0x80,0x00,0x8a,0x90, +0x80,0x00,0x8b,0xa0,0x80,0x00,0x8b,0xb4,0x80,0x00,0x88,0x54,0x80,0x00,0x8e,0xc8, +0x80,0x00,0x8e,0xc8,0x80,0x00,0x8e,0xc8,0x80,0x00,0x8e,0xfc,0x80,0x00,0x8f,0x3c, +0x80,0x00,0x8f,0x74,0x80,0x00,0x8f,0xa4,0x80,0x00,0x8f,0xe0,0x80,0x00,0x90,0x20, +0x80,0x00,0x90,0x88,0x80,0x00,0x90,0x9c,0x80,0x00,0x90,0xd8,0x80,0x00,0x90,0xe0, +0x80,0x00,0x91,0x1c,0x80,0x00,0x91,0x30,0x80,0x00,0x91,0x38,0x80,0x00,0x91,0x40, +0x80,0x00,0x91,0x40,0x80,0x00,0x91,0x40,0x80,0x00,0x91,0x40,0x80,0x00,0x90,0x60, +0x80,0x00,0x91,0x70,0x80,0x00,0x91,0x84,0x80,0x00,0x8d,0x00,}; + +u32 Rtl8192UsbPHY_REGArray[] = { +0x0, }; + +u32 Rtl8192UsbPHY_REG_1T2RArray[] = { +0x800,0x00000000, +0x804,0x00000001, +0x808,0x0000fc00, +0x80c,0x0000001c, +0x810,0x801010aa, +0x814,0x008514d0, +0x818,0x00000040, +0x81c,0x00000000, +0x820,0x00000004, +0x824,0x00690000, +0x828,0x00000004, +0x82c,0x00e90000, +0x830,0x00000004, +0x834,0x00690000, +0x838,0x00000004, +0x83c,0x00e90000, +0x840,0x00000000, +0x844,0x00000000, +0x848,0x00000000, +0x84c,0x00000000, +0x850,0x00000000, +0x854,0x00000000, +0x858,0x65a965a9, +0x85c,0x65a965a9, +0x860,0x001f0010, +0x864,0x007f0010, +0x868,0x001f0010, +0x86c,0x007f0010, +0x870,0x0f100f70, +0x874,0x0f100f70, +0x878,0x00000000, +0x87c,0x00000000, +0x880,0x6870e36c, +0x884,0xe3573600, +0x888,0x4260c340, +0x88c,0x0000ff00, +0x890,0x00000000, +0x894,0xfffffffe, +0x898,0x4c42382f, +0x89c,0x00656056, +0x8b0,0x00000000, +0x8e0,0x00000000, +0x8e4,0x00000000, +0x900,0x00000000, +0x904,0x00000023, +0x908,0x00000000, +0x90c,0x31121311, +0xa00,0x00d0c7d8, +0xa04,0x811f0008, +0xa08,0x80cd8300, +0xa0c,0x2e62740f, +0xa10,0x95009b78, +0xa14,0x11145008, +0xa18,0x00881117, +0xa1c,0x89140fa0, +0xa20,0x1a1b0000, +0xa24,0x090e1317, +0xa28,0x00000204, +0xa2c,0x00000000, +0xc00,0x00000040, +0xc04,0x00005433, +0xc08,0x000000e4, +0xc0c,0x6c6c6c6c, +0xc10,0x08800000, +0xc14,0x40000100, +0xc18,0x08000000, +0xc1c,0x40000100, +0xc20,0x08000000, +0xc24,0x40000100, +0xc28,0x08000000, +0xc2c,0x40000100, +0xc30,0x6de9ac44, +0xc34,0x465c52cd, +0xc38,0x497f5994, +0xc3c,0x0a969764, +0xc40,0x1f7c403f, +0xc44,0x000100b7, +0xc48,0xec020000, +0xc4c,0x00000300, +0xc50,0x69543420, +0xc54,0x433c0094, +0xc58,0x69543420, +0xc5c,0x433c0094, +0xc60,0x69543420, +0xc64,0x433c0094, +0xc68,0x69543420, +0xc6c,0x433c0094, +0xc70,0x2c7f000d, +0xc74,0x0186175b, +0xc78,0x0000001f, +0xc7c,0x00b91612, +0xc80,0x40000100, +0xc84,0x20000000, +0xc88,0x40000100, +0xc8c,0x20200000, +0xc90,0x40000100, +0xc94,0x00000000, +0xc98,0x40000100, +0xc9c,0x00000000, +0xca0,0x00492492, +0xca4,0x00000000, +0xca8,0x00000000, +0xcac,0x00000000, +0xcb0,0x00000000, +0xcb4,0x00000000, +0xcb8,0x00000000, +0xcbc,0x00492492, +0xcc0,0x00000000, +0xcc4,0x00000000, +0xcc8,0x00000000, +0xccc,0x00000000, +0xcd0,0x00000000, +0xcd4,0x00000000, +0xcd8,0x64b22427, +0xcdc,0x00766932, +0xce0,0x00222222, +0xd00,0x00000750, +0xd04,0x00000403, +0xd08,0x0000907f, +0xd0c,0x00000001, +0xd10,0xa0633333, +0xd14,0x33333c63, +0xd18,0x6a8f5b6b, +0xd1c,0x00000000, +0xd20,0x00000000, +0xd24,0x00000000, +0xd28,0x00000000, +0xd2c,0xcc979975, +0xd30,0x00000000, +0xd34,0x00000000, +0xd38,0x00000000, +0xd3c,0x00027293, +0xd40,0x00000000, +0xd44,0x00000000, +0xd48,0x00000000, +0xd4c,0x00000000, +0xd50,0x6437140a, +0xd54,0x024dbd02, +0xd58,0x00000000, +0xd5c,0x04032064, +0xe00,0x161a1a1a, +0xe04,0x12121416, +0xe08,0x00001800, +0xe0c,0x00000000, +0xe10,0x161a1a1a, +0xe14,0x12121416, +0xe18,0x161a1a1a, +0xe1c,0x12121416, +}; + +u32 Rtl8192UsbRadioA_Array[] = { +0x019,0x00000003, +0x000,0x000000bf, +0x001,0x00000ee0, +0x002,0x0000004c, +0x003,0x000007f1, +0x004,0x00000975, +0x005,0x00000c58, +0x006,0x00000ae6, +0x007,0x000000ca, +0x008,0x00000e1c, +0x009,0x000007f0, +0x00a,0x000009d0, +0x00b,0x000001ba, +0x00c,0x00000240, +0x00e,0x00000020, +0x00f,0x00000990, +0x012,0x00000806, +0x014,0x000005ab, +0x015,0x00000f80, +0x016,0x00000020, +0x017,0x00000597, +0x018,0x0000050a, +0x01a,0x00000f80, +0x01b,0x00000f5e, +0x01c,0x00000008, +0x01d,0x00000607, +0x01e,0x000006cc, +0x01f,0x00000000, +0x020,0x000001a5, +0x01f,0x00000001, +0x020,0x00000165, +0x01f,0x00000002, +0x020,0x000000c6, +0x01f,0x00000003, +0x020,0x00000086, +0x01f,0x00000004, +0x020,0x00000046, +0x01f,0x00000005, +0x020,0x000001e6, +0x01f,0x00000006, +0x020,0x000001a6, +0x01f,0x00000007, +0x020,0x00000166, +0x01f,0x00000008, +0x020,0x000000c7, +0x01f,0x00000009, +0x020,0x00000087, +0x01f,0x0000000a, +0x020,0x000000f7, +0x01f,0x0000000b, +0x020,0x000000d7, +0x01f,0x0000000c, +0x020,0x000000b7, +0x01f,0x0000000d, +0x020,0x00000097, +0x01f,0x0000000e, +0x020,0x00000077, +0x01f,0x0000000f, +0x020,0x00000057, +0x01f,0x00000010, +0x020,0x00000037, +0x01f,0x00000011, +0x020,0x000000fb, +0x01f,0x00000012, +0x020,0x000000db, +0x01f,0x00000013, +0x020,0x000000bb, +0x01f,0x00000014, +0x020,0x000000ff, +0x01f,0x00000015, +0x020,0x000000e3, +0x01f,0x00000016, +0x020,0x000000c3, +0x01f,0x00000017, +0x020,0x000000a3, +0x01f,0x00000018, +0x020,0x00000083, +0x01f,0x00000019, +0x020,0x00000063, +0x01f,0x0000001a, +0x020,0x00000043, +0x01f,0x0000001b, +0x020,0x00000023, +0x01f,0x0000001c, +0x020,0x00000003, +0x01f,0x0000001d, +0x020,0x000001e3, +0x01f,0x0000001e, +0x020,0x000001c3, +0x01f,0x0000001f, +0x020,0x000001a3, +0x01f,0x00000020, +0x020,0x00000183, +0x01f,0x00000021, +0x020,0x00000163, +0x01f,0x00000022, +0x020,0x00000143, +0x01f,0x00000023, +0x020,0x00000123, +0x01f,0x00000024, +0x020,0x00000103, +0x023,0x00000203, +0x024,0x00000200, +0x00b,0x000001ba, +0x02c,0x000003d7, +0x02d,0x00000ff0, +0x000,0x00000037, +0x004,0x00000160, +0x007,0x00000080, +0x002,0x0000088d, +0x0fe,0x00000000, +0x0fe,0x00000000, +0x016,0x00000200, +0x016,0x00000380, +0x016,0x00000020, +0x016,0x000001a0, +0x000,0x000000bf, +0x00d,0x0000001f, +0x00d,0x00000c9f, +0x002,0x0000004d, +0x000,0x00000cbf, +0x004,0x00000975, +0x007,0x00000700, +}; + +u32 Rtl8192UsbRadioB_Array[] = { +0x019,0x00000003, +0x000,0x000000bf, +0x001,0x000006e0, +0x002,0x0000004c, +0x003,0x000007f1, +0x004,0x00000975, +0x005,0x00000c58, +0x006,0x00000ae6, +0x007,0x000000ca, +0x008,0x00000e1c, +0x000,0x000000b7, +0x00a,0x00000850, +0x000,0x000000bf, +0x00b,0x000001ba, +0x00c,0x00000240, +0x00e,0x00000020, +0x015,0x00000f80, +0x016,0x00000020, +0x017,0x00000597, +0x018,0x0000050a, +0x01a,0x00000e00, +0x01b,0x00000f5e, +0x01d,0x00000607, +0x01e,0x000006cc, +0x00b,0x000001ba, +0x023,0x00000203, +0x024,0x00000200, +0x000,0x00000037, +0x004,0x00000160, +0x016,0x00000200, +0x016,0x00000380, +0x016,0x00000020, +0x016,0x000001a0, +0x00d,0x00000ccc, +0x000,0x000000bf, +0x002,0x0000004d, +0x000,0x00000cbf, +0x004,0x00000975, +0x007,0x00000700, +}; + +u32 Rtl8192UsbRadioC_Array[] = { +0x0, }; + +u32 Rtl8192UsbRadioD_Array[] = { +0x0, }; + +u32 Rtl8192UsbMACPHY_Array[] = { +0x03c,0xffff0000,0x00000f0f, +0x340,0xffffffff,0x161a1a1a, +0x344,0xffffffff,0x12121416, +0x348,0x0000ffff,0x00001818, +0x12c,0xffffffff,0x04000802, +0x318,0x00000fff,0x00000100, +}; + +u32 Rtl8192UsbMACPHY_Array_PG[] = { +0x03c,0xffff0000,0x00000f0f, +0xe00,0xffffffff,0x06090909, +0xe04,0xffffffff,0x00030306, +0xe08,0x0000ff00,0x00000000, +0xe10,0xffffffff,0x0a0c0d0f, +0xe14,0xffffffff,0x06070809, +0xe18,0xffffffff,0x0a0c0d0f, +0xe1c,0xffffffff,0x06070809, +0x12c,0xffffffff,0x04000802, +0x318,0x00000fff,0x00000800, +}; + +u32 Rtl8192UsbAGCTAB_Array[] = { +0xc78,0x7d000001, +0xc78,0x7d010001, +0xc78,0x7d020001, +0xc78,0x7d030001, +0xc78,0x7d040001, +0xc78,0x7d050001, +0xc78,0x7c060001, +0xc78,0x7b070001, +0xc78,0x7a080001, +0xc78,0x79090001, +0xc78,0x780a0001, +0xc78,0x770b0001, +0xc78,0x760c0001, +0xc78,0x750d0001, +0xc78,0x740e0001, +0xc78,0x730f0001, +0xc78,0x72100001, +0xc78,0x71110001, +0xc78,0x70120001, +0xc78,0x6f130001, +0xc78,0x6e140001, +0xc78,0x6d150001, +0xc78,0x6c160001, +0xc78,0x6b170001, +0xc78,0x6a180001, +0xc78,0x69190001, +0xc78,0x681a0001, +0xc78,0x671b0001, +0xc78,0x661c0001, +0xc78,0x651d0001, +0xc78,0x641e0001, +0xc78,0x491f0001, +0xc78,0x48200001, +0xc78,0x47210001, +0xc78,0x46220001, +0xc78,0x45230001, +0xc78,0x44240001, +0xc78,0x43250001, +0xc78,0x28260001, +0xc78,0x27270001, +0xc78,0x26280001, +0xc78,0x25290001, +0xc78,0x242a0001, +0xc78,0x232b0001, +0xc78,0x222c0001, +0xc78,0x212d0001, +0xc78,0x202e0001, +0xc78,0x0a2f0001, +0xc78,0x08300001, +0xc78,0x06310001, +0xc78,0x05320001, +0xc78,0x04330001, +0xc78,0x03340001, +0xc78,0x02350001, +0xc78,0x01360001, +0xc78,0x00370001, +0xc78,0x00380001, +0xc78,0x00390001, +0xc78,0x003a0001, +0xc78,0x003b0001, +0xc78,0x003c0001, +0xc78,0x003d0001, +0xc78,0x003e0001, +0xc78,0x003f0001, +0xc78,0x7d400001, +0xc78,0x7d410001, +0xc78,0x7d420001, +0xc78,0x7d430001, +0xc78,0x7d440001, +0xc78,0x7d450001, +0xc78,0x7c460001, +0xc78,0x7b470001, +0xc78,0x7a480001, +0xc78,0x79490001, +0xc78,0x784a0001, +0xc78,0x774b0001, +0xc78,0x764c0001, +0xc78,0x754d0001, +0xc78,0x744e0001, +0xc78,0x734f0001, +0xc78,0x72500001, +0xc78,0x71510001, +0xc78,0x70520001, +0xc78,0x6f530001, +0xc78,0x6e540001, +0xc78,0x6d550001, +0xc78,0x6c560001, +0xc78,0x6b570001, +0xc78,0x6a580001, +0xc78,0x69590001, +0xc78,0x685a0001, +0xc78,0x675b0001, +0xc78,0x665c0001, +0xc78,0x655d0001, +0xc78,0x645e0001, +0xc78,0x495f0001, +0xc78,0x48600001, +0xc78,0x47610001, +0xc78,0x46620001, +0xc78,0x45630001, +0xc78,0x44640001, +0xc78,0x43650001, +0xc78,0x28660001, +0xc78,0x27670001, +0xc78,0x26680001, +0xc78,0x25690001, +0xc78,0x246a0001, +0xc78,0x236b0001, +0xc78,0x226c0001, +0xc78,0x216d0001, +0xc78,0x206e0001, +0xc78,0x0a6f0001, +0xc78,0x08700001, +0xc78,0x06710001, +0xc78,0x05720001, +0xc78,0x04730001, +0xc78,0x03740001, +0xc78,0x02750001, +0xc78,0x01760001, +0xc78,0x00770001, +0xc78,0x00780001, +0xc78,0x00790001, +0xc78,0x007a0001, +0xc78,0x007b0001, +0xc78,0x007c0001, +0xc78,0x007d0001, +0xc78,0x007e0001, +0xc78,0x007f0001, +0xc78,0x2e00001e, +0xc78,0x2e01001e, +0xc78,0x2e02001e, +0xc78,0x2e03001e, +0xc78,0x2e04001e, +0xc78,0x2e05001e, +0xc78,0x3006001e, +0xc78,0x3407001e, +0xc78,0x3908001e, +0xc78,0x3c09001e, +0xc78,0x3f0a001e, +0xc78,0x420b001e, +0xc78,0x440c001e, +0xc78,0x450d001e, +0xc78,0x460e001e, +0xc78,0x460f001e, +0xc78,0x4710001e, +0xc78,0x4811001e, +0xc78,0x4912001e, +0xc78,0x4a13001e, +0xc78,0x4b14001e, +0xc78,0x4b15001e, +0xc78,0x4c16001e, +0xc78,0x4d17001e, +0xc78,0x4e18001e, +0xc78,0x4f19001e, +0xc78,0x4f1a001e, +0xc78,0x501b001e, +0xc78,0x511c001e, +0xc78,0x521d001e, +0xc78,0x521e001e, +0xc78,0x531f001e, +0xc78,0x5320001e, +0xc78,0x5421001e, +0xc78,0x5522001e, +0xc78,0x5523001e, +0xc78,0x5624001e, +0xc78,0x5725001e, +0xc78,0x5726001e, +0xc78,0x5827001e, +0xc78,0x5828001e, +0xc78,0x5929001e, +0xc78,0x592a001e, +0xc78,0x5a2b001e, +0xc78,0x5b2c001e, +0xc78,0x5c2d001e, +0xc78,0x5c2e001e, +0xc78,0x5d2f001e, +0xc78,0x5e30001e, +0xc78,0x5f31001e, +0xc78,0x6032001e, +0xc78,0x6033001e, +0xc78,0x6134001e, +0xc78,0x6235001e, +0xc78,0x6336001e, +0xc78,0x6437001e, +0xc78,0x6438001e, +0xc78,0x6539001e, +0xc78,0x663a001e, +0xc78,0x673b001e, +0xc78,0x673c001e, +0xc78,0x683d001e, +0xc78,0x693e001e, +0xc78,0x6a3f001e, +}; diff --git a/drivers/staging/rtl8192su/r819xU_firmware_img.h b/drivers/staging/rtl8192su/r819xU_firmware_img.h new file mode 100644 index 000000000000..d9d9515a1e61 --- /dev/null +++ b/drivers/staging/rtl8192su/r819xU_firmware_img.h @@ -0,0 +1,35 @@ +#ifndef IMG_H +#define IMG_H + +#define BOOT_ARR_LEN 344 +#define MAIN_ARR_LEN 45136 +#define DATA_ARR_LEN 796 +#define MACPHY_Array_PGLength 30 +#define PHY_REG_1T2RArrayLength 296 +#define AGCTAB_ArrayLength 384 +#define MACPHY_ArrayLength 18 + +#define RadioA_ArrayLength 246 +#define RadioB_ArrayLength 78 +#define RadioC_ArrayLength 1 +#define RadioD_ArrayLength 1 +#define PHY_REGArrayLength 1 + + +extern u8 rtl8190_fwboot_array[BOOT_ARR_LEN]; +extern u8 rtl8190_fwmain_array[MAIN_ARR_LEN]; +extern u8 rtl8190_fwdata_array[DATA_ARR_LEN]; + +extern u32 Rtl8192UsbPHY_REGArray[]; +extern u32 Rtl8192UsbPHY_REG_1T2RArray[]; +extern u32 Rtl8192UsbRadioA_Array[]; +extern u32 Rtl8192UsbRadioB_Array[]; +extern u32 Rtl8192UsbRadioC_Array[]; +extern u32 Rtl8192UsbRadioD_Array[]; +extern u32 Rtl8192UsbMACPHY_Array[]; +extern u32 Rtl8192UsbMACPHY_Array_PG[]; +extern u32 Rtl8192UsbAGCTAB_Array[]; + + + +#endif diff --git a/drivers/staging/rtl8192su/r819xU_phy.c b/drivers/staging/rtl8192su/r819xU_phy.c new file mode 100644 index 000000000000..00497d313f9b --- /dev/null +++ b/drivers/staging/rtl8192su/r819xU_phy.c @@ -0,0 +1,1826 @@ +#include "r8192U.h" +#include "r8192U_hw.h" +#include "r819xU_phy.h" +#include "r819xU_phyreg.h" +#include "r8190_rtl8256.h" +#include "r8192U_dm.h" +#include "r819xU_firmware_img.h" + +#ifdef ENABLE_DOT11D +#include "dot11d.h" +#endif +static u32 RF_CHANNEL_TABLE_ZEBRA[] = { + 0, + 0x085c, //2412 1 + 0x08dc, //2417 2 + 0x095c, //2422 3 + 0x09dc, //2427 4 + 0x0a5c, //2432 5 + 0x0adc, //2437 6 + 0x0b5c, //2442 7 + 0x0bdc, //2447 8 + 0x0c5c, //2452 9 + 0x0cdc, //2457 10 + 0x0d5c, //2462 11 + 0x0ddc, //2467 12 + 0x0e5c, //2472 13 + 0x0f72, //2484 +}; + + +#define rtl819XPHY_REG_1T2RArray Rtl8192UsbPHY_REG_1T2RArray +#define rtl819XMACPHY_Array_PG Rtl8192UsbMACPHY_Array_PG +#define rtl819XMACPHY_Array Rtl8192UsbMACPHY_Array +#define rtl819XRadioA_Array Rtl8192UsbRadioA_Array +#define rtl819XRadioB_Array Rtl8192UsbRadioB_Array +#define rtl819XRadioC_Array Rtl8192UsbRadioC_Array +#define rtl819XRadioD_Array Rtl8192UsbRadioD_Array +#define rtl819XAGCTAB_Array Rtl8192UsbAGCTAB_Array + +/****************************************************************************** + *function: This function read BB parameters from Header file we gen, + * and do register read/write + * input: u32 dwBitMask //taget bit pos in the addr to be modified + * output: none + * return: u32 return the shift bit bit position of the mask + * ****************************************************************************/ +u32 rtl8192_CalculateBitShift(u32 dwBitMask) +{ + u32 i; + for (i=0; i<=31; i++) + { + if (((dwBitMask>>i)&0x1) == 1) + break; + } + return i; +} +/****************************************************************************** + *function: This function check different RF type to execute legal judgement. If RF Path is illegal, we will return false. + * input: none + * output: none + * return: 0(illegal, false), 1(legal,true) + * ***************************************************************************/ +u8 rtl8192_phy_CheckIsLegalRFPath(struct net_device* dev, u32 eRFPath) +{ + u8 ret = 1; + struct r8192_priv *priv = ieee80211_priv(dev); + if (priv->rf_type == RF_2T4R) + ret = 0; + else if (priv->rf_type == RF_1T2R) + { + if (eRFPath == RF90_PATH_A || eRFPath == RF90_PATH_B) + ret = 1; + else if (eRFPath == RF90_PATH_C || eRFPath == RF90_PATH_D) + ret = 0; + } + return ret; +} +/****************************************************************************** + *function: This function set specific bits to BB register + * input: net_device dev + * u32 dwRegAddr //target addr to be modified + * u32 dwBitMask //taget bit pos in the addr to be modified + * u32 dwData //value to be write + * output: none + * return: none + * notice: + * ****************************************************************************/ +void rtl8192_setBBreg(struct net_device* dev, u32 dwRegAddr, u32 dwBitMask, u32 dwData) +{ + + u32 OriginalValue, BitShift, NewValue; + + if(dwBitMask!= bMaskDWord) + {//if not "double word" write + OriginalValue = read_nic_dword(dev, dwRegAddr); + BitShift = rtl8192_CalculateBitShift(dwBitMask); + NewValue = (((OriginalValue) & (~dwBitMask)) | (dwData << BitShift)); + write_nic_dword(dev, dwRegAddr, NewValue); + }else + write_nic_dword(dev, dwRegAddr, dwData); + return; +} +/****************************************************************************** + *function: This function reads specific bits from BB register + * input: net_device dev + * u32 dwRegAddr //target addr to be readback + * u32 dwBitMask //taget bit pos in the addr to be readback + * output: none + * return: u32 Data //the readback register value + * notice: + * ****************************************************************************/ +u32 rtl8192_QueryBBReg(struct net_device* dev, u32 dwRegAddr, u32 dwBitMask) +{ + u32 Ret = 0, OriginalValue, BitShift; + + OriginalValue = read_nic_dword(dev, dwRegAddr); + BitShift = rtl8192_CalculateBitShift(dwBitMask); + Ret =(OriginalValue & dwBitMask) >> BitShift; + + return (Ret); +} +static u32 phy_FwRFSerialRead( struct net_device* dev, RF90_RADIO_PATH_E eRFPath, u32 Offset ); + +static void phy_FwRFSerialWrite( struct net_device* dev, RF90_RADIO_PATH_E eRFPath, u32 Offset, u32 Data); + +/****************************************************************************** + *function: This function read register from RF chip + * input: net_device dev + * RF90_RADIO_PATH_E eRFPath //radio path of A/B/C/D + * u32 Offset //target address to be read + * output: none + * return: u32 readback value + * notice: There are three types of serial operations:(1) Software serial write.(2)Hardware LSSI-Low Speed Serial Interface.(3)Hardware HSSI-High speed serial write. Driver here need to implement (1) and (2)---need more spec for this information. + * ****************************************************************************/ +u32 rtl8192_phy_RFSerialRead(struct net_device* dev, RF90_RADIO_PATH_E eRFPath, u32 Offset) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + u32 ret = 0; + u32 NewOffset = 0; + BB_REGISTER_DEFINITION_T* pPhyReg = &priv->PHYRegDef[eRFPath]; + rtl8192_setBBreg(dev, pPhyReg->rfLSSIReadBack, bLSSIReadBackData, 0); + //make sure RF register offset is correct + Offset &= 0x3f; + + //switch page for 8256 RF IC + if (priv->rf_chip == RF_8256) + { + if (Offset >= 31) + { + priv->RfReg0Value[eRFPath] |= 0x140; + //Switch to Reg_Mode2 for Reg 31-45 + rtl8192_setBBreg(dev, pPhyReg->rf3wireOffset, bMaskDWord, (priv->RfReg0Value[eRFPath]<<16) ); + //modify offset + NewOffset = Offset -30; + } + else if (Offset >= 16) + { + priv->RfReg0Value[eRFPath] |= 0x100; + priv->RfReg0Value[eRFPath] &= (~0x40); + //Switch to Reg_Mode 1 for Reg16-30 + rtl8192_setBBreg(dev, pPhyReg->rf3wireOffset, bMaskDWord, (priv->RfReg0Value[eRFPath]<<16) ); + + NewOffset = Offset - 15; + } + else + NewOffset = Offset; + } + else + { + RT_TRACE((COMP_PHY|COMP_ERR), "check RF type here, need to be 8256\n"); + NewOffset = Offset; + } + //put desired read addr to LSSI control Register + rtl8192_setBBreg(dev, pPhyReg->rfHSSIPara2, bLSSIReadAddress, NewOffset); + //Issue a posedge trigger + // + rtl8192_setBBreg(dev, pPhyReg->rfHSSIPara2, bLSSIReadEdge, 0x0); + rtl8192_setBBreg(dev, pPhyReg->rfHSSIPara2, bLSSIReadEdge, 0x1); + + + // TODO: we should not delay such a long time. Ask help from SD3 + msleep(1); + + ret = rtl8192_QueryBBReg(dev, pPhyReg->rfLSSIReadBack, bLSSIReadBackData); + + + // Switch back to Reg_Mode0; + if(priv->rf_chip == RF_8256) + { + priv->RfReg0Value[eRFPath] &= 0xebf; + + rtl8192_setBBreg( + dev, + pPhyReg->rf3wireOffset, + bMaskDWord, + (priv->RfReg0Value[eRFPath] << 16)); + } + + return ret; + +} + +/****************************************************************************** + *function: This function write data to RF register + * input: net_device dev + * RF90_RADIO_PATH_E eRFPath //radio path of A/B/C/D + * u32 Offset //target address to be written + * u32 Data //The new register data to be written + * output: none + * return: none + * notice: For RF8256 only. + =========================================================== + *Reg Mode RegCTL[1] RegCTL[0] Note + * (Reg00[12]) (Reg00[10]) + *=========================================================== + *Reg_Mode0 0 x Reg 0 ~15(0x0 ~ 0xf) + *------------------------------------------------------------------ + *Reg_Mode1 1 0 Reg 16 ~30(0x1 ~ 0xf) + *------------------------------------------------------------------ + * Reg_Mode2 1 1 Reg 31 ~ 45(0x1 ~ 0xf) + *------------------------------------------------------------------ + * ****************************************************************************/ +void rtl8192_phy_RFSerialWrite(struct net_device* dev, RF90_RADIO_PATH_E eRFPath, u32 Offset, u32 Data) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + u32 DataAndAddr = 0, NewOffset = 0; + BB_REGISTER_DEFINITION_T *pPhyReg = &priv->PHYRegDef[eRFPath]; + + Offset &= 0x3f; + //spin_lock_irqsave(&priv->rf_lock, flags); +// down(&priv->rf_sem); + if (priv->rf_chip == RF_8256) + { + + if (Offset >= 31) + { + priv->RfReg0Value[eRFPath] |= 0x140; + rtl8192_setBBreg(dev, pPhyReg->rf3wireOffset, bMaskDWord, (priv->RfReg0Value[eRFPath] << 16)); + NewOffset = Offset - 30; + } + else if (Offset >= 16) + { + priv->RfReg0Value[eRFPath] |= 0x100; + priv->RfReg0Value[eRFPath] &= (~0x40); + rtl8192_setBBreg(dev, pPhyReg->rf3wireOffset, bMaskDWord, (priv->RfReg0Value[eRFPath]<<16)); + NewOffset = Offset - 15; + } + else + NewOffset = Offset; + } + else + { + RT_TRACE((COMP_PHY|COMP_ERR), "check RF type here, need to be 8256\n"); + NewOffset = Offset; + } + + // Put write addr in [5:0] and write data in [31:16] + DataAndAddr = (Data<<16) | (NewOffset&0x3f); + + // Write Operation + rtl8192_setBBreg(dev, pPhyReg->rf3wireOffset, bMaskDWord, DataAndAddr); + + + if(Offset==0x0) + priv->RfReg0Value[eRFPath] = Data; + + // Switch back to Reg_Mode0; + if(priv->rf_chip == RF_8256) + { + if(Offset != 0) + { + priv->RfReg0Value[eRFPath] &= 0xebf; + rtl8192_setBBreg( + dev, + pPhyReg->rf3wireOffset, + bMaskDWord, + (priv->RfReg0Value[eRFPath] << 16)); + } + } + //spin_unlock_irqrestore(&priv->rf_lock, flags); +// up(&priv->rf_sem); + return; +} + +/****************************************************************************** + *function: This function set specific bits to RF register + * input: net_device dev + * RF90_RADIO_PATH_E eRFPath //radio path of A/B/C/D + * u32 RegAddr //target addr to be modified + * u32 BitMask //taget bit pos in the addr to be modified + * u32 Data //value to be write + * output: none + * return: none + * notice: + * ****************************************************************************/ +void rtl8192_phy_SetRFReg(struct net_device* dev, RF90_RADIO_PATH_E eRFPath, u32 RegAddr, u32 BitMask, u32 Data) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + u32 Original_Value, BitShift, New_Value; +// u8 time = 0; + + if (!rtl8192_phy_CheckIsLegalRFPath(dev, eRFPath)) + return; + + if (priv->Rf_Mode == RF_OP_By_FW) + { + if (BitMask != bMask12Bits) // RF data is 12 bits only + { + Original_Value = phy_FwRFSerialRead(dev, eRFPath, RegAddr); + BitShift = rtl8192_CalculateBitShift(BitMask); + New_Value = ((Original_Value) & (~BitMask)) | (Data<< BitShift); + + phy_FwRFSerialWrite(dev, eRFPath, RegAddr, New_Value); + }else + phy_FwRFSerialWrite(dev, eRFPath, RegAddr, Data); + + udelay(200); + + } + else + { + if (BitMask != bMask12Bits) // RF data is 12 bits only + { + Original_Value = rtl8192_phy_RFSerialRead(dev, eRFPath, RegAddr); + BitShift = rtl8192_CalculateBitShift(BitMask); + New_Value = (((Original_Value) & (~BitMask)) | (Data<< BitShift)); + + rtl8192_phy_RFSerialWrite(dev, eRFPath, RegAddr, New_Value); + }else + rtl8192_phy_RFSerialWrite(dev, eRFPath, RegAddr, Data); + } + return; +} + +/****************************************************************************** + *function: This function reads specific bits from RF register + * input: net_device dev + * u32 RegAddr //target addr to be readback + * u32 BitMask //taget bit pos in the addr to be readback + * output: none + * return: u32 Data //the readback register value + * notice: + * ****************************************************************************/ +u32 rtl8192_phy_QueryRFReg(struct net_device* dev, RF90_RADIO_PATH_E eRFPath, u32 RegAddr, u32 BitMask) +{ + u32 Original_Value, Readback_Value, BitShift; + struct r8192_priv *priv = ieee80211_priv(dev); + + + if (!rtl8192_phy_CheckIsLegalRFPath(dev, eRFPath)) + return 0; + if (priv->Rf_Mode == RF_OP_By_FW) + { + Original_Value = phy_FwRFSerialRead(dev, eRFPath, RegAddr); + BitShift = rtl8192_CalculateBitShift(BitMask); + Readback_Value = (Original_Value & BitMask) >> BitShift; + udelay(200); + return (Readback_Value); + } + else + { + Original_Value = rtl8192_phy_RFSerialRead(dev, eRFPath, RegAddr); + BitShift = rtl8192_CalculateBitShift(BitMask); + Readback_Value = (Original_Value & BitMask) >> BitShift; + return (Readback_Value); + } +} +/****************************************************************************** + *function: We support firmware to execute RF-R/W. + * input: dev + * output: none + * return: none + * notice: + * ***************************************************************************/ +static u32 +phy_FwRFSerialRead( + struct net_device* dev, + RF90_RADIO_PATH_E eRFPath, + u32 Offset ) +{ + u32 retValue = 0; + u32 Data = 0; + u8 time = 0; + //DbgPrint("FW RF CTRL\n\r"); + /* 2007/11/02 MH Firmware RF Write control. By Francis' suggestion, we can + not execute the scheme in the initial step. Otherwise, RF-R/W will waste + much time. This is only for site survey. */ + // 1. Read operation need not insert data. bit 0-11 + //Data &= bMask12Bits; + // 2. Write RF register address. Bit 12-19 + Data |= ((Offset&0xFF)<<12); + // 3. Write RF path. bit 20-21 + Data |= ((eRFPath&0x3)<<20); + // 4. Set RF read indicator. bit 22=0 + //Data |= 0x00000; + // 5. Trigger Fw to operate the command. bit 31 + Data |= 0x80000000; + // 6. We can not execute read operation if bit 31 is 1. + while (read_nic_dword(dev, QPNR)&0x80000000) + { + // If FW can not finish RF-R/W for more than ?? times. We must reset FW. + if (time++ < 100) + { + //DbgPrint("FW not finish RF-R Time=%d\n\r", time); + udelay(10); + } + else + break; + } + // 7. Execute read operation. + write_nic_dword(dev, QPNR, Data); + // 8. Check if firmawre send back RF content. + while (read_nic_dword(dev, QPNR)&0x80000000) + { + // If FW can not finish RF-R/W for more than ?? times. We must reset FW. + if (time++ < 100) + { + //DbgPrint("FW not finish RF-W Time=%d\n\r", time); + udelay(10); + } + else + return (0); + } + retValue = read_nic_dword(dev, RF_DATA); + + return (retValue); + +} /* phy_FwRFSerialRead */ + +/****************************************************************************** + *function: We support firmware to execute RF-R/W. + * input: dev + * output: none + * return: none + * notice: + * ***************************************************************************/ +static void +phy_FwRFSerialWrite( + struct net_device* dev, + RF90_RADIO_PATH_E eRFPath, + u32 Offset, + u32 Data ) +{ + u8 time = 0; + + //DbgPrint("N FW RF CTRL RF-%d OF%02x DATA=%03x\n\r", eRFPath, Offset, Data); + /* 2007/11/02 MH Firmware RF Write control. By Francis' suggestion, we can + not execute the scheme in the initial step. Otherwise, RF-R/W will waste + much time. This is only for site survey. */ + + // 1. Set driver write bit and 12 bit data. bit 0-11 + //Data &= bMask12Bits; // Done by uper layer. + // 2. Write RF register address. bit 12-19 + Data |= ((Offset&0xFF)<<12); + // 3. Write RF path. bit 20-21 + Data |= ((eRFPath&0x3)<<20); + // 4. Set RF write indicator. bit 22=1 + Data |= 0x400000; + // 5. Trigger Fw to operate the command. bit 31=1 + Data |= 0x80000000; + + // 6. Write operation. We can not write if bit 31 is 1. + while (read_nic_dword(dev, QPNR)&0x80000000) + { + // If FW can not finish RF-R/W for more than ?? times. We must reset FW. + if (time++ < 100) + { + //DbgPrint("FW not finish RF-W Time=%d\n\r", time); + udelay(10); + } + else + break; + } + // 7. No matter check bit. We always force the write. Because FW will + // not accept the command. + write_nic_dword(dev, QPNR, Data); + /* 2007/11/02 MH Acoording to test, we must delay 20us to wait firmware + to finish RF write operation. */ + /* 2008/01/17 MH We support delay in firmware side now. */ + //delay_us(20); + +} /* phy_FwRFSerialWrite */ + + +/****************************************************************************** + *function: This function read BB parameters from Header file we gen, + * and do register read/write + * input: dev + * output: none + * return: none + * notice: BB parameters may change all the time, so please make + * sure it has been synced with the newest. + * ***************************************************************************/ +void rtl8192_phy_configmac(struct net_device* dev) +{ + u32 dwArrayLen = 0, i; + u32* pdwArray = NULL; + struct r8192_priv *priv = ieee80211_priv(dev); + + if(priv->btxpowerdata_readfromEEPORM) + { + RT_TRACE(COMP_PHY, "Rtl819XMACPHY_Array_PG\n"); + dwArrayLen = MACPHY_Array_PGLength; + pdwArray = rtl819XMACPHY_Array_PG; + + } + else + { + RT_TRACE(COMP_PHY, "Rtl819XMACPHY_Array\n"); + dwArrayLen = MACPHY_ArrayLength; + pdwArray = rtl819XMACPHY_Array; + } + for(i = 0; ibInHctTest) + { + PHY_REGArrayLen = PHY_REGArrayLengthDTM; + AGCTAB_ArrayLen = AGCTAB_ArrayLengthDTM; + Rtl8190PHY_REGArray_Table = Rtl819XPHY_REGArrayDTM; + Rtl8190AGCTAB_Array_Table = Rtl819XAGCTAB_ArrayDTM; + } +#endif + if (ConfigType == BaseBand_Config_PHY_REG) + { + for (i=0; iPHYRegDef[RF90_PATH_A].rfintfs = rFPGA0_XAB_RFInterfaceSW; // 16 LSBs if read 32-bit from 0x870 + priv->PHYRegDef[RF90_PATH_B].rfintfs = rFPGA0_XAB_RFInterfaceSW; // 16 MSBs if read 32-bit from 0x870 (16-bit for 0x872) + priv->PHYRegDef[RF90_PATH_C].rfintfs = rFPGA0_XCD_RFInterfaceSW;// 16 LSBs if read 32-bit from 0x874 + priv->PHYRegDef[RF90_PATH_D].rfintfs = rFPGA0_XCD_RFInterfaceSW;// 16 MSBs if read 32-bit from 0x874 (16-bit for 0x876) + + // RF Interface Readback Value + priv->PHYRegDef[RF90_PATH_A].rfintfi = rFPGA0_XAB_RFInterfaceRB; // 16 LSBs if read 32-bit from 0x8E0 + priv->PHYRegDef[RF90_PATH_B].rfintfi = rFPGA0_XAB_RFInterfaceRB;// 16 MSBs if read 32-bit from 0x8E0 (16-bit for 0x8E2) + priv->PHYRegDef[RF90_PATH_C].rfintfi = rFPGA0_XCD_RFInterfaceRB;// 16 LSBs if read 32-bit from 0x8E4 + priv->PHYRegDef[RF90_PATH_D].rfintfi = rFPGA0_XCD_RFInterfaceRB;// 16 MSBs if read 32-bit from 0x8E4 (16-bit for 0x8E6) + + // RF Interface Output (and Enable) + priv->PHYRegDef[RF90_PATH_A].rfintfo = rFPGA0_XA_RFInterfaceOE; // 16 LSBs if read 32-bit from 0x860 + priv->PHYRegDef[RF90_PATH_B].rfintfo = rFPGA0_XB_RFInterfaceOE; // 16 LSBs if read 32-bit from 0x864 + priv->PHYRegDef[RF90_PATH_C].rfintfo = rFPGA0_XC_RFInterfaceOE;// 16 LSBs if read 32-bit from 0x868 + priv->PHYRegDef[RF90_PATH_D].rfintfo = rFPGA0_XD_RFInterfaceOE;// 16 LSBs if read 32-bit from 0x86C + + // RF Interface (Output and) Enable + priv->PHYRegDef[RF90_PATH_A].rfintfe = rFPGA0_XA_RFInterfaceOE; // 16 MSBs if read 32-bit from 0x860 (16-bit for 0x862) + priv->PHYRegDef[RF90_PATH_B].rfintfe = rFPGA0_XB_RFInterfaceOE; // 16 MSBs if read 32-bit from 0x864 (16-bit for 0x866) + priv->PHYRegDef[RF90_PATH_C].rfintfe = rFPGA0_XC_RFInterfaceOE;// 16 MSBs if read 32-bit from 0x86A (16-bit for 0x86A) + priv->PHYRegDef[RF90_PATH_D].rfintfe = rFPGA0_XD_RFInterfaceOE;// 16 MSBs if read 32-bit from 0x86C (16-bit for 0x86E) + + //Addr of LSSI. Wirte RF register by driver + priv->PHYRegDef[RF90_PATH_A].rf3wireOffset = rFPGA0_XA_LSSIParameter; //LSSI Parameter + priv->PHYRegDef[RF90_PATH_B].rf3wireOffset = rFPGA0_XB_LSSIParameter; + priv->PHYRegDef[RF90_PATH_C].rf3wireOffset = rFPGA0_XC_LSSIParameter; + priv->PHYRegDef[RF90_PATH_D].rf3wireOffset = rFPGA0_XD_LSSIParameter; + + // RF parameter + priv->PHYRegDef[RF90_PATH_A].rfLSSI_Select = rFPGA0_XAB_RFParameter; //BB Band Select + priv->PHYRegDef[RF90_PATH_B].rfLSSI_Select = rFPGA0_XAB_RFParameter; + priv->PHYRegDef[RF90_PATH_C].rfLSSI_Select = rFPGA0_XCD_RFParameter; + priv->PHYRegDef[RF90_PATH_D].rfLSSI_Select = rFPGA0_XCD_RFParameter; + + // Tx AGC Gain Stage (same for all path. Should we remove this?) + priv->PHYRegDef[RF90_PATH_A].rfTxGainStage = rFPGA0_TxGainStage; //Tx gain stage + priv->PHYRegDef[RF90_PATH_B].rfTxGainStage = rFPGA0_TxGainStage; //Tx gain stage + priv->PHYRegDef[RF90_PATH_C].rfTxGainStage = rFPGA0_TxGainStage; //Tx gain stage + priv->PHYRegDef[RF90_PATH_D].rfTxGainStage = rFPGA0_TxGainStage; //Tx gain stage + + // Tranceiver A~D HSSI Parameter-1 + priv->PHYRegDef[RF90_PATH_A].rfHSSIPara1 = rFPGA0_XA_HSSIParameter1; //wire control parameter1 + priv->PHYRegDef[RF90_PATH_B].rfHSSIPara1 = rFPGA0_XB_HSSIParameter1; //wire control parameter1 + priv->PHYRegDef[RF90_PATH_C].rfHSSIPara1 = rFPGA0_XC_HSSIParameter1; //wire control parameter1 + priv->PHYRegDef[RF90_PATH_D].rfHSSIPara1 = rFPGA0_XD_HSSIParameter1; //wire control parameter1 + + // Tranceiver A~D HSSI Parameter-2 + priv->PHYRegDef[RF90_PATH_A].rfHSSIPara2 = rFPGA0_XA_HSSIParameter2; //wire control parameter2 + priv->PHYRegDef[RF90_PATH_B].rfHSSIPara2 = rFPGA0_XB_HSSIParameter2; //wire control parameter2 + priv->PHYRegDef[RF90_PATH_C].rfHSSIPara2 = rFPGA0_XC_HSSIParameter2; //wire control parameter2 + priv->PHYRegDef[RF90_PATH_D].rfHSSIPara2 = rFPGA0_XD_HSSIParameter2; //wire control parameter1 + + // RF switch Control + priv->PHYRegDef[RF90_PATH_A].rfSwitchControl = rFPGA0_XAB_SwitchControl; //TR/Ant switch control + priv->PHYRegDef[RF90_PATH_B].rfSwitchControl = rFPGA0_XAB_SwitchControl; + priv->PHYRegDef[RF90_PATH_C].rfSwitchControl = rFPGA0_XCD_SwitchControl; + priv->PHYRegDef[RF90_PATH_D].rfSwitchControl = rFPGA0_XCD_SwitchControl; + + // AGC control 1 + priv->PHYRegDef[RF90_PATH_A].rfAGCControl1 = rOFDM0_XAAGCCore1; + priv->PHYRegDef[RF90_PATH_B].rfAGCControl1 = rOFDM0_XBAGCCore1; + priv->PHYRegDef[RF90_PATH_C].rfAGCControl1 = rOFDM0_XCAGCCore1; + priv->PHYRegDef[RF90_PATH_D].rfAGCControl1 = rOFDM0_XDAGCCore1; + + // AGC control 2 + priv->PHYRegDef[RF90_PATH_A].rfAGCControl2 = rOFDM0_XAAGCCore2; + priv->PHYRegDef[RF90_PATH_B].rfAGCControl2 = rOFDM0_XBAGCCore2; + priv->PHYRegDef[RF90_PATH_C].rfAGCControl2 = rOFDM0_XCAGCCore2; + priv->PHYRegDef[RF90_PATH_D].rfAGCControl2 = rOFDM0_XDAGCCore2; + + // RX AFE control 1 + priv->PHYRegDef[RF90_PATH_A].rfRxIQImbalance = rOFDM0_XARxIQImbalance; + priv->PHYRegDef[RF90_PATH_B].rfRxIQImbalance = rOFDM0_XBRxIQImbalance; + priv->PHYRegDef[RF90_PATH_C].rfRxIQImbalance = rOFDM0_XCRxIQImbalance; + priv->PHYRegDef[RF90_PATH_D].rfRxIQImbalance = rOFDM0_XDRxIQImbalance; + + // RX AFE control 1 + priv->PHYRegDef[RF90_PATH_A].rfRxAFE = rOFDM0_XARxAFE; + priv->PHYRegDef[RF90_PATH_B].rfRxAFE = rOFDM0_XBRxAFE; + priv->PHYRegDef[RF90_PATH_C].rfRxAFE = rOFDM0_XCRxAFE; + priv->PHYRegDef[RF90_PATH_D].rfRxAFE = rOFDM0_XDRxAFE; + + // Tx AFE control 1 + priv->PHYRegDef[RF90_PATH_A].rfTxIQImbalance = rOFDM0_XATxIQImbalance; + priv->PHYRegDef[RF90_PATH_B].rfTxIQImbalance = rOFDM0_XBTxIQImbalance; + priv->PHYRegDef[RF90_PATH_C].rfTxIQImbalance = rOFDM0_XCTxIQImbalance; + priv->PHYRegDef[RF90_PATH_D].rfTxIQImbalance = rOFDM0_XDTxIQImbalance; + + // Tx AFE control 2 + priv->PHYRegDef[RF90_PATH_A].rfTxAFE = rOFDM0_XATxAFE; + priv->PHYRegDef[RF90_PATH_B].rfTxAFE = rOFDM0_XBTxAFE; + priv->PHYRegDef[RF90_PATH_C].rfTxAFE = rOFDM0_XCTxAFE; + priv->PHYRegDef[RF90_PATH_D].rfTxAFE = rOFDM0_XDTxAFE; + + // Tranceiver LSSI Readback + priv->PHYRegDef[RF90_PATH_A].rfLSSIReadBack = rFPGA0_XA_LSSIReadBack; + priv->PHYRegDef[RF90_PATH_B].rfLSSIReadBack = rFPGA0_XB_LSSIReadBack; + priv->PHYRegDef[RF90_PATH_C].rfLSSIReadBack = rFPGA0_XC_LSSIReadBack; + priv->PHYRegDef[RF90_PATH_D].rfLSSIReadBack = rFPGA0_XD_LSSIReadBack; + +} +/****************************************************************************** + *function: This function is to write register and then readback to make sure whether BB and RF is OK + * input: net_device dev + * HW90_BLOCK_E CheckBlock + * RF90_RADIO_PATH_E eRFPath //only used when checkblock is HW90_BLOCK_RF + * output: none + * return: return whether BB and RF is ok(0:OK; 1:Fail) + * notice: This function may be removed in the ASIC + * ***************************************************************************/ +u8 rtl8192_phy_checkBBAndRF(struct net_device* dev, HW90_BLOCK_E CheckBlock, RF90_RADIO_PATH_E eRFPath) +{ +// struct r8192_priv *priv = ieee80211_priv(dev); +// BB_REGISTER_DEFINITION_T *pPhyReg = &priv->PHYRegDef[eRFPath]; + u8 ret = 0; + u32 i, CheckTimes = 4, dwRegRead = 0; + u32 WriteAddr[4]; + u32 WriteData[] = {0xfffff027, 0xaa55a02f, 0x00000027, 0x55aa502f}; + // Initialize register address offset to be checked + WriteAddr[HW90_BLOCK_MAC] = 0x100; + WriteAddr[HW90_BLOCK_PHY0] = 0x900; + WriteAddr[HW90_BLOCK_PHY1] = 0x800; + WriteAddr[HW90_BLOCK_RF] = 0x3; + RT_TRACE(COMP_PHY, "=======>%s(), CheckBlock:%d\n", __FUNCTION__, CheckBlock); + for(i=0 ; i < CheckTimes ; i++) + { + + // + // Write Data to register and readback + // + switch(CheckBlock) + { + case HW90_BLOCK_MAC: + RT_TRACE(COMP_ERR, "PHY_CheckBBRFOK(): Never Write 0x100 here!"); + break; + + case HW90_BLOCK_PHY0: + case HW90_BLOCK_PHY1: + write_nic_dword(dev, WriteAddr[CheckBlock], WriteData[i]); + dwRegRead = read_nic_dword(dev, WriteAddr[CheckBlock]); + break; + + case HW90_BLOCK_RF: + WriteData[i] &= 0xfff; + rtl8192_phy_SetRFReg(dev, eRFPath, WriteAddr[HW90_BLOCK_RF], bMask12Bits, WriteData[i]); + // TODO: we should not delay for such a long time. Ask SD3 + msleep(1); + dwRegRead = rtl8192_phy_QueryRFReg(dev, eRFPath, WriteAddr[HW90_BLOCK_RF], bMask12Bits); + msleep(1); + break; + + default: + ret = 1; + break; + } + + + // + // Check whether readback data is correct + // + if(dwRegRead != WriteData[i]) + { + RT_TRACE((COMP_PHY|COMP_ERR), "====>error=====dwRegRead: %x, WriteData: %x \n", dwRegRead, WriteData[i]); + ret = 1; + break; + } + } + + return ret; +} + + +/****************************************************************************** + *function: This function initialize BB&RF + * input: net_device dev + * output: none + * return: none + * notice: Initialization value may change all the time, so please make + * sure it has been synced with the newest. + * ***************************************************************************/ +void rtl8192_BB_Config_ParaFile(struct net_device* dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + u8 bRegValue = 0, eCheckItem = 0, rtStatus = 0; + u32 dwRegValue = 0; + /************************************** + //<1>Initialize BaseBand + **************************************/ + + /*--set BB Global Reset--*/ + bRegValue = read_nic_byte(dev, BB_GLOBAL_RESET); + write_nic_byte(dev, BB_GLOBAL_RESET,(bRegValue|BB_GLOBAL_RESET_BIT)); + mdelay(50); + /*---set BB reset Active---*/ + dwRegValue = read_nic_dword(dev, CPU_GEN); + write_nic_dword(dev, CPU_GEN, (dwRegValue&(~CPU_GEN_BB_RST))); + + /*----Ckeck FPGAPHY0 and PHY1 board is OK----*/ + // TODO: this function should be removed on ASIC , Emily 2007.2.2 + for(eCheckItem=(HW90_BLOCK_E)HW90_BLOCK_PHY0; eCheckItem<=HW90_BLOCK_PHY1; eCheckItem++) + { + rtStatus = rtl8192_phy_checkBBAndRF(dev, (HW90_BLOCK_E)eCheckItem, (RF90_RADIO_PATH_E)0); //don't care RF path + if(rtStatus != 0) + { + RT_TRACE((COMP_ERR | COMP_PHY), "PHY_RF8256_Config():Check PHY%d Fail!!\n", eCheckItem-1); + return ; + } + } + /*---- Set CCK and OFDM Block "OFF"----*/ + rtl8192_setBBreg(dev, rFPGA0_RFMOD, bCCKEn|bOFDMEn, 0x0); + /*----BB Register Initilazation----*/ + //==m==>Set PHY REG From Header<==m== + rtl8192_phyConfigBB(dev, BaseBand_Config_PHY_REG); + + /*----Set BB reset de-Active----*/ + dwRegValue = read_nic_dword(dev, CPU_GEN); + write_nic_dword(dev, CPU_GEN, (dwRegValue|CPU_GEN_BB_RST)); + + /*----BB AGC table Initialization----*/ + //==m==>Set PHY REG From Header<==m== + rtl8192_phyConfigBB(dev, BaseBand_Config_AGC_TAB); + + /*----Enable XSTAL ----*/ + write_nic_byte_E(dev, 0x5e, 0x00); + if (priv->card_8192_version == (u8)VERSION_819xU_A) + { + //Antenna gain offset from B/C/D to A + dwRegValue = (priv->AntennaTxPwDiff[1]<<4 | priv->AntennaTxPwDiff[0]); + rtl8192_setBBreg(dev, rFPGA0_TxGainStage, (bXBTxAGC|bXCTxAGC), dwRegValue); + + //XSTALLCap + dwRegValue = priv->CrystalCap & 0xf; + rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, bXtalCap, dwRegValue); + } + + // Check if the CCK HighPower is turned ON. + // This is used to calculate PWDB. + priv->bCckHighPower = (u8)(rtl8192_QueryBBReg(dev, rFPGA0_XA_HSSIParameter2, 0x200)); + return; +} +/****************************************************************************** + *function: This function initialize BB&RF + * input: net_device dev + * output: none + * return: none + * notice: Initialization value may change all the time, so please make + * sure it has been synced with the newest. + * ***************************************************************************/ +void rtl8192_BBConfig(struct net_device* dev) +{ + rtl8192_InitBBRFRegDef(dev); + //config BB&RF. As hardCode based initialization has not been well + //implemented, so use file first.FIXME:should implement it for hardcode? + rtl8192_BB_Config_ParaFile(dev); + return; +} + +/****************************************************************************** + *function: This function obtains the initialization value of Tx power Level offset + * input: net_device dev + * output: none + * return: none + * ***************************************************************************/ +void rtl8192_phy_getTxPower(struct net_device* dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + priv->MCSTxPowerLevelOriginalOffset[0] = + read_nic_dword(dev, rTxAGC_Rate18_06); + priv->MCSTxPowerLevelOriginalOffset[1] = + read_nic_dword(dev, rTxAGC_Rate54_24); + priv->MCSTxPowerLevelOriginalOffset[2] = + read_nic_dword(dev, rTxAGC_Mcs03_Mcs00); + priv->MCSTxPowerLevelOriginalOffset[3] = + read_nic_dword(dev, rTxAGC_Mcs07_Mcs04); + priv->MCSTxPowerLevelOriginalOffset[4] = + read_nic_dword(dev, rTxAGC_Mcs11_Mcs08); + priv->MCSTxPowerLevelOriginalOffset[5] = + read_nic_dword(dev, rTxAGC_Mcs15_Mcs12); + + // read rx initial gain + priv->DefaultInitialGain[0] = read_nic_byte(dev, rOFDM0_XAAGCCore1); + priv->DefaultInitialGain[1] = read_nic_byte(dev, rOFDM0_XBAGCCore1); + priv->DefaultInitialGain[2] = read_nic_byte(dev, rOFDM0_XCAGCCore1); + priv->DefaultInitialGain[3] = read_nic_byte(dev, rOFDM0_XDAGCCore1); + RT_TRACE(COMP_INIT, "Default initial gain (c50=0x%x, c58=0x%x, c60=0x%x, c68=0x%x) \n", + priv->DefaultInitialGain[0], priv->DefaultInitialGain[1], + priv->DefaultInitialGain[2], priv->DefaultInitialGain[3]); + + // read framesync + priv->framesync = read_nic_byte(dev, rOFDM0_RxDetector3); + priv->framesyncC34 = read_nic_byte(dev, rOFDM0_RxDetector2); + RT_TRACE(COMP_INIT, "Default framesync (0x%x) = 0x%x \n", + rOFDM0_RxDetector3, priv->framesync); + + // read SIFS (save the value read fome MACPHY_REG.txt) + priv->SifsTime = read_nic_word(dev, SIFS); + + return; +} + +/****************************************************************************** + *function: This function obtains the initialization value of Tx power Level offset + * input: net_device dev + * output: none + * return: none + * ***************************************************************************/ +void rtl8192_phy_setTxPower(struct net_device* dev, u8 channel) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + u8 powerlevel = priv->TxPowerLevelCCK[channel-1]; + u8 powerlevelOFDM24G = priv->TxPowerLevelOFDM24G[channel-1]; + + switch(priv->rf_chip) + { + case RF_8256: + PHY_SetRF8256CCKTxPower(dev, powerlevel); //need further implement + PHY_SetRF8256OFDMTxPower(dev, powerlevelOFDM24G); + break; + default: +// case RF_8225: +// case RF_8258: + RT_TRACE((COMP_PHY|COMP_ERR), "error RF chipID(8225 or 8258) in function %s()\n", __FUNCTION__); + break; + } + return; +} + +/****************************************************************************** + *function: This function check Rf chip to do RF config + * input: net_device dev + * output: none + * return: only 8256 is supported + * ***************************************************************************/ +void rtl8192_phy_RFConfig(struct net_device* dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + + switch(priv->rf_chip) + { + case RF_8256: + PHY_RF8256_Config(dev); + break; + // case RF_8225: + // case RF_8258: + default: + RT_TRACE(COMP_ERR, "error chip id\n"); + break; + } + return; +} + +/****************************************************************************** + *function: This function update Initial gain + * input: net_device dev + * output: none + * return: As Windows has not implemented this, wait for complement + * ***************************************************************************/ +void rtl8192_phy_updateInitGain(struct net_device* dev) +{ + return; +} + +/****************************************************************************** + *function: This function read RF parameters from general head file, and do RF 3-wire + * input: net_device dev + * output: none + * return: return code show if RF configuration is successful(0:pass, 1:fail) + * Note: Delay may be required for RF configuration + * ***************************************************************************/ +u8 rtl8192_phy_ConfigRFWithHeaderFile(struct net_device* dev, RF90_RADIO_PATH_E eRFPath) +{ + + int i; + //u32* pRFArray; + u8 ret = 0; + + switch(eRFPath){ + case RF90_PATH_A: + for(i = 0;iTxPowerLevelCCK[channel-1]; + u8 powerlevelOFDM24G = priv->TxPowerLevelOFDM24G[channel-1]; + + switch(priv->rf_chip) + { + case RF_8225: +#ifdef TO_DO_LIST + PHY_SetRF8225CckTxPower(Adapter, powerlevel); + PHY_SetRF8225OfdmTxPower(Adapter, powerlevelOFDM24G); +#endif + break; + + case RF_8256: + PHY_SetRF8256CCKTxPower(dev, powerlevel); + PHY_SetRF8256OFDMTxPower(dev, powerlevelOFDM24G); + break; + + case RF_8258: + break; + default: + RT_TRACE(COMP_ERR, "unknown rf chip ID in rtl8192_SetTxPowerLevel()\n"); + break; + } + return; +} + +/****************************************************************************** + *function: This function set RF state on or off + * input: struct net_device *dev + * RT_RF_POWER_STATE eRFPowerState //Power State to set + * output: none + * return: none + * Note: + * ***************************************************************************/ +bool rtl8192_SetRFPowerState(struct net_device *dev, RT_RF_POWER_STATE eRFPowerState) +{ + bool bResult = true; +// u8 eRFPath; + struct r8192_priv *priv = ieee80211_priv(dev); + + if(eRFPowerState == priv->ieee80211->eRFPowerState) + return false; + + if(priv->SetRFPowerStateInProgress == true) + return false; + + priv->SetRFPowerStateInProgress = true; + + switch(priv->rf_chip) + { + case RF_8256: + switch( eRFPowerState ) + { + case eRfOn: +#if 0 + rtl8192_setBBreg(dev, rFPGA0_XA_RFInterfaceOE, BIT4, 0x1); // 0x860[4] + rtl8192_setBBreg(dev, rFPGA0_AnalogParameter4, 0x300, 0x3); // 0x88c[4] + rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x60, 0x3); // 0x880[6:5] + rtl8192_setBBreg(dev, rOFDM0_TRxPathEnable, 0xf, 0x3); // 0xc04[3:0] + rtl8192_setBBreg(dev, rOFDM1_TRxPathEnable, 0xf, 0x3); // 0xd04[3:0] + rtl8192_setBBreg(dev, rFPGA0_AnalogParameter2, 0x7000, 0x3); // 0x884[14:12] + // for(eRFPath = 0; eRFPath NumTotalRFPath; eRFPath++) + // PHY_SetRFReg(Adapter, (RF90_RADIO_PATH_E)eRFPath, 0x4, 0xC00, 0x2); + + //SwChnl(Adapter->ChannelID); +#endif + //RF-A, RF-B + //enable RF-Chip A/B + rtl8192_setBBreg(dev, rFPGA0_XA_RFInterfaceOE, BIT4, 0x1); // 0x860[4] + //analog to digital on + rtl8192_setBBreg(dev, rFPGA0_AnalogParameter4, 0x300, 0x3);// 0x88c[9:8] + //digital to analog on + rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x18, 0x3); // 0x880[4:3] + //rx antenna on + rtl8192_setBBreg(dev, rOFDM0_TRxPathEnable, 0x3, 0x3);// 0xc04[1:0] + //rx antenna on + rtl8192_setBBreg(dev, rOFDM1_TRxPathEnable, 0x3, 0x3);// 0xd04[1:0] + //analog to digital part2 on + rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x60, 0x3); // 0x880[6:5] + + break; + + case eRfSleep: + + break; + + case eRfOff: +#if 0 + rtl8192_setBBreg(dev, rFPGA0_XA_RFInterfaceOE, BIT4, 0x0); // 0x860[4] + rtl8192_setBBreg(dev, rFPGA0_AnalogParameter4, 0x300, 0x0); // 0x88c[4] + rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x60, 0x0); // 0x880[6:5] + rtl8192_setBBreg(dev, rOFDM0_TRxPathEnable, 0xf, 0); // 0xc04[3:0] + rtl8192_setBBreg(dev, rOFDM1_TRxPathEnable, 0xf, 0); // 0xd04[3:0] + rtl8192_setBBreg(dev, rFPGA0_AnalogParameter2, 0x7000, 0x0); // 0x884[14:12] + // for(eRFPath = 0; eRFPath NumTotalRFPath; eRFPath++) + // PHY_SetRFReg(Adapter, (RF90_RADIO_PATH_E)eRFPath, 0x4, 0xC00, 0x0); +#endif + //RF-A, RF-B + //disable RF-Chip A/B + rtl8192_setBBreg(dev, rFPGA0_XA_RFInterfaceOE, BIT4, 0x0); // 0x860[4] + //analog to digital off, for power save + rtl8192_setBBreg(dev, rFPGA0_AnalogParameter4, 0xf00, 0x0);// 0x88c[11:8] + //digital to analog off, for power save + rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x18, 0x0); // 0x880[4:3] + //rx antenna off + rtl8192_setBBreg(dev, rOFDM0_TRxPathEnable, 0xf, 0x0);// 0xc04[3:0] + //rx antenna off + rtl8192_setBBreg(dev, rOFDM1_TRxPathEnable, 0xf, 0x0);// 0xd04[3:0] + //analog to digital part2 off, for power save + rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x60, 0x0); // 0x880[6:5] + + break; + + default: + bResult = false; + RT_TRACE(COMP_ERR, "SetRFPowerState819xUsb(): unknow state to set: 0x%X!!!\n", eRFPowerState); + break; + } + break; + default: + RT_TRACE(COMP_ERR, "Not support rf_chip(%x)\n", priv->rf_chip); + break; + } +#ifdef TO_DO_LIST + if(bResult) + { + // Update current RF state variable. + pHalData->eRFPowerState = eRFPowerState; + switch(pHalData->RFChipID ) + { + case RF_8256: + switch(pHalData->eRFPowerState) + { + case eRfOff: + // + //If Rf off reason is from IPS, Led should blink with no link, by Maddest 071015 + // + if(pMgntInfo->RfOffReason==RF_CHANGE_BY_IPS ) + { + Adapter->HalFunc.LedControlHandler(Adapter,LED_CTL_NO_LINK); + } + else + { + // Turn off LED if RF is not ON. + Adapter->HalFunc.LedControlHandler(Adapter, LED_CTL_POWER_OFF); + } + break; + + case eRfOn: + // Turn on RF we are still linked, which might happen when + // we quickly turn off and on HW RF. 2006.05.12, by rcnjko. + if( pMgntInfo->bMediaConnect == TRUE ) + { + Adapter->HalFunc.LedControlHandler(Adapter, LED_CTL_LINK); + } + else + { + // Turn off LED if RF is not ON. + Adapter->HalFunc.LedControlHandler(Adapter, LED_CTL_NO_LINK); + } + break; + + default: + // do nothing. + break; + }// Switch RF state + break; + + default: + RT_TRACE(COMP_RF, DBG_LOUD, ("SetRFPowerState8190(): Unknown RF type\n")); + break; + } + + } +#endif + priv->SetRFPowerStateInProgress = false; + + return bResult; +} + +/**************************************************************************************** + *function: This function set command table variable(struct SwChnlCmd). + * input: SwChnlCmd* CmdTable //table to be set. + * u32 CmdTableIdx //variable index in table to be set + * u32 CmdTableSz //table size. + * SwChnlCmdID CmdID //command ID to set. + * u32 Para1 + * u32 Para2 + * u32 msDelay + * output: + * return: true if finished, false otherwise + * Note: + * ************************************************************************************/ +u8 rtl8192_phy_SetSwChnlCmdArray( + SwChnlCmd* CmdTable, + u32 CmdTableIdx, + u32 CmdTableSz, + SwChnlCmdID CmdID, + u32 Para1, + u32 Para2, + u32 msDelay + ) +{ + SwChnlCmd* pCmd; + + if(CmdTable == NULL) + { + RT_TRACE(COMP_ERR, "phy_SetSwChnlCmdArray(): CmdTable cannot be NULL.\n"); + return false; + } + if(CmdTableIdx >= CmdTableSz) + { + RT_TRACE(COMP_ERR, "phy_SetSwChnlCmdArray(): Access invalid index, please check size of the table, CmdTableIdx:%d, CmdTableSz:%d\n", + CmdTableIdx, CmdTableSz); + return false; + } + + pCmd = CmdTable + CmdTableIdx; + pCmd->CmdID = CmdID; + pCmd->Para1 = Para1; + pCmd->Para2 = Para2; + pCmd->msDelay = msDelay; + + return true; +} +/****************************************************************************** + *function: This function set channel step by step + * input: struct net_device *dev + * u8 channel + * u8* stage //3 stages + * u8* step // + * u32* delay //whether need to delay + * output: store new stage, step and delay for next step(combine with function above) + * return: true if finished, false otherwise + * Note: Wait for simpler function to replace it //wb + * ***************************************************************************/ +u8 rtl8192_phy_SwChnlStepByStep(struct net_device *dev, u8 channel, u8* stage, u8* step, u32* delay) +{ + struct r8192_priv *priv = ieee80211_priv(dev); +// PCHANNEL_ACCESS_SETTING pChnlAccessSetting; + SwChnlCmd PreCommonCmd[MAX_PRECMD_CNT]; + u32 PreCommonCmdCnt; + SwChnlCmd PostCommonCmd[MAX_POSTCMD_CNT]; + u32 PostCommonCmdCnt; + SwChnlCmd RfDependCmd[MAX_RFDEPENDCMD_CNT]; + u32 RfDependCmdCnt; + SwChnlCmd *CurrentCmd = NULL; + //RF90_RADIO_PATH_E eRFPath; + u8 eRFPath; +// u32 RfRetVal; +// u8 RetryCnt; + + RT_TRACE(COMP_CH, "====>%s()====stage:%d, step:%d, channel:%d\n", __FUNCTION__, *stage, *step, channel); +// RT_ASSERT(IsLegalChannel(Adapter, channel), ("illegal channel: %d\n", channel)); +#ifdef ENABLE_DOT11D + if (!IsLegalChannel(priv->ieee80211, channel)) + { + RT_TRACE(COMP_ERR, "=============>set to illegal channel:%d\n", channel); + return true; //return true to tell upper caller function this channel setting is finished! Or it will in while loop. + } +#endif +//FIXME:need to check whether channel is legal or not here.WB + + + //for(eRFPath = RF90_PATH_A; eRFPath NumTotalRFPath; eRFPath++) +// for(eRFPath = 0; eRFPath Fill up pre common command. + PreCommonCmdCnt = 0; + rtl8192_phy_SetSwChnlCmdArray(PreCommonCmd, PreCommonCmdCnt++, MAX_PRECMD_CNT, + CmdID_SetTxPowerLevel, 0, 0, 0); + rtl8192_phy_SetSwChnlCmdArray(PreCommonCmd, PreCommonCmdCnt++, MAX_PRECMD_CNT, + CmdID_End, 0, 0, 0); + + // <2> Fill up post common command. + PostCommonCmdCnt = 0; + + rtl8192_phy_SetSwChnlCmdArray(PostCommonCmd, PostCommonCmdCnt++, MAX_POSTCMD_CNT, + CmdID_End, 0, 0, 0); + + // <3> Fill up RF dependent command. + RfDependCmdCnt = 0; + switch( priv->rf_chip ) + { + case RF_8225: + if (!(channel >= 1 && channel <= 14)) + { + RT_TRACE(COMP_ERR, "illegal channel for Zebra 8225: %d\n", channel); + return true; + } + rtl8192_phy_SetSwChnlCmdArray(RfDependCmd, RfDependCmdCnt++, MAX_RFDEPENDCMD_CNT, + CmdID_RF_WriteReg, rZebra1_Channel, RF_CHANNEL_TABLE_ZEBRA[channel], 10); + rtl8192_phy_SetSwChnlCmdArray(RfDependCmd, RfDependCmdCnt++, MAX_RFDEPENDCMD_CNT, + CmdID_End, 0, 0, 0); + break; + + case RF_8256: + // TEST!! This is not the table for 8256!! + if (!(channel >= 1 && channel <= 14)) + { + RT_TRACE(COMP_ERR, "illegal channel for Zebra 8256: %d\n", channel); + return true; + } + rtl8192_phy_SetSwChnlCmdArray(RfDependCmd, RfDependCmdCnt++, MAX_RFDEPENDCMD_CNT, + CmdID_RF_WriteReg, rZebra1_Channel, channel, 10); + rtl8192_phy_SetSwChnlCmdArray(RfDependCmd, RfDependCmdCnt++, MAX_RFDEPENDCMD_CNT, + CmdID_End, 0, 0, 0); + break; + + case RF_8258: + break; + + default: + RT_TRACE(COMP_ERR, "Unknown RFChipID: %d\n", priv->rf_chip); + return true; + break; + } + + + do{ + switch(*stage) + { + case 0: + CurrentCmd=&PreCommonCmd[*step]; + break; + case 1: + CurrentCmd=&RfDependCmd[*step]; + break; + case 2: + CurrentCmd=&PostCommonCmd[*step]; + break; + } + + if(CurrentCmd->CmdID==CmdID_End) + { + if((*stage)==2) + { + (*delay)=CurrentCmd->msDelay; + return true; + } + else + { + (*stage)++; + (*step)=0; + continue; + } + } + + switch(CurrentCmd->CmdID) + { + case CmdID_SetTxPowerLevel: + if(priv->card_8192_version == (u8)VERSION_819xU_A) //xiong: consider it later! + rtl8192_SetTxPowerLevel(dev,channel); + break; + case CmdID_WritePortUlong: + write_nic_dword(dev, CurrentCmd->Para1, CurrentCmd->Para2); + break; + case CmdID_WritePortUshort: + write_nic_word(dev, CurrentCmd->Para1, (u16)CurrentCmd->Para2); + break; + case CmdID_WritePortUchar: + write_nic_byte(dev, CurrentCmd->Para1, (u8)CurrentCmd->Para2); + break; + case CmdID_RF_WriteReg: + for(eRFPath = 0; eRFPath < RF90_PATH_MAX; eRFPath++) + { + rtl8192_phy_SetRFReg(dev, (RF90_RADIO_PATH_E)eRFPath, CurrentCmd->Para1, bZebra1_ChannelNum, CurrentCmd->Para2); + } + break; + default: + break; + } + + break; + }while(true); +// }/*for(Number of RF paths)*/ + + (*delay)=CurrentCmd->msDelay; + (*step)++; + return false; +} + +/****************************************************************************** + *function: This function does acturally set channel work + * input: struct net_device *dev + * u8 channel + * output: none + * return: noin + * Note: We should not call this function directly + * ***************************************************************************/ +void rtl8192_phy_FinishSwChnlNow(struct net_device *dev, u8 channel) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + u32 delay = 0; + + while(!rtl8192_phy_SwChnlStepByStep(dev,channel,&priv->SwChnlStage,&priv->SwChnlStep,&delay)) + { + // if(delay>0) + // msleep(delay);//or mdelay? need further consideration + if(!priv->up) + break; + } +} +/****************************************************************************** + *function: Callback routine of the work item for switch channel. + * input: + * + * output: none + * return: noin + * ***************************************************************************/ +void rtl8192_SwChnl_WorkItem(struct net_device *dev) +{ + + struct r8192_priv *priv = ieee80211_priv(dev); + + RT_TRACE(COMP_CH, "==> SwChnlCallback819xUsbWorkItem(), chan:%d\n", priv->chan); + + + rtl8192_phy_FinishSwChnlNow(dev , priv->chan); + + RT_TRACE(COMP_CH, "<== SwChnlCallback819xUsbWorkItem()\n"); +} + +/****************************************************************************** + *function: This function scheduled actural workitem to set channel + * input: net_device dev + * u8 channel //channel to set + * output: none + * return: return code show if workitem is scheduled(1:pass, 0:fail) + * Note: Delay may be required for RF configuration + * ***************************************************************************/ +u8 rtl8192_phy_SwChnl(struct net_device* dev, u8 channel) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + RT_TRACE(COMP_CH, "=====>%s(), SwChnlInProgress:%d\n", __FUNCTION__, priv->SwChnlInProgress); + if(!priv->up) + return false; + if(priv->SwChnlInProgress) + return false; + +// if(pHalData->SetBWModeInProgress) +// return; +if (0) //to test current channel from RF reg 0x7. +{ + u8 eRFPath; + for(eRFPath = 0; eRFPath < 2; eRFPath++){ + printk("====>set channel:%x\n",rtl8192_phy_QueryRFReg(dev, (RF90_RADIO_PATH_E)eRFPath, 0x7, bZebra1_ChannelNum)); + udelay(10); + } +} + //-------------------------------------------- + switch(priv->ieee80211->mode) + { + case WIRELESS_MODE_A: + case WIRELESS_MODE_N_5G: + if (channel<=14){ + RT_TRACE(COMP_ERR, "WIRELESS_MODE_A but channel<=14"); + return false; + } + break; + case WIRELESS_MODE_B: + if (channel>14){ + RT_TRACE(COMP_ERR, "WIRELESS_MODE_B but channel>14"); + return false; + } + break; + case WIRELESS_MODE_G: + case WIRELESS_MODE_N_24G: + if (channel>14){ + RT_TRACE(COMP_ERR, "WIRELESS_MODE_G but channel>14"); + return false; + } + break; + } + //-------------------------------------------- + + priv->SwChnlInProgress = true; + if(channel == 0) + channel = 1; + + priv->chan=channel; + + priv->SwChnlStage=0; + priv->SwChnlStep=0; +// schedule_work(&(priv->SwChnlWorkItem)); +// rtl8192_SwChnl_WorkItem(dev); + if(priv->up) { +// queue_work(priv->priv_wq,&(priv->SwChnlWorkItem)); + rtl8192_SwChnl_WorkItem(dev); + } + + priv->SwChnlInProgress = false; + return true; +} + + +// +/****************************************************************************** + *function: Callback routine of the work item for set bandwidth mode. + * input: struct net_device *dev + * HT_CHANNEL_WIDTH Bandwidth //20M or 40M + * HT_EXTCHNL_OFFSET Offset //Upper, Lower, or Don't care + * output: none + * return: none + * Note: I doubt whether SetBWModeInProgress flag is necessary as we can + * test whether current work in the queue or not.//do I? + * ***************************************************************************/ +void rtl8192_SetBWModeWorkItem(struct net_device *dev) +{ + + struct r8192_priv *priv = ieee80211_priv(dev); + u8 regBwOpMode; + + RT_TRACE(COMP_SWBW, "==>rtl8192_SetBWModeWorkItem() Switch to %s bandwidth\n", \ + priv->CurrentChannelBW == HT_CHANNEL_WIDTH_20?"20MHz":"40MHz") + + + if(priv->rf_chip == RF_PSEUDO_11N) + { + priv->SetBWModeInProgress= false; + return; + } + + //<1>Set MAC register + regBwOpMode = read_nic_byte(dev, BW_OPMODE); + + switch(priv->CurrentChannelBW) + { + case HT_CHANNEL_WIDTH_20: + regBwOpMode |= BW_OPMODE_20MHZ; + // 2007/02/07 Mark by Emily becasue we have not verify whether this register works + write_nic_byte(dev, BW_OPMODE, regBwOpMode); + break; + + case HT_CHANNEL_WIDTH_20_40: + regBwOpMode &= ~BW_OPMODE_20MHZ; + // 2007/02/07 Mark by Emily becasue we have not verify whether this register works + write_nic_byte(dev, BW_OPMODE, regBwOpMode); + break; + + default: + RT_TRACE(COMP_ERR, "SetChannelBandwidth819xUsb(): unknown Bandwidth: %#X\n",priv->CurrentChannelBW); + break; + } + + //<2>Set PHY related register + switch(priv->CurrentChannelBW) + { + case HT_CHANNEL_WIDTH_20: + // Add by Vivi 20071119 + rtl8192_setBBreg(dev, rFPGA0_RFMOD, bRFMOD, 0x0); + rtl8192_setBBreg(dev, rFPGA1_RFMOD, bRFMOD, 0x0); + rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x00100000, 1); + + // Correct the tx power for CCK rate in 20M. Suggest by YN, 20071207 +#if 0 + write_nic_dword(dev, rCCK0_TxFilter1, 0x1a1b0000); + write_nic_dword(dev, rCCK0_TxFilter2, 0x090e1317); + write_nic_dword(dev, rCCK0_DebugPort, 0x00000204); +#endif + priv->cck_present_attentuation = + priv->cck_present_attentuation_20Mdefault + priv->cck_present_attentuation_difference; + + if(priv->cck_present_attentuation > 22) + priv->cck_present_attentuation= 22; + if(priv->cck_present_attentuation< 0) + priv->cck_present_attentuation = 0; + RT_TRACE(COMP_INIT, "20M, pHalData->CCKPresentAttentuation = %d\n", priv->cck_present_attentuation); + + if(priv->chan == 14 && !priv->bcck_in_ch14) + { + priv->bcck_in_ch14 = TRUE; + dm_cck_txpower_adjust(dev,priv->bcck_in_ch14); + } + else if(priv->chan != 14 && priv->bcck_in_ch14) + { + priv->bcck_in_ch14 = FALSE; + dm_cck_txpower_adjust(dev,priv->bcck_in_ch14); + } + else + dm_cck_txpower_adjust(dev,priv->bcck_in_ch14); + + break; + case HT_CHANNEL_WIDTH_20_40: + // Add by Vivi 20071119 + rtl8192_setBBreg(dev, rFPGA0_RFMOD, bRFMOD, 0x1); + rtl8192_setBBreg(dev, rFPGA1_RFMOD, bRFMOD, 0x1); + rtl8192_setBBreg(dev, rCCK0_System, bCCKSideBand, (priv->nCur40MhzPrimeSC>>1)); + rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x00100000, 0); + rtl8192_setBBreg(dev, rOFDM1_LSTF, 0xC00, priv->nCur40MhzPrimeSC); +#if 0 + // Correct the tx power for CCK rate in 40M. Suggest by YN, 20071207 + write_nic_dword(dev, rCCK0_TxFilter1, 0x35360000); + write_nic_dword(dev, rCCK0_TxFilter2, 0x121c252e); + write_nic_dword(dev, rCCK0_DebugPort, 0x00000409); +#endif + priv->cck_present_attentuation = + priv->cck_present_attentuation_40Mdefault + priv->cck_present_attentuation_difference; + + if(priv->cck_present_attentuation > 22) + priv->cck_present_attentuation = 22; + if(priv->cck_present_attentuation < 0) + priv->cck_present_attentuation = 0; + + RT_TRACE(COMP_INIT, "40M, pHalData->CCKPresentAttentuation = %d\n", priv->cck_present_attentuation); + if(priv->chan == 14 && !priv->bcck_in_ch14) + { + priv->bcck_in_ch14 = true; + dm_cck_txpower_adjust(dev,priv->bcck_in_ch14); + } + else if(priv->chan!= 14 && priv->bcck_in_ch14) + { + priv->bcck_in_ch14 = false; + dm_cck_txpower_adjust(dev,priv->bcck_in_ch14); + } + else + dm_cck_txpower_adjust(dev,priv->bcck_in_ch14); + + break; + default: + RT_TRACE(COMP_ERR, "SetChannelBandwidth819xUsb(): unknown Bandwidth: %#X\n" ,priv->CurrentChannelBW); + break; + + } + //Skip over setting of J-mode in BB register here. Default value is "None J mode". Emily 20070315 + +#if 1 + //<3>Set RF related register + switch( priv->rf_chip ) + { + case RF_8225: +#ifdef TO_DO_LIST + PHY_SetRF8225Bandwidth(Adapter, pHalData->CurrentChannelBW); +#endif + break; + + case RF_8256: + PHY_SetRF8256Bandwidth(dev, priv->CurrentChannelBW); + break; + + case RF_8258: + // PHY_SetRF8258Bandwidth(); + break; + + case RF_PSEUDO_11N: + // Do Nothing + break; + + default: + RT_TRACE(COMP_ERR, "Unknown RFChipID: %d\n", priv->rf_chip); + break; + } +#endif + priv->SetBWModeInProgress= false; + + RT_TRACE(COMP_SWBW, "<==SetBWMode819xUsb(), %d", atomic_read(&(priv->ieee80211->atm_swbw)) ); +} + +/****************************************************************************** + *function: This function schedules bandwith switch work. + * input: struct net_device *dev + * HT_CHANNEL_WIDTH Bandwidth //20M or 40M + * HT_EXTCHNL_OFFSET Offset //Upper, Lower, or Don't care + * output: none + * return: none + * Note: I doubt whether SetBWModeInProgress flag is necessary as we can + * test whether current work in the queue or not.//do I? + * ***************************************************************************/ +void rtl8192_SetBWMode(struct net_device *dev, HT_CHANNEL_WIDTH Bandwidth, HT_EXTCHNL_OFFSET Offset) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + + if(priv->SetBWModeInProgress) + return; + priv->SetBWModeInProgress= true; + + priv->CurrentChannelBW = Bandwidth; + + if(Offset==HT_EXTCHNL_OFFSET_LOWER) + priv->nCur40MhzPrimeSC = HAL_PRIME_CHNL_OFFSET_UPPER; + else if(Offset==HT_EXTCHNL_OFFSET_UPPER) + priv->nCur40MhzPrimeSC = HAL_PRIME_CHNL_OFFSET_LOWER; + else + priv->nCur40MhzPrimeSC = HAL_PRIME_CHNL_OFFSET_DONT_CARE; + + //queue_work(priv->priv_wq, &(priv->SetBWModeWorkItem)); + // schedule_work(&(priv->SetBWModeWorkItem)); + rtl8192_SetBWModeWorkItem(dev); + +} + +void InitialGain819xUsb(struct net_device *dev, u8 Operation) +{ + struct r8192_priv *priv = ieee80211_priv(dev); + + priv->InitialGainOperateType = Operation; + + if(priv->up) + { + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + queue_delayed_work(priv->priv_wq,&priv->initialgain_operate_wq,0); + #else + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + schedule_task(&priv->initialgain_operate_wq); + #else + queue_work(priv->priv_wq,&priv->initialgain_operate_wq); + #endif + #endif + } +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) +extern void InitialGainOperateWorkItemCallBack(struct work_struct *work) +{ + struct delayed_work *dwork = container_of(work,struct delayed_work,work); + struct r8192_priv *priv = container_of(dwork,struct r8192_priv,initialgain_operate_wq); + struct net_device *dev = priv->ieee80211->dev; +#else +extern void InitialGainOperateWorkItemCallBack(struct net_device *dev) +{ + struct r8192_priv *priv = ieee80211_priv(dev); +#endif +#define SCAN_RX_INITIAL_GAIN 0x17 +#define POWER_DETECTION_TH 0x08 + u32 BitMask; + u8 initial_gain; + u8 Operation; + + Operation = priv->InitialGainOperateType; + + switch(Operation) + { + case IG_Backup: + RT_TRACE(COMP_SCAN, "IG_Backup, backup the initial gain.\n"); + initial_gain = SCAN_RX_INITIAL_GAIN;//priv->DefaultInitialGain[0];// + BitMask = bMaskByte0; + if(dm_digtable.dig_algorithm == DIG_ALGO_BY_FALSE_ALARM) + rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x8); // FW DIG OFF + priv->initgain_backup.xaagccore1 = (u8)rtl8192_QueryBBReg(dev, rOFDM0_XAAGCCore1, BitMask); + priv->initgain_backup.xbagccore1 = (u8)rtl8192_QueryBBReg(dev, rOFDM0_XBAGCCore1, BitMask); + priv->initgain_backup.xcagccore1 = (u8)rtl8192_QueryBBReg(dev, rOFDM0_XCAGCCore1, BitMask); + priv->initgain_backup.xdagccore1 = (u8)rtl8192_QueryBBReg(dev, rOFDM0_XDAGCCore1, BitMask); + BitMask = bMaskByte2; + priv->initgain_backup.cca = (u8)rtl8192_QueryBBReg(dev, rCCK0_CCA, BitMask); + + RT_TRACE(COMP_SCAN, "Scan InitialGainBackup 0xc50 is %x\n",priv->initgain_backup.xaagccore1); + RT_TRACE(COMP_SCAN, "Scan InitialGainBackup 0xc58 is %x\n",priv->initgain_backup.xbagccore1); + RT_TRACE(COMP_SCAN, "Scan InitialGainBackup 0xc60 is %x\n",priv->initgain_backup.xcagccore1); + RT_TRACE(COMP_SCAN, "Scan InitialGainBackup 0xc68 is %x\n",priv->initgain_backup.xdagccore1); + RT_TRACE(COMP_SCAN, "Scan InitialGainBackup 0xa0a is %x\n",priv->initgain_backup.cca); + + RT_TRACE(COMP_SCAN, "Write scan initial gain = 0x%x \n", initial_gain); + write_nic_byte(dev, rOFDM0_XAAGCCore1, initial_gain); + write_nic_byte(dev, rOFDM0_XBAGCCore1, initial_gain); + write_nic_byte(dev, rOFDM0_XCAGCCore1, initial_gain); + write_nic_byte(dev, rOFDM0_XDAGCCore1, initial_gain); + RT_TRACE(COMP_SCAN, "Write scan 0xa0a = 0x%x \n", POWER_DETECTION_TH); + write_nic_byte(dev, 0xa0a, POWER_DETECTION_TH); + break; + case IG_Restore: + RT_TRACE(COMP_SCAN, "IG_Restore, restore the initial gain.\n"); + BitMask = 0x7f; //Bit0~ Bit6 + if(dm_digtable.dig_algorithm == DIG_ALGO_BY_FALSE_ALARM) + rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x8); // FW DIG OFF + + rtl8192_setBBreg(dev, rOFDM0_XAAGCCore1, BitMask, (u32)priv->initgain_backup.xaagccore1); + rtl8192_setBBreg(dev, rOFDM0_XBAGCCore1, BitMask, (u32)priv->initgain_backup.xbagccore1); + rtl8192_setBBreg(dev, rOFDM0_XCAGCCore1, BitMask, (u32)priv->initgain_backup.xcagccore1); + rtl8192_setBBreg(dev, rOFDM0_XDAGCCore1, BitMask, (u32)priv->initgain_backup.xdagccore1); + BitMask = bMaskByte2; + rtl8192_setBBreg(dev, rCCK0_CCA, BitMask, (u32)priv->initgain_backup.cca); + + RT_TRACE(COMP_SCAN, "Scan BBInitialGainRestore 0xc50 is %x\n",priv->initgain_backup.xaagccore1); + RT_TRACE(COMP_SCAN, "Scan BBInitialGainRestore 0xc58 is %x\n",priv->initgain_backup.xbagccore1); + RT_TRACE(COMP_SCAN, "Scan BBInitialGainRestore 0xc60 is %x\n",priv->initgain_backup.xcagccore1); + RT_TRACE(COMP_SCAN, "Scan BBInitialGainRestore 0xc68 is %x\n",priv->initgain_backup.xdagccore1); + RT_TRACE(COMP_SCAN, "Scan BBInitialGainRestore 0xa0a is %x\n",priv->initgain_backup.cca); + +#ifdef RTL8190P + SetTxPowerLevel8190(Adapter,priv->CurrentChannel); +#endif +#ifdef RTL8192E + SetTxPowerLevel8190(Adapter,priv->CurrentChannel); +#endif +//#ifdef RTL8192U + rtl8192_phy_setTxPower(dev,priv->ieee80211->current_network.channel); +//#endif + + if(dm_digtable.dig_algorithm == DIG_ALGO_BY_FALSE_ALARM) + rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x1); // FW DIG ON + break; + default: + RT_TRACE(COMP_SCAN, "Unknown IG Operation. \n"); + break; + } +} + diff --git a/drivers/staging/rtl8192su/r819xU_phy.h b/drivers/staging/rtl8192su/r819xU_phy.h new file mode 100644 index 000000000000..c165ac1265d9 --- /dev/null +++ b/drivers/staging/rtl8192su/r819xU_phy.h @@ -0,0 +1,94 @@ +#ifndef _R819XU_PHY_H +#define _R819XU_PHY_H + +/* Channel switch:The size of command tables for switch channel*/ +#define MAX_PRECMD_CNT 16 +#define MAX_RFDEPENDCMD_CNT 16 +#define MAX_POSTCMD_CNT 16 + +typedef enum _SwChnlCmdID{ + CmdID_End, + CmdID_SetTxPowerLevel, + CmdID_BBRegWrite10, + CmdID_WritePortUlong, + CmdID_WritePortUshort, + CmdID_WritePortUchar, + CmdID_RF_WriteReg, +}SwChnlCmdID; + +/*--------------------------------Define structure--------------------------------*/ +/* 1. Switch channel related */ +typedef struct _SwChnlCmd{ + SwChnlCmdID CmdID; + u32 Para1; + u32 Para2; + u32 msDelay; +}__attribute__ ((packed)) SwChnlCmd; + +extern u32 rtl819XMACPHY_Array_PG[]; +extern u32 rtl819XPHY_REG_1T2RArray[]; +extern u32 rtl819XAGCTAB_Array[]; +extern u32 rtl819XRadioA_Array[]; +extern u32 rtl819XRadioB_Array[]; +extern u32 rtl819XRadioC_Array[]; +extern u32 rtl819XRadioD_Array[]; + +typedef enum _HW90_BLOCK{ + HW90_BLOCK_MAC = 0, + HW90_BLOCK_PHY0 = 1, + HW90_BLOCK_PHY1 = 2, + HW90_BLOCK_RF = 3, + HW90_BLOCK_MAXIMUM = 4, // Never use this +}HW90_BLOCK_E, *PHW90_BLOCK_E; + +typedef enum _RF90_RADIO_PATH{ + RF90_PATH_A = 0, //Radio Path A + RF90_PATH_B = 1, //Radio Path B + RF90_PATH_C = 2, //Radio Path C + RF90_PATH_D = 3, //Radio Path D + RF90_PATH_MAX //Max RF number 92 support +}RF90_RADIO_PATH_E, *PRF90_RADIO_PATH_E; + +#define bMaskByte0 0xff +#define bMaskByte1 0xff00 +#define bMaskByte2 0xff0000 +#define bMaskByte3 0xff000000 +#define bMaskHWord 0xffff0000 +#define bMaskLWord 0x0000ffff +#define bMaskDWord 0xffffffff + +//extern u32 rtl8192_CalculateBitShift(u32 dwBitMask); +extern u8 rtl8192_phy_CheckIsLegalRFPath(struct net_device* dev, u32 eRFPath); +extern void rtl8192_setBBreg(struct net_device* dev, u32 dwRegAddr, u32 dwBitMask, u32 dwData); +extern u32 rtl8192_QueryBBReg(struct net_device* dev, u32 dwRegAddr, u32 dwBitMask); +//extern u32 rtl8192_phy_RFSerialRead(struct net_device* dev, RF90_RADIO_PATH_E eRFPath, u32 Offset); +//extern void rtl8192_phy_RFSerialWrite(struct net_device* dev, RF90_RADIO_PATH_E eRFPath, u32 Offset, u32 Data); +extern void rtl8192_phy_SetRFReg(struct net_device* dev, RF90_RADIO_PATH_E eRFPath, u32 RegAddr, u32 BitMask, u32 Data); +extern u32 rtl8192_phy_QueryRFReg(struct net_device* dev, RF90_RADIO_PATH_E eRFPath, u32 RegAddr, u32 BitMask); +extern void rtl8192_phy_configmac(struct net_device* dev); +extern void rtl8192_phyConfigBB(struct net_device* dev, u8 ConfigType); +//extern void rtl8192_InitBBRFRegDef(struct net_device* dev); +extern u8 rtl8192_phy_checkBBAndRF(struct net_device* dev, HW90_BLOCK_E CheckBlock, RF90_RADIO_PATH_E eRFPath); +//extern void rtl8192_BB_Config_ParaFile(struct net_device* dev); +extern void rtl8192_BBConfig(struct net_device* dev); +extern void rtl8192_phy_getTxPower(struct net_device* dev); +extern void rtl8192_phy_setTxPower(struct net_device* dev, u8 channel); +extern void rtl8192_phy_RFConfig(struct net_device* dev); +extern void rtl8192_phy_updateInitGain(struct net_device* dev); +extern u8 rtl8192_phy_ConfigRFWithHeaderFile(struct net_device* dev, RF90_RADIO_PATH_E eRFPath); + +extern u8 rtl8192_phy_SwChnl(struct net_device* dev, u8 channel); +extern void rtl8192_SetBWMode(struct net_device *dev, HT_CHANNEL_WIDTH Bandwidth, HT_EXTCHNL_OFFSET Offset); +extern void rtl8192_SwChnl_WorkItem(struct net_device *dev); +void rtl8192_SetBWModeWorkItem(struct net_device *dev); +extern bool rtl8192_SetRFPowerState(struct net_device *dev, RT_RF_POWER_STATE eRFPowerState); +//added by amy +extern void InitialGain819xUsb(struct net_device *dev, u8 Operation); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) +extern void InitialGainOperateWorkItemCallBack(struct work_struct *work); +#else +extern void InitialGainOperateWorkItemCallBack(struct net_device *dev); +#endif + +#endif diff --git a/drivers/staging/rtl8192su/r819xU_phyreg.h b/drivers/staging/rtl8192su/r819xU_phyreg.h new file mode 100644 index 000000000000..b62f1a6fb1eb --- /dev/null +++ b/drivers/staging/rtl8192su/r819xU_phyreg.h @@ -0,0 +1,871 @@ +#ifndef _R819XU_PHYREG_H +#define _R819XU_PHYREG_H + + +#define RF_DATA 0x1d4 // FW will write RF data in the register. + +//Register //duplicate register due to connection: RF_Mode, TRxRN, NumOf L-STF +//page 1 +#define rPMAC_Reset 0x100 +#define rPMAC_TxStart 0x104 +#define rPMAC_TxLegacySIG 0x108 +#define rPMAC_TxHTSIG1 0x10c +#define rPMAC_TxHTSIG2 0x110 +#define rPMAC_PHYDebug 0x114 +#define rPMAC_TxPacketNum 0x118 +#define rPMAC_TxIdle 0x11c +#define rPMAC_TxMACHeader0 0x120 +#define rPMAC_TxMACHeader1 0x124 +#define rPMAC_TxMACHeader2 0x128 +#define rPMAC_TxMACHeader3 0x12c +#define rPMAC_TxMACHeader4 0x130 +#define rPMAC_TxMACHeader5 0x134 +#define rPMAC_TxDataType 0x138 +#define rPMAC_TxRandomSeed 0x13c +#define rPMAC_CCKPLCPPreamble 0x140 +#define rPMAC_CCKPLCPHeader 0x144 +#define rPMAC_CCKCRC16 0x148 +#define rPMAC_OFDMRxCRC32OK 0x170 +#define rPMAC_OFDMRxCRC32Er 0x174 +#define rPMAC_OFDMRxParityEr 0x178 +#define rPMAC_OFDMRxCRC8Er 0x17c +#define rPMAC_CCKCRxRC16Er 0x180 +#define rPMAC_CCKCRxRC32Er 0x184 +#define rPMAC_CCKCRxRC32OK 0x188 +#define rPMAC_TxStatus 0x18c + +//page8 +#define rFPGA0_RFMOD 0x800 //RF mode & CCK TxSC +#define rFPGA0_TxInfo 0x804 +#define rFPGA0_PSDFunction 0x808 +#define rFPGA0_TxGainStage 0x80c +#define rFPGA0_RFTiming1 0x810 +#define rFPGA0_RFTiming2 0x814 +//#define rFPGA0_XC_RFTiming 0x818 +//#define rFPGA0_XD_RFTiming 0x81c +#define rFPGA0_XA_HSSIParameter1 0x820 +#define rFPGA0_XA_HSSIParameter2 0x824 +#define rFPGA0_XB_HSSIParameter1 0x828 +#define rFPGA0_XB_HSSIParameter2 0x82c +#define rFPGA0_XC_HSSIParameter1 0x830 +#define rFPGA0_XC_HSSIParameter2 0x834 +#define rFPGA0_XD_HSSIParameter1 0x838 +#define rFPGA0_XD_HSSIParameter2 0x83c +#define rFPGA0_XA_LSSIParameter 0x840 +#define rFPGA0_XB_LSSIParameter 0x844 +#define rFPGA0_XC_LSSIParameter 0x848 +#define rFPGA0_XD_LSSIParameter 0x84c +#define rFPGA0_RFWakeUpParameter 0x850 +#define rFPGA0_RFSleepUpParameter 0x854 +#define rFPGA0_XAB_SwitchControl 0x858 +#define rFPGA0_XCD_SwitchControl 0x85c +#define rFPGA0_XA_RFInterfaceOE 0x860 +#define rFPGA0_XB_RFInterfaceOE 0x864 +#define rFPGA0_XC_RFInterfaceOE 0x868 +#define rFPGA0_XD_RFInterfaceOE 0x86c +#define rFPGA0_XAB_RFInterfaceSW 0x870 +#define rFPGA0_XCD_RFInterfaceSW 0x874 +#define rFPGA0_XAB_RFParameter 0x878 +#define rFPGA0_XCD_RFParameter 0x87c +#define rFPGA0_AnalogParameter1 0x880 +#define rFPGA0_AnalogParameter2 0x884 +#define rFPGA0_AnalogParameter3 0x888 +#define rFPGA0_AnalogParameter4 0x88c +#define rFPGA0_XA_LSSIReadBack 0x8a0 +#define rFPGA0_XB_LSSIReadBack 0x8a4 +#define rFPGA0_XC_LSSIReadBack 0x8a8 +#define rFPGA0_XD_LSSIReadBack 0x8ac +#define rFPGA0_PSDReport 0x8b4 +#define rFPGA0_XAB_RFInterfaceRB 0x8e0 +#define rFPGA0_XCD_RFInterfaceRB 0x8e4 + +//page 9 +#define rFPGA1_RFMOD 0x900 //RF mode & OFDM TxSC +#define rFPGA1_TxBlock 0x904 +#define rFPGA1_DebugSelect 0x908 +#define rFPGA1_TxInfo 0x90c + +//page a +#define rCCK0_System 0xa00 +#define rCCK0_AFESetting 0xa04 +#define rCCK0_CCA 0xa08 +#define rCCK0_RxAGC1 0xa0c //AGC default value, saturation level +#define rCCK0_RxAGC2 0xa10 //AGC & DAGC +#define rCCK0_RxHP 0xa14 +#define rCCK0_DSPParameter1 0xa18 //Timing recovery & Channel estimation threshold +#define rCCK0_DSPParameter2 0xa1c //SQ threshold +#define rCCK0_TxFilter1 0xa20 +#define rCCK0_TxFilter2 0xa24 +#define rCCK0_DebugPort 0xa28 //debug port and Tx filter3 +#define rCCK0_FalseAlarmReport 0xa2c //0xa2d +#define rCCK0_TRSSIReport 0xa50 +#define rCCK0_RxReport 0xa54 //0xa57 +#define rCCK0_FACounterLower 0xa5c //0xa5b +#define rCCK0_FACounterUpper 0xa58 //0xa5c + +//page c +#define rOFDM0_LSTF 0xc00 +#define rOFDM0_TRxPathEnable 0xc04 +#define rOFDM0_TRMuxPar 0xc08 +#define rOFDM0_TRSWIsolation 0xc0c +#define rOFDM0_XARxAFE 0xc10 //RxIQ DC offset, Rx digital filter, DC notch filter +#define rOFDM0_XARxIQImbalance 0xc14 //RxIQ imblance matrix +#define rOFDM0_XBRxAFE 0xc18 +#define rOFDM0_XBRxIQImbalance 0xc1c +#define rOFDM0_XCRxAFE 0xc20 +#define rOFDM0_XCRxIQImbalance 0xc24 +#define rOFDM0_XDRxAFE 0xc28 +#define rOFDM0_XDRxIQImbalance 0xc2c +#define rOFDM0_RxDetector1 0xc30 //PD,BW & SBD +#define rOFDM0_RxDetector2 0xc34 //SBD & Fame Sync. +#define rOFDM0_RxDetector3 0xc38 //Frame Sync. +#define rOFDM0_RxDetector4 0xc3c //PD, SBD, Frame Sync & Short-GI +#define rOFDM0_RxDSP 0xc40 //Rx Sync Path +#define rOFDM0_CFOandDAGC 0xc44 //CFO & DAGC +#define rOFDM0_CCADropThreshold 0xc48 //CCA Drop threshold +#define rOFDM0_ECCAThreshold 0xc4c // energy CCA +#define rOFDM0_XAAGCCore1 0xc50 +#define rOFDM0_XAAGCCore2 0xc54 +#define rOFDM0_XBAGCCore1 0xc58 +#define rOFDM0_XBAGCCore2 0xc5c +#define rOFDM0_XCAGCCore1 0xc60 +#define rOFDM0_XCAGCCore2 0xc64 +#define rOFDM0_XDAGCCore1 0xc68 +#define rOFDM0_XDAGCCore2 0xc6c +#define rOFDM0_AGCParameter1 0xc70 +#define rOFDM0_AGCParameter2 0xc74 +#define rOFDM0_AGCRSSITable 0xc78 +#define rOFDM0_HTSTFAGC 0xc7c +#define rOFDM0_XATxIQImbalance 0xc80 +#define rOFDM0_XATxAFE 0xc84 +#define rOFDM0_XBTxIQImbalance 0xc88 +#define rOFDM0_XBTxAFE 0xc8c +#define rOFDM0_XCTxIQImbalance 0xc90 +#define rOFDM0_XCTxAFE 0xc94 +#define rOFDM0_XDTxIQImbalance 0xc98 +#define rOFDM0_XDTxAFE 0xc9c +#define rOFDM0_RxHPParameter 0xce0 +#define rOFDM0_TxPseudoNoiseWgt 0xce4 +#define rOFDM0_FrameSync 0xcf0 +#define rOFDM0_DFSReport 0xcf4 +#define rOFDM0_TxCoeff1 0xca4 +#define rOFDM0_TxCoeff2 0xca8 +#define rOFDM0_TxCoeff3 0xcac +#define rOFDM0_TxCoeff4 0xcb0 +#define rOFDM0_TxCoeff5 0xcb4 +#define rOFDM0_TxCoeff6 0xcb8 + + +//page d +#define rOFDM1_LSTF 0xd00 +#define rOFDM1_TRxPathEnable 0xd04 +#define rOFDM1_CFO 0xd08 +#define rOFDM1_CSI1 0xd10 +#define rOFDM1_SBD 0xd14 +#define rOFDM1_CSI2 0xd18 +#define rOFDM1_CFOTracking 0xd2c +#define rOFDM1_TRxMesaure1 0xd34 +#define rOFDM1_IntfDet 0xd3c +#define rOFDM1_PseudoNoiseStateAB 0xd50 +#define rOFDM1_PseudoNoiseStateCD 0xd54 +#define rOFDM1_RxPseudoNoiseWgt 0xd58 +#define rOFDM_PHYCounter1 0xda0 //cca, parity fail +#define rOFDM_PHYCounter2 0xda4 //rate illegal, crc8 fail +#define rOFDM_PHYCounter3 0xda8 //MCS not support +#define rOFDM_ShortCFOAB 0xdac +#define rOFDM_ShortCFOCD 0xdb0 +#define rOFDM_LongCFOAB 0xdb4 +#define rOFDM_LongCFOCD 0xdb8 +#define rOFDM_TailCFOAB 0xdbc +#define rOFDM_TailCFOCD 0xdc0 +#define rOFDM_PWMeasure1 0xdc4 +#define rOFDM_PWMeasure2 0xdc8 +#define rOFDM_BWReport 0xdcc +#define rOFDM_AGCReport 0xdd0 +#define rOFDM_RxSNR 0xdd4 +#define rOFDM_RxEVMCSI 0xdd8 +#define rOFDM_SIGReport 0xddc + +//page e +#define rTxAGC_Rate18_06 0xe00 +#define rTxAGC_Rate54_24 0xe04 +#define rTxAGC_CCK_Mcs32 0xe08 +#define rTxAGC_Mcs03_Mcs00 0xe10 +#define rTxAGC_Mcs07_Mcs04 0xe14 +#define rTxAGC_Mcs11_Mcs08 0xe18 +#define rTxAGC_Mcs15_Mcs12 0xe1c + + +//RF +//Zebra1 +#define rZebra1_HSSIEnable 0x0 +#define rZebra1_TRxEnable1 0x1 +#define rZebra1_TRxEnable2 0x2 +#define rZebra1_AGC 0x4 +#define rZebra1_ChargePump 0x5 +#define rZebra1_Channel 0x7 +#define rZebra1_TxGain 0x8 +#define rZebra1_TxLPF 0x9 +#define rZebra1_RxLPF 0xb +#define rZebra1_RxHPFCorner 0xc + +//Zebra4 +#define rGlobalCtrl 0 +#define rRTL8256_TxLPF 19 +#define rRTL8256_RxLPF 11 + +//RTL8258 +#define rRTL8258_TxLPF 0x11 +#define rRTL8258_RxLPF 0x13 +#define rRTL8258_RSSILPF 0xa + +//Bit Mask +//page-1 +#define bBBResetB 0x100 +#define bGlobalResetB 0x200 +#define bOFDMTxStart 0x4 +#define bCCKTxStart 0x8 +#define bCRC32Debug 0x100 +#define bPMACLoopback 0x10 +#define bTxLSIG 0xffffff +#define bOFDMTxRate 0xf +#define bOFDMTxReserved 0x10 +#define bOFDMTxLength 0x1ffe0 +#define bOFDMTxParity 0x20000 +#define bTxHTSIG1 0xffffff +#define bTxHTMCSRate 0x7f +#define bTxHTBW 0x80 +#define bTxHTLength 0xffff00 +#define bTxHTSIG2 0xffffff +#define bTxHTSmoothing 0x1 +#define bTxHTSounding 0x2 +#define bTxHTReserved 0x4 +#define bTxHTAggreation 0x8 +#define bTxHTSTBC 0x30 +#define bTxHTAdvanceCoding 0x40 +#define bTxHTShortGI 0x80 +#define bTxHTNumberHT_LTF 0x300 +#define bTxHTCRC8 0x3fc00 +#define bCounterReset 0x10000 +#define bNumOfOFDMTx 0xffff +#define bNumOfCCKTx 0xffff0000 +#define bTxIdleInterval 0xffff +#define bOFDMService 0xffff0000 +#define bTxMACHeader 0xffffffff +#define bTxDataInit 0xff +#define bTxHTMode 0x100 +#define bTxDataType 0x30000 +#define bTxRandomSeed 0xffffffff +#define bCCKTxPreamble 0x1 +#define bCCKTxSFD 0xffff0000 +#define bCCKTxSIG 0xff +#define bCCKTxService 0xff00 +#define bCCKLengthExt 0x8000 +#define bCCKTxLength 0xffff0000 +#define bCCKTxCRC16 0xffff +#define bCCKTxStatus 0x1 +#define bOFDMTxStatus 0x2 + +//page-8 +#define bRFMOD 0x1 +#define bJapanMode 0x2 +#define bCCKTxSC 0x30 +#define bCCKEn 0x1000000 +#define bOFDMEn 0x2000000 +#define bOFDMRxADCPhase 0x10000 +#define bOFDMTxDACPhase 0x40000 +#define bXATxAGC 0x3f +#define bXBTxAGC 0xf00 +#define bXCTxAGC 0xf000 +#define bXDTxAGC 0xf0000 +#define bPAStart 0xf0000000 +#define bTRStart 0x00f00000 +#define bRFStart 0x0000f000 +#define bBBStart 0x000000f0 +#define bBBCCKStart 0x0000000f +#define bPAEnd 0xf //Reg0x814 +#define bTREnd 0x0f000000 +#define bRFEnd 0x000f0000 +#define bCCAMask 0x000000f0 //T2R +#define bR2RCCAMask 0x00000f00 +#define bHSSI_R2TDelay 0xf8000000 +#define bHSSI_T2RDelay 0xf80000 +#define bContTxHSSI 0x400 //chane gain at continue Tx +#define bIGFromCCK 0x200 +#define bAGCAddress 0x3f +#define bRxHPTx 0x7000 +#define bRxHPT2R 0x38000 +#define bRxHPCCKIni 0xc0000 +#define bAGCTxCode 0xc00000 +#define bAGCRxCode 0x300000 +#define b3WireDataLength 0x800 +#define b3WireAddressLength 0x400 +#define b3WireRFPowerDown 0x1 +//#define bHWSISelect 0x8 +#define b5GPAPEPolarity 0x40000000 +#define b2GPAPEPolarity 0x80000000 +#define bRFSW_TxDefaultAnt 0x3 +#define bRFSW_TxOptionAnt 0x30 +#define bRFSW_RxDefaultAnt 0x300 +#define bRFSW_RxOptionAnt 0x3000 +#define bRFSI_3WireData 0x1 +#define bRFSI_3WireClock 0x2 +#define bRFSI_3WireLoad 0x4 +#define bRFSI_3WireRW 0x8 +#define bRFSI_3Wire 0xf //3-wire total control +#define bRFSI_RFENV 0x10 +#define bRFSI_TRSW 0x20 +#define bRFSI_TRSWB 0x40 +#define bRFSI_ANTSW 0x100 +#define bRFSI_ANTSWB 0x200 +#define bRFSI_PAPE 0x400 +#define bRFSI_PAPE5G 0x800 +#define bBandSelect 0x1 +#define bHTSIG2_GI 0x80 +#define bHTSIG2_Smoothing 0x01 +#define bHTSIG2_Sounding 0x02 +#define bHTSIG2_Aggreaton 0x08 +#define bHTSIG2_STBC 0x30 +#define bHTSIG2_AdvCoding 0x40 +#define bHTSIG2_NumOfHTLTF 0x300 +#define bHTSIG2_CRC8 0x3fc +#define bHTSIG1_MCS 0x7f +#define bHTSIG1_BandWidth 0x80 +#define bHTSIG1_HTLength 0xffff +#define bLSIG_Rate 0xf +#define bLSIG_Reserved 0x10 +#define bLSIG_Length 0x1fffe +#define bLSIG_Parity 0x20 +#define bCCKRxPhase 0x4 +#define bLSSIReadAddress 0x3f000000 //LSSI "Read" Address +#define bLSSIReadEdge 0x80000000 //LSSI "Read" edge signal +#define bLSSIReadBackData 0xfff +#define bLSSIReadOKFlag 0x1000 +#define bCCKSampleRate 0x8 //0: 44MHz, 1:88MHz + +#define bRegulator0Standby 0x1 +#define bRegulatorPLLStandby 0x2 +#define bRegulator1Standby 0x4 +#define bPLLPowerUp 0x8 +#define bDPLLPowerUp 0x10 +#define bDA10PowerUp 0x20 +#define bAD7PowerUp 0x200 +#define bDA6PowerUp 0x2000 +#define bXtalPowerUp 0x4000 +#define b40MDClkPowerUP 0x8000 +#define bDA6DebugMode 0x20000 +#define bDA6Swing 0x380000 +#define bADClkPhase 0x4000000 +#define b80MClkDelay 0x18000000 +#define bAFEWatchDogEnable 0x20000000 +#define bXtalCap 0x0f000000 +#define bIntDifClkEnable 0x400 +#define bExtSigClkEnable 0x800 +#define bBandgapMbiasPowerUp 0x10000 +#define bAD11SHGain 0xc0000 +#define bAD11InputRange 0x700000 +#define bAD11OPCurrent 0x3800000 +#define bIPathLoopback 0x4000000 +#define bQPathLoopback 0x8000000 +#define bAFELoopback 0x10000000 +#define bDA10Swing 0x7e0 +#define bDA10Reverse 0x800 +#define bDAClkSource 0x1000 +#define bAD7InputRange 0x6000 +#define bAD7Gain 0x38000 +#define bAD7OutputCMMode 0x40000 +#define bAD7InputCMMode 0x380000 +#define bAD7Current 0xc00000 +#define bRegulatorAdjust 0x7000000 +#define bAD11PowerUpAtTx 0x1 +#define bDA10PSAtTx 0x10 +#define bAD11PowerUpAtRx 0x100 +#define bDA10PSAtRx 0x1000 + +#define bCCKRxAGCFormat 0x200 + +#define bPSDFFTSamplepPoint 0xc000 +#define bPSDAverageNum 0x3000 +#define bIQPathControl 0xc00 +#define bPSDFreq 0x3ff +#define bPSDAntennaPath 0x30 +#define bPSDIQSwitch 0x40 +#define bPSDRxTrigger 0x400000 +#define bPSDTxTrigger 0x80000000 +#define bPSDSineToneScale 0x7f000000 +#define bPSDReport 0xffff + +//page-9 +#define bOFDMTxSC 0x30000000 +#define bCCKTxOn 0x1 +#define bOFDMTxOn 0x2 +#define bDebugPage 0xfff //reset debug page and also HWord, LWord +#define bDebugItem 0xff //reset debug page and LWord +#define bAntL 0x10 +#define bAntNonHT 0x100 +#define bAntHT1 0x1000 +#define bAntHT2 0x10000 +#define bAntHT1S1 0x100000 +#define bAntNonHTS1 0x1000000 + +//page-a +#define bCCKBBMode 0x3 +#define bCCKTxPowerSaving 0x80 +#define bCCKRxPowerSaving 0x40 +#define bCCKSideBand 0x10 +#define bCCKScramble 0x8 +#define bCCKAntDiversity 0x8000 +#define bCCKCarrierRecovery 0x4000 +#define bCCKTxRate 0x3000 +#define bCCKDCCancel 0x0800 +#define bCCKISICancel 0x0400 +#define bCCKMatchFilter 0x0200 +#define bCCKEqualizer 0x0100 +#define bCCKPreambleDetect 0x800000 +#define bCCKFastFalseCCA 0x400000 +#define bCCKChEstStart 0x300000 +#define bCCKCCACount 0x080000 +#define bCCKcs_lim 0x070000 +#define bCCKBistMode 0x80000000 +#define bCCKCCAMask 0x40000000 +#define bCCKTxDACPhase 0x4 +#define bCCKRxADCPhase 0x20000000 //r_rx_clk +#define bCCKr_cp_mode0 0x0100 +#define bCCKTxDCOffset 0xf0 +#define bCCKRxDCOffset 0xf +#define bCCKCCAMode 0xc000 +#define bCCKFalseCS_lim 0x3f00 +#define bCCKCS_ratio 0xc00000 +#define bCCKCorgBit_sel 0x300000 +#define bCCKPD_lim 0x0f0000 +#define bCCKNewCCA 0x80000000 +#define bCCKRxHPofIG 0x8000 +#define bCCKRxIG 0x7f00 +#define bCCKLNAPolarity 0x800000 +#define bCCKRx1stGain 0x7f0000 +#define bCCKRFExtend 0x20000000 //CCK Rx Iinital gain polarity +#define bCCKRxAGCSatLevel 0x1f000000 +#define bCCKRxAGCSatCount 0xe0 +#define bCCKRxRFSettle 0x1f //AGCsamp_dly +#define bCCKFixedRxAGC 0x8000 +//#define bCCKRxAGCFormat 0x4000 //remove to HSSI register 0x824 +#define bCCKAntennaPolarity 0x2000 +#define bCCKTxFilterType 0x0c00 +#define bCCKRxAGCReportType 0x0300 +#define bCCKRxDAGCEn 0x80000000 +#define bCCKRxDAGCPeriod 0x20000000 +#define bCCKRxDAGCSatLevel 0x1f000000 +#define bCCKTimingRecovery 0x800000 +#define bCCKTxC0 0x3f0000 +#define bCCKTxC1 0x3f000000 +#define bCCKTxC2 0x3f +#define bCCKTxC3 0x3f00 +#define bCCKTxC4 0x3f0000 +#define bCCKTxC5 0x3f000000 +#define bCCKTxC6 0x3f +#define bCCKTxC7 0x3f00 +#define bCCKDebugPort 0xff0000 +#define bCCKDACDebug 0x0f000000 +#define bCCKFalseAlarmEnable 0x8000 +#define bCCKFalseAlarmRead 0x4000 +#define bCCKTRSSI 0x7f +#define bCCKRxAGCReport 0xfe +#define bCCKRxReport_AntSel 0x80000000 +#define bCCKRxReport_MFOff 0x40000000 +#define bCCKRxRxReport_SQLoss 0x20000000 +#define bCCKRxReport_Pktloss 0x10000000 +#define bCCKRxReport_Lockedbit 0x08000000 +#define bCCKRxReport_RateError 0x04000000 +#define bCCKRxReport_RxRate 0x03000000 +#define bCCKRxFACounterLower 0xff +#define bCCKRxFACounterUpper 0xff000000 +#define bCCKRxHPAGCStart 0xe000 +#define bCCKRxHPAGCFinal 0x1c00 + +#define bCCKRxFalseAlarmEnable 0x8000 +#define bCCKFACounterFreeze 0x4000 + +#define bCCKTxPathSel 0x10000000 +#define bCCKDefaultRxPath 0xc000000 +#define bCCKOptionRxPath 0x3000000 + +//page c +#define bNumOfSTF 0x3 +#define bShift_L 0xc0 +#define bGI_TH 0xc +#define bRxPathA 0x1 +#define bRxPathB 0x2 +#define bRxPathC 0x4 +#define bRxPathD 0x8 +#define bTxPathA 0x1 +#define bTxPathB 0x2 +#define bTxPathC 0x4 +#define bTxPathD 0x8 +#define bTRSSIFreq 0x200 +#define bADCBackoff 0x3000 +#define bDFIRBackoff 0xc000 +#define bTRSSILatchPhase 0x10000 +#define bRxIDCOffset 0xff +#define bRxQDCOffset 0xff00 +#define bRxDFIRMode 0x1800000 +#define bRxDCNFType 0xe000000 +#define bRXIQImb_A 0x3ff +#define bRXIQImb_B 0xfc00 +#define bRXIQImb_C 0x3f0000 +#define bRXIQImb_D 0xffc00000 +#define bDC_dc_Notch 0x60000 +#define bRxNBINotch 0x1f000000 +#define bPD_TH 0xf +#define bPD_TH_Opt2 0xc000 +#define bPWED_TH 0x700 +#define bIfMF_Win_L 0x800 +#define bPD_Option 0x1000 +#define bMF_Win_L 0xe000 +#define bBW_Search_L 0x30000 +#define bwin_enh_L 0xc0000 +#define bBW_TH 0x700000 +#define bED_TH2 0x3800000 +#define bBW_option 0x4000000 +#define bRatio_TH 0x18000000 +#define bWindow_L 0xe0000000 +#define bSBD_Option 0x1 +#define bFrame_TH 0x1c +#define bFS_Option 0x60 +#define bDC_Slope_check 0x80 +#define bFGuard_Counter_DC_L 0xe00 +#define bFrame_Weight_Short 0x7000 +#define bSub_Tune 0xe00000 +#define bFrame_DC_Length 0xe000000 +#define bSBD_start_offset 0x30000000 +#define bFrame_TH_2 0x7 +#define bFrame_GI2_TH 0x38 +#define bGI2_Sync_en 0x40 +#define bSarch_Short_Early 0x300 +#define bSarch_Short_Late 0xc00 +#define bSarch_GI2_Late 0x70000 +#define bCFOAntSum 0x1 +#define bCFOAcc 0x2 +#define bCFOStartOffset 0xc +#define bCFOLookBack 0x70 +#define bCFOSumWeight 0x80 +#define bDAGCEnable 0x10000 +#define bTXIQImb_A 0x3ff +#define bTXIQImb_B 0xfc00 +#define bTXIQImb_C 0x3f0000 +#define bTXIQImb_D 0xffc00000 +#define bTxIDCOffset 0xff +#define bTxQDCOffset 0xff00 +#define bTxDFIRMode 0x10000 +#define bTxPesudoNoiseOn 0x4000000 +#define bTxPesudoNoise_A 0xff +#define bTxPesudoNoise_B 0xff00 +#define bTxPesudoNoise_C 0xff0000 +#define bTxPesudoNoise_D 0xff000000 +#define bCCADropOption 0x20000 +#define bCCADropThres 0xfff00000 +#define bEDCCA_H 0xf +#define bEDCCA_L 0xf0 +#define bLambda_ED 0x300 +#define bRxInitialGain 0x7f +#define bRxAntDivEn 0x80 +#define bRxAGCAddressForLNA 0x7f00 +#define bRxHighPowerFlow 0x8000 +#define bRxAGCFreezeThres 0xc0000 +#define bRxFreezeStep_AGC1 0x300000 +#define bRxFreezeStep_AGC2 0xc00000 +#define bRxFreezeStep_AGC3 0x3000000 +#define bRxFreezeStep_AGC0 0xc000000 +#define bRxRssi_Cmp_En 0x10000000 +#define bRxQuickAGCEn 0x20000000 +#define bRxAGCFreezeThresMode 0x40000000 +#define bRxOverFlowCheckType 0x80000000 +#define bRxAGCShift 0x7f +#define bTRSW_Tri_Only 0x80 +#define bPowerThres 0x300 +#define bRxAGCEn 0x1 +#define bRxAGCTogetherEn 0x2 +#define bRxAGCMin 0x4 +#define bRxHP_Ini 0x7 +#define bRxHP_TRLNA 0x70 +#define bRxHP_RSSI 0x700 +#define bRxHP_BBP1 0x7000 +#define bRxHP_BBP2 0x70000 +#define bRxHP_BBP3 0x700000 +#define bRSSI_H 0x7f0000 //the threshold for high power +#define bRSSI_Gen 0x7f000000 //the threshold for ant diversity +#define bRxSettle_TRSW 0x7 +#define bRxSettle_LNA 0x38 +#define bRxSettle_RSSI 0x1c0 +#define bRxSettle_BBP 0xe00 +#define bRxSettle_RxHP 0x7000 +#define bRxSettle_AntSW_RSSI 0x38000 +#define bRxSettle_AntSW 0xc0000 +#define bRxProcessTime_DAGC 0x300000 +#define bRxSettle_HSSI 0x400000 +#define bRxProcessTime_BBPPW 0x800000 +#define bRxAntennaPowerShift 0x3000000 +#define bRSSITableSelect 0xc000000 +#define bRxHP_Final 0x7000000 +#define bRxHTSettle_BBP 0x7 +#define bRxHTSettle_HSSI 0x8 +#define bRxHTSettle_RxHP 0x70 +#define bRxHTSettle_BBPPW 0x80 +#define bRxHTSettle_Idle 0x300 +#define bRxHTSettle_Reserved 0x1c00 +#define bRxHTRxHPEn 0x8000 +#define bRxHTAGCFreezeThres 0x30000 +#define bRxHTAGCTogetherEn 0x40000 +#define bRxHTAGCMin 0x80000 +#define bRxHTAGCEn 0x100000 +#define bRxHTDAGCEn 0x200000 +#define bRxHTRxHP_BBP 0x1c00000 +#define bRxHTRxHP_Final 0xe0000000 +#define bRxPWRatioTH 0x3 +#define bRxPWRatioEn 0x4 +#define bRxMFHold 0x3800 +#define bRxPD_Delay_TH1 0x38 +#define bRxPD_Delay_TH2 0x1c0 +#define bRxPD_DC_COUNT_MAX 0x600 +//#define bRxMF_Hold 0x3800 +#define bRxPD_Delay_TH 0x8000 +#define bRxProcess_Delay 0xf0000 +#define bRxSearchrange_GI2_Early 0x700000 +#define bRxFrame_Guard_Counter_L 0x3800000 +#define bRxSGI_Guard_L 0xc000000 +#define bRxSGI_Search_L 0x30000000 +#define bRxSGI_TH 0xc0000000 +#define bDFSCnt0 0xff +#define bDFSCnt1 0xff00 +#define bDFSFlag 0xf0000 + +#define bMFWeightSum 0x300000 +#define bMinIdxTH 0x7f000000 + +#define bDAFormat 0x40000 + +#define bTxChEmuEnable 0x01000000 + +#define bTRSWIsolation_A 0x7f +#define bTRSWIsolation_B 0x7f00 +#define bTRSWIsolation_C 0x7f0000 +#define bTRSWIsolation_D 0x7f000000 + +#define bExtLNAGain 0x7c00 + +//page d +#define bSTBCEn 0x4 +#define bAntennaMapping 0x10 +#define bNss 0x20 +#define bCFOAntSumD 0x200 +#define bPHYCounterReset 0x8000000 +#define bCFOReportGet 0x4000000 +#define bOFDMContinueTx 0x10000000 +#define bOFDMSingleCarrier 0x20000000 +#define bOFDMSingleTone 0x40000000 +//#define bRxPath1 0x01 +//#define bRxPath2 0x02 +//#define bRxPath3 0x04 +//#define bRxPath4 0x08 +//#define bTxPath1 0x10 +//#define bTxPath2 0x20 +#define bHTDetect 0x100 +#define bCFOEn 0x10000 +#define bCFOValue 0xfff00000 +#define bSigTone_Re 0x3f +#define bSigTone_Im 0x7f00 +#define bCounter_CCA 0xffff +#define bCounter_ParityFail 0xffff0000 +#define bCounter_RateIllegal 0xffff +#define bCounter_CRC8Fail 0xffff0000 +#define bCounter_MCSNoSupport 0xffff +#define bCounter_FastSync 0xffff +#define bShortCFO 0xfff +#define bShortCFOTLength 12 //total +#define bShortCFOFLength 11 //fraction +#define bLongCFO 0x7ff +#define bLongCFOTLength 11 +#define bLongCFOFLength 11 +#define bTailCFO 0x1fff +#define bTailCFOTLength 13 +#define bTailCFOFLength 12 + +#define bmax_en_pwdB 0xffff +#define bCC_power_dB 0xffff0000 +#define bnoise_pwdB 0xffff +#define bPowerMeasTLength 10 +#define bPowerMeasFLength 3 +#define bRx_HT_BW 0x1 +#define bRxSC 0x6 +#define bRx_HT 0x8 + +#define bNB_intf_det_on 0x1 +#define bIntf_win_len_cfg 0x30 +#define bNB_Intf_TH_cfg 0x1c0 + +#define bRFGain 0x3f +#define bTableSel 0x40 +#define bTRSW 0x80 + +#define bRxSNR_A 0xff +#define bRxSNR_B 0xff00 +#define bRxSNR_C 0xff0000 +#define bRxSNR_D 0xff000000 +#define bSNREVMTLength 8 +#define bSNREVMFLength 1 + +#define bCSI1st 0xff +#define bCSI2nd 0xff00 +#define bRxEVM1st 0xff0000 +#define bRxEVM2nd 0xff000000 + +#define bSIGEVM 0xff +#define bPWDB 0xff00 +#define bSGIEN 0x10000 + +#define bSFactorQAM1 0xf +#define bSFactorQAM2 0xf0 +#define bSFactorQAM3 0xf00 +#define bSFactorQAM4 0xf000 +#define bSFactorQAM5 0xf0000 +#define bSFactorQAM6 0xf0000 +#define bSFactorQAM7 0xf00000 +#define bSFactorQAM8 0xf000000 +#define bSFactorQAM9 0xf0000000 +#define bCSIScheme 0x100000 + +#define bNoiseLvlTopSet 0x3 +#define bChSmooth 0x4 +#define bChSmoothCfg1 0x38 +#define bChSmoothCfg2 0x1c0 +#define bChSmoothCfg3 0xe00 +#define bChSmoothCfg4 0x7000 +#define bMRCMode 0x800000 +#define bTHEVMCfg 0x7000000 + +#define bLoopFitType 0x1 +#define bUpdCFO 0x40 +#define bUpdCFOOffData 0x80 +#define bAdvUpdCFO 0x100 +#define bAdvTimeCtrl 0x800 +#define bUpdClko 0x1000 +#define bFC 0x6000 +#define bTrackingMode 0x8000 +#define bPhCmpEnable 0x10000 +#define bUpdClkoLTF 0x20000 +#define bComChCFO 0x40000 +#define bCSIEstiMode 0x80000 +#define bAdvUpdEqz 0x100000 +#define bUChCfg 0x7000000 +#define bUpdEqz 0x8000000 + +//page e +#define bTxAGCRate18_06 0x7f7f7f7f +#define bTxAGCRate54_24 0x7f7f7f7f +#define bTxAGCRateMCS32 0x7f +#define bTxAGCRateCCK 0x7f00 +#define bTxAGCRateMCS3_MCS0 0x7f7f7f7f +#define bTxAGCRateMCS7_MCS4 0x7f7f7f7f +#define bTxAGCRateMCS11_MCS8 0x7f7f7f7f +#define bTxAGCRateMCS15_MCS12 0x7f7f7f7f + + +//Rx Pseduo noise +#define bRxPesudoNoiseOn 0x20000000 +#define bRxPesudoNoise_A 0xff +#define bRxPesudoNoise_B 0xff00 +#define bRxPesudoNoise_C 0xff0000 +#define bRxPesudoNoise_D 0xff000000 +#define bPesudoNoiseState_A 0xffff +#define bPesudoNoiseState_B 0xffff0000 +#define bPesudoNoiseState_C 0xffff +#define bPesudoNoiseState_D 0xffff0000 + +//RF +//Zebra1 +#define bZebra1_HSSIEnable 0x8 +#define bZebra1_TRxControl 0xc00 +#define bZebra1_TRxGainSetting 0x07f +#define bZebra1_RxCorner 0xc00 +#define bZebra1_TxChargePump 0x38 +#define bZebra1_RxChargePump 0x7 +#define bZebra1_ChannelNum 0xf80 +#define bZebra1_TxLPFBW 0x400 +#define bZebra1_RxLPFBW 0x600 + +//Zebra4 +#define bRTL8256RegModeCtrl1 0x100 +#define bRTL8256RegModeCtrl0 0x40 +#define bRTL8256_TxLPFBW 0x18 +#define bRTL8256_RxLPFBW 0x600 + +//RTL8258 +#define bRTL8258_TxLPFBW 0xc +#define bRTL8258_RxLPFBW 0xc00 +#define bRTL8258_RSSILPFBW 0xc0 + +//byte endable for sb_write +#define bByte0 0x1 +#define bByte1 0x2 +#define bByte2 0x4 +#define bByte3 0x8 +#define bWord0 0x3 +#define bWord1 0xc +#define bDWord 0xf + +//for PutRegsetting & GetRegSetting BitMask +#define bMaskByte0 0xff +#define bMaskByte1 0xff00 +#define bMaskByte2 0xff0000 +#define bMaskByte3 0xff000000 +#define bMaskHWord 0xffff0000 +#define bMaskLWord 0x0000ffff +#define bMaskDWord 0xffffffff + +//for PutRFRegsetting & GetRFRegSetting BitMask +#define bMask12Bits 0xfff + +#define bEnable 0x1 +#define bDisable 0x0 + +#define LeftAntenna 0x0 +#define RightAntenna 0x1 + +#define tCheckTxStatus 500 //500ms +#define tUpdateRxCounter 100 //100ms + +#define rateCCK 0 +#define rateOFDM 1 +#define rateHT 2 + +//define Register-End +#define bPMAC_End 0x1ff +#define bFPGAPHY0_End 0x8ff +#define bFPGAPHY1_End 0x9ff +#define bCCKPHY0_End 0xaff +#define bOFDMPHY0_End 0xcff +#define bOFDMPHY1_End 0xdff + +//define max debug item in each debug page +//#define bMaxItem_FPGA_PHY0 0x9 +//#define bMaxItem_FPGA_PHY1 0x3 +//#define bMaxItem_PHY_11B 0x16 +//#define bMaxItem_OFDM_PHY0 0x29 +//#define bMaxItem_OFDM_PHY1 0x0 + +#define bPMACControl 0x0 +#define bWMACControl 0x1 +#define bWNICControl 0x2 + +#define PathA 0x0 +#define PathB 0x1 +#define PathC 0x2 +#define PathD 0x3 + +#define rRTL8256RxMixerPole 0xb +#define bZebraRxMixerPole 0x6 +#define rRTL8256TxBBOPBias 0x9 +#define bRTL8256TxBBOPBias 0x400 +#define rRTL8256TxBBBW 19 +#define bRTL8256TxBBBW 0x18 + +#endif //__INC_HAL8190PCIPHYREG_H diff --git a/drivers/staging/serqt_usb/Makefile b/drivers/staging/serqt_usb/Makefile deleted file mode 100644 index 4fd1da275e8d..000000000000 --- a/drivers/staging/serqt_usb/Makefile +++ /dev/null @@ -1 +0,0 @@ -obj-$(CONFIG_USB_SERIAL_QUATECH_ESU100) += serqt_usb.o diff --git a/drivers/staging/serqt_usb/serqt_usb.c b/drivers/staging/serqt_usb/serqt_usb.c deleted file mode 100644 index 234f332fc82f..000000000000 --- a/drivers/staging/serqt_usb/serqt_usb.c +++ /dev/null @@ -1,2656 +0,0 @@ -/* - * This code was developed for the Quatech USB line for linux, it used - * much of the code developed by Greg Kroah-Hartman for USB serial devices - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Use our own dbg macro */ -/* #define DEBUG_ON */ -/* #undef dbg */ -#ifdef DEBUG_ON -#define mydbg(const...) printk(const) -#else -#define mydbg(const...) -#endif - -/* parity check flag */ -#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) - -#define SERIAL_TTY_MAJOR 0 /* Nice legal number now */ -#define SERIAL_TTY_MINORS 255 /* loads of devices :) */ -#define MAX_NUM_PORTS 8 /* The maximum number of ports one device can grab at once */ -#define PREFUFF_LEVEL_CONSERVATIVE 128 -#define ATC_DISABLED 0x00 - -#define RR_BITS 0x03 /* for clearing clock bits */ -#define DUPMODE_BITS 0xc0 - -#define RS232_MODE 0x00 -#define RTSCTS_TO_CONNECTOR 0x40 -#define CLKS_X4 0x02 - -#define LOOPMODE_BITS 0x41 /* LOOP1 = b6, LOOP0 = b0 (PORT B) */ -#define ALL_LOOPBACK 0x01 -#define MODEM_CTRL 0x40 - -#define THISCHAR data[i] -#define NEXTCHAR data[i + 1] -#define THIRDCHAR data[i + 2] -#define FOURTHCHAR data[i + 3] - -/* - * Useful defintions for port A, Port B and Port C - */ -#define FULLPWRBIT 0x00000080 -#define NEXT_BOARD_POWER_BIT 0x00000004 - -#define SERIAL_LSR_OE 0x02 -#define SERIAL_LSR_PE 0x04 -#define SERIAL_LSR_FE 0x08 -#define SERIAL_LSR_BI 0x10 - -#define SERIAL_LSR_TEMT 0x40 - -#define DIV_LATCH_LS 0x00 -#define XMT_HOLD_REGISTER 0x00 -#define XVR_BUFFER_REGISTER 0x00 -#define DIV_LATCH_MS 0x01 -#define FIFO_CONTROL_REGISTER 0x02 -#define LINE_CONTROL_REGISTER 0x03 -#define MODEM_CONTROL_REGISTER 0x04 -#define LINE_STATUS_REGISTER 0x05 -#define MODEM_STATUS_REGISTER 0x06 - -#define SERIAL_MCR_DTR 0x01 -#define SERIAL_MCR_RTS 0x02 -#define SERIAL_MCR_LOOP 0x10 - -#define SERIAL_MSR_CTS 0x10 -#define SERIAL_MSR_CD 0x80 -#define SERIAL_MSR_RI 0x40 -#define SERIAL_MSR_DSR 0x20 -#define SERIAL_MSR_MASK 0xf0 - -#define SERIAL_8_DATA 0x03 -#define SERIAL_7_DATA 0x02 -#define SERIAL_6_DATA 0x01 -#define SERIAL_5_DATA 0x00 - -#define SERIAL_ODD_PARITY 0X08 -#define SERIAL_EVEN_PARITY 0X18 -#define SERIAL_TWO_STOPB 0x04 -#define SERIAL_ONE_STOPB 0x00 - -#define MAX_BAUD_RATE 460800 -#define MAX_BAUD_REMAINDER 4608 - -#define QT_SET_GET_DEVICE 0xc2 -#define QT_OPEN_CLOSE_CHANNEL 0xca -#define QT_GET_SET_PREBUF_TRIG_LVL 0xcc -#define QT_SET_ATF 0xcd -#define QT_GET_SET_REGISTER 0xc0 -#define QT_GET_SET_UART 0xc1 -#define QT_HW_FLOW_CONTROL_MASK 0xc5 -#define QT_SW_FLOW_CONTROL_MASK 0xc6 -#define QT_SW_FLOW_CONTROL_DISABLE 0xc7 -#define QT_BREAK_CONTROL 0xc8 - -#define SERIALQT_PCI_IOC_MAGIC 'k' -#define SERIALQT_WRITE_QOPR _IOW(SERIALQT_PCI_IOC_MAGIC, 0, int) -#define SERIALQT_WRITE_QMCR _IOW(SERIALQT_PCI_IOC_MAGIC, 1, int) -#define SERIALQT_GET_NUMOF_UNITS _IOR(SERIALQT_PCI_IOC_MAGIC, 2, void *) -#define SERIALQT_GET_THIS_UNIT _IOR(SERIALQT_PCI_IOC_MAGIC, 3, void *) -#define SERIALQT_READ_QOPR _IOR(SERIALQT_PCI_IOC_MAGIC, 4, int) -#define SERIALQT_READ_QMCR _IOR(SERIALQT_PCI_IOC_MAGIC, 5, int) -#define SERIALQT_IS422_EXTENDED _IOR(SERIALQT_PCI_IOC_MAGIC, 6, int) /* returns successful if 422 extended */ - -#define USBD_TRANSFER_DIRECTION_IN 0xc0 -#define USBD_TRANSFER_DIRECTION_OUT 0x40 - -#define ATC_DISABLED 0x00 -#define ATC_RTS_ENABLED 0x02 -#define ATC_DTR_ENABLED 0x01 - -#define RR_BITS 0x03 /* for clearing clock bits */ -#define DUPMODE_BITS 0xc0 - -#define FULL_DUPLEX 0x00 -#define HALF_DUPLEX_RTS 0x40 -#define HALF_DUPLEX_DTR 0x80 - -#define QMCR_FULL_DUPLEX 0x00 -#define QMCR_HALF_DUPLEX_RTS 0x02 -#define QMCR_HALF_DUPLEX_DTR 0x01 -#define QMCR_HALF_DUPLEX_MASK 0x03 -#define QMCR_CONNECTOR_MASK 0x1C - -#define QMCR_RX_EN_MASK 0x20 - -#define QMCR_ALL_LOOPBACK 0x10 -#define QMCR_MODEM_CONTROL 0X00 - -#define SERIALQT_IOC_MAXNR 6 - -struct usb_serial_port { - struct usb_serial *serial; /* pointer back to the owner of this port */ - struct tty_struct *tty; /* the coresponding tty for this port */ - unsigned char number; - char active; /* someone has this device open */ - - unsigned char *interrupt_in_buffer; - struct urb *interrupt_in_urb; - __u8 interrupt_in_endpointAddress; - - unsigned char *bulk_in_buffer; - unsigned char *xfer_to_tty_buffer; - struct urb *read_urb; - __u8 bulk_in_endpointAddress; - - unsigned char *bulk_out_buffer; - int bulk_out_size; - struct urb *write_urb; - __u8 bulk_out_endpointAddress; - - wait_queue_head_t write_wait; - wait_queue_head_t wait; - struct work_struct work; - - int open_count; /* number of times this port has been opened */ - struct semaphore sem; /* locks this structure */ - - __u8 shadowLCR; /* last LCR value received */ - __u8 shadowMCR; /* last MCR value received */ - __u8 shadowMSR; /* last MSR value received */ - __u8 shadowLSR; /* last LSR value received */ - int RxHolding; - char closePending; - int ReadBulkStopped; - - void *private; /* data private to the specific port */ -}; - -struct identity { - int index; - int n_identity; -}; - -struct usb_serial { - struct usb_device *dev; - struct usb_interface *interface; /* the interface for this device */ - struct tty_driver *tty_driver; /* the tty_driver for this device */ - unsigned char minor; /* the starting minor number for this device */ - unsigned char num_ports; /* the number of ports this device has */ - char num_interrupt_in; /* number of interrupt in endpoints we have */ - char num_bulk_in; /* number of bulk in endpoints we have */ - char num_bulk_out; /* number of bulk out endpoints we have */ - unsigned char num_OpenCount; /* the number of ports this device has */ - - __u16 vendor; /* vendor id of this device */ - __u16 product; /* product id of this device */ - struct usb_serial_port port[MAX_NUM_PORTS]; - - void *private; /* data private to the specific driver */ -}; - -static inline int port_paranoia_check(struct usb_serial_port *port, - const char *function) -{ - if (!port) { - dbg("%s - port == NULL", function); - return -1; - } - if (!port->serial) { - dbg("%s - port->serial == NULL\n", function); - return -1; - } - if (!port->tty) { - dbg("%s - port->tty == NULL\n", function); - return -1; - } - - return 0; -} - -/* Inline functions to check the sanity of a pointer that is passed to us */ -static inline int serial_paranoia_check(struct usb_serial *serial, - const char *function) -{ - if (!serial) { - dbg("%s - serial == NULL\n", function); - return -1; - } - - return 0; -} - -static inline struct usb_serial *get_usb_serial(struct usb_serial_port *port, - const char *function) -{ - /* if no port was specified, or it fails a paranoia check */ - if (!port || - port_paranoia_check(port, function) || - serial_paranoia_check(port->serial, function)) { - /* then say that we dont have a valid usb_serial thing, which will - * end up genrating -ENODEV return values */ - return NULL; - } - - return port->serial; -} - -struct qt_get_device_data { - __u8 porta; - __u8 portb; - __u8 portc; -}; - -struct qt_open_channel_data { - __u8 line_status; - __u8 modem_status; -}; - -static void ProcessLineStatus(struct usb_serial_port *port, - unsigned char line_status); -static void ProcessModemStatus(struct usb_serial_port *port, - unsigned char modem_status); -static void ProcessRxChar(struct usb_serial_port *port, unsigned char Data); -static struct usb_serial *get_free_serial(int num_ports, int *minor); - -static int serqt_probe(struct usb_interface *interface, - const struct usb_device_id *id); - -static void serqt_usb_disconnect(struct usb_interface *interface); -static int box_set_device(struct usb_serial *serial, - struct qt_get_device_data *pDeviceData); -static int box_get_device(struct usb_serial *serial, - struct qt_get_device_data *pDeviceData); -static int serial_open(struct tty_struct *tty, struct file *filp); -static void serial_close(struct tty_struct *tty, struct file *filp); -static int serial_write_room(struct tty_struct *tty); -static int serial_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg); -static void serial_set_termios(struct tty_struct *tty, struct ktermios *old); -static int serial_write(struct tty_struct *tty, const unsigned char *buf, - int count); - -static void serial_throttle(struct tty_struct *tty); -static void serial_unthrottle(struct tty_struct *tty); -static int serial_break(struct tty_struct *tty, int break_state); -static int serial_chars_in_buffer(struct tty_struct *tty); - -static int qt_open(struct tty_struct *tty, struct usb_serial_port *port, - struct file *filp); -static int BoxSetPrebufferLevel(struct usb_serial *serial); - -static int BoxSetATC(struct usb_serial *serial, __u16 n_Mode); -static int BoxSetUart(struct usb_serial *serial, unsigned short Uart_Number, - unsigned short default_divisor, - unsigned char default_LCR); - -static int BoxOPenCloseChannel(struct usb_serial *serial, __u16 Uart_Number, - __u16 OpenClose, - struct qt_open_channel_data *pDeviceData); -static void qt_close(struct tty_struct *tty, struct usb_serial_port *port, - struct file *filp); -static int BoxGetRegister(struct usb_serial *serial, unsigned short Uart_Number, - unsigned short Register_Num, __u8 *pValue); -static int BoxSetRegister(struct usb_serial *serial, unsigned short Uart_Number, - unsigned short Register_Num, unsigned short Value); -static void qt_write_bulk_callback(struct urb *urb); -static int qt_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *buf, int count); -static void port_softint(struct work_struct *work); -static int qt_write_room(struct usb_serial_port *port); -static int qt_chars_in_buffer(struct usb_serial_port *port); -static int qt_ioctl(struct tty_struct *tty, struct usb_serial_port *port, - struct file *file, unsigned int cmd, unsigned long arg); -static void qt_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, - struct ktermios *old_termios); -static int BoxSetHW_FlowCtrl(struct usb_serial *serial, unsigned int index, - int bSet); -static int BoxDisable_SW_FlowCtrl(struct usb_serial *serial, __u16 index); -static int EmulateWriteQMCR_Reg(int index, unsigned uc_value); -static int EmulateReadQMCR_Reg(int index, unsigned *uc_value); -static struct usb_serial *find_the_box(unsigned int index); -static int ioctl_serial_usb(struct inode *innod, struct file *filp, unsigned int cmd, - unsigned long arg); - -static int BoxSetSW_FlowCtrl(struct usb_serial *serial, __u16 Uart, - unsigned char stop_char, unsigned char start_char); -static void qt_read_bulk_callback(struct urb *urb); - -static void port_sofrint(void *private); - -static void return_serial(struct usb_serial *serial); - -static int serial_tiocmset(struct tty_struct *tty, struct file *file, - unsigned int set, unsigned int clear); -static int serial_tiocmget(struct tty_struct *tty, struct file *file); - -static int qt_tiocmset(struct tty_struct *tty, struct usb_serial_port *port, - struct file *file, unsigned int value); - -static int qt_tiocmget(struct tty_struct *tty, struct usb_serial_port *port, - struct file *file); - -/* Version Information */ -#define DRIVER_VERSION "v2.14" -#define DRIVER_AUTHOR "Tim Gobeli, Quatech, Inc" -#define DRIVER_DESC "Quatech USB to Serial Driver" - -#define USB_VENDOR_ID_QUATECH 0x061d /* Quatech VID */ -#define DEVICE_ID_QUATECH_RS232_SINGLE_PORT 0xC020 /* SSU100 */ -#define DEVICE_ID_QUATECH_RS422_SINGLE_PORT 0xC030 /* SSU200 */ -#define DEVICE_ID_QUATECH_RS232_DUAL_PORT 0xC040 /* DSU100 */ -#define DEVICE_ID_QUATECH_RS422_DUAL_PORT 0xC050 /* DSU200 */ -#define DEVICE_ID_QUATECH_RS232_FOUR_PORT 0xC060 /* QSU100 */ -#define DEVICE_ID_QUATECH_RS422_FOUR_PORT 0xC070 /* QSU200 */ -#define DEVICE_ID_QUATECH_RS232_EIGHT_PORT_A 0xC080 /* ESU100A */ -#define DEVICE_ID_QUATECH_RS232_EIGHT_PORT_B 0xC081 /* ESU100B */ -#define DEVICE_ID_QUATECH_RS422_EIGHT_PORT_A 0xC0A0 /* ESU200A */ -#define DEVICE_ID_QUATECH_RS422_EIGHT_PORT_B 0xC0A1 /* ESU200B */ -#define DEVICE_ID_QUATECH_RS232_16_PORT_A 0xC090 /* HSU100A */ -#define DEVICE_ID_QUATECH_RS232_16_PORT_B 0xC091 /* HSU100B */ -#define DEVICE_ID_QUATECH_RS232_16_PORT_C 0xC092 /* HSU100C */ -#define DEVICE_ID_QUATECH_RS232_16_PORT_D 0xC093 /* HSU100D */ -#define DEVICE_ID_QUATECH_RS422_16_PORT_A 0xC0B0 /* HSU200A */ -#define DEVICE_ID_QUATECH_RS422_16_PORT_B 0xC0B1 /* HSU200B */ -#define DEVICE_ID_QUATECH_RS422_16_PORT_C 0xC0B2 /* HSU200C */ -#define DEVICE_ID_QUATECH_RS422_16_PORT_D 0xC0B3 /* HSU200D */ - -/* table of Quatech devices */ -static struct usb_device_id serqt_table[] = { - {USB_DEVICE - (USB_VENDOR_ID_QUATECH, DEVICE_ID_QUATECH_RS232_SINGLE_PORT)}, - {USB_DEVICE - (USB_VENDOR_ID_QUATECH, DEVICE_ID_QUATECH_RS422_SINGLE_PORT)}, - {USB_DEVICE(USB_VENDOR_ID_QUATECH, DEVICE_ID_QUATECH_RS232_DUAL_PORT)}, - {USB_DEVICE(USB_VENDOR_ID_QUATECH, DEVICE_ID_QUATECH_RS422_DUAL_PORT)}, - {USB_DEVICE(USB_VENDOR_ID_QUATECH, DEVICE_ID_QUATECH_RS232_FOUR_PORT)}, - {USB_DEVICE(USB_VENDOR_ID_QUATECH, DEVICE_ID_QUATECH_RS422_FOUR_PORT)}, - {USB_DEVICE - (USB_VENDOR_ID_QUATECH, DEVICE_ID_QUATECH_RS232_EIGHT_PORT_A)}, - {USB_DEVICE - (USB_VENDOR_ID_QUATECH, DEVICE_ID_QUATECH_RS232_EIGHT_PORT_B)}, - {USB_DEVICE - (USB_VENDOR_ID_QUATECH, DEVICE_ID_QUATECH_RS422_EIGHT_PORT_A)}, - {USB_DEVICE - (USB_VENDOR_ID_QUATECH, DEVICE_ID_QUATECH_RS422_EIGHT_PORT_B)}, - {USB_DEVICE(USB_VENDOR_ID_QUATECH, DEVICE_ID_QUATECH_RS232_16_PORT_A)}, - {USB_DEVICE(USB_VENDOR_ID_QUATECH, DEVICE_ID_QUATECH_RS232_16_PORT_B)}, - {USB_DEVICE(USB_VENDOR_ID_QUATECH, DEVICE_ID_QUATECH_RS232_16_PORT_C)}, - {USB_DEVICE(USB_VENDOR_ID_QUATECH, DEVICE_ID_QUATECH_RS232_16_PORT_D)}, - {USB_DEVICE(USB_VENDOR_ID_QUATECH, DEVICE_ID_QUATECH_RS422_16_PORT_A)}, - {USB_DEVICE(USB_VENDOR_ID_QUATECH, DEVICE_ID_QUATECH_RS422_16_PORT_B)}, - {USB_DEVICE(USB_VENDOR_ID_QUATECH, DEVICE_ID_QUATECH_RS422_16_PORT_C)}, - {USB_DEVICE(USB_VENDOR_ID_QUATECH, DEVICE_ID_QUATECH_RS422_16_PORT_D)}, - {} /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, serqt_table); - -static int major_number; -static struct usb_serial *serial_table[SERIAL_TTY_MINORS]; /* initially all NULL */ - -/* table of Quatech 422devices */ -static unsigned int serqt_422_table[] = { - DEVICE_ID_QUATECH_RS422_SINGLE_PORT, - DEVICE_ID_QUATECH_RS422_DUAL_PORT, - DEVICE_ID_QUATECH_RS422_FOUR_PORT, - DEVICE_ID_QUATECH_RS422_EIGHT_PORT_A, - DEVICE_ID_QUATECH_RS422_EIGHT_PORT_B, - DEVICE_ID_QUATECH_RS422_16_PORT_A, - DEVICE_ID_QUATECH_RS422_16_PORT_B, - DEVICE_ID_QUATECH_RS422_16_PORT_C, - DEVICE_ID_QUATECH_RS422_16_PORT_D, - 0 /* terminate with zero */ -}; - -/* usb specific object needed to register this driver with the usb subsystem */ -static struct usb_driver serqt_usb_driver = { - .name = "quatech-usb-serial", - .probe = serqt_probe, - .disconnect = serqt_usb_disconnect, - .id_table = serqt_table, -}; - -static struct ktermios *serial_termios[SERIAL_TTY_MINORS]; -static struct ktermios *serial_termios_locked[SERIAL_TTY_MINORS]; - -static const struct tty_operations serial_ops = { - .open = serial_open, - .close = serial_close, - .write = serial_write, - .write_room = serial_write_room, - .ioctl = serial_ioctl, - .set_termios = serial_set_termios, - .throttle = serial_throttle, - .unthrottle = serial_unthrottle, - .break_ctl = serial_break, - .chars_in_buffer = serial_chars_in_buffer, - .tiocmset = serial_tiocmset, - .tiocmget = serial_tiocmget, -}; - -static struct tty_driver serial_tty_driver = { - .magic = TTY_DRIVER_MAGIC, - .driver_name = "Quatech usb-serial", - .name = "ttyQT_USB", - .major = SERIAL_TTY_MAJOR, - .minor_start = 0, - .num = SERIAL_TTY_MINORS, - .type = TTY_DRIVER_TYPE_SERIAL, - .subtype = SERIAL_TYPE_NORMAL, - .flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV, - - .termios = serial_termios, - .termios_locked = serial_termios_locked, - .init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL, - - .init_termios.c_iflag = ICRNL | IXON, - .init_termios.c_oflag = OPOST, - - .init_termios.c_lflag = - ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | IEXTEN, -}; - -/* fops for parent device */ -static const struct file_operations serialqt_usb_fops = { - .ioctl = ioctl_serial_usb, -}; - - /** - * serqt_probe - * - * Called by the usb core when a new device is connected that it thinks - * this driver might be interested in. - * - */ -static int serqt_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - struct usb_device *dev = interface_to_usbdev(interface); - struct usb_serial *serial = NULL; - struct usb_serial_port *port; - struct usb_endpoint_descriptor *endpoint; - struct usb_endpoint_descriptor *interrupt_in_endpoint[MAX_NUM_PORTS]; - struct usb_endpoint_descriptor *bulk_in_endpoint[MAX_NUM_PORTS]; - struct usb_endpoint_descriptor *bulk_out_endpoint[MAX_NUM_PORTS]; - int minor; - int buffer_size; - int i; - struct usb_host_interface *iface_desc; - int num_interrupt_in = 0; - int num_bulk_in = 0; - int num_bulk_out = 0; - int num_ports; - struct qt_get_device_data DeviceData; - int status; - - mydbg("In %s\n", __func__); - - /* let's find the endpoints needed */ - /* check out the endpoints */ - iface_desc = interface->cur_altsetting;; - for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { - endpoint = &iface_desc->endpoint[i].desc; - - if ((endpoint->bEndpointAddress & 0x80) && - ((endpoint->bmAttributes & 3) == 0x02)) { - /* we found a bulk in endpoint */ - mydbg("found bulk in"); - bulk_in_endpoint[num_bulk_in] = endpoint; - ++num_bulk_in; - } - - if (((endpoint->bEndpointAddress & 0x80) == 0x00) && - ((endpoint->bmAttributes & 3) == 0x02)) { - /* we found a bulk out endpoint */ - mydbg("found bulk out\n"); - bulk_out_endpoint[num_bulk_out] = endpoint; - ++num_bulk_out; - } - - if ((endpoint->bEndpointAddress & 0x80) && - ((endpoint->bmAttributes & 3) == 0x03)) { - /* we found a interrupt in endpoint */ - mydbg("found interrupt in\n"); - interrupt_in_endpoint[num_interrupt_in] = endpoint; - ++num_interrupt_in; - } - } - - /* found all that we need */ - dev_info(&interface->dev, "Quatech converter detected\n"); - num_ports = num_bulk_out; - if (num_ports == 0) { - err("Quatech device with no bulk out, not allowed."); - return -ENODEV; - - } - - serial = get_free_serial(num_ports, &minor); - if (serial == NULL) { - err("No more free serial devices"); - return -ENODEV; - } - - serial->dev = dev; - serial->interface = interface; - serial->minor = minor; - serial->num_ports = num_ports; - serial->num_bulk_in = num_bulk_in; - serial->num_bulk_out = num_bulk_out; - serial->num_interrupt_in = num_interrupt_in; - serial->vendor = dev->descriptor.idVendor; - serial->product = dev->descriptor.idProduct; - - /* set up the endpoint information */ - for (i = 0; i < num_bulk_in; ++i) { - endpoint = bulk_in_endpoint[i]; - port = &serial->port[i]; - port->read_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!port->read_urb) { - err("No free urbs available"); - goto probe_error; - } - buffer_size = endpoint->wMaxPacketSize; - port->bulk_in_endpointAddress = endpoint->bEndpointAddress; - port->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL); - port->xfer_to_tty_buffer = kmalloc(buffer_size, GFP_KERNEL); - if (!port->bulk_in_buffer) { - err("Couldn't allocate bulk_in_buffer"); - goto probe_error; - } - usb_fill_bulk_urb(port->read_urb, dev, - usb_rcvbulkpipe(dev, - endpoint->bEndpointAddress), - port->bulk_in_buffer, buffer_size, - qt_read_bulk_callback, port); - } - - for (i = 0; i < num_bulk_out; ++i) { - endpoint = bulk_out_endpoint[i]; - port = &serial->port[i]; - port->write_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!port->write_urb) { - err("No free urbs available"); - goto probe_error; - } - buffer_size = endpoint->wMaxPacketSize; - port->bulk_out_size = buffer_size; - port->bulk_out_endpointAddress = endpoint->bEndpointAddress; - port->bulk_out_buffer = kmalloc(buffer_size, GFP_KERNEL); - if (!port->bulk_out_buffer) { - err("Couldn't allocate bulk_out_buffer"); - goto probe_error; - } - usb_fill_bulk_urb(port->write_urb, dev, - usb_sndbulkpipe(dev, - endpoint->bEndpointAddress), - port->bulk_out_buffer, buffer_size, - qt_write_bulk_callback, port); - - } - - /* For us numb of bulkin or out = number of ports */ - mydbg("%s - setting up %d port structures for this device\n", - __func__, num_bulk_in); - for (i = 0; i < num_bulk_in; ++i) { - port = &serial->port[i]; - port->number = i + serial->minor; - port->serial = serial; - - INIT_WORK(&port->work, port_softint); - - init_MUTEX(&port->sem); - - } - status = box_get_device(serial, &DeviceData); - if (status < 0) { - mydbg(__FILE__ "box_get_device failed"); - goto probe_error; - } - - mydbg(__FILE__ "DeviceData.portb = 0x%x", DeviceData.portb); - - DeviceData.portb &= ~FULLPWRBIT; - mydbg(__FILE__ "Changing DeviceData.portb to 0x%x", DeviceData.portb); - - status = box_set_device(serial, &DeviceData); - if (status < 0) { - mydbg(__FILE__ "box_set_device failed\n"); - goto probe_error; - } - - /* initialize the devfs nodes for this device and let the user know what ports we are bound to */ - for (i = 0; i < serial->num_ports; ++i) { - dev_info(&interface->dev, - "Converter now attached to ttyUSB%d (or usb/tts/%d for devfs)", - serial->port[i].number, serial->port[i].number); - } - - /* usb_serial_console_init (debug, minor); */ - - /***********TAG add start next board here ****/ - status = box_get_device(serial, &DeviceData); - if (status < 0) { - mydbg(__FILE__ "box_get_device failed"); - goto probe_error; - } - /* - * and before we power up lets initialiaze parnent device stuff here before - * we set thmem via any other method such as the property pages - */ - switch (serial->product) { - case DEVICE_ID_QUATECH_RS232_SINGLE_PORT: - case DEVICE_ID_QUATECH_RS232_DUAL_PORT: - case DEVICE_ID_QUATECH_RS232_FOUR_PORT: - case DEVICE_ID_QUATECH_RS232_EIGHT_PORT_A: - case DEVICE_ID_QUATECH_RS232_EIGHT_PORT_B: - case DEVICE_ID_QUATECH_RS232_16_PORT_A: - case DEVICE_ID_QUATECH_RS232_16_PORT_B: - case DEVICE_ID_QUATECH_RS232_16_PORT_C: - case DEVICE_ID_QUATECH_RS232_16_PORT_D: - DeviceData.porta &= ~(RR_BITS | DUPMODE_BITS); - DeviceData.porta |= CLKS_X4; - DeviceData.portb &= ~(LOOPMODE_BITS); - DeviceData.portb |= RS232_MODE; - break; - - case DEVICE_ID_QUATECH_RS422_SINGLE_PORT: - case DEVICE_ID_QUATECH_RS422_DUAL_PORT: - case DEVICE_ID_QUATECH_RS422_FOUR_PORT: - case DEVICE_ID_QUATECH_RS422_EIGHT_PORT_A: - case DEVICE_ID_QUATECH_RS422_EIGHT_PORT_B: - case DEVICE_ID_QUATECH_RS422_16_PORT_A: - case DEVICE_ID_QUATECH_RS422_16_PORT_B: - case DEVICE_ID_QUATECH_RS422_16_PORT_C: - case DEVICE_ID_QUATECH_RS422_16_PORT_D: - DeviceData.porta &= ~(RR_BITS | DUPMODE_BITS); - DeviceData.porta |= CLKS_X4; - DeviceData.portb &= ~(LOOPMODE_BITS); - DeviceData.portb |= ALL_LOOPBACK; - break; - default: - DeviceData.porta &= ~(RR_BITS | DUPMODE_BITS); - DeviceData.porta |= CLKS_X4; - DeviceData.portb &= ~(LOOPMODE_BITS); - DeviceData.portb |= RS232_MODE; - break; - - } - status = BoxSetPrebufferLevel(serial); /* sets to default vaue */ - if (status < 0) { - mydbg(__FILE__ "BoxSetPrebufferLevel failed\n"); - goto probe_error; - } - - status = BoxSetATC(serial, ATC_DISABLED); - if (status < 0) { - mydbg(__FILE__ "BoxSetATC failed\n"); - goto probe_error; - } - /**********************************************************/ - mydbg(__FILE__ "DeviceData.portb = 0x%x", DeviceData.portb); - - DeviceData.portb |= NEXT_BOARD_POWER_BIT; - mydbg(__FILE__ "Changing DeviceData.portb to 0x%x", DeviceData.portb); - - status = box_set_device(serial, &DeviceData); - if (status < 0) { - mydbg(__FILE__ "box_set_device failed\n"); - goto probe_error; - } - - mydbg("Exit Success %s\n", __func__); - - usb_set_intfdata(interface, serial); - return 0; - -probe_error: - - for (i = 0; i < num_bulk_in; ++i) { - port = &serial->port[i]; - usb_free_urb(port->read_urb); - kfree(port->bulk_in_buffer); - } - for (i = 0; i < num_bulk_out; ++i) { - port = &serial->port[i]; - usb_free_urb(port->write_urb); - kfree(port->bulk_out_buffer); - kfree(port->xfer_to_tty_buffer); - } - for (i = 0; i < num_interrupt_in; ++i) { - port = &serial->port[i]; - usb_free_urb(port->interrupt_in_urb); - kfree(port->interrupt_in_buffer); - } - - /* return the minor range that this device had */ - return_serial(serial); - mydbg("Exit fail %s\n", __func__); - - /* free up any memory that we allocated */ - kfree(serial); - return -EIO; -} - -/* - * returns the serial_table array pointers that are taken - * up in consecutive positions for each port to a common usb_serial structure - * back to NULL - */ -static void return_serial(struct usb_serial *serial) -{ - int i; - - mydbg("%s\n", __func__); - - if (serial == NULL) - return; - - for (i = 0; i < serial->num_ports; ++i) - serial_table[serial->minor + i] = NULL; - - return; -} - -/* - * Finds the first locatio int the serial_table array where it can fit - * num_ports number of consecutive points to a common usb_serial - * structure,allocates a stucture points to it in all the structures, and - * returns the index to the first location in the array in the "minor" - * variable. - */ -static struct usb_serial *get_free_serial(int num_ports, int *minor) -{ - struct usb_serial *serial = NULL; - int i, j; - int good_spot; - - mydbg("%s %d\n", __func__, num_ports); - - *minor = 0; - for (i = 0; i < SERIAL_TTY_MINORS; ++i) { - if (serial_table[i]) - continue; - - good_spot = 1; - /* - * find a spot in the array where you can fit consecutive - * positions to put the pointers to the usb_serail allocated - * structure for all the minor numbers (ie. ports) - */ - for (j = 1; j <= num_ports - 1; ++j) - if (serial_table[i + j]) - good_spot = 0; - if (good_spot == 0) - continue; - - serial = kmalloc(sizeof(struct usb_serial), GFP_KERNEL); - if (!serial) { - err("%s - Out of memory", __func__); - return NULL; - } - memset(serial, 0, sizeof(struct usb_serial)); - serial_table[i] = serial; - *minor = i; - mydbg("%s - minor base = %d\n", __func__, *minor); - - /* - * copy in the pointer into the array starting a the *minor - * position minor is the index into the array. - */ - for (i = *minor + 1; - (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i) - serial_table[i] = serial; - return serial; - } - return NULL; -} - -static int flip_that(struct tty_struct *tty, __u16 index, - struct usb_serial *serial) -{ - tty_flip_buffer_push(tty); - tty_schedule_flip(tty); - return 0; -} - -/* Handles processing and moving data to the tty layer */ -static void port_sofrint(void *private) -{ - struct usb_serial_port *port = private; - struct usb_serial *serial = get_usb_serial(port, __func__); - struct tty_struct *tty = port->tty; - unsigned char *data = port->read_urb->transfer_buffer; - unsigned int index; - struct urb *urb = port->read_urb; - unsigned int RxCount = urb->actual_length; - int i, result; - int flag, flag_data; - - /* index = MINOR(port->tty->device) - serial->minor; */ - index = tty->index - serial->minor; - - mydbg("%s - port %d\n", __func__, port->number); - mydbg("%s - port->RxHolding = %d\n", __func__, port->RxHolding); - - if (port_paranoia_check(port, __func__) != 0) { - mydbg("%s - port_paranoia_check, exiting\n", __func__); - port->ReadBulkStopped = 1; - return; - } - - if (!serial) { - mydbg("%s - bad serial pointer, exiting\n", __func__); - return; - } - if (port->closePending == 1) { - /* Were closing , stop reading */ - mydbg("%s - (port->closepending == 1\n", __func__); - port->ReadBulkStopped = 1; - return; - } - - /* - * RxHolding is asserted by throttle, if we assert it, we're not - * receiving any more characters and let the box handle the flow - * control - */ - if (port->RxHolding == 1) { - port->ReadBulkStopped = 1; - return; - } - - if (urb->status) { - port->ReadBulkStopped = 1; - - mydbg("%s - nonzero read bulk status received: %d\n", - __func__, urb->status); - return; - } - - tty = port->tty; - mydbg("%s - port %d, tty =0x%p\n", __func__, port->number, tty); - - if (tty && RxCount) { - flag_data = 0; - for (i = 0; i < RxCount; ++i) { - /* Look ahead code here */ - if ((i <= (RxCount - 3)) && (THISCHAR == 0x1b) - && (NEXTCHAR == 0x1b)) { - flag = 0; - switch (THIRDCHAR) { - case 0x00: - /* Line status change 4th byte must follow */ - if (i > (RxCount - 4)) { - mydbg("Illegal escape sequences in received data\n"); - break; - } - ProcessLineStatus(port, FOURTHCHAR); - i += 3; - flag = 1; - break; - - case 0x01: - /* Modem status status change 4th byte must follow */ - mydbg("Modem status status. \n"); - if (i > (RxCount - 4)) { - mydbg - ("Illegal escape sequences in received data\n"); - break; - } - ProcessModemStatus(port, FOURTHCHAR); - i += 3; - flag = 1; - break; - case 0xff: - mydbg("No status sequence. \n"); - - ProcessRxChar(port, THISCHAR); - ProcessRxChar(port, NEXTCHAR); - i += 2; - break; - } - if (flag == 1) - continue; - } - - if (tty && urb->actual_length) { - tty_buffer_request_room(tty, 1); - tty_insert_flip_string(tty, (data + i), 1); - } - - } - tty_flip_buffer_push(tty); - } - - /* Continue trying to always read */ - usb_fill_bulk_urb(port->read_urb, serial->dev, - usb_rcvbulkpipe(serial->dev, - port->bulk_in_endpointAddress), - port->read_urb->transfer_buffer, - port->read_urb->transfer_buffer_length, - qt_read_bulk_callback, port); - result = usb_submit_urb(port->read_urb, GFP_ATOMIC); - if (result) - mydbg("%s - failed resubmitting read urb, error %d", - __func__, result); - else { - if (tty && RxCount) - flip_that(tty, index, serial); - } - - return; - -} - -static void qt_read_bulk_callback(struct urb *urb) -{ - - struct usb_serial_port *port = (struct usb_serial_port *)urb->context; - - if (urb->status) { - port->ReadBulkStopped = 1; - mydbg("%s - nonzero write bulk status received: %d\n", - __func__, urb->status); - return; - } - - port_sofrint((void *)port); - schedule_work(&port->work); -} - -static void ProcessRxChar(struct usb_serial_port *port, unsigned char Data) -{ - struct tty_struct *tty; - struct urb *urb = port->read_urb; - tty = port->tty; - /* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them. */ - - if (tty && urb->actual_length) { - tty_buffer_request_room(tty, 1); - tty_insert_flip_string(tty, &Data, 1); - /* tty_flip_buffer_push(tty); */ - } - - return; -} - -static void ProcessLineStatus(struct usb_serial_port *port, - unsigned char line_status) -{ - - port->shadowLSR = - line_status & (SERIAL_LSR_OE | SERIAL_LSR_PE | SERIAL_LSR_FE | - SERIAL_LSR_BI); - return; -} - -static void ProcessModemStatus(struct usb_serial_port *port, - unsigned char modem_status) -{ - - port->shadowMSR = modem_status; - wake_up_interruptible(&port->wait); - return; -} - -static void serqt_usb_disconnect(struct usb_interface *interface) -{ - struct usb_serial *serial = usb_get_intfdata(interface); - /* struct device *dev = &interface->dev; */ - struct usb_serial_port *port; - int i; - - mydbg("%s\n", __func__); - if (serial) { - - serial->dev = NULL; - - for (i = 0; i < serial->num_ports; ++i) - serial->port[i].open_count = 0; - - for (i = 0; i < serial->num_bulk_in; ++i) { - port = &serial->port[i]; - usb_unlink_urb(port->read_urb); - usb_free_urb(port->read_urb); - kfree(port->bulk_in_buffer); - } - for (i = 0; i < serial->num_bulk_out; ++i) { - port = &serial->port[i]; - usb_unlink_urb(port->write_urb); - usb_free_urb(port->write_urb); - kfree(port->bulk_out_buffer); - } - for (i = 0; i < serial->num_interrupt_in; ++i) { - port = &serial->port[i]; - usb_unlink_urb(port->interrupt_in_urb); - usb_free_urb(port->interrupt_in_urb); - kfree(port->interrupt_in_buffer); - } - - /* return the minor range that this device had */ - return_serial(serial); - - /* free up any memory that we allocated */ - kfree(serial); - - } else { - dev_info(&interface->dev, "device disconnected"); - } - -} - -static struct usb_serial *get_serial_by_minor(unsigned int minor) -{ - return serial_table[minor]; -} - -/***************************************************************************** - * Driver tty interface functions - *****************************************************************************/ -static int serial_open(struct tty_struct *tty, struct file *filp) -{ - struct usb_serial *serial; - struct usb_serial_port *port; - unsigned int portNumber; - int retval = 0; - - mydbg("%s\n", __func__); - - /* initialize the pointer incase something fails */ - tty->driver_data = NULL; - - /* get the serial object associated with this tty pointer */ - /* serial = get_serial_by_minor (MINOR(tty->device)); */ - - /* get the serial object associated with this tty pointer */ - serial = get_serial_by_minor(tty->index); - - if (serial_paranoia_check(serial, __func__)) - return -ENODEV; - - /* set up our port structure making the tty driver remember our port object, and us it */ - portNumber = tty->index - serial->minor; - port = &serial->port[portNumber]; - tty->driver_data = port; - - down(&port->sem); - port->tty = tty; - - ++port->open_count; - if (port->open_count == 1) { - port->closePending = 0; - mydbg("%s port->closepending = 0\n", __func__); - - port->RxHolding = 0; - mydbg("%s port->RxHolding = 0\n", __func__); - - retval = qt_open(tty, port, filp); - } - - if (retval) - port->open_count = 0; - mydbg("%s returning port->closePending = %d\n", __func__, - port->closePending); - - up(&port->sem); - return retval; -} - -/***************************************************************************** - *device's specific driver functions - *****************************************************************************/ -static int qt_open(struct tty_struct *tty, struct usb_serial_port *port, - struct file *filp) -{ - struct usb_serial *serial = port->serial; - int result = 0; - unsigned int index; - struct qt_get_device_data DeviceData; - struct qt_open_channel_data ChannelData; - unsigned short default_divisor = 0x30; /* gives 9600 baud rate */ - unsigned char default_LCR = SERIAL_8_DATA; /* 8, none , 1 */ - int status = 0; - - if (port_paranoia_check(port, __func__)) - return -ENODEV; - - mydbg("%s - port %d\n", __func__, port->number); - - index = tty->index - serial->minor; - - status = box_get_device(serial, &DeviceData); - if (status < 0) { - mydbg(__FILE__ "box_get_device failed\n"); - return status; - } - serial->num_OpenCount++; - mydbg("%s serial->num_OpenCount = %d\n", __func__, - serial->num_OpenCount); - /* Open uart channel */ - - /* Port specific setups */ - status = BoxOPenCloseChannel(serial, index, 1, &ChannelData); - if (status < 0) { - mydbg(__FILE__ "BoxOPenCloseChannel failed\n"); - return status; - } - mydbg(__FILE__ "BoxOPenCloseChannel completed.\n"); - - port->shadowLSR = ChannelData.line_status & - (SERIAL_LSR_OE | SERIAL_LSR_PE | SERIAL_LSR_FE | SERIAL_LSR_BI); - - port->shadowMSR = ChannelData.modem_status & - (SERIAL_MSR_CTS | SERIAL_MSR_DSR | SERIAL_MSR_RI | SERIAL_MSR_CD); - - /* Set Baud rate to default and turn off (default)flow control here */ - status = BoxSetUart(serial, index, default_divisor, default_LCR); - if (status < 0) { - mydbg(__FILE__ "BoxSetUart failed\n"); - return status; - } - mydbg(__FILE__ "BoxSetUart completed.\n"); - - /* Put this here to make it responsive to stty and defauls set by the tty layer */ - qt_set_termios(tty, port, NULL); - - /* Initialize the wait que head */ - init_waitqueue_head(&(port->wait)); - - /* if we have a bulk endpoint, start reading from it */ - if (serial->num_bulk_in) { - /* Start reading from the device */ - usb_fill_bulk_urb(port->read_urb, serial->dev, - usb_rcvbulkpipe(serial->dev, - port-> - bulk_in_endpointAddress), - port->read_urb->transfer_buffer, - port->read_urb->transfer_buffer_length, - qt_read_bulk_callback, port); - - port->ReadBulkStopped = 0; - - result = usb_submit_urb(port->read_urb, GFP_ATOMIC); - - if (result) { - err("%s - failed resubmitting read urb, error %d\n", - __func__, result); - port->ReadBulkStopped = 1; - } - - } - - return result; -} - -static void serial_close(struct tty_struct *tty, struct file *filp) -{ - struct usb_serial_port *port = - tty->driver_data; - struct usb_serial *serial = get_usb_serial(port, __func__); - - if (!serial) - return; - - down(&port->sem); - - mydbg("%s - port %d\n", __func__, port->number); - - /* if disconnect beat us to the punch here, there's nothing to do */ - if (tty->driver_data) { - if (!port->open_count) { - mydbg("%s - port not opened\n", __func__); - goto exit; - } - - --port->open_count; - if (port->open_count <= 0) { - port->closePending = 1; - mydbg("%s - port->closePending = 1\n", __func__); - - if (serial->dev) { - qt_close(tty, port, filp); - port->open_count = 0; - } - } - - } - -exit: - up(&port->sem); - - mydbg("%s - %d return\n", __func__, port->number); - -} - -static void qt_close(struct tty_struct *tty, struct usb_serial_port *port, - struct file *filp) -{ - unsigned long jift = jiffies + 10 * HZ; - u8 lsr, mcr; - struct usb_serial *serial = port->serial; - int status; - unsigned int index; - - struct qt_open_channel_data ChannelData; - status = 0; - lsr = 0; - - mydbg("%s - port %d\n", __func__, port->number); - index = tty->index - serial->minor; - - /* shutdown any bulk reads that might be going on */ - if (serial->num_bulk_out) - usb_unlink_urb(port->write_urb); - if (serial->num_bulk_in) - usb_unlink_urb(port->read_urb); - - /* wait up to 30 seconds for transmitter to empty */ - do { - status = BoxGetRegister(serial, index, LINE_STATUS_REGISTER, &lsr); - if (status < 0) { - mydbg(__FILE__ "box_get_device failed\n"); - break; - } - - if ((lsr & SERIAL_LSR_TEMT) - && (port->ReadBulkStopped == 1)) - break; - schedule(); - - } - while (jiffies <= jift); - - if (jiffies > jift) - mydbg("%s - port %d timout of checking transmitter empty\n", - __func__, port->number); - else - mydbg("%s - port %d checking transmitter empty succeded\n", - __func__, port->number); - - status = - BoxGetRegister(serial, index, MODEM_CONTROL_REGISTER, - &mcr); - mydbg(__FILE__ "BoxGetRegister MCR = 0x%x.\n", mcr); - - if (status >= 0) { - mcr &= ~(SERIAL_MCR_DTR | SERIAL_MCR_RTS); - /* status = BoxSetRegister(serial, index, MODEM_CONTROL_REGISTER, mcr); */ - } - - /* Close uart channel */ - status = BoxOPenCloseChannel(serial, index, 0, &ChannelData); - if (status < 0) - mydbg("%s - port %d BoxOPenCloseChannel failed.\n", - __func__, port->number); - - serial->num_OpenCount--; - -} - -static int serial_write(struct tty_struct *tty, const unsigned char *buf, - int count) -{ - struct usb_serial_port *port = tty->driver_data; - struct usb_serial *serial; - int retval = -EINVAL; - unsigned int index; - - serial = get_usb_serial(port, __func__); - if (serial == NULL) - return -ENODEV; - /* This can happen if we get disconnected a */ - if (port->open_count == 0) - return -ENODEV; - index = tty->index - serial->minor; - - mydbg("%s - port %d, %d byte(s)\n", __func__, port->number, count); - mydbg("%s - port->RxHolding = %d\n", __func__, port->RxHolding); - - if (!port->open_count) { - mydbg("%s - port not opened\n", __func__); - goto exit; - } - - retval = qt_write(tty, port, buf, count); - -exit: - return retval; -} - -static int qt_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *buf, int count) -{ - int result; - unsigned int index; - struct usb_serial *serial = get_usb_serial(port, __func__); - - if (serial == NULL) - return -ENODEV; - - mydbg("%s - port %d\n", __func__, port->number); - - if (count == 0) { - mydbg("%s - write request of 0 bytes\n", __func__); - return 0; - } - - index = tty->index - serial->minor; - /* only do something if we have a bulk out endpoint */ - if (serial->num_bulk_out) { - if (port->write_urb->status == -EINPROGRESS) { - mydbg("%s - already writing\n", __func__); - return 0; - } - - count = - (count > port->bulk_out_size) ? port->bulk_out_size : count; - memcpy(port->write_urb->transfer_buffer, buf, count); - - /* usb_serial_debug_data(__FILE__, __func__, count, port->write_urb->transfer_buffer); */ - - /* set up our urb */ - - usb_fill_bulk_urb(port->write_urb, serial->dev, - usb_sndbulkpipe(serial->dev, - port-> - bulk_out_endpointAddress), - port->write_urb->transfer_buffer, count, - qt_write_bulk_callback, port); - - /* send the data out the bulk port */ - result = usb_submit_urb(port->write_urb, GFP_ATOMIC); - if (result) - mydbg("%s - failed submitting write urb, error %d\n", - __func__, result); - else - result = count; - - return result; - } - - /* no bulk out, so return 0 bytes written */ - return 0; -} - -static void qt_write_bulk_callback(struct urb *urb) -{ - struct usb_serial_port *port = (struct usb_serial_port *)urb->context; - struct usb_serial *serial = get_usb_serial(port, __func__); - - mydbg("%s - port %d\n", __func__, port->number); - - if (!serial) { - mydbg("%s - bad serial pointer, exiting\n", __func__); - return; - } - - if (urb->status) { - mydbg("%s - nonzero write bulk status received: %d\n", - __func__, urb->status); - return; - } - port_softint(&port->work); - schedule_work(&port->work); - - return; -} - -static void port_softint(struct work_struct *work) -{ - struct usb_serial_port *port = - container_of(work, struct usb_serial_port, work); - struct usb_serial *serial = get_usb_serial(port, __func__); - struct tty_struct *tty; - - mydbg("%s - port %d\n", __func__, port->number); - - if (!serial) - return; - - tty = port->tty; - if (!tty) - return; -#if 0 - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) - && tty->ldisc.write_wakeup) { - mydbg("%s - write wakeup call.\n", __func__); - (tty->ldisc.write_wakeup) (tty); - } -#endif - - wake_up_interruptible(&tty->write_wait); -} -static int serial_write_room(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct usb_serial *serial = get_usb_serial(port, __func__); - int retval = -EINVAL; - - if (!serial) - return -ENODEV; - - down(&port->sem); - - mydbg("%s - port %d\n", __func__, port->number); - - if (!port->open_count) { - mydbg("%s - port not open\n", __func__); - goto exit; - } - - retval = qt_write_room(port); - -exit: - up(&port->sem); - return retval; -} -static int qt_write_room(struct usb_serial_port *port) -{ - struct usb_serial *serial = port->serial; - int room = 0; - if (port->closePending == 1) { - mydbg("%s - port->closePending == 1\n", __func__); - return -ENODEV; - } - - mydbg("%s - port %d\n", __func__, port->number); - - if (serial->num_bulk_out) { - if (port->write_urb->status != -EINPROGRESS) - room = port->bulk_out_size; - } - - mydbg("%s - returns %d\n", __func__, room); - return room; -} -static int serial_chars_in_buffer(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct usb_serial *serial = get_usb_serial(port, __func__); - int retval = -EINVAL; - - if (!serial) - return -ENODEV; - - down(&port->sem); - - mydbg("%s = port %d\n", __func__, port->number); - - if (!port->open_count) { - mydbg("%s - port not open\n", __func__); - goto exit; - } - - retval = qt_chars_in_buffer(port); - -exit: - up(&port->sem); - return retval; -} - -static int qt_chars_in_buffer(struct usb_serial_port *port) -{ - struct usb_serial *serial = port->serial; - int chars = 0; - - mydbg("%s - port %d\n", __func__, port->number); - - if (serial->num_bulk_out) { - if (port->write_urb->status == -EINPROGRESS) - chars = port->write_urb->transfer_buffer_length; - } - - mydbg("%s - returns %d\n", __func__, chars); - return chars; -} - -static int serial_tiocmset(struct tty_struct *tty, struct file *file, - unsigned int set, unsigned int clear) -{ - - struct usb_serial_port *port = tty->driver_data; - struct usb_serial *serial = get_usb_serial(port, __func__); - int retval = -ENODEV; - unsigned int index; - mydbg("In %s \n", __func__); - - if (!serial) - return -ENODEV; - - index = tty->index - serial->minor; - - down(&port->sem); - - mydbg("%s - port %d \n", __func__, port->number); - mydbg("%s - port->RxHolding = %d\n", __func__, port->RxHolding); - - if (!port->open_count) { - mydbg("%s - port not open\n", __func__); - goto exit; - } - - retval = qt_tiocmset(tty, port, file, set); - -exit: - up(&port->sem); - return retval; -} - -static int qt_tiocmset(struct tty_struct *tty, struct usb_serial_port *port, - struct file *file, unsigned int value) -{ - - u8 mcr; - int status; - unsigned int index; - struct usb_serial *serial = get_usb_serial(port, __func__); - - if (serial == NULL) - return -ENODEV; - - mydbg("%s - port %d\n", __func__, port->number); - - /**************************************************************************************/ - /** TIOCMGET - */ - index = tty->index - serial->minor; - status = - BoxGetRegister(port->serial, index, MODEM_CONTROL_REGISTER, - &mcr); - if (status < 0) - return -ESPIPE; - - /* - * Turn off the RTS and DTR and loopbcck and then only turn on what was - * asked for - */ - mcr &= ~(SERIAL_MCR_RTS | SERIAL_MCR_DTR | SERIAL_MCR_LOOP); - if (value & TIOCM_RTS) - mcr |= SERIAL_MCR_RTS; - if (value & TIOCM_DTR) - mcr |= SERIAL_MCR_DTR; - if (value & TIOCM_LOOP) - mcr |= SERIAL_MCR_LOOP; - - status = - BoxSetRegister(port->serial, index, MODEM_CONTROL_REGISTER, - mcr); - if (status < 0) - return -ESPIPE; - else - return 0; -} - -static int serial_tiocmget(struct tty_struct *tty, struct file *file) -{ - - struct usb_serial_port *port = tty->driver_data; - struct usb_serial *serial = get_usb_serial(port, __func__); - int retval = -ENODEV; - unsigned int index; - mydbg("In %s \n", __func__); - - if (!serial) - return -ENODEV; - - index = tty->index - serial->minor; - - down(&port->sem); - - mydbg("%s - port %d\n", __func__, port->number); - mydbg("%s - port->RxHolding = %d\n", __func__, port->RxHolding); - - if (!port->open_count) { - mydbg("%s - port not open\n", __func__); - goto exit; - } - - retval = qt_tiocmget(tty, port, file); - -exit: - up(&port->sem); - return retval; -} - -static int qt_tiocmget(struct tty_struct *tty, - struct usb_serial_port *port, struct file *file) -{ - - u8 mcr; - u8 msr; - unsigned int result = 0; - int status; - unsigned int index; - - struct usb_serial *serial = get_usb_serial(port, __func__); - if (serial == NULL) - return -ENODEV; - - mydbg("%s - port %d, tty =0x%p\n", __func__, port->number, tty); - - /**************************************************************************************/ - /** TIOCMGET - */ - index = tty->index - serial->minor; - status = - BoxGetRegister(port->serial, index, MODEM_CONTROL_REGISTER, - &mcr); - if (status >= 0) { - status = - BoxGetRegister(port->serial, index, - MODEM_STATUS_REGISTER, &msr); - - } - - if (status >= 0) { - result = ((mcr & SERIAL_MCR_DTR) ? TIOCM_DTR : 0) - /* DTR IS SET */ - | ((mcr & SERIAL_MCR_RTS) ? TIOCM_RTS : 0) - /* RTS IS SET */ - | ((msr & SERIAL_MSR_CTS) ? TIOCM_CTS : 0) - /* CTS is set */ - | ((msr & SERIAL_MSR_CD) ? TIOCM_CAR : 0) - /* Carrier detect is set */ - | ((msr & SERIAL_MSR_RI) ? TIOCM_RI : 0) - /* Ring indicator set */ - | ((msr & SERIAL_MSR_DSR) ? TIOCM_DSR : 0); - /* DSR is set */ - return result; - - } else - return -ESPIPE; -} - -static int serial_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) -{ - - struct usb_serial_port *port = tty->driver_data; - struct usb_serial *serial = get_usb_serial(port, __func__); - int retval = -ENODEV; - unsigned int index; - mydbg("In %s \n", __func__); - - if (!serial) - return -ENODEV; - - index = tty->index - serial->minor; - - down(&port->sem); - - mydbg("%s - port %d, cmd 0x%.4x\n", __func__, port->number, cmd); - mydbg("%s - port->RxHolding = %d\n", __func__, port->RxHolding); - - if (!port->open_count) { - mydbg("%s - port not open\n", __func__); - goto exit; - } - - retval = qt_ioctl(tty, port, file, cmd, arg); - -exit: - up(&port->sem); - return retval; -} -static int qt_ioctl(struct tty_struct *tty, struct usb_serial_port *port, - struct file *file, unsigned int cmd, unsigned long arg) -{ - __u8 mcr; - __u8 msr; - unsigned short prev_msr; - unsigned int value, result = 0; - int status; - unsigned int index; - - struct usb_serial *serial = get_usb_serial(port, __func__); - if (serial == NULL) - return -ENODEV; - - mydbg("%s - port %d, tty =0x%p\n", __func__, port->number, tty); - - /* TIOCMGET */ - index = tty->index - serial->minor; - - if (cmd == TIOCMIWAIT) { - DECLARE_WAITQUEUE(wait, current); - prev_msr = port->shadowMSR & SERIAL_MSR_MASK; - while (1) { - add_wait_queue(&port->wait, &wait); - set_current_state(TASK_INTERRUPTIBLE); - schedule(); - remove_wait_queue(&port->wait, &wait); - /* see if a signal woke us up */ - if (signal_pending(current)) - return -ERESTARTSYS; - msr = port->shadowMSR & SERIAL_MSR_MASK; - if (msr == prev_msr) - return -EIO; /* no change error */ - - if ((arg & TIOCM_RNG - && ((prev_msr & SERIAL_MSR_RI) == - (msr & SERIAL_MSR_RI))) - || (arg & TIOCM_DSR - && ((prev_msr & SERIAL_MSR_DSR) == - (msr & SERIAL_MSR_DSR))) - || (arg & TIOCM_CD - && ((prev_msr & SERIAL_MSR_CD) == - (msr & SERIAL_MSR_CD))) - || (arg & TIOCM_CTS - && ((prev_msr & SERIAL_MSR_CTS) == - (msr & SERIAL_MSR_CTS)))) { - return 0; - } - - } - - } - mydbg("%s -No ioctl for that one. port = %d\n", __func__, - port->number); - - return -ENOIOCTLCMD; -} - -static void serial_set_termios(struct tty_struct *tty, struct ktermios *old) -{ - struct usb_serial_port *port = - tty->driver_data; - struct usb_serial *serial = get_usb_serial(port, __func__); - - if (!serial) - return; - - down(&port->sem); - - mydbg("%s - port %d\n", __func__, port->number); - - if (!port->open_count) { - mydbg("%s - port not open\n", __func__); - goto exit; - } - - /* pass on to the driver specific version of this function if it is available */ - qt_set_termios(tty, port, old); - -exit: - up(&port->sem); -} - -static void qt_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, - struct ktermios *old_termios) -{ - unsigned int cflag; - int baud, divisor, remainder; - unsigned char new_LCR = 0; - int status; - struct usb_serial *serial; - __u16 index; - __u16 tmp, tmp2; - - mydbg("%s - port %d\n", __func__, port->number); - - tmp = port->tty->index; - mydbg("%s - MINOR(port->tty->index) = %d\n", __func__, tmp); - - serial = port->serial; - tmp2 = serial->minor; - mydbg("%s - serial->minor = %d\n", __func__, tmp2); - - index = port->tty->index - serial->minor; - - cflag = tty->termios->c_cflag; - - mydbg("%s - 3\n", __func__); - - switch (cflag) { - case CS5: - new_LCR |= SERIAL_5_DATA; - break; - case CS6: - new_LCR |= SERIAL_6_DATA; - break; - case CS7: - new_LCR |= SERIAL_7_DATA; - break; - default: - case CS8: - new_LCR |= SERIAL_8_DATA; - break; - } - - /* Parity stuff */ - if (cflag & PARENB) { - if (cflag & PARODD) - new_LCR |= SERIAL_ODD_PARITY; - else - new_LCR |= SERIAL_EVEN_PARITY; - } - if (cflag & CSTOPB) - new_LCR |= SERIAL_TWO_STOPB; - else - new_LCR |= SERIAL_TWO_STOPB; - - mydbg("%s - 4\n", __func__); - /* Thats the LCR stuff, go ahead and set it */ - baud = tty_get_baud_rate(tty); - if (!baud) - /* pick a default, any default... */ - baud = 9600; - - mydbg("%s - got baud = %d\n", __func__, baud); - - divisor = MAX_BAUD_RATE / baud; - remainder = MAX_BAUD_RATE % baud; - /* Round to nearest divisor */ - if (((remainder * 2) >= baud) && (baud != 110)) - divisor++; - - /* - * Set Baud rate to default and turn off (default)flow control here - */ - status = BoxSetUart(serial, index, (unsigned short)divisor, new_LCR); - if (status < 0) { - mydbg(__FILE__ "BoxSetUart failed\n"); - return; - } - - /* Now determine flow control */ - if (cflag & CRTSCTS) { - mydbg("%s - Enabling HW flow control port %d\n", __func__, - port->number); - - /* Enable RTS/CTS flow control */ - status = BoxSetHW_FlowCtrl(serial, index, 1); - - if (status < 0) { - mydbg(__FILE__ "BoxSetHW_FlowCtrl failed\n"); - return; - } - } else { - /* Disable RTS/CTS flow control */ - mydbg("%s - disabling HW flow control port %d\n", __func__, - port->number); - - status = BoxSetHW_FlowCtrl(serial, index, 0); - if (status < 0) { - mydbg(__FILE__ "BoxSetHW_FlowCtrl failed\n"); - return; - } - - } - - /* if we are implementing XON/XOFF, set the start and stop character in - * the device */ - if (I_IXOFF(tty) || I_IXON(tty)) { - unsigned char stop_char = STOP_CHAR(tty); - unsigned char start_char = START_CHAR(tty); - status = - BoxSetSW_FlowCtrl(serial, index, stop_char, - start_char); - if (status < 0) - mydbg(__FILE__ "BoxSetSW_FlowCtrl (enabled) failed\n"); - - } else { - /* disable SW flow control */ - status = BoxDisable_SW_FlowCtrl(serial, index); - if (status < 0) - mydbg(__FILE__ "BoxSetSW_FlowCtrl (diabling) failed\n"); - - } - tty->termios->c_cflag &= ~CMSPAR; - /* FIXME: Error cases should be returning the actual bits changed only */ -} - -/**************************************************************************** -* BoxGetRegister -* issuse a GET_REGISTER vendor-spcific request on the default control pipe -* If successful, fills in the pValue with the register value asked for -****************************************************************************/ -static int BoxGetRegister(struct usb_serial *serial, unsigned short Uart_Number, - unsigned short Register_Num, __u8 *pValue) -{ - int result; - __u16 current_length; - - current_length = sizeof(struct qt_get_device_data); - - result = - usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), - QT_GET_SET_REGISTER, 0xC0, Register_Num, - Uart_Number, (void *)pValue, sizeof(*pValue), 300); - - return result; -} - -/**************************************************************************** -* BoxSetRegister -* issuse a GET_REGISTER vendor-spcific request on the default control pipe -* If successful, fills in the pValue with the register value asked for -****************************************************************************/ -static int BoxSetRegister(struct usb_serial *serial, unsigned short Uart_Number, - unsigned short Register_Num, unsigned short Value) -{ - int result; - unsigned short RegAndByte; - - RegAndByte = Value; - RegAndByte = RegAndByte << 8; - RegAndByte = RegAndByte + Register_Num; - -/* - result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - QT_GET_SET_REGISTER, 0xC0, Register_Num, - Uart_Number, NULL, 0, 300); -*/ - - result = - usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - QT_GET_SET_REGISTER, 0x40, RegAndByte, Uart_Number, - NULL, 0, 300); - - return result; -} - -/** - * box_get_device - * Issue a GET_DEVICE vendor-specific request on the default control pipe If - * successful, fills in the qt_get_device_data structure pointed to by - * device_data, otherwise return a negative error number of the problem. - */ -static int box_get_device(struct usb_serial *serial, - struct qt_get_device_data *device_data) -{ - int result; - __u16 current_length; - unsigned char *transfer_buffer; - - current_length = sizeof(struct qt_get_device_data); - transfer_buffer = kmalloc(current_length, GFP_KERNEL); - if (!transfer_buffer) - return -ENOMEM; - - result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), - QT_SET_GET_DEVICE, 0xc0, 0, 0, - transfer_buffer, current_length, 300); - if (result > 0) - memcpy(device_data, transfer_buffer, current_length); - kfree(transfer_buffer); - - return result; -} - -/** - * box_set_device - * Issue a SET_DEVICE vendor-specific request on the default control pipe If - * successful returns the number of bytes written, otherwise it returns a - * negative error number of the problem. - */ -static int box_set_device(struct usb_serial *serial, - struct qt_get_device_data *device_data) -{ - int result; - __u16 length; - __u16 PortSettings; - - PortSettings = ((__u16) (device_data->portb)); - PortSettings = (PortSettings << 8); - PortSettings += ((__u16) (device_data->porta)); - - length = sizeof(struct qt_get_device_data); - mydbg("%s - PortSettings = 0x%x\n", __func__, PortSettings); - - result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - QT_SET_GET_DEVICE, 0x40, PortSettings, - 0, NULL, 0, 300); - return result; -} - -/**************************************************************************** - * BoxOPenCloseChannel - * This funciotn notifies the device that the device driver wishes to open a particular UART channel. its - * purpose is to allow the device driver and the device to synchronize state information. - * OpenClose = 1 for open , 0 for close - ****************************************************************************/ -static int BoxOPenCloseChannel(struct usb_serial *serial, __u16 Uart_Number, - __u16 OpenClose, - struct qt_open_channel_data *pDeviceData) -{ - int result; - __u16 length; - __u8 Direcion; - unsigned int pipe; - length = sizeof(struct qt_open_channel_data); - - /* if opening... */ - if (OpenClose == 1) { - Direcion = USBD_TRANSFER_DIRECTION_IN; - pipe = usb_rcvctrlpipe(serial->dev, 0); - result = - usb_control_msg(serial->dev, pipe, QT_OPEN_CLOSE_CHANNEL, - Direcion, OpenClose, Uart_Number, - pDeviceData, length, 300); - - } else { - Direcion = USBD_TRANSFER_DIRECTION_OUT; - pipe = usb_sndctrlpipe(serial->dev, 0); - result = - usb_control_msg(serial->dev, pipe, QT_OPEN_CLOSE_CHANNEL, - Direcion, OpenClose, Uart_Number, NULL, 0, - 300); - - } - - return result; -} - -/**************************************************************************** - * BoxSetPrebufferLevel - TELLS BOX WHEN TO ASSERT FLOW CONTROL - ****************************************************************************/ -static int BoxSetPrebufferLevel(struct usb_serial *serial) -{ - int result; - __u16 buffer_length; - - buffer_length = PREFUFF_LEVEL_CONSERVATIVE; - result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - QT_GET_SET_PREBUF_TRIG_LVL, 0x40, - buffer_length, 0, NULL, 0, 300); - return result; -} - -/**************************************************************************** - * BoxSetATC - TELLS BOX WHEN TO ASSERT automatic transmitter control - ****************************************************************************/ -static int BoxSetATC(struct usb_serial *serial, __u16 n_Mode) -{ - int result; - __u16 buffer_length; - - buffer_length = PREFUFF_LEVEL_CONSERVATIVE; - - result = - usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - QT_SET_ATF, 0x40, n_Mode, 0, NULL, 0, 300); - - return result; -} - -/**************************************************************************** -* BoxSetUart -* issuse a SET_UART vendor-spcific request on the default control pipe -* If successful sets baud rate divisor and LCR value -****************************************************************************/ -static int BoxSetUart(struct usb_serial *serial, unsigned short Uart_Number, - unsigned short default_divisor, unsigned char default_LCR) -{ - int result; - unsigned short UartNumandLCR; - - UartNumandLCR = (default_LCR << 8) + Uart_Number; - - result = - usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - QT_GET_SET_UART, 0x40, default_divisor, - UartNumandLCR, NULL, 0, 300); - - return result; -} - -static int BoxSetHW_FlowCtrl(struct usb_serial *serial, unsigned int index, - int bSet) -{ - __u8 mcr = 0; - __u8 msr = 0, MOUT_Value = 0; - struct usb_serial_port *port; - unsigned int status; - - port = serial->port; - - if (bSet == 1) { - /* flow control, box will clear RTS line to prevent remote */ - mcr = SERIAL_MCR_RTS; - } /* device from xmitting more chars */ - else { - /* no flow control to remote device */ - mcr = 0; - - } - MOUT_Value = mcr << 8; - - if (bSet == 1) { - /* flow control, box will inhibit xmit data if CTS line is - * asserted */ - msr = SERIAL_MSR_CTS; - } else { - /* Box will not inhimbe xmit data due to CTS line */ - msr = 0; - } - MOUT_Value |= msr; - - status = - usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - QT_HW_FLOW_CONTROL_MASK, 0x40, MOUT_Value, - index, NULL, 0, 300); - return status; - -} - -static int BoxSetSW_FlowCtrl(struct usb_serial *serial, __u16 index, - unsigned char stop_char, unsigned char start_char) -{ - __u16 nSWflowout; - int result; - - nSWflowout = start_char << 8; - nSWflowout = (unsigned short)stop_char; - - result = - usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - QT_SW_FLOW_CONTROL_MASK, 0x40, nSWflowout, - index, NULL, 0, 300); - return result; - -} -static int BoxDisable_SW_FlowCtrl(struct usb_serial *serial, __u16 index) -{ - int result; - - result = - usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - QT_SW_FLOW_CONTROL_DISABLE, 0x40, 0, index, - NULL, 0, 300); - return result; - -} - -static void serial_throttle(struct tty_struct *tty) -{ - struct usb_serial_port *port = - tty->driver_data; - struct usb_serial *serial = get_usb_serial(port, __func__); - mydbg("%s - port %d\n", __func__, port->number); - - if (!serial) - return; - - down(&port->sem); - - if (!port->open_count) { - mydbg("%s - port not open\n", __func__); - goto exit; - } - /* shut down any bulk reads that may be going on */ -/* usb_unlink_urb (port->read_urb); */ - /* pass on to the driver specific version of this function */ - port->RxHolding = 1; - mydbg("%s - port->RxHolding = 1\n", __func__); - -exit: - up(&port->sem); - return; -} - -static void serial_unthrottle(struct tty_struct *tty) -{ - struct usb_serial_port *port = - tty->driver_data; - struct usb_serial *serial = get_usb_serial(port, __func__); - unsigned int result; - - if (!serial) - return; - down(&port->sem); - - mydbg("%s - port %d\n", __func__, port->number); - - if (!port->open_count) { - mydbg("%s - port not open\n", __func__); - goto exit; - } - - if (port->RxHolding == 1) { - mydbg("%s -port->RxHolding == 1\n", __func__); - - port->RxHolding = 0; - mydbg("%s - port->RxHolding = 0\n", __func__); - - /* if we have a bulk endpoint, start it up */ - if ((serial->num_bulk_in) && (port->ReadBulkStopped == 1)) { - /* Start reading from the device */ - usb_fill_bulk_urb(port->read_urb, serial->dev, - usb_rcvbulkpipe(serial->dev, - port-> - bulk_in_endpointAddress), - port->read_urb->transfer_buffer, - port->read_urb-> - transfer_buffer_length, - qt_read_bulk_callback, port); - result = usb_submit_urb(port->read_urb, GFP_ATOMIC); - if (result) - err("%s - failed restarting read urb, error %d", - __func__, result); - } - } -exit: - up(&port->sem); - return; - -} - -static int serial_break(struct tty_struct *tty, int break_state) -{ - struct usb_serial_port *port = tty->driver_data; - struct usb_serial *serial = get_usb_serial(port, __func__); - u16 index, onoff; - unsigned int result; - - index = tty->index - serial->minor; - if (!serial) - return -ENODEV; - - if (break_state == -1) - onoff = 1; - else - onoff = 0; - - down(&port->sem); - - mydbg("%s - port %d\n", __func__, port->number); - - if (!port->open_count) { - mydbg("%s - port not open\n", __func__); - goto exit; - } - - result = - usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - QT_BREAK_CONTROL, 0x40, onoff, index, - NULL, 0, 300); - -exit: - up(&port->sem); - return 0; -} - -static int ioctl_serial_usb(struct inode *innod, struct file *filp, unsigned int cmd, - unsigned long arg) -{ - - unsigned err; - unsigned ucOPR_NewValue, uc_Value; - int *p_Num_of_adapters, counts, index, *p_QMCR_Value; - struct identity *p_Identity_of; - struct identity Identity_of; - struct usb_serial *lastserial, *serial; - - mydbg(KERN_DEBUG "ioctl_serial_usb cmd =\n"); - if (_IOC_TYPE(cmd) != SERIALQT_PCI_IOC_MAGIC) - return -ENOTTY; - if (_IOC_NR(cmd) > SERIALQT_IOC_MAXNR) - return -ENOTTY; - mydbg(KERN_DEBUG "ioctl_serial_usb cmd = 0x%x\n", cmd); - err = 0; - switch (cmd) { - - case SERIALQT_WRITE_QMCR: - err = -ENOTTY; - index = arg >> 16; - counts = 0; - - ucOPR_NewValue = arg; - - err = EmulateWriteQMCR_Reg(index, ucOPR_NewValue); - break; - - case SERIALQT_READ_QMCR: - err = -ENOTTY; - p_QMCR_Value = (int *)arg; - index = arg >> 16; - counts = 0; - - err = EmulateReadQMCR_Reg(index, &uc_Value); - if (err == 0) - err = put_user(uc_Value, p_QMCR_Value); - break; - - case SERIALQT_GET_NUMOF_UNITS: - p_Num_of_adapters = (int *)arg; - counts = 0; /* Initialize counts to zero */ - /* struct usb_serial *lastserial = serial_table[0], *serial; */ - lastserial = serial_table[0]; - - mydbg(KERN_DEBUG "SERIALQT_GET_NUMOF_UNITS \n"); - /* if first pointer is nonull, we at least have one box */ - if (lastserial) - counts = 1; /* we at least have one box */ - - for (index = 1; index < SERIAL_TTY_MINORS; index++) { - serial = serial_table[index]; - if (serial) { - if (serial != lastserial) { - /* we had a change in the array, hence - * another box is there */ - lastserial = serial; - counts++; - } - } else - break; - } - - mydbg(KERN_DEBUG "ioctl_serial_usb writting counts = %d", - counts); - - err = put_user(counts, p_Num_of_adapters); - - break; - case SERIALQT_GET_THIS_UNIT: - counts = 0; - p_Identity_of = (struct identity *)arg; - /* copy user structure to local variable */ - get_user(Identity_of.index, &p_Identity_of->index); - mydbg(KERN_DEBUG "SERIALQT_GET_THIS_UNIT Identity_of.index\n"); - mydbg(KERN_DEBUG - "SERIALQT_GET_THIS_UNIT Identity_of.index= 0x%x\n", - Identity_of.index); - - err = -ENOTTY; - serial = find_the_box(Identity_of.index); - if (serial) { - err = - put_user(serial->product, - &p_Identity_of->n_identity); - - } - break; - - case SERIALQT_IS422_EXTENDED: - err = -ENOTTY; - mydbg(KERN_DEBUG "SERIALQT_IS422_EXTENDED \n"); - index = arg >> 16; - - counts = 0; - - mydbg(KERN_DEBUG - "SERIALQT_IS422_EXTENDED, looking Identity_of.indext = 0x%x\n", - index); - serial = find_the_box(index); - if (serial) { - mydbg("%s index = 0x%x, serial = 0x%p\n", __func__, - index, serial); - for (counts = 0; serqt_422_table[counts] != 0; counts++) { - - mydbg - ("%s serial->product = = 0x%x, serqt_422_table[counts] = 0x%x\n", - __func__, serial->product, - serqt_422_table[counts]); - if (serial->product == serqt_422_table[counts]) { - err = 0; - - mydbg - ("%s found match for 422extended\n", - __func__); - break; - } - } - } - break; - - default: - err = -ENOTTY; - } - - mydbg("%s returning err = 0x%x\n", __func__, err); - return err; -} - -static struct usb_serial *find_the_box(unsigned int index) -{ - struct usb_serial *lastserial, *foundserial, *serial; - int counts = 0, index2; - lastserial = serial_table[0]; - foundserial = NULL; - for (index2 = 0; index2 < SERIAL_TTY_MINORS; index2++) { - serial = serial_table[index2]; - - mydbg("%s index = 0x%x, index2 = 0x%x, serial = 0x%p\n", - __func__, index, index2, serial); - - if (serial) { - /* first see if this is the unit we'er looking for */ - mydbg - ("%s inside if(serial) counts = 0x%x , index = 0x%x\n", - __func__, counts, index); - if (counts == index) { - /* we found the one we're looking for, copythe - * product Id to user */ - mydbg("%s we found the one we're looking for serial = 0x%p\n", - __func__, serial); - foundserial = serial; - break; - } - - if (serial != lastserial) { - /* when we have a change in the pointer */ - lastserial = serial; - counts++; - } - } else - break; /* no matches */ - } - - mydbg("%s returning foundserial = 0x%p\n", __func__, foundserial); - return foundserial; -} - -static int EmulateWriteQMCR_Reg(int index, unsigned uc_value) -{ - - __u16 ATC_Mode = 0; - struct usb_serial *serial; - int status; - struct qt_get_device_data DeviceData; - unsigned uc_temp = 0; - mydbg("Inside %s, uc_value = 0x%x\n", __func__, uc_value); - - DeviceData.porta = 0; - DeviceData.portb = 0; - serial = find_the_box(index); - /* Determine Duplex mode */ - if (!(serial)) - return -ENOTTY; - status = box_get_device(serial, &DeviceData); - if (status < 0) { - mydbg(__FILE__ "box_set_device failed\n"); - return status; - } - - uc_temp = uc_value & QMCR_HALF_DUPLEX_MASK; - switch (uc_temp) { - case QMCR_FULL_DUPLEX: - DeviceData.porta &= ~DUPMODE_BITS; - DeviceData.porta |= FULL_DUPLEX; - ATC_Mode = ATC_DISABLED; - break; - case QMCR_HALF_DUPLEX_RTS: - DeviceData.porta &= ~DUPMODE_BITS; - DeviceData.porta |= HALF_DUPLEX_RTS; - ATC_Mode = ATC_RTS_ENABLED; - break; - case QMCR_HALF_DUPLEX_DTR: - DeviceData.porta &= ~DUPMODE_BITS; - DeviceData.porta |= HALF_DUPLEX_DTR; - ATC_Mode = ATC_DTR_ENABLED; - break; - default: - break; - } - - uc_temp = uc_value & QMCR_CONNECTOR_MASK; - switch (uc_temp) { - case QMCR_MODEM_CONTROL: - DeviceData.portb &= ~LOOPMODE_BITS; /* reset connection bits */ - DeviceData.portb |= MODEM_CTRL; - break; - case QMCR_ALL_LOOPBACK: - DeviceData.portb &= ~LOOPMODE_BITS; /* reset connection bits */ - DeviceData.portb |= ALL_LOOPBACK; - break; - } - - mydbg(__FILE__ "Calling box_set_device with failed\n"); - status = box_set_device(serial, &DeviceData); - if (status < 0) { - mydbg(__FILE__ "box_set_device failed\n"); - return status; - } - - /* This bit (otherwise unused) i'll used to detect whether ATC is - * selected */ - if (uc_value & QMCR_RX_EN_MASK) { - - mydbg(__FILE__ - "calling BoxsetATC with DeviceData.porta = 0x%x and DeviceData.portb = 0x%x\n", - DeviceData.porta, DeviceData.portb); - status = BoxSetATC(serial, ATC_Mode); - if (status < 0) { - mydbg(__FILE__ "BoxSetATC failed\n"); - return status; - } - } else { - - mydbg(__FILE__ - "calling BoxsetATC with DeviceData.porta = 0x%x and DeviceData.portb = 0x%x\n", - DeviceData.porta, DeviceData.portb); - status = BoxSetATC(serial, ATC_DISABLED); - if (status < 0) { - mydbg(__FILE__ "BoxSetATC failed\n"); - return status; - } - } - - return 0; - -} - -static int EmulateReadQMCR_Reg(int index, unsigned *uc_value) -{ - struct usb_serial *serial; - int status; - struct qt_get_device_data DeviceData; - __u8 uc_temp; - - *uc_value = 0; - - serial = find_the_box(index); - if (!(serial)) - return -ENOTTY; - - status = box_get_device(serial, &DeviceData); - if (status < 0) { - mydbg(__FILE__ "box_get_device failed\n"); - return status; - } - uc_temp = DeviceData.porta & DUPMODE_BITS; - switch (uc_temp) { - case FULL_DUPLEX: - *uc_value |= QMCR_FULL_DUPLEX; - break; - case HALF_DUPLEX_RTS: - *uc_value |= QMCR_HALF_DUPLEX_RTS; - break; - case HALF_DUPLEX_DTR: - *uc_value |= QMCR_HALF_DUPLEX_DTR; - break; - default: - break; - } - - /* I use this for ATC control se */ - uc_temp = DeviceData.portb & LOOPMODE_BITS; - - switch (uc_temp) { - case ALL_LOOPBACK: - *uc_value |= QMCR_ALL_LOOPBACK; - break; - case MODEM_CTRL: - *uc_value |= QMCR_MODEM_CONTROL; - break; - default: - break; - - } - return 0; - -} - -static int __init serqt_usb_init(void) -{ - int i, result; - int status = 0; - - mydbg("%s\n", __func__); - tty_set_operations(&serial_tty_driver, &serial_ops); - result = tty_register_driver(&serial_tty_driver); - if (result) { - mydbg("tty_register_driver failed error = 0x%x", result); - return result; - } - - /* Initalize our global data */ - for (i = 0; i < SERIAL_TTY_MINORS; ++i) - serial_table[i] = NULL; - - /* register this driver with the USB subsystem */ - result = usb_register(&serqt_usb_driver); - if (result < 0) { - err("usb_register failed for the " __FILE__ - " driver. Error number %d", result); - return result; - } - status = 0; /* Dynamic assignment of major number */ - major_number = - register_chrdev(status, "SerialQT_USB", &serialqt_usb_fops); - if (major_number < 0) { - mydbg(KERN_DEBUG "No devices found \n\n"); - return -EBUSY; - } else - mydbg(KERN_DEBUG "SerQT_USB major number assignment = %d \n\n", - major_number); - - printk(KERN_INFO DRIVER_DESC " " DRIVER_VERSION); - return 0; -} - -static void __exit serqt_usb_exit(void) -{ - /* deregister this driver with the USB subsystem */ - usb_deregister(&serqt_usb_driver); - tty_unregister_driver(&serial_tty_driver); - unregister_chrdev(major_number, "SerialQT_USB"); -} - -module_init(serqt_usb_init); -module_exit(serqt_usb_exit); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/serqt_usb/Kconfig b/drivers/staging/serqt_usb2/Kconfig similarity index 76% rename from drivers/staging/serqt_usb/Kconfig rename to drivers/staging/serqt_usb2/Kconfig index cc1af5df40d7..f4fed40e23dd 100644 --- a/drivers/staging/serqt_usb/Kconfig +++ b/drivers/staging/serqt_usb2/Kconfig @@ -1,4 +1,4 @@ -config USB_SERIAL_QUATECH_ESU100 +config USB_SERIAL_QUATECH2 tristate "USB Quatech ESU-100 8 Port Serial Driver" depends on USB_SERIAL help @@ -6,4 +6,4 @@ config USB_SERIAL_QUATECH_ESU100 serial adapter. To compile this driver as a module, choose M here: the - module will be called serqt_usb. + module will be called serqt_usb2. diff --git a/drivers/staging/serqt_usb2/Makefile b/drivers/staging/serqt_usb2/Makefile new file mode 100644 index 000000000000..21578617f7e8 --- /dev/null +++ b/drivers/staging/serqt_usb2/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_USB_SERIAL_QUATECH2) += serqt_usb2.o diff --git a/drivers/staging/serqt_usb2/serqt_usb2.c b/drivers/staging/serqt_usb2/serqt_usb2.c new file mode 100644 index 000000000000..90b29b564631 --- /dev/null +++ b/drivers/staging/serqt_usb2/serqt_usb2.c @@ -0,0 +1,1655 @@ +/* + * This code was developed for the Quatech USB line for linux, it used + * much of the code developed by Greg Kroah-Hartman for USB serial devices + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int debug; + +/* Version Information */ +#define DRIVER_VERSION "v2.14" +#define DRIVER_AUTHOR "Tim Gobeli, Quatech, Inc" +#define DRIVER_DESC "Quatech USB to Serial Driver" + +#define USB_VENDOR_ID_QUATECH 0x061d /* Quatech VID */ +#define QUATECH_SSU100 0xC020 /* SSU100 */ +#define QUATECH_SSU200 0xC030 /* SSU200 */ +#define QUATECH_DSU100 0xC040 /* DSU100 */ +#define QUATECH_DSU200 0xC050 /* DSU200 */ +#define QUATECH_QSU100 0xC060 /* QSU100 */ +#define QUATECH_QSU200 0xC070 /* QSU200 */ +#define QUATECH_ESU100A 0xC080 /* ESU100A */ +#define QUATECH_ESU100B 0xC081 /* ESU100B */ +#define QUATECH_ESU200A 0xC0A0 /* ESU200A */ +#define QUATECH_ESU200B 0xC0A1 /* ESU200B */ +#define QUATECH_HSU100A 0xC090 /* HSU100A */ +#define QUATECH_HSU100B 0xC091 /* HSU100B */ +#define QUATECH_HSU100C 0xC092 /* HSU100C */ +#define QUATECH_HSU100D 0xC093 /* HSU100D */ +#define QUATECH_HSU200A 0xC0B0 /* HSU200A */ +#define QUATECH_HSU200B 0xC0B1 /* HSU200B */ +#define QUATECH_HSU200C 0xC0B2 /* HSU200C */ +#define QUATECH_HSU200D 0xC0B3 /* HSU200D */ +#define QUATECH_SSU100_2 0xC120 /* SSU100_2 */ +#define QUATECH_DSU100_2 0xC140 /* DSU100_2 */ +#define QUATECH_DSU400_2 0xC150 /* DSU400_2 */ +#define QUATECH_QSU100_2 0xC160 /* QSU100_2 */ +#define QUATECH_QSU400_2 0xC170 /* QSU400_2 */ +#define QUATECH_ESU400_2 0xC180 /* ESU400_2 */ +#define QUATECH_ESU100_2 0xC1A0 /* ESU100_2 */ + +#define QT_SET_GET_DEVICE 0xc2 +#define QT_OPEN_CLOSE_CHANNEL 0xca +#define QT_GET_SET_PREBUF_TRIG_LVL 0xcc +#define QT_SET_ATF 0xcd +#define QT_GET_SET_REGISTER 0xc0 +#define QT_GET_SET_UART 0xc1 +#define QT_HW_FLOW_CONTROL_MASK 0xc5 +#define QT_SW_FLOW_CONTROL_MASK 0xc6 +#define QT_SW_FLOW_CONTROL_DISABLE 0xc7 +#define QT_BREAK_CONTROL 0xc8 + +#define USBD_TRANSFER_DIRECTION_IN 0xc0 +#define USBD_TRANSFER_DIRECTION_OUT 0x40 + +#define MAX_BAUD_RATE 460800 +#define MAX_BAUD_REMAINDER 4608 + +#define DIV_LATCH_LS 0x00 +#define XMT_HOLD_REGISTER 0x00 +#define XVR_BUFFER_REGISTER 0x00 +#define DIV_LATCH_MS 0x01 +#define FIFO_CONTROL_REGISTER 0x02 +#define LINE_CONTROL_REGISTER 0x03 +#define MODEM_CONTROL_REGISTER 0x04 +#define LINE_STATUS_REGISTER 0x05 +#define MODEM_STATUS_REGISTER 0x06 + +#define SERIAL_MCR_DTR 0x01 +#define SERIAL_MCR_RTS 0x02 +#define SERIAL_MCR_LOOP 0x10 + +#define SERIAL_MSR_CTS 0x10 +#define SERIAL_MSR_CD 0x80 +#define SERIAL_MSR_RI 0x40 +#define SERIAL_MSR_DSR 0x20 +#define SERIAL_MSR_MASK 0xf0 + +#define SERIAL_8_DATA 0x03 +#define SERIAL_7_DATA 0x02 +#define SERIAL_6_DATA 0x01 +#define SERIAL_5_DATA 0x00 + +#define SERIAL_ODD_PARITY 0X08 +#define SERIAL_EVEN_PARITY 0X18 +#define SERIAL_TWO_STOPB 0x04 +#define SERIAL_ONE_STOPB 0x00 + +#define DEFAULT_DIVISOR 0x30 /* gives 9600 baud rate */ +#define DEFAULT_LCR SERIAL_8_DATA /* 8, none , 1 */ + +#define FULLPWRBIT 0x00000080 +#define NEXT_BOARD_POWER_BIT 0x00000004 + +#define SERIAL_LSR_OE 0x02 +#define SERIAL_LSR_PE 0x04 +#define SERIAL_LSR_FE 0x08 +#define SERIAL_LSR_BI 0x10 + +#define SERIAL_MSR_CTS 0x10 +#define SERIAL_MSR_CD 0x80 +#define SERIAL_MSR_RI 0x40 +#define SERIAL_MSR_DSR 0x20 +#define SERIAL_MSR_MASK 0xf0 + +#define PREFUFF_LEVEL_CONSERVATIVE 128 +#define ATC_DISABLED 0x0 + +#define RR_BITS 0x03 /* for clearing clock bits */ +#define DUPMODE_BITS 0xc0 +#define CLKS_X4 0x02 + +#define LOOPMODE_BITS 0x41 /* LOOP1 = b6, LOOP0 = b0 (PORT B) */ +#define ALL_LOOPBACK 0x01 +#define MODEM_CTRL 0x40 +#define RS232_MODE 0x00 + +static struct usb_device_id serqt_id_table[] = { + {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_SSU100)}, + {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_SSU200)}, + {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU100)}, + {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU200)}, + {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_QSU100)}, + {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_QSU200)}, + {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_ESU100A)}, + {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_ESU100B)}, + {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_ESU200A)}, + {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_ESU200B)}, + {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_HSU100A)}, + {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_HSU100B)}, + {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_HSU100C)}, + {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_HSU100D)}, + {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_HSU200A)}, + {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_HSU200B)}, + {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_HSU200C)}, + {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_HSU200D)}, + {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_SSU100_2)}, + {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU100_2)}, + {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU400_2)}, + {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_QSU100_2)}, + {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_QSU400_2)}, + {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_ESU400_2)}, + {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_ESU100_2)}, + {} /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(usb, serqt_id_table); + +struct qt_get_device_data { + __u8 porta; + __u8 portb; + __u8 portc; +}; + +struct qt_open_channel_data { + __u8 line_status; + __u8 modem_status; +}; + +struct quatech_port { + int port_num; /* number of the port */ + struct urb *write_urb; /* write URB for this port */ + struct urb *read_urb; /* read URB for this port */ + struct urb *int_urb; + + __u8 shadowLCR; /* last LCR value received */ + __u8 shadowMCR; /* last MCR value received */ + __u8 shadowMSR; /* last MSR value received */ + __u8 shadowLSR; /* last LSR value received */ + char open_ports; + + /* Used for TIOCMIWAIT */ + wait_queue_head_t msr_wait; + char prev_status, diff_status; + + wait_queue_head_t wait; + + struct async_icount icount; + + struct usb_serial_port *port; /* owner of this object */ + struct qt_get_device_data DeviceData; + spinlock_t lock; + bool read_urb_busy; + int RxHolding; + int ReadBulkStopped; + char closePending; +}; + +static struct usb_driver serqt_usb_driver = { + .name = "quatech-usb-serial", + .probe = usb_serial_probe, + .disconnect = usb_serial_disconnect, + .id_table = serqt_id_table, + .no_dynamic_id = 1, +}; + +static int port_paranoia_check(struct usb_serial_port *port, + const char *function) +{ + if (!port) { + dbg("%s - port == NULL", function); + return -1; + } + if (!port->serial) { + dbg("%s - port->serial == NULL\n", function); + return -1; + } + + return 0; +} + +static int serial_paranoia_check(struct usb_serial *serial, + const char *function) +{ + if (!serial) { + dbg("%s - serial == NULL\n", function); + return -1; + } + + if (!serial->type) { + dbg("%s - serial->type == NULL!", function); + return -1; + } + + return 0; +} + +static inline struct quatech_port *qt_get_port_private(struct usb_serial_port + *port) +{ + return (struct quatech_port *)usb_get_serial_port_data(port); +} + +static inline void qt_set_port_private(struct usb_serial_port *port, + struct quatech_port *data) +{ + usb_set_serial_port_data(port, (void *)data); +} + +static struct usb_serial *get_usb_serial(struct usb_serial_port *port, + const char *function) +{ + /* if no port was specified, or it fails a paranoia check */ + if (!port || + port_paranoia_check(port, function) || + serial_paranoia_check(port->serial, function)) { + /* + * then say that we dont have a valid usb_serial thing, + * which will end up genrating -ENODEV return values + */ + return NULL; + } + + return port->serial; +} + +static void ProcessLineStatus(struct quatech_port *qt_port, + unsigned char line_status) +{ + + qt_port->shadowLSR = + line_status & (SERIAL_LSR_OE | SERIAL_LSR_PE | SERIAL_LSR_FE | + SERIAL_LSR_BI); + return; +} + +static void ProcessModemStatus(struct quatech_port *qt_port, + unsigned char modem_status) +{ + + qt_port->shadowMSR = modem_status; + wake_up_interruptible(&qt_port->wait); + return; +} + +static void ProcessRxChar(struct tty_struct *tty, struct usb_serial_port *port, + unsigned char data) +{ + struct urb *urb = port->read_urb; + if (urb->actual_length) + tty_insert_flip_char(tty, data, TTY_NORMAL); +} + +static void qt_write_bulk_callback(struct urb *urb) +{ + struct tty_struct *tty; + int status; + struct quatech_port *quatech_port; + + status = urb->status; + + if (status) { + dbg("nonzero write bulk status received:%d\n", status); + return; + } + + quatech_port = urb->context; + + dbg("%s - port %d\n", __func__, quatech_port->port_num); + + tty = tty_port_tty_get(&quatech_port->port->port); + + if (tty) + tty_wakeup(tty); + tty_kref_put(tty); +} + +static void qt_interrupt_callback(struct urb *urb) +{ + /* FIXME */ +} + +static void qt_read_bulk_callback(struct urb *urb) +{ + + struct usb_serial_port *port = urb->context; + struct usb_serial *serial = get_usb_serial(port, __func__); + struct quatech_port *qt_port = qt_get_port_private(port); + unsigned char *data; + struct tty_struct *tty; + unsigned int index; + unsigned int RxCount; + int i, result; + int flag, flag_data; + + if (urb->status) { + qt_port->ReadBulkStopped = 1; + dbg("%s - nonzero write bulk status received: %d\n", + __func__, urb->status); + return; + } + + tty = tty_port_tty_get(&port->port); + if (!tty) { + dbg("%s - bad tty pointer - exiting", __func__); + return; + } + + data = urb->transfer_buffer; + + RxCount = urb->actual_length; + + /* index = MINOR(port->tty->device) - serial->minor; */ + index = tty->index - serial->minor; + + dbg("%s - port %d\n", __func__, port->number); + dbg("%s - port->RxHolding = %d\n", __func__, qt_port->RxHolding); + + if (port_paranoia_check(port, __func__) != 0) { + dbg("%s - port_paranoia_check, exiting\n", __func__); + qt_port->ReadBulkStopped = 1; + return; + } + + if (!serial) { + dbg("%s - bad serial pointer, exiting\n", __func__); + return; + } + if (qt_port->closePending == 1) { + /* Were closing , stop reading */ + dbg("%s - (qt_port->closepending == 1\n", __func__); + qt_port->ReadBulkStopped = 1; + return; + } + + /* + * RxHolding is asserted by throttle, if we assert it, we're not + * receiving any more characters and let the box handle the flow + * control + */ + if (qt_port->RxHolding == 1) { + qt_port->ReadBulkStopped = 1; + return; + } + + if (urb->status) { + qt_port->ReadBulkStopped = 1; + + dbg("%s - nonzero read bulk status received: %d\n", + __func__, urb->status); + return; + } + + if (tty && RxCount) { + flag_data = 0; + for (i = 0; i < RxCount; ++i) { + /* Look ahead code here */ + if ((i <= (RxCount - 3)) && (data[i] == 0x1b) + && (data[i + 1] == 0x1b)) { + flag = 0; + switch (data[i + 2]) { + case 0x00: + /* line status change 4th byte must follow */ + if (i > (RxCount - 4)) { + dbg("Illegal escape seuences in received data\n"); + break; + } + ProcessLineStatus(qt_port, data[i + 3]); + i += 3; + flag = 1; + break; + + case 0x01: + /* Modem status status change 4th byte must follow */ + dbg("Modem status status. \n"); + if (i > (RxCount - 4)) { + dbg("Illegal escape sequences in received data\n"); + break; + } + ProcessModemStatus(qt_port, + data[i + 3]); + i += 3; + flag = 1; + break; + case 0xff: + dbg("No status sequence. \n"); + + if (tty) { + ProcessRxChar(tty, port, data[i]); + ProcessRxChar(tty, port, data[i + 1]); + } + i += 2; + break; + } + if (flag == 1) + continue; + } + + if (tty && urb->actual_length) + tty_insert_flip_char(tty, data[i], TTY_NORMAL); + + } + tty_flip_buffer_push(tty); + } + + /* Continue trying to always read */ + usb_fill_bulk_urb(port->read_urb, serial->dev, + usb_rcvbulkpipe(serial->dev, + port->bulk_in_endpointAddress), + port->read_urb->transfer_buffer, + port->read_urb->transfer_buffer_length, + qt_read_bulk_callback, port); + result = usb_submit_urb(port->read_urb, GFP_ATOMIC); + if (result) + dbg("%s - failed resubmitting read urb, error %d", + __func__, result); + else { + if (tty && RxCount) { + tty_flip_buffer_push(tty); + tty_schedule_flip(tty); + } + } + + schedule_work(&port->work); +} + +/* + * qt_get_device + * Issue a GET_DEVICE vendor-specific request on the default control pipe If + * successful, fills in the qt_get_device_data structure pointed to by + * device_data, otherwise return a negative error number of the problem. + */ + +static int qt_get_device(struct usb_serial *serial, + struct qt_get_device_data *device_data) +{ + int result; + unsigned char *transfer_buffer; + + transfer_buffer = + kmalloc(sizeof(struct qt_get_device_data), GFP_KERNEL); + if (!transfer_buffer) + return -ENOMEM; + + result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), + QT_SET_GET_DEVICE, 0xc0, 0, 0, + transfer_buffer, + sizeof(struct qt_get_device_data), 300); + if (result > 0) + memcpy(device_data, transfer_buffer, + sizeof(struct qt_get_device_data)); + kfree(transfer_buffer); + + return result; +} + +/**************************************************************************** + * BoxSetPrebufferLevel + TELLS BOX WHEN TO ASSERT FLOW CONTROL + ****************************************************************************/ +static int BoxSetPrebufferLevel(struct usb_serial *serial) +{ + int result; + __u16 buffer_length; + + buffer_length = PREFUFF_LEVEL_CONSERVATIVE; + result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + QT_GET_SET_PREBUF_TRIG_LVL, 0x40, + buffer_length, 0, NULL, 0, 300); + return result; +} + +/**************************************************************************** + * BoxSetATC + TELLS BOX WHEN TO ASSERT automatic transmitter control + ****************************************************************************/ +static int BoxSetATC(struct usb_serial *serial, __u16 n_Mode) +{ + int result; + __u16 buffer_length; + + buffer_length = PREFUFF_LEVEL_CONSERVATIVE; + + result = + usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + QT_SET_ATF, 0x40, n_Mode, 0, NULL, 0, 300); + + return result; +} + +/** + * qt_set_device + * Issue a SET_DEVICE vendor-specific request on the default control pipe If + * successful returns the number of bytes written, otherwise it returns a + * negative error number of the problem. + */ +static int qt_set_device(struct usb_serial *serial, + struct qt_get_device_data *device_data) +{ + int result; + __u16 length; + __u16 PortSettings; + + PortSettings = ((__u16) (device_data->portb)); + PortSettings = (PortSettings << 8); + PortSettings += ((__u16) (device_data->porta)); + + length = sizeof(struct qt_get_device_data); + dbg("%s - PortSettings = 0x%x\n", __func__, PortSettings); + + result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + QT_SET_GET_DEVICE, 0x40, PortSettings, + 0, NULL, 0, 300); + return result; +} + +static int qt_open_channel(struct usb_serial *serial, __u16 Uart_Number, + struct qt_open_channel_data *pDeviceData) +{ + int result; + + result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), + QT_OPEN_CLOSE_CHANNEL, + USBD_TRANSFER_DIRECTION_IN, 1, Uart_Number, + pDeviceData, + sizeof(struct qt_open_channel_data), 300); + + return result; + +} + +static int qt_close_channel(struct usb_serial *serial, __u16 Uart_Number) +{ + int result; + + result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), + QT_OPEN_CLOSE_CHANNEL, + USBD_TRANSFER_DIRECTION_OUT, 0, Uart_Number, + NULL, 0, 300); + + return result; + +} + +/**************************************************************************** +* BoxGetRegister +* issuse a GET_REGISTER vendor-spcific request on the default control pipe +* If successful, fills in the pValue with the register value asked for +****************************************************************************/ +static int BoxGetRegister(struct usb_serial *serial, unsigned short Uart_Number, + unsigned short Register_Num, __u8 *pValue) +{ + int result; + __u16 current_length; + + current_length = sizeof(struct qt_get_device_data); + + result = + usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), + QT_GET_SET_REGISTER, 0xC0, Register_Num, + Uart_Number, (void *)pValue, sizeof(*pValue), 300); + + return result; +} + +/**************************************************************************** +* BoxSetRegister +* issuse a GET_REGISTER vendor-spcific request on the default control pipe +* If successful, fills in the pValue with the register value asked for +****************************************************************************/ +static int BoxSetRegister(struct usb_serial *serial, unsigned short Uart_Number, + unsigned short Register_Num, unsigned short Value) +{ + int result; + unsigned short RegAndByte; + + RegAndByte = Value; + RegAndByte = RegAndByte << 8; + RegAndByte = RegAndByte + Register_Num; + +/* + result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + QT_GET_SET_REGISTER, 0xC0, Register_Num, + Uart_Number, NULL, 0, 300); +*/ + + result = + usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + QT_GET_SET_REGISTER, 0x40, RegAndByte, Uart_Number, + NULL, 0, 300); + + return result; +} + +/* + * qt_setuart + * issuse a SET_UART vendor-spcific request on the default control pipe + * If successful sets baud rate divisor and LCR value + */ +static int qt_setuart(struct usb_serial *serial, unsigned short Uart_Number, + unsigned short default_divisor, unsigned char default_LCR) +{ + int result; + unsigned short UartNumandLCR; + + UartNumandLCR = (default_LCR << 8) + Uart_Number; + + result = + usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + QT_GET_SET_UART, 0x40, default_divisor, + UartNumandLCR, NULL, 0, 300); + + return result; +} + +static int BoxSetHW_FlowCtrl(struct usb_serial *serial, unsigned int index, + int bSet) +{ + __u8 mcr = 0; + __u8 msr = 0, MOUT_Value = 0; + unsigned int status; + + if (bSet == 1) { + /* flow control, box will clear RTS line to prevent remote */ + mcr = SERIAL_MCR_RTS; + } /* device from xmitting more chars */ + else { + /* no flow control to remote device */ + mcr = 0; + + } + MOUT_Value = mcr << 8; + + if (bSet == 1) { + /* flow control, box will inhibit xmit data if CTS line is + * asserted */ + msr = SERIAL_MSR_CTS; + } else { + /* Box will not inhimbe xmit data due to CTS line */ + msr = 0; + } + MOUT_Value |= msr; + + status = + usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + QT_HW_FLOW_CONTROL_MASK, 0x40, MOUT_Value, + index, NULL, 0, 300); + return status; + +} + +static int BoxSetSW_FlowCtrl(struct usb_serial *serial, __u16 index, + unsigned char stop_char, unsigned char start_char) +{ + __u16 nSWflowout; + int result; + + nSWflowout = start_char << 8; + nSWflowout = (unsigned short)stop_char; + + result = + usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + QT_SW_FLOW_CONTROL_MASK, 0x40, nSWflowout, + index, NULL, 0, 300); + return result; + +} + +static int BoxDisable_SW_FlowCtrl(struct usb_serial *serial, __u16 index) +{ + int result; + + result = + usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + QT_SW_FLOW_CONTROL_DISABLE, 0x40, 0, index, + NULL, 0, 300); + return result; + +} + +static int qt_startup(struct usb_serial *serial) +{ + struct usb_serial_port *port; + struct quatech_port *qt_port; + struct qt_get_device_data DeviceData; + int i; + int status; + + dbg("enterting %s", __func__); + + /* Now setup per port private data */ + for (i = 0; i < serial->num_ports; i++) { + port = serial->port[i]; + qt_port = kzalloc(sizeof(*qt_port), GFP_KERNEL); + if (!qt_port) { + dbg("%s: kmalloc for quatech_port (%d) failed!.", + __func__, i); + return -ENOMEM; + } + spin_lock_init(&qt_port->lock); + + usb_set_serial_port_data(port, qt_port); + + } + + status = qt_get_device(serial, &DeviceData); + if (status < 0) { + dbg(__FILE__ "box_get_device failed"); + goto startup_error; + } + + dbg(__FILE__ "DeviceData.portb = 0x%x", DeviceData.portb); + + DeviceData.portb &= ~FULLPWRBIT; + dbg(__FILE__ "Changing DeviceData.portb to 0x%x", DeviceData.portb); + + status = qt_set_device(serial, &DeviceData); + if (status < 0) { + dbg(__FILE__ "qt_set_device failed\n"); + goto startup_error; + } + + status = qt_get_device(serial, &DeviceData); + if (status < 0) { + dbg(__FILE__ "qt_get_device failed"); + goto startup_error; + } + + switch (serial->dev->descriptor.idProduct) { + case QUATECH_SSU100: + case QUATECH_DSU100: + case QUATECH_QSU100: + case QUATECH_ESU100A: + case QUATECH_ESU100B: + case QUATECH_HSU100A: + case QUATECH_HSU100B: + case QUATECH_HSU100C: + case QUATECH_HSU100D: + DeviceData.porta &= ~(RR_BITS | DUPMODE_BITS); + DeviceData.porta |= CLKS_X4; + DeviceData.portb &= ~(LOOPMODE_BITS); + DeviceData.portb |= RS232_MODE; + break; + + case QUATECH_SSU200: + case QUATECH_DSU200: + case QUATECH_QSU200: + case QUATECH_ESU200A: + case QUATECH_ESU200B: + case QUATECH_HSU200A: + case QUATECH_HSU200B: + case QUATECH_HSU200C: + case QUATECH_HSU200D: + DeviceData.porta &= ~(RR_BITS | DUPMODE_BITS); + DeviceData.porta |= CLKS_X4; + DeviceData.portb &= ~(LOOPMODE_BITS); + DeviceData.portb |= ALL_LOOPBACK; + break; + default: + DeviceData.porta &= ~(RR_BITS | DUPMODE_BITS); + DeviceData.porta |= CLKS_X4; + DeviceData.portb &= ~(LOOPMODE_BITS); + DeviceData.portb |= RS232_MODE; + break; + + } + + status = BoxSetPrebufferLevel(serial); /* sets to default value */ + if (status < 0) { + dbg(__FILE__ "BoxSetPrebufferLevel failed\n"); + goto startup_error; + } + + status = BoxSetATC(serial, ATC_DISABLED); + if (status < 0) { + dbg(__FILE__ "BoxSetATC failed\n"); + goto startup_error; + } + + dbg(__FILE__ "DeviceData.portb = 0x%x", DeviceData.portb); + + DeviceData.portb |= NEXT_BOARD_POWER_BIT; + dbg(__FILE__ "Changing DeviceData.portb to 0x%x", DeviceData.portb); + + status = qt_set_device(serial, &DeviceData); + if (status < 0) { + dbg(__FILE__ "qt_set_device failed\n"); + goto startup_error; + } + + dbg("Exit Success %s\n", __func__); + + return 0; + +startup_error: + for (i = 0; i < serial->num_ports; i++) { + port = serial->port[i]; + qt_port = qt_get_port_private(port); + kfree(qt_port); + usb_set_serial_port_data(port, NULL); + } + + dbg("Exit fail %s\n", __func__); + + return -EIO; +} + +static void qt_release(struct usb_serial *serial) +{ + struct usb_serial_port *port; + struct quatech_port *qt_port; + int i; + + dbg("enterting %s", __func__); + + for (i = 0; i < serial->num_ports; i++) { + port = serial->port[i]; + if (!port) + continue; + + qt_port = usb_get_serial_port_data(port); + kfree(qt_port); + usb_set_serial_port_data(port, NULL); + } + +} + +int qt_open(struct tty_struct *tty, + struct usb_serial_port *port, struct file *filp) +{ + struct usb_serial *serial; + struct quatech_port *quatech_port; + struct quatech_port *port0; + struct qt_open_channel_data ChannelData; + + int result; + + if (port_paranoia_check(port, __func__)) + return -ENODEV; + + dbg("%s - port %d\n", __func__, port->number); + + serial = port->serial; + + if (serial_paranoia_check(serial, __func__)) + return -ENODEV; + + quatech_port = qt_get_port_private(port); + port0 = qt_get_port_private(serial->port[0]); + + if (quatech_port == NULL || port0 == NULL) + return -ENODEV; + + usb_clear_halt(serial->dev, port->write_urb->pipe); + usb_clear_halt(serial->dev, port->read_urb->pipe); + port0->open_ports++; + + result = qt_get_device(serial, &port0->DeviceData); + + /* Port specific setups */ + result = qt_open_channel(serial, port->number, &ChannelData); + if (result < 0) { + dbg(__FILE__ "qt_open_channel failed\n"); + return result; + } + dbg(__FILE__ "qt_open_channel completed.\n"); + +/* FIXME: are these needed? Does it even do anything useful? */ + quatech_port->shadowLSR = ChannelData.line_status & + (SERIAL_LSR_OE | SERIAL_LSR_PE | SERIAL_LSR_FE | SERIAL_LSR_BI); + + quatech_port->shadowMSR = ChannelData.modem_status & + (SERIAL_MSR_CTS | SERIAL_MSR_DSR | SERIAL_MSR_RI | SERIAL_MSR_CD); + + /* Set Baud rate to default and turn off (default)flow control here */ + result = qt_setuart(serial, port->number, DEFAULT_DIVISOR, DEFAULT_LCR); + if (result < 0) { + dbg(__FILE__ "qt_setuart failed\n"); + return result; + } + dbg(__FILE__ "qt_setuart completed.\n"); + + /* + * Put this here to make it responsive to stty and defauls set by + * the tty layer + */ + /* FIXME: is this needed? */ + /* qt_set_termios(tty, port, NULL); */ + + /* Check to see if we've set up our endpoint info yet */ + if (port0->open_ports == 1) { + if (serial->port[0]->interrupt_in_buffer == NULL) { + /* set up interrupt urb */ + usb_fill_int_urb(serial->port[0]->interrupt_in_urb, + serial->dev, + usb_rcvintpipe(serial->dev, + serial->port[0]->interrupt_in_endpointAddress), + serial->port[0]->interrupt_in_buffer, + serial->port[0]-> + interrupt_in_urb->transfer_buffer_length, + qt_interrupt_callback, serial, + serial->port[0]-> + interrupt_in_urb->interval); + + result = + usb_submit_urb(serial->port[0]->interrupt_in_urb, + GFP_KERNEL); + if (result) { + dev_err(&port->dev, + "%s - Error %d submitting " + "interrupt urb\n", __func__, result); + } + + } + + } + + dbg("port number is %d \n", port->number); + dbg("serial number is %d \n", port->serial->minor); + dbg("Bulkin endpoint is %d \n", port->bulk_in_endpointAddress); + dbg("BulkOut endpoint is %d \n", port->bulk_out_endpointAddress); + dbg("Interrupt endpoint is %d \n", port->interrupt_in_endpointAddress); + dbg("port's number in the device is %d\n", quatech_port->port_num); + quatech_port->read_urb = port->read_urb; + + /* set up our bulk in urb */ + + usb_fill_bulk_urb(quatech_port->read_urb, + serial->dev, + usb_rcvbulkpipe(serial->dev, + port->bulk_in_endpointAddress), + port->bulk_in_buffer, + quatech_port->read_urb->transfer_buffer_length, + qt_read_bulk_callback, quatech_port); + + dbg("qt_open: bulkin endpoint is %d\n", port->bulk_in_endpointAddress); + quatech_port->read_urb_busy = true; + result = usb_submit_urb(quatech_port->read_urb, GFP_KERNEL); + if (result) { + dev_err(&port->dev, + "%s - Error %d submitting control urb\n", + __func__, result); + quatech_port->read_urb_busy = false; + } + + /* initialize our wait queues */ + init_waitqueue_head(&quatech_port->wait); + init_waitqueue_head(&quatech_port->msr_wait); + + /* initialize our icount structure */ + memset(&(quatech_port->icount), 0x00, sizeof(quatech_port->icount)); + + return 0; + +} + +static int qt_chars_in_buffer(struct tty_struct *tty) +{ + struct usb_serial_port *port = tty->driver_data; + struct usb_serial *serial; + int chars = 0; + + serial = get_usb_serial(port, __func__); + + dbg("%s - port %d\n", __func__, port->number); + + if (serial->num_bulk_out) { + if (port->write_urb->status == -EINPROGRESS) + chars = port->write_urb->transfer_buffer_length; + } + + dbg("%s - returns %d\n", __func__, chars); + + return chars; +} + +static void qt_block_until_empty(struct tty_struct *tty, + struct quatech_port *qt_port) +{ + int timeout = HZ / 10; + int wait = 30; + int count; + + while (1) { + + count = qt_chars_in_buffer(tty); + + if (count <= 0) + return; + + interruptible_sleep_on_timeout(&qt_port->wait, timeout); + + wait--; + if (wait == 0) { + dbg("%s - TIMEOUT", __func__); + return; + } else { + wait = 30; + } + } +} + +static void qt_close(struct tty_struct *tty, struct usb_serial_port *port, + struct file *filp) +{ + struct usb_serial *serial = port->serial; + struct quatech_port *qt_port; + struct quatech_port *port0; + int status; + unsigned int index; + status = 0; + + dbg("%s - port %d\n", __func__, port->number); + index = tty->index - serial->minor; + + qt_port = qt_get_port_private(port); + port0 = qt_get_port_private(serial->port[0]); + + /* shutdown any bulk reads that might be going on */ + if (serial->num_bulk_out) + usb_unlink_urb(port->write_urb); + if (serial->num_bulk_in) + usb_unlink_urb(port->read_urb); + + /* wait up to for transmitter to empty */ + if (serial->dev) + qt_block_until_empty(tty, qt_port); + + /* Close uart channel */ + status = qt_close_channel(serial, index); + if (status < 0) + dbg("%s - port %d qt_close_channel failed.\n", + __func__, port->number); + + port0->open_ports--; + + dbg("qt_num_open_ports in close%d:in port%d\n", + port0->open_ports, port->number); + + if (port0->open_ports == 0) { + if (serial->port[0]->interrupt_in_urb) { + dbg("%s", "Shutdown interrupt_in_urb\n"); + usb_kill_urb(serial->port[0]->interrupt_in_urb); + } + + } + + if (qt_port->write_urb) { + /* if this urb had a transfer buffer already (old tx) free it */ + if (qt_port->write_urb->transfer_buffer != NULL) + kfree(qt_port->write_urb->transfer_buffer); + usb_free_urb(qt_port->write_urb); + } + +} + +static int qt_write(struct tty_struct *tty, struct usb_serial_port *port, + const unsigned char *buf, int count) +{ + int result; + struct usb_serial *serial = get_usb_serial(port, __func__); + + if (serial == NULL) + return -ENODEV; + + dbg("%s - port %d\n", __func__, port->number); + + if (count == 0) { + dbg("%s - write request of 0 bytes\n", __func__); + return 0; + } + + /* only do something if we have a bulk out endpoint */ + if (serial->num_bulk_out) { + if (port->write_urb->status == -EINPROGRESS) { + dbg("%s - already writing\n", __func__); + return 0; + } + + count = + (count > port->bulk_out_size) ? port->bulk_out_size : count; + memcpy(port->write_urb->transfer_buffer, buf, count); + + /* set up our urb */ + + usb_fill_bulk_urb(port->write_urb, serial->dev, + usb_sndbulkpipe(serial->dev, + port-> + bulk_out_endpointAddress), + port->write_urb->transfer_buffer, count, + qt_write_bulk_callback, port); + + /* send the data out the bulk port */ + result = usb_submit_urb(port->write_urb, GFP_ATOMIC); + if (result) + dbg("%s - failed submitting write urb, error %d\n", + __func__, result); + else + result = count; + + return result; + } + + /* no bulk out, so return 0 bytes written */ + return 0; +} + +static int qt_write_room(struct tty_struct *tty) +{ + struct usb_serial_port *port = tty->driver_data; + struct usb_serial *serial; + struct quatech_port *qt_port; + unsigned long flags; + + int retval = -EINVAL; + + if (port_paranoia_check(port, __func__)) { + dbg("%s", "Invalid port\n"); + return -1; + } + + serial = get_usb_serial(port, __func__); + + if (!serial) + return -ENODEV; + + qt_port = qt_get_port_private(port); + + spin_lock_irqsave(&qt_port->lock, flags); + + dbg("%s - port %d\n", __func__, port->number); + + if (serial->num_bulk_out) { + if (port->write_urb->status != -EINPROGRESS) + retval = port->bulk_out_size; + } + + spin_unlock_irqrestore(&qt_port->lock, flags); + return retval; + +} + +static int qt_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct usb_serial_port *port = tty->driver_data; + struct quatech_port *qt_port = qt_get_port_private(port); + struct usb_serial *serial = get_usb_serial(port, __func__); + unsigned int index; + + dbg("%s cmd 0x%04x", __func__, cmd); + + index = tty->index - serial->minor; + + if (cmd == TIOCMIWAIT) { + while (qt_port != NULL) { + interruptible_sleep_on(&qt_port->msr_wait); + if (signal_pending(current)) + return -ERESTARTSYS; + else { + char diff = qt_port->diff_status; + + if (diff == 0) + return -EIO; /* no change => error */ + + /* Consume all events */ + qt_port->diff_status = 0; + + if (((arg & TIOCM_RNG) + && (diff & SERIAL_MSR_RI)) + || ((arg & TIOCM_DSR) + && (diff & SERIAL_MSR_DSR)) + || ((arg & TIOCM_CD) + && (diff & SERIAL_MSR_CD)) + || ((arg & TIOCM_CTS) + && (diff & SERIAL_MSR_CTS))) { + return 0; + } + } + } + return 0; + } + + dbg("%s -No ioctl for that one. port = %d\n", __func__, port->number); + return -ENOIOCTLCMD; +} + +static void qt_set_termios(struct tty_struct *tty, + struct usb_serial_port *port, + struct ktermios *old_termios) +{ + struct ktermios *termios = tty->termios; + unsigned char new_LCR = 0; + unsigned int cflag = termios->c_cflag; + unsigned int index; + int baud, divisor, remainder; + int status; + + dbg("%s", __func__); + + index = tty->index - port->serial->minor; + + switch (cflag) { + case CS5: + new_LCR |= SERIAL_5_DATA; + break; + case CS6: + new_LCR |= SERIAL_6_DATA; + break; + case CS7: + new_LCR |= SERIAL_7_DATA; + break; + default: + case CS8: + new_LCR |= SERIAL_8_DATA; + break; + } + + /* Parity stuff */ + if (cflag & PARENB) { + if (cflag & PARODD) + new_LCR |= SERIAL_ODD_PARITY; + else + new_LCR |= SERIAL_EVEN_PARITY; + } + if (cflag & CSTOPB) + new_LCR |= SERIAL_TWO_STOPB; + else + new_LCR |= SERIAL_TWO_STOPB; + + dbg("%s - 4\n", __func__); + + /* Thats the LCR stuff, go ahead and set it */ + baud = tty_get_baud_rate(tty); + if (!baud) + /* pick a default, any default... */ + baud = 9600; + + dbg("%s - got baud = %d\n", __func__, baud); + + divisor = MAX_BAUD_RATE / baud; + remainder = MAX_BAUD_RATE % baud; + /* Round to nearest divisor */ + if (((remainder * 2) >= baud) && (baud != 110)) + divisor++; + + /* + * Set Baud rate to default and turn off (default)flow control here + */ + status = + qt_setuart(port->serial, index, (unsigned short)divisor, new_LCR); + if (status < 0) { + dbg(__FILE__ "qt_setuart failed\n"); + return; + } + + /* Now determine flow control */ + if (cflag & CRTSCTS) { + dbg("%s - Enabling HW flow control port %d\n", __func__, + port->number); + + /* Enable RTS/CTS flow control */ + status = BoxSetHW_FlowCtrl(port->serial, index, 1); + + if (status < 0) { + dbg(__FILE__ "BoxSetHW_FlowCtrl failed\n"); + return; + } + } else { + /* Disable RTS/CTS flow control */ + dbg("%s - disabling HW flow control port %d\n", __func__, + port->number); + + status = BoxSetHW_FlowCtrl(port->serial, index, 0); + if (status < 0) { + dbg(__FILE__ "BoxSetHW_FlowCtrl failed\n"); + return; + } + + } + + /* if we are implementing XON/XOFF, set the start and stop character in + * the device */ + if (I_IXOFF(tty) || I_IXON(tty)) { + unsigned char stop_char = STOP_CHAR(tty); + unsigned char start_char = START_CHAR(tty); + status = + BoxSetSW_FlowCtrl(port->serial, index, stop_char, + start_char); + if (status < 0) + dbg(__FILE__ "BoxSetSW_FlowCtrl (enabled) failed\n"); + + } else { + /* disable SW flow control */ + status = BoxDisable_SW_FlowCtrl(port->serial, index); + if (status < 0) + dbg(__FILE__ "BoxSetSW_FlowCtrl (diabling) failed\n"); + + } + tty->termios->c_cflag &= ~CMSPAR; + /* FIXME: Error cases should be returning the actual bits changed only */ +} + +static void qt_break(struct tty_struct *tty, int break_state) +{ + struct usb_serial_port *port = tty->driver_data; + struct usb_serial *serial = get_usb_serial(port, __func__); + struct quatech_port *qt_port; + u16 index, onoff; + unsigned int result; + unsigned long flags; + + index = tty->index - serial->minor; + + qt_port = qt_get_port_private(port); + + if (break_state == -1) + onoff = 1; + else + onoff = 0; + + spin_lock_irqsave(&qt_port->lock, flags); + + dbg("%s - port %d\n", __func__, port->number); + + result = + usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + QT_BREAK_CONTROL, 0x40, onoff, index, NULL, 0, 300); + + spin_unlock_irqrestore(&qt_port->lock, flags); +} + +static inline int qt_real_tiocmget(struct tty_struct *tty, + struct usb_serial_port *port, + struct file *file, struct usb_serial *serial) +{ + + u8 mcr; + u8 msr; + unsigned int result = 0; + int status; + unsigned int index; + + dbg("%s - port %d, tty =0x%p\n", __func__, port->number, tty); + + index = tty->index - serial->minor; + status = + BoxGetRegister(port->serial, index, MODEM_CONTROL_REGISTER, &mcr); + if (status >= 0) { + status = + BoxGetRegister(port->serial, index, + MODEM_STATUS_REGISTER, &msr); + + } + + if (status >= 0) { + result = ((mcr & SERIAL_MCR_DTR) ? TIOCM_DTR : 0) + /* DTR IS SET */ + | ((mcr & SERIAL_MCR_RTS) ? TIOCM_RTS : 0) + /* RTS IS SET */ + | ((msr & SERIAL_MSR_CTS) ? TIOCM_CTS : 0) + /* CTS is set */ + | ((msr & SERIAL_MSR_CD) ? TIOCM_CAR : 0) + /* Carrier detect is set */ + | ((msr & SERIAL_MSR_RI) ? TIOCM_RI : 0) + /* Ring indicator set */ + | ((msr & SERIAL_MSR_DSR) ? TIOCM_DSR : 0); + /* DSR is set */ + return result; + + } else + return -ESPIPE; +} + +static inline int qt_real_tiocmset(struct tty_struct *tty, + struct usb_serial_port *port, + struct file *file, + struct usb_serial *serial, + unsigned int value) +{ + + u8 mcr; + int status; + unsigned int index; + + dbg("%s - port %d\n", __func__, port->number); + + index = tty->index - serial->minor; + status = + BoxGetRegister(port->serial, index, MODEM_CONTROL_REGISTER, &mcr); + if (status < 0) + return -ESPIPE; + + /* + * Turn off the RTS and DTR and loopbcck and then only turn on what was + * asked for + */ + mcr &= ~(SERIAL_MCR_RTS | SERIAL_MCR_DTR | SERIAL_MCR_LOOP); + if (value & TIOCM_RTS) + mcr |= SERIAL_MCR_RTS; + if (value & TIOCM_DTR) + mcr |= SERIAL_MCR_DTR; + if (value & TIOCM_LOOP) + mcr |= SERIAL_MCR_LOOP; + + status = + BoxSetRegister(port->serial, index, MODEM_CONTROL_REGISTER, mcr); + if (status < 0) + return -ESPIPE; + else + return 0; +} + +static int qt_tiocmget(struct tty_struct *tty, struct file *file) +{ + struct usb_serial_port *port = tty->driver_data; + struct usb_serial *serial = get_usb_serial(port, __func__); + struct quatech_port *qt_port = qt_get_port_private(port); + int retval = -ENODEV; + unsigned long flags; + + dbg("In %s \n", __func__); + + if (!serial) + return -ENODEV; + + spin_lock_irqsave(&qt_port->lock, flags); + + dbg("%s - port %d\n", __func__, port->number); + dbg("%s - port->RxHolding = %d\n", __func__, qt_port->RxHolding); + + retval = qt_real_tiocmget(tty, port, file, serial); + + spin_unlock_irqrestore(&qt_port->lock, flags); + return retval; +} + +static int qt_tiocmset(struct tty_struct *tty, struct file *file, + unsigned int set, unsigned int clear) +{ + + struct usb_serial_port *port = tty->driver_data; + struct usb_serial *serial = get_usb_serial(port, __func__); + struct quatech_port *qt_port = qt_get_port_private(port); + unsigned long flags; + int retval = -ENODEV; + + dbg("In %s \n", __func__); + + if (!serial) + return -ENODEV; + + spin_lock_irqsave(&qt_port->lock, flags); + + dbg("%s - port %d \n", __func__, port->number); + dbg("%s - qt_port->RxHolding = %d\n", __func__, qt_port->RxHolding); + + retval = qt_real_tiocmset(tty, port, file, serial, set); + + spin_unlock_irqrestore(&qt_port->lock, flags); + return retval; +} + +static void qt_throttle(struct tty_struct *tty) +{ + struct usb_serial_port *port = tty->driver_data; + struct usb_serial *serial = get_usb_serial(port, __func__); + struct quatech_port *qt_port; + unsigned long flags; + + dbg("%s - port %d\n", __func__, port->number); + + if (!serial) + return; + + qt_port = qt_get_port_private(port); + + spin_lock_irqsave(&qt_port->lock, flags); + + /* pass on to the driver specific version of this function */ + qt_port->RxHolding = 1; + dbg("%s - port->RxHolding = 1\n", __func__); + + spin_unlock_irqrestore(&qt_port->lock, flags); + return; +} + +static void qt_unthrottle(struct tty_struct *tty) +{ + struct usb_serial_port *port = tty->driver_data; + struct usb_serial *serial = get_usb_serial(port, __func__); + struct quatech_port *qt_port; + unsigned long flags; + unsigned int result; + + if (!serial) + return; + + qt_port = qt_get_port_private(port); + + spin_lock_irqsave(&qt_port->lock, flags); + + dbg("%s - port %d\n", __func__, port->number); + + if (qt_port->RxHolding == 1) { + dbg("%s -qt_port->RxHolding == 1\n", __func__); + + qt_port->RxHolding = 0; + dbg("%s - qt_port->RxHolding = 0\n", __func__); + + /* if we have a bulk endpoint, start it up */ + if ((serial->num_bulk_in) && (qt_port->ReadBulkStopped == 1)) { + /* Start reading from the device */ + usb_fill_bulk_urb(port->read_urb, serial->dev, + usb_rcvbulkpipe(serial->dev, + port->bulk_in_endpointAddress), + port->read_urb->transfer_buffer, + port->read_urb-> + transfer_buffer_length, + qt_read_bulk_callback, port); + result = usb_submit_urb(port->read_urb, GFP_ATOMIC); + if (result) + err("%s - failed restarting read urb, error %d", + __func__, result); + } + } + spin_unlock_irqrestore(&qt_port->lock, flags); + return; + +} + +static int qt_calc_num_ports(struct usb_serial *serial) +{ + int num_ports; + + dbg("numberofendpoints: %d \n", + (int)serial->interface->cur_altsetting->desc.bNumEndpoints); + dbg("numberofendpoints: %d \n", + (int)serial->interface->altsetting->desc.bNumEndpoints); + + num_ports = + (serial->interface->cur_altsetting->desc.bNumEndpoints - 1) / 2; + + return num_ports; +} + +static struct usb_serial_driver quatech_device = { + .driver = { + .owner = THIS_MODULE, + .name = "serqt", + }, + .description = DRIVER_DESC, + .usb_driver = &serqt_usb_driver, + .id_table = serqt_id_table, + .num_ports = 8, + .open = qt_open, + .close = qt_close, + .write = qt_write, + .write_room = qt_write_room, + .chars_in_buffer = qt_chars_in_buffer, + .throttle = qt_throttle, + .unthrottle = qt_unthrottle, + .calc_num_ports = qt_calc_num_ports, + .ioctl = qt_ioctl, + .set_termios = qt_set_termios, + .break_ctl = qt_break, + .tiocmget = qt_tiocmget, + .tiocmset = qt_tiocmset, + .attach = qt_startup, + .release = qt_release, +}; + +static int __init serqt_usb_init(void) +{ + int retval; + + dbg("%s\n", __func__); + + /* register with usb-serial */ + retval = usb_serial_register(&quatech_device); + + if (retval) + goto failed_usb_serial_register; + + printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" + DRIVER_DESC "\n"); + + /* register with usb */ + + retval = usb_register(&serqt_usb_driver); + if (retval == 0) + return 0; + + /* if we're here, usb_register() failed */ + usb_serial_deregister(&quatech_device); +failed_usb_serial_register: + return retval; +} + +static void __exit serqt_usb_exit(void) +{ + usb_deregister(&serqt_usb_driver); + usb_serial_deregister(&quatech_device); +} + +module_init(serqt_usb_init); +module_exit(serqt_usb_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + +module_param(debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/staging/slicoss/slicoss.c b/drivers/staging/slicoss/slicoss.c index 6f5d0bff4358..ed47db5ce5ff 100644 --- a/drivers/staging/slicoss/slicoss.c +++ b/drivers/staging/slicoss/slicoss.c @@ -1872,7 +1872,6 @@ static int slic_card_download(struct adapter *adapter) __iomem struct slic_regs *slic_regs = adapter->slic_regs; u32 instruction; u32 baseaddress; - u32 failure; u32 i; u32 numsects = 0; u32 sectsize[3]; @@ -4049,7 +4048,7 @@ static struct pci_driver slic_driver = { .name = DRV_NAME, .id_table = slic_pci_tbl, .probe = slic_entry_probe, - .remove = slic_entry_remove, + .remove = __devexit_p(slic_entry_remove), }; static int __init slic_module_init(void) diff --git a/drivers/staging/stlc45xx/stlc45xx.c b/drivers/staging/stlc45xx/stlc45xx.c index 3eced5520c56..cfdaac9b747e 100644 --- a/drivers/staging/stlc45xx/stlc45xx.c +++ b/drivers/staging/stlc45xx/stlc45xx.c @@ -1787,7 +1787,6 @@ static int stlc45xx_tx_pspoll(struct stlc45xx *stlc, bool powersave) int payload_len, padding, i; struct s_lm_data_out *data; struct txbuffer *entry; - DECLARE_MAC_BUF(mac); struct sk_buff *skb; char *payload; u16 fc; @@ -1813,8 +1812,8 @@ static int stlc45xx_tx_pspoll(struct stlc45xx *stlc, bool powersave) memcpy(pspoll->addr1, stlc->bssid, ETH_ALEN); memcpy(pspoll->addr2, stlc->mac_addr, ETH_ALEN); - stlc45xx_debug(DEBUG_PSM, "sending PS-Poll frame to %s (powersave %d, " - "fc 0x%x, aid %d)", print_mac(mac, pspoll->addr1), + stlc45xx_debug(DEBUG_PSM, "sending PS-Poll frame to %pM (powersave %d, " + "fc 0x%x, aid %d)", pspoll->addr1, powersave, fc, stlc->aid); spin_lock_bh(&stlc->tx_lock); @@ -1903,7 +1902,6 @@ static int stlc45xx_tx_nullfunc(struct stlc45xx *stlc, bool powersave) int payload_len, padding, i; struct s_lm_data_out *data; struct txbuffer *entry; - DECLARE_MAC_BUF(mac); struct sk_buff *skb; char *payload; u16 fc; @@ -1928,9 +1926,8 @@ static int stlc45xx_tx_nullfunc(struct stlc45xx *stlc, bool powersave) memcpy(nullfunc->addr2, stlc->mac_addr, ETH_ALEN); memcpy(nullfunc->addr3, stlc->bssid, ETH_ALEN); - stlc45xx_debug(DEBUG_PSM, "sending Null frame to %s (powersave %d, " - "fc 0x%x)", - print_mac(mac, nullfunc->addr1), powersave, fc); + stlc45xx_debug(DEBUG_PSM, "sending Null frame to %pM (powersave %d, " + "fc 0x%x)", nullfunc->addr1, powersave, fc); spin_lock_bh(&stlc->tx_lock); diff --git a/drivers/staging/sxg/sxg.c b/drivers/staging/sxg/sxg.c index 076b3f7d39eb..3a0dac962e4d 100644 --- a/drivers/staging/sxg/sxg.c +++ b/drivers/staging/sxg/sxg.c @@ -355,7 +355,7 @@ void sxg_remove_msix_isr(struct adapter_t *adapter) for(i=0; i< adapter->nr_msix_entries;i++) { vector = adapter->msi_entries[i].vector; - DBG_ERROR("%s : Freeing IRQ vector#%d\n",__FUNCTION__,vector); + DBG_ERROR("%s : Freeing IRQ vector#%d\n",__func__,vector); free_irq(vector,netdev); } } @@ -852,7 +852,7 @@ static inline int sxg_read_config(struct adapter_t *adapter) * Get out of here */ printk(KERN_ERR"%s : Could not allocate memory for reading \ - EEPROM\n", __FUNCTION__); + EEPROM\n", __func__); return -ENOMEM; } @@ -887,7 +887,7 @@ static inline int sxg_read_config(struct adapter_t *adapter) case SXG_CFG_LOAD_ERROR: default: /* Fix default handler later */ printk(KERN_WARNING"%s : We could not read the config \ - word. Status = %ld\n", __FUNCTION__, status); + word. Status = %ld\n", __func__, status); break; } pci_free_consistent(adapter->pcidev, sizeof(struct sw_cfg_data), data, @@ -996,7 +996,7 @@ static int sxg_entry_probe(struct pci_dev *pcidev, adapter->asictype = SAHARA_REV_B; } else { ASSERT(0); - DBG_ERROR("%s Unexpected revision ID %x\n", __FUNCTION__, revision_id); + DBG_ERROR("%s Unexpected revision ID %x\n", __func__, revision_id); goto err_out_exit_sxg_probe; } adapter->netdev = netdev; @@ -1176,9 +1176,9 @@ static int sxg_entry_probe(struct pci_dev *pcidev, smp_processor_id()); pci_disable_device(pcidev); - DBG_ERROR("sxg: %s deallocate device\n", __FUNCTION__); + DBG_ERROR("sxg: %s deallocate device\n", __func__); kfree(netdev); - printk("Exit %s, Sxg driver loading failed..\n", __FUNCTION__); + printk("Exit %s, Sxg driver loading failed..\n", __func__); return -ENODEV; } @@ -2191,10 +2191,10 @@ static int sxg_entry_open(struct net_device *dev) /* * The microcode expects it to be downloaded on every open. */ - DBG_ERROR("sxg: %s ENTER sxg_download_microcode\n", __FUNCTION__); + DBG_ERROR("sxg: %s ENTER sxg_download_microcode\n", __func__); if (sxg_download_microcode(adapter, SXG_UCODE_SYSTEM)) { DBG_ERROR("sxg: %s ENTER sxg_adapter_set_hwaddr\n", - __FUNCTION__); + __func__); sxg_read_config(adapter); } else { adapter->state = ADAPT_FAIL; @@ -2307,14 +2307,14 @@ static void __devexit sxg_entry_remove(struct pci_dev *pcidev) mmio_start = pci_resource_start(pcidev, 0); mmio_len = pci_resource_len(pcidev, 0); - DBG_ERROR("sxg: %s rel_region(0) start[%x] len[%x]\n", __FUNCTION__, + DBG_ERROR("sxg: %s rel_region(0) start[%x] len[%x]\n", __func__, mmio_start, mmio_len); release_mem_region(mmio_start, mmio_len); mmio_start = pci_resource_start(pcidev, 2); mmio_len = pci_resource_len(pcidev, 2); - DBG_ERROR("sxg: %s rel_region(2) start[%x] len[%x]\n", __FUNCTION__, + DBG_ERROR("sxg: %s rel_region(2) start[%x] len[%x]\n", __func__, mmio_start, mmio_len); release_mem_region(mmio_start, mmio_len); @@ -2400,7 +2400,7 @@ static int sxg_entry_halt(struct net_device *dev) atomic_set(&adapter->pending_allocations, 0); adapter->intrregistered = 0; sxg_remove_isr(adapter); - DBG_ERROR("sxg: %s (%s) EXIT\n", __FUNCTION__, dev->name); + DBG_ERROR("sxg: %s (%s) EXIT\n", __func__, dev->name); return (STATUS_SUCCESS); } @@ -2454,7 +2454,7 @@ static int sxg_send_packets(struct sk_buff *skb, struct net_device *dev) u32 status = STATUS_SUCCESS; /* - * DBG_ERROR("sxg: %s ENTER sxg_send_packets skb[%p]\n", __FUNCTION__, + * DBG_ERROR("sxg: %s ENTER sxg_send_packets skb[%p]\n", __func__, * skb); */ @@ -3405,7 +3405,7 @@ static int sxg_read_mdio_reg(struct adapter_t *adapter, SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "WrtMDIO", adapter, 0, 0, 0); - DBG_ERROR("ENTER %s\n", __FUNCTION__); + DBG_ERROR("ENTER %s\n", __func__); /* Ensure values don't exceed field width */ DevAddr &= 0x001F; /* 5-bit field */ @@ -3441,7 +3441,7 @@ static int sxg_read_mdio_reg(struct adapter_t *adapter, udelay(100); /* Timeout in 100us units */ READ_REG(HwRegs->MacAmiimIndicator, ValueRead); if (--Timeout == 0) { - DBG_ERROR("EXIT %s with STATUS_FAILURE 1\n", __FUNCTION__); + DBG_ERROR("EXIT %s with STATUS_FAILURE 1\n", __func__); return (STATUS_FAILURE); } @@ -3462,7 +3462,7 @@ static int sxg_read_mdio_reg(struct adapter_t *adapter, udelay(100); /* Timeout in 100us units */ READ_REG(HwRegs->MacAmiimIndicator, ValueRead); if (--Timeout == 0) { - DBG_ERROR("EXIT %s with STATUS_FAILURE 2\n", __FUNCTION__); + DBG_ERROR("EXIT %s with STATUS_FAILURE 2\n", __func__); return (STATUS_FAILURE); } @@ -3472,7 +3472,7 @@ static int sxg_read_mdio_reg(struct adapter_t *adapter, READ_REG(HwRegs->MacAmiimField, *pValue); *pValue &= 0xFFFF; /* data is in the lower 16 bits */ - DBG_ERROR("EXIT %s\n", __FUNCTION__); + DBG_ERROR("EXIT %s\n", __func__); return (STATUS_SUCCESS); } @@ -3545,7 +3545,7 @@ static void sxg_mcast_set_mask(struct adapter_t *adapter) { struct sxg_ucode_regs *sxg_regs = adapter->UcodeRegs; - DBG_ERROR("%s ENTER (%s) MacFilter[%x] mask[%llx]\n", __FUNCTION__, + DBG_ERROR("%s ENTER (%s) MacFilter[%x] mask[%llx]\n", __func__, adapter->netdev->name, (unsigned int)adapter->MacFilter, adapter->MulticastMask); @@ -4055,7 +4055,7 @@ static int sxg_adapter_set_hwaddr(struct adapter_t *adapter) * sxg_dbg_macaddrs(adapter); */ /* DBG_ERROR ("%s AFTER copying from config.macinfo into currmacaddr\n", - * __FUNCTION__); + * __func__); */ /* sxg_dbg_macaddrs(adapter); */ @@ -4066,7 +4066,7 @@ static int sxg_adapter_set_hwaddr(struct adapter_t *adapter) printk("sxg: Dev is Null\n"); } - DBG_ERROR("%s ENTER (%s)\n", __FUNCTION__, adapter->netdev->name); + DBG_ERROR("%s ENTER (%s)\n", __func__, adapter->netdev->name); if (netif_running(dev)) { return -EBUSY; @@ -4516,7 +4516,7 @@ static struct pci_driver sxg_driver = { .name = sxg_driver_name, .id_table = sxg_pci_tbl, .probe = sxg_entry_probe, - .remove = sxg_entry_remove, + .remove = __devexit_p(sxg_entry_remove), #if SXG_POWER_MANAGEMENT_ENABLED .suspend = sxgpm_suspend, .resume = sxgpm_resume, diff --git a/drivers/staging/sxg/sxg_ethtool.c b/drivers/staging/sxg/sxg_ethtool.c index 97f765d1250f..ad89cb829b85 100644 --- a/drivers/staging/sxg/sxg_ethtool.c +++ b/drivers/staging/sxg/sxg_ethtool.c @@ -278,7 +278,7 @@ static int sxg_nic_get_eeprom(struct net_device *netdev, * Get out of here */ printk(KERN_ERR"%s : Could not allocate memory for reading \ - EEPROM\n", __FUNCTION__); + EEPROM\n", __func__); return -ENOMEM; } diff --git a/drivers/staging/uc2322/aten2011.c b/drivers/staging/uc2322/aten2011.c index 9c62f787cc9c..39d0926d1a90 100644 --- a/drivers/staging/uc2322/aten2011.c +++ b/drivers/staging/uc2322/aten2011.c @@ -2336,7 +2336,7 @@ static int ATEN2011_startup(struct usb_serial *serial) return 0; } -static void ATEN2011_shutdown(struct usb_serial *serial) +static void ATEN2011_release(struct usb_serial *serial) { int i; struct ATENINTL_port *ATEN2011_port; @@ -2382,7 +2382,7 @@ static struct usb_serial_driver aten_serial_driver = { .tiocmget = ATEN2011_tiocmget, .tiocmset = ATEN2011_tiocmset, .attach = ATEN2011_startup, - .shutdown = ATEN2011_shutdown, + .release = ATEN2011_release, .read_bulk_callback = ATEN2011_bulk_in_callback, .read_int_callback = ATEN2011_interrupt_callback, }; diff --git a/drivers/staging/udlfb/Kconfig b/drivers/staging/udlfb/Kconfig new file mode 100644 index 000000000000..641692da0e4f --- /dev/null +++ b/drivers/staging/udlfb/Kconfig @@ -0,0 +1,8 @@ +config FB_UDL + tristate "Displaylink USB Framebuffer support" + depends on FB && USB + ---help--- + This is an experimental driver for DisplayLink USB devices + that provides a framebuffer device. A normal framebuffer can + be used with this driver, or xorg can be run on the device + using it. diff --git a/drivers/staging/udlfb/Makefile b/drivers/staging/udlfb/Makefile new file mode 100644 index 000000000000..30d9e675b10f --- /dev/null +++ b/drivers/staging/udlfb/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_FB_UDL) += udlfb.o diff --git a/drivers/staging/udlfb/udlfb.c b/drivers/staging/udlfb/udlfb.c new file mode 100644 index 000000000000..0ab9d15f3439 --- /dev/null +++ b/drivers/staging/udlfb/udlfb.c @@ -0,0 +1,937 @@ +/***************************************************************************** + * DLFB Kernel Driver * + * Version 0.2 (udlfb) * + * (C) 2009 Roberto De Ioris * + * * + * This file is licensed under the GPLv2. See COPYING in the package. * + * Based on the amazing work of Florian Echtler and libdlo 0.1 * + * * + * * + * 10.06.09 release 0.2.3 (edid ioctl, fallback for unsupported modes) * + * 05.06.09 release 0.2.2 (real screen blanking, rle compression, double buffer) * + * 31.05.09 release 0.2 * + * 22.05.09 First public (ugly) release * + *****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "udlfb.h" + +#define DRIVER_VERSION "DLFB 0.2" + +/* memory functions taken from vfb */ + +static void *rvmalloc(unsigned long size) +{ + void *mem; + unsigned long adr; + + size = PAGE_ALIGN(size); + mem = vmalloc_32(size); + if (!mem) + return NULL; + + memset(mem, 0, size); /* Clear the ram out, no junk to the user */ + adr = (unsigned long)mem; + while (size > 0) { + SetPageReserved(vmalloc_to_page((void *)adr)); + adr += PAGE_SIZE; + size -= PAGE_SIZE; + } + + return mem; +} + +static void rvfree(void *mem, unsigned long size) +{ + unsigned long adr; + + if (!mem) + return; + + adr = (unsigned long)mem; + while ((long)size > 0) { + ClearPageReserved(vmalloc_to_page((void *)adr)); + adr += PAGE_SIZE; + size -= PAGE_SIZE; + } + vfree(mem); +} + +static int dlfb_mmap(struct fb_info *info, struct vm_area_struct *vma) +{ + unsigned long start = vma->vm_start; + unsigned long size = vma->vm_end - vma->vm_start; + unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; + unsigned long page, pos; + + printk("MMAP: %lu %u\n", offset + size, info->fix.smem_len); + + if (offset + size > info->fix.smem_len) + return -EINVAL; + + pos = (unsigned long)info->fix.smem_start + offset; + + while (size > 0) { + page = vmalloc_to_pfn((void *)pos); + if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) + return -EAGAIN; + + start += PAGE_SIZE; + pos += PAGE_SIZE; + if (size > PAGE_SIZE) + size -= PAGE_SIZE; + else + size = 0; + } + + vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */ + return 0; + +} + +/* ioctl structure */ +struct dloarea { + int x, y; + int w, h; + int x2, y2; +}; + +/* +static struct usb_device_id id_table [] = { + { USB_DEVICE(0x17e9, 0x023d) }, + { } +}; +*/ + +static struct usb_device_id id_table[] = { + {.idVendor = 0x17e9, .match_flags = USB_DEVICE_ID_MATCH_VENDOR,}, + {}, +}; +MODULE_DEVICE_TABLE(usb, id_table); + +static struct usb_driver dlfb_driver; + +// thanks to Henrik Bjerregaard Pedersen for this function +static char *rle_compress16(uint16_t * src, char *dst, int rem) +{ + + int rl; + uint16_t pix0; + char *end_if_raw = dst + 6 + 2 * rem; + + dst += 6; // header will be filled in if RLE is worth it + + while (rem && dst < end_if_raw) { + char *start = (char *)src; + + pix0 = *src++; + rl = 1; + rem--; + while (rem && *src == pix0) + rem--, rl++, src++; + *dst++ = rl; + *dst++ = start[1]; + *dst++ = start[0]; + } + + return dst; +} + +/* +Thanks to Henrik Bjerregaard Pedersen for rle implementation and code refactoring. +Next step is huffman compression. +*/ + +static int +image_blit(struct dlfb_data *dev_info, int x, int y, int width, int height, + char *data) +{ + + int i, j, base; + int rem = width; + int ret; + + int firstdiff, thistime; + + char *bufptr; + + if (x + width > dev_info->info->var.xres) + return -EINVAL; + + if (y + height > dev_info->info->var.yres) + return -EINVAL; + + mutex_lock(&dev_info->bulk_mutex); + + base = + dev_info->base16 + ((dev_info->info->var.xres * 2 * y) + (x * 2)); + + data += (dev_info->info->var.xres * 2 * y) + (x * 2); + + /* printk("IMAGE_BLIT\n"); */ + + bufptr = dev_info->buf; + + for (i = y; i < y + height; i++) { + + if (dev_info->bufend - bufptr < BUF_HIGH_WATER_MARK) { + ret = dlfb_bulk_msg(dev_info, bufptr - dev_info->buf); + bufptr = dev_info->buf; + } + + rem = width; + + /* printk("WRITING LINE %d\n", i); */ + + while (rem) { + + if (dev_info->bufend - bufptr < BUF_HIGH_WATER_MARK) { + ret = + dlfb_bulk_msg(dev_info, + bufptr - dev_info->buf); + bufptr = dev_info->buf; + } + // number of pixels to consider this time + thistime = rem; + if (thistime > 255) + thistime = 255; + + // find position of first pixel that has changed + firstdiff = -1; + for (j = 0; j < thistime * 2; j++) { + if (dev_info->backing_buffer + [base - dev_info->base16 + j] != data[j]) { + firstdiff = j / 2; + break; + } + } + + if (firstdiff >= 0) { + char *end_of_rle; + + end_of_rle = + rle_compress16((uint16_t *) (data + + firstdiff * 2), + bufptr, + thistime - firstdiff); + + if (end_of_rle < + bufptr + 6 + 2 * (thistime - firstdiff)) { + bufptr[0] = 0xAF; + bufptr[1] = 0x69; + + bufptr[2] = + (char)((base + + firstdiff * 2) >> 16); + bufptr[3] = + (char)((base + firstdiff * 2) >> 8); + bufptr[4] = + (char)(base + firstdiff * 2); + bufptr[5] = thistime - firstdiff; + + bufptr = end_of_rle; + + } else { + // fallback to raw (or some other encoding?) + *bufptr++ = 0xAF; + *bufptr++ = 0x68; + + *bufptr++ = + (char)((base + + firstdiff * 2) >> 16); + *bufptr++ = + (char)((base + firstdiff * 2) >> 8); + *bufptr++ = + (char)(base + firstdiff * 2); + *bufptr++ = thistime - firstdiff; + // PUT COMPRESSION HERE + for (j = firstdiff * 2; + j < thistime * 2; j += 2) { + *bufptr++ = data[j + 1]; + *bufptr++ = data[j]; + } + } + } + + base += thistime * 2; + data += thistime * 2; + rem -= thistime; + } + + memcpy(dev_info->backing_buffer + (base - dev_info->base16) - + (width * 2), data - (width * 2), width * 2); + + base += (dev_info->info->var.xres * 2) - (width * 2); + data += (dev_info->info->var.xres * 2) - (width * 2); + + } + + if (bufptr > dev_info->buf) { + ret = dlfb_bulk_msg(dev_info, bufptr - dev_info->buf); + } + + mutex_unlock(&dev_info->bulk_mutex); + + return base; + +} + +static int +draw_rect(struct dlfb_data *dev_info, int x, int y, int width, int height, + unsigned char red, unsigned char green, unsigned char blue) +{ + + int i, j, base; + int ret; + unsigned short col = + (((((red) & 0xF8) | ((green) >> 5)) & 0xFF) << 8) + + (((((green) & 0x1C) << 3) | ((blue) >> 3)) & 0xFF); + int rem = width; + + char *bufptr; + + if (x + width > dev_info->info->var.xres) + return -EINVAL; + + if (y + height > dev_info->info->var.yres) + return -EINVAL; + + mutex_lock(&dev_info->bulk_mutex); + + base = dev_info->base16 + (dev_info->info->var.xres * 2 * y) + (x * 2); + + bufptr = dev_info->buf; + + for (i = y; i < y + height; i++) { + + for (j = 0; j < width * 2; j += 2) { + dev_info->backing_buffer[base - dev_info->base16 + j] = + (char)(col >> 8); + dev_info->backing_buffer[base - dev_info->base16 + j + + 1] = (char)(col); + } + if (dev_info->bufend - bufptr < BUF_HIGH_WATER_MARK) { + ret = dlfb_bulk_msg(dev_info, bufptr - dev_info->buf); + bufptr = dev_info->buf; + } + + rem = width; + + while (rem) { + + if (dev_info->bufend - bufptr < BUF_HIGH_WATER_MARK) { + ret = + dlfb_bulk_msg(dev_info, + bufptr - dev_info->buf); + bufptr = dev_info->buf; + } + + *bufptr++ = 0xAF; + *bufptr++ = 0x69; + + *bufptr++ = (char)(base >> 16); + *bufptr++ = (char)(base >> 8); + *bufptr++ = (char)(base); + + if (rem > 255) { + *bufptr++ = 255; + *bufptr++ = 255; + rem -= 255; + base += 255 * 2; + } else { + *bufptr++ = rem; + *bufptr++ = rem; + base += rem * 2; + rem = 0; + } + + *bufptr++ = (char)(col >> 8); + *bufptr++ = (char)(col); + + } + + base += (dev_info->info->var.xres * 2) - (width * 2); + + } + + if (bufptr > dev_info->buf) + ret = dlfb_bulk_msg(dev_info, bufptr - dev_info->buf); + + mutex_unlock(&dev_info->bulk_mutex); + + return 1; +} + +static void swapfb(struct dlfb_data *dev_info) +{ + + int tmpbase; + char *bufptr; + + mutex_lock(&dev_info->bulk_mutex); + + tmpbase = dev_info->base16; + + dev_info->base16 = dev_info->base16d; + dev_info->base16d = tmpbase; + + bufptr = dev_info->buf; + + bufptr = dlfb_set_register(bufptr, 0xFF, 0x00); + + // set addresses + bufptr = + dlfb_set_register(bufptr, 0x20, (char)(dev_info->base16 >> 16)); + bufptr = dlfb_set_register(bufptr, 0x21, (char)(dev_info->base16 >> 8)); + bufptr = dlfb_set_register(bufptr, 0x22, (char)(dev_info->base16)); + + bufptr = dlfb_set_register(bufptr, 0xFF, 0x00); + + dlfb_bulk_msg(dev_info, bufptr - dev_info->buf); + + mutex_unlock(&dev_info->bulk_mutex); +} + +static int copyfb(struct dlfb_data *dev_info) +{ + int base; + int source; + int rem; + int i, ret; + + char *bufptr; + + base = dev_info->base16d; + + mutex_lock(&dev_info->bulk_mutex); + + source = dev_info->base16; + + bufptr = dev_info->buf; + + for (i = 0; i < dev_info->info->var.yres; i++) { + + if (dev_info->bufend - bufptr < BUF_HIGH_WATER_MARK) { + ret = dlfb_bulk_msg(dev_info, bufptr - dev_info->buf); + bufptr = dev_info->buf; + } + + rem = dev_info->info->var.xres; + + while (rem) { + + if (dev_info->bufend - bufptr < BUF_HIGH_WATER_MARK) { + ret = + dlfb_bulk_msg(dev_info, + bufptr - dev_info->buf); + bufptr = dev_info->buf; + + } + + *bufptr++ = 0xAF; + *bufptr++ = 0x6A; + + *bufptr++ = (char)(base >> 16); + *bufptr++ = (char)(base >> 8); + *bufptr++ = (char)(base); + + if (rem > 255) { + *bufptr++ = 255; + *bufptr++ = (char)(source >> 16); + *bufptr++ = (char)(source >> 8); + *bufptr++ = (char)(source); + + rem -= 255; + base += 255 * 2; + source += 255 * 2; + + } else { + *bufptr++ = rem; + *bufptr++ = (char)(source >> 16); + *bufptr++ = (char)(source >> 8); + *bufptr++ = (char)(source); + + base += rem * 2; + source += rem * 2; + rem = 0; + } + } + } + + if (bufptr > dev_info->buf) + ret = dlfb_bulk_msg(dev_info, bufptr - dev_info->buf); + + mutex_unlock(&dev_info->bulk_mutex); + + return 1; + +} + +static int +copyarea(struct dlfb_data *dev_info, int dx, int dy, int sx, int sy, + int width, int height) +{ + int base; + int source; + int rem; + int i, ret; + + char *bufptr; + + if (dx + width > dev_info->info->var.xres) + return -EINVAL; + + if (dy + height > dev_info->info->var.yres) + return -EINVAL; + + mutex_lock(&dev_info->bulk_mutex); + + base = + dev_info->base16 + (dev_info->info->var.xres * 2 * dy) + (dx * 2); + source = (dev_info->info->var.xres * 2 * sy) + (sx * 2); + + bufptr = dev_info->buf; + + for (i = sy; i < sy + height; i++) { + + memcpy(dev_info->backing_buffer + base - dev_info->base16, + dev_info->backing_buffer + source, width * 2); + + if (dev_info->bufend - bufptr < BUF_HIGH_WATER_MARK) { + ret = dlfb_bulk_msg(dev_info, bufptr - dev_info->buf); + bufptr = dev_info->buf; + } + + rem = width; + + while (rem) { + + if (dev_info->bufend - bufptr < BUF_HIGH_WATER_MARK) { + ret = + dlfb_bulk_msg(dev_info, + bufptr - dev_info->buf); + bufptr = dev_info->buf; + } + + *bufptr++ = 0xAF; + *bufptr++ = 0x6A; + + *bufptr++ = (char)(base >> 16); + *bufptr++ = (char)(base >> 8); + *bufptr++ = (char)(base); + + if (rem > 255) { + *bufptr++ = 255; + *bufptr++ = (char)(source >> 16); + *bufptr++ = (char)(source >> 8); + *bufptr++ = (char)(source); + + rem -= 255; + base += 255 * 2; + source += 255 * 2; + + } else { + *bufptr++ = rem; + *bufptr++ = (char)(source >> 16); + *bufptr++ = (char)(source >> 8); + *bufptr++ = (char)(source); + + base += rem * 2; + source += rem * 2; + rem = 0; + } + } + + base += (dev_info->info->var.xres * 2) - (width * 2); + source += (dev_info->info->var.xres * 2) - (width * 2); + } + + if (bufptr > dev_info->buf) + ret = dlfb_bulk_msg(dev_info, bufptr - dev_info->buf); + + mutex_unlock(&dev_info->bulk_mutex); + + return 1; +} + +static void dlfb_copyarea(struct fb_info *info, const struct fb_copyarea *area) +{ + + struct dlfb_data *dev = info->par; + + copyarea(dev, area->dx, area->dy, area->sx, area->sy, area->width, + area->height); + + /* printk("COPY AREA %d %d %d %d %d %d !!!\n", area->dx, area->dy, area->sx, area->sy, area->width, area->height); */ + +} + +static void dlfb_imageblit(struct fb_info *info, const struct fb_image *image) +{ + + int ret; + struct dlfb_data *dev = info->par; + /* printk("IMAGE BLIT (1) %d %d %d %d DEPTH %d {%p}!!!\n", image->dx, image->dy, image->width, image->height, image->depth, dev->udev); */ + cfb_imageblit(info, image); + ret = + image_blit(dev, image->dx, image->dy, image->width, image->height, + info->screen_base); + /* printk("IMAGE BLIT (2) %d %d %d %d DEPTH %d {%p} %d!!!\n", image->dx, image->dy, image->width, image->height, image->depth, dev->udev, ret); */ +} + +static void dlfb_fillrect(struct fb_info *info, + const struct fb_fillrect *region) +{ + + unsigned char red, green, blue; + struct dlfb_data *dev = info->par; + + memcpy(&red, ®ion->color, 1); + memcpy(&green, ®ion->color + 1, 1); + memcpy(&blue, ®ion->color + 2, 1); + draw_rect(dev, region->dx, region->dy, region->width, region->height, + red, green, blue); + /* printk("FILL RECT %d %d !!!\n", region->dx, region->dy); */ + +} + +static int dlfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) +{ + + struct dlfb_data *dev_info = info->par; + struct dloarea *area = NULL; + + if (cmd == 0xAD) { + char *edid = (char *)arg; + dlfb_edid(dev_info); + if (copy_to_user(edid, dev_info->edid, 128)) { + return -EFAULT; + } + return 0; + } + + if (cmd == 0xAA || cmd == 0xAB || cmd == 0xAC) { + + area = (struct dloarea *)arg; + + if (area->x < 0) + area->x = 0; + + if (area->x > info->var.xres) + area->x = info->var.xres; + + if (area->y < 0) + area->y = 0; + + if (area->y > info->var.yres) + area->y = info->var.yres; + } + + if (cmd == 0xAA) { + image_blit(dev_info, area->x, area->y, area->w, area->h, + info->screen_base); + } + if (cmd == 0xAC) { + copyfb(dev_info); + image_blit(dev_info, area->x, area->y, area->w, area->h, + info->screen_base); + swapfb(dev_info); + } else if (cmd == 0xAB) { + + if (area->x2 < 0) + area->x2 = 0; + + if (area->y2 < 0) + area->y2 = 0; + + copyarea(dev_info, + area->x2, area->y2, area->x, area->y, area->w, + area->h); + } + return 0; +} + +/* taken from vesafb */ + +static int +dlfb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, struct fb_info *info) +{ + int err = 0; + + if (regno >= info->cmap.len) + return 1; + + if (regno < 16) { + if (info->var.red.offset == 10) { + /* 1:5:5:5 */ + ((u32 *) (info->pseudo_palette))[regno] = + ((red & 0xf800) >> 1) | + ((green & 0xf800) >> 6) | ((blue & 0xf800) >> 11); + } else { + /* 0:5:6:5 */ + ((u32 *) (info->pseudo_palette))[regno] = + ((red & 0xf800)) | + ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11); + } + } + + return err; +} + +static int dlfb_release(struct fb_info *info, int user) +{ + struct dlfb_data *dev_info = info->par; + image_blit(dev_info, 0, 0, info->var.xres, info->var.yres, + info->screen_base); + return 0; +} + +static int dlfb_blank(int blank_mode, struct fb_info *info) +{ + struct dlfb_data *dev_info = info->par; + char *bufptr = dev_info->buf; + + bufptr = dlfb_set_register(bufptr, 0xFF, 0x00); + if (blank_mode != FB_BLANK_UNBLANK) { + bufptr = dlfb_set_register(bufptr, 0x1F, 0x01); + } else { + bufptr = dlfb_set_register(bufptr, 0x1F, 0x00); + } + bufptr = dlfb_set_register(bufptr, 0xFF, 0xFF); + + dlfb_bulk_msg(dev_info, bufptr - dev_info->buf); + + return 0; +} + +static struct fb_ops dlfb_ops = { + .fb_setcolreg = dlfb_setcolreg, + .fb_fillrect = dlfb_fillrect, + .fb_copyarea = dlfb_copyarea, + .fb_imageblit = dlfb_imageblit, + .fb_mmap = dlfb_mmap, + .fb_ioctl = dlfb_ioctl, + .fb_release = dlfb_release, + .fb_blank = dlfb_blank, +}; + +static int +dlfb_probe(struct usb_interface *interface, const struct usb_device_id *id) +{ + struct dlfb_data *dev_info; + struct fb_info *info; + + int ret; + char rbuf[4]; + + dev_info = kzalloc(sizeof(*dev_info), GFP_KERNEL); + if (dev_info == NULL) { + printk("cannot allocate dev_info structure.\n"); + return -ENOMEM; + } + + mutex_init(&dev_info->bulk_mutex); + + dev_info->udev = usb_get_dev(interface_to_usbdev(interface)); + dev_info->interface = interface; + + printk("DisplayLink device attached\n"); + + /* add framebuffer info to usb interface */ + usb_set_intfdata(interface, dev_info); + + dev_info->buf = kmalloc(BUF_SIZE, GFP_KERNEL); + /* usb_buffer_alloc(dev_info->udev, BUF_SIZE , GFP_KERNEL, &dev_info->tx_urb->transfer_dma); */ + + if (dev_info->buf == NULL) { + printk("unable to allocate memory for dlfb commands\n"); + goto out; + } + dev_info->bufend = dev_info->buf + BUF_SIZE; + + dev_info->tx_urb = usb_alloc_urb(0, GFP_KERNEL); + usb_fill_bulk_urb(dev_info->tx_urb, dev_info->udev, + usb_sndbulkpipe(dev_info->udev, 1), dev_info->buf, 0, + dlfb_bulk_callback, dev_info); + + ret = + usb_control_msg(dev_info->udev, usb_rcvctrlpipe(dev_info->udev, 0), + (0x06), (0x80 | (0x02 << 5)), 0, 0, rbuf, 4, 0); + printk("ret control msg 0: %d %x%x%x%x\n", ret, rbuf[0], rbuf[1], + rbuf[2], rbuf[3]); + + dlfb_edid(dev_info); + + info = framebuffer_alloc(sizeof(u32) * 256, &dev_info->udev->dev); + + if (!info) { + printk("non posso allocare il framebuffer displaylink"); + goto out; + } + + fb_parse_edid(dev_info->edid, &info->var); + + printk("EDID XRES %d YRES %d\n", info->var.xres, info->var.yres); + + if (dlfb_set_video_mode(dev_info, info->var.xres, info->var.yres) != 0) { + info->var.xres = 1280; + info->var.yres = 1024; + if (dlfb_set_video_mode + (dev_info, info->var.xres, info->var.yres) != 0) { + goto out; + } + } + + printk("found valid mode...%d\n", info->var.pixclock); + + info->pseudo_palette = info->par; + info->par = dev_info; + + dev_info->info = info; + + info->flags = + FBINFO_DEFAULT | FBINFO_READS_FAST | FBINFO_HWACCEL_IMAGEBLIT | + FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT; + info->fbops = &dlfb_ops; + info->screen_base = rvmalloc(dev_info->screen_size); + + if (info->screen_base == NULL) { + printk + ("cannot allocate framebuffer virtual memory of %d bytes\n", + dev_info->screen_size); + goto out0; + } + + printk("screen base allocated !!!\n"); + + dev_info->backing_buffer = kzalloc(dev_info->screen_size, GFP_KERNEL); + + if (!dev_info->backing_buffer) + printk("non posso allocare il backing buffer\n"); + + /* info->var = dev_info->si; */ + + info->var.bits_per_pixel = 16; + info->var.activate = FB_ACTIVATE_TEST; + info->var.vmode = FB_VMODE_NONINTERLACED; + + info->var.red.offset = 11; + info->var.red.length = 5; + info->var.red.msb_right = 0; + + info->var.green.offset = 5; + info->var.green.length = 6; + info->var.green.msb_right = 0; + + info->var.blue.offset = 0; + info->var.blue.length = 5; + info->var.blue.msb_right = 0; + + /* info->var.pixclock = (10000000 / FB_W * 1000 / FB_H)/2 ; */ + + info->fix.smem_start = (unsigned long)info->screen_base; + info->fix.smem_len = PAGE_ALIGN(dev_info->screen_size); + if (strlen(dev_info->udev->product) > 15) { + memcpy(info->fix.id, dev_info->udev->product, 15); + } else { + memcpy(info->fix.id, dev_info->udev->product, + strlen(dev_info->udev->product)); + } + info->fix.type = FB_TYPE_PACKED_PIXELS; + info->fix.visual = FB_VISUAL_TRUECOLOR; + info->fix.accel = info->flags; + info->fix.line_length = dev_info->line_length; + + if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) + goto out1; + + printk("colormap allocated\n"); + if (register_framebuffer(info) < 0) + goto out2; + + draw_rect(dev_info, 0, 0, dev_info->info->var.xres, + dev_info->info->var.yres, 0x30, 0xff, 0x30); + + return 0; + +out2: + fb_dealloc_cmap(&info->cmap); +out1: + rvfree(info->screen_base, dev_info->screen_size); +out0: + framebuffer_release(info); +out: + usb_set_intfdata(interface, NULL); + usb_put_dev(dev_info->udev); + kfree(dev_info); + return -ENOMEM; + +} + +static void dlfb_disconnect(struct usb_interface *interface) +{ + struct dlfb_data *dev_info = usb_get_intfdata(interface); + + mutex_unlock(&dev_info->bulk_mutex); + + usb_kill_urb(dev_info->tx_urb); + usb_free_urb(dev_info->tx_urb); + usb_set_intfdata(interface, NULL); + usb_put_dev(dev_info->udev); + + if (dev_info->info) { + unregister_framebuffer(dev_info->info); + fb_dealloc_cmap(&dev_info->info->cmap); + rvfree(dev_info->info->screen_base, dev_info->screen_size); + kfree(dev_info->backing_buffer); + framebuffer_release(dev_info->info); + + } + + kfree(dev_info); + + printk("DisplayLink device disconnected\n"); +} + +static struct usb_driver dlfb_driver = { + .name = "udlfb", + .probe = dlfb_probe, + .disconnect = dlfb_disconnect, + .id_table = id_table, +}; + +static int __init dlfb_init(void) +{ + int res; + + dlfb_init_modes(); + + res = usb_register(&dlfb_driver); + if (res) + err("usb_register failed. Error number %d", res); + + printk("VMODES initialized\n"); + + return res; +} + +static void __exit dlfb_exit(void) +{ + usb_deregister(&dlfb_driver); +} + +module_init(dlfb_init); +module_exit(dlfb_exit); + +MODULE_AUTHOR("Roberto De Ioris "); +MODULE_DESCRIPTION(DRIVER_VERSION); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/udlfb/udlfb.h b/drivers/staging/udlfb/udlfb.h new file mode 100644 index 000000000000..08bd671204b2 --- /dev/null +++ b/drivers/staging/udlfb/udlfb.h @@ -0,0 +1,225 @@ +#ifndef UDLFB_H +#define UDLFB_H + +#define MAX_VMODES 4 +#define FB_BPP 16 + +#define STD_CHANNEL "\x57\xCD\xDC\xA7\x1C\x88\x5E\x15" \ + "\x60\xFE\xC6\x97\x16\x3D\x47\xF2" + +/* as libdlo */ +#define BUF_HIGH_WATER_MARK 1024 +#define BUF_SIZE (64*1024) + +struct dlfb_data { + struct usb_device *udev; + struct usb_interface *interface; + struct urb *tx_urb, *ctrl_urb; + struct usb_ctrlrequest dr; + struct fb_info *info; + char *buf; + char *bufend; + char *backing_buffer; + struct mutex bulk_mutex; + char edid[128]; + int screen_size; + int line_length; + struct completion done; + int base16; + int base16d; + int base8; + int base8d; +}; + +struct dlfb_video_mode { + uint8_t col; + uint32_t hclock; + uint32_t vclock; + uint8_t unknown1[6]; + uint16_t xres; + uint8_t unknown2[6]; + uint16_t yres; + uint8_t unknown3[4]; +} __attribute__ ((__packed__)); + +static struct dlfb_video_mode dlfb_video_modes[MAX_VMODES]; + +static void dlfb_bulk_callback(struct urb *urb) +{ + struct dlfb_data *dev_info = urb->context; + complete(&dev_info->done); +} + +static void dlfb_edid(struct dlfb_data *dev_info) +{ + int i; + int ret; + char rbuf[2]; + + for (i = 0; i < 128; i++) { + ret = + usb_control_msg(dev_info->udev, + usb_rcvctrlpipe(dev_info->udev, 0), (0x02), + (0x80 | (0x02 << 5)), i << 8, 0xA1, rbuf, 2, + 0); + /*printk("ret control msg edid %d: %d [%d]\n",i, ret, rbuf[1]); */ + dev_info->edid[i] = rbuf[1]; + } + +} + +static int dlfb_bulk_msg(struct dlfb_data *dev_info, int len) +{ + int ret; + + init_completion(&dev_info->done); + + dev_info->tx_urb->actual_length = 0; + dev_info->tx_urb->transfer_buffer_length = len; + + ret = usb_submit_urb(dev_info->tx_urb, GFP_KERNEL); + if (!wait_for_completion_timeout(&dev_info->done, 1000)) { + usb_kill_urb(dev_info->tx_urb); + printk("usb timeout !!!\n"); + } + + return dev_info->tx_urb->actual_length; +} + +static void dlfb_init_modes(void) +{ + dlfb_video_modes[0].col = 0; + memcpy(&dlfb_video_modes[0].hclock, "\x20\x3C\x7A\xC9", 4); + memcpy(&dlfb_video_modes[0].vclock, "\xF2\x6C\x48\xF9", 4); + memcpy(&dlfb_video_modes[0].unknown1, "\x70\x53\xFF\xFF\x21\x27", 6); + dlfb_video_modes[0].xres = 800; + memcpy(&dlfb_video_modes[0].unknown2, "\x91\xF3\xFF\xFF\xFF\xF9", 6); + dlfb_video_modes[0].yres = 480; + memcpy(&dlfb_video_modes[0].unknown3, "\x01\x02\xC8\x19", 4); + + dlfb_video_modes[1].col = 0; + memcpy(&dlfb_video_modes[1].hclock, "\x36\x18\xD5\x10", 4); + memcpy(&dlfb_video_modes[1].vclock, "\x60\xA9\x7B\x33", 4); + memcpy(&dlfb_video_modes[1].unknown1, "\xA1\x2B\x27\x32\xFF\xFF", 6); + dlfb_video_modes[1].xres = 1024; + memcpy(&dlfb_video_modes[1].unknown2, "\xD9\x9A\xFF\xCA\xFF\xFF", 6); + dlfb_video_modes[1].yres = 768; + memcpy(&dlfb_video_modes[1].unknown3, "\x04\x03\xC8\x32", 4); + + dlfb_video_modes[2].col = 0; + memcpy(&dlfb_video_modes[2].hclock, "\x98\xF8\x0D\x57", 4); + memcpy(&dlfb_video_modes[2].vclock, "\x2A\x55\x4D\x54", 4); + memcpy(&dlfb_video_modes[2].unknown1, "\xCA\x0D\xFF\xFF\x94\x43", 6); + dlfb_video_modes[2].xres = 1280; + memcpy(&dlfb_video_modes[2].unknown2, "\x9A\xA8\xFF\xFF\xFF\xF9", 6); + dlfb_video_modes[2].yres = 1024; + memcpy(&dlfb_video_modes[2].unknown3, "\x04\x02\x60\x54", 4); + + dlfb_video_modes[3].col = 0; + memcpy(&dlfb_video_modes[3].hclock, "\x42\x24\x38\x36", 4); + memcpy(&dlfb_video_modes[3].vclock, "\xC1\x52\xD9\x29", 4); + memcpy(&dlfb_video_modes[3].unknown1, "\xEA\xB8\x32\x60\xFF\xFF", 6); + dlfb_video_modes[3].xres = 1400; + memcpy(&dlfb_video_modes[3].unknown2, "\xC9\x4E\xFF\xFF\xFF\xF2", 6); + dlfb_video_modes[3].yres = 1050; + memcpy(&dlfb_video_modes[3].unknown3, "\x04\x02\x1E\x5F", 4); +} + +static char *dlfb_set_register(char *bufptr, uint8_t reg, uint8_t val) +{ + *bufptr++ = 0xAF; + *bufptr++ = 0x20; + *bufptr++ = reg; + *bufptr++ = val; + + return bufptr; +} + +static int dlfb_set_video_mode(struct dlfb_data *dev_info, int width, int height) +{ + int i, ret; + unsigned char j; + char *bufptr = dev_info->buf; + uint8_t *vdata; + + for (i = 0; i < MAX_VMODES; i++) { + printk("INIT VIDEO %d %d %d\n", i, dlfb_video_modes[i].xres, + dlfb_video_modes[i].yres); + if (dlfb_video_modes[i].xres == width + && dlfb_video_modes[i].yres == height) { + + dev_info->base16 = 0; + dev_info->base16d = width * height * (FB_BPP / 8); + + //dev_info->base8 = width * height * (FB_BPP / 8); + + dev_info->base8 = dev_info->base16; + dev_info->base8d = dev_info->base16d; + + /* set encryption key (null) */ + memcpy(dev_info->buf, STD_CHANNEL, 16); + ret = + usb_control_msg(dev_info->udev, + usb_sndctrlpipe(dev_info->udev, 0), + 0x12, (0x02 << 5), 0, 0, + dev_info->buf, 16, 0); + printk("ret control msg 1 (STD_CHANNEL): %d\n", ret); + + /* set registers */ + bufptr = dlfb_set_register(bufptr, 0xFF, 0x00); + + /* set color depth */ + bufptr = dlfb_set_register(bufptr, 0x00, 0x00); + + /* set addresses */ + bufptr = + dlfb_set_register(bufptr, 0x20, + (char)(dev_info->base16 >> 16)); + bufptr = + dlfb_set_register(bufptr, 0x21, + (char)(dev_info->base16 >> 8)); + bufptr = + dlfb_set_register(bufptr, 0x22, + (char)(dev_info->base16)); + + bufptr = + dlfb_set_register(bufptr, 0x26, + (char)(dev_info->base8 >> 16)); + bufptr = + dlfb_set_register(bufptr, 0x27, + (char)(dev_info->base8 >> 8)); + bufptr = + dlfb_set_register(bufptr, 0x28, + (char)(dev_info->base8)); + + /* set video mode */ + vdata = (uint8_t *)&dlfb_video_modes[i]; + for (j = 0; j < 29; j++) + bufptr = dlfb_set_register(bufptr, j, vdata[j]); + + /* blank */ + bufptr = dlfb_set_register(bufptr, 0x1F, 0x00); + + /* end registers */ + bufptr = dlfb_set_register(bufptr, 0xFF, 0xFF); + + /* send */ + ret = dlfb_bulk_msg(dev_info, bufptr - dev_info->buf); + printk("ret bulk 2: %d %d\n", ret, + bufptr - dev_info->buf); + + /* flush */ + ret = dlfb_bulk_msg(dev_info, 0); + printk("ret bulk 3: %d\n", ret); + + dev_info->screen_size = width * height * (FB_BPP / 8); + dev_info->line_length = width * (FB_BPP / 8); + + return 0; + } + } + + return -1; +} + +#endif diff --git a/drivers/staging/vt6655/80211hdr.h b/drivers/staging/vt6655/80211hdr.h new file mode 100644 index 000000000000..b4bbb8d3c243 --- /dev/null +++ b/drivers/staging/vt6655/80211hdr.h @@ -0,0 +1,357 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * File: 80211hdr.h + * + * Purpose: Defines the macros, types, and functions for dealing + * with 802.11 MAC headers. + * + * Author: Lyndon Chen + * + * Date: Apr 8, 2002 + * + */ + + + +#ifndef __80211HDR_H__ +#define __80211HDR_H__ + + +#if !defined(__TTYPE_H__) +#include "ttype.h" +#endif + +/*--------------------- Export Definitions -------------------------*/ +// bit type +#define BIT0 0x00000001 +#define BIT1 0x00000002 +#define BIT2 0x00000004 +#define BIT3 0x00000008 +#define BIT4 0x00000010 +#define BIT5 0x00000020 +#define BIT6 0x00000040 +#define BIT7 0x00000080 +#define BIT8 0x00000100 +#define BIT9 0x00000200 +#define BIT10 0x00000400 +#define BIT11 0x00000800 +#define BIT12 0x00001000 +#define BIT13 0x00002000 +#define BIT14 0x00004000 +#define BIT15 0x00008000 +#define BIT16 0x00010000 +#define BIT17 0x00020000 +#define BIT18 0x00040000 +#define BIT19 0x00080000 +#define BIT20 0x00100000 +#define BIT21 0x00200000 +#define BIT22 0x00400000 +#define BIT23 0x00800000 +#define BIT24 0x01000000 +#define BIT25 0x02000000 +#define BIT26 0x04000000 +#define BIT27 0x08000000 +#define BIT28 0x10000000 +#define BIT29 0x20000000 +#define BIT30 0x40000000 +#define BIT31 0x80000000 + +// 802.11 frame related, defined as 802.11 spec +#define WLAN_ADDR_LEN 6 +#define WLAN_CRC_LEN 4 +#define WLAN_CRC32_LEN 4 +#define WLAN_FCS_LEN 4 +#define WLAN_BSSID_LEN 6 +#define WLAN_BSS_TS_LEN 8 +#define WLAN_HDR_ADDR2_LEN 16 +#define WLAN_HDR_ADDR3_LEN 24 +#define WLAN_HDR_ADDR4_LEN 30 +#define WLAN_IEHDR_LEN 2 +#define WLAN_SSID_MAXLEN 32 +//#define WLAN_RATES_MAXLEN 255 +#define WLAN_RATES_MAXLEN 16 +#define WLAN_RATES_MAXLEN_11B 4 +#define WLAN_RSN_MAXLEN 32 +#define WLAN_DATA_MAXLEN 2312 +#define WLAN_A3FR_MAXLEN (WLAN_HDR_ADDR3_LEN + WLAN_DATA_MAXLEN + WLAN_CRC_LEN) + + +#define WLAN_BEACON_FR_MAXLEN WLAN_A3FR_MAXLEN +#define WLAN_ATIM_FR_MAXLEN (WLAN_HDR_ADDR3_LEN + 0) +#define WLAN_NULLDATA_FR_MAXLEN (WLAN_HDR_ADDR3_LEN + 0) +#define WLAN_DISASSOC_FR_MAXLEN (WLAN_HDR_ADDR3_LEN + 2) +#define WLAN_ASSOCREQ_FR_MAXLEN WLAN_A3FR_MAXLEN +#define WLAN_ASSOCRESP_FR_MAXLEN WLAN_A3FR_MAXLEN +#define WLAN_REASSOCREQ_FR_MAXLEN WLAN_A3FR_MAXLEN +#define WLAN_REASSOCRESP_FR_MAXLEN WLAN_A3FR_MAXLEN +#define WLAN_PROBEREQ_FR_MAXLEN WLAN_A3FR_MAXLEN +#define WLAN_PROBERESP_FR_MAXLEN WLAN_A3FR_MAXLEN +#define WLAN_AUTHEN_FR_MAXLEN WLAN_A3FR_MAXLEN +#define WLAN_DEAUTHEN_FR_MAXLEN (WLAN_HDR_ADDR3_LEN + 2) + + +#define WLAN_WEP_NKEYS 4 +#define WLAN_WEP40_KEYLEN 5 +#define WLAN_WEP104_KEYLEN 13 +#define WLAN_WEP232_KEYLEN 29 +//#define WLAN_WEPMAX_KEYLEN 29 +#define WLAN_WEPMAX_KEYLEN 32 +#define WLAN_CHALLENGE_IE_MAXLEN 255 +#define WLAN_CHALLENGE_IE_LEN 130 +#define WLAN_CHALLENGE_LEN 128 +#define WLAN_WEP_IV_LEN 4 +#define WLAN_WEP_ICV_LEN 4 +#define WLAN_FRAGS_MAX 16 + +// Frame Type +#define WLAN_TYPE_MGR 0x00 +#define WLAN_TYPE_CTL 0x01 +#define WLAN_TYPE_DATA 0x02 + +#define WLAN_FTYPE_MGMT 0x00 +#define WLAN_FTYPE_CTL 0x01 +#define WLAN_FTYPE_DATA 0x02 + + +// Frame Subtypes +#define WLAN_FSTYPE_ASSOCREQ 0x00 +#define WLAN_FSTYPE_ASSOCRESP 0x01 +#define WLAN_FSTYPE_REASSOCREQ 0x02 +#define WLAN_FSTYPE_REASSOCRESP 0x03 +#define WLAN_FSTYPE_PROBEREQ 0x04 +#define WLAN_FSTYPE_PROBERESP 0x05 +#define WLAN_FSTYPE_BEACON 0x08 +#define WLAN_FSTYPE_ATIM 0x09 +#define WLAN_FSTYPE_DISASSOC 0x0a +#define WLAN_FSTYPE_AUTHEN 0x0b +#define WLAN_FSTYPE_DEAUTHEN 0x0c +#define WLAN_FSTYPE_ACTION 0x0d + +// Control +#define WLAN_FSTYPE_PSPOLL 0x0a +#define WLAN_FSTYPE_RTS 0x0b +#define WLAN_FSTYPE_CTS 0x0c +#define WLAN_FSTYPE_ACK 0x0d +#define WLAN_FSTYPE_CFEND 0x0e +#define WLAN_FSTYPE_CFENDCFACK 0x0f + +// Data +#define WLAN_FSTYPE_DATAONLY 0x00 +#define WLAN_FSTYPE_DATA_CFACK 0x01 +#define WLAN_FSTYPE_DATA_CFPOLL 0x02 +#define WLAN_FSTYPE_DATA_CFACK_CFPOLL 0x03 +#define WLAN_FSTYPE_NULL 0x04 +#define WLAN_FSTYPE_CFACK 0x05 +#define WLAN_FSTYPE_CFPOLL 0x06 +#define WLAN_FSTYPE_CFACK_CFPOLL 0x07 + + +#ifdef __BIG_ENDIAN + +// GET & SET Frame Control bit +#define WLAN_GET_FC_PRVER(n) ((((WORD)(n) >> 8) & (BIT0 | BIT1)) +#define WLAN_GET_FC_FTYPE(n) ((((WORD)(n) >> 8) & (BIT2 | BIT3)) >> 2) +#define WLAN_GET_FC_FSTYPE(n) ((((WORD)(n) >> 8) & (BIT4|BIT5|BIT6|BIT7)) >> 4) +#define WLAN_GET_FC_TODS(n) ((((WORD)(n) << 8) & (BIT8)) >> 8) +#define WLAN_GET_FC_FROMDS(n) ((((WORD)(n) << 8) & (BIT9)) >> 9) +#define WLAN_GET_FC_MOREFRAG(n) ((((WORD)(n) << 8) & (BIT10)) >> 10) +#define WLAN_GET_FC_RETRY(n) ((((WORD)(n) << 8) & (BIT11)) >> 11) +#define WLAN_GET_FC_PWRMGT(n) ((((WORD)(n) << 8) & (BIT12)) >> 12) +#define WLAN_GET_FC_MOREDATA(n) ((((WORD)(n) << 8) & (BIT13)) >> 13) +#define WLAN_GET_FC_ISWEP(n) ((((WORD)(n) << 8) & (BIT14)) >> 14) +#define WLAN_GET_FC_ORDER(n) ((((WORD)(n) << 8) & (BIT15)) >> 15) + +// Sequence Field bit +#define WLAN_GET_SEQ_FRGNUM(n) (((WORD)(n) >> 8) & (BIT0|BIT1|BIT2|BIT3)) +#define WLAN_GET_SEQ_SEQNUM(n) ((((WORD)(n) >> 8) & (~(BIT0|BIT1|BIT2|BIT3))) >> 4) + + +// Capability Field bit +#define WLAN_GET_CAP_INFO_ESS(n) (((n) >> 8) & BIT0) +#define WLAN_GET_CAP_INFO_IBSS(n) ((((n) >> 8) & BIT1) >> 1) +#define WLAN_GET_CAP_INFO_CFPOLLABLE(n) ((((n) >> 8) & BIT2) >> 2) +#define WLAN_GET_CAP_INFO_CFPOLLREQ(n) ((((n) >> 8) & BIT3) >> 3) +#define WLAN_GET_CAP_INFO_PRIVACY(n) ((((n) >> 8) & BIT4) >> 4) +#define WLAN_GET_CAP_INFO_SHORTPREAMBLE(n) ((((n) >> 8) & BIT5) >> 5) +#define WLAN_GET_CAP_INFO_PBCC(n) ((((n) >> 8) & BIT6) >> 6) +#define WLAN_GET_CAP_INFO_AGILITY(n) ((((n) >> 8) & BIT7) >> 7) +#define WLAN_GET_CAP_INFO_SPECTRUMMNG(n) ((((n)) & BIT8) >> 10) +#define WLAN_GET_CAP_INFO_SHORTSLOTTIME(n) ((((n)) & BIT10) >> 10) +#define WLAN_GET_CAP_INFO_DSSSOFDM(n) ((((n)) & BIT13) >> 13) +#define WLAN_GET_CAP_INFO_GRPACK(n) ((((n)) & BIT14) >> 14) + + +#else + +// GET & SET Frame Control bit +#define WLAN_GET_FC_PRVER(n) (((WORD)(n)) & (BIT0 | BIT1)) +#define WLAN_GET_FC_FTYPE(n) ((((WORD)(n)) & (BIT2 | BIT3)) >> 2) +#define WLAN_GET_FC_FSTYPE(n) ((((WORD)(n)) & (BIT4|BIT5|BIT6|BIT7)) >> 4) +#define WLAN_GET_FC_TODS(n) ((((WORD)(n)) & (BIT8)) >> 8) +#define WLAN_GET_FC_FROMDS(n) ((((WORD)(n)) & (BIT9)) >> 9) +#define WLAN_GET_FC_MOREFRAG(n) ((((WORD)(n)) & (BIT10)) >> 10) +#define WLAN_GET_FC_RETRY(n) ((((WORD)(n)) & (BIT11)) >> 11) +#define WLAN_GET_FC_PWRMGT(n) ((((WORD)(n)) & (BIT12)) >> 12) +#define WLAN_GET_FC_MOREDATA(n) ((((WORD)(n)) & (BIT13)) >> 13) +#define WLAN_GET_FC_ISWEP(n) ((((WORD)(n)) & (BIT14)) >> 14) +#define WLAN_GET_FC_ORDER(n) ((((WORD)(n)) & (BIT15)) >> 15) + + +// Sequence Field bit +#define WLAN_GET_SEQ_FRGNUM(n) (((WORD)(n)) & (BIT0|BIT1|BIT2|BIT3)) +#define WLAN_GET_SEQ_SEQNUM(n) ((((WORD)(n)) & (~(BIT0|BIT1|BIT2|BIT3))) >> 4) + + +// Capability Field bit +#define WLAN_GET_CAP_INFO_ESS(n) ((n) & BIT0) +#define WLAN_GET_CAP_INFO_IBSS(n) (((n) & BIT1) >> 1) +#define WLAN_GET_CAP_INFO_CFPOLLABLE(n) (((n) & BIT2) >> 2) +#define WLAN_GET_CAP_INFO_CFPOLLREQ(n) (((n) & BIT3) >> 3) +#define WLAN_GET_CAP_INFO_PRIVACY(n) (((n) & BIT4) >> 4) +#define WLAN_GET_CAP_INFO_SHORTPREAMBLE(n) (((n) & BIT5) >> 5) +#define WLAN_GET_CAP_INFO_PBCC(n) (((n) & BIT6) >> 6) +#define WLAN_GET_CAP_INFO_AGILITY(n) (((n) & BIT7) >> 7) +#define WLAN_GET_CAP_INFO_SPECTRUMMNG(n) (((n) & BIT8) >> 10) +#define WLAN_GET_CAP_INFO_SHORTSLOTTIME(n) (((n) & BIT10) >> 10) +#define WLAN_GET_CAP_INFO_DSSSOFDM(n) (((n) & BIT13) >> 13) +#define WLAN_GET_CAP_INFO_GRPACK(n) (((n) & BIT14) >> 14) + + +#endif //#ifdef __BIG_ENDIAN + + +#define WLAN_SET_CAP_INFO_ESS(n) (n) +#define WLAN_SET_CAP_INFO_IBSS(n) ((n) << 1) +#define WLAN_SET_CAP_INFO_CFPOLLABLE(n) ((n) << 2) +#define WLAN_SET_CAP_INFO_CFPOLLREQ(n) ((n) << 3) +#define WLAN_SET_CAP_INFO_PRIVACY(n) ((n) << 4) +#define WLAN_SET_CAP_INFO_SHORTPREAMBLE(n) ((n) << 5) +#define WLAN_SET_CAP_INFO_SPECTRUMMNG(n) ((n) << 8) +#define WLAN_SET_CAP_INFO_PBCC(n) ((n) << 6) +#define WLAN_SET_CAP_INFO_AGILITY(n) ((n) << 7) +#define WLAN_SET_CAP_INFO_SHORTSLOTTIME(n) ((n) << 10) +#define WLAN_SET_CAP_INFO_DSSSOFDM(n) ((n) << 13) +#define WLAN_SET_CAP_INFO_GRPACK(n) ((n) << 14) + + +#define WLAN_SET_FC_PRVER(n) ((WORD)(n)) +#define WLAN_SET_FC_FTYPE(n) (((WORD)(n)) << 2) +#define WLAN_SET_FC_FSTYPE(n) (((WORD)(n)) << 4) +#define WLAN_SET_FC_TODS(n) (((WORD)(n)) << 8) +#define WLAN_SET_FC_FROMDS(n) (((WORD)(n)) << 9) +#define WLAN_SET_FC_MOREFRAG(n) (((WORD)(n)) << 10) +#define WLAN_SET_FC_RETRY(n) (((WORD)(n)) << 11) +#define WLAN_SET_FC_PWRMGT(n) (((WORD)(n)) << 12) +#define WLAN_SET_FC_MOREDATA(n) (((WORD)(n)) << 13) +#define WLAN_SET_FC_ISWEP(n) (((WORD)(n)) << 14) +#define WLAN_SET_FC_ORDER(n) (((WORD)(n)) << 15) + +#define WLAN_SET_SEQ_FRGNUM(n) ((WORD)(n)) +#define WLAN_SET_SEQ_SEQNUM(n) (((WORD)(n)) << 4) + +// ERP Field bit + +#define WLAN_GET_ERP_NONERP_PRESENT(n) ((n) & BIT0) +#define WLAN_GET_ERP_USE_PROTECTION(n) (((n) & BIT1) >> 1) +#define WLAN_GET_ERP_BARKER_MODE(n) (((n) & BIT2) >> 2) + +#define WLAN_SET_ERP_NONERP_PRESENT(n) (n) +#define WLAN_SET_ERP_USE_PROTECTION(n) ((n) << 1) +#define WLAN_SET_ERP_BARKER_MODE(n) ((n) << 2) + + + +// Support & Basic Rates field +#define WLAN_MGMT_IS_BASICRATE(b) ((b) & BIT7) +#define WLAN_MGMT_GET_RATE(b) ((b) & ~BIT7) + +// TIM field +#define WLAN_MGMT_IS_MULTICAST_TIM(b) ((b) & BIT0) +#define WLAN_MGMT_GET_TIM_OFFSET(b) (((b) & ~BIT0) >> 1) + +// 3-Addr & 4-Addr +#define WLAN_HDR_A3_DATA_PTR(p) (((PBYTE)(p)) + WLAN_HDR_ADDR3_LEN) +#define WLAN_HDR_A4_DATA_PTR(p) (((PBYTE)(p)) + WLAN_HDR_ADDR4_LEN) + +// IEEE ADDR +#define IEEE_ADDR_UNIVERSAL 0x02 +#define IEEE_ADDR_GROUP 0x01 + +typedef struct { + BYTE abyAddr[6]; +} IEEE_ADDR, *PIEEE_ADDR; + +// 802.11 Header Format + +typedef struct tagWLAN_80211HDR_A2 { + + WORD wFrameCtl; + WORD wDurationID; + BYTE abyAddr1[WLAN_ADDR_LEN]; + BYTE abyAddr2[WLAN_ADDR_LEN]; + +}__attribute__ ((__packed__)) +WLAN_80211HDR_A2, *PWLAN_80211HDR_A2; + +typedef struct tagWLAN_80211HDR_A3 { + + WORD wFrameCtl; + WORD wDurationID; + BYTE abyAddr1[WLAN_ADDR_LEN]; + BYTE abyAddr2[WLAN_ADDR_LEN]; + BYTE abyAddr3[WLAN_ADDR_LEN]; + WORD wSeqCtl; + +}__attribute__ ((__packed__)) +WLAN_80211HDR_A3, *PWLAN_80211HDR_A3; + +typedef struct tagWLAN_80211HDR_A4 { + + WORD wFrameCtl; + WORD wDurationID; + BYTE abyAddr1[WLAN_ADDR_LEN]; + BYTE abyAddr2[WLAN_ADDR_LEN]; + BYTE abyAddr3[WLAN_ADDR_LEN]; + WORD wSeqCtl; + BYTE abyAddr4[WLAN_ADDR_LEN]; + +}__attribute__ ((__packed__)) +WLAN_80211HDR_A4, *PWLAN_80211HDR_A4; + + +typedef union tagUWLAN_80211HDR { + + WLAN_80211HDR_A2 sA2; + WLAN_80211HDR_A3 sA3; + WLAN_80211HDR_A4 sA4; + +} UWLAN_80211HDR, *PUWLAN_80211HDR; + + +/*--------------------- Export Classes ----------------------------*/ + +/*--------------------- Export Variables --------------------------*/ + +/*--------------------- Export Functions --------------------------*/ + + + +#endif // __80211HDR_H__ + + diff --git a/drivers/staging/vt6655/80211mgr.c b/drivers/staging/vt6655/80211mgr.c new file mode 100644 index 000000000000..84745fb6b035 --- /dev/null +++ b/drivers/staging/vt6655/80211mgr.c @@ -0,0 +1,1050 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * File: 80211mgr.c + * + * Purpose: Handles the 802.11 managment support functions + * + * Author: Lyndon Chen + * + * Date: May 8, 2002 + * + * Functions: + * vMgrEncodeBeacon - Encode the Beacon frame + * vMgrDecodeBeacon - Decode the Beacon frame + * vMgrEncodeIBSSATIM - Encode the IBSS ATIM frame + * vMgrDecodeIBSSATIM - Decode the IBSS ATIM frame + * vMgrEncodeDisassociation - Encode the Disassociation frame + * vMgrDecodeDisassociation - Decode the Disassociation frame + * vMgrEncodeAssocRequest - Encode the Association request frame + * vMgrDecodeAssocRequest - Decode the Association request frame + * vMgrEncodeAssocResponse - Encode the Association response frame + * vMgrDecodeAssocResponse - Decode the Association response frame + * vMgrEncodeReAssocRequest - Encode the ReAssociation request frame + * vMgrDecodeReAssocRequest - Decode the ReAssociation request frame + * vMgrEncodeProbeRequest - Encode the Probe request frame + * vMgrDecodeProbeRequest - Decode the Probe request frame + * vMgrEncodeProbeResponse - Encode the Probe response frame + * vMgrDecodeProbeResponse - Decode the Probe response frame + * vMgrEncodeAuthen - Encode the Authentication frame + * vMgrDecodeAuthen - Decode the Authentication frame + * vMgrEncodeDeauthen - Encode the DeAuthentication frame + * vMgrDecodeDeauthen - Decode the DeAuthentication frame + * vMgrEncodeReassocResponse - Encode the Reassociation response frame + * vMgrDecodeReassocResponse - Decode the Reassociation response frame + * + * Revision History: + * + */ + + + +#if !defined(__TMACRO_H__) +#include "tmacro.h" +#endif +#if !defined(__TETHER_H__) +#include "tether.h" +#endif +#if !defined(__80211MGR_H__) +#include "80211mgr.h" +#endif +#if !defined(__80211HDR_H__) +#include "80211hdr.h" +#endif +#if !defined(__DEVICE_H__) +#include "device.h" +#endif +#if !defined(__WPA_H__) +#include "wpa.h" +#endif + + + +/*--------------------- Static Definitions -------------------------*/ + + + +/*--------------------- Static Classes ----------------------------*/ + +/*--------------------- Static Variables --------------------------*/ + +static int msglevel =MSG_LEVEL_INFO; +//static int msglevel =MSG_LEVEL_DEBUG; +/*--------------------- Static Functions --------------------------*/ + + + +/*--------------------- Export Variables --------------------------*/ + + +/*--------------------- Export Functions --------------------------*/ + + +/*+ + * + * Routine Description: + * Encode Beacon frame body offset + * + * Return Value: + * None. + * +-*/ + +VOID +vMgrEncodeBeacon( + IN PWLAN_FR_BEACON pFrame + ) +{ + pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf; + + // Fixed Fields + pFrame->pqwTimestamp = (PQWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + + WLAN_BEACON_OFF_TS); + pFrame->pwBeaconInterval = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + + WLAN_BEACON_OFF_BCN_INT); + pFrame->pwCapInfo = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + + WLAN_BEACON_OFF_CAPINFO); + + pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_BEACON_OFF_SSID; + + return; +} + +/*+ + * + * Routine Description: + * Decode Beacon frame body offset + * + * + * Return Value: + * None. + * +-*/ + + +VOID +vMgrDecodeBeacon( + IN PWLAN_FR_BEACON pFrame + ) +{ + PWLAN_IE pItem; + + pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf; + + // Fixed Fields + pFrame->pqwTimestamp = (PQWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + + WLAN_BEACON_OFF_TS); + pFrame->pwBeaconInterval = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + + WLAN_BEACON_OFF_BCN_INT); + pFrame->pwCapInfo = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + + WLAN_BEACON_OFF_CAPINFO); + + // Information elements + pItem = (PWLAN_IE)((PBYTE)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))) + + WLAN_BEACON_OFF_SSID); + while( ((PBYTE)pItem) < (pFrame->pBuf + pFrame->len) ){ + + switch (pItem->byElementID) { + case WLAN_EID_SSID: + if (pFrame->pSSID == NULL) + pFrame->pSSID = (PWLAN_IE_SSID)pItem; + break; + case WLAN_EID_SUPP_RATES: + if (pFrame->pSuppRates == NULL) + pFrame->pSuppRates = (PWLAN_IE_SUPP_RATES)pItem; + break; + case WLAN_EID_FH_PARMS: + //pFrame->pFHParms = (PWLAN_IE_FH_PARMS)pItem; + break; + case WLAN_EID_DS_PARMS: + if (pFrame->pDSParms == NULL) + pFrame->pDSParms = (PWLAN_IE_DS_PARMS)pItem; + break; + case WLAN_EID_CF_PARMS: + if (pFrame->pCFParms == NULL) + pFrame->pCFParms = (PWLAN_IE_CF_PARMS)pItem; + break; + case WLAN_EID_IBSS_PARMS: + if (pFrame->pIBSSParms == NULL) + pFrame->pIBSSParms = (PWLAN_IE_IBSS_PARMS)pItem; + break; + case WLAN_EID_TIM: + if (pFrame->pTIM == NULL) + pFrame->pTIM = (PWLAN_IE_TIM)pItem; + break; + + case WLAN_EID_RSN: + if (pFrame->pRSN == NULL) { + pFrame->pRSN = (PWLAN_IE_RSN)pItem; + } + break; + case WLAN_EID_RSN_WPA: + if (pFrame->pRSNWPA == NULL) { + if (WPAb_Is_RSN((PWLAN_IE_RSN_EXT)pItem) == TRUE) + pFrame->pRSNWPA = (PWLAN_IE_RSN_EXT)pItem; + } + break; + + case WLAN_EID_ERP: + if (pFrame->pERP == NULL) + pFrame->pERP = (PWLAN_IE_ERP)pItem; + break; + case WLAN_EID_EXTSUPP_RATES: + if (pFrame->pExtSuppRates == NULL) + pFrame->pExtSuppRates = (PWLAN_IE_SUPP_RATES)pItem; + break; + + case WLAN_EID_COUNTRY: //7 + if (pFrame->pIE_Country == NULL) + pFrame->pIE_Country = (PWLAN_IE_COUNTRY)pItem; + break; + + case WLAN_EID_PWR_CONSTRAINT: //32 + if (pFrame->pIE_PowerConstraint == NULL) + pFrame->pIE_PowerConstraint = (PWLAN_IE_PW_CONST)pItem; + break; + + case WLAN_EID_CH_SWITCH: //37 + if (pFrame->pIE_CHSW == NULL) + pFrame->pIE_CHSW = (PWLAN_IE_CH_SW)pItem; + break; + + case WLAN_EID_QUIET: //40 + if (pFrame->pIE_Quiet == NULL) + pFrame->pIE_Quiet = (PWLAN_IE_QUIET)pItem; + break; + + case WLAN_EID_IBSS_DFS: + if (pFrame->pIE_IBSSDFS == NULL) + pFrame->pIE_IBSSDFS = (PWLAN_IE_IBSS_DFS)pItem; + break; + + default: + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Unrecognized EID=%dd in beacon decode.\n", pItem->byElementID); + break; + + } + pItem = (PWLAN_IE)(((PBYTE)pItem) + 2 + pItem->len); + } + + return; +} + + +/*+ + * + * Routine Description: + * Encode IBSS ATIM + * + * + * Return Value: + * None. + * +-*/ + + +VOID +vMgrEncodeIBSSATIM( + IN PWLAN_FR_IBSSATIM pFrame + ) +{ + pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf; + pFrame->len = WLAN_HDR_ADDR3_LEN; + + return; +} + + +/*+ + * + * Routine Description: + * Decode IBSS ATIM + * + * + * Return Value: + * None. + * +-*/ + +VOID +vMgrDecodeIBSSATIM( + IN PWLAN_FR_IBSSATIM pFrame + ) +{ + pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf; + + return; +} + + +/*+ + * + * Routine Description: + * Encode Disassociation + * + * + * Return Value: + * None. + * +-*/ + +VOID +vMgrEncodeDisassociation( + IN PWLAN_FR_DISASSOC pFrame + ) +{ + pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf; + + + // Fixed Fields + pFrame->pwReason = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + + WLAN_DISASSOC_OFF_REASON); + pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_DISASSOC_OFF_REASON + sizeof(*(pFrame->pwReason)); + + return; +} + + +/*+ + * + * Routine Description: + * Decode Disassociation + * + * + * Return Value: + * None. + * +-*/ + +VOID +vMgrDecodeDisassociation( + IN PWLAN_FR_DISASSOC pFrame + ) +{ + pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf; + + // Fixed Fields + pFrame->pwReason = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + + WLAN_DISASSOC_OFF_REASON); + + return; +} + +/*+ + * + * Routine Description: + * Encode Association Request + * + * + * Return Value: + * None. + * +-*/ + + +VOID +vMgrEncodeAssocRequest( + IN PWLAN_FR_ASSOCREQ pFrame + ) +{ + pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf; + // Fixed Fields + pFrame->pwCapInfo = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + + WLAN_ASSOCREQ_OFF_CAP_INFO); + pFrame->pwListenInterval = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + + WLAN_ASSOCREQ_OFF_LISTEN_INT); + pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_ASSOCREQ_OFF_LISTEN_INT + sizeof(*(pFrame->pwListenInterval)); + return; +} + + +/*+ + * + * Routine Description: (AP) + * Decode Association Request + * + * + * Return Value: + * None. + * +-*/ + +VOID +vMgrDecodeAssocRequest( + IN PWLAN_FR_ASSOCREQ pFrame + ) +{ + PWLAN_IE pItem; + + pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf; + // Fixed Fields + pFrame->pwCapInfo = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + + WLAN_ASSOCREQ_OFF_CAP_INFO); + pFrame->pwListenInterval = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + + WLAN_ASSOCREQ_OFF_LISTEN_INT); + + // Information elements + pItem = (PWLAN_IE)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + + WLAN_ASSOCREQ_OFF_SSID); + + while (((PBYTE)pItem) < (pFrame->pBuf + pFrame->len)) { + switch (pItem->byElementID){ + case WLAN_EID_SSID: + if (pFrame->pSSID == NULL) + pFrame->pSSID = (PWLAN_IE_SSID)pItem; + break; + case WLAN_EID_SUPP_RATES: + if (pFrame->pSuppRates == NULL) + pFrame->pSuppRates = (PWLAN_IE_SUPP_RATES)pItem; + break; + + case WLAN_EID_RSN: + if (pFrame->pRSN == NULL) { + pFrame->pRSN = (PWLAN_IE_RSN)pItem; + } + break; + case WLAN_EID_RSN_WPA: + if (pFrame->pRSNWPA == NULL) { + if (WPAb_Is_RSN((PWLAN_IE_RSN_EXT)pItem) == TRUE) + pFrame->pRSNWPA = (PWLAN_IE_RSN_EXT)pItem; + } + break; + case WLAN_EID_EXTSUPP_RATES: + if (pFrame->pExtSuppRates == NULL) + pFrame->pExtSuppRates = (PWLAN_IE_SUPP_RATES)pItem; + break; + + default: + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Unrecognized EID=%dd in assocreq decode.\n", + pItem->byElementID); + break; + } + pItem = (PWLAN_IE)(((PBYTE)pItem) + 2 + pItem->len); + } + return; +} + +/*+ + * + * Routine Description: (AP) + * Encode Association Response + * + * + * Return Value: + * None. + * +-*/ + +VOID +vMgrEncodeAssocResponse( + IN PWLAN_FR_ASSOCRESP pFrame + ) +{ + pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf; + + // Fixed Fields + pFrame->pwCapInfo = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + + WLAN_ASSOCRESP_OFF_CAP_INFO); + pFrame->pwStatus = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + + WLAN_ASSOCRESP_OFF_STATUS); + pFrame->pwAid = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + + WLAN_ASSOCRESP_OFF_AID); + pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_ASSOCRESP_OFF_AID + + sizeof(*(pFrame->pwAid)); + + return; +} + + +/*+ + * + * Routine Description: + * Decode Association Response + * + * + * Return Value: + * None. + * +-*/ + +VOID +vMgrDecodeAssocResponse( + IN PWLAN_FR_ASSOCRESP pFrame + ) +{ + PWLAN_IE pItem; + + pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf; + + // Fixed Fields + pFrame->pwCapInfo = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + + WLAN_ASSOCRESP_OFF_CAP_INFO); + pFrame->pwStatus = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + + WLAN_ASSOCRESP_OFF_STATUS); + pFrame->pwAid = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + + WLAN_ASSOCRESP_OFF_AID); + + // Information elements + pFrame->pSuppRates = (PWLAN_IE_SUPP_RATES)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + + WLAN_ASSOCRESP_OFF_SUPP_RATES); + + pItem = (PWLAN_IE)(pFrame->pSuppRates); + pItem = (PWLAN_IE)(((PBYTE)pItem) + 2 + pItem->len); + + if ((((PBYTE)pItem) < (pFrame->pBuf + pFrame->len)) && (pItem->byElementID == WLAN_EID_EXTSUPP_RATES)) { + pFrame->pExtSuppRates = (PWLAN_IE_SUPP_RATES)pItem; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pFrame->pExtSuppRates=[%p].\n", pItem); + } + else { + pFrame->pExtSuppRates = NULL; + } + return; +} + + +/*+ + * + * Routine Description: + * Encode Reassociation Request + * + * + * Return Value: + * None. + * +-*/ + +VOID +vMgrEncodeReassocRequest( + IN PWLAN_FR_REASSOCREQ pFrame + ) +{ + pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf; + + // Fixed Fields + pFrame->pwCapInfo = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + + WLAN_REASSOCREQ_OFF_CAP_INFO); + pFrame->pwListenInterval = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + + WLAN_REASSOCREQ_OFF_LISTEN_INT); + pFrame->pAddrCurrAP = (PIEEE_ADDR)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + + WLAN_REASSOCREQ_OFF_CURR_AP); + pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_REASSOCREQ_OFF_CURR_AP + sizeof(*(pFrame->pAddrCurrAP)); + + return; +} + + +/*+ + * + * Routine Description: (AP) + * Decode Reassociation Request + * + * + * Return Value: + * None. + * +-*/ + + +VOID +vMgrDecodeReassocRequest( + IN PWLAN_FR_REASSOCREQ pFrame + ) +{ + PWLAN_IE pItem; + pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf; + + // Fixed Fields + pFrame->pwCapInfo = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + + WLAN_REASSOCREQ_OFF_CAP_INFO); + pFrame->pwListenInterval = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + + WLAN_REASSOCREQ_OFF_LISTEN_INT); + pFrame->pAddrCurrAP = (PIEEE_ADDR)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + + WLAN_REASSOCREQ_OFF_CURR_AP); + + // Information elements + pItem = (PWLAN_IE)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + + WLAN_REASSOCREQ_OFF_SSID); + + while(((PBYTE)pItem) < (pFrame->pBuf + pFrame->len)) { + + switch (pItem->byElementID){ + case WLAN_EID_SSID: + if (pFrame->pSSID == NULL) + pFrame->pSSID = (PWLAN_IE_SSID)pItem; + break; + case WLAN_EID_SUPP_RATES: + if (pFrame->pSuppRates == NULL) + pFrame->pSuppRates = (PWLAN_IE_SUPP_RATES)pItem; + break; + + case WLAN_EID_RSN: + if (pFrame->pRSN == NULL) { + pFrame->pRSN = (PWLAN_IE_RSN)pItem; + } + break; + case WLAN_EID_RSN_WPA: + if (pFrame->pRSNWPA == NULL) { + if (WPAb_Is_RSN((PWLAN_IE_RSN_EXT)pItem) == TRUE) + pFrame->pRSNWPA = (PWLAN_IE_RSN_EXT)pItem; + } + break; + + case WLAN_EID_EXTSUPP_RATES: + if (pFrame->pExtSuppRates == NULL) + pFrame->pExtSuppRates = (PWLAN_IE_SUPP_RATES)pItem; + break; + default: + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Unrecognized EID=%dd in reassocreq decode.\n", + pItem->byElementID); + break; + } + pItem = (PWLAN_IE)(((PBYTE)pItem) + 2 + pItem->len); + } + return; +} + + + +/*+ + * + * Routine Description: + * Encode Probe Request + * + * + * Return Value: + * None. + * +-*/ + + +VOID +vMgrEncodeProbeRequest( + IN PWLAN_FR_PROBEREQ pFrame + ) +{ + pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf; + pFrame->len = WLAN_HDR_ADDR3_LEN; + return; +} + +/*+ + * + * Routine Description: + * Decode Probe Request + * + * + * Return Value: + * None. + * +-*/ + +VOID +vMgrDecodeProbeRequest( + IN PWLAN_FR_PROBEREQ pFrame + ) +{ + PWLAN_IE pItem; + + pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf; + + // Information elements + pItem = (PWLAN_IE)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))); + + while( ((PBYTE)pItem) < (pFrame->pBuf + pFrame->len) ) { + + switch (pItem->byElementID) { + case WLAN_EID_SSID: + if (pFrame->pSSID == NULL) + pFrame->pSSID = (PWLAN_IE_SSID)pItem; + break; + + case WLAN_EID_SUPP_RATES: + if (pFrame->pSuppRates == NULL) + pFrame->pSuppRates = (PWLAN_IE_SUPP_RATES)pItem; + break; + + case WLAN_EID_EXTSUPP_RATES: + if (pFrame->pExtSuppRates == NULL) + pFrame->pExtSuppRates = (PWLAN_IE_SUPP_RATES)pItem; + break; + + default: + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Bad EID=%dd in probereq\n", pItem->byElementID); + break; + } + + pItem = (PWLAN_IE)(((PBYTE)pItem) + 2 + pItem->len); + } + return; +} + + +/*+ + * + * Routine Description: + * Encode Probe Response + * + * + * Return Value: + * None. + * +-*/ + + +VOID +vMgrEncodeProbeResponse( + IN PWLAN_FR_PROBERESP pFrame + ) +{ + pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf; + + // Fixed Fields + pFrame->pqwTimestamp = (PQWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + + WLAN_PROBERESP_OFF_TS); + pFrame->pwBeaconInterval = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + + WLAN_PROBERESP_OFF_BCN_INT); + pFrame->pwCapInfo = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + + WLAN_PROBERESP_OFF_CAP_INFO); + + pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_PROBERESP_OFF_CAP_INFO + + sizeof(*(pFrame->pwCapInfo)); + + return; +} + + + +/*+ + * + * Routine Description: + * Decode Probe Response + * + * + * Return Value: + * None. + * +-*/ + +VOID +vMgrDecodeProbeResponse( + IN PWLAN_FR_PROBERESP pFrame + ) +{ + PWLAN_IE pItem; +// BYTE byCheckEID = 0; + + + pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf; + + // Fixed Fields + pFrame->pqwTimestamp = (PQWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + + WLAN_PROBERESP_OFF_TS); + pFrame->pwBeaconInterval = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + + WLAN_PROBERESP_OFF_BCN_INT); + pFrame->pwCapInfo = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + + WLAN_PROBERESP_OFF_CAP_INFO); + + // Information elements + pItem = (PWLAN_IE)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + + WLAN_PROBERESP_OFF_SSID); + + while( ((PBYTE)pItem) < (pFrame->pBuf + pFrame->len) ) { + /* + if (pItem->byElementID < byCheckEID) + break; + else + byCheckEID = pItem->byElementID; +*/ + switch (pItem->byElementID) { + case WLAN_EID_SSID: + if (pFrame->pSSID == NULL) + pFrame->pSSID = (PWLAN_IE_SSID)pItem; + break; + case WLAN_EID_SUPP_RATES: + if (pFrame->pSuppRates == NULL) + pFrame->pSuppRates = (PWLAN_IE_SUPP_RATES)pItem; + break; + case WLAN_EID_FH_PARMS: + break; + case WLAN_EID_DS_PARMS: + if (pFrame->pDSParms == NULL) + pFrame->pDSParms = (PWLAN_IE_DS_PARMS)pItem; + break; + case WLAN_EID_CF_PARMS: + if (pFrame->pCFParms == NULL) + pFrame->pCFParms = (PWLAN_IE_CF_PARMS)pItem; + break; + case WLAN_EID_IBSS_PARMS: + if (pFrame->pIBSSParms == NULL) + pFrame->pIBSSParms = (PWLAN_IE_IBSS_PARMS)pItem; + break; + + case WLAN_EID_RSN: + if (pFrame->pRSN == NULL) { + pFrame->pRSN = (PWLAN_IE_RSN)pItem; + } + break; + case WLAN_EID_RSN_WPA: + if (pFrame->pRSNWPA == NULL) { + if (WPAb_Is_RSN((PWLAN_IE_RSN_EXT)pItem) == TRUE) + pFrame->pRSNWPA = (PWLAN_IE_RSN_EXT)pItem; + } + break; + case WLAN_EID_ERP: + if (pFrame->pERP == NULL) + pFrame->pERP = (PWLAN_IE_ERP)pItem; + break; + case WLAN_EID_EXTSUPP_RATES: + if (pFrame->pExtSuppRates == NULL) + pFrame->pExtSuppRates = (PWLAN_IE_SUPP_RATES)pItem; + break; + + case WLAN_EID_COUNTRY: //7 + if (pFrame->pIE_Country == NULL) + pFrame->pIE_Country = (PWLAN_IE_COUNTRY)pItem; + break; + + case WLAN_EID_PWR_CONSTRAINT: //32 + if (pFrame->pIE_PowerConstraint == NULL) + pFrame->pIE_PowerConstraint = (PWLAN_IE_PW_CONST)pItem; + break; + + case WLAN_EID_CH_SWITCH: //37 + if (pFrame->pIE_CHSW == NULL) + pFrame->pIE_CHSW = (PWLAN_IE_CH_SW)pItem; + break; + + case WLAN_EID_QUIET: //40 + if (pFrame->pIE_Quiet == NULL) + pFrame->pIE_Quiet = (PWLAN_IE_QUIET)pItem; + break; + + case WLAN_EID_IBSS_DFS: + if (pFrame->pIE_IBSSDFS == NULL) + pFrame->pIE_IBSSDFS = (PWLAN_IE_IBSS_DFS)pItem; + break; + + default: + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Bad EID=%dd in proberesp\n", pItem->byElementID); + break; + } + + pItem = (PWLAN_IE)(((PBYTE)pItem) + 2 + pItem->len); + } + return; +} + + +/*+ + * + * Routine Description: + * Encode Authentication frame + * + * + * Return Value: + * None. + * +-*/ + +VOID +vMgrEncodeAuthen( + IN PWLAN_FR_AUTHEN pFrame + ) +{ + pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf; + + // Fixed Fields + pFrame->pwAuthAlgorithm = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + + WLAN_AUTHEN_OFF_AUTH_ALG); + pFrame->pwAuthSequence = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + + WLAN_AUTHEN_OFF_AUTH_SEQ); + pFrame->pwStatus = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + + WLAN_AUTHEN_OFF_STATUS); + pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_AUTHEN_OFF_STATUS + sizeof(*(pFrame->pwStatus)); + + return; +} + + +/*+ + * + * Routine Description: + * Decode Authentication + * + * + * Return Value: + * None. + * +-*/ + +VOID +vMgrDecodeAuthen( + IN PWLAN_FR_AUTHEN pFrame + ) +{ + PWLAN_IE pItem; + + pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf; + + // Fixed Fields + pFrame->pwAuthAlgorithm = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + + WLAN_AUTHEN_OFF_AUTH_ALG); + pFrame->pwAuthSequence = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + + WLAN_AUTHEN_OFF_AUTH_SEQ); + pFrame->pwStatus = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + + WLAN_AUTHEN_OFF_STATUS); + + // Information elements + pItem = (PWLAN_IE)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + + WLAN_AUTHEN_OFF_CHALLENGE); + + if ((((PBYTE)pItem) < (pFrame->pBuf + pFrame->len)) && (pItem->byElementID == WLAN_EID_CHALLENGE)) { + pFrame->pChallenge = (PWLAN_IE_CHALLENGE)pItem; + } + + return; +} + + +/*+ + * + * Routine Description: + * Encode Authentication + * + * + * Return Value: + * None. + * +-*/ + +VOID +vMgrEncodeDeauthen( + IN PWLAN_FR_DEAUTHEN pFrame + ) +{ + pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf; + + // Fixed Fields + pFrame->pwReason = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + + WLAN_DEAUTHEN_OFF_REASON); + pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_DEAUTHEN_OFF_REASON + sizeof(*(pFrame->pwReason)); + + return; +} + + +/*+ + * + * Routine Description: + * Decode Deauthentication + * + * + * Return Value: + * None. + * +-*/ + +VOID +vMgrDecodeDeauthen( + IN PWLAN_FR_DEAUTHEN pFrame + ) +{ + pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf; + + // Fixed Fields + pFrame->pwReason = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + + WLAN_DEAUTHEN_OFF_REASON); + + return; +} + + +/*+ + * + * Routine Description: (AP) + * Encode Reassociation Response + * + * + * Return Value: + * None. + * +-*/ + +VOID +vMgrEncodeReassocResponse( + IN PWLAN_FR_REASSOCRESP pFrame + ) +{ + pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf; + + // Fixed Fields + pFrame->pwCapInfo = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + + WLAN_REASSOCRESP_OFF_CAP_INFO); + pFrame->pwStatus = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + + WLAN_REASSOCRESP_OFF_STATUS); + pFrame->pwAid = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + + WLAN_REASSOCRESP_OFF_AID); + + pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_REASSOCRESP_OFF_AID + sizeof(*(pFrame->pwAid)); + + return; +} + + +/*+ + * + * Routine Description: + * Decode Reassociation Response + * + * + * Return Value: + * None. + * +-*/ + + +VOID +vMgrDecodeReassocResponse( + IN PWLAN_FR_REASSOCRESP pFrame + ) +{ + PWLAN_IE pItem; + + pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf; + + // Fixed Fields + pFrame->pwCapInfo = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + + WLAN_REASSOCRESP_OFF_CAP_INFO); + pFrame->pwStatus = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + + WLAN_REASSOCRESP_OFF_STATUS); + pFrame->pwAid = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + + WLAN_REASSOCRESP_OFF_AID); + + //Information elements + pFrame->pSuppRates = (PWLAN_IE_SUPP_RATES)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) + + WLAN_REASSOCRESP_OFF_SUPP_RATES); + + pItem = (PWLAN_IE)(pFrame->pSuppRates); + pItem = (PWLAN_IE)(((PBYTE)pItem) + 2 + pItem->len); + + if ((((PBYTE)pItem) < (pFrame->pBuf + pFrame->len)) && (pItem->byElementID == WLAN_EID_EXTSUPP_RATES)) { + pFrame->pExtSuppRates = (PWLAN_IE_SUPP_RATES)pItem; + } + return; +} diff --git a/drivers/staging/vt6655/80211mgr.h b/drivers/staging/vt6655/80211mgr.h new file mode 100644 index 000000000000..dc54a65edab5 --- /dev/null +++ b/drivers/staging/vt6655/80211mgr.h @@ -0,0 +1,832 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * File: 80211mgr.h + * + * Purpose: Defines the macros, types, and functions for dealing + * with 802.11 managment frames. + * + * Author: Lyndon Chen + * + * Date: May 8, 2002 + * + */ + + +#ifndef __80211MGR_H__ +#define __80211MGR_H__ + +#if !defined(__TTYPE_H__) +#include "ttype.h" +#endif +#if !defined(__80211HDR_H__) +#include "80211hdr.h" +#endif + + +/*--------------------- Export Definitions -------------------------*/ + +#define WLAN_MIN_ARRAY 1 + +// Information Element ID value +#define WLAN_EID_SSID 0 +#define WLAN_EID_SUPP_RATES 1 +#define WLAN_EID_FH_PARMS 2 +#define WLAN_EID_DS_PARMS 3 +#define WLAN_EID_CF_PARMS 4 +#define WLAN_EID_TIM 5 +#define WLAN_EID_IBSS_PARMS 6 +#define WLAN_EID_COUNTRY 7 +#define WLAN_EID_CHALLENGE 16 +#define WLAN_EID_PWR_CONSTRAINT 32 +#define WLAN_EID_PWR_CAPABILITY 33 +#define WLAN_EID_TPC_REQ 34 +#define WLAN_EID_TPC_REP 35 +#define WLAN_EID_SUPP_CH 36 +#define WLAN_EID_CH_SWITCH 37 +#define WLAN_EID_MEASURE_REQ 38 +#define WLAN_EID_MEASURE_REP 39 +#define WLAN_EID_QUIET 40 +#define WLAN_EID_IBSS_DFS 41 +#define WLAN_EID_ERP 42 +// reference 802.11i 7.3.2 table 20 +#define WLAN_EID_RSN 48 +#define WLAN_EID_EXTSUPP_RATES 50 +// reference WiFi WPA spec. +#define WLAN_EID_RSN_WPA 221 + + +#define WLAN_EID_ERP_NONERP_PRESENT 0x01 +#define WLAN_EID_ERP_USE_PROTECTION 0x02 +#define WLAN_EID_ERP_BARKER_MODE 0x04 + +// Reason Codes +#define WLAN_MGMT_REASON_RSVD 0 +#define WLAN_MGMT_REASON_UNSPEC 1 +#define WLAN_MGMT_REASON_PRIOR_AUTH_INVALID 2 +#define WLAN_MGMT_REASON_DEAUTH_LEAVING 3 +#define WLAN_MGMT_REASON_DISASSOC_INACTIVE 4 +#define WLAN_MGMT_REASON_DISASSOC_AP_BUSY 5 +#define WLAN_MGMT_REASON_CLASS2_NONAUTH 6 +#define WLAN_MGMT_REASON_CLASS3_NONASSOC 7 +#define WLAN_MGMT_REASON_DISASSOC_STA_HASLEFT 8 +#define WLAN_MGMT_REASON_CANT_ASSOC_NONAUTH 9 +#define WLAN_MGMT_REASON_DISASSOC_PWR_CAP_UNACCEPT 10 +#define WLAN_MGMT_REASON_DISASSOC_SUPP_CH_UNACCEPT 11 +#define WLAN_MGMT_REASON_INVALID_IE 13 +#define WLAN_MGMT_REASON_MIC_FAILURE 14 +#define WLAN_MGMT_REASON_4WAY_HANDSHAKE_TIMEOUT 15 +#define WLAN_MGMT_REASON_GRPKEY_UPDATE_TIMEOUT 16 +#define WLAN_MGMT_REASON_4WAY_INFO_DIFFERENT 17 +#define WLAN_MGMT_REASON_MULTCAST_CIPHER_INVALID 18 +#define WLAN_MGMT_REASON_UNCAST_CIPHER_INVALID 19 +#define WLAN_MGMT_REASON_AKMP_INVALID 20 +#define WLAN_MGMT_REASON_RSNE_UNSUPPORTED 21 +#define WLAN_MGMT_REASON_RSNE_CAP_INVALID 22 +#define WLAN_MGMT_REASON_80211X_AUTH_FAILED 23 + +// Status Codes +#define WLAN_MGMT_STATUS_SUCCESS 0 +#define WLAN_MGMT_STATUS_UNSPEC_FAILURE 1 +#define WLAN_MGMT_STATUS_CAPS_UNSUPPORTED 10 +#define WLAN_MGMT_STATUS_REASSOC_NO_ASSOC 11 +#define WLAN_MGMT_STATUS_ASSOC_DENIED_UNSPEC 12 +#define WLAN_MGMT_STATUS_UNSUPPORTED_AUTHALG 13 +#define WLAN_MGMT_STATUS_RX_AUTH_NOSEQ 14 +#define WLAN_MGMT_STATUS_CHALLENGE_FAIL 15 +#define WLAN_MGMT_STATUS_AUTH_TIMEOUT 16 +#define WLAN_MGMT_STATUS_ASSOC_DENIED_BUSY 17 +#define WLAN_MGMT_STATUS_ASSOC_DENIED_RATES 18 +#define WLAN_MGMT_STATUS_ASSOC_DENIED_SHORTPREAMBLE 19 +#define WLAN_MGMT_STATUS_ASSOC_DENIED_PBCC 20 +#define WLAN_MGMT_STATUS_ASSOC_DENIED_AGILITY 21 + +// reference 802.11h 7.3.1.9 +// +#define WLAN_MGMT_STATUS_ASSOC_REJECT_BCS_SPECTRUM_MNG 22 +#define WLAN_MGMT_STATUS_ASSOC_REJECT_BCS_PWR_CAP 23 +#define WLAN_MGMT_STATUS_ASSOC_REJECT_BCS_SUPP_CH 24 +// +// reference 802.11g 7.3.1.9 +// +#define WLAN_MGMT_STATUS_SHORTSLOTTIME_UNSUPPORTED 25 +#define WLAN_MGMT_STATUS_DSSSOFDM_UNSUPPORTED 26 +// +// reference 802.11i 7.3.1.9 table 19 +// +#define WLAN_MGMT_STATUS_INVALID_IE 40 +#define WLAN_MGMT_STATUS_GROUP_CIPHER_INVALID 41 +#define WLAN_MGMT_STATUS_PAIRWISE_CIPHER_INVALID 42 +#define WLAN_MGMT_STATUS_AKMP_INVALID 43 +#define WLAN_MGMT_STATUS_UNSUPPORT_RSN_IE_VER 44 +#define WLAN_MGMT_STATUS_INVALID_RSN_IE_CAP 45 +#define WLAN_MGMT_STATUS_CIPHER_REJECT 46 + + + +// Auth Algorithm +#define WLAN_AUTH_ALG_OPENSYSTEM 0 +#define WLAN_AUTH_ALG_SHAREDKEY 1 + + + +// Management Frame Field Offsets +// Note: Not all fields are listed because of variable lengths. +// Note: These offsets are from the start of the frame data + +#define WLAN_BEACON_OFF_TS 0 +#define WLAN_BEACON_OFF_BCN_INT 8 +#define WLAN_BEACON_OFF_CAPINFO 10 +#define WLAN_BEACON_OFF_SSID 12 + +#define WLAN_DISASSOC_OFF_REASON 0 + +#define WLAN_ASSOCREQ_OFF_CAP_INFO 0 +#define WLAN_ASSOCREQ_OFF_LISTEN_INT 2 +#define WLAN_ASSOCREQ_OFF_SSID 4 + +#define WLAN_ASSOCRESP_OFF_CAP_INFO 0 +#define WLAN_ASSOCRESP_OFF_STATUS 2 +#define WLAN_ASSOCRESP_OFF_AID 4 +#define WLAN_ASSOCRESP_OFF_SUPP_RATES 6 + +#define WLAN_REASSOCREQ_OFF_CAP_INFO 0 +#define WLAN_REASSOCREQ_OFF_LISTEN_INT 2 +#define WLAN_REASSOCREQ_OFF_CURR_AP 4 +#define WLAN_REASSOCREQ_OFF_SSID 10 + +#define WLAN_REASSOCRESP_OFF_CAP_INFO 0 +#define WLAN_REASSOCRESP_OFF_STATUS 2 +#define WLAN_REASSOCRESP_OFF_AID 4 +#define WLAN_REASSOCRESP_OFF_SUPP_RATES 6 + +#define WLAN_PROBEREQ_OFF_SSID 0 + +#define WLAN_PROBERESP_OFF_TS 0 +#define WLAN_PROBERESP_OFF_BCN_INT 8 +#define WLAN_PROBERESP_OFF_CAP_INFO 10 +#define WLAN_PROBERESP_OFF_SSID 12 + +#define WLAN_AUTHEN_OFF_AUTH_ALG 0 +#define WLAN_AUTHEN_OFF_AUTH_SEQ 2 +#define WLAN_AUTHEN_OFF_STATUS 4 +#define WLAN_AUTHEN_OFF_CHALLENGE 6 + +#define WLAN_DEAUTHEN_OFF_REASON 0 + + +// +// Cipher Suite Selectors defiened in 802.11i +// +#define WLAN_11i_CSS_USE_GROUP 0 +#define WLAN_11i_CSS_WEP40 1 +#define WLAN_11i_CSS_TKIP 2 +#define WLAN_11i_CSS_CCMP 4 +#define WLAN_11i_CSS_WEP104 5 +#define WLAN_11i_CSS_UNKNOWN 255 + +// +// Authentication and Key Management Suite Selectors defined in 802.11i +// +#define WLAN_11i_AKMSS_802_1X 1 +#define WLAN_11i_AKMSS_PSK 2 +#define WLAN_11i_AKMSS_UNKNOWN 255 + +// Measurement type definitions reference ieee 802.11h Table 20b +#define MEASURE_TYPE_BASIC 0 +#define MEASURE_TYPE_CCA 1 +#define MEASURE_TYPE_RPI 2 + +// Measurement request mode definitions reference ieee 802.11h Figure 46h +#define MEASURE_MODE_ENABLE 0x02 +#define MEASURE_MODE_REQ 0x04 +#define MEASURE_MODE_REP 0x08 + +// Measurement report mode definitions reference ieee 802.11h Figure 46m +#define MEASURE_MODE_LATE 0x01 +#define MEASURE_MODE_INCAPABLE 0x02 +#define MEASURE_MODE_REFUSED 0x04 + + + +/*--------------------- Export Classes ----------------------------*/ + +/*--------------------- Export Variables --------------------------*/ + +/*--------------------- Export Types ------------------------------*/ + + +// Information Element Types + +#pragma pack(1) +typedef struct tagWLAN_IE { + BYTE byElementID; + BYTE len; +}__attribute__ ((__packed__)) +WLAN_IE, *PWLAN_IE; + + +// Service Set Identity (SSID) +#pragma pack(1) +typedef struct tagWLAN_IE_SSID { + BYTE byElementID; + BYTE len; + BYTE abySSID[1]; +}__attribute__ ((__packed__)) +WLAN_IE_SSID, *PWLAN_IE_SSID; + + +// Supported Rates +#pragma pack(1) +typedef struct tagWLAN_IE_SUPP_RATES { + BYTE byElementID; + BYTE len; + BYTE abyRates[1]; +}__attribute__ ((__packed__)) +WLAN_IE_SUPP_RATES, *PWLAN_IE_SUPP_RATES; + + + +// FH Parameter Set +#pragma pack(1) +typedef struct _WLAN_IE_FH_PARMS { + BYTE byElementID; + BYTE len; + WORD wDwellTime; + BYTE byHopSet; + BYTE byHopPattern; + BYTE byHopIndex; +} WLAN_IE_FH_PARMS, *PWLAN_IE_FH_PARMS; + + +// DS Parameter Set +#pragma pack(1) +typedef struct tagWLAN_IE_DS_PARMS { + BYTE byElementID; + BYTE len; + BYTE byCurrChannel; +}__attribute__ ((__packed__)) +WLAN_IE_DS_PARMS, *PWLAN_IE_DS_PARMS; + + +// CF Parameter Set +#pragma pack(1) +typedef struct tagWLAN_IE_CF_PARMS { + BYTE byElementID; + BYTE len; + BYTE byCFPCount; + BYTE byCFPPeriod; + WORD wCFPMaxDuration; + WORD wCFPDurRemaining; +}__attribute__ ((__packed__)) +WLAN_IE_CF_PARMS, *PWLAN_IE_CF_PARMS; + + +// TIM +#pragma pack(1) +typedef struct tagWLAN_IE_TIM { + BYTE byElementID; + BYTE len; + BYTE byDTIMCount; + BYTE byDTIMPeriod; + BYTE byBitMapCtl; + BYTE byVirtBitMap[1]; +}__attribute__ ((__packed__)) +WLAN_IE_TIM, *PWLAN_IE_TIM; + + +// IBSS Parameter Set +#pragma pack(1) +typedef struct tagWLAN_IE_IBSS_PARMS { + BYTE byElementID; + BYTE len; + WORD wATIMWindow; +}__attribute__ ((__packed__)) +WLAN_IE_IBSS_PARMS, *PWLAN_IE_IBSS_PARMS; + + +// Challenge Text +#pragma pack(1) +typedef struct tagWLAN_IE_CHALLENGE { + BYTE byElementID; + BYTE len; + BYTE abyChallenge[1]; +}__attribute__ ((__packed__)) +WLAN_IE_CHALLENGE, *PWLAN_IE_CHALLENGE; + + +#pragma pack(1) +typedef struct tagWLAN_IE_RSN_EXT { + BYTE byElementID; + BYTE len; + BYTE abyOUI[4]; + WORD wVersion; + BYTE abyMulticast[4]; + WORD wPKCount; + struct { + BYTE abyOUI[4]; + } PKSList[1]; // the rest is variable so need to + // overlay ieauth structure +} WLAN_IE_RSN_EXT, *PWLAN_IE_RSN_EXT; + +#pragma pack(1) +typedef struct tagWLAN_IE_RSN_AUTH { + WORD wAuthCount; + struct { + BYTE abyOUI[4]; + } AuthKSList[1]; +} WLAN_IE_RSN_AUTH, *PWLAN_IE_RSN_AUTH; + +// RSN Identity +#pragma pack(1) +typedef struct tagWLAN_IE_RSN { + BYTE byElementID; + BYTE len; + WORD wVersion; + BYTE abyRSN[WLAN_MIN_ARRAY]; +} WLAN_IE_RSN, *PWLAN_IE_RSN; + + +// ERP +#pragma pack(1) +typedef struct tagWLAN_IE_ERP { + BYTE byElementID; + BYTE len; + BYTE byContext; +}__attribute__ ((__packed__)) +WLAN_IE_ERP, *PWLAN_IE_ERP; + + +#pragma pack(1) +typedef struct _MEASEURE_REQ { + BYTE byChannel; + BYTE abyStartTime[8]; + BYTE abyDuration[2]; +} MEASEURE_REQ, *PMEASEURE_REQ, + MEASEURE_REQ_BASIC, *PMEASEURE_REQ_BASIC, + MEASEURE_REQ_CCA, *PMEASEURE_REQ_CCA, + MEASEURE_REQ_RPI, *PMEASEURE_REQ_RPI; + +typedef struct _MEASEURE_REP_BASIC { + BYTE byChannel; + BYTE abyStartTime[8]; + BYTE abyDuration[2]; + BYTE byMap; +} MEASEURE_REP_BASIC, *PMEASEURE_REP_BASIC; + +typedef struct _MEASEURE_REP_CCA { + BYTE byChannel; + BYTE abyStartTime[8]; + BYTE abyDuration[2]; + BYTE byCCABusyFraction; +} MEASEURE_REP_CCA, *PMEASEURE_REP_CCA; + +typedef struct _MEASEURE_REP_RPI { + BYTE byChannel; + BYTE abyStartTime[8]; + BYTE abyDuration[2]; + BYTE abyRPIdensity[8]; +} MEASEURE_REP_RPI, *PMEASEURE_REP_RPI; + +typedef union _MEASEURE_REP { + + MEASEURE_REP_BASIC sBasic; + MEASEURE_REP_CCA sCCA; + MEASEURE_REP_RPI sRPI; + +} MEASEURE_REP, *PMEASEURE_REP; + +typedef struct _WLAN_IE_MEASURE_REQ { + BYTE byElementID; + BYTE len; + BYTE byToken; + BYTE byMode; + BYTE byType; + MEASEURE_REQ sReq; +} WLAN_IE_MEASURE_REQ, *PWLAN_IE_MEASURE_REQ; + +typedef struct _WLAN_IE_MEASURE_REP { + BYTE byElementID; + BYTE len; + BYTE byToken; + BYTE byMode; + BYTE byType; + MEASEURE_REP sRep; +} WLAN_IE_MEASURE_REP, *PWLAN_IE_MEASURE_REP; + +typedef struct _WLAN_IE_CH_SW { + BYTE byElementID; + BYTE len; + BYTE byMode; + BYTE byChannel; + BYTE byCount; +} WLAN_IE_CH_SW, *PWLAN_IE_CH_SW; + +typedef struct _WLAN_IE_QUIET { + BYTE byElementID; + BYTE len; + BYTE byQuietCount; + BYTE byQuietPeriod; + BYTE abyQuietDuration[2]; + BYTE abyQuietOffset[2]; +} WLAN_IE_QUIET, *PWLAN_IE_QUIET; + +typedef struct _WLAN_IE_COUNTRY { + BYTE byElementID; + BYTE len; + BYTE abyCountryString[3]; + BYTE abyCountryInfo[3]; +} WLAN_IE_COUNTRY, *PWLAN_IE_COUNTRY; + +typedef struct _WLAN_IE_PW_CONST { + BYTE byElementID; + BYTE len; + BYTE byPower; +} WLAN_IE_PW_CONST, *PWLAN_IE_PW_CONST; + +typedef struct _WLAN_IE_PW_CAP { + BYTE byElementID; + BYTE len; + BYTE byMinPower; + BYTE byMaxPower; +} WLAN_IE_PW_CAP, *PWLAN_IE_PW_CAP; + +typedef struct _WLAN_IE_SUPP_CH { + BYTE byElementID; + BYTE len; + BYTE abyChannelTuple[2]; +} WLAN_IE_SUPP_CH, *PWLAN_IE_SUPP_CH; + +typedef struct _WLAN_IE_TPC_REQ { + BYTE byElementID; + BYTE len; +} WLAN_IE_TPC_REQ, *PWLAN_IE_TPC_REQ; + +typedef struct _WLAN_IE_TPC_REP { + BYTE byElementID; + BYTE len; + BYTE byTxPower; + BYTE byLinkMargin; +} WLAN_IE_TPC_REP, *PWLAN_IE_TPC_REP; + + +typedef struct _WLAN_IE_IBSS_DFS { + BYTE byElementID; + BYTE len; + BYTE abyDFSOwner[6]; + BYTE byDFSRecovery; + BYTE abyChannelMap[2]; +} WLAN_IE_IBSS_DFS, *PWLAN_IE_IBSS_DFS; + +#pragma pack() + + + +// Frame Types +// prototype structure, all mgmt frame types will start with these members +typedef struct tagWLAN_FR_MGMT { + + UINT uType; + UINT len; + PBYTE pBuf; + PUWLAN_80211HDR pHdr; + +} WLAN_FR_MGMT, *PWLAN_FR_MGMT; + +// Beacon frame +typedef struct tagWLAN_FR_BEACON { + + UINT uType; + UINT len; + PBYTE pBuf; + PUWLAN_80211HDR pHdr; + // fixed fields + PQWORD pqwTimestamp; + PWORD pwBeaconInterval; + PWORD pwCapInfo; + /*-- info elements ----------*/ + PWLAN_IE_SSID pSSID; + PWLAN_IE_SUPP_RATES pSuppRates; +// PWLAN_IE_FH_PARMS pFHParms; + PWLAN_IE_DS_PARMS pDSParms; + PWLAN_IE_CF_PARMS pCFParms; + PWLAN_IE_TIM pTIM; + PWLAN_IE_IBSS_PARMS pIBSSParms; + PWLAN_IE_RSN pRSN; + PWLAN_IE_RSN_EXT pRSNWPA; + PWLAN_IE_ERP pERP; + PWLAN_IE_SUPP_RATES pExtSuppRates; + PWLAN_IE_COUNTRY pIE_Country; + PWLAN_IE_PW_CONST pIE_PowerConstraint; + PWLAN_IE_CH_SW pIE_CHSW; + PWLAN_IE_IBSS_DFS pIE_IBSSDFS; + PWLAN_IE_QUIET pIE_Quiet; + +} WLAN_FR_BEACON, *PWLAN_FR_BEACON; + + +// IBSS ATIM frame +typedef struct tagWLAN_FR_IBSSATIM { + + UINT uType; + UINT len; + PBYTE pBuf; + PUWLAN_80211HDR pHdr; + + // fixed fields + // info elements + // this frame type has a null body + +} WLAN_FR_IBSSATIM, *PWLAN_FR_IBSSATIM; + +// Disassociation +typedef struct tagWLAN_FR_DISASSOC { + + UINT uType; + UINT len; + PBYTE pBuf; + PUWLAN_80211HDR pHdr; + /*-- fixed fields -----------*/ + PWORD pwReason; + /*-- info elements ----------*/ + +} WLAN_FR_DISASSOC, *PWLAN_FR_DISASSOC; + +// Association Request +typedef struct tagWLAN_FR_ASSOCREQ { + + UINT uType; + UINT len; + PBYTE pBuf; + PUWLAN_80211HDR pHdr; + /*-- fixed fields -----------*/ + PWORD pwCapInfo; + PWORD pwListenInterval; + /*-- info elements ----------*/ + PWLAN_IE_SSID pSSID; + PWLAN_IE_SUPP_RATES pSuppRates; + PWLAN_IE_RSN pRSN; + PWLAN_IE_RSN_EXT pRSNWPA; + PWLAN_IE_SUPP_RATES pExtSuppRates; + PWLAN_IE_PW_CAP pCurrPowerCap; + PWLAN_IE_SUPP_CH pCurrSuppCh; + +} WLAN_FR_ASSOCREQ, *PWLAN_FR_ASSOCREQ; + +// Association Response +typedef struct tagWLAN_FR_ASSOCRESP { + + UINT uType; + UINT len; + PBYTE pBuf; + PUWLAN_80211HDR pHdr; + /*-- fixed fields -----------*/ + PWORD pwCapInfo; + PWORD pwStatus; + PWORD pwAid; + /*-- info elements ----------*/ + PWLAN_IE_SUPP_RATES pSuppRates; + PWLAN_IE_SUPP_RATES pExtSuppRates; + +} WLAN_FR_ASSOCRESP, *PWLAN_FR_ASSOCRESP; + +// Reassociation Request +typedef struct tagWLAN_FR_REASSOCREQ { + + UINT uType; + UINT len; + PBYTE pBuf; + PUWLAN_80211HDR pHdr; + + /*-- fixed fields -----------*/ + PWORD pwCapInfo; + PWORD pwListenInterval; + PIEEE_ADDR pAddrCurrAP; + + /*-- info elements ----------*/ + PWLAN_IE_SSID pSSID; + PWLAN_IE_SUPP_RATES pSuppRates; + PWLAN_IE_RSN pRSN; + PWLAN_IE_RSN_EXT pRSNWPA; + PWLAN_IE_SUPP_RATES pExtSuppRates; + +} WLAN_FR_REASSOCREQ, *PWLAN_FR_REASSOCREQ; + +// Reassociation Response +typedef struct tagWLAN_FR_REASSOCRESP { + + UINT uType; + UINT len; + PBYTE pBuf; + PUWLAN_80211HDR pHdr; + /*-- fixed fields -----------*/ + PWORD pwCapInfo; + PWORD pwStatus; + PWORD pwAid; + /*-- info elements ----------*/ + PWLAN_IE_SUPP_RATES pSuppRates; + PWLAN_IE_SUPP_RATES pExtSuppRates; + +} WLAN_FR_REASSOCRESP, *PWLAN_FR_REASSOCRESP; + +// Probe Request +typedef struct tagWLAN_FR_PROBEREQ { + + UINT uType; + UINT len; + PBYTE pBuf; + PUWLAN_80211HDR pHdr; + /*-- fixed fields -----------*/ + /*-- info elements ----------*/ + PWLAN_IE_SSID pSSID; + PWLAN_IE_SUPP_RATES pSuppRates; + PWLAN_IE_SUPP_RATES pExtSuppRates; + +} WLAN_FR_PROBEREQ, *PWLAN_FR_PROBEREQ; + +// Probe Response +typedef struct tagWLAN_FR_PROBERESP { + + UINT uType; + UINT len; + PBYTE pBuf; + PUWLAN_80211HDR pHdr; + /*-- fixed fields -----------*/ + PQWORD pqwTimestamp; + PWORD pwBeaconInterval; + PWORD pwCapInfo; + /*-- info elements ----------*/ + PWLAN_IE_SSID pSSID; + PWLAN_IE_SUPP_RATES pSuppRates; + PWLAN_IE_DS_PARMS pDSParms; + PWLAN_IE_CF_PARMS pCFParms; + PWLAN_IE_IBSS_PARMS pIBSSParms; + PWLAN_IE_RSN pRSN; + PWLAN_IE_RSN_EXT pRSNWPA; + PWLAN_IE_ERP pERP; + PWLAN_IE_SUPP_RATES pExtSuppRates; + PWLAN_IE_COUNTRY pIE_Country; + PWLAN_IE_PW_CONST pIE_PowerConstraint; + PWLAN_IE_CH_SW pIE_CHSW; + PWLAN_IE_IBSS_DFS pIE_IBSSDFS; + PWLAN_IE_QUIET pIE_Quiet; + +} WLAN_FR_PROBERESP, *PWLAN_FR_PROBERESP; + +// Authentication +typedef struct tagWLAN_FR_AUTHEN { + + UINT uType; + UINT len; + PBYTE pBuf; + PUWLAN_80211HDR pHdr; + /*-- fixed fields -----------*/ + PWORD pwAuthAlgorithm; + PWORD pwAuthSequence; + PWORD pwStatus; + /*-- info elements ----------*/ + PWLAN_IE_CHALLENGE pChallenge; + +} WLAN_FR_AUTHEN, *PWLAN_FR_AUTHEN; + +// Deauthenication +typedef struct tagWLAN_FR_DEAUTHEN { + + UINT uType; + UINT len; + PBYTE pBuf; + PUWLAN_80211HDR pHdr; + /*-- fixed fields -----------*/ + PWORD pwReason; + + /*-- info elements ----------*/ + +} WLAN_FR_DEAUTHEN, *PWLAN_FR_DEAUTHEN; + +/*--------------------- Export Functions --------------------------*/ +VOID +vMgrEncodeBeacon( + IN PWLAN_FR_BEACON pFrame + ); + +VOID +vMgrDecodeBeacon( + IN PWLAN_FR_BEACON pFrame + ); + +VOID +vMgrEncodeIBSSATIM( + IN PWLAN_FR_IBSSATIM pFrame + ); + +VOID +vMgrDecodeIBSSATIM( + IN PWLAN_FR_IBSSATIM pFrame + ); + +VOID +vMgrEncodeDisassociation( + IN PWLAN_FR_DISASSOC pFrame + ); + +VOID +vMgrDecodeDisassociation( + IN PWLAN_FR_DISASSOC pFrame + ); + +VOID +vMgrEncodeAssocRequest( + IN PWLAN_FR_ASSOCREQ pFrame + ); + +VOID +vMgrDecodeAssocRequest( + IN PWLAN_FR_ASSOCREQ pFrame + ); + +VOID +vMgrEncodeAssocResponse( + IN PWLAN_FR_ASSOCRESP pFrame + ); + +VOID +vMgrDecodeAssocResponse( + IN PWLAN_FR_ASSOCRESP pFrame + ); + +VOID +vMgrEncodeReassocRequest( + IN PWLAN_FR_REASSOCREQ pFrame + ); + +VOID +vMgrDecodeReassocRequest( + IN PWLAN_FR_REASSOCREQ pFrame + ); + +VOID +vMgrEncodeProbeRequest( + IN PWLAN_FR_PROBEREQ pFrame + ); + +VOID +vMgrDecodeProbeRequest( + IN PWLAN_FR_PROBEREQ pFrame + ); + +VOID +vMgrEncodeProbeResponse( + IN PWLAN_FR_PROBERESP pFrame + ); + +VOID +vMgrDecodeProbeResponse( + IN PWLAN_FR_PROBERESP pFrame + ); + +VOID +vMgrEncodeAuthen( + IN PWLAN_FR_AUTHEN pFrame + ); + +VOID +vMgrDecodeAuthen( + IN PWLAN_FR_AUTHEN pFrame + ); + +VOID +vMgrEncodeDeauthen( + IN PWLAN_FR_DEAUTHEN pFrame + ); + +VOID +vMgrDecodeDeauthen( + IN PWLAN_FR_DEAUTHEN pFrame + ); + +VOID +vMgrEncodeReassocResponse( + IN PWLAN_FR_REASSOCRESP pFrame + ); + +VOID +vMgrDecodeReassocResponse( + IN PWLAN_FR_REASSOCRESP pFrame + ); + +#endif// __80211MGR_H__ diff --git a/drivers/staging/vt6655/IEEE11h.c b/drivers/staging/vt6655/IEEE11h.c new file mode 100644 index 000000000000..5f25b8e88bd9 --- /dev/null +++ b/drivers/staging/vt6655/IEEE11h.c @@ -0,0 +1,324 @@ +/* + * Copyright (c) 1996, 2005 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * File: IEEE11h.c + * + * Purpose: + * + * Functions: + * + * Revision History: + * + * Author: Yiching Chen + * + * Date: Mar. 31, 2005 + * + */ + + +#if !defined(__TTYPE_H__) +#include "ttype.h" +#endif +#if !defined(__UMEM_H__) +#include "umem.h" +#endif +#if !defined(__TMACRO_H__) +#include "tmacro.h" +#endif +#if !defined(__TETHER_H__) +#include "tether.h" +#endif +#if !defined(__IEEE11h_H__) +#include "IEEE11h.h" +#endif + +#if !defined(__DEVICE_H__) +#include "device.h" +#endif +#if !defined(__WMGR_H__) +#include "wmgr.h" +#endif +#if !defined(__RXTX_H__) +#include "rxtx.h" +#endif + + + +/*--------------------- Static Definitions -------------------------*/ +static int msglevel =MSG_LEVEL_INFO; + +#pragma pack(1) + +typedef struct _WLAN_FRAME_ACTION { + WLAN_80211HDR_A3 Header; + BYTE byCategory; + BYTE byAction; + BYTE abyVars[1]; +} WLAN_FRAME_ACTION, *PWLAN_FRAME_ACTION; + +typedef struct _WLAN_FRAME_MSRREQ { + WLAN_80211HDR_A3 Header; + BYTE byCategory; + BYTE byAction; + BYTE byDialogToken; + WLAN_IE_MEASURE_REQ sMSRReqEIDs[1]; +} WLAN_FRAME_MSRREQ, *PWLAN_FRAME_MSRREQ; + +typedef struct _WLAN_FRAME_MSRREP { + WLAN_80211HDR_A3 Header; + BYTE byCategory; + BYTE byAction; + BYTE byDialogToken; + WLAN_IE_MEASURE_REP sMSRRepEIDs[1]; +} WLAN_FRAME_MSRREP, *PWLAN_FRAME_MSRREP; + +typedef struct _WLAN_FRAME_TPCREQ { + WLAN_80211HDR_A3 Header; + BYTE byCategory; + BYTE byAction; + BYTE byDialogToken; + WLAN_IE_TPC_REQ sTPCReqEIDs; +} WLAN_FRAME_TPCREQ, *PWLAN_FRAME_TPCREQ; + +typedef struct _WLAN_FRAME_TPCREP { + WLAN_80211HDR_A3 Header; + BYTE byCategory; + BYTE byAction; + BYTE byDialogToken; + WLAN_IE_TPC_REP sTPCRepEIDs; +} WLAN_FRAME_TPCREP, *PWLAN_FRAME_TPCREP; + +#pragma pack() + +// action field reference ieee 802.11h Table 20e +#define ACTION_MSRREQ 0 +#define ACTION_MSRREP 1 +#define ACTION_TPCREQ 2 +#define ACTION_TPCREP 3 +#define ACTION_CHSW 4 + +/*--------------------- Static Classes ----------------------------*/ + +/*--------------------- Static Variables --------------------------*/ + +/*--------------------- Static Functions --------------------------*/ +static BOOL s_bRxMSRReq(PSMgmtObject pMgmt, PWLAN_FRAME_MSRREQ pMSRReq, UINT uLength) +{ + UINT uNumOfEIDs = 0; + BOOL bResult = TRUE; + + if (uLength <= WLAN_A3FR_MAXLEN) { + MEMvCopy(pMgmt->abyCurrentMSRReq, pMSRReq, uLength); + } + uNumOfEIDs = ((uLength - OFFSET(WLAN_FRAME_MSRREQ, sMSRReqEIDs))/ (sizeof(WLAN_IE_MEASURE_REQ))); + pMgmt->pCurrMeasureEIDRep = &(((PWLAN_FRAME_MSRREP) (pMgmt->abyCurrentMSRRep))->sMSRRepEIDs[0]); + pMgmt->uLengthOfRepEIDs = 0; + bResult = CARDbStartMeasure(pMgmt->pAdapter, + ((PWLAN_FRAME_MSRREQ) (pMgmt->abyCurrentMSRReq))->sMSRReqEIDs, + uNumOfEIDs + ); + return (bResult); +} + + +static BOOL s_bRxTPCReq(PSMgmtObject pMgmt, PWLAN_FRAME_TPCREQ pTPCReq, BYTE byRate, BYTE byRSSI) +{ + PWLAN_FRAME_TPCREP pFrame; + PSTxMgmtPacket pTxPacket = NULL; + + + pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool; + memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_A3FR_MAXLEN); + pTxPacket->p80211Header = (PUWLAN_80211HDR)((PBYTE)pTxPacket + sizeof(STxMgmtPacket)); + + pFrame = (PWLAN_FRAME_TPCREP)((PBYTE)pTxPacket + sizeof(STxMgmtPacket)); + + pFrame->Header.wFrameCtl = ( WLAN_SET_FC_FTYPE(WLAN_FTYPE_MGMT) | + WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_ACTION) + ); + + MEMvCopy( pFrame->Header.abyAddr1, pTPCReq->Header.abyAddr2, WLAN_ADDR_LEN); + MEMvCopy( pFrame->Header.abyAddr2, CARDpGetCurrentAddress(pMgmt->pAdapter), WLAN_ADDR_LEN); + MEMvCopy( pFrame->Header.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN); + + pFrame->byCategory = 0; + pFrame->byAction = 3; + pFrame->byDialogToken = ((PWLAN_FRAME_MSRREQ) (pMgmt->abyCurrentMSRReq))->byDialogToken; + + pFrame->sTPCRepEIDs.byElementID = WLAN_EID_TPC_REP; + pFrame->sTPCRepEIDs.len = 2; + pFrame->sTPCRepEIDs.byTxPower = CARDbyGetTransmitPower(pMgmt->pAdapter); + switch (byRate) { + case RATE_54M: + pFrame->sTPCRepEIDs.byLinkMargin = 65 - byRSSI; + break; + case RATE_48M: + pFrame->sTPCRepEIDs.byLinkMargin = 66 - byRSSI; + break; + case RATE_36M: + pFrame->sTPCRepEIDs.byLinkMargin = 70 - byRSSI; + break; + case RATE_24M: + pFrame->sTPCRepEIDs.byLinkMargin = 74 - byRSSI; + break; + case RATE_18M: + pFrame->sTPCRepEIDs.byLinkMargin = 77 - byRSSI; + break; + case RATE_12M: + pFrame->sTPCRepEIDs.byLinkMargin = 79 - byRSSI; + break; + case RATE_9M: + pFrame->sTPCRepEIDs.byLinkMargin = 81 - byRSSI; + break; + case RATE_6M: + default: + pFrame->sTPCRepEIDs.byLinkMargin = 82 - byRSSI; + break; + } + + pTxPacket->cbMPDULen = sizeof(WLAN_FRAME_TPCREP); + pTxPacket->cbPayloadLen = sizeof(WLAN_FRAME_TPCREP) - WLAN_HDR_ADDR3_LEN; + if (csMgmt_xmit(pMgmt->pAdapter, pTxPacket) != CMD_STATUS_PENDING) + return (FALSE); + return (TRUE); +// return (CARDbSendPacket(pMgmt->pAdapter, pFrame, PKT_TYPE_802_11_MNG, sizeof(WLAN_FRAME_TPCREP))); + +} + + +/*--------------------- Export Variables --------------------------*/ + +/*--------------------- Export Functions --------------------------*/ + + +/*+ + * + * Description: + * Handles action management frames. + * + * Parameters: + * In: + * pMgmt - Management Object structure + * pRxPacket - Received packet + * Out: + * none + * + * Return Value: None. + * +-*/ +BOOL +IEEE11hbMgrRxAction ( + IN PVOID pMgmtHandle, + IN PVOID pRxPacket + ) +{ + PSMgmtObject pMgmt = (PSMgmtObject) pMgmtHandle; + PWLAN_FRAME_ACTION pAction = NULL; + UINT uLength = 0; + PWLAN_IE_CH_SW pChannelSwitch = NULL; + + + // decode the frame + uLength = ((PSRxMgmtPacket)pRxPacket)->cbMPDULen; + if (uLength > WLAN_A3FR_MAXLEN) { + return (FALSE); + } + + + pAction = (PWLAN_FRAME_ACTION) (((PSRxMgmtPacket)pRxPacket)->p80211Header); + + if (pAction->byCategory == 0) { + switch (pAction->byAction) { + case ACTION_MSRREQ: + return (s_bRxMSRReq(pMgmt, (PWLAN_FRAME_MSRREQ) pAction, uLength)); + break; + case ACTION_MSRREP: + break; + case ACTION_TPCREQ: + return (s_bRxTPCReq(pMgmt, + (PWLAN_FRAME_TPCREQ) pAction, + ((PSRxMgmtPacket)pRxPacket)->byRxRate, + (BYTE) ((PSRxMgmtPacket)pRxPacket)->uRSSI)); + break; + case ACTION_TPCREP: + break; + case ACTION_CHSW: + pChannelSwitch = (PWLAN_IE_CH_SW) (pAction->abyVars); + if ((pChannelSwitch->byElementID == WLAN_EID_CH_SWITCH) && + (pChannelSwitch->len == 3)) { + // valid element id + CARDbChannelSwitch( pMgmt->pAdapter, + pChannelSwitch->byMode, + CARDbyGetChannelMapping(pMgmt->pAdapter, pChannelSwitch->byChannel, pMgmt->eCurrentPHYMode), + pChannelSwitch->byCount + ); + } + break; + default: + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Unknown Action = %d\n", pAction->byAction); + break; + } + } else { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Unknown Category = %d\n", pAction->byCategory); + pAction->byCategory |= 0x80; + + //return (CARDbSendPacket(pMgmt->pAdapter, pAction, PKT_TYPE_802_11_MNG, uLength)); + return (TRUE); + } + return (TRUE); +} + + +BOOL IEEE11hbMSRRepTx ( + IN PVOID pMgmtHandle + ) +{ + PSMgmtObject pMgmt = (PSMgmtObject) pMgmtHandle; + PWLAN_FRAME_MSRREP pMSRRep = (PWLAN_FRAME_MSRREP) (pMgmt->abyCurrentMSRRep + sizeof(STxMgmtPacket)); + UINT uLength = 0; + PSTxMgmtPacket pTxPacket = NULL; + + pTxPacket = (PSTxMgmtPacket)pMgmt->abyCurrentMSRRep; + memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_A3FR_MAXLEN); + pTxPacket->p80211Header = (PUWLAN_80211HDR)((PBYTE)pTxPacket + sizeof(STxMgmtPacket)); + + + pMSRRep->Header.wFrameCtl = ( WLAN_SET_FC_FTYPE(WLAN_FTYPE_MGMT) | + WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_ACTION) + ); + + MEMvCopy( pMSRRep->Header.abyAddr1, ((PWLAN_FRAME_MSRREQ) (pMgmt->abyCurrentMSRReq))->Header.abyAddr2, WLAN_ADDR_LEN); + MEMvCopy( pMSRRep->Header.abyAddr2, CARDpGetCurrentAddress(pMgmt->pAdapter), WLAN_ADDR_LEN); + MEMvCopy( pMSRRep->Header.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN); + + pMSRRep->byCategory = 0; + pMSRRep->byAction = 1; + pMSRRep->byDialogToken = ((PWLAN_FRAME_MSRREQ) (pMgmt->abyCurrentMSRReq))->byDialogToken; + + uLength = pMgmt->uLengthOfRepEIDs + OFFSET(WLAN_FRAME_MSRREP, sMSRRepEIDs); + + pTxPacket->cbMPDULen = uLength; + pTxPacket->cbPayloadLen = uLength - WLAN_HDR_ADDR3_LEN; + if (csMgmt_xmit(pMgmt->pAdapter, pTxPacket) != CMD_STATUS_PENDING) + return (FALSE); + return (TRUE); +// return (CARDbSendPacket(pMgmt->pAdapter, pMSRRep, PKT_TYPE_802_11_MNG, uLength)); + +} + diff --git a/drivers/staging/vt6655/IEEE11h.h b/drivers/staging/vt6655/IEEE11h.h new file mode 100644 index 000000000000..22bcaf1f6817 --- /dev/null +++ b/drivers/staging/vt6655/IEEE11h.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 1996, 2005 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * File: IEEE11h.h + * + * Purpose: Defines the macros, types, and functions for dealing + * with IEEE 802.11h. + * + * Author: Yiching Chen + * + * Date: Mar. 31, 2005 + * + */ + +#ifndef __IEEE11h_H__ +#define __IEEE11h_H__ + + +#if !defined(__TTYPE_H__) +#include "ttype.h" +#endif +#if !defined(__80211HDR_H__) +#include "80211hdr.h" +#endif +#if !defined(__80211MGR_H__) +#include "80211mgr.h" +#endif + + +/*--------------------- Export Definitions -------------------------*/ + +/*--------------------- Export Classes ----------------------------*/ + +/*--------------------- Export Variables --------------------------*/ + +/*--------------------- Export Types ------------------------------*/ + +/*--------------------- Export Functions --------------------------*/ +#ifdef __cplusplus +extern "C" { /* Assume C declarations for C++ */ +#endif /* __cplusplus */ + +BOOL IEEE11hbMSRRepTx ( + IN PVOID pMgmtHandle + ); + +#ifdef __cplusplus +} /* End of extern "C" { */ +#endif /* __cplusplus */ + + +#endif // __IEEE11h_H__ diff --git a/drivers/staging/vt6655/Kconfig b/drivers/staging/vt6655/Kconfig new file mode 100644 index 000000000000..a01b1e49fb31 --- /dev/null +++ b/drivers/staging/vt6655/Kconfig @@ -0,0 +1,6 @@ +config VT6655 + tristate "VIA Technologies VT6655 support" + depends on PCI + ---help--- + This is a vendor-written driver for VIA VT6655. + diff --git a/drivers/staging/vt6655/Makefile b/drivers/staging/vt6655/Makefile new file mode 100644 index 000000000000..7d76e7ef3f88 --- /dev/null +++ b/drivers/staging/vt6655/Makefile @@ -0,0 +1,38 @@ +# TODO: all of these should be removed +EXTRA_CFLAGS += -DLINUX -D__KERNEL__ -DMODULE -DEXPORT_SYMTAB -D__NO_VERSION__ +EXTRA_CFLAGS += -DHOSTAP + +vt6655-y += device_main.o \ + card.o \ + mac.o \ + baseband.o \ + wctl.o \ + 80211mgr.o \ + wcmd.o \ + wmgr.o \ + bssdb.o \ + rxtx.o \ + dpc.o \ + power.o \ + datarate.o \ + srom.o \ + mib.o \ + rc4.o \ + tether.o \ + tcrc.o \ + ioctl.o \ + hostap.o \ + wpa.o \ + key.o \ + tkip.o \ + michael.o \ + wroute.o \ + rf.o \ + iwctl.o \ + wpactl.o \ + wpa2.o \ + aes_ccmp.o \ + vntwifi.o \ + IEEE11h.o + +obj-$(CONFIG_VT6655) += vt6655.o diff --git a/drivers/staging/vt6655/Makefile.arm b/drivers/staging/vt6655/Makefile.arm new file mode 100644 index 000000000000..2d2ccaded6ac --- /dev/null +++ b/drivers/staging/vt6655/Makefile.arm @@ -0,0 +1,181 @@ +# +# +# Build options: +# PRIV_OBJ := 1 for object version +# BIG_ENDIAN := 1 for big-endian mode +# +# arm-linux-tools chain are located at: +# /usr/local/bin/arm-linux-gcc +# /usr/local/bin/arm-linux-ld +# + +IO_MAP := 0 +HOSTAP := 1 +PRIV_OBJ := 1 +BIG_ENDIAN := 1 + +test_dir = $(shell [ -e $(dir)/include/linux ] && echo $(dir)) +KSP := $(foreach dir, $(KSP), $(test_dir)) + +KSRC := $(firstword $(KSP)) + +#ifeq (,$(KSRC)) +# $(error Linux kernel source not found) +#endif + +# check kernel version +KVER := $(shell uname -r | cut -c1-3 | sed 's/2\.[56]/2\.6/') +KERVER2=$(shell uname -r | cut -d. -f2) + +ifeq ($(KVER), 2.6) +# 2.6 kernel +TARGET = viawget.ko + +else +TARGET = viawget.o + +endif + +INSTDIR := $(shell find /lib/modules/$(shell uname -r) -name $(TARGET) -printf "%h\n" | sort | head -1) +ifeq (,$(INSTDIR)) + ifeq (,$(KERVER2)) + ifneq (,$(wildcard /lib/modules/$(shell uname -r)/kernel)) + INSTDIR := /lib/modules/$(shell uname -r)/kernel/drivers/net + else + INSTDIR := /lib/modules/$(shell uname -r)/net + endif + else + ifneq ($(KERVER2),2) + INSTDIR := /lib/modules/$(shell uname -r)/kernel/drivers/net + else + INSTDIR := /lib/modules/$(shell uname -r)/net + endif + endif +endif + + +SRC = device_main.c card.c mac.c baseband.c wctl.c 80211mgr.c \ + wcmd.c wmgr.c bssdb.c rxtx.c dpc.c power.c datarate.c srom.c \ + mib.c rc4.c tether.c tcrc.c ioctl.c hostap.c wpa.c key.c tkip.c \ + michael.c wroute.c rf.c iwctl.c wpactl.c wpa2.c aes_ccmp.c + +ifeq ($(IO_MAP), 1) + CFLAGS += -DIO_MAP +endif + +ifeq ($(HOSTAP), 1) + CFLAGS += -DHOSTAP +endif + +ifeq ($(PRIV_OBJ), 1) + CFLAGS += -DPRIVATE_OBJ +endif + +ifeq ($(BIG_ENDIAN), 1) + CFLAGS += -D__BIG_ENDIAN + CFLAGS += -mbig-endian + LDOPTS += -EB +else + CFLAGS += -mlittle-endian + LDOPTS += -EL +endif + +CFLAGS += -I$(PWD) -I$(PWD)/../include -I$(PWD)/../solomon + + +# build rule +ifeq ($(KVER), 2.6) +# 2.6 kernel + +ifndef KERNEL_CONF +KERNEL_CONF= $(KSRC)/.config +endif + +include ${KERNEL_CONF} + +obj-m += viawget.o + +viawget-objs := device_main.o card.o mac.o baseband.o wctl.o 80211mgr.o \ + wcmd.o wmgr.o bssdb.o rxtx.o dpc.o power.o datarate.o srom.o \ + mib.o rc4.o tether.o tcrc.o ioctl.o hostap.o wpa.o key.o tkip.o \ + michael.o wroute.o rf.o iwctl.o wpactl.o wpa2.o aes_ccmp.o + +.c.o: + $(CC) $(CFLAGS) -o $@ $< + +default: + make -C $(KSRC) SUBDIRS=$(shell pwd) modules + +else + +# 2.2/2.4 kernel +OBJS := device_main.o card.o mac.o baseband.o wctl.o 80211mgr.o \ + wcmd.o wmgr.o bssdb.o rxtx.o dpc.o power.o datarate.o srom.o \ + mib.o rc4.o tether.o tcrc.o ioctl.o hostap.o wpa.o key.o tkip.o \ + michael.o wroute.o rf.o iwctl.o wpactl.o wpa2.o + + +CC := /usr/local/bin/arm-linux-gcc +LD := /usr/local/bin/arm-linux-ld + +CFLAGS += -Wall -DLINUX -D__KERNEL__ -DMODULE -DEXPORT_SYMTAB -D__NO_VERSION__ -O2 -pipe +#CFLAGS += -Wstrict-prototypes -fomit-frame-pointer +COPTS+= -march=armv4 -fno-strict-aliasing -fno-common +#COPTS+= -mapcs-32 -mtune=xscale -mshort-load-bytes -msoft-float -mfp=2 +#COPTS+= -mthumb -mcpu=arm9 -ffunction-sections -fdata-sections + + +.SILENT: $(TARGET) clean + + + +ifeq ($(PRIV_OBJ), 1) + +ifeq ($(BIG_ENDIAN), 1) + TARGET = arm_be_g.o +else + TARGET = arm_le_g.o +endif + +endif + + + +$(TARGET): $(filter-out $(TARGET), $(SRC:.c=.o)) + $(LD) $(LDOPTS) -r $^ -o $@ + echo + echo "***********************************" + echo "Build options:" + echo " VERSION $(KVER)" + echo -n " SMP " + if [ "$(SMP)" = "1" ]; \ + then echo "Enabled"; else echo "Disabled"; fi + + +endif # ifeq ($(KVER),2.6) + + +ifeq ($(KVER), 2.6) +install: default +else +install: clean $(TARGET) +endif + mkdir -p $(MOD_ROOT)$(INSTDIR) + install -m 644 -o root $(TARGET) $(MOD_ROOT)$(INSTDIR) + +ifeq (,$(MOD_ROOT)) + /sbin/depmod -a || true +else + /sbin/depmod -b $(MOD_ROOT) -a || true +endif + + +uninstall: + rm -f $(INSTDIR)/$(TARGET) + /sbin/depmod -a + +clean: + rm -f $(TARGET) $(SRC:.c=.o) *~ + rm -f .*.o.d .*.o.cmd .*.ko.cmd *.mod.c *.mod.o + +-include .depend.mak diff --git a/drivers/staging/vt6655/Makefile.x86 b/drivers/staging/vt6655/Makefile.x86 new file mode 100644 index 000000000000..69082f09ba73 --- /dev/null +++ b/drivers/staging/vt6655/Makefile.x86 @@ -0,0 +1,209 @@ +# +# Build options: +# PRIV_OBJ := 1 for object version +# + +IO_MAP := 0 +HOSTAP := 1 +PRIV_OBJ := 1 + +KSP := /lib/modules/$(shell uname -r)/build \ + /usr/src/linux-$(shell uname -r) \ + /usr/src/linux-$(shell uname -r | sed 's/-.*//') \ + /usr/src/kernel-headers-$(shell uname -r) \ + /usr/src/kernel-source-$(shell uname -r) \ + /usr/src/linux-$(shell uname -r | sed 's/\([0-9]*\.[0-9]*\)\..*/\1/') \ + /usr/src/linux + +test_dir = $(shell [ -e $(dir)/include/linux ] && echo $(dir)) +KSP := $(foreach dir, $(KSP), $(test_dir)) + +KSRC := $(firstword $(KSP)) + +ifeq (,$(KSRC)) + $(error Linux kernel source not found) +endif + +# check kernel version +KVER := $(shell uname -r | cut -c1-3 | sed 's/2\.[56]/2\.6/') +KERVER2=$(shell uname -r | cut -d. -f2) + +ifeq ($(KVER), 2.6) +# 2.6 kernel +TARGET = viawget.ko + +else +TARGET = viawget.o + +endif + +INSTDIR := $(shell find /lib/modules/$(shell uname -r) -name $(TARGET) -printf "%h\n" | sort | head -1) +ifeq (,$(INSTDIR)) + ifeq (,$(KERVER2)) + ifneq (,$(wildcard /lib/modules/$(shell uname -r)/kernel)) + INSTDIR := /lib/modules/$(shell uname -r)/kernel/drivers/net + else + INSTDIR := /lib/modules/$(shell uname -r)/net + endif + else + ifneq ($(KERVER2),2) + INSTDIR := /lib/modules/$(shell uname -r)/kernel/drivers/net + else + INSTDIR := /lib/modules/$(shell uname -r)/net + endif + endif +endif + + +SRC = device_main.c card.c mac.c baseband.c wctl.c 80211mgr.c \ + wcmd.c wmgr.c bssdb.c wpa2.c rxtx.c dpc.c power.c datarate.c \ + srom.c mib.c rc4.c tether.c tcrc.c ioctl.c hostap.c wpa.c key.c \ + tkip.c michael.c wroute.c rf.c iwctl.c wpactl.c aes_ccmp.c + +ifeq ($(IO_MAP), 1) + CFLAGS += -DIO_MAP +endif + +ifeq ($(HOSTAP), 1) + CFLAGS += -DHOSTAP +endif + +ifeq ($(PRIV_OBJ), 1) + CFLAGS += -DPRIVATE_OBJ +endif + +CFLAGS += -I$(PWD) -I$(PWD)/../include -I$(PWD)/../solomon + + +# build rule +ifeq ($(KVER), 2.6) +# 2.6 kernel + +ifndef KERNEL_CONF +KERNEL_CONF= $(KSRC)/.config +endif + +include ${KERNEL_CONF} + +obj-m += viawget.o + +viawget-objs := device_main.o card.o mac.o baseband.o wctl.o 80211mgr.o \ + wcmd.o wmgr.o bssdb.o rxtx.o dpc.o power.o datarate.o srom.o \ + mib.o rc4.o tether.o tcrc.o ioctl.o hostap.o wpa.o key.o tkip.o \ + michael.o wroute.o rf.o iwctl.o wpactl.o wpa2.o aes_ccmp.o + +.c.o: + $(CC) $(CFLAGS) -o $@ $< + +default: + make -C $(KSRC) SUBDIRS=$(shell pwd) modules + +else + +# 2.2/2.4 kernel +OBJS := device_main.o card.o mac.o baseband.o wctl.o 80211mgr.o \ + wcmd.o wmgr.o bssdb.o rxtx.o dpc.o power.o datarate.o srom.o \ + mib.o rc4.o tether.o tcrc.o ioctl.o hostap.o wpa.o key.o tkip.o \ + michael.o wroute.o rf.o iwctl.o wpactl.o wpa2.o aes_ccmp.o + +VERSION_FILE := $(KSRC)/include/linux/version.h +CONFIG_FILE := $(KSRC)/include/linux/config.h + + +ifeq (,$(wildcard $(VERSION_FILE))) + $(error Linux kernel source not configured - missing version.h) +endif + +ifeq (,$(wildcard $(CONFIG_FILE))) + $(error Linux kernel source not configured - missing config.h) +endif + +ifneq (,$(findstring egcs-2.91.66, $(shell cat /proc/version))) + CC := kgcc gcc cc +else + CC := gcc cc +endif + +test_cc = $(shell which $(cc) > /dev/null 2>&1 && echo $(cc)) +CC := $(foreach cc, $(CC), $(test_cc)) +CC := $(firstword $(CC)) + +CFLAGS += -Wall -DLINUX -D__KERNEL__ -DMODULE -DEXPORT_SYMTAB -D__NO_VERSION__ -O2 -pipe +CFLAGS += -I$(KSRC)/include -Wstrict-prototypes -fomit-frame-pointer +CFLAGS += $(shell [ -f $(KSRC)/include/linux/modversions.h ] && \ + echo "-DMODVERSIONS -include $(KSRC)/include/linux/modversions.h") + +.SILENT: $(TARGET) clean + + +# look for SMP in config.h +SMP := $(shell $(CC) $(CFLAGS) -E -dM $(CONFIG_FILE) | \ + grep CONFIG_SMP | awk '{ print $$3 }') + +ifneq ($(SMP),1) + SMP := 0 +endif + + +ifeq ($(SMP), 1) + CFLAGS += -D__SMP__ +endif + + +ifeq ($(PRIV_OBJ), 1) + CFLAGS += -DPRIVATE_OBJ + TARGET = x86g_up.o + +ifeq ($(SMP), 1) + TARGET = x86g_smp.o +endif + +endif + + +# check x86_64 +SUBARCH := $(shell uname -m) +ifeq ($(SUBARCH),x86_64) + CFLAGS += -mcmodel=kernel -mno-red-zone +endif + + +$(TARGET): $(filter-out $(TARGET), $(SRC:.c=.o)) + $(LD) -r $^ -o $@ + echo; echo + echo "**************************************************" + echo "Build options:" + echo " VERSION $(KVER)" + echo -n " SMP " + if [ "$(SMP)" = "1" ]; \ + then echo "Enabled"; else echo "Disabled"; fi + + + +endif # ifeq ($(KVER),2.6) + + +ifeq ($(KVER), 2.6) +install: default +else +install: clean $(TARGET) +endif + mkdir -p $(MOD_ROOT)$(INSTDIR) + install -m 644 -o root $(TARGET) $(MOD_ROOT)$(INSTDIR) + +ifeq (,$(MOD_ROOT)) + /sbin/depmod -a || true +else + /sbin/depmod -b $(MOD_ROOT) -a || true +endif + + +uninstall: + rm -f $(INSTDIR)/$(TARGET) + /sbin/depmod -a + +clean: + rm -f $(TARGET) $(SRC:.c=.o) *~ + rm -f .*.o.d .*.o.cmd .*.ko.cmd *.mod.c *.mod.o + +-include .depend.mak diff --git a/drivers/staging/vt6655/aes_ccmp.c b/drivers/staging/vt6655/aes_ccmp.c new file mode 100644 index 000000000000..59cc018d48a2 --- /dev/null +++ b/drivers/staging/vt6655/aes_ccmp.c @@ -0,0 +1,410 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * File: aes_ccmp.c + * + * Purpose: AES_CCMP decryption + * + * Author: Warren Hsu + * + * Date: Feb 15, 2005 + * + * Functions: + * AESbGenCCMP - Parsing RX-packet + * + * + * Revision History: + * + */ + +#if !defined(__UMEM_H__) +#include "umem.h" +#endif +#if !defined(__DEVICE_H__) +#include "device.h" +#endif +#if !defined(__80211HDR_H__) +#include "80211hdr.h" +#endif + + +/*--------------------- Static Definitions -------------------------*/ + +/*--------------------- Static Classes ----------------------------*/ + +/*--------------------- Static Variables --------------------------*/ + +/* + * SBOX Table + */ + +BYTE sbox_table[256] = +{ +0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, +0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, +0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, +0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, +0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, +0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, +0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, +0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, +0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, +0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, +0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, +0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, +0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, +0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, +0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, +0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 +}; + +BYTE dot2_table[256] = { +0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e, +0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e, +0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e, +0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e, +0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e, +0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe, +0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, +0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee, 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe, +0x1b, 0x19, 0x1f, 0x1d, 0x13, 0x11, 0x17, 0x15, 0x0b, 0x09, 0x0f, 0x0d, 0x03, 0x01, 0x07, 0x05, +0x3b, 0x39, 0x3f, 0x3d, 0x33, 0x31, 0x37, 0x35, 0x2b, 0x29, 0x2f, 0x2d, 0x23, 0x21, 0x27, 0x25, +0x5b, 0x59, 0x5f, 0x5d, 0x53, 0x51, 0x57, 0x55, 0x4b, 0x49, 0x4f, 0x4d, 0x43, 0x41, 0x47, 0x45, +0x7b, 0x79, 0x7f, 0x7d, 0x73, 0x71, 0x77, 0x75, 0x6b, 0x69, 0x6f, 0x6d, 0x63, 0x61, 0x67, 0x65, +0x9b, 0x99, 0x9f, 0x9d, 0x93, 0x91, 0x97, 0x95, 0x8b, 0x89, 0x8f, 0x8d, 0x83, 0x81, 0x87, 0x85, +0xbb, 0xb9, 0xbf, 0xbd, 0xb3, 0xb1, 0xb7, 0xb5, 0xab, 0xa9, 0xaf, 0xad, 0xa3, 0xa1, 0xa7, 0xa5, +0xdb, 0xd9, 0xdf, 0xdd, 0xd3, 0xd1, 0xd7, 0xd5, 0xcb, 0xc9, 0xcf, 0xcd, 0xc3, 0xc1, 0xc7, 0xc5, +0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed, 0xe3, 0xe1, 0xe7, 0xe5 +}; + +BYTE dot3_table[256] = { +0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x18, 0x1b, 0x1e, 0x1d, 0x14, 0x17, 0x12, 0x11, +0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f, 0x3a, 0x39, 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21, +0x60, 0x63, 0x66, 0x65, 0x6c, 0x6f, 0x6a, 0x69, 0x78, 0x7b, 0x7e, 0x7d, 0x74, 0x77, 0x72, 0x71, +0x50, 0x53, 0x56, 0x55, 0x5c, 0x5f, 0x5a, 0x59, 0x48, 0x4b, 0x4e, 0x4d, 0x44, 0x47, 0x42, 0x41, +0xc0, 0xc3, 0xc6, 0xc5, 0xcc, 0xcf, 0xca, 0xc9, 0xd8, 0xdb, 0xde, 0xdd, 0xd4, 0xd7, 0xd2, 0xd1, +0xf0, 0xf3, 0xf6, 0xf5, 0xfc, 0xff, 0xfa, 0xf9, 0xe8, 0xeb, 0xee, 0xed, 0xe4, 0xe7, 0xe2, 0xe1, +0xa0, 0xa3, 0xa6, 0xa5, 0xac, 0xaf, 0xaa, 0xa9, 0xb8, 0xbb, 0xbe, 0xbd, 0xb4, 0xb7, 0xb2, 0xb1, +0x90, 0x93, 0x96, 0x95, 0x9c, 0x9f, 0x9a, 0x99, 0x88, 0x8b, 0x8e, 0x8d, 0x84, 0x87, 0x82, 0x81, +0x9b, 0x98, 0x9d, 0x9e, 0x97, 0x94, 0x91, 0x92, 0x83, 0x80, 0x85, 0x86, 0x8f, 0x8c, 0x89, 0x8a, +0xab, 0xa8, 0xad, 0xae, 0xa7, 0xa4, 0xa1, 0xa2, 0xb3, 0xb0, 0xb5, 0xb6, 0xbf, 0xbc, 0xb9, 0xba, +0xfb, 0xf8, 0xfd, 0xfe, 0xf7, 0xf4, 0xf1, 0xf2, 0xe3, 0xe0, 0xe5, 0xe6, 0xef, 0xec, 0xe9, 0xea, +0xcb, 0xc8, 0xcd, 0xce, 0xc7, 0xc4, 0xc1, 0xc2, 0xd3, 0xd0, 0xd5, 0xd6, 0xdf, 0xdc, 0xd9, 0xda, +0x5b, 0x58, 0x5d, 0x5e, 0x57, 0x54, 0x51, 0x52, 0x43, 0x40, 0x45, 0x46, 0x4f, 0x4c, 0x49, 0x4a, +0x6b, 0x68, 0x6d, 0x6e, 0x67, 0x64, 0x61, 0x62, 0x73, 0x70, 0x75, 0x76, 0x7f, 0x7c, 0x79, 0x7a, +0x3b, 0x38, 0x3d, 0x3e, 0x37, 0x34, 0x31, 0x32, 0x23, 0x20, 0x25, 0x26, 0x2f, 0x2c, 0x29, 0x2a, +0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16, 0x1f, 0x1c, 0x19, 0x1a +}; + +/*--------------------- Static Functions --------------------------*/ + +/*--------------------- Export Variables --------------------------*/ + +/*--------------------- Export Functions --------------------------*/ + +void xor_128(BYTE *a, BYTE *b, BYTE *out) +{ +PDWORD dwPtrA = (PDWORD) a; +PDWORD dwPtrB = (PDWORD) b; +PDWORD dwPtrOut =(PDWORD) out; + + (*dwPtrOut++) = (*dwPtrA++) ^ (*dwPtrB++); + (*dwPtrOut++) = (*dwPtrA++) ^ (*dwPtrB++); + (*dwPtrOut++) = (*dwPtrA++) ^ (*dwPtrB++); + (*dwPtrOut++) = (*dwPtrA++) ^ (*dwPtrB++); +} + + +void xor_32(BYTE *a, BYTE *b, BYTE *out) +{ +PDWORD dwPtrA = (PDWORD) a; +PDWORD dwPtrB = (PDWORD) b; +PDWORD dwPtrOut =(PDWORD) out; + + (*dwPtrOut++) = (*dwPtrA++) ^ (*dwPtrB++); +} + +void AddRoundKey(BYTE *key, int round) +{ +BYTE sbox_key[4]; +BYTE rcon_table[10] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36}; + + sbox_key[0] = sbox_table[key[13]]; + sbox_key[1] = sbox_table[key[14]]; + sbox_key[2] = sbox_table[key[15]]; + sbox_key[3] = sbox_table[key[12]]; + + key[0] = key[0] ^ rcon_table[round]; + xor_32(&key[0], sbox_key, &key[0]); + + xor_32(&key[4], &key[0], &key[4]); + xor_32(&key[8], &key[4], &key[8]); + xor_32(&key[12], &key[8], &key[12]); +} + +void SubBytes(BYTE *in, BYTE *out) +{ +int i; + + for (i=0; i< 16; i++) + { + out[i] = sbox_table[in[i]]; + } +} + +void ShiftRows(BYTE *in, BYTE *out) +{ + out[0] = in[0]; + out[1] = in[5]; + out[2] = in[10]; + out[3] = in[15]; + out[4] = in[4]; + out[5] = in[9]; + out[6] = in[14]; + out[7] = in[3]; + out[8] = in[8]; + out[9] = in[13]; + out[10] = in[2]; + out[11] = in[7]; + out[12] = in[12]; + out[13] = in[1]; + out[14] = in[6]; + out[15] = in[11]; +} + +void MixColumns(BYTE *in, BYTE *out) +{ + + out[0] = dot2_table[in[0]] ^ dot3_table[in[1]] ^ in[2] ^ in[3]; + out[1] = in[0] ^ dot2_table[in[1]] ^ dot3_table[in[2]] ^ in[3]; + out[2] = in[0] ^ in[1] ^ dot2_table[in[2]] ^ dot3_table[in[3]]; + out[3] = dot3_table[in[0]] ^ in[1] ^ in[2] ^ dot2_table[in[3]]; +} + + +void AESv128(BYTE *key, BYTE *data, BYTE *ciphertext) +{ +int i; +int round; +BYTE TmpdataA[16]; +BYTE TmpdataB[16]; +BYTE abyRoundKey[16]; + + for(i=0; i<16; i++) + abyRoundKey[i] = key[i]; + + for (round = 0; round < 11; round++) + { + if (round == 0) + { + xor_128(abyRoundKey, data, ciphertext); + AddRoundKey(abyRoundKey, round); + } + else if (round == 10) + { + SubBytes(ciphertext, TmpdataA); + ShiftRows(TmpdataA, TmpdataB); + xor_128(TmpdataB, abyRoundKey, ciphertext); + } + else // round 1 ~ 9 + { + SubBytes(ciphertext, TmpdataA); + ShiftRows(TmpdataA, TmpdataB); + MixColumns(&TmpdataB[0], &TmpdataA[0]); + MixColumns(&TmpdataB[4], &TmpdataA[4]); + MixColumns(&TmpdataB[8], &TmpdataA[8]); + MixColumns(&TmpdataB[12], &TmpdataA[12]); + xor_128(TmpdataA, abyRoundKey, ciphertext); + AddRoundKey(abyRoundKey, round); + } + } + +} + +/* + * Description: AES decryption + * + * Parameters: + * In: + * pbyRxKey - The key used to decrypt + * pbyFrame - Starting address of packet header + * wFrameSize - Total packet size including CRC + * Out: + * none + * + * Return Value: MIC compare result + * + */ +BOOL AESbGenCCMP(PBYTE pbyRxKey, PBYTE pbyFrame, WORD wFrameSize) +{ +BYTE abyNonce[13]; +BYTE MIC_IV[16]; +BYTE MIC_HDR1[16]; +BYTE MIC_HDR2[16]; +BYTE abyMIC[16]; +BYTE abyCTRPLD[16]; +BYTE abyTmp[16]; +BYTE abyPlainText[16]; +BYTE abyLastCipher[16]; + +PS802_11Header pMACHeader = (PS802_11Header) pbyFrame; +PBYTE pbyIV; +PBYTE pbyPayload; +WORD wHLen = 22; +WORD wPayloadSize = wFrameSize - 8 - 8 - 4 - WLAN_HDR_ADDR3_LEN;//8 is IV, 8 is MIC, 4 is CRC +BOOL bA4 = FALSE; +BYTE byTmp; +WORD wCnt; +int ii,jj,kk; + + + pbyIV = pbyFrame + WLAN_HDR_ADDR3_LEN; + if ( WLAN_GET_FC_TODS(*(PWORD)pbyFrame) && + WLAN_GET_FC_FROMDS(*(PWORD)pbyFrame) ) { + bA4 = TRUE; + pbyIV += 6; // 6 is 802.11 address4 + wHLen += 6; + wPayloadSize -= 6; + } + pbyPayload = pbyIV + 8; //IV-length + + abyNonce[0] = 0x00; //now is 0, if Qos here will be priority + MEMvCopy(&(abyNonce[1]), pMACHeader->abyAddr2, U_ETHER_ADDR_LEN); + abyNonce[7] = pbyIV[7]; + abyNonce[8] = pbyIV[6]; + abyNonce[9] = pbyIV[5]; + abyNonce[10] = pbyIV[4]; + abyNonce[11] = pbyIV[1]; + abyNonce[12] = pbyIV[0]; + + //MIC_IV + MIC_IV[0] = 0x59; + MEMvCopy(&(MIC_IV[1]), &(abyNonce[0]), 13); + MIC_IV[14] = (BYTE)(wPayloadSize >> 8); + MIC_IV[15] = (BYTE)(wPayloadSize & 0xff); + + //MIC_HDR1 + MIC_HDR1[0] = (BYTE)(wHLen >> 8); + MIC_HDR1[1] = (BYTE)(wHLen & 0xff); + byTmp = (BYTE)(pMACHeader->wFrameCtl & 0xff); + MIC_HDR1[2] = byTmp & 0x8f; + byTmp = (BYTE)(pMACHeader->wFrameCtl >> 8); + byTmp &= 0x87; + MIC_HDR1[3] = byTmp | 0x40; + MEMvCopy(&(MIC_HDR1[4]), pMACHeader->abyAddr1, U_ETHER_ADDR_LEN); + MEMvCopy(&(MIC_HDR1[10]), pMACHeader->abyAddr2, U_ETHER_ADDR_LEN); + + //MIC_HDR2 + MEMvCopy(&(MIC_HDR2[0]), pMACHeader->abyAddr3, U_ETHER_ADDR_LEN); + byTmp = (BYTE)(pMACHeader->wSeqCtl & 0xff); + MIC_HDR2[6] = byTmp & 0x0f; + MIC_HDR2[7] = 0; + if ( bA4 ) { + MEMvCopy(&(MIC_HDR2[8]), pMACHeader->abyAddr4, U_ETHER_ADDR_LEN); + } else { + MIC_HDR2[8] = 0x00; + MIC_HDR2[9] = 0x00; + MIC_HDR2[10] = 0x00; + MIC_HDR2[11] = 0x00; + MIC_HDR2[12] = 0x00; + MIC_HDR2[13] = 0x00; + } + MIC_HDR2[14] = 0x00; + MIC_HDR2[15] = 0x00; + + //CCMP + AESv128(pbyRxKey,MIC_IV,abyMIC); + for ( kk=0; kk<16; kk++ ) { + abyTmp[kk] = MIC_HDR1[kk] ^ abyMIC[kk]; + } + AESv128(pbyRxKey,abyTmp,abyMIC); + for ( kk=0; kk<16; kk++ ) { + abyTmp[kk] = MIC_HDR2[kk] ^ abyMIC[kk]; + } + AESv128(pbyRxKey,abyTmp,abyMIC); + + wCnt = 1; + abyCTRPLD[0] = 0x01; + MEMvCopy(&(abyCTRPLD[1]), &(abyNonce[0]), 13); + + for(jj=wPayloadSize; jj>16; jj=jj-16) { + + abyCTRPLD[14] = (BYTE) (wCnt >> 8); + abyCTRPLD[15] = (BYTE) (wCnt & 0xff); + + AESv128(pbyRxKey,abyCTRPLD,abyTmp); + + for ( kk=0; kk<16; kk++ ) { + abyPlainText[kk] = abyTmp[kk] ^ pbyPayload[kk]; + } + for ( kk=0; kk<16; kk++ ) { + abyTmp[kk] = abyMIC[kk] ^ abyPlainText[kk]; + } + AESv128(pbyRxKey,abyTmp,abyMIC); + + MEMvCopy(pbyPayload, abyPlainText, 16); + wCnt++; + pbyPayload += 16; + } //for wPayloadSize + + //last payload + MEMvCopy(&(abyLastCipher[0]), pbyPayload, jj); + for ( ii=jj; ii<16; ii++ ) { + abyLastCipher[ii] = 0x00; + } + + abyCTRPLD[14] = (BYTE) (wCnt >> 8); + abyCTRPLD[15] = (BYTE) (wCnt & 0xff); + + AESv128(pbyRxKey,abyCTRPLD,abyTmp); + for ( kk=0; kk<16; kk++ ) { + abyPlainText[kk] = abyTmp[kk] ^ abyLastCipher[kk]; + } + MEMvCopy(pbyPayload, abyPlainText, jj); + pbyPayload += jj; + + //for MIC calculation + for ( ii=jj; ii<16; ii++ ) { + abyPlainText[ii] = 0x00; + } + for ( kk=0; kk<16; kk++ ) { + abyTmp[kk] = abyMIC[kk] ^ abyPlainText[kk]; + } + AESv128(pbyRxKey,abyTmp,abyMIC); + + //=>above is the calculate MIC + //-------------------------------------------- + + wCnt = 0; + abyCTRPLD[14] = (BYTE) (wCnt >> 8); + abyCTRPLD[15] = (BYTE) (wCnt & 0xff); + AESv128(pbyRxKey,abyCTRPLD,abyTmp); + for ( kk=0; kk<8; kk++ ) { + abyTmp[kk] = abyTmp[kk] ^ pbyPayload[kk]; + } + //=>above is the dec-MIC from packet + //-------------------------------------------- + + if ( MEMEqualMemory(abyMIC,abyTmp,8) ) { + return TRUE; + } else { + return FALSE; + } + +} diff --git a/drivers/staging/vt6655/aes_ccmp.h b/drivers/staging/vt6655/aes_ccmp.h new file mode 100644 index 000000000000..2b1920f28609 --- /dev/null +++ b/drivers/staging/vt6655/aes_ccmp.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * File: aes_ccmp.h + * + * Purpose: AES_CCMP Decryption + * + * Author: Warren Hsu + * + * Date: Feb 15, 2005 + * + */ + +#ifndef __AES_H__ +#define __AES_H__ + +#if !defined(__TTYPE_H__) +#include "ttype.h" +#endif + +/*--------------------- Export Definitions -------------------------*/ + +/*--------------------- Export Types ------------------------------*/ + +/*--------------------- Export Classes ----------------------------*/ + +/*--------------------- Export Variables --------------------------*/ + +/*--------------------- Export Functions --------------------------*/ +BOOL AESbGenCCMP(PBYTE pbyRxKey, PBYTE pbyFrame, WORD wFrameSize); + +#endif //__AES_H__ diff --git a/drivers/staging/vt6655/baseband.c b/drivers/staging/vt6655/baseband.c new file mode 100644 index 000000000000..bc6db8699539 --- /dev/null +++ b/drivers/staging/vt6655/baseband.c @@ -0,0 +1,2990 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * File: baseband.c + * + * Purpose: Implement functions to access baseband + * + * Author: Kyle Hsu + * + * Date: Aug.22, 2002 + * + * Functions: + * BBuGetFrameTime - Calculate data frame transmitting time + * BBvCaculateParameter - Caculate PhyLength, PhyService and Phy Signal parameter for baseband Tx + * BBbReadEmbeded - Embeded read baseband register via MAC + * BBbWriteEmbeded - Embeded write baseband register via MAC + * BBbIsRegBitsOn - Test if baseband register bits on + * BBbIsRegBitsOff - Test if baseband register bits off + * BBbVT3253Init - VIA VT3253 baseband chip init code + * BBvReadAllRegs - Read All Baseband Registers + * BBvLoopbackOn - Turn on BaseBand Loopback mode + * BBvLoopbackOff - Turn off BaseBand Loopback mode + * + * Revision History: + * 06-10-2003 Bryan YC Fan: Re-write codes to support VT3253 spec. + * 08-07-2003 Bryan YC Fan: Add MAXIM2827/2825 and RFMD2959 support. + * 08-26-2003 Kyle Hsu : Modify BBuGetFrameTime() and BBvCaculateParameter(). + * cancel the setting of MAC_REG_SOFTPWRCTL on BBbVT3253Init(). + * Add the comments. + * 09-01-2003 Bryan YC Fan: RF & BB tables updated. + * Modified BBvLoopbackOn & BBvLoopbackOff(). + */ + +#if !defined(__TMACRO_H__) +#include "tmacro.h" +#endif +#if !defined(__TBIT_H__) +#include "tbit.h" +#endif +#if !defined(__TETHER_H__) +#include "tether.h" +#endif +#if !defined(__MAC_H__) +#include "mac.h" +#endif +#if !defined(__BASEBAND_H__) +#include "baseband.h" +#endif +#if !defined(__SROM_H__) +#include "srom.h" +#endif +#if !defined(__UMEM_H__) +#include "umem.h" +#endif +#if !defined(__RF_H__) +#include "rf.h" +#endif + +/*--------------------- Static Definitions -------------------------*/ +//static int msglevel =MSG_LEVEL_DEBUG; +static int msglevel =MSG_LEVEL_INFO; + +//#define PLICE_DEBUG + +/*--------------------- Static Classes ----------------------------*/ + +/*--------------------- Static Variables --------------------------*/ +/*--------------------- Static Functions --------------------------*/ + +/*--------------------- Export Variables --------------------------*/ + +/*--------------------- Static Definitions -------------------------*/ + +/*--------------------- Static Classes ----------------------------*/ + +/*--------------------- Static Variables --------------------------*/ + + + +#define CB_VT3253_INIT_FOR_RFMD 446 +BYTE byVT3253InitTab_RFMD[CB_VT3253_INIT_FOR_RFMD][2] = { + {0x00, 0x30}, + {0x01, 0x00}, + {0x02, 0x00}, + {0x03, 0x00}, + {0x04, 0x00}, + {0x05, 0x00}, + {0x06, 0x00}, + {0x07, 0x00}, + {0x08, 0x70}, + {0x09, 0x45}, + {0x0a, 0x2a}, + {0x0b, 0x76}, + {0x0c, 0x00}, + {0x0d, 0x01}, + {0x0e, 0x80}, + {0x0f, 0x00}, + {0x10, 0x00}, + {0x11, 0x00}, + {0x12, 0x00}, + {0x13, 0x00}, + {0x14, 0x00}, + {0x15, 0x00}, + {0x16, 0x00}, + {0x17, 0x00}, + {0x18, 0x00}, + {0x19, 0x00}, + {0x1a, 0x00}, + {0x1b, 0x9d}, + {0x1c, 0x05}, + {0x1d, 0x00}, + {0x1e, 0x00}, + {0x1f, 0x00}, + {0x20, 0x00}, + {0x21, 0x00}, + {0x22, 0x00}, + {0x23, 0x00}, + {0x24, 0x00}, + {0x25, 0x4a}, + {0x26, 0x00}, + {0x27, 0x00}, + {0x28, 0x00}, + {0x29, 0x00}, + {0x2a, 0x00}, + {0x2b, 0x00}, + {0x2c, 0x00}, + {0x2d, 0xa8}, + {0x2e, 0x1a}, + {0x2f, 0x0c}, + {0x30, 0x26}, + {0x31, 0x5b}, + {0x32, 0x00}, + {0x33, 0x00}, + {0x34, 0x00}, + {0x35, 0x00}, + {0x36, 0xaa}, + {0x37, 0xaa}, + {0x38, 0xff}, + {0x39, 0xff}, + {0x3a, 0x00}, + {0x3b, 0x00}, + {0x3c, 0x00}, + {0x3d, 0x0d}, + {0x3e, 0x51}, + {0x3f, 0x04}, + {0x40, 0x00}, + {0x41, 0x08}, + {0x42, 0x00}, + {0x43, 0x08}, + {0x44, 0x06}, + {0x45, 0x14}, + {0x46, 0x05}, + {0x47, 0x08}, + {0x48, 0x00}, + {0x49, 0x00}, + {0x4a, 0x00}, + {0x4b, 0x00}, + {0x4c, 0x09}, + {0x4d, 0x80}, + {0x4e, 0x00}, + {0x4f, 0xc5}, + {0x50, 0x14}, + {0x51, 0x19}, + {0x52, 0x00}, + {0x53, 0x00}, + {0x54, 0x00}, + {0x55, 0x00}, + {0x56, 0x00}, + {0x57, 0x00}, + {0x58, 0x00}, + {0x59, 0xb0}, + {0x5a, 0x00}, + {0x5b, 0x00}, + {0x5c, 0x00}, + {0x5d, 0x00}, + {0x5e, 0x00}, + {0x5f, 0x00}, + {0x60, 0x44}, + {0x61, 0x04}, + {0x62, 0x00}, + {0x63, 0x00}, + {0x64, 0x00}, + {0x65, 0x00}, + {0x66, 0x04}, + {0x67, 0xb7}, + {0x68, 0x00}, + {0x69, 0x00}, + {0x6a, 0x00}, + {0x6b, 0x00}, + {0x6c, 0x00}, + {0x6d, 0x03}, + {0x6e, 0x01}, + {0x6f, 0x00}, + {0x70, 0x00}, + {0x71, 0x00}, + {0x72, 0x00}, + {0x73, 0x00}, + {0x74, 0x00}, + {0x75, 0x00}, + {0x76, 0x00}, + {0x77, 0x00}, + {0x78, 0x00}, + {0x79, 0x00}, + {0x7a, 0x00}, + {0x7b, 0x00}, + {0x7c, 0x00}, + {0x7d, 0x00}, + {0x7e, 0x00}, + {0x7f, 0x00}, + {0x80, 0x0b}, + {0x81, 0x00}, + {0x82, 0x3c}, + {0x83, 0x00}, + {0x84, 0x00}, + {0x85, 0x00}, + {0x86, 0x00}, + {0x87, 0x00}, + {0x88, 0x08}, + {0x89, 0x00}, + {0x8a, 0x08}, + {0x8b, 0xa6}, + {0x8c, 0x84}, + {0x8d, 0x47}, + {0x8e, 0xbb}, + {0x8f, 0x02}, + {0x90, 0x21}, + {0x91, 0x0c}, + {0x92, 0x04}, + {0x93, 0x22}, + {0x94, 0x00}, + {0x95, 0x00}, + {0x96, 0x00}, + {0x97, 0xeb}, + {0x98, 0x00}, + {0x99, 0x00}, + {0x9a, 0x00}, + {0x9b, 0x00}, + {0x9c, 0x00}, + {0x9d, 0x00}, + {0x9e, 0x00}, + {0x9f, 0x00}, + {0xa0, 0x00}, + {0xa1, 0x00}, + {0xa2, 0x00}, + {0xa3, 0x00}, + {0xa4, 0x00}, + {0xa5, 0x00}, + {0xa6, 0x10}, + {0xa7, 0x04}, + {0xa8, 0x10}, + {0xa9, 0x00}, + {0xaa, 0x8f}, + {0xab, 0x00}, + {0xac, 0x00}, + {0xad, 0x00}, + {0xae, 0x00}, + {0xaf, 0x80}, + {0xb0, 0x38}, + {0xb1, 0x00}, + {0xb2, 0x00}, + {0xb3, 0x00}, + {0xb4, 0xee}, + {0xb5, 0xff}, + {0xb6, 0x10}, + {0xb7, 0x00}, + {0xb8, 0x00}, + {0xb9, 0x00}, + {0xba, 0x00}, + {0xbb, 0x03}, + {0xbc, 0x00}, + {0xbd, 0x00}, + {0xbe, 0x00}, + {0xbf, 0x00}, + {0xc0, 0x10}, + {0xc1, 0x10}, + {0xc2, 0x18}, + {0xc3, 0x20}, + {0xc4, 0x10}, + {0xc5, 0x00}, + {0xc6, 0x22}, + {0xc7, 0x14}, + {0xc8, 0x0f}, + {0xc9, 0x08}, + {0xca, 0xa4}, + {0xcb, 0xa7}, + {0xcc, 0x3c}, + {0xcd, 0x10}, + {0xce, 0x20}, + {0xcf, 0x00}, + {0xd0, 0x00}, + {0xd1, 0x10}, + {0xd2, 0x00}, + {0xd3, 0x00}, + {0xd4, 0x10}, + {0xd5, 0x33}, + {0xd6, 0x70}, + {0xd7, 0x01}, + {0xd8, 0x00}, + {0xd9, 0x00}, + {0xda, 0x00}, + {0xdb, 0x00}, + {0xdc, 0x00}, + {0xdd, 0x00}, + {0xde, 0x00}, + {0xdf, 0x00}, + {0xe0, 0x00}, + {0xe1, 0x00}, + {0xe2, 0xcc}, + {0xe3, 0x04}, + {0xe4, 0x08}, + {0xe5, 0x10}, + {0xe6, 0x00}, + {0xe7, 0x0e}, + {0xe8, 0x88}, + {0xe9, 0xd4}, + {0xea, 0x05}, + {0xeb, 0xf0}, + {0xec, 0x79}, + {0xed, 0x0f}, + {0xee, 0x04}, + {0xef, 0x04}, + {0xf0, 0x00}, + {0xf1, 0x00}, + {0xf2, 0x00}, + {0xf3, 0x00}, + {0xf4, 0x00}, + {0xf5, 0x00}, + {0xf6, 0x00}, + {0xf7, 0x00}, + {0xf8, 0x00}, + {0xf9, 0x00}, + {0xF0, 0x00}, + {0xF1, 0xF8}, + {0xF0, 0x80}, + {0xF0, 0x00}, + {0xF1, 0xF4}, + {0xF0, 0x81}, + {0xF0, 0x01}, + {0xF1, 0xF0}, + {0xF0, 0x82}, + {0xF0, 0x02}, + {0xF1, 0xEC}, + {0xF0, 0x83}, + {0xF0, 0x03}, + {0xF1, 0xE8}, + {0xF0, 0x84}, + {0xF0, 0x04}, + {0xF1, 0xE4}, + {0xF0, 0x85}, + {0xF0, 0x05}, + {0xF1, 0xE0}, + {0xF0, 0x86}, + {0xF0, 0x06}, + {0xF1, 0xDC}, + {0xF0, 0x87}, + {0xF0, 0x07}, + {0xF1, 0xD8}, + {0xF0, 0x88}, + {0xF0, 0x08}, + {0xF1, 0xD4}, + {0xF0, 0x89}, + {0xF0, 0x09}, + {0xF1, 0xD0}, + {0xF0, 0x8A}, + {0xF0, 0x0A}, + {0xF1, 0xCC}, + {0xF0, 0x8B}, + {0xF0, 0x0B}, + {0xF1, 0xC8}, + {0xF0, 0x8C}, + {0xF0, 0x0C}, + {0xF1, 0xC4}, + {0xF0, 0x8D}, + {0xF0, 0x0D}, + {0xF1, 0xC0}, + {0xF0, 0x8E}, + {0xF0, 0x0E}, + {0xF1, 0xBC}, + {0xF0, 0x8F}, + {0xF0, 0x0F}, + {0xF1, 0xB8}, + {0xF0, 0x90}, + {0xF0, 0x10}, + {0xF1, 0xB4}, + {0xF0, 0x91}, + {0xF0, 0x11}, + {0xF1, 0xB0}, + {0xF0, 0x92}, + {0xF0, 0x12}, + {0xF1, 0xAC}, + {0xF0, 0x93}, + {0xF0, 0x13}, + {0xF1, 0xA8}, + {0xF0, 0x94}, + {0xF0, 0x14}, + {0xF1, 0xA4}, + {0xF0, 0x95}, + {0xF0, 0x15}, + {0xF1, 0xA0}, + {0xF0, 0x96}, + {0xF0, 0x16}, + {0xF1, 0x9C}, + {0xF0, 0x97}, + {0xF0, 0x17}, + {0xF1, 0x98}, + {0xF0, 0x98}, + {0xF0, 0x18}, + {0xF1, 0x94}, + {0xF0, 0x99}, + {0xF0, 0x19}, + {0xF1, 0x90}, + {0xF0, 0x9A}, + {0xF0, 0x1A}, + {0xF1, 0x8C}, + {0xF0, 0x9B}, + {0xF0, 0x1B}, + {0xF1, 0x88}, + {0xF0, 0x9C}, + {0xF0, 0x1C}, + {0xF1, 0x84}, + {0xF0, 0x9D}, + {0xF0, 0x1D}, + {0xF1, 0x80}, + {0xF0, 0x9E}, + {0xF0, 0x1E}, + {0xF1, 0x7C}, + {0xF0, 0x9F}, + {0xF0, 0x1F}, + {0xF1, 0x78}, + {0xF0, 0xA0}, + {0xF0, 0x20}, + {0xF1, 0x74}, + {0xF0, 0xA1}, + {0xF0, 0x21}, + {0xF1, 0x70}, + {0xF0, 0xA2}, + {0xF0, 0x22}, + {0xF1, 0x6C}, + {0xF0, 0xA3}, + {0xF0, 0x23}, + {0xF1, 0x68}, + {0xF0, 0xA4}, + {0xF0, 0x24}, + {0xF1, 0x64}, + {0xF0, 0xA5}, + {0xF0, 0x25}, + {0xF1, 0x60}, + {0xF0, 0xA6}, + {0xF0, 0x26}, + {0xF1, 0x5C}, + {0xF0, 0xA7}, + {0xF0, 0x27}, + {0xF1, 0x58}, + {0xF0, 0xA8}, + {0xF0, 0x28}, + {0xF1, 0x54}, + {0xF0, 0xA9}, + {0xF0, 0x29}, + {0xF1, 0x50}, + {0xF0, 0xAA}, + {0xF0, 0x2A}, + {0xF1, 0x4C}, + {0xF0, 0xAB}, + {0xF0, 0x2B}, + {0xF1, 0x48}, + {0xF0, 0xAC}, + {0xF0, 0x2C}, + {0xF1, 0x44}, + {0xF0, 0xAD}, + {0xF0, 0x2D}, + {0xF1, 0x40}, + {0xF0, 0xAE}, + {0xF0, 0x2E}, + {0xF1, 0x3C}, + {0xF0, 0xAF}, + {0xF0, 0x2F}, + {0xF1, 0x38}, + {0xF0, 0xB0}, + {0xF0, 0x30}, + {0xF1, 0x34}, + {0xF0, 0xB1}, + {0xF0, 0x31}, + {0xF1, 0x30}, + {0xF0, 0xB2}, + {0xF0, 0x32}, + {0xF1, 0x2C}, + {0xF0, 0xB3}, + {0xF0, 0x33}, + {0xF1, 0x28}, + {0xF0, 0xB4}, + {0xF0, 0x34}, + {0xF1, 0x24}, + {0xF0, 0xB5}, + {0xF0, 0x35}, + {0xF1, 0x20}, + {0xF0, 0xB6}, + {0xF0, 0x36}, + {0xF1, 0x1C}, + {0xF0, 0xB7}, + {0xF0, 0x37}, + {0xF1, 0x18}, + {0xF0, 0xB8}, + {0xF0, 0x38}, + {0xF1, 0x14}, + {0xF0, 0xB9}, + {0xF0, 0x39}, + {0xF1, 0x10}, + {0xF0, 0xBA}, + {0xF0, 0x3A}, + {0xF1, 0x0C}, + {0xF0, 0xBB}, + {0xF0, 0x3B}, + {0xF1, 0x08}, + {0xF0, 0x00}, + {0xF0, 0x3C}, + {0xF1, 0x04}, + {0xF0, 0xBD}, + {0xF0, 0x3D}, + {0xF1, 0x00}, + {0xF0, 0xBE}, + {0xF0, 0x3E}, + {0xF1, 0x00}, + {0xF0, 0xBF}, + {0xF0, 0x3F}, + {0xF1, 0x00}, + {0xF0, 0xC0}, + {0xF0, 0x00}, +}; + +#define CB_VT3253B0_INIT_FOR_RFMD 256 +BYTE byVT3253B0_RFMD[CB_VT3253B0_INIT_FOR_RFMD][2] = { + {0x00, 0x31}, + {0x01, 0x00}, + {0x02, 0x00}, + {0x03, 0x00}, + {0x04, 0x00}, + {0x05, 0x81}, + {0x06, 0x00}, + {0x07, 0x00}, + {0x08, 0x38}, + {0x09, 0x45}, + {0x0a, 0x2a}, + {0x0b, 0x76}, + {0x0c, 0x00}, + {0x0d, 0x00}, + {0x0e, 0x80}, + {0x0f, 0x00}, + {0x10, 0x00}, + {0x11, 0x00}, + {0x12, 0x00}, + {0x13, 0x00}, + {0x14, 0x00}, + {0x15, 0x00}, + {0x16, 0x00}, + {0x17, 0x00}, + {0x18, 0x00}, + {0x19, 0x00}, + {0x1a, 0x00}, + {0x1b, 0x8e}, + {0x1c, 0x06}, + {0x1d, 0x00}, + {0x1e, 0x00}, + {0x1f, 0x00}, + {0x20, 0x00}, + {0x21, 0x00}, + {0x22, 0x00}, + {0x23, 0x00}, + {0x24, 0x00}, + {0x25, 0x4a}, + {0x26, 0x00}, + {0x27, 0x00}, + {0x28, 0x00}, + {0x29, 0x00}, + {0x2a, 0x00}, + {0x2b, 0x00}, + {0x2c, 0x00}, + {0x2d, 0x34}, + {0x2e, 0x18}, + {0x2f, 0x0c}, + {0x30, 0x26}, + {0x31, 0x5b}, + {0x32, 0x00}, + {0x33, 0x00}, + {0x34, 0x00}, + {0x35, 0x00}, + {0x36, 0xaa}, + {0x37, 0xaa}, + {0x38, 0xff}, + {0x39, 0xff}, + {0x3a, 0xf8}, + {0x3b, 0x00}, + {0x3c, 0x00}, + {0x3d, 0x09}, + {0x3e, 0x0d}, + {0x3f, 0x04}, + {0x40, 0x00}, + {0x41, 0x08}, + {0x42, 0x00}, + {0x43, 0x08}, + {0x44, 0x08}, + {0x45, 0x14}, + {0x46, 0x05}, + {0x47, 0x08}, + {0x48, 0x00}, + {0x49, 0x00}, + {0x4a, 0x00}, + {0x4b, 0x00}, + {0x4c, 0x09}, + {0x4d, 0x80}, + {0x4e, 0x00}, + {0x4f, 0xc5}, + {0x50, 0x14}, + {0x51, 0x19}, + {0x52, 0x00}, + {0x53, 0x00}, + {0x54, 0x00}, + {0x55, 0x00}, + {0x56, 0x00}, + {0x57, 0x00}, + {0x58, 0x00}, + {0x59, 0xb0}, + {0x5a, 0x00}, + {0x5b, 0x00}, + {0x5c, 0x00}, + {0x5d, 0x00}, + {0x5e, 0x00}, + {0x5f, 0x00}, + {0x60, 0x39}, + {0x61, 0x83}, + {0x62, 0x00}, + {0x63, 0x00}, + {0x64, 0x00}, + {0x65, 0x00}, + {0x66, 0xc0}, + {0x67, 0x49}, + {0x68, 0x00}, + {0x69, 0x00}, + {0x6a, 0x00}, + {0x6b, 0x00}, + {0x6c, 0x00}, + {0x6d, 0x03}, + {0x6e, 0x01}, + {0x6f, 0x00}, + {0x70, 0x00}, + {0x71, 0x00}, + {0x72, 0x00}, + {0x73, 0x00}, + {0x74, 0x00}, + {0x75, 0x00}, + {0x76, 0x00}, + {0x77, 0x00}, + {0x78, 0x00}, + {0x79, 0x00}, + {0x7a, 0x00}, + {0x7b, 0x00}, + {0x7c, 0x00}, + {0x7d, 0x00}, + {0x7e, 0x00}, + {0x7f, 0x00}, + {0x80, 0x89}, + {0x81, 0x00}, + {0x82, 0x0e}, + {0x83, 0x00}, + {0x84, 0x00}, + {0x85, 0x00}, + {0x86, 0x00}, + {0x87, 0x00}, + {0x88, 0x08}, + {0x89, 0x00}, + {0x8a, 0x0e}, + {0x8b, 0xa7}, + {0x8c, 0x88}, + {0x8d, 0x47}, + {0x8e, 0xaa}, + {0x8f, 0x02}, + {0x90, 0x23}, + {0x91, 0x0c}, + {0x92, 0x06}, + {0x93, 0x08}, + {0x94, 0x00}, + {0x95, 0x00}, + {0x96, 0x00}, + {0x97, 0xeb}, + {0x98, 0x00}, + {0x99, 0x00}, + {0x9a, 0x00}, + {0x9b, 0x00}, + {0x9c, 0x00}, + {0x9d, 0x00}, + {0x9e, 0x00}, + {0x9f, 0x00}, + {0xa0, 0x00}, + {0xa1, 0x00}, + {0xa2, 0x00}, + {0xa3, 0xcd}, + {0xa4, 0x07}, + {0xa5, 0x33}, + {0xa6, 0x18}, + {0xa7, 0x00}, + {0xa8, 0x18}, + {0xa9, 0x00}, + {0xaa, 0x28}, + {0xab, 0x00}, + {0xac, 0x00}, + {0xad, 0x00}, + {0xae, 0x00}, + {0xaf, 0x18}, + {0xb0, 0x38}, + {0xb1, 0x30}, + {0xb2, 0x00}, + {0xb3, 0x00}, + {0xb4, 0x00}, + {0xb5, 0x00}, + {0xb6, 0x84}, + {0xb7, 0xfd}, + {0xb8, 0x00}, + {0xb9, 0x00}, + {0xba, 0x00}, + {0xbb, 0x03}, + {0xbc, 0x00}, + {0xbd, 0x00}, + {0xbe, 0x00}, + {0xbf, 0x00}, + {0xc0, 0x10}, + {0xc1, 0x20}, + {0xc2, 0x18}, + {0xc3, 0x20}, + {0xc4, 0x10}, + {0xc5, 0x2c}, + {0xc6, 0x1e}, + {0xc7, 0x10}, + {0xc8, 0x12}, + {0xc9, 0x01}, + {0xca, 0x6f}, + {0xcb, 0xa7}, + {0xcc, 0x3c}, + {0xcd, 0x10}, + {0xce, 0x00}, + {0xcf, 0x22}, + {0xd0, 0x00}, + {0xd1, 0x10}, + {0xd2, 0x00}, + {0xd3, 0x00}, + {0xd4, 0x10}, + {0xd5, 0x33}, + {0xd6, 0x80}, + {0xd7, 0x21}, + {0xd8, 0x00}, + {0xd9, 0x00}, + {0xda, 0x00}, + {0xdb, 0x00}, + {0xdc, 0x00}, + {0xdd, 0x00}, + {0xde, 0x00}, + {0xdf, 0x00}, + {0xe0, 0x00}, + {0xe1, 0xB3}, + {0xe2, 0x00}, + {0xe3, 0x00}, + {0xe4, 0x00}, + {0xe5, 0x10}, + {0xe6, 0x00}, + {0xe7, 0x18}, + {0xe8, 0x08}, + {0xe9, 0xd4}, + {0xea, 0x00}, + {0xeb, 0xff}, + {0xec, 0x79}, + {0xed, 0x10}, + {0xee, 0x30}, + {0xef, 0x02}, + {0xf0, 0x00}, + {0xf1, 0x09}, + {0xf2, 0x00}, + {0xf3, 0x00}, + {0xf4, 0x00}, + {0xf5, 0x00}, + {0xf6, 0x00}, + {0xf7, 0x00}, + {0xf8, 0x00}, + {0xf9, 0x00}, + {0xfa, 0x00}, + {0xfb, 0x00}, + {0xfc, 0x00}, + {0xfd, 0x00}, + {0xfe, 0x00}, + {0xff, 0x00}, +}; + +#define CB_VT3253B0_AGC_FOR_RFMD2959 195 +// For RFMD2959 +BYTE byVT3253B0_AGC4_RFMD2959[CB_VT3253B0_AGC_FOR_RFMD2959][2] = { + {0xF0, 0x00}, + {0xF1, 0x3E}, + {0xF0, 0x80}, + {0xF0, 0x00}, + {0xF1, 0x3E}, + {0xF0, 0x81}, + {0xF0, 0x01}, + {0xF1, 0x3E}, + {0xF0, 0x82}, + {0xF0, 0x02}, + {0xF1, 0x3E}, + {0xF0, 0x83}, + {0xF0, 0x03}, + {0xF1, 0x3B}, + {0xF0, 0x84}, + {0xF0, 0x04}, + {0xF1, 0x39}, + {0xF0, 0x85}, + {0xF0, 0x05}, + {0xF1, 0x38}, + {0xF0, 0x86}, + {0xF0, 0x06}, + {0xF1, 0x37}, + {0xF0, 0x87}, + {0xF0, 0x07}, + {0xF1, 0x36}, + {0xF0, 0x88}, + {0xF0, 0x08}, + {0xF1, 0x35}, + {0xF0, 0x89}, + {0xF0, 0x09}, + {0xF1, 0x35}, + {0xF0, 0x8A}, + {0xF0, 0x0A}, + {0xF1, 0x34}, + {0xF0, 0x8B}, + {0xF0, 0x0B}, + {0xF1, 0x34}, + {0xF0, 0x8C}, + {0xF0, 0x0C}, + {0xF1, 0x33}, + {0xF0, 0x8D}, + {0xF0, 0x0D}, + {0xF1, 0x32}, + {0xF0, 0x8E}, + {0xF0, 0x0E}, + {0xF1, 0x31}, + {0xF0, 0x8F}, + {0xF0, 0x0F}, + {0xF1, 0x30}, + {0xF0, 0x90}, + {0xF0, 0x10}, + {0xF1, 0x2F}, + {0xF0, 0x91}, + {0xF0, 0x11}, + {0xF1, 0x2F}, + {0xF0, 0x92}, + {0xF0, 0x12}, + {0xF1, 0x2E}, + {0xF0, 0x93}, + {0xF0, 0x13}, + {0xF1, 0x2D}, + {0xF0, 0x94}, + {0xF0, 0x14}, + {0xF1, 0x2C}, + {0xF0, 0x95}, + {0xF0, 0x15}, + {0xF1, 0x2B}, + {0xF0, 0x96}, + {0xF0, 0x16}, + {0xF1, 0x2B}, + {0xF0, 0x97}, + {0xF0, 0x17}, + {0xF1, 0x2A}, + {0xF0, 0x98}, + {0xF0, 0x18}, + {0xF1, 0x29}, + {0xF0, 0x99}, + {0xF0, 0x19}, + {0xF1, 0x28}, + {0xF0, 0x9A}, + {0xF0, 0x1A}, + {0xF1, 0x27}, + {0xF0, 0x9B}, + {0xF0, 0x1B}, + {0xF1, 0x26}, + {0xF0, 0x9C}, + {0xF0, 0x1C}, + {0xF1, 0x25}, + {0xF0, 0x9D}, + {0xF0, 0x1D}, + {0xF1, 0x24}, + {0xF0, 0x9E}, + {0xF0, 0x1E}, + {0xF1, 0x24}, + {0xF0, 0x9F}, + {0xF0, 0x1F}, + {0xF1, 0x23}, + {0xF0, 0xA0}, + {0xF0, 0x20}, + {0xF1, 0x22}, + {0xF0, 0xA1}, + {0xF0, 0x21}, + {0xF1, 0x21}, + {0xF0, 0xA2}, + {0xF0, 0x22}, + {0xF1, 0x20}, + {0xF0, 0xA3}, + {0xF0, 0x23}, + {0xF1, 0x20}, + {0xF0, 0xA4}, + {0xF0, 0x24}, + {0xF1, 0x1F}, + {0xF0, 0xA5}, + {0xF0, 0x25}, + {0xF1, 0x1E}, + {0xF0, 0xA6}, + {0xF0, 0x26}, + {0xF1, 0x1D}, + {0xF0, 0xA7}, + {0xF0, 0x27}, + {0xF1, 0x1C}, + {0xF0, 0xA8}, + {0xF0, 0x28}, + {0xF1, 0x1B}, + {0xF0, 0xA9}, + {0xF0, 0x29}, + {0xF1, 0x1B}, + {0xF0, 0xAA}, + {0xF0, 0x2A}, + {0xF1, 0x1A}, + {0xF0, 0xAB}, + {0xF0, 0x2B}, + {0xF1, 0x1A}, + {0xF0, 0xAC}, + {0xF0, 0x2C}, + {0xF1, 0x19}, + {0xF0, 0xAD}, + {0xF0, 0x2D}, + {0xF1, 0x18}, + {0xF0, 0xAE}, + {0xF0, 0x2E}, + {0xF1, 0x17}, + {0xF0, 0xAF}, + {0xF0, 0x2F}, + {0xF1, 0x16}, + {0xF0, 0xB0}, + {0xF0, 0x30}, + {0xF1, 0x15}, + {0xF0, 0xB1}, + {0xF0, 0x31}, + {0xF1, 0x15}, + {0xF0, 0xB2}, + {0xF0, 0x32}, + {0xF1, 0x15}, + {0xF0, 0xB3}, + {0xF0, 0x33}, + {0xF1, 0x14}, + {0xF0, 0xB4}, + {0xF0, 0x34}, + {0xF1, 0x13}, + {0xF0, 0xB5}, + {0xF0, 0x35}, + {0xF1, 0x12}, + {0xF0, 0xB6}, + {0xF0, 0x36}, + {0xF1, 0x11}, + {0xF0, 0xB7}, + {0xF0, 0x37}, + {0xF1, 0x10}, + {0xF0, 0xB8}, + {0xF0, 0x38}, + {0xF1, 0x0F}, + {0xF0, 0xB9}, + {0xF0, 0x39}, + {0xF1, 0x0E}, + {0xF0, 0xBA}, + {0xF0, 0x3A}, + {0xF1, 0x0D}, + {0xF0, 0xBB}, + {0xF0, 0x3B}, + {0xF1, 0x0C}, + {0xF0, 0xBC}, + {0xF0, 0x3C}, + {0xF1, 0x0B}, + {0xF0, 0xBD}, + {0xF0, 0x3D}, + {0xF1, 0x0B}, + {0xF0, 0xBE}, + {0xF0, 0x3E}, + {0xF1, 0x0A}, + {0xF0, 0xBF}, + {0xF0, 0x3F}, + {0xF1, 0x09}, + {0xF0, 0x00}, +}; + +#define CB_VT3253B0_INIT_FOR_AIROHA2230 256 +// For AIROHA +BYTE byVT3253B0_AIROHA2230[CB_VT3253B0_INIT_FOR_AIROHA2230][2] = { + {0x00, 0x31}, + {0x01, 0x00}, + {0x02, 0x00}, + {0x03, 0x00}, + {0x04, 0x00}, + {0x05, 0x80}, + {0x06, 0x00}, + {0x07, 0x00}, + {0x08, 0x70}, + {0x09, 0x41}, + {0x0a, 0x2A}, + {0x0b, 0x76}, + {0x0c, 0x00}, + {0x0d, 0x00}, + {0x0e, 0x80}, + {0x0f, 0x00}, + {0x10, 0x00}, + {0x11, 0x00}, + {0x12, 0x00}, + {0x13, 0x00}, + {0x14, 0x00}, + {0x15, 0x00}, + {0x16, 0x00}, + {0x17, 0x00}, + {0x18, 0x00}, + {0x19, 0x00}, + {0x1a, 0x00}, + {0x1b, 0x8f}, + {0x1c, 0x09}, + {0x1d, 0x00}, + {0x1e, 0x00}, + {0x1f, 0x00}, + {0x20, 0x00}, + {0x21, 0x00}, + {0x22, 0x00}, + {0x23, 0x00}, + {0x24, 0x00}, + {0x25, 0x4a}, + {0x26, 0x00}, + {0x27, 0x00}, + {0x28, 0x00}, + {0x29, 0x00}, + {0x2a, 0x00}, + {0x2b, 0x00}, + {0x2c, 0x00}, + {0x2d, 0x4a}, + {0x2e, 0x00}, + {0x2f, 0x0a}, + {0x30, 0x26}, + {0x31, 0x5b}, + {0x32, 0x00}, + {0x33, 0x00}, + {0x34, 0x00}, + {0x35, 0x00}, + {0x36, 0xaa}, + {0x37, 0xaa}, + {0x38, 0xff}, + {0x39, 0xff}, + {0x3a, 0x79}, + {0x3b, 0x00}, + {0x3c, 0x00}, + {0x3d, 0x0b}, + {0x3e, 0x48}, + {0x3f, 0x04}, + {0x40, 0x00}, + {0x41, 0x08}, + {0x42, 0x00}, + {0x43, 0x08}, + {0x44, 0x08}, + {0x45, 0x14}, + {0x46, 0x05}, + {0x47, 0x09}, + {0x48, 0x00}, + {0x49, 0x00}, + {0x4a, 0x00}, + {0x4b, 0x00}, + {0x4c, 0x09}, + {0x4d, 0x73}, + {0x4e, 0x00}, + {0x4f, 0xc5}, + {0x50, 0x15}, + {0x51, 0x19}, + {0x52, 0x00}, + {0x53, 0x00}, + {0x54, 0x00}, + {0x55, 0x00}, + {0x56, 0x00}, + {0x57, 0x00}, + {0x58, 0x00}, + {0x59, 0xb0}, + {0x5a, 0x00}, + {0x5b, 0x00}, + {0x5c, 0x00}, + {0x5d, 0x00}, + {0x5e, 0x00}, + {0x5f, 0x00}, + {0x60, 0xe4}, + {0x61, 0x80}, + {0x62, 0x00}, + {0x63, 0x00}, + {0x64, 0x00}, + {0x65, 0x00}, + {0x66, 0x98}, + {0x67, 0x0a}, + {0x68, 0x00}, + {0x69, 0x00}, + {0x6a, 0x00}, + {0x6b, 0x00}, + //{0x6c, 0x80}, + {0x6c, 0x00}, //RobertYu:20050125, request by JJSue + {0x6d, 0x03}, + {0x6e, 0x01}, + {0x6f, 0x00}, + {0x70, 0x00}, + {0x71, 0x00}, + {0x72, 0x00}, + {0x73, 0x00}, + {0x74, 0x00}, + {0x75, 0x00}, + {0x76, 0x00}, + {0x77, 0x00}, + {0x78, 0x00}, + {0x79, 0x00}, + {0x7a, 0x00}, + {0x7b, 0x00}, + {0x7c, 0x00}, + {0x7d, 0x00}, + {0x7e, 0x00}, + {0x7f, 0x00}, + {0x80, 0x8c}, + {0x81, 0x01}, + {0x82, 0x09}, + {0x83, 0x00}, + {0x84, 0x00}, + {0x85, 0x00}, + {0x86, 0x00}, + {0x87, 0x00}, + {0x88, 0x08}, + {0x89, 0x00}, + {0x8a, 0x0f}, + {0x8b, 0xb7}, + {0x8c, 0x88}, + {0x8d, 0x47}, + {0x8e, 0xaa}, + {0x8f, 0x02}, + {0x90, 0x22}, + {0x91, 0x00}, + {0x92, 0x00}, + {0x93, 0x00}, + {0x94, 0x00}, + {0x95, 0x00}, + {0x96, 0x00}, + {0x97, 0xeb}, + {0x98, 0x00}, + {0x99, 0x00}, + {0x9a, 0x00}, + {0x9b, 0x00}, + {0x9c, 0x00}, + {0x9d, 0x00}, + {0x9e, 0x00}, + {0x9f, 0x01}, + {0xa0, 0x00}, + {0xa1, 0x00}, + {0xa2, 0x00}, + {0xa3, 0x00}, + {0xa4, 0x00}, + {0xa5, 0x00}, + {0xa6, 0x10}, + {0xa7, 0x00}, + {0xa8, 0x18}, + {0xa9, 0x00}, + {0xaa, 0x00}, + {0xab, 0x00}, + {0xac, 0x00}, + {0xad, 0x00}, + {0xae, 0x00}, + {0xaf, 0x18}, + {0xb0, 0x38}, + {0xb1, 0x30}, + {0xb2, 0x00}, + {0xb3, 0x00}, + {0xb4, 0xff}, + {0xb5, 0x0f}, + {0xb6, 0xe4}, + {0xb7, 0xe2}, + {0xb8, 0x00}, + {0xb9, 0x00}, + {0xba, 0x00}, + {0xbb, 0x03}, + {0xbc, 0x01}, + {0xbd, 0x00}, + {0xbe, 0x00}, + {0xbf, 0x00}, + {0xc0, 0x18}, + {0xc1, 0x20}, + {0xc2, 0x07}, + {0xc3, 0x18}, + {0xc4, 0xff}, + {0xc5, 0x2c}, + {0xc6, 0x0c}, + {0xc7, 0x0a}, + {0xc8, 0x0e}, + {0xc9, 0x01}, + {0xca, 0x68}, + {0xcb, 0xa7}, + {0xcc, 0x3c}, + {0xcd, 0x10}, + {0xce, 0x00}, + {0xcf, 0x25}, + {0xd0, 0x40}, + {0xd1, 0x12}, + {0xd2, 0x00}, + {0xd3, 0x00}, + {0xd4, 0x10}, + {0xd5, 0x28}, + {0xd6, 0x80}, + {0xd7, 0x2A}, + {0xd8, 0x00}, + {0xd9, 0x00}, + {0xda, 0x00}, + {0xdb, 0x00}, + {0xdc, 0x00}, + {0xdd, 0x00}, + {0xde, 0x00}, + {0xdf, 0x00}, + {0xe0, 0x00}, + {0xe1, 0xB3}, + {0xe2, 0x00}, + {0xe3, 0x00}, + {0xe4, 0x00}, + {0xe5, 0x10}, + {0xe6, 0x00}, + {0xe7, 0x1C}, + {0xe8, 0x00}, + {0xe9, 0xf4}, + {0xea, 0x00}, + {0xeb, 0xff}, + {0xec, 0x79}, + {0xed, 0x20}, + {0xee, 0x30}, + {0xef, 0x01}, + {0xf0, 0x00}, + {0xf1, 0x3e}, + {0xf2, 0x00}, + {0xf3, 0x00}, + {0xf4, 0x00}, + {0xf5, 0x00}, + {0xf6, 0x00}, + {0xf7, 0x00}, + {0xf8, 0x00}, + {0xf9, 0x00}, + {0xfa, 0x00}, + {0xfb, 0x00}, + {0xfc, 0x00}, + {0xfd, 0x00}, + {0xfe, 0x00}, + {0xff, 0x00}, +}; + + + +#define CB_VT3253B0_INIT_FOR_UW2451 256 +//For UW2451 +BYTE byVT3253B0_UW2451[CB_VT3253B0_INIT_FOR_UW2451][2] = { + {0x00, 0x31}, + {0x01, 0x00}, + {0x02, 0x00}, + {0x03, 0x00}, + {0x04, 0x00}, + {0x05, 0x81}, + {0x06, 0x00}, + {0x07, 0x00}, + {0x08, 0x38}, + {0x09, 0x45}, + {0x0a, 0x28}, + {0x0b, 0x76}, + {0x0c, 0x00}, + {0x0d, 0x00}, + {0x0e, 0x80}, + {0x0f, 0x00}, + {0x10, 0x00}, + {0x11, 0x00}, + {0x12, 0x00}, + {0x13, 0x00}, + {0x14, 0x00}, + {0x15, 0x00}, + {0x16, 0x00}, + {0x17, 0x00}, + {0x18, 0x00}, + {0x19, 0x00}, + {0x1a, 0x00}, + {0x1b, 0x8f}, + {0x1c, 0x0f}, + {0x1d, 0x00}, + {0x1e, 0x00}, + {0x1f, 0x00}, + {0x20, 0x00}, + {0x21, 0x00}, + {0x22, 0x00}, + {0x23, 0x00}, + {0x24, 0x00}, + {0x25, 0x4a}, + {0x26, 0x00}, + {0x27, 0x00}, + {0x28, 0x00}, + {0x29, 0x00}, + {0x2a, 0x00}, + {0x2b, 0x00}, + {0x2c, 0x00}, + {0x2d, 0x18}, + {0x2e, 0x00}, + {0x2f, 0x0a}, + {0x30, 0x26}, + {0x31, 0x5b}, + {0x32, 0x00}, + {0x33, 0x00}, + {0x34, 0x00}, + {0x35, 0x00}, + {0x36, 0xaa}, + {0x37, 0xaa}, + {0x38, 0xff}, + {0x39, 0xff}, + {0x3a, 0x00}, + {0x3b, 0x00}, + {0x3c, 0x00}, + {0x3d, 0x03}, + {0x3e, 0x1d}, + {0x3f, 0x04}, + {0x40, 0x00}, + {0x41, 0x08}, + {0x42, 0x00}, + {0x43, 0x08}, + {0x44, 0x08}, + {0x45, 0x14}, + {0x46, 0x05}, + {0x47, 0x09}, + {0x48, 0x00}, + {0x49, 0x00}, + {0x4a, 0x00}, + {0x4b, 0x00}, + {0x4c, 0x09}, + {0x4d, 0x90}, + {0x4e, 0x00}, + {0x4f, 0xc5}, + {0x50, 0x15}, + {0x51, 0x19}, + {0x52, 0x00}, + {0x53, 0x00}, + {0x54, 0x00}, + {0x55, 0x00}, + {0x56, 0x00}, + {0x57, 0x00}, + {0x58, 0x00}, + {0x59, 0xb0}, + {0x5a, 0x00}, + {0x5b, 0x00}, + {0x5c, 0x00}, + {0x5d, 0x00}, + {0x5e, 0x00}, + {0x5f, 0x00}, + {0x60, 0xb3}, + {0x61, 0x81}, + {0x62, 0x00}, + {0x63, 0x00}, + {0x64, 0x00}, + {0x65, 0x00}, + {0x66, 0x57}, + {0x67, 0x6c}, + {0x68, 0x00}, + {0x69, 0x00}, + {0x6a, 0x00}, + {0x6b, 0x00}, + //{0x6c, 0x80}, + {0x6c, 0x00}, //RobertYu:20050125, request by JJSue + {0x6d, 0x03}, + {0x6e, 0x01}, + {0x6f, 0x00}, + {0x70, 0x00}, + {0x71, 0x00}, + {0x72, 0x00}, + {0x73, 0x00}, + {0x74, 0x00}, + {0x75, 0x00}, + {0x76, 0x00}, + {0x77, 0x00}, + {0x78, 0x00}, + {0x79, 0x00}, + {0x7a, 0x00}, + {0x7b, 0x00}, + {0x7c, 0x00}, + {0x7d, 0x00}, + {0x7e, 0x00}, + {0x7f, 0x00}, + {0x80, 0x8c}, + {0x81, 0x00}, + {0x82, 0x0e}, + {0x83, 0x00}, + {0x84, 0x00}, + {0x85, 0x00}, + {0x86, 0x00}, + {0x87, 0x00}, + {0x88, 0x08}, + {0x89, 0x00}, + {0x8a, 0x0e}, + {0x8b, 0xa7}, + {0x8c, 0x88}, + {0x8d, 0x47}, + {0x8e, 0xaa}, + {0x8f, 0x02}, + {0x90, 0x00}, + {0x91, 0x00}, + {0x92, 0x00}, + {0x93, 0x00}, + {0x94, 0x00}, + {0x95, 0x00}, + {0x96, 0x00}, + {0x97, 0xe3}, + {0x98, 0x00}, + {0x99, 0x00}, + {0x9a, 0x00}, + {0x9b, 0x00}, + {0x9c, 0x00}, + {0x9d, 0x00}, + {0x9e, 0x00}, + {0x9f, 0x00}, + {0xa0, 0x00}, + {0xa1, 0x00}, + {0xa2, 0x00}, + {0xa3, 0x00}, + {0xa4, 0x00}, + {0xa5, 0x00}, + {0xa6, 0x10}, + {0xa7, 0x00}, + {0xa8, 0x18}, + {0xa9, 0x00}, + {0xaa, 0x00}, + {0xab, 0x00}, + {0xac, 0x00}, + {0xad, 0x00}, + {0xae, 0x00}, + {0xaf, 0x18}, + {0xb0, 0x18}, + {0xb1, 0x30}, + {0xb2, 0x00}, + {0xb3, 0x00}, + {0xb4, 0x00}, + {0xb5, 0x00}, + {0xb6, 0x00}, + {0xb7, 0x00}, + {0xb8, 0x00}, + {0xb9, 0x00}, + {0xba, 0x00}, + {0xbb, 0x03}, + {0xbc, 0x01}, + {0xbd, 0x00}, + {0xbe, 0x00}, + {0xbf, 0x00}, + {0xc0, 0x10}, + {0xc1, 0x20}, + {0xc2, 0x00}, + {0xc3, 0x20}, + {0xc4, 0x00}, + {0xc5, 0x2c}, + {0xc6, 0x1c}, + {0xc7, 0x10}, + {0xc8, 0x10}, + {0xc9, 0x01}, + {0xca, 0x68}, + {0xcb, 0xa7}, + {0xcc, 0x3c}, + {0xcd, 0x09}, + {0xce, 0x00}, + {0xcf, 0x20}, + {0xd0, 0x40}, + {0xd1, 0x10}, + {0xd2, 0x00}, + {0xd3, 0x00}, + {0xd4, 0x20}, + {0xd5, 0x28}, + {0xd6, 0xa0}, + {0xd7, 0x2a}, + {0xd8, 0x00}, + {0xd9, 0x00}, + {0xda, 0x00}, + {0xdb, 0x00}, + {0xdc, 0x00}, + {0xdd, 0x00}, + {0xde, 0x00}, + {0xdf, 0x00}, + {0xe0, 0x00}, + {0xe1, 0xd3}, + {0xe2, 0xc0}, + {0xe3, 0x00}, + {0xe4, 0x00}, + {0xe5, 0x10}, + {0xe6, 0x00}, + {0xe7, 0x12}, + {0xe8, 0x12}, + {0xe9, 0x34}, + {0xea, 0x00}, + {0xeb, 0xff}, + {0xec, 0x79}, + {0xed, 0x20}, + {0xee, 0x30}, + {0xef, 0x01}, + {0xf0, 0x00}, + {0xf1, 0x3e}, + {0xf2, 0x00}, + {0xf3, 0x00}, + {0xf4, 0x00}, + {0xf5, 0x00}, + {0xf6, 0x00}, + {0xf7, 0x00}, + {0xf8, 0x00}, + {0xf9, 0x00}, + {0xfa, 0x00}, + {0xfb, 0x00}, + {0xfc, 0x00}, + {0xfd, 0x00}, + {0xfe, 0x00}, + {0xff, 0x00}, +}; + +#define CB_VT3253B0_AGC 193 +// For AIROHA +BYTE byVT3253B0_AGC[CB_VT3253B0_AGC][2] = { + {0xF0, 0x00}, + {0xF1, 0x00}, + {0xF0, 0x80}, + {0xF0, 0x01}, + {0xF1, 0x00}, + {0xF0, 0x81}, + {0xF0, 0x02}, + {0xF1, 0x02}, + {0xF0, 0x82}, + {0xF0, 0x03}, + {0xF1, 0x04}, + {0xF0, 0x83}, + {0xF0, 0x03}, + {0xF1, 0x04}, + {0xF0, 0x84}, + {0xF0, 0x04}, + {0xF1, 0x06}, + {0xF0, 0x85}, + {0xF0, 0x05}, + {0xF1, 0x06}, + {0xF0, 0x86}, + {0xF0, 0x06}, + {0xF1, 0x06}, + {0xF0, 0x87}, + {0xF0, 0x07}, + {0xF1, 0x08}, + {0xF0, 0x88}, + {0xF0, 0x08}, + {0xF1, 0x08}, + {0xF0, 0x89}, + {0xF0, 0x09}, + {0xF1, 0x0A}, + {0xF0, 0x8A}, + {0xF0, 0x0A}, + {0xF1, 0x0A}, + {0xF0, 0x8B}, + {0xF0, 0x0B}, + {0xF1, 0x0C}, + {0xF0, 0x8C}, + {0xF0, 0x0C}, + {0xF1, 0x0C}, + {0xF0, 0x8D}, + {0xF0, 0x0D}, + {0xF1, 0x0E}, + {0xF0, 0x8E}, + {0xF0, 0x0E}, + {0xF1, 0x0E}, + {0xF0, 0x8F}, + {0xF0, 0x0F}, + {0xF1, 0x10}, + {0xF0, 0x90}, + {0xF0, 0x10}, + {0xF1, 0x10}, + {0xF0, 0x91}, + {0xF0, 0x11}, + {0xF1, 0x12}, + {0xF0, 0x92}, + {0xF0, 0x12}, + {0xF1, 0x12}, + {0xF0, 0x93}, + {0xF0, 0x13}, + {0xF1, 0x14}, + {0xF0, 0x94}, + {0xF0, 0x14}, + {0xF1, 0x14}, + {0xF0, 0x95}, + {0xF0, 0x15}, + {0xF1, 0x16}, + {0xF0, 0x96}, + {0xF0, 0x16}, + {0xF1, 0x16}, + {0xF0, 0x97}, + {0xF0, 0x17}, + {0xF1, 0x18}, + {0xF0, 0x98}, + {0xF0, 0x18}, + {0xF1, 0x18}, + {0xF0, 0x99}, + {0xF0, 0x19}, + {0xF1, 0x1A}, + {0xF0, 0x9A}, + {0xF0, 0x1A}, + {0xF1, 0x1A}, + {0xF0, 0x9B}, + {0xF0, 0x1B}, + {0xF1, 0x1C}, + {0xF0, 0x9C}, + {0xF0, 0x1C}, + {0xF1, 0x1C}, + {0xF0, 0x9D}, + {0xF0, 0x1D}, + {0xF1, 0x1E}, + {0xF0, 0x9E}, + {0xF0, 0x1E}, + {0xF1, 0x1E}, + {0xF0, 0x9F}, + {0xF0, 0x1F}, + {0xF1, 0x20}, + {0xF0, 0xA0}, + {0xF0, 0x20}, + {0xF1, 0x20}, + {0xF0, 0xA1}, + {0xF0, 0x21}, + {0xF1, 0x22}, + {0xF0, 0xA2}, + {0xF0, 0x22}, + {0xF1, 0x22}, + {0xF0, 0xA3}, + {0xF0, 0x23}, + {0xF1, 0x24}, + {0xF0, 0xA4}, + {0xF0, 0x24}, + {0xF1, 0x24}, + {0xF0, 0xA5}, + {0xF0, 0x25}, + {0xF1, 0x26}, + {0xF0, 0xA6}, + {0xF0, 0x26}, + {0xF1, 0x26}, + {0xF0, 0xA7}, + {0xF0, 0x27}, + {0xF1, 0x28}, + {0xF0, 0xA8}, + {0xF0, 0x28}, + {0xF1, 0x28}, + {0xF0, 0xA9}, + {0xF0, 0x29}, + {0xF1, 0x2A}, + {0xF0, 0xAA}, + {0xF0, 0x2A}, + {0xF1, 0x2A}, + {0xF0, 0xAB}, + {0xF0, 0x2B}, + {0xF1, 0x2C}, + {0xF0, 0xAC}, + {0xF0, 0x2C}, + {0xF1, 0x2C}, + {0xF0, 0xAD}, + {0xF0, 0x2D}, + {0xF1, 0x2E}, + {0xF0, 0xAE}, + {0xF0, 0x2E}, + {0xF1, 0x2E}, + {0xF0, 0xAF}, + {0xF0, 0x2F}, + {0xF1, 0x30}, + {0xF0, 0xB0}, + {0xF0, 0x30}, + {0xF1, 0x30}, + {0xF0, 0xB1}, + {0xF0, 0x31}, + {0xF1, 0x32}, + {0xF0, 0xB2}, + {0xF0, 0x32}, + {0xF1, 0x32}, + {0xF0, 0xB3}, + {0xF0, 0x33}, + {0xF1, 0x34}, + {0xF0, 0xB4}, + {0xF0, 0x34}, + {0xF1, 0x34}, + {0xF0, 0xB5}, + {0xF0, 0x35}, + {0xF1, 0x36}, + {0xF0, 0xB6}, + {0xF0, 0x36}, + {0xF1, 0x36}, + {0xF0, 0xB7}, + {0xF0, 0x37}, + {0xF1, 0x38}, + {0xF0, 0xB8}, + {0xF0, 0x38}, + {0xF1, 0x38}, + {0xF0, 0xB9}, + {0xF0, 0x39}, + {0xF1, 0x3A}, + {0xF0, 0xBA}, + {0xF0, 0x3A}, + {0xF1, 0x3A}, + {0xF0, 0xBB}, + {0xF0, 0x3B}, + {0xF1, 0x3C}, + {0xF0, 0xBC}, + {0xF0, 0x3C}, + {0xF1, 0x3C}, + {0xF0, 0xBD}, + {0xF0, 0x3D}, + {0xF1, 0x3E}, + {0xF0, 0xBE}, + {0xF0, 0x3E}, + {0xF1, 0x3E}, + {0xF0, 0xBF}, + {0xF0, 0x00}, +}; + +const WORD awcFrameTime[MAX_RATE] = +{10, 20, 55, 110, 24, 36, 48, 72, 96, 144, 192, 216}; + + +/*--------------------- Static Functions --------------------------*/ + +static +ULONG +s_ulGetRatio(PSDevice pDevice); + +static +VOID +s_vChangeAntenna( + IN PSDevice pDevice + ); + +static +VOID +s_vChangeAntenna ( + IN PSDevice pDevice + ) +{ + +#ifdef PLICE_DEBUG + //printk("Enter s_vChangeAntenna:original RxMode is %d,TxMode is %d\n",pDevice->byRxAntennaMode,pDevice->byTxAntennaMode); +#endif + if ( pDevice->dwRxAntennaSel == 0) { + pDevice->dwRxAntennaSel=1; + if (pDevice->bTxRxAntInv == TRUE) + BBvSetRxAntennaMode(pDevice->PortOffset, ANT_A); + else + BBvSetRxAntennaMode(pDevice->PortOffset, ANT_B); + } else { + pDevice->dwRxAntennaSel=0; + if (pDevice->bTxRxAntInv == TRUE) + BBvSetRxAntennaMode(pDevice->PortOffset, ANT_B); + else + BBvSetRxAntennaMode(pDevice->PortOffset, ANT_A); + } + if ( pDevice->dwTxAntennaSel == 0) { + pDevice->dwTxAntennaSel=1; + BBvSetTxAntennaMode(pDevice->PortOffset, ANT_B); + } else { + pDevice->dwTxAntennaSel=0; + BBvSetTxAntennaMode(pDevice->PortOffset, ANT_A); + } +} + + +/*--------------------- Export Variables --------------------------*/ +/* + * Description: Calculate data frame transmitting time + * + * Parameters: + * In: + * byPreambleType - Preamble Type + * byPktType - PK_TYPE_11A, PK_TYPE_11B, PK_TYPE_11GB, PK_TYPE_11GA + * cbFrameLength - Baseband Type + * wRate - Tx Rate + * Out: + * + * Return Value: FrameTime + * + */ +UINT +BBuGetFrameTime ( + IN BYTE byPreambleType, + IN BYTE byPktType, + IN UINT cbFrameLength, + IN WORD wRate + ) +{ + UINT uFrameTime; + UINT uPreamble; + UINT uTmp; + UINT uRateIdx = (UINT)wRate; + UINT uRate = 0; + + + if (uRateIdx > RATE_54M) { + return 0; + } + + uRate = (UINT)awcFrameTime[uRateIdx]; + + if (uRateIdx <= 3) { //CCK mode + + if (byPreambleType == 1) {//Short + uPreamble = 96; + } else { + uPreamble = 192; + } + uFrameTime = (cbFrameLength * 80) / uRate; //????? + uTmp = (uFrameTime * uRate) / 80; + if (cbFrameLength != uTmp) { + uFrameTime ++; + } + + return (uPreamble + uFrameTime); + } + else { + uFrameTime = (cbFrameLength * 8 + 22) / uRate; //???????? + uTmp = ((uFrameTime * uRate) - 22) / 8; + if(cbFrameLength != uTmp) { + uFrameTime ++; + } + uFrameTime = uFrameTime * 4; //??????? + if(byPktType != PK_TYPE_11A) { + uFrameTime += 6; //?????? + } + return (20 + uFrameTime); //?????? + } +} + +/* + * Description: Caculate Length, Service, and Signal fields of Phy for Tx + * + * Parameters: + * In: + * pDevice - Device Structure + * cbFrameLength - Tx Frame Length + * wRate - Tx Rate + * Out: + * pwPhyLen - pointer to Phy Length field + * pbyPhySrv - pointer to Phy Service field + * pbyPhySgn - pointer to Phy Signal field + * + * Return Value: none + * + */ +VOID +BBvCaculateParameter ( + IN PSDevice pDevice, + IN UINT cbFrameLength, + IN WORD wRate, + IN BYTE byPacketType, + OUT PWORD pwPhyLen, + OUT PBYTE pbyPhySrv, + OUT PBYTE pbyPhySgn + ) +{ + UINT cbBitCount; + UINT cbUsCount = 0; + UINT cbTmp; + BOOL bExtBit; + BYTE byPreambleType = pDevice->byPreambleType; + BOOL bCCK = pDevice->bCCK; + + cbBitCount = cbFrameLength * 8; + bExtBit = FALSE; + + switch (wRate) { + case RATE_1M : + cbUsCount = cbBitCount; + *pbyPhySgn = 0x00; + break; + + case RATE_2M : + cbUsCount = cbBitCount / 2; + if (byPreambleType == 1) + *pbyPhySgn = 0x09; + else // long preamble + *pbyPhySgn = 0x01; + break; + + case RATE_5M : + if (bCCK == FALSE) + cbBitCount ++; + cbUsCount = (cbBitCount * 10) / 55; + cbTmp = (cbUsCount * 55) / 10; + if (cbTmp != cbBitCount) + cbUsCount ++; + if (byPreambleType == 1) + *pbyPhySgn = 0x0a; + else // long preamble + *pbyPhySgn = 0x02; + break; + + case RATE_11M : + + if (bCCK == FALSE) + cbBitCount ++; + cbUsCount = cbBitCount / 11; + cbTmp = cbUsCount * 11; + if (cbTmp != cbBitCount) { + cbUsCount ++; + if ((cbBitCount - cbTmp) <= 3) + bExtBit = TRUE; + } + if (byPreambleType == 1) + *pbyPhySgn = 0x0b; + else // long preamble + *pbyPhySgn = 0x03; + break; + + case RATE_6M : + if(byPacketType == PK_TYPE_11A) {//11a, 5GHZ + *pbyPhySgn = 0x9B; //1001 1011 + } + else {//11g, 2.4GHZ + *pbyPhySgn = 0x8B; //1000 1011 + } + break; + + case RATE_9M : + if(byPacketType == PK_TYPE_11A) {//11a, 5GHZ + *pbyPhySgn = 0x9F; //1001 1111 + } + else {//11g, 2.4GHZ + *pbyPhySgn = 0x8F; //1000 1111 + } + break; + + case RATE_12M : + if(byPacketType == PK_TYPE_11A) {//11a, 5GHZ + *pbyPhySgn = 0x9A; //1001 1010 + } + else {//11g, 2.4GHZ + *pbyPhySgn = 0x8A; //1000 1010 + } + break; + + case RATE_18M : + if(byPacketType == PK_TYPE_11A) {//11a, 5GHZ + *pbyPhySgn = 0x9E; //1001 1110 + } + else {//11g, 2.4GHZ + *pbyPhySgn = 0x8E; //1000 1110 + } + break; + + case RATE_24M : + if(byPacketType == PK_TYPE_11A) {//11a, 5GHZ + *pbyPhySgn = 0x99; //1001 1001 + } + else {//11g, 2.4GHZ + *pbyPhySgn = 0x89; //1000 1001 + } + break; + + case RATE_36M : + if(byPacketType == PK_TYPE_11A) {//11a, 5GHZ + *pbyPhySgn = 0x9D; //1001 1101 + } + else {//11g, 2.4GHZ + *pbyPhySgn = 0x8D; //1000 1101 + } + break; + + case RATE_48M : + if(byPacketType == PK_TYPE_11A) {//11a, 5GHZ + *pbyPhySgn = 0x98; //1001 1000 + } + else {//11g, 2.4GHZ + *pbyPhySgn = 0x88; //1000 1000 + } + break; + + case RATE_54M : + if (byPacketType == PK_TYPE_11A) {//11a, 5GHZ + *pbyPhySgn = 0x9C; //1001 1100 + } + else {//11g, 2.4GHZ + *pbyPhySgn = 0x8C; //1000 1100 + } + break; + + default : + if (byPacketType == PK_TYPE_11A) {//11a, 5GHZ + *pbyPhySgn = 0x9C; //1001 1100 + } + else {//11g, 2.4GHZ + *pbyPhySgn = 0x8C; //1000 1100 + } + break; + } + + if (byPacketType == PK_TYPE_11B) { + *pbyPhySrv = 0x00; + if (bExtBit) + *pbyPhySrv = *pbyPhySrv | 0x80; + *pwPhyLen = (WORD)cbUsCount; + } + else { + *pbyPhySrv = 0x00; + *pwPhyLen = (WORD)cbFrameLength; + } +} + +/* + * Description: Read a byte from BASEBAND, by embeded programming + * + * Parameters: + * In: + * dwIoBase - I/O base address + * byBBAddr - address of register in Baseband + * Out: + * pbyData - data read + * + * Return Value: TRUE if succeeded; FALSE if failed. + * + */ +BOOL BBbReadEmbeded (DWORD_PTR dwIoBase, BYTE byBBAddr, PBYTE pbyData) +{ + WORD ww; + BYTE byValue; + + // BB reg offset + VNSvOutPortB(dwIoBase + MAC_REG_BBREGADR, byBBAddr); + + // turn on REGR + MACvRegBitsOn(dwIoBase, MAC_REG_BBREGCTL, BBREGCTL_REGR); + // W_MAX_TIMEOUT is the timeout period + for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { + VNSvInPortB(dwIoBase + MAC_REG_BBREGCTL, &byValue); + if (BITbIsBitOn(byValue, BBREGCTL_DONE)) + break; + } + + // get BB data + VNSvInPortB(dwIoBase + MAC_REG_BBREGDATA, pbyData); + + if (ww == W_MAX_TIMEOUT) { + DBG_PORT80(0x30); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO" DBG_PORT80(0x30)\n"); + return FALSE; + } + return TRUE; +} + + +/* + * Description: Write a Byte to BASEBAND, by embeded programming + * + * Parameters: + * In: + * dwIoBase - I/O base address + * byBBAddr - address of register in Baseband + * byData - data to write + * Out: + * none + * + * Return Value: TRUE if succeeded; FALSE if failed. + * + */ +BOOL BBbWriteEmbeded (DWORD_PTR dwIoBase, BYTE byBBAddr, BYTE byData) +{ + WORD ww; + BYTE byValue; + + // BB reg offset + VNSvOutPortB(dwIoBase + MAC_REG_BBREGADR, byBBAddr); + // set BB data + VNSvOutPortB(dwIoBase + MAC_REG_BBREGDATA, byData); + + // turn on BBREGCTL_REGW + MACvRegBitsOn(dwIoBase, MAC_REG_BBREGCTL, BBREGCTL_REGW); + // W_MAX_TIMEOUT is the timeout period + for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { + VNSvInPortB(dwIoBase + MAC_REG_BBREGCTL, &byValue); + if (BITbIsBitOn(byValue, BBREGCTL_DONE)) + break; + } + + if (ww == W_MAX_TIMEOUT) { + DBG_PORT80(0x31); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO" DBG_PORT80(0x31)\n"); + return FALSE; + } + return TRUE; +} + + +/* + * Description: Test if all bits are set for the Baseband register + * + * Parameters: + * In: + * dwIoBase - I/O base address + * byBBAddr - address of register in Baseband + * byTestBits - TestBits + * Out: + * none + * + * Return Value: TRUE if all TestBits are set; FALSE otherwise. + * + */ +BOOL BBbIsRegBitsOn (DWORD_PTR dwIoBase, BYTE byBBAddr, BYTE byTestBits) +{ + BYTE byOrgData; + + BBbReadEmbeded(dwIoBase, byBBAddr, &byOrgData); + return BITbIsAllBitsOn(byOrgData, byTestBits); +} + + +/* + * Description: Test if all bits are clear for the Baseband register + * + * Parameters: + * In: + * dwIoBase - I/O base address + * byBBAddr - address of register in Baseband + * byTestBits - TestBits + * Out: + * none + * + * Return Value: TRUE if all TestBits are clear; FALSE otherwise. + * + */ +BOOL BBbIsRegBitsOff (DWORD_PTR dwIoBase, BYTE byBBAddr, BYTE byTestBits) +{ + BYTE byOrgData; + + BBbReadEmbeded(dwIoBase, byBBAddr, &byOrgData); + return BITbIsAllBitsOff(byOrgData, byTestBits); +} + +/* + * Description: VIA VT3253 Baseband chip init function + * + * Parameters: + * In: + * dwIoBase - I/O base address + * byRevId - Revision ID + * byRFType - RF type + * Out: + * none + * + * Return Value: TRUE if succeeded; FALSE if failed. + * + */ + +BOOL BBbVT3253Init (PSDevice pDevice) +{ + BOOL bResult = TRUE; + int ii; + DWORD_PTR dwIoBase = pDevice->PortOffset; + BYTE byRFType = pDevice->byRFType; + BYTE byLocalID = pDevice->byLocalID; + + if (byRFType == RF_RFMD2959) { + if (byLocalID <= REV_ID_VT3253_A1) { + for (ii = 0; ii < CB_VT3253_INIT_FOR_RFMD; ii++) { + bResult &= BBbWriteEmbeded(dwIoBase,byVT3253InitTab_RFMD[ii][0],byVT3253InitTab_RFMD[ii][1]); + } + } else { + for (ii = 0; ii < CB_VT3253B0_INIT_FOR_RFMD; ii++) { + bResult &= BBbWriteEmbeded(dwIoBase,byVT3253B0_RFMD[ii][0],byVT3253B0_RFMD[ii][1]); + } + for (ii = 0; ii < CB_VT3253B0_AGC_FOR_RFMD2959; ii++) { + bResult &= BBbWriteEmbeded(dwIoBase,byVT3253B0_AGC4_RFMD2959[ii][0],byVT3253B0_AGC4_RFMD2959[ii][1]); + } + VNSvOutPortD(dwIoBase + MAC_REG_ITRTMSET, 0x23); + MACvRegBitsOn(dwIoBase, MAC_REG_PAPEDELAY, BIT0); + } + pDevice->abyBBVGA[0] = 0x18; + pDevice->abyBBVGA[1] = 0x0A; + pDevice->abyBBVGA[2] = 0x0; + pDevice->abyBBVGA[3] = 0x0; + pDevice->ldBmThreshold[0] = -70; + pDevice->ldBmThreshold[1] = -50; + pDevice->ldBmThreshold[2] = 0; + pDevice->ldBmThreshold[3] = 0; + } else if ((byRFType == RF_AIROHA) || (byRFType == RF_AL2230S) ) { + for (ii = 0; ii < CB_VT3253B0_INIT_FOR_AIROHA2230; ii++) { + bResult &= BBbWriteEmbeded(dwIoBase,byVT3253B0_AIROHA2230[ii][0],byVT3253B0_AIROHA2230[ii][1]); + } + for (ii = 0; ii < CB_VT3253B0_AGC; ii++) { + bResult &= BBbWriteEmbeded(dwIoBase,byVT3253B0_AGC[ii][0],byVT3253B0_AGC[ii][1]); + } + pDevice->abyBBVGA[0] = 0x1C; + pDevice->abyBBVGA[1] = 0x10; + pDevice->abyBBVGA[2] = 0x0; + pDevice->abyBBVGA[3] = 0x0; + pDevice->ldBmThreshold[0] = -70; + pDevice->ldBmThreshold[1] = -48; + pDevice->ldBmThreshold[2] = 0; + pDevice->ldBmThreshold[3] = 0; + } else if (byRFType == RF_UW2451) { + for (ii = 0; ii < CB_VT3253B0_INIT_FOR_UW2451; ii++) { + bResult &= BBbWriteEmbeded(dwIoBase,byVT3253B0_UW2451[ii][0],byVT3253B0_UW2451[ii][1]); + } + for (ii = 0; ii < CB_VT3253B0_AGC; ii++) { + bResult &= BBbWriteEmbeded(dwIoBase,byVT3253B0_AGC[ii][0],byVT3253B0_AGC[ii][1]); + } + VNSvOutPortB(dwIoBase + MAC_REG_ITRTMSET, 0x23); + MACvRegBitsOn(dwIoBase, MAC_REG_PAPEDELAY, BIT0); + + pDevice->abyBBVGA[0] = 0x14; + pDevice->abyBBVGA[1] = 0x0A; + pDevice->abyBBVGA[2] = 0x0; + pDevice->abyBBVGA[3] = 0x0; + pDevice->ldBmThreshold[0] = -60; + pDevice->ldBmThreshold[1] = -50; + pDevice->ldBmThreshold[2] = 0; + pDevice->ldBmThreshold[3] = 0; + } else if (byRFType == RF_UW2452) { + for (ii = 0; ii < CB_VT3253B0_INIT_FOR_UW2451; ii++) { + bResult &= BBbWriteEmbeded(dwIoBase,byVT3253B0_UW2451[ii][0],byVT3253B0_UW2451[ii][1]); + } + // Init ANT B select,TX Config CR09 = 0x61->0x45, 0x45->0x41(VC1/VC2 define, make the ANT_A, ANT_B inverted) + //bResult &= BBbWriteEmbeded(dwIoBase,0x09,0x41); + // Init ANT B select,RX Config CR10 = 0x28->0x2A, 0x2A->0x28(VC1/VC2 define, make the ANT_A, ANT_B inverted) + //bResult &= BBbWriteEmbeded(dwIoBase,0x0a,0x28); + // Select VC1/VC2, CR215 = 0x02->0x06 + bResult &= BBbWriteEmbeded(dwIoBase,0xd7,0x06); + + //{{RobertYu:20050125, request by Jack + bResult &= BBbWriteEmbeded(dwIoBase,0x90,0x20); + bResult &= BBbWriteEmbeded(dwIoBase,0x97,0xeb); + //}} + + //{{RobertYu:20050221, request by Jack + bResult &= BBbWriteEmbeded(dwIoBase,0xa6,0x00); + bResult &= BBbWriteEmbeded(dwIoBase,0xa8,0x30); + //}} + bResult &= BBbWriteEmbeded(dwIoBase,0xb0,0x58); + + for (ii = 0; ii < CB_VT3253B0_AGC; ii++) { + bResult &= BBbWriteEmbeded(dwIoBase,byVT3253B0_AGC[ii][0],byVT3253B0_AGC[ii][1]); + } + //VNSvOutPortB(dwIoBase + MAC_REG_ITRTMSET, 0x23); // RobertYu: 20050104, 20050131 disable PA_Delay + //MACvRegBitsOn(dwIoBase, MAC_REG_PAPEDELAY, BIT0); // RobertYu: 20050104, 20050131 disable PA_Delay + + pDevice->abyBBVGA[0] = 0x14; + pDevice->abyBBVGA[1] = 0x0A; + pDevice->abyBBVGA[2] = 0x0; + pDevice->abyBBVGA[3] = 0x0; + pDevice->ldBmThreshold[0] = -60; + pDevice->ldBmThreshold[1] = -50; + pDevice->ldBmThreshold[2] = 0; + pDevice->ldBmThreshold[3] = 0; + //}} RobertYu + + } else if (byRFType == RF_VT3226) { + for (ii = 0; ii < CB_VT3253B0_INIT_FOR_AIROHA2230; ii++) { + bResult &= BBbWriteEmbeded(dwIoBase,byVT3253B0_AIROHA2230[ii][0],byVT3253B0_AIROHA2230[ii][1]); + } + for (ii = 0; ii < CB_VT3253B0_AGC; ii++) { + bResult &= BBbWriteEmbeded(dwIoBase,byVT3253B0_AGC[ii][0],byVT3253B0_AGC[ii][1]); + } + pDevice->abyBBVGA[0] = 0x1C; + pDevice->abyBBVGA[1] = 0x10; + pDevice->abyBBVGA[2] = 0x0; + pDevice->abyBBVGA[3] = 0x0; + pDevice->ldBmThreshold[0] = -70; + pDevice->ldBmThreshold[1] = -48; + pDevice->ldBmThreshold[2] = 0; + pDevice->ldBmThreshold[3] = 0; + // Fix VT3226 DFC system timing issue + MACvSetRFLE_LatchBase(dwIoBase); + //{{ RobertYu: 20050104 + } else if (byRFType == RF_AIROHA7230) { + for (ii = 0; ii < CB_VT3253B0_INIT_FOR_AIROHA2230; ii++) { + bResult &= BBbWriteEmbeded(dwIoBase,byVT3253B0_AIROHA2230[ii][0],byVT3253B0_AIROHA2230[ii][1]); + } + + //{{ RobertYu:20050223, request by JerryChung + // Init ANT B select,TX Config CR09 = 0x61->0x45, 0x45->0x41(VC1/VC2 define, make the ANT_A, ANT_B inverted) + //bResult &= BBbWriteEmbeded(dwIoBase,0x09,0x41); + // Init ANT B select,RX Config CR10 = 0x28->0x2A, 0x2A->0x28(VC1/VC2 define, make the ANT_A, ANT_B inverted) + //bResult &= BBbWriteEmbeded(dwIoBase,0x0a,0x28); + // Select VC1/VC2, CR215 = 0x02->0x06 + bResult &= BBbWriteEmbeded(dwIoBase,0xd7,0x06); + //}} + + for (ii = 0; ii < CB_VT3253B0_AGC; ii++) { + bResult &= BBbWriteEmbeded(dwIoBase,byVT3253B0_AGC[ii][0],byVT3253B0_AGC[ii][1]); + } + pDevice->abyBBVGA[0] = 0x1C; + pDevice->abyBBVGA[1] = 0x10; + pDevice->abyBBVGA[2] = 0x0; + pDevice->abyBBVGA[3] = 0x0; + pDevice->ldBmThreshold[0] = -70; + pDevice->ldBmThreshold[1] = -48; + pDevice->ldBmThreshold[2] = 0; + pDevice->ldBmThreshold[3] = 0; + //}} RobertYu + } else { + // No VGA Table now + pDevice->bUpdateBBVGA = FALSE; + pDevice->abyBBVGA[0] = 0x1C; + } + + if (byLocalID > REV_ID_VT3253_A1) { + BBbWriteEmbeded(dwIoBase, 0x04, 0x7F); + BBbWriteEmbeded(dwIoBase, 0x0D, 0x01); + } + + return bResult; +} + + + +/* + * Description: Read All Baseband Registers + * + * Parameters: + * In: + * dwIoBase - I/O base address + * pbyBBRegs - Point to struct that stores Baseband Registers + * Out: + * none + * + * Return Value: none + * + */ +VOID BBvReadAllRegs (DWORD_PTR dwIoBase, PBYTE pbyBBRegs) +{ + int ii; + BYTE byBase = 1; + for (ii = 0; ii < BB_MAX_CONTEXT_SIZE; ii++) { + BBbReadEmbeded(dwIoBase, (BYTE)(ii*byBase), pbyBBRegs); + pbyBBRegs += byBase; + } +} + +/* + * Description: Turn on BaseBand Loopback mode + * + * Parameters: + * In: + * dwIoBase - I/O base address + * bCCK - If CCK is set + * Out: + * none + * + * Return Value: none + * + */ + + +void BBvLoopbackOn (PSDevice pDevice) +{ + BYTE byData; + DWORD_PTR dwIoBase = pDevice->PortOffset; + + //CR C9 = 0x00 + BBbReadEmbeded(dwIoBase, 0xC9, &pDevice->byBBCRc9);//CR201 + BBbWriteEmbeded(dwIoBase, 0xC9, 0); + BBbReadEmbeded(dwIoBase, 0x4D, &pDevice->byBBCR4d);//CR77 + BBbWriteEmbeded(dwIoBase, 0x4D, 0x90); + + //CR 88 = 0x02(CCK), 0x03(OFDM) + BBbReadEmbeded(dwIoBase, 0x88, &pDevice->byBBCR88);//CR136 + + if (pDevice->uConnectionRate <= RATE_11M) { //CCK + // Enable internal digital loopback: CR33 |= 0000 0001 + BBbReadEmbeded(dwIoBase, 0x21, &byData);//CR33 + BBbWriteEmbeded(dwIoBase, 0x21, (BYTE)(byData | 0x01));//CR33 + // CR154 = 0x00 + BBbWriteEmbeded(dwIoBase, 0x9A, 0); //CR154 + + BBbWriteEmbeded(dwIoBase, 0x88, 0x02);//CR239 + } + else { //OFDM + // Enable internal digital loopback:CR154 |= 0000 0001 + BBbReadEmbeded(dwIoBase, 0x9A, &byData);//CR154 + BBbWriteEmbeded(dwIoBase, 0x9A, (BYTE)(byData | 0x01));//CR154 + // CR33 = 0x00 + BBbWriteEmbeded(dwIoBase, 0x21, 0); //CR33 + + BBbWriteEmbeded(dwIoBase, 0x88, 0x03);//CR239 + } + + //CR14 = 0x00 + BBbWriteEmbeded(dwIoBase, 0x0E, 0);//CR14 + + // Disable TX_IQUN + BBbReadEmbeded(pDevice->PortOffset, 0x09, &pDevice->byBBCR09); + BBbWriteEmbeded(pDevice->PortOffset, 0x09, (BYTE)(pDevice->byBBCR09 & 0xDE)); +} + +/* + * Description: Turn off BaseBand Loopback mode + * + * Parameters: + * In: + * pDevice - Device Structure + * + * Out: + * none + * + * Return Value: none + * + */ +void BBvLoopbackOff (PSDevice pDevice) +{ + BYTE byData; + DWORD_PTR dwIoBase = pDevice->PortOffset; + + BBbWriteEmbeded(dwIoBase, 0xC9, pDevice->byBBCRc9);//CR201 + BBbWriteEmbeded(dwIoBase, 0x88, pDevice->byBBCR88);//CR136 + BBbWriteEmbeded(dwIoBase, 0x09, pDevice->byBBCR09);//CR136 + BBbWriteEmbeded(dwIoBase, 0x4D, pDevice->byBBCR4d);//CR77 + + if (pDevice->uConnectionRate <= RATE_11M) { // CCK + // Set the CR33 Bit2 to disable internal Loopback. + BBbReadEmbeded(dwIoBase, 0x21, &byData);//CR33 + BBbWriteEmbeded(dwIoBase, 0x21, (BYTE)(byData & 0xFE));//CR33 + } + else { // OFDM + BBbReadEmbeded(dwIoBase, 0x9A, &byData);//CR154 + BBbWriteEmbeded(dwIoBase, 0x9A, (BYTE)(byData & 0xFE));//CR154 + } + BBbReadEmbeded(dwIoBase, 0x0E, &byData);//CR14 + BBbWriteEmbeded(dwIoBase, 0x0E, (BYTE)(byData | 0x80));//CR14 + +} + + + +/* + * Description: Set ShortSlotTime mode + * + * Parameters: + * In: + * pDevice - Device Structure + * Out: + * none + * + * Return Value: none + * + */ +VOID +BBvSetShortSlotTime (PSDevice pDevice) +{ + BYTE byBBRxConf=0; + BYTE byBBVGA=0; + + BBbReadEmbeded(pDevice->PortOffset, 0x0A, &byBBRxConf);//CR10 + + if (pDevice->bShortSlotTime) { + byBBRxConf &= 0xDF;//1101 1111 + } else { + byBBRxConf |= 0x20;//0010 0000 + } + + // patch for 3253B0 Baseband with Cardbus module + BBbReadEmbeded(pDevice->PortOffset, 0xE7, &byBBVGA); + if (byBBVGA == pDevice->abyBBVGA[0]) { + byBBRxConf |= 0x20;//0010 0000 + } + + BBbWriteEmbeded(pDevice->PortOffset, 0x0A, byBBRxConf);//CR10 + +} + +VOID BBvSetVGAGainOffset(PSDevice pDevice, BYTE byData) +{ + BYTE byBBRxConf=0; + + BBbWriteEmbeded(pDevice->PortOffset, 0xE7, byData); + + BBbReadEmbeded(pDevice->PortOffset, 0x0A, &byBBRxConf);//CR10 + // patch for 3253B0 Baseband with Cardbus module + if (byData == pDevice->abyBBVGA[0]) { + byBBRxConf |= 0x20;//0010 0000 + } else if (pDevice->bShortSlotTime) { + byBBRxConf &= 0xDF;//1101 1111 + } else { + byBBRxConf |= 0x20;//0010 0000 + } + pDevice->byBBVGACurrent = byData; + BBbWriteEmbeded(pDevice->PortOffset, 0x0A, byBBRxConf);//CR10 +} + + +/* + * Description: Baseband SoftwareReset + * + * Parameters: + * In: + * dwIoBase - I/O base address + * Out: + * none + * + * Return Value: none + * + */ +VOID +BBvSoftwareReset (DWORD_PTR dwIoBase) +{ + BBbWriteEmbeded(dwIoBase, 0x50, 0x40); + BBbWriteEmbeded(dwIoBase, 0x50, 0); + BBbWriteEmbeded(dwIoBase, 0x9C, 0x01); + BBbWriteEmbeded(dwIoBase, 0x9C, 0); +} + +/* + * Description: Baseband Power Save Mode ON + * + * Parameters: + * In: + * dwIoBase - I/O base address + * Out: + * none + * + * Return Value: none + * + */ +VOID +BBvPowerSaveModeON (DWORD_PTR dwIoBase) +{ + BYTE byOrgData; + + BBbReadEmbeded(dwIoBase, 0x0D, &byOrgData); + byOrgData |= BIT0; + BBbWriteEmbeded(dwIoBase, 0x0D, byOrgData); +} + +/* + * Description: Baseband Power Save Mode OFF + * + * Parameters: + * In: + * dwIoBase - I/O base address + * Out: + * none + * + * Return Value: none + * + */ +VOID +BBvPowerSaveModeOFF (DWORD_PTR dwIoBase) +{ + BYTE byOrgData; + + BBbReadEmbeded(dwIoBase, 0x0D, &byOrgData); + byOrgData &= ~(BIT0); + BBbWriteEmbeded(dwIoBase, 0x0D, byOrgData); +} + +/* + * Description: Set Tx Antenna mode + * + * Parameters: + * In: + * pDevice - Device Structure + * byAntennaMode - Antenna Mode + * Out: + * none + * + * Return Value: none + * + */ + +VOID +BBvSetTxAntennaMode (DWORD_PTR dwIoBase, BYTE byAntennaMode) +{ + BYTE byBBTxConf; + +#ifdef PLICE_DEBUG + //printk("Enter BBvSetTxAntennaMode\n"); +#endif + BBbReadEmbeded(dwIoBase, 0x09, &byBBTxConf);//CR09 + if (byAntennaMode == ANT_DIVERSITY) { + // bit 1 is diversity + byBBTxConf |= 0x02; + } else if (byAntennaMode == ANT_A) { + // bit 2 is ANTSEL + byBBTxConf &= 0xF9; // 1111 1001 + } else if (byAntennaMode == ANT_B) { +#ifdef PLICE_DEBUG + //printk("BBvSetTxAntennaMode:ANT_B\n"); +#endif + byBBTxConf &= 0xFD; // 1111 1101 + byBBTxConf |= 0x04; + } + BBbWriteEmbeded(dwIoBase, 0x09, byBBTxConf);//CR09 +} + + + + +/* + * Description: Set Rx Antenna mode + * + * Parameters: + * In: + * pDevice - Device Structure + * byAntennaMode - Antenna Mode + * Out: + * none + * + * Return Value: none + * + */ + +VOID +BBvSetRxAntennaMode (DWORD_PTR dwIoBase, BYTE byAntennaMode) +{ + BYTE byBBRxConf; + + BBbReadEmbeded(dwIoBase, 0x0A, &byBBRxConf);//CR10 + if (byAntennaMode == ANT_DIVERSITY) { + byBBRxConf |= 0x01; + + } else if (byAntennaMode == ANT_A) { + byBBRxConf &= 0xFC; // 1111 1100 + } else if (byAntennaMode == ANT_B) { + byBBRxConf &= 0xFE; // 1111 1110 + byBBRxConf |= 0x02; + } + BBbWriteEmbeded(dwIoBase, 0x0A, byBBRxConf);//CR10 +} + + +/* + * Description: BBvSetDeepSleep + * + * Parameters: + * In: + * pDevice - Device Structure + * Out: + * none + * + * Return Value: none + * + */ +VOID +BBvSetDeepSleep (DWORD_PTR dwIoBase, BYTE byLocalID) +{ + BBbWriteEmbeded(dwIoBase, 0x0C, 0x17);//CR12 + BBbWriteEmbeded(dwIoBase, 0x0D, 0xB9);//CR13 +} + +VOID +BBvExitDeepSleep (DWORD_PTR dwIoBase, BYTE byLocalID) +{ + BBbWriteEmbeded(dwIoBase, 0x0C, 0x00);//CR12 + BBbWriteEmbeded(dwIoBase, 0x0D, 0x01);//CR13 +} + + + +static +ULONG +s_ulGetRatio (PSDevice pDevice) +{ +ULONG ulRatio = 0; +ULONG ulMaxPacket; +ULONG ulPacketNum; + + //This is a thousand-ratio + ulMaxPacket = pDevice->uNumSQ3[RATE_54M]; + if ( pDevice->uNumSQ3[RATE_54M] != 0 ) { + ulPacketNum = pDevice->uNumSQ3[RATE_54M]; + ulRatio = (ulPacketNum * 1000 / pDevice->uDiversityCnt); + //ulRatio = (pDevice->uNumSQ3[RATE_54M] * 1000 / pDevice->uDiversityCnt); + ulRatio += TOP_RATE_54M; + } + if ( pDevice->uNumSQ3[RATE_48M] > ulMaxPacket ) { + ulPacketNum = pDevice->uNumSQ3[RATE_54M] + pDevice->uNumSQ3[RATE_48M]; + ulRatio = (ulPacketNum * 1000 / pDevice->uDiversityCnt); + //ulRatio = (pDevice->uNumSQ3[RATE_48M] * 1000 / pDevice->uDiversityCnt); + ulRatio += TOP_RATE_48M; + ulMaxPacket = pDevice->uNumSQ3[RATE_48M]; + } + if ( pDevice->uNumSQ3[RATE_36M] > ulMaxPacket ) { + ulPacketNum = pDevice->uNumSQ3[RATE_54M] + pDevice->uNumSQ3[RATE_48M] + + pDevice->uNumSQ3[RATE_36M]; + ulRatio = (ulPacketNum * 1000 / pDevice->uDiversityCnt); + //ulRatio = (pDevice->uNumSQ3[RATE_36M] * 1000 / pDevice->uDiversityCnt); + ulRatio += TOP_RATE_36M; + ulMaxPacket = pDevice->uNumSQ3[RATE_36M]; + } + if ( pDevice->uNumSQ3[RATE_24M] > ulMaxPacket ) { + ulPacketNum = pDevice->uNumSQ3[RATE_54M] + pDevice->uNumSQ3[RATE_48M] + + pDevice->uNumSQ3[RATE_36M] + pDevice->uNumSQ3[RATE_24M]; + ulRatio = (ulPacketNum * 1000 / pDevice->uDiversityCnt); + //ulRatio = (pDevice->uNumSQ3[RATE_24M] * 1000 / pDevice->uDiversityCnt); + ulRatio += TOP_RATE_24M; + ulMaxPacket = pDevice->uNumSQ3[RATE_24M]; + } + if ( pDevice->uNumSQ3[RATE_18M] > ulMaxPacket ) { + ulPacketNum = pDevice->uNumSQ3[RATE_54M] + pDevice->uNumSQ3[RATE_48M] + + pDevice->uNumSQ3[RATE_36M] + pDevice->uNumSQ3[RATE_24M] + + pDevice->uNumSQ3[RATE_18M]; + ulRatio = (ulPacketNum * 1000 / pDevice->uDiversityCnt); + //ulRatio = (pDevice->uNumSQ3[RATE_18M] * 1000 / pDevice->uDiversityCnt); + ulRatio += TOP_RATE_18M; + ulMaxPacket = pDevice->uNumSQ3[RATE_18M]; + } + if ( pDevice->uNumSQ3[RATE_12M] > ulMaxPacket ) { + ulPacketNum = pDevice->uNumSQ3[RATE_54M] + pDevice->uNumSQ3[RATE_48M] + + pDevice->uNumSQ3[RATE_36M] + pDevice->uNumSQ3[RATE_24M] + + pDevice->uNumSQ3[RATE_18M] + pDevice->uNumSQ3[RATE_12M]; + ulRatio = (ulPacketNum * 1000 / pDevice->uDiversityCnt); + //ulRatio = (pDevice->uNumSQ3[RATE_12M] * 1000 / pDevice->uDiversityCnt); + ulRatio += TOP_RATE_12M; + ulMaxPacket = pDevice->uNumSQ3[RATE_12M]; + } + if ( pDevice->uNumSQ3[RATE_11M] > ulMaxPacket ) { + ulPacketNum = pDevice->uDiversityCnt - pDevice->uNumSQ3[RATE_1M] - + pDevice->uNumSQ3[RATE_2M] - pDevice->uNumSQ3[RATE_5M] - + pDevice->uNumSQ3[RATE_6M] - pDevice->uNumSQ3[RATE_9M]; + ulRatio = (ulPacketNum * 1000 / pDevice->uDiversityCnt); + //ulRatio = (pDevice->uNumSQ3[RATE_11M] * 1000 / pDevice->uDiversityCnt); + ulRatio += TOP_RATE_11M; + ulMaxPacket = pDevice->uNumSQ3[RATE_11M]; + } + if ( pDevice->uNumSQ3[RATE_9M] > ulMaxPacket ) { + ulPacketNum = pDevice->uDiversityCnt - pDevice->uNumSQ3[RATE_1M] - + pDevice->uNumSQ3[RATE_2M] - pDevice->uNumSQ3[RATE_5M] - + pDevice->uNumSQ3[RATE_6M]; + ulRatio = (ulPacketNum * 1000 / pDevice->uDiversityCnt); + //ulRatio = (pDevice->uNumSQ3[RATE_9M] * 1000 / pDevice->uDiversityCnt); + ulRatio += TOP_RATE_9M; + ulMaxPacket = pDevice->uNumSQ3[RATE_9M]; + } + if ( pDevice->uNumSQ3[RATE_6M] > ulMaxPacket ) { + ulPacketNum = pDevice->uDiversityCnt - pDevice->uNumSQ3[RATE_1M] - + pDevice->uNumSQ3[RATE_2M] - pDevice->uNumSQ3[RATE_5M]; + ulRatio = (ulPacketNum * 1000 / pDevice->uDiversityCnt); + //ulRatio = (pDevice->uNumSQ3[RATE_6M] * 1000 / pDevice->uDiversityCnt); + ulRatio += TOP_RATE_6M; + ulMaxPacket = pDevice->uNumSQ3[RATE_6M]; + } + if ( pDevice->uNumSQ3[RATE_5M] > ulMaxPacket ) { + ulPacketNum = pDevice->uDiversityCnt - pDevice->uNumSQ3[RATE_1M] - + pDevice->uNumSQ3[RATE_2M]; + ulRatio = (ulPacketNum * 1000 / pDevice->uDiversityCnt); + //ulRatio = (pDevice->uNumSQ3[RATE_5M] * 1000 / pDevice->uDiversityCnt); + ulRatio += TOP_RATE_55M; + ulMaxPacket = pDevice->uNumSQ3[RATE_5M]; + } + if ( pDevice->uNumSQ3[RATE_2M] > ulMaxPacket ) { + ulPacketNum = pDevice->uDiversityCnt - pDevice->uNumSQ3[RATE_1M]; + ulRatio = (ulPacketNum * 1000 / pDevice->uDiversityCnt); + //ulRatio = (pDevice->uNumSQ3[RATE_2M] * 1000 / pDevice->uDiversityCnt); + ulRatio += TOP_RATE_2M; + ulMaxPacket = pDevice->uNumSQ3[RATE_2M]; + } + if ( pDevice->uNumSQ3[RATE_1M] > ulMaxPacket ) { + ulPacketNum = pDevice->uDiversityCnt; + ulRatio = (ulPacketNum * 1000 / pDevice->uDiversityCnt); + //ulRatio = (pDevice->uNumSQ3[RATE_1M] * 1000 / pDevice->uDiversityCnt); + ulRatio += TOP_RATE_1M; + } + + return ulRatio; +} + + +VOID +BBvClearAntDivSQ3Value (PSDevice pDevice) +{ + UINT ii; + + pDevice->uDiversityCnt = 0; + for (ii = 0; ii < MAX_RATE; ii++) { + pDevice->uNumSQ3[ii] = 0; + } +} + + +/* + * Description: Antenna Diversity + * + * Parameters: + * In: + * pDevice - Device Structure + * byRSR - RSR from received packet + * bySQ3 - SQ3 value from received packet + * Out: + * none + * + * Return Value: none + * + */ + +VOID +BBvAntennaDiversity (PSDevice pDevice, BYTE byRxRate, BYTE bySQ3) +{ + + if ((byRxRate >= MAX_RATE) || (pDevice->wAntDiversityMaxRate >= MAX_RATE)) { + return; + } + pDevice->uDiversityCnt++; + // DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pDevice->uDiversityCnt = %d\n", (int)pDevice->uDiversityCnt); + + pDevice->uNumSQ3[byRxRate]++; + + if (pDevice->byAntennaState == 0) { + + if (pDevice->uDiversityCnt > pDevice->ulDiversityNValue) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ulDiversityNValue=[%d],54M-[%d]\n", + (int)pDevice->ulDiversityNValue, (int)pDevice->uNumSQ3[(int)pDevice->wAntDiversityMaxRate]); + + if (pDevice->uNumSQ3[pDevice->wAntDiversityMaxRate] < pDevice->uDiversityCnt/2) { + + pDevice->ulRatio_State0 = s_ulGetRatio(pDevice); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"SQ3_State0, rate = [%08x]\n", (int)pDevice->ulRatio_State0); + + if ( pDevice->byTMax == 0 ) + return; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"1.[%08x], uNumSQ3[%d]=%d, %d\n", + (int)pDevice->ulRatio_State0, (int)pDevice->wAntDiversityMaxRate, + (int)pDevice->uNumSQ3[(int)pDevice->wAntDiversityMaxRate], (int)pDevice->uDiversityCnt); +#ifdef PLICE_DEBUG + //printk("BBvAntennaDiversity1:call s_vChangeAntenna\n"); +#endif + s_vChangeAntenna(pDevice); + pDevice->byAntennaState = 1; + del_timer(&pDevice->TimerSQ3Tmax3); + del_timer(&pDevice->TimerSQ3Tmax2); + pDevice->TimerSQ3Tmax1.expires = RUN_AT(pDevice->byTMax * HZ); + add_timer(&pDevice->TimerSQ3Tmax1); + + } else { + + pDevice->TimerSQ3Tmax3.expires = RUN_AT(pDevice->byTMax3 * HZ); + add_timer(&pDevice->TimerSQ3Tmax3); + } + BBvClearAntDivSQ3Value(pDevice); + + } + } else { //byAntennaState == 1 + + if (pDevice->uDiversityCnt > pDevice->ulDiversityMValue) { + + del_timer(&pDevice->TimerSQ3Tmax1); + + pDevice->ulRatio_State1 = s_ulGetRatio(pDevice); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"RX:SQ3_State1, rate0 = %08x,rate1 = %08x\n", + (int)pDevice->ulRatio_State0,(int)pDevice->ulRatio_State1); + + if (pDevice->ulRatio_State1 < pDevice->ulRatio_State0) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"2.[%08x][%08x], uNumSQ3[%d]=%d, %d\n", + (int)pDevice->ulRatio_State0, (int)pDevice->ulRatio_State1, + (int)pDevice->wAntDiversityMaxRate, + (int)pDevice->uNumSQ3[(int)pDevice->wAntDiversityMaxRate], (int)pDevice->uDiversityCnt); +#ifdef PLICE_DEBUG + //printk("BBvAntennaDiversity2:call s_vChangeAntenna\n"); +#endif + s_vChangeAntenna(pDevice); + pDevice->TimerSQ3Tmax3.expires = RUN_AT(pDevice->byTMax3 * HZ); + pDevice->TimerSQ3Tmax2.expires = RUN_AT(pDevice->byTMax2 * HZ); + add_timer(&pDevice->TimerSQ3Tmax3); + add_timer(&pDevice->TimerSQ3Tmax2); + } + pDevice->byAntennaState = 0; + BBvClearAntDivSQ3Value(pDevice); + } + } //byAntennaState +} + +/*+ + * + * Description: + * Timer for SQ3 antenna diversity + * + * Parameters: + * In: + * Out: + * none + * + * Return Value: none + * +-*/ + +VOID +TimerSQ3CallBack ( + IN HANDLE hDeviceContext + ) +{ + PSDevice pDevice = (PSDevice)hDeviceContext; + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"TimerSQ3CallBack..."); + + + spin_lock_irq(&pDevice->lock); + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"3.[%08x][%08x], %d\n",(int)pDevice->ulRatio_State0, (int)pDevice->ulRatio_State1, (int)pDevice->uDiversityCnt); +#ifdef PLICE_DEBUG + //printk("TimerSQ3CallBack1:call s_vChangeAntenna\n"); +#endif + + s_vChangeAntenna(pDevice); + pDevice->byAntennaState = 0; + BBvClearAntDivSQ3Value(pDevice); + + pDevice->TimerSQ3Tmax3.expires = RUN_AT(pDevice->byTMax3 * HZ); + pDevice->TimerSQ3Tmax2.expires = RUN_AT(pDevice->byTMax2 * HZ); + add_timer(&pDevice->TimerSQ3Tmax3); + add_timer(&pDevice->TimerSQ3Tmax2); + + spin_unlock_irq(&pDevice->lock); + + return; +} + + +/*+ + * + * Description: + * Timer for SQ3 antenna diversity + * + * Parameters: + * In: + * pvSysSpec1 + * hDeviceContext - Pointer to the adapter + * pvSysSpec2 + * pvSysSpec3 + * Out: + * none + * + * Return Value: none + * +-*/ + +VOID +TimerState1CallBack ( + IN HANDLE hDeviceContext + ) +{ + PSDevice pDevice = (PSDevice)hDeviceContext; + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"TimerState1CallBack..."); + + spin_lock_irq(&pDevice->lock); + if (pDevice->uDiversityCnt < pDevice->ulDiversityMValue/100) { +#ifdef PLICE_DEBUG + //printk("TimerSQ3CallBack2:call s_vChangeAntenna\n"); +#endif + + s_vChangeAntenna(pDevice); + pDevice->TimerSQ3Tmax3.expires = RUN_AT(pDevice->byTMax3 * HZ); + pDevice->TimerSQ3Tmax2.expires = RUN_AT(pDevice->byTMax2 * HZ); + add_timer(&pDevice->TimerSQ3Tmax3); + add_timer(&pDevice->TimerSQ3Tmax2); + } else { + pDevice->ulRatio_State1 = s_ulGetRatio(pDevice); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"SQ3_State1, rate0 = %08x,rate1 = %08x\n", + (int)pDevice->ulRatio_State0,(int)pDevice->ulRatio_State1); + + if ( pDevice->ulRatio_State1 < pDevice->ulRatio_State0 ) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"2.[%08x][%08x], uNumSQ3[%d]=%d, %d\n", + (int)pDevice->ulRatio_State0, (int)pDevice->ulRatio_State1, + (int)pDevice->wAntDiversityMaxRate, + (int)pDevice->uNumSQ3[(int)pDevice->wAntDiversityMaxRate], (int)pDevice->uDiversityCnt); +#ifdef PLICE_DEBUG + //printk("TimerSQ3CallBack3:call s_vChangeAntenna\n"); +#endif + + s_vChangeAntenna(pDevice); + + pDevice->TimerSQ3Tmax3.expires = RUN_AT(pDevice->byTMax3 * HZ); + pDevice->TimerSQ3Tmax2.expires = RUN_AT(pDevice->byTMax2 * HZ); + add_timer(&pDevice->TimerSQ3Tmax3); + add_timer(&pDevice->TimerSQ3Tmax2); + } + } + pDevice->byAntennaState = 0; + BBvClearAntDivSQ3Value(pDevice); + spin_unlock_irq(&pDevice->lock); + + return; +} + diff --git a/drivers/staging/vt6655/baseband.h b/drivers/staging/vt6655/baseband.h new file mode 100644 index 000000000000..09cf4f961ac2 --- /dev/null +++ b/drivers/staging/vt6655/baseband.h @@ -0,0 +1,198 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * File: baseband.h + * + * Purpose: Implement functions to access baseband + * + * Author: Jerry Chen + * + * Date: Jun. 5, 2002 + * + */ + + +#ifndef __BASEBAND_H__ +#define __BASEBAND_H__ + + +#if !defined(__TTYPE_H__) +#include "ttype.h" +#endif + +#if !defined(__TETHER_H__) +#include "tether.h" +#endif + +#if !defined(__DEVICE_H__) +#include "device.h" +#endif + + +/*--------------------- Export Definitions -------------------------*/ + +// +// Registers in the BASEBAND +// +#define BB_MAX_CONTEXT_SIZE 256 + + +// +// Baseband RF pair definition in eeprom (Bits 6..0) +// + +/* +#define RATE_1M 0 +#define RATE_2M 1 +#define RATE_5M 2 +#define RATE_11M 3 +#define RATE_6M 4 +#define RATE_9M 5 +#define RATE_12M 6 +#define RATE_18M 7 +#define RATE_24M 8 +#define RATE_36M 9 +#define RATE_48M 10 +#define RATE_54M 11 +#define RATE_AUTO 12 +#define MAX_RATE 12 + + +//0:11A 1:11B 2:11G +#define BB_TYPE_11A 0 +#define BB_TYPE_11B 1 +#define BB_TYPE_11G 2 + +//0:11a,1:11b,2:11gb(only CCK in BasicRate),3:11ga(OFDM in Basic Rate) +#define PK_TYPE_11A 0 +#define PK_TYPE_11B 1 +#define PK_TYPE_11GB 2 +#define PK_TYPE_11GA 3 +*/ + + +#define PREAMBLE_LONG 0 +#define PREAMBLE_SHORT 1 + + +#define F5G 0 +#define F2_4G 1 + +#define TOP_RATE_54M 0x80000000 +#define TOP_RATE_48M 0x40000000 +#define TOP_RATE_36M 0x20000000 +#define TOP_RATE_24M 0x10000000 +#define TOP_RATE_18M 0x08000000 +#define TOP_RATE_12M 0x04000000 +#define TOP_RATE_11M 0x02000000 +#define TOP_RATE_9M 0x01000000 +#define TOP_RATE_6M 0x00800000 +#define TOP_RATE_55M 0x00400000 +#define TOP_RATE_2M 0x00200000 +#define TOP_RATE_1M 0x00100000 + +/*--------------------- Export Types ------------------------------*/ + +/*--------------------- Export Macros ------------------------------*/ + + + +#define BBvClearFOE(dwIoBase) \ +{ \ + BBbWriteEmbeded(dwIoBase, 0xB1, 0); \ +} + +#define BBvSetFOE(dwIoBase) \ +{ \ + BBbWriteEmbeded(dwIoBase, 0xB1, 0x0C); \ +} + + +/*--------------------- Export Classes ----------------------------*/ + +/*--------------------- Export Variables --------------------------*/ + +/*--------------------- Export Functions --------------------------*/ +#ifdef __cplusplus +extern "C" { /* Assume C declarations for C++ */ +#endif /* __cplusplus */ + +UINT +BBuGetFrameTime( + IN BYTE byPreambleType, + IN BYTE byPktType, + IN UINT cbFrameLength, + IN WORD wRate + ); + +VOID +BBvCaculateParameter ( + IN PSDevice pDevice, + IN UINT cbFrameLength, + IN WORD wRate, + IN BYTE byPacketType, + OUT PWORD pwPhyLen, + OUT PBYTE pbyPhySrv, + OUT PBYTE pbyPhySgn + ); + +BOOL BBbReadEmbeded(DWORD_PTR dwIoBase, BYTE byBBAddr, PBYTE pbyData); +BOOL BBbWriteEmbeded(DWORD_PTR dwIoBase, BYTE byBBAddr, BYTE byData); + +VOID BBvReadAllRegs(DWORD_PTR dwIoBase, PBYTE pbyBBRegs); +void BBvLoopbackOn(PSDevice pDevice); +void BBvLoopbackOff(PSDevice pDevice); +void BBvSetShortSlotTime(PSDevice pDevice); +BOOL BBbIsRegBitsOn(DWORD_PTR dwIoBase, BYTE byBBAddr, BYTE byTestBits); +BOOL BBbIsRegBitsOff(DWORD_PTR dwIoBase, BYTE byBBAddr, BYTE byTestBits); +VOID BBvSetVGAGainOffset(PSDevice pDevice, BYTE byData); + +// VT3253 Baseband +BOOL BBbVT3253Init(PSDevice pDevice); +VOID BBvSoftwareReset(DWORD_PTR dwIoBase); +VOID BBvPowerSaveModeON(DWORD_PTR dwIoBase); +VOID BBvPowerSaveModeOFF(DWORD_PTR dwIoBase); +VOID BBvSetTxAntennaMode(DWORD_PTR dwIoBase, BYTE byAntennaMode); +VOID BBvSetRxAntennaMode(DWORD_PTR dwIoBase, BYTE byAntennaMode); +VOID BBvSetDeepSleep(DWORD_PTR dwIoBase, BYTE byLocalID); +VOID BBvExitDeepSleep(DWORD_PTR dwIoBase, BYTE byLocalID); + +// timer for antenna diversity +VOID +TimerSQ3CallBack( + IN HANDLE hDeviceContext + ); +VOID +TimerState1CallBack( + IN HANDLE hDeviceContext + ); + +void BBvAntennaDiversity(PSDevice pDevice, BYTE byRxRate, BYTE bySQ3); +VOID +BBvClearAntDivSQ3Value (PSDevice pDevice); + + +#ifdef __cplusplus +} /* End of extern "C" { */ +#endif /* __cplusplus */ + + +#endif // __BASEBAND_H__ + + + diff --git a/drivers/staging/vt6655/bssdb.c b/drivers/staging/vt6655/bssdb.c new file mode 100644 index 000000000000..746fadcffe8a --- /dev/null +++ b/drivers/staging/vt6655/bssdb.c @@ -0,0 +1,1786 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * File: bssdb.c + * + * Purpose: Handles the Basic Service Set & Node Database functions + * + * Functions: + * BSSpSearchBSSList - Search known BSS list for Desire SSID or BSSID + * BSSvClearBSSList - Clear BSS List + * BSSbInsertToBSSList - Insert a BSS set into known BSS list + * BSSbUpdateToBSSList - Update BSS set in known BSS list + * BSSDBbIsSTAInNodeDB - Search Node DB table to find the index of matched DstAddr + * BSSvCreateOneNode - Allocate an Node for Node DB + * BSSvUpdateAPNode - Update AP Node content in Index 0 of KnownNodeDB + * BSSvSecondCallBack - One second timer callback function to update Node DB info & AP link status + * BSSvUpdateNodeTxCounter - Update Tx attemps, Tx failure counter in Node DB for auto-fall back rate control + * + * Revision History: + * + * Author: Lyndon Chen + * + * Date: July 17, 2002 + * + */ + + +#if !defined(__TBIT_H__) +#include "tbit.h" +#endif//chester +#if !defined(__TTYPE_H__) +#include "ttype.h" +#endif +#if !defined(__TMACRO_H__) +#include "tmacro.h" +#endif +#if !defined(__TETHER_H__) +#include "tether.h" +#endif +#if !defined(__DEVICE_H__) +#include "device.h" +#endif +#if !defined(__80211HDR_H__) +#include "80211hdr.h" +#endif +#if !defined(__BSSDB_H__) +#include "bssdb.h" +#endif +#if !defined(__WMGR_H__) +#include "wmgr.h" +#endif +#if !defined(__DATARATE_H__) +#include "datarate.h" +#endif +#if !defined(__DESC_H__) +#include "desc.h" +#endif +#if !defined(__WCMD_H__) +#include "wcmd.h" +#endif +#if !defined(__WPA_H__) +#include "wpa.h" +#endif +#if !defined(__BASEBAND_H__) +#include "baseband.h" +#endif +#if !defined(__RF_H__) +#include "rf.h" +#endif +#if !defined(__CARD_H__) +#include "card.h" +#endif +#if !defined(__MAC_H__) +#include "mac.h" +#endif +#if !defined(__WPA2_H__) +#include "wpa2.h" +#endif +#if !defined(__UMEM_H__) +#include "umem.h" +#endif +//DavidWang +#if !defined(__IOWPA_H__) +#include "iowpa.h" +#endif + +//#define PLICE_DEBUG +/*--------------------- Static Definitions -------------------------*/ + + + + +/*--------------------- Static Classes ----------------------------*/ + +/*--------------------- Static Variables --------------------------*/ +static int msglevel =MSG_LEVEL_INFO; +//static int msglevel =MSG_LEVEL_DEBUG; + + + +const WORD awHWRetry0[5][5] = { + {RATE_18M, RATE_18M, RATE_12M, RATE_12M, RATE_12M}, + {RATE_24M, RATE_24M, RATE_18M, RATE_12M, RATE_12M}, + {RATE_36M, RATE_36M, RATE_24M, RATE_18M, RATE_18M}, + {RATE_48M, RATE_48M, RATE_36M, RATE_24M, RATE_24M}, + {RATE_54M, RATE_54M, RATE_48M, RATE_36M, RATE_36M} + }; +const WORD awHWRetry1[5][5] = { + {RATE_18M, RATE_18M, RATE_12M, RATE_6M, RATE_6M}, + {RATE_24M, RATE_24M, RATE_18M, RATE_6M, RATE_6M}, + {RATE_36M, RATE_36M, RATE_24M, RATE_12M, RATE_12M}, + {RATE_48M, RATE_48M, RATE_24M, RATE_12M, RATE_12M}, + {RATE_54M, RATE_54M, RATE_36M, RATE_18M, RATE_18M} + }; + + + +/*--------------------- Static Functions --------------------------*/ + +VOID s_vCheckSensitivity( + IN HANDLE hDeviceContext + ); + +#ifdef Calcu_LinkQual +VOID s_uCalculateLinkQual( + IN HANDLE hDeviceContext + ); +#endif + + +VOID s_vCheckPreEDThreshold( + IN HANDLE hDeviceContext + ); +/*--------------------- Export Variables --------------------------*/ + + +/*--------------------- Export Functions --------------------------*/ + + + + + +/*+ + * + * Routine Description: + * Search known BSS list for Desire SSID or BSSID. + * + * Return Value: + * PTR to KnownBSS or NULL + * +-*/ + +PKnownBSS +BSSpSearchBSSList( + IN HANDLE hDeviceContext, + IN PBYTE pbyDesireBSSID, + IN PBYTE pbyDesireSSID, + IN CARD_PHY_TYPE ePhyType + ) +{ + PSDevice pDevice = (PSDevice)hDeviceContext; + PSMgmtObject pMgmt = pDevice->pMgmt; + PBYTE pbyBSSID = NULL; + PWLAN_IE_SSID pSSID = NULL; + PKnownBSS pCurrBSS = NULL; + PKnownBSS pSelect = NULL; +BYTE ZeroBSSID[WLAN_BSSID_LEN]={0x00,0x00,0x00,0x00,0x00,0x00}; + UINT ii = 0; +// UINT jj = 0; //DavidWang + if (pbyDesireBSSID != NULL) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"BSSpSearchBSSList BSSID[%02X %02X %02X-%02X %02X %02X]\n", + *pbyDesireBSSID,*(pbyDesireBSSID+1),*(pbyDesireBSSID+2), + *(pbyDesireBSSID+3),*(pbyDesireBSSID+4),*(pbyDesireBSSID+5)); + if ((!IS_BROADCAST_ADDRESS(pbyDesireBSSID)) && + (memcmp(pbyDesireBSSID, ZeroBSSID, 6)!= 0)) { + pbyBSSID = pbyDesireBSSID; + } + } + if (pbyDesireSSID != NULL) { + if (((PWLAN_IE_SSID)pbyDesireSSID)->len != 0) { + pSSID = (PWLAN_IE_SSID) pbyDesireSSID; + } + } + + if (pbyBSSID != NULL) { + // match BSSID first + for (ii = 0; ii sBSSList[ii]); +if(pDevice->bLinkPass==FALSE) pCurrBSS->bSelected = FALSE; + if ((pCurrBSS->bActive) && + (pCurrBSS->bSelected == FALSE)) { + if (IS_ETH_ADDRESS_EQUAL(pCurrBSS->abyBSSID, pbyBSSID)) { + if (pSSID != NULL) { + // compare ssid + if (MEMEqualMemory(pSSID->abySSID, + ((PWLAN_IE_SSID)pCurrBSS->abySSID)->abySSID, + pSSID->len)) { + if ((pMgmt->eConfigMode == WMAC_CONFIG_AUTO) || + ((pMgmt->eConfigMode == WMAC_CONFIG_IBSS_STA) && WLAN_GET_CAP_INFO_IBSS(pCurrBSS->wCapInfo)) || + ((pMgmt->eConfigMode == WMAC_CONFIG_ESS_STA) && WLAN_GET_CAP_INFO_ESS(pCurrBSS->wCapInfo)) + ) { + pCurrBSS->bSelected = TRUE; + return(pCurrBSS); + } + } + } else { + if ((pMgmt->eConfigMode == WMAC_CONFIG_AUTO) || + ((pMgmt->eConfigMode == WMAC_CONFIG_IBSS_STA) && WLAN_GET_CAP_INFO_IBSS(pCurrBSS->wCapInfo)) || + ((pMgmt->eConfigMode == WMAC_CONFIG_ESS_STA) && WLAN_GET_CAP_INFO_ESS(pCurrBSS->wCapInfo)) + ) { + pCurrBSS->bSelected = TRUE; + return(pCurrBSS); + } + } + } + } + } + } else { + // ignore BSSID + for (ii = 0; ii sBSSList[ii]); + //2007-0721-01by MikeLiu + pCurrBSS->bSelected = FALSE; + if (pCurrBSS->bActive) { + + if (pSSID != NULL) { + // matched SSID + if (!MEMEqualMemory(pSSID->abySSID, + ((PWLAN_IE_SSID)pCurrBSS->abySSID)->abySSID, + pSSID->len) || + (pSSID->len != ((PWLAN_IE_SSID)pCurrBSS->abySSID)->len)) { + // SSID not match skip this BSS + continue; + } + } + if (((pMgmt->eConfigMode == WMAC_CONFIG_IBSS_STA) && WLAN_GET_CAP_INFO_ESS(pCurrBSS->wCapInfo)) || + ((pMgmt->eConfigMode == WMAC_CONFIG_ESS_STA) && WLAN_GET_CAP_INFO_IBSS(pCurrBSS->wCapInfo)) + ) { + // Type not match skip this BSS + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"BSS type mismatch.... Config[%d] BSS[0x%04x]\n", pMgmt->eConfigMode, pCurrBSS->wCapInfo); + continue; + } + + if (ePhyType != PHY_TYPE_AUTO) { + if (((ePhyType == PHY_TYPE_11A) && (PHY_TYPE_11A != pCurrBSS->eNetworkTypeInUse)) || + ((ePhyType != PHY_TYPE_11A) && (PHY_TYPE_11A == pCurrBSS->eNetworkTypeInUse))) { + // PhyType not match skip this BSS + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Physical type mismatch.... ePhyType[%d] BSS[%d]\n", ePhyType, pCurrBSS->eNetworkTypeInUse); + continue; + } + } +/* + if (pMgmt->eAuthenMode < WMAC_AUTH_WPA) { + if (pCurrBSS->bWPAValid == TRUE) { + // WPA AP will reject connection of station without WPA enable. + continue; + } + } else if ((pMgmt->eAuthenMode == WMAC_AUTH_WPA) || + (pMgmt->eAuthenMode == WMAC_AUTH_WPAPSK)) { + if (pCurrBSS->bWPAValid == FALSE) { + // station with WPA enable can't join NonWPA AP. + continue; + } + } else if ((pMgmt->eAuthenMode == WMAC_AUTH_WPA2) || + (pMgmt->eAuthenMode == WMAC_AUTH_WPA2PSK)) { + if (pCurrBSS->bWPA2Valid == FALSE) { + // station with WPA2 enable can't join NonWPA2 AP. + continue; + } + } +*/ + if (pSelect == NULL) { + pSelect = pCurrBSS; + } else { + // compare RSSI, select signal strong one + if (pCurrBSS->uRSSI < pSelect->uRSSI) { + pSelect = pCurrBSS; + } + } + } + } + if (pSelect != NULL) { + pSelect->bSelected = TRUE; +/* + if (pDevice->bRoaming == FALSE) { + // Einsn Add @20070907 + ZERO_MEMORY(pbyDesireSSID, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1); + MEMvCopy(pbyDesireSSID,pCurrBSS->abySSID,WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1) ; + }*/ + + return(pSelect); + } + } + return(NULL); + +} + + +/*+ + * + * Routine Description: + * Clear BSS List + * + * Return Value: + * None. + * +-*/ + + +VOID +BSSvClearBSSList( + IN HANDLE hDeviceContext, + IN BOOL bKeepCurrBSSID + ) +{ + PSDevice pDevice = (PSDevice)hDeviceContext; + PSMgmtObject pMgmt = pDevice->pMgmt; + UINT ii; + + for (ii = 0; ii < MAX_BSS_NUM; ii++) { + if (bKeepCurrBSSID) { + if (pMgmt->sBSSList[ii].bActive && + IS_ETH_ADDRESS_EQUAL(pMgmt->sBSSList[ii].abyBSSID, pMgmt->abyCurrBSSID)) { + // bKeepCurrBSSID = FALSE; + continue; + } + } + + if ((pMgmt->sBSSList[ii].bActive) && (pMgmt->sBSSList[ii].uClearCount < BSS_CLEAR_COUNT)) { + pMgmt->sBSSList[ii].uClearCount ++; + continue; + } + + pMgmt->sBSSList[ii].bActive = FALSE; + memset(&pMgmt->sBSSList[ii], 0, sizeof(KnownBSS)); + } + BSSvClearAnyBSSJoinRecord(pDevice); + + return; +} + + + +/*+ + * + * Routine Description: + * search BSS list by BSSID & SSID if matched + * + * Return Value: + * TRUE if found. + * +-*/ +PKnownBSS +BSSpAddrIsInBSSList( + IN HANDLE hDeviceContext, + IN PBYTE abyBSSID, + IN PWLAN_IE_SSID pSSID + ) +{ + PSDevice pDevice = (PSDevice)hDeviceContext; + PSMgmtObject pMgmt = pDevice->pMgmt; + PKnownBSS pBSSList = NULL; + UINT ii; + + for (ii = 0; ii < MAX_BSS_NUM; ii++) { + pBSSList = &(pMgmt->sBSSList[ii]); + if (pBSSList->bActive) { + if (IS_ETH_ADDRESS_EQUAL(pBSSList->abyBSSID, abyBSSID)) { +// if (pSSID == NULL) +// return pBSSList; + if (pSSID->len == ((PWLAN_IE_SSID)pBSSList->abySSID)->len){ + if (memcmp(pSSID->abySSID, + ((PWLAN_IE_SSID)pBSSList->abySSID)->abySSID, + pSSID->len) == 0) + return pBSSList; + } + } + } + } + + return NULL; +}; + + + + +/*+ + * + * Routine Description: + * Insert a BSS set into known BSS list + * + * Return Value: + * TRUE if success. + * +-*/ + +BOOL +BSSbInsertToBSSList ( + IN HANDLE hDeviceContext, + IN PBYTE abyBSSIDAddr, + IN QWORD qwTimestamp, + IN WORD wBeaconInterval, + IN WORD wCapInfo, + IN BYTE byCurrChannel, + IN PWLAN_IE_SSID pSSID, + IN PWLAN_IE_SUPP_RATES pSuppRates, + IN PWLAN_IE_SUPP_RATES pExtSuppRates, + IN PERPObject psERP, + IN PWLAN_IE_RSN pRSN, + IN PWLAN_IE_RSN_EXT pRSNWPA, + IN PWLAN_IE_COUNTRY pIE_Country, + IN PWLAN_IE_QUIET pIE_Quiet, + IN UINT uIELength, + IN PBYTE pbyIEs, + IN HANDLE pRxPacketContext + ) +{ + + PSDevice pDevice = (PSDevice)hDeviceContext; + PSMgmtObject pMgmt = pDevice->pMgmt; + PSRxMgmtPacket pRxPacket = (PSRxMgmtPacket)pRxPacketContext; + PKnownBSS pBSSList = NULL; + UINT ii; + BOOL bParsingQuiet = FALSE; + PWLAN_IE_QUIET pQuiet = NULL; + + + + pBSSList = (PKnownBSS)&(pMgmt->sBSSList[0]); + + for (ii = 0; ii < MAX_BSS_NUM; ii++) { + pBSSList = (PKnownBSS)&(pMgmt->sBSSList[ii]); + if (!pBSSList->bActive) + break; + } + + if (ii == MAX_BSS_NUM){ + DEVICE_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Get free KnowBSS node failed.\n"); + return FALSE; + } + // save the BSS info + pBSSList->bActive = TRUE; + memcpy( pBSSList->abyBSSID, abyBSSIDAddr, WLAN_BSSID_LEN); + HIDWORD(pBSSList->qwBSSTimestamp) = cpu_to_le32(HIDWORD(qwTimestamp)); + LODWORD(pBSSList->qwBSSTimestamp) = cpu_to_le32(LODWORD(qwTimestamp)); + pBSSList->wBeaconInterval = cpu_to_le16(wBeaconInterval); + pBSSList->wCapInfo = cpu_to_le16(wCapInfo); + pBSSList->uClearCount = 0; + + if (pSSID->len > WLAN_SSID_MAXLEN) + pSSID->len = WLAN_SSID_MAXLEN; + memcpy( pBSSList->abySSID, pSSID, pSSID->len + WLAN_IEHDR_LEN); + + pBSSList->uChannel = byCurrChannel; + + if (pSuppRates->len > WLAN_RATES_MAXLEN) + pSuppRates->len = WLAN_RATES_MAXLEN; + memcpy( pBSSList->abySuppRates, pSuppRates, pSuppRates->len + WLAN_IEHDR_LEN); + + if (pExtSuppRates != NULL) { + if (pExtSuppRates->len > WLAN_RATES_MAXLEN) + pExtSuppRates->len = WLAN_RATES_MAXLEN; + memcpy(pBSSList->abyExtSuppRates, pExtSuppRates, pExtSuppRates->len + WLAN_IEHDR_LEN); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"BSSbInsertToBSSList: pExtSuppRates->len = %d\n", pExtSuppRates->len); + + } else { + memset(pBSSList->abyExtSuppRates, 0, WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1); + } + pBSSList->sERP.byERP = psERP->byERP; + pBSSList->sERP.bERPExist = psERP->bERPExist; + + // Check if BSS is 802.11a/b/g + if (pBSSList->uChannel > CB_MAX_CHANNEL_24G) { + pBSSList->eNetworkTypeInUse = PHY_TYPE_11A; + } else { + if (pBSSList->sERP.bERPExist == TRUE) { + pBSSList->eNetworkTypeInUse = PHY_TYPE_11G; + } else { + pBSSList->eNetworkTypeInUse = PHY_TYPE_11B; + } + } + + pBSSList->byRxRate = pRxPacket->byRxRate; + pBSSList->qwLocalTSF = pRxPacket->qwLocalTSF; + pBSSList->uRSSI = pRxPacket->uRSSI; + pBSSList->bySQ = pRxPacket->bySQ; + + if ((pMgmt->eCurrMode == WMAC_MODE_ESS_STA) && + (pMgmt->eCurrState == WMAC_STATE_ASSOC)) { + // assoc with BSS + if (pBSSList == pMgmt->pCurrBSS) { + bParsingQuiet = TRUE; + } + } + + WPA_ClearRSN(pBSSList); + + if (pRSNWPA != NULL) { + UINT uLen = pRSNWPA->len + 2; + + if (uLen <= (uIELength - (UINT)(ULONG_PTR)((PBYTE)pRSNWPA - pbyIEs))) { + pBSSList->wWPALen = uLen; + memcpy(pBSSList->byWPAIE, pRSNWPA, uLen); + WPA_ParseRSN(pBSSList, pRSNWPA); + } + } + + WPA2_ClearRSN(pBSSList); + + if (pRSN != NULL) { + UINT uLen = pRSN->len + 2; + if (uLen <= (uIELength - (UINT)(ULONG_PTR)((PBYTE)pRSN - pbyIEs))) { + pBSSList->wRSNLen = uLen; + memcpy(pBSSList->byRSNIE, pRSN, uLen); + WPA2vParseRSN(pBSSList, pRSN); + } + } + + if ((pMgmt->eAuthenMode == WMAC_AUTH_WPA2) || (pBSSList->bWPA2Valid == TRUE)) { + + PSKeyItem pTransmitKey = NULL; + BOOL bIs802_1x = FALSE; + + for (ii = 0; ii < pBSSList->wAKMSSAuthCount; ii ++) { + if (pBSSList->abyAKMSSAuthType[ii] == WLAN_11i_AKMSS_802_1X) { + bIs802_1x = TRUE; + break; + } + } + if ((bIs802_1x == TRUE) && (pSSID->len == ((PWLAN_IE_SSID)pMgmt->abyDesireSSID)->len) && + (MEMEqualMemory(pSSID->abySSID, ((PWLAN_IE_SSID)pMgmt->abyDesireSSID)->abySSID, pSSID->len))) { + + bAdd_PMKID_Candidate((HANDLE)pDevice, pBSSList->abyBSSID, &pBSSList->sRSNCapObj); + + if ((pDevice->bLinkPass == TRUE) && (pMgmt->eCurrState == WMAC_STATE_ASSOC)) { + if ((KeybGetTransmitKey(&(pDevice->sKey), pDevice->abyBSSID, PAIRWISE_KEY, &pTransmitKey) == TRUE) || + (KeybGetTransmitKey(&(pDevice->sKey), pDevice->abyBSSID, GROUP_KEY, &pTransmitKey) == TRUE)) { + pDevice->gsPMKIDCandidate.StatusType = Ndis802_11StatusType_PMKID_CandidateList; + pDevice->gsPMKIDCandidate.Version = 1; + + } + + } + } + } + + if (pDevice->bUpdateBBVGA) { + // Moniter if RSSI is too strong. + pBSSList->byRSSIStatCnt = 0; + RFvRSSITodBm(pDevice, (BYTE)(pRxPacket->uRSSI), &pBSSList->ldBmMAX); + pBSSList->ldBmAverage[0] = pBSSList->ldBmMAX; + for (ii = 1; ii < RSSI_STAT_COUNT; ii++) + pBSSList->ldBmAverage[ii] = 0; + } + + if ((pIE_Country != NULL) && + (pMgmt->b11hEnable == TRUE)) { + CARDvSetCountryInfo(pMgmt->pAdapter, + pBSSList->eNetworkTypeInUse, + pIE_Country); + } + + + + if ((bParsingQuiet == TRUE) && (pIE_Quiet != NULL)) { + if ((((PWLAN_IE_QUIET)pIE_Quiet)->len == 8) && + (((PWLAN_IE_QUIET)pIE_Quiet)->byQuietCount != 0)) { + // valid EID + if (pQuiet == NULL) { + pQuiet = (PWLAN_IE_QUIET)pIE_Quiet; + CARDbSetQuiet( pMgmt->pAdapter, + TRUE, + pQuiet->byQuietCount, + pQuiet->byQuietPeriod, + *((PWORD)pQuiet->abyQuietDuration), + *((PWORD)pQuiet->abyQuietOffset) + ); + } else { + pQuiet = (PWLAN_IE_QUIET)pIE_Quiet; + CARDbSetQuiet( pMgmt->pAdapter, + FALSE, + pQuiet->byQuietCount, + pQuiet->byQuietPeriod, + *((PWORD)pQuiet->abyQuietDuration), + *((PWORD)pQuiet->abyQuietOffset) + ); + } + } + } + + if ((bParsingQuiet == TRUE) && + (pQuiet != NULL)) { + CARDbStartQuiet(pMgmt->pAdapter); + } + + pBSSList->uIELength = uIELength; + if (pBSSList->uIELength > WLAN_BEACON_FR_MAXLEN) + pBSSList->uIELength = WLAN_BEACON_FR_MAXLEN; + MEMvCopy(pBSSList->abyIEs, pbyIEs, pBSSList->uIELength); + + return TRUE; +} + + +/*+ + * + * Routine Description: + * Update BSS set in known BSS list + * + * Return Value: + * TRUE if success. + * +-*/ +// TODO: input structure modify + +BOOL +BSSbUpdateToBSSList ( + IN HANDLE hDeviceContext, + IN QWORD qwTimestamp, + IN WORD wBeaconInterval, + IN WORD wCapInfo, + IN BYTE byCurrChannel, + IN BOOL bChannelHit, + IN PWLAN_IE_SSID pSSID, + IN PWLAN_IE_SUPP_RATES pSuppRates, + IN PWLAN_IE_SUPP_RATES pExtSuppRates, + IN PERPObject psERP, + IN PWLAN_IE_RSN pRSN, + IN PWLAN_IE_RSN_EXT pRSNWPA, + IN PWLAN_IE_COUNTRY pIE_Country, + IN PWLAN_IE_QUIET pIE_Quiet, + IN PKnownBSS pBSSList, + IN UINT uIELength, + IN PBYTE pbyIEs, + IN HANDLE pRxPacketContext + ) +{ + int ii; + PSDevice pDevice = (PSDevice)hDeviceContext; + PSMgmtObject pMgmt = pDevice->pMgmt; + PSRxMgmtPacket pRxPacket = (PSRxMgmtPacket)pRxPacketContext; + LONG ldBm; + BOOL bParsingQuiet = FALSE; + PWLAN_IE_QUIET pQuiet = NULL; + + + + if (pBSSList == NULL) + return FALSE; + + HIDWORD(pBSSList->qwBSSTimestamp) = cpu_to_le32(HIDWORD(qwTimestamp)); + LODWORD(pBSSList->qwBSSTimestamp) = cpu_to_le32(LODWORD(qwTimestamp)); + pBSSList->wBeaconInterval = cpu_to_le16(wBeaconInterval); + pBSSList->wCapInfo = cpu_to_le16(wCapInfo); + pBSSList->uClearCount = 0; + pBSSList->uChannel = byCurrChannel; +// DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"BSSbUpdateToBSSList: pBSSList->uChannel: %d\n", pBSSList->uChannel); + + if (pSSID->len > WLAN_SSID_MAXLEN) + pSSID->len = WLAN_SSID_MAXLEN; + + if ((pSSID->len != 0) && (pSSID->abySSID[0] != 0)) + memcpy(pBSSList->abySSID, pSSID, pSSID->len + WLAN_IEHDR_LEN); + memcpy(pBSSList->abySuppRates, pSuppRates,pSuppRates->len + WLAN_IEHDR_LEN); + + if (pExtSuppRates != NULL) { + memcpy(pBSSList->abyExtSuppRates, pExtSuppRates,pExtSuppRates->len + WLAN_IEHDR_LEN); + } else { + memset(pBSSList->abyExtSuppRates, 0, WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1); + } + pBSSList->sERP.byERP = psERP->byERP; + pBSSList->sERP.bERPExist = psERP->bERPExist; + + // Check if BSS is 802.11a/b/g + if (pBSSList->uChannel > CB_MAX_CHANNEL_24G) { + pBSSList->eNetworkTypeInUse = PHY_TYPE_11A; + } else { + if (pBSSList->sERP.bERPExist == TRUE) { + pBSSList->eNetworkTypeInUse = PHY_TYPE_11G; + } else { + pBSSList->eNetworkTypeInUse = PHY_TYPE_11B; + } + } + + pBSSList->byRxRate = pRxPacket->byRxRate; + pBSSList->qwLocalTSF = pRxPacket->qwLocalTSF; + if(bChannelHit) + pBSSList->uRSSI = pRxPacket->uRSSI; + pBSSList->bySQ = pRxPacket->bySQ; + + if ((pMgmt->eCurrMode == WMAC_MODE_ESS_STA) && + (pMgmt->eCurrState == WMAC_STATE_ASSOC)) { + // assoc with BSS + if (pBSSList == pMgmt->pCurrBSS) { + bParsingQuiet = TRUE; + } + } + + WPA_ClearRSN(pBSSList); //mike update + + if (pRSNWPA != NULL) { + UINT uLen = pRSNWPA->len + 2; + if (uLen <= (uIELength - (UINT)(ULONG_PTR)((PBYTE)pRSNWPA - pbyIEs))) { + pBSSList->wWPALen = uLen; + memcpy(pBSSList->byWPAIE, pRSNWPA, uLen); + WPA_ParseRSN(pBSSList, pRSNWPA); + } + } + + WPA2_ClearRSN(pBSSList); //mike update + + if (pRSN != NULL) { + UINT uLen = pRSN->len + 2; + if (uLen <= (uIELength - (UINT)(ULONG_PTR)((PBYTE)pRSN - pbyIEs))) { + pBSSList->wRSNLen = uLen; + memcpy(pBSSList->byRSNIE, pRSN, uLen); + WPA2vParseRSN(pBSSList, pRSN); + } + } + + if (pRxPacket->uRSSI != 0) { + RFvRSSITodBm(pDevice, (BYTE)(pRxPacket->uRSSI), &ldBm); + // Moniter if RSSI is too strong. + pBSSList->byRSSIStatCnt++; + pBSSList->byRSSIStatCnt %= RSSI_STAT_COUNT; + pBSSList->ldBmAverage[pBSSList->byRSSIStatCnt] = ldBm; + for(ii=0;iildBmAverage[ii] != 0) { + pBSSList->ldBmMAX = max(pBSSList->ldBmAverage[ii], ldBm); + } + } + } + + if ((pIE_Country != NULL) && + (pMgmt->b11hEnable == TRUE)) { + CARDvSetCountryInfo(pMgmt->pAdapter, + pBSSList->eNetworkTypeInUse, + pIE_Country); + } + + if ((bParsingQuiet == TRUE) && (pIE_Quiet != NULL)) { + if ((((PWLAN_IE_QUIET)pIE_Quiet)->len == 8) && + (((PWLAN_IE_QUIET)pIE_Quiet)->byQuietCount != 0)) { + // valid EID + if (pQuiet == NULL) { + pQuiet = (PWLAN_IE_QUIET)pIE_Quiet; + CARDbSetQuiet( pMgmt->pAdapter, + TRUE, + pQuiet->byQuietCount, + pQuiet->byQuietPeriod, + *((PWORD)pQuiet->abyQuietDuration), + *((PWORD)pQuiet->abyQuietOffset) + ); + } else { + pQuiet = (PWLAN_IE_QUIET)pIE_Quiet; + CARDbSetQuiet( pMgmt->pAdapter, + FALSE, + pQuiet->byQuietCount, + pQuiet->byQuietPeriod, + *((PWORD)pQuiet->abyQuietDuration), + *((PWORD)pQuiet->abyQuietOffset) + ); + } + } + } + + if ((bParsingQuiet == TRUE) && + (pQuiet != NULL)) { + CARDbStartQuiet(pMgmt->pAdapter); + } + + pBSSList->uIELength = uIELength; + if (pBSSList->uIELength > WLAN_BEACON_FR_MAXLEN) + pBSSList->uIELength = WLAN_BEACON_FR_MAXLEN; + memcpy(pBSSList->abyIEs, pbyIEs, pBSSList->uIELength); + + return TRUE; +} + + + + + +/*+ + * + * Routine Description: + * Search Node DB table to find the index of matched DstAddr + * + * Return Value: + * None + * +-*/ + +BOOL +BSSDBbIsSTAInNodeDB( + IN PVOID pMgmtObject, + IN PBYTE abyDstAddr, + OUT PUINT puNodeIndex + ) +{ + PSMgmtObject pMgmt = (PSMgmtObject) pMgmtObject; + UINT ii; + + // Index = 0 reserved for AP Node + for (ii = 1; ii < (MAX_NODE_NUM + 1); ii++) { + if (pMgmt->sNodeDBTable[ii].bActive) { + if (IS_ETH_ADDRESS_EQUAL(abyDstAddr, pMgmt->sNodeDBTable[ii].abyMACAddr)) { + *puNodeIndex = ii; + return TRUE; + } + } + } + + return FALSE; +}; + + + +/*+ + * + * Routine Description: + * Find an empty node and allocated; if no empty found, + * instand used of most inactive one. + * + * Return Value: + * None + * +-*/ +VOID +BSSvCreateOneNode( + IN HANDLE hDeviceContext, + OUT PUINT puNodeIndex + ) +{ + + PSDevice pDevice = (PSDevice)hDeviceContext; + PSMgmtObject pMgmt = pDevice->pMgmt; + UINT ii; + UINT BigestCount = 0; + UINT SelectIndex; + struct sk_buff *skb; + // Index = 0 reserved for AP Node (In STA mode) + // Index = 0 reserved for Broadcast/MultiCast (In AP mode) + SelectIndex = 1; + for (ii = 1; ii < (MAX_NODE_NUM + 1); ii++) { + if (pMgmt->sNodeDBTable[ii].bActive) { + if (pMgmt->sNodeDBTable[ii].uInActiveCount > BigestCount) { + BigestCount = pMgmt->sNodeDBTable[ii].uInActiveCount; + SelectIndex = ii; + } + } + else { + break; + } + } + + // if not found replace uInActiveCount is largest one. + if ( ii == (MAX_NODE_NUM + 1)) { + *puNodeIndex = SelectIndex; + DEVICE_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Replace inactive node = %d\n", SelectIndex); + // clear ps buffer + if (pMgmt->sNodeDBTable[*puNodeIndex].sTxPSQueue.next != NULL) { + while ((skb = skb_dequeue(&pMgmt->sNodeDBTable[*puNodeIndex].sTxPSQueue)) != NULL) + dev_kfree_skb(skb); + } + } + else { + *puNodeIndex = ii; + } + + memset(&pMgmt->sNodeDBTable[*puNodeIndex], 0, sizeof(KnownNodeDB)); + pMgmt->sNodeDBTable[*puNodeIndex].bActive = TRUE; + pMgmt->sNodeDBTable[*puNodeIndex].uRatePollTimeout = FALLBACK_POLL_SECOND; + // for AP mode PS queue + skb_queue_head_init(&pMgmt->sNodeDBTable[*puNodeIndex].sTxPSQueue); + pMgmt->sNodeDBTable[*puNodeIndex].byAuthSequence = 0; + pMgmt->sNodeDBTable[*puNodeIndex].wEnQueueCnt = 0; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Create node index = %d\n", ii); + return; +}; + + + +/*+ + * + * Routine Description: + * Remove Node by NodeIndex + * + * + * Return Value: + * None + * +-*/ +VOID +BSSvRemoveOneNode( + IN HANDLE hDeviceContext, + IN UINT uNodeIndex + ) +{ + + PSDevice pDevice = (PSDevice)hDeviceContext; + PSMgmtObject pMgmt = pDevice->pMgmt; + BYTE byMask[8] = {1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80}; + struct sk_buff *skb; + + + while ((skb = skb_dequeue(&pMgmt->sNodeDBTable[uNodeIndex].sTxPSQueue)) != NULL) + dev_kfree_skb(skb); + // clear context + memset(&pMgmt->sNodeDBTable[uNodeIndex], 0, sizeof(KnownNodeDB)); + // clear tx bit map + pMgmt->abyPSTxMap[pMgmt->sNodeDBTable[uNodeIndex].wAID >> 3] &= ~byMask[pMgmt->sNodeDBTable[uNodeIndex].wAID & 7]; + + return; +}; +/*+ + * + * Routine Description: + * Update AP Node content in Index 0 of KnownNodeDB + * + * + * Return Value: + * None + * +-*/ + +VOID +BSSvUpdateAPNode( + IN HANDLE hDeviceContext, + IN PWORD pwCapInfo, + IN PWLAN_IE_SUPP_RATES pSuppRates, + IN PWLAN_IE_SUPP_RATES pExtSuppRates + ) +{ + PSDevice pDevice = (PSDevice)hDeviceContext; + PSMgmtObject pMgmt = pDevice->pMgmt; + UINT uRateLen = WLAN_RATES_MAXLEN; + + memset(&pMgmt->sNodeDBTable[0], 0, sizeof(KnownNodeDB)); + + pMgmt->sNodeDBTable[0].bActive = TRUE; + if (pDevice->eCurrentPHYType == PHY_TYPE_11B) { + uRateLen = WLAN_RATES_MAXLEN_11B; + } + pMgmt->abyCurrSuppRates[1] = RATEuSetIE((PWLAN_IE_SUPP_RATES)pSuppRates, + (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates, + uRateLen); + pMgmt->abyCurrExtSuppRates[1] = RATEuSetIE((PWLAN_IE_SUPP_RATES)pExtSuppRates, + (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates, + uRateLen); + RATEvParseMaxRate((PVOID) pDevice, + (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates, + (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates, + TRUE, + &(pMgmt->sNodeDBTable[0].wMaxBasicRate), + &(pMgmt->sNodeDBTable[0].wMaxSuppRate), + &(pMgmt->sNodeDBTable[0].wSuppRate), + &(pMgmt->sNodeDBTable[0].byTopCCKBasicRate), + &(pMgmt->sNodeDBTable[0].byTopOFDMBasicRate) + ); + memcpy(pMgmt->sNodeDBTable[0].abyMACAddr, pMgmt->abyCurrBSSID, WLAN_ADDR_LEN); + pMgmt->sNodeDBTable[0].wTxDataRate = pMgmt->sNodeDBTable[0].wMaxSuppRate; + pMgmt->sNodeDBTable[0].bShortPreamble = WLAN_GET_CAP_INFO_SHORTPREAMBLE(*pwCapInfo); + pMgmt->sNodeDBTable[0].uRatePollTimeout = FALLBACK_POLL_SECOND; +#ifdef PLICE_DEBUG + printk("BSSvUpdateAPNode:MaxSuppRate is %d\n",pMgmt->sNodeDBTable[0].wMaxSuppRate); +#endif + // Auto rate fallback function initiation. + // RATEbInit(pDevice); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pMgmt->sNodeDBTable[0].wTxDataRate = %d \n", pMgmt->sNodeDBTable[0].wTxDataRate); + +}; + + + + + +/*+ + * + * Routine Description: + * Add Multicast Node content in Index 0 of KnownNodeDB + * + * + * Return Value: + * None + * +-*/ + + +VOID +BSSvAddMulticastNode( + IN HANDLE hDeviceContext + ) +{ + PSDevice pDevice = (PSDevice)hDeviceContext; + PSMgmtObject pMgmt = pDevice->pMgmt; + + if (!pDevice->bEnableHostWEP) + memset(&pMgmt->sNodeDBTable[0], 0, sizeof(KnownNodeDB)); + memset(pMgmt->sNodeDBTable[0].abyMACAddr, 0xff, WLAN_ADDR_LEN); + pMgmt->sNodeDBTable[0].bActive = TRUE; + pMgmt->sNodeDBTable[0].bPSEnable = FALSE; + skb_queue_head_init(&pMgmt->sNodeDBTable[0].sTxPSQueue); + RATEvParseMaxRate((PVOID) pDevice, + (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates, + (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates, + TRUE, + &(pMgmt->sNodeDBTable[0].wMaxBasicRate), + &(pMgmt->sNodeDBTable[0].wMaxSuppRate), + &(pMgmt->sNodeDBTable[0].wSuppRate), + &(pMgmt->sNodeDBTable[0].byTopCCKBasicRate), + &(pMgmt->sNodeDBTable[0].byTopOFDMBasicRate) + ); + pMgmt->sNodeDBTable[0].wTxDataRate = pMgmt->sNodeDBTable[0].wMaxBasicRate; +#ifdef PLICE_DEBUG + printk("BSSvAddMultiCastNode:pMgmt->sNodeDBTable[0].wTxDataRate is %d\n",pMgmt->sNodeDBTable[0].wTxDataRate); +#endif + pMgmt->sNodeDBTable[0].uRatePollTimeout = FALLBACK_POLL_SECOND; + +}; + + + + + +/*+ + * + * Routine Description: + * + * + * Second call back function to update Node DB info & AP link status + * + * + * Return Value: + * none. + * +-*/ + //2008-4-14 by chester for led issue + #ifdef FOR_LED_ON_NOTEBOOK +BOOL cc=FALSE; +UINT status; +#endif +VOID +BSSvSecondCallBack( + IN HANDLE hDeviceContext + ) +{ + PSDevice pDevice = (PSDevice)hDeviceContext; + PSMgmtObject pMgmt = pDevice->pMgmt; + UINT ii; + PWLAN_IE_SSID pItemSSID, pCurrSSID; + UINT uSleepySTACnt = 0; + UINT uNonShortSlotSTACnt = 0; + UINT uLongPreambleSTACnt = 0; +viawget_wpa_header* wpahdr; + + spin_lock_irq(&pDevice->lock); + + pDevice->uAssocCount = 0; + + pDevice->byERPFlag &= + ~(WLAN_SET_ERP_BARKER_MODE(1) | WLAN_SET_ERP_NONERP_PRESENT(1)); + //2008-4-14 by chester for led issue +#ifdef FOR_LED_ON_NOTEBOOK +MACvGPIOIn(pDevice->PortOffset, &pDevice->byGPIO); +if (((BITbIsBitOff(pDevice->byGPIO,GPIO0_DATA)&&(pDevice->bHWRadioOff == FALSE))||(BITbIsBitOn(pDevice->byGPIO,GPIO0_DATA)&&(pDevice->bHWRadioOff == TRUE)))&&(cc==FALSE)){ +cc=TRUE; +} +else if(cc==TRUE){ + +if(pDevice->bHWRadioOff == TRUE){ + if (BITbIsBitOff(pDevice->byGPIO,GPIO0_DATA)) +//||(BITbIsBitOff(pDevice->byGPIO,GPIO0_DATA) && BITbIsBitOn(pDevice->byRadioCtl, EEP_RADIOCTL_INV))) +{if(status==1) goto start; +status=1; +CARDbRadioPowerOff(pDevice); + pMgmt->sNodeDBTable[0].bActive = FALSE; + pMgmt->eCurrMode = WMAC_MODE_STANDBY; + pMgmt->eCurrState = WMAC_STATE_IDLE; + //netif_stop_queue(pDevice->dev); + pDevice->bLinkPass = FALSE; + +} + if (BITbIsBitOn(pDevice->byGPIO,GPIO0_DATA)) +//||(BITbIsBitOff(pDevice->byGPIO,GPIO0_DATA) && BITbIsBitOn(pDevice->byRadioCtl, EEP_RADIOCTL_INV))) +{if(status==2) goto start; +status=2; +CARDbRadioPowerOn(pDevice); +} } +else{ + if (BITbIsBitOn(pDevice->byGPIO,GPIO0_DATA)) +//||(BITbIsBitOff(pDevice->byGPIO,GPIO0_DATA) && BITbIsBitOn(pDevice->byRadioCtl, EEP_RADIOCTL_INV))) +{if(status==3) goto start; +status=3; +CARDbRadioPowerOff(pDevice); + pMgmt->sNodeDBTable[0].bActive = FALSE; + pMgmt->eCurrMode = WMAC_MODE_STANDBY; + pMgmt->eCurrState = WMAC_STATE_IDLE; + //netif_stop_queue(pDevice->dev); + pDevice->bLinkPass = FALSE; + +} + if (BITbIsBitOff(pDevice->byGPIO,GPIO0_DATA)) +//||(BITbIsBitOff(pDevice->byGPIO,GPIO0_DATA) && BITbIsBitOn(pDevice->byRadioCtl, EEP_RADIOCTL_INV))) +{if(status==4) goto start; +status=4; +CARDbRadioPowerOn(pDevice); +} } +} +start: +#endif + + + if (pDevice->wUseProtectCntDown > 0) { + pDevice->wUseProtectCntDown --; + } + else { + // disable protect mode + pDevice->byERPFlag &= ~(WLAN_SET_ERP_USE_PROTECTION(1)); + } + +{ + pDevice->byReAssocCount++; + if((pDevice->byReAssocCount > 10) && (pDevice->bLinkPass != TRUE)) { //10 sec timeout + printk("Re-association timeout!!!\n"); + pDevice->byReAssocCount = 0; + #ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT + // if(pDevice->bWPASuppWextEnabled == TRUE) + { + union iwreq_data wrqu; + memset(&wrqu, 0, sizeof (wrqu)); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + printk("wireless_send_event--->SIOCGIWAP(disassociated)\n"); + wireless_send_event(pDevice->dev, SIOCGIWAP, &wrqu, NULL); + } + #endif + } + else if(pDevice->bLinkPass == TRUE) + pDevice->byReAssocCount = 0; +} + +#ifdef Calcu_LinkQual + s_uCalculateLinkQual((HANDLE)pDevice); +#endif + + for (ii = 0; ii < (MAX_NODE_NUM + 1); ii++) { + + if (pMgmt->sNodeDBTable[ii].bActive) { + + // Increase in-activity counter + pMgmt->sNodeDBTable[ii].uInActiveCount++; + + if (ii > 0) { + if (pMgmt->sNodeDBTable[ii].uInActiveCount > MAX_INACTIVE_COUNT) { + BSSvRemoveOneNode(pDevice, ii); + DEVICE_PRT(MSG_LEVEL_NOTICE, KERN_INFO + "Inactive timeout [%d] sec, STA index = [%d] remove\n", MAX_INACTIVE_COUNT, ii); + continue; + } + + if (pMgmt->sNodeDBTable[ii].eNodeState >= NODE_ASSOC) { + + pDevice->uAssocCount++; + + // check if Non ERP exist + if (pMgmt->sNodeDBTable[ii].uInActiveCount < ERP_RECOVER_COUNT) { + if (!pMgmt->sNodeDBTable[ii].bShortPreamble) { + pDevice->byERPFlag |= WLAN_SET_ERP_BARKER_MODE(1); + uLongPreambleSTACnt ++; + } + if (!pMgmt->sNodeDBTable[ii].bERPExist) { + pDevice->byERPFlag |= WLAN_SET_ERP_NONERP_PRESENT(1); + pDevice->byERPFlag |= WLAN_SET_ERP_USE_PROTECTION(1); + } + if (!pMgmt->sNodeDBTable[ii].bShortSlotTime) + uNonShortSlotSTACnt++; + } + } + + // check if any STA in PS mode + if (pMgmt->sNodeDBTable[ii].bPSEnable) + uSleepySTACnt++; + + + } + + // Rate fallback check + + if (!pDevice->bFixRate) { +/* + if ((pMgmt->eCurrMode == WMAC_MODE_ESS_STA) && (ii == 0)) + RATEvTxRateFallBack(pDevice, &(pMgmt->sNodeDBTable[ii])); +*/ + if (ii > 0) { + // ii = 0 for multicast node (AP & Adhoc) + RATEvTxRateFallBack((PVOID)pDevice, &(pMgmt->sNodeDBTable[ii])); + } + else { + // ii = 0 reserved for unicast AP node (Infra STA) + if (pMgmt->eCurrMode == WMAC_MODE_ESS_STA) +#ifdef PLICE_DEBUG + printk("SecondCallback:Before:TxDataRate is %d\n",pMgmt->sNodeDBTable[0].wTxDataRate); +#endif + RATEvTxRateFallBack((PVOID)pDevice, &(pMgmt->sNodeDBTable[ii])); +#ifdef PLICE_DEBUG + printk("SecondCallback:After:TxDataRate is %d\n",pMgmt->sNodeDBTable[0].wTxDataRate); +#endif + + } + + } + + // check if pending PS queue + if (pMgmt->sNodeDBTable[ii].wEnQueueCnt != 0) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Index= %d, Queue = %d pending \n", + ii, pMgmt->sNodeDBTable[ii].wEnQueueCnt); + if ((ii >0) && (pMgmt->sNodeDBTable[ii].wEnQueueCnt > 15)) { + BSSvRemoveOneNode(pDevice, ii); + DEVICE_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Pending many queues PS STA Index = %d remove \n", ii); + continue; + } + } + } + + } + + + if ((pMgmt->eCurrMode == WMAC_MODE_ESS_AP) && (pDevice->eCurrentPHYType == PHY_TYPE_11G)) { + + // on/off protect mode + if (WLAN_GET_ERP_USE_PROTECTION(pDevice->byERPFlag)) { + if (!pDevice->bProtectMode) { + MACvEnableProtectMD(pDevice->PortOffset); + pDevice->bProtectMode = TRUE; + } + } + else { + if (pDevice->bProtectMode) { + MACvDisableProtectMD(pDevice->PortOffset); + pDevice->bProtectMode = FALSE; + } + } + // on/off short slot time + + if (uNonShortSlotSTACnt > 0) { + if (pDevice->bShortSlotTime) { + pDevice->bShortSlotTime = FALSE; + BBvSetShortSlotTime(pDevice); + vUpdateIFS((PVOID)pDevice); + } + } + else { + if (!pDevice->bShortSlotTime) { + pDevice->bShortSlotTime = TRUE; + BBvSetShortSlotTime(pDevice); + vUpdateIFS((PVOID)pDevice); + } + } + + // on/off barker long preamble mode + + if (uLongPreambleSTACnt > 0) { + if (!pDevice->bBarkerPreambleMd) { + MACvEnableBarkerPreambleMd(pDevice->PortOffset); + pDevice->bBarkerPreambleMd = TRUE; + } + } + else { + if (pDevice->bBarkerPreambleMd) { + MACvDisableBarkerPreambleMd(pDevice->PortOffset); + pDevice->bBarkerPreambleMd = FALSE; + } + } + + } + + + // Check if any STA in PS mode, enable DTIM multicast deliver + if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) { + if (uSleepySTACnt > 0) + pMgmt->sNodeDBTable[0].bPSEnable = TRUE; + else + pMgmt->sNodeDBTable[0].bPSEnable = FALSE; + } + + pItemSSID = (PWLAN_IE_SSID)pMgmt->abyDesireSSID; + pCurrSSID = (PWLAN_IE_SSID)pMgmt->abyCurrSSID; +//printk("pCurrSSID=%s\n",pCurrSSID->abySSID); + if ((pMgmt->eCurrMode == WMAC_MODE_STANDBY) || + (pMgmt->eCurrMode == WMAC_MODE_ESS_STA)) { + + if (pMgmt->sNodeDBTable[0].bActive) { // Assoc with BSS + // DEVICE_PRT(MSG_LEVEL_INFO, KERN_INFO "Callback inactive Count = [%d]\n", pMgmt->sNodeDBTable[0].uInActiveCount); + //if (pDevice->bUpdateBBVGA) { + // s_vCheckSensitivity((HANDLE) pDevice); + //} + if (pDevice->bUpdateBBVGA) { + // s_vCheckSensitivity((HANDLE) pDevice); + s_vCheckPreEDThreshold((HANDLE)pDevice); + } + if ((pMgmt->sNodeDBTable[0].uInActiveCount >= (LOST_BEACON_COUNT/2)) && + (pDevice->byBBVGACurrent != pDevice->abyBBVGA[0]) ) { + pDevice->byBBVGANew = pDevice->abyBBVGA[0]; + bScheduleCommand((HANDLE) pDevice, WLAN_CMD_CHANGE_BBSENSITIVITY, NULL); + } + + + if (pMgmt->sNodeDBTable[0].uInActiveCount >= LOST_BEACON_COUNT) { + pMgmt->sNodeDBTable[0].bActive = FALSE; + pMgmt->eCurrMode = WMAC_MODE_STANDBY; + pMgmt->eCurrState = WMAC_STATE_IDLE; + netif_stop_queue(pDevice->dev); + pDevice->bLinkPass = FALSE; + pDevice->bRoaming = TRUE; + DEVICE_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Lost AP beacon [%d] sec, disconnected !\n", pMgmt->sNodeDBTable[0].uInActiveCount); + if ((pDevice->bWPADEVUp) && (pDevice->skb != NULL)) { + wpahdr = (viawget_wpa_header *)pDevice->skb->data; + wpahdr->type = VIAWGET_DISASSOC_MSG; + wpahdr->resp_ie_len = 0; + wpahdr->req_ie_len = 0; + skb_put(pDevice->skb, sizeof(viawget_wpa_header)); + pDevice->skb->dev = pDevice->wpadev; + pDevice->skb->mac_header = pDevice->skb->data; + pDevice->skb->pkt_type = PACKET_HOST; + pDevice->skb->protocol = htons(ETH_P_802_2); + memset(pDevice->skb->cb, 0, sizeof(pDevice->skb->cb)); + netif_rx(pDevice->skb); + pDevice->skb = dev_alloc_skb((int)pDevice->rx_buf_sz); + }; + #ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT + // if(pDevice->bWPASuppWextEnabled == TRUE) + { + union iwreq_data wrqu; + memset(&wrqu, 0, sizeof (wrqu)); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + printk("wireless_send_event--->SIOCGIWAP(disassociated)\n"); + wireless_send_event(pDevice->dev, SIOCGIWAP, &wrqu, NULL); + } + #endif + } + } + else if (pItemSSID->len != 0) { + if (pDevice->uAutoReConnectTime < 10) { + pDevice->uAutoReConnectTime++; + #ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT + //network manager support need not do Roaming scan??? + if(pDevice->bWPASuppWextEnabled ==TRUE) + pDevice->uAutoReConnectTime = 0; + #endif + + } + else { + //mike use old encryption status for wpa reauthen + if(pDevice->bWPADEVUp) + pDevice->eEncryptionStatus = pDevice->eOldEncryptionStatus; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Roaming ...\n"); + BSSvClearBSSList((HANDLE)pDevice, pDevice->bLinkPass); + pMgmt->eScanType = WMAC_SCAN_ACTIVE; + bScheduleCommand((HANDLE) pDevice, WLAN_CMD_BSSID_SCAN, pMgmt->abyDesireSSID); + bScheduleCommand((HANDLE) pDevice, WLAN_CMD_SSID, pMgmt->abyDesireSSID); + pDevice->uAutoReConnectTime = 0; + } + } + } + + if (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) { + // if adhoc started which essid is NULL string, rescaning. + if ((pMgmt->eCurrState == WMAC_STATE_STARTED) && (pCurrSSID->len == 0)) { + if (pDevice->uAutoReConnectTime < 10) { + pDevice->uAutoReConnectTime++; + } + else { + DEVICE_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Adhoc re-scaning ...\n"); + pMgmt->eScanType = WMAC_SCAN_ACTIVE; + bScheduleCommand((HANDLE) pDevice, WLAN_CMD_BSSID_SCAN, NULL); + bScheduleCommand((HANDLE) pDevice, WLAN_CMD_SSID, NULL); + pDevice->uAutoReConnectTime = 0; + }; + } + if (pMgmt->eCurrState == WMAC_STATE_JOINTED) { + if (pDevice->bUpdateBBVGA) { + //s_vCheckSensitivity((HANDLE) pDevice); + s_vCheckPreEDThreshold((HANDLE)pDevice); + } + if (pMgmt->sNodeDBTable[0].uInActiveCount >=ADHOC_LOST_BEACON_COUNT) { + DEVICE_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Lost other STA beacon [%d] sec, started !\n", pMgmt->sNodeDBTable[0].uInActiveCount); + pMgmt->sNodeDBTable[0].uInActiveCount = 0; + pMgmt->eCurrState = WMAC_STATE_STARTED; + netif_stop_queue(pDevice->dev); + pDevice->bLinkPass = FALSE; + } + } + } + + spin_unlock_irq(&pDevice->lock); + + pMgmt->sTimerSecondCallback.expires = RUN_AT(HZ); + add_timer(&pMgmt->sTimerSecondCallback); + return; +} + + + + +/*+ + * + * Routine Description: + * + * + * Update Tx attemps, Tx failure counter in Node DB + * + * + * Return Value: + * none. + * +-*/ + + + +VOID +BSSvUpdateNodeTxCounter( + IN HANDLE hDeviceContext, + IN BYTE byTsr0, + IN BYTE byTsr1, + IN PBYTE pbyBuffer, + IN UINT uFIFOHeaderSize + ) +{ + PSDevice pDevice = (PSDevice)hDeviceContext; + PSMgmtObject pMgmt = pDevice->pMgmt; + UINT uNodeIndex = 0; + BYTE byTxRetry = (byTsr0 & TSR0_NCR); + PSTxBufHead pTxBufHead; + PS802_11Header pMACHeader; + WORD wRate; + WORD wFallBackRate = RATE_1M; + BYTE byFallBack; + UINT ii; +// UINT txRetryTemp; +//PLICE_DEBUG-> + //txRetryTemp = byTxRetry; + //if (txRetryTemp== 8) + //txRetryTemp -=3; +//PLICE_DEBUG <- + pTxBufHead = (PSTxBufHead) pbyBuffer; + if (pTxBufHead->wFIFOCtl & FIFOCTL_AUTO_FB_0) { + byFallBack = AUTO_FB_0; + } else if (pTxBufHead->wFIFOCtl & FIFOCTL_AUTO_FB_1) { + byFallBack = AUTO_FB_1; + } else { + byFallBack = AUTO_FB_NONE; + } + wRate = pTxBufHead->wReserved; //?wRate + //printk("BSSvUpdateNodeTxCounter:byTxRetry is %d\n",byTxRetry); + +//printk("BSSvUpdateNodeTx:wRate is %d,byFallback is %d\n",wRate,byFallBack); +//#ifdef PLICE_DEBUG + //printk("BSSvUpdateNodeTx: wRate is %d\n",wRate); +////#endif + // Only Unicast using support rates + if (pTxBufHead->wFIFOCtl & FIFOCTL_NEEDACK) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"wRate %04X, byTsr0 %02X, byTsr1 %02X\n", wRate, byTsr0, byTsr1); + if (pMgmt->eCurrMode == WMAC_MODE_ESS_STA) { + pMgmt->sNodeDBTable[0].uTxAttempts += 1; + if ((byTsr1 & TSR1_TERR) == 0) { + // transmit success, TxAttempts at least plus one + pMgmt->sNodeDBTable[0].uTxOk[MAX_RATE]++; + if ( (byFallBack == AUTO_FB_NONE) || + (wRate < RATE_18M) ) { + wFallBackRate = wRate; + } else if (byFallBack == AUTO_FB_0) { +//PLICE_DEBUG + if (byTxRetry < 5) + //if (txRetryTemp < 5) + wFallBackRate = awHWRetry0[wRate-RATE_18M][byTxRetry]; + //wFallBackRate = awHWRetry0[wRate-RATE_12M][byTxRetry]; + //wFallBackRate = awHWRetry0[wRate-RATE_18M][txRetryTemp] +1; + else + wFallBackRate = awHWRetry0[wRate-RATE_18M][4]; + //wFallBackRate = awHWRetry0[wRate-RATE_12M][4]; + } else if (byFallBack == AUTO_FB_1) { + if (byTxRetry < 5) + wFallBackRate = awHWRetry1[wRate-RATE_18M][byTxRetry]; + else + wFallBackRate = awHWRetry1[wRate-RATE_18M][4]; + } + pMgmt->sNodeDBTable[0].uTxOk[wFallBackRate]++; + } else { + pMgmt->sNodeDBTable[0].uTxFailures ++; + } + pMgmt->sNodeDBTable[0].uTxRetry += byTxRetry; + if (byTxRetry != 0) { + pMgmt->sNodeDBTable[0].uTxFail[MAX_RATE]+=byTxRetry; + if ( (byFallBack == AUTO_FB_NONE) || + (wRate < RATE_18M) ) { + pMgmt->sNodeDBTable[0].uTxFail[wRate]+=byTxRetry; + } else if (byFallBack == AUTO_FB_0) { +//PLICE_DEBUG + for(ii=0;iisNodeDBTable[0].uTxFail[wFallBackRate]++; + } + } else if (byFallBack == AUTO_FB_1) { + for(ii=0;iisNodeDBTable[0].uTxFail[wFallBackRate]++; + } + } + } + }; + + if ((pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) || + (pMgmt->eCurrMode == WMAC_MODE_ESS_AP)) { + + pMACHeader = (PS802_11Header)(pbyBuffer + uFIFOHeaderSize); + + if (BSSDBbIsSTAInNodeDB((HANDLE)pMgmt, &(pMACHeader->abyAddr1[0]), &uNodeIndex)){ + pMgmt->sNodeDBTable[uNodeIndex].uTxAttempts += 1; + if ((byTsr1 & TSR1_TERR) == 0) { + // transmit success, TxAttempts at least plus one + pMgmt->sNodeDBTable[uNodeIndex].uTxOk[MAX_RATE]++; + if ( (byFallBack == AUTO_FB_NONE) || + (wRate < RATE_18M) ) { + wFallBackRate = wRate; + } else if (byFallBack == AUTO_FB_0) { + if (byTxRetry < 5) + wFallBackRate = awHWRetry0[wRate-RATE_18M][byTxRetry]; + else + wFallBackRate = awHWRetry0[wRate-RATE_18M][4]; + } else if (byFallBack == AUTO_FB_1) { + if (byTxRetry < 5) + wFallBackRate = awHWRetry1[wRate-RATE_18M][byTxRetry]; + else + wFallBackRate = awHWRetry1[wRate-RATE_18M][4]; + } + pMgmt->sNodeDBTable[uNodeIndex].uTxOk[wFallBackRate]++; + } else { + pMgmt->sNodeDBTable[uNodeIndex].uTxFailures ++; + } + pMgmt->sNodeDBTable[uNodeIndex].uTxRetry += byTxRetry; + if (byTxRetry != 0) { + pMgmt->sNodeDBTable[uNodeIndex].uTxFail[MAX_RATE]+=byTxRetry; + if ( (byFallBack == AUTO_FB_NONE) || + (wRate < RATE_18M) ) { + pMgmt->sNodeDBTable[uNodeIndex].uTxFail[wRate]+=byTxRetry; + } else if (byFallBack == AUTO_FB_0) { + for(ii=0;iisNodeDBTable[uNodeIndex].uTxFail[wFallBackRate]++; + } + } else if (byFallBack == AUTO_FB_1) { + for(ii=0;iisNodeDBTable[uNodeIndex].uTxFail[wFallBackRate]++; + } + } + } + }; + } + }; + + return; + +} + + + + +/*+ + * + * Routine Description: + * Clear Nodes & skb in DB Table + * + * + * Parameters: + * In: + * hDeviceContext - The adapter context. + * uStartIndex - starting index + * Out: + * none + * + * Return Value: + * None. + * +-*/ + + +VOID +BSSvClearNodeDBTable( + IN HANDLE hDeviceContext, + IN UINT uStartIndex + ) + +{ + PSDevice pDevice = (PSDevice)hDeviceContext; + PSMgmtObject pMgmt = pDevice->pMgmt; + struct sk_buff *skb; + UINT ii; + + for (ii = uStartIndex; ii < (MAX_NODE_NUM + 1); ii++) { + if (pMgmt->sNodeDBTable[ii].bActive) { + // check if sTxPSQueue has been initial + if (pMgmt->sNodeDBTable[ii].sTxPSQueue.next != NULL) { + while ((skb = skb_dequeue(&pMgmt->sNodeDBTable[ii].sTxPSQueue)) != NULL){ + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "PS skb != NULL %d\n", ii); + dev_kfree_skb(skb); + } + } + memset(&pMgmt->sNodeDBTable[ii], 0, sizeof(KnownNodeDB)); + } + } + + return; +}; + + +VOID s_vCheckSensitivity( + IN HANDLE hDeviceContext + ) +{ + PSDevice pDevice = (PSDevice)hDeviceContext; + PKnownBSS pBSSList = NULL; + PSMgmtObject pMgmt = pDevice->pMgmt; + int ii; + + if ((pDevice->byLocalID <= REV_ID_VT3253_A1) && (pDevice->byRFType == RF_RFMD2959) && + (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA)) { + return; + } + + if ((pMgmt->eCurrState == WMAC_STATE_ASSOC) || + ((pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) && (pMgmt->eCurrState == WMAC_STATE_JOINTED))) { + pBSSList = BSSpAddrIsInBSSList(pDevice, pMgmt->abyCurrBSSID, (PWLAN_IE_SSID)pMgmt->abyCurrSSID); + if (pBSSList != NULL) { + // Updata BB Reg if RSSI is too strong. + LONG LocalldBmAverage = 0; + LONG uNumofdBm = 0; + for (ii = 0; ii < RSSI_STAT_COUNT; ii++) { + if (pBSSList->ldBmAverage[ii] != 0) { + uNumofdBm ++; + LocalldBmAverage += pBSSList->ldBmAverage[ii]; + } + } + if (uNumofdBm > 0) { + LocalldBmAverage = LocalldBmAverage/uNumofdBm; + for (ii=0;iildBmThreshold[ii], pDevice->abyBBVGA[ii]); + if (LocalldBmAverage < pDevice->ldBmThreshold[ii]) { + pDevice->byBBVGANew = pDevice->abyBBVGA[ii]; + break; + } + } + if (pDevice->byBBVGANew != pDevice->byBBVGACurrent) { + pDevice->uBBVGADiffCount++; + if (pDevice->uBBVGADiffCount >= BB_VGA_CHANGE_THRESHOLD) + bScheduleCommand((HANDLE) pDevice, WLAN_CMD_CHANGE_BBSENSITIVITY, NULL); + } else { + pDevice->uBBVGADiffCount = 0; + } + } + } + } +} + + +VOID +BSSvClearAnyBSSJoinRecord ( + IN HANDLE hDeviceContext + ) +{ + PSDevice pDevice = (PSDevice)hDeviceContext; + PSMgmtObject pMgmt = pDevice->pMgmt; + UINT ii; + + for (ii = 0; ii < MAX_BSS_NUM; ii++) { + pMgmt->sBSSList[ii].bSelected = FALSE; + } + return; +} + +#ifdef Calcu_LinkQual +VOID s_uCalculateLinkQual( + IN HANDLE hDeviceContext + ) +{ + PSDevice pDevice = (PSDevice)hDeviceContext; + ULONG TxOkRatio, TxCnt; + ULONG RxOkRatio,RxCnt; + ULONG RssiRatio; + long ldBm; + +TxCnt = pDevice->scStatistic.TxNoRetryOkCount + + pDevice->scStatistic.TxRetryOkCount + + pDevice->scStatistic.TxFailCount; +RxCnt = pDevice->scStatistic.RxFcsErrCnt + + pDevice->scStatistic.RxOkCnt; +TxOkRatio = (TxCnt < 6) ? 4000:((pDevice->scStatistic.TxNoRetryOkCount * 4000) / TxCnt); +RxOkRatio = (RxCnt < 6) ? 2000:((pDevice->scStatistic.RxOkCnt * 2000) / RxCnt); +//decide link quality +if(pDevice->bLinkPass !=TRUE) +{ + // printk("s_uCalculateLinkQual-->Link disconnect and Poor quality**\n"); + pDevice->scStatistic.LinkQuality = 0; + pDevice->scStatistic.SignalStren = 0; +} +else +{ + RFvRSSITodBm(pDevice, (BYTE)(pDevice->uCurrRSSI), &ldBm); + if(-ldBm < 50) { + RssiRatio = 4000; + } + else if(-ldBm > 90) { + RssiRatio = 0; + } + else { + RssiRatio = (40-(-ldBm-50))*4000/40; + } + pDevice->scStatistic.SignalStren = RssiRatio/40; + pDevice->scStatistic.LinkQuality = (RssiRatio+TxOkRatio+RxOkRatio)/100; +} + pDevice->scStatistic.RxFcsErrCnt = 0; + pDevice->scStatistic.RxOkCnt = 0; + pDevice->scStatistic.TxFailCount = 0; + pDevice->scStatistic.TxNoRetryOkCount = 0; + pDevice->scStatistic.TxRetryOkCount = 0; + return; +} +#endif + +VOID s_vCheckPreEDThreshold( + IN HANDLE hDeviceContext + ) +{ + PSDevice pDevice = (PSDevice)hDeviceContext; + PKnownBSS pBSSList = NULL; + PSMgmtObject pMgmt = &(pDevice->sMgmtObj); + + if ((pMgmt->eCurrState == WMAC_STATE_ASSOC) || + ((pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) && (pMgmt->eCurrState == WMAC_STATE_JOINTED))) { + pBSSList = BSSpAddrIsInBSSList(pDevice, pMgmt->abyCurrBSSID, (PWLAN_IE_SSID)pMgmt->abyCurrSSID); + if (pBSSList != NULL) { + pDevice->byBBPreEDRSSI = (BYTE) (~(pBSSList->ldBmAverRange) + 1); + //BBvUpdatePreEDThreshold(pDevice, FALSE); + } + } + return; +} diff --git a/drivers/staging/vt6655/bssdb.h b/drivers/staging/vt6655/bssdb.h new file mode 100644 index 000000000000..d35616d4883d --- /dev/null +++ b/drivers/staging/vt6655/bssdb.h @@ -0,0 +1,380 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * File: bssdb.h + * + * Purpose: Handles the Basic Service Set & Node Database functions + * + * Author: Lyndon Chen + * + * Date: July 16, 2002 + * + */ + +#ifndef __BSSDB_H__ +#define __BSSDB_H__ + +//#if !defined(__DEVICE_H__) +//#include "device.h" +//#endif +#include +#if !defined(__80211HDR_H__) +#include "80211hdr.h" +#endif +#if !defined(__80211MGR_H__) +#include "80211mgr.h" +#endif +#if !defined(__CARD_H__) +#include "card.h" +#endif + + + +/*--------------------- Export Definitions -------------------------*/ + +#define MAX_NODE_NUM 64 +#define MAX_BSS_NUM 42 +#define LOST_BEACON_COUNT 10 // 10 sec, XP defined +#define MAX_PS_TX_BUF 32 // sta max power saving tx buf +#define ADHOC_LOST_BEACON_COUNT 30 // 30 sec, beacon lost for adhoc only +#define MAX_INACTIVE_COUNT 300 // 300 sec, inactive STA node refresh + +#define USE_PROTECT_PERIOD 10 // 10 sec, Use protect mode check period +#define ERP_RECOVER_COUNT 30 // 30 sec, ERP support callback check +#define BSS_CLEAR_COUNT 1 + +#define RSSI_STAT_COUNT 10 +#define MAX_CHECK_RSSI_COUNT 8 + +// STA dwflags +#define WLAN_STA_AUTH BIT0 +#define WLAN_STA_ASSOC BIT1 +#define WLAN_STA_PS BIT2 +#define WLAN_STA_TIM BIT3 +// permanent; do not remove entry on expiration +#define WLAN_STA_PERM BIT4 +// If 802.1X is used, this flag is +// controlling whether STA is authorized to +// send and receive non-IEEE 802.1X frames +#define WLAN_STA_AUTHORIZED BIT5 + +#define MAX_RATE 12 + +#define MAX_WPA_IE_LEN 64 + + +/*--------------------- Export Classes ----------------------------*/ + +/*--------------------- Export Variables --------------------------*/ + + +/*--------------------- Export Types ------------------------------*/ + +// +// IEEE 802.11 Structures and definitions +// + +typedef enum _NDIS_802_11_NETWORK_TYPE +{ + Ndis802_11FH, + Ndis802_11DS, + Ndis802_11OFDM5, + Ndis802_11OFDM24, + Ndis802_11NetworkTypeMax // not a real type, defined as an upper bound +} NDIS_802_11_NETWORK_TYPE, *PNDIS_802_11_NETWORK_TYPE; + + +typedef struct tagSERPObject { + BOOL bERPExist; + BYTE byERP; +} ERPObject, DEF* PERPObject; + + +typedef struct tagSRSNCapObject { + BOOL bRSNCapExist; + WORD wRSNCap; +} SRSNCapObject, DEF* PSRSNCapObject; + +// BSS info(AP) +#pragma pack(1) +typedef struct tagKnownBSS { + // BSS info + BOOL bActive; + BYTE abyBSSID[WLAN_BSSID_LEN]; + UINT uChannel; + BYTE abySuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1]; + BYTE abyExtSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1]; + UINT uRSSI; + BYTE bySQ; + WORD wBeaconInterval; + WORD wCapInfo; + BYTE abySSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1]; + BYTE byRxRate; +// WORD wATIMWindow; + BYTE byRSSIStatCnt; + LONG ldBmMAX; + LONG ldBmAverage[RSSI_STAT_COUNT]; + LONG ldBmAverRange; + //For any BSSID selection improvment + BOOL bSelected; + + //++ WPA informations + BOOL bWPAValid; + BYTE byGKType; + BYTE abyPKType[4]; + WORD wPKCount; + BYTE abyAuthType[4]; + WORD wAuthCount; + BYTE byDefaultK_as_PK; + BYTE byReplayIdx; + //-- + + //++ WPA2 informations + BOOL bWPA2Valid; + BYTE byCSSGK; + WORD wCSSPKCount; + BYTE abyCSSPK[4]; + WORD wAKMSSAuthCount; + BYTE abyAKMSSAuthType[4]; + + //++ wpactl + BYTE byWPAIE[MAX_WPA_IE_LEN]; + BYTE byRSNIE[MAX_WPA_IE_LEN]; + WORD wWPALen; + WORD wRSNLen; + + // Clear count + UINT uClearCount; +// BYTE abyIEs[WLAN_BEACON_FR_MAXLEN]; + UINT uIELength; + QWORD qwBSSTimestamp; + QWORD qwLocalTSF; // local TSF timer + +// NDIS_802_11_NETWORK_TYPE NetworkTypeInUse; + CARD_PHY_TYPE eNetworkTypeInUse; + + ERPObject sERP; + SRSNCapObject sRSNCapObj; + BYTE abyIEs[1024]; // don't move this field !! + +}__attribute__ ((__packed__)) +KnownBSS , DEF* PKnownBSS; + +//2006-1116-01, by NomadZhao +#pragma pack() + +typedef enum tagNODE_STATE { + NODE_FREE, + NODE_AGED, + NODE_KNOWN, + NODE_AUTH, + NODE_ASSOC +} NODE_STATE, *PNODE_STATE; + + +// STA node info +typedef struct tagKnownNodeDB { + // STA info + BOOL bActive; + BYTE abyMACAddr[WLAN_ADDR_LEN]; + BYTE abyCurrSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN]; + BYTE abyCurrExtSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN]; + WORD wTxDataRate; + BOOL bShortPreamble; + BOOL bERPExist; + BOOL bShortSlotTime; + UINT uInActiveCount; + WORD wMaxBasicRate; //Get from byTopOFDMBasicRate or byTopCCKBasicRate which depends on packetTyp. + WORD wMaxSuppRate; //Records the highest supported rate getting from SuppRates IE and ExtSuppRates IE in Beacon. + WORD wSuppRate; + BYTE byTopOFDMBasicRate;//Records the highest basic rate in OFDM mode + BYTE byTopCCKBasicRate; //Records the highest basic rate in CCK mode + + // For AP mode + struct sk_buff_head sTxPSQueue; + WORD wCapInfo; + WORD wListenInterval; + WORD wAID; + NODE_STATE eNodeState; + BOOL bPSEnable; + BOOL bRxPSPoll; + BYTE byAuthSequence; + ULONG ulLastRxJiffer; + BYTE bySuppRate; + DWORD dwFlags; + WORD wEnQueueCnt; + + BOOL bOnFly; + ULONGLONG KeyRSC; + BYTE byKeyIndex; + DWORD dwKeyIndex; + BYTE byCipherSuite; + DWORD dwTSC47_16; + WORD wTSC15_0; + UINT uWepKeyLength; + BYTE abyWepKey[WLAN_WEPMAX_KEYLEN]; + // + // Auto rate fallback vars + BOOL bIsInFallback; + UINT uAverageRSSI; + UINT uRateRecoveryTimeout; + UINT uRatePollTimeout; + UINT uTxFailures; + UINT uTxAttempts; + + UINT uTxRetry; + UINT uFailureRatio; + UINT uRetryRatio; + UINT uTxOk[MAX_RATE+1]; + UINT uTxFail[MAX_RATE+1]; + UINT uTimeCount; + +} KnownNodeDB, DEF* PKnownNodeDB; + + +/*--------------------- Export Functions --------------------------*/ + + + +PKnownBSS +BSSpSearchBSSList( + IN HANDLE hDeviceContext, + IN PBYTE pbyDesireBSSID, + IN PBYTE pbyDesireSSID, + IN CARD_PHY_TYPE ePhyType + ); + +PKnownBSS +BSSpAddrIsInBSSList( + IN HANDLE hDeviceContext, + IN PBYTE abyBSSID, + IN PWLAN_IE_SSID pSSID + ); + +VOID +BSSvClearBSSList( + IN HANDLE hDeviceContext, + IN BOOL bKeepCurrBSSID + ); + +BOOL +BSSbInsertToBSSList( + IN HANDLE hDeviceContext, + IN PBYTE abyBSSIDAddr, + IN QWORD qwTimestamp, + IN WORD wBeaconInterval, + IN WORD wCapInfo, + IN BYTE byCurrChannel, + IN PWLAN_IE_SSID pSSID, + IN PWLAN_IE_SUPP_RATES pSuppRates, + IN PWLAN_IE_SUPP_RATES pExtSuppRates, + IN PERPObject psERP, + IN PWLAN_IE_RSN pRSN, + IN PWLAN_IE_RSN_EXT pRSNWPA, + IN PWLAN_IE_COUNTRY pIE_Country, + IN PWLAN_IE_QUIET pIE_Quiet, + IN UINT uIELength, + IN PBYTE pbyIEs, + IN HANDLE pRxPacketContext + ); + + +BOOL +BSSbUpdateToBSSList( + IN HANDLE hDeviceContext, + IN QWORD qwTimestamp, + IN WORD wBeaconInterval, + IN WORD wCapInfo, + IN BYTE byCurrChannel, + IN BOOL bChannelHit, + IN PWLAN_IE_SSID pSSID, + IN PWLAN_IE_SUPP_RATES pSuppRates, + IN PWLAN_IE_SUPP_RATES pExtSuppRates, + IN PERPObject psERP, + IN PWLAN_IE_RSN pRSN, + IN PWLAN_IE_RSN_EXT pRSNWPA, + IN PWLAN_IE_COUNTRY pIE_Country, + IN PWLAN_IE_QUIET pIE_Quiet, + IN PKnownBSS pBSSList, + IN UINT uIELength, + IN PBYTE pbyIEs, + IN HANDLE pRxPacketContext + ); + + +BOOL +BSSDBbIsSTAInNodeDB( + IN HANDLE hDeviceContext, + IN PBYTE abyDstAddr, + OUT PUINT puNodeIndex + ); + +VOID +BSSvCreateOneNode( + IN HANDLE hDeviceContext, + OUT PUINT puNodeIndex + ); + +VOID +BSSvUpdateAPNode( + IN HANDLE hDeviceContext, + IN PWORD pwCapInfo, + IN PWLAN_IE_SUPP_RATES pItemRates, + IN PWLAN_IE_SUPP_RATES pExtSuppRates + ); + + +VOID +BSSvSecondCallBack( + IN HANDLE hDeviceContext + ); + +VOID +BSSvUpdateNodeTxCounter( + IN HANDLE hDeviceContext, + IN BYTE byTsr0, + IN BYTE byTsr1, + IN PBYTE pbyBuffer, + IN UINT uFIFOHeaderSize + ); + +VOID +BSSvRemoveOneNode( + IN HANDLE hDeviceContext, + IN UINT uNodeIndex + ); + +VOID +BSSvAddMulticastNode( + IN HANDLE hDeviceContext + ); + + +VOID +BSSvClearNodeDBTable( + IN HANDLE hDeviceContext, + IN UINT uStartIndex + ); + +VOID +BSSvClearAnyBSSJoinRecord( + IN HANDLE hDeviceContext + ); + +#endif //__BSSDB_H__ diff --git a/drivers/staging/vt6655/card.c b/drivers/staging/vt6655/card.c new file mode 100644 index 000000000000..723f44e0bbae --- /dev/null +++ b/drivers/staging/vt6655/card.c @@ -0,0 +1,3126 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * File: card.c + * Purpose: Provide functions to setup NIC operation mode + * Functions: + * s_vSafeResetTx - Rest Tx + * CARDvSetRSPINF - Set RSPINF + * vUpdateIFS - Update slotTime,SIFS,DIFS, and EIFS + * CARDvUpdateBasicTopRate - Update BasicTopRate + * CARDbAddBasicRate - Add to BasicRateSet + * CARDbSetBasicRate - Set Basic Tx Rate + * CARDbIsOFDMinBasicRate - Check if any OFDM rate is in BasicRateSet + * CARDvSetLoopbackMode - Set Loopback mode + * CARDbSoftwareReset - Sortware reset NIC + * CARDqGetTSFOffset - Caculate TSFOffset + * CARDbGetCurrentTSF - Read Current NIC TSF counter + * CARDqGetNextTBTT - Caculate Next Beacon TSF counter + * CARDvSetFirstNextTBTT - Set NIC Beacon time + * CARDvUpdateNextTBTT - Sync. NIC Beacon time + * CARDbRadioPowerOff - Turn Off NIC Radio Power + * CARDbRadioPowerOn - Turn On NIC Radio Power + * CARDbSetWEPMode - Set NIC Wep mode + * CARDbSetTxPower - Set NIC tx power + * + * Revision History: + * 06-10-2003 Bryan YC Fan: Re-write codes to support VT3253 spec. + * 08-26-2003 Kyle Hsu: Modify the defination type of dwIoBase. + * 09-01-2003 Bryan YC Fan: Add vUpdateIFS(). + * + */ + +#if !defined(__TMACRO_H__) +#include "tmacro.h" +#endif +#if !defined(__CARD_H__) +#include "card.h" +#endif +#if !defined(__TBIT_H__) +#include "tbit.h" +#endif +#if !defined(__BASEBAND_H__) +#include "baseband.h" +#endif +#if !defined(__MAC_H__) +#include "mac.h" +#endif +#if !defined(__DESC_H__) +#include "desc.h" +#endif +#if !defined(__RF_H__) +#include "rf.h" +#endif +#if !defined(__VNTWIFI_H__) +#include "vntwifi.h" +#endif +#if !defined(__POWER_H__) +#include "power.h" +#endif +#if !defined(__KEY_H__) +#include "key.h" +#endif +#if !defined(__RC4_H__) +#include "rc4.h" +#endif +#if !defined(__COUNTRY_H__) +#include "country.h" +#endif +#if !defined(__UMEM_H__) +#include "umem.h" +#endif + + + +/*--------------------- Static Definitions -------------------------*/ + +//static int msglevel =MSG_LEVEL_DEBUG; +static int msglevel =MSG_LEVEL_INFO; + +#define C_SIFS_A 16 // micro sec. +#define C_SIFS_BG 10 + +#define C_EIFS 80 // micro sec. + + +#define C_SLOT_SHORT 9 // micro sec. +#define C_SLOT_LONG 20 + +#define C_CWMIN_A 15 // slot time +#define C_CWMIN_B 31 + +#define C_CWMAX 1023 // slot time + +#define CARD_MAX_CHANNEL_TBL 56 + +#define WAIT_BEACON_TX_DOWN_TMO 3 // Times + +typedef struct tagSChannelTblElement { + BYTE byChannelNumber; + UINT uFrequency; + BOOL bValid; + BYTE byMAP; +}SChannelTblElement, DEF* PSChannelTblElement; + + //1M, 2M, 5M, 11M, 18M, 24M, 36M, 54M +static BYTE abyDefaultSuppRatesG[] = {WLAN_EID_SUPP_RATES, 8, 0x02, 0x04, 0x0B, 0x16, 0x24, 0x30, 0x48, 0x6C}; + //6M, 9M, 12M, 48M +static BYTE abyDefaultExtSuppRatesG[] = {WLAN_EID_EXTSUPP_RATES, 4, 0x0C, 0x12, 0x18, 0x60}; + //6M, 9M, 12M, 18M, 24M, 36M, 48M, 54M +static BYTE abyDefaultSuppRatesA[] = {WLAN_EID_SUPP_RATES, 8, 0x0C, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C}; + //1M, 2M, 5M, 11M, +static BYTE abyDefaultSuppRatesB[] = {WLAN_EID_SUPP_RATES, 4, 0x02, 0x04, 0x0B, 0x16}; + + + +/*--------------------- Static Classes ----------------------------*/ + +/*--------------------- Static Variables --------------------------*/ + + +const WORD cwRXBCNTSFOff[MAX_RATE] = +{17, 17, 17, 17, 34, 23, 17, 11, 8, 5, 4, 3}; + +static SChannelTblElement sChannelTbl[CARD_MAX_CHANNEL_TBL+1] = +{ + {0, 0, FALSE, 0}, + {1, 2412, TRUE, 0}, + {2, 2417, TRUE, 0}, + {3, 2422, TRUE, 0}, + {4, 2427, TRUE, 0}, + {5, 2432, TRUE, 0}, + {6, 2437, TRUE, 0}, + {7, 2442, TRUE, 0}, + {8, 2447, TRUE, 0}, + {9, 2452, TRUE, 0}, + {10, 2457, TRUE, 0}, + {11, 2462, TRUE, 0}, + {12, 2467, TRUE, 0}, + {13, 2472, TRUE, 0}, + {14, 2484, TRUE, 0}, + {183, 4915, TRUE, 0}, + {184, 4920, TRUE, 0}, + {185, 4925, TRUE, 0}, + {187, 4935, TRUE, 0}, + {188, 4940, TRUE, 0}, + {189, 4945, TRUE, 0}, + {192, 4960, TRUE, 0}, + {196, 4980, TRUE, 0}, + {7, 5035, TRUE, 0}, + {8, 5040, TRUE, 0}, + {9, 5045, TRUE, 0}, + {11, 5055, TRUE, 0}, + {12, 5060, TRUE, 0}, + {16, 5080, TRUE, 0}, + {34, 5170, TRUE, 0}, + {36, 5180, TRUE, 0}, + {38, 5190, TRUE, 0}, + {40, 5200, TRUE, 0}, + {42, 5210, TRUE, 0}, + {44, 5220, TRUE, 0}, + {46, 5230, TRUE, 0}, + {48, 5240, TRUE, 0}, + {52, 5260, TRUE, 0}, + {56, 5280, TRUE, 0}, + {60, 5300, TRUE, 0}, + {64, 5320, TRUE, 0}, + {100, 5500, TRUE, 0}, + {104, 5520, TRUE, 0}, + {108, 5540, TRUE, 0}, + {112, 5560, TRUE, 0}, + {116, 5580, TRUE, 0}, + {120, 5600, TRUE, 0}, + {124, 5620, TRUE, 0}, + {128, 5640, TRUE, 0}, + {132, 5660, TRUE, 0}, + {136, 5680, TRUE, 0}, + {140, 5700, TRUE, 0}, + {149, 5745, TRUE, 0}, + {153, 5765, TRUE, 0}, + {157, 5785, TRUE, 0}, + {161, 5805, TRUE, 0}, + {165, 5825, TRUE, 0} +}; + + +/************************************************************************ + * The Radar regulation rules for each country + ************************************************************************/ +SCountryTable ChannelRuleTab[CCODE_MAX+1] = +{ +/************************************************************************ + * This table is based on Athero driver rules + ************************************************************************/ +/* Country Available channels, ended with 0 */ +/* 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 */ +{CCODE_FCC, {'U','S'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1} + , { 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 17, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} }, +{CCODE_TELEC, {'J','P'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 23, 0, 0, 23, 0, 23, 23, 0, 23, 0, 0, 23, 23, 23, 0, 23, 0, 23, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_ETSI, {'E','U'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0} + , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} }, +{CCODE_RESV3, {' ',' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_RESV4, {' ',' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_RESV5, {' ',' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_RESV6, {' ',' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_RESV7, {' ',' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_RESV8, {' ',' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_RESV9, {' ',' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_RESVa, {' ',' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_RESVb, {' ',' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_RESVc, {' ',' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_RESVd, {' ',' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_RESVe, {' ',' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_ALLBAND, {' ',' '}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1} + , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_ALBANIA, {'A','L'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_ALGERIA, {'D','Z'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_ARGENTINA, {'A','R'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0} + , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 0} }, +{CCODE_ARMENIA, {'A','M'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 18, 0, 18, 0, 18, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_AUSTRALIA, {'A','U'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1} + , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 23, 0, 23, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} }, +{CCODE_AUSTRIA, {'A','T'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 15, 0, 15, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_AZERBAIJAN, {'A','Z'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 18, 0, 18, 0, 18, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_BAHRAIN, {'B','H'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_BELARUS, {'B','Y'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_BELGIUM, {'B','E'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 18, 0, 18, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_BELIZE, {'B','Z'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1} + , { 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} }, +{CCODE_BOLIVIA, {'B','O'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1} + , { 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} }, +{CCODE_BRAZIL, {'B','R'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_BRUNEI_DARUSSALAM, {'B','N'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1} + , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} }, +{CCODE_BULGARIA, {'B','G'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0} + , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 23, 0, 23, 0, 23, 23, 23, 0, 0, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 0, 0, 0, 0, 0} }, +{CCODE_CANADA, {'C','A'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1} + , { 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 17, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} }, +{CCODE_CHILE, {'C','L'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1} + , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 17, 17} }, +{CCODE_CHINA, {'C','N'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1} + , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} }, +{CCODE_COLOMBIA, {'C','O'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1} + , { 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 17, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} }, +{CCODE_COSTA_RICA, {'C','R'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_CROATIA, {'H','R'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_CYPRUS, {'C','Y'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0} + , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} }, +{CCODE_CZECH, {'C','Z'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_DENMARK, {'D','K'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0} + , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} }, +{CCODE_DOMINICAN_REPUBLIC, {'D','O'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1} + , { 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 17, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} }, +{CCODE_ECUADOR, {'E','C'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_EGYPT, {'E','G'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_EL_SALVADOR, {'S','V'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_ESTONIA, {'E','E'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0} + , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} }, +{CCODE_FINLAND, {'F','I'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0} + , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} }, +{CCODE_FRANCE, {'F','R'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_GERMANY, {'D','E'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0} + , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} }, +{CCODE_GREECE, {'G','R'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_GEORGIA, {'G','E'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 18, 0, 18, 0, 18, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_GUATEMALA, {'G','T'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1} + , { 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 17, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} }, +{CCODE_HONDURAS, {'H','N'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_HONG_KONG, {'H','K'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1} + , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 23, 0, 23, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} }, +{CCODE_HUNGARY, {'H','U'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 18, 0, 18, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_ICELAND, {'I','S'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0} + , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} }, +{CCODE_INDIA, {'I','N'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_INDONESIA, {'I','D'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_IRAN, {'I','R'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1} + , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} }, +{CCODE_IRELAND, {'I','E'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0} + , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} }, +{CCODE_ITALY, {'I','T'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0} + , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} }, +{CCODE_ISRAEL, {'I','L'}, { 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_JAPAN, {'J','P'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 23, 0, 23, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_JORDAN, {'J','O'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_KAZAKHSTAN, {'K','Z'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_KUWAIT, {'K','W'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_LATVIA, {'L','V'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_LEBANON, {'L','B'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_LEICHTENSTEIN, {'L','I'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 18, 0, 18, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_LITHUANIA, {'L','T'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0} + , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} }, +{CCODE_LUXEMBURG, {'L','U'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0} + , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} }, +{CCODE_MACAU, {'M','O'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1} + , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 23, 0, 23, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} }, +{CCODE_MACEDONIA, {'M','K'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_MALTA, {'M','T'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0} + , { 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 16, 0, 16, 0, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 16, 0} }, +{CCODE_MALAYSIA, {'M','Y'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_MEXICO, {'M','X'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1} + , { 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 17, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} }, +{CCODE_MONACO, {'M','C'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 18, 0, 18, 0, 18, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_MOROCCO, {'M','A'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_NETHERLANDS, {'N','L'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0} + , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} }, +{CCODE_NEW_ZEALAND, {'N','Z'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1} + , { 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 23, 0, 23, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} }, +{CCODE_NORTH_KOREA, {'K','P'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0} + , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 23, 23, 23, 0} }, +{CCODE_NORWAY, {'N','O'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0} + , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} }, +{CCODE_OMAN, {'O','M'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_PAKISTAN, {'P','K'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_PANAMA, {'P','A'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1} + , { 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 17, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} }, +{CCODE_PERU, {'P','E'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_PHILIPPINES, {'P','H'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1} + , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 17, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} }, +{CCODE_POLAND, {'P','L'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0} + , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} }, +{CCODE_PORTUGAL, {'P','T'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0} + , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} }, +{CCODE_PUERTO_RICO, {'P','R'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1} + , { 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 17, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} }, +{CCODE_QATAR, {'Q','A'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_ROMANIA, {'R','O'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_RUSSIA, {'R','U'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_SAUDI_ARABIA, {'S','A'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_SINGAPORE, {'S','G'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1} + , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 20, 20} }, +{CCODE_SLOVAKIA, {'S','K'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0} + , { 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 16, 0, 16, 0, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 16, 0} }, +{CCODE_SLOVENIA, {'S','I'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0} + , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} }, +{CCODE_SOUTH_AFRICA, {'Z','A'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0} + , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} }, +{CCODE_SOUTH_KOREA, {'K','R'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0} + , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 23, 23, 23, 0} }, +{CCODE_SPAIN, {'E','S'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0} + , { 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 16, 0, 16, 0, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 16, 0} }, +{CCODE_SWEDEN, {'S','E'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0} + , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} }, +{CCODE_SWITZERLAND, {'C','H'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 18, 0, 18, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_SYRIA, {'S','Y'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_TAIWAN, {'T','W'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0} + , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 0} }, +{CCODE_THAILAND, {'T','H'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0} + , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 23, 23, 23, 0} }, +{CCODE_TRINIDAD_TOBAGO, {'T','T'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 18, 0, 18, 0, 18, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_TUNISIA, {'T','N'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_TURKEY, {'T','R'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_UK, {'G','B'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0} + , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} }, +{CCODE_UKRAINE, {'U','A'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_UNITED_ARAB_EMIRATES, {'A','E'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_UNITED_STATES, {'U','S'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1} + , { 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 17, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} }, +{CCODE_URUGUAY, {'U','Y'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0} + , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 23, 23, 23, 0} }, +{CCODE_UZBEKISTAN, {'U','Z'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_VENEZUELA, {'V','E'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0} + , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 23, 23, 23, 0} }, +{CCODE_VIETNAM, {'V','N'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_YEMEN, {'Y','E'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_ZIMBABWE, {'Z','W'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_JAPAN_W52_W53, {'J','J'}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, +{CCODE_MAX, {'U','N'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1} + , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} } +/* 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 */ +}; + + +/*--------------------- Static Functions --------------------------*/ + +static +VOID +s_vCaculateOFDMRParameter( + IN BYTE byRate, + IN CARD_PHY_TYPE ePHYType, + OUT PBYTE pbyTxRate, + OUT PBYTE pbyRsvTime + ); + + +/*--------------------- Export Variables --------------------------*/ + +/*--------------------- Export Functions --------------------------*/ + + +/*--------------------- Export function -------------------------*/ +/************************************************************************ + * Country Channel Valid + * Input: CountryCode, ChannelNum + * ChanneIndex is defined as VT3253 MAC channel: + * 1 = 2.4G channel 1 + * 2 = 2.4G channel 2 + * ... + * 14 = 2.4G channel 14 + * 15 = 4.9G channel 183 + * 16 = 4.9G channel 184 + * ..... + * Output: TRUE if the specified 5GHz band is allowed to be used. + False otherwise. +// 4.9G => Ch 183, 184, 185, 187, 188, 189, 192, 196 (Value:15 ~ 22) + +// 5G => Ch 7, 8, 9, 11, 12, 16, 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64, +// 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165 (Value 23 ~ 56) + ************************************************************************/ +//2008-8-4 by chester +BOOL +ChannelValid(UINT CountryCode, UINT ChannelIndex) +{ + BOOL bValid; + + bValid = FALSE; + /* + * If Channel Index is invalid, return invalid + */ + if ((ChannelIndex > CB_MAX_CHANNEL) || + (ChannelIndex == 0)) + { + bValid = FALSE; + goto exit; + } + + bValid = sChannelTbl[ChannelIndex].bValid; + +exit: + return (bValid); + +} /* end ChannelValid */ + + +/* + * Description: Caculate TxRate and RsvTime fields for RSPINF in OFDM mode. + * + * Parameters: + * In: + * wRate - Tx Rate + * byPktType - Tx Packet type + * Out: + * pbyTxRate - pointer to RSPINF TxRate field + * pbyRsvTime - pointer to RSPINF RsvTime field + * + * Return Value: none + * + */ +static +VOID +s_vCaculateOFDMRParameter ( + IN BYTE byRate, + IN CARD_PHY_TYPE ePHYType, + OUT PBYTE pbyTxRate, + OUT PBYTE pbyRsvTime + ) +{ + switch (byRate) { + case RATE_6M : + if (ePHYType == PHY_TYPE_11A) {//5GHZ + *pbyTxRate = 0x9B; + *pbyRsvTime = 44; + } + else { + *pbyTxRate = 0x8B; + *pbyRsvTime = 50; + } + break; + + case RATE_9M : + if (ePHYType == PHY_TYPE_11A) {//5GHZ + *pbyTxRate = 0x9F; + *pbyRsvTime = 36; + } + else { + *pbyTxRate = 0x8F; + *pbyRsvTime = 42; + } + break; + + case RATE_12M : + if (ePHYType == PHY_TYPE_11A) {//5GHZ + *pbyTxRate = 0x9A; + *pbyRsvTime = 32; + } + else { + *pbyTxRate = 0x8A; + *pbyRsvTime = 38; + } + break; + + case RATE_18M : + if (ePHYType == PHY_TYPE_11A) {//5GHZ + *pbyTxRate = 0x9E; + *pbyRsvTime = 28; + } + else { + *pbyTxRate = 0x8E; + *pbyRsvTime = 34; + } + break; + + case RATE_36M : + if (ePHYType == PHY_TYPE_11A) {//5GHZ + *pbyTxRate = 0x9D; + *pbyRsvTime = 24; + } + else { + *pbyTxRate = 0x8D; + *pbyRsvTime = 30; + } + break; + + case RATE_48M : + if (ePHYType == PHY_TYPE_11A) {//5GHZ + *pbyTxRate = 0x98; + *pbyRsvTime = 24; + } + else { + *pbyTxRate = 0x88; + *pbyRsvTime = 30; + } + break; + + case RATE_54M : + if (ePHYType == PHY_TYPE_11A) {//5GHZ + *pbyTxRate = 0x9C; + *pbyRsvTime = 24; + } + else { + *pbyTxRate = 0x8C; + *pbyRsvTime = 30; + } + break; + + case RATE_24M : + default : + if (ePHYType == PHY_TYPE_11A) {//5GHZ + *pbyTxRate = 0x99; + *pbyRsvTime = 28; + } + else { + *pbyTxRate = 0x89; + *pbyRsvTime = 34; + } + break; + } +} + + + +/* + * Description: Set RSPINF + * + * Parameters: + * In: + * pDevice - The adapter to be set + * Out: + * none + * + * Return Value: None. + * + */ +static +VOID +s_vSetRSPINF (PSDevice pDevice, CARD_PHY_TYPE ePHYType, PVOID pvSupportRateIEs, PVOID pvExtSupportRateIEs) +{ + BYTE byServ = 0, bySignal = 0; // For CCK + WORD wLen = 0; + BYTE byTxRate = 0, byRsvTime = 0; // For OFDM + + //Set to Page1 + MACvSelectPage1(pDevice->PortOffset); + + //RSPINF_b_1 + BBvCaculateParameter(pDevice, + 14, + VNTWIFIbyGetACKTxRate(RATE_1M, pvSupportRateIEs, pvExtSupportRateIEs), + PK_TYPE_11B, + &wLen, + &byServ, + &bySignal + ); + + VNSvOutPortD(pDevice->PortOffset + MAC_REG_RSPINF_B_1, MAKEDWORD(wLen,MAKEWORD(bySignal,byServ))); + ///RSPINF_b_2 + BBvCaculateParameter(pDevice, + 14, + VNTWIFIbyGetACKTxRate(RATE_2M, pvSupportRateIEs, pvExtSupportRateIEs), + PK_TYPE_11B, + &wLen, + &byServ, + &bySignal + ); + + VNSvOutPortD(pDevice->PortOffset + MAC_REG_RSPINF_B_2, MAKEDWORD(wLen,MAKEWORD(bySignal,byServ))); + //RSPINF_b_5 + BBvCaculateParameter(pDevice, + 14, + VNTWIFIbyGetACKTxRate(RATE_5M, pvSupportRateIEs, pvExtSupportRateIEs), + PK_TYPE_11B, + &wLen, + &byServ, + &bySignal + ); + + VNSvOutPortD(pDevice->PortOffset + MAC_REG_RSPINF_B_5, MAKEDWORD(wLen,MAKEWORD(bySignal,byServ))); + //RSPINF_b_11 + BBvCaculateParameter(pDevice, + 14, + VNTWIFIbyGetACKTxRate(RATE_11M, pvSupportRateIEs, pvExtSupportRateIEs), + PK_TYPE_11B, + &wLen, + &byServ, + &bySignal + ); + + VNSvOutPortD(pDevice->PortOffset + MAC_REG_RSPINF_B_11, MAKEDWORD(wLen,MAKEWORD(bySignal,byServ))); + //RSPINF_a_6 + s_vCaculateOFDMRParameter(RATE_6M, + ePHYType, + &byTxRate, + &byRsvTime); + VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_6, MAKEWORD(byTxRate,byRsvTime)); + //RSPINF_a_9 + s_vCaculateOFDMRParameter(RATE_9M, + ePHYType, + &byTxRate, + &byRsvTime); + VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_9, MAKEWORD(byTxRate,byRsvTime)); + //RSPINF_a_12 + s_vCaculateOFDMRParameter(RATE_12M, + ePHYType, + &byTxRate, + &byRsvTime); + VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_12, MAKEWORD(byTxRate,byRsvTime)); + //RSPINF_a_18 + s_vCaculateOFDMRParameter(RATE_18M, + ePHYType, + &byTxRate, + &byRsvTime); + VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_18, MAKEWORD(byTxRate,byRsvTime)); + //RSPINF_a_24 + s_vCaculateOFDMRParameter(RATE_24M, + ePHYType, + &byTxRate, + &byRsvTime); + VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_24, MAKEWORD(byTxRate,byRsvTime)); + //RSPINF_a_36 + s_vCaculateOFDMRParameter( + VNTWIFIbyGetACKTxRate(RATE_36M, pvSupportRateIEs, pvExtSupportRateIEs), + ePHYType, + &byTxRate, + &byRsvTime); + VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_36, MAKEWORD(byTxRate,byRsvTime)); + //RSPINF_a_48 + s_vCaculateOFDMRParameter( + VNTWIFIbyGetACKTxRate(RATE_48M, pvSupportRateIEs, pvExtSupportRateIEs), + ePHYType, + &byTxRate, + &byRsvTime); + VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_48, MAKEWORD(byTxRate,byRsvTime)); + //RSPINF_a_54 + s_vCaculateOFDMRParameter( + VNTWIFIbyGetACKTxRate(RATE_54M, pvSupportRateIEs, pvExtSupportRateIEs), + ePHYType, + &byTxRate, + &byRsvTime); + VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_54, MAKEWORD(byTxRate,byRsvTime)); + //RSPINF_a_72 + VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_72, MAKEWORD(byTxRate,byRsvTime)); + //Set to Page0 + MACvSelectPage0(pDevice->PortOffset); +} + + + + +/*--------------------- Export Variables --------------------------*/ + +/*--------------------- Export Functions --------------------------*/ +BYTE CARDbyGetChannelMapping (PVOID pDeviceHandler, BYTE byChannelNumber, CARD_PHY_TYPE ePhyType) +{ + UINT ii; + + if ((ePhyType == PHY_TYPE_11B) || (ePhyType == PHY_TYPE_11G)) { + return (byChannelNumber); + } + + for(ii = (CB_MAX_CHANNEL_24G + 1); ii <= CB_MAX_CHANNEL; ) { + if (sChannelTbl[ii].byChannelNumber == byChannelNumber) { + return ((BYTE) ii); + } + ii++; + } + return (0); +} + + +BYTE CARDbyGetChannelNumber (PVOID pDeviceHandler, BYTE byChannelIndex) +{ +// PSDevice pDevice = (PSDevice) pDeviceHandler; + return(sChannelTbl[byChannelIndex].byChannelNumber); +} + +/* + * Description: Set NIC media channel + * + * Parameters: + * In: + * pDeviceHandler - The adapter to be set + * uConnectionChannel - Channel to be set + * Out: + * none + * + * Return Value: TRUE if succeeded; FALSE if failed. + * + */ +BOOL CARDbSetChannel (PVOID pDeviceHandler, UINT uConnectionChannel) +{ + PSDevice pDevice = (PSDevice) pDeviceHandler; + BOOL bResult = TRUE; + + + if (pDevice->byCurrentCh == uConnectionChannel) { + return bResult; + } + + if (sChannelTbl[uConnectionChannel].bValid == FALSE) { + return (FALSE); + } + + if ((uConnectionChannel > CB_MAX_CHANNEL_24G) && + (pDevice->eCurrentPHYType != PHY_TYPE_11A)) { + CARDbSetPhyParameter(pDevice, PHY_TYPE_11A, 0, 0, NULL, NULL); + } else if ((uConnectionChannel <= CB_MAX_CHANNEL_24G) && + (pDevice->eCurrentPHYType == PHY_TYPE_11A)) { + CARDbSetPhyParameter(pDevice, PHY_TYPE_11G, 0, 0, NULL, NULL); + } + // clear NAV + MACvRegBitsOn(pDevice->PortOffset, MAC_REG_MACCR, MACCR_CLRNAV); + + //{{ RobertYu: 20041202 + //// TX_PE will reserve 3 us for MAX2829 A mode only, it is for better TX throughput + + if ( pDevice->byRFType == RF_AIROHA7230 ) + { + RFbAL7230SelectChannelPostProcess(pDevice->PortOffset, pDevice->byCurrentCh, (BYTE)uConnectionChannel); + } + //}} RobertYu + + + pDevice->byCurrentCh = (BYTE)uConnectionChannel; + bResult &= RFbSelectChannel(pDevice->PortOffset, pDevice->byRFType, (BYTE)uConnectionChannel); + + // Init Synthesizer Table + if (pDevice->bEnablePSMode == TRUE) + RFvWriteWakeProgSyn(pDevice->PortOffset, pDevice->byRFType, uConnectionChannel); + + + //DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"CARDbSetMediaChannel: %d\n", (BYTE)uConnectionChannel); + BBvSoftwareReset(pDevice->PortOffset); + + if (pDevice->byLocalID > REV_ID_VT3253_B1) { + // set HW default power register + MACvSelectPage1(pDevice->PortOffset); + RFbSetPower(pDevice, RATE_1M, pDevice->byCurrentCh); + VNSvOutPortB(pDevice->PortOffset + MAC_REG_PWRCCK, pDevice->byCurPwr); + RFbSetPower(pDevice, RATE_6M, pDevice->byCurrentCh); + VNSvOutPortB(pDevice->PortOffset + MAC_REG_PWROFDM, pDevice->byCurPwr); + MACvSelectPage0(pDevice->PortOffset); + } + + if (pDevice->eCurrentPHYType == PHY_TYPE_11B) { +#ifdef PLICE_DEBUG + //printk("Func:CARDbSetChannel:call RFbSetPower:11B\n"); +#endif + RFbSetPower(pDevice, RATE_1M, pDevice->byCurrentCh); + } else { +#ifdef PLICE_DEBUG + //printk("Func:CARDbSetChannel:call RFbSetPower\n"); +#endif + RFbSetPower(pDevice, RATE_6M, pDevice->byCurrentCh); + } + + return(bResult); +} + + + +/* + * Description: Card Send packet function + * + * Parameters: + * In: + * pDeviceHandler - The adapter to be set + * pPacket - Packet buffer pointer + * ePktType - Packet type + * uLength - Packet length + * Out: + * none + * + * Return Value: TRUE if succeeded; FALSE if failed. + * + */ +/* +BOOL CARDbSendPacket (PVOID pDeviceHandler, PVOID pPacket, CARD_PKT_TYPE ePktType, UINT uLength) +{ + PSDevice pDevice = (PSDevice) pDeviceHandler; + if (ePktType == PKT_TYPE_802_11_MNG) { + return TXbTD0Send(pDevice, pPacket, uLength); + } else if (ePktType == PKT_TYPE_802_11_BCN) { + return TXbBeaconSend(pDevice, pPacket, uLength); + } if (ePktType == PKT_TYPE_802_11_DATA) { + return TXbTD1Send(pDevice, pPacket, uLength); + } + + return (TRUE); +} +*/ + + +/* + * Description: Get Card short preamble option value + * + * Parameters: + * In: + * pDevice - The adapter to be set + * Out: + * none + * + * Return Value: TRUE if short preamble; otherwise FALSE + * + */ +BOOL CARDbIsShortPreamble (PVOID pDeviceHandler) +{ + PSDevice pDevice = (PSDevice) pDeviceHandler; + if (pDevice->byPreambleType == 0) { + return(FALSE); + } + return(TRUE); +} + +/* + * Description: Get Card short slot time option value + * + * Parameters: + * In: + * pDevice - The adapter to be set + * Out: + * none + * + * Return Value: TRUE if short slot time; otherwise FALSE + * + */ +BOOL CARDbIsShorSlotTime (PVOID pDeviceHandler) +{ + PSDevice pDevice = (PSDevice) pDeviceHandler; + return(pDevice->bShortSlotTime); +} + + +/* + * Description: Update IFS + * + * Parameters: + * In: + * pDevice - The adapter to be set + * Out: + * none + * + * Return Value: None. + * + */ +BOOL CARDbSetPhyParameter (PVOID pDeviceHandler, CARD_PHY_TYPE ePHYType, WORD wCapInfo, BYTE byERPField, PVOID pvSupportRateIEs, PVOID pvExtSupportRateIEs) +{ + PSDevice pDevice = (PSDevice) pDeviceHandler; + BYTE byCWMaxMin = 0; + BYTE bySlot = 0; + BYTE bySIFS = 0; + BYTE byDIFS = 0; + BYTE byData; +// PWLAN_IE_SUPP_RATES pRates = NULL; + PWLAN_IE_SUPP_RATES pSupportRates = (PWLAN_IE_SUPP_RATES) pvSupportRateIEs; + PWLAN_IE_SUPP_RATES pExtSupportRates = (PWLAN_IE_SUPP_RATES) pvExtSupportRateIEs; + + + //Set SIFS, DIFS, EIFS, SlotTime, CwMin + if (ePHYType == PHY_TYPE_11A) { + if (pSupportRates == NULL) { + pSupportRates = (PWLAN_IE_SUPP_RATES) abyDefaultSuppRatesA; + } + if (pDevice->byRFType == RF_AIROHA7230) { + // AL7230 use single PAPE and connect to PAPE_2.4G + MACvSetBBType(pDevice->PortOffset, BB_TYPE_11G); + pDevice->abyBBVGA[0] = 0x20; + pDevice->abyBBVGA[2] = 0x10; + pDevice->abyBBVGA[3] = 0x10; + BBbReadEmbeded(pDevice->PortOffset, 0xE7, &byData); + if (byData == 0x1C) { + BBbWriteEmbeded(pDevice->PortOffset, 0xE7, pDevice->abyBBVGA[0]); + } + } else if (pDevice->byRFType == RF_UW2452) { + MACvSetBBType(pDevice->PortOffset, BB_TYPE_11A); + pDevice->abyBBVGA[0] = 0x18; + BBbReadEmbeded(pDevice->PortOffset, 0xE7, &byData); + if (byData == 0x14) { + BBbWriteEmbeded(pDevice->PortOffset, 0xE7, pDevice->abyBBVGA[0]); + BBbWriteEmbeded(pDevice->PortOffset, 0xE1, 0x57); + } + } else { + MACvSetBBType(pDevice->PortOffset, BB_TYPE_11A); + } + BBbWriteEmbeded(pDevice->PortOffset, 0x88, 0x03); + bySlot = C_SLOT_SHORT; + bySIFS = C_SIFS_A; + byDIFS = C_SIFS_A + 2*C_SLOT_SHORT; + byCWMaxMin = 0xA4; + } else if (ePHYType == PHY_TYPE_11B) { + if (pSupportRates == NULL) { + pSupportRates = (PWLAN_IE_SUPP_RATES) abyDefaultSuppRatesB; + } + MACvSetBBType(pDevice->PortOffset, BB_TYPE_11B); + if (pDevice->byRFType == RF_AIROHA7230) { + pDevice->abyBBVGA[0] = 0x1C; + pDevice->abyBBVGA[2] = 0x00; + pDevice->abyBBVGA[3] = 0x00; + BBbReadEmbeded(pDevice->PortOffset, 0xE7, &byData); + if (byData == 0x20) { + BBbWriteEmbeded(pDevice->PortOffset, 0xE7, pDevice->abyBBVGA[0]); + } + } else if (pDevice->byRFType == RF_UW2452) { + pDevice->abyBBVGA[0] = 0x14; + BBbReadEmbeded(pDevice->PortOffset, 0xE7, &byData); + if (byData == 0x18) { + BBbWriteEmbeded(pDevice->PortOffset, 0xE7, pDevice->abyBBVGA[0]); + BBbWriteEmbeded(pDevice->PortOffset, 0xE1, 0xD3); + } + } + BBbWriteEmbeded(pDevice->PortOffset, 0x88, 0x02); + bySlot = C_SLOT_LONG; + bySIFS = C_SIFS_BG; + byDIFS = C_SIFS_BG + 2*C_SLOT_LONG; + byCWMaxMin = 0xA5; + } else {// PK_TYPE_11GA & PK_TYPE_11GB + if (pSupportRates == NULL) { + pSupportRates = (PWLAN_IE_SUPP_RATES) abyDefaultSuppRatesG; + pExtSupportRates = (PWLAN_IE_SUPP_RATES) abyDefaultExtSuppRatesG; + } + MACvSetBBType(pDevice->PortOffset, BB_TYPE_11G); + if (pDevice->byRFType == RF_AIROHA7230) { + pDevice->abyBBVGA[0] = 0x1C; + pDevice->abyBBVGA[2] = 0x00; + pDevice->abyBBVGA[3] = 0x00; + BBbReadEmbeded(pDevice->PortOffset, 0xE7, &byData); + if (byData == 0x20) { + BBbWriteEmbeded(pDevice->PortOffset, 0xE7, pDevice->abyBBVGA[0]); + } + } else if (pDevice->byRFType == RF_UW2452) { + pDevice->abyBBVGA[0] = 0x14; + BBbReadEmbeded(pDevice->PortOffset, 0xE7, &byData); + if (byData == 0x18) { + BBbWriteEmbeded(pDevice->PortOffset, 0xE7, pDevice->abyBBVGA[0]); + BBbWriteEmbeded(pDevice->PortOffset, 0xE1, 0xD3); + } + } + BBbWriteEmbeded(pDevice->PortOffset, 0x88, 0x08); + bySIFS = C_SIFS_BG; + if(VNTWIFIbIsShortSlotTime(wCapInfo)) { + bySlot = C_SLOT_SHORT; + byDIFS = C_SIFS_BG + 2*C_SLOT_SHORT; + } else { + bySlot = C_SLOT_LONG; + byDIFS = C_SIFS_BG + 2*C_SLOT_LONG; + } + if (VNTWIFIbyGetMaxSupportRate(pSupportRates, pExtSupportRates) > RATE_11M) { + byCWMaxMin = 0xA4; + } else { + byCWMaxMin = 0xA5; + } + if (pDevice->bProtectMode != VNTWIFIbIsProtectMode(byERPField)) { + pDevice->bProtectMode = VNTWIFIbIsProtectMode(byERPField); + if (pDevice->bProtectMode) { + MACvEnableProtectMD(pDevice->PortOffset); + } else { + MACvDisableProtectMD(pDevice->PortOffset); + } + } + if (pDevice->bBarkerPreambleMd != VNTWIFIbIsBarkerMode(byERPField)) { + pDevice->bBarkerPreambleMd = VNTWIFIbIsBarkerMode(byERPField); + if (pDevice->bBarkerPreambleMd) { + MACvEnableBarkerPreambleMd(pDevice->PortOffset); + } else { + MACvDisableBarkerPreambleMd(pDevice->PortOffset); + } + } + } + + if (pDevice->byRFType == RF_RFMD2959) { + // bcs TX_PE will reserve 3 us + // hardware's processing time here is 2 us. + bySIFS -= 3; + byDIFS -= 3; + //{{ RobertYu: 20041202 + //// TX_PE will reserve 3 us for MAX2829 A mode only, it is for better TX throughput + //// MAC will need 2 us to process, so the SIFS, DIFS can be shorter by 2 us. + } + + if (pDevice->bySIFS != bySIFS) { + pDevice->bySIFS = bySIFS; + VNSvOutPortB(pDevice->PortOffset + MAC_REG_SIFS, pDevice->bySIFS); + } + if (pDevice->byDIFS != byDIFS) { + pDevice->byDIFS = byDIFS; + VNSvOutPortB(pDevice->PortOffset + MAC_REG_DIFS, pDevice->byDIFS); + } + if (pDevice->byEIFS != C_EIFS) { + pDevice->byEIFS = C_EIFS; + VNSvOutPortB(pDevice->PortOffset + MAC_REG_EIFS, pDevice->byEIFS); + } + if (pDevice->bySlot != bySlot) { + pDevice->bySlot = bySlot; + VNSvOutPortB(pDevice->PortOffset + MAC_REG_SLOT, pDevice->bySlot); + if (pDevice->bySlot == C_SLOT_SHORT) { + pDevice->bShortSlotTime = TRUE; + } else { + pDevice->bShortSlotTime = FALSE; + } + BBvSetShortSlotTime(pDevice); + } + if (pDevice->byCWMaxMin != byCWMaxMin) { + pDevice->byCWMaxMin = byCWMaxMin; + VNSvOutPortB(pDevice->PortOffset + MAC_REG_CWMAXMIN0, pDevice->byCWMaxMin); + } + if (VNTWIFIbIsShortPreamble(wCapInfo)) { + pDevice->byPreambleType = pDevice->byShortPreamble; + } else { + pDevice->byPreambleType = 0; + } + s_vSetRSPINF(pDevice, ePHYType, pSupportRates, pExtSupportRates); + pDevice->eCurrentPHYType = ePHYType; + // set for NDIS OID_802_11SUPPORTED_RATES + return (TRUE); +} + +/* + * Description: Sync. TSF counter to BSS + * Get TSF offset and write to HW + * + * Parameters: + * In: + * pDevice - The adapter to be sync. + * byRxRate - data rate of receive beacon + * qwBSSTimestamp - Rx BCN's TSF + * qwLocalTSF - Local TSF + * Out: + * none + * + * Return Value: none + * + */ +BOOL CARDbUpdateTSF (PVOID pDeviceHandler, BYTE byRxRate, QWORD qwBSSTimestamp, QWORD qwLocalTSF) +{ + PSDevice pDevice = (PSDevice) pDeviceHandler; + QWORD qwTSFOffset; + + HIDWORD(qwTSFOffset) = 0; + LODWORD(qwTSFOffset) = 0; + + if ((HIDWORD(qwBSSTimestamp) != HIDWORD(qwLocalTSF)) || + (LODWORD(qwBSSTimestamp) != LODWORD(qwLocalTSF))) { + qwTSFOffset = CARDqGetTSFOffset(byRxRate, qwBSSTimestamp, qwLocalTSF); + // adjust TSF + // HW's TSF add TSF Offset reg + VNSvOutPortD(pDevice->PortOffset + MAC_REG_TSFOFST, LODWORD(qwTSFOffset)); + VNSvOutPortD(pDevice->PortOffset + MAC_REG_TSFOFST + 4, HIDWORD(qwTSFOffset)); + MACvRegBitsOn(pDevice->PortOffset, MAC_REG_TFTCTL, TFTCTL_TSFSYNCEN); + } + return(TRUE); +} + + +/* + * Description: Set NIC TSF counter for first Beacon time + * Get NEXTTBTT from adjusted TSF and Beacon Interval + * + * Parameters: + * In: + * pDevice - The adapter to be set. + * wBeaconInterval - Beacon Interval + * Out: + * none + * + * Return Value: TRUE if succeed; otherwise FALSE + * + */ +BOOL CARDbSetBeaconPeriod (PVOID pDeviceHandler, WORD wBeaconInterval) +{ + PSDevice pDevice = (PSDevice) pDeviceHandler; + UINT uBeaconInterval = 0; + UINT uLowNextTBTT = 0; + UINT uHighRemain = 0; + UINT uLowRemain = 0; + QWORD qwNextTBTT; + + HIDWORD(qwNextTBTT) = 0; + LODWORD(qwNextTBTT) = 0; + CARDbGetCurrentTSF(pDevice->PortOffset, &qwNextTBTT); //Get Local TSF counter + uBeaconInterval = wBeaconInterval * 1024; + // Next TBTT = ((local_current_TSF / beacon_interval) + 1 ) * beacon_interval + uLowNextTBTT = (LODWORD(qwNextTBTT) >> 10) << 10; + uLowRemain = (uLowNextTBTT) % uBeaconInterval; + // high dword (mod) bcn + uHighRemain = (((0xffffffff % uBeaconInterval) + 1) * HIDWORD(qwNextTBTT)) + % uBeaconInterval; + uLowRemain = (uHighRemain + uLowRemain) % uBeaconInterval; + uLowRemain = uBeaconInterval - uLowRemain; + + // check if carry when add one beacon interval + if ((~uLowNextTBTT) < uLowRemain) { + HIDWORD(qwNextTBTT) ++ ; + } + LODWORD(qwNextTBTT) = uLowNextTBTT + uLowRemain; + + // set HW beacon interval + VNSvOutPortW(pDevice->PortOffset + MAC_REG_BI, wBeaconInterval); + pDevice->wBeaconInterval = wBeaconInterval; + // Set NextTBTT + VNSvOutPortD(pDevice->PortOffset + MAC_REG_NEXTTBTT, LODWORD(qwNextTBTT)); + VNSvOutPortD(pDevice->PortOffset + MAC_REG_NEXTTBTT + 4, HIDWORD(qwNextTBTT)); + MACvRegBitsOn(pDevice->PortOffset, MAC_REG_TFTCTL, TFTCTL_TBTTSYNCEN); + + return(TRUE); +} + + + +/* + * Description: Card Stop Hardware Tx + * + * Parameters: + * In: + * pDeviceHandler - The adapter to be set + * ePktType - Packet type to stop + * Out: + * none + * + * Return Value: TRUE if all data packet complete; otherwise FALSE. + * + */ +BOOL CARDbStopTxPacket (PVOID pDeviceHandler, CARD_PKT_TYPE ePktType) +{ + PSDevice pDevice = (PSDevice) pDeviceHandler; + + + if (ePktType == PKT_TYPE_802_11_ALL) { + pDevice->bStopBeacon = TRUE; + pDevice->bStopTx0Pkt = TRUE; + pDevice->bStopDataPkt = TRUE; + } else if (ePktType == PKT_TYPE_802_11_BCN) { + pDevice->bStopBeacon = TRUE; + } else if (ePktType == PKT_TYPE_802_11_MNG) { + pDevice->bStopTx0Pkt = TRUE; + } else if (ePktType == PKT_TYPE_802_11_DATA) { + pDevice->bStopDataPkt = TRUE; + } + + if (pDevice->bStopBeacon == TRUE) { + if (pDevice->bIsBeaconBufReadySet == TRUE) { + if (pDevice->cbBeaconBufReadySetCnt < WAIT_BEACON_TX_DOWN_TMO) { + pDevice->cbBeaconBufReadySetCnt ++; + return(FALSE); + } + } + pDevice->bIsBeaconBufReadySet = FALSE; + pDevice->cbBeaconBufReadySetCnt = 0; + MACvRegBitsOff(pDevice->PortOffset, MAC_REG_TCR, TCR_AUTOBCNTX); + } + // wait all TD0 complete + if (pDevice->bStopTx0Pkt == TRUE) { + if (pDevice->iTDUsed[TYPE_TXDMA0] != 0){ + return(FALSE); + } + } + // wait all Data TD complete + if (pDevice->bStopDataPkt == TRUE) { + if (pDevice->iTDUsed[TYPE_AC0DMA] != 0){ + return(FALSE); + } + } + + return(TRUE); +} + + +/* + * Description: Card Start Hardware Tx + * + * Parameters: + * In: + * pDeviceHandler - The adapter to be set + * ePktType - Packet type to start + * Out: + * none + * + * Return Value: TRUE if success; FALSE if failed. + * + */ +BOOL CARDbStartTxPacket (PVOID pDeviceHandler, CARD_PKT_TYPE ePktType) +{ + PSDevice pDevice = (PSDevice) pDeviceHandler; + + + if (ePktType == PKT_TYPE_802_11_ALL) { + pDevice->bStopBeacon = FALSE; + pDevice->bStopTx0Pkt = FALSE; + pDevice->bStopDataPkt = FALSE; + } else if (ePktType == PKT_TYPE_802_11_BCN) { + pDevice->bStopBeacon = FALSE; + } else if (ePktType == PKT_TYPE_802_11_MNG) { + pDevice->bStopTx0Pkt = FALSE; + } else if (ePktType == PKT_TYPE_802_11_DATA) { + pDevice->bStopDataPkt = FALSE; + } + + if ((pDevice->bStopBeacon == FALSE) && + (pDevice->bBeaconBufReady == TRUE) && + (pDevice->eOPMode == OP_MODE_ADHOC)) { + MACvRegBitsOn(pDevice->PortOffset, MAC_REG_TCR, TCR_AUTOBCNTX); + } + + return(TRUE); +} + + + +/* + * Description: Card Set BSSID value + * + * Parameters: + * In: + * pDeviceHandler - The adapter to be set + * pbyBSSID - pointer to BSSID field + * bAdhoc - flag to indicate IBSS + * Out: + * none + * + * Return Value: TRUE if success; FALSE if failed. + * + */ +BOOL CARDbSetBSSID(PVOID pDeviceHandler, PBYTE pbyBSSID, CARD_OP_MODE eOPMode) +{ + PSDevice pDevice = (PSDevice) pDeviceHandler; + + MACvWriteBSSIDAddress(pDevice->PortOffset, pbyBSSID); + MEMvCopy(pDevice->abyBSSID, pbyBSSID, WLAN_BSSID_LEN); + if (eOPMode == OP_MODE_ADHOC) { + MACvRegBitsOn(pDevice->PortOffset, MAC_REG_HOSTCR, HOSTCR_ADHOC); + } else { + MACvRegBitsOff(pDevice->PortOffset, MAC_REG_HOSTCR, HOSTCR_ADHOC); + } + if (eOPMode == OP_MODE_AP) { + MACvRegBitsOn(pDevice->PortOffset, MAC_REG_HOSTCR, HOSTCR_AP); + } else { + MACvRegBitsOff(pDevice->PortOffset, MAC_REG_HOSTCR, HOSTCR_AP); + } + if (eOPMode == OP_MODE_UNKNOWN) { + MACvRegBitsOff(pDevice->PortOffset, MAC_REG_RCR, RCR_BSSID); + pDevice->bBSSIDFilter = FALSE; + pDevice->byRxMode &= ~RCR_BSSID; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "wcmd: rx_mode = %x\n", pDevice->byRxMode ); + } else { + if (IS_NULL_ADDRESS(pDevice->abyBSSID) == FALSE) { + MACvRegBitsOn(pDevice->PortOffset, MAC_REG_RCR, RCR_BSSID); + pDevice->bBSSIDFilter = TRUE; + pDevice->byRxMode |= RCR_BSSID; + } + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "wmgr: rx_mode = %x\n", pDevice->byRxMode ); + } + // Adopt BSS state in Adapter Device Object + pDevice->eOPMode = eOPMode; + return(TRUE); +} + + +/* + * Description: Card indicate status + * + * Parameters: + * In: + * pDeviceHandler - The adapter to be set + * eStatus - Status + * Out: + * none + * + * Return Value: TRUE if success; FALSE if failed. + * + */ + + + + +/* + * Description: Save Assoc info. contain in assoc. response frame + * + * Parameters: + * In: + * pDevice - The adapter to be set + * wCapabilityInfo - Capability information + * wStatus - Status code + * wAID - Assoc. ID + * uLen - Length of IEs + * pbyIEs - pointer to IEs + * Out: + * none + * + * Return Value: TRUE if succeed; otherwise FALSE + * + */ +BOOL CARDbSetTxDataRate( + PVOID pDeviceHandler, + WORD wDataRate + ) +{ + PSDevice pDevice = (PSDevice) pDeviceHandler; + + pDevice->wCurrentRate = wDataRate; + return(TRUE); +} + +/*+ + * + * Routine Description: + * Consider to power down when no more packets to tx or rx. + * + * Parameters: + * In: + * pDevice - The adapter to be set + * Out: + * none + * + * Return Value: TRUE if power down success; otherwise FALSE + * +-*/ +BOOL +CARDbPowerDown( + PVOID pDeviceHandler + ) +{ + PSDevice pDevice = (PSDevice)pDeviceHandler; + UINT uIdx; + + // check if already in Doze mode + if (MACbIsRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_PS)) + return TRUE; + + // Froce PSEN on + MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_PSEN); + + // check if all TD are empty, + + for (uIdx = 0; uIdx < TYPE_MAXTD; uIdx ++) { + if (pDevice->iTDUsed[uIdx] != 0) + return FALSE; + } + + MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_GO2DOZE); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Go to Doze ZZZZZZZZZZZZZZZ\n"); + return TRUE; +} + +/* + * Description: Turn off Radio power + * + * Parameters: + * In: + * pDevice - The adapter to be turned off + * Out: + * none + * + * Return Value: TRUE if success; otherwise FALSE + * + */ +BOOL CARDbRadioPowerOff (PVOID pDeviceHandler) +{ + PSDevice pDevice = (PSDevice) pDeviceHandler; + BOOL bResult = TRUE; + + if (pDevice->bRadioOff == TRUE) + return TRUE; + + + switch (pDevice->byRFType) { + + case RF_RFMD2959: + MACvWordRegBitsOff(pDevice->PortOffset, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_TXPEINV); + MACvWordRegBitsOn(pDevice->PortOffset, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_SWPE1); + break; + + case RF_AIROHA: + case RF_AL2230S: + case RF_AIROHA7230: //RobertYu:20050104 + MACvWordRegBitsOff(pDevice->PortOffset, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_SWPE2); + MACvWordRegBitsOff(pDevice->PortOffset, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_SWPE3); + break; + + } + + MACvRegBitsOff(pDevice->PortOffset, MAC_REG_HOSTCR, HOSTCR_RXON); + + BBvSetDeepSleep(pDevice->PortOffset, pDevice->byLocalID); + + pDevice->bRadioOff = TRUE; + //2007-0409-03, by chester +printk("chester power off\n"); +MACvRegBitsOn(pDevice->PortOffset, MAC_REG_GPIOCTL0, LED_ACTSET); //LED issue + return bResult; +} + + +/* + * Description: Turn on Radio power + * + * Parameters: + * In: + * pDevice - The adapter to be turned on + * Out: + * none + * + * Return Value: TRUE if success; otherwise FALSE + * + */ +BOOL CARDbRadioPowerOn (PVOID pDeviceHandler) +{ + PSDevice pDevice = (PSDevice) pDeviceHandler; + BOOL bResult = TRUE; +printk("chester power on\n"); + if (pDevice->bRadioControlOff == TRUE){ +if (pDevice->bHWRadioOff == TRUE) printk("chester bHWRadioOff\n"); +if (pDevice->bRadioControlOff == TRUE) printk("chester bRadioControlOff\n"); + return FALSE;} + + if (pDevice->bRadioOff == FALSE) + { +printk("chester pbRadioOff\n"); +return TRUE;} + + BBvExitDeepSleep(pDevice->PortOffset, pDevice->byLocalID); + + MACvRegBitsOn(pDevice->PortOffset, MAC_REG_HOSTCR, HOSTCR_RXON); + + switch (pDevice->byRFType) { + + case RF_RFMD2959: + MACvWordRegBitsOn(pDevice->PortOffset, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_TXPEINV); + MACvWordRegBitsOff(pDevice->PortOffset, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_SWPE1); + break; + + case RF_AIROHA: + case RF_AL2230S: + case RF_AIROHA7230: //RobertYu:20050104 + MACvWordRegBitsOn(pDevice->PortOffset, MAC_REG_SOFTPWRCTL, (SOFTPWRCTL_SWPE2 | + SOFTPWRCTL_SWPE3)); + break; + + } + + pDevice->bRadioOff = FALSE; +// 2007-0409-03, by chester +printk("chester power on\n"); +MACvRegBitsOff(pDevice->PortOffset, MAC_REG_GPIOCTL0, LED_ACTSET); //LED issue + return bResult; +} + + + +BOOL CARDbRemoveKey (PVOID pDeviceHandler, PBYTE pbyBSSID) +{ + PSDevice pDevice = (PSDevice) pDeviceHandler; + + KeybRemoveAllKey(&(pDevice->sKey), pbyBSSID, pDevice->PortOffset); + return (TRUE); +} + + +/* + * + * Description: + * Add BSSID in PMKID Candidate list. + * + * Parameters: + * In: + * hDeviceContext - device structure point + * pbyBSSID - BSSID address for adding + * wRSNCap - BSS's RSN capability + * Out: + * none + * + * Return Value: none. + * +-*/ +BOOL +CARDbAdd_PMKID_Candidate ( + IN PVOID pDeviceHandler, + IN PBYTE pbyBSSID, + IN BOOL bRSNCapExist, + IN WORD wRSNCap + ) +{ + PSDevice pDevice = (PSDevice) pDeviceHandler; + PPMKID_CANDIDATE pCandidateList; + UINT ii = 0; + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"bAdd_PMKID_Candidate START: (%d)\n", (int)pDevice->gsPMKIDCandidate.NumCandidates); + + if (pDevice->gsPMKIDCandidate.NumCandidates >= MAX_PMKIDLIST) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"vFlush_PMKID_Candidate: 3\n"); + ZERO_MEMORY(&pDevice->gsPMKIDCandidate, sizeof(SPMKIDCandidateEvent)); + } + + for (ii = 0; ii < 6; ii++) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"%02X ", *(pbyBSSID + ii)); + } + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"\n"); + + + // Update Old Candidate + for (ii = 0; ii < pDevice->gsPMKIDCandidate.NumCandidates; ii++) { + pCandidateList = &pDevice->gsPMKIDCandidate.CandidateList[ii]; + if (MEMEqualMemory(pCandidateList->BSSID, pbyBSSID, U_ETHER_ADDR_LEN)) { + if ((bRSNCapExist == TRUE) && (wRSNCap & BIT0)) { + pCandidateList->Flags |= NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED; + } else { + pCandidateList->Flags &= ~(NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED); + } + return TRUE; + } + } + + // New Candidate + pCandidateList = &pDevice->gsPMKIDCandidate.CandidateList[pDevice->gsPMKIDCandidate.NumCandidates]; + if ((bRSNCapExist == TRUE) && (wRSNCap & BIT0)) { + pCandidateList->Flags |= NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED; + } else { + pCandidateList->Flags &= ~(NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED); + } + MEMvCopy(pCandidateList->BSSID, pbyBSSID, U_ETHER_ADDR_LEN); + pDevice->gsPMKIDCandidate.NumCandidates++; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"NumCandidates:%d\n", (int)pDevice->gsPMKIDCandidate.NumCandidates); + return TRUE; +} + +PVOID +CARDpGetCurrentAddress ( + IN PVOID pDeviceHandler + ) +{ + PSDevice pDevice = (PSDevice) pDeviceHandler; + + return (pDevice->abyCurrentNetAddr); +} + + + +VOID CARDvInitChannelTable (PVOID pDeviceHandler) +{ + PSDevice pDevice = (PSDevice) pDeviceHandler; + BOOL bMultiBand = FALSE; + UINT ii; + + for(ii=1;ii<=CARD_MAX_CHANNEL_TBL;ii++) { + sChannelTbl[ii].bValid = FALSE; + } + + switch (pDevice->byRFType) { + case RF_RFMD2959 : + case RF_AIROHA : + case RF_AL2230S: + case RF_UW2451 : + case RF_VT3226 : + // printk("chester-false\n"); + bMultiBand = FALSE; + break; + case RF_AIROHA7230 : + case RF_UW2452 : + case RF_NOTHING : + default : + bMultiBand = TRUE; + break; + } + + if ((pDevice->dwDiagRefCount != 0) || + (pDevice->b11hEnable == TRUE)) { + if (bMultiBand == TRUE) { + for(ii=0;iiabyRegPwr[ii+1] = pDevice->abyOFDMDefaultPwr[ii+1]; + pDevice->abyLocalPwr[ii+1] = pDevice->abyOFDMDefaultPwr[ii+1]; + } + for(ii=0;iiabyRegPwr[ii+1] = pDevice->abyCCKDefaultPwr[ii+1]; + pDevice->abyLocalPwr[ii+1] = pDevice->abyCCKDefaultPwr[ii+1]; + } + } else { + for(ii=0;ii by chester + if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[ii] != 0) { + sChannelTbl[ii+1].bValid = TRUE; + pDevice->abyRegPwr[ii+1] = pDevice->abyCCKDefaultPwr[ii+1]; + pDevice->abyLocalPwr[ii+1] = pDevice->abyCCKDefaultPwr[ii+1]; + } + } + } + } else if (pDevice->byZoneType <= CCODE_MAX) { + if (bMultiBand == TRUE) { + for(ii=0;iibyZoneType].bChannelIdxList[ii] != 0) { + sChannelTbl[ii+1].bValid = TRUE; + pDevice->abyRegPwr[ii+1] = ChannelRuleTab[pDevice->byZoneType].byPower[ii]; + pDevice->abyLocalPwr[ii+1] = ChannelRuleTab[pDevice->byZoneType].byPower[ii]; + } + } + } else { + for(ii=0;iibyZoneType].bChannelIdxList[ii] != 0) { + sChannelTbl[ii+1].bValid = TRUE; + pDevice->abyRegPwr[ii+1] = ChannelRuleTab[pDevice->byZoneType].byPower[ii]; + pDevice->abyLocalPwr[ii+1] = ChannelRuleTab[pDevice->byZoneType].byPower[ii]; + } + } + } + } + DEVICE_PRT(MSG_LEVEL_NOTICE, KERN_INFO"Zone=[%d][%c][%c]!!\n",pDevice->byZoneType,ChannelRuleTab[pDevice->byZoneType].chCountryCode[0],ChannelRuleTab[pDevice->byZoneType].chCountryCode[1]); + for(ii=0;iiabyRegPwr[ii+1] == 0) { + pDevice->abyRegPwr[ii+1] = pDevice->abyOFDMDefaultPwr[ii+1]; + } + if (pDevice->abyLocalPwr[ii+1] == 0) { + pDevice->abyLocalPwr[ii+1] = pDevice->abyOFDMDefaultPwr[ii+1]; + } + } +} + + + +/* + * + * Description: + * Start Spectrum Measure defined in 802.11h + * + * Parameters: + * In: + * hDeviceContext - device structure point + * Out: + * none + * + * Return Value: none. + * +-*/ +BOOL +CARDbStartMeasure ( + IN PVOID pDeviceHandler, + IN PVOID pvMeasureEIDs, + IN UINT uNumOfMeasureEIDs + ) +{ + PSDevice pDevice = (PSDevice) pDeviceHandler; + PWLAN_IE_MEASURE_REQ pEID = (PWLAN_IE_MEASURE_REQ) pvMeasureEIDs; + QWORD qwCurrTSF; + QWORD qwStartTSF; + BOOL bExpired = TRUE; + WORD wDuration = 0; + + if ((pEID == NULL) || + (uNumOfMeasureEIDs == 0)) { + return (TRUE); + } + CARDbGetCurrentTSF(pDevice->PortOffset, &qwCurrTSF); + if (pDevice->bMeasureInProgress == TRUE) { + pDevice->bMeasureInProgress = FALSE; + VNSvOutPortB(pDevice->PortOffset + MAC_REG_RCR, pDevice->byOrgRCR); + MACvSelectPage1(pDevice->PortOffset); + VNSvOutPortD(pDevice->PortOffset + MAC_REG_MAR0, pDevice->dwOrgMAR0); + VNSvOutPortD(pDevice->PortOffset + MAC_REG_MAR4, pDevice->dwOrgMAR4); + // clear measure control + MACvRegBitsOff(pDevice->PortOffset, MAC_REG_MSRCTL, MSRCTL_EN); + MACvSelectPage0(pDevice->PortOffset); + CARDbSetChannel(pDevice, pDevice->byOrgChannel); + MACvSelectPage1(pDevice->PortOffset); + MACvRegBitsOn(pDevice->PortOffset, MAC_REG_MSRCTL+1, MSRCTL1_TXPAUSE); + MACvSelectPage0(pDevice->PortOffset); + } + pDevice->uNumOfMeasureEIDs = uNumOfMeasureEIDs; + + do { + pDevice->pCurrMeasureEID = pEID; + pEID++; + pDevice->uNumOfMeasureEIDs--; + + if (pDevice->byLocalID > REV_ID_VT3253_B1) { + HIDWORD(qwStartTSF) = HIDWORD(*((PQWORD) (pDevice->pCurrMeasureEID->sReq.abyStartTime))); + LODWORD(qwStartTSF) = LODWORD(*((PQWORD) (pDevice->pCurrMeasureEID->sReq.abyStartTime))); + wDuration = *((PWORD) (pDevice->pCurrMeasureEID->sReq.abyDuration)); + wDuration += 1; // 1 TU for channel switching + + if ((LODWORD(qwStartTSF) == 0) && (HIDWORD(qwStartTSF) == 0)) { + // start imediately by setting start TSF == current TSF + 2 TU + LODWORD(qwStartTSF) = LODWORD(qwCurrTSF) + 2048; + HIDWORD(qwStartTSF) = HIDWORD(qwCurrTSF); + if (LODWORD(qwCurrTSF) > LODWORD(qwStartTSF)) { + HIDWORD(qwStartTSF)++; + } + bExpired = FALSE; + break; + } else { + // start at setting start TSF - 1TU(for channel switching) + if (LODWORD(qwStartTSF) < 1024) { + HIDWORD(qwStartTSF)--; + } + LODWORD(qwStartTSF) -= 1024; + } + + if ((HIDWORD(qwCurrTSF) < HIDWORD(qwStartTSF)) || + ((HIDWORD(qwCurrTSF) == HIDWORD(qwStartTSF)) && + (LODWORD(qwCurrTSF) < LODWORD(qwStartTSF))) + ) { + bExpired = FALSE; + break; + } + VNTWIFIbMeasureReport( pDevice->pMgmt, + FALSE, + pDevice->pCurrMeasureEID, + MEASURE_MODE_LATE, + pDevice->byBasicMap, + pDevice->byCCAFraction, + pDevice->abyRPIs + ); + } else { + // hardware do not support measure + VNTWIFIbMeasureReport( pDevice->pMgmt, + FALSE, + pDevice->pCurrMeasureEID, + MEASURE_MODE_INCAPABLE, + pDevice->byBasicMap, + pDevice->byCCAFraction, + pDevice->abyRPIs + ); + } + } while (pDevice->uNumOfMeasureEIDs != 0); + + if (bExpired == FALSE) { + MACvSelectPage1(pDevice->PortOffset); + VNSvOutPortD(pDevice->PortOffset + MAC_REG_MSRSTART, LODWORD(qwStartTSF)); + VNSvOutPortD(pDevice->PortOffset + MAC_REG_MSRSTART + 4, HIDWORD(qwStartTSF)); + VNSvOutPortW(pDevice->PortOffset + MAC_REG_MSRDURATION, wDuration); + MACvRegBitsOn(pDevice->PortOffset, MAC_REG_MSRCTL, MSRCTL_EN); + MACvSelectPage0(pDevice->PortOffset); + } else { + // all measure start time expired we should complete action + VNTWIFIbMeasureReport( pDevice->pMgmt, + TRUE, + NULL, + 0, + pDevice->byBasicMap, + pDevice->byCCAFraction, + pDevice->abyRPIs + ); + } + return (TRUE); +} + + +/* + * + * Description: + * Do Channel Switch defined in 802.11h + * + * Parameters: + * In: + * hDeviceContext - device structure point + * Out: + * none + * + * Return Value: none. + * +-*/ +BOOL +CARDbChannelSwitch ( + IN PVOID pDeviceHandler, + IN BYTE byMode, + IN BYTE byNewChannel, + IN BYTE byCount + ) +{ + PSDevice pDevice = (PSDevice) pDeviceHandler; + BOOL bResult = TRUE; + + if (byCount == 0) { + bResult = CARDbSetChannel(pDevice, byNewChannel); + VNTWIFIbChannelSwitch(pDevice->pMgmt, byNewChannel); + MACvSelectPage1(pDevice->PortOffset); + MACvRegBitsOn(pDevice->PortOffset, MAC_REG_MSRCTL+1, MSRCTL1_TXPAUSE); + MACvSelectPage0(pDevice->PortOffset); + return(bResult); + } + pDevice->byChannelSwitchCount = byCount; + pDevice->byNewChannel = byNewChannel; + pDevice->bChannelSwitch = TRUE; + if (byMode == 1) { + bResult=CARDbStopTxPacket(pDevice, PKT_TYPE_802_11_ALL); + } + return (bResult); +} + + +/* + * + * Description: + * Handle Quiet EID defined in 802.11h + * + * Parameters: + * In: + * hDeviceContext - device structure point + * Out: + * none + * + * Return Value: none. + * +-*/ +BOOL +CARDbSetQuiet ( + IN PVOID pDeviceHandler, + IN BOOL bResetQuiet, + IN BYTE byQuietCount, + IN BYTE byQuietPeriod, + IN WORD wQuietDuration, + IN WORD wQuietOffset + ) +{ + PSDevice pDevice = (PSDevice) pDeviceHandler; + UINT ii = 0; + + if (bResetQuiet == TRUE) { + MACvRegBitsOff(pDevice->PortOffset, MAC_REG_MSRCTL, (MSRCTL_QUIETTXCHK | MSRCTL_QUIETEN)); + for(ii=0;iisQuiet[ii].bEnable = FALSE; + } + pDevice->uQuietEnqueue = 0; + pDevice->bEnableFirstQuiet = FALSE; + pDevice->bQuietEnable = FALSE; + pDevice->byQuietStartCount = byQuietCount; + } + if (pDevice->sQuiet[pDevice->uQuietEnqueue].bEnable == FALSE) { + pDevice->sQuiet[pDevice->uQuietEnqueue].bEnable = TRUE; + pDevice->sQuiet[pDevice->uQuietEnqueue].byPeriod = byQuietPeriod; + pDevice->sQuiet[pDevice->uQuietEnqueue].wDuration = wQuietDuration; + pDevice->sQuiet[pDevice->uQuietEnqueue].dwStartTime = (DWORD) byQuietCount; + pDevice->sQuiet[pDevice->uQuietEnqueue].dwStartTime *= pDevice->wBeaconInterval; + pDevice->sQuiet[pDevice->uQuietEnqueue].dwStartTime += wQuietOffset; + pDevice->uQuietEnqueue++; + pDevice->uQuietEnqueue %= MAX_QUIET_COUNT; + if (pDevice->byQuietStartCount < byQuietCount) { + pDevice->byQuietStartCount = byQuietCount; + } + } else { + // we can not handle Quiet EID more + } + return (TRUE); +} + + +/* + * + * Description: + * Do Quiet, It will called by either ISR (after start) or VNTWIFI (before start) so do not need SPINLOCK + * + * Parameters: + * In: + * hDeviceContext - device structure point + * Out: + * none + * + * Return Value: none. + * +-*/ +BOOL +CARDbStartQuiet ( + IN PVOID pDeviceHandler + ) +{ + PSDevice pDevice = (PSDevice) pDeviceHandler; + UINT ii = 0; + DWORD dwStartTime = 0xFFFFFFFF; + UINT uCurrentQuietIndex = 0; + DWORD dwNextTime = 0; + DWORD dwGap = 0; + DWORD dwDuration = 0; + + for(ii=0;iisQuiet[ii].bEnable == TRUE) && + (dwStartTime > pDevice->sQuiet[ii].dwStartTime)) { + dwStartTime = pDevice->sQuiet[ii].dwStartTime; + uCurrentQuietIndex = ii; + } + } + if (dwStartTime == 0xFFFFFFFF) { + // no more quiet + pDevice->bQuietEnable = FALSE; + MACvRegBitsOff(pDevice->PortOffset, MAC_REG_MSRCTL, (MSRCTL_QUIETTXCHK | MSRCTL_QUIETEN)); + } else { + if (pDevice->bQuietEnable == FALSE) { + // first quiet + pDevice->byQuietStartCount--; + dwNextTime = pDevice->sQuiet[uCurrentQuietIndex].dwStartTime; + dwNextTime %= pDevice->wBeaconInterval; + MACvSelectPage1(pDevice->PortOffset); + VNSvOutPortW(pDevice->PortOffset + MAC_REG_QUIETINIT, (WORD) dwNextTime); + VNSvOutPortW(pDevice->PortOffset + MAC_REG_QUIETDUR, (WORD) pDevice->sQuiet[uCurrentQuietIndex].wDuration); + if (pDevice->byQuietStartCount == 0) { + pDevice->bEnableFirstQuiet = FALSE; + MACvRegBitsOn(pDevice->PortOffset, MAC_REG_MSRCTL, (MSRCTL_QUIETTXCHK | MSRCTL_QUIETEN)); + } else { + pDevice->bEnableFirstQuiet = TRUE; + } + MACvSelectPage0(pDevice->PortOffset); + } else { + if (pDevice->dwCurrentQuietEndTime > pDevice->sQuiet[uCurrentQuietIndex].dwStartTime) { + // overlap with previous Quiet + dwGap = pDevice->dwCurrentQuietEndTime - pDevice->sQuiet[uCurrentQuietIndex].dwStartTime; + if (dwGap >= pDevice->sQuiet[uCurrentQuietIndex].wDuration) { + // return FALSE to indicate next quiet expired, should call this function again + return (FALSE); + } + dwDuration = pDevice->sQuiet[uCurrentQuietIndex].wDuration - dwGap; + dwGap = 0; + } else { + dwGap = pDevice->sQuiet[uCurrentQuietIndex].dwStartTime - pDevice->dwCurrentQuietEndTime; + dwDuration = pDevice->sQuiet[uCurrentQuietIndex].wDuration; + } + // set GAP and Next duration + MACvSelectPage1(pDevice->PortOffset); + VNSvOutPortW(pDevice->PortOffset + MAC_REG_QUIETGAP, (WORD) dwGap); + VNSvOutPortW(pDevice->PortOffset + MAC_REG_QUIETDUR, (WORD) dwDuration); + MACvRegBitsOn(pDevice->PortOffset, MAC_REG_MSRCTL, MSRCTL_QUIETRPT); + MACvSelectPage0(pDevice->PortOffset); + } + pDevice->bQuietEnable = TRUE; + pDevice->dwCurrentQuietEndTime = pDevice->sQuiet[uCurrentQuietIndex].dwStartTime; + pDevice->dwCurrentQuietEndTime += pDevice->sQuiet[uCurrentQuietIndex].wDuration; + if (pDevice->sQuiet[uCurrentQuietIndex].byPeriod == 0) { + // not period disable current quiet element + pDevice->sQuiet[uCurrentQuietIndex].bEnable = FALSE; + } else { + // set next period start time + dwNextTime = (DWORD) pDevice->sQuiet[uCurrentQuietIndex].byPeriod; + dwNextTime *= pDevice->wBeaconInterval; + pDevice->sQuiet[uCurrentQuietIndex].dwStartTime = dwNextTime; + } + if (pDevice->dwCurrentQuietEndTime > 0x80010000) { + // decreament all time to avoid wrap around + for(ii=0;iisQuiet[ii].bEnable == TRUE) { + pDevice->sQuiet[ii].dwStartTime -= 0x80000000; + } + } + pDevice->dwCurrentQuietEndTime -= 0x80000000; + } + } + return (TRUE); +} + + +/* + * + * Description: + * Set Channel Info of Country + * + * Parameters: + * In: + * hDeviceContext - device structure point + * Out: + * none + * + * Return Value: none. + * +-*/ +VOID +CARDvSetCountryInfo ( + IN PVOID pDeviceHandler, + IN CARD_PHY_TYPE ePHYType, + IN PVOID pIE + ) +{ + PSDevice pDevice = (PSDevice) pDeviceHandler; + UINT ii = 0; + UINT uu = 0; + UINT step = 0; + UINT uNumOfCountryInfo = 0; + BYTE byCh = 0; + PWLAN_IE_COUNTRY pIE_Country = (PWLAN_IE_COUNTRY) pIE; + + + uNumOfCountryInfo = (pIE_Country->len - 3); + uNumOfCountryInfo /= 3; + + if (ePHYType == PHY_TYPE_11A) { + pDevice->bCountryInfo5G = TRUE; + for(ii=CB_MAX_CHANNEL_24G+1;ii<=CARD_MAX_CHANNEL_TBL;ii++) { + sChannelTbl[ii].bValid = FALSE; + } + step = 4; + } else { + pDevice->bCountryInfo24G = TRUE; + for(ii=1;ii<=CB_MAX_CHANNEL_24G;ii++) { + sChannelTbl[ii].bValid = FALSE; + } + step = 1; + } + pDevice->abyCountryCode[0] = pIE_Country->abyCountryString[0]; + pDevice->abyCountryCode[1] = pIE_Country->abyCountryString[1]; + pDevice->abyCountryCode[2] = pIE_Country->abyCountryString[2]; + + for(ii=0;iiabyCountryInfo[ii*3+1];uu++) { + byCh = CARDbyGetChannelMapping(pDevice, (BYTE)(pIE_Country->abyCountryInfo[ii*3]+step*uu), ePHYType); + sChannelTbl[byCh].bValid = TRUE; + pDevice->abyRegPwr[byCh] = pIE_Country->abyCountryInfo[ii*3+2]; + } + } +} + +/* + * + * Description: + * Set Local Power Constraint + * + * Parameters: + * In: + * hDeviceContext - device structure point + * Out: + * none + * + * Return Value: none. + * +-*/ +VOID +CARDvSetPowerConstraint ( + IN PVOID pDeviceHandler, + IN BYTE byChannel, + IN I8 byPower + ) +{ + PSDevice pDevice = (PSDevice) pDeviceHandler; + + if (byChannel > CB_MAX_CHANNEL_24G) { + if (pDevice->bCountryInfo5G == TRUE) { + pDevice->abyLocalPwr[byChannel] = pDevice->abyRegPwr[byChannel] - byPower; + } + } else { + if (pDevice->bCountryInfo24G == TRUE) { + pDevice->abyLocalPwr[byChannel] = pDevice->abyRegPwr[byChannel] - byPower; + } + } +} + + +/* + * + * Description: + * Set Local Power Constraint + * + * Parameters: + * In: + * hDeviceContext - device structure point + * Out: + * none + * + * Return Value: none. + * +-*/ +VOID +CARDvGetPowerCapability ( + IN PVOID pDeviceHandler, + OUT PBYTE pbyMinPower, + OUT PBYTE pbyMaxPower + ) +{ + PSDevice pDevice = (PSDevice) pDeviceHandler; + BYTE byDec = 0; + + *pbyMaxPower = pDevice->abyOFDMDefaultPwr[pDevice->byCurrentCh]; + byDec = pDevice->abyOFDMPwrTbl[pDevice->byCurrentCh]; + if (pDevice->byRFType == RF_UW2452) { + byDec *= 3; + byDec >>= 1; + } else { + byDec <<= 1; + } + *pbyMinPower = pDevice->abyOFDMDefaultPwr[pDevice->byCurrentCh] - byDec; +} + + +/* + * + * Description: + * Set Support Channels IE defined in 802.11h + * + * Parameters: + * In: + * hDeviceContext - device structure point + * Out: + * none + * + * Return Value: none. + * +-*/ +BYTE +CARDbySetSupportChannels ( + IN PVOID pDeviceHandler, + IN OUT PBYTE pbyIEs + ) +{ + PSDevice pDevice = (PSDevice) pDeviceHandler; + UINT ii; + BYTE byCount; + PWLAN_IE_SUPP_CH pIE = (PWLAN_IE_SUPP_CH) pbyIEs; + PBYTE pbyChTupple; + BYTE byLen = 0; + + + pIE->byElementID = WLAN_EID_SUPP_CH; + pIE->len = 0; + pbyChTupple = pIE->abyChannelTuple; + byLen = 2; + // lower band + byCount = 0; + if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[28] == TRUE) { + for (ii=28;ii<36;ii+=2) { + if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[ii] == TRUE) { + byCount++; + } + } + *pbyChTupple++ = 34; + *pbyChTupple++ = byCount; + byLen += 2; + } else if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[29] == TRUE) { + for (ii=29;ii<36;ii+=2) { + if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[ii] == TRUE) { + byCount++; + } + } + *pbyChTupple++ = 36; + *pbyChTupple++ = byCount; + byLen += 2; + } + // middle band + byCount = 0; + if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[36] == TRUE) { + for (ii=36;ii<40;ii++) { + if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[ii] == TRUE) { + byCount++; + } + } + *pbyChTupple++ = 52; + *pbyChTupple++ = byCount; + byLen += 2; + } + // higher band + byCount = 0; + if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[40] == TRUE) { + for (ii=40;ii<51;ii++) { + if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[ii] == TRUE) { + byCount++; + } + } + *pbyChTupple++ = 100; + *pbyChTupple++ = byCount; + byLen += 2; + } else if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[51] == TRUE) { + for (ii=51;ii<56;ii++) { + if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[ii] == TRUE) { + byCount++; + } + } + *pbyChTupple++ = 149; + *pbyChTupple++ = byCount; + byLen += 2; + } + pIE->len += (byLen - 2); + return (byLen); +} + + +/* + * + * Description: + * Get Current Tx Power + * + * Parameters: + * In: + * hDeviceContext - device structure point + * Out: + * none + * + * Return Value: none. + * +-*/ +I8 +CARDbyGetTransmitPower ( + IN PVOID pDeviceHandler + ) +{ + PSDevice pDevice = (PSDevice) pDeviceHandler; + + return (pDevice->byCurPwrdBm); +} + + +BOOL +CARDbChannelGetList ( + IN UINT uCountryCodeIdx, + OUT PBYTE pbyChannelTable + ) +{ + if (uCountryCodeIdx >= CCODE_MAX) { + return (FALSE); + } + MEMvCopy(pbyChannelTable, ChannelRuleTab[uCountryCodeIdx].bChannelIdxList, CB_MAX_CHANNEL); + return (TRUE); +} + + +VOID +CARDvSetCountryIE( + IN PVOID pDeviceHandler, + IN PVOID pIE + ) +{ + PSDevice pDevice = (PSDevice) pDeviceHandler; + UINT ii; + PWLAN_IE_COUNTRY pIECountry = (PWLAN_IE_COUNTRY) pIE; + + pIECountry->byElementID = WLAN_EID_COUNTRY; + pIECountry->len = 0; + pIECountry->abyCountryString[0] = ChannelRuleTab[pDevice->byZoneType].chCountryCode[0]; + pIECountry->abyCountryString[1] = ChannelRuleTab[pDevice->byZoneType].chCountryCode[1]; + pIECountry->abyCountryString[2] = ' '; + for (ii = CB_MAX_CHANNEL_24G; ii < CB_MAX_CHANNEL; ii++ ) { + if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[ii] != 0) { + pIECountry->abyCountryInfo[pIECountry->len++] = sChannelTbl[ii+1].byChannelNumber; + pIECountry->abyCountryInfo[pIECountry->len++] = 1; + pIECountry->abyCountryInfo[pIECountry->len++] = ChannelRuleTab[pDevice->byZoneType].byPower[ii]; + } + } + pIECountry->len += 3; +} + + +BOOL +CARDbGetChannelMapInfo( + IN PVOID pDeviceHandler, + IN UINT uChannelIndex, + OUT PBYTE pbyChannelNumber, + OUT PBYTE pbyMap + ) +{ +// PSDevice pDevice = (PSDevice) pDeviceHandler; + + if (uChannelIndex > CB_MAX_CHANNEL) { + return FALSE; + } + *pbyChannelNumber = sChannelTbl[uChannelIndex].byChannelNumber; + *pbyMap = sChannelTbl[uChannelIndex].byMAP; + return sChannelTbl[uChannelIndex].bValid; +} + + +VOID +CARDvSetChannelMapInfo( + IN PVOID pDeviceHandler, + IN UINT uChannelIndex, + IN BYTE byMap + ) +{ +// PSDevice pDevice = (PSDevice) pDeviceHandler; + + if (uChannelIndex > CB_MAX_CHANNEL) { + return; + } + sChannelTbl[uChannelIndex].byMAP |= byMap; +} + + +VOID +CARDvClearChannelMapInfo( + IN PVOID pDeviceHandler + ) +{ +// PSDevice pDevice = (PSDevice) pDeviceHandler; + UINT ii = 0; + + for (ii = 1; ii <= CB_MAX_CHANNEL; ii++) { + sChannelTbl[ii].byMAP = 0; + } +} + + +BYTE +CARDbyAutoChannelSelect( + IN PVOID pDeviceHandler, + CARD_PHY_TYPE ePHYType + ) +{ +// PSDevice pDevice = (PSDevice) pDeviceHandler; + UINT ii = 0; + BYTE byOptionChannel = 0; + INT aiWeight[CB_MAX_CHANNEL_24G+1] = {-1000,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + + if (ePHYType == PHY_TYPE_11A) { + for(ii=CB_MAX_CHANNEL_24G+1;ii<=CB_MAX_CHANNEL;ii++) { + if (sChannelTbl[ii].bValid == TRUE) { + if (byOptionChannel == 0) { + byOptionChannel = (BYTE) ii; + } + if (sChannelTbl[ii].byMAP == 0) { + return ((BYTE) ii); + } else if (BITbIsBitOff(sChannelTbl[ii].byMAP, 0x08)) { + byOptionChannel = (BYTE) ii; + } + } + } + } else { + byOptionChannel = 0; + for(ii=1;ii<=CB_MAX_CHANNEL_24G;ii++) { + if (sChannelTbl[ii].bValid == TRUE) { + if (sChannelTbl[ii].byMAP == 0) { + aiWeight[ii] += 100; + } else if (BITbIsBitOn(sChannelTbl[ii].byMAP, 0x01)) { + if (ii > 3) { + aiWeight[ii-3] -= 10; + } + if (ii > 2) { + aiWeight[ii-2] -= 20; + } + if (ii > 1) { + aiWeight[ii-1] -= 40; + } + aiWeight[ii] -= 80; + if (ii < CB_MAX_CHANNEL_24G) { + aiWeight[ii+1] -= 40; + } + if (ii < (CB_MAX_CHANNEL_24G - 1)) { + aiWeight[ii+2] -= 20; + } + if (ii < (CB_MAX_CHANNEL_24G - 2)) { + aiWeight[ii+3] -= 10; + } + } + } + } + for(ii=1;ii<=CB_MAX_CHANNEL_24G;ii++) { + if ((sChannelTbl[ii].bValid == TRUE) && + (aiWeight[ii] > aiWeight[byOptionChannel])) { + byOptionChannel = (BYTE) ii; + } + } + } + return (byOptionChannel); +} + + + +//xxx +VOID +CARDvSafeResetTx ( + IN PVOID pDeviceHandler + ) +{ + PSDevice pDevice = (PSDevice) pDeviceHandler; + UINT uu; + PSTxDesc pCurrTD; + + // initialize TD index + pDevice->apTailTD[0] = pDevice->apCurrTD[0] = &(pDevice->apTD0Rings[0]); + pDevice->apTailTD[1] = pDevice->apCurrTD[1] = &(pDevice->apTD1Rings[0]); + + for (uu = 0; uu < TYPE_MAXTD; uu ++) + pDevice->iTDUsed[uu] = 0; + + for (uu = 0; uu < pDevice->sOpts.nTxDescs[0]; uu++) { + pCurrTD = &(pDevice->apTD0Rings[uu]); + pCurrTD->m_td0TD0.f1Owner = OWNED_BY_HOST; + // init all Tx Packet pointer to NULL + } + for (uu = 0; uu < pDevice->sOpts.nTxDescs[1]; uu++) { + pCurrTD = &(pDevice->apTD1Rings[uu]); + pCurrTD->m_td0TD0.f1Owner = OWNED_BY_HOST; + // init all Tx Packet pointer to NULL + } + + // set MAC TD pointer + MACvSetCurrTXDescAddr(TYPE_TXDMA0, pDevice->PortOffset, + (pDevice->td0_pool_dma)); + + MACvSetCurrTXDescAddr(TYPE_AC0DMA, pDevice->PortOffset, + (pDevice->td1_pool_dma)); + + // set MAC Beacon TX pointer + MACvSetCurrBCNTxDescAddr(pDevice->PortOffset, + (pDevice->tx_beacon_dma)); + +} + + + +/*+ + * + * Description: + * Reset Rx + * + * Parameters: + * In: + * pDevice - Pointer to the adapter + * Out: + * none + * + * Return Value: none + * +-*/ +VOID +CARDvSafeResetRx ( + IN PVOID pDeviceHandler + ) +{ + PSDevice pDevice = (PSDevice) pDeviceHandler; + UINT uu; + PSRxDesc pDesc; + + + + // initialize RD index + pDevice->pCurrRD[0]=&(pDevice->aRD0Ring[0]); + pDevice->pCurrRD[1]=&(pDevice->aRD1Ring[0]); + + // init state, all RD is chip's + for (uu = 0; uu < pDevice->sOpts.nRxDescs0; uu++) { + pDesc =&(pDevice->aRD0Ring[uu]); + pDesc->m_rd0RD0.wResCount = (WORD)(pDevice->rx_buf_sz); + pDesc->m_rd0RD0.f1Owner=OWNED_BY_NIC; + pDesc->m_rd1RD1.wReqCount = (WORD)(pDevice->rx_buf_sz); + } + + // init state, all RD is chip's + for (uu = 0; uu < pDevice->sOpts.nRxDescs1; uu++) { + pDesc =&(pDevice->aRD1Ring[uu]); + pDesc->m_rd0RD0.wResCount = (WORD)(pDevice->rx_buf_sz); + pDesc->m_rd0RD0.f1Owner=OWNED_BY_NIC; + pDesc->m_rd1RD1.wReqCount = (WORD)(pDevice->rx_buf_sz); + } + + pDevice->cbDFCB = CB_MAX_RX_FRAG; + pDevice->cbFreeDFCB = pDevice->cbDFCB; + + // set perPkt mode + MACvRx0PerPktMode(pDevice->PortOffset); + MACvRx1PerPktMode(pDevice->PortOffset); + // set MAC RD pointer + MACvSetCurrRx0DescAddr(pDevice->PortOffset, + pDevice->rd0_pool_dma); + + MACvSetCurrRx1DescAddr(pDevice->PortOffset, + pDevice->rd1_pool_dma); +} + + + + +/* + * Description: Get response Control frame rate in CCK mode + * + * Parameters: + * In: + * pDevice - The adapter to be set + * wRateIdx - Receiving data rate + * Out: + * none + * + * Return Value: response Control frame rate + * + */ +WORD CARDwGetCCKControlRate(PVOID pDeviceHandler, WORD wRateIdx) +{ + PSDevice pDevice = (PSDevice) pDeviceHandler; + UINT ui = (UINT)wRateIdx; + + while (ui > RATE_1M) { + if (pDevice->wBasicRate & ((WORD)1 << ui)) { + return (WORD)ui; + } + ui --; + } + return (WORD)RATE_1M; +} + +/* + * Description: Get response Control frame rate in OFDM mode + * + * Parameters: + * In: + * pDevice - The adapter to be set + * wRateIdx - Receiving data rate + * Out: + * none + * + * Return Value: response Control frame rate + * + */ +WORD CARDwGetOFDMControlRate (PVOID pDeviceHandler, WORD wRateIdx) +{ + PSDevice pDevice = (PSDevice) pDeviceHandler; + UINT ui = (UINT)wRateIdx; + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"BASIC RATE: %X\n", pDevice->wBasicRate); + + if (!CARDbIsOFDMinBasicRate((PVOID)pDevice)) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"CARDwGetOFDMControlRate:(NO OFDM) %d\n", wRateIdx); + if (wRateIdx > RATE_24M) + wRateIdx = RATE_24M; + return wRateIdx; + } + while (ui > RATE_11M) { + if (pDevice->wBasicRate & ((WORD)1 << ui)) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"CARDwGetOFDMControlRate : %d\n", ui); + return (WORD)ui; + } + ui --; + } + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"CARDwGetOFDMControlRate: 6M\n"); + return (WORD)RATE_24M; +} + + +/* + * Description: Set RSPINF + * + * Parameters: + * In: + * pDevice - The adapter to be set + * Out: + * none + * + * Return Value: None. + * + */ +void CARDvSetRSPINF (PVOID pDeviceHandler, CARD_PHY_TYPE ePHYType) +{ + PSDevice pDevice = (PSDevice) pDeviceHandler; + BYTE byServ = 0x00, bySignal = 0x00; //For CCK + WORD wLen = 0x0000; + BYTE byTxRate, byRsvTime; //For OFDM + + //Set to Page1 + MACvSelectPage1(pDevice->PortOffset); + + //RSPINF_b_1 + BBvCaculateParameter(pDevice, + 14, + CARDwGetCCKControlRate((PVOID)pDevice, RATE_1M), + PK_TYPE_11B, + &wLen, + &byServ, + &bySignal + ); + + VNSvOutPortD(pDevice->PortOffset + MAC_REG_RSPINF_B_1, MAKEDWORD(wLen,MAKEWORD(bySignal,byServ))); + ///RSPINF_b_2 + BBvCaculateParameter(pDevice, + 14, + CARDwGetCCKControlRate((PVOID)pDevice, RATE_2M), + PK_TYPE_11B, + &wLen, + &byServ, + &bySignal + ); + + VNSvOutPortD(pDevice->PortOffset + MAC_REG_RSPINF_B_2, MAKEDWORD(wLen,MAKEWORD(bySignal,byServ))); + //RSPINF_b_5 + BBvCaculateParameter(pDevice, + 14, + CARDwGetCCKControlRate((PVOID)pDevice, RATE_5M), + PK_TYPE_11B, + &wLen, + &byServ, + &bySignal + ); + + VNSvOutPortD(pDevice->PortOffset + MAC_REG_RSPINF_B_5, MAKEDWORD(wLen,MAKEWORD(bySignal,byServ))); + //RSPINF_b_11 + BBvCaculateParameter(pDevice, + 14, + CARDwGetCCKControlRate((PVOID)pDevice, RATE_11M), + PK_TYPE_11B, + &wLen, + &byServ, + &bySignal + ); + + VNSvOutPortD(pDevice->PortOffset + MAC_REG_RSPINF_B_11, MAKEDWORD(wLen,MAKEWORD(bySignal,byServ))); + //RSPINF_a_6 + s_vCaculateOFDMRParameter(RATE_6M, + ePHYType, + &byTxRate, + &byRsvTime); + VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_6, MAKEWORD(byTxRate,byRsvTime)); + //RSPINF_a_9 + s_vCaculateOFDMRParameter(RATE_9M, + ePHYType, + &byTxRate, + &byRsvTime); + VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_9, MAKEWORD(byTxRate,byRsvTime)); + //RSPINF_a_12 + s_vCaculateOFDMRParameter(RATE_12M, + ePHYType, + &byTxRate, + &byRsvTime); + VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_12, MAKEWORD(byTxRate,byRsvTime)); + //RSPINF_a_18 + s_vCaculateOFDMRParameter(RATE_18M, + ePHYType, + &byTxRate, + &byRsvTime); + VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_18, MAKEWORD(byTxRate,byRsvTime)); + //RSPINF_a_24 + s_vCaculateOFDMRParameter(RATE_24M, + ePHYType, + &byTxRate, + &byRsvTime); + VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_24, MAKEWORD(byTxRate,byRsvTime)); + //RSPINF_a_36 + s_vCaculateOFDMRParameter(CARDwGetOFDMControlRate((PVOID)pDevice, RATE_36M), + ePHYType, + &byTxRate, + &byRsvTime); + VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_36, MAKEWORD(byTxRate,byRsvTime)); + //RSPINF_a_48 + s_vCaculateOFDMRParameter(CARDwGetOFDMControlRate((PVOID)pDevice, RATE_48M), + ePHYType, + &byTxRate, + &byRsvTime); + VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_48, MAKEWORD(byTxRate,byRsvTime)); + //RSPINF_a_54 + s_vCaculateOFDMRParameter(CARDwGetOFDMControlRate((PVOID)pDevice, RATE_54M), + ePHYType, + &byTxRate, + &byRsvTime); + VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_54, MAKEWORD(byTxRate,byRsvTime)); + + //RSPINF_a_72 + s_vCaculateOFDMRParameter(CARDwGetOFDMControlRate((PVOID)pDevice, RATE_54M), + ePHYType, + &byTxRate, + &byRsvTime); + VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_72, MAKEWORD(byTxRate,byRsvTime)); + //Set to Page0 + MACvSelectPage0(pDevice->PortOffset); +} + +/* + * Description: Update IFS + * + * Parameters: + * In: + * pDevice - The adapter to be set + * Out: + * none + * + * Return Value: None. + * + */ +void vUpdateIFS (PVOID pDeviceHandler) +{ + //Set SIFS, DIFS, EIFS, SlotTime, CwMin + PSDevice pDevice = (PSDevice) pDeviceHandler; + + BYTE byMaxMin = 0; + if (pDevice->byPacketType==PK_TYPE_11A) {//0000 0000 0000 0000,11a + pDevice->uSlot = C_SLOT_SHORT; + pDevice->uSIFS = C_SIFS_A; + pDevice->uDIFS = C_SIFS_A + 2*C_SLOT_SHORT; + pDevice->uCwMin = C_CWMIN_A; + byMaxMin = 4; + } + else if (pDevice->byPacketType==PK_TYPE_11B) {//0000 0001 0000 0000,11b + pDevice->uSlot = C_SLOT_LONG; + pDevice->uSIFS = C_SIFS_BG; + pDevice->uDIFS = C_SIFS_BG + 2*C_SLOT_LONG; + pDevice->uCwMin = C_CWMIN_B; + byMaxMin = 5; + } + else { // PK_TYPE_11GA & PK_TYPE_11GB + pDevice->uSIFS = C_SIFS_BG; + if (pDevice->bShortSlotTime) { + pDevice->uSlot = C_SLOT_SHORT; + } else { + pDevice->uSlot = C_SLOT_LONG; + } + pDevice->uDIFS = C_SIFS_BG + 2*pDevice->uSlot; + if (pDevice->wBasicRate & 0x0150) { //0000 0001 0101 0000,24M,12M,6M + pDevice->uCwMin = C_CWMIN_A; + byMaxMin = 4; + } + else { + pDevice->uCwMin = C_CWMIN_B; + byMaxMin = 5; + } + } + + pDevice->uCwMax = C_CWMAX; + pDevice->uEIFS = C_EIFS; + if (pDevice->byRFType == RF_RFMD2959) { + // bcs TX_PE will reserve 3 us + VNSvOutPortB(pDevice->PortOffset + MAC_REG_SIFS, (BYTE)(pDevice->uSIFS - 3)); + VNSvOutPortB(pDevice->PortOffset + MAC_REG_DIFS, (BYTE)(pDevice->uDIFS - 3)); + } else { + VNSvOutPortB(pDevice->PortOffset + MAC_REG_SIFS, (BYTE)pDevice->uSIFS); + VNSvOutPortB(pDevice->PortOffset + MAC_REG_DIFS, (BYTE)pDevice->uDIFS); + } + VNSvOutPortB(pDevice->PortOffset + MAC_REG_EIFS, (BYTE)pDevice->uEIFS); + VNSvOutPortB(pDevice->PortOffset + MAC_REG_SLOT, (BYTE)pDevice->uSlot); + byMaxMin |= 0xA0;//1010 1111,C_CWMAX = 1023 + VNSvOutPortB(pDevice->PortOffset + MAC_REG_CWMAXMIN0, (BYTE)byMaxMin); +} + +void CARDvUpdateBasicTopRate (PVOID pDeviceHandler) +{ + PSDevice pDevice = (PSDevice) pDeviceHandler; + BYTE byTopOFDM = RATE_24M, byTopCCK = RATE_1M; + BYTE ii; + + //Determines the highest basic rate. + for (ii = RATE_54M; ii >= RATE_6M; ii --) { + if ( (pDevice->wBasicRate) & ((WORD)(1<byTopOFDMBasicRate = byTopOFDM; + + for (ii = RATE_11M;; ii --) { + if ( (pDevice->wBasicRate) & ((WORD)(1<byTopCCKBasicRate = byTopCCK; +} + + +/* + * Description: Set NIC Tx Basic Rate + * + * Parameters: + * In: + * pDevice - The adapter to be set + * wBasicRate - Basic Rate to be set + * Out: + * none + * + * Return Value: TRUE if succeeded; FALSE if failed. + * + */ +BOOL CARDbAddBasicRate (PVOID pDeviceHandler, WORD wRateIdx) +{ + PSDevice pDevice = (PSDevice) pDeviceHandler; + WORD wRate = (WORD)(1<wBasicRate |= wRate; + + //Determines the highest basic rate. + CARDvUpdateBasicTopRate((PVOID)pDevice); + + return(TRUE); +} + +BOOL CARDbIsOFDMinBasicRate (PVOID pDeviceHandler) +{ + PSDevice pDevice = (PSDevice) pDeviceHandler; + int ii; + + for (ii = RATE_54M; ii >= RATE_6M; ii --) { + if ((pDevice->wBasicRate) & ((WORD)(1<byBBType == BB_TYPE_11A || pDevice->byBBType == BB_TYPE_11B) { + return (BYTE)pDevice->byBBType; + } + else if (CARDbIsOFDMinBasicRate((PVOID)pDevice)) { + return PK_TYPE_11GA; + } + else { + return PK_TYPE_11GB; + } +} + +/* + * Description: Set NIC Loopback mode + * + * Parameters: + * In: + * pDevice - The adapter to be set + * wLoopbackMode - Loopback mode to be set + * Out: + * none + * + * Return Value: none + * + */ +void CARDvSetLoopbackMode (DWORD_PTR dwIoBase, WORD wLoopbackMode) +{ + switch(wLoopbackMode) { + case CARD_LB_NONE: + case CARD_LB_MAC: + case CARD_LB_PHY: + break; + default: + ASSERT(FALSE); + break; + } + // set MAC loopback + MACvSetLoopbackMode(dwIoBase, LOBYTE(wLoopbackMode)); + // set Baseband loopback +} + + +/* + * Description: Software Reset NIC + * + * Parameters: + * In: + * pDevice - The adapter to be reset + * Out: + * none + * + * Return Value: none + * + */ +BOOL CARDbSoftwareReset (PVOID pDeviceHandler) +{ + PSDevice pDevice = (PSDevice) pDeviceHandler; + + // reset MAC + if (!MACbSafeSoftwareReset(pDevice->PortOffset)) + return FALSE; + + return TRUE; +} + + +/* + * Description: Caculate TSF offset of two TSF input + * Get TSF Offset from RxBCN's TSF and local TSF + * + * Parameters: + * In: + * pDevice - The adapter to be sync. + * qwTSF1 - Rx BCN's TSF + * qwTSF2 - Local TSF + * Out: + * none + * + * Return Value: TSF Offset value + * + */ +QWORD CARDqGetTSFOffset (BYTE byRxRate, QWORD qwTSF1, QWORD qwTSF2) +{ + QWORD qwTSFOffset; + WORD wRxBcnTSFOffst= 0;; + + HIDWORD(qwTSFOffset) = 0; + LODWORD(qwTSFOffset) = 0; + wRxBcnTSFOffst = cwRXBCNTSFOff[byRxRate%MAX_RATE]; + (qwTSF2).u.dwLowDword += (DWORD)(wRxBcnTSFOffst); + if ((qwTSF2).u.dwLowDword < (DWORD)(wRxBcnTSFOffst)) { + (qwTSF2).u.dwHighDword++; + } + LODWORD(qwTSFOffset) = LODWORD(qwTSF1) - LODWORD(qwTSF2); + if (LODWORD(qwTSF1) < LODWORD(qwTSF2)) { + // if borrow needed + HIDWORD(qwTSFOffset) = HIDWORD(qwTSF1) - HIDWORD(qwTSF2) - 1 ; + } + else { + HIDWORD(qwTSFOffset) = HIDWORD(qwTSF1) - HIDWORD(qwTSF2); + }; + return (qwTSFOffset); +} + + +/* + * Description: Read NIC TSF counter + * Get local TSF counter + * + * Parameters: + * In: + * pDevice - The adapter to be read + * Out: + * qwCurrTSF - Current TSF counter + * + * Return Value: TRUE if success; otherwise FALSE + * + */ +BOOL CARDbGetCurrentTSF (DWORD_PTR dwIoBase, PQWORD pqwCurrTSF) +{ + WORD ww; + BYTE byData; + + MACvRegBitsOn(dwIoBase, MAC_REG_TFTCTL, TFTCTL_TSFCNTRRD); + for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { + VNSvInPortB(dwIoBase + MAC_REG_TFTCTL, &byData); + if (BITbIsBitOff(byData, TFTCTL_TSFCNTRRD)) + break; + } + if (ww == W_MAX_TIMEOUT) + return(FALSE); + VNSvInPortD(dwIoBase + MAC_REG_TSFCNTR, &LODWORD(*pqwCurrTSF)); + VNSvInPortD(dwIoBase + MAC_REG_TSFCNTR + 4, &HIDWORD(*pqwCurrTSF)); + + return(TRUE); +} + + +/* + * Description: Read NIC TSF counter + * Get NEXTTBTT from adjusted TSF and Beacon Interval + * + * Parameters: + * In: + * qwTSF - Current TSF counter + * wbeaconInterval - Beacon Interval + * Out: + * qwCurrTSF - Current TSF counter + * + * Return Value: TSF value of next Beacon + * + */ +QWORD CARDqGetNextTBTT (QWORD qwTSF, WORD wBeaconInterval) +{ + + UINT uLowNextTBTT; + UINT uHighRemain, uLowRemain; + UINT uBeaconInterval; + + uBeaconInterval = wBeaconInterval * 1024; + // Next TBTT = ((local_current_TSF / beacon_interval) + 1 ) * beacon_interval + uLowNextTBTT = (LODWORD(qwTSF) >> 10) << 10; + // low dword (mod) bcn + uLowRemain = (uLowNextTBTT) % uBeaconInterval; +// uHighRemain = ((0x80000000 % uBeaconInterval)* 2 * HIDWORD(qwTSF)) +// % uBeaconInterval; + // high dword (mod) bcn + uHighRemain = (((0xffffffff % uBeaconInterval) + 1) * HIDWORD(qwTSF)) + % uBeaconInterval; + uLowRemain = (uHighRemain + uLowRemain) % uBeaconInterval; + uLowRemain = uBeaconInterval - uLowRemain; + + // check if carry when add one beacon interval + if ((~uLowNextTBTT) < uLowRemain) + HIDWORD(qwTSF) ++ ; + + LODWORD(qwTSF) = uLowNextTBTT + uLowRemain; + + return (qwTSF); +} + + +/* + * Description: Set NIC TSF counter for first Beacon time + * Get NEXTTBTT from adjusted TSF and Beacon Interval + * + * Parameters: + * In: + * dwIoBase - IO Base + * wBeaconInterval - Beacon Interval + * Out: + * none + * + * Return Value: none + * + */ +void CARDvSetFirstNextTBTT (DWORD_PTR dwIoBase, WORD wBeaconInterval) +{ + + QWORD qwNextTBTT; + + HIDWORD(qwNextTBTT) = 0; + LODWORD(qwNextTBTT) = 0; + CARDbGetCurrentTSF(dwIoBase, &qwNextTBTT); //Get Local TSF counter + qwNextTBTT = CARDqGetNextTBTT(qwNextTBTT, wBeaconInterval); + // Set NextTBTT + VNSvOutPortD(dwIoBase + MAC_REG_NEXTTBTT, LODWORD(qwNextTBTT)); + VNSvOutPortD(dwIoBase + MAC_REG_NEXTTBTT + 4, HIDWORD(qwNextTBTT)); + MACvRegBitsOn(dwIoBase, MAC_REG_TFTCTL, TFTCTL_TBTTSYNCEN); + //DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Card:First Next TBTT[%8xh:%8xh] \n", HIDWORD(qwNextTBTT), LODWORD(qwNextTBTT)); + return; +} + + +/* + * Description: Sync NIC TSF counter for Beacon time + * Get NEXTTBTT and write to HW + * + * Parameters: + * In: + * pDevice - The adapter to be set + * qwTSF - Current TSF counter + * wBeaconInterval - Beacon Interval + * Out: + * none + * + * Return Value: none + * + */ +void CARDvUpdateNextTBTT (DWORD_PTR dwIoBase, QWORD qwTSF, WORD wBeaconInterval) +{ + + qwTSF = CARDqGetNextTBTT(qwTSF, wBeaconInterval); + // Set NextTBTT + VNSvOutPortD(dwIoBase + MAC_REG_NEXTTBTT, LODWORD(qwTSF)); + VNSvOutPortD(dwIoBase + MAC_REG_NEXTTBTT + 4, HIDWORD(qwTSF)); + MACvRegBitsOn(dwIoBase, MAC_REG_TFTCTL, TFTCTL_TBTTSYNCEN); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Card:Update Next TBTT[%8xh:%8xh] \n",(UINT)HIDWORD(qwTSF), (UINT)LODWORD(qwTSF)); + + return; +} + + + + + + + diff --git a/drivers/staging/vt6655/card.h b/drivers/staging/vt6655/card.h new file mode 100644 index 000000000000..bb292e14b0b3 --- /dev/null +++ b/drivers/staging/vt6655/card.h @@ -0,0 +1,273 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * File: card.h + * + * Purpose: Provide functions to setup NIC operation mode + * + * Author: Tevin Chen + * + * Date: May 21, 1996 + * + */ + + +#ifndef __CARD_H__ +#define __CARD_H__ + +//#if !defined(__DEVICE_H__) +//#include "device.h" +//#endif +#if !defined(__TTYPE_H__) +#include "ttype.h" +#endif + + + + +/*--------------------- Export Definitions -------------------------*/ +// +// Loopback mode +// +// LOBYTE is MAC LB mode, HIBYTE is MII LB mode +#define CARD_LB_NONE MAKEWORD(MAC_LB_NONE, 0) +#define CARD_LB_MAC MAKEWORD(MAC_LB_INTERNAL, 0) // PHY must ISO, avoid MAC loopback packet go out +#define CARD_LB_PHY MAKEWORD(MAC_LB_EXT, 0) + + +#define DEFAULT_MSDU_LIFETIME 512 // ms +#define DEFAULT_MSDU_LIFETIME_RES_64us 8000 // 64us + +#define DEFAULT_MGN_LIFETIME 8 // ms +#define DEFAULT_MGN_LIFETIME_RES_64us 125 // 64us + +#define CB_MAX_CHANNEL_24G 14 +#define CB_MAX_CHANNEL_5G 42 //[20050104] add channel9(5045MHz), 41==>42 +#define CB_MAX_CHANNEL (CB_MAX_CHANNEL_24G+CB_MAX_CHANNEL_5G) + +typedef enum _CARD_PHY_TYPE { + PHY_TYPE_AUTO, + PHY_TYPE_11B, + PHY_TYPE_11G, + PHY_TYPE_11A +} CARD_PHY_TYPE, *PCARD_PHY_TYPE; + +typedef enum _CARD_PKT_TYPE { + PKT_TYPE_802_11_BCN, + PKT_TYPE_802_11_MNG, + PKT_TYPE_802_11_DATA, + PKT_TYPE_802_11_ALL +} CARD_PKT_TYPE, *PCARD_PKT_TYPE; + +typedef enum _CARD_STATUS_TYPE { + CARD_STATUS_MEDIA_CONNECT, + CARD_STATUS_MEDIA_DISCONNECT, + CARD_STATUS_PMKID +} CARD_STATUS_TYPE, *PCARD_STATUS_TYPE; + +typedef enum _CARD_OP_MODE { + OP_MODE_INFRASTRUCTURE, + OP_MODE_ADHOC, + OP_MODE_AP, + OP_MODE_UNKNOWN +} CARD_OP_MODE, *PCARD_OP_MODE; + + + +/*--------------------- Export Classes ----------------------------*/ + +/*--------------------- Export Variables --------------------------*/ + +/*--------------------- Export Functions --------------------------*/ +#ifdef __cplusplus +extern "C" { /* Assume C declarations for C++ */ +#endif /* __cplusplus */ + +BOOL ChannelValid(UINT CountryCode, UINT ChannelIndex); +void CARDvSetRSPINF(PVOID pDeviceHandler, CARD_PHY_TYPE ePHYType); +void vUpdateIFS(PVOID pDeviceHandler); +void CARDvUpdateBasicTopRate(PVOID pDeviceHandler); +BOOL CARDbAddBasicRate(PVOID pDeviceHandler, WORD wRateIdx); +BOOL CARDbIsOFDMinBasicRate(PVOID pDeviceHandler); +void CARDvSetLoopbackMode(DWORD_PTR dwIoBase, WORD wLoopbackMode); +BOOL CARDbSoftwareReset(PVOID pDeviceHandler); +void CARDvSetFirstNextTBTT(DWORD_PTR dwIoBase, WORD wBeaconInterval); +void CARDvUpdateNextTBTT(DWORD_PTR dwIoBase, QWORD qwTSF, WORD wBeaconInterval); +BOOL CARDbGetCurrentTSF(DWORD_PTR dwIoBase, PQWORD pqwCurrTSF); +QWORD CARDqGetNextTBTT(QWORD qwTSF, WORD wBeaconInterval); +QWORD CARDqGetTSFOffset(BYTE byRxRate, QWORD qwTSF1, QWORD qwTSF2); +BOOL CARDbSetTxPower(PVOID pDeviceHandler, ULONG ulTxPower); +BYTE CARDbyGetPktType(PVOID pDeviceHandler); +VOID CARDvSafeResetTx(PVOID pDeviceHandler); +VOID CARDvSafeResetRx(PVOID pDeviceHandler); + +//xxx +BOOL CARDbRadioPowerOff(PVOID pDeviceHandler); +BOOL CARDbRadioPowerOn(PVOID pDeviceHandler); +BOOL CARDbSetChannel(PVOID pDeviceHandler, UINT uConnectionChannel); +//BOOL CARDbSendPacket(PVOID pDeviceHandler, PVOID pPacket, CARD_PKT_TYPE ePktType, UINT uLength); +BOOL CARDbIsShortPreamble(PVOID pDeviceHandler); +BOOL CARDbIsShorSlotTime(PVOID pDeviceHandler); +BOOL CARDbSetPhyParameter(PVOID pDeviceHandler, CARD_PHY_TYPE ePHYType, WORD wCapInfo, BYTE byERPField, PVOID pvSupportRateIEs, PVOID pvExtSupportRateIEs); +BOOL CARDbUpdateTSF(PVOID pDeviceHandler, BYTE byRxRate, QWORD qwBSSTimestamp, QWORD qwLocalTSF); +BOOL CARDbStopTxPacket(PVOID pDeviceHandler, CARD_PKT_TYPE ePktType); +BOOL CARDbStartTxPacket(PVOID pDeviceHandler, CARD_PKT_TYPE ePktType); +BOOL CARDbSetBeaconPeriod(PVOID pDeviceHandler, WORD wBeaconInterval); +BOOL CARDbSetBSSID(PVOID pDeviceHandler, PBYTE pbyBSSID, CARD_OP_MODE eOPMode); + +BOOL +CARDbPowerDown( + PVOID pDeviceHandler + ); + +BOOL CARDbSetTxDataRate( + PVOID pDeviceHandler, + WORD wDataRate + ); + + +BOOL CARDbRemoveKey (PVOID pDeviceHandler, PBYTE pbyBSSID); + +BOOL +CARDbAdd_PMKID_Candidate ( + IN PVOID pDeviceHandler, + IN PBYTE pbyBSSID, + IN BOOL bRSNCapExist, + IN WORD wRSNCap + ); + +PVOID +CARDpGetCurrentAddress ( + IN PVOID pDeviceHandler + ); + + +VOID CARDvInitChannelTable(PVOID pDeviceHandler); +BYTE CARDbyGetChannelMapping(PVOID pDeviceHandler, BYTE byChannelNumber, CARD_PHY_TYPE ePhyType); + +BOOL +CARDbStartMeasure ( + IN PVOID pDeviceHandler, + IN PVOID pvMeasureEIDs, + IN UINT uNumOfMeasureEIDs + ); + +BOOL +CARDbChannelSwitch ( + IN PVOID pDeviceHandler, + IN BYTE byMode, + IN BYTE byNewChannel, + IN BYTE byCount + ); + +BOOL +CARDbSetQuiet ( + IN PVOID pDeviceHandler, + IN BOOL bResetQuiet, + IN BYTE byQuietCount, + IN BYTE byQuietPeriod, + IN WORD wQuietDuration, + IN WORD wQuietOffset + ); + +BOOL +CARDbStartQuiet ( + IN PVOID pDeviceHandler + ); + +VOID +CARDvSetCountryInfo ( + IN PVOID pDeviceHandler, + IN CARD_PHY_TYPE ePHYType, + IN PVOID pIE + ); + +VOID +CARDvSetPowerConstraint ( + IN PVOID pDeviceHandler, + IN BYTE byChannel, + IN I8 byPower + ); + +VOID +CARDvGetPowerCapability ( + IN PVOID pDeviceHandler, + OUT PBYTE pbyMinPower, + OUT PBYTE pbyMaxPower + ); + +BYTE +CARDbySetSupportChannels ( + IN PVOID pDeviceHandler, + IN OUT PBYTE pbyIEs + ); + +I8 +CARDbyGetTransmitPower ( + IN PVOID pDeviceHandler + ); + +BOOL +CARDbChannelGetList ( + IN UINT uCountryCodeIdx, + OUT PBYTE pbyChannelTable + ); + +VOID +CARDvSetCountryIE( + IN PVOID pDeviceHandler, + IN PVOID pIE + ); + +BOOL +CARDbGetChannelMapInfo( + IN PVOID pDeviceHandler, + IN UINT uChannelIndex, + OUT PBYTE pbyChannelNumber, + OUT PBYTE pbyMap + ); + +VOID +CARDvSetChannelMapInfo( + IN PVOID pDeviceHandler, + IN UINT uChannelIndex, + IN BYTE byMap + ); + +VOID +CARDvClearChannelMapInfo( + IN PVOID pDeviceHandler + ); + +BYTE +CARDbyAutoChannelSelect( + IN PVOID pDeviceHandler, + CARD_PHY_TYPE ePHYType + ); + +BYTE CARDbyGetChannelNumber(PVOID pDeviceHandler, BYTE byChannelIndex); + +#ifdef __cplusplus +} /* End of extern "C" { */ +#endif /* __cplusplus */ + + +#endif // __CARD_H__ + + + diff --git a/drivers/staging/vt6655/country.h b/drivers/staging/vt6655/country.h new file mode 100644 index 000000000000..65d1e52916ce --- /dev/null +++ b/drivers/staging/vt6655/country.h @@ -0,0 +1,192 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * File: country.h + * + * Purpose: Country Code information + * + * Author: Lucas Lin + * + * Date: Dec 23, 2004 + * + */ + +#ifndef __COUNTRY_H__ +#define __COUNTRY_H__ + +#if !defined(__TTYPE_H__) +#include "ttype.h" +#endif + + +/*--------------------- Export Definitions -------------------------*/ +/************************************************************************ + * The definition here should be complied with the INF country order + * Please check with VNWL.inf/VNWL64.inf/VNWL*.inf + ************************************************************************/ +typedef enum _COUNTRY_CODE { + CCODE_FCC = 0, + CCODE_TELEC, + CCODE_ETSI, + CCODE_RESV3, + CCODE_RESV4, + CCODE_RESV5, + CCODE_RESV6, + CCODE_RESV7, + CCODE_RESV8, + CCODE_RESV9, + CCODE_RESVa, + CCODE_RESVb, + CCODE_RESVc, + CCODE_RESVd, + CCODE_RESVe, + CCODE_ALLBAND, + CCODE_ALBANIA, + CCODE_ALGERIA, + CCODE_ARGENTINA, + CCODE_ARMENIA, + CCODE_AUSTRALIA, + CCODE_AUSTRIA, + CCODE_AZERBAIJAN, + CCODE_BAHRAIN, + CCODE_BELARUS, + CCODE_BELGIUM, + CCODE_BELIZE, + CCODE_BOLIVIA, + CCODE_BRAZIL, + CCODE_BRUNEI_DARUSSALAM, + CCODE_BULGARIA, + CCODE_CANADA, + CCODE_CHILE, + CCODE_CHINA, + CCODE_COLOMBIA, + CCODE_COSTA_RICA, + CCODE_CROATIA, + CCODE_CYPRUS, + CCODE_CZECH, + CCODE_DENMARK, + CCODE_DOMINICAN_REPUBLIC, + CCODE_ECUADOR, + CCODE_EGYPT, + CCODE_EL_SALVADOR, + CCODE_ESTONIA, + CCODE_FINLAND, + CCODE_FRANCE, + CCODE_GERMANY, + CCODE_GREECE, + CCODE_GEORGIA, + CCODE_GUATEMALA, + CCODE_HONDURAS, + CCODE_HONG_KONG, + CCODE_HUNGARY, + CCODE_ICELAND, + CCODE_INDIA, + CCODE_INDONESIA, + CCODE_IRAN, + CCODE_IRELAND, + CCODE_ITALY, + CCODE_ISRAEL, + CCODE_JAPAN, + CCODE_JORDAN, + CCODE_KAZAKHSTAN, + CCODE_KUWAIT, + CCODE_LATVIA, + CCODE_LEBANON, + CCODE_LEICHTENSTEIN, + CCODE_LITHUANIA, + CCODE_LUXEMBURG, + CCODE_MACAU, + CCODE_MACEDONIA, + CCODE_MALTA, + CCODE_MALAYSIA, + CCODE_MEXICO, + CCODE_MONACO, + CCODE_MOROCCO, + CCODE_NETHERLANDS, + CCODE_NEW_ZEALAND, + CCODE_NORTH_KOREA, + CCODE_NORWAY, + CCODE_OMAN, + CCODE_PAKISTAN, + CCODE_PANAMA, + CCODE_PERU, + CCODE_PHILIPPINES, + CCODE_POLAND, + CCODE_PORTUGAL, + CCODE_PUERTO_RICO, + CCODE_QATAR, + CCODE_ROMANIA, + CCODE_RUSSIA, + CCODE_SAUDI_ARABIA, + CCODE_SINGAPORE, + CCODE_SLOVAKIA, + CCODE_SLOVENIA, + CCODE_SOUTH_AFRICA, + CCODE_SOUTH_KOREA, + CCODE_SPAIN, + CCODE_SWEDEN, + CCODE_SWITZERLAND, + CCODE_SYRIA, + CCODE_TAIWAN, + CCODE_THAILAND, + CCODE_TRINIDAD_TOBAGO, + CCODE_TUNISIA, + CCODE_TURKEY, + CCODE_UK, + CCODE_UKRAINE, + CCODE_UNITED_ARAB_EMIRATES, + CCODE_UNITED_STATES, + CCODE_URUGUAY, + CCODE_UZBEKISTAN, + CCODE_VENEZUELA, + CCODE_VIETNAM, + CCODE_YEMEN, + CCODE_ZIMBABWE, + CCODE_JAPAN_W52_W53, + CCODE_MAX +} COUNTRY_CODE; + +typedef struct tagSCountryTable +{ + BYTE byChannelCountryCode; /* The country code */ + CHAR chCountryCode[2]; + BYTE bChannelIdxList[CB_MAX_CHANNEL]; /* Available channels Index */ + BYTE byPower[CB_MAX_CHANNEL]; +} SCountryTable, DEF* PSCountryTable; + +/*--------------------- Export Classes ----------------------------*/ + +/*--------------------- Export Variables --------------------------*/ +extern SCountryTable ChannelRuleTab[CCODE_MAX+1]; + +/*--------------------- Export Functions --------------------------*/ +#ifdef __cplusplus +extern "C" { /* Assume C declarations for C++ */ +#endif /* __cplusplus */ + + +#ifdef __cplusplus +} /* End of extern "C" { */ +#endif /* __cplusplus */ + + +/************************************************************************ + * Function prototype + ************************************************************************/ +#endif /* __COUNTRY_H__ */ diff --git a/drivers/staging/vt6655/datarate.c b/drivers/staging/vt6655/datarate.c new file mode 100644 index 000000000000..f58f9636be2d --- /dev/null +++ b/drivers/staging/vt6655/datarate.c @@ -0,0 +1,455 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * File: datarate.c + * + * Purpose: Handles the auto fallback & data rates functions + * + * Author: Lyndon Chen + * + * Date: July 17, 2002 + * + * Functions: + * RATEvParseMaxRate - Parsing the highest basic & support rate in rate field of frame + * RATEvTxRateFallBack - Rate fallback Algorithm Implementaion + * RATEuSetIE- Set rate IE field. + * + * Revision History: + * + */ + +#if !defined(__TTYPE_H__) +#include "ttype.h" +#endif +#if !defined(__TMACRO_H__) +#include "tmacro.h" +#endif +#if !defined(__MAC_H__) +#include "mac.h" +#endif +#if !defined(__80211MGR_H__) +#include "80211mgr.h" +#endif +#if !defined(__BSSDB_H__) +#include "bssdb.h" +#endif +#if !defined(__DATARATE_H__) +#include "datarate.h" +#endif +#if !defined(__CARD_H__) +#include "card.h" +#endif +#if !defined(__BASEBAND_H__) +#include "baseband.h" +#endif +#if !defined(__SROM_H__) +#include "srom.h" +#endif + +/*--------------------- Static Definitions -------------------------*/ + + + + +/*--------------------- Static Classes ----------------------------*/ + + + extern WORD TxRate_iwconfig; //2008-5-8 by chester +/*--------------------- Static Variables --------------------------*/ +//static int msglevel =MSG_LEVEL_DEBUG; +static int msglevel =MSG_LEVEL_INFO; +const BYTE acbyIERate[MAX_RATE] = +{0x02, 0x04, 0x0B, 0x16, 0x0C, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C}; + +#define AUTORATE_TXOK_CNT 0x0400 +#define AUTORATE_TXFAIL_CNT 0x0064 +#define AUTORATE_TIMEOUT 10 + +/*--------------------- Static Functions --------------------------*/ + +VOID s_vResetCounter ( + IN PKnownNodeDB psNodeDBTable + ); + + + +VOID +s_vResetCounter ( + IN PKnownNodeDB psNodeDBTable + ) +{ + BYTE ii; + + // clear statistic counter for auto_rate + for(ii=0;ii<=MAX_RATE;ii++) { + psNodeDBTable->uTxOk[ii] = 0; + psNodeDBTable->uTxFail[ii] = 0; + } +} + +/*--------------------- Export Variables --------------------------*/ + + +/*--------------------- Export Functions --------------------------*/ + + +/*+ + * + * Description: + * Get RateIdx from the value in SuppRates IE or ExtSuppRates IE + * + * Parameters: + * In: + * BYTE - Rate value in SuppRates IE or ExtSuppRates IE + * Out: + * none + * + * Return Value: RateIdx + * +-*/ +BYTE +DATARATEbyGetRateIdx ( + IN BYTE byRate + ) +{ + BYTE ii; + + //Erase basicRate flag. + byRate = byRate & 0x7F;//0111 1111 + + for (ii = 0; ii < MAX_RATE; ii ++) { + if (acbyIERate[ii] == byRate) + return ii; + } + return 0; +} + + + +/*+ + * + * Routine Description: + * Rate fallback Algorithm Implementaion + * + * Parameters: + * In: + * pDevice - Pointer to the adapter + * psNodeDBTable - Pointer to Node Data Base + * Out: + * none + * + * Return Value: none + * +-*/ +#define AUTORATE_TXCNT_THRESHOLD 20 +#define AUTORATE_INC_THRESHOLD 30 + + + + +/*+ + * + * Description: + * Get RateIdx from the value in SuppRates IE or ExtSuppRates IE + * + * Parameters: + * In: + * BYTE - Rate value in SuppRates IE or ExtSuppRates IE + * Out: + * none + * + * Return Value: RateIdx + * +-*/ +WORD +wGetRateIdx( + IN BYTE byRate + ) +{ + WORD ii; + + //Erase basicRate flag. + byRate = byRate & 0x7F;//0111 1111 + + for (ii = 0; ii < MAX_RATE; ii ++) { + if (acbyIERate[ii] == byRate) + return ii; + } + return 0; +} + +/*+ + * + * Description: + * Parsing the highest basic & support rate in rate field of frame. + * + * Parameters: + * In: + * pDevice - Pointer to the adapter + * pItemRates - Pointer to Rate field defined in 802.11 spec. + * pItemExtRates - Pointer to Extended Rate field defined in 802.11 spec. + * Out: + * pwMaxBasicRate - Maximum Basic Rate + * pwMaxSuppRate - Maximum Supported Rate + * pbyTopCCKRate - Maximum Basic Rate in CCK mode + * pbyTopOFDMRate - Maximum Basic Rate in OFDM mode + * + * Return Value: none + * +-*/ +VOID +RATEvParseMaxRate ( + IN PVOID pDeviceHandler, + IN PWLAN_IE_SUPP_RATES pItemRates, + IN PWLAN_IE_SUPP_RATES pItemExtRates, + IN BOOL bUpdateBasicRate, + OUT PWORD pwMaxBasicRate, + OUT PWORD pwMaxSuppRate, + OUT PWORD pwSuppRate, + OUT PBYTE pbyTopCCKRate, + OUT PBYTE pbyTopOFDMRate + ) +{ +PSDevice pDevice = (PSDevice) pDeviceHandler; +UINT ii; +BYTE byHighSuppRate = 0; +BYTE byRate = 0; +WORD wOldBasicRate = pDevice->wBasicRate; +UINT uRateLen; + + + if (pItemRates == NULL) + return; + + *pwSuppRate = 0; + uRateLen = pItemRates->len; + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ParseMaxRate Len: %d\n", uRateLen); + if (pDevice->eCurrentPHYType != PHY_TYPE_11B) { + if (uRateLen > WLAN_RATES_MAXLEN) + uRateLen = WLAN_RATES_MAXLEN; + } else { + if (uRateLen > WLAN_RATES_MAXLEN_11B) + uRateLen = WLAN_RATES_MAXLEN_11B; + } + + for (ii = 0; ii < uRateLen; ii++) { + byRate = (BYTE)(pItemRates->abyRates[ii]); + if (WLAN_MGMT_IS_BASICRATE(byRate) && + (bUpdateBasicRate == TRUE)) { + // Add to basic rate set, update pDevice->byTopCCKBasicRate and pDevice->byTopOFDMBasicRate + CARDbAddBasicRate((PVOID)pDevice, wGetRateIdx(byRate)); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ParseMaxRate AddBasicRate: %d\n", wGetRateIdx(byRate)); + } + byRate = (BYTE)(pItemRates->abyRates[ii]&0x7F); + if (byHighSuppRate == 0) + byHighSuppRate = byRate; + if (byRate > byHighSuppRate) + byHighSuppRate = byRate; + *pwSuppRate |= (1<byElementID == WLAN_EID_EXTSUPP_RATES) && + (pDevice->eCurrentPHYType != PHY_TYPE_11B)) { + + UINT uExtRateLen = pItemExtRates->len; + + if (uExtRateLen > WLAN_RATES_MAXLEN) + uExtRateLen = WLAN_RATES_MAXLEN; + + for (ii = 0; ii < uExtRateLen ; ii++) { + byRate = (BYTE)(pItemExtRates->abyRates[ii]); + // select highest basic rate + if (WLAN_MGMT_IS_BASICRATE(pItemExtRates->abyRates[ii])) { + // Add to basic rate set, update pDevice->byTopCCKBasicRate and pDevice->byTopOFDMBasicRate + CARDbAddBasicRate((PVOID)pDevice, wGetRateIdx(byRate)); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ParseMaxRate AddBasicRate: %d\n", wGetRateIdx(byRate)); + } + byRate = (BYTE)(pItemExtRates->abyRates[ii]&0x7F); + if (byHighSuppRate == 0) + byHighSuppRate = byRate; + if (byRate > byHighSuppRate) + byHighSuppRate = byRate; + *pwSuppRate |= (1<byPacketType == PK_TYPE_11GB) && CARDbIsOFDMinBasicRate((PVOID)pDevice)) { + pDevice->byPacketType = PK_TYPE_11GA; + } + + *pbyTopCCKRate = pDevice->byTopCCKBasicRate; + *pbyTopOFDMRate = pDevice->byTopOFDMBasicRate; + *pwMaxSuppRate = wGetRateIdx(byHighSuppRate); + if ((pDevice->byPacketType==PK_TYPE_11B) || (pDevice->byPacketType==PK_TYPE_11GB)) + *pwMaxBasicRate = pDevice->byTopCCKBasicRate; + else + *pwMaxBasicRate = pDevice->byTopOFDMBasicRate; + if (wOldBasicRate != pDevice->wBasicRate) + CARDvSetRSPINF((PVOID)pDevice, pDevice->eCurrentPHYType); + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Exit ParseMaxRate\n"); +} + + +/*+ + * + * Routine Description: + * Rate fallback Algorithm Implementaion + * + * Parameters: + * In: + * pDevice - Pointer to the adapter + * psNodeDBTable - Pointer to Node Data Base + * Out: + * none + * + * Return Value: none + * +-*/ +#define AUTORATE_TXCNT_THRESHOLD 20 +#define AUTORATE_INC_THRESHOLD 30 + +VOID +RATEvTxRateFallBack ( + IN PVOID pDeviceHandler, + IN PKnownNodeDB psNodeDBTable + ) +{ +PSDevice pDevice = (PSDevice) pDeviceHandler; +WORD wIdxDownRate = 0; +UINT ii; +//DWORD dwRateTable[MAX_RATE] = {1, 2, 5, 11, 6, 9, 12, 18, 24, 36, 48, 54}; +BOOL bAutoRate[MAX_RATE] = {TRUE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE,TRUE,TRUE,TRUE,TRUE,TRUE}; +DWORD dwThroughputTbl[MAX_RATE] = {10, 20, 55, 110, 60, 90, 120, 180, 240, 360, 480, 540}; +DWORD dwThroughput = 0; +WORD wIdxUpRate = 0; +DWORD dwTxDiff = 0; + + if (pDevice->pMgmt->eScanState != WMAC_NO_SCANNING) { + // Don't do Fallback when scanning Channel + return; + } + + psNodeDBTable->uTimeCount ++; + + if (psNodeDBTable->uTxFail[MAX_RATE] > psNodeDBTable->uTxOk[MAX_RATE]) + dwTxDiff = psNodeDBTable->uTxFail[MAX_RATE] - psNodeDBTable->uTxOk[MAX_RATE]; + + if ((psNodeDBTable->uTxOk[MAX_RATE] < AUTORATE_TXOK_CNT) && + (dwTxDiff < AUTORATE_TXFAIL_CNT) && + (psNodeDBTable->uTimeCount < AUTORATE_TIMEOUT)) { + return; + } + + if (psNodeDBTable->uTimeCount >= AUTORATE_TIMEOUT) { + psNodeDBTable->uTimeCount = 0; + } + + + for(ii=0;iiwSuppRate & (0x0001<wTxDataRate;ii++) { + if ( (psNodeDBTable->uTxOk[ii] != 0) || + (psNodeDBTable->uTxFail[ii] != 0) ) { + dwThroughputTbl[ii] *= psNodeDBTable->uTxOk[ii]; + if (ii < RATE_11M) { + psNodeDBTable->uTxFail[ii] *= 4; + } + dwThroughputTbl[ii] /= (psNodeDBTable->uTxOk[ii] + psNodeDBTable->uTxFail[ii]); + } +// DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Rate %d,Ok: %d, Fail:%d, Throughput:%d\n", +// ii, psNodeDBTable->uTxOk[ii], psNodeDBTable->uTxFail[ii], dwThroughputTbl[ii]); + } + dwThroughput = dwThroughputTbl[psNodeDBTable->wTxDataRate]; + + wIdxDownRate = psNodeDBTable->wTxDataRate; + for(ii = psNodeDBTable->wTxDataRate; ii > 0;) { + ii--; + if ( (dwThroughputTbl[ii] > dwThroughput) && + (bAutoRate[ii]==TRUE) ) { + dwThroughput = dwThroughputTbl[ii]; + wIdxDownRate = (WORD) ii; + } + } + psNodeDBTable->wTxDataRate = wIdxDownRate; + if (psNodeDBTable->uTxOk[MAX_RATE]) { + if (psNodeDBTable->uTxOk[MAX_RATE] > + (psNodeDBTable->uTxFail[MAX_RATE] * 4) ) { + psNodeDBTable->wTxDataRate = wIdxUpRate; + } + }else { // adhoc, if uTxOk =0 & uTxFail = 0 + if (psNodeDBTable->uTxFail[MAX_RATE] == 0) + psNodeDBTable->wTxDataRate = wIdxUpRate; + } +//2008-5-8 by chester +TxRate_iwconfig=psNodeDBTable->wTxDataRate; + s_vResetCounter(psNodeDBTable); +// DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Rate: %d, U:%d, D:%d\n", psNodeDBTable->wTxDataRate, wIdxUpRate, wIdxDownRate); + + return; + +} + +/*+ + * + * Description: + * This routine is used to assemble available Rate IE. + * + * Parameters: + * In: + * pDevice + * Out: + * + * Return Value: None + * +-*/ +BYTE +RATEuSetIE ( + IN PWLAN_IE_SUPP_RATES pSrcRates, + IN PWLAN_IE_SUPP_RATES pDstRates, + IN UINT uRateLen + ) +{ + UINT ii, uu, uRateCnt = 0; + + if ((pSrcRates == NULL) || (pDstRates == NULL)) + return 0; + + if (pSrcRates->len == 0) + return 0; + + for (ii = 0; ii < uRateLen; ii++) { + for (uu = 0; uu < pSrcRates->len; uu++) { + if ((pSrcRates->abyRates[uu] & 0x7F) == acbyIERate[ii]) { + pDstRates->abyRates[uRateCnt ++] = pSrcRates->abyRates[uu]; + break; + } + } + } + return (BYTE)uRateCnt; +} + diff --git a/drivers/staging/vt6655/datarate.h b/drivers/staging/vt6655/datarate.h new file mode 100644 index 000000000000..5096f3df4993 --- /dev/null +++ b/drivers/staging/vt6655/datarate.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * File: datarate.h + * + * Purpose: Handles the auto fallback & data rates functions + * + * Author: Lyndon Chen + * + * Date: July 16, 2002 + * + */ +#ifndef __DATARATE_H__ +#define __DATARATE_H__ + +/*--------------------- Export Definitions -------------------------*/ + +#define FALLBACK_PKT_COLLECT_TR_H 50 // pkts +#define FALLBACK_PKT_COLLECT_TR_L 10 // pkts +#define FALLBACK_POLL_SECOND 5 // 5 sec +#define FALLBACK_RECOVER_SECOND 30 // 30 sec +#define FALLBACK_THRESHOLD 15 // percent +#define UPGRADE_THRESHOLD 5 // percent +#define UPGRADE_CNT_THRD 3 // times +#define RETRY_TIMES_THRD_H 2 // times +#define RETRY_TIMES_THRD_L 1 // times + + +/*--------------------- Export Classes ----------------------------*/ + +/*--------------------- Export Variables --------------------------*/ + + +/*--------------------- Export Types ------------------------------*/ + + +/*--------------------- Export Functions --------------------------*/ + + + +VOID +RATEvParseMaxRate( + IN PVOID pDeviceHandler, + IN PWLAN_IE_SUPP_RATES pItemRates, + IN PWLAN_IE_SUPP_RATES pItemExtRates, + IN BOOL bUpdateBasicRate, + OUT PWORD pwMaxBasicRate, + OUT PWORD pwMaxSuppRate, + OUT PWORD pwSuppRate, + OUT PBYTE pbyTopCCKRate, + OUT PBYTE pbyTopOFDMRate + ); + +VOID +RATEvTxRateFallBack( + IN PVOID pDeviceHandler, + IN PKnownNodeDB psNodeDBTable + ); + +BYTE +RATEuSetIE( + IN PWLAN_IE_SUPP_RATES pSrcRates, + IN PWLAN_IE_SUPP_RATES pDstRates, + IN UINT uRateLen + ); + +WORD +wGetRateIdx( + IN BYTE byRate + ); + + +BYTE +DATARATEbyGetRateIdx( + IN BYTE byRate + ); + + +#endif //__DATARATE_H__ diff --git a/drivers/staging/vt6655/desc.h b/drivers/staging/vt6655/desc.h new file mode 100644 index 000000000000..c0fc1d3b0a2e --- /dev/null +++ b/drivers/staging/vt6655/desc.h @@ -0,0 +1,697 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * File: desc.h + * + * Purpose:The header file of descriptor + * + * Revision History: + * + * Author: Tevin Chen + * + * Date: May 21, 1996 + * + */ + + +#ifndef __DESC_H__ +#define __DESC_H__ + +#include +#include + +#if !defined(__TTYPE_H__) +#include "ttype.h" +#endif +#if !defined(__TETHER_H__) +#include "tether.h" +#endif +// #ifdef PRIVATE_OBJ +//#if !defined(__DEVICE_MODULE_H) +//#include "device_module.h" +//#endif + + + + +/*--------------------- Export Definitions -------------------------*/ + +#define B_OWNED_BY_CHIP 1 // +#define B_OWNED_BY_HOST 0 // + +// +// Bits in the RSR register +// +#define RSR_ADDRBROAD 0x80 // 1000 0000 +#define RSR_ADDRMULTI 0x40 // 0100 0000 +#define RSR_ADDRUNI 0x00 // 0000 0000 +#define RSR_IVLDTYP 0x20 // 0010 0000 , invalid packet type +#define RSR_IVLDLEN 0x10 // 0001 0000 , invalid len (> 2312 byte) +#define RSR_BSSIDOK 0x08 // 0000 1000 +#define RSR_CRCOK 0x04 // 0000 0100 +#define RSR_BCNSSIDOK 0x02 // 0000 0010 +#define RSR_ADDROK 0x01 // 0000 0001 + +// +// Bits in the new RSR register +// +#define NEWRSR_DECRYPTOK 0x10 // 0001 0000 +#define NEWRSR_CFPIND 0x08 // 0000 1000 +#define NEWRSR_HWUTSF 0x04 // 0000 0100 +#define NEWRSR_BCNHITAID 0x02 // 0000 0010 +#define NEWRSR_BCNHITAID0 0x01 // 0000 0001 + +// +// Bits in the TSR0 register +// +#define TSR0_PWRSTS1_2 0xC0 // 1100 0000 +#define TSR0_PWRSTS7 0x20 // 0010 0000 +#define TSR0_NCR 0x1F // 0001 1111 + +// +// Bits in the TSR1 register +// +#define TSR1_TERR 0x80 // 1000 0000 +#define TSR1_PWRSTS4_6 0x70 // 0111 0000 +#define TSR1_RETRYTMO 0x08 // 0000 1000 +#define TSR1_TMO 0x04 // 0000 0100 +#define TSR1_PWRSTS3 0x02 // 0000 0010 +#define ACK_DATA 0x01 // 0000 0000 + +// +// Bits in the TCR register +// +#define EDMSDU 0x04 // 0000 0100 end of sdu +#define TCR_EDP 0x02 // 0000 0010 end of packet +#define TCR_STP 0x01 // 0000 0001 start of packet + +// max transmit or receive buffer size +#define CB_MAX_BUF_SIZE 2900U // max buffer size + // NOTE: must be multiple of 4 +#define CB_MAX_TX_BUF_SIZE CB_MAX_BUF_SIZE // max Tx buffer size +#define CB_MAX_RX_BUF_SIZE_NORMAL CB_MAX_BUF_SIZE // max Rx buffer size when not use Multi-RD + +#define CB_BEACON_BUF_SIZE 512U // default beacon buffer size + +#define CB_MAX_RX_DESC 128 // max # of descriptor +#define CB_MIN_RX_DESC 16 // min # of rx descriptor +#define CB_MAX_TX_DESC 64 // max # of descriptor +#define CB_MIN_TX_DESC 16 // min # of tx descriptor + +#define CB_MAX_RECEIVED_PACKETS 16 // max # of received packets at one time + // limit our receive routine to indicating + // this many at a time for 2 reasons: + // 1. driver flow control to protocol layer + // 2. limit the time used in ISR routine + +#define CB_EXTRA_RD_NUM 32 // default # of Extra RD +#define CB_RD_NUM 32 // default # of RD +#define CB_TD_NUM 32 // default # of TD + + +// max number of physical segments +// in a single NDIS packet. Above this threshold, the packet +// is copied into a single physically contiguous buffer +#define CB_MAX_SEGMENT 4 + +#define CB_MIN_MAP_REG_NUM 4 +#define CB_MAX_MAP_REG_NUM CB_MAX_TX_DESC + +#define CB_PROTOCOL_RESERVED_SECTION 16 + + +// if retrys excess 15 times , tx will abort, and +// if tx fifo underflow, tx will fail +// we should try to resend it +#define CB_MAX_TX_ABORT_RETRY 3 + +#ifdef __BIG_ENDIAN + +// WMAC definition FIFO Control +#define FIFOCTL_AUTO_FB_1 0x0010 // 0001 0000 0000 0000 +#define FIFOCTL_AUTO_FB_0 0x0008 // 0000 1000 0000 0000 +#define FIFOCTL_GRPACK 0x0004 // 0000 0100 0000 0000 +#define FIFOCTL_11GA 0x0003 // 0000 0011 0000 0000 +#define FIFOCTL_11GB 0x0002 // 0000 0010 0000 0000 +#define FIFOCTL_11B 0x0001 // 0000 0001 0000 0000 +#define FIFOCTL_11A 0x0000 // 0000 0000 0000 0000 +#define FIFOCTL_RTS 0x8000 // 0000 0000 1000 0000 +#define FIFOCTL_ISDMA0 0x4000 // 0000 0000 0100 0000 +#define FIFOCTL_GENINT 0x2000 // 0000 0000 0010 0000 +#define FIFOCTL_TMOEN 0x1000 // 0000 0000 0001 0000 +#define FIFOCTL_LRETRY 0x0800 // 0000 0000 0000 1000 +#define FIFOCTL_CRCDIS 0x0400 // 0000 0000 0000 0100 +#define FIFOCTL_NEEDACK 0x0200 // 0000 0000 0000 0010 +#define FIFOCTL_LHEAD 0x0100 // 0000 0000 0000 0001 + +//WMAC definition Frag Control +#define FRAGCTL_AES 0x0003 // 0000 0011 0000 0000 +#define FRAGCTL_TKIP 0x0002 // 0000 0010 0000 0000 +#define FRAGCTL_LEGACY 0x0001 // 0000 0001 0000 0000 +#define FRAGCTL_NONENCRYPT 0x0000 // 0000 0000 0000 0000 +//#define FRAGCTL_AC3 0x0C00 // 0000 0000 0000 1100 +//#define FRAGCTL_AC2 0x0800 // 0000 0000 0000 1000 +//#define FRAGCTL_AC1 0x0400 // 0000 0000 0000 0100 +//#define FRAGCTL_AC0 0x0000 // 0000 0000 0000 0000 +#define FRAGCTL_ENDFRAG 0x0300 // 0000 0000 0000 0011 +#define FRAGCTL_MIDFRAG 0x0200 // 0000 0000 0000 0010 +#define FRAGCTL_STAFRAG 0x0100 // 0000 0000 0000 0001 +#define FRAGCTL_NONFRAG 0x0000 // 0000 0000 0000 0000 + +#else + +#define FIFOCTL_AUTO_FB_1 0x1000 // 0001 0000 0000 0000 +#define FIFOCTL_AUTO_FB_0 0x0800 // 0000 1000 0000 0000 +#define FIFOCTL_GRPACK 0x0400 // 0000 0100 0000 0000 +#define FIFOCTL_11GA 0x0300 // 0000 0011 0000 0000 +#define FIFOCTL_11GB 0x0200 // 0000 0010 0000 0000 +#define FIFOCTL_11B 0x0100 // 0000 0001 0000 0000 +#define FIFOCTL_11A 0x0000 // 0000 0000 0000 0000 +#define FIFOCTL_RTS 0x0080 // 0000 0000 1000 0000 +#define FIFOCTL_ISDMA0 0x0040 // 0000 0000 0100 0000 +#define FIFOCTL_GENINT 0x0020 // 0000 0000 0010 0000 +#define FIFOCTL_TMOEN 0x0010 // 0000 0000 0001 0000 +#define FIFOCTL_LRETRY 0x0008 // 0000 0000 0000 1000 +#define FIFOCTL_CRCDIS 0x0004 // 0000 0000 0000 0100 +#define FIFOCTL_NEEDACK 0x0002 // 0000 0000 0000 0010 +#define FIFOCTL_LHEAD 0x0001 // 0000 0000 0000 0001 + +//WMAC definition Frag Control +#define FRAGCTL_AES 0x0300 // 0000 0011 0000 0000 +#define FRAGCTL_TKIP 0x0200 // 0000 0010 0000 0000 +#define FRAGCTL_LEGACY 0x0100 // 0000 0001 0000 0000 +#define FRAGCTL_NONENCRYPT 0x0000 // 0000 0000 0000 0000 +//#define FRAGCTL_AC3 0x000C // 0000 0000 0000 1100 +//#define FRAGCTL_AC2 0x0008 // 0000 0000 0000 1000 +//#define FRAGCTL_AC1 0x0004 // 0000 0000 0000 0100 +//#define FRAGCTL_AC0 0x0000 // 0000 0000 0000 0000 +#define FRAGCTL_ENDFRAG 0x0003 // 0000 0000 0000 0011 +#define FRAGCTL_MIDFRAG 0x0002 // 0000 0000 0000 0010 +#define FRAGCTL_STAFRAG 0x0001 // 0000 0000 0000 0001 +#define FRAGCTL_NONFRAG 0x0000 // 0000 0000 0000 0000 + +#endif // #ifdef __BIG_ENDIAN + +//#define TYPE_AC0DMA 0 +//#define TYPE_TXDMA0 1 +#define TYPE_TXDMA0 0 +#define TYPE_AC0DMA 1 +#define TYPE_ATIMDMA 2 +#define TYPE_SYNCDMA 3 +#define TYPE_MAXTD 2 + +#define TYPE_BEACONDMA 4 + +#define TYPE_RXDMA0 0 +#define TYPE_RXDMA1 1 +#define TYPE_MAXRD 2 + + + +// TD_INFO flags control bit +#define TD_FLAGS_NETIF_SKB 0x01 // check if need release skb +#define TD_FLAGS_PRIV_SKB 0x02 // check if called from private skb(hostap) +#define TD_FLAGS_PS_RETRY 0x04 // check if PS STA frame re-transmit +//#define TD_FLAGS_NETIF_SKB 0x04 + +/*--------------------- Export Types ------------------------------*/ + +// ref_sk_buff is used for mapping the skb structure between pre-built driver-obj & running kernel. +// Since different kernel version (2.4x) may change skb structure, i.e. pre-built driver-obj +// may link to older skb that leads error. + +typedef struct tagDEVICE_RD_INFO { + struct sk_buff* skb; +#ifdef PRIVATE_OBJ + ref_sk_buff ref_skb; +#endif + dma_addr_t skb_dma; + dma_addr_t curr_desc; +} DEVICE_RD_INFO, *PDEVICE_RD_INFO; + +/* +static inline PDEVICE_RD_INFO alloc_rd_info(void) { + PDEVICE_RD_INFO ptr; + if ((ptr = kmalloc(sizeof(DEVICE_RD_INFO), GFP_ATOMIC)) == NULL) + return NULL; + else { + memset(ptr,0,sizeof(DEVICE_RD_INFO)); + return ptr; + } +} +*/ + +/* +typedef struct tagRDES0 { + WORD wResCount; + WORD wf1Owner ; +// WORD f15Reserved : 15; +// WORD f1Owner : 1; +} __attribute__ ((__packed__)) +SRDES0; +*/ + +#ifdef __BIG_ENDIAN + +typedef struct tagRDES0 { + volatile WORD wResCount; + union { + volatile U16 f15Reserved; + struct { + volatile U8 f8Reserved1; + volatile U8 f1Owner:1; + volatile U8 f7Reserved:7; + } __attribute__ ((__packed__)); + } __attribute__ ((__packed__)); +} __attribute__ ((__packed__)) +SRDES0, *PSRDES0; + +#else + +typedef struct tagRDES0 { + WORD wResCount; + WORD f15Reserved : 15; + WORD f1Owner : 1; +} __attribute__ ((__packed__)) +SRDES0; + + +#endif + +typedef struct tagRDES1 { + WORD wReqCount; + WORD wReserved; +} __attribute__ ((__packed__)) +SRDES1; + +// +// Rx descriptor +// +typedef struct tagSRxDesc { + volatile SRDES0 m_rd0RD0; + volatile SRDES1 m_rd1RD1; + volatile U32 buff_addr; + volatile U32 next_desc; + struct tagSRxDesc *next;//4 bytes + volatile PDEVICE_RD_INFO pRDInfo;//4 bytes + volatile U32 Reserved[2];//8 bytes +} __attribute__ ((__packed__)) +SRxDesc, DEF* PSRxDesc; +typedef const SRxDesc DEF* PCSRxDesc; + +#ifdef __BIG_ENDIAN + +/* +typedef struct tagTDES0 { + volatile BYTE byTSR0; + volatile BYTE byTSR1; + volatile WORD wOwner_Txtime; +// volatile WORD f15Txtime : 15; +// volatile WORD f1Owner:1; +} __attribute__ ((__packed__)) +STDES0; +*/ + +typedef struct tagTDES0 { + volatile BYTE byTSR0; + volatile BYTE byTSR1; + union { + volatile U16 f15Txtime; + struct { + volatile U8 f8Reserved1; + volatile U8 f1Owner:1; + volatile U8 f7Reserved:7; + } __attribute__ ((__packed__)); + } __attribute__ ((__packed__)); +} __attribute__ ((__packed__)) +STDES0, PSTDES0; + +#else + +typedef struct tagTDES0 { + volatile BYTE byTSR0; + volatile BYTE byTSR1; + volatile WORD f15Txtime : 15; + volatile WORD f1Owner:1; +} __attribute__ ((__packed__)) +STDES0; + +#endif + + +typedef struct tagTDES1 { + volatile WORD wReqCount; + volatile BYTE byTCR; + volatile BYTE byReserved; +} __attribute__ ((__packed__)) +STDES1; + + +typedef struct tagDEVICE_TD_INFO{ + struct sk_buff* skb; + PBYTE buf; + dma_addr_t skb_dma; + dma_addr_t buf_dma; + dma_addr_t curr_desc; + DWORD dwReqCount; + DWORD dwHeaderLength; + BYTE byFlags; +} DEVICE_TD_INFO, *PDEVICE_TD_INFO; + +/* +static inline PDEVICE_TD_INFO alloc_td_info(void) { + PDEVICE_TD_INFO ptr; + if ((ptr = kmalloc(sizeof(DEVICE_TD_INFO),GFP_ATOMIC))==NULL) + return NULL; + else { + memset(ptr,0,sizeof(DEVICE_TD_INFO)); + return ptr; + } +} +*/ + +// +// transmit descriptor +// +typedef struct tagSTxDesc { + volatile STDES0 m_td0TD0; + volatile STDES1 m_td1TD1; + volatile U32 buff_addr; + volatile U32 next_desc; + struct tagSTxDesc* next; //4 bytes + volatile PDEVICE_TD_INFO pTDInfo;//4 bytes + volatile U32 Reserved[2];//8 bytes +} __attribute__ ((__packed__)) +STxDesc, DEF* PSTxDesc; +typedef const STxDesc DEF* PCSTxDesc; + + +typedef struct tagSTxSyncDesc { + volatile STDES0 m_td0TD0; + volatile STDES1 m_td1TD1; + volatile DWORD buff_addr; // pointer to logical buffer + volatile DWORD next_desc; // pointer to next logical descriptor + volatile WORD m_wFIFOCtl; + volatile WORD m_wTimeStamp; + struct tagSTxSyncDesc* next; //4 bytes + volatile PDEVICE_TD_INFO pTDInfo;//4 bytes + volatile DWORD m_dwReserved2; +} __attribute__ ((__packed__)) +STxSyncDesc, DEF* PSTxSyncDesc; +typedef const STxSyncDesc DEF* PCSTxSyncDesc; + + +// +// RsvTime buffer header +// +typedef struct tagSRrvTime_gRTS { + WORD wRTSTxRrvTime_ba; + WORD wRTSTxRrvTime_aa; + WORD wRTSTxRrvTime_bb; + WORD wReserved; + WORD wTxRrvTime_b; + WORD wTxRrvTime_a; +}__attribute__ ((__packed__)) +SRrvTime_gRTS, DEF* PSRrvTime_gRTS; +typedef const SRrvTime_gRTS DEF* PCSRrvTime_gRTS; + +typedef struct tagSRrvTime_gCTS { + WORD wCTSTxRrvTime_ba; + WORD wReserved; + WORD wTxRrvTime_b; + WORD wTxRrvTime_a; +}__attribute__ ((__packed__)) +SRrvTime_gCTS, DEF* PSRrvTime_gCTS; +typedef const SRrvTime_gCTS DEF* PCSRrvTime_gCTS; + +typedef struct tagSRrvTime_ab { + WORD wRTSTxRrvTime; + WORD wTxRrvTime; +}__attribute__ ((__packed__)) +SRrvTime_ab, DEF* PSRrvTime_ab; +typedef const SRrvTime_ab DEF* PCSRrvTime_ab; + +typedef struct tagSRrvTime_atim { + WORD wCTSTxRrvTime_ba; + WORD wTxRrvTime_a; +}__attribute__ ((__packed__)) +SRrvTime_atim, DEF* PSRrvTime_atim; +typedef const SRrvTime_atim DEF* PCSRrvTime_atim; + +// +// RTS buffer header +// +typedef struct tagSRTSData { + WORD wFrameControl; + WORD wDurationID; + BYTE abyRA[U_ETHER_ADDR_LEN]; + BYTE abyTA[U_ETHER_ADDR_LEN]; +}__attribute__ ((__packed__)) +SRTSData, DEF* PSRTSData; +typedef const SRTSData DEF* PCSRTSData; + +typedef struct tagSRTS_g { + BYTE bySignalField_b; + BYTE byServiceField_b; + WORD wTransmitLength_b; + BYTE bySignalField_a; + BYTE byServiceField_a; + WORD wTransmitLength_a; + WORD wDuration_ba; + WORD wDuration_aa; + WORD wDuration_bb; + WORD wReserved; + SRTSData Data; +}__attribute__ ((__packed__)) +SRTS_g, DEF* PSRTS_g; +typedef const SRTS_g DEF* PCSRTS_g; + + +typedef struct tagSRTS_g_FB { + BYTE bySignalField_b; + BYTE byServiceField_b; + WORD wTransmitLength_b; + BYTE bySignalField_a; + BYTE byServiceField_a; + WORD wTransmitLength_a; + WORD wDuration_ba; + WORD wDuration_aa; + WORD wDuration_bb; + WORD wReserved; + WORD wRTSDuration_ba_f0; + WORD wRTSDuration_aa_f0; + WORD wRTSDuration_ba_f1; + WORD wRTSDuration_aa_f1; + SRTSData Data; +}__attribute__ ((__packed__)) +SRTS_g_FB, DEF* PSRTS_g_FB; +typedef const SRTS_g_FB DEF* PCSRTS_g_FB; + + +typedef struct tagSRTS_ab { + BYTE bySignalField; + BYTE byServiceField; + WORD wTransmitLength; + WORD wDuration; + WORD wReserved; + SRTSData Data; +}__attribute__ ((__packed__)) +SRTS_ab, DEF* PSRTS_ab; +typedef const SRTS_ab DEF* PCSRTS_ab; + + +typedef struct tagSRTS_a_FB { + BYTE bySignalField; + BYTE byServiceField; + WORD wTransmitLength; + WORD wDuration; + WORD wReserved; + WORD wRTSDuration_f0; + WORD wRTSDuration_f1; + SRTSData Data; +}__attribute__ ((__packed__)) +SRTS_a_FB, DEF* PSRTS_a_FB; +typedef const SRTS_a_FB DEF* PCSRTS_a_FB; + + +// +// CTS buffer header +// +typedef struct tagSCTSData { + WORD wFrameControl; + WORD wDurationID; + BYTE abyRA[U_ETHER_ADDR_LEN]; + WORD wReserved; +}__attribute__ ((__packed__)) +SCTSData, DEF* PSCTSData; + +typedef struct tagSCTS { + BYTE bySignalField_b; + BYTE byServiceField_b; + WORD wTransmitLength_b; + WORD wDuration_ba; + WORD wReserved; + SCTSData Data; +}__attribute__ ((__packed__)) +SCTS, DEF* PSCTS; +typedef const SCTS DEF* PCSCTS; + +typedef struct tagSCTS_FB { + BYTE bySignalField_b; + BYTE byServiceField_b; + WORD wTransmitLength_b; + WORD wDuration_ba; + WORD wReserved; + WORD wCTSDuration_ba_f0; + WORD wCTSDuration_ba_f1; + SCTSData Data; +}__attribute__ ((__packed__)) +SCTS_FB, DEF* PSCTS_FB; +typedef const SCTS_FB DEF* PCSCTS_FB; + + +// +// Tx FIFO header +// +typedef struct tagSTxBufHead { + DWORD adwTxKey[4]; + WORD wFIFOCtl; + WORD wTimeStamp; + WORD wFragCtl; + BYTE byTxPower; + BYTE wReserved; +}__attribute__ ((__packed__)) +STxBufHead, DEF* PSTxBufHead; +typedef const STxBufHead DEF* PCSTxBufHead; + +typedef struct tagSTxShortBufHead { + WORD wFIFOCtl; + WORD wTimeStamp; +}__attribute__ ((__packed__)) +STxShortBufHead, DEF* PSTxShortBufHead; +typedef const STxShortBufHead DEF* PCSTxShortBufHead; + +// +// Tx data header +// +typedef struct tagSTxDataHead_g { + BYTE bySignalField_b; + BYTE byServiceField_b; + WORD wTransmitLength_b; + BYTE bySignalField_a; + BYTE byServiceField_a; + WORD wTransmitLength_a; + WORD wDuration_b; + WORD wDuration_a; + WORD wTimeStampOff_b; + WORD wTimeStampOff_a; +}__attribute__ ((__packed__)) +STxDataHead_g, DEF* PSTxDataHead_g; +typedef const STxDataHead_g DEF* PCSTxDataHead_g; + +typedef struct tagSTxDataHead_g_FB { + BYTE bySignalField_b; + BYTE byServiceField_b; + WORD wTransmitLength_b; + BYTE bySignalField_a; + BYTE byServiceField_a; + WORD wTransmitLength_a; + WORD wDuration_b; + WORD wDuration_a; + WORD wDuration_a_f0; + WORD wDuration_a_f1; + WORD wTimeStampOff_b; + WORD wTimeStampOff_a; +}__attribute__ ((__packed__)) +STxDataHead_g_FB, DEF* PSTxDataHead_g_FB; +typedef const STxDataHead_g_FB DEF* PCSTxDataHead_g_FB; + + +typedef struct tagSTxDataHead_ab { + BYTE bySignalField; + BYTE byServiceField; + WORD wTransmitLength; + WORD wDuration; + WORD wTimeStampOff; +}__attribute__ ((__packed__)) +STxDataHead_ab, DEF* PSTxDataHead_ab; +typedef const STxDataHead_ab DEF* PCSTxDataHead_ab; + + +typedef struct tagSTxDataHead_a_FB { + BYTE bySignalField; + BYTE byServiceField; + WORD wTransmitLength; + WORD wDuration; + WORD wTimeStampOff; + WORD wDuration_f0; + WORD wDuration_f1; +}__attribute__ ((__packed__)) +STxDataHead_a_FB, DEF* PSTxDataHead_a_FB; +typedef const STxDataHead_a_FB DEF* PCSTxDataHead_a_FB; + +// +// MICHDR data header +// +typedef struct tagSMICHDRHead { + DWORD adwHDR0[4]; + DWORD adwHDR1[4]; + DWORD adwHDR2[4]; +}__attribute__ ((__packed__)) +SMICHDRHead, DEF* PSMICHDRHead; +typedef const SMICHDRHead DEF* PCSMICHDRHead; + +typedef struct tagSBEACONCtl { + DWORD BufReady : 1; + DWORD TSF : 15; + DWORD BufLen : 11; + DWORD Reserved : 5; +}__attribute__ ((__packed__)) +SBEACONCtl; + + +typedef struct tagSSecretKey { + DWORD dwLowDword; + BYTE byHighByte; +}__attribute__ ((__packed__)) +SSecretKey; + +typedef struct tagSKeyEntry { + BYTE abyAddrHi[2]; + WORD wKCTL; + BYTE abyAddrLo[4]; + DWORD dwKey0[4]; + DWORD dwKey1[4]; + DWORD dwKey2[4]; + DWORD dwKey3[4]; + DWORD dwKey4[4]; +}__attribute__ ((__packed__)) +SKeyEntry; +/*--------------------- Export Macros ------------------------------*/ + +/*--------------------- Export Classes ----------------------------*/ + +/*--------------------- Export Variables --------------------------*/ + +/*--------------------- Export Functions --------------------------*/ + + + + +#endif // __DESC_H__ + diff --git a/drivers/staging/vt6655/device.h b/drivers/staging/vt6655/device.h new file mode 100644 index 000000000000..264d1bb2ff79 --- /dev/null +++ b/drivers/staging/vt6655/device.h @@ -0,0 +1,1063 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * File: device.h + * + * Purpose: MAC Data structure + * + * Author: Tevin Chen + * + * Date: Mar 17, 1997 + * + */ + +#ifndef __DEVICE_H__ +#define __DEVICE_H__ + +#ifdef MODULE +#ifdef MODVERSIONS +#include +#endif /* MODVERSIONS */ +#include +#endif /* MODULE */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include +#ifdef SIOCETHTOOL +#define DEVICE_ETHTOOL_IOCTL_SUPPORT +#include +#else +#undef DEVICE_ETHTOOL_IOCTL_SUPPORT +#endif +/* Include Wireless Extension definition and check version - Jean II */ +#include +#if WIRELESS_EXT > 12 +#include // New driver API +#endif /* WIRELESS_EXT > 12 */ + +//2008-0409-07, by Einsn Liu +#if WIRELESS_EXT > 17 +#ifndef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT +#define WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT +#endif +#endif +//2008-4-14 by chester for led issue +//#define FOR_LED_ON_NOTEBOOK +// + + + +// device specific +// +#if !defined(_KCOMPAT_H) +#include "kcompat.h" +#endif + +#if !defined(__DEVICE_CONFIG_H) +#include "device_cfg.h" +#endif + +#if !defined(__TTYPE_H__) +#include "ttype.h" +#endif +#if !defined(__80211HDR_H__) +#include "80211hdr.h" +#endif +#if !defined(__TETHER_H__) +#include "tether.h" +#endif +#if !defined(__WMGR_H__) +#include "wmgr.h" +#endif +#if !defined(__WCMD_H__) +#include "wcmd.h" +#endif +#if !defined(__MIB_H__) +#include "mib.h" +#endif +#if !defined(__SROM_H__) +#include "srom.h" +#endif +#if !defined(__RC4_H__) +#include "rc4.h" +#endif +#if !defined(__TPCI_H__) +#include "tpci.h" +#endif +#if !defined(__DESC_H__) +#include "desc.h" +#endif + +#if !defined(__KEY_H__) +#include "key.h" +#endif + +#if !defined(__MAC_H__) +#include "mac.h" +#endif + +//PLICE_DEBUG-> +//#define THREAD + +//#define TASK_LET +//PLICE_DEBUG<- + +// #ifdef PRIVATE_OBJ +//#if !defined(__DEVICE_MODULE_H) +//#include "device_module.h" +//#endif + + +/*--------------------- Export Definitions -------------------------*/ + +#define MAC_MAX_CONTEXT_REG (256+128) + +#define MAX_MULTICAST_ADDRESS_NUM 32 +#define MULTICAST_ADDRESS_LIST_SIZE (MAX_MULTICAST_ADDRESS_NUM * U_ETHER_ADDR_LEN) + + +//#define OP_MODE_INFRASTRUCTURE 0 +//#define OP_MODE_ADHOC 1 +//#define OP_MODE_AP 2 + +#define DUPLICATE_RX_CACHE_LENGTH 5 + +#define NUM_KEY_ENTRY 11 + +#define TX_WEP_NONE 0 +#define TX_WEP_OTF 1 +#define TX_WEP_SW 2 +#define TX_WEP_SWOTP 3 +#define TX_WEP_OTPSW 4 +#define TX_WEP_SW232 5 + +#define KEYSEL_WEP40 0 +#define KEYSEL_WEP104 1 +#define KEYSEL_TKIP 2 +#define KEYSEL_CCMP 3 + + + +#define AUTO_FB_NONE 0 +#define AUTO_FB_0 1 +#define AUTO_FB_1 2 + +#define FB_RATE0 0 +#define FB_RATE1 1 + +// Antenna Mode +#define ANT_A 0 +#define ANT_B 1 +#define ANT_DIVERSITY 2 +#define ANT_RXD_TXA 3 +#define ANT_RXD_TXB 4 +#define ANT_UNKNOWN 0xFF + +#define MAXCHECKHANGCNT 4 + +#define BB_VGA_LEVEL 4 +#define BB_VGA_CHANGE_THRESHOLD 16 + + +#ifndef RUN_AT +#define RUN_AT(x) (jiffies+(x)) +#endif + +// DMA related +#define RESERV_AC0DMA 4 + + +// BUILD OBJ mode +#ifdef PRIVATE_OBJ + +#undef dev_kfree_skb +#undef dev_kfree_skb_irq +#undef dev_alloc_skb +#undef kfree +#undef del_timer +#undef init_timer +#undef add_timer +#undef kmalloc +#undef netif_stop_queue +#undef netif_start_queue +#undef netif_wake_queue +#undef netif_queue_stopped +#undef netif_rx +#undef netif_running +#undef udelay +#undef mdelay +#undef eth_type_trans +#undef skb_put +#undef HZ +#undef RUN_AT +#undef pci_alloc_consistent +#undef pci_free_consistent +#undef register_netdevice +#undef register_netdev +#undef unregister_netdevice +#undef unregister_netdev +#undef skb_queue_head_init +#undef skb_queue_tail +#undef skb_queue_empty +#undef free_irq +#undef copy_from_user +#undef copy_to_user +#undef spin_lock_init +#undef pci_map_single +#undef pci_unmap_single + +// redefine kernel dependent fucntion +#define dev_kfree_skb ref_dev_kfree_skb +#define dev_kfree_skb_irq ref_dev_kfree_skb_irq +#define dev_alloc_skb ref_dev_alloc_skb +#define kfree ref_kfree +#define del_timer ref_del_timer +#define init_timer ref_init_timer +#define add_timer ref_add_timer +#define kmalloc ref_kmalloc +#define netif_stop_queue ref_netif_stop_queue +#define netif_start_queue ref_netif_start_queue +#define netif_wake_queue ref_netif_wake_queue +#define netif_queue_stopped ref_netif_queue_stopped +#define netif_rx ref_netif_rx +#define netif_running ref_netif_running +#define udelay ref_udelay +#define mdelay ref_mdelay +#define get_jiffies() ref_get_jiffies() +#define RUN_AT(x) (get_jiffies()+(x)) +#define HZ ref_HZ_tick() +#define eth_type_trans ref_eth_type_trans +#define skb_put ref_skb_put +#define skb_queue_head_init ref_skb_queue_head_init +#define skb_queue_tail ref_skb_queue_tail +#define skb_queue_empty ref_skb_queue_empty + +#define pci_alloc_consistent ref_pci_alloc_consistent +#define pci_free_consistent ref_pci_free_consistent +#define register_netdevice ref_register_netdevice +#define register_netdev ref_register_netdev +#define unregister_netdevice ref_unregister_netdevice +#define unregister_netdev ref_unregister_netdev + +#define free_irq ref_free_irq +#define copy_from_user ref_copy_from_user +#define copy_to_user ref_copy_to_user +#define spin_lock_init ref_spin_lock_init +#define pci_map_single ref_pci_map_single +#define pci_unmap_single ref_pci_unmap_single +#endif + + +#ifdef PRIVATE_OBJ +#undef printk +#define DEVICE_PRT(l, p, args...) {if (l<=msglevel) do {} while (0);} +//#define DEVICE_PRT(l, p, args...) {if (l<=msglevel) printk( p ,##args);} +#else +#define DEVICE_PRT(l, p, args...) {if (l<=msglevel) printk( p ,##args);} +#endif + + +#define AVAIL_TD(p,q) ((p)->sOpts.nTxDescs[(q)]-((p)->iTDUsed[(q)])) + +//PLICE_DEBUG -> +#define NUM 64 +//PLICE_DEUBG <- + + + +/*--------------------- Export Types ------------------------------*/ + + +//0:11A 1:11B 2:11G +typedef enum _VIA_BB_TYPE +{ + BB_TYPE_11A=0, + BB_TYPE_11B, + BB_TYPE_11G +} VIA_BB_TYPE, *PVIA_BB_TYPE; + +//0:11a,1:11b,2:11gb(only CCK in BasicRate),3:11ga(OFDM in Basic Rate) +typedef enum _VIA_PKT_TYPE +{ + PK_TYPE_11A=0, + PK_TYPE_11B, + PK_TYPE_11GB, + PK_TYPE_11GA +} VIA_PKT_TYPE, *PVIA_PKT_TYPE; + + +typedef enum __device_msg_level { + MSG_LEVEL_ERR=0, //Errors that will cause abnormal operation. + MSG_LEVEL_NOTICE=1, //Some errors need users to be notified. + MSG_LEVEL_INFO=2, //Normal message. + MSG_LEVEL_VERBOSE=3, //Will report all trival errors. + MSG_LEVEL_DEBUG=4 //Only for debug purpose. +} DEVICE_MSG_LEVEL, *PDEVICE_MSG_LEVEL; + +typedef enum __device_init_type { + DEVICE_INIT_COLD=0, // cold init + DEVICE_INIT_RESET, // reset init or Dx to D0 power remain init + DEVICE_INIT_DXPL // Dx to D0 power lost init +} DEVICE_INIT_TYPE, *PDEVICE_INIT_TYPE; + + +//++ NDIS related + +#define MAX_BSSIDINFO_4_PMKID 16 +#define MAX_PMKIDLIST 5 +//Flags for PMKID Candidate list structure +#define NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED 0x01 + +// PMKID Structures +typedef UCHAR NDIS_802_11_PMKID_VALUE[16]; + + +typedef enum _NDIS_802_11_WEP_STATUS +{ + Ndis802_11WEPEnabled, + Ndis802_11Encryption1Enabled = Ndis802_11WEPEnabled, + Ndis802_11WEPDisabled, + Ndis802_11EncryptionDisabled = Ndis802_11WEPDisabled, + Ndis802_11WEPKeyAbsent, + Ndis802_11Encryption1KeyAbsent = Ndis802_11WEPKeyAbsent, + Ndis802_11WEPNotSupported, + Ndis802_11EncryptionNotSupported = Ndis802_11WEPNotSupported, + Ndis802_11Encryption2Enabled, + Ndis802_11Encryption2KeyAbsent, + Ndis802_11Encryption3Enabled, + Ndis802_11Encryption3KeyAbsent +} NDIS_802_11_WEP_STATUS, *PNDIS_802_11_WEP_STATUS, + NDIS_802_11_ENCRYPTION_STATUS, *PNDIS_802_11_ENCRYPTION_STATUS; + + +typedef enum _NDIS_802_11_STATUS_TYPE +{ + Ndis802_11StatusType_Authentication, + Ndis802_11StatusType_MediaStreamMode, + Ndis802_11StatusType_PMKID_CandidateList, + Ndis802_11StatusTypeMax // not a real type, defined as an upper bound +} NDIS_802_11_STATUS_TYPE, *PNDIS_802_11_STATUS_TYPE; + +//Added new types for PMKID Candidate lists. +typedef struct _PMKID_CANDIDATE { + NDIS_802_11_MAC_ADDRESS BSSID; + ULONG Flags; +} PMKID_CANDIDATE, *PPMKID_CANDIDATE; + + +typedef struct _BSSID_INFO +{ + NDIS_802_11_MAC_ADDRESS BSSID; + NDIS_802_11_PMKID_VALUE PMKID; +} BSSID_INFO, *PBSSID_INFO; + +typedef struct tagSPMKID { + ULONG Length; + ULONG BSSIDInfoCount; + BSSID_INFO BSSIDInfo[MAX_BSSIDINFO_4_PMKID]; +} SPMKID, *PSPMKID; + +typedef struct tagSPMKIDCandidateEvent { + NDIS_802_11_STATUS_TYPE StatusType; + ULONG Version; // Version of the structure + ULONG NumCandidates; // No. of pmkid candidates + PMKID_CANDIDATE CandidateList[MAX_PMKIDLIST]; +} SPMKIDCandidateEvent, DEF* PSPMKIDCandidateEvent; + + +//-- + +//++ 802.11h related +#define MAX_QUIET_COUNT 8 + +typedef struct tagSQuietControl { + BOOL bEnable; + DWORD dwStartTime; + BYTE byPeriod; + WORD wDuration; +} SQuietControl, DEF* PSQuietControl; + +//-- +typedef struct __chip_info_tbl{ + CHIP_TYPE chip_id; + char* name; + int io_size; + int nTxQueue; + U32 flags; +} CHIP_INFO, *PCHIP_INFO; + + +typedef enum { + OWNED_BY_HOST=0, + OWNED_BY_NIC=1 +} DEVICE_OWNER_TYPE, *PDEVICE_OWNER_TYPE; + + +// The receive duplicate detection cache entry +typedef struct tagSCacheEntry{ + WORD wFmSequence; + BYTE abyAddr2[U_ETHER_ADDR_LEN]; +} SCacheEntry, *PSCacheEntry; + + +typedef struct tagSCache{ +/* The receive cache is updated circularly. The next entry to be written is + * indexed by the "InPtr". +*/ + UINT uInPtr; // Place to use next + SCacheEntry asCacheEntry[DUPLICATE_RX_CACHE_LENGTH]; +} SCache, *PSCache; + +#define CB_MAX_RX_FRAG 64 +// DeFragment Control Block, used for collecting fragments prior to reassembly +typedef struct tagSDeFragControlBlock +{ + WORD wSequence; + WORD wFragNum; + BYTE abyAddr2[U_ETHER_ADDR_LEN]; + UINT uLifetime; + struct sk_buff* skb; +#ifdef PRIVATE_OBJ + ref_sk_buff ref_skb; +#endif + PBYTE pbyRxBuffer; + UINT cbFrameLength; + BOOL bInUse; +} SDeFragControlBlock, DEF* PSDeFragControlBlock; + + + + +//flags for options +#define DEVICE_FLAGS_IP_ALIGN 0x00000001UL +#define DEVICE_FLAGS_PREAMBLE_TYPE 0x00000002UL +#define DEVICE_FLAGS_OP_MODE 0x00000004UL +#define DEVICE_FLAGS_PS_MODE 0x00000008UL +#define DEVICE_FLAGS_80211h_MODE 0x00000010UL +#define DEVICE_FLAGS_DiversityANT 0x00000020UL + +//flags for driver status +#define DEVICE_FLAGS_OPENED 0x00010000UL +#define DEVICE_FLAGS_WOL_ENABLED 0x00080000UL +//flags for capbilities +#define DEVICE_FLAGS_TX_ALIGN 0x01000000UL +#define DEVICE_FLAGS_HAVE_CAM 0x02000000UL +#define DEVICE_FLAGS_FLOW_CTRL 0x04000000UL + +//flags for MII status +#define DEVICE_LINK_FAIL 0x00000001UL +#define DEVICE_SPEED_10 0x00000002UL +#define DEVICE_SPEED_100 0x00000004UL +#define DEVICE_SPEED_1000 0x00000008UL +#define DEVICE_DUPLEX_FULL 0x00000010UL +#define DEVICE_AUTONEG_ENABLE 0x00000020UL +#define DEVICE_FORCED_BY_EEPROM 0x00000040UL +//for device_set_media_duplex +#define DEVICE_LINK_CHANGE 0x00000001UL + + +//PLICE_DEBUG-> + + +typedef struct _RxManagementQueue +{ + int packet_num; + int head,tail; + PSRxMgmtPacket Q[NUM]; +} RxManagementQueue,*PSRxManagementQueue; + + + +//PLICE_DEBUG<- + + +typedef struct __device_opt { + int nRxDescs0; //Number of RX descriptors0 + int nRxDescs1; //Number of RX descriptors1 + int nTxDescs[2]; //Number of TX descriptors 0, 1 + int int_works; //interrupt limits + int rts_thresh; //rts threshold + int frag_thresh; + int data_rate; + int channel_num; + int short_retry; + int long_retry; + int bbp_type; + U32 flags; +} OPTIONS, *POPTIONS; + + +typedef struct __device_info { + struct __device_info* next; + struct __device_info* prev; + + struct pci_dev* pcid; + +#if CONFIG_PM + u32 pci_state[16]; +#endif + +// netdev + struct net_device* dev; + struct net_device* next_module; + struct net_device_stats stats; + +//dma addr, rx/tx pool + dma_addr_t pool_dma; + dma_addr_t rd0_pool_dma; + dma_addr_t rd1_pool_dma; + + dma_addr_t td0_pool_dma; + dma_addr_t td1_pool_dma; + + dma_addr_t tx_bufs_dma0; + dma_addr_t tx_bufs_dma1; + dma_addr_t tx_beacon_dma; + + PBYTE tx0_bufs; + PBYTE tx1_bufs; + PBYTE tx_beacon_bufs; + + CHIP_TYPE chip_id; + + U32 PortOffset; + DWORD dwIsr; + U32 memaddr; + U32 ioaddr; + U32 io_size; + + BYTE byRevId; + WORD SubSystemID; + WORD SubVendorID; + + int nTxQueues; + volatile int iTDUsed[TYPE_MAXTD]; + + volatile PSTxDesc apCurrTD[TYPE_MAXTD]; + volatile PSTxDesc apTailTD[TYPE_MAXTD]; + + volatile PSTxDesc apTD0Rings; + volatile PSTxDesc apTD1Rings; + + volatile PSRxDesc aRD0Ring; + volatile PSRxDesc aRD1Ring; + volatile PSRxDesc pCurrRD[TYPE_MAXRD]; + SCache sDupRxCache; + + SDeFragControlBlock sRxDFCB[CB_MAX_RX_FRAG]; + UINT cbDFCB; + UINT cbFreeDFCB; + UINT uCurrentDFCBIdx; + + OPTIONS sOpts; + + U32 flags; + + U32 rx_buf_sz; + int multicast_limit; + BYTE byRxMode; + + spinlock_t lock; +//PLICE_DEBUG-> + struct tasklet_struct RxMngWorkItem; + RxManagementQueue rxManeQueue; +//PLICE_DEBUG<- +//PLICE_DEBUG -> + pid_t MLMEThr_pid; + struct completion notify; + struct semaphore mlme_semaphore; +//PLICE_DEBUG <- + + + U32 rx_bytes; + + // Version control + BYTE byLocalID; + BYTE byRFType; + + BYTE byMaxPwrLevel; + BYTE byZoneType; + BOOL bZoneRegExist; + BYTE byOriginalZonetype; + BYTE abyMacContext[MAC_MAX_CONTEXT_REG]; + BOOL bLinkPass; // link status: OK or fail + BYTE abyCurrentNetAddr[U_ETHER_ADDR_LEN]; + + // Adapter statistics + SStatCounter scStatistic; + // 802.11 counter + SDot11Counters s802_11Counter; + + + // 802.11 management + PSMgmtObject pMgmt; + SMgmtObject sMgmtObj; + + // 802.11 MAC specific + UINT uCurrRSSI; + BYTE byCurrSQ; + + DWORD dwTxAntennaSel; + DWORD dwRxAntennaSel; + BYTE byAntennaCount; + BYTE byRxAntennaMode; + BYTE byTxAntennaMode; + BOOL bTxRxAntInv; + + PBYTE pbyTmpBuff; + UINT uSIFS; //Current SIFS + UINT uDIFS; //Current DIFS + UINT uEIFS; //Current EIFS + UINT uSlot; //Current SlotTime + UINT uCwMin; //Current CwMin + UINT uCwMax; //CwMax is fixed on 1023. + // PHY parameter + BYTE bySIFS; + BYTE byDIFS; + BYTE byEIFS; + BYTE bySlot; + BYTE byCWMaxMin; + CARD_PHY_TYPE eCurrentPHYType; + + + VIA_BB_TYPE byBBType; //0: 11A, 1:11B, 2:11G + VIA_PKT_TYPE byPacketType; //0:11a,1:11b,2:11gb(only CCK in BasicRate),3:11ga(OFDM in Basic Rate) + WORD wBasicRate; + BYTE byACKRate; + BYTE byTopOFDMBasicRate; + BYTE byTopCCKBasicRate; + + BYTE byMinChannel; + BYTE byMaxChannel; + UINT uConnectionRate; + + BYTE byPreambleType; + BYTE byShortPreamble; + + WORD wCurrentRate; + WORD wRTSThreshold; + WORD wFragmentationThreshold; + BYTE byShortRetryLimit; + BYTE byLongRetryLimit; + CARD_OP_MODE eOPMode; + BYTE byOpMode; + BOOL bBSSIDFilter; + WORD wMaxTransmitMSDULifetime; + BYTE abyBSSID[U_ETHER_ADDR_LEN]; + BYTE abyDesireBSSID[U_ETHER_ADDR_LEN]; + WORD wCTSDuration; // update while speed change + WORD wACKDuration; // update while speed change + WORD wRTSTransmitLen; // update while speed change + BYTE byRTSServiceField; // update while speed change + BYTE byRTSSignalField; // update while speed change + + DWORD dwMaxReceiveLifetime; // dot11MaxReceiveLifetime + + BOOL bCCK; + BOOL bEncryptionEnable; + BOOL bLongHeader; + BOOL bShortSlotTime; + BOOL bProtectMode; + BOOL bNonERPPresent; + BOOL bBarkerPreambleMd; + + BYTE byERPFlag; + WORD wUseProtectCntDown; + + BOOL bRadioControlOff; + BOOL bRadioOff; + BOOL bEnablePSMode; + WORD wListenInterval; + BOOL bPWBitOn; + WMAC_POWER_MODE ePSMode; + + + // GPIO Radio Control + BYTE byRadioCtl; + BYTE byGPIO; + BOOL bHWRadioOff; + BOOL bPrvActive4RadioOFF; + BOOL bGPIOBlockRead; + + // Beacon releated + WORD wSeqCounter; + WORD wBCNBufLen; + BOOL bBeaconBufReady; + BOOL bBeaconSent; + BOOL bIsBeaconBufReadySet; + UINT cbBeaconBufReadySetCnt; + BOOL bFixRate; + BYTE byCurrentCh; + UINT uScanTime; + + CMD_STATE eCommandState; + + CMD_CODE eCommand; + BOOL bBeaconTx; + + BOOL bStopBeacon; + BOOL bStopDataPkt; + BOOL bStopTx0Pkt; + UINT uAutoReConnectTime; + + // 802.11 counter + + CMD_ITEM eCmdQueue[CMD_Q_SIZE]; + UINT uCmdDequeueIdx; + UINT uCmdEnqueueIdx; + UINT cbFreeCmdQueue; + BOOL bCmdRunning; + BOOL bCmdClear; + + + + BOOL bRoaming; + //WOW + BYTE abyIPAddr[4]; + + ULONG ulTxPower; + NDIS_802_11_WEP_STATUS eEncryptionStatus; + BOOL bTransmitKey; +//2007-0925-01by MikeLiu +//mike add :save old Encryption + NDIS_802_11_WEP_STATUS eOldEncryptionStatus; + SKeyManagement sKey; + DWORD dwIVCounter; + + QWORD qwPacketNumber; //For CCMP and TKIP as TSC(6 bytes) + UINT uCurrentWEPMode; + + RC4Ext SBox; + BYTE abyPRNG[WLAN_WEPMAX_KEYLEN+3]; + + BYTE byKeyIndex; + UINT uKeyLength; + BYTE abyKey[WLAN_WEP232_KEYLEN]; + + BOOL bAES; + BYTE byCntMeasure; + + // for AP mode + UINT uAssocCount; + BOOL bMoreData; + + // QoS + BOOL bGrpAckPolicy; + + // for OID_802_11_ASSOCIATION_INFORMATION + BOOL bAssocInfoSet; + + + BYTE byAutoFBCtrl; + + BOOL bTxMICFail; + BOOL bRxMICFail; + + + UINT uRATEIdx; + + + // For Update BaseBand VGA Gain Offset + BOOL bUpdateBBVGA; + UINT uBBVGADiffCount; + BYTE byBBVGANew; + BYTE byBBVGACurrent; + BYTE abyBBVGA[BB_VGA_LEVEL]; + LONG ldBmThreshold[BB_VGA_LEVEL]; + + BYTE byBBPreEDRSSI; + BYTE byBBPreEDIndex; + + BOOL bRadioCmd; + DWORD dwDiagRefCount; + + // For FOE Tuning + BYTE byFOETuning; + + // For Auto Power Tunning + + BYTE byAutoPwrTunning; + SHORT sPSetPointCCK; + SHORT sPSetPointOFDMG; + SHORT sPSetPointOFDMA; + LONG lPFormulaOffset; + SHORT sPThreshold; + CHAR cAdjustStep; + CHAR cMinTxAGC; + + // For RF Power table + BYTE byCCKPwr; + BYTE byOFDMPwrG; + BYTE byCurPwr; + I8 byCurPwrdBm; + BYTE abyCCKPwrTbl[CB_MAX_CHANNEL_24G+1]; + BYTE abyOFDMPwrTbl[CB_MAX_CHANNEL+1]; + I8 abyCCKDefaultPwr[CB_MAX_CHANNEL_24G+1]; + I8 abyOFDMDefaultPwr[CB_MAX_CHANNEL+1]; + I8 abyRegPwr[CB_MAX_CHANNEL+1]; + I8 abyLocalPwr[CB_MAX_CHANNEL+1]; + + + // BaseBand Loopback Use + BYTE byBBCR4d; + BYTE byBBCRc9; + BYTE byBBCR88; + BYTE byBBCR09; + + // command timer + struct timer_list sTimerCommand; +#ifdef TxInSleep + struct timer_list sTimerTxData; + ULONG nTxDataTimeCout; + BOOL fTxDataInSleep; + BOOL IsTxDataTrigger; +#endif + +#ifdef WPA_SM_Transtatus + BOOL fWPA_Authened; //is WPA/WPA-PSK or WPA2/WPA2-PSK authen?? +#endif + BYTE byReAssocCount; //mike add:re-association retry times! + BYTE byLinkWaitCount; + + + BYTE abyNodeName[17]; + + BOOL bDiversityRegCtlON; + BOOL bDiversityEnable; + ULONG ulDiversityNValue; + ULONG ulDiversityMValue; + BYTE byTMax; + BYTE byTMax2; + BYTE byTMax3; + ULONG ulSQ3TH; + +// ANT diversity + ULONG uDiversityCnt; + BYTE byAntennaState; + ULONG ulRatio_State0; + ULONG ulRatio_State1; + + //SQ3 functions for antenna diversity + struct timer_list TimerSQ3Tmax1; + struct timer_list TimerSQ3Tmax2; + struct timer_list TimerSQ3Tmax3; + + + ULONG uNumSQ3[MAX_RATE]; + WORD wAntDiversityMaxRate; + + + SEthernetHeader sTxEthHeader; + SEthernetHeader sRxEthHeader; + BYTE abyBroadcastAddr[U_ETHER_ADDR_LEN]; + BYTE abySNAP_RFC1042[U_ETHER_ADDR_LEN]; + BYTE abySNAP_Bridgetunnel[U_ETHER_ADDR_LEN]; + BYTE abyEEPROM[EEP_MAX_CONTEXT_SIZE]; //DWORD alignment + // Pre-Authentication & PMK cache + SPMKID gsPMKID; + SPMKIDCandidateEvent gsPMKIDCandidate; + + + // for 802.11h + BOOL b11hEnable; + BYTE abyCountryCode[3]; + // for 802.11h DFS + UINT uNumOfMeasureEIDs; + PWLAN_IE_MEASURE_REQ pCurrMeasureEID; + BOOL bMeasureInProgress; + BYTE byOrgChannel; + BYTE byOrgRCR; + DWORD dwOrgMAR0; + DWORD dwOrgMAR4; + BYTE byBasicMap; + BYTE byCCAFraction; + BYTE abyRPIs[8]; + DWORD dwRPIs[8]; + BOOL bChannelSwitch; + BYTE byNewChannel; + BYTE byChannelSwitchCount; + BOOL bQuietEnable; + BOOL bEnableFirstQuiet; + BYTE byQuietStartCount; + UINT uQuietEnqueue; + DWORD dwCurrentQuietEndTime; + SQuietControl sQuiet[MAX_QUIET_COUNT]; + // for 802.11h TPC + BOOL bCountryInfo5G; + BOOL bCountryInfo24G; + + WORD wBeaconInterval; + + //WPA supplicant deamon + struct net_device *wpadev; + BOOL bWPADEVUp; + struct sk_buff *skb; +#ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT +/* + BOOL bwextstep0; + BOOL bwextstep1; + BOOL bwextstep2; + BOOL bwextstep3; + */ + UINT bwextcount; + BOOL bWPASuppWextEnabled; +#endif + + //-- +#ifdef HOSTAP + // user space daemon: hostapd, is used for HOSTAP + BOOL bEnableHostapd; + BOOL bEnable8021x; + BOOL bEnableHostWEP; + struct net_device *apdev; + int (*tx_80211)(struct sk_buff *skb, struct net_device *dev); +#endif + UINT uChannel; + BOOL bMACSuspend; + +#ifdef WIRELESS_EXT + struct iw_statistics wstats; // wireless stats +#endif /* WIRELESS_EXT */ + BOOL bCommit; + +} DEVICE_INFO, *PSDevice; + + +//PLICE_DEBUG-> + + + inline static VOID EnQueue (PSDevice pDevice,PSRxMgmtPacket pRxMgmtPacket) +{ + //printk("Enter EnQueue:tail is %d\n",pDevice->rxManeQueue.tail); + if ((pDevice->rxManeQueue.tail+1) % NUM == pDevice->rxManeQueue.head) + { + //printk("Queue is Full,tail is %d\n",pDevice->rxManeQueue.tail); + return ; + } + else + { + pDevice->rxManeQueue.tail = (pDevice->rxManeQueue.tail+1)% NUM; + pDevice->rxManeQueue.Q[pDevice->rxManeQueue.tail] = pRxMgmtPacket; + pDevice->rxManeQueue.packet_num++; + //printk("packet num is %d\n",pDevice->rxManeQueue.packet_num); + } +} + + + + + inline static PSRxMgmtPacket DeQueue (PSDevice pDevice) +{ + PSRxMgmtPacket pRxMgmtPacket; + if (pDevice->rxManeQueue.tail == pDevice->rxManeQueue.head) + { + printk("Queue is Empty\n"); + return NULL; + } + else + { + int x; + //x=pDevice->rxManeQueue.head = (pDevice->rxManeQueue.head+1)%NUM; + pDevice->rxManeQueue.head = (pDevice->rxManeQueue.head+1)%NUM; + x = pDevice->rxManeQueue.head; + //printk("Enter DeQueue:head is %d\n",x); + pRxMgmtPacket = pDevice->rxManeQueue.Q[x]; + pDevice->rxManeQueue.packet_num--; + return pRxMgmtPacket; + } +} + +VOID InitRxManagementQueue(PSDevice pDevice); + + + +//PLICE_DEBUG<- + + + + + + +inline static BOOL device_get_ip(PSDevice pInfo) { + struct in_device* in_dev=(struct in_device*) pInfo->dev->ip_ptr; + struct in_ifaddr* ifa; + + if (in_dev!=NULL) { + ifa=(struct in_ifaddr*) in_dev->ifa_list; + if (ifa!=NULL) { + memcpy(pInfo->abyIPAddr,&ifa->ifa_address,4); + return TRUE; + } + } + return FALSE; +} + + + +static inline PDEVICE_RD_INFO alloc_rd_info(void) { + PDEVICE_RD_INFO ptr; + if ((ptr = (PDEVICE_RD_INFO)kmalloc((int)sizeof(DEVICE_RD_INFO), (int)GFP_ATOMIC)) == NULL) + return NULL; + else { + memset(ptr,0,sizeof(DEVICE_RD_INFO)); + return ptr; + } +} + +static inline PDEVICE_TD_INFO alloc_td_info(void) { + PDEVICE_TD_INFO ptr; + if ((ptr = (PDEVICE_TD_INFO)kmalloc((int)sizeof(DEVICE_TD_INFO), (int)GFP_ATOMIC))==NULL) + return NULL; + else { + memset(ptr,0,sizeof(DEVICE_TD_INFO)); + return ptr; + } +} + +/*--------------------- Export Functions --------------------------*/ + +BOOL device_dma0_xmit(PSDevice pDevice, struct sk_buff *skb, UINT uNodeIndex); +BOOL device_alloc_frag_buf(PSDevice pDevice, PSDeFragControlBlock pDeF); +int Config_FileOperation(PSDevice pDevice,BOOL fwrite,unsigned char *Parameter); +#endif + + diff --git a/drivers/staging/vt6655/device_cfg.h b/drivers/staging/vt6655/device_cfg.h new file mode 100644 index 000000000000..1cbb4440b46f --- /dev/null +++ b/drivers/staging/vt6655/device_cfg.h @@ -0,0 +1,142 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * File: device_cfg.h + * + * Purpose: Driver configuration header + * Author: Lyndon Chen + * + * Date: Dec 17, 2002 + * + */ +#ifndef __DEVICE_CONFIG_H +#define __DEVICE_CONFIG_H + +//#include +#include + +#if !defined(__TTYPE_H__) +#include "ttype.h" +#endif + + + +typedef __u8 UINT8, *PUINT8; +typedef __u16 UINT16, *PUINT16; +typedef __u32 UINT32, *PUINT32; + + +#ifndef VOID +#define VOID void +#endif + +#ifndef CONST +#define CONST const +#endif + +#ifndef STATIC +#define STATIC static +#endif + +#ifndef DEF +#define DEF +#endif + +#ifndef IN +#define IN +#endif + +#ifndef OUT +#define OUT +#endif + +typedef +struct _version { + UINT8 major; + UINT8 minor; + UINT8 build; +} version_t, *pversion_t; + +#ifndef FALSE +#define FALSE (0) +#endif + +#ifndef TRUE +#define TRUE (!(FALSE)) +#endif + +#define VID_TABLE_SIZE 64 +#define MCAST_TABLE_SIZE 64 +#define MCAM_SIZE 32 +#define VCAM_SIZE 32 +#define TX_QUEUE_NO 8 + +#define DEVICE_NAME "vt6655" +#define DEVICE_FULL_DRV_NAM "VIA Networking Solomon-A/B/G Wireless LAN Adapter Driver" + +#ifndef MAJOR_VERSION +#define MAJOR_VERSION 1 +#endif + +#ifndef MINOR_VERSION +#define MINOR_VERSION 17 +#endif + +#ifndef DEVICE_VERSION +#define DEVICE_VERSION "1.19.12" +#endif +//config file +#include +#include +#ifndef CONFIG_PATH +#define CONFIG_PATH "/etc/vntconfiguration.dat" +#endif + +//Max: 2378=2312Payload + 30HD +4CRC + 2Padding + 4Len + 8TSF + 4RSR +#define PKT_BUF_SZ 2390 + + +#define MALLOC(x,y) kmalloc((x),(y)) +#define FREE(x) kfree((x)) +#define MAX_UINTS 8 +#define OPTION_DEFAULT { [0 ... MAX_UINTS-1] = -1} + + + +typedef enum _chip_type{ + VT3253=1 +} CHIP_TYPE, *PCHIP_TYPE; + + + +#ifdef VIAWET_DEBUG +#define ASSERT(x) { \ + if (!(x)) { \ + printk(KERN_ERR "assertion %s failed: file %s line %d\n", #x,\ + __FUNCTION__, __LINE__);\ + *(int*) 0=0;\ + }\ +} +#define DBG_PORT80(value) outb(value, 0x80) +#else +#define ASSERT(x) +#define DBG_PORT80(value) +#endif + + +#endif diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c new file mode 100644 index 000000000000..a10ed27acbc2 --- /dev/null +++ b/drivers/staging/vt6655/device_main.c @@ -0,0 +1,4074 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * File: device_main.c + * + * Purpose: driver entry for initial, open, close, tx and rx. + * + * Author: Lyndon Chen + * + * Date: Jan 8, 2003 + * + * Functions: + * + * device_found1 - module initial (insmod) driver entry + * device_remove1 - module remove entry + * device_init_info - device structure resource allocation function + * device_free_info - device structure resource free function + * device_get_pci_info - get allocated pci io/mem resource + * device_print_info - print out resource + * device_open - allocate dma/descripter resource & initial mac/bbp function + * device_xmit - asynchrous data tx function + * device_intr - interrupt handle function + * device_set_multi - set mac filter + * device_ioctl - ioctl entry + * device_close - shutdown mac/bbp & free dma/descripter resource + * device_rx_srv - rx service function + * device_receive_frame - rx data function + * device_alloc_rx_buf - rx buffer pre-allocated function + * device_alloc_frag_buf - rx fragement pre-allocated function + * device_free_tx_buf - free tx buffer function + * device_free_frag_buf- free de-fragement buffer + * device_dma0_tx_80211- tx 802.11 frame via dma0 + * device_dma0_xmit- tx PS bufferred frame via dma0 + * device_init_rd0_ring- initial rd dma0 ring + * device_init_rd1_ring- initial rd dma1 ring + * device_init_td0_ring- initial tx dma0 ring buffer + * device_init_td1_ring- initial tx dma1 ring buffer + * device_init_registers- initial MAC & BBP & RF internal registers. + * device_init_rings- initial tx/rx ring buffer + * device_init_defrag_cb- initial & allocate de-fragement buffer. + * device_free_rings- free all allocated ring buffer + * device_tx_srv- tx interrupt service function + * + * Revision History: + */ +#undef __NO_VERSION__ + +#if !defined(__DEVICE_H__) +#include "device.h" +#endif +#if !defined(__CARD_H__) +#include "card.h" +#endif +#if !defined(__TBIT_H__) +#include "tbit.h" +#endif +#if !defined(__BASEBAND_H__) +#include "baseband.h" +#endif +#if !defined(__MAC_H__) +#include "mac.h" +#endif +#if !defined(__TETHER_H__) +#include "tether.h" +#endif +#if !defined(__WMGR_H__) +#include "wmgr.h" +#endif +#if !defined(__WCTL_H__) +#include "wctl.h" +#endif +#if !defined(__POWER_H__) +#include "power.h" +#endif +#if !defined(__WCMD_H__) +#include "wcmd.h" +#endif +#if !defined(__IOCMD_H__) +#include "iocmd.h" +#endif +#if !defined(__TCRC_H__) +#include "tcrc.h" +#endif +#if !defined(__RXTX_H__) +#include "rxtx.h" +#endif +#if !defined(__WROUTE_H__) +#include "wroute.h" +#endif +#if !defined(__BSSDB_H__) +#include "bssdb.h" +#endif +#if !defined(__HOSTAP_H__) +#include "hostap.h" +#endif +#if !defined(__WPACTL_H__) +#include "wpactl.h" +#endif +#if !defined(__IOCTL_H__) +#include "ioctl.h" +#endif +#if !defined(__IWCTL_H__) +#include "iwctl.h" +#endif +#if !defined(__DPC_H__) +#include "dpc.h" +#endif +#if !defined(__DATARATE_H__) +#include "datarate.h" +#endif +#if !defined(__RF_H__) +#include "rf.h" +#endif +#if !defined(__IOWPA_H__) +#include "iowpa.h" +#endif + +#include +#include +// #ifdef PRIVATE_OBJ +//#if !defined(__DEVICE_EXP_H) +//#include "device_exp.h" +//#endif +//#if !defined(__DEVICE_MODULE_H) +//#include "device_module.h" +//#endif + + +// #endif +//#define DEBUG +/*--------------------- Static Definitions -------------------------*/ +//static int msglevel =MSG_LEVEL_DEBUG; +static int msglevel = MSG_LEVEL_INFO; + +//#define PLICE_DEBUG +// +// Define module options +// +#ifndef PRIVATE_OBJ +MODULE_AUTHOR("VIA Networking Technologies, Inc., "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("VIA Networking Solomon-A/B/G Wireless LAN Adapter Driver"); +#endif + +//PLICE_DEBUG -> + static int mlme_kill; + //static struct task_struct * mlme_task; +//PLICE_DEBUG <- + +#define DEVICE_PARAM(N,D) +/* + static const int N[MAX_UINTS]=OPTION_DEFAULT;\ + MODULE_PARM(N, "1-" __MODULE_STRING(MAX_UINTS) "i");\ + MODULE_PARM_DESC(N, D); +*/ + +#define RX_DESC_MIN0 16 +#define RX_DESC_MAX0 128 +#define RX_DESC_DEF0 32 +DEVICE_PARAM(RxDescriptors0,"Number of receive descriptors0"); + +#define RX_DESC_MIN1 16 +#define RX_DESC_MAX1 128 +#define RX_DESC_DEF1 32 +DEVICE_PARAM(RxDescriptors1,"Number of receive descriptors1"); + +#define TX_DESC_MIN0 16 +#define TX_DESC_MAX0 128 +#define TX_DESC_DEF0 32 +DEVICE_PARAM(TxDescriptors0,"Number of transmit descriptors0"); + +#define TX_DESC_MIN1 16 +#define TX_DESC_MAX1 128 +#define TX_DESC_DEF1 64 +DEVICE_PARAM(TxDescriptors1,"Number of transmit descriptors1"); + + +#define IP_ALIG_DEF 0 +/* IP_byte_align[] is used for IP header DWORD byte aligned + 0: indicate the IP header won't be DWORD byte aligned.(Default) . + 1: indicate the IP header will be DWORD byte aligned. + In some enviroment, the IP header should be DWORD byte aligned, + or the packet will be droped when we receive it. (eg: IPVS) +*/ +DEVICE_PARAM(IP_byte_align,"Enable IP header dword aligned"); + + +#define INT_WORKS_DEF 20 +#define INT_WORKS_MIN 10 +#define INT_WORKS_MAX 64 + +DEVICE_PARAM(int_works,"Number of packets per interrupt services"); + +#define CHANNEL_MIN 1 +#define CHANNEL_MAX 14 +#define CHANNEL_DEF 6 + +DEVICE_PARAM(Channel, "Channel number"); + + +/* PreambleType[] is the preamble length used for transmit. + 0: indicate allows long preamble type + 1: indicate allows short preamble type +*/ + +#define PREAMBLE_TYPE_DEF 1 + +DEVICE_PARAM(PreambleType, "Preamble Type"); + + +#define RTS_THRESH_MIN 512 +#define RTS_THRESH_MAX 2347 +#define RTS_THRESH_DEF 2347 + +DEVICE_PARAM(RTSThreshold, "RTS threshold"); + + +#define FRAG_THRESH_MIN 256 +#define FRAG_THRESH_MAX 2346 +#define FRAG_THRESH_DEF 2346 + +DEVICE_PARAM(FragThreshold, "Fragmentation threshold"); + + +#define DATA_RATE_MIN 0 +#define DATA_RATE_MAX 13 +#define DATA_RATE_DEF 13 +/* datarate[] index + 0: indicate 1 Mbps 0x02 + 1: indicate 2 Mbps 0x04 + 2: indicate 5.5 Mbps 0x0B + 3: indicate 11 Mbps 0x16 + 4: indicate 6 Mbps 0x0c + 5: indicate 9 Mbps 0x12 + 6: indicate 12 Mbps 0x18 + 7: indicate 18 Mbps 0x24 + 8: indicate 24 Mbps 0x30 + 9: indicate 36 Mbps 0x48 + 10: indicate 48 Mbps 0x60 + 11: indicate 54 Mbps 0x6c + 12: indicate 72 Mbps 0x90 + 13: indicate auto rate +*/ + +DEVICE_PARAM(ConnectionRate, "Connection data rate"); + +#define OP_MODE_DEF 0 + +DEVICE_PARAM(OPMode, "Infrastruct, adhoc, AP mode "); + +/* OpMode[] is used for transmit. + 0: indicate infrastruct mode used + 1: indicate adhoc mode used + 2: indicate AP mode used +*/ + + +/* PSMode[] + 0: indicate disable power saving mode + 1: indicate enable power saving mode +*/ + +#define PS_MODE_DEF 0 + +DEVICE_PARAM(PSMode, "Power saving mode"); + + +#define SHORT_RETRY_MIN 0 +#define SHORT_RETRY_MAX 31 +#define SHORT_RETRY_DEF 8 + + +DEVICE_PARAM(ShortRetryLimit, "Short frame retry limits"); + +#define LONG_RETRY_MIN 0 +#define LONG_RETRY_MAX 15 +#define LONG_RETRY_DEF 4 + + +DEVICE_PARAM(LongRetryLimit, "long frame retry limits"); + + +/* BasebandType[] baseband type selected + 0: indicate 802.11a type + 1: indicate 802.11b type + 2: indicate 802.11g type +*/ +#define BBP_TYPE_MIN 0 +#define BBP_TYPE_MAX 2 +#define BBP_TYPE_DEF 2 + +DEVICE_PARAM(BasebandType, "baseband type"); + + + +/* 80211hEnable[] + 0: indicate disable 802.11h + 1: indicate enable 802.11h +*/ + +#define X80211h_MODE_DEF 0 + +DEVICE_PARAM(b80211hEnable, "802.11h mode"); + +/* 80211hEnable[] + 0: indicate disable 802.11h + 1: indicate enable 802.11h +*/ + +#define DIVERSITY_ANT_DEF 0 + +DEVICE_PARAM(bDiversityANTEnable, "ANT diversity mode"); + + +// +// Static vars definitions +// + + +#ifndef PRIVATE_OBJ +static int device_nics =0; +static PSDevice pDevice_Infos =NULL; +static struct net_device *root_device_dev = NULL; + +static CHIP_INFO chip_info_table[]= { + { VT3253, "VIA Networking Solomon-A/B/G Wireless LAN Adapter ", + 256, 1, DEVICE_FLAGS_IP_ALIGN|DEVICE_FLAGS_TX_ALIGN }, + {0,NULL} +}; + +static struct pci_device_id device_id_table[] __devinitdata = { +{ 0x1106, 0x3253, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (int)&chip_info_table[0]}, +{ 0, } +}; +#endif + +/*--------------------- Static Functions --------------------------*/ + +#ifndef PRIVATE_OBJ + +static int device_found1(struct pci_dev *pcid, const struct pci_device_id *ent); +static BOOL device_init_info(struct pci_dev* pcid, PSDevice* ppDevice, PCHIP_INFO); +static void device_free_info(PSDevice pDevice); +static BOOL device_get_pci_info(PSDevice, struct pci_dev* pcid); +static void device_print_info(PSDevice pDevice); +static struct net_device_stats *device_get_stats(struct net_device *dev); +static void device_init_diversity_timer(PSDevice pDevice); +static int device_open(struct net_device *dev); +static int device_xmit(struct sk_buff *skb, struct net_device *dev); +static irqreturn_t device_intr(int irq, void*dev_instance); +static void device_set_multi(struct net_device *dev); +static int device_close(struct net_device *dev); +static int device_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); + +#ifdef CONFIG_PM +static int device_notify_reboot(struct notifier_block *, unsigned long event, void *ptr); +static int viawget_suspend(struct pci_dev *pcid, u32 state); +static int viawget_resume(struct pci_dev *pcid); +struct notifier_block device_notifier = { + notifier_call: device_notify_reboot, + next: NULL, + priority: 0 +}; +#endif + +#endif // #ifndef PRIVATE_OBJ + +static void device_init_rd0_ring(PSDevice pDevice); +static void device_init_rd1_ring(PSDevice pDevice); +static void device_init_defrag_cb(PSDevice pDevice); +static void device_init_td0_ring(PSDevice pDevice); +static void device_init_td1_ring(PSDevice pDevice); + +#ifndef PRIVATE_OBJ +static int device_dma0_tx_80211(struct sk_buff *skb, struct net_device *dev); +#endif +//2008-0714by Mike Liu +static BOOL device_release_WPADEV(PSDevice pDevice); + +static int ethtool_ioctl(struct net_device *dev, void *useraddr); +static int device_rx_srv(PSDevice pDevice, UINT uIdx); +static int device_tx_srv(PSDevice pDevice, UINT uIdx); +static BOOL device_alloc_rx_buf(PSDevice pDevice, PSRxDesc pDesc); +static void device_init_registers(PSDevice pDevice, DEVICE_INIT_TYPE InitType); +static void device_free_tx_buf(PSDevice pDevice, PSTxDesc pDesc); +static void device_free_td0_ring(PSDevice pDevice); +static void device_free_td1_ring(PSDevice pDevice); +static void device_free_rd0_ring(PSDevice pDevice); +static void device_free_rd1_ring(PSDevice pDevice); +static void device_free_rings(PSDevice pDevice); +static void device_free_frag_buf(PSDevice pDevice); +static int Config_FileGetParameter(UCHAR *string, UCHAR *dest,UCHAR *source); + + +/*--------------------- Export Variables --------------------------*/ + +/*--------------------- Export Functions --------------------------*/ + + +#ifndef PRIVATE_OBJ + +static char* get_chip_name(int chip_id) { + int i; + for (i=0;chip_info_table[i].name!=NULL;i++) + if (chip_info_table[i].chip_id==chip_id) + break; + return chip_info_table[i].name; +} + +static void __devexit device_remove1(struct pci_dev *pcid) +{ + PSDevice pDevice=pci_get_drvdata(pcid); + + if (pDevice==NULL) + return; + device_free_info(pDevice); + +} + +#endif +/* +static void +device_set_int_opt(int *opt, int val, int min, int max, int def,char* name,char* devname) { + if (val==-1) + *opt=def; + else if (valmax) { + DEVICE_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: the value of parameter %s is invalid, the valid range is (%d-%d)\n" , + devname,name, min,max); + *opt=def; + } else { + DEVICE_PRT(MSG_LEVEL_INFO, KERN_INFO "%s: set value of parameter %s to %d\n", + devname, name, val); + *opt=val; + } +} + +static void +device_set_bool_opt(PU32 opt, int val,BOOL def,U32 flag, char* name,char* devname) { + (*opt)&=(~flag); + if (val==-1) + *opt|=(def ? flag : 0); + else if (val<0 || val>1) { + DEVICE_PRT(MSG_LEVEL_INFO, KERN_NOTICE + "%s: the value of parameter %s is invalid, the valid range is (0-1)\n",devname,name); + *opt|=(def ? flag : 0); + } else { + DEVICE_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: set parameter %s to %s\n", + devname,name , val ? "TRUE" : "FALSE"); + *opt|=(val ? flag : 0); + } +} +*/ +static void +device_get_options(PSDevice pDevice, int index, char* devname) { + + POPTIONS pOpts = &(pDevice->sOpts); + pOpts->nRxDescs0=RX_DESC_DEF0; + pOpts->nRxDescs1=RX_DESC_DEF1; + pOpts->nTxDescs[0]=TX_DESC_DEF0; + pOpts->nTxDescs[1]=TX_DESC_DEF1; +pOpts->flags|=DEVICE_FLAGS_IP_ALIGN; + pOpts->int_works=INT_WORKS_DEF; + pOpts->rts_thresh=RTS_THRESH_DEF; + pOpts->frag_thresh=FRAG_THRESH_DEF; + pOpts->data_rate=DATA_RATE_DEF; + pOpts->channel_num=CHANNEL_DEF; + +pOpts->flags|=DEVICE_FLAGS_PREAMBLE_TYPE; +pOpts->flags|=DEVICE_FLAGS_OP_MODE; +//pOpts->flags|=DEVICE_FLAGS_PS_MODE; + pOpts->short_retry=SHORT_RETRY_DEF; + pOpts->long_retry=LONG_RETRY_DEF; + pOpts->bbp_type=BBP_TYPE_DEF; +pOpts->flags|=DEVICE_FLAGS_80211h_MODE; +pOpts->flags|=DEVICE_FLAGS_DiversityANT; + + +} + +static void +device_set_options(PSDevice pDevice) { + + BYTE abyBroadcastAddr[U_ETHER_ADDR_LEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + BYTE abySNAP_RFC1042[U_ETHER_ADDR_LEN] = {0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00}; + BYTE abySNAP_Bridgetunnel[U_ETHER_ADDR_LEN] = {0xAA, 0xAA, 0x03, 0x00, 0x00, 0xF8}; + + + memcpy(pDevice->abyBroadcastAddr, abyBroadcastAddr, U_ETHER_ADDR_LEN); + memcpy(pDevice->abySNAP_RFC1042, abySNAP_RFC1042, U_ETHER_ADDR_LEN); + memcpy(pDevice->abySNAP_Bridgetunnel, abySNAP_Bridgetunnel, U_ETHER_ADDR_LEN); + + pDevice->uChannel = pDevice->sOpts.channel_num; + pDevice->wRTSThreshold = pDevice->sOpts.rts_thresh; + pDevice->wFragmentationThreshold = pDevice->sOpts.frag_thresh; + pDevice->byShortRetryLimit = pDevice->sOpts.short_retry; + pDevice->byLongRetryLimit = pDevice->sOpts.long_retry; + pDevice->wMaxTransmitMSDULifetime = DEFAULT_MSDU_LIFETIME; + pDevice->byShortPreamble = (pDevice->sOpts.flags & DEVICE_FLAGS_PREAMBLE_TYPE) ? 1 : 0; + pDevice->byOpMode = (pDevice->sOpts.flags & DEVICE_FLAGS_OP_MODE) ? 1 : 0; + pDevice->ePSMode = (pDevice->sOpts.flags & DEVICE_FLAGS_PS_MODE) ? 1 : 0; + pDevice->b11hEnable = (pDevice->sOpts.flags & DEVICE_FLAGS_80211h_MODE) ? 1 : 0; + pDevice->bDiversityRegCtlON = (pDevice->sOpts.flags & DEVICE_FLAGS_DiversityANT) ? 1 : 0; + pDevice->uConnectionRate = pDevice->sOpts.data_rate; + if (pDevice->uConnectionRate < RATE_AUTO) pDevice->bFixRate = TRUE; + pDevice->byBBType = pDevice->sOpts.bbp_type; + pDevice->byPacketType = pDevice->byBBType; + +//PLICE_DEBUG-> + pDevice->byAutoFBCtrl = AUTO_FB_0; + //pDevice->byAutoFBCtrl = AUTO_FB_1; +//PLICE_DEBUG<- +pDevice->bUpdateBBVGA = TRUE; + pDevice->byFOETuning = 0; + pDevice->wCTSDuration = 0; + pDevice->byPreambleType = 0; + + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO" uChannel= %d\n",(INT)pDevice->uChannel); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO" byOpMode= %d\n",(INT)pDevice->byOpMode); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO" ePSMode= %d\n",(INT)pDevice->ePSMode); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO" wRTSThreshold= %d\n",(INT)pDevice->wRTSThreshold); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO" byShortRetryLimit= %d\n",(INT)pDevice->byShortRetryLimit); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO" byLongRetryLimit= %d\n",(INT)pDevice->byLongRetryLimit); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO" byPreambleType= %d\n",(INT)pDevice->byPreambleType); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO" byShortPreamble= %d\n",(INT)pDevice->byShortPreamble); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO" uConnectionRate= %d\n",(INT)pDevice->uConnectionRate); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO" byBBType= %d\n",(INT)pDevice->byBBType); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO" pDevice->b11hEnable= %d\n",(INT)pDevice->b11hEnable); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO" pDevice->bDiversityRegCtlON= %d\n",(INT)pDevice->bDiversityRegCtlON); +} + +static VOID s_vCompleteCurrentMeasure (IN PSDevice pDevice, IN BYTE byResult) +{ + UINT ii; + DWORD dwDuration = 0; + BYTE byRPI0 = 0; + + for(ii=1;ii<8;ii++) { + pDevice->dwRPIs[ii] *= 255; + dwDuration |= *((PWORD) (pDevice->pCurrMeasureEID->sReq.abyDuration)); + dwDuration <<= 10; + pDevice->dwRPIs[ii] /= dwDuration; + pDevice->abyRPIs[ii] = (BYTE) pDevice->dwRPIs[ii]; + byRPI0 += pDevice->abyRPIs[ii]; + } + pDevice->abyRPIs[0] = (0xFF - byRPI0); + + if (pDevice->uNumOfMeasureEIDs == 0) { + VNTWIFIbMeasureReport( pDevice->pMgmt, + TRUE, + pDevice->pCurrMeasureEID, + byResult, + pDevice->byBasicMap, + pDevice->byCCAFraction, + pDevice->abyRPIs + ); + } else { + VNTWIFIbMeasureReport( pDevice->pMgmt, + FALSE, + pDevice->pCurrMeasureEID, + byResult, + pDevice->byBasicMap, + pDevice->byCCAFraction, + pDevice->abyRPIs + ); + CARDbStartMeasure (pDevice, pDevice->pCurrMeasureEID++, pDevice->uNumOfMeasureEIDs); + } + +} + + + +// +// Initialiation of MAC & BBP registers +// + +static void device_init_registers(PSDevice pDevice, DEVICE_INIT_TYPE InitType) +{ + UINT ii; + BYTE byValue; + BYTE byValue1; + BYTE byCCKPwrdBm = 0; + BYTE byOFDMPwrdBm = 0; + INT zonetype=0; + PSMgmtObject pMgmt = &(pDevice->sMgmtObj); + MACbShutdown(pDevice->PortOffset); + BBvSoftwareReset(pDevice->PortOffset); + + if ((InitType == DEVICE_INIT_COLD) || + (InitType == DEVICE_INIT_DXPL)) { + // Do MACbSoftwareReset in MACvInitialize + MACbSoftwareReset(pDevice->PortOffset); + // force CCK + pDevice->bCCK = TRUE; + pDevice->bAES = FALSE; + pDevice->bProtectMode = FALSE; //Only used in 11g type, sync with ERP IE + pDevice->bNonERPPresent = FALSE; + pDevice->bBarkerPreambleMd = FALSE; + pDevice->wCurrentRate = RATE_1M; + pDevice->byTopOFDMBasicRate = RATE_24M; + pDevice->byTopCCKBasicRate = RATE_1M; + + pDevice->byRevId = 0; //Target to IF pin while programming to RF chip. + + // init MAC + MACvInitialize(pDevice->PortOffset); + + // Get Local ID + VNSvInPortB(pDevice->PortOffset + MAC_REG_LOCALID, &(pDevice->byLocalID)); + + spin_lock_irq(&pDevice->lock); + SROMvReadAllContents(pDevice->PortOffset,pDevice->abyEEPROM); + + spin_unlock_irq(&pDevice->lock); + + // Get Channel range + + pDevice->byMinChannel = 1; + pDevice->byMaxChannel = CB_MAX_CHANNEL; + + // Get Antena + byValue = SROMbyReadEmbedded(pDevice->PortOffset, EEP_OFS_ANTENNA); + if (byValue & EEP_ANTINV) + pDevice->bTxRxAntInv = TRUE; + else + pDevice->bTxRxAntInv = FALSE; +#ifdef PLICE_DEBUG + //printk("init_register:TxRxAntInv is %d,byValue is %d\n",pDevice->bTxRxAntInv,byValue); +#endif + + byValue &= (EEP_ANTENNA_AUX | EEP_ANTENNA_MAIN); + if (byValue == 0) // if not set default is All + byValue = (EEP_ANTENNA_AUX | EEP_ANTENNA_MAIN); +#ifdef PLICE_DEBUG + //printk("init_register:byValue is %d\n",byValue); +#endif + pDevice->ulDiversityNValue = 100*260;//100*SROMbyReadEmbedded(pDevice->PortOffset, 0x51); + pDevice->ulDiversityMValue = 100*16;//SROMbyReadEmbedded(pDevice->PortOffset, 0x52); + pDevice->byTMax = 1;//SROMbyReadEmbedded(pDevice->PortOffset, 0x53); + pDevice->byTMax2 = 4;//SROMbyReadEmbedded(pDevice->PortOffset, 0x54); + pDevice->ulSQ3TH = 0;//(ULONG) SROMbyReadEmbedded(pDevice->PortOffset, 0x55); + pDevice->byTMax3 = 64;//SROMbyReadEmbedded(pDevice->PortOffset, 0x56); + + if (byValue == (EEP_ANTENNA_AUX | EEP_ANTENNA_MAIN)) { + pDevice->byAntennaCount = 2; + pDevice->byTxAntennaMode = ANT_B; + pDevice->dwTxAntennaSel = 1; + pDevice->dwRxAntennaSel = 1; + if (pDevice->bTxRxAntInv == TRUE) + pDevice->byRxAntennaMode = ANT_A; + else + pDevice->byRxAntennaMode = ANT_B; + // chester for antenna +byValue1 = SROMbyReadEmbedded(pDevice->PortOffset, EEP_OFS_ANTENNA); + // if (pDevice->bDiversityRegCtlON) + if((byValue1&0x08)==0) + pDevice->bDiversityEnable = FALSE;//SROMbyReadEmbedded(pDevice->PortOffset, 0x50); + else + pDevice->bDiversityEnable = TRUE; +#ifdef PLICE_DEBUG + //printk("aux |main antenna: RxAntennaMode is %d\n",pDevice->byRxAntennaMode); +#endif + } else { + pDevice->bDiversityEnable = FALSE; + pDevice->byAntennaCount = 1; + pDevice->dwTxAntennaSel = 0; + pDevice->dwRxAntennaSel = 0; + if (byValue & EEP_ANTENNA_AUX) { + pDevice->byTxAntennaMode = ANT_A; + if (pDevice->bTxRxAntInv == TRUE) + pDevice->byRxAntennaMode = ANT_B; + else + pDevice->byRxAntennaMode = ANT_A; + } else { + pDevice->byTxAntennaMode = ANT_B; + if (pDevice->bTxRxAntInv == TRUE) + pDevice->byRxAntennaMode = ANT_A; + else + pDevice->byRxAntennaMode = ANT_B; + } + } +#ifdef PLICE_DEBUG + //printk("init registers: TxAntennaMode is %d\n",pDevice->byTxAntennaMode); +#endif + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "bDiversityEnable=[%d],NValue=[%d],MValue=[%d],TMax=[%d],TMax2=[%d]\n", + pDevice->bDiversityEnable,(int)pDevice->ulDiversityNValue,(int)pDevice->ulDiversityMValue,pDevice->byTMax,pDevice->byTMax2); + +//#ifdef ZoneType_DefaultSetting +//2008-8-4 by chester +//zonetype initial + pDevice->byOriginalZonetype = pDevice->abyEEPROM[EEP_OFS_ZONETYPE]; + if((zonetype=Config_FileOperation(pDevice,FALSE,NULL)) >= 0) { //read zonetype file ok! + if ((zonetype == 0)&& + (pDevice->abyEEPROM[EEP_OFS_ZONETYPE] !=0x00)){ //for USA + pDevice->abyEEPROM[EEP_OFS_ZONETYPE] = 0; + pDevice->abyEEPROM[EEP_OFS_MAXCHANNEL] = 0x0B; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Init Zone Type :USA\n"); + } + else if((zonetype == 1)&& + (pDevice->abyEEPROM[EEP_OFS_ZONETYPE]!=0x01)){ //for Japan + pDevice->abyEEPROM[EEP_OFS_ZONETYPE] = 0x01; + pDevice->abyEEPROM[EEP_OFS_MAXCHANNEL] = 0x0D; + } + else if((zonetype == 2)&& + (pDevice->abyEEPROM[EEP_OFS_ZONETYPE]!=0x02)){ //for Europe + pDevice->abyEEPROM[EEP_OFS_ZONETYPE] = 0x02; + pDevice->abyEEPROM[EEP_OFS_MAXCHANNEL] = 0x0D; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Init Zone Type :Europe\n"); + } + +else +{ + if(zonetype!=pDevice->abyEEPROM[EEP_OFS_ZONETYPE]) + printk("zonetype in file[%02x] mismatch with in EEPROM[%02x]\n",zonetype,pDevice->abyEEPROM[EEP_OFS_ZONETYPE]); + else + printk("Read Zonetype file sucess,use default zonetype setting[%02x]\n",zonetype); + } + } + else + printk("Read Zonetype file fail,use default zonetype setting[%02x]\n",SROMbyReadEmbedded(pDevice->PortOffset, EEP_OFS_ZONETYPE)); + + // Get RFType + pDevice->byRFType = SROMbyReadEmbedded(pDevice->PortOffset, EEP_OFS_RFTYPE); + + if ((pDevice->byRFType & RF_EMU) != 0) { + // force change RevID for VT3253 emu + pDevice->byRevId = 0x80; + } + + pDevice->byRFType &= RF_MASK; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pDevice->byRFType = %x\n", pDevice->byRFType); + + if (pDevice->bZoneRegExist == FALSE) { + pDevice->byZoneType = pDevice->abyEEPROM[EEP_OFS_ZONETYPE]; + } + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pDevice->byZoneType = %x\n", pDevice->byZoneType); + + //Init RF module + RFbInit(pDevice); + + //Get Desire Power Value + pDevice->byCurPwr = 0xFF; + pDevice->byCCKPwr = SROMbyReadEmbedded(pDevice->PortOffset, EEP_OFS_PWR_CCK); + pDevice->byOFDMPwrG = SROMbyReadEmbedded(pDevice->PortOffset, EEP_OFS_PWR_OFDMG); + //byCCKPwrdBm = SROMbyReadEmbedded(pDevice->PortOffset, EEP_OFS_CCK_PWR_dBm); + + //byOFDMPwrdBm = SROMbyReadEmbedded(pDevice->PortOffset, EEP_OFS_OFDM_PWR_dBm); +//printk("CCKPwrdBm is 0x%x,byOFDMPwrdBm is 0x%x\n",byCCKPwrdBm,byOFDMPwrdBm); + // Load power Table + + + for (ii=0;iiabyCCKPwrTbl[ii+1] = SROMbyReadEmbedded(pDevice->PortOffset, (BYTE)(ii + EEP_OFS_CCK_PWR_TBL)); + if (pDevice->abyCCKPwrTbl[ii+1] == 0) { + pDevice->abyCCKPwrTbl[ii+1] = pDevice->byCCKPwr; + } + pDevice->abyOFDMPwrTbl[ii+1] = SROMbyReadEmbedded(pDevice->PortOffset, (BYTE)(ii + EEP_OFS_OFDM_PWR_TBL)); + if (pDevice->abyOFDMPwrTbl[ii+1] == 0) { + pDevice->abyOFDMPwrTbl[ii+1] = pDevice->byOFDMPwrG; + } + pDevice->abyCCKDefaultPwr[ii+1] = byCCKPwrdBm; + pDevice->abyOFDMDefaultPwr[ii+1] = byOFDMPwrdBm; + } + //2008-8-4 by chester + //recover 12,13 ,14channel for EUROPE by 11 channel + if(((pDevice->abyEEPROM[EEP_OFS_ZONETYPE] == ZoneType_Japan) || + (pDevice->abyEEPROM[EEP_OFS_ZONETYPE] == ZoneType_Europe))&& + (pDevice->byOriginalZonetype == ZoneType_USA)) { + for(ii=11;ii<14;ii++) { + pDevice->abyCCKPwrTbl[ii] = pDevice->abyCCKPwrTbl[10]; + pDevice->abyOFDMPwrTbl[ii] = pDevice->abyOFDMPwrTbl[10]; + + } + } + + + // Load OFDM A Power Table + for (ii=0;iiabyOFDMPwrTbl[ii+CB_MAX_CHANNEL_24G+1] = SROMbyReadEmbedded(pDevice->PortOffset, (BYTE)(ii + EEP_OFS_OFDMA_PWR_TBL)); + pDevice->abyOFDMDefaultPwr[ii+CB_MAX_CHANNEL_24G+1] = SROMbyReadEmbedded(pDevice->PortOffset, (BYTE)(ii + EEP_OFS_OFDMA_PWR_dBm)); + } + CARDvInitChannelTable((PVOID)pDevice); + + + if (pDevice->byLocalID > REV_ID_VT3253_B1) { + MACvSelectPage1(pDevice->PortOffset); + VNSvOutPortB(pDevice->PortOffset + MAC_REG_MSRCTL + 1, (MSRCTL1_TXPWR | MSRCTL1_CSAPAREN)); + MACvSelectPage0(pDevice->PortOffset); + } + + + // use relative tx timeout and 802.11i D4 + MACvWordRegBitsOn(pDevice->PortOffset, MAC_REG_CFG, (CFG_TKIPOPT | CFG_NOTXTIMEOUT)); + + // set performance parameter by registry + MACvSetShortRetryLimit(pDevice->PortOffset, pDevice->byShortRetryLimit); + MACvSetLongRetryLimit(pDevice->PortOffset, pDevice->byLongRetryLimit); + + // reset TSF counter + VNSvOutPortB(pDevice->PortOffset + MAC_REG_TFTCTL, TFTCTL_TSFCNTRST); + // enable TSF counter + VNSvOutPortB(pDevice->PortOffset + MAC_REG_TFTCTL, TFTCTL_TSFCNTREN); + + // initialize BBP registers + BBbVT3253Init(pDevice); + + if (pDevice->bUpdateBBVGA) { + pDevice->byBBVGACurrent = pDevice->abyBBVGA[0]; + pDevice->byBBVGANew = pDevice->byBBVGACurrent; + BBvSetVGAGainOffset(pDevice, pDevice->abyBBVGA[0]); + } +#ifdef PLICE_DEBUG + //printk("init registers:RxAntennaMode is %x,TxAntennaMode is %x\n",pDevice->byRxAntennaMode,pDevice->byTxAntennaMode); +#endif + BBvSetRxAntennaMode(pDevice->PortOffset, pDevice->byRxAntennaMode); + BBvSetTxAntennaMode(pDevice->PortOffset, pDevice->byTxAntennaMode); + + pDevice->byCurrentCh = 0; + + //pDevice->NetworkType = Ndis802_11Automode; + // Set BB and packet type at the same time. + // Set Short Slot Time, xIFS, and RSPINF. + if (pDevice->uConnectionRate == RATE_AUTO) { + pDevice->wCurrentRate = RATE_54M; + } else { + pDevice->wCurrentRate = (WORD)pDevice->uConnectionRate; + } + + // default G Mode + VNTWIFIbConfigPhyMode(pDevice->pMgmt, PHY_TYPE_11G); + VNTWIFIbConfigPhyMode(pDevice->pMgmt, PHY_TYPE_AUTO); + + pDevice->bRadioOff = FALSE; + + pDevice->byRadioCtl = SROMbyReadEmbedded(pDevice->PortOffset, EEP_OFS_RADIOCTL); + pDevice->bHWRadioOff = FALSE; + + if (pDevice->byRadioCtl & EEP_RADIOCTL_ENABLE) { + // Get GPIO + MACvGPIOIn(pDevice->PortOffset, &pDevice->byGPIO); +//2008-4-14 by chester for led issue + #ifdef FOR_LED_ON_NOTEBOOK +if (BITbIsBitOn(pDevice->byGPIO,GPIO0_DATA)){pDevice->bHWRadioOff = TRUE;} +if (BITbIsBitOff(pDevice->byGPIO,GPIO0_DATA)){pDevice->bHWRadioOff = FALSE;} + + } + if ( (pDevice->bRadioControlOff == TRUE)) { + CARDbRadioPowerOff(pDevice); + } +else CARDbRadioPowerOn(pDevice); +#else + if ((BITbIsBitOn(pDevice->byGPIO,GPIO0_DATA) && BITbIsBitOff(pDevice->byRadioCtl, EEP_RADIOCTL_INV)) || + (BITbIsBitOff(pDevice->byGPIO,GPIO0_DATA) && BITbIsBitOn(pDevice->byRadioCtl, EEP_RADIOCTL_INV))) { + pDevice->bHWRadioOff = TRUE; + } + } + if ((pDevice->bHWRadioOff == TRUE) || (pDevice->bRadioControlOff == TRUE)) { + CARDbRadioPowerOff(pDevice); + } + +#endif + } + pMgmt->eScanType = WMAC_SCAN_PASSIVE; + // get Permanent network address + SROMvReadEtherAddress(pDevice->PortOffset, pDevice->abyCurrentNetAddr); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Network address = %02x-%02x-%02x=%02x-%02x-%02x\n", + pDevice->abyCurrentNetAddr[0], + pDevice->abyCurrentNetAddr[1], + pDevice->abyCurrentNetAddr[2], + pDevice->abyCurrentNetAddr[3], + pDevice->abyCurrentNetAddr[4], + pDevice->abyCurrentNetAddr[5]); + + + // reset Tx pointer + CARDvSafeResetRx(pDevice); + // reset Rx pointer + CARDvSafeResetTx(pDevice); + + if (pDevice->byLocalID <= REV_ID_VT3253_A1) { + MACvRegBitsOn(pDevice->PortOffset, MAC_REG_RCR, RCR_WPAERR); + } + + pDevice->eEncryptionStatus = Ndis802_11EncryptionDisabled; + + // Turn On Rx DMA + MACvReceive0(pDevice->PortOffset); + MACvReceive1(pDevice->PortOffset); + + // start the adapter + MACvStart(pDevice->PortOffset); + + netif_stop_queue(pDevice->dev); + + +} + + + +static VOID device_init_diversity_timer(PSDevice pDevice) { + + init_timer(&pDevice->TimerSQ3Tmax1); + pDevice->TimerSQ3Tmax1.data = (ULONG)pDevice; + pDevice->TimerSQ3Tmax1.function = (TimerFunction)TimerSQ3CallBack; + pDevice->TimerSQ3Tmax1.expires = RUN_AT(HZ); + + init_timer(&pDevice->TimerSQ3Tmax2); + pDevice->TimerSQ3Tmax2.data = (ULONG)pDevice; + pDevice->TimerSQ3Tmax2.function = (TimerFunction)TimerSQ3CallBack; + pDevice->TimerSQ3Tmax2.expires = RUN_AT(HZ); + + init_timer(&pDevice->TimerSQ3Tmax3); + pDevice->TimerSQ3Tmax3.data = (ULONG)pDevice; + pDevice->TimerSQ3Tmax3.function = (TimerFunction)TimerState1CallBack; + pDevice->TimerSQ3Tmax3.expires = RUN_AT(HZ); + + return; +} + + +static BOOL device_release_WPADEV(PSDevice pDevice) +{ + viawget_wpa_header *wpahdr; + int ii=0; + // wait_queue_head_t Set_wait; + //send device close to wpa_supplicnat layer + if (pDevice->bWPADEVUp==TRUE) { + wpahdr = (viawget_wpa_header *)pDevice->skb->data; + wpahdr->type = VIAWGET_DEVICECLOSE_MSG; + wpahdr->resp_ie_len = 0; + wpahdr->req_ie_len = 0; + skb_put(pDevice->skb, sizeof(viawget_wpa_header)); + pDevice->skb->dev = pDevice->wpadev; + pDevice->skb->mac_header = pDevice->skb->data; + pDevice->skb->pkt_type = PACKET_HOST; + pDevice->skb->protocol = htons(ETH_P_802_2); + memset(pDevice->skb->cb, 0, sizeof(pDevice->skb->cb)); + netif_rx(pDevice->skb); + pDevice->skb = dev_alloc_skb((int)pDevice->rx_buf_sz); + + //wait release WPADEV + // init_waitqueue_head(&Set_wait); + // wait_event_timeout(Set_wait, ((pDevice->wpadev==NULL)&&(pDevice->skb == NULL)),5*HZ); //1s wait + while((pDevice->bWPADEVUp==TRUE)) { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout (HZ/20); //wait 50ms + ii++; + if(ii>20) + break; + } + }; + return TRUE; +} + + +static const struct net_device_ops device_netdev_ops = { + .ndo_open = device_open, + .ndo_stop = device_close, + .ndo_do_ioctl = device_ioctl, + .ndo_get_stats = device_get_stats, + .ndo_start_xmit = device_xmit, + .ndo_set_multicast_list = device_set_multi, +}; + + +#ifndef PRIVATE_OBJ + +static int +device_found1(struct pci_dev *pcid, const struct pci_device_id *ent) +{ + static BOOL bFirst = TRUE; + struct net_device* dev = NULL; + PCHIP_INFO pChip_info = (PCHIP_INFO)ent->driver_data; + PSDevice pDevice; + int rc; + if (device_nics ++>= MAX_UINTS) { + printk(KERN_NOTICE DEVICE_NAME ": already found %d NICs\n", device_nics); + return -ENODEV; + } + + + dev = alloc_etherdev(sizeof(DEVICE_INFO)); + + pDevice = (PSDevice) netdev_priv(dev); + + if (dev == NULL) { + printk(KERN_ERR DEVICE_NAME ": allocate net device failed \n"); + return -ENODEV; + } + + // Chain it all together + // SET_MODULE_OWNER(dev); + SET_NETDEV_DEV(dev, &pcid->dev); + + if (bFirst) { + printk(KERN_NOTICE "%s Ver. %s\n",DEVICE_FULL_DRV_NAM, DEVICE_VERSION); + printk(KERN_NOTICE "Copyright (c) 2003 VIA Networking Technologies, Inc.\n"); + bFirst=FALSE; + } + + if (!device_init_info(pcid, &pDevice, pChip_info)) { + return -ENOMEM; + } + pDevice->dev = dev; + pDevice->next_module = root_device_dev; + root_device_dev = dev; + dev->irq = pcid->irq; + + if (pci_enable_device(pcid)) { + device_free_info(pDevice); + return -ENODEV; + } +#ifdef DEBUG + printk("Before get pci_info memaddr is %x\n",pDevice->memaddr); +#endif + if (device_get_pci_info(pDevice,pcid) == FALSE) { + printk(KERN_ERR DEVICE_NAME ": Failed to find PCI device.\n"); + device_free_info(pDevice); + return -ENODEV; + } + +#if 1 + +#ifdef DEBUG + + //pci_read_config_byte(pcid, PCI_BASE_ADDRESS_0, &pDevice->byRevId); + printk("after get pci_info memaddr is %x, io addr is %x,io_size is %d\n",pDevice->memaddr,pDevice->ioaddr,pDevice->io_size); + { + int i; + U32 bar,len; + u32 address[] = { + PCI_BASE_ADDRESS_0, + PCI_BASE_ADDRESS_1, + PCI_BASE_ADDRESS_2, + PCI_BASE_ADDRESS_3, + PCI_BASE_ADDRESS_4, + PCI_BASE_ADDRESS_5, + 0}; + for (i=0;address[i];i++) + { + //pci_write_config_dword(pcid,address[i], 0xFFFFFFFF); + pci_read_config_dword(pcid, address[i], &bar); + printk("bar %d is %x\n",i,bar); + if (!bar) + { + printk("bar %d not implemented\n",i); + continue; + } + if (bar & PCI_BASE_ADDRESS_SPACE_IO) { + /* This is IO */ + + len = bar & (PCI_BASE_ADDRESS_IO_MASK & 0xFFFF); + len = len & ~(len - 1); + + printk("IO space: len in IO %x, BAR %d\n", len, i); + } + else + { + len = bar & 0xFFFFFFF0; + len = ~len + 1; + + printk("len in MEM %x, BAR %d\n", len, i); + } + } + } +#endif + + +#endif + +#ifdef DEBUG + //return 0 ; +#endif + pDevice->PortOffset = (DWORD)ioremap(pDevice->memaddr & PCI_BASE_ADDRESS_MEM_MASK, pDevice->io_size); + //pDevice->PortOffset = (DWORD)ioremap(pDevice->ioaddr & PCI_BASE_ADDRESS_IO_MASK, pDevice->io_size); + + if(pDevice->PortOffset == 0) { + printk(KERN_ERR DEVICE_NAME ": Failed to IO remapping ..\n"); + device_free_info(pDevice); + return -ENODEV; + } + + + + + rc = pci_request_regions(pcid, DEVICE_NAME); + if (rc) { + printk(KERN_ERR DEVICE_NAME ": Failed to find PCI device\n"); + device_free_info(pDevice); + return -ENODEV; + } + + dev->base_addr = pDevice->ioaddr; +#ifdef PLICE_DEBUG + BYTE value; + + VNSvInPortB(pDevice->PortOffset+0x4F, &value); + printk("Before write: value is %x\n",value); + //VNSvInPortB(pDevice->PortOffset+0x3F, 0x00); + VNSvOutPortB(pDevice->PortOffset,value); + VNSvInPortB(pDevice->PortOffset+0x4F, &value); + printk("After write: value is %x\n",value); +#endif + + + +#ifdef IO_MAP + pDevice->PortOffset = pDevice->ioaddr; +#endif + // do reset + if (!MACbSoftwareReset(pDevice->PortOffset)) { + printk(KERN_ERR DEVICE_NAME ": Failed to access MAC hardware..\n"); + device_free_info(pDevice); + return -ENODEV; + } + // initial to reload eeprom + MACvInitialize(pDevice->PortOffset); + MACvReadEtherAddress(pDevice->PortOffset, dev->dev_addr); + + device_get_options(pDevice, device_nics-1, dev->name); + device_set_options(pDevice); + //Mask out the options cannot be set to the chip + pDevice->sOpts.flags &= pChip_info->flags; + + //Enable the chip specified capbilities + pDevice->flags = pDevice->sOpts.flags | (pChip_info->flags & 0xFF000000UL); + pDevice->tx_80211 = device_dma0_tx_80211; + pDevice->sMgmtObj.pAdapter = (PVOID)pDevice; + pDevice->pMgmt = &(pDevice->sMgmtObj); + + dev->irq = pcid->irq; + dev->netdev_ops = &device_netdev_ops; + +#ifdef WIRELESS_EXT +//Einsn Modify for ubuntu-7.04 +// dev->wireless_handlers->get_wireless_stats = iwctl_get_wireless_stats; +#if WIRELESS_EXT > 12 + dev->wireless_handlers = (struct iw_handler_def *)&iwctl_handler_def; +// netdev->wireless_handlers = NULL; +#endif /* WIRELESS_EXT > 12 */ +#endif /* WIRELESS_EXT */ + + rc = register_netdev(dev); + if (rc) + { + printk(KERN_ERR DEVICE_NAME " Failed to register netdev\n"); + device_free_info(pDevice); + return -ENODEV; + } +//2008-07-21-01by MikeLiu +//register wpadev + if(wpa_set_wpadev(pDevice, 1)!=0) { + printk("Fail to Register WPADEV?\n"); + unregister_netdev(pDevice->dev); + free_netdev(dev); + } + device_print_info(pDevice); + pci_set_drvdata(pcid, pDevice); + return 0; + +} + +static void device_print_info(PSDevice pDevice) +{ + struct net_device* dev=pDevice->dev; + + DEVICE_PRT(MSG_LEVEL_INFO, KERN_INFO "%s: %s\n",dev->name, get_chip_name(pDevice->chip_id)); + DEVICE_PRT(MSG_LEVEL_INFO, KERN_INFO "%s: MAC=%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X", + dev->name, + dev->dev_addr[0],dev->dev_addr[1],dev->dev_addr[2], + dev->dev_addr[3],dev->dev_addr[4],dev->dev_addr[5]); +#ifdef IO_MAP + DEVICE_PRT(MSG_LEVEL_INFO, KERN_INFO" IO=0x%lx ",(ULONG) pDevice->ioaddr); + DEVICE_PRT(MSG_LEVEL_INFO, KERN_INFO" IRQ=%d \n", pDevice->dev->irq); +#else + DEVICE_PRT(MSG_LEVEL_INFO, KERN_INFO" IO=0x%lx Mem=0x%lx ",(ULONG) pDevice->ioaddr,(ULONG) pDevice->PortOffset); + DEVICE_PRT(MSG_LEVEL_INFO, KERN_INFO" IRQ=%d \n", pDevice->dev->irq); +#endif + +} + +static BOOL device_init_info(struct pci_dev* pcid, PSDevice* ppDevice, + PCHIP_INFO pChip_info) { + + PSDevice p; + + memset(*ppDevice,0,sizeof(DEVICE_INFO)); + + if (pDevice_Infos == NULL) { + pDevice_Infos =*ppDevice; + } + else { + for (p=pDevice_Infos;p->next!=NULL;p=p->next) + do {} while (0); + p->next = *ppDevice; + (*ppDevice)->prev = p; + } + + (*ppDevice)->pcid = pcid; + (*ppDevice)->chip_id = pChip_info->chip_id; + (*ppDevice)->io_size = pChip_info->io_size; + (*ppDevice)->nTxQueues = pChip_info->nTxQueue; + (*ppDevice)->multicast_limit =32; + + spin_lock_init(&((*ppDevice)->lock)); + + return TRUE; +} + +static BOOL device_get_pci_info(PSDevice pDevice, struct pci_dev* pcid) { + + U16 pci_cmd; + U8 b; + UINT cis_addr; +#ifdef PLICE_DEBUG + BYTE pci_config[256]; + BYTE value =0x00; + int ii,j; + U16 max_lat=0x0000; + memset(pci_config,0x00,256); +#endif + + pci_read_config_byte(pcid, PCI_REVISION_ID, &pDevice->byRevId); + pci_read_config_word(pcid, PCI_SUBSYSTEM_ID,&pDevice->SubSystemID); + pci_read_config_word(pcid, PCI_SUBSYSTEM_VENDOR_ID, &pDevice->SubVendorID); + pci_read_config_word(pcid, PCI_COMMAND, (u16 *) & (pci_cmd)); + + pci_set_master(pcid); + + pDevice->memaddr = pci_resource_start(pcid,0); + pDevice->ioaddr = pci_resource_start(pcid,1); + +#ifdef DEBUG +// pDevice->ioaddr = pci_resource_start(pcid, 0); +// pDevice->memaddr = pci_resource_start(pcid,1); +#endif + + cis_addr = pci_resource_start(pcid,2); + + pDevice->pcid = pcid; + + pci_read_config_byte(pcid, PCI_REG_COMMAND, &b); + pci_write_config_byte(pcid, PCI_REG_COMMAND, (b|COMMAND_BUSM)); + +#ifdef PLICE_DEBUG + //pci_read_config_word(pcid,PCI_REG_MAX_LAT,&max_lat); + //printk("max lat is %x,SubSystemID is %x\n",max_lat,pDevice->SubSystemID); + //for (ii=0;ii<0xFF;ii++) + //pci_read_config_word(pcid,PCI_REG_MAX_LAT,&max_lat); + //max_lat = 0x20; + //pci_write_config_word(pcid,PCI_REG_MAX_LAT,max_lat); + //pci_read_config_word(pcid,PCI_REG_MAX_LAT,&max_lat); + //printk("max lat is %x\n",max_lat); + + for (ii=0;ii<0xFF;ii++) + { + pci_read_config_byte(pcid,ii,&value); + pci_config[ii] = value; + } + for (ii=0,j=1;ii<0x100;ii++,j++) + { + if (j %16 == 0) + { + printk("%x:",pci_config[ii]); + printk("\n"); + } + else + { + printk("%x:",pci_config[ii]); + } + } +#endif + return TRUE; +} + +static void device_free_info(PSDevice pDevice) { + PSDevice ptr; + struct net_device* dev=pDevice->dev; + + ASSERT(pDevice); +//2008-0714-01by chester +device_release_WPADEV(pDevice); + +//2008-07-21-01by MikeLiu +//unregister wpadev + if(wpa_set_wpadev(pDevice, 0)!=0) + printk("unregister wpadev fail?\n"); + + if (pDevice_Infos==NULL) + return; + + for (ptr=pDevice_Infos;ptr && (ptr!=pDevice);ptr=ptr->next) + do {} while (0); + + if (ptr==pDevice) { + if (ptr==pDevice_Infos) + pDevice_Infos=ptr->next; + else + ptr->prev->next=ptr->next; + } + else { + DEVICE_PRT(MSG_LEVEL_ERR, KERN_ERR "info struct not found\n"); + return; + } +#ifdef HOSTAP + if (dev) + hostap_set_hostapd(pDevice, 0, 0); +#endif + if (dev) + unregister_netdev(dev); + + if (pDevice->PortOffset) + iounmap((PVOID)pDevice->PortOffset); + + if (pDevice->pcid) + pci_release_regions(pDevice->pcid); + if (dev) + free_netdev(dev); + + if (pDevice->pcid) { + pci_set_drvdata(pDevice->pcid,NULL); + } +} +#endif// ifndef PRIVATE_OBJ + +static BOOL device_init_rings(PSDevice pDevice) { + void* vir_pool; + + + /*allocate all RD/TD rings a single pool*/ + vir_pool = pci_alloc_consistent(pDevice->pcid, + pDevice->sOpts.nRxDescs0 * sizeof(SRxDesc) + + pDevice->sOpts.nRxDescs1 * sizeof(SRxDesc) + + pDevice->sOpts.nTxDescs[0] * sizeof(STxDesc) + + pDevice->sOpts.nTxDescs[1] * sizeof(STxDesc), + &pDevice->pool_dma); + + if (vir_pool == NULL) { + DEVICE_PRT(MSG_LEVEL_ERR,KERN_ERR "%s : allocate desc dma memory failed\n", pDevice->dev->name); + return FALSE; + } + + memset(vir_pool, 0, + pDevice->sOpts.nRxDescs0 * sizeof(SRxDesc) + + pDevice->sOpts.nRxDescs1 * sizeof(SRxDesc) + + pDevice->sOpts.nTxDescs[0] * sizeof(STxDesc) + + pDevice->sOpts.nTxDescs[1] * sizeof(STxDesc) + ); + + pDevice->aRD0Ring = vir_pool; + pDevice->aRD1Ring = vir_pool + + pDevice->sOpts.nRxDescs0 * sizeof(SRxDesc); + + + pDevice->rd0_pool_dma = pDevice->pool_dma; + pDevice->rd1_pool_dma = pDevice->rd0_pool_dma + + pDevice->sOpts.nRxDescs0 * sizeof(SRxDesc); + + pDevice->tx0_bufs = pci_alloc_consistent(pDevice->pcid, + pDevice->sOpts.nTxDescs[0] * PKT_BUF_SZ + + pDevice->sOpts.nTxDescs[1] * PKT_BUF_SZ + + CB_BEACON_BUF_SIZE + + CB_MAX_BUF_SIZE, + &pDevice->tx_bufs_dma0); + + if (pDevice->tx0_bufs == NULL) { + DEVICE_PRT(MSG_LEVEL_ERR,KERN_ERR "%s: allocate buf dma memory failed\n", pDevice->dev->name); + pci_free_consistent(pDevice->pcid, + pDevice->sOpts.nRxDescs0 * sizeof(SRxDesc) + + pDevice->sOpts.nRxDescs1 * sizeof(SRxDesc) + + pDevice->sOpts.nTxDescs[0] * sizeof(STxDesc) + + pDevice->sOpts.nTxDescs[1] * sizeof(STxDesc), + vir_pool, pDevice->pool_dma + ); + return FALSE; + } + + memset(pDevice->tx0_bufs, 0, + pDevice->sOpts.nTxDescs[0] * PKT_BUF_SZ + + pDevice->sOpts.nTxDescs[1] * PKT_BUF_SZ + + CB_BEACON_BUF_SIZE + + CB_MAX_BUF_SIZE + ); + + pDevice->td0_pool_dma = pDevice->rd1_pool_dma + + pDevice->sOpts.nRxDescs1 * sizeof(SRxDesc); + + pDevice->td1_pool_dma = pDevice->td0_pool_dma + + pDevice->sOpts.nTxDescs[0] * sizeof(STxDesc); + + + // vir_pool: pvoid type + pDevice->apTD0Rings = vir_pool + + pDevice->sOpts.nRxDescs0 * sizeof(SRxDesc) + + pDevice->sOpts.nRxDescs1 * sizeof(SRxDesc); + + pDevice->apTD1Rings = vir_pool + + pDevice->sOpts.nRxDescs0 * sizeof(SRxDesc) + + pDevice->sOpts.nRxDescs1 * sizeof(SRxDesc) + + pDevice->sOpts.nTxDescs[0] * sizeof(STxDesc); + + + pDevice->tx1_bufs = pDevice->tx0_bufs + + pDevice->sOpts.nTxDescs[0] * PKT_BUF_SZ; + + + pDevice->tx_beacon_bufs = pDevice->tx1_bufs + + pDevice->sOpts.nTxDescs[1] * PKT_BUF_SZ; + + pDevice->pbyTmpBuff = pDevice->tx_beacon_bufs + + CB_BEACON_BUF_SIZE; + + pDevice->tx_bufs_dma1 = pDevice->tx_bufs_dma0 + + pDevice->sOpts.nTxDescs[0] * PKT_BUF_SZ; + + + pDevice->tx_beacon_dma = pDevice->tx_bufs_dma1 + + pDevice->sOpts.nTxDescs[1] * PKT_BUF_SZ; + + + return TRUE; +} + +static void device_free_rings(PSDevice pDevice) { + + pci_free_consistent(pDevice->pcid, + pDevice->sOpts.nRxDescs0 * sizeof(SRxDesc) + + pDevice->sOpts.nRxDescs1 * sizeof(SRxDesc) + + pDevice->sOpts.nTxDescs[0] * sizeof(STxDesc) + + pDevice->sOpts.nTxDescs[1] * sizeof(STxDesc) + , + pDevice->aRD0Ring, pDevice->pool_dma + ); + + if (pDevice->tx0_bufs) + pci_free_consistent(pDevice->pcid, + pDevice->sOpts.nTxDescs[0] * PKT_BUF_SZ + + pDevice->sOpts.nTxDescs[1] * PKT_BUF_SZ + + CB_BEACON_BUF_SIZE + + CB_MAX_BUF_SIZE, + pDevice->tx0_bufs, pDevice->tx_bufs_dma0 + ); +} + +static void device_init_rd0_ring(PSDevice pDevice) { + int i; + dma_addr_t curr = pDevice->rd0_pool_dma; + PSRxDesc pDesc; + + /* Init the RD0 ring entries */ + for (i = 0; i < pDevice->sOpts.nRxDescs0; i ++, curr += sizeof(SRxDesc)) { + pDesc = &(pDevice->aRD0Ring[i]); + pDesc->pRDInfo = alloc_rd_info(); + ASSERT(pDesc->pRDInfo); + if (!device_alloc_rx_buf(pDevice, pDesc)) { + DEVICE_PRT(MSG_LEVEL_ERR,KERN_ERR "%s: can not alloc rx bufs\n", + pDevice->dev->name); + } + pDesc->next = &(pDevice->aRD0Ring[(i+1) % pDevice->sOpts.nRxDescs0]); + pDesc->pRDInfo->curr_desc = cpu_to_le32(curr); + pDesc->next_desc = cpu_to_le32(curr + sizeof(SRxDesc)); + } + + pDevice->aRD0Ring[i-1].next_desc = cpu_to_le32(pDevice->rd0_pool_dma); + pDevice->pCurrRD[0] = &(pDevice->aRD0Ring[0]); +} + + +static void device_init_rd1_ring(PSDevice pDevice) { + int i; + dma_addr_t curr = pDevice->rd1_pool_dma; + PSRxDesc pDesc; + + /* Init the RD1 ring entries */ + for (i = 0; i < pDevice->sOpts.nRxDescs1; i ++, curr += sizeof(SRxDesc)) { + pDesc = &(pDevice->aRD1Ring[i]); + pDesc->pRDInfo = alloc_rd_info(); + ASSERT(pDesc->pRDInfo); + if (!device_alloc_rx_buf(pDevice, pDesc)) { + DEVICE_PRT(MSG_LEVEL_ERR,KERN_ERR "%s: can not alloc rx bufs\n", + pDevice->dev->name); + } + pDesc->next = &(pDevice->aRD1Ring[(i+1) % pDevice->sOpts.nRxDescs1]); + pDesc->pRDInfo->curr_desc = cpu_to_le32(curr); + pDesc->next_desc = cpu_to_le32(curr + sizeof(SRxDesc)); + } + + pDevice->aRD1Ring[i-1].next_desc = cpu_to_le32(pDevice->rd1_pool_dma); + pDevice->pCurrRD[1] = &(pDevice->aRD1Ring[0]); +} + + +static void device_init_defrag_cb(PSDevice pDevice) { + int i; + PSDeFragControlBlock pDeF; + + /* Init the fragment ctl entries */ + for (i = 0; i < CB_MAX_RX_FRAG; i++) { + pDeF = &(pDevice->sRxDFCB[i]); + if (!device_alloc_frag_buf(pDevice, pDeF)) { + DEVICE_PRT(MSG_LEVEL_ERR,KERN_ERR "%s: can not alloc frag bufs\n", + pDevice->dev->name); + }; + } + pDevice->cbDFCB = CB_MAX_RX_FRAG; + pDevice->cbFreeDFCB = pDevice->cbDFCB; +} + + + + +static void device_free_rd0_ring(PSDevice pDevice) { + int i; + + for (i = 0; i < pDevice->sOpts.nRxDescs0; i++) { + PSRxDesc pDesc =&(pDevice->aRD0Ring[i]); + PDEVICE_RD_INFO pRDInfo =pDesc->pRDInfo; + + pci_unmap_single(pDevice->pcid,pRDInfo->skb_dma, + pDevice->rx_buf_sz, PCI_DMA_FROMDEVICE); + + dev_kfree_skb(pRDInfo->skb); + + kfree((PVOID)pDesc->pRDInfo); + } + +} + +static void device_free_rd1_ring(PSDevice pDevice) { + int i; + + + for (i = 0; i < pDevice->sOpts.nRxDescs1; i++) { + PSRxDesc pDesc=&(pDevice->aRD1Ring[i]); + PDEVICE_RD_INFO pRDInfo=pDesc->pRDInfo; + + pci_unmap_single(pDevice->pcid,pRDInfo->skb_dma, + pDevice->rx_buf_sz, PCI_DMA_FROMDEVICE); + + dev_kfree_skb(pRDInfo->skb); + + kfree((PVOID)pDesc->pRDInfo); + } + +} + +static void device_free_frag_buf(PSDevice pDevice) { + PSDeFragControlBlock pDeF; + int i; + + for (i = 0; i < CB_MAX_RX_FRAG; i++) { + + pDeF = &(pDevice->sRxDFCB[i]); + + if (pDeF->skb) + dev_kfree_skb(pDeF->skb); + + } + +} + +static void device_init_td0_ring(PSDevice pDevice) { + int i; + dma_addr_t curr; + PSTxDesc pDesc; + + curr = pDevice->td0_pool_dma; + for (i = 0; i < pDevice->sOpts.nTxDescs[0]; i++, curr += sizeof(STxDesc)) { + pDesc = &(pDevice->apTD0Rings[i]); + pDesc->pTDInfo = alloc_td_info(); + ASSERT(pDesc->pTDInfo); + if (pDevice->flags & DEVICE_FLAGS_TX_ALIGN) { + pDesc->pTDInfo->buf = pDevice->tx0_bufs + (i)*PKT_BUF_SZ; + pDesc->pTDInfo->buf_dma = pDevice->tx_bufs_dma0 + (i)*PKT_BUF_SZ; + } + pDesc->next =&(pDevice->apTD0Rings[(i+1) % pDevice->sOpts.nTxDescs[0]]); + pDesc->pTDInfo->curr_desc = cpu_to_le32(curr); + pDesc->next_desc = cpu_to_le32(curr+sizeof(STxDesc)); + } + + pDevice->apTD0Rings[i-1].next_desc = cpu_to_le32(pDevice->td0_pool_dma); + pDevice->apTailTD[0] = pDevice->apCurrTD[0] =&(pDevice->apTD0Rings[0]); + +} + +static void device_init_td1_ring(PSDevice pDevice) { + int i; + dma_addr_t curr; + PSTxDesc pDesc; + + /* Init the TD ring entries */ + curr=pDevice->td1_pool_dma; + for (i = 0; i < pDevice->sOpts.nTxDescs[1]; i++, curr+=sizeof(STxDesc)) { + pDesc=&(pDevice->apTD1Rings[i]); + pDesc->pTDInfo = alloc_td_info(); + ASSERT(pDesc->pTDInfo); + if (pDevice->flags & DEVICE_FLAGS_TX_ALIGN) { + pDesc->pTDInfo->buf=pDevice->tx1_bufs+(i)*PKT_BUF_SZ; + pDesc->pTDInfo->buf_dma=pDevice->tx_bufs_dma1+(i)*PKT_BUF_SZ; + } + pDesc->next=&(pDevice->apTD1Rings[(i+1) % pDevice->sOpts.nTxDescs[1]]); + pDesc->pTDInfo->curr_desc = cpu_to_le32(curr); + pDesc->next_desc = cpu_to_le32(curr+sizeof(STxDesc)); + } + + pDevice->apTD1Rings[i-1].next_desc = cpu_to_le32(pDevice->td1_pool_dma); + pDevice->apTailTD[1] = pDevice->apCurrTD[1] = &(pDevice->apTD1Rings[0]); +} + + + +static void device_free_td0_ring(PSDevice pDevice) { + int i; + for (i = 0; i < pDevice->sOpts.nTxDescs[0]; i++) { + PSTxDesc pDesc=&(pDevice->apTD0Rings[i]); + PDEVICE_TD_INFO pTDInfo=pDesc->pTDInfo; + + if (pTDInfo->skb_dma && (pTDInfo->skb_dma != pTDInfo->buf_dma)) + pci_unmap_single(pDevice->pcid,pTDInfo->skb_dma, + pTDInfo->skb->len, PCI_DMA_TODEVICE); + + if (pTDInfo->skb) + dev_kfree_skb(pTDInfo->skb); + + kfree((PVOID)pDesc->pTDInfo); + } +} + +static void device_free_td1_ring(PSDevice pDevice) { + int i; + + for (i = 0; i < pDevice->sOpts.nTxDescs[1]; i++) { + PSTxDesc pDesc=&(pDevice->apTD1Rings[i]); + PDEVICE_TD_INFO pTDInfo=pDesc->pTDInfo; + + if (pTDInfo->skb_dma && (pTDInfo->skb_dma != pTDInfo->buf_dma)) + pci_unmap_single(pDevice->pcid, pTDInfo->skb_dma, + pTDInfo->skb->len, PCI_DMA_TODEVICE); + + if (pTDInfo->skb) + dev_kfree_skb(pTDInfo->skb); + + kfree((PVOID)pDesc->pTDInfo); + } + +} + + + +/*-----------------------------------------------------------------*/ + +static int device_rx_srv(PSDevice pDevice, UINT uIdx) { + PSRxDesc pRD; + int works = 0; + + + for (pRD = pDevice->pCurrRD[uIdx]; + pRD->m_rd0RD0.f1Owner == OWNED_BY_HOST; + pRD = pRD->next) { +// DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pDevice->pCurrRD = %x, works = %d\n", pRD, works); + if (works++>15) + break; + if (device_receive_frame(pDevice, pRD)) { + if (!device_alloc_rx_buf(pDevice,pRD)) { + DEVICE_PRT(MSG_LEVEL_ERR, KERN_ERR + "%s: can not allocate rx buf\n", pDevice->dev->name); + break; + } + } + pRD->m_rd0RD0.f1Owner = OWNED_BY_NIC; +#ifdef PRIVATE_OBJ + ref_set_rx_jiffies(pDevice->dev); +#else + pDevice->dev->last_rx = jiffies; +#endif + } + + pDevice->pCurrRD[uIdx]=pRD; + + return works; +} + + +static BOOL device_alloc_rx_buf(PSDevice pDevice, PSRxDesc pRD) { + + PDEVICE_RD_INFO pRDInfo=pRD->pRDInfo; + +#ifdef PRIVATE_OBJ + + pRDInfo->skb=dev_alloc_skb(pDevice->rx_buf_sz); + if (pRDInfo->skb==NULL) + return FALSE; + ref_skb_remap(pDevice->dev, &(pRDInfo->ref_skb), pRDInfo->skb); + pRDInfo->skb_dma = pci_map_single(pDevice->pcid, pRDInfo->ref_skb.tail, pDevice->rx_buf_sz, + PCI_DMA_FROMDEVICE); +#else + + pRDInfo->skb = dev_alloc_skb((int)pDevice->rx_buf_sz); +#ifdef PLICE_DEBUG + //printk("device_alloc_rx_buf:skb is %x\n",pRDInfo->skb); +#endif + if (pRDInfo->skb==NULL) + return FALSE; + ASSERT(pRDInfo->skb); + pRDInfo->skb->dev = pDevice->dev; + pRDInfo->skb_dma = pci_map_single(pDevice->pcid, pRDInfo->skb->tail, pDevice->rx_buf_sz, + PCI_DMA_FROMDEVICE); +#endif + *((PU32) &(pRD->m_rd0RD0)) = 0; + + pRD->m_rd0RD0.wResCount = cpu_to_le16(pDevice->rx_buf_sz); + pRD->m_rd0RD0.f1Owner = OWNED_BY_NIC; + pRD->m_rd1RD1.wReqCount = cpu_to_le16(pDevice->rx_buf_sz); + pRD->buff_addr = cpu_to_le32(pRDInfo->skb_dma); + + return TRUE; +} + + + +BOOL device_alloc_frag_buf(PSDevice pDevice, PSDeFragControlBlock pDeF) { + +#ifdef PRIVATE_OBJ + + pDeF->skb=dev_alloc_skb(pDevice->rx_buf_sz); + if (pDeF->skb==NULL) + return FALSE; + ref_skb_remap(pDevice->dev, &(pDeF->ref_skb), pDeF->skb); + +#else + pDeF->skb = dev_alloc_skb((int)pDevice->rx_buf_sz); + if (pDeF->skb == NULL) + return FALSE; + ASSERT(pDeF->skb); + pDeF->skb->dev = pDevice->dev; +#endif + + return TRUE; +} + + + +static int device_tx_srv(PSDevice pDevice, UINT uIdx) { + PSTxDesc pTD; + BOOL bFull=FALSE; + int works = 0; + BYTE byTsr0; + BYTE byTsr1; + UINT uFrameSize, uFIFOHeaderSize; + PSTxBufHead pTxBufHead; + struct net_device_stats* pStats = &pDevice->stats; + struct sk_buff* skb; + UINT uNodeIndex; + PSMgmtObject pMgmt = pDevice->pMgmt; +#ifdef PRIVATE_OBJ + ref_sk_buff ref_skb; +#endif + + + for (pTD = pDevice->apTailTD[uIdx]; pDevice->iTDUsed[uIdx] >0; pTD = pTD->next) { + + if (pTD->m_td0TD0.f1Owner == OWNED_BY_NIC) + break; + if (works++>15) + break; + + byTsr0 = pTD->m_td0TD0.byTSR0; + byTsr1 = pTD->m_td0TD0.byTSR1; + + //Only the status of first TD in the chain is correct + if (pTD->m_td1TD1.byTCR & TCR_STP) { + + if ((pTD->pTDInfo->byFlags & TD_FLAGS_NETIF_SKB) != 0) { + uFIFOHeaderSize = pTD->pTDInfo->dwHeaderLength; + uFrameSize = pTD->pTDInfo->dwReqCount - uFIFOHeaderSize; + pTxBufHead = (PSTxBufHead) (pTD->pTDInfo->buf); +#ifdef PRIVATE_OBJ + ref_skb_remap(pDevice->dev, &ref_skb, pTD->pTDInfo->skb); +#endif + // Update the statistics based on the Transmit status + // now, we DO'NT check TSR0_CDH + + STAvUpdateTDStatCounter(&pDevice->scStatistic, + byTsr0, byTsr1, + (PBYTE)(pTD->pTDInfo->buf + uFIFOHeaderSize), + uFrameSize, uIdx); + + + BSSvUpdateNodeTxCounter(pDevice, + byTsr0, byTsr1, + (PBYTE)(pTD->pTDInfo->buf), + uFIFOHeaderSize + ); + + if (BITbIsBitOff(byTsr1, TSR1_TERR)) { + if (byTsr0 != 0) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO" Tx[%d] OK but has error. tsr1[%02X] tsr0[%02X].\n", + (INT)uIdx, byTsr1, byTsr0); + } + if ((pTxBufHead->wFragCtl & FRAGCTL_ENDFRAG) != FRAGCTL_NONFRAG) { + pDevice->s802_11Counter.TransmittedFragmentCount ++; + } + pStats->tx_packets++; +#ifdef PRIVATE_OBJ + pStats->tx_bytes += *(ref_skb.len); +#else + pStats->tx_bytes += pTD->pTDInfo->skb->len; +#endif + } + else { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO" Tx[%d] dropped & tsr1[%02X] tsr0[%02X].\n", + (INT)uIdx, byTsr1, byTsr0); + pStats->tx_errors++; + pStats->tx_dropped++; + } + } + + if ((pTD->pTDInfo->byFlags & TD_FLAGS_PRIV_SKB) != 0) { + if (pDevice->bEnableHostapd) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "tx call back netif.. \n"); +#ifdef PRIVATE_OBJ + ref_skb_remap(pDevice->apdev, &(ref_skb), pTD->pTDInfo->skb); + ref_skb.mac.raw = ref_skb.data; + *(ref_skb.pkt_type) = PACKET_OTHERHOST; + //*(ref_skb.protocol) = htons(ETH_P_802_2); + memset(ref_skb.cb, 0, sizeof(ref_skb.cb)); + netif_rx(ref_skb.skb); +#else + skb = pTD->pTDInfo->skb; + skb->dev = pDevice->apdev; + skb->mac_header = skb->data; + skb->pkt_type = PACKET_OTHERHOST; + //skb->protocol = htons(ETH_P_802_2); + memset(skb->cb, 0, sizeof(skb->cb)); + netif_rx(skb); +#endif + } + } + + if (BITbIsBitOn(byTsr1, TSR1_TERR)) { + if ((pTD->pTDInfo->byFlags & TD_FLAGS_PRIV_SKB) != 0) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO" Tx[%d] fail has error. tsr1[%02X] tsr0[%02X].\n", + (INT)uIdx, byTsr1, byTsr0); + } + +// DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO" Tx[%d] fail has error. tsr1[%02X] tsr0[%02X].\n", +// (INT)uIdx, byTsr1, byTsr0); + + if ((pMgmt->eCurrMode == WMAC_MODE_ESS_AP) && + (pTD->pTDInfo->byFlags & TD_FLAGS_NETIF_SKB)) { + WORD wAID; + BYTE byMask[8] = {1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80}; + + skb = pTD->pTDInfo->skb; + if (BSSDBbIsSTAInNodeDB(pMgmt, (PBYTE)(skb->data), &uNodeIndex)) { + if (pMgmt->sNodeDBTable[uNodeIndex].bPSEnable) { + skb_queue_tail(&pMgmt->sNodeDBTable[uNodeIndex].sTxPSQueue, skb); + pMgmt->sNodeDBTable[uNodeIndex].wEnQueueCnt++; + // set tx map + wAID = pMgmt->sNodeDBTable[uNodeIndex].wAID; + pMgmt->abyPSTxMap[wAID >> 3] |= byMask[wAID & 7]; + pTD->pTDInfo->byFlags &= ~(TD_FLAGS_NETIF_SKB); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "tx_srv:tx fail re-queue sta index= %d, QueCnt= %d\n" + ,(INT)uNodeIndex, pMgmt->sNodeDBTable[uNodeIndex].wEnQueueCnt); + pStats->tx_errors--; + pStats->tx_dropped--; + } + } + } + } + device_free_tx_buf(pDevice,pTD); + pDevice->iTDUsed[uIdx]--; + } + } + + + if (uIdx == TYPE_AC0DMA) { + // RESERV_AC0DMA reserved for relay + + if (AVAIL_TD(pDevice, uIdx) < RESERV_AC0DMA) { + bFull = TRUE; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " AC0DMA is Full = %d\n", pDevice->iTDUsed[uIdx]); + } + if (netif_queue_stopped(pDevice->dev) && (bFull==FALSE)){ + netif_wake_queue(pDevice->dev); + } + } + + + pDevice->apTailTD[uIdx] = pTD; + + return works; +} + + +static void device_error(PSDevice pDevice, WORD status) { + + if (status & ISR_FETALERR) { + DEVICE_PRT(MSG_LEVEL_ERR, KERN_ERR + "%s: Hardware fatal error.\n", + pDevice->dev->name); + netif_stop_queue(pDevice->dev); + del_timer(&pDevice->sTimerCommand); + del_timer(&(pDevice->pMgmt->sTimerSecondCallback)); + pDevice->bCmdRunning = FALSE; + MACbShutdown(pDevice->PortOffset); + return; + } + +} + +static void device_free_tx_buf(PSDevice pDevice, PSTxDesc pDesc) { + PDEVICE_TD_INFO pTDInfo=pDesc->pTDInfo; + struct sk_buff* skb=pTDInfo->skb; + + // pre-allocated buf_dma can't be unmapped. + if (pTDInfo->skb_dma && (pTDInfo->skb_dma != pTDInfo->buf_dma)) { + pci_unmap_single(pDevice->pcid,pTDInfo->skb_dma,skb->len, + PCI_DMA_TODEVICE); + } + + if ((pTDInfo->byFlags & TD_FLAGS_NETIF_SKB) != 0) + dev_kfree_skb_irq(skb); + + pTDInfo->skb_dma = 0; + pTDInfo->skb = 0; + pTDInfo->byFlags = 0; +} + + + +//PLICE_DEBUG -> +VOID InitRxManagementQueue(PSDevice pDevice) +{ + pDevice->rxManeQueue.packet_num = 0; + pDevice->rxManeQueue.head = pDevice->rxManeQueue.tail = 0; +} +//PLICE_DEBUG<- + + + + + +//PLICE_DEBUG -> +INT MlmeThread( + void * Context) +{ + PSDevice pDevice = (PSDevice) Context; + PSRxMgmtPacket pRxMgmtPacket; + // int i ; + //complete(&pDevice->notify); +//printk("Enter MngWorkItem,Queue packet num is %d\n",pDevice->rxManeQueue.packet_num); + + //printk("Enter MlmeThread,packet _num is %d\n",pDevice->rxManeQueue.packet_num); + //i = 0; +#if 1 + while (1) + { + + //printk("DDDD\n"); + //down(&pDevice->mlme_semaphore); + // pRxMgmtPacket = DeQueue(pDevice); +#if 1 + spin_lock_irq(&pDevice->lock); + while(pDevice->rxManeQueue.packet_num != 0) + { + pRxMgmtPacket = DeQueue(pDevice); + //pDevice; + //DequeueManageObject(pDevice->FirstRecvMngList, pDevice->LastRecvMngList); + vMgrRxManagePacket(pDevice, pDevice->pMgmt, pRxMgmtPacket); + //printk("packet_num is %d\n",pDevice->rxManeQueue.packet_num); + + } + spin_unlock_irq(&pDevice->lock); + if (mlme_kill == 0) + break; + //udelay(200); +#endif + //printk("Before schedule thread jiffies is %x\n",jiffies); + schedule(); + //printk("after schedule thread jiffies is %x\n",jiffies); + if (mlme_kill == 0) + break; + //printk("i is %d\n",i); + } + +#endif + return 0; + +} + + +#ifdef PRIVATE_OBJ + +int __device_open(HANDLE pExDevice) { + PSDevice_info pDevice_info = (PSDevice_info)pExDevice; + PSDevice pDevice = (PSDevice)(pDevice_info->pWDevice); + +#else + +static int device_open(struct net_device *dev) { + PSDevice pDevice=(PSDevice) netdev_priv(dev); + int i; +#endif + pDevice->rx_buf_sz = PKT_BUF_SZ; + if (!device_init_rings(pDevice)) { + return -ENOMEM; + } +//2008-5-13 by chester +#ifndef PRIVATE_OBJ + i=request_irq(pDevice->pcid->irq, &device_intr, IRQF_SHARED, dev->name, dev); + if (i) + return i; +#endif + //printk("DEBUG1\n"); +#ifdef WPA_SM_Transtatus + extern SWPAResult wpa_Result; + memset(wpa_Result.ifname,0,sizeof(wpa_Result.ifname)); + wpa_Result.proto = 0; + wpa_Result.key_mgmt = 0; + wpa_Result.eap_type = 0; + wpa_Result.authenticated = FALSE; + pDevice->fWPA_Authened = FALSE; +#endif +DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "call device init rd0 ring\n"); +device_init_rd0_ring(pDevice); + device_init_rd1_ring(pDevice); + device_init_defrag_cb(pDevice); + device_init_td0_ring(pDevice); + device_init_td1_ring(pDevice); +// VNTWIFIvSet11h(pDevice->pMgmt, pDevice->b11hEnable); + + + if (pDevice->bDiversityRegCtlON) { + device_init_diversity_timer(pDevice); + } + vMgrObjectInit(pDevice); + vMgrTimerInit(pDevice); + +//PLICE_DEBUG-> +#ifdef TASK_LET + tasklet_init (&pDevice->RxMngWorkItem,(void *)MngWorkItem,(unsigned long )pDevice); +#endif +#ifdef THREAD + InitRxManagementQueue(pDevice); + mlme_kill = 0; + mlme_task = kthread_run(MlmeThread,(void *) pDevice, "MLME"); + if (IS_ERR(mlme_task)) { + printk("thread create fail\n"); + return -1; + } + + mlme_kill = 1; +#endif + + + +#if 0 + pDevice->MLMEThr_pid = kernel_thread(MlmeThread, pDevice, CLONE_VM); + if (pDevice->MLMEThr_pid <0 ) + { + printk("unable start thread MlmeThread\n"); + return -1; + } +#endif + + //printk("thread id is %d\n",pDevice->MLMEThr_pid); + //printk("Create thread time is %x\n",jiffies); + //wait_for_completion(&pDevice->notify); + + + + + // if (( SROMbyReadEmbedded(pDevice->PortOffset, EEP_OFS_RADIOCTL)&0x06)==0x04) + // return -ENOMEM; +DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "call device_init_registers\n"); + device_init_registers(pDevice, DEVICE_INIT_COLD); + MACvReadEtherAddress(pDevice->PortOffset, pDevice->abyCurrentNetAddr); + memcpy(pDevice->pMgmt->abyMACAddr, pDevice->abyCurrentNetAddr, U_ETHER_ADDR_LEN); +#ifdef PRIVATE_OBJ + __device_set_multi(pExDevice); +#else + device_set_multi(pDevice->dev); +#endif + + // Init for Key Management + KeyvInitTable(&pDevice->sKey, pDevice->PortOffset); + add_timer(&(pDevice->pMgmt->sTimerSecondCallback)); + + #ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT + /* + pDevice->bwextstep0 = FALSE; + pDevice->bwextstep1 = FALSE; + pDevice->bwextstep2 = FALSE; + pDevice->bwextstep3 = FALSE; + */ + pDevice->bwextcount=0; + pDevice->bWPASuppWextEnabled = FALSE; +#endif + pDevice->byReAssocCount = 0; + pDevice->bWPADEVUp = FALSE; + // Patch: if WEP key already set by iwconfig but device not yet open + if ((pDevice->bEncryptionEnable == TRUE) && (pDevice->bTransmitKey == TRUE)) { + KeybSetDefaultKey(&(pDevice->sKey), + (DWORD)(pDevice->byKeyIndex | (1 << 31)), + pDevice->uKeyLength, + NULL, + pDevice->abyKey, + KEY_CTL_WEP, + pDevice->PortOffset, + pDevice->byLocalID + ); + pDevice->eEncryptionStatus = Ndis802_11Encryption1Enabled; + } + +//printk("DEBUG2\n"); + + +DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "call MACvIntEnable\n"); + MACvIntEnable(pDevice->PortOffset, IMR_MASK_VALUE); + + if (pDevice->pMgmt->eConfigMode == WMAC_CONFIG_AP) { + bScheduleCommand((HANDLE)pDevice, WLAN_CMD_RUN_AP, NULL); + } + else { + bScheduleCommand((HANDLE)pDevice, WLAN_CMD_BSSID_SCAN, NULL); + bScheduleCommand((HANDLE)pDevice, WLAN_CMD_SSID, NULL); + } + pDevice->flags |=DEVICE_FLAGS_OPENED; + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "device_open success.. \n"); + return 0; +} + + +#ifdef PRIVATE_OBJ + +int __device_close(HANDLE pExDevice) { + PSDevice_info pDevice_info = (PSDevice_info)pExDevice; + struct net_device *dev = pDevice_info->dev; + PSDevice pDevice = (PSDevice)(pDevice_info->pWDevice); + +#else +static int device_close(struct net_device *dev) { + PSDevice pDevice=(PSDevice) netdev_priv(dev); +#endif + PSMgmtObject pMgmt = pDevice->pMgmt; + //PLICE_DEBUG-> +#ifdef THREAD + mlme_kill = 0; +#endif +//PLICE_DEBUG<- +//2007-1121-02by EinsnLiu + if (pDevice->bLinkPass) { + bScheduleCommand((HANDLE)pDevice, WLAN_CMD_DISASSOCIATE, NULL); + mdelay(30); + } +#ifdef TxInSleep + del_timer(&pDevice->sTimerTxData); +#endif + del_timer(&pDevice->sTimerCommand); + del_timer(&pMgmt->sTimerSecondCallback); + if (pDevice->bDiversityRegCtlON) { + del_timer(&pDevice->TimerSQ3Tmax1); + del_timer(&pDevice->TimerSQ3Tmax2); + del_timer(&pDevice->TimerSQ3Tmax3); + } + +#ifdef TASK_LET + tasklet_kill(&pDevice->RxMngWorkItem); +#endif + netif_stop_queue(dev); + pDevice->bCmdRunning = FALSE; + MACbShutdown(pDevice->PortOffset); + MACbSoftwareReset(pDevice->PortOffset); + CARDbRadioPowerOff(pDevice); + + pDevice->bLinkPass = FALSE; + memset(pMgmt->abyCurrBSSID, 0, 6); + pMgmt->eCurrState = WMAC_STATE_IDLE; + device_free_td0_ring(pDevice); + device_free_td1_ring(pDevice); + device_free_rd0_ring(pDevice); + device_free_rd1_ring(pDevice); + device_free_frag_buf(pDevice); + device_free_rings(pDevice); + BSSvClearNodeDBTable(pDevice, 0); + free_irq(dev->irq, dev); + pDevice->flags &=(~DEVICE_FLAGS_OPENED); + //2008-0714-01by chester +device_release_WPADEV(pDevice); +//PLICE_DEBUG-> + //tasklet_kill(&pDevice->RxMngWorkItem); +//PLICE_DEBUG<- + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "device_close.. \n"); + return 0; +} + +#ifdef PRIVATE_OBJ + +int __device_dma0_tx_80211(HANDLE pExDevice, struct sk_buff *skb) { + PSDevice_info pDevice_info = (PSDevice_info)pExDevice; + PSDevice pDevice = (PSDevice)(pDevice_info->pWDevice); + ref_sk_buff ref_skb; + +#else + + +static int device_dma0_tx_80211(struct sk_buff *skb, struct net_device *dev) { + PSDevice pDevice=netdev_priv(dev); +#endif + PBYTE pbMPDU; + UINT cbMPDULen = 0; + + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "device_dma0_tx_80211\n"); + spin_lock_irq(&pDevice->lock); + + if (AVAIL_TD(pDevice, TYPE_TXDMA0) <= 0) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "device_dma0_tx_80211, td0 <=0\n"); + dev_kfree_skb_irq(skb); + spin_unlock_irq(&pDevice->lock); + return 0; + } + + if (pDevice->bStopTx0Pkt == TRUE) { + dev_kfree_skb_irq(skb); + spin_unlock_irq(&pDevice->lock); + return 0; + }; + +#ifdef PRIVATE_OBJ + ref_skb_remap(pDevice->dev, &ref_skb, skb); + cbMPDULen = *(ref_skb.len); + pbMPDU = ref_skb.data; +#else + cbMPDULen = skb->len; + pbMPDU = skb->data; +#endif + + vDMA0_tx_80211(pDevice, skb, pbMPDU, cbMPDULen); + + spin_unlock_irq(&pDevice->lock); + + return 0; + +} + + + +BOOL device_dma0_xmit(PSDevice pDevice, struct sk_buff *skb, UINT uNodeIndex) { + PSMgmtObject pMgmt = pDevice->pMgmt; + PSTxDesc pHeadTD, pLastTD; + UINT cbFrameBodySize; + UINT uMACfragNum; + BYTE byPktTyp; + BOOL bNeedEncryption = FALSE; + PSKeyItem pTransmitKey = NULL; + UINT cbHeaderSize; + UINT ii; + SKeyItem STempKey; +// BYTE byKeyIndex = 0; +#ifdef PRIVATE_OBJ + ref_sk_buff ref_skb; +#endif + + + if (pDevice->bStopTx0Pkt == TRUE) { + dev_kfree_skb_irq(skb); + return FALSE; + }; + + if (AVAIL_TD(pDevice, TYPE_TXDMA0) <= 0) { + dev_kfree_skb_irq(skb); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "device_dma0_xmit, td0 <=0\n"); + return FALSE; + } + + if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) { + if (pDevice->uAssocCount == 0) { + dev_kfree_skb_irq(skb); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "device_dma0_xmit, assocCount = 0\n"); + return FALSE; + } + } + +#ifdef PRIVATE_OBJ + ref_skb_remap(pDevice->dev, &(ref_skb), skb); +#endif + pHeadTD = pDevice->apCurrTD[TYPE_TXDMA0]; + + pHeadTD->m_td1TD1.byTCR = (TCR_EDP|TCR_STP); + +#ifdef PRIVATE_OBJ + memcpy(pDevice->sTxEthHeader.abyDstAddr, (PBYTE)(ref_skb.data), U_HEADER_LEN); + cbFrameBodySize = *(ref_skb.len) - U_HEADER_LEN; + +#else + memcpy(pDevice->sTxEthHeader.abyDstAddr, (PBYTE)(skb->data), U_HEADER_LEN); + cbFrameBodySize = skb->len - U_HEADER_LEN; +#endif + + // 802.1H + if (ntohs(pDevice->sTxEthHeader.wType) > MAX_DATA_LEN) { + cbFrameBodySize += 8; + } + uMACfragNum = cbGetFragCount(pDevice, pTransmitKey, cbFrameBodySize, &pDevice->sTxEthHeader); + + if ( uMACfragNum > AVAIL_TD(pDevice, TYPE_TXDMA0)) { + dev_kfree_skb_irq(skb); + return FALSE; + } + byPktTyp = (BYTE)pDevice->byPacketType; + + + if (pDevice->bFixRate) { + if (pDevice->eCurrentPHYType == PHY_TYPE_11B) { + if (pDevice->uConnectionRate >= RATE_11M) { + pDevice->wCurrentRate = RATE_11M; + } else { + pDevice->wCurrentRate = (WORD)pDevice->uConnectionRate; + } + } else { + if (pDevice->uConnectionRate >= RATE_54M) + pDevice->wCurrentRate = RATE_54M; + else + pDevice->wCurrentRate = (WORD)pDevice->uConnectionRate; + } + } + else { + pDevice->wCurrentRate = pDevice->pMgmt->sNodeDBTable[uNodeIndex].wTxDataRate; + } + + //preamble type + if (pMgmt->sNodeDBTable[uNodeIndex].bShortPreamble) { + pDevice->byPreambleType = pDevice->byShortPreamble; + } + else { + pDevice->byPreambleType = PREAMBLE_LONG; + } + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "dma0: pDevice->wCurrentRate = %d \n", pDevice->wCurrentRate); + + + if (pDevice->wCurrentRate <= RATE_11M) { + byPktTyp = PK_TYPE_11B; + } else if (pDevice->eCurrentPHYType == PHY_TYPE_11A) { + byPktTyp = PK_TYPE_11A; + } else { + if (pDevice->bProtectMode == TRUE) { + byPktTyp = PK_TYPE_11GB; + } else { + byPktTyp = PK_TYPE_11GA; + } + } + + if (pDevice->bEncryptionEnable == TRUE) + bNeedEncryption = TRUE; + + if (pDevice->bEnableHostWEP) { + pTransmitKey = &STempKey; + pTransmitKey->byCipherSuite = pMgmt->sNodeDBTable[uNodeIndex].byCipherSuite; + pTransmitKey->dwKeyIndex = pMgmt->sNodeDBTable[uNodeIndex].dwKeyIndex; + pTransmitKey->uKeyLength = pMgmt->sNodeDBTable[uNodeIndex].uWepKeyLength; + pTransmitKey->dwTSC47_16 = pMgmt->sNodeDBTable[uNodeIndex].dwTSC47_16; + pTransmitKey->wTSC15_0 = pMgmt->sNodeDBTable[uNodeIndex].wTSC15_0; + memcpy(pTransmitKey->abyKey, + &pMgmt->sNodeDBTable[uNodeIndex].abyWepKey[0], + pTransmitKey->uKeyLength + ); + } + vGenerateFIFOHeader(pDevice, byPktTyp, pDevice->pbyTmpBuff, bNeedEncryption, + cbFrameBodySize, TYPE_TXDMA0, pHeadTD, + &pDevice->sTxEthHeader, (PBYTE)skb->data, pTransmitKey, uNodeIndex, + &uMACfragNum, + &cbHeaderSize + ); + + if (MACbIsRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_PS)) { + // Disable PS + MACbPSWakeup(pDevice->PortOffset); + } + + pDevice->bPWBitOn = FALSE; + + pLastTD = pHeadTD; + for (ii = 0; ii < uMACfragNum; ii++) { + // Poll Transmit the adapter + wmb(); + pHeadTD->m_td0TD0.f1Owner=OWNED_BY_NIC; + wmb(); + if (ii == (uMACfragNum - 1)) + pLastTD = pHeadTD; + pHeadTD = pHeadTD->next; + } + + // Save the information needed by the tx interrupt handler + // to complete the Send request + pLastTD->pTDInfo->skb = skb; + pLastTD->pTDInfo->byFlags = 0; + pLastTD->pTDInfo->byFlags |= TD_FLAGS_NETIF_SKB; + + pDevice->apCurrTD[TYPE_TXDMA0] = pHeadTD; + + MACvTransmit0(pDevice->PortOffset); + + + return TRUE; +} + +//TYPE_AC0DMA data tx +#ifdef PRIVATE_OBJ + +int __device_xmit(HANDLE pExDevice, struct sk_buff *skb) { + PSDevice_info pDevice_info = (PSDevice_info)pExDevice; + PSDevice pDevice = (PSDevice)(pDevice_info->pWDevice); + struct net_device *dev = pDevice_info->dev; + ref_sk_buff ref_skb; + +#else +static int device_xmit(struct sk_buff *skb, struct net_device *dev) { + PSDevice pDevice=netdev_priv(dev); + +#endif + PSMgmtObject pMgmt = pDevice->pMgmt; + PSTxDesc pHeadTD, pLastTD; + UINT uNodeIndex = 0; + BYTE byMask[8] = {1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80}; + WORD wAID; + UINT uMACfragNum = 1; + UINT cbFrameBodySize; + BYTE byPktTyp; + UINT cbHeaderSize; + BOOL bNeedEncryption = FALSE; + PSKeyItem pTransmitKey = NULL; + SKeyItem STempKey; + UINT ii; + BOOL bTKIP_UseGTK = FALSE; + BOOL bNeedDeAuth = FALSE; + PBYTE pbyBSSID; + BOOL bNodeExist = FALSE; + + + + spin_lock_irq(&pDevice->lock); + if (pDevice->bLinkPass == FALSE) { + dev_kfree_skb_irq(skb); + spin_unlock_irq(&pDevice->lock); + return 0; + } + + if (pDevice->bStopDataPkt) { + dev_kfree_skb_irq(skb); + spin_unlock_irq(&pDevice->lock); + return 0; + } + +#ifdef PRIVATE_OBJ + ref_skb_remap(pDevice->dev, &ref_skb, skb); +#endif + + if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) { + if (pDevice->uAssocCount == 0) { + dev_kfree_skb_irq(skb); + spin_unlock_irq(&pDevice->lock); + return 0; + } +#ifdef PRIVATE_OBJ + if (IS_MULTICAST_ADDRESS((PBYTE)(ref_skb.data))) { +#else + if (IS_MULTICAST_ADDRESS((PBYTE)(skb->data))) { +#endif + uNodeIndex = 0; + bNodeExist = TRUE; + if (pMgmt->sNodeDBTable[0].bPSEnable) { +#ifdef PRIVATE_OBJ + skb_queue_tail(&(pMgmt->sNodeDBTable[0].sTxPSQueue), ref_skb.skb); +#else + skb_queue_tail(&(pMgmt->sNodeDBTable[0].sTxPSQueue), skb); +#endif + pMgmt->sNodeDBTable[0].wEnQueueCnt++; + // set tx map + pMgmt->abyPSTxMap[0] |= byMask[0]; + spin_unlock_irq(&pDevice->lock); + return 0; + } +}else { +#ifdef PRIVATE_OBJ + if (BSSDBbIsSTAInNodeDB(pMgmt, (PBYTE)(ref_skb.data), &uNodeIndex)) { +#else + if (BSSDBbIsSTAInNodeDB(pMgmt, (PBYTE)(skb->data), &uNodeIndex)) { +#endif + if (pMgmt->sNodeDBTable[uNodeIndex].bPSEnable) { +#ifdef PRIVATE_OBJ + skb_queue_tail(&pMgmt->sNodeDBTable[uNodeIndex].sTxPSQueue, ref_skb.skb); +#else + skb_queue_tail(&pMgmt->sNodeDBTable[uNodeIndex].sTxPSQueue, skb); +#endif + pMgmt->sNodeDBTable[uNodeIndex].wEnQueueCnt++; + // set tx map + wAID = pMgmt->sNodeDBTable[uNodeIndex].wAID; + pMgmt->abyPSTxMap[wAID >> 3] |= byMask[wAID & 7]; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Set:pMgmt->abyPSTxMap[%d]= %d\n", + (wAID >> 3), pMgmt->abyPSTxMap[wAID >> 3]); + spin_unlock_irq(&pDevice->lock); + return 0; + } + + if (pMgmt->sNodeDBTable[uNodeIndex].bShortPreamble) { + pDevice->byPreambleType = pDevice->byShortPreamble; + + }else { + pDevice->byPreambleType = PREAMBLE_LONG; + } + bNodeExist = TRUE; + + } + } + + if (bNodeExist == FALSE) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_DEBUG"Unknown STA not found in node DB \n"); + dev_kfree_skb_irq(skb); + spin_unlock_irq(&pDevice->lock); + return 0; + } + } + + pHeadTD = pDevice->apCurrTD[TYPE_AC0DMA]; + + pHeadTD->m_td1TD1.byTCR = (TCR_EDP|TCR_STP); + + +#ifdef PRIVATE_OBJ + memcpy(pDevice->sTxEthHeader.abyDstAddr, (PBYTE)(ref_skb.data), U_HEADER_LEN); + cbFrameBodySize = *(ref_skb.len) - U_HEADER_LEN; +#else + memcpy(pDevice->sTxEthHeader.abyDstAddr, (PBYTE)(skb->data), U_HEADER_LEN); + cbFrameBodySize = skb->len - U_HEADER_LEN; +#endif + // 802.1H + if (ntohs(pDevice->sTxEthHeader.wType) > MAX_DATA_LEN) { + cbFrameBodySize += 8; + } + + + if (pDevice->bEncryptionEnable == TRUE) { + bNeedEncryption = TRUE; + // get Transmit key + do { + if ((pDevice->pMgmt->eCurrMode == WMAC_MODE_ESS_STA) && + (pDevice->pMgmt->eCurrState == WMAC_STATE_ASSOC)) { + pbyBSSID = pDevice->abyBSSID; + // get pairwise key + if (KeybGetTransmitKey(&(pDevice->sKey), pbyBSSID, PAIRWISE_KEY, &pTransmitKey) == FALSE) { + // get group key + if(KeybGetTransmitKey(&(pDevice->sKey), pbyBSSID, GROUP_KEY, &pTransmitKey) == TRUE) { + bTKIP_UseGTK = TRUE; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_DEBUG"Get GTK.\n"); + break; + } + } else { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_DEBUG"Get PTK.\n"); + break; + } + }else if (pDevice->pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) { + + pbyBSSID = pDevice->sTxEthHeader.abyDstAddr; //TO_DS = 0 and FROM_DS = 0 --> 802.11 MAC Address1 + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_DEBUG"IBSS Serach Key: \n"); + for (ii = 0; ii< 6; ii++) + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_DEBUG"%x \n", *(pbyBSSID+ii)); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_DEBUG"\n"); + + // get pairwise key + if(KeybGetTransmitKey(&(pDevice->sKey), pbyBSSID, PAIRWISE_KEY, &pTransmitKey) == TRUE) + break; + } + // get group key + pbyBSSID = pDevice->abyBroadcastAddr; + if(KeybGetTransmitKey(&(pDevice->sKey), pbyBSSID, GROUP_KEY, &pTransmitKey) == FALSE) { + pTransmitKey = NULL; + if (pDevice->pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_DEBUG"IBSS and KEY is NULL. [%d]\n", pDevice->pMgmt->eCurrMode); + } + else + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_DEBUG"NOT IBSS and KEY is NULL. [%d]\n", pDevice->pMgmt->eCurrMode); + } else { + bTKIP_UseGTK = TRUE; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_DEBUG"Get GTK.\n"); + } + } while(FALSE); + } + + if (pDevice->bEnableHostWEP) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_DEBUG"acdma0: STA index %d\n", uNodeIndex); + if (pDevice->bEncryptionEnable == TRUE) { + pTransmitKey = &STempKey; + pTransmitKey->byCipherSuite = pMgmt->sNodeDBTable[uNodeIndex].byCipherSuite; + pTransmitKey->dwKeyIndex = pMgmt->sNodeDBTable[uNodeIndex].dwKeyIndex; + pTransmitKey->uKeyLength = pMgmt->sNodeDBTable[uNodeIndex].uWepKeyLength; + pTransmitKey->dwTSC47_16 = pMgmt->sNodeDBTable[uNodeIndex].dwTSC47_16; + pTransmitKey->wTSC15_0 = pMgmt->sNodeDBTable[uNodeIndex].wTSC15_0; + memcpy(pTransmitKey->abyKey, + &pMgmt->sNodeDBTable[uNodeIndex].abyWepKey[0], + pTransmitKey->uKeyLength + ); + } + } + + uMACfragNum = cbGetFragCount(pDevice, pTransmitKey, cbFrameBodySize, &pDevice->sTxEthHeader); + + if (uMACfragNum > AVAIL_TD(pDevice, TYPE_AC0DMA)) { + DEVICE_PRT(MSG_LEVEL_ERR, KERN_DEBUG "uMACfragNum > AVAIL_TD(TYPE_AC0DMA) = %d\n", uMACfragNum); + dev_kfree_skb_irq(skb); + spin_unlock_irq(&pDevice->lock); + return 0; + } + + if (pTransmitKey != NULL) { + if ((pTransmitKey->byCipherSuite == KEY_CTL_WEP) && + (pTransmitKey->uKeyLength == WLAN_WEP232_KEYLEN)) { + uMACfragNum = 1; //WEP256 doesn't support fragment + } + } + + byPktTyp = (BYTE)pDevice->byPacketType; + + if (pDevice->bFixRate) { +#ifdef PLICE_DEBUG + printk("Fix Rate: PhyType is %d,ConnectionRate is %d\n",pDevice->eCurrentPHYType,pDevice->uConnectionRate); +#endif + + if (pDevice->eCurrentPHYType == PHY_TYPE_11B) { + if (pDevice->uConnectionRate >= RATE_11M) { + pDevice->wCurrentRate = RATE_11M; + } else { + pDevice->wCurrentRate = (WORD)pDevice->uConnectionRate; + } + } else { + if ((pDevice->eCurrentPHYType == PHY_TYPE_11A) && + (pDevice->uConnectionRate <= RATE_6M)) { + pDevice->wCurrentRate = RATE_6M; + } else { + if (pDevice->uConnectionRate >= RATE_54M) + pDevice->wCurrentRate = RATE_54M; + else + pDevice->wCurrentRate = (WORD)pDevice->uConnectionRate; + + } + } + pDevice->byACKRate = (BYTE) pDevice->wCurrentRate; + pDevice->byTopCCKBasicRate = RATE_1M; + pDevice->byTopOFDMBasicRate = RATE_6M; + } + else { + //auto rate + if (pDevice->sTxEthHeader.wType == TYPE_PKT_802_1x) { + if (pDevice->eCurrentPHYType != PHY_TYPE_11A) { + pDevice->wCurrentRate = RATE_1M; + pDevice->byACKRate = RATE_1M; + pDevice->byTopCCKBasicRate = RATE_1M; + pDevice->byTopOFDMBasicRate = RATE_6M; + } else { + pDevice->wCurrentRate = RATE_6M; + pDevice->byACKRate = RATE_6M; + pDevice->byTopCCKBasicRate = RATE_1M; + pDevice->byTopOFDMBasicRate = RATE_6M; + } + } + else { + VNTWIFIvGetTxRate( pDevice->pMgmt, + pDevice->sTxEthHeader.abyDstAddr, + &(pDevice->wCurrentRate), + &(pDevice->byACKRate), + &(pDevice->byTopCCKBasicRate), + &(pDevice->byTopOFDMBasicRate)); + +#if 0 +printk("auto rate:Rate : %d,AckRate:%d,TopCCKRate:%d,TopOFDMRate:%d\n", +pDevice->wCurrentRate,pDevice->byACKRate, +pDevice->byTopCCKBasicRate,pDevice->byTopOFDMBasicRate); + +#endif + +#if 0 + + pDevice->wCurrentRate = 11; + pDevice->byACKRate = 8; + pDevice->byTopCCKBasicRate = 3; + pDevice->byTopOFDMBasicRate = 8; +#endif + + + } + } + +// DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "acdma0: pDevice->wCurrentRate = %d \n", pDevice->wCurrentRate); + + if (pDevice->wCurrentRate <= RATE_11M) { + byPktTyp = PK_TYPE_11B; + } else if (pDevice->eCurrentPHYType == PHY_TYPE_11A) { + byPktTyp = PK_TYPE_11A; + } else { + if (pDevice->bProtectMode == TRUE) { + byPktTyp = PK_TYPE_11GB; + } else { + byPktTyp = PK_TYPE_11GA; + } + } + +//#ifdef PLICE_DEBUG +// printk("FIX RATE:CurrentRate is %d"); +//#endif + + if (bNeedEncryption == TRUE) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ntohs Pkt Type=%04x\n", ntohs(pDevice->sTxEthHeader.wType)); + if ((pDevice->sTxEthHeader.wType) == TYPE_PKT_802_1x) { + bNeedEncryption = FALSE; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Pkt Type=%04x\n", (pDevice->sTxEthHeader.wType)); + if ((pDevice->pMgmt->eCurrMode == WMAC_MODE_ESS_STA) && (pDevice->pMgmt->eCurrState == WMAC_STATE_ASSOC)) { + if (pTransmitKey == NULL) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Don't Find TX KEY\n"); + } + else { + if (bTKIP_UseGTK == TRUE) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"error: KEY is GTK!!~~\n"); + } + else { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Find PTK [%lX]\n", pTransmitKey->dwKeyIndex); + bNeedEncryption = TRUE; + } + } + } + + if (pDevice->byCntMeasure == 2) { + bNeedDeAuth = TRUE; + pDevice->s802_11Counter.TKIPCounterMeasuresInvoked++; + } + + if (pDevice->bEnableHostWEP) { + if ((uNodeIndex != 0) && + (pMgmt->sNodeDBTable[uNodeIndex].dwKeyIndex & PAIRWISE_KEY)) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Find PTK [%lX]\n", pTransmitKey->dwKeyIndex); + bNeedEncryption = TRUE; + } + } + } + else { + if (pTransmitKey == NULL) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"return no tx key\n"); + dev_kfree_skb_irq(skb); + spin_unlock_irq(&pDevice->lock); + return 0; + } + } + } + + +#ifdef PRIVATE_OBJ + vGenerateFIFOHeader(pDevice, byPktTyp, pDevice->pbyTmpBuff, bNeedEncryption, + cbFrameBodySize, TYPE_AC0DMA, pHeadTD, + &pDevice->sTxEthHeader, (PBYTE)ref_skb.data, pTransmitKey, uNodeIndex, + &uMACfragNum, + &cbHeaderSize + ); +#else +#ifdef PLICE_DEBUG + //if (skb->len == 98) + //{ + // printk("ping:len is %d\n"); + //} +#endif + vGenerateFIFOHeader(pDevice, byPktTyp, pDevice->pbyTmpBuff, bNeedEncryption, + cbFrameBodySize, TYPE_AC0DMA, pHeadTD, + &pDevice->sTxEthHeader, (PBYTE)skb->data, pTransmitKey, uNodeIndex, + &uMACfragNum, + &cbHeaderSize + ); +#endif + + if (MACbIsRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_PS)) { + // Disable PS + MACbPSWakeup(pDevice->PortOffset); + } + pDevice->bPWBitOn = FALSE; + + pLastTD = pHeadTD; + for (ii = 0; ii < uMACfragNum; ii++) { + // Poll Transmit the adapter + wmb(); + pHeadTD->m_td0TD0.f1Owner=OWNED_BY_NIC; + wmb(); + if (ii == uMACfragNum - 1) + pLastTD = pHeadTD; + pHeadTD = pHeadTD->next; + } + + // Save the information needed by the tx interrupt handler + // to complete the Send request +#ifdef PRIVATE_OBJ + pLastTD->pTDInfo->skb = ref_skb.skb; +#else + pLastTD->pTDInfo->skb = skb; +#endif + pLastTD->pTDInfo->byFlags = 0; + pLastTD->pTDInfo->byFlags |= TD_FLAGS_NETIF_SKB; +#ifdef TxInSleep + pDevice->nTxDataTimeCout=0; //2008-8-21 chester for send null packet + #endif + if (AVAIL_TD(pDevice, TYPE_AC0DMA) <= 1) { + netif_stop_queue(dev); + } + + pDevice->apCurrTD[TYPE_AC0DMA] = pHeadTD; +//#ifdef PLICE_DEBUG + if (pDevice->bFixRate) + { + printk("FixRate:Rate is %d,TxPower is %d\n",pDevice->wCurrentRate,pDevice->byCurPwr); + } + else + { + //printk("Auto Rate:Rate is %d,TxPower is %d\n",pDevice->wCurrentRate,pDevice->byCurPwr); + } +//#endif + +{ + BYTE Protocol_Version; //802.1x Authentication + BYTE Packet_Type; //802.1x Authentication + BYTE Descriptor_type; + WORD Key_info; +BOOL bTxeapol_key = FALSE; + Protocol_Version = skb->data[U_HEADER_LEN]; + Packet_Type = skb->data[U_HEADER_LEN+1]; + Descriptor_type = skb->data[U_HEADER_LEN+1+1+2]; + Key_info = (skb->data[U_HEADER_LEN+1+1+2+1] << 8)|(skb->data[U_HEADER_LEN+1+1+2+2]); + if (pDevice->sTxEthHeader.wType == TYPE_PKT_802_1x) { + if(((Protocol_Version==1) ||(Protocol_Version==2)) && + (Packet_Type==3)) { //802.1x OR eapol-key challenge frame transfer + bTxeapol_key = TRUE; + if((Descriptor_type==254)||(Descriptor_type==2)) { //WPA or RSN + if(!(Key_info & BIT3) && //group-key challenge + (Key_info & BIT8) && (Key_info & BIT9)) { //send 2/2 key + pDevice->fWPA_Authened = TRUE; + if(Descriptor_type==254) + printk("WPA "); + else + printk("WPA2 "); + printk("Authentication completed!!\n"); + } + } + } + } +} + + MACvTransmitAC0(pDevice->PortOffset); +// DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "acdma0:pDevice->apCurrTD= %p\n", pHeadTD); + +#ifdef PRIVATE_OBJ + ref_set_tx_jiffies(pDevice->dev); +#else + dev->trans_start = jiffies; +#endif + + spin_unlock_irq(&pDevice->lock); + return 0; + +} + +#ifdef PRIVATE_OBJ + +int __device_intr(int irq, HANDLE pExDevice, struct pt_regs *regs) { + PSDevice_info pDevice_info = (PSDevice_info)pExDevice; + PSDevice pDevice = (PSDevice)(pDevice_info->pWDevice); + + +#else +static irqreturn_t device_intr(int irq, void *dev_instance) { + struct net_device* dev=dev_instance; + PSDevice pDevice=(PSDevice) netdev_priv(dev); +#endif + + int max_count=0; + DWORD dwMIBCounter=0; + PSMgmtObject pMgmt = pDevice->pMgmt; + BYTE byOrgPageSel=0; + int handled = 0; + BYTE byData = 0; + int ii= 0; +// BYTE byRSSI; + + + MACvReadISR(pDevice->PortOffset, &pDevice->dwIsr); + + if (pDevice->dwIsr == 0) + return IRQ_RETVAL(handled); + + if (pDevice->dwIsr == 0xffffffff) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "dwIsr = 0xffff\n"); + return IRQ_RETVAL(handled); + } + /* + // 2008-05-21 by Richardtai, we can't read RSSI here, because no packet bound with RSSI + + if ((BITbIsBitOn(pDevice->dwIsr, ISR_RXDMA0)) && + (pDevice->byLocalID != REV_ID_VT3253_B0) && + (pDevice->bBSSIDFilter == TRUE)) { + // update RSSI + //BBbReadEmbeded(pDevice->PortOffset, 0x3E, &byRSSI); + //pDevice->uCurrRSSI = byRSSI; + } + */ + + handled = 1; + MACvIntDisable(pDevice->PortOffset); + spin_lock_irq(&pDevice->lock); + + //Make sure current page is 0 + VNSvInPortB(pDevice->PortOffset + MAC_REG_PAGE1SEL, &byOrgPageSel); + if (byOrgPageSel == 1) { + MACvSelectPage0(pDevice->PortOffset); + } + else + byOrgPageSel = 0; + + MACvReadMIBCounter(pDevice->PortOffset, &dwMIBCounter); + // TBD.... + // Must do this after doing rx/tx, cause ISR bit is slow + // than RD/TD write back + // update ISR counter + STAvUpdate802_11Counter(&pDevice->s802_11Counter, &pDevice->scStatistic , dwMIBCounter); + while (pDevice->dwIsr != 0) { + + STAvUpdateIsrStatCounter(&pDevice->scStatistic, pDevice->dwIsr); + MACvWriteISR(pDevice->PortOffset, pDevice->dwIsr); + + if (pDevice->dwIsr & ISR_FETALERR){ + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " ISR_FETALERR \n"); + VNSvOutPortB(pDevice->PortOffset + MAC_REG_SOFTPWRCTL, 0); + VNSvOutPortW(pDevice->PortOffset + MAC_REG_SOFTPWRCTL, SOFTPWRCTL_SWPECTI); + device_error(pDevice, pDevice->dwIsr); + } + + if (pDevice->byLocalID > REV_ID_VT3253_B1) { + + if (BITbIsBitOn(pDevice->dwIsr, ISR_MEASURESTART)) { + // 802.11h measure start + pDevice->byOrgChannel = pDevice->byCurrentCh; + VNSvInPortB(pDevice->PortOffset + MAC_REG_RCR, &(pDevice->byOrgRCR)); + VNSvOutPortB(pDevice->PortOffset + MAC_REG_RCR, (RCR_RXALLTYPE | RCR_UNICAST | RCR_BROADCAST | RCR_MULTICAST | RCR_WPAERR)); + MACvSelectPage1(pDevice->PortOffset); + VNSvInPortD(pDevice->PortOffset + MAC_REG_MAR0, &(pDevice->dwOrgMAR0)); + VNSvInPortD(pDevice->PortOffset + MAC_REG_MAR4, &(pDevice->dwOrgMAR4)); + MACvSelectPage0(pDevice->PortOffset); + //xxxx + // WCMDbFlushCommandQueue(pDevice->pMgmt, TRUE); + if (CARDbSetChannel(pDevice, pDevice->pCurrMeasureEID->sReq.byChannel) == TRUE) { + pDevice->bMeasureInProgress = TRUE; + MACvSelectPage1(pDevice->PortOffset); + MACvRegBitsOn(pDevice->PortOffset, MAC_REG_MSRCTL, MSRCTL_READY); + MACvSelectPage0(pDevice->PortOffset); + pDevice->byBasicMap = 0; + pDevice->byCCAFraction = 0; + for(ii=0;ii<8;ii++) { + pDevice->dwRPIs[ii] = 0; + } + } else { + // can not measure because set channel fail + // WCMDbResetCommandQueue(pDevice->pMgmt); + // clear measure control + MACvRegBitsOff(pDevice->PortOffset, MAC_REG_MSRCTL, MSRCTL_EN); + s_vCompleteCurrentMeasure(pDevice, MEASURE_MODE_INCAPABLE); + MACvSelectPage1(pDevice->PortOffset); + MACvRegBitsOn(pDevice->PortOffset, MAC_REG_MSRCTL+1, MSRCTL1_TXPAUSE); + MACvSelectPage0(pDevice->PortOffset); + } + } + if (BITbIsBitOn(pDevice->dwIsr, ISR_MEASUREEND)) { + // 802.11h measure end + pDevice->bMeasureInProgress = FALSE; + VNSvOutPortB(pDevice->PortOffset + MAC_REG_RCR, pDevice->byOrgRCR); + MACvSelectPage1(pDevice->PortOffset); + VNSvOutPortD(pDevice->PortOffset + MAC_REG_MAR0, pDevice->dwOrgMAR0); + VNSvOutPortD(pDevice->PortOffset + MAC_REG_MAR4, pDevice->dwOrgMAR4); + VNSvInPortB(pDevice->PortOffset + MAC_REG_MSRBBSTS, &byData); + pDevice->byBasicMap |= (byData >> 4); + VNSvInPortB(pDevice->PortOffset + MAC_REG_CCAFRACTION, &pDevice->byCCAFraction); + VNSvInPortB(pDevice->PortOffset + MAC_REG_MSRCTL, &byData); + // clear measure control + MACvRegBitsOff(pDevice->PortOffset, MAC_REG_MSRCTL, MSRCTL_EN); + MACvSelectPage0(pDevice->PortOffset); + CARDbSetChannel(pDevice, pDevice->byOrgChannel); + // WCMDbResetCommandQueue(pDevice->pMgmt); + MACvSelectPage1(pDevice->PortOffset); + MACvRegBitsOn(pDevice->PortOffset, MAC_REG_MSRCTL+1, MSRCTL1_TXPAUSE); + MACvSelectPage0(pDevice->PortOffset); + if (BITbIsBitOn(byData, MSRCTL_FINISH)) { + // measure success + s_vCompleteCurrentMeasure(pDevice, 0); + } else { + // can not measure because not ready before end of measure time + s_vCompleteCurrentMeasure(pDevice, MEASURE_MODE_LATE); + } + } + if (BITbIsBitOn(pDevice->dwIsr, ISR_QUIETSTART)) { + do { + ; + } while (CARDbStartQuiet(pDevice) == FALSE); + } + } + + if (pDevice->dwIsr & ISR_TBTT) { + if (pDevice->bEnableFirstQuiet == TRUE) { + pDevice->byQuietStartCount--; + if (pDevice->byQuietStartCount == 0) { + pDevice->bEnableFirstQuiet = FALSE; + MACvSelectPage1(pDevice->PortOffset); + MACvRegBitsOn(pDevice->PortOffset, MAC_REG_MSRCTL, (MSRCTL_QUIETTXCHK | MSRCTL_QUIETEN)); + MACvSelectPage0(pDevice->PortOffset); + } + } + if ((pDevice->bChannelSwitch == TRUE) && + (pDevice->eOPMode == OP_MODE_INFRASTRUCTURE)) { + pDevice->byChannelSwitchCount--; + if (pDevice->byChannelSwitchCount == 0) { + pDevice->bChannelSwitch = FALSE; + CARDbSetChannel(pDevice, pDevice->byNewChannel); + VNTWIFIbChannelSwitch(pDevice->pMgmt, pDevice->byNewChannel); + MACvSelectPage1(pDevice->PortOffset); + MACvRegBitsOn(pDevice->PortOffset, MAC_REG_MSRCTL+1, MSRCTL1_TXPAUSE); + MACvSelectPage0(pDevice->PortOffset); + CARDbStartTxPacket(pDevice, PKT_TYPE_802_11_ALL); + + } + } + if (pDevice->eOPMode == OP_MODE_ADHOC) { + //pDevice->bBeaconSent = FALSE; + } else { + if ((pDevice->bUpdateBBVGA) && (pDevice->bLinkPass == TRUE) && (pDevice->uCurrRSSI != 0)) { + LONG ldBm; + + RFvRSSITodBm(pDevice, (BYTE) pDevice->uCurrRSSI, &ldBm); + for (ii=0;iildBmThreshold[ii]) { + pDevice->byBBVGANew = pDevice->abyBBVGA[ii]; + break; + } + } + if (pDevice->byBBVGANew != pDevice->byBBVGACurrent) { + pDevice->uBBVGADiffCount++; + if (pDevice->uBBVGADiffCount == 1) { + // first VGA diff gain + BBvSetVGAGainOffset(pDevice, pDevice->byBBVGANew); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"First RSSI[%d] NewGain[%d] OldGain[%d] Count[%d]\n", + (int)ldBm, pDevice->byBBVGANew, pDevice->byBBVGACurrent, (int)pDevice->uBBVGADiffCount); + } + if (pDevice->uBBVGADiffCount >= BB_VGA_CHANGE_THRESHOLD) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"RSSI[%d] NewGain[%d] OldGain[%d] Count[%d]\n", + (int)ldBm, pDevice->byBBVGANew, pDevice->byBBVGACurrent, (int)pDevice->uBBVGADiffCount); + BBvSetVGAGainOffset(pDevice, pDevice->byBBVGANew); + } + } else { + pDevice->uBBVGADiffCount = 1; + } + } + } + + pDevice->bBeaconSent = FALSE; + if (pDevice->bEnablePSMode) { + PSbIsNextTBTTWakeUp((HANDLE)pDevice); + }; + + if ((pDevice->eOPMode == OP_MODE_AP) || + (pDevice->eOPMode == OP_MODE_ADHOC)) { + + MACvOneShotTimer1MicroSec(pDevice->PortOffset, + (pMgmt->wIBSSBeaconPeriod - MAKE_BEACON_RESERVED) << 10); + } + + if (pDevice->eOPMode == OP_MODE_ADHOC && pDevice->pMgmt->wCurrATIMWindow > 0) { + // todo adhoc PS mode + }; + + } + + if (pDevice->dwIsr & ISR_BNTX) { + + if (pDevice->eOPMode == OP_MODE_ADHOC) { + pDevice->bIsBeaconBufReadySet = FALSE; + pDevice->cbBeaconBufReadySetCnt = 0; + }; + + if (pDevice->eOPMode == OP_MODE_AP) { + if(pMgmt->byDTIMCount > 0) { + pMgmt->byDTIMCount --; + pMgmt->sNodeDBTable[0].bRxPSPoll = FALSE; + } + else { + if(pMgmt->byDTIMCount == 0) { + // check if mutltcast tx bufferring + pMgmt->byDTIMCount = pMgmt->byDTIMPeriod - 1; + pMgmt->sNodeDBTable[0].bRxPSPoll = TRUE; + bScheduleCommand((HANDLE)pDevice, WLAN_CMD_RX_PSPOLL, NULL); + } + } + } + pDevice->bBeaconSent = TRUE; + + if (pDevice->bChannelSwitch == TRUE) { + pDevice->byChannelSwitchCount--; + if (pDevice->byChannelSwitchCount == 0) { + pDevice->bChannelSwitch = FALSE; + CARDbSetChannel(pDevice, pDevice->byNewChannel); + VNTWIFIbChannelSwitch(pDevice->pMgmt, pDevice->byNewChannel); + MACvSelectPage1(pDevice->PortOffset); + MACvRegBitsOn(pDevice->PortOffset, MAC_REG_MSRCTL+1, MSRCTL1_TXPAUSE); + MACvSelectPage0(pDevice->PortOffset); + //VNTWIFIbSendBeacon(pDevice->pMgmt); + CARDbStartTxPacket(pDevice, PKT_TYPE_802_11_ALL); + } + } + + } + + if (pDevice->dwIsr & ISR_RXDMA0) { + max_count += device_rx_srv(pDevice, TYPE_RXDMA0); + } + if (pDevice->dwIsr & ISR_RXDMA1) { + max_count += device_rx_srv(pDevice, TYPE_RXDMA1); + } + if (pDevice->dwIsr & ISR_TXDMA0){ + max_count += device_tx_srv(pDevice, TYPE_TXDMA0); + } + if (pDevice->dwIsr & ISR_AC0DMA){ + max_count += device_tx_srv(pDevice, TYPE_AC0DMA); + } + if (pDevice->dwIsr & ISR_SOFTTIMER) { + + } + if (pDevice->dwIsr & ISR_SOFTTIMER1) { + if (pDevice->eOPMode == OP_MODE_AP) { + if (pDevice->bShortSlotTime) + pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SHORTSLOTTIME(1); + else + pMgmt->wCurrCapInfo &= ~(WLAN_SET_CAP_INFO_SHORTSLOTTIME(1)); + } + bMgrPrepareBeaconToSend(pDevice, pMgmt); + pDevice->byCntMeasure = 0; + } + + MACvReadISR(pDevice->PortOffset, &pDevice->dwIsr); + + MACvReceive0(pDevice->PortOffset); + MACvReceive1(pDevice->PortOffset); + + if (max_count>pDevice->sOpts.int_works) + break; + } + + if (byOrgPageSel == 1) { + MACvSelectPage1(pDevice->PortOffset); + } + + spin_unlock_irq(&pDevice->lock); + MACvIntEnable(pDevice->PortOffset, IMR_MASK_VALUE); + + return IRQ_RETVAL(handled); +} + + +static unsigned const ethernet_polynomial = 0x04c11db7U; +static inline u32 ether_crc(int length, unsigned char *data) +{ + int crc = -1; + + while(--length >= 0) { + unsigned char current_octet = *data++; + int bit; + for (bit = 0; bit < 8; bit++, current_octet >>= 1) { + crc = (crc << 1) ^ + ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0); + } + } + return crc; +} + +//2008-8-4 by chester +static int Config_FileGetParameter(UCHAR *string, UCHAR *dest,UCHAR *source) +{ + UCHAR buf1[100]; + int source_len = strlen(source); + + memset(buf1,0,100); + strcat(buf1, string); + strcat(buf1, "="); + source+=strlen(buf1); + + memcpy(dest,source,source_len-strlen(buf1)); + return TRUE; +} + +int Config_FileOperation(PSDevice pDevice,BOOL fwrite,unsigned char *Parameter) { + UCHAR *config_path=CONFIG_PATH; + UCHAR *buffer=NULL; + UCHAR tmpbuffer[20]; + struct file *filp=NULL; + mm_segment_t old_fs = get_fs(); + //int oldfsuid=0,oldfsgid=0; + int result=0; + + set_fs (KERNEL_DS); + + /* Can't do this anymore, so we rely on correct filesystem permissions: + //Make sure a caller can read or write power as root + oldfsuid=current->cred->fsuid; + oldfsgid=current->cred->fsgid; + current->cred->fsuid = 0; + current->cred->fsgid = 0; + */ + + //open file + filp = filp_open(config_path, O_RDWR, 0); + if (IS_ERR(filp)) { + printk("Config_FileOperation:open file fail?\n"); + result=-1; + goto error2; + } + + if(!(filp->f_op) || !(filp->f_op->read) ||!(filp->f_op->write)) { + printk("file %s cann't readable or writable?\n",config_path); + result = -1; + goto error1; + } + +buffer = (UCHAR *)kmalloc(1024, GFP_KERNEL); +if(buffer==NULL) { + printk("alllocate mem for file fail?\n"); + result = -1; + goto error1; +} + +if(filp->f_op->read(filp, buffer, 1024, &filp->f_pos)<0) { + printk("read file error?\n"); + result = -1; + goto error1; +} + +if(Config_FileGetParameter("ZONETYPE",tmpbuffer,buffer)!=TRUE) { + printk("get parameter error?\n"); + result = -1; + goto error1; +} + +if(memcmp(tmpbuffer,"USA",3)==0) { + result=ZoneType_USA; +} +else if(memcmp(tmpbuffer,"JAPAN",5)==0) { + result=ZoneType_Japan; +} +else if(memcmp(tmpbuffer,"EUROPE",5)==0) { + result=ZoneType_Europe; +} +else { + result = -1; + printk("Unknown Zonetype[%s]?\n",tmpbuffer); +} + +error1: + if(buffer) + kfree(buffer); + + if(filp_close(filp,NULL)) + printk("Config_FileOperation:close file fail\n"); + +error2: + set_fs (old_fs); + + /* + current->cred->fsuid=oldfsuid; + current->cred->fsgid=oldfsgid; + */ + + return result; +} + + +#ifdef PRIVATE_OBJ + +void __device_set_multi(HANDLE pExDevice) { + PSDevice_info pDevice_info = (PSDevice_info)pExDevice; + ref_net_device *dev = &(pDevice_info->ref_dev); + PSDevice pDevice = (PSDevice)(pDevice_info->pWDevice); + +#else + +static void device_set_multi(struct net_device *dev) { + PSDevice pDevice = (PSDevice) netdev_priv(dev); +#endif + + PSMgmtObject pMgmt = pDevice->pMgmt; + u32 mc_filter[2]; + int i; + struct dev_mc_list *mclist; + + + VNSvInPortB(pDevice->PortOffset + MAC_REG_RCR, &(pDevice->byRxMode)); + +#ifdef PRIVATE_OBJ + if (*(dev->flags) & IFF_PROMISC) { /* Set promiscuous. */ + DEVICE_PRT(MSG_LEVEL_ERR,KERN_ERR "%s: Promiscuous mode enabled.\n", pDevice->dev->name); + +#else + if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ + DEVICE_PRT(MSG_LEVEL_ERR,KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name); +#endif + /* Unconditionally log net taps. */ + pDevice->byRxMode |= (RCR_MULTICAST|RCR_BROADCAST|RCR_UNICAST); + } +#ifdef PRIVATE_OBJ + else if ((*(dev->mc_count) > pDevice->multicast_limit) + || (*(dev->flags) & IFF_ALLMULTI)) { +#else + else if ((dev->mc_count > pDevice->multicast_limit) + || (dev->flags & IFF_ALLMULTI)) { +#endif + MACvSelectPage1(pDevice->PortOffset); + VNSvOutPortD(pDevice->PortOffset + MAC_REG_MAR0, 0xffffffff); + VNSvOutPortD(pDevice->PortOffset + MAC_REG_MAR0 + 4, 0xffffffff); + MACvSelectPage0(pDevice->PortOffset); + pDevice->byRxMode |= (RCR_MULTICAST|RCR_BROADCAST); + } + else { + memset(mc_filter, 0, sizeof(mc_filter)); +#ifdef PRIVATE_OBJ + for (i = 0, mclist = dev->mc_list; mclist && i < *(dev->mc_count); + i++, mclist = mclist->next) { +#else + for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + i++, mclist = mclist->next) { +#endif + int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26; + mc_filter[bit_nr >> 5] |= cpu_to_le32(1 << (bit_nr & 31)); + } + MACvSelectPage1(pDevice->PortOffset); + VNSvOutPortD(pDevice->PortOffset + MAC_REG_MAR0, mc_filter[0]); + VNSvOutPortD(pDevice->PortOffset + MAC_REG_MAR0 + 4, mc_filter[1]); + MACvSelectPage0(pDevice->PortOffset); + pDevice->byRxMode &= ~(RCR_UNICAST); + pDevice->byRxMode |= (RCR_MULTICAST|RCR_BROADCAST); + } + + if (pMgmt->eConfigMode == WMAC_CONFIG_AP) { + // If AP mode, don't enable RCR_UNICAST. Since hw only compare addr1 with local mac. + pDevice->byRxMode |= (RCR_MULTICAST|RCR_BROADCAST); + pDevice->byRxMode &= ~(RCR_UNICAST); + } + + VNSvOutPortB(pDevice->PortOffset + MAC_REG_RCR, pDevice->byRxMode); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pDevice->byRxMode = %x\n", pDevice->byRxMode ); +} + + +#ifdef PRIVATE_OBJ + +struct net_device_stats *__device_get_stats(HANDLE pExDevice) { + PSDevice_info pDevice_info = (PSDevice_info)pExDevice; + PSDevice pDevice = (PSDevice)(pDevice_info->pWDevice); + +#else +static struct net_device_stats *device_get_stats(struct net_device *dev) { + PSDevice pDevice=(PSDevice) netdev_priv(dev); +#endif + + return &pDevice->stats; +} + + +#ifdef PRIVATE_OBJ + +int __device_ioctl(HANDLE pExDevice, struct ifreq *rq, int cmd) { + PSDevice_info pDevice_info = (PSDevice_info)pExDevice; + struct net_device *dev = pDevice_info->dev; + PSDevice pDevice = (PSDevice)(pDevice_info->pWDevice); + +#else + +static int device_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { + PSDevice pDevice = (PSDevice)netdev_priv(dev); +#endif + +#ifdef WIRELESS_EXT + struct iwreq *wrq = (struct iwreq *) rq; + int rc =0; +#endif + PSMgmtObject pMgmt = pDevice->pMgmt; + PSCmdRequest pReq; + + + if (pMgmt == NULL) { + rc = -EFAULT; + return rc; + } + + switch(cmd) { + +#ifdef WIRELESS_EXT +//#if WIRELESS_EXT < 13 + + case SIOCGIWNAME: + rc = iwctl_giwname(dev, NULL, (char *)&(wrq->u.name), NULL); + break; + + case SIOCGIWNWID: //0x8b03 support + #ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT + rc = iwctl_giwnwid(dev, NULL, &(wrq->u.nwid), NULL); + #else + rc = -EOPNOTSUPP; + #endif + break; + + // Set frequency/channel + case SIOCSIWFREQ: + rc = iwctl_siwfreq(dev, NULL, &(wrq->u.freq), NULL); + break; + + // Get frequency/channel + case SIOCGIWFREQ: + rc = iwctl_giwfreq(dev, NULL, &(wrq->u.freq), NULL); + break; + + // Set desired network name (ESSID) + case SIOCSIWESSID: + + { + char essid[IW_ESSID_MAX_SIZE+1]; + if (wrq->u.essid.length > IW_ESSID_MAX_SIZE) { + rc = -E2BIG; + break; + } + if (copy_from_user(essid, wrq->u.essid.pointer, + wrq->u.essid.length)) { + rc = -EFAULT; + break; + } + rc = iwctl_siwessid(dev, NULL, + &(wrq->u.essid), essid); + } + break; + + + // Get current network name (ESSID) + case SIOCGIWESSID: + + { + char essid[IW_ESSID_MAX_SIZE+1]; + if (wrq->u.essid.pointer) + rc = iwctl_giwessid(dev, NULL, + &(wrq->u.essid), essid); + if (copy_to_user(wrq->u.essid.pointer, + essid, + wrq->u.essid.length) ) + rc = -EFAULT; + } + break; + + case SIOCSIWAP: + + rc = iwctl_siwap(dev, NULL, &(wrq->u.ap_addr), NULL); + break; + + + // Get current Access Point (BSSID) + case SIOCGIWAP: + rc = iwctl_giwap(dev, NULL, &(wrq->u.ap_addr), NULL); + break; + + + // Set desired station name + case SIOCSIWNICKN: + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWNICKN \n"); + rc = -EOPNOTSUPP; + break; + + // Get current station name + case SIOCGIWNICKN: + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWNICKN \n"); + rc = -EOPNOTSUPP; + break; + + // Set the desired bit-rate + case SIOCSIWRATE: + rc = iwctl_siwrate(dev, NULL, &(wrq->u.bitrate), NULL); + break; + + // Get the current bit-rate + case SIOCGIWRATE: + + rc = iwctl_giwrate(dev, NULL, &(wrq->u.bitrate), NULL); + break; + + // Set the desired RTS threshold + case SIOCSIWRTS: + + rc = iwctl_siwrts(dev, NULL, &(wrq->u.rts), NULL); + break; + + // Get the current RTS threshold + case SIOCGIWRTS: + + rc = iwctl_giwrts(dev, NULL, &(wrq->u.rts), NULL); + break; + + // Set the desired fragmentation threshold + case SIOCSIWFRAG: + + rc = iwctl_siwfrag(dev, NULL, &(wrq->u.frag), NULL); + break; + + // Get the current fragmentation threshold + case SIOCGIWFRAG: + + rc = iwctl_giwfrag(dev, NULL, &(wrq->u.frag), NULL); + break; + + // Set mode of operation + case SIOCSIWMODE: + rc = iwctl_siwmode(dev, NULL, &(wrq->u.mode), NULL); + break; + + // Get mode of operation + case SIOCGIWMODE: + rc = iwctl_giwmode(dev, NULL, &(wrq->u.mode), NULL); + break; + + // Set WEP keys and mode + case SIOCSIWENCODE: + { + char abyKey[WLAN_WEP232_KEYLEN]; + + if (wrq->u.encoding.pointer) { + + + if (wrq->u.encoding.length > WLAN_WEP232_KEYLEN) { + rc = -E2BIG; + break; + } + memset(abyKey, 0, WLAN_WEP232_KEYLEN); + if (copy_from_user(abyKey, + wrq->u.encoding.pointer, + wrq->u.encoding.length)) { + rc = -EFAULT; + break; + } + } else if (wrq->u.encoding.length != 0) { + rc = -EINVAL; + break; + } + rc = iwctl_siwencode(dev, NULL, &(wrq->u.encoding), abyKey); + } + break; + + // Get the WEP keys and mode + case SIOCGIWENCODE: + + if (!capable(CAP_NET_ADMIN)) { + rc = -EPERM; + break; + } + { + char abyKey[WLAN_WEP232_KEYLEN]; + + rc = iwctl_giwencode(dev, NULL, &(wrq->u.encoding), abyKey); + if (rc != 0) break; + if (wrq->u.encoding.pointer) { + if (copy_to_user(wrq->u.encoding.pointer, + abyKey, + wrq->u.encoding.length)) + rc = -EFAULT; + } + } + break; + +#if WIRELESS_EXT > 9 + // Get the current Tx-Power + case SIOCGIWTXPOW: + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWTXPOW \n"); + rc = -EOPNOTSUPP; + break; + + case SIOCSIWTXPOW: + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWTXPOW \n"); + rc = -EOPNOTSUPP; + break; + +#endif // WIRELESS_EXT > 9 + +#if WIRELESS_EXT > 10 + case SIOCSIWRETRY: + + rc = iwctl_siwretry(dev, NULL, &(wrq->u.retry), NULL); + break; + + case SIOCGIWRETRY: + + rc = iwctl_giwretry(dev, NULL, &(wrq->u.retry), NULL); + break; + +#endif // WIRELESS_EXT > 10 + + // Get range of parameters + case SIOCGIWRANGE: + + { + struct iw_range range; + + rc = iwctl_giwrange(dev, NULL, &(wrq->u.data), (char *) &range); + if (copy_to_user(wrq->u.data.pointer, &range, sizeof(struct iw_range))) + rc = -EFAULT; + } + + break; + + case SIOCGIWPOWER: + + rc = iwctl_giwpower(dev, NULL, &(wrq->u.power), NULL); + break; + + + case SIOCSIWPOWER: + + rc = iwctl_siwpower(dev, NULL, &(wrq->u.power), NULL); + break; + + + case SIOCGIWSENS: + + rc = iwctl_giwsens(dev, NULL, &(wrq->u.sens), NULL); + break; + + case SIOCSIWSENS: + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWSENS \n"); + rc = -EOPNOTSUPP; + break; + + case SIOCGIWAPLIST: + { + char buffer[IW_MAX_AP * (sizeof(struct sockaddr) + sizeof(struct iw_quality))]; + + if (wrq->u.data.pointer) { + rc = iwctl_giwaplist(dev, NULL, &(wrq->u.data), buffer); + if (rc == 0) { + if (copy_to_user(wrq->u.data.pointer, + buffer, + (wrq->u.data.length * (sizeof(struct sockaddr) + sizeof(struct iw_quality))) + )) + rc = -EFAULT; + } + } + } + break; + + +#ifdef WIRELESS_SPY + // Set the spy list + case SIOCSIWSPY: + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWSPY \n"); + rc = -EOPNOTSUPP; + break; + + // Get the spy list + case SIOCGIWSPY: + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWSPY \n"); + rc = -EOPNOTSUPP; + break; + +#endif // WIRELESS_SPY + + case SIOCGIWPRIV: + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWPRIV \n"); + rc = -EOPNOTSUPP; +/* + if(wrq->u.data.pointer) { + wrq->u.data.length = sizeof(iwctl_private_args) / sizeof( iwctl_private_args[0]); + + if(copy_to_user(wrq->u.data.pointer, + (u_char *) iwctl_private_args, + sizeof(iwctl_private_args))) + rc = -EFAULT; + } +*/ + break; + + +//#endif // WIRELESS_EXT < 13 +//2008-0409-07, by Einsn Liu +#ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT + case SIOCSIWAUTH: + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWAUTH \n"); + rc = iwctl_siwauth(dev, NULL, &(wrq->u.param), NULL); + break; + + case SIOCGIWAUTH: + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWAUTH \n"); + rc = iwctl_giwauth(dev, NULL, &(wrq->u.param), NULL); + break; + + case SIOCSIWGENIE: + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWGENIE \n"); + rc = iwctl_siwgenie(dev, NULL, &(wrq->u.data), wrq->u.data.pointer); + break; + + case SIOCGIWGENIE: + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWGENIE \n"); + rc = iwctl_giwgenie(dev, NULL, &(wrq->u.data), wrq->u.data.pointer); + break; + + case SIOCSIWENCODEEXT: + { + char extra[sizeof(struct iw_encode_ext)+MAX_KEY_LEN+1]; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWENCODEEXT \n"); + if(wrq->u.encoding.pointer){ + memset(extra, 0, sizeof(struct iw_encode_ext)+MAX_KEY_LEN+1); + if(wrq->u.encoding.length > (sizeof(struct iw_encode_ext)+ MAX_KEY_LEN)){ + rc = -E2BIG; + break; + } + if(copy_from_user(extra, wrq->u.encoding.pointer,wrq->u.encoding.length)){ + rc = -EFAULT; + break; + } + }else if(wrq->u.encoding.length != 0){ + rc = -EINVAL; + break; + } + rc = iwctl_siwencodeext(dev, NULL, &(wrq->u.encoding), extra); + } + break; + + case SIOCGIWENCODEEXT: + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWENCODEEXT \n"); + rc = iwctl_giwencodeext(dev, NULL, &(wrq->u.encoding), NULL); + break; + + case SIOCSIWMLME: + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWMLME \n"); + rc = iwctl_siwmlme(dev, NULL, &(wrq->u.data), wrq->u.data.pointer); + break; + +#endif // #ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT +//End Add -- //2008-0409-07, by Einsn Liu + +#endif // WIRELESS_EXT + + case IOCTL_CMD_TEST: + + if (!(pDevice->flags & DEVICE_FLAGS_OPENED)) { + rc = -EFAULT; + break; + } else { + rc = 0; + } + pReq = (PSCmdRequest)rq; + pReq->wResult = MAGIC_CODE; + break; + + case IOCTL_CMD_SET: + + #ifdef SndEvt_ToAPI + if((((PSCmdRequest)rq)->wCmdCode !=WLAN_CMD_SET_EVT) && + !(pDevice->flags & DEVICE_FLAGS_OPENED)) + #else + if (!(pDevice->flags & DEVICE_FLAGS_OPENED) && + (((PSCmdRequest)rq)->wCmdCode !=WLAN_CMD_SET_WPA)) + #endif + { + rc = -EFAULT; + break; + } else { + rc = 0; + } + + if (test_and_set_bit( 0, (void*)&(pMgmt->uCmdBusy))) { + return -EBUSY; + } + rc = private_ioctl(pDevice, rq); + clear_bit( 0, (void*)&(pMgmt->uCmdBusy)); + break; + + case IOCTL_CMD_HOSTAPD: + + +#if WIRELESS_EXT > 8 + rc = hostap_ioctl(pDevice, &wrq->u.data); +#else // WIRELESS_EXT > 8 + rc = hostap_ioctl(pDevice, (struct iw_point *) &wrq->u.data); +#endif // WIRELESS_EXT > 8 + break; + + case IOCTL_CMD_WPA: + +#if WIRELESS_EXT > 8 + rc = wpa_ioctl(pDevice, &wrq->u.data); +#else // WIRELESS_EXT > 8 + rc = wpa_ioctl(pDevice, (struct iw_point *) &wrq->u.data); +#endif // WIRELESS_EXT > 8 + break; + + case SIOCETHTOOL: + return ethtool_ioctl(dev, (void *) rq->ifr_data); + // All other calls are currently unsupported + + default: + rc = -EOPNOTSUPP; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Ioctl command not support..%x\n", cmd); + + + } + + if (pDevice->bCommit) { + if (pMgmt->eConfigMode == WMAC_CONFIG_AP) { + netif_stop_queue(pDevice->dev); + spin_lock_irq(&pDevice->lock); + bScheduleCommand((HANDLE)pDevice, WLAN_CMD_RUN_AP, NULL); + spin_unlock_irq(&pDevice->lock); + } + else { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Commit the settings\n"); + spin_lock_irq(&pDevice->lock); + pDevice->bLinkPass = FALSE; + memset(pMgmt->abyCurrBSSID, 0, 6); + pMgmt->eCurrState = WMAC_STATE_IDLE; + netif_stop_queue(pDevice->dev); + #ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT + pMgmt->eScanType = WMAC_SCAN_ACTIVE; + if(pDevice->bWPASuppWextEnabled !=TRUE) + #endif + bScheduleCommand((HANDLE) pDevice, WLAN_CMD_BSSID_SCAN, pMgmt->abyDesireSSID); + bScheduleCommand((HANDLE) pDevice, WLAN_CMD_SSID, NULL); + spin_unlock_irq(&pDevice->lock); + } + pDevice->bCommit = FALSE; + } + + return rc; +} + + +static int ethtool_ioctl(struct net_device *dev, void *useraddr) +{ + u32 ethcmd; + + if (copy_from_user(ðcmd, useraddr, sizeof(ethcmd))) + return -EFAULT; + + switch (ethcmd) { + case ETHTOOL_GDRVINFO: { + struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO}; + strncpy(info.driver, DEVICE_NAME, sizeof(info.driver)-1); + strncpy(info.version, DEVICE_VERSION, sizeof(info.version)-1); + if (copy_to_user(useraddr, &info, sizeof(info))) + return -EFAULT; + return 0; + } + + } + + return -EOPNOTSUPP; +} + +/*------------------------------------------------------------------*/ +#ifndef PRIVATE_OBJ + +MODULE_DEVICE_TABLE(pci, device_id_table); + +static struct pci_driver device_driver = { + name: DEVICE_NAME, + id_table: device_id_table, + probe: device_found1, + remove: device_remove1, +#ifdef CONFIG_PM + suspend: viawget_suspend, + resume: viawget_resume, +#endif +}; + +static int __init device_init_module(void) +{ + int ret; + + +// ret=pci_module_init(&device_driver); + //ret = pcie_port_service_register(&device_driver); + ret = pci_register_driver(&device_driver); +#ifdef CONFIG_PM + if(ret >= 0) + register_reboot_notifier(&device_notifier); +#endif + + return ret; +} + +static void __exit device_cleanup_module(void) +{ + + +#ifdef CONFIG_PM + unregister_reboot_notifier(&device_notifier); +#endif + pci_unregister_driver(&device_driver); + +} + +module_init(device_init_module); +module_exit(device_cleanup_module); + + +#ifdef CONFIG_PM +static int +device_notify_reboot(struct notifier_block *nb, unsigned long event, void *p) +{ + struct pci_dev *pdev = NULL; + switch(event) { + case SYS_DOWN: + case SYS_HALT: + case SYS_POWER_OFF: + while ((pdev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) { + if(pci_dev_driver(pdev) == &device_driver) { + if (pci_get_drvdata(pdev)) + viawget_suspend(pdev, 3); + } + } + } + return NOTIFY_DONE; +} + +static int +viawget_suspend(struct pci_dev *pcid, u32 state) +{ + int power_status; // to silence the compiler + + PSDevice pDevice=pci_get_drvdata(pcid); + PSMgmtObject pMgmt = pDevice->pMgmt; + + netif_stop_queue(pDevice->dev); + spin_lock_irq(&pDevice->lock); + pci_save_state(pcid); + del_timer(&pDevice->sTimerCommand); + del_timer(&pMgmt->sTimerSecondCallback); + pDevice->cbFreeCmdQueue = CMD_Q_SIZE; + pDevice->uCmdDequeueIdx = 0; + pDevice->uCmdEnqueueIdx = 0; + pDevice->bCmdRunning = FALSE; + MACbShutdown(pDevice->PortOffset); + MACvSaveContext(pDevice->PortOffset, pDevice->abyMacContext); + pDevice->bLinkPass = FALSE; + memset(pMgmt->abyCurrBSSID, 0, 6); + pMgmt->eCurrState = WMAC_STATE_IDLE; + pci_disable_device(pcid); + power_status = pci_set_power_state(pcid, state); + spin_unlock_irq(&pDevice->lock); + return 0; +} + +static int +viawget_resume(struct pci_dev *pcid) +{ + PSDevice pDevice=pci_get_drvdata(pcid); + PSMgmtObject pMgmt = pDevice->pMgmt; + int power_status; // to silence the compiler + + + power_status = pci_set_power_state(pcid, 0); + power_status = pci_enable_wake(pcid, 0, 0); + pci_restore_state(pcid); + if (netif_running(pDevice->dev)) { + spin_lock_irq(&pDevice->lock); + MACvRestoreContext(pDevice->PortOffset, pDevice->abyMacContext); + device_init_registers(pDevice, DEVICE_INIT_DXPL); + if (pMgmt->sNodeDBTable[0].bActive == TRUE) { // Assoc with BSS + pMgmt->sNodeDBTable[0].bActive = FALSE; + pDevice->bLinkPass = FALSE; + if(pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) { + // In Adhoc, BSS state set back to started. + pMgmt->eCurrState = WMAC_STATE_STARTED; + } + else { + pMgmt->eCurrMode = WMAC_MODE_STANDBY; + pMgmt->eCurrState = WMAC_STATE_IDLE; + } + } + init_timer(&pMgmt->sTimerSecondCallback); + init_timer(&pDevice->sTimerCommand); + MACvIntEnable(pDevice->PortOffset, IMR_MASK_VALUE); + BSSvClearBSSList((HANDLE)pDevice, pDevice->bLinkPass); + bScheduleCommand((HANDLE) pDevice, WLAN_CMD_BSSID_SCAN, NULL); + bScheduleCommand((HANDLE) pDevice, WLAN_CMD_SSID, NULL); + spin_unlock_irq(&pDevice->lock); + } + return 0; +} + +#endif + +#endif //#ifndef PRIVATE_OBJ + +#ifdef PRIVATE_OBJ + + +int __device_hw_reset(HANDLE pExDevice){ + PSDevice_info pDevice_info = (PSDevice_info)pExDevice; + + return MACbSoftwareReset(pDevice_info->port_offset); +} + + +int __device_hw_init(HANDLE pExDevice){ + PSDevice_info pDevice_info = (PSDevice_info)pExDevice; + PSDevice pDevice; + + pDevice = (PSDevice)kmalloc(sizeof(DEVICE_INFO), (int)GFP_ATOMIC); + if (pDevice == NULL) + return FALSE; + + memset(pDevice, 0, sizeof(DEVICE_INFO)); + pDevice_info->pWDevice = pDevice; + pDevice->PortOffset = pDevice_info->port_offset; + pDevice->dev = pDevice_info->dev; + pDevice->pcid = pDevice_info->pcid; + pDevice->chip_id = pDevice_info->chip_id; + pDevice->memaddr = pDevice_info->mem_addr; + pDevice->ioaddr = pDevice_info->io_addr; + pDevice->io_size = pDevice_info->io_size; + pDevice->nTxQueues = pDevice_info->nTxQueues; + pDevice->multicast_limit = pDevice_info->multicast_limit; + pDevice->sMgmtObj.pAdapter = (PVOID)pDevice; + pDevice->pMgmt = &(pDevice->sMgmtObj); + MACvInitialize(pDevice->PortOffset); + device_get_options(pDevice, 0 , pDevice_info->dev->name); + device_set_options(pDevice); + pDevice->sOpts.flags &= pDevice_info->flags; + pDevice->flags = pDevice->sOpts.flags | (pDevice_info->flags & 0xFF000000UL); + spin_lock_init(&(pDevice->lock)); + + return TRUE; +} + + +void __device_read_mac(HANDLE pExDevice, PBYTE dev_addr){ + PSDevice_info pDevice_info = (PSDevice_info)pExDevice; + PSDevice pDevice = (PSDevice)(pDevice_info->pWDevice); + + MACvReadEtherAddress(pDevice->PortOffset, dev_addr); + return; +} + + +#endif + + diff --git a/drivers/staging/vt6655/dpc.c b/drivers/staging/vt6655/dpc.c new file mode 100644 index 000000000000..acc6d82a9544 --- /dev/null +++ b/drivers/staging/vt6655/dpc.c @@ -0,0 +1,1668 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * File: dpc.c + * + * Purpose: handle dpc rx functions + * + * Author: Lyndon Chen + * + * Date: May 20, 2003 + * + * Functions: + * device_receive_frame - Rcv 802.11 frame function + * s_bAPModeRxCtl- AP Rcv frame filer Ctl. + * s_bAPModeRxData- AP Rcv data frame handle + * s_bHandleRxEncryption- Rcv decrypted data via on-fly + * s_bHostWepRxEncryption- Rcv encrypted data via host + * s_byGetRateIdx- get rate index + * s_vGetDASA- get data offset + * s_vProcessRxMACHeader- Rcv 802.11 and translate to 802.3 + * + * Revision History: + * + */ + + +#if !defined(__DEVICE_H__) +#include "device.h" +#endif +#if !defined(__RXTX_H__) +#include "rxtx.h" +#endif +#if !defined(__TETHER_H__) +#include "tether.h" +#endif +#if !defined(__CARD_H__) +#include "card.h" +#endif +#if !defined(__BSSDB_H__) +#include "bssdb.h" +#endif +#if !defined(__MAC_H__) +#include "mac.h" +#endif +#if !defined(__BASEBAND_H__) +#include "baseband.h" +#endif +#if !defined(__UMEM_H__) +#include "umem.h" +#endif +#if !defined(__MICHAEL_H__) +#include "michael.h" +#endif +#if !defined(__TKIP_H__) +#include "tkip.h" +#endif +#if !defined(__TCRC_H__) +#include "tcrc.h" +#endif +#if !defined(__WCTL_H__) +#include "wctl.h" +#endif +#if !defined(__WROUTE_H__) +#include "wroute.h" +#endif +#if !defined(__TBIT_H__) +#include "tbit.h" +#endif +#if !defined(__HOSTAP_H__) +#include "hostap.h" +#endif +#if !defined(__RF_H__) +#include "rf.h" +#endif +#if !defined(__IOWPA_H__) +#include "iowpa.h" +#endif +#if !defined(__AES_H__) +#include "aes_ccmp.h" +#endif + +//#define PLICE_DEBUG + + +/*--------------------- Static Definitions -------------------------*/ + +/*--------------------- Static Classes ----------------------------*/ + +/*--------------------- Static Variables --------------------------*/ +//static int msglevel =MSG_LEVEL_DEBUG; +static int msglevel =MSG_LEVEL_INFO; + +const BYTE acbyRxRate[MAX_RATE] = +{2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108}; + + +/*--------------------- Static Functions --------------------------*/ + +/*--------------------- Static Definitions -------------------------*/ + +/*--------------------- Static Functions --------------------------*/ + +static BYTE s_byGetRateIdx(IN BYTE byRate); + + +static +VOID +s_vGetDASA( + IN PBYTE pbyRxBufferAddr, + OUT PUINT pcbHeaderSize, + OUT PSEthernetHeader psEthHeader + ); + +static +VOID +s_vProcessRxMACHeader ( + IN PSDevice pDevice, + IN PBYTE pbyRxBufferAddr, + IN UINT cbPacketSize, + IN BOOL bIsWEP, + IN BOOL bExtIV, + OUT PUINT pcbHeadSize + ); + +static BOOL s_bAPModeRxCtl( + IN PSDevice pDevice, + IN PBYTE pbyFrame, + IN INT iSANodeIndex + ); + +#ifdef PRIVATE_OBJ + +static BOOL s_bAPModeRxData ( + IN PSDevice pDevice, + IN ref_sk_buff* skb, + IN UINT FrameSize, + IN UINT cbHeaderOffset, + IN INT iSANodeIndex, + IN INT iDANodeIndex + ); +#else + +static BOOL s_bAPModeRxData ( + IN PSDevice pDevice, + IN struct sk_buff* skb, + IN UINT FrameSize, + IN UINT cbHeaderOffset, + IN INT iSANodeIndex, + IN INT iDANodeIndex + ); +#endif + + +static BOOL s_bHandleRxEncryption( + IN PSDevice pDevice, + IN PBYTE pbyFrame, + IN UINT FrameSize, + IN PBYTE pbyRsr, + OUT PBYTE pbyNewRsr, + OUT PSKeyItem *pKeyOut, + OUT PBOOL pbExtIV, + OUT PWORD pwRxTSC15_0, + OUT PDWORD pdwRxTSC47_16 + ); + +static BOOL s_bHostWepRxEncryption( + + IN PSDevice pDevice, + IN PBYTE pbyFrame, + IN UINT FrameSize, + IN PBYTE pbyRsr, + IN BOOL bOnFly, + IN PSKeyItem pKey, + OUT PBYTE pbyNewRsr, + OUT PBOOL pbExtIV, + OUT PWORD pwRxTSC15_0, + OUT PDWORD pdwRxTSC47_16 + + ); + +/*--------------------- Export Variables --------------------------*/ + +/*+ + * + * Description: + * Translate Rcv 802.11 header to 802.3 header with Rx buffer + * + * Parameters: + * In: + * pDevice + * dwRxBufferAddr - Address of Rcv Buffer + * cbPacketSize - Rcv Packet size + * bIsWEP - If Rcv with WEP + * Out: + * pcbHeaderSize - 802.11 header size + * + * Return Value: None + * +-*/ +static +VOID +s_vProcessRxMACHeader ( + IN PSDevice pDevice, + IN PBYTE pbyRxBufferAddr, + IN UINT cbPacketSize, + IN BOOL bIsWEP, + IN BOOL bExtIV, + OUT PUINT pcbHeadSize + ) +{ + PBYTE pbyRxBuffer; + UINT cbHeaderSize = 0; + PWORD pwType; + PS802_11Header pMACHeader; + int ii; + + + pMACHeader = (PS802_11Header) (pbyRxBufferAddr + cbHeaderSize); + + s_vGetDASA((PBYTE)pMACHeader, &cbHeaderSize, &pDevice->sRxEthHeader); + + if (bIsWEP) { + if (bExtIV) { + // strip IV&ExtIV , add 8 byte + cbHeaderSize += (WLAN_HDR_ADDR3_LEN + 8); + } else { + // strip IV , add 4 byte + cbHeaderSize += (WLAN_HDR_ADDR3_LEN + 4); + } + } + else { + cbHeaderSize += WLAN_HDR_ADDR3_LEN; + }; + + pbyRxBuffer = (PBYTE) (pbyRxBufferAddr + cbHeaderSize); + if (IS_ETH_ADDRESS_EQUAL(pbyRxBuffer, &pDevice->abySNAP_Bridgetunnel[0])) { + cbHeaderSize += 6; + } + else if (IS_ETH_ADDRESS_EQUAL(pbyRxBuffer, &pDevice->abySNAP_RFC1042[0])) { + cbHeaderSize += 6; + pwType = (PWORD) (pbyRxBufferAddr + cbHeaderSize); + if ((*pwType!= TYPE_PKT_IPX) && (*pwType != cpu_to_le16(0xF380))) { + } + else { + cbHeaderSize -= 8; + pwType = (PWORD) (pbyRxBufferAddr + cbHeaderSize); + if (bIsWEP) { + if (bExtIV) { + *pwType = htons(cbPacketSize - WLAN_HDR_ADDR3_LEN - 8); // 8 is IV&ExtIV + } else { + *pwType = htons(cbPacketSize - WLAN_HDR_ADDR3_LEN - 4); // 4 is IV + } + } + else { + *pwType = htons(cbPacketSize - WLAN_HDR_ADDR3_LEN); + } + } + } + else { + cbHeaderSize -= 2; + pwType = (PWORD) (pbyRxBufferAddr + cbHeaderSize); + if (bIsWEP) { + if (bExtIV) { + *pwType = htons(cbPacketSize - WLAN_HDR_ADDR3_LEN - 8); // 8 is IV&ExtIV + } else { + *pwType = htons(cbPacketSize - WLAN_HDR_ADDR3_LEN - 4); // 4 is IV + } + } + else { + *pwType = htons(cbPacketSize - WLAN_HDR_ADDR3_LEN); + } + } + + cbHeaderSize -= (U_ETHER_ADDR_LEN * 2); + pbyRxBuffer = (PBYTE) (pbyRxBufferAddr + cbHeaderSize); + for(ii=0;iisRxEthHeader.abyDstAddr[ii]; + for(ii=0;iisRxEthHeader.abySrcAddr[ii]; + + *pcbHeadSize = cbHeaderSize; +} + + + + +static BYTE s_byGetRateIdx (IN BYTE byRate) +{ + BYTE byRateIdx; + + for (byRateIdx = 0; byRateIdx wFrameCtl & FC_TODS) == 0) { + if (pMACHeader->wFrameCtl & FC_FROMDS) { + for(ii=0;iiabyDstAddr[ii] = pMACHeader->abyAddr1[ii]; + psEthHeader->abySrcAddr[ii] = pMACHeader->abyAddr3[ii]; + } + } + else { + // IBSS mode + for(ii=0;iiabyDstAddr[ii] = pMACHeader->abyAddr1[ii]; + psEthHeader->abySrcAddr[ii] = pMACHeader->abyAddr2[ii]; + } + } + } + else { + // Is AP mode.. + if (pMACHeader->wFrameCtl & FC_FROMDS) { + for(ii=0;iiabyDstAddr[ii] = pMACHeader->abyAddr3[ii]; + psEthHeader->abySrcAddr[ii] = pMACHeader->abyAddr4[ii]; + cbHeaderSize += 6; + } + } + else { + for(ii=0;iiabyDstAddr[ii] = pMACHeader->abyAddr3[ii]; + psEthHeader->abySrcAddr[ii] = pMACHeader->abyAddr2[ii]; + } + } + }; + *pcbHeaderSize = cbHeaderSize; +} + + + + +//PLICE_DEBUG -> + +VOID MngWorkItem(PVOID Context) +{ + PSRxMgmtPacket pRxMgmtPacket; + PSDevice pDevice = (PSDevice) Context; + //printk("Enter MngWorkItem,Queue packet num is %d\n",pDevice->rxManeQueue.packet_num); + spin_lock_irq(&pDevice->lock); + while(pDevice->rxManeQueue.packet_num != 0) + { + pRxMgmtPacket = DeQueue(pDevice); + vMgrRxManagePacket(pDevice, pDevice->pMgmt, pRxMgmtPacket); + } + spin_unlock_irq(&pDevice->lock); +} + + +//PLICE_DEBUG<- + + + +BOOL +device_receive_frame ( + IN PSDevice pDevice, + IN PSRxDesc pCurrRD + ) +{ + + PDEVICE_RD_INFO pRDInfo = pCurrRD->pRDInfo; +#ifdef PLICE_DEBUG + //printk("device_receive_frame:pCurrRD is %x,pRDInfo is %x\n",pCurrRD,pCurrRD->pRDInfo); +#endif + struct net_device_stats* pStats=&pDevice->stats; +#ifdef PRIVATE_OBJ + ref_sk_buff* skb; +#else + struct sk_buff* skb; +#endif + PSMgmtObject pMgmt = pDevice->pMgmt; + PSRxMgmtPacket pRxPacket = &(pDevice->pMgmt->sRxPacket); + PS802_11Header p802_11Header; + PBYTE pbyRsr; + PBYTE pbyNewRsr; + PBYTE pbyRSSI; + PQWORD pqwTSFTime; + PWORD pwFrameSize; + PBYTE pbyFrame; + BOOL bDeFragRx = FALSE; + BOOL bIsWEP = FALSE; + UINT cbHeaderOffset; + UINT FrameSize; + WORD wEtherType = 0; + INT iSANodeIndex = -1; + INT iDANodeIndex = -1; + UINT ii; + UINT cbIVOffset; + BOOL bExtIV = FALSE; + PBYTE pbyRxSts; + PBYTE pbyRxRate; + PBYTE pbySQ; + UINT cbHeaderSize; + PSKeyItem pKey = NULL; + WORD wRxTSC15_0 = 0; + DWORD dwRxTSC47_16 = 0; + SKeyItem STempKey; + // 802.11h RPI + DWORD dwDuration = 0; + LONG ldBm = 0; + LONG ldBmThreshold = 0; + PS802_11Header pMACHeader; + BOOL bRxeapol_key = FALSE; + +// DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---------- device_receive_frame---\n"); +#ifdef PRIVATE_OBJ + skb = &(pRDInfo->ref_skb); +#else + + skb = pRDInfo->skb; +#endif + + +//PLICE_DEBUG-> +#if 1 + pci_unmap_single(pDevice->pcid, pRDInfo->skb_dma, + pDevice->rx_buf_sz, PCI_DMA_FROMDEVICE); +#endif +//PLICE_DEBUG<- + pwFrameSize = (PWORD)(skb->data + 2); + FrameSize = cpu_to_le16(pCurrRD->m_rd1RD1.wReqCount) - cpu_to_le16(pCurrRD->m_rd0RD0.wResCount); + + // Max: 2312Payload + 30HD +4CRC + 2Padding + 4Len + 8TSF + 4RSR + // Min (ACK): 10HD +4CRC + 2Padding + 4Len + 8TSF + 4RSR + if ((FrameSize > 2364)||(FrameSize <= 32)) { + // Frame Size error drop this packet. + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---------- WRONG Length 1 \n"); + return FALSE; + } + + pbyRxSts = (PBYTE) (skb->data); + pbyRxRate = (PBYTE) (skb->data + 1); + pbyRsr = (PBYTE) (skb->data + FrameSize - 1); + pbyRSSI = (PBYTE) (skb->data + FrameSize - 2); + pbyNewRsr = (PBYTE) (skb->data + FrameSize - 3); + pbySQ = (PBYTE) (skb->data + FrameSize - 4); + pqwTSFTime = (PQWORD) (skb->data + FrameSize - 12); + pbyFrame = (PBYTE)(skb->data + 4); + + // get packet size + FrameSize = cpu_to_le16(*pwFrameSize); + + if ((FrameSize > 2346)|(FrameSize < 14)) { // Max: 2312Payload + 30HD +4CRC + // Min: 14 bytes ACK + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---------- WRONG Length 2 \n"); + return FALSE; + } +//PLICE_DEBUG-> +#if 1 + // update receive statistic counter + STAvUpdateRDStatCounter(&pDevice->scStatistic, + *pbyRsr, + *pbyNewRsr, + *pbyRxRate, + pbyFrame, + FrameSize); + +#endif + + pMACHeader=(PS802_11Header)((PBYTE) (skb->data)+8); +//PLICE_DEBUG<- + if (pDevice->bMeasureInProgress == TRUE) { + if ((*pbyRsr & RSR_CRCOK) != 0) { + pDevice->byBasicMap |= 0x01; + } + dwDuration = (FrameSize << 4); + dwDuration /= acbyRxRate[*pbyRxRate%MAX_RATE]; + if (*pbyRxRate <= RATE_11M) { + if (BITbIsBitOn(*pbyRxSts, 0x01)) { + // long preamble + dwDuration += 192; + } else { + // short preamble + dwDuration += 96; + } + } else { + dwDuration += 16; + } + RFvRSSITodBm(pDevice, *pbyRSSI, &ldBm); + ldBmThreshold = -57; + for (ii = 7; ii > 0;) { + if (ldBm > ldBmThreshold) { + break; + } + ldBmThreshold -= 5; + ii--; + } + pDevice->dwRPIs[ii] += dwDuration; + return FALSE; + } + + if (!IS_MULTICAST_ADDRESS(pbyFrame) && !IS_BROADCAST_ADDRESS(pbyFrame)) { + if (WCTLbIsDuplicate(&(pDevice->sDupRxCache), (PS802_11Header) (skb->data + 4))) { + pDevice->s802_11Counter.FrameDuplicateCount++; + return FALSE; + } + } + + + // Use for TKIP MIC + s_vGetDASA(skb->data+4, &cbHeaderSize, &pDevice->sRxEthHeader); + + // filter packet send from myself + if (IS_ETH_ADDRESS_EQUAL((PBYTE)&(pDevice->sRxEthHeader.abySrcAddr[0]), pDevice->abyCurrentNetAddr)) + return FALSE; + + if ((pMgmt->eCurrMode == WMAC_MODE_ESS_AP) || (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA)) { + if (IS_CTL_PSPOLL(pbyFrame) || !IS_TYPE_CONTROL(pbyFrame)) { + p802_11Header = (PS802_11Header) (pbyFrame); + // get SA NodeIndex + if (BSSDBbIsSTAInNodeDB(pMgmt, (PBYTE)(p802_11Header->abyAddr2), &iSANodeIndex)) { +#ifdef PRIVATE_OBJ + pMgmt->sNodeDBTable[iSANodeIndex].ulLastRxJiffer = get_jiffies(); +#else + pMgmt->sNodeDBTable[iSANodeIndex].ulLastRxJiffer = jiffies; +#endif + pMgmt->sNodeDBTable[iSANodeIndex].uInActiveCount = 0; + } + } + } + + if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) { + if (s_bAPModeRxCtl(pDevice, pbyFrame, iSANodeIndex) == TRUE) { + return FALSE; + } + } + if (IS_FC_WEP(pbyFrame)) { + BOOL bRxDecryOK = FALSE; + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"rx WEP pkt\n"); + bIsWEP = TRUE; + if ((pDevice->bEnableHostWEP) && (iSANodeIndex >= 0)) { + pKey = &STempKey; + pKey->byCipherSuite = pMgmt->sNodeDBTable[iSANodeIndex].byCipherSuite; + pKey->dwKeyIndex = pMgmt->sNodeDBTable[iSANodeIndex].dwKeyIndex; + pKey->uKeyLength = pMgmt->sNodeDBTable[iSANodeIndex].uWepKeyLength; + pKey->dwTSC47_16 = pMgmt->sNodeDBTable[iSANodeIndex].dwTSC47_16; + pKey->wTSC15_0 = pMgmt->sNodeDBTable[iSANodeIndex].wTSC15_0; + memcpy(pKey->abyKey, + &pMgmt->sNodeDBTable[iSANodeIndex].abyWepKey[0], + pKey->uKeyLength + ); + + bRxDecryOK = s_bHostWepRxEncryption(pDevice, + pbyFrame, + FrameSize, + pbyRsr, + pMgmt->sNodeDBTable[iSANodeIndex].bOnFly, + pKey, + pbyNewRsr, + &bExtIV, + &wRxTSC15_0, + &dwRxTSC47_16); + } else { + bRxDecryOK = s_bHandleRxEncryption(pDevice, + pbyFrame, + FrameSize, + pbyRsr, + pbyNewRsr, + &pKey, + &bExtIV, + &wRxTSC15_0, + &dwRxTSC47_16); + } + + if (bRxDecryOK) { + if ((*pbyNewRsr & NEWRSR_DECRYPTOK) == 0) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ICV Fail\n"); + if ( (pDevice->pMgmt->eAuthenMode == WMAC_AUTH_WPA) || + (pDevice->pMgmt->eAuthenMode == WMAC_AUTH_WPAPSK) || + (pDevice->pMgmt->eAuthenMode == WMAC_AUTH_WPANONE) || + (pDevice->pMgmt->eAuthenMode == WMAC_AUTH_WPA2) || + (pDevice->pMgmt->eAuthenMode == WMAC_AUTH_WPA2PSK)) { + + if ((pKey != NULL) && (pKey->byCipherSuite == KEY_CTL_TKIP)) { + pDevice->s802_11Counter.TKIPICVErrors++; + } else if ((pKey != NULL) && (pKey->byCipherSuite == KEY_CTL_CCMP)) { + pDevice->s802_11Counter.CCMPDecryptErrors++; + } else if ((pKey != NULL) && (pKey->byCipherSuite == KEY_CTL_WEP)) { +// pDevice->s802_11Counter.WEPICVErrorCount.QuadPart++; + } + } + return FALSE; + } + } else { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"WEP Func Fail\n"); + return FALSE; + } + if ((pKey != NULL) && (pKey->byCipherSuite == KEY_CTL_CCMP)) + FrameSize -= 8; // Message Integrity Code + else + FrameSize -= 4; // 4 is ICV + } + + + // + // RX OK + // + //remove the CRC length + FrameSize -= U_CRC_LEN; + + if ((BITbIsAllBitsOff(*pbyRsr, (RSR_ADDRBROAD | RSR_ADDRMULTI))) && // unicast address + (IS_FRAGMENT_PKT((skb->data+4))) + ) { + // defragment + bDeFragRx = WCTLbHandleFragment(pDevice, (PS802_11Header) (skb->data+4), FrameSize, bIsWEP, bExtIV); + pDevice->s802_11Counter.ReceivedFragmentCount++; + if (bDeFragRx) { + // defrag complete +#ifdef PRIVATE_OBJ + skb = &(pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].ref_skb); +#else + skb = pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].skb; +#endif + FrameSize = pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].cbFrameLength; + + } + else { + return FALSE; + } + } + + +// Management & Control frame Handle + if ((IS_TYPE_DATA((skb->data+4))) == FALSE) { + // Handle Control & Manage Frame + + if (IS_TYPE_MGMT((skb->data+4))) { + PBYTE pbyData1; + PBYTE pbyData2; + + pRxPacket->p80211Header = (PUWLAN_80211HDR)(skb->data+4); + pRxPacket->cbMPDULen = FrameSize; + pRxPacket->uRSSI = *pbyRSSI; + pRxPacket->bySQ = *pbySQ; + HIDWORD(pRxPacket->qwLocalTSF) = cpu_to_le32(HIDWORD(*pqwTSFTime)); + LODWORD(pRxPacket->qwLocalTSF) = cpu_to_le32(LODWORD(*pqwTSFTime)); + if (bIsWEP) { + // strip IV + pbyData1 = WLAN_HDR_A3_DATA_PTR(skb->data+4); + pbyData2 = WLAN_HDR_A3_DATA_PTR(skb->data+4) + 4; + for (ii = 0; ii < (FrameSize - 4); ii++) { + *pbyData1 = *pbyData2; + pbyData1++; + pbyData2++; + } + } + pRxPacket->byRxRate = s_byGetRateIdx(*pbyRxRate); + pRxPacket->byRxChannel = (*pbyRxSts) >> 2; +//PLICE_DEBUG-> +//EnQueue(pDevice,pRxPacket); + +#ifdef THREAD + EnQueue(pDevice,pRxPacket); + + //printk("enque time is %x\n",jiffies); + //up(&pDevice->mlme_semaphore); + //Enque (pDevice->FirstRecvMngList,pDevice->LastRecvMngList,pMgmt); +#else + +#ifdef TASK_LET + EnQueue(pDevice,pRxPacket); + tasklet_schedule(&pDevice->RxMngWorkItem); +#else +//printk("RxMan\n"); + vMgrRxManagePacket((HANDLE)pDevice, pDevice->pMgmt, pRxPacket); + //tasklet_schedule(&pDevice->RxMngWorkItem); +#endif + +#endif +//PLICE_DEBUG<- + //vMgrRxManagePacket((HANDLE)pDevice, pDevice->pMgmt, pRxPacket); + // hostap Deamon handle 802.11 management + if (pDevice->bEnableHostapd) { + skb->dev = pDevice->apdev; +#ifdef PRIVATE_OBJ + ref_skb_add_offset(skb->skb, 4); + ref_skb_set_dev(pDevice->apdev, skb->skb); + skb_put(skb->skb, FrameSize); + skb->mac_header = skb->data; + *(skb->pkt_type) = PACKET_OTHERHOST; + *(skb->protocol) = htons(ETH_P_802_2); + memset(skb->cb, 0, sizeof(skb->cb)); + netif_rx(skb->skb); +#else + skb->data += 4; + skb->tail += 4; + skb_put(skb, FrameSize); + skb->mac_header = skb->data; + skb->pkt_type = PACKET_OTHERHOST; + skb->protocol = htons(ETH_P_802_2); + memset(skb->cb, 0, sizeof(skb->cb)); + netif_rx(skb); +#endif + return TRUE; + } + } + else { + // Control Frame + }; + return FALSE; + } + else { + if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) { + //In AP mode, hw only check addr1(BSSID or RA) if equal to local MAC. + if (BITbIsBitOff(*pbyRsr, RSR_BSSIDOK)) { + if (bDeFragRx) { + if (!device_alloc_frag_buf(pDevice, &pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx])) { + DEVICE_PRT(MSG_LEVEL_ERR,KERN_ERR "%s: can not alloc more frag bufs\n", + pDevice->dev->name); + } + } + return FALSE; + } + } + else { + // discard DATA packet while not associate || BSSID error + if ((pDevice->bLinkPass == FALSE) || + BITbIsBitOff(*pbyRsr, RSR_BSSIDOK)) { + if (bDeFragRx) { + if (!device_alloc_frag_buf(pDevice, &pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx])) { + DEVICE_PRT(MSG_LEVEL_ERR,KERN_ERR "%s: can not alloc more frag bufs\n", + pDevice->dev->name); + } + } + return FALSE; + } + + //mike add:station mode check eapol-key challenge---> + { + BYTE Protocol_Version; //802.1x Authentication + BYTE Packet_Type; //802.1x Authentication + if (bIsWEP) + cbIVOffset = 8; + else + cbIVOffset = 0; + wEtherType = (skb->data[cbIVOffset + 8 + 24 + 6] << 8) | + skb->data[cbIVOffset + 8 + 24 + 6 + 1]; + Protocol_Version = skb->data[cbIVOffset + 8 + 24 + 6 + 1 +1]; + Packet_Type = skb->data[cbIVOffset + 8 + 24 + 6 + 1 +1+1]; + if (wEtherType == ETH_P_PAE) { //Protocol Type in LLC-Header + if(((Protocol_Version==1) ||(Protocol_Version==2)) && + (Packet_Type==3)) { //802.1x OR eapol-key challenge frame receive + bRxeapol_key = TRUE; + } + } + } + //mike add:station mode check eapol-key challenge<--- + } + } + +// Data frame Handle + + if (pDevice->bEnablePSMode) { + if (IS_FC_MOREDATA((skb->data+4))) { + if (BITbIsBitOn(*pbyRsr, RSR_ADDROK)) { + //PSbSendPSPOLL((PSDevice)pDevice); + } + } + else { + if (pDevice->pMgmt->bInTIMWake == TRUE) { + pDevice->pMgmt->bInTIMWake = FALSE; + } + } + }; + + // Now it only supports 802.11g Infrastructure Mode, and support rate must up to 54 Mbps + if (pDevice->bDiversityEnable && (FrameSize>50) && + (pDevice->eOPMode == OP_MODE_INFRASTRUCTURE) && + (pDevice->bLinkPass == TRUE)) { + //printk("device_receive_frame: RxRate is %d\n",*pbyRxRate); + BBvAntennaDiversity(pDevice, s_byGetRateIdx(*pbyRxRate), 0); + } + + + if (pDevice->byLocalID != REV_ID_VT3253_B1) { + pDevice->uCurrRSSI = *pbyRSSI; + } + pDevice->byCurrSQ = *pbySQ; + + if ((*pbyRSSI != 0) && + (pMgmt->pCurrBSS!=NULL)) { + RFvRSSITodBm(pDevice, *pbyRSSI, &ldBm); + // Moniter if RSSI is too strong. + pMgmt->pCurrBSS->byRSSIStatCnt++; + pMgmt->pCurrBSS->byRSSIStatCnt %= RSSI_STAT_COUNT; + pMgmt->pCurrBSS->ldBmAverage[pMgmt->pCurrBSS->byRSSIStatCnt] = ldBm; + for(ii=0;iipCurrBSS->ldBmAverage[ii] != 0) { + pMgmt->pCurrBSS->ldBmMAX = max(pMgmt->pCurrBSS->ldBmAverage[ii], ldBm); + } + } + } + + // ----------------------------------------------- + + if ((pMgmt->eCurrMode == WMAC_MODE_ESS_AP) && (pDevice->bEnable8021x == TRUE)){ + BYTE abyMacHdr[24]; + + // Only 802.1x packet incoming allowed + if (bIsWEP) + cbIVOffset = 8; + else + cbIVOffset = 0; + wEtherType = (skb->data[cbIVOffset + 4 + 24 + 6] << 8) | + skb->data[cbIVOffset + 4 + 24 + 6 + 1]; + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"wEtherType = %04x \n", wEtherType); + if (wEtherType == ETH_P_PAE) { + skb->dev = pDevice->apdev; + + if (bIsWEP == TRUE) { + // strip IV header(8) + memcpy(&abyMacHdr[0], (skb->data + 4), 24); + memcpy((skb->data + 4 + cbIVOffset), &abyMacHdr[0], 24); + } +#ifdef PRIVATE_OBJ + ref_skb_add_offset(skb->skb, (cbIVOffset + 4)); + ref_skb_set_dev(pDevice->apdev, skb->skb); + skb_put(skb->skb, FrameSize); + skb->mac_header = skb->data; + *(skb->pkt_type) = PACKET_OTHERHOST; + *(skb->protocol) = htons(ETH_P_802_2); + memset(skb->cb, 0, sizeof(skb->cb)); + netif_rx(skb->skb); +#else + skb->data += (cbIVOffset + 4); + skb->tail += (cbIVOffset + 4); + skb_put(skb, FrameSize); + skb->mac_header = skb->data; + + skb->pkt_type = PACKET_OTHERHOST; + skb->protocol = htons(ETH_P_802_2); + memset(skb->cb, 0, sizeof(skb->cb)); + netif_rx(skb); +#endif + return TRUE; + +} + // check if 802.1x authorized + if (!(pMgmt->sNodeDBTable[iSANodeIndex].dwFlags & WLAN_STA_AUTHORIZED)) + return FALSE; + } + + + if ((pKey != NULL) && (pKey->byCipherSuite == KEY_CTL_TKIP)) { + if (bIsWEP) { + FrameSize -= 8; //MIC + } + } + + //-------------------------------------------------------------------------------- + // Soft MIC + if ((pKey != NULL) && (pKey->byCipherSuite == KEY_CTL_TKIP)) { + if (bIsWEP) { + PDWORD pdwMIC_L; + PDWORD pdwMIC_R; + DWORD dwMIC_Priority; + DWORD dwMICKey0 = 0, dwMICKey1 = 0; + DWORD dwLocalMIC_L = 0; + DWORD dwLocalMIC_R = 0; + viawget_wpa_header *wpahdr; + + + if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) { + dwMICKey0 = cpu_to_le32(*(PDWORD)(&pKey->abyKey[24])); + dwMICKey1 = cpu_to_le32(*(PDWORD)(&pKey->abyKey[28])); + } + else { + if (pDevice->pMgmt->eAuthenMode == WMAC_AUTH_WPANONE) { + dwMICKey0 = cpu_to_le32(*(PDWORD)(&pKey->abyKey[16])); + dwMICKey1 = cpu_to_le32(*(PDWORD)(&pKey->abyKey[20])); + } else if ((pKey->dwKeyIndex & BIT28) == 0) { + dwMICKey0 = cpu_to_le32(*(PDWORD)(&pKey->abyKey[16])); + dwMICKey1 = cpu_to_le32(*(PDWORD)(&pKey->abyKey[20])); + } else { + dwMICKey0 = cpu_to_le32(*(PDWORD)(&pKey->abyKey[24])); + dwMICKey1 = cpu_to_le32(*(PDWORD)(&pKey->abyKey[28])); + } + } + + MIC_vInit(dwMICKey0, dwMICKey1); + MIC_vAppend((PBYTE)&(pDevice->sRxEthHeader.abyDstAddr[0]), 12); + dwMIC_Priority = 0; + MIC_vAppend((PBYTE)&dwMIC_Priority, 4); + // 4 is Rcv buffer header, 24 is MAC Header, and 8 is IV and Ext IV. + MIC_vAppend((PBYTE)(skb->data + 4 + WLAN_HDR_ADDR3_LEN + 8), + FrameSize - WLAN_HDR_ADDR3_LEN - 8); + MIC_vGetMIC(&dwLocalMIC_L, &dwLocalMIC_R); + MIC_vUnInit(); + + pdwMIC_L = (PDWORD)(skb->data + 4 + FrameSize); + pdwMIC_R = (PDWORD)(skb->data + 4 + FrameSize + 4); + //DBG_PRN_GRP12(("RxL: %lx, RxR: %lx\n", *pdwMIC_L, *pdwMIC_R)); + //DBG_PRN_GRP12(("LocalL: %lx, LocalR: %lx\n", dwLocalMIC_L, dwLocalMIC_R)); + //DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"dwMICKey0= %lx,dwMICKey1= %lx \n", dwMICKey0, dwMICKey1); + + + if ((cpu_to_le32(*pdwMIC_L) != dwLocalMIC_L) || (cpu_to_le32(*pdwMIC_R) != dwLocalMIC_R) || + (pDevice->bRxMICFail == TRUE)) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"MIC comparison is fail!\n"); + pDevice->bRxMICFail = FALSE; + //pDevice->s802_11Counter.TKIPLocalMICFailures.QuadPart++; + pDevice->s802_11Counter.TKIPLocalMICFailures++; + if (bDeFragRx) { + if (!device_alloc_frag_buf(pDevice, &pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx])) { + DEVICE_PRT(MSG_LEVEL_ERR,KERN_ERR "%s: can not alloc more frag bufs\n", + pDevice->dev->name); + } + } + +//2008-0409-07, by Einsn Liu + #ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT + //send event to wpa_supplicant + //if(pDevice->bWPADevEnable == TRUE) + { + union iwreq_data wrqu; + struct iw_michaelmicfailure ev; + int keyidx = pbyFrame[cbHeaderSize+3] >> 6; //top two-bits + memset(&ev, 0, sizeof(ev)); + ev.flags = keyidx & IW_MICFAILURE_KEY_ID; + if ((pMgmt->eCurrMode == WMAC_MODE_ESS_STA) && + (pMgmt->eCurrState == WMAC_STATE_ASSOC) && + (*pbyRsr & (RSR_ADDRBROAD | RSR_ADDRMULTI)) == 0) { + ev.flags |= IW_MICFAILURE_PAIRWISE; + } else { + ev.flags |= IW_MICFAILURE_GROUP; + } + + ev.src_addr.sa_family = ARPHRD_ETHER; + memcpy(ev.src_addr.sa_data, pMACHeader->abyAddr2, ETH_ALEN); + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = sizeof(ev); + wireless_send_event(pDevice->dev, IWEVMICHAELMICFAILURE, &wrqu, (char *)&ev); + + } + #endif + if ((pDevice->bWPADEVUp) && (pDevice->skb != NULL)) { + wpahdr = (viawget_wpa_header *)pDevice->skb->data; + if ((pDevice->pMgmt->eCurrMode == WMAC_MODE_ESS_STA) && + (pDevice->pMgmt->eCurrState == WMAC_STATE_ASSOC) && + (*pbyRsr & (RSR_ADDRBROAD | RSR_ADDRMULTI)) == 0) { + //s802_11_Status.Flags = NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR; + wpahdr->type = VIAWGET_PTK_MIC_MSG; + } else { + //s802_11_Status.Flags = NDIS_802_11_AUTH_REQUEST_GROUP_ERROR; + wpahdr->type = VIAWGET_GTK_MIC_MSG; + } + wpahdr->resp_ie_len = 0; + wpahdr->req_ie_len = 0; + skb_put(pDevice->skb, sizeof(viawget_wpa_header)); + pDevice->skb->dev = pDevice->wpadev; + pDevice->skb->mac_header = pDevice->skb->data; + pDevice->skb->pkt_type = PACKET_HOST; + pDevice->skb->protocol = htons(ETH_P_802_2); + memset(pDevice->skb->cb, 0, sizeof(pDevice->skb->cb)); + netif_rx(pDevice->skb); + pDevice->skb = dev_alloc_skb((int)pDevice->rx_buf_sz); + }; + + return FALSE; + + } + } + } //---end of SOFT MIC----------------------------------------------------------------------- + + // ++++++++++ Reply Counter Check +++++++++++++ + + if ((pKey != NULL) && ((pKey->byCipherSuite == KEY_CTL_TKIP) || + (pKey->byCipherSuite == KEY_CTL_CCMP))) { + if (bIsWEP) { + WORD wLocalTSC15_0 = 0; + DWORD dwLocalTSC47_16 = 0; + ULONGLONG RSC = 0; + // endian issues + RSC = *((ULONGLONG *) &(pKey->KeyRSC)); + wLocalTSC15_0 = (WORD) RSC; + dwLocalTSC47_16 = (DWORD) (RSC>>16); + + RSC = dwRxTSC47_16; + RSC <<= 16; + RSC += wRxTSC15_0; + MEMvCopy(&(pKey->KeyRSC), &RSC, sizeof(QWORD)); + + if ( (pDevice->sMgmtObj.eCurrMode == WMAC_MODE_ESS_STA) && + (pDevice->sMgmtObj.eCurrState == WMAC_STATE_ASSOC)) { + // check RSC + if ( (wRxTSC15_0 < wLocalTSC15_0) && + (dwRxTSC47_16 <= dwLocalTSC47_16) && + !((dwRxTSC47_16 == 0) && (dwLocalTSC47_16 == 0xFFFFFFFF))) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"TSC is illegal~~!\n "); + if (pKey->byCipherSuite == KEY_CTL_TKIP) + //pDevice->s802_11Counter.TKIPReplays.QuadPart++; + pDevice->s802_11Counter.TKIPReplays++; + else + //pDevice->s802_11Counter.CCMPReplays.QuadPart++; + pDevice->s802_11Counter.CCMPReplays++; + + if (bDeFragRx) { + if (!device_alloc_frag_buf(pDevice, &pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx])) { + DEVICE_PRT(MSG_LEVEL_ERR,KERN_ERR "%s: can not alloc more frag bufs\n", + pDevice->dev->name); + } + } + return FALSE; + } + } + } + } // ----- End of Reply Counter Check -------------------------- + + + + if ((pKey != NULL) && (bIsWEP)) { +// pDevice->s802_11Counter.DecryptSuccessCount.QuadPart++; + } + + + s_vProcessRxMACHeader(pDevice, (PBYTE)(skb->data+4), FrameSize, bIsWEP, bExtIV, &cbHeaderOffset); + FrameSize -= cbHeaderOffset; + cbHeaderOffset += 4; // 4 is Rcv buffer header + + // Null data, framesize = 14 + if (FrameSize < 15) + return FALSE; + + if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) { + if (s_bAPModeRxData(pDevice, + skb, + FrameSize, + cbHeaderOffset, + iSANodeIndex, + iDANodeIndex + ) == FALSE) { + + if (bDeFragRx) { + if (!device_alloc_frag_buf(pDevice, &pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx])) { + DEVICE_PRT(MSG_LEVEL_ERR,KERN_ERR "%s: can not alloc more frag bufs\n", + pDevice->dev->name); + } + } + return FALSE; + } + +// if(pDevice->bRxMICFail == FALSE) { +// for (ii =0; ii < 100; ii++) +// printk(" %02x", *(skb->data + ii)); +// printk("\n"); +// } + + } + +#ifdef PRIVATE_OBJ + ref_skb_add_offset(skb->skb, cbHeaderOffset); + skb_put(skb->skb, FrameSize); + *(skb->protocol)=eth_type_trans(skb->skb, skb->dev); + +#else + skb->data += cbHeaderOffset; + skb->tail += cbHeaderOffset; + skb_put(skb, FrameSize); + skb->protocol=eth_type_trans(skb, skb->dev); +#endif + + + //drop frame not met IEEE 802.3 +/* + if (pDevice->flags & DEVICE_FLAGS_VAL_PKT_LEN) { +#ifdef PRIVATE_OBJ + if ((*(skb->protocol)==htons(ETH_P_802_3)) && + (*(skb->len)!=htons(skb->mac.ethernet->h_proto))) { +#else + if ((skb->protocol==htons(ETH_P_802_3)) && + (skb->len!=htons(skb->mac.ethernet->h_proto))) { +#endif + pStats->rx_length_errors++; + pStats->rx_dropped++; + if (bDeFragRx) { + if (!device_alloc_frag_buf(pDevice, &pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx])) { + DEVICE_PRT(MSG_LEVEL_ERR,KERN_ERR "%s: can not alloc more frag bufs\n", + pDevice->dev->name); + } + } + return FALSE; + } + } +*/ + +#ifdef PRIVATE_OBJ + *(skb->ip_summed)=CHECKSUM_NONE; + pStats->rx_bytes +=*(skb->len); + pStats->rx_packets++; + netif_rx(skb->skb); +#else + skb->ip_summed=CHECKSUM_NONE; + pStats->rx_bytes +=skb->len; + pStats->rx_packets++; + netif_rx(skb); +#endif + + if (bDeFragRx) { + if (!device_alloc_frag_buf(pDevice, &pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx])) { + DEVICE_PRT(MSG_LEVEL_ERR,KERN_ERR "%s: can not alloc more frag bufs\n", + pDevice->dev->name); + } + return FALSE; + } + return TRUE; +} + + +static BOOL s_bAPModeRxCtl ( + IN PSDevice pDevice, + IN PBYTE pbyFrame, + IN INT iSANodeIndex + ) +{ + PS802_11Header p802_11Header; + CMD_STATUS Status; + PSMgmtObject pMgmt = pDevice->pMgmt; + + + if (IS_CTL_PSPOLL(pbyFrame) || !IS_TYPE_CONTROL(pbyFrame)) { + + p802_11Header = (PS802_11Header) (pbyFrame); + if (!IS_TYPE_MGMT(pbyFrame)) { + + // Data & PS-Poll packet + // check frame class + if (iSANodeIndex > 0) { + // frame class 3 fliter & checking + if (pMgmt->sNodeDBTable[iSANodeIndex].eNodeState < NODE_AUTH) { + // send deauth notification + // reason = (6) class 2 received from nonauth sta + vMgrDeAuthenBeginSta(pDevice, + pMgmt, + (PBYTE)(p802_11Header->abyAddr2), + (WLAN_MGMT_REASON_CLASS2_NONAUTH), + &Status + ); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "dpc: send vMgrDeAuthenBeginSta 1\n"); + return TRUE; + }; + if (pMgmt->sNodeDBTable[iSANodeIndex].eNodeState < NODE_ASSOC) { + // send deassoc notification + // reason = (7) class 3 received from nonassoc sta + vMgrDisassocBeginSta(pDevice, + pMgmt, + (PBYTE)(p802_11Header->abyAddr2), + (WLAN_MGMT_REASON_CLASS3_NONASSOC), + &Status + ); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "dpc: send vMgrDisassocBeginSta 2\n"); + return TRUE; + }; + + if (pMgmt->sNodeDBTable[iSANodeIndex].bPSEnable) { + // delcare received ps-poll event + if (IS_CTL_PSPOLL(pbyFrame)) { + pMgmt->sNodeDBTable[iSANodeIndex].bRxPSPoll = TRUE; + bScheduleCommand((HANDLE)pDevice, WLAN_CMD_RX_PSPOLL, NULL); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "dpc: WLAN_CMD_RX_PSPOLL 1\n"); + } + else { + // check Data PS state + // if PW bit off, send out all PS bufferring packets. + if (!IS_FC_POWERMGT(pbyFrame)) { + pMgmt->sNodeDBTable[iSANodeIndex].bPSEnable = FALSE; + pMgmt->sNodeDBTable[iSANodeIndex].bRxPSPoll = TRUE; + bScheduleCommand((HANDLE)pDevice, WLAN_CMD_RX_PSPOLL, NULL); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "dpc: WLAN_CMD_RX_PSPOLL 2\n"); + } + } + } + else { + if (IS_FC_POWERMGT(pbyFrame)) { + pMgmt->sNodeDBTable[iSANodeIndex].bPSEnable = TRUE; + // Once if STA in PS state, enable multicast bufferring + pMgmt->sNodeDBTable[0].bPSEnable = TRUE; + } + else { + // clear all pending PS frame. + if (pMgmt->sNodeDBTable[iSANodeIndex].wEnQueueCnt > 0) { + pMgmt->sNodeDBTable[iSANodeIndex].bPSEnable = FALSE; + pMgmt->sNodeDBTable[iSANodeIndex].bRxPSPoll = TRUE; + bScheduleCommand((HANDLE)pDevice, WLAN_CMD_RX_PSPOLL, NULL); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "dpc: WLAN_CMD_RX_PSPOLL 3\n"); + + } + } + } + } + else { + vMgrDeAuthenBeginSta(pDevice, + pMgmt, + (PBYTE)(p802_11Header->abyAddr2), + (WLAN_MGMT_REASON_CLASS2_NONAUTH), + &Status + ); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "dpc: send vMgrDeAuthenBeginSta 3\n"); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "BSSID:%02x-%02x-%02x=%02x-%02x-%02x \n", + p802_11Header->abyAddr3[0], + p802_11Header->abyAddr3[1], + p802_11Header->abyAddr3[2], + p802_11Header->abyAddr3[3], + p802_11Header->abyAddr3[4], + p802_11Header->abyAddr3[5] + ); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "ADDR2:%02x-%02x-%02x=%02x-%02x-%02x \n", + p802_11Header->abyAddr2[0], + p802_11Header->abyAddr2[1], + p802_11Header->abyAddr2[2], + p802_11Header->abyAddr2[3], + p802_11Header->abyAddr2[4], + p802_11Header->abyAddr2[5] + ); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "ADDR1:%02x-%02x-%02x=%02x-%02x-%02x \n", + p802_11Header->abyAddr1[0], + p802_11Header->abyAddr1[1], + p802_11Header->abyAddr1[2], + p802_11Header->abyAddr1[3], + p802_11Header->abyAddr1[4], + p802_11Header->abyAddr1[5] + ); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "dpc: wFrameCtl= %x\n", p802_11Header->wFrameCtl ); + VNSvInPortB(pDevice->PortOffset + MAC_REG_RCR, &(pDevice->byRxMode)); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "dpc:pDevice->byRxMode = %x\n", pDevice->byRxMode ); + return TRUE; + } + } + } + return FALSE; + +} + +static BOOL s_bHandleRxEncryption ( + IN PSDevice pDevice, + IN PBYTE pbyFrame, + IN UINT FrameSize, + IN PBYTE pbyRsr, + OUT PBYTE pbyNewRsr, + OUT PSKeyItem *pKeyOut, + OUT PBOOL pbExtIV, + OUT PWORD pwRxTSC15_0, + OUT PDWORD pdwRxTSC47_16 + ) +{ + UINT PayloadLen = FrameSize; + PBYTE pbyIV; + BYTE byKeyIdx; + PSKeyItem pKey = NULL; + BYTE byDecMode = KEY_CTL_WEP; + PSMgmtObject pMgmt = pDevice->pMgmt; + + + *pwRxTSC15_0 = 0; + *pdwRxTSC47_16 = 0; + + pbyIV = pbyFrame + WLAN_HDR_ADDR3_LEN; + if ( WLAN_GET_FC_TODS(*(PWORD)pbyFrame) && + WLAN_GET_FC_FROMDS(*(PWORD)pbyFrame) ) { + pbyIV += 6; // 6 is 802.11 address4 + PayloadLen -= 6; + } + byKeyIdx = (*(pbyIV+3) & 0xc0); + byKeyIdx >>= 6; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"\nKeyIdx: %d\n", byKeyIdx); + + if ((pMgmt->eAuthenMode == WMAC_AUTH_WPA) || + (pMgmt->eAuthenMode == WMAC_AUTH_WPAPSK) || + (pMgmt->eAuthenMode == WMAC_AUTH_WPANONE) || + (pMgmt->eAuthenMode == WMAC_AUTH_WPA2) || + (pMgmt->eAuthenMode == WMAC_AUTH_WPA2PSK)) { + if (((*pbyRsr & (RSR_ADDRBROAD | RSR_ADDRMULTI)) == 0) && + (pDevice->pMgmt->byCSSPK != KEY_CTL_NONE)) { + // unicast pkt use pairwise key + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"unicast pkt\n"); + if (KeybGetKey(&(pDevice->sKey), pDevice->abyBSSID, 0xFFFFFFFF, &pKey) == TRUE) { + if (pDevice->pMgmt->byCSSPK == KEY_CTL_TKIP) + byDecMode = KEY_CTL_TKIP; + else if (pDevice->pMgmt->byCSSPK == KEY_CTL_CCMP) + byDecMode = KEY_CTL_CCMP; + } + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"unicast pkt: %d, %p\n", byDecMode, pKey); + } else { + // use group key + KeybGetKey(&(pDevice->sKey), pDevice->abyBSSID, byKeyIdx, &pKey); + if (pDevice->pMgmt->byCSSGK == KEY_CTL_TKIP) + byDecMode = KEY_CTL_TKIP; + else if (pDevice->pMgmt->byCSSGK == KEY_CTL_CCMP) + byDecMode = KEY_CTL_CCMP; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"group pkt: %d, %d, %p\n", byKeyIdx, byDecMode, pKey); + } + } + // our WEP only support Default Key + if (pKey == NULL) { + // use default group key + KeybGetKey(&(pDevice->sKey), pDevice->abyBroadcastAddr, byKeyIdx, &pKey); + if (pDevice->pMgmt->byCSSGK == KEY_CTL_TKIP) + byDecMode = KEY_CTL_TKIP; + else if (pDevice->pMgmt->byCSSGK == KEY_CTL_CCMP) + byDecMode = KEY_CTL_CCMP; + } + *pKeyOut = pKey; + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"AES:%d %d %d\n", pDevice->pMgmt->byCSSPK, pDevice->pMgmt->byCSSGK, byDecMode); + + if (pKey == NULL) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey == NULL\n"); + if (byDecMode == KEY_CTL_WEP) { +// pDevice->s802_11Counter.WEPUndecryptableCount.QuadPart++; + } else if (pDevice->bLinkPass == TRUE) { +// pDevice->s802_11Counter.DecryptFailureCount.QuadPart++; + } + return FALSE; + } + if (byDecMode != pKey->byCipherSuite) { + if (byDecMode == KEY_CTL_WEP) { +// pDevice->s802_11Counter.WEPUndecryptableCount.QuadPart++; + } else if (pDevice->bLinkPass == TRUE) { +// pDevice->s802_11Counter.DecryptFailureCount.QuadPart++; + } + *pKeyOut = NULL; + return FALSE; + } + if (byDecMode == KEY_CTL_WEP) { + // handle WEP + if ((pDevice->byLocalID <= REV_ID_VT3253_A1) || + (((PSKeyTable)(pKey->pvKeyTable))->bSoftWEP == TRUE)) { + // Software WEP + // 1. 3253A + // 2. WEP 256 + + PayloadLen -= (WLAN_HDR_ADDR3_LEN + 4 + 4); // 24 is 802.11 header,4 is IV, 4 is crc + MEMvCopy(pDevice->abyPRNG, pbyIV, 3); + MEMvCopy(pDevice->abyPRNG + 3, pKey->abyKey, pKey->uKeyLength); + rc4_init(&pDevice->SBox, pDevice->abyPRNG, pKey->uKeyLength + 3); + rc4_encrypt(&pDevice->SBox, pbyIV+4, pbyIV+4, PayloadLen); + + if (ETHbIsBufferCrc32Ok(pbyIV+4, PayloadLen)) { + *pbyNewRsr |= NEWRSR_DECRYPTOK; + } + } + } else if ((byDecMode == KEY_CTL_TKIP) || + (byDecMode == KEY_CTL_CCMP)) { + // TKIP/AES + + PayloadLen -= (WLAN_HDR_ADDR3_LEN + 8 + 4); // 24 is 802.11 header, 8 is IV&ExtIV, 4 is crc + *pdwRxTSC47_16 = cpu_to_le32(*(PDWORD)(pbyIV + 4)); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ExtIV: %lx\n",*pdwRxTSC47_16); + if (byDecMode == KEY_CTL_TKIP) { + *pwRxTSC15_0 = cpu_to_le16(MAKEWORD(*(pbyIV+2), *pbyIV)); + } else { + *pwRxTSC15_0 = cpu_to_le16(*(PWORD)pbyIV); + } + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"TSC0_15: %x\n", *pwRxTSC15_0); + + if ((byDecMode == KEY_CTL_TKIP) && + (pDevice->byLocalID <= REV_ID_VT3253_A1)) { + // Software TKIP + // 1. 3253 A + PS802_11Header pMACHeader = (PS802_11Header) (pbyFrame); + TKIPvMixKey(pKey->abyKey, pMACHeader->abyAddr2, *pwRxTSC15_0, *pdwRxTSC47_16, pDevice->abyPRNG); + rc4_init(&pDevice->SBox, pDevice->abyPRNG, TKIP_KEY_LEN); + rc4_encrypt(&pDevice->SBox, pbyIV+8, pbyIV+8, PayloadLen); + if (ETHbIsBufferCrc32Ok(pbyIV+8, PayloadLen)) { + *pbyNewRsr |= NEWRSR_DECRYPTOK; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ICV OK!\n"); + } else { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ICV FAIL!!!\n"); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"PayloadLen = %d\n", PayloadLen); + } + } + }// end of TKIP/AES + + if ((*(pbyIV+3) & 0x20) != 0) + *pbExtIV = TRUE; + return TRUE; +} + + +static BOOL s_bHostWepRxEncryption ( + IN PSDevice pDevice, + IN PBYTE pbyFrame, + IN UINT FrameSize, + IN PBYTE pbyRsr, + IN BOOL bOnFly, + IN PSKeyItem pKey, + OUT PBYTE pbyNewRsr, + OUT PBOOL pbExtIV, + OUT PWORD pwRxTSC15_0, + OUT PDWORD pdwRxTSC47_16 + ) +{ + UINT PayloadLen = FrameSize; + PBYTE pbyIV; + BYTE byKeyIdx; + BYTE byDecMode = KEY_CTL_WEP; + PS802_11Header pMACHeader; + + + + *pwRxTSC15_0 = 0; + *pdwRxTSC47_16 = 0; + + pbyIV = pbyFrame + WLAN_HDR_ADDR3_LEN; + if ( WLAN_GET_FC_TODS(*(PWORD)pbyFrame) && + WLAN_GET_FC_FROMDS(*(PWORD)pbyFrame) ) { + pbyIV += 6; // 6 is 802.11 address4 + PayloadLen -= 6; + } + byKeyIdx = (*(pbyIV+3) & 0xc0); + byKeyIdx >>= 6; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"\nKeyIdx: %d\n", byKeyIdx); + + + if (pDevice->pMgmt->byCSSGK == KEY_CTL_TKIP) + byDecMode = KEY_CTL_TKIP; + else if (pDevice->pMgmt->byCSSGK == KEY_CTL_CCMP) + byDecMode = KEY_CTL_CCMP; + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"AES:%d %d %d\n", pDevice->pMgmt->byCSSPK, pDevice->pMgmt->byCSSGK, byDecMode); + + if (byDecMode != pKey->byCipherSuite) { + if (byDecMode == KEY_CTL_WEP) { +// pDevice->s802_11Counter.WEPUndecryptableCount.QuadPart++; + } else if (pDevice->bLinkPass == TRUE) { +// pDevice->s802_11Counter.DecryptFailureCount.QuadPart++; + } + return FALSE; + } + + if (byDecMode == KEY_CTL_WEP) { + // handle WEP + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"byDecMode == KEY_CTL_WEP \n"); + if ((pDevice->byLocalID <= REV_ID_VT3253_A1) || + (((PSKeyTable)(pKey->pvKeyTable))->bSoftWEP == TRUE) || + (bOnFly == FALSE)) { + // Software WEP + // 1. 3253A + // 2. WEP 256 + // 3. NotOnFly + + PayloadLen -= (WLAN_HDR_ADDR3_LEN + 4 + 4); // 24 is 802.11 header,4 is IV, 4 is crc + MEMvCopy(pDevice->abyPRNG, pbyIV, 3); + MEMvCopy(pDevice->abyPRNG + 3, pKey->abyKey, pKey->uKeyLength); + rc4_init(&pDevice->SBox, pDevice->abyPRNG, pKey->uKeyLength + 3); + rc4_encrypt(&pDevice->SBox, pbyIV+4, pbyIV+4, PayloadLen); + + if (ETHbIsBufferCrc32Ok(pbyIV+4, PayloadLen)) { + *pbyNewRsr |= NEWRSR_DECRYPTOK; + } + } + } else if ((byDecMode == KEY_CTL_TKIP) || + (byDecMode == KEY_CTL_CCMP)) { + // TKIP/AES + + PayloadLen -= (WLAN_HDR_ADDR3_LEN + 8 + 4); // 24 is 802.11 header, 8 is IV&ExtIV, 4 is crc + *pdwRxTSC47_16 = cpu_to_le32(*(PDWORD)(pbyIV + 4)); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ExtIV: %lx\n",*pdwRxTSC47_16); + + if (byDecMode == KEY_CTL_TKIP) { + *pwRxTSC15_0 = cpu_to_le16(MAKEWORD(*(pbyIV+2), *pbyIV)); + } else { + *pwRxTSC15_0 = cpu_to_le16(*(PWORD)pbyIV); + } + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"TSC0_15: %x\n", *pwRxTSC15_0); + + if (byDecMode == KEY_CTL_TKIP) { + if ((pDevice->byLocalID <= REV_ID_VT3253_A1) || (bOnFly == FALSE)) { + // Software TKIP + // 1. 3253 A + // 2. NotOnFly + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"soft KEY_CTL_TKIP \n"); + pMACHeader = (PS802_11Header) (pbyFrame); + TKIPvMixKey(pKey->abyKey, pMACHeader->abyAddr2, *pwRxTSC15_0, *pdwRxTSC47_16, pDevice->abyPRNG); + rc4_init(&pDevice->SBox, pDevice->abyPRNG, TKIP_KEY_LEN); + rc4_encrypt(&pDevice->SBox, pbyIV+8, pbyIV+8, PayloadLen); + if (ETHbIsBufferCrc32Ok(pbyIV+8, PayloadLen)) { + *pbyNewRsr |= NEWRSR_DECRYPTOK; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ICV OK!\n"); + } else { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ICV FAIL!!!\n"); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"PayloadLen = %d\n", PayloadLen); + } + } + } + + if (byDecMode == KEY_CTL_CCMP) { + if (bOnFly == FALSE) { + // Software CCMP + // NotOnFly + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"soft KEY_CTL_CCMP\n"); + if (AESbGenCCMP(pKey->abyKey, pbyFrame, FrameSize)) { + *pbyNewRsr |= NEWRSR_DECRYPTOK; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"CCMP MIC compare OK!\n"); + } else { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"CCMP MIC fail!\n"); + } + } + } + + }// end of TKIP/AES + + if ((*(pbyIV+3) & 0x20) != 0) + *pbExtIV = TRUE; + return TRUE; +} + + + + +#ifdef PRIVATE_OBJ + +static BOOL s_bAPModeRxData ( + IN PSDevice pDevice, + IN ref_sk_buff* skb, + IN UINT FrameSize, + IN UINT cbHeaderOffset, + IN INT iSANodeIndex, + IN INT iDANodeIndex + ) + +#else + +static BOOL s_bAPModeRxData ( + IN PSDevice pDevice, + IN struct sk_buff* skb, + IN UINT FrameSize, + IN UINT cbHeaderOffset, + IN INT iSANodeIndex, + IN INT iDANodeIndex + ) +#endif +{ + PSMgmtObject pMgmt = pDevice->pMgmt; + BOOL bRelayAndForward = FALSE; + BOOL bRelayOnly = FALSE; + BYTE byMask[8] = {1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80}; + WORD wAID; +#ifdef PRIVATE_OBJ + struct sk_buff* tmp_skb; + ref_sk_buff s_ref_skb; + ref_sk_buff* skbcpy = &s_ref_skb; +#else + struct sk_buff* skbcpy = NULL; +#endif + + + + if (FrameSize > CB_MAX_BUF_SIZE) + return FALSE; + // check DA + if(IS_MULTICAST_ADDRESS((PBYTE)(skb->data+cbHeaderOffset))) { + if (pMgmt->sNodeDBTable[0].bPSEnable) { + +#ifdef PRIVATE_OBJ + tmp_skb = dev_alloc_skb((int)pDevice->rx_buf_sz); + skbcpy = &s_ref_skb; + ref_skb_remap(pDevice->dev, skbcpy, tmp_skb); +#else + skbcpy = dev_alloc_skb((int)pDevice->rx_buf_sz); +#endif + // if any node in PS mode, buffer packet until DTIM. + if (skbcpy == NULL) { + DEVICE_PRT(MSG_LEVEL_NOTICE, KERN_INFO "relay multicast no skb available \n"); + } + else { + skbcpy->dev = pDevice->dev; +#ifdef PRIVATE_OBJ + *(skbcpy->len) = FrameSize; + memcpy(skbcpy->data, skb->data+cbHeaderOffset, FrameSize); + skb_queue_tail(&(pMgmt->sNodeDBTable[0].sTxPSQueue), skbcpy->skb); +#else + skbcpy->len = FrameSize; + memcpy(skbcpy->data, skb->data+cbHeaderOffset, FrameSize); + skb_queue_tail(&(pMgmt->sNodeDBTable[0].sTxPSQueue), skbcpy); +#endif + pMgmt->sNodeDBTable[0].wEnQueueCnt++; + // set tx map + pMgmt->abyPSTxMap[0] |= byMask[0]; + } + } + else { + bRelayAndForward = TRUE; + } + } + else { + // check if relay + if (BSSDBbIsSTAInNodeDB(pMgmt, (PBYTE)(skb->data+cbHeaderOffset), &iDANodeIndex)) { + if (pMgmt->sNodeDBTable[iDANodeIndex].eNodeState >= NODE_ASSOC) { + if (pMgmt->sNodeDBTable[iDANodeIndex].bPSEnable) { + // queue this skb until next PS tx, and then release. + +#ifdef PRIVATE_OBJ + ref_skb_add_offset(skb->skb, cbHeaderOffset); + skb_put(skb->skb, FrameSize); + skb_queue_tail(&pMgmt->sNodeDBTable[iDANodeIndex].sTxPSQueue, skb->skb); +#else + skb->data += cbHeaderOffset; + skb->tail += cbHeaderOffset; + skb_put(skb, FrameSize); + skb_queue_tail(&pMgmt->sNodeDBTable[iDANodeIndex].sTxPSQueue, skb); +#endif + pMgmt->sNodeDBTable[iDANodeIndex].wEnQueueCnt++; + wAID = pMgmt->sNodeDBTable[iDANodeIndex].wAID; + pMgmt->abyPSTxMap[wAID >> 3] |= byMask[wAID & 7]; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "relay: index= %d, pMgmt->abyPSTxMap[%d]= %d\n", + iDANodeIndex, (wAID >> 3), pMgmt->abyPSTxMap[wAID >> 3]); + return TRUE; + } + else { + bRelayOnly = TRUE; + } + } + }; + } + + if (bRelayOnly || bRelayAndForward) { + // relay this packet right now + if (bRelayAndForward) + iDANodeIndex = 0; + + if ((pDevice->uAssocCount > 1) && (iDANodeIndex >= 0)) { + ROUTEbRelay(pDevice, (PBYTE)(skb->data + cbHeaderOffset), FrameSize, (UINT)iDANodeIndex); + } + + if (bRelayOnly) + return FALSE; + } + // none associate, don't forward + if (pDevice->uAssocCount == 0) + return FALSE; + + return TRUE; +} + diff --git a/drivers/staging/vt6655/dpc.h b/drivers/staging/vt6655/dpc.h new file mode 100644 index 000000000000..68447c44dc2f --- /dev/null +++ b/drivers/staging/vt6655/dpc.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * File: whdr.h + * + * Purpose: + * + * Author: Jerry Chen + * + * Date: Jun. 27, 2002 + * + */ + + +#ifndef __DPC_H__ +#define __DPC_H__ + +#if !defined(__TTYPE_H__) +#include "ttype.h" +#endif +#if !defined(__DEVICE_H__) +#include "device.h" +#endif +#if !defined(__WCMD_H__) +#include "wcmd.h" +#endif + + +/*--------------------- Export Definitions -------------------------*/ + +/*--------------------- Export Classes ----------------------------*/ + +/*--------------------- Export Variables --------------------------*/ + +/*--------------------- Export Functions --------------------------*/ + + +#ifdef __cplusplus +extern "C" { /* Assume C declarations for C++ */ +#endif /* __cplusplus */ + + +BOOL +device_receive_frame ( + IN PSDevice pDevice, + IN PSRxDesc pCurrRD + ); + + +#ifdef __cplusplus +} /* End of extern "C" { */ +#endif /* __cplusplus */ + + + +VOID MngWorkItem(PVOID Context); +#endif // __RXTX_H__ + + + diff --git a/drivers/staging/vt6655/hostap.c b/drivers/staging/vt6655/hostap.c new file mode 100644 index 000000000000..91f189ddeef4 --- /dev/null +++ b/drivers/staging/vt6655/hostap.c @@ -0,0 +1,914 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * File: hostap.c + * + * Purpose: handle hostap deamon ioctl input/out functions + * + * Author: Lyndon Chen + * + * Date: Oct. 20, 2003 + * + * Functions: + * + * Revision History: + * + */ + + +#if !defined(__HOSTAP_H__) +#include "hostap.h" +#endif +#if !defined(__IOCMD_H__) +#include "iocmd.h" +#endif +#if !defined(__MAC_H__) +#include "mac.h" +#endif +#if !defined(__CARD_H__) +#include "card.h" +#endif +#if !defined(__BASEBAND_H__) +#include "baseband.h" +#endif +#if !defined(__WPACTL_H__) +#include "wpactl.h" +#endif +#if !defined(__KEY_H__) +#include "key.h" +#endif +#if !defined(__MAC_H__) +#include "mac.h" +#endif + + +#define VIAWGET_HOSTAPD_MAX_BUF_SIZE 1024 +#define HOSTAP_CRYPT_FLAG_SET_TX_KEY BIT0 +#define HOSTAP_CRYPT_FLAG_PERMANENT BIT1 +#define HOSTAP_CRYPT_ERR_UNKNOWN_ALG 2 +#define HOSTAP_CRYPT_ERR_UNKNOWN_ADDR 3 +#define HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED 4 +#define HOSTAP_CRYPT_ERR_KEY_SET_FAILED 5 +#define HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED 6 +#define HOSTAP_CRYPT_ERR_CARD_CONF_FAILED 7 + + +/*--------------------- Static Definitions -------------------------*/ + +/*--------------------- Static Classes ----------------------------*/ + +/*--------------------- Static Variables --------------------------*/ +//static int msglevel =MSG_LEVEL_DEBUG; +static int msglevel =MSG_LEVEL_INFO; + +/*--------------------- Static Functions --------------------------*/ + + + + +/*--------------------- Export Variables --------------------------*/ + + +/* + * Description: + * register net_device (AP) for hostap deamon + * + * Parameters: + * In: + * pDevice - + * rtnl_locked - + * Out: + * + * Return Value: + * + */ + +static int hostap_enable_hostapd(PSDevice pDevice, int rtnl_locked) +{ + PSDevice apdev_priv; + struct net_device *dev = pDevice->dev; + int ret; + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%s: Enabling hostapd mode\n", dev->name); + +#ifdef PRIVATE_OBJ + pDevice->apdev = ref_init_apdev(dev); + + if (pDevice->apdev == NULL) + return -ENOMEM; + + if (rtnl_locked) + ret = register_netdevice(pDevice->apdev); + else + ret = register_netdev(pDevice->apdev); + if (ret) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%s: register_netdevice(AP) failed!\n", + dev->name); + return -1; + } + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%s: Registered netdevice %s for AP management\n", + dev->name, pDevice->apdev->name); + +#else + pDevice->apdev = (struct net_device *)kmalloc(sizeof(struct net_device), GFP_KERNEL); + if (pDevice->apdev == NULL) + return -ENOMEM; + memset(pDevice->apdev, 0, sizeof(struct net_device)); + + apdev_priv = netdev_priv(pDevice->apdev); + *apdev_priv = *pDevice; + memcpy(pDevice->apdev->dev_addr, dev->dev_addr, ETH_ALEN); + + const struct net_device_ops apdev_netdev_ops = { + .ndo_start_xmit = pDevice->tx_80211, + }; + pDevice->apdev->netdev_ops = &apdev_netdev_ops; + + pDevice->apdev->type = ARPHRD_IEEE80211; + + pDevice->apdev->base_addr = dev->base_addr; + pDevice->apdev->irq = dev->irq; + pDevice->apdev->mem_start = dev->mem_start; + pDevice->apdev->mem_end = dev->mem_end; + sprintf(pDevice->apdev->name, "%sap", dev->name); + if (rtnl_locked) + ret = register_netdevice(pDevice->apdev); + else + ret = register_netdev(pDevice->apdev); + if (ret) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%s: register_netdevice(AP) failed!\n", + dev->name); + return -1; + } + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%s: Registered netdevice %s for AP management\n", + dev->name, pDevice->apdev->name); + + KeyvInitTable(&pDevice->sKey, pDevice->PortOffset); +#endif + + return 0; +} + +/* + * Description: + * unregister net_device(AP) + * + * Parameters: + * In: + * pDevice - + * rtnl_locked - + * Out: + * + * Return Value: + * + */ + +static int hostap_disable_hostapd(PSDevice pDevice, int rtnl_locked) +{ + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%s: disabling hostapd mode\n", pDevice->dev->name); + + if (pDevice->apdev && pDevice->apdev->name && pDevice->apdev->name[0]) { + if (rtnl_locked) + unregister_netdevice(pDevice->apdev); + else + unregister_netdev(pDevice->apdev); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%s: Netdevice %s unregistered\n", + pDevice->dev->name, pDevice->apdev->name); + } + kfree(pDevice->apdev); + pDevice->apdev = NULL; + pDevice->bEnable8021x = FALSE; + pDevice->bEnableHostWEP = FALSE; + pDevice->bEncryptionEnable = FALSE; + +//4.2007-0118-03, by EinsnLiu +//execute some clear work +pDevice->pMgmt->byCSSPK=KEY_CTL_NONE; +pDevice->pMgmt->byCSSGK=KEY_CTL_NONE; +KeyvInitTable(&pDevice->sKey,pDevice->PortOffset); + + return 0; +} + + +/* + * Description: + * Set enable/disable hostapd mode + * + * Parameters: + * In: + * pDevice - + * rtnl_locked - + * Out: + * + * Return Value: + * + */ + +int hostap_set_hostapd(PSDevice pDevice, int val, int rtnl_locked) +{ + if (val < 0 || val > 1) + return -EINVAL; + + if (pDevice->bEnableHostapd == val) + return 0; + + pDevice->bEnableHostapd = val; + + if (val) + return hostap_enable_hostapd(pDevice, rtnl_locked); + else + return hostap_disable_hostapd(pDevice, rtnl_locked); +} + + +/* + * Description: + * remove station function supported for hostap deamon + * + * Parameters: + * In: + * pDevice - + * param - + * Out: + * + * Return Value: + * + */ +static int hostap_remove_sta(PSDevice pDevice, + struct viawget_hostapd_param *param) +{ + UINT uNodeIndex; + + + if (BSSDBbIsSTAInNodeDB(pDevice->pMgmt, param->sta_addr, &uNodeIndex)) { + BSSvRemoveOneNode(pDevice, uNodeIndex); + } + else { + return -ENOENT; + } + return 0; +} + +/* + * Description: + * add a station from hostap deamon + * + * Parameters: + * In: + * pDevice - + * param - + * Out: + * + * Return Value: + * + */ +static int hostap_add_sta(PSDevice pDevice, + struct viawget_hostapd_param *param) +{ + PSMgmtObject pMgmt = pDevice->pMgmt; + UINT uNodeIndex; + + + if (!BSSDBbIsSTAInNodeDB(pMgmt, param->sta_addr, &uNodeIndex)) { + BSSvCreateOneNode((PSDevice)pDevice, &uNodeIndex); + } + memcpy(pMgmt->sNodeDBTable[uNodeIndex].abyMACAddr, param->sta_addr, WLAN_ADDR_LEN); + pMgmt->sNodeDBTable[uNodeIndex].eNodeState = NODE_ASSOC; + pMgmt->sNodeDBTable[uNodeIndex].wCapInfo = param->u.add_sta.capability; +// TODO listenInterval +// pMgmt->sNodeDBTable[uNodeIndex].wListenInterval = 1; + pMgmt->sNodeDBTable[uNodeIndex].bPSEnable = FALSE; + pMgmt->sNodeDBTable[uNodeIndex].bySuppRate = param->u.add_sta.tx_supp_rates; + + // set max tx rate + pMgmt->sNodeDBTable[uNodeIndex].wTxDataRate = + pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate; + // set max basic rate + pMgmt->sNodeDBTable[uNodeIndex].wMaxBasicRate = RATE_2M; + // Todo: check sta preamble, if ap can't support, set status code + pMgmt->sNodeDBTable[uNodeIndex].bShortPreamble = + WLAN_GET_CAP_INFO_SHORTPREAMBLE(pMgmt->sNodeDBTable[uNodeIndex].wCapInfo); + + pMgmt->sNodeDBTable[uNodeIndex].wAID = (WORD)param->u.add_sta.aid; +#ifdef PRIVATE_OBJ + pMgmt->sNodeDBTable[uNodeIndex].ulLastRxJiffer = get_jiffies(); +#else + pMgmt->sNodeDBTable[uNodeIndex].ulLastRxJiffer = jiffies; +#endif + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Add STA AID= %d \n", pMgmt->sNodeDBTable[uNodeIndex].wAID); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "MAC=%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X \n", + param->sta_addr[0], + param->sta_addr[1], + param->sta_addr[2], + param->sta_addr[3], + param->sta_addr[4], + param->sta_addr[5] + ) ; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Max Support rate = %d \n", + pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate); + + return 0; +} + +/* + * Description: + * get station info + * + * Parameters: + * In: + * pDevice - + * param - + * Out: + * + * Return Value: + * + */ + +static int hostap_get_info_sta(PSDevice pDevice, + struct viawget_hostapd_param *param) +{ + PSMgmtObject pMgmt = pDevice->pMgmt; + UINT uNodeIndex; + + if (BSSDBbIsSTAInNodeDB(pMgmt, param->sta_addr, &uNodeIndex)) { +#ifdef PRIVATE_OBJ + param->u.get_info_sta.inactive_sec = + (get_jiffies() - pMgmt->sNodeDBTable[uNodeIndex].ulLastRxJiffer) / HZ; +#else + param->u.get_info_sta.inactive_sec = + (jiffies - pMgmt->sNodeDBTable[uNodeIndex].ulLastRxJiffer) / HZ; +#endif + //param->u.get_info_sta.txexc = pMgmt->sNodeDBTable[uNodeIndex].uTxAttempts; + } + else { + return -ENOENT; + } + + return 0; +} + +/* + * Description: + * reset txexec + * + * Parameters: + * In: + * pDevice - + * param - + * Out: + * TURE, FALSE + * + * Return Value: + * + */ +/* +static int hostap_reset_txexc_sta(PSDevice pDevice, + struct viawget_hostapd_param *param) +{ + PSMgmtObject pMgmt = pDevice->pMgmt; + UINT uNodeIndex; + + if (BSSDBbIsSTAInNodeDB(pMgmt, param->sta_addr, &uNodeIndex)) { + pMgmt->sNodeDBTable[uNodeIndex].uTxAttempts = 0; + } + else { + return -ENOENT; + } + + return 0; +} +*/ + +/* + * Description: + * set station flag + * + * Parameters: + * In: + * pDevice - + * param - + * Out: + * + * Return Value: + * + */ +static int hostap_set_flags_sta(PSDevice pDevice, + struct viawget_hostapd_param *param) +{ + PSMgmtObject pMgmt = pDevice->pMgmt; + UINT uNodeIndex; + + if (BSSDBbIsSTAInNodeDB(pMgmt, param->sta_addr, &uNodeIndex)) { + pMgmt->sNodeDBTable[uNodeIndex].dwFlags |= param->u.set_flags_sta.flags_or; + pMgmt->sNodeDBTable[uNodeIndex].dwFlags &= param->u.set_flags_sta.flags_and; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " dwFlags = %x \n", + (UINT)pMgmt->sNodeDBTable[uNodeIndex].dwFlags); + } + else { + return -ENOENT; + } + + return 0; +} + + + +/* + * Description: + * set generic element (wpa ie) + * + * Parameters: + * In: + * pDevice - + * param - + * Out: + * + * Return Value: + * + */ +static int hostap_set_generic_element(PSDevice pDevice, + struct viawget_hostapd_param *param) +{ + PSMgmtObject pMgmt = pDevice->pMgmt; + + + + memcpy( pMgmt->abyWPAIE, + param->u.generic_elem.data, + param->u.generic_elem.len + ); + + pMgmt->wWPAIELen = param->u.generic_elem.len; + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pMgmt->wWPAIELen = %d\n", pMgmt->wWPAIELen); + + // disable wpa + if (pMgmt->wWPAIELen == 0) { + pMgmt->eAuthenMode = WMAC_AUTH_OPEN; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " No WPAIE, Disable WPA \n"); + } else { + // enable wpa + if ((pMgmt->abyWPAIE[0] == WLAN_EID_RSN_WPA) || + (pMgmt->abyWPAIE[0] == WLAN_EID_RSN)) { + pMgmt->eAuthenMode = WMAC_AUTH_WPANONE; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Set WPAIE enable WPA\n"); + } else + return -EINVAL; + } + + return 0; +} + +/* + * Description: + * flush station nodes table. + * + * Parameters: + * In: + * pDevice - + * Out: + * + * Return Value: + * + */ + +static void hostap_flush_sta(PSDevice pDevice) +{ + // reserved node index =0 for multicast node. + BSSvClearNodeDBTable(pDevice, 1); + pDevice->uAssocCount = 0; + + return; +} + +/* + * Description: + * set each stations encryption key + * + * Parameters: + * In: + * pDevice - + * param - + * Out: + * + * Return Value: + * + */ +static int hostap_set_encryption(PSDevice pDevice, + struct viawget_hostapd_param *param, + int param_len) +{ + PSMgmtObject pMgmt = pDevice->pMgmt; + DWORD dwKeyIndex = 0; + BYTE abyKey[MAX_KEY_LEN]; + BYTE abySeq[MAX_KEY_LEN]; + NDIS_802_11_KEY_RSC KeyRSC; + BYTE byKeyDecMode = KEY_CTL_WEP; + int ret = 0; + int iNodeIndex = -1; + int ii; + BOOL bKeyTableFull = FALSE; + WORD wKeyCtl = 0; + + + param->u.crypt.err = 0; +/* + if (param_len != + (int) ((char *) param->u.crypt.key - (char *) param) + + param->u.crypt.key_len) + return -EINVAL; +*/ + + if (param->u.crypt.alg > WPA_ALG_CCMP) + return -EINVAL; + + + if ((param->u.crypt.idx > 3) || (param->u.crypt.key_len > MAX_KEY_LEN)) { + param->u.crypt.err = HOSTAP_CRYPT_ERR_KEY_SET_FAILED; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " HOSTAP_CRYPT_ERR_KEY_SET_FAILED\n"); + return -EINVAL; + } + + if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && + param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && + param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) { + if (param->u.crypt.idx >= MAX_GROUP_KEY) + return -EINVAL; + iNodeIndex = 0; + + } else { + if (BSSDBbIsSTAInNodeDB(pMgmt, param->sta_addr, &iNodeIndex) == FALSE) { + param->u.crypt.err = HOSTAP_CRYPT_ERR_UNKNOWN_ADDR; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " HOSTAP_CRYPT_ERR_UNKNOWN_ADDR\n"); + return -EINVAL; + } + } + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " hostap_set_encryption: sta_index %d \n", iNodeIndex); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " hostap_set_encryption: alg %d \n", param->u.crypt.alg); + + if (param->u.crypt.alg == WPA_ALG_NONE) { + + if (pMgmt->sNodeDBTable[iNodeIndex].bOnFly == TRUE) { + if (KeybRemoveKey(&(pDevice->sKey), + param->sta_addr, + pMgmt->sNodeDBTable[iNodeIndex].dwKeyIndex, + pDevice->PortOffset) == FALSE) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "KeybRemoveKey fail \n"); + } + pMgmt->sNodeDBTable[iNodeIndex].bOnFly = FALSE; + } + pMgmt->sNodeDBTable[iNodeIndex].byKeyIndex = 0; + pMgmt->sNodeDBTable[iNodeIndex].dwKeyIndex = 0; + pMgmt->sNodeDBTable[iNodeIndex].uWepKeyLength = 0; + pMgmt->sNodeDBTable[iNodeIndex].KeyRSC = 0; + pMgmt->sNodeDBTable[iNodeIndex].dwTSC47_16 = 0; + pMgmt->sNodeDBTable[iNodeIndex].wTSC15_0 = 0; + pMgmt->sNodeDBTable[iNodeIndex].byCipherSuite = 0; + memset(&pMgmt->sNodeDBTable[iNodeIndex].abyWepKey[0], + 0, + MAX_KEY_LEN + ); + + return ret; + } + + memcpy(abyKey, param->u.crypt.key, param->u.crypt.key_len); + // copy to node key tbl + pMgmt->sNodeDBTable[iNodeIndex].byKeyIndex = param->u.crypt.idx; + pMgmt->sNodeDBTable[iNodeIndex].uWepKeyLength = param->u.crypt.key_len; + memcpy(&pMgmt->sNodeDBTable[iNodeIndex].abyWepKey[0], + param->u.crypt.key, + param->u.crypt.key_len + ); + + dwKeyIndex = (DWORD)(param->u.crypt.idx); + if (param->u.crypt.flags & HOSTAP_CRYPT_FLAG_SET_TX_KEY) { + pDevice->byKeyIndex = (BYTE)dwKeyIndex; + pDevice->bTransmitKey = TRUE; + dwKeyIndex |= (1 << 31); + } + + if (param->u.crypt.alg == WPA_ALG_WEP) { + + if ((pDevice->bEnable8021x == FALSE) || (iNodeIndex == 0)) { + KeybSetDefaultKey(&(pDevice->sKey), + dwKeyIndex & ~(BIT30 | USE_KEYRSC), + param->u.crypt.key_len, + NULL, + abyKey, + KEY_CTL_WEP, + pDevice->PortOffset, + pDevice->byLocalID); + + } else { + // 8021x enable, individual key + dwKeyIndex |= (1 << 30); // set pairwise key + if (KeybSetKey(&(pDevice->sKey), + ¶m->sta_addr[0], + dwKeyIndex & ~(USE_KEYRSC), + param->u.crypt.key_len, + (PQWORD) &(KeyRSC), + (PBYTE)abyKey, + KEY_CTL_WEP, + pDevice->PortOffset, + pDevice->byLocalID) == TRUE) { + + pMgmt->sNodeDBTable[iNodeIndex].bOnFly = TRUE; + + } else { + // Key Table Full + pMgmt->sNodeDBTable[iNodeIndex].bOnFly = FALSE; + bKeyTableFull = TRUE; + } + } + pDevice->eEncryptionStatus = Ndis802_11Encryption1Enabled; + pDevice->bEncryptionEnable = TRUE; + pMgmt->byCSSPK = KEY_CTL_WEP; + pMgmt->byCSSGK = KEY_CTL_WEP; + pMgmt->sNodeDBTable[iNodeIndex].byCipherSuite = KEY_CTL_WEP; + pMgmt->sNodeDBTable[iNodeIndex].dwKeyIndex = dwKeyIndex; + return ret; + } + + if (param->u.crypt.seq) { + memcpy(&abySeq, param->u.crypt.seq, 8); + for (ii = 0 ; ii < 8 ; ii++) { + KeyRSC |= (abySeq[ii] << (ii * 8)); + } + dwKeyIndex |= 1 << 29; + pMgmt->sNodeDBTable[iNodeIndex].KeyRSC = KeyRSC; + } + + if (param->u.crypt.alg == WPA_ALG_TKIP) { + if (param->u.crypt.key_len != MAX_KEY_LEN) + return -EINVAL; + pDevice->eEncryptionStatus = Ndis802_11Encryption2Enabled; + byKeyDecMode = KEY_CTL_TKIP; + pMgmt->byCSSPK = KEY_CTL_TKIP; + pMgmt->byCSSGK = KEY_CTL_TKIP; + } + + if (param->u.crypt.alg == WPA_ALG_CCMP) { + if ((param->u.crypt.key_len != AES_KEY_LEN) || + (pDevice->byLocalID <= REV_ID_VT3253_A1)) + return -EINVAL; + pDevice->eEncryptionStatus = Ndis802_11Encryption3Enabled; + byKeyDecMode = KEY_CTL_CCMP; + pMgmt->byCSSPK = KEY_CTL_CCMP; + pMgmt->byCSSGK = KEY_CTL_CCMP; + } + + + if (iNodeIndex == 0) { + KeybSetDefaultKey(&(pDevice->sKey), + dwKeyIndex, + param->u.crypt.key_len, + (PQWORD) &(KeyRSC), + abyKey, + byKeyDecMode, + pDevice->PortOffset, + pDevice->byLocalID); + pMgmt->sNodeDBTable[iNodeIndex].bOnFly = TRUE; + + } else { + dwKeyIndex |= (1 << 30); // set pairwise key + if (KeybSetKey(&(pDevice->sKey), + ¶m->sta_addr[0], + dwKeyIndex, + param->u.crypt.key_len, + (PQWORD) &(KeyRSC), + (PBYTE)abyKey, + byKeyDecMode, + pDevice->PortOffset, + pDevice->byLocalID) == TRUE) { + + pMgmt->sNodeDBTable[iNodeIndex].bOnFly = TRUE; + + } else { + // Key Table Full + pMgmt->sNodeDBTable[iNodeIndex].bOnFly = FALSE; + bKeyTableFull = TRUE; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " Key Table Full\n"); + } + + } + + if (bKeyTableFull == TRUE) { + wKeyCtl &= 0x7F00; // clear all key control filed + wKeyCtl |= (byKeyDecMode << 4); + wKeyCtl |= (byKeyDecMode); + wKeyCtl |= 0x0044; // use group key for all address + wKeyCtl |= 0x4000; // disable KeyTable[MAX_KEY_TABLE-1] on-fly to genernate rx int + MACvSetDefaultKeyCtl(pDevice->PortOffset, wKeyCtl, MAX_KEY_TABLE-1, pDevice->byLocalID); + } + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " Set key sta_index= %d \n", iNodeIndex); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " tx_index=%d len=%d \n", param->u.crypt.idx, + param->u.crypt.key_len ); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " key=%x-%x-%x-%x-%x-xxxxx \n", + pMgmt->sNodeDBTable[iNodeIndex].abyWepKey[0], + pMgmt->sNodeDBTable[iNodeIndex].abyWepKey[1], + pMgmt->sNodeDBTable[iNodeIndex].abyWepKey[2], + pMgmt->sNodeDBTable[iNodeIndex].abyWepKey[3], + pMgmt->sNodeDBTable[iNodeIndex].abyWepKey[4] + ); + + // set wep key + pDevice->bEncryptionEnable = TRUE; + pMgmt->sNodeDBTable[iNodeIndex].byCipherSuite = byKeyDecMode; + pMgmt->sNodeDBTable[iNodeIndex].dwKeyIndex = dwKeyIndex; + pMgmt->sNodeDBTable[iNodeIndex].dwTSC47_16 = 0; + pMgmt->sNodeDBTable[iNodeIndex].wTSC15_0 = 0; + + return ret; +} + + + +/* + * Description: + * get each stations encryption key + * + * Parameters: + * In: + * pDevice - + * param - + * Out: + * + * Return Value: + * + */ +static int hostap_get_encryption(PSDevice pDevice, + struct viawget_hostapd_param *param, + int param_len) +{ + PSMgmtObject pMgmt = pDevice->pMgmt; + int ret = 0; + int ii; + int iNodeIndex =0; + + + param->u.crypt.err = 0; + + if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && + param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && + param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) { + iNodeIndex = 0; + } else { + if (BSSDBbIsSTAInNodeDB(pMgmt, param->sta_addr, &iNodeIndex) == FALSE) { + param->u.crypt.err = HOSTAP_CRYPT_ERR_UNKNOWN_ADDR; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "hostap_get_encryption: HOSTAP_CRYPT_ERR_UNKNOWN_ADDR\n"); + return -EINVAL; + } + } + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "hostap_get_encryption: %d\n", iNodeIndex); + memset(param->u.crypt.seq, 0, 8); + for (ii = 0 ; ii < 8 ; ii++) { + param->u.crypt.seq[ii] = (BYTE)pMgmt->sNodeDBTable[iNodeIndex].KeyRSC >> (ii * 8); + } + + return ret; +} + + +/* + * Description: + * hostap_ioctl main function supported for hostap deamon. + * + * Parameters: + * In: + * pDevice - + * iw_point - + * Out: + * + * Return Value: + * + */ + +int hostap_ioctl(PSDevice pDevice, struct iw_point *p) +{ + struct viawget_hostapd_param *param; + int ret = 0; + int ap_ioctl = 0; + + if (p->length < sizeof(struct viawget_hostapd_param) || + p->length > VIAWGET_HOSTAPD_MAX_BUF_SIZE || !p->pointer) + return -EINVAL; + + param = (struct viawget_hostapd_param *) kmalloc((int)p->length, (int)GFP_KERNEL); + if (param == NULL) + return -ENOMEM; + + if (copy_from_user(param, p->pointer, p->length)) { + ret = -EFAULT; + goto out; + } + + switch (param->cmd) { + case VIAWGET_HOSTAPD_SET_ENCRYPTION: + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_SET_ENCRYPTION \n"); + spin_lock_irq(&pDevice->lock); + ret = hostap_set_encryption(pDevice, param, p->length); + spin_unlock_irq(&pDevice->lock); + break; + case VIAWGET_HOSTAPD_GET_ENCRYPTION: + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_GET_ENCRYPTION \n"); + spin_lock_irq(&pDevice->lock); + ret = hostap_get_encryption(pDevice, param, p->length); + spin_unlock_irq(&pDevice->lock); + break; + case VIAWGET_HOSTAPD_SET_ASSOC_AP_ADDR: + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_SET_ASSOC_AP_ADDR \n"); + return -EOPNOTSUPP; + break; + case VIAWGET_HOSTAPD_FLUSH: + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_FLUSH \n"); + spin_lock_irq(&pDevice->lock); + hostap_flush_sta(pDevice); + spin_unlock_irq(&pDevice->lock); + break; + case VIAWGET_HOSTAPD_ADD_STA: + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_ADD_STA \n"); + spin_lock_irq(&pDevice->lock); + ret = hostap_add_sta(pDevice, param); + spin_unlock_irq(&pDevice->lock); + break; + case VIAWGET_HOSTAPD_REMOVE_STA: + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_REMOVE_STA \n"); + spin_lock_irq(&pDevice->lock); + ret = hostap_remove_sta(pDevice, param); + spin_unlock_irq(&pDevice->lock); + break; + case VIAWGET_HOSTAPD_GET_INFO_STA: + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_GET_INFO_STA \n"); + ret = hostap_get_info_sta(pDevice, param); + ap_ioctl = 1; + break; +/* + case VIAWGET_HOSTAPD_RESET_TXEXC_STA: + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_RESET_TXEXC_STA \n"); + ret = hostap_reset_txexc_sta(pDevice, param); + break; +*/ + case VIAWGET_HOSTAPD_SET_FLAGS_STA: + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_SET_FLAGS_STA \n"); + ret = hostap_set_flags_sta(pDevice, param); + break; + + case VIAWGET_HOSTAPD_MLME: + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_MLME \n"); + return -EOPNOTSUPP; + + case VIAWGET_HOSTAPD_SET_GENERIC_ELEMENT: + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_SET_GENERIC_ELEMENT \n"); + ret = hostap_set_generic_element(pDevice, param); + break; + + case VIAWGET_HOSTAPD_SCAN_REQ: + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_SCAN_REQ \n"); + return -EOPNOTSUPP; + + case VIAWGET_HOSTAPD_STA_CLEAR_STATS: + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_STA_CLEAR_STATS \n"); + return -EOPNOTSUPP; + + default: + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "hostap_ioctl: unknown cmd=%d\n", + (int)param->cmd); + return -EOPNOTSUPP; + break; + } + + + if ((ret == 0) && ap_ioctl) { + if (copy_to_user(p->pointer, param, p->length)) { + ret = -EFAULT; + goto out; + } + } + + out: + if (param != NULL) + kfree(param); + + return ret; +} + diff --git a/drivers/staging/vt6655/hostap.h b/drivers/staging/vt6655/hostap.h new file mode 100644 index 000000000000..1fcb2f0788b3 --- /dev/null +++ b/drivers/staging/vt6655/hostap.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * File: hostap.h + * + * Purpose: + * + * Author: Lyndon Chen + * + * Date: May 21, 2003 + * + */ + + +#ifndef __HOSTAP_H__ +#define __HOSTAP_H__ + +#if !defined(__DEVICE_H__) +#include "device.h" +#endif + + +/*--------------------- Export Definitions -------------------------*/ + +#if WIRELESS_EXT < 9 +struct iw_point { + caddr_t pointer; + __u16 length; + __u16 flags; +}; +#endif /* WIRELESS_EXT < 9 */ + +#define WLAN_RATE_1M BIT0 +#define WLAN_RATE_2M BIT1 +#define WLAN_RATE_5M5 BIT2 +#define WLAN_RATE_11M BIT3 +#define WLAN_RATE_6M BIT4 +#define WLAN_RATE_9M BIT5 +#define WLAN_RATE_12M BIT6 +#define WLAN_RATE_18M BIT7 +#define WLAN_RATE_24M BIT8 +#define WLAN_RATE_36M BIT9 +#define WLAN_RATE_48M BIT10 +#define WLAN_RATE_54M BIT11 + + +/*--------------------- Export Classes ----------------------------*/ + +/*--------------------- Export Variables --------------------------*/ + +/*--------------------- Export Functions --------------------------*/ + + +#ifdef __cplusplus +extern "C" { /* Assume C declarations for C++ */ +#endif /* __cplusplus */ + +#ifndef ETH_P_PAE +#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */ +#endif /* ETH_P_PAE */ + +#ifndef ARPHRD_IEEE80211 +#define ARPHRD_IEEE80211 801 +#endif + +int hostap_set_hostapd(PSDevice pDevice, int val, int rtnl_locked); +int hostap_ioctl(PSDevice pDevice, struct iw_point *p); + +#ifdef __cplusplus +} /* End of extern "C" { */ +#endif /* __cplusplus */ + + + + +#endif // __HOSTAP_H__ + + + diff --git a/drivers/staging/vt6655/iocmd.h b/drivers/staging/vt6655/iocmd.h new file mode 100644 index 000000000000..ada9ee999767 --- /dev/null +++ b/drivers/staging/vt6655/iocmd.h @@ -0,0 +1,481 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * File: iocmd.h + * + * Purpose: Handles the viawget ioctl private interface functions + * + * Author: Lyndon Chen + * + * Date: May 8, 2002 + * + */ + +#ifndef __IOCMD_H__ +#define __IOCMD_H__ + +#if !defined(__TTYPE_H__) +#include "ttype.h" +#endif + + +/*--------------------- Export Definitions -------------------------*/ + +#if !defined(DEF) +#define DEF +#endif + +//typedef int BOOL; +//typedef uint32_t u32; +//typedef uint16_t u16; +//typedef uint8_t u8; + + +// ioctl Command code +#define MAGIC_CODE 0x3142 +#define IOCTL_CMD_TEST (SIOCDEVPRIVATE + 0) +#define IOCTL_CMD_SET (SIOCDEVPRIVATE + 1) +#define IOCTL_CMD_HOSTAPD (SIOCDEVPRIVATE + 2) +#define IOCTL_CMD_WPA (SIOCDEVPRIVATE + 3) + + +typedef enum tagWMAC_CMD { + + WLAN_CMD_BSS_SCAN, + WLAN_CMD_BSS_JOIN, + WLAN_CMD_DISASSOC, + WLAN_CMD_SET_WEP, + WLAN_CMD_GET_LINK, + WLAN_CMD_GET_LISTLEN, + WLAN_CMD_GET_LIST, + WLAN_CMD_GET_MIB, + WLAN_CMD_GET_STAT, + WLAN_CMD_STOP_MAC, + WLAN_CMD_START_MAC, + WLAN_CMD_AP_START, + WLAN_CMD_SET_HOSTAPD, + WLAN_CMD_SET_HOSTAPD_STA, + WLAN_CMD_SET_802_1X, + WLAN_CMD_SET_HOST_WEP, + WLAN_CMD_SET_WPA, + WLAN_CMD_GET_NODE_CNT, + WLAN_CMD_ZONETYPE_SET, + WLAN_CMD_GET_NODE_LIST + +} WMAC_CMD, DEF* PWMAC_CMD; + + typedef enum tagWZONETYPE { + ZoneType_USA=0, + ZoneType_Japan=1, + ZoneType_Europe=2 +}WZONETYPE; + +#define ADHOC 0 +#define INFRA 1 +#define BOTH 2 +#define AP 3 + +#define ADHOC_STARTED 1 +#define ADHOC_JOINTED 2 + + +#define PHY80211a 0 +#define PHY80211b 1 +#define PHY80211g 2 + +#define SSID_ID 0 +#define SSID_MAXLEN 32 +#define BSSID_LEN 6 +#define WEP_NKEYS 4 +#define WEP_KEYMAXLEN 29 +#define WEP_40BIT_LEN 5 +#define WEP_104BIT_LEN 13 +#define WEP_232BIT_LEN 16 + + +// Ioctl interface structure +// Command structure +// +#pragma pack(1) +typedef struct tagSCmdRequest { + U8 name[16]; + void *data; + U16 wResult; + U16 wCmdCode; +} SCmdRequest, *PSCmdRequest; + + +// +// Scan +// + +typedef struct tagSCmdScan { + + U8 ssid[SSID_MAXLEN + 2]; + +} SCmdScan, *PSCmdScan; + + +// +// BSS Join +// + +typedef struct tagSCmdBSSJoin { + + U16 wBSSType; + U16 wBBPType; + U8 ssid[SSID_MAXLEN + 2]; + U32 uChannel; + BOOL bPSEnable; + BOOL bShareKeyAuth; + +} SCmdBSSJoin, *PSCmdBSSJoin; + +typedef struct tagSCmdZoneTypeSet { + + BOOL bWrite; + WZONETYPE ZoneType; + +} SCmdZoneTypeSet, *PSCmdZoneTypeSet; + +#ifdef WPA_SM_Transtatus +typedef struct tagSWPAResult { + char ifname[100]; + U8 proto; + U8 key_mgmt; + U8 eap_type; + BOOL authenticated; +} SWPAResult, *PSWPAResult; +#endif + + +typedef struct tagSCmdStartAP { + + U16 wBSSType; + U16 wBBPType; + U8 ssid[SSID_MAXLEN + 2]; + U32 uChannel; + U32 uBeaconInt; + BOOL bShareKeyAuth; + U8 byBasicRate; + +} SCmdStartAP, *PSCmdStartAP; + + +typedef struct tagSCmdSetWEP { + + BOOL bEnableWep; + U8 byKeyIndex; + U8 abyWepKey[WEP_NKEYS][WEP_KEYMAXLEN]; + BOOL bWepKeyAvailable[WEP_NKEYS]; + U32 auWepKeyLength[WEP_NKEYS]; + +} SCmdSetWEP, *PSCmdSetWEP; + + + +typedef struct tagSBSSIDItem { + + U32 uChannel; + U8 abyBSSID[BSSID_LEN]; + U8 abySSID[SSID_MAXLEN + 1]; + //2006-1116-01, by NomadZhao + //U16 wBeaconInterval; + //U16 wCapInfo; + //U8 byNetType; + U8 byNetType; + U16 wBeaconInterval; + U16 wCapInfo; // for address of byNetType at align 4 + + BOOL bWEPOn; + U32 uRSSI; + +} SBSSIDItem; + + +typedef struct tagSBSSIDList { + + U32 uItem; + SBSSIDItem sBSSIDList[0]; +} SBSSIDList, *PSBSSIDList; + + +typedef struct tagSCmdLinkStatus { + + BOOL bLink; + U16 wBSSType; + U8 byState; + U8 abyBSSID[BSSID_LEN]; + U8 abySSID[SSID_MAXLEN + 2]; + U32 uChannel; + U32 uLinkRate; + +} SCmdLinkStatus, *PSCmdLinkStatus; + +// +// 802.11 counter +// +typedef struct tagSDot11MIBCount { + U32 TransmittedFragmentCount; + U32 MulticastTransmittedFrameCount; + U32 FailedCount; + U32 RetryCount; + U32 MultipleRetryCount; + U32 RTSSuccessCount; + U32 RTSFailureCount; + U32 ACKFailureCount; + U32 FrameDuplicateCount; + U32 ReceivedFragmentCount; + U32 MulticastReceivedFrameCount; + U32 FCSErrorCount; +} SDot11MIBCount, DEF* PSDot11MIBCount; + + + +// +// statistic counter +// +typedef struct tagSStatMIBCount { + // + // ISR status count + // + U32 dwIsrTx0OK; + U32 dwIsrTx1OK; + U32 dwIsrBeaconTxOK; + U32 dwIsrRxOK; + U32 dwIsrTBTTInt; + U32 dwIsrSTIMERInt; + U32 dwIsrUnrecoverableError; + U32 dwIsrSoftInterrupt; + U32 dwIsrRxNoBuf; + ///////////////////////////////////// + + U32 dwIsrUnknown; // unknown interrupt count + + // RSR status count + // + U32 dwRsrFrmAlgnErr; + U32 dwRsrErr; + U32 dwRsrCRCErr; + U32 dwRsrCRCOk; + U32 dwRsrBSSIDOk; + U32 dwRsrADDROk; + U32 dwRsrICVOk; + U32 dwNewRsrShortPreamble; + U32 dwRsrLong; + U32 dwRsrRunt; + + U32 dwRsrRxControl; + U32 dwRsrRxData; + U32 dwRsrRxManage; + + U32 dwRsrRxPacket; + U32 dwRsrRxOctet; + U32 dwRsrBroadcast; + U32 dwRsrMulticast; + U32 dwRsrDirected; + // 64-bit OID + U32 ullRsrOK; + + // for some optional OIDs (64 bits) and DMI support + U32 ullRxBroadcastBytes; + U32 ullRxMulticastBytes; + U32 ullRxDirectedBytes; + U32 ullRxBroadcastFrames; + U32 ullRxMulticastFrames; + U32 ullRxDirectedFrames; + + U32 dwRsrRxFragment; + U32 dwRsrRxFrmLen64; + U32 dwRsrRxFrmLen65_127; + U32 dwRsrRxFrmLen128_255; + U32 dwRsrRxFrmLen256_511; + U32 dwRsrRxFrmLen512_1023; + U32 dwRsrRxFrmLen1024_1518; + + // TSR0,1 status count + // + U32 dwTsrTotalRetry[2]; // total collision retry count + U32 dwTsrOnceRetry[2]; // this packet only occur one collision + U32 dwTsrMoreThanOnceRetry[2]; // this packet occur more than one collision + U32 dwTsrRetry[2]; // this packet has ever occur collision, + // that is (dwTsrOnceCollision0 + dwTsrMoreThanOnceCollision0) + U32 dwTsrACKData[2]; + U32 dwTsrErr[2]; + U32 dwAllTsrOK[2]; + U32 dwTsrRetryTimeout[2]; + U32 dwTsrTransmitTimeout[2]; + + U32 dwTsrTxPacket[2]; + U32 dwTsrTxOctet[2]; + U32 dwTsrBroadcast[2]; + U32 dwTsrMulticast[2]; + U32 dwTsrDirected[2]; + + // RD/TD count + U32 dwCntRxFrmLength; + U32 dwCntTxBufLength; + + U8 abyCntRxPattern[16]; + U8 abyCntTxPattern[16]; + + // Software check.... + U32 dwCntRxDataErr; // rx buffer data software compare CRC err count + U32 dwCntDecryptErr; // rx buffer data software compare CRC err count + U32 dwCntRxICVErr; // rx buffer data software compare CRC err count + U32 idxRxErrorDesc; // index for rx data error RD + + // 64-bit OID + U32 ullTsrOK[2]; + + // for some optional OIDs (64 bits) and DMI support + U32 ullTxBroadcastFrames[2]; + U32 ullTxMulticastFrames[2]; + U32 ullTxDirectedFrames[2]; + U32 ullTxBroadcastBytes[2]; + U32 ullTxMulticastBytes[2]; + U32 ullTxDirectedBytes[2]; +} SStatMIBCount, DEF* PSStatMIBCount; + + +typedef struct tagSNodeItem { + // STA info + U16 wAID; + U8 abyMACAddr[6]; + U16 wTxDataRate; + U16 wInActiveCount; + U16 wEnQueueCnt; + U16 wFlags; + BOOL bPWBitOn; + U8 byKeyIndex; + U16 wWepKeyLength; + U8 abyWepKey[WEP_KEYMAXLEN]; + // Auto rate fallback vars + BOOL bIsInFallback; + U32 uTxFailures; + U32 uTxAttempts; + U16 wFailureRatio; + +} SNodeItem; + + +typedef struct tagSNodeList { + + U32 uItem; + SNodeItem sNodeList[0]; + +} SNodeList, *PSNodeList; + + + +typedef struct tagSCmdValue { + + U32 dwValue; + +} SCmdValue, *PSCmdValue; + + +// +// hostapd & viawget ioctl related +// + + +// VIAGWET_IOCTL_HOSTAPD ioctl() cmd: +enum { + VIAWGET_HOSTAPD_FLUSH = 1, + VIAWGET_HOSTAPD_ADD_STA = 2, + VIAWGET_HOSTAPD_REMOVE_STA = 3, + VIAWGET_HOSTAPD_GET_INFO_STA = 4, + VIAWGET_HOSTAPD_SET_ENCRYPTION = 5, + VIAWGET_HOSTAPD_GET_ENCRYPTION = 6, + VIAWGET_HOSTAPD_SET_FLAGS_STA = 7, + VIAWGET_HOSTAPD_SET_ASSOC_AP_ADDR = 8, + VIAWGET_HOSTAPD_SET_GENERIC_ELEMENT = 9, + VIAWGET_HOSTAPD_MLME = 10, + VIAWGET_HOSTAPD_SCAN_REQ = 11, + VIAWGET_HOSTAPD_STA_CLEAR_STATS = 12, +}; + + +#define VIAWGET_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \ +((int) (&((struct viawget_hostapd_param *) 0)->u.generic_elem.data)) + +// Maximum length for algorithm names (-1 for nul termination) used in ioctl() + + + +struct viawget_hostapd_param { + U32 cmd; + U8 sta_addr[6]; + union { + struct { + U16 aid; + U16 capability; + U8 tx_supp_rates; + } add_sta; + struct { + U32 inactive_sec; + } get_info_sta; + struct { + U8 alg; + U32 flags; + U32 err; + U8 idx; + U8 seq[8]; + U16 key_len; + U8 key[0]; + } crypt; + struct { + U32 flags_and; + U32 flags_or; + } set_flags_sta; + struct { + U16 rid; + U16 len; + U8 data[0]; + } rid; + struct { + U8 len; + U8 data[0]; + } generic_elem; + struct { + U16 cmd; + U16 reason_code; + } mlme; + struct { + U8 ssid_len; + U8 ssid[32]; + } scan_req; + } u; +}; + +//2006-1116-01, by NomadZhao +#pragma pack() + +/*--------------------- Export Classes ----------------------------*/ + +/*--------------------- Export Variables --------------------------*/ + + +/*--------------------- Export Types ------------------------------*/ + + +/*--------------------- Export Functions --------------------------*/ + + + +#endif //__IOCMD_H__ diff --git a/drivers/staging/vt6655/ioctl.c b/drivers/staging/vt6655/ioctl.c new file mode 100644 index 000000000000..4869107a2bca --- /dev/null +++ b/drivers/staging/vt6655/ioctl.c @@ -0,0 +1,775 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * File: ioctl.c + * + * Purpose: private ioctl functions + * + * Author: Lyndon Chen + * + * Date: Auguest 20, 2003 + * + * Functions: + * + * Revision History: + * + */ + + +#if !defined(__IOCTL_H__) +#include "ioctl.h" +#endif +#if !defined(__IOCMD_H__) +#include "iocmd.h" +#endif +#if !defined(__MAC_H__) +#include "mac.h" +#endif +#if !defined(__CARD_H__) +#include "card.h" +#endif +#if !defined(__HOSTAP_H__) +#include "hostap.h" +#endif +#if !defined(__UMEM_H__) +#include "umem.h" +#endif +#if !defined(__WPACTL_H__) +#include "wpactl.h" +#endif +#if !defined(__RF_H__) +#include "rf.h" +#endif + + +/*--------------------- Static Definitions -------------------------*/ + +/*--------------------- Static Classes ----------------------------*/ + +/*--------------------- Static Variables --------------------------*/ +//static int msglevel =MSG_LEVEL_DEBUG; +static int msglevel =MSG_LEVEL_INFO; + +/*--------------------- Static Functions --------------------------*/ + +#ifdef WPA_SM_Transtatus + SWPAResult wpa_Result; +#endif + + +/*--------------------- Export Variables --------------------------*/ + +int private_ioctl(PSDevice pDevice, struct ifreq *rq) { + + PSCmdRequest pReq = (PSCmdRequest)rq; + PSMgmtObject pMgmt = pDevice->pMgmt; + int result = 0; + PWLAN_IE_SSID pItemSSID; + SCmdBSSJoin sJoinCmd; + SCmdZoneTypeSet sZoneTypeCmd; + SCmdScan sScanCmd; + SCmdStartAP sStartAPCmd; + SCmdSetWEP sWEPCmd; + SCmdValue sValue; + SBSSIDList sList; + SNodeList sNodeList; + PSBSSIDList pList; + PSNodeList pNodeList; + UINT cbListCount; + PKnownBSS pBSS; + PKnownNodeDB pNode; + UINT ii, jj; + SCmdLinkStatus sLinkStatus; + BYTE abySuppRates[] = {WLAN_EID_SUPP_RATES, 4, 0x02, 0x04, 0x0B, 0x16}; + BYTE abyNullAddr[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + DWORD dwKeyIndex= 0; + BYTE abyScanSSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1]; + LONG ldBm; + + + pReq->wResult = 0; + + switch(pReq->wCmdCode) { + + case WLAN_CMD_BSS_SCAN: + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "WLAN_CMD_BSS_SCAN..begin \n"); + if (copy_from_user(&sScanCmd, pReq->data, sizeof(SCmdScan))) { + result = -EFAULT; + break; + }; + + pItemSSID = (PWLAN_IE_SSID)sScanCmd.ssid; + if (pItemSSID->len != 0) { + memset(abyScanSSID, 0, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1); + memcpy(abyScanSSID, pItemSSID, pItemSSID->len + WLAN_IEHDR_LEN); + } + + if (pDevice->bMACSuspend == TRUE) { + if (pDevice->bRadioOff == TRUE) + CARDbRadioPowerOn(pDevice); + vMgrTimerInit(pDevice); + MACvIntEnable(pDevice->PortOffset, IMR_MASK_VALUE); + add_timer(&pMgmt->sTimerSecondCallback); + pDevice->bMACSuspend = FALSE; + } + spin_lock_irq(&pDevice->lock); + if (memcmp(pMgmt->abyCurrBSSID, &abyNullAddr[0], 6) == 0) + BSSvClearBSSList((HANDLE)pDevice, FALSE); + else + BSSvClearBSSList((HANDLE)pDevice, pDevice->bLinkPass); + + if (pItemSSID->len != 0) + bScheduleCommand((HANDLE) pDevice, WLAN_CMD_BSSID_SCAN, abyScanSSID); + else + bScheduleCommand((HANDLE) pDevice, WLAN_CMD_BSSID_SCAN, NULL); + spin_unlock_irq(&pDevice->lock); + break; + + case WLAN_CMD_ZONETYPE_SET: + //mike add :cann't support. + result=-EOPNOTSUPP; + break; + + if (copy_from_user(&sZoneTypeCmd, pReq->data, sizeof(SCmdZoneTypeSet))) { + result = -EFAULT; + break; + }; + + if(sZoneTypeCmd.bWrite==TRUE) { + //////write zonetype + if(sZoneTypeCmd.ZoneType == ZoneType_USA) { + //set to USA + printk("set_ZoneType:USA\n"); + } + else if(sZoneTypeCmd.ZoneType == ZoneType_Japan) { + //set to Japan + printk("set_ZoneType:Japan\n"); + } + else if(sZoneTypeCmd.ZoneType == ZoneType_Europe) { + //set to Europe + printk("set_ZoneType:Europe\n"); + } + } + else { + ///////read zonetype + BYTE zonetype=0; + + + if(zonetype == 0x00) { //USA + sZoneTypeCmd.ZoneType = ZoneType_USA; + } + else if(zonetype == 0x01) { //Japan + sZoneTypeCmd.ZoneType = ZoneType_Japan; + } + else if(zonetype == 0x02) { //Europe + sZoneTypeCmd.ZoneType = ZoneType_Europe; + } + else { //Unknow ZoneType + printk("Error:ZoneType[%x] Unknown ???\n",zonetype); + result = -EFAULT; + break; + } + if (copy_to_user(pReq->data, &sZoneTypeCmd, sizeof(SCmdZoneTypeSet))) { + result = -EFAULT; + break; + }; + } + + break; + + case WLAN_CMD_BSS_JOIN: + + if (pDevice->bMACSuspend == TRUE) { + if (pDevice->bRadioOff == TRUE) + CARDbRadioPowerOn(pDevice); + vMgrTimerInit(pDevice); + MACvIntEnable(pDevice->PortOffset, IMR_MASK_VALUE); + add_timer(&pMgmt->sTimerSecondCallback); + pDevice->bMACSuspend = FALSE; + } + + if (copy_from_user(&sJoinCmd, pReq->data, sizeof(SCmdBSSJoin))) { + result = -EFAULT; + break; + }; + + pItemSSID = (PWLAN_IE_SSID)sJoinCmd.ssid; + memset(pMgmt->abyDesireSSID, 0, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1); + memcpy(pMgmt->abyDesireSSID, pItemSSID, pItemSSID->len + WLAN_IEHDR_LEN); + if (sJoinCmd.wBSSType == ADHOC) { + pMgmt->eConfigMode = WMAC_CONFIG_IBSS_STA; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "ioct set to adhoc mode\n"); + } + else { + pMgmt->eConfigMode = WMAC_CONFIG_ESS_STA; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "ioct set to STA mode\n"); + } + if (sJoinCmd.bPSEnable == TRUE) { + pDevice->ePSMode = WMAC_POWER_FAST; +// pDevice->ePSMode = WMAC_POWER_MAX; + pMgmt->wListenInterval = 2; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Power Saving On\n"); + } + else { + pDevice->ePSMode = WMAC_POWER_CAM; + pMgmt->wListenInterval = 1; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Power Saving Off \n"); + } + + if (sJoinCmd.bShareKeyAuth == TRUE){ + pMgmt->bShareKeyAlgorithm = TRUE; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Share Key \n"); + } + else { + pMgmt->bShareKeyAlgorithm = FALSE; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Open System \n"); + } + pDevice->uChannel = sJoinCmd.uChannel; + netif_stop_queue(pDevice->dev); + spin_lock_irq(&pDevice->lock); + pMgmt->eCurrState = WMAC_STATE_IDLE; + bScheduleCommand((HANDLE) pDevice, WLAN_CMD_BSSID_SCAN, pMgmt->abyDesireSSID); + bScheduleCommand((HANDLE) pDevice, WLAN_CMD_SSID, NULL); + spin_unlock_irq(&pDevice->lock); + break; + + case WLAN_CMD_SET_WEP: + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "WLAN_CMD_SET_WEP Key. \n"); + memset(&sWEPCmd, 0 ,sizeof(SCmdSetWEP)); + if (copy_from_user(&sWEPCmd, pReq->data, sizeof(SCmdSetWEP))) { + result = -EFAULT; + break; + }; + if (sWEPCmd.bEnableWep != TRUE) { + pDevice->bEncryptionEnable = FALSE; + pDevice->eEncryptionStatus = Ndis802_11EncryptionDisabled; + MACvDisableDefaultKey(pDevice->PortOffset); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "WEP function disable. \n"); + break; + } + + for (ii = 0; ii < WLAN_WEP_NKEYS; ii ++) { + if (sWEPCmd.bWepKeyAvailable[ii]) { + if (ii == sWEPCmd.byKeyIndex) + //2006-1123-02, by EinsnLiu + //Evaluate the "dwKeyIndex" error + // dwKeyIndex |= (1 << 31); + dwKeyIndex =ii|(1 << 31); + else + dwKeyIndex = ii; + + KeybSetDefaultKey(&(pDevice->sKey), + dwKeyIndex, + sWEPCmd.auWepKeyLength[ii], + NULL, + (PBYTE)&sWEPCmd.abyWepKey[ii][0], + KEY_CTL_WEP, + pDevice->PortOffset, + pDevice->byLocalID); + } + } + pDevice->byKeyIndex = sWEPCmd.byKeyIndex; + pDevice->bTransmitKey = TRUE; + pDevice->bEncryptionEnable = TRUE; + pDevice->eEncryptionStatus = Ndis802_11Encryption1Enabled; + + break; + + case WLAN_CMD_GET_LINK: + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "WLAN_CMD_GET_LINK status. \n"); + + memset(sLinkStatus.abySSID, 0 , WLAN_SSID_MAXLEN + 1); + + if (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) + sLinkStatus.wBSSType = ADHOC; + else + sLinkStatus.wBSSType = INFRA; + + if (pMgmt->eCurrState == WMAC_STATE_JOINTED) + sLinkStatus.byState = ADHOC_JOINTED; + else + sLinkStatus.byState = ADHOC_STARTED; + + sLinkStatus.uChannel = pMgmt->uCurrChannel; + if (pDevice->bLinkPass == TRUE) { + sLinkStatus.bLink = TRUE; + pItemSSID = (PWLAN_IE_SSID)pMgmt->abyCurrSSID; + memcpy(sLinkStatus.abySSID, pItemSSID->abySSID, pItemSSID->len); + memcpy(sLinkStatus.abyBSSID, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN); + sLinkStatus.uLinkRate = pMgmt->sNodeDBTable[0].wTxDataRate; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO" Link Success ! \n"); + } + else { + sLinkStatus.bLink = FALSE; + } + if (copy_to_user(pReq->data, &sLinkStatus, sizeof(SCmdLinkStatus))) { + result = -EFAULT; + break; + }; + + break; + + case WLAN_CMD_GET_LISTLEN: + cbListCount = 0; + pBSS = &(pMgmt->sBSSList[0]); + for (ii = 0; ii < MAX_BSS_NUM; ii++) { + pBSS = &(pMgmt->sBSSList[ii]); + if (!pBSS->bActive) + continue; + cbListCount++; + }; + sList.uItem = cbListCount; + if (copy_to_user(pReq->data, &sList, sizeof(SBSSIDList))) { + result = -EFAULT; + break; + }; + pReq->wResult = 0; + break; + + case WLAN_CMD_GET_LIST: + if (copy_from_user(&sList, pReq->data, sizeof(SBSSIDList))) { + result = -EFAULT; + break; + }; + pList = (PSBSSIDList)kmalloc(sizeof(SBSSIDList) + (sList.uItem * sizeof(SBSSIDItem)), (int)GFP_ATOMIC); + if (pList == NULL) { + result = -ENOMEM; + break; + } + pList->uItem = sList.uItem; + pBSS = &(pMgmt->sBSSList[0]); + for (ii = 0, jj = 0; jj < MAX_BSS_NUM ; jj++) { + pBSS = &(pMgmt->sBSSList[jj]); + if (pBSS->bActive) { + pList->sBSSIDList[ii].uChannel = pBSS->uChannel; + pList->sBSSIDList[ii].wBeaconInterval = pBSS->wBeaconInterval; + pList->sBSSIDList[ii].wCapInfo = pBSS->wCapInfo; +// pList->sBSSIDList[ii].uRSSI = pBSS->uRSSI; + RFvRSSITodBm(pDevice, (BYTE)(pBSS->uRSSI), &ldBm); + pList->sBSSIDList[ii].uRSSI = (UINT)ldBm; + memcpy(pList->sBSSIDList[ii].abyBSSID, pBSS->abyBSSID, WLAN_BSSID_LEN); + pItemSSID = (PWLAN_IE_SSID)pBSS->abySSID; + memset(pList->sBSSIDList[ii].abySSID, 0, WLAN_SSID_MAXLEN + 1); + memcpy(pList->sBSSIDList[ii].abySSID, pItemSSID->abySSID, pItemSSID->len); + if (WLAN_GET_CAP_INFO_ESS(pBSS->wCapInfo)) { + pList->sBSSIDList[ii].byNetType = INFRA; + } + else { + pList->sBSSIDList[ii].byNetType = ADHOC; + } + if (WLAN_GET_CAP_INFO_PRIVACY(pBSS->wCapInfo)) { + pList->sBSSIDList[ii].bWEPOn = TRUE; + } + else { + pList->sBSSIDList[ii].bWEPOn = FALSE; + } + ii ++; + if (ii >= pList->uItem) + break; + } + } + + if (copy_to_user(pReq->data, pList, sizeof(SBSSIDList) + (sList.uItem * sizeof(SBSSIDItem)))) { + result = -EFAULT; + break; + }; + kfree(pList); + pReq->wResult = 0; + break; + + case WLAN_CMD_GET_MIB: + if (copy_to_user(pReq->data, &(pDevice->s802_11Counter), sizeof(SDot11MIBCount))) { + result = -EFAULT; + break; + }; + break; + + case WLAN_CMD_GET_STAT: + if (copy_to_user(pReq->data, &(pDevice->scStatistic), sizeof(SStatCounter))) { + result = -EFAULT; + break; + }; + break; + case WLAN_CMD_STOP_MAC: + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "WLAN_CMD_STOP_MAC\n"); + netif_stop_queue(pDevice->dev); + + spin_lock_irq(&pDevice->lock); + if (pDevice->bRadioOff == FALSE) { + CARDbRadioPowerOff(pDevice); + } + pDevice->bLinkPass = FALSE; + memset(pMgmt->abyCurrBSSID, 0, 6); + pMgmt->eCurrState = WMAC_STATE_IDLE; + del_timer(&pDevice->sTimerCommand); + del_timer(&pMgmt->sTimerSecondCallback); + pDevice->bCmdRunning = FALSE; + pDevice->bMACSuspend = TRUE; + MACvIntDisable(pDevice->PortOffset); + spin_unlock_irq(&pDevice->lock); + + break; + + case WLAN_CMD_START_MAC: + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "WLAN_CMD_START_MAC\n"); + + if (pDevice->bMACSuspend == TRUE) { + if (pDevice->bRadioOff == TRUE) + CARDbRadioPowerOn(pDevice); + vMgrTimerInit(pDevice); + MACvIntEnable(pDevice->PortOffset, IMR_MASK_VALUE); + add_timer(&pMgmt->sTimerSecondCallback); + pDevice->bMACSuspend = FALSE; + } + break; + + case WLAN_CMD_SET_HOSTAPD: + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "WLAN_CMD_SET_HOSTAPD\n"); + + if (copy_from_user(&sValue, pReq->data, sizeof(SCmdValue))) { + result = -EFAULT; + break; + }; + if (sValue.dwValue == 1) { + if (hostap_set_hostapd(pDevice, 1, 1) == 0){ + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Enable HOSTAP\n"); + } + else { + result = -EFAULT; + break; + } + } + else { + hostap_set_hostapd(pDevice, 0, 1); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Disable HOSTAP\n"); + } + + break; + + case WLAN_CMD_SET_HOSTAPD_STA: + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "WLAN_CMD_SET_HOSTAPD_STA\n"); + + break; + case WLAN_CMD_SET_802_1X: + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "WLAN_CMD_SET_802_1X\n"); + if (copy_from_user(&sValue, pReq->data, sizeof(SCmdValue))) { + result = -EFAULT; + break; + }; + + if (sValue.dwValue == 1) { + pDevice->bEnable8021x = TRUE; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Enable 802.1x\n"); + } + else { + pDevice->bEnable8021x = FALSE; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Disable 802.1x\n"); + } + + break; + + + case WLAN_CMD_SET_HOST_WEP: + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "WLAN_CMD_SET_HOST_WEP\n"); + if (copy_from_user(&sValue, pReq->data, sizeof(SCmdValue))) { + result = -EFAULT; + break; + }; + + if (sValue.dwValue == 1) { + pDevice->bEnableHostWEP = TRUE; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Enable HostWEP\n"); + } + else { + pDevice->bEnableHostWEP = FALSE; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Disable HostWEP\n"); + } + + break; + + case WLAN_CMD_SET_WPA: + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "WLAN_CMD_SET_WPA\n"); + + if (copy_from_user(&sValue, pReq->data, sizeof(SCmdValue))) { + result = -EFAULT; + break; + }; + if (sValue.dwValue == 1) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "up wpadev\n"); + memcpy(pDevice->wpadev->dev_addr, pDevice->dev->dev_addr, U_ETHER_ADDR_LEN); + pDevice->bWPADEVUp = TRUE; + } + else { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "close wpadev\n"); + pDevice->bWPADEVUp = FALSE; + } + + break; + + case WLAN_CMD_AP_START: + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "WLAN_CMD_AP_START\n"); + if (pDevice->bRadioOff == TRUE) { + CARDbRadioPowerOn(pDevice); + vMgrTimerInit(pDevice); + MACvIntEnable(pDevice->PortOffset, IMR_MASK_VALUE); + add_timer(&pMgmt->sTimerSecondCallback); + } + if (copy_from_user(&sStartAPCmd, pReq->data, sizeof(SCmdStartAP))) { + result = -EFAULT; + break; + }; + + if (sStartAPCmd.wBSSType == AP) { + pMgmt->eConfigMode = WMAC_CONFIG_AP; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "ioct set to AP mode\n"); + } + else { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "ioct BSS type not set to AP mode\n"); + result = -EFAULT; + break; + } + + + if (sStartAPCmd.wBBPType == PHY80211g) { + pMgmt->byAPBBType = PHY_TYPE_11G; + } + else if (sStartAPCmd.wBBPType == PHY80211a) { + pMgmt->byAPBBType = PHY_TYPE_11A; + } + else { + pMgmt->byAPBBType = PHY_TYPE_11B; + } + + pItemSSID = (PWLAN_IE_SSID)sStartAPCmd.ssid; + memset(pMgmt->abyDesireSSID, 0, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1); + memcpy(pMgmt->abyDesireSSID, pItemSSID, pItemSSID->len + WLAN_IEHDR_LEN); + + if ((sStartAPCmd.uChannel > 0)&&(sStartAPCmd.uChannel <= 14)) + pDevice->uChannel = sStartAPCmd.uChannel; + + if ((sStartAPCmd.uBeaconInt >= 20) && (sStartAPCmd.uBeaconInt <= 1000)) + pMgmt->wIBSSBeaconPeriod = sStartAPCmd.uBeaconInt; + else + pMgmt->wIBSSBeaconPeriod = 100; + + if (sStartAPCmd.bShareKeyAuth == TRUE){ + pMgmt->bShareKeyAlgorithm = TRUE; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Share Key \n"); + } + else { + pMgmt->bShareKeyAlgorithm = FALSE; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Open System \n"); + } + memcpy(pMgmt->abyIBSSSuppRates, abySuppRates, 6); + + if (sStartAPCmd.byBasicRate & BIT3) { + pMgmt->abyIBSSSuppRates[2] |= BIT7; + pMgmt->abyIBSSSuppRates[3] |= BIT7; + pMgmt->abyIBSSSuppRates[4] |= BIT7; + pMgmt->abyIBSSSuppRates[5] |= BIT7; + }else if (sStartAPCmd.byBasicRate & BIT2) { + pMgmt->abyIBSSSuppRates[2] |= BIT7; + pMgmt->abyIBSSSuppRates[3] |= BIT7; + pMgmt->abyIBSSSuppRates[4] |= BIT7; + }else if (sStartAPCmd.byBasicRate & BIT1) { + pMgmt->abyIBSSSuppRates[2] |= BIT7; + pMgmt->abyIBSSSuppRates[3] |= BIT7; + }else if (sStartAPCmd.byBasicRate & BIT1) { + pMgmt->abyIBSSSuppRates[2] |= BIT7; + }else { + //default 1,2M + pMgmt->abyIBSSSuppRates[2] |= BIT7; + pMgmt->abyIBSSSuppRates[3] |= BIT7; + } + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Support Rate= %x %x %x %x\n", + pMgmt->abyIBSSSuppRates[2], + pMgmt->abyIBSSSuppRates[3], + pMgmt->abyIBSSSuppRates[4], + pMgmt->abyIBSSSuppRates[5] + ); + + netif_stop_queue(pDevice->dev); + spin_lock_irq(&pDevice->lock); + bScheduleCommand((HANDLE)pDevice, WLAN_CMD_RUN_AP, NULL); + spin_unlock_irq(&pDevice->lock); + break; + + case WLAN_CMD_GET_NODE_CNT: + + cbListCount = 0; + pNode = &(pMgmt->sNodeDBTable[0]); + for (ii = 0; ii < (MAX_NODE_NUM + 1); ii++) { + pNode = &(pMgmt->sNodeDBTable[ii]); + if (!pNode->bActive) + continue; + cbListCount++; + }; + + sNodeList.uItem = cbListCount; + if (copy_to_user(pReq->data, &sNodeList, sizeof(SNodeList))) { + result = -EFAULT; + break; + }; + pReq->wResult = 0; + break; + + case WLAN_CMD_GET_NODE_LIST: + + if (copy_from_user(&sNodeList, pReq->data, sizeof(SNodeList))) { + result = -EFAULT; + break; + }; + pNodeList = (PSNodeList)kmalloc(sizeof(SNodeList) + (sNodeList.uItem * sizeof(SNodeItem)), (int)GFP_ATOMIC); + if (pNodeList == NULL) { + result = -ENOMEM; + break; + } + pNodeList->uItem = sNodeList.uItem; + pNode = &(pMgmt->sNodeDBTable[0]); + for (ii = 0, jj = 0; ii < (MAX_NODE_NUM + 1); ii++) { + pNode = &(pMgmt->sNodeDBTable[ii]); + if (pNode->bActive) { + pNodeList->sNodeList[jj].wAID = pNode->wAID; + memcpy(pNodeList->sNodeList[jj].abyMACAddr, pNode->abyMACAddr, WLAN_ADDR_LEN); + pNodeList->sNodeList[jj].wTxDataRate = pNode->wTxDataRate; + pNodeList->sNodeList[jj].wInActiveCount = (WORD)pNode->uInActiveCount; + pNodeList->sNodeList[jj].wEnQueueCnt = (WORD)pNode->wEnQueueCnt; + pNodeList->sNodeList[jj].wFlags = (WORD)pNode->dwFlags; + pNodeList->sNodeList[jj].bPWBitOn = pNode->bPSEnable; + pNodeList->sNodeList[jj].byKeyIndex = pNode->byKeyIndex; + pNodeList->sNodeList[jj].wWepKeyLength = pNode->uWepKeyLength; + memcpy(&(pNodeList->sNodeList[jj].abyWepKey[0]), &(pNode->abyWepKey[0]), WEP_KEYMAXLEN); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "key= %2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n", + pNodeList->sNodeList[jj].abyWepKey[0], + pNodeList->sNodeList[jj].abyWepKey[1], + pNodeList->sNodeList[jj].abyWepKey[2], + pNodeList->sNodeList[jj].abyWepKey[3], + pNodeList->sNodeList[jj].abyWepKey[4] + ); + pNodeList->sNodeList[jj].bIsInFallback = pNode->bIsInFallback; + pNodeList->sNodeList[jj].uTxFailures = pNode->uTxFailures; + pNodeList->sNodeList[jj].uTxAttempts = pNode->uTxAttempts; + pNodeList->sNodeList[jj].wFailureRatio = (WORD)pNode->uFailureRatio; + jj ++; + if (jj >= pNodeList->uItem) + break; + } + }; + if (copy_to_user(pReq->data, pNodeList, sizeof(SNodeList) + (sNodeList.uItem * sizeof(SNodeItem)))) { + result = -EFAULT; + break; + }; + kfree(pNodeList); + pReq->wResult = 0; + break; + +#ifdef WPA_SM_Transtatus + case 0xFF: + memset(wpa_Result.ifname,0,sizeof(wpa_Result.ifname)); + wpa_Result.proto = 0; + wpa_Result.key_mgmt = 0; + wpa_Result.eap_type = 0; + wpa_Result.authenticated = FALSE; + pDevice->fWPA_Authened = FALSE; + if (copy_from_user(&wpa_Result, pReq->data, sizeof(wpa_Result))) { + result = -EFAULT; + break; + } + + if(wpa_Result.authenticated==TRUE) { + #ifdef SndEvt_ToAPI + { + union iwreq_data wrqu; + + pItemSSID = (PWLAN_IE_SSID)pMgmt->abyCurrSSID; + + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.flags = RT_WPACONNECTED_EVENT_FLAG; + wrqu.data.length =pItemSSID->len; + wireless_send_event(pDevice->dev, IWEVCUSTOM, &wrqu, pItemSSID->abySSID); + } + #endif + pDevice->fWPA_Authened = TRUE; //is sucessful peer to wpa_Result.authenticated? +} + + //printk("get private wpa_supplicant announce WPA SM\n"); + //printk("wpa-->ifname=%s\n",wpa_Result.ifname); + //printk("wpa-->proto=%d\n",wpa_Result.proto); + //printk("wpa-->key-mgmt=%d\n",wpa_Result.key_mgmt); + //printk("wpa-->eap_type=%d\n",wpa_Result.eap_type); + //printk("wpa-->authenticated is %s\n",(wpa_Result.authenticated==TRUE)?"TRUE":"FALSE"); + + pReq->wResult = 0; + break; +#endif + + + default: + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Private command not support..\n"); + } + + return result; +} + +/* +VOID +vConfigWEPKey ( + IN PSDevice pDevice, + IN DWORD dwKeyIndex, + IN PBYTE pbyKey, + IN ULONG uKeyLength + ) +{ + int ii; + + + ZERO_MEMORY(&pDevice->abyWepKey[dwKeyIndex][0], WLAN_WEPMAX_KEYLEN); + MEMvCopy(&pDevice->abyWepKey[dwKeyIndex][0], pbyKey, uKeyLength); + + pDevice->bWepKeyAvailable[dwKeyIndex] = TRUE; + pDevice->auWepKeyLength[dwKeyIndex] = uKeyLength; + + MACvSetDefaultKeyEntry(pDevice->PortOffset, uKeyLength, dwKeyIndex, + (PDWORD) &(pDevice->abyWepKey[dwKeyIndex][0]), pDevice->byLocalID); + + if (pDevice->eEncryptionStatus < Ndis802_11EncryptionNotSupported) { + for(ii=0; iibWepKeyAvailable[ii] == TRUE) && + (pDevice->auWepKeyLength[ii] == WLAN_WEP232_KEYLEN)) { + pDevice->uCurrentWEPMode = TX_WEP_SW232; + MACvDisableDefaultKey(pDevice->PortOffset); + break; + } + } + if ((ii == MAX_GROUP_KEY) && + (pDevice->eEncryptionStatus < Ndis802_11EncryptionNotSupported)) { + MACvEnableDefaultKey(pDevice->PortOffset, pDevice->byLocalID); + } + } +} +*/ diff --git a/drivers/staging/vt6655/ioctl.h b/drivers/staging/vt6655/ioctl.h new file mode 100644 index 000000000000..9c6816eab46c --- /dev/null +++ b/drivers/staging/vt6655/ioctl.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * File: hostap.h + * + * Purpose: + * + * Author: Lyndon Chen + * + * Date: May 21, 2003 + * + */ + + +#ifndef __IOCTL_H__ +#define __IOCTL_H__ + +#if !defined(__DEVICE_H__) +#include "device.h" +#endif + + +/*--------------------- Export Definitions -------------------------*/ + + +/*--------------------- Export Classes ----------------------------*/ + +/*--------------------- Export Variables --------------------------*/ + +/*--------------------- Export Functions --------------------------*/ + + +#ifdef __cplusplus +extern "C" { /* Assume C declarations for C++ */ +#endif /* __cplusplus */ + + +int private_ioctl(PSDevice pDevice, struct ifreq *rq); + +/* +VOID vConfigWEPKey ( + IN PSDevice pDevice, + IN DWORD dwKeyIndex, + IN PBYTE pbyKey, + IN ULONG uKeyLength + ); +*/ + +#ifdef __cplusplus +} /* End of extern "C" { */ +#endif /* __cplusplus */ + + + + +#endif // __IOCTL_H__ + + + diff --git a/drivers/staging/vt6655/iowpa.h b/drivers/staging/vt6655/iowpa.h new file mode 100644 index 000000000000..451e2efc5ce5 --- /dev/null +++ b/drivers/staging/vt6655/iowpa.h @@ -0,0 +1,159 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * File: iowpa.h + * + * Purpose: Handles wpa supplicant ioctl interface + * + * Author: Lyndon Chen + * + * Date: May 8, 2002 + * + */ + +#ifndef __IOWPA_H__ +#define __IOWPA_H__ + + +/*--------------------- Export Definitions -------------------------*/ + + +#define WPA_IE_LEN 64 + + +//WPA related +/* +typedef enum { WPA_ALG_NONE, WPA_ALG_WEP, WPA_ALG_TKIP, WPA_ALG_CCMP } wpa_alg; +typedef enum { CIPHER_NONE, CIPHER_WEP40, CIPHER_TKIP, CIPHER_CCMP, + CIPHER_WEP104 } wpa_cipher; +typedef enum { KEY_MGMT_802_1X, KEY_MGMT_PSK, KEY_MGMT_NONE, + KEY_MGMT_802_1X_NO_WPA, KEY_MGMT_WPA_NONE } wpa_key_mgmt; +*/ + +enum { + VIAWGET_SET_WPA = 1, + VIAWGET_SET_KEY = 2, + VIAWGET_SET_SCAN = 3, + VIAWGET_GET_SCAN = 4, + VIAWGET_GET_SSID = 5, + VIAWGET_GET_BSSID = 6, + VIAWGET_SET_DROP_UNENCRYPT = 7, + VIAWGET_SET_DEAUTHENTICATE = 8, + VIAWGET_SET_ASSOCIATE = 9, + VIAWGET_SET_DISASSOCIATE= 10 +}; + + +enum { + VIAWGET_ASSOC_MSG = 1, + VIAWGET_DISASSOC_MSG = 2, + VIAWGET_PTK_MIC_MSG = 3, + VIAWGET_GTK_MIC_MSG = 4, + VIAWGET_CCKM_ROAM_MSG = 5, + VIAWGET_DEVICECLOSE_MSG = 6 +}; + + + +#pragma pack(1) +typedef struct viawget_wpa_header { + u8 type; + u16 req_ie_len; + u16 resp_ie_len; +} viawget_wpa_header; + + + +struct viawget_wpa_param { + u32 cmd; + u8 addr[6]; + union { + struct { + u8 len; + u8 data[0]; + } generic_elem; + + struct { + u8 bssid[6]; + u8 ssid[32]; + u8 ssid_len; + u8 *wpa_ie; + u16 wpa_ie_len; + int pairwise_suite; + int group_suite; + int key_mgmt_suite; + int auth_alg; + int mode; + + } wpa_associate; + + struct { + int alg_name; + u16 key_index; + u16 set_tx; + u8 *seq; + u16 seq_len; + u8 *key; + u16 key_len; + } wpa_key; + + struct { + u8 ssid_len; + u8 ssid[32]; + } scan_req; + + struct { + u16 scan_count; + u8 *buf; + } scan_results; + + } u; + +}; + +#pragma pack(1) +struct viawget_scan_result { + u8 bssid[6]; + u8 ssid[32]; + u16 ssid_len; + u8 wpa_ie[WPA_IE_LEN]; + u16 wpa_ie_len; + u8 rsn_ie[WPA_IE_LEN]; + u16 rsn_ie_len; + int freq; // MHz + int caps; // e.g. privacy + int qual; // signal quality + int noise; + int level; + int maxrate; +}; + +//2006-1116-01, by NomadZhao +#pragma pack() +/*--------------------- Export Classes ----------------------------*/ + +/*--------------------- Export Variables --------------------------*/ + + +/*--------------------- Export Types ------------------------------*/ + + +/*--------------------- Export Functions --------------------------*/ + + + +#endif //__IOWPA_H__ diff --git a/drivers/staging/vt6655/iwctl.c b/drivers/staging/vt6655/iwctl.c new file mode 100644 index 000000000000..4d5a1da8edfc --- /dev/null +++ b/drivers/staging/vt6655/iwctl.c @@ -0,0 +1,2397 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * File: iwctl.c + * + * Purpose: wireless ext & ioctl functions + * + * Author: Lyndon Chen + * + * Date: July 5, 2006 + * + * Functions: + * + * Revision History: + * + */ + + +#if !defined(__DEVICE_H__) +#include "device.h" +#endif +#if !defined(__IOCTL_H__) +#include "ioctl.h" +#endif +#if !defined(__IOCMD_H__) +#include "iocmd.h" +#endif +#if !defined(__MAC_H__) +#include "mac.h" +#endif +#if !defined(__CARD_H__) +#include "card.h" +#endif +#if !defined(__HOSTAP_H__) +#include "hostap.h" +#endif +#if !defined(__UMEM_H__) +#include "umem.h" +#endif +#if !defined(__POWER_H__) +#include "power.h" +#endif +#if !defined(__RF_H__) +#include "rf.h" +#endif + +#ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT +#if !defined(__IOWPA_H__) +#include "iowpa.h" +#endif +#if !defined(__WPACTL_H__) +#include "wpactl.h" +#endif +#endif + +#if WIRELESS_EXT > 12 +#include +#endif +extern WORD TxRate_iwconfig;//2008-5-8 by chester + +/*--------------------- Static Definitions -------------------------*/ + +//2008-0409-07, by Einsn Liu +#ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT +#define SUPPORTED_WIRELESS_EXT 18 +#else +#define SUPPORTED_WIRELESS_EXT 17 +#endif + +#ifdef WIRELESS_EXT + +static const long frequency_list[] = { + 2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447, 2452, 2457, 2462, 2467, 2472, 2484, + 4915, 4920, 4925, 4935, 4940, 4945, 4960, 4980, + 5035, 5040, 5045, 5055, 5060, 5080, 5170, 5180, 5190, 5200, 5210, 5220, 5230, 5240, + 5260, 5280, 5300, 5320, 5500, 5520, 5540, 5560, 5580, 5600, 5620, 5640, 5660, 5680, + 5700, 5745, 5765, 5785, 5805, 5825 + }; + +#endif + + +/*--------------------- Static Classes ----------------------------*/ + + +//static int msglevel =MSG_LEVEL_DEBUG; +static int msglevel =MSG_LEVEL_INFO; + + +/*--------------------- Static Variables --------------------------*/ +/*--------------------- Static Functions --------------------------*/ + +/*--------------------- Export Variables --------------------------*/ + +#ifdef WIRELESS_EXT + +#if WIRELESS_EXT > 12 + +struct iw_statistics *iwctl_get_wireless_stats(struct net_device *dev) +{ + PSDevice pDevice = netdev_priv(dev); + long ldBm; + pDevice->wstats.status = pDevice->eOPMode; + #ifdef Calcu_LinkQual + #if 0 + if(pDevice->byBBType == BB_TYPE_11B) { + if(pDevice->byCurrSQ > 120) + pDevice->scStatistic.LinkQuality = 100; + else + pDevice->scStatistic.LinkQuality = pDevice->byCurrSQ*100/120; + } + else if(pDevice->byBBType == BB_TYPE_11G) { + if(pDevice->byCurrSQ < 20) + pDevice->scStatistic.LinkQuality = 100; + else if(pDevice->byCurrSQ >96) + pDevice->scStatistic.LinkQuality = 0; + else + pDevice->scStatistic.LinkQuality = (96-pDevice->byCurrSQ)*100/76; + } + if(pDevice->bLinkPass !=TRUE) + pDevice->scStatistic.LinkQuality = 0; + #endif + if(pDevice->scStatistic.LinkQuality > 100) + pDevice->scStatistic.LinkQuality = 100; + pDevice->wstats.qual.qual =(BYTE) pDevice->scStatistic.LinkQuality; + #else + pDevice->wstats.qual.qual = pDevice->byCurrSQ; + #endif + RFvRSSITodBm(pDevice, (BYTE)(pDevice->uCurrRSSI), &ldBm); + pDevice->wstats.qual.level = ldBm; + //pDevice->wstats.qual.level = 0x100 - pDevice->uCurrRSSI; + pDevice->wstats.qual.noise = 0; + pDevice->wstats.qual.updated = 1; + pDevice->wstats.discard.nwid = 0; + pDevice->wstats.discard.code = 0; + pDevice->wstats.discard.fragment = 0; + pDevice->wstats.discard.retries = (U32)pDevice->scStatistic.dwTsrErr; + pDevice->wstats.discard.misc = 0; + pDevice->wstats.miss.beacon = 0; + + return &pDevice->wstats; +} + +#endif + + + +/*------------------------------------------------------------------*/ + + +static int iwctl_commit(struct net_device *dev, + struct iw_request_info *info, + void *wrq, + char *extra) +{ + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWCOMMIT \n"); + + return 0; + +} + +/* + * Wireless Handler : get protocol name + */ + +int iwctl_giwname(struct net_device *dev, + struct iw_request_info *info, + char *wrq, + char *extra) +{ + strcpy(wrq, "802.11-a/b/g"); + return 0; +} + +int iwctl_giwnwid(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *wrq, + char *extra) +{ + //wrq->value = 0x100; + //wrq->disabled = 0; + //wrq->fixed = 1; + //return 0; + return -EOPNOTSUPP; +} +#if WIRELESS_EXT > 13 + +/* + * Wireless Handler : set scan + */ + +int iwctl_siwscan(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *wrq, + char *extra) +{ + PSDevice pDevice = (PSDevice)netdev_priv(dev); + struct iw_scan_req *req = (struct iw_scan_req *)extra; + PSMgmtObject pMgmt = &(pDevice->sMgmtObj); + BYTE abyScanSSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1]; + PWLAN_IE_SSID pItemSSID=NULL; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWSCAN \n"); + + +if(pDevice->byReAssocCount > 0) { //reject scan when re-associating! +//send scan event to wpa_Supplicant + union iwreq_data wrqu; + printk("wireless_send_event--->SIOCGIWSCAN(scan done)\n"); + memset(&wrqu, 0, sizeof(wrqu)); + wireless_send_event(pDevice->dev, SIOCGIWSCAN, &wrqu, NULL); + return 0; +} + + spin_lock_irq(&pDevice->lock); + BSSvClearBSSList((HANDLE)pDevice, pDevice->bLinkPass); + +//mike add: active scan OR passive scan OR desire_ssid scan + if(wrq->length == sizeof(struct iw_scan_req)) { + if (wrq->flags & IW_SCAN_THIS_ESSID) { //desire_ssid scan + memset(abyScanSSID, 0, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1); + pItemSSID = (PWLAN_IE_SSID)abyScanSSID; + pItemSSID->byElementID = WLAN_EID_SSID; + memcpy(pItemSSID->abySSID, req->essid, (int)req->essid_len); + if (pItemSSID->abySSID[req->essid_len - 1] == '\0') { + if(req->essid_len>0) + pItemSSID->len = req->essid_len - 1; + } + else + pItemSSID->len = req->essid_len; + pMgmt->eScanType = WMAC_SCAN_PASSIVE; + printk("SIOCSIWSCAN:[desired_ssid=%s,len=%d]\n",((PWLAN_IE_SSID)abyScanSSID)->abySSID, + ((PWLAN_IE_SSID)abyScanSSID)->len); + bScheduleCommand((HANDLE) pDevice, WLAN_CMD_BSSID_SCAN, abyScanSSID); + spin_unlock_irq(&pDevice->lock); + + return 0; + } + else if(req->scan_type == IW_SCAN_TYPE_PASSIVE) { //passive scan + pMgmt->eScanType = WMAC_SCAN_PASSIVE; + } + } + else { //active scan + pMgmt->eScanType = WMAC_SCAN_ACTIVE; + } + + pMgmt->eScanType = WMAC_SCAN_PASSIVE; + bScheduleCommand((HANDLE) pDevice, WLAN_CMD_BSSID_SCAN, NULL); + spin_unlock_irq(&pDevice->lock); + + return 0; +} + + +/* + * Wireless Handler : get scan results + */ + +int iwctl_giwscan(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *wrq, + char *extra) +{ + int ii, jj, kk; + PSDevice pDevice = (PSDevice)netdev_priv(dev); + PSMgmtObject pMgmt = &(pDevice->sMgmtObj); + PKnownBSS pBSS; + PWLAN_IE_SSID pItemSSID; + PWLAN_IE_SUPP_RATES pSuppRates, pExtSuppRates; + char *current_ev = extra; + char *end_buf = extra + IW_SCAN_MAX_DATA; + char *current_val = NULL; + struct iw_event iwe; + long ldBm; +#if WIRELESS_EXT > 14 + char buf[MAX_WPA_IE_LEN * 2 + 30]; +#endif /* WIRELESS_EXT > 14 */ + + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWSCAN \n"); + + if (pMgmt->eScanState == WMAC_IS_SCANNING) { + // In scanning.. + return -EAGAIN; + } + pBSS = &(pMgmt->sBSSList[0]); + for (ii = 0, jj = 0; jj < MAX_BSS_NUM ; jj++) { + if (current_ev >= end_buf) + break; + pBSS = &(pMgmt->sBSSList[jj]); + if (pBSS->bActive) { + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWAP; + iwe.u.ap_addr.sa_family = ARPHRD_ETHER; + memcpy(iwe.u.ap_addr.sa_data, pBSS->abyBSSID, WLAN_BSSID_LEN); + current_ev = iwe_stream_add_event(info,current_ev,end_buf, &iwe, IW_EV_ADDR_LEN); + //ADD ssid + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWESSID; + pItemSSID = (PWLAN_IE_SSID)pBSS->abySSID; + iwe.u.data.length = pItemSSID->len; + iwe.u.data.flags = 1; + current_ev = iwe_stream_add_point(info,current_ev,end_buf, &iwe, pItemSSID->abySSID); + //ADD mode + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWMODE; + if (WLAN_GET_CAP_INFO_ESS(pBSS->wCapInfo)) { + iwe.u.mode = IW_MODE_INFRA; + } + else { + iwe.u.mode = IW_MODE_ADHOC; + } + iwe.len = IW_EV_UINT_LEN; + current_ev = iwe_stream_add_event(info,current_ev, end_buf, &iwe, IW_EV_UINT_LEN); + //ADD frequency + pSuppRates = (PWLAN_IE_SUPP_RATES)pBSS->abySuppRates; + pExtSuppRates = (PWLAN_IE_SUPP_RATES)pBSS->abyExtSuppRates; + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWFREQ; + iwe.u.freq.m = pBSS->uChannel; + iwe.u.freq.e = 0; + iwe.u.freq.i = 0; + current_ev = iwe_stream_add_event(info,current_ev,end_buf, &iwe, IW_EV_FREQ_LEN); + + + //2008-0409-04, by Einsn Liu + { + int f = (int)pBSS->uChannel - 1; + if(f < 0)f = 0; + iwe.u.freq.m = frequency_list[f] * 100000; + iwe.u.freq.e = 1; + } + current_ev = iwe_stream_add_event(info,current_ev,end_buf, &iwe, IW_EV_FREQ_LEN); + //ADD quality + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = IWEVQUAL; + RFvRSSITodBm(pDevice, (BYTE)(pBSS->uRSSI), &ldBm); + iwe.u.qual.level = ldBm; + iwe.u.qual.noise = 0; +//2008-0409-01, by Einsn Liu + if(-ldBm<50){ + iwe.u.qual.qual = 100; + }else if(-ldBm > 90) { + iwe.u.qual.qual = 0; + }else { + iwe.u.qual.qual=(40-(-ldBm-50))*100/40; + } + iwe.u.qual.updated=7; + + // iwe.u.qual.qual = 0; + current_ev = iwe_stream_add_event(info,current_ev, end_buf, &iwe, IW_EV_QUAL_LEN); + + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWENCODE; + iwe.u.data.length = 0; + if (WLAN_GET_CAP_INFO_PRIVACY(pBSS->wCapInfo)) { + iwe.u.data.flags =IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; + }else { + iwe.u.data.flags = IW_ENCODE_DISABLED; + } + current_ev = iwe_stream_add_point(info,current_ev,end_buf, &iwe, pItemSSID->abySSID); + + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWRATE; + iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; + current_val = current_ev + IW_EV_LCP_LEN; + + for (kk = 0 ; kk < 12 ; kk++) { + if (pSuppRates->abyRates[kk] == 0) + break; + // Bit rate given in 500 kb/s units (+ 0x80) + iwe.u.bitrate.value = ((pSuppRates->abyRates[kk] & 0x7f) * 500000); + current_val = iwe_stream_add_value(info,current_ev, current_val, end_buf, &iwe, IW_EV_PARAM_LEN); + } + for (kk = 0 ; kk < 8 ; kk++) { + if (pExtSuppRates->abyRates[kk] == 0) + break; + // Bit rate given in 500 kb/s units (+ 0x80) + iwe.u.bitrate.value = ((pExtSuppRates->abyRates[kk] & 0x7f) * 500000); + current_val = iwe_stream_add_value(info,current_ev, current_val, end_buf, &iwe, IW_EV_PARAM_LEN); + } + + if((current_val - current_ev) > IW_EV_LCP_LEN) + current_ev = current_val; + +#if WIRELESS_EXT > 14 + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = IWEVCUSTOM; + sprintf(buf, "bcn_int=%d", pBSS->wBeaconInterval); + iwe.u.data.length = strlen(buf); + current_ev = iwe_stream_add_point(info,current_ev, end_buf, &iwe, buf); + +#if WIRELESS_EXT > 17 + if ((pBSS->wWPALen > 0) && (pBSS->wWPALen <= MAX_WPA_IE_LEN)) { + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = IWEVGENIE; + iwe.u.data.length = pBSS->wWPALen; + current_ev = iwe_stream_add_point(info,current_ev, end_buf, &iwe, pBSS->byWPAIE); + } + + if ((pBSS->wRSNLen > 0) && (pBSS->wRSNLen <= MAX_WPA_IE_LEN)) { + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = IWEVGENIE; + iwe.u.data.length = pBSS->wRSNLen; + current_ev = iwe_stream_add_point(info,current_ev, end_buf, &iwe, pBSS->byRSNIE); + } + +#else // WIRELESS_EXT > 17 + if ((pBSS->wWPALen > 0) && (pBSS->wWPALen <= MAX_WPA_IE_LEN)) { + u8 *p = buf; + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = IWEVCUSTOM; + p += sprintf(p, "wpa_ie="); + for (ii = 0; ii < pBSS->wWPALen; ii++) { + p += sprintf(p, "%02x", pBSS->byWPAIE[ii]); + } + iwe.u.data.length = strlen(buf); + current_ev = iwe_stream_add_point(info,current_ev, end_buf, &iwe, buf); + } + + + if ((pBSS->wRSNLen > 0) && (pBSS->wRSNLen <= MAX_WPA_IE_LEN)) { + u8 *p = buf; + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = IWEVCUSTOM; + p += sprintf(p, "rsn_ie="); + for (ii = 0; ii < pBSS->wRSNLen; ii++) { + p += sprintf(p, "%02x", pBSS->byRSNIE[ii]); + } + iwe.u.data.length = strlen(buf); + current_ev = iwe_stream_add_point(info,current_ev, end_buf, &iwe, buf); + } +#endif +#endif + } + }// for + + wrq->length = current_ev - extra; + return 0; + +} + +#endif /* WIRELESS_EXT > 13 */ + + +/* + * Wireless Handler : set frequence or channel + */ + +int iwctl_siwfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *wrq, + char *extra) +{ + PSDevice pDevice = (PSDevice)netdev_priv(dev); + int rc = 0; + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWFREQ \n"); + + // If setting by frequency, convert to a channel + if((wrq->e == 1) && + (wrq->m >= (int) 2.412e8) && + (wrq->m <= (int) 2.487e8)) { + int f = wrq->m / 100000; + int c = 0; + while((c < 14) && (f != frequency_list[c])) + c++; + wrq->e = 0; + wrq->m = c + 1; + } + // Setting by channel number + if((wrq->m > 14) || (wrq->e > 0)) + rc = -EOPNOTSUPP; + else { + int channel = wrq->m; + if((channel < 1) || (channel > 14)) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%s: New channel value of %d is invalid!\n", dev->name, wrq->m); + rc = -EINVAL; + } else { + // Yes ! We can set it !!! + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " Set to channel = %d\n", channel); + pDevice->uChannel = channel; + //2007-0207-04, by EinsnLiu + //Make change effect at once + pDevice->bCommit = TRUE; + } + } + + return rc; +} + +/* + * Wireless Handler : get frequence or channel + */ + +int iwctl_giwfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *wrq, + char *extra) +{ + PSDevice pDevice = (PSDevice)netdev_priv(dev); + PSMgmtObject pMgmt = &(pDevice->sMgmtObj); + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWFREQ \n"); + +#ifdef WEXT_USECHANNELS + wrq->m = (int)pMgmt->uCurrChannel; + wrq->e = 0; +#else + { + int f = (int)pMgmt->uCurrChannel - 1; + if(f < 0) + f = 0; + wrq->m = frequency_list[f] * 100000; + wrq->e = 1; + } +#endif + + return 0; +} + +/* + * Wireless Handler : set operation mode + */ + +int iwctl_siwmode(struct net_device *dev, + struct iw_request_info *info, + __u32 *wmode, + char *extra) +{ + PSDevice pDevice = (PSDevice)netdev_priv(dev); + PSMgmtObject pMgmt = &(pDevice->sMgmtObj); + int rc = 0; + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWMODE \n"); + + if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP && pDevice->bEnableHostapd) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Can't set operation mode, hostapd is running \n"); + return rc; + } + + switch(*wmode) { + + case IW_MODE_ADHOC: + if (pMgmt->eConfigMode != WMAC_CONFIG_IBSS_STA) { + pMgmt->eConfigMode = WMAC_CONFIG_IBSS_STA; + if (pDevice->flags & DEVICE_FLAGS_OPENED) { + pDevice->bCommit = TRUE; + } + } + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "set mode to ad-hoc \n"); + break; + case IW_MODE_AUTO: + case IW_MODE_INFRA: + if (pMgmt->eConfigMode != WMAC_CONFIG_ESS_STA) { + pMgmt->eConfigMode = WMAC_CONFIG_ESS_STA; + if (pDevice->flags & DEVICE_FLAGS_OPENED) { + pDevice->bCommit = TRUE; + } + } + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "set mode to infrastructure \n"); + break; + case IW_MODE_MASTER: + + pMgmt->eConfigMode = WMAC_CONFIG_ESS_STA; + rc = -EOPNOTSUPP; + break; + + if (pMgmt->eConfigMode != WMAC_CONFIG_AP) { + pMgmt->eConfigMode = WMAC_CONFIG_AP; + if (pDevice->flags & DEVICE_FLAGS_OPENED) { + pDevice->bCommit = TRUE; + } + } + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "set mode to Access Point \n"); + break; + + case IW_MODE_REPEAT: + pMgmt->eConfigMode = WMAC_CONFIG_ESS_STA; + rc = -EOPNOTSUPP; + break; + default: + rc = -EINVAL; + } + + return rc; +} + +/* + * Wireless Handler : get operation mode + */ + +int iwctl_giwmode(struct net_device *dev, + struct iw_request_info *info, + __u32 *wmode, + char *extra) +{ + PSDevice pDevice = (PSDevice)netdev_priv(dev); + PSMgmtObject pMgmt = &(pDevice->sMgmtObj); + + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWMODE \n"); + // If not managed, assume it's ad-hoc + switch (pMgmt->eConfigMode) { + case WMAC_CONFIG_ESS_STA: + *wmode = IW_MODE_INFRA; + break; + case WMAC_CONFIG_IBSS_STA: + *wmode = IW_MODE_ADHOC; + break; + case WMAC_CONFIG_AUTO: + *wmode = IW_MODE_INFRA; + break; + case WMAC_CONFIG_AP: + *wmode = IW_MODE_MASTER; + break; + default: + *wmode = IW_MODE_ADHOC; + } + + return 0; +} + + +/* + * Wireless Handler : get capability range + */ + +int iwctl_giwrange(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *wrq, + char *extra) +{ + struct iw_range *range = (struct iw_range *) extra; + int i,k; + BYTE abySupportedRates[13]= {0x02, 0x04, 0x0B, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x90}; + + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWRANGE \n"); + if (wrq->pointer) { + wrq->length = sizeof(struct iw_range); + memset(range, 0, sizeof(struct iw_range)); + range->min_nwid = 0x0000; + range->max_nwid = 0x0000; + range->num_channels = 14; + // Should be based on cap_rid.country to give only + // what the current card support + k = 0; + for(i = 0; i < 14; i++) { + range->freq[k].i = i + 1; // List index + range->freq[k].m = frequency_list[i] * 100000; + range->freq[k++].e = 1; // Values in table in MHz -> * 10^5 * 10 + } + range->num_frequency = k; + // Hum... Should put the right values there + #ifdef Calcu_LinkQual + range->max_qual.qual = 100; + #else + range->max_qual.qual = 255; + #endif + range->max_qual.level = 0; + range->max_qual.noise = 0; + range->sensitivity = 255; + + for(i = 0 ; i < 13 ; i++) { + range->bitrate[i] = abySupportedRates[i] * 500000; + if(range->bitrate[i] == 0) + break; + } + range->num_bitrates = i; + + // Set an indication of the max TCP throughput + // in bit/s that we can expect using this interface. + // May be use for QoS stuff... Jean II + if(i > 2) + range->throughput = 5 * 1000 * 1000; + else + range->throughput = 1.5 * 1000 * 1000; + + range->min_rts = 0; + range->max_rts = 2312; + range->min_frag = 256; + range->max_frag = 2312; + + + // the encoding capabilities + range->num_encoding_sizes = 3; + // 64(40) bits WEP + range->encoding_size[0] = 5; + // 128(104) bits WEP + range->encoding_size[1] = 13; + // 256 bits for WPA-PSK + range->encoding_size[2] = 32; + // 4 keys are allowed + range->max_encoding_tokens = 4; + +#if WIRELESS_EXT > 17 + range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | + IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; +#endif + +#if WIRELESS_EXT > 9 + range->min_pmp = 0; + range->max_pmp = 1000000;// 1 secs + range->min_pmt = 0; + range->max_pmt = 1000000;// 1 secs + range->pmp_flags = IW_POWER_PERIOD; + range->pmt_flags = IW_POWER_TIMEOUT; + range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R; + + // Transmit Power - values are in mW + + range->txpower[0] = 100; + range->num_txpower = 1; + range->txpower_capa = IW_TXPOW_MWATT; +#endif // WIRELESS_EXT > 9 +#if WIRELESS_EXT > 10 + range->we_version_source = SUPPORTED_WIRELESS_EXT; + range->we_version_compiled = WIRELESS_EXT; + range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME; + range->retry_flags = IW_RETRY_LIMIT; + range->r_time_flags = IW_RETRY_LIFETIME; + range->min_retry = 1; + range->max_retry = 65535; + range->min_r_time = 1024; + range->max_r_time = 65535 * 1024; +#endif // WIRELESS_EXT > 10 +#if WIRELESS_EXT > 11 + // Experimental measurements - boundary 11/5.5 Mb/s + // Note : with or without the (local->rssi), results + // are somewhat different. - Jean II + range->avg_qual.qual = 6; + range->avg_qual.level = 176; // -80 dBm + range->avg_qual.noise = 0; +#endif // WIRELESS_EXT > 11 + } + + + return 0; +} + + +/* + * Wireless Handler : set ap mac address + */ + +int iwctl_siwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *wrq, + char *extra) +{ + PSDevice pDevice = (PSDevice)netdev_priv(dev); + PSMgmtObject pMgmt = &(pDevice->sMgmtObj); + int rc = 0; + BYTE ZeroBSSID[WLAN_BSSID_LEN]={0x00,0x00,0x00,0x00,0x00,0x00}; + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWAP \n"); +if (pMgmt->eScanState == WMAC_IS_SCANNING) { + // In scanning.. + printk("SIOCSIWAP(??)-->In scanning...\n"); + // return -EAGAIN; + } + if (wrq->sa_family != ARPHRD_ETHER) + rc = -EINVAL; + else { + memset(pMgmt->abyDesireBSSID, 0xFF, 6); + memcpy(pMgmt->abyDesireBSSID, wrq->sa_data, 6); + //2008-0409-05, by Einsn Liu + if((pDevice->bLinkPass == TRUE) && + (memcmp(pMgmt->abyDesireBSSID, pMgmt->abyCurrBSSID, 6)== 0)){ + return rc; + } + //mike :add + if ((IS_BROADCAST_ADDRESS(pMgmt->abyDesireBSSID)) || + (memcmp(pMgmt->abyDesireBSSID, ZeroBSSID, 6) == 0)){ + printk("SIOCSIWAP:invalid desired BSSID return!\n"); + return rc; + } + //mike add: if desired AP is hidden ssid(there are two same BSSID in list), + // then ignore,because you don't known which one to be connect with?? + { + UINT ii , uSameBssidNum=0; + for (ii = 0; ii < MAX_BSS_NUM; ii++) { + if (pMgmt->sBSSList[ii].bActive && + IS_ETH_ADDRESS_EQUAL(pMgmt->sBSSList[ii].abyBSSID,pMgmt->abyDesireBSSID)) { + uSameBssidNum++; + } + } + if(uSameBssidNum >= 2) { //hit: desired AP is in hidden ssid mode!!! + printk("SIOCSIWAP:ignore for desired AP in hidden mode\n"); + return rc; + } + } + if (pDevice->flags & DEVICE_FLAGS_OPENED) { + pDevice->bCommit = TRUE; + } + } + return rc; +} + +/* + * Wireless Handler : get ap mac address + */ + +int iwctl_giwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *wrq, + char *extra) +{ + PSDevice pDevice = (PSDevice)netdev_priv(dev); + PSMgmtObject pMgmt = &(pDevice->sMgmtObj); + + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWAP \n"); + + memcpy(wrq->sa_data, pMgmt->abyCurrBSSID, 6); + //2008-0410, by Einsn Liu + if ((pDevice->bLinkPass == FALSE) && (pMgmt->eCurrMode != WMAC_MODE_ESS_AP)) + memset(wrq->sa_data, 0, 6); + + if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) { + memcpy(wrq->sa_data, pMgmt->abyCurrBSSID, 6); + } + + wrq->sa_family = ARPHRD_ETHER; + + return 0; + +} + + +/* + * Wireless Handler : get ap list + */ + +int iwctl_giwaplist(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *wrq, + char *extra) +{ + int ii,jj, rc = 0; + struct sockaddr sock[IW_MAX_AP]; + struct iw_quality qual[IW_MAX_AP]; + PSDevice pDevice = (PSDevice)netdev_priv(dev); + PSMgmtObject pMgmt = &(pDevice->sMgmtObj); + + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWAPLIST \n"); + // Only super-user can see AP list + + if (!capable(CAP_NET_ADMIN)) { + rc = -EPERM; + return rc; + } + + if (wrq->pointer) { + + PKnownBSS pBSS = &(pMgmt->sBSSList[0]); + + for (ii = 0, jj= 0; ii < MAX_BSS_NUM; ii++) { + pBSS = &(pMgmt->sBSSList[ii]); + if (!pBSS->bActive) + continue; + if ( jj >= IW_MAX_AP) + break; + memcpy(sock[jj].sa_data, pBSS->abyBSSID, 6); + sock[jj].sa_family = ARPHRD_ETHER; + qual[jj].level = pBSS->uRSSI; + qual[jj].qual = qual[jj].noise = 0; + qual[jj].updated = 2; + jj++; + } + + wrq->flags = 1; // Should be define'd + wrq->length = jj; + memcpy(extra, sock, sizeof(struct sockaddr)*jj); + memcpy(extra + sizeof(struct sockaddr)*jj, qual, sizeof(struct iw_quality)*jj); + } + + return rc; +} + + +/* + * Wireless Handler : set essid + */ + +int iwctl_siwessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *wrq, + char *extra) +{ + PSDevice pDevice = (PSDevice)netdev_priv(dev); + PSMgmtObject pMgmt = &(pDevice->sMgmtObj); + PWLAN_IE_SSID pItemSSID; + //2008-0409-05, by Einsn Liu + BYTE len; + + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWESSID \n"); + pDevice->fWPA_Authened = FALSE; +if (pMgmt->eScanState == WMAC_IS_SCANNING) { + // In scanning.. + printk("SIOCSIWESSID(??)-->In scanning...\n"); + // return -EAGAIN; + } + // Check if we asked for `any' + if(wrq->flags == 0) { + // Just send an empty SSID list + // Just send an empty SSID list + memset(pMgmt->abyDesireSSID, 0, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1); + memset(pMgmt->abyDesireBSSID, 0xFF,6); + printk("set essid to 'any' \n"); + #ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT + //Unknown desired AP,so here need not associate?? + //if(pDevice->bWPASuppWextEnabled == TRUE) { + return 0; + // } + #endif + } else { + // Set the SSID + memset(pMgmt->abyDesireSSID, 0, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1); + pItemSSID = (PWLAN_IE_SSID)pMgmt->abyDesireSSID; + pItemSSID->byElementID = WLAN_EID_SSID; + memcpy(pItemSSID->abySSID, extra, wrq->length); + if (pItemSSID->abySSID[wrq->length - 1] == '\0') { + if(wrq->length>0) + pItemSSID->len = wrq->length - 1; + } + else + pItemSSID->len = wrq->length; + printk("set essid to %s \n",pItemSSID->abySSID); + //2008-0409-05, by Einsn Liu + len=(pItemSSID->len > ((PWLAN_IE_SSID)pMgmt->abyCurrSSID)->len)?pItemSSID->len:((PWLAN_IE_SSID)pMgmt->abyCurrSSID)->len; + if((pDevice->bLinkPass == TRUE) && + (memcmp(pItemSSID->abySSID,((PWLAN_IE_SSID)pMgmt->abyCurrSSID)->abySSID,len)==0)) + return 0; + + //mike:need clear desiredBSSID + if(pItemSSID->len==0) { + memset(pMgmt->abyDesireBSSID, 0xFF,6); + return 0; + } + +#ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT + //Wext wil order another command of siwap to link with desired AP, + //so here need not associate?? + if(pDevice->bWPASuppWextEnabled == TRUE) { + /*******search if in hidden ssid mode ****/ + { + PKnownBSS pCurr = NULL; + BYTE abyTmpDesireSSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1]; + UINT ii , uSameBssidNum=0; + + memset(abyTmpDesireSSID,0,sizeof(abyTmpDesireSSID)); + memcpy(abyTmpDesireSSID,pMgmt->abyDesireSSID,sizeof(abyTmpDesireSSID)); + pCurr = BSSpSearchBSSList(pDevice, + NULL, + abyTmpDesireSSID, + pMgmt->eConfigPHYMode + ); + + if (pCurr == NULL){ + printk("SIOCSIWESSID:hidden ssid site survey before associate.......\n"); + vResetCommandTimer((HANDLE) pDevice); + pMgmt->eScanType = WMAC_SCAN_ACTIVE; + bScheduleCommand((HANDLE) pDevice, WLAN_CMD_BSSID_SCAN, pMgmt->abyDesireSSID); + bScheduleCommand((HANDLE) pDevice, WLAN_CMD_SSID, pMgmt->abyDesireSSID); + } + else { //mike:to find out if that desired SSID is a hidden-ssid AP , + // by means of judging if there are two same BSSID exist in list ? + for (ii = 0; ii < MAX_BSS_NUM; ii++) { + if (pMgmt->sBSSList[ii].bActive && + IS_ETH_ADDRESS_EQUAL(pMgmt->sBSSList[ii].abyBSSID, pCurr->abyBSSID)) { + uSameBssidNum++; + } + } + if(uSameBssidNum >= 2) { //hit: desired AP is in hidden ssid mode!!! + printk("SIOCSIWESSID:hidden ssid directly associate.......\n"); + vResetCommandTimer((HANDLE) pDevice); + pMgmt->eScanType = WMAC_SCAN_PASSIVE; //this scan type,you'll submit scan result! + bScheduleCommand((HANDLE) pDevice, WLAN_CMD_BSSID_SCAN, pMgmt->abyDesireSSID); + bScheduleCommand((HANDLE) pDevice, WLAN_CMD_SSID, pMgmt->abyDesireSSID); + } + } + } + return 0; + } + #endif + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "set essid = %s \n", pItemSSID->abySSID); +/* + #if WIRELESS_EXT < 21 + DEVICE_PRT(MSG_LEVEL_INFO, KERN_INFO " SIOCSIWESSID1 \n"); + pItemSSID->len = wrq->length - 1; + #else + DEVICE_PRT(MSG_LEVEL_INFO, KERN_INFO " SIOCSIWESSID2 \n"); + pItemSSID->len = wrq->length; + #endif + */ + } + + if (pDevice->flags & DEVICE_FLAGS_OPENED) { + pDevice->bCommit = TRUE; + } + + + return 0; +} + + +/* + * Wireless Handler : get essid + */ + +int iwctl_giwessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *wrq, + char *extra) +{ + + PSDevice pDevice = (PSDevice)netdev_priv(dev); + PSMgmtObject pMgmt = &(pDevice->sMgmtObj); + PWLAN_IE_SSID pItemSSID; + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWESSID \n"); + + // Note : if wrq->u.data.flags != 0, we should + // get the relevant SSID from the SSID list... + + // Get the current SSID + pItemSSID = (PWLAN_IE_SSID)pMgmt->abyCurrSSID; + //pItemSSID = (PWLAN_IE_SSID)pMgmt->abyDesireSSID; + memcpy(extra, pItemSSID->abySSID , pItemSSID->len); + extra[pItemSSID->len] = '\0'; + wrq->length = pItemSSID->len + 1; + //2008-0409-03, by Einsn Liu + #if WIRELESS_EXT < 21 + wrq->length = pItemSSID->len + 1; + #else + wrq->length = pItemSSID->len; + #endif + wrq->flags = 1; // active + + + return 0; +} + +/* + * Wireless Handler : set data rate + */ + +int iwctl_siwrate(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *wrq, + char *extra) +{ + PSDevice pDevice = (PSDevice)netdev_priv(dev); + int rc = 0; + u8 brate = 0; + int i; + BYTE abySupportedRates[13]= {0x02, 0x04, 0x0B, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x90}; + + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWRATE \n"); + if (!(pDevice->flags & DEVICE_FLAGS_OPENED)) { + rc = -EINVAL; + return rc; + } + + // First : get a valid bit rate value + + // Which type of value + if((wrq->value < 13) && + (wrq->value >= 0)) { + // Setting by rate index + // Find value in the magic rate table + brate = wrq->value; + } else { + // Setting by frequency value + u8 normvalue = (u8) (wrq->value/500000); + + // Check if rate is valid + for(i = 0 ; i < 13 ; i++) { + if(normvalue == abySupportedRates[i]) { + brate = i; + break; + } + } + } + // -1 designed the max rate (mostly auto mode) + if(wrq->value == -1) { + // Get the highest available rate + for(i = 0 ; i < 13 ; i++) { + if(abySupportedRates[i] == 0) + break; + } + if(i != 0) + brate = i - 1; + + } + // Check that it is valid + // brate is index of abySupportedRates[] + if(brate > 13 ) { + rc = -EINVAL; + return rc; + } + + // Now, check if we want a fixed or auto value + if(wrq->fixed != 0) { + // Fixed mode + // One rate, fixed + printk("Rate Fix\n"); + pDevice->bFixRate = TRUE; + if ((pDevice->byBBType == BB_TYPE_11B)&& (brate > 3)) { + + pDevice->uConnectionRate = 3; + } + else { + pDevice->uConnectionRate = brate; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Fixed to Rate %d \n", pDevice->uConnectionRate); + } + + } + else { + pDevice->bFixRate = FALSE; + pDevice->uConnectionRate = 13; + printk("auto rate:connection_rate is 13\n"); +} + + return rc; +} + +/* + * Wireless Handler : get data rate + */ + +int iwctl_giwrate(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *wrq, + char *extra) +{ + PSDevice pDevice = (PSDevice)netdev_priv(dev); +//2007-0118-05, by EinsnLiu +//Mark the unnecessary sentences. +// PSMgmtObject pMgmt = &(pDevice->sMgmtObj); + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWRATE \n"); + { + BYTE abySupportedRates[13]= {0x02, 0x04, 0x0B, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x90}; + int brate = 0; +//2008-5-8 by chester +if(pDevice->bLinkPass){ +if(pDevice->bFixRate == TRUE){ + if (pDevice->uConnectionRate < 13) { + brate = abySupportedRates[pDevice->uConnectionRate]; + }else { + if (pDevice->byBBType == BB_TYPE_11B) + brate = 0x16; + if (pDevice->byBBType == BB_TYPE_11G) + brate = 0x6C; + if (pDevice->byBBType == BB_TYPE_11A) + brate = 0x6C; + } +} +else +{ + + brate = abySupportedRates[TxRate_iwconfig]; +} +} +else brate =0; +//2007-0118-05, by EinsnLiu +//Mark the unnecessary sentences. +/* + if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) { + if (pDevice->byBBType == BB_TYPE_11B) + brate = 0x16; + if (pDevice->byBBType == BB_TYPE_11G) + brate = 0x6C; + if (pDevice->byBBType == BB_TYPE_11A) + brate = 0x6C; + } +*/ + +// if (pDevice->uConnectionRate == 13) +// brate = abySupportedRates[pDevice->wCurrentRate]; + wrq->value = brate * 500000; + // If more than one rate, set auto + if (pDevice->bFixRate == TRUE) + wrq->fixed = TRUE; + } + + + return 0; +} + + + +/* + * Wireless Handler : set rts threshold + */ + +int iwctl_siwrts(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *wrq, + char *extra) +{ + PSDevice pDevice = (PSDevice)netdev_priv(dev); + int rc = 0; + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWRTS \n"); + + { + int rthr = wrq->value; + if(wrq->disabled) + rthr = 2312; + if((rthr < 0) || (rthr > 2312)) { + rc = -EINVAL; + }else { + pDevice->wRTSThreshold = rthr; + } + } + + return 0; +} + +/* + * Wireless Handler : get rts + */ + +int iwctl_giwrts(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *wrq, + char *extra) +{ + PSDevice pDevice = (PSDevice)netdev_priv(dev); + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWRTS \n"); + wrq->value = pDevice->wRTSThreshold; + wrq->disabled = (wrq->value >= 2312); + wrq->fixed = 1; + + return 0; +} + +/* + * Wireless Handler : set fragment threshold + */ + +int iwctl_siwfrag(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *wrq, + char *extra) +{ + PSDevice pDevice = (PSDevice)netdev_priv(dev); + int rc = 0; + int fthr = wrq->value; + + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWFRAG \n"); + + + if (wrq->disabled) + fthr = 2312; + if((fthr < 256) || (fthr > 2312)) { + rc = -EINVAL; + }else { + fthr &= ~0x1; // Get an even value + pDevice->wFragmentationThreshold = (u16)fthr; + } + + return rc; +} + +/* + * Wireless Handler : get fragment threshold + */ + +int iwctl_giwfrag(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *wrq, + char *extra) +{ + PSDevice pDevice = (PSDevice)netdev_priv(dev); + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWFRAG \n"); + wrq->value = pDevice->wFragmentationThreshold; + wrq->disabled = (wrq->value >= 2312); + wrq->fixed = 1; + + return 0; +} + + + +/* + * Wireless Handler : set retry threshold + */ +int iwctl_siwretry(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *wrq, + char *extra) +{ + PSDevice pDevice = (PSDevice)netdev_priv(dev); + int rc = 0; + + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWRETRY \n"); + + if (wrq->disabled) { + rc = -EINVAL; + return rc; + } + + if (wrq->flags & IW_RETRY_LIMIT) { + if(wrq->flags & IW_RETRY_MAX) + pDevice->byLongRetryLimit = wrq->value; + else if (wrq->flags & IW_RETRY_MIN) + pDevice->byShortRetryLimit = wrq->value; + else { + // No modifier : set both + pDevice->byShortRetryLimit = wrq->value; + pDevice->byLongRetryLimit = wrq->value; + } + } + if (wrq->flags & IW_RETRY_LIFETIME) { + pDevice->wMaxTransmitMSDULifetime = wrq->value; + } + + + return rc; +} + +/* + * Wireless Handler : get retry threshold + */ +int iwctl_giwretry(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *wrq, + char *extra) +{ + PSDevice pDevice = (PSDevice)netdev_priv(dev); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWRETRY \n"); + wrq->disabled = 0; // Can't be disabled + + // Note : by default, display the min retry number + if((wrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) { + wrq->flags = IW_RETRY_LIFETIME; + wrq->value = (int)pDevice->wMaxTransmitMSDULifetime; //ms + } else if((wrq->flags & IW_RETRY_MAX)) { + wrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX; + wrq->value = (int)pDevice->byLongRetryLimit; + } else { + wrq->flags = IW_RETRY_LIMIT; + wrq->value = (int)pDevice->byShortRetryLimit; + if((int)pDevice->byShortRetryLimit != (int)pDevice->byLongRetryLimit) + wrq->flags |= IW_RETRY_MIN; + } + + + return 0; +} + + +/* + * Wireless Handler : set encode mode + */ +int iwctl_siwencode(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *wrq, + char *extra) +{ + PSDevice pDevice = (PSDevice)netdev_priv(dev); + PSMgmtObject pMgmt = &(pDevice->sMgmtObj); + DWORD dwKeyIndex = (DWORD)(wrq->flags & IW_ENCODE_INDEX); + int ii,uu, rc = 0; + int index = (wrq->flags & IW_ENCODE_INDEX); + +//2007-0207-07, by EinsnLiu +//There are some problems when using iwconfig encode/key command to set the WEP key. +//I almost rewrite this function. +//now it support:(assume the wireless interface's name is eth0) +//iwconfig eth0 key [1] 1122334455 open /*set key stirng to index 1,and driver using key index is set to 1*/ +//iwconfig eth0 key [3] /*set driver using key index to 3,the key string no change */ +//iwconfig eth0 key 1122334455 /*set key string to driver using index*/ +//iwconfig eth0 key restricted /*enable share key*/ + + PSKeyTable pkeytab; + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWENCODE \n"); + +if((wrq->flags & IW_ENCODE_DISABLED)==0){ + //Not disable encryption + + if (dwKeyIndex > WLAN_WEP_NKEYS) { + rc = -EINVAL; + return rc; + } + + if(dwKeyIndex<1&&((wrq->flags&IW_ENCODE_NOKEY)==0)){//set default key + if(pDevice->byKeyIndexbyKeyIndex; + } + else dwKeyIndex=0; + }else dwKeyIndex--; + + + // Check the size of the key + if (wrq->length > WLAN_WEP232_KEYLEN) { + rc = -EINVAL; + return rc; + } + + if(wrq->length>0){//have key + + if (wrq->length == WLAN_WEP232_KEYLEN) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Set 232 bit wep key\n"); + } + else if (wrq->length == WLAN_WEP104_KEYLEN) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Set 104 bit wep key\n"); + } + else if (wrq->length == WLAN_WEP40_KEYLEN) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Set 40 bit wep key, index= %d\n", (int)dwKeyIndex); + }else {//no support length + rc = -EINVAL; + return rc; + } + memset(pDevice->abyKey, 0, WLAN_WEP232_KEYLEN); + memcpy(pDevice->abyKey, extra, wrq->length); + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"abyKey: "); + for (ii = 0; ii < wrq->length; ii++) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%02x ", pDevice->abyKey[ii]); + } + + if (pDevice->flags & DEVICE_FLAGS_OPENED) { + spin_lock_irq(&pDevice->lock); + KeybSetDefaultKey(&(pDevice->sKey), + (DWORD)(dwKeyIndex | (1 << 31)), + wrq->length, + NULL, + pDevice->abyKey, + KEY_CTL_WEP, + pDevice->PortOffset, + pDevice->byLocalID + ); + spin_unlock_irq(&pDevice->lock); + } + pDevice->byKeyIndex = (BYTE)dwKeyIndex; + pDevice->uKeyLength = wrq->length; + pDevice->bTransmitKey = TRUE; + pDevice->bEncryptionEnable = TRUE; + pDevice->eEncryptionStatus = Ndis802_11Encryption1Enabled; + + }else if(index>0){ + //when the length is 0 the request only changes the default transmit key index + //check the new key has a non zero lenget + if(pDevice->bEncryptionEnable==FALSE) + { + rc = -EINVAL; + return rc; + } + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Just set Default key Index:\n"); + pkeytab=&(pDevice->sKey.KeyTable[MAX_KEY_TABLE-1]); + if(pkeytab->GroupKey[(BYTE)dwKeyIndex].uKeyLength==0){ + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Default key len is 0\n"); + rc = -EINVAL; + return rc; + } + pDevice->byKeyIndex =(BYTE)dwKeyIndex; + pkeytab->dwGTKeyIndex =dwKeyIndex | (1 << 31); + pkeytab->GroupKey[(BYTE)dwKeyIndex].dwKeyIndex=dwKeyIndex | (1 << 31); + } + +}else {//disable the key + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Disable WEP function\n"); + if(pDevice->bEncryptionEnable==FALSE) + return 0; + pMgmt->bShareKeyAlgorithm = FALSE; + pDevice->bEncryptionEnable = FALSE; + pDevice->eEncryptionStatus = Ndis802_11EncryptionDisabled; + if (pDevice->flags & DEVICE_FLAGS_OPENED) { + spin_lock_irq(&pDevice->lock); + for(uu=0;uuPortOffset, uu); + spin_unlock_irq(&pDevice->lock); + } +} +//End Modify,Einsn + +/* + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWENCODE \n"); + + // Check the size of the key + if (wrq->length > WLAN_WEP232_KEYLEN) { + rc = -EINVAL; + return rc; + } + + if (dwKeyIndex > WLAN_WEP_NKEYS) { + rc = -EINVAL; + return rc; + } + + if (dwKeyIndex > 0) + dwKeyIndex--; + + // Send the key to the card + if (wrq->length > 0) { + + if (wrq->length == WLAN_WEP232_KEYLEN) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Set 232 bit wep key\n"); + } + else if (wrq->length == WLAN_WEP104_KEYLEN) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Set 104 bit wep key\n"); + } + else if (wrq->length == WLAN_WEP40_KEYLEN) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Set 40 bit wep key, index= %d\n", (int)dwKeyIndex); + } + memset(pDevice->abyKey, 0, WLAN_WEP232_KEYLEN); + memcpy(pDevice->abyKey, extra, wrq->length); + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"abyKey: "); + for (ii = 0; ii < wrq->length; ii++) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%02x ", pDevice->abyKey[ii]); + } + + if (pDevice->flags & DEVICE_FLAGS_OPENED) { + spin_lock_irq(&pDevice->lock); + KeybSetDefaultKey(&(pDevice->sKey), + (DWORD)(pDevice->byKeyIndex | (1 << 31)), + pDevice->uKeyLength, + NULL, + pDevice->abyKey, + KEY_CTL_WEP, + pDevice->PortOffset, + pDevice->byLocalID + ); + spin_unlock_irq(&pDevice->lock); + } + pDevice->byKeyIndex = (BYTE)dwKeyIndex; + pDevice->uKeyLength = wrq->length; + pDevice->bTransmitKey = TRUE; + pDevice->bEncryptionEnable = TRUE; + pDevice->eEncryptionStatus = Ndis802_11Encryption1Enabled; + + // Do we want to just set the transmit key index ? + if ( index < 4 ) { + pDevice->byKeyIndex = index; + } + else if(!wrq->flags & IW_ENCODE_MODE) { + rc = -EINVAL; + return rc; + } + } + // Read the flags + if(wrq->flags & IW_ENCODE_DISABLED){ + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Disable WEP function\n"); + pMgmt->bShareKeyAlgorithm = FALSE; + pDevice->bEncryptionEnable = FALSE; + pDevice->eEncryptionStatus = Ndis802_11EncryptionDisabled; + if (pDevice->flags & DEVICE_FLAGS_OPENED) { + spin_lock_irq(&pDevice->lock); + for(uu=0;uuPortOffset, uu); + spin_unlock_irq(&pDevice->lock); + } + } +*/ + + if(wrq->flags & IW_ENCODE_RESTRICTED) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Enable WEP & ShareKey System\n"); + pMgmt->bShareKeyAlgorithm = TRUE; + } + if(wrq->flags & IW_ENCODE_OPEN) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Enable WEP & Open System\n"); + pMgmt->bShareKeyAlgorithm = FALSE; + } + return rc; +} + +/* + * Wireless Handler : get encode mode + */ + /* +int iwctl_giwencode(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *wrq, + char *extra) +{ + PSDevice pDevice = (PSDevice)netdev_priv(dev); + PSMgmtObject pMgmt = &(pDevice->sMgmtObj); + int rc = 0; + char abyKey[WLAN_WEP232_KEYLEN]; + UINT index = (UINT)(wrq->flags & IW_ENCODE_INDEX); + PSKeyItem pKey = NULL; + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWENCODE\n"); +//2007-0207-06, by EinsnLiu +//the key index in iwconfig is 1-4 when our driver is 0-3 +//so it can't be used directly. +//if the index is 0,we should used the index set by driver. + if (index > WLAN_WEP_NKEYS) { + rc = -EINVAL; + return rc; + } + if(index<1){//set default key + if(pDevice->byKeyIndexbyKeyIndex; + } + else index=0; + }else index--; +//End Add,Einsn + + memset(abyKey, 0, sizeof(abyKey)); + // Check encryption mode + wrq->flags = IW_ENCODE_NOKEY; + // Is WEP enabled ??? + if (pDevice->bEncryptionEnable) + wrq->flags |= IW_ENCODE_ENABLED; + else + wrq->flags |= IW_ENCODE_DISABLED; + + if (pMgmt->bShareKeyAlgorithm) + wrq->flags |= IW_ENCODE_RESTRICTED; + else + wrq->flags |= IW_ENCODE_OPEN; + + if (KeybGetKey(&(pDevice->sKey), pDevice->abyBroadcastAddr, (BYTE)index , &pKey)){ + wrq->length = pKey->uKeyLength; + memcpy(abyKey, pKey->abyKey, pKey->uKeyLength); +//2007-0207-06, by EinsnLiu +//only get key success need to copy data +//index should +1. +//there is not necessary to return -EINVAL when get key failed +//if return -EINVAL,the encryption item can't be display by the command "iwconfig". + wrq->flags |= index+1; + memcpy(extra, abyKey, WLAN_WEP232_KEYLEN); + } + + //else { + // rc = -EINVAL; + // return rc; + // } + + +//End Modify,Einsn + + return 0; +} +*/ + +//2008-0409-06, by Einsn Liu + +int iwctl_giwencode(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *wrq, + char *extra) +{ + PSDevice pDevice = (PSDevice)netdev_priv(dev); + PSMgmtObject pMgmt = &(pDevice->sMgmtObj); + char abyKey[WLAN_WEP232_KEYLEN]; + + UINT index = (UINT)(wrq->flags & IW_ENCODE_INDEX); + PSKeyItem pKey = NULL; + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWENCODE\n"); + + if (index > WLAN_WEP_NKEYS) { + return -EINVAL; + } + if(index<1){//get default key + if(pDevice->byKeyIndexbyKeyIndex; + } else + index=0; + }else + index--; + + memset(abyKey, 0, WLAN_WEP232_KEYLEN); + // Check encryption mode + wrq->flags = IW_ENCODE_NOKEY; + // Is WEP enabled ??? + if (pDevice->bEncryptionEnable) + wrq->flags |= IW_ENCODE_ENABLED; + else + wrq->flags |= IW_ENCODE_DISABLED; + + if (pMgmt->bShareKeyAlgorithm) + wrq->flags |= IW_ENCODE_RESTRICTED; + else + wrq->flags |= IW_ENCODE_OPEN; + wrq->length=0; + + if((index==0)&&(pDevice->eEncryptionStatus == Ndis802_11Encryption2Enabled|| + pDevice->eEncryptionStatus == Ndis802_11Encryption3Enabled)){//get wpa pairwise key + if (KeybGetKey(&(pDevice->sKey),pMgmt->abyCurrBSSID, 0xffffffff, &pKey)){ + wrq->length = pKey->uKeyLength; + memcpy(abyKey, pKey->abyKey, pKey->uKeyLength); + memcpy(extra, abyKey, WLAN_WEP232_KEYLEN); + } + }else if (KeybGetKey(&(pDevice->sKey), pDevice->abyBroadcastAddr, (BYTE)index , &pKey)){ + wrq->length = pKey->uKeyLength; + memcpy(abyKey, pKey->abyKey, pKey->uKeyLength); + memcpy(extra, abyKey, WLAN_WEP232_KEYLEN); + } + + wrq->flags |= index+1; + + return 0; +} + +/* + * Wireless Handler : set power mode + */ +int iwctl_siwpower(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *wrq, + char *extra) +{ + PSDevice pDevice = (PSDevice)netdev_priv(dev); + PSMgmtObject pMgmt = &(pDevice->sMgmtObj); + int rc = 0; + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWPOWER \n"); + + if (!(pDevice->flags & DEVICE_FLAGS_OPENED)) { + rc = -EINVAL; + return rc; + } + + if (wrq->disabled) { + pDevice->ePSMode = WMAC_POWER_CAM; + PSvDisablePowerSaving(pDevice); + return rc; + } + if ((wrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { + pDevice->ePSMode = WMAC_POWER_FAST; + PSvEnablePowerSaving((HANDLE)pDevice, pMgmt->wListenInterval); + + } else if ((wrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) { + pDevice->ePSMode = WMAC_POWER_FAST; + PSvEnablePowerSaving((HANDLE)pDevice, pMgmt->wListenInterval); + } + switch (wrq->flags & IW_POWER_MODE) { + case IW_POWER_UNICAST_R: + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWPOWER: IW_POWER_UNICAST_R \n"); + rc = -EINVAL; + break; + case IW_POWER_ALL_R: + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWPOWER: IW_POWER_ALL_R \n"); + rc = -EINVAL; + case IW_POWER_ON: + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWPOWER: IW_POWER_ON \n"); + break; + default: + rc = -EINVAL; + } + + return rc; +} + +/* + * Wireless Handler : get power mode + */ +int iwctl_giwpower(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *wrq, + char *extra) +{ + PSDevice pDevice = (PSDevice)netdev_priv(dev); + PSMgmtObject pMgmt = &(pDevice->sMgmtObj); + int mode = pDevice->ePSMode; + + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWPOWER \n"); + + + if ((wrq->disabled = (mode == WMAC_POWER_CAM))) + return 0; + + if ((wrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { + wrq->value = (int)((pMgmt->wListenInterval * pMgmt->wCurrBeaconPeriod) << 10); + wrq->flags = IW_POWER_TIMEOUT; + } else { + wrq->value = (int)((pMgmt->wListenInterval * pMgmt->wCurrBeaconPeriod) << 10); + wrq->flags = IW_POWER_PERIOD; + } + wrq->flags |= IW_POWER_ALL_R; + + return 0; +} + + +/* + * Wireless Handler : get Sensitivity + */ +int iwctl_giwsens(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *wrq, + char *extra) +{ + PSDevice pDevice = (PSDevice)netdev_priv(dev); + long ldBm; + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWSENS \n"); + if (pDevice->bLinkPass == TRUE) { + RFvRSSITodBm(pDevice, (BYTE)(pDevice->uCurrRSSI), &ldBm); + wrq->value = ldBm; + } + else { + wrq->value = 0; + }; + wrq->disabled = (wrq->value == 0); + wrq->fixed = 1; + + + return 0; +} + +//2008-0409-07, by Einsn Liu +#ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT + +int iwctl_siwauth(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *wrq, + char *extra) +{ + PSDevice pDevice = (PSDevice)netdev_priv(dev); + PSMgmtObject pMgmt = &(pDevice->sMgmtObj); + int ret=0; + static int wpa_version=0; //must be static to save the last value,einsn liu + static int pairwise=0; + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWAUTH \n"); + switch (wrq->flags & IW_AUTH_INDEX) { + case IW_AUTH_WPA_VERSION: + wpa_version = wrq->value; + if(wrq->value == IW_AUTH_WPA_VERSION_DISABLED) { + printk("iwctl_siwauth:set WPADEV to disable at 1??????\n"); + //pDevice->bWPADevEnable = FALSE; + } + else if(wrq->value == IW_AUTH_WPA_VERSION_WPA) { + printk("iwctl_siwauth:set WPADEV to WPA1******\n"); + } + else { + printk("iwctl_siwauth:set WPADEV to WPA2******\n"); + } + //pDevice->bWPASuppWextEnabled =TRUE; + break; + case IW_AUTH_CIPHER_PAIRWISE: + pairwise = wrq->value; + + if(pairwise == IW_AUTH_CIPHER_CCMP){ + pDevice->eEncryptionStatus = Ndis802_11Encryption3Enabled; + }else if(pairwise == IW_AUTH_CIPHER_TKIP){ + pDevice->eEncryptionStatus = Ndis802_11Encryption2Enabled; + }else if(pairwise == IW_AUTH_CIPHER_WEP40||pairwise == IW_AUTH_CIPHER_WEP104){ + pDevice->eEncryptionStatus = Ndis802_11Encryption1Enabled; + }else if(pairwise == IW_AUTH_CIPHER_NONE){ + //do nothing,einsn liu + }else pDevice->eEncryptionStatus = Ndis802_11EncryptionDisabled; + + break; + case IW_AUTH_CIPHER_GROUP: + if(wpa_version == IW_AUTH_WPA_VERSION_DISABLED) + break; + if(pairwise == IW_AUTH_CIPHER_NONE){ + if(wrq->value == IW_AUTH_CIPHER_CCMP){ + pDevice->eEncryptionStatus = Ndis802_11Encryption3Enabled; + }else { + pDevice->eEncryptionStatus = Ndis802_11Encryption2Enabled; + } + } + break; + case IW_AUTH_KEY_MGMT: + + if(wpa_version == IW_AUTH_WPA_VERSION_WPA2){ + if(wrq->value == IW_AUTH_KEY_MGMT_PSK) + pMgmt->eAuthenMode = WMAC_AUTH_WPA2PSK; + else pMgmt->eAuthenMode = WMAC_AUTH_WPA2; + }else if(wpa_version == IW_AUTH_WPA_VERSION_WPA){ + if(wrq->value == 0){ + pMgmt->eAuthenMode = WMAC_AUTH_WPANONE; + }else if(wrq->value == IW_AUTH_KEY_MGMT_PSK) + pMgmt->eAuthenMode = WMAC_AUTH_WPAPSK; + else pMgmt->eAuthenMode = WMAC_AUTH_WPA; + } + + break; + case IW_AUTH_TKIP_COUNTERMEASURES: + break; /* FIXME */ + case IW_AUTH_DROP_UNENCRYPTED: + break; + case IW_AUTH_80211_AUTH_ALG: + if(wrq->value==IW_AUTH_ALG_OPEN_SYSTEM){ + pMgmt->bShareKeyAlgorithm=FALSE; + }else if(wrq->value==IW_AUTH_ALG_SHARED_KEY){ + pMgmt->bShareKeyAlgorithm=TRUE; + } + break; + case IW_AUTH_WPA_ENABLED: + //pDevice->bWPADevEnable = !! wrq->value; + break; + case IW_AUTH_RX_UNENCRYPTED_EAPOL: + break; + case IW_AUTH_ROAMING_CONTROL: + ret = -EOPNOTSUPP; + break; + case IW_AUTH_PRIVACY_INVOKED: + pDevice->bEncryptionEnable = !!wrq->value; + if(pDevice->bEncryptionEnable == FALSE){ + wpa_version = 0; + pairwise = 0; + pDevice->eEncryptionStatus = Ndis802_11EncryptionDisabled; + pMgmt->bShareKeyAlgorithm = FALSE; + pMgmt->eAuthenMode = FALSE; + //pDevice->bWPADevEnable = FALSE; + } + + break; + default: + ret = -EOPNOTSUPP; + break; + } +/* + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "wpa_version = %d\n",wpa_version); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pairwise = %d\n",pairwise); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pDevice->eEncryptionStatus = %d\n",pDevice->eEncryptionStatus); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pMgmt->eAuthenMode = %d\n",pMgmt->eAuthenMode); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pMgmt->bShareKeyAlgorithm = %s\n",pMgmt->bShareKeyAlgorithm?"TRUE":"FALSE"); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pDevice->bEncryptionEnable = %s\n",pDevice->bEncryptionEnable?"TRUE":"FALSE"); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pDevice->bWPADevEnable = %s\n",pDevice->bWPADevEnable?"TRUE":"FALSE"); +*/ + return ret; +} + + +int iwctl_giwauth(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *wrq, + char *extra) +{ + return -EOPNOTSUPP; +} + + + +int iwctl_siwgenie(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *wrq, + char *extra) +{ + PSDevice pDevice = (PSDevice)netdev_priv(dev); + PSMgmtObject pMgmt = &(pDevice->sMgmtObj); + int ret=0; + + if(wrq->length){ + if ((wrq->length < 2) || (extra[1]+2 != wrq->length)) { + ret = -EINVAL; + goto out; + } + if(wrq->length > MAX_WPA_IE_LEN){ + ret = -ENOMEM; + goto out; + } + memset(pMgmt->abyWPAIE, 0, MAX_WPA_IE_LEN); + if(copy_from_user(pMgmt->abyWPAIE, extra, wrq->length)){ + ret = -EFAULT; + goto out; + } + pMgmt->wWPAIELen = wrq->length; + }else { + memset(pMgmt->abyWPAIE, 0, MAX_WPA_IE_LEN); + pMgmt->wWPAIELen = 0; + } + + out://not completely ...not necessary in wpa_supplicant 0.5.8 + return 0; +} + +int iwctl_giwgenie(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *wrq, + char *extra) +{ + PSDevice pDevice = (PSDevice)netdev_priv(dev); + PSMgmtObject pMgmt = &(pDevice->sMgmtObj); + int ret=0; + int space = wrq->length; + + wrq->length = 0; + if(pMgmt->wWPAIELen > 0){ + wrq->length = pMgmt->wWPAIELen; + if(pMgmt->wWPAIELen <= space){ + if(copy_to_user(extra, pMgmt->abyWPAIE, pMgmt->wWPAIELen)){ + ret = -EFAULT; + } + }else + ret = -E2BIG; + } + + return ret; +} + + +int iwctl_siwencodeext(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *wrq, + char *extra) +{ + PSDevice pDevice = (PSDevice)netdev_priv(dev); + struct iw_encode_ext *ext = (struct iw_encode_ext*)extra; + struct viawget_wpa_param *param=NULL; +//original member + wpa_alg alg_name; + u8 addr[6]; + int key_idx, set_tx; + u8 seq[IW_ENCODE_SEQ_MAX_SIZE]; + u8 key[64]; + size_t seq_len,key_len=0; +// + // int ii; + u8 *buf; + size_t blen; + u8 key_array[64]; + int ret=0; + +printk("SIOCSIWENCODEEXT...... \n"); + +blen = sizeof(*param); +buf = kmalloc((int)blen, (int)GFP_KERNEL); +if (buf == NULL) + return -ENOMEM; +memset(buf, 0, blen); +param = (struct viawget_wpa_param *) buf; + +//recover alg_name +switch (ext->alg) { + case IW_ENCODE_ALG_NONE: + alg_name = WPA_ALG_NONE; + break; + case IW_ENCODE_ALG_WEP: + alg_name = WPA_ALG_WEP; + break; + case IW_ENCODE_ALG_TKIP: + alg_name = WPA_ALG_TKIP; + break; + case IW_ENCODE_ALG_CCMP: + alg_name = WPA_ALG_CCMP; + break; + default: + printk("Unknown alg = %d\n",ext->alg); + ret= -ENOMEM; + goto error; + } +//recover addr + memcpy(addr, ext->addr.sa_data, ETH_ALEN); +//recover key_idx + key_idx = (wrq->flags&IW_ENCODE_INDEX) - 1; +//recover set_tx +if(ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) + set_tx = 1; +//recover seq,seq_len + if(ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) { + seq_len=IW_ENCODE_SEQ_MAX_SIZE; + memcpy(seq, ext->rx_seq, seq_len); + } +//recover key,key_len +if(ext->key_len) { + key_len=ext->key_len; + memcpy(key, &ext->key[0], key_len); + } + +memset(key_array, 0, 64); +if ( key_len > 0) { + memcpy(key_array, key, key_len); + if (key_len == 32) { + // notice ! the oder + memcpy(&key_array[16], &key[24], 8); + memcpy(&key_array[24], &key[16], 8); + } + } + +/**************Translate iw_encode_ext to viawget_wpa_param****************/ +memcpy(param->addr, addr, ETH_ALEN); +param->u.wpa_key.alg_name = (int)alg_name; +param->u.wpa_key.set_tx = set_tx; +param->u.wpa_key.key_index = key_idx; +param->u.wpa_key.key_len = key_len; +param->u.wpa_key.key = (u8 *)key_array; +param->u.wpa_key.seq = (u8 *)seq; +param->u.wpa_key.seq_len = seq_len; + +#if 0 +int ii; +printk("param->u.wpa_key.alg_name =%d\n",param->u.wpa_key.alg_name); +printk("param->addr=%02x:%02x:%02x:%02x:%02x:%02x\n", + param->addr[0],param->addr[1],param->addr[2], + param->addr[3],param->addr[4],param->addr[5]); +printk("param->u.wpa_key.set_tx =%d\n",param->u.wpa_key.set_tx); +printk("param->u.wpa_key.key_index =%d\n",param->u.wpa_key.key_index); +printk("param->u.wpa_key.key_len =%d\n",param->u.wpa_key.key_len); +printk("param->u.wpa_key.key ="); +for(ii=0;iiu.wpa_key.key_len;ii++) + printk("%02x:",param->u.wpa_key.key[ii]); + printk("\n"); +printk("param->u.wpa_key.seq_len =%d\n",param->u.wpa_key.seq_len); +printk("param->u.wpa_key.seq ="); +for(ii=0;iiu.wpa_key.seq_len;ii++) + printk("%02x:",param->u.wpa_key.seq[ii]); + printk("\n"); + +printk("...........\n"); +#endif +//****set if current action is Network Manager count?? +//****this method is so foolish,but there is no other way??? +if(param->u.wpa_key.alg_name == WPA_ALG_NONE) { + if(param->u.wpa_key.key_index ==0) { + pDevice->bwextcount++; + } + if((pDevice->bwextcount == 1)&&(param->u.wpa_key.key_index ==1)) { + pDevice->bwextcount++; + } + if((pDevice->bwextcount ==2)&&(param->u.wpa_key.key_index ==2)) { + pDevice->bwextcount++; + } + if((pDevice->bwextcount ==3)&&(param->u.wpa_key.key_index ==3)) { + pDevice->bwextcount++; + } + } +if( pDevice->bwextcount == 4) { + printk("SIOCSIWENCODEEXT:Enable WPA WEXT SUPPORT!!!!!\n"); + pDevice->bwextcount=0; + pDevice->bWPASuppWextEnabled = TRUE; + } +//****** + + spin_lock_irq(&pDevice->lock); + ret = wpa_set_keys(pDevice, param, TRUE); + spin_unlock_irq(&pDevice->lock); + +error: +kfree(param); + return ret; +} + + + +int iwctl_giwencodeext(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *wrq, + char *extra) +{ + return -EOPNOTSUPP;; +} + +int iwctl_siwmlme(struct net_device *dev, + struct iw_request_info * info, + struct iw_point *wrq, + char *extra) +{ + PSDevice pDevice = (PSDevice)netdev_priv(dev); + PSMgmtObject pMgmt = &(pDevice->sMgmtObj); + struct iw_mlme *mlme = (struct iw_mlme *)extra; + //u16 reason = cpu_to_le16(mlme->reason_code); + int ret = 0; + + if(memcmp(pMgmt->abyCurrBSSID, mlme->addr.sa_data, ETH_ALEN)){ + ret = -EINVAL; + return ret; + } + switch(mlme->cmd){ + case IW_MLME_DEAUTH: + //this command seems to be not complete,please test it --einsnliu + //bScheduleCommand((HANDLE) pDevice, WLAN_CMD_DEAUTH, (PBYTE)&reason); + break; + case IW_MLME_DISASSOC: + if(pDevice->bLinkPass == TRUE){ + printk("iwctl_siwmlme--->send DISASSOCIATE\n"); + //clear related flags + memset(pMgmt->abyDesireBSSID, 0xFF,6); + KeyvInitTable(&pDevice->sKey, pDevice->PortOffset); + bScheduleCommand((HANDLE)pDevice, WLAN_CMD_DISASSOCIATE, NULL); + } + break; + default: + ret = -EOPNOTSUPP; + } + + return ret; + +} + +#endif + + +/*------------------------------------------------------------------*/ +/* + * Structures to export the Wireless Handlers + */ + + +#if WIRELESS_EXT > 12 + +/* +static const iw_handler iwctl_handler[] = +{ + (iw_handler) iwctl_commit, // SIOCSIWCOMMIT + (iw_handler) iwctl_giwname, // SIOCGIWNAME + (iw_handler) NULL, // SIOCSIWNWID + (iw_handler) NULL, // SIOCGIWNWID + (iw_handler) iwctl_siwfreq, // SIOCSIWFREQ + (iw_handler) iwctl_giwfreq, // SIOCGIWFREQ + (iw_handler) iwctl_siwmode, // SIOCSIWMODE + (iw_handler) iwctl_giwmode, // SIOCGIWMODE + (iw_handler) NULL, // SIOCSIWSENS + (iw_handler) iwctl_giwsens, // SIOCGIWSENS + (iw_handler) NULL, // SIOCSIWRANGE + (iw_handler) iwctl_giwrange, // SIOCGIWRANGE + (iw_handler) NULL, // SIOCSIWPRIV + (iw_handler) NULL, // SIOCGIWPRIV + (iw_handler) NULL, // SIOCSIWSTATS + (iw_handler) NULL, // SIOCGIWSTATS + (iw_handler) NULL, // SIOCSIWSPY + (iw_handler) NULL, // SIOCGIWSPY + (iw_handler) NULL, // -- hole -- + (iw_handler) NULL, // -- hole -- + (iw_handler) iwctl_siwap, // SIOCSIWAP + (iw_handler) iwctl_giwap, // SIOCGIWAP + (iw_handler) NULL, // -- hole -- 0x16 + (iw_handler) iwctl_giwaplist, // SIOCGIWAPLIST +#if WIRELESS_EXT > 13 + (iw_handler) iwctl_siwscan, // SIOCSIWSCAN + (iw_handler) iwctl_giwscan, // SIOCGIWSCAN +#else + (iw_handler) NULL, + (iw_handler) NULL, +#endif + (iw_handler) iwctl_siwessid, // SIOCSIWESSID + (iw_handler) iwctl_giwessid, // SIOCGIWESSID + (iw_handler) NULL, // SIOCSIWNICKN + (iw_handler) NULL, // SIOCGIWNICKN + (iw_handler) NULL, // -- hole -- + (iw_handler) NULL, // -- hole -- + (iw_handler) iwctl_siwrate, // SIOCSIWRATE 0x20 + (iw_handler) iwctl_giwrate, // SIOCGIWRATE + (iw_handler) iwctl_siwrts, // SIOCSIWRTS + (iw_handler) iwctl_giwrts, // SIOCGIWRTS + (iw_handler) iwctl_siwfrag, // SIOCSIWFRAG + (iw_handler) iwctl_giwfrag, // SIOCGIWFRAG + (iw_handler) NULL, // SIOCSIWTXPOW + (iw_handler) NULL, // SIOCGIWTXPOW + (iw_handler) iwctl_siwretry, // SIOCSIWRETRY + (iw_handler) iwctl_giwretry, // SIOCGIWRETRY + (iw_handler) iwctl_siwencode, // SIOCSIWENCODE + (iw_handler) iwctl_giwencode, // SIOCGIWENCODE + (iw_handler) iwctl_siwpower, // SIOCSIWPOWER + (iw_handler) iwctl_giwpower, // SIOCGIWPOWER +#if WIRELESS_EXT > 17 + (iw_handler) NULL, // -- hole -- + (iw_handler) NULL, // -- hole -- + (iw_handler) iwctl_siwgenie, // SIOCSIWGENIE + (iw_handler) iwctl_giwgenie, // SIOCGIWGENIE + (iw_handler) iwctl_siwauth, // SIOCSIWAUTH + (iw_handler) iwctl_giwauth, // SIOCGIWAUTH + (iw_handler) iwctl_siwencodeext, // SIOCSIWENCODEEXT + (iw_handler) iwctl_giwencodeext, // SIOCGIWENCODEEXT + (iw_handler) NULL, // SIOCSIWPMKSA + (iw_handler) NULL, // -- hole -- +#endif // WIRELESS_EXT > 17 + +}; +*/ + +static const iw_handler iwctl_handler[] = +{ + (iw_handler) iwctl_commit, // SIOCSIWCOMMIT + (iw_handler) NULL, // SIOCGIWNAME + (iw_handler) NULL, // SIOCSIWNWID + (iw_handler) NULL, // SIOCGIWNWID + (iw_handler) NULL, // SIOCSIWFREQ + (iw_handler) NULL, // SIOCGIWFREQ + (iw_handler) NULL, // SIOCSIWMODE + (iw_handler) NULL, // SIOCGIWMODE + (iw_handler) NULL, // SIOCSIWSENS + (iw_handler) NULL, // SIOCGIWSENS + (iw_handler) NULL, // SIOCSIWRANGE + (iw_handler) iwctl_giwrange, // SIOCGIWRANGE + (iw_handler) NULL, // SIOCSIWPRIV + (iw_handler) NULL, // SIOCGIWPRIV + (iw_handler) NULL, // SIOCSIWSTATS + (iw_handler) NULL, // SIOCGIWSTATS + (iw_handler) NULL, // SIOCSIWSPY + (iw_handler) NULL, // SIOCGIWSPY + (iw_handler) NULL, // -- hole -- + (iw_handler) NULL, // -- hole -- + (iw_handler) NULL, // SIOCSIWAP + (iw_handler) NULL, // SIOCGIWAP + (iw_handler) NULL, // -- hole -- 0x16 + (iw_handler) NULL, // SIOCGIWAPLIST +#if WIRELESS_EXT > 13 + (iw_handler) iwctl_siwscan, // SIOCSIWSCAN + (iw_handler) iwctl_giwscan, // SIOCGIWSCAN +#else + (iw_handler) NULL, + (iw_handler) NULL, +#endif + (iw_handler) NULL, // SIOCSIWESSID + (iw_handler) NULL, // SIOCGIWESSID + (iw_handler) NULL, // SIOCSIWNICKN + (iw_handler) NULL, // SIOCGIWNICKN + (iw_handler) NULL, // -- hole -- + (iw_handler) NULL, // -- hole -- + (iw_handler) NULL, // SIOCSIWRATE 0x20 + (iw_handler) NULL, // SIOCGIWRATE + (iw_handler) NULL, // SIOCSIWRTS + (iw_handler) NULL, // SIOCGIWRTS + (iw_handler) NULL, // SIOCSIWFRAG + (iw_handler) NULL, // SIOCGIWFRAG + (iw_handler) NULL, // SIOCSIWTXPOW + (iw_handler) NULL, // SIOCGIWTXPOW + (iw_handler) NULL, // SIOCSIWRETRY + (iw_handler) NULL, // SIOCGIWRETRY + (iw_handler) NULL, // SIOCSIWENCODE + (iw_handler) NULL, // SIOCGIWENCODE + (iw_handler) NULL, // SIOCSIWPOWER + (iw_handler) NULL, // SIOCGIWPOWER + +//2008-0409-07, by Einsn Liu +#if WIRELESS_EXT > 17 + (iw_handler) NULL, // -- hole -- + (iw_handler) NULL, // -- hole -- + (iw_handler) NULL, // SIOCSIWGENIE + (iw_handler) NULL, // SIOCGIWGENIE + (iw_handler) NULL, // SIOCSIWAUTH + (iw_handler) NULL, // SIOCGIWAUTH + (iw_handler) NULL, // SIOCSIWENCODEEXT + (iw_handler) NULL, // SIOCGIWENCODEEXT + (iw_handler) NULL, // SIOCSIWPMKSA + (iw_handler) NULL, // -- hole -- +#endif // WIRELESS_EXT > 17 +}; + + +static const iw_handler iwctl_private_handler[] = +{ + NULL, // SIOCIWFIRSTPRIV +}; + + +struct iw_priv_args iwctl_private_args[] = { +{ IOCTL_CMD_SET, + IW_PRIV_TYPE_CHAR | 1024, 0, + "set"}, +}; + + + +const struct iw_handler_def iwctl_handler_def = +{ +#if WIRELESS_EXT > 16 + .get_wireless_stats = &iwctl_get_wireless_stats, +#endif + .num_standard = sizeof(iwctl_handler)/sizeof(iw_handler), +// .num_private = sizeof(iwctl_private_handler)/sizeof(iw_handler), +// .num_private_args = sizeof(iwctl_private_args)/sizeof(struct iw_priv_args), + .num_private = 0, + .num_private_args = 0, + .standard = (iw_handler *) iwctl_handler, +// .private = (iw_handler *) iwctl_private_handler, +// .private_args = (struct iw_priv_args *)iwctl_private_args, + .private = NULL, + .private_args = NULL, +}; + + +#endif // WIRELESS_EXT > 12 + + +#endif // WIRELESS_EXT diff --git a/drivers/staging/vt6655/iwctl.h b/drivers/staging/vt6655/iwctl.h new file mode 100644 index 000000000000..07554e14d5f2 --- /dev/null +++ b/drivers/staging/vt6655/iwctl.h @@ -0,0 +1,332 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * File: iwctl.h + * + * Purpose: + * + * Author: Lyndon Chen + * + * Date: May 21, 2004 + * + */ + + +#ifndef __IWCTL_H__ +#define __IWCTL_H__ + +#if !defined(__DEVICE_H__) +#include "device.h" +#endif + + +/*--------------------- Export Definitions -------------------------*/ + + +/*--------------------- Export Classes ----------------------------*/ + +/*--------------------- Export Variables --------------------------*/ + +/*--------------------- Export Functions --------------------------*/ + + +#ifdef __cplusplus +extern "C" { /* Assume C declarations for C++ */ +#endif /* __cplusplus */ + + +#if WIRELESS_EXT < 18 + + +#define SIOCSIWMLME 0x8B16 +#define SIOCSIWGENIE 0x8B30 + +// WPA : Authentication mode parameters +#define SIOCSIWAUTH 0x8B32 +#define SIOCGIWAUTH 0x8B33 + +// WPA : Extended version of encoding configuration +#define SIOCSIWENCODEEXT 0x8B34 +#define SIOCGIWENCODEEXT 0x8B35 + +#define IW_AUTH_WPA_VERSION 0 +#define IW_AUTH_CIPHER_PAIRWISE 1 +#define IW_AUTH_CIPHER_GROUP 2 +#define IW_AUTH_KEY_MGMT 3 +#define IW_AUTH_TKIP_COUNTERMEASURES 4 +#define IW_AUTH_DROP_UNENCRYPTED 5 +#define IW_AUTH_80211_AUTH_ALG 6 +#define IW_AUTH_WPA_ENABLED 7 +#define IW_AUTH_RX_UNENCRYPTED_EAPOL 8 +#define IW_AUTH_ROAMING_CONTROL 9 +#define IW_AUTH_PRIVACY_INVOKED 10 + +#define IW_AUTH_WPA_VERSION_DISABLED 0x00000001 +#define IW_AUTH_WPA_VERSION_WPA 0x00000002 +#define IW_AUTH_WPA_VERSION_WPA2 0x00000004 + +#define IW_AUTH_CIPHER_NONE 0x00000001 +#define IW_AUTH_CIPHER_WEP40 0x00000002 +#define IW_AUTH_CIPHER_TKIP 0x00000004 +#define IW_AUTH_CIPHER_CCMP 0x00000008 +#define IW_AUTH_CIPHER_WEP104 0x00000010 + +#define IW_AUTH_KEY_MGMT_802_1X 1 +#define IW_AUTH_KEY_MGMT_PSK 2 + +#define IW_AUTH_ALG_OPEN_SYSTEM 0x00000001 +#define IW_AUTH_ALG_SHARED_KEY 0x00000002 +#define IW_AUTH_ALG_LEAP 0x00000004 + +#define IW_AUTH_ROAMING_ENABLE 0 +#define IW_AUTH_ROAMING_DISABLE 1 + +#define IW_ENCODE_SEQ_MAX_SIZE 8 + +#define IW_ENCODE_ALG_NONE 0 +#define IW_ENCODE_ALG_WEP 1 +#define IW_ENCODE_ALG_TKIP 2 +#define IW_ENCODE_ALG_CCMP 3 + + +struct iw_encode_ext +{ + __u32 ext_flags; // IW_ENCODE_EXT_* + __u8 tx_seq[IW_ENCODE_SEQ_MAX_SIZE]; // LSB first + __u8 rx_seq[IW_ENCODE_SEQ_MAX_SIZE]; // LSB first + struct sockaddr addr; // ff:ff:ff:ff:ff:ff for broadcast/multicast + // (group) keys or unicast address for + // individual keys + __u16 alg; // IW_ENCODE_ALG_* + __u16 key_len; + __u8 key[0]; +}; + + +struct iw_mlme +{ + __u16 cmd; /* IW_MLME_* */ + __u16 reason_code; + struct sockaddr addr; +}; + +#endif // WIRELESS_EXT < 18 + + + +#ifdef WIRELESS_EXT + +struct iw_statistics *iwctl_get_wireless_stats (struct net_device *dev); + + +int iwctl_siwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *wrq, + char *extra); + +int iwctl_giwrange(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *wrq, + char *extra); + + +int iwctl_giwmode(struct net_device *dev, + struct iw_request_info *info, + __u32 *wmode, + char *extra); + +int iwctl_siwmode(struct net_device *dev, + struct iw_request_info *info, + __u32 *wmode, + char *extra); + +int iwctl_giwfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *wrq, + char *extra); + +int iwctl_siwfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *wrq, + char *extra); + +int iwctl_giwname(struct net_device *dev, + struct iw_request_info *info, + char *wrq, + char *extra); + +int iwctl_giwnwid(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *wrq, + char *extra) ; + +int iwctl_giwsens(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *wrq, + char *extra); + +int iwctl_giwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *wrq, + char *extra); + +int iwctl_giwaplist(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *wrq, + char *extra); + +int iwctl_siwessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *wrq, + char *extra); + +int iwctl_giwessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *wrq, + char *extra); + +int iwctl_siwrate(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *wrq, + char *extra); + +int iwctl_giwrate(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *wrq, + char *extra); + +int iwctl_siwrts(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *wrq, + char *extra); + + +int iwctl_giwrts(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *wrq, + char *extra); + +int iwctl_siwfrag(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *wrq, + char *extra); + +int iwctl_giwfrag(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *wrq, + char *extra); + +int iwctl_siwretry(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *wrq, + char *extra); + +int iwctl_giwretry(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *wrq, + char *extra); + +int iwctl_siwencode(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *wrq, + char *extra); + +int iwctl_giwencode(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *wrq, + char *extra); + +int iwctl_siwpower(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *wrq, + char *extra); + +int iwctl_giwpower(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *wrq, + char *extra); + +int iwctl_giwscan(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *wrq, + char *extra); + +int iwctl_siwscan(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *wrq, + char *extra); + +//2008-0409-07, by Einsn Liu +#ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT +int iwctl_siwauth(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *wrq, + char *extra); + +int iwctl_giwauth(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *wrq, + char *extra); + +int iwctl_siwgenie(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *wrq, + char *extra); + +int iwctl_giwgenie(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *wrq, + char *extra); + +int iwctl_siwencodeext(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *wrq, + char *extra); + +int iwctl_giwencodeext(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *wrq, + char *extra); + +int iwctl_siwmlme(struct net_device *dev, + struct iw_request_info * info, + struct iw_point *wrq, + char *extra); +#endif // #ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT + + +#endif + +#if WIRELESS_EXT > 12 +extern const struct iw_handler_def iwctl_handler_def; +extern const struct iw_priv_args iwctl_private_args; +#else +struct iw_request_info {}; +#endif //WIRELESS_EXT > 12 + +#ifdef __cplusplus +} /* End of extern "C" { */ +#endif /* __cplusplus */ + + + + +#endif // __IWCTL_H__ + + + diff --git a/drivers/staging/vt6655/kcompat.h b/drivers/staging/vt6655/kcompat.h new file mode 100644 index 000000000000..652c2c78b0f5 --- /dev/null +++ b/drivers/staging/vt6655/kcompat.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * File: kcompat.h + * + * Purpose: define kernel compatibility header + * + * Author: Lyndon Chen + * + * Date: Apr 8, 2002 + * + */ +#ifndef _KCOMPAT_H +#define _KCOMPAT_H + +#include + +#ifndef __init +#define __init +#endif + +#ifndef __exit +#define __exit +#endif + +#ifndef __devexit +#define __devexit +#endif + +#ifndef __devinitdata +#define __devinitdata +#endif + +#ifndef MODULE_LICENSE +#define MODULE_LICENSE(license) +#endif + +#ifndef MOD_INC_USE_COUNT +#define MOD_INC_USE_COUNT do {} while (0) +#endif + +#ifndef MOD_DEC_USE_COUNT +#define MOD_DEC_USE_COUNT do {} while (0) +#endif + +#ifndef HAVE_NETDEV_PRIV +#define netdev_priv(dev) (dev->priv) +#endif + +#ifndef IRQ_RETVAL +typedef void irqreturn_t; + +#ifdef PRIVATE_OBJ +#define IRQ_RETVAL(x) (int)x +#else +#define IRQ_RETVAL(x) +#endif + +#endif + + +#ifndef MODULE_LICESEN +#define MODULE_LICESEN(x) +#endif + + +#endif + diff --git a/drivers/staging/vt6655/key.c b/drivers/staging/vt6655/key.c new file mode 100644 index 000000000000..168ebd3be944 --- /dev/null +++ b/drivers/staging/vt6655/key.c @@ -0,0 +1,836 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * File: key.c + * + * Purpose: Implement functions for 802.11i Key management + * + * Author: Jerry Chen + * + * Date: May 29, 2003 + * + * Functions: + * KeyvInitTable - Init Key management table + * KeybGetKey - Get Key from table + * KeybSetKey - Set Key to table + * KeybRemoveKey - Remove Key from table + * KeybGetTransmitKey - Get Transmit Key from table + * + * Revision History: + * + */ + + +#if !defined(__TMACRO_H__) +#include "tmacro.h" +#endif +#if !defined(__TBIT_H__) +#include "tbit.h" +#endif +#if !defined(__KEY_H__) +#include "key.h" +#endif +#if !defined(__UMEM_H__) +#include "umem.h" +#endif +#if !defined(__MAC_H__) +#include "mac.h" +#endif + + +/*--------------------- Static Definitions -------------------------*/ + +/*--------------------- Static Classes ----------------------------*/ + +/*--------------------- Static Variables --------------------------*/ +static int msglevel =MSG_LEVEL_INFO; +//static int msglevel =MSG_LEVEL_DEBUG; +/*--------------------- Static Functions --------------------------*/ + +/*--------------------- Export Variables --------------------------*/ + +/*--------------------- Static Definitions -------------------------*/ + +/*--------------------- Static Classes ----------------------------*/ + +/*--------------------- Static Variables --------------------------*/ + +/*--------------------- Static Functions --------------------------*/ +static VOID +s_vCheckKeyTableValid (PSKeyManagement pTable, DWORD_PTR dwIoBase) +{ + int i; + + for (i=0;iKeyTable[i].bInUse == TRUE) && + (pTable->KeyTable[i].PairwiseKey.bKeyValid == FALSE) && + (pTable->KeyTable[i].GroupKey[0].bKeyValid == FALSE) && + (pTable->KeyTable[i].GroupKey[1].bKeyValid == FALSE) && + (pTable->KeyTable[i].GroupKey[2].bKeyValid == FALSE) && + (pTable->KeyTable[i].GroupKey[3].bKeyValid == FALSE) + ) { + pTable->KeyTable[i].bInUse = FALSE; + pTable->KeyTable[i].wKeyCtl = 0; + pTable->KeyTable[i].bSoftWEP = FALSE; + MACvDisableKeyEntry(dwIoBase, i); + } + } +} + + +/*--------------------- Export Functions --------------------------*/ + + +/* + * Description: Init Key management table + * + * Parameters: + * In: + * pTable - Pointer to Key table + * Out: + * none + * + * Return Value: none + * + */ +VOID KeyvInitTable (PSKeyManagement pTable, DWORD_PTR dwIoBase) +{ + int i; + int jj; + + for (i=0;iKeyTable[i].bInUse = FALSE; + pTable->KeyTable[i].PairwiseKey.bKeyValid = FALSE; + pTable->KeyTable[i].PairwiseKey.pvKeyTable = (PVOID)&pTable->KeyTable[i]; + for (jj=0; jj < MAX_GROUP_KEY; jj++) { + pTable->KeyTable[i].GroupKey[jj].bKeyValid = FALSE; + pTable->KeyTable[i].GroupKey[jj].pvKeyTable = (PVOID)&pTable->KeyTable[i]; + } + pTable->KeyTable[i].wKeyCtl = 0; + pTable->KeyTable[i].dwGTKeyIndex = 0; + pTable->KeyTable[i].bSoftWEP = FALSE; + MACvDisableKeyEntry(dwIoBase, i); + } +} + + +/* + * Description: Get Key from table + * + * Parameters: + * In: + * pTable - Pointer to Key table + * pbyBSSID - BSSID of Key + * dwKeyIndex - Key Index (0xFFFFFFFF means pairwise key) + * Out: + * pKey - Key return + * + * Return Value: TRUE if found otherwise FALSE + * + */ +BOOL KeybGetKey ( + IN PSKeyManagement pTable, + IN PBYTE pbyBSSID, + IN DWORD dwKeyIndex, + OUT PSKeyItem *pKey + ) +{ + int i; + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"KeybGetKey() \n"); + + *pKey = NULL; + for (i=0;iKeyTable[i].bInUse == TRUE) && + IS_ETH_ADDRESS_EQUAL(pTable->KeyTable[i].abyBSSID,pbyBSSID)) { + if (dwKeyIndex == 0xFFFFFFFF) { + if (pTable->KeyTable[i].PairwiseKey.bKeyValid == TRUE) { + *pKey = &(pTable->KeyTable[i].PairwiseKey); + return (TRUE); + } + else { + return (FALSE); + } + } else if (dwKeyIndex < MAX_GROUP_KEY) { + if (pTable->KeyTable[i].GroupKey[dwKeyIndex].bKeyValid == TRUE) { + *pKey = &(pTable->KeyTable[i].GroupKey[dwKeyIndex]); + return (TRUE); + } + else { + return (FALSE); + } + } + else { + return (FALSE); + } + } + } + return (FALSE); +} + + +/* + * Description: Set Key to table + * + * Parameters: + * In: + * pTable - Pointer to Key table + * pbyBSSID - BSSID of Key + * dwKeyIndex - Key index (reference to NDIS DDK) + * uKeyLength - Key length + * KeyRSC - Key RSC + * pbyKey - Pointer to key + * Out: + * none + * + * Return Value: TRUE if success otherwise FALSE + * + */ +BOOL KeybSetKey ( + PSKeyManagement pTable, + PBYTE pbyBSSID, + DWORD dwKeyIndex, + ULONG uKeyLength, + PQWORD pKeyRSC, + PBYTE pbyKey, + BYTE byKeyDecMode, + DWORD_PTR dwIoBase, + BYTE byLocalID + ) +{ + int i,j; + UINT ii; + PSKeyItem pKey; + UINT uKeyIdx; + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Enter KeybSetKey: %lX\n", dwKeyIndex); + + j = (MAX_KEY_TABLE-1); + for (i=0;i<(MAX_KEY_TABLE-1);i++) { + if ((pTable->KeyTable[i].bInUse == FALSE) && + (j == (MAX_KEY_TABLE-1))) { + // found empty table + j = i; + } + if ((pTable->KeyTable[i].bInUse == TRUE) && + IS_ETH_ADDRESS_EQUAL(pTable->KeyTable[i].abyBSSID,pbyBSSID)) { + // found table already exist + if ((dwKeyIndex & PAIRWISE_KEY) != 0) { + // Pairwise key + pKey = &(pTable->KeyTable[i].PairwiseKey); + pTable->KeyTable[i].wKeyCtl &= 0xFFF0; // clear pairwise key control filed + pTable->KeyTable[i].wKeyCtl |= byKeyDecMode; + uKeyIdx = 4; // use HW key entry 4 for pairwise key + } else { + // Group key + if ((dwKeyIndex & 0x000000FF) >= MAX_GROUP_KEY) + return (FALSE); + pKey = &(pTable->KeyTable[i].GroupKey[dwKeyIndex & 0x000000FF]); + if ((dwKeyIndex & TRANSMIT_KEY) != 0) { + // Group transmit key + pTable->KeyTable[i].dwGTKeyIndex = dwKeyIndex; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Group transmit key(R)[%lX]: %d\n", pTable->KeyTable[i].dwGTKeyIndex, i); + } + pTable->KeyTable[i].wKeyCtl &= 0xFF0F; // clear group key control filed + pTable->KeyTable[i].wKeyCtl |= (byKeyDecMode << 4); + pTable->KeyTable[i].wKeyCtl |= 0x0040; // use group key for group address + uKeyIdx = (dwKeyIndex & 0x000000FF); + } + pTable->KeyTable[i].wKeyCtl |= 0x8000; // enable on-fly + + pKey->bKeyValid = TRUE; + pKey->uKeyLength = uKeyLength; + pKey->dwKeyIndex = dwKeyIndex; + pKey->byCipherSuite = byKeyDecMode; + MEMvCopy(pKey->abyKey, pbyKey, uKeyLength); + if (byKeyDecMode == KEY_CTL_WEP) { + if (uKeyLength == WLAN_WEP40_KEYLEN) + pKey->abyKey[15] &= 0x7F; + if (uKeyLength == WLAN_WEP104_KEYLEN) + pKey->abyKey[15] |= 0x80; + } + MACvSetKeyEntry(dwIoBase, pTable->KeyTable[i].wKeyCtl, i, uKeyIdx, pbyBSSID, (PDWORD)pKey->abyKey, byLocalID); + + if ((dwKeyIndex & USE_KEYRSC) == 0) { + // RSC set by NIC + ZERO_MEMORY(&(pKey->KeyRSC), sizeof(QWORD)); + } + else { + MEMvCopy(&(pKey->KeyRSC), pKeyRSC, sizeof(QWORD)); + } + pKey->dwTSC47_16 = 0; + pKey->wTSC15_0 = 0; + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"KeybSetKey(R): \n"); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->bKeyValid: %d\n ", pKey->bKeyValid); + //DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->uKeyLength: %d\n ", pKey->uKeyLength); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->abyKey: "); + for (ii = 0; ii < pKey->uKeyLength; ii++) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%02x ", pKey->abyKey[ii]); + } + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"\n"); + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->dwTSC47_16: %lx\n ", pKey->dwTSC47_16); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->wTSC15_0: %x\n ", pKey->wTSC15_0); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->dwKeyIndex: %lx\n ", pKey->dwKeyIndex); + + return (TRUE); + } + } + if (j < (MAX_KEY_TABLE-1)) { + MEMvCopy(pTable->KeyTable[j].abyBSSID,pbyBSSID,U_ETHER_ADDR_LEN); + pTable->KeyTable[j].bInUse = TRUE; + if ((dwKeyIndex & PAIRWISE_KEY) != 0) { + // Pairwise key + pKey = &(pTable->KeyTable[j].PairwiseKey); + pTable->KeyTable[j].wKeyCtl &= 0xFFF0; // clear pairwise key control filed + pTable->KeyTable[j].wKeyCtl |= byKeyDecMode; + uKeyIdx = 4; // use HW key entry 4 for pairwise key + } else { + // Group key + if ((dwKeyIndex & 0x000000FF) >= MAX_GROUP_KEY) + return (FALSE); + pKey = &(pTable->KeyTable[j].GroupKey[dwKeyIndex & 0x000000FF]); + if ((dwKeyIndex & TRANSMIT_KEY) != 0) { + // Group transmit key + pTable->KeyTable[j].dwGTKeyIndex = dwKeyIndex; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Group transmit key(N)[%lX]: %d\n", pTable->KeyTable[j].dwGTKeyIndex, j); + } + pTable->KeyTable[j].wKeyCtl &= 0xFF0F; // clear group key control filed + pTable->KeyTable[j].wKeyCtl |= (byKeyDecMode << 4); + pTable->KeyTable[j].wKeyCtl |= 0x0040; // use group key for group address + uKeyIdx = (dwKeyIndex & 0x000000FF); + } + pTable->KeyTable[j].wKeyCtl |= 0x8000; // enable on-fly + + pKey->bKeyValid = TRUE; + pKey->uKeyLength = uKeyLength; + pKey->dwKeyIndex = dwKeyIndex; + pKey->byCipherSuite = byKeyDecMode; + MEMvCopy(pKey->abyKey, pbyKey, uKeyLength); + if (byKeyDecMode == KEY_CTL_WEP) { + if (uKeyLength == WLAN_WEP40_KEYLEN) + pKey->abyKey[15] &= 0x7F; + if (uKeyLength == WLAN_WEP104_KEYLEN) + pKey->abyKey[15] |= 0x80; + } + MACvSetKeyEntry(dwIoBase, pTable->KeyTable[j].wKeyCtl, j, uKeyIdx, pbyBSSID, (PDWORD)pKey->abyKey, byLocalID); + + if ((dwKeyIndex & USE_KEYRSC) == 0) { + // RSC set by NIC + ZERO_MEMORY(&(pKey->KeyRSC), sizeof(QWORD)); + } + else { + MEMvCopy(&(pKey->KeyRSC), pKeyRSC, sizeof(QWORD)); + } + pKey->dwTSC47_16 = 0; + pKey->wTSC15_0 = 0; + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"KeybSetKey(N): \n"); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->bKeyValid: %d\n ", pKey->bKeyValid); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->uKeyLength: %d\n ", (int)pKey->uKeyLength); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->abyKey: "); + for (ii = 0; ii < pKey->uKeyLength; ii++) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%02x ", pKey->abyKey[ii]); + } + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"\n"); + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->dwTSC47_16: %lx\n ", pKey->dwTSC47_16); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->wTSC15_0: %x\n ", pKey->wTSC15_0); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->dwKeyIndex: %lx\n ", pKey->dwKeyIndex); + + return (TRUE); + } + return (FALSE); +} + + +/* + * Description: Remove Key from table + * + * Parameters: + * In: + * pTable - Pointer to Key table + * pbyBSSID - BSSID of Key + * dwKeyIndex - Key Index (reference to NDIS DDK) + * Out: + * none + * + * Return Value: TRUE if success otherwise FALSE + * + */ +BOOL KeybRemoveKey ( + PSKeyManagement pTable, + PBYTE pbyBSSID, + DWORD dwKeyIndex, + DWORD_PTR dwIoBase + ) +{ + int i; + + if (IS_BROADCAST_ADDRESS(pbyBSSID)) { + // dealte all key + if ((dwKeyIndex & PAIRWISE_KEY) != 0) { + for (i=0;iKeyTable[i].PairwiseKey.bKeyValid = FALSE; + } + s_vCheckKeyTableValid(pTable, dwIoBase); + return TRUE; + } + else if ((dwKeyIndex & 0x000000FF) < MAX_GROUP_KEY) { + for (i=0;iKeyTable[i].GroupKey[dwKeyIndex & 0x000000FF].bKeyValid = FALSE; + if ((dwKeyIndex & 0x7FFFFFFF) == (pTable->KeyTable[i].dwGTKeyIndex & 0x7FFFFFFF)) { + // remove Group transmit key + pTable->KeyTable[i].dwGTKeyIndex = 0; + } + } + s_vCheckKeyTableValid(pTable, dwIoBase); + return TRUE; + } + else { + return FALSE; + } + } + + for (i=0;iKeyTable[i].bInUse == TRUE) && + IS_ETH_ADDRESS_EQUAL(pTable->KeyTable[i].abyBSSID,pbyBSSID)) { + if ((dwKeyIndex & PAIRWISE_KEY) != 0) { + pTable->KeyTable[i].PairwiseKey.bKeyValid = FALSE; + s_vCheckKeyTableValid(pTable, dwIoBase); + return (TRUE); + } + else if ((dwKeyIndex & 0x000000FF) < MAX_GROUP_KEY) { + pTable->KeyTable[i].GroupKey[dwKeyIndex & 0x000000FF].bKeyValid = FALSE; + if ((dwKeyIndex & 0x7FFFFFFF) == (pTable->KeyTable[i].dwGTKeyIndex & 0x7FFFFFFF)) { + // remove Group transmit key + pTable->KeyTable[i].dwGTKeyIndex = 0; + } + s_vCheckKeyTableValid(pTable, dwIoBase); + return (TRUE); + } + else { + return (FALSE); + } + } + } + return (FALSE); +} + + +/* + * Description: Remove Key from table + * + * Parameters: + * In: + * pTable - Pointer to Key table + * pbyBSSID - BSSID of Key + * Out: + * none + * + * Return Value: TRUE if success otherwise FALSE + * + */ +BOOL KeybRemoveAllKey ( + PSKeyManagement pTable, + PBYTE pbyBSSID, + DWORD_PTR dwIoBase + ) +{ + int i,u; + + for (i=0;iKeyTable[i].bInUse == TRUE) && + IS_ETH_ADDRESS_EQUAL(pTable->KeyTable[i].abyBSSID,pbyBSSID)) { + pTable->KeyTable[i].PairwiseKey.bKeyValid = FALSE; + for(u=0;uKeyTable[i].GroupKey[u].bKeyValid = FALSE; + } + pTable->KeyTable[i].dwGTKeyIndex = 0; + s_vCheckKeyTableValid(pTable, dwIoBase); + return (TRUE); + } + } + return (FALSE); +} + +/* + * Description: Remove WEP Key from table + * + * Parameters: + * In: + * pTable - Pointer to Key table + * Out: + * none + * + * Return Value: TRUE if success otherwise FALSE + * + */ +VOID KeyvRemoveWEPKey ( + PSKeyManagement pTable, + DWORD dwKeyIndex, + DWORD_PTR dwIoBase + ) +{ + + if ((dwKeyIndex & 0x000000FF) < MAX_GROUP_KEY) { + if (pTable->KeyTable[MAX_KEY_TABLE-1].bInUse == TRUE) { + if (pTable->KeyTable[MAX_KEY_TABLE-1].GroupKey[dwKeyIndex & 0x000000FF].byCipherSuite == KEY_CTL_WEP) { + pTable->KeyTable[MAX_KEY_TABLE-1].GroupKey[dwKeyIndex & 0x000000FF].bKeyValid = FALSE; + if ((dwKeyIndex & 0x7FFFFFFF) == (pTable->KeyTable[MAX_KEY_TABLE-1].dwGTKeyIndex & 0x7FFFFFFF)) { + // remove Group transmit key + pTable->KeyTable[MAX_KEY_TABLE-1].dwGTKeyIndex = 0; + } + } + } + s_vCheckKeyTableValid(pTable, dwIoBase); + } + return; +} + +VOID KeyvRemoveAllWEPKey ( + PSKeyManagement pTable, + DWORD_PTR dwIoBase + ) +{ + int i; + + for(i=0;iKeyTable[i].bInUse == TRUE) && + IS_ETH_ADDRESS_EQUAL(pTable->KeyTable[i].abyBSSID,pbyBSSID)) { + + if (dwKeyType == PAIRWISE_KEY) { + + if (pTable->KeyTable[i].PairwiseKey.bKeyValid == TRUE) { + *pKey = &(pTable->KeyTable[i].PairwiseKey); + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"KeybGetTransmitKey:"); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"PAIRWISE_KEY: KeyTable.abyBSSID: "); + for (ii = 0; ii < 6; ii++) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"%x ", pTable->KeyTable[i].abyBSSID[ii]); + } + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"\n"); + + + return (TRUE); + } + else { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"PairwiseKey.bKeyValid == FALSE\n"); + return (FALSE); + } + } // End of Type == PAIRWISE + else { + if (pTable->KeyTable[i].dwGTKeyIndex == 0) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ERROR: dwGTKeyIndex == 0 !!!\n"); + return FALSE; + } + if (pTable->KeyTable[i].GroupKey[(pTable->KeyTable[i].dwGTKeyIndex&0x000000FF)].bKeyValid == TRUE) { + *pKey = &(pTable->KeyTable[i].GroupKey[(pTable->KeyTable[i].dwGTKeyIndex&0x000000FF)]); + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"KeybGetTransmitKey:"); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"GROUP_KEY: KeyTable.abyBSSID\n"); + for (ii = 0; ii < 6; ii++) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"%x ", pTable->KeyTable[i].abyBSSID[ii]); + } + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"\n"); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"dwGTKeyIndex: %lX\n", pTable->KeyTable[i].dwGTKeyIndex); + + return (TRUE); + } + else { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"GroupKey.bKeyValid == FALSE\n"); + return (FALSE); + } + } // End of Type = GROUP + } // BSSID match + } + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ERROR: NO Match BSSID !!! "); + for (ii = 0; ii < 6; ii++) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"%02x ", *(pbyBSSID+ii)); + } + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"\n"); + return (FALSE); +} + + +/* + * Description: Check Pairewise Key + * + * Parameters: + * In: + * pTable - Pointer to Key table + * Out: + * none + * + * Return Value: TRUE if found otherwise FALSE + * + */ +BOOL KeybCheckPairewiseKey ( + IN PSKeyManagement pTable, + OUT PSKeyItem *pKey + ) +{ + int i; + + *pKey = NULL; + for (i=0;iKeyTable[i].bInUse == TRUE) && + (pTable->KeyTable[i].PairwiseKey.bKeyValid == TRUE)) { + *pKey = &(pTable->KeyTable[i].PairwiseKey); + return (TRUE); + } + } + return (FALSE); +} + +/* + * Description: Set Key to table + * + * Parameters: + * In: + * pTable - Pointer to Key table + * dwKeyIndex - Key index (reference to NDIS DDK) + * uKeyLength - Key length + * KeyRSC - Key RSC + * pbyKey - Pointer to key + * Out: + * none + * + * Return Value: TRUE if success otherwise FALSE + * + */ +BOOL KeybSetDefaultKey ( + PSKeyManagement pTable, + DWORD dwKeyIndex, + ULONG uKeyLength, + PQWORD pKeyRSC, + PBYTE pbyKey, + BYTE byKeyDecMode, + DWORD_PTR dwIoBase, + BYTE byLocalID + ) +{ + UINT ii; + PSKeyItem pKey; + UINT uKeyIdx; + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Enter KeybSetDefaultKey: %1x, %d \n", (int)dwKeyIndex, (int)uKeyLength); + + + if ((dwKeyIndex & PAIRWISE_KEY) != 0) { // Pairwise key + return (FALSE); + } else if ((dwKeyIndex & 0x000000FF) >= MAX_GROUP_KEY) { + return (FALSE); + } + + pTable->KeyTable[MAX_KEY_TABLE-1].bInUse = TRUE; + for(ii=0;iiKeyTable[MAX_KEY_TABLE-1].abyBSSID[ii] = 0xFF; + + // Group key + pKey = &(pTable->KeyTable[MAX_KEY_TABLE-1].GroupKey[dwKeyIndex & 0x000000FF]); + if ((dwKeyIndex & TRANSMIT_KEY) != 0) { + // Group transmit key + pTable->KeyTable[MAX_KEY_TABLE-1].dwGTKeyIndex = dwKeyIndex; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Group transmit key(R)[%lX]: %d\n", pTable->KeyTable[MAX_KEY_TABLE-1].dwGTKeyIndex, MAX_KEY_TABLE-1); + + } + pTable->KeyTable[MAX_KEY_TABLE-1].wKeyCtl &= 0x7F00; // clear all key control filed + pTable->KeyTable[MAX_KEY_TABLE-1].wKeyCtl |= (byKeyDecMode << 4); + pTable->KeyTable[MAX_KEY_TABLE-1].wKeyCtl |= (byKeyDecMode); + pTable->KeyTable[MAX_KEY_TABLE-1].wKeyCtl |= 0x0044; // use group key for all address + uKeyIdx = (dwKeyIndex & 0x000000FF); + + if ((uKeyLength == WLAN_WEP232_KEYLEN) && + (byKeyDecMode == KEY_CTL_WEP)) { + pTable->KeyTable[MAX_KEY_TABLE-1].wKeyCtl |= 0x4000; // disable on-fly disable address match + pTable->KeyTable[MAX_KEY_TABLE-1].bSoftWEP = TRUE; + } else { + if (pTable->KeyTable[MAX_KEY_TABLE-1].bSoftWEP == FALSE) + pTable->KeyTable[MAX_KEY_TABLE-1].wKeyCtl |= 0xC000; // enable on-fly disable address match + } + + pKey->bKeyValid = TRUE; + pKey->uKeyLength = uKeyLength; + pKey->dwKeyIndex = dwKeyIndex; + pKey->byCipherSuite = byKeyDecMode; + MEMvCopy(pKey->abyKey, pbyKey, uKeyLength); + if (byKeyDecMode == KEY_CTL_WEP) { + if (uKeyLength == WLAN_WEP40_KEYLEN) + pKey->abyKey[15] &= 0x7F; + if (uKeyLength == WLAN_WEP104_KEYLEN) + pKey->abyKey[15] |= 0x80; + } + MACvSetKeyEntry(dwIoBase, pTable->KeyTable[MAX_KEY_TABLE-1].wKeyCtl, MAX_KEY_TABLE-1, uKeyIdx, pTable->KeyTable[MAX_KEY_TABLE-1].abyBSSID, (PDWORD)pKey->abyKey, byLocalID); + + if ((dwKeyIndex & USE_KEYRSC) == 0) { + // RSC set by NIC + ZERO_MEMORY(&(pKey->KeyRSC), sizeof(QWORD)); + } else { + MEMvCopy(&(pKey->KeyRSC), pKeyRSC, sizeof(QWORD)); + } + pKey->dwTSC47_16 = 0; + pKey->wTSC15_0 = 0; + + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"KeybSetKey(R): \n"); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->bKeyValid: %d\n", pKey->bKeyValid); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->uKeyLength: %d\n", (int)pKey->uKeyLength); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->abyKey: \n"); + for (ii = 0; ii < pKey->uKeyLength; ii++) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"%x", pKey->abyKey[ii]); + } + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"\n"); + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->dwTSC47_16: %lx\n", pKey->dwTSC47_16); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->wTSC15_0: %x\n", pKey->wTSC15_0); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->dwKeyIndex: %lx\n", pKey->dwKeyIndex); + + return (TRUE); +} + + +/* + * Description: Set Key to table + * + * Parameters: + * In: + * pTable - Pointer to Key table + * dwKeyIndex - Key index (reference to NDIS DDK) + * uKeyLength - Key length + * KeyRSC - Key RSC + * pbyKey - Pointer to key + * Out: + * none + * + * Return Value: TRUE if success otherwise FALSE + * + */ +BOOL KeybSetAllGroupKey ( + PSKeyManagement pTable, + DWORD dwKeyIndex, + ULONG uKeyLength, + PQWORD pKeyRSC, + PBYTE pbyKey, + BYTE byKeyDecMode, + DWORD_PTR dwIoBase, + BYTE byLocalID + ) +{ + int i; + UINT ii; + PSKeyItem pKey; + UINT uKeyIdx; + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Enter KeybSetAllGroupKey: %lX\n", dwKeyIndex); + + + if ((dwKeyIndex & PAIRWISE_KEY) != 0) { // Pairwise key + return (FALSE); + } else if ((dwKeyIndex & 0x000000FF) >= MAX_GROUP_KEY) { + return (FALSE); + } + + for (i=0; i < MAX_KEY_TABLE-1; i++) { + if (pTable->KeyTable[i].bInUse == TRUE) { + // found table already exist + // Group key + pKey = &(pTable->KeyTable[i].GroupKey[dwKeyIndex & 0x000000FF]); + if ((dwKeyIndex & TRANSMIT_KEY) != 0) { + // Group transmit key + pTable->KeyTable[i].dwGTKeyIndex = dwKeyIndex; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Group transmit key(R)[%lX]: %d\n", pTable->KeyTable[i].dwGTKeyIndex, i); + + } + pTable->KeyTable[i].wKeyCtl &= 0xFF0F; // clear group key control filed + pTable->KeyTable[i].wKeyCtl |= (byKeyDecMode << 4); + pTable->KeyTable[i].wKeyCtl |= 0x0040; // use group key for group address + uKeyIdx = (dwKeyIndex & 0x000000FF); + + pTable->KeyTable[i].wKeyCtl |= 0x8000; // enable on-fly + + pKey->bKeyValid = TRUE; + pKey->uKeyLength = uKeyLength; + pKey->dwKeyIndex = dwKeyIndex; + pKey->byCipherSuite = byKeyDecMode; + MEMvCopy(pKey->abyKey, pbyKey, uKeyLength); + if (byKeyDecMode == KEY_CTL_WEP) { + if (uKeyLength == WLAN_WEP40_KEYLEN) + pKey->abyKey[15] &= 0x7F; + if (uKeyLength == WLAN_WEP104_KEYLEN) + pKey->abyKey[15] |= 0x80; + } + MACvSetKeyEntry(dwIoBase, pTable->KeyTable[i].wKeyCtl, i, uKeyIdx, pTable->KeyTable[i].abyBSSID, (PDWORD)pKey->abyKey, byLocalID); + + if ((dwKeyIndex & USE_KEYRSC) == 0) { + // RSC set by NIC + ZERO_MEMORY(&(pKey->KeyRSC), sizeof(QWORD)); + } + else { + MEMvCopy(&(pKey->KeyRSC), pKeyRSC, sizeof(QWORD)); + } + pKey->dwTSC47_16 = 0; + pKey->wTSC15_0 = 0; + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"KeybSetKey(R): \n"); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->bKeyValid: %d\n ", pKey->bKeyValid); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->uKeyLength: %d\n ", (int)pKey->uKeyLength); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->abyKey: "); + for (ii = 0; ii < pKey->uKeyLength; ii++) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"%02x ", pKey->abyKey[ii]); + } + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"\n"); + + //DBG_PRN_GRP12(("pKey->dwTSC47_16: %lX\n ", pKey->dwTSC47_16)); + //DBG_PRN_GRP12(("pKey->wTSC15_0: %X\n ", pKey->wTSC15_0)); + //DBG_PRN_GRP12(("pKey->dwKeyIndex: %lX\n ", pKey->dwKeyIndex)); + + } // (pTable->KeyTable[i].bInUse == TRUE) + } + return (TRUE); +} diff --git a/drivers/staging/vt6655/key.h b/drivers/staging/vt6655/key.h new file mode 100644 index 000000000000..9c7d335ea088 --- /dev/null +++ b/drivers/staging/vt6655/key.h @@ -0,0 +1,202 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * File: key.h + * + * Purpose: Implement functions for 802.11i Key management + * + * Author: Jerry Chen + * + * Date: May 29, 2003 + * + */ + + +#ifndef __KEY_H__ +#define __KEY_H__ + +#if !defined(__TTYPE_H__) +#include "ttype.h" +#endif + +#if !defined(__TETHER_H__) +#include "tether.h" +#endif + +#if !defined(__80211MGR_H__) +#include "80211mgr.h" +#endif + +/*--------------------- Export Definitions -------------------------*/ +#define MAX_GROUP_KEY 4 +#define MAX_KEY_TABLE 11 +#define MAX_KEY_LEN 32 +#define AES_KEY_LEN 16 + + +#define AUTHENTICATOR_KEY 0x10000000 +#define USE_KEYRSC 0x20000000 +#define PAIRWISE_KEY 0x40000000 +#define TRANSMIT_KEY 0x80000000 + +#define GROUP_KEY 0x00000000 + +#define KEY_CTL_WEP 0x00 +#define KEY_CTL_NONE 0x01 +#define KEY_CTL_TKIP 0x02 +#define KEY_CTL_CCMP 0x03 +#define KEY_CTL_INVALID 0xFF + + +typedef struct tagSKeyItem +{ + BOOL bKeyValid; + ULONG uKeyLength; + BYTE abyKey[MAX_KEY_LEN]; + QWORD KeyRSC; + DWORD dwTSC47_16; + WORD wTSC15_0; + BYTE byCipherSuite; + BYTE byReserved0; + DWORD dwKeyIndex; + PVOID pvKeyTable; +} SKeyItem, DEF* PSKeyItem; //64 + +typedef struct tagSKeyTable +{ + BYTE abyBSSID[U_ETHER_ADDR_LEN]; //6 + BYTE byReserved0[2]; //8 + SKeyItem PairwiseKey; + SKeyItem GroupKey[MAX_GROUP_KEY]; //64*5 = 320, 320+8=328 + DWORD dwGTKeyIndex; // GroupTransmitKey Index + BOOL bInUse; + //2006-1116-01, by NomadZhao + //WORD wKeyCtl; + //BOOL bSoftWEP; + BOOL bSoftWEP; + WORD wKeyCtl; // for address of wKeyCtl at align 4 + + BYTE byReserved1[6]; +} SKeyTable, DEF* PSKeyTable; //348 + +typedef struct tagSKeyManagement +{ + SKeyTable KeyTable[MAX_KEY_TABLE]; +} SKeyManagement, DEF* PSKeyManagement; + +/*--------------------- Export Types ------------------------------*/ + +/*--------------------- Export Macros ------------------------------*/ + +/*--------------------- Export Classes ----------------------------*/ + +/*--------------------- Export Variables --------------------------*/ + +/*--------------------- Export Functions --------------------------*/ +#ifdef __cplusplus +extern "C" { /* Assume C declarations for C++ */ +#endif /* __cplusplus */ + +VOID KeyvInitTable(PSKeyManagement pTable, DWORD_PTR dwIoBase); + +BOOL KeybGetKey( + IN PSKeyManagement pTable, + IN PBYTE pbyBSSID, + IN DWORD dwKeyIndex, + OUT PSKeyItem *pKey + ); + +BOOL KeybSetKey( + PSKeyManagement pTable, + PBYTE pbyBSSID, + DWORD dwKeyIndex, + ULONG uKeyLength, + PQWORD pKeyRSC, + PBYTE pbyKey, + BYTE byKeyDecMode, + DWORD_PTR dwIoBase, + BYTE byLocalID + ); + +BOOL KeybSetDefaultKey( + PSKeyManagement pTable, + DWORD dwKeyIndex, + ULONG uKeyLength, + PQWORD pKeyRSC, + PBYTE pbyKey, + BYTE byKeyDecMode, + DWORD_PTR dwIoBase, + BYTE byLocalID + ); + +BOOL KeybRemoveKey( + PSKeyManagement pTable, + PBYTE pbyBSSID, + DWORD dwKeyIndex, + DWORD_PTR dwIoBase + ); + +BOOL KeybGetTransmitKey( + IN PSKeyManagement pTable, + IN PBYTE pbyBSSID, + IN DWORD dwKeyType, + OUT PSKeyItem *pKey + ); + +BOOL KeybCheckPairewiseKey( + IN PSKeyManagement pTable, + OUT PSKeyItem *pKey + ); + +BOOL KeybRemoveAllKey( + PSKeyManagement pTable, + PBYTE pbyBSSID, + DWORD_PTR dwIoBase + ); + +VOID KeyvRemoveWEPKey( + PSKeyManagement pTable, + DWORD dwKeyIndex, + DWORD_PTR dwIoBase + ); + +VOID KeyvRemoveAllWEPKey( + PSKeyManagement pTable, + DWORD_PTR dwIoBase + ); + +BOOL KeybSetAllGroupKey ( + PSKeyManagement pTable, + DWORD dwKeyIndex, + ULONG uKeyLength, + PQWORD pKeyRSC, + PBYTE pbyKey, + BYTE byKeyDecMode, + DWORD_PTR dwIoBase, + BYTE byLocalID + ); + +#ifdef __cplusplus +} /* End of extern "C" { */ + +#endif /* __cplusplus */ + + +#endif // __KEY_H__ + diff --git a/drivers/staging/vt6655/mac.c b/drivers/staging/vt6655/mac.c new file mode 100644 index 000000000000..0283ed3bedd4 --- /dev/null +++ b/drivers/staging/vt6655/mac.c @@ -0,0 +1,1752 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * File: mac.c + * + * Purpose: MAC routines + * + * Author: Tevin Chen + * + * Date: May 21, 1996 + * + * Functions: + * MACvReadAllRegs - Read All MAC Registers to buffer + * MACbIsRegBitsOn - Test if All test Bits On + * MACbIsRegBitsOff - Test if All test Bits Off + * MACbIsIntDisable - Test if MAC interrupt disable + * MACbyReadMultiAddr - Read Multicast Address Mask Pattern + * MACvWriteMultiAddr - Write Multicast Address Mask Pattern + * MACvSetMultiAddrByHash - Set Multicast Address Mask by Hash value + * MACvResetMultiAddrByHash - Clear Multicast Address Mask by Hash value + * MACvSetRxThreshold - Set Rx Threshold value + * MACvGetRxThreshold - Get Rx Threshold value + * MACvSetTxThreshold - Set Tx Threshold value + * MACvGetTxThreshold - Get Tx Threshold value + * MACvSetDmaLength - Set Dma Length value + * MACvGetDmaLength - Get Dma Length value + * MACvSetShortRetryLimit - Set 802.11 Short Retry limit + * MACvGetShortRetryLimit - Get 802.11 Short Retry limit + * MACvSetLongRetryLimit - Set 802.11 Long Retry limit + * MACvGetLongRetryLimit - Get 802.11 Long Retry limit + * MACvSetLoopbackMode - Set MAC Loopback Mode + * MACbIsInLoopbackMode - Test if MAC in Loopback mode + * MACvSetPacketFilter - Set MAC Address Filter + * MACvSaveContext - Save Context of MAC Registers + * MACvRestoreContext - Restore Context of MAC Registers + * MACbCompareContext - Compare if values of MAC Registers same as Context + * MACbSoftwareReset - Software Reset MAC + * MACbSafeRxOff - Turn Off MAC Rx + * MACbSafeTxOff - Turn Off MAC Tx + * MACbSafeStop - Stop MAC function + * MACbShutdown - Shut down MAC + * MACvInitialize - Initialize MAC + * MACvSetCurrRxDescAddr - Set Rx Descriptos Address + * MACvSetCurrTx0DescAddr - Set Tx0 Descriptos Address + * MACvSetCurrTx1DescAddr - Set Tx1 Descriptos Address + * MACvTimer0MicroSDelay - Micro Second Delay Loop by MAC + * + * Revision History: + * 08-22-2003 Kyle Hsu : Porting MAC functions from sim53 + * 09-03-2003 Bryan YC Fan : Add MACvClearBusSusInd()& MACvEnableBusSusEn() + * 09-18-2003 Jerry Chen : Add MACvSetKeyEntry & MACvDisableKeyEntry + * + */ + +#if !defined(__TMACRO_H__) +#include "tmacro.h" +#endif +#if !defined(__TBIT_H__) +#include "tbit.h" +#endif +#if !defined(__TETHER_H__) +#include "tether.h" +#endif +#if !defined(__MAC_H__) +#include "mac.h" +#endif + + +WORD TxRate_iwconfig;//2008-5-8 by chester +/*--------------------- Static Definitions -------------------------*/ +//static int msglevel =MSG_LEVEL_DEBUG; +static int msglevel =MSG_LEVEL_INFO; +/*--------------------- Static Classes ----------------------------*/ + +/*--------------------- Static Variables --------------------------*/ + +/*--------------------- Static Functions --------------------------*/ + +/*--------------------- Export Variables --------------------------*/ + +/*--------------------- Export Functions --------------------------*/ + +/* + * Description: + * Read All MAC Registers to buffer + * + * Parameters: + * In: + * dwIoBase - Base Address for MAC + * Out: + * pbyMacRegs - buffer to read + * + * Return Value: none + * + */ +VOID MACvReadAllRegs (DWORD_PTR dwIoBase, PBYTE pbyMacRegs) +{ + int ii; + + // read page0 register + for (ii = 0; ii < MAC_MAX_CONTEXT_SIZE_PAGE0; ii++) { + VNSvInPortB(dwIoBase + ii, pbyMacRegs); + pbyMacRegs++; + } + + MACvSelectPage1(dwIoBase); + + // read page1 register + for (ii = 0; ii < MAC_MAX_CONTEXT_SIZE_PAGE1; ii++) { + VNSvInPortB(dwIoBase + ii, pbyMacRegs); + pbyMacRegs++; + } + + MACvSelectPage0(dwIoBase); + +} + +/* + * Description: + * Test if all test bits on + * + * Parameters: + * In: + * dwIoBase - Base Address for MAC + * byRegOfs - Offset of MAC Register + * byTestBits - Test bits + * Out: + * none + * + * Return Value: TRUE if all test bits On; otherwise FALSE + * + */ +BOOL MACbIsRegBitsOn (DWORD_PTR dwIoBase, BYTE byRegOfs, BYTE byTestBits) +{ + BYTE byData; + + VNSvInPortB(dwIoBase + byRegOfs, &byData); + return BITbIsAllBitsOn(byData, byTestBits); +} + +/* + * Description: + * Test if all test bits off + * + * Parameters: + * In: + * dwIoBase - Base Address for MAC + * byRegOfs - Offset of MAC Register + * byTestBits - Test bits + * Out: + * none + * + * Return Value: TRUE if all test bits Off; otherwise FALSE + * + */ +BOOL MACbIsRegBitsOff (DWORD_PTR dwIoBase, BYTE byRegOfs, BYTE byTestBits) +{ + BYTE byData; + + VNSvInPortB(dwIoBase + byRegOfs, &byData); + return BITbIsAllBitsOff(byData, byTestBits); +} + +/* + * Description: + * Test if MAC interrupt disable + * + * Parameters: + * In: + * dwIoBase - Base Address for MAC + * Out: + * none + * + * Return Value: TRUE if interrupt is disable; otherwise FALSE + * + */ +BOOL MACbIsIntDisable (DWORD_PTR dwIoBase) +{ + DWORD dwData; + + VNSvInPortD(dwIoBase + MAC_REG_IMR, &dwData); + if (dwData != 0) + return FALSE; + + return TRUE; +} + +/* + * Description: + * Read MAC Multicast Address Mask + * + * Parameters: + * In: + * dwIoBase - Base Address for MAC + * uByteidx - Index of Mask + * Out: + * none + * + * Return Value: Mask Value read + * + */ +BYTE MACbyReadMultiAddr (DWORD_PTR dwIoBase, UINT uByteIdx) +{ + BYTE byData; + + MACvSelectPage1(dwIoBase); + VNSvInPortB(dwIoBase + MAC_REG_MAR0 + uByteIdx, &byData); + MACvSelectPage0(dwIoBase); + return byData; +} + +/* + * Description: + * Write MAC Multicast Address Mask + * + * Parameters: + * In: + * dwIoBase - Base Address for MAC + * uByteidx - Index of Mask + * byData - Mask Value to write + * Out: + * none + * + * Return Value: none + * + */ +VOID MACvWriteMultiAddr (DWORD_PTR dwIoBase, UINT uByteIdx, BYTE byData) +{ + MACvSelectPage1(dwIoBase); + VNSvOutPortB(dwIoBase + MAC_REG_MAR0 + uByteIdx, byData); + MACvSelectPage0(dwIoBase); +} + +/* + * Description: + * Set this hash index into multicast address register bit + * + * Parameters: + * In: + * dwIoBase - Base Address for MAC + * byHashIdx - Hash index to set + * Out: + * none + * + * Return Value: none + * + */ +void MACvSetMultiAddrByHash (DWORD_PTR dwIoBase, BYTE byHashIdx) +{ + UINT uByteIdx; + BYTE byBitMask; + BYTE byOrgValue; + + // calculate byte position + uByteIdx = byHashIdx / 8; + ASSERT(uByteIdx < 8); + // calculate bit position + byBitMask = 1; + byBitMask <<= (byHashIdx % 8); + // turn on the bit + byOrgValue = MACbyReadMultiAddr(dwIoBase, uByteIdx); + MACvWriteMultiAddr(dwIoBase, uByteIdx, (BYTE)(byOrgValue | byBitMask)); +} + +/* + * Description: + * Reset this hash index into multicast address register bit + * + * Parameters: + * In: + * dwIoBase - Base Address for MAC + * byHashIdx - Hash index to clear + * Out: + * none + * + * Return Value: none + * + */ +void MACvResetMultiAddrByHash (DWORD_PTR dwIoBase, BYTE byHashIdx) +{ + UINT uByteIdx; + BYTE byBitMask; + BYTE byOrgValue; + + // calculate byte position + uByteIdx = byHashIdx / 8; + ASSERT(uByteIdx < 8); + // calculate bit position + byBitMask = 1; + byBitMask <<= (byHashIdx % 8); + // turn off the bit + byOrgValue = MACbyReadMultiAddr(dwIoBase, uByteIdx); + MACvWriteMultiAddr(dwIoBase, uByteIdx, (BYTE)(byOrgValue & (~byBitMask))); +} + +/* + * Description: + * Set Rx Threshold + * + * Parameters: + * In: + * dwIoBase - Base Address for MAC + * byThreshold - Threshold Value + * Out: + * none + * + * Return Value: none + * + */ +void MACvSetRxThreshold (DWORD_PTR dwIoBase, BYTE byThreshold) +{ + BYTE byOrgValue; + + ASSERT(byThreshold < 4); + + // set FCR0 + VNSvInPortB(dwIoBase + MAC_REG_FCR0, &byOrgValue); + byOrgValue = (byOrgValue & 0xCF) | (byThreshold << 4); + VNSvOutPortB(dwIoBase + MAC_REG_FCR0, byOrgValue); +} + +/* + * Description: + * Get Rx Threshold + * + * Parameters: + * In: + * dwIoBase - Base Address for MAC + * Out: + * pbyThreshold- Threshold Value Get + * + * Return Value: none + * + */ +void MACvGetRxThreshold (DWORD_PTR dwIoBase, PBYTE pbyThreshold) +{ + // get FCR0 + VNSvInPortB(dwIoBase + MAC_REG_FCR0, pbyThreshold); + *pbyThreshold = (*pbyThreshold >> 4) & 0x03; +} + +/* + * Description: + * Set Tx Threshold + * + * Parameters: + * In: + * dwIoBase - Base Address for MAC + * byThreshold - Threshold Value + * Out: + * none + * + * Return Value: none + * + */ +void MACvSetTxThreshold (DWORD_PTR dwIoBase, BYTE byThreshold) +{ + BYTE byOrgValue; + + ASSERT(byThreshold < 4); + + // set FCR0 + VNSvInPortB(dwIoBase + MAC_REG_FCR0, &byOrgValue); + byOrgValue = (byOrgValue & 0xF3) | (byThreshold << 2); + VNSvOutPortB(dwIoBase + MAC_REG_FCR0, byOrgValue); +} + +/* + * Description: + * Get Tx Threshold + * + * Parameters: + * In: + * dwIoBase - Base Address for MAC + * Out: + * pbyThreshold- Threshold Value Get + * + * Return Value: none + * + */ +void MACvGetTxThreshold (DWORD_PTR dwIoBase, PBYTE pbyThreshold) +{ + // get FCR0 + VNSvInPortB(dwIoBase + MAC_REG_FCR0, pbyThreshold); + *pbyThreshold = (*pbyThreshold >> 2) & 0x03; +} + +/* + * Description: + * Set Dma Length + * + * Parameters: + * In: + * dwIoBase - Base Address for MAC + * byDmaLength - Dma Length Value + * Out: + * none + * + * Return Value: none + * + */ +void MACvSetDmaLength (DWORD_PTR dwIoBase, BYTE byDmaLength) +{ + BYTE byOrgValue; + + ASSERT(byDmaLength < 4); + + // set FCR0 + VNSvInPortB(dwIoBase + MAC_REG_FCR0, &byOrgValue); + byOrgValue = (byOrgValue & 0xFC) | byDmaLength; + VNSvOutPortB(dwIoBase + MAC_REG_FCR0, byOrgValue); +} + +/* + * Description: + * Get Dma Length + * + * Parameters: + * In: + * dwIoBase - Base Address for MAC + * Out: + * pbyDmaLength- Dma Length Value Get + * + * Return Value: none + * + */ +void MACvGetDmaLength (DWORD_PTR dwIoBase, PBYTE pbyDmaLength) +{ + // get FCR0 + VNSvInPortB(dwIoBase + MAC_REG_FCR0, pbyDmaLength); + *pbyDmaLength &= 0x03; +} + +/* + * Description: + * Set 802.11 Short Retry Limit + * + * Parameters: + * In: + * dwIoBase - Base Address for MAC + * byRetryLimit- Retry Limit + * Out: + * none + * + * Return Value: none + * + */ +void MACvSetShortRetryLimit (DWORD_PTR dwIoBase, BYTE byRetryLimit) +{ + // set SRT + VNSvOutPortB(dwIoBase + MAC_REG_SRT, byRetryLimit); +} + +/* + * Description: + * Get 802.11 Short Retry Limit + * + * Parameters: + * In: + * dwIoBase - Base Address for MAC + * Out: + * pbyRetryLimit - Retry Limit Get + * + * Return Value: none + * + */ +void MACvGetShortRetryLimit (DWORD_PTR dwIoBase, PBYTE pbyRetryLimit) +{ + // get SRT + VNSvInPortB(dwIoBase + MAC_REG_SRT, pbyRetryLimit); +} + +/* + * Description: + * Set 802.11 Long Retry Limit + * + * Parameters: + * In: + * dwIoBase - Base Address for MAC + * byRetryLimit- Retry Limit + * Out: + * none + * + * Return Value: none + * + */ +void MACvSetLongRetryLimit (DWORD_PTR dwIoBase, BYTE byRetryLimit) +{ + // set LRT + VNSvOutPortB(dwIoBase + MAC_REG_LRT, byRetryLimit); +} + +/* + * Description: + * Get 802.11 Long Retry Limit + * + * Parameters: + * In: + * dwIoBase - Base Address for MAC + * Out: + * pbyRetryLimit - Retry Limit Get + * + * Return Value: none + * + */ +void MACvGetLongRetryLimit (DWORD_PTR dwIoBase, PBYTE pbyRetryLimit) +{ + // get LRT + VNSvInPortB(dwIoBase + MAC_REG_LRT, pbyRetryLimit); +} + +/* + * Description: + * Set MAC Loopback mode + * + * Parameters: + * In: + * dwIoBase - Base Address for MAC + * byLoopbackMode - Loopback Mode + * Out: + * none + * + * Return Value: none + * + */ +void MACvSetLoopbackMode (DWORD_PTR dwIoBase, BYTE byLoopbackMode) +{ + BYTE byOrgValue; + + ASSERT(byLoopbackMode < 3); + byLoopbackMode <<= 6; + // set TCR + VNSvInPortB(dwIoBase + MAC_REG_TEST, &byOrgValue); + byOrgValue = byOrgValue & 0x3F; + byOrgValue = byOrgValue | byLoopbackMode; + VNSvOutPortB(dwIoBase + MAC_REG_TEST, byOrgValue); +} + +/* + * Description: + * Test if MAC in Loopback mode + * + * Parameters: + * In: + * dwIoBase - Base Address for MAC + * Out: + * none + * + * Return Value: TRUE if in Loopback mode; otherwise FALSE + * + */ +BOOL MACbIsInLoopbackMode (DWORD_PTR dwIoBase) +{ + BYTE byOrgValue; + + VNSvInPortB(dwIoBase + MAC_REG_TEST, &byOrgValue); + if (BITbIsAnyBitsOn(byOrgValue, (TEST_LBINT | TEST_LBEXT))) + return TRUE; + return FALSE; +} + +/* + * Description: + * Set MAC Address filter + * + * Parameters: + * In: + * dwIoBase - Base Address for MAC + * wFilterType - Filter Type + * Out: + * none + * + * Return Value: none + * + */ +void MACvSetPacketFilter (DWORD_PTR dwIoBase, WORD wFilterType) +{ + BYTE byOldRCR; + BYTE byNewRCR = 0; + + // if only in DIRECTED mode, multicast-address will set to zero, + // but if other mode exist (e.g. PROMISCUOUS), multicast-address + // will be open + if (BITbIsBitOn(wFilterType, PKT_TYPE_DIRECTED)) { + // set multicast address to accept none + MACvSelectPage1(dwIoBase); + VNSvOutPortD(dwIoBase + MAC_REG_MAR0, 0L); + VNSvOutPortD(dwIoBase + MAC_REG_MAR0 + sizeof(DWORD), 0L); + MACvSelectPage0(dwIoBase); + } + + if (BITbIsAnyBitsOn(wFilterType, PKT_TYPE_PROMISCUOUS | PKT_TYPE_ALL_MULTICAST)) { + // set multicast address to accept all + MACvSelectPage1(dwIoBase); + VNSvOutPortD(dwIoBase + MAC_REG_MAR0, 0xFFFFFFFFL); + VNSvOutPortD(dwIoBase + MAC_REG_MAR0 + sizeof(DWORD), 0xFFFFFFFFL); + MACvSelectPage0(dwIoBase); + } + + if (BITbIsBitOn(wFilterType, PKT_TYPE_PROMISCUOUS)) { + + byNewRCR |= (RCR_RXALLTYPE | RCR_UNICAST | RCR_MULTICAST | RCR_BROADCAST); + + byNewRCR &= ~RCR_BSSID; + } + + if (BITbIsAnyBitsOn(wFilterType, (PKT_TYPE_ALL_MULTICAST | PKT_TYPE_MULTICAST))) + byNewRCR |= RCR_MULTICAST; + + if (BITbIsBitOn(wFilterType, PKT_TYPE_BROADCAST)) + byNewRCR |= RCR_BROADCAST; + + if (BITbIsBitOn(wFilterType, PKT_TYPE_ERROR_CRC)) + byNewRCR |= RCR_ERRCRC; + + VNSvInPortB(dwIoBase + MAC_REG_RCR, &byOldRCR); + if (byNewRCR != byOldRCR) { + // Modify the Receive Command Register + VNSvOutPortB(dwIoBase + MAC_REG_RCR, byNewRCR); + } +} + +/* + * Description: + * Save MAC registers to context buffer + * + * Parameters: + * In: + * dwIoBase - Base Address for MAC + * Out: + * pbyCxtBuf - Context buffer + * + * Return Value: none + * + */ +void MACvSaveContext (DWORD_PTR dwIoBase, PBYTE pbyCxtBuf) +{ + int ii; + + // read page0 register + for (ii = 0; ii < MAC_MAX_CONTEXT_SIZE_PAGE0; ii++) { + VNSvInPortB((dwIoBase + ii), (pbyCxtBuf + ii)); + } + + MACvSelectPage1(dwIoBase); + + // read page1 register + for (ii = 0; ii < MAC_MAX_CONTEXT_SIZE_PAGE1; ii++) { + VNSvInPortB((dwIoBase + ii), (pbyCxtBuf + MAC_MAX_CONTEXT_SIZE_PAGE0 + ii)); + } + + MACvSelectPage0(dwIoBase); +} + +/* + * Description: + * Restore MAC registers from context buffer + * + * Parameters: + * In: + * dwIoBase - Base Address for MAC + * pbyCxtBuf - Context buffer + * Out: + * none + * + * Return Value: none + * + */ +VOID MACvRestoreContext (DWORD_PTR dwIoBase, PBYTE pbyCxtBuf) +{ + int ii; + + MACvSelectPage1(dwIoBase); + // restore page1 + for (ii = 0; ii < MAC_MAX_CONTEXT_SIZE_PAGE1; ii++) { + VNSvOutPortB((dwIoBase + ii), *(pbyCxtBuf + MAC_MAX_CONTEXT_SIZE_PAGE0 + ii)); + } + MACvSelectPage0(dwIoBase); + + // restore RCR,TCR,IMR... + for (ii = MAC_REG_RCR; ii < MAC_REG_ISR; ii++) { + VNSvOutPortB(dwIoBase + ii, *(pbyCxtBuf + ii)); + } + // restore MAC Config. + for (ii = MAC_REG_LRT; ii < MAC_REG_PAGE1SEL; ii++) { + VNSvOutPortB(dwIoBase + ii, *(pbyCxtBuf + ii)); + } + VNSvOutPortB(dwIoBase + MAC_REG_CFG, *(pbyCxtBuf + MAC_REG_CFG)); + + // restore PS Config. + for (ii = MAC_REG_PSCFG; ii < MAC_REG_BBREGCTL; ii++) { + VNSvOutPortB(dwIoBase + ii, *(pbyCxtBuf + ii)); + } + + // restore CURR_RX_DESC_ADDR, CURR_TX_DESC_ADDR + VNSvOutPortD(dwIoBase + MAC_REG_TXDMAPTR0, *(PDWORD)(pbyCxtBuf + MAC_REG_TXDMAPTR0)); + VNSvOutPortD(dwIoBase + MAC_REG_AC0DMAPTR, *(PDWORD)(pbyCxtBuf + MAC_REG_AC0DMAPTR)); + VNSvOutPortD(dwIoBase + MAC_REG_BCNDMAPTR, *(PDWORD)(pbyCxtBuf + MAC_REG_BCNDMAPTR)); + + + VNSvOutPortD(dwIoBase + MAC_REG_RXDMAPTR0, *(PDWORD)(pbyCxtBuf + MAC_REG_RXDMAPTR0)); + + VNSvOutPortD(dwIoBase + MAC_REG_RXDMAPTR1, *(PDWORD)(pbyCxtBuf + MAC_REG_RXDMAPTR1)); + +} + +/* + * Description: + * Compare if MAC registers same as context buffer + * + * Parameters: + * In: + * dwIoBase - Base Address for MAC + * pbyCxtBuf - Context buffer + * Out: + * none + * + * Return Value: TRUE if all values are the same; otherwise FALSE + * + */ +BOOL MACbCompareContext (DWORD_PTR dwIoBase, PBYTE pbyCxtBuf) +{ + DWORD dwData; + + // compare MAC context to determine if this is a power lost init, + // return TRUE for power remaining init, return FALSE for power lost init + + // compare CURR_RX_DESC_ADDR, CURR_TX_DESC_ADDR + VNSvInPortD(dwIoBase + MAC_REG_TXDMAPTR0, &dwData); + if (dwData != *(PDWORD)(pbyCxtBuf + MAC_REG_TXDMAPTR0)) { + return FALSE; + } + + VNSvInPortD(dwIoBase + MAC_REG_AC0DMAPTR, &dwData); + if (dwData != *(PDWORD)(pbyCxtBuf + MAC_REG_AC0DMAPTR)) { + return FALSE; + } + + VNSvInPortD(dwIoBase + MAC_REG_RXDMAPTR0, &dwData); + if (dwData != *(PDWORD)(pbyCxtBuf + MAC_REG_RXDMAPTR0)) { + return FALSE; + } + + VNSvInPortD(dwIoBase + MAC_REG_RXDMAPTR1, &dwData); + if (dwData != *(PDWORD)(pbyCxtBuf + MAC_REG_RXDMAPTR1)) { + return FALSE; + } + + + return TRUE; +} + +/* + * Description: + * Software Reset MAC + * + * Parameters: + * In: + * dwIoBase - Base Address for MAC + * Out: + * none + * + * Return Value: TRUE if Reset Success; otherwise FALSE + * + */ +BOOL MACbSoftwareReset (DWORD_PTR dwIoBase) +{ + BYTE byData; + WORD ww; + + // turn on HOSTCR_SOFTRST, just write 0x01 to reset + //MACvRegBitsOn(dwIoBase, MAC_REG_HOSTCR, HOSTCR_SOFTRST); + VNSvOutPortB(dwIoBase+ MAC_REG_HOSTCR, 0x01); + + for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { + VNSvInPortB(dwIoBase + MAC_REG_HOSTCR, &byData); + if (BITbIsBitOff(byData, HOSTCR_SOFTRST)) + break; + } + if (ww == W_MAX_TIMEOUT) + return FALSE; + return TRUE; + +} + +/* + * Description: + * save some important register's value, then do reset, then restore register's value + * + * Parameters: + * In: + * dwIoBase - Base Address for MAC + * Out: + * none + * + * Return Value: TRUE if success; otherwise FALSE + * + */ +BOOL MACbSafeSoftwareReset (DWORD_PTR dwIoBase) +{ + BYTE abyTmpRegData[MAC_MAX_CONTEXT_SIZE_PAGE0+MAC_MAX_CONTEXT_SIZE_PAGE1]; + BOOL bRetVal; + + // PATCH.... + // save some important register's value, then do + // reset, then restore register's value + + // save MAC context + MACvSaveContext(dwIoBase, abyTmpRegData); + // do reset + bRetVal = MACbSoftwareReset(dwIoBase); + //BBvSoftwareReset(pDevice->PortOffset); + // restore MAC context, except CR0 + MACvRestoreContext(dwIoBase, abyTmpRegData); + + return bRetVal; +} + +/* + * Description: + * Trun Off MAC Rx + * + * Parameters: + * In: + * dwIoBase - Base Address for MAC + * Out: + * none + * + * Return Value: TRUE if success; otherwise FALSE + * + */ +BOOL MACbSafeRxOff (DWORD_PTR dwIoBase) +{ + WORD ww; + DWORD dwData; + BYTE byData; + + // turn off wow temp for turn off Rx safely + + // Clear RX DMA0,1 + VNSvOutPortD(dwIoBase + MAC_REG_RXDMACTL0, DMACTL_CLRRUN); + VNSvOutPortD(dwIoBase + MAC_REG_RXDMACTL1, DMACTL_CLRRUN); + for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { + VNSvInPortD(dwIoBase + MAC_REG_RXDMACTL0, &dwData); + if (BITbIsAllBitsOff(dwData, DMACTL_RUN)) + break; + } + if (ww == W_MAX_TIMEOUT) { + DBG_PORT80(0x10); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO" DBG_PORT80(0x10)\n"); + return(FALSE); + } + for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { + VNSvInPortD(dwIoBase + MAC_REG_RXDMACTL1, &dwData); + if (BITbIsAllBitsOff(dwData, DMACTL_RUN)) + break; + } + if (ww == W_MAX_TIMEOUT) { + DBG_PORT80(0x11); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO" DBG_PORT80(0x11)\n"); + return(FALSE); + } + + // try to safe shutdown RX + MACvRegBitsOff(dwIoBase, MAC_REG_HOSTCR, HOSTCR_RXON); + // W_MAX_TIMEOUT is the timeout period + for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { + VNSvInPortB(dwIoBase + MAC_REG_HOSTCR, &byData); + if (BITbIsAllBitsOff(byData, HOSTCR_RXONST)) + break; + } + if (ww == W_MAX_TIMEOUT) { + DBG_PORT80(0x12); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO" DBG_PORT80(0x12)\n"); + return(FALSE); + } + return TRUE; +} + +/* + * Description: + * Trun Off MAC Tx + * + * Parameters: + * In: + * dwIoBase - Base Address for MAC + * Out: + * none + * + * Return Value: TRUE if success; otherwise FALSE + * + */ +BOOL MACbSafeTxOff (DWORD_PTR dwIoBase) +{ + WORD ww; + DWORD dwData; + BYTE byData; + + // Clear TX DMA + //Tx0 + VNSvOutPortD(dwIoBase + MAC_REG_TXDMACTL0, DMACTL_CLRRUN); + //AC0 + VNSvOutPortD(dwIoBase + MAC_REG_AC0DMACTL, DMACTL_CLRRUN); + + + for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { + VNSvInPortD(dwIoBase + MAC_REG_TXDMACTL0, &dwData); + if (BITbIsAllBitsOff(dwData, DMACTL_RUN)) + break; + } + if (ww == W_MAX_TIMEOUT) { + DBG_PORT80(0x20); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO" DBG_PORT80(0x20)\n"); + return(FALSE); + } + for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { + VNSvInPortD(dwIoBase + MAC_REG_AC0DMACTL, &dwData); + if (BITbIsAllBitsOff(dwData, DMACTL_RUN)) + break; + } + if (ww == W_MAX_TIMEOUT) { + DBG_PORT80(0x21); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO" DBG_PORT80(0x21)\n"); + return(FALSE); + } + + // try to safe shutdown TX + MACvRegBitsOff(dwIoBase, MAC_REG_HOSTCR, HOSTCR_TXON); + + // W_MAX_TIMEOUT is the timeout period + for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { + VNSvInPortB(dwIoBase + MAC_REG_HOSTCR, &byData); + if (BITbIsAllBitsOff(byData, HOSTCR_TXONST)) + break; + } + if (ww == W_MAX_TIMEOUT) { + DBG_PORT80(0x24); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO" DBG_PORT80(0x24)\n"); + return(FALSE); + } + return TRUE; +} + +/* + * Description: + * Stop MAC function + * + * Parameters: + * In: + * dwIoBase - Base Address for MAC + * Out: + * none + * + * Return Value: TRUE if success; otherwise FALSE + * + */ +BOOL MACbSafeStop (DWORD_PTR dwIoBase) +{ + MACvRegBitsOff(dwIoBase, MAC_REG_TCR, TCR_AUTOBCNTX); + + if (MACbSafeRxOff(dwIoBase) == FALSE) { + DBG_PORT80(0xA1); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO" MACbSafeRxOff == FALSE)\n"); + MACbSafeSoftwareReset(dwIoBase); + return FALSE; + } + if (MACbSafeTxOff(dwIoBase) == FALSE) { + DBG_PORT80(0xA2); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO" MACbSafeTxOff == FALSE)\n"); + MACbSafeSoftwareReset(dwIoBase); + return FALSE; + } + + MACvRegBitsOff(dwIoBase, MAC_REG_HOSTCR, HOSTCR_MACEN); + + return TRUE; +} + +/* + * Description: + * Shut Down MAC + * + * Parameters: + * In: + * dwIoBase - Base Address for MAC + * Out: + * none + * + * Return Value: TRUE if success; otherwise FALSE + * + */ +BOOL MACbShutdown (DWORD_PTR dwIoBase) +{ + // disable MAC IMR + MACvIntDisable(dwIoBase); + MACvSetLoopbackMode(dwIoBase, MAC_LB_INTERNAL); + // stop the adapter + if (!MACbSafeStop(dwIoBase)) { + MACvSetLoopbackMode(dwIoBase, MAC_LB_NONE); + return FALSE; + } + MACvSetLoopbackMode(dwIoBase, MAC_LB_NONE); + return TRUE; +} + +/* + * Description: + * Initialize MAC + * + * Parameters: + * In: + * dwIoBase - Base Address for MAC + * Out: + * none + * + * Return Value: none + * + */ +void MACvInitialize (DWORD_PTR dwIoBase) +{ + // clear sticky bits + MACvClearStckDS(dwIoBase); + // disable force PME-enable + VNSvOutPortB(dwIoBase + MAC_REG_PMC1, PME_OVR); + // only 3253 A + /* + MACvPwrEvntDisable(dwIoBase); + // clear power status + VNSvOutPortW(dwIoBase + MAC_REG_WAKEUPSR0, 0x0F0F); + */ + + // do reset + MACbSoftwareReset(dwIoBase); + + // issue AUTOLD in EECSR to reload eeprom + //MACvRegBitsOn(dwIoBase, MAC_REG_I2MCSR, I2MCSR_AUTOLD); + // wait until EEPROM loading complete + //while (TRUE) { + // U8 u8Data; + // VNSvInPortB(dwIoBase + MAC_REG_I2MCSR, &u8Data); + // if (BITbIsBitOff(u8Data, I2MCSR_AUTOLD)) + // break; + //} + + // reset TSF counter + VNSvOutPortB(dwIoBase + MAC_REG_TFTCTL, TFTCTL_TSFCNTRST); + // enable TSF counter + VNSvOutPortB(dwIoBase + MAC_REG_TFTCTL, TFTCTL_TSFCNTREN); + + + // set packet filter + // receive directed and broadcast address + + MACvSetPacketFilter(dwIoBase, PKT_TYPE_DIRECTED | PKT_TYPE_BROADCAST); + +} + +/* + * Description: + * Set the chip with current rx descriptor address + * + * Parameters: + * In: + * dwIoBase - Base Address for MAC + * dwCurrDescAddr - Descriptor Address + * Out: + * none + * + * Return Value: none + * + */ +void MACvSetCurrRx0DescAddr (DWORD_PTR dwIoBase, DWORD dwCurrDescAddr) +{ +WORD ww; +BYTE byData; +BYTE byOrgDMACtl; + + VNSvInPortB(dwIoBase + MAC_REG_RXDMACTL0, &byOrgDMACtl); + if (BITbIsAllBitsOn(byOrgDMACtl, DMACTL_RUN)) { + VNSvOutPortB(dwIoBase + MAC_REG_RXDMACTL0+2, DMACTL_RUN); + } + for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { + VNSvInPortB(dwIoBase + MAC_REG_RXDMACTL0, &byData); + if (BITbIsAllBitsOff(byData, DMACTL_RUN)) + break; + } + if (ww == W_MAX_TIMEOUT) { + DBG_PORT80(0x13); + } + VNSvOutPortD(dwIoBase + MAC_REG_RXDMAPTR0, dwCurrDescAddr); + if (BITbIsAllBitsOn(byOrgDMACtl, DMACTL_RUN)) { + VNSvOutPortB(dwIoBase + MAC_REG_RXDMACTL0, DMACTL_RUN); + } +} + +/* + * Description: + * Set the chip with current rx descriptor address + * + * Parameters: + * In: + * dwIoBase - Base Address for MAC + * dwCurrDescAddr - Descriptor Address + * Out: + * none + * + * Return Value: none + * + */ +void MACvSetCurrRx1DescAddr (DWORD_PTR dwIoBase, DWORD dwCurrDescAddr) +{ +WORD ww; +BYTE byData; +BYTE byOrgDMACtl; + + VNSvInPortB(dwIoBase + MAC_REG_RXDMACTL1, &byOrgDMACtl); + if (BITbIsAllBitsOn(byOrgDMACtl, DMACTL_RUN)) { + VNSvOutPortB(dwIoBase + MAC_REG_RXDMACTL1+2, DMACTL_RUN); + } + for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { + VNSvInPortB(dwIoBase + MAC_REG_RXDMACTL1, &byData); + if (BITbIsAllBitsOff(byData, DMACTL_RUN)) + break; + } + if (ww == W_MAX_TIMEOUT) { + DBG_PORT80(0x14); + } + VNSvOutPortD(dwIoBase + MAC_REG_RXDMAPTR1, dwCurrDescAddr); + if (BITbIsAllBitsOn(byOrgDMACtl, DMACTL_RUN)) { + VNSvOutPortB(dwIoBase + MAC_REG_RXDMACTL1, DMACTL_RUN); + } +} + +/* + * Description: + * Set the chip with current tx0 descriptor address + * + * Parameters: + * In: + * dwIoBase - Base Address for MAC + * dwCurrDescAddr - Descriptor Address + * Out: + * none + * + * Return Value: none + * + */ +void MACvSetCurrTx0DescAddrEx (DWORD_PTR dwIoBase, DWORD dwCurrDescAddr) +{ +WORD ww; +BYTE byData; +BYTE byOrgDMACtl; + + VNSvInPortB(dwIoBase + MAC_REG_TXDMACTL0, &byOrgDMACtl); + if (BITbIsAllBitsOn(byOrgDMACtl, DMACTL_RUN)) { + VNSvOutPortB(dwIoBase + MAC_REG_TXDMACTL0+2, DMACTL_RUN); + } + for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { + VNSvInPortB(dwIoBase + MAC_REG_TXDMACTL0, &byData); + if (BITbIsAllBitsOff(byData, DMACTL_RUN)) + break; + } + if (ww == W_MAX_TIMEOUT) { + DBG_PORT80(0x25); + } + VNSvOutPortD(dwIoBase + MAC_REG_TXDMAPTR0, dwCurrDescAddr); + if (BITbIsAllBitsOn(byOrgDMACtl, DMACTL_RUN)) { + VNSvOutPortB(dwIoBase + MAC_REG_TXDMACTL0, DMACTL_RUN); + } +} + +/* + * Description: + * Set the chip with current AC0 descriptor address + * + * Parameters: + * In: + * dwIoBase - Base Address for MAC + * dwCurrDescAddr - Descriptor Address + * Out: + * none + * + * Return Value: none + * + */ + //TxDMA1 = AC0DMA +void MACvSetCurrAC0DescAddrEx (DWORD_PTR dwIoBase, DWORD dwCurrDescAddr) +{ +WORD ww; +BYTE byData; +BYTE byOrgDMACtl; + + VNSvInPortB(dwIoBase + MAC_REG_AC0DMACTL, &byOrgDMACtl); + if (BITbIsAllBitsOn(byOrgDMACtl, DMACTL_RUN)) { + VNSvOutPortB(dwIoBase + MAC_REG_AC0DMACTL+2, DMACTL_RUN); + } + for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { + VNSvInPortB(dwIoBase + MAC_REG_AC0DMACTL, &byData); + if (BITbIsAllBitsOff(byData, DMACTL_RUN)) + break; + } + if (ww == W_MAX_TIMEOUT) { + DBG_PORT80(0x26); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO" DBG_PORT80(0x26)\n"); + } + VNSvOutPortD(dwIoBase + MAC_REG_AC0DMAPTR, dwCurrDescAddr); + if (BITbIsAllBitsOn(byOrgDMACtl, DMACTL_RUN)) { + VNSvOutPortB(dwIoBase + MAC_REG_AC0DMACTL, DMACTL_RUN); + } +} + + + +void MACvSetCurrTXDescAddr (int iTxType, DWORD_PTR dwIoBase, DWORD dwCurrDescAddr) +{ + if(iTxType == TYPE_AC0DMA){ + MACvSetCurrAC0DescAddrEx(dwIoBase, dwCurrDescAddr); + }else if(iTxType == TYPE_TXDMA0){ + MACvSetCurrTx0DescAddrEx(dwIoBase, dwCurrDescAddr); + } +} + +/* + * Description: + * Micro Second Delay via MAC + * + * Parameters: + * In: + * dwIoBase - Base Address for MAC + * uDelay - Delay time (timer resolution is 4 us) + * Out: + * none + * + * Return Value: none + * + */ +VOID MACvTimer0MicroSDelay (DWORD_PTR dwIoBase, UINT uDelay) +{ +BYTE byValue; +UINT uu,ii; + + VNSvOutPortB(dwIoBase + MAC_REG_TMCTL0, 0); + VNSvOutPortD(dwIoBase + MAC_REG_TMDATA0, uDelay); + VNSvOutPortB(dwIoBase + MAC_REG_TMCTL0, (TMCTL_TMD | TMCTL_TE)); + for(ii=0;ii<66;ii++) { // assume max PCI clock is 66Mhz + for (uu = 0; uu < uDelay; uu++) { + VNSvInPortB(dwIoBase + MAC_REG_TMCTL0, &byValue); + if ((byValue == 0) || + (BITbIsAllBitsOn(byValue, TMCTL_TSUSP))) { + VNSvOutPortB(dwIoBase + MAC_REG_TMCTL0, 0); + return; + } + } + } + VNSvOutPortB(dwIoBase + MAC_REG_TMCTL0, 0); + +} + +/* + * Description: + * Micro Second One shot timer via MAC + * + * Parameters: + * In: + * dwIoBase - Base Address for MAC + * uDelay - Delay time + * Out: + * none + * + * Return Value: none + * + */ +void MACvOneShotTimer0MicroSec (DWORD_PTR dwIoBase, UINT uDelayTime) +{ + VNSvOutPortB(dwIoBase + MAC_REG_TMCTL0, 0); + VNSvOutPortD(dwIoBase + MAC_REG_TMDATA0, uDelayTime); + VNSvOutPortB(dwIoBase + MAC_REG_TMCTL0, (TMCTL_TMD | TMCTL_TE)); +} + +/* + * Description: + * Micro Second One shot timer via MAC + * + * Parameters: + * In: + * dwIoBase - Base Address for MAC + * uDelay - Delay time + * Out: + * none + * + * Return Value: none + * + */ +void MACvOneShotTimer1MicroSec (DWORD_PTR dwIoBase, UINT uDelayTime) +{ + VNSvOutPortB(dwIoBase + MAC_REG_TMCTL1, 0); + VNSvOutPortD(dwIoBase + MAC_REG_TMDATA1, uDelayTime); + VNSvOutPortB(dwIoBase + MAC_REG_TMCTL1, (TMCTL_TMD | TMCTL_TE)); +} + + +void MACvSetMISCFifo (DWORD_PTR dwIoBase, WORD wOffset, DWORD dwData) +{ + if (wOffset > 273) + return; + VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, wOffset); + VNSvOutPortD(dwIoBase + MAC_REG_MISCFFDATA, dwData); + VNSvOutPortW(dwIoBase + MAC_REG_MISCFFCTL, MISCFFCTL_WRITE); +} + + +BOOL MACbTxDMAOff (DWORD_PTR dwIoBase, UINT idx) +{ +BYTE byData; +UINT ww = 0; + + if (idx == TYPE_TXDMA0) { + VNSvOutPortB(dwIoBase + MAC_REG_TXDMACTL0+2, DMACTL_RUN); + for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { + VNSvInPortB(dwIoBase + MAC_REG_TXDMACTL0, &byData); + if (BITbIsAllBitsOff(byData, DMACTL_RUN)) + break; + } + } else if (idx == TYPE_AC0DMA) { + VNSvOutPortB(dwIoBase + MAC_REG_AC0DMACTL+2, DMACTL_RUN); + for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { + VNSvInPortB(dwIoBase + MAC_REG_AC0DMACTL, &byData); + if (BITbIsAllBitsOff(byData, DMACTL_RUN)) + break; + } + } + if (ww == W_MAX_TIMEOUT) { + DBG_PORT80(0x29); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO" DBG_PORT80(0x29)\n"); + return FALSE; + } + return TRUE; +} + +void MACvClearBusSusInd (DWORD_PTR dwIoBase) +{ + DWORD dwOrgValue; + UINT ww; + // check if BcnSusInd enabled + VNSvInPortD(dwIoBase + MAC_REG_ENCFG , &dwOrgValue); + if(BITbIsBitOff(dwOrgValue, EnCFG_BcnSusInd)) + return; + //Set BcnSusClr + dwOrgValue = dwOrgValue | EnCFG_BcnSusClr; + VNSvOutPortD(dwIoBase + MAC_REG_ENCFG, dwOrgValue); + for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { + VNSvInPortD(dwIoBase + MAC_REG_ENCFG , &dwOrgValue); + if(BITbIsBitOff(dwOrgValue, EnCFG_BcnSusInd)) + break; + } + if (ww == W_MAX_TIMEOUT) { + DBG_PORT80(0x33); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO" DBG_PORT80(0x33)\n"); + } +} + +void MACvEnableBusSusEn (DWORD_PTR dwIoBase) +{ + BYTE byOrgValue; + DWORD dwOrgValue; + UINT ww; + // check if BcnSusInd enabled + VNSvInPortB(dwIoBase + MAC_REG_CFG , &byOrgValue); + + //Set BcnSusEn + byOrgValue = byOrgValue | CFG_BCNSUSEN; + VNSvOutPortB(dwIoBase + MAC_REG_ENCFG, byOrgValue); + for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { + VNSvInPortD(dwIoBase + MAC_REG_ENCFG , &dwOrgValue); + if(BITbIsBitOn(dwOrgValue, EnCFG_BcnSusInd)) + break; + } + if (ww == W_MAX_TIMEOUT) { + DBG_PORT80(0x34); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO" DBG_PORT80(0x34)\n"); + } +} + +BOOL MACbFlushSYNCFifo (DWORD_PTR dwIoBase) +{ + BYTE byOrgValue; + UINT ww; + // Read MACCR + VNSvInPortB(dwIoBase + MAC_REG_MACCR , &byOrgValue); + + // Set SYNCFLUSH + byOrgValue = byOrgValue | MACCR_SYNCFLUSH; + VNSvOutPortB(dwIoBase + MAC_REG_MACCR, byOrgValue); + + // Check if SyncFlushOK + for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { + VNSvInPortB(dwIoBase + MAC_REG_MACCR , &byOrgValue); + if(BITbIsBitOn(byOrgValue, MACCR_SYNCFLUSHOK)) + break; + } + if (ww == W_MAX_TIMEOUT) { + DBG_PORT80(0x35); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO" DBG_PORT80(0x33)\n"); + } + return TRUE; +} + +BOOL MACbPSWakeup (DWORD_PTR dwIoBase) +{ + BYTE byOrgValue; + UINT ww; + // Read PSCTL + if (MACbIsRegBitsOff(dwIoBase, MAC_REG_PSCTL, PSCTL_PS)) { + return TRUE; + } + // Disable PS + MACvRegBitsOff(dwIoBase, MAC_REG_PSCTL, PSCTL_PSEN); + + // Check if SyncFlushOK + for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { + VNSvInPortB(dwIoBase + MAC_REG_PSCTL , &byOrgValue); + if(BITbIsBitOn(byOrgValue, PSCTL_WAKEDONE)) + break; + } + if (ww == W_MAX_TIMEOUT) { + DBG_PORT80(0x36); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO" DBG_PORT80(0x33)\n"); + return FALSE; + } + return TRUE; +} + +/* + * Description: + * Set the Key by MISCFIFO + * + * Parameters: + * In: + * dwIoBase - Base Address for MAC + * + * Out: + * none + * + * Return Value: none + * + */ + +void MACvSetKeyEntry (DWORD_PTR dwIoBase, WORD wKeyCtl, UINT uEntryIdx, UINT uKeyIdx, PBYTE pbyAddr, PDWORD pdwKey, BYTE byLocalID) +{ +WORD wOffset; +DWORD dwData; +int ii; + + if (byLocalID <= 1) + return; + + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"MACvSetKeyEntry\n"); + wOffset = MISCFIFO_KEYETRY0; + wOffset += (uEntryIdx * MISCFIFO_KEYENTRYSIZE); + + dwData = 0; + dwData |= wKeyCtl; + dwData <<= 16; + dwData |= MAKEWORD(*(pbyAddr+4), *(pbyAddr+5)); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"1. wOffset: %d, Data: %lX, KeyCtl:%X\n", wOffset, dwData, wKeyCtl); + + VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, wOffset); + VNSvOutPortD(dwIoBase + MAC_REG_MISCFFDATA, dwData); + VNSvOutPortW(dwIoBase + MAC_REG_MISCFFCTL, MISCFFCTL_WRITE); + wOffset++; + + dwData = 0; + dwData |= *(pbyAddr+3); + dwData <<= 8; + dwData |= *(pbyAddr+2); + dwData <<= 8; + dwData |= *(pbyAddr+1); + dwData <<= 8; + dwData |= *(pbyAddr+0); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"2. wOffset: %d, Data: %lX\n", wOffset, dwData); + + VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, wOffset); + VNSvOutPortD(dwIoBase + MAC_REG_MISCFFDATA, dwData); + VNSvOutPortW(dwIoBase + MAC_REG_MISCFFCTL, MISCFFCTL_WRITE); + wOffset++; + + wOffset += (uKeyIdx * 4); + for (ii=0;ii<4;ii++) { + // alway push 128 bits + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"3.(%d) wOffset: %d, Data: %lX\n", ii, wOffset+ii, *pdwKey); + VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, wOffset+ii); + VNSvOutPortD(dwIoBase + MAC_REG_MISCFFDATA, *pdwKey++); + VNSvOutPortW(dwIoBase + MAC_REG_MISCFFCTL, MISCFFCTL_WRITE); + } +} + + + +/* + * Description: + * Disable the Key Entry by MISCFIFO + * + * Parameters: + * In: + * dwIoBase - Base Address for MAC + * + * Out: + * none + * + * Return Value: none + * + */ +void MACvDisableKeyEntry (DWORD_PTR dwIoBase, UINT uEntryIdx) +{ +WORD wOffset; + + wOffset = MISCFIFO_KEYETRY0; + wOffset += (uEntryIdx * MISCFIFO_KEYENTRYSIZE); + + VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, wOffset); + VNSvOutPortD(dwIoBase + MAC_REG_MISCFFDATA, 0); + VNSvOutPortW(dwIoBase + MAC_REG_MISCFFCTL, MISCFFCTL_WRITE); +} + + +/* + * Description: + * Set the default Key (KeyEntry[10]) by MISCFIFO + * + * Parameters: + * In: + * dwIoBase - Base Address for MAC + * + * Out: + * none + * + * Return Value: none + * + */ + +void MACvSetDefaultKeyEntry (DWORD_PTR dwIoBase, UINT uKeyLen, UINT uKeyIdx, PDWORD pdwKey, BYTE byLocalID) +{ +WORD wOffset; +DWORD dwData; +int ii; + + if (byLocalID <= 1) + return; + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"MACvSetDefaultKeyEntry\n"); + wOffset = MISCFIFO_KEYETRY0; + wOffset += (10 * MISCFIFO_KEYENTRYSIZE); + + wOffset++; + wOffset++; + wOffset += (uKeyIdx * 4); + // alway push 128 bits + for (ii=0; ii<3; ii++) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"(%d) wOffset: %d, Data: %lX\n", ii, wOffset+ii, *pdwKey); + VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, wOffset+ii); + VNSvOutPortD(dwIoBase + MAC_REG_MISCFFDATA, *pdwKey++); + VNSvOutPortW(dwIoBase + MAC_REG_MISCFFCTL, MISCFFCTL_WRITE); + } + dwData = *pdwKey; + if (uKeyLen == WLAN_WEP104_KEYLEN) { + dwData |= 0x80000000; + } + VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, wOffset+3); + VNSvOutPortD(dwIoBase + MAC_REG_MISCFFDATA, dwData); + VNSvOutPortW(dwIoBase + MAC_REG_MISCFFCTL, MISCFFCTL_WRITE); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"End. wOffset: %d, Data: %lX\n", wOffset+3, dwData); + +} + + +/* + * Description: + * Enable default Key (KeyEntry[10]) by MISCFIFO + * + * Parameters: + * In: + * dwIoBase - Base Address for MAC + * + * Out: + * none + * + * Return Value: none + * + */ +/* +void MACvEnableDefaultKey (DWORD_PTR dwIoBase, BYTE byLocalID) +{ +WORD wOffset; +DWORD dwData; + + + if (byLocalID <= 1) + return; + + wOffset = MISCFIFO_KEYETRY0; + wOffset += (10 * MISCFIFO_KEYENTRYSIZE); + + dwData = 0xC0440000; + VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, wOffset); + VNSvOutPortD(dwIoBase + MAC_REG_MISCFFDATA, dwData); + VNSvOutPortW(dwIoBase + MAC_REG_MISCFFCTL, MISCFFCTL_WRITE); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"MACvEnableDefaultKey: wOffset: %d, Data: %lX\n", wOffset, dwData); + +} +*/ + +/* + * Description: + * Disable default Key (KeyEntry[10]) by MISCFIFO + * + * Parameters: + * In: + * dwIoBase - Base Address for MAC + * + * Out: + * none + * + * Return Value: none + * + */ +void MACvDisableDefaultKey (DWORD_PTR dwIoBase) +{ +WORD wOffset; +DWORD dwData; + + + wOffset = MISCFIFO_KEYETRY0; + wOffset += (10 * MISCFIFO_KEYENTRYSIZE); + + dwData = 0x0; + VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, wOffset); + VNSvOutPortD(dwIoBase + MAC_REG_MISCFFDATA, dwData); + VNSvOutPortW(dwIoBase + MAC_REG_MISCFFCTL, MISCFFCTL_WRITE); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"MACvDisableDefaultKey: wOffset: %d, Data: %lX\n", wOffset, dwData); +} + +/* + * Description: + * Set the default TKIP Group Key (KeyEntry[10]) by MISCFIFO + * + * Parameters: + * In: + * dwIoBase - Base Address for MAC + * + * Out: + * none + * + * Return Value: none + * + */ +void MACvSetDefaultTKIPKeyEntry (DWORD_PTR dwIoBase, UINT uKeyLen, UINT uKeyIdx, PDWORD pdwKey, BYTE byLocalID) +{ +WORD wOffset; +DWORD dwData; +int ii; + + if (byLocalID <= 1) + return; + + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"MACvSetDefaultTKIPKeyEntry\n"); + wOffset = MISCFIFO_KEYETRY0; + // Kyle test : change offset from 10 -> 0 + wOffset += (10 * MISCFIFO_KEYENTRYSIZE); + + dwData = 0xC0660000; + VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, wOffset); + VNSvOutPortD(dwIoBase + MAC_REG_MISCFFDATA, dwData); + VNSvOutPortW(dwIoBase + MAC_REG_MISCFFCTL, MISCFFCTL_WRITE); + wOffset++; + + dwData = 0; + VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, wOffset); + VNSvOutPortD(dwIoBase + MAC_REG_MISCFFDATA, dwData); + VNSvOutPortW(dwIoBase + MAC_REG_MISCFFCTL, MISCFFCTL_WRITE); + wOffset++; + + wOffset += (uKeyIdx * 4); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"1. wOffset: %d, Data: %lX, idx:%d\n", wOffset, *pdwKey, uKeyIdx); + // alway push 128 bits + for (ii=0; ii<4; ii++) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"2.(%d) wOffset: %d, Data: %lX\n", ii, wOffset+ii, *pdwKey); + VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, wOffset+ii); + VNSvOutPortD(dwIoBase + MAC_REG_MISCFFDATA, *pdwKey++); + VNSvOutPortW(dwIoBase + MAC_REG_MISCFFCTL, MISCFFCTL_WRITE); + } + +} + + + +/* + * Description: + * Set the Key Control by MISCFIFO + * + * Parameters: + * In: + * dwIoBase - Base Address for MAC + * + * Out: + * none + * + * Return Value: none + * + */ + +void MACvSetDefaultKeyCtl (DWORD_PTR dwIoBase, WORD wKeyCtl, UINT uEntryIdx, BYTE byLocalID) +{ +WORD wOffset; +DWORD dwData; + + if (byLocalID <= 1) + return; + + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"MACvSetKeyEntry\n"); + wOffset = MISCFIFO_KEYETRY0; + wOffset += (uEntryIdx * MISCFIFO_KEYENTRYSIZE); + + dwData = 0; + dwData |= wKeyCtl; + dwData <<= 16; + dwData |= 0xffff; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"1. wOffset: %d, Data: %lX, KeyCtl:%X\n", wOffset, dwData, wKeyCtl); + + VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, wOffset); + VNSvOutPortD(dwIoBase + MAC_REG_MISCFFDATA, dwData); + VNSvOutPortW(dwIoBase + MAC_REG_MISCFFCTL, MISCFFCTL_WRITE); + +} + diff --git a/drivers/staging/vt6655/mac.h b/drivers/staging/vt6655/mac.h new file mode 100644 index 000000000000..edb70965d4dc --- /dev/null +++ b/drivers/staging/vt6655/mac.h @@ -0,0 +1,1166 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * File: mac.h + * + * Purpose: MAC routines + * + * Author: Tevin Chen + * + * Date: May 21, 1996 + * Revision History: + * 07-01-2003 Bryan YC Fan: Re-write codes to support VT3253 spec. + * 08-25-2003 Kyle Hsu: Porting MAC functions from sim53. + * 09-03-2003 Bryan YC Fan: Add MACvDisableProtectMD & MACvEnableProtectMD + * + */ + +#ifndef __MAC_H__ +#define __MAC_H__ + + + +#if !defined(__TTYPE_H__) +#include "ttype.h" +#endif +#if !defined(__TMACRO_H__) +#include "tmacro.h" +#endif +#if !defined(__UPC_H__) +#include "upc.h" +#endif + +/*--------------------- Export Definitions -------------------------*/ +// +// Registers in the MAC +// +#define MAC_MAX_CONTEXT_SIZE_PAGE0 256 +#define MAC_MAX_CONTEXT_SIZE_PAGE1 128 +#define MAC_MAX_CONTEXT_SIZE MAC_MAX_CONTEXT_SIZE_PAGE0 + MAC_MAX_CONTEXT_SIZE_PAGE1 + +// Registers not related to 802.11b +#define MAC_REG_BCFG0 0x00 +#define MAC_REG_BCFG1 0x01 +#define MAC_REG_FCR0 0x02 +#define MAC_REG_FCR1 0x03 +#define MAC_REG_BISTCMD 0x04 +#define MAC_REG_BISTSR0 0x05 +#define MAC_REG_BISTSR1 0x06 +#define MAC_REG_BISTSR2 0x07 +#define MAC_REG_I2MCSR 0x08 +#define MAC_REG_I2MTGID 0x09 +#define MAC_REG_I2MTGAD 0x0A +#define MAC_REG_I2MCFG 0x0B +#define MAC_REG_I2MDIPT 0x0C +#define MAC_REG_I2MDOPT 0x0E +#define MAC_REG_PMC0 0x10 +#define MAC_REG_PMC1 0x11 +#define MAC_REG_STICKHW 0x12 +#define MAC_REG_LOCALID 0x14 +#define MAC_REG_TESTCFG 0x15 +#define MAC_REG_JUMPER0 0x16 +#define MAC_REG_JUMPER1 0x17 +#define MAC_REG_TMCTL0 0x18 +#define MAC_REG_TMCTL1 0x19 +#define MAC_REG_TMDATA0 0x1C +// MAC Parameter related +#define MAC_REG_LRT 0x20 // +#define MAC_REG_SRT 0x21 // +#define MAC_REG_SIFS 0x22 // +#define MAC_REG_DIFS 0x23 // +#define MAC_REG_EIFS 0x24 // +#define MAC_REG_SLOT 0x25 // +#define MAC_REG_BI 0x26 // +#define MAC_REG_CWMAXMIN0 0x28 // +#define MAC_REG_LINKOFFTOTM 0x2A +#define MAC_REG_SWTMOT 0x2B +#define MAC_REG_MIBCNTR 0x2C +#define MAC_REG_RTSOKCNT 0x2C +#define MAC_REG_RTSFAILCNT 0x2D +#define MAC_REG_ACKFAILCNT 0x2E +#define MAC_REG_FCSERRCNT 0x2F +// TSF Related +#define MAC_REG_TSFCNTR 0x30 // +#define MAC_REG_NEXTTBTT 0x38 // +#define MAC_REG_TSFOFST 0x40 // +#define MAC_REG_TFTCTL 0x48 // +// WMAC Control/Status Related +#define MAC_REG_ENCFG 0x4C // +#define MAC_REG_PAGE1SEL 0x4F // +#define MAC_REG_CFG 0x50 // +#define MAC_REG_TEST 0x52 // +#define MAC_REG_HOSTCR 0x54 // +#define MAC_REG_MACCR 0x55 // +#define MAC_REG_RCR 0x56 // +#define MAC_REG_TCR 0x57 // +#define MAC_REG_IMR 0x58 // +#define MAC_REG_ISR 0x5C +// Power Saving Related +#define MAC_REG_PSCFG 0x60 // +#define MAC_REG_PSCTL 0x61 // +#define MAC_REG_PSPWRSIG 0x62 // +#define MAC_REG_BBCR13 0x63 +#define MAC_REG_AIDATIM 0x64 +#define MAC_REG_PWBT 0x66 +#define MAC_REG_WAKEOKTMR 0x68 +#define MAC_REG_CALTMR 0x69 +#define MAC_REG_SYNSPACCNT 0x6A +#define MAC_REG_WAKSYNOPT 0x6B +// Baseband/IF Control Group +#define MAC_REG_BBREGCTL 0x6C // +#define MAC_REG_CHANNEL 0x6D +#define MAC_REG_BBREGADR 0x6E +#define MAC_REG_BBREGDATA 0x6F +#define MAC_REG_IFREGCTL 0x70 // +#define MAC_REG_IFDATA 0x71 // +#define MAC_REG_ITRTMSET 0x74 // +#define MAC_REG_PAPEDELAY 0x77 // +#define MAC_REG_SOFTPWRCTL 0x78 // +#define MAC_REG_GPIOCTL0 0x7A // +#define MAC_REG_GPIOCTL1 0x7B // + +// MAC DMA Related Group +#define MAC_REG_TXDMACTL0 0x7C // +#define MAC_REG_TXDMAPTR0 0x80 // +#define MAC_REG_AC0DMACTL 0x84 // +#define MAC_REG_AC0DMAPTR 0x88 // +#define MAC_REG_BCNDMACTL 0x8C // +#define MAC_REG_BCNDMAPTR 0x90 // +#define MAC_REG_RXDMACTL0 0x94 // +#define MAC_REG_RXDMAPTR0 0x98 // +#define MAC_REG_RXDMACTL1 0x9C // +#define MAC_REG_RXDMAPTR1 0xA0 // +#define MAC_REG_SYNCDMACTL 0xA4 // +#define MAC_REG_SYNCDMAPTR 0xA8 +#define MAC_REG_ATIMDMACTL 0xAC +#define MAC_REG_ATIMDMAPTR 0xB0 +// MiscFF PIO related +#define MAC_REG_MISCFFNDEX 0xB4 +#define MAC_REG_MISCFFCTL 0xB6 +#define MAC_REG_MISCFFDATA 0xB8 +// Extend SW Timer +#define MAC_REG_TMDATA1 0xBC +// WOW Related Group +#define MAC_REG_WAKEUPEN0 0xC0 +#define MAC_REG_WAKEUPEN1 0xC1 +#define MAC_REG_WAKEUPSR0 0xC2 +#define MAC_REG_WAKEUPSR1 0xC3 +#define MAC_REG_WAKE128_0 0xC4 +#define MAC_REG_WAKE128_1 0xD4 +#define MAC_REG_WAKE128_2 0xE4 +#define MAC_REG_WAKE128_3 0xF4 + +/////////////// Page 1 /////////////////// +#define MAC_REG_CRC_128_0 0x04 +#define MAC_REG_CRC_128_1 0x06 +#define MAC_REG_CRC_128_2 0x08 +#define MAC_REG_CRC_128_3 0x0A +// MAC Configuration Group +#define MAC_REG_PAR0 0x0C +#define MAC_REG_PAR4 0x10 +#define MAC_REG_BSSID0 0x14 +#define MAC_REG_BSSID4 0x18 +#define MAC_REG_MAR0 0x1C +#define MAC_REG_MAR4 0x20 +// MAC RSPPKT INFO Group +#define MAC_REG_RSPINF_B_1 0x24 +#define MAC_REG_RSPINF_B_2 0x28 +#define MAC_REG_RSPINF_B_5 0x2C +#define MAC_REG_RSPINF_B_11 0x30 +#define MAC_REG_RSPINF_A_6 0x34 +#define MAC_REG_RSPINF_A_9 0x36 +#define MAC_REG_RSPINF_A_12 0x38 +#define MAC_REG_RSPINF_A_18 0x3A +#define MAC_REG_RSPINF_A_24 0x3C +#define MAC_REG_RSPINF_A_36 0x3E +#define MAC_REG_RSPINF_A_48 0x40 +#define MAC_REG_RSPINF_A_54 0x42 +#define MAC_REG_RSPINF_A_72 0x44 + +// 802.11h relative +#define MAC_REG_QUIETINIT 0x60 +#define MAC_REG_QUIETGAP 0x62 +#define MAC_REG_QUIETDUR 0x64 +#define MAC_REG_MSRCTL 0x66 +#define MAC_REG_MSRBBSTS 0x67 +#define MAC_REG_MSRSTART 0x68 +#define MAC_REG_MSRDURATION 0x70 +#define MAC_REG_CCAFRACTION 0x72 +#define MAC_REG_PWRCCK 0x73 +#define MAC_REG_PWROFDM 0x7C + + +// +// Bits in the BCFG0 register +// +#define BCFG0_PERROFF 0x40 +#define BCFG0_MRDMDIS 0x20 +#define BCFG0_MRDLDIS 0x10 +#define BCFG0_MWMEN 0x08 +#define BCFG0_VSERREN 0x02 +#define BCFG0_LATMEN 0x01 + +// +// Bits in the BCFG1 register +// +#define BCFG1_CFUNOPT 0x80 +#define BCFG1_CREQOPT 0x40 +#define BCFG1_DMA8 0x10 +#define BCFG1_ARBITOPT 0x08 +#define BCFG1_PCIMEN 0x04 +#define BCFG1_MIOEN 0x02 +#define BCFG1_CISDLYEN 0x01 + +// Bits in RAMBIST registers +#define BISTCMD_TSTPAT5 0x00 // +#define BISTCMD_TSTPATA 0x80 // +#define BISTCMD_TSTERR 0x20 // +#define BISTCMD_TSTPATF 0x18 // +#define BISTCMD_TSTPAT0 0x10 // +#define BISTCMD_TSTMODE 0x04 // +#define BISTCMD_TSTITTX 0x03 // +#define BISTCMD_TSTATRX 0x02 // +#define BISTCMD_TSTATTX 0x01 // +#define BISTCMD_TSTRX 0x00 // +#define BISTSR0_BISTGO 0x01 // +#define BISTSR1_TSTSR 0x01 // +#define BISTSR2_CMDPRTEN 0x02 // +#define BISTSR2_RAMTSTEN 0x01 // + +// +// Bits in the I2MCFG EEPROM register +// +#define I2MCFG_BOUNDCTL 0x80 +#define I2MCFG_WAITCTL 0x20 +#define I2MCFG_SCLOECTL 0x10 +#define I2MCFG_WBUSYCTL 0x08 +#define I2MCFG_NORETRY 0x04 +#define I2MCFG_I2MLDSEQ 0x02 +#define I2MCFG_I2CMFAST 0x01 + +// +// Bits in the I2MCSR EEPROM register +// +#define I2MCSR_EEMW 0x80 +#define I2MCSR_EEMR 0x40 +#define I2MCSR_AUTOLD 0x08 +#define I2MCSR_NACK 0x02 +#define I2MCSR_DONE 0x01 + +// +// Bits in the PMC1 register +// +#define SPS_RST 0x80 +#define PCISTIKY 0x40 +#define PME_OVR 0x02 + +// +// Bits in the STICKYHW register +// +#define STICKHW_DS1_SHADOW 0x02 +#define STICKHW_DS0_SHADOW 0x01 + +// +// Bits in the TMCTL register +// +#define TMCTL_TSUSP 0x04 +#define TMCTL_TMD 0x02 +#define TMCTL_TE 0x01 + +// +// Bits in the TFTCTL register +// +#define TFTCTL_HWUTSF 0x80 // +#define TFTCTL_TBTTSYNC 0x40 +#define TFTCTL_HWUTSFEN 0x20 +#define TFTCTL_TSFCNTRRD 0x10 // +#define TFTCTL_TBTTSYNCEN 0x08 // +#define TFTCTL_TSFSYNCEN 0x04 // +#define TFTCTL_TSFCNTRST 0x02 // +#define TFTCTL_TSFCNTREN 0x01 // + +// +// Bits in the EnhanceCFG register +// +#define EnCFG_BarkerPream 0x00020000 +#define EnCFG_NXTBTTCFPSTR 0x00010000 +//#define EnCFG_TXLMT3UPDATE 0x00008000 +//#define EnCFG_TXLMT2UPDATE 0x00004000 +//#define EnCFG_TXLMT1UPDATE 0x00002000 +//#define EnCFG_TXLMT3EN 0x00001000 +//#define EnCFG_TXLMT2EN 0x00000800 +//#define EnCFG_TXLMT1EN 0x00000400 +#define EnCFG_BcnSusClr 0x00000200 +#define EnCFG_BcnSusInd 0x00000100 +//#define EnCFG_CWOFF1 0x00000080 +#define EnCFG_CFP_ProtectEn 0x00000040 +#define EnCFG_ProtectMd 0x00000020 +#define EnCFG_HwParCFP 0x00000010 +//#define EnCFG_QOS 0x00000008 +#define EnCFG_CFNULRSP 0x00000004 +#define EnCFG_BBType_MASK 0x00000003 +#define EnCFG_BBType_g 0x00000002 +#define EnCFG_BBType_b 0x00000001 +#define EnCFG_BBType_a 0x00000000 + +// +// Bits in the Page1Sel register +// +#define PAGE1_SEL 0x01 + +// +// Bits in the CFG register +// +#define CFG_TKIPOPT 0x80 +#define CFG_RXDMAOPT 0x40 +#define CFG_TMOT_SW 0x20 +#define CFG_TMOT_HWLONG 0x10 +#define CFG_TMOT_HW 0x00 +#define CFG_CFPENDOPT 0x08 +#define CFG_BCNSUSEN 0x04 +#define CFG_NOTXTIMEOUT 0x02 +#define CFG_NOBUFOPT 0x01 + +// +// Bits in the TEST register +// +#define TEST_LBEXT 0x80 // +#define TEST_LBINT 0x40 // +#define TEST_LBNONE 0x00 // +#define TEST_SOFTINT 0x20 // +#define TEST_CONTTX 0x10 // +#define TEST_TXPE 0x08 // +#define TEST_NAVDIS 0x04 // +#define TEST_NOCTS 0x02 // +#define TEST_NOACK 0x01 // + +// +// Bits in the HOSTCR register +// +#define HOSTCR_TXONST 0x80 // +#define HOSTCR_RXONST 0x40 // +#define HOSTCR_ADHOC 0x20 // Network Type 1 = Ad-hoc +#define HOSTCR_AP 0x10 // Port Type 1 = AP +#define HOSTCR_TXON 0x08 //0000 1000 +#define HOSTCR_RXON 0x04 //0000 0100 +#define HOSTCR_MACEN 0x02 //0000 0010 +#define HOSTCR_SOFTRST 0x01 //0000 0001 + +// +// Bits in the MACCR register +// +#define MACCR_SYNCFLUSHOK 0x04 // +#define MACCR_SYNCFLUSH 0x02 // +#define MACCR_CLRNAV 0x01 // + +// Bits in the MAC_REG_GPIOCTL0 register +// +#define LED_ACTSET 0x01 // +#define LED_RFOFF 0x02 // +#define LED_NOCONNECT 0x04 // +// +// Bits in the RCR register +// +#define RCR_SSID 0x80 +#define RCR_RXALLTYPE 0x40 // +#define RCR_UNICAST 0x20 // +#define RCR_BROADCAST 0x10 // +#define RCR_MULTICAST 0x08 // +#define RCR_WPAERR 0x04 // +#define RCR_ERRCRC 0x02 // +#define RCR_BSSID 0x01 // + +// +// Bits in the TCR register +// +#define TCR_SYNCDCFOPT 0x02 // +#define TCR_AUTOBCNTX 0x01 // Beacon automatically transmit enable + +// +// Bits in the IMR register +// +#define IMR_MEASURESTART 0x80000000 // +#define IMR_QUIETSTART 0x20000000 // +#define IMR_RADARDETECT 0x10000000 // +#define IMR_MEASUREEND 0x08000000 // +#define IMR_SOFTTIMER1 0x00200000 // +//#define IMR_SYNCFLUSHOK 0x00100000 // +//#define IMR_ATIMEND 0x00080000 //0000 1000 0000 0000 0000 0000 +//#define IMR_CFPEND 0x00040000 //0000 0100 0000 0000 0000 0000 +//#define IMR_AC3DMA 0x00020000 //0000 0010 0000 0000 0000 0000 +//#define IMR_AC2DMA 0x00010000 //0000 0001 0000 0000 0000 0000 +//#define IMR_AC1DMA 0x00008000 //0000 0000 1000 0000 0000 0000 +//#define IMR_SYNCTX 0x00004000 //0000 0000 0100 0000 0000 0000 +//#define IMR_ATIMTX 0x00002000 //0000 0000 0010 0000 0000 0000 +#define IMR_RXDMA1 0x00001000 //0000 0000 0001 0000 0000 0000 +#define IMR_RXNOBUF 0x00000800 // +#define IMR_MIBNEARFULL 0x00000400 // +#define IMR_SOFTINT 0x00000200 // +#define IMR_FETALERR 0x00000100 // +#define IMR_WATCHDOG 0x00000080 // +#define IMR_SOFTTIMER 0x00000040 // +#define IMR_GPIO 0x00000020 // +#define IMR_TBTT 0x00000010 // +#define IMR_RXDMA0 0x00000008 // +#define IMR_BNTX 0x00000004 // +#define IMR_AC0DMA 0x00000002 // +#define IMR_TXDMA0 0x00000001 // + + +// +// Bits in the ISR register +// + +#define ISR_MEASURESTART 0x80000000 // +#define ISR_QUIETSTART 0x20000000 // +#define ISR_RADARDETECT 0x10000000 // +#define ISR_MEASUREEND 0x08000000 // +#define ISR_SOFTTIMER1 0x00200000 // +//#define ISR_SYNCFLUSHOK 0x00100000 //0001 0000 0000 0000 0000 0000 +//#define ISR_ATIMEND 0x00080000 //0000 1000 0000 0000 0000 0000 +//#define ISR_CFPEND 0x00040000 //0000 0100 0000 0000 0000 0000 +//#define ISR_AC3DMA 0x00020000 //0000 0010 0000 0000 0000 0000 +//#define ISR_AC2DMA 0x00010000 //0000 0001 0000 0000 0000 0000 +//#define ISR_AC1DMA 0x00008000 //0000 0000 1000 0000 0000 0000 +//#define ISR_SYNCTX 0x00004000 //0000 0000 0100 0000 0000 0000 +//#define ISR_ATIMTX 0x00002000 //0000 0000 0010 0000 0000 0000 +#define ISR_RXDMA1 0x00001000 //0000 0000 0001 0000 0000 0000 +#define ISR_RXNOBUF 0x00000800 //0000 0000 0000 1000 0000 0000 +#define ISR_MIBNEARFULL 0x00000400 //0000 0000 0000 0100 0000 0000 +#define ISR_SOFTINT 0x00000200 // +#define ISR_FETALERR 0x00000100 // +#define ISR_WATCHDOG 0x00000080 // +#define ISR_SOFTTIMER 0x00000040 // +#define ISR_GPIO 0x00000020 // +#define ISR_TBTT 0x00000010 // +#define ISR_RXDMA0 0x00000008 // +#define ISR_BNTX 0x00000004 // +#define ISR_AC0DMA 0x00000002 // +#define ISR_TXDMA0 0x00000001 // + + +// +// Bits in the PSCFG register +// +#define PSCFG_PHILIPMD 0x40 // +#define PSCFG_WAKECALEN 0x20 // +#define PSCFG_WAKETMREN 0x10 // +#define PSCFG_BBPSPROG 0x08 // +#define PSCFG_WAKESYN 0x04 // +#define PSCFG_SLEEPSYN 0x02 // +#define PSCFG_AUTOSLEEP 0x01 // + +// +// Bits in the PSCTL register +// +#define PSCTL_WAKEDONE 0x20 // +#define PSCTL_PS 0x10 // +#define PSCTL_GO2DOZE 0x08 // +#define PSCTL_LNBCN 0x04 // +#define PSCTL_ALBCN 0x02 // +#define PSCTL_PSEN 0x01 // + +// +// Bits in the PSPWSIG register +// +#define PSSIG_WPE3 0x80 // +#define PSSIG_WPE2 0x40 // +#define PSSIG_WPE1 0x20 // +#define PSSIG_WRADIOPE 0x10 // +#define PSSIG_SPE3 0x08 // +#define PSSIG_SPE2 0x04 // +#define PSSIG_SPE1 0x02 // +#define PSSIG_SRADIOPE 0x01 // + +// +// Bits in the BBREGCTL register +// +#define BBREGCTL_DONE 0x04 // +#define BBREGCTL_REGR 0x02 // +#define BBREGCTL_REGW 0x01 // + +// +// Bits in the IFREGCTL register +// +#define IFREGCTL_DONE 0x04 // +#define IFREGCTL_IFRF 0x02 // +#define IFREGCTL_REGW 0x01 // + +// +// Bits in the SOFTPWRCTL register +// +#define SOFTPWRCTL_RFLEOPT 0x0800 // +#define SOFTPWRCTL_TXPEINV 0x0200 // +#define SOFTPWRCTL_SWPECTI 0x0100 // +#define SOFTPWRCTL_SWPAPE 0x0020 // +#define SOFTPWRCTL_SWCALEN 0x0010 // +#define SOFTPWRCTL_SWRADIO_PE 0x0008 // +#define SOFTPWRCTL_SWPE2 0x0004 // +#define SOFTPWRCTL_SWPE1 0x0002 // +#define SOFTPWRCTL_SWPE3 0x0001 // + +// +// Bits in the GPIOCTL1 register +// +#define GPIO1_DATA1 0x20 // +#define GPIO1_MD1 0x10 // +#define GPIO1_DATA0 0x02 // +#define GPIO1_MD0 0x01 // + +// +// Bits in the DMACTL register +// +#define DMACTL_CLRRUN 0x00080000 // +#define DMACTL_RUN 0x00000008 // +#define DMACTL_WAKE 0x00000004 // +#define DMACTL_DEAD 0x00000002 // +#define DMACTL_ACTIVE 0x00000001 // +// +// Bits in the RXDMACTL0 register +// +#define RX_PERPKT 0x00000100 // +#define RX_PERPKTCLR 0x01000000 // +// +// Bits in the BCNDMACTL register +// +#define BEACON_READY 0x01 // +// +// Bits in the MISCFFCTL register +// +#define MISCFFCTL_WRITE 0x0001 // + + +// +// Bits in WAKEUPEN0 +// +#define WAKEUPEN0_DIRPKT 0x10 +#define WAKEUPEN0_LINKOFF 0x08 +#define WAKEUPEN0_ATIMEN 0x04 +#define WAKEUPEN0_TIMEN 0x02 +#define WAKEUPEN0_MAGICEN 0x01 + +// +// Bits in WAKEUPEN1 +// +#define WAKEUPEN1_128_3 0x08 +#define WAKEUPEN1_128_2 0x04 +#define WAKEUPEN1_128_1 0x02 +#define WAKEUPEN1_128_0 0x01 + +// +// Bits in WAKEUPSR0 +// +#define WAKEUPSR0_DIRPKT 0x10 +#define WAKEUPSR0_LINKOFF 0x08 +#define WAKEUPSR0_ATIMEN 0x04 +#define WAKEUPSR0_TIMEN 0x02 +#define WAKEUPSR0_MAGICEN 0x01 + +// +// Bits in WAKEUPSR1 +// +#define WAKEUPSR1_128_3 0x08 +#define WAKEUPSR1_128_2 0x04 +#define WAKEUPSR1_128_1 0x02 +#define WAKEUPSR1_128_0 0x01 + +// +// Bits in the MAC_REG_GPIOCTL register +// +#define GPIO0_MD 0x01 // +#define GPIO0_DATA 0x02 // +#define GPIO0_INTMD 0x04 // +#define GPIO1_MD 0x10 // +#define GPIO1_DATA 0x20 // + + +// +// Bits in the MSRCTL register +// +#define MSRCTL_FINISH 0x80 +#define MSRCTL_READY 0x40 +#define MSRCTL_RADARDETECT 0x20 +#define MSRCTL_EN 0x10 +#define MSRCTL_QUIETTXCHK 0x08 +#define MSRCTL_QUIETRPT 0x04 +#define MSRCTL_QUIETINT 0x02 +#define MSRCTL_QUIETEN 0x01 +// +// Bits in the MSRCTL1 register +// +#define MSRCTL1_TXPWR 0x08 +#define MSRCTL1_CSAPAREN 0x04 +#define MSRCTL1_TXPAUSE 0x01 + + +// Loopback mode +#define MAC_LB_EXT 0x02 // +#define MAC_LB_INTERNAL 0x01 // +#define MAC_LB_NONE 0x00 // + +// Ethernet address filter type +#define PKT_TYPE_NONE 0x00 // turn off receiver +#define PKT_TYPE_ALL_MULTICAST 0x80 +#define PKT_TYPE_PROMISCUOUS 0x40 +#define PKT_TYPE_DIRECTED 0x20 // obselete, directed address is always accepted +#define PKT_TYPE_BROADCAST 0x10 +#define PKT_TYPE_MULTICAST 0x08 +#define PKT_TYPE_ERROR_WPA 0x04 +#define PKT_TYPE_ERROR_CRC 0x02 +#define PKT_TYPE_BSSID 0x01 + +#define Default_BI 0x200 + + +// MiscFIFO Offset +#define MISCFIFO_KEYETRY0 32 +#define MISCFIFO_KEYENTRYSIZE 22 +#define MISCFIFO_SYNINFO_IDX 10 +#define MISCFIFO_SYNDATA_IDX 11 +#define MISCFIFO_SYNDATASIZE 21 + +// enabled mask value of irq +#define IMR_MASK_VALUE (IMR_SOFTTIMER1 | \ + IMR_RXDMA1 | \ + IMR_RXNOBUF | \ + IMR_MIBNEARFULL | \ + IMR_SOFTINT | \ + IMR_FETALERR | \ + IMR_WATCHDOG | \ + IMR_SOFTTIMER | \ + IMR_GPIO | \ + IMR_TBTT | \ + IMR_RXDMA0 | \ + IMR_BNTX | \ + IMR_AC0DMA | \ + IMR_TXDMA0) + +// max time out delay time +#define W_MAX_TIMEOUT 0xFFF0U // + +// wait time within loop +#define CB_DELAY_LOOP_WAIT 10 // 10ms + +// +// revision id +// +#define REV_ID_VT3253_A0 0x00 +#define REV_ID_VT3253_A1 0x01 +#define REV_ID_VT3253_B0 0x08 +#define REV_ID_VT3253_B1 0x09 + +/*--------------------- Export Types ------------------------------*/ + +/*--------------------- Export Macros ------------------------------*/ + +#define MACvRegBitsOn(dwIoBase, byRegOfs, byBits) \ +{ \ + BYTE byData; \ + VNSvInPortB(dwIoBase + byRegOfs, &byData); \ + VNSvOutPortB(dwIoBase + byRegOfs, byData | (byBits)); \ +} + +#define MACvWordRegBitsOn(dwIoBase, byRegOfs, wBits) \ +{ \ + WORD wData; \ + VNSvInPortW(dwIoBase + byRegOfs, &wData); \ + VNSvOutPortW(dwIoBase + byRegOfs, wData | (wBits)); \ +} + +#define MACvDWordRegBitsOn(dwIoBase, byRegOfs, dwBits) \ +{ \ + DWORD dwData; \ + VNSvInPortD(dwIoBase + byRegOfs, &dwData); \ + VNSvOutPortD(dwIoBase + byRegOfs, dwData | (dwBits)); \ +} + +#define MACvRegBitsOnEx(dwIoBase, byRegOfs, byMask, byBits) \ +{ \ + BYTE byData; \ + VNSvInPortB(dwIoBase + byRegOfs, &byData); \ + byData &= byMask; \ + VNSvOutPortB(dwIoBase + byRegOfs, byData | (byBits)); \ +} + +#define MACvRegBitsOff(dwIoBase, byRegOfs, byBits) \ +{ \ + BYTE byData; \ + VNSvInPortB(dwIoBase + byRegOfs, &byData); \ + VNSvOutPortB(dwIoBase + byRegOfs, byData & ~(byBits)); \ +} + +#define MACvWordRegBitsOff(dwIoBase, byRegOfs, wBits) \ +{ \ + WORD wData; \ + VNSvInPortW(dwIoBase + byRegOfs, &wData); \ + VNSvOutPortW(dwIoBase + byRegOfs, wData & ~(wBits)); \ +} + +#define MACvDWordRegBitsOff(dwIoBase, byRegOfs, dwBits) \ +{ \ + DWORD dwData; \ + VNSvInPortD(dwIoBase + byRegOfs, &dwData); \ + VNSvOutPortD(dwIoBase + byRegOfs, dwData & ~(dwBits)); \ +} + +#define MACvGetCurrRx0DescAddr(dwIoBase, pdwCurrDescAddr) \ +{ \ + VNSvInPortD(dwIoBase + MAC_REG_RXDMAPTR0, \ + (PDWORD)pdwCurrDescAddr); \ +} + +#define MACvGetCurrRx1DescAddr(dwIoBase, pdwCurrDescAddr) \ +{ \ + VNSvInPortD(dwIoBase + MAC_REG_RXDMAPTR1, \ + (PDWORD)pdwCurrDescAddr); \ +} + +#define MACvGetCurrTx0DescAddr(dwIoBase, pdwCurrDescAddr) \ +{ \ + VNSvInPortD(dwIoBase + MAC_REG_TXDMAPTR0, \ + (PDWORD)pdwCurrDescAddr); \ +} + +#define MACvGetCurrAC0DescAddr(dwIoBase, pdwCurrDescAddr) \ +{ \ + VNSvInPortD(dwIoBase + MAC_REG_AC0DMAPTR, \ + (PDWORD)pdwCurrDescAddr); \ +} + +#define MACvGetCurrSyncDescAddr(dwIoBase, pdwCurrDescAddr) \ +{ \ + VNSvInPortD(dwIoBase + MAC_REG_SYNCDMAPTR, \ + (PDWORD)pdwCurrDescAddr); \ +} + +#define MACvGetCurrATIMDescAddr(dwIoBase, pdwCurrDescAddr) \ +{ \ + VNSvInPortD(dwIoBase + MAC_REG_ATIMDMAPTR, \ + (PDWORD)pdwCurrDescAddr); \ +} \ + +// set the chip with current BCN tx descriptor address +#define MACvSetCurrBCNTxDescAddr(dwIoBase, dwCurrDescAddr) \ +{ \ + VNSvOutPortD(dwIoBase + MAC_REG_BCNDMAPTR, \ + dwCurrDescAddr); \ +} + +// set the chip with current BCN length +#define MACvSetCurrBCNLength(dwIoBase, wCurrBCNLength) \ +{ \ + VNSvOutPortW(dwIoBase + MAC_REG_BCNDMACTL+2, \ + wCurrBCNLength); \ +} + +#define MACvReadBSSIDAddress(dwIoBase, pbyEtherAddr) \ +{ \ + VNSvOutPortB(dwIoBase + MAC_REG_PAGE1SEL, 1); \ + VNSvInPortB(dwIoBase + MAC_REG_BSSID0, \ + (PBYTE)pbyEtherAddr); \ + VNSvInPortB(dwIoBase + MAC_REG_BSSID0 + 1, \ + pbyEtherAddr + 1); \ + VNSvInPortB(dwIoBase + MAC_REG_BSSID0 + 2, \ + pbyEtherAddr + 2); \ + VNSvInPortB(dwIoBase + MAC_REG_BSSID0 + 3, \ + pbyEtherAddr + 3); \ + VNSvInPortB(dwIoBase + MAC_REG_BSSID0 + 4, \ + pbyEtherAddr + 4); \ + VNSvInPortB(dwIoBase + MAC_REG_BSSID0 + 5, \ + pbyEtherAddr + 5); \ + VNSvOutPortB(dwIoBase + MAC_REG_PAGE1SEL, 0); \ +} + +#define MACvWriteBSSIDAddress(dwIoBase, pbyEtherAddr) \ +{ \ + VNSvOutPortB(dwIoBase + MAC_REG_PAGE1SEL, 1); \ + VNSvOutPortB(dwIoBase + MAC_REG_BSSID0, \ + *(pbyEtherAddr)); \ + VNSvOutPortB(dwIoBase + MAC_REG_BSSID0 + 1, \ + *(pbyEtherAddr + 1)); \ + VNSvOutPortB(dwIoBase + MAC_REG_BSSID0 + 2, \ + *(pbyEtherAddr + 2)); \ + VNSvOutPortB(dwIoBase + MAC_REG_BSSID0 + 3, \ + *(pbyEtherAddr + 3)); \ + VNSvOutPortB(dwIoBase + MAC_REG_BSSID0 + 4, \ + *(pbyEtherAddr + 4)); \ + VNSvOutPortB(dwIoBase + MAC_REG_BSSID0 + 5, \ + *(pbyEtherAddr + 5)); \ + VNSvOutPortB(dwIoBase + MAC_REG_PAGE1SEL, 0); \ +} + +#define MACvReadEtherAddress(dwIoBase, pbyEtherAddr) \ +{ \ + VNSvOutPortB(dwIoBase + MAC_REG_PAGE1SEL, 1); \ + VNSvInPortB(dwIoBase + MAC_REG_PAR0, \ + (PBYTE)pbyEtherAddr); \ + VNSvInPortB(dwIoBase + MAC_REG_PAR0 + 1, \ + pbyEtherAddr + 1); \ + VNSvInPortB(dwIoBase + MAC_REG_PAR0 + 2, \ + pbyEtherAddr + 2); \ + VNSvInPortB(dwIoBase + MAC_REG_PAR0 + 3, \ + pbyEtherAddr + 3); \ + VNSvInPortB(dwIoBase + MAC_REG_PAR0 + 4, \ + pbyEtherAddr + 4); \ + VNSvInPortB(dwIoBase + MAC_REG_PAR0 + 5, \ + pbyEtherAddr + 5); \ + VNSvOutPortB(dwIoBase + MAC_REG_PAGE1SEL, 0); \ +} + + +#define MACvWriteEtherAddress(dwIoBase, pbyEtherAddr) \ +{ \ + VNSvOutPortB(dwIoBase + MAC_REG_PAGE1SEL, 1); \ + VNSvOutPortB(dwIoBase + MAC_REG_PAR0, \ + *pbyEtherAddr); \ + VNSvOutPortB(dwIoBase + MAC_REG_PAR0 + 1, \ + *(pbyEtherAddr + 1)); \ + VNSvOutPortB(dwIoBase + MAC_REG_PAR0 + 2, \ + *(pbyEtherAddr + 2)); \ + VNSvOutPortB(dwIoBase + MAC_REG_PAR0 + 3, \ + *(pbyEtherAddr + 3)); \ + VNSvOutPortB(dwIoBase + MAC_REG_PAR0 + 4, \ + *(pbyEtherAddr + 4)); \ + VNSvOutPortB(dwIoBase + MAC_REG_PAR0 + 5, \ + *(pbyEtherAddr + 5)); \ + VNSvOutPortB(dwIoBase + MAC_REG_PAGE1SEL, 0); \ +} + + +#define MACvClearISR(dwIoBase) \ +{ \ + VNSvOutPortD(dwIoBase + MAC_REG_ISR, IMR_MASK_VALUE); \ +} + +#define MACvStart(dwIoBase) \ +{ \ + VNSvOutPortB(dwIoBase + MAC_REG_HOSTCR, \ + (HOSTCR_MACEN | HOSTCR_RXON | HOSTCR_TXON)); \ +} + +#define MACvRx0PerPktMode(dwIoBase) \ +{ \ + VNSvOutPortD(dwIoBase + MAC_REG_RXDMACTL0, RX_PERPKT); \ +} + +#define MACvRx0BufferFillMode(dwIoBase) \ +{ \ + VNSvOutPortD(dwIoBase + MAC_REG_RXDMACTL0, RX_PERPKTCLR); \ +} + +#define MACvRx1PerPktMode(dwIoBase) \ +{ \ + VNSvOutPortD(dwIoBase + MAC_REG_RXDMACTL1, RX_PERPKT); \ +} + +#define MACvRx1BufferFillMode(dwIoBase) \ +{ \ + VNSvOutPortD(dwIoBase + MAC_REG_RXDMACTL1, RX_PERPKTCLR); \ +} + +#define MACvRxOn(dwIoBase) \ +{ \ + MACvRegBitsOn(dwIoBase, MAC_REG_HOSTCR, HOSTCR_RXON); \ +} + +#define MACvReceive0(dwIoBase) \ +{ \ + DWORD dwData; \ + VNSvInPortD(dwIoBase + MAC_REG_RXDMACTL0, &dwData); \ + if (dwData & DMACTL_RUN) { \ + VNSvOutPortD(dwIoBase + MAC_REG_RXDMACTL0, DMACTL_WAKE);\ + } \ + else { \ + VNSvOutPortD(dwIoBase + MAC_REG_RXDMACTL0, DMACTL_RUN); \ + } \ +} + +#define MACvReceive1(dwIoBase) \ +{ \ + DWORD dwData; \ + VNSvInPortD(dwIoBase + MAC_REG_RXDMACTL1, &dwData); \ + if (dwData & DMACTL_RUN) { \ + VNSvOutPortD(dwIoBase + MAC_REG_RXDMACTL1, DMACTL_WAKE);\ + } \ + else { \ + VNSvOutPortD(dwIoBase + MAC_REG_RXDMACTL1, DMACTL_RUN); \ + } \ +} + +#define MACvTxOn(dwIoBase) \ +{ \ + MACvRegBitsOn(dwIoBase, MAC_REG_HOSTCR, HOSTCR_TXON); \ +} + +#define MACvTransmit0(dwIoBase) \ +{ \ + DWORD dwData; \ + VNSvInPortD(dwIoBase + MAC_REG_TXDMACTL0, &dwData); \ + if (dwData & DMACTL_RUN) { \ + VNSvOutPortD(dwIoBase + MAC_REG_TXDMACTL0, DMACTL_WAKE);\ + } \ + else { \ + VNSvOutPortD(dwIoBase + MAC_REG_TXDMACTL0, DMACTL_RUN); \ + } \ +} + +#define MACvTransmitAC0(dwIoBase) \ +{ \ + DWORD dwData; \ + VNSvInPortD(dwIoBase + MAC_REG_AC0DMACTL, &dwData); \ + if (dwData & DMACTL_RUN) { \ + VNSvOutPortD(dwIoBase + MAC_REG_AC0DMACTL, DMACTL_WAKE);\ + } \ + else { \ + VNSvOutPortD(dwIoBase + MAC_REG_AC0DMACTL, DMACTL_RUN); \ + } \ +} + +#define MACvTransmitSYNC(dwIoBase) \ +{ \ + DWORD dwData; \ + VNSvInPortD(dwIoBase + MAC_REG_SYNCDMACTL, &dwData); \ + if (dwData & DMACTL_RUN) { \ + VNSvOutPortD(dwIoBase + MAC_REG_SYNCDMACTL, DMACTL_WAKE);\ + } \ + else { \ + VNSvOutPortD(dwIoBase + MAC_REG_SYNCDMACTL, DMACTL_RUN); \ + } \ +} + +#define MACvTransmitATIM(dwIoBase) \ +{ \ + DWORD dwData; \ + VNSvInPortD(dwIoBase + MAC_REG_ATIMDMACTL, &dwData); \ + if (dwData & DMACTL_RUN) { \ + VNSvOutPortD(dwIoBase + MAC_REG_ATIMDMACTL, DMACTL_WAKE);\ + } \ + else { \ + VNSvOutPortD(dwIoBase + MAC_REG_ATIMDMACTL, DMACTL_RUN); \ + } \ +} + +#define MACvTransmitBCN(dwIoBase) \ +{ \ + VNSvOutPortB(dwIoBase + MAC_REG_BCNDMACTL, BEACON_READY); \ +} + +#define MACvClearStckDS(dwIoBase) \ +{ \ + BYTE byOrgValue; \ + VNSvInPortB(dwIoBase + MAC_REG_STICKHW, &byOrgValue); \ + byOrgValue = byOrgValue & 0xFC; \ + VNSvOutPortB(dwIoBase + MAC_REG_STICKHW, byOrgValue); \ +} + +#define MACvReadISR(dwIoBase, pdwValue) \ +{ \ + VNSvInPortD(dwIoBase + MAC_REG_ISR, pdwValue); \ +} + +#define MACvWriteISR(dwIoBase, dwValue) \ +{ \ + VNSvOutPortD(dwIoBase + MAC_REG_ISR, dwValue); \ +} + +#define MACvIntEnable(dwIoBase, dwMask) \ +{ \ + VNSvOutPortD(dwIoBase + MAC_REG_IMR, dwMask); \ +} + +#define MACvIntDisable(dwIoBase) \ +{ \ + VNSvOutPortD(dwIoBase + MAC_REG_IMR, 0); \ +} + +#define MACvSelectPage0(dwIoBase) \ +{ \ + VNSvOutPortB(dwIoBase + MAC_REG_PAGE1SEL, 0); \ +} +#define MACvSelectPage1(dwIoBase) \ +{ \ + VNSvOutPortB(dwIoBase + MAC_REG_PAGE1SEL, 1); \ +} + +#define MACvReadMIBCounter(dwIoBase, pdwCounter) \ +{ \ + VNSvInPortD(dwIoBase + MAC_REG_MIBCNTR , pdwCounter); \ +} + +#define MACvPwrEvntDisable(dwIoBase) \ +{ \ + VNSvOutPortW(dwIoBase + MAC_REG_WAKEUPEN0, 0x0000); \ +} + +#define MACvEnableProtectMD(dwIoBase) \ +{ \ + DWORD dwOrgValue; \ + VNSvInPortD(dwIoBase + MAC_REG_ENCFG , &dwOrgValue); \ + dwOrgValue = dwOrgValue | EnCFG_ProtectMd; \ + VNSvOutPortD(dwIoBase + MAC_REG_ENCFG, dwOrgValue); \ +} + +#define MACvDisableProtectMD(dwIoBase) \ +{ \ + DWORD dwOrgValue; \ + VNSvInPortD(dwIoBase + MAC_REG_ENCFG , &dwOrgValue); \ + dwOrgValue = dwOrgValue & ~EnCFG_ProtectMd; \ + VNSvOutPortD(dwIoBase + MAC_REG_ENCFG, dwOrgValue); \ +} + +#define MACvEnableBarkerPreambleMd(dwIoBase) \ +{ \ + DWORD dwOrgValue; \ + VNSvInPortD(dwIoBase + MAC_REG_ENCFG , &dwOrgValue); \ + dwOrgValue = dwOrgValue | EnCFG_BarkerPream; \ + VNSvOutPortD(dwIoBase + MAC_REG_ENCFG, dwOrgValue); \ +} + +#define MACvDisableBarkerPreambleMd(dwIoBase) \ +{ \ + DWORD dwOrgValue; \ + VNSvInPortD(dwIoBase + MAC_REG_ENCFG , &dwOrgValue); \ + dwOrgValue = dwOrgValue & ~EnCFG_BarkerPream; \ + VNSvOutPortD(dwIoBase + MAC_REG_ENCFG, dwOrgValue); \ +} + +#define MACvSetBBType(dwIoBase, byTyp) \ +{ \ + DWORD dwOrgValue; \ + VNSvInPortD(dwIoBase + MAC_REG_ENCFG , &dwOrgValue); \ + dwOrgValue = dwOrgValue & ~EnCFG_BBType_MASK; \ + dwOrgValue = dwOrgValue | (DWORD) byTyp; \ + VNSvOutPortD(dwIoBase + MAC_REG_ENCFG, dwOrgValue); \ +} + +#define MACvReadATIMW(dwIoBase, pwCounter) \ +{ \ + VNSvInPortW(dwIoBase + MAC_REG_AIDATIM , pwCounter); \ +} + +#define MACvWriteATIMW(dwIoBase, wCounter) \ +{ \ + VNSvOutPortW(dwIoBase + MAC_REG_AIDATIM , wCounter); \ +} + +#define MACvWriteCRC16_128(dwIoBase, byRegOfs, wCRC) \ +{ \ + VNSvOutPortB(dwIoBase + MAC_REG_PAGE1SEL, 1); \ + VNSvOutPortW(dwIoBase + byRegOfs, wCRC); \ + VNSvOutPortB(dwIoBase + MAC_REG_PAGE1SEL, 0); \ +} + +#define MACvGPIOIn(dwIoBase, pbyValue) \ +{ \ + VNSvInPortB(dwIoBase + MAC_REG_GPIOCTL1, pbyValue); \ +} + +#define MACvSetRFLE_LatchBase(dwIoBase) \ +{ \ + MACvWordRegBitsOn(dwIoBase, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_RFLEOPT); \ +} + +/*--------------------- Export Classes ----------------------------*/ + +/*--------------------- Export Variables --------------------------*/ + +/*--------------------- Export Functions --------------------------*/ +#ifdef __cplusplus +extern "C" { /* Assume C declarations for C++ */ +#endif /* __cplusplus */ + +extern WORD TxRate_iwconfig;//2008-5-8 by chester +VOID MACvReadAllRegs(DWORD_PTR dwIoBase, PBYTE pbyMacRegs); + +BOOL MACbIsRegBitsOn(DWORD_PTR dwIoBase, BYTE byRegOfs, BYTE byTestBits); +BOOL MACbIsRegBitsOff(DWORD_PTR dwIoBase, BYTE byRegOfs, BYTE byTestBits); + +BOOL MACbIsIntDisable(DWORD_PTR dwIoBase); + +BYTE MACbyReadMultiAddr(DWORD_PTR dwIoBase, UINT uByteIdx); +VOID MACvWriteMultiAddr(DWORD_PTR dwIoBase, UINT uByteIdx, BYTE byData); +VOID MACvSetMultiAddrByHash(DWORD_PTR dwIoBase, BYTE byHashIdx); +VOID MACvResetMultiAddrByHash(DWORD_PTR dwIoBase, BYTE byHashIdx); + +VOID MACvSetRxThreshold(DWORD_PTR dwIoBase, BYTE byThreshold); +VOID MACvGetRxThreshold(DWORD_PTR dwIoBase, PBYTE pbyThreshold); + +VOID MACvSetTxThreshold(DWORD_PTR dwIoBase, BYTE byThreshold); +VOID MACvGetTxThreshold(DWORD_PTR dwIoBase, PBYTE pbyThreshold); + +VOID MACvSetDmaLength(DWORD_PTR dwIoBase, BYTE byDmaLength); +VOID MACvGetDmaLength(DWORD_PTR dwIoBase, PBYTE pbyDmaLength); + +VOID MACvSetShortRetryLimit(DWORD_PTR dwIoBase, BYTE byRetryLimit); +VOID MACvGetShortRetryLimit(DWORD_PTR dwIoBase, PBYTE pbyRetryLimit); + +VOID MACvSetLongRetryLimit(DWORD_PTR dwIoBase, BYTE byRetryLimit); +VOID MACvGetLongRetryLimit(DWORD_PTR dwIoBase, PBYTE pbyRetryLimit); + +VOID MACvSetLoopbackMode(DWORD_PTR dwIoBase, BYTE byLoopbackMode); +BOOL MACbIsInLoopbackMode(DWORD_PTR dwIoBase); + +VOID MACvSetPacketFilter(DWORD_PTR dwIoBase, WORD wFilterType); + +VOID MACvSaveContext(DWORD_PTR dwIoBase, PBYTE pbyCxtBuf); +VOID MACvRestoreContext(DWORD_PTR dwIoBase, PBYTE pbyCxtBuf); +BOOL MACbCompareContext(DWORD_PTR dwIoBase, PBYTE pbyCxtBuf); + +BOOL MACbSoftwareReset(DWORD_PTR dwIoBase); +BOOL MACbSafeSoftwareReset(DWORD_PTR dwIoBase); +BOOL MACbSafeRxOff(DWORD_PTR dwIoBase); +BOOL MACbSafeTxOff(DWORD_PTR dwIoBase); +BOOL MACbSafeStop(DWORD_PTR dwIoBase); +BOOL MACbShutdown(DWORD_PTR dwIoBase); +VOID MACvInitialize(DWORD_PTR dwIoBase); +VOID MACvSetCurrRx0DescAddr(DWORD_PTR dwIoBase, DWORD dwCurrDescAddr); +VOID MACvSetCurrRx1DescAddr(DWORD_PTR dwIoBase, DWORD dwCurrDescAddr); +VOID MACvSetCurrTXDescAddr(int iTxType, DWORD_PTR dwIoBase, DWORD dwCurrDescAddr); +VOID MACvSetCurrTx0DescAddrEx(DWORD_PTR dwIoBase, DWORD dwCurrDescAddr); +VOID MACvSetCurrAC0DescAddrEx(DWORD_PTR dwIoBase, DWORD dwCurrDescAddr); +VOID MACvSetCurrSyncDescAddrEx(DWORD_PTR dwIoBase, DWORD dwCurrDescAddr); +VOID MACvSetCurrATIMDescAddrEx(DWORD_PTR dwIoBase, DWORD dwCurrDescAddr); +void MACvTimer0MicroSDelay(DWORD_PTR dwIoBase, UINT uDelay); +void MACvOneShotTimer0MicroSec(DWORD_PTR dwIoBase, UINT uDelayTime); +void MACvOneShotTimer1MicroSec(DWORD_PTR dwIoBase, UINT uDelayTime); + +void MACvSetMISCFifo(DWORD_PTR dwIoBase, WORD wOffset, DWORD dwData); + +BOOL MACbTxDMAOff (DWORD_PTR dwIoBase, UINT idx); + +void MACvClearBusSusInd(DWORD_PTR dwIoBase); +void MACvEnableBusSusEn(DWORD_PTR dwIoBase); + +BOOL MACbFlushSYNCFifo(DWORD_PTR dwIoBase); +BOOL MACbPSWakeup(DWORD_PTR dwIoBase); + +void MACvSetKeyEntry(DWORD_PTR dwIoBase, WORD wKeyCtl, UINT uEntryIdx, UINT uKeyIdx, PBYTE pbyAddr, PDWORD pdwKey, BYTE byLocalID); +void MACvDisableKeyEntry(DWORD_PTR dwIoBase, UINT uEntryIdx); +void MACvSetDefaultKeyEntry(DWORD_PTR dwIoBase, UINT uKeyLen, UINT uKeyIdx, PDWORD pdwKey, BYTE byLocalID); +//void MACvEnableDefaultKey(DWORD_PTR dwIoBase, BYTE byLocalID); +void MACvDisableDefaultKey(DWORD_PTR dwIoBase); +void MACvSetDefaultTKIPKeyEntry(DWORD_PTR dwIoBase, UINT uKeyLen, UINT uKeyIdx, PDWORD pdwKey, BYTE byLocalID); +void MACvSetDefaultKeyCtl(DWORD_PTR dwIoBase, WORD wKeyCtl, UINT uEntryIdx, BYTE byLocalID); + +#ifdef __cplusplus +} /* End of extern "C" { */ +#endif /* __cplusplus */ + +#endif // __MAC_H__ + diff --git a/drivers/staging/vt6655/mib.c b/drivers/staging/vt6655/mib.c new file mode 100644 index 000000000000..3f06de141a84 --- /dev/null +++ b/drivers/staging/vt6655/mib.c @@ -0,0 +1,616 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * File: mib.c + * + * Purpose: Implement MIB Data Structure + * + * Author: Tevin Chen + * + * Date: May 21, 1996 + * + * Functions: + * STAvClearAllCounter - Clear All MIB Counter + * STAvUpdateIstStatCounter - Update ISR statistic counter + * STAvUpdateRDStatCounter - Update Rx statistic counter + * STAvUpdateRDStatCounterEx - Update Rx statistic counter and copy rcv data + * STAvUpdateTDStatCounter - Update Tx statistic counter + * STAvUpdateTDStatCounterEx - Update Tx statistic counter and copy tx data + * STAvUpdate802_11Counter - Update 802.11 mib counter + * + * Revision History: + * + */ + + +#if !defined(__UPC_H__) +#include "upc.h" +#endif +#if !defined(__MAC_H__) +#include "mac.h" +#endif +#if !defined(__TBIT_H__) +#include "tbit.h" +#endif +#if !defined(__TETHER_H__) +#include "tether.h" +#endif +#if !defined(__MIB_H__) +#include "mib.h" +#endif +#if !defined(__WCTL_H__) +#include "wctl.h" +#endif +#if !defined(__UMEM_H__) +#include "umem.h" +#endif +#if !defined(__BASEBAND_H__) +#include "baseband.h" +#endif + +/*--------------------- Static Definitions -------------------------*/ +static int msglevel =MSG_LEVEL_INFO; +/*--------------------- Static Classes ----------------------------*/ + +/*--------------------- Static Variables --------------------------*/ + +/*--------------------- Static Functions --------------------------*/ + +/*--------------------- Export Variables --------------------------*/ + +/*--------------------- Export Functions --------------------------*/ + + + +/* + * Description: Clear All Statistic Counter + * + * Parameters: + * In: + * pStatistic - Pointer to Statistic Counter Data Structure + * Out: + * none + * + * Return Value: none + * + */ +void STAvClearAllCounter (PSStatCounter pStatistic) +{ + // set memory to zero + ZERO_MEMORY(pStatistic, sizeof(SStatCounter)); +} + + +/* + * Description: Update Isr Statistic Counter + * + * Parameters: + * In: + * pStatistic - Pointer to Statistic Counter Data Structure + * wisr - Interrupt status + * Out: + * none + * + * Return Value: none + * + */ +void STAvUpdateIsrStatCounter (PSStatCounter pStatistic, DWORD dwIsr) +{ + /**********************/ + /* ABNORMAL interrupt */ + /**********************/ + // not any IMR bit invoke irq + + if (dwIsr == 0) { + pStatistic->ISRStat.dwIsrUnknown++; + return; + } + +//Added by Kyle + if (BITbIsBitOn(dwIsr, ISR_TXDMA0)) // ISR, bit0 + pStatistic->ISRStat.dwIsrTx0OK++; // TXDMA0 successful + + if (BITbIsBitOn(dwIsr, ISR_AC0DMA)) // ISR, bit1 + pStatistic->ISRStat.dwIsrAC0TxOK++; // AC0DMA successful + + if (BITbIsBitOn(dwIsr, ISR_BNTX)) // ISR, bit2 + pStatistic->ISRStat.dwIsrBeaconTxOK++; // BeaconTx successful + + if (BITbIsBitOn(dwIsr, ISR_RXDMA0)) // ISR, bit3 + pStatistic->ISRStat.dwIsrRx0OK++; // Rx0 successful + + if (BITbIsBitOn(dwIsr, ISR_TBTT)) // ISR, bit4 + pStatistic->ISRStat.dwIsrTBTTInt++; // TBTT successful + + if (BITbIsBitOn(dwIsr, ISR_SOFTTIMER)) // ISR, bit6 + pStatistic->ISRStat.dwIsrSTIMERInt++; + + if (BITbIsBitOn(dwIsr, ISR_WATCHDOG)) // ISR, bit7 + pStatistic->ISRStat.dwIsrWatchDog++; + + if (BITbIsBitOn(dwIsr, ISR_FETALERR)) // ISR, bit8 + pStatistic->ISRStat.dwIsrUnrecoverableError++; + + if (BITbIsBitOn(dwIsr, ISR_SOFTINT)) // ISR, bit9 + pStatistic->ISRStat.dwIsrSoftInterrupt++; // software interrupt + + if (BITbIsBitOn(dwIsr, ISR_MIBNEARFULL)) // ISR, bit10 + pStatistic->ISRStat.dwIsrMIBNearfull++; + + if (BITbIsBitOn(dwIsr, ISR_RXNOBUF)) // ISR, bit11 + pStatistic->ISRStat.dwIsrRxNoBuf++; // Rx No Buff + + if (BITbIsBitOn(dwIsr, ISR_RXDMA1)) // ISR, bit12 + pStatistic->ISRStat.dwIsrRx1OK++; // Rx1 successful + +// if (BITbIsBitOn(dwIsr, ISR_ATIMTX)) // ISR, bit13 +// pStatistic->ISRStat.dwIsrATIMTxOK++; // ATIMTX successful + +// if (BITbIsBitOn(dwIsr, ISR_SYNCTX)) // ISR, bit14 +// pStatistic->ISRStat.dwIsrSYNCTxOK++; // SYNCTX successful + +// if (BITbIsBitOn(dwIsr, ISR_CFPEND)) // ISR, bit18 +// pStatistic->ISRStat.dwIsrCFPEnd++; + +// if (BITbIsBitOn(dwIsr, ISR_ATIMEND)) // ISR, bit19 +// pStatistic->ISRStat.dwIsrATIMEnd++; + +// if (BITbIsBitOn(dwIsr, ISR_SYNCFLUSHOK)) // ISR, bit20 +// pStatistic->ISRStat.dwIsrSYNCFlushOK++; + + if (BITbIsBitOn(dwIsr, ISR_SOFTTIMER1)) // ISR, bit21 + pStatistic->ISRStat.dwIsrSTIMER1Int++; + +} + + +/* + * Description: Update Rx Statistic Counter + * + * Parameters: + * In: + * pStatistic - Pointer to Statistic Counter Data Structure + * byRSR - Rx Status + * byNewRSR - Rx Status + * pbyBuffer - Rx Buffer + * cbFrameLength - Rx Length + * Out: + * none + * + * Return Value: none + * + */ +void STAvUpdateRDStatCounter (PSStatCounter pStatistic, + BYTE byRSR, BYTE byNewRSR, BYTE byRxRate, + PBYTE pbyBuffer, UINT cbFrameLength) +{ + //need change + PS802_11Header pHeader = (PS802_11Header)pbyBuffer; + + if (BITbIsBitOn(byRSR, RSR_ADDROK)) + pStatistic->dwRsrADDROk++; + if (BITbIsBitOn(byRSR, RSR_CRCOK)) { + pStatistic->dwRsrCRCOk++; + + pStatistic->ullRsrOK++; + + if (cbFrameLength >= U_ETHER_ADDR_LEN) { + // update counters in case that successful transmit + if (BITbIsBitOn(byRSR, RSR_ADDRBROAD)) { + pStatistic->ullRxBroadcastFrames++; + pStatistic->ullRxBroadcastBytes += (ULONGLONG)cbFrameLength; + } + else if (BITbIsBitOn(byRSR, RSR_ADDRMULTI)) { + pStatistic->ullRxMulticastFrames++; + pStatistic->ullRxMulticastBytes += (ULONGLONG)cbFrameLength; + } + else { + pStatistic->ullRxDirectedFrames++; + pStatistic->ullRxDirectedBytes += (ULONGLONG)cbFrameLength; + } + } + } + + if(byRxRate==22) { + pStatistic->CustomStat.ullRsr11M++; + if(BITbIsBitOn(byRSR, RSR_CRCOK)) { + pStatistic->CustomStat.ullRsr11MCRCOk++; + } + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"11M: ALL[%d], OK[%d]:[%02x]\n", (INT)pStatistic->CustomStat.ullRsr11M, (INT)pStatistic->CustomStat.ullRsr11MCRCOk, byRSR); + } + else if(byRxRate==11) { + pStatistic->CustomStat.ullRsr5M++; + if(BITbIsBitOn(byRSR, RSR_CRCOK)) { + pStatistic->CustomStat.ullRsr5MCRCOk++; + } + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO" 5M: ALL[%d], OK[%d]:[%02x]\n", (INT)pStatistic->CustomStat.ullRsr5M, (INT)pStatistic->CustomStat.ullRsr5MCRCOk, byRSR); + } + else if(byRxRate==4) { + pStatistic->CustomStat.ullRsr2M++; + if(BITbIsBitOn(byRSR, RSR_CRCOK)) { + pStatistic->CustomStat.ullRsr2MCRCOk++; + } + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO" 2M: ALL[%d], OK[%d]:[%02x]\n", (INT)pStatistic->CustomStat.ullRsr2M, (INT)pStatistic->CustomStat.ullRsr2MCRCOk, byRSR); + } + else if(byRxRate==2){ + pStatistic->CustomStat.ullRsr1M++; + if(BITbIsBitOn(byRSR, RSR_CRCOK)) { + pStatistic->CustomStat.ullRsr1MCRCOk++; + } + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO" 1M: ALL[%d], OK[%d]:[%02x]\n", (INT)pStatistic->CustomStat.ullRsr1M, (INT)pStatistic->CustomStat.ullRsr1MCRCOk, byRSR); + } + else if(byRxRate==12){ + pStatistic->CustomStat.ullRsr6M++; + if(BITbIsBitOn(byRSR, RSR_CRCOK)) { + pStatistic->CustomStat.ullRsr6MCRCOk++; + } + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO" 6M: ALL[%d], OK[%d]\n", (INT)pStatistic->CustomStat.ullRsr6M, (INT)pStatistic->CustomStat.ullRsr6MCRCOk); + } + else if(byRxRate==18){ + pStatistic->CustomStat.ullRsr9M++; + if(BITbIsBitOn(byRSR, RSR_CRCOK)) { + pStatistic->CustomStat.ullRsr9MCRCOk++; + } + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO" 9M: ALL[%d], OK[%d]\n", (INT)pStatistic->CustomStat.ullRsr9M, (INT)pStatistic->CustomStat.ullRsr9MCRCOk); + } + else if(byRxRate==24){ + pStatistic->CustomStat.ullRsr12M++; + if(BITbIsBitOn(byRSR, RSR_CRCOK)) { + pStatistic->CustomStat.ullRsr12MCRCOk++; + } + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"12M: ALL[%d], OK[%d]\n", (INT)pStatistic->CustomStat.ullRsr12M, (INT)pStatistic->CustomStat.ullRsr12MCRCOk); + } + else if(byRxRate==36){ + pStatistic->CustomStat.ullRsr18M++; + if(BITbIsBitOn(byRSR, RSR_CRCOK)) { + pStatistic->CustomStat.ullRsr18MCRCOk++; + } + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"18M: ALL[%d], OK[%d]\n", (INT)pStatistic->CustomStat.ullRsr18M, (INT)pStatistic->CustomStat.ullRsr18MCRCOk); + } + else if(byRxRate==48){ + pStatistic->CustomStat.ullRsr24M++; + if(BITbIsBitOn(byRSR, RSR_CRCOK)) { + pStatistic->CustomStat.ullRsr24MCRCOk++; + } + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"24M: ALL[%d], OK[%d]\n", (INT)pStatistic->CustomStat.ullRsr24M, (INT)pStatistic->CustomStat.ullRsr24MCRCOk); + } + else if(byRxRate==72){ + pStatistic->CustomStat.ullRsr36M++; + if(BITbIsBitOn(byRSR, RSR_CRCOK)) { + pStatistic->CustomStat.ullRsr36MCRCOk++; + } + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"36M: ALL[%d], OK[%d]\n", (INT)pStatistic->CustomStat.ullRsr36M, (INT)pStatistic->CustomStat.ullRsr36MCRCOk); + } + else if(byRxRate==96){ + pStatistic->CustomStat.ullRsr48M++; + if(BITbIsBitOn(byRSR, RSR_CRCOK)) { + pStatistic->CustomStat.ullRsr48MCRCOk++; + } + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"48M: ALL[%d], OK[%d]\n", (INT)pStatistic->CustomStat.ullRsr48M, (INT)pStatistic->CustomStat.ullRsr48MCRCOk); + } + else if(byRxRate==108){ + pStatistic->CustomStat.ullRsr54M++; + if(BITbIsBitOn(byRSR, RSR_CRCOK)) { + pStatistic->CustomStat.ullRsr54MCRCOk++; + } + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"54M: ALL[%d], OK[%d]\n", (INT)pStatistic->CustomStat.ullRsr54M, (INT)pStatistic->CustomStat.ullRsr54MCRCOk); + } + else { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Unknown: Total[%d], CRCOK[%d]\n", (INT)pStatistic->dwRsrRxPacket+1, (INT)pStatistic->dwRsrCRCOk); + } + + if (BITbIsBitOn(byRSR, RSR_BSSIDOK)) + pStatistic->dwRsrBSSIDOk++; + + if (BITbIsBitOn(byRSR, RSR_BCNSSIDOK)) + pStatistic->dwRsrBCNSSIDOk++; + if (BITbIsBitOn(byRSR, RSR_IVLDLEN)) //invalid len (> 2312 byte) + pStatistic->dwRsrLENErr++; + if (BITbIsBitOn(byRSR, RSR_IVLDTYP)) //invalid packet type + pStatistic->dwRsrTYPErr++; + if (BITbIsBitOn(byRSR, (RSR_IVLDTYP | RSR_IVLDLEN))) + pStatistic->dwRsrErr++; + + if (BITbIsBitOn(byNewRSR, NEWRSR_DECRYPTOK)) + pStatistic->dwNewRsrDECRYPTOK++; + if (BITbIsBitOn(byNewRSR, NEWRSR_CFPIND)) + pStatistic->dwNewRsrCFP++; + if (BITbIsBitOn(byNewRSR, NEWRSR_HWUTSF)) + pStatistic->dwNewRsrUTSF++; + if (BITbIsBitOn(byNewRSR, NEWRSR_BCNHITAID)) + pStatistic->dwNewRsrHITAID++; + if (BITbIsBitOn(byNewRSR, NEWRSR_BCNHITAID0)) + pStatistic->dwNewRsrHITAID0++; + + // increase rx packet count + pStatistic->dwRsrRxPacket++; + pStatistic->dwRsrRxOctet += cbFrameLength; + + + if (IS_TYPE_DATA(pbyBuffer)) { + pStatistic->dwRsrRxData++; + } else if (IS_TYPE_MGMT(pbyBuffer)){ + pStatistic->dwRsrRxManage++; + } else if (IS_TYPE_CONTROL(pbyBuffer)){ + pStatistic->dwRsrRxControl++; + } + + if (BITbIsBitOn(byRSR, RSR_ADDRBROAD)) + pStatistic->dwRsrBroadcast++; + else if (BITbIsBitOn(byRSR, RSR_ADDRMULTI)) + pStatistic->dwRsrMulticast++; + else + pStatistic->dwRsrDirected++; + + if (WLAN_GET_FC_MOREFRAG(pHeader->wFrameCtl)) + pStatistic->dwRsrRxFragment++; + + if (cbFrameLength < MIN_PACKET_LEN + 4) { + pStatistic->dwRsrRunt++; + } + else if (cbFrameLength == MIN_PACKET_LEN + 4) { + pStatistic->dwRsrRxFrmLen64++; + } + else if ((65 <= cbFrameLength) && (cbFrameLength <= 127)) { + pStatistic->dwRsrRxFrmLen65_127++; + } + else if ((128 <= cbFrameLength) && (cbFrameLength <= 255)) { + pStatistic->dwRsrRxFrmLen128_255++; + } + else if ((256 <= cbFrameLength) && (cbFrameLength <= 511)) { + pStatistic->dwRsrRxFrmLen256_511++; + } + else if ((512 <= cbFrameLength) && (cbFrameLength <= 1023)) { + pStatistic->dwRsrRxFrmLen512_1023++; + } + else if ((1024 <= cbFrameLength) && (cbFrameLength <= MAX_PACKET_LEN + 4)) { + pStatistic->dwRsrRxFrmLen1024_1518++; + } else if (cbFrameLength > MAX_PACKET_LEN + 4) { + pStatistic->dwRsrLong++; + } + +} + + + +/* + * Description: Update Rx Statistic Counter and copy Rx buffer + * + * Parameters: + * In: + * pStatistic - Pointer to Statistic Counter Data Structure + * byRSR - Rx Status + * byNewRSR - Rx Status + * pbyBuffer - Rx Buffer + * cbFrameLength - Rx Length + * Out: + * none + * + * Return Value: none + * + */ + +void +STAvUpdateRDStatCounterEx ( + PSStatCounter pStatistic, + BYTE byRSR, + BYTE byNewRSR, + BYTE byRxRate, + PBYTE pbyBuffer, + UINT cbFrameLength + ) +{ + STAvUpdateRDStatCounter( + pStatistic, + byRSR, + byNewRSR, + byRxRate, + pbyBuffer, + cbFrameLength + ); + + // rx length + pStatistic->dwCntRxFrmLength = cbFrameLength; + // rx pattern, we just see 10 bytes for sample + MEMvCopy(pStatistic->abyCntRxPattern, (PBYTE)pbyBuffer, 10); +} + + +/* + * Description: Update Tx Statistic Counter + * + * Parameters: + * In: + * pStatistic - Pointer to Statistic Counter Data Structure + * byTSR0 - Tx Status + * byTSR1 - Tx Status + * pbyBuffer - Tx Buffer + * cbFrameLength - Tx Length + * uIdx - Index of Tx DMA + * Out: + * none + * + * Return Value: none + * + */ +void +STAvUpdateTDStatCounter ( + PSStatCounter pStatistic, + BYTE byTSR0, + BYTE byTSR1, + PBYTE pbyBuffer, + UINT cbFrameLength, + UINT uIdx + ) +{ + PWLAN_80211HDR_A4 pHeader; + PBYTE pbyDestAddr; + BYTE byTSR0_NCR = byTSR0 & TSR0_NCR; + + + + pHeader = (PWLAN_80211HDR_A4) pbyBuffer; + if (WLAN_GET_FC_TODS(pHeader->wFrameCtl) == 0) { + pbyDestAddr = &(pHeader->abyAddr1[0]); + } + else { + pbyDestAddr = &(pHeader->abyAddr3[0]); + } + // increase tx packet count + pStatistic->dwTsrTxPacket[uIdx]++; + pStatistic->dwTsrTxOctet[uIdx] += cbFrameLength; + + if (byTSR0_NCR != 0) { + pStatistic->dwTsrRetry[uIdx]++; + pStatistic->dwTsrTotalRetry[uIdx] += byTSR0_NCR; + + if (byTSR0_NCR == 1) + pStatistic->dwTsrOnceRetry[uIdx]++; + else + pStatistic->dwTsrMoreThanOnceRetry[uIdx]++; + } + + if ((byTSR1&(TSR1_TERR|TSR1_RETRYTMO|TSR1_TMO|ACK_DATA)) == 0) { + pStatistic->ullTsrOK[uIdx]++; + pStatistic->CustomStat.ullTsrAllOK = + (pStatistic->ullTsrOK[TYPE_AC0DMA] + pStatistic->ullTsrOK[TYPE_TXDMA0]); + // update counters in case that successful transmit + if (IS_BROADCAST_ADDRESS(pbyDestAddr)) { + pStatistic->ullTxBroadcastFrames[uIdx]++; + pStatistic->ullTxBroadcastBytes[uIdx] += (ULONGLONG)cbFrameLength; + } + else if (IS_MULTICAST_ADDRESS(pbyDestAddr)) { + pStatistic->ullTxMulticastFrames[uIdx]++; + pStatistic->ullTxMulticastBytes[uIdx] += (ULONGLONG)cbFrameLength; + } + else { + pStatistic->ullTxDirectedFrames[uIdx]++; + pStatistic->ullTxDirectedBytes[uIdx] += (ULONGLONG)cbFrameLength; + } + } + else { + if (BITbIsBitOn(byTSR1, TSR1_TERR)) + pStatistic->dwTsrErr[uIdx]++; + if (BITbIsBitOn(byTSR1, TSR1_RETRYTMO)) + pStatistic->dwTsrRetryTimeout[uIdx]++; + if (BITbIsBitOn(byTSR1, TSR1_TMO)) + pStatistic->dwTsrTransmitTimeout[uIdx]++; + if (BITbIsBitOn(byTSR1, ACK_DATA)) + pStatistic->dwTsrACKData[uIdx]++; + } + + if (IS_BROADCAST_ADDRESS(pbyDestAddr)) + pStatistic->dwTsrBroadcast[uIdx]++; + else if (IS_MULTICAST_ADDRESS(pbyDestAddr)) + pStatistic->dwTsrMulticast[uIdx]++; + else + pStatistic->dwTsrDirected[uIdx]++; + +} + + +/* + * Description: Update Tx Statistic Counter and copy Tx buffer + * + * Parameters: + * In: + * pStatistic - Pointer to Statistic Counter Data Structure + * pbyBuffer - Tx Buffer + * cbFrameLength - Tx Length + * Out: + * none + * + * Return Value: none + * + */ +void +STAvUpdateTDStatCounterEx ( + PSStatCounter pStatistic, + PBYTE pbyBuffer, + DWORD cbFrameLength + ) +{ + UINT uPktLength; + + uPktLength = (UINT)cbFrameLength; + + // tx length + pStatistic->dwCntTxBufLength = uPktLength; + // tx pattern, we just see 16 bytes for sample + MEMvCopy(pStatistic->abyCntTxPattern, pbyBuffer, 16); +} + + +/* + * Description: Update 802.11 mib counter + * + * Parameters: + * In: + * p802_11Counter - Pointer to 802.11 mib counter + * pStatistic - Pointer to Statistic Counter Data Structure + * dwCounter - hardware counter for 802.11 mib + * Out: + * none + * + * Return Value: none + * + */ +void +STAvUpdate802_11Counter( + PSDot11Counters p802_11Counter, + PSStatCounter pStatistic, + DWORD dwCounter + ) +{ + //p802_11Counter->TransmittedFragmentCount + p802_11Counter->MulticastTransmittedFrameCount = (ULONGLONG) (pStatistic->dwTsrBroadcast[TYPE_AC0DMA] + + pStatistic->dwTsrBroadcast[TYPE_TXDMA0] + + pStatistic->dwTsrMulticast[TYPE_AC0DMA] + + pStatistic->dwTsrMulticast[TYPE_TXDMA0]); + p802_11Counter->FailedCount = (ULONGLONG) (pStatistic->dwTsrErr[TYPE_AC0DMA] + pStatistic->dwTsrErr[TYPE_TXDMA0]); + p802_11Counter->RetryCount = (ULONGLONG) (pStatistic->dwTsrRetry[TYPE_AC0DMA] + pStatistic->dwTsrRetry[TYPE_TXDMA0]); + p802_11Counter->MultipleRetryCount = (ULONGLONG) (pStatistic->dwTsrMoreThanOnceRetry[TYPE_AC0DMA] + + pStatistic->dwTsrMoreThanOnceRetry[TYPE_TXDMA0]); + //p802_11Counter->FrameDuplicateCount + p802_11Counter->RTSSuccessCount += (ULONGLONG) (dwCounter & 0x000000ff); + p802_11Counter->RTSFailureCount += (ULONGLONG) ((dwCounter & 0x0000ff00) >> 8); + p802_11Counter->ACKFailureCount += (ULONGLONG) ((dwCounter & 0x00ff0000) >> 16); + p802_11Counter->FCSErrorCount += (ULONGLONG) ((dwCounter & 0xff000000) >> 24); + //p802_11Counter->ReceivedFragmentCount + p802_11Counter->MulticastReceivedFrameCount = (ULONGLONG) (pStatistic->dwRsrBroadcast + + pStatistic->dwRsrMulticast); +} + +/* + * Description: Clear 802.11 mib counter + * + * Parameters: + * In: + * p802_11Counter - Pointer to 802.11 mib counter + * Out: + * none + * + * Return Value: none + * + */ +void +STAvClear802_11Counter(PSDot11Counters p802_11Counter) +{ + // set memory to zero + ZERO_MEMORY(p802_11Counter, sizeof(SDot11Counters)); +} diff --git a/drivers/staging/vt6655/mib.h b/drivers/staging/vt6655/mib.h new file mode 100644 index 000000000000..b4e1c4a19a7d --- /dev/null +++ b/drivers/staging/vt6655/mib.h @@ -0,0 +1,399 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * File: mib.h + * + * Purpose: Implement MIB Data Structure + * + * Author: Tevin Chen + * + * Date: May 21, 1996 + * + */ + +#ifndef __MIB_H__ +#define __MIB_H__ + +#if !defined(__TTYPE_H__) +#include "ttype.h" +#endif +#if !defined(__TETHER_H__) +#include "tether.h" +#endif +#if !defined(__DESC_H__) +#include "desc.h" +#endif + + + +//#define ULONGLONG ULONG + +/*--------------------- Export Definitions -------------------------*/ +// +// 802.11 counter +// + +typedef struct tagSDot11Counters { + ULONG Length; // Length of structure + ULONGLONG TransmittedFragmentCount; + ULONGLONG MulticastTransmittedFrameCount; + ULONGLONG FailedCount; + ULONGLONG RetryCount; + ULONGLONG MultipleRetryCount; + ULONGLONG RTSSuccessCount; + ULONGLONG RTSFailureCount; + ULONGLONG ACKFailureCount; + ULONGLONG FrameDuplicateCount; + ULONGLONG ReceivedFragmentCount; + ULONGLONG MulticastReceivedFrameCount; + ULONGLONG FCSErrorCount; + ULONGLONG TKIPLocalMICFailures; + ULONGLONG TKIPRemoteMICFailures; + ULONGLONG TKIPICVErrors; + ULONGLONG TKIPCounterMeasuresInvoked; + ULONGLONG TKIPReplays; + ULONGLONG CCMPFormatErrors; + ULONGLONG CCMPReplays; + ULONGLONG CCMPDecryptErrors; + ULONGLONG FourWayHandshakeFailures; +// ULONGLONG WEPUndecryptableCount; +// ULONGLONG WEPICVErrorCount; +// ULONGLONG DecryptSuccessCount; +// ULONGLONG DecryptFailureCount; +} SDot11Counters, DEF* PSDot11Counters; + + +// +// MIB2 counter +// +typedef struct tagSMib2Counter { + LONG ifIndex; + TCHAR ifDescr[256]; // max size 255 plus zero ending + // e.g. "interface 1" + LONG ifType; + LONG ifMtu; + DWORD ifSpeed; + BYTE ifPhysAddress[U_ETHER_ADDR_LEN]; + LONG ifAdminStatus; + LONG ifOperStatus; + DWORD ifLastChange; + DWORD ifInOctets; + DWORD ifInUcastPkts; + DWORD ifInNUcastPkts; + DWORD ifInDiscards; + DWORD ifInErrors; + DWORD ifInUnknownProtos; + DWORD ifOutOctets; + DWORD ifOutUcastPkts; + DWORD ifOutNUcastPkts; + DWORD ifOutDiscards; + DWORD ifOutErrors; + DWORD ifOutQLen; + DWORD ifSpecific; +} SMib2Counter, DEF* PSMib2Counter; + +// Value in the ifType entry +//#define ETHERNETCSMACD 6 // +#define WIRELESSLANIEEE80211b 6 // + +// Value in the ifAdminStatus/ifOperStatus entry +#define UP 1 // +#define DOWN 2 // +#define TESTING 3 // + + +// +// RMON counter +// +typedef struct tagSRmonCounter { + LONG etherStatsIndex; + DWORD etherStatsDataSource; + DWORD etherStatsDropEvents; + DWORD etherStatsOctets; + DWORD etherStatsPkts; + DWORD etherStatsBroadcastPkts; + DWORD etherStatsMulticastPkts; + DWORD etherStatsCRCAlignErrors; + DWORD etherStatsUndersizePkts; + DWORD etherStatsOversizePkts; + DWORD etherStatsFragments; + DWORD etherStatsJabbers; + DWORD etherStatsCollisions; + DWORD etherStatsPkt64Octets; + DWORD etherStatsPkt65to127Octets; + DWORD etherStatsPkt128to255Octets; + DWORD etherStatsPkt256to511Octets; + DWORD etherStatsPkt512to1023Octets; + DWORD etherStatsPkt1024to1518Octets; + DWORD etherStatsOwners; + DWORD etherStatsStatus; +} SRmonCounter, DEF* PSRmonCounter; + +// +// Custom counter +// +typedef struct tagSCustomCounters { + ULONG Length; + + ULONGLONG ullTsrAllOK; + + ULONGLONG ullRsr11M; + ULONGLONG ullRsr5M; + ULONGLONG ullRsr2M; + ULONGLONG ullRsr1M; + + ULONGLONG ullRsr11MCRCOk; + ULONGLONG ullRsr5MCRCOk; + ULONGLONG ullRsr2MCRCOk; + ULONGLONG ullRsr1MCRCOk; + + ULONGLONG ullRsr54M; + ULONGLONG ullRsr48M; + ULONGLONG ullRsr36M; + ULONGLONG ullRsr24M; + ULONGLONG ullRsr18M; + ULONGLONG ullRsr12M; + ULONGLONG ullRsr9M; + ULONGLONG ullRsr6M; + + ULONGLONG ullRsr54MCRCOk; + ULONGLONG ullRsr48MCRCOk; + ULONGLONG ullRsr36MCRCOk; + ULONGLONG ullRsr24MCRCOk; + ULONGLONG ullRsr18MCRCOk; + ULONGLONG ullRsr12MCRCOk; + ULONGLONG ullRsr9MCRCOk; + ULONGLONG ullRsr6MCRCOk; + +} SCustomCounters, DEF* PSCustomCounters; + + +// +// Custom counter +// +typedef struct tagSISRCounters { + ULONG Length; + + DWORD dwIsrTx0OK; + DWORD dwIsrAC0TxOK; + DWORD dwIsrBeaconTxOK; + DWORD dwIsrRx0OK; + DWORD dwIsrTBTTInt; + DWORD dwIsrSTIMERInt; + DWORD dwIsrWatchDog; + DWORD dwIsrUnrecoverableError; + DWORD dwIsrSoftInterrupt; + DWORD dwIsrMIBNearfull; + DWORD dwIsrRxNoBuf; + + DWORD dwIsrUnknown; // unknown interrupt count + + DWORD dwIsrRx1OK; + DWORD dwIsrATIMTxOK; + DWORD dwIsrSYNCTxOK; + DWORD dwIsrCFPEnd; + DWORD dwIsrATIMEnd; + DWORD dwIsrSYNCFlushOK; + DWORD dwIsrSTIMER1Int; + ///////////////////////////////////// +} SISRCounters, DEF* PSISRCounters; + + +// Value in the etherStatsStatus entry +#define VALID 1 // +#define CREATE_REQUEST 2 // +#define UNDER_CREATION 3 // +#define INVALID 4 // + +//#define MAX_RATE 12 +// +// statistic counter +// +typedef struct tagSStatCounter { + // + // ISR status count + // + + + // RSR status count + // + DWORD dwRsrFrmAlgnErr; + DWORD dwRsrErr; + DWORD dwRsrCRCErr; + DWORD dwRsrCRCOk; + DWORD dwRsrBSSIDOk; + DWORD dwRsrADDROk; + DWORD dwRsrBCNSSIDOk; + DWORD dwRsrLENErr; + DWORD dwRsrTYPErr; + + DWORD dwNewRsrDECRYPTOK; + DWORD dwNewRsrCFP; + DWORD dwNewRsrUTSF; + DWORD dwNewRsrHITAID; + DWORD dwNewRsrHITAID0; + + DWORD dwRsrLong; + DWORD dwRsrRunt; + + DWORD dwRsrRxControl; + DWORD dwRsrRxData; + DWORD dwRsrRxManage; + + DWORD dwRsrRxPacket; + DWORD dwRsrRxOctet; + DWORD dwRsrBroadcast; + DWORD dwRsrMulticast; + DWORD dwRsrDirected; + // 64-bit OID + ULONGLONG ullRsrOK; + + // for some optional OIDs (64 bits) and DMI support + ULONGLONG ullRxBroadcastBytes; + ULONGLONG ullRxMulticastBytes; + ULONGLONG ullRxDirectedBytes; + ULONGLONG ullRxBroadcastFrames; + ULONGLONG ullRxMulticastFrames; + ULONGLONG ullRxDirectedFrames; + + DWORD dwRsrRxFragment; + DWORD dwRsrRxFrmLen64; + DWORD dwRsrRxFrmLen65_127; + DWORD dwRsrRxFrmLen128_255; + DWORD dwRsrRxFrmLen256_511; + DWORD dwRsrRxFrmLen512_1023; + DWORD dwRsrRxFrmLen1024_1518; + + // TSR status count + // + DWORD dwTsrTotalRetry[TYPE_MAXTD]; // total collision retry count + DWORD dwTsrOnceRetry[TYPE_MAXTD]; // this packet only occur one collision + DWORD dwTsrMoreThanOnceRetry[TYPE_MAXTD]; // this packet occur more than one collision + DWORD dwTsrRetry[TYPE_MAXTD]; // this packet has ever occur collision, + // that is (dwTsrOnceCollision0 + dwTsrMoreThanOnceCollision0) + DWORD dwTsrACKData[TYPE_MAXTD]; + DWORD dwTsrErr[TYPE_MAXTD]; + DWORD dwAllTsrOK[TYPE_MAXTD]; + DWORD dwTsrRetryTimeout[TYPE_MAXTD]; + DWORD dwTsrTransmitTimeout[TYPE_MAXTD]; + + DWORD dwTsrTxPacket[TYPE_MAXTD]; + DWORD dwTsrTxOctet[TYPE_MAXTD]; + DWORD dwTsrBroadcast[TYPE_MAXTD]; + DWORD dwTsrMulticast[TYPE_MAXTD]; + DWORD dwTsrDirected[TYPE_MAXTD]; + + // RD/TD count + DWORD dwCntRxFrmLength; + DWORD dwCntTxBufLength; + + BYTE abyCntRxPattern[16]; + BYTE abyCntTxPattern[16]; + + + + // Software check.... + DWORD dwCntRxDataErr; // rx buffer data software compare CRC err count + DWORD dwCntDecryptErr; // rx buffer data software compare CRC err count + DWORD dwCntRxICVErr; // rx buffer data software compare CRC err count + UINT idxRxErrorDesc[TYPE_MAXRD]; // index for rx data error RD + + // 64-bit OID + ULONGLONG ullTsrOK[TYPE_MAXTD]; + + // for some optional OIDs (64 bits) and DMI support + ULONGLONG ullTxBroadcastFrames[TYPE_MAXTD]; + ULONGLONG ullTxMulticastFrames[TYPE_MAXTD]; + ULONGLONG ullTxDirectedFrames[TYPE_MAXTD]; + ULONGLONG ullTxBroadcastBytes[TYPE_MAXTD]; + ULONGLONG ullTxMulticastBytes[TYPE_MAXTD]; + ULONGLONG ullTxDirectedBytes[TYPE_MAXTD]; + +// DWORD dwTxRetryCount[8]; + // + // ISR status count + // + SISRCounters ISRStat; + + SCustomCounters CustomStat; + + #ifdef Calcu_LinkQual + //Tx count: + ULONG TxNoRetryOkCount; //success tx no retry ! + ULONG TxRetryOkCount; //sucess tx but retry ! + ULONG TxFailCount; //fail tx ? + //Rx count: + ULONG RxOkCnt; //sucess rx ! + ULONG RxFcsErrCnt; //fail rx ? + //statistic + ULONG SignalStren; + ULONG LinkQuality; + #endif +} SStatCounter, DEF* PSStatCounter; + +/*--------------------- Export Classes ----------------------------*/ + +/*--------------------- Export Variables --------------------------*/ + +/*--------------------- Export Functions --------------------------*/ +#ifdef __cplusplus +extern "C" { /* Assume C declarations for C++ */ +#endif /* __cplusplus */ + + +void STAvClearAllCounter(PSStatCounter pStatistic); + +void STAvUpdateIsrStatCounter(PSStatCounter pStatistic, DWORD dwIsr); + +void STAvUpdateRDStatCounter(PSStatCounter pStatistic, + BYTE byRSR, BYTE byNewRSR, BYTE byRxRate, + PBYTE pbyBuffer, UINT cbFrameLength); + +void STAvUpdateRDStatCounterEx(PSStatCounter pStatistic, + BYTE byRSR, BYTE byNewRsr, BYTE byRxRate, + PBYTE pbyBuffer, UINT cbFrameLength); + +void STAvUpdateTDStatCounter(PSStatCounter pStatistic, + BYTE byTSR0, BYTE byTSR1, + PBYTE pbyBuffer, UINT cbFrameLength, UINT uIdx ); + +void STAvUpdateTDStatCounterEx( + PSStatCounter pStatistic, + PBYTE pbyBuffer, + DWORD cbFrameLength + ); + +void STAvUpdate802_11Counter( + PSDot11Counters p802_11Counter, + PSStatCounter pStatistic, + DWORD dwCounter + ); + +void STAvClear802_11Counter(PSDot11Counters p802_11Counter); + +#ifdef __cplusplus +} /* End of extern "C" { */ +#endif /* __cplusplus */ + + + + +#endif // __MIB_H__ + + + diff --git a/drivers/staging/vt6655/michael.c b/drivers/staging/vt6655/michael.c new file mode 100644 index 000000000000..7bda4c19e903 --- /dev/null +++ b/drivers/staging/vt6655/michael.c @@ -0,0 +1,188 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * File: michael.cpp + * + * Purpose: The implementation of LIST data structure. + * + * Author: Kyle Hsu + * + * Date: Sep 4, 2002 + * + * Functions: + * s_dwGetUINT32 - Convert from BYTE[] to DWORD in a portable way + * s_vPutUINT32 - Convert from DWORD to BYTE[] in a portable way + * s_vClear - Reset the state to the empty message. + * s_vSetKey - Set the key. + * MIC_vInit - Set the key. + * s_vAppendByte - Append the byte to our word-sized buffer. + * MIC_vAppend - call s_vAppendByte. + * MIC_vGetMIC - Append the minimum padding and call s_vAppendByte. + * + * Revision History: + * + */ + +#if !defined(__TMACRO_H__) +#include "tmacro.h" +#endif +#if !defined(__TBIT_H__) +#include "tbit.h" +#endif +#if !defined(__MICHAEL_H__) +#include "michael.h" +#endif + +/*--------------------- Static Definitions -------------------------*/ + +/*--------------------- Static Variables --------------------------*/ + +/*--------------------- Static Functions --------------------------*/ +/* +static DWORD s_dwGetUINT32(BYTE * p); // Get DWORD from 4 bytes LSByte first +static VOID s_vPutUINT32(BYTE* p, DWORD val); // Put DWORD into 4 bytes LSByte first +*/ +static VOID s_vClear(void); // Clear the internal message, + // resets the object to the state just after construction. +static VOID s_vSetKey(DWORD dwK0, DWORD dwK1); +static VOID s_vAppendByte(BYTE b); // Add a single byte to the internal message + +/*--------------------- Export Variables --------------------------*/ +static DWORD L, R; // Current state + +static DWORD K0, K1; // Key +static DWORD M; // Message accumulator (single word) +static UINT nBytesInM; // # bytes in M + +/*--------------------- Export Functions --------------------------*/ + +/* +static DWORD s_dwGetUINT32 (BYTE * p) +// Convert from BYTE[] to DWORD in a portable way +{ + DWORD res = 0; + UINT i; + for(i=0; i<4; i++ ) + { + res |= (*p++) << (8*i); + } + return res; +} + +static VOID s_vPutUINT32 (BYTE* p, DWORD val) +// Convert from DWORD to BYTE[] in a portable way +{ + UINT i; + for(i=0; i<4; i++ ) + { + *p++ = (BYTE) (val & 0xff); + val >>= 8; + } +} +*/ + +static VOID s_vClear (void) +{ + // Reset the state to the empty message. + L = K0; + R = K1; + nBytesInM = 0; + M = 0; +} + +static VOID s_vSetKey (DWORD dwK0, DWORD dwK1) +{ + // Set the key + K0 = dwK0; + K1 = dwK1; + // and reset the message + s_vClear(); +} + +static VOID s_vAppendByte (BYTE b) +{ + // Append the byte to our word-sized buffer + M |= b << (8*nBytesInM); + nBytesInM++; + // Process the word if it is full. + if( nBytesInM >= 4 ) + { + L ^= M; + R ^= ROL32( L, 17 ); + L += R; + R ^= ((L & 0xff00ff00) >> 8) | ((L & 0x00ff00ff) << 8); + L += R; + R ^= ROL32( L, 3 ); + L += R; + R ^= ROR32( L, 2 ); + L += R; + // Clear the buffer + M = 0; + nBytesInM = 0; + } +} + +VOID MIC_vInit (DWORD dwK0, DWORD dwK1) +{ + // Set the key + s_vSetKey(dwK0, dwK1); +} + + +VOID MIC_vUnInit (void) +{ + // Wipe the key material + K0 = 0; + K1 = 0; + + // And the other fields as well. + //Note that this sets (L,R) to (K0,K1) which is just fine. + s_vClear(); +} + +VOID MIC_vAppend (PBYTE src, UINT nBytes) +{ + // This is simple + while (nBytes > 0) + { + s_vAppendByte(*src++); + nBytes--; + } +} + +VOID MIC_vGetMIC (PDWORD pdwL, PDWORD pdwR) +{ + // Append the minimum padding + s_vAppendByte(0x5a); + s_vAppendByte(0); + s_vAppendByte(0); + s_vAppendByte(0); + s_vAppendByte(0); + // and then zeroes until the length is a multiple of 4 + while( nBytesInM != 0 ) + { + s_vAppendByte(0); + } + // The s_vAppendByte function has already computed the result. + *pdwL = L; + *pdwR = R; + // Reset to the empty message. + s_vClear(); +} + diff --git a/drivers/staging/vt6655/michael.h b/drivers/staging/vt6655/michael.h new file mode 100644 index 000000000000..62a24a6083aa --- /dev/null +++ b/drivers/staging/vt6655/michael.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * File: Michael.h + * + * Purpose: Reference implementation for Michael + * written by Niels Ferguson + * + * Author: Kyle Hsu + * + * Date: Jan 2, 2003 + * + */ + + +#ifndef __MICHAEL_H__ +#define __MICHAEL_H__ + +#if !defined(__UMEM_H__) +#include "umem.h" +#endif +/*--------------------- Export Definitions -------------------------*/ + +/*--------------------- Export Types ------------------------------*/ + +VOID MIC_vInit(DWORD dwK0, DWORD dwK1); + +VOID MIC_vUnInit(void); + +// Append bytes to the message to be MICed +VOID MIC_vAppend(PBYTE src, UINT nBytes); + +// Get the MIC result. Destination should accept 8 bytes of result. +// This also resets the message to empty. +VOID MIC_vGetMIC(PDWORD pdwL, PDWORD pdwR); + +/*--------------------- Export Macros ------------------------------*/ + +// Rotation functions on 32 bit values +#define ROL32( A, n ) \ + ( ((A) << (n)) | ( ((A)>>(32-(n))) & ( (1UL << (n)) - 1 ) ) ) +#define ROR32( A, n ) ROL32( (A), 32-(n) ) + +#endif //__MICHAEL_H__ + + diff --git a/drivers/staging/vt6655/power.c b/drivers/staging/vt6655/power.c new file mode 100644 index 000000000000..edd8336712a2 --- /dev/null +++ b/drivers/staging/vt6655/power.c @@ -0,0 +1,441 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * File: power.c + * + * Purpose: Handles 802.11 power managment functions + * + * Author: Lyndon Chen + * + * Date: July 17, 2002 + * + * Functions: + * PSvEnablePowerSaving - Enable Power Saving Mode + * PSvDiasblePowerSaving - Disable Power Saving Mode + * PSbConsiderPowerDown - Decide if we can Power Down + * PSvSendPSPOLL - Send PS-POLL packet + * PSbSendNullPacket - Send Null packet + * PSbIsNextTBTTWakeUp - Decide if we need to wake up at next Beacon + * + * Revision History: + * + */ + + + +#if !defined(__TTYPE_H__) +#include "ttype.h" +#endif +#if !defined(__TBIT_H__) +#include "tbit.h" +#endif +#if !defined(__MAC_H__) +#include "mac.h" +#endif +#if !defined(__DEVICE_H__) +#include "device.h" +#endif +#if !defined(__WMGR_H__) +#include "wmgr.h" +#endif +#if !defined(__POWER_H__) +#include "power.h" +#endif +#if !defined(__WCMD_H__) +#include "wcmd.h" +#endif +#if !defined(__TBIT_H__) +#include "tbit.h" +#endif +#if !defined(__UMEM_H__) +#include "umem.h" +#endif +#if !defined(__RXTX_H__) +#include "rxtx.h" +#endif +#if !defined(__CARD_H__) +#include "card.h" +#endif + + + + +/*--------------------- Static Definitions -------------------------*/ + + + + +/*--------------------- Static Classes ----------------------------*/ + +/*--------------------- Static Variables --------------------------*/ +static int msglevel =MSG_LEVEL_INFO; +/*--------------------- Static Functions --------------------------*/ + + +/*--------------------- Export Variables --------------------------*/ + + +/*--------------------- Export Functions --------------------------*/ + +/*+ + * + * Routine Description: + * Enable hw power saving functions + * + * Return Value: + * None. + * +-*/ + + +VOID +PSvEnablePowerSaving( + IN HANDLE hDeviceContext, + IN WORD wListenInterval + ) +{ + PSDevice pDevice = (PSDevice)hDeviceContext; + PSMgmtObject pMgmt = pDevice->pMgmt; + WORD wAID = pMgmt->wCurrAID | BIT14 | BIT15; + + // set period of power up before TBTT + VNSvOutPortW(pDevice->PortOffset + MAC_REG_PWBT, C_PWBT); + if (pDevice->eOPMode != OP_MODE_ADHOC) { + // set AID + VNSvOutPortW(pDevice->PortOffset + MAC_REG_AIDATIM, wAID); + } else { + // set ATIM Window + MACvWriteATIMW(pDevice->PortOffset, pMgmt->wCurrATIMWindow); + } + // Set AutoSleep + MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCFG, PSCFG_AUTOSLEEP); + // Set HWUTSF + MACvRegBitsOn(pDevice->PortOffset, MAC_REG_TFTCTL, TFTCTL_HWUTSF); + + if (wListenInterval >= 2) { + // clear always listen beacon + MACvRegBitsOff(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_ALBCN); + //pDevice->wCFG &= ~CFG_ALB; + // first time set listen next beacon + MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_LNBCN); + pMgmt->wCountToWakeUp = wListenInterval; + } + else { + // always listen beacon + MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_ALBCN); + //pDevice->wCFG |= CFG_ALB; + pMgmt->wCountToWakeUp = 0; + } + + // enable power saving hw function + MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_PSEN); + pDevice->bEnablePSMode = TRUE; + + if (pDevice->eOPMode == OP_MODE_ADHOC) { +// bMgrPrepareBeaconToSend((HANDLE)pDevice, pMgmt); + } + // We don't send null pkt in ad hoc mode since beacon will handle this. + else if (pDevice->eOPMode == OP_MODE_INFRASTRUCTURE) { + PSbSendNullPacket(pDevice); + } + pDevice->bPWBitOn = TRUE; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "PS:Power Saving Mode Enable... \n"); + return; +} + + + + + + +/*+ + * + * Routine Description: + * Disable hw power saving functions + * + * Return Value: + * None. + * +-*/ + +VOID +PSvDisablePowerSaving( + IN HANDLE hDeviceContext + ) +{ + PSDevice pDevice = (PSDevice)hDeviceContext; +// PSMgmtObject pMgmt = pDevice->pMgmt; + + // disable power saving hw function + MACbPSWakeup(pDevice->PortOffset); + //clear AutoSleep + MACvRegBitsOff(pDevice->PortOffset, MAC_REG_PSCFG, PSCFG_AUTOSLEEP); + //clear HWUTSF + MACvRegBitsOff(pDevice->PortOffset, MAC_REG_TFTCTL, TFTCTL_HWUTSF); + // set always listen beacon + MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_ALBCN); + + pDevice->bEnablePSMode = FALSE; + + if (pDevice->eOPMode == OP_MODE_INFRASTRUCTURE) { + PSbSendNullPacket(pDevice); + } + pDevice->bPWBitOn = FALSE; + return; +} + + +/*+ + * + * Routine Description: + * Consider to power down when no more packets to tx or rx. + * + * Return Value: + * TRUE, if power down success + * FALSE, if fail +-*/ + + +BOOL +PSbConsiderPowerDown( + IN HANDLE hDeviceContext, + IN BOOL bCheckRxDMA, + IN BOOL bCheckCountToWakeUp + ) +{ + PSDevice pDevice = (PSDevice)hDeviceContext; + PSMgmtObject pMgmt = pDevice->pMgmt; + UINT uIdx; + + // check if already in Doze mode + if (MACbIsRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_PS)) + return TRUE; + + if (pMgmt->eCurrMode != WMAC_MODE_IBSS_STA) { + // check if in TIM wake period + if (pMgmt->bInTIMWake) + return FALSE; + } + + // check scan state + if (pDevice->bCmdRunning) + return FALSE; + + // Froce PSEN on + MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_PSEN); + + // check if all TD are empty, + for (uIdx = 0; uIdx < TYPE_MAXTD; uIdx ++) { + if (pDevice->iTDUsed[uIdx] != 0) + return FALSE; + } + + // check if rx isr is clear + if (bCheckRxDMA && + ((pDevice->dwIsr& ISR_RXDMA0) != 0) && + ((pDevice->dwIsr & ISR_RXDMA1) != 0)){ + return FALSE; + }; + + if (pMgmt->eCurrMode != WMAC_MODE_IBSS_STA) { + if (bCheckCountToWakeUp && + (pMgmt->wCountToWakeUp == 0 || pMgmt->wCountToWakeUp == 1)) { + return FALSE; + } + } + + // no Tx, no Rx isr, now go to Doze + MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_GO2DOZE); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Go to Doze ZZZZZZZZZZZZZZZ\n"); + return TRUE; +} + + + +/*+ + * + * Routine Description: + * Send PS-POLL packet + * + * Return Value: + * None. + * +-*/ + + + +VOID +PSvSendPSPOLL( + IN HANDLE hDeviceContext + ) +{ + PSDevice pDevice = (PSDevice)hDeviceContext; + PSMgmtObject pMgmt = pDevice->pMgmt; + PSTxMgmtPacket pTxPacket = NULL; + + + memset(pMgmt->pbyPSPacketPool, 0, sizeof(STxMgmtPacket) + WLAN_HDR_ADDR2_LEN); + pTxPacket = (PSTxMgmtPacket)pMgmt->pbyPSPacketPool; + pTxPacket->p80211Header = (PUWLAN_80211HDR)((PBYTE)pTxPacket + sizeof(STxMgmtPacket)); + pTxPacket->p80211Header->sA2.wFrameCtl = cpu_to_le16( + ( + WLAN_SET_FC_FTYPE(WLAN_TYPE_CTL) | + WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_PSPOLL) | + WLAN_SET_FC_PWRMGT(0) + )); + pTxPacket->p80211Header->sA2.wDurationID = pMgmt->wCurrAID | BIT14 | BIT15; + memcpy(pTxPacket->p80211Header->sA2.abyAddr1, pMgmt->abyCurrBSSID, WLAN_ADDR_LEN); + memcpy(pTxPacket->p80211Header->sA2.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN); + pTxPacket->cbMPDULen = WLAN_HDR_ADDR2_LEN; + pTxPacket->cbPayloadLen = 0; + // send the frame + if (csMgmt_xmit(pDevice, pTxPacket) != CMD_STATUS_PENDING) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Send PS-Poll packet failed..\n"); + } + else { +// DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Send PS-Poll packet success..\n"); + }; + + return; +} + + + +/*+ + * + * Routine Description: + * Send NULL packet to AP for notification power state of STA + * + * Return Value: + * None. + * +-*/ +BOOL +PSbSendNullPacket( + IN HANDLE hDeviceContext + ) +{ + PSDevice pDevice = (PSDevice)hDeviceContext; + PSTxMgmtPacket pTxPacket = NULL; + PSMgmtObject pMgmt = pDevice->pMgmt; + UINT uIdx; + + + if (pDevice->bLinkPass == FALSE) { + return FALSE; + } + #ifdef TxInSleep + if ((pDevice->bEnablePSMode == FALSE) && + (pDevice->fTxDataInSleep == FALSE)){ + return FALSE; + } +#else + if (pDevice->bEnablePSMode == FALSE) { + return FALSE; + } +#endif + if (pDevice->bEnablePSMode) { + for (uIdx = 0; uIdx < TYPE_MAXTD; uIdx ++) { + if (pDevice->iTDUsed[uIdx] != 0) + return FALSE; + } + } + + memset(pMgmt->pbyPSPacketPool, 0, sizeof(STxMgmtPacket) + WLAN_NULLDATA_FR_MAXLEN); + pTxPacket = (PSTxMgmtPacket)pMgmt->pbyPSPacketPool; + pTxPacket->p80211Header = (PUWLAN_80211HDR)((PBYTE)pTxPacket + sizeof(STxMgmtPacket)); + + if (pDevice->bEnablePSMode) { + + pTxPacket->p80211Header->sA3.wFrameCtl = cpu_to_le16( + ( + WLAN_SET_FC_FTYPE(WLAN_TYPE_DATA) | + WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_NULL) | + WLAN_SET_FC_PWRMGT(1) + )); + } + else { + pTxPacket->p80211Header->sA3.wFrameCtl = cpu_to_le16( + ( + WLAN_SET_FC_FTYPE(WLAN_TYPE_DATA) | + WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_NULL) | + WLAN_SET_FC_PWRMGT(0) + )); + } + + if(pMgmt->eCurrMode != WMAC_MODE_IBSS_STA) { + pTxPacket->p80211Header->sA3.wFrameCtl |= cpu_to_le16((WORD)WLAN_SET_FC_TODS(1)); + } + + memcpy(pTxPacket->p80211Header->sA3.abyAddr1, pMgmt->abyCurrBSSID, WLAN_ADDR_LEN); + memcpy(pTxPacket->p80211Header->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN); + memcpy(pTxPacket->p80211Header->sA3.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN); + pTxPacket->cbMPDULen = WLAN_HDR_ADDR3_LEN; + pTxPacket->cbPayloadLen = 0; + // send the frame + if (csMgmt_xmit(pDevice, pTxPacket) != CMD_STATUS_PENDING) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Send Null Packet failed !\n"); + return FALSE; + } + else { + +// DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Send Null Packet success....\n"); + } + + + return TRUE ; +} + +/*+ + * + * Routine Description: + * Check if Next TBTT must wake up + * + * Return Value: + * None. + * +-*/ + +BOOL +PSbIsNextTBTTWakeUp( + IN HANDLE hDeviceContext + ) +{ + + PSDevice pDevice = (PSDevice)hDeviceContext; + PSMgmtObject pMgmt = pDevice->pMgmt; + BOOL bWakeUp = FALSE; + + if (pMgmt->wListenInterval >= 2) { + if (pMgmt->wCountToWakeUp == 0) { + pMgmt->wCountToWakeUp = pMgmt->wListenInterval; + } + + pMgmt->wCountToWakeUp --; + + if (pMgmt->wCountToWakeUp == 1) { + // Turn on wake up to listen next beacon + MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_LNBCN); + bWakeUp = TRUE; + } + + } + + return bWakeUp; +} + diff --git a/drivers/staging/vt6655/power.h b/drivers/staging/vt6655/power.h new file mode 100644 index 000000000000..a01e7e9aaf67 --- /dev/null +++ b/drivers/staging/vt6655/power.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * File: power.h + * + * Purpose: Handles 802.11 power managment functions + * + * Author: Lyndon Chen + * + * Date: July 17, 2002 + * + */ + +#ifndef __POWER_H__ +#define __POWER_H__ + + +/*--------------------- Export Definitions -------------------------*/ +#define C_PWBT 1000 // micro sec. power up before TBTT +#define PS_FAST_INTERVAL 1 // Fast power saving listen interval +#define PS_MAX_INTERVAL 4 // MAX power saving listen interval + +/*--------------------- Export Classes ----------------------------*/ + +/*--------------------- Export Variables --------------------------*/ + + +/*--------------------- Export Types ------------------------------*/ + + +/*--------------------- Export Functions --------------------------*/ + +// IN PSDevice pDevice +// IN PSDevice hDeviceContext + +BOOL +PSbConsiderPowerDown( + IN HANDLE hDeviceContext, + IN BOOL bCheckRxDMA, + IN BOOL bCheckCountToWakeUp + ); + +VOID +PSvDisablePowerSaving( + IN HANDLE hDeviceContext + ); + +VOID +PSvEnablePowerSaving( + IN HANDLE hDeviceContext, + IN WORD wListenInterval + ); + +VOID +PSvSendPSPOLL( + IN HANDLE hDeviceContext + ); + +BOOL +PSbSendNullPacket( + IN HANDLE hDeviceContext + ); + +BOOL +PSbIsNextTBTTWakeUp( + IN HANDLE hDeviceContext + ); + +#endif //__POWER_H__ diff --git a/drivers/staging/vt6655/rc4.c b/drivers/staging/vt6655/rc4.c new file mode 100644 index 000000000000..0345e3247f4d --- /dev/null +++ b/drivers/staging/vt6655/rc4.c @@ -0,0 +1,86 @@ +/* + * File: rc4.c + * + * 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. + * + * Purpose: + * + * Functions: + * + * Revision History: + * + * Author: Kyle Hsu + * + * Date: Sep 4, 2002 + * + */ + +#if !defined(__RC4_H__) +#include "rc4.h" +#endif + +VOID rc4_init(PRC4Ext pRC4, PBYTE pbyKey, UINT cbKey_len) +{ + UINT ust1, ust2; + UINT keyindex; + UINT stateindex; + PBYTE pbyst; + UINT idx; + + pbyst = pRC4->abystate; + pRC4->ux = 0; + pRC4->uy = 0; + for (idx = 0; idx < 256; idx++) + pbyst[idx] = (BYTE)idx; + keyindex = 0; + stateindex = 0; + for (idx = 0; idx < 256; idx++) { + ust1 = pbyst[idx]; + stateindex = (stateindex + pbyKey[keyindex] + ust1) & 0xff; + ust2 = pbyst[stateindex]; + pbyst[stateindex] = (BYTE)ust1; + pbyst[idx] = (BYTE)ust2; + if (++keyindex >= cbKey_len) + keyindex = 0; + } +} + +UINT rc4_byte(PRC4Ext pRC4) +{ + UINT ux; + UINT uy; + UINT ustx, usty; + PBYTE pbyst; + + pbyst = pRC4->abystate; + ux = (pRC4->ux + 1) & 0xff; + ustx = pbyst[ux]; + uy = (ustx + pRC4->uy) & 0xff; + usty = pbyst[uy]; + pRC4->ux = ux; + pRC4->uy = uy; + pbyst[uy] = (BYTE)ustx; + pbyst[ux] = (BYTE)usty; + + return pbyst[(ustx + usty) & 0xff]; +} + +VOID rc4_encrypt(PRC4Ext pRC4, PBYTE pbyDest, + PBYTE pbySrc, UINT cbData_len) +{ + UINT ii; + for (ii = 0; ii < cbData_len; ii++) + pbyDest[ii] = (BYTE)(pbySrc[ii] ^ rc4_byte(pRC4)); +} diff --git a/drivers/staging/vt6655/rc4.h b/drivers/staging/vt6655/rc4.h new file mode 100644 index 000000000000..4e3ccc559c8f --- /dev/null +++ b/drivers/staging/vt6655/rc4.h @@ -0,0 +1,51 @@ +/* + * File: rc4.h + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Purpose: + * + * Functions: + * + * Revision History: + * + * Author: Kyle Hsu + * + * Date: Sep 4, 2002 + * + */ + +#ifndef __RC4_H__ +#define __RC4_H__ + +#if !defined(__TTYPE_H__) +#include "ttype.h" +#endif + + + +/*--------------------- Export Definitions -------------------------*/ +/*--------------------- Export Types ------------------------------*/ +typedef struct { + UINT ux; + UINT uy; + BYTE abystate[256]; +} RC4Ext, DEF* PRC4Ext; + +VOID rc4_init(PRC4Ext pRC4, PBYTE pbyKey, UINT cbKey_len); +UINT rc4_byte(PRC4Ext pRC4); +void rc4_encrypt(PRC4Ext pRC4, PBYTE pbyDest, PBYTE pbySrc, UINT cbData_len); + +#endif //__RC4_H__ diff --git a/drivers/staging/vt6655/rf.c b/drivers/staging/vt6655/rf.c new file mode 100644 index 000000000000..9d4e3eb7c8e5 --- /dev/null +++ b/drivers/staging/vt6655/rf.c @@ -0,0 +1,1283 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * File: rf.c + * + * Purpose: rf function code + * + * Author: Jerry Chen + * + * Date: Feb. 19, 2004 + * + * Functions: + * IFRFbWriteEmbeded - Embeded write RF register via MAC + * + * Revision History: + * + */ +#if !defined(__MAC_H__) +#include "mac.h" +#endif +#if !defined(__SROM_H__) +#include "srom.h" +#endif +#if !defined(__TBIT_H__) +#include "tbit.h" +#endif +#if !defined(__RF_H__) +#include "rf.h" +#endif +#if !defined(__BASEBAND_H__) +#include "baseband.h" +#endif + +/*--------------------- Static Definitions -------------------------*/ + +//static int msglevel =MSG_LEVEL_INFO; + +#define BY_RF2959_REG_LEN 23 //24bits +#define CB_RF2959_INIT_SEQ 15 +#define SWITCH_CHANNEL_DELAY_RF2959 200 //us +#define RF2959_PWR_IDX_LEN 32 + +#define BY_MA2825_REG_LEN 23 //24bit +#define CB_MA2825_INIT_SEQ 13 +#define SWITCH_CHANNEL_DELAY_MA2825 200 //us +#define MA2825_PWR_IDX_LEN 31 + +#define BY_AL2230_REG_LEN 23 //24bit +#define CB_AL2230_INIT_SEQ 15 +#define SWITCH_CHANNEL_DELAY_AL2230 200 //us +#define AL2230_PWR_IDX_LEN 64 + + +#define BY_UW2451_REG_LEN 23 +#define CB_UW2451_INIT_SEQ 6 +#define SWITCH_CHANNEL_DELAY_UW2451 200 //us +#define UW2451_PWR_IDX_LEN 25 + +//{{ RobertYu: 20041118 +#define BY_MA2829_REG_LEN 23 //24bit +#define CB_MA2829_INIT_SEQ 13 +#define SWITCH_CHANNEL_DELAY_MA2829 200 //us +#define MA2829_PWR_IDX_LEN 64 +//}} RobertYu + +//{{ RobertYu:20050103 +#define BY_AL7230_REG_LEN 23 //24bit +#define CB_AL7230_INIT_SEQ 16 +#define SWITCH_CHANNEL_DELAY_AL7230 200 //us +#define AL7230_PWR_IDX_LEN 64 +//}} RobertYu + +//{{ RobertYu: 20041210 +#define BY_UW2452_REG_LEN 23 +#define CB_UW2452_INIT_SEQ 5 //RoberYu:20050113, Rev0.2 Programming Guide(remove R3, so 6-->5) +#define SWITCH_CHANNEL_DELAY_UW2452 100 //us +#define UW2452_PWR_IDX_LEN 64 +//}} RobertYu + +#define BY_VT3226_REG_LEN 23 +#define CB_VT3226_INIT_SEQ 12 +#define SWITCH_CHANNEL_DELAY_VT3226 200 //us +#define VT3226_PWR_IDX_LEN 16 + +/*--------------------- Static Classes ----------------------------*/ + +/*--------------------- Static Variables --------------------------*/ + + + +const DWORD dwAL2230InitTable[CB_AL2230_INIT_SEQ] = { + 0x03F79000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // + 0x03333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // + 0x01A00200+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // + 0x00FFF300+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // + 0x0005A400+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // + 0x0F4DC500+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // + 0x0805B600+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // + 0x0146C700+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // + 0x00068800+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // + 0x0403B900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // + 0x00DBBA00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // + 0x00099B00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // + 0x0BDFFC00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x00000D00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x00580F00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW + }; + +const DWORD dwAL2230ChannelTable0[CB_MAX_CHANNEL] = { + 0x03F79000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 1, Tf = 2412MHz + 0x03F79000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 2, Tf = 2417MHz + 0x03E79000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 3, Tf = 2422MHz + 0x03E79000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 4, Tf = 2427MHz + 0x03F7A000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 5, Tf = 2432MHz + 0x03F7A000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 6, Tf = 2437MHz + 0x03E7A000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 7, Tf = 2442MHz + 0x03E7A000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 8, Tf = 2447MHz + 0x03F7B000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 9, Tf = 2452MHz + 0x03F7B000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 10, Tf = 2457MHz + 0x03E7B000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 11, Tf = 2462MHz + 0x03E7B000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 12, Tf = 2467MHz + 0x03F7C000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 13, Tf = 2472MHz + 0x03E7C000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW // channel = 14, Tf = 2412M + }; + +const DWORD dwAL2230ChannelTable1[CB_MAX_CHANNEL] = { + 0x03333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 1, Tf = 2412MHz + 0x0B333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 2, Tf = 2417MHz + 0x03333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 3, Tf = 2422MHz + 0x0B333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 4, Tf = 2427MHz + 0x03333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 5, Tf = 2432MHz + 0x0B333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 6, Tf = 2437MHz + 0x03333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 7, Tf = 2442MHz + 0x0B333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 8, Tf = 2447MHz + 0x03333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 9, Tf = 2452MHz + 0x0B333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 10, Tf = 2457MHz + 0x03333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 11, Tf = 2462MHz + 0x0B333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 12, Tf = 2467MHz + 0x03333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 13, Tf = 2472MHz + 0x06666100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW // channel = 14, Tf = 2412M + }; + +DWORD dwAL2230PowerTable[AL2230_PWR_IDX_LEN] = { + 0x04040900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x04041900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x04042900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x04043900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x04044900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x04045900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x04046900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x04047900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x04048900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x04049900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x0404A900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x0404B900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x0404C900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x0404D900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x0404E900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x0404F900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x04050900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x04051900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x04052900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x04053900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x04054900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x04055900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x04056900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x04057900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x04058900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x04059900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x0405A900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x0405B900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x0405C900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x0405D900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x0405E900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x0405F900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x04060900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x04061900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x04062900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x04063900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x04064900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x04065900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x04066900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x04067900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x04068900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x04069900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x0406A900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x0406B900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x0406C900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x0406D900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x0406E900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x0406F900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x04070900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x04071900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x04072900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x04073900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x04074900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x04075900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x04076900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x04077900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x04078900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x04079900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x0407A900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x0407B900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x0407C900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x0407D900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x0407E900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x0407F900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW + }; + +//{{ RobertYu:20050104 +// 40MHz reference frequency +// Need to Pull PLLON(PE3) low when writing channel registers through 3-wire. +const DWORD dwAL7230InitTable[CB_AL7230_INIT_SEQ] = { + 0x00379000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Channel1 // Need modify for 11a + 0x13333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Channel1 // Need modify for 11a + 0x841FF200+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11a: 451FE2 + 0x3FDFA300+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11a: 5FDFA3 + 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // 11b/g // Need modify for 11a + //0x802B4500+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11a: 8D1B45 + // RoberYu:20050113, Rev0.47 Regsiter Setting Guide + 0x802B5500+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11a: 8D1B55 + 0x56AF3600+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, + 0xCE020700+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11a: 860207 + 0x6EBC0800+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, + 0x221BB900+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, + 0xE0000A00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11a: E0600A + 0x08031B00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // init 0x080B1B00 => 0x080F1B00 for 3 wire control TxGain(D10) + //0x00093C00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11a: 00143C + // RoberYu:20050113, Rev0.47 Regsiter Setting Guide + 0x000A3C00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11a: 00143C + 0xFFFFFD00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, + 0x00000E00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, + 0x1ABA8F00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW // Need modify for 11a: 12BACF + }; + +const DWORD dwAL7230InitTableAMode[CB_AL7230_INIT_SEQ] = { + 0x0FF52000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Channel184 // Need modify for 11b/g + 0x00000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Channel184 // Need modify for 11b/g + 0x451FE200+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11b/g + 0x5FDFA300+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11b/g + 0x67F78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // 11a // Need modify for 11b/g + 0x853F5500+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11b/g, RoberYu:20050113 + 0x56AF3600+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, + 0xCE020700+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11b/g + 0x6EBC0800+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, + 0x221BB900+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, + 0xE0600A00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11b/g + 0x08031B00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // init 0x080B1B00 => 0x080F1B00 for 3 wire control TxGain(D10) + 0x00147C00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11b/g + 0xFFFFFD00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, + 0x00000E00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, + 0x12BACF00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW // Need modify for 11b/g + }; + + +const DWORD dwAL7230ChannelTable0[CB_MAX_CHANNEL] = { + 0x00379000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 1, Tf = 2412MHz + 0x00379000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 2, Tf = 2417MHz + 0x00379000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 3, Tf = 2422MHz + 0x00379000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 4, Tf = 2427MHz + 0x0037A000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 5, Tf = 2432MHz + 0x0037A000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 6, Tf = 2437MHz + 0x0037A000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 7, Tf = 2442MHz + 0x0037A000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 8, Tf = 2447MHz //RobertYu: 20050218, update for APNode 0.49 + 0x0037B000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 9, Tf = 2452MHz //RobertYu: 20050218, update for APNode 0.49 + 0x0037B000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 10, Tf = 2457MHz //RobertYu: 20050218, update for APNode 0.49 + 0x0037B000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 11, Tf = 2462MHz //RobertYu: 20050218, update for APNode 0.49 + 0x0037B000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 12, Tf = 2467MHz //RobertYu: 20050218, update for APNode 0.49 + 0x0037C000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 13, Tf = 2472MHz //RobertYu: 20050218, update for APNode 0.49 + 0x0037C000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 14, Tf = 2484MHz + + // 4.9G => Ch 183, 184, 185, 187, 188, 189, 192, 196 (Value:15 ~ 22) + 0x0FF52000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 183, Tf = 4915MHz (15) + 0x0FF52000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 184, Tf = 4920MHz (16) + 0x0FF52000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 185, Tf = 4925MHz (17) + 0x0FF52000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 187, Tf = 4935MHz (18) + 0x0FF52000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 188, Tf = 4940MHz (19) + 0x0FF52000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 189, Tf = 4945MHz (20) + 0x0FF53000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 192, Tf = 4960MHz (21) + 0x0FF53000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 196, Tf = 4980MHz (22) + + // 5G => Ch 7, 8, 9, 11, 12, 16, 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64, + // 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165 (Value 23 ~ 56) + + 0x0FF54000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 7, Tf = 5035MHz (23) + 0x0FF54000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 8, Tf = 5040MHz (24) + 0x0FF54000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 9, Tf = 5045MHz (25) + 0x0FF54000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 11, Tf = 5055MHz (26) + 0x0FF54000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 12, Tf = 5060MHz (27) + 0x0FF55000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 16, Tf = 5080MHz (28) + 0x0FF56000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 34, Tf = 5170MHz (29) + 0x0FF56000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 36, Tf = 5180MHz (30) + 0x0FF57000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 38, Tf = 5190MHz (31) //RobertYu: 20050218, update for APNode 0.49 + 0x0FF57000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 40, Tf = 5200MHz (32) + 0x0FF57000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 42, Tf = 5210MHz (33) + 0x0FF57000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 44, Tf = 5220MHz (34) + 0x0FF57000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 46, Tf = 5230MHz (35) + 0x0FF57000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 48, Tf = 5240MHz (36) + 0x0FF58000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 52, Tf = 5260MHz (37) + 0x0FF58000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 56, Tf = 5280MHz (38) + 0x0FF58000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 60, Tf = 5300MHz (39) + 0x0FF59000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 64, Tf = 5320MHz (40) + + 0x0FF5C000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 100, Tf = 5500MHz (41) + 0x0FF5C000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 104, Tf = 5520MHz (42) + 0x0FF5C000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 108, Tf = 5540MHz (43) + 0x0FF5D000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 112, Tf = 5560MHz (44) + 0x0FF5D000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 116, Tf = 5580MHz (45) + 0x0FF5D000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 120, Tf = 5600MHz (46) + 0x0FF5E000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 124, Tf = 5620MHz (47) + 0x0FF5E000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 128, Tf = 5640MHz (48) + 0x0FF5E000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 132, Tf = 5660MHz (49) + 0x0FF5F000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 136, Tf = 5680MHz (50) + 0x0FF5F000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 140, Tf = 5700MHz (51) + 0x0FF60000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 149, Tf = 5745MHz (52) + 0x0FF60000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 153, Tf = 5765MHz (53) + 0x0FF60000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 157, Tf = 5785MHz (54) + 0x0FF61000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 161, Tf = 5805MHz (55) + 0x0FF61000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW // channel = 165, Tf = 5825MHz (56) + }; + +const DWORD dwAL7230ChannelTable1[CB_MAX_CHANNEL] = { + 0x13333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 1, Tf = 2412MHz + 0x1B333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 2, Tf = 2417MHz + 0x03333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 3, Tf = 2422MHz + 0x0B333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 4, Tf = 2427MHz + 0x13333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 5, Tf = 2432MHz + 0x1B333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 6, Tf = 2437MHz + 0x03333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 7, Tf = 2442MHz + 0x0B333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 8, Tf = 2447MHz + 0x13333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 9, Tf = 2452MHz + 0x1B333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 10, Tf = 2457MHz + 0x03333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 11, Tf = 2462MHz + 0x0B333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 12, Tf = 2467MHz + 0x13333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 13, Tf = 2472MHz + 0x06666100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 14, Tf = 2484MHz + + // 4.9G => Ch 183, 184, 185, 187, 188, 189, 192, 196 (Value:15 ~ 22) + 0x1D555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 183, Tf = 4915MHz (15) + 0x00000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 184, Tf = 4920MHz (16) + 0x02AAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 185, Tf = 4925MHz (17) + 0x08000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 187, Tf = 4935MHz (18) + 0x0AAAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 188, Tf = 4940MHz (19) + 0x0D555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 189, Tf = 4945MHz (20) + 0x15555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 192, Tf = 4960MHz (21) + 0x00000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 196, Tf = 4980MHz (22) + + // 5G => Ch 7, 8, 9, 11, 12, 16, 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64, + // 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165 (Value 23 ~ 56) + 0x1D555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 7, Tf = 5035MHz (23) + 0x00000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 8, Tf = 5040MHz (24) + 0x02AAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 9, Tf = 5045MHz (25) + 0x08000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 11, Tf = 5055MHz (26) + 0x0AAAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 12, Tf = 5060MHz (27) + 0x15555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 16, Tf = 5080MHz (28) + 0x05555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 34, Tf = 5170MHz (29) + 0x0AAAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 36, Tf = 5180MHz (30) + 0x10000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 38, Tf = 5190MHz (31) + 0x15555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 40, Tf = 5200MHz (32) + 0x1AAAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 42, Tf = 5210MHz (33) + 0x00000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 44, Tf = 5220MHz (34) + 0x05555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 46, Tf = 5230MHz (35) + 0x0AAAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 48, Tf = 5240MHz (36) + 0x15555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 52, Tf = 5260MHz (37) + 0x00000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 56, Tf = 5280MHz (38) + 0x0AAAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 60, Tf = 5300MHz (39) + 0x15555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 64, Tf = 5320MHz (40) + 0x15555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 100, Tf = 5500MHz (41) + 0x00000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 104, Tf = 5520MHz (42) + 0x0AAAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 108, Tf = 5540MHz (43) + 0x15555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 112, Tf = 5560MHz (44) + 0x00000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 116, Tf = 5580MHz (45) + 0x0AAAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 120, Tf = 5600MHz (46) + 0x15555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 124, Tf = 5620MHz (47) + 0x00000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 128, Tf = 5640MHz (48) + 0x0AAAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 132, Tf = 5660MHz (49) + 0x15555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 136, Tf = 5680MHz (50) + 0x00000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 140, Tf = 5700MHz (51) + 0x18000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 149, Tf = 5745MHz (52) + 0x02AAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 153, Tf = 5765MHz (53) + 0x0D555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 157, Tf = 5785MHz (54) + 0x18000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 161, Tf = 5805MHz (55) + 0x02AAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW // channel = 165, Tf = 5825MHz (56) + }; + +const DWORD dwAL7230ChannelTable2[CB_MAX_CHANNEL] = { + 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 1, Tf = 2412MHz + 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 2, Tf = 2417MHz + 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 3, Tf = 2422MHz + 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 4, Tf = 2427MHz + 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 5, Tf = 2432MHz + 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 6, Tf = 2437MHz + 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 7, Tf = 2442MHz + 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 8, Tf = 2447MHz + 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 9, Tf = 2452MHz + 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 10, Tf = 2457MHz + 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 11, Tf = 2462MHz + 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 12, Tf = 2467MHz + 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 13, Tf = 2472MHz + 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 14, Tf = 2484MHz + + // 4.9G => Ch 183, 184, 185, 187, 188, 189, 192, 196 (Value:15 ~ 22) + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 183, Tf = 4915MHz (15) + 0x67D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 184, Tf = 4920MHz (16) + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 185, Tf = 4925MHz (17) + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 187, Tf = 4935MHz (18) + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 188, Tf = 4940MHz (19) + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 189, Tf = 4945MHz (20) + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 192, Tf = 4960MHz (21) + 0x67D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 196, Tf = 4980MHz (22) + + // 5G => Ch 7, 8, 9, 11, 12, 16, 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64, + // 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165 (Value 23 ~ 56) + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 7, Tf = 5035MHz (23) + 0x67D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 8, Tf = 5040MHz (24) + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 9, Tf = 5045MHz (25) + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 11, Tf = 5055MHz (26) + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 12, Tf = 5060MHz (27) + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 16, Tf = 5080MHz (28) + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 34, Tf = 5170MHz (29) + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 36, Tf = 5180MHz (30) + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 38, Tf = 5190MHz (31) + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 40, Tf = 5200MHz (32) + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 42, Tf = 5210MHz (33) + 0x67D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 44, Tf = 5220MHz (34) + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 46, Tf = 5230MHz (35) + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 48, Tf = 5240MHz (36) + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 52, Tf = 5260MHz (37) + 0x67D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 56, Tf = 5280MHz (38) + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 60, Tf = 5300MHz (39) + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 64, Tf = 5320MHz (40) + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 100, Tf = 5500MHz (41) + 0x67D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 104, Tf = 5520MHz (42) + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 108, Tf = 5540MHz (43) + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 112, Tf = 5560MHz (44) + 0x67D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 116, Tf = 5580MHz (45) + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 120, Tf = 5600MHz (46) + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 124, Tf = 5620MHz (47) + 0x67D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 128, Tf = 5640MHz (48) + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 132, Tf = 5660MHz (49) + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 136, Tf = 5680MHz (50) + 0x67D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 140, Tf = 5700MHz (51) + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 149, Tf = 5745MHz (52) + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 153, Tf = 5765MHz (53) + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 157, Tf = 5785MHz (54) + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 161, Tf = 5805MHz (55) + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW // channel = 165, Tf = 5825MHz (56) + }; +//}} RobertYu + + + + +/*--------------------- Static Functions --------------------------*/ + + + + +/* + * Description: AIROHA IFRF chip init function + * + * Parameters: + * In: + * dwIoBase - I/O base address + * Out: + * none + * + * Return Value: TRUE if succeeded; FALSE if failed. + * + */ +BOOL s_bAL7230Init (DWORD_PTR dwIoBase) +{ + int ii; + BOOL bResult; + + bResult = TRUE; + + //3-wire control for normal mode + VNSvOutPortB(dwIoBase + MAC_REG_SOFTPWRCTL, 0); + + MACvWordRegBitsOn(dwIoBase, MAC_REG_SOFTPWRCTL, (SOFTPWRCTL_SWPECTI | + SOFTPWRCTL_TXPEINV)); + BBvPowerSaveModeOFF(dwIoBase); //RobertYu:20050106, have DC value for Calibration + + for (ii = 0; ii < CB_AL7230_INIT_SEQ; ii++) + bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL7230InitTable[ii]); + + // PLL On + MACvWordRegBitsOn(dwIoBase, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_SWPE3); + + //Calibration + MACvTimer0MicroSDelay(dwIoBase, 150);//150us + bResult &= IFRFbWriteEmbeded(dwIoBase, (0x9ABA8F00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW)); //TXDCOC:active, RCK:diable + MACvTimer0MicroSDelay(dwIoBase, 30);//30us + bResult &= IFRFbWriteEmbeded(dwIoBase, (0x3ABA8F00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW)); //TXDCOC:diable, RCK:active + MACvTimer0MicroSDelay(dwIoBase, 30);//30us + bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL7230InitTable[CB_AL7230_INIT_SEQ-1]); //TXDCOC:diable, RCK:diable + + MACvWordRegBitsOn(dwIoBase, MAC_REG_SOFTPWRCTL, (SOFTPWRCTL_SWPE3 | + SOFTPWRCTL_SWPE2 | + SOFTPWRCTL_SWPECTI | + SOFTPWRCTL_TXPEINV)); + + BBvPowerSaveModeON(dwIoBase); // RobertYu:20050106 + + // PE1: TX_ON, PE2: RX_ON, PE3: PLLON + //3-wire control for power saving mode + VNSvOutPortB(dwIoBase + MAC_REG_PSPWRSIG, (PSSIG_WPE3 | PSSIG_WPE2)); //1100 0000 + + return bResult; +} + +// Need to Pull PLLON low when writing channel registers through 3-wire interface +BOOL s_bAL7230SelectChannel (DWORD_PTR dwIoBase, BYTE byChannel) +{ + BOOL bResult; + + bResult = TRUE; + + // PLLON Off + MACvWordRegBitsOff(dwIoBase, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_SWPE3); + + bResult &= IFRFbWriteEmbeded (dwIoBase, dwAL7230ChannelTable0[byChannel-1]); //Reg0 + bResult &= IFRFbWriteEmbeded (dwIoBase, dwAL7230ChannelTable1[byChannel-1]); //Reg1 + bResult &= IFRFbWriteEmbeded (dwIoBase, dwAL7230ChannelTable2[byChannel-1]); //Reg4 + + // PLLOn On + MACvWordRegBitsOn(dwIoBase, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_SWPE3); + + // Set Channel[7] = 0 to tell H/W channel is changing now. + VNSvOutPortB(dwIoBase + MAC_REG_CHANNEL, (byChannel & 0x7F)); + MACvTimer0MicroSDelay(dwIoBase, SWITCH_CHANNEL_DELAY_AL7230); + // Set Channel[7] = 1 to tell H/W channel change is done. + VNSvOutPortB(dwIoBase + MAC_REG_CHANNEL, (byChannel | 0x80)); + + return bResult; +} + +/* + * Description: Select channel with UW2452 chip + * + * Parameters: + * In: + * dwIoBase - I/O base address + * uChannel - Channel number + * Out: + * none + * + * Return Value: TRUE if succeeded; FALSE if failed. + * + */ + + +//{{ RobertYu: 20041210 +/* + * Description: UW2452 IFRF chip init function + * + * Parameters: + * In: + * dwIoBase - I/O base address + * Out: + * none + * + * Return Value: TRUE if succeeded; FALSE if failed. + * + */ + + + +//}} RobertYu +//////////////////////////////////////////////////////////////////////////////// + +/* + * Description: VT3226 IFRF chip init function + * + * Parameters: + * In: + * dwIoBase - I/O base address + * Out: + * none + * + * Return Value: TRUE if succeeded; FALSE if failed. + * + */ + +/* + * Description: Select channel with VT3226 chip + * + * Parameters: + * In: + * dwIoBase - I/O base address + * uChannel - Channel number + * Out: + * none + * + * Return Value: TRUE if succeeded; FALSE if failed. + * + */ + + + +/*--------------------- Export Variables --------------------------*/ + +/*--------------------- Export Functions --------------------------*/ + +/* + * Description: Write to IF/RF, by embeded programming + * + * Parameters: + * In: + * dwIoBase - I/O base address + * dwData - data to write + * Out: + * none + * + * Return Value: TRUE if succeeded; FALSE if failed. + * + */ +BOOL IFRFbWriteEmbeded (DWORD_PTR dwIoBase, DWORD dwData) +{ + WORD ww; + DWORD dwValue; + + VNSvOutPortD(dwIoBase + MAC_REG_IFREGCTL, dwData); + + // W_MAX_TIMEOUT is the timeout period + for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { + VNSvInPortD(dwIoBase + MAC_REG_IFREGCTL, &dwValue); + if (BITbIsBitOn(dwValue, IFREGCTL_DONE)) + break; + } + + if (ww == W_MAX_TIMEOUT) { +// DBG_PORT80_ALWAYS(0x32); + return FALSE; + } + return TRUE; +} + + + +/* + * Description: RFMD RF2959 IFRF chip init function + * + * Parameters: + * In: + * dwIoBase - I/O base address + * Out: + * none + * + * Return Value: TRUE if succeeded; FALSE if failed. + * + */ + +/* + * Description: Select channel with RFMD 2959 chip + * + * Parameters: + * In: + * dwIoBase - I/O base address + * uChannel - Channel number + * Out: + * none + * + * Return Value: TRUE if succeeded; FALSE if failed. + * + */ + +/* + * Description: AIROHA IFRF chip init function + * + * Parameters: + * In: + * dwIoBase - I/O base address + * Out: + * none + * + * Return Value: TRUE if succeeded; FALSE if failed. + * + */ +BOOL RFbAL2230Init (DWORD_PTR dwIoBase) +{ + int ii; + BOOL bResult; + + bResult = TRUE; + + //3-wire control for normal mode + VNSvOutPortB(dwIoBase + MAC_REG_SOFTPWRCTL, 0); + + MACvWordRegBitsOn(dwIoBase, MAC_REG_SOFTPWRCTL, (SOFTPWRCTL_SWPECTI | + SOFTPWRCTL_TXPEINV)); +//2008-8-21 chester + // PLL Off + + MACvWordRegBitsOff(dwIoBase, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_SWPE3); + + + + //patch abnormal AL2230 frequency output +//2008-8-21 chester + IFRFbWriteEmbeded(dwIoBase, (0x07168700+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW)); + + + for (ii = 0; ii < CB_AL2230_INIT_SEQ; ii++) + bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL2230InitTable[ii]); +//2008-8-21 chester +MACvTimer0MicroSDelay(dwIoBase, 30); //delay 30 us + + // PLL On + MACvWordRegBitsOn(dwIoBase, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_SWPE3); + + MACvTimer0MicroSDelay(dwIoBase, 150);//150us + bResult &= IFRFbWriteEmbeded(dwIoBase, (0x00d80f00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW)); + MACvTimer0MicroSDelay(dwIoBase, 30);//30us + bResult &= IFRFbWriteEmbeded(dwIoBase, (0x00780f00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW)); + MACvTimer0MicroSDelay(dwIoBase, 30);//30us + bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL2230InitTable[CB_AL2230_INIT_SEQ-1]); + + MACvWordRegBitsOn(dwIoBase, MAC_REG_SOFTPWRCTL, (SOFTPWRCTL_SWPE3 | + SOFTPWRCTL_SWPE2 | + SOFTPWRCTL_SWPECTI | + SOFTPWRCTL_TXPEINV)); + + //3-wire control for power saving mode + VNSvOutPortB(dwIoBase + MAC_REG_PSPWRSIG, (PSSIG_WPE3 | PSSIG_WPE2)); //1100 0000 + + return bResult; +} + +BOOL RFbAL2230SelectChannel (DWORD_PTR dwIoBase, BYTE byChannel) +{ + BOOL bResult; + + bResult = TRUE; + + bResult &= IFRFbWriteEmbeded (dwIoBase, dwAL2230ChannelTable0[byChannel-1]); + bResult &= IFRFbWriteEmbeded (dwIoBase, dwAL2230ChannelTable1[byChannel-1]); + + // Set Channel[7] = 0 to tell H/W channel is changing now. + VNSvOutPortB(dwIoBase + MAC_REG_CHANNEL, (byChannel & 0x7F)); + MACvTimer0MicroSDelay(dwIoBase, SWITCH_CHANNEL_DELAY_AL2230); + // Set Channel[7] = 1 to tell H/W channel change is done. + VNSvOutPortB(dwIoBase + MAC_REG_CHANNEL, (byChannel | 0x80)); + + return bResult; +} + +/* + * Description: UW2451 IFRF chip init function + * + * Parameters: + * In: + * dwIoBase - I/O base address + * Out: + * none + * + * Return Value: TRUE if succeeded; FALSE if failed. + * + */ + + +/* + * Description: Select channel with UW2451 chip + * + * Parameters: + * In: + * dwIoBase - I/O base address + * uChannel - Channel number + * Out: + * none + * + * Return Value: TRUE if succeeded; FALSE if failed. + * + */ + +/* + * Description: Set sleep mode to UW2451 chip + * + * Parameters: + * In: + * dwIoBase - I/O base address + * uChannel - Channel number + * Out: + * none + * + * Return Value: TRUE if succeeded; FALSE if failed. + * + */ + +/* + * Description: RF init function + * + * Parameters: + * In: + * byBBType + * byRFType + * Out: + * none + * + * Return Value: TRUE if succeeded; FALSE if failed. + * + */ +BOOL RFbInit ( + IN PSDevice pDevice + ) +{ +BOOL bResult = TRUE; + switch (pDevice->byRFType) { + case RF_AIROHA : + case RF_AL2230S: + pDevice->byMaxPwrLevel = AL2230_PWR_IDX_LEN; + bResult = RFbAL2230Init(pDevice->PortOffset); + break; + case RF_AIROHA7230 : + pDevice->byMaxPwrLevel = AL7230_PWR_IDX_LEN; + bResult = s_bAL7230Init(pDevice->PortOffset); + break; + case RF_NOTHING : + bResult = TRUE; + break; + default : + bResult = FALSE; + break; + } + return bResult; +} + +/* + * Description: RF ShutDown function + * + * Parameters: + * In: + * byBBType + * byRFType + * Out: + * none + * + * Return Value: TRUE if succeeded; FALSE if failed. + * + */ +BOOL RFbShutDown ( + IN PSDevice pDevice + ) +{ +BOOL bResult = TRUE; + + switch (pDevice->byRFType) { + case RF_AIROHA7230 : + bResult = IFRFbWriteEmbeded (pDevice->PortOffset, 0x1ABAEF00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW); + break; + default : + bResult = TRUE; + break; + } + return bResult; +} + +/* + * Description: Select channel + * + * Parameters: + * In: + * byRFType + * byChannel - Channel number + * Out: + * none + * + * Return Value: TRUE if succeeded; FALSE if failed. + * + */ +BOOL RFbSelectChannel (DWORD_PTR dwIoBase, BYTE byRFType, BYTE byChannel) +{ +BOOL bResult = TRUE; + switch (byRFType) { + + case RF_AIROHA : + case RF_AL2230S: + bResult = RFbAL2230SelectChannel(dwIoBase, byChannel); + break; + //{{ RobertYu: 20050104 + case RF_AIROHA7230 : + bResult = s_bAL7230SelectChannel(dwIoBase, byChannel); + break; + //}} RobertYu + case RF_NOTHING : + bResult = TRUE; + break; + default: + bResult = FALSE; + break; + } + return bResult; +} + +/* + * Description: Write WakeProgSyn + * + * Parameters: + * In: + * dwIoBase - I/O base address + * uChannel - channel number + * bySleepCnt - SleepProgSyn count + * + * Return Value: None. + * + */ +BOOL RFvWriteWakeProgSyn (DWORD_PTR dwIoBase, BYTE byRFType, UINT uChannel) +{ + int ii; + BYTE byInitCount = 0; + BYTE bySleepCount = 0; + + VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, 0); + switch (byRFType) { + case RF_AIROHA: + case RF_AL2230S: + + if (uChannel > CB_MAX_CHANNEL_24G) + return FALSE; + + byInitCount = CB_AL2230_INIT_SEQ + 2; // Init Reg + Channel Reg (2) + bySleepCount = 0; + if (byInitCount > (MISCFIFO_SYNDATASIZE - bySleepCount)) { + return FALSE; + } + + for (ii = 0; ii < CB_AL2230_INIT_SEQ; ii++ ) { + MACvSetMISCFifo(dwIoBase, (WORD)(MISCFIFO_SYNDATA_IDX + ii), dwAL2230InitTable[ii]); + } + MACvSetMISCFifo(dwIoBase, (WORD)(MISCFIFO_SYNDATA_IDX + ii), dwAL2230ChannelTable0[uChannel-1]); + ii ++; + MACvSetMISCFifo(dwIoBase, (WORD)(MISCFIFO_SYNDATA_IDX + ii), dwAL2230ChannelTable1[uChannel-1]); + break; + + //{{ RobertYu: 20050104 + // Need to check, PLLON need to be low for channel setting + case RF_AIROHA7230: + byInitCount = CB_AL7230_INIT_SEQ + 3; // Init Reg + Channel Reg (3) + bySleepCount = 0; + if (byInitCount > (MISCFIFO_SYNDATASIZE - bySleepCount)) { + return FALSE; + } + + if (uChannel <= CB_MAX_CHANNEL_24G) + { + for (ii = 0; ii < CB_AL7230_INIT_SEQ; ii++ ) { + MACvSetMISCFifo(dwIoBase, (WORD)(MISCFIFO_SYNDATA_IDX + ii), dwAL7230InitTable[ii]); + } + } + else + { + for (ii = 0; ii < CB_AL7230_INIT_SEQ; ii++ ) { + MACvSetMISCFifo(dwIoBase, (WORD)(MISCFIFO_SYNDATA_IDX + ii), dwAL7230InitTableAMode[ii]); + } + } + + MACvSetMISCFifo(dwIoBase, (WORD)(MISCFIFO_SYNDATA_IDX + ii), dwAL7230ChannelTable0[uChannel-1]); + ii ++; + MACvSetMISCFifo(dwIoBase, (WORD)(MISCFIFO_SYNDATA_IDX + ii), dwAL7230ChannelTable1[uChannel-1]); + ii ++; + MACvSetMISCFifo(dwIoBase, (WORD)(MISCFIFO_SYNDATA_IDX + ii), dwAL7230ChannelTable2[uChannel-1]); + break; + //}} RobertYu + + case RF_NOTHING : + return TRUE; + break; + + default: + return FALSE; + break; + } + + MACvSetMISCFifo(dwIoBase, MISCFIFO_SYNINFO_IDX, (DWORD)MAKEWORD(bySleepCount, byInitCount)); + + return TRUE; +} + +/* + * Description: Set Tx power + * + * Parameters: + * In: + * dwIoBase - I/O base address + * dwRFPowerTable - RF Tx Power Setting + * Out: + * none + * + * Return Value: TRUE if succeeded; FALSE if failed. + * + */ +BOOL RFbSetPower ( + IN PSDevice pDevice, + IN UINT uRATE, + IN UINT uCH + ) +{ +BOOL bResult = TRUE; +BYTE byPwr = 0; +BYTE byDec = 0; +BYTE byPwrdBm = 0; + + if (pDevice->dwDiagRefCount != 0) { + return TRUE; + } + if ((uCH < 1) || (uCH > CB_MAX_CHANNEL)) { + return FALSE; + } + + switch (uRATE) { + case RATE_1M: + case RATE_2M: + case RATE_5M: + case RATE_11M: + byPwr = pDevice->abyCCKPwrTbl[uCH]; + byPwrdBm = pDevice->abyCCKDefaultPwr[uCH]; +//PLICE_DEBUG-> + //byPwr+=5; +//PLICE_DEBUG <- + +//printk("Rate <11:byPwr is %d\n",byPwr); + break; + case RATE_6M: + case RATE_9M: + case RATE_18M: + byPwr = pDevice->abyOFDMPwrTbl[uCH]; + if (pDevice->byRFType == RF_UW2452) { + byDec = byPwr + 14; + } else { + byDec = byPwr + 10; + } + if (byDec >= pDevice->byMaxPwrLevel) { + byDec = pDevice->byMaxPwrLevel-1; + } + if (pDevice->byRFType == RF_UW2452) { + byPwrdBm = byDec - byPwr; + byPwrdBm /= 3; + } else { + byPwrdBm = byDec - byPwr; + byPwrdBm >>= 1; + } + byPwrdBm += pDevice->abyOFDMDefaultPwr[uCH]; + byPwr = byDec; +//PLICE_DEBUG-> + //byPwr+=5; +//PLICE_DEBUG<- + +//printk("Rate <24:byPwr is %d\n",byPwr); + break; + case RATE_24M: + case RATE_36M: + case RATE_48M: + case RATE_54M: + byPwr = pDevice->abyOFDMPwrTbl[uCH]; + byPwrdBm = pDevice->abyOFDMDefaultPwr[uCH]; +//PLICE_DEBUG-> + //byPwr+=5; +//PLICE_DEBUG<- +//printk("Rate < 54:byPwr is %d\n",byPwr); + break; + } + +#if 0 + + // 802.11h TPC + if (pDevice->bLinkPass == TRUE) { + // do not over local constraint + if (byPwrdBm > pDevice->abyLocalPwr[uCH]) { + pDevice->byCurPwrdBm = pDevice->abyLocalPwr[uCH]; + byDec = byPwrdBm - pDevice->abyLocalPwr[uCH]; + if (pDevice->byRFType == RF_UW2452) { + byDec *= 3; + } else { + byDec <<= 1; + } + if (byPwr > byDec) { + byPwr -= byDec; + } else { + byPwr = 0; + } + } else { + pDevice->byCurPwrdBm = byPwrdBm; + } + } else { + // do not over regulatory constraint + if (byPwrdBm > pDevice->abyRegPwr[uCH]) { + pDevice->byCurPwrdBm = pDevice->abyRegPwr[uCH]; + byDec = byPwrdBm - pDevice->abyRegPwr[uCH]; + if (pDevice->byRFType == RF_UW2452) { + byDec *= 3; + } else { + byDec <<= 1; + } + if (byPwr > byDec) { + byPwr -= byDec; + } else { + byPwr = 0; + } + } else { + pDevice->byCurPwrdBm = byPwrdBm; + } + } +#endif + +// if (pDevice->byLocalID <= REV_ID_VT3253_B1) { + if (pDevice->byCurPwr == byPwr) { + return TRUE; + } + bResult = RFbRawSetPower(pDevice, byPwr, uRATE); +// } + if (bResult == TRUE) { + pDevice->byCurPwr = byPwr; + } + return bResult; +} + +/* + * Description: Set Tx power + * + * Parameters: + * In: + * dwIoBase - I/O base address + * dwRFPowerTable - RF Tx Power Setting + * Out: + * none + * + * Return Value: TRUE if succeeded; FALSE if failed. + * + */ + +BOOL RFbRawSetPower ( + IN PSDevice pDevice, + IN BYTE byPwr, + IN UINT uRATE + ) +{ +BOOL bResult = TRUE; +DWORD dwMax7230Pwr = 0; + + if (byPwr >= pDevice->byMaxPwrLevel) { + return (FALSE); + } + switch (pDevice->byRFType) { + + case RF_AIROHA : + bResult &= IFRFbWriteEmbeded(pDevice->PortOffset, dwAL2230PowerTable[byPwr]); + if (uRATE <= RATE_11M) { + bResult &= IFRFbWriteEmbeded(pDevice->PortOffset, 0x0001B400+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW); + } else { + bResult &= IFRFbWriteEmbeded(pDevice->PortOffset, 0x0005A400+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW); + } + break; + + + case RF_AL2230S : + bResult &= IFRFbWriteEmbeded(pDevice->PortOffset, dwAL2230PowerTable[byPwr]); + if (uRATE <= RATE_11M) { + bResult &= IFRFbWriteEmbeded(pDevice->PortOffset, 0x040C1400+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW); + bResult &= IFRFbWriteEmbeded(pDevice->PortOffset, 0x00299B00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW); + }else { + bResult &= IFRFbWriteEmbeded(pDevice->PortOffset, 0x0005A400+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW); + bResult &= IFRFbWriteEmbeded(pDevice->PortOffset, 0x00099B00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW); + } + + break; + + case RF_AIROHA7230: + // 0x080F1B00 for 3 wire control TxGain(D10) and 0x31 as TX Gain value + dwMax7230Pwr = 0x080C0B00 | ( (byPwr) << 12 ) | + (BY_AL7230_REG_LEN << 3 ) | IFREGCTL_REGW; + + bResult &= IFRFbWriteEmbeded(pDevice->PortOffset, dwMax7230Pwr); + break; + + + default : + break; + } + return bResult; +} + +/*+ + * + * Routine Description: + * Translate RSSI to dBm + * + * Parameters: + * In: + * pDevice - The adapter to be translated + * byCurrRSSI - RSSI to be translated + * Out: + * pdwdbm - Translated dbm number + * + * Return Value: none + * +-*/ +VOID +RFvRSSITodBm ( + IN PSDevice pDevice, + IN BYTE byCurrRSSI, + OUT PLONG pldBm + ) +{ + BYTE byIdx = (((byCurrRSSI & 0xC0) >> 6) & 0x03); + LONG b = (byCurrRSSI & 0x3F); + LONG a = 0; + BYTE abyAIROHARF[4] = {0, 18, 0, 40}; + + switch (pDevice->byRFType) { + case RF_AIROHA: + case RF_AL2230S: + case RF_AIROHA7230: //RobertYu: 20040104 + a = abyAIROHARF[byIdx]; + break; + default: + break; + } + + *pldBm = -1 * (a + b * 2); +} + +//////////////////////////////////////////////////////////////////////////////// +//{{ RobertYu: 20050104 + + +// Post processing for the 11b/g and 11a. +// for save time on changing Reg2,3,5,7,10,12,15 +BOOL RFbAL7230SelectChannelPostProcess (DWORD_PTR dwIoBase, BYTE byOldChannel, BYTE byNewChannel) +{ + BOOL bResult; + + bResult = TRUE; + + // if change between 11 b/g and 11a need to update the following register + // Channel Index 1~14 + + if( (byOldChannel <= CB_MAX_CHANNEL_24G) && (byNewChannel > CB_MAX_CHANNEL_24G) ) + { + // Change from 2.4G to 5G + bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL7230InitTableAMode[2]); //Reg2 + bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL7230InitTableAMode[3]); //Reg3 + bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL7230InitTableAMode[5]); //Reg5 + bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL7230InitTableAMode[7]); //Reg7 + bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL7230InitTableAMode[10]);//Reg10 + bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL7230InitTableAMode[12]);//Reg12 + bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL7230InitTableAMode[15]);//Reg15 + } + else if( (byOldChannel > CB_MAX_CHANNEL_24G) && (byNewChannel <= CB_MAX_CHANNEL_24G) ) + { + // change from 5G to 2.4G + bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL7230InitTable[2]); //Reg2 + bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL7230InitTable[3]); //Reg3 + bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL7230InitTable[5]); //Reg5 + bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL7230InitTable[7]); //Reg7 + bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL7230InitTable[10]);//Reg10 + bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL7230InitTable[12]);//Reg12 + bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL7230InitTable[15]);//Reg15 + } + + return bResult; +} + + +//}} RobertYu +//////////////////////////////////////////////////////////////////////////////// + diff --git a/drivers/staging/vt6655/rf.h b/drivers/staging/vt6655/rf.h new file mode 100644 index 000000000000..05fe17b2cfb7 --- /dev/null +++ b/drivers/staging/vt6655/rf.h @@ -0,0 +1,118 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * File: rf.h + * + * Purpose: + * + * Author: Jerry Chen + * + * Date: Feb. 19, 2004 + * + */ + + +#ifndef __RF_H__ +#define __RF_H__ + +#if !defined(__TTYPE_H__) +#include "ttype.h" +#endif +#if !defined(__DEVICE_H__) +#include "device.h" +#endif +/*--------------------- Export Definitions -------------------------*/ +// +// Baseband RF pair definition in eeprom (Bits 6..0) +// +#define RF_RFMD2959 0x01 +#define RF_MAXIMAG 0x02 +#define RF_AIROHA 0x03 + +//#define RF_GCT5103 0x04 +#define RF_UW2451 0x05 +#define RF_MAXIMG 0x06 +#define RF_MAXIM2829 0x07 // RobertYu: 20041118 +#define RF_UW2452 0x08 // RobertYu: 20041210 +#define RF_AIROHA7230 0x0a // RobertYu: 20050104 +#define RF_UW2453 0x0b + +#define RF_VT3226 0x09 +#define RF_AL2230S 0x0e + +#define RF_NOTHING 0x7E +#define RF_EMU 0x80 +#define RF_MASK 0x7F + +#define ZONE_FCC 0 +#define ZONE_MKK1 1 +#define ZONE_ETSI 2 +#define ZONE_IC 3 +#define ZONE_SPAIN 4 +#define ZONE_FRANCE 5 +#define ZONE_MKK 6 +#define ZONE_ISRAEL 7 + +//[20050104] CB_MAXIM2829_CHANNEL_5G_HIGH, CB_UW2452_CHANNEL_5G_HIGH: 40==>41 +#define CB_MAXIM2829_CHANNEL_5G_HIGH 41 //Index41: channel = 100, Tf = 5500MHz, set the (A3:A0=0101) D6=1 +#define CB_UW2452_CHANNEL_5G_HIGH 41 //[20041210] Index41: channel = 100, Tf = 5500MHz, change VCO2->VCO3 + + +/*--------------------- Export Classes ----------------------------*/ + +/*--------------------- Export Variables --------------------------*/ + +/*--------------------- Export Functions --------------------------*/ +#ifdef __cplusplus +extern "C" { /* Assume C declarations for C++ */ +#endif /* __cplusplus */ + +BOOL IFRFbWriteEmbeded(DWORD_PTR dwIoBase, DWORD dwData); +BOOL RFbSelectChannel(DWORD_PTR dwIoBase, BYTE byRFType, BYTE byChannel); +BOOL RFbInit ( + IN PSDevice pDevice + ); +BOOL RFvWriteWakeProgSyn(DWORD_PTR dwIoBase, BYTE byRFType, UINT uChannel); +BOOL RFbSetPower(PSDevice pDevice, UINT uRATE, UINT uCH); +BOOL RFbRawSetPower( + IN PSDevice pDevice, + IN BYTE byPwr, + IN UINT uRATE + ); + +VOID +RFvRSSITodBm( + IN PSDevice pDevice, + IN BYTE byCurrRSSI, + OUT PLONG pldBm + ); + +//{{ RobertYu: 20050104 +BOOL RFbAL7230SelectChannelPostProcess(DWORD_PTR dwIoBase, BYTE byOldChannel, BYTE byNewChannel); +//}} RobertYu + +#ifdef __cplusplus +} /* End of extern "C" { */ +#endif /* __cplusplus */ + + +#endif // __RF_H__ + + + diff --git a/drivers/staging/vt6655/rxtx.c b/drivers/staging/vt6655/rxtx.c new file mode 100644 index 000000000000..c8a4a5533c7e --- /dev/null +++ b/drivers/staging/vt6655/rxtx.c @@ -0,0 +1,3269 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * File: rxtx.c + * + * Purpose: handle WMAC/802.3/802.11 rx & tx functions + * + * Author: Lyndon Chen + * + * Date: May 20, 2003 + * + * Functions: + * s_vGenerateTxParameter - Generate tx dma requried parameter. + * vGenerateMACHeader - Translate 802.3 to 802.11 header + * cbGetFragCount - Caculate fragement number count + * csBeacon_xmit - beacon tx function + * csMgmt_xmit - management tx function + * s_cbFillTxBufHead - fulfill tx dma buffer header + * s_uGetDataDuration - get tx data required duration + * s_uFillDataHead- fulfill tx data duration header + * s_uGetRTSCTSDuration- get rtx/cts requried duration + * s_uGetRTSCTSRsvTime- get rts/cts reserved time + * s_uGetTxRsvTime- get frame reserved time + * s_vFillCTSHead- fulfill CTS ctl header + * s_vFillFragParameter- Set fragement ctl parameter. + * s_vFillRTSHead- fulfill RTS ctl header + * s_vFillTxKey- fulfill tx encrypt key + * s_vSWencryption- Software encrypt header + * vDMA0_tx_80211- tx 802.11 frame via dma0 + * vGenerateFIFOHeader- Generate tx FIFO ctl header + * + * Revision History: + * + */ + + +#if !defined(__DEVICE_H__) +#include "device.h" +#endif +#if !defined(__RXTX_H__) +#include "rxtx.h" +#endif +#if !defined(__TETHER_H__) +#include "tether.h" +#endif +#if !defined(__CARD_H__) +#include "card.h" +#endif +#if !defined(__BSSDB_H__) +#include "bssdb.h" +#endif +#if !defined(__MAC_H__) +#include "mac.h" +#endif +#if !defined(__BASEBAND_H__) +#include "baseband.h" +#endif +#if !defined(__UMEM_H__) +#include "umem.h" +#endif +#if !defined(__MICHAEL_H__) +#include "michael.h" +#endif +#if !defined(__TKIP_H__) +#include "tkip.h" +#endif +#if !defined(__TCRC_H__) +#include "tcrc.h" +#endif +#if !defined(__WCTL_H__) +#include "wctl.h" +#endif +#if !defined(__WROUTE_H__) +#include "wroute.h" +#endif +#if !defined(__TBIT_H__) +#include "tbit.h" +#endif +#if !defined(__HOSTAP_H__) +#include "hostap.h" +#endif +#if !defined(__RF_H__) +#include "rf.h" +#endif + +/*--------------------- Static Definitions -------------------------*/ + +/*--------------------- Static Classes ----------------------------*/ + +/*--------------------- Static Variables --------------------------*/ +//static int msglevel =MSG_LEVEL_DEBUG; +static int msglevel =MSG_LEVEL_INFO; + +#define PLICE_DEBUG + + +/*--------------------- Static Functions --------------------------*/ + +/*--------------------- Static Definitions -------------------------*/ +#define CRITICAL_PACKET_LEN 256 // if packet size < 256 -> in-direct send + // packet size >= 256 -> direct send + +const WORD wTimeStampOff[2][MAX_RATE] = { + {384, 288, 226, 209, 54, 43, 37, 31, 28, 25, 24, 23}, // Long Preamble + {384, 192, 130, 113, 54, 43, 37, 31, 28, 25, 24, 23}, // Short Preamble + }; + +const WORD wFB_Opt0[2][5] = { + {RATE_12M, RATE_18M, RATE_24M, RATE_36M, RATE_48M}, // fallback_rate0 + {RATE_12M, RATE_12M, RATE_18M, RATE_24M, RATE_36M}, // fallback_rate1 + }; +const WORD wFB_Opt1[2][5] = { + {RATE_12M, RATE_18M, RATE_24M, RATE_24M, RATE_36M}, // fallback_rate0 + {RATE_6M , RATE_6M, RATE_12M, RATE_12M, RATE_18M}, // fallback_rate1 + }; + + +#define RTSDUR_BB 0 +#define RTSDUR_BA 1 +#define RTSDUR_AA 2 +#define CTSDUR_BA 3 +#define RTSDUR_BA_F0 4 +#define RTSDUR_AA_F0 5 +#define RTSDUR_BA_F1 6 +#define RTSDUR_AA_F1 7 +#define CTSDUR_BA_F0 8 +#define CTSDUR_BA_F1 9 +#define DATADUR_B 10 +#define DATADUR_A 11 +#define DATADUR_A_F0 12 +#define DATADUR_A_F1 13 + +/*--------------------- Static Functions --------------------------*/ + + + +static +VOID +s_vFillTxKey( + IN PSDevice pDevice, + IN PBYTE pbyBuf, + IN PBYTE pbyIVHead, + IN PSKeyItem pTransmitKey, + IN PBYTE pbyHdrBuf, + IN WORD wPayloadLen, + OUT PBYTE pMICHDR + ); + + + +static +VOID +s_vFillRTSHead( + IN PSDevice pDevice, + IN BYTE byPktTyp, + IN PVOID pvRTS, + IN UINT cbFrameLength, + IN BOOL bNeedAck, + IN BOOL bDisCRC, + IN PSEthernetHeader psEthHeader, + IN WORD wCurrentRate, + IN BYTE byFBOption + ); + +static +VOID +s_vGenerateTxParameter( + IN PSDevice pDevice, + IN BYTE byPktTyp, + IN PVOID pTxBufHead, + IN PVOID pvRrvTime, + IN PVOID pvRTS, + IN PVOID pvCTS, + IN UINT cbFrameSize, + IN BOOL bNeedACK, + IN UINT uDMAIdx, + IN PSEthernetHeader psEthHeader, + IN WORD wCurrentRate + ); + + + +static void s_vFillFragParameter( + IN PSDevice pDevice, + IN PBYTE pbyBuffer, + IN UINT uTxType, + IN PVOID pvtdCurr, + IN WORD wFragType, + IN UINT cbReqCount + ); + + +static +UINT +s_cbFillTxBufHead ( + IN PSDevice pDevice, + IN BYTE byPktTyp, + IN PBYTE pbyTxBufferAddr, + IN UINT cbFrameBodySize, + IN UINT uDMAIdx, + IN PSTxDesc pHeadTD, + IN PSEthernetHeader psEthHeader, + IN PBYTE pPacket, + IN BOOL bNeedEncrypt, + IN PSKeyItem pTransmitKey, + IN UINT uNodeIndex, + OUT PUINT puMACfragNum + ); + + +static +UINT +s_uFillDataHead ( + IN PSDevice pDevice, + IN BYTE byPktTyp, + IN PVOID pTxDataHead, + IN UINT cbFrameLength, + IN UINT uDMAIdx, + IN BOOL bNeedAck, + IN UINT uFragIdx, + IN UINT cbLastFragmentSize, + IN UINT uMACfragNum, + IN BYTE byFBOption, + IN WORD wCurrentRate + ); + + +/*--------------------- Export Variables --------------------------*/ + + + +static +VOID +s_vFillTxKey ( + IN PSDevice pDevice, + IN PBYTE pbyBuf, + IN PBYTE pbyIVHead, + IN PSKeyItem pTransmitKey, + IN PBYTE pbyHdrBuf, + IN WORD wPayloadLen, + OUT PBYTE pMICHDR + ) +{ + PDWORD pdwIV = (PDWORD) pbyIVHead; + PDWORD pdwExtIV = (PDWORD) ((PBYTE)pbyIVHead+4); + WORD wValue; + PS802_11Header pMACHeader = (PS802_11Header)pbyHdrBuf; + DWORD dwRevIVCounter; + BYTE byKeyIndex = 0; + + + + //Fill TXKEY + if (pTransmitKey == NULL) + return; + + dwRevIVCounter = cpu_to_le32(pDevice->dwIVCounter); + *pdwIV = pDevice->dwIVCounter; + byKeyIndex = pTransmitKey->dwKeyIndex & 0xf; + + if (pTransmitKey->byCipherSuite == KEY_CTL_WEP) { + if (pTransmitKey->uKeyLength == WLAN_WEP232_KEYLEN ){ + MEMvCopy(pDevice->abyPRNG, (PBYTE)&(dwRevIVCounter), 3); + MEMvCopy(pDevice->abyPRNG+3, pTransmitKey->abyKey, pTransmitKey->uKeyLength); + } else { + MEMvCopy(pbyBuf, (PBYTE)&(dwRevIVCounter), 3); + MEMvCopy(pbyBuf+3, pTransmitKey->abyKey, pTransmitKey->uKeyLength); + if(pTransmitKey->uKeyLength == WLAN_WEP40_KEYLEN) { + MEMvCopy(pbyBuf+8, (PBYTE)&(dwRevIVCounter), 3); + MEMvCopy(pbyBuf+11, pTransmitKey->abyKey, pTransmitKey->uKeyLength); + } + MEMvCopy(pDevice->abyPRNG, pbyBuf, 16); + } + // Append IV after Mac Header + *pdwIV &= WEP_IV_MASK;//00000000 11111111 11111111 11111111 + *pdwIV |= (byKeyIndex << 30); + *pdwIV = cpu_to_le32(*pdwIV); + pDevice->dwIVCounter++; + if (pDevice->dwIVCounter > WEP_IV_MASK) { + pDevice->dwIVCounter = 0; + } + } else if (pTransmitKey->byCipherSuite == KEY_CTL_TKIP) { + pTransmitKey->wTSC15_0++; + if (pTransmitKey->wTSC15_0 == 0) { + pTransmitKey->dwTSC47_16++; + } + TKIPvMixKey(pTransmitKey->abyKey, pDevice->abyCurrentNetAddr, + pTransmitKey->wTSC15_0, pTransmitKey->dwTSC47_16, pDevice->abyPRNG); + MEMvCopy(pbyBuf, pDevice->abyPRNG, 16); + // Make IV + MEMvCopy(pdwIV, pDevice->abyPRNG, 3); + + *(pbyIVHead+3) = (BYTE)(((byKeyIndex << 6) & 0xc0) | 0x20); // 0x20 is ExtIV + // Append IV&ExtIV after Mac Header + *pdwExtIV = cpu_to_le32(pTransmitKey->dwTSC47_16); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"vFillTxKey()---- pdwExtIV: %lx\n", *pdwExtIV); + + } else if (pTransmitKey->byCipherSuite == KEY_CTL_CCMP) { + pTransmitKey->wTSC15_0++; + if (pTransmitKey->wTSC15_0 == 0) { + pTransmitKey->dwTSC47_16++; + } + MEMvCopy(pbyBuf, pTransmitKey->abyKey, 16); + + // Make IV + *pdwIV = 0; + *(pbyIVHead+3) = (BYTE)(((byKeyIndex << 6) & 0xc0) | 0x20); // 0x20 is ExtIV + *pdwIV |= cpu_to_le16((WORD)(pTransmitKey->wTSC15_0)); + //Append IV&ExtIV after Mac Header + *pdwExtIV = cpu_to_le32(pTransmitKey->dwTSC47_16); + + //Fill MICHDR0 + *pMICHDR = 0x59; + *((PBYTE)(pMICHDR+1)) = 0; // TxPriority + MEMvCopy(pMICHDR+2, &(pMACHeader->abyAddr2[0]), 6); + *((PBYTE)(pMICHDR+8)) = HIBYTE(HIWORD(pTransmitKey->dwTSC47_16)); + *((PBYTE)(pMICHDR+9)) = LOBYTE(HIWORD(pTransmitKey->dwTSC47_16)); + *((PBYTE)(pMICHDR+10)) = HIBYTE(LOWORD(pTransmitKey->dwTSC47_16)); + *((PBYTE)(pMICHDR+11)) = LOBYTE(LOWORD(pTransmitKey->dwTSC47_16)); + *((PBYTE)(pMICHDR+12)) = HIBYTE(pTransmitKey->wTSC15_0); + *((PBYTE)(pMICHDR+13)) = LOBYTE(pTransmitKey->wTSC15_0); + *((PBYTE)(pMICHDR+14)) = HIBYTE(wPayloadLen); + *((PBYTE)(pMICHDR+15)) = LOBYTE(wPayloadLen); + + //Fill MICHDR1 + *((PBYTE)(pMICHDR+16)) = 0; // HLEN[15:8] + if (pDevice->bLongHeader) { + *((PBYTE)(pMICHDR+17)) = 28; // HLEN[7:0] + } else { + *((PBYTE)(pMICHDR+17)) = 22; // HLEN[7:0] + } + wValue = cpu_to_le16(pMACHeader->wFrameCtl & 0xC78F); + MEMvCopy(pMICHDR+18, (PBYTE)&wValue, 2); // MSKFRACTL + MEMvCopy(pMICHDR+20, &(pMACHeader->abyAddr1[0]), 6); + MEMvCopy(pMICHDR+26, &(pMACHeader->abyAddr2[0]), 6); + + //Fill MICHDR2 + MEMvCopy(pMICHDR+32, &(pMACHeader->abyAddr3[0]), 6); + wValue = pMACHeader->wSeqCtl; + wValue &= 0x000F; + wValue = cpu_to_le16(wValue); + MEMvCopy(pMICHDR+38, (PBYTE)&wValue, 2); // MSKSEQCTL + if (pDevice->bLongHeader) { + MEMvCopy(pMICHDR+40, &(pMACHeader->abyAddr4[0]), 6); + } + } +} + + +static +VOID +s_vSWencryption ( + IN PSDevice pDevice, + IN PSKeyItem pTransmitKey, + IN PBYTE pbyPayloadHead, + IN WORD wPayloadSize + ) +{ + UINT cbICVlen = 4; + DWORD dwICV = 0xFFFFFFFFL; + PDWORD pdwICV; + + if (pTransmitKey == NULL) + return; + + if (pTransmitKey->byCipherSuite == KEY_CTL_WEP) { + //======================================================================= + // Append ICV after payload + dwICV = CRCdwGetCrc32Ex(pbyPayloadHead, wPayloadSize, dwICV);//ICV(Payload) + pdwICV = (PDWORD)(pbyPayloadHead + wPayloadSize); + // finally, we must invert dwCRC to get the correct answer + *pdwICV = cpu_to_le32(~dwICV); + // RC4 encryption + rc4_init(&pDevice->SBox, pDevice->abyPRNG, pTransmitKey->uKeyLength + 3); + rc4_encrypt(&pDevice->SBox, pbyPayloadHead, pbyPayloadHead, wPayloadSize+cbICVlen); + //======================================================================= + } else if (pTransmitKey->byCipherSuite == KEY_CTL_TKIP) { + //======================================================================= + //Append ICV after payload + dwICV = CRCdwGetCrc32Ex(pbyPayloadHead, wPayloadSize, dwICV);//ICV(Payload) + pdwICV = (PDWORD)(pbyPayloadHead + wPayloadSize); + // finally, we must invert dwCRC to get the correct answer + *pdwICV = cpu_to_le32(~dwICV); + // RC4 encryption + rc4_init(&pDevice->SBox, pDevice->abyPRNG, TKIP_KEY_LEN); + rc4_encrypt(&pDevice->SBox, pbyPayloadHead, pbyPayloadHead, wPayloadSize+cbICVlen); + //======================================================================= + } +} + + + + +/*byPktTyp : PK_TYPE_11A 0 + PK_TYPE_11B 1 + PK_TYPE_11GB 2 + PK_TYPE_11GA 3 +*/ +static +UINT +s_uGetTxRsvTime ( + IN PSDevice pDevice, + IN BYTE byPktTyp, + IN UINT cbFrameLength, + IN WORD wRate, + IN BOOL bNeedAck + ) +{ + UINT uDataTime, uAckTime; + + uDataTime = BBuGetFrameTime(pDevice->byPreambleType, byPktTyp, cbFrameLength, wRate); +#ifdef PLICE_DEBUG + //printk("s_uGetTxRsvTime is %d\n",uDataTime); +#endif + if (byPktTyp == PK_TYPE_11B) {//llb,CCK mode + uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktTyp, 14, (WORD)pDevice->byTopCCKBasicRate); + } else {//11g 2.4G OFDM mode & 11a 5G OFDM mode + uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktTyp, 14, (WORD)pDevice->byTopOFDMBasicRate); + } + + if (bNeedAck) { + return (uDataTime + pDevice->uSIFS + uAckTime); + } + else { + return uDataTime; + } +} + +//byFreqType: 0=>5GHZ 1=>2.4GHZ +static +UINT +s_uGetRTSCTSRsvTime ( + IN PSDevice pDevice, + IN BYTE byRTSRsvType, + IN BYTE byPktTyp, + IN UINT cbFrameLength, + IN WORD wCurrentRate + ) +{ + UINT uRrvTime , uRTSTime, uCTSTime, uAckTime, uDataTime; + + uRrvTime = uRTSTime = uCTSTime = uAckTime = uDataTime = 0; + + + uDataTime = BBuGetFrameTime(pDevice->byPreambleType, byPktTyp, cbFrameLength, wCurrentRate); + if (byRTSRsvType == 0) { //RTSTxRrvTime_bb + uRTSTime = BBuGetFrameTime(pDevice->byPreambleType, byPktTyp, 20, pDevice->byTopCCKBasicRate); + uCTSTime = uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktTyp, 14, pDevice->byTopCCKBasicRate); + } + else if (byRTSRsvType == 1){ //RTSTxRrvTime_ba, only in 2.4GHZ + uRTSTime = BBuGetFrameTime(pDevice->byPreambleType, byPktTyp, 20, pDevice->byTopCCKBasicRate); + uCTSTime = BBuGetFrameTime(pDevice->byPreambleType, byPktTyp, 14, pDevice->byTopCCKBasicRate); + uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktTyp, 14, pDevice->byTopOFDMBasicRate); + } + else if (byRTSRsvType == 2) { //RTSTxRrvTime_aa + uRTSTime = BBuGetFrameTime(pDevice->byPreambleType, byPktTyp, 20, pDevice->byTopOFDMBasicRate); + uCTSTime = uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktTyp, 14, pDevice->byTopOFDMBasicRate); + } + else if (byRTSRsvType == 3) { //CTSTxRrvTime_ba, only in 2.4GHZ + uCTSTime = BBuGetFrameTime(pDevice->byPreambleType, byPktTyp, 14, pDevice->byTopCCKBasicRate); + uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktTyp, 14, pDevice->byTopOFDMBasicRate); + uRrvTime = uCTSTime + uAckTime + uDataTime + 2*pDevice->uSIFS; + return uRrvTime; + } + + //RTSRrvTime + uRrvTime = uRTSTime + uCTSTime + uAckTime + uDataTime + 3*pDevice->uSIFS; + return uRrvTime; +} + +//byFreqType 0: 5GHz, 1:2.4Ghz +static +UINT +s_uGetDataDuration ( + IN PSDevice pDevice, + IN BYTE byDurType, + IN UINT cbFrameLength, + IN BYTE byPktType, + IN WORD wRate, + IN BOOL bNeedAck, + IN UINT uFragIdx, + IN UINT cbLastFragmentSize, + IN UINT uMACfragNum, + IN BYTE byFBOption + ) +{ + BOOL bLastFrag = 0; + UINT uAckTime =0, uNextPktTime = 0; + + + + if (uFragIdx == (uMACfragNum-1)) { + bLastFrag = 1; + } + + + switch (byDurType) { + + case DATADUR_B: //DATADUR_B + if (((uMACfragNum == 1)) || (bLastFrag == 1)) {//Non Frag or Last Frag + if (bNeedAck) { + uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopCCKBasicRate); + return (pDevice->uSIFS + uAckTime); + } else { + return 0; + } + } + else {//First Frag or Mid Frag + if (uFragIdx == (uMACfragNum-2)) { + uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbLastFragmentSize, wRate, bNeedAck); + } else { + uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wRate, bNeedAck); + } + if (bNeedAck) { + uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopCCKBasicRate); + return (pDevice->uSIFS + uAckTime + uNextPktTime); + } else { + return (pDevice->uSIFS + uNextPktTime); + } + } + break; + + case DATADUR_A: //DATADUR_A + if (((uMACfragNum==1)) || (bLastFrag==1)) {//Non Frag or Last Frag + if(bNeedAck){ + uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopOFDMBasicRate); + return (pDevice->uSIFS + uAckTime); + } else { + return 0; + } + } + else {//First Frag or Mid Frag + if(uFragIdx == (uMACfragNum-2)){ + uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbLastFragmentSize, wRate, bNeedAck); + } else { + uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wRate, bNeedAck); + } + if(bNeedAck){ + uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopOFDMBasicRate); + return (pDevice->uSIFS + uAckTime + uNextPktTime); + } else { + return (pDevice->uSIFS + uNextPktTime); + } + } + break; + + case DATADUR_A_F0: //DATADUR_A_F0 + if (((uMACfragNum==1)) || (bLastFrag==1)) {//Non Frag or Last Frag + if(bNeedAck){ + uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopOFDMBasicRate); + return (pDevice->uSIFS + uAckTime); + } else { + return 0; + } + } + else { //First Frag or Mid Frag + if (byFBOption == AUTO_FB_0) { + if (wRate < RATE_18M) + wRate = RATE_18M; + else if (wRate > RATE_54M) + wRate = RATE_54M; + + if(uFragIdx == (uMACfragNum-2)){ + uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbLastFragmentSize, wFB_Opt0[FB_RATE0][wRate-RATE_18M], bNeedAck); + } else { + uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt0[FB_RATE0][wRate-RATE_18M], bNeedAck); + } + } else { // (byFBOption == AUTO_FB_1) + if (wRate < RATE_18M) + wRate = RATE_18M; + else if (wRate > RATE_54M) + wRate = RATE_54M; + + if(uFragIdx == (uMACfragNum-2)){ + uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbLastFragmentSize, wFB_Opt1[FB_RATE0][wRate-RATE_18M], bNeedAck); + } else { + uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt1[FB_RATE0][wRate-RATE_18M], bNeedAck); + } + } + + if(bNeedAck){ + uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopOFDMBasicRate); + return (pDevice->uSIFS + uAckTime + uNextPktTime); + } else { + return (pDevice->uSIFS + uNextPktTime); + } + } + break; + + case DATADUR_A_F1: //DATADUR_A_F1 + if (((uMACfragNum==1)) || (bLastFrag==1)) {//Non Frag or Last Frag + if(bNeedAck){ + uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopOFDMBasicRate); + return (pDevice->uSIFS + uAckTime); + } else { + return 0; + } + } + else { //First Frag or Mid Frag + if (byFBOption == AUTO_FB_0) { + if (wRate < RATE_18M) + wRate = RATE_18M; + else if (wRate > RATE_54M) + wRate = RATE_54M; + + if(uFragIdx == (uMACfragNum-2)){ + uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbLastFragmentSize, wFB_Opt0[FB_RATE1][wRate-RATE_18M], bNeedAck); + } else { + uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt0[FB_RATE1][wRate-RATE_18M], bNeedAck); + } + + } else { // (byFBOption == AUTO_FB_1) + if (wRate < RATE_18M) + wRate = RATE_18M; + else if (wRate > RATE_54M) + wRate = RATE_54M; + + if(uFragIdx == (uMACfragNum-2)){ + uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbLastFragmentSize, wFB_Opt1[FB_RATE1][wRate-RATE_18M], bNeedAck); + } else { + uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt1[FB_RATE1][wRate-RATE_18M], bNeedAck); + } + } + if(bNeedAck){ + uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopOFDMBasicRate); + return (pDevice->uSIFS + uAckTime + uNextPktTime); + } else { + return (pDevice->uSIFS + uNextPktTime); + } + } + break; + + default: + break; + } + + ASSERT(FALSE); + return 0; +} + + +//byFreqType: 0=>5GHZ 1=>2.4GHZ +static +UINT +s_uGetRTSCTSDuration ( + IN PSDevice pDevice, + IN BYTE byDurType, + IN UINT cbFrameLength, + IN BYTE byPktType, + IN WORD wRate, + IN BOOL bNeedAck, + IN BYTE byFBOption + ) +{ + UINT uCTSTime = 0, uDurTime = 0; + + + switch (byDurType) { + + case RTSDUR_BB: //RTSDuration_bb + uCTSTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopCCKBasicRate); + uDurTime = uCTSTime + 2*pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wRate, bNeedAck); + break; + + case RTSDUR_BA: //RTSDuration_ba + uCTSTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopCCKBasicRate); + uDurTime = uCTSTime + 2*pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wRate, bNeedAck); + break; + + case RTSDUR_AA: //RTSDuration_aa + uCTSTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopOFDMBasicRate); + uDurTime = uCTSTime + 2*pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wRate, bNeedAck); + break; + + case CTSDUR_BA: //CTSDuration_ba + uDurTime = pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wRate, bNeedAck); + break; + + case RTSDUR_BA_F0: //RTSDuration_ba_f0 + uCTSTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopCCKBasicRate); + if ((byFBOption == AUTO_FB_0) && (wRate >= RATE_18M) && (wRate <=RATE_54M)) { + uDurTime = uCTSTime + 2*pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt0[FB_RATE0][wRate-RATE_18M], bNeedAck); + } else if ((byFBOption == AUTO_FB_1) && (wRate >= RATE_18M) && (wRate <=RATE_54M)) { + uDurTime = uCTSTime + 2*pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt1[FB_RATE0][wRate-RATE_18M], bNeedAck); + } + break; + + case RTSDUR_AA_F0: //RTSDuration_aa_f0 + uCTSTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopOFDMBasicRate); + if ((byFBOption == AUTO_FB_0) && (wRate >= RATE_18M) && (wRate <=RATE_54M)) { + uDurTime = uCTSTime + 2*pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt0[FB_RATE0][wRate-RATE_18M], bNeedAck); + } else if ((byFBOption == AUTO_FB_1) && (wRate >= RATE_18M) && (wRate <=RATE_54M)) { + uDurTime = uCTSTime + 2*pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt1[FB_RATE0][wRate-RATE_18M], bNeedAck); + } + break; + + case RTSDUR_BA_F1: //RTSDuration_ba_f1 + uCTSTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopCCKBasicRate); + if ((byFBOption == AUTO_FB_0) && (wRate >= RATE_18M) && (wRate <=RATE_54M)) { + uDurTime = uCTSTime + 2*pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt0[FB_RATE1][wRate-RATE_18M], bNeedAck); + } else if ((byFBOption == AUTO_FB_1) && (wRate >= RATE_18M) && (wRate <=RATE_54M)) { + uDurTime = uCTSTime + 2*pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt1[FB_RATE1][wRate-RATE_18M], bNeedAck); + } + break; + + case RTSDUR_AA_F1: //RTSDuration_aa_f1 + uCTSTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopOFDMBasicRate); + if ((byFBOption == AUTO_FB_0) && (wRate >= RATE_18M) && (wRate <=RATE_54M)) { + uDurTime = uCTSTime + 2*pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt0[FB_RATE1][wRate-RATE_18M], bNeedAck); + } else if ((byFBOption == AUTO_FB_1) && (wRate >= RATE_18M) && (wRate <=RATE_54M)) { + uDurTime = uCTSTime + 2*pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt1[FB_RATE1][wRate-RATE_18M], bNeedAck); + } + break; + + case CTSDUR_BA_F0: //CTSDuration_ba_f0 + if ((byFBOption == AUTO_FB_0) && (wRate >= RATE_18M) && (wRate <=RATE_54M)) { + uDurTime = pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt0[FB_RATE0][wRate-RATE_18M], bNeedAck); + } else if ((byFBOption == AUTO_FB_1) && (wRate >= RATE_18M) && (wRate <=RATE_54M)) { + uDurTime = pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt1[FB_RATE0][wRate-RATE_18M], bNeedAck); + } + break; + + case CTSDUR_BA_F1: //CTSDuration_ba_f1 + if ((byFBOption == AUTO_FB_0) && (wRate >= RATE_18M) && (wRate <=RATE_54M)) { + uDurTime = pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt0[FB_RATE1][wRate-RATE_18M], bNeedAck); + } else if ((byFBOption == AUTO_FB_1) && (wRate >= RATE_18M) && (wRate <=RATE_54M)) { + uDurTime = pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt1[FB_RATE1][wRate-RATE_18M], bNeedAck); + } + break; + + default: + break; + } + + return uDurTime; + +} + + + +static +UINT +s_uFillDataHead ( + IN PSDevice pDevice, + IN BYTE byPktTyp, + IN PVOID pTxDataHead, + IN UINT cbFrameLength, + IN UINT uDMAIdx, + IN BOOL bNeedAck, + IN UINT uFragIdx, + IN UINT cbLastFragmentSize, + IN UINT uMACfragNum, + IN BYTE byFBOption, + IN WORD wCurrentRate + ) +{ + WORD wLen = 0x0000; + + if (pTxDataHead == NULL) { + return 0; + } + + if (byPktTyp == PK_TYPE_11GB || byPktTyp == PK_TYPE_11GA) { + if (byFBOption == AUTO_FB_NONE) { + PSTxDataHead_g pBuf = (PSTxDataHead_g)pTxDataHead; + //Get SignalField,ServiceField,Length + BBvCaculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktTyp, + (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField_a), (PBYTE)&(pBuf->bySignalField_a) + ); + pBuf->wTransmitLength_a = cpu_to_le16(wLen); + BBvCaculateParameter(pDevice, cbFrameLength, pDevice->byTopCCKBasicRate, PK_TYPE_11B, + (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField_b), (PBYTE)&(pBuf->bySignalField_b) + ); + pBuf->wTransmitLength_b = cpu_to_le16(wLen); + //Get Duration and TimeStamp + pBuf->wDuration_a = cpu_to_le16((WORD)s_uGetDataDuration(pDevice, DATADUR_A, cbFrameLength, + byPktTyp, wCurrentRate, bNeedAck, uFragIdx, + cbLastFragmentSize, uMACfragNum, + byFBOption)); //1: 2.4GHz + pBuf->wDuration_b = cpu_to_le16((WORD)s_uGetDataDuration(pDevice, DATADUR_B, cbFrameLength, + PK_TYPE_11B, pDevice->byTopCCKBasicRate, + bNeedAck, uFragIdx, cbLastFragmentSize, + uMACfragNum, byFBOption)); //1: 2.4 + + pBuf->wTimeStampOff_a = cpu_to_le16(wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE]); + pBuf->wTimeStampOff_b = cpu_to_le16(wTimeStampOff[pDevice->byPreambleType%2][pDevice->byTopCCKBasicRate%MAX_RATE]); + + return (pBuf->wDuration_a); + } else { + // Auto Fallback + PSTxDataHead_g_FB pBuf = (PSTxDataHead_g_FB)pTxDataHead; + //Get SignalField,ServiceField,Length + BBvCaculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktTyp, + (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField_a), (PBYTE)&(pBuf->bySignalField_a) + ); + pBuf->wTransmitLength_a = cpu_to_le16(wLen); + BBvCaculateParameter(pDevice, cbFrameLength, pDevice->byTopCCKBasicRate, PK_TYPE_11B, + (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField_b), (PBYTE)&(pBuf->bySignalField_b) + ); + pBuf->wTransmitLength_b = cpu_to_le16(wLen); + //Get Duration and TimeStamp + pBuf->wDuration_a = cpu_to_le16((WORD)s_uGetDataDuration(pDevice, DATADUR_A, cbFrameLength, byPktTyp, + wCurrentRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption)); //1: 2.4GHz + pBuf->wDuration_b = cpu_to_le16((WORD)s_uGetDataDuration(pDevice, DATADUR_B, cbFrameLength, PK_TYPE_11B, + pDevice->byTopCCKBasicRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption)); //1: 2.4GHz + pBuf->wDuration_a_f0 = cpu_to_le16((WORD)s_uGetDataDuration(pDevice, DATADUR_A_F0, cbFrameLength, byPktTyp, + wCurrentRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption)); //1: 2.4GHz + pBuf->wDuration_a_f1 = cpu_to_le16((WORD)s_uGetDataDuration(pDevice, DATADUR_A_F1, cbFrameLength, byPktTyp, + wCurrentRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption)); //1: 2.4GHz + + pBuf->wTimeStampOff_a = cpu_to_le16(wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE]); + pBuf->wTimeStampOff_b = cpu_to_le16(wTimeStampOff[pDevice->byPreambleType%2][pDevice->byTopCCKBasicRate%MAX_RATE]); + + return (pBuf->wDuration_a); + } //if (byFBOption == AUTO_FB_NONE) + } + else if (byPktTyp == PK_TYPE_11A) { + if ((byFBOption != AUTO_FB_NONE)) { + // Auto Fallback + PSTxDataHead_a_FB pBuf = (PSTxDataHead_a_FB)pTxDataHead; + //Get SignalField,ServiceField,Length + BBvCaculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktTyp, + (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField), (PBYTE)&(pBuf->bySignalField) + ); + pBuf->wTransmitLength = cpu_to_le16(wLen); + //Get Duration and TimeStampOff + + pBuf->wDuration = cpu_to_le16((WORD)s_uGetDataDuration(pDevice, DATADUR_A, cbFrameLength, byPktTyp, + wCurrentRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption)); //0: 5GHz + pBuf->wDuration_f0 = cpu_to_le16((WORD)s_uGetDataDuration(pDevice, DATADUR_A_F0, cbFrameLength, byPktTyp, + wCurrentRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption)); //0: 5GHz + pBuf->wDuration_f1 = cpu_to_le16((WORD)s_uGetDataDuration(pDevice, DATADUR_A_F1, cbFrameLength, byPktTyp, + wCurrentRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption)); //0: 5GHz + pBuf->wTimeStampOff = cpu_to_le16(wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE]); + return (pBuf->wDuration); + } else { + PSTxDataHead_ab pBuf = (PSTxDataHead_ab)pTxDataHead; + //Get SignalField,ServiceField,Length + BBvCaculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktTyp, + (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField), (PBYTE)&(pBuf->bySignalField) + ); + pBuf->wTransmitLength = cpu_to_le16(wLen); + //Get Duration and TimeStampOff + + pBuf->wDuration = cpu_to_le16((WORD)s_uGetDataDuration(pDevice, DATADUR_A, cbFrameLength, byPktTyp, + wCurrentRate, bNeedAck, uFragIdx, + cbLastFragmentSize, uMACfragNum, + byFBOption)); + + pBuf->wTimeStampOff = cpu_to_le16(wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE]); + return (pBuf->wDuration); + } + } + else { + PSTxDataHead_ab pBuf = (PSTxDataHead_ab)pTxDataHead; + //Get SignalField,ServiceField,Length + BBvCaculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktTyp, + (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField), (PBYTE)&(pBuf->bySignalField) + ); + pBuf->wTransmitLength = cpu_to_le16(wLen); + //Get Duration and TimeStampOff + pBuf->wDuration = cpu_to_le16((WORD)s_uGetDataDuration(pDevice, DATADUR_B, cbFrameLength, byPktTyp, + wCurrentRate, bNeedAck, uFragIdx, + cbLastFragmentSize, uMACfragNum, + byFBOption)); + pBuf->wTimeStampOff = cpu_to_le16(wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE]); + return (pBuf->wDuration); + } + return 0; +} + + +static +VOID +s_vFillRTSHead ( + IN PSDevice pDevice, + IN BYTE byPktTyp, + IN PVOID pvRTS, + IN UINT cbFrameLength, + IN BOOL bNeedAck, + IN BOOL bDisCRC, + IN PSEthernetHeader psEthHeader, + IN WORD wCurrentRate, + IN BYTE byFBOption + ) +{ + UINT uRTSFrameLen = 20; + WORD wLen = 0x0000; + + // dummy code, only to avoid compiler warning message + UNREFERENCED_PARAMETER(bNeedAck); + + if (pvRTS == NULL) + return; + + if (bDisCRC) { + // When CRCDIS bit is on, H/W forgot to generate FCS for RTS frame, + // in this case we need to decrease its length by 4. + uRTSFrameLen -= 4; + } + + // Note: So far RTSHead dosen't appear in ATIM & Beacom DMA, so we don't need to take them into account. + // Otherwise, we need to modified codes for them. + if (byPktTyp == PK_TYPE_11GB || byPktTyp == PK_TYPE_11GA) { + if (byFBOption == AUTO_FB_NONE) { + PSRTS_g pBuf = (PSRTS_g)pvRTS; + //Get SignalField,ServiceField,Length + BBvCaculateParameter(pDevice, uRTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B, + (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField_b), (PBYTE)&(pBuf->bySignalField_b) + ); + pBuf->wTransmitLength_b = cpu_to_le16(wLen); + BBvCaculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktTyp, + (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField_a), (PBYTE)&(pBuf->bySignalField_a) + ); + pBuf->wTransmitLength_a = cpu_to_le16(wLen); + //Get Duration + pBuf->wDuration_bb = cpu_to_le16((WORD)s_uGetRTSCTSDuration(pDevice, RTSDUR_BB, cbFrameLength, PK_TYPE_11B, pDevice->byTopCCKBasicRate, bNeedAck, byFBOption)); //0:RTSDuration_bb, 1:2.4G, 1:CCKData + pBuf->wDuration_aa = cpu_to_le16((WORD)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA, cbFrameLength, byPktTyp, wCurrentRate, bNeedAck, byFBOption)); //2:RTSDuration_aa, 1:2.4G, 2,3: 2.4G OFDMData + pBuf->wDuration_ba = cpu_to_le16((WORD)s_uGetRTSCTSDuration(pDevice, RTSDUR_BA, cbFrameLength, byPktTyp, wCurrentRate, bNeedAck, byFBOption)); //1:RTSDuration_ba, 1:2.4G, 2,3:2.4G OFDM Data + + pBuf->Data.wDurationID = pBuf->wDuration_aa; + //Get RTS Frame body + pBuf->Data.wFrameControl = TYPE_CTL_RTS;//0x00B4 + if ((pDevice->eOPMode == OP_MODE_ADHOC) || + (pDevice->eOPMode == OP_MODE_AP)) { + MEMvCopy(&(pBuf->Data.abyRA[0]), &(psEthHeader->abyDstAddr[0]), U_ETHER_ADDR_LEN); + } + else { + MEMvCopy(&(pBuf->Data.abyRA[0]), &(pDevice->abyBSSID[0]), U_ETHER_ADDR_LEN); + } + if (pDevice->eOPMode == OP_MODE_AP) { + MEMvCopy(&(pBuf->Data.abyTA[0]), &(pDevice->abyBSSID[0]), U_ETHER_ADDR_LEN); + } + else { + MEMvCopy(&(pBuf->Data.abyTA[0]), &(psEthHeader->abySrcAddr[0]), U_ETHER_ADDR_LEN); + } + } + else { + PSRTS_g_FB pBuf = (PSRTS_g_FB)pvRTS; + //Get SignalField,ServiceField,Length + BBvCaculateParameter(pDevice, uRTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B, + (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField_b), (PBYTE)&(pBuf->bySignalField_b) + ); + pBuf->wTransmitLength_b = cpu_to_le16(wLen); + BBvCaculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktTyp, + (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField_a), (PBYTE)&(pBuf->bySignalField_a) + ); + pBuf->wTransmitLength_a = cpu_to_le16(wLen); + + //Get Duration + pBuf->wDuration_bb = cpu_to_le16((WORD)s_uGetRTSCTSDuration(pDevice, RTSDUR_BB, cbFrameLength, PK_TYPE_11B, pDevice->byTopCCKBasicRate, bNeedAck, byFBOption)); //0:RTSDuration_bb, 1:2.4G, 1:CCKData + pBuf->wDuration_aa = cpu_to_le16((WORD)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA, cbFrameLength, byPktTyp, wCurrentRate, bNeedAck, byFBOption)); //2:RTSDuration_aa, 1:2.4G, 2,3:2.4G OFDMData + pBuf->wDuration_ba = cpu_to_le16((WORD)s_uGetRTSCTSDuration(pDevice, RTSDUR_BA, cbFrameLength, byPktTyp, wCurrentRate, bNeedAck, byFBOption)); //1:RTSDuration_ba, 1:2.4G, 2,3:2.4G OFDMData + pBuf->wRTSDuration_ba_f0 = cpu_to_le16((WORD)s_uGetRTSCTSDuration(pDevice, RTSDUR_BA_F0, cbFrameLength, byPktTyp, wCurrentRate, bNeedAck, byFBOption)); //4:wRTSDuration_ba_f0, 1:2.4G, 1:CCKData + pBuf->wRTSDuration_aa_f0 = cpu_to_le16((WORD)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA_F0, cbFrameLength, byPktTyp, wCurrentRate, bNeedAck, byFBOption)); //5:wRTSDuration_aa_f0, 1:2.4G, 1:CCKData + pBuf->wRTSDuration_ba_f1 = cpu_to_le16((WORD)s_uGetRTSCTSDuration(pDevice, RTSDUR_BA_F1, cbFrameLength, byPktTyp, wCurrentRate, bNeedAck, byFBOption)); //6:wRTSDuration_ba_f1, 1:2.4G, 1:CCKData + pBuf->wRTSDuration_aa_f1 = cpu_to_le16((WORD)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA_F1, cbFrameLength, byPktTyp, wCurrentRate, bNeedAck, byFBOption)); //7:wRTSDuration_aa_f1, 1:2.4G, 1:CCKData + pBuf->Data.wDurationID = pBuf->wDuration_aa; + //Get RTS Frame body + pBuf->Data.wFrameControl = TYPE_CTL_RTS;//0x00B4 + + if ((pDevice->eOPMode == OP_MODE_ADHOC) || + (pDevice->eOPMode == OP_MODE_AP)) { + MEMvCopy(&(pBuf->Data.abyRA[0]), &(psEthHeader->abyDstAddr[0]), U_ETHER_ADDR_LEN); + } + else { + MEMvCopy(&(pBuf->Data.abyRA[0]), &(pDevice->abyBSSID[0]), U_ETHER_ADDR_LEN); + } + + if (pDevice->eOPMode == OP_MODE_AP) { + MEMvCopy(&(pBuf->Data.abyTA[0]), &(pDevice->abyBSSID[0]), U_ETHER_ADDR_LEN); + } + else { + MEMvCopy(&(pBuf->Data.abyTA[0]), &(psEthHeader->abySrcAddr[0]), U_ETHER_ADDR_LEN); + } + + } // if (byFBOption == AUTO_FB_NONE) + } + else if (byPktTyp == PK_TYPE_11A) { + if (byFBOption == AUTO_FB_NONE) { + PSRTS_ab pBuf = (PSRTS_ab)pvRTS; + //Get SignalField,ServiceField,Length + BBvCaculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktTyp, + (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField), (PBYTE)&(pBuf->bySignalField) + ); + pBuf->wTransmitLength = cpu_to_le16(wLen); + //Get Duration + pBuf->wDuration = cpu_to_le16((WORD)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA, cbFrameLength, byPktTyp, wCurrentRate, bNeedAck, byFBOption)); //0:RTSDuration_aa, 0:5G, 0: 5G OFDMData + pBuf->Data.wDurationID = pBuf->wDuration; + //Get RTS Frame body + pBuf->Data.wFrameControl = TYPE_CTL_RTS;//0x00B4 + + if ((pDevice->eOPMode == OP_MODE_ADHOC) || + (pDevice->eOPMode == OP_MODE_AP)) { + MEMvCopy(&(pBuf->Data.abyRA[0]), &(psEthHeader->abyDstAddr[0]), U_ETHER_ADDR_LEN); + } + else { + MEMvCopy(&(pBuf->Data.abyRA[0]), &(pDevice->abyBSSID[0]), U_ETHER_ADDR_LEN); + } + + if (pDevice->eOPMode == OP_MODE_AP) { + MEMvCopy(&(pBuf->Data.abyTA[0]), &(pDevice->abyBSSID[0]), U_ETHER_ADDR_LEN); + } + else { + MEMvCopy(&(pBuf->Data.abyTA[0]), &(psEthHeader->abySrcAddr[0]), U_ETHER_ADDR_LEN); + } + + } + else { + PSRTS_a_FB pBuf = (PSRTS_a_FB)pvRTS; + //Get SignalField,ServiceField,Length + BBvCaculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktTyp, + (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField), (PBYTE)&(pBuf->bySignalField) + ); + pBuf->wTransmitLength = cpu_to_le16(wLen); + //Get Duration + pBuf->wDuration = cpu_to_le16((WORD)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA, cbFrameLength, byPktTyp, wCurrentRate, bNeedAck, byFBOption)); //0:RTSDuration_aa, 0:5G, 0: 5G OFDMData + pBuf->wRTSDuration_f0 = cpu_to_le16((WORD)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA_F0, cbFrameLength, byPktTyp, wCurrentRate, bNeedAck, byFBOption)); //5:RTSDuration_aa_f0, 0:5G, 0: 5G OFDMData + pBuf->wRTSDuration_f1 = cpu_to_le16((WORD)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA_F1, cbFrameLength, byPktTyp, wCurrentRate, bNeedAck, byFBOption)); //7:RTSDuration_aa_f1, 0:5G, 0: + pBuf->Data.wDurationID = pBuf->wDuration; + //Get RTS Frame body + pBuf->Data.wFrameControl = TYPE_CTL_RTS;//0x00B4 + + if ((pDevice->eOPMode == OP_MODE_ADHOC) || + (pDevice->eOPMode == OP_MODE_AP)) { + MEMvCopy(&(pBuf->Data.abyRA[0]), &(psEthHeader->abyDstAddr[0]), U_ETHER_ADDR_LEN); + } + else { + MEMvCopy(&(pBuf->Data.abyRA[0]), &(pDevice->abyBSSID[0]), U_ETHER_ADDR_LEN); + } + if (pDevice->eOPMode == OP_MODE_AP) { + MEMvCopy(&(pBuf->Data.abyTA[0]), &(pDevice->abyBSSID[0]), U_ETHER_ADDR_LEN); + } + else { + MEMvCopy(&(pBuf->Data.abyTA[0]), &(psEthHeader->abySrcAddr[0]), U_ETHER_ADDR_LEN); + } + } + } + else if (byPktTyp == PK_TYPE_11B) { + PSRTS_ab pBuf = (PSRTS_ab)pvRTS; + //Get SignalField,ServiceField,Length + BBvCaculateParameter(pDevice, uRTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B, + (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField), (PBYTE)&(pBuf->bySignalField) + ); + pBuf->wTransmitLength = cpu_to_le16(wLen); + //Get Duration + pBuf->wDuration = cpu_to_le16((WORD)s_uGetRTSCTSDuration(pDevice, RTSDUR_BB, cbFrameLength, byPktTyp, wCurrentRate, bNeedAck, byFBOption)); //0:RTSDuration_bb, 1:2.4G, 1:CCKData + pBuf->Data.wDurationID = pBuf->wDuration; + //Get RTS Frame body + pBuf->Data.wFrameControl = TYPE_CTL_RTS;//0x00B4 + + + if ((pDevice->eOPMode == OP_MODE_ADHOC) || + (pDevice->eOPMode == OP_MODE_AP)) { + MEMvCopy(&(pBuf->Data.abyRA[0]), &(psEthHeader->abyDstAddr[0]), U_ETHER_ADDR_LEN); + } + else { + MEMvCopy(&(pBuf->Data.abyRA[0]), &(pDevice->abyBSSID[0]), U_ETHER_ADDR_LEN); + } + + if (pDevice->eOPMode == OP_MODE_AP) { + MEMvCopy(&(pBuf->Data.abyTA[0]), &(pDevice->abyBSSID[0]), U_ETHER_ADDR_LEN); + } + else { + MEMvCopy(&(pBuf->Data.abyTA[0]), &(psEthHeader->abySrcAddr[0]), U_ETHER_ADDR_LEN); + } + } +} + +static +VOID +s_vFillCTSHead ( + IN PSDevice pDevice, + IN UINT uDMAIdx, + IN BYTE byPktTyp, + IN PVOID pvCTS, + IN UINT cbFrameLength, + IN BOOL bNeedAck, + IN BOOL bDisCRC, + IN WORD wCurrentRate, + IN BYTE byFBOption + ) +{ + UINT uCTSFrameLen = 14; + WORD wLen = 0x0000; + + if (pvCTS == NULL) { + return; + } + + if (bDisCRC) { + // When CRCDIS bit is on, H/W forgot to generate FCS for CTS frame, + // in this case we need to decrease its length by 4. + uCTSFrameLen -= 4; + } + + if (byPktTyp == PK_TYPE_11GB || byPktTyp == PK_TYPE_11GA) { + if (byFBOption != AUTO_FB_NONE && uDMAIdx != TYPE_ATIMDMA && uDMAIdx != TYPE_BEACONDMA) { + // Auto Fall back + PSCTS_FB pBuf = (PSCTS_FB)pvCTS; + //Get SignalField,ServiceField,Length + BBvCaculateParameter(pDevice, uCTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B, + (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField_b), (PBYTE)&(pBuf->bySignalField_b) + ); + + + pBuf->wTransmitLength_b = cpu_to_le16(wLen); + + pBuf->wDuration_ba = (WORD)s_uGetRTSCTSDuration(pDevice, CTSDUR_BA, cbFrameLength, byPktTyp, wCurrentRate, bNeedAck, byFBOption); //3:CTSDuration_ba, 1:2.4G, 2,3:2.4G OFDM Data + pBuf->wDuration_ba += pDevice->wCTSDuration; + pBuf->wDuration_ba = cpu_to_le16(pBuf->wDuration_ba); + //Get CTSDuration_ba_f0 + pBuf->wCTSDuration_ba_f0 = (WORD)s_uGetRTSCTSDuration(pDevice, CTSDUR_BA_F0, cbFrameLength, byPktTyp, wCurrentRate, bNeedAck, byFBOption); //8:CTSDuration_ba_f0, 1:2.4G, 2,3:2.4G OFDM Data + pBuf->wCTSDuration_ba_f0 += pDevice->wCTSDuration; + pBuf->wCTSDuration_ba_f0 = cpu_to_le16(pBuf->wCTSDuration_ba_f0); + //Get CTSDuration_ba_f1 + pBuf->wCTSDuration_ba_f1 = (WORD)s_uGetRTSCTSDuration(pDevice, CTSDUR_BA_F1, cbFrameLength, byPktTyp, wCurrentRate, bNeedAck, byFBOption); //9:CTSDuration_ba_f1, 1:2.4G, 2,3:2.4G OFDM Data + pBuf->wCTSDuration_ba_f1 += pDevice->wCTSDuration; + pBuf->wCTSDuration_ba_f1 = cpu_to_le16(pBuf->wCTSDuration_ba_f1); + //Get CTS Frame body + pBuf->Data.wDurationID = pBuf->wDuration_ba; + pBuf->Data.wFrameControl = TYPE_CTL_CTS;//0x00C4 + pBuf->Data.wReserved = 0x0000; + MEMvCopy(&(pBuf->Data.abyRA[0]), &(pDevice->abyCurrentNetAddr[0]), U_ETHER_ADDR_LEN); + + } else { //if (byFBOption != AUTO_FB_NONE && uDMAIdx != TYPE_ATIMDMA && uDMAIdx != TYPE_BEACONDMA) + PSCTS pBuf = (PSCTS)pvCTS; + //Get SignalField,ServiceField,Length + BBvCaculateParameter(pDevice, uCTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B, + (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField_b), (PBYTE)&(pBuf->bySignalField_b) + ); + pBuf->wTransmitLength_b = cpu_to_le16(wLen); + //Get CTSDuration_ba + pBuf->wDuration_ba = cpu_to_le16((WORD)s_uGetRTSCTSDuration(pDevice, CTSDUR_BA, cbFrameLength, byPktTyp, wCurrentRate, bNeedAck, byFBOption)); //3:CTSDuration_ba, 1:2.4G, 2,3:2.4G OFDM Data + pBuf->wDuration_ba += pDevice->wCTSDuration; + pBuf->wDuration_ba = cpu_to_le16(pBuf->wDuration_ba); + + //Get CTS Frame body + pBuf->Data.wDurationID = pBuf->wDuration_ba; + pBuf->Data.wFrameControl = TYPE_CTL_CTS;//0x00C4 + pBuf->Data.wReserved = 0x0000; + MEMvCopy(&(pBuf->Data.abyRA[0]), &(pDevice->abyCurrentNetAddr[0]), U_ETHER_ADDR_LEN); + } + } +} + + + + + + +/*+ + * + * Description: + * Generate FIFO control for MAC & Baseband controller + * + * Parameters: + * In: + * pDevice - Pointer to adpater + * pTxDataHead - Transmit Data Buffer + * pTxBufHead - pTxBufHead + * pvRrvTime - pvRrvTime + * pvRTS - RTS Buffer + * pCTS - CTS Buffer + * cbFrameSize - Transmit Data Length (Hdr+Payload+FCS) + * bNeedACK - If need ACK + * uDescIdx - Desc Index + * Out: + * none + * + * Return Value: none + * +-*/ +// UINT cbFrameSize,//Hdr+Payload+FCS +static +VOID +s_vGenerateTxParameter ( + IN PSDevice pDevice, + IN BYTE byPktTyp, + IN PVOID pTxBufHead, + IN PVOID pvRrvTime, + IN PVOID pvRTS, + IN PVOID pvCTS, + IN UINT cbFrameSize, + IN BOOL bNeedACK, + IN UINT uDMAIdx, + IN PSEthernetHeader psEthHeader, + IN WORD wCurrentRate + ) +{ + UINT cbMACHdLen = WLAN_HDR_ADDR3_LEN; //24 + WORD wFifoCtl; + BOOL bDisCRC = FALSE; + BYTE byFBOption = AUTO_FB_NONE; +// WORD wCurrentRate = pDevice->wCurrentRate; + + //DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"s_vGenerateTxParameter...\n"); + PSTxBufHead pFifoHead = (PSTxBufHead)pTxBufHead; + pFifoHead->wReserved = wCurrentRate; + wFifoCtl = pFifoHead->wFIFOCtl; + + if (wFifoCtl & FIFOCTL_CRCDIS) { + bDisCRC = TRUE; + } + + if (wFifoCtl & FIFOCTL_AUTO_FB_0) { + byFBOption = AUTO_FB_0; + } + else if (wFifoCtl & FIFOCTL_AUTO_FB_1) { + byFBOption = AUTO_FB_1; + } + + if (pDevice->bLongHeader) + cbMACHdLen = WLAN_HDR_ADDR3_LEN + 6; + + if (byPktTyp == PK_TYPE_11GB || byPktTyp == PK_TYPE_11GA) { + + if (pvRTS != NULL) { //RTS_need + //Fill RsvTime + if (pvRrvTime) { + PSRrvTime_gRTS pBuf = (PSRrvTime_gRTS)pvRrvTime; + pBuf->wRTSTxRrvTime_aa = cpu_to_le16((WORD)s_uGetRTSCTSRsvTime(pDevice, 2, byPktTyp, cbFrameSize, wCurrentRate));//2:RTSTxRrvTime_aa, 1:2.4GHz + pBuf->wRTSTxRrvTime_ba = cpu_to_le16((WORD)s_uGetRTSCTSRsvTime(pDevice, 1, byPktTyp, cbFrameSize, wCurrentRate));//1:RTSTxRrvTime_ba, 1:2.4GHz + pBuf->wRTSTxRrvTime_bb = cpu_to_le16((WORD)s_uGetRTSCTSRsvTime(pDevice, 0, byPktTyp, cbFrameSize, wCurrentRate));//0:RTSTxRrvTime_bb, 1:2.4GHz + pBuf->wTxRrvTime_a = cpu_to_le16((WORD) s_uGetTxRsvTime(pDevice, byPktTyp, cbFrameSize, wCurrentRate, bNeedACK));//2.4G OFDM + pBuf->wTxRrvTime_b = cpu_to_le16((WORD) s_uGetTxRsvTime(pDevice, PK_TYPE_11B, cbFrameSize, pDevice->byTopCCKBasicRate, bNeedACK));//1:CCK + } + //Fill RTS + s_vFillRTSHead(pDevice, byPktTyp, pvRTS, cbFrameSize, bNeedACK, bDisCRC, psEthHeader, wCurrentRate, byFBOption); + } + else {//RTS_needless, PCF mode + + //Fill RsvTime + if (pvRrvTime) { + PSRrvTime_gCTS pBuf = (PSRrvTime_gCTS)pvRrvTime; + pBuf->wTxRrvTime_a = cpu_to_le16((WORD)s_uGetTxRsvTime(pDevice, byPktTyp, cbFrameSize, wCurrentRate, bNeedACK));//2.4G OFDM + pBuf->wTxRrvTime_b = cpu_to_le16((WORD)s_uGetTxRsvTime(pDevice, PK_TYPE_11B, cbFrameSize, pDevice->byTopCCKBasicRate, bNeedACK));//1:CCK + pBuf->wCTSTxRrvTime_ba = cpu_to_le16((WORD)s_uGetRTSCTSRsvTime(pDevice, 3, byPktTyp, cbFrameSize, wCurrentRate));//3:CTSTxRrvTime_Ba, 1:2.4GHz + } + + + //Fill CTS + s_vFillCTSHead(pDevice, uDMAIdx, byPktTyp, pvCTS, cbFrameSize, bNeedACK, bDisCRC, wCurrentRate, byFBOption); + } + } + else if (byPktTyp == PK_TYPE_11A) { + + if (pvRTS != NULL) {//RTS_need, non PCF mode + //Fill RsvTime + if (pvRrvTime) { + PSRrvTime_ab pBuf = (PSRrvTime_ab)pvRrvTime; + pBuf->wRTSTxRrvTime = cpu_to_le16((WORD)s_uGetRTSCTSRsvTime(pDevice, 2, byPktTyp, cbFrameSize, wCurrentRate));//2:RTSTxRrvTime_aa, 0:5GHz + pBuf->wTxRrvTime = cpu_to_le16((WORD)s_uGetTxRsvTime(pDevice, byPktTyp, cbFrameSize, wCurrentRate, bNeedACK));//0:OFDM + } + //Fill RTS + s_vFillRTSHead(pDevice, byPktTyp, pvRTS, cbFrameSize, bNeedACK, bDisCRC, psEthHeader, wCurrentRate, byFBOption); + } + else if (pvRTS == NULL) {//RTS_needless, non PCF mode + //Fill RsvTime + if (pvRrvTime) { + PSRrvTime_ab pBuf = (PSRrvTime_ab)pvRrvTime; + pBuf->wTxRrvTime = cpu_to_le16((WORD)s_uGetTxRsvTime(pDevice, PK_TYPE_11A, cbFrameSize, wCurrentRate, bNeedACK)); //0:OFDM + } + } + } + else if (byPktTyp == PK_TYPE_11B) { + + if ((pvRTS != NULL)) {//RTS_need, non PCF mode + //Fill RsvTime + if (pvRrvTime) { + PSRrvTime_ab pBuf = (PSRrvTime_ab)pvRrvTime; + pBuf->wRTSTxRrvTime = cpu_to_le16((WORD)s_uGetRTSCTSRsvTime(pDevice, 0, byPktTyp, cbFrameSize, wCurrentRate));//0:RTSTxRrvTime_bb, 1:2.4GHz + pBuf->wTxRrvTime = cpu_to_le16((WORD)s_uGetTxRsvTime(pDevice, PK_TYPE_11B, cbFrameSize, wCurrentRate, bNeedACK));//1:CCK + } + //Fill RTS + s_vFillRTSHead(pDevice, byPktTyp, pvRTS, cbFrameSize, bNeedACK, bDisCRC, psEthHeader, wCurrentRate, byFBOption); + } + else { //RTS_needless, non PCF mode + //Fill RsvTime + if (pvRrvTime) { + PSRrvTime_ab pBuf = (PSRrvTime_ab)pvRrvTime; + pBuf->wTxRrvTime = cpu_to_le16((WORD)s_uGetTxRsvTime(pDevice, PK_TYPE_11B, cbFrameSize, wCurrentRate, bNeedACK)); //1:CCK + } + } + } + //DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"s_vGenerateTxParameter END.\n"); +} +/* + PBYTE pbyBuffer,//point to pTxBufHead + WORD wFragType,//00:Non-Frag, 01:Start, 02:Mid, 03:Last + UINT cbFragmentSize,//Hdr+payoad+FCS +*/ +static +VOID +s_vFillFragParameter( + IN PSDevice pDevice, + IN PBYTE pbyBuffer, + IN UINT uTxType, + IN PVOID pvtdCurr, + IN WORD wFragType, + IN UINT cbReqCount + ) +{ + PSTxBufHead pTxBufHead = (PSTxBufHead) pbyBuffer; + //DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"s_vFillFragParameter...\n"); + + if (uTxType == TYPE_SYNCDMA) { + //PSTxSyncDesc ptdCurr = (PSTxSyncDesc)s_pvGetTxDescHead(pDevice, uTxType, uCurIdx); + PSTxSyncDesc ptdCurr = (PSTxSyncDesc)pvtdCurr; + + //Set FIFOCtl & TimeStamp in TxSyncDesc + ptdCurr->m_wFIFOCtl = pTxBufHead->wFIFOCtl; + ptdCurr->m_wTimeStamp = pTxBufHead->wTimeStamp; + //Set TSR1 & ReqCount in TxDescHead + ptdCurr->m_td1TD1.wReqCount = cpu_to_le16((WORD)(cbReqCount)); + if (wFragType == FRAGCTL_ENDFRAG) { //Last Fragmentation + ptdCurr->m_td1TD1.byTCR |= (TCR_STP | TCR_EDP | EDMSDU); + } + else { + ptdCurr->m_td1TD1.byTCR |= (TCR_STP | TCR_EDP); + } + } + else { + //PSTxDesc ptdCurr = (PSTxDesc)s_pvGetTxDescHead(pDevice, uTxType, uCurIdx); + PSTxDesc ptdCurr = (PSTxDesc)pvtdCurr; + //Set TSR1 & ReqCount in TxDescHead + ptdCurr->m_td1TD1.wReqCount = cpu_to_le16((WORD)(cbReqCount)); + if (wFragType == FRAGCTL_ENDFRAG) { //Last Fragmentation + ptdCurr->m_td1TD1.byTCR |= (TCR_STP | TCR_EDP | EDMSDU); + } + else { + ptdCurr->m_td1TD1.byTCR |= (TCR_STP | TCR_EDP); + } + } + + pTxBufHead->wFragCtl |= (WORD)wFragType;//0x0001; //0000 0000 0000 0001 + + //DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"s_vFillFragParameter END\n"); +} + +static +UINT +s_cbFillTxBufHead ( + IN PSDevice pDevice, + IN BYTE byPktTyp, + IN PBYTE pbyTxBufferAddr, + IN UINT cbFrameBodySize, + IN UINT uDMAIdx, + IN PSTxDesc pHeadTD, + IN PSEthernetHeader psEthHeader, + IN PBYTE pPacket, + IN BOOL bNeedEncrypt, + IN PSKeyItem pTransmitKey, + IN UINT uNodeIndex, + OUT PUINT puMACfragNum + ) +{ + UINT cbMACHdLen; + UINT cbFrameSize; + UINT cbFragmentSize; //Hdr+(IV)+payoad+(MIC)+(ICV)+FCS + UINT cbFragPayloadSize; + UINT cbLastFragmentSize; //Hdr+(IV)+payoad+(MIC)+(ICV)+FCS + UINT cbLastFragPayloadSize; + UINT uFragIdx; + PBYTE pbyPayloadHead; + PBYTE pbyIVHead; + PBYTE pbyMacHdr; + WORD wFragType; //00:Non-Frag, 01:Start, 10:Mid, 11:Last + UINT uDuration; + PBYTE pbyBuffer; +// UINT uKeyEntryIdx = NUM_KEY_ENTRY+1; +// BYTE byKeySel = 0xFF; + UINT cbIVlen = 0; + UINT cbICVlen = 0; + UINT cbMIClen = 0; + UINT cbFCSlen = 4; + UINT cb802_1_H_len = 0; + UINT uLength = 0; + UINT uTmpLen = 0; +// BYTE abyTmp[8]; +// DWORD dwCRC; + UINT cbMICHDR = 0; + DWORD dwMICKey0, dwMICKey1; + DWORD dwMIC_Priority; + PDWORD pdwMIC_L; + PDWORD pdwMIC_R; + DWORD dwSafeMIC_L, dwSafeMIC_R; //Fix "Last Frag Size" < "MIC length". + BOOL bMIC2Frag = FALSE; + UINT uMICFragLen = 0; + UINT uMACfragNum = 1; + UINT uPadding = 0; + UINT cbReqCount = 0; + + BOOL bNeedACK; + BOOL bRTS; + BOOL bIsAdhoc; + PBYTE pbyType; + PSTxDesc ptdCurr; + PSTxBufHead psTxBufHd = (PSTxBufHead) pbyTxBufferAddr; +// UINT tmpDescIdx; + UINT cbHeaderLength = 0; + PVOID pvRrvTime; + PSMICHDRHead pMICHDR; + PVOID pvRTS; + PVOID pvCTS; + PVOID pvTxDataHd; + WORD wTxBufSize; // FFinfo size + UINT uTotalCopyLength = 0; + BYTE byFBOption = AUTO_FB_NONE; + BOOL bIsWEP256 = FALSE; + PSMgmtObject pMgmt = pDevice->pMgmt; + + + pvRrvTime = pMICHDR = pvRTS = pvCTS = pvTxDataHd = NULL; + + //DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"s_cbFillTxBufHead...\n"); + if ((pDevice->eOPMode == OP_MODE_ADHOC) || + (pDevice->eOPMode == OP_MODE_AP)) { + + if (IS_MULTICAST_ADDRESS(&(psEthHeader->abyDstAddr[0])) || + IS_BROADCAST_ADDRESS(&(psEthHeader->abyDstAddr[0]))) { + bNeedACK = FALSE; + } + else { + bNeedACK = TRUE; + } + bIsAdhoc = TRUE; + } + else { + // MSDUs in Infra mode always need ACK + bNeedACK = TRUE; + bIsAdhoc = FALSE; + } + + if (pDevice->bLongHeader) + cbMACHdLen = WLAN_HDR_ADDR3_LEN + 6; + else + cbMACHdLen = WLAN_HDR_ADDR3_LEN; + + + if ((bNeedEncrypt == TRUE) && (pTransmitKey != NULL)) { + if (pTransmitKey->byCipherSuite == KEY_CTL_WEP) { + cbIVlen = 4; + cbICVlen = 4; + if (pTransmitKey->uKeyLength == WLAN_WEP232_KEYLEN) { + bIsWEP256 = TRUE; + } + } + if (pTransmitKey->byCipherSuite == KEY_CTL_TKIP) { + cbIVlen = 8;//IV+ExtIV + cbMIClen = 8; + cbICVlen = 4; + } + if (pTransmitKey->byCipherSuite == KEY_CTL_CCMP) { + cbIVlen = 8;//RSN Header + cbICVlen = 8;//MIC + cbMICHDR = sizeof(SMICHDRHead); + } + if (pDevice->byLocalID > REV_ID_VT3253_A1) { + //MAC Header should be padding 0 to DW alignment. + uPadding = 4 - (cbMACHdLen%4); + uPadding %= 4; + } + } + + + cbFrameSize = cbMACHdLen + cbIVlen + (cbFrameBodySize + cbMIClen) + cbICVlen + cbFCSlen; + + if ((bNeedACK == FALSE) || + (cbFrameSize < pDevice->wRTSThreshold) || + ((cbFrameSize >= pDevice->wFragmentationThreshold) && (pDevice->wFragmentationThreshold <= pDevice->wRTSThreshold)) + ) { + bRTS = FALSE; + } + else { + bRTS = TRUE; + psTxBufHd->wFIFOCtl |= (FIFOCTL_RTS | FIFOCTL_LRETRY); + } + // + // Use for AUTO FALL BACK + // + if (psTxBufHd->wFIFOCtl & FIFOCTL_AUTO_FB_0) { + byFBOption = AUTO_FB_0; + } + else if (psTxBufHd->wFIFOCtl & FIFOCTL_AUTO_FB_1) { + byFBOption = AUTO_FB_1; + } + + ////////////////////////////////////////////////////// + //Set RrvTime/RTS/CTS Buffer + wTxBufSize = sizeof(STxBufHead); + if (byPktTyp == PK_TYPE_11GB || byPktTyp == PK_TYPE_11GA) {//802.11g packet + + if (byFBOption == AUTO_FB_NONE) { + if (bRTS == TRUE) {//RTS_need + pvRrvTime = (PSRrvTime_gRTS) (pbyTxBufferAddr + wTxBufSize); + pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gRTS)); + pvRTS = (PSRTS_g) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gRTS) + cbMICHDR); + pvCTS = NULL; + pvTxDataHd = (PSTxDataHead_g) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gRTS) + cbMICHDR + sizeof(SRTS_g)); + cbHeaderLength = wTxBufSize + sizeof(SRrvTime_gRTS) + cbMICHDR + sizeof(SRTS_g) + sizeof(STxDataHead_g); + } + else { //RTS_needless + pvRrvTime = (PSRrvTime_gCTS) (pbyTxBufferAddr + wTxBufSize); + pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS)); + pvRTS = NULL; + pvCTS = (PSCTS) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS) + cbMICHDR); + pvTxDataHd = (PSTxDataHead_g) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS) + cbMICHDR + sizeof(SCTS)); + cbHeaderLength = wTxBufSize + sizeof(SRrvTime_gCTS) + cbMICHDR + sizeof(SCTS) + sizeof(STxDataHead_g); + } + } else { + // Auto Fall Back + if (bRTS == TRUE) {//RTS_need + pvRrvTime = (PSRrvTime_gRTS) (pbyTxBufferAddr + wTxBufSize); + pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gRTS)); + pvRTS = (PSRTS_g_FB) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gRTS) + cbMICHDR); + pvCTS = NULL; + pvTxDataHd = (PSTxDataHead_g_FB) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gRTS) + cbMICHDR + sizeof(SRTS_g_FB)); + cbHeaderLength = wTxBufSize + sizeof(SRrvTime_gRTS) + cbMICHDR + sizeof(SRTS_g_FB) + sizeof(STxDataHead_g_FB); + } + else { //RTS_needless + pvRrvTime = (PSRrvTime_gCTS) (pbyTxBufferAddr + wTxBufSize); + pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS)); + pvRTS = NULL; + pvCTS = (PSCTS_FB) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS) + cbMICHDR); + pvTxDataHd = (PSTxDataHead_g_FB) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS) + cbMICHDR + sizeof(SCTS_FB)); + cbHeaderLength = wTxBufSize + sizeof(SRrvTime_gCTS) + cbMICHDR + sizeof(SCTS_FB) + sizeof(STxDataHead_g_FB); + } + } // Auto Fall Back + } + else {//802.11a/b packet + + if (byFBOption == AUTO_FB_NONE) { + if (bRTS == TRUE) { + pvRrvTime = (PSRrvTime_ab) (pbyTxBufferAddr + wTxBufSize); + pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab)); + pvRTS = (PSRTS_ab) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab) + cbMICHDR); + pvCTS = NULL; + pvTxDataHd = (PSTxDataHead_ab) (pbyTxBufferAddr + wTxBufSize + sizeof(PSRrvTime_ab) + cbMICHDR + sizeof(SRTS_ab)); + cbHeaderLength = wTxBufSize + sizeof(PSRrvTime_ab) + cbMICHDR + sizeof(SRTS_ab) + sizeof(STxDataHead_ab); + } + else { //RTS_needless, need MICHDR + pvRrvTime = (PSRrvTime_ab) (pbyTxBufferAddr + wTxBufSize); + pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab)); + pvRTS = NULL; + pvCTS = NULL; + pvTxDataHd = (PSTxDataHead_ab) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab) + cbMICHDR); + cbHeaderLength = wTxBufSize + sizeof(SRrvTime_ab) + cbMICHDR + sizeof(STxDataHead_ab); + } + } else { + // Auto Fall Back + if (bRTS == TRUE) {//RTS_need + pvRrvTime = (PSRrvTime_ab) (pbyTxBufferAddr + wTxBufSize); + pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab)); + pvRTS = (PSRTS_a_FB) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab) + cbMICHDR); + pvCTS = NULL; + pvTxDataHd = (PSTxDataHead_a_FB) (pbyTxBufferAddr + wTxBufSize + sizeof(PSRrvTime_ab) + cbMICHDR + sizeof(SRTS_a_FB)); + cbHeaderLength = wTxBufSize + sizeof(PSRrvTime_ab) + cbMICHDR + sizeof(SRTS_a_FB) + sizeof(STxDataHead_a_FB); + } + else { //RTS_needless + pvRrvTime = (PSRrvTime_ab) (pbyTxBufferAddr + wTxBufSize); + pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab)); + pvRTS = NULL; + pvCTS = NULL; + pvTxDataHd = (PSTxDataHead_a_FB) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab) + cbMICHDR); + cbHeaderLength = wTxBufSize + sizeof(SRrvTime_ab) + cbMICHDR + sizeof(STxDataHead_a_FB); + } + } // Auto Fall Back + } + ZERO_MEMORY((PVOID)(pbyTxBufferAddr + wTxBufSize), (cbHeaderLength - wTxBufSize)); + +////////////////////////////////////////////////////////////////// + if ((bNeedEncrypt == TRUE) && (pTransmitKey != NULL) && (pTransmitKey->byCipherSuite == KEY_CTL_TKIP)) { + if (pDevice->pMgmt->eAuthenMode == WMAC_AUTH_WPANONE) { + dwMICKey0 = *(PDWORD)(&pTransmitKey->abyKey[16]); + dwMICKey1 = *(PDWORD)(&pTransmitKey->abyKey[20]); + } + else if ((pTransmitKey->dwKeyIndex & AUTHENTICATOR_KEY) != 0) { + dwMICKey0 = *(PDWORD)(&pTransmitKey->abyKey[16]); + dwMICKey1 = *(PDWORD)(&pTransmitKey->abyKey[20]); + } + else { + dwMICKey0 = *(PDWORD)(&pTransmitKey->abyKey[24]); + dwMICKey1 = *(PDWORD)(&pTransmitKey->abyKey[28]); + } + // DO Software Michael + MIC_vInit(dwMICKey0, dwMICKey1); + MIC_vAppend((PBYTE)&(psEthHeader->abyDstAddr[0]), 12); + dwMIC_Priority = 0; + MIC_vAppend((PBYTE)&dwMIC_Priority, 4); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"MIC KEY: %lX, %lX\n", dwMICKey0, dwMICKey1); + } + +/////////////////////////////////////////////////////////////////// + + pbyMacHdr = (PBYTE)(pbyTxBufferAddr + cbHeaderLength); + pbyPayloadHead = (PBYTE)(pbyMacHdr + cbMACHdLen + uPadding + cbIVlen); + pbyIVHead = (PBYTE)(pbyMacHdr + cbMACHdLen + uPadding); + + if ((cbFrameSize > pDevice->wFragmentationThreshold) && (bNeedACK == TRUE) && (bIsWEP256 == FALSE)) { + // Fragmentation + // FragThreshold = Fragment size(Hdr+(IV)+fragment payload+(MIC)+(ICV)+FCS) + cbFragmentSize = pDevice->wFragmentationThreshold; + cbFragPayloadSize = cbFragmentSize - cbMACHdLen - cbIVlen - cbICVlen - cbFCSlen; + //FragNum = (FrameSize-(Hdr+FCS))/(Fragment Size -(Hrd+FCS))) + uMACfragNum = (WORD) ((cbFrameBodySize + cbMIClen) / cbFragPayloadSize); + cbLastFragPayloadSize = (cbFrameBodySize + cbMIClen) % cbFragPayloadSize; + if (cbLastFragPayloadSize == 0) { + cbLastFragPayloadSize = cbFragPayloadSize; + } else { + uMACfragNum++; + } + //[Hdr+(IV)+last fragment payload+(MIC)+(ICV)+FCS] + cbLastFragmentSize = cbMACHdLen + cbLastFragPayloadSize + cbIVlen + cbICVlen + cbFCSlen; + + for (uFragIdx = 0; uFragIdx < uMACfragNum; uFragIdx ++) { + if (uFragIdx == 0) { + //========================= + // Start Fragmentation + //========================= + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Start Fragmentation...\n"); + wFragType = FRAGCTL_STAFRAG; + + + //Fill FIFO,RrvTime,RTS,and CTS + s_vGenerateTxParameter(pDevice, byPktTyp, (PVOID)psTxBufHd, pvRrvTime, pvRTS, pvCTS, + cbFragmentSize, bNeedACK, uDMAIdx, psEthHeader, pDevice->wCurrentRate); + //Fill DataHead + uDuration = s_uFillDataHead(pDevice, byPktTyp, pvTxDataHd, cbFragmentSize, uDMAIdx, bNeedACK, + uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption, pDevice->wCurrentRate); + // Generate TX MAC Header + vGenerateMACHeader(pDevice, pbyMacHdr, (WORD)uDuration, psEthHeader, bNeedEncrypt, + wFragType, uDMAIdx, uFragIdx); + + if (bNeedEncrypt == TRUE) { + //Fill TXKEY + s_vFillTxKey(pDevice, (PBYTE)(psTxBufHd->adwTxKey), pbyIVHead, pTransmitKey, + pbyMacHdr, (WORD)cbFragPayloadSize, (PBYTE)pMICHDR); + //Fill IV(ExtIV,RSNHDR) + if (pDevice->bEnableHostWEP) { + pMgmt->sNodeDBTable[uNodeIndex].dwTSC47_16 = pTransmitKey->dwTSC47_16; + pMgmt->sNodeDBTable[uNodeIndex].wTSC15_0 = pTransmitKey->wTSC15_0; + } + } + + + // 802.1H + if (ntohs(psEthHeader->wType) > MAX_DATA_LEN) { + if ((psEthHeader->wType == TYPE_PKT_IPX) || + (psEthHeader->wType == cpu_to_le16(0xF380))) { + MEMvCopy((PBYTE) (pbyPayloadHead), &pDevice->abySNAP_Bridgetunnel[0], 6); + } + else { + MEMvCopy((PBYTE) (pbyPayloadHead), &pDevice->abySNAP_RFC1042[0], 6); + } + pbyType = (PBYTE) (pbyPayloadHead + 6); + MEMvCopy(pbyType, &(psEthHeader->wType), sizeof(WORD)); + cb802_1_H_len = 8; + } + + cbReqCount = cbHeaderLength + cbMACHdLen + uPadding + cbIVlen + cbFragPayloadSize; + //--------------------------- + // S/W or H/W Encryption + //--------------------------- + //Fill MICHDR + //if (pDevice->bAES) { + // s_vFillMICHDR(pDevice, (PBYTE)pMICHDR, pbyMacHdr, (WORD)cbFragPayloadSize); + //} + //cbReqCount += s_uDoEncryption(pDevice, psEthHeader, (PVOID)psTxBufHd, byKeySel, + // pbyPayloadHead, (WORD)cbFragPayloadSize, uDMAIdx); + + + + //pbyBuffer = (PBYTE)pDevice->aamTxBuf[uDMAIdx][uDescIdx].pbyVAddr; + pbyBuffer = (PBYTE)pHeadTD->pTDInfo->buf; + + uLength = cbHeaderLength + cbMACHdLen + uPadding + cbIVlen + cb802_1_H_len; + //copy TxBufferHeader + MacHeader to desc + MEMvCopy(pbyBuffer, (PVOID)psTxBufHd, uLength); + + // Copy the Packet into a tx Buffer + MEMvCopy((pbyBuffer + uLength), (pPacket + 14), (cbFragPayloadSize - cb802_1_H_len)); + + + uTotalCopyLength += cbFragPayloadSize - cb802_1_H_len; + + if ((bNeedEncrypt == TRUE) && (pTransmitKey != NULL) && (pTransmitKey->byCipherSuite == KEY_CTL_TKIP)) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Start MIC: %d\n", cbFragPayloadSize); + MIC_vAppend((pbyBuffer + uLength - cb802_1_H_len), cbFragPayloadSize); + + } + + //--------------------------- + // S/W Encryption + //--------------------------- + if ((pDevice->byLocalID <= REV_ID_VT3253_A1)) { + if (bNeedEncrypt) { + s_vSWencryption(pDevice, pTransmitKey, (pbyBuffer + uLength - cb802_1_H_len), (WORD)cbFragPayloadSize); + cbReqCount += cbICVlen; + } + } + + ptdCurr = (PSTxDesc)pHeadTD; + //-------------------- + //1.Set TSR1 & ReqCount in TxDescHead + //2.Set FragCtl in TxBufferHead + //3.Set Frame Control + //4.Set Sequence Control + //5.Get S/W generate FCS + //-------------------- + s_vFillFragParameter(pDevice, pbyBuffer, uDMAIdx, (PVOID)ptdCurr, wFragType, cbReqCount); + + ptdCurr->pTDInfo->dwReqCount = cbReqCount - uPadding; + ptdCurr->pTDInfo->dwHeaderLength = cbHeaderLength; + ptdCurr->pTDInfo->skb_dma = ptdCurr->pTDInfo->buf_dma; + ptdCurr->buff_addr = cpu_to_le32(ptdCurr->pTDInfo->skb_dma); + pDevice->iTDUsed[uDMAIdx]++; + pHeadTD = ptdCurr->next; + } + else if (uFragIdx == (uMACfragNum-1)) { + //========================= + // Last Fragmentation + //========================= + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Last Fragmentation...\n"); + //tmpDescIdx = (uDescIdx + uFragIdx) % pDevice->cbTD[uDMAIdx]; + + wFragType = FRAGCTL_ENDFRAG; + + //Fill FIFO,RrvTime,RTS,and CTS + s_vGenerateTxParameter(pDevice, byPktTyp, (PVOID)psTxBufHd, pvRrvTime, pvRTS, pvCTS, + cbLastFragmentSize, bNeedACK, uDMAIdx, psEthHeader, pDevice->wCurrentRate); + //Fill DataHead + uDuration = s_uFillDataHead(pDevice, byPktTyp, pvTxDataHd, cbLastFragmentSize, uDMAIdx, bNeedACK, + uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption, pDevice->wCurrentRate); + + // Generate TX MAC Header + vGenerateMACHeader(pDevice, pbyMacHdr, (WORD)uDuration, psEthHeader, bNeedEncrypt, + wFragType, uDMAIdx, uFragIdx); + + if (bNeedEncrypt == TRUE) { + //Fill TXKEY + s_vFillTxKey(pDevice, (PBYTE)(psTxBufHd->adwTxKey), pbyIVHead, pTransmitKey, + pbyMacHdr, (WORD)cbLastFragPayloadSize, (PBYTE)pMICHDR); + + if (pDevice->bEnableHostWEP) { + pMgmt->sNodeDBTable[uNodeIndex].dwTSC47_16 = pTransmitKey->dwTSC47_16; + pMgmt->sNodeDBTable[uNodeIndex].wTSC15_0 = pTransmitKey->wTSC15_0; + } + + } + + + cbReqCount = cbHeaderLength + cbMACHdLen + uPadding + cbIVlen + cbLastFragPayloadSize; + //--------------------------- + // S/W or H/W Encryption + //--------------------------- + + + + pbyBuffer = (PBYTE)pHeadTD->pTDInfo->buf; + //pbyBuffer = (PBYTE)pDevice->aamTxBuf[uDMAIdx][tmpDescIdx].pbyVAddr; + + uLength = cbHeaderLength + cbMACHdLen + uPadding + cbIVlen; + + //copy TxBufferHeader + MacHeader to desc + MEMvCopy(pbyBuffer, (PVOID)psTxBufHd, uLength); + + // Copy the Packet into a tx Buffer + if (bMIC2Frag == FALSE) { + + MEMvCopy((pbyBuffer + uLength), + (pPacket + 14 + uTotalCopyLength), + (cbLastFragPayloadSize - cbMIClen) + ); + //TODO check uTmpLen ! + uTmpLen = cbLastFragPayloadSize - cbMIClen; + + } + if ((bNeedEncrypt == TRUE) && (pTransmitKey != NULL) && (pTransmitKey->byCipherSuite == KEY_CTL_TKIP)) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"LAST: uMICFragLen:%d, cbLastFragPayloadSize:%d, uTmpLen:%d\n", + uMICFragLen, cbLastFragPayloadSize, uTmpLen); + + if (bMIC2Frag == FALSE) { + if (uTmpLen != 0) + MIC_vAppend((pbyBuffer + uLength), uTmpLen); + pdwMIC_L = (PDWORD)(pbyBuffer + uLength + uTmpLen); + pdwMIC_R = (PDWORD)(pbyBuffer + uLength + uTmpLen + 4); + MIC_vGetMIC(pdwMIC_L, pdwMIC_R); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Last MIC:%lX, %lX\n", *pdwMIC_L, *pdwMIC_R); + } else { + if (uMICFragLen >= 4) { + MEMvCopy((pbyBuffer + uLength), ((PBYTE)&dwSafeMIC_R + (uMICFragLen - 4)), + (cbMIClen - uMICFragLen)); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"LAST: uMICFragLen >= 4: %X, %d\n", + *(PBYTE)((PBYTE)&dwSafeMIC_R + (uMICFragLen - 4)), + (cbMIClen - uMICFragLen)); + + } else { + MEMvCopy((pbyBuffer + uLength), ((PBYTE)&dwSafeMIC_L + uMICFragLen), + (4 - uMICFragLen)); + MEMvCopy((pbyBuffer + uLength + (4 - uMICFragLen)), &dwSafeMIC_R, 4); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"LAST: uMICFragLen < 4: %X, %d\n", + *(PBYTE)((PBYTE)&dwSafeMIC_R + uMICFragLen - 4), + (cbMIClen - uMICFragLen)); + } + /* + for (ii = 0; ii < cbLastFragPayloadSize + 8 + 24; ii++) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"%02x ", *((PBYTE)((pbyBuffer + uLength) + ii - 8 - 24))); + } + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"\n\n"); + */ + } + MIC_vUnInit(); + } else { + ASSERT(uTmpLen == (cbLastFragPayloadSize - cbMIClen)); + } + + + //--------------------------- + // S/W Encryption + //--------------------------- + if ((pDevice->byLocalID <= REV_ID_VT3253_A1)) { + if (bNeedEncrypt) { + s_vSWencryption(pDevice, pTransmitKey, (pbyBuffer + uLength), (WORD)cbLastFragPayloadSize); + cbReqCount += cbICVlen; + } + } + + ptdCurr = (PSTxDesc)pHeadTD; + + //-------------------- + //1.Set TSR1 & ReqCount in TxDescHead + //2.Set FragCtl in TxBufferHead + //3.Set Frame Control + //4.Set Sequence Control + //5.Get S/W generate FCS + //-------------------- + + + s_vFillFragParameter(pDevice, pbyBuffer, uDMAIdx, (PVOID)ptdCurr, wFragType, cbReqCount); + + ptdCurr->pTDInfo->dwReqCount = cbReqCount - uPadding; + ptdCurr->pTDInfo->dwHeaderLength = cbHeaderLength; + ptdCurr->pTDInfo->skb_dma = ptdCurr->pTDInfo->buf_dma; + ptdCurr->buff_addr = cpu_to_le32(ptdCurr->pTDInfo->skb_dma); + pDevice->iTDUsed[uDMAIdx]++; + pHeadTD = ptdCurr->next; + + } + else { + //========================= + // Middle Fragmentation + //========================= + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Middle Fragmentation...\n"); + //tmpDescIdx = (uDescIdx + uFragIdx) % pDevice->cbTD[uDMAIdx]; + + wFragType = FRAGCTL_MIDFRAG; + + //Fill FIFO,RrvTime,RTS,and CTS + s_vGenerateTxParameter(pDevice, byPktTyp, (PVOID)psTxBufHd, pvRrvTime, pvRTS, pvCTS, + cbFragmentSize, bNeedACK, uDMAIdx, psEthHeader, pDevice->wCurrentRate); + //Fill DataHead + uDuration = s_uFillDataHead(pDevice, byPktTyp, pvTxDataHd, cbFragmentSize, uDMAIdx, bNeedACK, + uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption, pDevice->wCurrentRate); + + // Generate TX MAC Header + vGenerateMACHeader(pDevice, pbyMacHdr, (WORD)uDuration, psEthHeader, bNeedEncrypt, + wFragType, uDMAIdx, uFragIdx); + + + if (bNeedEncrypt == TRUE) { + //Fill TXKEY + s_vFillTxKey(pDevice, (PBYTE)(psTxBufHd->adwTxKey), pbyIVHead, pTransmitKey, + pbyMacHdr, (WORD)cbFragPayloadSize, (PBYTE)pMICHDR); + + if (pDevice->bEnableHostWEP) { + pMgmt->sNodeDBTable[uNodeIndex].dwTSC47_16 = pTransmitKey->dwTSC47_16; + pMgmt->sNodeDBTable[uNodeIndex].wTSC15_0 = pTransmitKey->wTSC15_0; + } + } + + cbReqCount = cbHeaderLength + cbMACHdLen + uPadding + cbIVlen + cbFragPayloadSize; + //--------------------------- + // S/W or H/W Encryption + //--------------------------- + //Fill MICHDR + //if (pDevice->bAES) { + // s_vFillMICHDR(pDevice, (PBYTE)pMICHDR, pbyMacHdr, (WORD)cbFragPayloadSize); + //} + //cbReqCount += s_uDoEncryption(pDevice, psEthHeader, (PVOID)psTxBufHd, byKeySel, + // pbyPayloadHead, (WORD)cbFragPayloadSize, uDMAIdx); + + + pbyBuffer = (PBYTE)pHeadTD->pTDInfo->buf; + //pbyBuffer = (PBYTE)pDevice->aamTxBuf[uDMAIdx][tmpDescIdx].pbyVAddr; + + + uLength = cbHeaderLength + cbMACHdLen + uPadding + cbIVlen; + + //copy TxBufferHeader + MacHeader to desc + MEMvCopy(pbyBuffer, (PVOID)psTxBufHd, uLength); + + // Copy the Packet into a tx Buffer + MEMvCopy((pbyBuffer + uLength), + (pPacket + 14 + uTotalCopyLength), + cbFragPayloadSize + ); + uTmpLen = cbFragPayloadSize; + + uTotalCopyLength += uTmpLen; + + if ((bNeedEncrypt == TRUE) && (pTransmitKey != NULL) && (pTransmitKey->byCipherSuite == KEY_CTL_TKIP)) { + + MIC_vAppend((pbyBuffer + uLength), uTmpLen); + + if (uTmpLen < cbFragPayloadSize) { + bMIC2Frag = TRUE; + uMICFragLen = cbFragPayloadSize - uTmpLen; + ASSERT(uMICFragLen < cbMIClen); + + pdwMIC_L = (PDWORD)(pbyBuffer + uLength + uTmpLen); + pdwMIC_R = (PDWORD)(pbyBuffer + uLength + uTmpLen + 4); + MIC_vGetMIC(pdwMIC_L, pdwMIC_R); + dwSafeMIC_L = *pdwMIC_L; + dwSafeMIC_R = *pdwMIC_R; + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"MIDDLE: uMICFragLen:%d, cbFragPayloadSize:%d, uTmpLen:%d\n", + uMICFragLen, cbFragPayloadSize, uTmpLen); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Fill MIC in Middle frag [%d]\n", uMICFragLen); + /* + for (ii = 0; ii < uMICFragLen; ii++) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"%02x ", *((PBYTE)((pbyBuffer + uLength + uTmpLen) + ii))); + } + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"\n"); + */ + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Get MIC:%lX, %lX\n", *pdwMIC_L, *pdwMIC_R); + } + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Middle frag len: %d\n", uTmpLen); + /* + for (ii = 0; ii < uTmpLen; ii++) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"%02x ", *((PBYTE)((pbyBuffer + uLength) + ii))); + } + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"\n\n"); + */ + + } else { + ASSERT(uTmpLen == (cbFragPayloadSize)); + } + + if ((pDevice->byLocalID <= REV_ID_VT3253_A1)) { + if (bNeedEncrypt) { + s_vSWencryption(pDevice, pTransmitKey, (pbyBuffer + uLength), (WORD)cbFragPayloadSize); + cbReqCount += cbICVlen; + } + } + + ptdCurr = (PSTxDesc)pHeadTD; + + //-------------------- + //1.Set TSR1 & ReqCount in TxDescHead + //2.Set FragCtl in TxBufferHead + //3.Set Frame Control + //4.Set Sequence Control + //5.Get S/W generate FCS + //-------------------- + + s_vFillFragParameter(pDevice, pbyBuffer, uDMAIdx, (PVOID)ptdCurr, wFragType, cbReqCount); + + ptdCurr->pTDInfo->dwReqCount = cbReqCount - uPadding; + ptdCurr->pTDInfo->dwHeaderLength = cbHeaderLength; + ptdCurr->pTDInfo->skb_dma = ptdCurr->pTDInfo->buf_dma; + ptdCurr->buff_addr = cpu_to_le32(ptdCurr->pTDInfo->skb_dma); + pDevice->iTDUsed[uDMAIdx]++; + pHeadTD = ptdCurr->next; + } + } // for (uMACfragNum) + } + else { + //========================= + // No Fragmentation + //========================= + //DEVICE_PRTGRP03(("No Fragmentation...\n")); + //DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"No Fragmentation...\n"); + wFragType = FRAGCTL_NONFRAG; + + //Set FragCtl in TxBufferHead + psTxBufHd->wFragCtl |= (WORD)wFragType; + + //Fill FIFO,RrvTime,RTS,and CTS + s_vGenerateTxParameter(pDevice, byPktTyp, (PVOID)psTxBufHd, pvRrvTime, pvRTS, pvCTS, + cbFrameSize, bNeedACK, uDMAIdx, psEthHeader, pDevice->wCurrentRate); + //Fill DataHead + uDuration = s_uFillDataHead(pDevice, byPktTyp, pvTxDataHd, cbFrameSize, uDMAIdx, bNeedACK, + 0, 0, uMACfragNum, byFBOption, pDevice->wCurrentRate); + + // Generate TX MAC Header + vGenerateMACHeader(pDevice, pbyMacHdr, (WORD)uDuration, psEthHeader, bNeedEncrypt, + wFragType, uDMAIdx, 0); + + if (bNeedEncrypt == TRUE) { + //Fill TXKEY + s_vFillTxKey(pDevice, (PBYTE)(psTxBufHd->adwTxKey), pbyIVHead, pTransmitKey, + pbyMacHdr, (WORD)cbFrameBodySize, (PBYTE)pMICHDR); + + if (pDevice->bEnableHostWEP) { + pMgmt->sNodeDBTable[uNodeIndex].dwTSC47_16 = pTransmitKey->dwTSC47_16; + pMgmt->sNodeDBTable[uNodeIndex].wTSC15_0 = pTransmitKey->wTSC15_0; + } + } + + // 802.1H + if (ntohs(psEthHeader->wType) > MAX_DATA_LEN) { + if ((psEthHeader->wType == TYPE_PKT_IPX) || + (psEthHeader->wType == cpu_to_le16(0xF380))) { + MEMvCopy((PBYTE) (pbyPayloadHead), &pDevice->abySNAP_Bridgetunnel[0], 6); + } + else { + MEMvCopy((PBYTE) (pbyPayloadHead), &pDevice->abySNAP_RFC1042[0], 6); + } + pbyType = (PBYTE) (pbyPayloadHead + 6); + MEMvCopy(pbyType, &(psEthHeader->wType), sizeof(WORD)); + cb802_1_H_len = 8; + } + + cbReqCount = cbHeaderLength + cbMACHdLen + uPadding + cbIVlen + (cbFrameBodySize + cbMIClen); + //--------------------------- + // S/W or H/W Encryption + //--------------------------- + //Fill MICHDR + //if (pDevice->bAES) { + // DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Fill MICHDR...\n"); + // s_vFillMICHDR(pDevice, (PBYTE)pMICHDR, pbyMacHdr, (WORD)cbFrameBodySize); + //} + + pbyBuffer = (PBYTE)pHeadTD->pTDInfo->buf; + //pbyBuffer = (PBYTE)pDevice->aamTxBuf[uDMAIdx][uDescIdx].pbyVAddr; + + uLength = cbHeaderLength + cbMACHdLen + uPadding + cbIVlen + cb802_1_H_len; + + //copy TxBufferHeader + MacHeader to desc + MEMvCopy(pbyBuffer, (PVOID)psTxBufHd, uLength); + + // Copy the Packet into a tx Buffer + MEMvCopy((pbyBuffer + uLength), + (pPacket + 14), + cbFrameBodySize - cb802_1_H_len + ); + + if ((bNeedEncrypt == TRUE) && (pTransmitKey != NULL) && (pTransmitKey->byCipherSuite == KEY_CTL_TKIP)){ + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Length:%d, %d\n", cbFrameBodySize - cb802_1_H_len, uLength); + /* + for (ii = 0; ii < (cbFrameBodySize - cb802_1_H_len); ii++) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"%02x ", *((PBYTE)((pbyBuffer + uLength) + ii))); + } + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"\n"); + */ + + MIC_vAppend((pbyBuffer + uLength - cb802_1_H_len), cbFrameBodySize); + + pdwMIC_L = (PDWORD)(pbyBuffer + uLength - cb802_1_H_len + cbFrameBodySize); + pdwMIC_R = (PDWORD)(pbyBuffer + uLength - cb802_1_H_len + cbFrameBodySize + 4); + + MIC_vGetMIC(pdwMIC_L, pdwMIC_R); + MIC_vUnInit(); + + + if (pDevice->bTxMICFail == TRUE) { + *pdwMIC_L = 0; + *pdwMIC_R = 0; + pDevice->bTxMICFail = FALSE; + } + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"uLength: %d, %d\n", uLength, cbFrameBodySize); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"cbReqCount:%d, %d, %d, %d\n", cbReqCount, cbHeaderLength, uPadding, cbIVlen); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"MIC:%lx, %lx\n", *pdwMIC_L, *pdwMIC_R); +/* + for (ii = 0; ii < 8; ii++) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"%02x ", *(((PBYTE)(pdwMIC_L) + ii))); + } + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"\n"); +*/ + + } + + + if ((pDevice->byLocalID <= REV_ID_VT3253_A1)){ + if (bNeedEncrypt) { + s_vSWencryption(pDevice, pTransmitKey, (pbyBuffer + uLength - cb802_1_H_len), + (WORD)(cbFrameBodySize + cbMIClen)); + cbReqCount += cbICVlen; + } + } + + + ptdCurr = (PSTxDesc)pHeadTD; + + ptdCurr->pTDInfo->dwReqCount = cbReqCount - uPadding; + ptdCurr->pTDInfo->dwHeaderLength = cbHeaderLength; + ptdCurr->pTDInfo->skb_dma = ptdCurr->pTDInfo->buf_dma; + ptdCurr->buff_addr = cpu_to_le32(ptdCurr->pTDInfo->skb_dma); + //Set TSR1 & ReqCount in TxDescHead + ptdCurr->m_td1TD1.byTCR |= (TCR_STP | TCR_EDP | EDMSDU); + ptdCurr->m_td1TD1.wReqCount = cpu_to_le16((WORD)(cbReqCount)); + + pDevice->iTDUsed[uDMAIdx]++; + + +// DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO" ptdCurr->m_dwReserved0[%d] ptdCurr->m_dwReserved1[%d].\n", ptdCurr->pTDInfo->dwReqCount, ptdCurr->pTDInfo->dwHeaderLength); +// DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO" cbHeaderLength[%d]\n", cbHeaderLength); + + } + *puMACfragNum = uMACfragNum; + //DEVICE_PRTGRP03(("s_cbFillTxBufHead END\n")); + return cbHeaderLength; +} + + +VOID +vGenerateFIFOHeader ( + IN PSDevice pDevice, + IN BYTE byPktTyp, + IN PBYTE pbyTxBufferAddr, + IN BOOL bNeedEncrypt, + IN UINT cbPayloadSize, + IN UINT uDMAIdx, + IN PSTxDesc pHeadTD, + IN PSEthernetHeader psEthHeader, + IN PBYTE pPacket, + IN PSKeyItem pTransmitKey, + IN UINT uNodeIndex, + OUT PUINT puMACfragNum, + OUT PUINT pcbHeaderSize + ) +{ + UINT wTxBufSize; // FFinfo size + BOOL bNeedACK; + BOOL bIsAdhoc; + WORD cbMacHdLen; + PSTxBufHead pTxBufHead = (PSTxBufHead) pbyTxBufferAddr; + + wTxBufSize = sizeof(STxBufHead); + + ZERO_MEMORY(pTxBufHead, wTxBufSize); + //Set FIFOCTL_NEEDACK + + if ((pDevice->eOPMode == OP_MODE_ADHOC) || + (pDevice->eOPMode == OP_MODE_AP)) { + if (IS_MULTICAST_ADDRESS(&(psEthHeader->abyDstAddr[0])) || + IS_BROADCAST_ADDRESS(&(psEthHeader->abyDstAddr[0]))) { + bNeedACK = FALSE; + pTxBufHead->wFIFOCtl = pTxBufHead->wFIFOCtl & (~FIFOCTL_NEEDACK); + } + else { + bNeedACK = TRUE; + pTxBufHead->wFIFOCtl |= FIFOCTL_NEEDACK; + } + bIsAdhoc = TRUE; + } + else { + // MSDUs in Infra mode always need ACK + bNeedACK = TRUE; + pTxBufHead->wFIFOCtl |= FIFOCTL_NEEDACK; + bIsAdhoc = FALSE; + } + + + pTxBufHead->wFIFOCtl |= FIFOCTL_TMOEN; + pTxBufHead->wTimeStamp = cpu_to_le16(DEFAULT_MSDU_LIFETIME_RES_64us); + + //Set FIFOCTL_LHEAD + if (pDevice->bLongHeader) + pTxBufHead->wFIFOCtl |= FIFOCTL_LHEAD; + + //Set FIFOCTL_GENINT + + pTxBufHead->wFIFOCtl |= FIFOCTL_GENINT; + + + //Set FIFOCTL_ISDMA0 + if (TYPE_TXDMA0 == uDMAIdx) { + pTxBufHead->wFIFOCtl |= FIFOCTL_ISDMA0; + } + + //Set FRAGCTL_MACHDCNT + if (pDevice->bLongHeader) { + cbMacHdLen = WLAN_HDR_ADDR3_LEN + 6; + } else { + cbMacHdLen = WLAN_HDR_ADDR3_LEN; + } + pTxBufHead->wFragCtl |= cpu_to_le16((WORD)(cbMacHdLen << 10)); + + //Set packet type + if (byPktTyp == PK_TYPE_11A) {//0000 0000 0000 0000 + ; + } + else if (byPktTyp == PK_TYPE_11B) {//0000 0001 0000 0000 + pTxBufHead->wFIFOCtl |= FIFOCTL_11B; + } + else if (byPktTyp == PK_TYPE_11GB) {//0000 0010 0000 0000 + pTxBufHead->wFIFOCtl |= FIFOCTL_11GB; + } + else if (byPktTyp == PK_TYPE_11GA) {//0000 0011 0000 0000 + pTxBufHead->wFIFOCtl |= FIFOCTL_11GA; + } + //Set FIFOCTL_GrpAckPolicy + if (pDevice->bGrpAckPolicy == TRUE) {//0000 0100 0000 0000 + pTxBufHead->wFIFOCtl |= FIFOCTL_GRPACK; + } + + //Set Auto Fallback Ctl + if (pDevice->wCurrentRate >= RATE_18M) { + if (pDevice->byAutoFBCtrl == AUTO_FB_0) { + pTxBufHead->wFIFOCtl |= FIFOCTL_AUTO_FB_0; + } else if (pDevice->byAutoFBCtrl == AUTO_FB_1) { + pTxBufHead->wFIFOCtl |= FIFOCTL_AUTO_FB_1; + } + } + + //Set FRAGCTL_WEPTYP + pDevice->bAES = FALSE; + + //Set FRAGCTL_WEPTYP + if (pDevice->byLocalID > REV_ID_VT3253_A1) { + if ((bNeedEncrypt) && (pTransmitKey != NULL)) { //WEP enabled + if (pTransmitKey->byCipherSuite == KEY_CTL_TKIP) { + pTxBufHead->wFragCtl |= FRAGCTL_TKIP; + } + else if (pTransmitKey->byCipherSuite == KEY_CTL_WEP) { //WEP40 or WEP104 + if (pTransmitKey->uKeyLength != WLAN_WEP232_KEYLEN) + pTxBufHead->wFragCtl |= FRAGCTL_LEGACY; + } + else if (pTransmitKey->byCipherSuite == KEY_CTL_CCMP) { //CCMP + pTxBufHead->wFragCtl |= FRAGCTL_AES; + } + } + } + +#ifdef PLICE_DEBUG + //printk("Func:vGenerateFIFOHeader:TxDataRate is %d,TxPower is %d\n",pDevice->wCurrentRate,pDevice->byCurPwr); + + //if (pDevice->wCurrentRate <= 3) + //{ + // RFbRawSetPower(pDevice,36,pDevice->wCurrentRate); + //} + //else + + RFbSetPower(pDevice, pDevice->wCurrentRate, pDevice->byCurrentCh); +#endif + //if (pDevice->wCurrentRate == 3) + //pDevice->byCurPwr = 46; + pTxBufHead->byTxPower = pDevice->byCurPwr; + + + + +/* + if(pDevice->bEnableHostWEP) + pTxBufHead->wFragCtl &= ~(FRAGCTL_TKIP | FRAGCTL_LEGACY |FRAGCTL_AES); +*/ + *pcbHeaderSize = s_cbFillTxBufHead(pDevice, byPktTyp, pbyTxBufferAddr, cbPayloadSize, + uDMAIdx, pHeadTD, psEthHeader, pPacket, bNeedEncrypt, + pTransmitKey, uNodeIndex, puMACfragNum); + + return; +} + + + + +/*+ + * + * Description: + * Translate 802.3 to 802.11 header + * + * Parameters: + * In: + * pDevice - Pointer to adpater + * dwTxBufferAddr - Transmit Buffer + * pPacket - Packet from upper layer + * cbPacketSize - Transmit Data Length + * Out: + * pcbHeadSize - Header size of MAC&Baseband control and 802.11 Header + * pcbAppendPayload - size of append payload for 802.1H translation + * + * Return Value: none + * +-*/ + +VOID +vGenerateMACHeader ( + IN PSDevice pDevice, + IN PBYTE pbyBufferAddr, + IN WORD wDuration, + IN PSEthernetHeader psEthHeader, + IN BOOL bNeedEncrypt, + IN WORD wFragType, + IN UINT uDMAIdx, + IN UINT uFragIdx + ) +{ + PS802_11Header pMACHeader = (PS802_11Header)pbyBufferAddr; + + ZERO_MEMORY(pMACHeader, (sizeof(S802_11Header))); //- sizeof(pMACHeader->dwIV))); + + if (uDMAIdx == TYPE_ATIMDMA) { + pMACHeader->wFrameCtl = TYPE_802_11_ATIM; + } else { + pMACHeader->wFrameCtl = TYPE_802_11_DATA; + } + + if (pDevice->eOPMode == OP_MODE_AP) { + MEMvCopy(&(pMACHeader->abyAddr1[0]), &(psEthHeader->abyDstAddr[0]), U_ETHER_ADDR_LEN); + MEMvCopy(&(pMACHeader->abyAddr2[0]), &(pDevice->abyBSSID[0]), U_ETHER_ADDR_LEN); + MEMvCopy(&(pMACHeader->abyAddr3[0]), &(psEthHeader->abySrcAddr[0]), U_ETHER_ADDR_LEN); + pMACHeader->wFrameCtl |= FC_FROMDS; + } + else { + if (pDevice->eOPMode == OP_MODE_ADHOC) { + MEMvCopy(&(pMACHeader->abyAddr1[0]), &(psEthHeader->abyDstAddr[0]), U_ETHER_ADDR_LEN); + MEMvCopy(&(pMACHeader->abyAddr2[0]), &(psEthHeader->abySrcAddr[0]), U_ETHER_ADDR_LEN); + MEMvCopy(&(pMACHeader->abyAddr3[0]), &(pDevice->abyBSSID[0]), U_ETHER_ADDR_LEN); + } + else { + MEMvCopy(&(pMACHeader->abyAddr3[0]), &(psEthHeader->abyDstAddr[0]), U_ETHER_ADDR_LEN); + MEMvCopy(&(pMACHeader->abyAddr2[0]), &(psEthHeader->abySrcAddr[0]), U_ETHER_ADDR_LEN); + MEMvCopy(&(pMACHeader->abyAddr1[0]), &(pDevice->abyBSSID[0]), U_ETHER_ADDR_LEN); + pMACHeader->wFrameCtl |= FC_TODS; + } + } + + if (bNeedEncrypt) + pMACHeader->wFrameCtl |= cpu_to_le16((WORD)WLAN_SET_FC_ISWEP(1)); + + pMACHeader->wDurationID = cpu_to_le16(wDuration); + + if (pDevice->bLongHeader) { + PWLAN_80211HDR_A4 pMACA4Header = (PWLAN_80211HDR_A4) pbyBufferAddr; + pMACHeader->wFrameCtl |= (FC_TODS | FC_FROMDS); + MEMvCopy(pMACA4Header->abyAddr4, pDevice->abyBSSID, WLAN_ADDR_LEN); + } + pMACHeader->wSeqCtl = cpu_to_le16(pDevice->wSeqCounter << 4); + + //Set FragNumber in Sequence Control + pMACHeader->wSeqCtl |= cpu_to_le16((WORD)uFragIdx); + + if ((wFragType == FRAGCTL_ENDFRAG) || (wFragType == FRAGCTL_NONFRAG)) { + pDevice->wSeqCounter++; + if (pDevice->wSeqCounter > 0x0fff) + pDevice->wSeqCounter = 0; + } + + if ((wFragType == FRAGCTL_STAFRAG) || (wFragType == FRAGCTL_MIDFRAG)) { //StartFrag or MidFrag + pMACHeader->wFrameCtl |= FC_MOREFRAG; + } +} + + + + + + +CMD_STATUS csMgmt_xmit(PSDevice pDevice, PSTxMgmtPacket pPacket) { + + PSTxDesc pFrstTD; + BYTE byPktTyp; + PBYTE pbyTxBufferAddr; + PVOID pvRTS; + PSCTS pCTS; + PVOID pvTxDataHd; + UINT uDuration; + UINT cbReqCount; + PS802_11Header pMACHeader; + UINT cbHeaderSize; + UINT cbFrameBodySize; + BOOL bNeedACK; + BOOL bIsPSPOLL = FALSE; + PSTxBufHead pTxBufHead; + UINT cbFrameSize; + UINT cbIVlen = 0; + UINT cbICVlen = 0; + UINT cbMIClen = 0; + UINT cbFCSlen = 4; + UINT uPadding = 0; + WORD wTxBufSize; + UINT cbMacHdLen; + SEthernetHeader sEthHeader; + PVOID pvRrvTime; + PVOID pMICHDR; + PSMgmtObject pMgmt = pDevice->pMgmt; + WORD wCurrentRate = RATE_1M; + + + if (AVAIL_TD(pDevice, TYPE_TXDMA0) <= 0) { + return CMD_STATUS_RESOURCES; + } + + pFrstTD = pDevice->apCurrTD[TYPE_TXDMA0]; + pbyTxBufferAddr = (PBYTE)pFrstTD->pTDInfo->buf; + cbFrameBodySize = pPacket->cbPayloadLen; + pTxBufHead = (PSTxBufHead) pbyTxBufferAddr; + wTxBufSize = sizeof(STxBufHead); + memset(pTxBufHead, 0, wTxBufSize); + + if (pDevice->eCurrentPHYType == PHY_TYPE_11A) { + wCurrentRate = RATE_6M; + byPktTyp = PK_TYPE_11A; + } else { + wCurrentRate = RATE_1M; + byPktTyp = PK_TYPE_11B; + } + + // SetPower will cause error power TX state for OFDM Date packet in TX buffer. + // 2004.11.11 Kyle -- Using OFDM power to tx MngPkt will decrease the connection capability. + // And cmd timer will wait data pkt TX finish before scanning so it's OK + // to set power here. + if (pDevice->pMgmt->eScanState != WMAC_NO_SCANNING) { + + RFbSetPower(pDevice, wCurrentRate, pDevice->byCurrentCh); + } else { + RFbSetPower(pDevice, wCurrentRate, pMgmt->uCurrChannel); + } + pTxBufHead->byTxPower = pDevice->byCurPwr; + //+++++++++++++++++++++ Patch VT3253 A1 performance +++++++++++++++++++++++++++ + if (pDevice->byFOETuning) { + if ((pPacket->p80211Header->sA3.wFrameCtl & TYPE_DATE_NULL) == TYPE_DATE_NULL) { + wCurrentRate = RATE_24M; + byPktTyp = PK_TYPE_11GA; + } + } + + //Set packet type + if (byPktTyp == PK_TYPE_11A) {//0000 0000 0000 0000 + pTxBufHead->wFIFOCtl = 0; + } + else if (byPktTyp == PK_TYPE_11B) {//0000 0001 0000 0000 + pTxBufHead->wFIFOCtl |= FIFOCTL_11B; + } + else if (byPktTyp == PK_TYPE_11GB) {//0000 0010 0000 0000 + pTxBufHead->wFIFOCtl |= FIFOCTL_11GB; + } + else if (byPktTyp == PK_TYPE_11GA) {//0000 0011 0000 0000 + pTxBufHead->wFIFOCtl |= FIFOCTL_11GA; + } + + pTxBufHead->wFIFOCtl |= FIFOCTL_TMOEN; + pTxBufHead->wTimeStamp = cpu_to_le16(DEFAULT_MGN_LIFETIME_RES_64us); + + + if (IS_MULTICAST_ADDRESS(&(pPacket->p80211Header->sA3.abyAddr1[0])) || + IS_BROADCAST_ADDRESS(&(pPacket->p80211Header->sA3.abyAddr1[0]))) { + bNeedACK = FALSE; + } + else { + bNeedACK = TRUE; + pTxBufHead->wFIFOCtl |= FIFOCTL_NEEDACK; + }; + + if ((pMgmt->eCurrMode == WMAC_MODE_ESS_AP) || + (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) ) { + + pTxBufHead->wFIFOCtl |= FIFOCTL_LRETRY; + //Set Preamble type always long + //pDevice->byPreambleType = PREAMBLE_LONG; + // probe-response don't retry + //if ((pPacket->p80211Header->sA4.wFrameCtl & TYPE_SUBTYPE_MASK) == TYPE_MGMT_PROBE_RSP) { + // bNeedACK = FALSE; + // pTxBufHead->wFIFOCtl &= (~FIFOCTL_NEEDACK); + //} + } + + pTxBufHead->wFIFOCtl |= (FIFOCTL_GENINT | FIFOCTL_ISDMA0); + + if ((pPacket->p80211Header->sA4.wFrameCtl & TYPE_SUBTYPE_MASK) == TYPE_CTL_PSPOLL) { + bIsPSPOLL = TRUE; + cbMacHdLen = WLAN_HDR_ADDR2_LEN; + } else { + cbMacHdLen = WLAN_HDR_ADDR3_LEN; + } + + //Set FRAGCTL_MACHDCNT + pTxBufHead->wFragCtl |= cpu_to_le16((WORD)(cbMacHdLen << 10)); + + // Notes: + // Although spec says MMPDU can be fragmented; In most case, + // no one will send a MMPDU under fragmentation. With RTS may occur. + pDevice->bAES = FALSE; //Set FRAGCTL_WEPTYP + + if (WLAN_GET_FC_ISWEP(pPacket->p80211Header->sA4.wFrameCtl) != 0) { + if (pDevice->eEncryptionStatus == Ndis802_11Encryption1Enabled) { + cbIVlen = 4; + cbICVlen = 4; + pTxBufHead->wFragCtl |= FRAGCTL_LEGACY; + } + else if (pDevice->eEncryptionStatus == Ndis802_11Encryption2Enabled) { + cbIVlen = 8;//IV+ExtIV + cbMIClen = 8; + cbICVlen = 4; + pTxBufHead->wFragCtl |= FRAGCTL_TKIP; + //We need to get seed here for filling TxKey entry. + //TKIPvMixKey(pTransmitKey->abyKey, pDevice->abyCurrentNetAddr, + // pTransmitKey->wTSC15_0, pTransmitKey->dwTSC47_16, pDevice->abyPRNG); + } + else if (pDevice->eEncryptionStatus == Ndis802_11Encryption3Enabled) { + cbIVlen = 8;//RSN Header + cbICVlen = 8;//MIC + pTxBufHead->wFragCtl |= FRAGCTL_AES; + pDevice->bAES = TRUE; + } + //MAC Header should be padding 0 to DW alignment. + uPadding = 4 - (cbMacHdLen%4); + uPadding %= 4; + } + + cbFrameSize = cbMacHdLen + cbFrameBodySize + cbIVlen + cbMIClen + cbICVlen + cbFCSlen; + + //Set FIFOCTL_GrpAckPolicy + if (pDevice->bGrpAckPolicy == TRUE) {//0000 0100 0000 0000 + pTxBufHead->wFIFOCtl |= FIFOCTL_GRPACK; + } + //the rest of pTxBufHead->wFragCtl:FragTyp will be set later in s_vFillFragParameter() + + //Set RrvTime/RTS/CTS Buffer + if (byPktTyp == PK_TYPE_11GB || byPktTyp == PK_TYPE_11GA) {//802.11g packet + + pvRrvTime = (PSRrvTime_gCTS) (pbyTxBufferAddr + wTxBufSize); + pMICHDR = NULL; + pvRTS = NULL; + pCTS = (PSCTS) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS)); + pvTxDataHd = (PSTxDataHead_g) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS) + sizeof(SCTS)); + cbHeaderSize = wTxBufSize + sizeof(SRrvTime_gCTS) + sizeof(SCTS) + sizeof(STxDataHead_g); + } + else { // 802.11a/b packet + pvRrvTime = (PSRrvTime_ab) (pbyTxBufferAddr + wTxBufSize); + pMICHDR = NULL; + pvRTS = NULL; + pCTS = NULL; + pvTxDataHd = (PSTxDataHead_ab) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab)); + cbHeaderSize = wTxBufSize + sizeof(SRrvTime_ab) + sizeof(STxDataHead_ab); + } + + ZERO_MEMORY((PVOID)(pbyTxBufferAddr + wTxBufSize), (cbHeaderSize - wTxBufSize)); + + MEMvCopy(&(sEthHeader.abyDstAddr[0]), &(pPacket->p80211Header->sA3.abyAddr1[0]), U_ETHER_ADDR_LEN); + MEMvCopy(&(sEthHeader.abySrcAddr[0]), &(pPacket->p80211Header->sA3.abyAddr2[0]), U_ETHER_ADDR_LEN); + //========================= + // No Fragmentation + //========================= + pTxBufHead->wFragCtl |= (WORD)FRAGCTL_NONFRAG; + + + //Fill FIFO,RrvTime,RTS,and CTS + s_vGenerateTxParameter(pDevice, byPktTyp, pbyTxBufferAddr, pvRrvTime, pvRTS, pCTS, + cbFrameSize, bNeedACK, TYPE_TXDMA0, &sEthHeader, wCurrentRate); + + //Fill DataHead + uDuration = s_uFillDataHead(pDevice, byPktTyp, pvTxDataHd, cbFrameSize, TYPE_TXDMA0, bNeedACK, + 0, 0, 1, AUTO_FB_NONE, wCurrentRate); + + pMACHeader = (PS802_11Header) (pbyTxBufferAddr + cbHeaderSize); + + cbReqCount = cbHeaderSize + cbMacHdLen + uPadding + cbIVlen + cbFrameBodySize; + + if (WLAN_GET_FC_ISWEP(pPacket->p80211Header->sA4.wFrameCtl) != 0) { + PBYTE pbyIVHead; + PBYTE pbyPayloadHead; + PBYTE pbyBSSID; + PSKeyItem pTransmitKey = NULL; + + pbyIVHead = (PBYTE)(pbyTxBufferAddr + cbHeaderSize + cbMacHdLen + uPadding); + pbyPayloadHead = (PBYTE)(pbyTxBufferAddr + cbHeaderSize + cbMacHdLen + uPadding + cbIVlen); + + //Fill TXKEY + //Kyle: Need fix: TKIP and AES did't encryt Mnt Packet. + //s_vFillTxKey(pDevice, (PBYTE)pTxBufHead->adwTxKey, NULL); + + //Fill IV(ExtIV,RSNHDR) + //s_vFillPrePayload(pDevice, pbyIVHead, NULL); + //--------------------------- + // S/W or H/W Encryption + //--------------------------- + //Fill MICHDR + //if (pDevice->bAES) { + // s_vFillMICHDR(pDevice, (PBYTE)pMICHDR, (PBYTE)pMACHeader, (WORD)cbFrameBodySize); + //} + do { + if ((pDevice->eOPMode == OP_MODE_INFRASTRUCTURE) && + (pDevice->bLinkPass == TRUE)) { + pbyBSSID = pDevice->abyBSSID; + // get pairwise key + if (KeybGetTransmitKey(&(pDevice->sKey), pbyBSSID, PAIRWISE_KEY, &pTransmitKey) == FALSE) { + // get group key + if(KeybGetTransmitKey(&(pDevice->sKey), pbyBSSID, GROUP_KEY, &pTransmitKey) == TRUE) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Get GTK.\n"); + break; + } + } else { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Get PTK.\n"); + break; + } + } + // get group key + pbyBSSID = pDevice->abyBroadcastAddr; + if(KeybGetTransmitKey(&(pDevice->sKey), pbyBSSID, GROUP_KEY, &pTransmitKey) == FALSE) { + pTransmitKey = NULL; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"KEY is NULL. OP Mode[%d]\n", pDevice->eOPMode); + } else { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Get GTK.\n"); + } + } while(FALSE); + //Fill TXKEY + s_vFillTxKey(pDevice, (PBYTE)(pTxBufHead->adwTxKey), pbyIVHead, pTransmitKey, + (PBYTE)pMACHeader, (WORD)cbFrameBodySize, NULL); + + MEMvCopy(pMACHeader, pPacket->p80211Header, cbMacHdLen); + MEMvCopy(pbyPayloadHead, ((PBYTE)(pPacket->p80211Header) + cbMacHdLen), + cbFrameBodySize); + } + else { + // Copy the Packet into a tx Buffer + MEMvCopy(pMACHeader, pPacket->p80211Header, pPacket->cbMPDULen); + } + + pMACHeader->wSeqCtl = cpu_to_le16(pDevice->wSeqCounter << 4); + pDevice->wSeqCounter++ ; + if (pDevice->wSeqCounter > 0x0fff) + pDevice->wSeqCounter = 0; + + if (bIsPSPOLL) { + // The MAC will automatically replace the Duration-field of MAC header by Duration-field + // of FIFO control header. + // This will cause AID-field of PS-POLL packet be incorrect (Because PS-POLL's AID field is + // in the same place of other packet's Duration-field). + // And it will cause Cisco-AP to issue Disassociation-packet + if (byPktTyp == PK_TYPE_11GB || byPktTyp == PK_TYPE_11GA) { + ((PSTxDataHead_g)pvTxDataHd)->wDuration_a = cpu_to_le16(pPacket->p80211Header->sA2.wDurationID); + ((PSTxDataHead_g)pvTxDataHd)->wDuration_b = cpu_to_le16(pPacket->p80211Header->sA2.wDurationID); + } else { + ((PSTxDataHead_ab)pvTxDataHd)->wDuration = cpu_to_le16(pPacket->p80211Header->sA2.wDurationID); + } + } + + + // first TD is the only TD + //Set TSR1 & ReqCount in TxDescHead + pFrstTD->m_td1TD1.byTCR = (TCR_STP | TCR_EDP | EDMSDU); + pFrstTD->pTDInfo->skb_dma = pFrstTD->pTDInfo->buf_dma; + pFrstTD->m_td1TD1.wReqCount = cpu_to_le16((WORD)(cbReqCount)); + pFrstTD->buff_addr = cpu_to_le32(pFrstTD->pTDInfo->skb_dma); + pFrstTD->pTDInfo->byFlags = 0; + + if (MACbIsRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_PS)) { + // Disable PS + MACbPSWakeup(pDevice->PortOffset); + } + pDevice->bPWBitOn = FALSE; + + wmb(); + pFrstTD->m_td0TD0.f1Owner = OWNED_BY_NIC; + wmb(); + + pDevice->iTDUsed[TYPE_TXDMA0]++; + + if (AVAIL_TD(pDevice, TYPE_TXDMA0) <= 1) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " available td0 <= 1\n"); + } + + pDevice->apCurrTD[TYPE_TXDMA0] = pFrstTD->next; +#ifdef PLICE_DEBUG + //printk("SCAN:CurrentRate is %d,TxPower is %d\n",wCurrentRate,pTxBufHead->byTxPower); +#endif + +#ifdef TxInSleep + pDevice->nTxDataTimeCout=0; //2008-8-21 chester for send null packet + #endif + + // Poll Transmit the adapter + MACvTransmit0(pDevice->PortOffset); + + return CMD_STATUS_PENDING; + +} + + +CMD_STATUS csBeacon_xmit(PSDevice pDevice, PSTxMgmtPacket pPacket) { + + BYTE byPktTyp; + PBYTE pbyBuffer = (PBYTE)pDevice->tx_beacon_bufs; + UINT cbFrameSize = pPacket->cbMPDULen + WLAN_FCS_LEN; + UINT cbHeaderSize = 0; + WORD wTxBufSize = sizeof(STxShortBufHead); + PSTxShortBufHead pTxBufHead = (PSTxShortBufHead) pbyBuffer; + PSTxDataHead_ab pTxDataHead = (PSTxDataHead_ab) (pbyBuffer + wTxBufSize); + PS802_11Header pMACHeader; + WORD wCurrentRate; + WORD wLen = 0x0000; + + + memset(pTxBufHead, 0, wTxBufSize); + + if (pDevice->eCurrentPHYType == PHY_TYPE_11A) { + wCurrentRate = RATE_6M; + byPktTyp = PK_TYPE_11A; + } else { + wCurrentRate = RATE_2M; + byPktTyp = PK_TYPE_11B; + } + + //Set Preamble type always long + pDevice->byPreambleType = PREAMBLE_LONG; + + //Set FIFOCTL_GENINT + + pTxBufHead->wFIFOCtl |= FIFOCTL_GENINT; + + + //Set packet type & Get Duration + if (byPktTyp == PK_TYPE_11A) {//0000 0000 0000 0000 + pTxDataHead->wDuration = cpu_to_le16((WORD)s_uGetDataDuration(pDevice, DATADUR_A, cbFrameSize, byPktTyp, + wCurrentRate, FALSE, 0, 0, 1, AUTO_FB_NONE)); + } + else if (byPktTyp == PK_TYPE_11B) {//0000 0001 0000 0000 + pTxBufHead->wFIFOCtl |= FIFOCTL_11B; + pTxDataHead->wDuration = cpu_to_le16((WORD)s_uGetDataDuration(pDevice, DATADUR_B, cbFrameSize, byPktTyp, + wCurrentRate, FALSE, 0, 0, 1, AUTO_FB_NONE)); + } + + BBvCaculateParameter(pDevice, cbFrameSize, wCurrentRate, byPktTyp, + (PWORD)&(wLen), (PBYTE)&(pTxDataHead->byServiceField), (PBYTE)&(pTxDataHead->bySignalField) + ); + pTxDataHead->wTransmitLength = cpu_to_le16(wLen); + //Get TimeStampOff + pTxDataHead->wTimeStampOff = cpu_to_le16(wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE]); + cbHeaderSize = wTxBufSize + sizeof(STxDataHead_ab); + + //Generate Beacon Header + pMACHeader = (PS802_11Header)(pbyBuffer + cbHeaderSize); + MEMvCopy(pMACHeader, pPacket->p80211Header, pPacket->cbMPDULen); + + pMACHeader->wDurationID = 0; + pMACHeader->wSeqCtl = cpu_to_le16(pDevice->wSeqCounter << 4); + pDevice->wSeqCounter++ ; + if (pDevice->wSeqCounter > 0x0fff) + pDevice->wSeqCounter = 0; + + // Set Beacon buffer length + pDevice->wBCNBufLen = pPacket->cbMPDULen + cbHeaderSize; + + MACvSetCurrBCNTxDescAddr(pDevice->PortOffset, (pDevice->tx_beacon_dma)); + + MACvSetCurrBCNLength(pDevice->PortOffset, pDevice->wBCNBufLen); + // Set auto Transmit on + MACvRegBitsOn(pDevice->PortOffset, MAC_REG_TCR, TCR_AUTOBCNTX); + // Poll Transmit the adapter + MACvTransmitBCN(pDevice->PortOffset); + + return CMD_STATUS_PENDING; +} + + + +UINT +cbGetFragCount ( + IN PSDevice pDevice, + IN PSKeyItem pTransmitKey, + IN UINT cbFrameBodySize, + IN PSEthernetHeader psEthHeader + ) +{ + UINT cbMACHdLen; + UINT cbFrameSize; + UINT cbFragmentSize; //Hdr+(IV)+payoad+(MIC)+(ICV)+FCS + UINT cbFragPayloadSize; + UINT cbLastFragPayloadSize; + UINT cbIVlen = 0; + UINT cbICVlen = 0; + UINT cbMIClen = 0; + UINT cbFCSlen = 4; + UINT uMACfragNum = 1; + BOOL bNeedACK; + + + + if ((pDevice->eOPMode == OP_MODE_ADHOC) || + (pDevice->eOPMode == OP_MODE_AP)) { + if (IS_MULTICAST_ADDRESS(&(psEthHeader->abyDstAddr[0])) || + IS_BROADCAST_ADDRESS(&(psEthHeader->abyDstAddr[0]))) { + bNeedACK = FALSE; + } + else { + bNeedACK = TRUE; + } + } + else { + // MSDUs in Infra mode always need ACK + bNeedACK = TRUE; + } + + if (pDevice->bLongHeader) + cbMACHdLen = WLAN_HDR_ADDR3_LEN + 6; + else + cbMACHdLen = WLAN_HDR_ADDR3_LEN; + + + if (pDevice->bEncryptionEnable == TRUE) { + + if (pTransmitKey == NULL) { + if ((pDevice->eEncryptionStatus == Ndis802_11Encryption1Enabled) || + (pDevice->pMgmt->eAuthenMode < WMAC_AUTH_WPA)) { + cbIVlen = 4; + cbICVlen = 4; + } else if (pDevice->eEncryptionStatus == Ndis802_11Encryption2Enabled) { + cbIVlen = 8;//IV+ExtIV + cbMIClen = 8; + cbICVlen = 4; + } else if (pDevice->eEncryptionStatus == Ndis802_11Encryption3Enabled) { + cbIVlen = 8;//RSN Header + cbICVlen = 8;//MIC + } + } else if (pTransmitKey->byCipherSuite == KEY_CTL_WEP) { + cbIVlen = 4; + cbICVlen = 4; + } else if (pTransmitKey->byCipherSuite == KEY_CTL_TKIP) { + cbIVlen = 8;//IV+ExtIV + cbMIClen = 8; + cbICVlen = 4; + } else if (pTransmitKey->byCipherSuite == KEY_CTL_CCMP) { + cbIVlen = 8;//RSN Header + cbICVlen = 8;//MIC + } + } + + cbFrameSize = cbMACHdLen + cbIVlen + (cbFrameBodySize + cbMIClen) + cbICVlen + cbFCSlen; + + if ((cbFrameSize > pDevice->wFragmentationThreshold) && (bNeedACK == TRUE)) { + // Fragmentation + cbFragmentSize = pDevice->wFragmentationThreshold; + cbFragPayloadSize = cbFragmentSize - cbMACHdLen - cbIVlen - cbICVlen - cbFCSlen; + uMACfragNum = (WORD) ((cbFrameBodySize + cbMIClen) / cbFragPayloadSize); + cbLastFragPayloadSize = (cbFrameBodySize + cbMIClen) % cbFragPayloadSize; + if (cbLastFragPayloadSize == 0) { + cbLastFragPayloadSize = cbFragPayloadSize; + } else { + uMACfragNum++; + } + } + return uMACfragNum; +} + + +VOID +vDMA0_tx_80211(PSDevice pDevice, struct sk_buff *skb, PBYTE pbMPDU, UINT cbMPDULen) { + + PSTxDesc pFrstTD; + BYTE byPktTyp; + PBYTE pbyTxBufferAddr; + PVOID pvRTS; + PVOID pvCTS; + PVOID pvTxDataHd; + UINT uDuration; + UINT cbReqCount; + PS802_11Header pMACHeader; + UINT cbHeaderSize; + UINT cbFrameBodySize; + BOOL bNeedACK; + BOOL bIsPSPOLL = FALSE; + PSTxBufHead pTxBufHead; + UINT cbFrameSize; + UINT cbIVlen = 0; + UINT cbICVlen = 0; + UINT cbMIClen = 0; + UINT cbFCSlen = 4; + UINT uPadding = 0; + UINT cbMICHDR = 0; + UINT uLength = 0; + DWORD dwMICKey0, dwMICKey1; + DWORD dwMIC_Priority; + PDWORD pdwMIC_L; + PDWORD pdwMIC_R; + WORD wTxBufSize; + UINT cbMacHdLen; + SEthernetHeader sEthHeader; + PVOID pvRrvTime; + PVOID pMICHDR; + PSMgmtObject pMgmt = pDevice->pMgmt; + WORD wCurrentRate = RATE_1M; + PUWLAN_80211HDR p80211Header; + UINT uNodeIndex = 0; + BOOL bNodeExist = FALSE; + SKeyItem STempKey; + PSKeyItem pTransmitKey = NULL; + PBYTE pbyIVHead; + PBYTE pbyPayloadHead; + PBYTE pbyMacHdr; + + UINT cbExtSuppRate = 0; +// PWLAN_IE pItem; + + + pvRrvTime = pMICHDR = pvRTS = pvCTS = pvTxDataHd = NULL; + + if(cbMPDULen <= WLAN_HDR_ADDR3_LEN) { + cbFrameBodySize = 0; + } + else { + cbFrameBodySize = cbMPDULen - WLAN_HDR_ADDR3_LEN; + } + p80211Header = (PUWLAN_80211HDR)pbMPDU; + + + pFrstTD = pDevice->apCurrTD[TYPE_TXDMA0]; + pbyTxBufferAddr = (PBYTE)pFrstTD->pTDInfo->buf; + pTxBufHead = (PSTxBufHead) pbyTxBufferAddr; + wTxBufSize = sizeof(STxBufHead); + memset(pTxBufHead, 0, wTxBufSize); + + if (pDevice->eCurrentPHYType == PHY_TYPE_11A) { + wCurrentRate = RATE_6M; + byPktTyp = PK_TYPE_11A; + } else { + wCurrentRate = RATE_1M; + byPktTyp = PK_TYPE_11B; + } + + // SetPower will cause error power TX state for OFDM Date packet in TX buffer. + // 2004.11.11 Kyle -- Using OFDM power to tx MngPkt will decrease the connection capability. + // And cmd timer will wait data pkt TX finish before scanning so it's OK + // to set power here. + if (pDevice->pMgmt->eScanState != WMAC_NO_SCANNING) { + RFbSetPower(pDevice, wCurrentRate, pDevice->byCurrentCh); + } else { + RFbSetPower(pDevice, wCurrentRate, pMgmt->uCurrChannel); + } + pTxBufHead->byTxPower = pDevice->byCurPwr; + + //+++++++++++++++++++++ Patch VT3253 A1 performance +++++++++++++++++++++++++++ + if (pDevice->byFOETuning) { + if ((p80211Header->sA3.wFrameCtl & TYPE_DATE_NULL) == TYPE_DATE_NULL) { + wCurrentRate = RATE_24M; + byPktTyp = PK_TYPE_11GA; + } + } + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"vDMA0_tx_80211: p80211Header->sA3.wFrameCtl = %x \n", p80211Header->sA3.wFrameCtl); + + //Set packet type + if (byPktTyp == PK_TYPE_11A) {//0000 0000 0000 0000 + pTxBufHead->wFIFOCtl = 0; + } + else if (byPktTyp == PK_TYPE_11B) {//0000 0001 0000 0000 + pTxBufHead->wFIFOCtl |= FIFOCTL_11B; + } + else if (byPktTyp == PK_TYPE_11GB) {//0000 0010 0000 0000 + pTxBufHead->wFIFOCtl |= FIFOCTL_11GB; + } + else if (byPktTyp == PK_TYPE_11GA) {//0000 0011 0000 0000 + pTxBufHead->wFIFOCtl |= FIFOCTL_11GA; + } + + pTxBufHead->wFIFOCtl |= FIFOCTL_TMOEN; + pTxBufHead->wTimeStamp = cpu_to_le16(DEFAULT_MGN_LIFETIME_RES_64us); + + + if (IS_MULTICAST_ADDRESS(&(p80211Header->sA3.abyAddr1[0])) || + IS_BROADCAST_ADDRESS(&(p80211Header->sA3.abyAddr1[0]))) { + bNeedACK = FALSE; + if (pDevice->bEnableHostWEP) { + uNodeIndex = 0; + bNodeExist = TRUE; + }; + } + else { + if (pDevice->bEnableHostWEP) { + if (BSSDBbIsSTAInNodeDB(pDevice->pMgmt, (PBYTE)(p80211Header->sA3.abyAddr1), &uNodeIndex)) + bNodeExist = TRUE; + }; + bNeedACK = TRUE; + pTxBufHead->wFIFOCtl |= FIFOCTL_NEEDACK; + }; + + if ((pMgmt->eCurrMode == WMAC_MODE_ESS_AP) || + (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) ) { + + pTxBufHead->wFIFOCtl |= FIFOCTL_LRETRY; + //Set Preamble type always long + //pDevice->byPreambleType = PREAMBLE_LONG; + + // probe-response don't retry + //if ((p80211Header->sA4.wFrameCtl & TYPE_SUBTYPE_MASK) == TYPE_MGMT_PROBE_RSP) { + // bNeedACK = FALSE; + // pTxBufHead->wFIFOCtl &= (~FIFOCTL_NEEDACK); + //} + } + + pTxBufHead->wFIFOCtl |= (FIFOCTL_GENINT | FIFOCTL_ISDMA0); + + if ((p80211Header->sA4.wFrameCtl & TYPE_SUBTYPE_MASK) == TYPE_CTL_PSPOLL) { + bIsPSPOLL = TRUE; + cbMacHdLen = WLAN_HDR_ADDR2_LEN; + } else { + cbMacHdLen = WLAN_HDR_ADDR3_LEN; + } + + // hostapd deamon ext support rate patch + if (WLAN_GET_FC_FSTYPE(p80211Header->sA4.wFrameCtl) == WLAN_FSTYPE_ASSOCRESP) { + + if (((PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates)->len != 0) { + cbExtSuppRate += ((PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates)->len + WLAN_IEHDR_LEN; + } + + if (((PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates)->len != 0) { + cbExtSuppRate += ((PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates)->len + WLAN_IEHDR_LEN; + } + + if (cbExtSuppRate >0) { + cbFrameBodySize = WLAN_ASSOCRESP_OFF_SUPP_RATES; + } + } + + + //Set FRAGCTL_MACHDCNT + pTxBufHead->wFragCtl |= cpu_to_le16((WORD)cbMacHdLen << 10); + + // Notes: + // Although spec says MMPDU can be fragmented; In most case, + // no one will send a MMPDU under fragmentation. With RTS may occur. + pDevice->bAES = FALSE; //Set FRAGCTL_WEPTYP + + + if (WLAN_GET_FC_ISWEP(p80211Header->sA4.wFrameCtl) != 0) { + if (pDevice->eEncryptionStatus == Ndis802_11Encryption1Enabled) { + cbIVlen = 4; + cbICVlen = 4; + pTxBufHead->wFragCtl |= FRAGCTL_LEGACY; + } + else if (pDevice->eEncryptionStatus == Ndis802_11Encryption2Enabled) { + cbIVlen = 8;//IV+ExtIV + cbMIClen = 8; + cbICVlen = 4; + pTxBufHead->wFragCtl |= FRAGCTL_TKIP; + //We need to get seed here for filling TxKey entry. + //TKIPvMixKey(pTransmitKey->abyKey, pDevice->abyCurrentNetAddr, + // pTransmitKey->wTSC15_0, pTransmitKey->dwTSC47_16, pDevice->abyPRNG); + } + else if (pDevice->eEncryptionStatus == Ndis802_11Encryption3Enabled) { + cbIVlen = 8;//RSN Header + cbICVlen = 8;//MIC + cbMICHDR = sizeof(SMICHDRHead); + pTxBufHead->wFragCtl |= FRAGCTL_AES; + pDevice->bAES = TRUE; + } + //MAC Header should be padding 0 to DW alignment. + uPadding = 4 - (cbMacHdLen%4); + uPadding %= 4; + } + + cbFrameSize = cbMacHdLen + cbFrameBodySize + cbIVlen + cbMIClen + cbICVlen + cbFCSlen + cbExtSuppRate; + + //Set FIFOCTL_GrpAckPolicy + if (pDevice->bGrpAckPolicy == TRUE) {//0000 0100 0000 0000 + pTxBufHead->wFIFOCtl |= FIFOCTL_GRPACK; + } + //the rest of pTxBufHead->wFragCtl:FragTyp will be set later in s_vFillFragParameter() + + + if (byPktTyp == PK_TYPE_11GB || byPktTyp == PK_TYPE_11GA) {//802.11g packet + + pvRrvTime = (PSRrvTime_gCTS) (pbyTxBufferAddr + wTxBufSize); + pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS)); + pvRTS = NULL; + pvCTS = (PSCTS) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS) + cbMICHDR); + pvTxDataHd = (PSTxDataHead_g) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS) + cbMICHDR + sizeof(SCTS)); + cbHeaderSize = wTxBufSize + sizeof(SRrvTime_gCTS) + cbMICHDR + sizeof(SCTS) + sizeof(STxDataHead_g); + + } + else {//802.11a/b packet + + pvRrvTime = (PSRrvTime_ab) (pbyTxBufferAddr + wTxBufSize); + pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab)); + pvRTS = NULL; + pvCTS = NULL; + pvTxDataHd = (PSTxDataHead_ab) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab) + cbMICHDR); + cbHeaderSize = wTxBufSize + sizeof(SRrvTime_ab) + cbMICHDR + sizeof(STxDataHead_ab); + + } + + ZERO_MEMORY((PVOID)(pbyTxBufferAddr + wTxBufSize), (cbHeaderSize - wTxBufSize)); + MEMvCopy(&(sEthHeader.abyDstAddr[0]), &(p80211Header->sA3.abyAddr1[0]), U_ETHER_ADDR_LEN); + MEMvCopy(&(sEthHeader.abySrcAddr[0]), &(p80211Header->sA3.abyAddr2[0]), U_ETHER_ADDR_LEN); + //========================= + // No Fragmentation + //========================= + pTxBufHead->wFragCtl |= (WORD)FRAGCTL_NONFRAG; + + + //Fill FIFO,RrvTime,RTS,and CTS + s_vGenerateTxParameter(pDevice, byPktTyp, pbyTxBufferAddr, pvRrvTime, pvRTS, pvCTS, + cbFrameSize, bNeedACK, TYPE_TXDMA0, &sEthHeader, wCurrentRate); + + //Fill DataHead + uDuration = s_uFillDataHead(pDevice, byPktTyp, pvTxDataHd, cbFrameSize, TYPE_TXDMA0, bNeedACK, + 0, 0, 1, AUTO_FB_NONE, wCurrentRate); + + pMACHeader = (PS802_11Header) (pbyTxBufferAddr + cbHeaderSize); + + cbReqCount = cbHeaderSize + cbMacHdLen + uPadding + cbIVlen + (cbFrameBodySize + cbMIClen) + cbExtSuppRate; + + pbyMacHdr = (PBYTE)(pbyTxBufferAddr + cbHeaderSize); + pbyPayloadHead = (PBYTE)(pbyMacHdr + cbMacHdLen + uPadding + cbIVlen); + pbyIVHead = (PBYTE)(pbyMacHdr + cbMacHdLen + uPadding); + + // Copy the Packet into a tx Buffer + memcpy(pbyMacHdr, pbMPDU, cbMacHdLen); + + // version set to 0, patch for hostapd deamon + pMACHeader->wFrameCtl &= cpu_to_le16(0xfffc); + memcpy(pbyPayloadHead, (pbMPDU + cbMacHdLen), cbFrameBodySize); + + // replace support rate, patch for hostapd deamon( only support 11M) + if (WLAN_GET_FC_FSTYPE(p80211Header->sA4.wFrameCtl) == WLAN_FSTYPE_ASSOCRESP) { + if (cbExtSuppRate != 0) { + if (((PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates)->len != 0) + memcpy((pbyPayloadHead + cbFrameBodySize), + pMgmt->abyCurrSuppRates, + ((PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates)->len + WLAN_IEHDR_LEN + ); + if (((PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates)->len != 0) + memcpy((pbyPayloadHead + cbFrameBodySize) + ((PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates)->len + WLAN_IEHDR_LEN, + pMgmt->abyCurrExtSuppRates, + ((PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates)->len + WLAN_IEHDR_LEN + ); + } + } + + // Set wep + if (WLAN_GET_FC_ISWEP(p80211Header->sA4.wFrameCtl) != 0) { + + if (pDevice->bEnableHostWEP) { + pTransmitKey = &STempKey; + pTransmitKey->byCipherSuite = pMgmt->sNodeDBTable[uNodeIndex].byCipherSuite; + pTransmitKey->dwKeyIndex = pMgmt->sNodeDBTable[uNodeIndex].dwKeyIndex; + pTransmitKey->uKeyLength = pMgmt->sNodeDBTable[uNodeIndex].uWepKeyLength; + pTransmitKey->dwTSC47_16 = pMgmt->sNodeDBTable[uNodeIndex].dwTSC47_16; + pTransmitKey->wTSC15_0 = pMgmt->sNodeDBTable[uNodeIndex].wTSC15_0; + memcpy(pTransmitKey->abyKey, + &pMgmt->sNodeDBTable[uNodeIndex].abyWepKey[0], + pTransmitKey->uKeyLength + ); + } + + if ((pTransmitKey != NULL) && (pTransmitKey->byCipherSuite == KEY_CTL_TKIP)) { + + dwMICKey0 = *(PDWORD)(&pTransmitKey->abyKey[16]); + dwMICKey1 = *(PDWORD)(&pTransmitKey->abyKey[20]); + + // DO Software Michael + MIC_vInit(dwMICKey0, dwMICKey1); + MIC_vAppend((PBYTE)&(sEthHeader.abyDstAddr[0]), 12); + dwMIC_Priority = 0; + MIC_vAppend((PBYTE)&dwMIC_Priority, 4); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"DMA0_tx_8021:MIC KEY: %lX, %lX\n", dwMICKey0, dwMICKey1); + + uLength = cbHeaderSize + cbMacHdLen + uPadding + cbIVlen; + + MIC_vAppend((pbyTxBufferAddr + uLength), cbFrameBodySize); + + pdwMIC_L = (PDWORD)(pbyTxBufferAddr + uLength + cbFrameBodySize); + pdwMIC_R = (PDWORD)(pbyTxBufferAddr + uLength + cbFrameBodySize + 4); + + MIC_vGetMIC(pdwMIC_L, pdwMIC_R); + MIC_vUnInit(); + + if (pDevice->bTxMICFail == TRUE) { + *pdwMIC_L = 0; + *pdwMIC_R = 0; + pDevice->bTxMICFail = FALSE; + } + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"uLength: %d, %d\n", uLength, cbFrameBodySize); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"cbReqCount:%d, %d, %d, %d\n", cbReqCount, cbHeaderSize, uPadding, cbIVlen); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"MIC:%lx, %lx\n", *pdwMIC_L, *pdwMIC_R); + + } + + + s_vFillTxKey(pDevice, (PBYTE)(pTxBufHead->adwTxKey), pbyIVHead, pTransmitKey, + pbyMacHdr, (WORD)cbFrameBodySize, (PBYTE)pMICHDR); + + if (pDevice->bEnableHostWEP) { + pMgmt->sNodeDBTable[uNodeIndex].dwTSC47_16 = pTransmitKey->dwTSC47_16; + pMgmt->sNodeDBTable[uNodeIndex].wTSC15_0 = pTransmitKey->wTSC15_0; + } + + if ((pDevice->byLocalID <= REV_ID_VT3253_A1)) { + s_vSWencryption(pDevice, pTransmitKey, pbyPayloadHead, (WORD)(cbFrameBodySize + cbMIClen)); + } + } + + pMACHeader->wSeqCtl = cpu_to_le16(pDevice->wSeqCounter << 4); + pDevice->wSeqCounter++ ; + if (pDevice->wSeqCounter > 0x0fff) + pDevice->wSeqCounter = 0; + + + if (bIsPSPOLL) { + // The MAC will automatically replace the Duration-field of MAC header by Duration-field + // of FIFO control header. + // This will cause AID-field of PS-POLL packet be incorrect (Because PS-POLL's AID field is + // in the same place of other packet's Duration-field). + // And it will cause Cisco-AP to issue Disassociation-packet + if (byPktTyp == PK_TYPE_11GB || byPktTyp == PK_TYPE_11GA) { + ((PSTxDataHead_g)pvTxDataHd)->wDuration_a = cpu_to_le16(p80211Header->sA2.wDurationID); + ((PSTxDataHead_g)pvTxDataHd)->wDuration_b = cpu_to_le16(p80211Header->sA2.wDurationID); + } else { + ((PSTxDataHead_ab)pvTxDataHd)->wDuration = cpu_to_le16(p80211Header->sA2.wDurationID); + } + } + + + // first TD is the only TD + //Set TSR1 & ReqCount in TxDescHead + pFrstTD->pTDInfo->skb = skb; + pFrstTD->m_td1TD1.byTCR = (TCR_STP | TCR_EDP | EDMSDU); + pFrstTD->pTDInfo->skb_dma = pFrstTD->pTDInfo->buf_dma; + pFrstTD->m_td1TD1.wReqCount = cpu_to_le16(cbReqCount); + pFrstTD->buff_addr = cpu_to_le32(pFrstTD->pTDInfo->skb_dma); + pFrstTD->pTDInfo->byFlags = 0; + pFrstTD->pTDInfo->byFlags |= TD_FLAGS_PRIV_SKB; + + if (MACbIsRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_PS)) { + // Disable PS + MACbPSWakeup(pDevice->PortOffset); + } + pDevice->bPWBitOn = FALSE; + + wmb(); + pFrstTD->m_td0TD0.f1Owner = OWNED_BY_NIC; + wmb(); + + pDevice->iTDUsed[TYPE_TXDMA0]++; + + if (AVAIL_TD(pDevice, TYPE_TXDMA0) <= 1) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " available td0 <= 1\n"); + } + + pDevice->apCurrTD[TYPE_TXDMA0] = pFrstTD->next; + + // Poll Transmit the adapter + MACvTransmit0(pDevice->PortOffset); + + return; +} + + diff --git a/drivers/staging/vt6655/rxtx.h b/drivers/staging/vt6655/rxtx.h new file mode 100644 index 000000000000..3e85264e2843 --- /dev/null +++ b/drivers/staging/vt6655/rxtx.h @@ -0,0 +1,132 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * File: whdr.h + * + * Purpose: + * + * Author: Jerry Chen + * + * Date: Jun. 27, 2002 + * + */ + + +#ifndef __RXTX_H__ +#define __RXTX_H__ + +#if !defined(__TTYPE_H__) +#include "ttype.h" +#endif +#if !defined(__DEVICE_H__) +#include "device.h" +#endif +#if !defined(__WCMD_H__) +#include "wcmd.h" +#endif + + +/*--------------------- Export Definitions -------------------------*/ + +/*--------------------- Export Classes ----------------------------*/ + +/*--------------------- Export Variables --------------------------*/ + +/*--------------------- Export Functions --------------------------*/ + + +#ifdef __cplusplus +extern "C" { /* Assume C declarations for C++ */ +#endif /* __cplusplus */ + +/* +VOID vGenerateMACHeader( + IN PSDevice pDevice, + IN DWORD dwTxBufferAddr, + IN PBYTE pbySkbData, + IN UINT cbPacketSize, + IN BOOL bDMA0Used, + OUT PUINT pcbHeadSize, + OUT PUINT pcbAppendPayload + ); + +VOID vProcessRxMACHeader ( + IN PSDevice pDevice, + IN DWORD dwRxBufferAddr, + IN UINT cbPacketSize, + IN BOOL bIsWEP, + OUT PUINT pcbHeadSize + ); +*/ + + +VOID +vGenerateMACHeader ( + IN PSDevice pDevice, + IN PBYTE pbyBufferAddr, + IN WORD wDuration, + IN PSEthernetHeader psEthHeader, + IN BOOL bNeedEncrypt, + IN WORD wFragType, + IN UINT uDMAIdx, + IN UINT uFragIdx + ); + + +UINT +cbGetFragCount( + IN PSDevice pDevice, + IN PSKeyItem pTransmitKey, + IN UINT cbFrameBodySize, + IN PSEthernetHeader psEthHeader + ); + + +VOID +vGenerateFIFOHeader ( + IN PSDevice pDevice, + IN BYTE byPktTyp, + IN PBYTE pbyTxBufferAddr, + IN BOOL bNeedEncrypt, + IN UINT cbPayloadSize, + IN UINT uDMAIdx, + IN PSTxDesc pHeadTD, + IN PSEthernetHeader psEthHeader, + IN PBYTE pPacket, + IN PSKeyItem pTransmitKey, + IN UINT uNodeIndex, + OUT PUINT puMACfragNum, + OUT PUINT pcbHeaderSize + ); + + +VOID vDMA0_tx_80211(PSDevice pDevice, struct sk_buff *skb, PBYTE pbMPDU, UINT cbMPDULen); +CMD_STATUS csMgmt_xmit(PSDevice pDevice, PSTxMgmtPacket pPacket); +CMD_STATUS csBeacon_xmit(PSDevice pDevice, PSTxMgmtPacket pPacket); + +#ifdef __cplusplus +} /* End of extern "C" { */ +#endif /* __cplusplus */ + + + + +#endif // __RXTX_H__ + + + diff --git a/drivers/staging/vt6655/srom.c b/drivers/staging/vt6655/srom.c new file mode 100644 index 000000000000..655d68593701 --- /dev/null +++ b/drivers/staging/vt6655/srom.c @@ -0,0 +1,437 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * File: srom.c + * + * Purpose:Implement functions to access eeprom + * + * Author: Jerry Chen + * + * Date: Jan 29, 2003 + * + * Functions: + * SROMbyReadEmbedded - Embedded read eeprom via MAC + * SROMbWriteEmbedded - Embedded write eeprom via MAC + * SROMvRegBitsOn - Set Bits On in eeprom + * SROMvRegBitsOff - Clear Bits Off in eeprom + * SROMbIsRegBitsOn - Test if Bits On in eeprom + * SROMbIsRegBitsOff - Test if Bits Off in eeprom + * SROMvReadAllContents - Read all contents in eeprom + * SROMvWriteAllContents - Write all contents in eeprom + * SROMvReadEtherAddress - Read Ethernet Address in eeprom + * SROMvWriteEtherAddress - Write Ethernet Address in eeprom + * SROMvReadSubSysVenId - Read Sub_VID and Sub_SysId in eeprom + * SROMbAutoLoad - Auto Load eeprom to MAC register + * + * Revision History: + * + */ + + +#if !defined(__UPC_H__) +#include "upc.h" +#endif +#if !defined(__TMACRO_H__) +#include "tmacro.h" +#endif +#if !defined(__TBIT_H__) +#include "tbit.h" +#endif +#if !defined(__TETHER_H__) +#include "tether.h" +#endif +#if !defined(__MAC_H__) +#include "mac.h" +#endif +#if !defined(__SROM_H__) +#include "srom.h" +#endif + + + + +/*--------------------- Static Definitions -------------------------*/ + +/*--------------------- Static Classes ----------------------------*/ + +/*--------------------- Static Variables --------------------------*/ + +/*--------------------- Static Functions --------------------------*/ + +/*--------------------- Export Variables --------------------------*/ + +/*--------------------- Export Functions --------------------------*/ + + + + +/* + * Description: Read a byte from EEPROM, by MAC I2C + * + * Parameters: + * In: + * dwIoBase - I/O base address + * byContntOffset - address of EEPROM + * Out: + * none + * + * Return Value: data read + * + */ +BYTE SROMbyReadEmbedded(DWORD_PTR dwIoBase, BYTE byContntOffset) +{ + WORD wDelay, wNoACK; + BYTE byWait; + BYTE byData; + BYTE byOrg; + + byData = 0xFF; + VNSvInPortB(dwIoBase + MAC_REG_I2MCFG, &byOrg); + // turn off hardware retry for getting NACK + VNSvOutPortB(dwIoBase + MAC_REG_I2MCFG, (byOrg & (~I2MCFG_NORETRY))); + for (wNoACK = 0; wNoACK < W_MAX_I2CRETRY; wNoACK++) { + VNSvOutPortB(dwIoBase + MAC_REG_I2MTGID, EEP_I2C_DEV_ID); + VNSvOutPortB(dwIoBase + MAC_REG_I2MTGAD, byContntOffset); + + // issue read command + VNSvOutPortB(dwIoBase + MAC_REG_I2MCSR, I2MCSR_EEMR); + // wait DONE be set + for (wDelay = 0; wDelay < W_MAX_TIMEOUT; wDelay++) { + VNSvInPortB(dwIoBase + MAC_REG_I2MCSR, &byWait); + if (BITbIsAnyBitsOn(byWait, (I2MCSR_DONE | I2MCSR_NACK))) + break; + PCAvDelayByIO(CB_DELAY_LOOP_WAIT); + } + if ((wDelay < W_MAX_TIMEOUT) && + (BITbIsBitOff(byWait, I2MCSR_NACK))) { + break; + } + } + VNSvInPortB(dwIoBase + MAC_REG_I2MDIPT, &byData); + VNSvOutPortB(dwIoBase + MAC_REG_I2MCFG, byOrg); + return byData; +} + + +/* + * Description: Write a byte to EEPROM, by MAC I2C + * + * Parameters: + * In: + * dwIoBase - I/O base address + * byContntOffset - address of EEPROM + * wData - data to write + * Out: + * none + * + * Return Value: TRUE if succeeded; FALSE if failed. + * + */ +BOOL SROMbWriteEmbedded (DWORD_PTR dwIoBase, BYTE byContntOffset, BYTE byData) +{ + WORD wDelay, wNoACK; + BYTE byWait; + + BYTE byOrg; + + VNSvInPortB(dwIoBase + MAC_REG_I2MCFG, &byOrg); + // turn off hardware retry for getting NACK + VNSvOutPortB(dwIoBase + MAC_REG_I2MCFG, (byOrg & (~I2MCFG_NORETRY))); + for (wNoACK = 0; wNoACK < W_MAX_I2CRETRY; wNoACK++) { + VNSvOutPortB(dwIoBase + MAC_REG_I2MTGID, EEP_I2C_DEV_ID); + VNSvOutPortB(dwIoBase + MAC_REG_I2MTGAD, byContntOffset); + VNSvOutPortB(dwIoBase + MAC_REG_I2MDOPT, byData); + + // issue write command + VNSvOutPortB(dwIoBase + MAC_REG_I2MCSR, I2MCSR_EEMW); + // wait DONE be set + for (wDelay = 0; wDelay < W_MAX_TIMEOUT; wDelay++) { + VNSvInPortB(dwIoBase + MAC_REG_I2MCSR, &byWait); + if (BITbIsAnyBitsOn(byWait, (I2MCSR_DONE | I2MCSR_NACK))) + break; + PCAvDelayByIO(CB_DELAY_LOOP_WAIT); + } + + if ((wDelay < W_MAX_TIMEOUT) && + (BITbIsBitOff(byWait, I2MCSR_NACK))) { + break; + } + } + if (wNoACK == W_MAX_I2CRETRY) { + VNSvOutPortB(dwIoBase + MAC_REG_I2MCFG, byOrg); + return FALSE; + } + VNSvOutPortB(dwIoBase + MAC_REG_I2MCFG, byOrg); + return TRUE; +} + + +/* + * Description: Turn bits on in eeprom + * + * Parameters: + * In: + * dwIoBase - I/O base address + * byContntOffset - address of EEPROM + * byBits - bits to turn on + * Out: + * none + * + * Return Value: none + * + */ +void SROMvRegBitsOn (DWORD_PTR dwIoBase, BYTE byContntOffset, BYTE byBits) +{ + BYTE byOrgData; + + byOrgData = SROMbyReadEmbedded(dwIoBase, byContntOffset); + SROMbWriteEmbedded(dwIoBase, byContntOffset,(BYTE)(byOrgData | byBits)); +} + + +/* + * Description: Turn bits off in eeprom + * + * Parameters: + * In: + * dwIoBase - I/O base address + * byContntOffset - address of EEPROM + * byBits - bits to turn off + * Out: + * none + * + */ +void SROMvRegBitsOff (DWORD_PTR dwIoBase, BYTE byContntOffset, BYTE byBits) +{ + BYTE byOrgData; + + byOrgData = SROMbyReadEmbedded(dwIoBase, byContntOffset); + SROMbWriteEmbedded(dwIoBase, byContntOffset,(BYTE)(byOrgData & (~byBits))); +} + + +/* + * Description: Test if bits on in eeprom + * + * Parameters: + * In: + * dwIoBase - I/O base address + * byContntOffset - address of EEPROM + * byTestBits - bits to test + * Out: + * none + * + * Return Value: TRUE if all test bits on; otherwise FALSE + * + */ +BOOL SROMbIsRegBitsOn (DWORD_PTR dwIoBase, BYTE byContntOffset, BYTE byTestBits) +{ + BYTE byOrgData; + + byOrgData = SROMbyReadEmbedded(dwIoBase, byContntOffset); + return BITbIsAllBitsOn(byOrgData, byTestBits); +} + + +/* + * Description: Test if bits off in eeprom + * + * Parameters: + * In: + * dwIoBase - I/O base address + * byContntOffset - address of EEPROM + * byTestBits - bits to test + * Out: + * none + * + * Return Value: TRUE if all test bits off; otherwise FALSE + * + */ +BOOL SROMbIsRegBitsOff (DWORD_PTR dwIoBase, BYTE byContntOffset, BYTE byTestBits) +{ + BYTE byOrgData; + + byOrgData = SROMbyReadEmbedded(dwIoBase, byContntOffset); + return BITbIsAllBitsOff(byOrgData, byTestBits); +} + + +/* + * Description: Read all contents of eeprom to buffer + * + * Parameters: + * In: + * dwIoBase - I/O base address + * Out: + * pbyEepromRegs - EEPROM content Buffer + * + * Return Value: none + * + */ +void SROMvReadAllContents (DWORD_PTR dwIoBase, PBYTE pbyEepromRegs) +{ + int ii; + + // ii = Rom Address + for (ii = 0; ii < EEP_MAX_CONTEXT_SIZE; ii++) { + *pbyEepromRegs = SROMbyReadEmbedded(dwIoBase,(BYTE) ii); + pbyEepromRegs++; + } +} + + +/* + * Description: Write all contents of buffer to eeprom + * + * Parameters: + * In: + * dwIoBase - I/O base address + * pbyEepromRegs - EEPROM content Buffer + * Out: + * none + * + * Return Value: none + * + */ +void SROMvWriteAllContents (DWORD_PTR dwIoBase, PBYTE pbyEepromRegs) +{ + int ii; + + // ii = Rom Address + for (ii = 0; ii < EEP_MAX_CONTEXT_SIZE; ii++) { + SROMbWriteEmbedded(dwIoBase,(BYTE) ii, *pbyEepromRegs); + pbyEepromRegs++; + } +} + + +/* + * Description: Read Ethernet Address from eeprom to buffer + * + * Parameters: + * In: + * dwIoBase - I/O base address + * Out: + * pbyEtherAddress - Ethernet Address buffer + * + * Return Value: none + * + */ +void SROMvReadEtherAddress (DWORD_PTR dwIoBase, PBYTE pbyEtherAddress) +{ + BYTE ii; + + // ii = Rom Address + for (ii = 0; ii < U_ETHER_ADDR_LEN; ii++) { + *pbyEtherAddress = SROMbyReadEmbedded(dwIoBase, ii); + pbyEtherAddress++; + } +} + + +/* + * Description: Write Ethernet Address from buffer to eeprom + * + * Parameters: + * In: + * dwIoBase - I/O base address + * pbyEtherAddress - Ethernet Address buffer + * Out: + * none + * + * Return Value: none + * + */ +void SROMvWriteEtherAddress (DWORD_PTR dwIoBase, PBYTE pbyEtherAddress) +{ + BYTE ii; + + // ii = Rom Address + for (ii = 0; ii < U_ETHER_ADDR_LEN; ii++) { + SROMbWriteEmbedded(dwIoBase, ii, *pbyEtherAddress); + pbyEtherAddress++; + } +} + + +/* + * Description: Read Sub_VID and Sub_SysId from eeprom to buffer + * + * Parameters: + * In: + * dwIoBase - I/O base address + * Out: + * pdwSubSysVenId - Sub_VID and Sub_SysId read + * + * Return Value: none + * + */ +void SROMvReadSubSysVenId (DWORD_PTR dwIoBase, PDWORD pdwSubSysVenId) +{ + PBYTE pbyData; + + pbyData = (PBYTE)pdwSubSysVenId; + // sub vendor + *pbyData = SROMbyReadEmbedded(dwIoBase, 6); + *(pbyData+1) = SROMbyReadEmbedded(dwIoBase, 7); + // sub system + *(pbyData+2) = SROMbyReadEmbedded(dwIoBase, 8); + *(pbyData+3) = SROMbyReadEmbedded(dwIoBase, 9); +} + +/* + * Description: Auto Load EEPROM to MAC register + * + * Parameters: + * In: + * dwIoBase - I/O base address + * Out: + * none + * + * Return Value: TRUE if success; otherwise FALSE + * + */ +BOOL SROMbAutoLoad (DWORD_PTR dwIoBase) +{ + BYTE byWait; + int ii; + + BYTE byOrg; + + VNSvInPortB(dwIoBase + MAC_REG_I2MCFG, &byOrg); + // turn on hardware retry + VNSvOutPortB(dwIoBase + MAC_REG_I2MCFG, (byOrg | I2MCFG_NORETRY)); + + MACvRegBitsOn(dwIoBase, MAC_REG_I2MCSR, I2MCSR_AUTOLD); + + // ii = Rom Address + for (ii = 0; ii < EEP_MAX_CONTEXT_SIZE; ii++) { + MACvTimer0MicroSDelay(dwIoBase, CB_EEPROM_READBYTE_WAIT); + VNSvInPortB(dwIoBase + MAC_REG_I2MCSR, &byWait); + if (BITbIsBitOff(byWait, I2MCSR_AUTOLD)) + break; + } + + VNSvOutPortB(dwIoBase + MAC_REG_I2MCFG, byOrg); + + if (ii == EEP_MAX_CONTEXT_SIZE) + return FALSE; + return TRUE; +} + + diff --git a/drivers/staging/vt6655/srom.h b/drivers/staging/vt6655/srom.h new file mode 100644 index 000000000000..a4ca5f0b196d --- /dev/null +++ b/drivers/staging/vt6655/srom.h @@ -0,0 +1,179 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * File: srom.h + * + * Purpose: Implement functions to access eeprom + * + * Author: Jerry Chen + * + * Date: Jan 29, 2003 + * + */ + + +#ifndef __SROM_H__ +#define __SROM_H__ + +#if !defined(__TTYPE_H__) +#include "ttype.h" +#endif + + +/*--------------------- Export Definitions -------------------------*/ + + +#define EEP_MAX_CONTEXT_SIZE 256 + +#define CB_EEPROM_READBYTE_WAIT 900 //us + +#define W_MAX_I2CRETRY 0x0fff + +// +// Contents in the EEPROM +// + +#define EEP_OFS_PAR 0x00 // physical address +#define EEP_OFS_ANTENNA 0x16 +#define EEP_OFS_RADIOCTL 0x17 +#define EEP_OFS_RFTYPE 0x1B // for select RF +#define EEP_OFS_MINCHANNEL 0x1C // Min Channel # +#define EEP_OFS_MAXCHANNEL 0x1D // Max Channel # +#define EEP_OFS_SIGNATURE 0x1E // +#define EEP_OFS_ZONETYPE 0x1F // +#define EEP_OFS_RFTABLE 0x20 // RF POWER TABLE +#define EEP_OFS_PWR_CCK 0x20 +#define EEP_OFS_SETPT_CCK 0x21 +#define EEP_OFS_PWR_OFDMG 0x23 +#define EEP_OFS_SETPT_OFDMG 0x24 +#define EEP_OFS_PWR_FORMULA_OST 0x26 // +#define EEP_OFS_MAJOR_VER 0x2E +#define EEP_OFS_MINOR_VER 0x2F +#define EEP_OFS_CCK_PWR_TBL 0x30 +#define EEP_OFS_CCK_PWR_dBm 0x3F +#define EEP_OFS_OFDM_PWR_TBL 0x40 +#define EEP_OFS_OFDM_PWR_dBm 0x4F +//{{ RobertYu: 20041124 +#define EEP_OFS_SETPT_OFDMA 0x4E +#define EEP_OFS_OFDMA_PWR_TBL 0x50 +//}} +#define EEP_OFS_OFDMA_PWR_dBm 0xD2 + + +//----------need to remove -------------------- +#define EEP_OFS_BBTAB_LEN 0x70 // BB Table Length +#define EEP_OFS_BBTAB_ADR 0x71 // BB Table Offset +#define EEP_OFS_CHECKSUM 0xFF // reserved area for baseband 28h ~ 78h + +#define EEP_I2C_DEV_ID 0x50 // EEPROM device address on the I2C bus + + +// +// Bits in EEP_OFS_ANTENNA +// +#define EEP_ANTENNA_MAIN 0x01 +#define EEP_ANTENNA_AUX 0x02 +#define EEP_ANTINV 0x04 + +// +// Bits in EEP_OFS_RADIOCTL +// +#define EEP_RADIOCTL_ENABLE 0x80 +#define EEP_RADIOCTL_INV 0x01 + + + +/*--------------------- Export Types ------------------------------*/ + +// AT24C02 eeprom contents +// 2048 bits = 256 bytes = 128 words +// +typedef struct tagSSromReg { + BYTE abyPAR[6]; // 0x00 (WORD) + + WORD wSUB_VID; // 0x03 (WORD) + WORD wSUB_SID; + + BYTE byBCFG0; // 0x05 (WORD) + BYTE byBCFG1; + + BYTE byFCR0; // 0x06 (WORD) + BYTE byFCR1; + BYTE byPMC0; // 0x07 (WORD) + BYTE byPMC1; + BYTE byMAXLAT; // 0x08 (WORD) + BYTE byMINGNT; + BYTE byCFG0; // 0x09 (WORD) + BYTE byCFG1; + WORD wCISPTR; // 0x0A (WORD) + WORD wRsv0; // 0x0B (WORD) + WORD wRsv1; // 0x0C (WORD) + BYTE byBBPAIR; // 0x0D (WORD) + BYTE byRFTYPE; + BYTE byMinChannel; // 0x0E (WORD) + BYTE byMaxChannel; + BYTE bySignature; // 0x0F (WORD) + BYTE byCheckSum; + + BYTE abyReserved0[96]; // 0x10 (WORD) + BYTE abyCIS[128]; // 0x80 (WORD) +} SSromReg, DEF* PSSromReg; + +/*--------------------- Export Macros ------------------------------*/ + +/*--------------------- Export Classes ----------------------------*/ + +/*--------------------- Export Variables --------------------------*/ + +/*--------------------- Export Functions --------------------------*/ +#ifdef __cplusplus +extern "C" { /* Assume C declarations for C++ */ +#endif /* __cplusplus */ + + +BYTE SROMbyReadEmbedded(DWORD_PTR dwIoBase, BYTE byContntOffset); +BOOL SROMbWriteEmbedded(DWORD_PTR dwIoBase, BYTE byContntOffset, BYTE byData); + +void SROMvRegBitsOn(DWORD_PTR dwIoBase, BYTE byContntOffset, BYTE byBits); +void SROMvRegBitsOff(DWORD_PTR dwIoBase, BYTE byContntOffset, BYTE byBits); + +BOOL SROMbIsRegBitsOn(DWORD_PTR dwIoBase, BYTE byContntOffset, BYTE byTestBits); +BOOL SROMbIsRegBitsOff(DWORD_PTR dwIoBase, BYTE byContntOffset, BYTE byTestBits); + +void SROMvReadAllContents(DWORD_PTR dwIoBase, PBYTE pbyEepromRegs); +void SROMvWriteAllContents(DWORD_PTR dwIoBase, PBYTE pbyEepromRegs); + +void SROMvReadEtherAddress(DWORD_PTR dwIoBase, PBYTE pbyEtherAddress); +void SROMvWriteEtherAddress(DWORD_PTR dwIoBase, PBYTE pbyEtherAddress); + +VOID SROMvReadSubSysVenId(DWORD_PTR dwIoBase, PDWORD pdwSubSysVenId); + +BOOL SROMbAutoLoad (DWORD_PTR dwIoBase); + + +#ifdef __cplusplus +} /* End of extern "C" { */ +#endif /* __cplusplus */ + + + + +#endif // __EEPROM_H__ + + diff --git a/drivers/staging/vt6655/tbit.h b/drivers/staging/vt6655/tbit.h new file mode 100644 index 000000000000..7c3a82e9b608 --- /dev/null +++ b/drivers/staging/vt6655/tbit.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * File: tbit.h + * + * Purpose: Bit routines + * + * Author: Tevin Chen + * + * Date: May 21, 1996 + * + */ + + +#ifndef __TBIT_H__ +#define __TBIT_H__ + +#if !defined(__TTYPE_H__) +#include "ttype.h" +#endif + + + +/*--------------------- Export Definitions -------------------------*/ + +/*--------------------- Export Types ------------------------------*/ + +/*--------------------- Export Macros ------------------------------*/ + +// test single bit on +#define BITbIsBitOn(tData, tTestBit) \ + (((tData) & (tTestBit)) != 0) + +// test single bit off +#define BITbIsBitOff(tData, tTestBit) \ + (((tData) & (tTestBit)) == 0) + + +#define BITbIsAllBitsOn(tData, tTestBit) \ + (((tData) & (tTestBit)) == (tTestBit)) + +#define BITbIsAllBitsOff(tData, tTestBit) \ + (((tData) & (tTestBit)) == 0) + +#define BITbIsAnyBitsOn(tData, tTestBit) \ + (((tData) & (tTestBit)) != 0) + +#define BITbIsAnyBitsOff(tData, tTestBit) \ + (((tData) & (tTestBit)) != (tTestBit)) + +/*--------------------- Export Classes ----------------------------*/ + +/*--------------------- Export Variables --------------------------*/ + +/*--------------------- Export Functions --------------------------*/ + + + +#endif // __TBIT_H__ + + + diff --git a/drivers/staging/vt6655/tcrc.c b/drivers/staging/vt6655/tcrc.c new file mode 100644 index 000000000000..b70080c267c8 --- /dev/null +++ b/drivers/staging/vt6655/tcrc.c @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2003 VIA Networking, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * File: tcrc.c + * + * Purpose: Implement functions to caculate CRC + * + * Author: Tevin Chen + * + * Date: May 21, 1996 + * + * Functions: + * CRCdwCrc32 - + * CRCdwGetCrc32 - + * CRCdwGetCrc32Ex - + * + * Revision History: + * + */ + + +#if !defined(__TBIT_H__) +#include "tbit.h" +#endif +#if !defined(__TCRC_H__) +#include "tcrc.h" +#endif + + + + +/*--------------------- Static Definitions -------------------------*/ + +/*--------------------- Static Classes ----------------------------*/ + +/*--------------------- Static Variables --------------------------*/ + +// 32-bit CRC table +static const DWORD s_adwCrc32Table[256] = { + 0x00000000L, 0x77073096L, 0xEE0E612CL, 0x990951BAL, + 0x076DC419L, 0x706AF48FL, 0xE963A535L, 0x9E6495A3L, + 0x0EDB8832L, 0x79DCB8A4L, 0xE0D5E91EL, 0x97D2D988L, + 0x09B64C2BL, 0x7EB17CBDL, 0xE7B82D07L, 0x90BF1D91L, + 0x1DB71064L, 0x6AB020F2L, 0xF3B97148L, 0x84BE41DEL, + 0x1ADAD47DL, 0x6DDDE4EBL, 0xF4D4B551L, 0x83D385C7L, + 0x136C9856L, 0x646BA8C0L, 0xFD62F97AL, 0x8A65C9ECL, + 0x14015C4FL, 0x63066CD9L, 0xFA0F3D63L, 0x8D080DF5L, + 0x3B6E20C8L, 0x4C69105EL, 0xD56041E4L, 0xA2677172L, + 0x3C03E4D1L, 0x4B04D447L, 0xD20D85FDL, 0xA50AB56BL, + 0x35B5A8FAL, 0x42B2986CL, 0xDBBBC9D6L, 0xACBCF940L, + 0x32D86CE3L, 0x45DF5C75L, 0xDCD60DCFL, 0xABD13D59L, + 0x26D930ACL, 0x51DE003AL, 0xC8D75180L, 0xBFD06116L, + 0x21B4F4B5L, 0x56B3C423L, 0xCFBA9599L, 0xB8BDA50FL, + 0x2802B89EL, 0x5F058808L, 0xC60CD9B2L, 0xB10BE924L, + 0x2F6F7C87L, 0x58684C11L, 0xC1611DABL, 0xB6662D3DL, + 0x76DC4190L, 0x01DB7106L, 0x98D220BCL, 0xEFD5102AL, + 0x71B18589L, 0x06B6B51FL, 0x9FBFE4A5L, 0xE8B8D433L, + 0x7807C9A2L, 0x0F00F934L, 0x9609A88EL, 0xE10E9818L, + 0x7F6A0DBBL, 0x086D3D2DL, 0x91646C97L, 0xE6635C01L, + 0x6B6B51F4L, 0x1C6C6162L, 0x856530D8L, 0xF262004EL, + 0x6C0695EDL, 0x1B01A57BL, 0x8208F4C1L, 0xF50FC457L, + 0x65B0D9C6L, 0x12B7E950L, 0x8BBEB8EAL, 0xFCB9887CL, + 0x62DD1DDFL, 0x15DA2D49L, 0x8CD37CF3L, 0xFBD44C65L, + 0x4DB26158L, 0x3AB551CEL, 0xA3BC0074L, 0xD4BB30E2L, + 0x4ADFA541L, 0x3DD895D7L, 0xA4D1C46DL, 0xD3D6F4FBL, + 0x4369E96AL, 0x346ED9FCL, 0xAD678846L, 0xDA60B8D0L, + 0x44042D73L, 0x33031DE5L, 0xAA0A4C5FL, 0xDD0D7CC9L, + 0x5005713CL, 0x270241AAL, 0xBE0B1010L, 0xC90C2086L, + 0x5768B525L, 0x206F85B3L, 0xB966D409L, 0xCE61E49FL, + 0x5EDEF90EL, 0x29D9C998L, 0xB0D09822L, 0xC7D7A8B4L, + 0x59B33D17L, 0x2EB40D81L, 0xB7BD5C3BL, 0xC0BA6CADL, + 0xEDB88320L, 0x9ABFB3B6L, 0x03B6E20CL, 0x74B1D29AL, + 0xEAD54739L, 0x9DD277AFL, 0x04DB2615L, 0x73DC1683L, + 0xE3630B12L, 0x94643B84L, 0x0D6D6A3EL, 0x7A6A5AA8L, + 0xE40ECF0BL, 0x9309FF9DL, 0x0A00AE27L, 0x7D079EB1L, + 0xF00F9344L, 0x8708A3D2L, 0x1E01F268L, 0x6906C2FEL, + 0xF762575DL, 0x806567CBL, 0x196C3671L, 0x6E6B06E7L, + 0xFED41B76L, 0x89D32BE0L, 0x10DA7A5AL, 0x67DD4ACCL, + 0xF9B9DF6FL, 0x8EBEEFF9L, 0x17B7BE43L, 0x60B08ED5L, + 0xD6D6A3E8L, 0xA1D1937EL, 0x38D8C2C4L, 0x4FDFF252L, + 0xD1BB67F1L, 0xA6BC5767L, 0x3FB506DDL, 0x48B2364BL, + 0xD80D2BDAL, 0xAF0A1B4CL, 0x36034AF6L, 0x41047A60L, + 0xDF60EFC3L, 0xA867DF55L, 0x316E8EEFL, 0x4669BE79L, + 0xCB61B38CL, 0xBC66831AL, 0x256FD2A0L, 0x5268E236L, + 0xCC0C7795L, 0xBB0B4703L, 0x220216B9L, 0x5505262FL, + 0xC5BA3BBEL, 0xB2BD0B28L, 0x2BB45A92L, 0x5CB36A04L, + 0xC2D7FFA7L, 0xB5D0CF31L, 0x2CD99E8BL, 0x5BDEAE1DL, + 0x9B64C2B0L, 0xEC63F226L, 0x756AA39CL, 0x026D930AL, + 0x9C0906A9L, 0xEB0E363FL, 0x72076785L, 0x05005713L, + 0x95BF4A82L, 0xE2B87A14L, 0x7BB12BAEL, 0x0CB61B38L, + 0x92D28E9BL, 0xE5D5BE0DL, 0x7CDCEFB7L, 0x0BDBDF21L, + 0x86D3D2D4L, 0xF1D4E242L, 0x68DDB3F8L, 0x1FDA836EL, + 0x81BE16CDL, 0xF6B9265BL, 0x6FB077E1L, 0x18B74777L, + 0x88085AE6L, 0xFF0F6A70L, 0x66063BCAL, 0x11010B5CL, + 0x8F659EFFL, 0xF862AE69L, 0x616BFFD3L, 0x166CCF45L, + 0xA00AE278L, 0xD70DD2EEL, 0x4E048354L, 0x3903B3C2L, + 0xA7672661L, 0xD06016F7L, 0x4969474DL, 0x3E6E77DBL, + 0xAED16A4AL, 0xD9D65ADCL, 0x40DF0B66L, 0x37D83BF0L, + 0xA9BCAE53L, 0xDEBB9EC5L, 0x47B2CF7FL, 0x30B5FFE9L, + 0xBDBDF21CL, 0xCABAC28AL, 0x53B39330L, 0x24B4A3A6L, + 0xBAD03605L, 0xCDD70693L, 0x54DE5729L, 0x23D967BFL, + 0xB3667A2EL, 0xC4614AB8L, 0x5D681B02L, 0x2A6F2B94L, + 0xB40BBE37L, 0xC30C8EA1L, 0x5A05DF1BL, 0x2D02EF8DL +}; + +/*--------------------- Static Functions --------------------------*/ + +/*--------------------- Export Variables --------------------------*/ + + + + +/*+ + * + * Description: + * Generate a CRC-32 from the data stream + * + * Parameters: + * In: + * pbyData - the data stream + * cbByte - the length of the stream + * dwCrcSeed - Seed for CRC32 + * Out: + * none + * + * Return Value: CRC-32 + * +-*/ +DWORD CRCdwCrc32 (PBYTE pbyData, UINT cbByte, DWORD dwCrcSeed) +{ + DWORD dwCrc; + + dwCrc = dwCrcSeed; + while (cbByte--) { + dwCrc = s_adwCrc32Table[(BYTE)((dwCrc ^ (*pbyData)) & 0xFF)] ^ (dwCrc >> 8); + pbyData++; + } + + return dwCrc; +} + + +/*+ + * + * Description: + * To test CRC generator, input 8 bytes packet + * -- 0xff 0xff 0xff 0xff 0x00 0x00 0x00 0x00 + * the generated CRC should be + * -- 0xff 0xff 0xff 0xff + * + * Parameters: + * In: + * pbyData - the data stream + * cbByte - the length of the stream + * Out: + * none + * + * Return Value: CRC-32 + * +-*/ +DWORD CRCdwGetCrc32 (PBYTE pbyData, UINT cbByte) +{ + return ~CRCdwCrc32(pbyData, cbByte, 0xFFFFFFFFL); +} + + +/*+ + * + * Description: + * + * NOTE.... Because CRCdwGetCrc32Ex() is an iteration function, + * this means we will use the output of CRCdwGetCrc32Ex() + * to be a new argument to do next CRCdwGetCrc32Ex() calculation. + * Thus, the final result must be inverted to be the + * correct answer. + * + * Parameters: + * In: + * pbyData - the data stream + * cbByte - the length of the stream + * Out: + * none + * + * Return Value: CRC-32 + * +-*/ +DWORD CRCdwGetCrc32Ex(PBYTE pbyData, UINT cbByte, DWORD dwPreCRC) +{ + return CRCdwCrc32(pbyData, cbByte, dwPreCRC); +} + + diff --git a/drivers/staging/vt6655/tcrc.h b/drivers/staging/vt6655/tcrc.h new file mode 100644 index 000000000000..ebea22ed2da6 --- /dev/null +++ b/drivers/staging/vt6655/tcrc.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2003 VIA Networking, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * File: tcrc.h + * + * Purpose: Implement functions to caculate CRC + * + * Author: Tevin Chen + * + * Date: Jan. 28, 1997 + * + */ + + +#ifndef __TCRC_H__ +#define __TCRC_H__ + +#if !defined(__TTYPE_H__) +#include "ttype.h" +#endif + + + + +/*--------------------- Export Definitions -------------------------*/ + +/*--------------------- Export Types ------------------------------*/ + +/*--------------------- Export Macros ------------------------------*/ + +/*--------------------- Export Classes ----------------------------*/ + +/*--------------------- Export Variables --------------------------*/ + +/*--------------------- Export Functions --------------------------*/ +#ifdef __cplusplus +extern "C" { /* Assume C declarations for C++ */ +#endif /* __cplusplus */ + + +DWORD CRCdwCrc32(PBYTE pbyData, UINT cbByte, DWORD dwCrcSeed); +DWORD CRCdwGetCrc32(PBYTE pbyData, UINT cbByte); +DWORD CRCdwGetCrc32Ex(PBYTE pbyData, UINT cbByte, DWORD dwPreCRC); + + +#ifdef __cplusplus +} /* End of extern "C" { */ +#endif /* __cplusplus */ + + + + +#endif // __TCRC_H__ + + + diff --git a/drivers/staging/vt6655/test b/drivers/staging/vt6655/test new file mode 100644 index 000000000000..039f7d71c537 --- /dev/null +++ b/drivers/staging/vt6655/test @@ -0,0 +1,9 @@ +KSP := /lib/modules/$(shell uname -r)/build \ + /usr/src/linux-$(shell uname -r) \ + /usr/src/linux-$(shell uname -r | sed 's/-.*//') \ +# /usr/src/kernel-headers-$(shell uname -r) \ +# /usr/src/kernel-source-$(shell uname -r) \ +# /usr/src/linux-$(shell uname -r | sed 's/\([0-9]*\.[0-9]*\)\..*/\1/') \ +# /usr/src/linux /home/plice +test_dir = $(shell [ -e $(dir)/include/linux ] && echo $(dir)) +KSP := $(foreach dir, $(KSP), $(test_dir)) \ No newline at end of file diff --git a/drivers/staging/vt6655/tether.c b/drivers/staging/vt6655/tether.c new file mode 100644 index 000000000000..fd69423fe14b --- /dev/null +++ b/drivers/staging/vt6655/tether.c @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2003 VIA Networking, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * File: tether.c + * + * Purpose: + * + * Author: Tevin Chen + * + * Date: May 21, 1996 + * + * Functions: + * ETHbyGetHashIndexByCrc32 - Caculate multicast hash value by CRC32 + * ETHbIsBufferCrc32Ok - Check CRC value of the buffer if Ok or not + * + * Revision History: + * + */ + +#if !defined(__DEVICE_H__) +#include "device.h" +#endif +#if !defined(__TMACRO_H__) +#include "tmacro.h" +#endif +#if !defined(__TBIT_H__) +#include "tbit.h" +#endif +#if !defined(__TCRC_H__) +#include "tcrc.h" +#endif +#if !defined(__TETHER_H__) +#include "tether.h" +#endif + + + + +/*--------------------- Static Definitions -------------------------*/ + +/*--------------------- Static Classes ----------------------------*/ + +/*--------------------- Static Variables --------------------------*/ + +/*--------------------- Static Functions --------------------------*/ + +/*--------------------- Export Variables --------------------------*/ + + + +/* + * Description: Caculate multicast hash value by CRC32 + * + * Parameters: + * In: + * pbyMultiAddr - Multicast Address + * Out: + * none + * + * Return Value: Hash value + * + */ +BYTE ETHbyGetHashIndexByCrc32 (PBYTE pbyMultiAddr) +{ + int ii; + BYTE byTmpHash; + BYTE byHash = 0; + + // get the least 6-bits from CRC generator + byTmpHash = (BYTE)(CRCdwCrc32(pbyMultiAddr, U_ETHER_ADDR_LEN, + 0xFFFFFFFFL) & 0x3F); + // reverse most bit to least bit + for (ii = 0; ii < (sizeof(byTmpHash) * 8); ii++) { + byHash <<= 1; + if (BITbIsBitOn(byTmpHash, 0x01)) + byHash |= 1; + byTmpHash >>= 1; + } + + // adjust 6-bits to the right most + return (byHash >> 2); +} + + +/* + * Description: Check CRC value of the buffer if Ok or not + * + * Parameters: + * In: + * pbyBuffer - pointer of buffer (normally is rx buffer) + * cbFrameLength - length of buffer, including CRC portion + * Out: + * none + * + * Return Value: TRUE if ok; FALSE if error. + * + */ +BOOL ETHbIsBufferCrc32Ok (PBYTE pbyBuffer, UINT cbFrameLength) +{ + DWORD dwCRC; + + dwCRC = CRCdwGetCrc32(pbyBuffer, cbFrameLength - 4); + if (cpu_to_le32(*((PDWORD)(pbyBuffer + cbFrameLength - 4))) != dwCRC) { + return FALSE; + } + return TRUE; +} + diff --git a/drivers/staging/vt6655/tether.h b/drivers/staging/vt6655/tether.h new file mode 100644 index 000000000000..920a8bb68356 --- /dev/null +++ b/drivers/staging/vt6655/tether.h @@ -0,0 +1,256 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * File: tether.h + * + * Purpose: + * + * Author: Tevin Chen + * + * Date: Jan. 28, 1997 + * + */ + + + +#ifndef __TETHER_H__ +#define __TETHER_H__ + + +#if !defined(__TTYPE_H__) +#include "ttype.h" +#endif + + + + +/*--------------------- Export Definitions -------------------------*/ +// +// constants +// +#define U_ETHER_ADDR_LEN 6 // Ethernet address length +#define U_TYPE_LEN 2 // +#define U_CRC_LEN 4 // +#define U_HEADER_LEN (U_ETHER_ADDR_LEN * 2 + U_TYPE_LEN) +#define U_ETHER_ADDR_STR_LEN (U_ETHER_ADDR_LEN * 2 + 1) + // Ethernet address string length + +#define MIN_DATA_LEN 46 // min data length +#define MAX_DATA_LEN 1500 // max data length + +#define MIN_PACKET_LEN (MIN_DATA_LEN + U_HEADER_LEN) + // 60 + // min total packet length (tx) +#define MAX_PACKET_LEN (MAX_DATA_LEN + U_HEADER_LEN) + // 1514 + // max total packet length (tx) + +#define MAX_LOOKAHEAD_SIZE MAX_PACKET_LEN + +#define U_MULTI_ADDR_LEN 8 // multicast address length + + +#ifdef __BIG_ENDIAN + +#define TYPE_PKT_IP 0x0800 // +#define TYPE_PKT_ARP 0x0806 // +#define TYPE_PKT_RARP 0x8035 // +#define TYPE_PKT_IPX 0x8137 // +#define TYPE_PKT_802_1x 0x888e +#define TYPE_PKT_PreAuth 0x88C7 + +#define TYPE_PKT_PING_M_REQ 0x8011 // master reguest +#define TYPE_PKT_PING_S_GNT 0x8022 // slave grant +#define TYPE_PKT_PING_M 0x8077 // pingpong master packet +#define TYPE_PKT_PING_S 0x8088 // pingpong slave packet +#define TYPE_PKT_WOL_M_REQ 0x8033 // WOL waker request +#define TYPE_PKT_WOL_S_GNT 0x8044 // WOL sleeper grant +#define TYPE_MGMT_PROBE_RSP 0x5000 +#define TYPE_PKT_VNT_DIAG 0x8011 // Diag Pkt +#define TYPE_PKT_VNT_PER 0x8888 // Diag PER Pkt +// +// wFrameCtl field in the S802_11Header +// +// NOTE.... +// in network byte order, high byte is going first +#define FC_TODS 0x0001 +#define FC_FROMDS 0x0002 +#define FC_MOREFRAG 0x0004 +#define FC_RETRY 0x0008 +#define FC_POWERMGT 0x0010 +#define FC_MOREDATA 0x0020 +#define FC_WEP 0x0040 +#define TYPE_802_11_ATIM 0x9000 + +#define TYPE_802_11_DATA 0x0800 +#define TYPE_802_11_CTL 0x0400 +#define TYPE_802_11_MGMT 0x0000 +#define TYPE_802_11_MASK 0x0C00 +#define TYPE_SUBTYPE_MASK 0xFC00 +#define TYPE_802_11_NODATA 0x4000 +#define TYPE_DATE_NULL 0x4800 + +#define TYPE_CTL_PSPOLL 0xa400 +#define TYPE_CTL_RTS 0xb400 +#define TYPE_CTL_CTS 0xc400 +#define TYPE_CTL_ACK 0xd400 + + +//#define WEP_IV_MASK 0xFFFFFF00 + +#else //if LITTLE_ENDIAN +// +// wType field in the SEthernetHeader +// +// NOTE.... +// in network byte order, high byte is going first +#define TYPE_PKT_IP 0x0008 // +#define TYPE_PKT_ARP 0x0608 // +#define TYPE_PKT_RARP 0x3580 // +#define TYPE_PKT_IPX 0x3781 // + +#define TYPE_PKT_802_1x 0x8e88 +#define TYPE_PKT_PreAuth 0xC788 + +#define TYPE_PKT_PING_M_REQ 0x1180 // master reguest +#define TYPE_PKT_PING_S_GNT 0x2280 // slave grant +#define TYPE_PKT_PING_M 0x7780 // pingpong master packet +#define TYPE_PKT_PING_S 0x8880 // pingpong slave packet +#define TYPE_PKT_WOL_M_REQ 0x3380 // WOL waker request +#define TYPE_PKT_WOL_S_GNT 0x4480 // WOL sleeper grant +#define TYPE_MGMT_PROBE_RSP 0x0050 +#define TYPE_PKT_VNT_DIAG 0x1180 // Diag Pkt +#define TYPE_PKT_VNT_PER 0x8888 // Diag PER Pkt +// +// wFrameCtl field in the S802_11Header +// +// NOTE.... +// in network byte order, high byte is going first +#define FC_TODS 0x0100 +#define FC_FROMDS 0x0200 +#define FC_MOREFRAG 0x0400 +#define FC_RETRY 0x0800 +#define FC_POWERMGT 0x1000 +#define FC_MOREDATA 0x2000 +#define FC_WEP 0x4000 +#define TYPE_802_11_ATIM 0x0090 + +#define TYPE_802_11_DATA 0x0008 +#define TYPE_802_11_CTL 0x0004 +#define TYPE_802_11_MGMT 0x0000 +#define TYPE_802_11_MASK 0x000C +#define TYPE_SUBTYPE_MASK 0x00FC +#define TYPE_802_11_NODATA 0x0040 +#define TYPE_DATE_NULL 0x0048 + +#define TYPE_CTL_PSPOLL 0x00a4 +#define TYPE_CTL_RTS 0x00b4 +#define TYPE_CTL_CTS 0x00c4 +#define TYPE_CTL_ACK 0x00d4 + + +//#define WEP_IV_MASK 0x00FFFFFF + +#endif //#ifdef __BIG_ENDIAN + +#define WEP_IV_MASK 0x00FFFFFF + +/*--------------------- Export Types ------------------------------*/ +// +// Ethernet packet +// +typedef struct tagSEthernetHeader { + BYTE abyDstAddr[U_ETHER_ADDR_LEN]; + BYTE abySrcAddr[U_ETHER_ADDR_LEN]; + WORD wType; +}__attribute__ ((__packed__)) +SEthernetHeader, DEF* PSEthernetHeader; + + +// +// 802_3 packet +// +typedef struct tagS802_3Header { + BYTE abyDstAddr[U_ETHER_ADDR_LEN]; + BYTE abySrcAddr[U_ETHER_ADDR_LEN]; + WORD wLen; +}__attribute__ ((__packed__)) +S802_3Header, DEF* PS802_3Header; + +// +// 802_11 packet +// +typedef struct tagS802_11Header { + WORD wFrameCtl; + WORD wDurationID; + BYTE abyAddr1[U_ETHER_ADDR_LEN]; + BYTE abyAddr2[U_ETHER_ADDR_LEN]; + BYTE abyAddr3[U_ETHER_ADDR_LEN]; + WORD wSeqCtl; + BYTE abyAddr4[U_ETHER_ADDR_LEN]; +}__attribute__ ((__packed__)) +S802_11Header, DEF* PS802_11Header; + +/*--------------------- Export Macros ------------------------------*/ +// Frame type macro + +#define IS_MULTICAST_ADDRESS(pbyEtherAddr) \ + ((*(PBYTE)(pbyEtherAddr) & 0x01) == 1) + +#define IS_BROADCAST_ADDRESS(pbyEtherAddr) ( \ + (*(PDWORD)(pbyEtherAddr) == 0xFFFFFFFFL) && \ + (*(PWORD)((PBYTE)(pbyEtherAddr) + 4) == 0xFFFF) \ +) + +#define IS_NULL_ADDRESS(pbyEtherAddr) ( \ + (*(PDWORD)(pbyEtherAddr) == 0L) && \ + (*(PWORD)((PBYTE)(pbyEtherAddr) + 4) == 0) \ +) + +#define IS_ETH_ADDRESS_EQUAL(pbyAddr1, pbyAddr2) ( \ + (*(PDWORD)(pbyAddr1) == *(PDWORD)(pbyAddr2)) && \ + (*(PWORD)((PBYTE)(pbyAddr1) + 4) == \ + *(PWORD)((PBYTE)(pbyAddr2) + 4)) \ +) + +/*--------------------- Export Classes ----------------------------*/ + +/*--------------------- Export Variables --------------------------*/ + +/*--------------------- Export Functions --------------------------*/ +#ifdef __cplusplus +extern "C" { /* Assume C declarations for C++ */ +#endif /* __cplusplus */ + + +BYTE ETHbyGetHashIndexByCrc32(PBYTE pbyMultiAddr); +//BYTE ETHbyGetHashIndexByCrc(PBYTE pbyMultiAddr); +BOOL ETHbIsBufferCrc32Ok(PBYTE pbyBuffer, UINT cbFrameLength); + + +#ifdef __cplusplus +} /* End of extern "C" { */ +#endif /* __cplusplus */ + + + + +#endif // __TETHER_H__ + + + diff --git a/drivers/staging/vt6655/tkip.c b/drivers/staging/vt6655/tkip.c new file mode 100644 index 000000000000..2ded8420c390 --- /dev/null +++ b/drivers/staging/vt6655/tkip.c @@ -0,0 +1,284 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * File: tkip.c + * + * Purpose: Implement functions for 802.11i TKIP + * + * Author: Jerry Chen + * + * Date: Mar. 11, 2003 + * + * Functions: + * TKIPvMixKey - Get TKIP RC4 Key from TK,TA, and TSC + * + * Revision History: + * + */ + + +#if !defined(__TMACRO_H__) +#include "tmacro.h" +#endif +#if !defined(__TBIT_H__) +#include "tbit.h" +#endif +#if !defined(__TKIP_H__) +#include "tkip.h" +#endif +#if !defined(__UMEM_H__) +#include "umem.h" +#endif + + +/*--------------------- Static Definitions -------------------------*/ + +/*--------------------- Static Classes ----------------------------*/ + +/*--------------------- Static Variables --------------------------*/ + +/*--------------------- Static Functions --------------------------*/ + +/*--------------------- Export Variables --------------------------*/ + +/*--------------------- Static Definitions -------------------------*/ + +/*--------------------- Static Classes ----------------------------*/ + +/*--------------------- Static Variables --------------------------*/ + +/* The Sbox is reduced to 2 16-bit wide tables, each with 256 entries. */ +/* The 2nd table is the same as the 1st but with the upper and lower */ +/* bytes swapped. To allow an endian tolerant implementation, the byte */ +/* halves have been expressed independently here. */ +const BYTE TKIP_Sbox_Lower[256] = { + 0xA5,0x84,0x99,0x8D,0x0D,0xBD,0xB1,0x54, + 0x50,0x03,0xA9,0x7D,0x19,0x62,0xE6,0x9A, + 0x45,0x9D,0x40,0x87,0x15,0xEB,0xC9,0x0B, + 0xEC,0x67,0xFD,0xEA,0xBF,0xF7,0x96,0x5B, + 0xC2,0x1C,0xAE,0x6A,0x5A,0x41,0x02,0x4F, + 0x5C,0xF4,0x34,0x08,0x93,0x73,0x53,0x3F, + 0x0C,0x52,0x65,0x5E,0x28,0xA1,0x0F,0xB5, + 0x09,0x36,0x9B,0x3D,0x26,0x69,0xCD,0x9F, + 0x1B,0x9E,0x74,0x2E,0x2D,0xB2,0xEE,0xFB, + 0xF6,0x4D,0x61,0xCE,0x7B,0x3E,0x71,0x97, + 0xF5,0x68,0x00,0x2C,0x60,0x1F,0xC8,0xED, + 0xBE,0x46,0xD9,0x4B,0xDE,0xD4,0xE8,0x4A, + 0x6B,0x2A,0xE5,0x16,0xC5,0xD7,0x55,0x94, + 0xCF,0x10,0x06,0x81,0xF0,0x44,0xBA,0xE3, + 0xF3,0xFE,0xC0,0x8A,0xAD,0xBC,0x48,0x04, + 0xDF,0xC1,0x75,0x63,0x30,0x1A,0x0E,0x6D, + 0x4C,0x14,0x35,0x2F,0xE1,0xA2,0xCC,0x39, + 0x57,0xF2,0x82,0x47,0xAC,0xE7,0x2B,0x95, + 0xA0,0x98,0xD1,0x7F,0x66,0x7E,0xAB,0x83, + 0xCA,0x29,0xD3,0x3C,0x79,0xE2,0x1D,0x76, + 0x3B,0x56,0x4E,0x1E,0xDB,0x0A,0x6C,0xE4, + 0x5D,0x6E,0xEF,0xA6,0xA8,0xA4,0x37,0x8B, + 0x32,0x43,0x59,0xB7,0x8C,0x64,0xD2,0xE0, + 0xB4,0xFA,0x07,0x25,0xAF,0x8E,0xE9,0x18, + 0xD5,0x88,0x6F,0x72,0x24,0xF1,0xC7,0x51, + 0x23,0x7C,0x9C,0x21,0xDD,0xDC,0x86,0x85, + 0x90,0x42,0xC4,0xAA,0xD8,0x05,0x01,0x12, + 0xA3,0x5F,0xF9,0xD0,0x91,0x58,0x27,0xB9, + 0x38,0x13,0xB3,0x33,0xBB,0x70,0x89,0xA7, + 0xB6,0x22,0x92,0x20,0x49,0xFF,0x78,0x7A, + 0x8F,0xF8,0x80,0x17,0xDA,0x31,0xC6,0xB8, + 0xC3,0xB0,0x77,0x11,0xCB,0xFC,0xD6,0x3A +}; + +const BYTE TKIP_Sbox_Upper[256] = { + 0xC6,0xF8,0xEE,0xF6,0xFF,0xD6,0xDE,0x91, + 0x60,0x02,0xCE,0x56,0xE7,0xB5,0x4D,0xEC, + 0x8F,0x1F,0x89,0xFA,0xEF,0xB2,0x8E,0xFB, + 0x41,0xB3,0x5F,0x45,0x23,0x53,0xE4,0x9B, + 0x75,0xE1,0x3D,0x4C,0x6C,0x7E,0xF5,0x83, + 0x68,0x51,0xD1,0xF9,0xE2,0xAB,0x62,0x2A, + 0x08,0x95,0x46,0x9D,0x30,0x37,0x0A,0x2F, + 0x0E,0x24,0x1B,0xDF,0xCD,0x4E,0x7F,0xEA, + 0x12,0x1D,0x58,0x34,0x36,0xDC,0xB4,0x5B, + 0xA4,0x76,0xB7,0x7D,0x52,0xDD,0x5E,0x13, + 0xA6,0xB9,0x00,0xC1,0x40,0xE3,0x79,0xB6, + 0xD4,0x8D,0x67,0x72,0x94,0x98,0xB0,0x85, + 0xBB,0xC5,0x4F,0xED,0x86,0x9A,0x66,0x11, + 0x8A,0xE9,0x04,0xFE,0xA0,0x78,0x25,0x4B, + 0xA2,0x5D,0x80,0x05,0x3F,0x21,0x70,0xF1, + 0x63,0x77,0xAF,0x42,0x20,0xE5,0xFD,0xBF, + 0x81,0x18,0x26,0xC3,0xBE,0x35,0x88,0x2E, + 0x93,0x55,0xFC,0x7A,0xC8,0xBA,0x32,0xE6, + 0xC0,0x19,0x9E,0xA3,0x44,0x54,0x3B,0x0B, + 0x8C,0xC7,0x6B,0x28,0xA7,0xBC,0x16,0xAD, + 0xDB,0x64,0x74,0x14,0x92,0x0C,0x48,0xB8, + 0x9F,0xBD,0x43,0xC4,0x39,0x31,0xD3,0xF2, + 0xD5,0x8B,0x6E,0xDA,0x01,0xB1,0x9C,0x49, + 0xD8,0xAC,0xF3,0xCF,0xCA,0xF4,0x47,0x10, + 0x6F,0xF0,0x4A,0x5C,0x38,0x57,0x73,0x97, + 0xCB,0xA1,0xE8,0x3E,0x96,0x61,0x0D,0x0F, + 0xE0,0x7C,0x71,0xCC,0x90,0x06,0xF7,0x1C, + 0xC2,0x6A,0xAE,0x69,0x17,0x99,0x3A,0x27, + 0xD9,0xEB,0x2B,0x22,0xD2,0xA9,0x07,0x33, + 0x2D,0x3C,0x15,0xC9,0x87,0xAA,0x50,0xA5, + 0x03,0x59,0x09,0x1A,0x65,0xD7,0x84,0xD0, + 0x82,0x29,0x5A,0x1E,0x7B,0xA8,0x6D,0x2C +}; + + +//STKIPKeyManagement sTKIPKeyTable[MAX_TKIP_KEY]; + +/*--------------------- Static Functions --------------------------*/ +unsigned int tkip_sbox(unsigned int index); +unsigned int rotr1(unsigned int a); + +/*--------------------- Export Variables --------------------------*/ + +/************************************************************/ +/* tkip_sbox() */ +/* Returns a 16 bit value from a 64K entry table. The Table */ +/* is synthesized from two 256 entry byte wide tables. */ +/************************************************************/ +unsigned int tkip_sbox(unsigned int index) +{ + unsigned int index_low; + unsigned int index_high; + unsigned int left, right; + + index_low = (index % 256); + index_high = ((index >> 8) % 256); + + left = TKIP_Sbox_Lower[index_low] + (TKIP_Sbox_Upper[index_low] * 256); + right = TKIP_Sbox_Upper[index_high] + (TKIP_Sbox_Lower[index_high] * 256); + + return (left ^ right); +}; + + +unsigned int rotr1(unsigned int a) +{ + unsigned int b; + + if ((a & 0x01) == 0x01) { + b = (a >> 1) | 0x8000; + } else { + b = (a >> 1) & 0x7fff; + } + b = b % 65536; + return b; +} + + +/* + * Description: Caculate RC4Key fom TK, TA, and TSC + * + * Parameters: + * In: + * pbyTKey - TKey + * pbyTA - TA + * dwTSC - TSC + * Out: + * pbyRC4Key - RC4Key + * + * Return Value: none + * + */ +VOID TKIPvMixKey( + PBYTE pbyTKey, + PBYTE pbyTA, + WORD wTSC15_0, + DWORD dwTSC47_16, + PBYTE pbyRC4Key + ) +{ + unsigned int p1k[5]; +// unsigned int ttak0, ttak1, ttak2, ttak3, ttak4; + unsigned int tsc0, tsc1, tsc2; + unsigned int ppk0, ppk1, ppk2, ppk3, ppk4, ppk5; + unsigned long int pnl,pnh; + + int i, j; + + pnl = wTSC15_0; + pnh = dwTSC47_16; + + tsc0 = (unsigned int)((pnh >> 16) % 65536); /* msb */ + tsc1 = (unsigned int)(pnh % 65536); + tsc2 = (unsigned int)(pnl % 65536); /* lsb */ + + /* Phase 1, step 1 */ + p1k[0] = tsc1; + p1k[1] = tsc0; + p1k[2] = (unsigned int)(pbyTA[0] + (pbyTA[1]*256)); + p1k[3] = (unsigned int)(pbyTA[2] + (pbyTA[3]*256)); + p1k[4] = (unsigned int)(pbyTA[4] + (pbyTA[5]*256)); + + /* Phase 1, step 2 */ + for (i=0; i<8; i++) { + j = 2*(i & 1); + p1k[0] = (p1k[0] + tkip_sbox( (p1k[4] ^ ((256*pbyTKey[1+j]) + pbyTKey[j])) % 65536 )) % 65536; + p1k[1] = (p1k[1] + tkip_sbox( (p1k[0] ^ ((256*pbyTKey[5+j]) + pbyTKey[4+j])) % 65536 )) % 65536; + p1k[2] = (p1k[2] + tkip_sbox( (p1k[1] ^ ((256*pbyTKey[9+j]) + pbyTKey[8+j])) % 65536 )) % 65536; + p1k[3] = (p1k[3] + tkip_sbox( (p1k[2] ^ ((256*pbyTKey[13+j]) + pbyTKey[12+j])) % 65536 )) % 65536; + p1k[4] = (p1k[4] + tkip_sbox( (p1k[3] ^ (((256*pbyTKey[1+j]) + pbyTKey[j]))) % 65536 )) % 65536; + p1k[4] = (p1k[4] + i) % 65536; + } + /* Phase 2, Step 1 */ + ppk0 = p1k[0]; + ppk1 = p1k[1]; + ppk2 = p1k[2]; + ppk3 = p1k[3]; + ppk4 = p1k[4]; + ppk5 = (p1k[4] + tsc2) % 65536; + + /* Phase2, Step 2 */ + ppk0 = ppk0 + tkip_sbox( (ppk5 ^ ((256*pbyTKey[1]) + pbyTKey[0])) % 65536); + ppk1 = ppk1 + tkip_sbox( (ppk0 ^ ((256*pbyTKey[3]) + pbyTKey[2])) % 65536); + ppk2 = ppk2 + tkip_sbox( (ppk1 ^ ((256*pbyTKey[5]) + pbyTKey[4])) % 65536); + ppk3 = ppk3 + tkip_sbox( (ppk2 ^ ((256*pbyTKey[7]) + pbyTKey[6])) % 65536); + ppk4 = ppk4 + tkip_sbox( (ppk3 ^ ((256*pbyTKey[9]) + pbyTKey[8])) % 65536); + ppk5 = ppk5 + tkip_sbox( (ppk4 ^ ((256*pbyTKey[11]) + pbyTKey[10])) % 65536); + + ppk0 = ppk0 + rotr1(ppk5 ^ ((256*pbyTKey[13]) + pbyTKey[12])); + ppk1 = ppk1 + rotr1(ppk0 ^ ((256*pbyTKey[15]) + pbyTKey[14])); + ppk2 = ppk2 + rotr1(ppk1); + ppk3 = ppk3 + rotr1(ppk2); + ppk4 = ppk4 + rotr1(ppk3); + ppk5 = ppk5 + rotr1(ppk4); + + /* Phase 2, Step 3 */ + pbyRC4Key[0] = (tsc2 >> 8) % 256; + pbyRC4Key[1] = (((tsc2 >> 8) % 256) | 0x20) & 0x7f; + pbyRC4Key[2] = tsc2 % 256; + pbyRC4Key[3] = ((ppk5 ^ ((256*pbyTKey[1]) + pbyTKey[0])) >> 1) % 256; + + pbyRC4Key[4] = ppk0 % 256; + pbyRC4Key[5] = (ppk0 >> 8) % 256; + + pbyRC4Key[6] = ppk1 % 256; + pbyRC4Key[7] = (ppk1 >> 8) % 256; + + pbyRC4Key[8] = ppk2 % 256; + pbyRC4Key[9] = (ppk2 >> 8) % 256; + + pbyRC4Key[10] = ppk3 % 256; + pbyRC4Key[11] = (ppk3 >> 8) % 256; + + pbyRC4Key[12] = ppk4 % 256; + pbyRC4Key[13] = (ppk4 >> 8) % 256; + + pbyRC4Key[14] = ppk5 % 256; + pbyRC4Key[15] = (ppk5 >> 8) % 256; +} diff --git a/drivers/staging/vt6655/tkip.h b/drivers/staging/vt6655/tkip.h new file mode 100644 index 000000000000..dc8382b67019 --- /dev/null +++ b/drivers/staging/vt6655/tkip.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * File: tkip.h + * + * Purpose: Implement functions for 802.11i TKIP + * + * Author: Jerry Chen + * + * Date: Mar. 11, 2003 + * + */ + + +#ifndef __TKIP_H__ +#define __TKIP_H__ + +#if !defined(__TTYPE_H__) +#include "ttype.h" +#endif + +#if !defined(__TETHER_H__) +#include "tether.h" +#endif + + + +/*--------------------- Export Definitions -------------------------*/ +#define TKIP_KEY_LEN 16 + +/*--------------------- Export Types ------------------------------*/ + +/*--------------------- Export Macros ------------------------------*/ + +/*--------------------- Export Classes ----------------------------*/ + +/*--------------------- Export Variables --------------------------*/ + +/*--------------------- Export Functions --------------------------*/ +#ifdef __cplusplus +extern "C" { /* Assume C declarations for C++ */ +#endif /* __cplusplus */ + +VOID TKIPvMixKey( + PBYTE pbyTKey, + PBYTE pbyTA, + WORD wTSC15_0, + DWORD dwTSC47_16, + PBYTE pbyRC4Key + ); + +#ifdef __cplusplus +} /* End of extern "C" { */ +#endif /* __cplusplus */ + + +#endif // __TKIP_H__ + + + diff --git a/drivers/staging/vt6655/tmacro.h b/drivers/staging/vt6655/tmacro.h new file mode 100644 index 000000000000..3d932a258dd1 --- /dev/null +++ b/drivers/staging/vt6655/tmacro.h @@ -0,0 +1,152 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * File: tmacro.h + * + * Purpose: define basic common types and macros + * + * Author: Tevin Chen + * + * Date: May 21, 1996 + * + */ + + +#ifndef __TMACRO_H__ +#define __TMACRO_H__ + + +#if !defined(__TTYPE_H__) +#include "ttype.h" +#endif + + + + +/****** Common helper macros ***********************************************/ + +#if !defined(LONIBBLE) +#define LONIBBLE(b) ((BYTE)(b) & 0x0F) +#endif +#if !defined(HINIBBLE) +#define HINIBBLE(b) ((BYTE)(((WORD)(b) >> 4) & 0x0F)) +#endif + +#if !defined(LOBYTE) +#define LOBYTE(w) ((BYTE)(w)) +#endif +#if !defined(HIBYTE) +#define HIBYTE(w) ((BYTE)(((WORD)(w) >> 8) & 0xFF)) +#endif + +#if !defined(LOWORD) +#define LOWORD(d) ((WORD)(d)) +#endif +#if !defined(HIWORD) +#define HIWORD(d) ((WORD)((((DWORD)(d)) >> 16) & 0xFFFF)) +#endif + +#define LODWORD(q) ((q).u.dwLowDword) +#define HIDWORD(q) ((q).u.dwHighDword) + + + +#if !defined(MAKEBYTE) +#define MAKEBYTE(ln, hn) ((BYTE)(((BYTE)(ln) & 0x0F) | ((BYTE)(hn) << 4))) +#endif +#if !defined(MAKEWORD) +#define MAKEWORD(lb, hb) ((WORD)(((BYTE)(lb)) | (((WORD)((BYTE)(hb))) << 8))) +#endif +#if !defined(MAKEDWORD) +#define MAKEDWORD(lw, hw) ((DWORD)(((WORD)(lw)) | (((DWORD)((WORD)(hw))) << 16))) +#endif +#if !defined(MAKEQWORD) +#define MAKEQWORD(ld, hd, pq) {pq->u.dwLowDword = ld; pq->u.dwHighDword = hd;} +#endif + +#if !defined(MAKELONG) +#define MAKELONG(low, high) ((LONG)(((WORD)(low)) | (((DWORD)((WORD)(high))) << 16))) +#endif + + + +// Bytes Reverse: big endian to little endian convert +#if !defined(REVWORD) +#define REVWORD(w) ((WORD)( ((WORD)(w) >> 8) | ((WORD)(w) << 8) )) +#endif +#if !defined(REVDWORD) +#define REVDWORD(d) (MAKEDWORD(MAKEWORD(HIBYTE(HIWORD(d)),LOBYTE(HIWORD(d))),MAKEWORD(HIBYTE(LOWORD(d)),LOBYTE(LOWORD(d))))) +#endif + +/* map to known network names */ +/* +#define ntohs(x) REVWORD(x) +#define ntohl(x) REVDWORD(x) +#define htons(x) REVWORD(x) +#define htonl(x) REVDWORD(x) +*/ + + +/* +#ifndef NOMINMAX +#ifndef max +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif +#ifndef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif +#endif // NOMINMAX +*/ + + + +/****** Misc macros ********************************************************/ + +// get the field offset in the type(struct, class, ...) +#define OFFSET(type, field) ((int)(&((type NEAR*)1)->field)-1) + + +/* string equality shorthand */ +#define STR_EQ(x, y) (strcmp(x, y) == 0) +#define STR_NE(x, y) (strcmp(x, y) != 0) + + +// calculate element # of array +#define ELEMENT_NUM(array) (sizeof(array) / sizeof(array[0])) +//#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) + + +// null statement +#define NULL_FUNC() + + +/* Since not all compilers support structure assignment, the ASSIGN() + * macro is used. This controls how it's actually implemented. + */ +#ifdef NOSTRUCTASSIGN /* Version for old compilers that don't support it */ +#define ASSIGN(a,b) memcpy((char *)&(a),(char *)&(b),sizeof(b); +#else /* Version for compilers that do */ +#define ASSIGN(a,b) ((a) = (b)) +#endif + + + + +#endif // __TMACRO_H__ + + diff --git a/drivers/staging/vt6655/tpci.h b/drivers/staging/vt6655/tpci.h new file mode 100644 index 000000000000..4a1c8ed75ca6 --- /dev/null +++ b/drivers/staging/vt6655/tpci.h @@ -0,0 +1,117 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * File: tpci.h + * + * Purpose: PCI routines + * + * Author: Tevin Chen + * + * Date: May 21, 1996 + * + */ + + +#ifndef __TPCI_H__ +#define __TPCI_H__ + +#if !defined(__TTYPE_H__) +#include "ttype.h" +#endif + + + + +/*--------------------- Export Definitions -------------------------*/ +#define MAX_PCI_BUS 4 // max. # of PCI bus that we support +#define MAX_PCI_DEVICE 32 // max. # of PCI devices + + +// +// Registers in the PCI configuration space +// +#define PCI_REG_VENDOR_ID 0x00 // +#define PCI_REG_DEVICE_ID 0x02 // +#define PCI_REG_COMMAND 0x04 // +#define PCI_REG_STATUS 0x06 // +#define PCI_REG_REV_ID 0x08 // +#define PCI_REG_CLASS_CODE 0x09 // +#define PCI_REG_CACHELINE_SIZE 0x0C // +#define PCI_REG_LAT_TIMER 0x0D // +#define PCI_REG_HDR_TYPE 0x0E // +#define PCI_REG_BIST 0x0F // + +#define PCI_REG_BAR0 0x10 // +#define PCI_REG_BAR1 0x14 // +#define PCI_REG_BAR2 0x18 // +#define PCI_REG_CARDBUS_CIS_PTR 0x28 // + +#define PCI_REG_SUB_VEN_ID 0x2C // +#define PCI_REG_SUB_SYS_ID 0x2E // +#define PCI_REG_EXP_ROM_BAR 0x30 // +#define PCI_REG_CAP 0x34 // + +#define PCI_REG_INT_LINE 0x3C // +#define PCI_REG_INT_PIN 0x3D // +#define PCI_REG_MIN_GNT 0x3E // +#define PCI_REG_MAX_LAT 0x3F // + +#define PCI_REG_MAX_SIZE 0x100 // maximun total PCI registers + + +// +// Bits in the COMMAND register +// +#define COMMAND_BUSM 0x04 // +#define COMMAND_WAIT 0x80 // + +/*--------------------- Export Types ------------------------------*/ + +/*--------------------- Export Macros ------------------------------*/ + +// macro MAKE Bus Dev Fun ID into WORD +#define MAKE_BDF_TO_WORD(byBusId, byDevId, byFunId) \ + MAKEWORD( \ + ((((BYTE)(byDevId)) & 0x1F) << 3) + \ + (((BYTE)(byFunId)) & 0x07), \ + (byBusId) \ + ) + +#define GET_BUSID(wBusDevFunId) \ + HIBYTE(wBusDevFunId) + +#define GET_DEVID(wBusDevFunId) \ + (LOBYTE(wBusDevFunId) >> 3) + +#define GET_FUNID(wBusDevFunId) \ + (LOBYTE(wBusDevFunId) & 0x07) + + +/*--------------------- Export Classes ----------------------------*/ + +/*--------------------- Export Variables --------------------------*/ + +/*--------------------- Export Functions --------------------------*/ + + + + +#endif // __TPCI_H__ + + diff --git a/drivers/staging/vt6655/ttype.h b/drivers/staging/vt6655/ttype.h new file mode 100644 index 000000000000..1f26702cabf6 --- /dev/null +++ b/drivers/staging/vt6655/ttype.h @@ -0,0 +1,386 @@ +/* + * File: ttype.h + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Purpose: define basic common types and macros + * + * Author: Tevin Chen + * + * Date: May 21, 1996 + * + */ + + +#ifndef __TTYPE_H__ +#define __TTYPE_H__ + + +/******* Common definitions and typedefs ***********************************/ + +#ifndef VOID +#define VOID void +#endif + +#ifndef CONST +#define CONST const +#endif + +#ifndef STATIC +#define STATIC static +#endif + +#ifndef IN +#define IN +#endif + +#ifndef OUT +#define OUT +#endif + +#ifndef TxInSleep +#define TxInSleep +#endif +#if! defined(__CPU8051) +typedef int BOOL; +#else // __CPU8051 +#define BOOL int +#endif // __CPU8051 + +#if !defined(TRUE) +#define TRUE 1 +#endif +#if !defined(FALSE) +#define FALSE 0 +#endif + + +#if !defined(SUCCESS) +#define SUCCESS 0 +#endif +#if !defined(FAILED) +#define FAILED -1 +#endif + +//2007-0809-01by MikeLiu +#ifndef update_BssList +#define update_BssList +#endif + + + +#ifndef WPA_SM_Transtatus +#define WPA_SM_Transtatus +#endif + +#ifndef Calcu_LinkQual +#define Calcu_LinkQual +#endif + +#ifndef Calcu_LinkQual +#define Calcu_LinkQual +#endif + +/****** Simple typedefs ***************************************************/ + +#if! defined(__CPU8051) + +/* These lines assume that your compiler's longs are 32 bits and + * shorts are 16 bits. It is already assumed that chars are 8 bits, + * but it doesn't matter if they're signed or unsigned. + */ + +typedef signed char I8; /* 8-bit signed integer */ +typedef signed short I16; /* 16-bit signed integer */ +typedef signed long I32; /* 32-bit signed integer */ + +typedef unsigned char U8; /* 8-bit unsigned integer */ +typedef unsigned short U16; /* 16-bit unsigned integer */ +typedef unsigned long U32; /* 32-bit unsigned integer */ + + +#if defined(__WIN32) +typedef signed __int64 I64; /* 64-bit signed integer */ +typedef unsigned __int64 U64; /* 64-bit unsigned integer */ +#endif // __WIN32 + + +typedef char CHAR; +typedef signed short SHORT; +typedef signed int INT; +typedef signed long LONG; + +typedef unsigned char UCHAR; +typedef unsigned short USHORT; +typedef unsigned int UINT; +typedef unsigned long ULONG; +typedef unsigned long long ULONGLONG; //64 bit +typedef unsigned long long ULONGULONG; + + + +typedef unsigned char BYTE; // 8-bit +typedef unsigned short WORD; // 16-bit +typedef unsigned long DWORD; // 32-bit + +// QWORD is for those situation that we want +// an 8-byte-aligned 8 byte long structure +// which is NOT really a floating point number. +typedef union tagUQuadWord { + struct { + DWORD dwLowDword; + DWORD dwHighDword; + } u; + double DoNotUseThisField; +} UQuadWord; +typedef UQuadWord QWORD; // 64-bit + + + +#ifndef _TCHAR_DEFINED +typedef char TCHAR; +typedef char* PTCHAR; +typedef unsigned char TBYTE; +typedef unsigned char* PTBYTE; +#define _TCHAR_DEFINED +#endif + +#else // __CPU8051 + +#define U8 unsigned char +#define U16 unsigned short +#define U32 unsigned long + +#define USHORT unsigned short +#define UINT unsigned int + +#define BYTE unsigned char +#define WORD unsigned short +#define DWORD unsigned long + + +#endif // __CPU8051 + + +// maybe this should be defined in +#define U8_MAX 0xFFU +#define U16_MAX 0xFFFFU +#define U32_MAX 0xFFFFFFFFUL + +#define BYTE_MAX 0xFFU +#define WORD_MAX 0xFFFFU +#define DWORD_MAX 0xFFFFFFFFUL + + + + +/******* 32-bit vs. 16-bit definitions and typedefs ************************/ + +#if !defined(NULL) +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *)0) +#endif // __cplusplus +#endif // !NULL + + + + +#if defined(__WIN32) || defined(__CPU8051) + +#if !defined(FAR) +#define FAR +#endif +#if !defined(NEAR) +#define NEAR +#endif +#if !defined(DEF) +#define DEF +#endif +#if !defined(CALLBACK) +#define CALLBACK +#endif + +#else // !__WIN32__ + +#if !defined(FAR) +#define FAR +#endif +#if !defined(NEAR) +#define NEAR +#endif +#if !defined(DEF) +// default pointer type is FAR, if you want near pointer just redefine it to NEAR +#define DEF +#endif +#if !defined(CALLBACK) +#define CALLBACK +#endif + +#endif // !__WIN32__ + + + + +/****** Common pointer types ***********************************************/ + +#if! defined(__CPU8051) + +typedef signed char DEF* PI8; +typedef signed short DEF* PI16; +typedef signed long DEF* PI32; + +typedef unsigned char DEF* PU8; +typedef unsigned short DEF* PU16; +typedef unsigned long DEF* PU32; + +#if defined(__WIN32) +typedef signed __int64 DEF* PI64; +typedef unsigned __int64 DEF* PU64; +#endif // __WIN32 + +#if !defined(_WIN64) +typedef unsigned long ULONG_PTR; // 32-bit +typedef unsigned long DWORD_PTR; // 32-bit +#endif // _WIN64 + + +// boolean pointer +typedef int DEF* PBOOL; +typedef int NEAR* NPBOOL; +typedef int FAR* LPBOOL; + +typedef int DEF* PINT; +typedef int NEAR* NPINT; +typedef int FAR* LPINT; +typedef const int DEF* PCINT; +typedef const int NEAR* NPCINT; +typedef const int FAR* LPCINT; + +typedef unsigned int DEF* PUINT; +typedef const unsigned int DEF* PCUINT; + +typedef long DEF* PLONG; +typedef long NEAR* NPLONG; +typedef long FAR* LPLONG; +//typedef const long DEF* PCLONG; +typedef const long NEAR* NPCLONG; +typedef const long FAR* LPCLONG; + +typedef BYTE DEF* PBYTE; +typedef BYTE NEAR* NPBYTE; +typedef BYTE FAR* LPBYTE; +typedef const BYTE DEF* PCBYTE; +typedef const BYTE NEAR* NPCBYTE; +typedef const BYTE FAR* LPCBYTE; + +typedef WORD DEF* PWORD; +typedef WORD NEAR* NPWORD; +typedef WORD FAR* LPWORD; +typedef const WORD DEF* PCWORD; +typedef const WORD NEAR* NPCWORD; +typedef const WORD FAR* LPCWORD; + +typedef DWORD DEF* PDWORD; +typedef DWORD NEAR* NPDWORD; +typedef DWORD FAR* LPDWORD; +typedef const DWORD DEF* PCDWORD; +typedef const DWORD NEAR* NPCDWORD; +typedef const DWORD FAR* LPCDWORD; + +typedef QWORD DEF* PQWORD; +typedef QWORD NEAR* NPQWORD; +typedef QWORD FAR* LPQWORD; +typedef const QWORD DEF* PCQWORD; +typedef const QWORD NEAR* NPCQWORD; +typedef const QWORD FAR* LPCQWORD; + +typedef void DEF* PVOID; +typedef void NEAR* NPVOID; +typedef void FAR* LPVOID; + +// handle declaration +#ifdef STRICT +typedef void *HANDLE; +#else +typedef PVOID HANDLE; +#endif + +// +// ANSI (Single-byte Character) types +// +typedef char DEF* PCH; +typedef char NEAR* NPCH; +typedef char FAR* LPCH; +typedef const char DEF* PCCH; +typedef const char NEAR* NPCCH; +typedef const char FAR* LPCCH; + +typedef char DEF* PSTR; +typedef char NEAR* NPSTR; +typedef char FAR* LPSTR; +typedef const char DEF* PCSTR; +typedef const char NEAR* NPCSTR; +typedef const char FAR* LPCSTR; + +#endif // !__CPU8051 + + + + +/****** Misc definitions, types ********************************************/ + +// parameter prefix +#ifndef IN +#define IN +#endif + +#ifndef OUT +#define OUT +#endif + + +// unreferenced parameter macro to avoid warning message in MS C +#if defined(__TURBOC__) + +//you should use "#pragma argsused" to avoid warning message in Borland C +#ifndef UNREFERENCED_PARAMETER +#define UNREFERENCED_PARAMETER(x) +#endif + +#else + +#ifndef UNREFERENCED_PARAMETER +//#define UNREFERENCED_PARAMETER(x) x +#define UNREFERENCED_PARAMETER(x) +#endif + +#endif + + +// in-line assembly prefix +#if defined(__TURBOC__) +#define ASM asm +#else // !__TURBOC__ +#define ASM _asm +#endif // !__TURBOC__ + + + + +#endif // __TTYPE_H__ + + diff --git a/drivers/staging/vt6655/umem.h b/drivers/staging/vt6655/umem.h new file mode 100644 index 000000000000..2c3eafa038e7 --- /dev/null +++ b/drivers/staging/vt6655/umem.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * File: umem.h + * + * Purpose: Define Memory macros + * + * Author: Tevin Chen + * + * Date: Mar 17, 1997 + * + */ + + +#ifndef __UMEM_H__ +#define __UMEM_H__ + +#if !defined(__TTYPE_H__) +#include "ttype.h" +#endif + + + +/*--------------------- Export Definitions -------------------------*/ +// 4-byte memory tag +#define MEM_TAG 'mTEW' + +// Macros used for memory allocation and deallocation. + + + +#define ZERO_MEMORY(Destination,Length) { \ + memset((PVOID)(Destination), \ + 0, \ + (ULONG)(Length) \ + ); \ +} + +#define MEMvCopy(pvDest, pvSource, uCount) { \ + memcpy((PVOID)(pvDest), \ + (PVOID)(pvSource), \ + (ULONG)(uCount) \ + ); \ +} + + +#define MEMEqualMemory(Destination,Source,Length) (!memcmp((Destination),(Source),(Length))) +/*--------------------- Export Classes ----------------------------*/ + +/*--------------------- Export Variables --------------------------*/ + +/*--------------------- Export Functions --------------------------*/ + + + + +#endif // __UMEM_H__ + + diff --git a/drivers/staging/vt6655/upc.h b/drivers/staging/vt6655/upc.h new file mode 100644 index 000000000000..113fc2c88c11 --- /dev/null +++ b/drivers/staging/vt6655/upc.h @@ -0,0 +1,171 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * File: upc.h + * + * Purpose: Macros to access device + * + * Author: Tevin Chen + * + * Date: Mar 17, 1997 + * + */ + + +#ifndef __UPC_H__ +#define __UPC_H__ + +#if !defined(DEVICE_H) +#include "device.h" +#endif +#if !defined(__TTYPE_H__) +#include "ttype.h" +#endif + +/*--------------------- Export Definitions -------------------------*/ + + +// +// For IO mapped +// + +#ifdef IO_MAP + +#define VNSvInPortB(dwIOAddress, pbyData) { \ + *(pbyData) = inb(dwIOAddress); \ +} + + +#define VNSvInPortW(dwIOAddress, pwData) { \ + *(pwData) = inw(dwIOAddress); \ +} + +#define VNSvInPortD(dwIOAddress, pdwData) { \ + *(pdwData) = inl(dwIOAddress); \ +} + + +#define VNSvOutPortB(dwIOAddress, byData) { \ + outb(byData, dwIOAddress); \ +} + + +#define VNSvOutPortW(dwIOAddress, wData) { \ + outw(wData, dwIOAddress); \ +} + +#define VNSvOutPortD(dwIOAddress, dwData) { \ + outl(dwData, dwIOAddress); \ +} + +#else + +// +// For memory mapped IO +// + + +#define VNSvInPortB(dwIOAddress, pbyData) { \ + volatile BYTE* pbyAddr = ((PBYTE)(dwIOAddress)); \ + *(pbyData) = readb(pbyAddr); \ +} + + +#define VNSvInPortW(dwIOAddress, pwData) { \ + volatile WORD* pwAddr = ((PWORD)(dwIOAddress)); \ + *(pwData) = readw(pwAddr); \ +} + +#define VNSvInPortD(dwIOAddress, pdwData) { \ + volatile DWORD* pdwAddr = ((PDWORD)(dwIOAddress)); \ + *(pdwData) = readl(pdwAddr); \ +} + + +#define VNSvOutPortB(dwIOAddress, byData) { \ + volatile BYTE* pbyAddr = ((PBYTE)(dwIOAddress)); \ + writeb((BYTE)byData, pbyAddr); \ +} + + +#define VNSvOutPortW(dwIOAddress, wData) { \ + volatile WORD* pwAddr = ((PWORD)(dwIOAddress)); \ + writew((WORD)wData, pwAddr); \ +} + +#define VNSvOutPortD(dwIOAddress, dwData) { \ + volatile DWORD* pdwAddr = ((PDWORD)(dwIOAddress)); \ + writel((DWORD)dwData, pdwAddr); \ +} + +#endif + + +// +// ALWAYS IO-Mapped IO when in 16-bit/32-bit environment +// +#define PCBvInPortB(dwIOAddress, pbyData) { \ + *(pbyData) = inb(dwIOAddress); \ +} + +#define PCBvInPortW(dwIOAddress, pwData) { \ + *(pwData) = inw(dwIOAddress); \ +} + +#define PCBvInPortD(dwIOAddress, pdwData) { \ + *(pdwData) = inl(dwIOAddress); \ +} + +#define PCBvOutPortB(dwIOAddress, byData) { \ + outb(byData, dwIOAddress); \ +} + +#define PCBvOutPortW(dwIOAddress, wData) { \ + outw(wData, dwIOAddress); \ +} + +#define PCBvOutPortD(dwIOAddress, dwData) { \ + outl(dwData, dwIOAddress); \ +} + + +#define PCAvDelayByIO(uDelayUnit) { \ + BYTE byData; \ + ULONG ii; \ + \ + if (uDelayUnit <= 50) { \ + udelay(uDelayUnit); \ + } \ + else { \ + for (ii = 0; ii < (uDelayUnit); ii++) \ + byData = inb(0x61); \ + } \ +} + + +/*--------------------- Export Classes ----------------------------*/ + +/*--------------------- Export Variables --------------------------*/ + +/*--------------------- Export Functions --------------------------*/ + + + + +#endif // __UPC_H__ + diff --git a/drivers/staging/vt6655/vntconfiguration.dat b/drivers/staging/vt6655/vntconfiguration.dat new file mode 100644 index 000000000000..0064ddce7c11 --- /dev/null +++ b/drivers/staging/vt6655/vntconfiguration.dat @@ -0,0 +1 @@ +ZONETYPE=EUROPE \ No newline at end of file diff --git a/drivers/staging/vt6655/vntwifi.c b/drivers/staging/vt6655/vntwifi.c new file mode 100644 index 000000000000..58a1ba0eac07 --- /dev/null +++ b/drivers/staging/vt6655/vntwifi.c @@ -0,0 +1,832 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * File: vntwifi.c + * + * Purpose: export functions for vntwifi lib + * + * Functions: + * + * Revision History: + * + * Author: Yiching Chen + * + * Date: feb. 2, 2005 + * + */ + +#if !defined(__VNTWIFI_H__) +#include "vntwifi.h" +#endif +#if !defined(__UMEM_H__) +#include "umem.h" +#endif + + +#if !defined(__TBIT_H__) +#include "tbit.h" +#endif +#if !defined(__IEEE11h_H__) +#include "IEEE11h.h" +#endif +#if !defined(__COUNTRY_H__) +#include "country.h" +#endif +#if !defined(__DEVICE_H__) +#include "device.h" +#endif +#if !defined(__WMGR_H__) +#include "wmgr.h" +#endif +#if !defined(__DATARATE_H__) +#include "datarate.h" +#endif +//#define PLICE_DEBUG + +/*--------------------- Static Definitions -------------------------*/ +//static int msglevel =MSG_LEVEL_DEBUG; +//static int msglevel =MSG_LEVEL_INFO; + +/*--------------------- Static Classes ----------------------------*/ + +/*--------------------- Static Variables --------------------------*/ + +/*--------------------- Static Functions --------------------------*/ + +/*--------------------- Export Variables --------------------------*/ + +/*--------------------- Export Functions --------------------------*/ + +/*+ + * + * Description: + * Set Operation Mode + * + * Parameters: + * In: + * pMgmtHandle - pointer to management object + * eOPMode - Opreation Mode + * Out: + * none + * + * Return Value: none + * +-*/ +VOID +VNTWIFIvSetOPMode ( + IN PVOID pMgmtHandle, + IN WMAC_CONFIG_MODE eOPMode + ) +{ + PSMgmtObject pMgmt = (PSMgmtObject)pMgmtHandle; + + pMgmt->eConfigMode = eOPMode; +} + + +/*+ + * + * Description: + * Set Operation Mode + * + * Parameters: + * In: + * pMgmtHandle - pointer to management object + * wBeaconPeriod - Beacon Period + * wATIMWindow - ATIM window + * uChannel - channel number + * Out: + * none + * + * Return Value: none + * +-*/ +VOID +VNTWIFIvSetIBSSParameter ( + IN PVOID pMgmtHandle, + IN WORD wBeaconPeriod, + IN WORD wATIMWindow, + IN UINT uChannel + ) +{ + PSMgmtObject pMgmt = (PSMgmtObject)pMgmtHandle; + + pMgmt->wIBSSBeaconPeriod = wBeaconPeriod; + pMgmt->wIBSSATIMWindow = wATIMWindow; + pMgmt->uIBSSChannel = uChannel; +} + +/*+ + * + * Description: + * Get current SSID + * + * Parameters: + * In: + * pMgmtHandle - pointer to management object + * Out: + * none + * + * Return Value: current SSID pointer. + * +-*/ +PWLAN_IE_SSID +VNTWIFIpGetCurrentSSID ( + IN PVOID pMgmtHandle + ) +{ + PSMgmtObject pMgmt = (PSMgmtObject)pMgmtHandle; + return((PWLAN_IE_SSID) pMgmt->abyCurrSSID); +} + +/*+ + * + * Description: + * Get current link channel + * + * Parameters: + * In: + * pMgmtHandle - pointer to management object + * Out: + * none + * + * Return Value: current Channel. + * +-*/ +UINT +VNTWIFIpGetCurrentChannel ( + IN PVOID pMgmtHandle + ) +{ + PSMgmtObject pMgmt = (PSMgmtObject)pMgmtHandle; + if (pMgmtHandle != NULL) { + return (pMgmt->uCurrChannel); + } + return 0; +} + +/*+ + * + * Description: + * Get current Assoc ID + * + * Parameters: + * In: + * pMgmtHandle - pointer to management object + * Out: + * none + * + * Return Value: current Assoc ID + * +-*/ +WORD +VNTWIFIwGetAssocID ( + IN PVOID pMgmtHandle + ) +{ + PSMgmtObject pMgmt = (PSMgmtObject)pMgmtHandle; + return(pMgmt->wCurrAID); +} + + + +/*+ + * + * Description: + * This routine return max support rate of IES + * + * Parameters: + * In: + * pSupportRateIEs + * pExtSupportRateIEs + * + * Out: + * + * Return Value: max support rate + * +-*/ +BYTE +VNTWIFIbyGetMaxSupportRate ( + IN PWLAN_IE_SUPP_RATES pSupportRateIEs, + IN PWLAN_IE_SUPP_RATES pExtSupportRateIEs + ) +{ + BYTE byMaxSupportRate = RATE_1M; + BYTE bySupportRate = RATE_1M; + UINT ii = 0; + + if (pSupportRateIEs) { + for (ii = 0; ii < pSupportRateIEs->len; ii++) { + bySupportRate = DATARATEbyGetRateIdx(pSupportRateIEs->abyRates[ii]); + if (bySupportRate > byMaxSupportRate) { + byMaxSupportRate = bySupportRate; + } + } + } + if (pExtSupportRateIEs) { + for (ii = 0; ii < pExtSupportRateIEs->len; ii++) { + bySupportRate = DATARATEbyGetRateIdx(pExtSupportRateIEs->abyRates[ii]); + if (bySupportRate > byMaxSupportRate) { + byMaxSupportRate = bySupportRate; + } + } + } + + return byMaxSupportRate; +} + +/*+ + * + * Description: + * This routine return data rate of ACK packtet + * + * Parameters: + * In: + * byRxDataRate + * pSupportRateIEs + * pExtSupportRateIEs + * + * Out: + * + * Return Value: max support rate + * +-*/ +BYTE +VNTWIFIbyGetACKTxRate ( + IN BYTE byRxDataRate, + IN PWLAN_IE_SUPP_RATES pSupportRateIEs, + IN PWLAN_IE_SUPP_RATES pExtSupportRateIEs + ) +{ + BYTE byMaxAckRate; + BYTE byBasicRate; + UINT ii; + + if (byRxDataRate <= RATE_11M) { + byMaxAckRate = RATE_1M; + } else { + // 24M is mandatory for 802.11a and 802.11g + byMaxAckRate = RATE_24M; + } + if (pSupportRateIEs) { + for (ii = 0; ii < pSupportRateIEs->len; ii++) { + if (pSupportRateIEs->abyRates[ii] & 0x80) { + byBasicRate = DATARATEbyGetRateIdx(pSupportRateIEs->abyRates[ii]); + if ((byBasicRate <= byRxDataRate) && + (byBasicRate > byMaxAckRate)) { + byMaxAckRate = byBasicRate; + } + } + } + } + if (pExtSupportRateIEs) { + for (ii = 0; ii < pExtSupportRateIEs->len; ii++) { + if (pExtSupportRateIEs->abyRates[ii] & 0x80) { + byBasicRate = DATARATEbyGetRateIdx(pExtSupportRateIEs->abyRates[ii]); + if ((byBasicRate <= byRxDataRate) && + (byBasicRate > byMaxAckRate)) { + byMaxAckRate = byBasicRate; + } + } + } + } + + return byMaxAckRate; +} + +/*+ + * + * Description: + * Set Authentication Mode + * + * Parameters: + * In: + * pMgmtHandle - pointer to management object + * eAuthMode - Authentication mode + * Out: + * none + * + * Return Value: none + * +-*/ +VOID +VNTWIFIvSetAuthenticationMode ( + IN PVOID pMgmtHandle, + IN WMAC_AUTHENTICATION_MODE eAuthMode + ) +{ + PSMgmtObject pMgmt = (PSMgmtObject)pMgmtHandle; + + pMgmt->eAuthenMode = eAuthMode; + if ((eAuthMode == WMAC_AUTH_SHAREKEY) || + (eAuthMode == WMAC_AUTH_AUTO)) { + pMgmt->bShareKeyAlgorithm = TRUE; + } else { + pMgmt->bShareKeyAlgorithm = FALSE; + } +} + +/*+ + * + * Description: + * Set Encryption Mode + * + * Parameters: + * In: + * pMgmtHandle - pointer to management object + * eAuthMode - Authentication mode + * Out: + * none + * + * Return Value: none + * +-*/ +VOID +VNTWIFIvSetEncryptionMode ( + IN PVOID pMgmtHandle, + IN WMAC_ENCRYPTION_MODE eEncryptionMode + ) +{ + PSMgmtObject pMgmt = (PSMgmtObject)pMgmtHandle; + + pMgmt->eEncryptionMode = eEncryptionMode; + if ((eEncryptionMode == WMAC_ENCRYPTION_WEPEnabled) || + (eEncryptionMode == WMAC_ENCRYPTION_TKIPEnabled) || + (eEncryptionMode == WMAC_ENCRYPTION_AESEnabled) ) { + pMgmt->bPrivacyInvoked = TRUE; + } else { + pMgmt->bPrivacyInvoked = FALSE; + } +} + + + +BOOL +VNTWIFIbConfigPhyMode ( + IN PVOID pMgmtHandle, + IN CARD_PHY_TYPE ePhyType + ) +{ + PSMgmtObject pMgmt = (PSMgmtObject)pMgmtHandle; + + if ((ePhyType != PHY_TYPE_AUTO) && + (ePhyType != pMgmt->eCurrentPHYMode)) { + if (CARDbSetPhyParameter(pMgmt->pAdapter, ePhyType, 0, 0, NULL, NULL)==TRUE) { + pMgmt->eCurrentPHYMode = ePhyType; + } else { + return(FALSE); + } + } + pMgmt->eConfigPHYMode = ePhyType; + return(TRUE); +} + + +VOID +VNTWIFIbGetConfigPhyMode ( + IN PVOID pMgmtHandle, + OUT PVOID pePhyType + ) +{ + PSMgmtObject pMgmt = (PSMgmtObject)pMgmtHandle; + + if ((pMgmt != NULL) && (pePhyType != NULL)) { + *(PCARD_PHY_TYPE)pePhyType = pMgmt->eConfigPHYMode; + } +} + +/*+ + * + * Description: + * Clear BSS List Database except current assoc BSS + * + * Parameters: + * In: + * pMgmtHandle - Management Object structure + * bLinkPass - Current Link status + * Out: + * + * Return Value: None. + * +-*/ + + +/*+ + * + * Description: + * Query BSS List in management database + * + * Parameters: + * In: + * pMgmtHandle - Management Object structure + * Out: + * puBSSCount - BSS count + * pvFirstBSS - pointer to first BSS + * + * Return Value: None. + * +-*/ + +VOID +VNTWIFIvQueryBSSList ( + IN PVOID pMgmtHandle, + OUT PUINT puBSSCount, + OUT PVOID *pvFirstBSS + ) +{ + UINT ii = 0; + PSMgmtObject pMgmt = (PSMgmtObject)pMgmtHandle; + PKnownBSS pBSS = NULL; + UINT uCount = 0; + + *pvFirstBSS = NULL; + + for (ii = 0; ii < MAX_BSS_NUM; ii++) { + pBSS = &(pMgmt->sBSSList[ii]); + if (!pBSS->bActive) { + continue; + } + if (*pvFirstBSS == NULL) { + *pvFirstBSS = &(pMgmt->sBSSList[ii]); + } + uCount++; + } + *puBSSCount = uCount; +} + + + + +VOID +VNTWIFIvGetNextBSS ( + IN PVOID pMgmtHandle, + IN PVOID pvCurrentBSS, + OUT PVOID *pvNextBSS + ) +{ + PKnownBSS pBSS = (PKnownBSS) pvCurrentBSS; + PSMgmtObject pMgmt = (PSMgmtObject)pMgmtHandle; + + *pvNextBSS = NULL; + + while (*pvNextBSS == NULL) { + pBSS++; + if (pBSS > &(pMgmt->sBSSList[MAX_BSS_NUM])) { + return; + } + if (pBSS->bActive == TRUE) { + *pvNextBSS = pBSS; + return; + } + } +} + + + + + +/*+ + * + * Description: + * Update Tx attemps, Tx failure counter in Node DB + * + * In: + * Out: + * none + * + * Return Value: none + * +-*/ +VOID +VNTWIFIvUpdateNodeTxCounter( + IN PVOID pMgmtHandle, + IN PBYTE pbyDestAddress, + IN BOOL bTxOk, + IN WORD wRate, + IN PBYTE pbyTxFailCount + ) +{ + PSMgmtObject pMgmt = (PSMgmtObject)pMgmtHandle; + UINT uNodeIndex = 0; + UINT ii; + + if ((pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) || + (pMgmt->eCurrMode == WMAC_MODE_ESS_AP)) { + if (BSSDBbIsSTAInNodeDB(pMgmt, pbyDestAddress, &uNodeIndex) == FALSE) { + return; + } + } + pMgmt->sNodeDBTable[uNodeIndex].uTxAttempts++; + if (bTxOk == TRUE) { + // transmit success, TxAttempts at least plus one + pMgmt->sNodeDBTable[uNodeIndex].uTxOk[MAX_RATE]++; + pMgmt->sNodeDBTable[uNodeIndex].uTxOk[wRate]++; + } else { + pMgmt->sNodeDBTable[uNodeIndex].uTxFailures++; + } + pMgmt->sNodeDBTable[uNodeIndex].uTxRetry += pbyTxFailCount[MAX_RATE]; + for(ii=0;iisNodeDBTable[uNodeIndex].uTxFail[ii] += pbyTxFailCount[ii]; + } + return; +} + + +VOID +VNTWIFIvGetTxRate( + IN PVOID pMgmtHandle, + IN PBYTE pbyDestAddress, + OUT PWORD pwTxDataRate, + OUT PBYTE pbyACKRate, + OUT PBYTE pbyCCKBasicRate, + OUT PBYTE pbyOFDMBasicRate + ) +{ + PSMgmtObject pMgmt = (PSMgmtObject)pMgmtHandle; + UINT uNodeIndex = 0; + WORD wTxDataRate = RATE_1M; + BYTE byACKRate = RATE_1M; + BYTE byCCKBasicRate = RATE_1M; + BYTE byOFDMBasicRate = RATE_24M; + PWLAN_IE_SUPP_RATES pSupportRateIEs = NULL; + PWLAN_IE_SUPP_RATES pExtSupportRateIEs = NULL; + + + if ((pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) || + (pMgmt->eCurrMode == WMAC_MODE_ESS_AP)) { + // Adhoc Tx rate decided from node DB + if(BSSDBbIsSTAInNodeDB(pMgmt, pbyDestAddress, &uNodeIndex)) { + wTxDataRate = (pMgmt->sNodeDBTable[uNodeIndex].wTxDataRate); + pSupportRateIEs = (PWLAN_IE_SUPP_RATES) (pMgmt->sNodeDBTable[uNodeIndex].abyCurrSuppRates); + pExtSupportRateIEs = (PWLAN_IE_SUPP_RATES) (pMgmt->sNodeDBTable[uNodeIndex].abyCurrExtSuppRates); + } else { + if (pMgmt->eCurrentPHYMode != PHY_TYPE_11A) { + wTxDataRate = RATE_2M; + } else { + wTxDataRate = RATE_24M; + } + pSupportRateIEs = (PWLAN_IE_SUPP_RATES) pMgmt->abyCurrSuppRates; + pExtSupportRateIEs = (PWLAN_IE_SUPP_RATES) pMgmt->abyCurrExtSuppRates; + } + } else { // Infrastructure: rate decided from AP Node, index = 0 + + wTxDataRate = (pMgmt->sNodeDBTable[0].wTxDataRate); +#ifdef PLICE_DEBUG + printk("GetTxRate:AP MAC is %02x:%02x:%02x:%02x:%02x:%02x,TxRate is %d\n", + pMgmt->sNodeDBTable[0].abyMACAddr[0],pMgmt->sNodeDBTable[0].abyMACAddr[1], + pMgmt->sNodeDBTable[0].abyMACAddr[2],pMgmt->sNodeDBTable[0].abyMACAddr[3], + pMgmt->sNodeDBTable[0].abyMACAddr[4],pMgmt->sNodeDBTable[0].abyMACAddr[5],wTxDataRate); +#endif + + + pSupportRateIEs = (PWLAN_IE_SUPP_RATES) pMgmt->abyCurrSuppRates; + pExtSupportRateIEs = (PWLAN_IE_SUPP_RATES) pMgmt->abyCurrExtSuppRates; + } + byACKRate = VNTWIFIbyGetACKTxRate( (BYTE) wTxDataRate, + pSupportRateIEs, + pExtSupportRateIEs + ); + if (byACKRate > (BYTE) wTxDataRate) { + byACKRate = (BYTE) wTxDataRate; + } + byCCKBasicRate = VNTWIFIbyGetACKTxRate( RATE_11M, + pSupportRateIEs, + pExtSupportRateIEs + ); + byOFDMBasicRate = VNTWIFIbyGetACKTxRate(RATE_54M, + pSupportRateIEs, + pExtSupportRateIEs + ); + *pwTxDataRate = wTxDataRate; + *pbyACKRate = byACKRate; + *pbyCCKBasicRate = byCCKBasicRate; + *pbyOFDMBasicRate = byOFDMBasicRate; + return; +} + +BYTE +VNTWIFIbyGetKeyCypher( + IN PVOID pMgmtHandle, + IN BOOL bGroupKey + ) +{ + PSMgmtObject pMgmt = (PSMgmtObject)pMgmtHandle; + + if (bGroupKey == TRUE) { + return (pMgmt->byCSSGK); + } else { + return (pMgmt->byCSSPK); + } +} + + +/* +BOOL +VNTWIFIbInit( + IN PVOID pAdapterHandler, + OUT PVOID *pMgmtHandler + ) +{ + + PSMgmtObject pMgmt = NULL; + UINT ii; + + + pMgmt = (PSMgmtObject)kmalloc(sizeof(SMgmtObject), (int)GFP_ATOMIC); + if (pMgmt == NULL) { + *pMgmtHandler = NULL; + return FALSE; + } + + memset(pMgmt, 0, sizeof(SMgmtObject)); + pMgmt->pAdapter = (PVOID) pAdapterHandler; + + // should initial MAC address abyMACAddr + for(ii=0;iiabyDesireBSSID[ii] = 0xFF; + } + pMgmt->pbyPSPacketPool = &pMgmt->byPSPacketPool[0]; + pMgmt->pbyMgmtPacketPool = &pMgmt->byMgmtPacketPool[0]; + pMgmt->byCSSPK = KEY_CTL_NONE; + pMgmt->byCSSGK = KEY_CTL_NONE; + pMgmt->wIBSSBeaconPeriod = DEFAULT_IBSS_BI; + + pMgmt->cbFreeCmdQueue = CMD_Q_SIZE; + pMgmt->uCmdDequeueIdx = 0; + pMgmt->uCmdEnqueueIdx = 0; + pMgmt->eCommandState = WLAN_CMD_STATE_IDLE; + pMgmt->bCmdStop = FALSE; + pMgmt->bCmdRunning = FALSE; + + *pMgmtHandler = pMgmt; + return TRUE; +} +*/ + + + +BOOL +VNTWIFIbSetPMKIDCache ( + IN PVOID pMgmtObject, + IN ULONG ulCount, + IN PVOID pPMKIDInfo + ) +{ + PSMgmtObject pMgmt = (PSMgmtObject) pMgmtObject; + + if (ulCount > MAX_PMKID_CACHE) { + return (FALSE); + } + pMgmt->gsPMKIDCache.BSSIDInfoCount = ulCount; + MEMvCopy(pMgmt->gsPMKIDCache.BSSIDInfo, pPMKIDInfo, (ulCount*sizeof(PMKIDInfo))); + return (TRUE); +} + + + +WORD +VNTWIFIwGetMaxSupportRate( + IN PVOID pMgmtObject + ) +{ + WORD wRate = RATE_54M; + PSMgmtObject pMgmt = (PSMgmtObject) pMgmtObject; + + for(wRate = RATE_54M; wRate > RATE_1M; wRate--) { + if (BITbIsBitOn(pMgmt->sNodeDBTable[0].wSuppRate, (1<eCurrentPHYMode == PHY_TYPE_11A) { + return (RATE_6M); + } else { + return (RATE_1M); + } +} + + +VOID +VNTWIFIvSet11h ( + IN PVOID pMgmtObject, + IN BOOL b11hEnable + ) +{ + PSMgmtObject pMgmt = (PSMgmtObject) pMgmtObject; + + pMgmt->b11hEnable = b11hEnable; +} + +BOOL +VNTWIFIbMeasureReport( + IN PVOID pMgmtObject, + IN BOOL bEndOfReport, + IN PVOID pvMeasureEID, + IN BYTE byReportMode, + IN BYTE byBasicMap, + IN BYTE byCCAFraction, + IN PBYTE pbyRPIs + ) +{ + PSMgmtObject pMgmt = (PSMgmtObject) pMgmtObject; + PBYTE pbyCurrentEID = (PBYTE) (pMgmt->pCurrMeasureEIDRep); + + //spin_lock_irq(&pDevice->lock); + if ((pvMeasureEID != NULL) && + (pMgmt->uLengthOfRepEIDs < (WLAN_A3FR_MAXLEN - sizeof(MEASEURE_REP) - sizeof(WLAN_80211HDR_A3) - 3)) + ) { + pMgmt->pCurrMeasureEIDRep->byElementID = WLAN_EID_MEASURE_REP; + pMgmt->pCurrMeasureEIDRep->len = 3; + pMgmt->pCurrMeasureEIDRep->byToken = ((PWLAN_IE_MEASURE_REQ) pvMeasureEID)->byToken; + pMgmt->pCurrMeasureEIDRep->byMode = byReportMode; + pMgmt->pCurrMeasureEIDRep->byType = ((PWLAN_IE_MEASURE_REQ) pvMeasureEID)->byType; + switch (pMgmt->pCurrMeasureEIDRep->byType) { + case MEASURE_TYPE_BASIC : + pMgmt->pCurrMeasureEIDRep->len += sizeof(MEASEURE_REP_BASIC); + MEMvCopy( &(pMgmt->pCurrMeasureEIDRep->sRep.sBasic), + &(((PWLAN_IE_MEASURE_REQ) pvMeasureEID)->sReq), + sizeof(MEASEURE_REQ)); + pMgmt->pCurrMeasureEIDRep->sRep.sBasic.byMap = byBasicMap; + break; + case MEASURE_TYPE_CCA : + pMgmt->pCurrMeasureEIDRep->len += sizeof(MEASEURE_REP_CCA); + MEMvCopy( &(pMgmt->pCurrMeasureEIDRep->sRep.sCCA), + &(((PWLAN_IE_MEASURE_REQ) pvMeasureEID)->sReq), + sizeof(MEASEURE_REQ)); + pMgmt->pCurrMeasureEIDRep->sRep.sCCA.byCCABusyFraction = byCCAFraction; + break; + case MEASURE_TYPE_RPI : + pMgmt->pCurrMeasureEIDRep->len += sizeof(MEASEURE_REP_RPI); + MEMvCopy( &(pMgmt->pCurrMeasureEIDRep->sRep.sRPI), + &(((PWLAN_IE_MEASURE_REQ) pvMeasureEID)->sReq), + sizeof(MEASEURE_REQ)); + MEMvCopy(pMgmt->pCurrMeasureEIDRep->sRep.sRPI.abyRPIdensity, pbyRPIs, 8); + break; + default : + break; + } + pbyCurrentEID += (2 + pMgmt->pCurrMeasureEIDRep->len); + pMgmt->uLengthOfRepEIDs += (2 + pMgmt->pCurrMeasureEIDRep->len); + pMgmt->pCurrMeasureEIDRep = (PWLAN_IE_MEASURE_REP) pbyCurrentEID; + } + if (bEndOfReport == TRUE) { + IEEE11hbMSRRepTx(pMgmt); + } + //spin_unlock_irq(&pDevice->lock); + return (TRUE); +} + + +BOOL +VNTWIFIbChannelSwitch( + IN PVOID pMgmtObject, + IN BYTE byNewChannel + ) +{ + PSMgmtObject pMgmt = (PSMgmtObject) pMgmtObject; + + //spin_lock_irq(&pDevice->lock); + pMgmt->uCurrChannel = byNewChannel; + pMgmt->bSwitchChannel = FALSE; + //spin_unlock_irq(&pDevice->lock); + return TRUE; +} + +/* +BOOL +VNTWIFIbRadarPresent( + IN PVOID pMgmtObject, + IN BYTE byChannel + ) +{ + PSMgmtObject pMgmt = (PSMgmtObject) pMgmtObject; + if ((pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) && + (byChannel == (BYTE) pMgmt->uCurrChannel) && + (pMgmt->bSwitchChannel != TRUE) && + (pMgmt->b11hEnable == TRUE)) { + if (IS_ETH_ADDRESS_EQUAL(pMgmt->abyIBSSDFSOwner, CARDpGetCurrentAddress(pMgmt->pAdapter))) { + pMgmt->byNewChannel = CARDbyAutoChannelSelect(pMgmt->pAdapter,(BYTE) pMgmt->uCurrChannel); + pMgmt->bSwitchChannel = TRUE; + } + BEACONbSendBeacon(pMgmt); + CARDbChannelSwitch(pMgmt->pAdapter, 0, pMgmt->byNewChannel, 10); + } + return TRUE; +} +*/ + diff --git a/drivers/staging/vt6655/vntwifi.h b/drivers/staging/vt6655/vntwifi.h new file mode 100644 index 000000000000..3e620a726212 --- /dev/null +++ b/drivers/staging/vt6655/vntwifi.h @@ -0,0 +1,330 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * File: vntwifi.h + * + * Purpose: export VNT Host WiFi library function + * + * Author: Yiching Chen + * + * Date: Jan 7, 2004 + * + */ + +#ifndef __VNTWIFI_H__ +#define __VNTWIFI_H__ + +#if !defined(__TTYPE_H__) +#include "ttype.h" +#endif +#if !defined(__80211MGR_H__) +#include "80211mgr.h" +#endif +#if !defined(__CARD_H__) +#include "card.h" +#endif + +/*--------------------- Export Definitions -------------------------*/ +#define RATE_1M 0 +#define RATE_2M 1 +#define RATE_5M 2 +#define RATE_11M 3 +#define RATE_6M 4 +#define RATE_9M 5 +#define RATE_12M 6 +#define RATE_18M 7 +#define RATE_24M 8 +#define RATE_36M 9 +#define RATE_48M 10 +#define RATE_54M 11 +#define RATE_AUTO 12 +#define MAX_RATE 12 + +// key CipherSuite +#define KEY_CTL_WEP 0x00 +#define KEY_CTL_NONE 0x01 +#define KEY_CTL_TKIP 0x02 +#define KEY_CTL_CCMP 0x03 +#define KEY_CTL_INVALID 0xFF + +#define CHANNEL_MAX_24G 14 + +#define MAX_BSS_NUM 42 + +#define MAX_PMKID_CACHE 16 + +// Pre-configured Authenticaiton Mode (from XP) +typedef enum tagWMAC_AUTHENTICATION_MODE { + + WMAC_AUTH_OPEN, + WMAC_AUTH_SHAREKEY, + WMAC_AUTH_AUTO, + WMAC_AUTH_WPA, + WMAC_AUTH_WPAPSK, + WMAC_AUTH_WPANONE, + WMAC_AUTH_WPA2, + WMAC_AUTH_WPA2PSK, + WMAC_AUTH_MAX // Not a real mode, defined as upper bound + +} WMAC_AUTHENTICATION_MODE, *PWMAC_AUTHENTICATION_MODE; + +typedef enum tagWMAC_ENCRYPTION_MODE { + + WMAC_ENCRYPTION_WEPEnabled, + WMAC_ENCRYPTION_WEPDisabled, + WMAC_ENCRYPTION_WEPKeyAbsent, + WMAC_ENCRYPTION_WEPNotSupported, + WMAC_ENCRYPTION_TKIPEnabled, + WMAC_ENCRYPTION_TKIPKeyAbsent, + WMAC_ENCRYPTION_AESEnabled, + WMAC_ENCRYPTION_AESKeyAbsent + +} WMAC_ENCRYPTION_MODE, *PWMAC_ENCRYPTION_MODE; + +// Pre-configured Mode (from XP) + +typedef enum tagWMAC_CONFIG_MODE { + + WMAC_CONFIG_ESS_STA = 0, + WMAC_CONFIG_IBSS_STA, + WMAC_CONFIG_AUTO, + WMAC_CONFIG_AP + +} WMAC_CONFIG_MODE, *PWMAC_CONFIG_MODE; + + + +typedef enum tagWMAC_POWER_MODE { + + WMAC_POWER_CAM, + WMAC_POWER_FAST, + WMAC_POWER_MAX + +} WMAC_POWER_MODE, *PWMAC_POWER_MODE; + +#define VNTWIFIbIsShortSlotTime(wCapInfo) \ + WLAN_GET_CAP_INFO_SHORTSLOTTIME(wCapInfo) \ + +#define VNTWIFIbIsProtectMode(byERP) \ + ((byERP & WLAN_EID_ERP_USE_PROTECTION) != 0) \ + +#define VNTWIFIbIsBarkerMode(byERP) \ + ((byERP & WLAN_EID_ERP_BARKER_MODE) != 0) \ + +#define VNTWIFIbIsShortPreamble(wCapInfo) \ + WLAN_GET_CAP_INFO_SHORTPREAMBLE(wCapInfo) \ + +#define VNTWIFIbIsEncryption(wCapInfo) \ + WLAN_GET_CAP_INFO_PRIVACY(wCapInfo) \ + +#define VNTWIFIbIsESS(wCapInfo) \ + WLAN_GET_CAP_INFO_ESS(wCapInfo) \ + + +/*--------------------- Export Classes ----------------------------*/ + +/*--------------------- Export Variables --------------------------*/ + + +/*--------------------- Export Types ------------------------------*/ + + +/*--------------------- Export Functions --------------------------*/ + +#ifdef __cplusplus +extern "C" { /* Assume C declarations for C++ */ +#endif /* __cplusplus */ + + +VOID +VNTWIFIvSetIBSSParameter ( + IN PVOID pMgmtHandle, + IN WORD wBeaconPeriod, + IN WORD wATIMWindow, + IN UINT uChannel + ); + +VOID +VNTWIFIvSetOPMode ( + IN PVOID pMgmtHandle, + IN WMAC_CONFIG_MODE eOPMode + ); + +PWLAN_IE_SSID +VNTWIFIpGetCurrentSSID( + IN PVOID pMgmtHandle + ); + +UINT +VNTWIFIpGetCurrentChannel( + IN PVOID pMgmtHandle + ); + +WORD +VNTWIFIwGetAssocID ( + IN PVOID pMgmtHandle + ); + +BYTE +VNTWIFIbyGetMaxSupportRate ( + IN PWLAN_IE_SUPP_RATES pSupportRateIEs, + IN PWLAN_IE_SUPP_RATES pExtSupportRateIEs + ); + +BYTE +VNTWIFIbyGetACKTxRate ( + IN BYTE byRxDataRate, + IN PWLAN_IE_SUPP_RATES pSupportRateIEs, + IN PWLAN_IE_SUPP_RATES pExtSupportRateIEs + ); + +VOID +VNTWIFIvSetAuthenticationMode ( + IN PVOID pMgmtHandle, + IN WMAC_AUTHENTICATION_MODE eAuthMode + ); + +VOID +VNTWIFIvSetEncryptionMode ( + IN PVOID pMgmtHandle, + IN WMAC_ENCRYPTION_MODE eEncryptionMode + ); + + +BOOL +VNTWIFIbConfigPhyMode( + IN PVOID pMgmtHandle, + IN CARD_PHY_TYPE ePhyType + ); + +VOID +VNTWIFIbGetConfigPhyMode( + IN PVOID pMgmtHandle, + OUT PVOID pePhyType + ); + +VOID +VNTWIFIvQueryBSSList( + IN PVOID pMgmtHandle, + OUT PUINT puBSSCount, + OUT PVOID *pvFirstBSS + ); + + + + +VOID +VNTWIFIvGetNextBSS ( + IN PVOID pMgmtHandle, + IN PVOID pvCurrentBSS, + OUT PVOID *pvNextBSS + ); + + + +VOID +VNTWIFIvUpdateNodeTxCounter( + IN PVOID pMgmtHandle, + IN PBYTE pbyDestAddress, + IN BOOL bTxOk, + IN WORD wRate, + IN PBYTE pbyTxFailCount + ); + + +VOID +VNTWIFIvGetTxRate( + IN PVOID pMgmtHandle, + IN PBYTE pbyDestAddress, + OUT PWORD pwTxDataRate, + OUT PBYTE pbyACKRate, + OUT PBYTE pbyCCKBasicRate, + OUT PBYTE pbyOFDMBasicRate + ); +/* +BOOL +VNTWIFIbInit( + IN PVOID pAdapterHandler, + OUT PVOID *pMgmtHandler + ); +*/ + +BYTE +VNTWIFIbyGetKeyCypher( + IN PVOID pMgmtHandle, + IN BOOL bGroupKey + ); + + + + +BOOL +VNTWIFIbSetPMKIDCache ( + IN PVOID pMgmtObject, + IN ULONG ulCount, + IN PVOID pPMKIDInfo + ); + +BOOL +VNTWIFIbCommandRunning ( + IN PVOID pMgmtObject + ); + +WORD +VNTWIFIwGetMaxSupportRate( + IN PVOID pMgmtObject + ); + +// for 802.11h +VOID +VNTWIFIvSet11h ( + IN PVOID pMgmtObject, + IN BOOL b11hEnable + ); + +BOOL +VNTWIFIbMeasureReport( + IN PVOID pMgmtObject, + IN BOOL bEndOfReport, + IN PVOID pvMeasureEID, + IN BYTE byReportMode, + IN BYTE byBasicMap, + IN BYTE byCCAFraction, + IN PBYTE pbyRPIs + ); + +BOOL +VNTWIFIbChannelSwitch( + IN PVOID pMgmtObject, + IN BYTE byNewChannel + ); +/* +BOOL +VNTWIFIbRadarPresent( + IN PVOID pMgmtObject, + IN BYTE byChannel + ); +*/ + +#ifdef __cplusplus +} /* End of extern "C" { */ +#endif /* __cplusplus */ + + +#endif //__VNTWIFI_H__ diff --git a/drivers/staging/vt6655/wcmd.c b/drivers/staging/vt6655/wcmd.c new file mode 100644 index 000000000000..92563bd011b2 --- /dev/null +++ b/drivers/staging/vt6655/wcmd.c @@ -0,0 +1,1178 @@ + /* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * File: wcmd.c + * + * Purpose: Handles the management command interface functions + * + * Author: Lyndon Chen + * + * Date: May 8, 2003 + * + * Functions: + * s_vProbeChannel - Active scan channel + * s_MgrMakeProbeRequest - Make ProbeRequest packet + * CommandTimer - Timer function to handle command + * s_bCommandComplete - Command Complete function + * bScheduleCommand - Push Command and wait Command Scheduler to do + * vCommandTimer- Command call back functions + * vCommandTimerWait- Call back timer + * bClearBSSID_SCAN- Clear BSSID_SCAN cmd in CMD Queue + * + * Revision History: + * + */ + + + + +#if !defined(__TTYPE_H__) +#include "ttype.h" +#endif +#if !defined(__TMACRO_H__) +#include "tmacro.h" +#endif +#if !defined(__DEVICE_H__) +#include "device.h" +#endif +#if !defined(__MAC_H__) +#include "mac.h" +#endif +#if !defined(__CARD_H__) +#include "card.h" +#endif +#if !defined(__80211HDR_H__) +#include "80211hdr.h" +#endif +#if !defined(__WCMD_H__) +#include "wcmd.h" +#endif +#if !defined(__WMGR_H__) +#include "wmgr.h" +#endif +#if !defined(__POWER_H__) +#include "power.h" +#endif +#if !defined(__WCTL_H__) +#include "wctl.h" +#endif +#if !defined(__CARD_H__) +#include "card.h" +#endif +#if !defined(__BASEBAND_H__) +#include "baseband.h" +#endif +#if !defined(__UMEM_H__) +#include "umem.h" +#endif +#if !defined(__RXTX_H__) +#include "rxtx.h" +#endif +#if !defined(__RF_H__) +#include "rf.h" +#endif +//DavidWang +#if !defined(__IOWPA_H__) +#include "iowpa.h" +#endif + +/*--------------------- Static Definitions -------------------------*/ + + + + +/*--------------------- Static Classes ----------------------------*/ + +/*--------------------- Static Variables --------------------------*/ +static int msglevel =MSG_LEVEL_INFO; +//static int msglevel =MSG_LEVEL_DEBUG; +/*--------------------- Static Functions --------------------------*/ + +static +VOID +s_vProbeChannel( + IN PSDevice pDevice + ); + + +static +PSTxMgmtPacket +s_MgrMakeProbeRequest( + IN PSDevice pDevice, + IN PSMgmtObject pMgmt, + IN PBYTE pScanBSSID, + IN PWLAN_IE_SSID pSSID, + IN PWLAN_IE_SUPP_RATES pCurrRates, + IN PWLAN_IE_SUPP_RATES pCurrExtSuppRates + ); + +static +BOOL +s_bCommandComplete ( + PSDevice pDevice + ); + +/*--------------------- Export Variables --------------------------*/ + + +/*--------------------- Export Functions --------------------------*/ + + +/* + * Description: + * Stop AdHoc beacon during scan process + * + * Parameters: + * In: + * pDevice - Pointer to the adapter + * Out: + * none + * + * Return Value: none + * + */ +static +void +vAdHocBeaconStop(PSDevice pDevice) +{ + + PSMgmtObject pMgmt = &(pDevice->sMgmtObj); + BOOL bStop; + + /* + * temporarily stop Beacon packet for AdHoc Server + * if all of the following coditions are met: + * (1) STA is in AdHoc mode + * (2) VT3253 is programmed as automatic Beacon Transmitting + * (3) One of the following conditions is met + * (3.1) AdHoc channel is in B/G band and the + * current scan channel is in A band + * or + * (3.2) AdHoc channel is in A mode + */ + bStop = FALSE; + if ((pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) && + (pMgmt->eCurrState >= WMAC_STATE_STARTED)) + { + if ((pMgmt->uIBSSChannel <= CB_MAX_CHANNEL_24G) && + (pMgmt->uScanChannel > CB_MAX_CHANNEL_24G)) + { + bStop = TRUE; + } + if (pMgmt->uIBSSChannel > CB_MAX_CHANNEL_24G) + { + bStop = TRUE; + } + } + + if (bStop) + { + MACvRegBitsOff(pDevice->PortOffset, MAC_REG_TCR, TCR_AUTOBCNTX); + } + +} + +/* + * Description: + * Restart AdHoc beacon after scan process complete + * + * Parameters: + * In: + * pDevice - Pointer to the adapter + * Out: + * none + * + * Return Value: none + * + */ +static +void +vAdHocBeaconRestart(PSDevice pDevice) +{ + PSMgmtObject pMgmt = &(pDevice->sMgmtObj); + + /* + * Restart Beacon packet for AdHoc Server + * if all of the following coditions are met: + * (1) STA is in AdHoc mode + * (2) VT3253 is programmed as automatic Beacon Transmitting + */ + if ((pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) && + (pMgmt->eCurrState >= WMAC_STATE_STARTED)) + { + MACvRegBitsOn(pDevice->PortOffset, MAC_REG_TCR, TCR_AUTOBCNTX); + } + +} + + + + +/*+ + * + * Routine Description: + * Prepare and send probe request management frames. + * + * + * Return Value: + * none. + * +-*/ + +static +VOID +s_vProbeChannel( + IN PSDevice pDevice + ) +{ + //1M, 2M, 5M, 11M, 18M, 24M, 36M, 54M + BYTE abyCurrSuppRatesG[] = {WLAN_EID_SUPP_RATES, 8, 0x02, 0x04, 0x0B, 0x16, 0x24, 0x30, 0x48, 0x6C}; + BYTE abyCurrExtSuppRatesG[] = {WLAN_EID_EXTSUPP_RATES, 4, 0x0C, 0x12, 0x18, 0x60}; + //6M, 9M, 12M, 48M + BYTE abyCurrSuppRatesA[] = {WLAN_EID_SUPP_RATES, 8, 0x0C, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C}; + BYTE abyCurrSuppRatesB[] = {WLAN_EID_SUPP_RATES, 4, 0x02, 0x04, 0x0B, 0x16}; + PBYTE pbyRate; + PSTxMgmtPacket pTxPacket; + PSMgmtObject pMgmt = pDevice->pMgmt; + UINT ii; + + + if (pDevice->eCurrentPHYType == PHY_TYPE_11A) { + pbyRate = &abyCurrSuppRatesA[0]; + } else if (pDevice->eCurrentPHYType == PHY_TYPE_11B) { + pbyRate = &abyCurrSuppRatesB[0]; + } else { + pbyRate = &abyCurrSuppRatesG[0]; + } + // build an assocreq frame and send it + pTxPacket = s_MgrMakeProbeRequest + ( + pDevice, + pMgmt, + pMgmt->abyScanBSSID, + (PWLAN_IE_SSID)pMgmt->abyScanSSID, + (PWLAN_IE_SUPP_RATES)pbyRate, + (PWLAN_IE_SUPP_RATES)abyCurrExtSuppRatesG + ); + + if (pTxPacket != NULL ){ + for (ii = 0; ii < 2 ; ii++) { + if (csMgmt_xmit(pDevice, pTxPacket) != CMD_STATUS_PENDING) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Probe request sending fail.. \n"); + } + else { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Probe request is sending.. \n"); + } + } + } + +} + + + + +/*+ + * + * Routine Description: + * Constructs an probe request frame + * + * + * Return Value: + * A ptr to Tx frame or NULL on allocation failue + * +-*/ + + +PSTxMgmtPacket +s_MgrMakeProbeRequest( + IN PSDevice pDevice, + IN PSMgmtObject pMgmt, + IN PBYTE pScanBSSID, + IN PWLAN_IE_SSID pSSID, + IN PWLAN_IE_SUPP_RATES pCurrRates, + IN PWLAN_IE_SUPP_RATES pCurrExtSuppRates + + ) +{ + PSTxMgmtPacket pTxPacket = NULL; + WLAN_FR_PROBEREQ sFrame; + + + pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool; + memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_PROBEREQ_FR_MAXLEN); + pTxPacket->p80211Header = (PUWLAN_80211HDR)((PBYTE)pTxPacket + sizeof(STxMgmtPacket)); + sFrame.pBuf = (PBYTE)pTxPacket->p80211Header; + sFrame.len = WLAN_PROBEREQ_FR_MAXLEN; + vMgrEncodeProbeRequest(&sFrame); + sFrame.pHdr->sA3.wFrameCtl = cpu_to_le16( + ( + WLAN_SET_FC_FTYPE(WLAN_TYPE_MGR) | + WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_PROBEREQ) + )); + memcpy( sFrame.pHdr->sA3.abyAddr1, pScanBSSID, WLAN_ADDR_LEN); + memcpy( sFrame.pHdr->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN); + memcpy( sFrame.pHdr->sA3.abyAddr3, pScanBSSID, WLAN_BSSID_LEN); + // Copy the SSID, pSSID->len=0 indicate broadcast SSID + sFrame.pSSID = (PWLAN_IE_SSID)(sFrame.pBuf + sFrame.len); + sFrame.len += pSSID->len + WLAN_IEHDR_LEN; + memcpy(sFrame.pSSID, pSSID, pSSID->len + WLAN_IEHDR_LEN); + sFrame.pSuppRates = (PWLAN_IE_SUPP_RATES)(sFrame.pBuf + sFrame.len); + sFrame.len += pCurrRates->len + WLAN_IEHDR_LEN; + memcpy(sFrame.pSuppRates, pCurrRates, pCurrRates->len + WLAN_IEHDR_LEN); + // Copy the extension rate set + if (pDevice->eCurrentPHYType == PHY_TYPE_11G) { + sFrame.pExtSuppRates = (PWLAN_IE_SUPP_RATES)(sFrame.pBuf + sFrame.len); + sFrame.len += pCurrExtSuppRates->len + WLAN_IEHDR_LEN; + memcpy(sFrame.pExtSuppRates, pCurrExtSuppRates, pCurrExtSuppRates->len + WLAN_IEHDR_LEN); + } + pTxPacket->cbMPDULen = sFrame.len; + pTxPacket->cbPayloadLen = sFrame.len - WLAN_HDR_ADDR3_LEN; + + return pTxPacket; +} + + + + +VOID +vCommandTimerWait( + IN HANDLE hDeviceContext, + IN UINT MSecond + ) +{ + PSDevice pDevice = (PSDevice)hDeviceContext; + + init_timer(&pDevice->sTimerCommand); + pDevice->sTimerCommand.data = (ULONG)pDevice; + pDevice->sTimerCommand.function = (TimerFunction)vCommandTimer; + // RUN_AT :1 msec ~= (HZ/1024) + pDevice->sTimerCommand.expires = (UINT)RUN_AT((MSecond * HZ) >> 10); + add_timer(&pDevice->sTimerCommand); + return; +} + + + +VOID +vCommandTimer ( + IN HANDLE hDeviceContext + ) +{ + PSDevice pDevice = (PSDevice)hDeviceContext; + PSMgmtObject pMgmt = pDevice->pMgmt; + PWLAN_IE_SSID pItemSSID; + PWLAN_IE_SSID pItemSSIDCurr; + CMD_STATUS Status; + UINT ii; + BYTE byMask[8] = {1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80}; + struct sk_buff *skb; + + + if (pDevice->dwDiagRefCount != 0) + return; + if (pDevice->bCmdRunning != TRUE) + return; + + spin_lock_irq(&pDevice->lock); + + switch ( pDevice->eCommandState ) { + + case WLAN_CMD_SCAN_START: + + pDevice->byReAssocCount = 0; + if (pDevice->bRadioOff == TRUE) { + s_bCommandComplete(pDevice); + spin_unlock_irq(&pDevice->lock); + return; + } + + if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) { + s_bCommandComplete(pDevice); + CARDbSetBSSID(pMgmt->pAdapter, pMgmt->abyCurrBSSID, OP_MODE_AP); + spin_unlock_irq(&pDevice->lock); + return; + } + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"eCommandState= WLAN_CMD_SCAN_START\n"); + pItemSSID = (PWLAN_IE_SSID)pMgmt->abyScanSSID; + // wait all Data TD complete + if (pDevice->iTDUsed[TYPE_AC0DMA] != 0){ + spin_unlock_irq(&pDevice->lock); + vCommandTimerWait((HANDLE)pDevice, 10); + return; + }; + + if (pMgmt->uScanChannel == 0 ) { + pMgmt->uScanChannel = pDevice->byMinChannel; + // Set Baseband to be more sensitive. + + } + if (pMgmt->uScanChannel > pDevice->byMaxChannel) { + pMgmt->eScanState = WMAC_NO_SCANNING; + + // Set Baseband's sensitivity back. + // Set channel back + CARDbSetChannel(pMgmt->pAdapter, pMgmt->uCurrChannel); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Scanning, set back to channel: [%d]\n", pMgmt->uCurrChannel); + if (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) { + CARDbSetBSSID(pMgmt->pAdapter, pMgmt->abyCurrBSSID, OP_MODE_ADHOC); + } else { + CARDbSetBSSID(pMgmt->pAdapter, pMgmt->abyCurrBSSID, OP_MODE_INFRASTRUCTURE); + } + vAdHocBeaconRestart(pDevice); + s_bCommandComplete(pDevice); + + } else { +//2008-8-4 by chester + if (!ChannelValid(pDevice->byZoneType, pMgmt->uScanChannel)) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Invalid channel pMgmt->uScanChannel = %d \n",pMgmt->uScanChannel); + s_bCommandComplete(pDevice); + return; + } +//printk("chester-pMgmt->uScanChannel=%d,pDevice->byMaxChannel=%d\n",pMgmt->uScanChannel,pDevice->byMaxChannel); + if (pMgmt->uScanChannel == pDevice->byMinChannel) { + //pMgmt->eScanType = WMAC_SCAN_ACTIVE; + pMgmt->abyScanBSSID[0] = 0xFF; + pMgmt->abyScanBSSID[1] = 0xFF; + pMgmt->abyScanBSSID[2] = 0xFF; + pMgmt->abyScanBSSID[3] = 0xFF; + pMgmt->abyScanBSSID[4] = 0xFF; + pMgmt->abyScanBSSID[5] = 0xFF; + pItemSSID->byElementID = WLAN_EID_SSID; + // clear bssid list + // BSSvClearBSSList((HANDLE)pDevice, pDevice->bLinkPass); + pMgmt->eScanState = WMAC_IS_SCANNING; + + } + + vAdHocBeaconStop(pDevice); + + if (CARDbSetChannel(pMgmt->pAdapter, pMgmt->uScanChannel) == TRUE) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"SCAN Channel: %d\n", pMgmt->uScanChannel); + } else { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"SET SCAN Channel Fail: %d\n", pMgmt->uScanChannel); + } + CARDbSetBSSID(pMgmt->pAdapter, pMgmt->abyCurrBSSID, OP_MODE_UNKNOWN); +// printk("chester-mxch=%d\n",pDevice->byMaxChannel); + // printk("chester-ch=%d\n",pMgmt->uScanChannel); + pMgmt->uScanChannel++; +//2008-8-4 by chester + if (!ChannelValid(pDevice->byZoneType, pMgmt->uScanChannel) && + pMgmt->uScanChannel <= pDevice->byMaxChannel ){ + pMgmt->uScanChannel=pDevice->byMaxChannel+1; + pMgmt->eCommandState = WLAN_CMD_SCAN_END; + + } + + + if ((pMgmt->b11hEnable == FALSE) || + (pMgmt->uScanChannel < CB_MAX_CHANNEL_24G)) { + s_vProbeChannel(pDevice); + spin_unlock_irq(&pDevice->lock); + vCommandTimerWait((HANDLE)pDevice, WCMD_ACTIVE_SCAN_TIME); + return; + } else { + spin_unlock_irq(&pDevice->lock); + vCommandTimerWait((HANDLE)pDevice, WCMD_PASSIVE_SCAN_TIME); + return; + } + + } + + break; + + case WLAN_CMD_SCAN_END: + + // Set Baseband's sensitivity back. + // Set channel back + CARDbSetChannel(pMgmt->pAdapter, pMgmt->uCurrChannel); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Scanning, set back to channel: [%d]\n", pMgmt->uCurrChannel); + if (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) { + CARDbSetBSSID(pMgmt->pAdapter, pMgmt->abyCurrBSSID, OP_MODE_ADHOC); + } else { + CARDbSetBSSID(pMgmt->pAdapter, pMgmt->abyCurrBSSID, OP_MODE_INFRASTRUCTURE); + } + + pMgmt->eScanState = WMAC_NO_SCANNING; + vAdHocBeaconRestart(pDevice); +//2008-0409-07, by Einsn Liu +#ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT + if(pMgmt->eScanType == WMAC_SCAN_PASSIVE) + {//send scan event to wpa_Supplicant + union iwreq_data wrqu; + memset(&wrqu, 0, sizeof(wrqu)); + wireless_send_event(pDevice->dev, SIOCGIWSCAN, &wrqu, NULL); + } +#endif + s_bCommandComplete(pDevice); + break; + + case WLAN_CMD_DISASSOCIATE_START : + pDevice->byReAssocCount = 0; + if ((pMgmt->eCurrMode == WMAC_MODE_ESS_STA) && + (pMgmt->eCurrState != WMAC_STATE_ASSOC)) { + s_bCommandComplete(pDevice); + spin_unlock_irq(&pDevice->lock); + return; + } else { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Send Disassociation Packet..\n"); + // reason = 8 : disassoc because sta has left + vMgrDisassocBeginSta((HANDLE)pDevice, pMgmt, pMgmt->abyCurrBSSID, (8), &Status); + pDevice->bLinkPass = FALSE; + // unlock command busy + pItemSSID = (PWLAN_IE_SSID)pMgmt->abyCurrSSID; + pItemSSID->len = 0; + memset(pItemSSID->abySSID, 0, WLAN_SSID_MAXLEN); + pMgmt->eCurrState = WMAC_STATE_IDLE; + pMgmt->sNodeDBTable[0].bActive = FALSE; +// pDevice->bBeaconBufReady = FALSE; + } + netif_stop_queue(pDevice->dev); + pDevice->eCommandState = WLAN_DISASSOCIATE_WAIT; + // wait all Control TD complete + if (pDevice->iTDUsed[TYPE_TXDMA0] != 0){ + vCommandTimerWait((HANDLE)pDevice, 10); + spin_unlock_irq(&pDevice->lock); + return; + }; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO" CARDbRadioPowerOff\n"); + //2008-09-02 by chester + // CARDbRadioPowerOff(pDevice); + s_bCommandComplete(pDevice); + break; + + case WLAN_DISASSOCIATE_WAIT : + // wait all Control TD complete + if (pDevice->iTDUsed[TYPE_TXDMA0] != 0){ + vCommandTimerWait((HANDLE)pDevice, 10); + spin_unlock_irq(&pDevice->lock); + return; + }; +//2008-09-02 by chester + // CARDbRadioPowerOff(pDevice); + s_bCommandComplete(pDevice); + break; + + case WLAN_CMD_SSID_START: + pDevice->byReAssocCount = 0; + if (pDevice->bRadioOff == TRUE) { + s_bCommandComplete(pDevice); + spin_unlock_irq(&pDevice->lock); + return; + } +//printk("chester-currmode=%d\n",pMgmt->eCurrMode); +printk("chester-abyDesireSSID=%s\n",((PWLAN_IE_SSID)pMgmt->abyDesireSSID)->abySSID); + //memcpy(pMgmt->abyAdHocSSID,pMgmt->abyDesireSSID, + //((PWLAN_IE_SSID)pMgmt->abyDesireSSID)->len + WLAN_IEHDR_LEN); + pItemSSID = (PWLAN_IE_SSID)pMgmt->abyDesireSSID; + pItemSSIDCurr = (PWLAN_IE_SSID)pMgmt->abyCurrSSID; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO" cmd: desire ssid = %s\n", pItemSSID->abySSID); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO" cmd: curr ssid = %s\n", pItemSSIDCurr->abySSID); + + if (pMgmt->eCurrState == WMAC_STATE_ASSOC) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO" Cmd pMgmt->eCurrState == WMAC_STATE_ASSOC\n"); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO" pItemSSID->len =%d\n",pItemSSID->len); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO" pItemSSIDCurr->len = %d\n",pItemSSIDCurr->len); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO" desire ssid = %s\n", pItemSSID->abySSID); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO" curr ssid = %s\n", pItemSSIDCurr->abySSID); + } + + if ((pMgmt->eCurrState == WMAC_STATE_ASSOC) || + ((pMgmt->eCurrMode == WMAC_MODE_IBSS_STA)&& (pMgmt->eCurrState == WMAC_STATE_JOINTED))) { + + if (pItemSSID->len == pItemSSIDCurr->len) { + if (memcmp(pItemSSID->abySSID, pItemSSIDCurr->abySSID, pItemSSID->len) == 0) { + s_bCommandComplete(pDevice); + spin_unlock_irq(&pDevice->lock); + return; + } + } + + netif_stop_queue(pDevice->dev); + pDevice->bLinkPass = FALSE; + } + // set initial state + pMgmt->eCurrState = WMAC_STATE_IDLE; + pMgmt->eCurrMode = WMAC_MODE_STANDBY; + PSvDisablePowerSaving((HANDLE)pDevice); + BSSvClearNodeDBTable(pDevice, 0); + + vMgrJoinBSSBegin((HANDLE)pDevice, &Status); + // if Infra mode + if ((pMgmt->eCurrMode == WMAC_MODE_ESS_STA) && (pMgmt->eCurrState == WMAC_STATE_JOINTED)) { + + // Call mgr to begin the deauthentication + // reason = (3) beacuse sta has left ESS + if (pMgmt->eCurrState>= WMAC_STATE_AUTH) { + vMgrDeAuthenBeginSta((HANDLE)pDevice, pMgmt, pMgmt->abyCurrBSSID, (3), &Status); + } + // Call mgr to begin the authentication + vMgrAuthenBeginSta((HANDLE)pDevice, pMgmt, &Status); + if (Status == CMD_STATUS_SUCCESS) { + pDevice->byLinkWaitCount = 0; + pDevice->eCommandState = WLAN_AUTHENTICATE_WAIT; + vCommandTimerWait((HANDLE)pDevice, AUTHENTICATE_TIMEOUT); + spin_unlock_irq(&pDevice->lock); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO" Set eCommandState = WLAN_AUTHENTICATE_WAIT\n"); + return; + } + } + // if Adhoc mode + else if (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) { + if (pMgmt->eCurrState == WMAC_STATE_JOINTED) { + if (netif_queue_stopped(pDevice->dev)){ + netif_wake_queue(pDevice->dev); + } + pDevice->bLinkPass = TRUE; + + pMgmt->sNodeDBTable[0].bActive = TRUE; + pMgmt->sNodeDBTable[0].uInActiveCount = 0; + bClearBSSID_SCAN(pDevice); + } + else { + // start own IBSS + vMgrCreateOwnIBSS((HANDLE)pDevice, &Status); + if (Status != CMD_STATUS_SUCCESS){ + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " WLAN_CMD_IBSS_CREATE fail ! \n"); + }; + BSSvAddMulticastNode(pDevice); + } + } + // if SSID not found + else if (pMgmt->eCurrMode == WMAC_MODE_STANDBY) { + if (pMgmt->eConfigMode == WMAC_CONFIG_IBSS_STA || + pMgmt->eConfigMode == WMAC_CONFIG_AUTO) { + // start own IBSS + vMgrCreateOwnIBSS((HANDLE)pDevice, &Status); + if (Status != CMD_STATUS_SUCCESS){ + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO" WLAN_CMD_IBSS_CREATE fail ! \n"); + }; + BSSvAddMulticastNode(pDevice); + if (netif_queue_stopped(pDevice->dev)){ + netif_wake_queue(pDevice->dev); + } + pDevice->bLinkPass = TRUE; + } + else { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Disconnect SSID none\n"); + #ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT + // if(pDevice->bWPASuppWextEnabled == TRUE) + { + union iwreq_data wrqu; + memset(&wrqu, 0, sizeof (wrqu)); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + printk("wireless_send_event--->SIOCGIWAP(disassociated:vMgrJoinBSSBegin Fail !!)\n"); + wireless_send_event(pDevice->dev, SIOCGIWAP, &wrqu, NULL); + } + #endif + + } + } + s_bCommandComplete(pDevice); + break; + + case WLAN_AUTHENTICATE_WAIT : + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"eCommandState == WLAN_AUTHENTICATE_WAIT\n"); + if (pMgmt->eCurrState == WMAC_STATE_AUTH) { + // Call mgr to begin the association + pDevice->byLinkWaitCount = 0; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"eCurrState == WMAC_STATE_AUTH\n"); + vMgrAssocBeginSta((HANDLE)pDevice, pMgmt, &Status); + if (Status == CMD_STATUS_SUCCESS) { + pDevice->byLinkWaitCount = 0; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"eCommandState = WLAN_ASSOCIATE_WAIT\n"); + pDevice->eCommandState = WLAN_ASSOCIATE_WAIT; + vCommandTimerWait((HANDLE)pDevice, ASSOCIATE_TIMEOUT); + spin_unlock_irq(&pDevice->lock); + return; + } + } + + else if(pMgmt->eCurrState < WMAC_STATE_AUTHPENDING) { + printk("WLAN_AUTHENTICATE_WAIT:Authen Fail???\n"); + } + else if(pDevice->byLinkWaitCount <= 4){ //mike add:wait another 2 sec if authenticated_frame delay! + pDevice->byLinkWaitCount ++; + printk("WLAN_AUTHENTICATE_WAIT:wait %d times!!\n",pDevice->byLinkWaitCount); + spin_unlock_irq(&pDevice->lock); + vCommandTimerWait((HANDLE)pDevice, AUTHENTICATE_TIMEOUT/2); + return; + } + pDevice->byLinkWaitCount = 0; + #if 0 + #ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT + // if(pDevice->bWPASuppWextEnabled == TRUE) + { + union iwreq_data wrqu; + memset(&wrqu, 0, sizeof (wrqu)); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + printk("wireless_send_event--->SIOCGIWAP(disassociated:AUTHENTICATE_WAIT_timeout)\n"); + wireless_send_event(pDevice->dev, SIOCGIWAP, &wrqu, NULL); + } + #endif + #endif + s_bCommandComplete(pDevice); + break; + + case WLAN_ASSOCIATE_WAIT : + if (pMgmt->eCurrState == WMAC_STATE_ASSOC) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"eCurrState == WMAC_STATE_ASSOC\n"); + if (pDevice->ePSMode != WMAC_POWER_CAM) { + PSvEnablePowerSaving((HANDLE)pDevice, pMgmt->wListenInterval); + } + if (pMgmt->eAuthenMode >= WMAC_AUTH_WPA) { + KeybRemoveAllKey(&(pDevice->sKey), pDevice->abyBSSID, pDevice->PortOffset); + } + pDevice->bLinkPass = TRUE; + pDevice->byLinkWaitCount = 0; + pDevice->byReAssocCount = 0; + bClearBSSID_SCAN(pDevice); + if (pDevice->byFOETuning) { + BBvSetFOE(pDevice->PortOffset); + PSbSendNullPacket(pDevice); + } + if (netif_queue_stopped(pDevice->dev)){ + netif_wake_queue(pDevice->dev); + } + #ifdef TxInSleep + if(pDevice->IsTxDataTrigger != FALSE) { //TxDataTimer is not triggered at the first time + // printk("Re-initial TxDataTimer****\n"); + del_timer(&pDevice->sTimerTxData); + init_timer(&pDevice->sTimerTxData); + pDevice->sTimerTxData.data = (ULONG)pDevice; + pDevice->sTimerTxData.function = (TimerFunction)BSSvSecondTxData; + pDevice->sTimerTxData.expires = RUN_AT(10*HZ); //10s callback + pDevice->fTxDataInSleep = FALSE; + pDevice->nTxDataTimeCout = 0; + } + else { + // printk("mike:-->First time triger TimerTxData InSleep\n"); + } + pDevice->IsTxDataTrigger = TRUE; + add_timer(&pDevice->sTimerTxData); + #endif + } + else if(pMgmt->eCurrState < WMAC_STATE_ASSOCPENDING) { + printk("WLAN_ASSOCIATE_WAIT:Association Fail???\n"); + } + else if(pDevice->byLinkWaitCount <= 4){ //mike add:wait another 2 sec if associated_frame delay! + pDevice->byLinkWaitCount ++; + printk("WLAN_ASSOCIATE_WAIT:wait %d times!!\n",pDevice->byLinkWaitCount); + spin_unlock_irq(&pDevice->lock); + vCommandTimerWait((HANDLE)pDevice, ASSOCIATE_TIMEOUT/2); + return; + } + pDevice->byLinkWaitCount = 0; + #if 0 + #ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT + // if(pDevice->bWPASuppWextEnabled == TRUE) + { + union iwreq_data wrqu; + memset(&wrqu, 0, sizeof (wrqu)); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + printk("wireless_send_event--->SIOCGIWAP(disassociated:ASSOCIATE_WAIT_timeout)\n"); + wireless_send_event(pDevice->dev, SIOCGIWAP, &wrqu, NULL); + } + #endif + #endif + + s_bCommandComplete(pDevice); + break; + + case WLAN_CMD_AP_MODE_START : + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"eCommandState == WLAN_CMD_AP_MODE_START\n"); + + if (pMgmt->eConfigMode == WMAC_CONFIG_AP) { + del_timer(&pMgmt->sTimerSecondCallback); + pMgmt->eCurrState = WMAC_STATE_IDLE; + pMgmt->eCurrMode = WMAC_MODE_STANDBY; + pDevice->bLinkPass = FALSE; + if (pDevice->bEnableHostWEP == TRUE) + BSSvClearNodeDBTable(pDevice, 1); + else + BSSvClearNodeDBTable(pDevice, 0); + pDevice->uAssocCount = 0; + pMgmt->eCurrState = WMAC_STATE_IDLE; + pDevice->bFixRate = FALSE; + + vMgrCreateOwnIBSS((HANDLE)pDevice, &Status); + if (Status != CMD_STATUS_SUCCESS){ + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " vMgrCreateOwnIBSS fail ! \n"); + }; + // alway turn off unicast bit + MACvRegBitsOff(pDevice->PortOffset, MAC_REG_RCR, RCR_UNICAST); + pDevice->byRxMode &= ~RCR_UNICAST; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "wcmd: rx_mode = %x\n", pDevice->byRxMode ); + BSSvAddMulticastNode(pDevice); + if (netif_queue_stopped(pDevice->dev)){ + netif_wake_queue(pDevice->dev); + } + pDevice->bLinkPass = TRUE; + add_timer(&pMgmt->sTimerSecondCallback); + } + s_bCommandComplete(pDevice); + break; + + case WLAN_CMD_TX_PSPACKET_START : + // DTIM Multicast tx + if (pMgmt->sNodeDBTable[0].bRxPSPoll) { + while ((skb = skb_dequeue(&pMgmt->sNodeDBTable[0].sTxPSQueue)) != NULL) { + if (skb_queue_empty(&pMgmt->sNodeDBTable[0].sTxPSQueue)) { + pMgmt->abyPSTxMap[0] &= ~byMask[0]; + pDevice->bMoreData = FALSE; + } + else { + pDevice->bMoreData = TRUE; + } + if (!device_dma0_xmit(pDevice, skb, 0)) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Multicast ps tx fail \n"); + } + pMgmt->sNodeDBTable[0].wEnQueueCnt--; + } + }; + + // PS nodes tx + for (ii = 1; ii < (MAX_NODE_NUM + 1); ii++) { + if (pMgmt->sNodeDBTable[ii].bActive && + pMgmt->sNodeDBTable[ii].bRxPSPoll) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Index=%d Enqueu Cnt= %d\n", + ii, pMgmt->sNodeDBTable[ii].wEnQueueCnt); + while ((skb = skb_dequeue(&pMgmt->sNodeDBTable[ii].sTxPSQueue)) != NULL) { + if (skb_queue_empty(&pMgmt->sNodeDBTable[ii].sTxPSQueue)) { + // clear tx map + pMgmt->abyPSTxMap[pMgmt->sNodeDBTable[ii].wAID >> 3] &= + ~byMask[pMgmt->sNodeDBTable[ii].wAID & 7]; + pDevice->bMoreData = FALSE; + } + else { + pDevice->bMoreData = TRUE; + } + if (!device_dma0_xmit(pDevice, skb, ii)) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "sta ps tx fail \n"); + } + pMgmt->sNodeDBTable[ii].wEnQueueCnt--; + // check if sta ps enable, wait next pspoll + // if sta ps disable, send all pending buffers. + if (pMgmt->sNodeDBTable[ii].bPSEnable) + break; + } + if (skb_queue_empty(&pMgmt->sNodeDBTable[ii].sTxPSQueue)) { + // clear tx map + pMgmt->abyPSTxMap[pMgmt->sNodeDBTable[ii].wAID >> 3] &= + ~byMask[pMgmt->sNodeDBTable[ii].wAID & 7]; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Index=%d PS queue clear \n", ii); + } + pMgmt->sNodeDBTable[ii].bRxPSPoll = FALSE; + } + } + + s_bCommandComplete(pDevice); + break; + + + case WLAN_CMD_RADIO_START : + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"eCommandState == WLAN_CMD_RADIO_START\n"); + if (pDevice->bRadioCmd == TRUE) + CARDbRadioPowerOn(pDevice); + else + CARDbRadioPowerOff(pDevice); + + s_bCommandComplete(pDevice); + break; + + + case WLAN_CMD_CHECK_BBSENSITIVITY_CHANGE : + //DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"eCommandState == WLAN_CMD_CHECK_BBSENSITIVITY_START\n"); + // wait all TD complete + if (pDevice->iTDUsed[TYPE_AC0DMA] != 0){ + vCommandTimerWait((HANDLE)pDevice, 10); + spin_unlock_irq(&pDevice->lock); + return; + } + if (pDevice->iTDUsed[TYPE_TXDMA0] != 0){ + vCommandTimerWait((HANDLE)pDevice, 10); + spin_unlock_irq(&pDevice->lock); + return; + } + pDevice->byBBVGACurrent = pDevice->byBBVGANew; + BBvSetVGAGainOffset(pDevice, pDevice->byBBVGACurrent); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"SetVGAGainOffset %02X\n", pDevice->byBBVGACurrent); + s_bCommandComplete(pDevice); + break; + + default : + s_bCommandComplete(pDevice); + break; + + } //switch + spin_unlock_irq(&pDevice->lock); + return; + +} + + +static +BOOL +s_bCommandComplete ( + PSDevice pDevice + ) +{ + PWLAN_IE_SSID pSSID; + BOOL bRadioCmd = FALSE; + //WORD wDeAuthenReason = 0; + BOOL bForceSCAN = TRUE; + PSMgmtObject pMgmt = pDevice->pMgmt; + + + pDevice->eCommandState = WLAN_CMD_IDLE; + if (pDevice->cbFreeCmdQueue == CMD_Q_SIZE) { + //Command Queue Empty + pDevice->bCmdRunning = FALSE; + return TRUE; + } + else { + pDevice->eCommand = pDevice->eCmdQueue[pDevice->uCmdDequeueIdx].eCmd; + pSSID = (PWLAN_IE_SSID)pDevice->eCmdQueue[pDevice->uCmdDequeueIdx].abyCmdDesireSSID; + bRadioCmd = pDevice->eCmdQueue[pDevice->uCmdDequeueIdx].bRadioCmd; + bForceSCAN = pDevice->eCmdQueue[pDevice->uCmdDequeueIdx].bForceSCAN; + ADD_ONE_WITH_WRAP_AROUND(pDevice->uCmdDequeueIdx, CMD_Q_SIZE); + pDevice->cbFreeCmdQueue++; + pDevice->bCmdRunning = TRUE; + switch ( pDevice->eCommand ) { + case WLAN_CMD_BSSID_SCAN: + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"eCommandState= WLAN_CMD_BSSID_SCAN\n"); + pDevice->eCommandState = WLAN_CMD_SCAN_START; + pMgmt->uScanChannel = 0; + if (pSSID->len != 0) { + MEMvCopy(pMgmt->abyScanSSID, pSSID, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1); + } else { + memset(pMgmt->abyScanSSID, 0, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1); + } +/* + if ((bForceSCAN == FALSE) && (pDevice->bLinkPass == TRUE)) { + if ((pSSID->len == ((PWLAN_IE_SSID)pMgmt->abyCurrSSID)->len) && + (MEMEqualMemory(pSSID->abySSID, ((PWLAN_IE_SSID)pMgmt->abyCurrSSID)->abySSID, pSSID->len))) { + pDevice->eCommandState = WLAN_CMD_IDLE; + } + } +*/ + break; + case WLAN_CMD_SSID: + pDevice->eCommandState = WLAN_CMD_SSID_START; + if (pSSID->len > WLAN_SSID_MAXLEN) + pSSID->len = WLAN_SSID_MAXLEN; + if (pSSID->len != 0) + MEMvCopy(pDevice->pMgmt->abyDesireSSID, pSSID, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"eCommandState= WLAN_CMD_SSID_START\n"); + break; + case WLAN_CMD_DISASSOCIATE: + pDevice->eCommandState = WLAN_CMD_DISASSOCIATE_START; + break; + case WLAN_CMD_RX_PSPOLL: + pDevice->eCommandState = WLAN_CMD_TX_PSPACKET_START; + break; + case WLAN_CMD_RUN_AP: + pDevice->eCommandState = WLAN_CMD_AP_MODE_START; + break; + case WLAN_CMD_RADIO: + pDevice->eCommandState = WLAN_CMD_RADIO_START; + pDevice->bRadioCmd = bRadioCmd; + break; + case WLAN_CMD_CHANGE_BBSENSITIVITY: + pDevice->eCommandState = WLAN_CMD_CHECK_BBSENSITIVITY_CHANGE; + break; + + default: + break; + + } + + vCommandTimerWait((HANDLE)pDevice, 0); + } + + return TRUE; +} + + + +BOOL bScheduleCommand ( + IN HANDLE hDeviceContext, + IN CMD_CODE eCommand, + IN PBYTE pbyItem0 + ) +{ + PSDevice pDevice = (PSDevice)hDeviceContext; + + + if (pDevice->cbFreeCmdQueue == 0) { + return (FALSE); + } + pDevice->eCmdQueue[pDevice->uCmdEnqueueIdx].eCmd = eCommand; + pDevice->eCmdQueue[pDevice->uCmdEnqueueIdx].bForceSCAN = TRUE; + memset(pDevice->eCmdQueue[pDevice->uCmdEnqueueIdx].abyCmdDesireSSID, 0 , WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1); + + if (pbyItem0 != NULL) { + switch (eCommand) { + + case WLAN_CMD_BSSID_SCAN: + MEMvCopy(pDevice->eCmdQueue[pDevice->uCmdEnqueueIdx].abyCmdDesireSSID, + pbyItem0, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1); + pDevice->eCmdQueue[pDevice->uCmdEnqueueIdx].bForceSCAN = FALSE; + break; + + case WLAN_CMD_SSID: + MEMvCopy(pDevice->eCmdQueue[pDevice->uCmdEnqueueIdx].abyCmdDesireSSID, + pbyItem0, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1); + break; + + case WLAN_CMD_DISASSOCIATE: + pDevice->eCmdQueue[pDevice->uCmdEnqueueIdx].bNeedRadioOFF = *((PBOOL)pbyItem0); + break; +/* + case WLAN_CMD_DEAUTH: + pDevice->eCmdQueue[pDevice->uCmdEnqueueIdx].wDeAuthenReason = *((PWORD)pbyItem0); + break; +*/ + + case WLAN_CMD_RX_PSPOLL: + break; + + case WLAN_CMD_RADIO: + pDevice->eCmdQueue[pDevice->uCmdEnqueueIdx].bRadioCmd = *((PBOOL)pbyItem0); + break; + + case WLAN_CMD_CHANGE_BBSENSITIVITY: + pDevice->eCommandState = WLAN_CMD_CHECK_BBSENSITIVITY_CHANGE; + break; + + default: + break; + } + } + + ADD_ONE_WITH_WRAP_AROUND(pDevice->uCmdEnqueueIdx, CMD_Q_SIZE); + pDevice->cbFreeCmdQueue--; + + if (pDevice->bCmdRunning == FALSE) { + s_bCommandComplete(pDevice); + } + else { + } + return (TRUE); + +} + +/* + * Description: + * Clear BSSID_SCAN cmd in CMD Queue + * + * Parameters: + * In: + * hDeviceContext - Pointer to the adapter + * eCommand - Command + * Out: + * none + * + * Return Value: TRUE if success; otherwise FALSE + * + */ +BOOL bClearBSSID_SCAN ( + IN HANDLE hDeviceContext + ) +{ + PSDevice pDevice = (PSDevice)hDeviceContext; + UINT uCmdDequeueIdx = pDevice->uCmdDequeueIdx; + UINT ii; + + if ((pDevice->cbFreeCmdQueue < CMD_Q_SIZE) && (uCmdDequeueIdx != pDevice->uCmdEnqueueIdx)) { + for (ii = 0; ii < (CMD_Q_SIZE - pDevice->cbFreeCmdQueue); ii ++) { + if (pDevice->eCmdQueue[uCmdDequeueIdx].eCmd == WLAN_CMD_BSSID_SCAN) + pDevice->eCmdQueue[uCmdDequeueIdx].eCmd = WLAN_CMD_IDLE; + ADD_ONE_WITH_WRAP_AROUND(uCmdDequeueIdx, CMD_Q_SIZE); + if (uCmdDequeueIdx == pDevice->uCmdEnqueueIdx) + break; + } + } + return TRUE; +} + +//mike add:reset command timer +VOID +vResetCommandTimer( + IN HANDLE hDeviceContext + ) +{ + PSDevice pDevice = (PSDevice)hDeviceContext; + + //delete timer + del_timer(&pDevice->sTimerCommand); + //init timer + init_timer(&pDevice->sTimerCommand); + pDevice->sTimerCommand.data = (ULONG)pDevice; + pDevice->sTimerCommand.function = (TimerFunction)vCommandTimer; + pDevice->sTimerCommand.expires = RUN_AT(HZ); + pDevice->cbFreeCmdQueue = CMD_Q_SIZE; + pDevice->uCmdDequeueIdx = 0; + pDevice->uCmdEnqueueIdx = 0; + pDevice->eCommandState = WLAN_CMD_IDLE; + pDevice->bCmdRunning = FALSE; + pDevice->bCmdClear = FALSE; +} + + +#ifdef TxInSleep +VOID +BSSvSecondTxData( + IN HANDLE hDeviceContext + ) +{ + PSDevice pDevice = (PSDevice)hDeviceContext; + PSMgmtObject pMgmt = &(pDevice->sMgmtObj); + pDevice->nTxDataTimeCout++; + + if(pDevice->nTxDataTimeCout<4) //don't tx data if timer less than 40s + { + // printk("mike:%s-->no data Tx not exceed the desired Time as %d\n",__FUNCTION__, + // (int)pDevice->nTxDataTimeCout); + pDevice->sTimerTxData.expires = RUN_AT(10*HZ); //10s callback + add_timer(&pDevice->sTimerTxData); + return; + } + + spin_lock_irq(&pDevice->lock); + #if 1 + if(((pDevice->bLinkPass ==TRUE)&&(pMgmt->eAuthenMode < WMAC_AUTH_WPA)) || //open && sharekey linking + (pDevice->fWPA_Authened == TRUE)) { //wpa linking + #else + if(pDevice->bLinkPass ==TRUE) { + #endif + + // printk("mike:%s-->InSleep Tx Data Procedure\n",__FUNCTION__); + pDevice->fTxDataInSleep = TRUE; + PSbSendNullPacket(pDevice); //send null packet + pDevice->fTxDataInSleep = FALSE; + } + spin_unlock_irq(&pDevice->lock); + + pDevice->sTimerTxData.expires = RUN_AT(10*HZ); //10s callback + add_timer(&pDevice->sTimerTxData); + return; +} +#endif + diff --git a/drivers/staging/vt6655/wcmd.h b/drivers/staging/vt6655/wcmd.h new file mode 100644 index 000000000000..8c6bbc49f0bc --- /dev/null +++ b/drivers/staging/vt6655/wcmd.h @@ -0,0 +1,151 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * File: wcmd.h + * + * Purpose: Handles the management command interface functions + * + * Author: Lyndon Chen + * + * Date: May 8, 2002 + * + */ + +#ifndef __WCMD_H__ +#define __WCMD_H__ + +#if !defined(__TTYPE_H__) +#include "ttype.h" +#endif +#if !defined(__80211HDR_H__) +#include "80211hdr.h" +#endif +#if !defined(__80211MGR_H__) +#include "80211mgr.h" +#endif + +/*--------------------- Export Definitions -------------------------*/ + + + +#define AUTHENTICATE_TIMEOUT 1000 //ms +#define ASSOCIATE_TIMEOUT 1000 //ms + +// Command code +typedef enum tagCMD_CODE { + WLAN_CMD_BSSID_SCAN, + WLAN_CMD_SSID, + WLAN_CMD_DISASSOCIATE, + WLAN_CMD_DEAUTH, + WLAN_CMD_RX_PSPOLL, + WLAN_CMD_RADIO, + WLAN_CMD_CHANGE_BBSENSITIVITY, + WLAN_CMD_SETPOWER, + WLAN_CMD_TBTT_WAKEUP, + WLAN_CMD_BECON_SEND, + WLAN_CMD_CHANGE_ANTENNA, + WLAN_CMD_REMOVE_ALLKEY, + WLAN_CMD_MAC_DISPOWERSAVING, + WLAN_CMD_11H_CHSW, + WLAN_CMD_RUN_AP +} CMD_CODE, DEF* PCMD_CODE; + +#define CMD_Q_SIZE 32 + + +// Command code +typedef enum tagCMD_STATUS { + + CMD_STATUS_SUCCESS, + CMD_STATUS_FAILURE, + CMD_STATUS_RESOURCES, + CMD_STATUS_TIMEOUT, + CMD_STATUS_PENDING + +} CMD_STATUS, DEF* PCMD_STATUS; + + +typedef struct tagCMD_ITEM { + CMD_CODE eCmd; + BYTE abyCmdDesireSSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1]; + BOOL bNeedRadioOFF; + WORD wDeAuthenReason; + BOOL bRadioCmd; + BOOL bForceSCAN; +} CMD_ITEM, DEF* PCMD_ITEM; + +// Command state +typedef enum tagCMD_STATE { + WLAN_CMD_SCAN_START, + WLAN_CMD_SCAN_END, + WLAN_CMD_DISASSOCIATE_START, + WLAN_CMD_SSID_START, + WLAN_AUTHENTICATE_WAIT, + WLAN_ASSOCIATE_WAIT, + WLAN_DISASSOCIATE_WAIT, + WLAN_CMD_TX_PSPACKET_START, + WLAN_CMD_AP_MODE_START, + WLAN_CMD_RADIO_START, + WLAN_CMD_CHECK_BBSENSITIVITY_CHANGE, + WLAN_CMD_IDLE +} CMD_STATE, DEF* PCMD_STATE; + + +/*--------------------- Export Classes ----------------------------*/ + +/*--------------------- Export Variables --------------------------*/ + + +/*--------------------- Export Types ------------------------------*/ + + +/*--------------------- Export Functions --------------------------*/ + +VOID +vResetCommandTimer( + IN HANDLE hDeviceContext + ); + +VOID +vCommandTimer ( + IN HANDLE hDeviceContext + ); + +BOOL bClearBSSID_SCAN( + IN HANDLE hDeviceContext + ); + +BOOL +bScheduleCommand( + IN HANDLE hDeviceContext, + IN CMD_CODE eCommand, + IN PBYTE pbyItem0 + ); + +VOID +vCommandTimerWait( + IN HANDLE hDeviceContext, + IN UINT MSecond + ); +#ifdef TxInSleep +VOID +BSSvSecondTxData( + IN HANDLE hDeviceContext + ); +#endif +#endif //__WCMD_H__ diff --git a/drivers/staging/vt6655/wctl.c b/drivers/staging/vt6655/wctl.c new file mode 100644 index 000000000000..b4fecc2ed55c --- /dev/null +++ b/drivers/staging/vt6655/wctl.c @@ -0,0 +1,261 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * File: wctl.c + * + * Purpose: handle WMAC duplicate filter & defragment + * + * Author: Jerry Chen + * + * Date: Jun. 27, 2002 + * + * Functions: + * WCTLbIsDuplicate - Test if duplicate packet + * WCTLuSearchDFCB - Search DeFragment Control Database + * WCTLuInsertDFCB - Insert DeFragment Control Database + * WCTLbHandleFragment - Handle received fragment packet + * + * Revision History: + * + */ + + +#if !defined(__WCTL_H__) +#include "wctl.h" +#endif +#if !defined(__DEVICE_H__) +#include "device.h" +#endif +#if !defined(__CARD_H__) +#include "card.h" +#endif + +/*--------------------- Static Definitions -------------------------*/ + +/*--------------------- Static Classes ----------------------------*/ + +/*--------------------- Static Variables --------------------------*/ +// static int msglevel =MSG_LEVEL_INFO; +/*--------------------- Static Functions --------------------------*/ + +/*--------------------- Export Variables --------------------------*/ + + + +/* + * Description: + * Scan Rx cache. Return TRUE if packet is duplicate, else + * inserts in receive cache and returns FALSE. + * + * Parameters: + * In: + * pCache - Receive packets history + * pMACHeader - 802.11 MAC Header of received packet + * Out: + * none + * + * Return Value: TRUE if packet duplicate; otherwise FALSE + * + */ + +BOOL WCTLbIsDuplicate (PSCache pCache, PS802_11Header pMACHeader) +{ + UINT uIndex; + UINT ii; + PSCacheEntry pCacheEntry; + + if (IS_FC_RETRY(pMACHeader)) { + + uIndex = pCache->uInPtr; + for (ii = 0; ii < DUPLICATE_RX_CACHE_LENGTH; ii++) { + pCacheEntry = &(pCache->asCacheEntry[uIndex]); + if ((pCacheEntry->wFmSequence == pMACHeader->wSeqCtl) && + (IS_ETH_ADDRESS_EQUAL (&(pCacheEntry->abyAddr2[0]), &(pMACHeader->abyAddr2[0]))) + ) { + /* Duplicate match */ + return TRUE; + } + ADD_ONE_WITH_WRAP_AROUND(uIndex, DUPLICATE_RX_CACHE_LENGTH); + } + } + /* Not fount in cache - insert */ + pCacheEntry = &pCache->asCacheEntry[pCache->uInPtr]; + pCacheEntry->wFmSequence = pMACHeader->wSeqCtl; + memcpy(&(pCacheEntry->abyAddr2[0]), &(pMACHeader->abyAddr2[0]), U_ETHER_ADDR_LEN); + ADD_ONE_WITH_WRAP_AROUND(pCache->uInPtr, DUPLICATE_RX_CACHE_LENGTH); + return FALSE; +} + +/* + * Description: + * Found if sequence number of received fragment packet in Defragment Database + * + * Parameters: + * In: + * pDevice - Pointer to adapter + * pMACHeader - 802.11 MAC Header of received packet + * Out: + * none + * + * Return Value: index number in Defragment Database + * + */ +UINT WCTLuSearchDFCB (PSDevice pDevice, PS802_11Header pMACHeader) +{ +UINT ii; + + for(ii=0;iicbDFCB;ii++) { + if ((pDevice->sRxDFCB[ii].bInUse == TRUE) && + (IS_ETH_ADDRESS_EQUAL (&(pDevice->sRxDFCB[ii].abyAddr2[0]), &(pMACHeader->abyAddr2[0]))) + ) { + // + return(ii); + } + } + return(pDevice->cbDFCB); +} + + +/* + * Description: + * Insert received fragment packet in Defragment Database + * + * Parameters: + * In: + * pDevice - Pointer to adapter + * pMACHeader - 802.11 MAC Header of received packet + * Out: + * none + * + * Return Value: index number in Defragment Database + * + */ +UINT WCTLuInsertDFCB (PSDevice pDevice, PS802_11Header pMACHeader) +{ +UINT ii; + + if (pDevice->cbFreeDFCB == 0) + return(pDevice->cbDFCB); + for(ii=0;iicbDFCB;ii++) { + if (pDevice->sRxDFCB[ii].bInUse == FALSE) { + pDevice->cbFreeDFCB--; + pDevice->sRxDFCB[ii].uLifetime = pDevice->dwMaxReceiveLifetime; + pDevice->sRxDFCB[ii].bInUse = TRUE; + pDevice->sRxDFCB[ii].wSequence = (pMACHeader->wSeqCtl >> 4); + pDevice->sRxDFCB[ii].wFragNum = (pMACHeader->wSeqCtl & 0x000F); + memcpy(&(pDevice->sRxDFCB[ii].abyAddr2[0]), &(pMACHeader->abyAddr2[0]), U_ETHER_ADDR_LEN); + return(ii); + } + } + return(pDevice->cbDFCB); +} + + +/* + * Description: + * Handle received fragment packet + * + * Parameters: + * In: + * pDevice - Pointer to adapter + * pMACHeader - 802.11 MAC Header of received packet + * cbFrameLength - Frame length + * bWEP - is WEP packet + * Out: + * none + * + * Return Value: TRUE if it is valid fragment packet and we have resource to defragment; otherwise FALSE + * + */ +BOOL WCTLbHandleFragment (PSDevice pDevice, PS802_11Header pMACHeader, UINT cbFrameLength, BOOL bWEP, BOOL bExtIV) +{ +UINT uHeaderSize; + + + if (bWEP == TRUE) { + uHeaderSize = 28; + if (bExtIV) + // ExtIV + uHeaderSize +=4; + } + else { + uHeaderSize = 24; + } + + if (IS_FIRST_FRAGMENT_PKT(pMACHeader)) { + pDevice->uCurrentDFCBIdx = WCTLuSearchDFCB(pDevice, pMACHeader); + if (pDevice->uCurrentDFCBIdx < pDevice->cbDFCB) { + // duplicate, we must flush previous DCB + pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].uLifetime = pDevice->dwMaxReceiveLifetime; + pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].wSequence = (pMACHeader->wSeqCtl >> 4); + pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].wFragNum = (pMACHeader->wSeqCtl & 0x000F); + } + else { + pDevice->uCurrentDFCBIdx = WCTLuInsertDFCB(pDevice, pMACHeader); + if (pDevice->uCurrentDFCBIdx == pDevice->cbDFCB) { + return(FALSE); + } + } + // reserve 4 byte to match MAC RX Buffer +#ifdef PRIVATE_OBJ + pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].pbyRxBuffer = (PBYTE) (pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].ref_skb.data + 4); +#else + pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].pbyRxBuffer = (PBYTE) (pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].skb->data + 4); +#endif + memcpy(pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].pbyRxBuffer, pMACHeader, cbFrameLength); + pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].cbFrameLength = cbFrameLength; + pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].pbyRxBuffer += cbFrameLength; + pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].wFragNum++; + //DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "First pDevice->uCurrentDFCBIdx= %d\n", pDevice->uCurrentDFCBIdx); + return(FALSE); + } + else { + pDevice->uCurrentDFCBIdx = WCTLuSearchDFCB(pDevice, pMACHeader); + if (pDevice->uCurrentDFCBIdx != pDevice->cbDFCB) { + if ((pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].wSequence == (pMACHeader->wSeqCtl >> 4)) && + (pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].wFragNum == (pMACHeader->wSeqCtl & 0x000F)) && + ((pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].cbFrameLength + cbFrameLength - uHeaderSize) < 2346)) { + + memcpy(pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].pbyRxBuffer, ((PBYTE) (pMACHeader) + uHeaderSize), (cbFrameLength - uHeaderSize)); + pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].cbFrameLength += (cbFrameLength - uHeaderSize); + pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].pbyRxBuffer += (cbFrameLength - uHeaderSize); + pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].wFragNum++; + //DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Second pDevice->uCurrentDFCBIdx= %d\n", pDevice->uCurrentDFCBIdx); + } + else { + // seq error or frag # error flush DFCB + pDevice->cbFreeDFCB++; + pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].bInUse = FALSE; + return(FALSE); + } + } + else { + return(FALSE); + } + if (IS_LAST_FRAGMENT_PKT(pMACHeader)) { + //enq defragcontrolblock + pDevice->cbFreeDFCB++; + pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].bInUse = FALSE; + //DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Last pDevice->uCurrentDFCBIdx= %d\n", pDevice->uCurrentDFCBIdx); + return(TRUE); + } + return(FALSE); + } +} + + diff --git a/drivers/staging/vt6655/wctl.h b/drivers/staging/vt6655/wctl.h new file mode 100644 index 000000000000..f75ca59f6c61 --- /dev/null +++ b/drivers/staging/vt6655/wctl.h @@ -0,0 +1,127 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * File: wctl.h + * + * Purpose: + * + * Author: Jerry Chen + * + * Date: Jun. 27, 2002 + * + */ + + +#ifndef __WCTL_H__ +#define __WCTL_H__ + +#if !defined(__TTYPE_H__) +#include "ttype.h" +#endif +#if !defined(__TETHER_H__) +#include "tether.h" +#endif +#if !defined(__DEVICE_H__) +#include "device.h" +#endif + + + +/*--------------------- Export Definitions -------------------------*/ + +#define IS_TYPE_DATA(pMACHeader) \ + ((((PS802_11Header) pMACHeader)->wFrameCtl & TYPE_802_11_MASK) == TYPE_802_11_DATA) + +#define IS_TYPE_MGMT(pMACHeader) \ + ((((PS802_11Header) pMACHeader)->wFrameCtl & TYPE_802_11_MASK) == TYPE_802_11_MGMT) + +#define IS_TYPE_CONTROL(pMACHeader) \ + ((((PS802_11Header) pMACHeader)->wFrameCtl & TYPE_802_11_MASK) == TYPE_802_11_CTL) + +#define IS_FC_MOREDATA(pMACHeader) \ + ((((PS802_11Header) pMACHeader)->wFrameCtl & FC_MOREDATA) == FC_MOREDATA) + +#define IS_FC_POWERMGT(pMACHeader) \ + ((((PS802_11Header) pMACHeader)->wFrameCtl & FC_POWERMGT) == FC_POWERMGT) + +#define IS_FC_RETRY(pMACHeader) \ + ((((PS802_11Header) pMACHeader)->wFrameCtl & FC_RETRY) == FC_RETRY) + +#define IS_FC_WEP(pMACHeader) \ + ((((PS802_11Header) pMACHeader)->wFrameCtl & FC_WEP) == FC_WEP) + +#ifdef __BIG_ENDIAN + +#define IS_FRAGMENT_PKT(pMACHeader) \ + (((((PS802_11Header) pMACHeader)->wFrameCtl & FC_MOREFRAG) != 0) | \ + ((((PS802_11Header) pMACHeader)->wSeqCtl & 0x0F00) != 0)) + +#define IS_FIRST_FRAGMENT_PKT(pMACHeader) \ + ((((PS802_11Header) pMACHeader)->wSeqCtl & 0x0F00) == 0) + +#else + +#define IS_FRAGMENT_PKT(pMACHeader) \ + (((((PS802_11Header) pMACHeader)->wFrameCtl & FC_MOREFRAG) != 0) | \ + ((((PS802_11Header) pMACHeader)->wSeqCtl & 0x000F) != 0)) + +#define IS_FIRST_FRAGMENT_PKT(pMACHeader) \ + ((((PS802_11Header) pMACHeader)->wSeqCtl & 0x000F) == 0) + +#endif//#ifdef __BIG_ENDIAN + +#define IS_LAST_FRAGMENT_PKT(pMACHeader) \ + ((((PS802_11Header) pMACHeader)->wFrameCtl & FC_MOREFRAG) == 0) + +#define IS_CTL_PSPOLL(pMACHeader) \ + ((((PS802_11Header) pMACHeader)->wFrameCtl & TYPE_SUBTYPE_MASK) == TYPE_CTL_PSPOLL) + + +#define ADD_ONE_WITH_WRAP_AROUND(uVar, uModulo) { \ + if ((uVar) >= ((uModulo) - 1)) \ + (uVar) = 0; \ + else \ + (uVar)++; \ +} + + +/*--------------------- Export Classes ----------------------------*/ + +/*--------------------- Export Variables --------------------------*/ + +/*--------------------- Export Functions --------------------------*/ +#ifdef __cplusplus +extern "C" { /* Assume C declarations for C++ */ +#endif /* __cplusplus */ + +BOOL WCTLbIsDuplicate(PSCache pCache, PS802_11Header pMACHeader); +BOOL WCTLbHandleFragment(PSDevice pDevice, PS802_11Header pMACHeader, UINT cbFrameLength, BOOL bWEP, BOOL bExtIV); +UINT WCTLuSearchDFCB(PSDevice pDevice, PS802_11Header pMACHeader); +UINT WCTLuInsertDFCB(PSDevice pDevice, PS802_11Header pMACHeader); + +#ifdef __cplusplus +} /* End of extern "C" { */ +#endif /* __cplusplus */ + + + + +#endif // __WCTL_H__ + + + diff --git a/drivers/staging/vt6655/wmgr.c b/drivers/staging/vt6655/wmgr.c new file mode 100644 index 000000000000..c0886edac789 --- /dev/null +++ b/drivers/staging/vt6655/wmgr.c @@ -0,0 +1,5088 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * File: wmgr.c + * + * Purpose: Handles the 802.11 management functions + * + * Author: Lyndon Chen + * + * Date: May 8, 2002 + * + * Functions: + * nsMgrObjectInitial - Initialize Management Objet data structure + * vMgrObjectReset - Reset Management Objet data structure + * vMgrAssocBeginSta - Start associate function + * vMgrReAssocBeginSta - Start reassociate function + * vMgrDisassocBeginSta - Start disassociate function + * s_vMgrRxAssocRequest - Handle Rcv associate_request + * s_vMgrRxAssocResponse - Handle Rcv associate_response + * vMrgAuthenBeginSta - Start authentication function + * vMgrDeAuthenDeginSta - Start deauthentication function + * s_vMgrRxAuthentication - Handle Rcv authentication + * s_vMgrRxAuthenSequence_1 - Handle Rcv authentication sequence 1 + * s_vMgrRxAuthenSequence_2 - Handle Rcv authentication sequence 2 + * s_vMgrRxAuthenSequence_3 - Handle Rcv authentication sequence 3 + * s_vMgrRxAuthenSequence_4 - Handle Rcv authentication sequence 4 + * s_vMgrRxDisassociation - Handle Rcv disassociation + * s_vMgrRxBeacon - Handle Rcv Beacon + * vMgrCreateOwnIBSS - Create ad_hoc IBSS or AP BSS + * vMgrJoinBSSBegin - Join BSS function + * s_vMgrSynchBSS - Synch & adopt BSS parameters + * s_MgrMakeBeacon - Create Baecon frame + * s_MgrMakeProbeResponse - Create Probe Response frame + * s_MgrMakeAssocRequest - Create Associate Request frame + * s_MgrMakeReAssocRequest - Create ReAssociate Request frame + * s_vMgrRxProbeResponse - Handle Rcv probe_response + * s_vMrgRxProbeRequest - Handle Rcv probe_request + * bMgrPrepareBeaconToSend - Prepare Beacon frame + * s_vMgrLogStatus - Log 802.11 Status + * vMgrRxManagePacket - Rcv management frame dispatch function + * s_vMgrFormatTIM- Assember TIM field of beacon + * vMgrTimerInit- Initial 1-sec and command call back funtions + * + * Revision History: + * + */ + + +#if !defined(__TMACRO_H__) +#include "tmacro.h" +#endif +#if !defined(__TBIT_H__) +#include "tbit.h" +#endif +#if !defined(__DESC_H__) +#include "desc.h" +#endif +#if !defined(__DEVICE_H__) +#include "device.h" +#endif +#if !defined(__CARD_H__) +#include "card.h" +#endif +#if !defined(__80211HDR_H__) +#include "80211hdr.h" +#endif +#if !defined(__80211MGR_H__) +#include "80211mgr.h" +#endif +#if !defined(__WMGR_H__) +#include "wmgr.h" +#endif +#if !defined(__WCMD_H__) +#include "wcmd.h" +#endif +#if !defined(__MAC_H__) +#include "mac.h" +#endif +#if !defined(__BSSDB_H__) +#include "bssdb.h" +#endif +#if !defined(__POWER_H__) +#include "power.h" +#endif +#if !defined(__DATARATE_H__) +#include "datarate.h" +#endif +#if !defined(__BASEBAND_H__) +#include "baseband.h" +#endif +#if !defined(__RXTX_H__) +#include "rxtx.h" +#endif +#if !defined(__WPA_H__) +#include "wpa.h" +#endif +#if !defined(__RF_H__) +#include "rf.h" +#endif +#if !defined(__UMEM_H__) +#include "umem.h" +#endif +#if !defined(__IOWPA_H__) +#include "iowpa.h" +#endif + +#define PLICE_DEBUG + +/*--------------------- Static Definitions -------------------------*/ + + + +/*--------------------- Static Classes ----------------------------*/ + +/*--------------------- Static Variables --------------------------*/ +static int msglevel =MSG_LEVEL_INFO; +//static int msglevel =MSG_LEVEL_DEBUG; + +/*--------------------- Static Functions --------------------------*/ +//2008-8-4 by chester +static BOOL ChannelExceedZoneType( + IN PSDevice pDevice, + IN BYTE byCurrChannel + ); +// Association/diassociation functions +static +PSTxMgmtPacket +s_MgrMakeAssocRequest( + IN PSDevice pDevice, + IN PSMgmtObject pMgmt, + IN PBYTE pDAddr, + IN WORD wCurrCapInfo, + IN WORD wListenInterval, + IN PWLAN_IE_SSID pCurrSSID, + IN PWLAN_IE_SUPP_RATES pCurrRates, + IN PWLAN_IE_SUPP_RATES pCurrExtSuppRates + ); + +static +VOID +s_vMgrRxAssocRequest( + IN PSDevice pDevice, + IN PSMgmtObject pMgmt, + IN PSRxMgmtPacket pRxPacket, + IN UINT uNodeIndex + ); + +static +PSTxMgmtPacket +s_MgrMakeReAssocRequest( + IN PSDevice pDevice, + IN PSMgmtObject pMgmt, + IN PBYTE pDAddr, + IN WORD wCurrCapInfo, + IN WORD wListenInterval, + IN PWLAN_IE_SSID pCurrSSID, + IN PWLAN_IE_SUPP_RATES pCurrRates, + IN PWLAN_IE_SUPP_RATES pCurrExtSuppRates + ); + +static +VOID +s_vMgrRxAssocResponse( + IN PSDevice pDevice, + IN PSMgmtObject pMgmt, + IN PSRxMgmtPacket pRxPacket, + IN BOOL bReAssocType + ); + +static +VOID +s_vMgrRxDisassociation( + IN PSDevice pDevice, + IN PSMgmtObject pMgmt, + IN PSRxMgmtPacket pRxPacket + ); + +// Authentication/deauthen functions +static +VOID +s_vMgrRxAuthenSequence_1( + IN PSDevice pDevice, + IN PSMgmtObject pMgmt, + IN PWLAN_FR_AUTHEN pFrame + ); + +static +VOID +s_vMgrRxAuthenSequence_2( + IN PSDevice pDevice, + IN PSMgmtObject pMgmt, + IN PWLAN_FR_AUTHEN pFrame + ); + +static +VOID +s_vMgrRxAuthenSequence_3( + IN PSDevice pDevice, + IN PSMgmtObject pMgmt, + IN PWLAN_FR_AUTHEN pFrame + ); + +static +VOID +s_vMgrRxAuthenSequence_4( + IN PSDevice pDevice, + IN PSMgmtObject pMgmt, + IN PWLAN_FR_AUTHEN pFrame + ); + +static +VOID +s_vMgrRxAuthentication( + IN PSDevice pDevice, + IN PSMgmtObject pMgmt, + IN PSRxMgmtPacket pRxPacket + ); + +static +VOID +s_vMgrRxDeauthentication( + IN PSDevice pDevice, + IN PSMgmtObject pMgmt, + IN PSRxMgmtPacket pRxPacket + ); + +// Scan functions +// probe request/response functions +static +VOID +s_vMgrRxProbeRequest( + IN PSDevice pDevice, + IN PSMgmtObject pMgmt, + IN PSRxMgmtPacket pRxPacket + ); + +static +VOID +s_vMgrRxProbeResponse( + IN PSDevice pDevice, + IN PSMgmtObject pMgmt, + IN PSRxMgmtPacket pRxPacket + ); + +// beacon functions +static +VOID +s_vMgrRxBeacon( + IN PSDevice pDevice, + IN PSMgmtObject pMgmt, + IN PSRxMgmtPacket pRxPacket, + IN BOOL bInScan + ); + +static +VOID +s_vMgrFormatTIM( + IN PSMgmtObject pMgmt, + IN PWLAN_IE_TIM pTIM + ); + +static +PSTxMgmtPacket +s_MgrMakeBeacon( + IN PSDevice pDevice, + IN PSMgmtObject pMgmt, + IN WORD wCurrCapInfo, + IN WORD wCurrBeaconPeriod, + IN UINT uCurrChannel, + IN WORD wCurrATIMWinodw, + IN PWLAN_IE_SSID pCurrSSID, + IN PBYTE pCurrBSSID, + IN PWLAN_IE_SUPP_RATES pCurrSuppRates, + IN PWLAN_IE_SUPP_RATES pCurrExtSuppRates + ); + + +// Association response +static +PSTxMgmtPacket +s_MgrMakeAssocResponse( + IN PSDevice pDevice, + IN PSMgmtObject pMgmt, + IN WORD wCurrCapInfo, + IN WORD wAssocStatus, + IN WORD wAssocAID, + IN PBYTE pDstAddr, + IN PWLAN_IE_SUPP_RATES pCurrSuppRates, + IN PWLAN_IE_SUPP_RATES pCurrExtSuppRates + ); + +// ReAssociation response +static +PSTxMgmtPacket +s_MgrMakeReAssocResponse( + IN PSDevice pDevice, + IN PSMgmtObject pMgmt, + IN WORD wCurrCapInfo, + IN WORD wAssocStatus, + IN WORD wAssocAID, + IN PBYTE pDstAddr, + IN PWLAN_IE_SUPP_RATES pCurrSuppRates, + IN PWLAN_IE_SUPP_RATES pCurrExtSuppRates + ); + +// Probe response +static +PSTxMgmtPacket +s_MgrMakeProbeResponse( + IN PSDevice pDevice, + IN PSMgmtObject pMgmt, + IN WORD wCurrCapInfo, + IN WORD wCurrBeaconPeriod, + IN UINT uCurrChannel, + IN WORD wCurrATIMWinodw, + IN PBYTE pDstAddr, + IN PWLAN_IE_SSID pCurrSSID, + IN PBYTE pCurrBSSID, + IN PWLAN_IE_SUPP_RATES pCurrSuppRates, + IN PWLAN_IE_SUPP_RATES pCurrExtSuppRates, + IN BYTE byPHYType + ); + +// received status +static +VOID +s_vMgrLogStatus( + IN PSMgmtObject pMgmt, + IN WORD wStatus + ); + + +static +VOID +s_vMgrSynchBSS ( + IN PSDevice pDevice, + IN UINT uBSSMode, + IN PKnownBSS pCurr, + OUT PCMD_STATUS pStatus + ); + + +static BOOL +s_bCipherMatch ( + IN PKnownBSS pBSSNode, + IN NDIS_802_11_ENCRYPTION_STATUS EncStatus, + OUT PBYTE pbyCCSPK, + OUT PBYTE pbyCCSGK + ); + + + static VOID Encyption_Rebuild( + IN PSDevice pDevice, + IN PKnownBSS pCurr + ); +/* +static +VOID +s_vProbeChannel( + IN PSDevice pDevice + ); + +static +VOID +s_vListenChannel( + IN PSDevice pDevice + ); + +static +PSTxMgmtPacket +s_MgrMakeProbeRequest( + IN PSMgmtObject pMgmt, + IN PBYTE pScanBSSID, + IN PWLAN_IE_SSID pSSID, + IN PWLAN_IE_SUPP_RATES pCurrRates + ); +*/ + + + +/*--------------------- Export Variables --------------------------*/ + + +/*--------------------- Export Functions --------------------------*/ + + +/*+ + * + * Routine Description: + * Allocates and initializes the Management object. + * + * Return Value: + * Ndis_staus. + * +-*/ + +VOID +vMgrObjectInit( + IN HANDLE hDeviceContext + ) +{ + PSDevice pDevice = (PSDevice)hDeviceContext; + PSMgmtObject pMgmt = pDevice->pMgmt; + int ii; + + + pMgmt->pbyPSPacketPool = &pMgmt->byPSPacketPool[0]; + pMgmt->pbyMgmtPacketPool = &pMgmt->byMgmtPacketPool[0]; + pMgmt->uCurrChannel = pDevice->uChannel; + for(ii=0;iiabyDesireBSSID[ii] = 0xFF; + } + pMgmt->sAssocInfo.AssocInfo.Length = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION); + //memset(pMgmt->abyDesireSSID, 0, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN +1); + pMgmt->byCSSPK = KEY_CTL_NONE; + pMgmt->byCSSGK = KEY_CTL_NONE; + pMgmt->wIBSSBeaconPeriod = DEFAULT_IBSS_BI; + BSSvClearBSSList((HANDLE)pDevice, FALSE); + + return; +} + +/*+ + * + * Routine Description: + * Initializes timer object + * + * Return Value: + * Ndis_staus. + * +-*/ + +void +vMgrTimerInit( + IN HANDLE hDeviceContext + ) +{ + PSDevice pDevice = (PSDevice)hDeviceContext; + PSMgmtObject pMgmt = pDevice->pMgmt; + + + init_timer(&pMgmt->sTimerSecondCallback); + pMgmt->sTimerSecondCallback.data = (ULONG)pDevice; + pMgmt->sTimerSecondCallback.function = (TimerFunction)BSSvSecondCallBack; + pMgmt->sTimerSecondCallback.expires = RUN_AT(HZ); + + init_timer(&pDevice->sTimerCommand); + pDevice->sTimerCommand.data = (ULONG)pDevice; + pDevice->sTimerCommand.function = (TimerFunction)vCommandTimer; + pDevice->sTimerCommand.expires = RUN_AT(HZ); + + #ifdef TxInSleep + init_timer(&pDevice->sTimerTxData); + pDevice->sTimerTxData.data = (ULONG)pDevice; + pDevice->sTimerTxData.function = (TimerFunction)BSSvSecondTxData; + pDevice->sTimerTxData.expires = RUN_AT(10*HZ); //10s callback + pDevice->fTxDataInSleep = FALSE; + pDevice->IsTxDataTrigger = FALSE; + pDevice->nTxDataTimeCout = 0; + #endif + + pDevice->cbFreeCmdQueue = CMD_Q_SIZE; + pDevice->uCmdDequeueIdx = 0; + pDevice->uCmdEnqueueIdx = 0; + + return; +} + + + +/*+ + * + * Routine Description: + * Reset the management object structure. + * + * Return Value: + * None. + * +-*/ + +VOID +vMgrObjectReset( + IN HANDLE hDeviceContext + ) +{ + PSDevice pDevice = (PSDevice)hDeviceContext; + PSMgmtObject pMgmt = pDevice->pMgmt; + + pMgmt->eCurrMode = WMAC_MODE_STANDBY; + pMgmt->eCurrState = WMAC_STATE_IDLE; + pDevice->bEnablePSMode = FALSE; + // TODO: timer + + return; +} + + +/*+ + * + * Routine Description: + * Start the station association procedure. Namely, send an + * association request frame to the AP. + * + * Return Value: + * None. + * +-*/ + + +VOID +vMgrAssocBeginSta( + IN HANDLE hDeviceContext, + IN PSMgmtObject pMgmt, + OUT PCMD_STATUS pStatus + ) +{ + PSDevice pDevice = (PSDevice)hDeviceContext; + PSTxMgmtPacket pTxPacket; + + + pMgmt->wCurrCapInfo = 0; + pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_ESS(1); + if (pDevice->bEncryptionEnable) { + pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_PRIVACY(1); + } + // always allow receive short preamble + //if (pDevice->byPreambleType == 1) { + // pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SHORTPREAMBLE(1); + //} + pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SHORTPREAMBLE(1); + if (pMgmt->wListenInterval == 0) + pMgmt->wListenInterval = 1; // at least one. + + // ERP Phy (802.11g) should support short preamble. + if (pMgmt->eCurrentPHYMode == PHY_TYPE_11G) { + pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SHORTPREAMBLE(1); + if (CARDbIsShorSlotTime(pMgmt->pAdapter) == TRUE) { + pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SHORTSLOTTIME(1); + } + } else if (pMgmt->eCurrentPHYMode == PHY_TYPE_11B) { + if (CARDbIsShortPreamble(pMgmt->pAdapter) == TRUE) { + pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SHORTPREAMBLE(1); + } + } + if (pMgmt->b11hEnable == TRUE) + pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SPECTRUMMNG(1); + + /* build an assocreq frame and send it */ + pTxPacket = s_MgrMakeAssocRequest + ( + pDevice, + pMgmt, + pMgmt->abyCurrBSSID, + pMgmt->wCurrCapInfo, + pMgmt->wListenInterval, + (PWLAN_IE_SSID)pMgmt->abyCurrSSID, + (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates, + (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates + ); + + if (pTxPacket != NULL ){ + /* send the frame */ + *pStatus = csMgmt_xmit(pDevice, pTxPacket); + if (*pStatus == CMD_STATUS_PENDING) { + pMgmt->eCurrState = WMAC_STATE_ASSOCPENDING; + *pStatus = CMD_STATUS_SUCCESS; + } + } + else + *pStatus = CMD_STATUS_RESOURCES; + + return ; +} + + +/*+ + * + * Routine Description: + * Start the station re-association procedure. + * + * Return Value: + * None. + * +-*/ + +VOID +vMgrReAssocBeginSta( + IN HANDLE hDeviceContext, + IN PSMgmtObject pMgmt, + OUT PCMD_STATUS pStatus + ) +{ + PSDevice pDevice = (PSDevice)hDeviceContext; + PSTxMgmtPacket pTxPacket; + + + + pMgmt->wCurrCapInfo = 0; + pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_ESS(1); + if (pDevice->bEncryptionEnable) { + pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_PRIVACY(1); + } + + //if (pDevice->byPreambleType == 1) { + // pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SHORTPREAMBLE(1); + //} + pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SHORTPREAMBLE(1); + + if (pMgmt->wListenInterval == 0) + pMgmt->wListenInterval = 1; // at least one. + + + // ERP Phy (802.11g) should support short preamble. + if (pMgmt->eCurrentPHYMode == PHY_TYPE_11G) { + pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SHORTPREAMBLE(1); + if (CARDbIsShorSlotTime(pMgmt->pAdapter) == TRUE) { + pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SHORTSLOTTIME(1); + } + } else if (pMgmt->eCurrentPHYMode == PHY_TYPE_11B) { + if (CARDbIsShortPreamble(pMgmt->pAdapter) == TRUE) { + pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SHORTPREAMBLE(1); + } + } + if (pMgmt->b11hEnable == TRUE) + pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SPECTRUMMNG(1); + + + pTxPacket = s_MgrMakeReAssocRequest + ( + pDevice, + pMgmt, + pMgmt->abyCurrBSSID, + pMgmt->wCurrCapInfo, + pMgmt->wListenInterval, + (PWLAN_IE_SSID)pMgmt->abyCurrSSID, + (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates, + (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates + ); + + if (pTxPacket != NULL ){ + /* send the frame */ + *pStatus = csMgmt_xmit(pDevice, pTxPacket); + if (*pStatus != CMD_STATUS_PENDING) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Mgt:Reassociation tx failed.\n"); + } + else { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Mgt:Reassociation tx sending.\n"); + } + } + + + return ; +} + +/*+ + * + * Routine Description: + * Send an dis-association request frame to the AP. + * + * Return Value: + * None. + * +-*/ + +VOID +vMgrDisassocBeginSta( + IN HANDLE hDeviceContext, + IN PSMgmtObject pMgmt, + IN PBYTE abyDestAddress, + IN WORD wReason, + OUT PCMD_STATUS pStatus + ) +{ + PSDevice pDevice = (PSDevice)hDeviceContext; + PSTxMgmtPacket pTxPacket = NULL; + WLAN_FR_DISASSOC sFrame; + + pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool; + memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_DISASSOC_FR_MAXLEN); + pTxPacket->p80211Header = (PUWLAN_80211HDR)((PBYTE)pTxPacket + sizeof(STxMgmtPacket)); + + // Setup the sFrame structure + sFrame.pBuf = (PBYTE)pTxPacket->p80211Header; + sFrame.len = WLAN_DISASSOC_FR_MAXLEN; + + // format fixed field frame structure + vMgrEncodeDisassociation(&sFrame); + + // Setup the header + sFrame.pHdr->sA3.wFrameCtl = cpu_to_le16( + ( + WLAN_SET_FC_FTYPE(WLAN_TYPE_MGR) | + WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_DISASSOC) + )); + + memcpy( sFrame.pHdr->sA3.abyAddr1, abyDestAddress, WLAN_ADDR_LEN); + memcpy( sFrame.pHdr->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN); + memcpy( sFrame.pHdr->sA3.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN); + + // Set reason code + *(sFrame.pwReason) = cpu_to_le16(wReason); + pTxPacket->cbMPDULen = sFrame.len; + pTxPacket->cbPayloadLen = sFrame.len - WLAN_HDR_ADDR3_LEN; + + // send the frame + *pStatus = csMgmt_xmit(pDevice, pTxPacket); + if (*pStatus == CMD_STATUS_PENDING) { + pMgmt->eCurrState = WMAC_STATE_IDLE; + *pStatus = CMD_STATUS_SUCCESS; + }; + + return; +} + + + +/*+ + * + * Routine Description:(AP function) + * Handle incoming station association request frames. + * + * Return Value: + * None. + * +-*/ + +static +VOID +s_vMgrRxAssocRequest( + IN PSDevice pDevice, + IN PSMgmtObject pMgmt, + IN PSRxMgmtPacket pRxPacket, + IN UINT uNodeIndex + ) +{ + WLAN_FR_ASSOCREQ sFrame; + CMD_STATUS Status; + PSTxMgmtPacket pTxPacket; + WORD wAssocStatus = 0; + WORD wAssocAID = 0; + UINT uRateLen = WLAN_RATES_MAXLEN; + BYTE abyCurrSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1]; + BYTE abyCurrExtSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1]; + + + if (pMgmt->eCurrMode != WMAC_MODE_ESS_AP) + return; + // node index not found + if (!uNodeIndex) + return; + + //check if node is authenticated + //decode the frame + memset(&sFrame, 0, sizeof(WLAN_FR_ASSOCREQ)); + memset(abyCurrSuppRates, 0, WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1); + memset(abyCurrExtSuppRates, 0, WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1); + sFrame.len = pRxPacket->cbMPDULen; + sFrame.pBuf = (PBYTE)pRxPacket->p80211Header; + + vMgrDecodeAssocRequest(&sFrame); + + if (pMgmt->sNodeDBTable[uNodeIndex].eNodeState >= NODE_AUTH) { + pMgmt->sNodeDBTable[uNodeIndex].eNodeState = NODE_ASSOC; + pMgmt->sNodeDBTable[uNodeIndex].wCapInfo = cpu_to_le16(*sFrame.pwCapInfo); + pMgmt->sNodeDBTable[uNodeIndex].wListenInterval = cpu_to_le16(*sFrame.pwListenInterval); + pMgmt->sNodeDBTable[uNodeIndex].bPSEnable = + WLAN_GET_FC_PWRMGT(sFrame.pHdr->sA3.wFrameCtl) ? TRUE : FALSE; + // Todo: check sta basic rate, if ap can't support, set status code + if (pDevice->eCurrentPHYType == PHY_TYPE_11B) { + uRateLen = WLAN_RATES_MAXLEN_11B; + } + abyCurrSuppRates[0] = WLAN_EID_SUPP_RATES; + abyCurrSuppRates[1] = RATEuSetIE((PWLAN_IE_SUPP_RATES)sFrame.pSuppRates, + (PWLAN_IE_SUPP_RATES)abyCurrSuppRates, + uRateLen); + abyCurrExtSuppRates[0] = WLAN_EID_EXTSUPP_RATES; + if (pDevice->eCurrentPHYType == PHY_TYPE_11G) { + abyCurrExtSuppRates[1] = RATEuSetIE((PWLAN_IE_SUPP_RATES)sFrame.pExtSuppRates, + (PWLAN_IE_SUPP_RATES)abyCurrExtSuppRates, + uRateLen); + } else { + abyCurrExtSuppRates[1] = 0; + } + + + RATEvParseMaxRate((PVOID)pDevice, + (PWLAN_IE_SUPP_RATES)abyCurrSuppRates, + (PWLAN_IE_SUPP_RATES)abyCurrExtSuppRates, + FALSE, // do not change our basic rate + &(pMgmt->sNodeDBTable[uNodeIndex].wMaxBasicRate), + &(pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate), + &(pMgmt->sNodeDBTable[uNodeIndex].wSuppRate), + &(pMgmt->sNodeDBTable[uNodeIndex].byTopCCKBasicRate), + &(pMgmt->sNodeDBTable[uNodeIndex].byTopOFDMBasicRate) + ); + + // set max tx rate + pMgmt->sNodeDBTable[uNodeIndex].wTxDataRate = + pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate; +#ifdef PLICE_DEBUG + printk("RxAssocRequest:wTxDataRate is %d\n",pMgmt->sNodeDBTable[uNodeIndex].wTxDataRate); +#endif + // Todo: check sta preamble, if ap can't support, set status code + pMgmt->sNodeDBTable[uNodeIndex].bShortPreamble = + WLAN_GET_CAP_INFO_SHORTPREAMBLE(*sFrame.pwCapInfo); + pMgmt->sNodeDBTable[uNodeIndex].bShortSlotTime = + WLAN_GET_CAP_INFO_SHORTSLOTTIME(*sFrame.pwCapInfo); + pMgmt->sNodeDBTable[uNodeIndex].wAID = (WORD)uNodeIndex; + wAssocStatus = WLAN_MGMT_STATUS_SUCCESS; + wAssocAID = (WORD)uNodeIndex; + // check if ERP support + if(pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate > RATE_11M) + pMgmt->sNodeDBTable[uNodeIndex].bERPExist = TRUE; + + if (pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate <= RATE_11M) { + // B only STA join + pDevice->bProtectMode = TRUE; + pDevice->bNonERPPresent = TRUE; + } + if (pMgmt->sNodeDBTable[uNodeIndex].bShortPreamble == FALSE) { + pDevice->bBarkerPreambleMd = TRUE; + } + + DEVICE_PRT(MSG_LEVEL_INFO, KERN_INFO "Associate AID= %d \n", wAssocAID); + DEVICE_PRT(MSG_LEVEL_INFO, KERN_INFO "MAC=%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X \n", + sFrame.pHdr->sA3.abyAddr2[0], + sFrame.pHdr->sA3.abyAddr2[1], + sFrame.pHdr->sA3.abyAddr2[2], + sFrame.pHdr->sA3.abyAddr2[3], + sFrame.pHdr->sA3.abyAddr2[4], + sFrame.pHdr->sA3.abyAddr2[5] + ) ; + DEVICE_PRT(MSG_LEVEL_INFO, KERN_INFO "Max Support rate = %d \n", + pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate); + }//else { TODO: received STA under state1 handle } + else { + return; + } + + + // assoc response reply.. + pTxPacket = s_MgrMakeAssocResponse + ( + pDevice, + pMgmt, + pMgmt->wCurrCapInfo, + wAssocStatus, + wAssocAID, + sFrame.pHdr->sA3.abyAddr2, + (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates, + (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates + ); + if (pTxPacket != NULL ){ + + if (pDevice->bEnableHostapd) { + return; + } + /* send the frame */ + Status = csMgmt_xmit(pDevice, pTxPacket); + if (Status != CMD_STATUS_PENDING) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Mgt:Assoc response tx failed\n"); + } + else { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Mgt:Assoc response tx sending..\n"); + } + + } + + return; +} + + +/*+ + * + * Description:(AP function) + * Handle incoming station re-association request frames. + * + * Parameters: + * In: + * pMgmt - Management Object structure + * pRxPacket - Received Packet + * Out: + * none + * + * Return Value: None. + * +-*/ + +static +VOID +s_vMgrRxReAssocRequest( + IN PSDevice pDevice, + IN PSMgmtObject pMgmt, + IN PSRxMgmtPacket pRxPacket, + IN UINT uNodeIndex + ) +{ + WLAN_FR_REASSOCREQ sFrame; + CMD_STATUS Status; + PSTxMgmtPacket pTxPacket; + WORD wAssocStatus = 0; + WORD wAssocAID = 0; + UINT uRateLen = WLAN_RATES_MAXLEN; + BYTE abyCurrSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1]; + BYTE abyCurrExtSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1]; + + if (pMgmt->eCurrMode != WMAC_MODE_ESS_AP) + return; + // node index not found + if (!uNodeIndex) + return; + //check if node is authenticated + //decode the frame + memset(&sFrame, 0, sizeof(WLAN_FR_REASSOCREQ)); + sFrame.len = pRxPacket->cbMPDULen; + sFrame.pBuf = (PBYTE)pRxPacket->p80211Header; + vMgrDecodeReassocRequest(&sFrame); + + if (pMgmt->sNodeDBTable[uNodeIndex].eNodeState >= NODE_AUTH) { + pMgmt->sNodeDBTable[uNodeIndex].eNodeState = NODE_ASSOC; + pMgmt->sNodeDBTable[uNodeIndex].wCapInfo = cpu_to_le16(*sFrame.pwCapInfo); + pMgmt->sNodeDBTable[uNodeIndex].wListenInterval = cpu_to_le16(*sFrame.pwListenInterval); + pMgmt->sNodeDBTable[uNodeIndex].bPSEnable = + WLAN_GET_FC_PWRMGT(sFrame.pHdr->sA3.wFrameCtl) ? TRUE : FALSE; + // Todo: check sta basic rate, if ap can't support, set status code + + if (pDevice->eCurrentPHYType == PHY_TYPE_11B) { + uRateLen = WLAN_RATES_MAXLEN_11B; + } + + abyCurrSuppRates[0] = WLAN_EID_SUPP_RATES; + abyCurrSuppRates[1] = RATEuSetIE((PWLAN_IE_SUPP_RATES)sFrame.pSuppRates, + (PWLAN_IE_SUPP_RATES)abyCurrSuppRates, + uRateLen); + abyCurrExtSuppRates[0] = WLAN_EID_EXTSUPP_RATES; + if (pDevice->eCurrentPHYType == PHY_TYPE_11G) { + abyCurrExtSuppRates[1] = RATEuSetIE((PWLAN_IE_SUPP_RATES)sFrame.pExtSuppRates, + (PWLAN_IE_SUPP_RATES)abyCurrExtSuppRates, + uRateLen); + } else { + abyCurrExtSuppRates[1] = 0; + } + + + RATEvParseMaxRate((PVOID)pDevice, + (PWLAN_IE_SUPP_RATES)abyCurrSuppRates, + (PWLAN_IE_SUPP_RATES)abyCurrExtSuppRates, + FALSE, // do not change our basic rate + &(pMgmt->sNodeDBTable[uNodeIndex].wMaxBasicRate), + &(pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate), + &(pMgmt->sNodeDBTable[uNodeIndex].wSuppRate), + &(pMgmt->sNodeDBTable[uNodeIndex].byTopCCKBasicRate), + &(pMgmt->sNodeDBTable[uNodeIndex].byTopOFDMBasicRate) + ); + + // set max tx rate + pMgmt->sNodeDBTable[uNodeIndex].wTxDataRate = + pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate; +#ifdef PLICE_DEBUG + printk("RxReAssocRequest:TxDataRate is %d\n",pMgmt->sNodeDBTable[uNodeIndex].wTxDataRate); +#endif + // Todo: check sta preamble, if ap can't support, set status code + pMgmt->sNodeDBTable[uNodeIndex].bShortPreamble = + WLAN_GET_CAP_INFO_SHORTPREAMBLE(*sFrame.pwCapInfo); + pMgmt->sNodeDBTable[uNodeIndex].bShortSlotTime = + WLAN_GET_CAP_INFO_SHORTSLOTTIME(*sFrame.pwCapInfo); + pMgmt->sNodeDBTable[uNodeIndex].wAID = (WORD)uNodeIndex; + wAssocStatus = WLAN_MGMT_STATUS_SUCCESS; + wAssocAID = (WORD)uNodeIndex; + + // if suppurt ERP + if(pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate > RATE_11M) + pMgmt->sNodeDBTable[uNodeIndex].bERPExist = TRUE; + + if (pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate <= RATE_11M) { + // B only STA join + pDevice->bProtectMode = TRUE; + pDevice->bNonERPPresent = TRUE; + } + if (pMgmt->sNodeDBTable[uNodeIndex].bShortPreamble == FALSE) { + pDevice->bBarkerPreambleMd = TRUE; + } + + DEVICE_PRT(MSG_LEVEL_INFO, KERN_INFO "Rx ReAssociate AID= %d \n", wAssocAID); + DEVICE_PRT(MSG_LEVEL_INFO, KERN_INFO "MAC=%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X \n", + sFrame.pHdr->sA3.abyAddr2[0], + sFrame.pHdr->sA3.abyAddr2[1], + sFrame.pHdr->sA3.abyAddr2[2], + sFrame.pHdr->sA3.abyAddr2[3], + sFrame.pHdr->sA3.abyAddr2[4], + sFrame.pHdr->sA3.abyAddr2[5] + ) ; + DEVICE_PRT(MSG_LEVEL_INFO, KERN_INFO "Max Support rate = %d \n", + pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate); + + } + + + // assoc response reply.. + pTxPacket = s_MgrMakeReAssocResponse + ( + pDevice, + pMgmt, + pMgmt->wCurrCapInfo, + wAssocStatus, + wAssocAID, + sFrame.pHdr->sA3.abyAddr2, + (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates, + (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates + ); + + if (pTxPacket != NULL ){ + /* send the frame */ + if (pDevice->bEnableHostapd) { + return; + } + Status = csMgmt_xmit(pDevice, pTxPacket); + if (Status != CMD_STATUS_PENDING) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Mgt:ReAssoc response tx failed\n"); + } + else { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Mgt:ReAssoc response tx sending..\n"); + } + } + return; +} + + +/*+ + * + * Routine Description: + * Handle incoming association response frames. + * + * Return Value: + * None. + * +-*/ + +static +VOID +s_vMgrRxAssocResponse( + IN PSDevice pDevice, + IN PSMgmtObject pMgmt, + IN PSRxMgmtPacket pRxPacket, + IN BOOL bReAssocType + ) +{ + WLAN_FR_ASSOCRESP sFrame; + PWLAN_IE_SSID pItemSSID; + PBYTE pbyIEs; + viawget_wpa_header *wpahdr; + + + + if (pMgmt->eCurrState == WMAC_STATE_ASSOCPENDING || + pMgmt->eCurrState == WMAC_STATE_ASSOC) { + + sFrame.len = pRxPacket->cbMPDULen; + sFrame.pBuf = (PBYTE)pRxPacket->p80211Header; + // decode the frame + vMgrDecodeAssocResponse(&sFrame); + if ((sFrame.pwCapInfo == 0) || + (sFrame.pwStatus == 0) || + (sFrame.pwAid == 0) || + (sFrame.pSuppRates == 0)){ + DBG_PORT80(0xCC); + return; + }; + + pMgmt->sAssocInfo.AssocInfo.ResponseFixedIEs.Capabilities = *(sFrame.pwCapInfo); + pMgmt->sAssocInfo.AssocInfo.ResponseFixedIEs.StatusCode = *(sFrame.pwStatus); + pMgmt->sAssocInfo.AssocInfo.ResponseFixedIEs.AssociationId = *(sFrame.pwAid); + pMgmt->sAssocInfo.AssocInfo.AvailableResponseFixedIEs |= 0x07; + + pMgmt->sAssocInfo.AssocInfo.ResponseIELength = sFrame.len - 24 - 6; + pMgmt->sAssocInfo.AssocInfo.OffsetResponseIEs = pMgmt->sAssocInfo.AssocInfo.OffsetRequestIEs + pMgmt->sAssocInfo.AssocInfo.RequestIELength; + pbyIEs = pMgmt->sAssocInfo.abyIEs; + pbyIEs += pMgmt->sAssocInfo.AssocInfo.RequestIELength; + memcpy(pbyIEs, (sFrame.pBuf + 24 +6), pMgmt->sAssocInfo.AssocInfo.ResponseIELength); + + // save values and set current BSS state + if (cpu_to_le16((*(sFrame.pwStatus))) == WLAN_MGMT_STATUS_SUCCESS ){ + // set AID + pMgmt->wCurrAID = cpu_to_le16((*(sFrame.pwAid))); + if ( (pMgmt->wCurrAID >> 14) != (BIT0 | BIT1) ) + { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "AID from AP, has two msb clear.\n"); + }; + DEVICE_PRT(MSG_LEVEL_INFO, KERN_INFO "Association Successful, AID=%d.\n", pMgmt->wCurrAID & ~(BIT14|BIT15)); + pMgmt->eCurrState = WMAC_STATE_ASSOC; + BSSvUpdateAPNode((HANDLE)pDevice, sFrame.pwCapInfo, sFrame.pSuppRates, sFrame.pExtSuppRates); + pItemSSID = (PWLAN_IE_SSID)pMgmt->abyCurrSSID; + DEVICE_PRT(MSG_LEVEL_INFO, KERN_INFO "Link with AP(SSID): %s\n", pItemSSID->abySSID); + pDevice->bLinkPass = TRUE; + pDevice->uBBVGADiffCount = 0; + if ((pDevice->bWPADEVUp) && (pDevice->skb != NULL)) { + if(skb_tailroom(pDevice->skb) <(sizeof(viawget_wpa_header)+pMgmt->sAssocInfo.AssocInfo.ResponseIELength+ + pMgmt->sAssocInfo.AssocInfo.RequestIELength)) { //data room not enough + dev_kfree_skb(pDevice->skb); + pDevice->skb = dev_alloc_skb((int)pDevice->rx_buf_sz); + } + wpahdr = (viawget_wpa_header *)pDevice->skb->data; + wpahdr->type = VIAWGET_ASSOC_MSG; + wpahdr->resp_ie_len = pMgmt->sAssocInfo.AssocInfo.ResponseIELength; + wpahdr->req_ie_len = pMgmt->sAssocInfo.AssocInfo.RequestIELength; + memcpy(pDevice->skb->data + sizeof(viawget_wpa_header), pMgmt->sAssocInfo.abyIEs, wpahdr->req_ie_len); + memcpy(pDevice->skb->data + sizeof(viawget_wpa_header) + wpahdr->req_ie_len, + pbyIEs, + wpahdr->resp_ie_len + ); + skb_put(pDevice->skb, sizeof(viawget_wpa_header) + wpahdr->resp_ie_len + wpahdr->req_ie_len); + pDevice->skb->dev = pDevice->wpadev; + pDevice->skb->mac_header = pDevice->skb->data; + pDevice->skb->pkt_type = PACKET_HOST; + pDevice->skb->protocol = htons(ETH_P_802_2); + memset(pDevice->skb->cb, 0, sizeof(pDevice->skb->cb)); + netif_rx(pDevice->skb); + pDevice->skb = dev_alloc_skb((int)pDevice->rx_buf_sz); + } + +//2008-0409-07, by Einsn Liu +#ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT + //if(pDevice->bWPADevEnable == TRUE) + { + BYTE buf[512]; + size_t len; + union iwreq_data wrqu; + int we_event; + + memset(buf, 0, 512); + + len = pMgmt->sAssocInfo.AssocInfo.RequestIELength; + if(len) { + memcpy(buf, pMgmt->sAssocInfo.abyIEs, len); + memset(&wrqu, 0, sizeof (wrqu)); + wrqu.data.length = len; + we_event = IWEVASSOCREQIE; + wireless_send_event(pDevice->dev, we_event, &wrqu, buf); + } + + memset(buf, 0, 512); + len = pMgmt->sAssocInfo.AssocInfo.ResponseIELength; + + if(len) { + memcpy(buf, pbyIEs, len); + memset(&wrqu, 0, sizeof (wrqu)); + wrqu.data.length = len; + we_event = IWEVASSOCRESPIE; + wireless_send_event(pDevice->dev, we_event, &wrqu, buf); + } + + + memset(&wrqu, 0, sizeof (wrqu)); + memcpy(wrqu.ap_addr.sa_data, &pMgmt->abyCurrBSSID[0], ETH_ALEN); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + wireless_send_event(pDevice->dev, SIOCGIWAP, &wrqu, NULL); + } +#endif //#ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT +//End Add -- //2008-0409-07, by Einsn Liu + } + else { + if (bReAssocType) { + pMgmt->eCurrState = WMAC_STATE_IDLE; + } + else { + // jump back to the auth state and indicate the error + pMgmt->eCurrState = WMAC_STATE_AUTH; + } + s_vMgrLogStatus(pMgmt,cpu_to_le16((*(sFrame.pwStatus)))); + } + + } + +#ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT +//need clear flags related to Networkmanager + + pDevice->bwextcount = 0; + pDevice->bWPASuppWextEnabled = FALSE; +#endif + + +if(pMgmt->eCurrState == WMAC_STATE_ASSOC) + timer_expire(pDevice->sTimerCommand, 0); + return; +} + + + +/*+ + * + * Routine Description: + * Start the station authentication procedure. Namely, send an + * authentication frame to the AP. + * + * Return Value: + * None. + * +-*/ + +VOID +vMgrAuthenBeginSta( + IN HANDLE hDeviceContext, + IN PSMgmtObject pMgmt, + OUT PCMD_STATUS pStatus + ) +{ + PSDevice pDevice = (PSDevice)hDeviceContext; + WLAN_FR_AUTHEN sFrame; + PSTxMgmtPacket pTxPacket = NULL; + + pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool; + memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_AUTHEN_FR_MAXLEN); + pTxPacket->p80211Header = (PUWLAN_80211HDR)((PBYTE)pTxPacket + sizeof(STxMgmtPacket)); + sFrame.pBuf = (PBYTE)pTxPacket->p80211Header; + sFrame.len = WLAN_AUTHEN_FR_MAXLEN; + vMgrEncodeAuthen(&sFrame); + /* insert values */ + sFrame.pHdr->sA3.wFrameCtl = cpu_to_le16( + ( + WLAN_SET_FC_FTYPE(WLAN_TYPE_MGR) | + WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_AUTHEN) + )); + memcpy( sFrame.pHdr->sA3.abyAddr1, pMgmt->abyCurrBSSID, WLAN_ADDR_LEN); + memcpy( sFrame.pHdr->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN); + memcpy( sFrame.pHdr->sA3.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN); + if (pMgmt->bShareKeyAlgorithm) + *(sFrame.pwAuthAlgorithm) = cpu_to_le16(WLAN_AUTH_ALG_SHAREDKEY); + else + *(sFrame.pwAuthAlgorithm) = cpu_to_le16(WLAN_AUTH_ALG_OPENSYSTEM); + + *(sFrame.pwAuthSequence) = cpu_to_le16(1); + /* Adjust the length fields */ + pTxPacket->cbMPDULen = sFrame.len; + pTxPacket->cbPayloadLen = sFrame.len - WLAN_HDR_ADDR3_LEN; + + *pStatus = csMgmt_xmit(pDevice, pTxPacket); + if (*pStatus == CMD_STATUS_PENDING){ + pMgmt->eCurrState = WMAC_STATE_AUTHPENDING; + *pStatus = CMD_STATUS_SUCCESS; + } + + return ; +} + + + +/*+ + * + * Routine Description: + * Start the station(AP) deauthentication procedure. Namely, send an + * deauthentication frame to the AP or Sta. + * + * Return Value: + * None. + * +-*/ + +VOID +vMgrDeAuthenBeginSta( + IN HANDLE hDeviceContext, + IN PSMgmtObject pMgmt, + IN PBYTE abyDestAddress, + IN WORD wReason, + OUT PCMD_STATUS pStatus + ) +{ + PSDevice pDevice = (PSDevice)hDeviceContext; + WLAN_FR_DEAUTHEN sFrame; + PSTxMgmtPacket pTxPacket = NULL; + + + pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool; + memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_DEAUTHEN_FR_MAXLEN); + pTxPacket->p80211Header = (PUWLAN_80211HDR)((PBYTE)pTxPacket + sizeof(STxMgmtPacket)); + sFrame.pBuf = (PBYTE)pTxPacket->p80211Header; + sFrame.len = WLAN_DEAUTHEN_FR_MAXLEN; + vMgrEncodeDeauthen(&sFrame); + /* insert values */ + sFrame.pHdr->sA3.wFrameCtl = cpu_to_le16( + ( + WLAN_SET_FC_FTYPE(WLAN_TYPE_MGR) | + WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_DEAUTHEN) + )); + + memcpy( sFrame.pHdr->sA3.abyAddr1, abyDestAddress, WLAN_ADDR_LEN); + memcpy( sFrame.pHdr->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN); + memcpy( sFrame.pHdr->sA3.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN); + + *(sFrame.pwReason) = cpu_to_le16(wReason); // deauthen. bcs left BSS + /* Adjust the length fields */ + pTxPacket->cbMPDULen = sFrame.len; + pTxPacket->cbPayloadLen = sFrame.len - WLAN_HDR_ADDR3_LEN; + + *pStatus = csMgmt_xmit(pDevice, pTxPacket); + if (*pStatus == CMD_STATUS_PENDING){ + *pStatus = CMD_STATUS_SUCCESS; + } + + + return ; +} + + +/*+ + * + * Routine Description: + * Handle incoming authentication frames. + * + * Return Value: + * None. + * +-*/ + +static +VOID +s_vMgrRxAuthentication( + IN PSDevice pDevice, + IN PSMgmtObject pMgmt, + IN PSRxMgmtPacket pRxPacket + ) +{ + WLAN_FR_AUTHEN sFrame; + + // we better be an AP or a STA in AUTHPENDING otherwise ignore + if (!(pMgmt->eCurrMode == WMAC_MODE_ESS_AP || + pMgmt->eCurrState == WMAC_STATE_AUTHPENDING)) { + return; + } + + // decode the frame + sFrame.len = pRxPacket->cbMPDULen; + sFrame.pBuf = (PBYTE)pRxPacket->p80211Header; + vMgrDecodeAuthen(&sFrame); + switch (cpu_to_le16((*(sFrame.pwAuthSequence )))){ + case 1: + //AP funciton + s_vMgrRxAuthenSequence_1(pDevice,pMgmt, &sFrame); + break; + case 2: + s_vMgrRxAuthenSequence_2(pDevice, pMgmt, &sFrame); + break; + case 3: + //AP funciton + s_vMgrRxAuthenSequence_3(pDevice, pMgmt, &sFrame); + break; + case 4: + s_vMgrRxAuthenSequence_4(pDevice, pMgmt, &sFrame); + break; + default: + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Auth Sequence error, seq = %d\n", + cpu_to_le16((*(sFrame.pwAuthSequence)))); + break; + } + return; +} + + + +/*+ + * + * Routine Description: + * Handles incoming authen frames with sequence 1. Currently + * assumes we're an AP. So far, no one appears to use authentication + * in Ad-Hoc mode. + * + * Return Value: + * None. + * +-*/ + + +static +VOID +s_vMgrRxAuthenSequence_1( + IN PSDevice pDevice, + IN PSMgmtObject pMgmt, + IN PWLAN_FR_AUTHEN pFrame + ) +{ + PSTxMgmtPacket pTxPacket = NULL; + UINT uNodeIndex; + WLAN_FR_AUTHEN sFrame; + PSKeyItem pTransmitKey; + + // Insert a Node entry + if (!BSSDBbIsSTAInNodeDB(pMgmt, pFrame->pHdr->sA3.abyAddr2, &uNodeIndex)) { + BSSvCreateOneNode((PSDevice)pDevice, &uNodeIndex); + memcpy(pMgmt->sNodeDBTable[uNodeIndex].abyMACAddr, pFrame->pHdr->sA3.abyAddr2, + WLAN_ADDR_LEN); + } + + if (pMgmt->bShareKeyAlgorithm) { + pMgmt->sNodeDBTable[uNodeIndex].eNodeState = NODE_KNOWN; + pMgmt->sNodeDBTable[uNodeIndex].byAuthSequence = 1; + } + else { + pMgmt->sNodeDBTable[uNodeIndex].eNodeState = NODE_AUTH; + } + + // send auth reply + pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool; + memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_AUTHEN_FR_MAXLEN); + pTxPacket->p80211Header = (PUWLAN_80211HDR)((PBYTE)pTxPacket + sizeof(STxMgmtPacket)); + sFrame.pBuf = (PBYTE)pTxPacket->p80211Header; + sFrame.len = WLAN_AUTHEN_FR_MAXLEN; + // format buffer structure + vMgrEncodeAuthen(&sFrame); + // insert values + sFrame.pHdr->sA3.wFrameCtl = cpu_to_le16( + ( + WLAN_SET_FC_FTYPE(WLAN_TYPE_MGR) | + WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_AUTHEN)| + WLAN_SET_FC_ISWEP(0) + )); + memcpy( sFrame.pHdr->sA3.abyAddr1, pFrame->pHdr->sA3.abyAddr2, WLAN_ADDR_LEN); + memcpy( sFrame.pHdr->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN); + memcpy( sFrame.pHdr->sA3.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN); + *(sFrame.pwAuthAlgorithm) = *(pFrame->pwAuthAlgorithm); + *(sFrame.pwAuthSequence) = cpu_to_le16(2); + + if (cpu_to_le16(*(pFrame->pwAuthAlgorithm)) == WLAN_AUTH_ALG_SHAREDKEY) { + if (pMgmt->bShareKeyAlgorithm) + *(sFrame.pwStatus) = cpu_to_le16(WLAN_MGMT_STATUS_SUCCESS); + else + *(sFrame.pwStatus) = cpu_to_le16(WLAN_MGMT_STATUS_UNSUPPORTED_AUTHALG); + } + else { + if (pMgmt->bShareKeyAlgorithm) + *(sFrame.pwStatus) = cpu_to_le16(WLAN_MGMT_STATUS_UNSUPPORTED_AUTHALG); + else + *(sFrame.pwStatus) = cpu_to_le16(WLAN_MGMT_STATUS_SUCCESS); + } + + if (pMgmt->bShareKeyAlgorithm && + (cpu_to_le16(*(sFrame.pwStatus)) == WLAN_MGMT_STATUS_SUCCESS)) { + + sFrame.pChallenge = (PWLAN_IE_CHALLENGE)(sFrame.pBuf + sFrame.len); + sFrame.len += WLAN_CHALLENGE_IE_LEN; + sFrame.pChallenge->byElementID = WLAN_EID_CHALLENGE; + sFrame.pChallenge->len = WLAN_CHALLENGE_LEN; + memset(pMgmt->abyChallenge, 0, WLAN_CHALLENGE_LEN); + // get group key + if(KeybGetTransmitKey(&(pDevice->sKey), pDevice->abyBroadcastAddr, GROUP_KEY, &pTransmitKey) == TRUE) { + rc4_init(&pDevice->SBox, pDevice->abyPRNG, pTransmitKey->uKeyLength+3); + rc4_encrypt(&pDevice->SBox, pMgmt->abyChallenge, pMgmt->abyChallenge, WLAN_CHALLENGE_LEN); + } + memcpy(sFrame.pChallenge->abyChallenge, pMgmt->abyChallenge , WLAN_CHALLENGE_LEN); + } + + /* Adjust the length fields */ + pTxPacket->cbMPDULen = sFrame.len; + pTxPacket->cbPayloadLen = sFrame.len - WLAN_HDR_ADDR3_LEN; + // send the frame + if (pDevice->bEnableHostapd) { + return; + } + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Mgt:Authreq_reply sequence_1 tx.. \n"); + if (csMgmt_xmit(pDevice, pTxPacket) != CMD_STATUS_PENDING) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Mgt:Authreq_reply sequence_1 tx failed.\n"); + } + return; +} + + + +/*+ + * + * Routine Description: + * Handles incoming auth frames with sequence number 2. Currently + * assumes we're a station. + * + * + * Return Value: + * None. + * +-*/ + +static +VOID +s_vMgrRxAuthenSequence_2( + IN PSDevice pDevice, + IN PSMgmtObject pMgmt, + IN PWLAN_FR_AUTHEN pFrame + ) +{ + WLAN_FR_AUTHEN sFrame; + PSTxMgmtPacket pTxPacket = NULL; + + + switch (cpu_to_le16((*(pFrame->pwAuthAlgorithm)))) + { + case WLAN_AUTH_ALG_OPENSYSTEM: + if ( cpu_to_le16((*(pFrame->pwStatus))) == WLAN_MGMT_STATUS_SUCCESS ){ + DEVICE_PRT(MSG_LEVEL_INFO, KERN_INFO "802.11 Authen (OPEN) Successful.\n"); + pMgmt->eCurrState = WMAC_STATE_AUTH; + timer_expire(pDevice->sTimerCommand, 0); + } + else { + DEVICE_PRT(MSG_LEVEL_INFO, KERN_INFO "802.11 Authen (OPEN) Failed.\n"); + s_vMgrLogStatus(pMgmt, cpu_to_le16((*(pFrame->pwStatus)))); + pMgmt->eCurrState = WMAC_STATE_IDLE; + } + if (pDevice->eCommandState == WLAN_AUTHENTICATE_WAIT ) { +// spin_unlock_irq(&pDevice->lock); +// vCommandTimerWait((HANDLE)pDevice, 0); +// spin_lock_irq(&pDevice->lock); + } + + break; + + case WLAN_AUTH_ALG_SHAREDKEY: + + if (cpu_to_le16((*(pFrame->pwStatus))) == WLAN_MGMT_STATUS_SUCCESS) { + pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool; + memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_AUTHEN_FR_MAXLEN); + pTxPacket->p80211Header = (PUWLAN_80211HDR)((PBYTE)pTxPacket + sizeof(STxMgmtPacket)); + sFrame.pBuf = (PBYTE)pTxPacket->p80211Header; + sFrame.len = WLAN_AUTHEN_FR_MAXLEN; + // format buffer structure + vMgrEncodeAuthen(&sFrame); + // insert values + sFrame.pHdr->sA3.wFrameCtl = cpu_to_le16( + ( + WLAN_SET_FC_FTYPE(WLAN_TYPE_MGR) | + WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_AUTHEN)| + WLAN_SET_FC_ISWEP(1) + )); + memcpy( sFrame.pHdr->sA3.abyAddr1, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN); + memcpy( sFrame.pHdr->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN); + memcpy( sFrame.pHdr->sA3.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN); + *(sFrame.pwAuthAlgorithm) = *(pFrame->pwAuthAlgorithm); + *(sFrame.pwAuthSequence) = cpu_to_le16(3); + *(sFrame.pwStatus) = cpu_to_le16(WLAN_MGMT_STATUS_SUCCESS); + sFrame.pChallenge = (PWLAN_IE_CHALLENGE)(sFrame.pBuf + sFrame.len); + sFrame.len += WLAN_CHALLENGE_IE_LEN; + sFrame.pChallenge->byElementID = WLAN_EID_CHALLENGE; + sFrame.pChallenge->len = WLAN_CHALLENGE_LEN; + memcpy( sFrame.pChallenge->abyChallenge, pFrame->pChallenge->abyChallenge, WLAN_CHALLENGE_LEN); + // Adjust the length fields + pTxPacket->cbMPDULen = sFrame.len; + pTxPacket->cbPayloadLen = sFrame.len - WLAN_HDR_ADDR3_LEN; + // send the frame + if (csMgmt_xmit(pDevice, pTxPacket) != CMD_STATUS_PENDING) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Mgt:Auth_reply sequence_2 tx failed.\n"); + } + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Mgt:Auth_reply sequence_2 tx ...\n"); + } + else { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Mgt:rx Auth_reply sequence_2 status error ...\n"); + if ( pDevice->eCommandState == WLAN_AUTHENTICATE_WAIT ) { +// spin_unlock_irq(&pDevice->lock); +// vCommandTimerWait((HANDLE)pDevice, 0); +// spin_lock_irq(&pDevice->lock); + } + s_vMgrLogStatus(pMgmt, cpu_to_le16((*(pFrame->pwStatus)))); + } + break; + default: + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Mgt: rx auth.seq = 2 unknown AuthAlgorithm=%d\n", cpu_to_le16((*(pFrame->pwAuthAlgorithm)))); + break; + } + return; +} + + + +/*+ + * + * Routine Description: + * Handles incoming authen frames with sequence 3. Currently + * assumes we're an AP. This function assumes the frame has + * already been successfully decrypted. + * + * + * Return Value: + * None. + * +-*/ + +static +VOID +s_vMgrRxAuthenSequence_3( + IN PSDevice pDevice, + IN PSMgmtObject pMgmt, + IN PWLAN_FR_AUTHEN pFrame + ) +{ + PSTxMgmtPacket pTxPacket = NULL; + UINT uStatusCode = 0 ; + UINT uNodeIndex = 0; + WLAN_FR_AUTHEN sFrame; + + if (!WLAN_GET_FC_ISWEP(pFrame->pHdr->sA3.wFrameCtl)) { + uStatusCode = WLAN_MGMT_STATUS_CHALLENGE_FAIL; + goto reply; + } + if (BSSDBbIsSTAInNodeDB(pMgmt, pFrame->pHdr->sA3.abyAddr2, &uNodeIndex)) { + if (pMgmt->sNodeDBTable[uNodeIndex].byAuthSequence != 1) { + uStatusCode = WLAN_MGMT_STATUS_RX_AUTH_NOSEQ; + goto reply; + } + if (memcmp(pMgmt->abyChallenge, pFrame->pChallenge->abyChallenge, WLAN_CHALLENGE_LEN) != 0) { + uStatusCode = WLAN_MGMT_STATUS_CHALLENGE_FAIL; + goto reply; + } + } + else { + uStatusCode = WLAN_MGMT_STATUS_UNSPEC_FAILURE; + goto reply; + } + + if (uNodeIndex) { + pMgmt->sNodeDBTable[uNodeIndex].eNodeState = NODE_AUTH; + pMgmt->sNodeDBTable[uNodeIndex].byAuthSequence = 0; + } + uStatusCode = WLAN_MGMT_STATUS_SUCCESS; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Challenge text check ok..\n"); + +reply: + // send auth reply + pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool; + memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_AUTHEN_FR_MAXLEN); + pTxPacket->p80211Header = (PUWLAN_80211HDR)((PBYTE)pTxPacket + sizeof(STxMgmtPacket)); + sFrame.pBuf = (PBYTE)pTxPacket->p80211Header; + sFrame.len = WLAN_AUTHEN_FR_MAXLEN; + // format buffer structure + vMgrEncodeAuthen(&sFrame); + /* insert values */ + sFrame.pHdr->sA3.wFrameCtl = cpu_to_le16( + ( + WLAN_SET_FC_FTYPE(WLAN_TYPE_MGR) | + WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_AUTHEN)| + WLAN_SET_FC_ISWEP(0) + )); + memcpy( sFrame.pHdr->sA3.abyAddr1, pFrame->pHdr->sA3.abyAddr2, WLAN_ADDR_LEN); + memcpy( sFrame.pHdr->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN); + memcpy( sFrame.pHdr->sA3.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN); + *(sFrame.pwAuthAlgorithm) = *(pFrame->pwAuthAlgorithm); + *(sFrame.pwAuthSequence) = cpu_to_le16(4); + *(sFrame.pwStatus) = cpu_to_le16(uStatusCode); + + /* Adjust the length fields */ + pTxPacket->cbMPDULen = sFrame.len; + pTxPacket->cbPayloadLen = sFrame.len - WLAN_HDR_ADDR3_LEN; + // send the frame + if (pDevice->bEnableHostapd) { + return; + } + if (csMgmt_xmit(pDevice, pTxPacket) != CMD_STATUS_PENDING) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Mgt:Authreq_reply sequence_4 tx failed.\n"); + } + return; + +} + + + +/*+ + * + * Routine Description: + * Handles incoming authen frames with sequence 4 + * + * + * Return Value: + * None. + * +-*/ +static +VOID +s_vMgrRxAuthenSequence_4( + IN PSDevice pDevice, + IN PSMgmtObject pMgmt, + IN PWLAN_FR_AUTHEN pFrame + ) +{ + + if ( cpu_to_le16((*(pFrame->pwStatus))) == WLAN_MGMT_STATUS_SUCCESS ){ + DEVICE_PRT(MSG_LEVEL_INFO, KERN_INFO "802.11 Authen (SHAREDKEY) Successful.\n"); + pMgmt->eCurrState = WMAC_STATE_AUTH; + timer_expire(pDevice->sTimerCommand, 0); + } + else{ + DEVICE_PRT(MSG_LEVEL_INFO, KERN_INFO "802.11 Authen (SHAREDKEY) Failed.\n"); + s_vMgrLogStatus(pMgmt, cpu_to_le16((*(pFrame->pwStatus))) ); + pMgmt->eCurrState = WMAC_STATE_IDLE; + } + + if ( pDevice->eCommandState == WLAN_AUTHENTICATE_WAIT ) { +// spin_unlock_irq(&pDevice->lock); +// vCommandTimerWait((HANDLE)pDevice, 0); +// spin_lock_irq(&pDevice->lock); + } + +} + +/*+ + * + * Routine Description: + * Handles incoming disassociation frames + * + * + * Return Value: + * None. + * +-*/ + +static +VOID +s_vMgrRxDisassociation( + IN PSDevice pDevice, + IN PSMgmtObject pMgmt, + IN PSRxMgmtPacket pRxPacket + ) +{ + WLAN_FR_DISASSOC sFrame; + UINT uNodeIndex = 0; +// CMD_STATUS CmdStatus; + viawget_wpa_header *wpahdr; + + if ( pMgmt->eCurrMode == WMAC_MODE_ESS_AP ){ + // if is acting an AP.. + // a STA is leaving this BSS.. + sFrame.len = pRxPacket->cbMPDULen; + sFrame.pBuf = (PBYTE)pRxPacket->p80211Header; + if (BSSDBbIsSTAInNodeDB(pMgmt, pRxPacket->p80211Header->sA3.abyAddr2, &uNodeIndex)) { + BSSvRemoveOneNode(pDevice, uNodeIndex); + } + else { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Rx disassoc, sta not found\n"); + } + } + else if (pMgmt->eCurrMode == WMAC_MODE_ESS_STA ){ + sFrame.len = pRxPacket->cbMPDULen; + sFrame.pBuf = (PBYTE)pRxPacket->p80211Header; + vMgrDecodeDisassociation(&sFrame); + DEVICE_PRT(MSG_LEVEL_NOTICE, KERN_INFO "AP disassociated me, reason=%d.\n", cpu_to_le16(*(sFrame.pwReason))); + //TODO: do something let upper layer know or + //try to send associate packet again because of inactivity timeout + // if (pMgmt->eCurrState == WMAC_STATE_ASSOC) { + // vMgrReAssocBeginSta((PSDevice)pDevice, pMgmt, &CmdStatus); + // }; + if ((pDevice->bWPADEVUp) && (pDevice->skb != NULL)) { + wpahdr = (viawget_wpa_header *)pDevice->skb->data; + wpahdr->type = VIAWGET_DISASSOC_MSG; + wpahdr->resp_ie_len = 0; + wpahdr->req_ie_len = 0; + skb_put(pDevice->skb, sizeof(viawget_wpa_header)); + pDevice->skb->dev = pDevice->wpadev; + pDevice->skb->mac_header = pDevice->skb->data; + + pDevice->skb->pkt_type = PACKET_HOST; + pDevice->skb->protocol = htons(ETH_P_802_2); + memset(pDevice->skb->cb, 0, sizeof(pDevice->skb->cb)); + netif_rx(pDevice->skb); + pDevice->skb = dev_alloc_skb((int)pDevice->rx_buf_sz); + }; + + #ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT + // if(pDevice->bWPASuppWextEnabled == TRUE) + { + union iwreq_data wrqu; + memset(&wrqu, 0, sizeof (wrqu)); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + printk("wireless_send_event--->SIOCGIWAP(disassociated)\n"); + wireless_send_event(pDevice->dev, SIOCGIWAP, &wrqu, NULL); + } + #endif + + } + /* else, ignore it */ + + return; +} + + +/*+ + * + * Routine Description: + * Handles incoming deauthentication frames + * + * + * Return Value: + * None. + * +-*/ + +static +VOID +s_vMgrRxDeauthentication( + IN PSDevice pDevice, + IN PSMgmtObject pMgmt, + IN PSRxMgmtPacket pRxPacket + ) +{ + WLAN_FR_DEAUTHEN sFrame; + UINT uNodeIndex = 0; + viawget_wpa_header *wpahdr; + + + if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP ){ + //Todo: + // if is acting an AP.. + // a STA is leaving this BSS.. + sFrame.len = pRxPacket->cbMPDULen; + sFrame.pBuf = (PBYTE)pRxPacket->p80211Header; + if (BSSDBbIsSTAInNodeDB(pMgmt, pRxPacket->p80211Header->sA3.abyAddr2, &uNodeIndex)) { + BSSvRemoveOneNode(pDevice, uNodeIndex); + } + else { + DEVICE_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Rx deauth, sta not found\n"); + } + } + else { + if (pMgmt->eCurrMode == WMAC_MODE_ESS_STA ) { + sFrame.len = pRxPacket->cbMPDULen; + sFrame.pBuf = (PBYTE)pRxPacket->p80211Header; + vMgrDecodeDeauthen(&sFrame); + DEVICE_PRT(MSG_LEVEL_NOTICE, KERN_INFO "AP deauthed me, reason=%d.\n", cpu_to_le16((*(sFrame.pwReason)))); + // TODO: update BSS list for specific BSSID if pre-authentication case + if (IS_ETH_ADDRESS_EQUAL(sFrame.pHdr->sA3.abyAddr3, pMgmt->abyCurrBSSID)) { + if (pMgmt->eCurrState >= WMAC_STATE_AUTHPENDING) { + pMgmt->sNodeDBTable[0].bActive = FALSE; + pMgmt->eCurrMode = WMAC_MODE_STANDBY; + pMgmt->eCurrState = WMAC_STATE_IDLE; + netif_stop_queue(pDevice->dev); + pDevice->bLinkPass = FALSE; + } + }; + + if ((pDevice->bWPADEVUp) && (pDevice->skb != NULL)) { + wpahdr = (viawget_wpa_header *)pDevice->skb->data; + wpahdr->type = VIAWGET_DISASSOC_MSG; + wpahdr->resp_ie_len = 0; + wpahdr->req_ie_len = 0; + skb_put(pDevice->skb, sizeof(viawget_wpa_header)); + pDevice->skb->dev = pDevice->wpadev; + pDevice->skb->mac_header = pDevice->skb->data; + pDevice->skb->pkt_type = PACKET_HOST; + pDevice->skb->protocol = htons(ETH_P_802_2); + memset(pDevice->skb->cb, 0, sizeof(pDevice->skb->cb)); + netif_rx(pDevice->skb); + pDevice->skb = dev_alloc_skb((int)pDevice->rx_buf_sz); + }; + + #ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT + // if(pDevice->bWPASuppWextEnabled == TRUE) + { + union iwreq_data wrqu; + memset(&wrqu, 0, sizeof (wrqu)); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + printk("wireless_send_event--->SIOCGIWAP(disauthen)\n"); + wireless_send_event(pDevice->dev, SIOCGIWAP, &wrqu, NULL); + } + #endif + + } + /* else, ignore it. TODO: IBSS authentication service + would be implemented here */ + }; + return; +} + + +//2008-8-4 by chester +/*+ + * + * Routine Description: + * check if current channel is match ZoneType. + *for USA:1~11; + * Japan:1~13; + * Europe:1~13 + * Return Value: + * True:exceed; + * False:normal case +-*/ +static BOOL +ChannelExceedZoneType( + IN PSDevice pDevice, + IN BYTE byCurrChannel + ) +{ + BOOL exceed=FALSE; + + switch(pDevice->byZoneType) { + case 0x00: //USA:1~11 + if((byCurrChannel<1) ||(byCurrChannel>11)) + exceed = TRUE; + break; + case 0x01: //Japan:1~13 + case 0x02: //Europe:1~13 + if((byCurrChannel<1) ||(byCurrChannel>13)) + exceed = TRUE; + break; + default: //reserve for other zonetype + break; + } + + return exceed; +} + + +/*+ + * + * Routine Description: + * Handles and analysis incoming beacon frames. + * + * + * Return Value: + * None. + * +-*/ + +static +VOID +s_vMgrRxBeacon( + IN PSDevice pDevice, + IN PSMgmtObject pMgmt, + IN PSRxMgmtPacket pRxPacket, + IN BOOL bInScan + ) +{ + + PKnownBSS pBSSList; + WLAN_FR_BEACON sFrame; + QWORD qwTSFOffset; + BOOL bIsBSSIDEqual = FALSE; + BOOL bIsSSIDEqual = FALSE; + BOOL bTSFLargeDiff = FALSE; + BOOL bTSFOffsetPostive = FALSE; + BOOL bUpdateTSF = FALSE; + BOOL bIsAPBeacon = FALSE; + BOOL bIsChannelEqual = FALSE; + UINT uLocateByteIndex; + BYTE byTIMBitOn = 0; + WORD wAIDNumber = 0; + UINT uNodeIndex; + QWORD qwTimestamp, qwLocalTSF; + QWORD qwCurrTSF; + WORD wStartIndex = 0; + WORD wAIDIndex = 0; + BYTE byCurrChannel = pRxPacket->byRxChannel; + ERPObject sERP; + UINT uRateLen = WLAN_RATES_MAXLEN; + BOOL bChannelHit = FALSE; + BOOL bUpdatePhyParameter = FALSE; + BYTE byIEChannel = 0; + + + memset(&sFrame, 0, sizeof(WLAN_FR_BEACON)); + sFrame.len = pRxPacket->cbMPDULen; + sFrame.pBuf = (PBYTE)pRxPacket->p80211Header; + + // decode the beacon frame + vMgrDecodeBeacon(&sFrame); + + if ((sFrame.pwBeaconInterval == 0) || + (sFrame.pwCapInfo == 0) || + (sFrame.pSSID == 0) || + (sFrame.pSuppRates == 0) ) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Rx beacon frame error\n"); + return; + }; + + + if (sFrame.pDSParms != NULL) { + if (byCurrChannel > CB_MAX_CHANNEL_24G) { + // channel remapping to + byIEChannel = CARDbyGetChannelMapping(pDevice, sFrame.pDSParms->byCurrChannel, PHY_TYPE_11A); + } else { + byIEChannel = sFrame.pDSParms->byCurrChannel; + } + if (byCurrChannel != byIEChannel) { + // adjust channel info. bcs we rcv adjcent channel pakckets + bChannelHit = FALSE; + byCurrChannel = byIEChannel; + } + } else { + // no DS channel info + bChannelHit = TRUE; + } +//2008-0730-01by MikeLiu +if(ChannelExceedZoneType(pDevice,byCurrChannel)==TRUE) + return; + + if (sFrame.pERP != NULL) { + sERP.byERP = sFrame.pERP->byContext; + sERP.bERPExist = TRUE; + + } else { + sERP.bERPExist = FALSE; + sERP.byERP = 0; + } + + pBSSList = BSSpAddrIsInBSSList((HANDLE)pDevice, sFrame.pHdr->sA3.abyAddr3, sFrame.pSSID); + if (pBSSList == NULL) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Beacon/insert: RxChannel = : %d\n", byCurrChannel); + BSSbInsertToBSSList((HANDLE)pDevice, + sFrame.pHdr->sA3.abyAddr3, + *sFrame.pqwTimestamp, + *sFrame.pwBeaconInterval, + *sFrame.pwCapInfo, + byCurrChannel, + sFrame.pSSID, + sFrame.pSuppRates, + sFrame.pExtSuppRates, + &sERP, + sFrame.pRSN, + sFrame.pRSNWPA, + sFrame.pIE_Country, + sFrame.pIE_Quiet, + sFrame.len - WLAN_HDR_ADDR3_LEN, + sFrame.pHdr->sA4.abyAddr4, // payload of beacon + (HANDLE)pRxPacket + ); + } + else { +// DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"update bcn: RxChannel = : %d\n", byCurrChannel); + BSSbUpdateToBSSList((HANDLE)pDevice, + *sFrame.pqwTimestamp, + *sFrame.pwBeaconInterval, + *sFrame.pwCapInfo, + byCurrChannel, + bChannelHit, + sFrame.pSSID, + sFrame.pSuppRates, + sFrame.pExtSuppRates, + &sERP, + sFrame.pRSN, + sFrame.pRSNWPA, + sFrame.pIE_Country, + sFrame.pIE_Quiet, + pBSSList, + sFrame.len - WLAN_HDR_ADDR3_LEN, + sFrame.pHdr->sA4.abyAddr4, // payload of probresponse + (HANDLE)pRxPacket + ); + + } + + if (bInScan) { + return; + } + + if(byCurrChannel == (BYTE)pMgmt->uCurrChannel) + bIsChannelEqual = TRUE; + + if (bIsChannelEqual && (pMgmt->eCurrMode == WMAC_MODE_ESS_AP)) { + + // if rx beacon without ERP field + if (sERP.bERPExist) { + if (WLAN_GET_ERP_USE_PROTECTION(sERP.byERP)){ + pDevice->byERPFlag |= WLAN_SET_ERP_USE_PROTECTION(1); + pDevice->wUseProtectCntDown = USE_PROTECT_PERIOD; + } + } + else { + pDevice->byERPFlag |= WLAN_SET_ERP_USE_PROTECTION(1); + pDevice->wUseProtectCntDown = USE_PROTECT_PERIOD; + } + + if (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) { + if(!WLAN_GET_CAP_INFO_SHORTPREAMBLE(*sFrame.pwCapInfo)) + pDevice->byERPFlag |= WLAN_SET_ERP_BARKER_MODE(1); + if(!sERP.bERPExist) + pDevice->byERPFlag |= WLAN_SET_ERP_NONERP_PRESENT(1); + } + + // set to MAC&BBP + if (WLAN_GET_ERP_USE_PROTECTION(pDevice->byERPFlag)){ + if (!pDevice->bProtectMode) { + MACvEnableProtectMD(pDevice->PortOffset); + pDevice->bProtectMode = TRUE; + } + } + } + + + if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) + return; + + // check if BSSID the same + if (memcmp(sFrame.pHdr->sA3.abyAddr3, + pMgmt->abyCurrBSSID, + WLAN_BSSID_LEN) == 0) { + + bIsBSSIDEqual = TRUE; + +// 2008-05-21 by Richardtai + pDevice->uCurrRSSI = pRxPacket->uRSSI; + pDevice->byCurrSQ = pRxPacket->bySQ; + + if (pMgmt->sNodeDBTable[0].uInActiveCount != 0) { + pMgmt->sNodeDBTable[0].uInActiveCount = 0; + //DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"BCN:Wake Count= [%d]\n", pMgmt->wCountToWakeUp); + } + } + // check if SSID the same + if (sFrame.pSSID->len == ((PWLAN_IE_SSID)pMgmt->abyCurrSSID)->len) { + if (memcmp(sFrame.pSSID->abySSID, + ((PWLAN_IE_SSID)pMgmt->abyCurrSSID)->abySSID, + sFrame.pSSID->len + ) == 0) { + bIsSSIDEqual = TRUE; + }; + } + + if ((WLAN_GET_CAP_INFO_ESS(*sFrame.pwCapInfo)== TRUE) && + (bIsBSSIDEqual == TRUE) && + (bIsSSIDEqual == TRUE) && + (pMgmt->eCurrMode == WMAC_MODE_ESS_STA) && + (pMgmt->eCurrState == WMAC_STATE_ASSOC)) { + // add state check to prevent reconnect fail since we'll receive Beacon + + bIsAPBeacon = TRUE; + + if (pBSSList != NULL) { + + // Compare PHY paramater setting + if (pMgmt->wCurrCapInfo != pBSSList->wCapInfo) { + bUpdatePhyParameter = TRUE; + pMgmt->wCurrCapInfo = pBSSList->wCapInfo; + } + if (sFrame.pERP != NULL) { + if ((sFrame.pERP->byElementID == WLAN_EID_ERP) && + (pMgmt->byERPContext != sFrame.pERP->byContext)) { + bUpdatePhyParameter = TRUE; + pMgmt->byERPContext = sFrame.pERP->byContext; + } + } + // + // Basic Rate Set may change dynamiclly + // + if (pBSSList->eNetworkTypeInUse == PHY_TYPE_11B) { + uRateLen = WLAN_RATES_MAXLEN_11B; + } + pMgmt->abyCurrSuppRates[1] = RATEuSetIE((PWLAN_IE_SUPP_RATES)pBSSList->abySuppRates, + (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates, + uRateLen); + pMgmt->abyCurrExtSuppRates[1] = RATEuSetIE((PWLAN_IE_SUPP_RATES)pBSSList->abyExtSuppRates, + (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates, + uRateLen); + RATEvParseMaxRate( (PVOID)pDevice, + (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates, + (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates, + TRUE, + &(pMgmt->sNodeDBTable[0].wMaxBasicRate), + &(pMgmt->sNodeDBTable[0].wMaxSuppRate), + &(pMgmt->sNodeDBTable[0].wSuppRate), + &(pMgmt->sNodeDBTable[0].byTopCCKBasicRate), + &(pMgmt->sNodeDBTable[0].byTopOFDMBasicRate) + ); +#ifdef PLICE_DEBUG + //printk("RxBeacon:MaxSuppRate is %d\n",pMgmt->sNodeDBTable[0].wMaxSuppRate); +#endif + if (bUpdatePhyParameter == TRUE) { + CARDbSetPhyParameter( pMgmt->pAdapter, + pMgmt->eCurrentPHYMode, + pMgmt->wCurrCapInfo, + pMgmt->byERPContext, + pMgmt->abyCurrSuppRates, + pMgmt->abyCurrExtSuppRates + ); + } + if (sFrame.pIE_PowerConstraint != NULL) { + CARDvSetPowerConstraint(pMgmt->pAdapter, + (BYTE) pBSSList->uChannel, + sFrame.pIE_PowerConstraint->byPower + ); + } + if (sFrame.pIE_CHSW != NULL) { + CARDbChannelSwitch( pMgmt->pAdapter, + sFrame.pIE_CHSW->byMode, + CARDbyGetChannelMapping(pMgmt->pAdapter, sFrame.pIE_CHSW->byMode, pMgmt->eCurrentPHYMode), + sFrame.pIE_CHSW->byCount + ); + + } else if (bIsChannelEqual == FALSE) { + CARDbSetChannel(pMgmt->pAdapter, pBSSList->uChannel); + } + } + } + +// DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Beacon 2 \n"); + // check if CF field exisit + if (WLAN_GET_CAP_INFO_ESS(*sFrame.pwCapInfo)) { + if (sFrame.pCFParms->wCFPDurRemaining > 0) { + // TODO: deal with CFP period to set NAV + }; + }; + + HIDWORD(qwTimestamp) = cpu_to_le32(HIDWORD(*sFrame.pqwTimestamp)); + LODWORD(qwTimestamp) = cpu_to_le32(LODWORD(*sFrame.pqwTimestamp)); + HIDWORD(qwLocalTSF) = HIDWORD(pRxPacket->qwLocalTSF); + LODWORD(qwLocalTSF) = LODWORD(pRxPacket->qwLocalTSF); + + // check if beacon TSF larger or small than our local TSF + if (HIDWORD(qwTimestamp) == HIDWORD(qwLocalTSF)) { + if (LODWORD(qwTimestamp) >= LODWORD(qwLocalTSF)) { + bTSFOffsetPostive = TRUE; + } + else { + bTSFOffsetPostive = FALSE; + } + } + else if (HIDWORD(qwTimestamp) > HIDWORD(qwLocalTSF)) { + bTSFOffsetPostive = TRUE; + } + else if (HIDWORD(qwTimestamp) < HIDWORD(qwLocalTSF)) { + bTSFOffsetPostive = FALSE; + }; + + if (bTSFOffsetPostive) { + qwTSFOffset = CARDqGetTSFOffset(pRxPacket->byRxRate, (qwTimestamp), (qwLocalTSF)); + } + else { + qwTSFOffset = CARDqGetTSFOffset(pRxPacket->byRxRate, (qwLocalTSF), (qwTimestamp)); + } + + if (HIDWORD(qwTSFOffset) != 0 || + (LODWORD(qwTSFOffset) > TRIVIAL_SYNC_DIFFERENCE )) { + bTSFLargeDiff = TRUE; + } + + + // if infra mode + if (bIsAPBeacon == TRUE) { + + // Infra mode: Local TSF always follow AP's TSF if Difference huge. + if (bTSFLargeDiff) + bUpdateTSF = TRUE; + + if ((pDevice->bEnablePSMode == TRUE) &&(sFrame.pTIM != 0)) { + + // deal with DTIM, analysis TIM + pMgmt->bMulticastTIM = WLAN_MGMT_IS_MULTICAST_TIM(sFrame.pTIM->byBitMapCtl) ? TRUE : FALSE ; + pMgmt->byDTIMCount = sFrame.pTIM->byDTIMCount; + pMgmt->byDTIMPeriod = sFrame.pTIM->byDTIMPeriod; + wAIDNumber = pMgmt->wCurrAID & ~(BIT14|BIT15); + + // check if AID in TIM field bit on + // wStartIndex = N1 + wStartIndex = WLAN_MGMT_GET_TIM_OFFSET(sFrame.pTIM->byBitMapCtl) << 1; + // AIDIndex = N2 + wAIDIndex = (wAIDNumber >> 3); + if ((wAIDNumber > 0) && (wAIDIndex >= wStartIndex)) { + uLocateByteIndex = wAIDIndex - wStartIndex; + // len = byDTIMCount + byDTIMPeriod + byDTIMPeriod + byVirtBitMap[0~250] + if (sFrame.pTIM->len >= (uLocateByteIndex + 4)) { + byTIMBitOn = (0x01) << ((wAIDNumber) % 8); + pMgmt->bInTIM = sFrame.pTIM->byVirtBitMap[uLocateByteIndex] & byTIMBitOn ? TRUE : FALSE; + } + else { + pMgmt->bInTIM = FALSE; + }; + } + else { + pMgmt->bInTIM = FALSE; + }; + + if (pMgmt->bInTIM || + (pMgmt->bMulticastTIM && (pMgmt->byDTIMCount == 0))) { + pMgmt->bInTIMWake = TRUE; + // send out ps-poll packet +// DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "BCN:In TIM\n"); + if (pMgmt->bInTIM) { + PSvSendPSPOLL((PSDevice)pDevice); +// DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "BCN:PS-POLL sent..\n"); + }; + + } + else { + pMgmt->bInTIMWake = FALSE; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "BCN: Not In TIM..\n"); + if (pDevice->bPWBitOn == FALSE) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "BCN: Send Null Packet\n"); + if (PSbSendNullPacket(pDevice)) + pDevice->bPWBitOn = TRUE; + } + if(PSbConsiderPowerDown(pDevice, FALSE, FALSE)) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "BCN: Power down now...\n"); + }; + } + + } + + } + // if adhoc mode + if ((pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) && !bIsAPBeacon && bIsChannelEqual) { + if (bIsBSSIDEqual) { + // Use sNodeDBTable[0].uInActiveCount as IBSS beacons received count. + if (pMgmt->sNodeDBTable[0].uInActiveCount != 0) + pMgmt->sNodeDBTable[0].uInActiveCount = 0; + + // adhoc mode:TSF updated only when beacon larger then local TSF + if (bTSFLargeDiff && bTSFOffsetPostive && + (pMgmt->eCurrState == WMAC_STATE_JOINTED)) + bUpdateTSF = TRUE; + + // During dpc, already in spinlocked. + if (BSSDBbIsSTAInNodeDB(pMgmt, sFrame.pHdr->sA3.abyAddr2, &uNodeIndex)) { + + // Update the STA, (Techically the Beacons of all the IBSS nodes + // should be identical, but that's not happening in practice. + pMgmt->abyCurrSuppRates[1] = RATEuSetIE((PWLAN_IE_SUPP_RATES)sFrame.pSuppRates, + (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates, + WLAN_RATES_MAXLEN_11B); + RATEvParseMaxRate( (PVOID)pDevice, + (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates, + NULL, + TRUE, + &(pMgmt->sNodeDBTable[uNodeIndex].wMaxBasicRate), + &(pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate), + &(pMgmt->sNodeDBTable[uNodeIndex].wSuppRate), + &(pMgmt->sNodeDBTable[uNodeIndex].byTopCCKBasicRate), + &(pMgmt->sNodeDBTable[uNodeIndex].byTopOFDMBasicRate) + ); + pMgmt->sNodeDBTable[uNodeIndex].bShortPreamble = WLAN_GET_CAP_INFO_SHORTPREAMBLE(*sFrame.pwCapInfo); + pMgmt->sNodeDBTable[uNodeIndex].bShortSlotTime = WLAN_GET_CAP_INFO_SHORTSLOTTIME(*sFrame.pwCapInfo); + pMgmt->sNodeDBTable[uNodeIndex].uInActiveCount = 0; + } + else { + // Todo, initial Node content + BSSvCreateOneNode((PSDevice)pDevice, &uNodeIndex); + + pMgmt->abyCurrSuppRates[1] = RATEuSetIE((PWLAN_IE_SUPP_RATES)sFrame.pSuppRates, + (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates, + WLAN_RATES_MAXLEN_11B); + RATEvParseMaxRate( (PVOID)pDevice, + (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates, + NULL, + TRUE, + &(pMgmt->sNodeDBTable[uNodeIndex].wMaxBasicRate), + &(pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate), + &(pMgmt->sNodeDBTable[uNodeIndex].wSuppRate), + &(pMgmt->sNodeDBTable[uNodeIndex].byTopCCKBasicRate), + &(pMgmt->sNodeDBTable[uNodeIndex].byTopOFDMBasicRate) + ); + + memcpy(pMgmt->sNodeDBTable[uNodeIndex].abyMACAddr, sFrame.pHdr->sA3.abyAddr2, WLAN_ADDR_LEN); + pMgmt->sNodeDBTable[uNodeIndex].bShortPreamble = WLAN_GET_CAP_INFO_SHORTPREAMBLE(*sFrame.pwCapInfo); + pMgmt->sNodeDBTable[uNodeIndex].wTxDataRate = pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate; +#ifdef PLICE_DEBUG + //if (uNodeIndex == 0) + { + printk("s_vMgrRxBeacon:TxDataRate is %d,Index is %d\n",pMgmt->sNodeDBTable[uNodeIndex].wTxDataRate,uNodeIndex); + } +#endif +/* + pMgmt->sNodeDBTable[uNodeIndex].bShortSlotTime = WLAN_GET_CAP_INFO_SHORTSLOTTIME(*sFrame.pwCapInfo); + if(pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate > RATE_11M) + pMgmt->sNodeDBTable[uNodeIndex].bERPExist = TRUE; +*/ + } + + // if other stations jointed, indicate connect to upper layer.. + if (pMgmt->eCurrState == WMAC_STATE_STARTED) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Current IBSS State: [Started]........to: [Jointed] \n"); + pMgmt->eCurrState = WMAC_STATE_JOINTED; + pDevice->bLinkPass = TRUE; + if (netif_queue_stopped(pDevice->dev)){ + netif_wake_queue(pDevice->dev); + } + pMgmt->sNodeDBTable[0].bActive = TRUE; + pMgmt->sNodeDBTable[0].uInActiveCount = 0; + + }; + } + else if (bIsSSIDEqual) { + + // See other adhoc sta with the same SSID but BSSID is different. + // adpot this vars only when TSF larger then us. + if (bTSFLargeDiff && bTSFOffsetPostive) { + // we don't support ATIM under adhoc mode + // if ( sFrame.pIBSSParms->wATIMWindow == 0) { + // adpot this vars + // TODO: check sFrame cap if privacy on, and support rate syn + memcpy(pMgmt->abyCurrBSSID, sFrame.pHdr->sA3.abyAddr3, WLAN_BSSID_LEN); + memcpy(pDevice->abyBSSID, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN); + pMgmt->wCurrATIMWindow = cpu_to_le16(sFrame.pIBSSParms->wATIMWindow); + pMgmt->wCurrBeaconPeriod = cpu_to_le16(*sFrame.pwBeaconInterval); + pMgmt->abyCurrSuppRates[1] = RATEuSetIE((PWLAN_IE_SUPP_RATES)sFrame.pSuppRates, + (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates, + WLAN_RATES_MAXLEN_11B); + // set HW beacon interval and re-synchronizing.... + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Rejoining to Other Adhoc group with same SSID........\n"); + VNSvOutPortW(pDevice->PortOffset + MAC_REG_BI, pMgmt->wCurrBeaconPeriod); + CARDbUpdateTSF(pDevice, pRxPacket->byRxRate, qwTimestamp, qwLocalTSF); + CARDvUpdateNextTBTT(pDevice->PortOffset, qwTimestamp, pMgmt->wCurrBeaconPeriod); + // Turn off bssid filter to avoid filter others adhoc station which bssid is different. + MACvWriteBSSIDAddress(pDevice->PortOffset, pMgmt->abyCurrBSSID); + + CARDbSetPhyParameter ( pMgmt->pAdapter, + pMgmt->eCurrentPHYMode, + pMgmt->wCurrCapInfo, + pMgmt->byERPContext, + pMgmt->abyCurrSuppRates, + pMgmt->abyCurrExtSuppRates); + + + // MACvRegBitsOff(pDevice->PortOffset, MAC_REG_RCR, RCR_BSSID); + // set highest basic rate + // s_vSetHighestBasicRate(pDevice, (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates); + // Prepare beacon frame + bMgrPrepareBeaconToSend((HANDLE)pDevice, pMgmt); + // } + }; + } + }; + // endian issue ??? + // Update TSF + if (bUpdateTSF) { + CARDbGetCurrentTSF(pDevice->PortOffset, &qwCurrTSF); + CARDbUpdateTSF(pDevice, pRxPacket->byRxRate, qwTimestamp, pRxPacket->qwLocalTSF); + CARDbGetCurrentTSF(pDevice->PortOffset, &qwCurrTSF); + CARDvUpdateNextTBTT(pDevice->PortOffset, qwTimestamp, pMgmt->wCurrBeaconPeriod); + } + + return; +} + + + +/*+ + * + * Routine Description: + * Instructs the hw to create a bss using the supplied + * attributes. Note that this implementation only supports Ad-Hoc + * BSS creation. + * + * + * Return Value: + * CMD_STATUS + * +-*/ +VOID +vMgrCreateOwnIBSS( + IN HANDLE hDeviceContext, + OUT PCMD_STATUS pStatus + ) +{ + PSDevice pDevice = (PSDevice)hDeviceContext; + PSMgmtObject pMgmt = pDevice->pMgmt; + WORD wMaxBasicRate; + WORD wMaxSuppRate; + BYTE byTopCCKBasicRate; + BYTE byTopOFDMBasicRate; + QWORD qwCurrTSF; + UINT ii; + BYTE abyRATE[] = {0x82, 0x84, 0x8B, 0x96, 0x24, 0x30, 0x48, 0x6C, 0x0C, 0x12, 0x18, 0x60}; + BYTE abyCCK_RATE[] = {0x82, 0x84, 0x8B, 0x96}; + BYTE abyOFDM_RATE[] = {0x0C, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C}; + WORD wSuppRate; + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Create Basic Service Set .......\n"); + + if (pMgmt->eConfigMode == WMAC_CONFIG_IBSS_STA) { + if ((pMgmt->eAuthenMode == WMAC_AUTH_WPANONE) && + (pDevice->eEncryptionStatus != Ndis802_11Encryption2Enabled) && + (pDevice->eEncryptionStatus != Ndis802_11Encryption3Enabled)) { + // encryption mode error + *pStatus = CMD_STATUS_FAILURE; + return; + } + } + + pMgmt->abyCurrSuppRates[0] = WLAN_EID_SUPP_RATES; + pMgmt->abyCurrExtSuppRates[0] = WLAN_EID_EXTSUPP_RATES; + + if (pMgmt->eConfigMode == WMAC_CONFIG_AP) { + pMgmt->eCurrentPHYMode = pMgmt->byAPBBType; + } else { + if (pDevice->byBBType == BB_TYPE_11G) + pMgmt->eCurrentPHYMode = PHY_TYPE_11G; + if (pDevice->byBBType == BB_TYPE_11B) + pMgmt->eCurrentPHYMode = PHY_TYPE_11B; + if (pDevice->byBBType == BB_TYPE_11A) + pMgmt->eCurrentPHYMode = PHY_TYPE_11A; + } + + if (pMgmt->eCurrentPHYMode != PHY_TYPE_11A) { + pMgmt->abyCurrSuppRates[1] = WLAN_RATES_MAXLEN_11B; + pMgmt->abyCurrExtSuppRates[1] = 0; + for (ii = 0; ii < 4; ii++) + pMgmt->abyCurrSuppRates[2+ii] = abyRATE[ii]; + } else { + pMgmt->abyCurrSuppRates[1] = 8; + pMgmt->abyCurrExtSuppRates[1] = 0; + for (ii = 0; ii < 8; ii++) + pMgmt->abyCurrSuppRates[2+ii] = abyRATE[ii]; + } + + + if (pMgmt->eCurrentPHYMode == PHY_TYPE_11G) { + pMgmt->abyCurrSuppRates[1] = 8; + pMgmt->abyCurrExtSuppRates[1] = 4; + for (ii = 0; ii < 4; ii++) + pMgmt->abyCurrSuppRates[2+ii] = abyCCK_RATE[ii]; + for (ii = 4; ii < 8; ii++) + pMgmt->abyCurrSuppRates[2+ii] = abyOFDM_RATE[ii-4]; + for (ii = 0; ii < 4; ii++) + pMgmt->abyCurrExtSuppRates[2+ii] = abyOFDM_RATE[ii+4]; + } + + + // Disable Protect Mode + pDevice->bProtectMode = 0; + MACvDisableProtectMD(pDevice->PortOffset); + + pDevice->bBarkerPreambleMd = 0; + MACvDisableBarkerPreambleMd(pDevice->PortOffset); + + // Kyle Test 2003.11.04 + + // set HW beacon interval + if (pMgmt->wIBSSBeaconPeriod == 0) + pMgmt->wIBSSBeaconPeriod = DEFAULT_IBSS_BI; + + + CARDbGetCurrentTSF(pDevice->PortOffset, &qwCurrTSF); + // clear TSF counter + VNSvOutPortB(pDevice->PortOffset + MAC_REG_TFTCTL, TFTCTL_TSFCNTRST); + // enable TSF counter + VNSvOutPortB(pDevice->PortOffset + MAC_REG_TFTCTL, TFTCTL_TSFCNTREN); + + // set Next TBTT + CARDvSetFirstNextTBTT(pDevice->PortOffset, pMgmt->wIBSSBeaconPeriod); + + pMgmt->uIBSSChannel = pDevice->uChannel; + + if (pMgmt->uIBSSChannel == 0) + pMgmt->uIBSSChannel = DEFAULT_IBSS_CHANNEL; + + + // set basic rate + + RATEvParseMaxRate((PVOID)pDevice, (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates, + (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates, TRUE, + &wMaxBasicRate, &wMaxSuppRate, &wSuppRate, + &byTopCCKBasicRate, &byTopOFDMBasicRate); + + + if (pMgmt->eConfigMode == WMAC_CONFIG_AP) { + pMgmt->eCurrMode = WMAC_MODE_ESS_AP; + } + + if (pMgmt->eConfigMode == WMAC_CONFIG_IBSS_STA) { + MEMvCopy(pMgmt->abyIBSSDFSOwner, pDevice->abyCurrentNetAddr, 6); + pMgmt->byIBSSDFSRecovery = 10; + pMgmt->eCurrMode = WMAC_MODE_IBSS_STA; + } + + // Adopt pre-configured IBSS vars to current vars + pMgmt->eCurrState = WMAC_STATE_STARTED; + pMgmt->wCurrBeaconPeriod = pMgmt->wIBSSBeaconPeriod; + pMgmt->uCurrChannel = pMgmt->uIBSSChannel; + pMgmt->wCurrATIMWindow = pMgmt->wIBSSATIMWindow; + MACvWriteATIMW(pDevice->PortOffset, pMgmt->wCurrATIMWindow); + pDevice->uCurrRSSI = 0; + pDevice->byCurrSQ = 0; + //memcpy(pMgmt->abyDesireSSID,pMgmt->abyAdHocSSID, + // ((PWLAN_IE_SSID)pMgmt->abyAdHocSSID)->len + WLAN_IEHDR_LEN); + memset(pMgmt->abyCurrSSID, 0, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1); + memcpy(pMgmt->abyCurrSSID, + pMgmt->abyDesireSSID, + ((PWLAN_IE_SSID)pMgmt->abyDesireSSID)->len + WLAN_IEHDR_LEN + ); + + if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) { + // AP mode BSSID = MAC addr + memcpy(pMgmt->abyCurrBSSID, pMgmt->abyMACAddr, WLAN_ADDR_LEN); + DEVICE_PRT(MSG_LEVEL_INFO, KERN_INFO"AP beacon created BSSID:%02x-%02x-%02x-%02x-%02x-%02x \n", + pMgmt->abyCurrBSSID[0], + pMgmt->abyCurrBSSID[1], + pMgmt->abyCurrBSSID[2], + pMgmt->abyCurrBSSID[3], + pMgmt->abyCurrBSSID[4], + pMgmt->abyCurrBSSID[5] + ); + } + + if (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) { + + // BSSID selected must be randomized as spec 11.1.3 + pMgmt->abyCurrBSSID[5] = (BYTE) (LODWORD(qwCurrTSF)& 0x000000ff); + pMgmt->abyCurrBSSID[4] = (BYTE)((LODWORD(qwCurrTSF)& 0x0000ff00) >> 8); + pMgmt->abyCurrBSSID[3] = (BYTE)((LODWORD(qwCurrTSF)& 0x00ff0000) >> 16); + pMgmt->abyCurrBSSID[2] = (BYTE)((LODWORD(qwCurrTSF)& 0x00000ff0) >> 4); + pMgmt->abyCurrBSSID[1] = (BYTE)((LODWORD(qwCurrTSF)& 0x000ff000) >> 12); + pMgmt->abyCurrBSSID[0] = (BYTE)((LODWORD(qwCurrTSF)& 0x0ff00000) >> 20); + pMgmt->abyCurrBSSID[5] ^= pMgmt->abyMACAddr[0]; + pMgmt->abyCurrBSSID[4] ^= pMgmt->abyMACAddr[1]; + pMgmt->abyCurrBSSID[3] ^= pMgmt->abyMACAddr[2]; + pMgmt->abyCurrBSSID[2] ^= pMgmt->abyMACAddr[3]; + pMgmt->abyCurrBSSID[1] ^= pMgmt->abyMACAddr[4]; + pMgmt->abyCurrBSSID[0] ^= pMgmt->abyMACAddr[5]; + pMgmt->abyCurrBSSID[0] &= ~IEEE_ADDR_GROUP; + pMgmt->abyCurrBSSID[0] |= IEEE_ADDR_UNIVERSAL; + + + DEVICE_PRT(MSG_LEVEL_INFO, KERN_INFO"Adhoc beacon created bssid:%02x-%02x-%02x-%02x-%02x-%02x \n", + pMgmt->abyCurrBSSID[0], + pMgmt->abyCurrBSSID[1], + pMgmt->abyCurrBSSID[2], + pMgmt->abyCurrBSSID[3], + pMgmt->abyCurrBSSID[4], + pMgmt->abyCurrBSSID[5] + ); + } + + // Set Capability Info + pMgmt->wCurrCapInfo = 0; + + if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) { + pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_ESS(1); + pMgmt->byDTIMPeriod = DEFAULT_DTIM_PERIOD; + pMgmt->byDTIMCount = pMgmt->byDTIMPeriod - 1; + } + + if (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) { + pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_IBSS(1); + } + + if (pDevice->bEncryptionEnable) { + pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_PRIVACY(1); + if (pMgmt->eAuthenMode == WMAC_AUTH_WPANONE) { + if (pDevice->eEncryptionStatus == Ndis802_11Encryption3Enabled) { + pMgmt->byCSSPK = KEY_CTL_CCMP; + pMgmt->byCSSGK = KEY_CTL_CCMP; + } else if (pDevice->eEncryptionStatus == Ndis802_11Encryption2Enabled) { + pMgmt->byCSSPK = KEY_CTL_TKIP; + pMgmt->byCSSGK = KEY_CTL_TKIP; + } else { + pMgmt->byCSSPK = KEY_CTL_NONE; + pMgmt->byCSSGK = KEY_CTL_WEP; + } + } else { + pMgmt->byCSSPK = KEY_CTL_WEP; + pMgmt->byCSSGK = KEY_CTL_WEP; + } + }; + + pMgmt->byERPContext = 0; + +// memcpy(pDevice->abyBSSID, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN); + + if (pMgmt->eConfigMode == WMAC_CONFIG_AP) { + CARDbSetBSSID(pMgmt->pAdapter, pMgmt->abyCurrBSSID, OP_MODE_AP); + } else { + CARDbSetBSSID(pMgmt->pAdapter, pMgmt->abyCurrBSSID, OP_MODE_ADHOC); + } + + CARDbSetPhyParameter( pMgmt->pAdapter, + pMgmt->eCurrentPHYMode, + pMgmt->wCurrCapInfo, + pMgmt->byERPContext, + pMgmt->abyCurrSuppRates, + pMgmt->abyCurrExtSuppRates + ); + + CARDbSetBeaconPeriod(pMgmt->pAdapter, pMgmt->wIBSSBeaconPeriod); + // set channel and clear NAV + CARDbSetChannel(pMgmt->pAdapter, pMgmt->uIBSSChannel); + pMgmt->uCurrChannel = pMgmt->uIBSSChannel; + + if (CARDbIsShortPreamble(pMgmt->pAdapter)) { + pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SHORTPREAMBLE(1); + } else { + pMgmt->wCurrCapInfo &= (~WLAN_SET_CAP_INFO_SHORTPREAMBLE(1)); + } + + if ((pMgmt->b11hEnable == TRUE) && + (pMgmt->eCurrentPHYMode == PHY_TYPE_11A)) { + pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SPECTRUMMNG(1); + } else { + pMgmt->wCurrCapInfo &= (~WLAN_SET_CAP_INFO_SPECTRUMMNG(1)); + } + + pMgmt->eCurrState = WMAC_STATE_STARTED; + // Prepare beacon to send + if (bMgrPrepareBeaconToSend((HANDLE)pDevice, pMgmt)) { + *pStatus = CMD_STATUS_SUCCESS; + } + + return ; +} + + + +/*+ + * + * Routine Description: + * Instructs wmac to join a bss using the supplied attributes. + * The arguments may the BSSID or SSID and the rest of the + * attributes are obtained from the scan result of known bss list. + * + * + * Return Value: + * None. + * +-*/ + +VOID +vMgrJoinBSSBegin( + IN HANDLE hDeviceContext, + OUT PCMD_STATUS pStatus + ) +{ + + PSDevice pDevice = (PSDevice)hDeviceContext; + PSMgmtObject pMgmt = pDevice->pMgmt; + PKnownBSS pCurr = NULL; + UINT ii, uu; + PWLAN_IE_SUPP_RATES pItemRates = NULL; + PWLAN_IE_SUPP_RATES pItemExtRates = NULL; + PWLAN_IE_SSID pItemSSID; + UINT uRateLen = WLAN_RATES_MAXLEN; + WORD wMaxBasicRate = RATE_1M; + WORD wMaxSuppRate = RATE_1M; + WORD wSuppRate; + BYTE byTopCCKBasicRate = RATE_1M; + BYTE byTopOFDMBasicRate = RATE_1M; + + + for (ii = 0; ii < MAX_BSS_NUM; ii++) { + if (pMgmt->sBSSList[ii].bActive == TRUE) + break; + } + + if (ii == MAX_BSS_NUM) { + *pStatus = CMD_STATUS_RESOURCES; + DEVICE_PRT(MSG_LEVEL_NOTICE, KERN_INFO "BSS finding:BSS list is empty.\n"); + return; + }; + + // memset(pMgmt->abyDesireBSSID, 0, WLAN_BSSID_LEN); + // Search known BSS list for prefer BSSID or SSID + + pCurr = BSSpSearchBSSList(pDevice, + pMgmt->abyDesireBSSID, + pMgmt->abyDesireSSID, + pMgmt->eConfigPHYMode + ); + + if (pCurr == NULL){ + *pStatus = CMD_STATUS_RESOURCES; + pItemSSID = (PWLAN_IE_SSID)pMgmt->abyDesireSSID; + DEVICE_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Scanning [%s] not found, disconnected !\n", pItemSSID->abySSID); + return; + }; + + DEVICE_PRT(MSG_LEVEL_NOTICE, KERN_INFO "AP(BSS) finding:Found a AP(BSS)..\n"); + if (WLAN_GET_CAP_INFO_ESS(cpu_to_le16(pCurr->wCapInfo))){ + + if ((pMgmt->eAuthenMode == WMAC_AUTH_WPA)||(pMgmt->eAuthenMode == WMAC_AUTH_WPAPSK)) { + + // patch for CISCO migration mode +/* + if (pDevice->eEncryptionStatus == Ndis802_11Encryption2Enabled) { + if (WPA_SearchRSN(0, WPA_TKIP, pCurr) == FALSE) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"No match RSN info. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"); + // encryption mode error + pMgmt->eCurrState = WMAC_STATE_IDLE; + return; + } + } else if (pDevice->eEncryptionStatus == Ndis802_11Encryption3Enabled) { + if (WPA_SearchRSN(0, WPA_AESCCMP, pCurr) == FALSE) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"No match RSN info. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"); + // encryption mode error + pMgmt->eCurrState = WMAC_STATE_IDLE; + return; + } + } +*/ + } + +#ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT + //if(pDevice->bWPASuppWextEnabled == TRUE) + Encyption_Rebuild(pDevice, pCurr); +#endif + // Infrastructure BSS + s_vMgrSynchBSS(pDevice, + WMAC_MODE_ESS_STA, + pCurr, + pStatus + ); + + if (*pStatus == CMD_STATUS_SUCCESS){ + + // Adopt this BSS state vars in Mgmt Object + pMgmt->uCurrChannel = pCurr->uChannel; + + memset(pMgmt->abyCurrSuppRates, 0 , WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1); + memset(pMgmt->abyCurrExtSuppRates, 0 , WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1); + + if (pCurr->eNetworkTypeInUse == PHY_TYPE_11B) { + uRateLen = WLAN_RATES_MAXLEN_11B; + } + + pItemRates = (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates; + pItemExtRates = (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates; + + // Parse Support Rate IE + pItemRates->byElementID = WLAN_EID_SUPP_RATES; + pItemRates->len = RATEuSetIE((PWLAN_IE_SUPP_RATES)pCurr->abySuppRates, + pItemRates, + uRateLen); + + // Parse Extension Support Rate IE + pItemExtRates->byElementID = WLAN_EID_EXTSUPP_RATES; + pItemExtRates->len = RATEuSetIE((PWLAN_IE_SUPP_RATES)pCurr->abyExtSuppRates, + pItemExtRates, + uRateLen); + // Stuffing Rate IE + if ((pItemExtRates->len > 0) && (pItemRates->len < 8)) { + for (ii = 0; ii < (UINT)(8 - pItemRates->len); ) { + pItemRates->abyRates[pItemRates->len + ii] = pItemExtRates->abyRates[ii]; + ii ++; + if (pItemExtRates->len <= ii) + break; + } + pItemRates->len += (BYTE)ii; + if (pItemExtRates->len - ii > 0) { + pItemExtRates->len -= (BYTE)ii; + for (uu = 0; uu < pItemExtRates->len; uu ++) { + pItemExtRates->abyRates[uu] = pItemExtRates->abyRates[uu + ii]; + } + } else { + pItemExtRates->len = 0; + } + } + + RATEvParseMaxRate((PVOID)pDevice, pItemRates, pItemExtRates, TRUE, + &wMaxBasicRate, &wMaxSuppRate, &wSuppRate, + &byTopCCKBasicRate, &byTopOFDMBasicRate); + + // TODO: deal with if wCapInfo the privacy is on, but station WEP is off + // TODO: deal with if wCapInfo the PS-Pollable is on. + pMgmt->wCurrBeaconPeriod = pCurr->wBeaconInterval; + memset(pMgmt->abyCurrSSID, 0, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1); + memcpy(pMgmt->abyCurrBSSID, pCurr->abyBSSID, WLAN_BSSID_LEN); + memcpy(pMgmt->abyCurrSSID, pCurr->abySSID, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1); + + pMgmt->eCurrMode = WMAC_MODE_ESS_STA; + + pMgmt->eCurrState = WMAC_STATE_JOINTED; + // Adopt BSS state in Adapter Device Object + //pDevice->byOpMode = OP_MODE_INFRASTRUCTURE; +// memcpy(pDevice->abyBSSID, pCurr->abyBSSID, WLAN_BSSID_LEN); + + // Add current BSS to Candidate list + // This should only works for WPA2 BSS, and WPA2 BSS check must be done before. + if (pMgmt->eAuthenMode == WMAC_AUTH_WPA2) { + BOOL bResult = bAdd_PMKID_Candidate((HANDLE)pDevice, pMgmt->abyCurrBSSID, &pCurr->sRSNCapObj); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"bAdd_PMKID_Candidate: 1(%d)\n", bResult); + if (bResult == FALSE) { + vFlush_PMKID_Candidate((HANDLE)pDevice); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"vFlush_PMKID_Candidate: 4\n"); + bAdd_PMKID_Candidate((HANDLE)pDevice, pMgmt->abyCurrBSSID, &pCurr->sRSNCapObj); + } + } + + // Preamble type auto-switch: if AP can receive short-preamble cap, + // we can turn on too. + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Join ESS\n"); + + + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"End of Join AP -- A/B/G Action\n"); + } + else { + pMgmt->eCurrState = WMAC_STATE_IDLE; + }; + + + } + else { + // ad-hoc mode BSS + if (pMgmt->eAuthenMode == WMAC_AUTH_WPANONE) { + + if (pDevice->eEncryptionStatus == Ndis802_11Encryption2Enabled) { + if (WPA_SearchRSN(0, WPA_TKIP, pCurr) == FALSE) { + // encryption mode error + pMgmt->eCurrState = WMAC_STATE_IDLE; + return; + } + } else if (pDevice->eEncryptionStatus == Ndis802_11Encryption3Enabled) { + if (WPA_SearchRSN(0, WPA_AESCCMP, pCurr) == FALSE) { + // encryption mode error + pMgmt->eCurrState = WMAC_STATE_IDLE; + return; + } + } else { + // encryption mode error + pMgmt->eCurrState = WMAC_STATE_IDLE; + return; + } + } + + s_vMgrSynchBSS(pDevice, + WMAC_MODE_IBSS_STA, + pCurr, + pStatus + ); + + if (*pStatus == CMD_STATUS_SUCCESS){ + // Adopt this BSS state vars in Mgmt Object + // TODO: check if CapInfo privacy on, but we don't.. + pMgmt->uCurrChannel = pCurr->uChannel; + + + // Parse Support Rate IE + pMgmt->abyCurrSuppRates[0] = WLAN_EID_SUPP_RATES; + pMgmt->abyCurrSuppRates[1] = RATEuSetIE((PWLAN_IE_SUPP_RATES)pCurr->abySuppRates, + (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates, + WLAN_RATES_MAXLEN_11B); + // set basic rate + RATEvParseMaxRate((PVOID)pDevice, (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates, + NULL, TRUE, &wMaxBasicRate, &wMaxSuppRate, &wSuppRate, + &byTopCCKBasicRate, &byTopOFDMBasicRate); + + pMgmt->wCurrCapInfo = pCurr->wCapInfo; + pMgmt->wCurrBeaconPeriod = pCurr->wBeaconInterval; + memset(pMgmt->abyCurrSSID, 0, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN); + memcpy(pMgmt->abyCurrBSSID, pCurr->abyBSSID, WLAN_BSSID_LEN); + memcpy(pMgmt->abyCurrSSID, pCurr->abySSID, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN); +// pMgmt->wCurrATIMWindow = pCurr->wATIMWindow; + MACvWriteATIMW(pDevice->PortOffset, pMgmt->wCurrATIMWindow); + pMgmt->eCurrMode = WMAC_MODE_IBSS_STA; + + pMgmt->eCurrState = WMAC_STATE_STARTED; + // Adopt BSS state in Adapter Device Object + //pDevice->byOpMode = OP_MODE_ADHOC; +// pDevice->bLinkPass = TRUE; +// memcpy(pDevice->abyBSSID, pCurr->abyBSSID, WLAN_BSSID_LEN); + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Join IBSS ok:%02x-%02x-%02x-%02x-%02x-%02x \n", + pMgmt->abyCurrBSSID[0], + pMgmt->abyCurrBSSID[1], + pMgmt->abyCurrBSSID[2], + pMgmt->abyCurrBSSID[3], + pMgmt->abyCurrBSSID[4], + pMgmt->abyCurrBSSID[5] + ); + // Preamble type auto-switch: if AP can receive short-preamble cap, + // and if registry setting is short preamble we can turn on too. + + // Prepare beacon + bMgrPrepareBeaconToSend((HANDLE)pDevice, pMgmt); + } + else { + pMgmt->eCurrState = WMAC_STATE_IDLE; + }; + }; + return; +} + + + +/*+ + * + * Routine Description: + * Set HW to synchronize a specific BSS from known BSS list. + * + * + * Return Value: + * PCM_STATUS + * +-*/ +static +VOID +s_vMgrSynchBSS ( + IN PSDevice pDevice, + IN UINT uBSSMode, + IN PKnownBSS pCurr, + OUT PCMD_STATUS pStatus + ) +{ + CARD_PHY_TYPE ePhyType = PHY_TYPE_11B; + PSMgmtObject pMgmt = pDevice->pMgmt; +// int ii; + //1M, 2M, 5M, 11M, 18M, 24M, 36M, 54M + BYTE abyCurrSuppRatesG[] = {WLAN_EID_SUPP_RATES, 8, 0x02, 0x04, 0x0B, 0x16, 0x24, 0x30, 0x48, 0x6C}; + BYTE abyCurrExtSuppRatesG[] = {WLAN_EID_EXTSUPP_RATES, 4, 0x0C, 0x12, 0x18, 0x60}; + //6M, 9M, 12M, 48M + BYTE abyCurrSuppRatesA[] = {WLAN_EID_SUPP_RATES, 8, 0x0C, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C}; + BYTE abyCurrSuppRatesB[] = {WLAN_EID_SUPP_RATES, 4, 0x02, 0x04, 0x0B, 0x16}; + + + *pStatus = CMD_STATUS_FAILURE; + + if (s_bCipherMatch(pCurr, + pDevice->eEncryptionStatus, + &(pMgmt->byCSSPK), + &(pMgmt->byCSSGK)) == FALSE) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "s_bCipherMatch Fail .......\n"); + return; + } + + pMgmt->pCurrBSS = pCurr; + + // if previous mode is IBSS. + if(pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) { + MACvRegBitsOff(pDevice->PortOffset, MAC_REG_BCNDMACTL, BEACON_READY); + MACvRegBitsOff(pDevice->PortOffset, MAC_REG_TCR, TCR_AUTOBCNTX); + } + + // Init the BSS informations + pDevice->bCCK = TRUE; + pDevice->bProtectMode = FALSE; + MACvDisableProtectMD(pDevice->PortOffset); + pDevice->bBarkerPreambleMd = FALSE; + MACvDisableBarkerPreambleMd(pDevice->PortOffset); + pDevice->bNonERPPresent = FALSE; + pDevice->byPreambleType = 0; + pDevice->wBasicRate = 0; + // Set Basic Rate + CARDbAddBasicRate((PVOID)pDevice, RATE_1M); + // calculate TSF offset + // TSF Offset = Received Timestamp TSF - Marked Local's TSF + CARDbUpdateTSF(pDevice, pCurr->byRxRate, pCurr->qwBSSTimestamp, pCurr->qwLocalTSF); + + CARDbSetBeaconPeriod(pDevice, pCurr->wBeaconInterval); + + // set Next TBTT + // Next TBTT = ((local_current_TSF / beacon_interval) + 1 ) * beacon_interval + CARDvSetFirstNextTBTT(pDevice->PortOffset, pCurr->wBeaconInterval); + + // set BSSID + MACvWriteBSSIDAddress(pDevice->PortOffset, pCurr->abyBSSID); + + MACvReadBSSIDAddress(pDevice->PortOffset, pMgmt->abyCurrBSSID); + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Sync:set CurrBSSID address = %02x-%02x-%02x=%02x-%02x-%02x\n", + pMgmt->abyCurrBSSID[0], + pMgmt->abyCurrBSSID[1], + pMgmt->abyCurrBSSID[2], + pMgmt->abyCurrBSSID[3], + pMgmt->abyCurrBSSID[4], + pMgmt->abyCurrBSSID[5]); + + if (pCurr->eNetworkTypeInUse == PHY_TYPE_11A) { + if ((pMgmt->eConfigPHYMode == PHY_TYPE_11A) || + (pMgmt->eConfigPHYMode == PHY_TYPE_AUTO)) { + ePhyType = PHY_TYPE_11A; + } else { + return; + } + } else if (pCurr->eNetworkTypeInUse == PHY_TYPE_11B) { + if ((pMgmt->eConfigPHYMode == PHY_TYPE_11B) || + (pMgmt->eConfigPHYMode == PHY_TYPE_11G) || + (pMgmt->eConfigPHYMode == PHY_TYPE_AUTO)) { + ePhyType = PHY_TYPE_11B; + } else { + return; + } + } else { + if ((pMgmt->eConfigPHYMode == PHY_TYPE_11G) || + (pMgmt->eConfigPHYMode == PHY_TYPE_AUTO)) { + ePhyType = PHY_TYPE_11G; + } else if (pMgmt->eConfigPHYMode == PHY_TYPE_11B) { + ePhyType = PHY_TYPE_11B; + } else { + return; + } + } + + if (ePhyType == PHY_TYPE_11A) { + MEMvCopy(pMgmt->abyCurrSuppRates, &abyCurrSuppRatesA[0], sizeof(abyCurrSuppRatesA)); + pMgmt->abyCurrExtSuppRates[1] = 0; + } else if (ePhyType == PHY_TYPE_11B) { + MEMvCopy(pMgmt->abyCurrSuppRates, &abyCurrSuppRatesB[0], sizeof(abyCurrSuppRatesB)); + pMgmt->abyCurrExtSuppRates[1] = 0; + } else { + MEMvCopy(pMgmt->abyCurrSuppRates, &abyCurrSuppRatesG[0], sizeof(abyCurrSuppRatesG)); + MEMvCopy(pMgmt->abyCurrExtSuppRates, &abyCurrExtSuppRatesG[0], sizeof(abyCurrExtSuppRatesG)); + } + + + if (WLAN_GET_CAP_INFO_ESS(pCurr->wCapInfo)) { + CARDbSetBSSID(pMgmt->pAdapter, pCurr->abyBSSID, OP_MODE_INFRASTRUCTURE); + // Add current BSS to Candidate list + // This should only works for WPA2 BSS, and WPA2 BSS check must be done before. + if (pMgmt->eAuthenMode == WMAC_AUTH_WPA2) { + CARDbAdd_PMKID_Candidate(pMgmt->pAdapter, pMgmt->abyCurrBSSID, pCurr->sRSNCapObj.bRSNCapExist, pCurr->sRSNCapObj.wRSNCap); + } + } else { + CARDbSetBSSID(pMgmt->pAdapter, pCurr->abyBSSID, OP_MODE_ADHOC); + } + + if (CARDbSetPhyParameter( pMgmt->pAdapter, + ePhyType, + pCurr->wCapInfo, + pCurr->sERP.byERP, + pMgmt->abyCurrSuppRates, + pMgmt->abyCurrExtSuppRates + ) != TRUE) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "<----s_bSynchBSS Set Phy Mode Fail [%d]\n", ePhyType); + return; + } + // set channel and clear NAV + if (CARDbSetChannel(pMgmt->pAdapter, pCurr->uChannel) == FALSE) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "<----s_bSynchBSS Set Channel [%d]\n", pCurr->uChannel); + return; + } + +/* + for (ii=0;iildBmMAX< pDevice->ldBmThreshold[ii]) { + pDevice->byBBVGANew = pDevice->abyBBVGA[ii]; + break; + } + } + + if (pDevice->byBBVGANew != pDevice->byBBVGACurrent) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"RSSI[%d] NewGain[%d] OldGain[%d] \n", + (int)pCurr->ldBmMAX, pDevice->byBBVGANew, pDevice->byBBVGACurrent); + printk("RSSI[%d] NewGain[%d] OldGain[%d] \n", + (int)pCurr->ldBmMAX, pDevice->byBBVGANew, pDevice->byBBVGACurrent); + BBvSetVGAGainOffset(pDevice, pDevice->byBBVGANew); + } + printk("ldBmMAX[%d] NewGain[%d] OldGain[%d] \n", + (int)pCurr->ldBmMAX, pDevice->byBBVGANew, pDevice->byBBVGACurrent); +*/ + pMgmt->uCurrChannel = pCurr->uChannel; + pMgmt->eCurrentPHYMode = ePhyType; + pMgmt->byERPContext = pCurr->sERP.byERP; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Sync:Set to channel = [%d]\n", (INT)pCurr->uChannel); + + + *pStatus = CMD_STATUS_SUCCESS; + + + return; +}; + +//mike add: fix NetworkManager 0.7.0 hidden ssid mode in WPA encryption +// ,need reset eAuthenMode and eEncryptionStatus + static VOID Encyption_Rebuild( + IN PSDevice pDevice, + IN PKnownBSS pCurr + ) + { + PSMgmtObject pMgmt = &(pDevice->sMgmtObj); + // UINT ii , uSameBssidNum=0; + + // for (ii = 0; ii < MAX_BSS_NUM; ii++) { + // if (pMgmt->sBSSList[ii].bActive && + // IS_ETH_ADDRESS_EQUAL(pMgmt->sBSSList[ii].abyBSSID, pCurr->abyBSSID)) { + // uSameBssidNum++; + // } + // } + // if( uSameBssidNum>=2) { //we only check AP in hidden sssid mode + if ((pMgmt->eAuthenMode == WMAC_AUTH_WPAPSK) || //networkmanager 0.7.0 does not give the pairwise-key selsection, + (pMgmt->eAuthenMode == WMAC_AUTH_WPA2PSK)) { // so we need re-selsect it according to real pairwise-key info. + if(pCurr->bWPAValid == TRUE) { //WPA-PSK + pMgmt->eAuthenMode = WMAC_AUTH_WPAPSK; + if(pCurr->abyPKType[0] == WPA_TKIP) { + pDevice->eEncryptionStatus = Ndis802_11Encryption2Enabled; //TKIP + printk("Encyption_Rebuild--->ssid reset config to [WPAPSK-TKIP]\n"); + } + else if(pCurr->abyPKType[0] == WPA_AESCCMP) { + pDevice->eEncryptionStatus = Ndis802_11Encryption3Enabled; //AES + printk("Encyption_Rebuild--->ssid reset config to [WPAPSK-AES]\n"); + } + } + else if(pCurr->bWPA2Valid == TRUE) { //WPA2-PSK + pMgmt->eAuthenMode = WMAC_AUTH_WPA2PSK; + if(pCurr->abyCSSPK[0] == WLAN_11i_CSS_TKIP) { + pDevice->eEncryptionStatus = Ndis802_11Encryption2Enabled; //TKIP + printk("Encyption_Rebuild--->ssid reset config to [WPA2PSK-TKIP]\n"); + } + else if(pCurr->abyCSSPK[0] == WLAN_11i_CSS_CCMP) { + pDevice->eEncryptionStatus = Ndis802_11Encryption3Enabled; //AES + printk("Encyption_Rebuild--->ssid reset config to [WPA2PSK-AES]\n"); + } + } + } + // } + return; + } + + +/*+ + * + * Routine Description: + * Format TIM field + * + * + * Return Value: + * VOID + * +-*/ + +static +VOID +s_vMgrFormatTIM( + IN PSMgmtObject pMgmt, + IN PWLAN_IE_TIM pTIM + ) +{ + BYTE byMask[8] = {1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80}; + BYTE byMap; + UINT ii, jj; + BOOL bStartFound = FALSE; + BOOL bMulticast = FALSE; + WORD wStartIndex = 0; + WORD wEndIndex = 0; + + + // Find size of partial virtual bitmap + for (ii = 0; ii < (MAX_NODE_NUM + 1); ii++) { + byMap = pMgmt->abyPSTxMap[ii]; + if (!ii) { + // Mask out the broadcast bit which is indicated separately. + bMulticast = (byMap & byMask[0]) != 0; + if(bMulticast) { + pMgmt->sNodeDBTable[0].bRxPSPoll = TRUE; + } + byMap = 0; + } + if (byMap) { + if (!bStartFound) { + bStartFound = TRUE; + wStartIndex = ii; + } + wEndIndex = ii; + } + }; + + + // Round start index down to nearest even number + wStartIndex &= ~BIT0; + + // Round end index up to nearest even number + wEndIndex = ((wEndIndex + 1) & ~BIT0); + + // Size of element payload + + pTIM->len = 3 + (wEndIndex - wStartIndex) + 1; + + // Fill in the Fixed parts of the TIM + pTIM->byDTIMCount = pMgmt->byDTIMCount; + pTIM->byDTIMPeriod = pMgmt->byDTIMPeriod; + pTIM->byBitMapCtl = (bMulticast ? TIM_MULTICAST_MASK : 0) | + (((wStartIndex >> 1) << 1) & TIM_BITMAPOFFSET_MASK); + + // Append variable part of TIM + + for (ii = wStartIndex, jj =0 ; ii <= wEndIndex; ii++, jj++) { + pTIM->byVirtBitMap[jj] = pMgmt->abyPSTxMap[ii]; + } + + // Aid = 0 don't used. + pTIM->byVirtBitMap[0] &= ~BIT0; +} + + +/*+ + * + * Routine Description: + * Constructs an Beacon frame( Ad-hoc mode) + * + * + * Return Value: + * PTR to frame; or NULL on allocation failue + * +-*/ + +static +PSTxMgmtPacket +s_MgrMakeBeacon( + IN PSDevice pDevice, + IN PSMgmtObject pMgmt, + IN WORD wCurrCapInfo, + IN WORD wCurrBeaconPeriod, + IN UINT uCurrChannel, + IN WORD wCurrATIMWinodw, + IN PWLAN_IE_SSID pCurrSSID, + IN PBYTE pCurrBSSID, + IN PWLAN_IE_SUPP_RATES pCurrSuppRates, + IN PWLAN_IE_SUPP_RATES pCurrExtSuppRates + ) +{ + PSTxMgmtPacket pTxPacket = NULL; + WLAN_FR_BEACON sFrame; + BYTE abyBroadcastAddr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + PBYTE pbyBuffer; + UINT uLength = 0; + PWLAN_IE_IBSS_DFS pIBSSDFS = NULL; + UINT ii; + + // prepare beacon frame + pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool; + memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_BEACON_FR_MAXLEN); + pTxPacket->p80211Header = (PUWLAN_80211HDR)((PBYTE)pTxPacket + sizeof(STxMgmtPacket)); + // Setup the sFrame structure. + sFrame.pBuf = (PBYTE)pTxPacket->p80211Header; + sFrame.len = WLAN_BEACON_FR_MAXLEN; + vMgrEncodeBeacon(&sFrame); + // Setup the header + sFrame.pHdr->sA3.wFrameCtl = cpu_to_le16( + ( + WLAN_SET_FC_FTYPE(WLAN_TYPE_MGR) | + WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_BEACON) + )); + + if (pDevice->bEnablePSMode) { + sFrame.pHdr->sA3.wFrameCtl |= cpu_to_le16((WORD)WLAN_SET_FC_PWRMGT(1)); + } + + memcpy( sFrame.pHdr->sA3.abyAddr1, abyBroadcastAddr, WLAN_ADDR_LEN); + memcpy( sFrame.pHdr->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN); + memcpy( sFrame.pHdr->sA3.abyAddr3, pCurrBSSID, WLAN_BSSID_LEN); + *sFrame.pwBeaconInterval = cpu_to_le16(wCurrBeaconPeriod); + *sFrame.pwCapInfo = cpu_to_le16(wCurrCapInfo); + // Copy SSID + sFrame.pSSID = (PWLAN_IE_SSID)(sFrame.pBuf + sFrame.len); + sFrame.len += ((PWLAN_IE_SSID)pMgmt->abyCurrSSID)->len + WLAN_IEHDR_LEN; + memcpy(sFrame.pSSID, + pCurrSSID, + ((PWLAN_IE_SSID)pCurrSSID)->len + WLAN_IEHDR_LEN + ); + // Copy the rate set + sFrame.pSuppRates = (PWLAN_IE_SUPP_RATES)(sFrame.pBuf + sFrame.len); + sFrame.len += ((PWLAN_IE_SUPP_RATES)pCurrSuppRates)->len + WLAN_IEHDR_LEN; + memcpy(sFrame.pSuppRates, + pCurrSuppRates, + ((PWLAN_IE_SUPP_RATES)pCurrSuppRates)->len + WLAN_IEHDR_LEN + ); + // DS parameter + if (pDevice->eCurrentPHYType != PHY_TYPE_11A) { + sFrame.pDSParms = (PWLAN_IE_DS_PARMS)(sFrame.pBuf + sFrame.len); + sFrame.len += (1) + WLAN_IEHDR_LEN; + sFrame.pDSParms->byElementID = WLAN_EID_DS_PARMS; + sFrame.pDSParms->len = 1; + sFrame.pDSParms->byCurrChannel = (BYTE)uCurrChannel; + } + // TIM field + if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) { + sFrame.pTIM = (PWLAN_IE_TIM)(sFrame.pBuf + sFrame.len); + sFrame.pTIM->byElementID = WLAN_EID_TIM; + s_vMgrFormatTIM(pMgmt, sFrame.pTIM); + sFrame.len += (WLAN_IEHDR_LEN + sFrame.pTIM->len); + } + + if (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) { + + // IBSS parameter + sFrame.pIBSSParms = (PWLAN_IE_IBSS_PARMS)(sFrame.pBuf + sFrame.len); + sFrame.len += (2) + WLAN_IEHDR_LEN; + sFrame.pIBSSParms->byElementID = WLAN_EID_IBSS_PARMS; + sFrame.pIBSSParms->len = 2; + sFrame.pIBSSParms->wATIMWindow = wCurrATIMWinodw; + if (pMgmt->eAuthenMode == WMAC_AUTH_WPANONE) { + /* RSN parameter */ + sFrame.pRSNWPA = (PWLAN_IE_RSN_EXT)(sFrame.pBuf + sFrame.len); + sFrame.pRSNWPA->byElementID = WLAN_EID_RSN_WPA; + sFrame.pRSNWPA->len = 12; + sFrame.pRSNWPA->abyOUI[0] = 0x00; + sFrame.pRSNWPA->abyOUI[1] = 0x50; + sFrame.pRSNWPA->abyOUI[2] = 0xf2; + sFrame.pRSNWPA->abyOUI[3] = 0x01; + sFrame.pRSNWPA->wVersion = 1; + sFrame.pRSNWPA->abyMulticast[0] = 0x00; + sFrame.pRSNWPA->abyMulticast[1] = 0x50; + sFrame.pRSNWPA->abyMulticast[2] = 0xf2; + if (pDevice->eEncryptionStatus == Ndis802_11Encryption3Enabled) + sFrame.pRSNWPA->abyMulticast[3] = 0x04;//AES + else if (pDevice->eEncryptionStatus == Ndis802_11Encryption2Enabled) + sFrame.pRSNWPA->abyMulticast[3] = 0x02;//TKIP + else if (pDevice->eEncryptionStatus == Ndis802_11Encryption1Enabled) + sFrame.pRSNWPA->abyMulticast[3] = 0x01;//WEP40 + else + sFrame.pRSNWPA->abyMulticast[3] = 0x00;//NONE + + // Pairwise Key Cipher Suite + sFrame.pRSNWPA->wPKCount = 0; + // Auth Key Management Suite + *((PWORD)(sFrame.pBuf + sFrame.len + sFrame.pRSNWPA->len))=0; + sFrame.pRSNWPA->len +=2; + + // RSN Capabilites + *((PWORD)(sFrame.pBuf + sFrame.len + sFrame.pRSNWPA->len))=0; + sFrame.pRSNWPA->len +=2; + sFrame.len += sFrame.pRSNWPA->len + WLAN_IEHDR_LEN; + } + } + + if ((pMgmt->b11hEnable == TRUE) && + (pMgmt->eCurrentPHYMode == PHY_TYPE_11A)) { + // Country IE + pbyBuffer = (PBYTE)(sFrame.pBuf + sFrame.len); + CARDvSetCountryIE(pMgmt->pAdapter, pbyBuffer); + CARDvSetCountryInfo(pMgmt->pAdapter, PHY_TYPE_11A, pbyBuffer); + uLength += ((PWLAN_IE_COUNTRY) pbyBuffer)->len + WLAN_IEHDR_LEN; + pbyBuffer += (((PWLAN_IE_COUNTRY) pbyBuffer)->len + WLAN_IEHDR_LEN); + // Power Constrain IE + ((PWLAN_IE_PW_CONST) pbyBuffer)->byElementID = WLAN_EID_PWR_CONSTRAINT; + ((PWLAN_IE_PW_CONST) pbyBuffer)->len = 1; + ((PWLAN_IE_PW_CONST) pbyBuffer)->byPower = 0; + pbyBuffer += (1) + WLAN_IEHDR_LEN; + uLength += (1) + WLAN_IEHDR_LEN; + if (pMgmt->bSwitchChannel == TRUE) { + // Channel Switch IE + ((PWLAN_IE_CH_SW) pbyBuffer)->byElementID = WLAN_EID_CH_SWITCH; + ((PWLAN_IE_CH_SW) pbyBuffer)->len = 3; + ((PWLAN_IE_CH_SW) pbyBuffer)->byMode = 1; + ((PWLAN_IE_CH_SW) pbyBuffer)->byChannel = CARDbyGetChannelNumber(pMgmt->pAdapter, pMgmt->byNewChannel); + ((PWLAN_IE_CH_SW) pbyBuffer)->byCount = 0; + pbyBuffer += (3) + WLAN_IEHDR_LEN; + uLength += (3) + WLAN_IEHDR_LEN; + } + // TPC report + ((PWLAN_IE_TPC_REP) pbyBuffer)->byElementID = WLAN_EID_TPC_REP; + ((PWLAN_IE_TPC_REP) pbyBuffer)->len = 2; + ((PWLAN_IE_TPC_REP) pbyBuffer)->byTxPower = CARDbyGetTransmitPower(pMgmt->pAdapter); + ((PWLAN_IE_TPC_REP) pbyBuffer)->byLinkMargin = 0; + pbyBuffer += (2) + WLAN_IEHDR_LEN; + uLength += (2) + WLAN_IEHDR_LEN; + // IBSS DFS + if (pMgmt->eCurrMode != WMAC_MODE_ESS_AP) { + pIBSSDFS = (PWLAN_IE_IBSS_DFS) pbyBuffer; + pIBSSDFS->byElementID = WLAN_EID_IBSS_DFS; + pIBSSDFS->len = 7; + MEMvCopy( pIBSSDFS->abyDFSOwner, + pMgmt->abyIBSSDFSOwner, + 6); + pIBSSDFS->byDFSRecovery = pMgmt->byIBSSDFSRecovery; + pbyBuffer += (7) + WLAN_IEHDR_LEN; + uLength += (7) + WLAN_IEHDR_LEN; + for(ii=CB_MAX_CHANNEL_24G+1; ii<=CB_MAX_CHANNEL; ii++ ) { + if (CARDbGetChannelMapInfo(pMgmt->pAdapter, ii, pbyBuffer, pbyBuffer+1) == TRUE) { + pbyBuffer += 2; + uLength += 2; + pIBSSDFS->len += 2; + } + } + } + sFrame.len += uLength; + } + + if (pMgmt->eCurrentPHYMode == PHY_TYPE_11G) { + sFrame.pERP = (PWLAN_IE_ERP)(sFrame.pBuf + sFrame.len); + sFrame.len += 1 + WLAN_IEHDR_LEN; + sFrame.pERP->byElementID = WLAN_EID_ERP; + sFrame.pERP->len = 1; + sFrame.pERP->byContext = 0; + if (pDevice->bProtectMode == TRUE) + sFrame.pERP->byContext |= WLAN_EID_ERP_USE_PROTECTION; + if (pDevice->bNonERPPresent == TRUE) + sFrame.pERP->byContext |= WLAN_EID_ERP_NONERP_PRESENT; + if (pDevice->bBarkerPreambleMd == TRUE) + sFrame.pERP->byContext |= WLAN_EID_ERP_BARKER_MODE; + } + if (((PWLAN_IE_SUPP_RATES)pCurrExtSuppRates)->len != 0) { + sFrame.pExtSuppRates = (PWLAN_IE_SUPP_RATES)(sFrame.pBuf + sFrame.len); + sFrame.len += ((PWLAN_IE_SUPP_RATES)pCurrExtSuppRates)->len + WLAN_IEHDR_LEN; + MEMvCopy(sFrame.pExtSuppRates, + pCurrExtSuppRates, + ((PWLAN_IE_SUPP_RATES)pCurrExtSuppRates)->len + WLAN_IEHDR_LEN + ); + } + // hostapd wpa/wpa2 IE + if ((pMgmt->eCurrMode == WMAC_MODE_ESS_AP) && (pDevice->bEnableHostapd == TRUE)) { + if (pMgmt->eAuthenMode == WMAC_AUTH_WPANONE) { + if (pMgmt->wWPAIELen != 0) { + sFrame.pRSN = (PWLAN_IE_RSN)(sFrame.pBuf + sFrame.len); + memcpy(sFrame.pRSN, pMgmt->abyWPAIE, pMgmt->wWPAIELen); + sFrame.len += pMgmt->wWPAIELen; + } + } + } + + /* Adjust the length fields */ + pTxPacket->cbMPDULen = sFrame.len; + pTxPacket->cbPayloadLen = sFrame.len - WLAN_HDR_ADDR3_LEN; + + return pTxPacket; +} + + + + + +/*+ + * + * Routine Description: + * Constructs an Prob-response frame + * + * + * Return Value: + * PTR to frame; or NULL on allocation failue + * +-*/ + + + + +PSTxMgmtPacket +s_MgrMakeProbeResponse( + IN PSDevice pDevice, + IN PSMgmtObject pMgmt, + IN WORD wCurrCapInfo, + IN WORD wCurrBeaconPeriod, + IN UINT uCurrChannel, + IN WORD wCurrATIMWinodw, + IN PBYTE pDstAddr, + IN PWLAN_IE_SSID pCurrSSID, + IN PBYTE pCurrBSSID, + IN PWLAN_IE_SUPP_RATES pCurrSuppRates, + IN PWLAN_IE_SUPP_RATES pCurrExtSuppRates, + IN BYTE byPHYType + ) +{ + PSTxMgmtPacket pTxPacket = NULL; + WLAN_FR_PROBERESP sFrame; + PBYTE pbyBuffer; + UINT uLength = 0; + PWLAN_IE_IBSS_DFS pIBSSDFS = NULL; + UINT ii; + + + pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool; + memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_PROBERESP_FR_MAXLEN); + pTxPacket->p80211Header = (PUWLAN_80211HDR)((PBYTE)pTxPacket + sizeof(STxMgmtPacket)); + // Setup the sFrame structure. + sFrame.pBuf = (PBYTE)pTxPacket->p80211Header; + sFrame.len = WLAN_PROBERESP_FR_MAXLEN; + vMgrEncodeProbeResponse(&sFrame); + // Setup the header + sFrame.pHdr->sA3.wFrameCtl = cpu_to_le16( + ( + WLAN_SET_FC_FTYPE(WLAN_TYPE_MGR) | + WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_PROBERESP) + )); + memcpy( sFrame.pHdr->sA3.abyAddr1, pDstAddr, WLAN_ADDR_LEN); + memcpy( sFrame.pHdr->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN); + memcpy( sFrame.pHdr->sA3.abyAddr3, pCurrBSSID, WLAN_BSSID_LEN); + *sFrame.pwBeaconInterval = cpu_to_le16(wCurrBeaconPeriod); + *sFrame.pwCapInfo = cpu_to_le16(wCurrCapInfo); + + if (byPHYType == BB_TYPE_11B) { + *sFrame.pwCapInfo &= cpu_to_le16((WORD)~(WLAN_SET_CAP_INFO_SHORTSLOTTIME(1))); + } + + // Copy SSID + sFrame.pSSID = (PWLAN_IE_SSID)(sFrame.pBuf + sFrame.len); + sFrame.len += ((PWLAN_IE_SSID)pMgmt->abyCurrSSID)->len + WLAN_IEHDR_LEN; + memcpy(sFrame.pSSID, + pCurrSSID, + ((PWLAN_IE_SSID)pCurrSSID)->len + WLAN_IEHDR_LEN + ); + // Copy the rate set + sFrame.pSuppRates = (PWLAN_IE_SUPP_RATES)(sFrame.pBuf + sFrame.len); + + sFrame.len += ((PWLAN_IE_SUPP_RATES)pCurrSuppRates)->len + WLAN_IEHDR_LEN; + memcpy(sFrame.pSuppRates, + pCurrSuppRates, + ((PWLAN_IE_SUPP_RATES)pCurrSuppRates)->len + WLAN_IEHDR_LEN + ); + + // DS parameter + if (pDevice->eCurrentPHYType != PHY_TYPE_11A) { + sFrame.pDSParms = (PWLAN_IE_DS_PARMS)(sFrame.pBuf + sFrame.len); + sFrame.len += (1) + WLAN_IEHDR_LEN; + sFrame.pDSParms->byElementID = WLAN_EID_DS_PARMS; + sFrame.pDSParms->len = 1; + sFrame.pDSParms->byCurrChannel = (BYTE)uCurrChannel; + } + + if (pMgmt->eCurrMode != WMAC_MODE_ESS_AP) { + // IBSS parameter + sFrame.pIBSSParms = (PWLAN_IE_IBSS_PARMS)(sFrame.pBuf + sFrame.len); + sFrame.len += (2) + WLAN_IEHDR_LEN; + sFrame.pIBSSParms->byElementID = WLAN_EID_IBSS_PARMS; + sFrame.pIBSSParms->len = 2; + sFrame.pIBSSParms->wATIMWindow = 0; + } + if (pDevice->eCurrentPHYType == PHY_TYPE_11G) { + sFrame.pERP = (PWLAN_IE_ERP)(sFrame.pBuf + sFrame.len); + sFrame.len += 1 + WLAN_IEHDR_LEN; + sFrame.pERP->byElementID = WLAN_EID_ERP; + sFrame.pERP->len = 1; + sFrame.pERP->byContext = 0; + if (pDevice->bProtectMode == TRUE) + sFrame.pERP->byContext |= WLAN_EID_ERP_USE_PROTECTION; + if (pDevice->bNonERPPresent == TRUE) + sFrame.pERP->byContext |= WLAN_EID_ERP_NONERP_PRESENT; + if (pDevice->bBarkerPreambleMd == TRUE) + sFrame.pERP->byContext |= WLAN_EID_ERP_BARKER_MODE; + } + + if ((pMgmt->b11hEnable == TRUE) && + (pMgmt->eCurrentPHYMode == PHY_TYPE_11A)) { + // Country IE + pbyBuffer = (PBYTE)(sFrame.pBuf + sFrame.len); + CARDvSetCountryIE(pMgmt->pAdapter, pbyBuffer); + CARDvSetCountryInfo(pMgmt->pAdapter, PHY_TYPE_11A, pbyBuffer); + uLength += ((PWLAN_IE_COUNTRY) pbyBuffer)->len + WLAN_IEHDR_LEN; + pbyBuffer += (((PWLAN_IE_COUNTRY) pbyBuffer)->len + WLAN_IEHDR_LEN); + // Power Constrain IE + ((PWLAN_IE_PW_CONST) pbyBuffer)->byElementID = WLAN_EID_PWR_CONSTRAINT; + ((PWLAN_IE_PW_CONST) pbyBuffer)->len = 1; + ((PWLAN_IE_PW_CONST) pbyBuffer)->byPower = 0; + pbyBuffer += (1) + WLAN_IEHDR_LEN; + uLength += (1) + WLAN_IEHDR_LEN; + if (pMgmt->bSwitchChannel == TRUE) { + // Channel Switch IE + ((PWLAN_IE_CH_SW) pbyBuffer)->byElementID = WLAN_EID_CH_SWITCH; + ((PWLAN_IE_CH_SW) pbyBuffer)->len = 3; + ((PWLAN_IE_CH_SW) pbyBuffer)->byMode = 1; + ((PWLAN_IE_CH_SW) pbyBuffer)->byChannel = CARDbyGetChannelNumber(pMgmt->pAdapter, pMgmt->byNewChannel); + ((PWLAN_IE_CH_SW) pbyBuffer)->byCount = 0; + pbyBuffer += (3) + WLAN_IEHDR_LEN; + uLength += (3) + WLAN_IEHDR_LEN; + } + // TPC report + ((PWLAN_IE_TPC_REP) pbyBuffer)->byElementID = WLAN_EID_TPC_REP; + ((PWLAN_IE_TPC_REP) pbyBuffer)->len = 2; + ((PWLAN_IE_TPC_REP) pbyBuffer)->byTxPower = CARDbyGetTransmitPower(pMgmt->pAdapter); + ((PWLAN_IE_TPC_REP) pbyBuffer)->byLinkMargin = 0; + pbyBuffer += (2) + WLAN_IEHDR_LEN; + uLength += (2) + WLAN_IEHDR_LEN; + // IBSS DFS + if (pMgmt->eCurrMode != WMAC_MODE_ESS_AP) { + pIBSSDFS = (PWLAN_IE_IBSS_DFS) pbyBuffer; + pIBSSDFS->byElementID = WLAN_EID_IBSS_DFS; + pIBSSDFS->len = 7; + MEMvCopy( pIBSSDFS->abyDFSOwner, + pMgmt->abyIBSSDFSOwner, + 6); + pIBSSDFS->byDFSRecovery = pMgmt->byIBSSDFSRecovery; + pbyBuffer += (7) + WLAN_IEHDR_LEN; + uLength += (7) + WLAN_IEHDR_LEN; + for(ii=CB_MAX_CHANNEL_24G+1; ii<=CB_MAX_CHANNEL; ii++ ) { + if (CARDbGetChannelMapInfo(pMgmt->pAdapter, ii, pbyBuffer, pbyBuffer+1) == TRUE) { + pbyBuffer += 2; + uLength += 2; + pIBSSDFS->len += 2; + } + } + } + sFrame.len += uLength; + } + + + if (((PWLAN_IE_SUPP_RATES)pCurrExtSuppRates)->len != 0) { + sFrame.pExtSuppRates = (PWLAN_IE_SUPP_RATES)(sFrame.pBuf + sFrame.len); + sFrame.len += ((PWLAN_IE_SUPP_RATES)pCurrExtSuppRates)->len + WLAN_IEHDR_LEN; + MEMvCopy(sFrame.pExtSuppRates, + pCurrExtSuppRates, + ((PWLAN_IE_SUPP_RATES)pCurrExtSuppRates)->len + WLAN_IEHDR_LEN + ); + } + + // hostapd wpa/wpa2 IE + if ((pMgmt->eCurrMode == WMAC_MODE_ESS_AP) && (pDevice->bEnableHostapd == TRUE)) { + if (pMgmt->eAuthenMode == WMAC_AUTH_WPANONE) { + if (pMgmt->wWPAIELen != 0) { + sFrame.pRSN = (PWLAN_IE_RSN)(sFrame.pBuf + sFrame.len); + memcpy(sFrame.pRSN, pMgmt->abyWPAIE, pMgmt->wWPAIELen); + sFrame.len += pMgmt->wWPAIELen; + } + } + } + + // Adjust the length fields + pTxPacket->cbMPDULen = sFrame.len; + pTxPacket->cbPayloadLen = sFrame.len - WLAN_HDR_ADDR3_LEN; + + return pTxPacket; +} + + + +/*+ + * + * Routine Description: + * Constructs an association request frame + * + * + * Return Value: + * A ptr to frame or NULL on allocation failue + * +-*/ + + +PSTxMgmtPacket +s_MgrMakeAssocRequest( + IN PSDevice pDevice, + IN PSMgmtObject pMgmt, + IN PBYTE pDAddr, + IN WORD wCurrCapInfo, + IN WORD wListenInterval, + IN PWLAN_IE_SSID pCurrSSID, + IN PWLAN_IE_SUPP_RATES pCurrRates, + IN PWLAN_IE_SUPP_RATES pCurrExtSuppRates + ) +{ + PSTxMgmtPacket pTxPacket = NULL; + WLAN_FR_ASSOCREQ sFrame; + PBYTE pbyIEs; + PBYTE pbyRSN; + + + pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool; + memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_ASSOCREQ_FR_MAXLEN); + pTxPacket->p80211Header = (PUWLAN_80211HDR)((PBYTE)pTxPacket + sizeof(STxMgmtPacket)); + // Setup the sFrame structure. + sFrame.pBuf = (PBYTE)pTxPacket->p80211Header; + sFrame.len = WLAN_ASSOCREQ_FR_MAXLEN; + // format fixed field frame structure + vMgrEncodeAssocRequest(&sFrame); + // Setup the header + sFrame.pHdr->sA3.wFrameCtl = cpu_to_le16( + ( + WLAN_SET_FC_FTYPE(WLAN_TYPE_MGR) | + WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_ASSOCREQ) + )); + memcpy( sFrame.pHdr->sA3.abyAddr1, pDAddr, WLAN_ADDR_LEN); + memcpy( sFrame.pHdr->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN); + memcpy( sFrame.pHdr->sA3.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN); + + // Set the capibility and listen interval + *(sFrame.pwCapInfo) = cpu_to_le16(wCurrCapInfo); + *(sFrame.pwListenInterval) = cpu_to_le16(wListenInterval); + + // sFrame.len point to end of fixed field + sFrame.pSSID = (PWLAN_IE_SSID)(sFrame.pBuf + sFrame.len); + sFrame.len += pCurrSSID->len + WLAN_IEHDR_LEN; + memcpy(sFrame.pSSID, pCurrSSID, pCurrSSID->len + WLAN_IEHDR_LEN); + + pMgmt->sAssocInfo.AssocInfo.RequestIELength = pCurrSSID->len + WLAN_IEHDR_LEN; + pMgmt->sAssocInfo.AssocInfo.OffsetRequestIEs = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION); + pbyIEs = pMgmt->sAssocInfo.abyIEs; + MEMvCopy(pbyIEs, pCurrSSID, pCurrSSID->len + WLAN_IEHDR_LEN); + pbyIEs += pCurrSSID->len + WLAN_IEHDR_LEN; + + // Copy the rate set + sFrame.pSuppRates = (PWLAN_IE_SUPP_RATES)(sFrame.pBuf + sFrame.len); + if ((pDevice->eCurrentPHYType == PHY_TYPE_11B) && (pCurrRates->len > 4)) + sFrame.len += 4 + WLAN_IEHDR_LEN; + else + sFrame.len += pCurrRates->len + WLAN_IEHDR_LEN; + memcpy(sFrame.pSuppRates, pCurrRates, pCurrRates->len + WLAN_IEHDR_LEN); + + // Copy the extension rate set + if ((pDevice->eCurrentPHYType == PHY_TYPE_11G) && (pCurrExtSuppRates->len > 0)) { + sFrame.pExtSuppRates = (PWLAN_IE_SUPP_RATES)(sFrame.pBuf + sFrame.len); + sFrame.len += pCurrExtSuppRates->len + WLAN_IEHDR_LEN; + memcpy(sFrame.pExtSuppRates, pCurrExtSuppRates, pCurrExtSuppRates->len + WLAN_IEHDR_LEN); + } + + pMgmt->sAssocInfo.AssocInfo.RequestIELength += pCurrRates->len + WLAN_IEHDR_LEN; + MEMvCopy(pbyIEs, pCurrRates, pCurrRates->len + WLAN_IEHDR_LEN); + pbyIEs += pCurrRates->len + WLAN_IEHDR_LEN; + + // for 802.11h + if (pMgmt->b11hEnable == TRUE) { + if (sFrame.pCurrPowerCap == NULL) { + sFrame.pCurrPowerCap = (PWLAN_IE_PW_CAP)(sFrame.pBuf + sFrame.len); + sFrame.len += (2 + WLAN_IEHDR_LEN); + sFrame.pCurrPowerCap->byElementID = WLAN_EID_PWR_CAPABILITY; + sFrame.pCurrPowerCap->len = 2; + CARDvGetPowerCapability(pMgmt->pAdapter, + &(sFrame.pCurrPowerCap->byMinPower), + &(sFrame.pCurrPowerCap->byMaxPower) + ); + } + if (sFrame.pCurrSuppCh == NULL) { + sFrame.pCurrSuppCh = (PWLAN_IE_SUPP_CH)(sFrame.pBuf + sFrame.len); + sFrame.len += CARDbySetSupportChannels(pMgmt->pAdapter,(PBYTE)sFrame.pCurrSuppCh); + } + } + + if (((pMgmt->eAuthenMode == WMAC_AUTH_WPA) || + (pMgmt->eAuthenMode == WMAC_AUTH_WPAPSK) || + (pMgmt->eAuthenMode == WMAC_AUTH_WPANONE)) && + (pMgmt->pCurrBSS != NULL)) { + /* WPA IE */ + sFrame.pRSNWPA = (PWLAN_IE_RSN_EXT)(sFrame.pBuf + sFrame.len); + sFrame.pRSNWPA->byElementID = WLAN_EID_RSN_WPA; + sFrame.pRSNWPA->len = 16; + sFrame.pRSNWPA->abyOUI[0] = 0x00; + sFrame.pRSNWPA->abyOUI[1] = 0x50; + sFrame.pRSNWPA->abyOUI[2] = 0xf2; + sFrame.pRSNWPA->abyOUI[3] = 0x01; + sFrame.pRSNWPA->wVersion = 1; + //Group Key Cipher Suite + sFrame.pRSNWPA->abyMulticast[0] = 0x00; + sFrame.pRSNWPA->abyMulticast[1] = 0x50; + sFrame.pRSNWPA->abyMulticast[2] = 0xf2; + if (pMgmt->byCSSGK == KEY_CTL_WEP) { + sFrame.pRSNWPA->abyMulticast[3] = pMgmt->pCurrBSS->byGKType; + } else if (pMgmt->byCSSGK == KEY_CTL_TKIP) { + sFrame.pRSNWPA->abyMulticast[3] = WPA_TKIP; + } else if (pMgmt->byCSSGK == KEY_CTL_CCMP) { + sFrame.pRSNWPA->abyMulticast[3] = WPA_AESCCMP; + } else { + sFrame.pRSNWPA->abyMulticast[3] = WPA_NONE; + } + // Pairwise Key Cipher Suite + sFrame.pRSNWPA->wPKCount = 1; + sFrame.pRSNWPA->PKSList[0].abyOUI[0] = 0x00; + sFrame.pRSNWPA->PKSList[0].abyOUI[1] = 0x50; + sFrame.pRSNWPA->PKSList[0].abyOUI[2] = 0xf2; + if (pMgmt->byCSSPK == KEY_CTL_TKIP) { + sFrame.pRSNWPA->PKSList[0].abyOUI[3] = WPA_TKIP; + } else if (pMgmt->byCSSPK == KEY_CTL_CCMP) { + sFrame.pRSNWPA->PKSList[0].abyOUI[3] = WPA_AESCCMP; + } else { + sFrame.pRSNWPA->PKSList[0].abyOUI[3] = WPA_NONE; + } + // Auth Key Management Suite + pbyRSN = (PBYTE)(sFrame.pBuf + sFrame.len + 2 + sFrame.pRSNWPA->len); + *pbyRSN++=0x01; + *pbyRSN++=0x00; + *pbyRSN++=0x00; + *pbyRSN++=0x50; + *pbyRSN++=0xf2; + if (pMgmt->eAuthenMode == WMAC_AUTH_WPAPSK) { + *pbyRSN++=WPA_AUTH_PSK; + } + else if (pMgmt->eAuthenMode == WMAC_AUTH_WPA) { + *pbyRSN++=WPA_AUTH_IEEE802_1X; + } + else { + *pbyRSN++=WPA_NONE; + } + sFrame.pRSNWPA->len +=6; + + // RSN Capabilites + *pbyRSN++=0x00; + *pbyRSN++=0x00; + sFrame.pRSNWPA->len +=2; + sFrame.len += sFrame.pRSNWPA->len + WLAN_IEHDR_LEN; + // copy to AssocInfo. for OID_802_11_ASSOCIATION_INFORMATION + pMgmt->sAssocInfo.AssocInfo.RequestIELength += sFrame.pRSNWPA->len + WLAN_IEHDR_LEN; + MEMvCopy(pbyIEs, sFrame.pRSNWPA, sFrame.pRSNWPA->len + WLAN_IEHDR_LEN); + pbyIEs += sFrame.pRSNWPA->len + WLAN_IEHDR_LEN; + + } else if (((pMgmt->eAuthenMode == WMAC_AUTH_WPA2) || + (pMgmt->eAuthenMode == WMAC_AUTH_WPA2PSK)) && + (pMgmt->pCurrBSS != NULL)) { + UINT ii; + PWORD pwPMKID; + + // WPA IE + sFrame.pRSN = (PWLAN_IE_RSN)(sFrame.pBuf + sFrame.len); + sFrame.pRSN->byElementID = WLAN_EID_RSN; + sFrame.pRSN->len = 6; //Version(2)+GK(4) + sFrame.pRSN->wVersion = 1; + //Group Key Cipher Suite + sFrame.pRSN->abyRSN[0] = 0x00; + sFrame.pRSN->abyRSN[1] = 0x0F; + sFrame.pRSN->abyRSN[2] = 0xAC; + if (pMgmt->byCSSGK == KEY_CTL_WEP) { + sFrame.pRSN->abyRSN[3] = pMgmt->pCurrBSS->byCSSGK; + } else if (pMgmt->byCSSGK == KEY_CTL_TKIP) { + sFrame.pRSN->abyRSN[3] = WLAN_11i_CSS_TKIP; + } else if (pMgmt->byCSSGK == KEY_CTL_CCMP) { + sFrame.pRSN->abyRSN[3] = WLAN_11i_CSS_CCMP; + } else { + sFrame.pRSN->abyRSN[3] = WLAN_11i_CSS_UNKNOWN; + } + + // Pairwise Key Cipher Suite + sFrame.pRSN->abyRSN[4] = 1; + sFrame.pRSN->abyRSN[5] = 0; + sFrame.pRSN->abyRSN[6] = 0x00; + sFrame.pRSN->abyRSN[7] = 0x0F; + sFrame.pRSN->abyRSN[8] = 0xAC; + if (pMgmt->byCSSPK == KEY_CTL_TKIP) { + sFrame.pRSN->abyRSN[9] = WLAN_11i_CSS_TKIP; + } else if (pMgmt->byCSSPK == KEY_CTL_CCMP) { + sFrame.pRSN->abyRSN[9] = WLAN_11i_CSS_CCMP; + } else if (pMgmt->byCSSPK == KEY_CTL_NONE) { + sFrame.pRSN->abyRSN[9] = WLAN_11i_CSS_USE_GROUP; + } else { + sFrame.pRSN->abyRSN[9] = WLAN_11i_CSS_UNKNOWN; + } + sFrame.pRSN->len += 6; + + // Auth Key Management Suite + sFrame.pRSN->abyRSN[10] = 1; + sFrame.pRSN->abyRSN[11] = 0; + sFrame.pRSN->abyRSN[12] = 0x00; + sFrame.pRSN->abyRSN[13] = 0x0F; + sFrame.pRSN->abyRSN[14] = 0xAC; + if (pMgmt->eAuthenMode == WMAC_AUTH_WPA2PSK) { + sFrame.pRSN->abyRSN[15] = WLAN_11i_AKMSS_PSK; + } else if (pMgmt->eAuthenMode == WMAC_AUTH_WPA2) { + sFrame.pRSN->abyRSN[15] = WLAN_11i_AKMSS_802_1X; + } else { + sFrame.pRSN->abyRSN[15] = WLAN_11i_AKMSS_UNKNOWN; + } + sFrame.pRSN->len +=6; + + // RSN Capabilites + if (pMgmt->pCurrBSS->sRSNCapObj.bRSNCapExist == TRUE) { + MEMvCopy(&sFrame.pRSN->abyRSN[16], &pMgmt->pCurrBSS->sRSNCapObj.wRSNCap, 2); + } else { + sFrame.pRSN->abyRSN[16] = 0; + sFrame.pRSN->abyRSN[17] = 0; + } + sFrame.pRSN->len +=2; + + if ((pDevice->gsPMKID.BSSIDInfoCount > 0) && (pDevice->bRoaming == TRUE) && (pMgmt->eAuthenMode == WMAC_AUTH_WPA2)) { + // RSN PMKID + pbyRSN = &sFrame.pRSN->abyRSN[18]; + pwPMKID = (PWORD)pbyRSN; // Point to PMKID count + *pwPMKID = 0; // Initialize PMKID count + pbyRSN += 2; // Point to PMKID list + for (ii = 0; ii < pDevice->gsPMKID.BSSIDInfoCount; ii++) { + if (MEMEqualMemory(&pDevice->gsPMKID.BSSIDInfo[ii].BSSID[0], pMgmt->abyCurrBSSID, U_ETHER_ADDR_LEN)) { + (*pwPMKID) ++; + MEMvCopy(pbyRSN, pDevice->gsPMKID.BSSIDInfo[ii].PMKID, 16); + pbyRSN += 16; + } + } + if (*pwPMKID != 0) { + sFrame.pRSN->len += (2 + (*pwPMKID)*16); + } + } + + sFrame.len += sFrame.pRSN->len + WLAN_IEHDR_LEN; + // copy to AssocInfo. for OID_802_11_ASSOCIATION_INFORMATION + pMgmt->sAssocInfo.AssocInfo.RequestIELength += sFrame.pRSN->len + WLAN_IEHDR_LEN; + MEMvCopy(pbyIEs, sFrame.pRSN, sFrame.pRSN->len + WLAN_IEHDR_LEN); + pbyIEs += sFrame.pRSN->len + WLAN_IEHDR_LEN; + } + + + // Adjust the length fields + pTxPacket->cbMPDULen = sFrame.len; + pTxPacket->cbPayloadLen = sFrame.len - WLAN_HDR_ADDR3_LEN; + return pTxPacket; +} + + + + + + + + +/*+ + * + * Routine Description: + * Constructs an re-association request frame + * + * + * Return Value: + * A ptr to frame or NULL on allocation failue + * +-*/ + + +PSTxMgmtPacket +s_MgrMakeReAssocRequest( + IN PSDevice pDevice, + IN PSMgmtObject pMgmt, + IN PBYTE pDAddr, + IN WORD wCurrCapInfo, + IN WORD wListenInterval, + IN PWLAN_IE_SSID pCurrSSID, + IN PWLAN_IE_SUPP_RATES pCurrRates, + IN PWLAN_IE_SUPP_RATES pCurrExtSuppRates + ) +{ + PSTxMgmtPacket pTxPacket = NULL; + WLAN_FR_REASSOCREQ sFrame; + PBYTE pbyIEs; + PBYTE pbyRSN; + + + pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool; + memset( pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_REASSOCREQ_FR_MAXLEN); + pTxPacket->p80211Header = (PUWLAN_80211HDR)((PBYTE)pTxPacket + sizeof(STxMgmtPacket)); + /* Setup the sFrame structure. */ + sFrame.pBuf = (PBYTE)pTxPacket->p80211Header; + sFrame.len = WLAN_REASSOCREQ_FR_MAXLEN; + + // format fixed field frame structure + vMgrEncodeReassocRequest(&sFrame); + + /* Setup the header */ + sFrame.pHdr->sA3.wFrameCtl = cpu_to_le16( + ( + WLAN_SET_FC_FTYPE(WLAN_TYPE_MGR) | + WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_REASSOCREQ) + )); + memcpy( sFrame.pHdr->sA3.abyAddr1, pDAddr, WLAN_ADDR_LEN); + memcpy( sFrame.pHdr->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN); + memcpy( sFrame.pHdr->sA3.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN); + + /* Set the capibility and listen interval */ + *(sFrame.pwCapInfo) = cpu_to_le16(wCurrCapInfo); + *(sFrame.pwListenInterval) = cpu_to_le16(wListenInterval); + + memcpy(sFrame.pAddrCurrAP, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN); + /* Copy the SSID */ + /* sFrame.len point to end of fixed field */ + sFrame.pSSID = (PWLAN_IE_SSID)(sFrame.pBuf + sFrame.len); + sFrame.len += pCurrSSID->len + WLAN_IEHDR_LEN; + memcpy(sFrame.pSSID, pCurrSSID, pCurrSSID->len + WLAN_IEHDR_LEN); + + pMgmt->sAssocInfo.AssocInfo.RequestIELength = pCurrSSID->len + WLAN_IEHDR_LEN; + pMgmt->sAssocInfo.AssocInfo.OffsetRequestIEs = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION); + pbyIEs = pMgmt->sAssocInfo.abyIEs; + MEMvCopy(pbyIEs, pCurrSSID, pCurrSSID->len + WLAN_IEHDR_LEN); + pbyIEs += pCurrSSID->len + WLAN_IEHDR_LEN; + + /* Copy the rate set */ + /* sFrame.len point to end of SSID */ + sFrame.pSuppRates = (PWLAN_IE_SUPP_RATES)(sFrame.pBuf + sFrame.len); + sFrame.len += pCurrRates->len + WLAN_IEHDR_LEN; + memcpy(sFrame.pSuppRates, pCurrRates, pCurrRates->len + WLAN_IEHDR_LEN); + + // Copy the extension rate set + if ((pMgmt->eCurrentPHYMode == PHY_TYPE_11G) && (pCurrExtSuppRates->len > 0)) { + sFrame.pExtSuppRates = (PWLAN_IE_SUPP_RATES)(sFrame.pBuf + sFrame.len); + sFrame.len += pCurrExtSuppRates->len + WLAN_IEHDR_LEN; + memcpy(sFrame.pExtSuppRates, pCurrExtSuppRates, pCurrExtSuppRates->len + WLAN_IEHDR_LEN); + } + + pMgmt->sAssocInfo.AssocInfo.RequestIELength += pCurrRates->len + WLAN_IEHDR_LEN; + MEMvCopy(pbyIEs, pCurrRates, pCurrRates->len + WLAN_IEHDR_LEN); + pbyIEs += pCurrRates->len + WLAN_IEHDR_LEN; + + if (((pMgmt->eAuthenMode == WMAC_AUTH_WPA) || + (pMgmt->eAuthenMode == WMAC_AUTH_WPAPSK) || + (pMgmt->eAuthenMode == WMAC_AUTH_WPANONE)) && + (pMgmt->pCurrBSS != NULL)) { + /* WPA IE */ + sFrame.pRSNWPA = (PWLAN_IE_RSN_EXT)(sFrame.pBuf + sFrame.len); + sFrame.pRSNWPA->byElementID = WLAN_EID_RSN_WPA; + sFrame.pRSNWPA->len = 16; + sFrame.pRSNWPA->abyOUI[0] = 0x00; + sFrame.pRSNWPA->abyOUI[1] = 0x50; + sFrame.pRSNWPA->abyOUI[2] = 0xf2; + sFrame.pRSNWPA->abyOUI[3] = 0x01; + sFrame.pRSNWPA->wVersion = 1; + //Group Key Cipher Suite + sFrame.pRSNWPA->abyMulticast[0] = 0x00; + sFrame.pRSNWPA->abyMulticast[1] = 0x50; + sFrame.pRSNWPA->abyMulticast[2] = 0xf2; + if (pMgmt->byCSSGK == KEY_CTL_WEP) { + sFrame.pRSNWPA->abyMulticast[3] = pMgmt->pCurrBSS->byGKType; + } else if (pMgmt->byCSSGK == KEY_CTL_TKIP) { + sFrame.pRSNWPA->abyMulticast[3] = WPA_TKIP; + } else if (pMgmt->byCSSGK == KEY_CTL_CCMP) { + sFrame.pRSNWPA->abyMulticast[3] = WPA_AESCCMP; + } else { + sFrame.pRSNWPA->abyMulticast[3] = WPA_NONE; + } + // Pairwise Key Cipher Suite + sFrame.pRSNWPA->wPKCount = 1; + sFrame.pRSNWPA->PKSList[0].abyOUI[0] = 0x00; + sFrame.pRSNWPA->PKSList[0].abyOUI[1] = 0x50; + sFrame.pRSNWPA->PKSList[0].abyOUI[2] = 0xf2; + if (pMgmt->byCSSPK == KEY_CTL_TKIP) { + sFrame.pRSNWPA->PKSList[0].abyOUI[3] = WPA_TKIP; + } else if (pMgmt->byCSSPK == KEY_CTL_CCMP) { + sFrame.pRSNWPA->PKSList[0].abyOUI[3] = WPA_AESCCMP; + } else { + sFrame.pRSNWPA->PKSList[0].abyOUI[3] = WPA_NONE; + } + // Auth Key Management Suite + pbyRSN = (PBYTE)(sFrame.pBuf + sFrame.len + 2 + sFrame.pRSNWPA->len); + *pbyRSN++=0x01; + *pbyRSN++=0x00; + *pbyRSN++=0x00; + *pbyRSN++=0x50; + *pbyRSN++=0xf2; + if (pMgmt->eAuthenMode == WMAC_AUTH_WPAPSK) { + *pbyRSN++=WPA_AUTH_PSK; + } else if (pMgmt->eAuthenMode == WMAC_AUTH_WPA) { + *pbyRSN++=WPA_AUTH_IEEE802_1X; + } else { + *pbyRSN++=WPA_NONE; + } + sFrame.pRSNWPA->len +=6; + + // RSN Capabilites + *pbyRSN++=0x00; + *pbyRSN++=0x00; + sFrame.pRSNWPA->len +=2; + sFrame.len += sFrame.pRSNWPA->len + WLAN_IEHDR_LEN; + // copy to AssocInfo. for OID_802_11_ASSOCIATION_INFORMATION + pMgmt->sAssocInfo.AssocInfo.RequestIELength += sFrame.pRSNWPA->len + WLAN_IEHDR_LEN; + MEMvCopy(pbyIEs, sFrame.pRSNWPA, sFrame.pRSNWPA->len + WLAN_IEHDR_LEN); + pbyIEs += sFrame.pRSNWPA->len + WLAN_IEHDR_LEN; + + } else if (((pMgmt->eAuthenMode == WMAC_AUTH_WPA2) || + (pMgmt->eAuthenMode == WMAC_AUTH_WPA2PSK)) && + (pMgmt->pCurrBSS != NULL)) { + UINT ii; + PWORD pwPMKID; + + /* WPA IE */ + sFrame.pRSN = (PWLAN_IE_RSN)(sFrame.pBuf + sFrame.len); + sFrame.pRSN->byElementID = WLAN_EID_RSN; + sFrame.pRSN->len = 6; //Version(2)+GK(4) + sFrame.pRSN->wVersion = 1; + //Group Key Cipher Suite + sFrame.pRSN->abyRSN[0] = 0x00; + sFrame.pRSN->abyRSN[1] = 0x0F; + sFrame.pRSN->abyRSN[2] = 0xAC; + if (pMgmt->byCSSGK == KEY_CTL_WEP) { + sFrame.pRSN->abyRSN[3] = pMgmt->pCurrBSS->byCSSGK; + } else if (pMgmt->byCSSGK == KEY_CTL_TKIP) { + sFrame.pRSN->abyRSN[3] = WLAN_11i_CSS_TKIP; + } else if (pMgmt->byCSSGK == KEY_CTL_CCMP) { + sFrame.pRSN->abyRSN[3] = WLAN_11i_CSS_CCMP; + } else { + sFrame.pRSN->abyRSN[3] = WLAN_11i_CSS_UNKNOWN; + } + + // Pairwise Key Cipher Suite + sFrame.pRSN->abyRSN[4] = 1; + sFrame.pRSN->abyRSN[5] = 0; + sFrame.pRSN->abyRSN[6] = 0x00; + sFrame.pRSN->abyRSN[7] = 0x0F; + sFrame.pRSN->abyRSN[8] = 0xAC; + if (pMgmt->byCSSPK == KEY_CTL_TKIP) { + sFrame.pRSN->abyRSN[9] = WLAN_11i_CSS_TKIP; + } else if (pMgmt->byCSSPK == KEY_CTL_CCMP) { + sFrame.pRSN->abyRSN[9] = WLAN_11i_CSS_CCMP; + } else if (pMgmt->byCSSPK == KEY_CTL_NONE) { + sFrame.pRSN->abyRSN[9] = WLAN_11i_CSS_USE_GROUP; + } else { + sFrame.pRSN->abyRSN[9] = WLAN_11i_CSS_UNKNOWN; + } + sFrame.pRSN->len += 6; + + // Auth Key Management Suite + sFrame.pRSN->abyRSN[10] = 1; + sFrame.pRSN->abyRSN[11] = 0; + sFrame.pRSN->abyRSN[12] = 0x00; + sFrame.pRSN->abyRSN[13] = 0x0F; + sFrame.pRSN->abyRSN[14] = 0xAC; + if (pMgmt->eAuthenMode == WMAC_AUTH_WPA2PSK) { + sFrame.pRSN->abyRSN[15] = WLAN_11i_AKMSS_PSK; + } else if (pMgmt->eAuthenMode == WMAC_AUTH_WPA2) { + sFrame.pRSN->abyRSN[15] = WLAN_11i_AKMSS_802_1X; + } else { + sFrame.pRSN->abyRSN[15] = WLAN_11i_AKMSS_UNKNOWN; + } + sFrame.pRSN->len +=6; + + // RSN Capabilites + if (pMgmt->pCurrBSS->sRSNCapObj.bRSNCapExist == TRUE) { + MEMvCopy(&sFrame.pRSN->abyRSN[16], &pMgmt->pCurrBSS->sRSNCapObj.wRSNCap, 2); + } else { + sFrame.pRSN->abyRSN[16] = 0; + sFrame.pRSN->abyRSN[17] = 0; + } + sFrame.pRSN->len +=2; + + if ((pDevice->gsPMKID.BSSIDInfoCount > 0) && (pDevice->bRoaming == TRUE) && (pMgmt->eAuthenMode == WMAC_AUTH_WPA2)) { + // RSN PMKID + pbyRSN = &sFrame.pRSN->abyRSN[18]; + pwPMKID = (PWORD)pbyRSN; // Point to PMKID count + *pwPMKID = 0; // Initialize PMKID count + pbyRSN += 2; // Point to PMKID list + for (ii = 0; ii < pDevice->gsPMKID.BSSIDInfoCount; ii++) { + if (MEMEqualMemory(&pDevice->gsPMKID.BSSIDInfo[ii].BSSID[0], pMgmt->abyCurrBSSID, U_ETHER_ADDR_LEN)) { + (*pwPMKID) ++; + MEMvCopy(pbyRSN, pDevice->gsPMKID.BSSIDInfo[ii].PMKID, 16); + pbyRSN += 16; + } + } + if (*pwPMKID != 0) { + sFrame.pRSN->len += (2 + (*pwPMKID)*16); + } + } + + sFrame.len += sFrame.pRSN->len + WLAN_IEHDR_LEN; + // copy to AssocInfo. for OID_802_11_ASSOCIATION_INFORMATION + pMgmt->sAssocInfo.AssocInfo.RequestIELength += sFrame.pRSN->len + WLAN_IEHDR_LEN; + MEMvCopy(pbyIEs, sFrame.pRSN, sFrame.pRSN->len + WLAN_IEHDR_LEN); + pbyIEs += sFrame.pRSN->len + WLAN_IEHDR_LEN; + } + + + /* Adjust the length fields */ + pTxPacket->cbMPDULen = sFrame.len; + pTxPacket->cbPayloadLen = sFrame.len - WLAN_HDR_ADDR3_LEN; + + return pTxPacket; +} + + + +/*+ + * + * Routine Description: + * Constructs an assoc-response frame + * + * + * Return Value: + * PTR to frame; or NULL on allocation failue + * +-*/ + + +PSTxMgmtPacket +s_MgrMakeAssocResponse( + IN PSDevice pDevice, + IN PSMgmtObject pMgmt, + IN WORD wCurrCapInfo, + IN WORD wAssocStatus, + IN WORD wAssocAID, + IN PBYTE pDstAddr, + IN PWLAN_IE_SUPP_RATES pCurrSuppRates, + IN PWLAN_IE_SUPP_RATES pCurrExtSuppRates + ) +{ + PSTxMgmtPacket pTxPacket = NULL; + WLAN_FR_ASSOCRESP sFrame; + + + pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool; + memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_ASSOCREQ_FR_MAXLEN); + pTxPacket->p80211Header = (PUWLAN_80211HDR)((PBYTE)pTxPacket + sizeof(STxMgmtPacket)); + // Setup the sFrame structure + sFrame.pBuf = (PBYTE)pTxPacket->p80211Header; + sFrame.len = WLAN_REASSOCRESP_FR_MAXLEN; + vMgrEncodeAssocResponse(&sFrame); + // Setup the header + sFrame.pHdr->sA3.wFrameCtl = cpu_to_le16( + ( + WLAN_SET_FC_FTYPE(WLAN_TYPE_MGR) | + WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_ASSOCRESP) + )); + memcpy( sFrame.pHdr->sA3.abyAddr1, pDstAddr, WLAN_ADDR_LEN); + memcpy( sFrame.pHdr->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN); + memcpy( sFrame.pHdr->sA3.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN); + + *sFrame.pwCapInfo = cpu_to_le16(wCurrCapInfo); + *sFrame.pwStatus = cpu_to_le16(wAssocStatus); + *sFrame.pwAid = cpu_to_le16((WORD)(wAssocAID | BIT14 | BIT15)); + + // Copy the rate set + sFrame.pSuppRates = (PWLAN_IE_SUPP_RATES)(sFrame.pBuf + sFrame.len); + sFrame.len += ((PWLAN_IE_SUPP_RATES)pCurrSuppRates)->len + WLAN_IEHDR_LEN; + memcpy(sFrame.pSuppRates, + pCurrSuppRates, + ((PWLAN_IE_SUPP_RATES)pCurrSuppRates)->len + WLAN_IEHDR_LEN + ); + + if (((PWLAN_IE_SUPP_RATES)pCurrExtSuppRates)->len != 0) { + sFrame.pExtSuppRates = (PWLAN_IE_SUPP_RATES)(sFrame.pBuf + sFrame.len); + sFrame.len += ((PWLAN_IE_SUPP_RATES)pCurrExtSuppRates)->len + WLAN_IEHDR_LEN; + MEMvCopy(sFrame.pExtSuppRates, + pCurrExtSuppRates, + ((PWLAN_IE_SUPP_RATES)pCurrExtSuppRates)->len + WLAN_IEHDR_LEN + ); + } + + // Adjust the length fields + pTxPacket->cbMPDULen = sFrame.len; + pTxPacket->cbPayloadLen = sFrame.len - WLAN_HDR_ADDR3_LEN; + + return pTxPacket; +} + + +/*+ + * + * Routine Description: + * Constructs an reassoc-response frame + * + * + * Return Value: + * PTR to frame; or NULL on allocation failue + * +-*/ + + +PSTxMgmtPacket +s_MgrMakeReAssocResponse( + IN PSDevice pDevice, + IN PSMgmtObject pMgmt, + IN WORD wCurrCapInfo, + IN WORD wAssocStatus, + IN WORD wAssocAID, + IN PBYTE pDstAddr, + IN PWLAN_IE_SUPP_RATES pCurrSuppRates, + IN PWLAN_IE_SUPP_RATES pCurrExtSuppRates + ) +{ + PSTxMgmtPacket pTxPacket = NULL; + WLAN_FR_REASSOCRESP sFrame; + + + pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool; + memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_ASSOCREQ_FR_MAXLEN); + pTxPacket->p80211Header = (PUWLAN_80211HDR)((PBYTE)pTxPacket + sizeof(STxMgmtPacket)); + // Setup the sFrame structure + sFrame.pBuf = (PBYTE)pTxPacket->p80211Header; + sFrame.len = WLAN_REASSOCRESP_FR_MAXLEN; + vMgrEncodeReassocResponse(&sFrame); + // Setup the header + sFrame.pHdr->sA3.wFrameCtl = cpu_to_le16( + ( + WLAN_SET_FC_FTYPE(WLAN_TYPE_MGR) | + WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_REASSOCRESP) + )); + memcpy( sFrame.pHdr->sA3.abyAddr1, pDstAddr, WLAN_ADDR_LEN); + memcpy( sFrame.pHdr->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN); + memcpy( sFrame.pHdr->sA3.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN); + + *sFrame.pwCapInfo = cpu_to_le16(wCurrCapInfo); + *sFrame.pwStatus = cpu_to_le16(wAssocStatus); + *sFrame.pwAid = cpu_to_le16((WORD)(wAssocAID | BIT14 | BIT15)); + + // Copy the rate set + sFrame.pSuppRates = (PWLAN_IE_SUPP_RATES)(sFrame.pBuf + sFrame.len); + sFrame.len += ((PWLAN_IE_SUPP_RATES)pCurrSuppRates)->len + WLAN_IEHDR_LEN; + memcpy(sFrame.pSuppRates, + pCurrSuppRates, + ((PWLAN_IE_SUPP_RATES)pCurrSuppRates)->len + WLAN_IEHDR_LEN + ); + + if (((PWLAN_IE_SUPP_RATES)pCurrExtSuppRates)->len != 0) { + sFrame.pExtSuppRates = (PWLAN_IE_SUPP_RATES)(sFrame.pBuf + sFrame.len); + sFrame.len += ((PWLAN_IE_SUPP_RATES)pCurrExtSuppRates)->len + WLAN_IEHDR_LEN; + MEMvCopy(sFrame.pExtSuppRates, + pCurrExtSuppRates, + ((PWLAN_IE_SUPP_RATES)pCurrExtSuppRates)->len + WLAN_IEHDR_LEN + ); + } + + // Adjust the length fields + pTxPacket->cbMPDULen = sFrame.len; + pTxPacket->cbPayloadLen = sFrame.len - WLAN_HDR_ADDR3_LEN; + + return pTxPacket; +} + + +/*+ + * + * Routine Description: + * Handles probe response management frames. + * + * + * Return Value: + * none. + * +-*/ + +static +VOID +s_vMgrRxProbeResponse( + IN PSDevice pDevice, + IN PSMgmtObject pMgmt, + IN PSRxMgmtPacket pRxPacket + ) +{ + PKnownBSS pBSSList = NULL; + WLAN_FR_PROBERESP sFrame; + BYTE byCurrChannel = pRxPacket->byRxChannel; + ERPObject sERP; + BYTE byIEChannel = 0; + BOOL bChannelHit = TRUE; + + + memset(&sFrame, 0, sizeof(WLAN_FR_PROBERESP)); + // decode the frame + sFrame.len = pRxPacket->cbMPDULen; + sFrame.pBuf = (PBYTE)pRxPacket->p80211Header; + vMgrDecodeProbeResponse(&sFrame); + + if ((sFrame.pqwTimestamp == 0) || + (sFrame.pwBeaconInterval == 0) || + (sFrame.pwCapInfo == 0) || + (sFrame.pSSID == 0) || + (sFrame.pSuppRates == 0)) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Probe resp:Fail addr:[%p] \n", pRxPacket->p80211Header); + DBG_PORT80(0xCC); + return; + }; + + if(sFrame.pSSID->len == 0) + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Rx Probe resp: SSID len = 0 \n"); + + if (sFrame.pDSParms != 0) { + if (byCurrChannel > CB_MAX_CHANNEL_24G) { + // channel remapping to + byIEChannel = CARDbyGetChannelMapping(pMgmt->pAdapter, sFrame.pDSParms->byCurrChannel, PHY_TYPE_11A); + } else { + byIEChannel = sFrame.pDSParms->byCurrChannel; + } + if (byCurrChannel != byIEChannel) { + // adjust channel info. bcs we rcv adjcent channel pakckets + bChannelHit = FALSE; + byCurrChannel = byIEChannel; + } + } else { + // no DS channel info + bChannelHit = TRUE; + } + +//2008-0730-01by MikeLiu +if(ChannelExceedZoneType(pDevice,byCurrChannel)==TRUE) + return; + + if (sFrame.pERP != NULL) { + sERP.byERP = sFrame.pERP->byContext; + sERP.bERPExist = TRUE; + } else { + sERP.bERPExist = FALSE; + sERP.byERP = 0; + } + + + // update or insert the bss + pBSSList = BSSpAddrIsInBSSList((HANDLE)pDevice, sFrame.pHdr->sA3.abyAddr3, sFrame.pSSID); + if (pBSSList) { + BSSbUpdateToBSSList((HANDLE)pDevice, + *sFrame.pqwTimestamp, + *sFrame.pwBeaconInterval, + *sFrame.pwCapInfo, + byCurrChannel, + bChannelHit, + sFrame.pSSID, + sFrame.pSuppRates, + sFrame.pExtSuppRates, + &sERP, + sFrame.pRSN, + sFrame.pRSNWPA, + sFrame.pIE_Country, + sFrame.pIE_Quiet, + pBSSList, + sFrame.len - WLAN_HDR_ADDR3_LEN, + sFrame.pHdr->sA4.abyAddr4, // payload of probresponse + (HANDLE)pRxPacket + ); + } + else { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Probe resp/insert: RxChannel = : %d\n", byCurrChannel); + BSSbInsertToBSSList((HANDLE)pDevice, + sFrame.pHdr->sA3.abyAddr3, + *sFrame.pqwTimestamp, + *sFrame.pwBeaconInterval, + *sFrame.pwCapInfo, + byCurrChannel, + sFrame.pSSID, + sFrame.pSuppRates, + sFrame.pExtSuppRates, + &sERP, + sFrame.pRSN, + sFrame.pRSNWPA, + sFrame.pIE_Country, + sFrame.pIE_Quiet, + sFrame.len - WLAN_HDR_ADDR3_LEN, + sFrame.pHdr->sA4.abyAddr4, // payload of beacon + (HANDLE)pRxPacket + ); + } + return; + +} + +/*+ + * + * Routine Description:(AP)or(Ad-hoc STA) + * Handles probe request management frames. + * + * + * Return Value: + * none. + * +-*/ + + +static +VOID +s_vMgrRxProbeRequest( + IN PSDevice pDevice, + IN PSMgmtObject pMgmt, + IN PSRxMgmtPacket pRxPacket + ) +{ + WLAN_FR_PROBEREQ sFrame; + CMD_STATUS Status; + PSTxMgmtPacket pTxPacket; + BYTE byPHYType = BB_TYPE_11B; + + // STA in Ad-hoc mode: when latest TBTT beacon transmit success, + // STA have to response this request. + if ((pMgmt->eCurrMode == WMAC_MODE_ESS_AP) || + ((pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) && pDevice->bBeaconSent)) { + + memset(&sFrame, 0, sizeof(WLAN_FR_PROBEREQ)); + // decode the frame + sFrame.len = pRxPacket->cbMPDULen; + sFrame.pBuf = (PBYTE)pRxPacket->p80211Header; + vMgrDecodeProbeRequest(&sFrame); +/* + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Probe request rx:MAC addr:%02x-%02x-%02x=%02x-%02x-%02x \n", + sFrame.pHdr->sA3.abyAddr2[0], + sFrame.pHdr->sA3.abyAddr2[1], + sFrame.pHdr->sA3.abyAddr2[2], + sFrame.pHdr->sA3.abyAddr2[3], + sFrame.pHdr->sA3.abyAddr2[4], + sFrame.pHdr->sA3.abyAddr2[5] + ); +*/ + if (sFrame.pSSID->len != 0) { + if (sFrame.pSSID->len != ((PWLAN_IE_SSID)pMgmt->abyCurrSSID)->len) + return; + if (memcmp(sFrame.pSSID->abySSID, + ((PWLAN_IE_SSID)pMgmt->abyCurrSSID)->abySSID, + ((PWLAN_IE_SSID)pMgmt->abyCurrSSID)->len) != 0) { + return; + } + } + + if ((sFrame.pSuppRates->len > 4) || (sFrame.pExtSuppRates != NULL)) { + byPHYType = BB_TYPE_11G; + } + + // Probe response reply.. + pTxPacket = s_MgrMakeProbeResponse + ( + pDevice, + pMgmt, + pMgmt->wCurrCapInfo, + pMgmt->wCurrBeaconPeriod, + pMgmt->uCurrChannel, + 0, + sFrame.pHdr->sA3.abyAddr2, + (PWLAN_IE_SSID)pMgmt->abyCurrSSID, + (PBYTE)pMgmt->abyCurrBSSID, + (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates, + (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates, + byPHYType + ); + if (pTxPacket != NULL ){ + /* send the frame */ + Status = csMgmt_xmit(pDevice, pTxPacket); + if (Status != CMD_STATUS_PENDING) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Mgt:Probe response tx failed\n"); + } + else { +// DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Mgt:Probe response tx sending..\n"); + } + } + } + + return; +} + + + + + +/*+ + * + * Routine Description: + * + * Entry point for the reception and handling of 802.11 management + * frames. Makes a determination of the frame type and then calls + * the appropriate function. + * + * + * Return Value: + * none. + * +-*/ + + +VOID +vMgrRxManagePacket( + IN HANDLE hDeviceContext, + IN PSMgmtObject pMgmt, + IN PSRxMgmtPacket pRxPacket + ) +{ + PSDevice pDevice = (PSDevice)hDeviceContext; + BOOL bInScan = FALSE; + UINT uNodeIndex = 0; + NODE_STATE eNodeState = 0; + CMD_STATUS Status; + + + if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) { + if (BSSDBbIsSTAInNodeDB(pMgmt, pRxPacket->p80211Header->sA3.abyAddr2, &uNodeIndex)) + eNodeState = pMgmt->sNodeDBTable[uNodeIndex].eNodeState; + } + + switch( WLAN_GET_FC_FSTYPE((pRxPacket->p80211Header->sA3.wFrameCtl)) ){ + + case WLAN_FSTYPE_ASSOCREQ: + // Frame Clase = 2 + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "rx assocreq\n"); + if (eNodeState < NODE_AUTH) { + // send deauth notification + // reason = (6) class 2 received from nonauth sta + vMgrDeAuthenBeginSta(pDevice, + pMgmt, + pRxPacket->p80211Header->sA3.abyAddr2, + (6), + &Status + ); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "wmgr: send vMgrDeAuthenBeginSta 1\n"); + } + else { + s_vMgrRxAssocRequest(pDevice, pMgmt, pRxPacket, uNodeIndex); + } + break; + + case WLAN_FSTYPE_ASSOCRESP: + // Frame Clase = 2 + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "rx assocresp1\n"); + s_vMgrRxAssocResponse(pDevice, pMgmt, pRxPacket, FALSE); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "rx assocresp2\n"); + break; + + case WLAN_FSTYPE_REASSOCREQ: + // Frame Clase = 2 + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "rx reassocreq\n"); + // Todo: reassoc + if (eNodeState < NODE_AUTH) { + // send deauth notification + // reason = (6) class 2 received from nonauth sta + vMgrDeAuthenBeginSta(pDevice, + pMgmt, + pRxPacket->p80211Header->sA3.abyAddr2, + (6), + &Status + ); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "wmgr: send vMgrDeAuthenBeginSta 2\n"); + + } + s_vMgrRxReAssocRequest(pDevice, pMgmt, pRxPacket, uNodeIndex); + break; + + case WLAN_FSTYPE_REASSOCRESP: + // Frame Clase = 2 + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "rx reassocresp\n"); + s_vMgrRxAssocResponse(pDevice, pMgmt, pRxPacket, TRUE); + break; + + case WLAN_FSTYPE_PROBEREQ: + // Frame Clase = 0 + //DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "rx probereq\n"); + s_vMgrRxProbeRequest(pDevice, pMgmt, pRxPacket); + break; + + case WLAN_FSTYPE_PROBERESP: + // Frame Clase = 0 + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "rx proberesp\n"); + + s_vMgrRxProbeResponse(pDevice, pMgmt, pRxPacket); + break; + + case WLAN_FSTYPE_BEACON: + // Frame Clase = 0 + // DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "rx beacon\n"); + if (pMgmt->eScanState != WMAC_NO_SCANNING) { + bInScan = TRUE; + }; + s_vMgrRxBeacon(pDevice, pMgmt, pRxPacket, bInScan); + break; + + case WLAN_FSTYPE_ATIM: + // Frame Clase = 1 + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "rx atim\n"); + break; + + case WLAN_FSTYPE_DISASSOC: + // Frame Clase = 2 + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "rx disassoc\n"); + if (eNodeState < NODE_AUTH) { + // send deauth notification + // reason = (6) class 2 received from nonauth sta + vMgrDeAuthenBeginSta(pDevice, + pMgmt, + pRxPacket->p80211Header->sA3.abyAddr2, + (6), + &Status + ); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "wmgr: send vMgrDeAuthenBeginSta 3\n"); + } + s_vMgrRxDisassociation(pDevice, pMgmt, pRxPacket); + break; + + case WLAN_FSTYPE_AUTHEN: + // Frame Clase = 1 + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "rx authen\n"); + s_vMgrRxAuthentication(pDevice, pMgmt, pRxPacket); + break; + + case WLAN_FSTYPE_DEAUTHEN: + // Frame Clase = 1 + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "rx deauthen\n"); + s_vMgrRxDeauthentication(pDevice, pMgmt, pRxPacket); + break; + + default: + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "rx unknown mgmt\n"); + } + + return; +} + + + + +/*+ + * + * Routine Description: + * + * + * Prepare beacon to send + * + * Return Value: + * TRUE if success; FALSE if failed. + * +-*/ +BOOL +bMgrPrepareBeaconToSend( + IN HANDLE hDeviceContext, + IN PSMgmtObject pMgmt + ) +{ + PSDevice pDevice = (PSDevice)hDeviceContext; + PSTxMgmtPacket pTxPacket; + +// pDevice->bBeaconBufReady = FALSE; + if (pDevice->bEncryptionEnable || pDevice->bEnable8021x){ + pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_PRIVACY(1); + } + else { + pMgmt->wCurrCapInfo &= ~WLAN_SET_CAP_INFO_PRIVACY(1); + } + pTxPacket = s_MgrMakeBeacon + ( + pDevice, + pMgmt, + pMgmt->wCurrCapInfo, + pMgmt->wCurrBeaconPeriod, + pMgmt->uCurrChannel, + pMgmt->wCurrATIMWindow, //0, + (PWLAN_IE_SSID)pMgmt->abyCurrSSID, + (PBYTE)pMgmt->abyCurrBSSID, + (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates, + (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates + ); + + if ((pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) && + (pMgmt->abyCurrBSSID[0] == 0)) + return FALSE; + + csBeacon_xmit(pDevice, pTxPacket); + + return TRUE; +} + + + + +/*+ + * + * Routine Description: + * + * Log a warning message based on the contents of the Status + * Code field of an 802.11 management frame. Defines are + * derived from 802.11-1997 SPEC. + * + * Return Value: + * none. + * +-*/ +static +VOID +s_vMgrLogStatus( + IN PSMgmtObject pMgmt, + IN WORD wStatus + ) +{ + switch( wStatus ){ + case WLAN_MGMT_STATUS_UNSPEC_FAILURE: + DEVICE_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Status code == Unspecified error.\n"); + break; + case WLAN_MGMT_STATUS_CAPS_UNSUPPORTED: + DEVICE_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Status code == Can't support all requested capabilities.\n"); + break; + case WLAN_MGMT_STATUS_REASSOC_NO_ASSOC: + DEVICE_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Status code == Reassoc denied, can't confirm original Association.\n"); + break; + case WLAN_MGMT_STATUS_ASSOC_DENIED_UNSPEC: + DEVICE_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Status code == Assoc denied, undefine in spec\n"); + break; + case WLAN_MGMT_STATUS_UNSUPPORTED_AUTHALG: + DEVICE_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Status code == Peer doesn't support authen algorithm.\n"); + break; + case WLAN_MGMT_STATUS_RX_AUTH_NOSEQ: + DEVICE_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Status code == Authen frame received out of sequence.\n"); + break; + case WLAN_MGMT_STATUS_CHALLENGE_FAIL: + DEVICE_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Status code == Authen rejected, challenge failure.\n"); + break; + case WLAN_MGMT_STATUS_AUTH_TIMEOUT: + DEVICE_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Status code == Authen rejected, timeout waiting for next frame.\n"); + break; + case WLAN_MGMT_STATUS_ASSOC_DENIED_BUSY: + DEVICE_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Status code == Assoc denied, AP too busy.\n"); + break; + case WLAN_MGMT_STATUS_ASSOC_DENIED_RATES: + DEVICE_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Status code == Assoc denied, we haven't enough basic rates.\n"); + break; + case WLAN_MGMT_STATUS_ASSOC_DENIED_SHORTPREAMBLE: + DEVICE_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Status code == Assoc denied, we do not support short preamble.\n"); + break; + case WLAN_MGMT_STATUS_ASSOC_DENIED_PBCC: + DEVICE_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Status code == Assoc denied, we do not support PBCC.\n"); + break; + case WLAN_MGMT_STATUS_ASSOC_DENIED_AGILITY: + DEVICE_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Status code == Assoc denied, we do not support channel agility.\n"); + break; + default: + DEVICE_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Unknown status code %d.\n", wStatus); + break; + } +} + + +/* + * + * Description: + * Add BSSID in PMKID Candidate list. + * + * Parameters: + * In: + * hDeviceContext - device structure point + * pbyBSSID - BSSID address for adding + * wRSNCap - BSS's RSN capability + * Out: + * none + * + * Return Value: none. + * +-*/ +BOOL +bAdd_PMKID_Candidate ( + IN HANDLE hDeviceContext, + IN PBYTE pbyBSSID, + IN PSRSNCapObject psRSNCapObj + ) +{ + PSDevice pDevice = (PSDevice)hDeviceContext; + PPMKID_CANDIDATE pCandidateList; + UINT ii = 0; + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"bAdd_PMKID_Candidate START: (%d)\n", (int)pDevice->gsPMKIDCandidate.NumCandidates); + + if ((pDevice == NULL) || (pbyBSSID == NULL) || (psRSNCapObj == NULL)) + return FALSE; + + if (pDevice->gsPMKIDCandidate.NumCandidates >= MAX_PMKIDLIST) + return FALSE; + + + + // Update Old Candidate + for (ii = 0; ii < pDevice->gsPMKIDCandidate.NumCandidates; ii++) { + pCandidateList = &pDevice->gsPMKIDCandidate.CandidateList[ii]; + if (MEMEqualMemory(pCandidateList->BSSID, pbyBSSID, U_ETHER_ADDR_LEN)) { + if ((psRSNCapObj->bRSNCapExist == TRUE) && (psRSNCapObj->wRSNCap & BIT0)) { + pCandidateList->Flags |= NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED; + } else { + pCandidateList->Flags &= ~(NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED); + } + return TRUE; + } + } + + // New Candidate + pCandidateList = &pDevice->gsPMKIDCandidate.CandidateList[pDevice->gsPMKIDCandidate.NumCandidates]; + if ((psRSNCapObj->bRSNCapExist == TRUE) && (psRSNCapObj->wRSNCap & BIT0)) { + pCandidateList->Flags |= NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED; + } else { + pCandidateList->Flags &= ~(NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED); + } + MEMvCopy(pCandidateList->BSSID, pbyBSSID, U_ETHER_ADDR_LEN); + pDevice->gsPMKIDCandidate.NumCandidates++; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"NumCandidates:%d\n", (int)pDevice->gsPMKIDCandidate.NumCandidates); + return TRUE; +} + +/* + * + * Description: + * Flush PMKID Candidate list. + * + * Parameters: + * In: + * hDeviceContext - device structure point + * Out: + * none + * + * Return Value: none. + * +-*/ +VOID +vFlush_PMKID_Candidate ( + IN HANDLE hDeviceContext + ) +{ + PSDevice pDevice = (PSDevice)hDeviceContext; + + if (pDevice == NULL) + return; + + ZERO_MEMORY(&pDevice->gsPMKIDCandidate, sizeof(SPMKIDCandidateEvent)); +} + +static BOOL +s_bCipherMatch ( + IN PKnownBSS pBSSNode, + IN NDIS_802_11_ENCRYPTION_STATUS EncStatus, + OUT PBYTE pbyCCSPK, + OUT PBYTE pbyCCSGK + ) +{ + BYTE byMulticastCipher = KEY_CTL_INVALID; + BYTE byCipherMask = 0x00; + int i; + + if (pBSSNode == NULL) + return FALSE; + + // check cap. of BSS + + if ((WLAN_GET_CAP_INFO_PRIVACY(pBSSNode->wCapInfo) != 0) && + (EncStatus == Ndis802_11Encryption1Enabled)) { + // default is WEP only + byMulticastCipher = KEY_CTL_WEP; + } + + if ((WLAN_GET_CAP_INFO_PRIVACY(pBSSNode->wCapInfo) != 0) && + (pBSSNode->bWPA2Valid == TRUE) && + ((EncStatus == Ndis802_11Encryption3Enabled)||(EncStatus == Ndis802_11Encryption2Enabled))) { + + //WPA2 + // check Group Key Cipher + if ((pBSSNode->byCSSGK == WLAN_11i_CSS_WEP40) || + (pBSSNode->byCSSGK == WLAN_11i_CSS_WEP104)) { + byMulticastCipher = KEY_CTL_WEP; + } else if (pBSSNode->byCSSGK == WLAN_11i_CSS_TKIP) { + byMulticastCipher = KEY_CTL_TKIP; + } else if (pBSSNode->byCSSGK == WLAN_11i_CSS_CCMP) { + byMulticastCipher = KEY_CTL_CCMP; + } else { + byMulticastCipher = KEY_CTL_INVALID; + } + + // check Pairwise Key Cipher + for(i=0;iwCSSPKCount;i++) { + if ((pBSSNode->abyCSSPK[i] == WLAN_11i_CSS_WEP40) || + (pBSSNode->abyCSSPK[i] == WLAN_11i_CSS_WEP104)) { + // this should not happen as defined 802.11i + byCipherMask |= 0x01; + } else if (pBSSNode->abyCSSPK[i] == WLAN_11i_CSS_TKIP) { + byCipherMask |= 0x02; + } else if (pBSSNode->abyCSSPK[i] == WLAN_11i_CSS_CCMP) { + byCipherMask |= 0x04; + } else if (pBSSNode->abyCSSPK[i] == WLAN_11i_CSS_USE_GROUP) { + // use group key only ignore all others + byCipherMask = 0; + i = pBSSNode->wCSSPKCount; + } + } + } else if ((WLAN_GET_CAP_INFO_PRIVACY(pBSSNode->wCapInfo) != 0) && + (pBSSNode->bWPAValid == TRUE) && + ((EncStatus == Ndis802_11Encryption3Enabled)||(EncStatus == Ndis802_11Encryption2Enabled))) { + + //WPA + // check Group Key Cipher + if ((pBSSNode->byGKType == WPA_WEP40) || + (pBSSNode->byGKType == WPA_WEP104)) { + byMulticastCipher = KEY_CTL_WEP; + } else if (pBSSNode->byGKType == WPA_TKIP) { + byMulticastCipher = KEY_CTL_TKIP; + } else if (pBSSNode->byGKType == WPA_AESCCMP) { + byMulticastCipher = KEY_CTL_CCMP; + } else { + byMulticastCipher = KEY_CTL_INVALID; + } + + // check Pairwise Key Cipher + for(i=0;iwPKCount;i++) { + if (pBSSNode->abyPKType[i] == WPA_TKIP) { + byCipherMask |= 0x02; + } else if (pBSSNode->abyPKType[i] == WPA_AESCCMP) { + byCipherMask |= 0x04; + } else if (pBSSNode->abyPKType[i] == WPA_NONE) { + // use group key only ignore all others + byCipherMask = 0; + i = pBSSNode->wPKCount; + } + } + } + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"%d, %d, %d, %d, EncStatus:%d\n", + byMulticastCipher, byCipherMask, pBSSNode->bWPAValid, pBSSNode->bWPA2Valid, EncStatus); + + // mask our cap. with BSS + if (EncStatus == Ndis802_11Encryption1Enabled) { + // For supporting Cisco migration mode, don't care pairwise key cipher + if ((byMulticastCipher == KEY_CTL_WEP) && + (byCipherMask == 0)) { + *pbyCCSGK = KEY_CTL_WEP; + *pbyCCSPK = KEY_CTL_NONE; + return TRUE; + } else { + return FALSE; + } + + } else if (EncStatus == Ndis802_11Encryption2Enabled) { + if ((byMulticastCipher == KEY_CTL_TKIP) && + (byCipherMask == 0)) { + *pbyCCSGK = KEY_CTL_TKIP; + *pbyCCSPK = KEY_CTL_NONE; + return TRUE; + } else if ((byMulticastCipher == KEY_CTL_WEP) && + ((byCipherMask & 0x02) != 0)) { + *pbyCCSGK = KEY_CTL_WEP; + *pbyCCSPK = KEY_CTL_TKIP; + return TRUE; + } else if ((byMulticastCipher == KEY_CTL_TKIP) && + ((byCipherMask & 0x02) != 0)) { + *pbyCCSGK = KEY_CTL_TKIP; + *pbyCCSPK = KEY_CTL_TKIP; + return TRUE; + } else { + return FALSE; + } + } else if (EncStatus == Ndis802_11Encryption3Enabled) { + if ((byMulticastCipher == KEY_CTL_CCMP) && + (byCipherMask == 0)) { + // When CCMP is enable, "Use group cipher suite" shall not be a valid option. + return FALSE; + } else if ((byMulticastCipher == KEY_CTL_WEP) && + ((byCipherMask & 0x04) != 0)) { + *pbyCCSGK = KEY_CTL_WEP; + *pbyCCSPK = KEY_CTL_CCMP; + return TRUE; + } else if ((byMulticastCipher == KEY_CTL_TKIP) && + ((byCipherMask & 0x04) != 0)) { + *pbyCCSGK = KEY_CTL_TKIP; + *pbyCCSPK = KEY_CTL_CCMP; + return TRUE; + } else if ((byMulticastCipher == KEY_CTL_CCMP) && + ((byCipherMask & 0x04) != 0)) { + *pbyCCSGK = KEY_CTL_CCMP; + *pbyCCSPK = KEY_CTL_CCMP; + return TRUE; + } else { + return FALSE; + } + } + return TRUE; +} + + diff --git a/drivers/staging/vt6655/wmgr.h b/drivers/staging/vt6655/wmgr.h new file mode 100644 index 000000000000..5b526ab2d912 --- /dev/null +++ b/drivers/staging/vt6655/wmgr.h @@ -0,0 +1,521 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * File: wmgr.h + * + * Purpose: + * + * Author: lyndon chen + * + * Date: Jan 2, 2003 + * + * Functions: + * + * Revision History: + * + */ + + +#ifndef __WMGR_H__ +#define __WMGR_H__ + +#if !defined(__TTYPE_H__) +#include "ttype.h" +#endif +#if !defined(__80211MGR_H__) +#include "80211mgr.h" +#endif +#if !defined(__80211HDR_H__) +#include "80211hdr.h" +#endif +#if !defined(__WCMD_H__) +#include "wcmd.h" +#endif +#if !defined(__BSSDB_H__) +#include "bssdb.h" +#endif +#if !defined(__CARD_H__) +#include "card.h" +#endif +#if !defined(__WPA2_H__) +#include "wpa2.h" +#endif +#if !defined(__VNTWIFI_H__) +#include "vntwifi.h" +#endif + + + +/*--------------------- Export Definitions -------------------------*/ + + + +// Scan time +#define PROBE_DELAY 100 // (us) +#define SWITCH_CHANNEL_DELAY 200 // (us) +#define WLAN_SCAN_MINITIME 25 // (ms) +#define WLAN_SCAN_MAXTIME 100 // (ms) +#define TRIVIAL_SYNC_DIFFERENCE 0 // (us) +#define DEFAULT_IBSS_BI 100 // (ms) + +#define WCMD_ACTIVE_SCAN_TIME 50 //(ms) +#define WCMD_PASSIVE_SCAN_TIME 100 //(ms) + + +#define DEFAULT_MSDU_LIFETIME 512 // ms +#define DEFAULT_MSDU_LIFETIME_RES_64us 8000 // 64us + +#define DEFAULT_MGN_LIFETIME 8 // ms +#define DEFAULT_MGN_LIFETIME_RES_64us 125 // 64us + +#define MAKE_BEACON_RESERVED 10 //(us) + + +#define TIM_MULTICAST_MASK 0x01 +#define TIM_BITMAPOFFSET_MASK 0xFE +#define DEFAULT_DTIM_PERIOD 1 + +#define AP_LONG_RETRY_LIMIT 4 + +#define DEFAULT_IBSS_CHANNEL 6 //2.4G + + +/*--------------------- Export Classes ----------------------------*/ + +/*--------------------- Export Variables --------------------------*/ + +/*--------------------- Export Types ------------------------------*/ +#define timer_expire(timer,next_tick) mod_timer(&timer, RUN_AT(next_tick)) +typedef void (*TimerFunction)(ULONG); + + +//+++ NDIS related + +typedef UCHAR NDIS_802_11_MAC_ADDRESS[6]; +typedef struct _NDIS_802_11_AI_REQFI +{ + USHORT Capabilities; + USHORT ListenInterval; + NDIS_802_11_MAC_ADDRESS CurrentAPAddress; +} NDIS_802_11_AI_REQFI, *PNDIS_802_11_AI_REQFI; + +typedef struct _NDIS_802_11_AI_RESFI +{ + USHORT Capabilities; + USHORT StatusCode; + USHORT AssociationId; +} NDIS_802_11_AI_RESFI, *PNDIS_802_11_AI_RESFI; + +typedef struct _NDIS_802_11_ASSOCIATION_INFORMATION +{ + ULONG Length; + USHORT AvailableRequestFixedIEs; + NDIS_802_11_AI_REQFI RequestFixedIEs; + ULONG RequestIELength; + ULONG OffsetRequestIEs; + USHORT AvailableResponseFixedIEs; + NDIS_802_11_AI_RESFI ResponseFixedIEs; + ULONG ResponseIELength; + ULONG OffsetResponseIEs; +} NDIS_802_11_ASSOCIATION_INFORMATION, *PNDIS_802_11_ASSOCIATION_INFORMATION; + + + +typedef struct tagSAssocInfo { + NDIS_802_11_ASSOCIATION_INFORMATION AssocInfo; + BYTE abyIEs[WLAN_BEACON_FR_MAXLEN+WLAN_BEACON_FR_MAXLEN]; + // store ReqIEs set by OID_802_11_ASSOCIATION_INFORMATION + ULONG RequestIELength; + BYTE abyReqIEs[WLAN_BEACON_FR_MAXLEN]; +} SAssocInfo, DEF* PSAssocInfo; +//--- + + +/* +typedef enum tagWMAC_AUTHENTICATION_MODE { + + + WMAC_AUTH_OPEN, + WMAC_AUTH_SHAREKEY, + WMAC_AUTH_AUTO, + WMAC_AUTH_WPA, + WMAC_AUTH_WPAPSK, + WMAC_AUTH_WPANONE, + WMAC_AUTH_WPA2, + WMAC_AUTH_WPA2PSK, + WMAC_AUTH_MAX // Not a real mode, defined as upper bound + + +} WMAC_AUTHENTICATION_MODE, *PWMAC_AUTHENTICATION_MODE; +*/ + + +// Pre-configured Mode (from XP) +/* +typedef enum tagWMAC_CONFIG_MODE { + WMAC_CONFIG_ESS_STA, + WMAC_CONFIG_IBSS_STA, + WMAC_CONFIG_AUTO, + WMAC_CONFIG_AP + +} WMAC_CONFIG_MODE, *PWMAC_CONFIG_MODE; +*/ + +typedef enum tagWMAC_SCAN_TYPE { + + WMAC_SCAN_ACTIVE, + WMAC_SCAN_PASSIVE, + WMAC_SCAN_HYBRID + +} WMAC_SCAN_TYPE, *PWMAC_SCAN_TYPE; + + +typedef enum tagWMAC_SCAN_STATE { + + WMAC_NO_SCANNING, + WMAC_IS_SCANNING, + WMAC_IS_PROBEPENDING + +} WMAC_SCAN_STATE, *PWMAC_SCAN_STATE; + + + +// Notes: +// Basic Service Set state explained as following: +// WMAC_STATE_IDLE : no BSS is selected (Adhoc or Infra) +// WMAC_STATE_STARTED : no BSS is selected, start own IBSS (Adhoc only) +// WMAC_STATE_JOINTED : BSS is selected and synchronized (Adhoc or Infra) +// WMAC_STATE_AUTHPENDING : Authentication pending (Infra) +// WMAC_STATE_AUTH : Authenticated (Infra) +// WMAC_STATE_ASSOCPENDING : Association pending (Infra) +// WMAC_STATE_ASSOC : Associated (Infra) + +typedef enum tagWMAC_BSS_STATE { + + WMAC_STATE_IDLE, + WMAC_STATE_STARTED, + WMAC_STATE_JOINTED, + WMAC_STATE_AUTHPENDING, + WMAC_STATE_AUTH, + WMAC_STATE_ASSOCPENDING, + WMAC_STATE_ASSOC + +} WMAC_BSS_STATE, *PWMAC_BSS_STATE; + +// WMAC selected running mode +typedef enum tagWMAC_CURRENT_MODE { + + WMAC_MODE_STANDBY, + WMAC_MODE_ESS_STA, + WMAC_MODE_IBSS_STA, + WMAC_MODE_ESS_AP + +} WMAC_CURRENT_MODE, *PWMAC_CURRENT_MODE; + +/* +typedef enum tagWMAC_POWER_MODE { + + WMAC_POWER_CAM, + WMAC_POWER_FAST, + WMAC_POWER_MAX + +} WMAC_POWER_MODE, *PWMAC_POWER_MODE; +*/ + + +// Tx Managment Packet descriptor +typedef struct tagSTxMgmtPacket { + + PUWLAN_80211HDR p80211Header; + UINT cbMPDULen; + UINT cbPayloadLen; + +} STxMgmtPacket, DEF* PSTxMgmtPacket; + + +// Rx Managment Packet descriptor +typedef struct tagSRxMgmtPacket { + + PUWLAN_80211HDR p80211Header; + QWORD qwLocalTSF; + UINT cbMPDULen; + UINT cbPayloadLen; + UINT uRSSI; + BYTE bySQ; + BYTE byRxRate; + BYTE byRxChannel; + +} SRxMgmtPacket, DEF* PSRxMgmtPacket; + + + +typedef struct tagSMgmtObject +{ + + PVOID pAdapter; + // MAC address + BYTE abyMACAddr[WLAN_ADDR_LEN]; + + // Configuration Mode + WMAC_CONFIG_MODE eConfigMode; // MAC pre-configed mode + CARD_PHY_TYPE eCurrentPHYMode; + CARD_PHY_TYPE eConfigPHYMode; + + + // Operation state variables + WMAC_CURRENT_MODE eCurrMode; // MAC current connection mode + WMAC_BSS_STATE eCurrState; // MAC current BSS state + + PKnownBSS pCurrBSS; + BYTE byCSSGK; + BYTE byCSSPK; + +// BYTE abyNewSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN]; +// BYTE abyNewExtSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN]; + + // Current state vars + UINT uCurrChannel; + BYTE abyCurrSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1]; + BYTE abyCurrExtSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1]; + BYTE abyCurrSSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1]; + BYTE abyCurrBSSID[WLAN_BSSID_LEN]; + WORD wCurrCapInfo; + WORD wCurrAID; + WORD wCurrATIMWindow; + WORD wCurrBeaconPeriod; + BOOL bIsDS; + BYTE byERPContext; + + CMD_STATE eCommandState; + UINT uScanChannel; + + // Desire joinning BSS vars + BYTE abyDesireSSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1]; + BYTE abyDesireBSSID[WLAN_BSSID_LEN]; + + // Adhoc or AP configuration vars + //BYTE abyAdHocSSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1]; + WORD wIBSSBeaconPeriod; + WORD wIBSSATIMWindow; + UINT uIBSSChannel; + BYTE abyIBSSSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1]; + BYTE byAPBBType; + BYTE abyWPAIE[MAX_WPA_IE_LEN]; + WORD wWPAIELen; + + UINT uAssocCount; + BOOL bMoreData; + + // Scan state vars + WMAC_SCAN_STATE eScanState; + WMAC_SCAN_TYPE eScanType; + UINT uScanStartCh; + UINT uScanEndCh; + WORD wScanSteps; + UINT uScanBSSType; + // Desire scannig vars + BYTE abyScanSSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1]; + BYTE abyScanBSSID[WLAN_BSSID_LEN]; + + // Privacy + WMAC_AUTHENTICATION_MODE eAuthenMode; + WMAC_ENCRYPTION_MODE eEncryptionMode; + BOOL bShareKeyAlgorithm; + BYTE abyChallenge[WLAN_CHALLENGE_LEN]; + BOOL bPrivacyInvoked; + + // Received beacon state vars + BOOL bInTIM; + BOOL bMulticastTIM; + BYTE byDTIMCount; + BYTE byDTIMPeriod; + + // Power saving state vars + WMAC_POWER_MODE ePSMode; + WORD wListenInterval; + WORD wCountToWakeUp; + BOOL bInTIMWake; + PBYTE pbyPSPacketPool; + BYTE byPSPacketPool[sizeof(STxMgmtPacket) + WLAN_NULLDATA_FR_MAXLEN]; + BOOL bRxBeaconInTBTTWake; + BYTE abyPSTxMap[MAX_NODE_NUM + 1]; + + // managment command related + UINT uCmdBusy; + UINT uCmdHostAPBusy; + + // managment packet pool + PBYTE pbyMgmtPacketPool; + BYTE byMgmtPacketPool[sizeof(STxMgmtPacket) + WLAN_A3FR_MAXLEN]; + + + // One second callback timer + struct timer_list sTimerSecondCallback; + + // Temporarily Rx Mgmt Packet Descriptor + SRxMgmtPacket sRxPacket; + + // link list of known bss's (scan results) + KnownBSS sBSSList[MAX_BSS_NUM]; + + + + // table list of known node + // sNodeDBList[0] is reserved for AP under Infra mode + // sNodeDBList[0] is reserved for Multicast under adhoc/AP mode + KnownNodeDB sNodeDBTable[MAX_NODE_NUM + 1]; + + + + // WPA2 PMKID Cache + SPMKIDCache gsPMKIDCache; + BOOL bRoaming; + + // rate fall back vars + + + + // associate info + SAssocInfo sAssocInfo; + + + // for 802.11h + BOOL b11hEnable; + BOOL bSwitchChannel; + BYTE byNewChannel; + PWLAN_IE_MEASURE_REP pCurrMeasureEIDRep; + UINT uLengthOfRepEIDs; + BYTE abyCurrentMSRReq[sizeof(STxMgmtPacket) + WLAN_A3FR_MAXLEN]; + BYTE abyCurrentMSRRep[sizeof(STxMgmtPacket) + WLAN_A3FR_MAXLEN]; + BYTE abyIECountry[WLAN_A3FR_MAXLEN]; + BYTE abyIBSSDFSOwner[6]; + BYTE byIBSSDFSRecovery; + + struct sk_buff skb; + +} SMgmtObject, DEF *PSMgmtObject; + + +/*--------------------- Export Macros ------------------------------*/ + + +/*--------------------- Export Functions --------------------------*/ + + +void +vMgrObjectInit( + IN HANDLE hDeviceContext + ); + +void +vMgrTimerInit( + IN HANDLE hDeviceContext + ); + +VOID +vMgrObjectReset( + IN HANDLE hDeviceContext + ); + +void +vMgrAssocBeginSta( + IN HANDLE hDeviceContext, + IN PSMgmtObject pMgmt, + OUT PCMD_STATUS pStatus + ); + +VOID +vMgrReAssocBeginSta( + IN HANDLE hDeviceContext, + IN PSMgmtObject pMgmt, + OUT PCMD_STATUS pStatus + ); + +VOID +vMgrDisassocBeginSta( + IN HANDLE hDeviceContext, + IN PSMgmtObject pMgmt, + IN PBYTE abyDestAddress, + IN WORD wReason, + OUT PCMD_STATUS pStatus + ); + +VOID +vMgrAuthenBeginSta( + IN HANDLE hDeviceContext, + IN PSMgmtObject pMgmt, + OUT PCMD_STATUS pStatus + ); + +VOID +vMgrCreateOwnIBSS( + IN HANDLE hDeviceContext, + OUT PCMD_STATUS pStatus + ); + +VOID +vMgrJoinBSSBegin( + IN HANDLE hDeviceContext, + OUT PCMD_STATUS pStatus + ); + +VOID +vMgrRxManagePacket( + IN HANDLE hDeviceContext, + IN PSMgmtObject pMgmt, + IN PSRxMgmtPacket pRxPacket + ); + +/* +VOID +vMgrScanBegin( + IN HANDLE hDeviceContext, + OUT PCMD_STATUS pStatus + ); +*/ + +VOID +vMgrDeAuthenBeginSta( + IN HANDLE hDeviceContext, + IN PSMgmtObject pMgmt, + IN PBYTE abyDestAddress, + IN WORD wReason, + OUT PCMD_STATUS pStatus + ); + +BOOL +bMgrPrepareBeaconToSend( + IN HANDLE hDeviceContext, + IN PSMgmtObject pMgmt + ); + + +BOOL +bAdd_PMKID_Candidate ( + IN HANDLE hDeviceContext, + IN PBYTE pbyBSSID, + IN PSRSNCapObject psRSNCapObj + ); + +VOID +vFlush_PMKID_Candidate ( + IN HANDLE hDeviceContext + ); + +#endif // __WMGR_H__ diff --git a/drivers/staging/vt6655/wpa.c b/drivers/staging/vt6655/wpa.c new file mode 100644 index 000000000000..8b4e7fc31efa --- /dev/null +++ b/drivers/staging/vt6655/wpa.c @@ -0,0 +1,339 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * File: wpa.c + * + * Purpose: Handles the Basic Service Set & Node Database functions + * + * Functions: + * WPA_ParseRSN - Parse RSN IE. + * + * Revision History: + * + * Author: Kyle Hsu + * + * Date: July 14, 2003 + * + */ + + +#if !defined(__TTYPE_H__) +#include "ttype.h" +#endif +#if !defined(__UMEM_H__) +#include "umem.h" +#endif +#if !defined(__TMACRO_H__) +#include "tmacro.h" +#endif +#if !defined(__TETHER_H__) +#include "tether.h" +#endif +#if !defined(__DEVICE_H__) +#include "device.h" +#endif +#if !defined(__80211HDR_H__) +#include "80211hdr.h" +#endif +#if !defined(__BSSDB_H__) +#include "bssdb.h" +#endif +#if !defined(__WMGR_H__) +#include "wmgr.h" +#endif +#if !defined(__WPA_H__) +#include "wpa.h" +#endif +#if !defined(__80211MGR_H__) +#include "80211mgr.h" +#endif + + +/*--------------------- Static Variables --------------------------*/ +static int msglevel =MSG_LEVEL_INFO; + +const BYTE abyOUI00[4] = { 0x00, 0x50, 0xf2, 0x00 }; +const BYTE abyOUI01[4] = { 0x00, 0x50, 0xf2, 0x01 }; +const BYTE abyOUI02[4] = { 0x00, 0x50, 0xf2, 0x02 }; +const BYTE abyOUI03[4] = { 0x00, 0x50, 0xf2, 0x03 }; +const BYTE abyOUI04[4] = { 0x00, 0x50, 0xf2, 0x04 }; +const BYTE abyOUI05[4] = { 0x00, 0x50, 0xf2, 0x05 }; + + +/*+ + * + * Description: + * Clear RSN information in BSSList. + * + * Parameters: + * In: + * pBSSList - BSS list. + * Out: + * none + * + * Return Value: none. + * +-*/ + +VOID +WPA_ClearRSN ( + IN PKnownBSS pBSSList + ) +{ + int ii; + pBSSList->byGKType = WPA_TKIP; + for (ii=0; ii < 4; ii ++) + pBSSList->abyPKType[ii] = WPA_TKIP; + pBSSList->wPKCount = 0; + for (ii=0; ii < 4; ii ++) + pBSSList->abyAuthType[ii] = WPA_AUTH_IEEE802_1X; + pBSSList->wAuthCount = 0; + pBSSList->byDefaultK_as_PK = 0; + pBSSList->byReplayIdx = 0; + pBSSList->sRSNCapObj.bRSNCapExist = FALSE; + pBSSList->sRSNCapObj.wRSNCap = 0; + pBSSList->bWPAValid = FALSE; +} + + +/*+ + * + * Description: + * Parse RSN IE. + * + * Parameters: + * In: + * pBSSList - BSS list. + * pRSN - Pointer to the RSN IE. + * Out: + * none + * + * Return Value: none. + * +-*/ +VOID +WPA_ParseRSN ( + IN PKnownBSS pBSSList, + IN PWLAN_IE_RSN_EXT pRSN + ) +{ + PWLAN_IE_RSN_AUTH pIE_RSN_Auth = NULL; + int i, j, m, n = 0; + PBYTE pbyCaps; + + WPA_ClearRSN(pBSSList); + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"WPA_ParseRSN: [%d]\n", pRSN->len); + + // information element header makes sense + if ((pRSN->len >= 6) // oui1(4)+ver(2) + && (pRSN->byElementID == WLAN_EID_RSN_WPA) && MEMEqualMemory(pRSN->abyOUI, abyOUI01, 4) + && (pRSN->wVersion == 1)) { + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Legal RSN\n"); + // update each variable if pRSN is long enough to contain the variable + if (pRSN->len >= 10) //oui1(4)+ver(2)+GKSuite(4) + { + if (MEMEqualMemory(pRSN->abyMulticast, abyOUI01, 4)) + pBSSList->byGKType = WPA_WEP40; + else if (MEMEqualMemory(pRSN->abyMulticast, abyOUI02, 4)) + pBSSList->byGKType = WPA_TKIP; + else if (MEMEqualMemory(pRSN->abyMulticast, abyOUI03, 4)) + pBSSList->byGKType = WPA_AESWRAP; + else if (MEMEqualMemory(pRSN->abyMulticast, abyOUI04, 4)) + pBSSList->byGKType = WPA_AESCCMP; + else if (MEMEqualMemory(pRSN->abyMulticast, abyOUI05, 4)) + pBSSList->byGKType = WPA_WEP104; + else + // any vendor checks here + pBSSList->byGKType = WPA_NONE; + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"byGKType: %x\n", pBSSList->byGKType); + } + + if (pRSN->len >= 12) //oui1(4)+ver(2)+GKS(4)+PKSCnt(2) + { + j = 0; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"wPKCount: %d, sizeof(pBSSList->abyPKType): %d\n", pRSN->wPKCount, sizeof(pBSSList->abyPKType)); + for(i = 0; (i < pRSN->wPKCount) && (j < sizeof(pBSSList->abyPKType)/sizeof(BYTE)); i++) { + if(pRSN->len >= 12+i*4+4) { //oui1(4)+ver(2)+GKS(4)+PKSCnt(2)+PKS(4*i) + if (MEMEqualMemory(pRSN->PKSList[i].abyOUI, abyOUI00, 4)) + pBSSList->abyPKType[j++] = WPA_NONE; + else if (MEMEqualMemory(pRSN->PKSList[i].abyOUI, abyOUI02, 4)) + pBSSList->abyPKType[j++] = WPA_TKIP; + else if (MEMEqualMemory(pRSN->PKSList[i].abyOUI, abyOUI03, 4)) + pBSSList->abyPKType[j++] = WPA_AESWRAP; + else if (MEMEqualMemory(pRSN->PKSList[i].abyOUI, abyOUI04, 4)) + pBSSList->abyPKType[j++] = WPA_AESCCMP; + else + // any vendor checks here + ; + } + else + break; + //DBG_PRN_GRP14(("abyPKType[%d]: %X\n", j-1, pBSSList->abyPKType[j-1])); + } //for + pBSSList->wPKCount = (WORD)j; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"wPKCount: %d\n", pBSSList->wPKCount); + } + + m = pRSN->wPKCount; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"m: %d\n", m); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"14+m*4: %d\n", 14+m*4); + + if (pRSN->len >= 14+m*4) { //oui1(4)+ver(2)+GKS(4)+PKSCnt(2)+PKS(4*m)+AKC(2) + // overlay IE_RSN_Auth structure into correct place + pIE_RSN_Auth = (PWLAN_IE_RSN_AUTH) pRSN->PKSList[m].abyOUI; + j = 0; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"wAuthCount: %d, sizeof(pBSSList->abyAuthType): %d\n", + pIE_RSN_Auth->wAuthCount, sizeof(pBSSList->abyAuthType)); + for(i = 0; (i < pIE_RSN_Auth->wAuthCount) && (j < sizeof(pBSSList->abyAuthType)/sizeof(BYTE)); i++) { + if(pRSN->len >= 14+4+(m+i)*4) { //oui1(4)+ver(2)+GKS(4)+PKSCnt(2)+PKS(4*m)+AKC(2)+AKS(4*i) + if (MEMEqualMemory(pIE_RSN_Auth->AuthKSList[i].abyOUI, abyOUI01, 4)) + pBSSList->abyAuthType[j++] = WPA_AUTH_IEEE802_1X; + else if (MEMEqualMemory(pIE_RSN_Auth->AuthKSList[i].abyOUI, abyOUI02, 4)) + pBSSList->abyAuthType[j++] = WPA_AUTH_PSK; + else + // any vendor checks here + ; + } + else + break; + //DBG_PRN_GRP14(("abyAuthType[%d]: %X\n", j-1, pBSSList->abyAuthType[j-1])); + } + if(j > 0) + pBSSList->wAuthCount = (WORD)j; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"wAuthCount: %d\n", pBSSList->wAuthCount); + } + + if (pIE_RSN_Auth != NULL) { + + n = pIE_RSN_Auth->wAuthCount; + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"n: %d\n", n); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"14+4+(m+n)*4: %d\n", 14+4+(m+n)*4); + + if(pRSN->len+2 >= 14+4+(m+n)*4) { //oui1(4)+ver(2)+GKS(4)+PKSCnt(2)+PKS(4*m)+AKC(2)+AKS(4*n)+Cap(2) + pbyCaps = (PBYTE)pIE_RSN_Auth->AuthKSList[n].abyOUI; + pBSSList->byDefaultK_as_PK = (*pbyCaps) & WPA_GROUPFLAG; + pBSSList->byReplayIdx = 2 << ((*pbyCaps >> WPA_REPLAYBITSSHIFT) & WPA_REPLAYBITS); + pBSSList->sRSNCapObj.bRSNCapExist = TRUE; + pBSSList->sRSNCapObj.wRSNCap = *(PWORD)pbyCaps; + //DBG_PRN_GRP14(("pbyCaps: %X\n", *pbyCaps)); + //DBG_PRN_GRP14(("byDefaultK_as_PK: %X\n", pBSSList->byDefaultK_as_PK)); + //DBG_PRN_GRP14(("byReplayIdx: %X\n", pBSSList->byReplayIdx)); + } + } + pBSSList->bWPAValid = TRUE; + } +} + +/*+ + * + * Description: + * Search RSN information in BSSList. + * + * Parameters: + * In: + * byCmd - Search type + * byEncrypt- Encrcypt Type + * pBSSList - BSS list + * Out: + * none + * + * Return Value: none. + * +-*/ +BOOL +WPA_SearchRSN ( + BYTE byCmd, + BYTE byEncrypt, + IN PKnownBSS pBSSList + ) +{ + int ii; + BYTE byPKType = WPA_NONE; + + if (pBSSList->bWPAValid == FALSE) + return FALSE; + + switch(byCmd) { + case 0: + + if (byEncrypt != pBSSList->byGKType) + return FALSE; + + if (pBSSList->wPKCount > 0) { + for (ii = 0; ii < pBSSList->wPKCount; ii ++) { + if (pBSSList->abyPKType[ii] == WPA_AESCCMP) + byPKType = WPA_AESCCMP; + else if ((pBSSList->abyPKType[ii] == WPA_TKIP) && (byPKType != WPA_AESCCMP)) + byPKType = WPA_TKIP; + else if ((pBSSList->abyPKType[ii] == WPA_WEP40) && (byPKType != WPA_AESCCMP) && (byPKType != WPA_TKIP)) + byPKType = WPA_WEP40; + else if ((pBSSList->abyPKType[ii] == WPA_WEP104) && (byPKType != WPA_AESCCMP) && (byPKType != WPA_TKIP)) + byPKType = WPA_WEP104; + } + if (byEncrypt != byPKType) + return FALSE; + } + return TRUE; +// if (pBSSList->wAuthCount > 0) +// for (ii=0; ii < pBSSList->wAuthCount; ii ++) +// if (byAuth == pBSSList->abyAuthType[ii]) +// break; + break; + + default: + break; + } + return FALSE; +} + +/*+ + * + * Description: + * Check if RSN IE makes sense. + * + * Parameters: + * In: + * pRSN - Pointer to the RSN IE. + * Out: + * none + * + * Return Value: none. + * +-*/ +BOOL +WPAb_Is_RSN ( + IN PWLAN_IE_RSN_EXT pRSN + ) +{ + if (pRSN == NULL) + return FALSE; + + if ((pRSN->len >= 6) && // oui1(4)+ver(2) + (pRSN->byElementID == WLAN_EID_RSN_WPA) && MEMEqualMemory(pRSN->abyOUI, abyOUI01, 4) && + (pRSN->wVersion == 1)) { + return TRUE; + } + else + return FALSE; +} + diff --git a/drivers/staging/vt6655/wpa.h b/drivers/staging/vt6655/wpa.h new file mode 100644 index 000000000000..8000a37c6fc3 --- /dev/null +++ b/drivers/staging/vt6655/wpa.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * File: wpa.h + * + * Purpose: Defines the macros, types, and functions for dealing + * with WPA informations. + * + * Author: Kyle Hsu + * + * Date: Jul 14, 2003 + * + */ + +#ifndef __WPA_H__ +#define __WPA_H__ + + +#if !defined(__TTYPE_H__) +#include "ttype.h" +#endif +#if !defined(__80211HDR_H__) +#include "80211hdr.h" +#endif + + +/*--------------------- Export Definitions -------------------------*/ + +#define WPA_NONE 0 +#define WPA_WEP40 1 +#define WPA_TKIP 2 +#define WPA_AESWRAP 3 +#define WPA_AESCCMP 4 +#define WPA_WEP104 5 +#define WPA_AUTH_IEEE802_1X 1 +#define WPA_AUTH_PSK 2 + +#define WPA_GROUPFLAG 0x02 +#define WPA_REPLAYBITSSHIFT 2 +#define WPA_REPLAYBITS 0x03 + +/*--------------------- Export Classes ----------------------------*/ + +/*--------------------- Export Variables --------------------------*/ + +/*--------------------- Export Types ------------------------------*/ + + +/*--------------------- Export Functions --------------------------*/ +#ifdef __cplusplus +extern "C" { /* Assume C declarations for C++ */ +#endif /* __cplusplus */ + +VOID +WPA_ClearRSN( + IN PKnownBSS pBSSList + ); + +VOID +WPA_ParseRSN( + IN PKnownBSS pBSSList, + IN PWLAN_IE_RSN_EXT pRSN + ); + +BOOL +WPA_SearchRSN( + BYTE byCmd, + BYTE byEncrypt, + IN PKnownBSS pBSSList + ); + +BOOL +WPAb_Is_RSN( + IN PWLAN_IE_RSN_EXT pRSN + ); + +#ifdef __cplusplus +} /* End of extern "C" { */ +#endif /* __cplusplus */ + + +#endif // __WPA_H__ diff --git a/drivers/staging/vt6655/wpa2.c b/drivers/staging/vt6655/wpa2.c new file mode 100644 index 000000000000..e2fdb331069e --- /dev/null +++ b/drivers/staging/vt6655/wpa2.c @@ -0,0 +1,373 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * File: wpa2.c + * + * Purpose: Handles the Basic Service Set & Node Database functions + * + * Functions: + * + * Revision History: + * + * Author: Yiching Chen + * + * Date: Oct. 4, 2004 + * + */ +#if !defined(__WPA2_H__) +#include "wpa2.h" +#endif +#if !defined(__UMEM_H__) +#include "umem.h" +#endif +#if !defined(__DEVICE_H__) +#include "device.h" +#endif +#if !defined(__WMGR_H__) +#include "wmgr.h" +#endif + + +/*--------------------- Static Definitions -------------------------*/ +static int msglevel =MSG_LEVEL_INFO; +//static int msglevel =MSG_LEVEL_DEBUG; +/*--------------------- Static Classes ----------------------------*/ + +/*--------------------- Static Variables --------------------------*/ + +const BYTE abyOUIGK[4] = { 0x00, 0x0F, 0xAC, 0x00 }; +const BYTE abyOUIWEP40[4] = { 0x00, 0x0F, 0xAC, 0x01 }; +const BYTE abyOUIWEP104[4] = { 0x00, 0x0F, 0xAC, 0x05 }; +const BYTE abyOUITKIP[4] = { 0x00, 0x0F, 0xAC, 0x02 }; +const BYTE abyOUICCMP[4] = { 0x00, 0x0F, 0xAC, 0x04 }; + +const BYTE abyOUI8021X[4] = { 0x00, 0x0F, 0xAC, 0x01 }; +const BYTE abyOUIPSK[4] = { 0x00, 0x0F, 0xAC, 0x02 }; + + +/*--------------------- Static Functions --------------------------*/ + +/*--------------------- Export Variables --------------------------*/ + +/*--------------------- Export Functions --------------------------*/ + +/*+ + * + * Description: + * Clear RSN information in BSSList. + * + * Parameters: + * In: + * pBSSNode - BSS list. + * Out: + * none + * + * Return Value: none. + * +-*/ +VOID +WPA2_ClearRSN ( + IN PKnownBSS pBSSNode + ) +{ + int ii; + + pBSSNode->bWPA2Valid = FALSE; + + pBSSNode->byCSSGK = WLAN_11i_CSS_CCMP; + for (ii=0; ii < 4; ii ++) + pBSSNode->abyCSSPK[ii] = WLAN_11i_CSS_CCMP; + pBSSNode->wCSSPKCount = 1; + for (ii=0; ii < 4; ii ++) + pBSSNode->abyAKMSSAuthType[ii] = WLAN_11i_AKMSS_802_1X; + pBSSNode->wAKMSSAuthCount = 1; + pBSSNode->sRSNCapObj.bRSNCapExist = FALSE; + pBSSNode->sRSNCapObj.wRSNCap = 0; +} + +/*+ + * + * Description: + * Parse RSN IE. + * + * Parameters: + * In: + * pBSSNode - BSS list. + * pRSN - Pointer to the RSN IE. + * Out: + * none + * + * Return Value: none. + * +-*/ +VOID +WPA2vParseRSN ( + IN PKnownBSS pBSSNode, + IN PWLAN_IE_RSN pRSN + ) +{ + int i, j; + WORD m = 0, n = 0; + PBYTE pbyOUI; + BOOL bUseGK = FALSE; + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"WPA2_ParseRSN: [%d]\n", pRSN->len); + + WPA2_ClearRSN(pBSSNode); + + if (pRSN->len == 2) { // ver(2) + if ((pRSN->byElementID == WLAN_EID_RSN) && (pRSN->wVersion == 1)) { + pBSSNode->bWPA2Valid = TRUE; + } + return; + } + + if (pRSN->len < 6) { // ver(2) + GK(4) + // invalid CSS, P802.11i/D10.0, p31 + return; + } + + // information element header makes sense + if ((pRSN->byElementID == WLAN_EID_RSN) && + (pRSN->wVersion == 1)) { + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Legal 802.11i RSN\n"); + + pbyOUI = &(pRSN->abyRSN[0]); + if (MEMEqualMemory(pbyOUI, abyOUIWEP40, 4)) + pBSSNode->byCSSGK = WLAN_11i_CSS_WEP40; + else if (MEMEqualMemory(pbyOUI, abyOUITKIP, 4)) + pBSSNode->byCSSGK = WLAN_11i_CSS_TKIP; + else if (MEMEqualMemory(pbyOUI, abyOUICCMP, 4)) + pBSSNode->byCSSGK = WLAN_11i_CSS_CCMP; + else if (MEMEqualMemory(pbyOUI, abyOUIWEP104, 4)) + pBSSNode->byCSSGK = WLAN_11i_CSS_WEP104; + else if (MEMEqualMemory(pbyOUI, abyOUIGK, 4)) { + // invalid CSS, P802.11i/D10.0, p32 + return; + } else + // any vendor checks here + pBSSNode->byCSSGK = WLAN_11i_CSS_UNKNOWN; + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"802.11i CSS: %X\n", pBSSNode->byCSSGK); + + if (pRSN->len == 6) { + pBSSNode->bWPA2Valid = TRUE; + return; + } + + if (pRSN->len >= 8) { // ver(2) + GK(4) + PK count(2) + pBSSNode->wCSSPKCount = *((PWORD) &(pRSN->abyRSN[4])); + j = 0; + pbyOUI = &(pRSN->abyRSN[6]); + + for (i = 0; (i < pBSSNode->wCSSPKCount) && (j < sizeof(pBSSNode->abyCSSPK)/sizeof(BYTE)); i++) { + + if (pRSN->len >= 8+i*4+4) { // ver(2)+GK(4)+PKCnt(2)+PKS(4*i) + if (MEMEqualMemory(pbyOUI, abyOUIGK, 4)) { + pBSSNode->abyCSSPK[j++] = WLAN_11i_CSS_USE_GROUP; + bUseGK = TRUE; + } else if (MEMEqualMemory(pbyOUI, abyOUIWEP40, 4)) { + // Invialid CSS, continue to parsing + } else if (MEMEqualMemory(pbyOUI, abyOUITKIP, 4)) { + if (pBSSNode->byCSSGK != WLAN_11i_CSS_CCMP) + pBSSNode->abyCSSPK[j++] = WLAN_11i_CSS_TKIP; + else + ; // Invialid CSS, continue to parsing + } else if (MEMEqualMemory(pbyOUI, abyOUICCMP, 4)) { + pBSSNode->abyCSSPK[j++] = WLAN_11i_CSS_CCMP; + } else if (MEMEqualMemory(pbyOUI, abyOUIWEP104, 4)) { + // Invialid CSS, continue to parsing + } else { + // any vendor checks here + pBSSNode->abyCSSPK[j++] = WLAN_11i_CSS_UNKNOWN; + } + pbyOUI += 4; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"abyCSSPK[%d]: %X\n", j-1, pBSSNode->abyCSSPK[j-1]); + } else + break; + } //for + + if (bUseGK == TRUE) { + if (j != 1) { + // invalid CSS, This should be only PK CSS. + return; + } + if (pBSSNode->byCSSGK == WLAN_11i_CSS_CCMP) { + // invalid CSS, If CCMP is enable , PK can't be CSSGK. + return; + } + } + if ((pBSSNode->wCSSPKCount != 0) && (j == 0)) { + // invalid CSS, No valid PK. + return; + } + pBSSNode->wCSSPKCount = (WORD)j; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"wCSSPKCount: %d\n", pBSSNode->wCSSPKCount); + } + + m = *((PWORD) &(pRSN->abyRSN[4])); + + if (pRSN->len >= 10+m*4) { // ver(2) + GK(4) + PK count(2) + PKS(4*m) + AKMSS count(2) + pBSSNode->wAKMSSAuthCount = *((PWORD) &(pRSN->abyRSN[6+4*m]));; + j = 0; + pbyOUI = &(pRSN->abyRSN[8+4*m]); + for (i = 0; (i < pBSSNode->wAKMSSAuthCount) && (j < sizeof(pBSSNode->abyAKMSSAuthType)/sizeof(BYTE)); i++) { + if (pRSN->len >= 10+(m+i)*4+4) { // ver(2)+GK(4)+PKCnt(2)+PKS(4*m)+AKMSS(2)+AKS(4*i) + if (MEMEqualMemory(pbyOUI, abyOUI8021X, 4)) + pBSSNode->abyAKMSSAuthType[j++] = WLAN_11i_AKMSS_802_1X; + else if (MEMEqualMemory(pbyOUI, abyOUIPSK, 4)) + pBSSNode->abyAKMSSAuthType[j++] = WLAN_11i_AKMSS_PSK; + else + // any vendor checks here + pBSSNode->abyAKMSSAuthType[j++] = WLAN_11i_AKMSS_UNKNOWN; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"abyAKMSSAuthType[%d]: %X\n", j-1, pBSSNode->abyAKMSSAuthType[j-1]); + } else + break; + } + pBSSNode->wAKMSSAuthCount = (WORD)j; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO"wAKMSSAuthCount: %d\n", pBSSNode->wAKMSSAuthCount); + + n = *((PWORD) &(pRSN->abyRSN[6+4*m]));; + if (pRSN->len >= 12+4*m+4*n) { // ver(2)+GK(4)+PKCnt(2)+PKS(4*m)+AKMSSCnt(2)+AKMSS(4*n)+Cap(2) + pBSSNode->sRSNCapObj.bRSNCapExist = TRUE; + pBSSNode->sRSNCapObj.wRSNCap = *((PWORD) &(pRSN->abyRSN[8+4*m+4*n])); + } + } + //ignore PMKID lists bcs only (Re)Assocrequest has this field + pBSSNode->bWPA2Valid = TRUE; + } +} + + +/*+ + * + * Description: + * Set WPA IEs + * + * Parameters: + * In: + * pMgmtHandle - Pointer to management object + * Out: + * pRSNIEs - Pointer to the RSN IE to set. + * + * Return Value: length of IEs. + * +-*/ +UINT +WPA2uSetIEs( + IN PVOID pMgmtHandle, + OUT PWLAN_IE_RSN pRSNIEs + ) +{ + PSMgmtObject pMgmt = (PSMgmtObject) pMgmtHandle; + PBYTE pbyBuffer = NULL; + UINT ii = 0; + PWORD pwPMKID = NULL; + + if (pRSNIEs == NULL) { + return(0); + } + if (((pMgmt->eAuthenMode == WMAC_AUTH_WPA2) || + (pMgmt->eAuthenMode == WMAC_AUTH_WPA2PSK)) && + (pMgmt->pCurrBSS != NULL)) { + /* WPA2 IE */ + pbyBuffer = (PBYTE) pRSNIEs; + pRSNIEs->byElementID = WLAN_EID_RSN; + pRSNIEs->len = 6; //Version(2)+GK(4) + pRSNIEs->wVersion = 1; + //Group Key Cipher Suite + pRSNIEs->abyRSN[0] = 0x00; + pRSNIEs->abyRSN[1] = 0x0F; + pRSNIEs->abyRSN[2] = 0xAC; + if (pMgmt->byCSSGK == KEY_CTL_WEP) { + pRSNIEs->abyRSN[3] = pMgmt->pCurrBSS->byCSSGK; + } else if (pMgmt->byCSSGK == KEY_CTL_TKIP) { + pRSNIEs->abyRSN[3] = WLAN_11i_CSS_TKIP; + } else if (pMgmt->byCSSGK == KEY_CTL_CCMP) { + pRSNIEs->abyRSN[3] = WLAN_11i_CSS_CCMP; + } else { + pRSNIEs->abyRSN[3] = WLAN_11i_CSS_UNKNOWN; + } + + // Pairwise Key Cipher Suite + pRSNIEs->abyRSN[4] = 1; + pRSNIEs->abyRSN[5] = 0; + pRSNIEs->abyRSN[6] = 0x00; + pRSNIEs->abyRSN[7] = 0x0F; + pRSNIEs->abyRSN[8] = 0xAC; + if (pMgmt->byCSSPK == KEY_CTL_TKIP) { + pRSNIEs->abyRSN[9] = WLAN_11i_CSS_TKIP; + } else if (pMgmt->byCSSPK == KEY_CTL_CCMP) { + pRSNIEs->abyRSN[9] = WLAN_11i_CSS_CCMP; + } else if (pMgmt->byCSSPK == KEY_CTL_NONE) { + pRSNIEs->abyRSN[9] = WLAN_11i_CSS_USE_GROUP; + } else { + pRSNIEs->abyRSN[9] = WLAN_11i_CSS_UNKNOWN; + } + pRSNIEs->len += 6; + + // Auth Key Management Suite + pRSNIEs->abyRSN[10] = 1; + pRSNIEs->abyRSN[11] = 0; + pRSNIEs->abyRSN[12] = 0x00; + pRSNIEs->abyRSN[13] = 0x0F; + pRSNIEs->abyRSN[14] = 0xAC; + if (pMgmt->eAuthenMode == WMAC_AUTH_WPA2PSK) { + pRSNIEs->abyRSN[15] = WLAN_11i_AKMSS_PSK; + } else if (pMgmt->eAuthenMode == WMAC_AUTH_WPA2) { + pRSNIEs->abyRSN[15] = WLAN_11i_AKMSS_802_1X; + } else { + pRSNIEs->abyRSN[15] = WLAN_11i_AKMSS_UNKNOWN; + } + pRSNIEs->len +=6; + + // RSN Capabilites + if (pMgmt->pCurrBSS->sRSNCapObj.bRSNCapExist == TRUE) { + MEMvCopy(&pRSNIEs->abyRSN[16], &pMgmt->pCurrBSS->sRSNCapObj.wRSNCap, 2); + } else { + pRSNIEs->abyRSN[16] = 0; + pRSNIEs->abyRSN[17] = 0; + } + pRSNIEs->len +=2; + + if ((pMgmt->gsPMKIDCache.BSSIDInfoCount > 0) && + (pMgmt->bRoaming == TRUE) && + (pMgmt->eAuthenMode == WMAC_AUTH_WPA2)) { + // RSN PMKID + pwPMKID = (PWORD)(&pRSNIEs->abyRSN[18]); // Point to PMKID count + *pwPMKID = 0; // Initialize PMKID count + pbyBuffer = &pRSNIEs->abyRSN[20]; // Point to PMKID list + for (ii = 0; ii < pMgmt->gsPMKIDCache.BSSIDInfoCount; ii++) { + if (MEMEqualMemory(&pMgmt->gsPMKIDCache.BSSIDInfo[ii].abyBSSID[0], pMgmt->abyCurrBSSID, U_ETHER_ADDR_LEN)) { + (*pwPMKID) ++; + MEMvCopy(pbyBuffer, pMgmt->gsPMKIDCache.BSSIDInfo[ii].abyPMKID, 16); + pbyBuffer += 16; + } + } + if (*pwPMKID != 0) { + pRSNIEs->len += (2 + (*pwPMKID)*16); + } else { + pbyBuffer = &pRSNIEs->abyRSN[18]; + } + } + return(pRSNIEs->len + WLAN_IEHDR_LEN); + } + return(0); +} diff --git a/drivers/staging/vt6655/wpa2.h b/drivers/staging/vt6655/wpa2.h new file mode 100644 index 000000000000..bda045b313b9 --- /dev/null +++ b/drivers/staging/vt6655/wpa2.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * File: wpa2.h + * + * Purpose: Defines the macros, types, and functions for dealing + * with WPA2 informations. + * + * Author: Yiching Chen + * + * Date: Oct. 4, 2004 + * + */ + +#ifndef __WPA2_H__ +#define __WPA2_H__ + + +#if !defined(__TTYPE_H__) +#include "ttype.h" +#endif +#if !defined(__80211MGR_H__) +#include "80211mgr.h" +#endif +#if !defined(__80211HDR_H__) +#include "80211hdr.h" +#endif +#if !defined(__BSSDB_H__) +#include "bssdb.h" +#endif +#if !defined(__VNTWIFI_H__) +#include "vntwifi.h" +#endif + + + +/*--------------------- Export Definitions -------------------------*/ + +typedef struct tagsPMKIDInfo { + BYTE abyBSSID[6]; + BYTE abyPMKID[16]; +} PMKIDInfo, *PPMKIDInfo; + +typedef struct tagSPMKIDCache { + ULONG BSSIDInfoCount; + PMKIDInfo BSSIDInfo[MAX_PMKID_CACHE]; +} SPMKIDCache, *PSPMKIDCache; + + +/*--------------------- Export Classes ----------------------------*/ + +/*--------------------- Export Variables --------------------------*/ + +/*--------------------- Export Types ------------------------------*/ + +/*--------------------- Export Functions --------------------------*/ +#ifdef __cplusplus +extern "C" { /* Assume C declarations for C++ */ +#endif /* __cplusplus */ + +VOID +WPA2_ClearRSN ( + IN PKnownBSS pBSSNode + ); + +VOID +WPA2vParseRSN ( + IN PKnownBSS pBSSNode, + IN PWLAN_IE_RSN pRSN + ); + +UINT +WPA2uSetIEs( + IN PVOID pMgmtHandle, + OUT PWLAN_IE_RSN pRSNIEs + ); + + +#ifdef __cplusplus +} /* End of extern "C" { */ +#endif /* __cplusplus */ + + +#endif // __WPA2_H__ diff --git a/drivers/staging/vt6655/wpactl.c b/drivers/staging/vt6655/wpactl.c new file mode 100644 index 000000000000..cc4f0adb963e --- /dev/null +++ b/drivers/staging/vt6655/wpactl.c @@ -0,0 +1,1017 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * File: wpactl.c + * + * Purpose: handle wpa supplicant ioctl input/out functions + * + * Author: Lyndon Chen + * + * Date: Oct. 20, 2003 + * + * Functions: + * + * Revision History: + * + */ + + +#if !defined(__WPACTL_H__) +#include "wpactl.h" +#endif +#if !defined(__KEY_H__) +#include "key.h" +#endif +#if !defined(__MAC_H__) +#include "mac.h" +#endif +#if !defined(__DEVICE_H__) +#include "device.h" +#endif +#if !defined(__WMGR_H__) +#include "wmgr.h" +#endif +#if !defined(__IOCMD_H__) +#include "iocmd.h" +#endif +#if !defined(__IOWPA_H__) +#include "iowpa.h" +#endif +//2008-0717-05, by James +#if !defined(__RF_H__) +#include "rf.h" +#endif + +/*--------------------- Static Definitions -------------------------*/ + +#define VIAWGET_WPA_MAX_BUF_SIZE 1024 + + + +static const int frequency_list[] = { + 2412, 2417, 2422, 2427, 2432, 2437, 2442, + 2447, 2452, 2457, 2462, 2467, 2472, 2484 +}; +/*--------------------- Static Classes ----------------------------*/ + +/*--------------------- Static Variables --------------------------*/ +//static int msglevel =MSG_LEVEL_DEBUG; +static int msglevel =MSG_LEVEL_INFO; + +/*--------------------- Static Functions --------------------------*/ + + + + +/*--------------------- Export Variables --------------------------*/ + + +static void wpadev_setup(struct net_device *dev) +{ + dev->type = ARPHRD_IEEE80211; + dev->hard_header_len = ETH_HLEN; + dev->mtu = 2048; + dev->addr_len = ETH_ALEN; + dev->tx_queue_len = 1000; + + memset(dev->broadcast,0xFF, ETH_ALEN); + + dev->flags = IFF_BROADCAST|IFF_MULTICAST; +} + + + +/* + * Description: + * register netdev for wpa supplicant deamon + * + * Parameters: + * In: + * pDevice - + * enable - + * Out: + * + * Return Value: + * + */ + +static int wpa_init_wpadev(PSDevice pDevice) +{ + PSDevice wpadev_priv; + struct net_device *dev = pDevice->dev; + int ret=0; + + pDevice->wpadev = alloc_netdev(sizeof(PSDevice), "vntwpa", wpadev_setup); + if (pDevice->wpadev == NULL) + return -ENOMEM; + + wpadev_priv = netdev_priv(pDevice->wpadev); + *wpadev_priv = *pDevice; + + memcpy(pDevice->wpadev->dev_addr, dev->dev_addr, U_ETHER_ADDR_LEN); + pDevice->wpadev->base_addr = dev->base_addr; + pDevice->wpadev->irq = dev->irq; + pDevice->wpadev->mem_start = dev->mem_start; + pDevice->wpadev->mem_end = dev->mem_end; + ret = register_netdev(pDevice->wpadev); + if (ret) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%s: register_netdev(WPA) failed!\n", + dev->name); + free_netdev(pDevice->wpadev); + return -1; + } + + if (pDevice->skb == NULL) { + pDevice->skb = dev_alloc_skb((int)pDevice->rx_buf_sz); + if (pDevice->skb == NULL) + return -ENOMEM; + } + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%s: Registered netdev %s for WPA management\n", + dev->name, pDevice->wpadev->name); + + return 0; +} + + +/* + * Description: + * unregister net_device (wpadev) + * + * Parameters: + * In: + * pDevice - + * Out: + * + * Return Value: + * + */ + +static int wpa_release_wpadev(PSDevice pDevice) +{ + + if (pDevice->skb) { + dev_kfree_skb(pDevice->skb); + pDevice->skb = NULL; + } + + if (pDevice->wpadev) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%s: Netdevice %s unregistered\n", + pDevice->dev->name, pDevice->wpadev->name); + unregister_netdev(pDevice->wpadev); + free_netdev(pDevice->wpadev); + pDevice->wpadev = NULL; + } + + return 0; +} + + + + + +/* + * Description: + * Set enable/disable dev for wpa supplicant deamon + * + * Parameters: + * In: + * pDevice - + * val - + * Out: + * + * Return Value: + * + */ + +int wpa_set_wpadev(PSDevice pDevice, int val) +{ + + + if (val) + return wpa_init_wpadev(pDevice); + else + return wpa_release_wpadev(pDevice); +} + + +/* + * Description: + * Set WPA algorithm & keys + * + * Parameters: + * In: + * pDevice - + * param - + * Out: + * + * Return Value: + * + */ + +int wpa_set_keys(PSDevice pDevice, void *ctx, BOOL fcpfkernel) +{ + struct viawget_wpa_param *param=ctx; + PSMgmtObject pMgmt = pDevice->pMgmt; + DWORD dwKeyIndex = 0; + BYTE abyKey[MAX_KEY_LEN]; + BYTE abySeq[MAX_KEY_LEN]; + QWORD KeyRSC; +// NDIS_802_11_KEY_RSC KeyRSC; + BYTE byKeyDecMode = KEY_CTL_WEP; + int ret = 0; + int uu, ii; + + + if (param->u.wpa_key.alg_name > WPA_ALG_CCMP) + return -EINVAL; + + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "param->u.wpa_key.alg_name = %d \n", param->u.wpa_key.alg_name); + if (param->u.wpa_key.alg_name == WPA_ALG_NONE) { + pDevice->eEncryptionStatus = Ndis802_11EncryptionDisabled; + pDevice->bEncryptionEnable = FALSE; + pDevice->byKeyIndex = 0; + pDevice->bTransmitKey = FALSE; + KeyvRemoveAllWEPKey(&(pDevice->sKey), pDevice->PortOffset); + for (uu=0; uuPortOffset, uu); + } + return ret; + } + + //spin_unlock_irq(&pDevice->lock); + if(param->u.wpa_key.key && fcpfkernel) { + memcpy(&abyKey[0], param->u.wpa_key.key, param->u.wpa_key.key_len); + } + else { + spin_unlock_irq(&pDevice->lock); + if (param->u.wpa_key.key && + copy_from_user(&abyKey[0], param->u.wpa_key.key, param->u.wpa_key.key_len)){ + spin_lock_irq(&pDevice->lock); + return -EINVAL; + } +spin_lock_irq(&pDevice->lock); + } + + dwKeyIndex = (DWORD)(param->u.wpa_key.key_index); + + if (param->u.wpa_key.alg_name == WPA_ALG_WEP) { + if (dwKeyIndex > 3) { + return -EINVAL; + } + else { + if (param->u.wpa_key.set_tx) { + pDevice->byKeyIndex = (BYTE)dwKeyIndex; + pDevice->bTransmitKey = TRUE; + dwKeyIndex |= (1 << 31); + } + KeybSetDefaultKey(&(pDevice->sKey), + dwKeyIndex & ~(BIT30 | USE_KEYRSC), + param->u.wpa_key.key_len, + NULL, + abyKey, + KEY_CTL_WEP, + pDevice->PortOffset, + pDevice->byLocalID); + + } + pDevice->eEncryptionStatus = Ndis802_11Encryption1Enabled; + pDevice->bEncryptionEnable = TRUE; + return ret; + } + + //spin_unlock_irq(&pDevice->lock); + if(param->u.wpa_key.seq && fcpfkernel) { + memcpy(&abySeq[0], param->u.wpa_key.seq, param->u.wpa_key.seq_len); + } + else { + spin_unlock_irq(&pDevice->lock); + if (param->u.wpa_key.seq && + copy_from_user(&abySeq[0], param->u.wpa_key.seq, param->u.wpa_key.seq_len)){ + + spin_lock_irq(&pDevice->lock); + return -EINVAL; + } +spin_lock_irq(&pDevice->lock); +} + + if (param->u.wpa_key.seq_len > 0) { + for (ii = 0 ; ii < param->u.wpa_key.seq_len ; ii++) { + if (ii < 4) + LODWORD(KeyRSC) |= (abySeq[ii] << (ii * 8)); + else + HIDWORD(KeyRSC) |= (abySeq[ii] << ((ii-4) * 8)); + //KeyRSC |= (abySeq[ii] << (ii * 8)); + } + dwKeyIndex |= 1 << 29; + } + + if (param->u.wpa_key.key_index >= MAX_GROUP_KEY) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "return dwKeyIndex > 3\n"); + return -EINVAL; + } + + if (param->u.wpa_key.alg_name == WPA_ALG_TKIP) { + pDevice->eEncryptionStatus = Ndis802_11Encryption2Enabled; + } + + if (param->u.wpa_key.alg_name == WPA_ALG_CCMP) { + pDevice->eEncryptionStatus = Ndis802_11Encryption3Enabled; + } + + if (param->u.wpa_key.set_tx) + dwKeyIndex |= (1 << 31); + + if (pDevice->eEncryptionStatus == Ndis802_11Encryption3Enabled) + byKeyDecMode = KEY_CTL_CCMP; + else if (pDevice->eEncryptionStatus == Ndis802_11Encryption2Enabled) + byKeyDecMode = KEY_CTL_TKIP; + else + byKeyDecMode = KEY_CTL_WEP; + + // Fix HCT test that set 256 bits KEY and Ndis802_11Encryption3Enabled + if (pDevice->eEncryptionStatus == Ndis802_11Encryption3Enabled) { + if (param->u.wpa_key.key_len == MAX_KEY_LEN) + byKeyDecMode = KEY_CTL_TKIP; + else if (param->u.wpa_key.key_len == WLAN_WEP40_KEYLEN) + byKeyDecMode = KEY_CTL_WEP; + else if (param->u.wpa_key.key_len == WLAN_WEP104_KEYLEN) + byKeyDecMode = KEY_CTL_WEP; + } else if (pDevice->eEncryptionStatus == Ndis802_11Encryption2Enabled) { + if (param->u.wpa_key.key_len == WLAN_WEP40_KEYLEN) + byKeyDecMode = KEY_CTL_WEP; + else if (param->u.wpa_key.key_len == WLAN_WEP104_KEYLEN) + byKeyDecMode = KEY_CTL_WEP; + } + + + // Check TKIP key length + if ((byKeyDecMode == KEY_CTL_TKIP) && + (param->u.wpa_key.key_len != MAX_KEY_LEN)) { + // TKIP Key must be 256 bits + //DBG_PRN_WLAN03(("return NDIS_STATUS_INVALID_DATA - TKIP Key must be 256 bits\n")); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "return- TKIP Key must be 256 bits!\n"); + return -EINVAL; + } + // Check AES key length + if ((byKeyDecMode == KEY_CTL_CCMP) && + (param->u.wpa_key.key_len != AES_KEY_LEN)) { + // AES Key must be 128 bits + //DBG_PRN_WLAN03(("return NDIS_STATUS_INVALID_DATA - AES Key must be 128 bits\n")); + return -EINVAL; + } + + // spin_lock_irq(&pDevice->lock); + if (IS_BROADCAST_ADDRESS(¶m->addr[0]) || (param->addr == NULL)) { + // If IS_BROADCAST_ADDRESS, set the key as every key entry's group key. + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Groupe Key Assign.\n"); + + if ((KeybSetAllGroupKey(&(pDevice->sKey), + dwKeyIndex, + param->u.wpa_key.key_len, + (PQWORD) &(KeyRSC), + (PBYTE)abyKey, + byKeyDecMode, + pDevice->PortOffset, + pDevice->byLocalID) == TRUE) && + (KeybSetDefaultKey(&(pDevice->sKey), + dwKeyIndex, + param->u.wpa_key.key_len, + (PQWORD) &(KeyRSC), + (PBYTE)abyKey, + byKeyDecMode, + pDevice->PortOffset, + pDevice->byLocalID) == TRUE) ) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "GROUP Key Assign.\n"); + + } else { + //DBG_PRN_WLAN03(("return NDIS_STATUS_INVALID_DATA -KeybSetDefaultKey Fail.0\n")); + // spin_unlock_irq(&pDevice->lock); + return -EINVAL; + } + + } else { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Pairwise Key Assign.\n"); + // BSSID not 0xffffffffffff + // Pairwise Key can't be WEP + if (byKeyDecMode == KEY_CTL_WEP) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Pairwise Key can't be WEP\n"); + //spin_unlock_irq(&pDevice->lock); + return -EINVAL; + } + + dwKeyIndex |= (1 << 30); // set pairwise key + if (pMgmt->eConfigMode == WMAC_CONFIG_IBSS_STA) { + //DBG_PRN_WLAN03(("return NDIS_STATUS_INVALID_DATA - WMAC_CONFIG_IBSS_STA\n")); + //spin_unlock_irq(&pDevice->lock); + return -EINVAL; + } + if (KeybSetKey(&(pDevice->sKey), + ¶m->addr[0], + dwKeyIndex, + param->u.wpa_key.key_len, + (PQWORD) &(KeyRSC), + (PBYTE)abyKey, + byKeyDecMode, + pDevice->PortOffset, + pDevice->byLocalID) == TRUE) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Pairwise Key Set\n"); + + } else { + // Key Table Full + if (IS_ETH_ADDRESS_EQUAL(¶m->addr[0], pDevice->abyBSSID)) { + //DBG_PRN_WLAN03(("return NDIS_STATUS_INVALID_DATA -Key Table Full.2\n")); + //spin_unlock_irq(&pDevice->lock); + return -EINVAL; + + } else { + // Save Key and configure just before associate/reassociate to BSSID + // we do not implement now + //spin_unlock_irq(&pDevice->lock); + return -EINVAL; + } + } + } // BSSID not 0xffffffffffff + if ((ret == 0) && ((param->u.wpa_key.set_tx) != 0)) { + pDevice->byKeyIndex = (BYTE)param->u.wpa_key.key_index; + pDevice->bTransmitKey = TRUE; + } + pDevice->bEncryptionEnable = TRUE; + //spin_unlock_irq(&pDevice->lock); + +/* + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " key=%x-%x-%x-%x-%x-xxxxx \n", + pMgmt->sNodeDBTable[iNodeIndex].abyWepKey[byKeyIndex][0], + pMgmt->sNodeDBTable[iNodeIndex].abyWepKey[byKeyIndex][1], + pMgmt->sNodeDBTable[iNodeIndex].abyWepKey[byKeyIndex][2], + pMgmt->sNodeDBTable[iNodeIndex].abyWepKey[byKeyIndex][3], + pMgmt->sNodeDBTable[iNodeIndex].abyWepKey[byKeyIndex][4] + ); +*/ + + return ret; + +} + + +/* + * Description: + * enable wpa auth & mode + * + * Parameters: + * In: + * pDevice - + * param - + * Out: + * + * Return Value: + * + */ + +static int wpa_set_wpa(PSDevice pDevice, + struct viawget_wpa_param *param) +{ + + PSMgmtObject pMgmt = pDevice->pMgmt; + int ret = 0; + + pMgmt->eAuthenMode = WMAC_AUTH_OPEN; + pMgmt->bShareKeyAlgorithm = FALSE; + + return ret; +} + + + + + /* + * Description: + * set disassociate + * + * Parameters: + * In: + * pDevice - + * param - + * Out: + * + * Return Value: + * + */ + +static int wpa_set_disassociate(PSDevice pDevice, + struct viawget_wpa_param *param) +{ + PSMgmtObject pMgmt = pDevice->pMgmt; + int ret = 0; + + spin_lock_irq(&pDevice->lock); + if (pDevice->bLinkPass) { + if (!memcmp(param->addr, pMgmt->abyCurrBSSID, 6)) + bScheduleCommand((HANDLE)pDevice, WLAN_CMD_DISASSOCIATE, NULL); + } + spin_unlock_irq(&pDevice->lock); + + return ret; +} + + + +/* + * Description: + * enable scan process + * + * Parameters: + * In: + * pDevice - + * param - + * Out: + * + * Return Value: + * + */ + +static int wpa_set_scan(PSDevice pDevice, + struct viawget_wpa_param *param) +{ + int ret = 0; + + spin_lock_irq(&pDevice->lock); + BSSvClearBSSList((HANDLE)pDevice, pDevice->bLinkPass); + bScheduleCommand((HANDLE) pDevice, WLAN_CMD_BSSID_SCAN, NULL); + spin_unlock_irq(&pDevice->lock); + + return ret; +} + + + +/* + * Description: + * get bssid + * + * Parameters: + * In: + * pDevice - + * param - + * Out: + * + * Return Value: + * + */ + +static int wpa_get_bssid(PSDevice pDevice, + struct viawget_wpa_param *param) +{ + PSMgmtObject pMgmt = pDevice->pMgmt; + int ret = 0; + + memcpy(param->u.wpa_associate.bssid, pMgmt->abyCurrBSSID , 6); + + return ret; + +} + + +/* + * Description: + * get bssid + * + * Parameters: + * In: + * pDevice - + * param - + * Out: + * + * Return Value: + * + */ + +static int wpa_get_ssid(PSDevice pDevice, + struct viawget_wpa_param *param) +{ + PSMgmtObject pMgmt = pDevice->pMgmt; + PWLAN_IE_SSID pItemSSID; + int ret = 0; + + pItemSSID = (PWLAN_IE_SSID)pMgmt->abyCurrSSID; + + memcpy(param->u.wpa_associate.ssid, pItemSSID->abySSID , pItemSSID->len); + param->u.wpa_associate.ssid_len = pItemSSID->len; + + return ret; +} + + + +/* + * Description: + * get scan results + * + * Parameters: + * In: + * pDevice - + * param - + * Out: + * + * Return Value: + * + */ + +static int wpa_get_scan(PSDevice pDevice, + struct viawget_wpa_param *param) +{ + struct viawget_scan_result *scan_buf; + PSMgmtObject pMgmt = pDevice->pMgmt; + PWLAN_IE_SSID pItemSSID; + PKnownBSS pBSS; + PBYTE pBuf; + int ret = 0; + u16 count = 0; + u16 ii, jj; +#if 1 + + PBYTE ptempBSS; + + + + ptempBSS = kmalloc(sizeof(KnownBSS), (int)GFP_ATOMIC); + + if (ptempBSS == NULL) { + + printk("bubble sort kmalloc memory fail@@@\n"); + + ret = -ENOMEM; + + return ret; + + } + + for (ii = 0; ii < MAX_BSS_NUM; ii++) { + + for(jj=0;jjsBSSList[jj].bActive!=TRUE) || + + ((pMgmt->sBSSList[jj].uRSSI>pMgmt->sBSSList[jj+1].uRSSI) &&(pMgmt->sBSSList[jj+1].bActive!=FALSE))) { + + memcpy(ptempBSS,&pMgmt->sBSSList[jj],sizeof(KnownBSS)); + + memcpy(&pMgmt->sBSSList[jj],&pMgmt->sBSSList[jj+1],sizeof(KnownBSS)); + + memcpy(&pMgmt->sBSSList[jj+1],ptempBSS,sizeof(KnownBSS)); + + } + + } + + }; + + kfree(ptempBSS); + + // printk("bubble sort result:\n"); + + //for (ii = 0; ii < MAX_BSS_NUM; ii++) + + // printk("%d [%s]:RSSI=%d\n",ii,((PWLAN_IE_SSID)(pMgmt->sBSSList[ii].abySSID))->abySSID, + + // pMgmt->sBSSList[ii].uRSSI); + + #endif + +//******mike:bubble sort by stronger RSSI*****// + + + + + count = 0; + pBSS = &(pMgmt->sBSSList[0]); + for (ii = 0; ii < MAX_BSS_NUM; ii++) { + pBSS = &(pMgmt->sBSSList[ii]); + if (!pBSS->bActive) + continue; + count++; + }; + + pBuf = kmalloc(sizeof(struct viawget_scan_result) * count, (int)GFP_ATOMIC); + + if (pBuf == NULL) { + ret = -ENOMEM; + return ret; + } + memset(pBuf, 0, sizeof(struct viawget_scan_result) * count); + scan_buf = (struct viawget_scan_result *)pBuf; + pBSS = &(pMgmt->sBSSList[0]); + for (ii = 0, jj = 0; ii < MAX_BSS_NUM ; ii++) { + pBSS = &(pMgmt->sBSSList[ii]); + if (pBSS->bActive) { + if (jj >= count) + break; + memcpy(scan_buf->bssid, pBSS->abyBSSID, WLAN_BSSID_LEN); + pItemSSID = (PWLAN_IE_SSID)pBSS->abySSID; + memcpy(scan_buf->ssid, pItemSSID->abySSID, pItemSSID->len); + scan_buf->ssid_len = pItemSSID->len; + scan_buf->freq = frequency_list[pBSS->uChannel-1]; + scan_buf->caps = pBSS->wCapInfo; + //scan_buf->caps = pBSS->wCapInfo; + //scan_buf->qual = + //scan_buf->noise = + //scan_buf->level = + //scan_buf->maxrate = + if (pBSS->wWPALen != 0) { + scan_buf->wpa_ie_len = pBSS->wWPALen; + memcpy(scan_buf->wpa_ie, pBSS->byWPAIE, pBSS->wWPALen); + } + if (pBSS->wRSNLen != 0) { + scan_buf->rsn_ie_len = pBSS->wRSNLen; + memcpy(scan_buf->rsn_ie, pBSS->byRSNIE, pBSS->wRSNLen); + } + scan_buf = (struct viawget_scan_result *)((PBYTE)scan_buf + sizeof(struct viawget_scan_result)); + jj ++; + } + } + + if (jj < count) + count = jj; + + if (copy_to_user(param->u.scan_results.buf, pBuf, sizeof(struct viawget_scan_result) * count)) { + ret = -EFAULT; + }; + param->u.scan_results.scan_count = count; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO " param->u.scan_results.scan_count = %d\n", count) + + kfree(pBuf); + return ret; +} + + + +/* + * Description: + * set associate with AP + * + * Parameters: + * In: + * pDevice - + * param - + * Out: + * + * Return Value: + * + */ + +static int wpa_set_associate(PSDevice pDevice, + struct viawget_wpa_param *param) +{ + PSMgmtObject pMgmt = pDevice->pMgmt; + PWLAN_IE_SSID pItemSSID; + BYTE abyNullAddr[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + BYTE abyWPAIE[64]; + int ret = 0; + BOOL bWepEnabled=FALSE; + + // set key type & algorithm + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pairwise_suite = %d\n", param->u.wpa_associate.pairwise_suite); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "group_suite = %d\n", param->u.wpa_associate.group_suite); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "key_mgmt_suite = %d\n", param->u.wpa_associate.key_mgmt_suite); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "auth_alg = %d\n", param->u.wpa_associate.auth_alg); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "mode = %d\n", param->u.wpa_associate.mode); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "wpa_ie_len = %d\n", param->u.wpa_associate.wpa_ie_len); + + + if (param->u.wpa_associate.wpa_ie && + copy_from_user(&abyWPAIE[0], param->u.wpa_associate.wpa_ie, param->u.wpa_associate.wpa_ie_len)) + return -EINVAL; + + if (param->u.wpa_associate.mode == 1) + pMgmt->eConfigMode = WMAC_CONFIG_IBSS_STA; + else + pMgmt->eConfigMode = WMAC_CONFIG_ESS_STA; + // set ssid + memset(pMgmt->abyDesireSSID, 0, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1); + pItemSSID = (PWLAN_IE_SSID)pMgmt->abyDesireSSID; + pItemSSID->byElementID = WLAN_EID_SSID; + pItemSSID->len = param->u.wpa_associate.ssid_len; + memcpy(pItemSSID->abySSID, param->u.wpa_associate.ssid, pItemSSID->len); + // set bssid + if (memcmp(param->u.wpa_associate.bssid, &abyNullAddr[0], 6) != 0) + memcpy(pMgmt->abyDesireBSSID, param->u.wpa_associate.bssid, 6); +else +{ + bScheduleCommand((HANDLE) pDevice, WLAN_CMD_BSSID_SCAN, pItemSSID->abySSID); +} + + if (param->u.wpa_associate.wpa_ie_len == 0) { + if (param->u.wpa_associate.auth_alg & AUTH_ALG_SHARED_KEY) + pMgmt->eAuthenMode = WMAC_AUTH_SHAREKEY; + else + pMgmt->eAuthenMode = WMAC_AUTH_OPEN; + } else if (abyWPAIE[0] == RSN_INFO_ELEM) { + if (param->u.wpa_associate.key_mgmt_suite == KEY_MGMT_PSK) + pMgmt->eAuthenMode = WMAC_AUTH_WPA2PSK; + else + pMgmt->eAuthenMode = WMAC_AUTH_WPA2; + } else { + if (param->u.wpa_associate.key_mgmt_suite == KEY_MGMT_WPA_NONE) + pMgmt->eAuthenMode = WMAC_AUTH_WPANONE; + else if (param->u.wpa_associate.key_mgmt_suite == KEY_MGMT_PSK) + pMgmt->eAuthenMode = WMAC_AUTH_WPAPSK; + else + pMgmt->eAuthenMode = WMAC_AUTH_WPA; + } + + switch (param->u.wpa_associate.pairwise_suite) { + case CIPHER_CCMP: + pDevice->eEncryptionStatus = Ndis802_11Encryption3Enabled; + break; + case CIPHER_TKIP: + pDevice->eEncryptionStatus = Ndis802_11Encryption2Enabled; + break; + case CIPHER_WEP40: + case CIPHER_WEP104: + pDevice->eEncryptionStatus = Ndis802_11Encryption1Enabled; + bWepEnabled=TRUE; + break; + case CIPHER_NONE: + if (param->u.wpa_associate.group_suite == CIPHER_CCMP) + pDevice->eEncryptionStatus = Ndis802_11Encryption3Enabled; + else + pDevice->eEncryptionStatus = Ndis802_11Encryption2Enabled; + break; + default: + pDevice->eEncryptionStatus = Ndis802_11EncryptionDisabled; + }; + +//DavidWang add for WPA_supplicant support open/share mode + + if (pMgmt->eAuthenMode == WMAC_AUTH_SHAREKEY) { + pDevice->eEncryptionStatus = Ndis802_11Encryption1Enabled; + //pMgmt->eAuthenMode = WMAC_AUTH_SHAREKEY; + pMgmt->bShareKeyAlgorithm = TRUE; + } + else if (pMgmt->eAuthenMode == WMAC_AUTH_OPEN) { + if(!bWepEnabled) pDevice->eEncryptionStatus = Ndis802_11EncryptionDisabled; + else pDevice->eEncryptionStatus = Ndis802_11Encryption1Enabled; + //pMgmt->eAuthenMode = WMAC_AUTH_OPEN; + //pMgmt->bShareKeyAlgorithm = FALSE; //20080717-06, by chester//Fix Open mode, WEP encrytion + } +//mike save old encryption status + pDevice->eOldEncryptionStatus = pDevice->eEncryptionStatus; + + if (pDevice->eEncryptionStatus != Ndis802_11EncryptionDisabled) + pDevice->bEncryptionEnable = TRUE; + else + pDevice->bEncryptionEnable = FALSE; +if (!((pMgmt->eAuthenMode == WMAC_AUTH_SHAREKEY) || + ((pMgmt->eAuthenMode == WMAC_AUTH_OPEN) && (bWepEnabled==TRUE))) ) //DavidWang //20080717-06, by chester//Not to initial WEP + KeyvInitTable(&pDevice->sKey, pDevice->PortOffset); + spin_lock_irq(&pDevice->lock); + pDevice->bLinkPass = FALSE; + memset(pMgmt->abyCurrBSSID, 0, 6); + pMgmt->eCurrState = WMAC_STATE_IDLE; + netif_stop_queue(pDevice->dev); + //20080701-02, by Mike Liu +/*******search if ap_scan=2 ,which is associating request in hidden ssid mode ****/ +{ + PKnownBSS pCurr = NULL; + pCurr = BSSpSearchBSSList(pDevice, + pMgmt->abyDesireBSSID, + pMgmt->abyDesireSSID, + pMgmt->eConfigPHYMode + ); + + if (pCurr == NULL){ + printk("wpa_set_associate---->hidden mode site survey before associate.......\n"); + bScheduleCommand((HANDLE) pDevice, WLAN_CMD_BSSID_SCAN, pMgmt->abyDesireSSID); + }; +} +/****************************************************************/ + bScheduleCommand((HANDLE) pDevice, WLAN_CMD_SSID, NULL); + spin_unlock_irq(&pDevice->lock); + + return ret; +} + + +/* + * Description: + * wpa_ioctl main function supported for wpa supplicant + * + * Parameters: + * In: + * pDevice - + * iw_point - + * Out: + * + * Return Value: + * + */ + +int wpa_ioctl(PSDevice pDevice, struct iw_point *p) +{ + struct viawget_wpa_param *param; + int ret = 0; + int wpa_ioctl = 0; + + if (p->length < sizeof(struct viawget_wpa_param) || + p->length > VIAWGET_WPA_MAX_BUF_SIZE || !p->pointer) + return -EINVAL; + + param = (struct viawget_wpa_param *) kmalloc((int)p->length, (int)GFP_KERNEL); + if (param == NULL) + return -ENOMEM; + + if (copy_from_user(param, p->pointer, p->length)) { + ret = -EFAULT; + goto out; + } + + switch (param->cmd) { + case VIAWGET_SET_WPA: + ret = wpa_set_wpa(pDevice, param); + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_SET_WPA \n"); + break; + + case VIAWGET_SET_KEY: + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_SET_KEY \n"); + spin_lock_irq(&pDevice->lock); + ret = wpa_set_keys(pDevice, param, FALSE); + spin_unlock_irq(&pDevice->lock); + break; + + case VIAWGET_SET_SCAN: + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_SET_SCAN \n"); + ret = wpa_set_scan(pDevice, param); + break; + + case VIAWGET_GET_SCAN: + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_GET_SCAN\n"); + ret = wpa_get_scan(pDevice, param); + wpa_ioctl = 1; + break; + + case VIAWGET_GET_SSID: + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_GET_SSID \n"); + ret = wpa_get_ssid(pDevice, param); + wpa_ioctl = 1; + break; + + case VIAWGET_GET_BSSID: + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_GET_BSSID \n"); + ret = wpa_get_bssid(pDevice, param); + wpa_ioctl = 1; + break; + + case VIAWGET_SET_ASSOCIATE: + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_SET_ASSOCIATE \n"); + ret = wpa_set_associate(pDevice, param); + break; + + case VIAWGET_SET_DISASSOCIATE: + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_SET_DISASSOCIATE \n"); + ret = wpa_set_disassociate(pDevice, param); + break; + + case VIAWGET_SET_DROP_UNENCRYPT: + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_SET_DROP_UNENCRYPT \n"); + break; + + case VIAWGET_SET_DEAUTHENTICATE: + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_SET_DEAUTHENTICATE \n"); + break; + + default: + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "wpa_ioctl: unknown cmd=%d\n", + param->cmd); + return -EOPNOTSUPP; + break; + } + + if ((ret == 0) && wpa_ioctl) { + if (copy_to_user(p->pointer, param, p->length)) { + ret = -EFAULT; + goto out; + } + } + +out: + if (param != NULL) + kfree(param); + + return ret; +} + diff --git a/drivers/staging/vt6655/wpactl.h b/drivers/staging/vt6655/wpactl.h new file mode 100644 index 000000000000..9e7889785306 --- /dev/null +++ b/drivers/staging/vt6655/wpactl.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * File: wpactl.h + * + * Purpose: + * + * Author: Lyndon Chen + * + * Date: March 1, 2005 + * + */ + + +#ifndef __WPACTL_H__ +#define __WPACTL_H__ + +#if !defined(__DEVICE_H__) +#include "device.h" +#endif +#ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT +#if !defined(__IOWPA_H__) +#include "iowpa.h" +#endif +#endif + +/*--------------------- Export Definitions -------------------------*/ + + +//WPA related + +typedef enum { WPA_ALG_NONE, WPA_ALG_WEP, WPA_ALG_TKIP, WPA_ALG_CCMP } wpa_alg; +typedef enum { CIPHER_NONE, CIPHER_WEP40, CIPHER_TKIP, CIPHER_CCMP, + CIPHER_WEP104 } wpa_cipher; +typedef enum { KEY_MGMT_802_1X, KEY_MGMT_CCKM,KEY_MGMT_PSK, KEY_MGMT_NONE, + KEY_MGMT_802_1X_NO_WPA, KEY_MGMT_WPA_NONE } wpa_key_mgmt; + +#define AUTH_ALG_OPEN_SYSTEM 0x01 +#define AUTH_ALG_SHARED_KEY 0x02 +#define AUTH_ALG_LEAP 0x04 + +#define GENERIC_INFO_ELEM 0xdd +#define RSN_INFO_ELEM 0x30 + + + +typedef ULONGLONG NDIS_802_11_KEY_RSC; + +/*--------------------- Export Classes ----------------------------*/ + +/*--------------------- Export Variables --------------------------*/ + +/*--------------------- Export Functions --------------------------*/ + + +#ifdef __cplusplus +extern "C" { /* Assume C declarations for C++ */ +#endif /* __cplusplus */ + +int wpa_set_wpadev(PSDevice pDevice, int val); +int wpa_ioctl(PSDevice pDevice, struct iw_point *p); +int wpa_set_keys(PSDevice pDevice, void *ctx, BOOL fcpfkernel); + +#ifdef __cplusplus +} /* End of extern "C" { */ +#endif /* __cplusplus */ + + + + +#endif // __WPACL_H__ + + + diff --git a/drivers/staging/vt6655/wroute.c b/drivers/staging/vt6655/wroute.c new file mode 100644 index 000000000000..219ae21654e2 --- /dev/null +++ b/drivers/staging/vt6655/wroute.c @@ -0,0 +1,211 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * File: wroute.c + * + * Purpose: handle WMAC frame relay & filterring + * + * Author: Lyndon Chen + * + * Date: May 20, 2003 + * + * Functions: + * ROUTEbRelay - Relay packet + * + * Revision History: + * + */ + + +#if !defined(__MAC_H__) +#include "mac.h" +#endif +#if !defined(__TCRC_H__) +#include "tcrc.h" +#endif +#if !defined(__RXTX_H__) +#include "rxtx.h" +#endif +#if !defined(__WROUTE_H__) +#include "wroute.h" +#endif +#if !defined(__CARD_H__) +#include "card.h" +#endif +#if !defined(__BASEBAND_H__) +#include "baseband.h" +#endif +/*--------------------- Static Definitions -------------------------*/ + +/*--------------------- Static Classes ----------------------------*/ + +/*--------------------- Static Variables --------------------------*/ +static int msglevel =MSG_LEVEL_INFO; +//static int msglevel =MSG_LEVEL_DEBUG; +/*--------------------- Static Functions --------------------------*/ + +/*--------------------- Export Variables --------------------------*/ + + + +/* + * Description: + * Relay packet. Return TRUE if packet is copy to DMA1 + * + * Parameters: + * In: + * pDevice - + * pbySkbData - rx packet skb data + * Out: + * TURE, FALSE + * + * Return Value: TRUE if packet duplicate; otherwise FALSE + * + */ +BOOL ROUTEbRelay (PSDevice pDevice, PBYTE pbySkbData, UINT uDataLen, UINT uNodeIndex) +{ + PSMgmtObject pMgmt = pDevice->pMgmt; + PSTxDesc pHeadTD, pLastTD; + UINT cbFrameBodySize; + UINT uMACfragNum; + BYTE byPktTyp; + BOOL bNeedEncryption = FALSE; + SKeyItem STempKey; + PSKeyItem pTransmitKey = NULL; + UINT cbHeaderSize; + UINT ii; + PBYTE pbyBSSID; + + + + + if (AVAIL_TD(pDevice, TYPE_AC0DMA)<=0) { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Relay can't allocate TD1..\n"); + return FALSE; + } + + pHeadTD = pDevice->apCurrTD[TYPE_AC0DMA]; + + pHeadTD->m_td1TD1.byTCR = (TCR_EDP|TCR_STP); + + memcpy(pDevice->sTxEthHeader.abyDstAddr, (PBYTE)pbySkbData, U_HEADER_LEN); + + cbFrameBodySize = uDataLen - U_HEADER_LEN; + + if (ntohs(pDevice->sTxEthHeader.wType) > MAX_DATA_LEN) { + cbFrameBodySize += 8; + } + + if (pDevice->bEncryptionEnable == TRUE) { + bNeedEncryption = TRUE; + + // get group key + pbyBSSID = pDevice->abyBroadcastAddr; + if(KeybGetTransmitKey(&(pDevice->sKey), pbyBSSID, GROUP_KEY, &pTransmitKey) == FALSE) { + pTransmitKey = NULL; + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_DEBUG"KEY is NULL. [%d]\n", pDevice->pMgmt->eCurrMode); + } else { + DEVICE_PRT(MSG_LEVEL_DEBUG, KERN_DEBUG"Get GTK.\n"); + } + } + + if (pDevice->bEnableHostWEP) { + if (uNodeIndex >= 0) { + pTransmitKey = &STempKey; + pTransmitKey->byCipherSuite = pMgmt->sNodeDBTable[uNodeIndex].byCipherSuite; + pTransmitKey->dwKeyIndex = pMgmt->sNodeDBTable[uNodeIndex].dwKeyIndex; + pTransmitKey->uKeyLength = pMgmt->sNodeDBTable[uNodeIndex].uWepKeyLength; + pTransmitKey->dwTSC47_16 = pMgmt->sNodeDBTable[uNodeIndex].dwTSC47_16; + pTransmitKey->wTSC15_0 = pMgmt->sNodeDBTable[uNodeIndex].wTSC15_0; + memcpy(pTransmitKey->abyKey, + &pMgmt->sNodeDBTable[uNodeIndex].abyWepKey[0], + pTransmitKey->uKeyLength + ); + } + } + + uMACfragNum = cbGetFragCount(pDevice, pTransmitKey, cbFrameBodySize, &pDevice->sTxEthHeader); + + if (uMACfragNum > AVAIL_TD(pDevice,TYPE_AC0DMA)) { + return FALSE; + } + byPktTyp = (BYTE)pDevice->byPacketType; + + if (pDevice->bFixRate) { + if (pDevice->eCurrentPHYType == PHY_TYPE_11B) { + if (pDevice->uConnectionRate >= RATE_11M) { + pDevice->wCurrentRate = RATE_11M; + } else { + pDevice->wCurrentRate = (WORD)pDevice->uConnectionRate; + } + } else { + if ((pDevice->eCurrentPHYType == PHY_TYPE_11A) && + (pDevice->uConnectionRate <= RATE_6M)) { + pDevice->wCurrentRate = RATE_6M; + } else { + if (pDevice->uConnectionRate >= RATE_54M) + pDevice->wCurrentRate = RATE_54M; + else + pDevice->wCurrentRate = (WORD)pDevice->uConnectionRate; + } + } + } + else { + pDevice->wCurrentRate = pDevice->pMgmt->sNodeDBTable[uNodeIndex].wTxDataRate; + } + + if (pDevice->wCurrentRate <= RATE_11M) + byPktTyp = PK_TYPE_11B; + + vGenerateFIFOHeader(pDevice, byPktTyp, pDevice->pbyTmpBuff, bNeedEncryption, + cbFrameBodySize, TYPE_AC0DMA, pHeadTD, + &pDevice->sTxEthHeader, pbySkbData, pTransmitKey, uNodeIndex, + &uMACfragNum, + &cbHeaderSize + ); + + if (MACbIsRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_PS)) { + // Disable PS + MACbPSWakeup(pDevice->PortOffset); + } + + pDevice->bPWBitOn = FALSE; + + pLastTD = pHeadTD; + for (ii = 0; ii < uMACfragNum; ii++) { + // Poll Transmit the adapter + wmb(); + pHeadTD->m_td0TD0.f1Owner=OWNED_BY_NIC; + wmb(); + if (ii == (uMACfragNum - 1)) + pLastTD = pHeadTD; + pHeadTD = pHeadTD->next; + } + + pLastTD->pTDInfo->skb = 0; + pLastTD->pTDInfo->byFlags = 0; + + pDevice->apCurrTD[TYPE_AC0DMA] = pHeadTD; + + MACvTransmitAC0(pDevice->PortOffset); + + return TRUE; +} + + + diff --git a/drivers/staging/vt6655/wroute.h b/drivers/staging/vt6655/wroute.h new file mode 100644 index 000000000000..ea5f5896e9ba --- /dev/null +++ b/drivers/staging/vt6655/wroute.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * File: wroute.h + * + * Purpose: + * + * Author: Lyndon Chen + * + * Date: May 21, 2003 + * + */ + + +#ifndef __WROUTE_H__ +#define __WROUTE_H__ + + +#if !defined(__DEVICE_H__) +#include "device.h" +#endif + + + +/*--------------------- Export Definitions -------------------------*/ + +/*--------------------- Export Classes ----------------------------*/ + +/*--------------------- Export Variables --------------------------*/ + +/*--------------------- Export Functions --------------------------*/ + + +#ifdef __cplusplus +extern "C" { /* Assume C declarations for C++ */ +#endif /* __cplusplus */ + +BOOL ROUTEbRelay (PSDevice pDevice, PBYTE pbySkbData, UINT uDataLen, UINT uNodeIndex); + +#ifdef __cplusplus +} /* End of extern "C" { */ +#endif /* __cplusplus */ + + + + +#endif // __WROUTE_H__ + + + diff --git a/drivers/staging/winbond/Makefile b/drivers/staging/winbond/Makefile index b49c9730eddf..fb2b7d432b43 100644 --- a/drivers/staging/winbond/Makefile +++ b/drivers/staging/winbond/Makefile @@ -7,7 +7,6 @@ w35und-objs := \ wb35reg.o \ wb35rx.o \ wb35tx.o \ - wbhal.o \ wbusb.o \ diff --git a/drivers/staging/winbond/mds.c b/drivers/staging/winbond/mds.c index c7af09257e6f..59d6d67a9f7e 100644 --- a/drivers/staging/winbond/mds.c +++ b/drivers/staging/winbond/mds.c @@ -432,7 +432,7 @@ Mds_Tx(struct wbsoft_priv * adapter) return; //Only one thread can be run here - if (!atomic_inc_return(&pMds->TxThreadCount) == 1) + if (atomic_inc_return(&pMds->TxThreadCount) != 1) goto cleanup; // Start to fill the data diff --git a/drivers/staging/winbond/mto.c b/drivers/staging/winbond/mto.c index 94a060bcc628..7deb5c769763 100644 --- a/drivers/staging/winbond/mto.c +++ b/drivers/staging/winbond/mto.c @@ -175,7 +175,7 @@ void MTO_Init(struct wbsoft_priv *adapter) } else //follow the setting from EEPROM MTOPARA_TXPOWER_INDEX() = MTO_TXPOWER_FROM_EEPROM; - hal_set_rf_power(MTO_HAL(), (u8)MTOPARA_TXPOWER_INDEX()); + RFSynthesizer_SetPowerIndex(MTO_HAL(), (u8)MTOPARA_TXPOWER_INDEX()); //------------------------------------------------ // For RSSI turning 20060808.4 Cancel load from EEPROM diff --git a/drivers/staging/winbond/phy_calibration.c b/drivers/staging/winbond/phy_calibration.c index af8c01e313b0..8c56962ab80c 100644 --- a/drivers/staging/winbond/phy_calibration.c +++ b/drivers/staging/winbond/phy_calibration.c @@ -340,6 +340,25 @@ void _sin_cos(s32 angle, s32 *sin, s32 *cos) } } +static unsigned char hal_get_dxx_reg(struct hw_data *pHwData, u16 number, u32 * pValue) +{ + if (number < 0x1000) + number += 0x1000; + return Wb35Reg_ReadSync(pHwData, number, pValue); +} +#define hw_get_dxx_reg( _A, _B, _C ) hal_get_dxx_reg( _A, _B, (u32 *)_C ) + +static unsigned char hal_set_dxx_reg(struct hw_data *pHwData, u16 number, u32 value) +{ + unsigned char ret; + + if (number < 0x1000) + number += 0x1000; + ret = Wb35Reg_WriteSync(pHwData, number, value); + return ret; +} +#define hw_set_dxx_reg( _A, _B, _C ) hal_set_dxx_reg( _A, _B, (u32)_C ) + void _reset_rx_cal(struct hw_data *phw_data) { diff --git a/drivers/staging/winbond/wbhal.c b/drivers/staging/winbond/wbhal.c deleted file mode 100644 index c985ad065238..000000000000 --- a/drivers/staging/winbond/wbhal.c +++ /dev/null @@ -1,568 +0,0 @@ -#include "sysdef.h" -#include "wbhal_f.h" -#include "wblinux_f.h" - -void hal_set_ethernet_address( struct hw_data * pHwData, u8 *current_address ) -{ - u32 ltmp[2]; - - if( pHwData->SurpriseRemove ) return; - - memcpy( pHwData->CurrentMacAddress, current_address, ETH_ALEN ); - - ltmp[0]= cpu_to_le32( *(u32 *)pHwData->CurrentMacAddress ); - ltmp[1]= cpu_to_le32( *(u32 *)(pHwData->CurrentMacAddress + 4) ) & 0xffff; - - Wb35Reg_BurstWrite( pHwData, 0x03e8, ltmp, 2, AUTO_INCREMENT ); -} - -void hal_get_permanent_address( struct hw_data * pHwData, u8 *pethernet_address ) -{ - if( pHwData->SurpriseRemove ) return; - - memcpy( pethernet_address, pHwData->PermanentMacAddress, 6 ); -} - -static void hal_led_control(unsigned long data) -{ - struct wbsoft_priv *adapter = (struct wbsoft_priv *) data; - struct hw_data * pHwData = &adapter->sHwData; - struct wb35_reg *reg = &pHwData->reg; - u32 LEDSet = (pHwData->SoftwareSet & HAL_LED_SET_MASK) >> HAL_LED_SET_SHIFT; - u8 LEDgray[20] = { 0,3,4,6,8,10,11,12,13,14,15,14,13,12,11,10,8,6,4,2 }; - u8 LEDgray2[30] = { 7,8,9,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,0,0,0,0,15,14,13,12,11,10,9,8 }; - u32 TimeInterval = 500, ltmp, ltmp2; - ltmp=0; - - if( pHwData->SurpriseRemove ) return; - - if( pHwData->LED_control ) { - ltmp2 = pHwData->LED_control & 0xff; - if( ltmp2 == 5 ) // 5 is WPS mode - { - TimeInterval = 100; - ltmp2 = (pHwData->LED_control>>8) & 0xff; - switch( ltmp2 ) - { - case 1: // [0.2 On][0.1 Off]... - pHwData->LED_Blinking %= 3; - ltmp = 0x1010; // Led 1 & 0 Green and Red - if( pHwData->LED_Blinking == 2 ) // Turn off - ltmp = 0; - break; - case 2: // [0.1 On][0.1 Off]... - pHwData->LED_Blinking %= 2; - ltmp = 0x0010; // Led 0 red color - if( pHwData->LED_Blinking ) // Turn off - ltmp = 0; - break; - case 3: // [0.1 On][0.1 Off][0.1 On][0.1 Off][0.1 On][0.1 Off][0.1 On][0.1 Off][0.1 On][0.1 Off][0.5 Off]... - pHwData->LED_Blinking %= 15; - ltmp = 0x0010; // Led 0 red color - if( (pHwData->LED_Blinking >= 9) || (pHwData->LED_Blinking%2) ) // Turn off 0.6 sec - ltmp = 0; - break; - case 4: // [300 On][ off ] - ltmp = 0x1000; // Led 1 Green color - if( pHwData->LED_Blinking >= 3000 ) - ltmp = 0; // led maybe on after 300sec * 32bit counter overlap. - break; - } - pHwData->LED_Blinking++; - - reg->U1BC_LEDConfigure = ltmp; - if( LEDSet != 7 ) // Only 111 mode has 2 LEDs on PCB. - { - reg->U1BC_LEDConfigure |= (ltmp &0xff)<<8; // Copy LED result to each LED control register - reg->U1BC_LEDConfigure |= (ltmp &0xff00)>>8; - } - Wb35Reg_Write( pHwData, 0x03bc, reg->U1BC_LEDConfigure ); - } - } - else if( pHwData->CurrentRadioSw || pHwData->CurrentRadioHw ) // If radio off - { - if( reg->U1BC_LEDConfigure & 0x1010 ) - { - reg->U1BC_LEDConfigure &= ~0x1010; - Wb35Reg_Write( pHwData, 0x03bc, reg->U1BC_LEDConfigure ); - } - } - else - { - switch( LEDSet ) - { - case 4: // [100] Only 1 Led be placed on PCB and use pin 21 of IC. Use LED_0 for showing - if( !pHwData->LED_LinkOn ) // Blink only if not Link On - { - // Blinking if scanning is on progress - if( pHwData->LED_Scanning ) - { - if( pHwData->LED_Blinking == 0 ) - { - reg->U1BC_LEDConfigure |= 0x10; - Wb35Reg_Write( pHwData, 0x03bc, reg->U1BC_LEDConfigure ); // LED_0 On - pHwData->LED_Blinking = 1; - TimeInterval = 300; - } - else - { - reg->U1BC_LEDConfigure &= ~0x10; - Wb35Reg_Write( pHwData, 0x03bc, reg->U1BC_LEDConfigure ); // LED_0 Off - pHwData->LED_Blinking = 0; - TimeInterval = 300; - } - } - else - { - //Turn Off LED_0 - if( reg->U1BC_LEDConfigure & 0x10 ) - { - reg->U1BC_LEDConfigure &= ~0x10; - Wb35Reg_Write( pHwData, 0x03bc, reg->U1BC_LEDConfigure ); // LED_0 Off - } - } - } - else - { - // Turn On LED_0 - if( (reg->U1BC_LEDConfigure & 0x10) == 0 ) - { - reg->U1BC_LEDConfigure |= 0x10; - Wb35Reg_Write( pHwData, 0x03bc, reg->U1BC_LEDConfigure ); // LED_0 Off - } - } - break; - - case 6: // [110] Only 1 Led be placed on PCB and use pin 21 of IC. Use LED_0 for showing - if( !pHwData->LED_LinkOn ) // Blink only if not Link On - { - // Blinking if scanning is on progress - if( pHwData->LED_Scanning ) - { - if( pHwData->LED_Blinking == 0 ) - { - reg->U1BC_LEDConfigure &= ~0xf; - reg->U1BC_LEDConfigure |= 0x10; - Wb35Reg_Write( pHwData, 0x03bc, reg->U1BC_LEDConfigure ); // LED_0 On - pHwData->LED_Blinking = 1; - TimeInterval = 300; - } - else - { - reg->U1BC_LEDConfigure &= ~0x1f; - Wb35Reg_Write( pHwData, 0x03bc, reg->U1BC_LEDConfigure ); // LED_0 Off - pHwData->LED_Blinking = 0; - TimeInterval = 300; - } - } - else - { - // 20060901 Gray blinking if in disconnect state and not scanning - ltmp = reg->U1BC_LEDConfigure; - reg->U1BC_LEDConfigure &= ~0x1f; - if( LEDgray2[(pHwData->LED_Blinking%30)] ) - { - reg->U1BC_LEDConfigure |= 0x10; - reg->U1BC_LEDConfigure |= LEDgray2[ (pHwData->LED_Blinking%30) ]; - } - pHwData->LED_Blinking++; - if( reg->U1BC_LEDConfigure != ltmp ) - Wb35Reg_Write( pHwData, 0x03bc, reg->U1BC_LEDConfigure ); // LED_0 Off - TimeInterval = 100; - } - } - else - { - // Turn On LED_0 - if( (reg->U1BC_LEDConfigure & 0x10) == 0 ) - { - reg->U1BC_LEDConfigure |= 0x10; - Wb35Reg_Write( pHwData, 0x03bc, reg->U1BC_LEDConfigure ); // LED_0 Off - } - } - break; - - case 5: // [101] Only 1 Led be placed on PCB and use LED_1 for showing - if( !pHwData->LED_LinkOn ) // Blink only if not Link On - { - // Blinking if scanning is on progress - if( pHwData->LED_Scanning ) - { - if( pHwData->LED_Blinking == 0 ) - { - reg->U1BC_LEDConfigure |= 0x1000; - Wb35Reg_Write( pHwData, 0x03bc, reg->U1BC_LEDConfigure ); // LED_1 On - pHwData->LED_Blinking = 1; - TimeInterval = 300; - } - else - { - reg->U1BC_LEDConfigure &= ~0x1000; - Wb35Reg_Write( pHwData, 0x03bc, reg->U1BC_LEDConfigure ); // LED_1 Off - pHwData->LED_Blinking = 0; - TimeInterval = 300; - } - } - else - { - //Turn Off LED_1 - if( reg->U1BC_LEDConfigure & 0x1000 ) - { - reg->U1BC_LEDConfigure &= ~0x1000; - Wb35Reg_Write( pHwData, 0x03bc, reg->U1BC_LEDConfigure ); // LED_1 Off - } - } - } - else - { - // Is transmitting/receiving ?? - if( (adapter->RxByteCount != pHwData->RxByteCountLast ) || - (adapter->TxByteCount != pHwData->TxByteCountLast ) ) - { - if( (reg->U1BC_LEDConfigure & 0x3000) != 0x3000 ) - { - reg->U1BC_LEDConfigure |= 0x3000; - Wb35Reg_Write( pHwData, 0x03bc, reg->U1BC_LEDConfigure ); // LED_1 On - } - - // Update variable - pHwData->RxByteCountLast = adapter->RxByteCount; - pHwData->TxByteCountLast = adapter->TxByteCount; - TimeInterval = 200; - } - else - { - // Turn On LED_1 and blinking if transmitting/receiving - if( (reg->U1BC_LEDConfigure & 0x3000) != 0x1000 ) - { - reg->U1BC_LEDConfigure &= ~0x3000; - reg->U1BC_LEDConfigure |= 0x1000; - Wb35Reg_Write( pHwData, 0x03bc, reg->U1BC_LEDConfigure ); // LED_1 On - } - } - } - break; - - default: // Default setting. 2 LED be placed on PCB. LED_0: Link On LED_1 Active - if( (reg->U1BC_LEDConfigure & 0x3000) != 0x3000 ) - { - reg->U1BC_LEDConfigure |= 0x3000;// LED_1 is always on and event enable - Wb35Reg_Write( pHwData, 0x03bc, reg->U1BC_LEDConfigure ); - } - - if( pHwData->LED_Blinking ) - { - // Gray blinking - reg->U1BC_LEDConfigure &= ~0x0f; - reg->U1BC_LEDConfigure |= 0x10; - reg->U1BC_LEDConfigure |= LEDgray[ (pHwData->LED_Blinking-1)%20 ]; - Wb35Reg_Write( pHwData, 0x03bc, reg->U1BC_LEDConfigure ); - - pHwData->LED_Blinking += 2; - if( pHwData->LED_Blinking < 40 ) - TimeInterval = 100; - else - { - pHwData->LED_Blinking = 0; // Stop blinking - reg->U1BC_LEDConfigure &= ~0x0f; - Wb35Reg_Write( pHwData, 0x03bc, reg->U1BC_LEDConfigure ); - } - break; - } - - if( pHwData->LED_LinkOn ) - { - if( !(reg->U1BC_LEDConfigure & 0x10) ) // Check the LED_0 - { - //Try to turn ON LED_0 after gray blinking - reg->U1BC_LEDConfigure |= 0x10; - pHwData->LED_Blinking = 1; //Start blinking - TimeInterval = 50; - } - } - else - { - if( reg->U1BC_LEDConfigure & 0x10 ) // Check the LED_0 - { - reg->U1BC_LEDConfigure &= ~0x10; - Wb35Reg_Write( pHwData, 0x03bc, reg->U1BC_LEDConfigure ); - } - } - break; - } - - //20060828.1 Active send null packet to avoid AP disconnect - if( pHwData->LED_LinkOn ) - { - pHwData->NullPacketCount += TimeInterval; - if( pHwData->NullPacketCount >= DEFAULT_NULL_PACKET_COUNT ) - { - pHwData->NullPacketCount = 0; - } - } - } - - pHwData->time_count += TimeInterval; - Wb35Tx_CurrentTime(adapter, pHwData->time_count); // 20060928 add - pHwData->LEDTimer.expires = jiffies + msecs_to_jiffies(TimeInterval); - add_timer(&pHwData->LEDTimer); -} - -u8 hal_init_hardware(struct ieee80211_hw *hw) -{ - struct wbsoft_priv *priv = hw->priv; - struct hw_data * pHwData = &priv->sHwData; - u16 SoftwareSet; - - // Initial the variable - pHwData->MaxReceiveLifeTime = DEFAULT_MSDU_LIFE_TIME; // Setting Rx maximum MSDU life time - pHwData->FragmentThreshold = DEFAULT_FRAGMENT_THRESHOLD; // Setting default fragment threshold - - pHwData->InitialResource = 1; - if( Wb35Reg_initial(pHwData)) { - pHwData->InitialResource = 2; - if (Wb35Tx_initial(pHwData)) { - pHwData->InitialResource = 3; - if (Wb35Rx_initial(pHwData)) { - pHwData->InitialResource = 4; - init_timer(&pHwData->LEDTimer); - pHwData->LEDTimer.function = hal_led_control; - pHwData->LEDTimer.data = (unsigned long) priv; - pHwData->LEDTimer.expires = jiffies + msecs_to_jiffies(1000); - add_timer(&pHwData->LEDTimer); - - // - // For restrict to vendor's hardware - // - SoftwareSet = hal_software_set( pHwData ); - - #ifdef Vendor2 - // Try to make sure the EEPROM contain - SoftwareSet >>= 8; - if( SoftwareSet != 0x82 ) - return false; - #endif - - Wb35Rx_start(hw); - Wb35Tx_EP2VM_start(priv); - - return true; - } - } - } - - pHwData->SurpriseRemove = 1; - return false; -} - - -void hal_halt(struct hw_data * pHwData, void *ppa_data) -{ - switch( pHwData->InitialResource ) - { - case 4: - case 3: del_timer_sync(&pHwData->LEDTimer); - msleep(100); // Wait for Timer DPC exit 940623.2 - Wb35Rx_destroy( pHwData ); // Release the Rx - case 2: Wb35Tx_destroy( pHwData ); // Release the Tx - case 1: Wb35Reg_destroy( pHwData ); // Release the Wb35 Regisster resources - } -} - -//--------------------------------------------------------------------------------------------------- -void hal_set_beacon_period( struct hw_data * pHwData, u16 beacon_period ) -{ - u32 tmp; - - if( pHwData->SurpriseRemove ) return; - - pHwData->BeaconPeriod = beacon_period; - tmp = pHwData->BeaconPeriod << 16; - tmp |= pHwData->ProbeDelay; - Wb35Reg_Write( pHwData, 0x0848, tmp ); -} - - -static void hal_set_current_channel_ex( struct hw_data * pHwData, ChanInfo channel ) -{ - struct wb35_reg *reg = &pHwData->reg; - - if( pHwData->SurpriseRemove ) - return; - - printk("Going to channel: %d/%d\n", channel.band, channel.ChanNo); - - RFSynthesizer_SwitchingChannel( pHwData, channel );// Switch channel - pHwData->Channel = channel.ChanNo; - pHwData->band = channel.band; - #ifdef _PE_STATE_DUMP_ - printk("Set channel is %d, band =%d\n", pHwData->Channel, pHwData->band); - #endif - reg->M28_MacControl &= ~0xff; // Clean channel information field - reg->M28_MacControl |= channel.ChanNo; - Wb35Reg_WriteWithCallbackValue( pHwData, 0x0828, reg->M28_MacControl, - (s8 *)&channel, sizeof(ChanInfo)); -} -//--------------------------------------------------------------------------------------------------- -void hal_set_current_channel( struct hw_data * pHwData, ChanInfo channel ) -{ - hal_set_current_channel_ex( pHwData, channel ); -} -//--------------------------------------------------------------------------------------------------- -void hal_set_accept_broadcast( struct hw_data * pHwData, u8 enable ) -{ - struct wb35_reg *reg = &pHwData->reg; - - if( pHwData->SurpriseRemove ) return; - - reg->M00_MacControl &= ~0x02000000;//The HW value - - if (enable) - reg->M00_MacControl |= 0x02000000;//The HW value - - Wb35Reg_Write( pHwData, 0x0800, reg->M00_MacControl ); -} - -//for wep key error detection, we need to accept broadcast packets to be received temporary. -void hal_set_accept_promiscuous( struct hw_data * pHwData, u8 enable) -{ - struct wb35_reg *reg = &pHwData->reg; - - if (pHwData->SurpriseRemove) return; - if (enable) { - reg->M00_MacControl |= 0x00400000; - Wb35Reg_Write( pHwData, 0x0800, reg->M00_MacControl ); - } else { - reg->M00_MacControl&=~0x00400000; - Wb35Reg_Write( pHwData, 0x0800, reg->M00_MacControl ); - } -} - -void hal_set_accept_multicast( struct hw_data * pHwData, u8 enable ) -{ - struct wb35_reg *reg = &pHwData->reg; - - if( pHwData->SurpriseRemove ) return; - - reg->M00_MacControl &= ~0x01000000;//The HW value - if (enable) reg->M00_MacControl |= 0x01000000;//The HW value - Wb35Reg_Write( pHwData, 0x0800, reg->M00_MacControl ); -} - -void hal_set_accept_beacon( struct hw_data * pHwData, u8 enable ) -{ - struct wb35_reg *reg = &pHwData->reg; - - if( pHwData->SurpriseRemove ) return; - - // 20040108 debug - if( !enable )//Due to SME and MLME are not suitable for 35 - return; - - reg->M00_MacControl &= ~0x04000000;//The HW value - if( enable ) - reg->M00_MacControl |= 0x04000000;//The HW value - - Wb35Reg_Write( pHwData, 0x0800, reg->M00_MacControl ); -} -//--------------------------------------------------------------------------------------------------- - -void hal_stop( struct hw_data * pHwData ) -{ - struct wb35_reg *reg = &pHwData->reg; - - pHwData->Wb35Rx.rx_halt = 1; - Wb35Rx_stop( pHwData ); - - pHwData->Wb35Tx.tx_halt = 1; - Wb35Tx_stop( pHwData ); - - reg->D00_DmaControl &= ~0xc0000000;//Tx Off, Rx Off - Wb35Reg_Write( pHwData, 0x0400, reg->D00_DmaControl ); -} - -unsigned char hal_idle(struct hw_data * pHwData) -{ - struct wb35_reg *reg = &pHwData->reg; - struct wb_usb *pWbUsb = &pHwData->WbUsb; - - if( !pHwData->SurpriseRemove && ( pWbUsb->DetectCount || reg->EP0vm_state!=VM_STOP ) ) - return false; - - return true; -} -//--------------------------------------------------------------------------------------------------- -void hal_set_phy_type( struct hw_data * pHwData, u8 PhyType ) -{ - pHwData->phy_type = PhyType; -} - -void hal_set_radio_mode( struct hw_data * pHwData, unsigned char radio_off) -{ - struct wb35_reg *reg = &pHwData->reg; - - if( pHwData->SurpriseRemove ) return; - - if (radio_off) //disable Baseband receive off - { - pHwData->CurrentRadioSw = 1; // off - reg->M24_MacControl &= 0xffffffbf; - } - else - { - pHwData->CurrentRadioSw = 0; // on - reg->M24_MacControl |= 0x00000040; - } - Wb35Reg_Write( pHwData, 0x0824, reg->M24_MacControl ); -} - -u8 hal_get_antenna_number( struct hw_data * pHwData ) -{ - struct wb35_reg *reg = &pHwData->reg; - - if ((reg->BB2C & BIT(11)) == 0) - return 0; - else - return 1; -} - -//---------------------------------------------------------------------------------------------------- -//0 : radio on; 1: radio off -u8 hal_get_hw_radio_off( struct hw_data * pHwData ) -{ - struct wb35_reg *reg = &pHwData->reg; - - if( pHwData->SurpriseRemove ) return 1; - - //read the bit16 of register U1B0 - Wb35Reg_Read( pHwData, 0x3b0, ®->U1B0 ); - if ((reg->U1B0 & 0x00010000)) { - pHwData->CurrentRadioHw = 1; - return 1; - } else { - pHwData->CurrentRadioHw = 0; - return 0; - } -} - -unsigned char hal_get_dxx_reg( struct hw_data * pHwData, u16 number, u32 * pValue ) -{ - if( number < 0x1000 ) - number += 0x1000; - return Wb35Reg_ReadSync( pHwData, number, pValue ); -} - -unsigned char hal_set_dxx_reg( struct hw_data * pHwData, u16 number, u32 value ) -{ - unsigned char ret; - - if( number < 0x1000 ) - number += 0x1000; - ret = Wb35Reg_WriteSync( pHwData, number, value ); - return ret; -} - -void hal_set_rf_power(struct hw_data * pHwData, u8 PowerIndex) -{ - RFSynthesizer_SetPowerIndex( pHwData, PowerIndex ); -} diff --git a/drivers/staging/winbond/wbhal_f.h b/drivers/staging/winbond/wbhal_f.h index efcaefb6aa59..bfdf05d489f0 100644 --- a/drivers/staging/winbond/wbhal_f.h +++ b/drivers/staging/winbond/wbhal_f.h @@ -18,10 +18,6 @@ void hal_clear_all_default_key( struct hw_data * pHwData ); void hal_clear_all_group_key( struct hw_data * pHwData ); void hal_clear_all_mapping_key( struct hw_data * pHwData ); void hal_clear_all_key( struct hw_data * pHwData ); -void hal_get_ethernet_address( struct hw_data * pHwData, u8 *current_address ); -void hal_set_ethernet_address( struct hw_data * pHwData, u8 *current_address ); -void hal_get_permanent_address( struct hw_data * pHwData, u8 *pethernet_address ); -u8 hal_init_hardware(struct ieee80211_hw *hw); void hal_set_power_save_mode( struct hw_data * pHwData, unsigned char power_save, unsigned char wakeup, unsigned char dtim ); void hal_get_power_save_mode( struct hw_data * pHwData, u8 *pin_pwr_save ); void hal_set_slot_time( struct hw_data * pHwData, u8 type ); @@ -33,33 +29,21 @@ void hal_resume_sync_bss( struct hw_data * pHwData); void hal_set_aid( struct hw_data * pHwData, u16 aid ); void hal_set_bssid( struct hw_data * pHwData, u8 *pbssid ); void hal_get_bssid( struct hw_data * pHwData, u8 *pbssid ); -void hal_set_beacon_period( struct hw_data * pHwData, u16 beacon_period ); void hal_set_listen_interval( struct hw_data * pHwData, u16 listen_interval ); void hal_set_cap_info( struct hw_data * pHwData, u16 capability_info ); void hal_set_ssid( struct hw_data * pHwData, u8 *pssid, u8 ssid_len ); -void hal_set_current_channel( struct hw_data * pHwData, ChanInfo channel ); -void hal_set_accept_broadcast( struct hw_data * pHwData, u8 enable ); -void hal_set_accept_multicast( struct hw_data * pHwData, u8 enable ); -void hal_set_accept_beacon( struct hw_data * pHwData, u8 enable ); -void hal_stop( struct hw_data * pHwData ); -void hal_halt( struct hw_data * pHwData, void *ppa_data ); void hal_start_tx0( struct hw_data * pHwData ); -void hal_set_phy_type( struct hw_data * pHwData, u8 PhyType ); #define hal_get_cwmin( _A ) ( (_A)->cwmin ) void hal_set_cwmax( struct hw_data * pHwData, u16 cwin_max ); #define hal_get_cwmax( _A ) ( (_A)->cwmax ) void hal_set_rsn_wpa( struct hw_data * pHwData, u32 * RSN_IE_Bitmap , u32 * RSN_OUI_type , unsigned char bDesiredAuthMode); void hal_set_connect_info( struct hw_data * pHwData, unsigned char boConnect ); u8 hal_get_est_sq3( struct hw_data * pHwData, u8 Count ); -void hal_set_rf_power( struct hw_data * pHwData, u8 PowerIndex ); // 20060621 Modify -void hal_set_radio_mode( struct hw_data * pHwData, unsigned char boValue); void hal_descriptor_indicate( struct hw_data * pHwData, PDESCRIPTOR pDes ); u8 hal_get_antenna_number( struct hw_data * pHwData ); u32 hal_get_bss_pk_cnt( struct hw_data * pHwData ); #define hal_get_region_from_EEPROM( _A ) ( (_A)->reg.EEPROMRegion ) -void hal_set_accept_promiscuous ( struct hw_data * pHwData, u8 enable); #define hal_get_tx_buffer( _A, _B ) Wb35Tx_get_tx_buffer( _A, _B ) -u8 hal_get_hw_radio_off ( struct hw_data * pHwData ); #define hal_software_set( _A ) (_A->SoftwareSet) #define hal_driver_init_OK( _A ) (_A->IsInitOK) #define hal_rssi_boundary_high( _A ) (_A->RSSI_high) @@ -68,8 +52,6 @@ u8 hal_get_hw_radio_off ( struct hw_data * pHwData ); #define PHY_DEBUG( msg, args... ) -unsigned char hal_get_dxx_reg( struct hw_data * pHwData, u16 number, u32 * pValue ); -unsigned char hal_set_dxx_reg( struct hw_data * pHwData, u16 number, u32 value ); #define hal_get_time_count( _P ) (_P->time_count/10) // return 100ms count #define hal_detect_error( _P ) (_P->WbUsb.DetectCount) @@ -82,10 +64,7 @@ unsigned char hal_set_dxx_reg( struct hw_data * pHwData, u16 number, u32 valu #define hal_get_clear_interrupt(_A) #define hal_ibss_disconnect(_A) hal_stop_sync_bss(_A) #define hal_join_request_stop(_A) -unsigned char hal_idle( struct hw_data * pHwData ); #define hw_get_cxx_reg( _A, _B, _C ) #define hw_set_cxx_reg( _A, _B, _C ) -#define hw_get_dxx_reg( _A, _B, _C ) hal_get_dxx_reg( _A, _B, (u32 *)_C ) -#define hw_set_dxx_reg( _A, _B, _C ) hal_set_dxx_reg( _A, _B, (u32)_C ) diff --git a/drivers/staging/winbond/wbhal_s.h b/drivers/staging/winbond/wbhal_s.h index acfebf05d9d7..16d0e6f83113 100644 --- a/drivers/staging/winbond/wbhal_s.h +++ b/drivers/staging/winbond/wbhal_s.h @@ -401,7 +401,6 @@ struct hw_data { // For surprise remove u32 SurpriseRemove; // 0: Normal 1: Surprise remove - u8 InitialResource; u8 IsKeyPreSet; u8 CalOneTime; // 20060630.1 diff --git a/drivers/staging/winbond/wbusb.c b/drivers/staging/winbond/wbusb.c index 3b2d52819b4c..745279c528a2 100644 --- a/drivers/staging/winbond/wbusb.c +++ b/drivers/staging/winbond/wbusb.c @@ -2,6 +2,12 @@ * Copyright 2008 Pavel Machek * * Distribute under GPLv2. + * + * The original driver was written by: + * Jeff Lee + * + * and was adapted to the 2.6 kernel by: + * Costantino Leandro (Rxart Desktop) */ #include #include @@ -13,19 +19,18 @@ #include "wbhal_f.h" #include "wblinux_f.h" -MODULE_AUTHOR("Original by: Jeff Lee Adapted to 2.6.x by Costantino Leandro (Rxart Desktop) "); MODULE_DESCRIPTION("IS89C35 802.11bg WLAN USB Driver"); MODULE_LICENSE("GPL"); MODULE_VERSION("0.1"); static struct usb_device_id wb35_table[] __devinitdata = { - {USB_DEVICE(0x0416, 0x0035)}, - {USB_DEVICE(0x18E8, 0x6201)}, - {USB_DEVICE(0x18E8, 0x6206)}, - {USB_DEVICE(0x18E8, 0x6217)}, - {USB_DEVICE(0x18E8, 0x6230)}, - {USB_DEVICE(0x18E8, 0x6233)}, - {USB_DEVICE(0x1131, 0x2035)}, + { USB_DEVICE(0x0416, 0x0035) }, + { USB_DEVICE(0x18E8, 0x6201) }, + { USB_DEVICE(0x18E8, 0x6206) }, + { USB_DEVICE(0x18E8, 0x6217) }, + { USB_DEVICE(0x18E8, 0x6230) }, + { USB_DEVICE(0x18E8, 0x6233) }, + { USB_DEVICE(0x1131, 0x2035) }, { 0, } }; @@ -36,7 +41,7 @@ static struct ieee80211_rate wbsoft_rates[] = { }; static struct ieee80211_channel wbsoft_channels[] = { - { .center_freq = 2412}, + { .center_freq = 2412 }, }; static struct ieee80211_supported_band wbsoft_band_2GHz = { @@ -47,14 +52,14 @@ static struct ieee80211_supported_band wbsoft_band_2GHz = { }; static int wbsoft_add_interface(struct ieee80211_hw *dev, - struct ieee80211_if_init_conf *conf) + struct ieee80211_if_init_conf *conf) { printk("wbsoft_add interface called\n"); return 0; } static void wbsoft_remove_interface(struct ieee80211_hw *dev, - struct ieee80211_if_init_conf *conf) + struct ieee80211_if_init_conf *conf) { printk("wbsoft_remove interface called\n"); } @@ -79,36 +84,18 @@ static int wbsoft_get_tx_stats(struct ieee80211_hw *hw, } static void wbsoft_configure_filter(struct ieee80211_hw *dev, - unsigned int changed_flags, - unsigned int *total_flags, - int mc_count, struct dev_mc_list *mclist) + unsigned int changed_flags, + unsigned int *total_flags, + int mc_count, struct dev_mc_list *mclist) { - unsigned int bit_nr, new_flags; - u32 mc_filter[2]; - int i; + unsigned int new_flags; new_flags = 0; - if (*total_flags & FIF_PROMISC_IN_BSS) { + if (*total_flags & FIF_PROMISC_IN_BSS) new_flags |= FIF_PROMISC_IN_BSS; - mc_filter[1] = mc_filter[0] = ~0; - } else if ((*total_flags & FIF_ALLMULTI) || (mc_count > 32)) { + else if ((*total_flags & FIF_ALLMULTI) || (mc_count > 32)) new_flags |= FIF_ALLMULTI; - mc_filter[1] = mc_filter[0] = ~0; - } else { - mc_filter[1] = mc_filter[0] = 0; - for (i = 0; i < mc_count; i++) { - if (!mclist) - break; - printk("Should call ether_crc here\n"); - //bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26; - bit_nr = 0; - - bit_nr &= 0x3F; - mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); - mclist = mclist->next; - } - } dev->flags &= ~IEEE80211_HW_RX_INCLUDES_FCS; @@ -124,7 +111,6 @@ static int wbsoft_tx(struct ieee80211_hw *dev, struct sk_buff *skb) return NETDEV_TX_OK; } - static int wbsoft_start(struct ieee80211_hw *dev) { struct wbsoft_priv *priv = dev->priv; @@ -134,6 +120,127 @@ static int wbsoft_start(struct ieee80211_hw *dev) return 0; } +static void hal_set_radio_mode(struct hw_data *pHwData, unsigned char radio_off) +{ + struct wb35_reg *reg = &pHwData->reg; + + if (pHwData->SurpriseRemove) + return; + + if (radio_off) //disable Baseband receive off + { + pHwData->CurrentRadioSw = 1; // off + reg->M24_MacControl &= 0xffffffbf; + } else { + pHwData->CurrentRadioSw = 0; // on + reg->M24_MacControl |= 0x00000040; + } + Wb35Reg_Write(pHwData, 0x0824, reg->M24_MacControl); +} + +static void hal_set_beacon_period(struct hw_data *pHwData, u16 beacon_period) +{ + u32 tmp; + + if (pHwData->SurpriseRemove) + return; + + pHwData->BeaconPeriod = beacon_period; + tmp = pHwData->BeaconPeriod << 16; + tmp |= pHwData->ProbeDelay; + Wb35Reg_Write(pHwData, 0x0848, tmp); +} + +static void +hal_set_current_channel_ex(struct hw_data *pHwData, ChanInfo channel) +{ + struct wb35_reg *reg = &pHwData->reg; + + if (pHwData->SurpriseRemove) + return; + + printk("Going to channel: %d/%d\n", channel.band, channel.ChanNo); + + RFSynthesizer_SwitchingChannel(pHwData, channel); // Switch channel + pHwData->Channel = channel.ChanNo; + pHwData->band = channel.band; +#ifdef _PE_STATE_DUMP_ + printk("Set channel is %d, band =%d\n", pHwData->Channel, + pHwData->band); +#endif + reg->M28_MacControl &= ~0xff; // Clean channel information field + reg->M28_MacControl |= channel.ChanNo; + Wb35Reg_WriteWithCallbackValue(pHwData, 0x0828, reg->M28_MacControl, + (s8 *) & channel, sizeof(ChanInfo)); +} + +static void hal_set_current_channel(struct hw_data *pHwData, ChanInfo channel) +{ + hal_set_current_channel_ex(pHwData, channel); +} + +static void hal_set_accept_broadcast(struct hw_data *pHwData, u8 enable) +{ + struct wb35_reg *reg = &pHwData->reg; + + if (pHwData->SurpriseRemove) + return; + + reg->M00_MacControl &= ~0x02000000; //The HW value + + if (enable) + reg->M00_MacControl |= 0x02000000; //The HW value + + Wb35Reg_Write(pHwData, 0x0800, reg->M00_MacControl); +} + +//for wep key error detection, we need to accept broadcast packets to be received temporary. +static void hal_set_accept_promiscuous(struct hw_data *pHwData, u8 enable) +{ + struct wb35_reg *reg = &pHwData->reg; + + if (pHwData->SurpriseRemove) + return; + if (enable) { + reg->M00_MacControl |= 0x00400000; + Wb35Reg_Write(pHwData, 0x0800, reg->M00_MacControl); + } else { + reg->M00_MacControl &= ~0x00400000; + Wb35Reg_Write(pHwData, 0x0800, reg->M00_MacControl); + } +} + +static void hal_set_accept_multicast(struct hw_data *pHwData, u8 enable) +{ + struct wb35_reg *reg = &pHwData->reg; + + if (pHwData->SurpriseRemove) + return; + + reg->M00_MacControl &= ~0x01000000; //The HW value + if (enable) + reg->M00_MacControl |= 0x01000000; //The HW value + Wb35Reg_Write(pHwData, 0x0800, reg->M00_MacControl); +} + +static void hal_set_accept_beacon(struct hw_data *pHwData, u8 enable) +{ + struct wb35_reg *reg = &pHwData->reg; + + if (pHwData->SurpriseRemove) + return; + + // 20040108 debug + if (!enable) //Due to SME and MLME are not suitable for 35 + return; + + reg->M00_MacControl &= ~0x04000000; //The HW value + if (enable) + reg->M00_MacControl |= 0x04000000; //The HW value + + Wb35Reg_Write(pHwData, 0x0800, reg->M00_MacControl); +} + static int wbsoft_config(struct ieee80211_hw *dev, u32 changed) { struct wbsoft_priv *priv = dev->priv; @@ -142,36 +249,18 @@ static int wbsoft_config(struct ieee80211_hw *dev, u32 changed) printk("wbsoft_config called\n"); + /* Should use channel_num, or something, as that is already pre-translated */ ch.band = 1; - ch.ChanNo = 1; /* Should use channel_num, or something, as that is already pre-translated */ - + ch.ChanNo = 1; hal_set_current_channel(&priv->sHwData, ch); hal_set_beacon_period(&priv->sHwData, conf->beacon_int); -// hal_set_cap_info(&priv->sHwData, ?? ); -// hal_set_ssid(struct hw_data * pHwData, u8 * pssid, u8 ssid_len); ?? hal_set_accept_broadcast(&priv->sHwData, 1); - hal_set_accept_promiscuous(&priv->sHwData, 1); - hal_set_accept_multicast(&priv->sHwData, 1); - hal_set_accept_beacon(&priv->sHwData, 1); - hal_set_radio_mode(&priv->sHwData, 0); - //hal_set_antenna_number( struct hw_data * pHwData, u8 number ) - //hal_set_rf_power(struct hw_data * pHwData, u8 PowerIndex) + hal_set_accept_promiscuous(&priv->sHwData, 1); + hal_set_accept_multicast(&priv->sHwData, 1); + hal_set_accept_beacon(&priv->sHwData, 1); + hal_set_radio_mode(&priv->sHwData, 0); - -// hal_start_bss(&priv->sHwData, WLAN_BSSTYPE_INFRASTRUCTURE); ?? - -//void hal_set_rates(struct hw_data * pHwData, u8 * pbss_rates, -// u8 length, unsigned char basic_rate_set) - - return 0; -} - -static int wbsoft_config_interface(struct ieee80211_hw *dev, - struct ieee80211_vif *vif, - struct ieee80211_if_conf *conf) -{ - printk("wbsoft_config_interface called\n"); return 0; } @@ -183,63 +272,448 @@ static u64 wbsoft_get_tsf(struct ieee80211_hw *dev) static const struct ieee80211_ops wbsoft_ops = { .tx = wbsoft_tx, - .start = wbsoft_start, /* Start can be pretty much empty as we do wb35_hw_init() during probe? */ + .start = wbsoft_start, .stop = wbsoft_stop, .add_interface = wbsoft_add_interface, .remove_interface = wbsoft_remove_interface, .config = wbsoft_config, - .config_interface = wbsoft_config_interface, .configure_filter = wbsoft_configure_filter, .get_stats = wbsoft_get_stats, .get_tx_stats = wbsoft_get_tx_stats, .get_tsf = wbsoft_get_tsf, -// conf_tx: hal_set_cwmin()/hal_set_cwmax; }; -static unsigned char wb35_hw_init(struct ieee80211_hw *hw) +static void +hal_set_ethernet_address(struct hw_data *pHwData, u8 * current_address) +{ + u32 ltmp[2]; + + if (pHwData->SurpriseRemove) + return; + + memcpy(pHwData->CurrentMacAddress, current_address, ETH_ALEN); + + ltmp[0] = cpu_to_le32(*(u32 *) pHwData->CurrentMacAddress); + ltmp[1] = + cpu_to_le32(*(u32 *) (pHwData->CurrentMacAddress + 4)) & 0xffff; + + Wb35Reg_BurstWrite(pHwData, 0x03e8, ltmp, 2, AUTO_INCREMENT); +} + +static void +hal_get_permanent_address(struct hw_data *pHwData, u8 * pethernet_address) +{ + if (pHwData->SurpriseRemove) + return; + + memcpy(pethernet_address, pHwData->PermanentMacAddress, 6); +} + +static void hal_stop(struct hw_data *pHwData) +{ + struct wb35_reg *reg = &pHwData->reg; + + pHwData->Wb35Rx.rx_halt = 1; + Wb35Rx_stop(pHwData); + + pHwData->Wb35Tx.tx_halt = 1; + Wb35Tx_stop(pHwData); + + reg->D00_DmaControl &= ~0xc0000000; //Tx Off, Rx Off + Wb35Reg_Write(pHwData, 0x0400, reg->D00_DmaControl); +} + +static unsigned char hal_idle(struct hw_data *pHwData) +{ + struct wb35_reg *reg = &pHwData->reg; + struct wb_usb *pWbUsb = &pHwData->WbUsb; + + if (!pHwData->SurpriseRemove + && (pWbUsb->DetectCount || reg->EP0vm_state != VM_STOP)) + return false; + + return true; +} + +u8 hal_get_antenna_number(struct hw_data *pHwData) +{ + struct wb35_reg *reg = &pHwData->reg; + + if ((reg->BB2C & BIT(11)) == 0) + return 0; + else + return 1; +} + +/* 0 : radio on; 1: radio off */ +static u8 hal_get_hw_radio_off(struct hw_data * pHwData) +{ + struct wb35_reg *reg = &pHwData->reg; + + if (pHwData->SurpriseRemove) + return 1; + + //read the bit16 of register U1B0 + Wb35Reg_Read(pHwData, 0x3b0, ®->U1B0); + if ((reg->U1B0 & 0x00010000)) { + pHwData->CurrentRadioHw = 1; + return 1; + } else { + pHwData->CurrentRadioHw = 0; + return 0; + } +} + +static u8 LED_GRAY[20] = { + 0, 3, 4, 6, 8, 10, 11, 12, 13, 14, 15, 14, 13, 12, 11, 10, 8, 6, 4, 2 +}; + +static u8 LED_GRAY2[30] = { + 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 15, 14, 13, 12, 11, 10, 9, 8 +}; + +static void hal_led_control(unsigned long data) +{ + struct wbsoft_priv *adapter = (struct wbsoft_priv *)data; + struct hw_data *pHwData = &adapter->sHwData; + struct wb35_reg *reg = &pHwData->reg; + u32 LEDSet = (pHwData->SoftwareSet & HAL_LED_SET_MASK) >> HAL_LED_SET_SHIFT; + u32 TimeInterval = 500, ltmp, ltmp2; + ltmp = 0; + + if (pHwData->SurpriseRemove) + return; + + if (pHwData->LED_control) { + ltmp2 = pHwData->LED_control & 0xff; + if (ltmp2 == 5) // 5 is WPS mode + { + TimeInterval = 100; + ltmp2 = (pHwData->LED_control >> 8) & 0xff; + switch (ltmp2) { + case 1: // [0.2 On][0.1 Off]... + pHwData->LED_Blinking %= 3; + ltmp = 0x1010; // Led 1 & 0 Green and Red + if (pHwData->LED_Blinking == 2) // Turn off + ltmp = 0; + break; + case 2: // [0.1 On][0.1 Off]... + pHwData->LED_Blinking %= 2; + ltmp = 0x0010; // Led 0 red color + if (pHwData->LED_Blinking) // Turn off + ltmp = 0; + break; + case 3: // [0.1 On][0.1 Off][0.1 On][0.1 Off][0.1 On][0.1 Off][0.1 On][0.1 Off][0.1 On][0.1 Off][0.5 Off]... + pHwData->LED_Blinking %= 15; + ltmp = 0x0010; // Led 0 red color + if ((pHwData->LED_Blinking >= 9) || (pHwData->LED_Blinking % 2)) // Turn off 0.6 sec + ltmp = 0; + break; + case 4: // [300 On][ off ] + ltmp = 0x1000; // Led 1 Green color + if (pHwData->LED_Blinking >= 3000) + ltmp = 0; // led maybe on after 300sec * 32bit counter overlap. + break; + } + pHwData->LED_Blinking++; + + reg->U1BC_LEDConfigure = ltmp; + if (LEDSet != 7) // Only 111 mode has 2 LEDs on PCB. + { + reg->U1BC_LEDConfigure |= (ltmp & 0xff) << 8; // Copy LED result to each LED control register + reg->U1BC_LEDConfigure |= (ltmp & 0xff00) >> 8; + } + Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); + } + } else if (pHwData->CurrentRadioSw || pHwData->CurrentRadioHw) // If radio off + { + if (reg->U1BC_LEDConfigure & 0x1010) { + reg->U1BC_LEDConfigure &= ~0x1010; + Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); + } + } else { + switch (LEDSet) { + case 4: // [100] Only 1 Led be placed on PCB and use pin 21 of IC. Use LED_0 for showing + if (!pHwData->LED_LinkOn) // Blink only if not Link On + { + // Blinking if scanning is on progress + if (pHwData->LED_Scanning) { + if (pHwData->LED_Blinking == 0) { + reg->U1BC_LEDConfigure |= 0x10; + Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); // LED_0 On + pHwData->LED_Blinking = 1; + TimeInterval = 300; + } else { + reg->U1BC_LEDConfigure &= ~0x10; + Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); // LED_0 Off + pHwData->LED_Blinking = 0; + TimeInterval = 300; + } + } else { + //Turn Off LED_0 + if (reg->U1BC_LEDConfigure & 0x10) { + reg->U1BC_LEDConfigure &= ~0x10; + Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); // LED_0 Off + } + } + } else { + // Turn On LED_0 + if ((reg->U1BC_LEDConfigure & 0x10) == 0) { + reg->U1BC_LEDConfigure |= 0x10; + Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); // LED_0 Off + } + } + break; + + case 6: // [110] Only 1 Led be placed on PCB and use pin 21 of IC. Use LED_0 for showing + if (!pHwData->LED_LinkOn) // Blink only if not Link On + { + // Blinking if scanning is on progress + if (pHwData->LED_Scanning) { + if (pHwData->LED_Blinking == 0) { + reg->U1BC_LEDConfigure &= ~0xf; + reg->U1BC_LEDConfigure |= 0x10; + Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); // LED_0 On + pHwData->LED_Blinking = 1; + TimeInterval = 300; + } else { + reg->U1BC_LEDConfigure &= ~0x1f; + Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); // LED_0 Off + pHwData->LED_Blinking = 0; + TimeInterval = 300; + } + } else { + // 20060901 Gray blinking if in disconnect state and not scanning + ltmp = reg->U1BC_LEDConfigure; + reg->U1BC_LEDConfigure &= ~0x1f; + if (LED_GRAY2[(pHwData->LED_Blinking % 30)]) { + reg->U1BC_LEDConfigure |= 0x10; + reg->U1BC_LEDConfigure |= + LED_GRAY2[(pHwData->LED_Blinking % 30)]; + } + pHwData->LED_Blinking++; + if (reg->U1BC_LEDConfigure != ltmp) + Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); // LED_0 Off + TimeInterval = 100; + } + } else { + // Turn On LED_0 + if ((reg->U1BC_LEDConfigure & 0x10) == 0) { + reg->U1BC_LEDConfigure |= 0x10; + Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); // LED_0 Off + } + } + break; + + case 5: // [101] Only 1 Led be placed on PCB and use LED_1 for showing + if (!pHwData->LED_LinkOn) // Blink only if not Link On + { + // Blinking if scanning is on progress + if (pHwData->LED_Scanning) { + if (pHwData->LED_Blinking == 0) { + reg->U1BC_LEDConfigure |= + 0x1000; + Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); // LED_1 On + pHwData->LED_Blinking = 1; + TimeInterval = 300; + } else { + reg->U1BC_LEDConfigure &= + ~0x1000; + Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); // LED_1 Off + pHwData->LED_Blinking = 0; + TimeInterval = 300; + } + } else { + //Turn Off LED_1 + if (reg->U1BC_LEDConfigure & 0x1000) { + reg->U1BC_LEDConfigure &= + ~0x1000; + Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); // LED_1 Off + } + } + } else { + // Is transmitting/receiving ?? + if ((adapter->RxByteCount != + pHwData->RxByteCountLast) + || (adapter->TxByteCount != + pHwData->TxByteCountLast)) { + if ((reg->U1BC_LEDConfigure & 0x3000) != + 0x3000) { + reg->U1BC_LEDConfigure |= + 0x3000; + Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); // LED_1 On + } + // Update variable + pHwData->RxByteCountLast = + adapter->RxByteCount; + pHwData->TxByteCountLast = + adapter->TxByteCount; + TimeInterval = 200; + } else { + // Turn On LED_1 and blinking if transmitting/receiving + if ((reg->U1BC_LEDConfigure & 0x3000) != + 0x1000) { + reg->U1BC_LEDConfigure &= + ~0x3000; + reg->U1BC_LEDConfigure |= + 0x1000; + Wb35Reg_Write(pHwData, 0x03bc, reg->U1BC_LEDConfigure); // LED_1 On + } + } + } + break; + + default: // Default setting. 2 LED be placed on PCB. LED_0: Link On LED_1 Active + if ((reg->U1BC_LEDConfigure & 0x3000) != 0x3000) { + reg->U1BC_LEDConfigure |= 0x3000; // LED_1 is always on and event enable + Wb35Reg_Write(pHwData, 0x03bc, + reg->U1BC_LEDConfigure); + } + + if (pHwData->LED_Blinking) { + // Gray blinking + reg->U1BC_LEDConfigure &= ~0x0f; + reg->U1BC_LEDConfigure |= 0x10; + reg->U1BC_LEDConfigure |= + LED_GRAY[(pHwData->LED_Blinking - 1) % 20]; + Wb35Reg_Write(pHwData, 0x03bc, + reg->U1BC_LEDConfigure); + + pHwData->LED_Blinking += 2; + if (pHwData->LED_Blinking < 40) + TimeInterval = 100; + else { + pHwData->LED_Blinking = 0; // Stop blinking + reg->U1BC_LEDConfigure &= ~0x0f; + Wb35Reg_Write(pHwData, 0x03bc, + reg->U1BC_LEDConfigure); + } + break; + } + + if (pHwData->LED_LinkOn) { + if (!(reg->U1BC_LEDConfigure & 0x10)) // Check the LED_0 + { + //Try to turn ON LED_0 after gray blinking + reg->U1BC_LEDConfigure |= 0x10; + pHwData->LED_Blinking = 1; //Start blinking + TimeInterval = 50; + } + } else { + if (reg->U1BC_LEDConfigure & 0x10) // Check the LED_0 + { + reg->U1BC_LEDConfigure &= ~0x10; + Wb35Reg_Write(pHwData, 0x03bc, + reg->U1BC_LEDConfigure); + } + } + break; + } + + //20060828.1 Active send null packet to avoid AP disconnect + if (pHwData->LED_LinkOn) { + pHwData->NullPacketCount += TimeInterval; + if (pHwData->NullPacketCount >= + DEFAULT_NULL_PACKET_COUNT) { + pHwData->NullPacketCount = 0; + } + } + } + + pHwData->time_count += TimeInterval; + Wb35Tx_CurrentTime(adapter, pHwData->time_count); // 20060928 add + pHwData->LEDTimer.expires = jiffies + msecs_to_jiffies(TimeInterval); + add_timer(&pHwData->LEDTimer); +} + +static int hal_init_hardware(struct ieee80211_hw *hw) { struct wbsoft_priv *priv = hw->priv; - struct hw_data * pHwData; - u8 *pMacAddr; - u8 *pMacAddr2; - u32 InitStep = 0; - u8 EEPROM_region; - u8 HwRadioOff; + struct hw_data *pHwData = &priv->sHwData; + u16 SoftwareSet; + + pHwData->MaxReceiveLifeTime = DEFAULT_MSDU_LIFE_TIME; + pHwData->FragmentThreshold = DEFAULT_FRAGMENT_THRESHOLD; + + if (!Wb35Reg_initial(pHwData)) + goto error_reg_destroy; + + if (!Wb35Tx_initial(pHwData)) + goto error_tx_destroy; + + if (!Wb35Rx_initial(pHwData)) + goto error_rx_destroy; + + init_timer(&pHwData->LEDTimer); + pHwData->LEDTimer.function = hal_led_control; + pHwData->LEDTimer.data = (unsigned long)priv; + pHwData->LEDTimer.expires = jiffies + msecs_to_jiffies(1000); + add_timer(&pHwData->LEDTimer); + + SoftwareSet = hal_software_set(pHwData); + +#ifdef Vendor2 + // Try to make sure the EEPROM contain + SoftwareSet >>= 8; + if (SoftwareSet != 0x82) + return false; +#endif + + Wb35Rx_start(hw); + Wb35Tx_EP2VM_start(priv); + + return 0; + +error_rx_destroy: + Wb35Rx_destroy(pHwData); +error_tx_destroy: + Wb35Tx_destroy(pHwData); +error_reg_destroy: + Wb35Reg_destroy(pHwData); + + pHwData->SurpriseRemove = 1; + return -EINVAL; +} + +static int wb35_hw_init(struct ieee80211_hw *hw) +{ + struct wbsoft_priv *priv = hw->priv; + struct hw_data *pHwData = &priv->sHwData; + u8 EEPROM_region; + u8 HwRadioOff; + u8 *pMacAddr2; + u8 *pMacAddr; + int err; + + pHwData->phy_type = RF_DECIDE_BY_INF; + + priv->Mds.TxRTSThreshold = DEFAULT_RTSThreshold; + priv->Mds.TxFragmentThreshold = DEFAULT_FRAGMENT_THRESHOLD; + + priv->sLocalPara.region_INF = REGION_AUTO; + priv->sLocalPara.TxRateMode = RATE_AUTO; + priv->sLocalPara.bMacOperationMode = MODE_802_11_BG; + priv->sLocalPara.MTUsize = MAX_ETHERNET_PACKET_SIZE; + priv->sLocalPara.bPreambleMode = AUTO_MODE; + priv->sLocalPara.bWepKeyError = false; + priv->sLocalPara.bToSelfPacketReceived = false; + priv->sLocalPara.WepKeyDetectTimerCount = 2 * 100; /* 2 seconds */ - // - // Setting default value for Linux - // - priv->sLocalPara.region_INF = REGION_AUTO; - priv->sLocalPara.TxRateMode = RATE_AUTO; - priv->sLocalPara.bMacOperationMode = MODE_802_11_BG; // B/G mode - priv->Mds.TxRTSThreshold = DEFAULT_RTSThreshold; - priv->Mds.TxFragmentThreshold = DEFAULT_FRAGMENT_THRESHOLD; - hal_set_phy_type( &priv->sHwData, RF_WB_242_1 ); - priv->sLocalPara.MTUsize = MAX_ETHERNET_PACKET_SIZE; - priv->sLocalPara.bPreambleMode = AUTO_MODE; priv->sLocalPara.RadioOffStatus.boSwRadioOff = false; - pHwData = &priv->sHwData; - hal_set_phy_type( pHwData, RF_DECIDE_BY_INF ); - //added by ws for wep key error detection - priv->sLocalPara.bWepKeyError= false; - priv->sLocalPara.bToSelfPacketReceived = false; - priv->sLocalPara.WepKeyDetectTimerCount= 2 * 100; /// 2 seconds - - // Initial USB hal - InitStep = 1; - pHwData = &priv->sHwData; - if (!hal_init_hardware(hw)) + err = hal_init_hardware(hw); + if (err) goto error; - EEPROM_region = hal_get_region_from_EEPROM( pHwData ); + EEPROM_region = hal_get_region_from_EEPROM(pHwData); if (EEPROM_region != REGION_AUTO) priv->sLocalPara.region = EEPROM_region; else { if (priv->sLocalPara.region_INF != REGION_AUTO) priv->sLocalPara.region = priv->sLocalPara.region_INF; else - priv->sLocalPara.region = REGION_USA; //default setting + priv->sLocalPara.region = REGION_USA; /* default setting */ } // Get Software setting flag from hal @@ -247,93 +721,80 @@ static unsigned char wb35_hw_init(struct ieee80211_hw *hw) if (hal_software_set(pHwData) & 0x00000001) priv->sLocalPara.boAntennaDiversity = true; - // - // For TS module - // - InitStep = 2; - - // For MDS module - InitStep = 3; Mds_initial(priv); - //======================================= - // Initialize the SME, SCAN, MLME, ROAM - //======================================= - InitStep = 4; - InitStep = 5; - InitStep = 6; - - // If no user-defined address in the registry, use the addresss "burned" on the NIC instead. + /* + * If no user-defined address in the registry, use the addresss + * "burned" on the NIC instead. + */ pMacAddr = priv->sLocalPara.ThisMacAddress; pMacAddr2 = priv->sLocalPara.PermanentAddress; - hal_get_permanent_address( pHwData, priv->sLocalPara.PermanentAddress );// Reading ethernet address from EEPROM + + /* Reading ethernet address from EEPROM */ + hal_get_permanent_address(pHwData, priv->sLocalPara.PermanentAddress); if (memcmp(pMacAddr, "\x00\x00\x00\x00\x00\x00", MAC_ADDR_LENGTH) == 0) memcpy(pMacAddr, pMacAddr2, MAC_ADDR_LENGTH); else { - // Set the user define MAC address - hal_set_ethernet_address(pHwData, priv->sLocalPara.ThisMacAddress); + /* Set the user define MAC address */ + hal_set_ethernet_address(pHwData, + priv->sLocalPara.ThisMacAddress); } - //get current antenna priv->sLocalPara.bAntennaNo = hal_get_antenna_number(pHwData); #ifdef _PE_STATE_DUMP_ printk("Driver init, antenna no = %d\n", psLOCAL->bAntennaNo); #endif - hal_get_hw_radio_off( pHwData ); + hal_get_hw_radio_off(pHwData); - // Waiting for HAL setting OK + /* Waiting for HAL setting OK */ while (!hal_idle(pHwData)) msleep(10); MTO_Init(priv); - HwRadioOff = hal_get_hw_radio_off( pHwData ); + HwRadioOff = hal_get_hw_radio_off(pHwData); priv->sLocalPara.RadioOffStatus.boHwRadioOff = !!HwRadioOff; - hal_set_radio_mode( pHwData, (unsigned char)(priv->sLocalPara.RadioOffStatus.boSwRadioOff || priv->sLocalPara.RadioOffStatus.boHwRadioOff) ); + hal_set_radio_mode(pHwData, + (unsigned char)(priv->sLocalPara.RadioOffStatus. + boSwRadioOff + || priv->sLocalPara.RadioOffStatus. + boHwRadioOff)); - hal_driver_init_OK(pHwData) = 1; // Notify hal that the driver is ready now. - //set a tx power for reference..... -// sme_set_tx_power_level(priv, 12); FIXME? - return true; + /* Notify hal that the driver is ready now. */ + hal_driver_init_OK(pHwData) = 1; error: - switch (InitStep) { - case 5: - case 4: - case 3: Mds_Destroy( priv ); - case 2: - case 1: hal_halt( pHwData, NULL ); - case 0: break; - } - - return false; + return err; } -static int wb35_probe(struct usb_interface *intf, const struct usb_device_id *id_table) +static int wb35_probe(struct usb_interface *intf, + const struct usb_device_id *id_table) { - struct wb_usb *pWbUsb; - struct usb_host_interface *interface; - struct usb_endpoint_descriptor *endpoint; - u32 ltmp; struct usb_device *udev = interface_to_usbdev(intf); - struct wbsoft_priv *priv; + struct usb_endpoint_descriptor *endpoint; + struct usb_host_interface *interface; struct ieee80211_hw *dev; + struct wbsoft_priv *priv; + struct wb_usb *pWbUsb; int nr, err; + u32 ltmp; usb_get_dev(udev); - // 20060630.2 Check the device if it already be opened - nr = usb_control_msg(udev, usb_rcvctrlpipe( udev, 0 ), - 0x01, USB_TYPE_VENDOR|USB_RECIP_DEVICE|USB_DIR_IN, - 0x0, 0x400, <mp, 4, HZ*100 ); + /* Check the device if it already be opened */ + nr = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + 0x01, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, + 0x0, 0x400, <mp, 4, HZ * 100); if (nr < 0) { err = nr; goto error; } + /* Is already initialized? */ ltmp = cpu_to_le32(ltmp); - if (ltmp) { // Is already initialized? + if (ltmp) { err = -EBUSY; goto error; } @@ -351,23 +812,22 @@ static int wb35_probe(struct usb_interface *intf, const struct usb_device_id *id pWbUsb = &priv->sHwData.WbUsb; pWbUsb->udev = udev; - interface = intf->cur_altsetting; - endpoint = &interface->endpoint[0].desc; + interface = intf->cur_altsetting; + endpoint = &interface->endpoint[0].desc; if (endpoint[2].wMaxPacketSize == 512) { printk("[w35und] Working on USB 2.0\n"); pWbUsb->IsUsb20 = 1; } - if (!wb35_hw_init(dev)) { - err = -EINVAL; + err = wb35_hw_init(dev); + if (err) goto error_free_hw; - } SET_IEEE80211_DEV(dev, &udev->dev); { - struct hw_data * pHwData = &priv->sHwData; - unsigned char dev_addr[MAX_ADDR_LEN]; + struct hw_data *pHwData = &priv->sHwData; + unsigned char dev_addr[MAX_ADDR_LEN]; hal_get_permanent_address(pHwData, dev_addr); SET_IEEE80211_PERM_ADDR(dev, dev_addr); } @@ -397,22 +857,31 @@ error: return err; } +static void hal_halt(struct hw_data *pHwData) +{ + del_timer_sync(&pHwData->LEDTimer); + /* XXX: Wait for Timer DPC exit. */ + msleep(100); + Wb35Rx_destroy(pHwData); + Wb35Tx_destroy(pHwData); + Wb35Reg_destroy(pHwData); +} + static void wb35_hw_halt(struct wbsoft_priv *adapter) { - Mds_Destroy( adapter ); + Mds_Destroy(adapter); - // Turn off Rx and Tx hardware ability - hal_stop( &adapter->sHwData ); + /* Turn off Rx and Tx hardware ability */ + hal_stop(&adapter->sHwData); #ifdef _PE_USB_INI_DUMP_ printk("[w35und] Hal_stop O.K.\n"); #endif - msleep(100);// Waiting Irp completed + /* Waiting Irp completed */ + msleep(100); - // Halt the HAL - hal_halt(&adapter->sHwData, NULL); + hal_halt(&adapter->sHwData); } - static void wb35_disconnect(struct usb_interface *intf) { struct ieee80211_hw *hw = usb_get_intfdata(intf); diff --git a/drivers/staging/wlan-ng/README b/drivers/staging/wlan-ng/README index 028c299b613e..d0621f827c01 100644 --- a/drivers/staging/wlan-ng/README +++ b/drivers/staging/wlan-ng/README @@ -1,7 +1,6 @@ TODO: - checkpatch.pl cleanups - sparse warnings - - Lindent cleanups - move to use the in-kernel wireless stack Please send any patches or complaints about this driver to Greg diff --git a/drivers/staging/wlan-ng/hfa384x.h b/drivers/staging/wlan-ng/hfa384x.h index f3e87173471e..46cce8159e59 100644 --- a/drivers/staging/wlan-ng/hfa384x.h +++ b/drivers/staging/wlan-ng/hfa384x.h @@ -63,8 +63,9 @@ /*--- Mins & Maxs -----------------------------------*/ #define HFA384x_PORTID_MAX ((u16)7) #define HFA384x_NUMPORTS_MAX ((u16)(HFA384x_PORTID_MAX+1)) -#define HFA384x_PDR_LEN_MAX ((u16)512) /* in bytes, from EK */ -#define HFA384x_PDA_LEN_MAX ((u16)1024) /* in bytes, from EK */ +#define HFA384x_PDR_LEN_MAX ((u16)512) /* in bytes, from EK */ +#define HFA384x_PDA_RECS_MAX ((u16)200) /* a guess */ +#define HFA384x_PDA_LEN_MAX ((u16)1024) /* in bytes, from EK */ #define HFA384x_SCANRESULT_MAX ((u16)31) #define HFA384x_HSCANRESULT_MAX ((u16)31) #define HFA384x_CHINFORESULT_MAX ((u16)16) @@ -629,7 +630,7 @@ typedef struct hfa384x_ScanResultSub { typedef struct hfa384x_ScanResult { u16 rsvd; u16 scanreason; - hfa384x_ScanResultSub_t result[HFA384x_SCANRESULT_MAX]; + hfa384x_ScanResultSub_t result[HFA384x_SCANRESULT_MAX]; } __attribute__ ((packed)) hfa384x_ScanResult_t; /*-- Inquiry Frame, Diagnose: ChInfo Results & Subfields--*/ @@ -645,7 +646,7 @@ typedef struct hfa384x_ChInfoResultSub { typedef struct hfa384x_ChInfoResult { u16 scanchannels; - hfa384x_ChInfoResultSub_t result[HFA384x_CHINFORESULT_MAX]; + hfa384x_ChInfoResultSub_t result[HFA384x_CHINFORESULT_MAX]; } __attribute__ ((packed)) hfa384x_ChInfoResult_t; /*-- Inquiry Frame, Diagnose: Host Scan Results & Subfields--*/ @@ -665,7 +666,7 @@ typedef struct hfa384x_HScanResultSub { typedef struct hfa384x_HScanResult { u16 nresult; u16 rsvd; - hfa384x_HScanResultSub_t result[HFA384x_HSCANRESULT_MAX]; + hfa384x_HScanResultSub_t result[HFA384x_HSCANRESULT_MAX]; } __attribute__ ((packed)) hfa384x_HScanResult_t; /*-- Unsolicited Frame, MAC Mgmt: LinkStatus --*/ @@ -882,6 +883,213 @@ typedef union hfa384x_usbin { u8 boguspad[3000]; } __attribute__ ((packed)) hfa384x_usbin_t; +/*-------------------------------------------------------------------- +PD record structures. +--------------------------------------------------------------------*/ + +typedef struct hfa384x_pdr_pcb_partnum { + u8 num[8]; +} __attribute__ ((packed)) hfa384x_pdr_pcb_partnum_t; + +typedef struct hfa384x_pdr_pcb_tracenum { + u8 num[8]; +} __attribute__ ((packed)) hfa384x_pdr_pcb_tracenum_t; + +typedef struct hfa384x_pdr_nic_serial { + u8 num[12]; +} __attribute__ ((packed)) hfa384x_pdr_nic_serial_t; + +typedef struct hfa384x_pdr_mkk_measurements { + double carrier_freq; + double occupied_band; + double power_density; + double tx_spur_f1; + double tx_spur_f2; + double tx_spur_f3; + double tx_spur_f4; + double tx_spur_l1; + double tx_spur_l2; + double tx_spur_l3; + double tx_spur_l4; + double rx_spur_f1; + double rx_spur_f2; + double rx_spur_l1; + double rx_spur_l2; +} __attribute__ ((packed)) hfa384x_pdr_mkk_measurements_t; + +typedef struct hfa384x_pdr_nic_ramsize { + u8 size[12]; /* units of KB */ +} __attribute__ ((packed)) hfa384x_pdr_nic_ramsize_t; + +typedef struct hfa384x_pdr_mfisuprange { + u16 id; + u16 variant; + u16 bottom; + u16 top; +} __attribute__ ((packed)) hfa384x_pdr_mfisuprange_t; + +typedef struct hfa384x_pdr_cfisuprange { + u16 id; + u16 variant; + u16 bottom; + u16 top; +} __attribute__ ((packed)) hfa384x_pdr_cfisuprange_t; + +typedef struct hfa384x_pdr_nicid { + u16 id; + u16 variant; + u16 major; + u16 minor; +} __attribute__ ((packed)) hfa384x_pdr_nicid_t; + +typedef struct hfa384x_pdr_refdac_measurements { + u16 value[0]; +} __attribute__ ((packed)) hfa384x_pdr_refdac_measurements_t; + +typedef struct hfa384x_pdr_vgdac_measurements { + u16 value[0]; +} __attribute__ ((packed)) hfa384x_pdr_vgdac_measurements_t; + +typedef struct hfa384x_pdr_level_comp_measurements { + u16 value[0]; +} __attribute__ ((packed)) hfa384x_pdr_level_compc_measurements_t; + +typedef struct hfa384x_pdr_mac_address { + u8 addr[6]; +} __attribute__ ((packed)) hfa384x_pdr_mac_address_t; + +typedef struct hfa384x_pdr_mkk_callname { + u8 callname[8]; +} __attribute__ ((packed)) hfa384x_pdr_mkk_callname_t; + +typedef struct hfa384x_pdr_regdomain { + u16 numdomains; + u16 domain[5]; +} __attribute__ ((packed)) hfa384x_pdr_regdomain_t; + +typedef struct hfa384x_pdr_allowed_channel { + u16 ch_bitmap; +} __attribute__ ((packed)) hfa384x_pdr_allowed_channel_t; + +typedef struct hfa384x_pdr_default_channel { + u16 channel; +} __attribute__ ((packed)) hfa384x_pdr_default_channel_t; + +typedef struct hfa384x_pdr_privacy_option { + u16 available; +} __attribute__ ((packed)) hfa384x_pdr_privacy_option_t; + +typedef struct hfa384x_pdr_temptype { + u16 type; +} __attribute__ ((packed)) hfa384x_pdr_temptype_t; + +typedef struct hfa384x_pdr_refdac_setup { + u16 ch_value[14]; +} __attribute__ ((packed)) hfa384x_pdr_refdac_setup_t; + +typedef struct hfa384x_pdr_vgdac_setup { + u16 ch_value[14]; +} __attribute__ ((packed)) hfa384x_pdr_vgdac_setup_t; + +typedef struct hfa384x_pdr_level_comp_setup { + u16 ch_value[14]; +} __attribute__ ((packed)) hfa384x_pdr_level_comp_setup_t; + +typedef struct hfa384x_pdr_trimdac_setup { + u16 trimidac; + u16 trimqdac; +} __attribute__ ((packed)) hfa384x_pdr_trimdac_setup_t; + +typedef struct hfa384x_pdr_ifr_setting { + u16 value[3]; +} __attribute__ ((packed)) hfa384x_pdr_ifr_setting_t; + +typedef struct hfa384x_pdr_rfr_setting { + u16 value[3]; +} __attribute__ ((packed)) hfa384x_pdr_rfr_setting_t; + +typedef struct hfa384x_pdr_hfa3861_baseline { + u16 value[50]; +} __attribute__ ((packed)) hfa384x_pdr_hfa3861_baseline_t; + +typedef struct hfa384x_pdr_hfa3861_shadow { + u32 value[32]; +} __attribute__ ((packed)) hfa384x_pdr_hfa3861_shadow_t; + +typedef struct hfa384x_pdr_hfa3861_ifrf { + u32 value[20]; +} __attribute__ ((packed)) hfa384x_pdr_hfa3861_ifrf_t; + +typedef struct hfa384x_pdr_hfa3861_chcalsp { + u16 value[14]; +} __attribute__ ((packed)) hfa384x_pdr_hfa3861_chcalsp_t; + +typedef struct hfa384x_pdr_hfa3861_chcali { + u16 value[17]; +} __attribute__ ((packed)) hfa384x_pdr_hfa3861_chcali_t; + +typedef struct hfa384x_pdr_hfa3861_nic_config { + u16 config_bitmap; +} __attribute__ ((packed)) hfa384x_pdr_nic_config_t; + +typedef struct hfa384x_pdr_hfo_delay { + u8 hfo_delay; +} __attribute__ ((packed)) hfa384x_hfo_delay_t; + +typedef struct hfa384x_pdr_hfa3861_manf_testsp { + u16 value[30]; +} __attribute__ ((packed)) hfa384x_pdr_hfa3861_manf_testsp_t; + +typedef struct hfa384x_pdr_hfa3861_manf_testi { + u16 value[30]; +} __attribute__ ((packed)) hfa384x_pdr_hfa3861_manf_testi_t; + +typedef struct hfa384x_end_of_pda { + u16 crc; +} __attribute__ ((packed)) hfa384x_pdr_end_of_pda_t; + +typedef struct hfa384x_pdrec { + u16 len; /* in words */ + u16 code; + union pdr { + hfa384x_pdr_pcb_partnum_t pcb_partnum; + hfa384x_pdr_pcb_tracenum_t pcb_tracenum; + hfa384x_pdr_nic_serial_t nic_serial; + hfa384x_pdr_mkk_measurements_t mkk_measurements; + hfa384x_pdr_nic_ramsize_t nic_ramsize; + hfa384x_pdr_mfisuprange_t mfisuprange; + hfa384x_pdr_cfisuprange_t cfisuprange; + hfa384x_pdr_nicid_t nicid; + hfa384x_pdr_refdac_measurements_t refdac_measurements; + hfa384x_pdr_vgdac_measurements_t vgdac_measurements; + hfa384x_pdr_level_compc_measurements_t level_compc_measurements; + hfa384x_pdr_mac_address_t mac_address; + hfa384x_pdr_mkk_callname_t mkk_callname; + hfa384x_pdr_regdomain_t regdomain; + hfa384x_pdr_allowed_channel_t allowed_channel; + hfa384x_pdr_default_channel_t default_channel; + hfa384x_pdr_privacy_option_t privacy_option; + hfa384x_pdr_temptype_t temptype; + hfa384x_pdr_refdac_setup_t refdac_setup; + hfa384x_pdr_vgdac_setup_t vgdac_setup; + hfa384x_pdr_level_comp_setup_t level_comp_setup; + hfa384x_pdr_trimdac_setup_t trimdac_setup; + hfa384x_pdr_ifr_setting_t ifr_setting; + hfa384x_pdr_rfr_setting_t rfr_setting; + hfa384x_pdr_hfa3861_baseline_t hfa3861_baseline; + hfa384x_pdr_hfa3861_shadow_t hfa3861_shadow; + hfa384x_pdr_hfa3861_ifrf_t hfa3861_ifrf; + hfa384x_pdr_hfa3861_chcalsp_t hfa3861_chcalsp; + hfa384x_pdr_hfa3861_chcali_t hfa3861_chcali; + hfa384x_pdr_nic_config_t nic_config; + hfa384x_hfo_delay_t hfo_delay; + hfa384x_pdr_hfa3861_manf_testsp_t hfa3861_manf_testsp; + hfa384x_pdr_hfa3861_manf_testi_t hfa3861_manf_testi; + hfa384x_pdr_end_of_pda_t end_of_pda; + + } data; +} __attribute__ ((packed)) hfa384x_pdrec_t; + #ifdef __KERNEL__ /*-------------------------------------------------------------------- --- MAC state structure, argument to all functions -- @@ -925,7 +1133,7 @@ struct hfa384x; typedef void (*ctlx_cmdcb_t) (struct hfa384x *, const struct hfa384x_usbctlx *); -typedef void (*ctlx_usercb_t) (struct hfa384x *hw, +typedef void (*ctlx_usercb_t) (struct hfa384x * hw, void *ctlxresult, void *usercb_data); typedef struct hfa384x_usbctlx { @@ -1112,25 +1320,25 @@ typedef struct hfa384x { } hfa384x_t; -void hfa384x_create(hfa384x_t *hw, struct usb_device *usb); -void hfa384x_destroy(hfa384x_t *hw); +void hfa384x_create(hfa384x_t * hw, struct usb_device *usb); +void hfa384x_destroy(hfa384x_t * hw); int -hfa384x_corereset(hfa384x_t *hw, int holdtime, int settletime, int genesis); -int hfa384x_drvr_commtallies(hfa384x_t *hw); -int hfa384x_drvr_disable(hfa384x_t *hw, u16 macport); -int hfa384x_drvr_enable(hfa384x_t *hw, u16 macport); -int hfa384x_drvr_flashdl_enable(hfa384x_t *hw); -int hfa384x_drvr_flashdl_disable(hfa384x_t *hw); -int hfa384x_drvr_flashdl_write(hfa384x_t *hw, u32 daddr, void *buf, u32 len); -int hfa384x_drvr_getconfig(hfa384x_t *hw, u16 rid, void *buf, u16 len); -int hfa384x_drvr_ramdl_enable(hfa384x_t *hw, u32 exeaddr); -int hfa384x_drvr_ramdl_disable(hfa384x_t *hw); -int hfa384x_drvr_ramdl_write(hfa384x_t *hw, u32 daddr, void *buf, u32 len); -int hfa384x_drvr_readpda(hfa384x_t *hw, void *buf, unsigned int len); -int hfa384x_drvr_setconfig(hfa384x_t *hw, u16 rid, void *buf, u16 len); +hfa384x_corereset(hfa384x_t * hw, int holdtime, int settletime, int genesis); +int hfa384x_drvr_commtallies(hfa384x_t * hw); +int hfa384x_drvr_disable(hfa384x_t * hw, u16 macport); +int hfa384x_drvr_enable(hfa384x_t * hw, u16 macport); +int hfa384x_drvr_flashdl_enable(hfa384x_t * hw); +int hfa384x_drvr_flashdl_disable(hfa384x_t * hw); +int hfa384x_drvr_flashdl_write(hfa384x_t * hw, u32 daddr, void *buf, u32 len); +int hfa384x_drvr_getconfig(hfa384x_t * hw, u16 rid, void *buf, u16 len); +int hfa384x_drvr_ramdl_enable(hfa384x_t * hw, u32 exeaddr); +int hfa384x_drvr_ramdl_disable(hfa384x_t * hw); +int hfa384x_drvr_ramdl_write(hfa384x_t * hw, u32 daddr, void *buf, u32 len); +int hfa384x_drvr_readpda(hfa384x_t * hw, void *buf, unsigned int len); +int hfa384x_drvr_setconfig(hfa384x_t * hw, u16 rid, void *buf, u16 len); -static inline int hfa384x_drvr_getconfig16(hfa384x_t *hw, u16 rid, void *val) +static inline int hfa384x_drvr_getconfig16(hfa384x_t * hw, u16 rid, void *val) { int result = 0; result = hfa384x_drvr_getconfig(hw, rid, val, sizeof(u16)); @@ -1139,44 +1347,44 @@ static inline int hfa384x_drvr_getconfig16(hfa384x_t *hw, u16 rid, void *val) return result; } -static inline int hfa384x_drvr_setconfig16(hfa384x_t *hw, u16 rid, u16 val) +static inline int hfa384x_drvr_setconfig16(hfa384x_t * hw, u16 rid, u16 val) { u16 value = cpu_to_le16(val); return hfa384x_drvr_setconfig(hw, rid, &value, sizeof(value)); } int -hfa384x_drvr_getconfig_async(hfa384x_t *hw, +hfa384x_drvr_getconfig_async(hfa384x_t * hw, u16 rid, ctlx_usercb_t usercb, void *usercb_data); int -hfa384x_drvr_setconfig_async(hfa384x_t *hw, +hfa384x_drvr_setconfig_async(hfa384x_t * hw, u16 rid, void *buf, u16 len, ctlx_usercb_t usercb, void *usercb_data); static inline int -hfa384x_drvr_setconfig16_async(hfa384x_t *hw, u16 rid, u16 val) +hfa384x_drvr_setconfig16_async(hfa384x_t * hw, u16 rid, u16 val) { u16 value = cpu_to_le16(val); return hfa384x_drvr_setconfig_async(hw, rid, &value, sizeof(value), NULL, NULL); } -int hfa384x_drvr_start(hfa384x_t *hw); -int hfa384x_drvr_stop(hfa384x_t *hw); +int hfa384x_drvr_start(hfa384x_t * hw); +int hfa384x_drvr_stop(hfa384x_t * hw); int -hfa384x_drvr_txframe(hfa384x_t *hw, struct sk_buff *skb, - p80211_hdr_t *p80211_hdr, p80211_metawep_t *p80211_wep); -void hfa384x_tx_timeout(wlandevice_t *wlandev); +hfa384x_drvr_txframe(hfa384x_t * hw, struct sk_buff *skb, + p80211_hdr_t * p80211_hdr, p80211_metawep_t * p80211_wep); +void hfa384x_tx_timeout(wlandevice_t * wlandev); -int hfa384x_cmd_initialize(hfa384x_t *hw); -int hfa384x_cmd_enable(hfa384x_t *hw, u16 macport); -int hfa384x_cmd_disable(hfa384x_t *hw, u16 macport); -int hfa384x_cmd_allocate(hfa384x_t *hw, u16 len); -int hfa384x_cmd_monitor(hfa384x_t *hw, u16 enable); +int hfa384x_cmd_initialize(hfa384x_t * hw); +int hfa384x_cmd_enable(hfa384x_t * hw, u16 macport); +int hfa384x_cmd_disable(hfa384x_t * hw, u16 macport); +int hfa384x_cmd_allocate(hfa384x_t * hw, u16 len); +int hfa384x_cmd_monitor(hfa384x_t * hw, u16 enable); int -hfa384x_cmd_download(hfa384x_t *hw, +hfa384x_cmd_download(hfa384x_t * hw, u16 mode, u16 lowaddr, u16 highaddr, u16 codelen); #endif /* __KERNEL__ */ diff --git a/drivers/staging/wlan-ng/hfa384x_usb.c b/drivers/staging/wlan-ng/hfa384x_usb.c index 888198c9a106..51d9e520d52a 100644 --- a/drivers/staging/wlan-ng/hfa384x_usb.c +++ b/drivers/staging/wlan-ng/hfa384x_usb.c @@ -110,8 +110,6 @@ * -------------------------------------------------------------------- */ -#include - #include #include #include @@ -162,13 +160,13 @@ static void dbprint_urb(struct urb *urb); #endif static void -hfa384x_int_rxmonitor(wlandevice_t *wlandev, hfa384x_usb_rxfrm_t *rxfrm); +hfa384x_int_rxmonitor(wlandevice_t * wlandev, hfa384x_usb_rxfrm_t * rxfrm); static void hfa384x_usb_defer(struct work_struct *data); -static int submit_rx_urb(hfa384x_t *hw, gfp_t flags); +static int submit_rx_urb(hfa384x_t * hw, gfp_t flags); -static int submit_tx_urb(hfa384x_t *hw, struct urb *tx_urb, gfp_t flags); +static int submit_tx_urb(hfa384x_t * hw, struct urb *tx_urb, gfp_t flags); /*---------------------------------------------------*/ /* Callbacks */ @@ -177,22 +175,22 @@ static void hfa384x_ctlxout_callback(struct urb *urb); static void hfa384x_usbin_callback(struct urb *urb); static void -hfa384x_usbin_txcompl(wlandevice_t *wlandev, hfa384x_usbin_t *usbin); +hfa384x_usbin_txcompl(wlandevice_t * wlandev, hfa384x_usbin_t * usbin); -static void hfa384x_usbin_rx(wlandevice_t *wlandev, struct sk_buff *skb); +static void hfa384x_usbin_rx(wlandevice_t * wlandev, struct sk_buff *skb); -static void hfa384x_usbin_info(wlandevice_t *wlandev, hfa384x_usbin_t *usbin); +static void hfa384x_usbin_info(wlandevice_t * wlandev, hfa384x_usbin_t * usbin); static void -hfa384x_usbout_tx(wlandevice_t *wlandev, hfa384x_usbout_t *usbout); +hfa384x_usbout_tx(wlandevice_t * wlandev, hfa384x_usbout_t * usbout); -static void hfa384x_usbin_ctlx(hfa384x_t *hw, hfa384x_usbin_t *usbin, +static void hfa384x_usbin_ctlx(hfa384x_t * hw, hfa384x_usbin_t * usbin, int urb_status); /*---------------------------------------------------*/ /* Functions to support the prism2 usb command queue */ -static void hfa384x_usbctlxq_run(hfa384x_t *hw); +static void hfa384x_usbctlxq_run(hfa384x_t * hw); static void hfa384x_usbctlx_reqtimerfn(unsigned long data); @@ -204,9 +202,9 @@ static void hfa384x_usbctlx_completion_task(unsigned long data); static void hfa384x_usbctlx_reaper_task(unsigned long data); -static int hfa384x_usbctlx_submit(hfa384x_t *hw, hfa384x_usbctlx_t *ctlx); +static int hfa384x_usbctlx_submit(hfa384x_t * hw, hfa384x_usbctlx_t * ctlx); -static void unlocked_usbctlx_complete(hfa384x_t *hw, hfa384x_usbctlx_t *ctlx); +static void unlocked_usbctlx_complete(hfa384x_t * hw, hfa384x_usbctlx_t * ctlx); struct usbctlx_completor { int (*complete) (struct usbctlx_completor *); @@ -214,35 +212,35 @@ struct usbctlx_completor { typedef struct usbctlx_completor usbctlx_completor_t; static int -hfa384x_usbctlx_complete_sync(hfa384x_t *hw, - hfa384x_usbctlx_t *ctlx, - usbctlx_completor_t *completor); +hfa384x_usbctlx_complete_sync(hfa384x_t * hw, + hfa384x_usbctlx_t * ctlx, + usbctlx_completor_t * completor); static int -unlocked_usbctlx_cancel_async(hfa384x_t *hw, hfa384x_usbctlx_t *ctlx); +unlocked_usbctlx_cancel_async(hfa384x_t * hw, hfa384x_usbctlx_t * ctlx); -static void hfa384x_cb_status(hfa384x_t *hw, const hfa384x_usbctlx_t *ctlx); +static void hfa384x_cb_status(hfa384x_t * hw, const hfa384x_usbctlx_t * ctlx); -static void hfa384x_cb_rrid(hfa384x_t *hw, const hfa384x_usbctlx_t *ctlx); +static void hfa384x_cb_rrid(hfa384x_t * hw, const hfa384x_usbctlx_t * ctlx); static int -usbctlx_get_status(const hfa384x_usb_cmdresp_t *cmdresp, - hfa384x_cmdresult_t *result); +usbctlx_get_status(const hfa384x_usb_cmdresp_t * cmdresp, + hfa384x_cmdresult_t * result); static void -usbctlx_get_rridresult(const hfa384x_usb_rridresp_t *rridresp, - hfa384x_rridresult_t *result); +usbctlx_get_rridresult(const hfa384x_usb_rridresp_t * rridresp, + hfa384x_rridresult_t * result); /*---------------------------------------------------*/ /* Low level req/resp CTLX formatters and submitters */ static int -hfa384x_docmd(hfa384x_t *hw, +hfa384x_docmd(hfa384x_t * hw, CMD_MODE mode, - hfa384x_metacmd_t *cmd, + hfa384x_metacmd_t * cmd, ctlx_cmdcb_t cmdcb, ctlx_usercb_t usercb, void *usercb_data); static int -hfa384x_dorrid(hfa384x_t *hw, +hfa384x_dorrid(hfa384x_t * hw, CMD_MODE mode, u16 rid, void *riddata, @@ -250,7 +248,7 @@ hfa384x_dorrid(hfa384x_t *hw, ctlx_cmdcb_t cmdcb, ctlx_usercb_t usercb, void *usercb_data); static int -hfa384x_dowrid(hfa384x_t *hw, +hfa384x_dowrid(hfa384x_t * hw, CMD_MODE mode, u16 rid, void *riddata, @@ -258,7 +256,7 @@ hfa384x_dowrid(hfa384x_t *hw, ctlx_cmdcb_t cmdcb, ctlx_usercb_t usercb, void *usercb_data); static int -hfa384x_dormem(hfa384x_t *hw, +hfa384x_dormem(hfa384x_t * hw, CMD_MODE mode, u16 page, u16 offset, @@ -267,7 +265,7 @@ hfa384x_dormem(hfa384x_t *hw, ctlx_cmdcb_t cmdcb, ctlx_usercb_t usercb, void *usercb_data); static int -hfa384x_dowmem(hfa384x_t *hw, +hfa384x_dowmem(hfa384x_t * hw, CMD_MODE mode, u16 page, u16 offset, @@ -292,7 +290,7 @@ static inline const char *ctlxstr(CTLX_STATE s) return ctlx_str[s]; }; -static inline hfa384x_usbctlx_t *get_active_ctlx(hfa384x_t *hw) +static inline hfa384x_usbctlx_t *get_active_ctlx(hfa384x_t * hw) { return list_entry(hw->ctlxq.active.next, hfa384x_usbctlx_t, list); } @@ -304,21 +302,19 @@ void dbprint_urb(struct urb *urb) pr_debug("urb->status=0x%08x\n", urb->status); pr_debug("urb->transfer_flags=0x%08x\n", urb->transfer_flags); pr_debug("urb->transfer_buffer=0x%08x\n", - (unsigned int)urb->transfer_buffer); + (unsigned int)urb->transfer_buffer); pr_debug("urb->transfer_buffer_length=0x%08x\n", - urb->transfer_buffer_length); + urb->transfer_buffer_length); pr_debug("urb->actual_length=0x%08x\n", urb->actual_length); pr_debug("urb->bandwidth=0x%08x\n", urb->bandwidth); pr_debug("urb->setup_packet(ctl)=0x%08x\n", - (unsigned int)urb->setup_packet); - pr_debug("urb->start_frame(iso/irq)=0x%08x\n", - urb->start_frame); + (unsigned int)urb->setup_packet); + pr_debug("urb->start_frame(iso/irq)=0x%08x\n", urb->start_frame); pr_debug("urb->interval(irq)=0x%08x\n", urb->interval); pr_debug("urb->error_count(iso)=0x%08x\n", urb->error_count); pr_debug("urb->timeout=0x%08x\n", urb->timeout); pr_debug("urb->context=0x%08x\n", (unsigned int)urb->context); - pr_debug("urb->complete=0x%08x\n", - (unsigned int)urb->complete); + pr_debug("urb->complete=0x%08x\n", (unsigned int)urb->complete); } #endif @@ -338,7 +334,7 @@ void dbprint_urb(struct urb *urb) * Call context: * Any ----------------------------------------------------------------*/ -static int submit_rx_urb(hfa384x_t *hw, gfp_t memflags) +static int submit_rx_urb(hfa384x_t * hw, gfp_t memflags) { struct sk_buff *skb; int result; @@ -399,7 +395,7 @@ done: * Call context: * Any ----------------------------------------------------------------*/ -static int submit_tx_urb(hfa384x_t *hw, struct urb *tx_urb, gfp_t memflags) +static int submit_tx_urb(hfa384x_t * hw, struct urb *tx_urb, gfp_t memflags) { struct net_device *netdev = hw->wlandev->netdev; int result; @@ -536,7 +532,7 @@ static void hfa384x_usb_defer(struct work_struct *data) * Call context: * process ----------------------------------------------------------------*/ -void hfa384x_create(hfa384x_t *hw, struct usb_device *usb) +void hfa384x_create(hfa384x_t * hw, struct usb_device *usb) { memset(hw, 0, sizeof(hfa384x_t)); hw->usb = usb; @@ -612,7 +608,7 @@ void hfa384x_create(hfa384x_t *hw, struct usb_device *usb) * Call context: * process ----------------------------------------------------------------*/ -void hfa384x_destroy(hfa384x_t *hw) +void hfa384x_destroy(hfa384x_t * hw) { struct sk_buff *skb; @@ -634,7 +630,7 @@ static hfa384x_usbctlx_t *usbctlx_alloc(void) { hfa384x_usbctlx_t *ctlx; - ctlx = kmalloc(sizeof(*ctlx), in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); + ctlx = kmalloc(sizeof(*ctlx), in_interrupt()? GFP_ATOMIC : GFP_KERNEL); if (ctlx != NULL) { memset(ctlx, 0, sizeof(*ctlx)); init_completion(&ctlx->done); @@ -644,8 +640,8 @@ static hfa384x_usbctlx_t *usbctlx_alloc(void) } static int -usbctlx_get_status(const hfa384x_usb_cmdresp_t *cmdresp, - hfa384x_cmdresult_t *result) +usbctlx_get_status(const hfa384x_usb_cmdresp_t * cmdresp, + hfa384x_cmdresult_t * result) { result->status = le16_to_cpu(cmdresp->status); result->resp0 = le16_to_cpu(cmdresp->resp0); @@ -653,15 +649,15 @@ usbctlx_get_status(const hfa384x_usb_cmdresp_t *cmdresp, result->resp2 = le16_to_cpu(cmdresp->resp2); pr_debug("cmdresult:status=0x%04x " - "resp0=0x%04x resp1=0x%04x resp2=0x%04x\n", - result->status, result->resp0, result->resp1, result->resp2); + "resp0=0x%04x resp1=0x%04x resp2=0x%04x\n", + result->status, result->resp0, result->resp1, result->resp2); return result->status & HFA384x_STATUS_RESULT; } static void -usbctlx_get_rridresult(const hfa384x_usb_rridresp_t *rridresp, - hfa384x_rridresult_t *result) +usbctlx_get_rridresult(const hfa384x_usb_rridresp_t * rridresp, + hfa384x_rridresult_t * result) { result->rid = le16_to_cpu(rridresp->rid); result->riddata = rridresp->data; @@ -682,7 +678,7 @@ struct usbctlx_cmd_completor { }; typedef struct usbctlx_cmd_completor usbctlx_cmd_completor_t; -static int usbctlx_cmd_completor_fn(usbctlx_completor_t *head) +static int usbctlx_cmd_completor_fn(usbctlx_completor_t * head) { usbctlx_cmd_completor_t *complete = (usbctlx_cmd_completor_t *) head; return usbctlx_get_status(complete->cmdresp, complete->result); @@ -716,7 +712,7 @@ struct usbctlx_rrid_completor { }; typedef struct usbctlx_rrid_completor usbctlx_rrid_completor_t; -static int usbctlx_rrid_completor_fn(usbctlx_completor_t *head) +static int usbctlx_rrid_completor_fn(usbctlx_completor_t * head) { usbctlx_rrid_completor_t *complete = (usbctlx_rrid_completor_t *) head; hfa384x_rridresult_t rridresult; @@ -737,7 +733,7 @@ static int usbctlx_rrid_completor_fn(usbctlx_completor_t *head) } static inline usbctlx_completor_t *init_rrid_completor(usbctlx_rrid_completor_t - *completor, + * completor, const hfa384x_usb_rridresp_t * rridresp, void *riddata, @@ -777,7 +773,7 @@ struct usbctlx_rmem_completor { }; typedef struct usbctlx_rmem_completor usbctlx_rmem_completor_t; -static int usbctlx_rmem_completor_fn(usbctlx_completor_t *head) +static int usbctlx_rmem_completor_fn(usbctlx_completor_t * head) { usbctlx_rmem_completor_t *complete = (usbctlx_rmem_completor_t *) head; @@ -787,9 +783,9 @@ static int usbctlx_rmem_completor_fn(usbctlx_completor_t *head) } static inline usbctlx_completor_t *init_rmem_completor(usbctlx_rmem_completor_t - *completor, + * completor, hfa384x_usb_rmemresp_t - *rmemresp, void *data, + * rmemresp, void *data, unsigned int len) { completor->head.complete = usbctlx_rmem_completor_fn; @@ -820,7 +816,7 @@ static inline usbctlx_completor_t *init_rmem_completor(usbctlx_rmem_completor_t * Call context: * interrupt ----------------------------------------------------------------*/ -static void hfa384x_cb_status(hfa384x_t *hw, const hfa384x_usbctlx_t *ctlx) +static void hfa384x_cb_status(hfa384x_t * hw, const hfa384x_usbctlx_t * ctlx) { if (ctlx->usercb != NULL) { hfa384x_cmdresult_t cmdresult; @@ -857,15 +853,14 @@ static void hfa384x_cb_status(hfa384x_t *hw, const hfa384x_usbctlx_t *ctlx) * Call context: * interrupt ----------------------------------------------------------------*/ -static void hfa384x_cb_rrid(hfa384x_t *hw, const hfa384x_usbctlx_t *ctlx) +static void hfa384x_cb_rrid(hfa384x_t * hw, const hfa384x_usbctlx_t * ctlx) { if (ctlx->usercb != NULL) { hfa384x_rridresult_t rridresult; if (ctlx->state != CTLX_COMPLETE) { memset(&rridresult, 0, sizeof(rridresult)); - rridresult.rid = - le16_to_cpu(ctlx->outbuf.rridreq.rid); + rridresult.rid = le16_to_cpu(ctlx->outbuf.rridreq.rid); } else { usbctlx_get_rridresult(&ctlx->inbuf.rridresp, &rridresult); @@ -875,21 +870,21 @@ static void hfa384x_cb_rrid(hfa384x_t *hw, const hfa384x_usbctlx_t *ctlx) } } -static inline int hfa384x_docmd_wait(hfa384x_t *hw, hfa384x_metacmd_t *cmd) +static inline int hfa384x_docmd_wait(hfa384x_t * hw, hfa384x_metacmd_t * cmd) { return hfa384x_docmd(hw, DOWAIT, cmd, NULL, NULL, NULL); } static inline int -hfa384x_docmd_async(hfa384x_t *hw, - hfa384x_metacmd_t *cmd, +hfa384x_docmd_async(hfa384x_t * hw, + hfa384x_metacmd_t * cmd, ctlx_cmdcb_t cmdcb, ctlx_usercb_t usercb, void *usercb_data) { return hfa384x_docmd(hw, DOASYNC, cmd, cmdcb, usercb, usercb_data); } static inline int -hfa384x_dorrid_wait(hfa384x_t *hw, u16 rid, void *riddata, +hfa384x_dorrid_wait(hfa384x_t * hw, u16 rid, void *riddata, unsigned int riddatalen) { return hfa384x_dorrid(hw, DOWAIT, @@ -897,7 +892,7 @@ hfa384x_dorrid_wait(hfa384x_t *hw, u16 rid, void *riddata, } static inline int -hfa384x_dorrid_async(hfa384x_t *hw, +hfa384x_dorrid_async(hfa384x_t * hw, u16 rid, void *riddata, unsigned int riddatalen, ctlx_cmdcb_t cmdcb, ctlx_usercb_t usercb, void *usercb_data) @@ -908,7 +903,7 @@ hfa384x_dorrid_async(hfa384x_t *hw, } static inline int -hfa384x_dowrid_wait(hfa384x_t *hw, u16 rid, void *riddata, +hfa384x_dowrid_wait(hfa384x_t * hw, u16 rid, void *riddata, unsigned int riddatalen) { return hfa384x_dowrid(hw, DOWAIT, @@ -916,7 +911,7 @@ hfa384x_dowrid_wait(hfa384x_t *hw, u16 rid, void *riddata, } static inline int -hfa384x_dowrid_async(hfa384x_t *hw, +hfa384x_dowrid_async(hfa384x_t * hw, u16 rid, void *riddata, unsigned int riddatalen, ctlx_cmdcb_t cmdcb, ctlx_usercb_t usercb, void *usercb_data) @@ -927,7 +922,7 @@ hfa384x_dowrid_async(hfa384x_t *hw, } static inline int -hfa384x_dormem_wait(hfa384x_t *hw, +hfa384x_dormem_wait(hfa384x_t * hw, u16 page, u16 offset, void *data, unsigned int len) { return hfa384x_dormem(hw, DOWAIT, @@ -935,7 +930,7 @@ hfa384x_dormem_wait(hfa384x_t *hw, } static inline int -hfa384x_dormem_async(hfa384x_t *hw, +hfa384x_dormem_async(hfa384x_t * hw, u16 page, u16 offset, void *data, unsigned int len, ctlx_cmdcb_t cmdcb, ctlx_usercb_t usercb, void *usercb_data) @@ -946,7 +941,7 @@ hfa384x_dormem_async(hfa384x_t *hw, } static inline int -hfa384x_dowmem_wait(hfa384x_t *hw, +hfa384x_dowmem_wait(hfa384x_t * hw, u16 page, u16 offset, void *data, unsigned int len) { return hfa384x_dowmem(hw, DOWAIT, @@ -954,7 +949,7 @@ hfa384x_dowmem_wait(hfa384x_t *hw, } static inline int -hfa384x_dowmem_async(hfa384x_t *hw, +hfa384x_dowmem_async(hfa384x_t * hw, u16 page, u16 offset, void *data, @@ -986,7 +981,7 @@ hfa384x_dowmem_async(hfa384x_t *hw, * Call context: * process ----------------------------------------------------------------*/ -int hfa384x_cmd_initialize(hfa384x_t *hw) +int hfa384x_cmd_initialize(hfa384x_t * hw) { int result = 0; int i; @@ -1000,10 +995,10 @@ int hfa384x_cmd_initialize(hfa384x_t *hw) result = hfa384x_docmd_wait(hw, &cmd); pr_debug("cmdresp.init: " - "status=0x%04x, resp0=0x%04x, " - "resp1=0x%04x, resp2=0x%04x\n", - cmd.result.status, - cmd.result.resp0, cmd.result.resp1, cmd.result.resp2); + "status=0x%04x, resp0=0x%04x, " + "resp1=0x%04x, resp2=0x%04x\n", + cmd.result.status, + cmd.result.resp0, cmd.result.resp1, cmd.result.resp2); if (result == 0) { for (i = 0; i < HFA384x_NUMPORTS_MAX; i++) hw->port_enabled[i] = 0; @@ -1034,7 +1029,7 @@ int hfa384x_cmd_initialize(hfa384x_t *hw) * Call context: * process ----------------------------------------------------------------*/ -int hfa384x_cmd_disable(hfa384x_t *hw, u16 macport) +int hfa384x_cmd_disable(hfa384x_t * hw, u16 macport) { int result = 0; hfa384x_metacmd_t cmd; @@ -1070,7 +1065,7 @@ int hfa384x_cmd_disable(hfa384x_t *hw, u16 macport) * Call context: * process ----------------------------------------------------------------*/ -int hfa384x_cmd_enable(hfa384x_t *hw, u16 macport) +int hfa384x_cmd_enable(hfa384x_t * hw, u16 macport) { int result = 0; hfa384x_metacmd_t cmd; @@ -1115,7 +1110,7 @@ int hfa384x_cmd_enable(hfa384x_t *hw, u16 macport) * Call context: * process ----------------------------------------------------------------*/ -int hfa384x_cmd_monitor(hfa384x_t *hw, u16 enable) +int hfa384x_cmd_monitor(hfa384x_t * hw, u16 enable) { int result = 0; hfa384x_metacmd_t cmd; @@ -1169,15 +1164,14 @@ int hfa384x_cmd_monitor(hfa384x_t *hw, u16 enable) * Call context: * process ----------------------------------------------------------------*/ -int hfa384x_cmd_download(hfa384x_t *hw, u16 mode, u16 lowaddr, +int hfa384x_cmd_download(hfa384x_t * hw, u16 mode, u16 lowaddr, u16 highaddr, u16 codelen) { int result = 0; hfa384x_metacmd_t cmd; - printk(KERN_DEBUG - "mode=%d, lowaddr=0x%04x, highaddr=0x%04x, codelen=%d\n", - mode, lowaddr, highaddr, codelen); + pr_debug("mode=%d, lowaddr=0x%04x, highaddr=0x%04x, codelen=%d\n", + mode, lowaddr, highaddr, codelen); cmd.cmd = (HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_DOWNLD) | HFA384x_CMD_PROGMODE_SET(mode)); @@ -1214,7 +1208,7 @@ int hfa384x_cmd_download(hfa384x_t *hw, u16 mode, u16 lowaddr, * Call context: * process ----------------------------------------------------------------*/ -int hfa384x_corereset(hfa384x_t *hw, int holdtime, int settletime, int genesis) +int hfa384x_corereset(hfa384x_t * hw, int holdtime, int settletime, int genesis) { int result = 0; @@ -1251,9 +1245,9 @@ int hfa384x_corereset(hfa384x_t *hw, int holdtime, int settletime, int genesis) * Call context: * process ----------------------------------------------------------------*/ -static int hfa384x_usbctlx_complete_sync(hfa384x_t *hw, - hfa384x_usbctlx_t *ctlx, - usbctlx_completor_t *completor) +static int hfa384x_usbctlx_complete_sync(hfa384x_t * hw, + hfa384x_usbctlx_t * ctlx, + usbctlx_completor_t * completor) { unsigned long flags; int result; @@ -1367,9 +1361,9 @@ cleanup: * process ----------------------------------------------------------------*/ static int -hfa384x_docmd(hfa384x_t *hw, +hfa384x_docmd(hfa384x_t * hw, CMD_MODE mode, - hfa384x_metacmd_t *cmd, + hfa384x_metacmd_t * cmd, ctlx_cmdcb_t cmdcb, ctlx_usercb_t usercb, void *usercb_data) { int result; @@ -1391,8 +1385,8 @@ hfa384x_docmd(hfa384x_t *hw, ctlx->outbufsize = sizeof(ctlx->outbuf.cmdreq); pr_debug("cmdreq: cmd=0x%04x " - "parm0=0x%04x parm1=0x%04x parm2=0x%04x\n", - cmd->cmd, cmd->parm0, cmd->parm1, cmd->parm2); + "parm0=0x%04x parm1=0x%04x parm2=0x%04x\n", + cmd->cmd, cmd->parm0, cmd->parm1, cmd->parm2); ctlx->reapable = mode; ctlx->cmdcb = cmdcb; @@ -1456,7 +1450,7 @@ done: * process (DOWAIT or DOASYNC) ----------------------------------------------------------------*/ static int -hfa384x_dorrid(hfa384x_t *hw, +hfa384x_dorrid(hfa384x_t * hw, CMD_MODE mode, u16 rid, void *riddata, @@ -1537,7 +1531,7 @@ done: * process (DOWAIT or DOASYNC) ----------------------------------------------------------------*/ static int -hfa384x_dowrid(hfa384x_t *hw, +hfa384x_dowrid(hfa384x_t * hw, CMD_MODE mode, u16 rid, void *riddata, @@ -1556,9 +1550,8 @@ hfa384x_dowrid(hfa384x_t *hw, /* Initialize the command */ ctlx->outbuf.wridreq.type = cpu_to_le16(HFA384x_USB_WRIDREQ); ctlx->outbuf.wridreq.frmlen = cpu_to_le16((sizeof - (ctlx->outbuf.wridreq. - rid) + riddatalen + - 1) / 2); + (ctlx->outbuf.wridreq.rid) + + riddatalen + 1) / 2); ctlx->outbuf.wridreq.rid = cpu_to_le16(rid); memcpy(ctlx->outbuf.wridreq.data, riddata, riddatalen); @@ -1625,7 +1618,7 @@ done: * process (DOWAIT or DOASYNC) ----------------------------------------------------------------*/ static int -hfa384x_dormem(hfa384x_t *hw, +hfa384x_dormem(hfa384x_t * hw, CMD_MODE mode, u16 page, u16 offset, @@ -1646,20 +1639,18 @@ hfa384x_dormem(hfa384x_t *hw, ctlx->outbuf.rmemreq.type = cpu_to_le16(HFA384x_USB_RMEMREQ); ctlx->outbuf.rmemreq.frmlen = cpu_to_le16(sizeof(ctlx->outbuf.rmemreq.offset) + - sizeof(ctlx->outbuf.rmemreq.page) + len); + sizeof(ctlx->outbuf.rmemreq.page) + len); ctlx->outbuf.rmemreq.offset = cpu_to_le16(offset); ctlx->outbuf.rmemreq.page = cpu_to_le16(page); ctlx->outbufsize = sizeof(ctlx->outbuf.rmemreq); - printk(KERN_DEBUG - "type=0x%04x frmlen=%d offset=0x%04x page=0x%04x\n", - ctlx->outbuf.rmemreq.type, - ctlx->outbuf.rmemreq.frmlen, - ctlx->outbuf.rmemreq.offset, ctlx->outbuf.rmemreq.page); + pr_debug("type=0x%04x frmlen=%d offset=0x%04x page=0x%04x\n", + ctlx->outbuf.rmemreq.type, + ctlx->outbuf.rmemreq.frmlen, + ctlx->outbuf.rmemreq.offset, ctlx->outbuf.rmemreq.page); - pr_debug("pktsize=%zd\n", - ROUNDUP64(sizeof(ctlx->outbuf.rmemreq))); + pr_debug("pktsize=%zd\n", ROUNDUP64(sizeof(ctlx->outbuf.rmemreq))); ctlx->reapable = mode; ctlx->cmdcb = cmdcb; @@ -1718,7 +1709,7 @@ done: * process (DOWAIT or DOASYNC) ----------------------------------------------------------------*/ static int -hfa384x_dowmem(hfa384x_t *hw, +hfa384x_dowmem(hfa384x_t * hw, CMD_MODE mode, u16 page, u16 offset, @@ -1729,8 +1720,7 @@ hfa384x_dowmem(hfa384x_t *hw, int result; hfa384x_usbctlx_t *ctlx; - pr_debug("page=0x%04x offset=0x%04x len=%d\n", - page, offset, len); + pr_debug("page=0x%04x offset=0x%04x len=%d\n", page, offset, len); ctlx = usbctlx_alloc(); if (ctlx == NULL) { @@ -1742,7 +1732,7 @@ hfa384x_dowmem(hfa384x_t *hw, ctlx->outbuf.wmemreq.type = cpu_to_le16(HFA384x_USB_WMEMREQ); ctlx->outbuf.wmemreq.frmlen = cpu_to_le16(sizeof(ctlx->outbuf.wmemreq.offset) + - sizeof(ctlx->outbuf.wmemreq.page) + len); + sizeof(ctlx->outbuf.wmemreq.page) + len); ctlx->outbuf.wmemreq.offset = cpu_to_le16(offset); ctlx->outbuf.wmemreq.page = cpu_to_le16(page); memcpy(ctlx->outbuf.wmemreq.data, data, len); @@ -1793,7 +1783,7 @@ done: * Call context: * process ----------------------------------------------------------------*/ -int hfa384x_drvr_commtallies(hfa384x_t *hw) +int hfa384x_drvr_commtallies(hfa384x_t * hw) { hfa384x_metacmd_t cmd; @@ -1829,7 +1819,7 @@ int hfa384x_drvr_commtallies(hfa384x_t *hw) * Call context: * process ----------------------------------------------------------------*/ -int hfa384x_drvr_disable(hfa384x_t *hw, u16 macport) +int hfa384x_drvr_disable(hfa384x_t * hw, u16 macport) { int result = 0; @@ -1867,7 +1857,7 @@ int hfa384x_drvr_disable(hfa384x_t *hw, u16 macport) * Call context: * process ----------------------------------------------------------------*/ -int hfa384x_drvr_enable(hfa384x_t *hw, u16 macport) +int hfa384x_drvr_enable(hfa384x_t * hw, u16 macport) { int result = 0; @@ -1904,7 +1894,7 @@ int hfa384x_drvr_enable(hfa384x_t *hw, u16 macport) * Call context: * process ----------------------------------------------------------------*/ -int hfa384x_drvr_flashdl_enable(hfa384x_t *hw) +int hfa384x_drvr_flashdl_enable(hfa384x_t * hw) { int result = 0; int i; @@ -1962,7 +1952,7 @@ int hfa384x_drvr_flashdl_enable(hfa384x_t *hw) * Call context: * process ----------------------------------------------------------------*/ -int hfa384x_drvr_flashdl_disable(hfa384x_t *hw) +int hfa384x_drvr_flashdl_disable(hfa384x_t * hw) { /* Check that we're already in the download state */ if (hw->dlstate != HFA384x_DLSTATE_FLASHENABLED) @@ -2007,7 +1997,7 @@ int hfa384x_drvr_flashdl_disable(hfa384x_t *hw) * Call context: * process ----------------------------------------------------------------*/ -int hfa384x_drvr_flashdl_write(hfa384x_t *hw, u32 daddr, void *buf, u32 len) +int hfa384x_drvr_flashdl_write(hfa384x_t * hw, u32 daddr, void *buf, u32 len) { int result = 0; u32 dlbufaddr; @@ -2036,9 +2026,8 @@ int hfa384x_drvr_flashdl_write(hfa384x_t *hw, u32 daddr, void *buf, u32 len) /* NOTE: dlbuffer RID stores the address in AUX format */ dlbufaddr = HFA384x_ADDR_AUX_MKFLAT(hw->bufinfo.page, hw->bufinfo.offset); - printk(KERN_DEBUG - "dlbuf.page=0x%04x dlbuf.offset=0x%04x dlbufaddr=0x%08x\n", - hw->bufinfo.page, hw->bufinfo.offset, dlbufaddr); + pr_debug("dlbuf.page=0x%04x dlbuf.offset=0x%04x dlbufaddr=0x%08x\n", + hw->bufinfo.page, hw->bufinfo.offset, dlbufaddr); #if 0 printk(KERN_WARNING "dlbuf@0x%06lx len=%d to=%d\n", dlbufaddr, @@ -2154,7 +2143,7 @@ exit_proc: * Call context: * process ----------------------------------------------------------------*/ -int hfa384x_drvr_getconfig(hfa384x_t *hw, u16 rid, void *buf, u16 len) +int hfa384x_drvr_getconfig(hfa384x_t * hw, u16 rid, void *buf, u16 len) { int result; @@ -2191,7 +2180,7 @@ int hfa384x_drvr_getconfig(hfa384x_t *hw, u16 rid, void *buf, u16 len) * Any ----------------------------------------------------------------*/ int -hfa384x_drvr_getconfig_async(hfa384x_t *hw, +hfa384x_drvr_getconfig_async(hfa384x_t * hw, u16 rid, ctlx_usercb_t usercb, void *usercb_data) { return hfa384x_dorrid_async(hw, rid, NULL, 0, @@ -2222,7 +2211,7 @@ hfa384x_drvr_getconfig_async(hfa384x_t *hw, * process ----------------------------------------------------------------*/ int -hfa384x_drvr_setconfig_async(hfa384x_t *hw, +hfa384x_drvr_setconfig_async(hfa384x_t * hw, u16 rid, void *buf, u16 len, ctlx_usercb_t usercb, void *usercb_data) @@ -2249,7 +2238,7 @@ hfa384x_drvr_setconfig_async(hfa384x_t *hw, * Call context: * process ----------------------------------------------------------------*/ -int hfa384x_drvr_ramdl_disable(hfa384x_t *hw) +int hfa384x_drvr_ramdl_disable(hfa384x_t * hw) { /* Check that we're already in the download state */ if (hw->dlstate != HFA384x_DLSTATE_RAMENABLED) @@ -2289,7 +2278,7 @@ int hfa384x_drvr_ramdl_disable(hfa384x_t *hw) * Call context: * process ----------------------------------------------------------------*/ -int hfa384x_drvr_ramdl_enable(hfa384x_t *hw, u32 exeaddr) +int hfa384x_drvr_ramdl_enable(hfa384x_t * hw, u32 exeaddr) { int result = 0; u16 lowaddr; @@ -2324,9 +2313,8 @@ int hfa384x_drvr_ramdl_enable(hfa384x_t *hw, u32 exeaddr) /* Set the download state */ hw->dlstate = HFA384x_DLSTATE_RAMENABLED; } else { - printk(KERN_DEBUG - "cmd_download(0x%04x, 0x%04x) failed, result=%d.\n", - lowaddr, hiaddr, result); + pr_debug("cmd_download(0x%04x, 0x%04x) failed, result=%d.\n", + lowaddr, hiaddr, result); } return result; @@ -2358,7 +2346,7 @@ int hfa384x_drvr_ramdl_enable(hfa384x_t *hw, u32 exeaddr) * Call context: * process ----------------------------------------------------------------*/ -int hfa384x_drvr_ramdl_write(hfa384x_t *hw, u32 daddr, void *buf, u32 len) +int hfa384x_drvr_ramdl_write(hfa384x_t * hw, u32 daddr, void *buf, u32 len) { int result = 0; int nwrites; @@ -2424,7 +2412,7 @@ int hfa384x_drvr_ramdl_write(hfa384x_t *hw, u32 daddr, void *buf, u32 len) * 0 success * >0 f/w reported error - f/w status code * <0 driver reported error -* -ETIMEOUT timout waiting for the cmd regs to become +* -ETIMEDOUT timout waiting for the cmd regs to become * available, or waiting for the control reg * to indicate the Aux port is enabled. * -ENODATA the buffer does NOT contain a valid PDA. @@ -2437,7 +2425,7 @@ int hfa384x_drvr_ramdl_write(hfa384x_t *hw, u32 daddr, void *buf, u32 len) * Call context: * process or non-card interrupt. ----------------------------------------------------------------*/ -int hfa384x_drvr_readpda(hfa384x_t *hw, void *buf, unsigned int len) +int hfa384x_drvr_readpda(hfa384x_t * hw, void *buf, unsigned int len) { int result = 0; u16 *pda = buf; @@ -2543,7 +2531,7 @@ int hfa384x_drvr_readpda(hfa384x_t *hw, void *buf, unsigned int len) * Call context: * process ----------------------------------------------------------------*/ -int hfa384x_drvr_setconfig(hfa384x_t *hw, u16 rid, void *buf, u16 len) +int hfa384x_drvr_setconfig(hfa384x_t * hw, u16 rid, void *buf, u16 len) { return hfa384x_dowrid_wait(hw, rid, buf, len); } @@ -2568,7 +2556,7 @@ int hfa384x_drvr_setconfig(hfa384x_t *hw, u16 rid, void *buf, u16 len) * process ----------------------------------------------------------------*/ -int hfa384x_drvr_start(hfa384x_t *hw) +int hfa384x_drvr_start(hfa384x_t * hw) { int result, result1, result2; u16 status; @@ -2630,11 +2618,10 @@ int hfa384x_drvr_start(hfa384x_t *hw) usb_kill_urb(&hw->rx_urb); goto done; } else { - printk(KERN_DEBUG - "First cmd_initialize() failed (result %d),\n", - result1); - printk(KERN_DEBUG - "but second attempt succeeded. All should be ok\n"); + pr_debug("First cmd_initialize() failed (result %d),\n", + result1); + pr_debug + ("but second attempt succeeded. All should be ok\n"); } } else if (result2 != 0) { printk(KERN_WARNING @@ -2670,7 +2657,7 @@ done: * Call context: * process ----------------------------------------------------------------*/ -int hfa384x_drvr_stop(hfa384x_t *hw) +int hfa384x_drvr_stop(hfa384x_t * hw) { int result = 0; int i; @@ -2721,9 +2708,9 @@ int hfa384x_drvr_stop(hfa384x_t *hw) * Call context: * interrupt ----------------------------------------------------------------*/ -int hfa384x_drvr_txframe(hfa384x_t *hw, struct sk_buff *skb, - p80211_hdr_t *p80211_hdr, - p80211_metawep_t *p80211_wep) +int hfa384x_drvr_txframe(hfa384x_t * hw, struct sk_buff *skb, + p80211_hdr_t * p80211_hdr, + p80211_metawep_t * p80211_wep) { int usbpktlen = sizeof(hfa384x_tx_frame_t); int result; @@ -2814,7 +2801,7 @@ exit: return result; } -void hfa384x_tx_timeout(wlandevice_t *wlandev) +void hfa384x_tx_timeout(wlandevice_t * wlandev) { hfa384x_t *hw = wlandev->priv; unsigned long flags; @@ -2963,8 +2950,8 @@ static void hfa384x_usbctlx_completion_task(unsigned long data) * Call context: * Either process or interrupt, but presumably interrupt ----------------------------------------------------------------*/ -static int unlocked_usbctlx_cancel_async(hfa384x_t *hw, - hfa384x_usbctlx_t *ctlx) +static int unlocked_usbctlx_cancel_async(hfa384x_t * hw, + hfa384x_usbctlx_t * ctlx) { int ret; @@ -3013,7 +3000,7 @@ static int unlocked_usbctlx_cancel_async(hfa384x_t *hw, * Call context: * Either, assume interrupt ----------------------------------------------------------------*/ -static void unlocked_usbctlx_complete(hfa384x_t *hw, hfa384x_usbctlx_t *ctlx) +static void unlocked_usbctlx_complete(hfa384x_t * hw, hfa384x_usbctlx_t * ctlx) { /* Timers have been stopped, and ctlx should be in * a terminal state. Retire it from the "active" @@ -3030,8 +3017,7 @@ static void unlocked_usbctlx_complete(hfa384x_t *hw, hfa384x_usbctlx_t *ctlx) default: printk(KERN_ERR "CTLX[%d] not in a terminating state(%s)\n", - le16_to_cpu(ctlx->outbuf.type), - ctlxstr(ctlx->state)); + le16_to_cpu(ctlx->outbuf.type), ctlxstr(ctlx->state)); break; } /* switch */ } @@ -3052,7 +3038,7 @@ static void unlocked_usbctlx_complete(hfa384x_t *hw, hfa384x_usbctlx_t *ctlx) * Call context: * any ----------------------------------------------------------------*/ -static void hfa384x_usbctlxq_run(hfa384x_t *hw) +static void hfa384x_usbctlxq_run(hfa384x_t * hw) { unsigned long flags; @@ -3226,14 +3212,13 @@ static void hfa384x_usbin_callback(struct urb *urb) case -ENOENT: case -ECONNRESET: - pr_debug("status=%d, urb explicitly unlinked.\n", - urb->status); + pr_debug("status=%d, urb explicitly unlinked.\n", urb->status); action = ABORT; break; default: pr_debug("urb status=%d, transfer flags=0x%x\n", - urb->status, urb->transfer_flags); + urb->status, urb->transfer_flags); ++(wlandev->linux_stats.rx_errors); action = RESUBMIT; break; @@ -3293,18 +3278,17 @@ static void hfa384x_usbin_callback(struct urb *urb) case HFA384x_USB_BUFAVAIL: pr_debug("Received BUFAVAIL packet, frmlen=%d\n", - usbin->bufavail.frmlen); + usbin->bufavail.frmlen); break; case HFA384x_USB_ERROR: pr_debug("Received USB_ERROR packet, errortype=%d\n", - usbin->usberror.errortype); + usbin->usberror.errortype); break; default: - printk(KERN_DEBUG - "Unrecognized USBIN packet, type=%x, status=%d\n", - usbin->type, urb_status); + pr_debug("Unrecognized USBIN packet, type=%x, status=%d\n", + usbin->type, urb_status); break; } /* switch */ @@ -3334,7 +3318,7 @@ exit: * Call context: * interrupt ----------------------------------------------------------------*/ -static void hfa384x_usbin_ctlx(hfa384x_t *hw, hfa384x_usbin_t *usbin, +static void hfa384x_usbin_ctlx(hfa384x_t * hw, hfa384x_usbin_t * usbin, int urb_status) { hfa384x_usbctlx_t *ctlx; @@ -3400,8 +3384,8 @@ retry: * our request has been acknowledged. Odd, * but our OUT URB is still alive... */ - printk(KERN_DEBUG - "Causality violation: please reboot Universe, or email linux-wlan-devel@lists.linux-wlan.com\n"); + pr_debug + ("Causality violation: please reboot Universe, or email linux-wlan-devel@lists.linux-wlan.com\n"); ctlx->state = CTLX_RESP_COMPLETE; break; @@ -3455,8 +3439,8 @@ unlock: * Call context: * interrupt ----------------------------------------------------------------*/ -static void hfa384x_usbin_txcompl(wlandevice_t *wlandev, - hfa384x_usbin_t *usbin) +static void hfa384x_usbin_txcompl(wlandevice_t * wlandev, + hfa384x_usbin_t * usbin) { u16 status; @@ -3486,7 +3470,7 @@ static void hfa384x_usbin_txcompl(wlandevice_t *wlandev, * Call context: * interrupt ----------------------------------------------------------------*/ -static void hfa384x_usbin_rx(wlandevice_t *wlandev, struct sk_buff *skb) +static void hfa384x_usbin_rx(wlandevice_t * wlandev, struct sk_buff *skb) { hfa384x_usbin_t *usbin = (hfa384x_usbin_t *) skb->data; hfa384x_t *hw = wlandev->priv; @@ -3553,8 +3537,7 @@ static void hfa384x_usbin_rx(wlandevice_t *wlandev, struct sk_buff *skb) hfa384x_int_rxmonitor(wlandev, &usbin->rxfrm); dev_kfree_skb(skb); } else { - printk(KERN_DEBUG - "Received monitor frame: FCSerr set\n"); + pr_debug("Received monitor frame: FCSerr set\n"); } break; @@ -3590,8 +3573,8 @@ done: * Call context: * interrupt ----------------------------------------------------------------*/ -static void hfa384x_int_rxmonitor(wlandevice_t *wlandev, - hfa384x_usb_rxfrm_t *rxfrm) +static void hfa384x_int_rxmonitor(wlandevice_t * wlandev, + hfa384x_usb_rxfrm_t * rxfrm) { hfa384x_rx_frame_t *rxdesc = &(rxfrm->desc); unsigned int hdrlen = 0; @@ -3616,7 +3599,7 @@ static void hfa384x_int_rxmonitor(wlandevice_t *wlandev, (sizeof(p80211_caphdr_t) + WLAN_HDR_A4_LEN + WLAN_DATA_MAXLEN + WLAN_CRC_LEN)) { pr_debug("overlen frm: len=%zd\n", - skblen - sizeof(p80211_caphdr_t)); + skblen - sizeof(p80211_caphdr_t)); } if ((skb = dev_alloc_skb(skblen)) == NULL) { @@ -4072,7 +4055,7 @@ static void hfa384x_usb_throttlefn(unsigned long data) * Call context: * process or interrupt ----------------------------------------------------------------*/ -static int hfa384x_usbctlx_submit(hfa384x_t *hw, hfa384x_usbctlx_t *ctlx) +static int hfa384x_usbctlx_submit(hfa384x_t * hw, hfa384x_usbctlx_t * ctlx) { unsigned long flags; int ret; @@ -4113,7 +4096,7 @@ static int hfa384x_usbctlx_submit(hfa384x_t *hw, hfa384x_usbctlx_t *ctlx) * Call context: * interrupt ----------------------------------------------------------------*/ -static void hfa384x_usbout_tx(wlandevice_t *wlandev, hfa384x_usbout_t *usbout) +static void hfa384x_usbout_tx(wlandevice_t * wlandev, hfa384x_usbout_t * usbout) { prism2sta_ev_alloc(wlandev); } @@ -4172,15 +4155,13 @@ static int hfa384x_isgood_pdrcode(u16 pdrcode) default: if (pdrcode < 0x1000) { /* code is OK, but we don't know exactly what it is */ - printk(KERN_DEBUG - "Encountered unknown PDR#=0x%04x, " - "assuming it's ok.\n", pdrcode); + pr_debug("Encountered unknown PDR#=0x%04x, " + "assuming it's ok.\n", pdrcode); return 1; } else { /* bad code */ - printk(KERN_DEBUG - "Encountered unknown PDR#=0x%04x, " - "(>=0x1000), assuming it's bad.\n", pdrcode); + pr_debug("Encountered unknown PDR#=0x%04x, " + "(>=0x1000), assuming it's bad.\n", pdrcode); return 0; } break; diff --git a/drivers/staging/wlan-ng/p80211conv.c b/drivers/staging/wlan-ng/p80211conv.c index 2abce0c34444..8b4f3960d9bc 100644 --- a/drivers/staging/wlan-ng/p80211conv.c +++ b/drivers/staging/wlan-ng/p80211conv.c @@ -102,9 +102,9 @@ static u8 oui_8021h[] = { 0x00, 0x00, 0xf8 }; * Call context: * May be called in interrupt or non-interrupt context ----------------------------------------------------------------*/ -int skb_ether_to_p80211(wlandevice_t *wlandev, u32 ethconv, - struct sk_buff *skb, p80211_hdr_t *p80211_hdr, - p80211_metawep_t *p80211_wep) +int skb_ether_to_p80211(wlandevice_t * wlandev, u32 ethconv, + struct sk_buff *skb, p80211_hdr_t * p80211_hdr, + p80211_metawep_t * p80211_wep) { u16 fc; @@ -209,8 +209,8 @@ int skb_ether_to_p80211(wlandevice_t *wlandev, u32 ethconv, if ((foo = wep_encrypt(wlandev, skb->data, p80211_wep->data, skb->len, - (wlandev-> - hostwep & HOSTWEP_DEFAULTKEY_MASK), + (wlandev->hostwep & + HOSTWEP_DEFAULTKEY_MASK), p80211_wep->iv, p80211_wep->icv))) { printk(KERN_WARNING "Host en-WEP failed, dropping frame (%d).\n", @@ -230,8 +230,8 @@ int skb_ether_to_p80211(wlandevice_t *wlandev, u32 ethconv, } /* jkriegl: from orinoco, modified */ -static void orinoco_spy_gather(wlandevice_t *wlandev, char *mac, - p80211_rxmeta_t *rxmeta) +static void orinoco_spy_gather(wlandevice_t * wlandev, char *mac, + p80211_rxmeta_t * rxmeta) { int i; @@ -272,7 +272,7 @@ static void orinoco_spy_gather(wlandevice_t *wlandev, char *mac, * Call context: * May be called in interrupt or non-interrupt context ----------------------------------------------------------------*/ -int skb_p80211_to_ether(wlandevice_t *wlandev, u32 ethconv, +int skb_p80211_to_ether(wlandevice_t * wlandev, u32 ethconv, struct sk_buff *skb) { netdevice_t *netdev = wlandev->netdev; @@ -329,9 +329,8 @@ int skb_p80211_to_ether(wlandevice_t *wlandev, u32 ethconv, skb->data + payload_offset + payload_length - 4))) { /* de-wep failed, drop skb. */ - printk(KERN_DEBUG - "Host de-WEP failed, dropping frame (%d).\n", - foo); + pr_debug("Host de-WEP failed, dropping frame (%d).\n", + foo); wlandev->rx.decrypt_err++; return 2; } diff --git a/drivers/staging/wlan-ng/p80211conv.h b/drivers/staging/wlan-ng/p80211conv.h index 6fe163be24f6..0c62df19fa7f 100644 --- a/drivers/staging/wlan-ng/p80211conv.h +++ b/drivers/staging/wlan-ng/p80211conv.h @@ -153,8 +153,8 @@ struct wlandevice; int skb_p80211_to_ether(struct wlandevice *wlandev, u32 ethconv, struct sk_buff *skb); int skb_ether_to_p80211(struct wlandevice *wlandev, u32 ethconv, - struct sk_buff *skb, p80211_hdr_t *p80211_hdr, - p80211_metawep_t *p80211_wep); + struct sk_buff *skb, p80211_hdr_t * p80211_hdr, + p80211_metawep_t * p80211_wep); int p80211_stt_findproto(u16 proto); diff --git a/drivers/staging/wlan-ng/p80211hdr.h b/drivers/staging/wlan-ng/p80211hdr.h index ded477517690..1703c9239476 100644 --- a/drivers/staging/wlan-ng/p80211hdr.h +++ b/drivers/staging/wlan-ng/p80211hdr.h @@ -68,8 +68,6 @@ /*================================================================*/ /* Project Includes */ - - /*================================================================*/ /* Constants */ @@ -188,7 +186,6 @@ typedef union p80211_hdr { p80211_hdr_a4_t a4; } __attribute__ ((packed)) p80211_hdr_t; - /* Frame and header length macros */ #define WLAN_CTL_FRAMELEN(fstype) (\ diff --git a/drivers/staging/wlan-ng/p80211meta.h b/drivers/staging/wlan-ng/p80211meta.h index 2f3c9fc3358c..c1a677be8dea 100644 --- a/drivers/staging/wlan-ng/p80211meta.h +++ b/drivers/staging/wlan-ng/p80211meta.h @@ -60,7 +60,6 @@ /*================================================================*/ /* Project Includes */ - /*================================================================*/ /* Types */ diff --git a/drivers/staging/wlan-ng/p80211metadef.h b/drivers/staging/wlan-ng/p80211metadef.h index a29d6ae3e770..da8b6f53c74f 100644 --- a/drivers/staging/wlan-ng/p80211metadef.h +++ b/drivers/staging/wlan-ng/p80211metadef.h @@ -50,6 +50,14 @@ #define DIDmsg_dot11req_mibget \ (P80211DID_MKSECTION(1) | \ P80211DID_MKGROUP(1)) +#define DIDmsg_dot11req_mibget_mibattribute \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(1) | 0x00000000) +#define DIDmsg_dot11req_mibget_resultcode \ + (P80211DID_MKSECTION(1) | \ + P80211DID_MKGROUP(1) | \ + P80211DID_MKITEM(2) | 0x00000000) #define DIDmsg_dot11req_mibset \ (P80211DID_MKSECTION(1) | \ P80211DID_MKGROUP(2)) @@ -94,12 +102,48 @@ #define DIDmsg_p2req_readpda \ (P80211DID_MKSECTION(5) | \ P80211DID_MKGROUP(2)) +#define DIDmsg_p2req_readpda_pda \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(1) | 0x00000000) +#define DIDmsg_p2req_readpda_resultcode \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(2) | \ + P80211DID_MKITEM(2) | 0x00000000) #define DIDmsg_p2req_ramdl_state \ (P80211DID_MKSECTION(5) | \ P80211DID_MKGROUP(11)) +#define DIDmsg_p2req_ramdl_state_enable \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(11) | \ + P80211DID_MKITEM(1) | 0x00000000) +#define DIDmsg_p2req_ramdl_state_exeaddr \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(11) | \ + P80211DID_MKITEM(2) | 0x00000000) +#define DIDmsg_p2req_ramdl_state_resultcode \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(11) | \ + P80211DID_MKITEM(3) | 0x00000000) #define DIDmsg_p2req_ramdl_write \ (P80211DID_MKSECTION(5) | \ P80211DID_MKGROUP(12)) +#define DIDmsg_p2req_ramdl_write_addr \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(12) | \ + P80211DID_MKITEM(1) | 0x00000000) +#define DIDmsg_p2req_ramdl_write_len \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(12) | \ + P80211DID_MKITEM(2) | 0x00000000) +#define DIDmsg_p2req_ramdl_write_data \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(12) | \ + P80211DID_MKITEM(3) | 0x00000000) +#define DIDmsg_p2req_ramdl_write_resultcode \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(12) | \ + P80211DID_MKITEM(4) | 0x00000000) #define DIDmsg_p2req_flashdl_state \ (P80211DID_MKSECTION(5) | \ P80211DID_MKGROUP(13)) @@ -203,6 +247,10 @@ (P80211DID_MKSECTION(5) | \ P80211DID_MKGROUP(2) | \ P80211DID_MKITEM(1) | 0x18000000) +#define DIDmib_p2_p2NIC_p2PRISupRange \ + (P80211DID_MKSECTION(5) | \ + P80211DID_MKGROUP(5) | \ + P80211DID_MKITEM(6) | 0x10000000) #define DIDmib_p2_p2MAC \ (P80211DID_MKSECTION(5) | \ P80211DID_MKGROUP(6)) diff --git a/drivers/staging/wlan-ng/p80211mgmt.h b/drivers/staging/wlan-ng/p80211mgmt.h index 6235fe7f235c..c925a45b1885 100644 --- a/drivers/staging/wlan-ng/p80211mgmt.h +++ b/drivers/staging/wlan-ng/p80211mgmt.h @@ -103,12 +103,10 @@ /*================================================================*/ /* Project Includes */ - #ifndef _P80211HDR_H #include "p80211hdr.h" #endif - /*================================================================*/ /* Constants */ @@ -504,25 +502,25 @@ typedef struct wlan_fr_deauthen { } wlan_fr_deauthen_t; -void wlan_mgmt_encode_beacon(wlan_fr_beacon_t *f); -void wlan_mgmt_decode_beacon(wlan_fr_beacon_t *f); -void wlan_mgmt_encode_disassoc(wlan_fr_disassoc_t *f); -void wlan_mgmt_decode_disassoc(wlan_fr_disassoc_t *f); -void wlan_mgmt_encode_assocreq(wlan_fr_assocreq_t *f); -void wlan_mgmt_decode_assocreq(wlan_fr_assocreq_t *f); -void wlan_mgmt_encode_assocresp(wlan_fr_assocresp_t *f); -void wlan_mgmt_decode_assocresp(wlan_fr_assocresp_t *f); -void wlan_mgmt_encode_reassocreq(wlan_fr_reassocreq_t *f); -void wlan_mgmt_decode_reassocreq(wlan_fr_reassocreq_t *f); -void wlan_mgmt_encode_reassocresp(wlan_fr_reassocresp_t *f); -void wlan_mgmt_decode_reassocresp(wlan_fr_reassocresp_t *f); -void wlan_mgmt_encode_probereq(wlan_fr_probereq_t *f); -void wlan_mgmt_decode_probereq(wlan_fr_probereq_t *f); -void wlan_mgmt_encode_proberesp(wlan_fr_proberesp_t *f); -void wlan_mgmt_decode_proberesp(wlan_fr_proberesp_t *f); -void wlan_mgmt_encode_authen(wlan_fr_authen_t *f); -void wlan_mgmt_decode_authen(wlan_fr_authen_t *f); -void wlan_mgmt_encode_deauthen(wlan_fr_deauthen_t *f); -void wlan_mgmt_decode_deauthen(wlan_fr_deauthen_t *f); +void wlan_mgmt_encode_beacon(wlan_fr_beacon_t * f); +void wlan_mgmt_decode_beacon(wlan_fr_beacon_t * f); +void wlan_mgmt_encode_disassoc(wlan_fr_disassoc_t * f); +void wlan_mgmt_decode_disassoc(wlan_fr_disassoc_t * f); +void wlan_mgmt_encode_assocreq(wlan_fr_assocreq_t * f); +void wlan_mgmt_decode_assocreq(wlan_fr_assocreq_t * f); +void wlan_mgmt_encode_assocresp(wlan_fr_assocresp_t * f); +void wlan_mgmt_decode_assocresp(wlan_fr_assocresp_t * f); +void wlan_mgmt_encode_reassocreq(wlan_fr_reassocreq_t * f); +void wlan_mgmt_decode_reassocreq(wlan_fr_reassocreq_t * f); +void wlan_mgmt_encode_reassocresp(wlan_fr_reassocresp_t * f); +void wlan_mgmt_decode_reassocresp(wlan_fr_reassocresp_t * f); +void wlan_mgmt_encode_probereq(wlan_fr_probereq_t * f); +void wlan_mgmt_decode_probereq(wlan_fr_probereq_t * f); +void wlan_mgmt_encode_proberesp(wlan_fr_proberesp_t * f); +void wlan_mgmt_decode_proberesp(wlan_fr_proberesp_t * f); +void wlan_mgmt_encode_authen(wlan_fr_authen_t * f); +void wlan_mgmt_decode_authen(wlan_fr_authen_t * f); +void wlan_mgmt_encode_deauthen(wlan_fr_deauthen_t * f); +void wlan_mgmt_decode_deauthen(wlan_fr_deauthen_t * f); #endif /* _P80211MGMT_H */ diff --git a/drivers/staging/wlan-ng/p80211msg.h b/drivers/staging/wlan-ng/p80211msg.h index f15a5d921f3c..4ac77274eefd 100644 --- a/drivers/staging/wlan-ng/p80211msg.h +++ b/drivers/staging/wlan-ng/p80211msg.h @@ -51,7 +51,6 @@ /*================================================================*/ /* Project Includes */ - #define WLAN_DEVNAMELEN_MAX 16 /*--------------------------------------------------------------------*/ diff --git a/drivers/staging/wlan-ng/p80211netdev.c b/drivers/staging/wlan-ng/p80211netdev.c index 393e4df70dfd..90f499e00dc5 100644 --- a/drivers/staging/wlan-ng/p80211netdev.c +++ b/drivers/staging/wlan-ng/p80211netdev.c @@ -49,7 +49,6 @@ * -------------------------------------------------------------------- */ -#include #include #include #include @@ -95,18 +94,18 @@ static void p80211netdev_rx_bh(unsigned long arg); /* netdevice method functions */ -static int p80211knetdev_init(netdevice_t *netdev); -static struct net_device_stats *p80211knetdev_get_stats(netdevice_t *netdev); -static int p80211knetdev_open(netdevice_t *netdev); -static int p80211knetdev_stop(netdevice_t *netdev); +static int p80211knetdev_init(netdevice_t * netdev); +static struct net_device_stats *p80211knetdev_get_stats(netdevice_t * netdev); +static int p80211knetdev_open(netdevice_t * netdev); +static int p80211knetdev_stop(netdevice_t * netdev); static int p80211knetdev_hard_start_xmit(struct sk_buff *skb, - netdevice_t *netdev); -static void p80211knetdev_set_multicast_list(netdevice_t *dev); -static int p80211knetdev_do_ioctl(netdevice_t *dev, struct ifreq *ifr, + netdevice_t * netdev); +static void p80211knetdev_set_multicast_list(netdevice_t * dev); +static int p80211knetdev_do_ioctl(netdevice_t * dev, struct ifreq *ifr, int cmd); -static int p80211knetdev_set_mac_address(netdevice_t *dev, void *addr); -static void p80211knetdev_tx_timeout(netdevice_t *netdev); -static int p80211_rx_typedrop(wlandevice_t *wlandev, u16 fc); +static int p80211knetdev_set_mac_address(netdevice_t * dev, void *addr); +static void p80211knetdev_tx_timeout(netdevice_t * netdev); +static int p80211_rx_typedrop(wlandevice_t * wlandev, u16 fc); int wlan_watchdog = 5000; module_param(wlan_watchdog, int, 0644); @@ -128,7 +127,7 @@ MODULE_PARM_DESC(wlan_wext_write, "enable write wireless extensions"); * Returns: * nothing ----------------------------------------------------------------*/ -static int p80211knetdev_init(netdevice_t *netdev) +static int p80211knetdev_init(netdevice_t * netdev) { /* Called in response to register_netdev */ /* This is usually the probe function, but the probe has */ @@ -151,7 +150,7 @@ static int p80211knetdev_init(netdevice_t *netdev) * Returns: * the address of the statistics structure ----------------------------------------------------------------*/ -static struct net_device_stats *p80211knetdev_get_stats(netdevice_t *netdev) +static struct net_device_stats *p80211knetdev_get_stats(netdevice_t * netdev) { wlandevice_t *wlandev = netdev->ml_priv; @@ -175,7 +174,7 @@ static struct net_device_stats *p80211knetdev_get_stats(netdevice_t *netdev) * Returns: * zero on success, non-zero otherwise ----------------------------------------------------------------*/ -static int p80211knetdev_open(netdevice_t *netdev) +static int p80211knetdev_open(netdevice_t * netdev) { int result = 0; /* success */ wlandevice_t *wlandev = netdev->ml_priv; @@ -210,7 +209,7 @@ static int p80211knetdev_open(netdevice_t *netdev) * Returns: * zero on success, non-zero otherwise ----------------------------------------------------------------*/ -static int p80211knetdev_stop(netdevice_t *netdev) +static int p80211knetdev_stop(netdevice_t * netdev) { int result = 0; wlandevice_t *wlandev = netdev->ml_priv; @@ -237,7 +236,7 @@ static int p80211knetdev_stop(netdevice_t *netdev) * Side effects: * ----------------------------------------------------------------*/ -void p80211netdev_rx(wlandevice_t *wlandev, struct sk_buff *skb) +void p80211netdev_rx(wlandevice_t * wlandev, struct sk_buff *skb) { /* Enqueue for post-irq processing */ skb_queue_tail(&wlandev->nsd_rxq, skb); @@ -346,7 +345,7 @@ static void p80211netdev_rx_bh(unsigned long arg) * zero on success, non-zero on failure. ----------------------------------------------------------------*/ static int p80211knetdev_hard_start_xmit(struct sk_buff *skb, - netdevice_t *netdev) + netdevice_t * netdev) { int result = 0; int txresult = -1; @@ -410,7 +409,7 @@ static int p80211knetdev_hard_start_xmit(struct sk_buff *skb, &p80211_wep) != 0) { /* convert failed */ pr_debug("ether_to_80211(%d) failed.\n", - wlandev->ethconv); + wlandev->ethconv); result = 1; goto failed; } @@ -432,21 +431,21 @@ static int p80211knetdev_hard_start_xmit(struct sk_buff *skb, /* success and more buf */ /* avail, re: hw_txdata */ netif_wake_queue(wlandev->netdev); - result = 0; + result = NETDEV_TX_OK; } else if (txresult == 1) { /* success, no more avail */ pr_debug("txframe success, no more bufs\n"); /* netdev->tbusy = 1; don't set here, irqhdlr */ /* may have already cleared it */ - result = 0; + result = NETDEV_TX_OK; } else if (txresult == 2) { /* alloc failure, drop frame */ pr_debug("txframe returned alloc_fail\n"); - result = 1; + result = NETDEV_TX_BUSY; } else { /* buffer full or queue busy, drop frame. */ pr_debug("txframe returned full or busy\n"); - result = 1; + result = NETDEV_TX_BUSY; } failed: @@ -473,7 +472,7 @@ failed: * Returns: * nothing ----------------------------------------------------------------*/ -static void p80211knetdev_set_multicast_list(netdevice_t *dev) +static void p80211knetdev_set_multicast_list(netdevice_t * dev) { wlandevice_t *wlandev = dev->ml_priv; @@ -486,7 +485,7 @@ static void p80211knetdev_set_multicast_list(netdevice_t *dev) #ifdef SIOCETHTOOL -static int p80211netdev_ethtool(wlandevice_t *wlandev, void __user *useraddr) +static int p80211netdev_ethtool(wlandevice_t * wlandev, void __user * useraddr) { u32 ethcmd; struct ethtool_drvinfo info; @@ -558,7 +557,7 @@ static int p80211netdev_ethtool(wlandevice_t *wlandev, void __user *useraddr) * Process thread (ioctl caller). TODO: SMP support may require * locks. ----------------------------------------------------------------*/ -static int p80211knetdev_do_ioctl(netdevice_t *dev, struct ifreq *ifr, int cmd) +static int p80211knetdev_do_ioctl(netdevice_t * dev, struct ifreq *ifr, int cmd) { int result = 0; p80211ioctl_req_t *req = (p80211ioctl_req_t *) ifr; @@ -567,8 +566,6 @@ static int p80211knetdev_do_ioctl(netdevice_t *dev, struct ifreq *ifr, int cmd) pr_debug("rx'd ioctl, cmd=%d, len=%d\n", cmd, req->len); - mutex_lock(&wlandev->ioctl_lock); - #ifdef SIOCETHTOOL if (cmd == SIOCETHTOOL) { result = @@ -609,8 +606,6 @@ static int p80211knetdev_do_ioctl(netdevice_t *dev, struct ifreq *ifr, int cmd) result = -ENOMEM; } bail: - mutex_unlock(&wlandev->ioctl_lock); - return result; /* If allocate,copyfrom or copyto fails, return errno */ } @@ -639,7 +634,7 @@ bail: * * by: Collin R. Mulliner ----------------------------------------------------------------*/ -static int p80211knetdev_set_mac_address(netdevice_t *dev, void *addr) +static int p80211knetdev_set_mac_address(netdevice_t * dev, void *addr) { struct sockaddr *new_addr = addr; p80211msg_dot11req_mibset_t dot11req; @@ -654,7 +649,7 @@ static int p80211knetdev_set_mac_address(netdevice_t *dev, void *addr) /* Set up some convenience pointers. */ mibattr = &dot11req.mibattribute; - macaddr = (p80211item_pstr6_t *)&mibattr->data; + macaddr = (p80211item_pstr6_t *) & mibattr->data; resultcode = &dot11req.resultcode; /* Set up a dot11req_mibset */ @@ -682,7 +677,7 @@ static int p80211knetdev_set_mac_address(netdevice_t *dev, void *addr) resultcode->data = 0; /* now fire the request */ - result = p80211req_dorequest(dev->ml_priv, (u8 *)&dot11req); + result = p80211req_dorequest(dev->ml_priv, (u8 *) & dot11req); /* If the request wasn't successful, report an error and don't * change the netdev address @@ -699,7 +694,7 @@ static int p80211knetdev_set_mac_address(netdevice_t *dev, void *addr) return result; } -static int wlan_change_mtu(netdevice_t *dev, int new_mtu) +static int wlan_change_mtu(netdevice_t * dev, int new_mtu) { /* 2312 is max 802.11 payload, 20 is overhead, (ether + llc +snap) and another 8 for wep. */ @@ -712,17 +707,17 @@ static int wlan_change_mtu(netdevice_t *dev, int new_mtu) } static const struct net_device_ops p80211_netdev_ops = { - .ndo_init = p80211knetdev_init, - .ndo_open = p80211knetdev_open, - .ndo_stop = p80211knetdev_stop, - .ndo_get_stats = p80211knetdev_get_stats, - .ndo_start_xmit = p80211knetdev_hard_start_xmit, - .ndo_set_multicast_list = p80211knetdev_set_multicast_list, - .ndo_do_ioctl = p80211knetdev_do_ioctl, - .ndo_set_mac_address = p80211knetdev_set_mac_address, - .ndo_tx_timeout = p80211knetdev_tx_timeout, - .ndo_change_mtu = wlan_change_mtu, - .ndo_validate_addr = eth_validate_addr, + .ndo_init = p80211knetdev_init, + .ndo_open = p80211knetdev_open, + .ndo_stop = p80211knetdev_stop, + .ndo_get_stats = p80211knetdev_get_stats, + .ndo_start_xmit = p80211knetdev_hard_start_xmit, + .ndo_set_multicast_list = p80211knetdev_set_multicast_list, + .ndo_do_ioctl = p80211knetdev_do_ioctl, + .ndo_set_mac_address = p80211knetdev_set_mac_address, + .ndo_tx_timeout = p80211knetdev_tx_timeout, + .ndo_change_mtu = wlan_change_mtu, + .ndo_validate_addr = eth_validate_addr, }; /*---------------------------------------------------------------- @@ -747,7 +742,7 @@ static const struct net_device_ops p80211_netdev_ops = { * compiled drivers, this function will be called in the * context of the kernel startup code. ----------------------------------------------------------------*/ -int wlan_setup(wlandevice_t *wlandev) +int wlan_setup(wlandevice_t * wlandev) { int result = 0; netdevice_t *dev; @@ -772,11 +767,6 @@ int wlan_setup(wlandevice_t *wlandev) dev->ml_priv = wlandev; dev->netdev_ops = &p80211_netdev_ops; - mutex_init(&wlandev->ioctl_lock); - /* block ioctls until fully initialised. Don't forget to call - allow_ioctls at some point!*/ - mutex_lock(&wlandev->ioctl_lock); - #if (WIRELESS_EXT < 21) dev->get_wireless_stats = p80211wext_get_wireless_stats; #endif @@ -810,7 +800,7 @@ int wlan_setup(wlandevice_t *wlandev) * compiled drivers, this function will be called in the * context of the kernel startup code. ----------------------------------------------------------------*/ -int wlan_unsetup(wlandevice_t *wlandev) +int wlan_unsetup(wlandevice_t * wlandev) { int result = 0; @@ -846,7 +836,7 @@ int wlan_unsetup(wlandevice_t *wlandev) * Call Context: * Can be either interrupt or not. ----------------------------------------------------------------*/ -int register_wlandev(wlandevice_t *wlandev) +int register_wlandev(wlandevice_t * wlandev) { int i = 0; @@ -874,7 +864,7 @@ int register_wlandev(wlandevice_t *wlandev) * Call Context: * Can be either interrupt or not. ----------------------------------------------------------------*/ -int unregister_wlandev(wlandevice_t *wlandev) +int unregister_wlandev(wlandevice_t * wlandev) { struct sk_buff *skb; @@ -917,7 +907,7 @@ int unregister_wlandev(wlandevice_t *wlandev) * Call context: * Usually interrupt. ----------------------------------------------------------------*/ -void p80211netdev_hwremoved(wlandevice_t *wlandev) +void p80211netdev_hwremoved(wlandevice_t * wlandev) { wlandev->hwremoved = 1; if (wlandev->state == WLAN_DEVICE_OPEN) @@ -947,7 +937,7 @@ void p80211netdev_hwremoved(wlandevice_t *wlandev) * Call context: * interrupt ----------------------------------------------------------------*/ -static int p80211_rx_typedrop(wlandevice_t *wlandev, u16 fc) +static int p80211_rx_typedrop(wlandevice_t * wlandev, u16 fc) { u16 ftype; u16 fstype; @@ -1105,7 +1095,7 @@ static int p80211_rx_typedrop(wlandevice_t *wlandev, u16 fc) return drop; } -static void p80211knetdev_tx_timeout(netdevice_t *netdev) +static void p80211knetdev_tx_timeout(netdevice_t * netdev) { wlandevice_t *wlandev = netdev->ml_priv; @@ -1117,8 +1107,3 @@ static void p80211knetdev_tx_timeout(netdevice_t *netdev) netif_wake_queue(wlandev->netdev); } } - -void p80211_allow_ioctls(wlandevice_t *wlandev) -{ - mutex_unlock(&wlandev->ioctl_lock); -} diff --git a/drivers/staging/wlan-ng/p80211netdev.h b/drivers/staging/wlan-ng/p80211netdev.h index b96090d87880..f4fcd2b11c47 100644 --- a/drivers/staging/wlan-ng/p80211netdev.h +++ b/drivers/staging/wlan-ng/p80211netdev.h @@ -182,16 +182,16 @@ typedef struct wlandevice { unsigned int ethconv; /* device methods (init by MSD, used by p80211 */ - int (*open) (struct wlandevice *wlandev); - int (*close) (struct wlandevice *wlandev); - void (*reset) (struct wlandevice *wlandev); - int (*txframe) (struct wlandevice *wlandev, struct sk_buff *skb, - p80211_hdr_t *p80211_hdr, - p80211_metawep_t *p80211_wep); - int (*mlmerequest) (struct wlandevice *wlandev, p80211msg_t *msg); - int (*set_multicast_list) (struct wlandevice *wlandev, - netdevice_t *dev); - void (*tx_timeout) (struct wlandevice *wlandev); + int (*open) (struct wlandevice * wlandev); + int (*close) (struct wlandevice * wlandev); + void (*reset) (struct wlandevice * wlandev); + int (*txframe) (struct wlandevice * wlandev, struct sk_buff * skb, + p80211_hdr_t * p80211_hdr, + p80211_metawep_t * p80211_wep); + int (*mlmerequest) (struct wlandevice * wlandev, p80211msg_t * msg); + int (*set_multicast_list) (struct wlandevice * wlandev, + netdevice_t * dev); + void (*tx_timeout) (struct wlandevice * wlandev); /* 802.11 State */ u8 bssid[WLAN_BSSID_LEN]; @@ -227,22 +227,19 @@ typedef struct wlandevice { u8 spy_number; char spy_address[IW_MAX_SPY][ETH_ALEN]; struct iw_quality spy_stat[IW_MAX_SPY]; - - struct mutex ioctl_lock; } wlandevice_t; /* WEP stuff */ -int wep_change_key(wlandevice_t *wlandev, int keynum, u8 *key, int keylen); -int wep_decrypt(wlandevice_t *wlandev, u8 *buf, u32 len, int key_override, - u8 *iv, u8 *icv); -int wep_encrypt(wlandevice_t *wlandev, u8 *buf, u8 *dst, u32 len, int keynum, - u8 *iv, u8 *icv); +int wep_change_key(wlandevice_t * wlandev, int keynum, u8 * key, int keylen); +int wep_decrypt(wlandevice_t * wlandev, u8 * buf, u32 len, int key_override, + u8 * iv, u8 * icv); +int wep_encrypt(wlandevice_t * wlandev, u8 * buf, u8 * dst, u32 len, int keynum, + u8 * iv, u8 * icv); -int wlan_setup(wlandevice_t *wlandev); -int wlan_unsetup(wlandevice_t *wlandev); -int register_wlandev(wlandevice_t *wlandev); -int unregister_wlandev(wlandevice_t *wlandev); -void p80211netdev_rx(wlandevice_t *wlandev, struct sk_buff *skb); -void p80211netdev_hwremoved(wlandevice_t *wlandev); -void p80211_allow_ioctls(wlandevice_t *wlandev); +int wlan_setup(wlandevice_t * wlandev); +int wlan_unsetup(wlandevice_t * wlandev); +int register_wlandev(wlandevice_t * wlandev); +int unregister_wlandev(wlandevice_t * wlandev); +void p80211netdev_rx(wlandevice_t * wlandev, struct sk_buff *skb); +void p80211netdev_hwremoved(wlandevice_t * wlandev); #endif diff --git a/drivers/staging/wlan-ng/p80211req.c b/drivers/staging/wlan-ng/p80211req.c index 15ecba6e4693..584c4193ad84 100644 --- a/drivers/staging/wlan-ng/p80211req.c +++ b/drivers/staging/wlan-ng/p80211req.c @@ -73,9 +73,9 @@ #include "p80211metastruct.h" #include "p80211req.h" -static void p80211req_handlemsg(wlandevice_t *wlandev, p80211msg_t *msg); -static int p80211req_mibset_mibget(wlandevice_t *wlandev, - p80211msg_dot11req_mibget_t *mib_msg, +static void p80211req_handlemsg(wlandevice_t * wlandev, p80211msg_t * msg); +static int p80211req_mibset_mibget(wlandevice_t * wlandev, + p80211msg_dot11req_mibget_t * mib_msg, int isget); /*---------------------------------------------------------------- @@ -94,7 +94,7 @@ static int p80211req_mibset_mibget(wlandevice_t *wlandev, * Potentially blocks the caller, so it's a good idea to * not call this function from an interrupt context. ----------------------------------------------------------------*/ -int p80211req_dorequest(wlandevice_t *wlandev, u8 *msgbuf) +int p80211req_dorequest(wlandevice_t * wlandev, u8 * msgbuf) { int result = 0; p80211msg_t *msg = (p80211msg_t *) msgbuf; @@ -129,7 +129,7 @@ int p80211req_dorequest(wlandevice_t *wlandev, u8 *msgbuf) wlandev->mlmerequest(wlandev, msg); clear_bit(1, &(wlandev->request_pending)); - return result; /* if result==0, msg->status still may contain an err */ + return result; /* if result==0, msg->status still may contain an err */ } /*---------------------------------------------------------------- @@ -150,7 +150,7 @@ int p80211req_dorequest(wlandevice_t *wlandev, u8 *msgbuf) * Call context: * Process thread ----------------------------------------------------------------*/ -static void p80211req_handlemsg(wlandevice_t *wlandev, p80211msg_t *msg) +static void p80211req_handlemsg(wlandevice_t * wlandev, p80211msg_t * msg) { switch (msg->msgcode) { @@ -180,8 +180,8 @@ static void p80211req_handlemsg(wlandevice_t *wlandev, p80211msg_t *msg) return; } -static int p80211req_mibset_mibget(wlandevice_t *wlandev, - p80211msg_dot11req_mibget_t *mib_msg, +static int p80211req_mibset_mibget(wlandevice_t * wlandev, + p80211msg_dot11req_mibget_t * mib_msg, int isget) { p80211itemd_t *mibitem = (p80211itemd_t *) mib_msg->mibattribute.data; @@ -243,8 +243,8 @@ static int p80211req_mibset_mibget(wlandevice_t *wlandev, u32 *data = (u32 *) mibitem->data; if (isget) { - if (wlandev-> - hostwep & HOSTWEP_EXCLUDEUNENCRYPTED) + if (wlandev->hostwep & + HOSTWEP_EXCLUDEUNENCRYPTED) *data = P80211ENUM_truth_true; else *data = P80211ENUM_truth_false; diff --git a/drivers/staging/wlan-ng/p80211req.h b/drivers/staging/wlan-ng/p80211req.h index a95a45a6814d..5d9176762ba7 100644 --- a/drivers/staging/wlan-ng/p80211req.h +++ b/drivers/staging/wlan-ng/p80211req.h @@ -48,6 +48,6 @@ #ifndef _LINUX_P80211REQ_H #define _LINUX_P80211REQ_H -int p80211req_dorequest(wlandevice_t *wlandev, u8 *msgbuf); +int p80211req_dorequest(wlandevice_t * wlandev, u8 * msgbuf); #endif diff --git a/drivers/staging/wlan-ng/p80211types.h b/drivers/staging/wlan-ng/p80211types.h index a22437ceddca..043da1e5607f 100644 --- a/drivers/staging/wlan-ng/p80211types.h +++ b/drivers/staging/wlan-ng/p80211types.h @@ -61,7 +61,6 @@ /* Project Includes */ /*================================================================*/ - /*----------------------------------------------------------------*/ /* The following constants are indexes into the Mib Category List */ /* and the Message Category List */ @@ -345,11 +344,11 @@ struct catlistitem; /* metadata items. Some components may choose to use more, */ /* less or different metadata items. */ -typedef void (*p80211_totext_t) (struct catlistitem *, u32 did, u8 *itembuf, +typedef void (*p80211_totext_t) (struct catlistitem *, u32 did, u8 * itembuf, char *textbuf); -typedef void (*p80211_fromtext_t) (struct catlistitem *, u32 did, u8 *itembuf, +typedef void (*p80211_fromtext_t) (struct catlistitem *, u32 did, u8 * itembuf, char *textbuf); -typedef u32(*p80211_valid_t) (struct catlistitem *, u32 did, u8 *itembuf); +typedef u32(*p80211_valid_t) (struct catlistitem *, u32 did, u8 * itembuf); /*----------------------------------------------------------------*/ /* Enumeration Lists */ diff --git a/drivers/staging/wlan-ng/p80211wep.c b/drivers/staging/wlan-ng/p80211wep.c index 405ce89e4e6e..f0b4275ab228 100644 --- a/drivers/staging/wlan-ng/p80211wep.c +++ b/drivers/staging/wlan-ng/p80211wep.c @@ -48,9 +48,6 @@ /*================================================================*/ /* System Includes */ - -#include - #include #include #include @@ -77,58 +74,58 @@ /* Local Static Definitions */ static const u32 wep_crc32_table[256] = { - 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, - 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, - 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, - 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, - 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, - 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, - 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, - 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, - 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, - 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, - 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, - 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, - 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, - 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, - 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, - 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, - 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, - 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, - 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, - 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, - 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, - 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, - 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, - 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, - 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, - 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, - 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, - 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, - 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, - 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, - 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, - 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, - 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, - 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, - 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, - 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, - 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, - 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, - 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, - 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, - 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, - 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, - 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, - 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, - 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, - 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, - 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, - 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, - 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, - 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, - 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, - 0x2d02ef8dL + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, + 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, + 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, + 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, + 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, + 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, + 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, + 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, + 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, + 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, + 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, + 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, + 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, + 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, + 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, + 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, + 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, + 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, + 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, + 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, + 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, + 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, + 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, + 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, + 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, + 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, + 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, + 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, + 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, + 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, + 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, + 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, + 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, + 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, + 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, + 0x2d02ef8dL }; /*================================================================*/ @@ -139,17 +136,24 @@ static const u32 wep_crc32_table[256] = { /* keylen in bytes! */ -int wep_change_key(wlandevice_t *wlandev, int keynum, u8* key, int keylen) +int wep_change_key(wlandevice_t * wlandev, int keynum, u8 * key, int keylen) { - if (keylen < 0) return -1; - if (keylen >= MAX_KEYLEN) return -1; - if (key == NULL) return -1; - if (keynum < 0) return -1; - if (keynum >= NUM_WEPKEYS) return -1; - + if (keylen < 0) + return -1; + if (keylen >= MAX_KEYLEN) + return -1; + if (key == NULL) + return -1; + if (keynum < 0) + return -1; + if (keynum >= NUM_WEPKEYS) + return -1; #ifdef WEP_DEBUG - printk(KERN_DEBUG "WEP key %d len %d = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", keynum, keylen, key[0], key[1], key[2], key[3], key[4], key[5], key[6], key[7]); + printk(KERN_DEBUG + "WEP key %d len %d = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", + keynum, keylen, key[0], key[1], key[2], key[3], key[4], key[5], + key[6], key[7]); #endif wlandev->wep_keylens[keynum] = keylen; @@ -162,14 +166,16 @@ int wep_change_key(wlandevice_t *wlandev, int keynum, u8* key, int keylen) 4-byte IV at start of buffer, 4-byte ICV at end of buffer. if successful, buf start is payload begin, length -= 8; */ -int wep_decrypt(wlandevice_t *wlandev, u8 *buf, u32 len, int key_override, u8 *iv, u8 *icv) +int wep_decrypt(wlandevice_t * wlandev, u8 * buf, u32 len, int key_override, + u8 * iv, u8 * icv) { u32 i, j, k, crc, keylen; u8 s[256], key[64], c_crc[4]; u8 keyidx; /* Needs to be at least 8 bytes of payload */ - if (len <= 0) return -1; + if (len <= 0) + return -1; /* initialize the first bytes of the key from the IV */ key[0] = iv[0]; @@ -180,19 +186,24 @@ int wep_decrypt(wlandevice_t *wlandev, u8 *buf, u32 len, int key_override, u8 *i if (key_override >= 0) keyidx = key_override; - if (keyidx >= NUM_WEPKEYS) return -2; + if (keyidx >= NUM_WEPKEYS) + return -2; keylen = wlandev->wep_keylens[keyidx]; - if (keylen == 0) return -3; + if (keylen == 0) + return -3; /* copy the rest of the key over from the designated key */ - memcpy(key+3, wlandev->wep_keys[keyidx], keylen); + memcpy(key + 3, wlandev->wep_keys[keyidx], keylen); - keylen+=3; /* add in IV bytes */ + keylen += 3; /* add in IV bytes */ #ifdef WEP_DEBUG - printk(KERN_DEBUG "D %d: %02x %02x %02x (%d %d) %02x:%02x:%02x:%02x:%02x\n", len, key[0], key[1], key[2], keyidx, keylen, key[3], key[4], key[5], key[6], key[7]); + printk(KERN_DEBUG + "D %d: %02x %02x %02x (%d %d) %02x:%02x:%02x:%02x:%02x\n", len, + key[0], key[1], key[2], keyidx, keylen, key[3], key[4], key[5], + key[6], key[7]); #endif /* set up the RC4 state */ @@ -201,16 +212,16 @@ int wep_decrypt(wlandevice_t *wlandev, u8 *buf, u32 len, int key_override, u8 *i j = 0; for (i = 0; i < 256; i++) { j = (j + s[i] + key[i % keylen]) & 0xff; - swap(i,j); + swap(i, j); } /* Apply the RC4 to the data, update the CRC32 */ crc = ~0; i = j = 0; for (k = 0; k < len; k++) { - i = (i+1) & 0xff; - j = (j+s[i]) & 0xff; - swap(i,j); + i = (i + 1) & 0xff; + j = (j + s[i]) & 0xff; + swap(i, j); buf[k] ^= s[(s[i] + s[j]) & 0xff]; crc = wep_crc32_table[(crc ^ buf[k]) & 0xff] ^ (crc >> 8); } @@ -224,28 +235,32 @@ int wep_decrypt(wlandevice_t *wlandev, u8 *buf, u32 len, int key_override, u8 *i for (k = 0; k < 4; k++) { i = (i + 1) & 0xff; - j = (j+s[i]) & 0xff; - swap(i,j); + j = (j + s[i]) & 0xff; + swap(i, j); if ((c_crc[k] ^ s[(s[i] + s[j]) & 0xff]) != icv[k]) - return -(4 | (k << 4)) ; /* ICV mismatch */ + return -(4 | (k << 4)); /* ICV mismatch */ } return 0; } /* encrypts in-place. */ -int wep_encrypt(wlandevice_t *wlandev, u8 *buf, u8 *dst, u32 len, int keynum, u8 *iv, u8 *icv) +int wep_encrypt(wlandevice_t * wlandev, u8 * buf, u8 * dst, u32 len, int keynum, + u8 * iv, u8 * icv) { u32 i, j, k, crc, keylen; u8 s[256], key[64]; /* no point in WEPping an empty frame */ - if (len <= 0) return -1; + if (len <= 0) + return -1; /* we need to have a real key.. */ - if (keynum >= NUM_WEPKEYS) return -2; + if (keynum >= NUM_WEPKEYS) + return -2; keylen = wlandev->wep_keylens[keynum]; - if (keylen <= 0) return -3; + if (keylen <= 0) + return -3; /* use a random IV. And skip known weak ones. */ get_random_bytes(iv, 3); @@ -259,12 +274,15 @@ int wep_encrypt(wlandevice_t *wlandev, u8 *buf, u8 *dst, u32 len, int keynum, u8 key[2] = iv[2]; /* copy the rest of the key over from the designated key */ - memcpy(key+3, wlandev->wep_keys[keynum], keylen); + memcpy(key + 3, wlandev->wep_keys[keynum], keylen); - keylen+=3; /* add in IV bytes */ + keylen += 3; /* add in IV bytes */ #ifdef WEP_DEBUG - printk(KERN_DEBUG "E %d (%d/%d %d) %02x %02x %02x %02x:%02x:%02x:%02x:%02x\n", len, iv[3], keynum, keylen, key[0], key[1], key[2], key[3], key[4], key[5], key[6], key[7]); + printk(KERN_DEBUG + "E %d (%d/%d %d) %02x %02x %02x %02x:%02x:%02x:%02x:%02x\n", len, + iv[3], keynum, keylen, key[0], key[1], key[2], key[3], key[4], + key[5], key[6], key[7]); #endif /* set up the RC4 state */ @@ -273,7 +291,7 @@ int wep_encrypt(wlandevice_t *wlandev, u8 *buf, u8 *dst, u32 len, int keynum, u8 j = 0; for (i = 0; i < 256; i++) { j = (j + s[i] + key[i % keylen]) & 0xff; - swap(i,j); + swap(i, j); } /* Update CRC32 then apply RC4 to the data */ @@ -281,9 +299,9 @@ int wep_encrypt(wlandevice_t *wlandev, u8 *buf, u8 *dst, u32 len, int keynum, u8 i = j = 0; for (k = 0; k < len; k++) { crc = wep_crc32_table[(crc ^ buf[k]) & 0xff] ^ (crc >> 8); - i = (i+1) & 0xff; - j = (j+s[i]) & 0xff; - swap(i,j); + i = (i + 1) & 0xff; + j = (j + s[i]) & 0xff; + swap(i, j); dst[k] = buf[k] ^ s[(s[i] + s[j]) & 0xff]; } crc = ~crc; @@ -296,8 +314,8 @@ int wep_encrypt(wlandevice_t *wlandev, u8 *buf, u8 *dst, u32 len, int keynum, u8 for (k = 0; k < 4; k++) { i = (i + 1) & 0xff; - j = (j+s[i]) & 0xff; - swap(i,j); + j = (j + s[i]) & 0xff; + swap(i, j); icv[k] ^= s[(s[i] + s[j]) & 0xff]; } diff --git a/drivers/staging/wlan-ng/p80211wext.c b/drivers/staging/wlan-ng/p80211wext.c index 96078b0ea6aa..984e45d9f700 100644 --- a/drivers/staging/wlan-ng/p80211wext.c +++ b/drivers/staging/wlan-ng/p80211wext.c @@ -37,8 +37,6 @@ /*================================================================*/ /* System Includes */ - - #include #include #include @@ -68,10 +66,10 @@ #include "p80211ioctl.h" #include "p80211req.h" -static int p80211wext_giwrate(netdevice_t *dev, +static int p80211wext_giwrate(netdevice_t * dev, struct iw_request_info *info, struct iw_param *rrq, char *extra); -static int p80211wext_giwessid(netdevice_t *dev, +static int p80211wext_giwessid(netdevice_t * dev, struct iw_request_info *info, struct iw_point *data, char *essid); @@ -132,7 +130,7 @@ static int qual_as_percent(int snr) return 100; } -static int p80211wext_dorequest(wlandevice_t *wlandev, u32 did, u32 data) +static int p80211wext_dorequest(wlandevice_t * wlandev, u32 did, u32 data) { p80211msg_dot11req_mibset_t msg; p80211item_uint32_t mibitem; @@ -142,12 +140,12 @@ static int p80211wext_dorequest(wlandevice_t *wlandev, u32 did, u32 data) mibitem.did = did; mibitem.data = data; memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); - result = p80211req_dorequest(wlandev, (u8 *)&msg); + result = p80211req_dorequest(wlandev, (u8 *) & msg); return result; } -static int p80211wext_autojoin(wlandevice_t *wlandev) +static int p80211wext_autojoin(wlandevice_t * wlandev) { p80211msg_lnxreq_autojoin_t msg; struct iw_point data; @@ -179,7 +177,7 @@ static int p80211wext_autojoin(wlandevice_t *wlandev) memcpy(msg.ssid.data.data, ssid, data.length); msg.ssid.data.len = data.length; - result = p80211req_dorequest(wlandev, (u8 *)&msg); + result = p80211req_dorequest(wlandev, (u8 *) & msg); if (result) { err = -EFAULT; @@ -216,7 +214,7 @@ struct iw_statistics *p80211wext_get_wireless_stats(netdevice_t * dev) if (wlandev->mlmerequest == NULL) return NULL; - retval = wlandev->mlmerequest(wlandev, (p80211msg_t *)&quality); + retval = wlandev->mlmerequest(wlandev, (p80211msg_t *) & quality); wstats->qual.qual = qual_as_percent(quality.link.data); /* overall link quality */ wstats->qual.level = quality.level.data; /* instant signal level */ @@ -234,7 +232,7 @@ struct iw_statistics *p80211wext_get_wireless_stats(netdevice_t * dev) return wstats; } -static int p80211wext_giwname(netdevice_t *dev, +static int p80211wext_giwname(netdevice_t * dev, struct iw_request_info *info, char *name, char *extra) { @@ -263,7 +261,7 @@ exit: return err; } -static int p80211wext_giwfreq(netdevice_t *dev, +static int p80211wext_giwfreq(netdevice_t * dev, struct iw_request_info *info, struct iw_freq *freq, char *extra) { @@ -276,7 +274,7 @@ static int p80211wext_giwfreq(netdevice_t *dev, msg.msgcode = DIDmsg_dot11req_mibget; mibitem.did = DIDmib_dot11phy_dot11PhyDSSSTable_dot11CurrentChannel; memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); - result = p80211req_dorequest(wlandev, (u8 *)&msg); + result = p80211req_dorequest(wlandev, (u8 *) & msg); if (result) { err = -EFAULT; @@ -298,7 +296,7 @@ exit: return err; } -static int p80211wext_siwfreq(netdevice_t *dev, +static int p80211wext_siwfreq(netdevice_t * dev, struct iw_request_info *info, struct iw_freq *freq, char *extra) { @@ -323,7 +321,7 @@ static int p80211wext_siwfreq(netdevice_t *dev, mibitem.data = p80211_mhz_to_channel(freq->m); memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); - result = p80211req_dorequest(wlandev, (u8 *)&msg); + result = p80211req_dorequest(wlandev, (u8 *) & msg); if (result) { err = -EFAULT; @@ -334,9 +332,9 @@ exit: return err; } -static int p80211wext_giwmode(netdevice_t *dev, +static int p80211wext_giwmode(netdevice_t * dev, struct iw_request_info *info, - __u32 *mode, char *extra) + __u32 * mode, char *extra) { wlandevice_t *wlandev = dev->ml_priv; @@ -358,9 +356,9 @@ static int p80211wext_giwmode(netdevice_t *dev, return 0; } -static int p80211wext_siwmode(netdevice_t *dev, +static int p80211wext_siwmode(netdevice_t * dev, struct iw_request_info *info, - __u32 *mode, char *extra) + __u32 * mode, char *extra) { wlandevice_t *wlandev = dev->ml_priv; p80211item_uint32_t mibitem; @@ -404,7 +402,7 @@ static int p80211wext_siwmode(netdevice_t *dev, mibitem.did = DIDmib_p2_p2Static_p2CnfPortType; mibitem.data = (*mode == IW_MODE_ADHOC) ? 0 : 1; memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); - result = p80211req_dorequest(wlandev, (u8 *)&msg); + result = p80211req_dorequest(wlandev, (u8 *) & msg); if (result) err = -EFAULT; @@ -413,7 +411,7 @@ exit: return err; } -static int p80211wext_giwrange(netdevice_t *dev, +static int p80211wext_giwrange(netdevice_t * dev, struct iw_request_info *info, struct iw_point *data, char *extra) { @@ -482,7 +480,7 @@ static int p80211wext_giwrange(netdevice_t *dev, return 0; } -static int p80211wext_giwap(netdevice_t *dev, +static int p80211wext_giwap(netdevice_t * dev, struct iw_request_info *info, struct sockaddr *ap_addr, char *extra) { @@ -495,7 +493,7 @@ static int p80211wext_giwap(netdevice_t *dev, return 0; } -static int p80211wext_giwencode(netdevice_t *dev, +static int p80211wext_giwencode(netdevice_t * dev, struct iw_request_info *info, struct iw_point *erq, char *key) { @@ -536,7 +534,7 @@ exit: return err; } -static int p80211wext_siwencode(netdevice_t *dev, +static int p80211wext_siwencode(netdevice_t * dev, struct iw_request_info *info, struct iw_point *erq, char *key) { @@ -626,7 +624,7 @@ static int p80211wext_siwencode(netdevice_t *dev, msg.msgcode = DIDmsg_dot11req_mibset; memcpy(&msg.mibattribute.data, &pstr, sizeof(pstr)); - result = p80211req_dorequest(wlandev, (u8 *)&msg); + result = p80211req_dorequest(wlandev, (u8 *) & msg); if (result) { err = -EFAULT; @@ -683,7 +681,7 @@ exit: return err; } -static int p80211wext_giwessid(netdevice_t *dev, +static int p80211wext_giwessid(netdevice_t * dev, struct iw_request_info *info, struct iw_point *data, char *essid) { @@ -706,7 +704,7 @@ static int p80211wext_giwessid(netdevice_t *dev, return 0; } -static int p80211wext_siwessid(netdevice_t *dev, +static int p80211wext_siwessid(netdevice_t * dev, struct iw_request_info *info, struct iw_point *data, char *essid) { @@ -742,7 +740,7 @@ static int p80211wext_siwessid(netdevice_t *dev, msg.ssid.data.len = length; pr_debug("autojoin_ssid for %s \n", essid); - result = p80211req_dorequest(wlandev, (u8 *)&msg); + result = p80211req_dorequest(wlandev, (u8 *) & msg); pr_debug("autojoin_ssid %d\n", result); if (result) { @@ -754,7 +752,7 @@ exit: return err; } -static int p80211wext_siwcommit(netdevice_t *dev, +static int p80211wext_siwcommit(netdevice_t * dev, struct iw_request_info *info, struct iw_point *data, char *essid) { @@ -773,7 +771,7 @@ exit: return err; } -static int p80211wext_giwrate(netdevice_t *dev, +static int p80211wext_giwrate(netdevice_t * dev, struct iw_request_info *info, struct iw_param *rrq, char *extra) { @@ -786,7 +784,7 @@ static int p80211wext_giwrate(netdevice_t *dev, msg.msgcode = DIDmsg_dot11req_mibget; mibitem.did = DIDmib_p2_p2MAC_p2CurrentTxRate; memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); - result = p80211req_dorequest(wlandev, (u8 *)&msg); + result = p80211req_dorequest(wlandev, (u8 *) & msg); if (result) { err = -EFAULT; @@ -824,7 +822,7 @@ exit: return err; } -static int p80211wext_giwrts(netdevice_t *dev, +static int p80211wext_giwrts(netdevice_t * dev, struct iw_request_info *info, struct iw_param *rts, char *extra) { @@ -837,7 +835,7 @@ static int p80211wext_giwrts(netdevice_t *dev, msg.msgcode = DIDmsg_dot11req_mibget; mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11RTSThreshold; memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); - result = p80211req_dorequest(wlandev, (u8 *)&msg); + result = p80211req_dorequest(wlandev, (u8 *) & msg); if (result) { err = -EFAULT; @@ -854,7 +852,7 @@ exit: return err; } -static int p80211wext_siwrts(netdevice_t *dev, +static int p80211wext_siwrts(netdevice_t * dev, struct iw_request_info *info, struct iw_param *rts, char *extra) { @@ -877,7 +875,7 @@ static int p80211wext_siwrts(netdevice_t *dev, mibitem.data = rts->value; memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); - result = p80211req_dorequest(wlandev, (u8 *)&msg); + result = p80211req_dorequest(wlandev, (u8 *) & msg); if (result) { err = -EFAULT; @@ -888,7 +886,7 @@ exit: return err; } -static int p80211wext_giwfrag(netdevice_t *dev, +static int p80211wext_giwfrag(netdevice_t * dev, struct iw_request_info *info, struct iw_param *frag, char *extra) { @@ -902,7 +900,7 @@ static int p80211wext_giwfrag(netdevice_t *dev, mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11FragmentationThreshold; memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); - result = p80211req_dorequest(wlandev, (u8 *)&msg); + result = p80211req_dorequest(wlandev, (u8 *) & msg); if (result) { err = -EFAULT; @@ -919,7 +917,7 @@ exit: return err; } -static int p80211wext_siwfrag(netdevice_t *dev, +static int p80211wext_siwfrag(netdevice_t * dev, struct iw_request_info *info, struct iw_param *frag, char *extra) { @@ -944,7 +942,7 @@ static int p80211wext_siwfrag(netdevice_t *dev, mibitem.data = frag->value; memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); - result = p80211req_dorequest(wlandev, (u8 *)&msg); + result = p80211req_dorequest(wlandev, (u8 *) & msg); if (result) { err = -EFAULT; @@ -963,7 +961,7 @@ exit: #define IW_RETRY_SHORT IW_RETRY_MIN #endif -static int p80211wext_giwretry(netdevice_t *dev, +static int p80211wext_giwretry(netdevice_t * dev, struct iw_request_info *info, struct iw_param *rrq, char *extra) { @@ -978,7 +976,7 @@ static int p80211wext_giwretry(netdevice_t *dev, mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11ShortRetryLimit; memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); - result = p80211req_dorequest(wlandev, (u8 *)&msg); + result = p80211req_dorequest(wlandev, (u8 *) & msg); if (result) { err = -EFAULT; @@ -992,7 +990,7 @@ static int p80211wext_giwretry(netdevice_t *dev, mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11LongRetryLimit; memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); - result = p80211req_dorequest(wlandev, (u8 *)&msg); + result = p80211req_dorequest(wlandev, (u8 *) & msg); if (result) { err = -EFAULT; @@ -1007,7 +1005,7 @@ static int p80211wext_giwretry(netdevice_t *dev, DIDmib_dot11mac_dot11OperationTable_dot11MaxTransmitMSDULifetime; memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); - result = p80211req_dorequest(wlandev, (u8 *)&msg); + result = p80211req_dorequest(wlandev, (u8 *) & msg); if (result) { err = -EFAULT; @@ -1040,7 +1038,7 @@ exit: } -static int p80211wext_siwretry(netdevice_t *dev, +static int p80211wext_siwretry(netdevice_t * dev, struct iw_request_info *info, struct iw_param *rrq, char *extra) { @@ -1068,7 +1066,7 @@ static int p80211wext_siwretry(netdevice_t *dev, mibitem.data = rrq->value /= 1024; memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); - result = p80211req_dorequest(wlandev, (u8 *)&msg); + result = p80211req_dorequest(wlandev, (u8 *) & msg); if (result) { err = -EFAULT; @@ -1082,7 +1080,7 @@ static int p80211wext_siwretry(netdevice_t *dev, memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); - result = p80211req_dorequest(wlandev, (u8 *)&msg); + result = p80211req_dorequest(wlandev, (u8 *) & msg); if (result) { err = -EFAULT; @@ -1097,7 +1095,7 @@ static int p80211wext_siwretry(netdevice_t *dev, memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); - result = p80211req_dorequest(wlandev, (u8 *)&msg); + result = p80211req_dorequest(wlandev, (u8 *) & msg); if (result) { err = -EFAULT; @@ -1111,7 +1109,7 @@ exit: } -static int p80211wext_siwtxpow(netdevice_t *dev, +static int p80211wext_siwtxpow(netdevice_t * dev, struct iw_request_info *info, struct iw_param *rrq, char *extra) { @@ -1134,7 +1132,7 @@ static int p80211wext_siwtxpow(netdevice_t *dev, else mibitem.data = rrq->value; memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); - result = p80211req_dorequest(wlandev, (u8 *)&msg); + result = p80211req_dorequest(wlandev, (u8 *) & msg); if (result) { err = -EFAULT; @@ -1145,7 +1143,7 @@ exit: return err; } -static int p80211wext_giwtxpow(netdevice_t *dev, +static int p80211wext_giwtxpow(netdevice_t * dev, struct iw_request_info *info, struct iw_param *rrq, char *extra) { @@ -1160,7 +1158,7 @@ static int p80211wext_giwtxpow(netdevice_t *dev, DIDmib_dot11phy_dot11PhyTxPowerTable_dot11CurrentTxPowerLevel; memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); - result = p80211req_dorequest(wlandev, (u8 *)&msg); + result = p80211req_dorequest(wlandev, (u8 *) & msg); if (result) { err = -EFAULT; @@ -1180,7 +1178,7 @@ exit: return err; } -static int p80211wext_siwspy(netdevice_t *dev, +static int p80211wext_siwspy(netdevice_t * dev, struct iw_request_info *info, struct iw_point *srq, char *extra) { @@ -1215,7 +1213,7 @@ static int p80211wext_siwspy(netdevice_t *dev, } /* jkriegl: from orinoco, modified */ -static int p80211wext_giwspy(netdevice_t *dev, +static int p80211wext_giwspy(netdevice_t * dev, struct iw_request_info *info, struct iw_point *srq, char *extra) { @@ -1275,7 +1273,7 @@ static int prism2_result2err(int prism2_result) return err; } -static int p80211wext_siwscan(netdevice_t *dev, +static int p80211wext_siwscan(netdevice_t * dev, struct iw_request_info *info, struct iw_point *srq, char *extra) { @@ -1308,7 +1306,7 @@ static int p80211wext_siwscan(netdevice_t *dev, msg.maxchanneltime.data = 250; msg.minchanneltime.data = 200; - result = p80211req_dorequest(wlandev, (u8 *)&msg); + result = p80211req_dorequest(wlandev, (u8 *) & msg); if (result) err = prism2_result2err(msg.resultcode.data); @@ -1322,7 +1320,7 @@ exit: */ static char *wext_translate_bss(struct iw_request_info *info, char *current_ev, char *end_buf, - p80211msg_dot11req_scan_results_t *bss) + p80211msg_dot11req_scan_results_t * bss) { struct iw_event iwe; /* Temporary buffer */ @@ -1406,7 +1404,7 @@ static char *wext_translate_bss(struct iw_request_info *info, char *current_ev, return current_ev; } -static int p80211wext_giwscan(netdevice_t *dev, +static int p80211wext_giwscan(netdevice_t * dev, struct iw_request_info *info, struct iw_point *srq, char *extra) { @@ -1427,7 +1425,7 @@ static int p80211wext_giwscan(netdevice_t *dev, msg.msgcode = DIDmsg_dot11req_scan_results; msg.bssindex.data = i; - result = p80211req_dorequest(wlandev, (u8 *)&msg); + result = p80211req_dorequest(wlandev, (u8 *) & msg); if ((result != 0) || (msg.resultcode.data != P80211ENUM_resultcode_success)) { break; @@ -1466,7 +1464,7 @@ static int p80211wext_set_encodeext(struct net_device *dev, int idx = encoding->flags & IW_ENCODE_INDEX; pr_debug("set_encode_ext flags[%d] alg[%d] keylen[%d]\n", - ext->ext_flags, (int)ext->alg, (int)ext->key_len); + ext->ext_flags, (int)ext->alg, (int)ext->key_len); if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { /* set default key ? I'm not sure if this the the correct thing to do here */ @@ -1487,8 +1485,8 @@ static int p80211wext_set_encodeext(struct net_device *dev, } if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { - if (!(ext->alg & IW_ENCODE_ALG_WEP)) { - pr_debug("asked to set a non wep key :("); + if (ext->alg != IW_ENCODE_ALG_WEP) { + pr_debug("asked to set a non wep key :(\n"); return -EINVAL; } if (idx) { @@ -1502,7 +1500,7 @@ static int p80211wext_set_encodeext(struct net_device *dev, memcpy(wlandev->wep_keys[idx], ext->key, ext->key_len); memset(&msg, 0, sizeof(msg)); - pstr = (p80211item_pstr32_t *)&msg.mibattribute.data; + pstr = (p80211item_pstr32_t *) & msg.mibattribute.data; memcpy(pstr->data.data, ext->key, ext->key_len); pstr->data.len = ext->key_len; switch (idx) { @@ -1526,7 +1524,7 @@ static int p80211wext_set_encodeext(struct net_device *dev, break; } msg.msgcode = DIDmsg_dot11req_mibset; - result = p80211req_dorequest(wlandev, (u8 *)&msg); + result = p80211req_dorequest(wlandev, (u8 *) & msg); pr_debug("result (%d)\n", result); } return result; @@ -1546,12 +1544,11 @@ static int p80211wext_get_encodeext(struct net_device *dev, int idx; pr_debug("get_encode_ext flags[%d] alg[%d] keylen[%d]\n", - ext->ext_flags, (int)ext->alg, (int)ext->key_len); + ext->ext_flags, (int)ext->alg, (int)ext->key_len); max_len = encoding->length - sizeof(*ext); if (max_len <= 0) { - pr_debug("get_encodeext max_len [%d] invalid\n", - max_len); + pr_debug("get_encodeext max_len [%d] invalid\n", max_len); result = -EINVAL; goto exit; } @@ -1561,8 +1558,8 @@ static int p80211wext_get_encodeext(struct net_device *dev, if (idx) { if (idx < 1 || idx > NUM_WEPKEYS) { - printk(KERN_DEBUG - "get_encode_ext invalid key index [%d]\n", idx); + pr_debug("get_encode_ext invalid key index [%d]\n", + idx); result = -EINVAL; goto exit; } @@ -1593,8 +1590,7 @@ static int p80211_wext_set_iwauth(struct net_device *dev, struct iw_param *param = &wrqu->param; int result = 0; - pr_debug("set_iwauth flags[%d]\n", - (int)param->flags & IW_AUTH_INDEX); + pr_debug("set_iwauth flags[%d]\n", (int)param->flags & IW_AUTH_INDEX); switch (param->flags & IW_AUTH_INDEX) { case IW_AUTH_DROP_UNENCRYPTED: @@ -1635,8 +1631,7 @@ static int p80211_wext_set_iwauth(struct net_device *dev, wlandev->hostwep |= HOSTWEP_SHAREDKEY; } else { /* don't know what to do know */ - pr_debug("unknown AUTH_ALG (%d)\n", - param->value); + pr_debug("unknown AUTH_ALG (%d)\n", param->value); result = -EINVAL; } break; @@ -1657,8 +1652,7 @@ static int p80211_wext_get_iwauth(struct net_device *dev, struct iw_param *param = &wrqu->param; int result = 0; - pr_debug("get_iwauth flags[%d]\n", - (int)param->flags & IW_AUTH_INDEX); + pr_debug("get_iwauth flags[%d]\n", (int)param->flags & IW_AUTH_INDEX); switch (param->flags & IW_AUTH_INDEX) { case IW_AUTH_DROP_UNENCRYPTED: @@ -1673,9 +1667,8 @@ static int p80211_wext_get_iwauth(struct net_device *dev, case IW_AUTH_80211_AUTH_ALG: param->value = - wlandev-> - hostwep & HOSTWEP_SHAREDKEY ? IW_AUTH_ALG_SHARED_KEY : - IW_AUTH_ALG_OPEN_SYSTEM; + wlandev->hostwep & HOSTWEP_SHAREDKEY ? + IW_AUTH_ALG_SHARED_KEY : IW_AUTH_ALG_OPEN_SYSTEM; break; default: @@ -1755,7 +1748,7 @@ struct iw_handler_def p80211wext_handler_def = { .get_wireless_stats = p80211wext_get_wireless_stats }; -int p80211wext_event_associated(wlandevice_t *wlandev, int assoc) +int p80211wext_event_associated(wlandevice_t * wlandev, int assoc) { union iwreq_data data; diff --git a/drivers/staging/wlan-ng/prism2fw.c b/drivers/staging/wlan-ng/prism2fw.c new file mode 100644 index 000000000000..608b234b6a44 --- /dev/null +++ b/drivers/staging/wlan-ng/prism2fw.c @@ -0,0 +1,1406 @@ +/* from src/prism2/download/prism2dl.c +* +* utility for downloading prism2 images moved into kernelspace +* +* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. +* -------------------------------------------------------------------- +* +* linux-wlan +* +* The contents of this file are subject to the Mozilla Public +* License Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of +* the License at http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS +* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +* implied. See the License for the specific language governing +* rights and limitations under the License. +* +* Alternatively, the contents of this file may be used under the +* terms of the GNU Public License version 2 (the "GPL"), in which +* case the provisions of the GPL are applicable instead of the +* above. If you wish to allow the use of your version of this file +* only under the terms of the GPL and not to allow others to use +* your version of this file under the MPL, indicate your decision +* by deleting the provisions above and replace them with the notice +* and other provisions required by the GPL. If you do not delete +* the provisions above, a recipient may use your version of this +* file under either the MPL or the GPL. +* +* -------------------------------------------------------------------- +* +* Inquiries regarding the linux-wlan Open Source project can be +* made directly to: +* +* AbsoluteValue Systems Inc. +* info@linux-wlan.com +* http://www.linux-wlan.com +* +* -------------------------------------------------------------------- +* +* Portions of the development of this software were funded by +* Intersil Corporation as part of PRISM(R) chipset product development. +* +* -------------------------------------------------------------------- +*/ + +/*================================================================*/ +/* System Includes */ +#include +#include + +/*================================================================*/ +/* Local Constants */ + +#define PRISM2_USB_FWFILE "prism2_ru.hex" + +#define S3DATA_MAX 5000 +#define S3PLUG_MAX 200 +#define S3CRC_MAX 200 +#define S3INFO_MAX 50 +#define SREC_LINE_MAX 264 +#define S3LEN_TXTOFFSET 2 +#define S3LEN_TXTLEN 2 +#define S3ADDR_TXTOFFSET 4 +#define S3ADDR_TXTLEN 8 +#define S3DATA_TXTOFFSET 12 +/*S3DATA_TXTLEN variable, depends on len field */ +/*S3CKSUM_TXTOFFSET variable, depends on len field */ +#define S3CKSUM_TXTLEN 2 +#define SERNUM_LEN_MAX 12 + +#define S3PLUG_ITEMCODE_TXTOFFSET (S3DATA_TXTOFFSET) +#define S3PLUG_ITEMCODE_TXTLEN 8 +#define S3PLUG_ADDR_TXTOFFSET (S3DATA_TXTOFFSET+8) +#define S3PLUG_ADDR_TXTLEN 8 +#define S3PLUG_LEN_TXTOFFSET (S3DATA_TXTOFFSET+16) +#define S3PLUG_LEN_TXTLEN 8 + +#define S3CRC_ADDR_TXTOFFSET (S3DATA_TXTOFFSET) +#define S3CRC_ADDR_TXTLEN 8 +#define S3CRC_LEN_TXTOFFSET (S3DATA_TXTOFFSET+8) +#define S3CRC_LEN_TXTLEN 8 +#define S3CRC_DOWRITE_TXTOFFSET (S3DATA_TXTOFFSET+16) +#define S3CRC_DOWRITE_TXTLEN 8 + +#define S3INFO_LEN_TXTOFFSET (S3DATA_TXTOFFSET) +#define S3INFO_LEN_TXTLEN 4 +#define S3INFO_TYPE_TXTOFFSET (S3DATA_TXTOFFSET+4) +#define S3INFO_TYPE_TXTLEN 4 +#define S3INFO_DATA_TXTOFFSET (S3DATA_TXTOFFSET+8) +/* S3INFO_DATA_TXTLEN variable, depends on INFO_LEN field */ + +#define S3ADDR_PLUG (0xff000000UL) +#define S3ADDR_CRC (0xff100000UL) +#define S3ADDR_INFO (0xff200000UL) + +#define PDAFILE_LINE_MAX 1024 + +#define CHUNKS_MAX 100 + +#define WRITESIZE_MAX 4096 + +/*================================================================*/ +/* Local Macros */ + +#define bswap_16(x) \ + (__extension__ \ + ({ register unsigned short int __v, __x = (x); \ + __asm__ ("rorw $8, %w0" \ + : "=r" (__v) \ + : "0" (__x) \ + : "cc"); \ + __v; })) + +#define bswap_32(x) \ + (__extension__ \ + ({ register unsigned int __v, __x = (x); \ + __asm__ ("rorw $8, %w0;" \ + "rorl $16, %0;" \ + "rorw $8, %w0" \ + : "=r" (__v) \ + : "0" (__x) \ + : "cc"); \ + __v; })) + +/*================================================================*/ +/* Local Types */ + +typedef struct s3datarec { + u32 len; + u32 addr; + u8 checksum; + u8 *data; +} s3datarec_t; + +typedef struct s3plugrec { + u32 itemcode; + u32 addr; + u32 len; +} s3plugrec_t; + +typedef struct s3crcrec { + u32 addr; + u32 len; + unsigned int dowrite; +} s3crcrec_t; + +typedef struct s3inforec { + u16 len; + u16 type; + union { + hfa384x_compident_t version; + hfa384x_caplevel_t compat; + u16 buildseq; + hfa384x_compident_t platform; + } info; +} s3inforec_t; + +typedef struct pda { + u8 buf[HFA384x_PDA_LEN_MAX]; + hfa384x_pdrec_t *rec[HFA384x_PDA_RECS_MAX]; + unsigned int nrec; +} pda_t; + +typedef struct imgchunk { + u32 addr; /* start address */ + u32 len; /* in bytes */ + u16 crc; /* CRC value (if it falls at a chunk boundary) */ + u8 *data; +} imgchunk_t; + +/*================================================================*/ +/* Local Static Definitions */ + +/*----------------------------------------------------------------*/ +/* s-record image processing */ + +/* Data records */ +unsigned int ns3data = 0; +s3datarec_t s3data[S3DATA_MAX]; + +/* Plug records */ +unsigned int ns3plug = 0; +s3plugrec_t s3plug[S3PLUG_MAX]; + +/* CRC records */ +unsigned int ns3crc = 0; +s3crcrec_t s3crc[S3CRC_MAX]; + +/* Info records */ +unsigned int ns3info = 0; +s3inforec_t s3info[S3INFO_MAX]; + +/* S7 record (there _better_ be only one) */ +u32 startaddr; + +/* Load image chunks */ +unsigned int nfchunks; +imgchunk_t fchunk[CHUNKS_MAX]; + +/* Note that for the following pdrec_t arrays, the len and code */ +/* fields are stored in HOST byte order. The mkpdrlist() function */ +/* does the conversion. */ +/*----------------------------------------------------------------*/ +/* PDA, built from [card|newfile]+[addfile1+addfile2...] */ + +pda_t pda; +hfa384x_compident_t nicid; +hfa384x_caplevel_t rfid; +hfa384x_caplevel_t macid; +hfa384x_caplevel_t priid; + +/*================================================================*/ +/* Local Function Declarations */ + +int prism2_fwapply(char *rfptr, int rfsize, wlandevice_t * wlandev); +int read_srecfile(char *rfptr, int rfsize); +int mkimage(imgchunk_t * clist, unsigned int *ccnt); +int read_cardpda(pda_t * pda, wlandevice_t * wlandev); +int mkpdrlist(pda_t * pda); +int s3datarec_compare(const void *p1, const void *p2); +int plugimage(imgchunk_t * fchunk, unsigned int nfchunks, + s3plugrec_t * s3plug, unsigned int ns3plug, pda_t * pda); +int crcimage(imgchunk_t * fchunk, unsigned int nfchunks, + s3crcrec_t * s3crc, unsigned int ns3crc); +int writeimage(wlandevice_t * wlandev, imgchunk_t * fchunk, + unsigned int nfchunks); +void free_chunks(imgchunk_t * fchunk, unsigned int *nfchunks); +void free_srecs(void); + +int validate_identity(void); + +/*================================================================*/ +/* Function Definitions */ + +/*---------------------------------------------------------------- +* prism2_fwtry +* +* Try and get firmware into memory +* +* Arguments: +* udev usb device structure +* wlandev wlan device structure +* +* Returns: +* 0 - success +* ~0 - failure +----------------------------------------------------------------*/ +int prism2_fwtry(struct usb_device *udev, wlandevice_t * wlandev) +{ + const struct firmware *fw_entry = NULL; + + printk(KERN_INFO "prism2_usb: Checking for firmware %s\n", + PRISM2_USB_FWFILE); + if (request_firmware(&fw_entry, PRISM2_USB_FWFILE, &udev->dev) != 0) { + printk(KERN_INFO + "prism2_usb: Firmware not available, but not essential\n"); + printk(KERN_INFO + "prism2_usb: can continue to use card anyway.\n"); + return 1; + } + + printk(KERN_INFO "prism2_usb: %s will be processed, size %d\n", + PRISM2_USB_FWFILE, fw_entry->size); + prism2_fwapply((char *)fw_entry->data, fw_entry->size, wlandev); + + release_firmware(fw_entry); + return 0; +} + +/*---------------------------------------------------------------- +* prism2_fwapply +* +* Apply the firmware loaded into memory +* +* Arguments: +* rfptr firmware image in kernel memory +* rfsize firmware size in kernel memory +* wlandev device +* +* Returns: +* 0 - success +* ~0 - failure +----------------------------------------------------------------*/ +int prism2_fwapply(char *rfptr, int rfsize, wlandevice_t * wlandev) +{ + signed int result = 0; + p80211msg_dot11req_mibget_t getmsg; + p80211itemd_t *item; + u32 *data; + + /* Initialize the data structures */ + ns3data = 0; + memset(s3data, 0, sizeof(s3data)); + ns3plug = 0; + memset(s3plug, 0, sizeof(s3plug)); + ns3crc = 0; + memset(s3crc, 0, sizeof(s3crc)); + ns3info = 0; + memset(s3info, 0, sizeof(s3info)); + startaddr = 0; + + nfchunks = 0; + memset(fchunk, 0, sizeof(fchunk)); + memset(&nicid, 0, sizeof(nicid)); + memset(&rfid, 0, sizeof(rfid)); + memset(&macid, 0, sizeof(macid)); + memset(&priid, 0, sizeof(priid)); + + /* clear the pda and add an initial END record */ + memset(&pda, 0, sizeof(pda)); + pda.rec[0] = (hfa384x_pdrec_t *) pda.buf; + pda.rec[0]->len = cpu_to_le16(2); /* len in words *//* len in words */ + pda.rec[0]->code = cpu_to_le16(HFA384x_PDR_END_OF_PDA); + pda.nrec = 1; + + /*-----------------------------------------------------*/ + /* Put card into fwload state */ + prism2sta_ifstate(wlandev, P80211ENUM_ifstate_fwload); + + /* Build the PDA we're going to use. */ + if (read_cardpda(&pda, wlandev)) { + printk(KERN_ERR "load_cardpda failed, exiting.\n"); + return (1); + } + + /* read the card's PRI-SUP */ + memset(&getmsg, 0, sizeof(getmsg)); + getmsg.msgcode = DIDmsg_dot11req_mibget; + getmsg.msglen = sizeof(getmsg); + strcpy(getmsg.devname, wlandev->name); + + getmsg.mibattribute.did = DIDmsg_dot11req_mibget_mibattribute; + getmsg.mibattribute.status = P80211ENUM_msgitem_status_data_ok; + getmsg.resultcode.did = DIDmsg_dot11req_mibget_resultcode; + getmsg.resultcode.status = P80211ENUM_msgitem_status_no_value; + + item = (p80211itemd_t *) getmsg.mibattribute.data; + item->did = DIDmib_p2_p2NIC_p2PRISupRange; + item->status = P80211ENUM_msgitem_status_no_value; + + data = (u32 *) item->data; + + /* DIDmsg_dot11req_mibget */ + prism2mgmt_mibset_mibget(wlandev, &getmsg); + if (getmsg.resultcode.data != P80211ENUM_resultcode_success) { + printk(KERN_ERR "Couldn't fetch PRI-SUP info\n"); + } + + /* Already in host order */ + priid.role = *data++; + priid.id = *data++; + priid.variant = *data++; + priid.bottom = *data++; + priid.top = *data++; + + /* Read the S3 file */ + result = read_srecfile(rfptr, rfsize); + if (result) { + printk(KERN_ERR "Failed to read the data exiting.\n"); + return (1); + } + /* Sort the S3 data records */ + sort(s3data, ns3data, sizeof(s3datarec_t), s3datarec_compare, NULL); + + result = validate_identity(); + + if (result) { + printk(KERN_ERR "Incompatible firmware image.\n"); + return (1); + } + + if (startaddr == 0x00000000) { + printk(KERN_ERR "Can't RAM download a Flash image!\n"); + return (1); + } + + /* Make the image chunks */ + result = mkimage(fchunk, &nfchunks); + + /* Do any plugging */ + result = plugimage(fchunk, nfchunks, s3plug, ns3plug, &pda); + if (result) { + printk(KERN_ERR "Failed to plug data.\n"); + return (1); + } + + /* Insert any CRCs */ + if (crcimage(fchunk, nfchunks, s3crc, ns3crc)) { + printk(KERN_ERR "Failed to insert all CRCs\n"); + return (1); + } + + /* Write the image */ + result = writeimage(wlandev, fchunk, nfchunks); + if (result) { + printk(KERN_ERR "Failed to ramwrite image data.\n"); + return (1); + } + + /* clear any allocated memory */ + free_chunks(fchunk, &nfchunks); + free_srecs(); + + printk(KERN_INFO "prism2_usb: firmware loading finished.\n"); + + return result; +} + +/*---------------------------------------------------------------- +* crcimage +* +* Adds a CRC16 in the two bytes prior to each block identified by +* an S3 CRC record. Currently, we don't actually do a CRC we just +* insert the value 0xC0DE in hfa384x order. +* +* Arguments: +* fchunk Array of image chunks +* nfchunks Number of image chunks +* s3crc Array of crc records +* ns3crc Number of crc records +* +* Returns: +* 0 success +* ~0 failure +----------------------------------------------------------------*/ +int crcimage(imgchunk_t * fchunk, unsigned int nfchunks, s3crcrec_t * s3crc, + unsigned int ns3crc) +{ + int result = 0; + int i; + int c; + u32 crcstart; + u32 crcend; + u32 cstart = 0; + u32 cend; + u8 *dest; + u32 chunkoff; + + for (i = 0; i < ns3crc; i++) { + if (!s3crc[i].dowrite) + continue; + crcstart = s3crc[i].addr; + crcend = s3crc[i].addr + s3crc[i].len; + /* Find chunk */ + for (c = 0; c < nfchunks; c++) { + cstart = fchunk[c].addr; + cend = fchunk[c].addr + fchunk[c].len; + /* the line below does an address & len match search */ + /* unfortunately, I've found that the len fields of */ + /* some crc records don't match with the length of */ + /* the actual data, so we're not checking right */ + /* now */ + /* if ( crcstart-2 >= cstart && crcend <= cend ) break; */ + + /* note the -2 below, it's to make sure the chunk has */ + /* space for the CRC value */ + if (crcstart - 2 >= cstart && crcstart < cend) + break; + } + if (c >= nfchunks) { + printk(KERN_ERR + "Failed to find chunk for " + "crcrec[%d], addr=0x%06x len=%d , " + "aborting crc.\n", + i, s3crc[i].addr, s3crc[i].len); + return 1; + } + + /* Insert crc */ + pr_debug("Adding crc @ 0x%06x\n", s3crc[i].addr - 2); + chunkoff = crcstart - cstart - 2; + dest = fchunk[c].data + chunkoff; + *dest = 0xde; + *(dest + 1) = 0xc0; + + } + return result; +} + +/*---------------------------------------------------------------- +* free_chunks +* +* Clears the chunklist data structures in preparation for a new file. +* +* Arguments: +* none +* +* Returns: +* nothing +----------------------------------------------------------------*/ +void free_chunks(imgchunk_t * fchunk, unsigned int *nfchunks) +{ + int i; + for (i = 0; i < *nfchunks; i++) { + if (fchunk[i].data != NULL) { + kfree(fchunk[i].data); + } + } + *nfchunks = 0; + memset(fchunk, 0, sizeof(fchunk)); + +} + +/*---------------------------------------------------------------- +* free_srecs +* +* Clears the srec data structures in preparation for a new file. +* +* Arguments: +* none +* +* Returns: +* nothing +----------------------------------------------------------------*/ +void free_srecs(void) +{ + int i; + for (i = 0; i < ns3data; i++) { + kfree(s3data[i].data); + } + ns3data = 0; + memset(s3data, 0, sizeof(s3data)); + ns3plug = 0; + memset(s3plug, 0, sizeof(s3plug)); + ns3crc = 0; + memset(s3crc, 0, sizeof(s3crc)); + ns3info = 0; + memset(s3info, 0, sizeof(s3info)); + startaddr = 0; +} + +/*---------------------------------------------------------------- +* mkimage +* +* Scans the currently loaded set of S records for data residing +* in contiguous memory regions. Each contiguous region is then +* made into a 'chunk'. This function assumes that we're building +* a new chunk list. Assumes the s3data items are in sorted order. +* +* Arguments: none +* +* Returns: +* 0 - success +* ~0 - failure (probably an errno) +----------------------------------------------------------------*/ +int mkimage(imgchunk_t * clist, unsigned int *ccnt) +{ + int result = 0; + int i; + int j; + int currchunk = 0; + u32 nextaddr = 0; + u32 s3start; + u32 s3end; + u32 cstart = 0; + u32 cend; + u32 coffset; + + /* There may already be data in the chunklist */ + *ccnt = 0; + + /* Establish the location and size of each chunk */ + for (i = 0; i < ns3data; i++) { + if (s3data[i].addr == nextaddr) { + /* existing chunk, grow it */ + clist[currchunk].len += s3data[i].len; + nextaddr += s3data[i].len; + } else { + /* New chunk */ + (*ccnt)++; + currchunk = *ccnt - 1; + clist[currchunk].addr = s3data[i].addr; + clist[currchunk].len = s3data[i].len; + nextaddr = s3data[i].addr + s3data[i].len; + /* Expand the chunk if there is a CRC record at */ + /* their beginning bound */ + for (j = 0; j < ns3crc; j++) { + if (s3crc[j].dowrite && + s3crc[j].addr == clist[currchunk].addr) { + clist[currchunk].addr -= 2; + clist[currchunk].len += 2; + } + } + } + } + + /* We're currently assuming there aren't any overlapping chunks */ + /* if this proves false, we'll need to add code to coalesce. */ + + /* Allocate buffer space for chunks */ + for (i = 0; i < *ccnt; i++) { + clist[i].data = kmalloc(clist[i].len, GFP_KERNEL); + if (clist[i].data == NULL) { + printk(KERN_ERR + "failed to allocate image space, exitting.\n"); + return (1); + } + memset(clist[i].data, 0, clist[i].len); + } + + /* Display chunks */ + for (i = 0; i < *ccnt; i++) { + pr_debug("chunk[%d]: addr=0x%06x len=%d\n", + i, clist[i].addr, clist[i].len); + } + + /* Copy srec data to chunks */ + for (i = 0; i < ns3data; i++) { + s3start = s3data[i].addr; + s3end = s3start + s3data[i].len - 1; + for (j = 0; j < *ccnt; j++) { + cstart = clist[j].addr; + cend = cstart + clist[j].len - 1; + if (s3start >= cstart && s3end <= cend) { + break; + } + } + if (((unsigned int)j) >= (*ccnt)) { + printk(KERN_ERR + "s3rec(a=0x%06x,l=%d), no chunk match, exiting.\n", + s3start, s3data[i].len); + return (1); + } + coffset = s3start - cstart; + memcpy(clist[j].data + coffset, s3data[i].data, s3data[i].len); + } + + return result; +} + +/*---------------------------------------------------------------- +* mkpdrlist +* +* Reads a raw PDA and builds an array of pdrec_t structures. +* +* Arguments: +* pda buffer containing raw PDA bytes +* pdrec ptr to an array of pdrec_t's. Will be filled on exit. +* nrec ptr to a variable that will contain the count of PDRs +* +* Returns: +* 0 - success +* ~0 - failure (probably an errno) +----------------------------------------------------------------*/ +int mkpdrlist(pda_t * pda) +{ + int result = 0; + u16 *pda16 = (u16 *) pda->buf; + int curroff; /* in 'words' */ + + pda->nrec = 0; + curroff = 0; + while (curroff < (HFA384x_PDA_LEN_MAX / 2) && + le16_to_cpu(pda16[curroff + 1]) != HFA384x_PDR_END_OF_PDA) { + pda->rec[pda->nrec] = (hfa384x_pdrec_t *) & (pda16[curroff]); + + if (le16_to_cpu(pda->rec[pda->nrec]->code) == HFA384x_PDR_NICID) { + memcpy(&nicid, &pda->rec[pda->nrec]->data.nicid, + sizeof(nicid)); + nicid.id = le16_to_cpu(nicid.id); + nicid.variant = le16_to_cpu(nicid.variant); + nicid.major = le16_to_cpu(nicid.major); + nicid.minor = le16_to_cpu(nicid.minor); + } + if (le16_to_cpu(pda->rec[pda->nrec]->code) == + HFA384x_PDR_MFISUPRANGE) { + memcpy(&rfid, &pda->rec[pda->nrec]->data.mfisuprange, + sizeof(rfid)); + rfid.id = le16_to_cpu(rfid.id); + rfid.variant = le16_to_cpu(rfid.variant); + rfid.bottom = le16_to_cpu(rfid.bottom); + rfid.top = le16_to_cpu(rfid.top); + } + if (le16_to_cpu(pda->rec[pda->nrec]->code) == + HFA384x_PDR_CFISUPRANGE) { + memcpy(&macid, &pda->rec[pda->nrec]->data.cfisuprange, + sizeof(macid)); + macid.id = le16_to_cpu(macid.id); + macid.variant = le16_to_cpu(macid.variant); + macid.bottom = le16_to_cpu(macid.bottom); + macid.top = le16_to_cpu(macid.top); + } + + (pda->nrec)++; + curroff += le16_to_cpu(pda16[curroff]) + 1; + + } + if (curroff >= (HFA384x_PDA_LEN_MAX / 2)) { + printk(KERN_ERR + "no end record found or invalid lengths in " + "PDR data, exiting. %x %d\n", curroff, pda->nrec); + return (1); + } + if (le16_to_cpu(pda16[curroff + 1]) == HFA384x_PDR_END_OF_PDA) { + pda->rec[pda->nrec] = (hfa384x_pdrec_t *) & (pda16[curroff]); + (pda->nrec)++; + } + return result; +} + +/*---------------------------------------------------------------- +* plugimage +* +* Plugs the given image using the given plug records from the given +* PDA and filename. +* +* Arguments: +* fchunk Array of image chunks +* nfchunks Number of image chunks +* s3plug Array of plug records +* ns3plug Number of plug records +* pda Current pda data +* +* Returns: +* 0 success +* ~0 failure +----------------------------------------------------------------*/ +int plugimage(imgchunk_t * fchunk, unsigned int nfchunks, + s3plugrec_t * s3plug, unsigned int ns3plug, pda_t * pda) +{ + int result = 0; + int i; /* plug index */ + int j; /* index of PDR or -1 if fname plug */ + int c; /* chunk index */ + u32 pstart; + u32 pend; + u32 cstart = 0; + u32 cend; + u32 chunkoff; + u8 *dest; + + /* for each plug record */ + for (i = 0; i < ns3plug; i++) { + pstart = s3plug[i].addr; + pend = s3plug[i].addr + s3plug[i].len; + /* find the matching PDR (or filename) */ + if (s3plug[i].itemcode != 0xffffffffUL) { /* not filename */ + for (j = 0; j < pda->nrec; j++) { + if (s3plug[i].itemcode == + le16_to_cpu(pda->rec[j]->code)) + break; + } + } else { + j = -1; + } + if (j >= pda->nrec && j != -1) { /* if no matching PDR, fail */ + printk(KERN_WARNING + "warning: Failed to find PDR for " + "plugrec 0x%04x.\n", s3plug[i].itemcode); + continue; /* and move on to the next PDR */ +#if 0 + /* MSM: They swear that unless it's the MAC address, + * the serial number, or the TX calibration records, + * then there's reasonable defaults in the f/w + * image. Therefore, missing PDRs in the card + * should only be a warning, not fatal. + * TODO: add fatals for the PDRs mentioned above. + */ + result = 1; + continue; +#endif + } + + /* Validate plug len against PDR len */ + if (j != -1 && s3plug[i].len < le16_to_cpu(pda->rec[j]->len)) { + printk(KERN_ERR + "error: Plug vs. PDR len mismatch for " + "plugrec 0x%04x, abort plugging.\n", + s3plug[i].itemcode); + result = 1; + continue; + } + + /* Validate plug address against chunk data and identify chunk */ + for (c = 0; c < nfchunks; c++) { + cstart = fchunk[c].addr; + cend = fchunk[c].addr + fchunk[c].len; + if (pstart >= cstart && pend <= cend) + break; + } + if (c >= nfchunks) { + printk(KERN_ERR + "error: Failed to find image chunk for " + "plugrec 0x%04x.\n", s3plug[i].itemcode); + result = 1; + continue; + } + + /* Plug data */ + chunkoff = pstart - cstart; + dest = fchunk[c].data + chunkoff; + pr_debug("Plugging item 0x%04x @ 0x%06x, len=%d, " + "cnum=%d coff=0x%06x\n", + s3plug[i].itemcode, pstart, s3plug[i].len, + c, chunkoff); + + if (j == -1) { /* plug the filename */ + memset(dest, 0, s3plug[i].len); + strncpy(dest, PRISM2_USB_FWFILE, s3plug[i].len - 1); + } else { /* plug a PDR */ + memcpy(dest, &(pda->rec[j]->data), s3plug[i].len); + } + } + return result; + +} + +/*---------------------------------------------------------------- +* read_cardpda +* +* Sends the command for the driver to read the pda from the card +* named in the device variable. Upon success, the card pda is +* stored in the "cardpda" variables. Note that the pda structure +* is considered 'well formed' after this function. That means +* that the nrecs is valid, the rec array has been set up, and there's +* a valid PDAEND record in the raw PDA data. +* +* Arguments: +* pda pda structure +* wlandev device +* +* Returns: +* 0 - success +* ~0 - failure (probably an errno) +----------------------------------------------------------------*/ +int read_cardpda(pda_t * pda, wlandevice_t * wlandev) +{ + int result = 0; + p80211msg_p2req_readpda_t msg; + + /* set up the msg */ + msg.msgcode = DIDmsg_p2req_readpda; + msg.msglen = sizeof(msg); + strcpy(msg.devname, wlandev->name); + msg.pda.did = DIDmsg_p2req_readpda_pda; + msg.pda.len = HFA384x_PDA_LEN_MAX; + msg.pda.status = P80211ENUM_msgitem_status_no_value; + msg.resultcode.did = DIDmsg_p2req_readpda_resultcode; + msg.resultcode.len = sizeof(u32); + msg.resultcode.status = P80211ENUM_msgitem_status_no_value; + + if (prism2mgmt_readpda(wlandev, &msg) != 0) { + /* prism2mgmt_readpda prints an errno if appropriate */ + result = -1; + } else if (msg.resultcode.data == P80211ENUM_resultcode_success) { + memcpy(pda->buf, msg.pda.data, HFA384x_PDA_LEN_MAX); + result = mkpdrlist(pda); + } else { + /* resultcode must've been something other than success */ + result = -1; + } + + return result; +} + +/*---------------------------------------------------------------- +* copy_line +* +* Copies a line of text, up to \n, \0, or SREC_LINE_MAX, or limit of +* From array +* +* Arguments: +* from From addr +* to To addr +* limit Addr of last character in From array that can be copied +* +* Returns: +* Num characters copied +----------------------------------------------------------------*/ +int copyline(char *from, char *to, char *limit) +{ + int c = 0; + + while ((c < SREC_LINE_MAX - 1) && (from + c <= limit) && + (from[c] != '\n') && (from[c] != '\0')) { + to[c] = from[c]; + c++; + } + + to[c] = '\0'; + return (c < SREC_LINE_MAX - 1) ? c + 1 : c; +} + +/*---------------------------------------------------------------- +* read_srecfile +* +* Reads the given srecord file and loads the records into the +* s3xxx arrays. This function can be called repeatedly (once for +* each of a set of files), if necessary. This function performs +* no validation of the data except for the grossest of S-record +* line format checks. Don't forget that these will be DOS files... +* CR/LF at the end of each line. +* +* Here's the SREC format we're dealing with: +* S[37]nnaaaaaaaaddd...dddcc +* +* nn - number of bytes starting with the address field +* aaaaaaaa - address in readable (or big endian) format +* dd....dd - 0-245 data bytes (two chars per byte) +* cc - checksum +* +* The S7 record's (there should be only one) address value gets +* saved in startaddr. It's the start execution address used +* for RAM downloads. +* +* The S3 records have a collection of subformats indicated by the +* value of aaaaaaaa: +* 0xff000000 - Plug record, data field format: +* xxxxxxxxaaaaaaaassssssss +* x - PDR code number (little endian) +* a - Address in load image to plug (little endian) +* s - Length of plug data area (little endian) +* +* 0xff100000 - CRC16 generation record, data field format: +* aaaaaaaassssssssbbbbbbbb +* a - Start address for CRC calculation (little endian) +* s - Length of data to calculate over (little endian) +* b - Boolean, true=write crc, false=don't write +* +* 0xff200000 - Info record, data field format: +* ssssttttdd..dd +* s - Size in words (little endian) +* t - Info type (little endian), see #defines and +* s3inforec_t for details about types. +* d - (s - 1) little endian words giving the contents of +* the given info type. +* +* Arguments: +* rfptr firmware image (s-record structure) in kernel memory +* rfsize firmware size in kernel memory +* +* Returns: +* 0 - success +* ~0 - failure (probably an errno) +----------------------------------------------------------------*/ +int read_srecfile(char *rfptr, int rfsize) +{ + int result = 0; + char buf[SREC_LINE_MAX]; + char tmpbuf[30]; + s3datarec_t tmprec; + int i, c; + int line = 0; + u16 *tmpinfo; + char *endptr = rfptr + rfsize; + + pr_debug("Reading S-record file ...\n"); + + while ((c = copyline(rfptr, buf, endptr)) >= 12) { + rfptr = rfptr + c; + line++; + if (buf[0] != 'S') { + printk(KERN_ERR "%d warning: No initial \'S\'\n", line); + return 1; + } + if (buf[1] == '7') { /* S7 record, start address */ + buf[12] = '\0'; + startaddr = simple_strtoul(buf + 4, NULL, 16); + pr_debug(" S7 start addr, line=%d " + " addr=0x%08x\n", line, startaddr); + continue; + } else if (buf[1] == '3') { + /* Ok, it's an S3, parse and put it in the right array */ + /* Record Length field (we only want datalen) */ + memcpy(tmpbuf, buf + S3LEN_TXTOFFSET, S3LEN_TXTLEN); + tmpbuf[S3LEN_TXTLEN] = '\0'; + tmprec.len = simple_strtoul(tmpbuf, NULL, 16) - 4 - 1; /* 4=addr, 1=cksum */ + /* Address field */ + memcpy(tmpbuf, buf + S3ADDR_TXTOFFSET, S3ADDR_TXTLEN); + tmpbuf[S3ADDR_TXTLEN] = '\0'; + tmprec.addr = simple_strtoul(tmpbuf, NULL, 16); + /* Checksum field */ + tmprec.checksum = + simple_strtoul(buf + strlen(buf) - 2, NULL, 16); + + switch (tmprec.addr) { + case S3ADDR_PLUG: + memcpy(tmpbuf, buf + S3PLUG_ITEMCODE_TXTOFFSET, + S3PLUG_ITEMCODE_TXTLEN); + tmpbuf[S3PLUG_ITEMCODE_TXTLEN] = '\0'; + s3plug[ns3plug].itemcode = + simple_strtoul(tmpbuf, NULL, 16); + s3plug[ns3plug].itemcode = + bswap_32(s3plug[ns3plug].itemcode); + + memcpy(tmpbuf, buf + S3PLUG_ADDR_TXTOFFSET, + S3PLUG_ADDR_TXTLEN); + tmpbuf[S3PLUG_ADDR_TXTLEN] = '\0'; + s3plug[ns3plug].addr = + simple_strtoul(tmpbuf, NULL, 16); + s3plug[ns3plug].addr = + bswap_32(s3plug[ns3plug].addr); + + memcpy(tmpbuf, buf + S3PLUG_LEN_TXTOFFSET, + S3PLUG_LEN_TXTLEN); + tmpbuf[S3PLUG_LEN_TXTLEN] = '\0'; + s3plug[ns3plug].len = + simple_strtoul(tmpbuf, NULL, 16); + s3plug[ns3plug].len = + bswap_32(s3plug[ns3plug].len); + + pr_debug(" S3 plugrec, line=%d " + "itemcode=0x%04x addr=0x%08x len=%d\n", + line, + s3plug[ns3plug].itemcode, + s3plug[ns3plug].addr, + s3plug[ns3plug].len); + + ns3plug++; + if (ns3plug == S3PLUG_MAX) { + printk(KERN_ERR + "S3 plugrec limit reached - aborting\n"); + return 1; + } + break; + case S3ADDR_CRC: + memcpy(tmpbuf, buf + S3CRC_ADDR_TXTOFFSET, + S3CRC_ADDR_TXTLEN); + tmpbuf[S3CRC_ADDR_TXTLEN] = '\0'; + s3crc[ns3crc].addr = + simple_strtoul(tmpbuf, NULL, 16); + s3crc[ns3crc].addr = + bswap_32(s3crc[ns3crc].addr); + + memcpy(tmpbuf, buf + S3CRC_LEN_TXTOFFSET, + S3CRC_LEN_TXTLEN); + tmpbuf[S3CRC_LEN_TXTLEN] = '\0'; + s3crc[ns3crc].len = + simple_strtoul(tmpbuf, NULL, 16); + s3crc[ns3crc].len = bswap_32(s3crc[ns3crc].len); + + memcpy(tmpbuf, buf + S3CRC_DOWRITE_TXTOFFSET, + S3CRC_DOWRITE_TXTLEN); + tmpbuf[S3CRC_DOWRITE_TXTLEN] = '\0'; + s3crc[ns3crc].dowrite = + simple_strtoul(tmpbuf, NULL, 16); + s3crc[ns3crc].dowrite = + bswap_32(s3crc[ns3crc].dowrite); + + pr_debug(" S3 crcrec, line=%d " + "addr=0x%08x len=%d write=0x%08x\n", + line, + s3crc[ns3crc].addr, + s3crc[ns3crc].len, + s3crc[ns3crc].dowrite); + ns3crc++; + if (ns3crc == S3CRC_MAX) { + printk(KERN_ERR + "S3 crcrec limit reached - aborting\n"); + return 1; + } + break; + case S3ADDR_INFO: + memcpy(tmpbuf, buf + S3INFO_LEN_TXTOFFSET, + S3INFO_LEN_TXTLEN); + tmpbuf[S3INFO_LEN_TXTLEN] = '\0'; + s3info[ns3info].len = + simple_strtoul(tmpbuf, NULL, 16); + s3info[ns3info].len = + bswap_16(s3info[ns3info].len); + + memcpy(tmpbuf, buf + S3INFO_TYPE_TXTOFFSET, + S3INFO_TYPE_TXTLEN); + tmpbuf[S3INFO_TYPE_TXTLEN] = '\0'; + s3info[ns3info].type = + simple_strtoul(tmpbuf, NULL, 16); + s3info[ns3info].type = + bswap_16(s3info[ns3info].type); + + pr_debug(" S3 inforec, line=%d " + "len=0x%04x type=0x%04x\n", + line, + s3info[ns3info].len, + s3info[ns3info].type); + if (((s3info[ns3info].len - 1) * sizeof(u16)) > + sizeof(s3info[ns3info].info)) { + printk(KERN_ERR + " S3 inforec length too long - aborting\n"); + return 1; + } + + tmpinfo = + (u16 *) & (s3info[ns3info].info.version); + for (i = 0; i < s3info[ns3info].len - 1; i++) { + memcpy(tmpbuf, + buf + S3INFO_DATA_TXTOFFSET + + (i * 4), 4); + tmpbuf[4] = '\0'; + tmpinfo[i] = + simple_strtoul(tmpbuf, NULL, 16); + tmpinfo[i] = bswap_16(tmpinfo[i]); + } + pr_debug(" info="); + for (i = 0; i < s3info[ns3info].len - 1; i++) { + pr_debug("%04x ", tmpinfo[i]); + } + pr_debug("\n"); + + ns3info++; + if (ns3info == S3INFO_MAX) { + printk(KERN_ERR + "S3 inforec limit reached - aborting\n"); + return 1; + } + break; + default: /* Data record */ + s3data[ns3data].addr = tmprec.addr; + s3data[ns3data].len = tmprec.len; + s3data[ns3data].checksum = tmprec.checksum; + s3data[ns3data].data = + kmalloc(tmprec.len, GFP_KERNEL); + for (i = 0; i < tmprec.len; i++) { + memcpy(tmpbuf, + buf + S3DATA_TXTOFFSET + (i * 2), + 2); + tmpbuf[2] = '\0'; + s3data[ns3data].data[i] = + simple_strtoul(tmpbuf, NULL, 16); + } + ns3data++; + if (ns3data == S3DATA_MAX) { + printk(KERN_ERR + "S3 datarec limit reached - aborting\n"); + return 1; + } + break; + } + } else { + printk(KERN_WARNING + "%d warning: Unknown S-record detected.\n", + line); + } + } + return result; +} + +/*---------------------------------------------------------------- +* s3datarec_compare +* +* Comparison function for sort(). +* +* Arguments: +* p1 ptr to the first item +* p2 ptr to the second item +* Returns: +* 0 items are equal +* <0 p1 < p2 +* >0 p1 > p2 +----------------------------------------------------------------*/ +int s3datarec_compare(const void *p1, const void *p2) +{ + const s3datarec_t *s1 = p1; + const s3datarec_t *s2 = p2; + if (s1->addr == s2->addr) + return 0; + if (s1->addr < s2->addr) + return -1; + return 1; +} + +/*---------------------------------------------------------------- +* writeimage +* +* Takes the chunks, builds p80211 messages and sends them down +* to the driver for writing to the card. +* +* Arguments: +* wlandev device +* fchunk Array of image chunks +* nfchunks Number of image chunks +* +* Returns: +* 0 success +* ~0 failure +----------------------------------------------------------------*/ +int writeimage(wlandevice_t * wlandev, imgchunk_t * fchunk, + unsigned int nfchunks) +{ + int result = 0; + p80211msg_p2req_ramdl_state_t rstatemsg; + p80211msg_p2req_ramdl_write_t rwritemsg; + p80211msg_t *msgp; + u32 resultcode; + int i; + int j; + unsigned int nwrites; + u32 curroff; + u32 currlen; + u32 currdaddr; + + /* Initialize the messages */ + memset(&rstatemsg, 0, sizeof(rstatemsg)); + strcpy(rstatemsg.devname, wlandev->name); + rstatemsg.msgcode = DIDmsg_p2req_ramdl_state; + rstatemsg.msglen = sizeof(rstatemsg); + rstatemsg.enable.did = DIDmsg_p2req_ramdl_state_enable; + rstatemsg.exeaddr.did = DIDmsg_p2req_ramdl_state_exeaddr; + rstatemsg.resultcode.did = DIDmsg_p2req_ramdl_state_resultcode; + rstatemsg.enable.status = P80211ENUM_msgitem_status_data_ok; + rstatemsg.exeaddr.status = P80211ENUM_msgitem_status_data_ok; + rstatemsg.resultcode.status = P80211ENUM_msgitem_status_no_value; + rstatemsg.enable.len = sizeof(u32); + rstatemsg.exeaddr.len = sizeof(u32); + rstatemsg.resultcode.len = sizeof(u32); + + memset(&rwritemsg, 0, sizeof(rwritemsg)); + strcpy(rwritemsg.devname, wlandev->name); + rwritemsg.msgcode = DIDmsg_p2req_ramdl_write; + rwritemsg.msglen = sizeof(rwritemsg); + rwritemsg.addr.did = DIDmsg_p2req_ramdl_write_addr; + rwritemsg.len.did = DIDmsg_p2req_ramdl_write_len; + rwritemsg.data.did = DIDmsg_p2req_ramdl_write_data; + rwritemsg.resultcode.did = DIDmsg_p2req_ramdl_write_resultcode; + rwritemsg.addr.status = P80211ENUM_msgitem_status_data_ok; + rwritemsg.len.status = P80211ENUM_msgitem_status_data_ok; + rwritemsg.data.status = P80211ENUM_msgitem_status_data_ok; + rwritemsg.resultcode.status = P80211ENUM_msgitem_status_no_value; + rwritemsg.addr.len = sizeof(u32); + rwritemsg.len.len = sizeof(u32); + rwritemsg.data.len = WRITESIZE_MAX; + rwritemsg.resultcode.len = sizeof(u32); + + /* Send xxx_state(enable) */ + pr_debug("Sending dl_state(enable) message.\n"); + rstatemsg.enable.data = P80211ENUM_truth_true; + rstatemsg.exeaddr.data = startaddr; + + msgp = (p80211msg_t *) & rstatemsg; + result = prism2mgmt_ramdl_state(wlandev, msgp); + if (result) { + printk(KERN_ERR + "writeimage state enable failed w/ result=%d, " + "aborting download\n", result); + return result; + } + resultcode = rstatemsg.resultcode.data; + if (resultcode != P80211ENUM_resultcode_success) { + printk(KERN_ERR + "writeimage()->xxxdl_state msg indicates failure, " + "w/ resultcode=%d, aborting download.\n", resultcode); + return 1; + } + + /* Now, loop through the data chunks and send WRITESIZE_MAX data */ + for (i = 0; i < nfchunks; i++) { + nwrites = fchunk[i].len / WRITESIZE_MAX; + nwrites += (fchunk[i].len % WRITESIZE_MAX) ? 1 : 0; + curroff = 0; + for (j = 0; j < nwrites; j++) { + currlen = + (fchunk[i].len - (WRITESIZE_MAX * j)) > + WRITESIZE_MAX ? WRITESIZE_MAX : (fchunk[i].len - + (WRITESIZE_MAX * + j)); + curroff = j * WRITESIZE_MAX; + currdaddr = fchunk[i].addr + curroff; + /* Setup the message */ + rwritemsg.addr.data = currdaddr; + rwritemsg.len.data = currlen; + memcpy(rwritemsg.data.data, + fchunk[i].data + curroff, currlen); + + /* Send flashdl_write(pda) */ + pr_debug + ("Sending xxxdl_write message addr=%06x len=%d.\n", + currdaddr, currlen); + + msgp = (p80211msg_t *) & rwritemsg; + result = prism2mgmt_ramdl_write(wlandev, msgp); + + /* Check the results */ + if (result) { + printk(KERN_ERR + "writeimage chunk write failed w/ result=%d, " + "aborting download\n", result); + return result; + } + resultcode = rstatemsg.resultcode.data; + if (resultcode != P80211ENUM_resultcode_success) { + printk(KERN_ERR + "writeimage()->xxxdl_write msg indicates failure, " + "w/ resultcode=%d, aborting download.\n", + resultcode); + return 1; + } + + } + } + + /* Send xxx_state(disable) */ + pr_debug("Sending dl_state(disable) message.\n"); + rstatemsg.enable.data = P80211ENUM_truth_false; + rstatemsg.exeaddr.data = 0; + + msgp = (p80211msg_t *) & rstatemsg; + result = prism2mgmt_ramdl_state(wlandev, msgp); + if (result) { + printk(KERN_ERR + "writeimage state disable failed w/ result=%d, " + "aborting download\n", result); + return result; + } + resultcode = rstatemsg.resultcode.data; + if (resultcode != P80211ENUM_resultcode_success) { + printk(KERN_ERR + "writeimage()->xxxdl_state msg indicates failure, " + "w/ resultcode=%d, aborting download.\n", resultcode); + return 1; + } + return result; +} + +int validate_identity(void) +{ + int i; + int result = 1; + + pr_debug("NIC ID: %#x v%d.%d.%d\n", + nicid.id, nicid.major, nicid.minor, nicid.variant); + pr_debug("MFI ID: %#x v%d %d->%d\n", + rfid.id, rfid.variant, rfid.bottom, rfid.top); + pr_debug("CFI ID: %#x v%d %d->%d\n", + macid.id, macid.variant, macid.bottom, macid.top); + pr_debug("PRI ID: %#x v%d %d->%d\n", + priid.id, priid.variant, priid.bottom, priid.top); + + for (i = 0; i < ns3info; i++) { + switch (s3info[i].type) { + case 1: + pr_debug("Version: ID %#x %d.%d.%d\n", + s3info[i].info.version.id, + s3info[i].info.version.major, + s3info[i].info.version.minor, + s3info[i].info.version.variant); + break; + case 2: + pr_debug("Compat: Role %#x Id %#x v%d %d->%d\n", + s3info[i].info.compat.role, + s3info[i].info.compat.id, + s3info[i].info.compat.variant, + s3info[i].info.compat.bottom, + s3info[i].info.compat.top); + + /* MAC compat range */ + if ((s3info[i].info.compat.role == 1) && + (s3info[i].info.compat.id == 2)) { + if (s3info[i].info.compat.variant != + macid.variant) { + result = 2; + } + } + + /* PRI compat range */ + if ((s3info[i].info.compat.role == 1) && + (s3info[i].info.compat.id == 3)) { + if ((s3info[i].info.compat.bottom > priid.top) + || (s3info[i].info.compat.top < + priid.bottom)) { + result = 3; + } + } + /* SEC compat range */ + if ((s3info[i].info.compat.role == 1) && + (s3info[i].info.compat.id == 4)) { + + } + + break; + case 3: + pr_debug("Seq: %#x\n", s3info[i].info.buildseq); + + break; + case 4: + pr_debug("Platform: ID %#x %d.%d.%d\n", + s3info[i].info.version.id, + s3info[i].info.version.major, + s3info[i].info.version.minor, + s3info[i].info.version.variant); + + if (nicid.id != s3info[i].info.version.id) + continue; + if (nicid.major != s3info[i].info.version.major) + continue; + if (nicid.minor != s3info[i].info.version.minor) + continue; + if ((nicid.variant != s3info[i].info.version.variant) && + (nicid.id != 0x8008)) + continue; + + if (result != 2) + result = 0; + break; + case 0x8001: + pr_debug("name inforec len %d\n", s3info[i].len); + + break; + default: + pr_debug("Unknown inforec type %d\n", s3info[i].type); + } + } + // walk through + + return result; +} diff --git a/drivers/staging/wlan-ng/prism2mgmt.c b/drivers/staging/wlan-ng/prism2mgmt.c index e7a7939b4280..465457653eb3 100644 --- a/drivers/staging/wlan-ng/prism2mgmt.c +++ b/drivers/staging/wlan-ng/prism2mgmt.c @@ -117,7 +117,7 @@ * process thread (usually) * interrupt ----------------------------------------------------------------*/ -int prism2mgmt_scan(wlandevice_t *wlandev, void *msgp) +int prism2mgmt_scan(wlandevice_t * wlandev, void *msgp) { int result = 0; hfa384x_t *hw = wlandev->priv; @@ -362,7 +362,7 @@ exit: * process thread (usually) * interrupt ----------------------------------------------------------------*/ -int prism2mgmt_scan_results(wlandevice_t *wlandev, void *msgp) +int prism2mgmt_scan_results(wlandevice_t * wlandev, void *msgp) { int result = 0; p80211msg_dot11req_scan_results_t *req; @@ -389,7 +389,7 @@ int prism2mgmt_scan_results(wlandevice_t *wlandev, void *msgp) if (req->bssindex.data >= count) { pr_debug("requested index (%d) out of range (%d)\n", - req->bssindex.data, count); + req->bssindex.data, count); result = 2; req->resultcode.data = P80211ENUM_resultcode_invalid_parameters; goto exit; @@ -511,7 +511,7 @@ exit: * process thread (usually) * interrupt ----------------------------------------------------------------*/ -int prism2mgmt_start(wlandevice_t *wlandev, void *msgp) +int prism2mgmt_start(wlandevice_t * wlandev, void *msgp) { int result = 0; hfa384x_t *hw = wlandev->priv; @@ -544,7 +544,7 @@ int prism2mgmt_start(wlandevice_t *wlandev, void *msgp) /*** STATION ***/ /* Set the REQUIRED config items */ /* SSID */ - pstr = (p80211pstrd_t *)&(msg->ssid.data); + pstr = (p80211pstrd_t *) & (msg->ssid.data); prism2mgmt_pstr2bytestr(p2bytestr, pstr); result = hfa384x_drvr_setconfig(hw, HFA384x_RID_CNFOWNSSID, bytebuf, HFA384x_RID_CNFOWNSSID_LEN); @@ -688,7 +688,7 @@ done: * Call context: * process thread (usually) ----------------------------------------------------------------*/ -int prism2mgmt_readpda(wlandevice_t *wlandev, void *msgp) +int prism2mgmt_readpda(wlandevice_t * wlandev, void *msgp) { hfa384x_t *hw = wlandev->priv; p80211msg_p2req_readpda_t *msg = msgp; @@ -754,7 +754,7 @@ int prism2mgmt_readpda(wlandevice_t *wlandev, void *msgp) * Call context: * process thread (usually) ----------------------------------------------------------------*/ -int prism2mgmt_ramdl_state(wlandevice_t *wlandev, void *msgp) +int prism2mgmt_ramdl_state(wlandevice_t * wlandev, void *msgp) { hfa384x_t *hw = wlandev->priv; p80211msg_p2req_ramdl_state_t *msg = msgp; @@ -810,7 +810,7 @@ int prism2mgmt_ramdl_state(wlandevice_t *wlandev, void *msgp) * Call context: * process thread (usually) ----------------------------------------------------------------*/ -int prism2mgmt_ramdl_write(wlandevice_t *wlandev, void *msgp) +int prism2mgmt_ramdl_write(wlandevice_t * wlandev, void *msgp) { hfa384x_t *hw = wlandev->priv; p80211msg_p2req_ramdl_write_t *msg = msgp; @@ -872,7 +872,7 @@ int prism2mgmt_ramdl_write(wlandevice_t *wlandev, void *msgp) * Call context: * process thread (usually) ----------------------------------------------------------------*/ -int prism2mgmt_flashdl_state(wlandevice_t *wlandev, void *msgp) +int prism2mgmt_flashdl_state(wlandevice_t * wlandev, void *msgp) { int result = 0; hfa384x_t *hw = wlandev->priv; @@ -943,7 +943,7 @@ int prism2mgmt_flashdl_state(wlandevice_t *wlandev, void *msgp) * Call context: * process thread (usually) ----------------------------------------------------------------*/ -int prism2mgmt_flashdl_write(wlandevice_t *wlandev, void *msgp) +int prism2mgmt_flashdl_write(wlandevice_t * wlandev, void *msgp) { hfa384x_t *hw = wlandev->priv; p80211msg_p2req_flashdl_write_t *msg = msgp; @@ -1004,7 +1004,7 @@ int prism2mgmt_flashdl_write(wlandevice_t *wlandev, void *msgp) * process thread (usually) * interrupt ----------------------------------------------------------------*/ -int prism2mgmt_autojoin(wlandevice_t *wlandev, void *msgp) +int prism2mgmt_autojoin(wlandevice_t * wlandev, void *msgp) { hfa384x_t *hw = wlandev->priv; int result = 0; @@ -1037,7 +1037,7 @@ int prism2mgmt_autojoin(wlandevice_t *wlandev, void *msgp) /* Set the ssid */ memset(bytebuf, 0, 256); - pstr = (p80211pstrd_t *)&(msg->ssid.data); + pstr = (p80211pstrd_t *) & (msg->ssid.data); prism2mgmt_pstr2bytestr(p2bytestr, pstr); result = hfa384x_drvr_setconfig(hw, HFA384x_RID_CNFDESIREDSSID, bytebuf, @@ -1075,7 +1075,7 @@ int prism2mgmt_autojoin(wlandevice_t *wlandev, void *msgp) * process thread (usually) * interrupt ----------------------------------------------------------------*/ -int prism2mgmt_wlansniff(wlandevice_t *wlandev, void *msgp) +int prism2mgmt_wlansniff(wlandevice_t * wlandev, void *msgp) { int result = 0; p80211msg_lnxreq_wlansniff_t *msg = msgp; @@ -1096,17 +1096,16 @@ int prism2mgmt_wlansniff(wlandevice_t *wlandev, void *msgp) /* Disable monitor mode */ result = hfa384x_cmd_monitor(hw, HFA384x_MONITOR_DISABLE); if (result) { - printk(KERN_DEBUG - "failed to disable monitor mode, result=%d\n", - result); + pr_debug("failed to disable monitor mode, result=%d\n", + result); goto failed; } /* Disable port 0 */ result = hfa384x_drvr_disable(hw, 0); if (result) { - printk(KERN_DEBUG - "failed to disable port 0 after sniffing, result=%d\n", - result); + pr_debug + ("failed to disable port 0 after sniffing, result=%d\n", + result); goto failed; } /* Clear the driver state */ @@ -1117,9 +1116,9 @@ int prism2mgmt_wlansniff(wlandevice_t *wlandev, void *msgp) HFA384x_RID_CNFWEPFLAGS, hw->presniff_wepflags); if (result) { - printk(KERN_DEBUG - "failed to restore wepflags=0x%04x, result=%d\n", - hw->presniff_wepflags, result); + pr_debug + ("failed to restore wepflags=0x%04x, result=%d\n", + hw->presniff_wepflags, result); goto failed; } @@ -1130,18 +1129,18 @@ int prism2mgmt_wlansniff(wlandevice_t *wlandev, void *msgp) HFA384x_RID_CNFPORTTYPE, word); if (result) { - printk(KERN_DEBUG - "failed to restore porttype, result=%d\n", - result); + pr_debug + ("failed to restore porttype, result=%d\n", + result); goto failed; } /* Enable the port */ result = hfa384x_drvr_enable(hw, 0); if (result) { - printk(KERN_DEBUG - "failed to enable port to presniff setting, result=%d\n", - result); + pr_debug + ("failed to enable port to presniff setting, result=%d\n", + result); goto failed; } } else { @@ -1161,40 +1160,42 @@ int prism2mgmt_wlansniff(wlandevice_t *wlandev, void *msgp) /* Save macport 0 state */ result = hfa384x_drvr_getconfig16(hw, HFA384x_RID_CNFPORTTYPE, - &(hw-> - presniff_port_type)); + & + (hw-> + presniff_port_type)); if (result) { - printk(KERN_DEBUG - "failed to read porttype, result=%d\n", - result); + pr_debug + ("failed to read porttype, result=%d\n", + result); goto failed; } /* Save the wepflags state */ result = hfa384x_drvr_getconfig16(hw, HFA384x_RID_CNFWEPFLAGS, - &(hw-> - presniff_wepflags)); + & + (hw-> + presniff_wepflags)); if (result) { - printk(KERN_DEBUG - "failed to read wepflags, result=%d\n", - result); + pr_debug + ("failed to read wepflags, result=%d\n", + result); goto failed; } hfa384x_drvr_stop(hw); result = hfa384x_drvr_start(hw); if (result) { - printk(KERN_DEBUG - "failed to restart the card for sniffing, result=%d\n", - result); + pr_debug + ("failed to restart the card for sniffing, result=%d\n", + result); goto failed; } } else { /* Disable the port */ result = hfa384x_drvr_disable(hw, 0); if (result) { - printk(KERN_DEBUG - "failed to enable port for sniffing, result=%d\n", - result); + pr_debug + ("failed to enable port for sniffing, result=%d\n", + result); goto failed; } } @@ -1210,9 +1211,8 @@ int prism2mgmt_wlansniff(wlandevice_t *wlandev, void *msgp) hw->sniff_channel = word; if (result) { - printk(KERN_DEBUG - "failed to set channel %d, result=%d\n", - word, result); + pr_debug("failed to set channel %d, result=%d\n", + word, result); goto failed; } @@ -1224,9 +1224,9 @@ int prism2mgmt_wlansniff(wlandevice_t *wlandev, void *msgp) HFA384x_RID_CNFPORTTYPE, word); if (result) { - printk(KERN_DEBUG - "failed to set porttype %d, result=%d\n", - word, result); + pr_debug + ("failed to set porttype %d, result=%d\n", + word, result); goto failed; } if ((msg->keepwepflags.status == @@ -1243,9 +1243,9 @@ int prism2mgmt_wlansniff(wlandevice_t *wlandev, void *msgp) } if (result) { - printk(KERN_DEBUG - "failed to set wepflags=0x%04x, result=%d\n", - word, result); + pr_debug + ("failed to set wepflags=0x%04x, result=%d\n", + word, result); goto failed; } } @@ -1269,17 +1269,16 @@ int prism2mgmt_wlansniff(wlandevice_t *wlandev, void *msgp) /* Enable the port */ result = hfa384x_drvr_enable(hw, 0); if (result) { - printk(KERN_DEBUG - "failed to enable port for sniffing, result=%d\n", - result); + pr_debug + ("failed to enable port for sniffing, result=%d\n", + result); goto failed; } /* Enable monitor mode */ result = hfa384x_cmd_monitor(hw, HFA384x_MONITOR_ENABLE); if (result) { - printk(KERN_DEBUG - "failed to enable monitor mode, result=%d\n", - result); + pr_debug("failed to enable monitor mode, result=%d\n", + result); goto failed; } diff --git a/drivers/staging/wlan-ng/prism2mgmt.h b/drivers/staging/wlan-ng/prism2mgmt.h index 07eecebeb6cc..bdf2b3e03253 100644 --- a/drivers/staging/wlan-ng/prism2mgmt.h +++ b/drivers/staging/wlan-ng/prism2mgmt.h @@ -63,43 +63,43 @@ extern int prism2_reset_holdtime; extern int prism2_reset_settletime; -u32 prism2sta_ifstate(wlandevice_t *wlandev, u32 ifstate); +u32 prism2sta_ifstate(wlandevice_t * wlandev, u32 ifstate); -void prism2sta_ev_info(wlandevice_t *wlandev, hfa384x_InfFrame_t *inf); -void prism2sta_ev_txexc(wlandevice_t *wlandev, u16 status); -void prism2sta_ev_tx(wlandevice_t *wlandev, u16 status); -void prism2sta_ev_rx(wlandevice_t *wlandev, struct sk_buff *skb); -void prism2sta_ev_alloc(wlandevice_t *wlandev); +void prism2sta_ev_info(wlandevice_t * wlandev, hfa384x_InfFrame_t * inf); +void prism2sta_ev_txexc(wlandevice_t * wlandev, u16 status); +void prism2sta_ev_tx(wlandevice_t * wlandev, u16 status); +void prism2sta_ev_rx(wlandevice_t * wlandev, struct sk_buff *skb); +void prism2sta_ev_alloc(wlandevice_t * wlandev); -int prism2mgmt_mibset_mibget(wlandevice_t *wlandev, void *msgp); -int prism2mgmt_scan(wlandevice_t *wlandev, void *msgp); -int prism2mgmt_scan_results(wlandevice_t *wlandev, void *msgp); -int prism2mgmt_start(wlandevice_t *wlandev, void *msgp); -int prism2mgmt_wlansniff(wlandevice_t *wlandev, void *msgp); -int prism2mgmt_readpda(wlandevice_t *wlandev, void *msgp); -int prism2mgmt_ramdl_state(wlandevice_t *wlandev, void *msgp); -int prism2mgmt_ramdl_write(wlandevice_t *wlandev, void *msgp); -int prism2mgmt_flashdl_state(wlandevice_t *wlandev, void *msgp); -int prism2mgmt_flashdl_write(wlandevice_t *wlandev, void *msgp); -int prism2mgmt_autojoin(wlandevice_t *wlandev, void *msgp); +int prism2mgmt_mibset_mibget(wlandevice_t * wlandev, void *msgp); +int prism2mgmt_scan(wlandevice_t * wlandev, void *msgp); +int prism2mgmt_scan_results(wlandevice_t * wlandev, void *msgp); +int prism2mgmt_start(wlandevice_t * wlandev, void *msgp); +int prism2mgmt_wlansniff(wlandevice_t * wlandev, void *msgp); +int prism2mgmt_readpda(wlandevice_t * wlandev, void *msgp); +int prism2mgmt_ramdl_state(wlandevice_t * wlandev, void *msgp); +int prism2mgmt_ramdl_write(wlandevice_t * wlandev, void *msgp); +int prism2mgmt_flashdl_state(wlandevice_t * wlandev, void *msgp); +int prism2mgmt_flashdl_write(wlandevice_t * wlandev, void *msgp); +int prism2mgmt_autojoin(wlandevice_t * wlandev, void *msgp); /*--------------------------------------------------------------- * conversion functions going between wlan message data types and * Prism2 data types ---------------------------------------------------------------*/ /* byte area conversion functions*/ -void prism2mgmt_pstr2bytearea(u8 *bytearea, p80211pstrd_t *pstr); -void prism2mgmt_bytearea2pstr(u8 *bytearea, p80211pstrd_t *pstr, int len); +void prism2mgmt_pstr2bytearea(u8 * bytearea, p80211pstrd_t * pstr); +void prism2mgmt_bytearea2pstr(u8 * bytearea, p80211pstrd_t * pstr, int len); /* byte string conversion functions*/ -void prism2mgmt_pstr2bytestr(hfa384x_bytestr_t *bytestr, p80211pstrd_t *pstr); -void prism2mgmt_bytestr2pstr(hfa384x_bytestr_t *bytestr, p80211pstrd_t *pstr); +void prism2mgmt_pstr2bytestr(hfa384x_bytestr_t * bytestr, p80211pstrd_t * pstr); +void prism2mgmt_bytestr2pstr(hfa384x_bytestr_t * bytestr, p80211pstrd_t * pstr); /* functions to convert Group Addresses */ -void prism2mgmt_get_grpaddr(u32 did, p80211pstrd_t *pstr, hfa384x_t *priv); +void prism2mgmt_get_grpaddr(u32 did, p80211pstrd_t * pstr, hfa384x_t * priv); int prism2mgmt_set_grpaddr(u32 did, - u8 *prism2buf, p80211pstrd_t *pstr, - hfa384x_t *priv); + u8 * prism2buf, p80211pstrd_t * pstr, + hfa384x_t * priv); int prism2mgmt_get_grpaddr_index(u32 did); void prism2sta_processing_defer(struct work_struct *data); diff --git a/drivers/staging/wlan-ng/prism2mib.c b/drivers/staging/wlan-ng/prism2mib.c index 5a6ba86009df..f930254e1b34 100644 --- a/drivers/staging/wlan-ng/prism2mib.c +++ b/drivers/staging/wlan-ng/prism2mib.c @@ -50,7 +50,6 @@ * -------------------------------------------------------------------- */ -#include #include #include #include @@ -87,65 +86,65 @@ typedef struct mibrec { u16 parm1; u16 parm2; u16 parm3; - int (*func) (struct mibrec *mib, + int (*func) (struct mibrec * mib, int isget, - wlandevice_t *wlandev, - hfa384x_t *hw, - p80211msg_dot11req_mibset_t *msg, void *data); + wlandevice_t * wlandev, + hfa384x_t * hw, + p80211msg_dot11req_mibset_t * msg, void *data); } mibrec_t; -static int prism2mib_bytearea2pstr(mibrec_t *mib, +static int prism2mib_bytearea2pstr(mibrec_t * mib, int isget, - wlandevice_t *wlandev, - hfa384x_t *hw, - p80211msg_dot11req_mibset_t *msg, + wlandevice_t * wlandev, + hfa384x_t * hw, + p80211msg_dot11req_mibset_t * msg, void *data); -static int prism2mib_uint32(mibrec_t *mib, +static int prism2mib_uint32(mibrec_t * mib, int isget, - wlandevice_t *wlandev, - hfa384x_t *hw, - p80211msg_dot11req_mibset_t *msg, void *data); + wlandevice_t * wlandev, + hfa384x_t * hw, + p80211msg_dot11req_mibset_t * msg, void *data); -static int prism2mib_flag(mibrec_t *mib, +static int prism2mib_flag(mibrec_t * mib, int isget, - wlandevice_t *wlandev, - hfa384x_t *hw, - p80211msg_dot11req_mibset_t *msg, void *data); + wlandevice_t * wlandev, + hfa384x_t * hw, + p80211msg_dot11req_mibset_t * msg, void *data); -static int prism2mib_wepdefaultkey(mibrec_t *mib, +static int prism2mib_wepdefaultkey(mibrec_t * mib, int isget, - wlandevice_t *wlandev, - hfa384x_t *hw, - p80211msg_dot11req_mibset_t *msg, + wlandevice_t * wlandev, + hfa384x_t * hw, + p80211msg_dot11req_mibset_t * msg, void *data); -static int prism2mib_privacyinvoked(mibrec_t *mib, +static int prism2mib_privacyinvoked(mibrec_t * mib, int isget, - wlandevice_t *wlandev, - hfa384x_t *hw, - p80211msg_dot11req_mibset_t *msg, + wlandevice_t * wlandev, + hfa384x_t * hw, + p80211msg_dot11req_mibset_t * msg, void *data); -static int prism2mib_excludeunencrypted(mibrec_t *mib, +static int prism2mib_excludeunencrypted(mibrec_t * mib, int isget, - wlandevice_t *wlandev, - hfa384x_t *hw, - p80211msg_dot11req_mibset_t *msg, + wlandevice_t * wlandev, + hfa384x_t * hw, + p80211msg_dot11req_mibset_t * msg, void *data); -static int prism2mib_fragmentationthreshold(mibrec_t *mib, +static int prism2mib_fragmentationthreshold(mibrec_t * mib, int isget, - wlandevice_t *wlandev, - hfa384x_t *hw, - p80211msg_dot11req_mibset_t *msg, + wlandevice_t * wlandev, + hfa384x_t * hw, + p80211msg_dot11req_mibset_t * msg, void *data); -static int prism2mib_priv(mibrec_t *mib, +static int prism2mib_priv(mibrec_t * mib, int isget, - wlandevice_t *wlandev, - hfa384x_t *hw, - p80211msg_dot11req_mibset_t *msg, void *data); + wlandevice_t * wlandev, + hfa384x_t * hw, + p80211msg_dot11req_mibset_t * msg, void *data); static mibrec_t mibtab[] = { @@ -259,7 +258,7 @@ static mibrec_t mibtab[] = { * interrupt ----------------------------------------------------------------*/ -int prism2mgmt_mibset_mibget(wlandevice_t *wlandev, void *msgp) +int prism2mgmt_mibset_mibget(wlandevice_t * wlandev, void *msgp) { hfa384x_t *hw = wlandev->priv; int result, isget; @@ -331,8 +330,7 @@ int prism2mgmt_mibset_mibget(wlandevice_t *wlandev, void *msgp) if (msg->resultcode.data == P80211ENUM_resultcode_success) { if (result != 0) { - pr_debug("get/set failure, result=%d\n", - result); + pr_debug("get/set failure, result=%d\n", result); msg->resultcode.data = P80211ENUM_resultcode_implementation_failure; } else { @@ -374,11 +372,11 @@ done: * ----------------------------------------------------------------*/ -static int prism2mib_bytearea2pstr(mibrec_t *mib, +static int prism2mib_bytearea2pstr(mibrec_t * mib, int isget, - wlandevice_t *wlandev, - hfa384x_t *hw, - p80211msg_dot11req_mibset_t *msg, + wlandevice_t * wlandev, + hfa384x_t * hw, + p80211msg_dot11req_mibset_t * msg, void *data) { int result; @@ -424,11 +422,11 @@ static int prism2mib_bytearea2pstr(mibrec_t *mib, * ----------------------------------------------------------------*/ -static int prism2mib_uint32(mibrec_t *mib, +static int prism2mib_uint32(mibrec_t * mib, int isget, - wlandevice_t *wlandev, - hfa384x_t *hw, - p80211msg_dot11req_mibset_t *msg, void *data) + wlandevice_t * wlandev, + hfa384x_t * hw, + p80211msg_dot11req_mibset_t * msg, void *data) { int result; u32 *uint32 = (u32 *) data; @@ -471,11 +469,11 @@ static int prism2mib_uint32(mibrec_t *mib, * ----------------------------------------------------------------*/ -static int prism2mib_flag(mibrec_t *mib, +static int prism2mib_flag(mibrec_t * mib, int isget, - wlandevice_t *wlandev, - hfa384x_t *hw, - p80211msg_dot11req_mibset_t *msg, void *data) + wlandevice_t * wlandev, + hfa384x_t * hw, + p80211msg_dot11req_mibset_t * msg, void *data) { int result; u32 *uint32 = (u32 *) data; @@ -528,11 +526,11 @@ static int prism2mib_flag(mibrec_t *mib, * ----------------------------------------------------------------*/ -static int prism2mib_wepdefaultkey(mibrec_t *mib, +static int prism2mib_wepdefaultkey(mibrec_t * mib, int isget, - wlandevice_t *wlandev, - hfa384x_t *hw, - p80211msg_dot11req_mibset_t *msg, + wlandevice_t * wlandev, + hfa384x_t * hw, + p80211msg_dot11req_mibset_t * msg, void *data) { int result; @@ -578,11 +576,11 @@ static int prism2mib_wepdefaultkey(mibrec_t *mib, * ----------------------------------------------------------------*/ -static int prism2mib_privacyinvoked(mibrec_t *mib, +static int prism2mib_privacyinvoked(mibrec_t * mib, int isget, - wlandevice_t *wlandev, - hfa384x_t *hw, - p80211msg_dot11req_mibset_t *msg, + wlandevice_t * wlandev, + hfa384x_t * hw, + p80211msg_dot11req_mibset_t * msg, void *data) { int result; @@ -624,11 +622,11 @@ static int prism2mib_privacyinvoked(mibrec_t *mib, * ----------------------------------------------------------------*/ -static int prism2mib_excludeunencrypted(mibrec_t *mib, +static int prism2mib_excludeunencrypted(mibrec_t * mib, int isget, - wlandevice_t *wlandev, - hfa384x_t *hw, - p80211msg_dot11req_mibset_t *msg, + wlandevice_t * wlandev, + hfa384x_t * hw, + p80211msg_dot11req_mibset_t * msg, void *data) { int result; @@ -663,11 +661,11 @@ static int prism2mib_excludeunencrypted(mibrec_t *mib, * ----------------------------------------------------------------*/ -static int prism2mib_fragmentationthreshold(mibrec_t *mib, +static int prism2mib_fragmentationthreshold(mibrec_t * mib, int isget, - wlandevice_t *wlandev, - hfa384x_t *hw, - p80211msg_dot11req_mibset_t *msg, + wlandevice_t * wlandev, + hfa384x_t * hw, + p80211msg_dot11req_mibset_t * msg, void *data) { int result; @@ -712,11 +710,11 @@ static int prism2mib_fragmentationthreshold(mibrec_t *mib, * ----------------------------------------------------------------*/ -static int prism2mib_priv(mibrec_t *mib, +static int prism2mib_priv(mibrec_t * mib, int isget, - wlandevice_t *wlandev, - hfa384x_t *hw, - p80211msg_dot11req_mibset_t *msg, void *data) + wlandevice_t * wlandev, + hfa384x_t * hw, + p80211msg_dot11req_mibset_t * msg, void *data) { p80211pstrd_t *pstr = (p80211pstrd_t *) data; @@ -728,7 +726,7 @@ static int prism2mib_priv(mibrec_t *mib, if (isget) { hfa384x_drvr_getconfig(hw, HFA384x_RID_CNFWPADATA, - (u8 *)&wpa, + (u8 *) & wpa, sizeof(wpa)); pstr->len = le16_to_cpu(wpa.datalen); memcpy(pstr->data, wpa.data, pstr->len); @@ -739,7 +737,7 @@ static int prism2mib_priv(mibrec_t *mib, result = hfa384x_drvr_setconfig(hw, HFA384x_RID_CNFWPADATA, - (u8 *)&wpa, + (u8 *) & wpa, sizeof(wpa)); } break; @@ -766,7 +764,7 @@ static int prism2mib_priv(mibrec_t *mib, * ----------------------------------------------------------------*/ -void prism2mgmt_pstr2bytestr(hfa384x_bytestr_t *bytestr, p80211pstrd_t *pstr) +void prism2mgmt_pstr2bytestr(hfa384x_bytestr_t * bytestr, p80211pstrd_t * pstr) { bytestr->len = cpu_to_le16((u16) (pstr->len)); memcpy(bytestr->data, pstr->data, pstr->len); @@ -787,7 +785,7 @@ void prism2mgmt_pstr2bytestr(hfa384x_bytestr_t *bytestr, p80211pstrd_t *pstr) * ----------------------------------------------------------------*/ -void prism2mgmt_pstr2bytearea(u8 *bytearea, p80211pstrd_t *pstr) +void prism2mgmt_pstr2bytearea(u8 * bytearea, p80211pstrd_t * pstr) { memcpy(bytearea, pstr->data, pstr->len); } @@ -807,7 +805,7 @@ void prism2mgmt_pstr2bytearea(u8 *bytearea, p80211pstrd_t *pstr) * ----------------------------------------------------------------*/ -void prism2mgmt_bytestr2pstr(hfa384x_bytestr_t *bytestr, p80211pstrd_t *pstr) +void prism2mgmt_bytestr2pstr(hfa384x_bytestr_t * bytestr, p80211pstrd_t * pstr) { pstr->len = (u8) (le16_to_cpu((u16) (bytestr->len))); memcpy(pstr->data, bytestr->data, pstr->len); @@ -828,13 +826,8 @@ void prism2mgmt_bytestr2pstr(hfa384x_bytestr_t *bytestr, p80211pstrd_t *pstr) * ----------------------------------------------------------------*/ -void prism2mgmt_bytearea2pstr(u8 *bytearea, p80211pstrd_t *pstr, int len) +void prism2mgmt_bytearea2pstr(u8 * bytearea, p80211pstrd_t * pstr, int len) { pstr->len = (u8) len; memcpy(pstr->data, bytearea, len); } - - - - - diff --git a/drivers/staging/wlan-ng/prism2sta.c b/drivers/staging/wlan-ng/prism2sta.c index 9d57f82f4a25..f493cf430db8 100644 --- a/drivers/staging/wlan-ng/prism2sta.c +++ b/drivers/staging/wlan-ng/prism2sta.c @@ -127,37 +127,37 @@ MODULE_PARM_DESC(prism2_reset_settletime, "reset settle time in ms"); MODULE_LICENSE("Dual MPL/GPL"); -static int prism2sta_open(wlandevice_t *wlandev); -static int prism2sta_close(wlandevice_t *wlandev); -static void prism2sta_reset(wlandevice_t *wlandev); -static int prism2sta_txframe(wlandevice_t *wlandev, struct sk_buff *skb, - p80211_hdr_t *p80211_hdr, - p80211_metawep_t *p80211_wep); -static int prism2sta_mlmerequest(wlandevice_t *wlandev, p80211msg_t *msg); -static int prism2sta_getcardinfo(wlandevice_t *wlandev); -static int prism2sta_globalsetup(wlandevice_t *wlandev); -static int prism2sta_setmulticast(wlandevice_t *wlandev, netdevice_t *dev); +static int prism2sta_open(wlandevice_t * wlandev); +static int prism2sta_close(wlandevice_t * wlandev); +static void prism2sta_reset(wlandevice_t * wlandev); +static int prism2sta_txframe(wlandevice_t * wlandev, struct sk_buff *skb, + p80211_hdr_t * p80211_hdr, + p80211_metawep_t * p80211_wep); +static int prism2sta_mlmerequest(wlandevice_t * wlandev, p80211msg_t * msg); +static int prism2sta_getcardinfo(wlandevice_t * wlandev); +static int prism2sta_globalsetup(wlandevice_t * wlandev); +static int prism2sta_setmulticast(wlandevice_t * wlandev, netdevice_t * dev); -static void prism2sta_inf_handover(wlandevice_t *wlandev, - hfa384x_InfFrame_t *inf); -static void prism2sta_inf_tallies(wlandevice_t *wlandev, - hfa384x_InfFrame_t *inf); -static void prism2sta_inf_hostscanresults(wlandevice_t *wlandev, - hfa384x_InfFrame_t *inf); -static void prism2sta_inf_scanresults(wlandevice_t *wlandev, - hfa384x_InfFrame_t *inf); -static void prism2sta_inf_chinforesults(wlandevice_t *wlandev, - hfa384x_InfFrame_t *inf); -static void prism2sta_inf_linkstatus(wlandevice_t *wlandev, - hfa384x_InfFrame_t *inf); -static void prism2sta_inf_assocstatus(wlandevice_t *wlandev, - hfa384x_InfFrame_t *inf); -static void prism2sta_inf_authreq(wlandevice_t *wlandev, - hfa384x_InfFrame_t *inf); -static void prism2sta_inf_authreq_defer(wlandevice_t *wlandev, - hfa384x_InfFrame_t *inf); -static void prism2sta_inf_psusercnt(wlandevice_t *wlandev, - hfa384x_InfFrame_t *inf); +static void prism2sta_inf_handover(wlandevice_t * wlandev, + hfa384x_InfFrame_t * inf); +static void prism2sta_inf_tallies(wlandevice_t * wlandev, + hfa384x_InfFrame_t * inf); +static void prism2sta_inf_hostscanresults(wlandevice_t * wlandev, + hfa384x_InfFrame_t * inf); +static void prism2sta_inf_scanresults(wlandevice_t * wlandev, + hfa384x_InfFrame_t * inf); +static void prism2sta_inf_chinforesults(wlandevice_t * wlandev, + hfa384x_InfFrame_t * inf); +static void prism2sta_inf_linkstatus(wlandevice_t * wlandev, + hfa384x_InfFrame_t * inf); +static void prism2sta_inf_assocstatus(wlandevice_t * wlandev, + hfa384x_InfFrame_t * inf); +static void prism2sta_inf_authreq(wlandevice_t * wlandev, + hfa384x_InfFrame_t * inf); +static void prism2sta_inf_authreq_defer(wlandevice_t * wlandev, + hfa384x_InfFrame_t * inf); +static void prism2sta_inf_psusercnt(wlandevice_t * wlandev, + hfa384x_InfFrame_t * inf); /*---------------------------------------------------------------- * prism2sta_open @@ -180,7 +180,7 @@ static void prism2sta_inf_psusercnt(wlandevice_t *wlandev, * Call context: * process thread ----------------------------------------------------------------*/ -static int prism2sta_open(wlandevice_t *wlandev) +static int prism2sta_open(wlandevice_t * wlandev) { /* We don't currently have to do anything else. * The setup of the MAC should be subsequently completed via @@ -214,7 +214,7 @@ static int prism2sta_open(wlandevice_t *wlandev) * Call context: * process thread ----------------------------------------------------------------*/ -static int prism2sta_close(wlandevice_t *wlandev) +static int prism2sta_close(wlandevice_t * wlandev) { /* We don't currently have to do anything else. * Higher layers know we're not ready from dev->start==0 and @@ -242,7 +242,7 @@ static int prism2sta_close(wlandevice_t *wlandev) * Call context: * process thread ----------------------------------------------------------------*/ -static void prism2sta_reset(wlandevice_t *wlandev) +static void prism2sta_reset(wlandevice_t * wlandev) { return; } @@ -268,9 +268,9 @@ static void prism2sta_reset(wlandevice_t *wlandev) * Call context: * process thread ----------------------------------------------------------------*/ -static int prism2sta_txframe(wlandevice_t *wlandev, struct sk_buff *skb, - p80211_hdr_t *p80211_hdr, - p80211_metawep_t *p80211_wep) +static int prism2sta_txframe(wlandevice_t * wlandev, struct sk_buff *skb, + p80211_hdr_t * p80211_hdr, + p80211_metawep_t * p80211_wep) { hfa384x_t *hw = (hfa384x_t *) wlandev->priv; int result; @@ -310,7 +310,7 @@ static int prism2sta_txframe(wlandevice_t *wlandev, struct sk_buff *skb, * Call context: * process thread ----------------------------------------------------------------*/ -static int prism2sta_mlmerequest(wlandevice_t *wlandev, p80211msg_t *msg) +static int prism2sta_mlmerequest(wlandevice_t * wlandev, p80211msg_t * msg) { hfa384x_t *hw = (hfa384x_t *) wlandev->priv; @@ -401,12 +401,9 @@ static int prism2sta_mlmerequest(wlandevice_t *wlandev, p80211msg_t *msg) qualmsg->noise.status = P80211ENUM_msgitem_status_data_ok; - qualmsg->link.data = - le16_to_cpu(hw->qual.CQ_currBSS); - qualmsg->level.data = - le16_to_cpu(hw->qual.ASL_currBSS); - qualmsg->noise.data = - le16_to_cpu(hw->qual.ANL_currFC); + qualmsg->link.data = le16_to_cpu(hw->qual.CQ_currBSS); + qualmsg->level.data = le16_to_cpu(hw->qual.ASL_currBSS); + qualmsg->noise.data = le16_to_cpu(hw->qual.ANL_currFC); break; } @@ -440,7 +437,7 @@ static int prism2sta_mlmerequest(wlandevice_t *wlandev, p80211msg_t *msg) * process thread (usually) * interrupt ----------------------------------------------------------------*/ -u32 prism2sta_ifstate(wlandevice_t *wlandev, u32 ifstate) +u32 prism2sta_ifstate(wlandevice_t * wlandev, u32 ifstate) { hfa384x_t *hw = (hfa384x_t *) wlandev->priv; u32 result; @@ -448,7 +445,7 @@ u32 prism2sta_ifstate(wlandevice_t *wlandev, u32 ifstate) result = P80211ENUM_resultcode_implementation_failure; pr_debug("Current MSD state(%d), requesting(%d)\n", - wlandev->msdstate, ifstate); + wlandev->msdstate, ifstate); switch (ifstate) { case P80211ENUM_ifstate_fwload: switch (wlandev->msdstate) { @@ -610,7 +607,7 @@ u32 prism2sta_ifstate(wlandevice_t *wlandev, u32 ifstate) * Call context: * Either. ----------------------------------------------------------------*/ -static int prism2sta_getcardinfo(wlandevice_t *wlandev) +static int prism2sta_getcardinfo(wlandevice_t * wlandev) { int result = 0; hfa384x_t *hw = (hfa384x_t *) wlandev->priv; @@ -811,10 +808,8 @@ static int prism2sta_getcardinfo(wlandevice_t *wlandev) fields in byte order */ hw->cap_act_pri_cfi.role = le16_to_cpu(hw->cap_act_pri_cfi.role); hw->cap_act_pri_cfi.id = le16_to_cpu(hw->cap_act_pri_cfi.id); - hw->cap_act_pri_cfi.variant = - le16_to_cpu(hw->cap_act_pri_cfi.variant); - hw->cap_act_pri_cfi.bottom = - le16_to_cpu(hw->cap_act_pri_cfi.bottom); + hw->cap_act_pri_cfi.variant = le16_to_cpu(hw->cap_act_pri_cfi.variant); + hw->cap_act_pri_cfi.bottom = le16_to_cpu(hw->cap_act_pri_cfi.bottom); hw->cap_act_pri_cfi.top = le16_to_cpu(hw->cap_act_pri_cfi.top); printk(KERN_INFO @@ -836,10 +831,8 @@ static int prism2sta_getcardinfo(wlandevice_t *wlandev) fields in byte order */ hw->cap_act_sta_cfi.role = le16_to_cpu(hw->cap_act_sta_cfi.role); hw->cap_act_sta_cfi.id = le16_to_cpu(hw->cap_act_sta_cfi.id); - hw->cap_act_sta_cfi.variant = - le16_to_cpu(hw->cap_act_sta_cfi.variant); - hw->cap_act_sta_cfi.bottom = - le16_to_cpu(hw->cap_act_sta_cfi.bottom); + hw->cap_act_sta_cfi.variant = le16_to_cpu(hw->cap_act_sta_cfi.variant); + hw->cap_act_sta_cfi.bottom = le16_to_cpu(hw->cap_act_sta_cfi.bottom); hw->cap_act_sta_cfi.top = le16_to_cpu(hw->cap_act_sta_cfi.top); printk(KERN_INFO @@ -861,10 +854,8 @@ static int prism2sta_getcardinfo(wlandevice_t *wlandev) fields in byte order */ hw->cap_act_sta_mfi.role = le16_to_cpu(hw->cap_act_sta_mfi.role); hw->cap_act_sta_mfi.id = le16_to_cpu(hw->cap_act_sta_mfi.id); - hw->cap_act_sta_mfi.variant = - le16_to_cpu(hw->cap_act_sta_mfi.variant); - hw->cap_act_sta_mfi.bottom = - le16_to_cpu(hw->cap_act_sta_mfi.bottom); + hw->cap_act_sta_mfi.variant = le16_to_cpu(hw->cap_act_sta_mfi.variant); + hw->cap_act_sta_mfi.bottom = le16_to_cpu(hw->cap_act_sta_mfi.bottom); hw->cap_act_sta_mfi.top = le16_to_cpu(hw->cap_act_sta_mfi.top); printk(KERN_INFO @@ -940,7 +931,7 @@ done: * Call context: * process thread ----------------------------------------------------------------*/ -static int prism2sta_globalsetup(wlandevice_t *wlandev) +static int prism2sta_globalsetup(wlandevice_t * wlandev) { hfa384x_t *hw = (hfa384x_t *) wlandev->priv; @@ -949,7 +940,7 @@ static int prism2sta_globalsetup(wlandevice_t *wlandev) WLAN_DATA_MAXLEN); } -static int prism2sta_setmulticast(wlandevice_t *wlandev, netdevice_t *dev) +static int prism2sta_setmulticast(wlandevice_t * wlandev, netdevice_t * dev) { int result = 0; hfa384x_t *hw = (hfa384x_t *) wlandev->priv; @@ -990,8 +981,8 @@ exit: * Call context: * interrupt ----------------------------------------------------------------*/ -static void prism2sta_inf_handover(wlandevice_t *wlandev, - hfa384x_InfFrame_t *inf) +static void prism2sta_inf_handover(wlandevice_t * wlandev, + hfa384x_InfFrame_t * inf) { pr_debug("received infoframe:HANDOVER (unhandled)\n"); return; @@ -1014,8 +1005,8 @@ static void prism2sta_inf_handover(wlandevice_t *wlandev, * Call context: * interrupt ----------------------------------------------------------------*/ -static void prism2sta_inf_tallies(wlandevice_t *wlandev, - hfa384x_InfFrame_t *inf) +static void prism2sta_inf_tallies(wlandevice_t * wlandev, + hfa384x_InfFrame_t * inf) { hfa384x_t *hw = (hfa384x_t *) wlandev->priv; u16 *src16; @@ -1031,13 +1022,13 @@ static void prism2sta_inf_tallies(wlandevice_t *wlandev, cnt = sizeof(hfa384x_CommTallies32_t) / sizeof(u32); if (inf->framelen > 22) { - dst = (u32 *)&hw->tallies; - src32 = (u32 *)&inf->info.commtallies32; + dst = (u32 *) & hw->tallies; + src32 = (u32 *) & inf->info.commtallies32; for (i = 0; i < cnt; i++, dst++, src32++) *dst += le32_to_cpu(*src32); } else { - dst = (u32 *)&hw->tallies; - src16 = (u16 *)&inf->info.commtallies16; + dst = (u32 *) & hw->tallies; + src16 = (u16 *) & inf->info.commtallies16; for (i = 0; i < cnt; i++, dst++, src16++) *dst += le16_to_cpu(*src16); } @@ -1062,8 +1053,8 @@ static void prism2sta_inf_tallies(wlandevice_t *wlandev, * Call context: * interrupt ----------------------------------------------------------------*/ -static void prism2sta_inf_scanresults(wlandevice_t *wlandev, - hfa384x_InfFrame_t *inf) +static void prism2sta_inf_scanresults(wlandevice_t * wlandev, + hfa384x_InfFrame_t * inf) { hfa384x_t *hw = (hfa384x_t *) wlandev->priv; @@ -1080,14 +1071,14 @@ static void prism2sta_inf_scanresults(wlandevice_t *wlandev, /* Print em */ pr_debug("rx scanresults, reason=%d, nbss=%d:\n", - inf->info.scanresult.scanreason, nbss); + inf->info.scanresult.scanreason, nbss); for (i = 0; i < nbss; i++) { pr_debug("chid=%d anl=%d sl=%d bcnint=%d\n", - sr->result[i].chid, - sr->result[i].anl, - sr->result[i].sl, sr->result[i].bcnint); + sr->result[i].chid, + sr->result[i].anl, + sr->result[i].sl, sr->result[i].bcnint); pr_debug(" capinfo=0x%04x proberesp_rate=%d\n", - sr->result[i].capinfo, sr->result[i].proberesp_rate); + sr->result[i].capinfo, sr->result[i].proberesp_rate); } /* issue a join request */ joinreq.channel = sr->result[0].chid; @@ -1120,8 +1111,8 @@ static void prism2sta_inf_scanresults(wlandevice_t *wlandev, * Call context: * interrupt ----------------------------------------------------------------*/ -static void prism2sta_inf_hostscanresults(wlandevice_t *wlandev, - hfa384x_InfFrame_t *inf) +static void prism2sta_inf_hostscanresults(wlandevice_t * wlandev, + hfa384x_InfFrame_t * inf) { hfa384x_t *hw = (hfa384x_t *) wlandev->priv; int nbss; @@ -1162,8 +1153,8 @@ static void prism2sta_inf_hostscanresults(wlandevice_t *wlandev, * Call context: * interrupt ----------------------------------------------------------------*/ -static void prism2sta_inf_chinforesults(wlandevice_t *wlandev, - hfa384x_InfFrame_t *inf) +static void prism2sta_inf_chinforesults(wlandevice_t * wlandev, + hfa384x_InfFrame_t * inf) { hfa384x_t *hw = (hfa384x_t *) wlandev->priv; unsigned int i, n; @@ -1174,29 +1165,26 @@ static void prism2sta_inf_chinforesults(wlandevice_t *wlandev, for (i = 0, n = 0; i < HFA384x_CHINFORESULT_MAX; i++) { if (hw->channel_info.results.scanchannels & (1 << i)) { int channel = - le16_to_cpu(inf->info.chinforesult.result[n]. - chid) - 1; + le16_to_cpu(inf->info.chinforesult.result[n].chid) - + 1; hfa384x_ChInfoResultSub_t *chinforesult = &hw->channel_info.results.result[channel]; chinforesult->chid = channel; chinforesult->anl = - le16_to_cpu(inf->info.chinforesult.result[n]. - anl); + le16_to_cpu(inf->info.chinforesult.result[n].anl); chinforesult->pnl = - le16_to_cpu(inf->info.chinforesult.result[n]. - pnl); + le16_to_cpu(inf->info.chinforesult.result[n].pnl); chinforesult->active = le16_to_cpu(inf->info.chinforesult.result[n]. - active); - printk(KERN_DEBUG - "chinfo: channel %d, %s level (avg/peak)=%d/%d dB, pcf %d\n", - channel + 1, - chinforesult-> - active & HFA384x_CHINFORESULT_BSSACTIVE ? - "signal" : "noise", chinforesult->anl, - chinforesult->pnl, - chinforesult-> - active & HFA384x_CHINFORESULT_PCFACTIVE ? 1 : 0); + active); + pr_debug + ("chinfo: channel %d, %s level (avg/peak)=%d/%d dB, pcf %d\n", + channel + 1, + chinforesult-> + active & HFA384x_CHINFORESULT_BSSACTIVE ? "signal" + : "noise", chinforesult->anl, chinforesult->pnl, + chinforesult-> + active & HFA384x_CHINFORESULT_PCFACTIVE ? 1 : 0); n++; } } @@ -1276,9 +1264,9 @@ void prism2sta_processing_defer(struct work_struct *data) wlandev->bssid, WLAN_BSSID_LEN); if (result) { - printk(KERN_DEBUG - "getconfig(0x%02x) failed, result = %d\n", - HFA384x_RID_CURRENTBSSID, result); + pr_debug + ("getconfig(0x%02x) failed, result = %d\n", + HFA384x_RID_CURRENTBSSID, result); goto failed; } @@ -1286,23 +1274,23 @@ void prism2sta_processing_defer(struct work_struct *data) HFA384x_RID_CURRENTSSID, &ssid, sizeof(ssid)); if (result) { - printk(KERN_DEBUG - "getconfig(0x%02x) failed, result = %d\n", - HFA384x_RID_CURRENTSSID, result); + pr_debug + ("getconfig(0x%02x) failed, result = %d\n", + HFA384x_RID_CURRENTSSID, result); goto failed; } - prism2mgmt_bytestr2pstr((hfa384x_bytestr_t *)&ssid, - (p80211pstrd_t *)&wlandev-> - ssid); + prism2mgmt_bytestr2pstr((hfa384x_bytestr_t *) & ssid, + (p80211pstrd_t *) & + wlandev->ssid); /* Collect the port status */ result = hfa384x_drvr_getconfig16(hw, HFA384x_RID_PORTSTATUS, &portstatus); if (result) { - printk(KERN_DEBUG - "getconfig(0x%02x) failed, result = %d\n", - HFA384x_RID_PORTSTATUS, result); + pr_debug + ("getconfig(0x%02x) failed, result = %d\n", + HFA384x_RID_PORTSTATUS, result); goto failed; } wlandev->macmode = @@ -1366,9 +1354,8 @@ void prism2sta_processing_defer(struct work_struct *data) HFA384x_RID_CURRENTBSSID, wlandev->bssid, WLAN_BSSID_LEN); if (result) { - printk(KERN_DEBUG - "getconfig(0x%02x) failed, result = %d\n", - HFA384x_RID_CURRENTBSSID, result); + pr_debug("getconfig(0x%02x) failed, result = %d\n", + HFA384x_RID_CURRENTBSSID, result); goto failed; } @@ -1376,13 +1363,12 @@ void prism2sta_processing_defer(struct work_struct *data) HFA384x_RID_CURRENTSSID, &ssid, sizeof(ssid)); if (result) { - printk(KERN_DEBUG - "getconfig(0x%02x) failed, result = %d\n", - HFA384x_RID_CURRENTSSID, result); + pr_debug("getconfig(0x%02x) failed, result = %d\n", + HFA384x_RID_CURRENTSSID, result); goto failed; } - prism2mgmt_bytestr2pstr((hfa384x_bytestr_t *)&ssid, - (p80211pstrd_t *)&wlandev->ssid); + prism2mgmt_bytestr2pstr((hfa384x_bytestr_t *) & ssid, + (p80211pstrd_t *) & wlandev->ssid); hw->link_status = HFA384x_LINK_CONNECTED; netif_carrier_on(wlandev->netdev); @@ -1482,8 +1468,8 @@ failed: * Call context: * interrupt ----------------------------------------------------------------*/ -static void prism2sta_inf_linkstatus(wlandevice_t *wlandev, - hfa384x_InfFrame_t *inf) +static void prism2sta_inf_linkstatus(wlandevice_t * wlandev, + hfa384x_InfFrame_t * inf) { hfa384x_t *hw = (hfa384x_t *) wlandev->priv; @@ -1512,8 +1498,8 @@ static void prism2sta_inf_linkstatus(wlandevice_t *wlandev, * Call context: * interrupt ----------------------------------------------------------------*/ -static void prism2sta_inf_assocstatus(wlandevice_t *wlandev, - hfa384x_InfFrame_t *inf) +static void prism2sta_inf_assocstatus(wlandevice_t * wlandev, + hfa384x_InfFrame_t * inf) { hfa384x_t *hw = (hfa384x_t *) wlandev->priv; hfa384x_AssocStatus_t rec; @@ -1574,8 +1560,8 @@ static void prism2sta_inf_assocstatus(wlandevice_t *wlandev, * interrupt * ----------------------------------------------------------------*/ -static void prism2sta_inf_authreq(wlandevice_t *wlandev, - hfa384x_InfFrame_t *inf) +static void prism2sta_inf_authreq(wlandevice_t * wlandev, + hfa384x_InfFrame_t * inf) { hfa384x_t *hw = (hfa384x_t *) wlandev->priv; struct sk_buff *skb; @@ -1589,8 +1575,8 @@ static void prism2sta_inf_authreq(wlandevice_t *wlandev, } } -static void prism2sta_inf_authreq_defer(wlandevice_t *wlandev, - hfa384x_InfFrame_t *inf) +static void prism2sta_inf_authreq_defer(wlandevice_t * wlandev, + hfa384x_InfFrame_t * inf) { hfa384x_t *hw = (hfa384x_t *) wlandev->priv; hfa384x_authenticateStation_data_t rec; @@ -1763,8 +1749,8 @@ static void prism2sta_inf_authreq_defer(wlandevice_t *wlandev, * Call context: * interrupt ----------------------------------------------------------------*/ -static void prism2sta_inf_psusercnt(wlandevice_t *wlandev, - hfa384x_InfFrame_t *inf) +static void prism2sta_inf_psusercnt(wlandevice_t * wlandev, + hfa384x_InfFrame_t * inf) { hfa384x_t *hw = (hfa384x_t *) wlandev->priv; @@ -1790,7 +1776,7 @@ static void prism2sta_inf_psusercnt(wlandevice_t *wlandev, * Call context: * interrupt ----------------------------------------------------------------*/ -void prism2sta_ev_info(wlandevice_t *wlandev, hfa384x_InfFrame_t *inf) +void prism2sta_ev_info(wlandevice_t * wlandev, hfa384x_InfFrame_t * inf) { inf->infotype = le16_to_cpu(inf->infotype); /* Dispatch */ @@ -1858,7 +1844,7 @@ void prism2sta_ev_info(wlandevice_t *wlandev, hfa384x_InfFrame_t *inf) * Call context: * interrupt ----------------------------------------------------------------*/ -void prism2sta_ev_txexc(wlandevice_t *wlandev, u16 status) +void prism2sta_ev_txexc(wlandevice_t * wlandev, u16 status) { pr_debug("TxExc status=0x%x.\n", status); @@ -1881,7 +1867,7 @@ void prism2sta_ev_txexc(wlandevice_t *wlandev, u16 status) * Call context: * interrupt ----------------------------------------------------------------*/ -void prism2sta_ev_tx(wlandevice_t *wlandev, u16 status) +void prism2sta_ev_tx(wlandevice_t * wlandev, u16 status) { pr_debug("Tx Complete, status=0x%04x\n", status); /* update linux network stats */ @@ -1905,7 +1891,7 @@ void prism2sta_ev_tx(wlandevice_t *wlandev, u16 status) * Call context: * interrupt ----------------------------------------------------------------*/ -void prism2sta_ev_rx(wlandevice_t *wlandev, struct sk_buff *skb) +void prism2sta_ev_rx(wlandevice_t * wlandev, struct sk_buff *skb) { p80211netdev_rx(wlandev, skb); return; @@ -1927,7 +1913,7 @@ void prism2sta_ev_rx(wlandevice_t *wlandev, struct sk_buff *skb) * Call context: * interrupt ----------------------------------------------------------------*/ -void prism2sta_ev_alloc(wlandevice_t *wlandev) +void prism2sta_ev_alloc(wlandevice_t * wlandev) { netif_wake_queue(wlandev->netdev); return; @@ -2020,9 +2006,9 @@ void prism2sta_commsqual_defer(struct work_struct *data) } pr_debug("commsqual %d %d %d\n", - le16_to_cpu(hw->qual.CQ_currBSS), - le16_to_cpu(hw->qual.ASL_currBSS), - le16_to_cpu(hw->qual.ANL_currFC)); + le16_to_cpu(hw->qual.CQ_currBSS), + le16_to_cpu(hw->qual.ASL_currBSS), + le16_to_cpu(hw->qual.ANL_currFC)); } /* Lastly, we need to make sure the BSSID didn't change on us */ @@ -2030,9 +2016,8 @@ void prism2sta_commsqual_defer(struct work_struct *data) HFA384x_RID_CURRENTBSSID, wlandev->bssid, WLAN_BSSID_LEN); if (result) { - printk(KERN_DEBUG - "getconfig(0x%02x) failed, result = %d\n", - HFA384x_RID_CURRENTBSSID, result); + pr_debug("getconfig(0x%02x) failed, result = %d\n", + HFA384x_RID_CURRENTBSSID, result); goto done; } @@ -2040,13 +2025,12 @@ void prism2sta_commsqual_defer(struct work_struct *data) HFA384x_RID_CURRENTSSID, &ssid, sizeof(ssid)); if (result) { - printk(KERN_DEBUG - "getconfig(0x%02x) failed, result = %d\n", - HFA384x_RID_CURRENTSSID, result); + pr_debug("getconfig(0x%02x) failed, result = %d\n", + HFA384x_RID_CURRENTSSID, result); goto done; } - prism2mgmt_bytestr2pstr((hfa384x_bytestr_t *)&ssid, - (p80211pstrd_t *)&wlandev->ssid); + prism2mgmt_bytestr2pstr((hfa384x_bytestr_t *) & ssid, + (p80211pstrd_t *) & wlandev->ssid); /* Reschedule timer */ mod_timer(&hw->commsqual_timer, jiffies + HZ); diff --git a/drivers/staging/wlan-ng/prism2usb.c b/drivers/staging/wlan-ng/prism2usb.c index d8a12982135d..7aa703ce9dd4 100644 --- a/drivers/staging/wlan-ng/prism2usb.c +++ b/drivers/staging/wlan-ng/prism2usb.c @@ -2,6 +2,7 @@ #include "prism2mgmt.c" #include "prism2mib.c" #include "prism2sta.c" +#include "prism2fw.c" #define PRISM_USB_DEVICE(vid, pid, name) \ USB_DEVICE(vid, pid), \ @@ -23,9 +24,8 @@ static struct usb_device_id usb_prism_tbl[] = { (0x066b, 0x2213, "Linksys WUSB12v1.1 11Mbps WLAN USB Adapter")}, {PRISM_USB_DEVICE (0x067c, 0x1022, "Siemens SpeedStream 1022 11Mbps WLAN USB Adapter")}, - {PRISM_USB_DEVICE - (0x049f, 0x0033, - "Compaq/Intel W100 PRO/Wireless 11Mbps multiport WLAN Adapter")}, + {PRISM_USB_DEVICE(0x049f, 0x0033, + "Compaq/Intel W100 PRO/Wireless 11Mbps multiport WLAN Adapter")}, {PRISM_USB_DEVICE (0x0411, 0x0016, "Melco WLI-USB-S11 11Mbps WLAN Adapter")}, {PRISM_USB_DEVICE @@ -153,15 +153,16 @@ static int prism2sta_probe_usb(struct usb_interface *interface, wlandev->msdstate = WLAN_MSD_HWPRESENT; + /* Try and load firmware, then enable card before we register */ + prism2_fwtry(dev, wlandev); + prism2sta_ifstate(wlandev, P80211ENUM_ifstate_enable); + if (register_wlandev(wlandev) != 0) { printk(KERN_ERR "%s: register_wlandev() failed.\n", dev_info); result = -EIO; goto failed; } -/* enable the card */ - prism2sta_ifstate(wlandev, P80211ENUM_ifstate_enable); - goto done; failed: @@ -170,7 +171,6 @@ failed: wlandev = NULL; done: - p80211_allow_ioctls(wlandev); usb_set_intfdata(interface, wlandev); return result; } diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c index 5e38ba10a3a9..0a69672097a8 100644 --- a/drivers/thermal/thermal_sys.c +++ b/drivers/thermal/thermal_sys.c @@ -417,7 +417,7 @@ static LIST_HEAD(thermal_hwmon_list); static ssize_t name_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct thermal_hwmon_device *hwmon = dev->driver_data; + struct thermal_hwmon_device *hwmon = dev_get_drvdata(dev); return sprintf(buf, "%s\n", hwmon->type); } static DEVICE_ATTR(name, 0444, name_show, NULL); @@ -488,7 +488,7 @@ thermal_add_hwmon_sysfs(struct thermal_zone_device *tz) result = PTR_ERR(hwmon->device); goto free_mem; } - hwmon->device->driver_data = hwmon; + dev_set_drvdata(hwmon->device, hwmon); result = device_create_file(hwmon->device, &dev_attr_name); if (result) goto unregister_hwmon_device; diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index c6c816b7ecb5..dcd49f1e96d0 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -22,6 +22,7 @@ config USB_ARCH_HAS_HCD default y if PCMCIA && !M32R # sl811_cs default y if ARM # SL-811 default y if SUPERH # r8a66597-hcd + default y if MICROBLAZE default PCI # many non-PCI SOC chips embed OHCI @@ -63,6 +64,7 @@ config USB_ARCH_HAS_EHCI config USB tristate "Support for Host-side USB" depends on USB_ARCH_HAS_HCD + select NLS # for UTF-8 strings ---help--- Universal Serial Bus (USB) is a specification for a serial bus subsystem which offers higher speeds and more features than the diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index 0a3dc5ece634..19cb7d5480d7 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_USB_ISP116X_HCD) += host/ obj-$(CONFIG_USB_OHCI_HCD) += host/ obj-$(CONFIG_USB_UHCI_HCD) += host/ obj-$(CONFIG_USB_FHCI_HCD) += host/ +obj-$(CONFIG_USB_XHCI_HCD) += host/ obj-$(CONFIG_USB_SL811_HCD) += host/ obj-$(CONFIG_USB_U132_HCD) += host/ obj-$(CONFIG_USB_R8A66597_HCD) += host/ diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index 9cf9ff69e3e3..d171b563e94c 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -306,6 +306,7 @@ enum { #define FW_GET_BYTE(p) *((__u8 *) (p)) #define FW_DIR "ueagle-atm/" +#define UEA_FW_NAME_MAX 30 #define NB_MODEM 4 #define BULK_TIMEOUT 300 @@ -1564,9 +1565,9 @@ static void cmvs_file_name(struct uea_softc *sc, char *const cmv_name, int ver) file = cmv_file[sc->modem_index]; strcpy(cmv_name, FW_DIR); - strlcat(cmv_name, file, FIRMWARE_NAME_MAX); + strlcat(cmv_name, file, UEA_FW_NAME_MAX); if (ver == 2) - strlcat(cmv_name, ".v2", FIRMWARE_NAME_MAX); + strlcat(cmv_name, ".v2", UEA_FW_NAME_MAX); } static int request_cmvs_old(struct uea_softc *sc, @@ -1574,7 +1575,7 @@ static int request_cmvs_old(struct uea_softc *sc, { int ret, size; u8 *data; - char cmv_name[FIRMWARE_NAME_MAX]; /* 30 bytes stack variable */ + char cmv_name[UEA_FW_NAME_MAX]; /* 30 bytes stack variable */ cmvs_file_name(sc, cmv_name, 1); ret = request_firmware(fw, cmv_name, &sc->usb_dev->dev); @@ -1608,7 +1609,7 @@ static int request_cmvs(struct uea_softc *sc, int ret, size; u32 crc; u8 *data; - char cmv_name[FIRMWARE_NAME_MAX]; /* 30 bytes stack variable */ + char cmv_name[UEA_FW_NAME_MAX]; /* 30 bytes stack variable */ cmvs_file_name(sc, cmv_name, 2); ret = request_firmware(fw, cmv_name, &sc->usb_dev->dev); diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 7a1164dd1d37..38bfdb0f6660 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -16,7 +16,8 @@ * v0.9 - thorough cleaning, URBification, almost a rewrite * v0.10 - some more cleanups * v0.11 - fixed flow control, read error doesn't stop reads - * v0.12 - added TIOCM ioctls, added break handling, made struct acm kmalloced + * v0.12 - added TIOCM ioctls, added break handling, made struct acm + * kmalloced * v0.13 - added termios, added hangup * v0.14 - sized down struct acm * v0.15 - fixed flow control again - characters could be lost @@ -62,7 +63,7 @@ #include #include #include -#include +#include #include #include #include @@ -87,7 +88,10 @@ static struct acm *acm_table[ACM_TTY_MINORS]; static DEFINE_MUTEX(open_mutex); -#define ACM_READY(acm) (acm && acm->dev && acm->used) +#define ACM_READY(acm) (acm && acm->dev && acm->port.count) + +static const struct tty_port_operations acm_port_ops = { +}; #ifdef VERBOSE_DEBUG #define verbose 1 @@ -99,13 +103,15 @@ static DEFINE_MUTEX(open_mutex); * Functions for ACM control messages. */ -static int acm_ctrl_msg(struct acm *acm, int request, int value, void *buf, int len) +static int acm_ctrl_msg(struct acm *acm, int request, int value, + void *buf, int len) { int retval = usb_control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0), request, USB_RT_ACM, value, acm->control->altsetting[0].desc.bInterfaceNumber, buf, len, 5000); - dbg("acm_control_msg: rq: 0x%02x val: %#x len: %#x result: %d", request, value, len, retval); + dbg("acm_control_msg: rq: 0x%02x val: %#x len: %#x result: %d", + request, value, len, retval); return retval < 0 ? retval : 0; } @@ -150,9 +156,8 @@ static int acm_wb_is_avail(struct acm *acm) n = ACM_NW; spin_lock_irqsave(&acm->write_lock, flags); - for (i = 0; i < ACM_NW; i++) { + for (i = 0; i < ACM_NW; i++) n -= acm->wb[i].use; - } spin_unlock_irqrestore(&acm->write_lock, flags); return n; } @@ -183,7 +188,8 @@ static int acm_start_wb(struct acm *acm, struct acm_wb *wb) wb->urb->transfer_buffer_length = wb->len; wb->urb->dev = acm->dev; - if ((rc = usb_submit_urb(wb->urb, GFP_ATOMIC)) < 0) { + rc = usb_submit_urb(wb->urb, GFP_ATOMIC); + if (rc < 0) { dbg("usb_submit_urb(write bulk) failed: %d", rc); acm_write_done(acm, wb); } @@ -262,6 +268,7 @@ static void acm_ctrl_irq(struct urb *urb) { struct acm *acm = urb->context; struct usb_cdc_notification *dr = urb->transfer_buffer; + struct tty_struct *tty; unsigned char *data; int newctrl; int retval; @@ -287,40 +294,45 @@ static void acm_ctrl_irq(struct urb *urb) data = (unsigned char *)(dr + 1); switch (dr->bNotificationType) { + case USB_CDC_NOTIFY_NETWORK_CONNECTION: + dbg("%s network", dr->wValue ? + "connected to" : "disconnected from"); + break; - case USB_CDC_NOTIFY_NETWORK_CONNECTION: + case USB_CDC_NOTIFY_SERIAL_STATE: + tty = tty_port_tty_get(&acm->port); + newctrl = get_unaligned_le16(data); - dbg("%s network", dr->wValue ? "connected to" : "disconnected from"); - break; - - case USB_CDC_NOTIFY_SERIAL_STATE: - - newctrl = get_unaligned_le16(data); - - if (acm->tty && !acm->clocal && (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) { + if (tty) { + if (!acm->clocal && + (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) { dbg("calling hangup"); - tty_hangup(acm->tty); + tty_hangup(tty); } + tty_kref_put(tty); + } - acm->ctrlin = newctrl; - - dbg("input control lines: dcd%c dsr%c break%c ring%c framing%c parity%c overrun%c", - acm->ctrlin & ACM_CTRL_DCD ? '+' : '-', acm->ctrlin & ACM_CTRL_DSR ? '+' : '-', - acm->ctrlin & ACM_CTRL_BRK ? '+' : '-', acm->ctrlin & ACM_CTRL_RI ? '+' : '-', - acm->ctrlin & ACM_CTRL_FRAMING ? '+' : '-', acm->ctrlin & ACM_CTRL_PARITY ? '+' : '-', - acm->ctrlin & ACM_CTRL_OVERRUN ? '+' : '-'); + acm->ctrlin = newctrl; + dbg("input control lines: dcd%c dsr%c break%c ring%c framing%c parity%c overrun%c", + acm->ctrlin & ACM_CTRL_DCD ? '+' : '-', + acm->ctrlin & ACM_CTRL_DSR ? '+' : '-', + acm->ctrlin & ACM_CTRL_BRK ? '+' : '-', + acm->ctrlin & ACM_CTRL_RI ? '+' : '-', + acm->ctrlin & ACM_CTRL_FRAMING ? '+' : '-', + acm->ctrlin & ACM_CTRL_PARITY ? '+' : '-', + acm->ctrlin & ACM_CTRL_OVERRUN ? '+' : '-'); break; - default: - dbg("unknown notification %d received: index %d len %d data0 %d data1 %d", - dr->bNotificationType, dr->wIndex, - dr->wLength, data[0], data[1]); - break; + default: + dbg("unknown notification %d received: index %d len %d data0 %d data1 %d", + dr->bNotificationType, dr->wIndex, + dr->wLength, data[0], data[1]); + break; } exit: usb_mark_last_busy(acm->dev); - retval = usb_submit_urb (urb, GFP_ATOMIC); + retval = usb_submit_urb(urb, GFP_ATOMIC); if (retval) dev_err(&urb->dev->dev, "%s - usb_submit_urb failed with " "result %d", __func__, retval); @@ -371,15 +383,14 @@ static void acm_rx_tasklet(unsigned long _acm) { struct acm *acm = (void *)_acm; struct acm_rb *buf; - struct tty_struct *tty = acm->tty; + struct tty_struct *tty; struct acm_ru *rcv; unsigned long flags; unsigned char throttled; dbg("Entering acm_rx_tasklet"); - if (!ACM_READY(acm)) - { + if (!ACM_READY(acm)) { dbg("acm_rx_tasklet: ACM not ready"); return; } @@ -387,12 +398,13 @@ static void acm_rx_tasklet(unsigned long _acm) spin_lock_irqsave(&acm->throttle_lock, flags); throttled = acm->throttle; spin_unlock_irqrestore(&acm->throttle_lock, flags); - if (throttled) - { + if (throttled) { dbg("acm_rx_tasklet: throttled"); return; } + tty = tty_port_tty_get(&acm->port); + next_buffer: spin_lock_irqsave(&acm->read_lock, flags); if (list_empty(&acm->filled_read_bufs)) { @@ -406,20 +418,22 @@ next_buffer: dbg("acm_rx_tasklet: procesing buf 0x%p, size = %d", buf, buf->size); - tty_buffer_request_room(tty, buf->size); - spin_lock_irqsave(&acm->throttle_lock, flags); - throttled = acm->throttle; - spin_unlock_irqrestore(&acm->throttle_lock, flags); - if (!throttled) - tty_insert_flip_string(tty, buf->base, buf->size); - tty_flip_buffer_push(tty); - - if (throttled) { - dbg("Throttling noticed"); - spin_lock_irqsave(&acm->read_lock, flags); - list_add(&buf->list, &acm->filled_read_bufs); - spin_unlock_irqrestore(&acm->read_lock, flags); - return; + if (tty) { + spin_lock_irqsave(&acm->throttle_lock, flags); + throttled = acm->throttle; + spin_unlock_irqrestore(&acm->throttle_lock, flags); + if (!throttled) { + tty_buffer_request_room(tty, buf->size); + tty_insert_flip_string(tty, buf->base, buf->size); + tty_flip_buffer_push(tty); + } else { + tty_kref_put(tty); + dbg("Throttling noticed"); + spin_lock_irqsave(&acm->read_lock, flags); + list_add(&buf->list, &acm->filled_read_bufs); + spin_unlock_irqrestore(&acm->read_lock, flags); + return; + } } spin_lock_irqsave(&acm->read_lock, flags); @@ -428,6 +442,8 @@ next_buffer: goto next_buffer; urbs: + tty_kref_put(tty); + while (!list_empty(&acm->spare_read_bufs)) { spin_lock_irqsave(&acm->read_lock, flags); if (list_empty(&acm->spare_read_urbs)) { @@ -454,10 +470,11 @@ urbs: rcv->urb->transfer_dma = buf->dma; rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - /* This shouldn't kill the driver as unsuccessful URBs are returned to the - free-urbs-pool and resubmited ASAP */ + /* This shouldn't kill the driver as unsuccessful URBs are + returned to the free-urbs-pool and resubmited ASAP */ spin_lock_irqsave(&acm->read_lock, flags); - if (acm->susp_count || usb_submit_urb(rcv->urb, GFP_ATOMIC) < 0) { + if (acm->susp_count || + usb_submit_urb(rcv->urb, GFP_ATOMIC) < 0) { list_add(&buf->list, &acm->spare_read_bufs); list_add(&rcv->list, &acm->spare_read_urbs); acm->processing = 0; @@ -499,11 +516,14 @@ static void acm_write_bulk(struct urb *urb) static void acm_softint(struct work_struct *work) { struct acm *acm = container_of(work, struct acm, work); + struct tty_struct *tty; dev_vdbg(&acm->data->dev, "tx work\n"); if (!ACM_READY(acm)) return; - tty_wakeup(acm->tty); + tty = tty_port_tty_get(&acm->port); + tty_wakeup(tty); + tty_kref_put(tty); } static void acm_waker(struct work_struct *waker) @@ -543,8 +563,9 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) rv = 0; set_bit(TTY_NO_WRITE_SPLIT, &tty->flags); + tty->driver_data = acm; - acm->tty = tty; + tty_port_tty_set(&acm->port, tty); if (usb_autopm_get_interface(acm->control) < 0) goto early_bail; @@ -552,11 +573,10 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) acm->control->needs_remote_wakeup = 1; mutex_lock(&acm->mutex); - if (acm->used++) { + if (acm->port.count++) { usb_autopm_put_interface(acm->control); goto done; - } - + } acm->ctrlurb->dev = acm->dev; if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) { @@ -567,22 +587,22 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS) && (acm->ctrl_caps & USB_CDC_CAP_LINE)) goto full_bailout; + usb_autopm_put_interface(acm->control); INIT_LIST_HEAD(&acm->spare_read_urbs); INIT_LIST_HEAD(&acm->spare_read_bufs); INIT_LIST_HEAD(&acm->filled_read_bufs); - for (i = 0; i < acm->rx_buflimit; i++) { + + for (i = 0; i < acm->rx_buflimit; i++) list_add(&(acm->ru[i].list), &acm->spare_read_urbs); - } - for (i = 0; i < acm->rx_buflimit; i++) { + for (i = 0; i < acm->rx_buflimit; i++) list_add(&(acm->rb[i].list), &acm->spare_read_bufs); - } acm->throttle = 0; tasklet_schedule(&acm->urb_task); - + rv = tty_port_block_til_ready(&acm->port, tty, filp); done: mutex_unlock(&acm->mutex); err_out: @@ -593,16 +613,17 @@ full_bailout: usb_kill_urb(acm->ctrlurb); bail_out: usb_autopm_put_interface(acm->control); - acm->used--; + acm->port.count--; mutex_unlock(&acm->mutex); early_bail: mutex_unlock(&open_mutex); + tty_port_tty_set(&acm->port, NULL); return -EIO; } static void acm_tty_unregister(struct acm *acm) { - int i,nr; + int i, nr; nr = acm->rx_buflimit; tty_unregister_device(acm_tty_driver, acm->minor); @@ -619,41 +640,56 @@ static void acm_tty_unregister(struct acm *acm) static int acm_tty_chars_in_buffer(struct tty_struct *tty); -static void acm_tty_close(struct tty_struct *tty, struct file *filp) +static void acm_port_down(struct acm *acm, int drain) { - struct acm *acm = tty->driver_data; - int i,nr; - - if (!acm || !acm->used) - return; - - nr = acm->rx_buflimit; + int i, nr = acm->rx_buflimit; mutex_lock(&open_mutex); - if (!--acm->used) { - if (acm->dev) { - usb_autopm_get_interface(acm->control); - acm_set_control(acm, acm->ctrlout = 0); - - /* try letting the last writes drain naturally */ + if (acm->dev) { + usb_autopm_get_interface(acm->control); + acm_set_control(acm, acm->ctrlout = 0); + /* try letting the last writes drain naturally */ + if (drain) { wait_event_interruptible_timeout(acm->drain_wait, - (ACM_NW == acm_wb_is_avail(acm)) - || !acm->dev, + (ACM_NW == acm_wb_is_avail(acm)) || !acm->dev, ACM_CLOSE_TIMEOUT * HZ); - - usb_kill_urb(acm->ctrlurb); - for (i = 0; i < ACM_NW; i++) - usb_kill_urb(acm->wb[i].urb); - for (i = 0; i < nr; i++) - usb_kill_urb(acm->ru[i].urb); - acm->control->needs_remote_wakeup = 0; - usb_autopm_put_interface(acm->control); - } else - acm_tty_unregister(acm); + } + usb_kill_urb(acm->ctrlurb); + for (i = 0; i < ACM_NW; i++) + usb_kill_urb(acm->wb[i].urb); + for (i = 0; i < nr; i++) + usb_kill_urb(acm->ru[i].urb); + acm->control->needs_remote_wakeup = 0; + usb_autopm_put_interface(acm->control); } mutex_unlock(&open_mutex); } -static int acm_tty_write(struct tty_struct *tty, const unsigned char *buf, int count) +static void acm_tty_hangup(struct tty_struct *tty) +{ + struct acm *acm = tty->driver_data; + tty_port_hangup(&acm->port); + acm_port_down(acm, 0); +} + +static void acm_tty_close(struct tty_struct *tty, struct file *filp) +{ + struct acm *acm = tty->driver_data; + + /* Perform the closing process and see if we need to do the hardware + shutdown */ + if (tty_port_close_start(&acm->port, tty, filp) == 0) + return; + acm_port_down(acm, 0); + tty_port_close_end(&acm->port, tty); + mutex_lock(&open_mutex); + tty_port_tty_set(&acm->port, NULL); + if (!acm->dev) + acm_tty_unregister(acm); + mutex_unlock(&open_mutex); +} + +static int acm_tty_write(struct tty_struct *tty, + const unsigned char *buf, int count) { struct acm *acm = tty->driver_data; int stat; @@ -669,7 +705,8 @@ static int acm_tty_write(struct tty_struct *tty, const unsigned char *buf, int c return 0; spin_lock_irqsave(&acm->write_lock, flags); - if ((wbn = acm_wb_alloc(acm)) < 0) { + wbn = acm_wb_alloc(acm); + if (wbn < 0) { spin_unlock_irqrestore(&acm->write_lock, flags); return 0; } @@ -681,7 +718,8 @@ static int acm_tty_write(struct tty_struct *tty, const unsigned char *buf, int c wb->len = count; spin_unlock_irqrestore(&acm->write_lock, flags); - if ((stat = acm_write_start(acm, wbn)) < 0) + stat = acm_write_start(acm, wbn); + if (stat < 0) return stat; return count; } @@ -767,8 +805,10 @@ static int acm_tty_tiocmset(struct tty_struct *tty, struct file *file, return -EINVAL; newctrl = acm->ctrlout; - set = (set & TIOCM_DTR ? ACM_CTRL_DTR : 0) | (set & TIOCM_RTS ? ACM_CTRL_RTS : 0); - clear = (clear & TIOCM_DTR ? ACM_CTRL_DTR : 0) | (clear & TIOCM_RTS ? ACM_CTRL_RTS : 0); + set = (set & TIOCM_DTR ? ACM_CTRL_DTR : 0) | + (set & TIOCM_RTS ? ACM_CTRL_RTS : 0); + clear = (clear & TIOCM_DTR ? ACM_CTRL_DTR : 0) | + (clear & TIOCM_RTS ? ACM_CTRL_RTS : 0); newctrl = (newctrl & ~clear) | set; @@ -777,7 +817,8 @@ static int acm_tty_tiocmset(struct tty_struct *tty, struct file *file, return acm_set_control(acm, acm->ctrlout = newctrl); } -static int acm_tty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) +static int acm_tty_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) { struct acm *acm = tty->driver_data; @@ -799,7 +840,8 @@ static const __u8 acm_tty_size[] = { 5, 6, 7, 8 }; -static void acm_tty_set_termios(struct tty_struct *tty, struct ktermios *termios_old) +static void acm_tty_set_termios(struct tty_struct *tty, + struct ktermios *termios_old) { struct acm *acm = tty->driver_data; struct ktermios *termios = tty->termios; @@ -809,19 +851,23 @@ static void acm_tty_set_termios(struct tty_struct *tty, struct ktermios *termios if (!ACM_READY(acm)) return; + /* FIXME: Needs to support the tty_baud interface */ + /* FIXME: Broken on sparc */ newline.dwDTERate = cpu_to_le32p(acm_tty_speed + (termios->c_cflag & CBAUD & ~CBAUDEX) + (termios->c_cflag & CBAUDEX ? 15 : 0)); newline.bCharFormat = termios->c_cflag & CSTOPB ? 2 : 0; newline.bParityType = termios->c_cflag & PARENB ? - (termios->c_cflag & PARODD ? 1 : 2) + (termios->c_cflag & CMSPAR ? 2 : 0) : 0; + (termios->c_cflag & PARODD ? 1 : 2) + + (termios->c_cflag & CMSPAR ? 2 : 0) : 0; newline.bDataBits = acm_tty_size[(termios->c_cflag & CSIZE) >> 4]; - + /* FIXME: Needs to clear unsupported bits in the termios */ acm->clocal = ((termios->c_cflag & CLOCAL) != 0); if (!newline.dwDTERate) { newline.dwDTERate = acm->line.dwDTERate; newctrl &= ~ACM_CTRL_DTR; - } else newctrl |= ACM_CTRL_DTR; + } else + newctrl |= ACM_CTRL_DTR; if (newctrl != acm->ctrlout) acm_set_control(acm, acm->ctrlout = newctrl); @@ -846,9 +892,8 @@ static void acm_write_buffers_free(struct acm *acm) struct acm_wb *wb; struct usb_device *usb_dev = interface_to_usbdev(acm->control); - for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++) { + for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++) usb_buffer_free(usb_dev, acm->writesize, wb->buf, wb->dmah); - } } static void acm_read_buffers_free(struct acm *acm) @@ -857,7 +902,8 @@ static void acm_read_buffers_free(struct acm *acm) int i, n = acm->rx_buflimit; for (i = 0; i < n; i++) - usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma); + usb_buffer_free(usb_dev, acm->readsize, + acm->rb[i].base, acm->rb[i].dma); } /* Little helper: write buffers allocate */ @@ -882,8 +928,8 @@ static int acm_write_buffers_alloc(struct acm *acm) return 0; } -static int acm_probe (struct usb_interface *intf, - const struct usb_device_id *id) +static int acm_probe(struct usb_interface *intf, + const struct usb_device_id *id) { struct usb_cdc_union_desc *union_header = NULL; struct usb_cdc_country_functional_desc *cfd = NULL; @@ -891,13 +937,13 @@ static int acm_probe (struct usb_interface *intf, int buflen = intf->altsetting->extralen; struct usb_interface *control_interface; struct usb_interface *data_interface; - struct usb_endpoint_descriptor *epctrl; - struct usb_endpoint_descriptor *epread; - struct usb_endpoint_descriptor *epwrite; + struct usb_endpoint_descriptor *epctrl = NULL; + struct usb_endpoint_descriptor *epread = NULL; + struct usb_endpoint_descriptor *epwrite = NULL; struct usb_device *usb_dev = interface_to_usbdev(intf); struct acm *acm; int minor; - int ctrlsize,readsize; + int ctrlsize, readsize; u8 *buf; u8 ac_management_function = 0; u8 call_management_function = 0; @@ -906,6 +952,7 @@ static int acm_probe (struct usb_interface *intf, unsigned long quirks; int num_rx_buf; int i; + int combined_interfaces = 0; /* normal quirks */ quirks = (unsigned long)id->driver_info; @@ -917,7 +964,7 @@ static int acm_probe (struct usb_interface *intf, control_interface = usb_ifnum_to_if(usb_dev, 0); goto skip_normal_probe; } - + /* normal probing*/ if (!buffer) { dev_err(&intf->dev, "Weird descriptor references\n"); @@ -925,8 +972,10 @@ static int acm_probe (struct usb_interface *intf, } if (!buflen) { - if (intf->cur_altsetting->endpoint->extralen && intf->cur_altsetting->endpoint->extra) { - dev_dbg(&intf->dev,"Seeking extra descriptors on endpoint\n"); + if (intf->cur_altsetting->endpoint->extralen && + intf->cur_altsetting->endpoint->extra) { + dev_dbg(&intf->dev, + "Seeking extra descriptors on endpoint\n"); buflen = intf->cur_altsetting->endpoint->extralen; buffer = intf->cur_altsetting->endpoint->extra; } else { @@ -937,47 +986,43 @@ static int acm_probe (struct usb_interface *intf, } while (buflen > 0) { - if (buffer [1] != USB_DT_CS_INTERFACE) { + if (buffer[1] != USB_DT_CS_INTERFACE) { dev_err(&intf->dev, "skipping garbage\n"); goto next_desc; } - switch (buffer [2]) { - case USB_CDC_UNION_TYPE: /* we've found it */ - if (union_header) { - dev_err(&intf->dev, "More than one " - "union descriptor, " - "skipping ...\n"); - goto next_desc; - } - union_header = (struct usb_cdc_union_desc *) - buffer; - break; - case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/ - cfd = (struct usb_cdc_country_functional_desc *)buffer; - break; - case USB_CDC_HEADER_TYPE: /* maybe check version */ - break; /* for now we ignore it */ - case USB_CDC_ACM_TYPE: - ac_management_function = buffer[3]; - break; - case USB_CDC_CALL_MANAGEMENT_TYPE: - call_management_function = buffer[3]; - call_interface_num = buffer[4]; - if ((call_management_function & 3) != 3) - dev_err(&intf->dev, "This device " - "cannot do calls on its own. " - "It is no modem.\n"); - break; - default: - /* there are LOTS more CDC descriptors that - * could legitimately be found here. - */ - dev_dbg(&intf->dev, "Ignoring descriptor: " - "type %02x, length %d\n", - buffer[2], buffer[0]); - break; + switch (buffer[2]) { + case USB_CDC_UNION_TYPE: /* we've found it */ + if (union_header) { + dev_err(&intf->dev, "More than one " + "union descriptor, skipping ...\n"); + goto next_desc; } + union_header = (struct usb_cdc_union_desc *)buffer; + break; + case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/ + cfd = (struct usb_cdc_country_functional_desc *)buffer; + break; + case USB_CDC_HEADER_TYPE: /* maybe check version */ + break; /* for now we ignore it */ + case USB_CDC_ACM_TYPE: + ac_management_function = buffer[3]; + break; + case USB_CDC_CALL_MANAGEMENT_TYPE: + call_management_function = buffer[3]; + call_interface_num = buffer[4]; + if ((call_management_function & 3) != 3) + dev_err(&intf->dev, "This device cannot do calls on its own. It is not a modem.\n"); + break; + default: + /* there are LOTS more CDC descriptors that + * could legitimately be found here. + */ + dev_dbg(&intf->dev, "Ignoring descriptor: " + "type %02x, length %d\n", + buffer[2], buffer[0]); + break; + } next_desc: buflen -= buffer[0]; buffer += buffer[0]; @@ -985,33 +1030,72 @@ next_desc: if (!union_header) { if (call_interface_num > 0) { - dev_dbg(&intf->dev,"No union descriptor, using call management descriptor\n"); + dev_dbg(&intf->dev, "No union descriptor, using call management descriptor\n"); data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num)); control_interface = intf; } else { - dev_dbg(&intf->dev,"No union descriptor, giving up\n"); - return -ENODEV; + if (intf->cur_altsetting->desc.bNumEndpoints != 3) { + dev_dbg(&intf->dev,"No union descriptor, giving up\n"); + return -ENODEV; + } else { + dev_warn(&intf->dev,"No union descriptor, testing for castrated device\n"); + combined_interfaces = 1; + control_interface = data_interface = intf; + goto look_for_collapsed_interface; + } } } else { control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0); data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0)); if (!control_interface || !data_interface) { - dev_dbg(&intf->dev,"no interfaces\n"); + dev_dbg(&intf->dev, "no interfaces\n"); return -ENODEV; } } - + if (data_interface_num != call_interface_num) - dev_dbg(&intf->dev,"Separate call control interface. That is not fully supported.\n"); + dev_dbg(&intf->dev, "Separate call control interface. That is not fully supported.\n"); + + if (control_interface == data_interface) { + /* some broken devices designed for windows work this way */ + dev_warn(&intf->dev,"Control and data interfaces are not separated!\n"); + combined_interfaces = 1; + /* a popular other OS doesn't use it */ + quirks |= NO_CAP_LINE; + if (data_interface->cur_altsetting->desc.bNumEndpoints != 3) { + dev_err(&intf->dev, "This needs exactly 3 endpoints\n"); + return -EINVAL; + } +look_for_collapsed_interface: + for (i = 0; i < 3; i++) { + struct usb_endpoint_descriptor *ep; + ep = &data_interface->cur_altsetting->endpoint[i].desc; + + if (usb_endpoint_is_int_in(ep)) + epctrl = ep; + else if (usb_endpoint_is_bulk_out(ep)) + epwrite = ep; + else if (usb_endpoint_is_bulk_in(ep)) + epread = ep; + else + return -EINVAL; + } + if (!epctrl || !epread || !epwrite) + return -ENODEV; + else + goto made_compressed_probe; + } skip_normal_probe: /*workaround for switched interfaces */ - if (data_interface->cur_altsetting->desc.bInterfaceClass != CDC_DATA_INTERFACE_TYPE) { - if (control_interface->cur_altsetting->desc.bInterfaceClass == CDC_DATA_INTERFACE_TYPE) { + if (data_interface->cur_altsetting->desc.bInterfaceClass + != CDC_DATA_INTERFACE_TYPE) { + if (control_interface->cur_altsetting->desc.bInterfaceClass + == CDC_DATA_INTERFACE_TYPE) { struct usb_interface *t; - dev_dbg(&intf->dev,"Your device has switched interfaces.\n"); - + dev_dbg(&intf->dev, + "Your device has switched interfaces.\n"); t = control_interface; control_interface = data_interface; data_interface = t; @@ -1021,11 +1105,12 @@ skip_normal_probe: } /* Accept probe requests only for the control interface */ - if (intf != control_interface) + if (!combined_interfaces && intf != control_interface) return -ENODEV; - - if (usb_interface_claimed(data_interface)) { /* valid in this context */ - dev_dbg(&intf->dev,"The data interface isn't available\n"); + + if (!combined_interfaces && usb_interface_claimed(data_interface)) { + /* valid in this context */ + dev_dbg(&intf->dev, "The data interface isn't available\n"); return -EBUSY; } @@ -1042,12 +1127,13 @@ skip_normal_probe: if (!usb_endpoint_dir_in(epread)) { /* descriptors are swapped */ struct usb_endpoint_descriptor *t; - dev_dbg(&intf->dev,"The data interface has switched endpoints\n"); - + dev_dbg(&intf->dev, + "The data interface has switched endpoints\n"); t = epread; epread = epwrite; epwrite = t; } +made_compressed_probe: dbg("interfaces are valid"); for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++); @@ -1056,19 +1142,24 @@ skip_normal_probe: return -ENODEV; } - if (!(acm = kzalloc(sizeof(struct acm), GFP_KERNEL))) { + acm = kzalloc(sizeof(struct acm), GFP_KERNEL); + if (acm == NULL) { dev_dbg(&intf->dev, "out of memory (acm kzalloc)\n"); goto alloc_fail; } ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize); - readsize = le16_to_cpu(epread->wMaxPacketSize)* ( quirks == SINGLE_RX_URB ? 1 : 2); + readsize = le16_to_cpu(epread->wMaxPacketSize) * + (quirks == SINGLE_RX_URB ? 1 : 2); + acm->combined_interfaces = combined_interfaces; acm->writesize = le16_to_cpu(epwrite->wMaxPacketSize) * 20; acm->control = control_interface; acm->data = data_interface; acm->minor = minor; acm->dev = usb_dev; acm->ctrl_caps = ac_management_function; + if (quirks & NO_CAP_LINE) + acm->ctrl_caps &= ~USB_CDC_CAP_LINE; acm->ctrlsize = ctrlsize; acm->readsize = readsize; acm->rx_buflimit = num_rx_buf; @@ -1082,6 +1173,8 @@ skip_normal_probe: spin_lock_init(&acm->read_lock); mutex_init(&acm->mutex); acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress); + tty_port_init(&acm->port); + acm->port.ops = &acm_port_ops; buf = usb_buffer_alloc(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma); if (!buf) { @@ -1103,8 +1196,10 @@ skip_normal_probe: for (i = 0; i < num_rx_buf; i++) { struct acm_ru *rcv = &(acm->ru[i]); - if (!(rcv->urb = usb_alloc_urb(0, GFP_KERNEL))) { - dev_dbg(&intf->dev, "out of memory (read urbs usb_alloc_urb)\n"); + rcv->urb = usb_alloc_urb(0, GFP_KERNEL); + if (rcv->urb == NULL) { + dev_dbg(&intf->dev, + "out of memory (read urbs usb_alloc_urb)\n"); goto alloc_fail7; } @@ -1117,26 +1212,29 @@ skip_normal_probe: rb->base = usb_buffer_alloc(acm->dev, readsize, GFP_KERNEL, &rb->dma); if (!rb->base) { - dev_dbg(&intf->dev, "out of memory (read bufs usb_buffer_alloc)\n"); + dev_dbg(&intf->dev, + "out of memory (read bufs usb_buffer_alloc)\n"); goto alloc_fail7; } } - for(i = 0; i < ACM_NW; i++) - { + for (i = 0; i < ACM_NW; i++) { struct acm_wb *snd = &(acm->wb[i]); - if (!(snd->urb = usb_alloc_urb(0, GFP_KERNEL))) { - dev_dbg(&intf->dev, "out of memory (write urbs usb_alloc_urb)"); + snd->urb = usb_alloc_urb(0, GFP_KERNEL); + if (snd->urb == NULL) { + dev_dbg(&intf->dev, + "out of memory (write urbs usb_alloc_urb)"); goto alloc_fail7; } - usb_fill_bulk_urb(snd->urb, usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress), - NULL, acm->writesize, acm_write_bulk, snd); + usb_fill_bulk_urb(snd->urb, usb_dev, + usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress), + NULL, acm->writesize, acm_write_bulk, snd); snd->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; snd->instance = acm; } - usb_set_intfdata (intf, acm); + usb_set_intfdata(intf, acm); i = device_create_file(&intf->dev, &dev_attr_bmCapabilities); if (i < 0) @@ -1147,7 +1245,8 @@ skip_normal_probe: if (!acm->country_codes) goto skip_countries; acm->country_code_size = cfd->bLength - 4; - memcpy(acm->country_codes, (u8 *)&cfd->wCountyCode0, cfd->bLength - 4); + memcpy(acm->country_codes, (u8 *)&cfd->wCountyCode0, + cfd->bLength - 4); acm->country_rel_date = cfd->iCountryCodeRelDate; i = device_create_file(&intf->dev, &dev_attr_wCountryCodes); @@ -1156,7 +1255,8 @@ skip_normal_probe: goto skip_countries; } - i = device_create_file(&intf->dev, &dev_attr_iCountryCodeRelDate); + i = device_create_file(&intf->dev, + &dev_attr_iCountryCodeRelDate); if (i < 0) { kfree(acm->country_codes); goto skip_countries; @@ -1164,8 +1264,11 @@ skip_normal_probe: } skip_countries: - usb_fill_int_urb(acm->ctrlurb, usb_dev, usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress), - acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval); + usb_fill_int_urb(acm->ctrlurb, usb_dev, + usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress), + acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm, + /* works around buggy devices */ + epctrl->bInterval ? epctrl->bInterval : 0xff); acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; acm->ctrlurb->transfer_dma = acm->ctrl_dma; @@ -1212,7 +1315,7 @@ static void stop_data_traffic(struct acm *acm) tasklet_disable(&acm->urb_task); usb_kill_urb(acm->ctrlurb); - for(i = 0; i < ACM_NW; i++) + for (i = 0; i < ACM_NW; i++) usb_kill_urb(acm->wb[i].urb); for (i = 0; i < acm->rx_buflimit; i++) usb_kill_urb(acm->ru[i].urb); @@ -1227,13 +1330,14 @@ static void acm_disconnect(struct usb_interface *intf) { struct acm *acm = usb_get_intfdata(intf); struct usb_device *usb_dev = interface_to_usbdev(intf); + struct tty_struct *tty; /* sibling interface is already cleaning up */ if (!acm) return; mutex_lock(&open_mutex); - if (acm->country_codes){ + if (acm->country_codes) { device_remove_file(&acm->control->dev, &dev_attr_wCountryCodes); device_remove_file(&acm->control->dev, @@ -1247,22 +1351,26 @@ static void acm_disconnect(struct usb_interface *intf) stop_data_traffic(acm); acm_write_buffers_free(acm); - usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma); + usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer, + acm->ctrl_dma); acm_read_buffers_free(acm); - usb_driver_release_interface(&acm_driver, intf == acm->control ? + if (!acm->combined_interfaces) + usb_driver_release_interface(&acm_driver, intf == acm->control ? acm->data : acm->control); - if (!acm->used) { + if (acm->port.count == 0) { acm_tty_unregister(acm); mutex_unlock(&open_mutex); return; } mutex_unlock(&open_mutex); - - if (acm->tty) - tty_hangup(acm->tty); + tty = tty_port_tty_get(&acm->port); + if (tty) { + tty_hangup(tty); + tty_kref_put(tty); + } } #ifdef CONFIG_PM @@ -1297,7 +1405,7 @@ static int acm_suspend(struct usb_interface *intf, pm_message_t message) */ mutex_lock(&acm->mutex); - if (acm->used) + if (acm->port.count) stop_data_traffic(acm); mutex_unlock(&acm->mutex); @@ -1319,7 +1427,7 @@ static int acm_resume(struct usb_interface *intf) return 0; mutex_lock(&acm->mutex); - if (acm->used) { + if (acm->port.count) { rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO); if (rv < 0) goto err_out; @@ -1387,6 +1495,9 @@ static struct usb_device_id acm_ids[] = { Maybe we should define a new quirk for this. */ }, + { USB_DEVICE(0x1bbb, 0x0003), /* Alcatel OT-I650 */ + .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */ + }, /* control interfaces with various AT-command sets */ { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, @@ -1398,7 +1509,7 @@ static struct usb_device_id acm_ids[] = { { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, USB_CDC_ACM_PROTO_AT_GSM) }, { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, - USB_CDC_ACM_PROTO_AT_3G ) }, + USB_CDC_ACM_PROTO_AT_3G) }, { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, USB_CDC_ACM_PROTO_AT_CDMA) }, @@ -1406,7 +1517,7 @@ static struct usb_device_id acm_ids[] = { { } }; -MODULE_DEVICE_TABLE (usb, acm_ids); +MODULE_DEVICE_TABLE(usb, acm_ids); static struct usb_driver acm_driver = { .name = "cdc_acm", @@ -1429,6 +1540,7 @@ static struct usb_driver acm_driver = { static const struct tty_operations acm_ops = { .open = acm_tty_open, .close = acm_tty_close, + .hangup = acm_tty_hangup, .write = acm_tty_write, .write_room = acm_tty_write_room, .ioctl = acm_tty_ioctl, @@ -1460,7 +1572,8 @@ static int __init acm_init(void) acm_tty_driver->subtype = SERIAL_TYPE_NORMAL, acm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; acm_tty_driver->init_termios = tty_std_termios; - acm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; + acm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | + HUPCL | CLOCAL; tty_set_operations(acm_tty_driver, &acm_ops); retval = tty_register_driver(acm_tty_driver); @@ -1492,7 +1605,7 @@ static void __exit acm_exit(void) module_init(acm_init); module_exit(acm_exit); -MODULE_AUTHOR( DRIVER_AUTHOR ); -MODULE_DESCRIPTION( DRIVER_DESC ); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); MODULE_ALIAS_CHARDEV_MAJOR(ACM_TTY_MAJOR); diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h index 1f95e7aa1b66..1602324808ba 100644 --- a/drivers/usb/class/cdc-acm.h +++ b/drivers/usb/class/cdc-acm.h @@ -89,8 +89,8 @@ struct acm { struct usb_device *dev; /* the corresponding usb device */ struct usb_interface *control; /* control interface */ struct usb_interface *data; /* data interface */ - struct tty_struct *tty; /* the corresponding tty */ - struct urb *ctrlurb; /* urbs */ + struct tty_port port; /* our tty port data */ + struct urb *ctrlurb; /* urbs */ u8 *ctrl_buffer; /* buffers of urbs */ dma_addr_t ctrl_dma; /* dma handles of buffers */ u8 *country_codes; /* country codes from device */ @@ -120,12 +120,12 @@ struct acm { unsigned int ctrlout; /* output control lines (DTR, RTS) */ unsigned int writesize; /* max packet size for the output bulk endpoint */ unsigned int readsize,ctrlsize; /* buffer sizes for freeing */ - unsigned int used; /* someone has this acm's device open */ unsigned int minor; /* acm minor number */ unsigned char throttle; /* throttled by tty layer */ unsigned char clocal; /* termios CLOCAL */ unsigned int ctrl_caps; /* control capabilities from the class specific header */ unsigned int susp_count; /* number of suspended interfaces */ + int combined_interfaces:1; /* control and data collapsed */ struct acm_wb *delayed_wb; /* write queued for a device about to be woken */ }; @@ -134,3 +134,4 @@ struct acm { /* constants describing various quirks and errors */ #define NO_UNION_NORMAL 1 #define SINGLE_RX_URB 2 +#define NO_CAP_LINE 4 diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index d2747a49b974..26c09f0257db 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -1057,8 +1057,14 @@ static const struct file_operations usblp_fops = { .release = usblp_release, }; +static char *usblp_nodename(struct device *dev) +{ + return kasprintf(GFP_KERNEL, "usb/%s", dev_name(dev)); +} + static struct usb_class_driver usblp_class = { .name = "lp%d", + .nodename = usblp_nodename, .fops = &usblp_fops, .minor_base = USBLP_MINOR_BASE, }; diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index c40a9b284cc9..3703789d0d2a 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -927,21 +927,27 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) switch (cmd) { case USBTMC_IOCTL_CLEAR_OUT_HALT: retval = usbtmc_ioctl_clear_out_halt(data); + break; case USBTMC_IOCTL_CLEAR_IN_HALT: retval = usbtmc_ioctl_clear_in_halt(data); + break; case USBTMC_IOCTL_INDICATOR_PULSE: retval = usbtmc_ioctl_indicator_pulse(data); + break; case USBTMC_IOCTL_CLEAR: retval = usbtmc_ioctl_clear(data); + break; case USBTMC_IOCTL_ABORT_BULK_OUT: retval = usbtmc_ioctl_abort_bulk_out(data); + break; case USBTMC_IOCTL_ABORT_BULK_IN: retval = usbtmc_ioctl_abort_bulk_in(data); + break; } mutex_unlock(&data->io_mutex); diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig index e1759d17ac5d..69280c35b5cb 100644 --- a/drivers/usb/core/Kconfig +++ b/drivers/usb/core/Kconfig @@ -28,7 +28,7 @@ comment "Miscellaneous USB options" depends on USB config USB_DEVICEFS - bool "USB device filesystem" + bool "USB device filesystem (DEPRECATED)" if EMBEDDED depends on USB ---help--- If you say Y here (and to "/proc file system support" in the "File @@ -46,11 +46,15 @@ config USB_DEVICEFS For the format of the various /proc/bus/usb/ files, please read . - Usbfs files can't handle Access Control Lists (ACL), which are the - default way to grant access to USB devices for untrusted users of a - desktop system. The usbfs functionality is replaced by real - device-nodes managed by udev. These nodes live in /dev/bus/usb and - are used by libusb. + Modern Linux systems do not use this. + + Usbfs entries are files and not character devices; usbfs can't + handle Access Control Lists (ACL) which are the default way to + grant access to USB devices for untrusted users of a desktop + system. + + The usbfs functionality is replaced by real device-nodes managed by + udev. These nodes lived in /dev/bus/usb and are used by libusb. config USB_DEVICE_CLASS bool "USB device class-devices (DEPRECATED)" diff --git a/drivers/usb/core/Makefile b/drivers/usb/core/Makefile index b6078706fb93..ec16e6029905 100644 --- a/drivers/usb/core/Makefile +++ b/drivers/usb/core/Makefile @@ -4,14 +4,14 @@ usbcore-objs := usb.o hub.o hcd.o urb.o message.o driver.o \ config.o file.o buffer.o sysfs.o endpoint.o \ - devio.o notify.o generic.o quirks.o + devio.o notify.o generic.o quirks.o devices.o ifeq ($(CONFIG_PCI),y) usbcore-objs += hcd-pci.o endif ifeq ($(CONFIG_USB_DEVICEFS),y) - usbcore-objs += inode.o devices.o + usbcore-objs += inode.o endif obj-$(CONFIG_USB) += usbcore.o diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index 568244c99bdc..24dfb33f90cb 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -19,6 +19,32 @@ static inline const char *plural(int n) return (n == 1 ? "" : "s"); } +/* FIXME: this is a kludge */ +static int find_next_descriptor_more(unsigned char *buffer, int size, + int dt1, int dt2, int dt3, int *num_skipped) +{ + struct usb_descriptor_header *h; + int n = 0; + unsigned char *buffer0 = buffer; + + /* Find the next descriptor of type dt1 or dt2 or dt3 */ + while (size > 0) { + h = (struct usb_descriptor_header *) buffer; + if (h->bDescriptorType == dt1 || h->bDescriptorType == dt2 || + h->bDescriptorType == dt3) + break; + buffer += h->bLength; + size -= h->bLength; + ++n; + } + + /* Store the number of descriptors skipped and return the + * number of bytes skipped */ + if (num_skipped) + *num_skipped = n; + return buffer - buffer0; +} + static int find_next_descriptor(unsigned char *buffer, int size, int dt1, int dt2, int *num_skipped) { @@ -43,6 +69,129 @@ static int find_next_descriptor(unsigned char *buffer, int size, return buffer - buffer0; } +static int usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno, + int inum, int asnum, struct usb_host_endpoint *ep, + int num_ep, unsigned char *buffer, int size) +{ + unsigned char *buffer_start = buffer; + struct usb_ss_ep_comp_descriptor *desc; + int retval; + int num_skipped; + int max_tx; + int i; + + /* Allocate space for the SS endpoint companion descriptor */ + ep->ss_ep_comp = kzalloc(sizeof(struct usb_host_ss_ep_comp), + GFP_KERNEL); + if (!ep->ss_ep_comp) + return -ENOMEM; + desc = (struct usb_ss_ep_comp_descriptor *) buffer; + if (desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP) { + dev_warn(ddev, "No SuperSpeed endpoint companion for config %d " + " interface %d altsetting %d ep %d: " + "using minimum values\n", + cfgno, inum, asnum, ep->desc.bEndpointAddress); + ep->ss_ep_comp->desc.bLength = USB_DT_SS_EP_COMP_SIZE; + ep->ss_ep_comp->desc.bDescriptorType = USB_DT_SS_ENDPOINT_COMP; + ep->ss_ep_comp->desc.bMaxBurst = 0; + /* + * Leave bmAttributes as zero, which will mean no streams for + * bulk, and isoc won't support multiple bursts of packets. + * With bursts of only one packet, and a Mult of 1, the max + * amount of data moved per endpoint service interval is one + * packet. + */ + if (usb_endpoint_xfer_isoc(&ep->desc) || + usb_endpoint_xfer_int(&ep->desc)) + ep->ss_ep_comp->desc.wBytesPerInterval = + ep->desc.wMaxPacketSize; + /* + * The next descriptor is for an Endpoint or Interface, + * no extra descriptors to copy into the companion structure, + * and we didn't eat up any of the buffer. + */ + retval = 0; + goto valid; + } + memcpy(&ep->ss_ep_comp->desc, desc, USB_DT_SS_EP_COMP_SIZE); + desc = &ep->ss_ep_comp->desc; + buffer += desc->bLength; + size -= desc->bLength; + + /* Eat up the other descriptors we don't care about */ + ep->ss_ep_comp->extra = buffer; + i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT, + USB_DT_INTERFACE, &num_skipped); + ep->ss_ep_comp->extralen = i; + buffer += i; + size -= i; + retval = buffer - buffer_start + i; + if (num_skipped > 0) + dev_dbg(ddev, "skipped %d descriptor%s after %s\n", + num_skipped, plural(num_skipped), + "SuperSpeed endpoint companion"); + + /* Check the various values */ + if (usb_endpoint_xfer_control(&ep->desc) && desc->bMaxBurst != 0) { + dev_warn(ddev, "Control endpoint with bMaxBurst = %d in " + "config %d interface %d altsetting %d ep %d: " + "setting to zero\n", desc->bMaxBurst, + cfgno, inum, asnum, ep->desc.bEndpointAddress); + desc->bMaxBurst = 0; + } + if (desc->bMaxBurst > 15) { + dev_warn(ddev, "Endpoint with bMaxBurst = %d in " + "config %d interface %d altsetting %d ep %d: " + "setting to 15\n", desc->bMaxBurst, + cfgno, inum, asnum, ep->desc.bEndpointAddress); + desc->bMaxBurst = 15; + } + if ((usb_endpoint_xfer_control(&ep->desc) || usb_endpoint_xfer_int(&ep->desc)) + && desc->bmAttributes != 0) { + dev_warn(ddev, "%s endpoint with bmAttributes = %d in " + "config %d interface %d altsetting %d ep %d: " + "setting to zero\n", + usb_endpoint_xfer_control(&ep->desc) ? "Control" : "Bulk", + desc->bmAttributes, + cfgno, inum, asnum, ep->desc.bEndpointAddress); + desc->bmAttributes = 0; + } + if (usb_endpoint_xfer_bulk(&ep->desc) && desc->bmAttributes > 16) { + dev_warn(ddev, "Bulk endpoint with more than 65536 streams in " + "config %d interface %d altsetting %d ep %d: " + "setting to max\n", + cfgno, inum, asnum, ep->desc.bEndpointAddress); + desc->bmAttributes = 16; + } + if (usb_endpoint_xfer_isoc(&ep->desc) && desc->bmAttributes > 2) { + dev_warn(ddev, "Isoc endpoint has Mult of %d in " + "config %d interface %d altsetting %d ep %d: " + "setting to 3\n", desc->bmAttributes + 1, + cfgno, inum, asnum, ep->desc.bEndpointAddress); + desc->bmAttributes = 2; + } + if (usb_endpoint_xfer_isoc(&ep->desc)) { + max_tx = ep->desc.wMaxPacketSize * (desc->bMaxBurst + 1) * + (desc->bmAttributes + 1); + } else if (usb_endpoint_xfer_int(&ep->desc)) { + max_tx = ep->desc.wMaxPacketSize * (desc->bMaxBurst + 1); + } else { + goto valid; + } + if (desc->wBytesPerInterval > max_tx) { + dev_warn(ddev, "%s endpoint with wBytesPerInterval of %d in " + "config %d interface %d altsetting %d ep %d: " + "setting to %d\n", + usb_endpoint_xfer_isoc(&ep->desc) ? "Isoc" : "Int", + desc->wBytesPerInterval, + cfgno, inum, asnum, ep->desc.bEndpointAddress, + max_tx); + desc->wBytesPerInterval = max_tx; + } +valid: + return retval; +} + static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, int asnum, struct usb_host_interface *ifp, int num_ep, unsigned char *buffer, int size) @@ -50,7 +199,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, unsigned char *buffer0 = buffer; struct usb_endpoint_descriptor *d; struct usb_host_endpoint *endpoint; - int n, i, j; + int n, i, j, retval; d = (struct usb_endpoint_descriptor *) buffer; buffer += d->bLength; @@ -92,6 +241,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, if (usb_endpoint_xfer_int(d)) { i = 1; switch (to_usb_device(ddev)->speed) { + case USB_SPEED_SUPER: case USB_SPEED_HIGH: /* Many device manufacturers are using full-speed * bInterval values in high-speed interrupt endpoint @@ -161,17 +311,39 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, cfgno, inum, asnum, d->bEndpointAddress, maxp); } + /* Allocate room for and parse any SS endpoint companion descriptors */ + if (to_usb_device(ddev)->speed == USB_SPEED_SUPER) { + endpoint->extra = buffer; + i = find_next_descriptor_more(buffer, size, USB_DT_SS_ENDPOINT_COMP, + USB_DT_ENDPOINT, USB_DT_INTERFACE, &n); + endpoint->extralen = i; + buffer += i; + size -= i; - /* Skip over any Class Specific or Vendor Specific descriptors; - * find the next endpoint or interface descriptor */ - endpoint->extra = buffer; - i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT, - USB_DT_INTERFACE, &n); - endpoint->extralen = i; + if (size > 0) { + retval = usb_parse_ss_endpoint_companion(ddev, cfgno, + inum, asnum, endpoint, num_ep, buffer, + size); + if (retval >= 0) { + buffer += retval; + retval = buffer - buffer0; + } + } else { + retval = buffer - buffer0; + } + } else { + /* Skip over any Class Specific or Vendor Specific descriptors; + * find the next endpoint or interface descriptor */ + endpoint->extra = buffer; + i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT, + USB_DT_INTERFACE, &n); + endpoint->extralen = i; + retval = buffer - buffer0 + i; + } if (n > 0) dev_dbg(ddev, "skipped %d descriptor%s after %s\n", n, plural(n), "endpoint"); - return buffer - buffer0 + i; + return retval; skip_to_next_endpoint_or_interface_descriptor: i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT, @@ -452,6 +624,8 @@ static int usb_parse_configuration(struct device *ddev, int cfgidx, kref_init(&intfc->ref); } + /* FIXME: parse the BOS descriptor */ + /* Skip over any Class Specific or Vendor Specific descriptors; * find the first interface descriptor */ config->extra = buffer; diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index d0a21a5f8201..69e5773abfce 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -154,16 +154,11 @@ static const struct usb_device_id *usb_match_dynamic_id(struct usb_interface *in static int usb_probe_device(struct device *dev) { struct usb_device_driver *udriver = to_usb_device_driver(dev->driver); - struct usb_device *udev; + struct usb_device *udev = to_usb_device(dev); int error = -ENODEV; dev_dbg(dev, "%s\n", __func__); - if (!is_usb_device(dev)) /* Sanity check */ - return error; - - udev = to_usb_device(dev); - /* TODO: Add real matching code */ /* The device should always appear to be in use @@ -203,18 +198,13 @@ static void usb_cancel_queued_reset(struct usb_interface *iface) static int usb_probe_interface(struct device *dev) { struct usb_driver *driver = to_usb_driver(dev->driver); - struct usb_interface *intf; - struct usb_device *udev; + struct usb_interface *intf = to_usb_interface(dev); + struct usb_device *udev = interface_to_usbdev(intf); const struct usb_device_id *id; int error = -ENODEV; dev_dbg(dev, "%s\n", __func__); - if (is_usb_device(dev)) /* Sanity check */ - return error; - - intf = to_usb_interface(dev); - udev = interface_to_usbdev(intf); intf->needs_binding = 0; if (udev->authorized == 0) { @@ -385,7 +375,6 @@ void usb_driver_release_interface(struct usb_driver *driver, struct usb_interface *iface) { struct device *dev = &iface->dev; - struct usb_device *udev = interface_to_usbdev(iface); /* this should never happen, don't release something that's not ours */ if (!dev->driver || dev->driver != &driver->drvwrap.driver) @@ -394,23 +383,19 @@ void usb_driver_release_interface(struct usb_driver *driver, /* don't release from within disconnect() */ if (iface->condition != USB_INTERFACE_BOUND) return; + iface->condition = USB_INTERFACE_UNBINDING; - /* don't release if the interface hasn't been added yet */ + /* Release via the driver core only if the interface + * has already been registered + */ if (device_is_registered(dev)) { - iface->condition = USB_INTERFACE_UNBINDING; device_release_driver(dev); } else { - iface->condition = USB_INTERFACE_UNBOUND; - usb_cancel_queued_reset(iface); + down(&dev->sem); + usb_unbind_interface(dev); + dev->driver = NULL; + up(&dev->sem); } - dev->driver = NULL; - usb_set_intfdata(iface, NULL); - - usb_pm_lock(udev); - iface->condition = USB_INTERFACE_UNBOUND; - mark_quiesced(iface); - iface->needs_remote_wakeup = 0; - usb_pm_unlock(udev); } EXPORT_SYMBOL_GPL(usb_driver_release_interface); @@ -598,7 +583,7 @@ static int usb_device_match(struct device *dev, struct device_driver *drv) /* TODO: Add real matching code */ return 1; - } else { + } else if (is_usb_interface(dev)) { struct usb_interface *intf; struct usb_driver *usb_drv; const struct usb_device_id *id; @@ -630,11 +615,14 @@ static int usb_uevent(struct device *dev, struct kobj_uevent_env *env) /* driver is often null here; dev_dbg() would oops */ pr_debug("usb %s: uevent\n", dev_name(dev)); - if (is_usb_device(dev)) + if (is_usb_device(dev)) { usb_dev = to_usb_device(dev); - else { + } else if (is_usb_interface(dev)) { struct usb_interface *intf = to_usb_interface(dev); + usb_dev = interface_to_usbdev(intf); + } else { + return 0; } if (usb_dev->devnum < 0) { @@ -1762,6 +1750,7 @@ int usb_suspend(struct device *dev, pm_message_t msg) int usb_resume(struct device *dev, pm_message_t msg) { struct usb_device *udev; + int status; udev = to_usb_device(dev); @@ -1771,7 +1760,14 @@ int usb_resume(struct device *dev, pm_message_t msg) */ if (udev->skip_sys_resume) return 0; - return usb_external_resume_device(udev, msg); + status = usb_external_resume_device(udev, msg); + + /* Avoid PM error messages for devices disconnected while suspended + * as we'll display regular disconnect messages just a bit later. + */ + if (status == -ENODEV) + return 0; + return status; } #endif /* CONFIG_PM */ diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c index 40dee2ac0133..bc39fc40bbde 100644 --- a/drivers/usb/core/endpoint.c +++ b/drivers/usb/core/endpoint.c @@ -15,19 +15,18 @@ #include #include "usb.h" -#define MAX_ENDPOINT_MINORS (64*128*32) -static int usb_endpoint_major; -static DEFINE_IDR(endpoint_idr); - struct ep_device { struct usb_endpoint_descriptor *desc; struct usb_device *udev; struct device dev; - int minor; }; #define to_ep_device(_dev) \ container_of(_dev, struct ep_device, dev) +struct device_type usb_ep_device_type = { + .name = "usb_endpoint", +}; + struct ep_attribute { struct attribute attr; ssize_t (*show)(struct usb_device *, @@ -160,118 +159,10 @@ static struct attribute_group *ep_dev_groups[] = { NULL }; -static int usb_endpoint_major_init(void) -{ - dev_t dev; - int error; - - error = alloc_chrdev_region(&dev, 0, MAX_ENDPOINT_MINORS, - "usb_endpoint"); - if (error) { - printk(KERN_ERR "Unable to get a dynamic major for " - "usb endpoints.\n"); - return error; - } - usb_endpoint_major = MAJOR(dev); - - return error; -} - -static void usb_endpoint_major_cleanup(void) -{ - unregister_chrdev_region(MKDEV(usb_endpoint_major, 0), - MAX_ENDPOINT_MINORS); -} - -static int endpoint_get_minor(struct ep_device *ep_dev) -{ - static DEFINE_MUTEX(minor_lock); - int retval = -ENOMEM; - int id; - - mutex_lock(&minor_lock); - if (idr_pre_get(&endpoint_idr, GFP_KERNEL) == 0) - goto exit; - - retval = idr_get_new(&endpoint_idr, ep_dev, &id); - if (retval < 0) { - if (retval == -EAGAIN) - retval = -ENOMEM; - goto exit; - } - ep_dev->minor = id & MAX_ID_MASK; -exit: - mutex_unlock(&minor_lock); - return retval; -} - -static void endpoint_free_minor(struct ep_device *ep_dev) -{ - idr_remove(&endpoint_idr, ep_dev->minor); -} - -static struct endpoint_class { - struct kref kref; - struct class *class; -} *ep_class; - -static int init_endpoint_class(void) -{ - int result = 0; - - if (ep_class != NULL) { - kref_get(&ep_class->kref); - goto exit; - } - - ep_class = kmalloc(sizeof(*ep_class), GFP_KERNEL); - if (!ep_class) { - result = -ENOMEM; - goto exit; - } - - kref_init(&ep_class->kref); - ep_class->class = class_create(THIS_MODULE, "usb_endpoint"); - if (IS_ERR(ep_class->class)) { - result = PTR_ERR(ep_class->class); - goto class_create_error; - } - - result = usb_endpoint_major_init(); - if (result) - goto endpoint_major_error; - - goto exit; - -endpoint_major_error: - class_destroy(ep_class->class); -class_create_error: - kfree(ep_class); - ep_class = NULL; -exit: - return result; -} - -static void release_endpoint_class(struct kref *kref) -{ - /* Ok, we cheat as we know we only have one ep_class */ - class_destroy(ep_class->class); - kfree(ep_class); - ep_class = NULL; - usb_endpoint_major_cleanup(); -} - -static void destroy_endpoint_class(void) -{ - if (ep_class) - kref_put(&ep_class->kref, release_endpoint_class); -} - static void ep_device_release(struct device *dev) { struct ep_device *ep_dev = to_ep_device(dev); - endpoint_free_minor(ep_dev); kfree(ep_dev); } @@ -279,62 +170,32 @@ int usb_create_ep_devs(struct device *parent, struct usb_host_endpoint *endpoint, struct usb_device *udev) { - char name[8]; struct ep_device *ep_dev; int retval; - retval = init_endpoint_class(); - if (retval) - goto exit; - ep_dev = kzalloc(sizeof(*ep_dev), GFP_KERNEL); if (!ep_dev) { retval = -ENOMEM; - goto error_alloc; - } - - retval = endpoint_get_minor(ep_dev); - if (retval) { - dev_err(parent, "can not allocate minor number for %s\n", - dev_name(&ep_dev->dev)); - goto error_register; + goto exit; } ep_dev->desc = &endpoint->desc; ep_dev->udev = udev; ep_dev->dev.groups = ep_dev_groups; - ep_dev->dev.devt = MKDEV(usb_endpoint_major, ep_dev->minor); - ep_dev->dev.class = ep_class->class; + ep_dev->dev.type = &usb_ep_device_type; ep_dev->dev.parent = parent; ep_dev->dev.release = ep_device_release; - dev_set_name(&ep_dev->dev, "usbdev%d.%d_ep%02x", - udev->bus->busnum, udev->devnum, - endpoint->desc.bEndpointAddress); + dev_set_name(&ep_dev->dev, "ep_%02x", endpoint->desc.bEndpointAddress); retval = device_register(&ep_dev->dev); if (retval) - goto error_chrdev; + goto error_register; - /* create the symlink to the old-style "ep_XX" directory */ - sprintf(name, "ep_%02x", endpoint->desc.bEndpointAddress); - retval = sysfs_create_link(&parent->kobj, &ep_dev->dev.kobj, name); - if (retval) - goto error_link; endpoint->ep_dev = ep_dev; return retval; -error_link: - device_unregister(&ep_dev->dev); - destroy_endpoint_class(); - return retval; - -error_chrdev: - endpoint_free_minor(ep_dev); - error_register: kfree(ep_dev); -error_alloc: - destroy_endpoint_class(); exit: return retval; } @@ -344,12 +205,7 @@ void usb_remove_ep_devs(struct usb_host_endpoint *endpoint) struct ep_device *ep_dev = endpoint->ep_dev; if (ep_dev) { - char name[8]; - - sprintf(name, "ep_%02x", endpoint->desc.bEndpointAddress); - sysfs_remove_link(&ep_dev->dev.parent->kobj, name); device_unregister(&ep_dev->dev); endpoint->ep_dev = NULL; - destroy_endpoint_class(); } } diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c index 997e659ff693..5cef88929b3e 100644 --- a/drivers/usb/core/file.c +++ b/drivers/usb/core/file.c @@ -67,6 +67,16 @@ static struct usb_class { struct class *class; } *usb_class; +static char *usb_nodename(struct device *dev) +{ + struct usb_class_driver *drv; + + drv = dev_get_drvdata(dev); + if (!drv || !drv->nodename) + return NULL; + return drv->nodename(dev); +} + static int init_usb_class(void) { int result = 0; @@ -90,6 +100,7 @@ static int init_usb_class(void) kfree(usb_class); usb_class = NULL; } + usb_class->class->nodename = usb_nodename; exit: return result; @@ -198,7 +209,7 @@ int usb_register_dev(struct usb_interface *intf, else temp = name; intf->usb_dev = device_create(usb_class->class, &intf->dev, - MKDEV(USB_MAJOR, minor), NULL, + MKDEV(USB_MAJOR, minor), class_driver, "%s", temp); if (IS_ERR(intf->usb_dev)) { down_write(&minor_rwsem); diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index a4301dc02d27..91f2885b6ee1 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -185,180 +185,6 @@ void usb_hcd_pci_remove(struct pci_dev *dev) } EXPORT_SYMBOL_GPL(usb_hcd_pci_remove); - -#ifdef CONFIG_PM - -/** - * usb_hcd_pci_suspend - power management suspend of a PCI-based HCD - * @dev: USB Host Controller being suspended - * @message: Power Management message describing this state transition - * - * Store this function in the HCD's struct pci_driver as .suspend. - */ -int usb_hcd_pci_suspend(struct pci_dev *dev, pm_message_t message) -{ - struct usb_hcd *hcd = pci_get_drvdata(dev); - int retval = 0; - int wake, w; - int has_pci_pm; - - /* Root hub suspend should have stopped all downstream traffic, - * and all bus master traffic. And done so for both the interface - * and the stub usb_device (which we check here). But maybe it - * didn't; writing sysfs power/state files ignores such rules... - * - * We must ignore the FREEZE vs SUSPEND distinction here, because - * otherwise the swsusp will save (and restore) garbage state. - */ - if (!(hcd->state == HC_STATE_SUSPENDED || - hcd->state == HC_STATE_HALT)) { - dev_warn(&dev->dev, "Root hub is not suspended\n"); - retval = -EBUSY; - goto done; - } - - /* We might already be suspended (runtime PM -- not yet written) */ - if (dev->current_state != PCI_D0) - goto done; - - if (hcd->driver->pci_suspend) { - retval = hcd->driver->pci_suspend(hcd, message); - suspend_report_result(hcd->driver->pci_suspend, retval); - if (retval) - goto done; - } - - synchronize_irq(dev->irq); - - /* Downstream ports from this root hub should already be quiesced, so - * there will be no DMA activity. Now we can shut down the upstream - * link (except maybe for PME# resume signaling) and enter some PCI - * low power state, if the hardware allows. - */ - pci_disable_device(dev); - - pci_save_state(dev); - - /* Don't fail on error to enable wakeup. We rely on pci code - * to reject requests the hardware can't implement, rather - * than coding the same thing. - */ - wake = (hcd->state == HC_STATE_SUSPENDED && - device_may_wakeup(&dev->dev)); - w = pci_wake_from_d3(dev, wake); - if (w < 0) - wake = w; - dev_dbg(&dev->dev, "wakeup: %d\n", wake); - - /* Don't change state if we don't need to */ - if (message.event == PM_EVENT_FREEZE || - message.event == PM_EVENT_PRETHAW) { - dev_dbg(&dev->dev, "--> no state change\n"); - goto done; - } - - has_pci_pm = pci_find_capability(dev, PCI_CAP_ID_PM); - if (!has_pci_pm) { - dev_dbg(&dev->dev, "--> PCI D0 legacy\n"); - } else { - - /* NOTE: dev->current_state becomes nonzero only here, and - * only for devices that support PCI PM. Also, exiting - * PCI_D3 (but not PCI_D1 or PCI_D2) is allowed to reset - * some device state (e.g. as part of clock reinit). - */ - retval = pci_set_power_state(dev, PCI_D3hot); - suspend_report_result(pci_set_power_state, retval); - if (retval == 0) { - dev_dbg(&dev->dev, "--> PCI D3\n"); - } else { - dev_dbg(&dev->dev, "PCI D3 suspend fail, %d\n", - retval); - pci_restore_state(dev); - } - } - -#ifdef CONFIG_PPC_PMAC - if (retval == 0) { - /* Disable ASIC clocks for USB */ - if (machine_is(powermac)) { - struct device_node *of_node; - - of_node = pci_device_to_OF_node(dev); - if (of_node) - pmac_call_feature(PMAC_FTR_USB_ENABLE, - of_node, 0, 0); - } - } -#endif - - done: - return retval; -} -EXPORT_SYMBOL_GPL(usb_hcd_pci_suspend); - -/** - * usb_hcd_pci_resume - power management resume of a PCI-based HCD - * @dev: USB Host Controller being resumed - * - * Store this function in the HCD's struct pci_driver as .resume. - */ -int usb_hcd_pci_resume(struct pci_dev *dev) -{ - struct usb_hcd *hcd; - int retval; - -#ifdef CONFIG_PPC_PMAC - /* Reenable ASIC clocks for USB */ - if (machine_is(powermac)) { - struct device_node *of_node; - - of_node = pci_device_to_OF_node(dev); - if (of_node) - pmac_call_feature(PMAC_FTR_USB_ENABLE, - of_node, 0, 1); - } -#endif - - pci_restore_state(dev); - - hcd = pci_get_drvdata(dev); - if (hcd->state != HC_STATE_SUSPENDED) { - dev_dbg(hcd->self.controller, - "can't resume, not suspended!\n"); - return 0; - } - - pci_enable_wake(dev, PCI_D0, false); - - retval = pci_enable_device(dev); - if (retval < 0) { - dev_err(&dev->dev, "can't re-enable after resume, %d!\n", - retval); - return retval; - } - - pci_set_master(dev); - - /* yes, ignore this result too... */ - (void) pci_wake_from_d3(dev, 0); - - clear_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); - - if (hcd->driver->pci_resume) { - retval = hcd->driver->pci_resume(hcd); - if (retval) { - dev_err(hcd->self.controller, - "PCI post-resume error %d!\n", retval); - usb_hc_died(hcd); - } - } - return retval; -} -EXPORT_SYMBOL_GPL(usb_hcd_pci_resume); - -#endif /* CONFIG_PM */ - /** * usb_hcd_pci_shutdown - shutdown host controller * @dev: USB Host Controller being shutdown @@ -376,3 +202,181 @@ void usb_hcd_pci_shutdown(struct pci_dev *dev) } EXPORT_SYMBOL_GPL(usb_hcd_pci_shutdown); +#ifdef CONFIG_PM_SLEEP + +static int check_root_hub_suspended(struct device *dev) +{ + struct pci_dev *pci_dev = to_pci_dev(dev); + struct usb_hcd *hcd = pci_get_drvdata(pci_dev); + + if (!(hcd->state == HC_STATE_SUSPENDED || + hcd->state == HC_STATE_HALT)) { + dev_warn(dev, "Root hub is not suspended\n"); + return -EBUSY; + } + return 0; +} + +static int hcd_pci_suspend(struct device *dev) +{ + struct pci_dev *pci_dev = to_pci_dev(dev); + struct usb_hcd *hcd = pci_get_drvdata(pci_dev); + int retval; + + /* Root hub suspend should have stopped all downstream traffic, + * and all bus master traffic. And done so for both the interface + * and the stub usb_device (which we check here). But maybe it + * didn't; writing sysfs power/state files ignores such rules... + */ + retval = check_root_hub_suspended(dev); + if (retval) + return retval; + + /* We might already be suspended (runtime PM -- not yet written) */ + if (pci_dev->current_state != PCI_D0) + return retval; + + if (hcd->driver->pci_suspend) { + retval = hcd->driver->pci_suspend(hcd); + suspend_report_result(hcd->driver->pci_suspend, retval); + if (retval) + return retval; + } + + synchronize_irq(pci_dev->irq); + + /* Downstream ports from this root hub should already be quiesced, so + * there will be no DMA activity. Now we can shut down the upstream + * link (except maybe for PME# resume signaling). We'll enter a + * low power state during suspend_noirq, if the hardware allows. + */ + pci_disable_device(pci_dev); + return retval; +} + +static int hcd_pci_suspend_noirq(struct device *dev) +{ + struct pci_dev *pci_dev = to_pci_dev(dev); + struct usb_hcd *hcd = pci_get_drvdata(pci_dev); + int retval; + + retval = check_root_hub_suspended(dev); + if (retval) + return retval; + + pci_save_state(pci_dev); + + /* If the root hub is HALTed rather than SUSPENDed, + * disallow remote wakeup. + */ + if (hcd->state == HC_STATE_HALT) + device_set_wakeup_enable(dev, 0); + dev_dbg(dev, "wakeup: %d\n", device_may_wakeup(dev)); + + /* Possibly enable remote wakeup, + * choose the appropriate low-power state, and go to that state. + */ + retval = pci_prepare_to_sleep(pci_dev); + if (retval == -EIO) { /* Low-power not supported */ + dev_dbg(dev, "--> PCI D0 legacy\n"); + retval = 0; + } else if (retval == 0) { + dev_dbg(dev, "--> PCI %s\n", + pci_power_name(pci_dev->current_state)); + } else { + suspend_report_result(pci_prepare_to_sleep, retval); + return retval; + } + +#ifdef CONFIG_PPC_PMAC + /* Disable ASIC clocks for USB */ + if (machine_is(powermac)) { + struct device_node *of_node; + + of_node = pci_device_to_OF_node(pci_dev); + if (of_node) + pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 0); + } +#endif + return retval; +} + +static int hcd_pci_resume_noirq(struct device *dev) +{ + struct pci_dev *pci_dev = to_pci_dev(dev); + +#ifdef CONFIG_PPC_PMAC + /* Reenable ASIC clocks for USB */ + if (machine_is(powermac)) { + struct device_node *of_node; + + of_node = pci_device_to_OF_node(pci_dev); + if (of_node) + pmac_call_feature(PMAC_FTR_USB_ENABLE, + of_node, 0, 1); + } +#endif + + /* Go back to D0 and disable remote wakeup */ + pci_back_from_sleep(pci_dev); + return 0; +} + +static int resume_common(struct device *dev, bool hibernated) +{ + struct pci_dev *pci_dev = to_pci_dev(dev); + struct usb_hcd *hcd = pci_get_drvdata(pci_dev); + int retval; + + if (hcd->state != HC_STATE_SUSPENDED) { + dev_dbg(dev, "can't resume, not suspended!\n"); + return 0; + } + + retval = pci_enable_device(pci_dev); + if (retval < 0) { + dev_err(dev, "can't re-enable after resume, %d!\n", retval); + return retval; + } + + pci_set_master(pci_dev); + + clear_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); + + if (hcd->driver->pci_resume) { + retval = hcd->driver->pci_resume(hcd, hibernated); + if (retval) { + dev_err(dev, "PCI post-resume error %d!\n", retval); + usb_hc_died(hcd); + } + } + return retval; +} + +static int hcd_pci_resume(struct device *dev) +{ + return resume_common(dev, false); +} + +static int hcd_pci_restore(struct device *dev) +{ + return resume_common(dev, true); +} + +struct dev_pm_ops usb_hcd_pci_pm_ops = { + .suspend = hcd_pci_suspend, + .suspend_noirq = hcd_pci_suspend_noirq, + .resume_noirq = hcd_pci_resume_noirq, + .resume = hcd_pci_resume, + .freeze = check_root_hub_suspended, + .freeze_noirq = check_root_hub_suspended, + .thaw_noirq = NULL, + .thaw = NULL, + .poweroff = hcd_pci_suspend, + .poweroff_noirq = hcd_pci_suspend_noirq, + .restore_noirq = hcd_pci_resume_noirq, + .restore = hcd_pci_restore, +}; +EXPORT_SYMBOL_GPL(usb_hcd_pci_pm_ops); + +#endif /* CONFIG_PM_SLEEP */ diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 42b93da1085d..ce3f453f02ef 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -128,6 +128,27 @@ static inline int is_root_hub(struct usb_device *udev) #define KERNEL_REL ((LINUX_VERSION_CODE >> 16) & 0x0ff) #define KERNEL_VER ((LINUX_VERSION_CODE >> 8) & 0x0ff) +/* usb 3.0 root hub device descriptor */ +static const u8 usb3_rh_dev_descriptor[18] = { + 0x12, /* __u8 bLength; */ + 0x01, /* __u8 bDescriptorType; Device */ + 0x00, 0x03, /* __le16 bcdUSB; v3.0 */ + + 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ + 0x00, /* __u8 bDeviceSubClass; */ + 0x03, /* __u8 bDeviceProtocol; USB 3.0 hub */ + 0x09, /* __u8 bMaxPacketSize0; 2^9 = 512 Bytes */ + + 0x6b, 0x1d, /* __le16 idVendor; Linux Foundation */ + 0x02, 0x00, /* __le16 idProduct; device 0x0002 */ + KERNEL_VER, KERNEL_REL, /* __le16 bcdDevice */ + + 0x03, /* __u8 iManufacturer; */ + 0x02, /* __u8 iProduct; */ + 0x01, /* __u8 iSerialNumber; */ + 0x01 /* __u8 bNumConfigurations; */ +}; + /* usb 2.0 root hub device descriptor */ static const u8 usb2_rh_dev_descriptor [18] = { 0x12, /* __u8 bLength; */ @@ -273,6 +294,47 @@ static const u8 hs_rh_config_descriptor [] = { 0x0c /* __u8 ep_bInterval; (256ms -- usb 2.0 spec) */ }; +static const u8 ss_rh_config_descriptor[] = { + /* one configuration */ + 0x09, /* __u8 bLength; */ + 0x02, /* __u8 bDescriptorType; Configuration */ + 0x19, 0x00, /* __le16 wTotalLength; FIXME */ + 0x01, /* __u8 bNumInterfaces; (1) */ + 0x01, /* __u8 bConfigurationValue; */ + 0x00, /* __u8 iConfiguration; */ + 0xc0, /* __u8 bmAttributes; + Bit 7: must be set, + 6: Self-powered, + 5: Remote wakeup, + 4..0: resvd */ + 0x00, /* __u8 MaxPower; */ + + /* one interface */ + 0x09, /* __u8 if_bLength; */ + 0x04, /* __u8 if_bDescriptorType; Interface */ + 0x00, /* __u8 if_bInterfaceNumber; */ + 0x00, /* __u8 if_bAlternateSetting; */ + 0x01, /* __u8 if_bNumEndpoints; */ + 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */ + 0x00, /* __u8 if_bInterfaceSubClass; */ + 0x00, /* __u8 if_bInterfaceProtocol; */ + 0x00, /* __u8 if_iInterface; */ + + /* one endpoint (status change endpoint) */ + 0x07, /* __u8 ep_bLength; */ + 0x05, /* __u8 ep_bDescriptorType; Endpoint */ + 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ + 0x03, /* __u8 ep_bmAttributes; Interrupt */ + /* __le16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) + * see hub.c:hub_configure() for details. */ + (USB_MAXCHILDREN + 1 + 7) / 8, 0x00, + 0x0c /* __u8 ep_bInterval; (256ms -- usb 2.0 spec) */ + /* + * All 3.0 hubs should have an endpoint companion descriptor, + * but we're ignoring that for now. FIXME? + */ +}; + /*-------------------------------------------------------------------------*/ /* @@ -426,23 +488,39 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) case DeviceRequest | USB_REQ_GET_DESCRIPTOR: switch (wValue & 0xff00) { case USB_DT_DEVICE << 8: - if (hcd->driver->flags & HCD_USB2) + switch (hcd->driver->flags & HCD_MASK) { + case HCD_USB3: + bufp = usb3_rh_dev_descriptor; + break; + case HCD_USB2: bufp = usb2_rh_dev_descriptor; - else if (hcd->driver->flags & HCD_USB11) + break; + case HCD_USB11: bufp = usb11_rh_dev_descriptor; - else + break; + default: goto error; + } len = 18; if (hcd->has_tt) patch_protocol = 1; break; case USB_DT_CONFIG << 8: - if (hcd->driver->flags & HCD_USB2) { + switch (hcd->driver->flags & HCD_MASK) { + case HCD_USB3: + bufp = ss_rh_config_descriptor; + len = sizeof ss_rh_config_descriptor; + break; + case HCD_USB2: bufp = hs_rh_config_descriptor; len = sizeof hs_rh_config_descriptor; - } else { + break; + case HCD_USB11: bufp = fs_rh_config_descriptor; len = sizeof fs_rh_config_descriptor; + break; + default: + goto error; } if (device_can_wakeup(&hcd->self.root_hub->dev)) patch_wakeup = 1; @@ -755,23 +833,6 @@ static struct attribute_group usb_bus_attr_group = { /*-------------------------------------------------------------------------*/ -static struct class *usb_host_class; - -int usb_host_init(void) -{ - int retval = 0; - - usb_host_class = class_create(THIS_MODULE, "usb_host"); - if (IS_ERR(usb_host_class)) - retval = PTR_ERR(usb_host_class); - return retval; -} - -void usb_host_cleanup(void) -{ - class_destroy(usb_host_class); -} - /** * usb_bus_init - shared initialization code * @bus: the bus structure being initialized @@ -818,12 +879,6 @@ static int usb_register_bus(struct usb_bus *bus) set_bit (busnum, busmap.busmap); bus->busnum = busnum; - bus->dev = device_create(usb_host_class, bus->controller, MKDEV(0, 0), - bus, "usb_host%d", busnum); - result = PTR_ERR(bus->dev); - if (IS_ERR(bus->dev)) - goto error_create_class_dev; - /* Add it to the local list of buses */ list_add (&bus->bus_list, &usb_bus_list); mutex_unlock(&usb_bus_list_lock); @@ -834,8 +889,6 @@ static int usb_register_bus(struct usb_bus *bus) "number %d\n", bus->busnum); return 0; -error_create_class_dev: - clear_bit(busnum, busmap.busmap); error_find_busnum: mutex_unlock(&usb_bus_list_lock); return result; @@ -865,8 +918,6 @@ static void usb_deregister_bus (struct usb_bus *bus) usb_notify_remove_bus(bus); clear_bit (bus->busnum, busmap.busmap); - - device_unregister(bus->dev); } /** @@ -1199,7 +1250,8 @@ static int map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, /* Map the URB's buffers for DMA access. * Lower level HCD code should use *_dma exclusively, - * unless it uses pio or talks to another transport. + * unless it uses pio or talks to another transport, + * or uses the provided scatter gather list for bulk. */ if (is_root_hub(urb->dev)) return 0; @@ -1520,6 +1572,92 @@ rescan: } } +/* Check whether a new configuration or alt setting for an interface + * will exceed the bandwidth for the bus (or the host controller resources). + * Only pass in a non-NULL config or interface, not both! + * Passing NULL for both new_config and new_intf means the device will be + * de-configured by issuing a set configuration 0 command. + */ +int usb_hcd_check_bandwidth(struct usb_device *udev, + struct usb_host_config *new_config, + struct usb_interface *new_intf) +{ + int num_intfs, i, j; + struct usb_interface_cache *intf_cache; + struct usb_host_interface *alt = 0; + int ret = 0; + struct usb_hcd *hcd; + struct usb_host_endpoint *ep; + + hcd = bus_to_hcd(udev->bus); + if (!hcd->driver->check_bandwidth) + return 0; + + /* Configuration is being removed - set configuration 0 */ + if (!new_config && !new_intf) { + for (i = 1; i < 16; ++i) { + ep = udev->ep_out[i]; + if (ep) + hcd->driver->drop_endpoint(hcd, udev, ep); + ep = udev->ep_in[i]; + if (ep) + hcd->driver->drop_endpoint(hcd, udev, ep); + } + hcd->driver->check_bandwidth(hcd, udev); + return 0; + } + /* Check if the HCD says there's enough bandwidth. Enable all endpoints + * each interface's alt setting 0 and ask the HCD to check the bandwidth + * of the bus. There will always be bandwidth for endpoint 0, so it's + * ok to exclude it. + */ + if (new_config) { + num_intfs = new_config->desc.bNumInterfaces; + /* Remove endpoints (except endpoint 0, which is always on the + * schedule) from the old config from the schedule + */ + for (i = 1; i < 16; ++i) { + ep = udev->ep_out[i]; + if (ep) { + ret = hcd->driver->drop_endpoint(hcd, udev, ep); + if (ret < 0) + goto reset; + } + ep = udev->ep_in[i]; + if (ep) { + ret = hcd->driver->drop_endpoint(hcd, udev, ep); + if (ret < 0) + goto reset; + } + } + for (i = 0; i < num_intfs; ++i) { + + /* Dig the endpoints for alt setting 0 out of the + * interface cache for this interface + */ + intf_cache = new_config->intf_cache[i]; + for (j = 0; j < intf_cache->num_altsetting; j++) { + if (intf_cache->altsetting[j].desc.bAlternateSetting == 0) + alt = &intf_cache->altsetting[j]; + } + if (!alt) { + printk(KERN_DEBUG "Did not find alt setting 0 for intf %d\n", i); + continue; + } + for (j = 0; j < alt->desc.bNumEndpoints; j++) { + ret = hcd->driver->add_endpoint(hcd, udev, &alt->endpoint[j]); + if (ret < 0) + goto reset; + } + } + } + ret = hcd->driver->check_bandwidth(hcd, udev); +reset: + if (ret < 0) + hcd->driver->reset_bandwidth(hcd, udev); + return ret; +} + /* Disables the endpoint: synchronizes with the hcd to make sure all * endpoint state is gone from hardware. usb_hcd_flush_endpoint() must * have been called previously. Use for set_configuration, set_interface, @@ -1897,8 +2035,20 @@ int usb_add_hcd(struct usb_hcd *hcd, retval = -ENOMEM; goto err_allocate_root_hub; } - rhdev->speed = (hcd->driver->flags & HCD_USB2) ? USB_SPEED_HIGH : - USB_SPEED_FULL; + + switch (hcd->driver->flags & HCD_MASK) { + case HCD_USB11: + rhdev->speed = USB_SPEED_FULL; + break; + case HCD_USB2: + rhdev->speed = USB_SPEED_HIGH; + break; + case HCD_USB3: + rhdev->speed = USB_SPEED_SUPER; + break; + default: + goto err_allocate_root_hub; + } hcd->self.root_hub = rhdev; /* wakeup flag init defaults to "everything works" for root hubs, diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index e7d4479de41c..d397ecfd5b17 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -173,6 +173,8 @@ struct hc_driver { #define HCD_LOCAL_MEM 0x0002 /* HC needs local memory */ #define HCD_USB11 0x0010 /* USB 1.1 */ #define HCD_USB2 0x0020 /* USB 2.0 */ +#define HCD_USB3 0x0040 /* USB 3.0 */ +#define HCD_MASK 0x0070 /* called to init HCD and root hub */ int (*reset) (struct usb_hcd *hcd); @@ -182,10 +184,10 @@ struct hc_driver { * a whole, not just the root hub; they're for PCI bus glue. */ /* called after suspending the hub, before entering D3 etc */ - int (*pci_suspend) (struct usb_hcd *hcd, pm_message_t message); + int (*pci_suspend)(struct usb_hcd *hcd); /* called after entering D0 (etc), before resuming the hub */ - int (*pci_resume) (struct usb_hcd *hcd); + int (*pci_resume)(struct usb_hcd *hcd, bool hibernated); /* cleanly make HCD stop writing memory and doing I/O */ void (*stop) (struct usb_hcd *hcd); @@ -224,6 +226,43 @@ struct hc_driver { void (*relinquish_port)(struct usb_hcd *, int); /* has a port been handed over to a companion? */ int (*port_handed_over)(struct usb_hcd *, int); + + /* xHCI specific functions */ + /* Called by usb_alloc_dev to alloc HC device structures */ + int (*alloc_dev)(struct usb_hcd *, struct usb_device *); + /* Called by usb_release_dev to free HC device structures */ + void (*free_dev)(struct usb_hcd *, struct usb_device *); + + /* Bandwidth computation functions */ + /* Note that add_endpoint() can only be called once per endpoint before + * check_bandwidth() or reset_bandwidth() must be called. + * drop_endpoint() can only be called once per endpoint also. + * A call to xhci_drop_endpoint() followed by a call to xhci_add_endpoint() will + * add the endpoint to the schedule with possibly new parameters denoted by a + * different endpoint descriptor in usb_host_endpoint. + * A call to xhci_add_endpoint() followed by a call to xhci_drop_endpoint() is + * not allowed. + */ + /* Allocate endpoint resources and add them to a new schedule */ + int (*add_endpoint)(struct usb_hcd *, struct usb_device *, struct usb_host_endpoint *); + /* Drop an endpoint from a new schedule */ + int (*drop_endpoint)(struct usb_hcd *, struct usb_device *, struct usb_host_endpoint *); + /* Check that a new hardware configuration, set using + * endpoint_enable and endpoint_disable, does not exceed bus + * bandwidth. This must be called before any set configuration + * or set interface requests are sent to the device. + */ + int (*check_bandwidth)(struct usb_hcd *, struct usb_device *); + /* Reset the device schedule to the last known good schedule, + * which was set from a previous successful call to + * check_bandwidth(). This reverts any add_endpoint() and + * drop_endpoint() calls since that last successful call. + * Used for when a check_bandwidth() call fails due to resource + * or bandwidth constraints. + */ + void (*reset_bandwidth)(struct usb_hcd *, struct usb_device *); + /* Returns the hardware-chosen device address */ + int (*address_device)(struct usb_hcd *, struct usb_device *udev); }; extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb); @@ -242,6 +281,9 @@ extern void usb_hcd_disable_endpoint(struct usb_device *udev, extern void usb_hcd_reset_endpoint(struct usb_device *udev, struct usb_host_endpoint *ep); extern void usb_hcd_synchronize_unlinks(struct usb_device *udev); +extern int usb_hcd_check_bandwidth(struct usb_device *udev, + struct usb_host_config *new_config, + struct usb_interface *new_intf); extern int usb_hcd_get_frame_number(struct usb_device *udev); extern struct usb_hcd *usb_create_hcd(const struct hc_driver *driver, @@ -261,14 +303,11 @@ struct pci_device_id; extern int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id); extern void usb_hcd_pci_remove(struct pci_dev *dev); - -#ifdef CONFIG_PM -extern int usb_hcd_pci_suspend(struct pci_dev *dev, pm_message_t msg); -extern int usb_hcd_pci_resume(struct pci_dev *dev); -#endif /* CONFIG_PM */ - extern void usb_hcd_pci_shutdown(struct pci_dev *dev); +#ifdef CONFIG_PM_SLEEP +extern struct dev_pm_ops usb_hcd_pci_pm_ops; +#endif #endif /* CONFIG_PCI */ /* pci-ish (pdev null is ok) buffer alloc/mapping support */ diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index be86ae3f4088..2af3b4f06054 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -155,6 +155,8 @@ static inline char *portspeed(int portstatus) return "480 Mb/s"; else if (portstatus & (1 << USB_PORT_FEAT_LOWSPEED)) return "1.5 Mb/s"; + else if (portstatus & (1 << USB_PORT_FEAT_SUPERSPEED)) + return "5.0 Gb/s"; else return "12 Mb/s"; } @@ -457,13 +459,13 @@ static void hub_tt_kevent (struct work_struct *work) spin_lock_irqsave (&hub->tt.lock, flags); while (--limit && !list_empty (&hub->tt.clear_list)) { - struct list_head *temp; + struct list_head *next; struct usb_tt_clear *clear; struct usb_device *hdev = hub->hdev; int status; - temp = hub->tt.clear_list.next; - clear = list_entry (temp, struct usb_tt_clear, clear_list); + next = hub->tt.clear_list.next; + clear = list_entry (next, struct usb_tt_clear, clear_list); list_del (&clear->clear_list); /* drop lock so HCD can concurrently report other TT errors */ @@ -951,6 +953,9 @@ static int hub_configure(struct usb_hub *hub, ret); hub->tt.hub = hdev; break; + case 3: + /* USB 3.0 hubs don't have a TT */ + break; default: dev_dbg(hub_dev, "Unrecognized hub protocol %d\n", hdev->descriptor.bDeviceProtocol); @@ -1323,6 +1328,11 @@ EXPORT_SYMBOL_GPL(usb_set_device_state); * 0 is reserved by USB for default address; (b) Linux's USB stack * uses always #1 for the root hub of the controller. So USB stack's * port #1, which is wusb virtual-port #0 has address #2. + * + * Devices connected under xHCI are not as simple. The host controller + * supports virtualization, so the hardware assigns device addresses and + * the HCD must setup data structures before issuing a set address + * command to the hardware. */ static void choose_address(struct usb_device *udev) { @@ -1642,6 +1652,9 @@ int usb_new_device(struct usb_device *udev) err = usb_configure_device(udev); /* detect & probe dev/intfs */ if (err < 0) goto fail; + dev_dbg(&udev->dev, "udev %d, busnum %d, minor = %d\n", + udev->devnum, udev->bus->busnum, + (((udev->bus->busnum-1) * 128) + (udev->devnum-1))); /* export the usbdev device-node for libusb */ udev->dev.devt = MKDEV(USB_DEVICE_MAJOR, (((udev->bus->busnum-1) * 128) + (udev->devnum-1))); @@ -2395,19 +2408,29 @@ EXPORT_SYMBOL_GPL(usb_ep0_reinit); static int hub_set_address(struct usb_device *udev, int devnum) { int retval; + struct usb_hcd *hcd = bus_to_hcd(udev->bus); - if (devnum <= 1) + /* + * The host controller will choose the device address, + * instead of the core having chosen it earlier + */ + if (!hcd->driver->address_device && devnum <= 1) return -EINVAL; if (udev->state == USB_STATE_ADDRESS) return 0; if (udev->state != USB_STATE_DEFAULT) return -EINVAL; - retval = usb_control_msg(udev, usb_sndaddr0pipe(), - USB_REQ_SET_ADDRESS, 0, devnum, 0, - NULL, 0, USB_CTRL_SET_TIMEOUT); + if (hcd->driver->address_device) { + retval = hcd->driver->address_device(hcd, udev); + } else { + retval = usb_control_msg(udev, usb_sndaddr0pipe(), + USB_REQ_SET_ADDRESS, 0, devnum, 0, + NULL, 0, USB_CTRL_SET_TIMEOUT); + if (retval == 0) + update_address(udev, devnum); + } if (retval == 0) { /* Device now using proper address. */ - update_address(udev, devnum); usb_set_device_state(udev, USB_STATE_ADDRESS); usb_ep0_reinit(udev); } @@ -2430,6 +2453,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, static DEFINE_MUTEX(usb_address0_mutex); struct usb_device *hdev = hub->hdev; + struct usb_hcd *hcd = bus_to_hcd(hdev->bus); int i, j, retval; unsigned delay = HUB_SHORT_RESET_TIME; enum usb_device_speed oldspeed = udev->speed; @@ -2452,11 +2476,24 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, mutex_lock(&usb_address0_mutex); - /* Reset the device; full speed may morph to high speed */ - retval = hub_port_reset(hub, port1, udev, delay); - if (retval < 0) /* error or disconnect */ + if ((hcd->driver->flags & HCD_USB3) && udev->config) { + /* FIXME this will need special handling by the xHCI driver. */ + dev_dbg(&udev->dev, + "xHCI reset of configured device " + "not supported yet.\n"); + retval = -EINVAL; goto fail; - /* success, speed is known */ + } else if (!udev->config && oldspeed == USB_SPEED_SUPER) { + /* Don't reset USB 3.0 devices during an initial setup */ + usb_set_device_state(udev, USB_STATE_DEFAULT); + } else { + /* Reset the device; full speed may morph to high speed */ + /* FIXME a USB 2.0 device may morph into SuperSpeed on reset. */ + retval = hub_port_reset(hub, port1, udev, delay); + if (retval < 0) /* error or disconnect */ + goto fail; + /* success, speed is known */ + } retval = -ENODEV; if (oldspeed != USB_SPEED_UNKNOWN && oldspeed != udev->speed) { @@ -2471,6 +2508,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, * reported as 0xff in the device descriptor). WUSB1.0[4.8.1]. */ switch (udev->speed) { + case USB_SPEED_SUPER: case USB_SPEED_VARIABLE: /* fixed at 512 */ udev->ep0.desc.wMaxPacketSize = cpu_to_le16(512); break; @@ -2496,16 +2534,20 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, case USB_SPEED_LOW: speed = "low"; break; case USB_SPEED_FULL: speed = "full"; break; case USB_SPEED_HIGH: speed = "high"; break; + case USB_SPEED_SUPER: + speed = "super"; + break; case USB_SPEED_VARIABLE: speed = "variable"; type = "Wireless "; break; default: speed = "?"; break; } - dev_info (&udev->dev, - "%s %s speed %sUSB device using %s and address %d\n", - (udev->config) ? "reset" : "new", speed, type, - udev->bus->controller->driver->name, devnum); + if (udev->speed != USB_SPEED_SUPER) + dev_info(&udev->dev, + "%s %s speed %sUSB device using %s and address %d\n", + (udev->config) ? "reset" : "new", speed, type, + udev->bus->controller->driver->name, devnum); /* Set up TT records, if needed */ if (hdev->tt) { @@ -2530,7 +2572,11 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, * value. */ for (i = 0; i < GET_DESCRIPTOR_TRIES; (++i, msleep(100))) { - if (USE_NEW_SCHEME(retry_counter)) { + /* + * An xHCI controller cannot send any packets to a device until + * a set address command successfully completes. + */ + if (USE_NEW_SCHEME(retry_counter) && !(hcd->driver->flags & HCD_USB3)) { struct usb_device_descriptor *buf; int r = 0; @@ -2596,7 +2642,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, * unauthorized address in the Connect Ack sequence; * authorization will assign the final address. */ - if (udev->wusb == 0) { + if (udev->wusb == 0) { for (j = 0; j < SET_ADDRESS_TRIES; ++j) { retval = hub_set_address(udev, devnum); if (retval >= 0) @@ -2609,13 +2655,20 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, devnum, retval); goto fail; } + if (udev->speed == USB_SPEED_SUPER) { + devnum = udev->devnum; + dev_info(&udev->dev, + "%s SuperSpeed USB device using %s and address %d\n", + (udev->config) ? "reset" : "new", + udev->bus->controller->driver->name, devnum); + } /* cope with hardware quirkiness: * - let SET_ADDRESS settle, some device hardware wants it * - read ep0 maxpacket even for high and low speed, */ msleep(10); - if (USE_NEW_SCHEME(retry_counter)) + if (USE_NEW_SCHEME(retry_counter) && !(hcd->driver->flags & HCD_USB3)) break; } @@ -2634,8 +2687,11 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, if (retval) goto fail; - i = udev->descriptor.bMaxPacketSize0 == 0xff? /* wusb device? */ - 512 : udev->descriptor.bMaxPacketSize0; + if (udev->descriptor.bMaxPacketSize0 == 0xff || + udev->speed == USB_SPEED_SUPER) + i = 512; + else + i = udev->descriptor.bMaxPacketSize0; if (le16_to_cpu(udev->ep0.desc.wMaxPacketSize) != i) { if (udev->speed != USB_SPEED_FULL || !(i == 8 || i == 16 || i == 32 || i == 64)) { @@ -2847,19 +2903,41 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, } usb_set_device_state(udev, USB_STATE_POWERED); - udev->speed = USB_SPEED_UNKNOWN; udev->bus_mA = hub->mA_per_port; udev->level = hdev->level + 1; udev->wusb = hub_is_wusb(hub); - /* set the address */ - choose_address(udev); - if (udev->devnum <= 0) { - status = -ENOTCONN; /* Don't retry */ - goto loop; + /* + * USB 3.0 devices are reset automatically before the connect + * port status change appears, and the root hub port status + * shows the correct speed. We also get port change + * notifications for USB 3.0 devices from the USB 3.0 portion of + * an external USB 3.0 hub, but this isn't handled correctly yet + * FIXME. + */ + + if (!(hcd->driver->flags & HCD_USB3)) + udev->speed = USB_SPEED_UNKNOWN; + else if ((hdev->parent == NULL) && + (portstatus & (1 << USB_PORT_FEAT_SUPERSPEED))) + udev->speed = USB_SPEED_SUPER; + else + udev->speed = USB_SPEED_UNKNOWN; + + /* + * xHCI needs to issue an address device command later + * in the hub_port_init sequence for SS/HS/FS/LS devices. + */ + if (!(hcd->driver->flags & HCD_USB3)) { + /* set the address */ + choose_address(udev); + if (udev->devnum <= 0) { + status = -ENOTCONN; /* Don't retry */ + goto loop; + } } - /* reset and get descriptor */ + /* reset (non-USB 3.0 devices) and get descriptor */ status = hub_port_init(hub, udev, port1, i); if (status < 0) goto loop; diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h index 2a116ce53c9b..889c0f32a40b 100644 --- a/drivers/usb/core/hub.h +++ b/drivers/usb/core/hub.h @@ -47,7 +47,10 @@ #define USB_PORT_FEAT_L1 5 /* L1 suspend */ #define USB_PORT_FEAT_POWER 8 #define USB_PORT_FEAT_LOWSPEED 9 +/* This value was never in Table 11-17 */ #define USB_PORT_FEAT_HIGHSPEED 10 +/* This value is also fake */ +#define USB_PORT_FEAT_SUPERSPEED 11 #define USB_PORT_FEAT_C_CONNECTION 16 #define USB_PORT_FEAT_C_ENABLE 17 #define USB_PORT_FEAT_C_SUSPEND 18 diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c index dff5760a37f6..ffe75e83787c 100644 --- a/drivers/usb/core/inode.c +++ b/drivers/usb/core/inode.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include "usb.h" #include "hcd.h" @@ -265,9 +266,13 @@ static int remount(struct super_block *sb, int *flags, char *data) return -EINVAL; } + lock_kernel(); + if (usbfs_mount && usbfs_mount->mnt_sb) update_sb(usbfs_mount->mnt_sb); + unlock_kernel(); + return 0; } diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index b62628377654..2bed83caacb1 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -364,6 +365,7 @@ int usb_sg_init(struct usb_sg_request *io, struct usb_device *dev, int i; int urb_flags; int dma; + int use_sg; if (!io || !dev || !sg || usb_pipecontrol(pipe) @@ -391,7 +393,19 @@ int usb_sg_init(struct usb_sg_request *io, struct usb_device *dev, if (io->entries <= 0) return io->entries; - io->urbs = kmalloc(io->entries * sizeof *io->urbs, mem_flags); + /* If we're running on an xHCI host controller, queue the whole scatter + * gather list with one call to urb_enqueue(). This is only for bulk, + * as that endpoint type does not care how the data gets broken up + * across frames. + */ + if (usb_pipebulk(pipe) && + bus_to_hcd(dev->bus)->driver->flags & HCD_USB3) { + io->urbs = kmalloc(sizeof *io->urbs, mem_flags); + use_sg = true; + } else { + io->urbs = kmalloc(io->entries * sizeof *io->urbs, mem_flags); + use_sg = false; + } if (!io->urbs) goto nomem; @@ -401,62 +415,92 @@ int usb_sg_init(struct usb_sg_request *io, struct usb_device *dev, if (usb_pipein(pipe)) urb_flags |= URB_SHORT_NOT_OK; - for_each_sg(sg, sg, io->entries, i) { - unsigned len; - - io->urbs[i] = usb_alloc_urb(0, mem_flags); - if (!io->urbs[i]) { - io->entries = i; + if (use_sg) { + io->urbs[0] = usb_alloc_urb(0, mem_flags); + if (!io->urbs[0]) { + io->entries = 0; goto nomem; } - io->urbs[i]->dev = NULL; - io->urbs[i]->pipe = pipe; - io->urbs[i]->interval = period; - io->urbs[i]->transfer_flags = urb_flags; + io->urbs[0]->dev = NULL; + io->urbs[0]->pipe = pipe; + io->urbs[0]->interval = period; + io->urbs[0]->transfer_flags = urb_flags; - io->urbs[i]->complete = sg_complete; - io->urbs[i]->context = io; + io->urbs[0]->complete = sg_complete; + io->urbs[0]->context = io; + /* A length of zero means transfer the whole sg list */ + io->urbs[0]->transfer_buffer_length = length; + if (length == 0) { + for_each_sg(sg, sg, io->entries, i) { + io->urbs[0]->transfer_buffer_length += + sg_dma_len(sg); + } + } + io->urbs[0]->sg = io; + io->urbs[0]->num_sgs = io->entries; + io->entries = 1; + } else { + for_each_sg(sg, sg, io->entries, i) { + unsigned len; - /* - * Some systems need to revert to PIO when DMA is temporarily - * unavailable. For their sakes, both transfer_buffer and - * transfer_dma are set when possible. However this can only - * work on systems without: - * - * - HIGHMEM, since DMA buffers located in high memory are - * not directly addressable by the CPU for PIO; - * - * - IOMMU, since dma_map_sg() is allowed to use an IOMMU to - * make virtually discontiguous buffers be "dma-contiguous" - * so that PIO and DMA need diferent numbers of URBs. - * - * So when HIGHMEM or IOMMU are in use, transfer_buffer is NULL - * to prevent stale pointers and to help spot bugs. - */ - if (dma) { - io->urbs[i]->transfer_dma = sg_dma_address(sg); - len = sg_dma_len(sg); + io->urbs[i] = usb_alloc_urb(0, mem_flags); + if (!io->urbs[i]) { + io->entries = i; + goto nomem; + } + + io->urbs[i]->dev = NULL; + io->urbs[i]->pipe = pipe; + io->urbs[i]->interval = period; + io->urbs[i]->transfer_flags = urb_flags; + + io->urbs[i]->complete = sg_complete; + io->urbs[i]->context = io; + + /* + * Some systems need to revert to PIO when DMA is + * temporarily unavailable. For their sakes, both + * transfer_buffer and transfer_dma are set when + * possible. However this can only work on systems + * without: + * + * - HIGHMEM, since DMA buffers located in high memory + * are not directly addressable by the CPU for PIO; + * + * - IOMMU, since dma_map_sg() is allowed to use an + * IOMMU to make virtually discontiguous buffers be + * "dma-contiguous" so that PIO and DMA need diferent + * numbers of URBs. + * + * So when HIGHMEM or IOMMU are in use, transfer_buffer + * is NULL to prevent stale pointers and to help spot + * bugs. + */ + if (dma) { + io->urbs[i]->transfer_dma = sg_dma_address(sg); + len = sg_dma_len(sg); #if defined(CONFIG_HIGHMEM) || defined(CONFIG_GART_IOMMU) - io->urbs[i]->transfer_buffer = NULL; + io->urbs[i]->transfer_buffer = NULL; #else - io->urbs[i]->transfer_buffer = sg_virt(sg); + io->urbs[i]->transfer_buffer = sg_virt(sg); #endif - } else { - /* hc may use _only_ transfer_buffer */ - io->urbs[i]->transfer_buffer = sg_virt(sg); - len = sg->length; - } + } else { + /* hc may use _only_ transfer_buffer */ + io->urbs[i]->transfer_buffer = sg_virt(sg); + len = sg->length; + } - if (length) { - len = min_t(unsigned, len, length); - length -= len; - if (length == 0) - io->entries = i + 1; + if (length) { + len = min_t(unsigned, len, length); + length -= len; + if (length == 0) + io->entries = i + 1; + } + io->urbs[i]->transfer_buffer_length = len; } - io->urbs[i]->transfer_buffer_length = len; + io->urbs[--i]->transfer_flags &= ~URB_NO_INTERRUPT; } - io->urbs[--i]->transfer_flags &= ~URB_NO_INTERRUPT; /* transaction state */ io->count = io->entries; @@ -509,6 +553,10 @@ EXPORT_SYMBOL_GPL(usb_sg_init); * could be transferred. That capability is less useful for low or full * speed interrupt endpoints, which allow at most one packet per millisecond, * of at most 8 or 64 bytes (respectively). + * + * It is not necessary to call this function to reserve bandwidth for devices + * under an xHCI host controller, as the bandwidth is reserved when the + * configuration or interface alt setting is selected. */ void usb_sg_wait(struct usb_sg_request *io) { @@ -759,7 +807,7 @@ static int usb_string_sub(struct usb_device *dev, unsigned int langid, } /** - * usb_string - returns ISO 8859-1 version of a string descriptor + * usb_string - returns UTF-8 version of a string descriptor * @dev: the device whose string descriptor is being retrieved * @index: the number of the descriptor * @buf: where to put the string @@ -767,17 +815,10 @@ static int usb_string_sub(struct usb_device *dev, unsigned int langid, * Context: !in_interrupt () * * This converts the UTF-16LE encoded strings returned by devices, from - * usb_get_string_descriptor(), to null-terminated ISO-8859-1 encoded ones - * that are more usable in most kernel contexts. Note that all characters - * in the chosen descriptor that can't be encoded using ISO-8859-1 - * are converted to the question mark ("?") character, and this function + * usb_get_string_descriptor(), to null-terminated UTF-8 encoded ones + * that are more usable in most kernel contexts. Note that this function * chooses strings in the first language supported by the device. * - * The ASCII (or, redundantly, "US-ASCII") character set is the seven-bit - * subset of ISO 8859-1. ISO-8859-1 is the eight-bit subset of Unicode, - * and is appropriate for use many uses of English and several other - * Western European languages. (But it doesn't include the "Euro" symbol.) - * * This call is synchronous, and may not be used in an interrupt context. * * Returns length of the string (>= 0) or usb_control_msg status (< 0). @@ -786,7 +827,6 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size) { unsigned char *tbuf; int err; - unsigned int u, idx; if (dev->state == USB_STATE_SUSPENDED) return -EHOSTUNREACH; @@ -821,16 +861,9 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size) goto errout; size--; /* leave room for trailing NULL char in output buffer */ - for (idx = 0, u = 2; u < err; u += 2) { - if (idx >= size) - break; - if (tbuf[u+1]) /* high byte */ - buf[idx++] = '?'; /* non ISO-8859-1 character */ - else - buf[idx++] = tbuf[u]; - } - buf[idx] = 0; - err = idx; + err = utf16s_to_utf8s((wchar_t *) &tbuf[2], (err - 2) / 2, + UTF16_LITTLE_ENDIAN, buf, size); + buf[err] = 0; if (tbuf[1] != USB_DT_STRING) dev_dbg(&dev->dev, @@ -843,6 +876,9 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size) } EXPORT_SYMBOL_GPL(usb_string); +/* one UTF-8-encoded 16-bit character has at most three bytes */ +#define MAX_USB_STRING_SIZE (127 * 3 + 1) + /** * usb_cache_string - read a string descriptor and cache it for later use * @udev: the device whose string descriptor is being read @@ -860,9 +896,9 @@ char *usb_cache_string(struct usb_device *udev, int index) if (index <= 0) return NULL; - buf = kmalloc(256, GFP_KERNEL); + buf = kmalloc(MAX_USB_STRING_SIZE, GFP_KERNEL); if (buf) { - len = usb_string(udev, index, buf, 256); + len = usb_string(udev, index, buf, MAX_USB_STRING_SIZE); if (len > 0) { smallbuf = kmalloc(++len, GFP_KERNEL); if (!smallbuf) @@ -1664,6 +1700,21 @@ free_interfaces: if (ret) goto free_interfaces; + /* Make sure we have bandwidth (and available HCD resources) for this + * configuration. Remove endpoints from the schedule if we're dropping + * this configuration to set configuration 0. After this point, the + * host controller will not allow submissions to dropped endpoints. If + * this call fails, the device state is unchanged. + */ + if (cp) + ret = usb_hcd_check_bandwidth(dev, cp, NULL); + else + ret = usb_hcd_check_bandwidth(dev, NULL, NULL); + if (ret < 0) { + usb_autosuspend_device(dev); + goto free_interfaces; + } + /* if it's already configured, clear out old state first. * getting rid of old interfaces means unbinding their drivers. */ @@ -1686,6 +1737,7 @@ free_interfaces: dev->actconfig = cp; if (!cp) { usb_set_device_state(dev, USB_STATE_ADDRESS); + usb_hcd_check_bandwidth(dev, NULL, NULL); usb_autosuspend_device(dev); goto free_interfaces; } diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index c66789197927..b5c72e458943 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -552,8 +552,8 @@ static struct attribute *dev_string_attrs[] = { static mode_t dev_string_attrs_are_visible(struct kobject *kobj, struct attribute *a, int n) { - struct usb_device *udev = to_usb_device( - container_of(kobj, struct device, kobj)); + struct device *dev = container_of(kobj, struct device, kobj); + struct usb_device *udev = to_usb_device(dev); if (a == &dev_attr_manufacturer.attr) { if (udev->manufacturer == NULL) @@ -585,8 +585,8 @@ static ssize_t read_descriptors(struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t off, size_t count) { - struct usb_device *udev = to_usb_device( - container_of(kobj, struct device, kobj)); + struct device *dev = container_of(kobj, struct device, kobj); + struct usb_device *udev = to_usb_device(dev); size_t nleft = count; size_t srclen, n; int cfgno; @@ -786,8 +786,8 @@ static struct attribute *intf_assoc_attrs[] = { static mode_t intf_assoc_attrs_are_visible(struct kobject *kobj, struct attribute *a, int n) { - struct usb_interface *intf = to_usb_interface( - container_of(kobj, struct device, kobj)); + struct device *dev = container_of(kobj, struct device, kobj); + struct usb_interface *intf = to_usb_interface(dev); if (intf->intf_assoc == NULL) return 0; diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index 3376055f36e7..0885d4abdc62 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -241,6 +241,12 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb); * If the USB subsystem can't allocate sufficient bandwidth to perform * the periodic request, submitting such a periodic request should fail. * + * For devices under xHCI, the bandwidth is reserved at configuration time, or + * when the alt setting is selected. If there is not enough bus bandwidth, the + * configuration/alt setting request will fail. Therefore, submissions to + * periodic endpoints on devices under xHCI should never fail due to bandwidth + * constraints. + * * Device drivers must explicitly request that repetition, by ensuring that * some URB is always on the endpoint's queue (except possibly for short * periods during completion callacks). When there is no longer an urb @@ -351,6 +357,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) if (xfertype == USB_ENDPOINT_XFER_ISOC) { int n, len; + /* FIXME SuperSpeed isoc endpoints have up to 16 bursts */ /* "high bandwidth" mode, 1-3 packets/uframe? */ if (dev->speed == USB_SPEED_HIGH) { int mult = 1 + ((max >> 11) & 0x03); @@ -426,6 +433,11 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) return -EINVAL; /* too big? */ switch (dev->speed) { + case USB_SPEED_SUPER: /* units are 125us */ + /* Handle up to 2^(16-1) microframes */ + if (urb->interval > (1 << 15)) + return -EINVAL; + max = 1 << 15; case USB_SPEED_HIGH: /* units are microframes */ /* NOTE usb handles 2^15 */ if (urb->interval > (1024 * 8)) diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 7eee400d3e32..a26f73880c32 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -139,8 +140,7 @@ static int __find_interface(struct device *dev, void *data) struct find_interface_arg *arg = data; struct usb_interface *intf; - /* can't look at usb devices, only interfaces */ - if (is_usb_device(dev)) + if (!is_usb_interface(dev)) return 0; intf = to_usb_interface(dev); @@ -184,11 +184,16 @@ EXPORT_SYMBOL_GPL(usb_find_interface); static void usb_release_dev(struct device *dev) { struct usb_device *udev; + struct usb_hcd *hcd; udev = to_usb_device(dev); + hcd = bus_to_hcd(udev->bus); usb_destroy_configuration(udev); - usb_put_hcd(bus_to_hcd(udev->bus)); + /* Root hubs aren't real devices, so don't free HCD resources */ + if (hcd->driver->free_dev && udev->parent) + hcd->driver->free_dev(hcd, udev); + usb_put_hcd(hcd); kfree(udev->product); kfree(udev->manufacturer); kfree(udev->serial); @@ -305,10 +310,21 @@ static struct dev_pm_ops usb_device_pm_ops = { #endif /* CONFIG_PM */ + +static char *usb_nodename(struct device *dev) +{ + struct usb_device *usb_dev; + + usb_dev = to_usb_device(dev); + return kasprintf(GFP_KERNEL, "bus/usb/%03d/%03d", + usb_dev->bus->busnum, usb_dev->devnum); +} + struct device_type usb_device_type = { .name = "usb_device", .release = usb_release_dev, .uevent = usb_dev_uevent, + .nodename = usb_nodename, .pm = &usb_device_pm_ops, }; @@ -348,6 +364,13 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, kfree(dev); return NULL; } + /* Root hubs aren't true devices, so don't allocate HCD resources */ + if (usb_hcd->driver->alloc_dev && parent && + !usb_hcd->driver->alloc_dev(usb_hcd, dev)) { + usb_put_hcd(bus_to_hcd(bus)); + kfree(dev); + return NULL; + } device_initialize(&dev->dev); dev->dev.bus = &usb_bus_type; @@ -375,18 +398,24 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, */ if (unlikely(!parent)) { dev->devpath[0] = '0'; + dev->route = 0; dev->dev.parent = bus->controller; dev_set_name(&dev->dev, "usb%d", bus->busnum); root_hub = 1; } else { /* match any labeling on the hubs; it's one-based */ - if (parent->devpath[0] == '0') + if (parent->devpath[0] == '0') { snprintf(dev->devpath, sizeof dev->devpath, "%d", port1); - else + /* Root ports are not counted in route string */ + dev->route = 0; + } else { snprintf(dev->devpath, sizeof dev->devpath, "%s.%d", parent->devpath, port1); + dev->route = parent->route + + (port1 << ((parent->level - 1)*4)); + } dev->dev.parent = &parent->dev; dev_set_name(&dev->dev, "%d-%s", bus->busnum, dev->devpath); @@ -799,12 +828,12 @@ void usb_buffer_dmasync(struct urb *urb) return; if (controller->dma_mask) { - dma_sync_single(controller, + dma_sync_single_for_cpu(controller, urb->transfer_dma, urb->transfer_buffer_length, usb_pipein(urb->pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); if (usb_pipecontrol(urb->pipe)) - dma_sync_single(controller, + dma_sync_single_for_cpu(controller, urb->setup_dma, sizeof(struct usb_ctrlrequest), DMA_TO_DEVICE); @@ -922,8 +951,8 @@ void usb_buffer_dmasync_sg(const struct usb_device *dev, int is_in, || !controller->dma_mask) return; - dma_sync_sg(controller, sg, n_hw_ents, - is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE); + dma_sync_sg_for_cpu(controller, sg, n_hw_ents, + is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } EXPORT_SYMBOL_GPL(usb_buffer_dmasync_sg); #endif @@ -1001,6 +1030,35 @@ static struct notifier_block usb_bus_nb = { .notifier_call = usb_bus_notify, }; +struct dentry *usb_debug_root; +EXPORT_SYMBOL_GPL(usb_debug_root); + +struct dentry *usb_debug_devices; + +static int usb_debugfs_init(void) +{ + usb_debug_root = debugfs_create_dir("usb", NULL); + if (!usb_debug_root) + return -ENOENT; + + usb_debug_devices = debugfs_create_file("devices", 0444, + usb_debug_root, NULL, + &usbfs_devices_fops); + if (!usb_debug_devices) { + debugfs_remove(usb_debug_root); + usb_debug_root = NULL; + return -ENOENT; + } + + return 0; +} + +static void usb_debugfs_cleanup(void) +{ + debugfs_remove(usb_debug_devices); + debugfs_remove(usb_debug_root); +} + /* * Init */ @@ -1012,6 +1070,10 @@ static int __init usb_init(void) return 0; } + retval = usb_debugfs_init(); + if (retval) + goto out; + retval = ksuspend_usb_init(); if (retval) goto out; @@ -1021,9 +1083,6 @@ static int __init usb_init(void) retval = bus_register_notifier(&usb_bus_type, &usb_bus_nb); if (retval) goto bus_notifier_failed; - retval = usb_host_init(); - if (retval) - goto host_init_failed; retval = usb_major_init(); if (retval) goto major_init_failed; @@ -1053,8 +1112,6 @@ usb_devio_init_failed: driver_register_failed: usb_major_cleanup(); major_init_failed: - usb_host_cleanup(); -host_init_failed: bus_unregister_notifier(&usb_bus_type, &usb_bus_nb); bus_notifier_failed: bus_unregister(&usb_bus_type); @@ -1079,10 +1136,10 @@ static void __exit usb_exit(void) usb_deregister(&usbfs_driver); usb_devio_cleanup(); usb_hub_cleanup(); - usb_host_cleanup(); bus_unregister_notifier(&usb_bus_type, &usb_bus_nb); bus_unregister(&usb_bus_type); ksuspend_usb_cleanup(); + usb_debugfs_cleanup(); } subsys_initcall(usb_init); diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 79d8a9ea559b..e2a8cfaade1d 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -41,8 +41,6 @@ extern int usb_hub_init(void); extern void usb_hub_cleanup(void); extern int usb_major_init(void); extern void usb_major_cleanup(void); -extern int usb_host_init(void); -extern void usb_host_cleanup(void); #ifdef CONFIG_PM @@ -106,6 +104,7 @@ extern struct workqueue_struct *ksuspend_usb_wq; extern struct bus_type usb_bus_type; extern struct device_type usb_device_type; extern struct device_type usb_if_device_type; +extern struct device_type usb_ep_device_type; extern struct usb_device_driver usb_generic_driver; static inline int is_usb_device(const struct device *dev) @@ -113,6 +112,16 @@ static inline int is_usb_device(const struct device *dev) return dev->type == &usb_device_type; } +static inline int is_usb_interface(const struct device *dev) +{ + return dev->type == &usb_if_device_type; +} + +static inline int is_usb_endpoint(const struct device *dev) +{ + return dev->type == &usb_ep_device_type; +} + /* Do the same for device drivers and interface drivers. */ static inline int is_usb_device_driver(struct device_driver *drv) diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 080bb1e4b847..5d1ddf485d1e 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -156,7 +156,7 @@ config USB_ATMEL_USBA config USB_GADGET_FSL_USB2 boolean "Freescale Highspeed USB DR Peripheral Controller" - depends on FSL_SOC + depends on FSL_SOC || ARCH_MXC select USB_GADGET_DUALSPEED help Some of Freescale PowerPC processors have a High Speed @@ -253,7 +253,7 @@ config USB_PXA25X_SMALL config USB_GADGET_PXA27X boolean "PXA 27x" - depends on ARCH_PXA && PXA27x + depends on ARCH_PXA && (PXA27x || PXA3xx) select USB_OTG_UTILS help Intel's PXA 27x series XScale ARM v5TE processors include @@ -272,6 +272,20 @@ config USB_PXA27X default USB_GADGET select USB_GADGET_SELECTED +config USB_GADGET_S3C_HSOTG + boolean "S3C HS/OtG USB Device controller" + depends on S3C_DEV_USB_HSOTG + select USB_GADGET_S3C_HSOTG_PIO + help + The Samsung S3C64XX USB2.0 high-speed gadget controller + integrated into the S3C64XX series SoC. + +config USB_S3C_HSOTG + tristate + depends on USB_GADGET_S3C_HSOTG + default USB_GADGET + select USB_GADGET_SELECTED + config USB_GADGET_S3C2410 boolean "S3C2410 USB Device Controller" depends on ARCH_S3C2410 @@ -460,6 +474,27 @@ config USB_GOKU default USB_GADGET select USB_GADGET_SELECTED +config USB_GADGET_LANGWELL + boolean "Intel Langwell USB Device Controller" + depends on PCI + select USB_GADGET_DUALSPEED + help + Intel Langwell USB Device Controller is a High-Speed USB + On-The-Go device controller. + + The number of programmable endpoints is different through + controller revision. + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "langwell_udc" and force all + gadget drivers to also be dynamically linked. + +config USB_LANGWELL + tristate + depends on USB_GADGET_LANGWELL + default USB_GADGET + select USB_GADGET_SELECTED + # # LAST -- dummy/emulated controller @@ -566,6 +601,20 @@ config USB_ZERO_HNPTEST the "B-Peripheral" role, that device will use HNP to let this one serve as the USB host instead (in the "B-Host" role). +config USB_AUDIO + tristate "Audio Gadget (EXPERIMENTAL)" + depends on SND + help + Gadget Audio is compatible with USB Audio Class specification 1.0. + It will include at least one AudioControl interface, zero or more + AudioStream interface and zero or more MIDIStream interface. + + Gadget Audio will use on-board ALSA (CONFIG_SND) audio card to + playback or capture audio stream. + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "g_audio". + config USB_ETH tristate "Ethernet Gadget (with CDC Ethernet support)" depends on NET diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 39a51d746cb7..e6017e6bf6da 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -18,14 +18,21 @@ obj-$(CONFIG_USB_S3C2410) += s3c2410_udc.o obj-$(CONFIG_USB_AT91) += at91_udc.o obj-$(CONFIG_USB_ATMEL_USBA) += atmel_usba_udc.o obj-$(CONFIG_USB_FSL_USB2) += fsl_usb2_udc.o +fsl_usb2_udc-objs := fsl_udc_core.o +ifeq ($(CONFIG_ARCH_MXC),y) +fsl_usb2_udc-objs += fsl_mx3_udc.o +endif obj-$(CONFIG_USB_M66592) += m66592-udc.o obj-$(CONFIG_USB_FSL_QE) += fsl_qe_udc.o obj-$(CONFIG_USB_CI13XXX) += ci13xxx_udc.o +obj-$(CONFIG_USB_S3C_HSOTG) += s3c-hsotg.o +obj-$(CONFIG_USB_LANGWELL) += langwell_udc.o # # USB gadget drivers # g_zero-objs := zero.o +g_audio-objs := audio.o g_ether-objs := ether.o g_serial-objs := serial.o g_midi-objs := gmidi.o @@ -35,6 +42,7 @@ g_printer-objs := printer.o g_cdc-objs := cdc2.o obj-$(CONFIG_USB_ZERO) += g_zero.o +obj-$(CONFIG_USB_AUDIO) += g_audio.o obj-$(CONFIG_USB_ETH) += g_ether.o obj-$(CONFIG_USB_GADGETFS) += gadgetfs.o obj-$(CONFIG_USB_FILE_STORAGE) += g_file_storage.o diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index 0b2bb8f0706d..72bae8f39d81 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -485,7 +485,7 @@ static int at91_ep_enable(struct usb_ep *_ep, return -ESHUTDOWN; } - tmp = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; + tmp = usb_endpoint_type(desc); switch (tmp) { case USB_ENDPOINT_XFER_CONTROL: DBG("only one control endpoint\n"); @@ -517,7 +517,7 @@ ok: local_irq_save(flags); /* initialize endpoint to match this descriptor */ - ep->is_in = (desc->bEndpointAddress & USB_DIR_IN) != 0; + ep->is_in = usb_endpoint_dir_in(desc); ep->is_iso = (tmp == USB_ENDPOINT_XFER_ISOC); ep->stopped = 0; if (ep->is_in) @@ -1574,7 +1574,7 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver) udc->driver = driver; udc->gadget.dev.driver = &driver->driver; - udc->gadget.dev.driver_data = &driver->driver; + dev_set_drvdata(&udc->gadget.dev, &driver->driver); udc->enabled = 1; udc->selfpowered = 1; @@ -1583,7 +1583,7 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver) DBG("driver->bind() returned %d\n", retval); udc->driver = NULL; udc->gadget.dev.driver = NULL; - udc->gadget.dev.driver_data = NULL; + dev_set_drvdata(&udc->gadget.dev, NULL); udc->enabled = 0; udc->selfpowered = 0; return retval; @@ -1613,7 +1613,7 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver) driver->unbind(&udc->gadget); udc->gadget.dev.driver = NULL; - udc->gadget.dev.driver_data = NULL; + dev_set_drvdata(&udc->gadget.dev, NULL); udc->driver = NULL; DBG("unbound from %s\n", driver->driver.name); diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index 05c913cc3658..4e970cf0e29a 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -326,13 +326,7 @@ static int vbus_is_present(struct usba_udc *udc) return 1; } -#if defined(CONFIG_AVR32) - -static void toggle_bias(int is_on) -{ -} - -#elif defined(CONFIG_ARCH_AT91) +#if defined(CONFIG_ARCH_AT91SAM9RL) #include @@ -346,7 +340,13 @@ static void toggle_bias(int is_on) at91_sys_write(AT91_CKGR_UCKR, uckr & ~(AT91_PMC_BIASEN)); } -#endif /* CONFIG_ARCH_AT91 */ +#else + +static void toggle_bias(int is_on) +{ +} + +#endif /* CONFIG_ARCH_AT91SAM9RL */ static void next_fifo_transaction(struct usba_ep *ep, struct usba_request *req) { @@ -550,12 +550,12 @@ usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) DBG(DBG_HW, "%s: EPT_SIZE = %lu (maxpacket = %lu)\n", ep->ep.name, ept_cfg, maxpacket); - if ((desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) { + if (usb_endpoint_dir_in(desc)) { ep->is_in = 1; ept_cfg |= USBA_EPT_DIR_IN; } - switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { + switch (usb_endpoint_type(desc)) { case USB_ENDPOINT_XFER_CONTROL: ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_CONTROL); ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE); diff --git a/drivers/usb/gadget/audio.c b/drivers/usb/gadget/audio.c new file mode 100644 index 000000000000..94de7e864614 --- /dev/null +++ b/drivers/usb/gadget/audio.c @@ -0,0 +1,302 @@ +/* + * audio.c -- Audio gadget driver + * + * Copyright (C) 2008 Bryan Wu + * Copyright (C) 2008 Analog Devices, Inc + * + * Enter bugs at http://blackfin.uclinux.org/ + * + * Licensed under the GPL-2 or later. + */ + +/* #define VERBOSE_DEBUG */ + +#include +#include + +#include "u_audio.h" + +#define DRIVER_DESC "Linux USB Audio Gadget" +#define DRIVER_VERSION "Dec 18, 2008" + +/*-------------------------------------------------------------------------*/ + +/* + * Kbuild is not very cooperative with respect to linking separately + * compiled library objects into one module. So for now we won't use + * separate compilation ... ensuring init/exit sections work to shrink + * the runtime footprint, and giving us at least some parts of what + * a "gcc --combine ... part1.c part2.c part3.c ... " build would. + */ +#include "composite.c" +#include "usbstring.c" +#include "config.c" +#include "epautoconf.c" + +#include "u_audio.c" +#include "f_audio.c" + +/*-------------------------------------------------------------------------*/ + +/* DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!! + * Instead: allocate your own, using normal USB-IF procedures. + */ + +/* Thanks to NetChip Technologies for donating this product ID. */ +#define AUDIO_VENDOR_NUM 0x0525 /* NetChip */ +#define AUDIO_PRODUCT_NUM 0xa4a1 /* Linux-USB Audio Gadget */ + +/*-------------------------------------------------------------------------*/ + +static struct usb_device_descriptor device_desc = { + .bLength = sizeof device_desc, + .bDescriptorType = USB_DT_DEVICE, + + .bcdUSB = __constant_cpu_to_le16(0x200), + + .bDeviceClass = USB_CLASS_PER_INTERFACE, + .bDeviceSubClass = 0, + .bDeviceProtocol = 0, + /* .bMaxPacketSize0 = f(hardware) */ + + /* Vendor and product id defaults change according to what configs + * we support. (As does bNumConfigurations.) These values can + * also be overridden by module parameters. + */ + .idVendor = __constant_cpu_to_le16(AUDIO_VENDOR_NUM), + .idProduct = __constant_cpu_to_le16(AUDIO_PRODUCT_NUM), + /* .bcdDevice = f(hardware) */ + /* .iManufacturer = DYNAMIC */ + /* .iProduct = DYNAMIC */ + /* NO SERIAL NUMBER */ + .bNumConfigurations = 1, +}; + +static struct usb_otg_descriptor otg_descriptor = { + .bLength = sizeof otg_descriptor, + .bDescriptorType = USB_DT_OTG, + + /* REVISIT SRP-only hardware is possible, although + * it would not be called "OTG" ... + */ + .bmAttributes = USB_OTG_SRP | USB_OTG_HNP, +}; + +static const struct usb_descriptor_header *otg_desc[] = { + (struct usb_descriptor_header *) &otg_descriptor, + NULL, +}; + +/*-------------------------------------------------------------------------*/ + +/** + * Handle USB audio endpoint set/get command in setup class request + */ + +static int audio_set_endpoint_req(struct usb_configuration *c, + const struct usb_ctrlrequest *ctrl) +{ + struct usb_composite_dev *cdev = c->cdev; + int value = -EOPNOTSUPP; + u16 ep = le16_to_cpu(ctrl->wIndex); + u16 len = le16_to_cpu(ctrl->wLength); + u16 w_value = le16_to_cpu(ctrl->wValue); + + DBG(cdev, "bRequest 0x%x, w_value 0x%04x, len %d, endpoint %d\n", + ctrl->bRequest, w_value, len, ep); + + switch (ctrl->bRequest) { + case SET_CUR: + value = 0; + break; + + case SET_MIN: + break; + + case SET_MAX: + break; + + case SET_RES: + break; + + case SET_MEM: + break; + + default: + break; + } + + return value; +} + +static int audio_get_endpoint_req(struct usb_configuration *c, + const struct usb_ctrlrequest *ctrl) +{ + struct usb_composite_dev *cdev = c->cdev; + int value = -EOPNOTSUPP; + u8 ep = ((le16_to_cpu(ctrl->wIndex) >> 8) & 0xFF); + u16 len = le16_to_cpu(ctrl->wLength); + u16 w_value = le16_to_cpu(ctrl->wValue); + + DBG(cdev, "bRequest 0x%x, w_value 0x%04x, len %d, endpoint %d\n", + ctrl->bRequest, w_value, len, ep); + + switch (ctrl->bRequest) { + case GET_CUR: + case GET_MIN: + case GET_MAX: + case GET_RES: + value = 3; + break; + case GET_MEM: + break; + default: + break; + } + + return value; +} + +static int +audio_setup(struct usb_configuration *c, const struct usb_ctrlrequest *ctrl) +{ + struct usb_composite_dev *cdev = c->cdev; + struct usb_request *req = cdev->req; + int value = -EOPNOTSUPP; + u16 w_index = le16_to_cpu(ctrl->wIndex); + u16 w_value = le16_to_cpu(ctrl->wValue); + u16 w_length = le16_to_cpu(ctrl->wLength); + + /* composite driver infrastructure handles everything except + * Audio class messages; interface activation uses set_alt(). + */ + switch (ctrl->bRequestType) { + case USB_AUDIO_SET_ENDPOINT: + value = audio_set_endpoint_req(c, ctrl); + break; + + case USB_AUDIO_GET_ENDPOINT: + value = audio_get_endpoint_req(c, ctrl); + break; + + default: + ERROR(cdev, "Invalid control req%02x.%02x v%04x i%04x l%d\n", + ctrl->bRequestType, ctrl->bRequest, + w_value, w_index, w_length); + } + + /* respond with data transfer or status phase? */ + if (value >= 0) { + DBG(cdev, "Audio req%02x.%02x v%04x i%04x l%d\n", + ctrl->bRequestType, ctrl->bRequest, + w_value, w_index, w_length); + req->zero = 0; + req->length = value; + value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC); + if (value < 0) + ERROR(cdev, "Audio response on err %d\n", value); + } + + /* device either stalls (value < 0) or reports success */ + return value; +} + +/*-------------------------------------------------------------------------*/ + +static int __init audio_do_config(struct usb_configuration *c) +{ + /* FIXME alloc iConfiguration string, set it in c->strings */ + + if (gadget_is_otg(c->cdev->gadget)) { + c->descriptors = otg_desc; + c->bmAttributes |= USB_CONFIG_ATT_WAKEUP; + } + + audio_bind_config(c); + + return 0; +} + +static struct usb_configuration audio_config_driver = { + .label = DRIVER_DESC, + .bind = audio_do_config, + .setup = audio_setup, + .bConfigurationValue = 1, + /* .iConfiguration = DYNAMIC */ + .bmAttributes = USB_CONFIG_ATT_SELFPOWER, +}; + +/*-------------------------------------------------------------------------*/ + +static int __init audio_bind(struct usb_composite_dev *cdev) +{ + int gcnum; + int status; + + gcnum = usb_gadget_controller_number(cdev->gadget); + if (gcnum >= 0) + device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum); + else { + ERROR(cdev, "controller '%s' not recognized; trying %s\n", + cdev->gadget->name, + audio_config_driver.label); + device_desc.bcdDevice = + __constant_cpu_to_le16(0x0300 | 0x0099); + } + + /* device descriptor strings: manufacturer, product */ + snprintf(manufacturer, sizeof manufacturer, "%s %s with %s", + init_utsname()->sysname, init_utsname()->release, + cdev->gadget->name); + status = usb_string_id(cdev); + if (status < 0) + goto fail; + strings_dev[STRING_MANUFACTURER_IDX].id = status; + device_desc.iManufacturer = status; + + status = usb_string_id(cdev); + if (status < 0) + goto fail; + strings_dev[STRING_PRODUCT_IDX].id = status; + device_desc.iProduct = status; + + status = usb_add_config(cdev, &audio_config_driver); + if (status < 0) + goto fail; + + INFO(cdev, "%s, version: %s\n", DRIVER_DESC, DRIVER_VERSION); + return 0; + +fail: + return status; +} + +static int __exit audio_unbind(struct usb_composite_dev *cdev) +{ + return 0; +} + +static struct usb_composite_driver audio_driver = { + .name = "g_audio", + .dev = &device_desc, + .strings = audio_strings, + .bind = audio_bind, + .unbind = __exit_p(audio_unbind), +}; + +static int __init init(void) +{ + return usb_composite_register(&audio_driver); +} +module_init(init); + +static void __exit cleanup(void) +{ + usb_composite_unregister(&audio_driver); +} +module_exit(cleanup); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_AUTHOR("Bryan Wu "); +MODULE_LICENSE("GPL"); + diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c index 38e531ecae4d..c7cb87a6fee2 100644 --- a/drivers/usb/gadget/ci13xxx_udc.c +++ b/drivers/usb/gadget/ci13xxx_udc.c @@ -1977,9 +1977,9 @@ static int ep_enable(struct usb_ep *ep, if (!list_empty(&mEp->qh[mEp->dir].queue)) warn("enabling a non-empty endpoint!"); - mEp->dir = (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ? TX : RX; - mEp->num = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; - mEp->type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; + mEp->dir = usb_endpoint_dir_in(desc) ? TX : RX; + mEp->num = usb_endpoint_num(desc); + mEp->type = usb_endpoint_type(desc); mEp->ep.maxpacket = __constant_le16_to_cpu(desc->wMaxPacketSize); diff --git a/drivers/usb/gadget/f_audio.c b/drivers/usb/gadget/f_audio.c new file mode 100644 index 000000000000..66527ba2d2ea --- /dev/null +++ b/drivers/usb/gadget/f_audio.c @@ -0,0 +1,707 @@ +/* + * f_audio.c -- USB Audio class function driver + * + * Copyright (C) 2008 Bryan Wu + * Copyright (C) 2008 Analog Devices, Inc + * + * Enter bugs at http://blackfin.uclinux.org/ + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include + +#include "u_audio.h" + +#define OUT_EP_MAX_PACKET_SIZE 200 +static int req_buf_size = OUT_EP_MAX_PACKET_SIZE; +module_param(req_buf_size, int, S_IRUGO); +MODULE_PARM_DESC(req_buf_size, "ISO OUT endpoint request buffer size"); + +static int req_count = 256; +module_param(req_count, int, S_IRUGO); +MODULE_PARM_DESC(req_count, "ISO OUT endpoint request count"); + +static int audio_buf_size = 48000; +module_param(audio_buf_size, int, S_IRUGO); +MODULE_PARM_DESC(audio_buf_size, "Audio buffer size"); + +/* + * DESCRIPTORS ... most are static, but strings and full + * configuration descriptors are built on demand. + */ + +/* + * We have two interfaces- AudioControl and AudioStreaming + * TODO: only supcard playback currently + */ +#define F_AUDIO_AC_INTERFACE 0 +#define F_AUDIO_AS_INTERFACE 1 +#define F_AUDIO_NUM_INTERFACES 2 + +/* B.3.1 Standard AC Interface Descriptor */ +static struct usb_interface_descriptor ac_interface_desc __initdata = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bNumEndpoints = 0, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL, +}; + +DECLARE_USB_AC_HEADER_DESCRIPTOR(2); + +#define USB_DT_AC_HEADER_LENGH USB_DT_AC_HEADER_SIZE(F_AUDIO_NUM_INTERFACES) +/* B.3.2 Class-Specific AC Interface Descriptor */ +static struct usb_ac_header_descriptor_2 ac_header_desc = { + .bLength = USB_DT_AC_HEADER_LENGH, + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubtype = HEADER, + .bcdADC = __constant_cpu_to_le16(0x0100), + .wTotalLength = __constant_cpu_to_le16(USB_DT_AC_HEADER_LENGH), + .bInCollection = F_AUDIO_NUM_INTERFACES, + .baInterfaceNr = { + [0] = F_AUDIO_AC_INTERFACE, + [1] = F_AUDIO_AS_INTERFACE, + } +}; + +#define INPUT_TERMINAL_ID 1 +static struct usb_input_terminal_descriptor input_terminal_desc = { + .bLength = USB_DT_AC_INPUT_TERMINAL_SIZE, + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubtype = INPUT_TERMINAL, + .bTerminalID = INPUT_TERMINAL_ID, + .wTerminalType = USB_AC_TERMINAL_STREAMING, + .bAssocTerminal = 0, + .wChannelConfig = 0x3, +}; + +DECLARE_USB_AC_FEATURE_UNIT_DESCRIPTOR(0); + +#define FEATURE_UNIT_ID 2 +static struct usb_ac_feature_unit_descriptor_0 feature_unit_desc = { + .bLength = USB_DT_AC_FEATURE_UNIT_SIZE(0), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubtype = FEATURE_UNIT, + .bUnitID = FEATURE_UNIT_ID, + .bSourceID = INPUT_TERMINAL_ID, + .bControlSize = 2, + .bmaControls[0] = (FU_MUTE | FU_VOLUME), +}; + +static struct usb_audio_control mute_control = { + .list = LIST_HEAD_INIT(mute_control.list), + .name = "Mute Control", + .type = MUTE_CONTROL, + /* Todo: add real Mute control code */ + .set = generic_set_cmd, + .get = generic_get_cmd, +}; + +static struct usb_audio_control volume_control = { + .list = LIST_HEAD_INIT(volume_control.list), + .name = "Volume Control", + .type = VOLUME_CONTROL, + /* Todo: add real Volume control code */ + .set = generic_set_cmd, + .get = generic_get_cmd, +}; + +static struct usb_audio_control_selector feature_unit = { + .list = LIST_HEAD_INIT(feature_unit.list), + .id = FEATURE_UNIT_ID, + .name = "Mute & Volume Control", + .type = FEATURE_UNIT, + .desc = (struct usb_descriptor_header *)&feature_unit_desc, +}; + +#define OUTPUT_TERMINAL_ID 3 +static struct usb_output_terminal_descriptor output_terminal_desc = { + .bLength = USB_DT_AC_OUTPUT_TERMINAL_SIZE, + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubtype = OUTPUT_TERMINAL, + .bTerminalID = OUTPUT_TERMINAL_ID, + .wTerminalType = USB_AC_OUTPUT_TERMINAL_SPEAKER, + .bAssocTerminal = FEATURE_UNIT_ID, + .bSourceID = FEATURE_UNIT_ID, +}; + +/* B.4.1 Standard AS Interface Descriptor */ +static struct usb_interface_descriptor as_interface_alt_0_desc = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bAlternateSetting = 0, + .bNumEndpoints = 0, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING, +}; + +static struct usb_interface_descriptor as_interface_alt_1_desc = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bAlternateSetting = 1, + .bNumEndpoints = 1, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING, +}; + +/* B.4.2 Class-Specific AS Interface Descriptor */ +static struct usb_as_header_descriptor as_header_desc = { + .bLength = USB_DT_AS_HEADER_SIZE, + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubtype = AS_GENERAL, + .bTerminalLink = INPUT_TERMINAL_ID, + .bDelay = 1, + .wFormatTag = USB_AS_AUDIO_FORMAT_TYPE_I_PCM, +}; + +DECLARE_USB_AS_FORMAT_TYPE_I_DISCRETE_DESC(1); + +static struct usb_as_formate_type_i_discrete_descriptor_1 as_type_i_desc = { + .bLength = USB_AS_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(1), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubtype = FORMAT_TYPE, + .bFormatType = USB_AS_FORMAT_TYPE_I, + .bSubframeSize = 2, + .bBitResolution = 16, + .bSamFreqType = 1, +}; + +/* Standard ISO OUT Endpoint Descriptor */ +static struct usb_endpoint_descriptor as_out_ep_desc __initdata = { + .bLength = USB_DT_ENDPOINT_AUDIO_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_OUT, + .bmAttributes = USB_AS_ENDPOINT_ADAPTIVE + | USB_ENDPOINT_XFER_ISOC, + .wMaxPacketSize = __constant_cpu_to_le16(OUT_EP_MAX_PACKET_SIZE), + .bInterval = 4, +}; + +/* Class-specific AS ISO OUT Endpoint Descriptor */ +static struct usb_as_iso_endpoint_descriptor as_iso_out_desc __initdata = { + .bLength = USB_AS_ISO_ENDPOINT_DESC_SIZE, + .bDescriptorType = USB_DT_CS_ENDPOINT, + .bDescriptorSubtype = EP_GENERAL, + .bmAttributes = 1, + .bLockDelayUnits = 1, + .wLockDelay = __constant_cpu_to_le16(1), +}; + +static struct usb_descriptor_header *f_audio_desc[] __initdata = { + (struct usb_descriptor_header *)&ac_interface_desc, + (struct usb_descriptor_header *)&ac_header_desc, + + (struct usb_descriptor_header *)&input_terminal_desc, + (struct usb_descriptor_header *)&output_terminal_desc, + (struct usb_descriptor_header *)&feature_unit_desc, + + (struct usb_descriptor_header *)&as_interface_alt_0_desc, + (struct usb_descriptor_header *)&as_interface_alt_1_desc, + (struct usb_descriptor_header *)&as_header_desc, + + (struct usb_descriptor_header *)&as_type_i_desc, + + (struct usb_descriptor_header *)&as_out_ep_desc, + (struct usb_descriptor_header *)&as_iso_out_desc, + NULL, +}; + +/* string IDs are assigned dynamically */ + +#define STRING_MANUFACTURER_IDX 0 +#define STRING_PRODUCT_IDX 1 + +static char manufacturer[50]; + +static struct usb_string strings_dev[] = { + [STRING_MANUFACTURER_IDX].s = manufacturer, + [STRING_PRODUCT_IDX].s = DRIVER_DESC, + { } /* end of list */ +}; + +static struct usb_gadget_strings stringtab_dev = { + .language = 0x0409, /* en-us */ + .strings = strings_dev, +}; + +static struct usb_gadget_strings *audio_strings[] = { + &stringtab_dev, + NULL, +}; + +/* + * This function is an ALSA sound card following USB Audio Class Spec 1.0. + */ + +/*-------------------------------------------------------------------------*/ +struct f_audio_buf { + u8 *buf; + int actual; + struct list_head list; +}; + +static struct f_audio_buf *f_audio_buffer_alloc(int buf_size) +{ + struct f_audio_buf *copy_buf; + + copy_buf = kzalloc(sizeof *copy_buf, GFP_ATOMIC); + if (!copy_buf) + return (struct f_audio_buf *)-ENOMEM; + + copy_buf->buf = kzalloc(buf_size, GFP_ATOMIC); + if (!copy_buf->buf) { + kfree(copy_buf); + return (struct f_audio_buf *)-ENOMEM; + } + + return copy_buf; +} + +static void f_audio_buffer_free(struct f_audio_buf *audio_buf) +{ + kfree(audio_buf->buf); + kfree(audio_buf); +} +/*-------------------------------------------------------------------------*/ + +struct f_audio { + struct gaudio card; + + /* endpoints handle full and/or high speeds */ + struct usb_ep *out_ep; + struct usb_endpoint_descriptor *out_desc; + + spinlock_t lock; + struct f_audio_buf *copy_buf; + struct work_struct playback_work; + struct list_head play_queue; + + /* Control Set command */ + struct list_head cs; + u8 set_cmd; + struct usb_audio_control *set_con; +}; + +static inline struct f_audio *func_to_audio(struct usb_function *f) +{ + return container_of(f, struct f_audio, card.func); +} + +/*-------------------------------------------------------------------------*/ + +static void f_audio_playback_work(struct work_struct *data) +{ + struct f_audio *audio = container_of(data, struct f_audio, + playback_work); + struct f_audio_buf *play_buf; + + spin_lock_irq(&audio->lock); + if (list_empty(&audio->play_queue)) { + spin_unlock_irq(&audio->lock); + return; + } + play_buf = list_first_entry(&audio->play_queue, + struct f_audio_buf, list); + list_del(&play_buf->list); + spin_unlock_irq(&audio->lock); + + u_audio_playback(&audio->card, play_buf->buf, play_buf->actual); + f_audio_buffer_free(play_buf); + + return; +} + +static int f_audio_out_ep_complete(struct usb_ep *ep, struct usb_request *req) +{ + struct f_audio *audio = req->context; + struct usb_composite_dev *cdev = audio->card.func.config->cdev; + struct f_audio_buf *copy_buf = audio->copy_buf; + int err; + + if (!copy_buf) + return -EINVAL; + + /* Copy buffer is full, add it to the play_queue */ + if (audio_buf_size - copy_buf->actual < req->actual) { + list_add_tail(©_buf->list, &audio->play_queue); + schedule_work(&audio->playback_work); + copy_buf = f_audio_buffer_alloc(audio_buf_size); + if (copy_buf < 0) + return -ENOMEM; + } + + memcpy(copy_buf->buf + copy_buf->actual, req->buf, req->actual); + copy_buf->actual += req->actual; + audio->copy_buf = copy_buf; + + err = usb_ep_queue(ep, req, GFP_ATOMIC); + if (err) + ERROR(cdev, "%s queue req: %d\n", ep->name, err); + + return 0; + +} + +static void f_audio_complete(struct usb_ep *ep, struct usb_request *req) +{ + struct f_audio *audio = req->context; + int status = req->status; + u32 data = 0; + struct usb_ep *out_ep = audio->out_ep; + + switch (status) { + + case 0: /* normal completion? */ + if (ep == out_ep) + f_audio_out_ep_complete(ep, req); + else if (audio->set_con) { + memcpy(&data, req->buf, req->length); + audio->set_con->set(audio->set_con, audio->set_cmd, + le16_to_cpu(data)); + audio->set_con = NULL; + } + break; + default: + break; + } +} + +static int audio_set_intf_req(struct usb_function *f, + const struct usb_ctrlrequest *ctrl) +{ + struct f_audio *audio = func_to_audio(f); + struct usb_composite_dev *cdev = f->config->cdev; + struct usb_request *req = cdev->req; + u8 id = ((le16_to_cpu(ctrl->wIndex) >> 8) & 0xFF); + u16 len = le16_to_cpu(ctrl->wLength); + u16 w_value = le16_to_cpu(ctrl->wValue); + u8 con_sel = (w_value >> 8) & 0xFF; + u8 cmd = (ctrl->bRequest & 0x0F); + struct usb_audio_control_selector *cs; + struct usb_audio_control *con; + + DBG(cdev, "bRequest 0x%x, w_value 0x%04x, len %d, entity %d\n", + ctrl->bRequest, w_value, len, id); + + list_for_each_entry(cs, &audio->cs, list) { + if (cs->id == id) { + list_for_each_entry(con, &cs->control, list) { + if (con->type == con_sel) { + audio->set_con = con; + break; + } + } + break; + } + } + + audio->set_cmd = cmd; + req->context = audio; + req->complete = f_audio_complete; + + return len; +} + +static int audio_get_intf_req(struct usb_function *f, + const struct usb_ctrlrequest *ctrl) +{ + struct f_audio *audio = func_to_audio(f); + struct usb_composite_dev *cdev = f->config->cdev; + struct usb_request *req = cdev->req; + int value = -EOPNOTSUPP; + u8 id = ((le16_to_cpu(ctrl->wIndex) >> 8) & 0xFF); + u16 len = le16_to_cpu(ctrl->wLength); + u16 w_value = le16_to_cpu(ctrl->wValue); + u8 con_sel = (w_value >> 8) & 0xFF; + u8 cmd = (ctrl->bRequest & 0x0F); + struct usb_audio_control_selector *cs; + struct usb_audio_control *con; + + DBG(cdev, "bRequest 0x%x, w_value 0x%04x, len %d, entity %d\n", + ctrl->bRequest, w_value, len, id); + + list_for_each_entry(cs, &audio->cs, list) { + if (cs->id == id) { + list_for_each_entry(con, &cs->control, list) { + if (con->type == con_sel && con->get) { + value = con->get(con, cmd); + break; + } + } + break; + } + } + + req->context = audio; + req->complete = f_audio_complete; + memcpy(req->buf, &value, len); + + return len; +} + +static int +f_audio_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) +{ + struct usb_composite_dev *cdev = f->config->cdev; + struct usb_request *req = cdev->req; + int value = -EOPNOTSUPP; + u16 w_index = le16_to_cpu(ctrl->wIndex); + u16 w_value = le16_to_cpu(ctrl->wValue); + u16 w_length = le16_to_cpu(ctrl->wLength); + + /* composite driver infrastructure handles everything except + * Audio class messages; interface activation uses set_alt(). + */ + switch (ctrl->bRequestType) { + case USB_AUDIO_SET_INTF: + value = audio_set_intf_req(f, ctrl); + break; + + case USB_AUDIO_GET_INTF: + value = audio_get_intf_req(f, ctrl); + break; + + default: + ERROR(cdev, "invalid control req%02x.%02x v%04x i%04x l%d\n", + ctrl->bRequestType, ctrl->bRequest, + w_value, w_index, w_length); + } + + /* respond with data transfer or status phase? */ + if (value >= 0) { + DBG(cdev, "audio req%02x.%02x v%04x i%04x l%d\n", + ctrl->bRequestType, ctrl->bRequest, + w_value, w_index, w_length); + req->zero = 0; + req->length = value; + value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC); + if (value < 0) + ERROR(cdev, "audio response on err %d\n", value); + } + + /* device either stalls (value < 0) or reports success */ + return value; +} + +static int f_audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt) +{ + struct f_audio *audio = func_to_audio(f); + struct usb_composite_dev *cdev = f->config->cdev; + struct usb_ep *out_ep = audio->out_ep; + struct usb_request *req; + int i = 0, err = 0; + + DBG(cdev, "intf %d, alt %d\n", intf, alt); + + if (intf == 1) { + if (alt == 1) { + usb_ep_enable(out_ep, audio->out_desc); + out_ep->driver_data = audio; + audio->copy_buf = f_audio_buffer_alloc(audio_buf_size); + + /* + * allocate a bunch of read buffers + * and queue them all at once. + */ + for (i = 0; i < req_count && err == 0; i++) { + req = usb_ep_alloc_request(out_ep, GFP_ATOMIC); + if (req) { + req->buf = kzalloc(req_buf_size, + GFP_ATOMIC); + if (req->buf) { + req->length = req_buf_size; + req->context = audio; + req->complete = + f_audio_complete; + err = usb_ep_queue(out_ep, + req, GFP_ATOMIC); + if (err) + ERROR(cdev, + "%s queue req: %d\n", + out_ep->name, err); + } else + err = -ENOMEM; + } else + err = -ENOMEM; + } + + } else { + struct f_audio_buf *copy_buf = audio->copy_buf; + if (copy_buf) { + list_add_tail(©_buf->list, + &audio->play_queue); + schedule_work(&audio->playback_work); + } + } + } + + return err; +} + +static void f_audio_disable(struct usb_function *f) +{ + return; +} + +/*-------------------------------------------------------------------------*/ + +static void f_audio_build_desc(struct f_audio *audio) +{ + struct gaudio *card = &audio->card; + u8 *sam_freq; + int rate; + + /* Set channel numbers */ + input_terminal_desc.bNrChannels = u_audio_get_playback_channels(card); + as_type_i_desc.bNrChannels = u_audio_get_playback_channels(card); + + /* Set sample rates */ + rate = u_audio_get_playback_rate(card); + sam_freq = as_type_i_desc.tSamFreq[0]; + memcpy(sam_freq, &rate, 3); + + /* Todo: Set Sample bits and other parameters */ + + return; +} + +/* audio function driver setup/binding */ +static int __init +f_audio_bind(struct usb_configuration *c, struct usb_function *f) +{ + struct usb_composite_dev *cdev = c->cdev; + struct f_audio *audio = func_to_audio(f); + int status; + struct usb_ep *ep; + + f_audio_build_desc(audio); + + /* allocate instance-specific interface IDs, and patch descriptors */ + status = usb_interface_id(c, f); + if (status < 0) + goto fail; + ac_interface_desc.bInterfaceNumber = status; + + status = usb_interface_id(c, f); + if (status < 0) + goto fail; + as_interface_alt_0_desc.bInterfaceNumber = status; + as_interface_alt_1_desc.bInterfaceNumber = status; + + status = -ENODEV; + + /* allocate instance-specific endpoints */ + ep = usb_ep_autoconfig(cdev->gadget, &as_out_ep_desc); + if (!ep) + goto fail; + audio->out_ep = ep; + ep->driver_data = cdev; /* claim */ + + status = -ENOMEM; + + /* supcard all relevant hardware speeds... we expect that when + * hardware is dual speed, all bulk-capable endpoints work at + * both speeds + */ + + /* copy descriptors, and track endpoint copies */ + if (gadget_is_dualspeed(c->cdev->gadget)) { + c->highspeed = true; + f->hs_descriptors = usb_copy_descriptors(f_audio_desc); + } else + f->descriptors = usb_copy_descriptors(f_audio_desc); + + return 0; + +fail: + + return status; +} + +static void +f_audio_unbind(struct usb_configuration *c, struct usb_function *f) +{ + struct f_audio *audio = func_to_audio(f); + + usb_free_descriptors(f->descriptors); + kfree(audio); +} + +/*-------------------------------------------------------------------------*/ + +/* Todo: add more control selecotor dynamically */ +int __init control_selector_init(struct f_audio *audio) +{ + INIT_LIST_HEAD(&audio->cs); + list_add(&feature_unit.list, &audio->cs); + + INIT_LIST_HEAD(&feature_unit.control); + list_add(&mute_control.list, &feature_unit.control); + list_add(&volume_control.list, &feature_unit.control); + + volume_control.data[_CUR] = 0xffc0; + volume_control.data[_MIN] = 0xe3a0; + volume_control.data[_MAX] = 0xfff0; + volume_control.data[_RES] = 0x0030; + + return 0; +} + +/** + * audio_bind_config - add USB audio fucntion to a configuration + * @c: the configuration to supcard the USB audio function + * Context: single threaded during gadget setup + * + * Returns zero on success, else negative errno. + */ +int __init audio_bind_config(struct usb_configuration *c) +{ + struct f_audio *audio; + int status; + + /* allocate and initialize one new instance */ + audio = kzalloc(sizeof *audio, GFP_KERNEL); + if (!audio) + return -ENOMEM; + + audio->card.func.name = "g_audio"; + audio->card.gadget = c->cdev->gadget; + + INIT_LIST_HEAD(&audio->play_queue); + spin_lock_init(&audio->lock); + + /* set up ASLA audio devices */ + status = gaudio_setup(&audio->card); + if (status < 0) + goto setup_fail; + + audio->card.func.strings = audio_strings; + audio->card.func.bind = f_audio_bind; + audio->card.func.unbind = f_audio_unbind; + audio->card.func.set_alt = f_audio_set_alt; + audio->card.func.setup = f_audio_setup; + audio->card.func.disable = f_audio_disable; + audio->out_desc = &as_out_ep_desc; + + control_selector_init(audio); + + INIT_WORK(&audio->playback_work, f_audio_playback_work); + + status = usb_add_function(c, &audio->card.func); + if (status) + goto add_fail; + + INFO(c->cdev, "audio_buf_size %d, req_buf_size %d, req_count %d\n", + audio_buf_size, req_buf_size, req_count); + + return status; + +add_fail: + gaudio_cleanup(&audio->card); +setup_fail: + kfree(audio); + return status; +} diff --git a/drivers/usb/gadget/f_phonet.c b/drivers/usb/gadget/f_phonet.c index c1abeb89b413..96fb118355b0 100644 --- a/drivers/usb/gadget/f_phonet.c +++ b/drivers/usb/gadget/f_phonet.c @@ -188,8 +188,7 @@ static struct usb_descriptor_header *hs_pn_function[] = { static int pn_net_open(struct net_device *dev) { - if (netif_carrier_ok(dev)) - netif_wake_queue(dev); + netif_wake_queue(dev); return 0; } @@ -219,8 +218,7 @@ static void pn_tx_complete(struct usb_ep *ep, struct usb_request *req) } dev_kfree_skb_any(skb); - if (netif_carrier_ok(dev)) - netif_wake_queue(dev); + netif_wake_queue(dev); } static int pn_net_xmit(struct sk_buff *skb, struct net_device *dev) @@ -255,7 +253,7 @@ out_unlock: spin_unlock_irqrestore(&port->lock, flags); out: if (unlikely(skb)) { - dev_kfree_skb_any(skb); + dev_kfree_skb(skb); dev->stats.tx_dropped++; } return 0; @@ -383,7 +381,6 @@ static void __pn_reset(struct usb_function *f) struct phonet_port *port = netdev_priv(dev); netif_carrier_off(dev); - netif_stop_queue(dev); port->usb = NULL; usb_ep_disable(fp->out_ep); @@ -427,8 +424,6 @@ static int pn_set_alt(struct usb_function *f, unsigned intf, unsigned alt) fp->in_ep->driver_data = fp; netif_carrier_on(dev); - if (netif_running(dev)) - netif_wake_queue(dev); for (i = 0; i < phonet_rxq_size; i++) pn_rx_submit(fp, fp->out_reqv[i], GFP_ATOMIC); } @@ -574,9 +569,10 @@ static struct net_device *dev; int __init phonet_bind_config(struct usb_configuration *c) { struct f_phonet *fp; - int err; + int err, size; - fp = kzalloc(sizeof(*fp), GFP_KERNEL); + size = sizeof(*fp) + (phonet_rxq_size * sizeof(struct usb_request *)); + fp = kzalloc(size, GFP_KERNEL); if (!fp) return -ENOMEM; @@ -601,16 +597,13 @@ int __init gphonet_setup(struct usb_gadget *gadget) /* Create net device */ BUG_ON(dev); - dev = alloc_netdev(sizeof(*port) - + (phonet_rxq_size * sizeof(struct usb_request *)), - "upnlink%d", pn_net_setup); + dev = alloc_netdev(sizeof(*port), "upnlink%d", pn_net_setup); if (!dev) return -ENOMEM; port = netdev_priv(dev); spin_lock_init(&port->lock); netif_carrier_off(dev); - netif_stop_queue(dev); SET_NETDEV_DEV(dev, &gadget->dev); err = register_netdev(dev); diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c index 3279a4726042..424a37c5773f 100644 --- a/drivers/usb/gadget/f_rndis.c +++ b/drivers/usb/gadget/f_rndis.c @@ -475,7 +475,9 @@ static int rndis_set_alt(struct usb_function *f, unsigned intf, unsigned alt) if (rndis->port.in_ep->driver_data) { DBG(cdev, "reset rndis\n"); gether_disconnect(&rndis->port); - } else { + } + + if (!rndis->port.in) { DBG(cdev, "init rndis\n"); rndis->port.in = ep_choose(cdev->gadget, rndis->hs.in, rndis->fs.in); diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 381a53b3e11c..1e6aa504d58a 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -248,6 +248,8 @@ #include #include +#include + #include #include @@ -799,29 +801,9 @@ static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep) /* Routines for unaligned data access */ -static u16 get_be16(u8 *buf) +static u32 get_unaligned_be24(u8 *buf) { - return ((u16) buf[0] << 8) | ((u16) buf[1]); -} - -static u32 get_be32(u8 *buf) -{ - return ((u32) buf[0] << 24) | ((u32) buf[1] << 16) | - ((u32) buf[2] << 8) | ((u32) buf[3]); -} - -static void put_be16(u8 *buf, u16 val) -{ - buf[0] = val >> 8; - buf[1] = val; -} - -static void put_be32(u8 *buf, u32 val) -{ - buf[0] = val >> 24; - buf[1] = val >> 16; - buf[2] = val >> 8; - buf[3] = val & 0xff; + return 0xffffff & (u32) get_unaligned_be32(buf - 1); } @@ -1582,9 +1564,9 @@ static int do_read(struct fsg_dev *fsg) /* Get the starting Logical Block Address and check that it's * not too big */ if (fsg->cmnd[0] == SC_READ_6) - lba = (fsg->cmnd[1] << 16) | get_be16(&fsg->cmnd[2]); + lba = get_unaligned_be24(&fsg->cmnd[1]); else { - lba = get_be32(&fsg->cmnd[2]); + lba = get_unaligned_be32(&fsg->cmnd[2]); /* We allow DPO (Disable Page Out = don't save data in the * cache) and FUA (Force Unit Access = don't read from the @@ -1717,9 +1699,9 @@ static int do_write(struct fsg_dev *fsg) /* Get the starting Logical Block Address and check that it's * not too big */ if (fsg->cmnd[0] == SC_WRITE_6) - lba = (fsg->cmnd[1] << 16) | get_be16(&fsg->cmnd[2]); + lba = get_unaligned_be24(&fsg->cmnd[1]); else { - lba = get_be32(&fsg->cmnd[2]); + lba = get_unaligned_be32(&fsg->cmnd[2]); /* We allow DPO (Disable Page Out = don't save data in the * cache) and FUA (Force Unit Access = write directly to the @@ -1940,7 +1922,7 @@ static int do_verify(struct fsg_dev *fsg) /* Get the starting Logical Block Address and check that it's * not too big */ - lba = get_be32(&fsg->cmnd[2]); + lba = get_unaligned_be32(&fsg->cmnd[2]); if (lba >= curlun->num_sectors) { curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; return -EINVAL; @@ -1953,7 +1935,7 @@ static int do_verify(struct fsg_dev *fsg) return -EINVAL; } - verification_length = get_be16(&fsg->cmnd[7]); + verification_length = get_unaligned_be16(&fsg->cmnd[7]); if (unlikely(verification_length == 0)) return -EIO; // No default reply @@ -2103,7 +2085,7 @@ static int do_request_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh) memset(buf, 0, 18); buf[0] = valid | 0x70; // Valid, current error buf[2] = SK(sd); - put_be32(&buf[3], sdinfo); // Sense information + put_unaligned_be32(sdinfo, &buf[3]); /* Sense information */ buf[7] = 18 - 8; // Additional sense length buf[12] = ASC(sd); buf[13] = ASCQ(sd); @@ -2114,7 +2096,7 @@ static int do_request_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh) static int do_read_capacity(struct fsg_dev *fsg, struct fsg_buffhd *bh) { struct lun *curlun = fsg->curlun; - u32 lba = get_be32(&fsg->cmnd[2]); + u32 lba = get_unaligned_be32(&fsg->cmnd[2]); int pmi = fsg->cmnd[8]; u8 *buf = (u8 *) bh->buf; @@ -2124,8 +2106,9 @@ static int do_read_capacity(struct fsg_dev *fsg, struct fsg_buffhd *bh) return -EINVAL; } - put_be32(&buf[0], curlun->num_sectors - 1); // Max logical block - put_be32(&buf[4], 512); // Block length + put_unaligned_be32(curlun->num_sectors - 1, &buf[0]); + /* Max logical block */ + put_unaligned_be32(512, &buf[4]); /* Block length */ return 8; } @@ -2144,7 +2127,7 @@ static void store_cdrom_address(u8 *dest, int msf, u32 addr) dest[0] = 0; /* Reserved */ } else { /* Absolute sector */ - put_be32(dest, addr); + put_unaligned_be32(addr, dest); } } @@ -2152,7 +2135,7 @@ static int do_read_header(struct fsg_dev *fsg, struct fsg_buffhd *bh) { struct lun *curlun = fsg->curlun; int msf = fsg->cmnd[1] & 0x02; - u32 lba = get_be32(&fsg->cmnd[2]); + u32 lba = get_unaligned_be32(&fsg->cmnd[2]); u8 *buf = (u8 *) bh->buf; if ((fsg->cmnd[1] & ~0x02) != 0) { /* Mask away MSF */ @@ -2252,10 +2235,13 @@ static int do_mode_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh) buf[2] = 0x04; // Write cache enable, // Read cache not disabled // No cache retention priorities - put_be16(&buf[4], 0xffff); // Don't disable prefetch - // Minimum prefetch = 0 - put_be16(&buf[8], 0xffff); // Maximum prefetch - put_be16(&buf[10], 0xffff); // Maximum prefetch ceiling + put_unaligned_be16(0xffff, &buf[4]); + /* Don't disable prefetch */ + /* Minimum prefetch = 0 */ + put_unaligned_be16(0xffff, &buf[8]); + /* Maximum prefetch */ + put_unaligned_be16(0xffff, &buf[10]); + /* Maximum prefetch ceiling */ } buf += 12; } @@ -2272,7 +2258,7 @@ static int do_mode_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh) if (mscmnd == SC_MODE_SENSE_6) buf0[0] = len - 1; else - put_be16(buf0, len - 2); + put_unaligned_be16(len - 2, buf0); return len; } @@ -2360,9 +2346,10 @@ static int do_read_format_capacities(struct fsg_dev *fsg, buf[3] = 8; // Only the Current/Maximum Capacity Descriptor buf += 4; - put_be32(&buf[0], curlun->num_sectors); // Number of blocks - put_be32(&buf[4], 512); // Block length - buf[4] = 0x02; // Current capacity + put_unaligned_be32(curlun->num_sectors, &buf[0]); + /* Number of blocks */ + put_unaligned_be32(512, &buf[4]); /* Block length */ + buf[4] = 0x02; /* Current capacity */ return 12; } @@ -2882,7 +2869,7 @@ static int do_scsi_command(struct fsg_dev *fsg) break; case SC_MODE_SELECT_10: - fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]); + fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]); if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST, (1<<1) | (3<<7), 0, "MODE SELECT(10)")) == 0) @@ -2898,7 +2885,7 @@ static int do_scsi_command(struct fsg_dev *fsg) break; case SC_MODE_SENSE_10: - fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]); + fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]); if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, (1<<1) | (1<<2) | (3<<7), 0, "MODE SENSE(10)")) == 0) @@ -2923,7 +2910,8 @@ static int do_scsi_command(struct fsg_dev *fsg) break; case SC_READ_10: - fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]) << 9; + fsg->data_size_from_cmnd = + get_unaligned_be16(&fsg->cmnd[7]) << 9; if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, (1<<1) | (0xf<<2) | (3<<7), 1, "READ(10)")) == 0) @@ -2931,7 +2919,8 @@ static int do_scsi_command(struct fsg_dev *fsg) break; case SC_READ_12: - fsg->data_size_from_cmnd = get_be32(&fsg->cmnd[6]) << 9; + fsg->data_size_from_cmnd = + get_unaligned_be32(&fsg->cmnd[6]) << 9; if ((reply = check_command(fsg, 12, DATA_DIR_TO_HOST, (1<<1) | (0xf<<2) | (0xf<<6), 1, "READ(12)")) == 0) @@ -2949,7 +2938,7 @@ static int do_scsi_command(struct fsg_dev *fsg) case SC_READ_HEADER: if (!mod_data.cdrom) goto unknown_cmnd; - fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]); + fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]); if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, (3<<7) | (0x1f<<1), 1, "READ HEADER")) == 0) @@ -2959,7 +2948,7 @@ static int do_scsi_command(struct fsg_dev *fsg) case SC_READ_TOC: if (!mod_data.cdrom) goto unknown_cmnd; - fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]); + fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]); if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, (7<<6) | (1<<1), 1, "READ TOC")) == 0) @@ -2967,7 +2956,7 @@ static int do_scsi_command(struct fsg_dev *fsg) break; case SC_READ_FORMAT_CAPACITIES: - fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]); + fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]); if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, (3<<7), 1, "READ FORMAT CAPACITIES")) == 0) @@ -3025,7 +3014,8 @@ static int do_scsi_command(struct fsg_dev *fsg) break; case SC_WRITE_10: - fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]) << 9; + fsg->data_size_from_cmnd = + get_unaligned_be16(&fsg->cmnd[7]) << 9; if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST, (1<<1) | (0xf<<2) | (3<<7), 1, "WRITE(10)")) == 0) @@ -3033,7 +3023,8 @@ static int do_scsi_command(struct fsg_dev *fsg) break; case SC_WRITE_12: - fsg->data_size_from_cmnd = get_be32(&fsg->cmnd[6]) << 9; + fsg->data_size_from_cmnd = + get_unaligned_be32(&fsg->cmnd[6]) << 9; if ((reply = check_command(fsg, 12, DATA_DIR_FROM_HOST, (1<<1) | (0xf<<2) | (0xf<<6), 1, "WRITE(12)")) == 0) diff --git a/drivers/usb/gadget/fsl_mx3_udc.c b/drivers/usb/gadget/fsl_mx3_udc.c new file mode 100644 index 000000000000..4bc2bf3d602e --- /dev/null +++ b/drivers/usb/gadget/fsl_mx3_udc.c @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2009 + * Guennadi Liakhovetski, DENX Software Engineering, + * + * Description: + * Helper routines for i.MX3x SoCs from Freescale, needed by the fsl_usb2_udc.c + * driver to function correctly on these systems. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +#include +#include +#include +#include +#include + +static struct clk *mxc_ahb_clk; +static struct clk *mxc_usb_clk; + +int fsl_udc_clk_init(struct platform_device *pdev) +{ + struct fsl_usb2_platform_data *pdata; + unsigned long freq; + int ret; + + pdata = pdev->dev.platform_data; + + mxc_ahb_clk = clk_get(&pdev->dev, "usb_ahb"); + if (IS_ERR(mxc_ahb_clk)) + return PTR_ERR(mxc_ahb_clk); + + ret = clk_enable(mxc_ahb_clk); + if (ret < 0) { + dev_err(&pdev->dev, "clk_enable(\"usb_ahb\") failed\n"); + goto eenahb; + } + + /* make sure USB_CLK is running at 60 MHz +/- 1000 Hz */ + mxc_usb_clk = clk_get(&pdev->dev, "usb"); + if (IS_ERR(mxc_usb_clk)) { + dev_err(&pdev->dev, "clk_get(\"usb\") failed\n"); + ret = PTR_ERR(mxc_usb_clk); + goto egusb; + } + + freq = clk_get_rate(mxc_usb_clk); + if (pdata->phy_mode != FSL_USB2_PHY_ULPI && + (freq < 59999000 || freq > 60001000)) { + dev_err(&pdev->dev, "USB_CLK=%lu, should be 60MHz\n", freq); + goto eclkrate; + } + + ret = clk_enable(mxc_usb_clk); + if (ret < 0) { + dev_err(&pdev->dev, "clk_enable(\"usb_clk\") failed\n"); + goto eenusb; + } + + return 0; + +eenusb: +eclkrate: + clk_put(mxc_usb_clk); + mxc_usb_clk = NULL; +egusb: + clk_disable(mxc_ahb_clk); +eenahb: + clk_put(mxc_ahb_clk); + return ret; +} + +void fsl_udc_clk_finalize(struct platform_device *pdev) +{ + struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; + + /* ULPI transceivers don't need usbpll */ + if (pdata->phy_mode == FSL_USB2_PHY_ULPI) { + clk_disable(mxc_usb_clk); + clk_put(mxc_usb_clk); + mxc_usb_clk = NULL; + } +} + +void fsl_udc_clk_release(void) +{ + if (mxc_usb_clk) { + clk_disable(mxc_usb_clk); + clk_put(mxc_usb_clk); + } + clk_disable(mxc_ahb_clk); + clk_put(mxc_ahb_clk); +} diff --git a/drivers/usb/gadget/fsl_usb2_udc.c b/drivers/usb/gadget/fsl_udc_core.c similarity index 99% rename from drivers/usb/gadget/fsl_usb2_udc.c rename to drivers/usb/gadget/fsl_udc_core.c index 9d7b95d4e3d2..42a74b8a0bb8 100644 --- a/drivers/usb/gadget/fsl_usb2_udc.c +++ b/drivers/usb/gadget/fsl_udc_core.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -57,7 +58,9 @@ static const char driver_name[] = "fsl-usb2-udc"; static const char driver_desc[] = DRIVER_DESC; static struct usb_dr_device *dr_regs; +#ifndef CONFIG_ARCH_MXC static struct usb_sys_interface *usb_sys_regs; +#endif /* it is initialized in probe() */ static struct fsl_udc *udc_controller = NULL; @@ -174,10 +177,34 @@ static void nuke(struct fsl_ep *ep, int status) static int dr_controller_setup(struct fsl_udc *udc) { - unsigned int tmp = 0, portctrl = 0, ctrl = 0; + unsigned int tmp, portctrl; +#ifndef CONFIG_ARCH_MXC + unsigned int ctrl; +#endif unsigned long timeout; #define FSL_UDC_RESET_TIMEOUT 1000 + /* Config PHY interface */ + portctrl = fsl_readl(&dr_regs->portsc1); + portctrl &= ~(PORTSCX_PHY_TYPE_SEL | PORTSCX_PORT_WIDTH); + switch (udc->phy_mode) { + case FSL_USB2_PHY_ULPI: + portctrl |= PORTSCX_PTS_ULPI; + break; + case FSL_USB2_PHY_UTMI_WIDE: + portctrl |= PORTSCX_PTW_16BIT; + /* fall through */ + case FSL_USB2_PHY_UTMI: + portctrl |= PORTSCX_PTS_UTMI; + break; + case FSL_USB2_PHY_SERIAL: + portctrl |= PORTSCX_PTS_FSLS; + break; + default: + return -EINVAL; + } + fsl_writel(portctrl, &dr_regs->portsc1); + /* Stop and reset the usb controller */ tmp = fsl_readl(&dr_regs->usbcmd); tmp &= ~USB_CMD_RUN_STOP; @@ -215,31 +242,12 @@ static int dr_controller_setup(struct fsl_udc *udc) udc->ep_qh, (int)tmp, fsl_readl(&dr_regs->endpointlistaddr)); - /* Config PHY interface */ - portctrl = fsl_readl(&dr_regs->portsc1); - portctrl &= ~(PORTSCX_PHY_TYPE_SEL | PORTSCX_PORT_WIDTH); - switch (udc->phy_mode) { - case FSL_USB2_PHY_ULPI: - portctrl |= PORTSCX_PTS_ULPI; - break; - case FSL_USB2_PHY_UTMI_WIDE: - portctrl |= PORTSCX_PTW_16BIT; - /* fall through */ - case FSL_USB2_PHY_UTMI: - portctrl |= PORTSCX_PTS_UTMI; - break; - case FSL_USB2_PHY_SERIAL: - portctrl |= PORTSCX_PTS_FSLS; - break; - default: - return -EINVAL; - } - fsl_writel(portctrl, &dr_regs->portsc1); - /* Config control enable i/o output, cpu endian register */ +#ifndef CONFIG_ARCH_MXC ctrl = __raw_readl(&usb_sys_regs->control); ctrl |= USB_CTRL_IOENB; __raw_writel(ctrl, &usb_sys_regs->control); +#endif #if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE) /* Turn on cache snooping hardware, since some PowerPC platforms @@ -2043,6 +2051,7 @@ static int fsl_proc_read(char *page, char **start, off_t off, int count, size -= t; next += t; +#ifndef CONFIG_ARCH_MXC tmp_reg = usb_sys_regs->snoop1; t = scnprintf(next, size, "Snoop1 Reg : = [0x%x]\n\n", tmp_reg); size -= t; @@ -2053,6 +2062,7 @@ static int fsl_proc_read(char *page, char **start, off_t off, int count, tmp_reg); size -= t; next += t; +#endif /* ------fsl_udc, fsl_ep, fsl_request structure information ----- */ ep = &udc->eps[0]; @@ -2263,14 +2273,21 @@ static int __init fsl_udc_probe(struct platform_device *pdev) goto err_kfree; } - dr_regs = ioremap(res->start, res->end - res->start + 1); + dr_regs = ioremap(res->start, resource_size(res)); if (!dr_regs) { ret = -ENOMEM; goto err_release_mem_region; } +#ifndef CONFIG_ARCH_MXC usb_sys_regs = (struct usb_sys_interface *) ((u32)dr_regs + USB_DR_SYS_OFFSET); +#endif + + /* Initialize USB clocks */ + ret = fsl_udc_clk_init(pdev); + if (ret < 0) + goto err_iounmap_noclk; /* Read Device Controller Capability Parameters register */ dccparams = fsl_readl(&dr_regs->dccparams); @@ -2308,6 +2325,8 @@ static int __init fsl_udc_probe(struct platform_device *pdev) * leave usbintr reg untouched */ dr_controller_setup(udc_controller); + fsl_udc_clk_finalize(pdev); + /* Setup gadget structure */ udc_controller->gadget.ops = &fsl_gadget_ops; udc_controller->gadget.is_dualspeed = 1; @@ -2362,6 +2381,8 @@ err_unregister: err_free_irq: free_irq(udc_controller->irq, udc_controller); err_iounmap: + fsl_udc_clk_release(); +err_iounmap_noclk: iounmap(dr_regs); err_release_mem_region: release_mem_region(res->start, res->end - res->start + 1); @@ -2384,6 +2405,8 @@ static int __exit fsl_udc_remove(struct platform_device *pdev) return -ENODEV; udc_controller->done = &done; + fsl_udc_clk_release(); + /* DR has been stopped in usb_gadget_unregister_driver() */ remove_proc_file(); diff --git a/drivers/usb/gadget/fsl_usb2_udc.h b/drivers/usb/gadget/fsl_usb2_udc.h index e63ef12645f5..20aeceed48c7 100644 --- a/drivers/usb/gadget/fsl_usb2_udc.h +++ b/drivers/usb/gadget/fsl_usb2_udc.h @@ -563,4 +563,22 @@ static void dump_msg(const char *label, const u8 * buf, unsigned int length) * 2 + ((windex & USB_DIR_IN) ? 1 : 0)) #define get_pipe_by_ep(EP) (ep_index(EP) * 2 + ep_is_in(EP)) +struct platform_device; +#ifdef CONFIG_ARCH_MXC +int fsl_udc_clk_init(struct platform_device *pdev); +void fsl_udc_clk_finalize(struct platform_device *pdev); +void fsl_udc_clk_release(void); +#else +static inline int fsl_udc_clk_init(struct platform_device *pdev) +{ + return 0; +} +static inline void fsl_udc_clk_finalize(struct platform_device *pdev) +{ +} +static inline void fsl_udc_clk_release(void) +{ +} +#endif + #endif diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h index ec6d439a2aa5..8e0e9a0b7364 100644 --- a/drivers/usb/gadget/gadget_chips.h +++ b/drivers/usb/gadget/gadget_chips.h @@ -137,6 +137,12 @@ #define gadget_is_musbhdrc(g) 0 #endif +#ifdef CONFIG_USB_GADGET_LANGWELL +#define gadget_is_langwell(g) (!strcmp("langwell_udc", (g)->name)) +#else +#define gadget_is_langwell(g) 0 +#endif + /* from Montavista kernel (?) */ #ifdef CONFIG_USB_GADGET_MPC8272 #define gadget_is_mpc8272(g) !strcmp("mpc8272_udc", (g)->name) @@ -231,6 +237,8 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget) return 0x22; else if (gadget_is_ci13xxx(gadget)) return 0x23; + else if (gadget_is_langwell(gadget)) + return 0x24; return -ENOENT; } diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index de010c939dbb..112bb40a427c 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -110,10 +110,10 @@ goku_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) return -EINVAL; if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) return -ESHUTDOWN; - if (ep->num != (desc->bEndpointAddress & 0x0f)) + if (ep->num != usb_endpoint_num(desc)) return -EINVAL; - switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { + switch (usb_endpoint_type(desc)) { case USB_ENDPOINT_XFER_BULK: case USB_ENDPOINT_XFER_INT: break; @@ -142,7 +142,7 @@ goku_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) /* ep1/ep2 dma direction is chosen early; it works in the other * direction, with pio. be cautious with out-dma. */ - ep->is_in = (USB_DIR_IN & desc->bEndpointAddress) != 0; + ep->is_in = usb_endpoint_dir_in(desc); if (ep->is_in) { mode |= 1; ep->dma = (use_dma != 0) && (ep->num == UDC_MSTRD_ENDPOINT); diff --git a/drivers/usb/gadget/imx_udc.c b/drivers/usb/gadget/imx_udc.c index 168658b4b4e2..c52a681f376c 100644 --- a/drivers/usb/gadget/imx_udc.c +++ b/drivers/usb/gadget/imx_udc.c @@ -415,6 +415,13 @@ static int write_packet(struct imx_ep_struct *imx_ep, struct imx_request *req) u8 *buf; int length, count, temp; + if (unlikely(__raw_readl(imx_ep->imx_usb->base + + USB_EP_STAT(EP_NO(imx_ep))) & EPSTAT_ZLPS)) { + D_TRX(imx_ep->imx_usb->dev, "<%s> zlp still queued in EP %s\n", + __func__, imx_ep->ep.name); + return -1; + } + buf = req->req.buf + req->req.actual; prefetch(buf); @@ -734,9 +741,12 @@ static struct usb_request *imx_ep_alloc_request { struct imx_request *req; + if (!usb_ep) + return NULL; + req = kzalloc(sizeof *req, gfp_flags); - if (!req || !usb_ep) - return 0; + if (!req) + return NULL; INIT_LIST_HEAD(&req->queue); req->in_use = 0; diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index d20937f28a19..7d33f50b5874 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -384,9 +384,8 @@ ep_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr) return value; /* halt any endpoint by doing a "wrong direction" i/o call */ - if (data->desc.bEndpointAddress & USB_DIR_IN) { - if ((data->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - == USB_ENDPOINT_XFER_ISOC) + if (usb_endpoint_dir_in(&data->desc)) { + if (usb_endpoint_xfer_isoc(&data->desc)) return -EINVAL; DBG (data->dev, "%s halt\n", data->name); spin_lock_irq (&data->dev->lock); @@ -428,9 +427,8 @@ ep_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) return value; /* halt any endpoint by doing a "wrong direction" i/o call */ - if (!(data->desc.bEndpointAddress & USB_DIR_IN)) { - if ((data->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - == USB_ENDPOINT_XFER_ISOC) + if (!usb_endpoint_dir_in(&data->desc)) { + if (usb_endpoint_xfer_isoc(&data->desc)) return -EINVAL; DBG (data->dev, "%s halt\n", data->name); spin_lock_irq (&data->dev->lock); @@ -691,7 +689,7 @@ ep_aio_read(struct kiocb *iocb, const struct iovec *iov, struct ep_data *epdata = iocb->ki_filp->private_data; char *buf; - if (unlikely(epdata->desc.bEndpointAddress & USB_DIR_IN)) + if (unlikely(usb_endpoint_dir_in(&epdata->desc))) return -EINVAL; buf = kmalloc(iocb->ki_left, GFP_KERNEL); @@ -711,7 +709,7 @@ ep_aio_write(struct kiocb *iocb, const struct iovec *iov, size_t len = 0; int i = 0; - if (unlikely(!(epdata->desc.bEndpointAddress & USB_DIR_IN))) + if (unlikely(!usb_endpoint_dir_in(&epdata->desc))) return -EINVAL; buf = kmalloc(iocb->ki_left, GFP_KERNEL); diff --git a/drivers/usb/gadget/langwell_udc.c b/drivers/usb/gadget/langwell_udc.c new file mode 100644 index 000000000000..6829d5961359 --- /dev/null +++ b/drivers/usb/gadget/langwell_udc.c @@ -0,0 +1,3373 @@ +/* + * Intel Langwell USB Device Controller driver + * Copyright (C) 2008-2009, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + + +/* #undef DEBUG */ +/* #undef VERBOSE */ + +#if defined(CONFIG_USB_LANGWELL_OTG) +#define OTG_TRANSCEIVER +#endif + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "langwell_udc.h" + + +#define DRIVER_DESC "Intel Langwell USB Device Controller driver" +#define DRIVER_VERSION "16 May 2009" + +static const char driver_name[] = "langwell_udc"; +static const char driver_desc[] = DRIVER_DESC; + + +/* controller device global variable */ +static struct langwell_udc *the_controller; + +/* for endpoint 0 operations */ +static const struct usb_endpoint_descriptor +langwell_ep0_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0, + .bmAttributes = USB_ENDPOINT_XFER_CONTROL, + .wMaxPacketSize = EP0_MAX_PKT_SIZE, +}; + + +/*-------------------------------------------------------------------------*/ +/* debugging */ + +#ifdef DEBUG +#define DBG(dev, fmt, args...) \ + pr_debug("%s %s: " fmt , driver_name, \ + pci_name(dev->pdev), ## args) +#else +#define DBG(dev, fmt, args...) \ + do { } while (0) +#endif /* DEBUG */ + + +#ifdef VERBOSE +#define VDBG DBG +#else +#define VDBG(dev, fmt, args...) \ + do { } while (0) +#endif /* VERBOSE */ + + +#define ERROR(dev, fmt, args...) \ + pr_err("%s %s: " fmt , driver_name, \ + pci_name(dev->pdev), ## args) + +#define WARNING(dev, fmt, args...) \ + pr_warning("%s %s: " fmt , driver_name, \ + pci_name(dev->pdev), ## args) + +#define INFO(dev, fmt, args...) \ + pr_info("%s %s: " fmt , driver_name, \ + pci_name(dev->pdev), ## args) + + +#ifdef VERBOSE +static inline void print_all_registers(struct langwell_udc *dev) +{ + int i; + + /* Capability Registers */ + printk(KERN_DEBUG "Capability Registers (offset: " + "0x%04x, length: 0x%08x)\n", + CAP_REG_OFFSET, + (u32)sizeof(struct langwell_cap_regs)); + printk(KERN_DEBUG "caplength=0x%02x\n", + readb(&dev->cap_regs->caplength)); + printk(KERN_DEBUG "hciversion=0x%04x\n", + readw(&dev->cap_regs->hciversion)); + printk(KERN_DEBUG "hcsparams=0x%08x\n", + readl(&dev->cap_regs->hcsparams)); + printk(KERN_DEBUG "hccparams=0x%08x\n", + readl(&dev->cap_regs->hccparams)); + printk(KERN_DEBUG "dciversion=0x%04x\n", + readw(&dev->cap_regs->dciversion)); + printk(KERN_DEBUG "dccparams=0x%08x\n", + readl(&dev->cap_regs->dccparams)); + + /* Operational Registers */ + printk(KERN_DEBUG "Operational Registers (offset: " + "0x%04x, length: 0x%08x)\n", + OP_REG_OFFSET, + (u32)sizeof(struct langwell_op_regs)); + printk(KERN_DEBUG "extsts=0x%08x\n", + readl(&dev->op_regs->extsts)); + printk(KERN_DEBUG "extintr=0x%08x\n", + readl(&dev->op_regs->extintr)); + printk(KERN_DEBUG "usbcmd=0x%08x\n", + readl(&dev->op_regs->usbcmd)); + printk(KERN_DEBUG "usbsts=0x%08x\n", + readl(&dev->op_regs->usbsts)); + printk(KERN_DEBUG "usbintr=0x%08x\n", + readl(&dev->op_regs->usbintr)); + printk(KERN_DEBUG "frindex=0x%08x\n", + readl(&dev->op_regs->frindex)); + printk(KERN_DEBUG "ctrldssegment=0x%08x\n", + readl(&dev->op_regs->ctrldssegment)); + printk(KERN_DEBUG "deviceaddr=0x%08x\n", + readl(&dev->op_regs->deviceaddr)); + printk(KERN_DEBUG "endpointlistaddr=0x%08x\n", + readl(&dev->op_regs->endpointlistaddr)); + printk(KERN_DEBUG "ttctrl=0x%08x\n", + readl(&dev->op_regs->ttctrl)); + printk(KERN_DEBUG "burstsize=0x%08x\n", + readl(&dev->op_regs->burstsize)); + printk(KERN_DEBUG "txfilltuning=0x%08x\n", + readl(&dev->op_regs->txfilltuning)); + printk(KERN_DEBUG "txttfilltuning=0x%08x\n", + readl(&dev->op_regs->txttfilltuning)); + printk(KERN_DEBUG "ic_usb=0x%08x\n", + readl(&dev->op_regs->ic_usb)); + printk(KERN_DEBUG "ulpi_viewport=0x%08x\n", + readl(&dev->op_regs->ulpi_viewport)); + printk(KERN_DEBUG "configflag=0x%08x\n", + readl(&dev->op_regs->configflag)); + printk(KERN_DEBUG "portsc1=0x%08x\n", + readl(&dev->op_regs->portsc1)); + printk(KERN_DEBUG "devlc=0x%08x\n", + readl(&dev->op_regs->devlc)); + printk(KERN_DEBUG "otgsc=0x%08x\n", + readl(&dev->op_regs->otgsc)); + printk(KERN_DEBUG "usbmode=0x%08x\n", + readl(&dev->op_regs->usbmode)); + printk(KERN_DEBUG "endptnak=0x%08x\n", + readl(&dev->op_regs->endptnak)); + printk(KERN_DEBUG "endptnaken=0x%08x\n", + readl(&dev->op_regs->endptnaken)); + printk(KERN_DEBUG "endptsetupstat=0x%08x\n", + readl(&dev->op_regs->endptsetupstat)); + printk(KERN_DEBUG "endptprime=0x%08x\n", + readl(&dev->op_regs->endptprime)); + printk(KERN_DEBUG "endptflush=0x%08x\n", + readl(&dev->op_regs->endptflush)); + printk(KERN_DEBUG "endptstat=0x%08x\n", + readl(&dev->op_regs->endptstat)); + printk(KERN_DEBUG "endptcomplete=0x%08x\n", + readl(&dev->op_regs->endptcomplete)); + + for (i = 0; i < dev->ep_max / 2; i++) { + printk(KERN_DEBUG "endptctrl[%d]=0x%08x\n", + i, readl(&dev->op_regs->endptctrl[i])); + } +} +#endif /* VERBOSE */ + + +/*-------------------------------------------------------------------------*/ + +#define DIR_STRING(bAddress) (((bAddress) & USB_DIR_IN) ? "in" : "out") + +#define is_in(ep) (((ep)->ep_num == 0) ? ((ep)->dev->ep0_dir == \ + USB_DIR_IN) : ((ep)->desc->bEndpointAddress \ + & USB_DIR_IN) == USB_DIR_IN) + + +#ifdef DEBUG +static char *type_string(u8 bmAttributes) +{ + switch ((bmAttributes) & USB_ENDPOINT_XFERTYPE_MASK) { + case USB_ENDPOINT_XFER_BULK: + return "bulk"; + case USB_ENDPOINT_XFER_ISOC: + return "iso"; + case USB_ENDPOINT_XFER_INT: + return "int"; + }; + + return "control"; +} +#endif + + +/* configure endpoint control registers */ +static void ep_reset(struct langwell_ep *ep, unsigned char ep_num, + unsigned char is_in, unsigned char ep_type) +{ + struct langwell_udc *dev; + u32 endptctrl; + + dev = ep->dev; + VDBG(dev, "---> %s()\n", __func__); + + endptctrl = readl(&dev->op_regs->endptctrl[ep_num]); + if (is_in) { /* TX */ + if (ep_num) + endptctrl |= EPCTRL_TXR; + endptctrl |= EPCTRL_TXE; + endptctrl |= ep_type << EPCTRL_TXT_SHIFT; + } else { /* RX */ + if (ep_num) + endptctrl |= EPCTRL_RXR; + endptctrl |= EPCTRL_RXE; + endptctrl |= ep_type << EPCTRL_RXT_SHIFT; + } + + writel(endptctrl, &dev->op_regs->endptctrl[ep_num]); + + VDBG(dev, "<--- %s()\n", __func__); +} + + +/* reset ep0 dQH and endptctrl */ +static void ep0_reset(struct langwell_udc *dev) +{ + struct langwell_ep *ep; + int i; + + VDBG(dev, "---> %s()\n", __func__); + + /* ep0 in and out */ + for (i = 0; i < 2; i++) { + ep = &dev->ep[i]; + ep->dev = dev; + + /* ep0 dQH */ + ep->dqh = &dev->ep_dqh[i]; + + /* configure ep0 endpoint capabilities in dQH */ + ep->dqh->dqh_ios = 1; + ep->dqh->dqh_mpl = EP0_MAX_PKT_SIZE; + + /* FIXME: enable ep0-in HW zero length termination select */ + if (is_in(ep)) + ep->dqh->dqh_zlt = 0; + ep->dqh->dqh_mult = 0; + + /* configure ep0 control registers */ + ep_reset(&dev->ep[0], 0, i, USB_ENDPOINT_XFER_CONTROL); + } + + VDBG(dev, "<--- %s()\n", __func__); + return; +} + + +/*-------------------------------------------------------------------------*/ + +/* endpoints operations */ + +/* configure endpoint, making it usable */ +static int langwell_ep_enable(struct usb_ep *_ep, + const struct usb_endpoint_descriptor *desc) +{ + struct langwell_udc *dev; + struct langwell_ep *ep; + u16 max = 0; + unsigned long flags; + int retval = 0; + unsigned char zlt, ios = 0, mult = 0; + + ep = container_of(_ep, struct langwell_ep, ep); + dev = ep->dev; + VDBG(dev, "---> %s()\n", __func__); + + if (!_ep || !desc || ep->desc + || desc->bDescriptorType != USB_DT_ENDPOINT) + return -EINVAL; + + if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) + return -ESHUTDOWN; + + max = le16_to_cpu(desc->wMaxPacketSize); + + /* + * disable HW zero length termination select + * driver handles zero length packet through req->req.zero + */ + zlt = 1; + + /* + * sanity check type, direction, address, and then + * initialize the endpoint capabilities fields in dQH + */ + switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { + case USB_ENDPOINT_XFER_CONTROL: + ios = 1; + break; + case USB_ENDPOINT_XFER_BULK: + if ((dev->gadget.speed == USB_SPEED_HIGH + && max != 512) + || (dev->gadget.speed == USB_SPEED_FULL + && max > 64)) { + goto done; + } + break; + case USB_ENDPOINT_XFER_INT: + if (strstr(ep->ep.name, "-iso")) /* bulk is ok */ + goto done; + + switch (dev->gadget.speed) { + case USB_SPEED_HIGH: + if (max <= 1024) + break; + case USB_SPEED_FULL: + if (max <= 64) + break; + default: + if (max <= 8) + break; + goto done; + } + break; + case USB_ENDPOINT_XFER_ISOC: + if (strstr(ep->ep.name, "-bulk") + || strstr(ep->ep.name, "-int")) + goto done; + + switch (dev->gadget.speed) { + case USB_SPEED_HIGH: + if (max <= 1024) + break; + case USB_SPEED_FULL: + if (max <= 1023) + break; + default: + goto done; + } + /* + * FIXME: + * calculate transactions needed for high bandwidth iso + */ + mult = (unsigned char)(1 + ((max >> 11) & 0x03)); + max = max & 0x8ff; /* bit 0~10 */ + /* 3 transactions at most */ + if (mult > 3) + goto done; + break; + default: + goto done; + } + + spin_lock_irqsave(&dev->lock, flags); + + /* configure endpoint capabilities in dQH */ + ep->dqh->dqh_ios = ios; + ep->dqh->dqh_mpl = cpu_to_le16(max); + ep->dqh->dqh_zlt = zlt; + ep->dqh->dqh_mult = mult; + + ep->ep.maxpacket = max; + ep->desc = desc; + ep->stopped = 0; + ep->ep_num = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; + + /* ep_type */ + ep->ep_type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; + + /* configure endpoint control registers */ + ep_reset(ep, ep->ep_num, is_in(ep), ep->ep_type); + + DBG(dev, "enabled %s (ep%d%s-%s), max %04x\n", + _ep->name, + ep->ep_num, + DIR_STRING(desc->bEndpointAddress), + type_string(desc->bmAttributes), + max); + + spin_unlock_irqrestore(&dev->lock, flags); +done: + VDBG(dev, "<--- %s()\n", __func__); + return retval; +} + + +/*-------------------------------------------------------------------------*/ + +/* retire a request */ +static void done(struct langwell_ep *ep, struct langwell_request *req, + int status) +{ + struct langwell_udc *dev = ep->dev; + unsigned stopped = ep->stopped; + struct langwell_dtd *curr_dtd, *next_dtd; + int i; + + VDBG(dev, "---> %s()\n", __func__); + + /* remove the req from ep->queue */ + list_del_init(&req->queue); + + if (req->req.status == -EINPROGRESS) + req->req.status = status; + else + status = req->req.status; + + /* free dTD for the request */ + next_dtd = req->head; + for (i = 0; i < req->dtd_count; i++) { + curr_dtd = next_dtd; + if (i != req->dtd_count - 1) + next_dtd = curr_dtd->next_dtd_virt; + dma_pool_free(dev->dtd_pool, curr_dtd, curr_dtd->dtd_dma); + } + + if (req->mapped) { + dma_unmap_single(&dev->pdev->dev, req->req.dma, req->req.length, + is_in(ep) ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); + req->req.dma = DMA_ADDR_INVALID; + req->mapped = 0; + } else + dma_sync_single_for_cpu(&dev->pdev->dev, req->req.dma, + req->req.length, + is_in(ep) ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + + if (status != -ESHUTDOWN) + DBG(dev, "complete %s, req %p, stat %d, len %u/%u\n", + ep->ep.name, &req->req, status, + req->req.actual, req->req.length); + + /* don't modify queue heads during completion callback */ + ep->stopped = 1; + + spin_unlock(&dev->lock); + /* complete routine from gadget driver */ + if (req->req.complete) + req->req.complete(&ep->ep, &req->req); + + spin_lock(&dev->lock); + ep->stopped = stopped; + + VDBG(dev, "<--- %s()\n", __func__); +} + + +static void langwell_ep_fifo_flush(struct usb_ep *_ep); + +/* delete all endpoint requests, called with spinlock held */ +static void nuke(struct langwell_ep *ep, int status) +{ + /* called with spinlock held */ + ep->stopped = 1; + + /* endpoint fifo flush */ + if (&ep->ep && ep->desc) + langwell_ep_fifo_flush(&ep->ep); + + while (!list_empty(&ep->queue)) { + struct langwell_request *req = NULL; + req = list_entry(ep->queue.next, struct langwell_request, + queue); + done(ep, req, status); + } +} + + +/*-------------------------------------------------------------------------*/ + +/* endpoint is no longer usable */ +static int langwell_ep_disable(struct usb_ep *_ep) +{ + struct langwell_ep *ep; + unsigned long flags; + struct langwell_udc *dev; + int ep_num; + u32 endptctrl; + + ep = container_of(_ep, struct langwell_ep, ep); + dev = ep->dev; + VDBG(dev, "---> %s()\n", __func__); + + if (!_ep || !ep->desc) + return -EINVAL; + + spin_lock_irqsave(&dev->lock, flags); + + /* disable endpoint control register */ + ep_num = ep->ep_num; + endptctrl = readl(&dev->op_regs->endptctrl[ep_num]); + if (is_in(ep)) + endptctrl &= ~EPCTRL_TXE; + else + endptctrl &= ~EPCTRL_RXE; + writel(endptctrl, &dev->op_regs->endptctrl[ep_num]); + + /* nuke all pending requests (does flush) */ + nuke(ep, -ESHUTDOWN); + + ep->desc = NULL; + ep->stopped = 1; + + spin_unlock_irqrestore(&dev->lock, flags); + + DBG(dev, "disabled %s\n", _ep->name); + VDBG(dev, "<--- %s()\n", __func__); + + return 0; +} + + +/* allocate a request object to use with this endpoint */ +static struct usb_request *langwell_alloc_request(struct usb_ep *_ep, + gfp_t gfp_flags) +{ + struct langwell_ep *ep; + struct langwell_udc *dev; + struct langwell_request *req = NULL; + + if (!_ep) + return NULL; + + ep = container_of(_ep, struct langwell_ep, ep); + dev = ep->dev; + VDBG(dev, "---> %s()\n", __func__); + + req = kzalloc(sizeof(*req), gfp_flags); + if (!req) + return NULL; + + req->req.dma = DMA_ADDR_INVALID; + INIT_LIST_HEAD(&req->queue); + + VDBG(dev, "alloc request for %s\n", _ep->name); + VDBG(dev, "<--- %s()\n", __func__); + return &req->req; +} + + +/* free a request object */ +static void langwell_free_request(struct usb_ep *_ep, + struct usb_request *_req) +{ + struct langwell_ep *ep; + struct langwell_udc *dev; + struct langwell_request *req = NULL; + + ep = container_of(_ep, struct langwell_ep, ep); + dev = ep->dev; + VDBG(dev, "---> %s()\n", __func__); + + if (!_ep || !_req) + return; + + req = container_of(_req, struct langwell_request, req); + WARN_ON(!list_empty(&req->queue)); + + if (_req) + kfree(req); + + VDBG(dev, "free request for %s\n", _ep->name); + VDBG(dev, "<--- %s()\n", __func__); +} + + +/*-------------------------------------------------------------------------*/ + +/* queue dTD and PRIME endpoint */ +static int queue_dtd(struct langwell_ep *ep, struct langwell_request *req) +{ + u32 bit_mask, usbcmd, endptstat, dtd_dma; + u8 dtd_status; + int i; + struct langwell_dqh *dqh; + struct langwell_udc *dev; + + dev = ep->dev; + VDBG(dev, "---> %s()\n", __func__); + + i = ep->ep_num * 2 + is_in(ep); + dqh = &dev->ep_dqh[i]; + + if (ep->ep_num) + VDBG(dev, "%s\n", ep->name); + else + /* ep0 */ + VDBG(dev, "%s-%s\n", ep->name, is_in(ep) ? "in" : "out"); + + VDBG(dev, "ep_dqh[%d] addr: 0x%08x\n", i, (u32)&(dev->ep_dqh[i])); + + bit_mask = is_in(ep) ? + (1 << (ep->ep_num + 16)) : (1 << (ep->ep_num)); + + VDBG(dev, "bit_mask = 0x%08x\n", bit_mask); + + /* check if the pipe is empty */ + if (!(list_empty(&ep->queue))) { + /* add dTD to the end of linked list */ + struct langwell_request *lastreq; + lastreq = list_entry(ep->queue.prev, + struct langwell_request, queue); + + lastreq->tail->dtd_next = + cpu_to_le32(req->head->dtd_dma & DTD_NEXT_MASK); + + /* read prime bit, if 1 goto out */ + if (readl(&dev->op_regs->endptprime) & bit_mask) + goto out; + + do { + /* set ATDTW bit in USBCMD */ + usbcmd = readl(&dev->op_regs->usbcmd); + writel(usbcmd | CMD_ATDTW, &dev->op_regs->usbcmd); + + /* read correct status bit */ + endptstat = readl(&dev->op_regs->endptstat) & bit_mask; + + } while (!(readl(&dev->op_regs->usbcmd) & CMD_ATDTW)); + + /* write ATDTW bit to 0 */ + usbcmd = readl(&dev->op_regs->usbcmd); + writel(usbcmd & ~CMD_ATDTW, &dev->op_regs->usbcmd); + + if (endptstat) + goto out; + } + + /* write dQH next pointer and terminate bit to 0 */ + dtd_dma = req->head->dtd_dma & DTD_NEXT_MASK; + dqh->dtd_next = cpu_to_le32(dtd_dma); + + /* clear active and halt bit */ + dtd_status = (u8) ~(DTD_STS_ACTIVE | DTD_STS_HALTED); + dqh->dtd_status &= dtd_status; + VDBG(dev, "dqh->dtd_status = 0x%x\n", dqh->dtd_status); + + /* write 1 to endptprime register to PRIME endpoint */ + bit_mask = is_in(ep) ? (1 << (ep->ep_num + 16)) : (1 << ep->ep_num); + VDBG(dev, "endprime bit_mask = 0x%08x\n", bit_mask); + writel(bit_mask, &dev->op_regs->endptprime); +out: + VDBG(dev, "<--- %s()\n", __func__); + return 0; +} + + +/* fill in the dTD structure to build a transfer descriptor */ +static struct langwell_dtd *build_dtd(struct langwell_request *req, + unsigned *length, dma_addr_t *dma, int *is_last) +{ + u32 buf_ptr; + struct langwell_dtd *dtd; + struct langwell_udc *dev; + int i; + + dev = req->ep->dev; + VDBG(dev, "---> %s()\n", __func__); + + /* the maximum transfer length, up to 16k bytes */ + *length = min(req->req.length - req->req.actual, + (unsigned)DTD_MAX_TRANSFER_LENGTH); + + /* create dTD dma_pool resource */ + dtd = dma_pool_alloc(dev->dtd_pool, GFP_KERNEL, dma); + if (dtd == NULL) + return dtd; + dtd->dtd_dma = *dma; + + /* initialize buffer page pointers */ + buf_ptr = (u32)(req->req.dma + req->req.actual); + for (i = 0; i < 5; i++) + dtd->dtd_buf[i] = cpu_to_le32(buf_ptr + i * PAGE_SIZE); + + req->req.actual += *length; + + /* fill in total bytes with transfer size */ + dtd->dtd_total = cpu_to_le16(*length); + VDBG(dev, "dtd->dtd_total = %d\n", dtd->dtd_total); + + /* set is_last flag if req->req.zero is set or not */ + if (req->req.zero) { + if (*length == 0 || (*length % req->ep->ep.maxpacket) != 0) + *is_last = 1; + else + *is_last = 0; + } else if (req->req.length == req->req.actual) { + *is_last = 1; + } else + *is_last = 0; + + if (*is_last == 0) + VDBG(dev, "multi-dtd request!\n"); + + /* set interrupt on complete bit for the last dTD */ + if (*is_last && !req->req.no_interrupt) + dtd->dtd_ioc = 1; + + /* set multiplier override 0 for non-ISO and non-TX endpoint */ + dtd->dtd_multo = 0; + + /* set the active bit of status field to 1 */ + dtd->dtd_status = DTD_STS_ACTIVE; + VDBG(dev, "dtd->dtd_status = 0x%02x\n", dtd->dtd_status); + + VDBG(dev, "length = %d, dma addr= 0x%08x\n", *length, (int)*dma); + VDBG(dev, "<--- %s()\n", __func__); + return dtd; +} + + +/* generate dTD linked list for a request */ +static int req_to_dtd(struct langwell_request *req) +{ + unsigned count; + int is_last, is_first = 1; + struct langwell_dtd *dtd, *last_dtd = NULL; + struct langwell_udc *dev; + dma_addr_t dma; + + dev = req->ep->dev; + VDBG(dev, "---> %s()\n", __func__); + do { + dtd = build_dtd(req, &count, &dma, &is_last); + if (dtd == NULL) + return -ENOMEM; + + if (is_first) { + is_first = 0; + req->head = dtd; + } else { + last_dtd->dtd_next = cpu_to_le32(dma); + last_dtd->next_dtd_virt = dtd; + } + last_dtd = dtd; + req->dtd_count++; + } while (!is_last); + + /* set terminate bit to 1 for the last dTD */ + dtd->dtd_next = DTD_TERM; + + req->tail = dtd; + + VDBG(dev, "<--- %s()\n", __func__); + return 0; +} + +/*-------------------------------------------------------------------------*/ + +/* queue (submits) an I/O requests to an endpoint */ +static int langwell_ep_queue(struct usb_ep *_ep, struct usb_request *_req, + gfp_t gfp_flags) +{ + struct langwell_request *req; + struct langwell_ep *ep; + struct langwell_udc *dev; + unsigned long flags; + int is_iso = 0, zlflag = 0; + + /* always require a cpu-view buffer */ + req = container_of(_req, struct langwell_request, req); + ep = container_of(_ep, struct langwell_ep, ep); + + if (!_req || !_req->complete || !_req->buf + || !list_empty(&req->queue)) { + return -EINVAL; + } + + if (unlikely(!_ep || !ep->desc)) + return -EINVAL; + + dev = ep->dev; + req->ep = ep; + VDBG(dev, "---> %s()\n", __func__); + + if (ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) { + if (req->req.length > ep->ep.maxpacket) + return -EMSGSIZE; + is_iso = 1; + } + + if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) + return -ESHUTDOWN; + + /* set up dma mapping in case the caller didn't */ + if (_req->dma == DMA_ADDR_INVALID) { + /* WORKAROUND: WARN_ON(size == 0) */ + if (_req->length == 0) { + VDBG(dev, "req->length: 0->1\n"); + zlflag = 1; + _req->length++; + } + + _req->dma = dma_map_single(&dev->pdev->dev, + _req->buf, _req->length, + is_in(ep) ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + if (zlflag && (_req->length == 1)) { + VDBG(dev, "req->length: 1->0\n"); + zlflag = 0; + _req->length = 0; + } + + req->mapped = 1; + VDBG(dev, "req->mapped = 1\n"); + } else { + dma_sync_single_for_device(&dev->pdev->dev, + _req->dma, _req->length, + is_in(ep) ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + req->mapped = 0; + VDBG(dev, "req->mapped = 0\n"); + } + + DBG(dev, "%s queue req %p, len %u, buf %p, dma 0x%08x\n", + _ep->name, + _req, _req->length, _req->buf, _req->dma); + + _req->status = -EINPROGRESS; + _req->actual = 0; + req->dtd_count = 0; + + spin_lock_irqsave(&dev->lock, flags); + + /* build and put dTDs to endpoint queue */ + if (!req_to_dtd(req)) { + queue_dtd(ep, req); + } else { + spin_unlock_irqrestore(&dev->lock, flags); + return -ENOMEM; + } + + /* update ep0 state */ + if (ep->ep_num == 0) + dev->ep0_state = DATA_STATE_XMIT; + + if (likely(req != NULL)) { + list_add_tail(&req->queue, &ep->queue); + VDBG(dev, "list_add_tail() \n"); + } + + spin_unlock_irqrestore(&dev->lock, flags); + + VDBG(dev, "<--- %s()\n", __func__); + return 0; +} + + +/* dequeue (cancels, unlinks) an I/O request from an endpoint */ +static int langwell_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) +{ + struct langwell_ep *ep; + struct langwell_udc *dev; + struct langwell_request *req; + unsigned long flags; + int stopped, ep_num, retval = 0; + u32 endptctrl; + + ep = container_of(_ep, struct langwell_ep, ep); + dev = ep->dev; + VDBG(dev, "---> %s()\n", __func__); + + if (!_ep || !ep->desc || !_req) + return -EINVAL; + + if (!dev->driver) + return -ESHUTDOWN; + + spin_lock_irqsave(&dev->lock, flags); + stopped = ep->stopped; + + /* quiesce dma while we patch the queue */ + ep->stopped = 1; + ep_num = ep->ep_num; + + /* disable endpoint control register */ + endptctrl = readl(&dev->op_regs->endptctrl[ep_num]); + if (is_in(ep)) + endptctrl &= ~EPCTRL_TXE; + else + endptctrl &= ~EPCTRL_RXE; + writel(endptctrl, &dev->op_regs->endptctrl[ep_num]); + + /* make sure it's still queued on this endpoint */ + list_for_each_entry(req, &ep->queue, queue) { + if (&req->req == _req) + break; + } + + if (&req->req != _req) { + retval = -EINVAL; + goto done; + } + + /* queue head may be partially complete. */ + if (ep->queue.next == &req->queue) { + DBG(dev, "unlink (%s) dma\n", _ep->name); + _req->status = -ECONNRESET; + langwell_ep_fifo_flush(&ep->ep); + + /* not the last request in endpoint queue */ + if (likely(ep->queue.next == &req->queue)) { + struct langwell_dqh *dqh; + struct langwell_request *next_req; + + dqh = ep->dqh; + next_req = list_entry(req->queue.next, + struct langwell_request, queue); + + /* point the dQH to the first dTD of next request */ + writel((u32) next_req->head, &dqh->dqh_current); + } + } else { + struct langwell_request *prev_req; + + prev_req = list_entry(req->queue.prev, + struct langwell_request, queue); + writel(readl(&req->tail->dtd_next), + &prev_req->tail->dtd_next); + } + + done(ep, req, -ECONNRESET); + +done: + /* enable endpoint again */ + endptctrl = readl(&dev->op_regs->endptctrl[ep_num]); + if (is_in(ep)) + endptctrl |= EPCTRL_TXE; + else + endptctrl |= EPCTRL_RXE; + writel(endptctrl, &dev->op_regs->endptctrl[ep_num]); + + ep->stopped = stopped; + spin_unlock_irqrestore(&dev->lock, flags); + + VDBG(dev, "<--- %s()\n", __func__); + return retval; +} + + +/*-------------------------------------------------------------------------*/ + +/* endpoint set/clear halt */ +static void ep_set_halt(struct langwell_ep *ep, int value) +{ + u32 endptctrl = 0; + int ep_num; + struct langwell_udc *dev = ep->dev; + VDBG(dev, "---> %s()\n", __func__); + + ep_num = ep->ep_num; + endptctrl = readl(&dev->op_regs->endptctrl[ep_num]); + + /* value: 1 - set halt, 0 - clear halt */ + if (value) { + /* set the stall bit */ + if (is_in(ep)) + endptctrl |= EPCTRL_TXS; + else + endptctrl |= EPCTRL_RXS; + } else { + /* clear the stall bit and reset data toggle */ + if (is_in(ep)) { + endptctrl &= ~EPCTRL_TXS; + endptctrl |= EPCTRL_TXR; + } else { + endptctrl &= ~EPCTRL_RXS; + endptctrl |= EPCTRL_RXR; + } + } + + writel(endptctrl, &dev->op_regs->endptctrl[ep_num]); + + VDBG(dev, "<--- %s()\n", __func__); +} + + +/* set the endpoint halt feature */ +static int langwell_ep_set_halt(struct usb_ep *_ep, int value) +{ + struct langwell_ep *ep; + struct langwell_udc *dev; + unsigned long flags; + int retval = 0; + + ep = container_of(_ep, struct langwell_ep, ep); + dev = ep->dev; + + VDBG(dev, "---> %s()\n", __func__); + + if (!_ep || !ep->desc) + return -EINVAL; + + if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) + return -ESHUTDOWN; + + if (ep->desc && (ep->desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) + == USB_ENDPOINT_XFER_ISOC) + return -EOPNOTSUPP; + + spin_lock_irqsave(&dev->lock, flags); + + /* + * attempt to halt IN ep will fail if any transfer requests + * are still queue + */ + if (!list_empty(&ep->queue) && is_in(ep) && value) { + /* IN endpoint FIFO holds bytes */ + DBG(dev, "%s FIFO holds bytes\n", _ep->name); + retval = -EAGAIN; + goto done; + } + + /* endpoint set/clear halt */ + if (ep->ep_num) { + ep_set_halt(ep, value); + } else { /* endpoint 0 */ + dev->ep0_state = WAIT_FOR_SETUP; + dev->ep0_dir = USB_DIR_OUT; + } +done: + spin_unlock_irqrestore(&dev->lock, flags); + DBG(dev, "%s %s halt\n", _ep->name, value ? "set" : "clear"); + VDBG(dev, "<--- %s()\n", __func__); + return retval; +} + + +/* set the halt feature and ignores clear requests */ +static int langwell_ep_set_wedge(struct usb_ep *_ep) +{ + struct langwell_ep *ep; + struct langwell_udc *dev; + + ep = container_of(_ep, struct langwell_ep, ep); + dev = ep->dev; + + VDBG(dev, "---> %s()\n", __func__); + + if (!_ep || !ep->desc) + return -EINVAL; + + VDBG(dev, "<--- %s()\n", __func__); + return usb_ep_set_halt(_ep); +} + + +/* flush contents of a fifo */ +static void langwell_ep_fifo_flush(struct usb_ep *_ep) +{ + struct langwell_ep *ep; + struct langwell_udc *dev; + u32 flush_bit; + unsigned long timeout; + + ep = container_of(_ep, struct langwell_ep, ep); + dev = ep->dev; + + VDBG(dev, "---> %s()\n", __func__); + + if (!_ep || !ep->desc) { + VDBG(dev, "ep or ep->desc is NULL\n"); + VDBG(dev, "<--- %s()\n", __func__); + return; + } + + VDBG(dev, "%s-%s fifo flush\n", _ep->name, is_in(ep) ? "in" : "out"); + + /* flush endpoint buffer */ + if (ep->ep_num == 0) + flush_bit = (1 << 16) | 1; + else if (is_in(ep)) + flush_bit = 1 << (ep->ep_num + 16); /* TX */ + else + flush_bit = 1 << ep->ep_num; /* RX */ + + /* wait until flush complete */ + timeout = jiffies + FLUSH_TIMEOUT; + do { + writel(flush_bit, &dev->op_regs->endptflush); + while (readl(&dev->op_regs->endptflush)) { + if (time_after(jiffies, timeout)) { + ERROR(dev, "ep flush timeout\n"); + goto done; + } + cpu_relax(); + } + } while (readl(&dev->op_regs->endptstat) & flush_bit); +done: + VDBG(dev, "<--- %s()\n", __func__); +} + + +/* endpoints operations structure */ +static const struct usb_ep_ops langwell_ep_ops = { + + /* configure endpoint, making it usable */ + .enable = langwell_ep_enable, + + /* endpoint is no longer usable */ + .disable = langwell_ep_disable, + + /* allocate a request object to use with this endpoint */ + .alloc_request = langwell_alloc_request, + + /* free a request object */ + .free_request = langwell_free_request, + + /* queue (submits) an I/O requests to an endpoint */ + .queue = langwell_ep_queue, + + /* dequeue (cancels, unlinks) an I/O request from an endpoint */ + .dequeue = langwell_ep_dequeue, + + /* set the endpoint halt feature */ + .set_halt = langwell_ep_set_halt, + + /* set the halt feature and ignores clear requests */ + .set_wedge = langwell_ep_set_wedge, + + /* flush contents of a fifo */ + .fifo_flush = langwell_ep_fifo_flush, +}; + + +/*-------------------------------------------------------------------------*/ + +/* device controller usb_gadget_ops structure */ + +/* returns the current frame number */ +static int langwell_get_frame(struct usb_gadget *_gadget) +{ + struct langwell_udc *dev; + u16 retval; + + if (!_gadget) + return -ENODEV; + + dev = container_of(_gadget, struct langwell_udc, gadget); + VDBG(dev, "---> %s()\n", __func__); + + retval = readl(&dev->op_regs->frindex) & FRINDEX_MASK; + + VDBG(dev, "<--- %s()\n", __func__); + return retval; +} + + +/* tries to wake up the host connected to this gadget */ +static int langwell_wakeup(struct usb_gadget *_gadget) +{ + struct langwell_udc *dev; + u32 portsc1, devlc; + unsigned long flags; + + if (!_gadget) + return 0; + + dev = container_of(_gadget, struct langwell_udc, gadget); + VDBG(dev, "---> %s()\n", __func__); + + /* Remote Wakeup feature not enabled by host */ + if (!dev->remote_wakeup) + return -ENOTSUPP; + + spin_lock_irqsave(&dev->lock, flags); + + portsc1 = readl(&dev->op_regs->portsc1); + if (!(portsc1 & PORTS_SUSP)) { + spin_unlock_irqrestore(&dev->lock, flags); + return 0; + } + + /* LPM L1 to L0, remote wakeup */ + if (dev->lpm && dev->lpm_state == LPM_L1) { + portsc1 |= PORTS_SLP; + writel(portsc1, &dev->op_regs->portsc1); + } + + /* force port resume */ + if (dev->usb_state == USB_STATE_SUSPENDED) { + portsc1 |= PORTS_FPR; + writel(portsc1, &dev->op_regs->portsc1); + } + + /* exit PHY low power suspend */ + devlc = readl(&dev->op_regs->devlc); + VDBG(dev, "devlc = 0x%08x\n", devlc); + devlc &= ~LPM_PHCD; + writel(devlc, &dev->op_regs->devlc); + + spin_unlock_irqrestore(&dev->lock, flags); + + VDBG(dev, "<--- %s()\n", __func__); + return 0; +} + + +/* notify controller that VBUS is powered or not */ +static int langwell_vbus_session(struct usb_gadget *_gadget, int is_active) +{ + struct langwell_udc *dev; + unsigned long flags; + u32 usbcmd; + + if (!_gadget) + return -ENODEV; + + dev = container_of(_gadget, struct langwell_udc, gadget); + VDBG(dev, "---> %s()\n", __func__); + + spin_lock_irqsave(&dev->lock, flags); + VDBG(dev, "VBUS status: %s\n", is_active ? "on" : "off"); + + dev->vbus_active = (is_active != 0); + if (dev->driver && dev->softconnected && dev->vbus_active) { + usbcmd = readl(&dev->op_regs->usbcmd); + usbcmd |= CMD_RUNSTOP; + writel(usbcmd, &dev->op_regs->usbcmd); + } else { + usbcmd = readl(&dev->op_regs->usbcmd); + usbcmd &= ~CMD_RUNSTOP; + writel(usbcmd, &dev->op_regs->usbcmd); + } + + spin_unlock_irqrestore(&dev->lock, flags); + + VDBG(dev, "<--- %s()\n", __func__); + return 0; +} + + +/* constrain controller's VBUS power usage */ +static int langwell_vbus_draw(struct usb_gadget *_gadget, unsigned mA) +{ + struct langwell_udc *dev; + + if (!_gadget) + return -ENODEV; + + dev = container_of(_gadget, struct langwell_udc, gadget); + VDBG(dev, "---> %s()\n", __func__); + + if (dev->transceiver) { + VDBG(dev, "otg_set_power\n"); + VDBG(dev, "<--- %s()\n", __func__); + return otg_set_power(dev->transceiver, mA); + } + + VDBG(dev, "<--- %s()\n", __func__); + return -ENOTSUPP; +} + + +/* D+ pullup, software-controlled connect/disconnect to USB host */ +static int langwell_pullup(struct usb_gadget *_gadget, int is_on) +{ + struct langwell_udc *dev; + u32 usbcmd; + unsigned long flags; + + if (!_gadget) + return -ENODEV; + + dev = container_of(_gadget, struct langwell_udc, gadget); + + VDBG(dev, "---> %s()\n", __func__); + + spin_lock_irqsave(&dev->lock, flags); + dev->softconnected = (is_on != 0); + + if (dev->driver && dev->softconnected && dev->vbus_active) { + usbcmd = readl(&dev->op_regs->usbcmd); + usbcmd |= CMD_RUNSTOP; + writel(usbcmd, &dev->op_regs->usbcmd); + } else { + usbcmd = readl(&dev->op_regs->usbcmd); + usbcmd &= ~CMD_RUNSTOP; + writel(usbcmd, &dev->op_regs->usbcmd); + } + spin_unlock_irqrestore(&dev->lock, flags); + + VDBG(dev, "<--- %s()\n", __func__); + return 0; +} + + +/* device controller usb_gadget_ops structure */ +static const struct usb_gadget_ops langwell_ops = { + + /* returns the current frame number */ + .get_frame = langwell_get_frame, + + /* tries to wake up the host connected to this gadget */ + .wakeup = langwell_wakeup, + + /* set the device selfpowered feature, always selfpowered */ + /* .set_selfpowered = langwell_set_selfpowered, */ + + /* notify controller that VBUS is powered or not */ + .vbus_session = langwell_vbus_session, + + /* constrain controller's VBUS power usage */ + .vbus_draw = langwell_vbus_draw, + + /* D+ pullup, software-controlled connect/disconnect to USB host */ + .pullup = langwell_pullup, +}; + + +/*-------------------------------------------------------------------------*/ + +/* device controller operations */ + +/* reset device controller */ +static int langwell_udc_reset(struct langwell_udc *dev) +{ + u32 usbcmd, usbmode, devlc, endpointlistaddr; + unsigned long timeout; + + if (!dev) + return -EINVAL; + + DBG(dev, "---> %s()\n", __func__); + + /* set controller to stop state */ + usbcmd = readl(&dev->op_regs->usbcmd); + usbcmd &= ~CMD_RUNSTOP; + writel(usbcmd, &dev->op_regs->usbcmd); + + /* reset device controller */ + usbcmd = readl(&dev->op_regs->usbcmd); + usbcmd |= CMD_RST; + writel(usbcmd, &dev->op_regs->usbcmd); + + /* wait for reset to complete */ + timeout = jiffies + RESET_TIMEOUT; + while (readl(&dev->op_regs->usbcmd) & CMD_RST) { + if (time_after(jiffies, timeout)) { + ERROR(dev, "device reset timeout\n"); + return -ETIMEDOUT; + } + cpu_relax(); + } + + /* set controller to device mode */ + usbmode = readl(&dev->op_regs->usbmode); + usbmode |= MODE_DEVICE; + + /* turn setup lockout off, require setup tripwire in usbcmd */ + usbmode |= MODE_SLOM; + + writel(usbmode, &dev->op_regs->usbmode); + usbmode = readl(&dev->op_regs->usbmode); + VDBG(dev, "usbmode=0x%08x\n", usbmode); + + /* Write-Clear setup status */ + writel(0, &dev->op_regs->usbsts); + + /* if support USB LPM, ACK all LPM token */ + if (dev->lpm) { + devlc = readl(&dev->op_regs->devlc); + devlc &= ~LPM_STL; /* don't STALL LPM token */ + devlc &= ~LPM_NYT_ACK; /* ACK LPM token */ + writel(devlc, &dev->op_regs->devlc); + } + + /* fill endpointlistaddr register */ + endpointlistaddr = dev->ep_dqh_dma; + endpointlistaddr &= ENDPOINTLISTADDR_MASK; + writel(endpointlistaddr, &dev->op_regs->endpointlistaddr); + + VDBG(dev, "dQH base (vir: %p, phy: 0x%08x), endpointlistaddr=0x%08x\n", + dev->ep_dqh, endpointlistaddr, + readl(&dev->op_regs->endpointlistaddr)); + DBG(dev, "<--- %s()\n", __func__); + return 0; +} + + +/* reinitialize device controller endpoints */ +static int eps_reinit(struct langwell_udc *dev) +{ + struct langwell_ep *ep; + char name[14]; + int i; + + VDBG(dev, "---> %s()\n", __func__); + + /* initialize ep0 */ + ep = &dev->ep[0]; + ep->dev = dev; + strncpy(ep->name, "ep0", sizeof(ep->name)); + ep->ep.name = ep->name; + ep->ep.ops = &langwell_ep_ops; + ep->stopped = 0; + ep->ep.maxpacket = EP0_MAX_PKT_SIZE; + ep->ep_num = 0; + ep->desc = &langwell_ep0_desc; + INIT_LIST_HEAD(&ep->queue); + + ep->ep_type = USB_ENDPOINT_XFER_CONTROL; + + /* initialize other endpoints */ + for (i = 2; i < dev->ep_max; i++) { + ep = &dev->ep[i]; + if (i % 2) + snprintf(name, sizeof(name), "ep%din", i / 2); + else + snprintf(name, sizeof(name), "ep%dout", i / 2); + ep->dev = dev; + strncpy(ep->name, name, sizeof(ep->name)); + ep->ep.name = ep->name; + + ep->ep.ops = &langwell_ep_ops; + ep->stopped = 0; + ep->ep.maxpacket = (unsigned short) ~0; + ep->ep_num = i / 2; + + INIT_LIST_HEAD(&ep->queue); + list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list); + + ep->dqh = &dev->ep_dqh[i]; + } + + VDBG(dev, "<--- %s()\n", __func__); + return 0; +} + + +/* enable interrupt and set controller to run state */ +static void langwell_udc_start(struct langwell_udc *dev) +{ + u32 usbintr, usbcmd; + DBG(dev, "---> %s()\n", __func__); + + /* enable interrupts */ + usbintr = INTR_ULPIE /* ULPI */ + | INTR_SLE /* suspend */ + /* | INTR_SRE SOF received */ + | INTR_URE /* USB reset */ + | INTR_AAE /* async advance */ + | INTR_SEE /* system error */ + | INTR_FRE /* frame list rollover */ + | INTR_PCE /* port change detect */ + | INTR_UEE /* USB error interrupt */ + | INTR_UE; /* USB interrupt */ + writel(usbintr, &dev->op_regs->usbintr); + + /* clear stopped bit */ + dev->stopped = 0; + + /* set controller to run */ + usbcmd = readl(&dev->op_regs->usbcmd); + usbcmd |= CMD_RUNSTOP; + writel(usbcmd, &dev->op_regs->usbcmd); + + DBG(dev, "<--- %s()\n", __func__); + return; +} + + +/* disable interrupt and set controller to stop state */ +static void langwell_udc_stop(struct langwell_udc *dev) +{ + u32 usbcmd; + + DBG(dev, "---> %s()\n", __func__); + + /* disable all interrupts */ + writel(0, &dev->op_regs->usbintr); + + /* set stopped bit */ + dev->stopped = 1; + + /* set controller to stop state */ + usbcmd = readl(&dev->op_regs->usbcmd); + usbcmd &= ~CMD_RUNSTOP; + writel(usbcmd, &dev->op_regs->usbcmd); + + DBG(dev, "<--- %s()\n", __func__); + return; +} + + +/* stop all USB activities */ +static void stop_activity(struct langwell_udc *dev, + struct usb_gadget_driver *driver) +{ + struct langwell_ep *ep; + DBG(dev, "---> %s()\n", __func__); + + nuke(&dev->ep[0], -ESHUTDOWN); + + list_for_each_entry(ep, &dev->gadget.ep_list, ep.ep_list) { + nuke(ep, -ESHUTDOWN); + } + + /* report disconnect; the driver is already quiesced */ + if (driver) { + spin_unlock(&dev->lock); + driver->disconnect(&dev->gadget); + spin_lock(&dev->lock); + } + + DBG(dev, "<--- %s()\n", __func__); +} + + +/*-------------------------------------------------------------------------*/ + +/* device "function" sysfs attribute file */ +static ssize_t show_function(struct device *_dev, + struct device_attribute *attr, char *buf) +{ + struct langwell_udc *dev = the_controller; + + if (!dev->driver || !dev->driver->function + || strlen(dev->driver->function) > PAGE_SIZE) + return 0; + + return scnprintf(buf, PAGE_SIZE, "%s\n", dev->driver->function); +} +static DEVICE_ATTR(function, S_IRUGO, show_function, NULL); + + +/* device "langwell_udc" sysfs attribute file */ +static ssize_t show_langwell_udc(struct device *_dev, + struct device_attribute *attr, char *buf) +{ + struct langwell_udc *dev = the_controller; + struct langwell_request *req; + struct langwell_ep *ep = NULL; + char *next; + unsigned size; + unsigned t; + unsigned i; + unsigned long flags; + u32 tmp_reg; + + next = buf; + size = PAGE_SIZE; + spin_lock_irqsave(&dev->lock, flags); + + /* driver basic information */ + t = scnprintf(next, size, + DRIVER_DESC "\n" + "%s version: %s\n" + "Gadget driver: %s\n\n", + driver_name, DRIVER_VERSION, + dev->driver ? dev->driver->driver.name : "(none)"); + size -= t; + next += t; + + /* device registers */ + tmp_reg = readl(&dev->op_regs->usbcmd); + t = scnprintf(next, size, + "USBCMD reg:\n" + "SetupTW: %d\n" + "Run/Stop: %s\n\n", + (tmp_reg & CMD_SUTW) ? 1 : 0, + (tmp_reg & CMD_RUNSTOP) ? "Run" : "Stop"); + size -= t; + next += t; + + tmp_reg = readl(&dev->op_regs->usbsts); + t = scnprintf(next, size, + "USB Status Reg:\n" + "Device Suspend: %d\n" + "Reset Received: %d\n" + "System Error: %s\n" + "USB Error Interrupt: %s\n\n", + (tmp_reg & STS_SLI) ? 1 : 0, + (tmp_reg & STS_URI) ? 1 : 0, + (tmp_reg & STS_SEI) ? "Error" : "No error", + (tmp_reg & STS_UEI) ? "Error detected" : "No error"); + size -= t; + next += t; + + tmp_reg = readl(&dev->op_regs->usbintr); + t = scnprintf(next, size, + "USB Intrrupt Enable Reg:\n" + "Sleep Enable: %d\n" + "SOF Received Enable: %d\n" + "Reset Enable: %d\n" + "System Error Enable: %d\n" + "Port Change Dectected Enable: %d\n" + "USB Error Intr Enable: %d\n" + "USB Intr Enable: %d\n\n", + (tmp_reg & INTR_SLE) ? 1 : 0, + (tmp_reg & INTR_SRE) ? 1 : 0, + (tmp_reg & INTR_URE) ? 1 : 0, + (tmp_reg & INTR_SEE) ? 1 : 0, + (tmp_reg & INTR_PCE) ? 1 : 0, + (tmp_reg & INTR_UEE) ? 1 : 0, + (tmp_reg & INTR_UE) ? 1 : 0); + size -= t; + next += t; + + tmp_reg = readl(&dev->op_regs->frindex); + t = scnprintf(next, size, + "USB Frame Index Reg:\n" + "Frame Number is 0x%08x\n\n", + (tmp_reg & FRINDEX_MASK)); + size -= t; + next += t; + + tmp_reg = readl(&dev->op_regs->deviceaddr); + t = scnprintf(next, size, + "USB Device Address Reg:\n" + "Device Addr is 0x%x\n\n", + USBADR(tmp_reg)); + size -= t; + next += t; + + tmp_reg = readl(&dev->op_regs->endpointlistaddr); + t = scnprintf(next, size, + "USB Endpoint List Address Reg:\n" + "Endpoint List Pointer is 0x%x\n\n", + EPBASE(tmp_reg)); + size -= t; + next += t; + + tmp_reg = readl(&dev->op_regs->portsc1); + t = scnprintf(next, size, + "USB Port Status & Control Reg:\n" + "Port Reset: %s\n" + "Port Suspend Mode: %s\n" + "Over-current Change: %s\n" + "Port Enable/Disable Change: %s\n" + "Port Enabled/Disabled: %s\n" + "Current Connect Status: %s\n\n", + (tmp_reg & PORTS_PR) ? "Reset" : "Not Reset", + (tmp_reg & PORTS_SUSP) ? "Suspend " : "Not Suspend", + (tmp_reg & PORTS_OCC) ? "Detected" : "No", + (tmp_reg & PORTS_PEC) ? "Changed" : "Not Changed", + (tmp_reg & PORTS_PE) ? "Enable" : "Not Correct", + (tmp_reg & PORTS_CCS) ? "Attached" : "Not Attached"); + size -= t; + next += t; + + tmp_reg = readl(&dev->op_regs->devlc); + t = scnprintf(next, size, + "Device LPM Control Reg:\n" + "Parallel Transceiver : %d\n" + "Serial Transceiver : %d\n" + "Port Speed: %s\n" + "Port Force Full Speed Connenct: %s\n" + "PHY Low Power Suspend Clock Disable: %s\n" + "BmAttributes: %d\n\n", + LPM_PTS(tmp_reg), + (tmp_reg & LPM_STS) ? 1 : 0, + ({ + char *s; + switch (LPM_PSPD(tmp_reg)) { + case LPM_SPEED_FULL: + s = "Full Speed"; break; + case LPM_SPEED_LOW: + s = "Low Speed"; break; + case LPM_SPEED_HIGH: + s = "High Speed"; break; + default: + s = "Unknown Speed"; break; + } + s; + }), + (tmp_reg & LPM_PFSC) ? "Force Full Speed" : "Not Force", + (tmp_reg & LPM_PHCD) ? "Disabled" : "Enabled", + LPM_BA(tmp_reg)); + size -= t; + next += t; + + tmp_reg = readl(&dev->op_regs->usbmode); + t = scnprintf(next, size, + "USB Mode Reg:\n" + "Controller Mode is : %s\n\n", ({ + char *s; + switch (MODE_CM(tmp_reg)) { + case MODE_IDLE: + s = "Idle"; break; + case MODE_DEVICE: + s = "Device Controller"; break; + case MODE_HOST: + s = "Host Controller"; break; + default: + s = "None"; break; + } + s; + })); + size -= t; + next += t; + + tmp_reg = readl(&dev->op_regs->endptsetupstat); + t = scnprintf(next, size, + "Endpoint Setup Status Reg:\n" + "SETUP on ep 0x%04x\n\n", + tmp_reg & SETUPSTAT_MASK); + size -= t; + next += t; + + for (i = 0; i < dev->ep_max / 2; i++) { + tmp_reg = readl(&dev->op_regs->endptctrl[i]); + t = scnprintf(next, size, "EP Ctrl Reg [%d]: 0x%08x\n", + i, tmp_reg); + size -= t; + next += t; + } + tmp_reg = readl(&dev->op_regs->endptprime); + t = scnprintf(next, size, "EP Prime Reg: 0x%08x\n\n", tmp_reg); + size -= t; + next += t; + + /* langwell_udc, langwell_ep, langwell_request structure information */ + ep = &dev->ep[0]; + t = scnprintf(next, size, "%s MaxPacketSize: 0x%x, ep_num: %d\n", + ep->ep.name, ep->ep.maxpacket, ep->ep_num); + size -= t; + next += t; + + if (list_empty(&ep->queue)) { + t = scnprintf(next, size, "its req queue is empty\n\n"); + size -= t; + next += t; + } else { + list_for_each_entry(req, &ep->queue, queue) { + t = scnprintf(next, size, + "req %p actual 0x%x length 0x%x buf %p\n", + &req->req, req->req.actual, + req->req.length, req->req.buf); + size -= t; + next += t; + } + } + /* other gadget->eplist ep */ + list_for_each_entry(ep, &dev->gadget.ep_list, ep.ep_list) { + if (ep->desc) { + t = scnprintf(next, size, + "\n%s MaxPacketSize: 0x%x, " + "ep_num: %d\n", + ep->ep.name, ep->ep.maxpacket, + ep->ep_num); + size -= t; + next += t; + + if (list_empty(&ep->queue)) { + t = scnprintf(next, size, + "its req queue is empty\n\n"); + size -= t; + next += t; + } else { + list_for_each_entry(req, &ep->queue, queue) { + t = scnprintf(next, size, + "req %p actual 0x%x length " + "0x%x buf %p\n", + &req->req, req->req.actual, + req->req.length, req->req.buf); + size -= t; + next += t; + } + } + } + } + + spin_unlock_irqrestore(&dev->lock, flags); + return PAGE_SIZE - size; +} +static DEVICE_ATTR(langwell_udc, S_IRUGO, show_langwell_udc, NULL); + + +/*-------------------------------------------------------------------------*/ + +/* + * when a driver is successfully registered, it will receive + * control requests including set_configuration(), which enables + * non-control requests. then usb traffic follows until a + * disconnect is reported. then a host may connect again, or + * the driver might get unbound. + */ + +int usb_gadget_register_driver(struct usb_gadget_driver *driver) +{ + struct langwell_udc *dev = the_controller; + unsigned long flags; + int retval; + + if (!dev) + return -ENODEV; + + DBG(dev, "---> %s()\n", __func__); + + if (dev->driver) + return -EBUSY; + + spin_lock_irqsave(&dev->lock, flags); + + /* hook up the driver ... */ + driver->driver.bus = NULL; + dev->driver = driver; + dev->gadget.dev.driver = &driver->driver; + + spin_unlock_irqrestore(&dev->lock, flags); + + retval = driver->bind(&dev->gadget); + if (retval) { + DBG(dev, "bind to driver %s --> %d\n", + driver->driver.name, retval); + dev->driver = NULL; + dev->gadget.dev.driver = NULL; + return retval; + } + + retval = device_create_file(&dev->pdev->dev, &dev_attr_function); + if (retval) + goto err_unbind; + + dev->usb_state = USB_STATE_ATTACHED; + dev->ep0_state = WAIT_FOR_SETUP; + dev->ep0_dir = USB_DIR_OUT; + + /* enable interrupt and set controller to run state */ + if (dev->got_irq) + langwell_udc_start(dev); + + VDBG(dev, "After langwell_udc_start(), print all registers:\n"); +#ifdef VERBOSE + print_all_registers(dev); +#endif + + INFO(dev, "register driver: %s\n", driver->driver.name); + VDBG(dev, "<--- %s()\n", __func__); + return 0; + +err_unbind: + driver->unbind(&dev->gadget); + dev->gadget.dev.driver = NULL; + dev->driver = NULL; + + DBG(dev, "<--- %s()\n", __func__); + return retval; +} +EXPORT_SYMBOL(usb_gadget_register_driver); + + +/* unregister gadget driver */ +int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +{ + struct langwell_udc *dev = the_controller; + unsigned long flags; + + if (!dev) + return -ENODEV; + + DBG(dev, "---> %s()\n", __func__); + + if (unlikely(!driver || !driver->bind || !driver->unbind)) + return -EINVAL; + + /* unbind OTG transceiver */ + if (dev->transceiver) + (void)otg_set_peripheral(dev->transceiver, 0); + + /* disable interrupt and set controller to stop state */ + langwell_udc_stop(dev); + + dev->usb_state = USB_STATE_ATTACHED; + dev->ep0_state = WAIT_FOR_SETUP; + dev->ep0_dir = USB_DIR_OUT; + + spin_lock_irqsave(&dev->lock, flags); + + /* stop all usb activities */ + dev->gadget.speed = USB_SPEED_UNKNOWN; + stop_activity(dev, driver); + spin_unlock_irqrestore(&dev->lock, flags); + + /* unbind gadget driver */ + driver->unbind(&dev->gadget); + dev->gadget.dev.driver = NULL; + dev->driver = NULL; + + device_remove_file(&dev->pdev->dev, &dev_attr_function); + + INFO(dev, "unregistered driver '%s'\n", driver->driver.name); + DBG(dev, "<--- %s()\n", __func__); + return 0; +} +EXPORT_SYMBOL(usb_gadget_unregister_driver); + + +/*-------------------------------------------------------------------------*/ + +/* + * setup tripwire is used as a semaphore to ensure that the setup data + * payload is extracted from a dQH without being corrupted + */ +static void setup_tripwire(struct langwell_udc *dev) +{ + u32 usbcmd, + endptsetupstat; + unsigned long timeout; + struct langwell_dqh *dqh; + + VDBG(dev, "---> %s()\n", __func__); + + /* ep0 OUT dQH */ + dqh = &dev->ep_dqh[EP_DIR_OUT]; + + /* Write-Clear endptsetupstat */ + endptsetupstat = readl(&dev->op_regs->endptsetupstat); + writel(endptsetupstat, &dev->op_regs->endptsetupstat); + + /* wait until endptsetupstat is cleared */ + timeout = jiffies + SETUPSTAT_TIMEOUT; + while (readl(&dev->op_regs->endptsetupstat)) { + if (time_after(jiffies, timeout)) { + ERROR(dev, "setup_tripwire timeout\n"); + break; + } + cpu_relax(); + } + + /* while a hazard exists when setup packet arrives */ + do { + /* set setup tripwire bit */ + usbcmd = readl(&dev->op_regs->usbcmd); + writel(usbcmd | CMD_SUTW, &dev->op_regs->usbcmd); + + /* copy the setup packet to local buffer */ + memcpy(&dev->local_setup_buff, &dqh->dqh_setup, 8); + } while (!(readl(&dev->op_regs->usbcmd) & CMD_SUTW)); + + /* Write-Clear setup tripwire bit */ + usbcmd = readl(&dev->op_regs->usbcmd); + writel(usbcmd & ~CMD_SUTW, &dev->op_regs->usbcmd); + + VDBG(dev, "<--- %s()\n", __func__); +} + + +/* protocol ep0 stall, will automatically be cleared on new transaction */ +static void ep0_stall(struct langwell_udc *dev) +{ + u32 endptctrl; + + VDBG(dev, "---> %s()\n", __func__); + + /* set TX and RX to stall */ + endptctrl = readl(&dev->op_regs->endptctrl[0]); + endptctrl |= EPCTRL_TXS | EPCTRL_RXS; + writel(endptctrl, &dev->op_regs->endptctrl[0]); + + /* update ep0 state */ + dev->ep0_state = WAIT_FOR_SETUP; + dev->ep0_dir = USB_DIR_OUT; + + VDBG(dev, "<--- %s()\n", __func__); +} + + +/* PRIME a status phase for ep0 */ +static int prime_status_phase(struct langwell_udc *dev, int dir) +{ + struct langwell_request *req; + struct langwell_ep *ep; + int status = 0; + + VDBG(dev, "---> %s()\n", __func__); + + if (dir == EP_DIR_IN) + dev->ep0_dir = USB_DIR_IN; + else + dev->ep0_dir = USB_DIR_OUT; + + ep = &dev->ep[0]; + dev->ep0_state = WAIT_FOR_OUT_STATUS; + + req = dev->status_req; + + req->ep = ep; + req->req.length = 0; + req->req.status = -EINPROGRESS; + req->req.actual = 0; + req->req.complete = NULL; + req->dtd_count = 0; + + if (!req_to_dtd(req)) + status = queue_dtd(ep, req); + else + return -ENOMEM; + + if (status) + ERROR(dev, "can't queue ep0 status request\n"); + + list_add_tail(&req->queue, &ep->queue); + + VDBG(dev, "<--- %s()\n", __func__); + return status; +} + + +/* SET_ADDRESS request routine */ +static void set_address(struct langwell_udc *dev, u16 value, + u16 index, u16 length) +{ + VDBG(dev, "---> %s()\n", __func__); + + /* save the new address to device struct */ + dev->dev_addr = (u8) value; + VDBG(dev, "dev->dev_addr = %d\n", dev->dev_addr); + + /* update usb state */ + dev->usb_state = USB_STATE_ADDRESS; + + /* STATUS phase */ + if (prime_status_phase(dev, EP_DIR_IN)) + ep0_stall(dev); + + VDBG(dev, "<--- %s()\n", __func__); +} + + +/* return endpoint by windex */ +static struct langwell_ep *get_ep_by_windex(struct langwell_udc *dev, + u16 wIndex) +{ + struct langwell_ep *ep; + VDBG(dev, "---> %s()\n", __func__); + + if ((wIndex & USB_ENDPOINT_NUMBER_MASK) == 0) + return &dev->ep[0]; + + list_for_each_entry(ep, &dev->gadget.ep_list, ep.ep_list) { + u8 bEndpointAddress; + if (!ep->desc) + continue; + + bEndpointAddress = ep->desc->bEndpointAddress; + if ((wIndex ^ bEndpointAddress) & USB_DIR_IN) + continue; + + if ((wIndex & USB_ENDPOINT_NUMBER_MASK) + == (bEndpointAddress & USB_ENDPOINT_NUMBER_MASK)) + return ep; + } + + VDBG(dev, "<--- %s()\n", __func__); + return NULL; +} + + +/* return whether endpoint is stalled, 0: not stalled; 1: stalled */ +static int ep_is_stall(struct langwell_ep *ep) +{ + struct langwell_udc *dev = ep->dev; + u32 endptctrl; + int retval; + + VDBG(dev, "---> %s()\n", __func__); + + endptctrl = readl(&dev->op_regs->endptctrl[ep->ep_num]); + if (is_in(ep)) + retval = endptctrl & EPCTRL_TXS ? 1 : 0; + else + retval = endptctrl & EPCTRL_RXS ? 1 : 0; + + VDBG(dev, "<--- %s()\n", __func__); + return retval; +} + + +/* GET_STATUS request routine */ +static void get_status(struct langwell_udc *dev, u8 request_type, u16 value, + u16 index, u16 length) +{ + struct langwell_request *req; + struct langwell_ep *ep; + u16 status_data = 0; /* 16 bits cpu view status data */ + int status = 0; + + VDBG(dev, "---> %s()\n", __func__); + + ep = &dev->ep[0]; + + if ((request_type & USB_RECIP_MASK) == USB_RECIP_DEVICE) { + /* get device status */ + status_data = 1 << USB_DEVICE_SELF_POWERED; + status_data |= dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP; + } else if ((request_type & USB_RECIP_MASK) == USB_RECIP_INTERFACE) { + /* get interface status */ + status_data = 0; + } else if ((request_type & USB_RECIP_MASK) == USB_RECIP_ENDPOINT) { + /* get endpoint status */ + struct langwell_ep *epn; + epn = get_ep_by_windex(dev, index); + /* stall if endpoint doesn't exist */ + if (!epn) + goto stall; + + status_data = ep_is_stall(epn) << USB_ENDPOINT_HALT; + } + + dev->ep0_dir = USB_DIR_IN; + + /* borrow the per device status_req */ + req = dev->status_req; + + /* fill in the reqest structure */ + *((u16 *) req->req.buf) = cpu_to_le16(status_data); + req->ep = ep; + req->req.length = 2; + req->req.status = -EINPROGRESS; + req->req.actual = 0; + req->req.complete = NULL; + req->dtd_count = 0; + + /* prime the data phase */ + if (!req_to_dtd(req)) + status = queue_dtd(ep, req); + else /* no mem */ + goto stall; + + if (status) { + ERROR(dev, "response error on GET_STATUS request\n"); + goto stall; + } + + list_add_tail(&req->queue, &ep->queue); + dev->ep0_state = DATA_STATE_XMIT; + + VDBG(dev, "<--- %s()\n", __func__); + return; +stall: + ep0_stall(dev); + VDBG(dev, "<--- %s()\n", __func__); +} + + +/* setup packet interrupt handler */ +static void handle_setup_packet(struct langwell_udc *dev, + struct usb_ctrlrequest *setup) +{ + u16 wValue = le16_to_cpu(setup->wValue); + u16 wIndex = le16_to_cpu(setup->wIndex); + u16 wLength = le16_to_cpu(setup->wLength); + + VDBG(dev, "---> %s()\n", __func__); + + /* ep0 fifo flush */ + nuke(&dev->ep[0], -ESHUTDOWN); + + DBG(dev, "SETUP %02x.%02x v%04x i%04x l%04x\n", + setup->bRequestType, setup->bRequest, + wValue, wIndex, wLength); + + /* RNDIS gadget delegate */ + if ((setup->bRequestType == 0x21) && (setup->bRequest == 0x00)) { + /* USB_CDC_SEND_ENCAPSULATED_COMMAND */ + goto delegate; + } + + /* USB_CDC_GET_ENCAPSULATED_RESPONSE */ + if ((setup->bRequestType == 0xa1) && (setup->bRequest == 0x01)) { + /* USB_CDC_GET_ENCAPSULATED_RESPONSE */ + goto delegate; + } + + /* We process some stardard setup requests here */ + switch (setup->bRequest) { + case USB_REQ_GET_STATUS: + DBG(dev, "SETUP: USB_REQ_GET_STATUS\n"); + /* get status, DATA and STATUS phase */ + if ((setup->bRequestType & (USB_DIR_IN | USB_TYPE_MASK)) + != (USB_DIR_IN | USB_TYPE_STANDARD)) + break; + get_status(dev, setup->bRequestType, wValue, wIndex, wLength); + goto end; + + case USB_REQ_SET_ADDRESS: + DBG(dev, "SETUP: USB_REQ_SET_ADDRESS\n"); + /* STATUS phase */ + if (setup->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD + | USB_RECIP_DEVICE)) + break; + set_address(dev, wValue, wIndex, wLength); + goto end; + + case USB_REQ_CLEAR_FEATURE: + case USB_REQ_SET_FEATURE: + /* STATUS phase */ + { + int rc = -EOPNOTSUPP; + if (setup->bRequest == USB_REQ_SET_FEATURE) + DBG(dev, "SETUP: USB_REQ_SET_FEATURE\n"); + else if (setup->bRequest == USB_REQ_CLEAR_FEATURE) + DBG(dev, "SETUP: USB_REQ_CLEAR_FEATURE\n"); + + if ((setup->bRequestType & (USB_RECIP_MASK | USB_TYPE_MASK)) + == (USB_RECIP_ENDPOINT | USB_TYPE_STANDARD)) { + struct langwell_ep *epn; + epn = get_ep_by_windex(dev, wIndex); + /* stall if endpoint doesn't exist */ + if (!epn) { + ep0_stall(dev); + goto end; + } + + if (wValue != 0 || wLength != 0 + || epn->ep_num > dev->ep_max) + break; + + spin_unlock(&dev->lock); + rc = langwell_ep_set_halt(&epn->ep, + (setup->bRequest == USB_REQ_SET_FEATURE) + ? 1 : 0); + spin_lock(&dev->lock); + + } else if ((setup->bRequestType & (USB_RECIP_MASK + | USB_TYPE_MASK)) == (USB_RECIP_DEVICE + | USB_TYPE_STANDARD)) { + if (!gadget_is_otg(&dev->gadget)) + break; + else if (setup->bRequest == USB_DEVICE_B_HNP_ENABLE) { + dev->gadget.b_hnp_enable = 1; +#ifdef OTG_TRANSCEIVER + if (!dev->lotg->otg.default_a) + dev->lotg->hsm.b_hnp_enable = 1; +#endif + } else if (setup->bRequest == USB_DEVICE_A_HNP_SUPPORT) + dev->gadget.a_hnp_support = 1; + else if (setup->bRequest == + USB_DEVICE_A_ALT_HNP_SUPPORT) + dev->gadget.a_alt_hnp_support = 1; + else + break; + rc = 0; + } else + break; + + if (rc == 0) { + if (prime_status_phase(dev, EP_DIR_IN)) + ep0_stall(dev); + } + goto end; + } + + case USB_REQ_GET_DESCRIPTOR: + DBG(dev, "SETUP: USB_REQ_GET_DESCRIPTOR\n"); + goto delegate; + + case USB_REQ_SET_DESCRIPTOR: + DBG(dev, "SETUP: USB_REQ_SET_DESCRIPTOR unsupported\n"); + goto delegate; + + case USB_REQ_GET_CONFIGURATION: + DBG(dev, "SETUP: USB_REQ_GET_CONFIGURATION\n"); + goto delegate; + + case USB_REQ_SET_CONFIGURATION: + DBG(dev, "SETUP: USB_REQ_SET_CONFIGURATION\n"); + goto delegate; + + case USB_REQ_GET_INTERFACE: + DBG(dev, "SETUP: USB_REQ_GET_INTERFACE\n"); + goto delegate; + + case USB_REQ_SET_INTERFACE: + DBG(dev, "SETUP: USB_REQ_SET_INTERFACE\n"); + goto delegate; + + case USB_REQ_SYNCH_FRAME: + DBG(dev, "SETUP: USB_REQ_SYNCH_FRAME unsupported\n"); + goto delegate; + + default: + /* delegate USB standard requests to the gadget driver */ + goto delegate; +delegate: + /* USB requests handled by gadget */ + if (wLength) { + /* DATA phase from gadget, STATUS phase from udc */ + dev->ep0_dir = (setup->bRequestType & USB_DIR_IN) + ? USB_DIR_IN : USB_DIR_OUT; + VDBG(dev, "dev->ep0_dir = 0x%x, wLength = %d\n", + dev->ep0_dir, wLength); + spin_unlock(&dev->lock); + if (dev->driver->setup(&dev->gadget, + &dev->local_setup_buff) < 0) + ep0_stall(dev); + spin_lock(&dev->lock); + dev->ep0_state = (setup->bRequestType & USB_DIR_IN) + ? DATA_STATE_XMIT : DATA_STATE_RECV; + } else { + /* no DATA phase, IN STATUS phase from gadget */ + dev->ep0_dir = USB_DIR_IN; + VDBG(dev, "dev->ep0_dir = 0x%x, wLength = %d\n", + dev->ep0_dir, wLength); + spin_unlock(&dev->lock); + if (dev->driver->setup(&dev->gadget, + &dev->local_setup_buff) < 0) + ep0_stall(dev); + spin_lock(&dev->lock); + dev->ep0_state = WAIT_FOR_OUT_STATUS; + } + break; + } +end: + VDBG(dev, "<--- %s()\n", __func__); + return; +} + + +/* transfer completion, process endpoint request and free the completed dTDs + * for this request + */ +static int process_ep_req(struct langwell_udc *dev, int index, + struct langwell_request *curr_req) +{ + struct langwell_dtd *curr_dtd; + struct langwell_dqh *curr_dqh; + int td_complete, actual, remaining_length; + int i, dir; + u8 dtd_status = 0; + int retval = 0; + + curr_dqh = &dev->ep_dqh[index]; + dir = index % 2; + + curr_dtd = curr_req->head; + td_complete = 0; + actual = curr_req->req.length; + + VDBG(dev, "---> %s()\n", __func__); + + for (i = 0; i < curr_req->dtd_count; i++) { + remaining_length = le16_to_cpu(curr_dtd->dtd_total); + actual -= remaining_length; + + /* command execution states by dTD */ + dtd_status = curr_dtd->dtd_status; + + if (!dtd_status) { + /* transfers completed successfully */ + if (!remaining_length) { + td_complete++; + VDBG(dev, "dTD transmitted successfully\n"); + } else { + if (dir) { + VDBG(dev, "TX dTD remains data\n"); + retval = -EPROTO; + break; + + } else { + td_complete++; + break; + } + } + } else { + /* transfers completed with errors */ + if (dtd_status & DTD_STS_ACTIVE) { + DBG(dev, "request not completed\n"); + retval = 1; + return retval; + } else if (dtd_status & DTD_STS_HALTED) { + ERROR(dev, "dTD error %08x dQH[%d]\n", + dtd_status, index); + /* clear the errors and halt condition */ + curr_dqh->dtd_status = 0; + retval = -EPIPE; + break; + } else if (dtd_status & DTD_STS_DBE) { + DBG(dev, "data buffer (overflow) error\n"); + retval = -EPROTO; + break; + } else if (dtd_status & DTD_STS_TRE) { + DBG(dev, "transaction(ISO) error\n"); + retval = -EILSEQ; + break; + } else + ERROR(dev, "unknown error (0x%x)!\n", + dtd_status); + } + + if (i != curr_req->dtd_count - 1) + curr_dtd = (struct langwell_dtd *) + curr_dtd->next_dtd_virt; + } + + if (retval) + return retval; + + curr_req->req.actual = actual; + + VDBG(dev, "<--- %s()\n", __func__); + return 0; +} + + +/* complete DATA or STATUS phase of ep0 prime status phase if needed */ +static void ep0_req_complete(struct langwell_udc *dev, + struct langwell_ep *ep0, struct langwell_request *req) +{ + u32 new_addr; + VDBG(dev, "---> %s()\n", __func__); + + if (dev->usb_state == USB_STATE_ADDRESS) { + /* set the new address */ + new_addr = (u32)dev->dev_addr; + writel(new_addr << USBADR_SHIFT, &dev->op_regs->deviceaddr); + + new_addr = USBADR(readl(&dev->op_regs->deviceaddr)); + VDBG(dev, "new_addr = %d\n", new_addr); + } + + done(ep0, req, 0); + + switch (dev->ep0_state) { + case DATA_STATE_XMIT: + /* receive status phase */ + if (prime_status_phase(dev, EP_DIR_OUT)) + ep0_stall(dev); + break; + case DATA_STATE_RECV: + /* send status phase */ + if (prime_status_phase(dev, EP_DIR_IN)) + ep0_stall(dev); + break; + case WAIT_FOR_OUT_STATUS: + dev->ep0_state = WAIT_FOR_SETUP; + break; + case WAIT_FOR_SETUP: + ERROR(dev, "unexpect ep0 packets\n"); + break; + default: + ep0_stall(dev); + break; + } + + VDBG(dev, "<--- %s()\n", __func__); +} + + +/* USB transfer completion interrupt */ +static void handle_trans_complete(struct langwell_udc *dev) +{ + u32 complete_bits; + int i, ep_num, dir, bit_mask, status; + struct langwell_ep *epn; + struct langwell_request *curr_req, *temp_req; + + VDBG(dev, "---> %s()\n", __func__); + + complete_bits = readl(&dev->op_regs->endptcomplete); + VDBG(dev, "endptcomplete register: 0x%08x\n", complete_bits); + + /* Write-Clear the bits in endptcomplete register */ + writel(complete_bits, &dev->op_regs->endptcomplete); + + if (!complete_bits) { + DBG(dev, "complete_bits = 0\n"); + goto done; + } + + for (i = 0; i < dev->ep_max; i++) { + ep_num = i / 2; + dir = i % 2; + + bit_mask = 1 << (ep_num + 16 * dir); + + if (!(complete_bits & bit_mask)) + continue; + + /* ep0 */ + if (i == 1) + epn = &dev->ep[0]; + else + epn = &dev->ep[i]; + + if (epn->name == NULL) { + WARNING(dev, "invalid endpoint\n"); + continue; + } + + if (i < 2) + /* ep0 in and out */ + DBG(dev, "%s-%s transfer completed\n", + epn->name, + is_in(epn) ? "in" : "out"); + else + DBG(dev, "%s transfer completed\n", epn->name); + + /* process the req queue until an uncomplete request */ + list_for_each_entry_safe(curr_req, temp_req, + &epn->queue, queue) { + status = process_ep_req(dev, i, curr_req); + VDBG(dev, "%s req status: %d\n", epn->name, status); + + if (status) + break; + + /* write back status to req */ + curr_req->req.status = status; + + /* ep0 request completion */ + if (ep_num == 0) { + ep0_req_complete(dev, epn, curr_req); + break; + } else { + done(epn, curr_req, status); + } + } + } +done: + VDBG(dev, "<--- %s()\n", __func__); + return; +} + + +/* port change detect interrupt handler */ +static void handle_port_change(struct langwell_udc *dev) +{ + u32 portsc1, devlc; + u32 speed; + + VDBG(dev, "---> %s()\n", __func__); + + if (dev->bus_reset) + dev->bus_reset = 0; + + portsc1 = readl(&dev->op_regs->portsc1); + devlc = readl(&dev->op_regs->devlc); + VDBG(dev, "portsc1 = 0x%08x, devlc = 0x%08x\n", + portsc1, devlc); + + /* bus reset is finished */ + if (!(portsc1 & PORTS_PR)) { + /* get the speed */ + speed = LPM_PSPD(devlc); + switch (speed) { + case LPM_SPEED_HIGH: + dev->gadget.speed = USB_SPEED_HIGH; + break; + case LPM_SPEED_FULL: + dev->gadget.speed = USB_SPEED_FULL; + break; + case LPM_SPEED_LOW: + dev->gadget.speed = USB_SPEED_LOW; + break; + default: + dev->gadget.speed = USB_SPEED_UNKNOWN; + break; + } + VDBG(dev, "speed = %d, dev->gadget.speed = %d\n", + speed, dev->gadget.speed); + } + + /* LPM L0 to L1 */ + if (dev->lpm && dev->lpm_state == LPM_L0) + if (portsc1 & PORTS_SUSP && portsc1 & PORTS_SLP) { + INFO(dev, "LPM L0 to L1\n"); + dev->lpm_state = LPM_L1; + } + + /* LPM L1 to L0, force resume or remote wakeup finished */ + if (dev->lpm && dev->lpm_state == LPM_L1) + if (!(portsc1 & PORTS_SUSP)) { + if (portsc1 & PORTS_SLP) + INFO(dev, "LPM L1 to L0, force resume\n"); + else + INFO(dev, "LPM L1 to L0, remote wakeup\n"); + + dev->lpm_state = LPM_L0; + } + + /* update USB state */ + if (!dev->resume_state) + dev->usb_state = USB_STATE_DEFAULT; + + VDBG(dev, "<--- %s()\n", __func__); +} + + +/* USB reset interrupt handler */ +static void handle_usb_reset(struct langwell_udc *dev) +{ + u32 deviceaddr, + endptsetupstat, + endptcomplete; + unsigned long timeout; + + VDBG(dev, "---> %s()\n", __func__); + + /* Write-Clear the device address */ + deviceaddr = readl(&dev->op_regs->deviceaddr); + writel(deviceaddr & ~USBADR_MASK, &dev->op_regs->deviceaddr); + + dev->dev_addr = 0; + + /* clear usb state */ + dev->resume_state = 0; + + /* LPM L1 to L0, reset */ + if (dev->lpm) + dev->lpm_state = LPM_L0; + + dev->ep0_dir = USB_DIR_OUT; + dev->ep0_state = WAIT_FOR_SETUP; + dev->remote_wakeup = 0; /* default to 0 on reset */ + dev->gadget.b_hnp_enable = 0; + dev->gadget.a_hnp_support = 0; + dev->gadget.a_alt_hnp_support = 0; + + /* Write-Clear all the setup token semaphores */ + endptsetupstat = readl(&dev->op_regs->endptsetupstat); + writel(endptsetupstat, &dev->op_regs->endptsetupstat); + + /* Write-Clear all the endpoint complete status bits */ + endptcomplete = readl(&dev->op_regs->endptcomplete); + writel(endptcomplete, &dev->op_regs->endptcomplete); + + /* wait until all endptprime bits cleared */ + timeout = jiffies + PRIME_TIMEOUT; + while (readl(&dev->op_regs->endptprime)) { + if (time_after(jiffies, timeout)) { + ERROR(dev, "USB reset timeout\n"); + break; + } + cpu_relax(); + } + + /* write 1s to endptflush register to clear any primed buffers */ + writel((u32) ~0, &dev->op_regs->endptflush); + + if (readl(&dev->op_regs->portsc1) & PORTS_PR) { + VDBG(dev, "USB bus reset\n"); + /* bus is reseting */ + dev->bus_reset = 1; + + /* reset all the queues, stop all USB activities */ + stop_activity(dev, dev->driver); + dev->usb_state = USB_STATE_DEFAULT; + } else { + VDBG(dev, "device controller reset\n"); + /* controller reset */ + langwell_udc_reset(dev); + + /* reset all the queues, stop all USB activities */ + stop_activity(dev, dev->driver); + + /* reset ep0 dQH and endptctrl */ + ep0_reset(dev); + + /* enable interrupt and set controller to run state */ + langwell_udc_start(dev); + + dev->usb_state = USB_STATE_ATTACHED; + } + +#ifdef OTG_TRANSCEIVER + /* refer to USB OTG 6.6.2.3 b_hnp_en is cleared */ + if (!dev->lotg->otg.default_a) + dev->lotg->hsm.b_hnp_enable = 0; +#endif + + VDBG(dev, "<--- %s()\n", __func__); +} + + +/* USB bus suspend/resume interrupt */ +static void handle_bus_suspend(struct langwell_udc *dev) +{ + u32 devlc; + DBG(dev, "---> %s()\n", __func__); + + dev->resume_state = dev->usb_state; + dev->usb_state = USB_STATE_SUSPENDED; + +#ifdef OTG_TRANSCEIVER + if (dev->lotg->otg.default_a) { + if (dev->lotg->hsm.b_bus_suspend_vld == 1) { + dev->lotg->hsm.b_bus_suspend = 1; + /* notify transceiver the state changes */ + if (spin_trylock(&dev->lotg->wq_lock)) { + langwell_update_transceiver(); + spin_unlock(&dev->lotg->wq_lock); + } + } + dev->lotg->hsm.b_bus_suspend_vld++; + } else { + if (!dev->lotg->hsm.a_bus_suspend) { + dev->lotg->hsm.a_bus_suspend = 1; + /* notify transceiver the state changes */ + if (spin_trylock(&dev->lotg->wq_lock)) { + langwell_update_transceiver(); + spin_unlock(&dev->lotg->wq_lock); + } + } + } +#endif + + /* report suspend to the driver */ + if (dev->driver) { + if (dev->driver->suspend) { + spin_unlock(&dev->lock); + dev->driver->suspend(&dev->gadget); + spin_lock(&dev->lock); + DBG(dev, "suspend %s\n", dev->driver->driver.name); + } + } + + /* enter PHY low power suspend */ + devlc = readl(&dev->op_regs->devlc); + VDBG(dev, "devlc = 0x%08x\n", devlc); + devlc |= LPM_PHCD; + writel(devlc, &dev->op_regs->devlc); + + DBG(dev, "<--- %s()\n", __func__); +} + + +static void handle_bus_resume(struct langwell_udc *dev) +{ + u32 devlc; + DBG(dev, "---> %s()\n", __func__); + + dev->usb_state = dev->resume_state; + dev->resume_state = 0; + + /* exit PHY low power suspend */ + devlc = readl(&dev->op_regs->devlc); + VDBG(dev, "devlc = 0x%08x\n", devlc); + devlc &= ~LPM_PHCD; + writel(devlc, &dev->op_regs->devlc); + +#ifdef OTG_TRANSCEIVER + if (dev->lotg->otg.default_a == 0) + dev->lotg->hsm.a_bus_suspend = 0; +#endif + + /* report resume to the driver */ + if (dev->driver) { + if (dev->driver->resume) { + spin_unlock(&dev->lock); + dev->driver->resume(&dev->gadget); + spin_lock(&dev->lock); + DBG(dev, "resume %s\n", dev->driver->driver.name); + } + } + + DBG(dev, "<--- %s()\n", __func__); +} + + +/* USB device controller interrupt handler */ +static irqreturn_t langwell_irq(int irq, void *_dev) +{ + struct langwell_udc *dev = _dev; + u32 usbsts, + usbintr, + irq_sts, + portsc1; + + VDBG(dev, "---> %s()\n", __func__); + + if (dev->stopped) { + VDBG(dev, "handle IRQ_NONE\n"); + VDBG(dev, "<--- %s()\n", __func__); + return IRQ_NONE; + } + + spin_lock(&dev->lock); + + /* USB status */ + usbsts = readl(&dev->op_regs->usbsts); + + /* USB interrupt enable */ + usbintr = readl(&dev->op_regs->usbintr); + + irq_sts = usbsts & usbintr; + VDBG(dev, "usbsts = 0x%08x, usbintr = 0x%08x, irq_sts = 0x%08x\n", + usbsts, usbintr, irq_sts); + + if (!irq_sts) { + VDBG(dev, "handle IRQ_NONE\n"); + VDBG(dev, "<--- %s()\n", __func__); + spin_unlock(&dev->lock); + return IRQ_NONE; + } + + /* Write-Clear interrupt status bits */ + writel(irq_sts, &dev->op_regs->usbsts); + + /* resume from suspend */ + portsc1 = readl(&dev->op_regs->portsc1); + if (dev->usb_state == USB_STATE_SUSPENDED) + if (!(portsc1 & PORTS_SUSP)) + handle_bus_resume(dev); + + /* USB interrupt */ + if (irq_sts & STS_UI) { + VDBG(dev, "USB interrupt\n"); + + /* setup packet received from ep0 */ + if (readl(&dev->op_regs->endptsetupstat) + & EP0SETUPSTAT_MASK) { + VDBG(dev, "USB SETUP packet received interrupt\n"); + /* setup tripwire semaphone */ + setup_tripwire(dev); + handle_setup_packet(dev, &dev->local_setup_buff); + } + + /* USB transfer completion */ + if (readl(&dev->op_regs->endptcomplete)) { + VDBG(dev, "USB transfer completion interrupt\n"); + handle_trans_complete(dev); + } + } + + /* SOF received interrupt (for ISO transfer) */ + if (irq_sts & STS_SRI) { + /* FIXME */ + /* VDBG(dev, "SOF received interrupt\n"); */ + } + + /* port change detect interrupt */ + if (irq_sts & STS_PCI) { + VDBG(dev, "port change detect interrupt\n"); + handle_port_change(dev); + } + + /* suspend interrrupt */ + if (irq_sts & STS_SLI) { + VDBG(dev, "suspend interrupt\n"); + handle_bus_suspend(dev); + } + + /* USB reset interrupt */ + if (irq_sts & STS_URI) { + VDBG(dev, "USB reset interrupt\n"); + handle_usb_reset(dev); + } + + /* USB error or system error interrupt */ + if (irq_sts & (STS_UEI | STS_SEI)) { + /* FIXME */ + WARNING(dev, "error IRQ, irq_sts: %x\n", irq_sts); + } + + spin_unlock(&dev->lock); + + VDBG(dev, "<--- %s()\n", __func__); + return IRQ_HANDLED; +} + + +/*-------------------------------------------------------------------------*/ + +/* release device structure */ +static void gadget_release(struct device *_dev) +{ + struct langwell_udc *dev = the_controller; + + DBG(dev, "---> %s()\n", __func__); + + complete(dev->done); + + DBG(dev, "<--- %s()\n", __func__); + kfree(dev); +} + + +/* tear down the binding between this driver and the pci device */ +static void langwell_udc_remove(struct pci_dev *pdev) +{ + struct langwell_udc *dev = the_controller; + + DECLARE_COMPLETION(done); + + BUG_ON(dev->driver); + DBG(dev, "---> %s()\n", __func__); + + dev->done = &done; + + /* free memory allocated in probe */ + if (dev->dtd_pool) + dma_pool_destroy(dev->dtd_pool); + + if (dev->status_req) { + kfree(dev->status_req->req.buf); + kfree(dev->status_req); + } + + if (dev->ep_dqh) + dma_free_coherent(&pdev->dev, dev->ep_dqh_size, + dev->ep_dqh, dev->ep_dqh_dma); + + kfree(dev->ep); + + /* diable IRQ handler */ + if (dev->got_irq) + free_irq(pdev->irq, dev); + +#ifndef OTG_TRANSCEIVER + if (dev->cap_regs) + iounmap(dev->cap_regs); + + if (dev->region) + release_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + + if (dev->enabled) + pci_disable_device(pdev); +#else + if (dev->transceiver) { + otg_put_transceiver(dev->transceiver); + dev->transceiver = NULL; + dev->lotg = NULL; + } +#endif + + dev->cap_regs = NULL; + + INFO(dev, "unbind\n"); + DBG(dev, "<--- %s()\n", __func__); + + device_unregister(&dev->gadget.dev); + device_remove_file(&pdev->dev, &dev_attr_langwell_udc); + +#ifndef OTG_TRANSCEIVER + pci_set_drvdata(pdev, NULL); +#endif + + /* free dev, wait for the release() finished */ + wait_for_completion(&done); + + the_controller = NULL; +} + + +/* + * wrap this driver around the specified device, but + * don't respond over USB until a gadget driver binds to us. + */ +static int langwell_udc_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct langwell_udc *dev; +#ifndef OTG_TRANSCEIVER + unsigned long resource, len; +#endif + void __iomem *base = NULL; + size_t size; + int retval; + + if (the_controller) { + dev_warn(&pdev->dev, "ignoring\n"); + return -EBUSY; + } + + /* alloc, and start init */ + dev = kzalloc(sizeof *dev, GFP_KERNEL); + if (dev == NULL) { + retval = -ENOMEM; + goto error; + } + + /* initialize device spinlock */ + spin_lock_init(&dev->lock); + + dev->pdev = pdev; + DBG(dev, "---> %s()\n", __func__); + +#ifdef OTG_TRANSCEIVER + /* PCI device is already enabled by otg_transceiver driver */ + dev->enabled = 1; + + /* mem region and register base */ + dev->region = 1; + dev->transceiver = otg_get_transceiver(); + dev->lotg = otg_to_langwell(dev->transceiver); + base = dev->lotg->regs; +#else + pci_set_drvdata(pdev, dev); + + /* now all the pci goodies ... */ + if (pci_enable_device(pdev) < 0) { + retval = -ENODEV; + goto error; + } + dev->enabled = 1; + + /* control register: BAR 0 */ + resource = pci_resource_start(pdev, 0); + len = pci_resource_len(pdev, 0); + if (!request_mem_region(resource, len, driver_name)) { + ERROR(dev, "controller already in use\n"); + retval = -EBUSY; + goto error; + } + dev->region = 1; + + base = ioremap_nocache(resource, len); +#endif + if (base == NULL) { + ERROR(dev, "can't map memory\n"); + retval = -EFAULT; + goto error; + } + + dev->cap_regs = (struct langwell_cap_regs __iomem *) base; + VDBG(dev, "dev->cap_regs: %p\n", dev->cap_regs); + dev->op_regs = (struct langwell_op_regs __iomem *) + (base + OP_REG_OFFSET); + VDBG(dev, "dev->op_regs: %p\n", dev->op_regs); + + /* irq setup after old hardware is cleaned up */ + if (!pdev->irq) { + ERROR(dev, "No IRQ. Check PCI setup!\n"); + retval = -ENODEV; + goto error; + } + +#ifndef OTG_TRANSCEIVER + INFO(dev, "irq %d, io mem: 0x%08lx, len: 0x%08lx, pci mem 0x%p\n", + pdev->irq, resource, len, base); + /* enables bus-mastering for device dev */ + pci_set_master(pdev); + + if (request_irq(pdev->irq, langwell_irq, IRQF_SHARED, + driver_name, dev) != 0) { + ERROR(dev, "request interrupt %d failed\n", pdev->irq); + retval = -EBUSY; + goto error; + } + dev->got_irq = 1; +#endif + + /* set stopped bit */ + dev->stopped = 1; + + /* capabilities and endpoint number */ + dev->lpm = (readl(&dev->cap_regs->hccparams) & HCC_LEN) ? 1 : 0; + dev->dciversion = readw(&dev->cap_regs->dciversion); + dev->devcap = (readl(&dev->cap_regs->dccparams) & DEVCAP) ? 1 : 0; + VDBG(dev, "dev->lpm: %d\n", dev->lpm); + VDBG(dev, "dev->dciversion: 0x%04x\n", dev->dciversion); + VDBG(dev, "dccparams: 0x%08x\n", readl(&dev->cap_regs->dccparams)); + VDBG(dev, "dev->devcap: %d\n", dev->devcap); + if (!dev->devcap) { + ERROR(dev, "can't support device mode\n"); + retval = -ENODEV; + goto error; + } + + /* a pair of endpoints (out/in) for each address */ + dev->ep_max = DEN(readl(&dev->cap_regs->dccparams)) * 2; + VDBG(dev, "dev->ep_max: %d\n", dev->ep_max); + + /* allocate endpoints memory */ + dev->ep = kzalloc(sizeof(struct langwell_ep) * dev->ep_max, + GFP_KERNEL); + if (!dev->ep) { + ERROR(dev, "allocate endpoints memory failed\n"); + retval = -ENOMEM; + goto error; + } + + /* allocate device dQH memory */ + size = dev->ep_max * sizeof(struct langwell_dqh); + VDBG(dev, "orig size = %d\n", size); + if (size < DQH_ALIGNMENT) + size = DQH_ALIGNMENT; + else if ((size % DQH_ALIGNMENT) != 0) { + size += DQH_ALIGNMENT + 1; + size &= ~(DQH_ALIGNMENT - 1); + } + dev->ep_dqh = dma_alloc_coherent(&pdev->dev, size, + &dev->ep_dqh_dma, GFP_KERNEL); + if (!dev->ep_dqh) { + ERROR(dev, "allocate dQH memory failed\n"); + retval = -ENOMEM; + goto error; + } + dev->ep_dqh_size = size; + VDBG(dev, "ep_dqh_size = %d\n", dev->ep_dqh_size); + + /* initialize ep0 status request structure */ + dev->status_req = kzalloc(sizeof(struct langwell_request), GFP_KERNEL); + if (!dev->status_req) { + ERROR(dev, "allocate status_req memory failed\n"); + retval = -ENOMEM; + goto error; + } + INIT_LIST_HEAD(&dev->status_req->queue); + + /* allocate a small amount of memory to get valid address */ + dev->status_req->req.buf = kmalloc(8, GFP_KERNEL); + dev->status_req->req.dma = virt_to_phys(dev->status_req->req.buf); + + dev->resume_state = USB_STATE_NOTATTACHED; + dev->usb_state = USB_STATE_POWERED; + dev->ep0_dir = USB_DIR_OUT; + dev->remote_wakeup = 0; /* default to 0 on reset */ + +#ifndef OTG_TRANSCEIVER + /* reset device controller */ + langwell_udc_reset(dev); +#endif + + /* initialize gadget structure */ + dev->gadget.ops = &langwell_ops; /* usb_gadget_ops */ + dev->gadget.ep0 = &dev->ep[0].ep; /* gadget ep0 */ + INIT_LIST_HEAD(&dev->gadget.ep_list); /* ep_list */ + dev->gadget.speed = USB_SPEED_UNKNOWN; /* speed */ + dev->gadget.is_dualspeed = 1; /* support dual speed */ +#ifdef OTG_TRANSCEIVER + dev->gadget.is_otg = 1; /* support otg mode */ +#endif + + /* the "gadget" abstracts/virtualizes the controller */ + dev_set_name(&dev->gadget.dev, "gadget"); + dev->gadget.dev.parent = &pdev->dev; + dev->gadget.dev.dma_mask = pdev->dev.dma_mask; + dev->gadget.dev.release = gadget_release; + dev->gadget.name = driver_name; /* gadget name */ + + /* controller endpoints reinit */ + eps_reinit(dev); + +#ifndef OTG_TRANSCEIVER + /* reset ep0 dQH and endptctrl */ + ep0_reset(dev); +#endif + + /* create dTD dma_pool resource */ + dev->dtd_pool = dma_pool_create("langwell_dtd", + &dev->pdev->dev, + sizeof(struct langwell_dtd), + DTD_ALIGNMENT, + DMA_BOUNDARY); + + if (!dev->dtd_pool) { + retval = -ENOMEM; + goto error; + } + + /* done */ + INFO(dev, "%s\n", driver_desc); + INFO(dev, "irq %d, pci mem %p\n", pdev->irq, base); + INFO(dev, "Driver version: " DRIVER_VERSION "\n"); + INFO(dev, "Support (max) %d endpoints\n", dev->ep_max); + INFO(dev, "Device interface version: 0x%04x\n", dev->dciversion); + INFO(dev, "Controller mode: %s\n", dev->devcap ? "Device" : "Host"); + INFO(dev, "Support USB LPM: %s\n", dev->lpm ? "Yes" : "No"); + + VDBG(dev, "After langwell_udc_probe(), print all registers:\n"); +#ifdef VERBOSE + print_all_registers(dev); +#endif + + the_controller = dev; + + retval = device_register(&dev->gadget.dev); + if (retval) + goto error; + + retval = device_create_file(&pdev->dev, &dev_attr_langwell_udc); + if (retval) + goto error; + + VDBG(dev, "<--- %s()\n", __func__); + return 0; + +error: + if (dev) { + DBG(dev, "<--- %s()\n", __func__); + langwell_udc_remove(pdev); + } + + return retval; +} + + +/* device controller suspend */ +static int langwell_udc_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct langwell_udc *dev = the_controller; + u32 devlc; + + DBG(dev, "---> %s()\n", __func__); + + /* disable interrupt and set controller to stop state */ + langwell_udc_stop(dev); + + /* diable IRQ handler */ + if (dev->got_irq) + free_irq(pdev->irq, dev); + dev->got_irq = 0; + + + /* save PCI state */ + pci_save_state(pdev); + + /* set device power state */ + pci_set_power_state(pdev, PCI_D3hot); + + /* enter PHY low power suspend */ + devlc = readl(&dev->op_regs->devlc); + VDBG(dev, "devlc = 0x%08x\n", devlc); + devlc |= LPM_PHCD; + writel(devlc, &dev->op_regs->devlc); + + DBG(dev, "<--- %s()\n", __func__); + return 0; +} + + +/* device controller resume */ +static int langwell_udc_resume(struct pci_dev *pdev) +{ + struct langwell_udc *dev = the_controller; + u32 devlc; + + DBG(dev, "---> %s()\n", __func__); + + /* exit PHY low power suspend */ + devlc = readl(&dev->op_regs->devlc); + VDBG(dev, "devlc = 0x%08x\n", devlc); + devlc &= ~LPM_PHCD; + writel(devlc, &dev->op_regs->devlc); + + /* set device D0 power state */ + pci_set_power_state(pdev, PCI_D0); + + /* restore PCI state */ + pci_restore_state(pdev); + + /* enable IRQ handler */ + if (request_irq(pdev->irq, langwell_irq, IRQF_SHARED, driver_name, dev) + != 0) { + ERROR(dev, "request interrupt %d failed\n", pdev->irq); + return -1; + } + dev->got_irq = 1; + + /* reset and start controller to run state */ + if (dev->stopped) { + /* reset device controller */ + langwell_udc_reset(dev); + + /* reset ep0 dQH and endptctrl */ + ep0_reset(dev); + + /* start device if gadget is loaded */ + if (dev->driver) + langwell_udc_start(dev); + } + + /* reset USB status */ + dev->usb_state = USB_STATE_ATTACHED; + dev->ep0_state = WAIT_FOR_SETUP; + dev->ep0_dir = USB_DIR_OUT; + + DBG(dev, "<--- %s()\n", __func__); + return 0; +} + + +/* pci driver shutdown */ +static void langwell_udc_shutdown(struct pci_dev *pdev) +{ + struct langwell_udc *dev = the_controller; + u32 usbmode; + + DBG(dev, "---> %s()\n", __func__); + + /* reset controller mode to IDLE */ + usbmode = readl(&dev->op_regs->usbmode); + DBG(dev, "usbmode = 0x%08x\n", usbmode); + usbmode &= (~3 | MODE_IDLE); + writel(usbmode, &dev->op_regs->usbmode); + + DBG(dev, "<--- %s()\n", __func__); +} + +/*-------------------------------------------------------------------------*/ + +static const struct pci_device_id pci_ids[] = { { + .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe), + .class_mask = ~0, + .vendor = 0x8086, + .device = 0x0811, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, +}, { /* end: all zeroes */ } +}; + + +MODULE_DEVICE_TABLE(pci, pci_ids); + + +static struct pci_driver langwell_pci_driver = { + .name = (char *) driver_name, + .id_table = pci_ids, + + .probe = langwell_udc_probe, + .remove = langwell_udc_remove, + + /* device controller suspend/resume */ + .suspend = langwell_udc_suspend, + .resume = langwell_udc_resume, + + .shutdown = langwell_udc_shutdown, +}; + + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_AUTHOR("Xiaochen Shen "); +MODULE_VERSION(DRIVER_VERSION); +MODULE_LICENSE("GPL"); + + +static int __init init(void) +{ +#ifdef OTG_TRANSCEIVER + return langwell_register_peripheral(&langwell_pci_driver); +#else + return pci_register_driver(&langwell_pci_driver); +#endif +} +module_init(init); + + +static void __exit cleanup(void) +{ +#ifdef OTG_TRANSCEIVER + return langwell_unregister_peripheral(&langwell_pci_driver); +#else + pci_unregister_driver(&langwell_pci_driver); +#endif +} +module_exit(cleanup); + diff --git a/drivers/usb/gadget/langwell_udc.h b/drivers/usb/gadget/langwell_udc.h new file mode 100644 index 000000000000..9719934e1c08 --- /dev/null +++ b/drivers/usb/gadget/langwell_udc.h @@ -0,0 +1,228 @@ +/* + * Intel Langwell USB Device Controller driver + * Copyright (C) 2008-2009, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include + +#if defined(CONFIG_USB_LANGWELL_OTG) +#include +#endif + + +/*-------------------------------------------------------------------------*/ + +/* driver data structures and utilities */ + +/* + * dTD: Device Endpoint Transfer Descriptor + * describe to the device controller the location and quantity of + * data to be send/received for given transfer + */ +struct langwell_dtd { + u32 dtd_next; +/* bits 31:5, next transfer element pointer */ +#define DTD_NEXT(d) (((d)>>5)&0x7ffffff) +#define DTD_NEXT_MASK (0x7ffffff << 5) +/* terminate */ +#define DTD_TERM BIT(0) + /* bits 7:0, execution back states */ + u32 dtd_status:8; +#define DTD_STATUS(d) (((d)>>0)&0xff) +#define DTD_STS_ACTIVE BIT(7) /* active */ +#define DTD_STS_HALTED BIT(6) /* halted */ +#define DTD_STS_DBE BIT(5) /* data buffer error */ +#define DTD_STS_TRE BIT(3) /* transaction error */ + /* bits 9:8 */ + u32 dtd_res0:2; + /* bits 11:10, multipier override */ + u32 dtd_multo:2; +#define DTD_MULTO (BIT(11) | BIT(10)) + /* bits 14:12 */ + u32 dtd_res1:3; + /* bit 15, interrupt on complete */ + u32 dtd_ioc:1; +#define DTD_IOC BIT(15) + /* bits 30:16, total bytes */ + u32 dtd_total:15; +#define DTD_TOTAL(d) (((d)>>16)&0x7fff) +#define DTD_MAX_TRANSFER_LENGTH 0x4000 + /* bit 31 */ + u32 dtd_res2:1; + /* dTD buffer pointer page 0 to 4 */ + u32 dtd_buf[5]; +#define DTD_OFFSET_MASK 0xfff +/* bits 31:12, buffer pointer */ +#define DTD_BUFFER(d) (((d)>>12)&0x3ff) +/* bits 11:0, current offset */ +#define DTD_C_OFFSET(d) (((d)>>0)&0xfff) +/* bits 10:0, frame number */ +#define DTD_FRAME(d) (((d)>>0)&0x7ff) + + /* driver-private parts */ + + /* dtd dma address */ + dma_addr_t dtd_dma; + /* next dtd virtual address */ + struct langwell_dtd *next_dtd_virt; +}; + + +/* + * dQH: Device Endpoint Queue Head + * describe where all transfers are managed + * 48-byte data structure, aligned on 64-byte boundary + * + * These are associated with dTD structure + */ +struct langwell_dqh { + /* endpoint capabilities and characteristics */ + u32 dqh_res0:15; /* bits 14:0 */ + u32 dqh_ios:1; /* bit 15, interrupt on setup */ +#define DQH_IOS BIT(15) + u32 dqh_mpl:11; /* bits 26:16, maximum packet length */ +#define DQH_MPL (0x7ff << 16) + u32 dqh_res1:2; /* bits 28:27 */ + u32 dqh_zlt:1; /* bit 29, zero length termination */ +#define DQH_ZLT BIT(29) + u32 dqh_mult:2; /* bits 31:30 */ +#define DQH_MULT (BIT(30) | BIT(31)) + + /* current dTD pointer */ + u32 dqh_current; /* locate the transfer in progress */ +#define DQH_C_DTD(e) \ + (((e)>>5)&0x7ffffff) /* bits 31:5, current dTD pointer */ + + /* transfer overlay, hardware parts of a struct langwell_dtd */ + u32 dtd_next; + u32 dtd_status:8; /* bits 7:0, execution back states */ + u32 dtd_res0:2; /* bits 9:8 */ + u32 dtd_multo:2; /* bits 11:10, multipier override */ + u32 dtd_res1:3; /* bits 14:12 */ + u32 dtd_ioc:1; /* bit 15, interrupt on complete */ + u32 dtd_total:15; /* bits 30:16, total bytes */ + u32 dtd_res2:1; /* bit 31 */ + u32 dtd_buf[5]; /* dTD buffer pointer page 0 to 4 */ + + u32 dqh_res2; + struct usb_ctrlrequest dqh_setup; /* setup packet buffer */ +} __attribute__ ((aligned(64))); + + +/* endpoint data structure */ +struct langwell_ep { + struct usb_ep ep; + dma_addr_t dma; + struct langwell_udc *dev; + unsigned long irqs; + struct list_head queue; + struct langwell_dqh *dqh; + const struct usb_endpoint_descriptor *desc; + char name[14]; + unsigned stopped:1, + ep_type:2, + ep_num:8; +}; + + +/* request data structure */ +struct langwell_request { + struct usb_request req; + struct langwell_dtd *dtd, *head, *tail; + struct langwell_ep *ep; + dma_addr_t dtd_dma; + struct list_head queue; + unsigned dtd_count; + unsigned mapped:1; +}; + + +/* ep0 transfer state */ +enum ep0_state { + WAIT_FOR_SETUP, + DATA_STATE_XMIT, + DATA_STATE_NEED_ZLP, + WAIT_FOR_OUT_STATUS, + DATA_STATE_RECV, +}; + + +/* device suspend state */ +enum lpm_state { + LPM_L0, /* on */ + LPM_L1, /* LPM L1 sleep */ + LPM_L2, /* suspend */ + LPM_L3, /* off */ +}; + + +/* device data structure */ +struct langwell_udc { + /* each pci device provides one gadget, several endpoints */ + struct usb_gadget gadget; + spinlock_t lock; /* device lock */ + struct langwell_ep *ep; + struct usb_gadget_driver *driver; + struct otg_transceiver *transceiver; + u8 dev_addr; + u32 usb_state; + u32 resume_state; + u32 bus_reset; + enum lpm_state lpm_state; + enum ep0_state ep0_state; + u32 ep0_dir; + u16 dciversion; + unsigned ep_max; + unsigned devcap:1, + enabled:1, + region:1, + got_irq:1, + powered:1, + remote_wakeup:1, + rate:1, + is_reset:1, + softconnected:1, + vbus_active:1, + suspended:1, + stopped:1, + lpm:1; /* LPM capability */ + + /* pci state used to access those endpoints */ + struct pci_dev *pdev; + + /* Langwell otg transceiver */ + struct langwell_otg *lotg; + + /* control registers */ + struct langwell_cap_regs __iomem *cap_regs; + struct langwell_op_regs __iomem *op_regs; + + struct usb_ctrlrequest local_setup_buff; + struct langwell_dqh *ep_dqh; + size_t ep_dqh_size; + dma_addr_t ep_dqh_dma; + + /* ep0 status request */ + struct langwell_request *status_req; + + /* dma pool */ + struct dma_pool *dtd_pool; + + /* make sure release() is done */ + struct completion *done; +}; + diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c index 8cc676ecbb23..1937d8c7b433 100644 --- a/drivers/usb/gadget/pxa27x_udc.c +++ b/drivers/usb/gadget/pxa27x_udc.c @@ -38,7 +38,6 @@ #include #include #include -#include /* FIXME: for PSSR */ #include #include "pxa27x_udc.h" @@ -473,6 +472,23 @@ static inline void udc_clear_mask_UDCCR(struct pxa_udc *udc, int mask) (udccr & UDCCR_MASK_BITS) & ~(mask & UDCCR_MASK_BITS)); } +/** + * ep_write_UDCCSR - set bits in UDCCSR + * @udc: udc device + * @mask: bits to set in UDCCR + * + * Sets bits in UDCCSR (UDCCSR0 and UDCCSR*). + * + * A specific case is applied to ep0 : the ACM bit is always set to 1, for + * SET_INTERFACE and SET_CONFIGURATION. + */ +static inline void ep_write_UDCCSR(struct pxa_ep *ep, int mask) +{ + if (is_ep0(ep)) + mask |= UDCCSR0_ACM; + udc_ep_writel(ep, UDCCSR, mask); +} + /** * ep_count_bytes_remain - get how many bytes in udc endpoint * @ep: udc endpoint @@ -861,7 +877,7 @@ static int read_packet(struct pxa_ep *ep, struct pxa27x_request *req) *buf++ = udc_ep_readl(ep, UDCDR); req->req.actual += count; - udc_ep_writel(ep, UDCCSR, UDCCSR_PC); + ep_write_UDCCSR(ep, UDCCSR_PC); return count; } @@ -969,12 +985,12 @@ static int write_fifo(struct pxa_ep *ep, struct pxa27x_request *req) if (udccsr & UDCCSR_PC) { ep_vdbg(ep, "Clearing Transmit Complete, udccsr=%x\n", udccsr); - udc_ep_writel(ep, UDCCSR, UDCCSR_PC); + ep_write_UDCCSR(ep, UDCCSR_PC); } if (udccsr & UDCCSR_TRN) { ep_vdbg(ep, "Clearing Underrun on, udccsr=%x\n", udccsr); - udc_ep_writel(ep, UDCCSR, UDCCSR_TRN); + ep_write_UDCCSR(ep, UDCCSR_TRN); } count = write_packet(ep, req, max); @@ -996,7 +1012,7 @@ static int write_fifo(struct pxa_ep *ep, struct pxa27x_request *req) } if (is_short) - udc_ep_writel(ep, UDCCSR, UDCCSR_SP); + ep_write_UDCCSR(ep, UDCCSR_SP); /* requests complete when all IN data is in the FIFO */ if (is_last) { @@ -1029,7 +1045,7 @@ static int read_ep0_fifo(struct pxa_ep *ep, struct pxa27x_request *req) while (epout_has_pkt(ep)) { count = read_packet(ep, req); - udc_ep_writel(ep, UDCCSR, UDCCSR0_OPC); + ep_write_UDCCSR(ep, UDCCSR0_OPC); inc_ep_stats_bytes(ep, count, !USB_DIR_IN); is_short = (count < ep->fifo_size); @@ -1074,7 +1090,7 @@ static int write_ep0_fifo(struct pxa_ep *ep, struct pxa27x_request *req) /* Sends either a short packet or a 0 length packet */ if (unlikely(is_short)) - udc_ep_writel(ep, UDCCSR, UDCCSR0_IPR); + ep_write_UDCCSR(ep, UDCCSR0_IPR); ep_dbg(ep, "in %d bytes%s%s, %d left, req=%p, udccsr0=0x%03x\n", count, is_short ? "/S" : "", is_last ? "/L" : "", @@ -1277,7 +1293,7 @@ static int pxa_ep_set_halt(struct usb_ep *_ep, int value) /* FST, FEF bits are the same for control and non control endpoints */ rc = 0; - udc_ep_writel(ep, UDCCSR, UDCCSR_FST | UDCCSR_FEF); + ep_write_UDCCSR(ep, UDCCSR_FST | UDCCSR_FEF); if (is_ep0(ep)) set_ep0state(ep->dev, STALL); @@ -1343,7 +1359,7 @@ static void pxa_ep_fifo_flush(struct usb_ep *_ep) udc_ep_readl(ep, UDCDR); } else { /* most IN status is the same, but ISO can't stall */ - udc_ep_writel(ep, UDCCSR, + ep_write_UDCCSR(ep, UDCCSR_PC | UDCCSR_FEF | UDCCSR_TRN | (EPXFERTYPE_is_ISO(ep) ? 0 : UDCCSR_SST)); } @@ -1728,6 +1744,7 @@ static void udc_enable(struct pxa_udc *udc) memset(&udc->stats, 0, sizeof(udc->stats)); udc_set_mask_UDCCR(udc, UDCCR_UDE); + ep_write_UDCCSR(&udc->pxa_ep[0], UDCCSR0_ACM); udelay(2); if (udc_readl(udc, UDCCR) & UDCCR_EMCE) dev_err(udc->dev, "Configuration errors, udc disabled\n"); @@ -1893,6 +1910,15 @@ static void handle_ep0_ctrl_req(struct pxa_udc *udc, nuke(ep, -EPROTO); + /* + * In the PXA320 manual, in the section about Back-to-Back setup + * packets, it describes this situation. The solution is to set OPC to + * get rid of the status packet, and then continue with the setup + * packet. Generalize to pxa27x CPUs. + */ + if (epout_has_pkt(ep) && (ep_count_bytes_remain(ep) == 0)) + ep_write_UDCCSR(ep, UDCCSR0_OPC); + /* read SETUP packet */ for (i = 0; i < 2; i++) { if (unlikely(ep_is_empty(ep))) @@ -1919,7 +1945,7 @@ static void handle_ep0_ctrl_req(struct pxa_udc *udc, set_ep0state(udc, OUT_DATA_STAGE); /* Tell UDC to enter Data Stage */ - udc_ep_writel(ep, UDCCSR, UDCCSR0_SA | UDCCSR0_OPC); + ep_write_UDCCSR(ep, UDCCSR0_SA | UDCCSR0_OPC); i = udc->driver->setup(&udc->gadget, &u.r); if (i < 0) @@ -1929,7 +1955,7 @@ out: stall: ep_dbg(ep, "protocol STALL, udccsr0=%03x err %d\n", udc_ep_readl(ep, UDCCSR), i); - udc_ep_writel(ep, UDCCSR, UDCCSR0_FST | UDCCSR0_FTF); + ep_write_UDCCSR(ep, UDCCSR0_FST | UDCCSR0_FTF); set_ep0state(udc, STALL); goto out; } @@ -1966,6 +1992,8 @@ stall: * cleared by software. * - clearing UDCCSR0_OPC always flushes ep0. If in setup stage, never do it * before reading ep0. + * This is true only for PXA27x. This is not true anymore for PXA3xx family + * (check Back-to-Back setup packet in developers guide). * - irq can be called on a "packet complete" event (opc_irq=1), while * UDCCSR0_OPC is not yet raised (delta can be as big as 100ms * from experimentation). @@ -1998,7 +2026,7 @@ static void handle_ep0(struct pxa_udc *udc, int fifo_irq, int opc_irq) if (udccsr0 & UDCCSR0_SST) { ep_dbg(ep, "clearing stall status\n"); nuke(ep, -EPIPE); - udc_ep_writel(ep, UDCCSR, UDCCSR0_SST); + ep_write_UDCCSR(ep, UDCCSR0_SST); ep0_idle(udc); } @@ -2023,7 +2051,7 @@ static void handle_ep0(struct pxa_udc *udc, int fifo_irq, int opc_irq) break; case IN_DATA_STAGE: /* GET_DESCRIPTOR */ if (epout_has_pkt(ep)) - udc_ep_writel(ep, UDCCSR, UDCCSR0_OPC); + ep_write_UDCCSR(ep, UDCCSR0_OPC); if (req && !ep_is_full(ep)) completed = write_ep0_fifo(ep, req); if (completed) @@ -2036,7 +2064,7 @@ static void handle_ep0(struct pxa_udc *udc, int fifo_irq, int opc_irq) ep0_end_out_req(ep, req); break; case STALL: - udc_ep_writel(ep, UDCCSR, UDCCSR0_FST); + ep_write_UDCCSR(ep, UDCCSR0_FST); break; case IN_STATUS_STAGE: /* @@ -2131,6 +2159,7 @@ static void pxa27x_change_configuration(struct pxa_udc *udc, int config) set_ep0state(udc, WAIT_ACK_SET_CONF_INTERF); udc->driver->setup(&udc->gadget, &req); + ep_write_UDCCSR(&udc->pxa_ep[0], UDCCSR0_AREN); } /** @@ -2159,6 +2188,7 @@ static void pxa27x_change_interface(struct pxa_udc *udc, int iface, int alt) set_ep0state(udc, WAIT_ACK_SET_CONF_INTERF); udc->driver->setup(&udc->gadget, &req); + ep_write_UDCCSR(&udc->pxa_ep[0], UDCCSR0_AREN); } /* @@ -2280,7 +2310,7 @@ static void irq_udc_reset(struct pxa_udc *udc) memset(&udc->stats, 0, sizeof udc->stats); nuke(ep, -EPROTO); - udc_ep_writel(ep, UDCCSR, UDCCSR0_FTF | UDCCSR0_OPC); + ep_write_UDCCSR(ep, UDCCSR0_FTF | UDCCSR0_OPC); ep0_idle(udc); } @@ -2479,6 +2509,12 @@ static void pxa_udc_shutdown(struct platform_device *_dev) udc_disable(udc); } +#ifdef CONFIG_CPU_PXA27x +extern void pxa27x_clear_otgph(void); +#else +#define pxa27x_clear_otgph() do {} while (0) +#endif + #ifdef CONFIG_PM /** * pxa_udc_suspend - Suspend udc device @@ -2546,8 +2582,7 @@ static int pxa_udc_resume(struct platform_device *_dev) * Software must configure the USB OTG pad, UDC, and UHC * to the state they were in before entering sleep mode. */ - if (cpu_is_pxa27x()) - PSSR |= PSSR_OTGPH; + pxa27x_clear_otgph(); return 0; } @@ -2571,7 +2606,7 @@ static struct platform_driver udc_driver = { static int __init udc_init(void) { - if (!cpu_is_pxa27x()) + if (!cpu_is_pxa27x() && !cpu_is_pxa3xx()) return -ENODEV; printk(KERN_INFO "%s: version %s\n", driver_name, DRIVER_VERSION); diff --git a/drivers/usb/gadget/pxa27x_udc.h b/drivers/usb/gadget/pxa27x_udc.h index db58125331da..e25225e26586 100644 --- a/drivers/usb/gadget/pxa27x_udc.h +++ b/drivers/usb/gadget/pxa27x_udc.h @@ -130,6 +130,8 @@ #define UP2OCR_HXOE (1 << 17) /* Transceiver Output Enable */ #define UP2OCR_SEOS (1 << 24) /* Single-Ended Output Select */ +#define UDCCSR0_ACM (1 << 9) /* Ack Control Mode */ +#define UDCCSR0_AREN (1 << 8) /* Ack Response Enable */ #define UDCCSR0_SA (1 << 7) /* Setup Active */ #define UDCCSR0_RNE (1 << 6) /* Receive FIFO Not Empty */ #define UDCCSR0_FST (1 << 5) /* Force Stall */ diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c new file mode 100644 index 000000000000..50c71aae2cc2 --- /dev/null +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -0,0 +1,3269 @@ +/* linux/drivers/usb/gadget/s3c-hsotg.c + * + * Copyright 2008 Openmoko, Inc. + * Copyright 2008 Simtec Electronics + * Ben Dooks + * http://armlinux.simtec.co.uk/ + * + * S3C USB2.0 High-speed / OtG driver + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include + +#define DMA_ADDR_INVALID (~((dma_addr_t)0)) + +/* EP0_MPS_LIMIT + * + * Unfortunately there seems to be a limit of the amount of data that can + * be transfered by IN transactions on EP0. This is either 127 bytes or 3 + * packets (which practially means 1 packet and 63 bytes of data) when the + * MPS is set to 64. + * + * This means if we are wanting to move >127 bytes of data, we need to + * split the transactions up, but just doing one packet at a time does + * not work (this may be an implicit DATA0 PID on first packet of the + * transaction) and doing 2 packets is outside the controller's limits. + * + * If we try to lower the MPS size for EP0, then no transfers work properly + * for EP0, and the system will fail basic enumeration. As no cause for this + * has currently been found, we cannot support any large IN transfers for + * EP0. + */ +#define EP0_MPS_LIMIT 64 + +struct s3c_hsotg; +struct s3c_hsotg_req; + +/** + * struct s3c_hsotg_ep - driver endpoint definition. + * @ep: The gadget layer representation of the endpoint. + * @name: The driver generated name for the endpoint. + * @queue: Queue of requests for this endpoint. + * @parent: Reference back to the parent device structure. + * @req: The current request that the endpoint is processing. This is + * used to indicate an request has been loaded onto the endpoint + * and has yet to be completed (maybe due to data move, or simply + * awaiting an ack from the core all the data has been completed). + * @debugfs: File entry for debugfs file for this endpoint. + * @lock: State lock to protect contents of endpoint. + * @dir_in: Set to true if this endpoint is of the IN direction, which + * means that it is sending data to the Host. + * @index: The index for the endpoint registers. + * @name: The name array passed to the USB core. + * @halted: Set if the endpoint has been halted. + * @periodic: Set if this is a periodic ep, such as Interrupt + * @sent_zlp: Set if we've sent a zero-length packet. + * @total_data: The total number of data bytes done. + * @fifo_size: The size of the FIFO (for periodic IN endpoints) + * @fifo_load: The amount of data loaded into the FIFO (periodic IN) + * @last_load: The offset of data for the last start of request. + * @size_loaded: The last loaded size for DxEPTSIZE for periodic IN + * + * This is the driver's state for each registered enpoint, allowing it + * to keep track of transactions that need doing. Each endpoint has a + * lock to protect the state, to try and avoid using an overall lock + * for the host controller as much as possible. + * + * For periodic IN endpoints, we have fifo_size and fifo_load to try + * and keep track of the amount of data in the periodic FIFO for each + * of these as we don't have a status register that tells us how much + * is in each of them. + */ +struct s3c_hsotg_ep { + struct usb_ep ep; + struct list_head queue; + struct s3c_hsotg *parent; + struct s3c_hsotg_req *req; + struct dentry *debugfs; + + spinlock_t lock; + + unsigned long total_data; + unsigned int size_loaded; + unsigned int last_load; + unsigned int fifo_load; + unsigned short fifo_size; + + unsigned char dir_in; + unsigned char index; + + unsigned int halted:1; + unsigned int periodic:1; + unsigned int sent_zlp:1; + + char name[10]; +}; + +#define S3C_HSOTG_EPS (8+1) /* limit to 9 for the moment */ + +/** + * struct s3c_hsotg - driver state. + * @dev: The parent device supplied to the probe function + * @driver: USB gadget driver + * @plat: The platform specific configuration data. + * @regs: The memory area mapped for accessing registers. + * @regs_res: The resource that was allocated when claiming register space. + * @irq: The IRQ number we are using + * @debug_root: root directrory for debugfs. + * @debug_file: main status file for debugfs. + * @debug_fifo: FIFO status file for debugfs. + * @ep0_reply: Request used for ep0 reply. + * @ep0_buff: Buffer for EP0 reply data, if needed. + * @ctrl_buff: Buffer for EP0 control requests. + * @ctrl_req: Request for EP0 control packets. + * @eps: The endpoints being supplied to the gadget framework + */ +struct s3c_hsotg { + struct device *dev; + struct usb_gadget_driver *driver; + struct s3c_hsotg_plat *plat; + + void __iomem *regs; + struct resource *regs_res; + int irq; + + struct dentry *debug_root; + struct dentry *debug_file; + struct dentry *debug_fifo; + + struct usb_request *ep0_reply; + struct usb_request *ctrl_req; + u8 ep0_buff[8]; + u8 ctrl_buff[8]; + + struct usb_gadget gadget; + struct s3c_hsotg_ep eps[]; +}; + +/** + * struct s3c_hsotg_req - data transfer request + * @req: The USB gadget request + * @queue: The list of requests for the endpoint this is queued for. + * @in_progress: Has already had size/packets written to core + * @mapped: DMA buffer for this request has been mapped via dma_map_single(). + */ +struct s3c_hsotg_req { + struct usb_request req; + struct list_head queue; + unsigned char in_progress; + unsigned char mapped; +}; + +/* conversion functions */ +static inline struct s3c_hsotg_req *our_req(struct usb_request *req) +{ + return container_of(req, struct s3c_hsotg_req, req); +} + +static inline struct s3c_hsotg_ep *our_ep(struct usb_ep *ep) +{ + return container_of(ep, struct s3c_hsotg_ep, ep); +} + +static inline struct s3c_hsotg *to_hsotg(struct usb_gadget *gadget) +{ + return container_of(gadget, struct s3c_hsotg, gadget); +} + +static inline void __orr32(void __iomem *ptr, u32 val) +{ + writel(readl(ptr) | val, ptr); +} + +static inline void __bic32(void __iomem *ptr, u32 val) +{ + writel(readl(ptr) & ~val, ptr); +} + +/* forward decleration of functions */ +static void s3c_hsotg_dump(struct s3c_hsotg *hsotg); + +/** + * using_dma - return the DMA status of the driver. + * @hsotg: The driver state. + * + * Return true if we're using DMA. + * + * Currently, we have the DMA support code worked into everywhere + * that needs it, but the AMBA DMA implementation in the hardware can + * only DMA from 32bit aligned addresses. This means that gadgets such + * as the CDC Ethernet cannot work as they often pass packets which are + * not 32bit aligned. + * + * Unfortunately the choice to use DMA or not is global to the controller + * and seems to be only settable when the controller is being put through + * a core reset. This means we either need to fix the gadgets to take + * account of DMA alignment, or add bounce buffers (yuerk). + * + * Until this issue is sorted out, we always return 'false'. + */ +static inline bool using_dma(struct s3c_hsotg *hsotg) +{ + return false; /* support is not complete */ +} + +/** + * s3c_hsotg_en_gsint - enable one or more of the general interrupt + * @hsotg: The device state + * @ints: A bitmask of the interrupts to enable + */ +static void s3c_hsotg_en_gsint(struct s3c_hsotg *hsotg, u32 ints) +{ + u32 gsintmsk = readl(hsotg->regs + S3C_GINTMSK); + u32 new_gsintmsk; + + new_gsintmsk = gsintmsk | ints; + + if (new_gsintmsk != gsintmsk) { + dev_dbg(hsotg->dev, "gsintmsk now 0x%08x\n", new_gsintmsk); + writel(new_gsintmsk, hsotg->regs + S3C_GINTMSK); + } +} + +/** + * s3c_hsotg_disable_gsint - disable one or more of the general interrupt + * @hsotg: The device state + * @ints: A bitmask of the interrupts to enable + */ +static void s3c_hsotg_disable_gsint(struct s3c_hsotg *hsotg, u32 ints) +{ + u32 gsintmsk = readl(hsotg->regs + S3C_GINTMSK); + u32 new_gsintmsk; + + new_gsintmsk = gsintmsk & ~ints; + + if (new_gsintmsk != gsintmsk) + writel(new_gsintmsk, hsotg->regs + S3C_GINTMSK); +} + +/** + * s3c_hsotg_ctrl_epint - enable/disable an endpoint irq + * @hsotg: The device state + * @ep: The endpoint index + * @dir_in: True if direction is in. + * @en: The enable value, true to enable + * + * Set or clear the mask for an individual endpoint's interrupt + * request. + */ +static void s3c_hsotg_ctrl_epint(struct s3c_hsotg *hsotg, + unsigned int ep, unsigned int dir_in, + unsigned int en) +{ + unsigned long flags; + u32 bit = 1 << ep; + u32 daint; + + if (!dir_in) + bit <<= 16; + + local_irq_save(flags); + daint = readl(hsotg->regs + S3C_DAINTMSK); + if (en) + daint |= bit; + else + daint &= ~bit; + writel(daint, hsotg->regs + S3C_DAINTMSK); + local_irq_restore(flags); +} + +/** + * s3c_hsotg_init_fifo - initialise non-periodic FIFOs + * @hsotg: The device instance. + */ +static void s3c_hsotg_init_fifo(struct s3c_hsotg *hsotg) +{ + /* the ryu 2.6.24 release ahs + writel(0x1C0, hsotg->regs + S3C_GRXFSIZ); + writel(S3C_GNPTXFSIZ_NPTxFStAddr(0x200) | + S3C_GNPTXFSIZ_NPTxFDep(0x1C0), + hsotg->regs + S3C_GNPTXFSIZ); + */ + + /* set FIFO sizes to 2048/0x1C0 */ + + writel(2048, hsotg->regs + S3C_GRXFSIZ); + writel(S3C_GNPTXFSIZ_NPTxFStAddr(2048) | + S3C_GNPTXFSIZ_NPTxFDep(0x1C0), + hsotg->regs + S3C_GNPTXFSIZ); +} + +/** + * @ep: USB endpoint to allocate request for. + * @flags: Allocation flags + * + * Allocate a new USB request structure appropriate for the specified endpoint + */ +struct usb_request *s3c_hsotg_ep_alloc_request(struct usb_ep *ep, gfp_t flags) +{ + struct s3c_hsotg_req *req; + + req = kzalloc(sizeof(struct s3c_hsotg_req), flags); + if (!req) + return NULL; + + INIT_LIST_HEAD(&req->queue); + + req->req.dma = DMA_ADDR_INVALID; + return &req->req; +} + +/** + * is_ep_periodic - return true if the endpoint is in periodic mode. + * @hs_ep: The endpoint to query. + * + * Returns true if the endpoint is in periodic mode, meaning it is being + * used for an Interrupt or ISO transfer. + */ +static inline int is_ep_periodic(struct s3c_hsotg_ep *hs_ep) +{ + return hs_ep->periodic; +} + +/** + * s3c_hsotg_unmap_dma - unmap the DMA memory being used for the request + * @hsotg: The device state. + * @hs_ep: The endpoint for the request + * @hs_req: The request being processed. + * + * This is the reverse of s3c_hsotg_map_dma(), called for the completion + * of a request to ensure the buffer is ready for access by the caller. +*/ +static void s3c_hsotg_unmap_dma(struct s3c_hsotg *hsotg, + struct s3c_hsotg_ep *hs_ep, + struct s3c_hsotg_req *hs_req) +{ + struct usb_request *req = &hs_req->req; + enum dma_data_direction dir; + + dir = hs_ep->dir_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE; + + /* ignore this if we're not moving any data */ + if (hs_req->req.length == 0) + return; + + if (hs_req->mapped) { + /* we mapped this, so unmap and remove the dma */ + + dma_unmap_single(hsotg->dev, req->dma, req->length, dir); + + req->dma = DMA_ADDR_INVALID; + hs_req->mapped = 0; + } else { + dma_sync_single(hsotg->dev, req->dma, req->length, dir); + } +} + +/** + * s3c_hsotg_write_fifo - write packet Data to the TxFIFO + * @hsotg: The controller state. + * @hs_ep: The endpoint we're going to write for. + * @hs_req: The request to write data for. + * + * This is called when the TxFIFO has some space in it to hold a new + * transmission and we have something to give it. The actual setup of + * the data size is done elsewhere, so all we have to do is to actually + * write the data. + * + * The return value is zero if there is more space (or nothing was done) + * otherwise -ENOSPC is returned if the FIFO space was used up. + * + * This routine is only needed for PIO +*/ +static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg, + struct s3c_hsotg_ep *hs_ep, + struct s3c_hsotg_req *hs_req) +{ + bool periodic = is_ep_periodic(hs_ep); + u32 gnptxsts = readl(hsotg->regs + S3C_GNPTXSTS); + int buf_pos = hs_req->req.actual; + int to_write = hs_ep->size_loaded; + void *data; + int can_write; + int pkt_round; + + to_write -= (buf_pos - hs_ep->last_load); + + /* if there's nothing to write, get out early */ + if (to_write == 0) + return 0; + + if (periodic) { + u32 epsize = readl(hsotg->regs + S3C_DIEPTSIZ(hs_ep->index)); + int size_left; + int size_done; + + /* work out how much data was loaded so we can calculate + * how much data is left in the fifo. */ + + size_left = S3C_DxEPTSIZ_XferSize_GET(epsize); + + dev_dbg(hsotg->dev, "%s: left=%d, load=%d, fifo=%d, size %d\n", + __func__, size_left, + hs_ep->size_loaded, hs_ep->fifo_load, hs_ep->fifo_size); + + /* how much of the data has moved */ + size_done = hs_ep->size_loaded - size_left; + + /* how much data is left in the fifo */ + can_write = hs_ep->fifo_load - size_done; + dev_dbg(hsotg->dev, "%s: => can_write1=%d\n", + __func__, can_write); + + can_write = hs_ep->fifo_size - can_write; + dev_dbg(hsotg->dev, "%s: => can_write2=%d\n", + __func__, can_write); + + if (can_write <= 0) { + s3c_hsotg_en_gsint(hsotg, S3C_GINTSTS_PTxFEmp); + return -ENOSPC; + } + } else { + if (S3C_GNPTXSTS_NPTxQSpcAvail_GET(gnptxsts) == 0) { + dev_dbg(hsotg->dev, + "%s: no queue slots available (0x%08x)\n", + __func__, gnptxsts); + + s3c_hsotg_en_gsint(hsotg, S3C_GINTSTS_NPTxFEmp); + return -ENOSPC; + } + + can_write = S3C_GNPTXSTS_NPTxFSpcAvail_GET(gnptxsts); + } + + dev_dbg(hsotg->dev, "%s: GNPTXSTS=%08x, can=%d, to=%d, mps %d\n", + __func__, gnptxsts, can_write, to_write, hs_ep->ep.maxpacket); + + /* limit to 512 bytes of data, it seems at least on the non-periodic + * FIFO, requests of >512 cause the endpoint to get stuck with a + * fragment of the end of the transfer in it. + */ + if (can_write > 512) + can_write = 512; + + /* see if we can write data */ + + if (to_write > can_write) { + to_write = can_write; + pkt_round = to_write % hs_ep->ep.maxpacket; + + /* Not sure, but we probably shouldn't be writing partial + * packets into the FIFO, so round the write down to an + * exact number of packets. + * + * Note, we do not currently check to see if we can ever + * write a full packet or not to the FIFO. + */ + + if (pkt_round) + to_write -= pkt_round; + + /* enable correct FIFO interrupt to alert us when there + * is more room left. */ + + s3c_hsotg_en_gsint(hsotg, + periodic ? S3C_GINTSTS_PTxFEmp : + S3C_GINTSTS_NPTxFEmp); + } + + dev_dbg(hsotg->dev, "write %d/%d, can_write %d, done %d\n", + to_write, hs_req->req.length, can_write, buf_pos); + + if (to_write <= 0) + return -ENOSPC; + + hs_req->req.actual = buf_pos + to_write; + hs_ep->total_data += to_write; + + if (periodic) + hs_ep->fifo_load += to_write; + + to_write = DIV_ROUND_UP(to_write, 4); + data = hs_req->req.buf + buf_pos; + + writesl(hsotg->regs + S3C_EPFIFO(hs_ep->index), data, to_write); + + return (to_write >= can_write) ? -ENOSPC : 0; +} + +/** + * get_ep_limit - get the maximum data legnth for this endpoint + * @hs_ep: The endpoint + * + * Return the maximum data that can be queued in one go on a given endpoint + * so that transfers that are too long can be split. + */ +static unsigned get_ep_limit(struct s3c_hsotg_ep *hs_ep) +{ + int index = hs_ep->index; + unsigned maxsize; + unsigned maxpkt; + + if (index != 0) { + maxsize = S3C_DxEPTSIZ_XferSize_LIMIT + 1; + maxpkt = S3C_DxEPTSIZ_PktCnt_LIMIT + 1; + } else { + if (hs_ep->dir_in) { + /* maxsize = S3C_DIEPTSIZ0_XferSize_LIMIT + 1; */ + maxsize = 64+64+1; + maxpkt = S3C_DIEPTSIZ0_PktCnt_LIMIT + 1; + } else { + maxsize = 0x3f; + maxpkt = 2; + } + } + + /* we made the constant loading easier above by using +1 */ + maxpkt--; + maxsize--; + + /* constrain by packet count if maxpkts*pktsize is greater + * than the length register size. */ + + if ((maxpkt * hs_ep->ep.maxpacket) < maxsize) + maxsize = maxpkt * hs_ep->ep.maxpacket; + + return maxsize; +} + +/** + * s3c_hsotg_start_req - start a USB request from an endpoint's queue + * @hsotg: The controller state. + * @hs_ep: The endpoint to process a request for + * @hs_req: The request to start. + * @continuing: True if we are doing more for the current request. + * + * Start the given request running by setting the endpoint registers + * appropriately, and writing any data to the FIFOs. + */ +static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg, + struct s3c_hsotg_ep *hs_ep, + struct s3c_hsotg_req *hs_req, + bool continuing) +{ + struct usb_request *ureq = &hs_req->req; + int index = hs_ep->index; + int dir_in = hs_ep->dir_in; + u32 epctrl_reg; + u32 epsize_reg; + u32 epsize; + u32 ctrl; + unsigned length; + unsigned packets; + unsigned maxreq; + + if (index != 0) { + if (hs_ep->req && !continuing) { + dev_err(hsotg->dev, "%s: active request\n", __func__); + WARN_ON(1); + return; + } else if (hs_ep->req != hs_req && continuing) { + dev_err(hsotg->dev, + "%s: continue different req\n", __func__); + WARN_ON(1); + return; + } + } + + epctrl_reg = dir_in ? S3C_DIEPCTL(index) : S3C_DOEPCTL(index); + epsize_reg = dir_in ? S3C_DIEPTSIZ(index) : S3C_DOEPTSIZ(index); + + dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x, ep %d, dir %s\n", + __func__, readl(hsotg->regs + epctrl_reg), index, + hs_ep->dir_in ? "in" : "out"); + + length = ureq->length - ureq->actual; + + if (0) + dev_dbg(hsotg->dev, + "REQ buf %p len %d dma 0x%08x noi=%d zp=%d snok=%d\n", + ureq->buf, length, ureq->dma, + ureq->no_interrupt, ureq->zero, ureq->short_not_ok); + + maxreq = get_ep_limit(hs_ep); + if (length > maxreq) { + int round = maxreq % hs_ep->ep.maxpacket; + + dev_dbg(hsotg->dev, "%s: length %d, max-req %d, r %d\n", + __func__, length, maxreq, round); + + /* round down to multiple of packets */ + if (round) + maxreq -= round; + + length = maxreq; + } + + if (length) + packets = DIV_ROUND_UP(length, hs_ep->ep.maxpacket); + else + packets = 1; /* send one packet if length is zero. */ + + if (dir_in && index != 0) + epsize = S3C_DxEPTSIZ_MC(1); + else + epsize = 0; + + if (index != 0 && ureq->zero) { + /* test for the packets being exactly right for the + * transfer */ + + if (length == (packets * hs_ep->ep.maxpacket)) + packets++; + } + + epsize |= S3C_DxEPTSIZ_PktCnt(packets); + epsize |= S3C_DxEPTSIZ_XferSize(length); + + dev_dbg(hsotg->dev, "%s: %d@%d/%d, 0x%08x => 0x%08x\n", + __func__, packets, length, ureq->length, epsize, epsize_reg); + + /* store the request as the current one we're doing */ + hs_ep->req = hs_req; + + /* write size / packets */ + writel(epsize, hsotg->regs + epsize_reg); + + ctrl = readl(hsotg->regs + epctrl_reg); + + if (ctrl & S3C_DxEPCTL_Stall) { + dev_warn(hsotg->dev, "%s: ep%d is stalled\n", __func__, index); + + /* not sure what we can do here, if it is EP0 then we should + * get this cleared once the endpoint has transmitted the + * STALL packet, otherwise it needs to be cleared by the + * host. + */ + } + + if (using_dma(hsotg)) { + unsigned int dma_reg; + + /* write DMA address to control register, buffer already + * synced by s3c_hsotg_ep_queue(). */ + + dma_reg = dir_in ? S3C_DIEPDMA(index) : S3C_DOEPDMA(index); + writel(ureq->dma, hsotg->regs + dma_reg); + + dev_dbg(hsotg->dev, "%s: 0x%08x => 0x%08x\n", + __func__, ureq->dma, dma_reg); + } + + ctrl |= S3C_DxEPCTL_EPEna; /* ensure ep enabled */ + ctrl |= S3C_DxEPCTL_USBActEp; + ctrl |= S3C_DxEPCTL_CNAK; /* clear NAK set by core */ + + dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", __func__, ctrl); + writel(ctrl, hsotg->regs + epctrl_reg); + + /* set these, it seems that DMA support increments past the end + * of the packet buffer so we need to calculate the length from + * this information. */ + hs_ep->size_loaded = length; + hs_ep->last_load = ureq->actual; + + if (dir_in && !using_dma(hsotg)) { + /* set these anyway, we may need them for non-periodic in */ + hs_ep->fifo_load = 0; + + s3c_hsotg_write_fifo(hsotg, hs_ep, hs_req); + } + + /* clear the INTknTXFEmpMsk when we start request, more as a aide + * to debugging to see what is going on. */ + if (dir_in) + writel(S3C_DIEPMSK_INTknTXFEmpMsk, + hsotg->regs + S3C_DIEPINT(index)); + + /* Note, trying to clear the NAK here causes problems with transmit + * on the S3C6400 ending up with the TXFIFO becomming full. */ + + /* check ep is enabled */ + if (!(readl(hsotg->regs + epctrl_reg) & S3C_DxEPCTL_EPEna)) + dev_warn(hsotg->dev, + "ep%d: failed to become enabled (DxEPCTL=0x%08x)?\n", + index, readl(hsotg->regs + epctrl_reg)); + + dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", + __func__, readl(hsotg->regs + epctrl_reg)); +} + +/** + * s3c_hsotg_map_dma - map the DMA memory being used for the request + * @hsotg: The device state. + * @hs_ep: The endpoint the request is on. + * @req: The request being processed. + * + * We've been asked to queue a request, so ensure that the memory buffer + * is correctly setup for DMA. If we've been passed an extant DMA address + * then ensure the buffer has been synced to memory. If our buffer has no + * DMA memory, then we map the memory and mark our request to allow us to + * cleanup on completion. +*/ +static int s3c_hsotg_map_dma(struct s3c_hsotg *hsotg, + struct s3c_hsotg_ep *hs_ep, + struct usb_request *req) +{ + enum dma_data_direction dir; + struct s3c_hsotg_req *hs_req = our_req(req); + + dir = hs_ep->dir_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE; + + /* if the length is zero, ignore the DMA data */ + if (hs_req->req.length == 0) + return 0; + + if (req->dma == DMA_ADDR_INVALID) { + dma_addr_t dma; + + dma = dma_map_single(hsotg->dev, req->buf, req->length, dir); + + if (unlikely(dma_mapping_error(hsotg->dev, dma))) + goto dma_error; + + if (dma & 3) { + dev_err(hsotg->dev, "%s: unaligned dma buffer\n", + __func__); + + dma_unmap_single(hsotg->dev, dma, req->length, dir); + return -EINVAL; + } + + hs_req->mapped = 1; + req->dma = dma; + } else { + dma_sync_single(hsotg->dev, req->dma, req->length, dir); + hs_req->mapped = 0; + } + + return 0; + +dma_error: + dev_err(hsotg->dev, "%s: failed to map buffer %p, %d bytes\n", + __func__, req->buf, req->length); + + return -EIO; +} + +static int s3c_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req, + gfp_t gfp_flags) +{ + struct s3c_hsotg_req *hs_req = our_req(req); + struct s3c_hsotg_ep *hs_ep = our_ep(ep); + struct s3c_hsotg *hs = hs_ep->parent; + unsigned long irqflags; + bool first; + + dev_dbg(hs->dev, "%s: req %p: %d@%p, noi=%d, zero=%d, snok=%d\n", + ep->name, req, req->length, req->buf, req->no_interrupt, + req->zero, req->short_not_ok); + + /* initialise status of the request */ + INIT_LIST_HEAD(&hs_req->queue); + req->actual = 0; + req->status = -EINPROGRESS; + + /* if we're using DMA, sync the buffers as necessary */ + if (using_dma(hs)) { + int ret = s3c_hsotg_map_dma(hs, hs_ep, req); + if (ret) + return ret; + } + + spin_lock_irqsave(&hs_ep->lock, irqflags); + + first = list_empty(&hs_ep->queue); + list_add_tail(&hs_req->queue, &hs_ep->queue); + + if (first) + s3c_hsotg_start_req(hs, hs_ep, hs_req, false); + + spin_unlock_irqrestore(&hs_ep->lock, irqflags); + + return 0; +} + +static void s3c_hsotg_ep_free_request(struct usb_ep *ep, + struct usb_request *req) +{ + struct s3c_hsotg_req *hs_req = our_req(req); + + kfree(hs_req); +} + +/** + * s3c_hsotg_complete_oursetup - setup completion callback + * @ep: The endpoint the request was on. + * @req: The request completed. + * + * Called on completion of any requests the driver itself + * submitted that need cleaning up. + */ +static void s3c_hsotg_complete_oursetup(struct usb_ep *ep, + struct usb_request *req) +{ + struct s3c_hsotg_ep *hs_ep = our_ep(ep); + struct s3c_hsotg *hsotg = hs_ep->parent; + + dev_dbg(hsotg->dev, "%s: ep %p, req %p\n", __func__, ep, req); + + s3c_hsotg_ep_free_request(ep, req); +} + +/** + * ep_from_windex - convert control wIndex value to endpoint + * @hsotg: The driver state. + * @windex: The control request wIndex field (in host order). + * + * Convert the given wIndex into a pointer to an driver endpoint + * structure, or return NULL if it is not a valid endpoint. +*/ +static struct s3c_hsotg_ep *ep_from_windex(struct s3c_hsotg *hsotg, + u32 windex) +{ + struct s3c_hsotg_ep *ep = &hsotg->eps[windex & 0x7F]; + int dir = (windex & USB_DIR_IN) ? 1 : 0; + int idx = windex & 0x7F; + + if (windex >= 0x100) + return NULL; + + if (idx > S3C_HSOTG_EPS) + return NULL; + + if (idx && ep->dir_in != dir) + return NULL; + + return ep; +} + +/** + * s3c_hsotg_send_reply - send reply to control request + * @hsotg: The device state + * @ep: Endpoint 0 + * @buff: Buffer for request + * @length: Length of reply. + * + * Create a request and queue it on the given endpoint. This is useful as + * an internal method of sending replies to certain control requests, etc. + */ +static int s3c_hsotg_send_reply(struct s3c_hsotg *hsotg, + struct s3c_hsotg_ep *ep, + void *buff, + int length) +{ + struct usb_request *req; + int ret; + + dev_dbg(hsotg->dev, "%s: buff %p, len %d\n", __func__, buff, length); + + req = s3c_hsotg_ep_alloc_request(&ep->ep, GFP_ATOMIC); + hsotg->ep0_reply = req; + if (!req) { + dev_warn(hsotg->dev, "%s: cannot alloc req\n", __func__); + return -ENOMEM; + } + + req->buf = hsotg->ep0_buff; + req->length = length; + req->zero = 1; /* always do zero-length final transfer */ + req->complete = s3c_hsotg_complete_oursetup; + + if (length) + memcpy(req->buf, buff, length); + else + ep->sent_zlp = 1; + + ret = s3c_hsotg_ep_queue(&ep->ep, req, GFP_ATOMIC); + if (ret) { + dev_warn(hsotg->dev, "%s: cannot queue req\n", __func__); + return ret; + } + + return 0; +} + +/** + * s3c_hsotg_process_req_status - process request GET_STATUS + * @hsotg: The device state + * @ctrl: USB control request + */ +static int s3c_hsotg_process_req_status(struct s3c_hsotg *hsotg, + struct usb_ctrlrequest *ctrl) +{ + struct s3c_hsotg_ep *ep0 = &hsotg->eps[0]; + struct s3c_hsotg_ep *ep; + __le16 reply; + int ret; + + dev_dbg(hsotg->dev, "%s: USB_REQ_GET_STATUS\n", __func__); + + if (!ep0->dir_in) { + dev_warn(hsotg->dev, "%s: direction out?\n", __func__); + return -EINVAL; + } + + switch (ctrl->bRequestType & USB_RECIP_MASK) { + case USB_RECIP_DEVICE: + reply = cpu_to_le16(0); /* bit 0 => self powered, + * bit 1 => remote wakeup */ + break; + + case USB_RECIP_INTERFACE: + /* currently, the data result should be zero */ + reply = cpu_to_le16(0); + break; + + case USB_RECIP_ENDPOINT: + ep = ep_from_windex(hsotg, le16_to_cpu(ctrl->wIndex)); + if (!ep) + return -ENOENT; + + reply = cpu_to_le16(ep->halted ? 1 : 0); + break; + + default: + return 0; + } + + if (le16_to_cpu(ctrl->wLength) != 2) + return -EINVAL; + + ret = s3c_hsotg_send_reply(hsotg, ep0, &reply, 2); + if (ret) { + dev_err(hsotg->dev, "%s: failed to send reply\n", __func__); + return ret; + } + + return 1; +} + +static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value); + +/** + * s3c_hsotg_process_req_featire - process request {SET,CLEAR}_FEATURE + * @hsotg: The device state + * @ctrl: USB control request + */ +static int s3c_hsotg_process_req_feature(struct s3c_hsotg *hsotg, + struct usb_ctrlrequest *ctrl) +{ + bool set = (ctrl->bRequest == USB_REQ_SET_FEATURE); + struct s3c_hsotg_ep *ep; + + dev_dbg(hsotg->dev, "%s: %s_FEATURE\n", + __func__, set ? "SET" : "CLEAR"); + + if (ctrl->bRequestType == USB_RECIP_ENDPOINT) { + ep = ep_from_windex(hsotg, le16_to_cpu(ctrl->wIndex)); + if (!ep) { + dev_dbg(hsotg->dev, "%s: no endpoint for 0x%04x\n", + __func__, le16_to_cpu(ctrl->wIndex)); + return -ENOENT; + } + + switch (le16_to_cpu(ctrl->wValue)) { + case USB_ENDPOINT_HALT: + s3c_hsotg_ep_sethalt(&ep->ep, set); + break; + + default: + return -ENOENT; + } + } else + return -ENOENT; /* currently only deal with endpoint */ + + return 1; +} + +/** + * s3c_hsotg_process_control - process a control request + * @hsotg: The device state + * @ctrl: The control request received + * + * The controller has received the SETUP phase of a control request, and + * needs to work out what to do next (and whether to pass it on to the + * gadget driver). + */ +static void s3c_hsotg_process_control(struct s3c_hsotg *hsotg, + struct usb_ctrlrequest *ctrl) +{ + struct s3c_hsotg_ep *ep0 = &hsotg->eps[0]; + int ret = 0; + u32 dcfg; + + ep0->sent_zlp = 0; + + dev_dbg(hsotg->dev, "ctrl Req=%02x, Type=%02x, V=%04x, L=%04x\n", + ctrl->bRequest, ctrl->bRequestType, + ctrl->wValue, ctrl->wLength); + + /* record the direction of the request, for later use when enquing + * packets onto EP0. */ + + ep0->dir_in = (ctrl->bRequestType & USB_DIR_IN) ? 1 : 0; + dev_dbg(hsotg->dev, "ctrl: dir_in=%d\n", ep0->dir_in); + + /* if we've no data with this request, then the last part of the + * transaction is going to implicitly be IN. */ + if (ctrl->wLength == 0) + ep0->dir_in = 1; + + if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { + switch (ctrl->bRequest) { + case USB_REQ_SET_ADDRESS: + dcfg = readl(hsotg->regs + S3C_DCFG); + dcfg &= ~S3C_DCFG_DevAddr_MASK; + dcfg |= ctrl->wValue << S3C_DCFG_DevAddr_SHIFT; + writel(dcfg, hsotg->regs + S3C_DCFG); + + dev_info(hsotg->dev, "new address %d\n", ctrl->wValue); + + ret = s3c_hsotg_send_reply(hsotg, ep0, NULL, 0); + return; + + case USB_REQ_GET_STATUS: + ret = s3c_hsotg_process_req_status(hsotg, ctrl); + break; + + case USB_REQ_CLEAR_FEATURE: + case USB_REQ_SET_FEATURE: + ret = s3c_hsotg_process_req_feature(hsotg, ctrl); + break; + } + } + + /* as a fallback, try delivering it to the driver to deal with */ + + if (ret == 0 && hsotg->driver) { + ret = hsotg->driver->setup(&hsotg->gadget, ctrl); + if (ret < 0) + dev_dbg(hsotg->dev, "driver->setup() ret %d\n", ret); + } + + if (ret > 0) { + if (!ep0->dir_in) { + /* need to generate zlp in reply or take data */ + /* todo - deal with any data we might be sent? */ + ret = s3c_hsotg_send_reply(hsotg, ep0, NULL, 0); + } + } + + /* the request is either unhandlable, or is not formatted correctly + * so respond with a STALL for the status stage to indicate failure. + */ + + if (ret < 0) { + u32 reg; + u32 ctrl; + + dev_dbg(hsotg->dev, "ep0 stall (dir=%d)\n", ep0->dir_in); + reg = (ep0->dir_in) ? S3C_DIEPCTL0 : S3C_DOEPCTL0; + + /* S3C_DxEPCTL_Stall will be cleared by EP once it has + * taken effect, so no need to clear later. */ + + ctrl = readl(hsotg->regs + reg); + ctrl |= S3C_DxEPCTL_Stall; + ctrl |= S3C_DxEPCTL_CNAK; + writel(ctrl, hsotg->regs + reg); + + dev_dbg(hsotg->dev, + "writen DxEPCTL=0x%08x to %08x (DxEPCTL=0x%08x)\n", + ctrl, reg, readl(hsotg->regs + reg)); + + /* don't belive we need to anything more to get the EP + * to reply with a STALL packet */ + } +} + +static void s3c_hsotg_enqueue_setup(struct s3c_hsotg *hsotg); + +/** + * s3c_hsotg_complete_setup - completion of a setup transfer + * @ep: The endpoint the request was on. + * @req: The request completed. + * + * Called on completion of any requests the driver itself submitted for + * EP0 setup packets + */ +static void s3c_hsotg_complete_setup(struct usb_ep *ep, + struct usb_request *req) +{ + struct s3c_hsotg_ep *hs_ep = our_ep(ep); + struct s3c_hsotg *hsotg = hs_ep->parent; + + if (req->status < 0) { + dev_dbg(hsotg->dev, "%s: failed %d\n", __func__, req->status); + return; + } + + if (req->actual == 0) + s3c_hsotg_enqueue_setup(hsotg); + else + s3c_hsotg_process_control(hsotg, req->buf); +} + +/** + * s3c_hsotg_enqueue_setup - start a request for EP0 packets + * @hsotg: The device state. + * + * Enqueue a request on EP0 if necessary to received any SETUP packets + * received from the host. + */ +static void s3c_hsotg_enqueue_setup(struct s3c_hsotg *hsotg) +{ + struct usb_request *req = hsotg->ctrl_req; + struct s3c_hsotg_req *hs_req = our_req(req); + int ret; + + dev_dbg(hsotg->dev, "%s: queueing setup request\n", __func__); + + req->zero = 0; + req->length = 8; + req->buf = hsotg->ctrl_buff; + req->complete = s3c_hsotg_complete_setup; + + if (!list_empty(&hs_req->queue)) { + dev_dbg(hsotg->dev, "%s already queued???\n", __func__); + return; + } + + hsotg->eps[0].dir_in = 0; + + ret = s3c_hsotg_ep_queue(&hsotg->eps[0].ep, req, GFP_ATOMIC); + if (ret < 0) { + dev_err(hsotg->dev, "%s: failed queue (%d)\n", __func__, ret); + /* Don't think there's much we can do other than watch the + * driver fail. */ + } +} + +/** + * get_ep_head - return the first request on the endpoint + * @hs_ep: The controller endpoint to get + * + * Get the first request on the endpoint. +*/ +static struct s3c_hsotg_req *get_ep_head(struct s3c_hsotg_ep *hs_ep) +{ + if (list_empty(&hs_ep->queue)) + return NULL; + + return list_first_entry(&hs_ep->queue, struct s3c_hsotg_req, queue); +} + +/** + * s3c_hsotg_complete_request - complete a request given to us + * @hsotg: The device state. + * @hs_ep: The endpoint the request was on. + * @hs_req: The request to complete. + * @result: The result code (0 => Ok, otherwise errno) + * + * The given request has finished, so call the necessary completion + * if it has one and then look to see if we can start a new request + * on the endpoint. + * + * Note, expects the ep to already be locked as appropriate. +*/ +static void s3c_hsotg_complete_request(struct s3c_hsotg *hsotg, + struct s3c_hsotg_ep *hs_ep, + struct s3c_hsotg_req *hs_req, + int result) +{ + bool restart; + + if (!hs_req) { + dev_dbg(hsotg->dev, "%s: nothing to complete?\n", __func__); + return; + } + + dev_dbg(hsotg->dev, "complete: ep %p %s, req %p, %d => %p\n", + hs_ep, hs_ep->ep.name, hs_req, result, hs_req->req.complete); + + /* only replace the status if we've not already set an error + * from a previous transaction */ + + if (hs_req->req.status == -EINPROGRESS) + hs_req->req.status = result; + + hs_ep->req = NULL; + list_del_init(&hs_req->queue); + + if (using_dma(hsotg)) + s3c_hsotg_unmap_dma(hsotg, hs_ep, hs_req); + + /* call the complete request with the locks off, just in case the + * request tries to queue more work for this endpoint. */ + + if (hs_req->req.complete) { + spin_unlock(&hs_ep->lock); + hs_req->req.complete(&hs_ep->ep, &hs_req->req); + spin_lock(&hs_ep->lock); + } + + /* Look to see if there is anything else to do. Note, the completion + * of the previous request may have caused a new request to be started + * so be careful when doing this. */ + + if (!hs_ep->req && result >= 0) { + restart = !list_empty(&hs_ep->queue); + if (restart) { + hs_req = get_ep_head(hs_ep); + s3c_hsotg_start_req(hsotg, hs_ep, hs_req, false); + } + } +} + +/** + * s3c_hsotg_complete_request_lock - complete a request given to us (locked) + * @hsotg: The device state. + * @hs_ep: The endpoint the request was on. + * @hs_req: The request to complete. + * @result: The result code (0 => Ok, otherwise errno) + * + * See s3c_hsotg_complete_request(), but called with the endpoint's + * lock held. +*/ +static void s3c_hsotg_complete_request_lock(struct s3c_hsotg *hsotg, + struct s3c_hsotg_ep *hs_ep, + struct s3c_hsotg_req *hs_req, + int result) +{ + unsigned long flags; + + spin_lock_irqsave(&hs_ep->lock, flags); + s3c_hsotg_complete_request(hsotg, hs_ep, hs_req, result); + spin_unlock_irqrestore(&hs_ep->lock, flags); +} + +/** + * s3c_hsotg_rx_data - receive data from the FIFO for an endpoint + * @hsotg: The device state. + * @ep_idx: The endpoint index for the data + * @size: The size of data in the fifo, in bytes + * + * The FIFO status shows there is data to read from the FIFO for a given + * endpoint, so sort out whether we need to read the data into a request + * that has been made for that endpoint. + */ +static void s3c_hsotg_rx_data(struct s3c_hsotg *hsotg, int ep_idx, int size) +{ + struct s3c_hsotg_ep *hs_ep = &hsotg->eps[ep_idx]; + struct s3c_hsotg_req *hs_req = hs_ep->req; + void __iomem *fifo = hsotg->regs + S3C_EPFIFO(ep_idx); + int to_read; + int max_req; + int read_ptr; + + if (!hs_req) { + u32 epctl = readl(hsotg->regs + S3C_DOEPCTL(ep_idx)); + int ptr; + + dev_warn(hsotg->dev, + "%s: FIFO %d bytes on ep%d but no req (DxEPCTl=0x%08x)\n", + __func__, size, ep_idx, epctl); + + /* dump the data from the FIFO, we've nothing we can do */ + for (ptr = 0; ptr < size; ptr += 4) + (void)readl(fifo); + + return; + } + + spin_lock(&hs_ep->lock); + + to_read = size; + read_ptr = hs_req->req.actual; + max_req = hs_req->req.length - read_ptr; + + if (to_read > max_req) { + /* more data appeared than we where willing + * to deal with in this request. + */ + + /* currently we don't deal this */ + WARN_ON_ONCE(1); + } + + dev_dbg(hsotg->dev, "%s: read %d/%d, done %d/%d\n", + __func__, to_read, max_req, read_ptr, hs_req->req.length); + + hs_ep->total_data += to_read; + hs_req->req.actual += to_read; + to_read = DIV_ROUND_UP(to_read, 4); + + /* note, we might over-write the buffer end by 3 bytes depending on + * alignment of the data. */ + readsl(fifo, hs_req->req.buf + read_ptr, to_read); + + spin_unlock(&hs_ep->lock); +} + +/** + * s3c_hsotg_send_zlp - send zero-length packet on control endpoint + * @hsotg: The device instance + * @req: The request currently on this endpoint + * + * Generate a zero-length IN packet request for terminating a SETUP + * transaction. + * + * Note, since we don't write any data to the TxFIFO, then it is + * currently belived that we do not need to wait for any space in + * the TxFIFO. + */ +static void s3c_hsotg_send_zlp(struct s3c_hsotg *hsotg, + struct s3c_hsotg_req *req) +{ + u32 ctrl; + + if (!req) { + dev_warn(hsotg->dev, "%s: no request?\n", __func__); + return; + } + + if (req->req.length == 0) { + hsotg->eps[0].sent_zlp = 1; + s3c_hsotg_enqueue_setup(hsotg); + return; + } + + hsotg->eps[0].dir_in = 1; + hsotg->eps[0].sent_zlp = 1; + + dev_dbg(hsotg->dev, "sending zero-length packet\n"); + + /* issue a zero-sized packet to terminate this */ + writel(S3C_DxEPTSIZ_MC(1) | S3C_DxEPTSIZ_PktCnt(1) | + S3C_DxEPTSIZ_XferSize(0), hsotg->regs + S3C_DIEPTSIZ(0)); + + ctrl = readl(hsotg->regs + S3C_DIEPCTL0); + ctrl |= S3C_DxEPCTL_CNAK; /* clear NAK set by core */ + ctrl |= S3C_DxEPCTL_EPEna; /* ensure ep enabled */ + ctrl |= S3C_DxEPCTL_USBActEp; + writel(ctrl, hsotg->regs + S3C_DIEPCTL0); +} + +/** + * s3c_hsotg_handle_outdone - handle receiving OutDone/SetupDone from RXFIFO + * @hsotg: The device instance + * @epnum: The endpoint received from + * @was_setup: Set if processing a SetupDone event. + * + * The RXFIFO has delivered an OutDone event, which means that the data + * transfer for an OUT endpoint has been completed, either by a short + * packet or by the finish of a transfer. +*/ +static void s3c_hsotg_handle_outdone(struct s3c_hsotg *hsotg, + int epnum, bool was_setup) +{ + struct s3c_hsotg_ep *hs_ep = &hsotg->eps[epnum]; + struct s3c_hsotg_req *hs_req = hs_ep->req; + struct usb_request *req = &hs_req->req; + int result = 0; + + if (!hs_req) { + dev_dbg(hsotg->dev, "%s: no request active\n", __func__); + return; + } + + if (using_dma(hsotg)) { + u32 epsize = readl(hsotg->regs + S3C_DOEPTSIZ(epnum)); + unsigned size_done; + unsigned size_left; + + /* Calculate the size of the transfer by checking how much + * is left in the endpoint size register and then working it + * out from the amount we loaded for the transfer. + * + * We need to do this as DMA pointers are always 32bit aligned + * so may overshoot/undershoot the transfer. + */ + + size_left = S3C_DxEPTSIZ_XferSize_GET(epsize); + + size_done = hs_ep->size_loaded - size_left; + size_done += hs_ep->last_load; + + req->actual = size_done; + } + + if (req->actual < req->length && req->short_not_ok) { + dev_dbg(hsotg->dev, "%s: got %d/%d (short not ok) => error\n", + __func__, req->actual, req->length); + + /* todo - what should we return here? there's no one else + * even bothering to check the status. */ + } + + if (epnum == 0) { + if (!was_setup && req->complete != s3c_hsotg_complete_setup) + s3c_hsotg_send_zlp(hsotg, hs_req); + } + + s3c_hsotg_complete_request_lock(hsotg, hs_ep, hs_req, result); +} + +/** + * s3c_hsotg_read_frameno - read current frame number + * @hsotg: The device instance + * + * Return the current frame number +*/ +static u32 s3c_hsotg_read_frameno(struct s3c_hsotg *hsotg) +{ + u32 dsts; + + dsts = readl(hsotg->regs + S3C_DSTS); + dsts &= S3C_DSTS_SOFFN_MASK; + dsts >>= S3C_DSTS_SOFFN_SHIFT; + + return dsts; +} + +/** + * s3c_hsotg_handle_rx - RX FIFO has data + * @hsotg: The device instance + * + * The IRQ handler has detected that the RX FIFO has some data in it + * that requires processing, so find out what is in there and do the + * appropriate read. + * + * The RXFIFO is a true FIFO, the packets comming out are still in packet + * chunks, so if you have x packets received on an endpoint you'll get x + * FIFO events delivered, each with a packet's worth of data in it. + * + * When using DMA, we should not be processing events from the RXFIFO + * as the actual data should be sent to the memory directly and we turn + * on the completion interrupts to get notifications of transfer completion. + */ +void s3c_hsotg_handle_rx(struct s3c_hsotg *hsotg) +{ + u32 grxstsr = readl(hsotg->regs + S3C_GRXSTSP); + u32 epnum, status, size; + + WARN_ON(using_dma(hsotg)); + + epnum = grxstsr & S3C_GRXSTS_EPNum_MASK; + status = grxstsr & S3C_GRXSTS_PktSts_MASK; + + size = grxstsr & S3C_GRXSTS_ByteCnt_MASK; + size >>= S3C_GRXSTS_ByteCnt_SHIFT; + + if (1) + dev_dbg(hsotg->dev, "%s: GRXSTSP=0x%08x (%d@%d)\n", + __func__, grxstsr, size, epnum); + +#define __status(x) ((x) >> S3C_GRXSTS_PktSts_SHIFT) + + switch (status >> S3C_GRXSTS_PktSts_SHIFT) { + case __status(S3C_GRXSTS_PktSts_GlobalOutNAK): + dev_dbg(hsotg->dev, "GlobalOutNAK\n"); + break; + + case __status(S3C_GRXSTS_PktSts_OutDone): + dev_dbg(hsotg->dev, "OutDone (Frame=0x%08x)\n", + s3c_hsotg_read_frameno(hsotg)); + + if (!using_dma(hsotg)) + s3c_hsotg_handle_outdone(hsotg, epnum, false); + break; + + case __status(S3C_GRXSTS_PktSts_SetupDone): + dev_dbg(hsotg->dev, + "SetupDone (Frame=0x%08x, DOPEPCTL=0x%08x)\n", + s3c_hsotg_read_frameno(hsotg), + readl(hsotg->regs + S3C_DOEPCTL(0))); + + s3c_hsotg_handle_outdone(hsotg, epnum, true); + break; + + case __status(S3C_GRXSTS_PktSts_OutRX): + s3c_hsotg_rx_data(hsotg, epnum, size); + break; + + case __status(S3C_GRXSTS_PktSts_SetupRX): + dev_dbg(hsotg->dev, + "SetupRX (Frame=0x%08x, DOPEPCTL=0x%08x)\n", + s3c_hsotg_read_frameno(hsotg), + readl(hsotg->regs + S3C_DOEPCTL(0))); + + s3c_hsotg_rx_data(hsotg, epnum, size); + break; + + default: + dev_warn(hsotg->dev, "%s: unknown status %08x\n", + __func__, grxstsr); + + s3c_hsotg_dump(hsotg); + break; + } +} + +/** + * s3c_hsotg_ep0_mps - turn max packet size into register setting + * @mps: The maximum packet size in bytes. +*/ +static u32 s3c_hsotg_ep0_mps(unsigned int mps) +{ + switch (mps) { + case 64: + return S3C_D0EPCTL_MPS_64; + case 32: + return S3C_D0EPCTL_MPS_32; + case 16: + return S3C_D0EPCTL_MPS_16; + case 8: + return S3C_D0EPCTL_MPS_8; + } + + /* bad max packet size, warn and return invalid result */ + WARN_ON(1); + return (u32)-1; +} + +/** + * s3c_hsotg_set_ep_maxpacket - set endpoint's max-packet field + * @hsotg: The driver state. + * @ep: The index number of the endpoint + * @mps: The maximum packet size in bytes + * + * Configure the maximum packet size for the given endpoint, updating + * the hardware control registers to reflect this. + */ +static void s3c_hsotg_set_ep_maxpacket(struct s3c_hsotg *hsotg, + unsigned int ep, unsigned int mps) +{ + struct s3c_hsotg_ep *hs_ep = &hsotg->eps[ep]; + void __iomem *regs = hsotg->regs; + u32 mpsval; + u32 reg; + + if (ep == 0) { + /* EP0 is a special case */ + mpsval = s3c_hsotg_ep0_mps(mps); + if (mpsval > 3) + goto bad_mps; + } else { + if (mps >= S3C_DxEPCTL_MPS_LIMIT+1) + goto bad_mps; + + mpsval = mps; + } + + hs_ep->ep.maxpacket = mps; + + /* update both the in and out endpoint controldir_ registers, even + * if one of the directions may not be in use. */ + + reg = readl(regs + S3C_DIEPCTL(ep)); + reg &= ~S3C_DxEPCTL_MPS_MASK; + reg |= mpsval; + writel(reg, regs + S3C_DIEPCTL(ep)); + + reg = readl(regs + S3C_DOEPCTL(ep)); + reg &= ~S3C_DxEPCTL_MPS_MASK; + reg |= mpsval; + writel(reg, regs + S3C_DOEPCTL(ep)); + + return; + +bad_mps: + dev_err(hsotg->dev, "ep%d: bad mps of %d\n", ep, mps); +} + + +/** + * s3c_hsotg_trytx - check to see if anything needs transmitting + * @hsotg: The driver state + * @hs_ep: The driver endpoint to check. + * + * Check to see if there is a request that has data to send, and if so + * make an attempt to write data into the FIFO. + */ +static int s3c_hsotg_trytx(struct s3c_hsotg *hsotg, + struct s3c_hsotg_ep *hs_ep) +{ + struct s3c_hsotg_req *hs_req = hs_ep->req; + + if (!hs_ep->dir_in || !hs_req) + return 0; + + if (hs_req->req.actual < hs_req->req.length) { + dev_dbg(hsotg->dev, "trying to write more for ep%d\n", + hs_ep->index); + return s3c_hsotg_write_fifo(hsotg, hs_ep, hs_req); + } + + return 0; +} + +/** + * s3c_hsotg_complete_in - complete IN transfer + * @hsotg: The device state. + * @hs_ep: The endpoint that has just completed. + * + * An IN transfer has been completed, update the transfer's state and then + * call the relevant completion routines. + */ +static void s3c_hsotg_complete_in(struct s3c_hsotg *hsotg, + struct s3c_hsotg_ep *hs_ep) +{ + struct s3c_hsotg_req *hs_req = hs_ep->req; + u32 epsize = readl(hsotg->regs + S3C_DIEPTSIZ(hs_ep->index)); + int size_left, size_done; + + if (!hs_req) { + dev_dbg(hsotg->dev, "XferCompl but no req\n"); + return; + } + + /* Calculate the size of the transfer by checking how much is left + * in the endpoint size register and then working it out from + * the amount we loaded for the transfer. + * + * We do this even for DMA, as the transfer may have incremented + * past the end of the buffer (DMA transfers are always 32bit + * aligned). + */ + + size_left = S3C_DxEPTSIZ_XferSize_GET(epsize); + + size_done = hs_ep->size_loaded - size_left; + size_done += hs_ep->last_load; + + if (hs_req->req.actual != size_done) + dev_dbg(hsotg->dev, "%s: adjusting size done %d => %d\n", + __func__, hs_req->req.actual, size_done); + + hs_req->req.actual = size_done; + + /* if we did all of the transfer, and there is more data left + * around, then try restarting the rest of the request */ + + if (!size_left && hs_req->req.actual < hs_req->req.length) { + dev_dbg(hsotg->dev, "%s trying more for req...\n", __func__); + s3c_hsotg_start_req(hsotg, hs_ep, hs_req, true); + } else + s3c_hsotg_complete_request_lock(hsotg, hs_ep, hs_req, 0); +} + +/** + * s3c_hsotg_epint - handle an in/out endpoint interrupt + * @hsotg: The driver state + * @idx: The index for the endpoint (0..15) + * @dir_in: Set if this is an IN endpoint + * + * Process and clear any interrupt pending for an individual endpoint +*/ +static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx, + int dir_in) +{ + struct s3c_hsotg_ep *hs_ep = &hsotg->eps[idx]; + u32 epint_reg = dir_in ? S3C_DIEPINT(idx) : S3C_DOEPINT(idx); + u32 epctl_reg = dir_in ? S3C_DIEPCTL(idx) : S3C_DOEPCTL(idx); + u32 epsiz_reg = dir_in ? S3C_DIEPTSIZ(idx) : S3C_DOEPTSIZ(idx); + u32 ints; + u32 clear = 0; + + ints = readl(hsotg->regs + epint_reg); + + dev_dbg(hsotg->dev, "%s: ep%d(%s) DxEPINT=0x%08x\n", + __func__, idx, dir_in ? "in" : "out", ints); + + if (ints & S3C_DxEPINT_XferCompl) { + dev_dbg(hsotg->dev, + "%s: XferCompl: DxEPCTL=0x%08x, DxEPTSIZ=%08x\n", + __func__, readl(hsotg->regs + epctl_reg), + readl(hsotg->regs + epsiz_reg)); + + /* we get OutDone from the FIFO, so we only need to look + * at completing IN requests here */ + if (dir_in) { + s3c_hsotg_complete_in(hsotg, hs_ep); + + if (idx == 0) + s3c_hsotg_enqueue_setup(hsotg); + } else if (using_dma(hsotg)) { + /* We're using DMA, we need to fire an OutDone here + * as we ignore the RXFIFO. */ + + s3c_hsotg_handle_outdone(hsotg, idx, false); + } + + clear |= S3C_DxEPINT_XferCompl; + } + + if (ints & S3C_DxEPINT_EPDisbld) { + dev_dbg(hsotg->dev, "%s: EPDisbld\n", __func__); + clear |= S3C_DxEPINT_EPDisbld; + } + + if (ints & S3C_DxEPINT_AHBErr) { + dev_dbg(hsotg->dev, "%s: AHBErr\n", __func__); + clear |= S3C_DxEPINT_AHBErr; + } + + if (ints & S3C_DxEPINT_Setup) { /* Setup or Timeout */ + dev_dbg(hsotg->dev, "%s: Setup/Timeout\n", __func__); + + if (using_dma(hsotg) && idx == 0) { + /* this is the notification we've received a + * setup packet. In non-DMA mode we'd get this + * from the RXFIFO, instead we need to process + * the setup here. */ + + if (dir_in) + WARN_ON_ONCE(1); + else + s3c_hsotg_handle_outdone(hsotg, 0, true); + } + + clear |= S3C_DxEPINT_Setup; + } + + if (ints & S3C_DxEPINT_Back2BackSetup) { + dev_dbg(hsotg->dev, "%s: B2BSetup/INEPNakEff\n", __func__); + clear |= S3C_DxEPINT_Back2BackSetup; + } + + if (dir_in) { + /* not sure if this is important, but we'll clear it anyway + */ + if (ints & S3C_DIEPMSK_INTknTXFEmpMsk) { + dev_dbg(hsotg->dev, "%s: ep%d: INTknTXFEmpMsk\n", + __func__, idx); + clear |= S3C_DIEPMSK_INTknTXFEmpMsk; + } + + /* this probably means something bad is happening */ + if (ints & S3C_DIEPMSK_INTknEPMisMsk) { + dev_warn(hsotg->dev, "%s: ep%d: INTknEP\n", + __func__, idx); + clear |= S3C_DIEPMSK_INTknEPMisMsk; + } + } + + writel(clear, hsotg->regs + epint_reg); +} + +/** + * s3c_hsotg_irq_enumdone - Handle EnumDone interrupt (enumeration done) + * @hsotg: The device state. + * + * Handle updating the device settings after the enumeration phase has + * been completed. +*/ +static void s3c_hsotg_irq_enumdone(struct s3c_hsotg *hsotg) +{ + u32 dsts = readl(hsotg->regs + S3C_DSTS); + int ep0_mps = 0, ep_mps; + + /* This should signal the finish of the enumeration phase + * of the USB handshaking, so we should now know what rate + * we connected at. */ + + dev_dbg(hsotg->dev, "EnumDone (DSTS=0x%08x)\n", dsts); + + /* note, since we're limited by the size of transfer on EP0, and + * it seems IN transfers must be a even number of packets we do + * not advertise a 64byte MPS on EP0. */ + + /* catch both EnumSpd_FS and EnumSpd_FS48 */ + switch (dsts & S3C_DSTS_EnumSpd_MASK) { + case S3C_DSTS_EnumSpd_FS: + case S3C_DSTS_EnumSpd_FS48: + hsotg->gadget.speed = USB_SPEED_FULL; + dev_info(hsotg->dev, "new device is full-speed\n"); + + ep0_mps = EP0_MPS_LIMIT; + ep_mps = 64; + break; + + case S3C_DSTS_EnumSpd_HS: + dev_info(hsotg->dev, "new device is high-speed\n"); + hsotg->gadget.speed = USB_SPEED_HIGH; + + ep0_mps = EP0_MPS_LIMIT; + ep_mps = 512; + break; + + case S3C_DSTS_EnumSpd_LS: + hsotg->gadget.speed = USB_SPEED_LOW; + dev_info(hsotg->dev, "new device is low-speed\n"); + + /* note, we don't actually support LS in this driver at the + * moment, and the documentation seems to imply that it isn't + * supported by the PHYs on some of the devices. + */ + break; + } + + /* we should now know the maximum packet size for an + * endpoint, so set the endpoints to a default value. */ + + if (ep0_mps) { + int i; + s3c_hsotg_set_ep_maxpacket(hsotg, 0, ep0_mps); + for (i = 1; i < S3C_HSOTG_EPS; i++) + s3c_hsotg_set_ep_maxpacket(hsotg, i, ep_mps); + } + + /* ensure after enumeration our EP0 is active */ + + s3c_hsotg_enqueue_setup(hsotg); + + dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", + readl(hsotg->regs + S3C_DIEPCTL0), + readl(hsotg->regs + S3C_DOEPCTL0)); +} + +/** + * kill_all_requests - remove all requests from the endpoint's queue + * @hsotg: The device state. + * @ep: The endpoint the requests may be on. + * @result: The result code to use. + * @force: Force removal of any current requests + * + * Go through the requests on the given endpoint and mark them + * completed with the given result code. + */ +static void kill_all_requests(struct s3c_hsotg *hsotg, + struct s3c_hsotg_ep *ep, + int result, bool force) +{ + struct s3c_hsotg_req *req, *treq; + unsigned long flags; + + spin_lock_irqsave(&ep->lock, flags); + + list_for_each_entry_safe(req, treq, &ep->queue, queue) { + /* currently, we can't do much about an already + * running request on an in endpoint */ + + if (ep->req == req && ep->dir_in && !force) + continue; + + s3c_hsotg_complete_request(hsotg, ep, req, + result); + } + + spin_unlock_irqrestore(&ep->lock, flags); +} + +#define call_gadget(_hs, _entry) \ + if ((_hs)->gadget.speed != USB_SPEED_UNKNOWN && \ + (_hs)->driver && (_hs)->driver->_entry) \ + (_hs)->driver->_entry(&(_hs)->gadget); + +/** + * s3c_hsotg_disconnect_irq - disconnect irq service + * @hsotg: The device state. + * + * A disconnect IRQ has been received, meaning that the host has + * lost contact with the bus. Remove all current transactions + * and signal the gadget driver that this has happened. +*/ +static void s3c_hsotg_disconnect_irq(struct s3c_hsotg *hsotg) +{ + unsigned ep; + + for (ep = 0; ep < S3C_HSOTG_EPS; ep++) + kill_all_requests(hsotg, &hsotg->eps[ep], -ESHUTDOWN, true); + + call_gadget(hsotg, disconnect); +} + +/** + * s3c_hsotg_irq_fifoempty - TX FIFO empty interrupt handler + * @hsotg: The device state: + * @periodic: True if this is a periodic FIFO interrupt + */ +static void s3c_hsotg_irq_fifoempty(struct s3c_hsotg *hsotg, bool periodic) +{ + struct s3c_hsotg_ep *ep; + int epno, ret; + + /* look through for any more data to transmit */ + + for (epno = 0; epno < S3C_HSOTG_EPS; epno++) { + ep = &hsotg->eps[epno]; + + if (!ep->dir_in) + continue; + + if ((periodic && !ep->periodic) || + (!periodic && ep->periodic)) + continue; + + ret = s3c_hsotg_trytx(hsotg, ep); + if (ret < 0) + break; + } +} + +static struct s3c_hsotg *our_hsotg; + +/* IRQ flags which will trigger a retry around the IRQ loop */ +#define IRQ_RETRY_MASK (S3C_GINTSTS_NPTxFEmp | \ + S3C_GINTSTS_PTxFEmp | \ + S3C_GINTSTS_RxFLvl) + +/** + * s3c_hsotg_irq - handle device interrupt + * @irq: The IRQ number triggered + * @pw: The pw value when registered the handler. + */ +static irqreturn_t s3c_hsotg_irq(int irq, void *pw) +{ + struct s3c_hsotg *hsotg = pw; + int retry_count = 8; + u32 gintsts; + u32 gintmsk; + +irq_retry: + gintsts = readl(hsotg->regs + S3C_GINTSTS); + gintmsk = readl(hsotg->regs + S3C_GINTMSK); + + dev_dbg(hsotg->dev, "%s: %08x %08x (%08x) retry %d\n", + __func__, gintsts, gintsts & gintmsk, gintmsk, retry_count); + + gintsts &= gintmsk; + + if (gintsts & S3C_GINTSTS_OTGInt) { + u32 otgint = readl(hsotg->regs + S3C_GOTGINT); + + dev_info(hsotg->dev, "OTGInt: %08x\n", otgint); + + writel(otgint, hsotg->regs + S3C_GOTGINT); + writel(S3C_GINTSTS_OTGInt, hsotg->regs + S3C_GINTSTS); + } + + if (gintsts & S3C_GINTSTS_DisconnInt) { + dev_dbg(hsotg->dev, "%s: DisconnInt\n", __func__); + writel(S3C_GINTSTS_DisconnInt, hsotg->regs + S3C_GINTSTS); + + s3c_hsotg_disconnect_irq(hsotg); + } + + if (gintsts & S3C_GINTSTS_SessReqInt) { + dev_dbg(hsotg->dev, "%s: SessReqInt\n", __func__); + writel(S3C_GINTSTS_SessReqInt, hsotg->regs + S3C_GINTSTS); + } + + if (gintsts & S3C_GINTSTS_EnumDone) { + s3c_hsotg_irq_enumdone(hsotg); + writel(S3C_GINTSTS_EnumDone, hsotg->regs + S3C_GINTSTS); + } + + if (gintsts & S3C_GINTSTS_ConIDStsChng) { + dev_dbg(hsotg->dev, "ConIDStsChg (DSTS=0x%08x, GOTCTL=%08x)\n", + readl(hsotg->regs + S3C_DSTS), + readl(hsotg->regs + S3C_GOTGCTL)); + + writel(S3C_GINTSTS_ConIDStsChng, hsotg->regs + S3C_GINTSTS); + } + + if (gintsts & (S3C_GINTSTS_OEPInt | S3C_GINTSTS_IEPInt)) { + u32 daint = readl(hsotg->regs + S3C_DAINT); + u32 daint_out = daint >> S3C_DAINT_OutEP_SHIFT; + u32 daint_in = daint & ~(daint_out << S3C_DAINT_OutEP_SHIFT); + int ep; + + dev_dbg(hsotg->dev, "%s: daint=%08x\n", __func__, daint); + + for (ep = 0; ep < 15 && daint_out; ep++, daint_out >>= 1) { + if (daint_out & 1) + s3c_hsotg_epint(hsotg, ep, 0); + } + + for (ep = 0; ep < 15 && daint_in; ep++, daint_in >>= 1) { + if (daint_in & 1) + s3c_hsotg_epint(hsotg, ep, 1); + } + + writel(daint, hsotg->regs + S3C_DAINT); + writel(gintsts & (S3C_GINTSTS_OEPInt | S3C_GINTSTS_IEPInt), + hsotg->regs + S3C_GINTSTS); + } + + if (gintsts & S3C_GINTSTS_USBRst) { + dev_info(hsotg->dev, "%s: USBRst\n", __func__); + dev_dbg(hsotg->dev, "GNPTXSTS=%08x\n", + readl(hsotg->regs + S3C_GNPTXSTS)); + + kill_all_requests(hsotg, &hsotg->eps[0], -ECONNRESET, true); + + /* it seems after a reset we can end up with a situation + * where the TXFIFO still has data in it... try flushing + * it to remove anything that may still be in it. + */ + + if (1) { + writel(S3C_GRSTCTL_TxFNum(0) | S3C_GRSTCTL_TxFFlsh, + hsotg->regs + S3C_GRSTCTL); + + dev_info(hsotg->dev, "GNPTXSTS=%08x\n", + readl(hsotg->regs + S3C_GNPTXSTS)); + } + + s3c_hsotg_enqueue_setup(hsotg); + + writel(S3C_GINTSTS_USBRst, hsotg->regs + S3C_GINTSTS); + } + + /* check both FIFOs */ + + if (gintsts & S3C_GINTSTS_NPTxFEmp) { + dev_dbg(hsotg->dev, "NPTxFEmp\n"); + + /* Disable the interrupt to stop it happening again + * unless one of these endpoint routines decides that + * it needs re-enabling */ + + s3c_hsotg_disable_gsint(hsotg, S3C_GINTSTS_NPTxFEmp); + s3c_hsotg_irq_fifoempty(hsotg, false); + + writel(S3C_GINTSTS_NPTxFEmp, hsotg->regs + S3C_GINTSTS); + } + + if (gintsts & S3C_GINTSTS_PTxFEmp) { + dev_dbg(hsotg->dev, "PTxFEmp\n"); + + /* See note in S3C_GINTSTS_NPTxFEmp */ + + s3c_hsotg_disable_gsint(hsotg, S3C_GINTSTS_PTxFEmp); + s3c_hsotg_irq_fifoempty(hsotg, true); + + writel(S3C_GINTSTS_PTxFEmp, hsotg->regs + S3C_GINTSTS); + } + + if (gintsts & S3C_GINTSTS_RxFLvl) { + /* note, since GINTSTS_RxFLvl doubles as FIFO-not-empty, + * we need to retry s3c_hsotg_handle_rx if this is still + * set. */ + + s3c_hsotg_handle_rx(hsotg); + writel(S3C_GINTSTS_RxFLvl, hsotg->regs + S3C_GINTSTS); + } + + if (gintsts & S3C_GINTSTS_ModeMis) { + dev_warn(hsotg->dev, "warning, mode mismatch triggered\n"); + writel(S3C_GINTSTS_ModeMis, hsotg->regs + S3C_GINTSTS); + } + + if (gintsts & S3C_GINTSTS_USBSusp) { + dev_info(hsotg->dev, "S3C_GINTSTS_USBSusp\n"); + writel(S3C_GINTSTS_USBSusp, hsotg->regs + S3C_GINTSTS); + + call_gadget(hsotg, suspend); + } + + if (gintsts & S3C_GINTSTS_WkUpInt) { + dev_info(hsotg->dev, "S3C_GINTSTS_WkUpIn\n"); + writel(S3C_GINTSTS_WkUpInt, hsotg->regs + S3C_GINTSTS); + + call_gadget(hsotg, resume); + } + + if (gintsts & S3C_GINTSTS_ErlySusp) { + dev_dbg(hsotg->dev, "S3C_GINTSTS_ErlySusp\n"); + writel(S3C_GINTSTS_ErlySusp, hsotg->regs + S3C_GINTSTS); + } + + /* these next two seem to crop-up occasionally causing the core + * to shutdown the USB transfer, so try clearing them and logging + * the occurence. */ + + if (gintsts & S3C_GINTSTS_GOUTNakEff) { + dev_info(hsotg->dev, "GOUTNakEff triggered\n"); + + s3c_hsotg_dump(hsotg); + + writel(S3C_DCTL_CGOUTNak, hsotg->regs + S3C_DCTL); + writel(S3C_GINTSTS_GOUTNakEff, hsotg->regs + S3C_GINTSTS); + } + + if (gintsts & S3C_GINTSTS_GINNakEff) { + dev_info(hsotg->dev, "GINNakEff triggered\n"); + + s3c_hsotg_dump(hsotg); + + writel(S3C_DCTL_CGNPInNAK, hsotg->regs + S3C_DCTL); + writel(S3C_GINTSTS_GINNakEff, hsotg->regs + S3C_GINTSTS); + } + + /* if we've had fifo events, we should try and go around the + * loop again to see if there's any point in returning yet. */ + + if (gintsts & IRQ_RETRY_MASK && --retry_count > 0) + goto irq_retry; + + return IRQ_HANDLED; +} + +/** + * s3c_hsotg_ep_enable - enable the given endpoint + * @ep: The USB endpint to configure + * @desc: The USB endpoint descriptor to configure with. + * + * This is called from the USB gadget code's usb_ep_enable(). +*/ +static int s3c_hsotg_ep_enable(struct usb_ep *ep, + const struct usb_endpoint_descriptor *desc) +{ + struct s3c_hsotg_ep *hs_ep = our_ep(ep); + struct s3c_hsotg *hsotg = hs_ep->parent; + unsigned long flags; + int index = hs_ep->index; + u32 epctrl_reg; + u32 epctrl; + u32 mps; + int dir_in; + + dev_dbg(hsotg->dev, + "%s: ep %s: a 0x%02x, attr 0x%02x, mps 0x%04x, intr %d\n", + __func__, ep->name, desc->bEndpointAddress, desc->bmAttributes, + desc->wMaxPacketSize, desc->bInterval); + + /* not to be called for EP0 */ + WARN_ON(index == 0); + + dir_in = (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ? 1 : 0; + if (dir_in != hs_ep->dir_in) { + dev_err(hsotg->dev, "%s: direction mismatch!\n", __func__); + return -EINVAL; + } + + mps = le16_to_cpu(desc->wMaxPacketSize); + + /* note, we handle this here instead of s3c_hsotg_set_ep_maxpacket */ + + epctrl_reg = dir_in ? S3C_DIEPCTL(index) : S3C_DOEPCTL(index); + epctrl = readl(hsotg->regs + epctrl_reg); + + dev_dbg(hsotg->dev, "%s: read DxEPCTL=0x%08x from 0x%08x\n", + __func__, epctrl, epctrl_reg); + + spin_lock_irqsave(&hs_ep->lock, flags); + + epctrl &= ~(S3C_DxEPCTL_EPType_MASK | S3C_DxEPCTL_MPS_MASK); + epctrl |= S3C_DxEPCTL_MPS(mps); + + /* mark the endpoint as active, otherwise the core may ignore + * transactions entirely for this endpoint */ + epctrl |= S3C_DxEPCTL_USBActEp; + + /* set the NAK status on the endpoint, otherwise we might try and + * do something with data that we've yet got a request to process + * since the RXFIFO will take data for an endpoint even if the + * size register hasn't been set. + */ + + epctrl |= S3C_DxEPCTL_SNAK; + + /* update the endpoint state */ + hs_ep->ep.maxpacket = mps; + + /* default, set to non-periodic */ + hs_ep->periodic = 0; + + switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { + case USB_ENDPOINT_XFER_ISOC: + dev_err(hsotg->dev, "no current ISOC support\n"); + return -EINVAL; + + case USB_ENDPOINT_XFER_BULK: + epctrl |= S3C_DxEPCTL_EPType_Bulk; + break; + + case USB_ENDPOINT_XFER_INT: + if (dir_in) { + /* Allocate our TxFNum by simply using the index + * of the endpoint for the moment. We could do + * something better if the host indicates how + * many FIFOs we are expecting to use. */ + + hs_ep->periodic = 1; + epctrl |= S3C_DxEPCTL_TxFNum(index); + } + + epctrl |= S3C_DxEPCTL_EPType_Intterupt; + break; + + case USB_ENDPOINT_XFER_CONTROL: + epctrl |= S3C_DxEPCTL_EPType_Control; + break; + } + + /* for non control endpoints, set PID to D0 */ + if (index) + epctrl |= S3C_DxEPCTL_SetD0PID; + + dev_dbg(hsotg->dev, "%s: write DxEPCTL=0x%08x\n", + __func__, epctrl); + + writel(epctrl, hsotg->regs + epctrl_reg); + dev_dbg(hsotg->dev, "%s: read DxEPCTL=0x%08x\n", + __func__, readl(hsotg->regs + epctrl_reg)); + + /* enable the endpoint interrupt */ + s3c_hsotg_ctrl_epint(hsotg, index, dir_in, 1); + + spin_unlock_irqrestore(&hs_ep->lock, flags); + return 0; +} + +static int s3c_hsotg_ep_disable(struct usb_ep *ep) +{ + struct s3c_hsotg_ep *hs_ep = our_ep(ep); + struct s3c_hsotg *hsotg = hs_ep->parent; + int dir_in = hs_ep->dir_in; + int index = hs_ep->index; + unsigned long flags; + u32 epctrl_reg; + u32 ctrl; + + dev_info(hsotg->dev, "%s(ep %p)\n", __func__, ep); + + if (ep == &hsotg->eps[0].ep) { + dev_err(hsotg->dev, "%s: called for ep0\n", __func__); + return -EINVAL; + } + + epctrl_reg = dir_in ? S3C_DIEPCTL(index) : S3C_DOEPCTL(index); + + /* terminate all requests with shutdown */ + kill_all_requests(hsotg, hs_ep, -ESHUTDOWN, false); + + spin_lock_irqsave(&hs_ep->lock, flags); + + ctrl = readl(hsotg->regs + epctrl_reg); + ctrl &= ~S3C_DxEPCTL_EPEna; + ctrl &= ~S3C_DxEPCTL_USBActEp; + ctrl |= S3C_DxEPCTL_SNAK; + + dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", __func__, ctrl); + writel(ctrl, hsotg->regs + epctrl_reg); + + /* disable endpoint interrupts */ + s3c_hsotg_ctrl_epint(hsotg, hs_ep->index, hs_ep->dir_in, 0); + + spin_unlock_irqrestore(&hs_ep->lock, flags); + return 0; +} + +/** + * on_list - check request is on the given endpoint + * @ep: The endpoint to check. + * @test: The request to test if it is on the endpoint. +*/ +static bool on_list(struct s3c_hsotg_ep *ep, struct s3c_hsotg_req *test) +{ + struct s3c_hsotg_req *req, *treq; + + list_for_each_entry_safe(req, treq, &ep->queue, queue) { + if (req == test) + return true; + } + + return false; +} + +static int s3c_hsotg_ep_dequeue(struct usb_ep *ep, struct usb_request *req) +{ + struct s3c_hsotg_req *hs_req = our_req(req); + struct s3c_hsotg_ep *hs_ep = our_ep(ep); + struct s3c_hsotg *hs = hs_ep->parent; + unsigned long flags; + + dev_info(hs->dev, "ep_dequeue(%p,%p)\n", ep, req); + + if (hs_req == hs_ep->req) { + dev_dbg(hs->dev, "%s: already in progress\n", __func__); + return -EINPROGRESS; + } + + spin_lock_irqsave(&hs_ep->lock, flags); + + if (!on_list(hs_ep, hs_req)) { + spin_unlock_irqrestore(&hs_ep->lock, flags); + return -EINVAL; + } + + s3c_hsotg_complete_request(hs, hs_ep, hs_req, -ECONNRESET); + spin_unlock_irqrestore(&hs_ep->lock, flags); + + return 0; +} + +static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value) +{ + struct s3c_hsotg_ep *hs_ep = our_ep(ep); + struct s3c_hsotg *hs = hs_ep->parent; + int index = hs_ep->index; + unsigned long irqflags; + u32 epreg; + u32 epctl; + + dev_info(hs->dev, "%s(ep %p %s, %d)\n", __func__, ep, ep->name, value); + + spin_lock_irqsave(&hs_ep->lock, irqflags); + + /* write both IN and OUT control registers */ + + epreg = S3C_DIEPCTL(index); + epctl = readl(hs->regs + epreg); + + if (value) + epctl |= S3C_DxEPCTL_Stall; + else + epctl &= ~S3C_DxEPCTL_Stall; + + writel(epctl, hs->regs + epreg); + + epreg = S3C_DOEPCTL(index); + epctl = readl(hs->regs + epreg); + + if (value) + epctl |= S3C_DxEPCTL_Stall; + else + epctl &= ~S3C_DxEPCTL_Stall; + + writel(epctl, hs->regs + epreg); + + spin_unlock_irqrestore(&hs_ep->lock, irqflags); + + return 0; +} + +static struct usb_ep_ops s3c_hsotg_ep_ops = { + .enable = s3c_hsotg_ep_enable, + .disable = s3c_hsotg_ep_disable, + .alloc_request = s3c_hsotg_ep_alloc_request, + .free_request = s3c_hsotg_ep_free_request, + .queue = s3c_hsotg_ep_queue, + .dequeue = s3c_hsotg_ep_dequeue, + .set_halt = s3c_hsotg_ep_sethalt, + /* note, don't belive we have any call for the fifo routines */ +}; + +/** + * s3c_hsotg_corereset - issue softreset to the core + * @hsotg: The device state + * + * Issue a soft reset to the core, and await the core finishing it. +*/ +static int s3c_hsotg_corereset(struct s3c_hsotg *hsotg) +{ + int timeout; + u32 grstctl; + + dev_dbg(hsotg->dev, "resetting core\n"); + + /* issue soft reset */ + writel(S3C_GRSTCTL_CSftRst, hsotg->regs + S3C_GRSTCTL); + + timeout = 1000; + do { + grstctl = readl(hsotg->regs + S3C_GRSTCTL); + } while (!(grstctl & S3C_GRSTCTL_CSftRst) && timeout-- > 0); + + if (!grstctl & S3C_GRSTCTL_CSftRst) { + dev_err(hsotg->dev, "Failed to get CSftRst asserted\n"); + return -EINVAL; + } + + timeout = 1000; + + while (1) { + u32 grstctl = readl(hsotg->regs + S3C_GRSTCTL); + + if (timeout-- < 0) { + dev_info(hsotg->dev, + "%s: reset failed, GRSTCTL=%08x\n", + __func__, grstctl); + return -ETIMEDOUT; + } + + if (grstctl & S3C_GRSTCTL_CSftRst) + continue; + + if (!(grstctl & S3C_GRSTCTL_AHBIdle)) + continue; + + break; /* reset done */ + } + + dev_dbg(hsotg->dev, "reset successful\n"); + return 0; +} + +int usb_gadget_register_driver(struct usb_gadget_driver *driver) +{ + struct s3c_hsotg *hsotg = our_hsotg; + int ret; + + if (!hsotg) { + printk(KERN_ERR "%s: called with no device\n", __func__); + return -ENODEV; + } + + if (!driver) { + dev_err(hsotg->dev, "%s: no driver\n", __func__); + return -EINVAL; + } + + if (driver->speed != USB_SPEED_HIGH && + driver->speed != USB_SPEED_FULL) { + dev_err(hsotg->dev, "%s: bad speed\n", __func__); + } + + if (!driver->bind || !driver->setup) { + dev_err(hsotg->dev, "%s: missing entry points\n", __func__); + return -EINVAL; + } + + WARN_ON(hsotg->driver); + + driver->driver.bus = NULL; + hsotg->driver = driver; + hsotg->gadget.dev.driver = &driver->driver; + hsotg->gadget.dev.dma_mask = hsotg->dev->dma_mask; + hsotg->gadget.speed = USB_SPEED_UNKNOWN; + + ret = device_add(&hsotg->gadget.dev); + if (ret) { + dev_err(hsotg->dev, "failed to register gadget device\n"); + goto err; + } + + ret = driver->bind(&hsotg->gadget); + if (ret) { + dev_err(hsotg->dev, "failed bind %s\n", driver->driver.name); + + hsotg->gadget.dev.driver = NULL; + hsotg->driver = NULL; + goto err; + } + + /* we must now enable ep0 ready for host detection and then + * set configuration. */ + + s3c_hsotg_corereset(hsotg); + + /* set the PLL on, remove the HNP/SRP and set the PHY */ + writel(S3C_GUSBCFG_PHYIf16 | S3C_GUSBCFG_TOutCal(7) | + (0x5 << 10), hsotg->regs + S3C_GUSBCFG); + + /* looks like soft-reset changes state of FIFOs */ + s3c_hsotg_init_fifo(hsotg); + + __orr32(hsotg->regs + S3C_DCTL, S3C_DCTL_SftDiscon); + + writel(1 << 18 | S3C_DCFG_DevSpd_HS, hsotg->regs + S3C_DCFG); + + writel(S3C_GINTSTS_DisconnInt | S3C_GINTSTS_SessReqInt | + S3C_GINTSTS_ConIDStsChng | S3C_GINTSTS_USBRst | + S3C_GINTSTS_EnumDone | S3C_GINTSTS_OTGInt | + S3C_GINTSTS_USBSusp | S3C_GINTSTS_WkUpInt | + S3C_GINTSTS_GOUTNakEff | S3C_GINTSTS_GINNakEff | + S3C_GINTSTS_ErlySusp, + hsotg->regs + S3C_GINTMSK); + + if (using_dma(hsotg)) + writel(S3C_GAHBCFG_GlblIntrEn | S3C_GAHBCFG_DMAEn | + S3C_GAHBCFG_HBstLen_Incr4, + hsotg->regs + S3C_GAHBCFG); + else + writel(S3C_GAHBCFG_GlblIntrEn, hsotg->regs + S3C_GAHBCFG); + + /* Enabling INTknTXFEmpMsk here seems to be a big mistake, we end + * up being flooded with interrupts if the host is polling the + * endpoint to try and read data. */ + + writel(S3C_DIEPMSK_TimeOUTMsk | S3C_DIEPMSK_AHBErrMsk | + S3C_DIEPMSK_INTknEPMisMsk | + S3C_DIEPMSK_EPDisbldMsk | S3C_DIEPMSK_XferComplMsk, + hsotg->regs + S3C_DIEPMSK); + + /* don't need XferCompl, we get that from RXFIFO in slave mode. In + * DMA mode we may need this. */ + writel(S3C_DOEPMSK_SetupMsk | S3C_DOEPMSK_AHBErrMsk | + S3C_DOEPMSK_EPDisbldMsk | + using_dma(hsotg) ? (S3C_DIEPMSK_XferComplMsk | + S3C_DIEPMSK_TimeOUTMsk) : 0, + hsotg->regs + S3C_DOEPMSK); + + writel(0, hsotg->regs + S3C_DAINTMSK); + + dev_info(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", + readl(hsotg->regs + S3C_DIEPCTL0), + readl(hsotg->regs + S3C_DOEPCTL0)); + + /* enable in and out endpoint interrupts */ + s3c_hsotg_en_gsint(hsotg, S3C_GINTSTS_OEPInt | S3C_GINTSTS_IEPInt); + + /* Enable the RXFIFO when in slave mode, as this is how we collect + * the data. In DMA mode, we get events from the FIFO but also + * things we cannot process, so do not use it. */ + if (!using_dma(hsotg)) + s3c_hsotg_en_gsint(hsotg, S3C_GINTSTS_RxFLvl); + + /* Enable interrupts for EP0 in and out */ + s3c_hsotg_ctrl_epint(hsotg, 0, 0, 1); + s3c_hsotg_ctrl_epint(hsotg, 0, 1, 1); + + __orr32(hsotg->regs + S3C_DCTL, S3C_DCTL_PWROnPrgDone); + udelay(10); /* see openiboot */ + __bic32(hsotg->regs + S3C_DCTL, S3C_DCTL_PWROnPrgDone); + + dev_info(hsotg->dev, "DCTL=0x%08x\n", readl(hsotg->regs + S3C_DCTL)); + + /* S3C_DxEPCTL_USBActEp says RO in manual, but seems to be set by + writing to the EPCTL register.. */ + + /* set to read 1 8byte packet */ + writel(S3C_DxEPTSIZ_MC(1) | S3C_DxEPTSIZ_PktCnt(1) | + S3C_DxEPTSIZ_XferSize(8), hsotg->regs + DOEPTSIZ0); + + writel(s3c_hsotg_ep0_mps(hsotg->eps[0].ep.maxpacket) | + S3C_DxEPCTL_CNAK | S3C_DxEPCTL_EPEna | + S3C_DxEPCTL_USBActEp, + hsotg->regs + S3C_DOEPCTL0); + + /* enable, but don't activate EP0in */ + writel(s3c_hsotg_ep0_mps(hsotg->eps[0].ep.maxpacket) | + S3C_DxEPCTL_USBActEp, hsotg->regs + S3C_DIEPCTL0); + + s3c_hsotg_enqueue_setup(hsotg); + + dev_info(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", + readl(hsotg->regs + S3C_DIEPCTL0), + readl(hsotg->regs + S3C_DOEPCTL0)); + + /* clear global NAKs */ + writel(S3C_DCTL_CGOUTNak | S3C_DCTL_CGNPInNAK, + hsotg->regs + S3C_DCTL); + + /* remove the soft-disconnect and let's go */ + __bic32(hsotg->regs + S3C_DCTL, S3C_DCTL_SftDiscon); + + /* report to the user, and return */ + + dev_info(hsotg->dev, "bound driver %s\n", driver->driver.name); + return 0; + +err: + hsotg->driver = NULL; + hsotg->gadget.dev.driver = NULL; + return ret; +} + +int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +{ + struct s3c_hsotg *hsotg = our_hsotg; + int ep; + + if (!hsotg) + return -ENODEV; + + if (!driver || driver != hsotg->driver || !driver->unbind) + return -EINVAL; + + /* all endpoints should be shutdown */ + for (ep = 0; ep < S3C_HSOTG_EPS; ep++) + s3c_hsotg_ep_disable(&hsotg->eps[ep].ep); + + call_gadget(hsotg, disconnect); + + driver->unbind(&hsotg->gadget); + hsotg->driver = NULL; + hsotg->gadget.speed = USB_SPEED_UNKNOWN; + + device_del(&hsotg->gadget.dev); + + dev_info(hsotg->dev, "unregistered gadget driver '%s'\n", + driver->driver.name); + + return 0; +} +EXPORT_SYMBOL(usb_gadget_unregister_driver); + +static int s3c_hsotg_gadget_getframe(struct usb_gadget *gadget) +{ + return s3c_hsotg_read_frameno(to_hsotg(gadget)); +} + +static struct usb_gadget_ops s3c_hsotg_gadget_ops = { + .get_frame = s3c_hsotg_gadget_getframe, +}; + +/** + * s3c_hsotg_initep - initialise a single endpoint + * @hsotg: The device state. + * @hs_ep: The endpoint to be initialised. + * @epnum: The endpoint number + * + * Initialise the given endpoint (as part of the probe and device state + * creation) to give to the gadget driver. Setup the endpoint name, any + * direction information and other state that may be required. + */ +static void __devinit s3c_hsotg_initep(struct s3c_hsotg *hsotg, + struct s3c_hsotg_ep *hs_ep, + int epnum) +{ + u32 ptxfifo; + char *dir; + + if (epnum == 0) + dir = ""; + else if ((epnum % 2) == 0) { + dir = "out"; + } else { + dir = "in"; + hs_ep->dir_in = 1; + } + + hs_ep->index = epnum; + + snprintf(hs_ep->name, sizeof(hs_ep->name), "ep%d%s", epnum, dir); + + INIT_LIST_HEAD(&hs_ep->queue); + INIT_LIST_HEAD(&hs_ep->ep.ep_list); + + spin_lock_init(&hs_ep->lock); + + /* add to the list of endpoints known by the gadget driver */ + if (epnum) + list_add_tail(&hs_ep->ep.ep_list, &hsotg->gadget.ep_list); + + hs_ep->parent = hsotg; + hs_ep->ep.name = hs_ep->name; + hs_ep->ep.maxpacket = epnum ? 512 : EP0_MPS_LIMIT; + hs_ep->ep.ops = &s3c_hsotg_ep_ops; + + /* Read the FIFO size for the Periodic TX FIFO, even if we're + * an OUT endpoint, we may as well do this if in future the + * code is changed to make each endpoint's direction changeable. + */ + + ptxfifo = readl(hsotg->regs + S3C_DPTXFSIZn(epnum)); + hs_ep->fifo_size = S3C_DPTXFSIZn_DPTxFSize_GET(ptxfifo); + + /* if we're using dma, we need to set the next-endpoint pointer + * to be something valid. + */ + + if (using_dma(hsotg)) { + u32 next = S3C_DxEPCTL_NextEp((epnum + 1) % 15); + writel(next, hsotg->regs + S3C_DIEPCTL(epnum)); + writel(next, hsotg->regs + S3C_DOEPCTL(epnum)); + } +} + +/** + * s3c_hsotg_otgreset - reset the OtG phy block + * @hsotg: The host state. + * + * Power up the phy, set the basic configuration and start the PHY. + */ +static void s3c_hsotg_otgreset(struct s3c_hsotg *hsotg) +{ + u32 osc; + + writel(0, S3C_PHYPWR); + mdelay(1); + + osc = hsotg->plat->is_osc ? S3C_PHYCLK_EXT_OSC : 0; + + writel(osc | 0x10, S3C_PHYCLK); + + /* issue a full set of resets to the otg and core */ + + writel(S3C_RSTCON_PHY, S3C_RSTCON); + udelay(20); /* at-least 10uS */ + writel(0, S3C_RSTCON); +} + + +static void s3c_hsotg_init(struct s3c_hsotg *hsotg) +{ + /* unmask subset of endpoint interrupts */ + + writel(S3C_DIEPMSK_TimeOUTMsk | S3C_DIEPMSK_AHBErrMsk | + S3C_DIEPMSK_EPDisbldMsk | S3C_DIEPMSK_XferComplMsk, + hsotg->regs + S3C_DIEPMSK); + + writel(S3C_DOEPMSK_SetupMsk | S3C_DOEPMSK_AHBErrMsk | + S3C_DOEPMSK_EPDisbldMsk | S3C_DOEPMSK_XferComplMsk, + hsotg->regs + S3C_DOEPMSK); + + writel(0, hsotg->regs + S3C_DAINTMSK); + + if (0) { + /* post global nak until we're ready */ + writel(S3C_DCTL_SGNPInNAK | S3C_DCTL_SGOUTNak, + hsotg->regs + S3C_DCTL); + } + + /* setup fifos */ + + dev_info(hsotg->dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n", + readl(hsotg->regs + S3C_GRXFSIZ), + readl(hsotg->regs + S3C_GNPTXFSIZ)); + + s3c_hsotg_init_fifo(hsotg); + + /* set the PLL on, remove the HNP/SRP and set the PHY */ + writel(S3C_GUSBCFG_PHYIf16 | S3C_GUSBCFG_TOutCal(7) | (0x5 << 10), + hsotg->regs + S3C_GUSBCFG); + + writel(using_dma(hsotg) ? S3C_GAHBCFG_DMAEn : 0x0, + hsotg->regs + S3C_GAHBCFG); +} + +static void s3c_hsotg_dump(struct s3c_hsotg *hsotg) +{ + struct device *dev = hsotg->dev; + void __iomem *regs = hsotg->regs; + u32 val; + int idx; + + dev_info(dev, "DCFG=0x%08x, DCTL=0x%08x, DIEPMSK=%08x\n", + readl(regs + S3C_DCFG), readl(regs + S3C_DCTL), + readl(regs + S3C_DIEPMSK)); + + dev_info(dev, "GAHBCFG=0x%08x, 0x44=0x%08x\n", + readl(regs + S3C_GAHBCFG), readl(regs + 0x44)); + + dev_info(dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n", + readl(regs + S3C_GRXFSIZ), readl(regs + S3C_GNPTXFSIZ)); + + /* show periodic fifo settings */ + + for (idx = 1; idx <= 15; idx++) { + val = readl(regs + S3C_DPTXFSIZn(idx)); + dev_info(dev, "DPTx[%d] FSize=%d, StAddr=0x%08x\n", idx, + val >> S3C_DPTXFSIZn_DPTxFSize_SHIFT, + val & S3C_DPTXFSIZn_DPTxFStAddr_MASK); + } + + for (idx = 0; idx < 15; idx++) { + dev_info(dev, + "ep%d-in: EPCTL=0x%08x, SIZ=0x%08x, DMA=0x%08x\n", idx, + readl(regs + S3C_DIEPCTL(idx)), + readl(regs + S3C_DIEPTSIZ(idx)), + readl(regs + S3C_DIEPDMA(idx))); + + val = readl(regs + S3C_DOEPCTL(idx)); + dev_info(dev, + "ep%d-out: EPCTL=0x%08x, SIZ=0x%08x, DMA=0x%08x\n", + idx, readl(regs + S3C_DOEPCTL(idx)), + readl(regs + S3C_DOEPTSIZ(idx)), + readl(regs + S3C_DOEPDMA(idx))); + + } + + dev_info(dev, "DVBUSDIS=0x%08x, DVBUSPULSE=%08x\n", + readl(regs + S3C_DVBUSDIS), readl(regs + S3C_DVBUSPULSE)); +} + + +/** + * state_show - debugfs: show overall driver and device state. + * @seq: The seq file to write to. + * @v: Unused parameter. + * + * This debugfs entry shows the overall state of the hardware and + * some general information about each of the endpoints available + * to the system. + */ +static int state_show(struct seq_file *seq, void *v) +{ + struct s3c_hsotg *hsotg = seq->private; + void __iomem *regs = hsotg->regs; + int idx; + + seq_printf(seq, "DCFG=0x%08x, DCTL=0x%08x, DSTS=0x%08x\n", + readl(regs + S3C_DCFG), + readl(regs + S3C_DCTL), + readl(regs + S3C_DSTS)); + + seq_printf(seq, "DIEPMSK=0x%08x, DOEPMASK=0x%08x\n", + readl(regs + S3C_DIEPMSK), readl(regs + S3C_DOEPMSK)); + + seq_printf(seq, "GINTMSK=0x%08x, GINTSTS=0x%08x\n", + readl(regs + S3C_GINTMSK), + readl(regs + S3C_GINTSTS)); + + seq_printf(seq, "DAINTMSK=0x%08x, DAINT=0x%08x\n", + readl(regs + S3C_DAINTMSK), + readl(regs + S3C_DAINT)); + + seq_printf(seq, "GNPTXSTS=0x%08x, GRXSTSR=%08x\n", + readl(regs + S3C_GNPTXSTS), + readl(regs + S3C_GRXSTSR)); + + seq_printf(seq, "\nEndpoint status:\n"); + + for (idx = 0; idx < 15; idx++) { + u32 in, out; + + in = readl(regs + S3C_DIEPCTL(idx)); + out = readl(regs + S3C_DOEPCTL(idx)); + + seq_printf(seq, "ep%d: DIEPCTL=0x%08x, DOEPCTL=0x%08x", + idx, in, out); + + in = readl(regs + S3C_DIEPTSIZ(idx)); + out = readl(regs + S3C_DOEPTSIZ(idx)); + + seq_printf(seq, ", DIEPTSIZ=0x%08x, DOEPTSIZ=0x%08x", + in, out); + + seq_printf(seq, "\n"); + } + + return 0; +} + +static int state_open(struct inode *inode, struct file *file) +{ + return single_open(file, state_show, inode->i_private); +} + +static const struct file_operations state_fops = { + .owner = THIS_MODULE, + .open = state_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +/** + * fifo_show - debugfs: show the fifo information + * @seq: The seq_file to write data to. + * @v: Unused parameter. + * + * Show the FIFO information for the overall fifo and all the + * periodic transmission FIFOs. +*/ +static int fifo_show(struct seq_file *seq, void *v) +{ + struct s3c_hsotg *hsotg = seq->private; + void __iomem *regs = hsotg->regs; + u32 val; + int idx; + + seq_printf(seq, "Non-periodic FIFOs:\n"); + seq_printf(seq, "RXFIFO: Size %d\n", readl(regs + S3C_GRXFSIZ)); + + val = readl(regs + S3C_GNPTXFSIZ); + seq_printf(seq, "NPTXFIFO: Size %d, Start 0x%08x\n", + val >> S3C_GNPTXFSIZ_NPTxFDep_SHIFT, + val & S3C_GNPTXFSIZ_NPTxFStAddr_MASK); + + seq_printf(seq, "\nPeriodic TXFIFOs:\n"); + + for (idx = 1; idx <= 15; idx++) { + val = readl(regs + S3C_DPTXFSIZn(idx)); + + seq_printf(seq, "\tDPTXFIFO%2d: Size %d, Start 0x%08x\n", idx, + val >> S3C_DPTXFSIZn_DPTxFSize_SHIFT, + val & S3C_DPTXFSIZn_DPTxFStAddr_MASK); + } + + return 0; +} + +static int fifo_open(struct inode *inode, struct file *file) +{ + return single_open(file, fifo_show, inode->i_private); +} + +static const struct file_operations fifo_fops = { + .owner = THIS_MODULE, + .open = fifo_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + + +static const char *decode_direction(int is_in) +{ + return is_in ? "in" : "out"; +} + +/** + * ep_show - debugfs: show the state of an endpoint. + * @seq: The seq_file to write data to. + * @v: Unused parameter. + * + * This debugfs entry shows the state of the given endpoint (one is + * registered for each available). +*/ +static int ep_show(struct seq_file *seq, void *v) +{ + struct s3c_hsotg_ep *ep = seq->private; + struct s3c_hsotg *hsotg = ep->parent; + struct s3c_hsotg_req *req; + void __iomem *regs = hsotg->regs; + int index = ep->index; + int show_limit = 15; + unsigned long flags; + + seq_printf(seq, "Endpoint index %d, named %s, dir %s:\n", + ep->index, ep->ep.name, decode_direction(ep->dir_in)); + + /* first show the register state */ + + seq_printf(seq, "\tDIEPCTL=0x%08x, DOEPCTL=0x%08x\n", + readl(regs + S3C_DIEPCTL(index)), + readl(regs + S3C_DOEPCTL(index))); + + seq_printf(seq, "\tDIEPDMA=0x%08x, DOEPDMA=0x%08x\n", + readl(regs + S3C_DIEPDMA(index)), + readl(regs + S3C_DOEPDMA(index))); + + seq_printf(seq, "\tDIEPINT=0x%08x, DOEPINT=0x%08x\n", + readl(regs + S3C_DIEPINT(index)), + readl(regs + S3C_DOEPINT(index))); + + seq_printf(seq, "\tDIEPTSIZ=0x%08x, DOEPTSIZ=0x%08x\n", + readl(regs + S3C_DIEPTSIZ(index)), + readl(regs + S3C_DOEPTSIZ(index))); + + seq_printf(seq, "\n"); + seq_printf(seq, "mps %d\n", ep->ep.maxpacket); + seq_printf(seq, "total_data=%ld\n", ep->total_data); + + seq_printf(seq, "request list (%p,%p):\n", + ep->queue.next, ep->queue.prev); + + spin_lock_irqsave(&ep->lock, flags); + + list_for_each_entry(req, &ep->queue, queue) { + if (--show_limit < 0) { + seq_printf(seq, "not showing more requests...\n"); + break; + } + + seq_printf(seq, "%c req %p: %d bytes @%p, ", + req == ep->req ? '*' : ' ', + req, req->req.length, req->req.buf); + seq_printf(seq, "%d done, res %d\n", + req->req.actual, req->req.status); + } + + spin_unlock_irqrestore(&ep->lock, flags); + + return 0; +} + +static int ep_open(struct inode *inode, struct file *file) +{ + return single_open(file, ep_show, inode->i_private); +} + +static const struct file_operations ep_fops = { + .owner = THIS_MODULE, + .open = ep_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +/** + * s3c_hsotg_create_debug - create debugfs directory and files + * @hsotg: The driver state + * + * Create the debugfs files to allow the user to get information + * about the state of the system. The directory name is created + * with the same name as the device itself, in case we end up + * with multiple blocks in future systems. +*/ +static void __devinit s3c_hsotg_create_debug(struct s3c_hsotg *hsotg) +{ + struct dentry *root; + unsigned epidx; + + root = debugfs_create_dir(dev_name(hsotg->dev), NULL); + hsotg->debug_root = root; + if (IS_ERR(root)) { + dev_err(hsotg->dev, "cannot create debug root\n"); + return; + } + + /* create general state file */ + + hsotg->debug_file = debugfs_create_file("state", 0444, root, + hsotg, &state_fops); + + if (IS_ERR(hsotg->debug_file)) + dev_err(hsotg->dev, "%s: failed to create state\n", __func__); + + hsotg->debug_fifo = debugfs_create_file("fifo", 0444, root, + hsotg, &fifo_fops); + + if (IS_ERR(hsotg->debug_fifo)) + dev_err(hsotg->dev, "%s: failed to create fifo\n", __func__); + + /* create one file for each endpoint */ + + for (epidx = 0; epidx < S3C_HSOTG_EPS; epidx++) { + struct s3c_hsotg_ep *ep = &hsotg->eps[epidx]; + + ep->debugfs = debugfs_create_file(ep->name, 0444, + root, ep, &ep_fops); + + if (IS_ERR(ep->debugfs)) + dev_err(hsotg->dev, "failed to create %s debug file\n", + ep->name); + } +} + +/** + * s3c_hsotg_delete_debug - cleanup debugfs entries + * @hsotg: The driver state + * + * Cleanup (remove) the debugfs files for use on module exit. +*/ +static void __devexit s3c_hsotg_delete_debug(struct s3c_hsotg *hsotg) +{ + unsigned epidx; + + for (epidx = 0; epidx < S3C_HSOTG_EPS; epidx++) { + struct s3c_hsotg_ep *ep = &hsotg->eps[epidx]; + debugfs_remove(ep->debugfs); + } + + debugfs_remove(hsotg->debug_file); + debugfs_remove(hsotg->debug_fifo); + debugfs_remove(hsotg->debug_root); +} + +/** + * s3c_hsotg_gate - set the hardware gate for the block + * @pdev: The device we bound to + * @on: On or off. + * + * Set the hardware gate setting into the block. If we end up on + * something other than an S3C64XX, then we might need to change this + * to using a platform data callback, or some other mechanism. + */ +static void s3c_hsotg_gate(struct platform_device *pdev, bool on) +{ + unsigned long flags; + u32 others; + + local_irq_save(flags); + + others = __raw_readl(S3C64XX_OTHERS); + if (on) + others |= S3C64XX_OTHERS_USBMASK; + else + others &= ~S3C64XX_OTHERS_USBMASK; + __raw_writel(others, S3C64XX_OTHERS); + + local_irq_restore(flags); +} + +struct s3c_hsotg_plat s3c_hsotg_default_pdata; + +static int __devinit s3c_hsotg_probe(struct platform_device *pdev) +{ + struct s3c_hsotg_plat *plat = pdev->dev.platform_data; + struct device *dev = &pdev->dev; + struct s3c_hsotg *hsotg; + struct resource *res; + int epnum; + int ret; + + if (!plat) + plat = &s3c_hsotg_default_pdata; + + hsotg = kzalloc(sizeof(struct s3c_hsotg) + + sizeof(struct s3c_hsotg_ep) * S3C_HSOTG_EPS, + GFP_KERNEL); + if (!hsotg) { + dev_err(dev, "cannot get memory\n"); + return -ENOMEM; + } + + hsotg->dev = dev; + hsotg->plat = plat; + + platform_set_drvdata(pdev, hsotg); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "cannot find register resource 0\n"); + ret = -EINVAL; + goto err_mem; + } + + hsotg->regs_res = request_mem_region(res->start, resource_size(res), + dev_name(dev)); + if (!hsotg->regs_res) { + dev_err(dev, "cannot reserve registers\n"); + ret = -ENOENT; + goto err_mem; + } + + hsotg->regs = ioremap(res->start, resource_size(res)); + if (!hsotg->regs) { + dev_err(dev, "cannot map registers\n"); + ret = -ENXIO; + goto err_regs_res; + } + + ret = platform_get_irq(pdev, 0); + if (ret < 0) { + dev_err(dev, "cannot find IRQ\n"); + goto err_regs; + } + + hsotg->irq = ret; + + ret = request_irq(ret, s3c_hsotg_irq, 0, dev_name(dev), hsotg); + if (ret < 0) { + dev_err(dev, "cannot claim IRQ\n"); + goto err_regs; + } + + dev_info(dev, "regs %p, irq %d\n", hsotg->regs, hsotg->irq); + + device_initialize(&hsotg->gadget.dev); + + dev_set_name(&hsotg->gadget.dev, "gadget"); + + hsotg->gadget.is_dualspeed = 1; + hsotg->gadget.ops = &s3c_hsotg_gadget_ops; + hsotg->gadget.name = dev_name(dev); + + hsotg->gadget.dev.parent = dev; + hsotg->gadget.dev.dma_mask = dev->dma_mask; + + /* setup endpoint information */ + + INIT_LIST_HEAD(&hsotg->gadget.ep_list); + hsotg->gadget.ep0 = &hsotg->eps[0].ep; + + /* allocate EP0 request */ + + hsotg->ctrl_req = s3c_hsotg_ep_alloc_request(&hsotg->eps[0].ep, + GFP_KERNEL); + if (!hsotg->ctrl_req) { + dev_err(dev, "failed to allocate ctrl req\n"); + goto err_regs; + } + + /* reset the system */ + + s3c_hsotg_gate(pdev, true); + + s3c_hsotg_otgreset(hsotg); + s3c_hsotg_corereset(hsotg); + s3c_hsotg_init(hsotg); + + /* initialise the endpoints now the core has been initialised */ + for (epnum = 0; epnum < S3C_HSOTG_EPS; epnum++) + s3c_hsotg_initep(hsotg, &hsotg->eps[epnum], epnum); + + s3c_hsotg_create_debug(hsotg); + + s3c_hsotg_dump(hsotg); + + our_hsotg = hsotg; + return 0; + +err_regs: + iounmap(hsotg->regs); + +err_regs_res: + release_resource(hsotg->regs_res); + kfree(hsotg->regs_res); + +err_mem: + kfree(hsotg); + return ret; +} + +static int __devexit s3c_hsotg_remove(struct platform_device *pdev) +{ + struct s3c_hsotg *hsotg = platform_get_drvdata(pdev); + + s3c_hsotg_delete_debug(hsotg); + + usb_gadget_unregister_driver(hsotg->driver); + + free_irq(hsotg->irq, hsotg); + iounmap(hsotg->regs); + + release_resource(hsotg->regs_res); + kfree(hsotg->regs_res); + + s3c_hsotg_gate(pdev, false); + + kfree(hsotg); + return 0; +} + +#if 1 +#define s3c_hsotg_suspend NULL +#define s3c_hsotg_resume NULL +#endif + +static struct platform_driver s3c_hsotg_driver = { + .driver = { + .name = "s3c-hsotg", + .owner = THIS_MODULE, + }, + .probe = s3c_hsotg_probe, + .remove = __devexit_p(s3c_hsotg_remove), + .suspend = s3c_hsotg_suspend, + .resume = s3c_hsotg_resume, +}; + +static int __init s3c_hsotg_modinit(void) +{ + return platform_driver_register(&s3c_hsotg_driver); +} + +static void __exit s3c_hsotg_modexit(void) +{ + platform_driver_unregister(&s3c_hsotg_driver); +} + +module_init(s3c_hsotg_modinit); +module_exit(s3c_hsotg_modexit); + +MODULE_DESCRIPTION("Samsung S3C USB High-speed/OtG device"); +MODULE_AUTHOR("Ben Dooks "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:s3c-hsotg"); diff --git a/drivers/usb/gadget/u_audio.c b/drivers/usb/gadget/u_audio.c new file mode 100644 index 000000000000..0f3d22fc030e --- /dev/null +++ b/drivers/usb/gadget/u_audio.c @@ -0,0 +1,319 @@ +/* + * u_audio.c -- ALSA audio utilities for Gadget stack + * + * Copyright (C) 2008 Bryan Wu + * Copyright (C) 2008 Analog Devices, Inc + * + * Enter bugs at http://blackfin.uclinux.org/ + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "u_audio.h" + +/* + * This component encapsulates the ALSA devices for USB audio gadget + */ + +#define FILE_PCM_PLAYBACK "/dev/snd/pcmC0D0p" +#define FILE_PCM_CAPTURE "/dev/snd/pcmC0D0c" +#define FILE_CONTROL "/dev/snd/controlC0" + +static char *fn_play = FILE_PCM_PLAYBACK; +module_param(fn_play, charp, S_IRUGO); +MODULE_PARM_DESC(fn_play, "Playback PCM device file name"); + +static char *fn_cap = FILE_PCM_CAPTURE; +module_param(fn_cap, charp, S_IRUGO); +MODULE_PARM_DESC(fn_cap, "Capture PCM device file name"); + +static char *fn_cntl = FILE_CONTROL; +module_param(fn_cntl, charp, S_IRUGO); +MODULE_PARM_DESC(fn_cntl, "Control device file name"); + +/*-------------------------------------------------------------------------*/ + +/** + * Some ALSA internal helper functions + */ +static int snd_interval_refine_set(struct snd_interval *i, unsigned int val) +{ + struct snd_interval t; + t.empty = 0; + t.min = t.max = val; + t.openmin = t.openmax = 0; + t.integer = 1; + return snd_interval_refine(i, &t); +} + +static int _snd_pcm_hw_param_set(struct snd_pcm_hw_params *params, + snd_pcm_hw_param_t var, unsigned int val, + int dir) +{ + int changed; + if (hw_is_mask(var)) { + struct snd_mask *m = hw_param_mask(params, var); + if (val == 0 && dir < 0) { + changed = -EINVAL; + snd_mask_none(m); + } else { + if (dir > 0) + val++; + else if (dir < 0) + val--; + changed = snd_mask_refine_set( + hw_param_mask(params, var), val); + } + } else if (hw_is_interval(var)) { + struct snd_interval *i = hw_param_interval(params, var); + if (val == 0 && dir < 0) { + changed = -EINVAL; + snd_interval_none(i); + } else if (dir == 0) + changed = snd_interval_refine_set(i, val); + else { + struct snd_interval t; + t.openmin = 1; + t.openmax = 1; + t.empty = 0; + t.integer = 0; + if (dir < 0) { + t.min = val - 1; + t.max = val; + } else { + t.min = val; + t.max = val+1; + } + changed = snd_interval_refine(i, &t); + } + } else + return -EINVAL; + if (changed) { + params->cmask |= 1 << var; + params->rmask |= 1 << var; + } + return changed; +} +/*-------------------------------------------------------------------------*/ + +/** + * Set default hardware params + */ +static int playback_default_hw_params(struct gaudio_snd_dev *snd) +{ + struct snd_pcm_substream *substream = snd->substream; + struct snd_pcm_hw_params *params; + snd_pcm_sframes_t result; + + /* + * SNDRV_PCM_ACCESS_RW_INTERLEAVED, + * SNDRV_PCM_FORMAT_S16_LE + * CHANNELS: 2 + * RATE: 48000 + */ + snd->access = SNDRV_PCM_ACCESS_RW_INTERLEAVED; + snd->format = SNDRV_PCM_FORMAT_S16_LE; + snd->channels = 2; + snd->rate = 48000; + + params = kzalloc(sizeof(*params), GFP_KERNEL); + if (!params) + return -ENOMEM; + + _snd_pcm_hw_params_any(params); + _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_ACCESS, + snd->access, 0); + _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_FORMAT, + snd->format, 0); + _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_CHANNELS, + snd->channels, 0); + _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_RATE, + snd->rate, 0); + + snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL); + snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_HW_PARAMS, params); + + result = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_PREPARE, NULL); + if (result < 0) { + ERROR(snd->card, + "Preparing sound card failed: %d\n", (int)result); + kfree(params); + return result; + } + + /* Store the hardware parameters */ + snd->access = params_access(params); + snd->format = params_format(params); + snd->channels = params_channels(params); + snd->rate = params_rate(params); + + kfree(params); + + INFO(snd->card, + "Hardware params: access %x, format %x, channels %d, rate %d\n", + snd->access, snd->format, snd->channels, snd->rate); + + return 0; +} + +/** + * Playback audio buffer data by ALSA PCM device + */ +static size_t u_audio_playback(struct gaudio *card, void *buf, size_t count) +{ + struct gaudio_snd_dev *snd = &card->playback; + struct snd_pcm_substream *substream = snd->substream; + struct snd_pcm_runtime *runtime = substream->runtime; + mm_segment_t old_fs; + ssize_t result; + snd_pcm_sframes_t frames; + +try_again: + if (runtime->status->state == SNDRV_PCM_STATE_XRUN || + runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) { + result = snd_pcm_kernel_ioctl(substream, + SNDRV_PCM_IOCTL_PREPARE, NULL); + if (result < 0) { + ERROR(card, "Preparing sound card failed: %d\n", + (int)result); + return result; + } + } + + frames = bytes_to_frames(runtime, count); + old_fs = get_fs(); + set_fs(KERNEL_DS); + result = snd_pcm_lib_write(snd->substream, buf, frames); + if (result != frames) { + ERROR(card, "Playback error: %d\n", (int)result); + set_fs(old_fs); + goto try_again; + } + set_fs(old_fs); + + return 0; +} + +static int u_audio_get_playback_channels(struct gaudio *card) +{ + return card->playback.channels; +} + +static int u_audio_get_playback_rate(struct gaudio *card) +{ + return card->playback.rate; +} + +/** + * Open ALSA PCM and control device files + * Initial the PCM or control device + */ +static int gaudio_open_snd_dev(struct gaudio *card) +{ + struct snd_pcm_file *pcm_file; + struct gaudio_snd_dev *snd; + + if (!card) + return -ENODEV; + + /* Open control device */ + snd = &card->control; + snd->filp = filp_open(fn_cntl, O_RDWR, 0); + if (IS_ERR(snd->filp)) { + int ret = PTR_ERR(snd->filp); + ERROR(card, "unable to open sound control device file: %s\n", + fn_cntl); + snd->filp = NULL; + return ret; + } + snd->card = card; + + /* Open PCM playback device and setup substream */ + snd = &card->playback; + snd->filp = filp_open(fn_play, O_WRONLY, 0); + if (IS_ERR(snd->filp)) { + ERROR(card, "No such PCM playback device: %s\n", fn_play); + snd->filp = NULL; + } + pcm_file = snd->filp->private_data; + snd->substream = pcm_file->substream; + snd->card = card; + playback_default_hw_params(snd); + + /* Open PCM capture device and setup substream */ + snd = &card->capture; + snd->filp = filp_open(fn_cap, O_RDONLY, 0); + if (IS_ERR(snd->filp)) { + ERROR(card, "No such PCM capture device: %s\n", fn_cap); + snd->filp = NULL; + } + pcm_file = snd->filp->private_data; + snd->substream = pcm_file->substream; + snd->card = card; + + return 0; +} + +/** + * Close ALSA PCM and control device files + */ +static int gaudio_close_snd_dev(struct gaudio *gau) +{ + struct gaudio_snd_dev *snd; + + /* Close control device */ + snd = &gau->control; + if (!IS_ERR(snd->filp)) + filp_close(snd->filp, current->files); + + /* Close PCM playback device and setup substream */ + snd = &gau->playback; + if (!IS_ERR(snd->filp)) + filp_close(snd->filp, current->files); + + /* Close PCM capture device and setup substream */ + snd = &gau->capture; + if (!IS_ERR(snd->filp)) + filp_close(snd->filp, current->files); + + return 0; +} + +/** + * gaudio_setup - setup ALSA interface and preparing for USB transfer + * + * This sets up PCM, mixer or MIDI ALSA devices fore USB gadget using. + * + * Returns negative errno, or zero on success + */ +int __init gaudio_setup(struct gaudio *card) +{ + int ret; + + ret = gaudio_open_snd_dev(card); + if (ret) + ERROR(card, "we need at least one control device\n"); + + return ret; + +} + +/** + * gaudio_cleanup - remove ALSA device interface + * + * This is called to free all resources allocated by @gaudio_setup(). + */ +void gaudio_cleanup(struct gaudio *card) +{ + if (card) + gaudio_close_snd_dev(card); +} + diff --git a/drivers/usb/gadget/u_audio.h b/drivers/usb/gadget/u_audio.h new file mode 100644 index 000000000000..cc8d159c648a --- /dev/null +++ b/drivers/usb/gadget/u_audio.h @@ -0,0 +1,56 @@ +/* + * u_audio.h -- interface to USB gadget "ALSA AUDIO" utilities + * + * Copyright (C) 2008 Bryan Wu + * Copyright (C) 2008 Analog Devices, Inc + * + * Enter bugs at http://blackfin.uclinux.org/ + * + * Licensed under the GPL-2 or later. + */ + +#ifndef __U_AUDIO_H +#define __U_AUDIO_H + +#include +#include +#include +#include + +#include +#include +#include + +#include "gadget_chips.h" + +/* + * This represents the USB side of an audio card device, managed by a USB + * function which provides control and stream interfaces. + */ + +struct gaudio_snd_dev { + struct gaudio *card; + struct file *filp; + struct snd_pcm_substream *substream; + int access; + int format; + int channels; + int rate; +}; + +struct gaudio { + struct usb_function func; + struct usb_gadget *gadget; + + /* ALSA sound device interfaces */ + struct gaudio_snd_dev control; + struct gaudio_snd_dev playback; + struct gaudio_snd_dev capture; + + /* TODO */ +}; + +int gaudio_setup(struct gaudio *card); +void gaudio_cleanup(struct gaudio *card); + +#endif /* __U_AUDIO_H */ diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c index 4007770f7ed2..016f63b39028 100644 --- a/drivers/usb/gadget/u_ether.c +++ b/drivers/usb/gadget/u_ether.c @@ -520,7 +520,7 @@ static int eth_start_xmit(struct sk_buff *skb, struct net_device *net) */ if (list_empty(&dev->tx_reqs)) { spin_unlock_irqrestore(&dev->req_lock, flags); - return 1; + return NETDEV_TX_BUSY; } req = container_of(dev->tx_reqs.next, struct usb_request, list); diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c index 0a4d99ab40d8..fc6e709f45b1 100644 --- a/drivers/usb/gadget/u_serial.c +++ b/drivers/usb/gadget/u_serial.c @@ -371,6 +371,7 @@ __acquires(&port->port_lock) req->length = len; list_del(&req->list); + req->zero = (gs_buf_data_avail(&port->port_write_buf) == 0); pr_vdebug(PREFIX "%d: tx len=%d, 0x%02x 0x%02x 0x%02x ...\n", port->port_num, len, *((u8 *)req->buf), diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 845479f7c707..1576a0520adf 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -17,6 +17,26 @@ config USB_C67X00_HCD To compile this driver as a module, choose M here: the module will be called c67x00. +config USB_XHCI_HCD + tristate "xHCI HCD (USB 3.0) support (EXPERIMENTAL)" + depends on USB && PCI && EXPERIMENTAL + ---help--- + The eXtensible Host Controller Interface (xHCI) is standard for USB 3.0 + "SuperSpeed" host controller hardware. + + To compile this driver as a module, choose M here: the + module will be called xhci-hcd. + +config USB_XHCI_HCD_DEBUGGING + bool "Debugging for the xHCI host controller" + depends on USB_XHCI_HCD + ---help--- + Say 'Y' to turn on debugging for the xHCI host controller driver. + This will spew debugging output, even in interrupt context. + This should only be used for debugging xHCI driver bugs. + + If unsure, say N. + config USB_EHCI_HCD tristate "EHCI HCD (USB 2.0) support" depends on USB && USB_ARCH_HAS_EHCI diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index f163571e33d8..289d748bb414 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -12,6 +12,7 @@ fhci-objs := fhci-hcd.o fhci-hub.o fhci-q.o fhci-mem.o \ ifeq ($(CONFIG_FHCI_DEBUG),y) fhci-objs += fhci-dbg.o endif +xhci-objs := xhci-hcd.o xhci-mem.o xhci-pci.o xhci-ring.o xhci-hub.o xhci-dbg.o obj-$(CONFIG_USB_WHCI_HCD) += whci/ @@ -23,6 +24,7 @@ obj-$(CONFIG_USB_ISP116X_HCD) += isp116x-hcd.o obj-$(CONFIG_USB_OHCI_HCD) += ohci-hcd.o obj-$(CONFIG_USB_UHCI_HCD) += uhci-hcd.o obj-$(CONFIG_USB_FHCI_HCD) += fhci.o +obj-$(CONFIG_USB_XHCI_HCD) += xhci.o obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o diff --git a/drivers/usb/host/ehci-au1xxx.c b/drivers/usb/host/ehci-au1xxx.c index bf69f4739107..c3a778bd359c 100644 --- a/drivers/usb/host/ehci-au1xxx.c +++ b/drivers/usb/host/ehci-au1xxx.c @@ -97,6 +97,7 @@ static const struct hc_driver ehci_au1xxx_hc_driver = { .urb_enqueue = ehci_urb_enqueue, .urb_dequeue = ehci_urb_dequeue, .endpoint_disable = ehci_endpoint_disable, + .endpoint_reset = ehci_endpoint_reset, /* * scheduling support diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index 01c3da34f678..bf86809c5120 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -309,6 +309,7 @@ static const struct hc_driver ehci_fsl_hc_driver = { .urb_enqueue = ehci_urb_enqueue, .urb_dequeue = ehci_urb_dequeue, .endpoint_disable = ehci_endpoint_disable, + .endpoint_reset = ehci_endpoint_reset, /* * scheduling support diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index c637207a1c80..2b72473544d3 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -1024,6 +1024,51 @@ done: return; } +static void +ehci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep) +{ + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + struct ehci_qh *qh; + int eptype = usb_endpoint_type(&ep->desc); + + if (eptype != USB_ENDPOINT_XFER_BULK && eptype != USB_ENDPOINT_XFER_INT) + return; + + rescan: + spin_lock_irq(&ehci->lock); + qh = ep->hcpriv; + + /* For Bulk and Interrupt endpoints we maintain the toggle state + * in the hardware; the toggle bits in udev aren't used at all. + * When an endpoint is reset by usb_clear_halt() we must reset + * the toggle bit in the QH. + */ + if (qh) { + if (!list_empty(&qh->qtd_list)) { + WARN_ONCE(1, "clear_halt for a busy endpoint\n"); + } else if (qh->qh_state == QH_STATE_IDLE) { + qh->hw_token &= ~cpu_to_hc32(ehci, QTD_TOGGLE); + } else { + /* It's not safe to write into the overlay area + * while the QH is active. Unlink it first and + * wait for the unlink to complete. + */ + if (qh->qh_state == QH_STATE_LINKED) { + if (eptype == USB_ENDPOINT_XFER_BULK) { + unlink_async(ehci, qh); + } else { + intr_deschedule(ehci, qh); + (void) qh_schedule(ehci, qh); + } + } + spin_unlock_irq(&ehci->lock); + schedule_timeout_uninterruptible(1); + goto rescan; + } + } + spin_unlock_irq(&ehci->lock); +} + static int ehci_get_frame (struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); @@ -1097,7 +1142,7 @@ static int __init ehci_hcd_init(void) sizeof(struct ehci_itd), sizeof(struct ehci_sitd)); #ifdef DEBUG - ehci_debug_root = debugfs_create_dir("ehci", NULL); + ehci_debug_root = debugfs_create_dir("ehci", usb_debug_root); if (!ehci_debug_root) { retval = -ENOENT; goto err_debug; diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 97a53a48a3d8..f46ad27c9a90 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -391,7 +391,7 @@ static inline void create_companion_file(struct ehci_hcd *ehci) /* with integrated TT there is no companion! */ if (!ehci_is_TDI(ehci)) - i = device_create_file(ehci_to_hcd(ehci)->self.dev, + i = device_create_file(ehci_to_hcd(ehci)->self.controller, &dev_attr_companion); } @@ -399,7 +399,7 @@ static inline void remove_companion_file(struct ehci_hcd *ehci) { /* with integrated TT there is no companion! */ if (!ehci_is_TDI(ehci)) - device_remove_file(ehci_to_hcd(ehci)->self.dev, + device_remove_file(ehci_to_hcd(ehci)->self.controller, &dev_attr_companion); } diff --git a/drivers/usb/host/ehci-ixp4xx.c b/drivers/usb/host/ehci-ixp4xx.c index 9c32063a0c2f..a44bb4a94954 100644 --- a/drivers/usb/host/ehci-ixp4xx.c +++ b/drivers/usb/host/ehci-ixp4xx.c @@ -51,6 +51,7 @@ static const struct hc_driver ixp4xx_ehci_hc_driver = { .urb_enqueue = ehci_urb_enqueue, .urb_dequeue = ehci_urb_dequeue, .endpoint_disable = ehci_endpoint_disable, + .endpoint_reset = ehci_endpoint_reset, .get_frame_number = ehci_get_frame, .hub_status_data = ehci_hub_status_data, .hub_control = ehci_hub_control, diff --git a/drivers/usb/host/ehci-orion.c b/drivers/usb/host/ehci-orion.c index 9d487908012e..770dd9aba62a 100644 --- a/drivers/usb/host/ehci-orion.c +++ b/drivers/usb/host/ehci-orion.c @@ -149,6 +149,7 @@ static const struct hc_driver ehci_orion_hc_driver = { .urb_enqueue = ehci_urb_enqueue, .urb_dequeue = ehci_urb_dequeue, .endpoint_disable = ehci_endpoint_disable, + .endpoint_reset = ehci_endpoint_reset, /* * scheduling support @@ -187,7 +188,7 @@ ehci_orion_conf_mbus_windows(struct usb_hcd *hcd, } } -static int __init ehci_orion_drv_probe(struct platform_device *pdev) +static int __devinit ehci_orion_drv_probe(struct platform_device *pdev) { struct orion_ehci_data *pd = pdev->dev.platform_data; struct resource *res; diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index 5aa8bce90e1f..f3683e1da161 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -268,7 +268,7 @@ done: * Also they depend on separate root hub suspend/resume. */ -static int ehci_pci_suspend(struct usb_hcd *hcd, pm_message_t message) +static int ehci_pci_suspend(struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); unsigned long flags; @@ -293,12 +293,6 @@ static int ehci_pci_suspend(struct usb_hcd *hcd, pm_message_t message) ehci_writel(ehci, 0, &ehci->regs->intr_enable); (void)ehci_readl(ehci, &ehci->regs->intr_enable); - /* make sure snapshot being resumed re-enumerates everything */ - if (message.event == PM_EVENT_PRETHAW) { - ehci_halt(ehci); - ehci_reset(ehci); - } - clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); bail: spin_unlock_irqrestore (&ehci->lock, flags); @@ -309,7 +303,7 @@ static int ehci_pci_suspend(struct usb_hcd *hcd, pm_message_t message) return rc; } -static int ehci_pci_resume(struct usb_hcd *hcd) +static int ehci_pci_resume(struct usb_hcd *hcd, bool hibernated) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); struct pci_dev *pdev = to_pci_dev(hcd->self.controller); @@ -322,10 +316,12 @@ static int ehci_pci_resume(struct usb_hcd *hcd) /* Mark hardware accessible again as we are out of D3 state by now */ set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - /* If CF is still set, we maintained PCI Vaux power. + /* If CF is still set and we aren't resuming from hibernation + * then we maintained PCI Vaux power. * Just undo the effect of ehci_pci_suspend(). */ - if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) { + if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF && + !hibernated) { int mask = INTR_MASK; if (!hcd->self.root_hub->do_remote_wakeup) @@ -335,7 +331,6 @@ static int ehci_pci_resume(struct usb_hcd *hcd) return 0; } - ehci_dbg(ehci, "lost power, restarting\n"); usb_root_hub_lost_power(hcd->self.root_hub); /* Else reset, to cope with power loss or flush-to-storage @@ -393,6 +388,7 @@ static const struct hc_driver ehci_pci_hc_driver = { .urb_enqueue = ehci_urb_enqueue, .urb_dequeue = ehci_urb_dequeue, .endpoint_disable = ehci_endpoint_disable, + .endpoint_reset = ehci_endpoint_reset, /* * scheduling support @@ -429,10 +425,11 @@ static struct pci_driver ehci_pci_driver = { .probe = usb_hcd_pci_probe, .remove = usb_hcd_pci_remove, - -#ifdef CONFIG_PM - .suspend = usb_hcd_pci_suspend, - .resume = usb_hcd_pci_resume, -#endif .shutdown = usb_hcd_pci_shutdown, + +#ifdef CONFIG_PM_SLEEP + .driver = { + .pm = &usb_hcd_pci_pm_ops + }, +#endif }; diff --git a/drivers/usb/host/ehci-ppc-of.c b/drivers/usb/host/ehci-ppc-of.c index ef732b704f53..fbd272288fc2 100644 --- a/drivers/usb/host/ehci-ppc-of.c +++ b/drivers/usb/host/ehci-ppc-of.c @@ -61,6 +61,7 @@ static const struct hc_driver ehci_ppc_of_hc_driver = { .urb_enqueue = ehci_urb_enqueue, .urb_dequeue = ehci_urb_dequeue, .endpoint_disable = ehci_endpoint_disable, + .endpoint_reset = ehci_endpoint_reset, /* * scheduling support diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c index 1ba9f9a8c308..93f7035d00a1 100644 --- a/drivers/usb/host/ehci-ps3.c +++ b/drivers/usb/host/ehci-ps3.c @@ -65,6 +65,7 @@ static const struct hc_driver ps3_ehci_hc_driver = { .urb_enqueue = ehci_urb_enqueue, .urb_dequeue = ehci_urb_dequeue, .endpoint_disable = ehci_endpoint_disable, + .endpoint_reset = ehci_endpoint_reset, .get_frame_number = ehci_get_frame, .hub_status_data = ehci_hub_status_data, .hub_control = ehci_hub_control, @@ -76,7 +77,7 @@ static const struct hc_driver ps3_ehci_hc_driver = { .port_handed_over = ehci_port_handed_over, }; -static int ps3_ehci_probe(struct ps3_system_bus_device *dev) +static int __devinit ps3_ehci_probe(struct ps3_system_bus_device *dev) { int result; struct usb_hcd *hcd; @@ -162,7 +163,7 @@ static int ps3_ehci_probe(struct ps3_system_bus_device *dev) dev_dbg(&dev->core, "%s:%d: virq %lu\n", __func__, __LINE__, (unsigned long)virq); - ps3_system_bus_set_driver_data(dev, hcd); + ps3_system_bus_set_drvdata(dev, hcd); result = usb_add_hcd(hcd, virq, IRQF_DISABLED); @@ -195,8 +196,7 @@ fail_start: static int ps3_ehci_remove(struct ps3_system_bus_device *dev) { unsigned int tmp; - struct usb_hcd *hcd = - (struct usb_hcd *)ps3_system_bus_get_driver_data(dev); + struct usb_hcd *hcd = ps3_system_bus_get_drvdata(dev); BUG_ON(!hcd); @@ -208,7 +208,7 @@ static int ps3_ehci_remove(struct ps3_system_bus_device *dev) ehci_shutdown(hcd); usb_remove_hcd(hcd); - ps3_system_bus_set_driver_data(dev, NULL); + ps3_system_bus_set_drvdata(dev, NULL); BUG_ON(!hcd->regs); iounmap(hcd->regs); @@ -225,7 +225,7 @@ static int ps3_ehci_remove(struct ps3_system_bus_device *dev) return 0; } -static int ps3_ehci_driver_register(struct ps3_system_bus_driver *drv) +static int __init ps3_ehci_driver_register(struct ps3_system_bus_driver *drv) { return firmware_has_feature(FW_FEATURE_PS3_LV1) ? ps3_system_bus_driver_register(drv) diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 1976b1b3778c..3192f683f807 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -93,22 +93,6 @@ qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd) qh->hw_qtd_next = QTD_NEXT(ehci, qtd->qtd_dma); qh->hw_alt_next = EHCI_LIST_END(ehci); - /* Except for control endpoints, we make hardware maintain data - * toggle (like OHCI) ... here (re)initialize the toggle in the QH, - * and set the pseudo-toggle in udev. Only usb_clear_halt() will - * ever clear it. - */ - if (!(qh->hw_info1 & cpu_to_hc32(ehci, 1 << 14))) { - unsigned is_out, epnum; - - is_out = !(qtd->hw_token & cpu_to_hc32(ehci, 1 << 8)); - epnum = (hc32_to_cpup(ehci, &qh->hw_info1) >> 8) & 0x0f; - if (unlikely (!usb_gettoggle (qh->dev, epnum, is_out))) { - qh->hw_token &= ~cpu_to_hc32(ehci, QTD_TOGGLE); - usb_settoggle (qh->dev, epnum, is_out, 1); - } - } - /* HC must see latest qtd and qh data before we clear ACTIVE+HALT */ wmb (); qh->hw_token &= cpu_to_hc32(ehci, QTD_TOGGLE | QTD_STS_PING); @@ -850,7 +834,6 @@ done: qh->qh_state = QH_STATE_IDLE; qh->hw_info1 = cpu_to_hc32(ehci, info1); qh->hw_info2 = cpu_to_hc32(ehci, info2); - usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1); qh_refresh (ehci, qh); return qh; } @@ -881,7 +864,7 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh) } } - /* clear halt and/or toggle; and maybe recover from silicon quirk */ + /* clear halt and maybe recover from silicon quirk */ if (qh->qh_state == QH_STATE_IDLE) qh_refresh (ehci, qh); diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 556d0ec0c1f8..9d1babc7ff65 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -760,8 +760,10 @@ static int qh_schedule(struct ehci_hcd *ehci, struct ehci_qh *qh) if (status) { /* "normal" case, uframing flexible except with splits */ if (qh->period) { - frame = qh->period - 1; - do { + int i; + + for (i = qh->period; status && i > 0; --i) { + frame = ++ehci->random_frame % qh->period; for (uframe = 0; uframe < 8; uframe++) { status = check_intr_schedule (ehci, frame, uframe, qh, @@ -769,7 +771,7 @@ static int qh_schedule(struct ehci_hcd *ehci, struct ehci_qh *qh) if (status == 0) break; } - } while (status && frame--); + } /* qh->period == 0 means every uframe */ } else { diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 6cff195e1a36..90ad3395bb21 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -116,6 +116,7 @@ struct ehci_hcd { /* one per controller */ struct timer_list watchdog; unsigned long actions; unsigned stamp; + unsigned random_frame; unsigned long next_statechange; u32 command; diff --git a/drivers/usb/host/fhci-dbg.c b/drivers/usb/host/fhci-dbg.c index ea8a4255c5da..e799f86dab11 100644 --- a/drivers/usb/host/fhci-dbg.c +++ b/drivers/usb/host/fhci-dbg.c @@ -108,7 +108,7 @@ void fhci_dfs_create(struct fhci_hcd *fhci) { struct device *dev = fhci_to_hcd(fhci)->self.controller; - fhci->dfs_root = debugfs_create_dir(dev_name(dev), NULL); + fhci->dfs_root = debugfs_create_dir(dev_name(dev), usb_debug_root); if (!fhci->dfs_root) { WARN_ON(1); return; diff --git a/drivers/usb/host/hwa-hc.c b/drivers/usb/host/hwa-hc.c index cbf30e515f29..88b03214622b 100644 --- a/drivers/usb/host/hwa-hc.c +++ b/drivers/usb/host/hwa-hc.c @@ -172,25 +172,6 @@ error_cluster_id_get: } -static int hwahc_op_suspend(struct usb_hcd *usb_hcd, pm_message_t msg) -{ - struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); - struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); - dev_err(wusbhc->dev, "%s (%p [%p], 0x%lx) UNIMPLEMENTED\n", __func__, - usb_hcd, hwahc, *(unsigned long *) &msg); - return -ENOSYS; -} - -static int hwahc_op_resume(struct usb_hcd *usb_hcd) -{ - struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); - struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); - - dev_err(wusbhc->dev, "%s (%p [%p]) UNIMPLEMENTED\n", __func__, - usb_hcd, hwahc); - return -ENOSYS; -} - /* * No need to abort pipes, as when this is called, all the children * has been disconnected and that has done it [through @@ -598,8 +579,6 @@ static struct hc_driver hwahc_hc_driver = { .flags = HCD_USB2, /* FIXME */ .reset = hwahc_op_reset, .start = hwahc_op_start, - .pci_suspend = hwahc_op_suspend, - .pci_resume = hwahc_op_resume, .stop = hwahc_op_stop, .get_frame_number = hwahc_op_get_frame_number, .urb_enqueue = hwahc_op_urb_enqueue, diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c index d3269656aa4d..811f5dfdc582 100644 --- a/drivers/usb/host/ohci-dbg.c +++ b/drivers/usb/host/ohci-dbg.c @@ -431,7 +431,7 @@ static struct dentry *ohci_debug_root; struct debug_buffer { ssize_t (*fill_func)(struct debug_buffer *); /* fill method */ - struct device *dev; + struct ohci_hcd *ohci; struct mutex mutex; /* protect filling of buffer */ size_t count; /* number of characters filled into buffer */ char *page; @@ -505,15 +505,11 @@ show_list (struct ohci_hcd *ohci, char *buf, size_t count, struct ed *ed) static ssize_t fill_async_buffer(struct debug_buffer *buf) { - struct usb_bus *bus; - struct usb_hcd *hcd; struct ohci_hcd *ohci; size_t temp; unsigned long flags; - bus = dev_get_drvdata(buf->dev); - hcd = bus_to_hcd(bus); - ohci = hcd_to_ohci(hcd); + ohci = buf->ohci; /* display control and bulk lists together, for simplicity */ spin_lock_irqsave (&ohci->lock, flags); @@ -529,8 +525,6 @@ static ssize_t fill_async_buffer(struct debug_buffer *buf) static ssize_t fill_periodic_buffer(struct debug_buffer *buf) { - struct usb_bus *bus; - struct usb_hcd *hcd; struct ohci_hcd *ohci; struct ed **seen, *ed; unsigned long flags; @@ -542,9 +536,7 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf) return 0; seen_count = 0; - bus = (struct usb_bus *)dev_get_drvdata(buf->dev); - hcd = bus_to_hcd(bus); - ohci = hcd_to_ohci(hcd); + ohci = buf->ohci; next = buf->page; size = PAGE_SIZE; @@ -626,7 +618,6 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf) static ssize_t fill_registers_buffer(struct debug_buffer *buf) { - struct usb_bus *bus; struct usb_hcd *hcd; struct ohci_hcd *ohci; struct ohci_regs __iomem *regs; @@ -635,9 +626,8 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf) char *next; u32 rdata; - bus = (struct usb_bus *)dev_get_drvdata(buf->dev); - hcd = bus_to_hcd(bus); - ohci = hcd_to_ohci(hcd); + ohci = buf->ohci; + hcd = ohci_to_hcd(ohci); regs = ohci->regs; next = buf->page; size = PAGE_SIZE; @@ -710,7 +700,7 @@ done: return PAGE_SIZE - size; } -static struct debug_buffer *alloc_buffer(struct device *dev, +static struct debug_buffer *alloc_buffer(struct ohci_hcd *ohci, ssize_t (*fill_func)(struct debug_buffer *)) { struct debug_buffer *buf; @@ -718,7 +708,7 @@ static struct debug_buffer *alloc_buffer(struct device *dev, buf = kzalloc(sizeof(struct debug_buffer), GFP_KERNEL); if (buf) { - buf->dev = dev; + buf->ohci = ohci; buf->fill_func = fill_func; mutex_init(&buf->mutex); } @@ -810,26 +800,25 @@ static int debug_registers_open(struct inode *inode, struct file *file) static inline void create_debug_files (struct ohci_hcd *ohci) { struct usb_bus *bus = &ohci_to_hcd(ohci)->self; - struct device *dev = bus->dev; ohci->debug_dir = debugfs_create_dir(bus->bus_name, ohci_debug_root); if (!ohci->debug_dir) goto dir_error; ohci->debug_async = debugfs_create_file("async", S_IRUGO, - ohci->debug_dir, dev, + ohci->debug_dir, ohci, &debug_async_fops); if (!ohci->debug_async) goto async_error; ohci->debug_periodic = debugfs_create_file("periodic", S_IRUGO, - ohci->debug_dir, dev, + ohci->debug_dir, ohci, &debug_periodic_fops); if (!ohci->debug_periodic) goto periodic_error; ohci->debug_registers = debugfs_create_file("registers", S_IRUGO, - ohci->debug_dir, dev, + ohci->debug_dir, ohci, &debug_registers_fops); if (!ohci->debug_registers) goto registers_error; diff --git a/drivers/usb/host/ohci-ep93xx.c b/drivers/usb/host/ohci-ep93xx.c index 7cf74f8c2db1..b0dbf4157d29 100644 --- a/drivers/usb/host/ohci-ep93xx.c +++ b/drivers/usb/host/ohci-ep93xx.c @@ -47,7 +47,7 @@ static int usb_hcd_ep93xx_probe(const struct hc_driver *driver, struct usb_hcd *hcd; if (pdev->resource[1].flags != IORESOURCE_IRQ) { - pr_debug("resource[1] is not IORESOURCE_IRQ"); + dbg("resource[1] is not IORESOURCE_IRQ"); return -ENOMEM; } @@ -65,12 +65,18 @@ static int usb_hcd_ep93xx_probe(const struct hc_driver *driver, hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); if (hcd->regs == NULL) { - pr_debug("ioremap failed"); + dbg("ioremap failed"); retval = -ENOMEM; goto err2; } - usb_host_clock = clk_get(&pdev->dev, "usb_host"); + usb_host_clock = clk_get(&pdev->dev, NULL); + if (IS_ERR(usb_host_clock)) { + dbg("clk_get failed"); + retval = PTR_ERR(usb_host_clock); + goto err3; + } + ep93xx_start_hc(&pdev->dev); ohci_hcd_init(hcd_to_ohci(hcd)); @@ -80,6 +86,7 @@ static int usb_hcd_ep93xx_probe(const struct hc_driver *driver, return retval; ep93xx_stop_hc(&pdev->dev); +err3: iounmap(hcd->regs); err2: release_mem_region(hcd->rsrc_start, hcd->rsrc_len); diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 25db704f3a2a..58151687d351 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -571,7 +571,7 @@ static int ohci_init (struct ohci_hcd *ohci) */ static int ohci_run (struct ohci_hcd *ohci) { - u32 mask, temp; + u32 mask, val; int first = ohci->fminterval == 0; struct usb_hcd *hcd = ohci_to_hcd(ohci); @@ -580,8 +580,8 @@ static int ohci_run (struct ohci_hcd *ohci) /* boot firmware should have set this up (5.1.1.3.1) */ if (first) { - temp = ohci_readl (ohci, &ohci->regs->fminterval); - ohci->fminterval = temp & 0x3fff; + val = ohci_readl (ohci, &ohci->regs->fminterval); + ohci->fminterval = val & 0x3fff; if (ohci->fminterval != FI) ohci_dbg (ohci, "fminterval delta %d\n", ohci->fminterval - FI); @@ -600,25 +600,25 @@ static int ohci_run (struct ohci_hcd *ohci) switch (ohci->hc_control & OHCI_CTRL_HCFS) { case OHCI_USB_OPER: - temp = 0; + val = 0; break; case OHCI_USB_SUSPEND: case OHCI_USB_RESUME: ohci->hc_control &= OHCI_CTRL_RWC; ohci->hc_control |= OHCI_USB_RESUME; - temp = 10 /* msec wait */; + val = 10 /* msec wait */; break; // case OHCI_USB_RESET: default: ohci->hc_control &= OHCI_CTRL_RWC; ohci->hc_control |= OHCI_USB_RESET; - temp = 50 /* msec wait */; + val = 50 /* msec wait */; break; } ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); // flush the writes (void) ohci_readl (ohci, &ohci->regs->control); - msleep(temp); + msleep(val); memset (ohci->hcca, 0, sizeof (struct ohci_hcca)); @@ -628,9 +628,9 @@ static int ohci_run (struct ohci_hcd *ohci) retry: /* HC Reset requires max 10 us delay */ ohci_writel (ohci, OHCI_HCR, &ohci->regs->cmdstatus); - temp = 30; /* ... allow extra time */ + val = 30; /* ... allow extra time */ while ((ohci_readl (ohci, &ohci->regs->cmdstatus) & OHCI_HCR) != 0) { - if (--temp == 0) { + if (--val == 0) { spin_unlock_irq (&ohci->lock); ohci_err (ohci, "USB HC reset timed out!\n"); return -1; @@ -699,23 +699,23 @@ retry: ohci_writel (ohci, mask, &ohci->regs->intrenable); /* handle root hub init quirks ... */ - temp = roothub_a (ohci); - temp &= ~(RH_A_PSM | RH_A_OCPM); + val = roothub_a (ohci); + val &= ~(RH_A_PSM | RH_A_OCPM); if (ohci->flags & OHCI_QUIRK_SUPERIO) { /* NSC 87560 and maybe others */ - temp |= RH_A_NOCP; - temp &= ~(RH_A_POTPGT | RH_A_NPS); - ohci_writel (ohci, temp, &ohci->regs->roothub.a); + val |= RH_A_NOCP; + val &= ~(RH_A_POTPGT | RH_A_NPS); + ohci_writel (ohci, val, &ohci->regs->roothub.a); } else if ((ohci->flags & OHCI_QUIRK_AMD756) || (ohci->flags & OHCI_QUIRK_HUB_POWER)) { /* hub power always on; required for AMD-756 and some * Mac platforms. ganged overcurrent reporting, if any. */ - temp |= RH_A_NPS; - ohci_writel (ohci, temp, &ohci->regs->roothub.a); + val |= RH_A_NPS; + ohci_writel (ohci, val, &ohci->regs->roothub.a); } ohci_writel (ohci, RH_HS_LPSC, &ohci->regs->roothub.status); - ohci_writel (ohci, (temp & RH_A_NPS) ? 0 : RH_B_PPCM, + ohci_writel (ohci, (val & RH_A_NPS) ? 0 : RH_B_PPCM, &ohci->regs->roothub.b); // flush those writes (void) ohci_readl (ohci, &ohci->regs->control); @@ -724,7 +724,7 @@ retry: spin_unlock_irq (&ohci->lock); // POTPGT delay is bits 24-31, in 2 ms units. - mdelay ((temp >> 23) & 0x1fe); + mdelay ((val >> 23) & 0x1fe); hcd->state = HC_STATE_RUNNING; if (quirk_zfmicro(ohci)) { @@ -1105,7 +1105,7 @@ static int __init ohci_hcd_mod_init(void) set_bit(USB_OHCI_LOADED, &usb_hcds_loaded); #ifdef DEBUG - ohci_debug_root = debugfs_create_dir("ohci", NULL); + ohci_debug_root = debugfs_create_dir("ohci", usb_debug_root); if (!ohci_debug_root) { retval = -ENOENT; goto error_debug; diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index f9961b4c0da3..d2ba04dd785e 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c @@ -372,7 +372,7 @@ static int __devinit ohci_pci_start (struct usb_hcd *hcd) #ifdef CONFIG_PM -static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message) +static int ohci_pci_suspend(struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); unsigned long flags; @@ -394,10 +394,6 @@ static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message) ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); (void)ohci_readl(ohci, &ohci->regs->intrdisable); - /* make sure snapshot being resumed re-enumerates everything */ - if (message.event == PM_EVENT_PRETHAW) - ohci_usb_reset(ohci); - clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); bail: spin_unlock_irqrestore (&ohci->lock, flags); @@ -406,9 +402,14 @@ static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message) } -static int ohci_pci_resume (struct usb_hcd *hcd) +static int ohci_pci_resume(struct usb_hcd *hcd, bool hibernated) { set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + + /* Make sure resume from hibernation re-enumerates everything */ + if (hibernated) + ohci_usb_reset(hcd_to_ohci(hcd)); + ohci_finish_controller_resume(hcd); return 0; } @@ -484,12 +485,11 @@ static struct pci_driver ohci_pci_driver = { .probe = usb_hcd_pci_probe, .remove = usb_hcd_pci_remove, - -#ifdef CONFIG_PM - .suspend = usb_hcd_pci_suspend, - .resume = usb_hcd_pci_resume, -#endif - .shutdown = usb_hcd_pci_shutdown, -}; +#ifdef CONFIG_PM_SLEEP + .driver = { + .pm = &usb_hcd_pci_pm_ops + }, +#endif +}; diff --git a/drivers/usb/host/ohci-ps3.c b/drivers/usb/host/ohci-ps3.c index 3d1910317328..700950455f4d 100644 --- a/drivers/usb/host/ohci-ps3.c +++ b/drivers/usb/host/ohci-ps3.c @@ -75,7 +75,7 @@ static const struct hc_driver ps3_ohci_hc_driver = { #endif }; -static int ps3_ohci_probe(struct ps3_system_bus_device *dev) +static int __devinit ps3_ohci_probe(struct ps3_system_bus_device *dev) { int result; struct usb_hcd *hcd; @@ -162,7 +162,7 @@ static int ps3_ohci_probe(struct ps3_system_bus_device *dev) dev_dbg(&dev->core, "%s:%d: virq %lu\n", __func__, __LINE__, (unsigned long)virq); - ps3_system_bus_set_driver_data(dev, hcd); + ps3_system_bus_set_drvdata(dev, hcd); result = usb_add_hcd(hcd, virq, IRQF_DISABLED); @@ -195,8 +195,7 @@ fail_start: static int ps3_ohci_remove(struct ps3_system_bus_device *dev) { unsigned int tmp; - struct usb_hcd *hcd = - (struct usb_hcd *)ps3_system_bus_get_driver_data(dev); + struct usb_hcd *hcd = ps3_system_bus_get_drvdata(dev); BUG_ON(!hcd); @@ -208,7 +207,7 @@ static int ps3_ohci_remove(struct ps3_system_bus_device *dev) ohci_shutdown(hcd); usb_remove_hcd(hcd); - ps3_system_bus_set_driver_data(dev, NULL); + ps3_system_bus_set_drvdata(dev, NULL); BUG_ON(!hcd->regs); iounmap(hcd->regs); @@ -225,7 +224,7 @@ static int ps3_ohci_remove(struct ps3_system_bus_device *dev) return 0; } -static int ps3_ohci_driver_register(struct ps3_system_bus_driver *drv) +static int __init ps3_ohci_driver_register(struct ps3_system_bus_driver *drv) { return firmware_has_feature(FW_FEATURE_PS3_LV1) ? ps3_system_bus_driver_register(drv) diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index 033c2846ce59..83b5f9cea85a 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -15,6 +15,7 @@ #include #include #include "pci-quirks.h" +#include "xhci-ext-caps.h" #define UHCI_USBLEGSUP 0xc0 /* legacy support */ @@ -341,7 +342,127 @@ static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev) return; } +/* + * handshake - spin reading a register until handshake completes + * @ptr: address of hc register to be read + * @mask: bits to look at in result of read + * @done: value of those bits when handshake succeeds + * @wait_usec: timeout in microseconds + * @delay_usec: delay in microseconds to wait between polling + * + * Polls a register every delay_usec microseconds. + * Returns 0 when the mask bits have the value done. + * Returns -ETIMEDOUT if this condition is not true after + * wait_usec microseconds have passed. + */ +static int handshake(void __iomem *ptr, u32 mask, u32 done, + int wait_usec, int delay_usec) +{ + u32 result; + do { + result = readl(ptr); + result &= mask; + if (result == done) + return 0; + udelay(delay_usec); + wait_usec -= delay_usec; + } while (wait_usec > 0); + return -ETIMEDOUT; +} + +/** + * PCI Quirks for xHCI. + * + * Takes care of the handoff between the Pre-OS (i.e. BIOS) and the OS. + * It signals to the BIOS that the OS wants control of the host controller, + * and then waits 5 seconds for the BIOS to hand over control. + * If we timeout, assume the BIOS is broken and take control anyway. + */ +static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev) +{ + void __iomem *base; + int ext_cap_offset; + void __iomem *op_reg_base; + u32 val; + int timeout; + + if (!mmio_resource_enabled(pdev, 0)) + return; + + base = ioremap_nocache(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + if (base == NULL) + return; + + /* + * Find the Legacy Support Capability register - + * this is optional for xHCI host controllers. + */ + ext_cap_offset = xhci_find_next_cap_offset(base, XHCI_HCC_PARAMS_OFFSET); + do { + if (!ext_cap_offset) + /* We've reached the end of the extended capabilities */ + goto hc_init; + val = readl(base + ext_cap_offset); + if (XHCI_EXT_CAPS_ID(val) == XHCI_EXT_CAPS_LEGACY) + break; + ext_cap_offset = xhci_find_next_cap_offset(base, ext_cap_offset); + } while (1); + + /* If the BIOS owns the HC, signal that the OS wants it, and wait */ + if (val & XHCI_HC_BIOS_OWNED) { + writel(val & XHCI_HC_OS_OWNED, base + ext_cap_offset); + + /* Wait for 5 seconds with 10 microsecond polling interval */ + timeout = handshake(base + ext_cap_offset, XHCI_HC_BIOS_OWNED, + 0, 5000, 10); + + /* Assume a buggy BIOS and take HC ownership anyway */ + if (timeout) { + dev_warn(&pdev->dev, "xHCI BIOS handoff failed" + " (BIOS bug ?) %08x\n", val); + writel(val & ~XHCI_HC_BIOS_OWNED, base + ext_cap_offset); + } + } + + /* Disable any BIOS SMIs */ + writel(XHCI_LEGACY_DISABLE_SMI, + base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET); + +hc_init: + op_reg_base = base + XHCI_HC_LENGTH(readl(base)); + + /* Wait for the host controller to be ready before writing any + * operational or runtime registers. Wait 5 seconds and no more. + */ + timeout = handshake(op_reg_base + XHCI_STS_OFFSET, XHCI_STS_CNR, 0, + 5000, 10); + /* Assume a buggy HC and start HC initialization anyway */ + if (timeout) { + val = readl(op_reg_base + XHCI_STS_OFFSET); + dev_warn(&pdev->dev, + "xHCI HW not ready after 5 sec (HC bug?) " + "status = 0x%x\n", val); + } + + /* Send the halt and disable interrupts command */ + val = readl(op_reg_base + XHCI_CMD_OFFSET); + val &= ~(XHCI_CMD_RUN | XHCI_IRQS); + writel(val, op_reg_base + XHCI_CMD_OFFSET); + + /* Wait for the HC to halt - poll every 125 usec (one microframe). */ + timeout = handshake(op_reg_base + XHCI_STS_OFFSET, XHCI_STS_HALT, 1, + XHCI_MAX_HALT_USEC, 125); + if (timeout) { + val = readl(op_reg_base + XHCI_STS_OFFSET); + dev_warn(&pdev->dev, + "xHCI HW did not halt within %d usec " + "status = 0x%x\n", XHCI_MAX_HALT_USEC, val); + } + + iounmap(base); +} static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev) { @@ -351,5 +472,7 @@ static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev) quirk_usb_handoff_ohci(pdev); else if (pdev->class == PCI_CLASS_SERIAL_USB_EHCI) quirk_usb_disable_ehci(pdev); + else if (pdev->class == PCI_CLASS_SERIAL_USB_XHCI) + quirk_usb_handoff_xhci(pdev); } DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_usb_early_handoff); diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index f1626e58c141..56976cc0352a 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -46,31 +46,10 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Yoshihiro Shimoda"); MODULE_ALIAS("platform:r8a66597_hcd"); -#define DRIVER_VERSION "10 Apr 2008" +#define DRIVER_VERSION "2009-05-26" static const char hcd_name[] = "r8a66597_hcd"; -/* module parameters */ -#if !defined(CONFIG_SUPERH_ON_CHIP_R8A66597) -static unsigned short clock = XTAL12; -module_param(clock, ushort, 0644); -MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0 " - "(default=0)"); -#endif - -static unsigned short vif = LDRV; -module_param(vif, ushort, 0644); -MODULE_PARM_DESC(vif, "input VIF: 3.3V=32768, 1.5V=0(default=32768)"); - -static unsigned short endian; -module_param(endian, ushort, 0644); -MODULE_PARM_DESC(endian, "data endian: big=256, little=0 (default=0)"); - -static unsigned short irq_sense = 0xff; -module_param(irq_sense, ushort, 0644); -MODULE_PARM_DESC(irq_sense, "IRQ sense: low level=32, falling edge=0 " - "(default=32)"); - static void packet_write(struct r8a66597 *r8a66597, u16 pipenum); static int r8a66597_get_frame(struct usb_hcd *hcd); @@ -136,7 +115,8 @@ static int r8a66597_clock_enable(struct r8a66597 *r8a66597) } } while ((tmp & USBE) != USBE); r8a66597_bclr(r8a66597, USBE, SYSCFG0); - r8a66597_mdfy(r8a66597, clock, XTAL, SYSCFG0); + r8a66597_mdfy(r8a66597, get_xtal_from_pdata(r8a66597->pdata), XTAL, + SYSCFG0); i = 0; r8a66597_bset(r8a66597, XCKE, SYSCFG0); @@ -203,6 +183,9 @@ static void r8a66597_disable_port(struct r8a66597 *r8a66597, int port) static int enable_controller(struct r8a66597 *r8a66597) { int ret, port; + u16 vif = r8a66597->pdata->vif ? LDRV : 0; + u16 irq_sense = r8a66597->irq_sense_low ? INTL : 0; + u16 endian = r8a66597->pdata->endian ? BIGEND : 0; ret = r8a66597_clock_enable(r8a66597); if (ret < 0) @@ -2373,7 +2356,7 @@ static int __init_or_module r8a66597_remove(struct platform_device *pdev) return 0; } -static int __init r8a66597_probe(struct platform_device *pdev) +static int __devinit r8a66597_probe(struct platform_device *pdev) { #if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) && defined(CONFIG_HAVE_CLK) char clk_name[8]; @@ -2418,6 +2401,12 @@ static int __init r8a66597_probe(struct platform_device *pdev) goto clean_up; } + if (pdev->dev.platform_data == NULL) { + dev_err(&pdev->dev, "no platform data\n"); + ret = -ENODEV; + goto clean_up; + } + /* initialize hcd */ hcd = usb_create_hcd(&r8a66597_hc_driver, &pdev->dev, (char *)hcd_name); if (!hcd) { @@ -2428,6 +2417,8 @@ static int __init r8a66597_probe(struct platform_device *pdev) r8a66597 = hcd_to_r8a66597(hcd); memset(r8a66597, 0, sizeof(struct r8a66597)); dev_set_drvdata(&pdev->dev, r8a66597); + r8a66597->pdata = pdev->dev.platform_data; + r8a66597->irq_sense_low = irq_trigger == IRQF_TRIGGER_LOW; #if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) && defined(CONFIG_HAVE_CLK) snprintf(clk_name, sizeof(clk_name), "usb%d", pdev->id); @@ -2458,29 +2449,6 @@ static int __init r8a66597_probe(struct platform_device *pdev) hcd->rsrc_start = res->start; - /* irq_sense setting on cmdline takes precedence over resource - * settings, so the introduction of irqflags in IRQ resourse - * won't disturb existing setups */ - switch (irq_sense) { - case INTL: - irq_trigger = IRQF_TRIGGER_LOW; - break; - case 0: - irq_trigger = IRQF_TRIGGER_FALLING; - break; - case 0xff: - if (irq_trigger) - irq_sense = (irq_trigger & IRQF_TRIGGER_LOW) ? - INTL : 0; - else { - irq_sense = INTL; - irq_trigger = IRQF_TRIGGER_LOW; - } - break; - default: - dev_err(&pdev->dev, "Unknown irq_sense value.\n"); - } - ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | irq_trigger); if (ret != 0) { dev_err(&pdev->dev, "Failed to add hcd\n"); diff --git a/drivers/usb/host/r8a66597.h b/drivers/usb/host/r8a66597.h index f49208f1bb74..d72680b433f9 100644 --- a/drivers/usb/host/r8a66597.h +++ b/drivers/usb/host/r8a66597.h @@ -30,6 +30,8 @@ #include #endif +#include + #define SYSCFG0 0x00 #define SYSCFG1 0x02 #define SYSSTS0 0x04 @@ -488,6 +490,7 @@ struct r8a66597 { #if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) && defined(CONFIG_HAVE_CLK) struct clk *clk; #endif + struct r8a66597_platdata *pdata; struct r8a66597_device device0; struct r8a66597_root_hub root_hub[R8A66597_MAX_ROOT_HUB]; struct list_head pipe_queue[R8A66597_MAX_NUM_PIPE]; @@ -506,6 +509,7 @@ struct r8a66597 { unsigned long child_connect_map[4]; unsigned bus_suspended:1; + unsigned irq_sense_low:1; }; static inline struct r8a66597 *hcd_to_r8a66597(struct usb_hcd *hcd) @@ -660,10 +664,36 @@ static inline void r8a66597_port_power(struct r8a66597 *r8a66597, int port, { unsigned long dvstctr_reg = get_dvstctr_reg(port); - if (power) - r8a66597_bset(r8a66597, VBOUT, dvstctr_reg); - else - r8a66597_bclr(r8a66597, VBOUT, dvstctr_reg); + if (r8a66597->pdata->port_power) { + r8a66597->pdata->port_power(port, power); + } else { + if (power) + r8a66597_bset(r8a66597, VBOUT, dvstctr_reg); + else + r8a66597_bclr(r8a66597, VBOUT, dvstctr_reg); + } +} + +static inline u16 get_xtal_from_pdata(struct r8a66597_platdata *pdata) +{ + u16 clock = 0; + + switch (pdata->xtal) { + case R8A66597_PLATDATA_XTAL_12MHZ: + clock = XTAL12; + break; + case R8A66597_PLATDATA_XTAL_24MHZ: + clock = XTAL24; + break; + case R8A66597_PLATDATA_XTAL_48MHZ: + clock = XTAL48; + break; + default: + printk(KERN_ERR "r8a66597: platdata clock is wrong.\n"); + break; + } + + return clock; } #define get_pipectr_addr(pipenum) (PIPE1CTR + (pipenum - 1) * 2) diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index cf5e4cf7ea42..274751b4409c 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -769,7 +769,7 @@ static int uhci_rh_resume(struct usb_hcd *hcd) return rc; } -static int uhci_pci_suspend(struct usb_hcd *hcd, pm_message_t message) +static int uhci_pci_suspend(struct usb_hcd *hcd) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); int rc = 0; @@ -795,10 +795,6 @@ static int uhci_pci_suspend(struct usb_hcd *hcd, pm_message_t message) /* FIXME: Enable non-PME# remote wakeup? */ - /* make sure snapshot being resumed re-enumerates everything */ - if (message.event == PM_EVENT_PRETHAW) - uhci_hc_died(uhci); - done_okay: clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); done: @@ -806,7 +802,7 @@ done: return rc; } -static int uhci_pci_resume(struct usb_hcd *hcd) +static int uhci_pci_resume(struct usb_hcd *hcd, bool hibernated) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); @@ -820,6 +816,10 @@ static int uhci_pci_resume(struct usb_hcd *hcd) spin_lock_irq(&uhci->lock); + /* Make sure resume from hibernation re-enumerates everything */ + if (hibernated) + uhci_hc_died(uhci); + /* FIXME: Disable non-PME# remote wakeup? */ /* The firmware or a boot kernel may have changed the controller @@ -940,10 +940,11 @@ static struct pci_driver uhci_pci_driver = { .remove = usb_hcd_pci_remove, .shutdown = uhci_shutdown, -#ifdef CONFIG_PM - .suspend = usb_hcd_pci_suspend, - .resume = usb_hcd_pci_resume, -#endif /* PM */ +#ifdef CONFIG_PM_SLEEP + .driver = { + .pm = &usb_hcd_pci_pm_ops + }, +#endif }; static int __init uhci_hcd_init(void) @@ -961,7 +962,7 @@ static int __init uhci_hcd_init(void) errbuf = kmalloc(ERRBUF_LEN, GFP_KERNEL); if (!errbuf) goto errbuf_failed; - uhci_debugfs_root = debugfs_create_dir("uhci", NULL); + uhci_debugfs_root = debugfs_create_dir("uhci", usb_debug_root); if (!uhci_debugfs_root) goto debug_failed; } diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index 3e5807d14ffb..64e57bfe236b 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -260,7 +260,7 @@ static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci, INIT_LIST_HEAD(&qh->node); if (udev) { /* Normal QH */ - qh->type = hep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; + qh->type = usb_endpoint_type(&hep->desc); if (qh->type != USB_ENDPOINT_XFER_ISOC) { qh->dummy_td = uhci_alloc_td(uhci); if (!qh->dummy_td) { diff --git a/drivers/usb/host/xhci-dbg.c b/drivers/usb/host/xhci-dbg.c new file mode 100644 index 000000000000..2501c571f855 --- /dev/null +++ b/drivers/usb/host/xhci-dbg.c @@ -0,0 +1,485 @@ +/* + * xHCI host controller driver + * + * Copyright (C) 2008 Intel Corp. + * + * Author: Sarah Sharp + * Some code borrowed from the Linux EHCI driver. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "xhci.h" + +#define XHCI_INIT_VALUE 0x0 + +/* Add verbose debugging later, just print everything for now */ + +void xhci_dbg_regs(struct xhci_hcd *xhci) +{ + u32 temp; + + xhci_dbg(xhci, "// xHCI capability registers at %p:\n", + xhci->cap_regs); + temp = xhci_readl(xhci, &xhci->cap_regs->hc_capbase); + xhci_dbg(xhci, "// @%p = 0x%x (CAPLENGTH AND HCIVERSION)\n", + &xhci->cap_regs->hc_capbase, temp); + xhci_dbg(xhci, "// CAPLENGTH: 0x%x\n", + (unsigned int) HC_LENGTH(temp)); +#if 0 + xhci_dbg(xhci, "// HCIVERSION: 0x%x\n", + (unsigned int) HC_VERSION(temp)); +#endif + + xhci_dbg(xhci, "// xHCI operational registers at %p:\n", xhci->op_regs); + + temp = xhci_readl(xhci, &xhci->cap_regs->run_regs_off); + xhci_dbg(xhci, "// @%p = 0x%x RTSOFF\n", + &xhci->cap_regs->run_regs_off, + (unsigned int) temp & RTSOFF_MASK); + xhci_dbg(xhci, "// xHCI runtime registers at %p:\n", xhci->run_regs); + + temp = xhci_readl(xhci, &xhci->cap_regs->db_off); + xhci_dbg(xhci, "// @%p = 0x%x DBOFF\n", &xhci->cap_regs->db_off, temp); + xhci_dbg(xhci, "// Doorbell array at %p:\n", xhci->dba); +} + +static void xhci_print_cap_regs(struct xhci_hcd *xhci) +{ + u32 temp; + + xhci_dbg(xhci, "xHCI capability registers at %p:\n", xhci->cap_regs); + + temp = xhci_readl(xhci, &xhci->cap_regs->hc_capbase); + xhci_dbg(xhci, "CAPLENGTH AND HCIVERSION 0x%x:\n", + (unsigned int) temp); + xhci_dbg(xhci, "CAPLENGTH: 0x%x\n", + (unsigned int) HC_LENGTH(temp)); + xhci_dbg(xhci, "HCIVERSION: 0x%x\n", + (unsigned int) HC_VERSION(temp)); + + temp = xhci_readl(xhci, &xhci->cap_regs->hcs_params1); + xhci_dbg(xhci, "HCSPARAMS 1: 0x%x\n", + (unsigned int) temp); + xhci_dbg(xhci, " Max device slots: %u\n", + (unsigned int) HCS_MAX_SLOTS(temp)); + xhci_dbg(xhci, " Max interrupters: %u\n", + (unsigned int) HCS_MAX_INTRS(temp)); + xhci_dbg(xhci, " Max ports: %u\n", + (unsigned int) HCS_MAX_PORTS(temp)); + + temp = xhci_readl(xhci, &xhci->cap_regs->hcs_params2); + xhci_dbg(xhci, "HCSPARAMS 2: 0x%x\n", + (unsigned int) temp); + xhci_dbg(xhci, " Isoc scheduling threshold: %u\n", + (unsigned int) HCS_IST(temp)); + xhci_dbg(xhci, " Maximum allowed segments in event ring: %u\n", + (unsigned int) HCS_ERST_MAX(temp)); + + temp = xhci_readl(xhci, &xhci->cap_regs->hcs_params3); + xhci_dbg(xhci, "HCSPARAMS 3 0x%x:\n", + (unsigned int) temp); + xhci_dbg(xhci, " Worst case U1 device exit latency: %u\n", + (unsigned int) HCS_U1_LATENCY(temp)); + xhci_dbg(xhci, " Worst case U2 device exit latency: %u\n", + (unsigned int) HCS_U2_LATENCY(temp)); + + temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params); + xhci_dbg(xhci, "HCC PARAMS 0x%x:\n", (unsigned int) temp); + xhci_dbg(xhci, " HC generates %s bit addresses\n", + HCC_64BIT_ADDR(temp) ? "64" : "32"); + /* FIXME */ + xhci_dbg(xhci, " FIXME: more HCCPARAMS debugging\n"); + + temp = xhci_readl(xhci, &xhci->cap_regs->run_regs_off); + xhci_dbg(xhci, "RTSOFF 0x%x:\n", temp & RTSOFF_MASK); +} + +static void xhci_print_command_reg(struct xhci_hcd *xhci) +{ + u32 temp; + + temp = xhci_readl(xhci, &xhci->op_regs->command); + xhci_dbg(xhci, "USBCMD 0x%x:\n", temp); + xhci_dbg(xhci, " HC is %s\n", + (temp & CMD_RUN) ? "running" : "being stopped"); + xhci_dbg(xhci, " HC has %sfinished hard reset\n", + (temp & CMD_RESET) ? "not " : ""); + xhci_dbg(xhci, " Event Interrupts %s\n", + (temp & CMD_EIE) ? "enabled " : "disabled"); + xhci_dbg(xhci, " Host System Error Interrupts %s\n", + (temp & CMD_EIE) ? "enabled " : "disabled"); + xhci_dbg(xhci, " HC has %sfinished light reset\n", + (temp & CMD_LRESET) ? "not " : ""); +} + +static void xhci_print_status(struct xhci_hcd *xhci) +{ + u32 temp; + + temp = xhci_readl(xhci, &xhci->op_regs->status); + xhci_dbg(xhci, "USBSTS 0x%x:\n", temp); + xhci_dbg(xhci, " Event ring is %sempty\n", + (temp & STS_EINT) ? "not " : ""); + xhci_dbg(xhci, " %sHost System Error\n", + (temp & STS_FATAL) ? "WARNING: " : "No "); + xhci_dbg(xhci, " HC is %s\n", + (temp & STS_HALT) ? "halted" : "running"); +} + +static void xhci_print_op_regs(struct xhci_hcd *xhci) +{ + xhci_dbg(xhci, "xHCI operational registers at %p:\n", xhci->op_regs); + xhci_print_command_reg(xhci); + xhci_print_status(xhci); +} + +static void xhci_print_ports(struct xhci_hcd *xhci) +{ + u32 __iomem *addr; + int i, j; + int ports; + char *names[NUM_PORT_REGS] = { + "status", + "power", + "link", + "reserved", + }; + + ports = HCS_MAX_PORTS(xhci->hcs_params1); + addr = &xhci->op_regs->port_status_base; + for (i = 0; i < ports; i++) { + for (j = 0; j < NUM_PORT_REGS; ++j) { + xhci_dbg(xhci, "%p port %s reg = 0x%x\n", + addr, names[j], + (unsigned int) xhci_readl(xhci, addr)); + addr++; + } + } +} + +void xhci_print_ir_set(struct xhci_hcd *xhci, struct xhci_intr_reg *ir_set, int set_num) +{ + void *addr; + u32 temp; + + addr = &ir_set->irq_pending; + temp = xhci_readl(xhci, addr); + if (temp == XHCI_INIT_VALUE) + return; + + xhci_dbg(xhci, " %p: ir_set[%i]\n", ir_set, set_num); + + xhci_dbg(xhci, " %p: ir_set.pending = 0x%x\n", addr, + (unsigned int)temp); + + addr = &ir_set->irq_control; + temp = xhci_readl(xhci, addr); + xhci_dbg(xhci, " %p: ir_set.control = 0x%x\n", addr, + (unsigned int)temp); + + addr = &ir_set->erst_size; + temp = xhci_readl(xhci, addr); + xhci_dbg(xhci, " %p: ir_set.erst_size = 0x%x\n", addr, + (unsigned int)temp); + + addr = &ir_set->rsvd; + temp = xhci_readl(xhci, addr); + if (temp != XHCI_INIT_VALUE) + xhci_dbg(xhci, " WARN: %p: ir_set.rsvd = 0x%x\n", + addr, (unsigned int)temp); + + addr = &ir_set->erst_base[0]; + temp = xhci_readl(xhci, addr); + xhci_dbg(xhci, " %p: ir_set.erst_base[0] = 0x%x\n", + addr, (unsigned int) temp); + + addr = &ir_set->erst_base[1]; + temp = xhci_readl(xhci, addr); + xhci_dbg(xhci, " %p: ir_set.erst_base[1] = 0x%x\n", + addr, (unsigned int) temp); + + addr = &ir_set->erst_dequeue[0]; + temp = xhci_readl(xhci, addr); + xhci_dbg(xhci, " %p: ir_set.erst_dequeue[0] = 0x%x\n", + addr, (unsigned int) temp); + + addr = &ir_set->erst_dequeue[1]; + temp = xhci_readl(xhci, addr); + xhci_dbg(xhci, " %p: ir_set.erst_dequeue[1] = 0x%x\n", + addr, (unsigned int) temp); +} + +void xhci_print_run_regs(struct xhci_hcd *xhci) +{ + u32 temp; + int i; + + xhci_dbg(xhci, "xHCI runtime registers at %p:\n", xhci->run_regs); + temp = xhci_readl(xhci, &xhci->run_regs->microframe_index); + xhci_dbg(xhci, " %p: Microframe index = 0x%x\n", + &xhci->run_regs->microframe_index, + (unsigned int) temp); + for (i = 0; i < 7; ++i) { + temp = xhci_readl(xhci, &xhci->run_regs->rsvd[i]); + if (temp != XHCI_INIT_VALUE) + xhci_dbg(xhci, " WARN: %p: Rsvd[%i] = 0x%x\n", + &xhci->run_regs->rsvd[i], + i, (unsigned int) temp); + } +} + +void xhci_print_registers(struct xhci_hcd *xhci) +{ + xhci_print_cap_regs(xhci); + xhci_print_op_regs(xhci); + xhci_print_ports(xhci); +} + +void xhci_print_trb_offsets(struct xhci_hcd *xhci, union xhci_trb *trb) +{ + int i; + for (i = 0; i < 4; ++i) + xhci_dbg(xhci, "Offset 0x%x = 0x%x\n", + i*4, trb->generic.field[i]); +} + +/** + * Debug a transfer request block (TRB). + */ +void xhci_debug_trb(struct xhci_hcd *xhci, union xhci_trb *trb) +{ + u64 address; + u32 type = xhci_readl(xhci, &trb->link.control) & TRB_TYPE_BITMASK; + + switch (type) { + case TRB_TYPE(TRB_LINK): + xhci_dbg(xhci, "Link TRB:\n"); + xhci_print_trb_offsets(xhci, trb); + + address = trb->link.segment_ptr[0] + + (((u64) trb->link.segment_ptr[1]) << 32); + xhci_dbg(xhci, "Next ring segment DMA address = 0x%llx\n", address); + + xhci_dbg(xhci, "Interrupter target = 0x%x\n", + GET_INTR_TARGET(trb->link.intr_target)); + xhci_dbg(xhci, "Cycle bit = %u\n", + (unsigned int) (trb->link.control & TRB_CYCLE)); + xhci_dbg(xhci, "Toggle cycle bit = %u\n", + (unsigned int) (trb->link.control & LINK_TOGGLE)); + xhci_dbg(xhci, "No Snoop bit = %u\n", + (unsigned int) (trb->link.control & TRB_NO_SNOOP)); + break; + case TRB_TYPE(TRB_TRANSFER): + address = trb->trans_event.buffer[0] + + (((u64) trb->trans_event.buffer[1]) << 32); + /* + * FIXME: look at flags to figure out if it's an address or if + * the data is directly in the buffer field. + */ + xhci_dbg(xhci, "DMA address or buffer contents= %llu\n", address); + break; + case TRB_TYPE(TRB_COMPLETION): + address = trb->event_cmd.cmd_trb[0] + + (((u64) trb->event_cmd.cmd_trb[1]) << 32); + xhci_dbg(xhci, "Command TRB pointer = %llu\n", address); + xhci_dbg(xhci, "Completion status = %u\n", + (unsigned int) GET_COMP_CODE(trb->event_cmd.status)); + xhci_dbg(xhci, "Flags = 0x%x\n", (unsigned int) trb->event_cmd.flags); + break; + default: + xhci_dbg(xhci, "Unknown TRB with TRB type ID %u\n", + (unsigned int) type>>10); + xhci_print_trb_offsets(xhci, trb); + break; + } +} + +/** + * Debug a segment with an xHCI ring. + * + * @return The Link TRB of the segment, or NULL if there is no Link TRB + * (which is a bug, since all segments must have a Link TRB). + * + * Prints out all TRBs in the segment, even those after the Link TRB. + * + * XXX: should we print out TRBs that the HC owns? As long as we don't + * write, that should be fine... We shouldn't expect that the memory pointed to + * by the TRB is valid at all. Do we care about ones the HC owns? Probably, + * for HC debugging. + */ +void xhci_debug_segment(struct xhci_hcd *xhci, struct xhci_segment *seg) +{ + int i; + u32 addr = (u32) seg->dma; + union xhci_trb *trb = seg->trbs; + + for (i = 0; i < TRBS_PER_SEGMENT; ++i) { + trb = &seg->trbs[i]; + xhci_dbg(xhci, "@%08x %08x %08x %08x %08x\n", addr, + (unsigned int) trb->link.segment_ptr[0], + (unsigned int) trb->link.segment_ptr[1], + (unsigned int) trb->link.intr_target, + (unsigned int) trb->link.control); + addr += sizeof(*trb); + } +} + +void xhci_dbg_ring_ptrs(struct xhci_hcd *xhci, struct xhci_ring *ring) +{ + xhci_dbg(xhci, "Ring deq = %p (virt), 0x%llx (dma)\n", + ring->dequeue, + (unsigned long long)xhci_trb_virt_to_dma(ring->deq_seg, + ring->dequeue)); + xhci_dbg(xhci, "Ring deq updated %u times\n", + ring->deq_updates); + xhci_dbg(xhci, "Ring enq = %p (virt), 0x%llx (dma)\n", + ring->enqueue, + (unsigned long long)xhci_trb_virt_to_dma(ring->enq_seg, + ring->enqueue)); + xhci_dbg(xhci, "Ring enq updated %u times\n", + ring->enq_updates); +} + +/** + * Debugging for an xHCI ring, which is a queue broken into multiple segments. + * + * Print out each segment in the ring. Check that the DMA address in + * each link segment actually matches the segment's stored DMA address. + * Check that the link end bit is only set at the end of the ring. + * Check that the dequeue and enqueue pointers point to real data in this ring + * (not some other ring). + */ +void xhci_debug_ring(struct xhci_hcd *xhci, struct xhci_ring *ring) +{ + /* FIXME: Throw an error if any segment doesn't have a Link TRB */ + struct xhci_segment *seg; + struct xhci_segment *first_seg = ring->first_seg; + xhci_debug_segment(xhci, first_seg); + + if (!ring->enq_updates && !ring->deq_updates) { + xhci_dbg(xhci, " Ring has not been updated\n"); + return; + } + for (seg = first_seg->next; seg != first_seg; seg = seg->next) + xhci_debug_segment(xhci, seg); +} + +void xhci_dbg_erst(struct xhci_hcd *xhci, struct xhci_erst *erst) +{ + u32 addr = (u32) erst->erst_dma_addr; + int i; + struct xhci_erst_entry *entry; + + for (i = 0; i < erst->num_entries; ++i) { + entry = &erst->entries[i]; + xhci_dbg(xhci, "@%08x %08x %08x %08x %08x\n", + (unsigned int) addr, + (unsigned int) entry->seg_addr[0], + (unsigned int) entry->seg_addr[1], + (unsigned int) entry->seg_size, + (unsigned int) entry->rsvd); + addr += sizeof(*entry); + } +} + +void xhci_dbg_cmd_ptrs(struct xhci_hcd *xhci) +{ + u32 val; + + val = xhci_readl(xhci, &xhci->op_regs->cmd_ring[0]); + xhci_dbg(xhci, "// xHC command ring deq ptr low bits + flags = 0x%x\n", val); + val = xhci_readl(xhci, &xhci->op_regs->cmd_ring[1]); + xhci_dbg(xhci, "// xHC command ring deq ptr high bits = 0x%x\n", val); +} + +void xhci_dbg_ctx(struct xhci_hcd *xhci, struct xhci_device_control *ctx, dma_addr_t dma, unsigned int last_ep) +{ + int i, j; + int last_ep_ctx = 31; + /* Fields are 32 bits wide, DMA addresses are in bytes */ + int field_size = 32 / 8; + + xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - drop flags\n", + &ctx->drop_flags, (unsigned long long)dma, + ctx->drop_flags); + dma += field_size; + xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - add flags\n", + &ctx->add_flags, (unsigned long long)dma, + ctx->add_flags); + dma += field_size; + for (i = 0; i > 6; ++i) { + xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n", + &ctx->rsvd[i], (unsigned long long)dma, + ctx->rsvd[i], i); + dma += field_size; + } + + xhci_dbg(xhci, "Slot Context:\n"); + xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - dev_info\n", + &ctx->slot.dev_info, + (unsigned long long)dma, ctx->slot.dev_info); + dma += field_size; + xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - dev_info2\n", + &ctx->slot.dev_info2, + (unsigned long long)dma, ctx->slot.dev_info2); + dma += field_size; + xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - tt_info\n", + &ctx->slot.tt_info, + (unsigned long long)dma, ctx->slot.tt_info); + dma += field_size; + xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - dev_state\n", + &ctx->slot.dev_state, + (unsigned long long)dma, ctx->slot.dev_state); + dma += field_size; + for (i = 0; i > 4; ++i) { + xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n", + &ctx->slot.reserved[i], (unsigned long long)dma, + ctx->slot.reserved[i], i); + dma += field_size; + } + + if (last_ep < 31) + last_ep_ctx = last_ep + 1; + for (i = 0; i < last_ep_ctx; ++i) { + xhci_dbg(xhci, "Endpoint %02d Context:\n", i); + xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - ep_info\n", + &ctx->ep[i].ep_info, + (unsigned long long)dma, ctx->ep[i].ep_info); + dma += field_size; + xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - ep_info2\n", + &ctx->ep[i].ep_info2, + (unsigned long long)dma, ctx->ep[i].ep_info2); + dma += field_size; + xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - deq[0]\n", + &ctx->ep[i].deq[0], + (unsigned long long)dma, ctx->ep[i].deq[0]); + dma += field_size; + xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - deq[1]\n", + &ctx->ep[i].deq[1], + (unsigned long long)dma, ctx->ep[i].deq[1]); + dma += field_size; + xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - tx_info\n", + &ctx->ep[i].tx_info, + (unsigned long long)dma, ctx->ep[i].tx_info); + dma += field_size; + for (j = 0; j < 3; ++j) { + xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n", + &ctx->ep[i].reserved[j], + (unsigned long long)dma, + ctx->ep[i].reserved[j], j); + dma += field_size; + } + } +} diff --git a/drivers/usb/host/xhci-ext-caps.h b/drivers/usb/host/xhci-ext-caps.h new file mode 100644 index 000000000000..ecc131c3fe33 --- /dev/null +++ b/drivers/usb/host/xhci-ext-caps.h @@ -0,0 +1,145 @@ +/* + * xHCI host controller driver + * + * Copyright (C) 2008 Intel Corp. + * + * Author: Sarah Sharp + * Some code borrowed from the Linux EHCI driver. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* Up to 16 microframes to halt an HC - one microframe is 125 microsectonds */ +#define XHCI_MAX_HALT_USEC (16*125) +/* HC not running - set to 1 when run/stop bit is cleared. */ +#define XHCI_STS_HALT (1<<0) + +/* HCCPARAMS offset from PCI base address */ +#define XHCI_HCC_PARAMS_OFFSET 0x10 +/* HCCPARAMS contains the first extended capability pointer */ +#define XHCI_HCC_EXT_CAPS(p) (((p)>>16)&0xffff) + +/* Command and Status registers offset from the Operational Registers address */ +#define XHCI_CMD_OFFSET 0x00 +#define XHCI_STS_OFFSET 0x04 + +#define XHCI_MAX_EXT_CAPS 50 + +/* Capability Register */ +/* bits 7:0 - how long is the Capabilities register */ +#define XHCI_HC_LENGTH(p) (((p)>>00)&0x00ff) + +/* Extended capability register fields */ +#define XHCI_EXT_CAPS_ID(p) (((p)>>0)&0xff) +#define XHCI_EXT_CAPS_NEXT(p) (((p)>>8)&0xff) +#define XHCI_EXT_CAPS_VAL(p) ((p)>>16) +/* Extended capability IDs - ID 0 reserved */ +#define XHCI_EXT_CAPS_LEGACY 1 +#define XHCI_EXT_CAPS_PROTOCOL 2 +#define XHCI_EXT_CAPS_PM 3 +#define XHCI_EXT_CAPS_VIRT 4 +#define XHCI_EXT_CAPS_ROUTE 5 +/* IDs 6-9 reserved */ +#define XHCI_EXT_CAPS_DEBUG 10 +/* USB Legacy Support Capability - section 7.1.1 */ +#define XHCI_HC_BIOS_OWNED (1 << 16) +#define XHCI_HC_OS_OWNED (1 << 24) + +/* USB Legacy Support Capability - section 7.1.1 */ +/* Add this offset, plus the value of xECP in HCCPARAMS to the base address */ +#define XHCI_LEGACY_SUPPORT_OFFSET (0x00) + +/* USB Legacy Support Control and Status Register - section 7.1.2 */ +/* Add this offset, plus the value of xECP in HCCPARAMS to the base address */ +#define XHCI_LEGACY_CONTROL_OFFSET (0x04) +/* bits 1:2, 5:12, and 17:19 need to be preserved; bits 21:28 should be zero */ +#define XHCI_LEGACY_DISABLE_SMI ((0x3 << 1) + (0xff << 5) + (0x7 << 17)) + +/* command register values to disable interrupts and halt the HC */ +/* start/stop HC execution - do not write unless HC is halted*/ +#define XHCI_CMD_RUN (1 << 0) +/* Event Interrupt Enable - get irq when EINT bit is set in USBSTS register */ +#define XHCI_CMD_EIE (1 << 2) +/* Host System Error Interrupt Enable - get irq when HSEIE bit set in USBSTS */ +#define XHCI_CMD_HSEIE (1 << 3) +/* Enable Wrap Event - '1' means xHC generates an event when MFINDEX wraps. */ +#define XHCI_CMD_EWE (1 << 10) + +#define XHCI_IRQS (XHCI_CMD_EIE | XHCI_CMD_HSEIE | XHCI_CMD_EWE) + +/* true: Controller Not Ready to accept doorbell or op reg writes after reset */ +#define XHCI_STS_CNR (1 << 11) + +#include + +/** + * Return the next extended capability pointer register. + * + * @base PCI register base address. + * + * @ext_offset Offset of the 32-bit register that contains the extended + * capabilites pointer. If searching for the first extended capability, pass + * in XHCI_HCC_PARAMS_OFFSET. If searching for the next extended capability, + * pass in the offset of the current extended capability register. + * + * Returns 0 if there is no next extended capability register or returns the register offset + * from the PCI registers base address. + */ +static inline int xhci_find_next_cap_offset(void __iomem *base, int ext_offset) +{ + u32 next; + + next = readl(base + ext_offset); + + if (ext_offset == XHCI_HCC_PARAMS_OFFSET) + /* Find the first extended capability */ + next = XHCI_HCC_EXT_CAPS(next); + else + /* Find the next extended capability */ + next = XHCI_EXT_CAPS_NEXT(next); + if (!next) + return 0; + /* + * Address calculation from offset of extended capabilities + * (or HCCPARAMS) register - see section 5.3.6 and section 7. + */ + return ext_offset + (next << 2); +} + +/** + * Find the offset of the extended capabilities with capability ID id. + * + * @base PCI MMIO registers base address. + * @ext_offset Offset from base of the first extended capability to look at, + * or the address of HCCPARAMS. + * @id Extended capability ID to search for. + * + * This uses an arbitrary limit of XHCI_MAX_EXT_CAPS extended capabilities + * to make sure that the list doesn't contain a loop. + */ +static inline int xhci_find_ext_cap_by_id(void __iomem *base, int ext_offset, int id) +{ + u32 val; + int limit = XHCI_MAX_EXT_CAPS; + + while (ext_offset && limit > 0) { + val = readl(base + ext_offset); + if (XHCI_EXT_CAPS_ID(val) == id) + break; + ext_offset = xhci_find_next_cap_offset(base, ext_offset); + limit--; + } + if (limit > 0) + return ext_offset; + return 0; +} diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c new file mode 100644 index 000000000000..dba3e07ccd09 --- /dev/null +++ b/drivers/usb/host/xhci-hcd.c @@ -0,0 +1,1274 @@ +/* + * xHCI host controller driver + * + * Copyright (C) 2008 Intel Corp. + * + * Author: Sarah Sharp + * Some code borrowed from the Linux EHCI driver. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include + +#include "xhci.h" + +#define DRIVER_AUTHOR "Sarah Sharp" +#define DRIVER_DESC "'eXtensible' Host Controller (xHC) Driver" + +/* TODO: copied from ehci-hcd.c - can this be refactored? */ +/* + * handshake - spin reading hc until handshake completes or fails + * @ptr: address of hc register to be read + * @mask: bits to look at in result of read + * @done: value of those bits when handshake succeeds + * @usec: timeout in microseconds + * + * Returns negative errno, or zero on success + * + * Success happens when the "mask" bits have the specified value (hardware + * handshake done). There are two failure modes: "usec" have passed (major + * hardware flakeout), or the register reads as all-ones (hardware removed). + */ +static int handshake(struct xhci_hcd *xhci, void __iomem *ptr, + u32 mask, u32 done, int usec) +{ + u32 result; + + do { + result = xhci_readl(xhci, ptr); + if (result == ~(u32)0) /* card removed */ + return -ENODEV; + result &= mask; + if (result == done) + return 0; + udelay(1); + usec--; + } while (usec > 0); + return -ETIMEDOUT; +} + +/* + * Force HC into halt state. + * + * Disable any IRQs and clear the run/stop bit. + * HC will complete any current and actively pipelined transactions, and + * should halt within 16 microframes of the run/stop bit being cleared. + * Read HC Halted bit in the status register to see when the HC is finished. + * XXX: shouldn't we set HC_STATE_HALT here somewhere? + */ +int xhci_halt(struct xhci_hcd *xhci) +{ + u32 halted; + u32 cmd; + u32 mask; + + xhci_dbg(xhci, "// Halt the HC\n"); + /* Disable all interrupts from the host controller */ + mask = ~(XHCI_IRQS); + halted = xhci_readl(xhci, &xhci->op_regs->status) & STS_HALT; + if (!halted) + mask &= ~CMD_RUN; + + cmd = xhci_readl(xhci, &xhci->op_regs->command); + cmd &= mask; + xhci_writel(xhci, cmd, &xhci->op_regs->command); + + return handshake(xhci, &xhci->op_regs->status, + STS_HALT, STS_HALT, XHCI_MAX_HALT_USEC); +} + +/* + * Reset a halted HC, and set the internal HC state to HC_STATE_HALT. + * + * This resets pipelines, timers, counters, state machines, etc. + * Transactions will be terminated immediately, and operational registers + * will be set to their defaults. + */ +int xhci_reset(struct xhci_hcd *xhci) +{ + u32 command; + u32 state; + + state = xhci_readl(xhci, &xhci->op_regs->status); + BUG_ON((state & STS_HALT) == 0); + + xhci_dbg(xhci, "// Reset the HC\n"); + command = xhci_readl(xhci, &xhci->op_regs->command); + command |= CMD_RESET; + xhci_writel(xhci, command, &xhci->op_regs->command); + /* XXX: Why does EHCI set this here? Shouldn't other code do this? */ + xhci_to_hcd(xhci)->state = HC_STATE_HALT; + + return handshake(xhci, &xhci->op_regs->command, CMD_RESET, 0, 250 * 1000); +} + +/* + * Stop the HC from processing the endpoint queues. + */ +static void xhci_quiesce(struct xhci_hcd *xhci) +{ + /* + * Queues are per endpoint, so we need to disable an endpoint or slot. + * + * To disable a slot, we need to insert a disable slot command on the + * command ring and ring the doorbell. This will also free any internal + * resources associated with the slot (which might not be what we want). + * + * A Release Endpoint command sounds better - doesn't free internal HC + * memory, but removes the endpoints from the schedule and releases the + * bandwidth, disables the doorbells, and clears the endpoint enable + * flag. Usually used prior to a set interface command. + * + * TODO: Implement after command ring code is done. + */ + BUG_ON(!HC_IS_RUNNING(xhci_to_hcd(xhci)->state)); + xhci_dbg(xhci, "Finished quiescing -- code not written yet\n"); +} + +#if 0 +/* Set up MSI-X table for entry 0 (may claim other entries later) */ +static int xhci_setup_msix(struct xhci_hcd *xhci) +{ + int ret; + struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); + + xhci->msix_count = 0; + /* XXX: did I do this right? ixgbe does kcalloc for more than one */ + xhci->msix_entries = kmalloc(sizeof(struct msix_entry), GFP_KERNEL); + if (!xhci->msix_entries) { + xhci_err(xhci, "Failed to allocate MSI-X entries\n"); + return -ENOMEM; + } + xhci->msix_entries[0].entry = 0; + + ret = pci_enable_msix(pdev, xhci->msix_entries, xhci->msix_count); + if (ret) { + xhci_err(xhci, "Failed to enable MSI-X\n"); + goto free_entries; + } + + /* + * Pass the xhci pointer value as the request_irq "cookie". + * If more irqs are added, this will need to be unique for each one. + */ + ret = request_irq(xhci->msix_entries[0].vector, &xhci_irq, 0, + "xHCI", xhci_to_hcd(xhci)); + if (ret) { + xhci_err(xhci, "Failed to allocate MSI-X interrupt\n"); + goto disable_msix; + } + xhci_dbg(xhci, "Finished setting up MSI-X\n"); + return 0; + +disable_msix: + pci_disable_msix(pdev); +free_entries: + kfree(xhci->msix_entries); + xhci->msix_entries = NULL; + return ret; +} + +/* XXX: code duplication; can xhci_setup_msix call this? */ +/* Free any IRQs and disable MSI-X */ +static void xhci_cleanup_msix(struct xhci_hcd *xhci) +{ + struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); + if (!xhci->msix_entries) + return; + + free_irq(xhci->msix_entries[0].vector, xhci); + pci_disable_msix(pdev); + kfree(xhci->msix_entries); + xhci->msix_entries = NULL; + xhci_dbg(xhci, "Finished cleaning up MSI-X\n"); +} +#endif + +/* + * Initialize memory for HCD and xHC (one-time init). + * + * Program the PAGESIZE register, initialize the device context array, create + * device contexts (?), set up a command ring segment (or two?), create event + * ring (one for now). + */ +int xhci_init(struct usb_hcd *hcd) +{ + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + int retval = 0; + + xhci_dbg(xhci, "xhci_init\n"); + spin_lock_init(&xhci->lock); + retval = xhci_mem_init(xhci, GFP_KERNEL); + xhci_dbg(xhci, "Finished xhci_init\n"); + + return retval; +} + +/* + * Called in interrupt context when there might be work + * queued on the event ring + * + * xhci->lock must be held by caller. + */ +static void xhci_work(struct xhci_hcd *xhci) +{ + u32 temp; + + /* + * Clear the op reg interrupt status first, + * so we can receive interrupts from other MSI-X interrupters. + * Write 1 to clear the interrupt status. + */ + temp = xhci_readl(xhci, &xhci->op_regs->status); + temp |= STS_EINT; + xhci_writel(xhci, temp, &xhci->op_regs->status); + /* FIXME when MSI-X is supported and there are multiple vectors */ + /* Clear the MSI-X event interrupt status */ + + /* Acknowledge the interrupt */ + temp = xhci_readl(xhci, &xhci->ir_set->irq_pending); + temp |= 0x3; + xhci_writel(xhci, temp, &xhci->ir_set->irq_pending); + /* Flush posted writes */ + xhci_readl(xhci, &xhci->ir_set->irq_pending); + + /* FIXME this should be a delayed service routine that clears the EHB */ + xhci_handle_event(xhci); + + /* Clear the event handler busy flag; the event ring should be empty. */ + temp = xhci_readl(xhci, &xhci->ir_set->erst_dequeue[0]); + xhci_writel(xhci, temp & ~ERST_EHB, &xhci->ir_set->erst_dequeue[0]); + /* Flush posted writes -- FIXME is this necessary? */ + xhci_readl(xhci, &xhci->ir_set->irq_pending); +} + +/*-------------------------------------------------------------------------*/ + +/* + * xHCI spec says we can get an interrupt, and if the HC has an error condition, + * we might get bad data out of the event ring. Section 4.10.2.7 has a list of + * indicators of an event TRB error, but we check the status *first* to be safe. + */ +irqreturn_t xhci_irq(struct usb_hcd *hcd) +{ + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + u32 temp, temp2; + + spin_lock(&xhci->lock); + /* Check if the xHC generated the interrupt, or the irq is shared */ + temp = xhci_readl(xhci, &xhci->op_regs->status); + temp2 = xhci_readl(xhci, &xhci->ir_set->irq_pending); + if (!(temp & STS_EINT) && !ER_IRQ_PENDING(temp2)) { + spin_unlock(&xhci->lock); + return IRQ_NONE; + } + + if (temp & STS_FATAL) { + xhci_warn(xhci, "WARNING: Host System Error\n"); + xhci_halt(xhci); + xhci_to_hcd(xhci)->state = HC_STATE_HALT; + spin_unlock(&xhci->lock); + return -ESHUTDOWN; + } + + xhci_work(xhci); + spin_unlock(&xhci->lock); + + return IRQ_HANDLED; +} + +#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING +void xhci_event_ring_work(unsigned long arg) +{ + unsigned long flags; + int temp; + struct xhci_hcd *xhci = (struct xhci_hcd *) arg; + int i, j; + + xhci_dbg(xhci, "Poll event ring: %lu\n", jiffies); + + spin_lock_irqsave(&xhci->lock, flags); + temp = xhci_readl(xhci, &xhci->op_regs->status); + xhci_dbg(xhci, "op reg status = 0x%x\n", temp); + temp = xhci_readl(xhci, &xhci->ir_set->irq_pending); + xhci_dbg(xhci, "ir_set 0 pending = 0x%x\n", temp); + xhci_dbg(xhci, "No-op commands handled = %d\n", xhci->noops_handled); + xhci_dbg(xhci, "HC error bitmask = 0x%x\n", xhci->error_bitmask); + xhci->error_bitmask = 0; + xhci_dbg(xhci, "Event ring:\n"); + xhci_debug_segment(xhci, xhci->event_ring->deq_seg); + xhci_dbg_ring_ptrs(xhci, xhci->event_ring); + temp = xhci_readl(xhci, &xhci->ir_set->erst_dequeue[0]); + temp &= ERST_PTR_MASK; + xhci_dbg(xhci, "ERST deq = 0x%x\n", temp); + xhci_dbg(xhci, "Command ring:\n"); + xhci_debug_segment(xhci, xhci->cmd_ring->deq_seg); + xhci_dbg_ring_ptrs(xhci, xhci->cmd_ring); + xhci_dbg_cmd_ptrs(xhci); + for (i = 0; i < MAX_HC_SLOTS; ++i) { + if (xhci->devs[i]) { + for (j = 0; j < 31; ++j) { + if (xhci->devs[i]->ep_rings[j]) { + xhci_dbg(xhci, "Dev %d endpoint ring %d:\n", i, j); + xhci_debug_segment(xhci, xhci->devs[i]->ep_rings[j]->deq_seg); + } + } + } + } + + if (xhci->noops_submitted != NUM_TEST_NOOPS) + if (xhci_setup_one_noop(xhci)) + xhci_ring_cmd_db(xhci); + spin_unlock_irqrestore(&xhci->lock, flags); + + if (!xhci->zombie) + mod_timer(&xhci->event_ring_timer, jiffies + POLL_TIMEOUT * HZ); + else + xhci_dbg(xhci, "Quit polling the event ring.\n"); +} +#endif + +/* + * Start the HC after it was halted. + * + * This function is called by the USB core when the HC driver is added. + * Its opposite is xhci_stop(). + * + * xhci_init() must be called once before this function can be called. + * Reset the HC, enable device slot contexts, program DCBAAP, and + * set command ring pointer and event ring pointer. + * + * Setup MSI-X vectors and enable interrupts. + */ +int xhci_run(struct usb_hcd *hcd) +{ + u32 temp; + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + void (*doorbell)(struct xhci_hcd *) = NULL; + + hcd->uses_new_polling = 1; + hcd->poll_rh = 0; + + xhci_dbg(xhci, "xhci_run\n"); +#if 0 /* FIXME: MSI not setup yet */ + /* Do this at the very last minute */ + ret = xhci_setup_msix(xhci); + if (!ret) + return ret; + + return -ENOSYS; +#endif +#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING + init_timer(&xhci->event_ring_timer); + xhci->event_ring_timer.data = (unsigned long) xhci; + xhci->event_ring_timer.function = xhci_event_ring_work; + /* Poll the event ring */ + xhci->event_ring_timer.expires = jiffies + POLL_TIMEOUT * HZ; + xhci->zombie = 0; + xhci_dbg(xhci, "Setting event ring polling timer\n"); + add_timer(&xhci->event_ring_timer); +#endif + + xhci_dbg(xhci, "// Set the interrupt modulation register\n"); + temp = xhci_readl(xhci, &xhci->ir_set->irq_control); + temp &= ~ER_IRQ_INTERVAL_MASK; + temp |= (u32) 160; + xhci_writel(xhci, temp, &xhci->ir_set->irq_control); + + /* Set the HCD state before we enable the irqs */ + hcd->state = HC_STATE_RUNNING; + temp = xhci_readl(xhci, &xhci->op_regs->command); + temp |= (CMD_EIE); + xhci_dbg(xhci, "// Enable interrupts, cmd = 0x%x.\n", + temp); + xhci_writel(xhci, temp, &xhci->op_regs->command); + + temp = xhci_readl(xhci, &xhci->ir_set->irq_pending); + xhci_dbg(xhci, "// Enabling event ring interrupter %p by writing 0x%x to irq_pending\n", + xhci->ir_set, (unsigned int) ER_IRQ_ENABLE(temp)); + xhci_writel(xhci, ER_IRQ_ENABLE(temp), + &xhci->ir_set->irq_pending); + xhci_print_ir_set(xhci, xhci->ir_set, 0); + + if (NUM_TEST_NOOPS > 0) + doorbell = xhci_setup_one_noop(xhci); + + xhci_dbg(xhci, "Command ring memory map follows:\n"); + xhci_debug_ring(xhci, xhci->cmd_ring); + xhci_dbg_ring_ptrs(xhci, xhci->cmd_ring); + xhci_dbg_cmd_ptrs(xhci); + + xhci_dbg(xhci, "ERST memory map follows:\n"); + xhci_dbg_erst(xhci, &xhci->erst); + xhci_dbg(xhci, "Event ring:\n"); + xhci_debug_ring(xhci, xhci->event_ring); + xhci_dbg_ring_ptrs(xhci, xhci->event_ring); + temp = xhci_readl(xhci, &xhci->ir_set->erst_dequeue[0]); + temp &= ERST_PTR_MASK; + xhci_dbg(xhci, "ERST deq = 0x%x\n", temp); + temp = xhci_readl(xhci, &xhci->ir_set->erst_dequeue[1]); + xhci_dbg(xhci, "ERST deq upper = 0x%x\n", temp); + + temp = xhci_readl(xhci, &xhci->op_regs->command); + temp |= (CMD_RUN); + xhci_dbg(xhci, "// Turn on HC, cmd = 0x%x.\n", + temp); + xhci_writel(xhci, temp, &xhci->op_regs->command); + /* Flush PCI posted writes */ + temp = xhci_readl(xhci, &xhci->op_regs->command); + xhci_dbg(xhci, "// @%p = 0x%x\n", &xhci->op_regs->command, temp); + if (doorbell) + (*doorbell)(xhci); + + xhci_dbg(xhci, "Finished xhci_run\n"); + return 0; +} + +/* + * Stop xHCI driver. + * + * This function is called by the USB core when the HC driver is removed. + * Its opposite is xhci_run(). + * + * Disable device contexts, disable IRQs, and quiesce the HC. + * Reset the HC, finish any completed transactions, and cleanup memory. + */ +void xhci_stop(struct usb_hcd *hcd) +{ + u32 temp; + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + + spin_lock_irq(&xhci->lock); + if (HC_IS_RUNNING(hcd->state)) + xhci_quiesce(xhci); + xhci_halt(xhci); + xhci_reset(xhci); + spin_unlock_irq(&xhci->lock); + +#if 0 /* No MSI yet */ + xhci_cleanup_msix(xhci); +#endif +#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING + /* Tell the event ring poll function not to reschedule */ + xhci->zombie = 1; + del_timer_sync(&xhci->event_ring_timer); +#endif + + xhci_dbg(xhci, "// Disabling event ring interrupts\n"); + temp = xhci_readl(xhci, &xhci->op_regs->status); + xhci_writel(xhci, temp & ~STS_EINT, &xhci->op_regs->status); + temp = xhci_readl(xhci, &xhci->ir_set->irq_pending); + xhci_writel(xhci, ER_IRQ_DISABLE(temp), + &xhci->ir_set->irq_pending); + xhci_print_ir_set(xhci, xhci->ir_set, 0); + + xhci_dbg(xhci, "cleaning up memory\n"); + xhci_mem_cleanup(xhci); + xhci_dbg(xhci, "xhci_stop completed - status = %x\n", + xhci_readl(xhci, &xhci->op_regs->status)); +} + +/* + * Shutdown HC (not bus-specific) + * + * This is called when the machine is rebooting or halting. We assume that the + * machine will be powered off, and the HC's internal state will be reset. + * Don't bother to free memory. + */ +void xhci_shutdown(struct usb_hcd *hcd) +{ + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + + spin_lock_irq(&xhci->lock); + xhci_halt(xhci); + spin_unlock_irq(&xhci->lock); + +#if 0 + xhci_cleanup_msix(xhci); +#endif + + xhci_dbg(xhci, "xhci_shutdown completed - status = %x\n", + xhci_readl(xhci, &xhci->op_regs->status)); +} + +/*-------------------------------------------------------------------------*/ + +/** + * xhci_get_endpoint_index - Used for passing endpoint bitmasks between the core and + * HCDs. Find the index for an endpoint given its descriptor. Use the return + * value to right shift 1 for the bitmask. + * + * Index = (epnum * 2) + direction - 1, + * where direction = 0 for OUT, 1 for IN. + * For control endpoints, the IN index is used (OUT index is unused), so + * index = (epnum * 2) + direction - 1 = (epnum * 2) + 1 - 1 = (epnum * 2) + */ +unsigned int xhci_get_endpoint_index(struct usb_endpoint_descriptor *desc) +{ + unsigned int index; + if (usb_endpoint_xfer_control(desc)) + index = (unsigned int) (usb_endpoint_num(desc)*2); + else + index = (unsigned int) (usb_endpoint_num(desc)*2) + + (usb_endpoint_dir_in(desc) ? 1 : 0) - 1; + return index; +} + +/* Find the flag for this endpoint (for use in the control context). Use the + * endpoint index to create a bitmask. The slot context is bit 0, endpoint 0 is + * bit 1, etc. + */ +unsigned int xhci_get_endpoint_flag(struct usb_endpoint_descriptor *desc) +{ + return 1 << (xhci_get_endpoint_index(desc) + 1); +} + +/* Compute the last valid endpoint context index. Basically, this is the + * endpoint index plus one. For slot contexts with more than valid endpoint, + * we find the most significant bit set in the added contexts flags. + * e.g. ep 1 IN (with epnum 0x81) => added_ctxs = 0b1000 + * fls(0b1000) = 4, but the endpoint context index is 3, so subtract one. + */ +static inline unsigned int xhci_last_valid_endpoint(u32 added_ctxs) +{ + return fls(added_ctxs) - 1; +} + +/* Returns 1 if the arguments are OK; + * returns 0 this is a root hub; returns -EINVAL for NULL pointers. + */ +int xhci_check_args(struct usb_hcd *hcd, struct usb_device *udev, + struct usb_host_endpoint *ep, int check_ep, const char *func) { + if (!hcd || (check_ep && !ep) || !udev) { + printk(KERN_DEBUG "xHCI %s called with invalid args\n", + func); + return -EINVAL; + } + if (!udev->parent) { + printk(KERN_DEBUG "xHCI %s called for root hub\n", + func); + return 0; + } + if (!udev->slot_id) { + printk(KERN_DEBUG "xHCI %s called with unaddressed device\n", + func); + return -EINVAL; + } + return 1; +} + +/* + * non-error returns are a promise to giveback() the urb later + * we drop ownership so next owner (or urb unlink) can get it + */ +int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags) +{ + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + unsigned long flags; + int ret = 0; + unsigned int slot_id, ep_index; + + if (!urb || xhci_check_args(hcd, urb->dev, urb->ep, true, __func__) <= 0) + return -EINVAL; + + slot_id = urb->dev->slot_id; + ep_index = xhci_get_endpoint_index(&urb->ep->desc); + + spin_lock_irqsave(&xhci->lock, flags); + if (!xhci->devs || !xhci->devs[slot_id]) { + if (!in_interrupt()) + dev_warn(&urb->dev->dev, "WARN: urb submitted for dev with no Slot ID\n"); + ret = -EINVAL; + goto exit; + } + if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { + if (!in_interrupt()) + xhci_dbg(xhci, "urb submitted during PCI suspend\n"); + ret = -ESHUTDOWN; + goto exit; + } + if (usb_endpoint_xfer_control(&urb->ep->desc)) + ret = xhci_queue_ctrl_tx(xhci, mem_flags, urb, + slot_id, ep_index); + else if (usb_endpoint_xfer_bulk(&urb->ep->desc)) + ret = xhci_queue_bulk_tx(xhci, mem_flags, urb, + slot_id, ep_index); + else + ret = -EINVAL; +exit: + spin_unlock_irqrestore(&xhci->lock, flags); + return ret; +} + +/* + * Remove the URB's TD from the endpoint ring. This may cause the HC to stop + * USB transfers, potentially stopping in the middle of a TRB buffer. The HC + * should pick up where it left off in the TD, unless a Set Transfer Ring + * Dequeue Pointer is issued. + * + * The TRBs that make up the buffers for the canceled URB will be "removed" from + * the ring. Since the ring is a contiguous structure, they can't be physically + * removed. Instead, there are two options: + * + * 1) If the HC is in the middle of processing the URB to be canceled, we + * simply move the ring's dequeue pointer past those TRBs using the Set + * Transfer Ring Dequeue Pointer command. This will be the common case, + * when drivers timeout on the last submitted URB and attempt to cancel. + * + * 2) If the HC is in the middle of a different TD, we turn the TRBs into a + * series of 1-TRB transfer no-op TDs. (No-ops shouldn't be chained.) The + * HC will need to invalidate the any TRBs it has cached after the stop + * endpoint command, as noted in the xHCI 0.95 errata. + * + * 3) The TD may have completed by the time the Stop Endpoint Command + * completes, so software needs to handle that case too. + * + * This function should protect against the TD enqueueing code ringing the + * doorbell while this code is waiting for a Stop Endpoint command to complete. + * It also needs to account for multiple cancellations on happening at the same + * time for the same endpoint. + * + * Note that this function can be called in any context, or so says + * usb_hcd_unlink_urb() + */ +int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) +{ + unsigned long flags; + int ret; + struct xhci_hcd *xhci; + struct xhci_td *td; + unsigned int ep_index; + struct xhci_ring *ep_ring; + + xhci = hcd_to_xhci(hcd); + spin_lock_irqsave(&xhci->lock, flags); + /* Make sure the URB hasn't completed or been unlinked already */ + ret = usb_hcd_check_unlink_urb(hcd, urb, status); + if (ret || !urb->hcpriv) + goto done; + + xhci_dbg(xhci, "Cancel URB %p\n", urb); + ep_index = xhci_get_endpoint_index(&urb->ep->desc); + ep_ring = xhci->devs[urb->dev->slot_id]->ep_rings[ep_index]; + td = (struct xhci_td *) urb->hcpriv; + + ep_ring->cancels_pending++; + list_add_tail(&td->cancelled_td_list, &ep_ring->cancelled_td_list); + /* Queue a stop endpoint command, but only if this is + * the first cancellation to be handled. + */ + if (ep_ring->cancels_pending == 1) { + xhci_queue_stop_endpoint(xhci, urb->dev->slot_id, ep_index); + xhci_ring_cmd_db(xhci); + } +done: + spin_unlock_irqrestore(&xhci->lock, flags); + return ret; +} + +/* Drop an endpoint from a new bandwidth configuration for this device. + * Only one call to this function is allowed per endpoint before + * check_bandwidth() or reset_bandwidth() must be called. + * A call to xhci_drop_endpoint() followed by a call to xhci_add_endpoint() will + * add the endpoint to the schedule with possibly new parameters denoted by a + * different endpoint descriptor in usb_host_endpoint. + * A call to xhci_add_endpoint() followed by a call to xhci_drop_endpoint() is + * not allowed. + * + * The USB core will not allow URBs to be queued to an endpoint that is being + * disabled, so there's no need for mutual exclusion to protect + * the xhci->devs[slot_id] structure. + */ +int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev, + struct usb_host_endpoint *ep) +{ + struct xhci_hcd *xhci; + struct xhci_device_control *in_ctx; + unsigned int last_ctx; + unsigned int ep_index; + struct xhci_ep_ctx *ep_ctx; + u32 drop_flag; + u32 new_add_flags, new_drop_flags, new_slot_info; + int ret; + + ret = xhci_check_args(hcd, udev, ep, 1, __func__); + if (ret <= 0) + return ret; + xhci = hcd_to_xhci(hcd); + xhci_dbg(xhci, "%s called for udev %p\n", __func__, udev); + + drop_flag = xhci_get_endpoint_flag(&ep->desc); + if (drop_flag == SLOT_FLAG || drop_flag == EP0_FLAG) { + xhci_dbg(xhci, "xHCI %s - can't drop slot or ep 0 %#x\n", + __func__, drop_flag); + return 0; + } + + if (!xhci->devs || !xhci->devs[udev->slot_id]) { + xhci_warn(xhci, "xHCI %s called with unaddressed device\n", + __func__); + return -EINVAL; + } + + in_ctx = xhci->devs[udev->slot_id]->in_ctx; + ep_index = xhci_get_endpoint_index(&ep->desc); + ep_ctx = &xhci->devs[udev->slot_id]->out_ctx->ep[ep_index]; + /* If the HC already knows the endpoint is disabled, + * or the HCD has noted it is disabled, ignore this request + */ + if ((ep_ctx->ep_info & EP_STATE_MASK) == EP_STATE_DISABLED || + in_ctx->drop_flags & xhci_get_endpoint_flag(&ep->desc)) { + xhci_warn(xhci, "xHCI %s called with disabled ep %p\n", + __func__, ep); + return 0; + } + + in_ctx->drop_flags |= drop_flag; + new_drop_flags = in_ctx->drop_flags; + + in_ctx->add_flags = ~drop_flag; + new_add_flags = in_ctx->add_flags; + + last_ctx = xhci_last_valid_endpoint(in_ctx->add_flags); + /* Update the last valid endpoint context, if we deleted the last one */ + if ((in_ctx->slot.dev_info & LAST_CTX_MASK) > LAST_CTX(last_ctx)) { + in_ctx->slot.dev_info &= ~LAST_CTX_MASK; + in_ctx->slot.dev_info |= LAST_CTX(last_ctx); + } + new_slot_info = in_ctx->slot.dev_info; + + xhci_endpoint_zero(xhci, xhci->devs[udev->slot_id], ep); + + xhci_dbg(xhci, "drop ep 0x%x, slot id %d, new drop flags = %#x, new add flags = %#x, new slot info = %#x\n", + (unsigned int) ep->desc.bEndpointAddress, + udev->slot_id, + (unsigned int) new_drop_flags, + (unsigned int) new_add_flags, + (unsigned int) new_slot_info); + return 0; +} + +/* Add an endpoint to a new possible bandwidth configuration for this device. + * Only one call to this function is allowed per endpoint before + * check_bandwidth() or reset_bandwidth() must be called. + * A call to xhci_drop_endpoint() followed by a call to xhci_add_endpoint() will + * add the endpoint to the schedule with possibly new parameters denoted by a + * different endpoint descriptor in usb_host_endpoint. + * A call to xhci_add_endpoint() followed by a call to xhci_drop_endpoint() is + * not allowed. + * + * The USB core will not allow URBs to be queued to an endpoint until the + * configuration or alt setting is installed in the device, so there's no need + * for mutual exclusion to protect the xhci->devs[slot_id] structure. + */ +int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, + struct usb_host_endpoint *ep) +{ + struct xhci_hcd *xhci; + struct xhci_device_control *in_ctx; + unsigned int ep_index; + struct xhci_ep_ctx *ep_ctx; + u32 added_ctxs; + unsigned int last_ctx; + u32 new_add_flags, new_drop_flags, new_slot_info; + int ret = 0; + + ret = xhci_check_args(hcd, udev, ep, 1, __func__); + if (ret <= 0) + return ret; + xhci = hcd_to_xhci(hcd); + + added_ctxs = xhci_get_endpoint_flag(&ep->desc); + last_ctx = xhci_last_valid_endpoint(added_ctxs); + if (added_ctxs == SLOT_FLAG || added_ctxs == EP0_FLAG) { + /* FIXME when we have to issue an evaluate endpoint command to + * deal with ep0 max packet size changing once we get the + * descriptors + */ + xhci_dbg(xhci, "xHCI %s - can't add slot or ep 0 %#x\n", + __func__, added_ctxs); + return 0; + } + + if (!xhci->devs || !xhci->devs[udev->slot_id]) { + xhci_warn(xhci, "xHCI %s called with unaddressed device\n", + __func__); + return -EINVAL; + } + + in_ctx = xhci->devs[udev->slot_id]->in_ctx; + ep_index = xhci_get_endpoint_index(&ep->desc); + ep_ctx = &xhci->devs[udev->slot_id]->out_ctx->ep[ep_index]; + /* If the HCD has already noted the endpoint is enabled, + * ignore this request. + */ + if (in_ctx->add_flags & xhci_get_endpoint_flag(&ep->desc)) { + xhci_warn(xhci, "xHCI %s called with enabled ep %p\n", + __func__, ep); + return 0; + } + + /* + * Configuration and alternate setting changes must be done in + * process context, not interrupt context (or so documenation + * for usb_set_interface() and usb_set_configuration() claim). + */ + if (xhci_endpoint_init(xhci, xhci->devs[udev->slot_id], + udev, ep, GFP_KERNEL) < 0) { + dev_dbg(&udev->dev, "%s - could not initialize ep %#x\n", + __func__, ep->desc.bEndpointAddress); + return -ENOMEM; + } + + in_ctx->add_flags |= added_ctxs; + new_add_flags = in_ctx->add_flags; + + /* If xhci_endpoint_disable() was called for this endpoint, but the + * xHC hasn't been notified yet through the check_bandwidth() call, + * this re-adds a new state for the endpoint from the new endpoint + * descriptors. We must drop and re-add this endpoint, so we leave the + * drop flags alone. + */ + new_drop_flags = in_ctx->drop_flags; + + /* Update the last valid endpoint context, if we just added one past */ + if ((in_ctx->slot.dev_info & LAST_CTX_MASK) < LAST_CTX(last_ctx)) { + in_ctx->slot.dev_info &= ~LAST_CTX_MASK; + in_ctx->slot.dev_info |= LAST_CTX(last_ctx); + } + new_slot_info = in_ctx->slot.dev_info; + + xhci_dbg(xhci, "add ep 0x%x, slot id %d, new drop flags = %#x, new add flags = %#x, new slot info = %#x\n", + (unsigned int) ep->desc.bEndpointAddress, + udev->slot_id, + (unsigned int) new_drop_flags, + (unsigned int) new_add_flags, + (unsigned int) new_slot_info); + return 0; +} + +static void xhci_zero_in_ctx(struct xhci_virt_device *virt_dev) +{ + struct xhci_ep_ctx *ep_ctx; + int i; + + /* When a device's add flag and drop flag are zero, any subsequent + * configure endpoint command will leave that endpoint's state + * untouched. Make sure we don't leave any old state in the input + * endpoint contexts. + */ + virt_dev->in_ctx->drop_flags = 0; + virt_dev->in_ctx->add_flags = 0; + virt_dev->in_ctx->slot.dev_info &= ~LAST_CTX_MASK; + /* Endpoint 0 is always valid */ + virt_dev->in_ctx->slot.dev_info |= LAST_CTX(1); + for (i = 1; i < 31; ++i) { + ep_ctx = &virt_dev->in_ctx->ep[i]; + ep_ctx->ep_info = 0; + ep_ctx->ep_info2 = 0; + ep_ctx->deq[0] = 0; + ep_ctx->deq[1] = 0; + ep_ctx->tx_info = 0; + } +} + +/* Called after one or more calls to xhci_add_endpoint() or + * xhci_drop_endpoint(). If this call fails, the USB core is expected + * to call xhci_reset_bandwidth(). + * + * Since we are in the middle of changing either configuration or + * installing a new alt setting, the USB core won't allow URBs to be + * enqueued for any endpoint on the old config or interface. Nothing + * else should be touching the xhci->devs[slot_id] structure, so we + * don't need to take the xhci->lock for manipulating that. + */ +int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) +{ + int i; + int ret = 0; + int timeleft; + unsigned long flags; + struct xhci_hcd *xhci; + struct xhci_virt_device *virt_dev; + + ret = xhci_check_args(hcd, udev, NULL, 0, __func__); + if (ret <= 0) + return ret; + xhci = hcd_to_xhci(hcd); + + if (!udev->slot_id || !xhci->devs || !xhci->devs[udev->slot_id]) { + xhci_warn(xhci, "xHCI %s called with unaddressed device\n", + __func__); + return -EINVAL; + } + xhci_dbg(xhci, "%s called for udev %p\n", __func__, udev); + virt_dev = xhci->devs[udev->slot_id]; + + /* See section 4.6.6 - A0 = 1; A1 = D0 = D1 = 0 */ + virt_dev->in_ctx->add_flags |= SLOT_FLAG; + virt_dev->in_ctx->add_flags &= ~EP0_FLAG; + virt_dev->in_ctx->drop_flags &= ~SLOT_FLAG; + virt_dev->in_ctx->drop_flags &= ~EP0_FLAG; + xhci_dbg(xhci, "New Input Control Context:\n"); + xhci_dbg_ctx(xhci, virt_dev->in_ctx, virt_dev->in_ctx_dma, + LAST_CTX_TO_EP_NUM(virt_dev->in_ctx->slot.dev_info)); + + spin_lock_irqsave(&xhci->lock, flags); + ret = xhci_queue_configure_endpoint(xhci, virt_dev->in_ctx_dma, + udev->slot_id); + if (ret < 0) { + spin_unlock_irqrestore(&xhci->lock, flags); + xhci_dbg(xhci, "FIXME allocate a new ring segment\n"); + return -ENOMEM; + } + xhci_ring_cmd_db(xhci); + spin_unlock_irqrestore(&xhci->lock, flags); + + /* Wait for the configure endpoint command to complete */ + timeleft = wait_for_completion_interruptible_timeout( + &virt_dev->cmd_completion, + USB_CTRL_SET_TIMEOUT); + if (timeleft <= 0) { + xhci_warn(xhci, "%s while waiting for configure endpoint command\n", + timeleft == 0 ? "Timeout" : "Signal"); + /* FIXME cancel the configure endpoint command */ + return -ETIME; + } + + switch (virt_dev->cmd_status) { + case COMP_ENOMEM: + dev_warn(&udev->dev, "Not enough host controller resources " + "for new device state.\n"); + ret = -ENOMEM; + /* FIXME: can we allocate more resources for the HC? */ + break; + case COMP_BW_ERR: + dev_warn(&udev->dev, "Not enough bandwidth " + "for new device state.\n"); + ret = -ENOSPC; + /* FIXME: can we go back to the old state? */ + break; + case COMP_TRB_ERR: + /* the HCD set up something wrong */ + dev_warn(&udev->dev, "ERROR: Endpoint drop flag = 0, add flag = 1, " + "and endpoint is not disabled.\n"); + ret = -EINVAL; + break; + case COMP_SUCCESS: + dev_dbg(&udev->dev, "Successful Endpoint Configure command\n"); + break; + default: + xhci_err(xhci, "ERROR: unexpected command completion " + "code 0x%x.\n", virt_dev->cmd_status); + ret = -EINVAL; + break; + } + if (ret) { + /* Callee should call reset_bandwidth() */ + return ret; + } + + xhci_dbg(xhci, "Output context after successful config ep cmd:\n"); + xhci_dbg_ctx(xhci, virt_dev->out_ctx, virt_dev->out_ctx_dma, + LAST_CTX_TO_EP_NUM(virt_dev->in_ctx->slot.dev_info)); + + xhci_zero_in_ctx(virt_dev); + /* Free any old rings */ + for (i = 1; i < 31; ++i) { + if (virt_dev->new_ep_rings[i]) { + xhci_ring_free(xhci, virt_dev->ep_rings[i]); + virt_dev->ep_rings[i] = virt_dev->new_ep_rings[i]; + virt_dev->new_ep_rings[i] = NULL; + } + } + + return ret; +} + +void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) +{ + struct xhci_hcd *xhci; + struct xhci_virt_device *virt_dev; + int i, ret; + + ret = xhci_check_args(hcd, udev, NULL, 0, __func__); + if (ret <= 0) + return; + xhci = hcd_to_xhci(hcd); + + if (!xhci->devs || !xhci->devs[udev->slot_id]) { + xhci_warn(xhci, "xHCI %s called with unaddressed device\n", + __func__); + return; + } + xhci_dbg(xhci, "%s called for udev %p\n", __func__, udev); + virt_dev = xhci->devs[udev->slot_id]; + /* Free any rings allocated for added endpoints */ + for (i = 0; i < 31; ++i) { + if (virt_dev->new_ep_rings[i]) { + xhci_ring_free(xhci, virt_dev->new_ep_rings[i]); + virt_dev->new_ep_rings[i] = NULL; + } + } + xhci_zero_in_ctx(virt_dev); +} + +/* + * At this point, the struct usb_device is about to go away, the device has + * disconnected, and all traffic has been stopped and the endpoints have been + * disabled. Free any HC data structures associated with that device. + */ +void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev) +{ + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + unsigned long flags; + + if (udev->slot_id == 0) + return; + + spin_lock_irqsave(&xhci->lock, flags); + if (xhci_queue_slot_control(xhci, TRB_DISABLE_SLOT, udev->slot_id)) { + spin_unlock_irqrestore(&xhci->lock, flags); + xhci_dbg(xhci, "FIXME: allocate a command ring segment\n"); + return; + } + xhci_ring_cmd_db(xhci); + spin_unlock_irqrestore(&xhci->lock, flags); + /* + * Event command completion handler will free any data structures + * associated with the slot. XXX Can free sleep? + */ +} + +/* + * Returns 0 if the xHC ran out of device slots, the Enable Slot command + * timed out, or allocating memory failed. Returns 1 on success. + */ +int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev) +{ + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + unsigned long flags; + int timeleft; + int ret; + + spin_lock_irqsave(&xhci->lock, flags); + ret = xhci_queue_slot_control(xhci, TRB_ENABLE_SLOT, 0); + if (ret) { + spin_unlock_irqrestore(&xhci->lock, flags); + xhci_dbg(xhci, "FIXME: allocate a command ring segment\n"); + return 0; + } + xhci_ring_cmd_db(xhci); + spin_unlock_irqrestore(&xhci->lock, flags); + + /* XXX: how much time for xHC slot assignment? */ + timeleft = wait_for_completion_interruptible_timeout(&xhci->addr_dev, + USB_CTRL_SET_TIMEOUT); + if (timeleft <= 0) { + xhci_warn(xhci, "%s while waiting for a slot\n", + timeleft == 0 ? "Timeout" : "Signal"); + /* FIXME cancel the enable slot request */ + return 0; + } + + if (!xhci->slot_id) { + xhci_err(xhci, "Error while assigning device slot ID\n"); + return 0; + } + /* xhci_alloc_virt_device() does not touch rings; no need to lock */ + if (!xhci_alloc_virt_device(xhci, xhci->slot_id, udev, GFP_KERNEL)) { + /* Disable slot, if we can do it without mem alloc */ + xhci_warn(xhci, "Could not allocate xHCI USB device data structures\n"); + spin_lock_irqsave(&xhci->lock, flags); + if (!xhci_queue_slot_control(xhci, TRB_DISABLE_SLOT, udev->slot_id)) + xhci_ring_cmd_db(xhci); + spin_unlock_irqrestore(&xhci->lock, flags); + return 0; + } + udev->slot_id = xhci->slot_id; + /* Is this a LS or FS device under a HS hub? */ + /* Hub or peripherial? */ + return 1; +} + +/* + * Issue an Address Device command (which will issue a SetAddress request to + * the device). + * We should be protected by the usb_address0_mutex in khubd's hub_port_init, so + * we should only issue and wait on one address command at the same time. + * + * We add one to the device address issued by the hardware because the USB core + * uses address 1 for the root hubs (even though they're not really devices). + */ +int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) +{ + unsigned long flags; + int timeleft; + struct xhci_virt_device *virt_dev; + int ret = 0; + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + u32 temp; + + if (!udev->slot_id) { + xhci_dbg(xhci, "Bad Slot ID %d\n", udev->slot_id); + return -EINVAL; + } + + virt_dev = xhci->devs[udev->slot_id]; + + /* If this is a Set Address to an unconfigured device, setup ep 0 */ + if (!udev->config) + xhci_setup_addressable_virt_dev(xhci, udev); + /* Otherwise, assume the core has the device configured how it wants */ + + spin_lock_irqsave(&xhci->lock, flags); + ret = xhci_queue_address_device(xhci, virt_dev->in_ctx_dma, + udev->slot_id); + if (ret) { + spin_unlock_irqrestore(&xhci->lock, flags); + xhci_dbg(xhci, "FIXME: allocate a command ring segment\n"); + return ret; + } + xhci_ring_cmd_db(xhci); + spin_unlock_irqrestore(&xhci->lock, flags); + + /* ctrl tx can take up to 5 sec; XXX: need more time for xHC? */ + timeleft = wait_for_completion_interruptible_timeout(&xhci->addr_dev, + USB_CTRL_SET_TIMEOUT); + /* FIXME: From section 4.3.4: "Software shall be responsible for timing + * the SetAddress() "recovery interval" required by USB and aborting the + * command on a timeout. + */ + if (timeleft <= 0) { + xhci_warn(xhci, "%s while waiting for a slot\n", + timeleft == 0 ? "Timeout" : "Signal"); + /* FIXME cancel the address device command */ + return -ETIME; + } + + switch (virt_dev->cmd_status) { + case COMP_CTX_STATE: + case COMP_EBADSLT: + xhci_err(xhci, "Setup ERROR: address device command for slot %d.\n", + udev->slot_id); + ret = -EINVAL; + break; + case COMP_TX_ERR: + dev_warn(&udev->dev, "Device not responding to set address.\n"); + ret = -EPROTO; + break; + case COMP_SUCCESS: + xhci_dbg(xhci, "Successful Address Device command\n"); + break; + default: + xhci_err(xhci, "ERROR: unexpected command completion " + "code 0x%x.\n", virt_dev->cmd_status); + ret = -EINVAL; + break; + } + if (ret) { + return ret; + } + temp = xhci_readl(xhci, &xhci->op_regs->dcbaa_ptr[0]); + xhci_dbg(xhci, "Op regs DCBAA ptr[0] = %#08x\n", temp); + temp = xhci_readl(xhci, &xhci->op_regs->dcbaa_ptr[1]); + xhci_dbg(xhci, "Op regs DCBAA ptr[1] = %#08x\n", temp); + xhci_dbg(xhci, "Slot ID %d dcbaa entry[0] @%p = %#08x\n", + udev->slot_id, + &xhci->dcbaa->dev_context_ptrs[2*udev->slot_id], + xhci->dcbaa->dev_context_ptrs[2*udev->slot_id]); + xhci_dbg(xhci, "Slot ID %d dcbaa entry[1] @%p = %#08x\n", + udev->slot_id, + &xhci->dcbaa->dev_context_ptrs[2*udev->slot_id+1], + xhci->dcbaa->dev_context_ptrs[2*udev->slot_id+1]); + xhci_dbg(xhci, "Output Context DMA address = %#08llx\n", + (unsigned long long)virt_dev->out_ctx_dma); + xhci_dbg(xhci, "Slot ID %d Input Context:\n", udev->slot_id); + xhci_dbg_ctx(xhci, virt_dev->in_ctx, virt_dev->in_ctx_dma, 2); + xhci_dbg(xhci, "Slot ID %d Output Context:\n", udev->slot_id); + xhci_dbg_ctx(xhci, virt_dev->out_ctx, virt_dev->out_ctx_dma, 2); + /* + * USB core uses address 1 for the roothubs, so we add one to the + * address given back to us by the HC. + */ + udev->devnum = (virt_dev->out_ctx->slot.dev_state & DEV_ADDR_MASK) + 1; + /* Zero the input context control for later use */ + virt_dev->in_ctx->add_flags = 0; + virt_dev->in_ctx->drop_flags = 0; + /* Mirror flags in the output context for future ep enable/disable */ + virt_dev->out_ctx->add_flags = SLOT_FLAG | EP0_FLAG; + virt_dev->out_ctx->drop_flags = 0; + + xhci_dbg(xhci, "Device address = %d\n", udev->devnum); + /* XXX Meh, not sure if anyone else but choose_address uses this. */ + set_bit(udev->devnum, udev->bus->devmap.devicemap); + + return 0; +} + +int xhci_get_frame(struct usb_hcd *hcd) +{ + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + /* EHCI mods by the periodic size. Why? */ + return xhci_readl(xhci, &xhci->run_regs->microframe_index) >> 3; +} + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_LICENSE("GPL"); + +static int __init xhci_hcd_init(void) +{ +#ifdef CONFIG_PCI + int retval = 0; + + retval = xhci_register_pci(); + + if (retval < 0) { + printk(KERN_DEBUG "Problem registering PCI driver."); + return retval; + } +#endif + /* + * Check the compiler generated sizes of structures that must be laid + * out in specific ways for hardware access. + */ + BUILD_BUG_ON(sizeof(struct xhci_doorbell_array) != 256*32/8); + BUILD_BUG_ON(sizeof(struct xhci_slot_ctx) != 8*32/8); + BUILD_BUG_ON(sizeof(struct xhci_ep_ctx) != 8*32/8); + /* xhci_device_control has eight fields, and also + * embeds one xhci_slot_ctx and 31 xhci_ep_ctx + */ + BUILD_BUG_ON(sizeof(struct xhci_device_control) != (8+8+8*31)*32/8); + BUILD_BUG_ON(sizeof(struct xhci_stream_ctx) != 4*32/8); + BUILD_BUG_ON(sizeof(union xhci_trb) != 4*32/8); + BUILD_BUG_ON(sizeof(struct xhci_erst_entry) != 4*32/8); + BUILD_BUG_ON(sizeof(struct xhci_cap_regs) != 7*32/8); + BUILD_BUG_ON(sizeof(struct xhci_intr_reg) != 8*32/8); + /* xhci_run_regs has eight fields and embeds 128 xhci_intr_regs */ + BUILD_BUG_ON(sizeof(struct xhci_run_regs) != (8+8*128)*32/8); + BUILD_BUG_ON(sizeof(struct xhci_doorbell_array) != 256*32/8); + return 0; +} +module_init(xhci_hcd_init); + +static void __exit xhci_hcd_cleanup(void) +{ +#ifdef CONFIG_PCI + xhci_unregister_pci(); +#endif +} +module_exit(xhci_hcd_cleanup); diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c new file mode 100644 index 000000000000..eac5b53aa9e7 --- /dev/null +++ b/drivers/usb/host/xhci-hub.c @@ -0,0 +1,308 @@ +/* + * xHCI host controller driver + * + * Copyright (C) 2008 Intel Corp. + * + * Author: Sarah Sharp + * Some code borrowed from the Linux EHCI driver. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include + +#include "xhci.h" + +static void xhci_hub_descriptor(struct xhci_hcd *xhci, + struct usb_hub_descriptor *desc) +{ + int ports; + u16 temp; + + ports = HCS_MAX_PORTS(xhci->hcs_params1); + + /* USB 3.0 hubs have a different descriptor, but we fake this for now */ + desc->bDescriptorType = 0x29; + desc->bPwrOn2PwrGood = 10; /* xhci section 5.4.9 says 20ms max */ + desc->bHubContrCurrent = 0; + + desc->bNbrPorts = ports; + temp = 1 + (ports / 8); + desc->bDescLength = 7 + 2 * temp; + + /* Why does core/hcd.h define bitmap? It's just confusing. */ + memset(&desc->DeviceRemovable[0], 0, temp); + memset(&desc->DeviceRemovable[temp], 0xff, temp); + + /* Ugh, these should be #defines, FIXME */ + /* Using table 11-13 in USB 2.0 spec. */ + temp = 0; + /* Bits 1:0 - support port power switching, or power always on */ + if (HCC_PPC(xhci->hcc_params)) + temp |= 0x0001; + else + temp |= 0x0002; + /* Bit 2 - root hubs are not part of a compound device */ + /* Bits 4:3 - individual port over current protection */ + temp |= 0x0008; + /* Bits 6:5 - no TTs in root ports */ + /* Bit 7 - no port indicators */ + desc->wHubCharacteristics = (__force __u16) cpu_to_le16(temp); +} + +static unsigned int xhci_port_speed(unsigned int port_status) +{ + if (DEV_LOWSPEED(port_status)) + return 1 << USB_PORT_FEAT_LOWSPEED; + if (DEV_HIGHSPEED(port_status)) + return 1 << USB_PORT_FEAT_HIGHSPEED; + if (DEV_SUPERSPEED(port_status)) + return 1 << USB_PORT_FEAT_SUPERSPEED; + /* + * FIXME: Yes, we should check for full speed, but the core uses that as + * a default in portspeed() in usb/core/hub.c (which is the only place + * USB_PORT_FEAT_*SPEED is used). + */ + return 0; +} + +/* + * These bits are Read Only (RO) and should be saved and written to the + * registers: 0, 3, 10:13, 30 + * connect status, over-current status, port speed, and device removable. + * connect status and port speed are also sticky - meaning they're in + * the AUX well and they aren't changed by a hot, warm, or cold reset. + */ +#define XHCI_PORT_RO ((1<<0) | (1<<3) | (0xf<<10) | (1<<30)) +/* + * These bits are RW; writing a 0 clears the bit, writing a 1 sets the bit: + * bits 5:8, 9, 14:15, 25:27 + * link state, port power, port indicator state, "wake on" enable state + */ +#define XHCI_PORT_RWS ((0xf<<5) | (1<<9) | (0x3<<14) | (0x7<<25)) +/* + * These bits are RW; writing a 1 sets the bit, writing a 0 has no effect: + * bit 4 (port reset) + */ +#define XHCI_PORT_RW1S ((1<<4)) +/* + * These bits are RW; writing a 1 clears the bit, writing a 0 has no effect: + * bits 1, 17, 18, 19, 20, 21, 22, 23 + * port enable/disable, and + * change bits: connect, PED, warm port reset changed (reserved zero for USB 2.0 ports), + * over-current, reset, link state, and L1 change + */ +#define XHCI_PORT_RW1CS ((1<<1) | (0x7f<<17)) +/* + * Bit 16 is RW, and writing a '1' to it causes the link state control to be + * latched in + */ +#define XHCI_PORT_RW ((1<<16)) +/* + * These bits are Reserved Zero (RsvdZ) and zero should be written to them: + * bits 2, 24, 28:31 + */ +#define XHCI_PORT_RZ ((1<<2) | (1<<24) | (0xf<<28)) + +/* + * Given a port state, this function returns a value that would result in the + * port being in the same state, if the value was written to the port status + * control register. + * Save Read Only (RO) bits and save read/write bits where + * writing a 0 clears the bit and writing a 1 sets the bit (RWS). + * For all other types (RW1S, RW1CS, RW, and RZ), writing a '0' has no effect. + */ +static u32 xhci_port_state_to_neutral(u32 state) +{ + /* Save read-only status and port state */ + return (state & XHCI_PORT_RO) | (state & XHCI_PORT_RWS); +} + +int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, + u16 wIndex, char *buf, u16 wLength) +{ + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + int ports; + unsigned long flags; + u32 temp, status; + int retval = 0; + u32 __iomem *addr; + char *port_change_bit; + + ports = HCS_MAX_PORTS(xhci->hcs_params1); + + spin_lock_irqsave(&xhci->lock, flags); + switch (typeReq) { + case GetHubStatus: + /* No power source, over-current reported per port */ + memset(buf, 0, 4); + break; + case GetHubDescriptor: + xhci_hub_descriptor(xhci, (struct usb_hub_descriptor *) buf); + break; + case GetPortStatus: + if (!wIndex || wIndex > ports) + goto error; + wIndex--; + status = 0; + addr = &xhci->op_regs->port_status_base + NUM_PORT_REGS*(wIndex & 0xff); + temp = xhci_readl(xhci, addr); + xhci_dbg(xhci, "get port status, actual port %d status = 0x%x\n", wIndex, temp); + + /* wPortChange bits */ + if (temp & PORT_CSC) + status |= 1 << USB_PORT_FEAT_C_CONNECTION; + if (temp & PORT_PEC) + status |= 1 << USB_PORT_FEAT_C_ENABLE; + if ((temp & PORT_OCC)) + status |= 1 << USB_PORT_FEAT_C_OVER_CURRENT; + /* + * FIXME ignoring suspend, reset, and USB 2.1/3.0 specific + * changes + */ + if (temp & PORT_CONNECT) { + status |= 1 << USB_PORT_FEAT_CONNECTION; + status |= xhci_port_speed(temp); + } + if (temp & PORT_PE) + status |= 1 << USB_PORT_FEAT_ENABLE; + if (temp & PORT_OC) + status |= 1 << USB_PORT_FEAT_OVER_CURRENT; + if (temp & PORT_RESET) + status |= 1 << USB_PORT_FEAT_RESET; + if (temp & PORT_POWER) + status |= 1 << USB_PORT_FEAT_POWER; + xhci_dbg(xhci, "Get port status returned 0x%x\n", status); + put_unaligned(cpu_to_le32(status), (__le32 *) buf); + break; + case SetPortFeature: + wIndex &= 0xff; + if (!wIndex || wIndex > ports) + goto error; + wIndex--; + addr = &xhci->op_regs->port_status_base + NUM_PORT_REGS*(wIndex & 0xff); + temp = xhci_readl(xhci, addr); + temp = xhci_port_state_to_neutral(temp); + switch (wValue) { + case USB_PORT_FEAT_POWER: + /* + * Turn on ports, even if there isn't per-port switching. + * HC will report connect events even before this is set. + * However, khubd will ignore the roothub events until + * the roothub is registered. + */ + xhci_writel(xhci, temp | PORT_POWER, addr); + + temp = xhci_readl(xhci, addr); + xhci_dbg(xhci, "set port power, actual port %d status = 0x%x\n", wIndex, temp); + break; + case USB_PORT_FEAT_RESET: + temp = (temp | PORT_RESET); + xhci_writel(xhci, temp, addr); + + temp = xhci_readl(xhci, addr); + xhci_dbg(xhci, "set port reset, actual port %d status = 0x%x\n", wIndex, temp); + break; + default: + goto error; + } + temp = xhci_readl(xhci, addr); /* unblock any posted writes */ + break; + case ClearPortFeature: + if (!wIndex || wIndex > ports) + goto error; + wIndex--; + addr = &xhci->op_regs->port_status_base + + NUM_PORT_REGS*(wIndex & 0xff); + temp = xhci_readl(xhci, addr); + temp = xhci_port_state_to_neutral(temp); + switch (wValue) { + case USB_PORT_FEAT_C_RESET: + status = PORT_RC; + port_change_bit = "reset"; + break; + case USB_PORT_FEAT_C_CONNECTION: + status = PORT_CSC; + port_change_bit = "connect"; + break; + case USB_PORT_FEAT_C_OVER_CURRENT: + status = PORT_OCC; + port_change_bit = "over-current"; + break; + default: + goto error; + } + /* Change bits are all write 1 to clear */ + xhci_writel(xhci, temp | status, addr); + temp = xhci_readl(xhci, addr); + xhci_dbg(xhci, "clear port %s change, actual port %d status = 0x%x\n", + port_change_bit, wIndex, temp); + temp = xhci_readl(xhci, addr); /* unblock any posted writes */ + break; + default: +error: + /* "stall" on error */ + retval = -EPIPE; + } + spin_unlock_irqrestore(&xhci->lock, flags); + return retval; +} + +/* + * Returns 0 if the status hasn't changed, or the number of bytes in buf. + * Ports are 0-indexed from the HCD point of view, + * and 1-indexed from the USB core pointer of view. + * xHCI instances can have up to 127 ports, so FIXME if you see more than 15. + * + * Note that the status change bits will be cleared as soon as a port status + * change event is generated, so we use the saved status from that event. + */ +int xhci_hub_status_data(struct usb_hcd *hcd, char *buf) +{ + unsigned long flags; + u32 temp, status; + int i, retval; + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + int ports; + u32 __iomem *addr; + + ports = HCS_MAX_PORTS(xhci->hcs_params1); + + /* Initial status is no changes */ + buf[0] = 0; + status = 0; + if (ports > 7) { + buf[1] = 0; + retval = 2; + } else { + retval = 1; + } + + spin_lock_irqsave(&xhci->lock, flags); + /* For each port, did anything change? If so, set that bit in buf. */ + for (i = 0; i < ports; i++) { + addr = &xhci->op_regs->port_status_base + + NUM_PORT_REGS*i; + temp = xhci_readl(xhci, addr); + if (temp & (PORT_CSC | PORT_PEC | PORT_OCC)) { + if (i < 7) + buf[0] |= 1 << (i + 1); + else + buf[1] |= 1 << (i - 7); + status = 1; + } + } + spin_unlock_irqrestore(&xhci->lock, flags); + return status ? retval : 0; +} diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c new file mode 100644 index 000000000000..c8a72de1c508 --- /dev/null +++ b/drivers/usb/host/xhci-mem.c @@ -0,0 +1,769 @@ +/* + * xHCI host controller driver + * + * Copyright (C) 2008 Intel Corp. + * + * Author: Sarah Sharp + * Some code borrowed from the Linux EHCI driver. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include + +#include "xhci.h" + +/* + * Allocates a generic ring segment from the ring pool, sets the dma address, + * initializes the segment to zero, and sets the private next pointer to NULL. + * + * Section 4.11.1.1: + * "All components of all Command and Transfer TRBs shall be initialized to '0'" + */ +static struct xhci_segment *xhci_segment_alloc(struct xhci_hcd *xhci, gfp_t flags) +{ + struct xhci_segment *seg; + dma_addr_t dma; + + seg = kzalloc(sizeof *seg, flags); + if (!seg) + return 0; + xhci_dbg(xhci, "Allocating priv segment structure at %p\n", seg); + + seg->trbs = dma_pool_alloc(xhci->segment_pool, flags, &dma); + if (!seg->trbs) { + kfree(seg); + return 0; + } + xhci_dbg(xhci, "// Allocating segment at %p (virtual) 0x%llx (DMA)\n", + seg->trbs, (unsigned long long)dma); + + memset(seg->trbs, 0, SEGMENT_SIZE); + seg->dma = dma; + seg->next = NULL; + + return seg; +} + +static void xhci_segment_free(struct xhci_hcd *xhci, struct xhci_segment *seg) +{ + if (!seg) + return; + if (seg->trbs) { + xhci_dbg(xhci, "Freeing DMA segment at %p (virtual) 0x%llx (DMA)\n", + seg->trbs, (unsigned long long)seg->dma); + dma_pool_free(xhci->segment_pool, seg->trbs, seg->dma); + seg->trbs = NULL; + } + xhci_dbg(xhci, "Freeing priv segment structure at %p\n", seg); + kfree(seg); +} + +/* + * Make the prev segment point to the next segment. + * + * Change the last TRB in the prev segment to be a Link TRB which points to the + * DMA address of the next segment. The caller needs to set any Link TRB + * related flags, such as End TRB, Toggle Cycle, and no snoop. + */ +static void xhci_link_segments(struct xhci_hcd *xhci, struct xhci_segment *prev, + struct xhci_segment *next, bool link_trbs) +{ + u32 val; + + if (!prev || !next) + return; + prev->next = next; + if (link_trbs) { + prev->trbs[TRBS_PER_SEGMENT-1].link.segment_ptr[0] = next->dma; + + /* Set the last TRB in the segment to have a TRB type ID of Link TRB */ + val = prev->trbs[TRBS_PER_SEGMENT-1].link.control; + val &= ~TRB_TYPE_BITMASK; + val |= TRB_TYPE(TRB_LINK); + prev->trbs[TRBS_PER_SEGMENT-1].link.control = val; + } + xhci_dbg(xhci, "Linking segment 0x%llx to segment 0x%llx (DMA)\n", + (unsigned long long)prev->dma, + (unsigned long long)next->dma); +} + +/* XXX: Do we need the hcd structure in all these functions? */ +void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring) +{ + struct xhci_segment *seg; + struct xhci_segment *first_seg; + + if (!ring || !ring->first_seg) + return; + first_seg = ring->first_seg; + seg = first_seg->next; + xhci_dbg(xhci, "Freeing ring at %p\n", ring); + while (seg != first_seg) { + struct xhci_segment *next = seg->next; + xhci_segment_free(xhci, seg); + seg = next; + } + xhci_segment_free(xhci, first_seg); + ring->first_seg = NULL; + kfree(ring); +} + +/** + * Create a new ring with zero or more segments. + * + * Link each segment together into a ring. + * Set the end flag and the cycle toggle bit on the last segment. + * See section 4.9.1 and figures 15 and 16. + */ +static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci, + unsigned int num_segs, bool link_trbs, gfp_t flags) +{ + struct xhci_ring *ring; + struct xhci_segment *prev; + + ring = kzalloc(sizeof *(ring), flags); + xhci_dbg(xhci, "Allocating ring at %p\n", ring); + if (!ring) + return 0; + + INIT_LIST_HEAD(&ring->td_list); + INIT_LIST_HEAD(&ring->cancelled_td_list); + if (num_segs == 0) + return ring; + + ring->first_seg = xhci_segment_alloc(xhci, flags); + if (!ring->first_seg) + goto fail; + num_segs--; + + prev = ring->first_seg; + while (num_segs > 0) { + struct xhci_segment *next; + + next = xhci_segment_alloc(xhci, flags); + if (!next) + goto fail; + xhci_link_segments(xhci, prev, next, link_trbs); + + prev = next; + num_segs--; + } + xhci_link_segments(xhci, prev, ring->first_seg, link_trbs); + + if (link_trbs) { + /* See section 4.9.2.1 and 6.4.4.1 */ + prev->trbs[TRBS_PER_SEGMENT-1].link.control |= (LINK_TOGGLE); + xhci_dbg(xhci, "Wrote link toggle flag to" + " segment %p (virtual), 0x%llx (DMA)\n", + prev, (unsigned long long)prev->dma); + } + /* The ring is empty, so the enqueue pointer == dequeue pointer */ + ring->enqueue = ring->first_seg->trbs; + ring->enq_seg = ring->first_seg; + ring->dequeue = ring->enqueue; + ring->deq_seg = ring->first_seg; + /* The ring is initialized to 0. The producer must write 1 to the cycle + * bit to handover ownership of the TRB, so PCS = 1. The consumer must + * compare CCS to the cycle bit to check ownership, so CCS = 1. + */ + ring->cycle_state = 1; + + return ring; + +fail: + xhci_ring_free(xhci, ring); + return 0; +} + +/* All the xhci_tds in the ring's TD list should be freed at this point */ +void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id) +{ + struct xhci_virt_device *dev; + int i; + + /* Slot ID 0 is reserved */ + if (slot_id == 0 || !xhci->devs[slot_id]) + return; + + dev = xhci->devs[slot_id]; + xhci->dcbaa->dev_context_ptrs[2*slot_id] = 0; + xhci->dcbaa->dev_context_ptrs[2*slot_id + 1] = 0; + if (!dev) + return; + + for (i = 0; i < 31; ++i) + if (dev->ep_rings[i]) + xhci_ring_free(xhci, dev->ep_rings[i]); + + if (dev->in_ctx) + dma_pool_free(xhci->device_pool, + dev->in_ctx, dev->in_ctx_dma); + if (dev->out_ctx) + dma_pool_free(xhci->device_pool, + dev->out_ctx, dev->out_ctx_dma); + kfree(xhci->devs[slot_id]); + xhci->devs[slot_id] = 0; +} + +int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, + struct usb_device *udev, gfp_t flags) +{ + dma_addr_t dma; + struct xhci_virt_device *dev; + + /* Slot ID 0 is reserved */ + if (slot_id == 0 || xhci->devs[slot_id]) { + xhci_warn(xhci, "Bad Slot ID %d\n", slot_id); + return 0; + } + + xhci->devs[slot_id] = kzalloc(sizeof(*xhci->devs[slot_id]), flags); + if (!xhci->devs[slot_id]) + return 0; + dev = xhci->devs[slot_id]; + + /* Allocate the (output) device context that will be used in the HC */ + dev->out_ctx = dma_pool_alloc(xhci->device_pool, flags, &dma); + if (!dev->out_ctx) + goto fail; + dev->out_ctx_dma = dma; + xhci_dbg(xhci, "Slot %d output ctx = 0x%llx (dma)\n", slot_id, + (unsigned long long)dma); + memset(dev->out_ctx, 0, sizeof(*dev->out_ctx)); + + /* Allocate the (input) device context for address device command */ + dev->in_ctx = dma_pool_alloc(xhci->device_pool, flags, &dma); + if (!dev->in_ctx) + goto fail; + dev->in_ctx_dma = dma; + xhci_dbg(xhci, "Slot %d input ctx = 0x%llx (dma)\n", slot_id, + (unsigned long long)dma); + memset(dev->in_ctx, 0, sizeof(*dev->in_ctx)); + + /* Allocate endpoint 0 ring */ + dev->ep_rings[0] = xhci_ring_alloc(xhci, 1, true, flags); + if (!dev->ep_rings[0]) + goto fail; + + init_completion(&dev->cmd_completion); + + /* + * Point to output device context in dcbaa; skip the output control + * context, which is eight 32 bit fields (or 32 bytes long) + */ + xhci->dcbaa->dev_context_ptrs[2*slot_id] = + (u32) dev->out_ctx_dma + (32); + xhci_dbg(xhci, "Set slot id %d dcbaa entry %p to 0x%llx\n", + slot_id, + &xhci->dcbaa->dev_context_ptrs[2*slot_id], + (unsigned long long)dev->out_ctx_dma); + xhci->dcbaa->dev_context_ptrs[2*slot_id + 1] = 0; + + return 1; +fail: + xhci_free_virt_device(xhci, slot_id); + return 0; +} + +/* Setup an xHCI virtual device for a Set Address command */ +int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *udev) +{ + struct xhci_virt_device *dev; + struct xhci_ep_ctx *ep0_ctx; + struct usb_device *top_dev; + + dev = xhci->devs[udev->slot_id]; + /* Slot ID 0 is reserved */ + if (udev->slot_id == 0 || !dev) { + xhci_warn(xhci, "Slot ID %d is not assigned to this device\n", + udev->slot_id); + return -EINVAL; + } + ep0_ctx = &dev->in_ctx->ep[0]; + + /* 2) New slot context and endpoint 0 context are valid*/ + dev->in_ctx->add_flags = SLOT_FLAG | EP0_FLAG; + + /* 3) Only the control endpoint is valid - one endpoint context */ + dev->in_ctx->slot.dev_info |= LAST_CTX(1); + + switch (udev->speed) { + case USB_SPEED_SUPER: + dev->in_ctx->slot.dev_info |= (u32) udev->route; + dev->in_ctx->slot.dev_info |= (u32) SLOT_SPEED_SS; + break; + case USB_SPEED_HIGH: + dev->in_ctx->slot.dev_info |= (u32) SLOT_SPEED_HS; + break; + case USB_SPEED_FULL: + dev->in_ctx->slot.dev_info |= (u32) SLOT_SPEED_FS; + break; + case USB_SPEED_LOW: + dev->in_ctx->slot.dev_info |= (u32) SLOT_SPEED_LS; + break; + case USB_SPEED_VARIABLE: + xhci_dbg(xhci, "FIXME xHCI doesn't support wireless speeds\n"); + return -EINVAL; + break; + default: + /* Speed was set earlier, this shouldn't happen. */ + BUG(); + } + /* Find the root hub port this device is under */ + for (top_dev = udev; top_dev->parent && top_dev->parent->parent; + top_dev = top_dev->parent) + /* Found device below root hub */; + dev->in_ctx->slot.dev_info2 |= (u32) ROOT_HUB_PORT(top_dev->portnum); + xhci_dbg(xhci, "Set root hub portnum to %d\n", top_dev->portnum); + + /* Is this a LS/FS device under a HS hub? */ + /* + * FIXME: I don't think this is right, where does the TT info for the + * roothub or parent hub come from? + */ + if ((udev->speed == USB_SPEED_LOW || udev->speed == USB_SPEED_FULL) && + udev->tt) { + dev->in_ctx->slot.tt_info = udev->tt->hub->slot_id; + dev->in_ctx->slot.tt_info |= udev->ttport << 8; + } + xhci_dbg(xhci, "udev->tt = %p\n", udev->tt); + xhci_dbg(xhci, "udev->ttport = 0x%x\n", udev->ttport); + + /* Step 4 - ring already allocated */ + /* Step 5 */ + ep0_ctx->ep_info2 = EP_TYPE(CTRL_EP); + /* + * See section 4.3 bullet 6: + * The default Max Packet size for ep0 is "8 bytes for a USB2 + * LS/FS/HS device or 512 bytes for a USB3 SS device" + * XXX: Not sure about wireless USB devices. + */ + if (udev->speed == USB_SPEED_SUPER) + ep0_ctx->ep_info2 |= MAX_PACKET(512); + else + ep0_ctx->ep_info2 |= MAX_PACKET(8); + /* EP 0 can handle "burst" sizes of 1, so Max Burst Size field is 0 */ + ep0_ctx->ep_info2 |= MAX_BURST(0); + ep0_ctx->ep_info2 |= ERROR_COUNT(3); + + ep0_ctx->deq[0] = + dev->ep_rings[0]->first_seg->dma; + ep0_ctx->deq[0] |= dev->ep_rings[0]->cycle_state; + ep0_ctx->deq[1] = 0; + + /* Steps 7 and 8 were done in xhci_alloc_virt_device() */ + + return 0; +} + +/* Return the polling or NAK interval. + * + * The polling interval is expressed in "microframes". If xHCI's Interval field + * is set to N, it will service the endpoint every 2^(Interval)*125us. + * + * The NAK interval is one NAK per 1 to 255 microframes, or no NAKs if interval + * is set to 0. + */ +static inline unsigned int xhci_get_endpoint_interval(struct usb_device *udev, + struct usb_host_endpoint *ep) +{ + unsigned int interval = 0; + + switch (udev->speed) { + case USB_SPEED_HIGH: + /* Max NAK rate */ + if (usb_endpoint_xfer_control(&ep->desc) || + usb_endpoint_xfer_bulk(&ep->desc)) + interval = ep->desc.bInterval; + /* Fall through - SS and HS isoc/int have same decoding */ + case USB_SPEED_SUPER: + if (usb_endpoint_xfer_int(&ep->desc) || + usb_endpoint_xfer_isoc(&ep->desc)) { + if (ep->desc.bInterval == 0) + interval = 0; + else + interval = ep->desc.bInterval - 1; + if (interval > 15) + interval = 15; + if (interval != ep->desc.bInterval + 1) + dev_warn(&udev->dev, "ep %#x - rounding interval to %d microframes\n", + ep->desc.bEndpointAddress, 1 << interval); + } + break; + /* Convert bInterval (in 1-255 frames) to microframes and round down to + * nearest power of 2. + */ + case USB_SPEED_FULL: + case USB_SPEED_LOW: + if (usb_endpoint_xfer_int(&ep->desc) || + usb_endpoint_xfer_isoc(&ep->desc)) { + interval = fls(8*ep->desc.bInterval) - 1; + if (interval > 10) + interval = 10; + if (interval < 3) + interval = 3; + if ((1 << interval) != 8*ep->desc.bInterval) + dev_warn(&udev->dev, "ep %#x - rounding interval to %d microframes\n", + ep->desc.bEndpointAddress, 1 << interval); + } + break; + default: + BUG(); + } + return EP_INTERVAL(interval); +} + +static inline u32 xhci_get_endpoint_type(struct usb_device *udev, + struct usb_host_endpoint *ep) +{ + int in; + u32 type; + + in = usb_endpoint_dir_in(&ep->desc); + if (usb_endpoint_xfer_control(&ep->desc)) { + type = EP_TYPE(CTRL_EP); + } else if (usb_endpoint_xfer_bulk(&ep->desc)) { + if (in) + type = EP_TYPE(BULK_IN_EP); + else + type = EP_TYPE(BULK_OUT_EP); + } else if (usb_endpoint_xfer_isoc(&ep->desc)) { + if (in) + type = EP_TYPE(ISOC_IN_EP); + else + type = EP_TYPE(ISOC_OUT_EP); + } else if (usb_endpoint_xfer_int(&ep->desc)) { + if (in) + type = EP_TYPE(INT_IN_EP); + else + type = EP_TYPE(INT_OUT_EP); + } else { + BUG(); + } + return type; +} + +int xhci_endpoint_init(struct xhci_hcd *xhci, + struct xhci_virt_device *virt_dev, + struct usb_device *udev, + struct usb_host_endpoint *ep, + gfp_t mem_flags) +{ + unsigned int ep_index; + struct xhci_ep_ctx *ep_ctx; + struct xhci_ring *ep_ring; + unsigned int max_packet; + unsigned int max_burst; + + ep_index = xhci_get_endpoint_index(&ep->desc); + ep_ctx = &virt_dev->in_ctx->ep[ep_index]; + + /* Set up the endpoint ring */ + virt_dev->new_ep_rings[ep_index] = xhci_ring_alloc(xhci, 1, true, mem_flags); + if (!virt_dev->new_ep_rings[ep_index]) + return -ENOMEM; + ep_ring = virt_dev->new_ep_rings[ep_index]; + ep_ctx->deq[0] = ep_ring->first_seg->dma | ep_ring->cycle_state; + ep_ctx->deq[1] = 0; + + ep_ctx->ep_info = xhci_get_endpoint_interval(udev, ep); + + /* FIXME dig Mult and streams info out of ep companion desc */ + + /* Allow 3 retries for everything but isoc */ + if (!usb_endpoint_xfer_isoc(&ep->desc)) + ep_ctx->ep_info2 = ERROR_COUNT(3); + else + ep_ctx->ep_info2 = ERROR_COUNT(0); + + ep_ctx->ep_info2 |= xhci_get_endpoint_type(udev, ep); + + /* Set the max packet size and max burst */ + switch (udev->speed) { + case USB_SPEED_SUPER: + max_packet = ep->desc.wMaxPacketSize; + ep_ctx->ep_info2 |= MAX_PACKET(max_packet); + /* dig out max burst from ep companion desc */ + max_packet = ep->ss_ep_comp->desc.bMaxBurst; + ep_ctx->ep_info2 |= MAX_BURST(max_packet); + break; + case USB_SPEED_HIGH: + /* bits 11:12 specify the number of additional transaction + * opportunities per microframe (USB 2.0, section 9.6.6) + */ + if (usb_endpoint_xfer_isoc(&ep->desc) || + usb_endpoint_xfer_int(&ep->desc)) { + max_burst = (ep->desc.wMaxPacketSize & 0x1800) >> 11; + ep_ctx->ep_info2 |= MAX_BURST(max_burst); + } + /* Fall through */ + case USB_SPEED_FULL: + case USB_SPEED_LOW: + max_packet = ep->desc.wMaxPacketSize & 0x3ff; + ep_ctx->ep_info2 |= MAX_PACKET(max_packet); + break; + default: + BUG(); + } + /* FIXME Debug endpoint context */ + return 0; +} + +void xhci_endpoint_zero(struct xhci_hcd *xhci, + struct xhci_virt_device *virt_dev, + struct usb_host_endpoint *ep) +{ + unsigned int ep_index; + struct xhci_ep_ctx *ep_ctx; + + ep_index = xhci_get_endpoint_index(&ep->desc); + ep_ctx = &virt_dev->in_ctx->ep[ep_index]; + + ep_ctx->ep_info = 0; + ep_ctx->ep_info2 = 0; + ep_ctx->deq[0] = 0; + ep_ctx->deq[1] = 0; + ep_ctx->tx_info = 0; + /* Don't free the endpoint ring until the set interface or configuration + * request succeeds. + */ +} + +void xhci_mem_cleanup(struct xhci_hcd *xhci) +{ + struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); + int size; + int i; + + /* Free the Event Ring Segment Table and the actual Event Ring */ + xhci_writel(xhci, 0, &xhci->ir_set->erst_size); + xhci_writel(xhci, 0, &xhci->ir_set->erst_base[0]); + xhci_writel(xhci, 0, &xhci->ir_set->erst_base[1]); + xhci_writel(xhci, 0, &xhci->ir_set->erst_dequeue[0]); + xhci_writel(xhci, 0, &xhci->ir_set->erst_dequeue[1]); + size = sizeof(struct xhci_erst_entry)*(xhci->erst.num_entries); + if (xhci->erst.entries) + pci_free_consistent(pdev, size, + xhci->erst.entries, xhci->erst.erst_dma_addr); + xhci->erst.entries = NULL; + xhci_dbg(xhci, "Freed ERST\n"); + if (xhci->event_ring) + xhci_ring_free(xhci, xhci->event_ring); + xhci->event_ring = NULL; + xhci_dbg(xhci, "Freed event ring\n"); + + xhci_writel(xhci, 0, &xhci->op_regs->cmd_ring[0]); + xhci_writel(xhci, 0, &xhci->op_regs->cmd_ring[1]); + if (xhci->cmd_ring) + xhci_ring_free(xhci, xhci->cmd_ring); + xhci->cmd_ring = NULL; + xhci_dbg(xhci, "Freed command ring\n"); + + for (i = 1; i < MAX_HC_SLOTS; ++i) + xhci_free_virt_device(xhci, i); + + if (xhci->segment_pool) + dma_pool_destroy(xhci->segment_pool); + xhci->segment_pool = NULL; + xhci_dbg(xhci, "Freed segment pool\n"); + + if (xhci->device_pool) + dma_pool_destroy(xhci->device_pool); + xhci->device_pool = NULL; + xhci_dbg(xhci, "Freed device context pool\n"); + + xhci_writel(xhci, 0, &xhci->op_regs->dcbaa_ptr[0]); + xhci_writel(xhci, 0, &xhci->op_regs->dcbaa_ptr[1]); + if (xhci->dcbaa) + pci_free_consistent(pdev, sizeof(*xhci->dcbaa), + xhci->dcbaa, xhci->dcbaa->dma); + xhci->dcbaa = NULL; + + xhci->page_size = 0; + xhci->page_shift = 0; +} + +int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) +{ + dma_addr_t dma; + struct device *dev = xhci_to_hcd(xhci)->self.controller; + unsigned int val, val2; + struct xhci_segment *seg; + u32 page_size; + int i; + + page_size = xhci_readl(xhci, &xhci->op_regs->page_size); + xhci_dbg(xhci, "Supported page size register = 0x%x\n", page_size); + for (i = 0; i < 16; i++) { + if ((0x1 & page_size) != 0) + break; + page_size = page_size >> 1; + } + if (i < 16) + xhci_dbg(xhci, "Supported page size of %iK\n", (1 << (i+12)) / 1024); + else + xhci_warn(xhci, "WARN: no supported page size\n"); + /* Use 4K pages, since that's common and the minimum the HC supports */ + xhci->page_shift = 12; + xhci->page_size = 1 << xhci->page_shift; + xhci_dbg(xhci, "HCD page size set to %iK\n", xhci->page_size / 1024); + + /* + * Program the Number of Device Slots Enabled field in the CONFIG + * register with the max value of slots the HC can handle. + */ + val = HCS_MAX_SLOTS(xhci_readl(xhci, &xhci->cap_regs->hcs_params1)); + xhci_dbg(xhci, "// xHC can handle at most %d device slots.\n", + (unsigned int) val); + val2 = xhci_readl(xhci, &xhci->op_regs->config_reg); + val |= (val2 & ~HCS_SLOTS_MASK); + xhci_dbg(xhci, "// Setting Max device slots reg = 0x%x.\n", + (unsigned int) val); + xhci_writel(xhci, val, &xhci->op_regs->config_reg); + + /* + * Section 5.4.8 - doorbell array must be + * "physically contiguous and 64-byte (cache line) aligned". + */ + xhci->dcbaa = pci_alloc_consistent(to_pci_dev(dev), + sizeof(*xhci->dcbaa), &dma); + if (!xhci->dcbaa) + goto fail; + memset(xhci->dcbaa, 0, sizeof *(xhci->dcbaa)); + xhci->dcbaa->dma = dma; + xhci_dbg(xhci, "// Device context base array address = 0x%llx (DMA), %p (virt)\n", + (unsigned long long)xhci->dcbaa->dma, xhci->dcbaa); + xhci_writel(xhci, dma, &xhci->op_regs->dcbaa_ptr[0]); + xhci_writel(xhci, (u32) 0, &xhci->op_regs->dcbaa_ptr[1]); + + /* + * Initialize the ring segment pool. The ring must be a contiguous + * structure comprised of TRBs. The TRBs must be 16 byte aligned, + * however, the command ring segment needs 64-byte aligned segments, + * so we pick the greater alignment need. + */ + xhci->segment_pool = dma_pool_create("xHCI ring segments", dev, + SEGMENT_SIZE, 64, xhci->page_size); + /* See Table 46 and Note on Figure 55 */ + /* FIXME support 64-byte contexts */ + xhci->device_pool = dma_pool_create("xHCI input/output contexts", dev, + sizeof(struct xhci_device_control), + 64, xhci->page_size); + if (!xhci->segment_pool || !xhci->device_pool) + goto fail; + + /* Set up the command ring to have one segments for now. */ + xhci->cmd_ring = xhci_ring_alloc(xhci, 1, true, flags); + if (!xhci->cmd_ring) + goto fail; + xhci_dbg(xhci, "Allocated command ring at %p\n", xhci->cmd_ring); + xhci_dbg(xhci, "First segment DMA is 0x%llx\n", + (unsigned long long)xhci->cmd_ring->first_seg->dma); + + /* Set the address in the Command Ring Control register */ + val = xhci_readl(xhci, &xhci->op_regs->cmd_ring[0]); + val = (val & ~CMD_RING_ADDR_MASK) | + (xhci->cmd_ring->first_seg->dma & CMD_RING_ADDR_MASK) | + xhci->cmd_ring->cycle_state; + xhci_dbg(xhci, "// Setting command ring address low bits to 0x%x\n", val); + xhci_writel(xhci, val, &xhci->op_regs->cmd_ring[0]); + xhci_dbg(xhci, "// Setting command ring address high bits to 0x0\n"); + xhci_writel(xhci, (u32) 0, &xhci->op_regs->cmd_ring[1]); + xhci_dbg_cmd_ptrs(xhci); + + val = xhci_readl(xhci, &xhci->cap_regs->db_off); + val &= DBOFF_MASK; + xhci_dbg(xhci, "// Doorbell array is located at offset 0x%x" + " from cap regs base addr\n", val); + xhci->dba = (void *) xhci->cap_regs + val; + xhci_dbg_regs(xhci); + xhci_print_run_regs(xhci); + /* Set ir_set to interrupt register set 0 */ + xhci->ir_set = (void *) xhci->run_regs->ir_set; + + /* + * Event ring setup: Allocate a normal ring, but also setup + * the event ring segment table (ERST). Section 4.9.3. + */ + xhci_dbg(xhci, "// Allocating event ring\n"); + xhci->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, false, flags); + if (!xhci->event_ring) + goto fail; + + xhci->erst.entries = pci_alloc_consistent(to_pci_dev(dev), + sizeof(struct xhci_erst_entry)*ERST_NUM_SEGS, &dma); + if (!xhci->erst.entries) + goto fail; + xhci_dbg(xhci, "// Allocated event ring segment table at 0x%llx\n", + (unsigned long long)dma); + + memset(xhci->erst.entries, 0, sizeof(struct xhci_erst_entry)*ERST_NUM_SEGS); + xhci->erst.num_entries = ERST_NUM_SEGS; + xhci->erst.erst_dma_addr = dma; + xhci_dbg(xhci, "Set ERST to 0; private num segs = %i, virt addr = %p, dma addr = 0x%llx\n", + xhci->erst.num_entries, + xhci->erst.entries, + (unsigned long long)xhci->erst.erst_dma_addr); + + /* set ring base address and size for each segment table entry */ + for (val = 0, seg = xhci->event_ring->first_seg; val < ERST_NUM_SEGS; val++) { + struct xhci_erst_entry *entry = &xhci->erst.entries[val]; + entry->seg_addr[0] = seg->dma; + entry->seg_addr[1] = 0; + entry->seg_size = TRBS_PER_SEGMENT; + entry->rsvd = 0; + seg = seg->next; + } + + /* set ERST count with the number of entries in the segment table */ + val = xhci_readl(xhci, &xhci->ir_set->erst_size); + val &= ERST_SIZE_MASK; + val |= ERST_NUM_SEGS; + xhci_dbg(xhci, "// Write ERST size = %i to ir_set 0 (some bits preserved)\n", + val); + xhci_writel(xhci, val, &xhci->ir_set->erst_size); + + xhci_dbg(xhci, "// Set ERST entries to point to event ring.\n"); + /* set the segment table base address */ + xhci_dbg(xhci, "// Set ERST base address for ir_set 0 = 0x%llx\n", + (unsigned long long)xhci->erst.erst_dma_addr); + val = xhci_readl(xhci, &xhci->ir_set->erst_base[0]); + val &= ERST_PTR_MASK; + val |= (xhci->erst.erst_dma_addr & ~ERST_PTR_MASK); + xhci_writel(xhci, val, &xhci->ir_set->erst_base[0]); + xhci_writel(xhci, 0, &xhci->ir_set->erst_base[1]); + + /* Set the event ring dequeue address */ + xhci_set_hc_event_deq(xhci); + xhci_dbg(xhci, "Wrote ERST address to ir_set 0.\n"); + xhci_print_ir_set(xhci, xhci->ir_set, 0); + + /* + * XXX: Might need to set the Interrupter Moderation Register to + * something other than the default (~1ms minimum between interrupts). + * See section 5.5.1.2. + */ + init_completion(&xhci->addr_dev); + for (i = 0; i < MAX_HC_SLOTS; ++i) + xhci->devs[i] = 0; + + return 0; +fail: + xhci_warn(xhci, "Couldn't initialize memory\n"); + xhci_mem_cleanup(xhci); + return -ENOMEM; +} diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c new file mode 100644 index 000000000000..1462709e26c0 --- /dev/null +++ b/drivers/usb/host/xhci-pci.c @@ -0,0 +1,166 @@ +/* + * xHCI host controller driver PCI Bus Glue. + * + * Copyright (C) 2008 Intel Corp. + * + * Author: Sarah Sharp + * Some code borrowed from the Linux EHCI driver. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include + +#include "xhci.h" + +static const char hcd_name[] = "xhci_hcd"; + +/* called after powerup, by probe or system-pm "wakeup" */ +static int xhci_pci_reinit(struct xhci_hcd *xhci, struct pci_dev *pdev) +{ + /* + * TODO: Implement finding debug ports later. + * TODO: see if there are any quirks that need to be added to handle + * new extended capabilities. + */ + + /* PCI Memory-Write-Invalidate cycle support is optional (uncommon) */ + if (!pci_set_mwi(pdev)) + xhci_dbg(xhci, "MWI active\n"); + + xhci_dbg(xhci, "Finished xhci_pci_reinit\n"); + return 0; +} + +/* called during probe() after chip reset completes */ +static int xhci_pci_setup(struct usb_hcd *hcd) +{ + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + struct pci_dev *pdev = to_pci_dev(hcd->self.controller); + int retval; + + xhci->cap_regs = hcd->regs; + xhci->op_regs = hcd->regs + + HC_LENGTH(xhci_readl(xhci, &xhci->cap_regs->hc_capbase)); + xhci->run_regs = hcd->regs + + (xhci_readl(xhci, &xhci->cap_regs->run_regs_off) & RTSOFF_MASK); + /* Cache read-only capability registers */ + xhci->hcs_params1 = xhci_readl(xhci, &xhci->cap_regs->hcs_params1); + xhci->hcs_params2 = xhci_readl(xhci, &xhci->cap_regs->hcs_params2); + xhci->hcs_params3 = xhci_readl(xhci, &xhci->cap_regs->hcs_params3); + xhci->hcc_params = xhci_readl(xhci, &xhci->cap_regs->hcc_params); + xhci_print_registers(xhci); + + /* Make sure the HC is halted. */ + retval = xhci_halt(xhci); + if (retval) + return retval; + + xhci_dbg(xhci, "Resetting HCD\n"); + /* Reset the internal HC memory state and registers. */ + retval = xhci_reset(xhci); + if (retval) + return retval; + xhci_dbg(xhci, "Reset complete\n"); + + xhci_dbg(xhci, "Calling HCD init\n"); + /* Initialize HCD and host controller data structures. */ + retval = xhci_init(hcd); + if (retval) + return retval; + xhci_dbg(xhci, "Called HCD init\n"); + + pci_read_config_byte(pdev, XHCI_SBRN_OFFSET, &xhci->sbrn); + xhci_dbg(xhci, "Got SBRN %u\n", (unsigned int) xhci->sbrn); + + /* Find any debug ports */ + return xhci_pci_reinit(xhci, pdev); +} + +static const struct hc_driver xhci_pci_hc_driver = { + .description = hcd_name, + .product_desc = "xHCI Host Controller", + .hcd_priv_size = sizeof(struct xhci_hcd), + + /* + * generic hardware linkage + */ + .irq = xhci_irq, + .flags = HCD_MEMORY | HCD_USB3, + + /* + * basic lifecycle operations + */ + .reset = xhci_pci_setup, + .start = xhci_run, + /* suspend and resume implemented later */ + .stop = xhci_stop, + .shutdown = xhci_shutdown, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = xhci_urb_enqueue, + .urb_dequeue = xhci_urb_dequeue, + .alloc_dev = xhci_alloc_dev, + .free_dev = xhci_free_dev, + .add_endpoint = xhci_add_endpoint, + .drop_endpoint = xhci_drop_endpoint, + .check_bandwidth = xhci_check_bandwidth, + .reset_bandwidth = xhci_reset_bandwidth, + .address_device = xhci_address_device, + + /* + * scheduling support + */ + .get_frame_number = xhci_get_frame, + + /* Root hub support */ + .hub_control = xhci_hub_control, + .hub_status_data = xhci_hub_status_data, +}; + +/*-------------------------------------------------------------------------*/ + +/* PCI driver selection metadata; PCI hotplugging uses this */ +static const struct pci_device_id pci_ids[] = { { + /* handle any USB 3.0 xHCI controller */ + PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_XHCI, ~0), + .driver_data = (unsigned long) &xhci_pci_hc_driver, + }, + { /* end: all zeroes */ } +}; +MODULE_DEVICE_TABLE(pci, pci_ids); + +/* pci driver glue; this is a "new style" PCI driver module */ +static struct pci_driver xhci_pci_driver = { + .name = (char *) hcd_name, + .id_table = pci_ids, + + .probe = usb_hcd_pci_probe, + .remove = usb_hcd_pci_remove, + /* suspend and resume implemented later */ + + .shutdown = usb_hcd_pci_shutdown, +}; + +int xhci_register_pci() +{ + return pci_register_driver(&xhci_pci_driver); +} + +void xhci_unregister_pci() +{ + pci_unregister_driver(&xhci_pci_driver); +} diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c new file mode 100644 index 000000000000..02d81985c454 --- /dev/null +++ b/drivers/usb/host/xhci-ring.c @@ -0,0 +1,1648 @@ +/* + * xHCI host controller driver + * + * Copyright (C) 2008 Intel Corp. + * + * Author: Sarah Sharp + * Some code borrowed from the Linux EHCI driver. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * Ring initialization rules: + * 1. Each segment is initialized to zero, except for link TRBs. + * 2. Ring cycle state = 0. This represents Producer Cycle State (PCS) or + * Consumer Cycle State (CCS), depending on ring function. + * 3. Enqueue pointer = dequeue pointer = address of first TRB in the segment. + * + * Ring behavior rules: + * 1. A ring is empty if enqueue == dequeue. This means there will always be at + * least one free TRB in the ring. This is useful if you want to turn that + * into a link TRB and expand the ring. + * 2. When incrementing an enqueue or dequeue pointer, if the next TRB is a + * link TRB, then load the pointer with the address in the link TRB. If the + * link TRB had its toggle bit set, you may need to update the ring cycle + * state (see cycle bit rules). You may have to do this multiple times + * until you reach a non-link TRB. + * 3. A ring is full if enqueue++ (for the definition of increment above) + * equals the dequeue pointer. + * + * Cycle bit rules: + * 1. When a consumer increments a dequeue pointer and encounters a toggle bit + * in a link TRB, it must toggle the ring cycle state. + * 2. When a producer increments an enqueue pointer and encounters a toggle bit + * in a link TRB, it must toggle the ring cycle state. + * + * Producer rules: + * 1. Check if ring is full before you enqueue. + * 2. Write the ring cycle state to the cycle bit in the TRB you're enqueuing. + * Update enqueue pointer between each write (which may update the ring + * cycle state). + * 3. Notify consumer. If SW is producer, it rings the doorbell for command + * and endpoint rings. If HC is the producer for the event ring, + * and it generates an interrupt according to interrupt modulation rules. + * + * Consumer rules: + * 1. Check if TRB belongs to you. If the cycle bit == your ring cycle state, + * the TRB is owned by the consumer. + * 2. Update dequeue pointer (which may update the ring cycle state) and + * continue processing TRBs until you reach a TRB which is not owned by you. + * 3. Notify the producer. SW is the consumer for the event ring, and it + * updates event ring dequeue pointer. HC is the consumer for the command and + * endpoint rings; it generates events on the event ring for these. + */ + +#include +#include "xhci.h" + +/* + * Returns zero if the TRB isn't in this segment, otherwise it returns the DMA + * address of the TRB. + */ +dma_addr_t xhci_trb_virt_to_dma(struct xhci_segment *seg, + union xhci_trb *trb) +{ + unsigned long segment_offset; + + if (!seg || !trb || trb < seg->trbs) + return 0; + /* offset in TRBs */ + segment_offset = trb - seg->trbs; + if (segment_offset > TRBS_PER_SEGMENT) + return 0; + return seg->dma + (segment_offset * sizeof(*trb)); +} + +/* Does this link TRB point to the first segment in a ring, + * or was the previous TRB the last TRB on the last segment in the ERST? + */ +static inline bool last_trb_on_last_seg(struct xhci_hcd *xhci, struct xhci_ring *ring, + struct xhci_segment *seg, union xhci_trb *trb) +{ + if (ring == xhci->event_ring) + return (trb == &seg->trbs[TRBS_PER_SEGMENT]) && + (seg->next == xhci->event_ring->first_seg); + else + return trb->link.control & LINK_TOGGLE; +} + +/* Is this TRB a link TRB or was the last TRB the last TRB in this event ring + * segment? I.e. would the updated event TRB pointer step off the end of the + * event seg? + */ +static inline int last_trb(struct xhci_hcd *xhci, struct xhci_ring *ring, + struct xhci_segment *seg, union xhci_trb *trb) +{ + if (ring == xhci->event_ring) + return trb == &seg->trbs[TRBS_PER_SEGMENT]; + else + return (trb->link.control & TRB_TYPE_BITMASK) == TRB_TYPE(TRB_LINK); +} + +/* Updates trb to point to the next TRB in the ring, and updates seg if the next + * TRB is in a new segment. This does not skip over link TRBs, and it does not + * effect the ring dequeue or enqueue pointers. + */ +static void next_trb(struct xhci_hcd *xhci, + struct xhci_ring *ring, + struct xhci_segment **seg, + union xhci_trb **trb) +{ + if (last_trb(xhci, ring, *seg, *trb)) { + *seg = (*seg)->next; + *trb = ((*seg)->trbs); + } else { + *trb = (*trb)++; + } +} + +/* + * See Cycle bit rules. SW is the consumer for the event ring only. + * Don't make a ring full of link TRBs. That would be dumb and this would loop. + */ +static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer) +{ + union xhci_trb *next = ++(ring->dequeue); + + ring->deq_updates++; + /* Update the dequeue pointer further if that was a link TRB or we're at + * the end of an event ring segment (which doesn't have link TRBS) + */ + while (last_trb(xhci, ring, ring->deq_seg, next)) { + if (consumer && last_trb_on_last_seg(xhci, ring, ring->deq_seg, next)) { + ring->cycle_state = (ring->cycle_state ? 0 : 1); + if (!in_interrupt()) + xhci_dbg(xhci, "Toggle cycle state for ring %p = %i\n", + ring, + (unsigned int) ring->cycle_state); + } + ring->deq_seg = ring->deq_seg->next; + ring->dequeue = ring->deq_seg->trbs; + next = ring->dequeue; + } +} + +/* + * See Cycle bit rules. SW is the consumer for the event ring only. + * Don't make a ring full of link TRBs. That would be dumb and this would loop. + * + * If we've just enqueued a TRB that is in the middle of a TD (meaning the + * chain bit is set), then set the chain bit in all the following link TRBs. + * If we've enqueued the last TRB in a TD, make sure the following link TRBs + * have their chain bit cleared (so that each Link TRB is a separate TD). + * + * Section 6.4.4.1 of the 0.95 spec says link TRBs cannot have the chain bit + * set, but other sections talk about dealing with the chain bit set. + * Assume section 6.4.4.1 is wrong, and the chain bit can be set in a Link TRB. + */ +static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer) +{ + u32 chain; + union xhci_trb *next; + + chain = ring->enqueue->generic.field[3] & TRB_CHAIN; + next = ++(ring->enqueue); + + ring->enq_updates++; + /* Update the dequeue pointer further if that was a link TRB or we're at + * the end of an event ring segment (which doesn't have link TRBS) + */ + while (last_trb(xhci, ring, ring->enq_seg, next)) { + if (!consumer) { + if (ring != xhci->event_ring) { + next->link.control &= ~TRB_CHAIN; + next->link.control |= chain; + /* Give this link TRB to the hardware */ + wmb(); + if (next->link.control & TRB_CYCLE) + next->link.control &= (u32) ~TRB_CYCLE; + else + next->link.control |= (u32) TRB_CYCLE; + } + /* Toggle the cycle bit after the last ring segment. */ + if (last_trb_on_last_seg(xhci, ring, ring->enq_seg, next)) { + ring->cycle_state = (ring->cycle_state ? 0 : 1); + if (!in_interrupt()) + xhci_dbg(xhci, "Toggle cycle state for ring %p = %i\n", + ring, + (unsigned int) ring->cycle_state); + } + } + ring->enq_seg = ring->enq_seg->next; + ring->enqueue = ring->enq_seg->trbs; + next = ring->enqueue; + } +} + +/* + * Check to see if there's room to enqueue num_trbs on the ring. See rules + * above. + * FIXME: this would be simpler and faster if we just kept track of the number + * of free TRBs in a ring. + */ +static int room_on_ring(struct xhci_hcd *xhci, struct xhci_ring *ring, + unsigned int num_trbs) +{ + int i; + union xhci_trb *enq = ring->enqueue; + struct xhci_segment *enq_seg = ring->enq_seg; + + /* Check if ring is empty */ + if (enq == ring->dequeue) + return 1; + /* Make sure there's an extra empty TRB available */ + for (i = 0; i <= num_trbs; ++i) { + if (enq == ring->dequeue) + return 0; + enq++; + while (last_trb(xhci, ring, enq_seg, enq)) { + enq_seg = enq_seg->next; + enq = enq_seg->trbs; + } + } + return 1; +} + +void xhci_set_hc_event_deq(struct xhci_hcd *xhci) +{ + u32 temp; + dma_addr_t deq; + + deq = xhci_trb_virt_to_dma(xhci->event_ring->deq_seg, + xhci->event_ring->dequeue); + if (deq == 0 && !in_interrupt()) + xhci_warn(xhci, "WARN something wrong with SW event ring " + "dequeue ptr.\n"); + /* Update HC event ring dequeue pointer */ + temp = xhci_readl(xhci, &xhci->ir_set->erst_dequeue[0]); + temp &= ERST_PTR_MASK; + if (!in_interrupt()) + xhci_dbg(xhci, "// Write event ring dequeue pointer\n"); + xhci_writel(xhci, 0, &xhci->ir_set->erst_dequeue[1]); + xhci_writel(xhci, (deq & ~ERST_PTR_MASK) | temp, + &xhci->ir_set->erst_dequeue[0]); +} + +/* Ring the host controller doorbell after placing a command on the ring */ +void xhci_ring_cmd_db(struct xhci_hcd *xhci) +{ + u32 temp; + + xhci_dbg(xhci, "// Ding dong!\n"); + temp = xhci_readl(xhci, &xhci->dba->doorbell[0]) & DB_MASK; + xhci_writel(xhci, temp | DB_TARGET_HOST, &xhci->dba->doorbell[0]); + /* Flush PCI posted writes */ + xhci_readl(xhci, &xhci->dba->doorbell[0]); +} + +static void ring_ep_doorbell(struct xhci_hcd *xhci, + unsigned int slot_id, + unsigned int ep_index) +{ + struct xhci_ring *ep_ring; + u32 field; + __u32 __iomem *db_addr = &xhci->dba->doorbell[slot_id]; + + ep_ring = xhci->devs[slot_id]->ep_rings[ep_index]; + /* Don't ring the doorbell for this endpoint if there are pending + * cancellations because the we don't want to interrupt processing. + */ + if (!ep_ring->cancels_pending && !(ep_ring->state & SET_DEQ_PENDING)) { + field = xhci_readl(xhci, db_addr) & DB_MASK; + xhci_writel(xhci, field | EPI_TO_DB(ep_index), db_addr); + /* Flush PCI posted writes - FIXME Matthew Wilcox says this + * isn't time-critical and we shouldn't make the CPU wait for + * the flush. + */ + xhci_readl(xhci, db_addr); + } +} + +/* + * Find the segment that trb is in. Start searching in start_seg. + * If we must move past a segment that has a link TRB with a toggle cycle state + * bit set, then we will toggle the value pointed at by cycle_state. + */ +static struct xhci_segment *find_trb_seg( + struct xhci_segment *start_seg, + union xhci_trb *trb, int *cycle_state) +{ + struct xhci_segment *cur_seg = start_seg; + struct xhci_generic_trb *generic_trb; + + while (cur_seg->trbs > trb || + &cur_seg->trbs[TRBS_PER_SEGMENT - 1] < trb) { + generic_trb = &cur_seg->trbs[TRBS_PER_SEGMENT - 1].generic; + if (TRB_TYPE(generic_trb->field[3]) == TRB_LINK && + (generic_trb->field[3] & LINK_TOGGLE)) + *cycle_state = ~(*cycle_state) & 0x1; + cur_seg = cur_seg->next; + if (cur_seg == start_seg) + /* Looped over the entire list. Oops! */ + return 0; + } + return cur_seg; +} + +struct dequeue_state { + struct xhci_segment *new_deq_seg; + union xhci_trb *new_deq_ptr; + int new_cycle_state; +}; + +/* + * Move the xHC's endpoint ring dequeue pointer past cur_td. + * Record the new state of the xHC's endpoint ring dequeue segment, + * dequeue pointer, and new consumer cycle state in state. + * Update our internal representation of the ring's dequeue pointer. + * + * We do this in three jumps: + * - First we update our new ring state to be the same as when the xHC stopped. + * - Then we traverse the ring to find the segment that contains + * the last TRB in the TD. We toggle the xHC's new cycle state when we pass + * any link TRBs with the toggle cycle bit set. + * - Finally we move the dequeue state one TRB further, toggling the cycle bit + * if we've moved it past a link TRB with the toggle cycle bit set. + */ +static void find_new_dequeue_state(struct xhci_hcd *xhci, + unsigned int slot_id, unsigned int ep_index, + struct xhci_td *cur_td, struct dequeue_state *state) +{ + struct xhci_virt_device *dev = xhci->devs[slot_id]; + struct xhci_ring *ep_ring = dev->ep_rings[ep_index]; + struct xhci_generic_trb *trb; + + state->new_cycle_state = 0; + state->new_deq_seg = find_trb_seg(cur_td->start_seg, + ep_ring->stopped_trb, + &state->new_cycle_state); + if (!state->new_deq_seg) + BUG(); + /* Dig out the cycle state saved by the xHC during the stop ep cmd */ + state->new_cycle_state = 0x1 & dev->out_ctx->ep[ep_index].deq[0]; + + state->new_deq_ptr = cur_td->last_trb; + state->new_deq_seg = find_trb_seg(state->new_deq_seg, + state->new_deq_ptr, + &state->new_cycle_state); + if (!state->new_deq_seg) + BUG(); + + trb = &state->new_deq_ptr->generic; + if (TRB_TYPE(trb->field[3]) == TRB_LINK && + (trb->field[3] & LINK_TOGGLE)) + state->new_cycle_state = ~(state->new_cycle_state) & 0x1; + next_trb(xhci, ep_ring, &state->new_deq_seg, &state->new_deq_ptr); + + /* Don't update the ring cycle state for the producer (us). */ + ep_ring->dequeue = state->new_deq_ptr; + ep_ring->deq_seg = state->new_deq_seg; +} + +static void td_to_noop(struct xhci_hcd *xhci, struct xhci_ring *ep_ring, + struct xhci_td *cur_td) +{ + struct xhci_segment *cur_seg; + union xhci_trb *cur_trb; + + for (cur_seg = cur_td->start_seg, cur_trb = cur_td->first_trb; + true; + next_trb(xhci, ep_ring, &cur_seg, &cur_trb)) { + if ((cur_trb->generic.field[3] & TRB_TYPE_BITMASK) == + TRB_TYPE(TRB_LINK)) { + /* Unchain any chained Link TRBs, but + * leave the pointers intact. + */ + cur_trb->generic.field[3] &= ~TRB_CHAIN; + xhci_dbg(xhci, "Cancel (unchain) link TRB\n"); + xhci_dbg(xhci, "Address = %p (0x%llx dma); " + "in seg %p (0x%llx dma)\n", + cur_trb, + (unsigned long long)xhci_trb_virt_to_dma(cur_seg, cur_trb), + cur_seg, + (unsigned long long)cur_seg->dma); + } else { + cur_trb->generic.field[0] = 0; + cur_trb->generic.field[1] = 0; + cur_trb->generic.field[2] = 0; + /* Preserve only the cycle bit of this TRB */ + cur_trb->generic.field[3] &= TRB_CYCLE; + cur_trb->generic.field[3] |= TRB_TYPE(TRB_TR_NOOP); + xhci_dbg(xhci, "Cancel TRB %p (0x%llx dma) " + "in seg %p (0x%llx dma)\n", + cur_trb, + (unsigned long long)xhci_trb_virt_to_dma(cur_seg, cur_trb), + cur_seg, + (unsigned long long)cur_seg->dma); + } + if (cur_trb == cur_td->last_trb) + break; + } +} + +static int queue_set_tr_deq(struct xhci_hcd *xhci, int slot_id, + unsigned int ep_index, struct xhci_segment *deq_seg, + union xhci_trb *deq_ptr, u32 cycle_state); + +/* + * When we get a command completion for a Stop Endpoint Command, we need to + * unlink any cancelled TDs from the ring. There are two ways to do that: + * + * 1. If the HW was in the middle of processing the TD that needs to be + * cancelled, then we must move the ring's dequeue pointer past the last TRB + * in the TD with a Set Dequeue Pointer Command. + * 2. Otherwise, we turn all the TRBs in the TD into No-op TRBs (with the chain + * bit cleared) so that the HW will skip over them. + */ +static void handle_stopped_endpoint(struct xhci_hcd *xhci, + union xhci_trb *trb) +{ + unsigned int slot_id; + unsigned int ep_index; + struct xhci_ring *ep_ring; + struct list_head *entry; + struct xhci_td *cur_td = 0; + struct xhci_td *last_unlinked_td; + + struct dequeue_state deq_state; +#ifdef CONFIG_USB_HCD_STAT + ktime_t stop_time = ktime_get(); +#endif + + memset(&deq_state, 0, sizeof(deq_state)); + slot_id = TRB_TO_SLOT_ID(trb->generic.field[3]); + ep_index = TRB_TO_EP_INDEX(trb->generic.field[3]); + ep_ring = xhci->devs[slot_id]->ep_rings[ep_index]; + + if (list_empty(&ep_ring->cancelled_td_list)) + return; + + /* Fix up the ep ring first, so HW stops executing cancelled TDs. + * We have the xHCI lock, so nothing can modify this list until we drop + * it. We're also in the event handler, so we can't get re-interrupted + * if another Stop Endpoint command completes + */ + list_for_each(entry, &ep_ring->cancelled_td_list) { + cur_td = list_entry(entry, struct xhci_td, cancelled_td_list); + xhci_dbg(xhci, "Cancelling TD starting at %p, 0x%llx (dma).\n", + cur_td->first_trb, + (unsigned long long)xhci_trb_virt_to_dma(cur_td->start_seg, cur_td->first_trb)); + /* + * If we stopped on the TD we need to cancel, then we have to + * move the xHC endpoint ring dequeue pointer past this TD. + */ + if (cur_td == ep_ring->stopped_td) + find_new_dequeue_state(xhci, slot_id, ep_index, cur_td, + &deq_state); + else + td_to_noop(xhci, ep_ring, cur_td); + /* + * The event handler won't see a completion for this TD anymore, + * so remove it from the endpoint ring's TD list. Keep it in + * the cancelled TD list for URB completion later. + */ + list_del(&cur_td->td_list); + ep_ring->cancels_pending--; + } + last_unlinked_td = cur_td; + + /* If necessary, queue a Set Transfer Ring Dequeue Pointer command */ + if (deq_state.new_deq_ptr && deq_state.new_deq_seg) { + xhci_dbg(xhci, "Set TR Deq Ptr cmd, new deq seg = %p (0x%llx dma), " + "new deq ptr = %p (0x%llx dma), new cycle = %u\n", + deq_state.new_deq_seg, + (unsigned long long)deq_state.new_deq_seg->dma, + deq_state.new_deq_ptr, + (unsigned long long)xhci_trb_virt_to_dma(deq_state.new_deq_seg, deq_state.new_deq_ptr), + deq_state.new_cycle_state); + queue_set_tr_deq(xhci, slot_id, ep_index, + deq_state.new_deq_seg, + deq_state.new_deq_ptr, + (u32) deq_state.new_cycle_state); + /* Stop the TD queueing code from ringing the doorbell until + * this command completes. The HC won't set the dequeue pointer + * if the ring is running, and ringing the doorbell starts the + * ring running. + */ + ep_ring->state |= SET_DEQ_PENDING; + xhci_ring_cmd_db(xhci); + } else { + /* Otherwise just ring the doorbell to restart the ring */ + ring_ep_doorbell(xhci, slot_id, ep_index); + } + + /* + * Drop the lock and complete the URBs in the cancelled TD list. + * New TDs to be cancelled might be added to the end of the list before + * we can complete all the URBs for the TDs we already unlinked. + * So stop when we've completed the URB for the last TD we unlinked. + */ + do { + cur_td = list_entry(ep_ring->cancelled_td_list.next, + struct xhci_td, cancelled_td_list); + list_del(&cur_td->cancelled_td_list); + + /* Clean up the cancelled URB */ +#ifdef CONFIG_USB_HCD_STAT + hcd_stat_update(xhci->tp_stat, cur_td->urb->actual_length, + ktime_sub(stop_time, cur_td->start_time)); +#endif + cur_td->urb->hcpriv = NULL; + usb_hcd_unlink_urb_from_ep(xhci_to_hcd(xhci), cur_td->urb); + + xhci_dbg(xhci, "Giveback cancelled URB %p\n", cur_td->urb); + spin_unlock(&xhci->lock); + /* Doesn't matter what we pass for status, since the core will + * just overwrite it (because the URB has been unlinked). + */ + usb_hcd_giveback_urb(xhci_to_hcd(xhci), cur_td->urb, 0); + kfree(cur_td); + + spin_lock(&xhci->lock); + } while (cur_td != last_unlinked_td); + + /* Return to the event handler with xhci->lock re-acquired */ +} + +/* + * When we get a completion for a Set Transfer Ring Dequeue Pointer command, + * we need to clear the set deq pending flag in the endpoint ring state, so that + * the TD queueing code can ring the doorbell again. We also need to ring the + * endpoint doorbell to restart the ring, but only if there aren't more + * cancellations pending. + */ +static void handle_set_deq_completion(struct xhci_hcd *xhci, + struct xhci_event_cmd *event, + union xhci_trb *trb) +{ + unsigned int slot_id; + unsigned int ep_index; + struct xhci_ring *ep_ring; + struct xhci_virt_device *dev; + + slot_id = TRB_TO_SLOT_ID(trb->generic.field[3]); + ep_index = TRB_TO_EP_INDEX(trb->generic.field[3]); + dev = xhci->devs[slot_id]; + ep_ring = dev->ep_rings[ep_index]; + + if (GET_COMP_CODE(event->status) != COMP_SUCCESS) { + unsigned int ep_state; + unsigned int slot_state; + + switch (GET_COMP_CODE(event->status)) { + case COMP_TRB_ERR: + xhci_warn(xhci, "WARN Set TR Deq Ptr cmd invalid because " + "of stream ID configuration\n"); + break; + case COMP_CTX_STATE: + xhci_warn(xhci, "WARN Set TR Deq Ptr cmd failed due " + "to incorrect slot or ep state.\n"); + ep_state = dev->out_ctx->ep[ep_index].ep_info; + ep_state &= EP_STATE_MASK; + slot_state = dev->out_ctx->slot.dev_state; + slot_state = GET_SLOT_STATE(slot_state); + xhci_dbg(xhci, "Slot state = %u, EP state = %u\n", + slot_state, ep_state); + break; + case COMP_EBADSLT: + xhci_warn(xhci, "WARN Set TR Deq Ptr cmd failed because " + "slot %u was not enabled.\n", slot_id); + break; + default: + xhci_warn(xhci, "WARN Set TR Deq Ptr cmd with unknown " + "completion code of %u.\n", + GET_COMP_CODE(event->status)); + break; + } + /* OK what do we do now? The endpoint state is hosed, and we + * should never get to this point if the synchronization between + * queueing, and endpoint state are correct. This might happen + * if the device gets disconnected after we've finished + * cancelling URBs, which might not be an error... + */ + } else { + xhci_dbg(xhci, "Successful Set TR Deq Ptr cmd, deq[0] = 0x%x, " + "deq[1] = 0x%x.\n", + dev->out_ctx->ep[ep_index].deq[0], + dev->out_ctx->ep[ep_index].deq[1]); + } + + ep_ring->state &= ~SET_DEQ_PENDING; + ring_ep_doorbell(xhci, slot_id, ep_index); +} + + +static void handle_cmd_completion(struct xhci_hcd *xhci, + struct xhci_event_cmd *event) +{ + int slot_id = TRB_TO_SLOT_ID(event->flags); + u64 cmd_dma; + dma_addr_t cmd_dequeue_dma; + + cmd_dma = (((u64) event->cmd_trb[1]) << 32) + event->cmd_trb[0]; + cmd_dequeue_dma = xhci_trb_virt_to_dma(xhci->cmd_ring->deq_seg, + xhci->cmd_ring->dequeue); + /* Is the command ring deq ptr out of sync with the deq seg ptr? */ + if (cmd_dequeue_dma == 0) { + xhci->error_bitmask |= 1 << 4; + return; + } + /* Does the DMA address match our internal dequeue pointer address? */ + if (cmd_dma != (u64) cmd_dequeue_dma) { + xhci->error_bitmask |= 1 << 5; + return; + } + switch (xhci->cmd_ring->dequeue->generic.field[3] & TRB_TYPE_BITMASK) { + case TRB_TYPE(TRB_ENABLE_SLOT): + if (GET_COMP_CODE(event->status) == COMP_SUCCESS) + xhci->slot_id = slot_id; + else + xhci->slot_id = 0; + complete(&xhci->addr_dev); + break; + case TRB_TYPE(TRB_DISABLE_SLOT): + if (xhci->devs[slot_id]) + xhci_free_virt_device(xhci, slot_id); + break; + case TRB_TYPE(TRB_CONFIG_EP): + xhci->devs[slot_id]->cmd_status = GET_COMP_CODE(event->status); + complete(&xhci->devs[slot_id]->cmd_completion); + break; + case TRB_TYPE(TRB_ADDR_DEV): + xhci->devs[slot_id]->cmd_status = GET_COMP_CODE(event->status); + complete(&xhci->addr_dev); + break; + case TRB_TYPE(TRB_STOP_RING): + handle_stopped_endpoint(xhci, xhci->cmd_ring->dequeue); + break; + case TRB_TYPE(TRB_SET_DEQ): + handle_set_deq_completion(xhci, event, xhci->cmd_ring->dequeue); + break; + case TRB_TYPE(TRB_CMD_NOOP): + ++xhci->noops_handled; + break; + default: + /* Skip over unknown commands on the event ring */ + xhci->error_bitmask |= 1 << 6; + break; + } + inc_deq(xhci, xhci->cmd_ring, false); +} + +static void handle_port_status(struct xhci_hcd *xhci, + union xhci_trb *event) +{ + u32 port_id; + + /* Port status change events always have a successful completion code */ + if (GET_COMP_CODE(event->generic.field[2]) != COMP_SUCCESS) { + xhci_warn(xhci, "WARN: xHC returned failed port status event\n"); + xhci->error_bitmask |= 1 << 8; + } + /* FIXME: core doesn't care about all port link state changes yet */ + port_id = GET_PORT_ID(event->generic.field[0]); + xhci_dbg(xhci, "Port Status Change Event for port %d\n", port_id); + + /* Update event ring dequeue pointer before dropping the lock */ + inc_deq(xhci, xhci->event_ring, true); + xhci_set_hc_event_deq(xhci); + + spin_unlock(&xhci->lock); + /* Pass this up to the core */ + usb_hcd_poll_rh_status(xhci_to_hcd(xhci)); + spin_lock(&xhci->lock); +} + +/* + * This TD is defined by the TRBs starting at start_trb in start_seg and ending + * at end_trb, which may be in another segment. If the suspect DMA address is a + * TRB in this TD, this function returns that TRB's segment. Otherwise it + * returns 0. + */ +static struct xhci_segment *trb_in_td( + struct xhci_segment *start_seg, + union xhci_trb *start_trb, + union xhci_trb *end_trb, + dma_addr_t suspect_dma) +{ + dma_addr_t start_dma; + dma_addr_t end_seg_dma; + dma_addr_t end_trb_dma; + struct xhci_segment *cur_seg; + + start_dma = xhci_trb_virt_to_dma(start_seg, start_trb); + cur_seg = start_seg; + + do { + /* We may get an event for a Link TRB in the middle of a TD */ + end_seg_dma = xhci_trb_virt_to_dma(cur_seg, + &start_seg->trbs[TRBS_PER_SEGMENT - 1]); + /* If the end TRB isn't in this segment, this is set to 0 */ + end_trb_dma = xhci_trb_virt_to_dma(cur_seg, end_trb); + + if (end_trb_dma > 0) { + /* The end TRB is in this segment, so suspect should be here */ + if (start_dma <= end_trb_dma) { + if (suspect_dma >= start_dma && suspect_dma <= end_trb_dma) + return cur_seg; + } else { + /* Case for one segment with + * a TD wrapped around to the top + */ + if ((suspect_dma >= start_dma && + suspect_dma <= end_seg_dma) || + (suspect_dma >= cur_seg->dma && + suspect_dma <= end_trb_dma)) + return cur_seg; + } + return 0; + } else { + /* Might still be somewhere in this segment */ + if (suspect_dma >= start_dma && suspect_dma <= end_seg_dma) + return cur_seg; + } + cur_seg = cur_seg->next; + start_dma = xhci_trb_virt_to_dma(cur_seg, &cur_seg->trbs[0]); + } while (1); + +} + +/* + * If this function returns an error condition, it means it got a Transfer + * event with a corrupted Slot ID, Endpoint ID, or TRB DMA address. + * At this point, the host controller is probably hosed and should be reset. + */ +static int handle_tx_event(struct xhci_hcd *xhci, + struct xhci_transfer_event *event) +{ + struct xhci_virt_device *xdev; + struct xhci_ring *ep_ring; + int ep_index; + struct xhci_td *td = 0; + dma_addr_t event_dma; + struct xhci_segment *event_seg; + union xhci_trb *event_trb; + struct urb *urb = 0; + int status = -EINPROGRESS; + + xdev = xhci->devs[TRB_TO_SLOT_ID(event->flags)]; + if (!xdev) { + xhci_err(xhci, "ERROR Transfer event pointed to bad slot\n"); + return -ENODEV; + } + + /* Endpoint ID is 1 based, our index is zero based */ + ep_index = TRB_TO_EP_ID(event->flags) - 1; + ep_ring = xdev->ep_rings[ep_index]; + if (!ep_ring || (xdev->out_ctx->ep[ep_index].ep_info & EP_STATE_MASK) == EP_STATE_DISABLED) { + xhci_err(xhci, "ERROR Transfer event pointed to disabled endpoint\n"); + return -ENODEV; + } + + event_dma = event->buffer[0]; + if (event->buffer[1] != 0) + xhci_warn(xhci, "WARN ignoring upper 32-bits of 64-bit TRB dma address\n"); + + /* This TRB should be in the TD at the head of this ring's TD list */ + if (list_empty(&ep_ring->td_list)) { + xhci_warn(xhci, "WARN Event TRB for slot %d ep %d with no TDs queued?\n", + TRB_TO_SLOT_ID(event->flags), ep_index); + xhci_dbg(xhci, "Event TRB with TRB type ID %u\n", + (unsigned int) (event->flags & TRB_TYPE_BITMASK)>>10); + xhci_print_trb_offsets(xhci, (union xhci_trb *) event); + urb = NULL; + goto cleanup; + } + td = list_entry(ep_ring->td_list.next, struct xhci_td, td_list); + + /* Is this a TRB in the currently executing TD? */ + event_seg = trb_in_td(ep_ring->deq_seg, ep_ring->dequeue, + td->last_trb, event_dma); + if (!event_seg) { + /* HC is busted, give up! */ + xhci_err(xhci, "ERROR Transfer event TRB DMA ptr not part of current TD\n"); + return -ESHUTDOWN; + } + event_trb = &event_seg->trbs[(event_dma - event_seg->dma) / sizeof(*event_trb)]; + xhci_dbg(xhci, "Event TRB with TRB type ID %u\n", + (unsigned int) (event->flags & TRB_TYPE_BITMASK)>>10); + xhci_dbg(xhci, "Offset 0x00 (buffer[0]) = 0x%x\n", + (unsigned int) event->buffer[0]); + xhci_dbg(xhci, "Offset 0x04 (buffer[0]) = 0x%x\n", + (unsigned int) event->buffer[1]); + xhci_dbg(xhci, "Offset 0x08 (transfer length) = 0x%x\n", + (unsigned int) event->transfer_len); + xhci_dbg(xhci, "Offset 0x0C (flags) = 0x%x\n", + (unsigned int) event->flags); + + /* Look for common error cases */ + switch (GET_COMP_CODE(event->transfer_len)) { + /* Skip codes that require special handling depending on + * transfer type + */ + case COMP_SUCCESS: + case COMP_SHORT_TX: + break; + case COMP_STOP: + xhci_dbg(xhci, "Stopped on Transfer TRB\n"); + break; + case COMP_STOP_INVAL: + xhci_dbg(xhci, "Stopped on No-op or Link TRB\n"); + break; + case COMP_STALL: + xhci_warn(xhci, "WARN: Stalled endpoint\n"); + status = -EPIPE; + break; + case COMP_TRB_ERR: + xhci_warn(xhci, "WARN: TRB error on endpoint\n"); + status = -EILSEQ; + break; + case COMP_TX_ERR: + xhci_warn(xhci, "WARN: transfer error on endpoint\n"); + status = -EPROTO; + break; + case COMP_DB_ERR: + xhci_warn(xhci, "WARN: HC couldn't access mem fast enough\n"); + status = -ENOSR; + break; + default: + xhci_warn(xhci, "ERROR Unknown event condition, HC probably busted\n"); + urb = NULL; + goto cleanup; + } + /* Now update the urb's actual_length and give back to the core */ + /* Was this a control transfer? */ + if (usb_endpoint_xfer_control(&td->urb->ep->desc)) { + xhci_debug_trb(xhci, xhci->event_ring->dequeue); + switch (GET_COMP_CODE(event->transfer_len)) { + case COMP_SUCCESS: + if (event_trb == ep_ring->dequeue) { + xhci_warn(xhci, "WARN: Success on ctrl setup TRB without IOC set??\n"); + status = -ESHUTDOWN; + } else if (event_trb != td->last_trb) { + xhci_warn(xhci, "WARN: Success on ctrl data TRB without IOC set??\n"); + status = -ESHUTDOWN; + } else { + xhci_dbg(xhci, "Successful control transfer!\n"); + status = 0; + } + break; + case COMP_SHORT_TX: + xhci_warn(xhci, "WARN: short transfer on control ep\n"); + status = -EREMOTEIO; + break; + default: + /* Others already handled above */ + break; + } + /* + * Did we transfer any data, despite the errors that might have + * happened? I.e. did we get past the setup stage? + */ + if (event_trb != ep_ring->dequeue) { + /* The event was for the status stage */ + if (event_trb == td->last_trb) { + td->urb->actual_length = + td->urb->transfer_buffer_length; + } else { + /* Maybe the event was for the data stage? */ + if (GET_COMP_CODE(event->transfer_len) != COMP_STOP_INVAL) + /* We didn't stop on a link TRB in the middle */ + td->urb->actual_length = + td->urb->transfer_buffer_length - + TRB_LEN(event->transfer_len); + } + } + } else { + switch (GET_COMP_CODE(event->transfer_len)) { + case COMP_SUCCESS: + /* Double check that the HW transferred everything. */ + if (event_trb != td->last_trb) { + xhci_warn(xhci, "WARN Successful completion " + "on short TX\n"); + if (td->urb->transfer_flags & URB_SHORT_NOT_OK) + status = -EREMOTEIO; + else + status = 0; + } else { + xhci_dbg(xhci, "Successful bulk transfer!\n"); + status = 0; + } + break; + case COMP_SHORT_TX: + if (td->urb->transfer_flags & URB_SHORT_NOT_OK) + status = -EREMOTEIO; + else + status = 0; + break; + default: + /* Others already handled above */ + break; + } + dev_dbg(&td->urb->dev->dev, + "ep %#x - asked for %d bytes, " + "%d bytes untransferred\n", + td->urb->ep->desc.bEndpointAddress, + td->urb->transfer_buffer_length, + TRB_LEN(event->transfer_len)); + /* Fast path - was this the last TRB in the TD for this URB? */ + if (event_trb == td->last_trb) { + if (TRB_LEN(event->transfer_len) != 0) { + td->urb->actual_length = + td->urb->transfer_buffer_length - + TRB_LEN(event->transfer_len); + if (td->urb->actual_length < 0) { + xhci_warn(xhci, "HC gave bad length " + "of %d bytes left\n", + TRB_LEN(event->transfer_len)); + td->urb->actual_length = 0; + } + if (td->urb->transfer_flags & URB_SHORT_NOT_OK) + status = -EREMOTEIO; + else + status = 0; + } else { + td->urb->actual_length = td->urb->transfer_buffer_length; + /* Ignore a short packet completion if the + * untransferred length was zero. + */ + status = 0; + } + } else { + /* Slow path - walk the list, starting from the dequeue + * pointer, to get the actual length transferred. + */ + union xhci_trb *cur_trb; + struct xhci_segment *cur_seg; + + td->urb->actual_length = 0; + for (cur_trb = ep_ring->dequeue, cur_seg = ep_ring->deq_seg; + cur_trb != event_trb; + next_trb(xhci, ep_ring, &cur_seg, &cur_trb)) { + if (TRB_TYPE(cur_trb->generic.field[3]) != TRB_TR_NOOP && + TRB_TYPE(cur_trb->generic.field[3]) != TRB_LINK) + td->urb->actual_length += + TRB_LEN(cur_trb->generic.field[2]); + } + /* If the ring didn't stop on a Link or No-op TRB, add + * in the actual bytes transferred from the Normal TRB + */ + if (GET_COMP_CODE(event->transfer_len) != COMP_STOP_INVAL) + td->urb->actual_length += + TRB_LEN(cur_trb->generic.field[2]) - + TRB_LEN(event->transfer_len); + } + } + /* The Endpoint Stop Command completion will take care of + * any stopped TDs. A stopped TD may be restarted, so don't update the + * ring dequeue pointer or take this TD off any lists yet. + */ + if (GET_COMP_CODE(event->transfer_len) == COMP_STOP_INVAL || + GET_COMP_CODE(event->transfer_len) == COMP_STOP) { + ep_ring->stopped_td = td; + ep_ring->stopped_trb = event_trb; + } else { + /* Update ring dequeue pointer */ + while (ep_ring->dequeue != td->last_trb) + inc_deq(xhci, ep_ring, false); + inc_deq(xhci, ep_ring, false); + + /* Clean up the endpoint's TD list */ + urb = td->urb; + list_del(&td->td_list); + /* Was this TD slated to be cancelled but completed anyway? */ + if (!list_empty(&td->cancelled_td_list)) { + list_del(&td->cancelled_td_list); + ep_ring->cancels_pending--; + } + kfree(td); + urb->hcpriv = NULL; + } +cleanup: + inc_deq(xhci, xhci->event_ring, true); + xhci_set_hc_event_deq(xhci); + + /* FIXME for multi-TD URBs (who have buffers bigger than 64MB) */ + if (urb) { + usb_hcd_unlink_urb_from_ep(xhci_to_hcd(xhci), urb); + spin_unlock(&xhci->lock); + usb_hcd_giveback_urb(xhci_to_hcd(xhci), urb, status); + spin_lock(&xhci->lock); + } + return 0; +} + +/* + * This function handles all OS-owned events on the event ring. It may drop + * xhci->lock between event processing (e.g. to pass up port status changes). + */ +void xhci_handle_event(struct xhci_hcd *xhci) +{ + union xhci_trb *event; + int update_ptrs = 1; + int ret; + + if (!xhci->event_ring || !xhci->event_ring->dequeue) { + xhci->error_bitmask |= 1 << 1; + return; + } + + event = xhci->event_ring->dequeue; + /* Does the HC or OS own the TRB? */ + if ((event->event_cmd.flags & TRB_CYCLE) != + xhci->event_ring->cycle_state) { + xhci->error_bitmask |= 1 << 2; + return; + } + + /* FIXME: Handle more event types. */ + switch ((event->event_cmd.flags & TRB_TYPE_BITMASK)) { + case TRB_TYPE(TRB_COMPLETION): + handle_cmd_completion(xhci, &event->event_cmd); + break; + case TRB_TYPE(TRB_PORT_STATUS): + handle_port_status(xhci, event); + update_ptrs = 0; + break; + case TRB_TYPE(TRB_TRANSFER): + ret = handle_tx_event(xhci, &event->trans_event); + if (ret < 0) + xhci->error_bitmask |= 1 << 9; + else + update_ptrs = 0; + break; + default: + xhci->error_bitmask |= 1 << 3; + } + + if (update_ptrs) { + /* Update SW and HC event ring dequeue pointer */ + inc_deq(xhci, xhci->event_ring, true); + xhci_set_hc_event_deq(xhci); + } + /* Are there more items on the event ring? */ + xhci_handle_event(xhci); +} + +/**** Endpoint Ring Operations ****/ + +/* + * Generic function for queueing a TRB on a ring. + * The caller must have checked to make sure there's room on the ring. + */ +static void queue_trb(struct xhci_hcd *xhci, struct xhci_ring *ring, + bool consumer, + u32 field1, u32 field2, u32 field3, u32 field4) +{ + struct xhci_generic_trb *trb; + + trb = &ring->enqueue->generic; + trb->field[0] = field1; + trb->field[1] = field2; + trb->field[2] = field3; + trb->field[3] = field4; + inc_enq(xhci, ring, consumer); +} + +/* + * Does various checks on the endpoint ring, and makes it ready to queue num_trbs. + * FIXME allocate segments if the ring is full. + */ +static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring, + u32 ep_state, unsigned int num_trbs, gfp_t mem_flags) +{ + /* Make sure the endpoint has been added to xHC schedule */ + xhci_dbg(xhci, "Endpoint state = 0x%x\n", ep_state); + switch (ep_state) { + case EP_STATE_DISABLED: + /* + * USB core changed config/interfaces without notifying us, + * or hardware is reporting the wrong state. + */ + xhci_warn(xhci, "WARN urb submitted to disabled ep\n"); + return -ENOENT; + case EP_STATE_HALTED: + case EP_STATE_ERROR: + xhci_warn(xhci, "WARN waiting for halt or error on ep " + "to be cleared\n"); + /* FIXME event handling code for error needs to clear it */ + /* XXX not sure if this should be -ENOENT or not */ + return -EINVAL; + case EP_STATE_STOPPED: + case EP_STATE_RUNNING: + break; + default: + xhci_err(xhci, "ERROR unknown endpoint state for ep\n"); + /* + * FIXME issue Configure Endpoint command to try to get the HC + * back into a known state. + */ + return -EINVAL; + } + if (!room_on_ring(xhci, ep_ring, num_trbs)) { + /* FIXME allocate more room */ + xhci_err(xhci, "ERROR no room on ep ring\n"); + return -ENOMEM; + } + return 0; +} + +static int prepare_transfer(struct xhci_hcd *xhci, + struct xhci_virt_device *xdev, + unsigned int ep_index, + unsigned int num_trbs, + struct urb *urb, + struct xhci_td **td, + gfp_t mem_flags) +{ + int ret; + + ret = prepare_ring(xhci, xdev->ep_rings[ep_index], + xdev->out_ctx->ep[ep_index].ep_info & EP_STATE_MASK, + num_trbs, mem_flags); + if (ret) + return ret; + *td = kzalloc(sizeof(struct xhci_td), mem_flags); + if (!*td) + return -ENOMEM; + INIT_LIST_HEAD(&(*td)->td_list); + INIT_LIST_HEAD(&(*td)->cancelled_td_list); + + ret = usb_hcd_link_urb_to_ep(xhci_to_hcd(xhci), urb); + if (unlikely(ret)) { + kfree(*td); + return ret; + } + + (*td)->urb = urb; + urb->hcpriv = (void *) (*td); + /* Add this TD to the tail of the endpoint ring's TD list */ + list_add_tail(&(*td)->td_list, &xdev->ep_rings[ep_index]->td_list); + (*td)->start_seg = xdev->ep_rings[ep_index]->enq_seg; + (*td)->first_trb = xdev->ep_rings[ep_index]->enqueue; + + return 0; +} + +static unsigned int count_sg_trbs_needed(struct xhci_hcd *xhci, struct urb *urb) +{ + int num_sgs, num_trbs, running_total, temp, i; + struct scatterlist *sg; + + sg = NULL; + num_sgs = urb->num_sgs; + temp = urb->transfer_buffer_length; + + xhci_dbg(xhci, "count sg list trbs: \n"); + num_trbs = 0; + for_each_sg(urb->sg->sg, sg, num_sgs, i) { + unsigned int previous_total_trbs = num_trbs; + unsigned int len = sg_dma_len(sg); + + /* Scatter gather list entries may cross 64KB boundaries */ + running_total = TRB_MAX_BUFF_SIZE - + (sg_dma_address(sg) & ((1 << TRB_MAX_BUFF_SHIFT) - 1)); + if (running_total != 0) + num_trbs++; + + /* How many more 64KB chunks to transfer, how many more TRBs? */ + while (running_total < sg_dma_len(sg)) { + num_trbs++; + running_total += TRB_MAX_BUFF_SIZE; + } + xhci_dbg(xhci, " sg #%d: dma = %#llx, len = %#x (%d), num_trbs = %d\n", + i, (unsigned long long)sg_dma_address(sg), + len, len, num_trbs - previous_total_trbs); + + len = min_t(int, len, temp); + temp -= len; + if (temp == 0) + break; + } + xhci_dbg(xhci, "\n"); + if (!in_interrupt()) + dev_dbg(&urb->dev->dev, "ep %#x - urb len = %d, sglist used, num_trbs = %d\n", + urb->ep->desc.bEndpointAddress, + urb->transfer_buffer_length, + num_trbs); + return num_trbs; +} + +static void check_trb_math(struct urb *urb, int num_trbs, int running_total) +{ + if (num_trbs != 0) + dev_dbg(&urb->dev->dev, "%s - ep %#x - Miscalculated number of " + "TRBs, %d left\n", __func__, + urb->ep->desc.bEndpointAddress, num_trbs); + if (running_total != urb->transfer_buffer_length) + dev_dbg(&urb->dev->dev, "%s - ep %#x - Miscalculated tx length, " + "queued %#x (%d), asked for %#x (%d)\n", + __func__, + urb->ep->desc.bEndpointAddress, + running_total, running_total, + urb->transfer_buffer_length, + urb->transfer_buffer_length); +} + +static void giveback_first_trb(struct xhci_hcd *xhci, int slot_id, + unsigned int ep_index, int start_cycle, + struct xhci_generic_trb *start_trb, struct xhci_td *td) +{ + /* + * Pass all the TRBs to the hardware at once and make sure this write + * isn't reordered. + */ + wmb(); + start_trb->field[3] |= start_cycle; + ring_ep_doorbell(xhci, slot_id, ep_index); +} + +static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, + struct urb *urb, int slot_id, unsigned int ep_index) +{ + struct xhci_ring *ep_ring; + unsigned int num_trbs; + struct xhci_td *td; + struct scatterlist *sg; + int num_sgs; + int trb_buff_len, this_sg_len, running_total; + bool first_trb; + u64 addr; + + struct xhci_generic_trb *start_trb; + int start_cycle; + + ep_ring = xhci->devs[slot_id]->ep_rings[ep_index]; + num_trbs = count_sg_trbs_needed(xhci, urb); + num_sgs = urb->num_sgs; + + trb_buff_len = prepare_transfer(xhci, xhci->devs[slot_id], + ep_index, num_trbs, urb, &td, mem_flags); + if (trb_buff_len < 0) + return trb_buff_len; + /* + * Don't give the first TRB to the hardware (by toggling the cycle bit) + * until we've finished creating all the other TRBs. The ring's cycle + * state may change as we enqueue the other TRBs, so save it too. + */ + start_trb = &ep_ring->enqueue->generic; + start_cycle = ep_ring->cycle_state; + + running_total = 0; + /* + * How much data is in the first TRB? + * + * There are three forces at work for TRB buffer pointers and lengths: + * 1. We don't want to walk off the end of this sg-list entry buffer. + * 2. The transfer length that the driver requested may be smaller than + * the amount of memory allocated for this scatter-gather list. + * 3. TRBs buffers can't cross 64KB boundaries. + */ + sg = urb->sg->sg; + addr = (u64) sg_dma_address(sg); + this_sg_len = sg_dma_len(sg); + trb_buff_len = TRB_MAX_BUFF_SIZE - + (addr & ((1 << TRB_MAX_BUFF_SHIFT) - 1)); + trb_buff_len = min_t(int, trb_buff_len, this_sg_len); + if (trb_buff_len > urb->transfer_buffer_length) + trb_buff_len = urb->transfer_buffer_length; + xhci_dbg(xhci, "First length to xfer from 1st sglist entry = %u\n", + trb_buff_len); + + first_trb = true; + /* Queue the first TRB, even if it's zero-length */ + do { + u32 field = 0; + + /* Don't change the cycle bit of the first TRB until later */ + if (first_trb) + first_trb = false; + else + field |= ep_ring->cycle_state; + + /* Chain all the TRBs together; clear the chain bit in the last + * TRB to indicate it's the last TRB in the chain. + */ + if (num_trbs > 1) { + field |= TRB_CHAIN; + } else { + /* FIXME - add check for ZERO_PACKET flag before this */ + td->last_trb = ep_ring->enqueue; + field |= TRB_IOC; + } + xhci_dbg(xhci, " sg entry: dma = %#x, len = %#x (%d), " + "64KB boundary at %#x, end dma = %#x\n", + (unsigned int) addr, trb_buff_len, trb_buff_len, + (unsigned int) (addr + TRB_MAX_BUFF_SIZE) & ~(TRB_MAX_BUFF_SIZE - 1), + (unsigned int) addr + trb_buff_len); + if (TRB_MAX_BUFF_SIZE - + (addr & ((1 << TRB_MAX_BUFF_SHIFT) - 1)) < trb_buff_len) { + xhci_warn(xhci, "WARN: sg dma xfer crosses 64KB boundaries!\n"); + xhci_dbg(xhci, "Next boundary at %#x, end dma = %#x\n", + (unsigned int) (addr + TRB_MAX_BUFF_SIZE) & ~(TRB_MAX_BUFF_SIZE - 1), + (unsigned int) addr + trb_buff_len); + } + queue_trb(xhci, ep_ring, false, + (u32) addr, + (u32) ((u64) addr >> 32), + TRB_LEN(trb_buff_len) | TRB_INTR_TARGET(0), + /* We always want to know if the TRB was short, + * or we won't get an event when it completes. + * (Unless we use event data TRBs, which are a + * waste of space and HC resources.) + */ + field | TRB_ISP | TRB_TYPE(TRB_NORMAL)); + --num_trbs; + running_total += trb_buff_len; + + /* Calculate length for next transfer -- + * Are we done queueing all the TRBs for this sg entry? + */ + this_sg_len -= trb_buff_len; + if (this_sg_len == 0) { + --num_sgs; + if (num_sgs == 0) + break; + sg = sg_next(sg); + addr = (u64) sg_dma_address(sg); + this_sg_len = sg_dma_len(sg); + } else { + addr += trb_buff_len; + } + + trb_buff_len = TRB_MAX_BUFF_SIZE - + (addr & ((1 << TRB_MAX_BUFF_SHIFT) - 1)); + trb_buff_len = min_t(int, trb_buff_len, this_sg_len); + if (running_total + trb_buff_len > urb->transfer_buffer_length) + trb_buff_len = + urb->transfer_buffer_length - running_total; + } while (running_total < urb->transfer_buffer_length); + + check_trb_math(urb, num_trbs, running_total); + giveback_first_trb(xhci, slot_id, ep_index, start_cycle, start_trb, td); + return 0; +} + +/* This is very similar to what ehci-q.c qtd_fill() does */ +int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, + struct urb *urb, int slot_id, unsigned int ep_index) +{ + struct xhci_ring *ep_ring; + struct xhci_td *td; + int num_trbs; + struct xhci_generic_trb *start_trb; + bool first_trb; + int start_cycle; + u32 field; + + int running_total, trb_buff_len, ret; + u64 addr; + + if (urb->sg) + return queue_bulk_sg_tx(xhci, mem_flags, urb, slot_id, ep_index); + + ep_ring = xhci->devs[slot_id]->ep_rings[ep_index]; + + num_trbs = 0; + /* How much data is (potentially) left before the 64KB boundary? */ + running_total = TRB_MAX_BUFF_SIZE - + (urb->transfer_dma & ((1 << TRB_MAX_BUFF_SHIFT) - 1)); + + /* If there's some data on this 64KB chunk, or we have to send a + * zero-length transfer, we need at least one TRB + */ + if (running_total != 0 || urb->transfer_buffer_length == 0) + num_trbs++; + /* How many more 64KB chunks to transfer, how many more TRBs? */ + while (running_total < urb->transfer_buffer_length) { + num_trbs++; + running_total += TRB_MAX_BUFF_SIZE; + } + /* FIXME: this doesn't deal with URB_ZERO_PACKET - need one more */ + + if (!in_interrupt()) + dev_dbg(&urb->dev->dev, "ep %#x - urb len = %#x (%d), addr = %#llx, num_trbs = %d\n", + urb->ep->desc.bEndpointAddress, + urb->transfer_buffer_length, + urb->transfer_buffer_length, + (unsigned long long)urb->transfer_dma, + num_trbs); + + ret = prepare_transfer(xhci, xhci->devs[slot_id], ep_index, + num_trbs, urb, &td, mem_flags); + if (ret < 0) + return ret; + + /* + * Don't give the first TRB to the hardware (by toggling the cycle bit) + * until we've finished creating all the other TRBs. The ring's cycle + * state may change as we enqueue the other TRBs, so save it too. + */ + start_trb = &ep_ring->enqueue->generic; + start_cycle = ep_ring->cycle_state; + + running_total = 0; + /* How much data is in the first TRB? */ + addr = (u64) urb->transfer_dma; + trb_buff_len = TRB_MAX_BUFF_SIZE - + (urb->transfer_dma & ((1 << TRB_MAX_BUFF_SHIFT) - 1)); + if (urb->transfer_buffer_length < trb_buff_len) + trb_buff_len = urb->transfer_buffer_length; + + first_trb = true; + + /* Queue the first TRB, even if it's zero-length */ + do { + field = 0; + + /* Don't change the cycle bit of the first TRB until later */ + if (first_trb) + first_trb = false; + else + field |= ep_ring->cycle_state; + + /* Chain all the TRBs together; clear the chain bit in the last + * TRB to indicate it's the last TRB in the chain. + */ + if (num_trbs > 1) { + field |= TRB_CHAIN; + } else { + /* FIXME - add check for ZERO_PACKET flag before this */ + td->last_trb = ep_ring->enqueue; + field |= TRB_IOC; + } + queue_trb(xhci, ep_ring, false, + (u32) addr, + (u32) ((u64) addr >> 32), + TRB_LEN(trb_buff_len) | TRB_INTR_TARGET(0), + /* We always want to know if the TRB was short, + * or we won't get an event when it completes. + * (Unless we use event data TRBs, which are a + * waste of space and HC resources.) + */ + field | TRB_ISP | TRB_TYPE(TRB_NORMAL)); + --num_trbs; + running_total += trb_buff_len; + + /* Calculate length for next transfer */ + addr += trb_buff_len; + trb_buff_len = urb->transfer_buffer_length - running_total; + if (trb_buff_len > TRB_MAX_BUFF_SIZE) + trb_buff_len = TRB_MAX_BUFF_SIZE; + } while (running_total < urb->transfer_buffer_length); + + check_trb_math(urb, num_trbs, running_total); + giveback_first_trb(xhci, slot_id, ep_index, start_cycle, start_trb, td); + return 0; +} + +/* Caller must have locked xhci->lock */ +int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, + struct urb *urb, int slot_id, unsigned int ep_index) +{ + struct xhci_ring *ep_ring; + int num_trbs; + int ret; + struct usb_ctrlrequest *setup; + struct xhci_generic_trb *start_trb; + int start_cycle; + u32 field; + struct xhci_td *td; + + ep_ring = xhci->devs[slot_id]->ep_rings[ep_index]; + + /* + * Need to copy setup packet into setup TRB, so we can't use the setup + * DMA address. + */ + if (!urb->setup_packet) + return -EINVAL; + + if (!in_interrupt()) + xhci_dbg(xhci, "Queueing ctrl tx for slot id %d, ep %d\n", + slot_id, ep_index); + /* 1 TRB for setup, 1 for status */ + num_trbs = 2; + /* + * Don't need to check if we need additional event data and normal TRBs, + * since data in control transfers will never get bigger than 16MB + * XXX: can we get a buffer that crosses 64KB boundaries? + */ + if (urb->transfer_buffer_length > 0) + num_trbs++; + ret = prepare_transfer(xhci, xhci->devs[slot_id], ep_index, num_trbs, + urb, &td, mem_flags); + if (ret < 0) + return ret; + + /* + * Don't give the first TRB to the hardware (by toggling the cycle bit) + * until we've finished creating all the other TRBs. The ring's cycle + * state may change as we enqueue the other TRBs, so save it too. + */ + start_trb = &ep_ring->enqueue->generic; + start_cycle = ep_ring->cycle_state; + + /* Queue setup TRB - see section 6.4.1.2.1 */ + /* FIXME better way to translate setup_packet into two u32 fields? */ + setup = (struct usb_ctrlrequest *) urb->setup_packet; + queue_trb(xhci, ep_ring, false, + /* FIXME endianness is probably going to bite my ass here. */ + setup->bRequestType | setup->bRequest << 8 | setup->wValue << 16, + setup->wIndex | setup->wLength << 16, + TRB_LEN(8) | TRB_INTR_TARGET(0), + /* Immediate data in pointer */ + TRB_IDT | TRB_TYPE(TRB_SETUP)); + + /* If there's data, queue data TRBs */ + field = 0; + if (urb->transfer_buffer_length > 0) { + if (setup->bRequestType & USB_DIR_IN) + field |= TRB_DIR_IN; + queue_trb(xhci, ep_ring, false, + lower_32_bits(urb->transfer_dma), + upper_32_bits(urb->transfer_dma), + TRB_LEN(urb->transfer_buffer_length) | TRB_INTR_TARGET(0), + /* Event on short tx */ + field | TRB_ISP | TRB_TYPE(TRB_DATA) | ep_ring->cycle_state); + } + + /* Save the DMA address of the last TRB in the TD */ + td->last_trb = ep_ring->enqueue; + + /* Queue status TRB - see Table 7 and sections 4.11.2.2 and 6.4.1.2.3 */ + /* If the device sent data, the status stage is an OUT transfer */ + if (urb->transfer_buffer_length > 0 && setup->bRequestType & USB_DIR_IN) + field = 0; + else + field = TRB_DIR_IN; + queue_trb(xhci, ep_ring, false, + 0, + 0, + TRB_INTR_TARGET(0), + /* Event on completion */ + field | TRB_IOC | TRB_TYPE(TRB_STATUS) | ep_ring->cycle_state); + + giveback_first_trb(xhci, slot_id, ep_index, start_cycle, start_trb, td); + return 0; +} + +/**** Command Ring Operations ****/ + +/* Generic function for queueing a command TRB on the command ring */ +static int queue_command(struct xhci_hcd *xhci, u32 field1, u32 field2, u32 field3, u32 field4) +{ + if (!room_on_ring(xhci, xhci->cmd_ring, 1)) { + if (!in_interrupt()) + xhci_err(xhci, "ERR: No room for command on command ring\n"); + return -ENOMEM; + } + queue_trb(xhci, xhci->cmd_ring, false, field1, field2, field3, + field4 | xhci->cmd_ring->cycle_state); + return 0; +} + +/* Queue a no-op command on the command ring */ +static int queue_cmd_noop(struct xhci_hcd *xhci) +{ + return queue_command(xhci, 0, 0, 0, TRB_TYPE(TRB_CMD_NOOP)); +} + +/* + * Place a no-op command on the command ring to test the command and + * event ring. + */ +void *xhci_setup_one_noop(struct xhci_hcd *xhci) +{ + if (queue_cmd_noop(xhci) < 0) + return NULL; + xhci->noops_submitted++; + return xhci_ring_cmd_db; +} + +/* Queue a slot enable or disable request on the command ring */ +int xhci_queue_slot_control(struct xhci_hcd *xhci, u32 trb_type, u32 slot_id) +{ + return queue_command(xhci, 0, 0, 0, + TRB_TYPE(trb_type) | SLOT_ID_FOR_TRB(slot_id)); +} + +/* Queue an address device command TRB */ +int xhci_queue_address_device(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, + u32 slot_id) +{ + return queue_command(xhci, in_ctx_ptr, 0, 0, + TRB_TYPE(TRB_ADDR_DEV) | SLOT_ID_FOR_TRB(slot_id)); +} + +/* Queue a configure endpoint command TRB */ +int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, + u32 slot_id) +{ + return queue_command(xhci, in_ctx_ptr, 0, 0, + TRB_TYPE(TRB_CONFIG_EP) | SLOT_ID_FOR_TRB(slot_id)); +} + +int xhci_queue_stop_endpoint(struct xhci_hcd *xhci, int slot_id, + unsigned int ep_index) +{ + u32 trb_slot_id = SLOT_ID_FOR_TRB(slot_id); + u32 trb_ep_index = EP_ID_FOR_TRB(ep_index); + u32 type = TRB_TYPE(TRB_STOP_RING); + + return queue_command(xhci, 0, 0, 0, + trb_slot_id | trb_ep_index | type); +} + +/* Set Transfer Ring Dequeue Pointer command. + * This should not be used for endpoints that have streams enabled. + */ +static int queue_set_tr_deq(struct xhci_hcd *xhci, int slot_id, + unsigned int ep_index, struct xhci_segment *deq_seg, + union xhci_trb *deq_ptr, u32 cycle_state) +{ + dma_addr_t addr; + u32 trb_slot_id = SLOT_ID_FOR_TRB(slot_id); + u32 trb_ep_index = EP_ID_FOR_TRB(ep_index); + u32 type = TRB_TYPE(TRB_SET_DEQ); + + addr = xhci_trb_virt_to_dma(deq_seg, deq_ptr); + if (addr == 0) + xhci_warn(xhci, "WARN Cannot submit Set TR Deq Ptr\n"); + xhci_warn(xhci, "WARN deq seg = %p, deq pt = %p\n", + deq_seg, deq_ptr); + return queue_command(xhci, (u32) addr | cycle_state, 0, 0, + trb_slot_id | trb_ep_index | type); +} diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h new file mode 100644 index 000000000000..8936eeb5588b --- /dev/null +++ b/drivers/usb/host/xhci.h @@ -0,0 +1,1157 @@ +/* + * xHCI host controller driver + * + * Copyright (C) 2008 Intel Corp. + * + * Author: Sarah Sharp + * Some code borrowed from the Linux EHCI driver. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __LINUX_XHCI_HCD_H +#define __LINUX_XHCI_HCD_H + +#include +#include + +#include "../core/hcd.h" +/* Code sharing between pci-quirks and xhci hcd */ +#include "xhci-ext-caps.h" + +/* xHCI PCI Configuration Registers */ +#define XHCI_SBRN_OFFSET (0x60) + +/* Max number of USB devices for any host controller - limit in section 6.1 */ +#define MAX_HC_SLOTS 256 +/* Section 5.3.3 - MaxPorts */ +#define MAX_HC_PORTS 127 + +/* + * xHCI register interface. + * This corresponds to the eXtensible Host Controller Interface (xHCI) + * Revision 0.95 specification + * + * Registers should always be accessed with double word or quad word accesses. + * + * Some xHCI implementations may support 64-bit address pointers. Registers + * with 64-bit address pointers should be written to with dword accesses by + * writing the low dword first (ptr[0]), then the high dword (ptr[1]) second. + * xHCI implementations that do not support 64-bit address pointers will ignore + * the high dword, and write order is irrelevant. + */ + +/** + * struct xhci_cap_regs - xHCI Host Controller Capability Registers. + * @hc_capbase: length of the capabilities register and HC version number + * @hcs_params1: HCSPARAMS1 - Structural Parameters 1 + * @hcs_params2: HCSPARAMS2 - Structural Parameters 2 + * @hcs_params3: HCSPARAMS3 - Structural Parameters 3 + * @hcc_params: HCCPARAMS - Capability Parameters + * @db_off: DBOFF - Doorbell array offset + * @run_regs_off: RTSOFF - Runtime register space offset + */ +struct xhci_cap_regs { + u32 hc_capbase; + u32 hcs_params1; + u32 hcs_params2; + u32 hcs_params3; + u32 hcc_params; + u32 db_off; + u32 run_regs_off; + /* Reserved up to (CAPLENGTH - 0x1C) */ +}; + +/* hc_capbase bitmasks */ +/* bits 7:0 - how long is the Capabilities register */ +#define HC_LENGTH(p) XHCI_HC_LENGTH(p) +/* bits 31:16 */ +#define HC_VERSION(p) (((p) >> 16) & 0xffff) + +/* HCSPARAMS1 - hcs_params1 - bitmasks */ +/* bits 0:7, Max Device Slots */ +#define HCS_MAX_SLOTS(p) (((p) >> 0) & 0xff) +#define HCS_SLOTS_MASK 0xff +/* bits 8:18, Max Interrupters */ +#define HCS_MAX_INTRS(p) (((p) >> 8) & 0x7ff) +/* bits 24:31, Max Ports - max value is 0x7F = 127 ports */ +#define HCS_MAX_PORTS(p) (((p) >> 24) & 0x7f) + +/* HCSPARAMS2 - hcs_params2 - bitmasks */ +/* bits 0:3, frames or uframes that SW needs to queue transactions + * ahead of the HW to meet periodic deadlines */ +#define HCS_IST(p) (((p) >> 0) & 0xf) +/* bits 4:7, max number of Event Ring segments */ +#define HCS_ERST_MAX(p) (((p) >> 4) & 0xf) +/* bit 26 Scratchpad restore - for save/restore HW state - not used yet */ +/* bits 27:31 number of Scratchpad buffers SW must allocate for the HW */ + +/* HCSPARAMS3 - hcs_params3 - bitmasks */ +/* bits 0:7, Max U1 to U0 latency for the roothub ports */ +#define HCS_U1_LATENCY(p) (((p) >> 0) & 0xff) +/* bits 16:31, Max U2 to U0 latency for the roothub ports */ +#define HCS_U2_LATENCY(p) (((p) >> 16) & 0xffff) + +/* HCCPARAMS - hcc_params - bitmasks */ +/* true: HC can use 64-bit address pointers */ +#define HCC_64BIT_ADDR(p) ((p) & (1 << 0)) +/* true: HC can do bandwidth negotiation */ +#define HCC_BANDWIDTH_NEG(p) ((p) & (1 << 1)) +/* true: HC uses 64-byte Device Context structures + * FIXME 64-byte context structures aren't supported yet. + */ +#define HCC_64BYTE_CONTEXT(p) ((p) & (1 << 2)) +/* true: HC has port power switches */ +#define HCC_PPC(p) ((p) & (1 << 3)) +/* true: HC has port indicators */ +#define HCS_INDICATOR(p) ((p) & (1 << 4)) +/* true: HC has Light HC Reset Capability */ +#define HCC_LIGHT_RESET(p) ((p) & (1 << 5)) +/* true: HC supports latency tolerance messaging */ +#define HCC_LTC(p) ((p) & (1 << 6)) +/* true: no secondary Stream ID Support */ +#define HCC_NSS(p) ((p) & (1 << 7)) +/* Max size for Primary Stream Arrays - 2^(n+1), where n is bits 12:15 */ +#define HCC_MAX_PSA (1 << ((((p) >> 12) & 0xf) + 1)) +/* Extended Capabilities pointer from PCI base - section 5.3.6 */ +#define HCC_EXT_CAPS(p) XHCI_HCC_EXT_CAPS(p) + +/* db_off bitmask - bits 0:1 reserved */ +#define DBOFF_MASK (~0x3) + +/* run_regs_off bitmask - bits 0:4 reserved */ +#define RTSOFF_MASK (~0x1f) + + +/* Number of registers per port */ +#define NUM_PORT_REGS 4 + +/** + * struct xhci_op_regs - xHCI Host Controller Operational Registers. + * @command: USBCMD - xHC command register + * @status: USBSTS - xHC status register + * @page_size: This indicates the page size that the host controller + * supports. If bit n is set, the HC supports a page size + * of 2^(n+12), up to a 128MB page size. + * 4K is the minimum page size. + * @cmd_ring: CRP - 64-bit Command Ring Pointer + * @dcbaa_ptr: DCBAAP - 64-bit Device Context Base Address Array Pointer + * @config_reg: CONFIG - Configure Register + * @port_status_base: PORTSCn - base address for Port Status and Control + * Each port has a Port Status and Control register, + * followed by a Port Power Management Status and Control + * register, a Port Link Info register, and a reserved + * register. + * @port_power_base: PORTPMSCn - base address for + * Port Power Management Status and Control + * @port_link_base: PORTLIn - base address for Port Link Info (current + * Link PM state and control) for USB 2.1 and USB 3.0 + * devices. + */ +struct xhci_op_regs { + u32 command; + u32 status; + u32 page_size; + u32 reserved1; + u32 reserved2; + u32 dev_notification; + u32 cmd_ring[2]; + /* rsvd: offset 0x20-2F */ + u32 reserved3[4]; + u32 dcbaa_ptr[2]; + u32 config_reg; + /* rsvd: offset 0x3C-3FF */ + u32 reserved4[241]; + /* port 1 registers, which serve as a base address for other ports */ + u32 port_status_base; + u32 port_power_base; + u32 port_link_base; + u32 reserved5; + /* registers for ports 2-255 */ + u32 reserved6[NUM_PORT_REGS*254]; +}; + +/* USBCMD - USB command - command bitmasks */ +/* start/stop HC execution - do not write unless HC is halted*/ +#define CMD_RUN XHCI_CMD_RUN +/* Reset HC - resets internal HC state machine and all registers (except + * PCI config regs). HC does NOT drive a USB reset on the downstream ports. + * The xHCI driver must reinitialize the xHC after setting this bit. + */ +#define CMD_RESET (1 << 1) +/* Event Interrupt Enable - a '1' allows interrupts from the host controller */ +#define CMD_EIE XHCI_CMD_EIE +/* Host System Error Interrupt Enable - get out-of-band signal for HC errors */ +#define CMD_HSEIE XHCI_CMD_HSEIE +/* bits 4:6 are reserved (and should be preserved on writes). */ +/* light reset (port status stays unchanged) - reset completed when this is 0 */ +#define CMD_LRESET (1 << 7) +/* FIXME: ignoring host controller save/restore state for now. */ +#define CMD_CSS (1 << 8) +#define CMD_CRS (1 << 9) +/* Enable Wrap Event - '1' means xHC generates an event when MFINDEX wraps. */ +#define CMD_EWE XHCI_CMD_EWE +/* MFINDEX power management - '1' means xHC can stop MFINDEX counter if all root + * hubs are in U3 (selective suspend), disconnect, disabled, or powered-off. + * '0' means the xHC can power it off if all ports are in the disconnect, + * disabled, or powered-off state. + */ +#define CMD_PM_INDEX (1 << 11) +/* bits 12:31 are reserved (and should be preserved on writes). */ + +/* USBSTS - USB status - status bitmasks */ +/* HC not running - set to 1 when run/stop bit is cleared. */ +#define STS_HALT XHCI_STS_HALT +/* serious error, e.g. PCI parity error. The HC will clear the run/stop bit. */ +#define STS_FATAL (1 << 2) +/* event interrupt - clear this prior to clearing any IP flags in IR set*/ +#define STS_EINT (1 << 3) +/* port change detect */ +#define STS_PORT (1 << 4) +/* bits 5:7 reserved and zeroed */ +/* save state status - '1' means xHC is saving state */ +#define STS_SAVE (1 << 8) +/* restore state status - '1' means xHC is restoring state */ +#define STS_RESTORE (1 << 9) +/* true: save or restore error */ +#define STS_SRE (1 << 10) +/* true: Controller Not Ready to accept doorbell or op reg writes after reset */ +#define STS_CNR XHCI_STS_CNR +/* true: internal Host Controller Error - SW needs to reset and reinitialize */ +#define STS_HCE (1 << 12) +/* bits 13:31 reserved and should be preserved */ + +/* + * DNCTRL - Device Notification Control Register - dev_notification bitmasks + * Generate a device notification event when the HC sees a transaction with a + * notification type that matches a bit set in this bit field. + */ +#define DEV_NOTE_MASK (0xffff) +#define ENABLE_DEV_NOTE(x) (1 << x) +/* Most of the device notification types should only be used for debug. + * SW does need to pay attention to function wake notifications. + */ +#define DEV_NOTE_FWAKE ENABLE_DEV_NOTE(1) + +/* CRCR - Command Ring Control Register - cmd_ring bitmasks */ +/* bit 0 is the command ring cycle state */ +/* stop ring operation after completion of the currently executing command */ +#define CMD_RING_PAUSE (1 << 1) +/* stop ring immediately - abort the currently executing command */ +#define CMD_RING_ABORT (1 << 2) +/* true: command ring is running */ +#define CMD_RING_RUNNING (1 << 3) +/* bits 4:5 reserved and should be preserved */ +/* Command Ring pointer - bit mask for the lower 32 bits. */ +#define CMD_RING_ADDR_MASK (0xffffffc0) + +/* CONFIG - Configure Register - config_reg bitmasks */ +/* bits 0:7 - maximum number of device slots enabled (NumSlotsEn) */ +#define MAX_DEVS(p) ((p) & 0xff) +/* bits 8:31 - reserved and should be preserved */ + +/* PORTSC - Port Status and Control Register - port_status_base bitmasks */ +/* true: device connected */ +#define PORT_CONNECT (1 << 0) +/* true: port enabled */ +#define PORT_PE (1 << 1) +/* bit 2 reserved and zeroed */ +/* true: port has an over-current condition */ +#define PORT_OC (1 << 3) +/* true: port reset signaling asserted */ +#define PORT_RESET (1 << 4) +/* Port Link State - bits 5:8 + * A read gives the current link PM state of the port, + * a write with Link State Write Strobe set sets the link state. + */ +/* true: port has power (see HCC_PPC) */ +#define PORT_POWER (1 << 9) +/* bits 10:13 indicate device speed: + * 0 - undefined speed - port hasn't be initialized by a reset yet + * 1 - full speed + * 2 - low speed + * 3 - high speed + * 4 - super speed + * 5-15 reserved + */ +#define DEV_SPEED_MASK (0xf << 10) +#define XDEV_FS (0x1 << 10) +#define XDEV_LS (0x2 << 10) +#define XDEV_HS (0x3 << 10) +#define XDEV_SS (0x4 << 10) +#define DEV_UNDEFSPEED(p) (((p) & DEV_SPEED_MASK) == (0x0<<10)) +#define DEV_FULLSPEED(p) (((p) & DEV_SPEED_MASK) == XDEV_FS) +#define DEV_LOWSPEED(p) (((p) & DEV_SPEED_MASK) == XDEV_LS) +#define DEV_HIGHSPEED(p) (((p) & DEV_SPEED_MASK) == XDEV_HS) +#define DEV_SUPERSPEED(p) (((p) & DEV_SPEED_MASK) == XDEV_SS) +/* Bits 20:23 in the Slot Context are the speed for the device */ +#define SLOT_SPEED_FS (XDEV_FS << 10) +#define SLOT_SPEED_LS (XDEV_LS << 10) +#define SLOT_SPEED_HS (XDEV_HS << 10) +#define SLOT_SPEED_SS (XDEV_SS << 10) +/* Port Indicator Control */ +#define PORT_LED_OFF (0 << 14) +#define PORT_LED_AMBER (1 << 14) +#define PORT_LED_GREEN (2 << 14) +#define PORT_LED_MASK (3 << 14) +/* Port Link State Write Strobe - set this when changing link state */ +#define PORT_LINK_STROBE (1 << 16) +/* true: connect status change */ +#define PORT_CSC (1 << 17) +/* true: port enable change */ +#define PORT_PEC (1 << 18) +/* true: warm reset for a USB 3.0 device is done. A "hot" reset puts the port + * into an enabled state, and the device into the default state. A "warm" reset + * also resets the link, forcing the device through the link training sequence. + * SW can also look at the Port Reset register to see when warm reset is done. + */ +#define PORT_WRC (1 << 19) +/* true: over-current change */ +#define PORT_OCC (1 << 20) +/* true: reset change - 1 to 0 transition of PORT_RESET */ +#define PORT_RC (1 << 21) +/* port link status change - set on some port link state transitions: + * Transition Reason + * ------------------------------------------------------------------------------ + * - U3 to Resume Wakeup signaling from a device + * - Resume to Recovery to U0 USB 3.0 device resume + * - Resume to U0 USB 2.0 device resume + * - U3 to Recovery to U0 Software resume of USB 3.0 device complete + * - U3 to U0 Software resume of USB 2.0 device complete + * - U2 to U0 L1 resume of USB 2.1 device complete + * - U0 to U0 (???) L1 entry rejection by USB 2.1 device + * - U0 to disabled L1 entry error with USB 2.1 device + * - Any state to inactive Error on USB 3.0 port + */ +#define PORT_PLC (1 << 22) +/* port configure error change - port failed to configure its link partner */ +#define PORT_CEC (1 << 23) +/* bit 24 reserved */ +/* wake on connect (enable) */ +#define PORT_WKCONN_E (1 << 25) +/* wake on disconnect (enable) */ +#define PORT_WKDISC_E (1 << 26) +/* wake on over-current (enable) */ +#define PORT_WKOC_E (1 << 27) +/* bits 28:29 reserved */ +/* true: device is removable - for USB 3.0 roothub emulation */ +#define PORT_DEV_REMOVE (1 << 30) +/* Initiate a warm port reset - complete when PORT_WRC is '1' */ +#define PORT_WR (1 << 31) + +/* Port Power Management Status and Control - port_power_base bitmasks */ +/* Inactivity timer value for transitions into U1, in microseconds. + * Timeout can be up to 127us. 0xFF means an infinite timeout. + */ +#define PORT_U1_TIMEOUT(p) ((p) & 0xff) +/* Inactivity timer value for transitions into U2 */ +#define PORT_U2_TIMEOUT(p) (((p) & 0xff) << 8) +/* Bits 24:31 for port testing */ + + +/** + * struct xhci_intr_reg - Interrupt Register Set + * @irq_pending: IMAN - Interrupt Management Register. Used to enable + * interrupts and check for pending interrupts. + * @irq_control: IMOD - Interrupt Moderation Register. + * Used to throttle interrupts. + * @erst_size: Number of segments in the Event Ring Segment Table (ERST). + * @erst_base: ERST base address. + * @erst_dequeue: Event ring dequeue pointer. + * + * Each interrupter (defined by a MSI-X vector) has an event ring and an Event + * Ring Segment Table (ERST) associated with it. The event ring is comprised of + * multiple segments of the same size. The HC places events on the ring and + * "updates the Cycle bit in the TRBs to indicate to software the current + * position of the Enqueue Pointer." The HCD (Linux) processes those events and + * updates the dequeue pointer. + */ +struct xhci_intr_reg { + u32 irq_pending; + u32 irq_control; + u32 erst_size; + u32 rsvd; + u32 erst_base[2]; + u32 erst_dequeue[2]; +}; + +/* irq_pending bitmasks */ +#define ER_IRQ_PENDING(p) ((p) & 0x1) +/* bits 2:31 need to be preserved */ +/* THIS IS BUGGY - FIXME - IP IS WRITE 1 TO CLEAR */ +#define ER_IRQ_CLEAR(p) ((p) & 0xfffffffe) +#define ER_IRQ_ENABLE(p) ((ER_IRQ_CLEAR(p)) | 0x2) +#define ER_IRQ_DISABLE(p) ((ER_IRQ_CLEAR(p)) & ~(0x2)) + +/* irq_control bitmasks */ +/* Minimum interval between interrupts (in 250ns intervals). The interval + * between interrupts will be longer if there are no events on the event ring. + * Default is 4000 (1 ms). + */ +#define ER_IRQ_INTERVAL_MASK (0xffff) +/* Counter used to count down the time to the next interrupt - HW use only */ +#define ER_IRQ_COUNTER_MASK (0xffff << 16) + +/* erst_size bitmasks */ +/* Preserve bits 16:31 of erst_size */ +#define ERST_SIZE_MASK (0xffff << 16) + +/* erst_dequeue bitmasks */ +/* Dequeue ERST Segment Index (DESI) - Segment number (or alias) + * where the current dequeue pointer lies. This is an optional HW hint. + */ +#define ERST_DESI_MASK (0x7) +/* Event Handler Busy (EHB) - is the event ring scheduled to be serviced by + * a work queue (or delayed service routine)? + */ +#define ERST_EHB (1 << 3) +#define ERST_PTR_MASK (0xf) + +/** + * struct xhci_run_regs + * @microframe_index: + * MFINDEX - current microframe number + * + * Section 5.5 Host Controller Runtime Registers: + * "Software should read and write these registers using only Dword (32 bit) + * or larger accesses" + */ +struct xhci_run_regs { + u32 microframe_index; + u32 rsvd[7]; + struct xhci_intr_reg ir_set[128]; +}; + +/** + * struct doorbell_array + * + * Section 5.6 + */ +struct xhci_doorbell_array { + u32 doorbell[256]; +}; + +#define DB_TARGET_MASK 0xFFFFFF00 +#define DB_STREAM_ID_MASK 0x0000FFFF +#define DB_TARGET_HOST 0x0 +#define DB_STREAM_ID_HOST 0x0 +#define DB_MASK (0xff << 8) + +/* Endpoint Target - bits 0:7 */ +#define EPI_TO_DB(p) (((p) + 1) & 0xff) + + +/** + * struct xhci_slot_ctx + * @dev_info: Route string, device speed, hub info, and last valid endpoint + * @dev_info2: Max exit latency for device number, root hub port number + * @tt_info: tt_info is used to construct split transaction tokens + * @dev_state: slot state and device address + * + * Slot Context - section 6.2.1.1. This assumes the HC uses 32-byte context + * structures. If the HC uses 64-byte contexts, there is an additional 32 bytes + * reserved at the end of the slot context for HC internal use. + */ +struct xhci_slot_ctx { + u32 dev_info; + u32 dev_info2; + u32 tt_info; + u32 dev_state; + /* offset 0x10 to 0x1f reserved for HC internal use */ + u32 reserved[4]; +}; + +/* dev_info bitmasks */ +/* Route String - 0:19 */ +#define ROUTE_STRING_MASK (0xfffff) +/* Device speed - values defined by PORTSC Device Speed field - 20:23 */ +#define DEV_SPEED (0xf << 20) +/* bit 24 reserved */ +/* Is this LS/FS device connected through a HS hub? - bit 25 */ +#define DEV_MTT (0x1 << 25) +/* Set if the device is a hub - bit 26 */ +#define DEV_HUB (0x1 << 26) +/* Index of the last valid endpoint context in this device context - 27:31 */ +#define LAST_CTX_MASK (0x1f << 27) +#define LAST_CTX(p) ((p) << 27) +#define LAST_CTX_TO_EP_NUM(p) (((p) >> 27) - 1) +#define SLOT_FLAG (1 << 0) +#define EP0_FLAG (1 << 1) + +/* dev_info2 bitmasks */ +/* Max Exit Latency (ms) - worst case time to wake up all links in dev path */ +#define MAX_EXIT (0xffff) +/* Root hub port number that is needed to access the USB device */ +#define ROOT_HUB_PORT(p) (((p) & 0xff) << 16) + +/* tt_info bitmasks */ +/* + * TT Hub Slot ID - for low or full speed devices attached to a high-speed hub + * The Slot ID of the hub that isolates the high speed signaling from + * this low or full-speed device. '0' if attached to root hub port. + */ +#define TT_SLOT (0xff) +/* + * The number of the downstream facing port of the high-speed hub + * '0' if the device is not low or full speed. + */ +#define TT_PORT (0xff << 8) + +/* dev_state bitmasks */ +/* USB device address - assigned by the HC */ +#define DEV_ADDR_MASK (0xff) +/* bits 8:26 reserved */ +/* Slot state */ +#define SLOT_STATE (0x1f << 27) +#define GET_SLOT_STATE(p) (((p) & (0x1f << 27)) >> 27) + + +/** + * struct xhci_ep_ctx + * @ep_info: endpoint state, streams, mult, and interval information. + * @ep_info2: information on endpoint type, max packet size, max burst size, + * error count, and whether the HC will force an event for all + * transactions. + * @deq: 64-bit ring dequeue pointer address. If the endpoint only + * defines one stream, this points to the endpoint transfer ring. + * Otherwise, it points to a stream context array, which has a + * ring pointer for each flow. + * @tx_info: + * Average TRB lengths for the endpoint ring and + * max payload within an Endpoint Service Interval Time (ESIT). + * + * Endpoint Context - section 6.2.1.2. This assumes the HC uses 32-byte context + * structures. If the HC uses 64-byte contexts, there is an additional 32 bytes + * reserved at the end of the endpoint context for HC internal use. + */ +struct xhci_ep_ctx { + u32 ep_info; + u32 ep_info2; + u32 deq[2]; + u32 tx_info; + /* offset 0x14 - 0x1f reserved for HC internal use */ + u32 reserved[3]; +}; + +/* ep_info bitmasks */ +/* + * Endpoint State - bits 0:2 + * 0 - disabled + * 1 - running + * 2 - halted due to halt condition - ok to manipulate endpoint ring + * 3 - stopped + * 4 - TRB error + * 5-7 - reserved + */ +#define EP_STATE_MASK (0xf) +#define EP_STATE_DISABLED 0 +#define EP_STATE_RUNNING 1 +#define EP_STATE_HALTED 2 +#define EP_STATE_STOPPED 3 +#define EP_STATE_ERROR 4 +/* Mult - Max number of burtst within an interval, in EP companion desc. */ +#define EP_MULT(p) ((p & 0x3) << 8) +/* bits 10:14 are Max Primary Streams */ +/* bit 15 is Linear Stream Array */ +/* Interval - period between requests to an endpoint - 125u increments. */ +#define EP_INTERVAL(p) ((p & 0xff) << 16) + +/* ep_info2 bitmasks */ +/* + * Force Event - generate transfer events for all TRBs for this endpoint + * This will tell the HC to ignore the IOC and ISP flags (for debugging only). + */ +#define FORCE_EVENT (0x1) +#define ERROR_COUNT(p) (((p) & 0x3) << 1) +#define EP_TYPE(p) ((p) << 3) +#define ISOC_OUT_EP 1 +#define BULK_OUT_EP 2 +#define INT_OUT_EP 3 +#define CTRL_EP 4 +#define ISOC_IN_EP 5 +#define BULK_IN_EP 6 +#define INT_IN_EP 7 +/* bit 6 reserved */ +/* bit 7 is Host Initiate Disable - for disabling stream selection */ +#define MAX_BURST(p) (((p)&0xff) << 8) +#define MAX_PACKET(p) (((p)&0xffff) << 16) + + +/** + * struct xhci_device_control + * Input/Output context; see section 6.2.5. + * + * @drop_context: set the bit of the endpoint context you want to disable + * @add_context: set the bit of the endpoint context you want to enable + */ +struct xhci_device_control { + u32 drop_flags; + u32 add_flags; + u32 rsvd[6]; + struct xhci_slot_ctx slot; + struct xhci_ep_ctx ep[31]; +}; + +/* drop context bitmasks */ +#define DROP_EP(x) (0x1 << x) +/* add context bitmasks */ +#define ADD_EP(x) (0x1 << x) + + +struct xhci_virt_device { + /* + * Commands to the hardware are passed an "input context" that + * tells the hardware what to change in its data structures. + * The hardware will return changes in an "output context" that + * software must allocate for the hardware. We need to keep + * track of input and output contexts separately because + * these commands might fail and we don't trust the hardware. + */ + struct xhci_device_control *out_ctx; + dma_addr_t out_ctx_dma; + /* Used for addressing devices and configuration changes */ + struct xhci_device_control *in_ctx; + dma_addr_t in_ctx_dma; + /* FIXME when stream support is added */ + struct xhci_ring *ep_rings[31]; + /* Temporary storage in case the configure endpoint command fails and we + * have to restore the device state to the previous state + */ + struct xhci_ring *new_ep_rings[31]; + struct completion cmd_completion; + /* Status of the last command issued for this device */ + u32 cmd_status; +}; + + +/** + * struct xhci_device_context_array + * @dev_context_ptr array of 64-bit DMA addresses for device contexts + */ +struct xhci_device_context_array { + /* 64-bit device addresses; we only write 32-bit addresses */ + u32 dev_context_ptrs[2*MAX_HC_SLOTS]; + /* private xHCD pointers */ + dma_addr_t dma; +}; +/* TODO: write function to set the 64-bit device DMA address */ +/* + * TODO: change this to be dynamically sized at HC mem init time since the HC + * might not be able to handle the maximum number of devices possible. + */ + + +struct xhci_stream_ctx { + /* 64-bit stream ring address, cycle state, and stream type */ + u32 stream_ring[2]; + /* offset 0x14 - 0x1f reserved for HC internal use */ + u32 reserved[2]; +}; + + +struct xhci_transfer_event { + /* 64-bit buffer address, or immediate data */ + u32 buffer[2]; + u32 transfer_len; + /* This field is interpreted differently based on the type of TRB */ + u32 flags; +}; + +/** Transfer Event bit fields **/ +#define TRB_TO_EP_ID(p) (((p) >> 16) & 0x1f) + +/* Completion Code - only applicable for some types of TRBs */ +#define COMP_CODE_MASK (0xff << 24) +#define GET_COMP_CODE(p) (((p) & COMP_CODE_MASK) >> 24) +#define COMP_SUCCESS 1 +/* Data Buffer Error */ +#define COMP_DB_ERR 2 +/* Babble Detected Error */ +#define COMP_BABBLE 3 +/* USB Transaction Error */ +#define COMP_TX_ERR 4 +/* TRB Error - some TRB field is invalid */ +#define COMP_TRB_ERR 5 +/* Stall Error - USB device is stalled */ +#define COMP_STALL 6 +/* Resource Error - HC doesn't have memory for that device configuration */ +#define COMP_ENOMEM 7 +/* Bandwidth Error - not enough room in schedule for this dev config */ +#define COMP_BW_ERR 8 +/* No Slots Available Error - HC ran out of device slots */ +#define COMP_ENOSLOTS 9 +/* Invalid Stream Type Error */ +#define COMP_STREAM_ERR 10 +/* Slot Not Enabled Error - doorbell rung for disabled device slot */ +#define COMP_EBADSLT 11 +/* Endpoint Not Enabled Error */ +#define COMP_EBADEP 12 +/* Short Packet */ +#define COMP_SHORT_TX 13 +/* Ring Underrun - doorbell rung for an empty isoc OUT ep ring */ +#define COMP_UNDERRUN 14 +/* Ring Overrun - isoc IN ep ring is empty when ep is scheduled to RX */ +#define COMP_OVERRUN 15 +/* Virtual Function Event Ring Full Error */ +#define COMP_VF_FULL 16 +/* Parameter Error - Context parameter is invalid */ +#define COMP_EINVAL 17 +/* Bandwidth Overrun Error - isoc ep exceeded its allocated bandwidth */ +#define COMP_BW_OVER 18 +/* Context State Error - illegal context state transition requested */ +#define COMP_CTX_STATE 19 +/* No Ping Response Error - HC didn't get PING_RESPONSE in time to TX */ +#define COMP_PING_ERR 20 +/* Event Ring is full */ +#define COMP_ER_FULL 21 +/* Missed Service Error - HC couldn't service an isoc ep within interval */ +#define COMP_MISSED_INT 23 +/* Successfully stopped command ring */ +#define COMP_CMD_STOP 24 +/* Successfully aborted current command and stopped command ring */ +#define COMP_CMD_ABORT 25 +/* Stopped - transfer was terminated by a stop endpoint command */ +#define COMP_STOP 26 +/* Same as COMP_EP_STOPPED, but the transfered length in the event is invalid */ +#define COMP_STOP_INVAL 27 +/* Control Abort Error - Debug Capability - control pipe aborted */ +#define COMP_DBG_ABORT 28 +/* TRB type 29 and 30 reserved */ +/* Isoc Buffer Overrun - an isoc IN ep sent more data than could fit in TD */ +#define COMP_BUFF_OVER 31 +/* Event Lost Error - xHC has an "internal event overrun condition" */ +#define COMP_ISSUES 32 +/* Undefined Error - reported when other error codes don't apply */ +#define COMP_UNKNOWN 33 +/* Invalid Stream ID Error */ +#define COMP_STRID_ERR 34 +/* Secondary Bandwidth Error - may be returned by a Configure Endpoint cmd */ +/* FIXME - check for this */ +#define COMP_2ND_BW_ERR 35 +/* Split Transaction Error */ +#define COMP_SPLIT_ERR 36 + +struct xhci_link_trb { + /* 64-bit segment pointer*/ + u32 segment_ptr[2]; + u32 intr_target; + u32 control; +}; + +/* control bitfields */ +#define LINK_TOGGLE (0x1<<1) + +/* Command completion event TRB */ +struct xhci_event_cmd { + /* Pointer to command TRB, or the value passed by the event data trb */ + u32 cmd_trb[2]; + u32 status; + u32 flags; +}; + +/* flags bitmasks */ +/* bits 16:23 are the virtual function ID */ +/* bits 24:31 are the slot ID */ +#define TRB_TO_SLOT_ID(p) (((p) & (0xff<<24)) >> 24) +#define SLOT_ID_FOR_TRB(p) (((p) & 0xff) << 24) + +/* Stop Endpoint TRB - ep_index to endpoint ID for this TRB */ +#define TRB_TO_EP_INDEX(p) ((((p) & (0x1f << 16)) >> 16) - 1) +#define EP_ID_FOR_TRB(p) ((((p) + 1) & 0x1f) << 16) + + +/* Port Status Change Event TRB fields */ +/* Port ID - bits 31:24 */ +#define GET_PORT_ID(p) (((p) & (0xff << 24)) >> 24) + +/* Normal TRB fields */ +/* transfer_len bitmasks - bits 0:16 */ +#define TRB_LEN(p) ((p) & 0x1ffff) +/* TD size - number of bytes remaining in the TD (including this TRB): + * bits 17 - 21. Shift the number of bytes by 10. */ +#define TD_REMAINDER(p) ((((p) >> 10) & 0x1f) << 17) +/* Interrupter Target - which MSI-X vector to target the completion event at */ +#define TRB_INTR_TARGET(p) (((p) & 0x3ff) << 22) +#define GET_INTR_TARGET(p) (((p) >> 22) & 0x3ff) + +/* Cycle bit - indicates TRB ownership by HC or HCD */ +#define TRB_CYCLE (1<<0) +/* + * Force next event data TRB to be evaluated before task switch. + * Used to pass OS data back after a TD completes. + */ +#define TRB_ENT (1<<1) +/* Interrupt on short packet */ +#define TRB_ISP (1<<2) +/* Set PCIe no snoop attribute */ +#define TRB_NO_SNOOP (1<<3) +/* Chain multiple TRBs into a TD */ +#define TRB_CHAIN (1<<4) +/* Interrupt on completion */ +#define TRB_IOC (1<<5) +/* The buffer pointer contains immediate data */ +#define TRB_IDT (1<<6) + + +/* Control transfer TRB specific fields */ +#define TRB_DIR_IN (1<<16) + +struct xhci_generic_trb { + u32 field[4]; +}; + +union xhci_trb { + struct xhci_link_trb link; + struct xhci_transfer_event trans_event; + struct xhci_event_cmd event_cmd; + struct xhci_generic_trb generic; +}; + +/* TRB bit mask */ +#define TRB_TYPE_BITMASK (0xfc00) +#define TRB_TYPE(p) ((p) << 10) +/* TRB type IDs */ +/* bulk, interrupt, isoc scatter/gather, and control data stage */ +#define TRB_NORMAL 1 +/* setup stage for control transfers */ +#define TRB_SETUP 2 +/* data stage for control transfers */ +#define TRB_DATA 3 +/* status stage for control transfers */ +#define TRB_STATUS 4 +/* isoc transfers */ +#define TRB_ISOC 5 +/* TRB for linking ring segments */ +#define TRB_LINK 6 +#define TRB_EVENT_DATA 7 +/* Transfer Ring No-op (not for the command ring) */ +#define TRB_TR_NOOP 8 +/* Command TRBs */ +/* Enable Slot Command */ +#define TRB_ENABLE_SLOT 9 +/* Disable Slot Command */ +#define TRB_DISABLE_SLOT 10 +/* Address Device Command */ +#define TRB_ADDR_DEV 11 +/* Configure Endpoint Command */ +#define TRB_CONFIG_EP 12 +/* Evaluate Context Command */ +#define TRB_EVAL_CONTEXT 13 +/* Reset Transfer Ring Command */ +#define TRB_RESET_RING 14 +/* Stop Transfer Ring Command */ +#define TRB_STOP_RING 15 +/* Set Transfer Ring Dequeue Pointer Command */ +#define TRB_SET_DEQ 16 +/* Reset Device Command */ +#define TRB_RESET_DEV 17 +/* Force Event Command (opt) */ +#define TRB_FORCE_EVENT 18 +/* Negotiate Bandwidth Command (opt) */ +#define TRB_NEG_BANDWIDTH 19 +/* Set Latency Tolerance Value Command (opt) */ +#define TRB_SET_LT 20 +/* Get port bandwidth Command */ +#define TRB_GET_BW 21 +/* Force Header Command - generate a transaction or link management packet */ +#define TRB_FORCE_HEADER 22 +/* No-op Command - not for transfer rings */ +#define TRB_CMD_NOOP 23 +/* TRB IDs 24-31 reserved */ +/* Event TRBS */ +/* Transfer Event */ +#define TRB_TRANSFER 32 +/* Command Completion Event */ +#define TRB_COMPLETION 33 +/* Port Status Change Event */ +#define TRB_PORT_STATUS 34 +/* Bandwidth Request Event (opt) */ +#define TRB_BANDWIDTH_EVENT 35 +/* Doorbell Event (opt) */ +#define TRB_DOORBELL 36 +/* Host Controller Event */ +#define TRB_HC_EVENT 37 +/* Device Notification Event - device sent function wake notification */ +#define TRB_DEV_NOTE 38 +/* MFINDEX Wrap Event - microframe counter wrapped */ +#define TRB_MFINDEX_WRAP 39 +/* TRB IDs 40-47 reserved, 48-63 is vendor-defined */ + +/* + * TRBS_PER_SEGMENT must be a multiple of 4, + * since the command ring is 64-byte aligned. + * It must also be greater than 16. + */ +#define TRBS_PER_SEGMENT 64 +#define SEGMENT_SIZE (TRBS_PER_SEGMENT*16) +/* TRB buffer pointers can't cross 64KB boundaries */ +#define TRB_MAX_BUFF_SHIFT 16 +#define TRB_MAX_BUFF_SIZE (1 << TRB_MAX_BUFF_SHIFT) + +struct xhci_segment { + union xhci_trb *trbs; + /* private to HCD */ + struct xhci_segment *next; + dma_addr_t dma; +}; + +struct xhci_td { + struct list_head td_list; + struct list_head cancelled_td_list; + struct urb *urb; + struct xhci_segment *start_seg; + union xhci_trb *first_trb; + union xhci_trb *last_trb; +}; + +struct xhci_ring { + struct xhci_segment *first_seg; + union xhci_trb *enqueue; + struct xhci_segment *enq_seg; + unsigned int enq_updates; + union xhci_trb *dequeue; + struct xhci_segment *deq_seg; + unsigned int deq_updates; + struct list_head td_list; + /* ---- Related to URB cancellation ---- */ + struct list_head cancelled_td_list; + unsigned int cancels_pending; + unsigned int state; +#define SET_DEQ_PENDING (1 << 0) + /* The TRB that was last reported in a stopped endpoint ring */ + union xhci_trb *stopped_trb; + struct xhci_td *stopped_td; + /* + * Write the cycle state into the TRB cycle field to give ownership of + * the TRB to the host controller (if we are the producer), or to check + * if we own the TRB (if we are the consumer). See section 4.9.1. + */ + u32 cycle_state; +}; + +struct xhci_erst_entry { + /* 64-bit event ring segment address */ + u32 seg_addr[2]; + u32 seg_size; + /* Set to zero */ + u32 rsvd; +}; + +struct xhci_erst { + struct xhci_erst_entry *entries; + unsigned int num_entries; + /* xhci->event_ring keeps track of segment dma addresses */ + dma_addr_t erst_dma_addr; + /* Num entries the ERST can contain */ + unsigned int erst_size; +}; + +/* + * Each segment table entry is 4*32bits long. 1K seems like an ok size: + * (1K bytes * 8bytes/bit) / (4*32 bits) = 64 segment entries in the table, + * meaning 64 ring segments. + * Initial allocated size of the ERST, in number of entries */ +#define ERST_NUM_SEGS 1 +/* Initial allocated size of the ERST, in number of entries */ +#define ERST_SIZE 64 +/* Initial number of event segment rings allocated */ +#define ERST_ENTRIES 1 +/* Poll every 60 seconds */ +#define POLL_TIMEOUT 60 +/* XXX: Make these module parameters */ + + +/* There is one ehci_hci structure per controller */ +struct xhci_hcd { + /* glue to PCI and HCD framework */ + struct xhci_cap_regs __iomem *cap_regs; + struct xhci_op_regs __iomem *op_regs; + struct xhci_run_regs __iomem *run_regs; + struct xhci_doorbell_array __iomem *dba; + /* Our HCD's current interrupter register set */ + struct xhci_intr_reg __iomem *ir_set; + + /* Cached register copies of read-only HC data */ + __u32 hcs_params1; + __u32 hcs_params2; + __u32 hcs_params3; + __u32 hcc_params; + + spinlock_t lock; + + /* packed release number */ + u8 sbrn; + u16 hci_version; + u8 max_slots; + u8 max_interrupters; + u8 max_ports; + u8 isoc_threshold; + int event_ring_max; + int addr_64; + /* 4KB min, 128MB max */ + int page_size; + /* Valid values are 12 to 20, inclusive */ + int page_shift; + /* only one MSI vector for now, but might need more later */ + int msix_count; + struct msix_entry *msix_entries; + /* data structures */ + struct xhci_device_context_array *dcbaa; + struct xhci_ring *cmd_ring; + struct xhci_ring *event_ring; + struct xhci_erst erst; + /* slot enabling and address device helpers */ + struct completion addr_dev; + int slot_id; + /* Internal mirror of the HW's dcbaa */ + struct xhci_virt_device *devs[MAX_HC_SLOTS]; + + /* DMA pools */ + struct dma_pool *device_pool; + struct dma_pool *segment_pool; + +#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING + /* Poll the rings - for debugging */ + struct timer_list event_ring_timer; + int zombie; +#endif + /* Statistics */ + int noops_submitted; + int noops_handled; + int error_bitmask; +}; + +/* For testing purposes */ +#define NUM_TEST_NOOPS 0 + +/* convert between an HCD pointer and the corresponding EHCI_HCD */ +static inline struct xhci_hcd *hcd_to_xhci(struct usb_hcd *hcd) +{ + return (struct xhci_hcd *) (hcd->hcd_priv); +} + +static inline struct usb_hcd *xhci_to_hcd(struct xhci_hcd *xhci) +{ + return container_of((void *) xhci, struct usb_hcd, hcd_priv); +} + +#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING +#define XHCI_DEBUG 1 +#else +#define XHCI_DEBUG 0 +#endif + +#define xhci_dbg(xhci, fmt, args...) \ + do { if (XHCI_DEBUG) dev_dbg(xhci_to_hcd(xhci)->self.controller , fmt , ## args); } while (0) +#define xhci_info(xhci, fmt, args...) \ + do { if (XHCI_DEBUG) dev_info(xhci_to_hcd(xhci)->self.controller , fmt , ## args); } while (0) +#define xhci_err(xhci, fmt, args...) \ + dev_err(xhci_to_hcd(xhci)->self.controller , fmt , ## args) +#define xhci_warn(xhci, fmt, args...) \ + dev_warn(xhci_to_hcd(xhci)->self.controller , fmt , ## args) + +/* TODO: copied from ehci.h - can be refactored? */ +/* xHCI spec says all registers are little endian */ +static inline unsigned int xhci_readl(const struct xhci_hcd *xhci, + __u32 __iomem *regs) +{ + return readl(regs); +} +static inline void xhci_writel(struct xhci_hcd *xhci, + const unsigned int val, __u32 __iomem *regs) +{ + if (!in_interrupt()) + xhci_dbg(xhci, + "`MEM_WRITE_DWORD(3'b000, 32'h%p, 32'h%0x, 4'hf);\n", + regs, val); + writel(val, regs); +} + +/* xHCI debugging */ +void xhci_print_ir_set(struct xhci_hcd *xhci, struct xhci_intr_reg *ir_set, int set_num); +void xhci_print_registers(struct xhci_hcd *xhci); +void xhci_dbg_regs(struct xhci_hcd *xhci); +void xhci_print_run_regs(struct xhci_hcd *xhci); +void xhci_print_trb_offsets(struct xhci_hcd *xhci, union xhci_trb *trb); +void xhci_debug_trb(struct xhci_hcd *xhci, union xhci_trb *trb); +void xhci_debug_segment(struct xhci_hcd *xhci, struct xhci_segment *seg); +void xhci_debug_ring(struct xhci_hcd *xhci, struct xhci_ring *ring); +void xhci_dbg_erst(struct xhci_hcd *xhci, struct xhci_erst *erst); +void xhci_dbg_cmd_ptrs(struct xhci_hcd *xhci); +void xhci_dbg_ring_ptrs(struct xhci_hcd *xhci, struct xhci_ring *ring); +void xhci_dbg_ctx(struct xhci_hcd *xhci, struct xhci_device_control *ctx, dma_addr_t dma, unsigned int last_ep); + +/* xHCI memory managment */ +void xhci_mem_cleanup(struct xhci_hcd *xhci); +int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags); +void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id); +int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, struct usb_device *udev, gfp_t flags); +int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *udev); +unsigned int xhci_get_endpoint_index(struct usb_endpoint_descriptor *desc); +unsigned int xhci_get_endpoint_flag(struct usb_endpoint_descriptor *desc); +void xhci_endpoint_zero(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev, struct usb_host_endpoint *ep); +int xhci_endpoint_init(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev, + struct usb_device *udev, struct usb_host_endpoint *ep, + gfp_t mem_flags); +void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring); + +#ifdef CONFIG_PCI +/* xHCI PCI glue */ +int xhci_register_pci(void); +void xhci_unregister_pci(void); +#endif + +/* xHCI host controller glue */ +int xhci_halt(struct xhci_hcd *xhci); +int xhci_reset(struct xhci_hcd *xhci); +int xhci_init(struct usb_hcd *hcd); +int xhci_run(struct usb_hcd *hcd); +void xhci_stop(struct usb_hcd *hcd); +void xhci_shutdown(struct usb_hcd *hcd); +int xhci_get_frame(struct usb_hcd *hcd); +irqreturn_t xhci_irq(struct usb_hcd *hcd); +int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev); +void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev); +int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev); +int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags); +int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status); +int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, struct usb_host_endpoint *ep); +int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev, struct usb_host_endpoint *ep); +int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev); +void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev); + +/* xHCI ring, segment, TRB, and TD functions */ +dma_addr_t xhci_trb_virt_to_dma(struct xhci_segment *seg, union xhci_trb *trb); +void xhci_ring_cmd_db(struct xhci_hcd *xhci); +void *xhci_setup_one_noop(struct xhci_hcd *xhci); +void xhci_handle_event(struct xhci_hcd *xhci); +void xhci_set_hc_event_deq(struct xhci_hcd *xhci); +int xhci_queue_slot_control(struct xhci_hcd *xhci, u32 trb_type, u32 slot_id); +int xhci_queue_address_device(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, + u32 slot_id); +int xhci_queue_stop_endpoint(struct xhci_hcd *xhci, int slot_id, + unsigned int ep_index); +int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb, + int slot_id, unsigned int ep_index); +int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb, + int slot_id, unsigned int ep_index); +int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, + u32 slot_id); + +/* xHCI roothub code */ +int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, + char *buf, u16 wLength); +int xhci_hub_status_data(struct usb_hcd *hcd, char *buf); + +#endif /* __LINUX_XHCI_HCD_H */ diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c index a4ef77ef917d..3c5fe5cee05a 100644 --- a/drivers/usb/misc/iowarrior.c +++ b/drivers/usb/misc/iowarrior.c @@ -726,12 +726,18 @@ static const struct file_operations iowarrior_fops = { .poll = iowarrior_poll, }; +static char *iowarrior_nodename(struct device *dev) +{ + return kasprintf(GFP_KERNEL, "usb/%s", dev_name(dev)); +} + /* * usb class driver info in order to get a minor number from the usb core, * and to have the device registered with devfs and the driver core */ static struct usb_class_driver iowarrior_class = { .name = "iowarrior%d", + .nodename = iowarrior_nodename, .fops = &iowarrior_fops, .minor_base = IOWARRIOR_MINOR_BASE, }; diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c index ab0f3226158b..c1e2433f640d 100644 --- a/drivers/usb/misc/legousbtower.c +++ b/drivers/usb/misc/legousbtower.c @@ -266,12 +266,18 @@ static const struct file_operations tower_fops = { .llseek = tower_llseek, }; +static char *legousbtower_nodename(struct device *dev) +{ + return kasprintf(GFP_KERNEL, "usb/%s", dev_name(dev)); +} + /* * usb class driver info in order to get a minor number from the usb core, * and to have the device registered with the driver core */ static struct usb_class_driver tower_class = { .name = "legousbtower%d", + .nodename = legousbtower_nodename, .fops = &tower_fops, .minor_base = LEGO_USB_TOWER_MINOR_BASE, }; diff --git a/drivers/usb/misc/sisusbvga/Kconfig b/drivers/usb/misc/sisusbvga/Kconfig index 7603cbe0865d..30ea7ca6846e 100644 --- a/drivers/usb/misc/sisusbvga/Kconfig +++ b/drivers/usb/misc/sisusbvga/Kconfig @@ -1,7 +1,7 @@ config USB_SISUSBVGA tristate "USB 2.0 SVGA dongle support (Net2280/SiS315)" - depends on USB && USB_EHCI_HCD + depends on USB && (USB_MUSB_HDRC || USB_EHCI_HCD) ---help--- Say Y here if you intend to attach a USB2VGA dongle based on a Net2280 and a SiS315 chip. diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c index 5f1a19d1497d..a9f06d76960f 100644 --- a/drivers/usb/misc/usbtest.c +++ b/drivers/usb/misc/usbtest.c @@ -1072,23 +1072,34 @@ static int unlink1 (struct usbtest_dev *dev, int pipe, int size, int async) */ msleep (jiffies % (2 * INTERRUPT_RATE)); if (async) { -retry: - retval = usb_unlink_urb (urb); - if (retval == -EBUSY || retval == -EIDRM) { - /* we can't unlink urbs while they're completing. - * or if they've completed, and we haven't resubmitted. - * "normal" drivers would prevent resubmission, but - * since we're testing unlink paths, we can't. - */ - ERROR(dev, "unlink retry\n"); - goto retry; + while (!completion_done(&completion)) { + retval = usb_unlink_urb(urb); + + switch (retval) { + case -EBUSY: + case -EIDRM: + /* we can't unlink urbs while they're completing + * or if they've completed, and we haven't + * resubmitted. "normal" drivers would prevent + * resubmission, but since we're testing unlink + * paths, we can't. + */ + ERROR(dev, "unlink retry\n"); + continue; + case 0: + case -EINPROGRESS: + break; + + default: + dev_err(&dev->intf->dev, + "unlink fail %d\n", retval); + return retval; + } + + break; } } else usb_kill_urb (urb); - if (!(retval == 0 || retval == -EINPROGRESS)) { - dev_err(&dev->intf->dev, "unlink fail %d\n", retval); - return retval; - } wait_for_completion (&completion); retval = urb->status; diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c index 1f715436d6d3..a7eb4c99342c 100644 --- a/drivers/usb/mon/mon_text.c +++ b/drivers/usb/mon/mon_text.c @@ -733,7 +733,7 @@ int __init mon_text_init(void) { struct dentry *mondir; - mondir = debugfs_create_dir("usbmon", NULL); + mondir = debugfs_create_dir("usbmon", usb_debug_root); if (IS_ERR(mondir)) { printk(KERN_NOTICE TAG ": debugfs is not available\n"); return -ENODEV; diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index b66e8544d8b9..70073b157f0a 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -10,6 +10,7 @@ comment "Enable Host or Gadget support to see Inventra options" config USB_MUSB_HDRC depends on (USB || USB_GADGET) && HAVE_CLK depends on !SUPERH + select NOP_USB_XCEIV if ARCH_DAVINCI select TWL4030_USB if MACH_OMAP_3430SDP select USB_OTG_UTILS tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)' @@ -55,6 +56,7 @@ comment "Blackfin high speed USB Support" config USB_TUSB6010 boolean "TUSB 6010 support" depends on USB_MUSB_HDRC && !USB_MUSB_SOC + select NOP_USB_XCEIV default y help The TUSB 6010 chip, from Texas Instruments, connects a discrete diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c index 786134852092..f2f66ebc7362 100644 --- a/drivers/usb/musb/blackfin.c +++ b/drivers/usb/musb/blackfin.c @@ -143,7 +143,7 @@ static void musb_conn_timer_handler(unsigned long _musb) u16 val; spin_lock_irqsave(&musb->lock, flags); - switch (musb->xceiv.state) { + switch (musb->xceiv->state) { case OTG_STATE_A_IDLE: case OTG_STATE_A_WAIT_BCON: /* Start a new session */ @@ -154,7 +154,7 @@ static void musb_conn_timer_handler(unsigned long _musb) val = musb_readw(musb->mregs, MUSB_DEVCTL); if (!(val & MUSB_DEVCTL_BDEVICE)) { gpio_set_value(musb->config->gpio_vrsel, 1); - musb->xceiv.state = OTG_STATE_A_WAIT_BCON; + musb->xceiv->state = OTG_STATE_A_WAIT_BCON; } else { gpio_set_value(musb->config->gpio_vrsel, 0); @@ -247,6 +247,11 @@ int __init musb_platform_init(struct musb *musb) } gpio_direction_output(musb->config->gpio_vrsel, 0); + usb_nop_xceiv_register(); + musb->xceiv = otg_get_transceiver(); + if (!musb->xceiv) + return -ENODEV; + if (ANOMALY_05000346) { bfin_write_USB_APHY_CALIB(ANOMALY_05000346_value); SSYNC(); @@ -291,7 +296,7 @@ int __init musb_platform_init(struct musb *musb) musb_conn_timer_handler, (unsigned long) musb); } if (is_peripheral_enabled(musb)) - musb->xceiv.set_power = bfin_set_power; + musb->xceiv->set_power = bfin_set_power; musb->isr = blackfin_interrupt; diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c index 1976e9b41800..c3577bbbae6c 100644 --- a/drivers/usb/musb/cppi_dma.c +++ b/drivers/usb/musb/cppi_dma.c @@ -6,6 +6,7 @@ * The TUSB6020, using VLYNQ, has CPPI that looks much like DaVinci. */ +#include #include #include "musb_core.h" @@ -1145,17 +1146,27 @@ static bool cppi_rx_scan(struct cppi *cppi, unsigned ch) return completed; } -void cppi_completion(struct musb *musb, u32 rx, u32 tx) +irqreturn_t cppi_interrupt(int irq, void *dev_id) { - void __iomem *tibase; - int i, index; + struct musb *musb = dev_id; struct cppi *cppi; + void __iomem *tibase; struct musb_hw_ep *hw_ep = NULL; + u32 rx, tx; + int i, index; cppi = container_of(musb->dma_controller, struct cppi, controller); tibase = musb->ctrl_base; + tx = musb_readl(tibase, DAVINCI_TXCPPI_MASKED_REG); + rx = musb_readl(tibase, DAVINCI_RXCPPI_MASKED_REG); + + if (!tx && !rx) + return IRQ_NONE; + + DBG(4, "CPPI IRQ Tx%x Rx%x\n", tx, rx); + /* process TX channels */ for (index = 0; tx; tx = tx >> 1, index++) { struct cppi_channel *tx_ch; @@ -1273,6 +1284,8 @@ void cppi_completion(struct musb *musb, u32 rx, u32 tx) /* write to CPPI EOI register to re-enable interrupts */ musb_writel(tibase, DAVINCI_CPPI_EOI_REG, 0); + + return IRQ_HANDLED; } /* Instantiate a software object representing a DMA controller. */ @@ -1280,6 +1293,9 @@ struct dma_controller *__init dma_controller_create(struct musb *musb, void __iomem *mregs) { struct cppi *controller; + struct device *dev = musb->controller; + struct platform_device *pdev = to_platform_device(dev); + int irq = platform_get_irq(pdev, 1); controller = kzalloc(sizeof *controller, GFP_KERNEL); if (!controller) @@ -1310,6 +1326,15 @@ dma_controller_create(struct musb *musb, void __iomem *mregs) return NULL; } + if (irq > 0) { + if (request_irq(irq, cppi_interrupt, 0, "cppi-dma", musb)) { + dev_err(dev, "request_irq %d failed!\n", irq); + dma_controller_destroy(&controller->controller); + return NULL; + } + controller->irq = irq; + } + return &controller->controller; } @@ -1322,6 +1347,9 @@ void dma_controller_destroy(struct dma_controller *c) cppi = container_of(c, struct cppi, controller); + if (cppi->irq) + free_irq(cppi->irq, cppi->musb); + /* assert: caller stopped the controller first */ dma_pool_destroy(cppi->pool); diff --git a/drivers/usb/musb/cppi_dma.h b/drivers/usb/musb/cppi_dma.h index 729b4071787b..8a39de3e6e47 100644 --- a/drivers/usb/musb/cppi_dma.h +++ b/drivers/usb/musb/cppi_dma.h @@ -119,6 +119,8 @@ struct cppi { void __iomem *mregs; /* Mentor regs */ void __iomem *tibase; /* TI/CPPI regs */ + int irq; + struct cppi_channel tx[4]; struct cppi_channel rx[4]; @@ -127,7 +129,7 @@ struct cppi { struct list_head tx_complete; }; -/* irq handling hook */ -extern void cppi_completion(struct musb *, u32 rx, u32 tx); +/* CPPI IRQ handler */ +extern irqreturn_t cppi_interrupt(int, void *); #endif /* end of ifndef _CPPI_DMA_H_ */ diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c index 10d11ab113ab..180d7daa4099 100644 --- a/drivers/usb/musb/davinci.c +++ b/drivers/usb/musb/davinci.c @@ -215,7 +215,7 @@ static void otg_timer(unsigned long _musb) DBG(7, "poll devctl %02x (%s)\n", devctl, otg_state_string(musb)); spin_lock_irqsave(&musb->lock, flags); - switch (musb->xceiv.state) { + switch (musb->xceiv->state) { case OTG_STATE_A_WAIT_VFALL: /* Wait till VBUS falls below SessionEnd (~0.2V); the 1.3 RTL * seems to mis-handle session "start" otherwise (or in our @@ -226,7 +226,7 @@ static void otg_timer(unsigned long _musb) mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); break; } - musb->xceiv.state = OTG_STATE_A_WAIT_VRISE; + musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; musb_writel(musb->ctrl_base, DAVINCI_USB_INT_SET_REG, MUSB_INTR_VBUSERROR << DAVINCI_USB_USBINT_SHIFT); break; @@ -251,7 +251,7 @@ static void otg_timer(unsigned long _musb) if (devctl & MUSB_DEVCTL_BDEVICE) mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); else - musb->xceiv.state = OTG_STATE_A_IDLE; + musb->xceiv->state = OTG_STATE_A_IDLE; break; default: break; @@ -265,6 +265,7 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci) irqreturn_t retval = IRQ_NONE; struct musb *musb = __hci; void __iomem *tibase = musb->ctrl_base; + struct cppi *cppi; u32 tmp; spin_lock_irqsave(&musb->lock, flags); @@ -281,16 +282,9 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci) /* CPPI interrupts share the same IRQ line, but have their own * mask, state, "vector", and EOI registers. */ - if (is_cppi_enabled()) { - u32 cppi_tx = musb_readl(tibase, DAVINCI_TXCPPI_MASKED_REG); - u32 cppi_rx = musb_readl(tibase, DAVINCI_RXCPPI_MASKED_REG); - - if (cppi_tx || cppi_rx) { - DBG(4, "CPPI IRQ t%x r%x\n", cppi_tx, cppi_rx); - cppi_completion(musb, cppi_rx, cppi_tx); - retval = IRQ_HANDLED; - } - } + cppi = container_of(musb->dma_controller, struct cppi, controller); + if (is_cppi_enabled() && musb->dma_controller && !cppi->irq) + retval = cppi_interrupt(irq, __hci); /* ack and handle non-CPPI interrupts */ tmp = musb_readl(tibase, DAVINCI_USB_INT_SRC_MASKED_REG); @@ -331,21 +325,21 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci) * to stop registering in devctl. */ musb->int_usb &= ~MUSB_INTR_VBUSERROR; - musb->xceiv.state = OTG_STATE_A_WAIT_VFALL; + musb->xceiv->state = OTG_STATE_A_WAIT_VFALL; mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); WARNING("VBUS error workaround (delay coming)\n"); } else if (is_host_enabled(musb) && drvvbus) { musb->is_active = 1; MUSB_HST_MODE(musb); - musb->xceiv.default_a = 1; - musb->xceiv.state = OTG_STATE_A_WAIT_VRISE; + musb->xceiv->default_a = 1; + musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; portstate(musb->port1_status |= USB_PORT_STAT_POWER); del_timer(&otg_workaround); } else { musb->is_active = 0; MUSB_DEV_MODE(musb); - musb->xceiv.default_a = 0; - musb->xceiv.state = OTG_STATE_B_IDLE; + musb->xceiv->default_a = 0; + musb->xceiv->state = OTG_STATE_B_IDLE; portstate(musb->port1_status &= ~USB_PORT_STAT_POWER); } @@ -367,17 +361,12 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci) /* poll for ID change */ if (is_otg_enabled(musb) - && musb->xceiv.state == OTG_STATE_B_IDLE) + && musb->xceiv->state == OTG_STATE_B_IDLE) mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); spin_unlock_irqrestore(&musb->lock, flags); - /* REVISIT we sometimes get unhandled IRQs - * (e.g. ep0). not clear why... - */ - if (retval != IRQ_HANDLED) - DBG(5, "unhandled? %08x\n", tmp); - return IRQ_HANDLED; + return retval; } int musb_platform_set_mode(struct musb *musb, u8 mode) @@ -391,6 +380,11 @@ int __init musb_platform_init(struct musb *musb) void __iomem *tibase = musb->ctrl_base; u32 revision; + usb_nop_xceiv_register(); + musb->xceiv = otg_get_transceiver(); + if (!musb->xceiv) + return -ENODEV; + musb->mregs += DAVINCI_BASE_OFFSET; clk_enable(musb->clock); @@ -398,7 +392,7 @@ int __init musb_platform_init(struct musb *musb) /* returns zero if e.g. not clocked */ revision = musb_readl(tibase, DAVINCI_USB_VERSION_REG); if (revision == 0) - return -ENODEV; + goto fail; if (is_host_enabled(musb)) setup_timer(&otg_workaround, otg_timer, (unsigned long) musb); @@ -432,6 +426,10 @@ int __init musb_platform_init(struct musb *musb) musb->isr = davinci_interrupt; return 0; + +fail: + usb_nop_xceiv_unregister(); + return -ENODEV; } int musb_platform_exit(struct musb *musb) @@ -442,7 +440,7 @@ int musb_platform_exit(struct musb *musb) davinci_source_power(musb, 0 /*off*/, 1); /* delay, to avoid problems with module reload */ - if (is_host_enabled(musb) && musb->xceiv.default_a) { + if (is_host_enabled(musb) && musb->xceiv->default_a) { int maxdelay = 30; u8 devctl, warn = 0; @@ -471,5 +469,7 @@ int musb_platform_exit(struct musb *musb) clk_disable(musb->clock); + usb_nop_xceiv_unregister(); + return 0; } diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 4000cf6d1e81..554a414f65d1 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -112,6 +112,7 @@ #include "davinci.h" #endif +#define TA_WAIT_BCON(m) max_t(int, (m)->a_wait_bcon, OTG_TIME_A_WAIT_BCON) unsigned musb_debug; @@ -267,7 +268,7 @@ void musb_load_testpacket(struct musb *musb) const char *otg_state_string(struct musb *musb) { - switch (musb->xceiv.state) { + switch (musb->xceiv->state) { case OTG_STATE_A_IDLE: return "a_idle"; case OTG_STATE_A_WAIT_VRISE: return "a_wait_vrise"; case OTG_STATE_A_WAIT_BCON: return "a_wait_bcon"; @@ -287,12 +288,6 @@ const char *otg_state_string(struct musb *musb) #ifdef CONFIG_USB_MUSB_OTG -/* - * See also USB_OTG_1-3.pdf 6.6.5 Timers - * REVISIT: Are the other timers done in the hardware? - */ -#define TB_ASE0_BRST 100 /* Min 3.125 ms */ - /* * Handles OTG hnp timeouts, such as b_ase0_brst */ @@ -302,16 +297,18 @@ void musb_otg_timer_func(unsigned long data) unsigned long flags; spin_lock_irqsave(&musb->lock, flags); - switch (musb->xceiv.state) { + switch (musb->xceiv->state) { case OTG_STATE_B_WAIT_ACON: DBG(1, "HNP: b_wait_acon timeout; back to b_peripheral\n"); musb_g_disconnect(musb); - musb->xceiv.state = OTG_STATE_B_PERIPHERAL; + musb->xceiv->state = OTG_STATE_B_PERIPHERAL; musb->is_active = 0; break; + case OTG_STATE_A_SUSPEND: case OTG_STATE_A_WAIT_BCON: - DBG(1, "HNP: a_wait_bcon timeout; back to a_host\n"); - musb_hnp_stop(musb); + DBG(1, "HNP: %s timeout\n", otg_state_string(musb)); + musb_set_vbus(musb, 0); + musb->xceiv->state = OTG_STATE_A_WAIT_VFALL; break; default: DBG(1, "HNP: Unhandled mode %s\n", otg_state_string(musb)); @@ -320,10 +317,8 @@ void musb_otg_timer_func(unsigned long data) spin_unlock_irqrestore(&musb->lock, flags); } -static DEFINE_TIMER(musb_otg_timer, musb_otg_timer_func, 0, 0); - /* - * Stops the B-device HNP state. Caller must take care of locking. + * Stops the HNP transition. Caller must take care of locking. */ void musb_hnp_stop(struct musb *musb) { @@ -331,20 +326,17 @@ void musb_hnp_stop(struct musb *musb) void __iomem *mbase = musb->mregs; u8 reg; - switch (musb->xceiv.state) { + DBG(1, "HNP: stop from %s\n", otg_state_string(musb)); + + switch (musb->xceiv->state) { case OTG_STATE_A_PERIPHERAL: - case OTG_STATE_A_WAIT_VFALL: - case OTG_STATE_A_WAIT_BCON: - DBG(1, "HNP: Switching back to A-host\n"); musb_g_disconnect(musb); - musb->xceiv.state = OTG_STATE_A_IDLE; - MUSB_HST_MODE(musb); - musb->is_active = 0; + DBG(1, "HNP: back to %s\n", otg_state_string(musb)); break; case OTG_STATE_B_HOST: DBG(1, "HNP: Disabling HR\n"); hcd->self.is_b_host = 0; - musb->xceiv.state = OTG_STATE_B_PERIPHERAL; + musb->xceiv->state = OTG_STATE_B_PERIPHERAL; MUSB_DEV_MODE(musb); reg = musb_readb(mbase, MUSB_POWER); reg |= MUSB_POWER_SUSPENDM; @@ -402,7 +394,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, if (devctl & MUSB_DEVCTL_HM) { #ifdef CONFIG_USB_MUSB_HDRC_HCD - switch (musb->xceiv.state) { + switch (musb->xceiv->state) { case OTG_STATE_A_SUSPEND: /* remote wakeup? later, GetPortStatus * will stop RESUME signaling @@ -425,12 +417,12 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, musb->rh_timer = jiffies + msecs_to_jiffies(20); - musb->xceiv.state = OTG_STATE_A_HOST; + musb->xceiv->state = OTG_STATE_A_HOST; musb->is_active = 1; usb_hcd_resume_root_hub(musb_to_hcd(musb)); break; case OTG_STATE_B_WAIT_ACON: - musb->xceiv.state = OTG_STATE_B_PERIPHERAL; + musb->xceiv->state = OTG_STATE_B_PERIPHERAL; musb->is_active = 1; MUSB_DEV_MODE(musb); break; @@ -441,11 +433,11 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, } #endif } else { - switch (musb->xceiv.state) { + switch (musb->xceiv->state) { #ifdef CONFIG_USB_MUSB_HDRC_HCD case OTG_STATE_A_SUSPEND: /* possibly DISCONNECT is upcoming */ - musb->xceiv.state = OTG_STATE_A_HOST; + musb->xceiv->state = OTG_STATE_A_HOST; usb_hcd_resume_root_hub(musb_to_hcd(musb)); break; #endif @@ -490,7 +482,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, */ musb_writeb(mbase, MUSB_DEVCTL, MUSB_DEVCTL_SESSION); musb->ep0_stage = MUSB_EP0_START; - musb->xceiv.state = OTG_STATE_A_IDLE; + musb->xceiv->state = OTG_STATE_A_IDLE; MUSB_HST_MODE(musb); musb_set_vbus(musb, 1); @@ -516,7 +508,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, * REVISIT: do delays from lots of DEBUG_KERNEL checks * make trouble here, keeping VBUS < 4.4V ? */ - switch (musb->xceiv.state) { + switch (musb->xceiv->state) { case OTG_STATE_A_HOST: /* recovery is dicey once we've gotten past the * initial stages of enumeration, but if VBUS @@ -594,37 +586,40 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, if (devctl & MUSB_DEVCTL_LSDEV) musb->port1_status |= USB_PORT_STAT_LOW_SPEED; + /* indicate new connection to OTG machine */ + switch (musb->xceiv->state) { + case OTG_STATE_B_PERIPHERAL: + if (int_usb & MUSB_INTR_SUSPEND) { + DBG(1, "HNP: SUSPEND+CONNECT, now b_host\n"); + int_usb &= ~MUSB_INTR_SUSPEND; + goto b_host; + } else + DBG(1, "CONNECT as b_peripheral???\n"); + break; + case OTG_STATE_B_WAIT_ACON: + DBG(1, "HNP: CONNECT, now b_host\n"); +b_host: + musb->xceiv->state = OTG_STATE_B_HOST; + hcd->self.is_b_host = 1; + musb->ignore_disconnect = 0; + del_timer(&musb->otg_timer); + break; + default: + if ((devctl & MUSB_DEVCTL_VBUS) + == (3 << MUSB_DEVCTL_VBUS_SHIFT)) { + musb->xceiv->state = OTG_STATE_A_HOST; + hcd->self.is_b_host = 0; + } + break; + } + + /* poke the root hub */ + MUSB_HST_MODE(musb); if (hcd->status_urb) usb_hcd_poll_rh_status(hcd); else usb_hcd_resume_root_hub(hcd); - MUSB_HST_MODE(musb); - - /* indicate new connection to OTG machine */ - switch (musb->xceiv.state) { - case OTG_STATE_B_PERIPHERAL: - if (int_usb & MUSB_INTR_SUSPEND) { - DBG(1, "HNP: SUSPEND+CONNECT, now b_host\n"); - musb->xceiv.state = OTG_STATE_B_HOST; - hcd->self.is_b_host = 1; - int_usb &= ~MUSB_INTR_SUSPEND; - } else - DBG(1, "CONNECT as b_peripheral???\n"); - break; - case OTG_STATE_B_WAIT_ACON: - DBG(1, "HNP: Waiting to switch to b_host state\n"); - musb->xceiv.state = OTG_STATE_B_HOST; - hcd->self.is_b_host = 1; - break; - default: - if ((devctl & MUSB_DEVCTL_VBUS) - == (3 << MUSB_DEVCTL_VBUS_SHIFT)) { - musb->xceiv.state = OTG_STATE_A_HOST; - hcd->self.is_b_host = 0; - } - break; - } DBG(1, "CONNECT (%s) devctl %02x\n", otg_state_string(musb), devctl); } @@ -650,7 +645,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, } } else if (is_peripheral_capable()) { DBG(1, "BUS RESET as %s\n", otg_state_string(musb)); - switch (musb->xceiv.state) { + switch (musb->xceiv->state) { #ifdef CONFIG_USB_OTG case OTG_STATE_A_SUSPEND: /* We need to ignore disconnect on suspend @@ -661,24 +656,27 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, musb_g_reset(musb); /* FALLTHROUGH */ case OTG_STATE_A_WAIT_BCON: /* OPT TD.4.7-900ms */ - DBG(1, "HNP: Setting timer as %s\n", - otg_state_string(musb)); - musb_otg_timer.data = (unsigned long)musb; - mod_timer(&musb_otg_timer, jiffies - + msecs_to_jiffies(100)); + /* never use invalid T(a_wait_bcon) */ + DBG(1, "HNP: in %s, %d msec timeout\n", + otg_state_string(musb), + TA_WAIT_BCON(musb)); + mod_timer(&musb->otg_timer, jiffies + + msecs_to_jiffies(TA_WAIT_BCON(musb))); break; case OTG_STATE_A_PERIPHERAL: - musb_hnp_stop(musb); + musb->ignore_disconnect = 0; + del_timer(&musb->otg_timer); + musb_g_reset(musb); break; case OTG_STATE_B_WAIT_ACON: DBG(1, "HNP: RESET (%s), to b_peripheral\n", otg_state_string(musb)); - musb->xceiv.state = OTG_STATE_B_PERIPHERAL; + musb->xceiv->state = OTG_STATE_B_PERIPHERAL; musb_g_reset(musb); break; #endif case OTG_STATE_B_IDLE: - musb->xceiv.state = OTG_STATE_B_PERIPHERAL; + musb->xceiv->state = OTG_STATE_B_PERIPHERAL; /* FALLTHROUGH */ case OTG_STATE_B_PERIPHERAL: musb_g_reset(musb); @@ -763,7 +761,7 @@ static irqreturn_t musb_stage2_irq(struct musb *musb, u8 int_usb, MUSB_MODE(musb), devctl); handled = IRQ_HANDLED; - switch (musb->xceiv.state) { + switch (musb->xceiv->state) { #ifdef CONFIG_USB_MUSB_HDRC_HCD case OTG_STATE_A_HOST: case OTG_STATE_A_SUSPEND: @@ -776,7 +774,16 @@ static irqreturn_t musb_stage2_irq(struct musb *musb, u8 int_usb, #endif /* HOST */ #ifdef CONFIG_USB_MUSB_OTG case OTG_STATE_B_HOST: - musb_hnp_stop(musb); + /* REVISIT this behaves for "real disconnect" + * cases; make sure the other transitions from + * from B_HOST act right too. The B_HOST code + * in hnp_stop() is currently not used... + */ + musb_root_disconnect(musb); + musb_to_hcd(musb)->self.is_b_host = 0; + musb->xceiv->state = OTG_STATE_B_PERIPHERAL; + MUSB_DEV_MODE(musb); + musb_g_disconnect(musb); break; case OTG_STATE_A_PERIPHERAL: musb_hnp_stop(musb); @@ -805,26 +812,35 @@ static irqreturn_t musb_stage2_irq(struct musb *musb, u8 int_usb, otg_state_string(musb), devctl, power); handled = IRQ_HANDLED; - switch (musb->xceiv.state) { + switch (musb->xceiv->state) { #ifdef CONFIG_USB_MUSB_OTG case OTG_STATE_A_PERIPHERAL: - /* - * We cannot stop HNP here, devctl BDEVICE might be - * still set. + /* We also come here if the cable is removed, since + * this silicon doesn't report ID-no-longer-grounded. + * + * We depend on T(a_wait_bcon) to shut us down, and + * hope users don't do anything dicey during this + * undesired detour through A_WAIT_BCON. */ + musb_hnp_stop(musb); + usb_hcd_resume_root_hub(musb_to_hcd(musb)); + musb_root_disconnect(musb); + musb_platform_try_idle(musb, jiffies + + msecs_to_jiffies(musb->a_wait_bcon + ? : OTG_TIME_A_WAIT_BCON)); break; #endif case OTG_STATE_B_PERIPHERAL: musb_g_suspend(musb); musb->is_active = is_otg_enabled(musb) - && musb->xceiv.gadget->b_hnp_enable; + && musb->xceiv->gadget->b_hnp_enable; if (musb->is_active) { #ifdef CONFIG_USB_MUSB_OTG - musb->xceiv.state = OTG_STATE_B_WAIT_ACON; + musb->xceiv->state = OTG_STATE_B_WAIT_ACON; DBG(1, "HNP: Setting timer for b_ase0_brst\n"); - musb_otg_timer.data = (unsigned long)musb; - mod_timer(&musb_otg_timer, jiffies - + msecs_to_jiffies(TB_ASE0_BRST)); + mod_timer(&musb->otg_timer, jiffies + + msecs_to_jiffies( + OTG_TIME_B_ASE0_BRST)); #endif } break; @@ -834,9 +850,9 @@ static irqreturn_t musb_stage2_irq(struct musb *musb, u8 int_usb, + msecs_to_jiffies(musb->a_wait_bcon)); break; case OTG_STATE_A_HOST: - musb->xceiv.state = OTG_STATE_A_SUSPEND; + musb->xceiv->state = OTG_STATE_A_SUSPEND; musb->is_active = is_otg_enabled(musb) - && musb->xceiv.host->b_hnp_enable; + && musb->xceiv->host->b_hnp_enable; break; case OTG_STATE_B_HOST: /* Transition to B_PERIPHERAL, see 6.8.2.6 p 44 */ @@ -1068,14 +1084,13 @@ static struct fifo_cfg __initdata mode_4_cfg[] = { { .hw_ep_num = 8, .style = FIFO_RX, .maxpacket = 512, }, { .hw_ep_num = 9, .style = FIFO_TX, .maxpacket = 512, }, { .hw_ep_num = 9, .style = FIFO_RX, .maxpacket = 512, }, -{ .hw_ep_num = 10, .style = FIFO_TX, .maxpacket = 512, }, -{ .hw_ep_num = 10, .style = FIFO_RX, .maxpacket = 512, }, -{ .hw_ep_num = 11, .style = FIFO_TX, .maxpacket = 512, }, -{ .hw_ep_num = 11, .style = FIFO_RX, .maxpacket = 512, }, -{ .hw_ep_num = 12, .style = FIFO_TX, .maxpacket = 512, }, -{ .hw_ep_num = 12, .style = FIFO_RX, .maxpacket = 512, }, -{ .hw_ep_num = 13, .style = FIFO_TX, .maxpacket = 512, }, -{ .hw_ep_num = 13, .style = FIFO_RX, .maxpacket = 512, }, +{ .hw_ep_num = 10, .style = FIFO_TX, .maxpacket = 256, }, +{ .hw_ep_num = 10, .style = FIFO_RX, .maxpacket = 64, }, +{ .hw_ep_num = 11, .style = FIFO_TX, .maxpacket = 256, }, +{ .hw_ep_num = 11, .style = FIFO_RX, .maxpacket = 64, }, +{ .hw_ep_num = 12, .style = FIFO_TX, .maxpacket = 256, }, +{ .hw_ep_num = 12, .style = FIFO_RX, .maxpacket = 64, }, +{ .hw_ep_num = 13, .style = FIFO_RXTX, .maxpacket = 4096, }, { .hw_ep_num = 14, .style = FIFO_RXTX, .maxpacket = 1024, }, { .hw_ep_num = 15, .style = FIFO_RXTX, .maxpacket = 1024, }, }; @@ -1335,11 +1350,11 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb) } if (reg & MUSB_CONFIGDATA_HBRXE) { strcat(aInfo, ", HB-ISO Rx"); - strcat(aInfo, " (X)"); /* no driver support */ + musb->hb_iso_rx = true; } if (reg & MUSB_CONFIGDATA_HBTXE) { strcat(aInfo, ", HB-ISO Tx"); - strcat(aInfo, " (X)"); /* no driver support */ + musb->hb_iso_tx = true; } if (reg & MUSB_CONFIGDATA_SOFTCONE) strcat(aInfo, ", SoftConn"); @@ -1481,13 +1496,7 @@ static irqreturn_t generic_interrupt(int irq, void *__hci) spin_unlock_irqrestore(&musb->lock, flags); - /* REVISIT we sometimes get spurious IRQs on g_ep0 - * not clear why... - */ - if (retval != IRQ_HANDLED) - DBG(5, "spurious?\n"); - - return IRQ_HANDLED; + return retval; } #else @@ -1687,8 +1696,9 @@ musb_vbus_store(struct device *dev, struct device_attribute *attr, } spin_lock_irqsave(&musb->lock, flags); - musb->a_wait_bcon = val; - if (musb->xceiv.state == OTG_STATE_A_WAIT_BCON) + /* force T(a_wait_bcon) to be zero/unlimited *OR* valid */ + musb->a_wait_bcon = val ? max_t(int, val, OTG_TIME_A_WAIT_BCON) : 0 ; + if (musb->xceiv->state == OTG_STATE_A_WAIT_BCON) musb->is_active = 0; musb_platform_try_idle(musb, jiffies + msecs_to_jiffies(val)); spin_unlock_irqrestore(&musb->lock, flags); @@ -1706,10 +1716,13 @@ musb_vbus_show(struct device *dev, struct device_attribute *attr, char *buf) spin_lock_irqsave(&musb->lock, flags); val = musb->a_wait_bcon; + /* FIXME get_vbus_status() is normally #defined as false... + * and is effectively TUSB-specific. + */ vbus = musb_platform_get_vbus_status(musb); spin_unlock_irqrestore(&musb->lock, flags); - return sprintf(buf, "Vbus %s, timeout %lu\n", + return sprintf(buf, "Vbus %s, timeout %lu msec\n", vbus ? "on" : "off", val); } static DEVICE_ATTR(vbus, 0644, musb_vbus_show, musb_vbus_store); @@ -1749,8 +1762,8 @@ static void musb_irq_work(struct work_struct *data) struct musb *musb = container_of(data, struct musb, irq_work); static int old_state; - if (musb->xceiv.state != old_state) { - old_state = musb->xceiv.state; + if (musb->xceiv->state != old_state) { + old_state = musb->xceiv->state; sysfs_notify(&musb->controller->kobj, NULL, "mode"); } } @@ -1782,6 +1795,7 @@ allocate_instance(struct device *dev, hcd->uses_new_polling = 1; musb->vbuserr_retry = VBUSERR_RETRY_COUNT; + musb->a_wait_bcon = OTG_TIME_A_WAIT_BCON; #else musb = kzalloc(sizeof *musb, GFP_KERNEL); if (!musb) @@ -1847,7 +1861,7 @@ static void musb_free(struct musb *musb) } #ifdef CONFIG_USB_MUSB_OTG - put_device(musb->xceiv.dev); + put_device(musb->xceiv->dev); #endif #ifdef CONFIG_USB_MUSB_HDRC_HCD @@ -1928,10 +1942,18 @@ bad_config: } } - /* assume vbus is off */ - - /* platform adjusts musb->mregs and musb->isr if needed, - * and activates clocks + /* The musb_platform_init() call: + * - adjusts musb->mregs and musb->isr if needed, + * - may initialize an integrated tranceiver + * - initializes musb->xceiv, usually by otg_get_transceiver() + * - activates clocks. + * - stops powering VBUS + * - assigns musb->board_set_vbus if host mode is enabled + * + * There are various transciever configurations. Blackfin, + * DaVinci, TUSB60x0, and others integrate them. OMAP3 uses + * external/discrete ones in various flavors (twl4030 family, + * isp1504, non-OTG, etc) mostly hooking up through ULPI. */ musb->isr = generic_interrupt; status = musb_platform_init(musb); @@ -1968,6 +1990,10 @@ bad_config: if (status < 0) goto fail2; +#ifdef CONFIG_USB_OTG + setup_timer(&musb->otg_timer, musb_otg_timer_func, (unsigned long) musb); +#endif + /* Init IRQ workqueue before request_irq */ INIT_WORK(&musb->irq_work, musb_irq_work); @@ -1999,17 +2025,17 @@ bad_config: ? "DMA" : "PIO", musb->nIrq); -#ifdef CONFIG_USB_MUSB_HDRC_HCD - /* host side needs more setup, except for no-host modes */ - if (musb->board_mode != MUSB_PERIPHERAL) { + /* host side needs more setup */ + if (is_host_enabled(musb)) { struct usb_hcd *hcd = musb_to_hcd(musb); - if (musb->board_mode == MUSB_OTG) + otg_set_host(musb->xceiv, &hcd->self); + + if (is_otg_enabled(musb)) hcd->self.otg_port = 1; - musb->xceiv.host = &hcd->self; + musb->xceiv->host = &hcd->self; hcd->power_budget = 2 * (plat->power ? : 250); } -#endif /* CONFIG_USB_MUSB_HDRC_HCD */ /* For the host-only role, we can activate right away. * (We expect the ID pin to be forcibly grounded!!) @@ -2017,8 +2043,8 @@ bad_config: */ if (!is_otg_enabled(musb) && is_host_enabled(musb)) { MUSB_HST_MODE(musb); - musb->xceiv.default_a = 1; - musb->xceiv.state = OTG_STATE_A_IDLE; + musb->xceiv->default_a = 1; + musb->xceiv->state = OTG_STATE_A_IDLE; status = usb_add_hcd(musb_to_hcd(musb), -1, 0); if (status) @@ -2033,8 +2059,8 @@ bad_config: } else /* peripheral is enabled */ { MUSB_DEV_MODE(musb); - musb->xceiv.default_a = 0; - musb->xceiv.state = OTG_STATE_B_IDLE; + musb->xceiv->default_a = 0; + musb->xceiv->state = OTG_STATE_B_IDLE; status = musb_gadget_setup(musb); if (status) diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index efb39b5e55b5..f3772ca3b2cf 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -171,7 +172,8 @@ enum musb_h_ep0_state { /* peripheral side ep0 states */ enum musb_g_ep0_state { - MUSB_EP0_STAGE_SETUP, /* idle, waiting for setup */ + MUSB_EP0_STAGE_IDLE, /* idle, waiting for SETUP */ + MUSB_EP0_STAGE_SETUP, /* received SETUP */ MUSB_EP0_STAGE_TX, /* IN data */ MUSB_EP0_STAGE_RX, /* OUT data */ MUSB_EP0_STAGE_STATUSIN, /* (after OUT data) */ @@ -179,10 +181,15 @@ enum musb_g_ep0_state { MUSB_EP0_STAGE_ACKWAIT, /* after zlp, before statusin */ } __attribute__ ((packed)); -/* OTG protocol constants */ +/* + * OTG protocol constants. See USB OTG 1.3 spec, + * sections 5.5 "Device Timings" and 6.6.5 "Timers". + */ #define OTG_TIME_A_WAIT_VRISE 100 /* msec (max) */ -#define OTG_TIME_A_WAIT_BCON 0 /* 0=infinite; min 1000 msec */ -#define OTG_TIME_A_IDLE_BDIS 200 /* msec (min) */ +#define OTG_TIME_A_WAIT_BCON 1100 /* min 1 second */ +#define OTG_TIME_A_AIDL_BDIS 200 /* min 200 msec */ +#define OTG_TIME_B_ASE0_BRST 100 /* min 3.125 ms */ + /*************************** REGISTER ACCESS ********************************/ @@ -331,6 +338,8 @@ struct musb { struct list_head control; /* of musb_qh */ struct list_head in_bulk; /* of musb_qh */ struct list_head out_bulk; /* of musb_qh */ + + struct timer_list otg_timer; #endif /* called with IRQs blocked; ON/nonzero implies starting a session, @@ -355,7 +364,7 @@ struct musb { u16 int_rx; u16 int_tx; - struct otg_transceiver xceiv; + struct otg_transceiver *xceiv; int nIrq; unsigned irq_wake:1; @@ -386,6 +395,9 @@ struct musb { unsigned is_multipoint:1; unsigned ignore_disconnect:1; /* during bus resets */ + unsigned hb_iso_rx:1; /* high bandwidth iso rx? */ + unsigned hb_iso_tx:1; /* high bandwidth iso tx? */ + #ifdef C_MP_TX unsigned bulk_split:1; #define can_bulk_split(musb,type) \ diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index f79440cdfe7e..8b3c4e2ed7b8 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -310,7 +310,7 @@ static void txstate(struct musb *musb, struct musb_request *req) /* setup DMA, then program endpoint CSR */ request_size = min(request->length, musb_ep->dma->max_len); - if (request_size <= musb_ep->packet_sz) + if (request_size < musb_ep->packet_sz) musb_ep->dma->desired_mode = 0; else musb_ep->dma->desired_mode = 1; @@ -349,7 +349,8 @@ static void txstate(struct musb *musb, struct musb_request *req) #elif defined(CONFIG_USB_TI_CPPI_DMA) /* program endpoint CSR first, then setup DMA */ csr &= ~(MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_TXPKTRDY); - csr |= MUSB_TXCSR_MODE | MUSB_TXCSR_DMAENAB; + csr |= MUSB_TXCSR_DMAENAB | MUSB_TXCSR_DMAMODE | + MUSB_TXCSR_MODE; musb_writew(epio, MUSB_TXCSR, (MUSB_TXCSR_P_WZC_BITS & ~MUSB_TXCSR_P_UNDERRUN) | csr); @@ -1405,7 +1406,7 @@ static int musb_gadget_wakeup(struct usb_gadget *gadget) spin_lock_irqsave(&musb->lock, flags); - switch (musb->xceiv.state) { + switch (musb->xceiv->state) { case OTG_STATE_B_PERIPHERAL: /* NOTE: OTG state machine doesn't include B_SUSPENDED; * that's part of the standard usb 1.1 state machine, and @@ -1507,9 +1508,9 @@ static int musb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA) { struct musb *musb = gadget_to_musb(gadget); - if (!musb->xceiv.set_power) + if (!musb->xceiv->set_power) return -EOPNOTSUPP; - return otg_set_power(&musb->xceiv, mA); + return otg_set_power(musb->xceiv, mA); } static int musb_gadget_pullup(struct usb_gadget *gadget, int is_on) @@ -1732,11 +1733,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) spin_lock_irqsave(&musb->lock, flags); - /* REVISIT always use otg_set_peripheral(), handling - * issues including the root hub one below ... - */ - musb->xceiv.gadget = &musb->g; - musb->xceiv.state = OTG_STATE_B_IDLE; + otg_set_peripheral(musb->xceiv, &musb->g); musb->is_active = 1; /* FIXME this ignores the softconnect flag. Drivers are @@ -1748,6 +1745,8 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) if (!is_otg_enabled(musb)) musb_start(musb); + otg_set_peripheral(musb->xceiv, &musb->g); + spin_unlock_irqrestore(&musb->lock, flags); if (is_otg_enabled(musb)) { @@ -1761,8 +1760,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) if (retval < 0) { DBG(1, "add_hcd failed, %d\n", retval); spin_lock_irqsave(&musb->lock, flags); - musb->xceiv.gadget = NULL; - musb->xceiv.state = OTG_STATE_UNDEFINED; + otg_set_peripheral(musb->xceiv, NULL); musb->gadget_driver = NULL; musb->g.dev.driver = NULL; spin_unlock_irqrestore(&musb->lock, flags); @@ -1845,8 +1843,9 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) (void) musb_gadget_vbus_draw(&musb->g, 0); - musb->xceiv.state = OTG_STATE_UNDEFINED; + musb->xceiv->state = OTG_STATE_UNDEFINED; stop_activity(musb, driver); + otg_set_peripheral(musb->xceiv, NULL); DBG(3, "unregistering driver %s\n", driver->function); spin_unlock_irqrestore(&musb->lock, flags); @@ -1882,7 +1881,7 @@ EXPORT_SYMBOL(usb_gadget_unregister_driver); void musb_g_resume(struct musb *musb) { musb->is_suspended = 0; - switch (musb->xceiv.state) { + switch (musb->xceiv->state) { case OTG_STATE_B_IDLE: break; case OTG_STATE_B_WAIT_ACON: @@ -1908,10 +1907,10 @@ void musb_g_suspend(struct musb *musb) devctl = musb_readb(musb->mregs, MUSB_DEVCTL); DBG(3, "devctl %02x\n", devctl); - switch (musb->xceiv.state) { + switch (musb->xceiv->state) { case OTG_STATE_B_IDLE: if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) - musb->xceiv.state = OTG_STATE_B_PERIPHERAL; + musb->xceiv->state = OTG_STATE_B_PERIPHERAL; break; case OTG_STATE_B_PERIPHERAL: musb->is_suspended = 1; @@ -1957,22 +1956,24 @@ void musb_g_disconnect(struct musb *musb) spin_lock(&musb->lock); } - switch (musb->xceiv.state) { + switch (musb->xceiv->state) { default: #ifdef CONFIG_USB_MUSB_OTG DBG(2, "Unhandled disconnect %s, setting a_idle\n", otg_state_string(musb)); - musb->xceiv.state = OTG_STATE_A_IDLE; + musb->xceiv->state = OTG_STATE_A_IDLE; + MUSB_HST_MODE(musb); break; case OTG_STATE_A_PERIPHERAL: - musb->xceiv.state = OTG_STATE_A_WAIT_VFALL; + musb->xceiv->state = OTG_STATE_A_WAIT_BCON; + MUSB_HST_MODE(musb); break; case OTG_STATE_B_WAIT_ACON: case OTG_STATE_B_HOST: #endif case OTG_STATE_B_PERIPHERAL: case OTG_STATE_B_IDLE: - musb->xceiv.state = OTG_STATE_B_IDLE; + musb->xceiv->state = OTG_STATE_B_IDLE; break; case OTG_STATE_B_SRP_INIT: break; @@ -2028,10 +2029,10 @@ __acquires(musb->lock) * or else after HNP, as A-Device */ if (devctl & MUSB_DEVCTL_BDEVICE) { - musb->xceiv.state = OTG_STATE_B_PERIPHERAL; + musb->xceiv->state = OTG_STATE_B_PERIPHERAL; musb->g.is_a_peripheral = 0; } else if (is_otg_enabled(musb)) { - musb->xceiv.state = OTG_STATE_A_PERIPHERAL; + musb->xceiv->state = OTG_STATE_A_PERIPHERAL; musb->g.is_a_peripheral = 1; } else WARN_ON(1); diff --git a/drivers/usb/musb/musb_gadget_ep0.c b/drivers/usb/musb/musb_gadget_ep0.c index 3f5e30ddfa27..40ed50ecedff 100644 --- a/drivers/usb/musb/musb_gadget_ep0.c +++ b/drivers/usb/musb/musb_gadget_ep0.c @@ -4,6 +4,7 @@ * Copyright 2005 Mentor Graphics Corporation * Copyright (C) 2005-2006 by Texas Instruments * Copyright (C) 2006-2007 Nokia Corporation + * Copyright (C) 2008-2009 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 @@ -58,7 +59,8 @@ static char *decode_ep0stage(u8 stage) { switch (stage) { - case MUSB_EP0_STAGE_SETUP: return "idle"; + case MUSB_EP0_STAGE_IDLE: return "idle"; + case MUSB_EP0_STAGE_SETUP: return "setup"; case MUSB_EP0_STAGE_TX: return "in"; case MUSB_EP0_STAGE_RX: return "out"; case MUSB_EP0_STAGE_ACKWAIT: return "wait"; @@ -628,7 +630,7 @@ irqreturn_t musb_g_ep0_irq(struct musb *musb) musb_writew(regs, MUSB_CSR0, csr & ~MUSB_CSR0_P_SENTSTALL); retval = IRQ_HANDLED; - musb->ep0_state = MUSB_EP0_STAGE_SETUP; + musb->ep0_state = MUSB_EP0_STAGE_IDLE; csr = musb_readw(regs, MUSB_CSR0); } @@ -636,7 +638,18 @@ irqreturn_t musb_g_ep0_irq(struct musb *musb) if (csr & MUSB_CSR0_P_SETUPEND) { musb_writew(regs, MUSB_CSR0, MUSB_CSR0_P_SVDSETUPEND); retval = IRQ_HANDLED; - musb->ep0_state = MUSB_EP0_STAGE_SETUP; + /* Transition into the early status phase */ + switch (musb->ep0_state) { + case MUSB_EP0_STAGE_TX: + musb->ep0_state = MUSB_EP0_STAGE_STATUSOUT; + break; + case MUSB_EP0_STAGE_RX: + musb->ep0_state = MUSB_EP0_STAGE_STATUSIN; + break; + default: + ERR("SetupEnd came in a wrong ep0stage %s", + decode_ep0stage(musb->ep0_state)); + } csr = musb_readw(regs, MUSB_CSR0); /* NOTE: request may need completion */ } @@ -697,11 +710,31 @@ irqreturn_t musb_g_ep0_irq(struct musb *musb) if (req) musb_g_ep0_giveback(musb, req); } + + /* + * In case when several interrupts can get coalesced, + * check to see if we've already received a SETUP packet... + */ + if (csr & MUSB_CSR0_RXPKTRDY) + goto setup; + + retval = IRQ_HANDLED; + musb->ep0_state = MUSB_EP0_STAGE_IDLE; + break; + + case MUSB_EP0_STAGE_IDLE: + /* + * This state is typically (but not always) indiscernible + * from the status states since the corresponding interrupts + * tend to happen within too little period of time (with only + * a zero-length packet in between) and so get coalesced... + */ retval = IRQ_HANDLED; musb->ep0_state = MUSB_EP0_STAGE_SETUP; /* FALLTHROUGH */ case MUSB_EP0_STAGE_SETUP: +setup: if (csr & MUSB_CSR0_RXPKTRDY) { struct usb_ctrlrequest setup; int handled = 0; @@ -783,7 +816,7 @@ irqreturn_t musb_g_ep0_irq(struct musb *musb) stall: DBG(3, "stall (%d)\n", handled); musb->ackpend |= MUSB_CSR0_P_SENDSTALL; - musb->ep0_state = MUSB_EP0_STAGE_SETUP; + musb->ep0_state = MUSB_EP0_STAGE_IDLE; finish: musb_writew(regs, MUSB_CSR0, musb->ackpend); @@ -803,7 +836,7 @@ finish: /* "can't happen" */ WARN_ON(1); musb_writew(regs, MUSB_CSR0, MUSB_CSR0_P_SENDSTALL); - musb->ep0_state = MUSB_EP0_STAGE_SETUP; + musb->ep0_state = MUSB_EP0_STAGE_IDLE; break; } @@ -959,7 +992,7 @@ static int musb_g_ep0_halt(struct usb_ep *e, int value) csr |= MUSB_CSR0_P_SENDSTALL; musb_writew(regs, MUSB_CSR0, csr); - musb->ep0_state = MUSB_EP0_STAGE_SETUP; + musb->ep0_state = MUSB_EP0_STAGE_IDLE; musb->ackpend = 0; break; default: diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index db1b57415ec7..94a2a350a414 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -181,6 +181,19 @@ static inline void musb_h_tx_dma_start(struct musb_hw_ep *ep) musb_writew(ep->regs, MUSB_TXCSR, txcsr); } +static void musb_ep_set_qh(struct musb_hw_ep *ep, int is_in, struct musb_qh *qh) +{ + if (is_in != 0 || ep->is_shared_fifo) + ep->in_qh = qh; + if (is_in == 0 || ep->is_shared_fifo) + ep->out_qh = qh; +} + +static struct musb_qh *musb_ep_get_qh(struct musb_hw_ep *ep, int is_in) +{ + return is_in ? ep->in_qh : ep->out_qh; +} + /* * Start the URB at the front of an endpoint's queue * end must be claimed from the caller. @@ -210,7 +223,6 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh) case USB_ENDPOINT_XFER_CONTROL: /* control transfers always start with SETUP */ is_in = 0; - hw_ep->out_qh = qh; musb->ep0_stage = MUSB_EP0_START; buf = urb->setup_packet; len = 8; @@ -239,10 +251,7 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh) epnum, buf + offset, len); /* Configure endpoint */ - if (is_in || hw_ep->is_shared_fifo) - hw_ep->in_qh = qh; - else - hw_ep->out_qh = qh; + musb_ep_set_qh(hw_ep, is_in, qh); musb_ep_program(musb, epnum, urb, !is_in, buf, offset, len); /* transmit may have more work: start it when it is time */ @@ -286,9 +295,8 @@ start: } } -/* caller owns controller lock, irqs are blocked */ -static void -__musb_giveback(struct musb *musb, struct urb *urb, int status) +/* Context: caller owns controller lock, IRQs are blocked */ +static void musb_giveback(struct musb *musb, struct urb *urb, int status) __releases(musb->lock) __acquires(musb->lock) { @@ -321,60 +329,57 @@ __acquires(musb->lock) spin_lock(&musb->lock); } -/* for bulk/interrupt endpoints only */ -static inline void -musb_save_toggle(struct musb_hw_ep *ep, int is_in, struct urb *urb) +/* For bulk/interrupt endpoints only */ +static inline void musb_save_toggle(struct musb_qh *qh, int is_in, + struct urb *urb) { - struct usb_device *udev = urb->dev; + void __iomem *epio = qh->hw_ep->regs; u16 csr; - void __iomem *epio = ep->regs; - struct musb_qh *qh; - /* FIXME: the current Mentor DMA code seems to have + /* + * FIXME: the current Mentor DMA code seems to have * problems getting toggle correct. */ - if (is_in || ep->is_shared_fifo) - qh = ep->in_qh; + if (is_in) + csr = musb_readw(epio, MUSB_RXCSR) & MUSB_RXCSR_H_DATATOGGLE; else - qh = ep->out_qh; + csr = musb_readw(epio, MUSB_TXCSR) & MUSB_TXCSR_H_DATATOGGLE; - if (!is_in) { - csr = musb_readw(epio, MUSB_TXCSR); - usb_settoggle(udev, qh->epnum, 1, - (csr & MUSB_TXCSR_H_DATATOGGLE) - ? 1 : 0); - } else { - csr = musb_readw(epio, MUSB_RXCSR); - usb_settoggle(udev, qh->epnum, 0, - (csr & MUSB_RXCSR_H_DATATOGGLE) - ? 1 : 0); - } + usb_settoggle(urb->dev, qh->epnum, !is_in, csr ? 1 : 0); } -/* caller owns controller lock, irqs are blocked */ -static struct musb_qh * -musb_giveback(struct musb_qh *qh, struct urb *urb, int status) +/* + * Advance this hardware endpoint's queue, completing the specified URB and + * advancing to either the next URB queued to that qh, or else invalidating + * that qh and advancing to the next qh scheduled after the current one. + * + * Context: caller owns controller lock, IRQs are blocked + */ +static void musb_advance_schedule(struct musb *musb, struct urb *urb, + struct musb_hw_ep *hw_ep, int is_in) { + struct musb_qh *qh = musb_ep_get_qh(hw_ep, is_in); struct musb_hw_ep *ep = qh->hw_ep; - struct musb *musb = ep->musb; - int is_in = usb_pipein(urb->pipe); int ready = qh->is_ready; + int status; + + status = (urb->status == -EINPROGRESS) ? 0 : urb->status; /* save toggle eagerly, for paranoia */ switch (qh->type) { case USB_ENDPOINT_XFER_BULK: case USB_ENDPOINT_XFER_INT: - musb_save_toggle(ep, is_in, urb); + musb_save_toggle(qh, is_in, urb); break; case USB_ENDPOINT_XFER_ISOC: - if (status == 0 && urb->error_count) + if (urb->error_count) status = -EXDEV; break; } qh->is_ready = 0; - __musb_giveback(musb, urb, status); + musb_giveback(musb, urb, status); qh->is_ready = ready; /* reclaim resources (and bandwidth) ASAP; deschedule it, and @@ -388,11 +393,8 @@ musb_giveback(struct musb_qh *qh, struct urb *urb, int status) else ep->tx_reinit = 1; - /* clobber old pointers to this qh */ - if (is_in || ep->is_shared_fifo) - ep->in_qh = NULL; - else - ep->out_qh = NULL; + /* Clobber old pointers to this qh */ + musb_ep_set_qh(ep, is_in, NULL); qh->hep->hcpriv = NULL; switch (qh->type) { @@ -421,36 +423,10 @@ musb_giveback(struct musb_qh *qh, struct urb *urb, int status) break; } } - return qh; -} - -/* - * Advance this hardware endpoint's queue, completing the specified urb and - * advancing to either the next urb queued to that qh, or else invalidating - * that qh and advancing to the next qh scheduled after the current one. - * - * Context: caller owns controller lock, irqs are blocked - */ -static void -musb_advance_schedule(struct musb *musb, struct urb *urb, - struct musb_hw_ep *hw_ep, int is_in) -{ - struct musb_qh *qh; - - if (is_in || hw_ep->is_shared_fifo) - qh = hw_ep->in_qh; - else - qh = hw_ep->out_qh; - - if (urb->status == -EINPROGRESS) - qh = musb_giveback(qh, urb, 0); - else - qh = musb_giveback(qh, urb, urb->status); if (qh != NULL && qh->is_ready) { DBG(4, "... next ep%d %cX urb %p\n", - hw_ep->epnum, is_in ? 'R' : 'T', - next_urb(qh)); + hw_ep->epnum, is_in ? 'R' : 'T', next_urb(qh)); musb_start_urb(musb, is_in, qh); } } @@ -629,7 +605,8 @@ musb_rx_reinit(struct musb *musb, struct musb_qh *qh, struct musb_hw_ep *ep) musb_writeb(ep->regs, MUSB_RXTYPE, qh->type_reg); musb_writeb(ep->regs, MUSB_RXINTERVAL, qh->intv_reg); /* NOTE: bulk combining rewrites high bits of maxpacket */ - musb_writew(ep->regs, MUSB_RXMAXP, qh->maxpacket); + musb_writew(ep->regs, MUSB_RXMAXP, + qh->maxpacket | ((qh->hb_mult - 1) << 11)); ep->rx_reinit = 0; } @@ -651,9 +628,10 @@ static bool musb_tx_dma_program(struct dma_controller *dma, csr = musb_readw(epio, MUSB_TXCSR); if (length > pkt_size) { mode = 1; - csr |= MUSB_TXCSR_AUTOSET - | MUSB_TXCSR_DMAMODE - | MUSB_TXCSR_DMAENAB; + csr |= MUSB_TXCSR_DMAMODE | MUSB_TXCSR_DMAENAB; + /* autoset shouldn't be set in high bandwidth */ + if (qh->hb_mult == 1) + csr |= MUSB_TXCSR_AUTOSET; } else { mode = 0; csr &= ~(MUSB_TXCSR_AUTOSET | MUSB_TXCSR_DMAMODE); @@ -703,15 +681,8 @@ static void musb_ep_program(struct musb *musb, u8 epnum, void __iomem *mbase = musb->mregs; struct musb_hw_ep *hw_ep = musb->endpoints + epnum; void __iomem *epio = hw_ep->regs; - struct musb_qh *qh; - u16 packet_sz; - - if (!is_out || hw_ep->is_shared_fifo) - qh = hw_ep->in_qh; - else - qh = hw_ep->out_qh; - - packet_sz = qh->maxpacket; + struct musb_qh *qh = musb_ep_get_qh(hw_ep, !is_out); + u16 packet_sz = qh->maxpacket; DBG(3, "%s hw%d urb %p spd%d dev%d ep%d%s " "h_addr%02x h_port%02x bytes %d\n", @@ -1129,17 +1100,14 @@ void musb_host_tx(struct musb *musb, u8 epnum) u16 tx_csr; size_t length = 0; size_t offset = 0; - struct urb *urb; struct musb_hw_ep *hw_ep = musb->endpoints + epnum; void __iomem *epio = hw_ep->regs; - struct musb_qh *qh = hw_ep->is_shared_fifo ? hw_ep->in_qh - : hw_ep->out_qh; + struct musb_qh *qh = hw_ep->out_qh; + struct urb *urb = next_urb(qh); u32 status = 0; void __iomem *mbase = musb->mregs; struct dma_channel *dma; - urb = next_urb(qh); - musb_ep_select(mbase, epnum); tx_csr = musb_readw(epio, MUSB_TXCSR); @@ -1427,7 +1395,7 @@ static void musb_bulk_rx_nak_timeout(struct musb *musb, struct musb_hw_ep *ep) urb->actual_length += dma->actual_len; dma->actual_len = 0L; } - musb_save_toggle(ep, 1, urb); + musb_save_toggle(cur_qh, 1, urb); /* move cur_qh to end of queue */ list_move_tail(&cur_qh->ring, &musb->in_bulk); @@ -1531,6 +1499,10 @@ void musb_host_rx(struct musb *musb, u8 epnum) /* packet error reported later */ iso_err = true; } + } else if (rx_csr & MUSB_RXCSR_INCOMPRX) { + DBG(3, "end %d high bandwidth incomplete ISO packet RX\n", + epnum); + status = -EPROTO; } /* faults abort the transfer */ @@ -1738,7 +1710,11 @@ void musb_host_rx(struct musb *musb, u8 epnum) val &= ~MUSB_RXCSR_H_AUTOREQ; else val |= MUSB_RXCSR_H_AUTOREQ; - val |= MUSB_RXCSR_AUTOCLEAR | MUSB_RXCSR_DMAENAB; + val |= MUSB_RXCSR_DMAENAB; + + /* autoclear shouldn't be set in high bandwidth */ + if (qh->hb_mult == 1) + val |= MUSB_RXCSR_AUTOCLEAR; musb_writew(epio, MUSB_RXCSR, MUSB_RXCSR_H_WZC_BITS | val); @@ -1817,19 +1793,17 @@ static int musb_schedule( epnum++, hw_ep++) { int diff; - if (is_in || hw_ep->is_shared_fifo) { - if (hw_ep->in_qh != NULL) - continue; - } else if (hw_ep->out_qh != NULL) + if (musb_ep_get_qh(hw_ep, is_in) != NULL) continue; if (hw_ep == musb->bulk_ep) continue; if (is_in) - diff = hw_ep->max_packet_sz_rx - qh->maxpacket; + diff = hw_ep->max_packet_sz_rx; else - diff = hw_ep->max_packet_sz_tx - qh->maxpacket; + diff = hw_ep->max_packet_sz_tx; + diff -= (qh->maxpacket * qh->hb_mult); if (diff >= 0 && best_diff > diff) { best_diff = diff; @@ -1932,15 +1906,27 @@ static int musb_urb_enqueue( qh->is_ready = 1; qh->maxpacket = le16_to_cpu(epd->wMaxPacketSize); + qh->type = usb_endpoint_type(epd); - /* no high bandwidth support yet */ - if (qh->maxpacket & ~0x7ff) { - ret = -EMSGSIZE; - goto done; + /* Bits 11 & 12 of wMaxPacketSize encode high bandwidth multiplier. + * Some musb cores don't support high bandwidth ISO transfers; and + * we don't (yet!) support high bandwidth interrupt transfers. + */ + qh->hb_mult = 1 + ((qh->maxpacket >> 11) & 0x03); + if (qh->hb_mult > 1) { + int ok = (qh->type == USB_ENDPOINT_XFER_ISOC); + + if (ok) + ok = (usb_pipein(urb->pipe) && musb->hb_iso_rx) + || (usb_pipeout(urb->pipe) && musb->hb_iso_tx); + if (!ok) { + ret = -EMSGSIZE; + goto done; + } + qh->maxpacket &= 0x7ff; } qh->epnum = usb_endpoint_num(epd); - qh->type = usb_endpoint_type(epd); /* NOTE: urb->dev->devnum is wrong during SET_ADDRESS */ qh->addr_reg = (u8) usb_pipedevice(urb->pipe); @@ -2052,14 +2038,15 @@ done: * called with controller locked, irqs blocked * that hardware queue advances to the next transfer, unless prevented */ -static int musb_cleanup_urb(struct urb *urb, struct musb_qh *qh, int is_in) +static int musb_cleanup_urb(struct urb *urb, struct musb_qh *qh) { struct musb_hw_ep *ep = qh->hw_ep; void __iomem *epio = ep->regs; unsigned hw_end = ep->epnum; void __iomem *regs = ep->musb->mregs; - u16 csr; + int is_in = usb_pipein(urb->pipe); int status = 0; + u16 csr; musb_ep_select(regs, hw_end); @@ -2112,14 +2099,14 @@ static int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) { struct musb *musb = hcd_to_musb(hcd); struct musb_qh *qh; - struct list_head *sched; unsigned long flags; + int is_in = usb_pipein(urb->pipe); int ret; DBG(4, "urb=%p, dev%d ep%d%s\n", urb, usb_pipedevice(urb->pipe), usb_pipeendpoint(urb->pipe), - usb_pipein(urb->pipe) ? "in" : "out"); + is_in ? "in" : "out"); spin_lock_irqsave(&musb->lock, flags); ret = usb_hcd_check_unlink_urb(hcd, urb, status); @@ -2130,47 +2117,25 @@ static int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) if (!qh) goto done; - /* Any URB not actively programmed into endpoint hardware can be + /* + * Any URB not actively programmed into endpoint hardware can be * immediately given back; that's any URB not at the head of an * endpoint queue, unless someday we get real DMA queues. And even * if it's at the head, it might not be known to the hardware... * - * Otherwise abort current transfer, pending dma, etc.; urb->status + * Otherwise abort current transfer, pending DMA, etc.; urb->status * has already been updated. This is a synchronous abort; it'd be * OK to hold off until after some IRQ, though. + * + * NOTE: qh is invalid unless !list_empty(&hep->urb_list) */ - if (!qh->is_ready || urb->urb_list.prev != &qh->hep->urb_list) - ret = -EINPROGRESS; - else { - switch (qh->type) { - case USB_ENDPOINT_XFER_CONTROL: - sched = &musb->control; - break; - case USB_ENDPOINT_XFER_BULK: - if (qh->mux == 1) { - if (usb_pipein(urb->pipe)) - sched = &musb->in_bulk; - else - sched = &musb->out_bulk; - break; - } - default: - /* REVISIT when we get a schedule tree, periodic - * transfers won't always be at the head of a - * singleton queue... - */ - sched = NULL; - break; - } - } - - /* NOTE: qh is invalid unless !list_empty(&hep->urb_list) */ - if (ret < 0 || (sched && qh != first_qh(sched))) { + if (!qh->is_ready + || urb->urb_list.prev != &qh->hep->urb_list + || musb_ep_get_qh(qh->hw_ep, is_in) != qh) { int ready = qh->is_ready; - ret = 0; qh->is_ready = 0; - __musb_giveback(musb, urb, 0); + musb_giveback(musb, urb, 0); qh->is_ready = ready; /* If nothing else (usually musb_giveback) is using it @@ -2182,7 +2147,7 @@ static int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) kfree(qh); } } else - ret = musb_cleanup_urb(urb, qh, urb->pipe & USB_DIR_IN); + ret = musb_cleanup_urb(urb, qh); done: spin_unlock_irqrestore(&musb->lock, flags); return ret; @@ -2192,13 +2157,11 @@ done: static void musb_h_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep) { - u8 epnum = hep->desc.bEndpointAddress; + u8 is_in = hep->desc.bEndpointAddress & USB_DIR_IN; unsigned long flags; struct musb *musb = hcd_to_musb(hcd); - u8 is_in = epnum & USB_DIR_IN; struct musb_qh *qh; struct urb *urb; - struct list_head *sched; spin_lock_irqsave(&musb->lock, flags); @@ -2206,31 +2169,11 @@ musb_h_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep) if (qh == NULL) goto exit; - switch (qh->type) { - case USB_ENDPOINT_XFER_CONTROL: - sched = &musb->control; - break; - case USB_ENDPOINT_XFER_BULK: - if (qh->mux == 1) { - if (is_in) - sched = &musb->in_bulk; - else - sched = &musb->out_bulk; - break; - } - default: - /* REVISIT when we get a schedule tree, periodic transfers - * won't always be at the head of a singleton queue... - */ - sched = NULL; - break; - } + /* NOTE: qh is invalid unless !list_empty(&hep->urb_list) */ - /* NOTE: qh is invalid unless !list_empty(&hep->urb_list) */ - - /* kick first urb off the hardware, if needed */ + /* Kick the first URB off the hardware, if needed */ qh->is_ready = 0; - if (!sched || qh == first_qh(sched)) { + if (musb_ep_get_qh(qh->hw_ep, is_in) == qh) { urb = next_urb(qh); /* make software (then hardware) stop ASAP */ @@ -2238,7 +2181,7 @@ musb_h_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep) urb->status = -ESHUTDOWN; /* cleanup */ - musb_cleanup_urb(urb, qh, urb->pipe & USB_DIR_IN); + musb_cleanup_urb(urb, qh); /* Then nuke all the others ... and advance the * queue on hw_ep (e.g. bulk ring) when we're done. @@ -2254,7 +2197,7 @@ musb_h_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep) * will activate any of these as it advances. */ while (!list_empty(&hep->urb_list)) - __musb_giveback(musb, next_urb(qh), -ESHUTDOWN); + musb_giveback(musb, next_urb(qh), -ESHUTDOWN); hep->hcpriv = NULL; list_del(&qh->ring); @@ -2293,7 +2236,7 @@ static int musb_bus_suspend(struct usb_hcd *hcd) { struct musb *musb = hcd_to_musb(hcd); - if (musb->xceiv.state == OTG_STATE_A_SUSPEND) + if (musb->xceiv->state == OTG_STATE_A_SUSPEND) return 0; if (is_host_active(musb) && musb->is_active) { diff --git a/drivers/usb/musb/musb_host.h b/drivers/usb/musb/musb_host.h index 0b7fbcd21963..14b00776638d 100644 --- a/drivers/usb/musb/musb_host.h +++ b/drivers/usb/musb/musb_host.h @@ -67,6 +67,7 @@ struct musb_qh { u8 is_ready; /* safe to modify hw_ep */ u8 type; /* XFERTYPE_* */ u8 epnum; + u8 hb_mult; /* high bandwidth pkts per uf */ u16 maxpacket; u16 frame; /* for periodic schedule */ unsigned iso_idx; /* in urb->iso_frame_desc[] */ diff --git a/drivers/usb/musb/musb_virthub.c b/drivers/usb/musb/musb_virthub.c index bf677acc83db..bfe5fe4ebfee 100644 --- a/drivers/usb/musb/musb_virthub.c +++ b/drivers/usb/musb/musb_virthub.c @@ -78,18 +78,22 @@ static void musb_port_suspend(struct musb *musb, bool do_suspend) DBG(3, "Root port suspended, power %02x\n", power); musb->port1_status |= USB_PORT_STAT_SUSPEND; - switch (musb->xceiv.state) { + switch (musb->xceiv->state) { case OTG_STATE_A_HOST: - musb->xceiv.state = OTG_STATE_A_SUSPEND; + musb->xceiv->state = OTG_STATE_A_SUSPEND; musb->is_active = is_otg_enabled(musb) - && musb->xceiv.host->b_hnp_enable; + && musb->xceiv->host->b_hnp_enable; + if (musb->is_active) + mod_timer(&musb->otg_timer, jiffies + + msecs_to_jiffies( + OTG_TIME_A_AIDL_BDIS)); musb_platform_try_idle(musb, 0); break; #ifdef CONFIG_USB_MUSB_OTG case OTG_STATE_B_HOST: - musb->xceiv.state = OTG_STATE_B_WAIT_ACON; + musb->xceiv->state = OTG_STATE_B_WAIT_ACON; musb->is_active = is_otg_enabled(musb) - && musb->xceiv.host->b_hnp_enable; + && musb->xceiv->host->b_hnp_enable; musb_platform_try_idle(musb, 0); break; #endif @@ -116,7 +120,7 @@ static void musb_port_reset(struct musb *musb, bool do_reset) void __iomem *mbase = musb->mregs; #ifdef CONFIG_USB_MUSB_OTG - if (musb->xceiv.state == OTG_STATE_B_IDLE) { + if (musb->xceiv->state == OTG_STATE_B_IDLE) { DBG(2, "HNP: Returning from HNP; no hub reset from b_idle\n"); musb->port1_status &= ~USB_PORT_STAT_RESET; return; @@ -186,14 +190,23 @@ void musb_root_disconnect(struct musb *musb) usb_hcd_poll_rh_status(musb_to_hcd(musb)); musb->is_active = 0; - switch (musb->xceiv.state) { - case OTG_STATE_A_HOST: + switch (musb->xceiv->state) { case OTG_STATE_A_SUSPEND: - musb->xceiv.state = OTG_STATE_A_WAIT_BCON; +#ifdef CONFIG_USB_MUSB_OTG + if (is_otg_enabled(musb) + && musb->xceiv->host->b_hnp_enable) { + musb->xceiv->state = OTG_STATE_A_PERIPHERAL; + musb->g.is_a_peripheral = 1; + break; + } +#endif + /* FALLTHROUGH */ + case OTG_STATE_A_HOST: + musb->xceiv->state = OTG_STATE_A_WAIT_BCON; musb->is_active = 0; break; case OTG_STATE_A_WAIT_VFALL: - musb->xceiv.state = OTG_STATE_B_IDLE; + musb->xceiv->state = OTG_STATE_B_IDLE; break; default: DBG(1, "host disconnect (%s)\n", otg_state_string(musb)); @@ -332,7 +345,7 @@ int musb_hub_control( musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16; usb_hcd_poll_rh_status(musb_to_hcd(musb)); /* NOTE: it might really be A_WAIT_BCON ... */ - musb->xceiv.state = OTG_STATE_A_HOST; + musb->xceiv->state = OTG_STATE_A_HOST; } put_unaligned(cpu_to_le32(musb->port1_status diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index 60924ce08493..34875201ee04 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -44,7 +44,6 @@ #define get_cpu_rev() 2 #endif -#define MUSB_TIMEOUT_A_WAIT_BCON 1100 static struct timer_list musb_idle_timer; @@ -61,17 +60,17 @@ static void musb_do_idle(unsigned long _musb) devctl = musb_readb(musb->mregs, MUSB_DEVCTL); - switch (musb->xceiv.state) { + switch (musb->xceiv->state) { case OTG_STATE_A_WAIT_BCON: devctl &= ~MUSB_DEVCTL_SESSION; musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); devctl = musb_readb(musb->mregs, MUSB_DEVCTL); if (devctl & MUSB_DEVCTL_BDEVICE) { - musb->xceiv.state = OTG_STATE_B_IDLE; + musb->xceiv->state = OTG_STATE_B_IDLE; MUSB_DEV_MODE(musb); } else { - musb->xceiv.state = OTG_STATE_A_IDLE; + musb->xceiv->state = OTG_STATE_A_IDLE; MUSB_HST_MODE(musb); } break; @@ -89,7 +88,7 @@ static void musb_do_idle(unsigned long _musb) musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16; usb_hcd_poll_rh_status(musb_to_hcd(musb)); /* NOTE: it might really be A_WAIT_BCON ... */ - musb->xceiv.state = OTG_STATE_A_HOST; + musb->xceiv->state = OTG_STATE_A_HOST; } break; #endif @@ -97,9 +96,9 @@ static void musb_do_idle(unsigned long _musb) case OTG_STATE_A_HOST: devctl = musb_readb(musb->mregs, MUSB_DEVCTL); if (devctl & MUSB_DEVCTL_BDEVICE) - musb->xceiv.state = OTG_STATE_B_IDLE; + musb->xceiv->state = OTG_STATE_B_IDLE; else - musb->xceiv.state = OTG_STATE_A_WAIT_BCON; + musb->xceiv->state = OTG_STATE_A_WAIT_BCON; #endif default: break; @@ -118,7 +117,7 @@ void musb_platform_try_idle(struct musb *musb, unsigned long timeout) /* Never idle if active, or when VBUS timeout is not set as host */ if (musb->is_active || ((musb->a_wait_bcon == 0) - && (musb->xceiv.state == OTG_STATE_A_WAIT_BCON))) { + && (musb->xceiv->state == OTG_STATE_A_WAIT_BCON))) { DBG(4, "%s active, deleting timer\n", otg_state_string(musb)); del_timer(&musb_idle_timer); last_timer = jiffies; @@ -163,8 +162,8 @@ static void omap_set_vbus(struct musb *musb, int is_on) if (is_on) { musb->is_active = 1; - musb->xceiv.default_a = 1; - musb->xceiv.state = OTG_STATE_A_WAIT_VRISE; + musb->xceiv->default_a = 1; + musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; devctl |= MUSB_DEVCTL_SESSION; MUSB_HST_MODE(musb); @@ -175,8 +174,8 @@ static void omap_set_vbus(struct musb *musb, int is_on) * jumping right to B_IDLE... */ - musb->xceiv.default_a = 0; - musb->xceiv.state = OTG_STATE_B_IDLE; + musb->xceiv->default_a = 0; + musb->xceiv->state = OTG_STATE_B_IDLE; devctl &= ~MUSB_DEVCTL_SESSION; MUSB_DEV_MODE(musb); @@ -188,10 +187,6 @@ static void omap_set_vbus(struct musb *musb, int is_on) otg_state_string(musb), musb_readb(musb->mregs, MUSB_DEVCTL)); } -static int omap_set_power(struct otg_transceiver *x, unsigned mA) -{ - return 0; -} static int musb_platform_resume(struct musb *musb); @@ -202,24 +197,6 @@ int musb_platform_set_mode(struct musb *musb, u8 musb_mode) devctl |= MUSB_DEVCTL_SESSION; musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); - switch (musb_mode) { -#ifdef CONFIG_USB_MUSB_HDRC_HCD - case MUSB_HOST: - otg_set_host(&musb->xceiv, musb->xceiv.host); - break; -#endif -#ifdef CONFIG_USB_GADGET_MUSB_HDRC - case MUSB_PERIPHERAL: - otg_set_peripheral(&musb->xceiv, musb->xceiv.gadget); - break; -#endif -#ifdef CONFIG_USB_MUSB_OTG - case MUSB_OTG: - break; -#endif - default: - return -EINVAL; - } return 0; } @@ -231,6 +208,16 @@ int __init musb_platform_init(struct musb *musb) omap_cfg_reg(AE5_2430_USB0HS_STP); #endif + /* We require some kind of external transceiver, hooked + * up through ULPI. TWL4030-family PMICs include one, + * which needs a driver, drivers aren't always needed. + */ + musb->xceiv = otg_get_transceiver(); + if (!musb->xceiv) { + pr_err("HS USB OTG: no transceiver configured\n"); + return -ENODEV; + } + musb_platform_resume(musb); l = omap_readl(OTG_SYSCONFIG); @@ -240,7 +227,12 @@ int __init musb_platform_init(struct musb *musb) l &= ~AUTOIDLE; /* disable auto idle */ l &= ~NOIDLE; /* remove possible noidle */ l |= SMARTIDLE; /* enable smart idle */ - l |= AUTOIDLE; /* enable auto idle */ + /* + * MUSB AUTOIDLE don't work in 3430. + * Workaround by Richard Woodruff/TI + */ + if (!cpu_is_omap3430()) + l |= AUTOIDLE; /* enable auto idle */ omap_writel(l, OTG_SYSCONFIG); l = omap_readl(OTG_INTERFSEL); @@ -257,9 +249,6 @@ int __init musb_platform_init(struct musb *musb) if (is_host_enabled(musb)) musb->board_set_vbus = omap_set_vbus; - if (is_peripheral_enabled(musb)) - musb->xceiv.set_power = omap_set_power; - musb->a_wait_bcon = MUSB_TIMEOUT_A_WAIT_BCON; setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb); @@ -282,8 +271,7 @@ int musb_platform_suspend(struct musb *musb) l |= ENABLEWAKEUP; /* enable wakeup */ omap_writel(l, OTG_SYSCONFIG); - if (musb->xceiv.set_suspend) - musb->xceiv.set_suspend(&musb->xceiv, 1); + otg_set_suspend(musb->xceiv, 1); if (musb->set_clock) musb->set_clock(musb->clock, 0); @@ -300,8 +288,7 @@ static int musb_platform_resume(struct musb *musb) if (!musb->clock) return 0; - if (musb->xceiv.set_suspend) - musb->xceiv.set_suspend(&musb->xceiv, 0); + otg_set_suspend(musb->xceiv, 0); if (musb->set_clock) musb->set_clock(musb->clock, 1); diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c index 4ac1477d3569..88b587c703e9 100644 --- a/drivers/usb/musb/tusb6010.c +++ b/drivers/usb/musb/tusb6010.c @@ -259,6 +259,8 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *buf) tusb_fifo_read_unaligned(fifo, buf, len); } +static struct musb *the_musb; + #ifdef CONFIG_USB_GADGET_MUSB_HDRC /* This is used by gadget drivers, and OTG transceiver logic, allowing @@ -269,7 +271,7 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *buf) */ static int tusb_draw_power(struct otg_transceiver *x, unsigned mA) { - struct musb *musb = container_of(x, struct musb, xceiv); + struct musb *musb = the_musb; void __iomem *tbase = musb->ctrl_base; u32 reg; @@ -419,7 +421,7 @@ static void musb_do_idle(unsigned long _musb) spin_lock_irqsave(&musb->lock, flags); - switch (musb->xceiv.state) { + switch (musb->xceiv->state) { case OTG_STATE_A_WAIT_BCON: if ((musb->a_wait_bcon != 0) && (musb->idle_timeout == 0 @@ -483,7 +485,7 @@ void musb_platform_try_idle(struct musb *musb, unsigned long timeout) /* Never idle if active, or when VBUS timeout is not set as host */ if (musb->is_active || ((musb->a_wait_bcon == 0) - && (musb->xceiv.state == OTG_STATE_A_WAIT_BCON))) { + && (musb->xceiv->state == OTG_STATE_A_WAIT_BCON))) { DBG(4, "%s active, deleting timer\n", otg_state_string(musb)); del_timer(&musb_idle_timer); last_timer = jiffies; @@ -532,8 +534,8 @@ static void tusb_source_power(struct musb *musb, int is_on) if (musb->set_clock) musb->set_clock(musb->clock, 1); timer = OTG_TIMER_MS(OTG_TIME_A_WAIT_VRISE); - musb->xceiv.default_a = 1; - musb->xceiv.state = OTG_STATE_A_WAIT_VRISE; + musb->xceiv->default_a = 1; + musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; devctl |= MUSB_DEVCTL_SESSION; conf |= TUSB_DEV_CONF_USB_HOST_MODE; @@ -546,24 +548,24 @@ static void tusb_source_power(struct musb *musb, int is_on) /* If ID pin is grounded, we want to be a_idle */ otg_stat = musb_readl(tbase, TUSB_DEV_OTG_STAT); if (!(otg_stat & TUSB_DEV_OTG_STAT_ID_STATUS)) { - switch (musb->xceiv.state) { + switch (musb->xceiv->state) { case OTG_STATE_A_WAIT_VRISE: case OTG_STATE_A_WAIT_BCON: - musb->xceiv.state = OTG_STATE_A_WAIT_VFALL; + musb->xceiv->state = OTG_STATE_A_WAIT_VFALL; break; case OTG_STATE_A_WAIT_VFALL: - musb->xceiv.state = OTG_STATE_A_IDLE; + musb->xceiv->state = OTG_STATE_A_IDLE; break; default: - musb->xceiv.state = OTG_STATE_A_IDLE; + musb->xceiv->state = OTG_STATE_A_IDLE; } musb->is_active = 0; - musb->xceiv.default_a = 1; + musb->xceiv->default_a = 1; MUSB_HST_MODE(musb); } else { musb->is_active = 0; - musb->xceiv.default_a = 0; - musb->xceiv.state = OTG_STATE_B_IDLE; + musb->xceiv->default_a = 0; + musb->xceiv->state = OTG_STATE_B_IDLE; MUSB_DEV_MODE(musb); } @@ -674,7 +676,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase) else default_a = is_host_enabled(musb); DBG(2, "Default-%c\n", default_a ? 'A' : 'B'); - musb->xceiv.default_a = default_a; + musb->xceiv->default_a = default_a; tusb_source_power(musb, default_a); /* Don't allow idling immediately */ @@ -686,7 +688,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase) if (int_src & TUSB_INT_SRC_VBUS_SENSE_CHNG) { /* B-dev state machine: no vbus ~= disconnect */ - if ((is_otg_enabled(musb) && !musb->xceiv.default_a) + if ((is_otg_enabled(musb) && !musb->xceiv->default_a) || !is_host_enabled(musb)) { #ifdef CONFIG_USB_MUSB_HDRC_HCD /* ? musb_root_disconnect(musb); */ @@ -701,9 +703,9 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase) if (otg_stat & TUSB_DEV_OTG_STAT_SESS_END) { DBG(1, "Forcing disconnect (no interrupt)\n"); - if (musb->xceiv.state != OTG_STATE_B_IDLE) { + if (musb->xceiv->state != OTG_STATE_B_IDLE) { /* INTR_DISCONNECT can hide... */ - musb->xceiv.state = OTG_STATE_B_IDLE; + musb->xceiv->state = OTG_STATE_B_IDLE; musb->int_usb |= MUSB_INTR_DISCONNECT; } musb->is_active = 0; @@ -717,7 +719,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase) DBG(2, "vbus change, %s, otg %03x\n", otg_state_string(musb), otg_stat); - switch (musb->xceiv.state) { + switch (musb->xceiv->state) { case OTG_STATE_A_IDLE: DBG(2, "Got SRP, turning on VBUS\n"); musb_set_vbus(musb, 1); @@ -765,7 +767,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase) DBG(4, "%s timer, %03x\n", otg_state_string(musb), otg_stat); - switch (musb->xceiv.state) { + switch (musb->xceiv->state) { case OTG_STATE_A_WAIT_VRISE: /* VBUS has probably been valid for a while now, * but may well have bounced out of range a bit @@ -777,7 +779,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase) DBG(2, "devctl %02x\n", devctl); break; } - musb->xceiv.state = OTG_STATE_A_WAIT_BCON; + musb->xceiv->state = OTG_STATE_A_WAIT_BCON; musb->is_active = 0; idle_timeout = jiffies + msecs_to_jiffies(musb->a_wait_bcon); @@ -1093,9 +1095,14 @@ int __init musb_platform_init(struct musb *musb) { struct platform_device *pdev; struct resource *mem; - void __iomem *sync; + void __iomem *sync = NULL; int ret; + usb_nop_xceiv_register(); + musb->xceiv = otg_get_transceiver(); + if (!musb->xceiv) + return -ENODEV; + pdev = to_platform_device(musb->controller); /* dma address for async dma */ @@ -1106,14 +1113,16 @@ int __init musb_platform_init(struct musb *musb) mem = platform_get_resource(pdev, IORESOURCE_MEM, 1); if (!mem) { pr_debug("no sync dma resource?\n"); - return -ENODEV; + ret = -ENODEV; + goto done; } musb->sync = mem->start; sync = ioremap(mem->start, mem->end - mem->start + 1); if (!sync) { pr_debug("ioremap for sync failed\n"); - return -ENOMEM; + ret = -ENOMEM; + goto done; } musb->sync_va = sync; @@ -1126,28 +1135,37 @@ int __init musb_platform_init(struct musb *musb) if (ret) { printk(KERN_ERR "Could not start tusb6010 (%d)\n", ret); - return -ENODEV; + goto done; } musb->isr = tusb_interrupt; if (is_host_enabled(musb)) musb->board_set_vbus = tusb_source_power; - if (is_peripheral_enabled(musb)) - musb->xceiv.set_power = tusb_draw_power; + if (is_peripheral_enabled(musb)) { + musb->xceiv->set_power = tusb_draw_power; + the_musb = musb; + } setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb); +done: + if (ret < 0) { + if (sync) + iounmap(sync); + usb_nop_xceiv_unregister(); + } return ret; } int musb_platform_exit(struct musb *musb) { del_timer_sync(&musb_idle_timer); + the_musb = NULL; if (musb->board_set_power) musb->board_set_power(0); iounmap(musb->sync_va); - + usb_nop_xceiv_unregister(); return 0; } diff --git a/drivers/usb/otg/Kconfig b/drivers/usb/otg/Kconfig index aa884d072f0b..69feeec1628c 100644 --- a/drivers/usb/otg/Kconfig +++ b/drivers/usb/otg/Kconfig @@ -59,4 +59,18 @@ config NOP_USB_XCEIV built-in with usb ip or which are autonomous and doesn't require any phy programming such as ISP1x04 etc. +config USB_LANGWELL_OTG + tristate "Intel Langwell USB OTG dual-role support" + depends on USB && MRST + select USB_OTG + select USB_OTG_UTILS + help + Say Y here if you want to build Intel Langwell USB OTG + transciever driver in kernel. This driver implements role + switch between EHCI host driver and Langwell USB OTG + client driver. + + To compile this driver as a module, choose M here: the + module will be called langwell_otg. + endif # USB || OTG diff --git a/drivers/usb/otg/Makefile b/drivers/usb/otg/Makefile index 208167856529..6d1abdd3c0ac 100644 --- a/drivers/usb/otg/Makefile +++ b/drivers/usb/otg/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_USB_OTG_UTILS) += otg.o obj-$(CONFIG_USB_GPIO_VBUS) += gpio_vbus.o obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o obj-$(CONFIG_TWL4030_USB) += twl4030-usb.o +obj-$(CONFIG_USB_LANGWELL_OTG) += langwell_otg.o obj-$(CONFIG_NOP_USB_XCEIV) += nop-usb-xceiv.o ccflags-$(CONFIG_USB_DEBUG) += -DDEBUG diff --git a/drivers/usb/otg/langwell_otg.c b/drivers/usb/otg/langwell_otg.c new file mode 100644 index 000000000000..6f628d0e9f39 --- /dev/null +++ b/drivers/usb/otg/langwell_otg.c @@ -0,0 +1,1915 @@ +/* + * Intel Langwell USB OTG transceiver driver + * Copyright (C) 2008 - 2009, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + */ +/* This driver helps to switch Langwell OTG controller function between host + * and peripheral. It works with EHCI driver and Langwell client controller + * driver together. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../core/hcd.h" + +#include + +#define DRIVER_DESC "Intel Langwell USB OTG transceiver driver" +#define DRIVER_VERSION "3.0.0.32L.0002" + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_AUTHOR("Henry Yuan , Hao Wu "); +MODULE_VERSION(DRIVER_VERSION); +MODULE_LICENSE("GPL"); + +static const char driver_name[] = "langwell_otg"; + +static int langwell_otg_probe(struct pci_dev *pdev, + const struct pci_device_id *id); +static void langwell_otg_remove(struct pci_dev *pdev); +static int langwell_otg_suspend(struct pci_dev *pdev, pm_message_t message); +static int langwell_otg_resume(struct pci_dev *pdev); + +static int langwell_otg_set_host(struct otg_transceiver *otg, + struct usb_bus *host); +static int langwell_otg_set_peripheral(struct otg_transceiver *otg, + struct usb_gadget *gadget); +static int langwell_otg_start_srp(struct otg_transceiver *otg); + +static const struct pci_device_id pci_ids[] = {{ + .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe), + .class_mask = ~0, + .vendor = 0x8086, + .device = 0x0811, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, +}, { /* end: all zeroes */ } +}; + +static struct pci_driver otg_pci_driver = { + .name = (char *) driver_name, + .id_table = pci_ids, + + .probe = langwell_otg_probe, + .remove = langwell_otg_remove, + + .suspend = langwell_otg_suspend, + .resume = langwell_otg_resume, +}; + +static const char *state_string(enum usb_otg_state state) +{ + switch (state) { + case OTG_STATE_A_IDLE: + return "a_idle"; + case OTG_STATE_A_WAIT_VRISE: + return "a_wait_vrise"; + case OTG_STATE_A_WAIT_BCON: + return "a_wait_bcon"; + case OTG_STATE_A_HOST: + return "a_host"; + case OTG_STATE_A_SUSPEND: + return "a_suspend"; + case OTG_STATE_A_PERIPHERAL: + return "a_peripheral"; + case OTG_STATE_A_WAIT_VFALL: + return "a_wait_vfall"; + case OTG_STATE_A_VBUS_ERR: + return "a_vbus_err"; + case OTG_STATE_B_IDLE: + return "b_idle"; + case OTG_STATE_B_SRP_INIT: + return "b_srp_init"; + case OTG_STATE_B_PERIPHERAL: + return "b_peripheral"; + case OTG_STATE_B_WAIT_ACON: + return "b_wait_acon"; + case OTG_STATE_B_HOST: + return "b_host"; + default: + return "UNDEFINED"; + } +} + +/* HSM timers */ +static inline struct langwell_otg_timer *otg_timer_initializer +(void (*function)(unsigned long), unsigned long expires, unsigned long data) +{ + struct langwell_otg_timer *timer; + timer = kmalloc(sizeof(struct langwell_otg_timer), GFP_KERNEL); + timer->function = function; + timer->expires = expires; + timer->data = data; + return timer; +} + +static struct langwell_otg_timer *a_wait_vrise_tmr, *a_wait_bcon_tmr, + *a_aidl_bdis_tmr, *b_ase0_brst_tmr, *b_se0_srp_tmr, *b_srp_res_tmr, + *b_bus_suspend_tmr; + +static struct list_head active_timers; + +static struct langwell_otg *the_transceiver; + +/* host/client notify transceiver when event affects HNP state */ +void langwell_update_transceiver() +{ + otg_dbg("transceiver driver is notified\n"); + queue_work(the_transceiver->qwork, &the_transceiver->work); +} +EXPORT_SYMBOL(langwell_update_transceiver); + +static int langwell_otg_set_host(struct otg_transceiver *otg, + struct usb_bus *host) +{ + otg->host = host; + + return 0; +} + +static int langwell_otg_set_peripheral(struct otg_transceiver *otg, + struct usb_gadget *gadget) +{ + otg->gadget = gadget; + + return 0; +} + +static int langwell_otg_set_power(struct otg_transceiver *otg, + unsigned mA) +{ + return 0; +} + +/* A-device drives vbus, controlled through PMIC CHRGCNTL register*/ +static void langwell_otg_drv_vbus(int on) +{ + struct ipc_pmic_reg_data pmic_data = {0}; + struct ipc_pmic_reg_data battery_data; + + /* Check if battery is attached or not */ + battery_data.pmic_reg_data[0].register_address = 0xd2; + battery_data.ioc = 0; + battery_data.num_entries = 1; + if (ipc_pmic_register_read(&battery_data)) { + otg_dbg("Failed to read PMIC register 0xd2.\n"); + return; + } + + if ((battery_data.pmic_reg_data[0].value & 0x20) == 0) { + otg_dbg("no battery attached\n"); + return; + } + + /* Workaround for battery attachment issue */ + if (battery_data.pmic_reg_data[0].value == 0x34) { + otg_dbg("battery \n"); + return; + } + + otg_dbg("battery attached\n"); + + pmic_data.ioc = 0; + pmic_data.pmic_reg_data[0].register_address = 0xD4; + pmic_data.num_entries = 1; + if (on) + pmic_data.pmic_reg_data[0].value = 0x20; + else + pmic_data.pmic_reg_data[0].value = 0xc0; + + if (ipc_pmic_register_write(&pmic_data, TRUE)) + otg_dbg("Failed to write PMIC.\n"); + +} + +/* charge vbus or discharge vbus through a resistor to ground */ +static void langwell_otg_chrg_vbus(int on) +{ + + u32 val; + + val = readl(the_transceiver->regs + CI_OTGSC); + + if (on) + writel((val & ~OTGSC_INTSTS_MASK) | OTGSC_VC, + the_transceiver->regs + CI_OTGSC); + else + writel((val & ~OTGSC_INTSTS_MASK) | OTGSC_VD, + the_transceiver->regs + CI_OTGSC); + +} + +/* Start SRP */ +static int langwell_otg_start_srp(struct otg_transceiver *otg) +{ + u32 val; + + otg_dbg("Start SRP ->\n"); + + val = readl(the_transceiver->regs + CI_OTGSC); + + writel((val & ~OTGSC_INTSTS_MASK) | OTGSC_HADP, + the_transceiver->regs + CI_OTGSC); + + /* Check if the data plus is finished or not */ + msleep(8); + val = readl(the_transceiver->regs + CI_OTGSC); + if (val & (OTGSC_HADP | OTGSC_DP)) + otg_dbg("DataLine SRP Error\n"); + + /* FIXME: VBus SRP */ + + return 0; +} + + +/* stop SOF via bus_suspend */ +static void langwell_otg_loc_sof(int on) +{ + struct usb_hcd *hcd; + int err; + + otg_dbg("loc_sof -> %d\n", on); + + hcd = bus_to_hcd(the_transceiver->otg.host); + if (on) + err = hcd->driver->bus_resume(hcd); + else + err = hcd->driver->bus_suspend(hcd); + + if (err) + otg_dbg("Failed to resume/suspend bus - %d\n", err); +} + +static void langwell_otg_phy_low_power(int on) +{ + u32 val; + + otg_dbg("phy low power mode-> %d\n", on); + + val = readl(the_transceiver->regs + CI_HOSTPC1); + if (on) + writel(val | HOSTPC1_PHCD, the_transceiver->regs + CI_HOSTPC1); + else + writel(val & ~HOSTPC1_PHCD, the_transceiver->regs + CI_HOSTPC1); +} + +/* Enable/Disable OTG interrupt */ +static void langwell_otg_intr(int on) +{ + u32 val; + + otg_dbg("interrupt -> %d\n", on); + + val = readl(the_transceiver->regs + CI_OTGSC); + if (on) { + val = val | (OTGSC_INTEN_MASK | OTGSC_IDPU); + writel(val, the_transceiver->regs + CI_OTGSC); + } else { + val = val & ~(OTGSC_INTEN_MASK | OTGSC_IDPU); + writel(val, the_transceiver->regs + CI_OTGSC); + } +} + +/* set HAAR: Hardware Assist Auto-Reset */ +static void langwell_otg_HAAR(int on) +{ + u32 val; + + otg_dbg("HAAR -> %d\n", on); + + val = readl(the_transceiver->regs + CI_OTGSC); + if (on) + writel((val & ~OTGSC_INTSTS_MASK) | OTGSC_HAAR, + the_transceiver->regs + CI_OTGSC); + else + writel((val & ~OTGSC_INTSTS_MASK) & ~OTGSC_HAAR, + the_transceiver->regs + CI_OTGSC); +} + +/* set HABA: Hardware Assist B-Disconnect to A-Connect */ +static void langwell_otg_HABA(int on) +{ + u32 val; + + otg_dbg("HABA -> %d\n", on); + + val = readl(the_transceiver->regs + CI_OTGSC); + if (on) + writel((val & ~OTGSC_INTSTS_MASK) | OTGSC_HABA, + the_transceiver->regs + CI_OTGSC); + else + writel((val & ~OTGSC_INTSTS_MASK) & ~OTGSC_HABA, + the_transceiver->regs + CI_OTGSC); +} + +static int langwell_otg_check_se0_srp(int on) +{ + u32 val; + + int delay_time = TB_SE0_SRP * 10; /* step is 100us */ + + otg_dbg("check_se0_srp -> \n"); + + do { + udelay(100); + if (!delay_time--) + break; + val = readl(the_transceiver->regs + CI_PORTSC1); + val &= PORTSC_LS; + } while (!val); + + otg_dbg("check_se0_srp <- \n"); + return val; +} + +/* The timeout callback function to set time out bit */ +static void set_tmout(unsigned long indicator) +{ + *(int *)indicator = 1; +} + +void langwell_otg_nsf_msg(unsigned long indicator) +{ + switch (indicator) { + case 2: + case 4: + case 6: + case 7: + printk(KERN_ERR "OTG:NSF-%lu - deivce not responding\n", + indicator); + break; + case 3: + printk(KERN_ERR "OTG:NSF-%lu - deivce not supported\n", + indicator); + break; + default: + printk(KERN_ERR "Do not have this kind of NSF\n"); + break; + } +} + +/* Initialize timers */ +static void langwell_otg_init_timers(struct otg_hsm *hsm) +{ + /* HSM used timers */ + a_wait_vrise_tmr = otg_timer_initializer(&set_tmout, TA_WAIT_VRISE, + (unsigned long)&hsm->a_wait_vrise_tmout); + a_wait_bcon_tmr = otg_timer_initializer(&set_tmout, TA_WAIT_BCON, + (unsigned long)&hsm->a_wait_bcon_tmout); + a_aidl_bdis_tmr = otg_timer_initializer(&set_tmout, TA_AIDL_BDIS, + (unsigned long)&hsm->a_aidl_bdis_tmout); + b_ase0_brst_tmr = otg_timer_initializer(&set_tmout, TB_ASE0_BRST, + (unsigned long)&hsm->b_ase0_brst_tmout); + b_se0_srp_tmr = otg_timer_initializer(&set_tmout, TB_SE0_SRP, + (unsigned long)&hsm->b_se0_srp); + b_srp_res_tmr = otg_timer_initializer(&set_tmout, TB_SRP_RES, + (unsigned long)&hsm->b_srp_res_tmout); + b_bus_suspend_tmr = otg_timer_initializer(&set_tmout, TB_BUS_SUSPEND, + (unsigned long)&hsm->b_bus_suspend_tmout); +} + +/* Free timers */ +static void langwell_otg_free_timers(void) +{ + kfree(a_wait_vrise_tmr); + kfree(a_wait_bcon_tmr); + kfree(a_aidl_bdis_tmr); + kfree(b_ase0_brst_tmr); + kfree(b_se0_srp_tmr); + kfree(b_srp_res_tmr); + kfree(b_bus_suspend_tmr); +} + +/* Add timer to timer list */ +static void langwell_otg_add_timer(void *gtimer) +{ + struct langwell_otg_timer *timer = (struct langwell_otg_timer *)gtimer; + struct langwell_otg_timer *tmp_timer; + u32 val32; + + /* Check if the timer is already in the active list, + * if so update timer count + */ + list_for_each_entry(tmp_timer, &active_timers, list) + if (tmp_timer == timer) { + timer->count = timer->expires; + return; + } + timer->count = timer->expires; + + if (list_empty(&active_timers)) { + val32 = readl(the_transceiver->regs + CI_OTGSC); + writel(val32 | OTGSC_1MSE, the_transceiver->regs + CI_OTGSC); + } + + list_add_tail(&timer->list, &active_timers); +} + +/* Remove timer from the timer list; clear timeout status */ +static void langwell_otg_del_timer(void *gtimer) +{ + struct langwell_otg_timer *timer = (struct langwell_otg_timer *)gtimer; + struct langwell_otg_timer *tmp_timer, *del_tmp; + u32 val32; + + list_for_each_entry_safe(tmp_timer, del_tmp, &active_timers, list) + if (tmp_timer == timer) + list_del(&timer->list); + + if (list_empty(&active_timers)) { + val32 = readl(the_transceiver->regs + CI_OTGSC); + writel(val32 & ~OTGSC_1MSE, the_transceiver->regs + CI_OTGSC); + } +} + +/* Reduce timer count by 1, and find timeout conditions.*/ +static int langwell_otg_tick_timer(u32 *int_sts) +{ + struct langwell_otg_timer *tmp_timer, *del_tmp; + int expired = 0; + + list_for_each_entry_safe(tmp_timer, del_tmp, &active_timers, list) { + tmp_timer->count--; + /* check if timer expires */ + if (!tmp_timer->count) { + list_del(&tmp_timer->list); + tmp_timer->function(tmp_timer->data); + expired = 1; + } + } + + if (list_empty(&active_timers)) { + otg_dbg("tick timer: disable 1ms int\n"); + *int_sts = *int_sts & ~OTGSC_1MSE; + } + return expired; +} + +static void reset_otg(void) +{ + u32 val; + int delay_time = 1000; + + otg_dbg("reseting OTG controller ...\n"); + val = readl(the_transceiver->regs + CI_USBCMD); + writel(val | USBCMD_RST, the_transceiver->regs + CI_USBCMD); + do { + udelay(100); + if (!delay_time--) + otg_dbg("reset timeout\n"); + val = readl(the_transceiver->regs + CI_USBCMD); + val &= USBCMD_RST; + } while (val != 0); + otg_dbg("reset done.\n"); +} + +static void set_host_mode(void) +{ + u32 val; + + reset_otg(); + val = readl(the_transceiver->regs + CI_USBMODE); + val = (val & (~USBMODE_CM)) | USBMODE_HOST; + writel(val, the_transceiver->regs + CI_USBMODE); +} + +static void set_client_mode(void) +{ + u32 val; + + reset_otg(); + val = readl(the_transceiver->regs + CI_USBMODE); + val = (val & (~USBMODE_CM)) | USBMODE_DEVICE; + writel(val, the_transceiver->regs + CI_USBMODE); +} + +static void init_hsm(void) +{ + struct langwell_otg *langwell = the_transceiver; + u32 val32; + + /* read OTGSC after reset */ + val32 = readl(langwell->regs + CI_OTGSC); + otg_dbg("%s: OTGSC init value = 0x%x\n", __func__, val32); + + /* set init state */ + if (val32 & OTGSC_ID) { + langwell->hsm.id = 1; + langwell->otg.default_a = 0; + set_client_mode(); + langwell->otg.state = OTG_STATE_B_IDLE; + langwell_otg_drv_vbus(0); + } else { + langwell->hsm.id = 0; + langwell->otg.default_a = 1; + set_host_mode(); + langwell->otg.state = OTG_STATE_A_IDLE; + } + + /* set session indicator */ + if (val32 & OTGSC_BSE) + langwell->hsm.b_sess_end = 1; + if (val32 & OTGSC_BSV) + langwell->hsm.b_sess_vld = 1; + if (val32 & OTGSC_ASV) + langwell->hsm.a_sess_vld = 1; + if (val32 & OTGSC_AVV) + langwell->hsm.a_vbus_vld = 1; + + /* defautly power the bus */ + langwell->hsm.a_bus_req = 1; + langwell->hsm.a_bus_drop = 0; + /* defautly don't request bus as B device */ + langwell->hsm.b_bus_req = 0; + /* no system error */ + langwell->hsm.a_clr_err = 0; +} + +static irqreturn_t otg_dummy_irq(int irq, void *_dev) +{ + void __iomem *reg_base = _dev; + u32 val; + u32 int_mask = 0; + + val = readl(reg_base + CI_USBMODE); + if ((val & USBMODE_CM) != USBMODE_DEVICE) + return IRQ_NONE; + + val = readl(reg_base + CI_USBSTS); + int_mask = val & INTR_DUMMY_MASK; + + if (int_mask == 0) + return IRQ_NONE; + + /* clear hsm.b_conn here since host driver can't detect it + * otg_dummy_irq called means B-disconnect happened. + */ + if (the_transceiver->hsm.b_conn) { + the_transceiver->hsm.b_conn = 0; + if (spin_trylock(&the_transceiver->wq_lock)) { + queue_work(the_transceiver->qwork, + &the_transceiver->work); + spin_unlock(&the_transceiver->wq_lock); + } + } + /* Clear interrupts */ + writel(int_mask, reg_base + CI_USBSTS); + return IRQ_HANDLED; +} + +static irqreturn_t otg_irq(int irq, void *_dev) +{ + struct langwell_otg *langwell = _dev; + u32 int_sts, int_en; + u32 int_mask = 0; + int flag = 0; + + int_sts = readl(langwell->regs + CI_OTGSC); + int_en = (int_sts & OTGSC_INTEN_MASK) >> 8; + int_mask = int_sts & int_en; + if (int_mask == 0) + return IRQ_NONE; + + if (int_mask & OTGSC_IDIS) { + otg_dbg("%s: id change int\n", __func__); + langwell->hsm.id = (int_sts & OTGSC_ID) ? 1 : 0; + flag = 1; + } + if (int_mask & OTGSC_DPIS) { + otg_dbg("%s: data pulse int\n", __func__); + langwell->hsm.a_srp_det = (int_sts & OTGSC_DPS) ? 1 : 0; + flag = 1; + } + if (int_mask & OTGSC_BSEIS) { + otg_dbg("%s: b session end int\n", __func__); + langwell->hsm.b_sess_end = (int_sts & OTGSC_BSE) ? 1 : 0; + flag = 1; + } + if (int_mask & OTGSC_BSVIS) { + otg_dbg("%s: b session valid int\n", __func__); + langwell->hsm.b_sess_vld = (int_sts & OTGSC_BSV) ? 1 : 0; + flag = 1; + } + if (int_mask & OTGSC_ASVIS) { + otg_dbg("%s: a session valid int\n", __func__); + langwell->hsm.a_sess_vld = (int_sts & OTGSC_ASV) ? 1 : 0; + flag = 1; + } + if (int_mask & OTGSC_AVVIS) { + otg_dbg("%s: a vbus valid int\n", __func__); + langwell->hsm.a_vbus_vld = (int_sts & OTGSC_AVV) ? 1 : 0; + flag = 1; + } + + if (int_mask & OTGSC_1MSS) { + /* need to schedule otg_work if any timer is expired */ + if (langwell_otg_tick_timer(&int_sts)) + flag = 1; + } + + writel((int_sts & ~OTGSC_INTSTS_MASK) | int_mask, + langwell->regs + CI_OTGSC); + if (flag) + queue_work(langwell->qwork, &langwell->work); + + return IRQ_HANDLED; +} + +static void langwell_otg_work(struct work_struct *work) +{ + struct langwell_otg *langwell = container_of(work, + struct langwell_otg, work); + int retval; + + otg_dbg("%s: old state = %s\n", __func__, + state_string(langwell->otg.state)); + + switch (langwell->otg.state) { + case OTG_STATE_UNDEFINED: + case OTG_STATE_B_IDLE: + if (!langwell->hsm.id) { + langwell_otg_del_timer(b_srp_res_tmr); + langwell->otg.default_a = 1; + langwell->hsm.a_srp_det = 0; + + langwell_otg_chrg_vbus(0); + langwell_otg_drv_vbus(0); + + set_host_mode(); + langwell->otg.state = OTG_STATE_A_IDLE; + queue_work(langwell->qwork, &langwell->work); + } else if (langwell->hsm.b_srp_res_tmout) { + langwell->hsm.b_srp_res_tmout = 0; + langwell->hsm.b_bus_req = 0; + langwell_otg_nsf_msg(6); + } else if (langwell->hsm.b_sess_vld) { + langwell_otg_del_timer(b_srp_res_tmr); + langwell->hsm.b_sess_end = 0; + langwell->hsm.a_bus_suspend = 0; + + langwell_otg_chrg_vbus(0); + if (langwell->client_ops) { + langwell->client_ops->resume(langwell->pdev); + langwell->otg.state = OTG_STATE_B_PERIPHERAL; + } else + otg_dbg("client driver not loaded.\n"); + + } else if (langwell->hsm.b_bus_req && + (langwell->hsm.b_sess_end)) { + /* workaround for b_se0_srp detection */ + retval = langwell_otg_check_se0_srp(0); + if (retval) { + langwell->hsm.b_bus_req = 0; + otg_dbg("LS is not SE0, try again later\n"); + } else { + /* Start SRP */ + langwell_otg_start_srp(&langwell->otg); + langwell_otg_add_timer(b_srp_res_tmr); + } + } + break; + case OTG_STATE_B_SRP_INIT: + if (!langwell->hsm.id) { + langwell->otg.default_a = 1; + langwell->hsm.a_srp_det = 0; + + langwell_otg_drv_vbus(0); + langwell_otg_chrg_vbus(0); + + langwell->otg.state = OTG_STATE_A_IDLE; + queue_work(langwell->qwork, &langwell->work); + } else if (langwell->hsm.b_sess_vld) { + langwell_otg_chrg_vbus(0); + if (langwell->client_ops) { + langwell->client_ops->resume(langwell->pdev); + langwell->otg.state = OTG_STATE_B_PERIPHERAL; + } else + otg_dbg("client driver not loaded.\n"); + } + break; + case OTG_STATE_B_PERIPHERAL: + if (!langwell->hsm.id) { + langwell->otg.default_a = 1; + langwell->hsm.a_srp_det = 0; + + langwell_otg_drv_vbus(0); + langwell_otg_chrg_vbus(0); + set_host_mode(); + + if (langwell->client_ops) { + langwell->client_ops->suspend(langwell->pdev, + PMSG_FREEZE); + } else + otg_dbg("client driver has been removed.\n"); + + langwell->otg.state = OTG_STATE_A_IDLE; + queue_work(langwell->qwork, &langwell->work); + } else if (!langwell->hsm.b_sess_vld) { + langwell->hsm.b_hnp_enable = 0; + + if (langwell->client_ops) { + langwell->client_ops->suspend(langwell->pdev, + PMSG_FREEZE); + } else + otg_dbg("client driver has been removed.\n"); + + langwell->otg.state = OTG_STATE_B_IDLE; + } else if (langwell->hsm.b_bus_req && langwell->hsm.b_hnp_enable + && langwell->hsm.a_bus_suspend) { + + if (langwell->client_ops) { + langwell->client_ops->suspend(langwell->pdev, + PMSG_FREEZE); + } else + otg_dbg("client driver has been removed.\n"); + + langwell_otg_HAAR(1); + langwell->hsm.a_conn = 0; + + if (langwell->host_ops) { + langwell->host_ops->probe(langwell->pdev, + langwell->host_ops->id_table); + langwell->otg.state = OTG_STATE_B_WAIT_ACON; + } else + otg_dbg("host driver not loaded.\n"); + + langwell->hsm.a_bus_resume = 0; + langwell->hsm.b_ase0_brst_tmout = 0; + langwell_otg_add_timer(b_ase0_brst_tmr); + } + break; + + case OTG_STATE_B_WAIT_ACON: + if (!langwell->hsm.id) { + langwell_otg_del_timer(b_ase0_brst_tmr); + langwell->otg.default_a = 1; + langwell->hsm.a_srp_det = 0; + + langwell_otg_drv_vbus(0); + langwell_otg_chrg_vbus(0); + set_host_mode(); + + langwell_otg_HAAR(0); + if (langwell->host_ops) + langwell->host_ops->remove(langwell->pdev); + else + otg_dbg("host driver has been removed.\n"); + langwell->otg.state = OTG_STATE_A_IDLE; + queue_work(langwell->qwork, &langwell->work); + } else if (!langwell->hsm.b_sess_vld) { + langwell_otg_del_timer(b_ase0_brst_tmr); + langwell->hsm.b_hnp_enable = 0; + langwell->hsm.b_bus_req = 0; + langwell_otg_chrg_vbus(0); + langwell_otg_HAAR(0); + + if (langwell->host_ops) + langwell->host_ops->remove(langwell->pdev); + else + otg_dbg("host driver has been removed.\n"); + langwell->otg.state = OTG_STATE_B_IDLE; + } else if (langwell->hsm.a_conn) { + langwell_otg_del_timer(b_ase0_brst_tmr); + langwell_otg_HAAR(0); + langwell->otg.state = OTG_STATE_B_HOST; + queue_work(langwell->qwork, &langwell->work); + } else if (langwell->hsm.a_bus_resume || + langwell->hsm.b_ase0_brst_tmout) { + langwell_otg_del_timer(b_ase0_brst_tmr); + langwell_otg_HAAR(0); + langwell_otg_nsf_msg(7); + + if (langwell->host_ops) + langwell->host_ops->remove(langwell->pdev); + else + otg_dbg("host driver has been removed.\n"); + + langwell->hsm.a_bus_suspend = 0; + langwell->hsm.b_bus_req = 0; + + if (langwell->client_ops) + langwell->client_ops->resume(langwell->pdev); + else + otg_dbg("client driver not loaded.\n"); + + langwell->otg.state = OTG_STATE_B_PERIPHERAL; + } + break; + + case OTG_STATE_B_HOST: + if (!langwell->hsm.id) { + langwell->otg.default_a = 1; + langwell->hsm.a_srp_det = 0; + + langwell_otg_drv_vbus(0); + langwell_otg_chrg_vbus(0); + set_host_mode(); + if (langwell->host_ops) + langwell->host_ops->remove(langwell->pdev); + else + otg_dbg("host driver has been removed.\n"); + langwell->otg.state = OTG_STATE_A_IDLE; + queue_work(langwell->qwork, &langwell->work); + } else if (!langwell->hsm.b_sess_vld) { + langwell->hsm.b_hnp_enable = 0; + langwell->hsm.b_bus_req = 0; + langwell_otg_chrg_vbus(0); + if (langwell->host_ops) + langwell->host_ops->remove(langwell->pdev); + else + otg_dbg("host driver has been removed.\n"); + langwell->otg.state = OTG_STATE_B_IDLE; + } else if ((!langwell->hsm.b_bus_req) || + (!langwell->hsm.a_conn)) { + langwell->hsm.b_bus_req = 0; + langwell_otg_loc_sof(0); + if (langwell->host_ops) + langwell->host_ops->remove(langwell->pdev); + else + otg_dbg("host driver has been removed.\n"); + + langwell->hsm.a_bus_suspend = 0; + + if (langwell->client_ops) + langwell->client_ops->resume(langwell->pdev); + else + otg_dbg("client driver not loaded.\n"); + + langwell->otg.state = OTG_STATE_B_PERIPHERAL; + } + break; + + case OTG_STATE_A_IDLE: + langwell->otg.default_a = 1; + if (langwell->hsm.id) { + langwell->otg.default_a = 0; + langwell->hsm.b_bus_req = 0; + langwell_otg_drv_vbus(0); + langwell_otg_chrg_vbus(0); + + langwell->otg.state = OTG_STATE_B_IDLE; + queue_work(langwell->qwork, &langwell->work); + } else if (langwell->hsm.a_sess_vld) { + langwell_otg_drv_vbus(1); + langwell->hsm.a_srp_det = 1; + langwell->hsm.a_wait_vrise_tmout = 0; + langwell_otg_add_timer(a_wait_vrise_tmr); + langwell->otg.state = OTG_STATE_A_WAIT_VRISE; + queue_work(langwell->qwork, &langwell->work); + } else if (!langwell->hsm.a_bus_drop && + (langwell->hsm.a_srp_det || langwell->hsm.a_bus_req)) { + langwell_otg_drv_vbus(1); + langwell->hsm.a_wait_vrise_tmout = 0; + langwell_otg_add_timer(a_wait_vrise_tmr); + langwell->otg.state = OTG_STATE_A_WAIT_VRISE; + queue_work(langwell->qwork, &langwell->work); + } + break; + case OTG_STATE_A_WAIT_VRISE: + if (langwell->hsm.id) { + langwell_otg_del_timer(a_wait_vrise_tmr); + langwell->hsm.b_bus_req = 0; + langwell->otg.default_a = 0; + langwell_otg_drv_vbus(0); + langwell->otg.state = OTG_STATE_B_IDLE; + } else if (langwell->hsm.a_vbus_vld) { + langwell_otg_del_timer(a_wait_vrise_tmr); + if (langwell->host_ops) + langwell->host_ops->probe(langwell->pdev, + langwell->host_ops->id_table); + else + otg_dbg("host driver not loaded.\n"); + langwell->hsm.b_conn = 0; + langwell->hsm.a_set_b_hnp_en = 0; + langwell->hsm.a_wait_bcon_tmout = 0; + langwell_otg_add_timer(a_wait_bcon_tmr); + langwell->otg.state = OTG_STATE_A_WAIT_BCON; + } else if (langwell->hsm.a_wait_vrise_tmout) { + if (langwell->hsm.a_vbus_vld) { + if (langwell->host_ops) + langwell->host_ops->probe( + langwell->pdev, + langwell->host_ops->id_table); + else + otg_dbg("host driver not loaded.\n"); + langwell->hsm.b_conn = 0; + langwell->hsm.a_set_b_hnp_en = 0; + langwell->hsm.a_wait_bcon_tmout = 0; + langwell_otg_add_timer(a_wait_bcon_tmr); + langwell->otg.state = OTG_STATE_A_WAIT_BCON; + } else { + langwell_otg_drv_vbus(0); + langwell->otg.state = OTG_STATE_A_VBUS_ERR; + } + } + break; + case OTG_STATE_A_WAIT_BCON: + if (langwell->hsm.id) { + langwell_otg_del_timer(a_wait_bcon_tmr); + + langwell->otg.default_a = 0; + langwell->hsm.b_bus_req = 0; + if (langwell->host_ops) + langwell->host_ops->remove(langwell->pdev); + else + otg_dbg("host driver has been removed.\n"); + langwell_otg_drv_vbus(0); + langwell->otg.state = OTG_STATE_B_IDLE; + queue_work(langwell->qwork, &langwell->work); + } else if (!langwell->hsm.a_vbus_vld) { + langwell_otg_del_timer(a_wait_bcon_tmr); + + if (langwell->host_ops) + langwell->host_ops->remove(langwell->pdev); + else + otg_dbg("host driver has been removed.\n"); + langwell_otg_drv_vbus(0); + langwell->otg.state = OTG_STATE_A_VBUS_ERR; + } else if (langwell->hsm.a_bus_drop || + (langwell->hsm.a_wait_bcon_tmout && + !langwell->hsm.a_bus_req)) { + langwell_otg_del_timer(a_wait_bcon_tmr); + + if (langwell->host_ops) + langwell->host_ops->remove(langwell->pdev); + else + otg_dbg("host driver has been removed.\n"); + langwell_otg_drv_vbus(0); + langwell->otg.state = OTG_STATE_A_WAIT_VFALL; + } else if (langwell->hsm.b_conn) { + langwell_otg_del_timer(a_wait_bcon_tmr); + + langwell->hsm.a_suspend_req = 0; + langwell->otg.state = OTG_STATE_A_HOST; + if (!langwell->hsm.a_bus_req && + langwell->hsm.a_set_b_hnp_en) { + /* It is not safe enough to do a fast + * transistion from A_WAIT_BCON to + * A_SUSPEND */ + msleep(10000); + if (langwell->hsm.a_bus_req) + break; + + if (request_irq(langwell->pdev->irq, + otg_dummy_irq, IRQF_SHARED, + driver_name, langwell->regs) != 0) { + otg_dbg("request interrupt %d fail\n", + langwell->pdev->irq); + } + + langwell_otg_HABA(1); + langwell->hsm.b_bus_resume = 0; + langwell->hsm.a_aidl_bdis_tmout = 0; + langwell_otg_add_timer(a_aidl_bdis_tmr); + + langwell_otg_loc_sof(0); + langwell->otg.state = OTG_STATE_A_SUSPEND; + } else if (!langwell->hsm.a_bus_req && + !langwell->hsm.a_set_b_hnp_en) { + struct pci_dev *pdev = langwell->pdev; + if (langwell->host_ops) + langwell->host_ops->remove(pdev); + else + otg_dbg("host driver removed.\n"); + langwell_otg_drv_vbus(0); + langwell->otg.state = OTG_STATE_A_WAIT_VFALL; + } + } + break; + case OTG_STATE_A_HOST: + if (langwell->hsm.id) { + langwell->otg.default_a = 0; + langwell->hsm.b_bus_req = 0; + if (langwell->host_ops) + langwell->host_ops->remove(langwell->pdev); + else + otg_dbg("host driver has been removed.\n"); + langwell_otg_drv_vbus(0); + langwell->otg.state = OTG_STATE_B_IDLE; + queue_work(langwell->qwork, &langwell->work); + } else if (langwell->hsm.a_bus_drop || + (!langwell->hsm.a_set_b_hnp_en && !langwell->hsm.a_bus_req)) { + if (langwell->host_ops) + langwell->host_ops->remove(langwell->pdev); + else + otg_dbg("host driver has been removed.\n"); + langwell_otg_drv_vbus(0); + langwell->otg.state = OTG_STATE_A_WAIT_VFALL; + } else if (!langwell->hsm.a_vbus_vld) { + if (langwell->host_ops) + langwell->host_ops->remove(langwell->pdev); + else + otg_dbg("host driver has been removed.\n"); + langwell_otg_drv_vbus(0); + langwell->otg.state = OTG_STATE_A_VBUS_ERR; + } else if (langwell->hsm.a_set_b_hnp_en + && !langwell->hsm.a_bus_req) { + /* Set HABA to enable hardware assistance to signal + * A-connect after receiver B-disconnect. Hardware + * will then set client mode and enable URE, SLE and + * PCE after the assistance. otg_dummy_irq is used to + * clean these ints when client driver is not resumed. + */ + if (request_irq(langwell->pdev->irq, + otg_dummy_irq, IRQF_SHARED, driver_name, + langwell->regs) != 0) { + otg_dbg("request interrupt %d failed\n", + langwell->pdev->irq); + } + + /* set HABA */ + langwell_otg_HABA(1); + langwell->hsm.b_bus_resume = 0; + langwell->hsm.a_aidl_bdis_tmout = 0; + langwell_otg_add_timer(a_aidl_bdis_tmr); + langwell_otg_loc_sof(0); + langwell->otg.state = OTG_STATE_A_SUSPEND; + } else if (!langwell->hsm.b_conn || !langwell->hsm.a_bus_req) { + langwell->hsm.a_wait_bcon_tmout = 0; + langwell->hsm.a_set_b_hnp_en = 0; + langwell_otg_add_timer(a_wait_bcon_tmr); + langwell->otg.state = OTG_STATE_A_WAIT_BCON; + } + break; + case OTG_STATE_A_SUSPEND: + if (langwell->hsm.id) { + langwell_otg_del_timer(a_aidl_bdis_tmr); + langwell_otg_HABA(0); + free_irq(langwell->pdev->irq, langwell->regs); + langwell->otg.default_a = 0; + langwell->hsm.b_bus_req = 0; + if (langwell->host_ops) + langwell->host_ops->remove(langwell->pdev); + else + otg_dbg("host driver has been removed.\n"); + langwell_otg_drv_vbus(0); + langwell->otg.state = OTG_STATE_B_IDLE; + queue_work(langwell->qwork, &langwell->work); + } else if (langwell->hsm.a_bus_req || + langwell->hsm.b_bus_resume) { + langwell_otg_del_timer(a_aidl_bdis_tmr); + langwell_otg_HABA(0); + free_irq(langwell->pdev->irq, langwell->regs); + langwell->hsm.a_suspend_req = 0; + langwell_otg_loc_sof(1); + langwell->otg.state = OTG_STATE_A_HOST; + } else if (langwell->hsm.a_aidl_bdis_tmout || + langwell->hsm.a_bus_drop) { + langwell_otg_del_timer(a_aidl_bdis_tmr); + langwell_otg_HABA(0); + free_irq(langwell->pdev->irq, langwell->regs); + if (langwell->host_ops) + langwell->host_ops->remove(langwell->pdev); + else + otg_dbg("host driver has been removed.\n"); + langwell_otg_drv_vbus(0); + langwell->otg.state = OTG_STATE_A_WAIT_VFALL; + } else if (!langwell->hsm.b_conn && + langwell->hsm.a_set_b_hnp_en) { + langwell_otg_del_timer(a_aidl_bdis_tmr); + langwell_otg_HABA(0); + free_irq(langwell->pdev->irq, langwell->regs); + + if (langwell->host_ops) + langwell->host_ops->remove(langwell->pdev); + else + otg_dbg("host driver has been removed.\n"); + + langwell->hsm.b_bus_suspend = 0; + langwell->hsm.b_bus_suspend_vld = 0; + langwell->hsm.b_bus_suspend_tmout = 0; + + /* msleep(200); */ + if (langwell->client_ops) + langwell->client_ops->resume(langwell->pdev); + else + otg_dbg("client driver not loaded.\n"); + + langwell_otg_add_timer(b_bus_suspend_tmr); + langwell->otg.state = OTG_STATE_A_PERIPHERAL; + break; + } else if (!langwell->hsm.a_vbus_vld) { + langwell_otg_del_timer(a_aidl_bdis_tmr); + langwell_otg_HABA(0); + free_irq(langwell->pdev->irq, langwell->regs); + if (langwell->host_ops) + langwell->host_ops->remove(langwell->pdev); + else + otg_dbg("host driver has been removed.\n"); + langwell_otg_drv_vbus(0); + langwell->otg.state = OTG_STATE_A_VBUS_ERR; + } + break; + case OTG_STATE_A_PERIPHERAL: + if (langwell->hsm.id) { + langwell_otg_del_timer(b_bus_suspend_tmr); + langwell->otg.default_a = 0; + langwell->hsm.b_bus_req = 0; + if (langwell->client_ops) + langwell->client_ops->suspend(langwell->pdev, + PMSG_FREEZE); + else + otg_dbg("client driver has been removed.\n"); + langwell_otg_drv_vbus(0); + langwell->otg.state = OTG_STATE_B_IDLE; + queue_work(langwell->qwork, &langwell->work); + } else if (!langwell->hsm.a_vbus_vld) { + langwell_otg_del_timer(b_bus_suspend_tmr); + if (langwell->client_ops) + langwell->client_ops->suspend(langwell->pdev, + PMSG_FREEZE); + else + otg_dbg("client driver has been removed.\n"); + langwell_otg_drv_vbus(0); + langwell->otg.state = OTG_STATE_A_VBUS_ERR; + } else if (langwell->hsm.a_bus_drop) { + langwell_otg_del_timer(b_bus_suspend_tmr); + if (langwell->client_ops) + langwell->client_ops->suspend(langwell->pdev, + PMSG_FREEZE); + else + otg_dbg("client driver has been removed.\n"); + langwell_otg_drv_vbus(0); + langwell->otg.state = OTG_STATE_A_WAIT_VFALL; + } else if (langwell->hsm.b_bus_suspend) { + langwell_otg_del_timer(b_bus_suspend_tmr); + if (langwell->client_ops) + langwell->client_ops->suspend(langwell->pdev, + PMSG_FREEZE); + else + otg_dbg("client driver has been removed.\n"); + + if (langwell->host_ops) + langwell->host_ops->probe(langwell->pdev, + langwell->host_ops->id_table); + else + otg_dbg("host driver not loaded.\n"); + langwell->hsm.a_set_b_hnp_en = 0; + langwell->hsm.a_wait_bcon_tmout = 0; + langwell_otg_add_timer(a_wait_bcon_tmr); + langwell->otg.state = OTG_STATE_A_WAIT_BCON; + } else if (langwell->hsm.b_bus_suspend_tmout) { + u32 val; + val = readl(langwell->regs + CI_PORTSC1); + if (!(val & PORTSC_SUSP)) + break; + if (langwell->client_ops) + langwell->client_ops->suspend(langwell->pdev, + PMSG_FREEZE); + else + otg_dbg("client driver has been removed.\n"); + if (langwell->host_ops) + langwell->host_ops->probe(langwell->pdev, + langwell->host_ops->id_table); + else + otg_dbg("host driver not loaded.\n"); + langwell->hsm.a_set_b_hnp_en = 0; + langwell->hsm.a_wait_bcon_tmout = 0; + langwell_otg_add_timer(a_wait_bcon_tmr); + langwell->otg.state = OTG_STATE_A_WAIT_BCON; + } + break; + case OTG_STATE_A_VBUS_ERR: + if (langwell->hsm.id) { + langwell->otg.default_a = 0; + langwell->hsm.a_clr_err = 0; + langwell->hsm.a_srp_det = 0; + langwell->otg.state = OTG_STATE_B_IDLE; + queue_work(langwell->qwork, &langwell->work); + } else if (langwell->hsm.a_clr_err) { + langwell->hsm.a_clr_err = 0; + langwell->hsm.a_srp_det = 0; + reset_otg(); + init_hsm(); + if (langwell->otg.state == OTG_STATE_A_IDLE) + queue_work(langwell->qwork, &langwell->work); + } + break; + case OTG_STATE_A_WAIT_VFALL: + if (langwell->hsm.id) { + langwell->otg.default_a = 0; + langwell->otg.state = OTG_STATE_B_IDLE; + queue_work(langwell->qwork, &langwell->work); + } else if (langwell->hsm.a_bus_req) { + langwell_otg_drv_vbus(1); + langwell->hsm.a_wait_vrise_tmout = 0; + langwell_otg_add_timer(a_wait_vrise_tmr); + langwell->otg.state = OTG_STATE_A_WAIT_VRISE; + } else if (!langwell->hsm.a_sess_vld) { + langwell->hsm.a_srp_det = 0; + langwell_otg_drv_vbus(0); + set_host_mode(); + langwell->otg.state = OTG_STATE_A_IDLE; + } + break; + default: + ; + } + + otg_dbg("%s: new state = %s\n", __func__, + state_string(langwell->otg.state)); +} + + static ssize_t +show_registers(struct device *_dev, struct device_attribute *attr, char *buf) +{ + struct langwell_otg *langwell; + char *next; + unsigned size; + unsigned t; + + langwell = the_transceiver; + next = buf; + size = PAGE_SIZE; + + t = scnprintf(next, size, + "\n" + "USBCMD = 0x%08x \n" + "USBSTS = 0x%08x \n" + "USBINTR = 0x%08x \n" + "ASYNCLISTADDR = 0x%08x \n" + "PORTSC1 = 0x%08x \n" + "HOSTPC1 = 0x%08x \n" + "OTGSC = 0x%08x \n" + "USBMODE = 0x%08x \n", + readl(langwell->regs + 0x30), + readl(langwell->regs + 0x34), + readl(langwell->regs + 0x38), + readl(langwell->regs + 0x48), + readl(langwell->regs + 0x74), + readl(langwell->regs + 0xb4), + readl(langwell->regs + 0xf4), + readl(langwell->regs + 0xf8) + ); + size -= t; + next += t; + + return PAGE_SIZE - size; +} +static DEVICE_ATTR(registers, S_IRUGO, show_registers, NULL); + +static ssize_t +show_hsm(struct device *_dev, struct device_attribute *attr, char *buf) +{ + struct langwell_otg *langwell; + char *next; + unsigned size; + unsigned t; + + langwell = the_transceiver; + next = buf; + size = PAGE_SIZE; + + t = scnprintf(next, size, + "\n" + "current state = %s\n" + "a_bus_resume = \t%d\n" + "a_bus_suspend = \t%d\n" + "a_conn = \t%d\n" + "a_sess_vld = \t%d\n" + "a_srp_det = \t%d\n" + "a_vbus_vld = \t%d\n" + "b_bus_resume = \t%d\n" + "b_bus_suspend = \t%d\n" + "b_conn = \t%d\n" + "b_se0_srp = \t%d\n" + "b_sess_end = \t%d\n" + "b_sess_vld = \t%d\n" + "id = \t%d\n" + "a_set_b_hnp_en = \t%d\n" + "b_srp_done = \t%d\n" + "b_hnp_enable = \t%d\n" + "a_wait_vrise_tmout = \t%d\n" + "a_wait_bcon_tmout = \t%d\n" + "a_aidl_bdis_tmout = \t%d\n" + "b_ase0_brst_tmout = \t%d\n" + "a_bus_drop = \t%d\n" + "a_bus_req = \t%d\n" + "a_clr_err = \t%d\n" + "a_suspend_req = \t%d\n" + "b_bus_req = \t%d\n" + "b_bus_suspend_tmout = \t%d\n" + "b_bus_suspend_vld = \t%d\n", + state_string(langwell->otg.state), + langwell->hsm.a_bus_resume, + langwell->hsm.a_bus_suspend, + langwell->hsm.a_conn, + langwell->hsm.a_sess_vld, + langwell->hsm.a_srp_det, + langwell->hsm.a_vbus_vld, + langwell->hsm.b_bus_resume, + langwell->hsm.b_bus_suspend, + langwell->hsm.b_conn, + langwell->hsm.b_se0_srp, + langwell->hsm.b_sess_end, + langwell->hsm.b_sess_vld, + langwell->hsm.id, + langwell->hsm.a_set_b_hnp_en, + langwell->hsm.b_srp_done, + langwell->hsm.b_hnp_enable, + langwell->hsm.a_wait_vrise_tmout, + langwell->hsm.a_wait_bcon_tmout, + langwell->hsm.a_aidl_bdis_tmout, + langwell->hsm.b_ase0_brst_tmout, + langwell->hsm.a_bus_drop, + langwell->hsm.a_bus_req, + langwell->hsm.a_clr_err, + langwell->hsm.a_suspend_req, + langwell->hsm.b_bus_req, + langwell->hsm.b_bus_suspend_tmout, + langwell->hsm.b_bus_suspend_vld + ); + size -= t; + next += t; + + return PAGE_SIZE - size; +} +static DEVICE_ATTR(hsm, S_IRUGO, show_hsm, NULL); + +static ssize_t +get_a_bus_req(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct langwell_otg *langwell; + char *next; + unsigned size; + unsigned t; + + langwell = the_transceiver; + next = buf; + size = PAGE_SIZE; + + t = scnprintf(next, size, "%d", langwell->hsm.a_bus_req); + size -= t; + next += t; + + return PAGE_SIZE - size; +} + +static ssize_t +set_a_bus_req(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct langwell_otg *langwell; + langwell = the_transceiver; + if (!langwell->otg.default_a) + return -1; + if (count > 2) + return -1; + + if (buf[0] == '0') { + langwell->hsm.a_bus_req = 0; + otg_dbg("a_bus_req = 0\n"); + } else if (buf[0] == '1') { + /* If a_bus_drop is TRUE, a_bus_req can't be set */ + if (langwell->hsm.a_bus_drop) + return -1; + langwell->hsm.a_bus_req = 1; + otg_dbg("a_bus_req = 1\n"); + } + if (spin_trylock(&langwell->wq_lock)) { + queue_work(langwell->qwork, &langwell->work); + spin_unlock(&langwell->wq_lock); + } + return count; +} +static DEVICE_ATTR(a_bus_req, S_IRUGO | S_IWUGO, get_a_bus_req, set_a_bus_req); + +static ssize_t +get_a_bus_drop(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct langwell_otg *langwell; + char *next; + unsigned size; + unsigned t; + + langwell = the_transceiver; + next = buf; + size = PAGE_SIZE; + + t = scnprintf(next, size, "%d", langwell->hsm.a_bus_drop); + size -= t; + next += t; + + return PAGE_SIZE - size; +} + +static ssize_t +set_a_bus_drop(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct langwell_otg *langwell; + langwell = the_transceiver; + if (!langwell->otg.default_a) + return -1; + if (count > 2) + return -1; + + if (buf[0] == '0') { + langwell->hsm.a_bus_drop = 0; + otg_dbg("a_bus_drop = 0\n"); + } else if (buf[0] == '1') { + langwell->hsm.a_bus_drop = 1; + langwell->hsm.a_bus_req = 0; + otg_dbg("a_bus_drop = 1, then a_bus_req = 0\n"); + } + if (spin_trylock(&langwell->wq_lock)) { + queue_work(langwell->qwork, &langwell->work); + spin_unlock(&langwell->wq_lock); + } + return count; +} +static DEVICE_ATTR(a_bus_drop, S_IRUGO | S_IWUGO, + get_a_bus_drop, set_a_bus_drop); + +static ssize_t +get_b_bus_req(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct langwell_otg *langwell; + char *next; + unsigned size; + unsigned t; + + langwell = the_transceiver; + next = buf; + size = PAGE_SIZE; + + t = scnprintf(next, size, "%d", langwell->hsm.b_bus_req); + size -= t; + next += t; + + return PAGE_SIZE - size; +} + +static ssize_t +set_b_bus_req(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct langwell_otg *langwell; + langwell = the_transceiver; + + if (langwell->otg.default_a) + return -1; + + if (count > 2) + return -1; + + if (buf[0] == '0') { + langwell->hsm.b_bus_req = 0; + otg_dbg("b_bus_req = 0\n"); + } else if (buf[0] == '1') { + langwell->hsm.b_bus_req = 1; + otg_dbg("b_bus_req = 1\n"); + } + if (spin_trylock(&langwell->wq_lock)) { + queue_work(langwell->qwork, &langwell->work); + spin_unlock(&langwell->wq_lock); + } + return count; +} +static DEVICE_ATTR(b_bus_req, S_IRUGO | S_IWUGO, get_b_bus_req, set_b_bus_req); + +static ssize_t +set_a_clr_err(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct langwell_otg *langwell; + langwell = the_transceiver; + + if (!langwell->otg.default_a) + return -1; + if (count > 2) + return -1; + + if (buf[0] == '1') { + langwell->hsm.a_clr_err = 1; + otg_dbg("a_clr_err = 1\n"); + } + if (spin_trylock(&langwell->wq_lock)) { + queue_work(langwell->qwork, &langwell->work); + spin_unlock(&langwell->wq_lock); + } + return count; +} +static DEVICE_ATTR(a_clr_err, S_IWUGO, NULL, set_a_clr_err); + +static struct attribute *inputs_attrs[] = { + &dev_attr_a_bus_req.attr, + &dev_attr_a_bus_drop.attr, + &dev_attr_b_bus_req.attr, + &dev_attr_a_clr_err.attr, + NULL, +}; + +static struct attribute_group debug_dev_attr_group = { + .name = "inputs", + .attrs = inputs_attrs, +}; + +int langwell_register_host(struct pci_driver *host_driver) +{ + int ret = 0; + + the_transceiver->host_ops = host_driver; + queue_work(the_transceiver->qwork, &the_transceiver->work); + otg_dbg("host controller driver is registered\n"); + + return ret; +} +EXPORT_SYMBOL(langwell_register_host); + +void langwell_unregister_host(struct pci_driver *host_driver) +{ + if (the_transceiver->host_ops) + the_transceiver->host_ops->remove(the_transceiver->pdev); + the_transceiver->host_ops = NULL; + the_transceiver->hsm.a_bus_drop = 1; + queue_work(the_transceiver->qwork, &the_transceiver->work); + otg_dbg("host controller driver is unregistered\n"); +} +EXPORT_SYMBOL(langwell_unregister_host); + +int langwell_register_peripheral(struct pci_driver *client_driver) +{ + int ret = 0; + + if (client_driver) + ret = client_driver->probe(the_transceiver->pdev, + client_driver->id_table); + if (!ret) { + the_transceiver->client_ops = client_driver; + queue_work(the_transceiver->qwork, &the_transceiver->work); + otg_dbg("client controller driver is registered\n"); + } + + return ret; +} +EXPORT_SYMBOL(langwell_register_peripheral); + +void langwell_unregister_peripheral(struct pci_driver *client_driver) +{ + if (the_transceiver->client_ops) + the_transceiver->client_ops->remove(the_transceiver->pdev); + the_transceiver->client_ops = NULL; + the_transceiver->hsm.b_bus_req = 0; + queue_work(the_transceiver->qwork, &the_transceiver->work); + otg_dbg("client controller driver is unregistered\n"); +} +EXPORT_SYMBOL(langwell_unregister_peripheral); + +static int langwell_otg_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + unsigned long resource, len; + void __iomem *base = NULL; + int retval; + u32 val32; + struct langwell_otg *langwell; + char qname[] = "langwell_otg_queue"; + + retval = 0; + otg_dbg("\notg controller is detected.\n"); + if (pci_enable_device(pdev) < 0) { + retval = -ENODEV; + goto done; + } + + langwell = kzalloc(sizeof *langwell, GFP_KERNEL); + if (langwell == NULL) { + retval = -ENOMEM; + goto done; + } + the_transceiver = langwell; + + /* control register: BAR 0 */ + resource = pci_resource_start(pdev, 0); + len = pci_resource_len(pdev, 0); + if (!request_mem_region(resource, len, driver_name)) { + retval = -EBUSY; + goto err; + } + langwell->region = 1; + + base = ioremap_nocache(resource, len); + if (base == NULL) { + retval = -EFAULT; + goto err; + } + langwell->regs = base; + + if (!pdev->irq) { + otg_dbg("No IRQ.\n"); + retval = -ENODEV; + goto err; + } + + langwell->qwork = create_workqueue(qname); + if (!langwell->qwork) { + otg_dbg("cannot create workqueue %s\n", qname); + retval = -ENOMEM; + goto err; + } + INIT_WORK(&langwell->work, langwell_otg_work); + + /* OTG common part */ + langwell->pdev = pdev; + langwell->otg.dev = &pdev->dev; + langwell->otg.label = driver_name; + langwell->otg.set_host = langwell_otg_set_host; + langwell->otg.set_peripheral = langwell_otg_set_peripheral; + langwell->otg.set_power = langwell_otg_set_power; + langwell->otg.start_srp = langwell_otg_start_srp; + langwell->otg.state = OTG_STATE_UNDEFINED; + if (otg_set_transceiver(&langwell->otg)) { + otg_dbg("can't set transceiver\n"); + retval = -EBUSY; + goto err; + } + + reset_otg(); + init_hsm(); + + spin_lock_init(&langwell->lock); + spin_lock_init(&langwell->wq_lock); + INIT_LIST_HEAD(&active_timers); + langwell_otg_init_timers(&langwell->hsm); + + if (request_irq(pdev->irq, otg_irq, IRQF_SHARED, + driver_name, langwell) != 0) { + otg_dbg("request interrupt %d failed\n", pdev->irq); + retval = -EBUSY; + goto err; + } + + /* enable OTGSC int */ + val32 = OTGSC_DPIE | OTGSC_BSEIE | OTGSC_BSVIE | + OTGSC_ASVIE | OTGSC_AVVIE | OTGSC_IDIE | OTGSC_IDPU; + writel(val32, langwell->regs + CI_OTGSC); + + retval = device_create_file(&pdev->dev, &dev_attr_registers); + if (retval < 0) { + otg_dbg("Can't register sysfs attribute: %d\n", retval); + goto err; + } + + retval = device_create_file(&pdev->dev, &dev_attr_hsm); + if (retval < 0) { + otg_dbg("Can't hsm sysfs attribute: %d\n", retval); + goto err; + } + + retval = sysfs_create_group(&pdev->dev.kobj, &debug_dev_attr_group); + if (retval < 0) { + otg_dbg("Can't register sysfs attr group: %d\n", retval); + goto err; + } + + if (langwell->otg.state == OTG_STATE_A_IDLE) + queue_work(langwell->qwork, &langwell->work); + + return 0; + +err: + if (the_transceiver) + langwell_otg_remove(pdev); +done: + return retval; +} + +static void langwell_otg_remove(struct pci_dev *pdev) +{ + struct langwell_otg *langwell; + + langwell = the_transceiver; + + if (langwell->qwork) { + flush_workqueue(langwell->qwork); + destroy_workqueue(langwell->qwork); + } + langwell_otg_free_timers(); + + /* disable OTGSC interrupt as OTGSC doesn't change in reset */ + writel(0, langwell->regs + CI_OTGSC); + + if (pdev->irq) + free_irq(pdev->irq, langwell); + if (langwell->regs) + iounmap(langwell->regs); + if (langwell->region) + release_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + + otg_set_transceiver(NULL); + pci_disable_device(pdev); + sysfs_remove_group(&pdev->dev.kobj, &debug_dev_attr_group); + device_remove_file(&pdev->dev, &dev_attr_hsm); + device_remove_file(&pdev->dev, &dev_attr_registers); + kfree(langwell); + langwell = NULL; +} + +static void transceiver_suspend(struct pci_dev *pdev) +{ + pci_save_state(pdev); + pci_set_power_state(pdev, PCI_D3hot); + langwell_otg_phy_low_power(1); +} + +static int langwell_otg_suspend(struct pci_dev *pdev, pm_message_t message) +{ + int ret = 0; + struct langwell_otg *langwell; + + langwell = the_transceiver; + + /* Disbale OTG interrupts */ + langwell_otg_intr(0); + + if (pdev->irq) + free_irq(pdev->irq, langwell); + + /* Prevent more otg_work */ + flush_workqueue(langwell->qwork); + spin_lock(&langwell->wq_lock); + + /* start actions */ + switch (langwell->otg.state) { + case OTG_STATE_A_IDLE: + case OTG_STATE_B_IDLE: + case OTG_STATE_A_WAIT_VFALL: + case OTG_STATE_A_VBUS_ERR: + transceiver_suspend(pdev); + break; + case OTG_STATE_A_WAIT_VRISE: + langwell_otg_del_timer(a_wait_vrise_tmr); + langwell->hsm.a_srp_det = 0; + langwell_otg_drv_vbus(0); + langwell->otg.state = OTG_STATE_A_IDLE; + transceiver_suspend(pdev); + break; + case OTG_STATE_A_WAIT_BCON: + langwell_otg_del_timer(a_wait_bcon_tmr); + if (langwell->host_ops) + ret = langwell->host_ops->suspend(pdev, message); + langwell_otg_drv_vbus(0); + break; + case OTG_STATE_A_HOST: + if (langwell->host_ops) + ret = langwell->host_ops->suspend(pdev, message); + langwell_otg_drv_vbus(0); + langwell_otg_phy_low_power(1); + break; + case OTG_STATE_A_SUSPEND: + langwell_otg_del_timer(a_aidl_bdis_tmr); + langwell_otg_HABA(0); + if (langwell->host_ops) + langwell->host_ops->remove(pdev); + else + otg_dbg("host driver has been removed.\n"); + langwell_otg_drv_vbus(0); + transceiver_suspend(pdev); + langwell->otg.state = OTG_STATE_A_WAIT_VFALL; + break; + case OTG_STATE_A_PERIPHERAL: + if (langwell->client_ops) + ret = langwell->client_ops->suspend(pdev, message); + else + otg_dbg("client driver has been removed.\n"); + langwell_otg_drv_vbus(0); + transceiver_suspend(pdev); + langwell->otg.state = OTG_STATE_A_WAIT_VFALL; + break; + case OTG_STATE_B_HOST: + if (langwell->host_ops) + langwell->host_ops->remove(pdev); + else + otg_dbg("host driver has been removed.\n"); + langwell->hsm.b_bus_req = 0; + transceiver_suspend(pdev); + langwell->otg.state = OTG_STATE_B_IDLE; + break; + case OTG_STATE_B_PERIPHERAL: + if (langwell->client_ops) + ret = langwell->client_ops->suspend(pdev, message); + else + otg_dbg("client driver has been removed.\n"); + break; + case OTG_STATE_B_WAIT_ACON: + langwell_otg_del_timer(b_ase0_brst_tmr); + langwell_otg_HAAR(0); + if (langwell->host_ops) + langwell->host_ops->remove(pdev); + else + otg_dbg("host driver has been removed.\n"); + langwell->hsm.b_bus_req = 0; + langwell->otg.state = OTG_STATE_B_IDLE; + transceiver_suspend(pdev); + break; + default: + otg_dbg("error state before suspend\n "); + break; + } + spin_unlock(&langwell->wq_lock); + + return ret; +} + +static void transceiver_resume(struct pci_dev *pdev) +{ + pci_restore_state(pdev); + pci_set_power_state(pdev, PCI_D0); + langwell_otg_phy_low_power(0); +} + +static int langwell_otg_resume(struct pci_dev *pdev) +{ + int ret = 0; + struct langwell_otg *langwell; + + langwell = the_transceiver; + + spin_lock(&langwell->wq_lock); + + switch (langwell->otg.state) { + case OTG_STATE_A_IDLE: + case OTG_STATE_B_IDLE: + case OTG_STATE_A_WAIT_VFALL: + case OTG_STATE_A_VBUS_ERR: + transceiver_resume(pdev); + break; + case OTG_STATE_A_WAIT_BCON: + langwell_otg_add_timer(a_wait_bcon_tmr); + langwell_otg_drv_vbus(1); + if (langwell->host_ops) + ret = langwell->host_ops->resume(pdev); + break; + case OTG_STATE_A_HOST: + langwell_otg_drv_vbus(1); + langwell_otg_phy_low_power(0); + if (langwell->host_ops) + ret = langwell->host_ops->resume(pdev); + break; + case OTG_STATE_B_PERIPHERAL: + if (langwell->client_ops) + ret = langwell->client_ops->resume(pdev); + else + otg_dbg("client driver not loaded.\n"); + break; + default: + otg_dbg("error state before suspend\n "); + break; + } + + if (request_irq(pdev->irq, otg_irq, IRQF_SHARED, + driver_name, the_transceiver) != 0) { + otg_dbg("request interrupt %d failed\n", pdev->irq); + ret = -EBUSY; + } + + /* enable OTG interrupts */ + langwell_otg_intr(1); + + spin_unlock(&langwell->wq_lock); + + queue_work(langwell->qwork, &langwell->work); + + + return ret; +} + +static int __init langwell_otg_init(void) +{ + return pci_register_driver(&otg_pci_driver); +} +module_init(langwell_otg_init); + +static void __exit langwell_otg_cleanup(void) +{ + pci_unregister_driver(&otg_pci_driver); +} +module_exit(langwell_otg_cleanup); diff --git a/drivers/usb/otg/nop-usb-xceiv.c b/drivers/usb/otg/nop-usb-xceiv.c index c567168f89af..9ed5ea568679 100644 --- a/drivers/usb/otg/nop-usb-xceiv.c +++ b/drivers/usb/otg/nop-usb-xceiv.c @@ -22,8 +22,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Current status: - * this is to add "nop" transceiver for all those phy which is - * autonomous such as isp1504 etc. + * This provides a "nop" transceiver for PHYs which are + * autonomous such as isp1504, isp1707, etc. */ #include @@ -36,30 +36,25 @@ struct nop_usb_xceiv { struct device *dev; }; -static u64 nop_xceiv_dmamask = DMA_BIT_MASK(32); - -static struct platform_device nop_xceiv_device = { - .name = "nop_usb_xceiv", - .id = -1, - .dev = { - .dma_mask = &nop_xceiv_dmamask, - .coherent_dma_mask = DMA_BIT_MASK(32), - .platform_data = NULL, - }, -}; +static struct platform_device *pd; void usb_nop_xceiv_register(void) { - if (platform_device_register(&nop_xceiv_device) < 0) { + if (pd) + return; + pd = platform_device_register_simple("nop_usb_xceiv", -1, NULL, 0); + if (!pd) { printk(KERN_ERR "Unable to register usb nop transceiver\n"); return; } } +EXPORT_SYMBOL(usb_nop_xceiv_register); void usb_nop_xceiv_unregister(void) { - platform_device_unregister(&nop_xceiv_device); + platform_device_unregister(pd); } +EXPORT_SYMBOL(usb_nop_xceiv_unregister); static inline struct nop_usb_xceiv *xceiv_to_nop(struct otg_transceiver *x) { diff --git a/drivers/usb/otg/twl4030-usb.c b/drivers/usb/otg/twl4030-usb.c index d9478d0e1c8b..9e3e7a5c258b 100644 --- a/drivers/usb/otg/twl4030-usb.c +++ b/drivers/usb/otg/twl4030-usb.c @@ -217,6 +217,7 @@ /* In module TWL4030_MODULE_PM_MASTER */ #define PROTECT_KEY 0x0E +#define STS_HW_CONDITIONS 0x0F /* In module TWL4030_MODULE_PM_RECEIVER */ #define VUSB_DEDICATED1 0x7D @@ -351,15 +352,26 @@ static enum linkstat twl4030_usb_linkstat(struct twl4030_usb *twl) int status; int linkstat = USB_LINK_UNKNOWN; - /* STS_HW_CONDITIONS */ - status = twl4030_readb(twl, TWL4030_MODULE_PM_MASTER, 0x0f); + /* + * For ID/VBUS sensing, see manual section 15.4.8 ... + * except when using only battery backup power, two + * comparators produce VBUS_PRES and ID_PRES signals, + * which don't match docs elsewhere. But ... BIT(7) + * and BIT(2) of STS_HW_CONDITIONS, respectively, do + * seem to match up. If either is true the USB_PRES + * signal is active, the OTG module is activated, and + * its interrupt may be raised (may wake the system). + */ + status = twl4030_readb(twl, TWL4030_MODULE_PM_MASTER, + STS_HW_CONDITIONS); if (status < 0) dev_err(twl->dev, "USB link status err %d\n", status); - else if (status & BIT(7)) - linkstat = USB_LINK_VBUS; - else if (status & BIT(2)) - linkstat = USB_LINK_ID; - else + else if (status & (BIT(7) | BIT(2))) { + if (status & BIT(2)) + linkstat = USB_LINK_ID; + else + linkstat = USB_LINK_VBUS; + } else linkstat = USB_LINK_NONE; dev_dbg(twl->dev, "HW_CONDITIONS 0x%02x/%d; link %d\n", @@ -641,7 +653,7 @@ static int twl4030_set_host(struct otg_transceiver *x, struct usb_bus *host) return 0; } -static int __init twl4030_usb_probe(struct platform_device *pdev) +static int __devinit twl4030_usb_probe(struct platform_device *pdev) { struct twl4030_usb_data *pdata = pdev->dev.platform_data; struct twl4030_usb *twl; diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c index 6d106e74265e..2cbfab3716e5 100644 --- a/drivers/usb/serial/aircable.c +++ b/drivers/usb/serial/aircable.c @@ -364,7 +364,7 @@ static int aircable_attach(struct usb_serial *serial) return 0; } -static void aircable_shutdown(struct usb_serial *serial) +static void aircable_release(struct usb_serial *serial) { struct usb_serial_port *port = serial->port[0]; @@ -375,7 +375,6 @@ static void aircable_shutdown(struct usb_serial *serial) if (priv) { serial_buf_free(priv->tx_buf); serial_buf_free(priv->rx_buf); - usb_set_serial_port_data(port, NULL); kfree(priv); } } @@ -601,7 +600,7 @@ static struct usb_serial_driver aircable_device = { .num_ports = 1, .attach = aircable_attach, .probe = aircable_probe, - .shutdown = aircable_shutdown, + .release = aircable_release, .write = aircable_write, .write_room = aircable_write_room, .write_bulk_callback = aircable_write_bulk_callback, diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c index b7eacad4d48c..7033b031b443 100644 --- a/drivers/usb/serial/belkin_sa.c +++ b/drivers/usb/serial/belkin_sa.c @@ -90,11 +90,10 @@ static int debug; /* function prototypes for a Belkin USB Serial Adapter F5U103 */ static int belkin_sa_startup(struct usb_serial *serial); -static void belkin_sa_shutdown(struct usb_serial *serial); +static void belkin_sa_release(struct usb_serial *serial); static int belkin_sa_open(struct tty_struct *tty, struct usb_serial_port *port, struct file *filp); -static void belkin_sa_close(struct tty_struct *tty, - struct usb_serial_port *port, struct file *filp); +static void belkin_sa_close(struct usb_serial_port *port); static void belkin_sa_read_int_callback(struct urb *urb); static void belkin_sa_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios * old); @@ -143,7 +142,7 @@ static struct usb_serial_driver belkin_device = { .tiocmget = belkin_sa_tiocmget, .tiocmset = belkin_sa_tiocmset, .attach = belkin_sa_startup, - .shutdown = belkin_sa_shutdown, + .release = belkin_sa_release, }; @@ -198,14 +197,13 @@ static int belkin_sa_startup(struct usb_serial *serial) } -static void belkin_sa_shutdown(struct usb_serial *serial) +static void belkin_sa_release(struct usb_serial *serial) { struct belkin_sa_private *priv; int i; dbg("%s", __func__); - /* stop reads and writes on all ports */ for (i = 0; i < serial->num_ports; ++i) { /* My special items, the standard routines free my urbs */ priv = usb_get_serial_port_data(serial->port[i]); @@ -244,8 +242,7 @@ exit: } /* belkin_sa_open */ -static void belkin_sa_close(struct tty_struct *tty, - struct usb_serial_port *port, struct file *filp) +static void belkin_sa_close(struct usb_serial_port *port) { dbg("%s port %d", __func__, port->number); diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c index 83bbb5bca2ef..ba555c528cc6 100644 --- a/drivers/usb/serial/bus.c +++ b/drivers/usb/serial/bus.c @@ -59,23 +59,22 @@ static int usb_serial_device_probe(struct device *dev) retval = -ENODEV; goto exit; } + if (port->dev_state != PORT_REGISTERING) + goto exit; driver = port->serial->type; if (driver->port_probe) { - if (!try_module_get(driver->driver.owner)) { - dev_err(dev, "module get failed, exiting\n"); - retval = -EIO; - goto exit; - } retval = driver->port_probe(port); - module_put(driver->driver.owner); if (retval) goto exit; } retval = device_create_file(dev, &dev_attr_port_number); - if (retval) + if (retval) { + if (driver->port_remove) + retval = driver->port_remove(port); goto exit; + } minor = port->number; tty_register_device(usb_serial_tty_driver, minor, dev); @@ -98,19 +97,15 @@ static int usb_serial_device_remove(struct device *dev) if (!port) return -ENODEV; + if (port->dev_state != PORT_UNREGISTERING) + return retval; + device_remove_file(&port->dev, &dev_attr_port_number); driver = port->serial->type; - if (driver->port_remove) { - if (!try_module_get(driver->driver.owner)) { - dev_err(dev, "module get failed, exiting\n"); - retval = -EIO; - goto exit; - } + if (driver->port_remove) retval = driver->port_remove(port); - module_put(driver->driver.owner); - } -exit: + minor = port->number; tty_unregister_device(usb_serial_tty_driver, minor); dev_info(dev, "%s converter now disconnected from ttyUSB%d\n", diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c index ab4cc277aa65..2830766f5b39 100644 --- a/drivers/usb/serial/ch341.c +++ b/drivers/usb/serial/ch341.c @@ -262,13 +262,33 @@ error: kfree(priv); return r; } -static void ch341_close(struct tty_struct *tty, struct usb_serial_port *port, - struct file *filp) +static int ch341_carrier_raised(struct usb_serial_port *port) +{ + struct ch341_private *priv = usb_get_serial_port_data(port); + if (priv->line_status & CH341_BIT_DCD) + return 1; + return 0; +} + +static void ch341_dtr_rts(struct usb_serial_port *port, int on) { struct ch341_private *priv = usb_get_serial_port_data(port); unsigned long flags; - unsigned int c_cflag; + dbg("%s - port %d", __func__, port->number); + /* drop DTR and RTS */ + spin_lock_irqsave(&priv->lock, flags); + if (on) + priv->line_control |= CH341_BIT_RTS | CH341_BIT_DTR; + else + priv->line_control &= ~(CH341_BIT_RTS | CH341_BIT_DTR); + spin_unlock_irqrestore(&priv->lock, flags); + ch341_set_handshake(port->serial->dev, priv->line_control); + wake_up_interruptible(&priv->delta_msr_wait); +} + +static void ch341_close(struct usb_serial_port *port) +{ dbg("%s - port %d", __func__, port->number); /* shutdown our urbs */ @@ -276,18 +296,6 @@ static void ch341_close(struct tty_struct *tty, struct usb_serial_port *port, usb_kill_urb(port->write_urb); usb_kill_urb(port->read_urb); usb_kill_urb(port->interrupt_in_urb); - - if (tty) { - c_cflag = tty->termios->c_cflag; - if (c_cflag & HUPCL) { - /* drop DTR and RTS */ - spin_lock_irqsave(&priv->lock, flags); - priv->line_control = 0; - spin_unlock_irqrestore(&priv->lock, flags); - ch341_set_handshake(port->serial->dev, 0); - } - } - wake_up_interruptible(&priv->delta_msr_wait); } @@ -302,7 +310,6 @@ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port, dbg("ch341_open()"); priv->baud_rate = DEFAULT_BAUD_RATE; - priv->line_control = CH341_BIT_RTS | CH341_BIT_DTR; r = ch341_configure(serial->dev, priv); if (r) @@ -322,7 +329,7 @@ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port, if (r) { dev_err(&port->dev, "%s - failed submitting interrupt urb," " error %d\n", __func__, r); - ch341_close(tty, port, NULL); + ch341_close(port); return -EPROTO; } @@ -343,9 +350,6 @@ static void ch341_set_termios(struct tty_struct *tty, dbg("ch341_set_termios()"); - if (!tty || !tty->termios) - return; - baud_rate = tty_get_baud_rate(tty); priv->baud_rate = baud_rate; @@ -568,6 +572,8 @@ static struct usb_serial_driver ch341_device = { .usb_driver = &ch341_driver, .num_ports = 1, .open = ch341_open, + .dtr_rts = ch341_dtr_rts, + .carrier_raised = ch341_carrier_raised, .close = ch341_close, .ioctl = ch341_ioctl, .set_termios = ch341_set_termios, diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c index 19e24045b137..247b61bfb7f4 100644 --- a/drivers/usb/serial/console.c +++ b/drivers/usb/serial/console.c @@ -169,7 +169,9 @@ static int usb_console_setup(struct console *co, char *options) kfree(tty); } } - + /* So we know not to kill the hardware on a hangup on this + port. We have also bumped the use count by one so it won't go + idle */ port->console = 1; retval = 0; @@ -182,7 +184,7 @@ free_tty: kfree(tty); reset_open_count: port->port.count = 0; -goto out; + goto out; } static void usb_console_write(struct console *co, diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index e8d5133ce9c8..2b9eeda62bfe 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -1,5 +1,5 @@ /* - * Silicon Laboratories CP2101/CP2102 USB to RS232 serial adaptor driver + * Silicon Laboratories CP210x USB to RS232 serial adaptor driver * * Copyright (C) 2005 Craig Shelley (craig@microtron.org.uk) * @@ -27,44 +27,46 @@ /* * Version Information */ -#define DRIVER_VERSION "v0.08" -#define DRIVER_DESC "Silicon Labs CP2101/CP2102 RS232 serial adaptor driver" +#define DRIVER_VERSION "v0.09" +#define DRIVER_DESC "Silicon Labs CP210x RS232 serial adaptor driver" /* * Function Prototypes */ -static int cp2101_open(struct tty_struct *, struct usb_serial_port *, +static int cp210x_open(struct tty_struct *, struct usb_serial_port *, struct file *); -static void cp2101_cleanup(struct usb_serial_port *); -static void cp2101_close(struct tty_struct *, struct usb_serial_port *, - struct file*); -static void cp2101_get_termios(struct tty_struct *, +static void cp210x_cleanup(struct usb_serial_port *); +static void cp210x_close(struct usb_serial_port *); +static void cp210x_get_termios(struct tty_struct *, struct usb_serial_port *port); -static void cp2101_get_termios_port(struct usb_serial_port *port, +static void cp210x_get_termios_port(struct usb_serial_port *port, unsigned int *cflagp, unsigned int *baudp); -static void cp2101_set_termios(struct tty_struct *, struct usb_serial_port *, +static void cp210x_set_termios(struct tty_struct *, struct usb_serial_port *, struct ktermios*); -static int cp2101_tiocmget(struct tty_struct *, struct file *); -static int cp2101_tiocmset(struct tty_struct *, struct file *, +static int cp210x_tiocmget(struct tty_struct *, struct file *); +static int cp210x_tiocmset(struct tty_struct *, struct file *, unsigned int, unsigned int); -static int cp2101_tiocmset_port(struct usb_serial_port *port, struct file *, +static int cp210x_tiocmset_port(struct usb_serial_port *port, struct file *, unsigned int, unsigned int); -static void cp2101_break_ctl(struct tty_struct *, int); -static int cp2101_startup(struct usb_serial *); -static void cp2101_shutdown(struct usb_serial *); +static void cp210x_break_ctl(struct tty_struct *, int); +static int cp210x_startup(struct usb_serial *); +static void cp210x_disconnect(struct usb_serial *); static int debug; static struct usb_device_id id_table [] = { { USB_DEVICE(0x0471, 0x066A) }, /* AKTAKOM ACE-1001 cable */ { USB_DEVICE(0x0489, 0xE000) }, /* Pirelli Broadband S.p.A, DP-L10 SIP/GSM Mobile */ + { USB_DEVICE(0x0745, 0x1000) }, /* CipherLab USB CCD Barcode Scanner 1000 */ { USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */ + { USB_DEVICE(0x08FD, 0x000A) }, /* Digianswer A/S , ZigBee/802.15.4 MAC Device */ { USB_DEVICE(0x0FCF, 0x1003) }, /* Dynastream ANT development board */ { USB_DEVICE(0x0FCF, 0x1004) }, /* Dynastream ANT2USB */ { USB_DEVICE(0x0FCF, 0x1006) }, /* Dynastream ANT development board */ { USB_DEVICE(0x10A6, 0xAA26) }, /* Knock-off DCU-11 cable */ { USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */ { USB_DEVICE(0x10B5, 0xAC70) }, /* Nokia CA-42 USB */ + { USB_DEVICE(0x10C4, 0x0F91) }, /* Vstabi */ { USB_DEVICE(0x10C4, 0x800A) }, /* SPORTident BSM7-D-USB main station */ { USB_DEVICE(0x10C4, 0x803B) }, /* Pololu USB-serial converter */ { USB_DEVICE(0x10C4, 0x8053) }, /* Enfora EDG1228 */ @@ -85,10 +87,12 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(0x10C4, 0x81C8) }, /* Lipowsky Industrie Elektronik GmbH, Baby-JTAG */ { USB_DEVICE(0x10C4, 0x81E2) }, /* Lipowsky Industrie Elektronik GmbH, Baby-LIN */ { USB_DEVICE(0x10C4, 0x81E7) }, /* Aerocomm Radio */ + { USB_DEVICE(0x10C4, 0x81F2) }, /* C1007 HF band RFID controller */ { USB_DEVICE(0x10C4, 0x8218) }, /* Lipowsky Industrie Elektronik GmbH, HARP-1 */ { USB_DEVICE(0x10C4, 0x822B) }, /* Modem EDGE(GSM) Comander 2 */ { USB_DEVICE(0x10C4, 0x826B) }, /* Cygnal Integrated Products, Inc., Fasttrax GPS demostration module */ { USB_DEVICE(0x10c4, 0x8293) }, /* Telegesys ETRX2USB */ + { USB_DEVICE(0x10C4, 0x82F9) }, /* Procyon AVS */ { USB_DEVICE(0x10C4, 0x8341) }, /* Siemens MC35PU GPRS Modem */ { USB_DEVICE(0x10C4, 0x83A8) }, /* Amber Wireless AMB2560 */ { USB_DEVICE(0x10C4, 0x846E) }, /* BEI USB Sensor Interface (VCP) */ @@ -99,7 +103,9 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(0x10C4, 0xF003) }, /* Elan Digital Systems USBpulse100 */ { USB_DEVICE(0x10C4, 0xF004) }, /* Elan Digital Systems USBcount50 */ { USB_DEVICE(0x10C5, 0xEA61) }, /* Silicon Labs MobiData GPRS USB Modem */ + { USB_DEVICE(0x10CE, 0xEA6A) }, /* Silicon Labs MobiData GPRS USB Modem 100EU */ { USB_DEVICE(0x13AD, 0x9999) }, /* Baltech card reader */ + { USB_DEVICE(0x1555, 0x0004) }, /* Owen AC4 USB-RS485 Converter */ { USB_DEVICE(0x166A, 0x0303) }, /* Clipsal 5500PCU C-Bus USB interface */ { USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */ { USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */ @@ -108,53 +114,70 @@ static struct usb_device_id id_table [] = { MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver cp2101_driver = { - .name = "cp2101", +static struct usb_driver cp210x_driver = { + .name = "cp210x", .probe = usb_serial_probe, .disconnect = usb_serial_disconnect, .id_table = id_table, .no_dynamic_id = 1, }; -static struct usb_serial_driver cp2101_device = { +static struct usb_serial_driver cp210x_device = { .driver = { .owner = THIS_MODULE, - .name = "cp2101", + .name = "cp210x", }, - .usb_driver = &cp2101_driver, + .usb_driver = &cp210x_driver, .id_table = id_table, .num_ports = 1, - .open = cp2101_open, - .close = cp2101_close, - .break_ctl = cp2101_break_ctl, - .set_termios = cp2101_set_termios, - .tiocmget = cp2101_tiocmget, - .tiocmset = cp2101_tiocmset, - .attach = cp2101_startup, - .shutdown = cp2101_shutdown, + .open = cp210x_open, + .close = cp210x_close, + .break_ctl = cp210x_break_ctl, + .set_termios = cp210x_set_termios, + .tiocmget = cp210x_tiocmget, + .tiocmset = cp210x_tiocmset, + .attach = cp210x_startup, + .disconnect = cp210x_disconnect, }; /* Config request types */ #define REQTYPE_HOST_TO_DEVICE 0x41 #define REQTYPE_DEVICE_TO_HOST 0xc1 -/* Config SET requests. To GET, add 1 to the request number */ -#define CP2101_UART 0x00 /* Enable / Disable */ -#define CP2101_BAUDRATE 0x01 /* (BAUD_RATE_GEN_FREQ / baudrate) */ -#define CP2101_BITS 0x03 /* 0x(0)(databits)(parity)(stopbits) */ -#define CP2101_BREAK 0x05 /* On / Off */ -#define CP2101_CONTROL 0x07 /* Flow control line states */ -#define CP2101_MODEMCTL 0x13 /* Modem controls */ -#define CP2101_CONFIG_6 0x19 /* 6 bytes of config data ??? */ +/* Config request codes */ +#define CP210X_IFC_ENABLE 0x00 +#define CP210X_SET_BAUDDIV 0x01 +#define CP210X_GET_BAUDDIV 0x02 +#define CP210X_SET_LINE_CTL 0x03 +#define CP210X_GET_LINE_CTL 0x04 +#define CP210X_SET_BREAK 0x05 +#define CP210X_IMM_CHAR 0x06 +#define CP210X_SET_MHS 0x07 +#define CP210X_GET_MDMSTS 0x08 +#define CP210X_SET_XON 0x09 +#define CP210X_SET_XOFF 0x0A +#define CP210X_SET_EVENTMASK 0x0B +#define CP210X_GET_EVENTMASK 0x0C +#define CP210X_SET_CHAR 0x0D +#define CP210X_GET_CHARS 0x0E +#define CP210X_GET_PROPS 0x0F +#define CP210X_GET_COMM_STATUS 0x10 +#define CP210X_RESET 0x11 +#define CP210X_PURGE 0x12 +#define CP210X_SET_FLOW 0x13 +#define CP210X_GET_FLOW 0x14 +#define CP210X_EMBED_EVENTS 0x15 +#define CP210X_GET_EVENTSTATE 0x16 +#define CP210X_SET_CHARS 0x19 -/* CP2101_UART */ +/* CP210X_IFC_ENABLE */ #define UART_ENABLE 0x0001 #define UART_DISABLE 0x0000 -/* CP2101_BAUDRATE */ +/* CP210X_(SET|GET)_BAUDDIV */ #define BAUD_RATE_GEN_FREQ 0x384000 -/* CP2101_BITS */ +/* CP210X_(SET|GET)_LINE_CTL */ #define BITS_DATA_MASK 0X0f00 #define BITS_DATA_5 0X0500 #define BITS_DATA_6 0X0600 @@ -174,11 +197,11 @@ static struct usb_serial_driver cp2101_device = { #define BITS_STOP_1_5 0x0001 #define BITS_STOP_2 0x0002 -/* CP2101_BREAK */ +/* CP210X_SET_BREAK */ #define BREAK_ON 0x0000 #define BREAK_OFF 0x0001 -/* CP2101_CONTROL */ +/* CP210X_(SET_MHS|GET_MDMSTS) */ #define CONTROL_DTR 0x0001 #define CONTROL_RTS 0x0002 #define CONTROL_CTS 0x0010 @@ -189,13 +212,13 @@ static struct usb_serial_driver cp2101_device = { #define CONTROL_WRITE_RTS 0x0200 /* - * cp2101_get_config - * Reads from the CP2101 configuration registers + * cp210x_get_config + * Reads from the CP210x configuration registers * 'size' is specified in bytes. * 'data' is a pointer to a pre-allocated array of integers large * enough to hold 'size' bytes (with 4 bytes to each integer) */ -static int cp2101_get_config(struct usb_serial_port *port, u8 request, +static int cp210x_get_config(struct usb_serial_port *port, u8 request, unsigned int *data, int size) { struct usb_serial *serial = port->serial; @@ -211,9 +234,6 @@ static int cp2101_get_config(struct usb_serial_port *port, u8 request, return -ENOMEM; } - /* For get requests, the request number must be incremented */ - request++; - /* Issue the request, attempting to read 'size' bytes */ result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), request, REQTYPE_DEVICE_TO_HOST, 0x0000, @@ -236,12 +256,12 @@ static int cp2101_get_config(struct usb_serial_port *port, u8 request, } /* - * cp2101_set_config - * Writes to the CP2101 configuration registers + * cp210x_set_config + * Writes to the CP210x configuration registers * Values less than 16 bits wide are sent directly * 'size' is specified in bytes. */ -static int cp2101_set_config(struct usb_serial_port *port, u8 request, +static int cp210x_set_config(struct usb_serial_port *port, u8 request, unsigned int *data, int size) { struct usb_serial *serial = port->serial; @@ -292,21 +312,21 @@ static int cp2101_set_config(struct usb_serial_port *port, u8 request, } /* - * cp2101_set_config_single - * Convenience function for calling cp2101_set_config on single data values + * cp210x_set_config_single + * Convenience function for calling cp210x_set_config on single data values * without requiring an integer pointer */ -static inline int cp2101_set_config_single(struct usb_serial_port *port, +static inline int cp210x_set_config_single(struct usb_serial_port *port, u8 request, unsigned int data) { - return cp2101_set_config(port, request, &data, 2); + return cp210x_set_config(port, request, &data, 2); } /* - * cp2101_quantise_baudrate + * cp210x_quantise_baudrate * Quantises the baud rate as per AN205 Table 1 */ -static unsigned int cp2101_quantise_baudrate(unsigned int baud) { +static unsigned int cp210x_quantise_baudrate(unsigned int baud) { if (baud <= 56) baud = 0; else if (baud <= 300) baud = 300; else if (baud <= 600) baud = 600; @@ -343,7 +363,7 @@ static unsigned int cp2101_quantise_baudrate(unsigned int baud) { return baud; } -static int cp2101_open(struct tty_struct *tty, struct usb_serial_port *port, +static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port, struct file *filp) { struct usb_serial *serial = port->serial; @@ -351,7 +371,7 @@ static int cp2101_open(struct tty_struct *tty, struct usb_serial_port *port, dbg("%s - port %d", __func__, port->number); - if (cp2101_set_config_single(port, CP2101_UART, UART_ENABLE)) { + if (cp210x_set_config_single(port, CP210X_IFC_ENABLE, UART_ENABLE)) { dev_err(&port->dev, "%s - Unable to enable UART\n", __func__); return -EPROTO; @@ -373,17 +393,17 @@ static int cp2101_open(struct tty_struct *tty, struct usb_serial_port *port, } /* Configure the termios structure */ - cp2101_get_termios(tty, port); + cp210x_get_termios(tty, port); /* Set the DTR and RTS pins low */ - cp2101_tiocmset_port(tty ? (struct usb_serial_port *) tty->driver_data + cp210x_tiocmset_port(tty ? (struct usb_serial_port *) tty->driver_data : port, NULL, TIOCM_DTR | TIOCM_RTS, 0); return 0; } -static void cp2101_cleanup(struct usb_serial_port *port) +static void cp210x_cleanup(struct usb_serial_port *port) { struct usb_serial *serial = port->serial; @@ -398,8 +418,7 @@ static void cp2101_cleanup(struct usb_serial_port *port) } } -static void cp2101_close(struct tty_struct *tty, struct usb_serial_port *port, - struct file *filp) +static void cp210x_close(struct usb_serial_port *port) { dbg("%s - port %d", __func__, port->number); @@ -410,23 +429,23 @@ static void cp2101_close(struct tty_struct *tty, struct usb_serial_port *port, mutex_lock(&port->serial->disc_mutex); if (!port->serial->disconnected) - cp2101_set_config_single(port, CP2101_UART, UART_DISABLE); + cp210x_set_config_single(port, CP210X_IFC_ENABLE, UART_DISABLE); mutex_unlock(&port->serial->disc_mutex); } /* - * cp2101_get_termios + * cp210x_get_termios * Reads the baud rate, data bits, parity, stop bits and flow control mode * from the device, corrects any unsupported values, and configures the * termios structure to reflect the state of the device */ -static void cp2101_get_termios(struct tty_struct *tty, +static void cp210x_get_termios(struct tty_struct *tty, struct usb_serial_port *port) { unsigned int baud; if (tty) { - cp2101_get_termios_port(tty->driver_data, + cp210x_get_termios_port(tty->driver_data, &tty->termios->c_cflag, &baud); tty_encode_baud_rate(tty, baud, baud); } @@ -434,15 +453,15 @@ static void cp2101_get_termios(struct tty_struct *tty, else { unsigned int cflag; cflag = 0; - cp2101_get_termios_port(port, &cflag, &baud); + cp210x_get_termios_port(port, &cflag, &baud); } } /* - * cp2101_get_termios_port - * This is the heart of cp2101_get_termios which always uses a &usb_serial_port. + * cp210x_get_termios_port + * This is the heart of cp210x_get_termios which always uses a &usb_serial_port. */ -static void cp2101_get_termios_port(struct usb_serial_port *port, +static void cp210x_get_termios_port(struct usb_serial_port *port, unsigned int *cflagp, unsigned int *baudp) { unsigned int cflag, modem_ctl[4]; @@ -451,17 +470,17 @@ static void cp2101_get_termios_port(struct usb_serial_port *port, dbg("%s - port %d", __func__, port->number); - cp2101_get_config(port, CP2101_BAUDRATE, &baud, 2); + cp210x_get_config(port, CP210X_GET_BAUDDIV, &baud, 2); /* Convert to baudrate */ if (baud) - baud = cp2101_quantise_baudrate((BAUD_RATE_GEN_FREQ + baud/2)/ baud); + baud = cp210x_quantise_baudrate((BAUD_RATE_GEN_FREQ + baud/2)/ baud); dbg("%s - baud rate = %d", __func__, baud); *baudp = baud; cflag = *cflagp; - cp2101_get_config(port, CP2101_BITS, &bits, 2); + cp210x_get_config(port, CP210X_GET_LINE_CTL, &bits, 2); cflag &= ~CSIZE; switch (bits & BITS_DATA_MASK) { case BITS_DATA_5: @@ -486,14 +505,14 @@ static void cp2101_get_termios_port(struct usb_serial_port *port, cflag |= CS8; bits &= ~BITS_DATA_MASK; bits |= BITS_DATA_8; - cp2101_set_config(port, CP2101_BITS, &bits, 2); + cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2); break; default: dbg("%s - Unknown number of data bits, using 8", __func__); cflag |= CS8; bits &= ~BITS_DATA_MASK; bits |= BITS_DATA_8; - cp2101_set_config(port, CP2101_BITS, &bits, 2); + cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2); break; } @@ -516,20 +535,20 @@ static void cp2101_get_termios_port(struct usb_serial_port *port, __func__); cflag &= ~PARENB; bits &= ~BITS_PARITY_MASK; - cp2101_set_config(port, CP2101_BITS, &bits, 2); + cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2); break; case BITS_PARITY_SPACE: dbg("%s - parity = SPACE (not supported, disabling parity)", __func__); cflag &= ~PARENB; bits &= ~BITS_PARITY_MASK; - cp2101_set_config(port, CP2101_BITS, &bits, 2); + cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2); break; default: dbg("%s - Unknown parity mode, disabling parity", __func__); cflag &= ~PARENB; bits &= ~BITS_PARITY_MASK; - cp2101_set_config(port, CP2101_BITS, &bits, 2); + cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2); break; } @@ -542,7 +561,7 @@ static void cp2101_get_termios_port(struct usb_serial_port *port, dbg("%s - stop bits = 1.5 (not supported, using 1 stop bit)", __func__); bits &= ~BITS_STOP_MASK; - cp2101_set_config(port, CP2101_BITS, &bits, 2); + cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2); break; case BITS_STOP_2: dbg("%s - stop bits = 2", __func__); @@ -552,11 +571,11 @@ static void cp2101_get_termios_port(struct usb_serial_port *port, dbg("%s - Unknown number of stop bits, using 1 stop bit", __func__); bits &= ~BITS_STOP_MASK; - cp2101_set_config(port, CP2101_BITS, &bits, 2); + cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2); break; } - cp2101_get_config(port, CP2101_MODEMCTL, modem_ctl, 16); + cp210x_get_config(port, CP210X_GET_FLOW, modem_ctl, 16); if (modem_ctl[0] & 0x0008) { dbg("%s - flow control = CRTSCTS", __func__); cflag |= CRTSCTS; @@ -568,7 +587,7 @@ static void cp2101_get_termios_port(struct usb_serial_port *port, *cflagp = cflag; } -static void cp2101_set_termios(struct tty_struct *tty, +static void cp210x_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) { unsigned int cflag, old_cflag; @@ -583,13 +602,13 @@ static void cp2101_set_termios(struct tty_struct *tty, tty->termios->c_cflag &= ~CMSPAR; cflag = tty->termios->c_cflag; old_cflag = old_termios->c_cflag; - baud = cp2101_quantise_baudrate(tty_get_baud_rate(tty)); + baud = cp210x_quantise_baudrate(tty_get_baud_rate(tty)); /* If the baud rate is to be updated*/ if (baud != tty_termios_baud_rate(old_termios) && baud != 0) { dbg("%s - Setting baud rate to %d baud", __func__, baud); - if (cp2101_set_config_single(port, CP2101_BAUDRATE, + if (cp210x_set_config_single(port, CP210X_SET_BAUDDIV, ((BAUD_RATE_GEN_FREQ + baud/2) / baud))) { dbg("Baud rate requested not supported by device\n"); baud = tty_termios_baud_rate(old_termios); @@ -600,7 +619,7 @@ static void cp2101_set_termios(struct tty_struct *tty, /* If the number of data bits is to be updated */ if ((cflag & CSIZE) != (old_cflag & CSIZE)) { - cp2101_get_config(port, CP2101_BITS, &bits, 2); + cp210x_get_config(port, CP210X_GET_LINE_CTL, &bits, 2); bits &= ~BITS_DATA_MASK; switch (cflag & CSIZE) { case CS5: @@ -624,19 +643,19 @@ static void cp2101_set_termios(struct tty_struct *tty, dbg("%s - data bits = 9", __func__); break;*/ default: - dbg("cp2101 driver does not " + dbg("cp210x driver does not " "support the number of bits requested," " using 8 bit mode\n"); bits |= BITS_DATA_8; break; } - if (cp2101_set_config(port, CP2101_BITS, &bits, 2)) + if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2)) dbg("Number of data bits requested " "not supported by device\n"); } if ((cflag & (PARENB|PARODD)) != (old_cflag & (PARENB|PARODD))) { - cp2101_get_config(port, CP2101_BITS, &bits, 2); + cp210x_get_config(port, CP210X_GET_LINE_CTL, &bits, 2); bits &= ~BITS_PARITY_MASK; if (cflag & PARENB) { if (cflag & PARODD) { @@ -647,13 +666,13 @@ static void cp2101_set_termios(struct tty_struct *tty, dbg("%s - parity = EVEN", __func__); } } - if (cp2101_set_config(port, CP2101_BITS, &bits, 2)) + if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2)) dbg("Parity mode not supported " "by device\n"); } if ((cflag & CSTOPB) != (old_cflag & CSTOPB)) { - cp2101_get_config(port, CP2101_BITS, &bits, 2); + cp210x_get_config(port, CP210X_GET_LINE_CTL, &bits, 2); bits &= ~BITS_STOP_MASK; if (cflag & CSTOPB) { bits |= BITS_STOP_2; @@ -662,13 +681,13 @@ static void cp2101_set_termios(struct tty_struct *tty, bits |= BITS_STOP_1; dbg("%s - stop bits = 1", __func__); } - if (cp2101_set_config(port, CP2101_BITS, &bits, 2)) + if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2)) dbg("Number of stop bits requested " "not supported by device\n"); } if ((cflag & CRTSCTS) != (old_cflag & CRTSCTS)) { - cp2101_get_config(port, CP2101_MODEMCTL, modem_ctl, 16); + cp210x_get_config(port, CP210X_GET_FLOW, modem_ctl, 16); dbg("%s - read modem controls = 0x%.4x 0x%.4x 0x%.4x 0x%.4x", __func__, modem_ctl[0], modem_ctl[1], modem_ctl[2], modem_ctl[3]); @@ -688,19 +707,19 @@ static void cp2101_set_termios(struct tty_struct *tty, dbg("%s - write modem controls = 0x%.4x 0x%.4x 0x%.4x 0x%.4x", __func__, modem_ctl[0], modem_ctl[1], modem_ctl[2], modem_ctl[3]); - cp2101_set_config(port, CP2101_MODEMCTL, modem_ctl, 16); + cp210x_set_config(port, CP210X_SET_FLOW, modem_ctl, 16); } } -static int cp2101_tiocmset (struct tty_struct *tty, struct file *file, +static int cp210x_tiocmset (struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear) { struct usb_serial_port *port = tty->driver_data; - return cp2101_tiocmset_port(port, file, set, clear); + return cp210x_tiocmset_port(port, file, set, clear); } -static int cp2101_tiocmset_port(struct usb_serial_port *port, struct file *file, +static int cp210x_tiocmset_port(struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear) { unsigned int control = 0; @@ -726,10 +745,10 @@ static int cp2101_tiocmset_port(struct usb_serial_port *port, struct file *file, dbg("%s - control = 0x%.4x", __func__, control); - return cp2101_set_config(port, CP2101_CONTROL, &control, 2); + return cp210x_set_config(port, CP210X_SET_MHS, &control, 2); } -static int cp2101_tiocmget (struct tty_struct *tty, struct file *file) +static int cp210x_tiocmget (struct tty_struct *tty, struct file *file) { struct usb_serial_port *port = tty->driver_data; unsigned int control; @@ -737,7 +756,7 @@ static int cp2101_tiocmget (struct tty_struct *tty, struct file *file) dbg("%s - port %d", __func__, port->number); - cp2101_get_config(port, CP2101_CONTROL, &control, 1); + cp210x_get_config(port, CP210X_GET_MDMSTS, &control, 1); result = ((control & CONTROL_DTR) ? TIOCM_DTR : 0) |((control & CONTROL_RTS) ? TIOCM_RTS : 0) @@ -751,7 +770,7 @@ static int cp2101_tiocmget (struct tty_struct *tty, struct file *file) return result; } -static void cp2101_break_ctl (struct tty_struct *tty, int break_state) +static void cp210x_break_ctl (struct tty_struct *tty, int break_state) { struct usb_serial_port *port = tty->driver_data; unsigned int state; @@ -763,17 +782,17 @@ static void cp2101_break_ctl (struct tty_struct *tty, int break_state) state = BREAK_ON; dbg("%s - turning break %s", __func__, state == BREAK_OFF ? "off" : "on"); - cp2101_set_config(port, CP2101_BREAK, &state, 2); + cp210x_set_config(port, CP210X_SET_BREAK, &state, 2); } -static int cp2101_startup(struct usb_serial *serial) +static int cp210x_startup(struct usb_serial *serial) { - /* CP2101 buffers behave strangely unless device is reset */ + /* cp210x buffers behave strangely unless device is reset */ usb_reset_device(serial->dev); return 0; } -static void cp2101_shutdown(struct usb_serial *serial) +static void cp210x_disconnect(struct usb_serial *serial) { int i; @@ -781,21 +800,21 @@ static void cp2101_shutdown(struct usb_serial *serial) /* Stop reads and writes on all ports */ for (i = 0; i < serial->num_ports; ++i) - cp2101_cleanup(serial->port[i]); + cp210x_cleanup(serial->port[i]); } -static int __init cp2101_init(void) +static int __init cp210x_init(void) { int retval; - retval = usb_serial_register(&cp2101_device); + retval = usb_serial_register(&cp210x_device); if (retval) return retval; /* Failed to register */ - retval = usb_register(&cp2101_driver); + retval = usb_register(&cp210x_driver); if (retval) { /* Failed to register */ - usb_serial_deregister(&cp2101_device); + usb_serial_deregister(&cp210x_device); return retval; } @@ -805,14 +824,14 @@ static int __init cp2101_init(void) return 0; } -static void __exit cp2101_exit(void) +static void __exit cp210x_exit(void) { - usb_deregister(&cp2101_driver); - usb_serial_deregister(&cp2101_device); + usb_deregister(&cp210x_driver); + usb_serial_deregister(&cp210x_device); } -module_init(cp2101_init); -module_exit(cp2101_exit); +module_init(cp210x_init); +module_exit(cp210x_exit); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_VERSION(DRIVER_VERSION); diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c index dd501bb63ed6..336523fd7366 100644 --- a/drivers/usb/serial/cyberjack.c +++ b/drivers/usb/serial/cyberjack.c @@ -58,11 +58,11 @@ static int debug; /* Function prototypes */ static int cyberjack_startup(struct usb_serial *serial); -static void cyberjack_shutdown(struct usb_serial *serial); +static void cyberjack_disconnect(struct usb_serial *serial); +static void cyberjack_release(struct usb_serial *serial); static int cyberjack_open(struct tty_struct *tty, struct usb_serial_port *port, struct file *filp); -static void cyberjack_close(struct tty_struct *tty, - struct usb_serial_port *port, struct file *filp); +static void cyberjack_close(struct usb_serial_port *port); static int cyberjack_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count); static int cyberjack_write_room(struct tty_struct *tty); @@ -95,7 +95,8 @@ static struct usb_serial_driver cyberjack_device = { .id_table = id_table, .num_ports = 1, .attach = cyberjack_startup, - .shutdown = cyberjack_shutdown, + .disconnect = cyberjack_disconnect, + .release = cyberjack_release, .open = cyberjack_open, .close = cyberjack_close, .write = cyberjack_write, @@ -149,17 +150,25 @@ static int cyberjack_startup(struct usb_serial *serial) return 0; } -static void cyberjack_shutdown(struct usb_serial *serial) +static void cyberjack_disconnect(struct usb_serial *serial) +{ + int i; + + dbg("%s", __func__); + + for (i = 0; i < serial->num_ports; ++i) + usb_kill_urb(serial->port[i]->interrupt_in_urb); +} + +static void cyberjack_release(struct usb_serial *serial) { int i; dbg("%s", __func__); for (i = 0; i < serial->num_ports; ++i) { - usb_kill_urb(serial->port[i]->interrupt_in_urb); /* My special items, the standard routines free my urbs */ kfree(usb_get_serial_port_data(serial->port[i])); - usb_set_serial_port_data(serial->port[i], NULL); } } @@ -185,8 +194,7 @@ static int cyberjack_open(struct tty_struct *tty, return result; } -static void cyberjack_close(struct tty_struct *tty, - struct usb_serial_port *port, struct file *filp) +static void cyberjack_close(struct usb_serial_port *port) { dbg("%s - port %d", __func__, port->number); diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index e568710b263f..9734085fd2fe 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -171,11 +171,11 @@ struct cypress_buf { static int cypress_earthmate_startup(struct usb_serial *serial); static int cypress_hidcom_startup(struct usb_serial *serial); static int cypress_ca42v2_startup(struct usb_serial *serial); -static void cypress_shutdown(struct usb_serial *serial); +static void cypress_release(struct usb_serial *serial); static int cypress_open(struct tty_struct *tty, struct usb_serial_port *port, struct file *filp); -static void cypress_close(struct tty_struct *tty, - struct usb_serial_port *port, struct file *filp); +static void cypress_close(struct usb_serial_port *port); +static void cypress_dtr_rts(struct usb_serial_port *port, int on); static int cypress_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count); static void cypress_send(struct usb_serial_port *port); @@ -215,9 +215,10 @@ static struct usb_serial_driver cypress_earthmate_device = { .id_table = id_table_earthmate, .num_ports = 1, .attach = cypress_earthmate_startup, - .shutdown = cypress_shutdown, + .release = cypress_release, .open = cypress_open, .close = cypress_close, + .dtr_rts = cypress_dtr_rts, .write = cypress_write, .write_room = cypress_write_room, .ioctl = cypress_ioctl, @@ -241,9 +242,10 @@ static struct usb_serial_driver cypress_hidcom_device = { .id_table = id_table_cyphidcomrs232, .num_ports = 1, .attach = cypress_hidcom_startup, - .shutdown = cypress_shutdown, + .release = cypress_release, .open = cypress_open, .close = cypress_close, + .dtr_rts = cypress_dtr_rts, .write = cypress_write, .write_room = cypress_write_room, .ioctl = cypress_ioctl, @@ -267,9 +269,10 @@ static struct usb_serial_driver cypress_ca42v2_device = { .id_table = id_table_nokiaca42v2, .num_ports = 1, .attach = cypress_ca42v2_startup, - .shutdown = cypress_shutdown, + .release = cypress_release, .open = cypress_open, .close = cypress_close, + .dtr_rts = cypress_dtr_rts, .write = cypress_write, .write_room = cypress_write_room, .ioctl = cypress_ioctl, @@ -613,7 +616,7 @@ static int cypress_ca42v2_startup(struct usb_serial *serial) } /* cypress_ca42v2_startup */ -static void cypress_shutdown(struct usb_serial *serial) +static void cypress_release(struct usb_serial *serial) { struct cypress_private *priv; @@ -626,7 +629,6 @@ static void cypress_shutdown(struct usb_serial *serial) if (priv) { cypress_buf_free(priv->buf); kfree(priv); - usb_set_serial_port_data(serial->port[0], NULL); } } @@ -656,11 +658,7 @@ static int cypress_open(struct tty_struct *tty, priv->rx_flags = 0; spin_unlock_irqrestore(&priv->lock, flags); - /* raise both lines and set termios */ - spin_lock_irqsave(&priv->lock, flags); - priv->line_control = CONTROL_DTR | CONTROL_RTS; - priv->cmd_ctrl = 1; - spin_unlock_irqrestore(&priv->lock, flags); + /* Set termios */ result = cypress_write(tty, port, NULL, 0); if (result) { @@ -694,76 +692,42 @@ static int cypress_open(struct tty_struct *tty, __func__, result); cypress_set_dead(port); } - + port->port.drain_delay = 256; return result; } /* cypress_open */ - -static void cypress_close(struct tty_struct *tty, - struct usb_serial_port *port, struct file *filp) +static void cypress_dtr_rts(struct usb_serial_port *port, int on) +{ + struct cypress_private *priv = usb_get_serial_port_data(port); + /* drop dtr and rts */ + priv = usb_get_serial_port_data(port); + spin_lock_irq(&priv->lock); + if (on == 0) + priv->line_control = 0; + else + priv->line_control = CONTROL_DTR | CONTROL_RTS; + priv->cmd_ctrl = 1; + spin_unlock_irq(&priv->lock); + cypress_write(NULL, port, NULL, 0); +} + +static void cypress_close(struct usb_serial_port *port) { struct cypress_private *priv = usb_get_serial_port_data(port); - unsigned int c_cflag; - int bps; - long timeout; - wait_queue_t wait; dbg("%s - port %d", __func__, port->number); - /* wait for data to drain from buffer */ - spin_lock_irq(&priv->lock); - timeout = CYPRESS_CLOSING_WAIT; - init_waitqueue_entry(&wait, current); - add_wait_queue(&tty->write_wait, &wait); - for (;;) { - set_current_state(TASK_INTERRUPTIBLE); - if (cypress_buf_data_avail(priv->buf) == 0 - || timeout == 0 || signal_pending(current) - /* without mutex, allowed due to harmless failure mode */ - || port->serial->disconnected) - break; - spin_unlock_irq(&priv->lock); - timeout = schedule_timeout(timeout); - spin_lock_irq(&priv->lock); - } - set_current_state(TASK_RUNNING); - remove_wait_queue(&tty->write_wait, &wait); - /* clear out any remaining data in the buffer */ - cypress_buf_clear(priv->buf); - spin_unlock_irq(&priv->lock); - /* writing is potentially harmful, lock must be taken */ mutex_lock(&port->serial->disc_mutex); if (port->serial->disconnected) { mutex_unlock(&port->serial->disc_mutex); return; } - /* wait for characters to drain from device */ - if (tty) { - bps = tty_get_baud_rate(tty); - if (bps > 1200) - timeout = max((HZ * 2560) / bps, HZ / 10); - else - timeout = 2 * HZ; - schedule_timeout_interruptible(timeout); - } - + cypress_buf_clear(priv->buf); dbg("%s - stopping urbs", __func__); usb_kill_urb(port->interrupt_in_urb); usb_kill_urb(port->interrupt_out_urb); - if (tty) { - c_cflag = tty->termios->c_cflag; - if (c_cflag & HUPCL) { - /* drop dtr and rts */ - priv = usb_get_serial_port_data(port); - spin_lock_irq(&priv->lock); - priv->line_control = 0; - priv->cmd_ctrl = 1; - spin_unlock_irq(&priv->lock); - cypress_write(tty, port, NULL, 0); - } - } if (stats) dev_info(&port->dev, "Statistics: %d Bytes In | %d Bytes Out | %d Commands Issued\n", diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index 38ba4ea8b6bf..f4808091c47c 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -422,7 +422,6 @@ struct digi_port { int dp_throttled; int dp_throttle_restart; wait_queue_head_t dp_flush_wait; - int dp_in_close; /* close in progress */ wait_queue_head_t dp_close_wait; /* wait queue for close */ struct work_struct dp_wakeup_work; struct usb_serial_port *dp_port; @@ -456,11 +455,13 @@ static int digi_write_room(struct tty_struct *tty); static int digi_chars_in_buffer(struct tty_struct *tty); static int digi_open(struct tty_struct *tty, struct usb_serial_port *port, struct file *filp); -static void digi_close(struct tty_struct *tty, struct usb_serial_port *port, - struct file *filp); +static void digi_close(struct usb_serial_port *port); +static int digi_carrier_raised(struct usb_serial_port *port); +static void digi_dtr_rts(struct usb_serial_port *port, int on); static int digi_startup_device(struct usb_serial *serial); static int digi_startup(struct usb_serial *serial); -static void digi_shutdown(struct usb_serial *serial); +static void digi_disconnect(struct usb_serial *serial); +static void digi_release(struct usb_serial *serial); static void digi_read_bulk_callback(struct urb *urb); static int digi_read_inb_callback(struct urb *urb); static int digi_read_oob_callback(struct urb *urb); @@ -510,6 +511,8 @@ static struct usb_serial_driver digi_acceleport_2_device = { .num_ports = 3, .open = digi_open, .close = digi_close, + .dtr_rts = digi_dtr_rts, + .carrier_raised = digi_carrier_raised, .write = digi_write, .write_room = digi_write_room, .write_bulk_callback = digi_write_bulk_callback, @@ -522,7 +525,8 @@ static struct usb_serial_driver digi_acceleport_2_device = { .tiocmget = digi_tiocmget, .tiocmset = digi_tiocmset, .attach = digi_startup, - .shutdown = digi_shutdown, + .disconnect = digi_disconnect, + .release = digi_release, }; static struct usb_serial_driver digi_acceleport_4_device = { @@ -548,7 +552,8 @@ static struct usb_serial_driver digi_acceleport_4_device = { .tiocmget = digi_tiocmget, .tiocmset = digi_tiocmset, .attach = digi_startup, - .shutdown = digi_shutdown, + .disconnect = digi_disconnect, + .release = digi_release, }; @@ -1328,6 +1333,19 @@ static int digi_chars_in_buffer(struct tty_struct *tty) } +static void digi_dtr_rts(struct usb_serial_port *port, int on) +{ + /* Adjust DTR and RTS */ + digi_set_modem_signals(port, on * (TIOCM_DTR|TIOCM_RTS), 1); +} + +static int digi_carrier_raised(struct usb_serial_port *port) +{ + struct digi_port *priv = usb_get_serial_port_data(port); + if (priv->dp_modem_signals & TIOCM_CD) + return 1; + return 0; +} static int digi_open(struct tty_struct *tty, struct usb_serial_port *port, struct file *filp) @@ -1336,7 +1354,6 @@ static int digi_open(struct tty_struct *tty, struct usb_serial_port *port, unsigned char buf[32]; struct digi_port *priv = usb_get_serial_port_data(port); struct ktermios not_termios; - unsigned long flags = 0; dbg("digi_open: TOP: port=%d, open_count=%d", priv->dp_port_num, port->port.count); @@ -1345,26 +1362,6 @@ static int digi_open(struct tty_struct *tty, struct usb_serial_port *port, if (digi_startup_device(port->serial) != 0) return -ENXIO; - spin_lock_irqsave(&priv->dp_port_lock, flags); - - /* don't wait on a close in progress for non-blocking opens */ - if (priv->dp_in_close && (filp->f_flags&(O_NDELAY|O_NONBLOCK)) == 0) { - spin_unlock_irqrestore(&priv->dp_port_lock, flags); - return -EAGAIN; - } - - /* wait for a close in progress to finish */ - while (priv->dp_in_close) { - cond_wait_interruptible_timeout_irqrestore( - &priv->dp_close_wait, DIGI_RETRY_TIMEOUT, - &priv->dp_port_lock, flags); - if (signal_pending(current)) - return -EINTR; - spin_lock_irqsave(&priv->dp_port_lock, flags); - } - - spin_unlock_irqrestore(&priv->dp_port_lock, flags); - /* read modem signals automatically whenever they change */ buf[0] = DIGI_CMD_READ_INPUT_SIGNALS; buf[1] = priv->dp_port_num; @@ -1387,16 +1384,11 @@ static int digi_open(struct tty_struct *tty, struct usb_serial_port *port, not_termios.c_iflag = ~tty->termios->c_iflag; digi_set_termios(tty, port, ¬_termios); } - - /* set DTR and RTS */ - digi_set_modem_signals(port, TIOCM_DTR|TIOCM_RTS, 1); - return 0; } -static void digi_close(struct tty_struct *tty, struct usb_serial_port *port, - struct file *filp) +static void digi_close(struct usb_serial_port *port) { DEFINE_WAIT(wait); int ret; @@ -1411,28 +1403,9 @@ static void digi_close(struct tty_struct *tty, struct usb_serial_port *port, if (port->serial->disconnected) goto exit; - /* do cleanup only after final close on this port */ - spin_lock_irq(&priv->dp_port_lock); - priv->dp_in_close = 1; - spin_unlock_irq(&priv->dp_port_lock); - - /* tell line discipline to process only XON/XOFF */ - tty->closing = 1; - - /* wait for output to drain */ - if ((filp->f_flags&(O_NDELAY|O_NONBLOCK)) == 0) - tty_wait_until_sent(tty, DIGI_CLOSE_TIMEOUT); - - /* flush driver and line discipline buffers */ - tty_driver_flush_buffer(tty); - tty_ldisc_flush(tty); - if (port->serial->dev) { - /* wait for transmit idle */ - if ((filp->f_flags&(O_NDELAY|O_NONBLOCK)) == 0) - digi_transmit_idle(port, DIGI_CLOSE_TIMEOUT); - /* drop DTR and RTS */ - digi_set_modem_signals(port, 0, 0); + /* FIXME: Transmit idle belongs in the wait_unti_sent path */ + digi_transmit_idle(port, DIGI_CLOSE_TIMEOUT); /* disable input flow control */ buf[0] = DIGI_CMD_SET_INPUT_FLOW_CONTROL; @@ -1477,11 +1450,9 @@ static void digi_close(struct tty_struct *tty, struct usb_serial_port *port, /* shutdown any outstanding bulk writes */ usb_kill_urb(port->write_urb); } - tty->closing = 0; exit: spin_lock_irq(&priv->dp_port_lock); priv->dp_write_urb_in_use = 0; - priv->dp_in_close = 0; wake_up_interruptible(&priv->dp_close_wait); spin_unlock_irq(&priv->dp_port_lock); mutex_unlock(&port->serial->disc_mutex); @@ -1560,7 +1531,6 @@ static int digi_startup(struct usb_serial *serial) priv->dp_throttled = 0; priv->dp_throttle_restart = 0; init_waitqueue_head(&priv->dp_flush_wait); - priv->dp_in_close = 0; init_waitqueue_head(&priv->dp_close_wait); INIT_WORK(&priv->dp_wakeup_work, digi_wakeup_write_lock); priv->dp_port = serial->port[i]; @@ -1589,16 +1559,23 @@ static int digi_startup(struct usb_serial *serial) } -static void digi_shutdown(struct usb_serial *serial) +static void digi_disconnect(struct usb_serial *serial) { int i; - dbg("digi_shutdown: TOP, in_interrupt()=%ld", in_interrupt()); + dbg("digi_disconnect: TOP, in_interrupt()=%ld", in_interrupt()); /* stop reads and writes on all ports */ for (i = 0; i < serial->type->num_ports + 1; i++) { usb_kill_urb(serial->port[i]->read_urb); usb_kill_urb(serial->port[i]->write_urb); } +} + + +static void digi_release(struct usb_serial *serial) +{ + int i; + dbg("digi_release: TOP, in_interrupt()=%ld", in_interrupt()); /* free the private data structures for all ports */ /* number of regular ports + 1 for the out-of-band port */ diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c index c709ec474a80..80cb3471adbe 100644 --- a/drivers/usb/serial/empeg.c +++ b/drivers/usb/serial/empeg.c @@ -81,8 +81,7 @@ static int debug; /* function prototypes for an empeg-car player */ static int empeg_open(struct tty_struct *tty, struct usb_serial_port *port, struct file *filp); -static void empeg_close(struct tty_struct *tty, struct usb_serial_port *port, - struct file *filp); +static void empeg_close(struct usb_serial_port *port); static int empeg_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count); @@ -91,7 +90,6 @@ static int empeg_chars_in_buffer(struct tty_struct *tty); static void empeg_throttle(struct tty_struct *tty); static void empeg_unthrottle(struct tty_struct *tty); static int empeg_startup(struct usb_serial *serial); -static void empeg_shutdown(struct usb_serial *serial); static void empeg_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios); static void empeg_write_bulk_callback(struct urb *urb); @@ -125,7 +123,6 @@ static struct usb_serial_driver empeg_device = { .throttle = empeg_throttle, .unthrottle = empeg_unthrottle, .attach = empeg_startup, - .shutdown = empeg_shutdown, .set_termios = empeg_set_termios, .write = empeg_write, .write_room = empeg_write_room, @@ -181,8 +178,7 @@ static int empeg_open(struct tty_struct *tty, struct usb_serial_port *port, } -static void empeg_close(struct tty_struct *tty, struct usb_serial_port *port, - struct file *filp) +static void empeg_close(struct usb_serial_port *port) { dbg("%s - port %d", __func__, port->number); @@ -429,12 +425,6 @@ static int empeg_startup(struct usb_serial *serial) } -static void empeg_shutdown(struct usb_serial *serial) -{ - dbg("%s", __func__); -} - - static void empeg_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) { diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index d9fcdaedf389..3dc3768ca71c 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -47,7 +47,7 @@ /* * Version Information */ -#define DRIVER_VERSION "v1.4.3" +#define DRIVER_VERSION "v1.5.0" #define DRIVER_AUTHOR "Greg Kroah-Hartman , Bill Ryder , Kuba Ober " #define DRIVER_DESC "USB FTDI Serial Converters Driver" @@ -82,17 +82,20 @@ struct ftdi_private { int rx_processed; unsigned long rx_bytes; - __u16 interface; /* FT2232C port interface (0 for FT232/245) */ + __u16 interface; /* FT2232C, FT2232H or FT4232H port interface + (0 for FT232/245) */ speed_t force_baud; /* if non-zero, force the baud rate to this value */ int force_rtscts; /* if non-zero, force RTS-CTS to always be enabled */ + unsigned int latency; /* latency setting in use */ spinlock_t tx_lock; /* spinlock for transmit state */ unsigned long tx_bytes; unsigned long tx_outstanding_bytes; unsigned long tx_outstanding_urbs; + unsigned short max_packet_size; }; /* struct ftdi_sio_quirk is used by devices requiring special attention. */ @@ -163,6 +166,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_8U232AM_ALT_PID) }, { USB_DEVICE(FTDI_VID, FTDI_232RL_PID) }, { USB_DEVICE(FTDI_VID, FTDI_8U2232C_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_4232H_PID) }, { USB_DEVICE(FTDI_VID, FTDI_MICRO_CHAMELEON_PID) }, { USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) }, { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_PID) }, @@ -672,6 +676,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(JETI_VID, JETI_SPC1201_PID) }, { USB_DEVICE(MARVELL_VID, MARVELL_SHEEVAPLUG_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, + { USB_DEVICE(LARSENBRUSGAARD_VID, LB_ALTITRACK_PID) }, { }, /* Optional parameter entry */ { } /* Terminating entry */ }; @@ -692,12 +697,13 @@ static const char *ftdi_chip_name[] = { [FT232BM] = "FT232BM", [FT2232C] = "FT2232C", [FT232RL] = "FT232RL", + [FT2232H] = "FT2232H", + [FT4232H] = "FT4232H" }; /* Constants for read urb and write urb */ #define BUFSZ 512 -#define PKTSZ 64 /* rx_flags */ #define THROTTLED 0x01 @@ -714,13 +720,12 @@ static const char *ftdi_chip_name[] = { /* function prototypes for a FTDI serial converter */ static int ftdi_sio_probe(struct usb_serial *serial, const struct usb_device_id *id); -static void ftdi_shutdown(struct usb_serial *serial); static int ftdi_sio_port_probe(struct usb_serial_port *port); static int ftdi_sio_port_remove(struct usb_serial_port *port); static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port, struct file *filp); -static void ftdi_close(struct tty_struct *tty, - struct usb_serial_port *port, struct file *filp); +static void ftdi_close(struct usb_serial_port *port); +static void ftdi_dtr_rts(struct usb_serial_port *port, int on); static int ftdi_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count); static int ftdi_write_room(struct tty_struct *tty); @@ -743,6 +748,8 @@ static unsigned short int ftdi_232am_baud_base_to_divisor(int baud, int base); static unsigned short int ftdi_232am_baud_to_divisor(int baud); static __u32 ftdi_232bm_baud_base_to_divisor(int baud, int base); static __u32 ftdi_232bm_baud_to_divisor(int baud); +static __u32 ftdi_2232h_baud_base_to_divisor(int baud, int base); +static __u32 ftdi_2232h_baud_to_divisor(int baud); static struct usb_serial_driver ftdi_sio_device = { .driver = { @@ -758,6 +765,7 @@ static struct usb_serial_driver ftdi_sio_device = { .port_remove = ftdi_sio_port_remove, .open = ftdi_open, .close = ftdi_close, + .dtr_rts = ftdi_dtr_rts, .throttle = ftdi_throttle, .unthrottle = ftdi_unthrottle, .write = ftdi_write, @@ -770,7 +778,6 @@ static struct usb_serial_driver ftdi_sio_device = { .ioctl = ftdi_ioctl, .set_termios = ftdi_set_termios, .break_ctl = ftdi_break_ctl, - .shutdown = ftdi_shutdown, }; @@ -836,6 +843,36 @@ static __u32 ftdi_232bm_baud_to_divisor(int baud) return ftdi_232bm_baud_base_to_divisor(baud, 48000000); } +static __u32 ftdi_2232h_baud_base_to_divisor(int baud, int base) +{ + static const unsigned char divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7 }; + __u32 divisor; + int divisor3; + + /* hi-speed baud rate is 10-bit sampling instead of 16-bit */ + divisor3 = (base / 10 / baud) * 8; + + divisor = divisor3 >> 3; + divisor |= (__u32)divfrac[divisor3 & 0x7] << 14; + /* Deal with special cases for highest baud rates. */ + if (divisor == 1) + divisor = 0; + else if (divisor == 0x4001) + divisor = 1; + /* + * Set this bit to turn off a divide by 2.5 on baud rate generator + * This enables baud rates up to 12Mbaud but cannot reach below 1200 + * baud with this bit set + */ + divisor |= 0x00020000; + return divisor; +} + +static __u32 ftdi_2232h_baud_to_divisor(int baud) +{ + return ftdi_2232h_baud_base_to_divisor(baud, 120000000); +} + #define set_mctrl(port, set) update_mctrl((port), (set), 0) #define clear_mctrl(port, clear) update_mctrl((port), 0, (clear)) @@ -994,6 +1031,19 @@ static __u32 get_ftdi_divisor(struct tty_struct *tty, baud = 9600; } break; + case FT2232H: /* FT2232H chip */ + case FT4232H: /* FT4232H chip */ + if ((baud <= 12000000) & (baud >= 1200)) { + div_value = ftdi_2232h_baud_to_divisor(baud); + } else if (baud < 1200) { + div_value = ftdi_232bm_baud_to_divisor(baud); + } else { + dbg("%s - Baud rate too high!", __func__); + div_value = ftdi_232bm_baud_to_divisor(9600); + div_okay = 0; + baud = 9600; + } + break; } /* priv->chip_type */ if (div_okay) { @@ -1037,7 +1087,54 @@ static int change_speed(struct tty_struct *tty, struct usb_serial_port *port) return rv; } +static int write_latency_timer(struct usb_serial_port *port) +{ + struct ftdi_private *priv = usb_get_serial_port_data(port); + struct usb_device *udev = port->serial->dev; + char buf[1]; + int rv = 0; + int l = priv->latency; + if (priv->flags & ASYNC_LOW_LATENCY) + l = 1; + + dbg("%s: setting latency timer = %i", __func__, l); + + rv = usb_control_msg(udev, + usb_sndctrlpipe(udev, 0), + FTDI_SIO_SET_LATENCY_TIMER_REQUEST, + FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE, + l, priv->interface, + buf, 0, WDR_TIMEOUT); + + if (rv < 0) + dev_err(&port->dev, "Unable to write latency timer: %i\n", rv); + return rv; +} + +static int read_latency_timer(struct usb_serial_port *port) +{ + struct ftdi_private *priv = usb_get_serial_port_data(port); + struct usb_device *udev = port->serial->dev; + unsigned short latency = 0; + int rv = 0; + + + dbg("%s", __func__); + + rv = usb_control_msg(udev, + usb_rcvctrlpipe(udev, 0), + FTDI_SIO_GET_LATENCY_TIMER_REQUEST, + FTDI_SIO_GET_LATENCY_TIMER_REQUEST_TYPE, + 0, priv->interface, + (char *) &latency, 1, WDR_TIMEOUT); + + if (rv < 0) { + dev_err(&port->dev, "Unable to read latency timer: %i\n", rv); + return -EIO; + } + return latency; +} static int get_serial_info(struct usb_serial_port *port, struct serial_struct __user *retinfo) @@ -1097,6 +1194,7 @@ static int set_serial_info(struct tty_struct *tty, priv->custom_divisor = new_serial.custom_divisor; tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0; + write_latency_timer(port); check_and_exit: if ((old_priv.flags & ASYNC_SPD_MASK) != @@ -1146,14 +1244,29 @@ static void ftdi_determine_type(struct usb_serial_port *port) if (interfaces > 1) { int inter; - /* Multiple interfaces. Assume FT2232C. */ - priv->chip_type = FT2232C; + /* Multiple interfaces.*/ + if (version == 0x0800) { + priv->chip_type = FT4232H; + /* Hi-speed - baud clock runs at 120MHz */ + priv->baud_base = 120000000 / 2; + } else if (version == 0x0700) { + priv->chip_type = FT2232H; + /* Hi-speed - baud clock runs at 120MHz */ + priv->baud_base = 120000000 / 2; + } else + priv->chip_type = FT2232C; + /* Determine interface code. */ inter = serial->interface->altsetting->desc.bInterfaceNumber; - if (inter == 0) - priv->interface = PIT_SIOA; - else - priv->interface = PIT_SIOB; + if (inter == 0) { + priv->interface = INTERFACE_A; + } else if (inter == 1) { + priv->interface = INTERFACE_B; + } else if (inter == 2) { + priv->interface = INTERFACE_C; + } else if (inter == 3) { + priv->interface = INTERFACE_D; + } /* BM-type devices have a bug where bcdDevice gets set * to 0x200 when iSerialNumber is 0. */ if (version < 0x500) { @@ -1181,6 +1294,45 @@ static void ftdi_determine_type(struct usb_serial_port *port) } +/* Determine the maximum packet size for the device. This depends on the chip + * type and the USB host capabilities. The value should be obtained from the + * device descriptor as the chip will use the appropriate values for the host.*/ +static void ftdi_set_max_packet_size(struct usb_serial_port *port) +{ + struct ftdi_private *priv = usb_get_serial_port_data(port); + struct usb_serial *serial = port->serial; + struct usb_device *udev = serial->dev; + + struct usb_interface *interface = serial->interface; + struct usb_endpoint_descriptor *ep_desc = &interface->cur_altsetting->endpoint[1].desc; + + unsigned num_endpoints; + int i = 0; + + num_endpoints = interface->cur_altsetting->desc.bNumEndpoints; + dev_info(&udev->dev, "Number of endpoints %d\n", num_endpoints); + + /* NOTE: some customers have programmed FT232R/FT245R devices + * with an endpoint size of 0 - not good. In this case, we + * want to override the endpoint descriptor setting and use a + * value of 64 for wMaxPacketSize */ + for (i = 0; i < num_endpoints; i++) { + dev_info(&udev->dev, "Endpoint %d MaxPacketSize %d\n", i+1, + interface->cur_altsetting->endpoint[i].desc.wMaxPacketSize); + ep_desc = &interface->cur_altsetting->endpoint[i].desc; + if (ep_desc->wMaxPacketSize == 0) { + ep_desc->wMaxPacketSize = cpu_to_le16(0x40); + dev_info(&udev->dev, "Overriding wMaxPacketSize on endpoint %d\n", i); + } + } + + /* set max packet size based on descriptor */ + priv->max_packet_size = ep_desc->wMaxPacketSize; + + dev_info(&udev->dev, "Setting MaxPacketSize %d\n", priv->max_packet_size); +} + + /* * *************************************************************************** * Sysfs Attribute @@ -1192,27 +1344,13 @@ static ssize_t show_latency_timer(struct device *dev, { struct usb_serial_port *port = to_usb_serial_port(dev); struct ftdi_private *priv = usb_get_serial_port_data(port); - struct usb_device *udev = port->serial->dev; - unsigned short latency = 0; - int rv = 0; - - - dbg("%s", __func__); - - rv = usb_control_msg(udev, - usb_rcvctrlpipe(udev, 0), - FTDI_SIO_GET_LATENCY_TIMER_REQUEST, - FTDI_SIO_GET_LATENCY_TIMER_REQUEST_TYPE, - 0, priv->interface, - (char *) &latency, 1, WDR_TIMEOUT); - - if (rv < 0) { - dev_err(dev, "Unable to read latency timer: %i\n", rv); - return -EIO; - } - return sprintf(buf, "%i\n", latency); + if (priv->flags & ASYNC_LOW_LATENCY) + return sprintf(buf, "1\n"); + else + return sprintf(buf, "%i\n", priv->latency); } + /* Write a new value of the latency timer, in units of milliseconds. */ static ssize_t store_latency_timer(struct device *dev, struct device_attribute *attr, const char *valbuf, @@ -1220,25 +1358,13 @@ static ssize_t store_latency_timer(struct device *dev, { struct usb_serial_port *port = to_usb_serial_port(dev); struct ftdi_private *priv = usb_get_serial_port_data(port); - struct usb_device *udev = port->serial->dev; - char buf[1]; int v = simple_strtoul(valbuf, NULL, 10); int rv = 0; - dbg("%s: setting latency timer = %i", __func__, v); - - rv = usb_control_msg(udev, - usb_sndctrlpipe(udev, 0), - FTDI_SIO_SET_LATENCY_TIMER_REQUEST, - FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE, - v, priv->interface, - buf, 0, WDR_TIMEOUT); - - if (rv < 0) { - dev_err(dev, "Unable to write latency timer: %i\n", rv); + priv->latency = v; + rv = write_latency_timer(port); + if (rv < 0) return -EIO; - } - return count; } @@ -1290,7 +1416,9 @@ static int create_sysfs_attrs(struct usb_serial_port *port) if ((!retval) && (priv->chip_type == FT232BM || priv->chip_type == FT2232C || - priv->chip_type == FT232RL)) { + priv->chip_type == FT232RL || + priv->chip_type == FT2232H || + priv->chip_type == FT4232H)) { retval = device_create_file(&port->dev, &dev_attr_latency_timer); } @@ -1309,7 +1437,9 @@ static void remove_sysfs_attrs(struct usb_serial_port *port) device_remove_file(&port->dev, &dev_attr_event_char); if (priv->chip_type == FT232BM || priv->chip_type == FT2232C || - priv->chip_type == FT232RL) { + priv->chip_type == FT232RL || + priv->chip_type == FT2232H || + priv->chip_type == FT4232H) { device_remove_file(&port->dev, &dev_attr_latency_timer); } } @@ -1392,6 +1522,8 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port) usb_set_serial_port_data(port, priv); ftdi_determine_type(port); + ftdi_set_max_packet_size(port); + read_latency_timer(port); create_sysfs_attrs(port); return 0; } @@ -1460,18 +1592,6 @@ static int ftdi_mtxorb_hack_setup(struct usb_serial *serial) return 0; } -/* ftdi_shutdown is called from usbserial:usb_serial_disconnect - * it is called when the usb device is disconnected - * - * usbserial:usb_serial_disconnect - * calls __serial_close for each open of the port - * shutdown is called then (ie ftdi_shutdown) - */ -static void ftdi_shutdown(struct usb_serial *serial) -{ - dbg("%s", __func__); -} - static void ftdi_sio_priv_release(struct kref *k) { struct ftdi_private *priv = container_of(k, struct ftdi_private, kref); @@ -1514,6 +1634,8 @@ static int ftdi_open(struct tty_struct *tty, if (tty) tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0; + write_latency_timer(port); + /* No error checking for this (will get errors later anyway) */ /* See ftdi_sio.h for description of what is reset */ usb_control_msg(dev, usb_sndctrlpipe(dev, 0), @@ -1529,11 +1651,6 @@ static int ftdi_open(struct tty_struct *tty, if (tty) ftdi_set_termios(tty, port, tty->termios); - /* FIXME: Flow control might be enabled, so it should be checked - - we have no control of defaults! */ - /* Turn on RTS and DTR since we are not flow controlling by default */ - set_mctrl(port, TIOCM_DTR | TIOCM_RTS); - /* Not throttled */ spin_lock_irqsave(&priv->rx_lock, flags); priv->rx_flags &= ~(THROTTLED | ACTUALLY_THROTTLED); @@ -1558,6 +1675,30 @@ static int ftdi_open(struct tty_struct *tty, } /* ftdi_open */ +static void ftdi_dtr_rts(struct usb_serial_port *port, int on) +{ + struct ftdi_private *priv = usb_get_serial_port_data(port); + char buf[1]; + + mutex_lock(&port->serial->disc_mutex); + if (!port->serial->disconnected) { + /* Disable flow control */ + if (!on && usb_control_msg(port->serial->dev, + usb_sndctrlpipe(port->serial->dev, 0), + FTDI_SIO_SET_FLOW_CTRL_REQUEST, + FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, + 0, priv->interface, buf, 0, + WDR_TIMEOUT) < 0) { + dev_err(&port->dev, "error from flowcontrol urb\n"); + } + /* drop RTS and DTR */ + if (on) + set_mctrl(port, TIOCM_DTR | TIOCM_RTS); + else + clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); + } + mutex_unlock(&port->serial->disc_mutex); +} /* * usbserial:__serial_close only calls ftdi_close if the point is open @@ -1567,31 +1708,12 @@ static int ftdi_open(struct tty_struct *tty, * */ -static void ftdi_close(struct tty_struct *tty, - struct usb_serial_port *port, struct file *filp) +static void ftdi_close(struct usb_serial_port *port) { /* ftdi_close */ - unsigned int c_cflag = tty->termios->c_cflag; struct ftdi_private *priv = usb_get_serial_port_data(port); - char buf[1]; dbg("%s", __func__); - mutex_lock(&port->serial->disc_mutex); - if (c_cflag & HUPCL && !port->serial->disconnected) { - /* Disable flow control */ - if (usb_control_msg(port->serial->dev, - usb_sndctrlpipe(port->serial->dev, 0), - FTDI_SIO_SET_FLOW_CTRL_REQUEST, - FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, - 0, priv->interface, buf, 0, - WDR_TIMEOUT) < 0) { - dev_err(&port->dev, "error from flowcontrol urb\n"); - } - - /* drop RTS and DTR */ - clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); - } /* Note change no line if hupcl is off */ - mutex_unlock(&port->serial->disc_mutex); /* cancel any scheduled reading */ cancel_delayed_work_sync(&priv->rx_work); @@ -1644,8 +1766,8 @@ static int ftdi_write(struct tty_struct *tty, struct usb_serial_port *port, if (data_offset > 0) { /* Original sio needs control bytes too... */ transfer_size += (data_offset * - ((count + (PKTSZ - 1 - data_offset)) / - (PKTSZ - data_offset))); + ((count + (priv->max_packet_size - 1 - data_offset)) / + (priv->max_packet_size - data_offset))); } buffer = kmalloc(transfer_size, GFP_ATOMIC); @@ -1667,7 +1789,7 @@ static int ftdi_write(struct tty_struct *tty, struct usb_serial_port *port, if (data_offset > 0) { /* Original sio requires control byte at start of each packet. */ - int user_pktsz = PKTSZ - data_offset; + int user_pktsz = priv->max_packet_size - data_offset; int todo = count; unsigned char *first_byte = buffer; const unsigned char *current_position = buf; @@ -1748,11 +1870,6 @@ static void ftdi_write_bulk_callback(struct urb *urb) dbg("%s - port %d", __func__, port->number); - if (status) { - dbg("nonzero write bulk status received: %d", status); - return; - } - priv = usb_get_serial_port_data(port); if (!priv) { dbg("%s - bad port private data pointer - exiting", __func__); @@ -1763,13 +1880,18 @@ static void ftdi_write_bulk_callback(struct urb *urb) data_offset = priv->write_offset; if (data_offset > 0) { /* Subtract the control bytes */ - countback -= (data_offset * DIV_ROUND_UP(countback, PKTSZ)); + countback -= (data_offset * DIV_ROUND_UP(countback, priv->max_packet_size)); } spin_lock_irqsave(&priv->tx_lock, flags); --priv->tx_outstanding_urbs; priv->tx_outstanding_bytes -= countback; spin_unlock_irqrestore(&priv->tx_lock, flags); + if (status) { + dbg("nonzero write bulk status received: %d", status); + return; + } + usb_serial_port_softint(port); } /* ftdi_write_bulk_callback */ @@ -1865,7 +1987,7 @@ static void ftdi_read_bulk_callback(struct urb *urb) /* count data bytes, but not status bytes */ countread = urb->actual_length; - countread -= 2 * DIV_ROUND_UP(countread, PKTSZ); + countread -= 2 * DIV_ROUND_UP(countread, priv->max_packet_size); spin_lock_irqsave(&priv->rx_lock, flags); priv->rx_bytes += countread; spin_unlock_irqrestore(&priv->rx_lock, flags); @@ -1938,7 +2060,7 @@ static void ftdi_process_read(struct work_struct *work) need_flip = 0; for (packet_offset = priv->rx_processed; - packet_offset < urb->actual_length; packet_offset += PKTSZ) { + packet_offset < urb->actual_length; packet_offset += priv->max_packet_size) { int length; /* Compare new line status to the old one, signal if different/ @@ -1953,7 +2075,7 @@ static void ftdi_process_read(struct work_struct *work) priv->prev_status = new_status; } - length = min_t(u32, PKTSZ, urb->actual_length-packet_offset)-2; + length = min_t(u32, priv->max_packet_size, urb->actual_length-packet_offset)-2; if (length < 0) { dev_err(&port->dev, "%s - bad packet length: %d\n", __func__, length+2); @@ -1984,6 +2106,7 @@ static void ftdi_process_read(struct work_struct *work) if (data[packet_offset+1] & FTDI_RS_BI) { error_flag = TTY_BREAK; dbg("BREAK received"); + usb_serial_handle_break(port); } if (data[packet_offset+1] & FTDI_RS_PE) { error_flag = TTY_PARITY; @@ -1998,8 +2121,11 @@ static void ftdi_process_read(struct work_struct *work) /* Note that the error flag is duplicated for every character received since we don't know which character it applied to */ - tty_insert_flip_char(tty, - data[packet_offset + i], error_flag); + if (!usb_serial_handle_sysrq_char(port, + data[packet_offset + i])) + tty_insert_flip_char(tty, + data[packet_offset + i], + error_flag); } need_flip = 1; } @@ -2305,6 +2431,8 @@ static int ftdi_tiocmget(struct tty_struct *tty, struct file *file) case FT232BM: case FT2232C: case FT232RL: + case FT2232H: + case FT4232H: /* the 8U232AM returns a two byte value (the sio is a 1 byte value) - in the same format as the data returned from the in point */ diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index 12330fa1c095..f1d440a728a3 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -10,7 +10,7 @@ * The device is based on the FTDI FT8U100AX chip. It has a DB25 on one side, * USB on the other. * - * Thanx to FTDI (http://www.ftdi.co.uk) for so kindly providing details + * Thanx to FTDI (http://www.ftdichip.com) for so kindly providing details * of the protocol required to talk to the device and ongoing assistence * during development. * @@ -28,11 +28,15 @@ #define FTDI_8U232AM_ALT_PID 0x6006 /* FTDI's alternate PID for above */ #define FTDI_8U2232C_PID 0x6010 /* Dual channel device */ #define FTDI_232RL_PID 0xFBFA /* Product ID for FT232RL */ +#define FTDI_4232H_PID 0x6011 /* Quad channel hi-speed device */ #define FTDI_RELAIS_PID 0xFA10 /* Relais device from Rudolf Gugler */ #define FTDI_NF_RIC_VID 0x0DCD /* Vendor Id */ #define FTDI_NF_RIC_PID 0x0001 /* Product Id */ #define FTDI_USBX_707_PID 0xF857 /* ADSTech IR Blaster USBX-707 */ +/* Larsen and Brusgaard AltiTrack/USBtrack */ +#define LARSENBRUSGAARD_VID 0x0FD8 +#define LB_ALTITRACK_PID 0x0001 /* www.canusb.com Lawicel CANUSB device */ #define FTDI_CANUSB_PID 0xFFA8 /* Product Id */ @@ -873,6 +877,11 @@ #define FTDI_SIO_SET_LATENCY_TIMER 9 /* Set the latency timer */ #define FTDI_SIO_GET_LATENCY_TIMER 10 /* Get the latency timer */ +/* Interface indicies for FT2232, FT2232H and FT4232H devices*/ +#define INTERFACE_A 1 +#define INTERFACE_B 2 +#define INTERFACE_C 3 +#define INTERFACE_D 4 /* * FIC / OpenMoko, Inc. http://wiki.openmoko.org/wiki/Neo1973_Debug_Board_v3 @@ -1036,6 +1045,8 @@ typedef enum { FT232BM = 3, FT2232C = 4, FT232RL = 5, + FT2232H = 6, + FT4232H = 7 } ftdi_chip_type_t; typedef enum { diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c index 586d30ff450b..8839f1c70b7f 100644 --- a/drivers/usb/serial/garmin_gps.c +++ b/drivers/usb/serial/garmin_gps.c @@ -1,7 +1,7 @@ /* * Garmin GPS driver * - * Copyright (C) 2006,2007 Hermann Kneissel herkne@users.sourceforge.net + * Copyright (C) 2006-2009 Hermann Kneissel herkne@users.sourceforge.net * * The latest version of the driver can be found at * http://sourceforge.net/projects/garmin-gps/ @@ -51,7 +51,7 @@ static int debug; */ #define VERSION_MAJOR 0 -#define VERSION_MINOR 31 +#define VERSION_MINOR 33 #define _STR(s) #s #define _DRIVER_VERSION(a, b) "v" _STR(a) "." _STR(b) @@ -129,7 +129,6 @@ struct garmin_data { __u8 state; __u16 flags; __u8 mode; - __u8 ignorePkts; __u8 count; __u8 pkt_id; __u32 serial_num; @@ -141,8 +140,6 @@ struct garmin_data { __u8 inbuffer [GPS_IN_BUFSIZ]; /* tty -> usb */ __u8 outbuffer[GPS_OUT_BUFSIZ]; /* usb -> tty */ __u8 privpkt[4*6]; - atomic_t req_count; - atomic_t resp_count; spinlock_t lock; struct list_head pktlist; }; @@ -170,6 +167,8 @@ struct garmin_data { #define FLAGS_BULK_IN_ACTIVE 0x0020 #define FLAGS_BULK_IN_RESTART 0x0010 #define FLAGS_THROTTLED 0x0008 +#define APP_REQ_SEEN 0x0004 +#define APP_RESP_SEEN 0x0002 #define CLEAR_HALT_REQUIRED 0x0001 #define FLAGS_QUEUING 0x0100 @@ -184,20 +183,16 @@ struct garmin_data { /* function prototypes */ -static void gsp_next_packet(struct garmin_data *garmin_data_p); -static int garmin_write_bulk(struct usb_serial_port *port, +static int gsp_next_packet(struct garmin_data *garmin_data_p); +static int garmin_write_bulk(struct usb_serial_port *port, const unsigned char *buf, int count, int dismiss_ack); /* some special packets to be send or received */ static unsigned char const GARMIN_START_SESSION_REQ[] = { 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0 }; -static unsigned char const GARMIN_START_SESSION_REQ2[] - = { 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0 }; static unsigned char const GARMIN_START_SESSION_REPLY[] = { 0, 0, 0, 0, 6, 0, 0, 0, 4, 0, 0, 0 }; -static unsigned char const GARMIN_SESSION_ACTIVE_REPLY[] - = { 0, 0, 0, 0, 17, 0, 0, 0, 4, 0, 0, 0, 0, 16, 0, 0 }; static unsigned char const GARMIN_BULK_IN_AVAIL_REPLY[] = { 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0 }; static unsigned char const GARMIN_APP_LAYER_REPLY[] @@ -233,13 +228,6 @@ static struct usb_driver garmin_driver = { }; -static inline int noResponseFromAppLayer(struct garmin_data *garmin_data_p) -{ - return atomic_read(&garmin_data_p->req_count) == - atomic_read(&garmin_data_p->resp_count); -} - - static inline int getLayerId(const __u8 *usbPacket) { return __le32_to_cpup((__le32 *)(usbPacket)); @@ -325,8 +313,11 @@ static int pkt_add(struct garmin_data *garmin_data_p, state = garmin_data_p->state; spin_unlock_irqrestore(&garmin_data_p->lock, flags); + dbg("%s - added: pkt: %d - %d bytes", + __func__, pkt->seq, data_length); + /* in serial mode, if someone is waiting for data from - the device, iconvert and send the next packet to tty. */ + the device, convert and send the next packet to tty. */ if (result && (state == STATE_GSP_WAIT_DATA)) gsp_next_packet(garmin_data_p); } @@ -411,7 +402,7 @@ static int gsp_send_ack(struct garmin_data *garmin_data_p, __u8 pkt_id) /* * called for a complete packet received from tty layer * - * the complete packet (pkzid ... cksum) is in garmin_data_p->inbuf starting + * the complete packet (pktid ... cksum) is in garmin_data_p->inbuf starting * at GSP_INITIAL_OFFSET. * * count - number of bytes in the input buffer including space reserved for @@ -501,7 +492,6 @@ static int gsp_receive(struct garmin_data *garmin_data_p, unsigned long flags; int offs = 0; int ack_or_nak_seen = 0; - int i = 0; __u8 *dest; int size; /* dleSeen: set if last byte read was a DLE */ @@ -519,8 +509,8 @@ static int gsp_receive(struct garmin_data *garmin_data_p, skip = garmin_data_p->flags & FLAGS_GSP_SKIP; spin_unlock_irqrestore(&garmin_data_p->lock, flags); - dbg("%s - dle=%d skip=%d size=%d count=%d", - __func__, dleSeen, skip, size, count); + /* dbg("%s - dle=%d skip=%d size=%d count=%d", + __func__, dleSeen, skip, size, count); */ if (size == 0) size = GSP_INITIAL_OFFSET; @@ -568,7 +558,6 @@ static int gsp_receive(struct garmin_data *garmin_data_p, } else if (!skip) { if (dleSeen) { - dbg("non-masked DLE at %d - restarting", i); size = GSP_INITIAL_OFFSET; dleSeen = 0; } @@ -599,19 +588,19 @@ static int gsp_receive(struct garmin_data *garmin_data_p, else garmin_data_p->flags &= ~FLAGS_GSP_DLESEEN; - if (ack_or_nak_seen) - garmin_data_p->state = STATE_GSP_WAIT_DATA; - spin_unlock_irqrestore(&garmin_data_p->lock, flags); - if (ack_or_nak_seen) - gsp_next_packet(garmin_data_p); + if (ack_or_nak_seen) { + if (gsp_next_packet(garmin_data_p) > 0) + garmin_data_p->state = STATE_ACTIVE; + else + garmin_data_p->state = STATE_GSP_WAIT_DATA; + } return count; } - /* * Sends a usb packet to the tty * @@ -733,29 +722,28 @@ static int gsp_send(struct garmin_data *garmin_data_p, } - - - /* * Process the next pending data packet - if there is one */ -static void gsp_next_packet(struct garmin_data *garmin_data_p) +static int gsp_next_packet(struct garmin_data *garmin_data_p) { + int result = 0; struct garmin_packet *pkt = NULL; while ((pkt = pkt_pop(garmin_data_p)) != NULL) { dbg("%s - next pkt: %d", __func__, pkt->seq); - if (gsp_send(garmin_data_p, pkt->data, pkt->size) > 0) { + result = gsp_send(garmin_data_p, pkt->data, pkt->size); + if (result > 0) { kfree(pkt); - return; + return result; } kfree(pkt); } + return result; } - /****************************************************************************** * garmin native mode ******************************************************************************/ @@ -888,14 +876,6 @@ static int garmin_clear(struct garmin_data *garmin_data_p) unsigned long flags; int status = 0; - struct usb_serial_port *port = garmin_data_p->port; - - if (port != NULL && atomic_read(&garmin_data_p->resp_count)) { - /* send a terminate command */ - status = garmin_write_bulk(port, GARMIN_STOP_TRANSFER_REQ, - sizeof(GARMIN_STOP_TRANSFER_REQ), 1); - } - /* flush all queued data */ pkt_clear(garmin_data_p); @@ -908,16 +888,12 @@ static int garmin_clear(struct garmin_data *garmin_data_p) } - - - - static int garmin_init_session(struct usb_serial_port *port) { - unsigned long flags; struct usb_serial *serial = port->serial; struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); int status = 0; + int i = 0; if (status == 0) { usb_kill_urb(port->interrupt_in_urb); @@ -931,30 +907,25 @@ static int garmin_init_session(struct usb_serial_port *port) __func__, status); } + /* + * using the initialization method from gpsbabel. See comments in + * gpsbabel/jeeps/gpslibusb.c gusb_reset_toggles() + */ if (status == 0) { dbg("%s - starting session ...", __func__); garmin_data_p->state = STATE_ACTIVE; - status = garmin_write_bulk(port, GARMIN_START_SESSION_REQ, + + for (i = 0; i < 3; i++) { + status = garmin_write_bulk(port, + GARMIN_START_SESSION_REQ, sizeof(GARMIN_START_SESSION_REQ), 0); - if (status >= 0) { - - spin_lock_irqsave(&garmin_data_p->lock, flags); - garmin_data_p->ignorePkts++; - spin_unlock_irqrestore(&garmin_data_p->lock, flags); - - /* not needed, but the win32 driver does it too ... */ - status = garmin_write_bulk(port, - GARMIN_START_SESSION_REQ2, - sizeof(GARMIN_START_SESSION_REQ2), 0); - if (status >= 0) { - status = 0; - spin_lock_irqsave(&garmin_data_p->lock, flags); - garmin_data_p->ignorePkts++; - spin_unlock_irqrestore(&garmin_data_p->lock, - flags); - } + if (status < 0) + break; } + + if (status > 0) + status = 0; } return status; @@ -962,8 +933,6 @@ static int garmin_init_session(struct usb_serial_port *port) - - static int garmin_open(struct tty_struct *tty, struct usb_serial_port *port, struct file *filp) { @@ -977,8 +946,6 @@ static int garmin_open(struct tty_struct *tty, garmin_data_p->mode = initial_mode; garmin_data_p->count = 0; garmin_data_p->flags = 0; - atomic_set(&garmin_data_p->req_count, 0); - atomic_set(&garmin_data_p->resp_count, 0); spin_unlock_irqrestore(&garmin_data_p->lock, flags); /* shutdown any bulk reads that might be going on */ @@ -993,8 +960,7 @@ static int garmin_open(struct tty_struct *tty, } -static void garmin_close(struct tty_struct *tty, - struct usb_serial_port *port, struct file *filp) +static void garmin_close(struct usb_serial_port *port) { struct usb_serial *serial = port->serial; struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); @@ -1007,6 +973,7 @@ static void garmin_close(struct tty_struct *tty, return; mutex_lock(&port->serial->disc_mutex); + if (!port->serial->disconnected) garmin_clear(garmin_data_p); @@ -1014,25 +981,17 @@ static void garmin_close(struct tty_struct *tty, usb_kill_urb(port->read_urb); usb_kill_urb(port->write_urb); - if (!port->serial->disconnected) { - if (noResponseFromAppLayer(garmin_data_p) || - ((garmin_data_p->flags & CLEAR_HALT_REQUIRED) != 0)) { - process_resetdev_request(port); - garmin_data_p->state = STATE_RESET; - } else { - garmin_data_p->state = STATE_DISCONNECTED; - } - } else { + /* keep reset state so we know that we must start a new session */ + if (garmin_data_p->state != STATE_RESET) garmin_data_p->state = STATE_DISCONNECTED; - } + mutex_unlock(&port->serial->disc_mutex); } + static void garmin_write_bulk_callback(struct urb *urb) { - unsigned long flags; struct usb_serial_port *port = urb->context; - int status = urb->status; if (port) { struct garmin_data *garmin_data_p = @@ -1040,20 +999,13 @@ static void garmin_write_bulk_callback(struct urb *urb) dbg("%s - port %d", __func__, port->number); - if (GARMIN_LAYERID_APPL == getLayerId(urb->transfer_buffer) - && (garmin_data_p->mode == MODE_GARMIN_SERIAL)) { - gsp_send_ack(garmin_data_p, + if (GARMIN_LAYERID_APPL == getLayerId(urb->transfer_buffer)) { + + if (garmin_data_p->mode == MODE_GARMIN_SERIAL) { + gsp_send_ack(garmin_data_p, ((__u8 *)urb->transfer_buffer)[4]); + } } - - if (status) { - dbg("%s - nonzero write bulk status received: %d", - __func__, status); - spin_lock_irqsave(&garmin_data_p->lock, flags); - garmin_data_p->flags |= CLEAR_HALT_REQUIRED; - spin_unlock_irqrestore(&garmin_data_p->lock, flags); - } - usb_serial_port_softint(port); } @@ -1109,7 +1061,11 @@ static int garmin_write_bulk(struct usb_serial_port *port, urb->transfer_flags |= URB_ZERO_PACKET; if (GARMIN_LAYERID_APPL == getLayerId(buffer)) { - atomic_inc(&garmin_data_p->req_count); + + spin_lock_irqsave(&garmin_data_p->lock, flags); + garmin_data_p->flags |= APP_REQ_SEEN; + spin_unlock_irqrestore(&garmin_data_p->lock, flags); + if (garmin_data_p->mode == MODE_GARMIN_SERIAL) { pkt_clear(garmin_data_p); garmin_data_p->state = STATE_GSP_WAIT_DATA; @@ -1141,6 +1097,9 @@ static int garmin_write(struct tty_struct *tty, struct usb_serial_port *port, usb_serial_debug_data(debug, &port->dev, __func__, count, buf); + if (garmin_data_p->state == STATE_RESET) + return -EIO; + /* check for our private packets */ if (count >= GARMIN_PKTHDR_LENGTH) { len = PRIVPKTSIZ; @@ -1185,7 +1144,7 @@ static int garmin_write(struct tty_struct *tty, struct usb_serial_port *port, break; case PRIV_PKTID_RESET_REQ: - atomic_inc(&garmin_data_p->req_count); + process_resetdev_request(port); break; case PRIV_PKTID_SET_DEF_MODE: @@ -1201,8 +1160,6 @@ static int garmin_write(struct tty_struct *tty, struct usb_serial_port *port, } } - garmin_data_p->ignorePkts = 0; - if (garmin_data_p->mode == MODE_GARMIN_SERIAL) { return gsp_receive(garmin_data_p, buf, count); } else { /* MODE_NATIVE */ @@ -1225,31 +1182,33 @@ static int garmin_write_room(struct tty_struct *tty) static void garmin_read_process(struct garmin_data *garmin_data_p, unsigned char *data, unsigned data_length) { + unsigned long flags; + if (garmin_data_p->flags & FLAGS_DROP_DATA) { /* abort-transfer cmd is actice */ dbg("%s - pkt dropped", __func__); } else if (garmin_data_p->state != STATE_DISCONNECTED && garmin_data_p->state != STATE_RESET) { - /* remember any appl.layer packets, so we know - if a reset is required or not when closing - the device */ - if (0 == memcmp(data, GARMIN_APP_LAYER_REPLY, - sizeof(GARMIN_APP_LAYER_REPLY))) { - atomic_inc(&garmin_data_p->resp_count); - } - /* if throttling is active or postprecessing is required put the received data in the input queue, otherwise send it directly to the tty port */ if (garmin_data_p->flags & FLAGS_QUEUING) { pkt_add(garmin_data_p, data, data_length); - } else if (garmin_data_p->mode == MODE_GARMIN_SERIAL) { - if (getLayerId(data) == GARMIN_LAYERID_APPL) + } else if (getLayerId(data) == GARMIN_LAYERID_APPL) { + + spin_lock_irqsave(&garmin_data_p->lock, flags); + garmin_data_p->flags |= APP_RESP_SEEN; + spin_unlock_irqrestore(&garmin_data_p->lock, flags); + + if (garmin_data_p->mode == MODE_GARMIN_SERIAL) { pkt_add(garmin_data_p, data, data_length); - } else { - send_to_tty(garmin_data_p->port, data, data_length); + } else { + send_to_tty(garmin_data_p->port, data, + data_length); + } } + /* ignore system layer packets ... */ } } @@ -1364,8 +1323,6 @@ static void garmin_read_int_callback(struct urb *urb) } else { spin_lock_irqsave(&garmin_data_p->lock, flags); garmin_data_p->flags |= FLAGS_BULK_IN_ACTIVE; - /* do not send this packet to the user */ - garmin_data_p->ignorePkts = 1; spin_unlock_irqrestore(&garmin_data_p->lock, flags); } @@ -1392,17 +1349,7 @@ static void garmin_read_int_callback(struct urb *urb) __func__, garmin_data_p->serial_num); } - if (garmin_data_p->ignorePkts) { - /* this reply belongs to a request generated by the driver, - ignore it. */ - dbg("%s - pkt ignored (%d)", - __func__, garmin_data_p->ignorePkts); - spin_lock_irqsave(&garmin_data_p->lock, flags); - garmin_data_p->ignorePkts--; - spin_unlock_irqrestore(&garmin_data_p->lock, flags); - } else { - garmin_read_process(garmin_data_p, data, urb->actual_length); - } + garmin_read_process(garmin_data_p, data, urb->actual_length); port->interrupt_in_urb->dev = port->serial->dev; retval = usb_submit_urb(urb, GFP_ATOMIC); @@ -1528,7 +1475,7 @@ static int garmin_attach(struct usb_serial *serial) } -static void garmin_shutdown(struct usb_serial *serial) +static void garmin_disconnect(struct usb_serial *serial) { struct usb_serial_port *port = serial->port[0]; struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); @@ -1537,8 +1484,17 @@ static void garmin_shutdown(struct usb_serial *serial) usb_kill_urb(port->interrupt_in_urb); del_timer_sync(&garmin_data_p->timer); +} + + +static void garmin_release(struct usb_serial *serial) +{ + struct usb_serial_port *port = serial->port[0]; + struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); + + dbg("%s", __func__); + kfree(garmin_data_p); - usb_set_serial_port_data(port, NULL); } @@ -1557,7 +1513,8 @@ static struct usb_serial_driver garmin_device = { .throttle = garmin_throttle, .unthrottle = garmin_unthrottle, .attach = garmin_attach, - .shutdown = garmin_shutdown, + .disconnect = garmin_disconnect, + .release = garmin_release, .write = garmin_write, .write_room = garmin_write_room, .write_bulk_callback = garmin_write_bulk_callback, diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index 4cec9906ccf3..932d6241b787 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -63,7 +63,8 @@ struct usb_serial_driver usb_serial_generic_device = { .id_table = generic_device_ids, .usb_driver = &generic_driver, .num_ports = 1, - .shutdown = usb_serial_generic_shutdown, + .disconnect = usb_serial_generic_disconnect, + .release = usb_serial_generic_release, .throttle = usb_serial_generic_throttle, .unthrottle = usb_serial_generic_unthrottle, .resume = usb_serial_generic_resume, @@ -184,13 +185,94 @@ int usb_serial_generic_resume(struct usb_serial *serial) } EXPORT_SYMBOL_GPL(usb_serial_generic_resume); -void usb_serial_generic_close(struct tty_struct *tty, - struct usb_serial_port *port, struct file *filp) +void usb_serial_generic_close(struct usb_serial_port *port) { dbg("%s - port %d", __func__, port->number); generic_cleanup(port); } +static int usb_serial_multi_urb_write(struct tty_struct *tty, + struct usb_serial_port *port, const unsigned char *buf, int count) +{ + unsigned long flags; + struct urb *urb; + unsigned char *buffer; + int status; + int towrite; + int bwrite = 0; + + dbg("%s - port %d", __func__, port->number); + + if (count == 0) + dbg("%s - write request of 0 bytes", __func__); + + while (count > 0) { + towrite = (count > port->bulk_out_size) ? + port->bulk_out_size : count; + spin_lock_irqsave(&port->lock, flags); + if (port->urbs_in_flight > + port->serial->type->max_in_flight_urbs) { + spin_unlock_irqrestore(&port->lock, flags); + dbg("%s - write limit hit\n", __func__); + return bwrite; + } + port->tx_bytes_flight += towrite; + port->urbs_in_flight++; + spin_unlock_irqrestore(&port->lock, flags); + + buffer = kmalloc(towrite, GFP_ATOMIC); + if (!buffer) { + dev_err(&port->dev, + "%s ran out of kernel memory for urb ...\n", __func__); + goto error_no_buffer; + } + + urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!urb) { + dev_err(&port->dev, "%s - no more free urbs\n", + __func__); + goto error_no_urb; + } + + /* Copy data */ + memcpy(buffer, buf + bwrite, towrite); + usb_serial_debug_data(debug, &port->dev, __func__, + towrite, buffer); + /* fill the buffer and send it */ + usb_fill_bulk_urb(urb, port->serial->dev, + usb_sndbulkpipe(port->serial->dev, + port->bulk_out_endpointAddress), + buffer, towrite, + usb_serial_generic_write_bulk_callback, port); + + status = usb_submit_urb(urb, GFP_ATOMIC); + if (status) { + dev_err(&port->dev, + "%s - failed submitting write urb, error %d\n", + __func__, status); + goto error; + } + + /* This urb is the responsibility of the host driver now */ + usb_free_urb(urb); + dbg("%s write: %d", __func__, towrite); + count -= towrite; + bwrite += towrite; + } + return bwrite; + +error: + usb_free_urb(urb); +error_no_urb: + kfree(buffer); +error_no_buffer: + spin_lock_irqsave(&port->lock, flags); + port->urbs_in_flight--; + port->tx_bytes_flight -= towrite; + spin_unlock_irqrestore(&port->lock, flags); + return bwrite; +} + int usb_serial_generic_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count) { @@ -208,6 +290,11 @@ int usb_serial_generic_write(struct tty_struct *tty, /* only do something if we have a bulk out endpoint */ if (serial->num_bulk_out) { unsigned long flags; + + if (serial->type->max_in_flight_urbs) + return usb_serial_multi_urb_write(tty, port, + buf, count); + spin_lock_irqsave(&port->lock, flags); if (port->write_urb_busy) { spin_unlock_irqrestore(&port->lock, flags); @@ -253,20 +340,26 @@ int usb_serial_generic_write(struct tty_struct *tty, /* no bulk out, so return 0 bytes written */ return 0; } +EXPORT_SYMBOL_GPL(usb_serial_generic_write); int usb_serial_generic_write_room(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct usb_serial *serial = port->serial; + unsigned long flags; int room = 0; dbg("%s - port %d", __func__, port->number); - - /* FIXME: Locking */ - if (serial->num_bulk_out) { - if (!(port->write_urb_busy)) - room = port->bulk_out_size; + spin_lock_irqsave(&port->lock, flags); + if (serial->type->max_in_flight_urbs) { + if (port->urbs_in_flight < serial->type->max_in_flight_urbs) + room = port->bulk_out_size * + (serial->type->max_in_flight_urbs - + port->urbs_in_flight); + } else if (serial->num_bulk_out && !(port->write_urb_busy)) { + room = port->bulk_out_size; } + spin_unlock_irqrestore(&port->lock, flags); dbg("%s - returns %d", __func__, room); return room; @@ -277,11 +370,16 @@ int usb_serial_generic_chars_in_buffer(struct tty_struct *tty) struct usb_serial_port *port = tty->driver_data; struct usb_serial *serial = port->serial; int chars = 0; + unsigned long flags; dbg("%s - port %d", __func__, port->number); - /* FIXME: Locking */ - if (serial->num_bulk_out) { + if (serial->type->max_in_flight_urbs) { + spin_lock_irqsave(&port->lock, flags); + chars = port->tx_bytes_flight; + spin_unlock_irqrestore(&port->lock, flags); + } else if (serial->num_bulk_out) { + /* FIXME: Locking */ if (port->write_urb_busy) chars = port->write_urb->transfer_buffer_length; } @@ -291,7 +389,8 @@ int usb_serial_generic_chars_in_buffer(struct tty_struct *tty) } -static void resubmit_read_urb(struct usb_serial_port *port, gfp_t mem_flags) +void usb_serial_generic_resubmit_read_urb(struct usb_serial_port *port, + gfp_t mem_flags) { struct urb *urb = port->read_urb; struct usb_serial *serial = port->serial; @@ -312,25 +411,28 @@ static void resubmit_read_urb(struct usb_serial_port *port, gfp_t mem_flags) "%s - failed resubmitting read urb, error %d\n", __func__, result); } +EXPORT_SYMBOL_GPL(usb_serial_generic_resubmit_read_urb); /* Push data to tty layer and resubmit the bulk read URB */ static void flush_and_resubmit_read_urb(struct usb_serial_port *port) { struct urb *urb = port->read_urb; struct tty_struct *tty = tty_port_tty_get(&port->port); - int room; + char *ch = (char *)urb->transfer_buffer; + int i; + + if (!tty) + goto done; /* Push data to tty */ - if (tty && urb->actual_length) { - room = tty_buffer_request_room(tty, urb->actual_length); - if (room) { - tty_insert_flip_string(tty, urb->transfer_buffer, room); - tty_flip_buffer_push(tty); - } + for (i = 0; i < urb->actual_length; i++, ch++) { + if (!usb_serial_handle_sysrq_char(port, *ch)) + tty_insert_flip_char(tty, *ch, TTY_NORMAL); } + tty_flip_buffer_push(tty); tty_kref_put(tty); - - resubmit_read_urb(port, GFP_ATOMIC); +done: + usb_serial_generic_resubmit_read_urb(port, GFP_ATOMIC); } void usb_serial_generic_read_bulk_callback(struct urb *urb) @@ -364,12 +466,24 @@ EXPORT_SYMBOL_GPL(usb_serial_generic_read_bulk_callback); void usb_serial_generic_write_bulk_callback(struct urb *urb) { + unsigned long flags; struct usb_serial_port *port = urb->context; int status = urb->status; dbg("%s - port %d", __func__, port->number); - port->write_urb_busy = 0; + if (port->serial->type->max_in_flight_urbs) { + spin_lock_irqsave(&port->lock, flags); + --port->urbs_in_flight; + port->tx_bytes_flight -= urb->transfer_buffer_length; + if (port->urbs_in_flight < 0) + port->urbs_in_flight = 0; + spin_unlock_irqrestore(&port->lock, flags); + } else { + /* Handle the case for single urb mode */ + port->write_urb_busy = 0; + } + if (status) { dbg("%s - nonzero write bulk status received: %d", __func__, status); @@ -409,11 +523,36 @@ void usb_serial_generic_unthrottle(struct tty_struct *tty) if (was_throttled) { /* Resume reading from device */ - resubmit_read_urb(port, GFP_KERNEL); + usb_serial_generic_resubmit_read_urb(port, GFP_KERNEL); } } -void usb_serial_generic_shutdown(struct usb_serial *serial) +int usb_serial_handle_sysrq_char(struct usb_serial_port *port, unsigned int ch) +{ + if (port->sysrq && port->console) { + if (ch && time_before(jiffies, port->sysrq)) { + handle_sysrq(ch, tty_port_tty_get(&port->port)); + port->sysrq = 0; + return 1; + } + port->sysrq = 0; + } + return 0; +} +EXPORT_SYMBOL_GPL(usb_serial_handle_sysrq_char); + +int usb_serial_handle_break(struct usb_serial_port *port) +{ + if (!port->sysrq) { + port->sysrq = jiffies + HZ*5; + return 1; + } + port->sysrq = 0; + return 0; +} +EXPORT_SYMBOL_GPL(usb_serial_handle_break); + +void usb_serial_generic_disconnect(struct usb_serial *serial) { int i; @@ -424,3 +563,7 @@ void usb_serial_generic_shutdown(struct usb_serial *serial) generic_cleanup(serial->port[i]); } +void usb_serial_generic_release(struct usb_serial *serial) +{ + dbg("%s", __func__); +} diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index fb4a73d090f6..0191693625d6 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -207,8 +207,7 @@ static void edge_bulk_out_cmd_callback(struct urb *urb); /* function prototypes for the usbserial callbacks */ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port, struct file *filp); -static void edge_close(struct tty_struct *tty, struct usb_serial_port *port, - struct file *filp); +static void edge_close(struct usb_serial_port *port); static int edge_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count); static int edge_write_room(struct tty_struct *tty); @@ -225,7 +224,8 @@ static int edge_tiocmget(struct tty_struct *tty, struct file *file); static int edge_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear); static int edge_startup(struct usb_serial *serial); -static void edge_shutdown(struct usb_serial *serial); +static void edge_disconnect(struct usb_serial *serial); +static void edge_release(struct usb_serial *serial); #include "io_tables.h" /* all of the devices that this driver supports */ @@ -965,7 +965,7 @@ static int edge_open(struct tty_struct *tty, if (!edge_port->txfifo.fifo) { dbg("%s - no memory", __func__); - edge_close(tty, port, filp); + edge_close(port); return -ENOMEM; } @@ -975,7 +975,7 @@ static int edge_open(struct tty_struct *tty, if (!edge_port->write_urb) { dbg("%s - no memory", __func__); - edge_close(tty, port, filp); + edge_close(port); return -ENOMEM; } @@ -1099,8 +1099,7 @@ static void block_until_tx_empty(struct edgeport_port *edge_port) * edge_close * this function is called by the tty driver when a port is closed *****************************************************************************/ -static void edge_close(struct tty_struct *tty, - struct usb_serial_port *port, struct file *filp) +static void edge_close(struct usb_serial_port *port) { struct edgeport_serial *edge_serial; struct edgeport_port *edge_port; @@ -3195,21 +3194,16 @@ static int edge_startup(struct usb_serial *serial) /**************************************************************************** - * edge_shutdown + * edge_disconnect * This function is called whenever the device is removed from the usb bus. ****************************************************************************/ -static void edge_shutdown(struct usb_serial *serial) +static void edge_disconnect(struct usb_serial *serial) { struct edgeport_serial *edge_serial = usb_get_serial_data(serial); - int i; dbg("%s", __func__); /* stop reads and writes on all ports */ - for (i = 0; i < serial->num_ports; ++i) { - kfree(usb_get_serial_port_data(serial->port[i])); - usb_set_serial_port_data(serial->port[i], NULL); - } /* free up our endpoint stuff */ if (edge_serial->is_epic) { usb_kill_urb(edge_serial->interrupt_read_urb); @@ -3220,9 +3214,24 @@ static void edge_shutdown(struct usb_serial *serial) usb_free_urb(edge_serial->read_urb); kfree(edge_serial->bulk_in_buffer); } +} + + +/**************************************************************************** + * edge_release + * This function is called when the device structure is deallocated. + ****************************************************************************/ +static void edge_release(struct usb_serial *serial) +{ + struct edgeport_serial *edge_serial = usb_get_serial_data(serial); + int i; + + dbg("%s", __func__); + + for (i = 0; i < serial->num_ports; ++i) + kfree(usb_get_serial_port_data(serial->port[i])); kfree(edge_serial); - usb_set_serial_data(serial, NULL); } diff --git a/drivers/usb/serial/io_tables.h b/drivers/usb/serial/io_tables.h index 7eb9d67b81b6..9241d3147513 100644 --- a/drivers/usb/serial/io_tables.h +++ b/drivers/usb/serial/io_tables.h @@ -117,7 +117,8 @@ static struct usb_serial_driver edgeport_2port_device = { .throttle = edge_throttle, .unthrottle = edge_unthrottle, .attach = edge_startup, - .shutdown = edge_shutdown, + .disconnect = edge_disconnect, + .release = edge_release, .ioctl = edge_ioctl, .set_termios = edge_set_termios, .tiocmget = edge_tiocmget, @@ -145,7 +146,8 @@ static struct usb_serial_driver edgeport_4port_device = { .throttle = edge_throttle, .unthrottle = edge_unthrottle, .attach = edge_startup, - .shutdown = edge_shutdown, + .disconnect = edge_disconnect, + .release = edge_release, .ioctl = edge_ioctl, .set_termios = edge_set_termios, .tiocmget = edge_tiocmget, @@ -173,7 +175,8 @@ static struct usb_serial_driver edgeport_8port_device = { .throttle = edge_throttle, .unthrottle = edge_unthrottle, .attach = edge_startup, - .shutdown = edge_shutdown, + .disconnect = edge_disconnect, + .release = edge_release, .ioctl = edge_ioctl, .set_termios = edge_set_termios, .tiocmget = edge_tiocmget, @@ -200,7 +203,8 @@ static struct usb_serial_driver epic_device = { .throttle = edge_throttle, .unthrottle = edge_unthrottle, .attach = edge_startup, - .shutdown = edge_shutdown, + .disconnect = edge_disconnect, + .release = edge_release, .ioctl = edge_ioctl, .set_termios = edge_set_termios, .tiocmget = edge_tiocmget, diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index 513b25e044c1..e8bc42f92e79 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -102,7 +102,7 @@ struct edgeport_port { __u8 shadow_mcr; __u8 shadow_lsr; __u8 lsr_mask; - __u32 ump_read_timeout; /* Number of miliseconds the UMP will + __u32 ump_read_timeout; /* Number of milliseconds the UMP will wait without data before completing a read short */ int baud_rate; @@ -2009,8 +2009,7 @@ release_es_lock: return status; } -static void edge_close(struct tty_struct *tty, - struct usb_serial_port *port, struct file *filp) +static void edge_close(struct usb_serial_port *port) { struct edgeport_serial *edge_serial; struct edgeport_port *edge_port; @@ -2664,7 +2663,7 @@ cleanup: return -ENOMEM; } -static void edge_shutdown(struct usb_serial *serial) +static void edge_disconnect(struct usb_serial *serial) { int i; struct edgeport_port *edge_port; @@ -2674,12 +2673,22 @@ static void edge_shutdown(struct usb_serial *serial) for (i = 0; i < serial->num_ports; ++i) { edge_port = usb_get_serial_port_data(serial->port[i]); edge_remove_sysfs_attrs(edge_port->port); + } +} + +static void edge_release(struct usb_serial *serial) +{ + int i; + struct edgeport_port *edge_port; + + dbg("%s", __func__); + + for (i = 0; i < serial->num_ports; ++i) { + edge_port = usb_get_serial_port_data(serial->port[i]); edge_buf_free(edge_port->ep_out_buf); kfree(edge_port); - usb_set_serial_port_data(serial->port[i], NULL); } kfree(usb_get_serial_data(serial)); - usb_set_serial_data(serial, NULL); } @@ -2916,7 +2925,8 @@ static struct usb_serial_driver edgeport_1port_device = { .throttle = edge_throttle, .unthrottle = edge_unthrottle, .attach = edge_startup, - .shutdown = edge_shutdown, + .disconnect = edge_disconnect, + .release = edge_release, .port_probe = edge_create_sysfs_attrs, .ioctl = edge_ioctl, .set_termios = edge_set_termios, @@ -2945,7 +2955,8 @@ static struct usb_serial_driver edgeport_2port_device = { .throttle = edge_throttle, .unthrottle = edge_unthrottle, .attach = edge_startup, - .shutdown = edge_shutdown, + .disconnect = edge_disconnect, + .release = edge_release, .port_probe = edge_create_sysfs_attrs, .ioctl = edge_ioctl, .set_termios = edge_set_termios, diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index cd62825a9ac3..2545d45ce16f 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c @@ -76,11 +76,9 @@ static int initial_wait; /* Function prototypes for an ipaq */ static int ipaq_open(struct tty_struct *tty, struct usb_serial_port *port, struct file *filp); -static void ipaq_close(struct tty_struct *tty, - struct usb_serial_port *port, struct file *filp); +static void ipaq_close(struct usb_serial_port *port); static int ipaq_calc_num_ports(struct usb_serial *serial); static int ipaq_startup(struct usb_serial *serial); -static void ipaq_shutdown(struct usb_serial *serial); static int ipaq_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count); static int ipaq_write_bulk(struct usb_serial_port *port, @@ -577,7 +575,6 @@ static struct usb_serial_driver ipaq_device = { .close = ipaq_close, .attach = ipaq_startup, .calc_num_ports = ipaq_calc_num_ports, - .shutdown = ipaq_shutdown, .write = ipaq_write, .write_room = ipaq_write_room, .chars_in_buffer = ipaq_chars_in_buffer, @@ -714,8 +711,7 @@ error: } -static void ipaq_close(struct tty_struct *tty, - struct usb_serial_port *port, struct file *filp) +static void ipaq_close(struct usb_serial_port *port) { struct ipaq_private *priv = usb_get_serial_port_data(port); @@ -992,11 +988,6 @@ static int ipaq_startup(struct usb_serial *serial) return usb_reset_configuration(serial->dev); } -static void ipaq_shutdown(struct usb_serial *serial) -{ - dbg("%s", __func__); -} - static int __init ipaq_init(void) { int retval; diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c index da2a2b46644a..29ad038b9c8d 100644 --- a/drivers/usb/serial/ipw.c +++ b/drivers/usb/serial/ipw.c @@ -302,23 +302,17 @@ static int ipw_open(struct tty_struct *tty, return 0; } -static void ipw_close(struct tty_struct *tty, - struct usb_serial_port *port, struct file *filp) +static void ipw_dtr_rts(struct usb_serial_port *port, int on) { struct usb_device *dev = port->serial->dev; int result; - if (tty_hung_up_p(filp)) { - dbg("%s: tty_hung_up_p ...", __func__); - return; - } - /*--1: drop the dtr */ dbg("%s:dropping dtr", __func__); result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), IPW_SIO_SET_PIN, USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT, - IPW_PIN_CLRDTR, + on ? IPW_PIN_SETDTR : IPW_PIN_CLRDTR, 0, NULL, 0, @@ -332,7 +326,7 @@ static void ipw_close(struct tty_struct *tty, result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), IPW_SIO_SET_PIN, USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT, - IPW_PIN_CLRRTS, + on ? IPW_PIN_SETRTS : IPW_PIN_CLRRTS, 0, NULL, 0, @@ -340,7 +334,12 @@ static void ipw_close(struct tty_struct *tty, if (result < 0) dev_err(&port->dev, "dropping rts failed (error = %d)\n", result); +} +static void ipw_close(struct usb_serial_port *port) +{ + struct usb_device *dev = port->serial->dev; + int result; /*--3: purge */ dbg("%s:sending purge", __func__); @@ -461,6 +460,7 @@ static struct usb_serial_driver ipw_device = { .num_ports = 1, .open = ipw_open, .close = ipw_close, + .dtr_rts = ipw_dtr_rts, .port_probe = ipw_probe, .port_remove = ipw_disconnect, .write = ipw_write, diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c index 4e2cda93da59..66009b6b763a 100644 --- a/drivers/usb/serial/ir-usb.c +++ b/drivers/usb/serial/ir-usb.c @@ -88,8 +88,7 @@ static int xbof = -1; static int ir_startup (struct usb_serial *serial); static int ir_open(struct tty_struct *tty, struct usb_serial_port *port, struct file *filep); -static void ir_close(struct tty_struct *tty, struct usb_serial_port *port, - struct file *filep); +static void ir_close(struct usb_serial_port *port); static int ir_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count); static void ir_write_bulk_callback (struct urb *urb); @@ -346,8 +345,7 @@ static int ir_open(struct tty_struct *tty, return result; } -static void ir_close(struct tty_struct *tty, - struct usb_serial_port *port, struct file * filp) +static void ir_close(struct usb_serial_port *port) { dbg("%s - port %d", __func__, port->number); diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c index 4473d442b2aa..96873a7a32b0 100644 --- a/drivers/usb/serial/iuu_phoenix.c +++ b/drivers/usb/serial/iuu_phoenix.c @@ -40,7 +40,7 @@ static int debug; /* * Version Information */ -#define DRIVER_VERSION "v0.5" +#define DRIVER_VERSION "v0.10" #define DRIVER_DESC "Infinity USB Unlimited Phoenix driver" static struct usb_device_id id_table[] = { @@ -70,7 +70,6 @@ static void read_rxcmd_callback(struct urb *urb); struct iuu_private { spinlock_t lock; /* store irq state */ wait_queue_head_t delta_msr_wait; - u8 line_control; u8 line_status; u8 termios_initialized; int tiostatus; /* store IUART SIGNAL for tiocmget call */ @@ -122,8 +121,8 @@ static int iuu_startup(struct usb_serial *serial) return 0; } -/* Shutdown function */ -static void iuu_shutdown(struct usb_serial *serial) +/* Release function */ +static void iuu_release(struct usb_serial *serial) { struct usb_serial_port *port = serial->port[0]; struct iuu_private *priv = usb_get_serial_port_data(port); @@ -651,32 +650,33 @@ static int iuu_bulk_write(struct usb_serial_port *port) unsigned long flags; int result; int i; + int buf_len; char *buf_ptr = port->write_urb->transfer_buffer; dbg("%s - enter", __func__); + spin_lock_irqsave(&priv->lock, flags); *buf_ptr++ = IUU_UART_ESC; *buf_ptr++ = IUU_UART_TX; *buf_ptr++ = priv->writelen; - memcpy(buf_ptr, priv->writebuf, - priv->writelen); + memcpy(buf_ptr, priv->writebuf, priv->writelen); + buf_len = priv->writelen; + priv->writelen = 0; + spin_unlock_irqrestore(&priv->lock, flags); if (debug == 1) { - for (i = 0; i < priv->writelen; i++) + for (i = 0; i < buf_len; i++) sprintf(priv->dbgbuf + i*2 , "%02X", priv->writebuf[i]); - priv->dbgbuf[priv->writelen+i*2] = 0; + priv->dbgbuf[buf_len+i*2] = 0; dbg("%s - writing %i chars : %s", __func__, - priv->writelen, priv->dbgbuf); + buf_len, priv->dbgbuf); } usb_fill_bulk_urb(port->write_urb, port->serial->dev, usb_sndbulkpipe(port->serial->dev, port->bulk_out_endpointAddress), - port->write_urb->transfer_buffer, priv->writelen + 3, + port->write_urb->transfer_buffer, buf_len + 3, iuu_rxcmd, port); result = usb_submit_urb(port->write_urb, GFP_ATOMIC); - spin_lock_irqsave(&priv->lock, flags); - priv->writelen = 0; - spin_unlock_irqrestore(&priv->lock, flags); usb_serial_port_softint(port); return result; } @@ -770,14 +770,10 @@ static int iuu_uart_write(struct tty_struct *tty, struct usb_serial_port *port, return -ENOMEM; spin_lock_irqsave(&priv->lock, flags); - if (priv->writelen > 0) { - /* buffer already filled but not commited */ - spin_unlock_irqrestore(&priv->lock, flags); - return 0; - } + /* fill the buffer */ - memcpy(priv->writebuf, buf, count); - priv->writelen = count; + memcpy(priv->writebuf + priv->writelen, buf, count); + priv->writelen += count; spin_unlock_irqrestore(&priv->lock, flags); return count; @@ -819,7 +815,7 @@ static int iuu_uart_on(struct usb_serial_port *port) buf[0] = IUU_UART_ENABLE; buf[1] = (u8) ((IUU_BAUD_9600 >> 8) & 0x00FF); buf[2] = (u8) (0x00FF & IUU_BAUD_9600); - buf[3] = (u8) (0x0F0 & IUU_TWO_STOP_BITS) | (0x07 & IUU_PARITY_EVEN); + buf[3] = (u8) (0x0F0 & IUU_ONE_STOP_BIT) | (0x07 & IUU_PARITY_EVEN); status = bulk_immediate(port, buf, 4); if (status != IUU_OPERATION_OK) { @@ -946,19 +942,59 @@ static int iuu_uart_baud(struct usb_serial_port *port, u32 baud, return status; } -static int set_control_lines(struct usb_device *dev, u8 value) +static void iuu_set_termios(struct tty_struct *tty, + struct usb_serial_port *port, struct ktermios *old_termios) { - return 0; + const u32 supported_mask = CMSPAR|PARENB|PARODD; + + unsigned int cflag = tty->termios->c_cflag; + int status; + u32 actual; + u32 parity; + int csize = CS7; + int baud = 9600; /* Fixed for the moment */ + u32 newval = cflag & supported_mask; + + /* compute the parity parameter */ + parity = 0; + if (cflag & CMSPAR) { /* Using mark space */ + if (cflag & PARODD) + parity |= IUU_PARITY_SPACE; + else + parity |= IUU_PARITY_MARK; + } else if (!(cflag & PARENB)) { + parity |= IUU_PARITY_NONE; + csize = CS8; + } else if (cflag & PARODD) + parity |= IUU_PARITY_ODD; + else + parity |= IUU_PARITY_EVEN; + + parity |= (cflag & CSTOPB ? IUU_TWO_STOP_BITS : IUU_ONE_STOP_BIT); + + /* set it */ + status = iuu_uart_baud(port, + (clockmode == 2) ? 16457 : 9600 * boost / 100, + &actual, parity); + + /* set the termios value to the real one, so the user now what has + * changed. We support few fields so its easies to copy the old hw + * settings back over and then adjust them + */ + if (old_termios) + tty_termios_copy_hw(tty->termios, old_termios); + if (status != 0) /* Set failed - return old bits */ + return; + /* Re-encode speed, parity and csize */ + tty_encode_baud_rate(tty, baud, baud); + tty->termios->c_cflag &= ~(supported_mask|CSIZE); + tty->termios->c_cflag |= newval | csize; } -static void iuu_close(struct tty_struct *tty, - struct usb_serial_port *port, struct file *filp) +static void iuu_close(struct usb_serial_port *port) { /* iuu_led (port,255,0,0,0); */ struct usb_serial *serial; - struct iuu_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - unsigned int c_cflag; serial = port->serial; if (!serial) @@ -968,17 +1004,6 @@ static void iuu_close(struct tty_struct *tty, iuu_uart_off(port); if (serial->dev) { - if (tty) { - c_cflag = tty->termios->c_cflag; - if (c_cflag & HUPCL) { - /* drop DTR and RTS */ - priv = usb_get_serial_port_data(port); - spin_lock_irqsave(&priv->lock, flags); - priv->line_control = 0; - spin_unlock_irqrestore(&priv->lock, flags); - set_control_lines(port->serial->dev, 0); - } - } /* free writebuf */ /* shutdown our urbs */ dbg("%s - shutting down urbs", __func__); @@ -1154,7 +1179,7 @@ static int iuu_open(struct tty_struct *tty, if (result) { dev_err(&port->dev, "%s - failed submitting read urb," " error %d\n", __func__, result); - iuu_close(tty, port, NULL); + iuu_close(port); return -EPROTO; } else { dbg("%s - rxcmd OK", __func__); @@ -1175,8 +1200,9 @@ static struct usb_serial_driver iuu_device = { .read_bulk_callback = iuu_uart_read_callback, .tiocmget = iuu_tiocmget, .tiocmset = iuu_tiocmset, + .set_termios = iuu_set_termios, .attach = iuu_startup, - .shutdown = iuu_shutdown, + .release = iuu_release, }; static int __init iuu_init(void) diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index 00daa8f7759a..2594b8743d3f 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c @@ -1298,8 +1298,16 @@ static inline void stop_urb(struct urb *urb) usb_kill_urb(urb); } -static void keyspan_close(struct tty_struct *tty, - struct usb_serial_port *port, struct file *filp) +static void keyspan_dtr_rts(struct usb_serial_port *port, int on) +{ + struct keyspan_port_private *p_priv = usb_get_serial_port_data(port); + + p_priv->rts_state = on; + p_priv->dtr_state = on; + keyspan_send_setup(port, 0); +} + +static void keyspan_close(struct usb_serial_port *port) { int i; struct usb_serial *serial = port->serial; @@ -1336,7 +1344,6 @@ static void keyspan_close(struct tty_struct *tty, stop_urb(p_priv->out_urbs[i]); } } - tty_port_tty_set(&port->port, NULL); } /* download the firmware to a pre-renumeration device */ @@ -2682,7 +2689,7 @@ static int keyspan_startup(struct usb_serial *serial) return 0; } -static void keyspan_shutdown(struct usb_serial *serial) +static void keyspan_disconnect(struct usb_serial *serial) { int i, j; struct usb_serial_port *port; @@ -2722,6 +2729,17 @@ static void keyspan_shutdown(struct usb_serial *serial) usb_free_urb(p_priv->out_urbs[j]); } } +} + +static void keyspan_release(struct usb_serial *serial) +{ + int i; + struct usb_serial_port *port; + struct keyspan_serial_private *s_priv; + + dbg("%s", __func__); + + s_priv = usb_get_serial_data(serial); /* dbg("Freeing serial->private."); */ kfree(s_priv); diff --git a/drivers/usb/serial/keyspan.h b/drivers/usb/serial/keyspan.h index 38b4582e0734..3107ed15af64 100644 --- a/drivers/usb/serial/keyspan.h +++ b/drivers/usb/serial/keyspan.h @@ -38,11 +38,11 @@ static int keyspan_open (struct tty_struct *tty, struct usb_serial_port *port, struct file *filp); -static void keyspan_close (struct tty_struct *tty, - struct usb_serial_port *port, - struct file *filp); +static void keyspan_close (struct usb_serial_port *port); +static void keyspan_dtr_rts (struct usb_serial_port *port, int on); static int keyspan_startup (struct usb_serial *serial); -static void keyspan_shutdown (struct usb_serial *serial); +static void keyspan_disconnect (struct usb_serial *serial); +static void keyspan_release (struct usb_serial *serial); static int keyspan_write_room (struct tty_struct *tty); static int keyspan_write (struct tty_struct *tty, @@ -562,6 +562,7 @@ static struct usb_serial_driver keyspan_1port_device = { .num_ports = 1, .open = keyspan_open, .close = keyspan_close, + .dtr_rts = keyspan_dtr_rts, .write = keyspan_write, .write_room = keyspan_write_room, .set_termios = keyspan_set_termios, @@ -569,7 +570,8 @@ static struct usb_serial_driver keyspan_1port_device = { .tiocmget = keyspan_tiocmget, .tiocmset = keyspan_tiocmset, .attach = keyspan_startup, - .shutdown = keyspan_shutdown, + .disconnect = keyspan_disconnect, + .release = keyspan_release, }; static struct usb_serial_driver keyspan_2port_device = { @@ -582,6 +584,7 @@ static struct usb_serial_driver keyspan_2port_device = { .num_ports = 2, .open = keyspan_open, .close = keyspan_close, + .dtr_rts = keyspan_dtr_rts, .write = keyspan_write, .write_room = keyspan_write_room, .set_termios = keyspan_set_termios, @@ -589,7 +592,8 @@ static struct usb_serial_driver keyspan_2port_device = { .tiocmget = keyspan_tiocmget, .tiocmset = keyspan_tiocmset, .attach = keyspan_startup, - .shutdown = keyspan_shutdown, + .disconnect = keyspan_disconnect, + .release = keyspan_release, }; static struct usb_serial_driver keyspan_4port_device = { @@ -602,6 +606,7 @@ static struct usb_serial_driver keyspan_4port_device = { .num_ports = 4, .open = keyspan_open, .close = keyspan_close, + .dtr_rts = keyspan_dtr_rts, .write = keyspan_write, .write_room = keyspan_write_room, .set_termios = keyspan_set_termios, @@ -609,7 +614,8 @@ static struct usb_serial_driver keyspan_4port_device = { .tiocmget = keyspan_tiocmget, .tiocmset = keyspan_tiocmset, .attach = keyspan_startup, - .shutdown = keyspan_shutdown, + .disconnect = keyspan_disconnect, + .release = keyspan_release, }; #endif diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index bf1ae247da66..d0b12e40c2b1 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -651,6 +651,35 @@ static int keyspan_pda_chars_in_buffer(struct tty_struct *tty) } +static void keyspan_pda_dtr_rts(struct usb_serial_port *port, int on) +{ + struct usb_serial *serial = port->serial; + + if (serial->dev) { + if (on) + keyspan_pda_set_modem_info(serial, (1<<7) | (1<< 2)); + else + keyspan_pda_set_modem_info(serial, 0); + } +} + +static int keyspan_pda_carrier_raised(struct usb_serial_port *port) +{ + struct usb_serial *serial = port->serial; + unsigned char modembits; + + /* If we can read the modem status and the DCD is low then + carrier is not raised yet */ + if (keyspan_pda_get_modem_info(serial, &modembits) >= 0) { + if (!(modembits & (1>>6))) + return 0; + } + /* Carrier raised, or we failed (eg disconnected) so + progress accordingly */ + return 1; +} + + static int keyspan_pda_open(struct tty_struct *tty, struct usb_serial_port *port, struct file *filp) { @@ -682,13 +711,6 @@ static int keyspan_pda_open(struct tty_struct *tty, priv->tx_room = room; priv->tx_throttled = room ? 0 : 1; - /* the normal serial device seems to always turn on DTR and RTS here, - so do the same */ - if (tty && (tty->termios->c_cflag & CBAUD)) - keyspan_pda_set_modem_info(serial, (1<<7) | (1<<2)); - else - keyspan_pda_set_modem_info(serial, 0); - /*Start reading from the device*/ port->interrupt_in_urb->dev = serial->dev; rc = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); @@ -700,19 +722,11 @@ static int keyspan_pda_open(struct tty_struct *tty, error: return rc; } - - -static void keyspan_pda_close(struct tty_struct *tty, - struct usb_serial_port *port, struct file *filp) +static void keyspan_pda_close(struct usb_serial_port *port) { struct usb_serial *serial = port->serial; if (serial->dev) { - /* the normal serial device seems to always shut - off DTR and RTS now */ - if (tty->termios->c_cflag & HUPCL) - keyspan_pda_set_modem_info(serial, 0); - /* shutdown our bulk reads and writes */ usb_kill_urb(port->write_urb); usb_kill_urb(port->interrupt_in_urb); @@ -795,7 +809,7 @@ static int keyspan_pda_startup(struct usb_serial *serial) return 0; } -static void keyspan_pda_shutdown(struct usb_serial *serial) +static void keyspan_pda_release(struct usb_serial *serial) { dbg("%s", __func__); @@ -839,6 +853,8 @@ static struct usb_serial_driver keyspan_pda_device = { .usb_driver = &keyspan_pda_driver, .id_table = id_table_std, .num_ports = 1, + .dtr_rts = keyspan_pda_dtr_rts, + .carrier_raised = keyspan_pda_carrier_raised, .open = keyspan_pda_open, .close = keyspan_pda_close, .write = keyspan_pda_write, @@ -853,7 +869,7 @@ static struct usb_serial_driver keyspan_pda_device = { .tiocmget = keyspan_pda_tiocmget, .tiocmset = keyspan_pda_tiocmset, .attach = keyspan_pda_startup, - .shutdown = keyspan_pda_shutdown, + .release = keyspan_pda_release, }; diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index fcd9082f3e7f..0f44bb8e8d4f 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -73,11 +73,11 @@ static int debug; * Function prototypes */ static int klsi_105_startup(struct usb_serial *serial); -static void klsi_105_shutdown(struct usb_serial *serial); +static void klsi_105_disconnect(struct usb_serial *serial); +static void klsi_105_release(struct usb_serial *serial); static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port, struct file *filp); -static void klsi_105_close(struct tty_struct *tty, - struct usb_serial_port *port, struct file *filp); +static void klsi_105_close(struct usb_serial_port *port); static int klsi_105_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count); static void klsi_105_write_bulk_callback(struct urb *urb); @@ -132,7 +132,8 @@ static struct usb_serial_driver kl5kusb105d_device = { .tiocmget = klsi_105_tiocmget, .tiocmset = klsi_105_tiocmset, .attach = klsi_105_startup, - .shutdown = klsi_105_shutdown, + .disconnect = klsi_105_disconnect, + .release = klsi_105_release, .throttle = klsi_105_throttle, .unthrottle = klsi_105_unthrottle, }; @@ -316,7 +317,7 @@ err_cleanup: } /* klsi_105_startup */ -static void klsi_105_shutdown(struct usb_serial *serial) +static void klsi_105_disconnect(struct usb_serial *serial) { int i; @@ -326,33 +327,36 @@ static void klsi_105_shutdown(struct usb_serial *serial) for (i = 0; i < serial->num_ports; ++i) { struct klsi_105_private *priv = usb_get_serial_port_data(serial->port[i]); - unsigned long flags; if (priv) { /* kill our write urb pool */ int j; struct urb **write_urbs = priv->write_urb_pool; - spin_lock_irqsave(&priv->lock, flags); for (j = 0; j < NUM_URBS; j++) { if (write_urbs[j]) { - /* FIXME - uncomment the following - * usb_kill_urb call when the host - * controllers get fixed to set - * urb->dev = NULL after the urb is - * finished. Otherwise this call - * oopses. */ - /* usb_kill_urb(write_urbs[j]); */ - kfree(write_urbs[j]->transfer_buffer); + usb_kill_urb(write_urbs[j]); usb_free_urb(write_urbs[j]); } } - spin_unlock_irqrestore(&priv->lock, flags); - kfree(priv); - usb_set_serial_port_data(serial->port[i], NULL); } } -} /* klsi_105_shutdown */ +} /* klsi_105_disconnect */ + + +static void klsi_105_release(struct usb_serial *serial) +{ + int i; + + dbg("%s", __func__); + + for (i = 0; i < serial->num_ports; ++i) { + struct klsi_105_private *priv = + usb_get_serial_port_data(serial->port[i]); + + kfree(priv); + } +} /* klsi_105_release */ static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port, struct file *filp) @@ -447,8 +451,7 @@ exit: } /* klsi_105_open */ -static void klsi_105_close(struct tty_struct *tty, - struct usb_serial_port *port, struct file *filp) +static void klsi_105_close(struct usb_serial_port *port) { struct klsi_105_private *priv = usb_get_serial_port_data(port); int rc; diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c index c148544953b3..6db0e561f680 100644 --- a/drivers/usb/serial/kobil_sct.c +++ b/drivers/usb/serial/kobil_sct.c @@ -69,11 +69,10 @@ static int debug; /* Function prototypes */ static int kobil_startup(struct usb_serial *serial); -static void kobil_shutdown(struct usb_serial *serial); +static void kobil_release(struct usb_serial *serial); static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port, struct file *filp); -static void kobil_close(struct tty_struct *tty, struct usb_serial_port *port, - struct file *filp); +static void kobil_close(struct usb_serial_port *port); static int kobil_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count); static int kobil_write_room(struct tty_struct *tty); @@ -118,7 +117,7 @@ static struct usb_serial_driver kobil_device = { .id_table = id_table, .num_ports = 1, .attach = kobil_startup, - .shutdown = kobil_shutdown, + .release = kobil_release, .ioctl = kobil_ioctl, .set_termios = kobil_set_termios, .tiocmget = kobil_tiocmget, @@ -202,17 +201,13 @@ static int kobil_startup(struct usb_serial *serial) } -static void kobil_shutdown(struct usb_serial *serial) +static void kobil_release(struct usb_serial *serial) { int i; dbg("%s - port %d", __func__, serial->port[0]->number); - for (i = 0; i < serial->num_ports; ++i) { - while (serial->port[i]->port.count > 0) - kobil_close(NULL, serial->port[i], NULL); + for (i = 0; i < serial->num_ports; ++i) kfree(usb_get_serial_port_data(serial->port[i])); - usb_set_serial_port_data(serial->port[i], NULL); - } } @@ -346,11 +341,11 @@ static int kobil_open(struct tty_struct *tty, } -static void kobil_close(struct tty_struct *tty, - struct usb_serial_port *port, struct file *filp) +static void kobil_close(struct usb_serial_port *port) { dbg("%s - port %d", __func__, port->number); + /* FIXME: Add rts/dtr methods */ if (port->write_urb) { usb_kill_urb(port->write_urb); usb_free_urb(port->write_urb); diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index 82930a7d5093..d8825e159aa5 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c @@ -92,11 +92,11 @@ static int debug; * Function prototypes */ static int mct_u232_startup(struct usb_serial *serial); -static void mct_u232_shutdown(struct usb_serial *serial); +static void mct_u232_release(struct usb_serial *serial); static int mct_u232_open(struct tty_struct *tty, struct usb_serial_port *port, struct file *filp); -static void mct_u232_close(struct tty_struct *tty, - struct usb_serial_port *port, struct file *filp); +static void mct_u232_close(struct usb_serial_port *port); +static void mct_u232_dtr_rts(struct usb_serial_port *port, int on); static void mct_u232_read_int_callback(struct urb *urb); static void mct_u232_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old); @@ -140,6 +140,7 @@ static struct usb_serial_driver mct_u232_device = { .num_ports = 1, .open = mct_u232_open, .close = mct_u232_close, + .dtr_rts = mct_u232_dtr_rts, .throttle = mct_u232_throttle, .unthrottle = mct_u232_unthrottle, .read_int_callback = mct_u232_read_int_callback, @@ -148,7 +149,7 @@ static struct usb_serial_driver mct_u232_device = { .tiocmget = mct_u232_tiocmget, .tiocmset = mct_u232_tiocmset, .attach = mct_u232_startup, - .shutdown = mct_u232_shutdown, + .release = mct_u232_release, }; @@ -406,7 +407,7 @@ static int mct_u232_startup(struct usb_serial *serial) } /* mct_u232_startup */ -static void mct_u232_shutdown(struct usb_serial *serial) +static void mct_u232_release(struct usb_serial *serial) { struct mct_u232_private *priv; int i; @@ -416,12 +417,9 @@ static void mct_u232_shutdown(struct usb_serial *serial) for (i = 0; i < serial->num_ports; ++i) { /* My special items, the standard routines free my urbs */ priv = usb_get_serial_port_data(serial->port[i]); - if (priv) { - usb_set_serial_port_data(serial->port[i], NULL); - kfree(priv); - } + kfree(priv); } -} /* mct_u232_shutdown */ +} /* mct_u232_release */ static int mct_u232_open(struct tty_struct *tty, struct usb_serial_port *port, struct file *filp) @@ -496,29 +494,29 @@ error: return retval; } /* mct_u232_open */ - -static void mct_u232_close(struct tty_struct *tty, - struct usb_serial_port *port, struct file *filp) +static void mct_u232_dtr_rts(struct usb_serial_port *port, int on) { - unsigned int c_cflag; unsigned int control_state; struct mct_u232_private *priv = usb_get_serial_port_data(port); - dbg("%s port %d", __func__, port->number); - if (tty) { - c_cflag = tty->termios->c_cflag; - mutex_lock(&port->serial->disc_mutex); - if (c_cflag & HUPCL && !port->serial->disconnected) { - /* drop DTR and RTS */ - spin_lock_irq(&priv->lock); + mutex_lock(&port->serial->disc_mutex); + if (!port->serial->disconnected) { + /* drop DTR and RTS */ + spin_lock_irq(&priv->lock); + if (on) + priv->control_state |= TIOCM_DTR | TIOCM_RTS; + else priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS); - control_state = priv->control_state; - spin_unlock_irq(&priv->lock); - mct_u232_set_modem_ctrl(port->serial, control_state); - } - mutex_unlock(&port->serial->disc_mutex); + control_state = priv->control_state; + spin_unlock_irq(&priv->lock); + mct_u232_set_modem_ctrl(port->serial, control_state); } + mutex_unlock(&port->serial->disc_mutex); +} +static void mct_u232_close(struct usb_serial_port *port) +{ + dbg("%s port %d", __func__, port->number); if (port->serial->dev) { /* shutdown our urbs */ diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index 24e3b5d4b4d4..bfc5ce000ef9 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -533,8 +533,7 @@ static int mos7720_chars_in_buffer(struct tty_struct *tty) return chars; } -static void mos7720_close(struct tty_struct *tty, - struct usb_serial_port *port, struct file *filp) +static void mos7720_close(struct usb_serial_port *port) { struct usb_serial *serial; struct moschip_port *mos7720_port; @@ -1522,19 +1521,16 @@ static int mos7720_startup(struct usb_serial *serial) return 0; } -static void mos7720_shutdown(struct usb_serial *serial) +static void mos7720_release(struct usb_serial *serial) { int i; /* free private structure allocated for serial port */ - for (i = 0; i < serial->num_ports; ++i) { + for (i = 0; i < serial->num_ports; ++i) kfree(usb_get_serial_port_data(serial->port[i])); - usb_set_serial_port_data(serial->port[i], NULL); - } /* free private structure allocated for serial device */ kfree(usb_get_serial_data(serial)); - usb_set_serial_data(serial, NULL); } static struct usb_driver usb_driver = { @@ -1559,7 +1555,7 @@ static struct usb_serial_driver moschip7720_2port_driver = { .throttle = mos7720_throttle, .unthrottle = mos7720_unthrottle, .attach = mos7720_startup, - .shutdown = mos7720_shutdown, + .release = mos7720_release, .ioctl = mos7720_ioctl, .set_termios = mos7720_set_termios, .write = mos7720_write, diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 84fb1dcd30dc..c40f95c1951c 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -238,7 +238,7 @@ static int mos7840_set_reg_sync(struct usb_serial_port *port, __u16 reg, { struct usb_device *dev = port->serial->dev; val = val & 0x00ff; - dbg("mos7840_set_reg_sync offset is %x, value %x\n", reg, val); + dbg("mos7840_set_reg_sync offset is %x, value %x", reg, val); return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), MCS_WRREQ, MCS_WR_RTYPE, val, reg, NULL, 0, @@ -260,7 +260,7 @@ static int mos7840_get_reg_sync(struct usb_serial_port *port, __u16 reg, ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), MCS_RDREQ, MCS_RD_RTYPE, 0, reg, val, VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT); - dbg("mos7840_get_reg_sync offset is %x, return val %x\n", reg, *val); + dbg("mos7840_get_reg_sync offset is %x, return val %x", reg, *val); *val = (*val) & 0x00ff; return ret; } @@ -282,18 +282,18 @@ static int mos7840_set_uart_reg(struct usb_serial_port *port, __u16 reg, if (port->serial->num_ports == 4) { val |= (((__u16) port->number - (__u16) (port->serial->minor)) + 1) << 8; - dbg("mos7840_set_uart_reg application number is %x\n", val); + dbg("mos7840_set_uart_reg application number is %x", val); } else { if (((__u16) port->number - (__u16) (port->serial->minor)) == 0) { val |= (((__u16) port->number - (__u16) (port->serial->minor)) + 1) << 8; - dbg("mos7840_set_uart_reg application number is %x\n", + dbg("mos7840_set_uart_reg application number is %x", val); } else { val |= (((__u16) port->number - (__u16) (port->serial->minor)) + 2) << 8; - dbg("mos7840_set_uart_reg application number is %x\n", + dbg("mos7840_set_uart_reg application number is %x", val); } } @@ -315,24 +315,24 @@ static int mos7840_get_uart_reg(struct usb_serial_port *port, __u16 reg, int ret = 0; __u16 Wval; - /* dbg("application number is %4x \n", + /* dbg("application number is %4x", (((__u16)port->number - (__u16)(port->serial->minor))+1)<<8); */ /* Wval is same as application number */ if (port->serial->num_ports == 4) { Wval = (((__u16) port->number - (__u16) (port->serial->minor)) + 1) << 8; - dbg("mos7840_get_uart_reg application number is %x\n", Wval); + dbg("mos7840_get_uart_reg application number is %x", Wval); } else { if (((__u16) port->number - (__u16) (port->serial->minor)) == 0) { Wval = (((__u16) port->number - (__u16) (port->serial->minor)) + 1) << 8; - dbg("mos7840_get_uart_reg application number is %x\n", + dbg("mos7840_get_uart_reg application number is %x", Wval); } else { Wval = (((__u16) port->number - (__u16) (port->serial->minor)) + 2) << 8; - dbg("mos7840_get_uart_reg application number is %x\n", + dbg("mos7840_get_uart_reg application number is %x", Wval); } } @@ -346,11 +346,11 @@ static int mos7840_get_uart_reg(struct usb_serial_port *port, __u16 reg, static void mos7840_dump_serial_port(struct moschip_port *mos7840_port) { - dbg("***************************************\n"); - dbg("SpRegOffset is %2x\n", mos7840_port->SpRegOffset); - dbg("ControlRegOffset is %2x \n", mos7840_port->ControlRegOffset); - dbg("DCRRegOffset is %2x \n", mos7840_port->DcrRegOffset); - dbg("***************************************\n"); + dbg("***************************************"); + dbg("SpRegOffset is %2x", mos7840_port->SpRegOffset); + dbg("ControlRegOffset is %2x", mos7840_port->ControlRegOffset); + dbg("DCRRegOffset is %2x", mos7840_port->DcrRegOffset); + dbg("***************************************"); } @@ -474,12 +474,12 @@ static void mos7840_control_callback(struct urb *urb) goto exit; } - dbg("%s urb buffer size is %d\n", __func__, urb->actual_length); - dbg("%s mos7840_port->MsrLsr is %d port %d\n", __func__, + dbg("%s urb buffer size is %d", __func__, urb->actual_length); + dbg("%s mos7840_port->MsrLsr is %d port %d", __func__, mos7840_port->MsrLsr, mos7840_port->port_num); data = urb->transfer_buffer; regval = (__u8) data[0]; - dbg("%s data is %x\n", __func__, regval); + dbg("%s data is %x", __func__, regval); if (mos7840_port->MsrLsr == 0) mos7840_handle_new_msr(mos7840_port, regval); else if (mos7840_port->MsrLsr == 1) @@ -538,7 +538,7 @@ static void mos7840_interrupt_callback(struct urb *urb) __u16 wval, wreg = 0; int status = urb->status; - dbg("%s", " : Entering\n"); + dbg("%s", " : Entering"); switch (status) { case 0: @@ -570,7 +570,7 @@ static void mos7840_interrupt_callback(struct urb *urb) * Byte 5 FIFO status for both */ if (length && length > 5) { - dbg("%s \n", "Wrong data !!!"); + dbg("%s", "Wrong data !!!"); return; } @@ -587,17 +587,17 @@ static void mos7840_interrupt_callback(struct urb *urb) (__u16) (serial->minor)) + 1) << 8; if (mos7840_port->open) { if (sp[i] & 0x01) { - dbg("SP%d No Interrupt !!!\n", i); + dbg("SP%d No Interrupt !!!", i); } else { switch (sp[i] & 0x0f) { case SERIAL_IIR_RLS: dbg("Serial Port %d: Receiver status error or ", i); - dbg("address bit detected in 9-bit mode\n"); + dbg("address bit detected in 9-bit mode"); mos7840_port->MsrLsr = 1; wreg = LINE_STATUS_REGISTER; break; case SERIAL_IIR_MS: - dbg("Serial Port %d: Modem status change\n", i); + dbg("Serial Port %d: Modem status change", i); mos7840_port->MsrLsr = 0; wreg = MODEM_STATUS_REGISTER; break; @@ -689,7 +689,7 @@ static void mos7840_bulk_in_callback(struct urb *urb) mos7840_port = urb->context; if (!mos7840_port) { - dbg("%s", "NULL mos7840_port pointer \n"); + dbg("%s", "NULL mos7840_port pointer"); mos7840_port->read_urb_busy = false; return; } @@ -702,41 +702,41 @@ static void mos7840_bulk_in_callback(struct urb *urb) port = (struct usb_serial_port *)mos7840_port->port; if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Port Paranoia failed \n"); + dbg("%s", "Port Paranoia failed"); mos7840_port->read_urb_busy = false; return; } serial = mos7840_get_usb_serial(port, __func__); if (!serial) { - dbg("%s\n", "Bad serial pointer "); + dbg("%s", "Bad serial pointer"); mos7840_port->read_urb_busy = false; return; } - dbg("%s\n", "Entering... \n"); + dbg("%s", "Entering... "); data = urb->transfer_buffer; - dbg("%s", "Entering ........... \n"); + dbg("%s", "Entering ..........."); if (urb->actual_length) { tty = tty_port_tty_get(&mos7840_port->port->port); if (tty) { tty_buffer_request_room(tty, urb->actual_length); tty_insert_flip_string(tty, data, urb->actual_length); - dbg(" %s \n", data); + dbg(" %s ", data); tty_flip_buffer_push(tty); tty_kref_put(tty); } mos7840_port->icount.rx += urb->actual_length; smp_wmb(); - dbg("mos7840_port->icount.rx is %d:\n", + dbg("mos7840_port->icount.rx is %d:", mos7840_port->icount.rx); } if (!mos7840_port->read_urb) { - dbg("%s", "URB KILLED !!!\n"); + dbg("%s", "URB KILLED !!!"); mos7840_port->read_urb_busy = false; return; } @@ -777,16 +777,16 @@ static void mos7840_bulk_out_data_callback(struct urb *urb) spin_unlock(&mos7840_port->pool_lock); if (status) { - dbg("nonzero write bulk status received:%d\n", status); + dbg("nonzero write bulk status received:%d", status); return; } if (mos7840_port_paranoia_check(mos7840_port->port, __func__)) { - dbg("%s", "Port Paranoia failed \n"); + dbg("%s", "Port Paranoia failed"); return; } - dbg("%s \n", "Entering ........."); + dbg("%s", "Entering ........."); tty = tty_port_tty_get(&mos7840_port->port->port); if (tty && mos7840_port->open) @@ -830,15 +830,17 @@ static int mos7840_open(struct tty_struct *tty, struct moschip_port *mos7840_port; struct moschip_port *port0; + dbg ("%s enter", __func__); + if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Port Paranoia failed \n"); + dbg("%s", "Port Paranoia failed"); return -ENODEV; } serial = port->serial; if (mos7840_serial_paranoia_check(serial, __func__)) { - dbg("%s", "Serial Paranoia failed \n"); + dbg("%s", "Serial Paranoia failed"); return -ENODEV; } @@ -891,20 +893,20 @@ static int mos7840_open(struct tty_struct *tty, Data = 0x0; status = mos7840_get_reg_sync(port, mos7840_port->SpRegOffset, &Data); if (status < 0) { - dbg("Reading Spreg failed\n"); + dbg("Reading Spreg failed"); return -1; } Data |= 0x80; status = mos7840_set_reg_sync(port, mos7840_port->SpRegOffset, Data); if (status < 0) { - dbg("writing Spreg failed\n"); + dbg("writing Spreg failed"); return -1; } Data &= ~0x80; status = mos7840_set_reg_sync(port, mos7840_port->SpRegOffset, Data); if (status < 0) { - dbg("writing Spreg failed\n"); + dbg("writing Spreg failed"); return -1; } /* End of block to be checked */ @@ -913,7 +915,7 @@ static int mos7840_open(struct tty_struct *tty, status = mos7840_get_reg_sync(port, mos7840_port->ControlRegOffset, &Data); if (status < 0) { - dbg("Reading Controlreg failed\n"); + dbg("Reading Controlreg failed"); return -1; } Data |= 0x08; /* Driver done bit */ @@ -921,7 +923,7 @@ static int mos7840_open(struct tty_struct *tty, status = mos7840_set_reg_sync(port, mos7840_port->ControlRegOffset, Data); if (status < 0) { - dbg("writing Controlreg failed\n"); + dbg("writing Controlreg failed"); return -1; } /* do register settings here */ @@ -932,21 +934,21 @@ static int mos7840_open(struct tty_struct *tty, Data = 0x00; status = mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data); if (status < 0) { - dbg("disableing interrupts failed\n"); + dbg("disabling interrupts failed"); return -1; } /* Set FIFO_CONTROL_REGISTER to the default value */ Data = 0x00; status = mos7840_set_uart_reg(port, FIFO_CONTROL_REGISTER, Data); if (status < 0) { - dbg("Writing FIFO_CONTROL_REGISTER failed\n"); + dbg("Writing FIFO_CONTROL_REGISTER failed"); return -1; } Data = 0xcf; status = mos7840_set_uart_reg(port, FIFO_CONTROL_REGISTER, Data); if (status < 0) { - dbg("Writing FIFO_CONTROL_REGISTER failed\n"); + dbg("Writing FIFO_CONTROL_REGISTER failed"); return -1; } @@ -1043,12 +1045,12 @@ static int mos7840_open(struct tty_struct *tty, * (can't set it up in mos7840_startup as the * * structures were not set up at that time.) */ - dbg("port number is %d \n", port->number); - dbg("serial number is %d \n", port->serial->minor); - dbg("Bulkin endpoint is %d \n", port->bulk_in_endpointAddress); - dbg("BulkOut endpoint is %d \n", port->bulk_out_endpointAddress); - dbg("Interrupt endpoint is %d \n", port->interrupt_in_endpointAddress); - dbg("port's number in the device is %d\n", mos7840_port->port_num); + dbg("port number is %d", port->number); + dbg("serial number is %d", port->serial->minor); + dbg("Bulkin endpoint is %d", port->bulk_in_endpointAddress); + dbg("BulkOut endpoint is %d", port->bulk_out_endpointAddress); + dbg("Interrupt endpoint is %d", port->interrupt_in_endpointAddress); + dbg("port's number in the device is %d", mos7840_port->port_num); mos7840_port->read_urb = port->read_urb; /* set up our bulk in urb */ @@ -1061,7 +1063,7 @@ static int mos7840_open(struct tty_struct *tty, mos7840_port->read_urb->transfer_buffer_length, mos7840_bulk_in_callback, mos7840_port); - dbg("mos7840_open: bulkin endpoint is %d\n", + dbg("mos7840_open: bulkin endpoint is %d", port->bulk_in_endpointAddress); mos7840_port->read_urb_busy = true; response = usb_submit_urb(mos7840_port->read_urb, GFP_KERNEL); @@ -1087,9 +1089,11 @@ static int mos7840_open(struct tty_struct *tty, mos7840_port->icount.tx = 0; mos7840_port->icount.rx = 0; - dbg("\n\nusb_serial serial:%p mos7840_port:%p\n usb_serial_port port:%p\n\n", + dbg("usb_serial serial:%p mos7840_port:%p\n usb_serial_port port:%p", serial, mos7840_port, port); + dbg ("%s leave", __func__); + return 0; } @@ -1112,16 +1116,16 @@ static int mos7840_chars_in_buffer(struct tty_struct *tty) unsigned long flags; struct moschip_port *mos7840_port; - dbg("%s \n", " mos7840_chars_in_buffer:entering ..........."); + dbg("%s", " mos7840_chars_in_buffer:entering ..........."); if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Invalid port \n"); + dbg("%s", "Invalid port"); return 0; } mos7840_port = mos7840_get_port_private(port); if (mos7840_port == NULL) { - dbg("%s \n", "mos7840_break:leaving ..........."); + dbg("%s", "mos7840_break:leaving ..........."); return 0; } @@ -1135,54 +1139,12 @@ static int mos7840_chars_in_buffer(struct tty_struct *tty) } -/************************************************************************ - * - * mos7840_block_until_tx_empty - * - * This function will block the close until one of the following: - * 1. TX count are 0 - * 2. The mos7840 has stopped - * 3. A timeout of 3 seconds without activity has expired - * - ************************************************************************/ -static void mos7840_block_until_tx_empty(struct tty_struct *tty, - struct moschip_port *mos7840_port) -{ - int timeout = HZ / 10; - int wait = 30; - int count; - - while (1) { - - count = mos7840_chars_in_buffer(tty); - - /* Check for Buffer status */ - if (count <= 0) - return; - - /* Block the thread for a while */ - interruptible_sleep_on_timeout(&mos7840_port->wait_chase, - timeout); - - /* No activity.. count down section */ - wait--; - if (wait == 0) { - dbg("%s - TIMEOUT", __func__); - return; - } else { - /* Reset timeout value back to seconds */ - wait = 30; - } - } -} - /***************************************************************************** * mos7840_close * this function is called by the tty driver when a port is closed *****************************************************************************/ -static void mos7840_close(struct tty_struct *tty, - struct usb_serial_port *port, struct file *filp) +static void mos7840_close(struct usb_serial_port *port) { struct usb_serial *serial; struct moschip_port *mos7840_port; @@ -1190,16 +1152,16 @@ static void mos7840_close(struct tty_struct *tty, int j; __u16 Data; - dbg("%s\n", "mos7840_close:entering..."); + dbg("%s", "mos7840_close:entering..."); if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Port Paranoia failed \n"); + dbg("%s", "Port Paranoia failed"); return; } serial = mos7840_get_usb_serial(port, __func__); if (!serial) { - dbg("%s", "Serial Paranoia failed \n"); + dbg("%s", "Serial Paranoia failed"); return; } @@ -1223,35 +1185,31 @@ static void mos7840_close(struct tty_struct *tty, } } - if (serial->dev) - /* flush and block until tx is empty */ - mos7840_block_until_tx_empty(tty, mos7840_port); - /* While closing port, shutdown all bulk read, write * * and interrupt read if they exists */ if (serial->dev) { if (mos7840_port->write_urb) { - dbg("%s", "Shutdown bulk write\n"); + dbg("%s", "Shutdown bulk write"); usb_kill_urb(mos7840_port->write_urb); } if (mos7840_port->read_urb) { - dbg("%s", "Shutdown bulk read\n"); + dbg("%s", "Shutdown bulk read"); usb_kill_urb(mos7840_port->read_urb); mos7840_port->read_urb_busy = false; } if ((&mos7840_port->control_urb)) { - dbg("%s", "Shutdown control read\n"); + dbg("%s", "Shutdown control read"); /*/ usb_kill_urb (mos7840_port->control_urb); */ } } /* if(mos7840_port->ctrl_buf != NULL) */ /* kfree(mos7840_port->ctrl_buf); */ port0->open_ports--; - dbg("mos7840_num_open_ports in close%d:in port%d\n", + dbg("mos7840_num_open_ports in close%d:in port%d", port0->open_ports, port->number); if (port0->open_ports == 0) { if (serial->port[0]->interrupt_in_urb) { - dbg("%s", "Shutdown interrupt_in_urb\n"); + dbg("%s", "Shutdown interrupt_in_urb"); usb_kill_urb(serial->port[0]->interrupt_in_urb); } } @@ -1271,7 +1229,7 @@ static void mos7840_close(struct tty_struct *tty, mos7840_port->open = 0; - dbg("%s \n", "Leaving ............"); + dbg("%s", "Leaving ............"); } /************************************************************************ @@ -1326,17 +1284,17 @@ static void mos7840_break(struct tty_struct *tty, int break_state) struct usb_serial *serial; struct moschip_port *mos7840_port; - dbg("%s \n", "Entering ..........."); - dbg("mos7840_break: Start\n"); + dbg("%s", "Entering ..........."); + dbg("mos7840_break: Start"); if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Port Paranoia failed \n"); + dbg("%s", "Port Paranoia failed"); return; } serial = mos7840_get_usb_serial(port, __func__); if (!serial) { - dbg("%s", "Serial Paranoia failed \n"); + dbg("%s", "Serial Paranoia failed"); return; } @@ -1356,7 +1314,7 @@ static void mos7840_break(struct tty_struct *tty, int break_state) /* FIXME: no locking on shadowLCR anywhere in driver */ mos7840_port->shadowLCR = data; - dbg("mcs7840_break mos7840_port->shadowLCR is %x\n", + dbg("mcs7840_break mos7840_port->shadowLCR is %x", mos7840_port->shadowLCR); mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, mos7840_port->shadowLCR); @@ -1380,17 +1338,17 @@ static int mos7840_write_room(struct tty_struct *tty) unsigned long flags; struct moschip_port *mos7840_port; - dbg("%s \n", " mos7840_write_room:entering ..........."); + dbg("%s", " mos7840_write_room:entering ..........."); if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Invalid port \n"); - dbg("%s \n", " mos7840_write_room:leaving ..........."); + dbg("%s", "Invalid port"); + dbg("%s", " mos7840_write_room:leaving ..........."); return -1; } mos7840_port = mos7840_get_port_private(port); if (mos7840_port == NULL) { - dbg("%s \n", "mos7840_break:leaving ..........."); + dbg("%s", "mos7840_break:leaving ..........."); return -1; } @@ -1430,16 +1388,16 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port, /* __u16 Data; */ const unsigned char *current_position = data; unsigned char *data1; - dbg("%s \n", "entering ..........."); - /* dbg("mos7840_write: mos7840_port->shadowLCR is %x\n", + dbg("%s", "entering ..........."); + /* dbg("mos7840_write: mos7840_port->shadowLCR is %x", mos7840_port->shadowLCR); */ #ifdef NOTMOS7840 Data = 0x00; status = mos7840_get_uart_reg(port, LINE_CONTROL_REGISTER, &Data); mos7840_port->shadowLCR = Data; - dbg("mos7840_write: LINE_CONTROL_REGISTER is %x\n", Data); - dbg("mos7840_write: mos7840_port->shadowLCR is %x\n", + dbg("mos7840_write: LINE_CONTROL_REGISTER is %x", Data); + dbg("mos7840_write: mos7840_port->shadowLCR is %x", mos7840_port->shadowLCR); /* Data = 0x03; */ @@ -1453,32 +1411,32 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port, /* status = mos7840_set_uart_reg(port,DIVISOR_LATCH_LSB,Data); */ Data = 0x00; status = mos7840_get_uart_reg(port, DIVISOR_LATCH_LSB, &Data); - dbg("mos7840_write:DLL value is %x\n", Data); + dbg("mos7840_write:DLL value is %x", Data); Data = 0x0; status = mos7840_get_uart_reg(port, DIVISOR_LATCH_MSB, &Data); - dbg("mos7840_write:DLM value is %x\n", Data); + dbg("mos7840_write:DLM value is %x", Data); Data = Data & ~SERIAL_LCR_DLAB; - dbg("mos7840_write: mos7840_port->shadowLCR is %x\n", + dbg("mos7840_write: mos7840_port->shadowLCR is %x", mos7840_port->shadowLCR); status = mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data); #endif if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Port Paranoia failed \n"); + dbg("%s", "Port Paranoia failed"); return -1; } serial = port->serial; if (mos7840_serial_paranoia_check(serial, __func__)) { - dbg("%s", "Serial Paranoia failed \n"); + dbg("%s", "Serial Paranoia failed"); return -1; } mos7840_port = mos7840_get_port_private(port); if (mos7840_port == NULL) { - dbg("%s", "mos7840_port is NULL\n"); + dbg("%s", "mos7840_port is NULL"); return -1; } @@ -1490,7 +1448,7 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port, if (!mos7840_port->busy[i]) { mos7840_port->busy[i] = 1; urb = mos7840_port->write_urb_pool[i]; - dbg("\nURB:%d", i); + dbg("URB:%d", i); break; } } @@ -1525,7 +1483,7 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port, mos7840_bulk_out_data_callback, mos7840_port); data1 = urb->transfer_buffer; - dbg("\nbulkout endpoint is %d", port->bulk_out_endpointAddress); + dbg("bulkout endpoint is %d", port->bulk_out_endpointAddress); /* send it down the pipe */ status = usb_submit_urb(urb, GFP_ATOMIC); @@ -1540,7 +1498,7 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port, bytes_sent = transfer_size; mos7840_port->icount.tx += transfer_size; smp_wmb(); - dbg("mos7840_port->icount.tx is %d:\n", mos7840_port->icount.tx); + dbg("mos7840_port->icount.tx is %d:", mos7840_port->icount.tx); exit: return bytes_sent; @@ -1559,11 +1517,11 @@ static void mos7840_throttle(struct tty_struct *tty) int status; if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Invalid port \n"); + dbg("%s", "Invalid port"); return; } - dbg("- port %d\n", port->number); + dbg("- port %d", port->number); mos7840_port = mos7840_get_port_private(port); @@ -1571,11 +1529,11 @@ static void mos7840_throttle(struct tty_struct *tty) return; if (!mos7840_port->open) { - dbg("%s\n", "port not opened"); + dbg("%s", "port not opened"); return; } - dbg("%s", "Entering .......... \n"); + dbg("%s", "Entering .........."); /* if we are implementing XON/XOFF, send the stop character */ if (I_IXOFF(tty)) { @@ -1609,7 +1567,7 @@ static void mos7840_unthrottle(struct tty_struct *tty) struct moschip_port *mos7840_port = mos7840_get_port_private(port); if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Invalid port \n"); + dbg("%s", "Invalid port"); return; } @@ -1621,7 +1579,7 @@ static void mos7840_unthrottle(struct tty_struct *tty) return; } - dbg("%s", "Entering .......... \n"); + dbg("%s", "Entering .........."); /* if we are implementing XON/XOFF, send the start character */ if (I_IXOFF(tty)) { @@ -1706,7 +1664,7 @@ static int mos7840_tiocmset(struct tty_struct *tty, struct file *file, status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, mcr); if (status < 0) { - dbg("setting MODEM_CONTROL_REGISTER Failed\n"); + dbg("setting MODEM_CONTROL_REGISTER Failed"); return status; } @@ -1775,11 +1733,11 @@ static int mos7840_calc_baud_rate_divisor(int baudRate, int *divisor, custom++; *divisor = custom; - dbg(" Baud %d = %d\n", baudrate, custom); + dbg(" Baud %d = %d", baudrate, custom); return 0; } - dbg("%s\n", " Baud calculation Failed..."); + dbg("%s", " Baud calculation Failed..."); return -1; #endif } @@ -1805,16 +1763,16 @@ static int mos7840_send_cmd_write_baud_rate(struct moschip_port *mos7840_port, port = (struct usb_serial_port *)mos7840_port->port; if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Invalid port \n"); + dbg("%s", "Invalid port"); return -1; } if (mos7840_serial_paranoia_check(port->serial, __func__)) { - dbg("%s", "Invalid Serial \n"); + dbg("%s", "Invalid Serial"); return -1; } - dbg("%s", "Entering .......... \n"); + dbg("%s", "Entering .........."); number = mos7840_port->port->number - mos7840_port->port->serial->minor; @@ -1830,7 +1788,7 @@ static int mos7840_send_cmd_write_baud_rate(struct moschip_port *mos7840_port, status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data); if (status < 0) { - dbg("Writing spreg failed in set_serial_baud\n"); + dbg("Writing spreg failed in set_serial_baud"); return -1; } #endif @@ -1843,7 +1801,7 @@ static int mos7840_send_cmd_write_baud_rate(struct moschip_port *mos7840_port, status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data); if (status < 0) { - dbg("Writing spreg failed in set_serial_baud\n"); + dbg("Writing spreg failed in set_serial_baud"); return -1; } #endif @@ -1858,14 +1816,14 @@ static int mos7840_send_cmd_write_baud_rate(struct moschip_port *mos7840_port, status = mos7840_get_reg_sync(port, mos7840_port->SpRegOffset, &Data); if (status < 0) { - dbg("reading spreg failed in set_serial_baud\n"); + dbg("reading spreg failed in set_serial_baud"); return -1; } Data = (Data & 0x8f) | clk_sel_val; status = mos7840_set_reg_sync(port, mos7840_port->SpRegOffset, Data); if (status < 0) { - dbg("Writing spreg failed in set_serial_baud\n"); + dbg("Writing spreg failed in set_serial_baud"); return -1; } /* Calculate the Divisor */ @@ -1881,11 +1839,11 @@ static int mos7840_send_cmd_write_baud_rate(struct moschip_port *mos7840_port, /* Write the divisor */ Data = (unsigned char)(divisor & 0xff); - dbg("set_serial_baud Value to write DLL is %x\n", Data); + dbg("set_serial_baud Value to write DLL is %x", Data); mos7840_set_uart_reg(port, DIVISOR_LATCH_LSB, Data); Data = (unsigned char)((divisor & 0xff00) >> 8); - dbg("set_serial_baud Value to write DLM is %x\n", Data); + dbg("set_serial_baud Value to write DLM is %x", Data); mos7840_set_uart_reg(port, DIVISOR_LATCH_MSB, Data); /* Disable access to divisor latch */ @@ -1923,12 +1881,12 @@ static void mos7840_change_port_settings(struct tty_struct *tty, port = (struct usb_serial_port *)mos7840_port->port; if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Invalid port \n"); + dbg("%s", "Invalid port"); return; } if (mos7840_serial_paranoia_check(port->serial, __func__)) { - dbg("%s", "Invalid Serial \n"); + dbg("%s", "Invalid Serial"); return; } @@ -1941,7 +1899,7 @@ static void mos7840_change_port_settings(struct tty_struct *tty, return; } - dbg("%s", "Entering .......... \n"); + dbg("%s", "Entering .........."); lData = LCR_BITS_8; lStop = LCR_STOP_1; @@ -2001,7 +1959,7 @@ static void mos7840_change_port_settings(struct tty_struct *tty, ~(LCR_BITS_MASK | LCR_STOP_MASK | LCR_PAR_MASK); mos7840_port->shadowLCR |= (lData | lParity | lStop); - dbg("mos7840_change_port_settings mos7840_port->shadowLCR is %x\n", + dbg("mos7840_change_port_settings mos7840_port->shadowLCR is %x", mos7840_port->shadowLCR); /* Disable Interrupts */ Data = 0x00; @@ -2043,7 +2001,7 @@ static void mos7840_change_port_settings(struct tty_struct *tty, if (!baud) { /* pick a default, any default... */ - dbg("%s\n", "Picked default baud..."); + dbg("%s", "Picked default baud..."); baud = 9600; } @@ -2066,7 +2024,7 @@ static void mos7840_change_port_settings(struct tty_struct *tty, } wake_up(&mos7840_port->delta_msr_wait); mos7840_port->delta_msr_cond = 1; - dbg("mos7840_change_port_settings mos7840_port->shadowLCR is End %x\n", + dbg("mos7840_change_port_settings mos7840_port->shadowLCR is End %x", mos7840_port->shadowLCR); return; @@ -2086,16 +2044,16 @@ static void mos7840_set_termios(struct tty_struct *tty, unsigned int cflag; struct usb_serial *serial; struct moschip_port *mos7840_port; - dbg("mos7840_set_termios: START\n"); + dbg("mos7840_set_termios: START"); if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Invalid port \n"); + dbg("%s", "Invalid port"); return; } serial = port->serial; if (mos7840_serial_paranoia_check(serial, __func__)) { - dbg("%s", "Invalid Serial \n"); + dbg("%s", "Invalid Serial"); return; } @@ -2109,7 +2067,7 @@ static void mos7840_set_termios(struct tty_struct *tty, return; } - dbg("%s\n", "setting termios - "); + dbg("%s", "setting termios - "); cflag = tty->termios->c_cflag; @@ -2124,7 +2082,7 @@ static void mos7840_set_termios(struct tty_struct *tty, mos7840_change_port_settings(tty, mos7840_port, old_termios); if (!mos7840_port->read_urb) { - dbg("%s", "URB KILLED !!!!!\n"); + dbg("%s", "URB KILLED !!!!!"); return; } @@ -2190,7 +2148,7 @@ static int mos7840_set_modem_info(struct moschip_port *mos7840_port, port = (struct usb_serial_port *)mos7840_port->port; if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Invalid port \n"); + dbg("%s", "Invalid port"); return -1; } @@ -2235,7 +2193,7 @@ static int mos7840_set_modem_info(struct moschip_port *mos7840_port, status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data); unlock_kernel(); if (status < 0) { - dbg("setting MODEM_CONTROL_REGISTER Failed\n"); + dbg("setting MODEM_CONTROL_REGISTER Failed"); return -1; } @@ -2320,7 +2278,7 @@ static int mos7840_ioctl(struct tty_struct *tty, struct file *file, int mosret = 0; if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Invalid port \n"); + dbg("%s", "Invalid port"); return -1; } @@ -2420,9 +2378,8 @@ static int mos7840_calc_num_ports(struct usb_serial *serial) { int mos7840_num_ports = 0; - dbg("numberofendpoints: %d \n", - (int)serial->interface->cur_altsetting->desc.bNumEndpoints); - dbg("numberofendpoints: %d \n", + dbg("numberofendpoints: cur %d, alt %d", + (int)serial->interface->cur_altsetting->desc.bNumEndpoints, (int)serial->interface->altsetting->desc.bNumEndpoints); if (serial->interface->cur_altsetting->desc.bNumEndpoints == 5) { mos7840_num_ports = serial->num_ports = 2; @@ -2431,7 +2388,7 @@ static int mos7840_calc_num_ports(struct usb_serial *serial) serial->num_bulk_out = 4; mos7840_num_ports = serial->num_ports = 4; } - + dbg ("mos7840_num_ports = %d", mos7840_num_ports); return mos7840_num_ports; } @@ -2446,22 +2403,24 @@ static int mos7840_startup(struct usb_serial *serial) int i, status; __u16 Data; - dbg("%s \n", " mos7840_startup :entering.........."); + dbg("%s", "mos7840_startup :Entering.........."); if (!serial) { - dbg("%s\n", "Invalid Handler"); + dbg("%s", "Invalid Handler"); return -1; } dev = serial->dev; - dbg("%s\n", "Entering..."); + dbg("%s", "Entering..."); + dbg ("mos7840_startup: serial = %p", serial); /* we set up the pointers to the endpoints in the mos7840_open * * function, as the structures aren't created yet. */ /* set up port private structures */ for (i = 0; i < serial->num_ports; ++i) { + dbg ("mos7840_startup: configuring port %d............", i); mos7840_port = kzalloc(sizeof(struct moschip_port), GFP_KERNEL); if (mos7840_port == NULL) { dev_err(&dev->dev, "%s - Out of memory\n", __func__); @@ -2519,10 +2478,10 @@ static int mos7840_startup(struct usb_serial *serial) status = mos7840_get_reg_sync(serial->port[i], mos7840_port->ControlRegOffset, &Data); if (status < 0) { - dbg("Reading ControlReg failed status-0x%x\n", status); + dbg("Reading ControlReg failed status-0x%x", status); break; } else - dbg("ControlReg Reading success val is %x, status%d\n", + dbg("ControlReg Reading success val is %x, status%d", Data, status); Data |= 0x08; /* setting driver done bit */ Data |= 0x04; /* sp1_bit to have cts change reflect in @@ -2532,10 +2491,10 @@ static int mos7840_startup(struct usb_serial *serial) status = mos7840_set_reg_sync(serial->port[i], mos7840_port->ControlRegOffset, Data); if (status < 0) { - dbg("Writing ControlReg failed(rx_disable) status-0x%x\n", status); + dbg("Writing ControlReg failed(rx_disable) status-0x%x", status); break; } else - dbg("ControlReg Writing success(rx_disable) status%d\n", + dbg("ControlReg Writing success(rx_disable) status%d", status); /* Write default values in DCR (i.e 0x01 in DCR0, 0x05 in DCR2 @@ -2544,48 +2503,48 @@ static int mos7840_startup(struct usb_serial *serial) status = mos7840_set_reg_sync(serial->port[i], (__u16) (mos7840_port->DcrRegOffset + 0), Data); if (status < 0) { - dbg("Writing DCR0 failed status-0x%x\n", status); + dbg("Writing DCR0 failed status-0x%x", status); break; } else - dbg("DCR0 Writing success status%d\n", status); + dbg("DCR0 Writing success status%d", status); Data = 0x05; status = mos7840_set_reg_sync(serial->port[i], (__u16) (mos7840_port->DcrRegOffset + 1), Data); if (status < 0) { - dbg("Writing DCR1 failed status-0x%x\n", status); + dbg("Writing DCR1 failed status-0x%x", status); break; } else - dbg("DCR1 Writing success status%d\n", status); + dbg("DCR1 Writing success status%d", status); Data = 0x24; status = mos7840_set_reg_sync(serial->port[i], (__u16) (mos7840_port->DcrRegOffset + 2), Data); if (status < 0) { - dbg("Writing DCR2 failed status-0x%x\n", status); + dbg("Writing DCR2 failed status-0x%x", status); break; } else - dbg("DCR2 Writing success status%d\n", status); + dbg("DCR2 Writing success status%d", status); /* write values in clkstart0x0 and clkmulti 0x20 */ Data = 0x0; status = mos7840_set_reg_sync(serial->port[i], CLK_START_VALUE_REGISTER, Data); if (status < 0) { - dbg("Writing CLK_START_VALUE_REGISTER failed status-0x%x\n", status); + dbg("Writing CLK_START_VALUE_REGISTER failed status-0x%x", status); break; } else - dbg("CLK_START_VALUE_REGISTER Writing success status%d\n", status); + dbg("CLK_START_VALUE_REGISTER Writing success status%d", status); Data = 0x20; status = mos7840_set_reg_sync(serial->port[i], CLK_MULTI_REGISTER, Data); if (status < 0) { - dbg("Writing CLK_MULTI_REGISTER failed status-0x%x\n", + dbg("Writing CLK_MULTI_REGISTER failed status-0x%x", status); goto error; } else - dbg("CLK_MULTI_REGISTER Writing success status%d\n", + dbg("CLK_MULTI_REGISTER Writing success status%d", status); /* write value 0x0 to scratchpad register */ @@ -2593,11 +2552,11 @@ static int mos7840_startup(struct usb_serial *serial) status = mos7840_set_uart_reg(serial->port[i], SCRATCH_PAD_REGISTER, Data); if (status < 0) { - dbg("Writing SCRATCH_PAD_REGISTER failed status-0x%x\n", + dbg("Writing SCRATCH_PAD_REGISTER failed status-0x%x", status); break; } else - dbg("SCRATCH_PAD_REGISTER Writing success status%d\n", + dbg("SCRATCH_PAD_REGISTER Writing success status%d", status); /* Zero Length flag register */ @@ -2608,30 +2567,30 @@ static int mos7840_startup(struct usb_serial *serial) status = mos7840_set_reg_sync(serial->port[i], (__u16) (ZLP_REG1 + ((__u16)mos7840_port->port_num)), Data); - dbg("ZLIP offset%x\n", + dbg("ZLIP offset %x", (__u16) (ZLP_REG1 + ((__u16) mos7840_port->port_num))); if (status < 0) { - dbg("Writing ZLP_REG%d failed status-0x%x\n", + dbg("Writing ZLP_REG%d failed status-0x%x", i + 2, status); break; } else - dbg("ZLP_REG%d Writing success status%d\n", + dbg("ZLP_REG%d Writing success status%d", i + 2, status); } else { Data = 0xff; status = mos7840_set_reg_sync(serial->port[i], (__u16) (ZLP_REG1 + ((__u16)mos7840_port->port_num) - 0x1), Data); - dbg("ZLIP offset%x\n", + dbg("ZLIP offset %x", (__u16) (ZLP_REG1 + ((__u16) mos7840_port->port_num) - 0x1)); if (status < 0) { - dbg("Writing ZLP_REG%d failed status-0x%x\n", + dbg("Writing ZLP_REG%d failed status-0x%x", i + 1, status); break; } else - dbg("ZLP_REG%d Writing success status%d\n", + dbg("ZLP_REG%d Writing success status%d", i + 1, status); } @@ -2645,15 +2604,16 @@ static int mos7840_startup(struct usb_serial *serial) goto error; } } + dbg ("mos7840_startup: all ports configured..........."); /* Zero Length flag enable */ Data = 0x0f; status = mos7840_set_reg_sync(serial->port[0], ZLP_REG5, Data); if (status < 0) { - dbg("Writing ZLP_REG5 failed status-0x%x\n", status); + dbg("Writing ZLP_REG5 failed status-0x%x", status); goto error; } else - dbg("ZLP_REG5 Writing success status%d\n", status); + dbg("ZLP_REG5 Writing success status%d", status); /* setting configuration feature to one */ usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), @@ -2673,19 +2633,19 @@ error: } /**************************************************************************** - * mos7840_shutdown + * mos7840_disconnect * This function is called whenever the device is removed from the usb bus. ****************************************************************************/ -static void mos7840_shutdown(struct usb_serial *serial) +static void mos7840_disconnect(struct usb_serial *serial) { int i; unsigned long flags; struct moschip_port *mos7840_port; - dbg("%s \n", " shutdown :entering.........."); + dbg("%s", " disconnect :entering.........."); if (!serial) { - dbg("%s", "Invalid Handler \n"); + dbg("%s", "Invalid Handler"); return; } @@ -2702,14 +2662,45 @@ static void mos7840_shutdown(struct usb_serial *serial) mos7840_port->zombie = 1; spin_unlock_irqrestore(&mos7840_port->pool_lock, flags); usb_kill_urb(mos7840_port->control_urb); + } + } + + dbg("%s", "Thank u :: "); + +} + +/**************************************************************************** + * mos7840_release + * This function is called when the usb_serial structure is freed. + ****************************************************************************/ + +static void mos7840_release(struct usb_serial *serial) +{ + int i; + struct moschip_port *mos7840_port; + dbg("%s", " release :entering.........."); + + if (!serial) { + dbg("%s", "Invalid Handler"); + return; + } + + /* check for the ports to be closed,close the ports and disconnect */ + + /* free private structure allocated for serial port * + * stop reads and writes on all ports */ + + for (i = 0; i < serial->num_ports; ++i) { + mos7840_port = mos7840_get_port_private(serial->port[i]); + dbg("mos7840_port %d = %p", i, mos7840_port); + if (mos7840_port) { kfree(mos7840_port->ctrl_buf); kfree(mos7840_port->dr); kfree(mos7840_port); } - mos7840_set_port_private(serial->port[i], NULL); } - dbg("%s\n", "Thank u :: "); + dbg("%s", "Thank u :: "); } @@ -2747,7 +2738,8 @@ static struct usb_serial_driver moschip7840_4port_device = { .tiocmget = mos7840_tiocmget, .tiocmset = mos7840_tiocmset, .attach = mos7840_startup, - .shutdown = mos7840_shutdown, + .disconnect = mos7840_disconnect, + .release = mos7840_release, .read_bulk_callback = mos7840_bulk_in_callback, .read_int_callback = mos7840_interrupt_callback, }; @@ -2760,7 +2752,7 @@ static int __init moschip7840_init(void) { int retval; - dbg("%s \n", " mos7840_init :entering.........."); + dbg("%s", " mos7840_init :entering.........."); /* Register with the usb serial */ retval = usb_serial_register(&moschip7840_4port_device); @@ -2768,14 +2760,14 @@ static int __init moschip7840_init(void) if (retval) goto failed_port_device_register; - dbg("%s\n", "Entring..."); + dbg("%s", "Entering..."); printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" DRIVER_DESC "\n"); /* Register with the usb */ retval = usb_register(&io_driver); if (retval == 0) { - dbg("%s\n", "Leaving..."); + dbg("%s", "Leaving..."); return 0; } usb_serial_deregister(&moschip7840_4port_device); @@ -2790,13 +2782,13 @@ failed_port_device_register: static void __exit moschip7840_exit(void) { - dbg("%s \n", " mos7840_exit :entering.........."); + dbg("%s", " mos7840_exit :entering.........."); usb_deregister(&io_driver); usb_serial_deregister(&moschip7840_4port_device); - dbg("%s\n", "Entring..."); + dbg("%s", "Entering..."); } module_init(moschip7840_init); diff --git a/drivers/usb/serial/navman.c b/drivers/usb/serial/navman.c index bcdcbb822705..f5f3751a888c 100644 --- a/drivers/usb/serial/navman.c +++ b/drivers/usb/serial/navman.c @@ -98,8 +98,7 @@ static int navman_open(struct tty_struct *tty, return result; } -static void navman_close(struct tty_struct *tty, - struct usb_serial_port *port, struct file *filp) +static void navman_close(struct usb_serial_port *port) { dbg("%s - port %d", __func__, port->number); diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c index df6539712726..56857ddbd70b 100644 --- a/drivers/usb/serial/omninet.c +++ b/drivers/usb/serial/omninet.c @@ -66,14 +66,14 @@ static int debug; /* function prototypes */ static int omninet_open(struct tty_struct *tty, struct usb_serial_port *port, struct file *filp); -static void omninet_close(struct tty_struct *tty, struct usb_serial_port *port, - struct file *filp); +static void omninet_close(struct usb_serial_port *port); static void omninet_read_bulk_callback(struct urb *urb); static void omninet_write_bulk_callback(struct urb *urb); static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count); static int omninet_write_room(struct tty_struct *tty); -static void omninet_shutdown(struct usb_serial *serial); +static void omninet_disconnect(struct usb_serial *serial); +static void omninet_release(struct usb_serial *serial); static int omninet_attach(struct usb_serial *serial); static struct usb_device_id id_table[] = { @@ -109,7 +109,8 @@ static struct usb_serial_driver zyxel_omninet_device = { .write_room = omninet_write_room, .read_bulk_callback = omninet_read_bulk_callback, .write_bulk_callback = omninet_write_bulk_callback, - .shutdown = omninet_shutdown, + .disconnect = omninet_disconnect, + .release = omninet_release, }; @@ -189,8 +190,7 @@ static int omninet_open(struct tty_struct *tty, return result; } -static void omninet_close(struct tty_struct *tty, - struct usb_serial_port *port, struct file *filp) +static void omninet_close(struct usb_serial_port *port) { dbg("%s - port %d", __func__, port->number); usb_kill_urb(port->read_urb); @@ -347,13 +347,22 @@ static void omninet_write_bulk_callback(struct urb *urb) } -static void omninet_shutdown(struct usb_serial *serial) +static void omninet_disconnect(struct usb_serial *serial) { struct usb_serial_port *wport = serial->port[1]; - struct usb_serial_port *port = serial->port[0]; + dbg("%s", __func__); usb_kill_urb(wport->write_urb); +} + + +static void omninet_release(struct usb_serial *serial) +{ + struct usb_serial_port *port = serial->port[0]; + + dbg("%s", __func__); + kfree(usb_get_serial_port_data(port)); } diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c index b500ad10b758..336bba79ad32 100644 --- a/drivers/usb/serial/opticon.c +++ b/drivers/usb/serial/opticon.c @@ -173,8 +173,7 @@ static int opticon_open(struct tty_struct *tty, struct usb_serial_port *port, return result; } -static void opticon_close(struct tty_struct *tty, struct usb_serial_port *port, - struct file *filp) +static void opticon_close(struct usb_serial_port *port) { struct opticon_private *priv = usb_get_serial_data(port->serial); @@ -464,7 +463,7 @@ error: return retval; } -static void opticon_shutdown(struct usb_serial *serial) +static void opticon_disconnect(struct usb_serial *serial) { struct opticon_private *priv = usb_get_serial_data(serial); @@ -472,9 +471,16 @@ static void opticon_shutdown(struct usb_serial *serial) usb_kill_urb(priv->bulk_read_urb); usb_free_urb(priv->bulk_read_urb); +} + +static void opticon_release(struct usb_serial *serial) +{ + struct opticon_private *priv = usb_get_serial_data(serial); + + dbg("%s", __func__); + kfree(priv->bulk_in_buffer); kfree(priv); - usb_set_serial_data(serial, NULL); } static int opticon_suspend(struct usb_interface *intf, pm_message_t message) @@ -525,7 +531,8 @@ static struct usb_serial_driver opticon_device = { .close = opticon_close, .write = opticon_write, .write_room = opticon_write_room, - .shutdown = opticon_shutdown, + .disconnect = opticon_disconnect, + .release = opticon_release, .throttle = opticon_throttle, .unthrottle = opticon_unthrottle, .ioctl = opticon_ioctl, diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 7817b82889ca..575816e6ba37 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -43,12 +43,16 @@ #include /* Function prototypes */ +static int option_probe(struct usb_serial *serial, + const struct usb_device_id *id); static int option_open(struct tty_struct *tty, struct usb_serial_port *port, struct file *filp); -static void option_close(struct tty_struct *tty, struct usb_serial_port *port, - struct file *filp); +static void option_close(struct usb_serial_port *port); +static void option_dtr_rts(struct usb_serial_port *port, int on); + static int option_startup(struct usb_serial *serial); -static void option_shutdown(struct usb_serial *serial); +static void option_disconnect(struct usb_serial *serial); +static void option_release(struct usb_serial *serial); static int option_write_room(struct tty_struct *tty); static void option_instat_callback(struct urb *urb); @@ -61,7 +65,7 @@ static void option_set_termios(struct tty_struct *tty, static int option_tiocmget(struct tty_struct *tty, struct file *file); static int option_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear); -static int option_send_setup(struct tty_struct *tty, struct usb_serial_port *port); +static int option_send_setup(struct usb_serial_port *port); static int option_suspend(struct usb_serial *serial, pm_message_t message); static int option_resume(struct usb_serial *serial); @@ -201,9 +205,9 @@ static int option_resume(struct usb_serial *serial); #define NOVATELWIRELESS_PRODUCT_MC727 0x4100 #define NOVATELWIRELESS_PRODUCT_MC950D 0x4400 #define NOVATELWIRELESS_PRODUCT_U727 0x5010 +#define NOVATELWIRELESS_PRODUCT_MC760 0x6000 /* FUTURE NOVATEL PRODUCTS */ -#define NOVATELWIRELESS_PRODUCT_EVDO_FULLSPEED 0X6000 #define NOVATELWIRELESS_PRODUCT_EVDO_HIGHSPEED 0X6001 #define NOVATELWIRELESS_PRODUCT_HSPA_FULLSPEED 0X7000 #define NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED 0X7001 @@ -304,6 +308,10 @@ static int option_resume(struct usb_serial *serial); #define DLINK_PRODUCT_DWM_652 0x3e04 +/* TOSHIBA PRODUCTS */ +#define TOSHIBA_VENDOR_ID 0x0930 +#define TOSHIBA_PRODUCT_HSDPA_MINICARD 0x1302 + static struct usb_device_id option_ids[] = { { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) }, { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) }, @@ -421,7 +429,7 @@ static struct usb_device_id option_ids[] = { { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC950D) }, /* Novatel MC930D/MC950D */ { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC727) }, /* Novatel MC727/U727/USB727 */ { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_U727) }, /* Novatel MC727/U727/USB727 */ - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EVDO_FULLSPEED) }, /* Novatel EVDO product */ + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC760) }, /* Novatel MC760/U760/USB760 */ { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_FULLSPEED) }, /* Novatel HSPA product */ { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EVDO_EMBEDDED_FULLSPEED) }, /* Novatel EVDO Embedded product */ { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_FULLSPEED) }, /* Novatel HSPA Embedded product */ @@ -522,6 +530,7 @@ static struct usb_device_id option_ids[] = { { USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_H10) }, { USB_DEVICE(DLINK_VENDOR_ID, DLINK_PRODUCT_DWM_652) }, { USB_DEVICE(0x1da5, 0x4515) }, /* BenQ H20 */ + { USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_PRODUCT_HSDPA_MINICARD ) }, /* Toshiba 3G HSDPA == Novatel Expedite EU870D MiniCard */ { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, option_ids); @@ -549,8 +558,10 @@ static struct usb_serial_driver option_1port_device = { .usb_driver = &option_driver, .id_table = option_ids, .num_ports = 1, + .probe = option_probe, .open = option_open, .close = option_close, + .dtr_rts = option_dtr_rts, .write = option_write, .write_room = option_write_room, .chars_in_buffer = option_chars_in_buffer, @@ -558,7 +569,8 @@ static struct usb_serial_driver option_1port_device = { .tiocmget = option_tiocmget, .tiocmset = option_tiocmset, .attach = option_startup, - .shutdown = option_shutdown, + .disconnect = option_disconnect, + .release = option_release, .read_int_callback = option_instat_callback, .suspend = option_suspend, .resume = option_resume, @@ -624,13 +636,25 @@ static void __exit option_exit(void) module_init(option_init); module_exit(option_exit); +static int option_probe(struct usb_serial *serial, + const struct usb_device_id *id) +{ + /* D-Link DWM 652 still exposes CD-Rom emulation interface in modem mode */ + if (serial->dev->descriptor.idVendor == DLINK_VENDOR_ID && + serial->dev->descriptor.idProduct == DLINK_PRODUCT_DWM_652 && + serial->interface->cur_altsetting->desc.bInterfaceClass == 0x8) + return -ENODEV; + + return 0; +} + static void option_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) { dbg("%s", __func__); /* Doesn't support option setting */ tty_termios_copy_hw(tty->termios, old_termios); - option_send_setup(tty, port); + option_send_setup(port); } static int option_tiocmget(struct tty_struct *tty, struct file *file) @@ -669,7 +693,7 @@ static int option_tiocmset(struct tty_struct *tty, struct file *file, portdata->rts_state = 0; if (clear & TIOCM_DTR) portdata->dtr_state = 0; - return option_send_setup(tty, port); + return option_send_setup(port); } /* Write */ @@ -897,10 +921,6 @@ static int option_open(struct tty_struct *tty, dbg("%s", __func__); - /* Set some sane defaults */ - portdata->rts_state = 1; - portdata->dtr_state = 1; - /* Reset low level data toggle and start reading from endpoints */ for (i = 0; i < N_IN_URB; i++) { urb = portdata->in_urbs[i]; @@ -936,13 +956,28 @@ static int option_open(struct tty_struct *tty, usb_pipeout(urb->pipe), 0); */ } - option_send_setup(tty, port); + option_send_setup(port); return 0; } -static void option_close(struct tty_struct *tty, - struct usb_serial_port *port, struct file *filp) +static void option_dtr_rts(struct usb_serial_port *port, int on) +{ + struct usb_serial *serial = port->serial; + struct option_port_private *portdata; + + dbg("%s", __func__); + portdata = usb_get_serial_port_data(port); + mutex_lock(&serial->disc_mutex); + portdata->rts_state = on; + portdata->dtr_state = on; + if (serial->dev) + option_send_setup(port); + mutex_unlock(&serial->disc_mutex); +} + + +static void option_close(struct usb_serial_port *port) { int i; struct usb_serial *serial = port->serial; @@ -951,22 +986,13 @@ static void option_close(struct tty_struct *tty, dbg("%s", __func__); portdata = usb_get_serial_port_data(port); - portdata->rts_state = 0; - portdata->dtr_state = 0; - if (serial->dev) { - mutex_lock(&serial->disc_mutex); - if (!serial->disconnected) - option_send_setup(tty, port); - mutex_unlock(&serial->disc_mutex); - /* Stop reading/writing urbs */ for (i = 0; i < N_IN_URB; i++) usb_kill_urb(portdata->in_urbs[i]); for (i = 0; i < N_OUT_URB; i++) usb_kill_urb(portdata->out_urbs[i]); } - tty_port_tty_set(&port->port, NULL); } /* Helper functions used by option_setup_urbs */ @@ -1032,28 +1058,24 @@ static void option_setup_urbs(struct usb_serial *serial) * This is exactly the same as SET_CONTROL_LINE_STATE from the PSTN * CDC. */ -static int option_send_setup(struct tty_struct *tty, - struct usb_serial_port *port) +static int option_send_setup(struct usb_serial_port *port) { struct usb_serial *serial = port->serial; struct option_port_private *portdata; int ifNum = serial->interface->cur_altsetting->desc.bInterfaceNumber; + int val = 0; dbg("%s", __func__); portdata = usb_get_serial_port_data(port); - if (tty) { - int val = 0; - if (portdata->dtr_state) - val |= 0x01; - if (portdata->rts_state) - val |= 0x02; + if (portdata->dtr_state) + val |= 0x01; + if (portdata->rts_state) + val |= 0x02; - return usb_control_msg(serial->dev, - usb_rcvctrlpipe(serial->dev, 0), - 0x22, 0x21, val, ifNum, NULL, 0, USB_CTRL_SET_TIMEOUT); - } - return 0; + return usb_control_msg(serial->dev, + usb_rcvctrlpipe(serial->dev, 0), + 0x22, 0x21, val, ifNum, NULL, 0, USB_CTRL_SET_TIMEOUT); } static int option_startup(struct usb_serial *serial) @@ -1129,7 +1151,14 @@ static void stop_read_write_urbs(struct usb_serial *serial) } } -static void option_shutdown(struct usb_serial *serial) +static void option_disconnect(struct usb_serial *serial) +{ + dbg("%s", __func__); + + stop_read_write_urbs(serial); +} + +static void option_release(struct usb_serial *serial) { int i, j; struct usb_serial_port *port; @@ -1137,8 +1166,6 @@ static void option_shutdown(struct usb_serial *serial) dbg("%s", __func__); - stop_read_write_urbs(serial); - /* Now free them */ for (i = 0; i < serial->num_ports; ++i) { port = serial->port[i]; diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c index ba551f00f16f..3cece27325e7 100644 --- a/drivers/usb/serial/oti6858.c +++ b/drivers/usb/serial/oti6858.c @@ -143,8 +143,7 @@ struct oti6858_control_pkt { /* function prototypes */ static int oti6858_open(struct tty_struct *tty, struct usb_serial_port *port, struct file *filp); -static void oti6858_close(struct tty_struct *tty, - struct usb_serial_port *port, struct file *filp); +static void oti6858_close(struct usb_serial_port *port); static void oti6858_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old); static int oti6858_ioctl(struct tty_struct *tty, struct file *file, @@ -160,7 +159,7 @@ static int oti6858_tiocmget(struct tty_struct *tty, struct file *file); static int oti6858_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear); static int oti6858_startup(struct usb_serial *serial); -static void oti6858_shutdown(struct usb_serial *serial); +static void oti6858_release(struct usb_serial *serial); /* functions operating on buffers */ static struct oti6858_buf *oti6858_buf_alloc(unsigned int size); @@ -195,7 +194,7 @@ static struct usb_serial_driver oti6858_device = { .write_room = oti6858_write_room, .chars_in_buffer = oti6858_chars_in_buffer, .attach = oti6858_startup, - .shutdown = oti6858_shutdown, + .release = oti6858_release, }; struct oti6858_private { @@ -622,67 +621,30 @@ static int oti6858_open(struct tty_struct *tty, if (result != 0) { dev_err(&port->dev, "%s(): usb_submit_urb() failed" " with error %d\n", __func__, result); - oti6858_close(tty, port, NULL); + oti6858_close(port); return -EPROTO; } /* setup termios */ if (tty) oti6858_set_termios(tty, port, &tmp_termios); - + port->port.drain_delay = 256; /* FIXME: check the FIFO length */ return 0; } -static void oti6858_close(struct tty_struct *tty, - struct usb_serial_port *port, struct file *filp) +static void oti6858_close(struct usb_serial_port *port) { struct oti6858_private *priv = usb_get_serial_port_data(port); unsigned long flags; - long timeout; - wait_queue_t wait; dbg("%s(port = %d)", __func__, port->number); - /* wait for data to drain from the buffer */ spin_lock_irqsave(&priv->lock, flags); - timeout = 30 * HZ; /* PL2303_CLOSING_WAIT */ - init_waitqueue_entry(&wait, current); - add_wait_queue(&tty->write_wait, &wait); - dbg("%s(): entering wait loop", __func__); - for (;;) { - set_current_state(TASK_INTERRUPTIBLE); - if (oti6858_buf_data_avail(priv->buf) == 0 - || timeout == 0 || signal_pending(current) - || port->serial->disconnected) - break; - spin_unlock_irqrestore(&priv->lock, flags); - timeout = schedule_timeout(timeout); - spin_lock_irqsave(&priv->lock, flags); - } - set_current_state(TASK_RUNNING); - remove_wait_queue(&tty->write_wait, &wait); - dbg("%s(): after wait loop", __func__); - /* clear out any remaining data in the buffer */ oti6858_buf_clear(priv->buf); spin_unlock_irqrestore(&priv->lock, flags); - /* wait for characters to drain from the device */ - /* (this is long enough for the entire 256 byte */ - /* pl2303 hardware buffer to drain with no flow */ - /* control for data rates of 1200 bps or more, */ - /* for lower rates we should really know how much */ - /* data is in the buffer to compute a delay */ - /* that is not unnecessarily long) */ - /* FIXME - bps = tty_get_baud_rate(tty); - if (bps > 1200) - timeout = max((HZ*2560)/bps,HZ/10); - else - */ - timeout = 2*HZ; - schedule_timeout_interruptible(timeout); - dbg("%s(): after schedule_timeout_interruptible()", __func__); + dbg("%s(): after buf_clear()", __func__); /* cancel scheduled setup */ cancel_delayed_work(&priv->delayed_setup_work); @@ -694,15 +656,6 @@ static void oti6858_close(struct tty_struct *tty, usb_kill_urb(port->write_urb); usb_kill_urb(port->read_urb); usb_kill_urb(port->interrupt_in_urb); - - /* - if (tty && (tty->termios->c_cflag) & HUPCL) { - // drop DTR and RTS - spin_lock_irqsave(&priv->lock, flags); - priv->pending_setup.control &= ~CONTROL_MASK; - spin_unlock_irqrestore(&priv->lock, flags); - } - */ } static int oti6858_tiocmset(struct tty_struct *tty, struct file *file, @@ -829,7 +782,7 @@ static int oti6858_ioctl(struct tty_struct *tty, struct file *file, } -static void oti6858_shutdown(struct usb_serial *serial) +static void oti6858_release(struct usb_serial *serial) { struct oti6858_private *priv; int i; @@ -841,7 +794,6 @@ static void oti6858_shutdown(struct usb_serial *serial) if (priv) { oti6858_buf_free(priv->buf); kfree(priv); - usb_set_serial_port_data(serial->port[i], NULL); } } } diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 751a533a4347..ec6c132a25b5 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -652,69 +652,41 @@ static void pl2303_set_termios(struct tty_struct *tty, kfree(buf); } -static void pl2303_close(struct tty_struct *tty, - struct usb_serial_port *port, struct file *filp) +static void pl2303_dtr_rts(struct usb_serial_port *port, int on) +{ + struct pl2303_private *priv = usb_get_serial_port_data(port); + unsigned long flags; + u8 control; + + spin_lock_irqsave(&priv->lock, flags); + /* Change DTR and RTS */ + if (on) + priv->line_control |= (CONTROL_DTR | CONTROL_RTS); + else + priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS); + control = priv->line_control; + spin_unlock_irqrestore(&priv->lock, flags); + set_control_lines(port->serial->dev, control); +} + +static void pl2303_close(struct usb_serial_port *port) { struct pl2303_private *priv = usb_get_serial_port_data(port); unsigned long flags; - unsigned int c_cflag; - int bps; - long timeout; - wait_queue_t wait; dbg("%s - port %d", __func__, port->number); - /* wait for data to drain from the buffer */ spin_lock_irqsave(&priv->lock, flags); - timeout = PL2303_CLOSING_WAIT; - init_waitqueue_entry(&wait, current); - add_wait_queue(&tty->write_wait, &wait); - for (;;) { - set_current_state(TASK_INTERRUPTIBLE); - if (pl2303_buf_data_avail(priv->buf) == 0 || - timeout == 0 || signal_pending(current) || - port->serial->disconnected) - break; - spin_unlock_irqrestore(&priv->lock, flags); - timeout = schedule_timeout(timeout); - spin_lock_irqsave(&priv->lock, flags); - } - set_current_state(TASK_RUNNING); - remove_wait_queue(&tty->write_wait, &wait); /* clear out any remaining data in the buffer */ pl2303_buf_clear(priv->buf); spin_unlock_irqrestore(&priv->lock, flags); - /* wait for characters to drain from the device */ - /* (this is long enough for the entire 256 byte */ - /* pl2303 hardware buffer to drain with no flow */ - /* control for data rates of 1200 bps or more, */ - /* for lower rates we should really know how much */ - /* data is in the buffer to compute a delay */ - /* that is not unnecessarily long) */ - bps = tty_get_baud_rate(tty); - if (bps > 1200) - timeout = max((HZ*2560)/bps, HZ/10); - else - timeout = 2*HZ; - schedule_timeout_interruptible(timeout); - /* shutdown our urbs */ dbg("%s - shutting down urbs", __func__); usb_kill_urb(port->write_urb); usb_kill_urb(port->read_urb); usb_kill_urb(port->interrupt_in_urb); - if (tty) { - c_cflag = tty->termios->c_cflag; - if (c_cflag & HUPCL) { - /* drop DTR and RTS */ - spin_lock_irqsave(&priv->lock, flags); - priv->line_control = 0; - spin_unlock_irqrestore(&priv->lock, flags); - set_control_lines(port->serial->dev, 0); - } - } } static int pl2303_open(struct tty_struct *tty, @@ -748,7 +720,7 @@ static int pl2303_open(struct tty_struct *tty, if (result) { dev_err(&port->dev, "%s - failed submitting read urb," " error %d\n", __func__, result); - pl2303_close(tty, port, NULL); + pl2303_close(port); return -EPROTO; } @@ -758,9 +730,10 @@ static int pl2303_open(struct tty_struct *tty, if (result) { dev_err(&port->dev, "%s - failed submitting interrupt urb," " error %d\n", __func__, result); - pl2303_close(tty, port, NULL); + pl2303_close(port); return -EPROTO; } + port->port.drain_delay = 256; return 0; } @@ -821,6 +794,14 @@ static int pl2303_tiocmget(struct tty_struct *tty, struct file *file) return result; } +static int pl2303_carrier_raised(struct usb_serial_port *port) +{ + struct pl2303_private *priv = usb_get_serial_port_data(port); + if (priv->line_status & UART_DCD) + return 1; + return 0; +} + static int wait_modem_info(struct usb_serial_port *port, unsigned int arg) { struct pl2303_private *priv = usb_get_serial_port_data(port); @@ -897,7 +878,7 @@ static void pl2303_break_ctl(struct tty_struct *tty, int break_state) dbg("%s - error sending break = %d", __func__, result); } -static void pl2303_shutdown(struct usb_serial *serial) +static void pl2303_release(struct usb_serial *serial) { int i; struct pl2303_private *priv; @@ -909,7 +890,6 @@ static void pl2303_shutdown(struct usb_serial *serial) if (priv) { pl2303_buf_free(priv->buf); kfree(priv); - usb_set_serial_port_data(serial->port[i], NULL); } } } @@ -946,6 +926,8 @@ static void pl2303_update_line_status(struct usb_serial_port *port, spin_lock_irqsave(&priv->lock, flags); priv->line_status = data[status_idx]; spin_unlock_irqrestore(&priv->lock, flags); + if (priv->line_status & UART_BREAK_ERROR) + usb_serial_handle_break(port); wake_up_interruptible(&priv->delta_msr_wait); } @@ -1056,7 +1038,8 @@ static void pl2303_read_bulk_callback(struct urb *urb) if (line_status & UART_OVERRUN_ERROR) tty_insert_flip_char(tty, 0, TTY_OVERRUN); for (i = 0; i < urb->actual_length; ++i) - tty_insert_flip_char(tty, data[i], tty_flag); + if (!usb_serial_handle_sysrq_char(port, data[i])) + tty_insert_flip_char(tty, data[i], tty_flag); tty_flip_buffer_push(tty); } tty_kref_put(tty); @@ -1125,6 +1108,8 @@ static struct usb_serial_driver pl2303_device = { .num_ports = 1, .open = pl2303_open, .close = pl2303_close, + .dtr_rts = pl2303_dtr_rts, + .carrier_raised = pl2303_carrier_raised, .write = pl2303_write, .ioctl = pl2303_ioctl, .break_ctl = pl2303_break_ctl, @@ -1137,7 +1122,7 @@ static struct usb_serial_driver pl2303_device = { .write_room = pl2303_write_room, .chars_in_buffer = pl2303_chars_in_buffer, .attach = pl2303_startup, - .shutdown = pl2303_shutdown, + .release = pl2303_release, }; static int __init pl2303_init(void) diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index 913225c61610..032f7aeb40a4 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -1,7 +1,10 @@ /* USB Driver for Sierra Wireless - Copyright (C) 2006, 2007, 2008 Kevin Lloyd + Copyright (C) 2006, 2007, 2008 Kevin Lloyd , + + Copyright (C) 2008, 2009 Elina Pasheva, Matthew Safar, Rory Filer + IMPORTANT DISCLAIMER: This driver is not commercially supported by Sierra Wireless. Use at your own risk. @@ -14,8 +17,8 @@ Whom based his on the Keyspan driver by Hugh Blemings */ -#define DRIVER_VERSION "v.1.3.3" -#define DRIVER_AUTHOR "Kevin Lloyd " +#define DRIVER_VERSION "v.1.3.7" +#define DRIVER_AUTHOR "Kevin Lloyd, Elina Pasheva, Matthew Safar, Rory Filer" #define DRIVER_DESC "USB Driver for Sierra Wireless USB modems" #include @@ -26,23 +29,32 @@ #include #include #include -#include #define SWIMS_USB_REQUEST_SetPower 0x00 #define SWIMS_USB_REQUEST_SetNmea 0x07 -/* per port private data */ -#define N_IN_URB 4 -#define N_OUT_URB 4 +#define N_IN_URB 8 +#define N_OUT_URB 64 #define IN_BUFLEN 4096 +#define MAX_TRANSFER (PAGE_SIZE - 512) +/* MAX_TRANSFER is chosen so that the VM is not stressed by + allocations > PAGE_SIZE and the number of packets in a page + is an integer 512 is the largest possible packet on EHCI */ + static int debug; static int nmea; +/* Used in interface blacklisting */ +struct sierra_iface_info { + const u32 infolen; /* number of interface numbers on blacklist */ + const u8 *ifaceinfo; /* pointer to the array holding the numbers */ +}; + static int sierra_set_power_state(struct usb_device *udev, __u16 swiState) { int result; - dev_dbg(&udev->dev, "%s", __func__); + dev_dbg(&udev->dev, "%s\n", __func__); result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), SWIMS_USB_REQUEST_SetPower, /* __u8 request */ USB_TYPE_VENDOR, /* __u8 request type */ @@ -57,7 +69,7 @@ static int sierra_set_power_state(struct usb_device *udev, __u16 swiState) static int sierra_vsc_set_nmea(struct usb_device *udev, __u16 enable) { int result; - dev_dbg(&udev->dev, "%s", __func__); + dev_dbg(&udev->dev, "%s\n", __func__); result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), SWIMS_USB_REQUEST_SetNmea, /* __u8 request */ USB_TYPE_VENDOR, /* __u8 request type */ @@ -71,18 +83,39 @@ static int sierra_vsc_set_nmea(struct usb_device *udev, __u16 enable) static int sierra_calc_num_ports(struct usb_serial *serial) { - int result; - int *num_ports = usb_get_serial_data(serial); - dev_dbg(&serial->dev->dev, "%s", __func__); + int num_ports = 0; + u8 ifnum, numendpoints; - result = *num_ports; + dev_dbg(&serial->dev->dev, "%s\n", __func__); - if (result) { - kfree(num_ports); - usb_set_serial_data(serial, NULL); + ifnum = serial->interface->cur_altsetting->desc.bInterfaceNumber; + numendpoints = serial->interface->cur_altsetting->desc.bNumEndpoints; + + /* Dummy interface present on some SKUs should be ignored */ + if (ifnum == 0x99) + num_ports = 0; + else if (numendpoints <= 3) + num_ports = 1; + else + num_ports = (numendpoints-1)/2; + return num_ports; +} + +static int is_blacklisted(const u8 ifnum, + const struct sierra_iface_info *blacklist) +{ + const u8 *info; + int i; + + if (blacklist) { + info = blacklist->ifaceinfo; + + for (i = 0; i < blacklist->infolen; i++) { + if (info[i] == ifnum) + return 1; + } } - - return result; + return 0; } static int sierra_calc_interface(struct usb_serial *serial) @@ -90,7 +123,7 @@ static int sierra_calc_interface(struct usb_serial *serial) int interface; struct usb_interface *p_interface; struct usb_host_interface *p_host_interface; - dev_dbg(&serial->dev->dev, "%s", __func__); + dev_dbg(&serial->dev->dev, "%s\n", __func__); /* Get the interface structure pointer from the serial struct */ p_interface = serial->interface; @@ -111,23 +144,12 @@ static int sierra_probe(struct usb_serial *serial, { int result = 0; struct usb_device *udev; - int *num_ports; u8 ifnum; - u8 numendpoints; - dev_dbg(&serial->dev->dev, "%s", __func__); - - num_ports = kmalloc(sizeof(*num_ports), GFP_KERNEL); - if (!num_ports) - return -ENOMEM; - - ifnum = serial->interface->cur_altsetting->desc.bInterfaceNumber; - numendpoints = serial->interface->cur_altsetting->desc.bNumEndpoints; udev = serial->dev; + dev_dbg(&udev->dev, "%s\n", __func__); - /* Figure out the interface number from the serial structure */ ifnum = sierra_calc_interface(serial); - /* * If this interface supports more than 1 alternate * select the 2nd one @@ -139,23 +161,25 @@ static int sierra_probe(struct usb_serial *serial, usb_set_interface(udev, ifnum, 1); } - /* Dummy interface present on some SKUs should be ignored */ - if (ifnum == 0x99) - *num_ports = 0; - else if (numendpoints <= 3) - *num_ports = 1; - else - *num_ports = (numendpoints-1)/2; + /* ifnum could have changed - by calling usb_set_interface */ + ifnum = sierra_calc_interface(serial); - /* - * save off our num_ports info so that we can use it in the - * calc_num_ports callback - */ - usb_set_serial_data(serial, (void *)num_ports); + if (is_blacklisted(ifnum, + (struct sierra_iface_info *)id->driver_info)) { + dev_dbg(&serial->dev->dev, + "Ignoring blacklisted interface #%d\n", ifnum); + return -ENODEV; + } return result; } +static const u8 direct_ip_non_serial_ifaces[] = { 7, 8, 9, 10, 11 }; +static const struct sierra_iface_info direct_ip_interface_blacklist = { + .infolen = ARRAY_SIZE(direct_ip_non_serial_ifaces), + .ifaceinfo = direct_ip_non_serial_ifaces, +}; + static struct usb_device_id id_table [] = { { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */ { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */ @@ -188,9 +212,11 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(0x1199, 0x6833) }, /* Sierra Wireless MC8781 */ { USB_DEVICE(0x1199, 0x683A) }, /* Sierra Wireless MC8785 */ { USB_DEVICE(0x1199, 0x683B) }, /* Sierra Wireless MC8785 Composite */ - { USB_DEVICE(0x1199, 0x683C) }, /* Sierra Wireless MC8790 */ - { USB_DEVICE(0x1199, 0x683D) }, /* Sierra Wireless MC8790 */ - { USB_DEVICE(0x1199, 0x683E) }, /* Sierra Wireless MC8790 */ + /* Sierra Wireless MC8790, MC8791, MC8792 Composite */ + { USB_DEVICE(0x1199, 0x683C) }, + { USB_DEVICE(0x1199, 0x683D) }, /* Sierra Wireless MC8791 Composite */ + /* Sierra Wireless MC8790, MC8791, MC8792 */ + { USB_DEVICE(0x1199, 0x683E) }, { USB_DEVICE(0x1199, 0x6850) }, /* Sierra Wireless AirCard 880 */ { USB_DEVICE(0x1199, 0x6851) }, /* Sierra Wireless AirCard 881 */ { USB_DEVICE(0x1199, 0x6852) }, /* Sierra Wireless AirCard 880 E */ @@ -211,6 +237,10 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless AirCard 580 */ { USB_DEVICE(0x0F3D, 0x0112) }, /* Airprime/Sierra PC 5220 */ + { USB_DEVICE(0x1199, 0x68A3), /* Sierra Wireless Direct IP modems */ + .driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist + }, + { } }; MODULE_DEVICE_TABLE(usb, id_table); @@ -229,7 +259,6 @@ struct sierra_port_private { /* Input endpoints and buffers for this port */ struct urb *in_urbs[N_IN_URB]; - char *in_buffer[N_IN_URB]; /* Settings for the port */ int rts_state; /* Handshaking pins (outputs) */ @@ -240,66 +269,59 @@ struct sierra_port_private { int ri_state; }; -static int sierra_send_setup(struct tty_struct *tty, - struct usb_serial_port *port) +static int sierra_send_setup(struct usb_serial_port *port) { struct usb_serial *serial = port->serial; struct sierra_port_private *portdata; __u16 interface = 0; + int val = 0; - dev_dbg(&port->dev, "%s", __func__); + dev_dbg(&port->dev, "%s\n", __func__); portdata = usb_get_serial_port_data(port); - if (tty) { - int val = 0; - if (portdata->dtr_state) - val |= 0x01; - if (portdata->rts_state) - val |= 0x02; - - /* If composite device then properly report interface */ - if (serial->num_ports == 1) { - interface = sierra_calc_interface(serial); - - /* Control message is sent only to interfaces with - * interrupt_in endpoints - */ - if (port->interrupt_in_urb) { - /* send control message */ - return usb_control_msg(serial->dev, - usb_rcvctrlpipe(serial->dev, 0), - 0x22, 0x21, val, interface, - NULL, 0, USB_CTRL_SET_TIMEOUT); - } - } - - /* Otherwise the need to do non-composite mapping */ - else { - if (port->bulk_out_endpointAddress == 2) - interface = 0; - else if (port->bulk_out_endpointAddress == 4) - interface = 1; - else if (port->bulk_out_endpointAddress == 5) - interface = 2; + if (portdata->dtr_state) + val |= 0x01; + if (portdata->rts_state) + val |= 0x02; + /* If composite device then properly report interface */ + if (serial->num_ports == 1) { + interface = sierra_calc_interface(serial); + /* Control message is sent only to interfaces with + * interrupt_in endpoints + */ + if (port->interrupt_in_urb) { + /* send control message */ return usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), 0x22, 0x21, val, interface, NULL, 0, USB_CTRL_SET_TIMEOUT); - } } + /* Otherwise the need to do non-composite mapping */ + else { + if (port->bulk_out_endpointAddress == 2) + interface = 0; + else if (port->bulk_out_endpointAddress == 4) + interface = 1; + else if (port->bulk_out_endpointAddress == 5) + interface = 2; + return usb_control_msg(serial->dev, + usb_rcvctrlpipe(serial->dev, 0), + 0x22, 0x21, val, interface, + NULL, 0, USB_CTRL_SET_TIMEOUT); + } return 0; } static void sierra_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) { - dev_dbg(&port->dev, "%s", __func__); + dev_dbg(&port->dev, "%s\n", __func__); tty_termios_copy_hw(tty->termios, old_termios); - sierra_send_setup(tty, port); + sierra_send_setup(port); } static int sierra_tiocmget(struct tty_struct *tty, struct file *file) @@ -308,7 +330,7 @@ static int sierra_tiocmget(struct tty_struct *tty, struct file *file) unsigned int value; struct sierra_port_private *portdata; - dev_dbg(&port->dev, "%s", __func__); + dev_dbg(&port->dev, "%s\n", __func__); portdata = usb_get_serial_port_data(port); value = ((portdata->rts_state) ? TIOCM_RTS : 0) | @@ -338,7 +360,18 @@ static int sierra_tiocmset(struct tty_struct *tty, struct file *file, portdata->rts_state = 0; if (clear & TIOCM_DTR) portdata->dtr_state = 0; - return sierra_send_setup(tty, port); + return sierra_send_setup(port); +} + +static void sierra_release_urb(struct urb *urb) +{ + struct usb_serial_port *port; + if (urb) { + port = urb->context; + dev_dbg(&port->dev, "%s: %p\n", __func__, urb); + kfree(urb->transfer_buffer); + usb_free_urb(urb); + } } static void sierra_outdat_callback(struct urb *urb) @@ -348,14 +381,14 @@ static void sierra_outdat_callback(struct urb *urb) int status = urb->status; unsigned long flags; - dev_dbg(&port->dev, "%s - port %d", __func__, port->number); + dev_dbg(&port->dev, "%s - port %d\n", __func__, port->number); /* free up the transfer buffer, as usb_free_urb() does not do this */ kfree(urb->transfer_buffer); if (status) dev_dbg(&port->dev, "%s - nonzero write bulk status " - "received: %d", __func__, status); + "received: %d\n", __func__, status); spin_lock_irqsave(&portdata->lock, flags); --portdata->outstanding_urbs; @@ -373,50 +406,61 @@ static int sierra_write(struct tty_struct *tty, struct usb_serial_port *port, unsigned long flags; unsigned char *buffer; struct urb *urb; - int status; + size_t writesize = min((size_t)count, (size_t)MAX_TRANSFER); + int retval = 0; + + /* verify that we actually have some data to write */ + if (count == 0) + return 0; portdata = usb_get_serial_port_data(port); - dev_dbg(&port->dev, "%s: write (%d chars)", __func__, count); + dev_dbg(&port->dev, "%s: write (%zd bytes)\n", __func__, writesize); spin_lock_irqsave(&portdata->lock, flags); + dev_dbg(&port->dev, "%s - outstanding_urbs: %d\n", __func__, + portdata->outstanding_urbs); if (portdata->outstanding_urbs > N_OUT_URB) { spin_unlock_irqrestore(&portdata->lock, flags); dev_dbg(&port->dev, "%s - write limit hit\n", __func__); return 0; } portdata->outstanding_urbs++; + dev_dbg(&port->dev, "%s - 1, outstanding_urbs: %d\n", __func__, + portdata->outstanding_urbs); spin_unlock_irqrestore(&portdata->lock, flags); - buffer = kmalloc(count, GFP_ATOMIC); + buffer = kmalloc(writesize, GFP_ATOMIC); if (!buffer) { dev_err(&port->dev, "out of memory\n"); - count = -ENOMEM; + retval = -ENOMEM; goto error_no_buffer; } urb = usb_alloc_urb(0, GFP_ATOMIC); if (!urb) { dev_err(&port->dev, "no more free urbs\n"); - count = -ENOMEM; + retval = -ENOMEM; goto error_no_urb; } - memcpy(buffer, buf, count); + memcpy(buffer, buf, writesize); - usb_serial_debug_data(debug, &port->dev, __func__, count, buffer); + usb_serial_debug_data(debug, &port->dev, __func__, writesize, buffer); usb_fill_bulk_urb(urb, serial->dev, usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress), - buffer, count, sierra_outdat_callback, port); + buffer, writesize, sierra_outdat_callback, port); + + /* Handle the need to send a zero length packet */ + urb->transfer_flags |= URB_ZERO_PACKET; /* send it down the pipe */ - status = usb_submit_urb(urb, GFP_ATOMIC); - if (status) { + retval = usb_submit_urb(urb, GFP_ATOMIC); + if (retval) { dev_err(&port->dev, "%s - usb_submit_urb(write bulk) failed " - "with status = %d\n", __func__, status); - count = status; + "with status = %d\n", __func__, retval); goto error; } @@ -424,7 +468,7 @@ static int sierra_write(struct tty_struct *tty, struct usb_serial_port *port, * really free it when it is finished with it */ usb_free_urb(urb); - return count; + return writesize; error: usb_free_urb(urb); error_no_urb: @@ -432,8 +476,10 @@ error_no_urb: error_no_buffer: spin_lock_irqsave(&portdata->lock, flags); --portdata->outstanding_urbs; + dev_dbg(&port->dev, "%s - 2. outstanding_urbs: %d\n", __func__, + portdata->outstanding_urbs); spin_unlock_irqrestore(&portdata->lock, flags); - return count; + return retval; } static void sierra_indat_callback(struct urb *urb) @@ -445,33 +491,39 @@ static void sierra_indat_callback(struct urb *urb) unsigned char *data = urb->transfer_buffer; int status = urb->status; - dbg("%s: %p", __func__, urb); - endpoint = usb_pipeendpoint(urb->pipe); - port = urb->context; + port = urb->context; + + dev_dbg(&port->dev, "%s: %p\n", __func__, urb); if (status) { dev_dbg(&port->dev, "%s: nonzero status: %d on" - " endpoint %02x.", __func__, status, endpoint); + " endpoint %02x\n", __func__, status, endpoint); } else { if (urb->actual_length) { tty = tty_port_tty_get(&port->port); + tty_buffer_request_room(tty, urb->actual_length); tty_insert_flip_string(tty, data, urb->actual_length); tty_flip_buffer_push(tty); - tty_kref_put(tty); - } else - dev_dbg(&port->dev, "%s: empty read urb" - " received", __func__); - /* Resubmit urb so we continue receiving */ - if (port->port.count && status != -ESHUTDOWN) { - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err) - dev_err(&port->dev, "resubmit read urb failed." - "(%d)\n", err); + tty_kref_put(tty); + usb_serial_debug_data(debug, &port->dev, __func__, + urb->actual_length, data); + } else { + dev_dbg(&port->dev, "%s: empty read urb" + " received\n", __func__); } } + + /* Resubmit urb so we continue receiving */ + if (port->port.count && status != -ESHUTDOWN && status != -EPERM) { + err = usb_submit_urb(urb, GFP_ATOMIC); + if (err) + dev_err(&port->dev, "resubmit read urb failed." + "(%d)\n", err); + } + return; } @@ -483,8 +535,7 @@ static void sierra_instat_callback(struct urb *urb) struct sierra_port_private *portdata = usb_get_serial_port_data(port); struct usb_serial *serial = port->serial; - dev_dbg(&port->dev, "%s", __func__); - dev_dbg(&port->dev, "%s: urb %p port %p has data %p", __func__, + dev_dbg(&port->dev, "%s: urb %p port %p has data %p\n", __func__, urb, port, portdata); if (status == 0) { @@ -504,7 +555,7 @@ static void sierra_instat_callback(struct urb *urb) sizeof(struct usb_ctrlrequest)); struct tty_struct *tty; - dev_dbg(&port->dev, "%s: signal x%x", __func__, + dev_dbg(&port->dev, "%s: signal x%x\n", __func__, signals); old_dcd_state = portdata->dcd_state; @@ -519,20 +570,20 @@ static void sierra_instat_callback(struct urb *urb) tty_hangup(tty); tty_kref_put(tty); } else { - dev_dbg(&port->dev, "%s: type %x req %x", + dev_dbg(&port->dev, "%s: type %x req %x\n", __func__, req_pkt->bRequestType, req_pkt->bRequest); } } else - dev_dbg(&port->dev, "%s: error %d", __func__, status); + dev_dbg(&port->dev, "%s: error %d\n", __func__, status); /* Resubmit urb so we continue receiving IRQ data */ - if (status != -ESHUTDOWN) { + if (port->port.count && status != -ESHUTDOWN && status != -ENOENT) { urb->dev = serial->dev; err = usb_submit_urb(urb, GFP_ATOMIC); if (err) - dev_dbg(&port->dev, "%s: resubmit intr urb " - "failed. (%d)", __func__, err); + dev_err(&port->dev, "%s: resubmit intr urb " + "failed. (%d)\n", __func__, err); } } @@ -542,7 +593,7 @@ static int sierra_write_room(struct tty_struct *tty) struct sierra_port_private *portdata = usb_get_serial_port_data(port); unsigned long flags; - dev_dbg(&port->dev, "%s - port %d", __func__, port->number); + dev_dbg(&port->dev, "%s - port %d\n", __func__, port->number); /* try to give a good number back based on if we have any free urbs at * this point in time */ @@ -557,67 +608,99 @@ static int sierra_write_room(struct tty_struct *tty) return 2048; } -static int sierra_open(struct tty_struct *tty, - struct usb_serial_port *port, struct file *filp) +static void sierra_stop_rx_urbs(struct usb_serial_port *port) { - struct sierra_port_private *portdata; - struct usb_serial *serial = port->serial; + int i; + struct sierra_port_private *portdata = usb_get_serial_port_data(port); + + for (i = 0; i < ARRAY_SIZE(portdata->in_urbs); i++) + usb_kill_urb(portdata->in_urbs[i]); + + usb_kill_urb(port->interrupt_in_urb); +} + +static int sierra_submit_rx_urbs(struct usb_serial_port *port, gfp_t mem_flags) +{ + int ok_cnt; + int err = -EINVAL; int i; struct urb *urb; - int result; + struct sierra_port_private *portdata = usb_get_serial_port_data(port); - portdata = usb_get_serial_port_data(port); - - dev_dbg(&port->dev, "%s", __func__); - - /* Set some sane defaults */ - portdata->rts_state = 1; - portdata->dtr_state = 1; - - /* Reset low level data toggle and start reading from endpoints */ - for (i = 0; i < N_IN_URB; i++) { + ok_cnt = 0; + for (i = 0; i < ARRAY_SIZE(portdata->in_urbs); i++) { urb = portdata->in_urbs[i]; if (!urb) continue; - if (urb->dev != serial->dev) { - dev_dbg(&port->dev, "%s: dev %p != %p", - __func__, urb->dev, serial->dev); - continue; - } - - /* - * make sure endpoint data toggle is synchronized with the - * device - */ - usb_clear_halt(urb->dev, urb->pipe); - - result = usb_submit_urb(urb, GFP_KERNEL); - if (result) { - dev_err(&port->dev, "submit urb %d failed (%d) %d\n", - i, result, urb->transfer_buffer_length); + err = usb_submit_urb(urb, mem_flags); + if (err) { + dev_err(&port->dev, "%s: submit urb failed: %d\n", + __func__, err); + } else { + ok_cnt++; } } - sierra_send_setup(tty, port); - - /* start up the interrupt endpoint if we have one */ - if (port->interrupt_in_urb) { - result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); - if (result) - dev_err(&port->dev, "submit irq_in urb failed %d\n", - result); + if (ok_cnt && port->interrupt_in_urb) { + err = usb_submit_urb(port->interrupt_in_urb, mem_flags); + if (err) { + dev_err(&port->dev, "%s: submit intr urb failed: %d\n", + __func__, err); + } } - return 0; + + if (ok_cnt > 0) /* at least one rx urb submitted */ + return 0; + else + return err; } -static void sierra_close(struct tty_struct *tty, - struct usb_serial_port *port, struct file *filp) +static struct urb *sierra_setup_urb(struct usb_serial *serial, int endpoint, + int dir, void *ctx, int len, + gfp_t mem_flags, + usb_complete_t callback) +{ + struct urb *urb; + u8 *buf; + + if (endpoint == -1) + return NULL; + + urb = usb_alloc_urb(0, mem_flags); + if (urb == NULL) { + dev_dbg(&serial->dev->dev, "%s: alloc for endpoint %d failed\n", + __func__, endpoint); + return NULL; + } + + buf = kmalloc(len, mem_flags); + if (buf) { + /* Fill URB using supplied data */ + usb_fill_bulk_urb(urb, serial->dev, + usb_sndbulkpipe(serial->dev, endpoint) | dir, + buf, len, callback, ctx); + + /* debug */ + dev_dbg(&serial->dev->dev, "%s %c u : %p d:%p\n", __func__, + dir == USB_DIR_IN ? 'i' : 'o', urb, buf); + } else { + dev_dbg(&serial->dev->dev, "%s %c u:%p d:%p\n", __func__, + dir == USB_DIR_IN ? 'i' : 'o', urb, buf); + + sierra_release_urb(urb); + urb = NULL; + } + + return urb; +} + +static void sierra_close(struct usb_serial_port *port) { int i; struct usb_serial *serial = port->serial; struct sierra_port_private *portdata; - dev_dbg(&port->dev, "%s", __func__); + dev_dbg(&port->dev, "%s\n", __func__); portdata = usb_get_serial_port_data(port); portdata->rts_state = 0; @@ -626,27 +709,85 @@ static void sierra_close(struct tty_struct *tty, if (serial->dev) { mutex_lock(&serial->disc_mutex); if (!serial->disconnected) - sierra_send_setup(tty, port); + sierra_send_setup(port); mutex_unlock(&serial->disc_mutex); - /* Stop reading/writing urbs */ - for (i = 0; i < N_IN_URB; i++) - usb_kill_urb(portdata->in_urbs[i]); + /* Stop reading urbs */ + sierra_stop_rx_urbs(port); + /* .. and release them */ + for (i = 0; i < N_IN_URB; i++) { + sierra_release_urb(portdata->in_urbs[i]); + portdata->in_urbs[i] = NULL; + } } +} - usb_kill_urb(port->interrupt_in_urb); - tty_port_tty_set(&port->port, NULL); +static int sierra_open(struct tty_struct *tty, + struct usb_serial_port *port, struct file *filp) +{ + struct sierra_port_private *portdata; + struct usb_serial *serial = port->serial; + int i; + int err; + int endpoint; + struct urb *urb; + + portdata = usb_get_serial_port_data(port); + + dev_dbg(&port->dev, "%s\n", __func__); + + /* Set some sane defaults */ + portdata->rts_state = 1; + portdata->dtr_state = 1; + + + endpoint = port->bulk_in_endpointAddress; + for (i = 0; i < ARRAY_SIZE(portdata->in_urbs); i++) { + urb = sierra_setup_urb(serial, endpoint, USB_DIR_IN, port, + IN_BUFLEN, GFP_KERNEL, + sierra_indat_callback); + portdata->in_urbs[i] = urb; + } + /* clear halt condition */ + usb_clear_halt(serial->dev, + usb_sndbulkpipe(serial->dev, endpoint) | USB_DIR_IN); + + err = sierra_submit_rx_urbs(port, GFP_KERNEL); + if (err) { + /* get rid of everything as in close */ + sierra_close(port); + return err; + } + sierra_send_setup(port); + + return 0; +} + + +static void sierra_dtr_rts(struct usb_serial_port *port, int on) +{ + struct usb_serial *serial = port->serial; + struct sierra_port_private *portdata; + + portdata = usb_get_serial_port_data(port); + portdata->rts_state = on; + portdata->dtr_state = on; + + if (serial->dev) { + mutex_lock(&serial->disc_mutex); + if (!serial->disconnected) + sierra_send_setup(port); + mutex_unlock(&serial->disc_mutex); + } } static int sierra_startup(struct usb_serial *serial) { struct usb_serial_port *port; struct sierra_port_private *portdata; - struct urb *urb; int i; - int j; - dev_dbg(&serial->dev->dev, "%s", __func__); + dev_dbg(&serial->dev->dev, "%s\n", __func__); /* Set Device mode to D0 */ sierra_set_power_state(serial->dev, 0x0000); @@ -661,51 +802,25 @@ static int sierra_startup(struct usb_serial *serial) portdata = kzalloc(sizeof(*portdata), GFP_KERNEL); if (!portdata) { dev_dbg(&port->dev, "%s: kmalloc for " - "sierra_port_private (%d) failed!.", + "sierra_port_private (%d) failed!.\n", __func__, i); return -ENOMEM; } spin_lock_init(&portdata->lock); - for (j = 0; j < N_IN_URB; j++) { - portdata->in_buffer[j] = kmalloc(IN_BUFLEN, GFP_KERNEL); - if (!portdata->in_buffer[j]) { - for (--j; j >= 0; j--) - kfree(portdata->in_buffer[j]); - kfree(portdata); - return -ENOMEM; - } - } - + /* Set the port private data pointer */ usb_set_serial_port_data(port, portdata); - - /* initialize the in urbs */ - for (j = 0; j < N_IN_URB; ++j) { - urb = usb_alloc_urb(0, GFP_KERNEL); - if (urb == NULL) { - dev_dbg(&port->dev, "%s: alloc for in " - "port failed.", __func__); - continue; - } - /* Fill URB using supplied data. */ - usb_fill_bulk_urb(urb, serial->dev, - usb_rcvbulkpipe(serial->dev, - port->bulk_in_endpointAddress), - portdata->in_buffer[j], IN_BUFLEN, - sierra_indat_callback, port); - portdata->in_urbs[j] = urb; - } } return 0; } -static void sierra_shutdown(struct usb_serial *serial) +static void sierra_disconnect(struct usb_serial *serial) { - int i, j; + int i; struct usb_serial_port *port; struct sierra_port_private *portdata; - dev_dbg(&serial->dev->dev, "%s", __func__); + dev_dbg(&serial->dev->dev, "%s\n", __func__); for (i = 0; i < serial->num_ports; ++i) { port = serial->port[i]; @@ -714,12 +829,6 @@ static void sierra_shutdown(struct usb_serial *serial) portdata = usb_get_serial_port_data(port); if (!portdata) continue; - - for (j = 0; j < N_IN_URB; j++) { - usb_kill_urb(portdata->in_urbs[j]); - usb_free_urb(portdata->in_urbs[j]); - kfree(portdata->in_buffer[j]); - } kfree(portdata); usb_set_serial_port_data(port, NULL); } @@ -737,13 +846,14 @@ static struct usb_serial_driver sierra_device = { .probe = sierra_probe, .open = sierra_open, .close = sierra_close, + .dtr_rts = sierra_dtr_rts, .write = sierra_write, .write_room = sierra_write_room, .set_termios = sierra_set_termios, .tiocmget = sierra_tiocmget, .tiocmset = sierra_tiocmset, .attach = sierra_startup, - .shutdown = sierra_shutdown, + .disconnect = sierra_disconnect, .read_int_callback = sierra_instat_callback, }; diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c index 5e7528cc81a8..3c249d8e8b8e 100644 --- a/drivers/usb/serial/spcp8x5.c +++ b/drivers/usb/serial/spcp8x5.c @@ -356,7 +356,7 @@ cleanup: } /* call when the device plug out. free all the memory alloced by probe */ -static void spcp8x5_shutdown(struct usb_serial *serial) +static void spcp8x5_release(struct usb_serial *serial) { int i; struct spcp8x5_private *priv; @@ -366,7 +366,6 @@ static void spcp8x5_shutdown(struct usb_serial *serial) if (priv) { free_ringbuf(priv->buf); kfree(priv); - usb_set_serial_port_data(serial->port[i] , NULL); } } } @@ -446,66 +445,47 @@ static void spcp8x5_set_workMode(struct usb_device *dev, u16 value, "RTSCTS usb_control_msg(enable flowctrl) = %d\n", ret); } -/* close the serial port. We should wait for data sending to device 1st and - * then kill all urb. */ -static void spcp8x5_close(struct tty_struct *tty, - struct usb_serial_port *port, struct file *filp) +static int spcp8x5_carrier_raised(struct usb_serial_port *port) +{ + struct spcp8x5_private *priv = usb_get_serial_port_data(port); + if (priv->line_status & MSR_STATUS_LINE_DCD) + return 1; + return 0; +} + +static void spcp8x5_dtr_rts(struct usb_serial_port *port, int on) +{ + struct spcp8x5_private *priv = usb_get_serial_port_data(port); + unsigned long flags; + u8 control; + + spin_lock_irqsave(&priv->lock, flags); + if (on) + priv->line_control = MCR_CONTROL_LINE_DTR + | MCR_CONTROL_LINE_RTS; + else + priv->line_control &= ~ (MCR_CONTROL_LINE_DTR + | MCR_CONTROL_LINE_RTS); + control = priv->line_control; + spin_unlock_irqrestore(&priv->lock, flags); + spcp8x5_set_ctrlLine(port->serial->dev, control , priv->type); +} + +/* close the serial port. We should wait for data sending to device 1st and + * then kill all urb. */ +static void spcp8x5_close(struct usb_serial_port *port) { struct spcp8x5_private *priv = usb_get_serial_port_data(port); unsigned long flags; - unsigned int c_cflag; - int bps; - long timeout; - wait_queue_t wait; int result; dbg("%s - port %d", __func__, port->number); - /* wait for data to drain from the buffer */ spin_lock_irqsave(&priv->lock, flags); - timeout = SPCP8x5_CLOSING_WAIT; - init_waitqueue_entry(&wait, current); - add_wait_queue(&tty->write_wait, &wait); - for (;;) { - set_current_state(TASK_INTERRUPTIBLE); - if (ringbuf_avail_data(priv->buf) == 0 || - timeout == 0 || signal_pending(current)) - break; - spin_unlock_irqrestore(&priv->lock, flags); - timeout = schedule_timeout(timeout); - spin_lock_irqsave(&priv->lock, flags); - } - set_current_state(TASK_RUNNING); - remove_wait_queue(&tty->write_wait, &wait); - /* clear out any remaining data in the buffer */ clear_ringbuf(priv->buf); spin_unlock_irqrestore(&priv->lock, flags); - /* wait for characters to drain from the device (this is long enough - * for the entire all byte spcp8x5 hardware buffer to drain with no - * flow control for data rates of 1200 bps or more, for lower rates we - * should really know how much data is in the buffer to compute a delay - * that is not unnecessarily long) */ - bps = tty_get_baud_rate(tty); - if (bps > 1200) - timeout = max((HZ*2560) / bps, HZ/10); - else - timeout = 2*HZ; - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(timeout); - - /* clear control lines */ - if (tty) { - c_cflag = tty->termios->c_cflag; - if (c_cflag & HUPCL) { - spin_lock_irqsave(&priv->lock, flags); - priv->line_control = 0; - spin_unlock_irqrestore(&priv->lock, flags); - spcp8x5_set_ctrlLine(port->serial->dev, 0 , priv->type); - } - } - /* kill urb */ if (port->write_urb != NULL) { result = usb_unlink_urb(port->write_urb); @@ -665,13 +645,6 @@ static int spcp8x5_open(struct tty_struct *tty, if (ret) return ret; - spin_lock_irqsave(&priv->lock, flags); - if (tty && (tty->termios->c_cflag & CBAUD)) - priv->line_control = MCR_DTR | MCR_RTS; - else - priv->line_control = 0; - spin_unlock_irqrestore(&priv->lock, flags); - spcp8x5_set_ctrlLine(serial->dev, priv->line_control , priv->type); /* Setup termios */ @@ -691,9 +664,10 @@ static int spcp8x5_open(struct tty_struct *tty, port->read_urb->dev = serial->dev; ret = usb_submit_urb(port->read_urb, GFP_KERNEL); if (ret) { - spcp8x5_close(tty, port, NULL); + spcp8x5_close(port); return -EPROTO; } + port->port.drain_delay = 256; return 0; } @@ -1033,6 +1007,8 @@ static struct usb_serial_driver spcp8x5_device = { .num_ports = 1, .open = spcp8x5_open, .close = spcp8x5_close, + .dtr_rts = spcp8x5_dtr_rts, + .carrier_raised = spcp8x5_carrier_raised, .write = spcp8x5_write, .set_termios = spcp8x5_set_termios, .ioctl = spcp8x5_ioctl, @@ -1043,7 +1019,7 @@ static struct usb_serial_driver spcp8x5_device = { .write_bulk_callback = spcp8x5_write_bulk_callback, .chars_in_buffer = spcp8x5_chars_in_buffer, .attach = spcp8x5_startup, - .shutdown = spcp8x5_shutdown, + .release = spcp8x5_release, }; static int __init spcp8x5_init(void) diff --git a/drivers/usb/serial/symbolserial.c b/drivers/usb/serial/symbolserial.c index 69879e437940..6157fac9366b 100644 --- a/drivers/usb/serial/symbolserial.c +++ b/drivers/usb/serial/symbolserial.c @@ -152,8 +152,7 @@ static int symbol_open(struct tty_struct *tty, struct usb_serial_port *port, return result; } -static void symbol_close(struct tty_struct *tty, struct usb_serial_port *port, - struct file *filp) +static void symbol_close(struct usb_serial_port *port) { struct symbol_private *priv = usb_get_serial_data(port->serial); @@ -268,7 +267,7 @@ error: return retval; } -static void symbol_shutdown(struct usb_serial *serial) +static void symbol_disconnect(struct usb_serial *serial) { struct symbol_private *priv = usb_get_serial_data(serial); @@ -276,9 +275,16 @@ static void symbol_shutdown(struct usb_serial *serial) usb_kill_urb(priv->int_urb); usb_free_urb(priv->int_urb); +} + +static void symbol_release(struct usb_serial *serial) +{ + struct symbol_private *priv = usb_get_serial_data(serial); + + dbg("%s", __func__); + kfree(priv->int_buffer); kfree(priv); - usb_set_serial_data(serial, NULL); } static struct usb_driver symbol_driver = { @@ -300,7 +306,8 @@ static struct usb_serial_driver symbol_device = { .attach = symbol_startup, .open = symbol_open, .close = symbol_close, - .shutdown = symbol_shutdown, + .disconnect = symbol_disconnect, + .release = symbol_release, .throttle = symbol_throttle, .unthrottle = symbol_unthrottle, }; diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index 0a64bac306ee..991d8232e376 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -97,11 +97,10 @@ struct ti_device { /* Function Declarations */ static int ti_startup(struct usb_serial *serial); -static void ti_shutdown(struct usb_serial *serial); +static void ti_release(struct usb_serial *serial); static int ti_open(struct tty_struct *tty, struct usb_serial_port *port, struct file *file); -static void ti_close(struct tty_struct *tty, struct usb_serial_port *port, - struct file *file); +static void ti_close(struct usb_serial_port *port); static int ti_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *data, int count); static int ti_write_room(struct tty_struct *tty); @@ -231,7 +230,7 @@ static struct usb_serial_driver ti_1port_device = { .id_table = ti_id_table_3410, .num_ports = 1, .attach = ti_startup, - .shutdown = ti_shutdown, + .release = ti_release, .open = ti_open, .close = ti_close, .write = ti_write, @@ -259,7 +258,7 @@ static struct usb_serial_driver ti_2port_device = { .id_table = ti_id_table_5052, .num_ports = 2, .attach = ti_startup, - .shutdown = ti_shutdown, + .release = ti_release, .open = ti_open, .close = ti_close, .write = ti_write, @@ -474,7 +473,7 @@ free_tdev: } -static void ti_shutdown(struct usb_serial *serial) +static void ti_release(struct usb_serial *serial) { int i; struct ti_device *tdev = usb_get_serial_data(serial); @@ -487,12 +486,10 @@ static void ti_shutdown(struct usb_serial *serial) if (tport) { ti_buf_free(tport->tp_write_buf); kfree(tport); - usb_set_serial_port_data(serial->port[i], NULL); } } kfree(tdev); - usb_set_serial_data(serial, NULL); } @@ -647,8 +644,7 @@ release_lock: } -static void ti_close(struct tty_struct *tty, struct usb_serial_port *port, - struct file *file) +static void ti_close(struct usb_serial_port *port) { struct ti_device *tdev; struct ti_port *tport; diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index f331e2bde88a..d595aa5586a7 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -141,6 +141,14 @@ static void destroy_serial(struct kref *kref) if (serial->minor != SERIAL_TTY_NO_MINOR) return_serial(serial); + serial->type->release(serial); + + for (i = 0; i < serial->num_ports; ++i) { + port = serial->port[i]; + if (port) + put_device(&port->dev); + } + /* If this is a "fake" port, we have to clean it up here, as it will * not get cleaned up in port_release() as it was never registered with * the driver core */ @@ -148,9 +156,8 @@ static void destroy_serial(struct kref *kref) for (i = serial->num_ports; i < serial->num_port_pointers; ++i) { port = serial->port[i]; - if (!port) - continue; - port_free(port); + if (port) + port_free(port); } } @@ -238,9 +245,11 @@ static int serial_open (struct tty_struct *tty, struct file *filp) goto bailout_interface_put; mutex_unlock(&serial->disc_mutex); } - mutex_unlock(&port->mutex); - return 0; + /* Now do the correct tty layer semantics */ + retval = tty_port_block_til_ready(&port->port, tty, filp); + if (retval == 0) + return 0; bailout_interface_put: usb_autopm_put_interface(serial->interface); @@ -259,64 +268,89 @@ bailout_serial_put: return retval; } -static void serial_close(struct tty_struct *tty, struct file *filp) +/** + * serial_do_down - shut down hardware + * @port: port to shut down + * + * Shut down a USB port unless it is the console. We never shut down the + * console hardware as it will always be in use. + * + * Don't free any resources at this point + */ +static void serial_do_down(struct usb_serial_port *port) { - struct usb_serial_port *port = tty->driver_data; + struct usb_serial_driver *drv = port->serial->type; struct usb_serial *serial; struct module *owner; - int count; - if (!port) + /* The console is magical, do not hang up the console hardware + or there will be tears */ + if (port->console) return; - dbg("%s - port %d", __func__, port->number); - mutex_lock(&port->mutex); serial = port->serial; owner = serial->type->driver.owner; - if (port->port.count == 0) { - mutex_unlock(&port->mutex); - return; - } + if (drv->close) + drv->close(port); - if (port->port.count == 1) - /* only call the device specific close if this - * port is being closed by the last owner. Ensure we do - * this before we drop the port count. The call is protected - * by the port mutex - */ - serial->type->close(tty, port, filp); - - if (port->port.count == (port->console ? 2 : 1)) { - struct tty_struct *tty = tty_port_tty_get(&port->port); - if (tty) { - /* We must do this before we drop the port count to - zero. */ - if (tty->driver_data) - tty->driver_data = NULL; - tty_port_tty_set(&port->port, NULL); - tty_kref_put(tty); - } - } - - --port->port.count; - count = port->port.count; mutex_unlock(&port->mutex); +} + +/** + * serial_do_free - free resources post close/hangup + * @port: port to free up + * + * Do the resource freeing and refcount dropping for the port. We must + * be careful about ordering and we must avoid freeing up the console. + */ + +static void serial_do_free(struct usb_serial_port *port) +{ + struct usb_serial *serial; + struct module *owner; + + /* The console is magical, do not hang up the console hardware + or there will be tears */ + if (port->console) + return; + + serial = port->serial; + owner = serial->type->driver.owner; put_device(&port->dev); - /* Mustn't dereference port any more */ - if (count == 0) { - mutex_lock(&serial->disc_mutex); - if (!serial->disconnected) - usb_autopm_put_interface(serial->interface); - mutex_unlock(&serial->disc_mutex); - } + mutex_lock(&serial->disc_mutex); + if (!serial->disconnected) + usb_autopm_put_interface(serial->interface); + mutex_unlock(&serial->disc_mutex); usb_serial_put(serial); - /* Mustn't dereference serial any more */ - if (count == 0) - module_put(owner); + module_put(owner); +} + +static void serial_close(struct tty_struct *tty, struct file *filp) +{ + struct usb_serial_port *port = tty->driver_data; + + dbg("%s - port %d", __func__, port->number); + + + if (tty_port_close_start(&port->port, tty, filp) == 0) + return; + + serial_do_down(port); + tty_port_close_end(&port->port, tty); + tty_port_tty_set(&port->port, NULL); + serial_do_free(port); +} + +static void serial_hangup(struct tty_struct *tty) +{ + struct usb_serial_port *port = tty->driver_data; + serial_do_down(port); + tty_port_hangup(&port->port); + serial_do_free(port); } static int serial_write(struct tty_struct *tty, const unsigned char *buf, @@ -648,6 +682,29 @@ static struct usb_serial_driver *search_serial_device( return NULL; } +static int serial_carrier_raised(struct tty_port *port) +{ + struct usb_serial_port *p = container_of(port, struct usb_serial_port, port); + struct usb_serial_driver *drv = p->serial->type; + if (drv->carrier_raised) + return drv->carrier_raised(p); + /* No carrier control - don't block */ + return 1; +} + +static void serial_dtr_rts(struct tty_port *port, int on) +{ + struct usb_serial_port *p = container_of(port, struct usb_serial_port, port); + struct usb_serial_driver *drv = p->serial->type; + if (drv->dtr_rts) + drv->dtr_rts(p, on); +} + +static const struct tty_port_operations serial_port_ops = { + .carrier_raised = serial_carrier_raised, + .dtr_rts = serial_dtr_rts, +}; + int usb_serial_probe(struct usb_interface *interface, const struct usb_device_id *id) { @@ -841,6 +898,7 @@ int usb_serial_probe(struct usb_interface *interface, if (!port) goto probe_error; tty_port_init(&port->port); + port->port.ops = &serial_port_ops; port->serial = serial; spin_lock_init(&port->lock); mutex_init(&port->mutex); @@ -995,10 +1053,15 @@ int usb_serial_probe(struct usb_interface *interface, dev_set_name(&port->dev, "ttyUSB%d", port->number); dbg ("%s - registering %s", __func__, dev_name(&port->dev)); + port->dev_state = PORT_REGISTERING; retval = device_register(&port->dev); - if (retval) + if (retval) { dev_err(&port->dev, "Error registering port device, " "continuing\n"); + port->dev_state = PORT_UNREGISTERED; + } else { + port->dev_state = PORT_REGISTERED; + } } usb_serial_console_init(debug, minor); @@ -1062,31 +1125,38 @@ void usb_serial_disconnect(struct usb_interface *interface) serial->disconnected = 1; mutex_unlock(&serial->disc_mutex); - /* Unfortunately, many of the sub-drivers expect the port structures - * to exist when their shutdown method is called, so we have to go - * through this awkward two-step unregistration procedure. - */ for (i = 0; i < serial->num_ports; ++i) { port = serial->port[i]; if (port) { struct tty_struct *tty = tty_port_tty_get(&port->port); if (tty) { + /* The hangup will occur asynchronously but + the object refcounts will sort out all the + cleanup */ tty_hangup(tty); tty_kref_put(tty); } kill_traffic(port); cancel_work_sync(&port->work); - device_del(&port->dev); - } - } - serial->type->shutdown(serial); - for (i = 0; i < serial->num_ports; ++i) { - port = serial->port[i]; - if (port) { - put_device(&port->dev); - serial->port[i] = NULL; + if (port->dev_state == PORT_REGISTERED) { + + /* Make sure the port is bound so that the + * driver's port_remove method is called. + */ + if (!port->dev.driver) { + int rc; + + port->dev.driver = + &serial->type->driver; + rc = device_bind_driver(&port->dev); + } + port->dev_state = PORT_UNREGISTERING; + device_del(&port->dev); + port->dev_state = PORT_UNREGISTERED; + } } } + serial->type->disconnect(serial); /* let the last holder of this object * cause it to be cleaned up */ @@ -1135,6 +1205,7 @@ static const struct tty_operations serial_ops = { .open = serial_open, .close = serial_close, .write = serial_write, + .hangup = serial_hangup, .write_room = serial_write_room, .ioctl = serial_ioctl, .set_termios = serial_set_termios, @@ -1147,6 +1218,7 @@ static const struct tty_operations serial_ops = { .proc_fops = &serial_proc_fops, }; + struct tty_driver *usb_serial_tty_driver; static int __init usb_serial_init(void) @@ -1262,7 +1334,8 @@ static void fixup_generic(struct usb_serial_driver *device) set_to_generic_if_null(device, chars_in_buffer); set_to_generic_if_null(device, read_bulk_callback); set_to_generic_if_null(device, write_bulk_callback); - set_to_generic_if_null(device, shutdown); + set_to_generic_if_null(device, disconnect); + set_to_generic_if_null(device, release); } int usb_serial_register(struct usb_serial_driver *driver) diff --git a/drivers/usb/serial/usb_debug.c b/drivers/usb/serial/usb_debug.c index 6c9cbb59552a..614800972dc3 100644 --- a/drivers/usb/serial/usb_debug.c +++ b/drivers/usb/serial/usb_debug.c @@ -15,7 +15,19 @@ #include #include +#define URB_DEBUG_MAX_IN_FLIGHT_URBS 4000 #define USB_DEBUG_MAX_PACKET_SIZE 8 +#define USB_DEBUG_BRK_SIZE 8 +static char USB_DEBUG_BRK[USB_DEBUG_BRK_SIZE] = { + 0x00, + 0xff, + 0x01, + 0xfe, + 0x00, + 0xfe, + 0x01, + 0xff, +}; static struct usb_device_id id_table [] = { { USB_DEVICE(0x0525, 0x127a) }, @@ -38,6 +50,32 @@ static int usb_debug_open(struct tty_struct *tty, struct usb_serial_port *port, return usb_serial_generic_open(tty, port, filp); } +/* This HW really does not support a serial break, so one will be + * emulated when ever the break state is set to true. + */ +static void usb_debug_break_ctl(struct tty_struct *tty, int break_state) +{ + struct usb_serial_port *port = tty->driver_data; + if (!break_state) + return; + usb_serial_generic_write(tty, port, USB_DEBUG_BRK, USB_DEBUG_BRK_SIZE); +} + +static void usb_debug_read_bulk_callback(struct urb *urb) +{ + struct usb_serial_port *port = urb->context; + + if (urb->actual_length == USB_DEBUG_BRK_SIZE && + memcmp(urb->transfer_buffer, USB_DEBUG_BRK, + USB_DEBUG_BRK_SIZE) == 0) { + usb_serial_handle_break(port); + usb_serial_generic_resubmit_read_urb(port, GFP_ATOMIC); + return; + } + + usb_serial_generic_read_bulk_callback(urb); +} + static struct usb_serial_driver debug_device = { .driver = { .owner = THIS_MODULE, @@ -46,6 +84,9 @@ static struct usb_serial_driver debug_device = { .id_table = id_table, .num_ports = 1, .open = usb_debug_open, + .max_in_flight_urbs = URB_DEBUG_MAX_IN_FLIGHT_URBS, + .break_ctl = usb_debug_break_ctl, + .read_bulk_callback = usb_debug_read_bulk_callback, }; static int __init debug_init(void) diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index 5ac414bda718..f5d0f64dcc52 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -38,8 +38,7 @@ /* function prototypes for a handspring visor */ static int visor_open(struct tty_struct *tty, struct usb_serial_port *port, struct file *filp); -static void visor_close(struct tty_struct *tty, struct usb_serial_port *port, - struct file *filp); +static void visor_close(struct usb_serial_port *port); static int visor_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count); static int visor_write_room(struct tty_struct *tty); @@ -48,7 +47,7 @@ static void visor_unthrottle(struct tty_struct *tty); static int visor_probe(struct usb_serial *serial, const struct usb_device_id *id); static int visor_calc_num_ports(struct usb_serial *serial); -static void visor_shutdown(struct usb_serial *serial); +static void visor_release(struct usb_serial *serial); static void visor_write_bulk_callback(struct urb *urb); static void visor_read_bulk_callback(struct urb *urb); static void visor_read_int_callback(struct urb *urb); @@ -203,7 +202,7 @@ static struct usb_serial_driver handspring_device = { .attach = treo_attach, .probe = visor_probe, .calc_num_ports = visor_calc_num_ports, - .shutdown = visor_shutdown, + .release = visor_release, .write = visor_write, .write_room = visor_write_room, .write_bulk_callback = visor_write_bulk_callback, @@ -228,7 +227,7 @@ static struct usb_serial_driver clie_5_device = { .attach = clie_5_attach, .probe = visor_probe, .calc_num_ports = visor_calc_num_ports, - .shutdown = visor_shutdown, + .release = visor_release, .write = visor_write, .write_room = visor_write_room, .write_bulk_callback = visor_write_bulk_callback, @@ -324,8 +323,7 @@ exit: } -static void visor_close(struct tty_struct *tty, - struct usb_serial_port *port, struct file *filp) +static void visor_close(struct usb_serial_port *port) { struct visor_private *priv = usb_get_serial_port_data(port); unsigned char *transfer_buffer; @@ -920,7 +918,7 @@ static int clie_5_attach(struct usb_serial *serial) return generic_startup(serial); } -static void visor_shutdown(struct usb_serial *serial) +static void visor_release(struct usb_serial *serial) { struct visor_private *priv; int i; @@ -929,10 +927,7 @@ static void visor_shutdown(struct usb_serial *serial) for (i = 0; i < serial->num_ports; i++) { priv = usb_get_serial_port_data(serial->port[i]); - if (priv) { - usb_set_serial_port_data(serial->port[i], NULL); - kfree(priv); - } + kfree(priv); } } diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index 5335d3211c07..8d126dd7a02e 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -144,11 +144,10 @@ static int whiteheat_firmware_attach(struct usb_serial *serial); /* function prototypes for the Connect Tech WhiteHEAT serial converter */ static int whiteheat_attach(struct usb_serial *serial); -static void whiteheat_shutdown(struct usb_serial *serial); +static void whiteheat_release(struct usb_serial *serial); static int whiteheat_open(struct tty_struct *tty, struct usb_serial_port *port, struct file *filp); -static void whiteheat_close(struct tty_struct *tty, - struct usb_serial_port *port, struct file *filp); +static void whiteheat_close(struct usb_serial_port *port); static int whiteheat_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count); @@ -190,7 +189,7 @@ static struct usb_serial_driver whiteheat_device = { .id_table = id_table_std, .num_ports = 4, .attach = whiteheat_attach, - .shutdown = whiteheat_shutdown, + .release = whiteheat_release, .open = whiteheat_open, .close = whiteheat_close, .write = whiteheat_write, @@ -618,7 +617,7 @@ no_command_buffer: } -static void whiteheat_shutdown(struct usb_serial *serial) +static void whiteheat_release(struct usb_serial *serial) { struct usb_serial_port *command_port; struct usb_serial_port *port; @@ -712,8 +711,7 @@ exit: } -static void whiteheat_close(struct tty_struct *tty, - struct usb_serial_port *port, struct file *filp) +static void whiteheat_close(struct usb_serial_port *port) { struct whiteheat_private *info = usb_get_serial_port_data(port); struct whiteheat_urb_wrap *wrap; @@ -723,31 +721,7 @@ static void whiteheat_close(struct tty_struct *tty, dbg("%s - port %d", __func__, port->number); - mutex_lock(&port->serial->disc_mutex); - /* filp is NULL when called from usb_serial_disconnect */ - if ((filp && (tty_hung_up_p(filp))) || port->serial->disconnected) { - mutex_unlock(&port->serial->disc_mutex); - return; - } - mutex_unlock(&port->serial->disc_mutex); - - tty->closing = 1; - -/* - * Not currently in use; tty_wait_until_sent() calls - * serial_chars_in_buffer() which deadlocks on the second semaphore - * acquisition. This should be fixed at some point. Greg's been - * notified. - if ((filp->f_flags & (O_NDELAY | O_NONBLOCK)) == 0) { - tty_wait_until_sent(tty, CLOSING_DELAY); - } -*/ - - tty_driver_flush_buffer(tty); - tty_ldisc_flush(tty); - firm_report_tx_done(port); - firm_close(port); /* shutdown our bulk reads and writes */ @@ -775,10 +749,7 @@ static void whiteheat_close(struct tty_struct *tty, } spin_unlock_irq(&info->lock); mutex_unlock(&info->deathwarrant); - stop_command_port(port->serial); - - tty->closing = 0; } diff --git a/drivers/usb/storage/initializers.c b/drivers/usb/storage/initializers.c index 2dd9bd4bff56..ec17c96371af 100644 --- a/drivers/usb/storage/initializers.c +++ b/drivers/usb/storage/initializers.c @@ -52,7 +52,7 @@ int usb_stor_euscsi_init(struct us_data *us) us->iobuf[0] = 0x1; result = usb_stor_control_msg(us, us->send_ctrl_pipe, 0x0C, USB_RECIP_INTERFACE | USB_TYPE_VENDOR, - 0x01, 0x0, us->iobuf, 0x1, 5*HZ); + 0x01, 0x0, us->iobuf, 0x1, 5000); US_DEBUGP("-- result is %d\n", result); return 0; @@ -80,14 +80,16 @@ int usb_stor_ucr61s2b_init(struct us_data *us) res = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, bcb, US_BULK_CB_WRAP_LEN, &partial); - if(res) - return res; + if (res) + return -EIO; US_DEBUGP("Getting status packet...\n"); res = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs, US_BULK_CS_WRAP_LEN, &partial); + if (res) + return -EIO; - return (res ? -1 : 0); + return 0; } /* This places the HUAWEI E220 devices in multi-port mode */ @@ -99,6 +101,6 @@ int usb_stor_huawei_e220_init(struct us_data *us) USB_REQ_SET_FEATURE, USB_TYPE_STANDARD | USB_RECIP_DEVICE, 0x01, 0x0, NULL, 0x0, 1000); - US_DEBUGP("usb_control_msg performing result is %d\n", result); - return (result ? 0 : -1); + US_DEBUGP("Huawei mode set result is %d\n", result); + return (result ? 0 : -ENODEV); } diff --git a/drivers/usb/storage/option_ms.c b/drivers/usb/storage/option_ms.c index 353f922939a4..d41cc0a970f7 100644 --- a/drivers/usb/storage/option_ms.c +++ b/drivers/usb/storage/option_ms.c @@ -37,7 +37,7 @@ MODULE_PARM_DESC(option_zero_cd, "ZeroCD mode (1=Force Modem (default)," #define RESPONSE_LEN 1024 -static int option_rezero(struct us_data *us, int ep_in, int ep_out) +static int option_rezero(struct us_data *us) { const unsigned char rezero_msg[] = { 0x55, 0x53, 0x42, 0x43, 0x78, 0x56, 0x34, 0x12, @@ -54,10 +54,10 @@ static int option_rezero(struct us_data *us, int ep_in, int ep_out) if (buffer == NULL) return USB_STOR_TRANSPORT_ERROR; - memcpy(buffer, rezero_msg, sizeof (rezero_msg)); + memcpy(buffer, rezero_msg, sizeof(rezero_msg)); result = usb_stor_bulk_transfer_buf(us, - usb_sndbulkpipe(us->pusb_dev, ep_out), - buffer, sizeof (rezero_msg), NULL); + us->send_bulk_pipe, + buffer, sizeof(rezero_msg), NULL); if (result != USB_STOR_XFER_GOOD) { result = USB_STOR_XFER_ERROR; goto out; @@ -66,9 +66,15 @@ static int option_rezero(struct us_data *us, int ep_in, int ep_out) /* Some of the devices need to be asked for a response, but we don't * care what that response is. */ - result = usb_stor_bulk_transfer_buf(us, - usb_sndbulkpipe(us->pusb_dev, ep_out), + usb_stor_bulk_transfer_buf(us, + us->recv_bulk_pipe, buffer, RESPONSE_LEN, NULL); + + /* Read the CSW */ + usb_stor_bulk_transfer_buf(us, + us->recv_bulk_pipe, + buffer, 13, NULL); + result = USB_STOR_XFER_GOOD; out: @@ -76,63 +82,75 @@ out: return result; } +static int option_inquiry(struct us_data *us) +{ + const unsigned char inquiry_msg[] = { + 0x55, 0x53, 0x42, 0x43, 0x12, 0x34, 0x56, 0x78, + 0x24, 0x00, 0x00, 0x00, 0x80, 0x00, 0x06, 0x12, + 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + char *buffer; + int result; + + US_DEBUGP("Option MS: %s", "device inquiry for vendor name\n"); + + buffer = kzalloc(0x24, GFP_KERNEL); + if (buffer == NULL) + return USB_STOR_TRANSPORT_ERROR; + + memcpy(buffer, inquiry_msg, sizeof(inquiry_msg)); + result = usb_stor_bulk_transfer_buf(us, + us->send_bulk_pipe, + buffer, sizeof(inquiry_msg), NULL); + if (result != USB_STOR_XFER_GOOD) { + result = USB_STOR_XFER_ERROR; + goto out; + } + + result = usb_stor_bulk_transfer_buf(us, + us->recv_bulk_pipe, + buffer, 0x24, NULL); + if (result != USB_STOR_XFER_GOOD) { + result = USB_STOR_XFER_ERROR; + goto out; + } + + result = memcmp(buffer+8, "Option", 6); + + /* Read the CSW */ + usb_stor_bulk_transfer_buf(us, + us->recv_bulk_pipe, + buffer, 13, NULL); + +out: + kfree(buffer); + return result; +} + + int option_ms_init(struct us_data *us) { - struct usb_device *udev; - struct usb_interface *intf; - struct usb_host_interface *iface_desc; - struct usb_endpoint_descriptor *endpoint = NULL; - u8 ep_in = 0, ep_out = 0; - int ep_in_size = 0, ep_out_size = 0; - int i, result; - - udev = us->pusb_dev; - intf = us->pusb_intf; - - /* Ensure it's really a ZeroCD device; devices that are already - * in modem mode return 0xFF for class, subclass, and protocol. - */ - if (udev->descriptor.bDeviceClass != 0 || - udev->descriptor.bDeviceSubClass != 0 || - udev->descriptor.bDeviceProtocol != 0) - return USB_STOR_TRANSPORT_GOOD; + int result; US_DEBUGP("Option MS: option_ms_init called\n"); - /* Find the right mass storage interface */ - iface_desc = intf->cur_altsetting; - if (iface_desc->desc.bInterfaceClass != 0x8 || - iface_desc->desc.bInterfaceSubClass != 0x6 || - iface_desc->desc.bInterfaceProtocol != 0x50) { - US_DEBUGP("Option MS: mass storage interface not found, no action " - "required\n"); - return USB_STOR_TRANSPORT_GOOD; - } - - /* Find the mass storage bulk endpoints */ - for (i = 0; i < iface_desc->desc.bNumEndpoints && (!ep_in_size || !ep_out_size); ++i) { - endpoint = &iface_desc->endpoint[i].desc; - - if (usb_endpoint_is_bulk_in(endpoint)) { - ep_in = usb_endpoint_num(endpoint); - ep_in_size = le16_to_cpu(endpoint->wMaxPacketSize); - } else if (usb_endpoint_is_bulk_out(endpoint)) { - ep_out = usb_endpoint_num(endpoint); - ep_out_size = le16_to_cpu(endpoint->wMaxPacketSize); - } - } - - /* Can't find the mass storage endpoints */ - if (!ep_in_size || !ep_out_size) { - US_DEBUGP("Option MS: mass storage endpoints not found, no action " - "required\n"); - return USB_STOR_TRANSPORT_GOOD; - } + /* Additional test for vendor information via INQUIRY, + * because some vendor/product IDs are ambiguous + */ + result = option_inquiry(us); + if (result != 0) { + US_DEBUGP("Option MS: vendor is not Option or not determinable," + " no action taken\n"); + return 0; + } else + US_DEBUGP("Option MS: this is a genuine Option device," + " proceeding\n"); /* Force Modem mode */ if (option_zero_cd == ZCD_FORCE_MODEM) { US_DEBUGP("Option MS: %s", "Forcing Modem Mode\n"); - result = option_rezero(us, ep_in, ep_out); + result = option_rezero(us); if (result != USB_STOR_XFER_GOOD) US_DEBUGP("Option MS: Failed to switch to modem mode.\n"); return -EIO; @@ -142,6 +160,6 @@ int option_ms_init(struct us_data *us) " requests it\n"); } - return USB_STOR_TRANSPORT_GOOD; + return 0; } diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index 4ca3b5860643..cfa26d56ce60 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c @@ -132,7 +132,7 @@ static int slave_configure(struct scsi_device *sdev) if (us->fflags & US_FL_MAX_SECTORS_MIN) max_sectors = PAGE_CACHE_SIZE >> 9; - if (sdev->request_queue->max_sectors > max_sectors) + if (queue_max_sectors(sdev->request_queue) > max_sectors) blk_queue_max_sectors(sdev->request_queue, max_sectors); } else if (sdev->type == TYPE_TAPE) { @@ -483,7 +483,7 @@ static ssize_t show_max_sectors(struct device *dev, struct device_attribute *att { struct scsi_device *sdev = to_scsi_device(dev); - return sprintf(buf, "%u\n", sdev->request_queue->max_sectors); + return sprintf(buf, "%u\n", queue_max_sectors(sdev->request_queue)); } /* Input routine for the sysfs max_sectors file */ diff --git a/drivers/usb/storage/sierra_ms.c b/drivers/usb/storage/sierra_ms.c index 4359a2cb42df..4395c4100ec2 100644 --- a/drivers/usb/storage/sierra_ms.c +++ b/drivers/usb/storage/sierra_ms.c @@ -202,6 +202,6 @@ int sierra_ms_init(struct us_data *us) complete: result = device_create_file(&us->pusb_intf->dev, &dev_attr_truinst); - return USB_STOR_TRANSPORT_GOOD; + return 0; } diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 4b8b69045fe6..1b9c5dd0fb27 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -1385,7 +1385,7 @@ UNUSUAL_DEV( 0x10d6, 0x2200, 0x0100, 0x0100, UNUSUAL_DEV( 0x1186, 0x3e04, 0x0000, 0x0000, "D-Link", "USB Mass Storage", - US_SC_DEVICE, US_PR_DEVICE, option_ms_init, 0), + US_SC_DEVICE, US_PR_DEVICE, option_ms_init, US_FL_IGNORE_DEVICE), /* Reported by Kevin Lloyd * Entry is needed for the initializer function override, diff --git a/drivers/uwb/hwa-rc.c b/drivers/uwb/hwa-rc.c index 559f8784acf3..9052bcb4f528 100644 --- a/drivers/uwb/hwa-rc.c +++ b/drivers/uwb/hwa-rc.c @@ -501,7 +501,7 @@ int hwarc_filter_event_WUSB_0100(struct uwb_rc *rc, struct uwb_rceb **header, int result = -ENOANO; struct uwb_rceb *rceb = *header; int event = le16_to_cpu(rceb->wEvent); - size_t event_size; + ssize_t event_size; size_t core_size, offset; if (rceb->bEventType != UWB_RC_CET_GENERAL) diff --git a/drivers/uwb/wlp/txrx.c b/drivers/uwb/wlp/txrx.c index cd2035768b47..86a853b84119 100644 --- a/drivers/uwb/wlp/txrx.c +++ b/drivers/uwb/wlp/txrx.c @@ -326,7 +326,7 @@ int wlp_prepare_tx_frame(struct device *dev, struct wlp *wlp, int result = -EINVAL; struct ethhdr *eth_hdr = (void *) skb->data; - if (is_broadcast_ether_addr(eth_hdr->h_dest)) { + if (is_multicast_ether_addr(eth_hdr->h_dest)) { result = wlp_eda_for_each(&wlp->eda, wlp_wss_send_copy, skb); if (result < 0) { if (printk_ratelimit()) diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 0048f1185a60..d6d65ef85f54 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -397,7 +397,7 @@ config FB_SA1100 config FB_IMX tristate "Motorola i.MX LCD support" - depends on FB && (ARCH_IMX || ARCH_MX2) + depends on FB && (ARCH_MX1 || ARCH_MX2) select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT @@ -1122,12 +1122,14 @@ config FB_INTEL select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_BOOT_VESA_SUPPORT + select FB_BOOT_VESA_SUPPORT if FB_INTEL = y help This driver supports the on-board graphics built in to the Intel 830M/845G/852GM/855GM/865G/915G/915GM/945G/945GM/965G/965GM chipsets. Say Y if you have and plan to use such a board. + To make FB_INTELFB=Y work you need to say AGP_INTEL=y too. + To compile this driver as a module, choose M here: the module will be called intelfb. @@ -1460,7 +1462,7 @@ config FB_SIS select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_BOOT_VESA_SUPPORT + select FB_BOOT_VESA_SUPPORT if FB_SIS = y help This is the frame buffer device driver for the SiS 300, 315, 330 and 340 series as well as XGI V3XT, V5, V8, Z7 graphics chipsets. @@ -1759,6 +1761,16 @@ config FB_68328 Say Y here if you want to support the built-in frame buffer of the Motorola 68328 CPU family. +config FB_PXA168 + tristate "PXA168/910 LCD framebuffer support" + depends on FB && (CPU_PXA168 || CPU_PXA910) + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + ---help--- + Frame buffer driver for the built-in LCD controller in the Marvell + MMP processor. + config FB_PXA tristate "PXA LCD framebuffer support" depends on FB && ARCH_PXA @@ -1996,7 +2008,7 @@ config FB_PS3_DEFAULT_SIZE_M config FB_XILINX tristate "Xilinx frame buffer support" - depends on FB && XILINX_VIRTEX + depends on FB && (XILINX_VIRTEX || MICROBLAZE) select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT @@ -2094,6 +2106,7 @@ config FB_MB862XX_LIME bool "Lime GDC" depends on FB_MB862XX depends on OF && !FB_MB862XX_PCI_GDC + depends on PPC select FB_FOREIGN_ENDIAN select FB_LITTLE_ENDIAN ---help--- diff --git a/drivers/video/Makefile b/drivers/video/Makefile index d8d0be5151e3..01a819f47371 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -97,6 +97,7 @@ obj-$(CONFIG_FB_GBE) += gbefb.o obj-$(CONFIG_FB_CIRRUS) += cirrusfb.o obj-$(CONFIG_FB_ASILIANT) += asiliantfb.o obj-$(CONFIG_FB_PXA) += pxafb.o +obj-$(CONFIG_FB_PXA168) += pxa168fb.o obj-$(CONFIG_FB_W100) += w100fb.o obj-$(CONFIG_FB_TMIO) += tmiofb.o obj-$(CONFIG_FB_AU1100) += au1100fb.o diff --git a/drivers/video/acornfb.c b/drivers/video/acornfb.c index 6995fe1e86d4..0bcc59eb37fa 100644 --- a/drivers/video/acornfb.c +++ b/drivers/video/acornfb.c @@ -859,43 +859,6 @@ acornfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) return 0; } -/* - * Note that we are entered with the kernel locked. - */ -static int -acornfb_mmap(struct fb_info *info, struct vm_area_struct *vma) -{ - unsigned long off, start; - u32 len; - - off = vma->vm_pgoff << PAGE_SHIFT; - - start = info->fix.smem_start; - len = PAGE_ALIGN(start & ~PAGE_MASK) + info->fix.smem_len; - start &= PAGE_MASK; - if ((vma->vm_end - vma->vm_start + off) > len) - return -EINVAL; - off += start; - vma->vm_pgoff = off >> PAGE_SHIFT; - - /* This is an IO map - tell maydump to skip this VMA */ - vma->vm_flags |= VM_IO; - - vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); - - /* - * Don't alter the page protection flags; we want to keep the area - * cached for better performance. This does mean that we may miss - * some updates to the screen occasionally, but process switches - * should cause the caches and buffers to be flushed often enough. - */ - if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, - vma->vm_end - vma->vm_start, - vma->vm_page_prot)) - return -EAGAIN; - return 0; -} - static struct fb_ops acornfb_ops = { .owner = THIS_MODULE, .fb_check_var = acornfb_check_var, @@ -905,7 +868,6 @@ static struct fb_ops acornfb_ops = { .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, - .fb_mmap = acornfb_mmap, }; /* diff --git a/drivers/video/amba-clcd.c b/drivers/video/amba-clcd.c index d1f80bac54f0..fb8163d181ab 100644 --- a/drivers/video/amba-clcd.c +++ b/drivers/video/amba-clcd.c @@ -351,7 +351,7 @@ static int clcdfb_register(struct clcd_fb *fb) } fb->fb.fix.mmio_start = fb->dev->res.start; - fb->fb.fix.mmio_len = 4096; + fb->fb.fix.mmio_len = resource_size(&fb->dev->res); fb->regs = ioremap(fb->fb.fix.mmio_start, fb->fb.fix.mmio_len); if (!fb->regs) { diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c index 2fb63f6ea2f1..5afd64482f55 100644 --- a/drivers/video/atmel_lcdfb.c +++ b/drivers/video/atmel_lcdfb.c @@ -345,7 +345,7 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var, dev_dbg(dev, " bpp: %u\n", var->bits_per_pixel); dev_dbg(dev, " clk: %lu KHz\n", clk_value_khz); - if ((PICOS2KHZ(var->pixclock) * var->bits_per_pixel / 8) > clk_value_khz) { + if (PICOS2KHZ(var->pixclock) > clk_value_khz) { dev_err(dev, "%lu KHz pixel clock is too fast\n", PICOS2KHZ(var->pixclock)); return -EINVAL; } diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c index 35e8eb02b9e9..e4e4d433b007 100644 --- a/drivers/video/aty/aty128fb.c +++ b/drivers/video/aty/aty128fb.c @@ -354,7 +354,7 @@ static int default_crt_on __devinitdata = 0; static int default_lcd_on __devinitdata = 1; #ifdef CONFIG_MTRR -static int mtrr = 1; +static bool mtrr = true; #endif #ifdef CONFIG_PMAC_BACKLIGHT diff --git a/drivers/video/aty/radeon_pm.c b/drivers/video/aty/radeon_pm.c index 97a1f095f327..515cf1978d19 100644 --- a/drivers/video/aty/radeon_pm.c +++ b/drivers/video/aty/radeon_pm.c @@ -213,7 +213,6 @@ static void radeon_pm_disable_dynamic_mode(struct radeonfb_info *rinfo) PIXCLKS_CNTL__R300_PIXCLK_TRANS_ALWAYS_ONb | PIXCLKS_CNTL__R300_PIXCLK_TVO_ALWAYS_ONb | PIXCLKS_CNTL__R300_P2G2CLK_ALWAYS_ONb | - PIXCLKS_CNTL__R300_P2G2CLK_ALWAYS_ONb | PIXCLKS_CNTL__R300_DISP_DAC_PIXCLK_DAC2_BLANK_OFF); OUTPLL(pllPIXCLKS_CNTL, tmp); @@ -395,7 +394,7 @@ static void radeon_pm_enable_dynamic_mode(struct radeonfb_info *rinfo) PIXCLKS_CNTL__R300_PIXCLK_TRANS_ALWAYS_ONb | PIXCLKS_CNTL__R300_PIXCLK_TVO_ALWAYS_ONb | PIXCLKS_CNTL__R300_P2G2CLK_ALWAYS_ONb | - PIXCLKS_CNTL__R300_P2G2CLK_ALWAYS_ONb); + PIXCLKS_CNTL__R300_P2G2CLK_DAC_ALWAYS_ONb); OUTPLL(pllPIXCLKS_CNTL, tmp); tmp = INPLL(pllMCLK_MISC); diff --git a/drivers/video/bf54x-lq043fb.c b/drivers/video/bf54x-lq043fb.c index 37e60b1d2ed9..e49ae5edcc00 100644 --- a/drivers/video/bf54x-lq043fb.c +++ b/drivers/video/bf54x-lq043fb.c @@ -323,7 +323,6 @@ static int bfin_bf54x_fb_release(struct fb_info *info, int user) bfin_write_EPPI0_CONTROL(0); SSYNC(); disable_dma(CH_EPPI0); - memset(fbi->fb_buffer, 0, info->fix.smem_len); } spin_unlock(&fbi->lock); @@ -530,7 +529,7 @@ static irqreturn_t bfin_bf54x_irq_error(int irq, void *dev_id) return IRQ_HANDLED; } -static int __init bfin_bf54x_probe(struct platform_device *pdev) +static int __devinit bfin_bf54x_probe(struct platform_device *pdev) { struct bfin_bf54xfb_info *info; struct fb_info *fbinfo; @@ -626,14 +625,12 @@ static int __init bfin_bf54x_probe(struct platform_device *pdev) goto out3; } - memset(info->fb_buffer, 0, fbinfo->fix.smem_len); - fbinfo->screen_base = (void *)info->fb_buffer; fbinfo->fix.smem_start = (int)info->fb_buffer; fbinfo->fbops = &bfin_bf54x_fb_ops; - fbinfo->pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL); + fbinfo->pseudo_palette = kzalloc(sizeof(u32) * 16, GFP_KERNEL); if (!fbinfo->pseudo_palette) { printk(KERN_ERR DRIVER_NAME "Fail to allocate pseudo_palette\n"); @@ -642,8 +639,6 @@ static int __init bfin_bf54x_probe(struct platform_device *pdev) goto out4; } - memset(fbinfo->pseudo_palette, 0, sizeof(u32) * 16); - if (fb_alloc_cmap(&fbinfo->cmap, BFIN_LCD_NBR_PALETTE_ENTRIES, 0) < 0) { printk(KERN_ERR DRIVER_NAME @@ -712,7 +707,7 @@ out1: return ret; } -static int bfin_bf54x_remove(struct platform_device *pdev) +static int __devexit bfin_bf54x_remove(struct platform_device *pdev) { struct fb_info *fbinfo = platform_get_drvdata(pdev); @@ -781,7 +776,7 @@ static int bfin_bf54x_resume(struct platform_device *pdev) static struct platform_driver bfin_bf54x_driver = { .probe = bfin_bf54x_probe, - .remove = bfin_bf54x_remove, + .remove = __devexit_p(bfin_bf54x_remove), .suspend = bfin_bf54x_suspend, .resume = bfin_bf54x_resume, .driver = { @@ -790,7 +785,7 @@ static struct platform_driver bfin_bf54x_driver = { }, }; -static int __devinit bfin_bf54x_driver_init(void) +static int __init bfin_bf54x_driver_init(void) { return platform_driver_register(&bfin_bf54x_driver); } diff --git a/drivers/video/bfin-t350mcqb-fb.c b/drivers/video/bfin-t350mcqb-fb.c index 90cfddabf1f7..5cc36cfbf07b 100644 --- a/drivers/video/bfin-t350mcqb-fb.c +++ b/drivers/video/bfin-t350mcqb-fb.c @@ -242,7 +242,6 @@ static int bfin_t350mcqb_fb_release(struct fb_info *info, int user) SSYNC(); disable_dma(CH_PPI); bfin_t350mcqb_stop_timers(); - memset(fbi->fb_buffer, 0, info->fix.smem_len); } spin_unlock(&fbi->lock); @@ -527,8 +526,6 @@ static int __devinit bfin_t350mcqb_probe(struct platform_device *pdev) goto out3; } - memset(info->fb_buffer, 0, fbinfo->fix.smem_len); - fbinfo->screen_base = (void *)info->fb_buffer + ACTIVE_VIDEO_MEM_OFFSET; fbinfo->fix.smem_start = (int)info->fb_buffer + ACTIVE_VIDEO_MEM_OFFSET; @@ -602,7 +599,7 @@ out1: return ret; } -static int bfin_t350mcqb_remove(struct platform_device *pdev) +static int __devexit bfin_t350mcqb_remove(struct platform_device *pdev) { struct fb_info *fbinfo = platform_get_drvdata(pdev); @@ -637,9 +634,6 @@ static int bfin_t350mcqb_remove(struct platform_device *pdev) #ifdef CONFIG_PM static int bfin_t350mcqb_suspend(struct platform_device *pdev, pm_message_t state) { - struct fb_info *fbinfo = platform_get_drvdata(pdev); - struct bfin_t350mcqbfb_info *info = fbinfo->par; - bfin_t350mcqb_disable_ppi(); disable_dma(CH_PPI); bfin_write_PPI_STATUS(0xFFFF); @@ -649,9 +643,6 @@ static int bfin_t350mcqb_suspend(struct platform_device *pdev, pm_message_t stat static int bfin_t350mcqb_resume(struct platform_device *pdev) { - struct fb_info *fbinfo = platform_get_drvdata(pdev); - struct bfin_t350mcqbfb_info *info = fbinfo->par; - enable_dma(CH_PPI); bfin_t350mcqb_enable_ppi(); @@ -664,7 +655,7 @@ static int bfin_t350mcqb_resume(struct platform_device *pdev) static struct platform_driver bfin_t350mcqb_driver = { .probe = bfin_t350mcqb_probe, - .remove = bfin_t350mcqb_remove, + .remove = __devexit_p(bfin_t350mcqb_remove), .suspend = bfin_t350mcqb_suspend, .resume = bfin_t350mcqb_resume, .driver = { @@ -673,7 +664,7 @@ static struct platform_driver bfin_t350mcqb_driver = { }, }; -static int __devinit bfin_t350mcqb_driver_init(void) +static int __init bfin_t350mcqb_driver_init(void) { return platform_driver_register(&bfin_t350mcqb_driver); } diff --git a/drivers/video/bw2.c b/drivers/video/bw2.c index 1e35ba6f18e0..b0b147cb4cb3 100644 --- a/drivers/video/bw2.c +++ b/drivers/video/bw2.c @@ -111,9 +111,7 @@ struct bw2_par { u32 flags; #define BW2_FLAG_BLANKED 0x00000001 - unsigned long physbase; unsigned long which_io; - unsigned long fbsize; }; /** @@ -167,17 +165,15 @@ static int bw2_mmap(struct fb_info *info, struct vm_area_struct *vma) struct bw2_par *par = (struct bw2_par *)info->par; return sbusfb_mmap_helper(bw2_mmap_map, - par->physbase, par->fbsize, + info->fix.smem_start, info->fix.smem_len, par->which_io, vma); } static int bw2_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) { - struct bw2_par *par = (struct bw2_par *) info->par; - return sbusfb_ioctl_helper(cmd, arg, info, - FBTYPE_SUN2BW, 1, par->fbsize); + FBTYPE_SUN2BW, 1, info->fix.smem_len); } /* @@ -294,7 +290,7 @@ static int __devinit bw2_probe(struct of_device *op, const struct of_device_id * spin_lock_init(&par->lock); - par->physbase = op->resource[0].start; + info->fix.smem_start = op->resource[0].start; par->which_io = op->resource[0].flags & IORESOURCE_BITS; sbusfb_fill_var(&info->var, dp, 1); @@ -317,13 +313,13 @@ static int __devinit bw2_probe(struct of_device *op, const struct of_device_id * goto out_unmap_regs; } - par->fbsize = PAGE_ALIGN(linebytes * info->var.yres); + info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres); info->flags = FBINFO_DEFAULT; info->fbops = &bw2_ops; info->screen_base = of_ioremap(&op->resource[0], 0, - par->fbsize, "bw2 ram"); + info->fix.smem_len, "bw2 ram"); if (!info->screen_base) goto out_unmap_regs; @@ -338,12 +334,12 @@ static int __devinit bw2_probe(struct of_device *op, const struct of_device_id * dev_set_drvdata(&op->dev, info); printk(KERN_INFO "%s: bwtwo at %lx:%lx\n", - dp->full_name, par->which_io, par->physbase); + dp->full_name, par->which_io, info->fix.smem_start); return 0; out_unmap_screen: - of_iounmap(&op->resource[0], info->screen_base, par->fbsize); + of_iounmap(&op->resource[0], info->screen_base, info->fix.smem_len); out_unmap_regs: of_iounmap(&op->resource[0], par->regs, sizeof(struct bw2_regs)); @@ -363,7 +359,7 @@ static int __devexit bw2_remove(struct of_device *op) unregister_framebuffer(info); of_iounmap(&op->resource[0], par->regs, sizeof(struct bw2_regs)); - of_iounmap(&op->resource[0], info->screen_base, par->fbsize); + of_iounmap(&op->resource[0], info->screen_base, info->fix.smem_len); framebuffer_release(info); diff --git a/drivers/video/carminefb.c b/drivers/video/carminefb.c index c7ff3c1a266a..0c02f8ec4bf3 100644 --- a/drivers/video/carminefb.c +++ b/drivers/video/carminefb.c @@ -562,7 +562,7 @@ static int __devinit alloc_carmine_fb(void __iomem *regs, void __iomem *smem_bas if (ret < 0) goto err_free_fb; - if (fb_mode > ARRAY_SIZE(carmine_modedb)) + if (fb_mode >= ARRAY_SIZE(carmine_modedb)) fb_mode = CARMINEFB_DEFAULT_VIDEO_MODE; par->cur_mode = par->new_mode = ~0; diff --git a/drivers/video/cg14.c b/drivers/video/cg14.c index a2d1882791a5..fe45a3b8d0e0 100644 --- a/drivers/video/cg14.c +++ b/drivers/video/cg14.c @@ -196,9 +196,7 @@ struct cg14_par { u32 flags; #define CG14_FLAG_BLANKED 0x00000001 - unsigned long physbase; unsigned long iospace; - unsigned long fbsize; struct sbus_mmap_map mmap_map[CG14_MMAP_ENTRIES]; @@ -271,7 +269,7 @@ static int cg14_mmap(struct fb_info *info, struct vm_area_struct *vma) struct cg14_par *par = (struct cg14_par *) info->par; return sbusfb_mmap_helper(par->mmap_map, - par->physbase, par->fbsize, + info->fix.smem_start, info->fix.smem_len, par->iospace, vma); } @@ -343,7 +341,8 @@ static int cg14_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) default: ret = sbusfb_ioctl_helper(cmd, arg, info, - FBTYPE_MDICOLOR, 8, par->fbsize); + FBTYPE_MDICOLOR, 8, + info->fix.smem_len); break; }; @@ -462,7 +461,7 @@ static void cg14_unmap_regs(struct of_device *op, struct fb_info *info, par->cursor, sizeof(struct cg14_cursor)); if (info->screen_base) of_iounmap(&op->resource[1], - info->screen_base, par->fbsize); + info->screen_base, info->fix.smem_len); } static int __devinit cg14_probe(struct of_device *op, const struct of_device_id *match) @@ -488,14 +487,14 @@ static int __devinit cg14_probe(struct of_device *op, const struct of_device_id linebytes = of_getintprop_default(dp, "linebytes", info->var.xres); - par->fbsize = PAGE_ALIGN(linebytes * info->var.yres); + info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres); if (!strcmp(dp->parent->name, "sbus") || !strcmp(dp->parent->name, "sbi")) { - par->physbase = op->resource[0].start; + info->fix.smem_start = op->resource[0].start; par->iospace = op->resource[0].flags & IORESOURCE_BITS; } else { - par->physbase = op->resource[1].start; + info->fix.smem_start = op->resource[1].start; par->iospace = op->resource[0].flags & IORESOURCE_BITS; } @@ -507,7 +506,7 @@ static int __devinit cg14_probe(struct of_device *op, const struct of_device_id sizeof(struct cg14_cursor), "cg14 cursor"); info->screen_base = of_ioremap(&op->resource[1], 0, - par->fbsize, "cg14 ram"); + info->fix.smem_len, "cg14 ram"); if (!par->regs || !par->clut || !par->cursor || !info->screen_base) goto out_unmap_regs; @@ -557,7 +556,7 @@ static int __devinit cg14_probe(struct of_device *op, const struct of_device_id printk(KERN_INFO "%s: cgfourteen at %lx:%lx, %dMB\n", dp->full_name, - par->iospace, par->physbase, + par->iospace, info->fix.smem_start, par->ramsize >> 20); return 0; diff --git a/drivers/video/cg3.c b/drivers/video/cg3.c index 99f87fb61d05..b2319fa7286f 100644 --- a/drivers/video/cg3.c +++ b/drivers/video/cg3.c @@ -118,9 +118,7 @@ struct cg3_par { #define CG3_FLAG_BLANKED 0x00000001 #define CG3_FLAG_RDI 0x00000002 - unsigned long physbase; unsigned long which_io; - unsigned long fbsize; }; /** @@ -231,17 +229,15 @@ static int cg3_mmap(struct fb_info *info, struct vm_area_struct *vma) struct cg3_par *par = (struct cg3_par *)info->par; return sbusfb_mmap_helper(cg3_mmap_map, - par->physbase, par->fbsize, + info->fix.smem_start, info->fix.smem_len, par->which_io, vma); } static int cg3_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) { - struct cg3_par *par = (struct cg3_par *) info->par; - return sbusfb_ioctl_helper(cmd, arg, info, - FBTYPE_SUN3COLOR, 8, par->fbsize); + FBTYPE_SUN3COLOR, 8, info->fix.smem_len); } /* @@ -368,7 +364,7 @@ static int __devinit cg3_probe(struct of_device *op, spin_lock_init(&par->lock); - par->physbase = op->resource[0].start; + info->fix.smem_start = op->resource[0].start; par->which_io = op->resource[0].flags & IORESOURCE_BITS; sbusfb_fill_var(&info->var, dp, 8); @@ -382,7 +378,7 @@ static int __devinit cg3_probe(struct of_device *op, linebytes = of_getintprop_default(dp, "linebytes", info->var.xres); - par->fbsize = PAGE_ALIGN(linebytes * info->var.yres); + info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres); par->regs = of_ioremap(&op->resource[0], CG3_REGS_OFFSET, sizeof(struct cg3_regs), "cg3 regs"); @@ -392,7 +388,7 @@ static int __devinit cg3_probe(struct of_device *op, info->flags = FBINFO_DEFAULT; info->fbops = &cg3_ops; info->screen_base = of_ioremap(&op->resource[0], CG3_RAM_OFFSET, - par->fbsize, "cg3 ram"); + info->fix.smem_len, "cg3 ram"); if (!info->screen_base) goto out_unmap_regs; @@ -418,7 +414,7 @@ static int __devinit cg3_probe(struct of_device *op, dev_set_drvdata(&op->dev, info); printk(KERN_INFO "%s: cg3 at %lx:%lx\n", - dp->full_name, par->which_io, par->physbase); + dp->full_name, par->which_io, info->fix.smem_start); return 0; @@ -426,7 +422,7 @@ out_dealloc_cmap: fb_dealloc_cmap(&info->cmap); out_unmap_screen: - of_iounmap(&op->resource[0], info->screen_base, par->fbsize); + of_iounmap(&op->resource[0], info->screen_base, info->fix.smem_len); out_unmap_regs: of_iounmap(&op->resource[0], par->regs, sizeof(struct cg3_regs)); @@ -447,7 +443,7 @@ static int __devexit cg3_remove(struct of_device *op) fb_dealloc_cmap(&info->cmap); of_iounmap(&op->resource[0], par->regs, sizeof(struct cg3_regs)); - of_iounmap(&op->resource[0], info->screen_base, par->fbsize); + of_iounmap(&op->resource[0], info->screen_base, info->fix.smem_len); framebuffer_release(info); diff --git a/drivers/video/cg6.c b/drivers/video/cg6.c index 940ec04f0f1b..0d47c6030e3d 100644 --- a/drivers/video/cg6.c +++ b/drivers/video/cg6.c @@ -263,9 +263,7 @@ struct cg6_par { u32 flags; #define CG6_FLAG_BLANKED 0x00000001 - unsigned long physbase; unsigned long which_io; - unsigned long fbsize; }; static int cg6_sync(struct fb_info *info) @@ -596,16 +594,14 @@ static int cg6_mmap(struct fb_info *info, struct vm_area_struct *vma) struct cg6_par *par = (struct cg6_par *)info->par; return sbusfb_mmap_helper(cg6_mmap_map, - par->physbase, par->fbsize, + info->fix.smem_start, info->fix.smem_len, par->which_io, vma); } static int cg6_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) { - struct cg6_par *par = (struct cg6_par *)info->par; - return sbusfb_ioctl_helper(cmd, arg, info, - FBTYPE_SUNFAST_COLOR, 8, par->fbsize); + FBTYPE_SUNFAST_COLOR, 8, info->fix.smem_len); } /* @@ -631,12 +627,12 @@ static void __devinit cg6_init_fix(struct fb_info *info, int linebytes) break; }; if (((conf >> CG6_FHC_REV_SHIFT) & CG6_FHC_REV_MASK) >= 11) { - if (par->fbsize <= 0x100000) + if (info->fix.smem_len <= 0x100000) cg6_card_name = "TGX"; else cg6_card_name = "TGX+"; } else { - if (par->fbsize <= 0x100000) + if (info->fix.smem_len <= 0x100000) cg6_card_name = "GX"; else cg6_card_name = "GX+"; @@ -738,7 +734,8 @@ static void cg6_unmap_regs(struct of_device *op, struct fb_info *info, of_iounmap(&op->resource[0], par->fhc, sizeof(u32)); if (info->screen_base) - of_iounmap(&op->resource[0], info->screen_base, par->fbsize); + of_iounmap(&op->resource[0], info->screen_base, + info->fix.smem_len); } static int __devinit cg6_probe(struct of_device *op, @@ -759,7 +756,7 @@ static int __devinit cg6_probe(struct of_device *op, spin_lock_init(&par->lock); - par->physbase = op->resource[0].start; + info->fix.smem_start = op->resource[0].start; par->which_io = op->resource[0].flags & IORESOURCE_BITS; sbusfb_fill_var(&info->var, dp, 8); @@ -769,11 +766,11 @@ static int __devinit cg6_probe(struct of_device *op, linebytes = of_getintprop_default(dp, "linebytes", info->var.xres); - par->fbsize = PAGE_ALIGN(linebytes * info->var.yres); + info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres); dblbuf = of_getintprop_default(dp, "dblbuf", 0); if (dblbuf) - par->fbsize *= 4; + info->fix.smem_len *= 4; par->fbc = of_ioremap(&op->resource[0], CG6_FBC_OFFSET, 4096, "cgsix fbc"); @@ -792,7 +789,7 @@ static int __devinit cg6_probe(struct of_device *op, info->fbops = &cg6_ops; info->screen_base = of_ioremap(&op->resource[0], CG6_RAM_OFFSET, - par->fbsize, "cgsix ram"); + info->fix.smem_len, "cgsix ram"); if (!par->fbc || !par->tec || !par->thc || !par->bt || !par->fhc || !info->screen_base) goto out_unmap_regs; @@ -817,7 +814,7 @@ static int __devinit cg6_probe(struct of_device *op, printk(KERN_INFO "%s: CGsix [%s] at %lx:%lx\n", dp->full_name, info->fix.id, - par->which_io, par->physbase); + par->which_io, info->fix.smem_start); return 0; diff --git a/drivers/video/chipsfb.c b/drivers/video/chipsfb.c index 777389c40988..57b9d276497e 100644 --- a/drivers/video/chipsfb.c +++ b/drivers/video/chipsfb.c @@ -414,7 +414,6 @@ chipsfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent) } pci_set_drvdata(dp, p); - p->device = &dp->dev; init_chips(p, addr); diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index 38e86b84dce0..59d7d5ec17a4 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -180,7 +180,7 @@ static inline void vga_set_mem_top(struct vc_data *c) } #ifdef CONFIG_VGACON_SOFT_SCROLLBACK -#include +#include /* software scrollback */ static void *vgacon_scrollback; static int vgacon_scrollback_tail; @@ -210,8 +210,7 @@ static void vgacon_scrollback_init(int pitch) */ static void __init_refok vgacon_scrollback_startup(void) { - vgacon_scrollback = alloc_bootmem(CONFIG_VGACON_SOFT_SCROLLBACK_SIZE - * 1024); + vgacon_scrollback = kcalloc(CONFIG_VGACON_SOFT_SCROLLBACK_SIZE, 1024, GFP_NOWAIT); vgacon_scrollback_init(vga_video_num_columns * 2); } diff --git a/drivers/video/cyber2000fb.c b/drivers/video/cyber2000fb.c index 83c5cefc266c..da7c01b39be2 100644 --- a/drivers/video/cyber2000fb.c +++ b/drivers/video/cyber2000fb.c @@ -1736,10 +1736,8 @@ static int __init cyber2000fb_init(void) #ifdef CONFIG_ARCH_SHARK err = cyberpro_vl_probe(); - if (!err) { + if (!err) ret = 0; - __module_get(THIS_MODULE); - } #endif #ifdef CONFIG_PCI err = pci_register_driver(&cyberpro_driver); @@ -1749,14 +1747,15 @@ static int __init cyber2000fb_init(void) return ret ? err : 0; } +module_init(cyber2000fb_init); +#ifndef CONFIG_ARCH_SHARK static void __exit cyberpro_exit(void) { pci_unregister_driver(&cyberpro_driver); } - -module_init(cyber2000fb_init); module_exit(cyberpro_exit); +#endif MODULE_AUTHOR("Russell King"); MODULE_DESCRIPTION("CyberPro 2000, 2010 and 5000 framebuffer driver"); diff --git a/drivers/video/efifb.c b/drivers/video/efifb.c index 8dea2bc92705..eb12182b2059 100644 --- a/drivers/video/efifb.c +++ b/drivers/video/efifb.c @@ -280,6 +280,9 @@ static int __init efifb_probe(struct platform_device *dev) info->pseudo_palette = info->par; info->par = NULL; + info->aperture_base = efifb_fix.smem_start; + info->aperture_size = size_total; + info->screen_base = ioremap(efifb_fix.smem_start, efifb_fix.smem_len); if (!info->screen_base) { printk(KERN_ERR "efifb: abort, cannot ioremap video memory " @@ -337,7 +340,7 @@ static int __init efifb_probe(struct platform_device *dev) info->fbops = &efifb_ops; info->var = efifb_defined; info->fix = efifb_fix; - info->flags = FBINFO_FLAG_DEFAULT; + info->flags = FBINFO_FLAG_DEFAULT | FBINFO_MISC_FIRMWARE; if ((err = fb_alloc_cmap(&info->cmap, 256, 0)) < 0) { printk(KERN_ERR "efifb: cannot allocate colormap\n"); diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index d412a1ddc12f..f8a09bf8d0cd 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -1462,6 +1462,16 @@ static int fb_check_foreignness(struct fb_info *fi) return 0; } +static bool fb_do_apertures_overlap(struct fb_info *gen, struct fb_info *hw) +{ + /* is the generic aperture base the same as the HW one */ + if (gen->aperture_base == hw->aperture_base) + return true; + /* is the generic aperture base inside the hw base->hw base+size */ + if (gen->aperture_base > hw->aperture_base && gen->aperture_base <= hw->aperture_base + hw->aperture_size) + return true; + return false; +} /** * register_framebuffer - registers a frame buffer device * @fb_info: frame buffer info structure @@ -1485,6 +1495,23 @@ register_framebuffer(struct fb_info *fb_info) if (fb_check_foreignness(fb_info)) return -ENOSYS; + /* check all firmware fbs and kick off if the base addr overlaps */ + for (i = 0 ; i < FB_MAX; i++) { + if (!registered_fb[i]) + continue; + + if (registered_fb[i]->flags & FBINFO_MISC_FIRMWARE) { + if (fb_do_apertures_overlap(registered_fb[i], fb_info)) { + printk(KERN_ERR "fb: conflicting fb hw usage " + "%s vs %s - removing generic driver\n", + fb_info->fix.id, + registered_fb[i]->fix.id); + unregister_framebuffer(registered_fb[i]); + break; + } + } + } + num_registered_fb++; for (i = 0 ; i < FB_MAX; i++) if (!registered_fb[i]) @@ -1586,6 +1613,10 @@ unregister_framebuffer(struct fb_info *fb_info) device_destroy(fb_class, MKDEV(FB_MAJOR, i)); event.info = fb_info; fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event); + + /* this may free fb info */ + if (fb_info->fbops->fb_destroy) + fb_info->fbops->fb_destroy(fb_info); done: return ret; } diff --git a/drivers/video/hitfb.c b/drivers/video/hitfb.c index e6467cf9f19f..020db7fc9153 100644 --- a/drivers/video/hitfb.c +++ b/drivers/video/hitfb.c @@ -335,9 +335,9 @@ static int __init hitfb_probe(struct platform_device *dev) if (fb_get_options("hitfb", NULL)) return -ENODEV; - hitfb_fix.mmio_start = CONFIG_HD64461_IOBASE+0x1000; + hitfb_fix.mmio_start = HD64461_IO_OFFSET(0x1000); hitfb_fix.mmio_len = 0x1000; - hitfb_fix.smem_start = CONFIG_HD64461_IOBASE + 0x02000000; + hitfb_fix.smem_start = HD64461_IO_OFFSET(0x02000000); hitfb_fix.smem_len = 512 * 1024; lcdclor = fb_readw(HD64461_LCDCLOR); diff --git a/drivers/video/igafb.c b/drivers/video/igafb.c index 3a81060137a2..15d200109446 100644 --- a/drivers/video/igafb.c +++ b/drivers/video/igafb.c @@ -395,17 +395,16 @@ int __init igafb_init(void) /* We leak a reference here but as it cannot be unloaded this is fine. If you write unload code remember to free it in unload */ - size = sizeof(struct fb_info) + sizeof(struct iga_par) + sizeof(u32)*16; + size = sizeof(struct iga_par) + sizeof(u32)*16; - info = kzalloc(size, GFP_ATOMIC); + info = framebuffer_alloc(size, &pdev->dev); if (!info) { printk("igafb_init: can't alloc fb_info\n"); pci_dev_put(pdev); return -ENOMEM; } - par = (struct iga_par *) (info + 1); - + par = info->par; if ((addr = pdev->resource[0].start) == 0) { printk("igafb_init: no memory start\n"); @@ -526,7 +525,6 @@ int __init igafb_init(void) info->var = default_var; info->fix = igafb_fix; info->pseudo_palette = (void *)(par + 1); - info->device = &pdev->dev; if (!iga_init(info, par)) { iounmap((void *)par->io_base); diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c index ace14fe02fc4..0cafd642fbc0 100644 --- a/drivers/video/intelfb/intelfbdrv.c +++ b/drivers/video/intelfb/intelfbdrv.c @@ -1365,6 +1365,11 @@ static int intelfb_set_par(struct fb_info *info) DBG_MSG("intelfb_set_par (%dx%d-%d)\n", info->var.xres, info->var.yres, info->var.bits_per_pixel); + /* + * Disable VCO prior to timing register change. + */ + OUTREG(DPLL_A, INREG(DPLL_A) & ~DPLL_VCO_ENABLE); + intelfb_blank(FB_BLANK_POWERDOWN, info); if (ACCEL(dinfo, info)) diff --git a/drivers/video/leo.c b/drivers/video/leo.c index 7c7e8c2da9d9..e145e2d16fe3 100644 --- a/drivers/video/leo.c +++ b/drivers/video/leo.c @@ -191,9 +191,7 @@ struct leo_par { u32 flags; #define LEO_FLAG_BLANKED 0x00000001 - unsigned long physbase; unsigned long which_io; - unsigned long fbsize; }; static void leo_wait(struct leo_lx_krn __iomem *lx_krn) @@ -420,16 +418,14 @@ static int leo_mmap(struct fb_info *info, struct vm_area_struct *vma) struct leo_par *par = (struct leo_par *)info->par; return sbusfb_mmap_helper(leo_mmap_map, - par->physbase, par->fbsize, + info->fix.smem_start, info->fix.smem_len, par->which_io, vma); } static int leo_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) { - struct leo_par *par = (struct leo_par *) info->par; - return sbusfb_ioctl_helper(cmd, arg, info, - FBTYPE_SUNLEO, 32, par->fbsize); + FBTYPE_SUNLEO, 32, info->fix.smem_len); } /* @@ -569,7 +565,7 @@ static int __devinit leo_probe(struct of_device *op, spin_lock_init(&par->lock); - par->physbase = op->resource[0].start; + info->fix.smem_start = op->resource[0].start; par->which_io = op->resource[0].flags & IORESOURCE_BITS; sbusfb_fill_var(&info->var, dp, 32); @@ -577,7 +573,7 @@ static int __devinit leo_probe(struct of_device *op, linebytes = of_getintprop_default(dp, "linebytes", info->var.xres); - par->fbsize = PAGE_ALIGN(linebytes * info->var.yres); + info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres); par->lc_ss0_usr = of_ioremap(&op->resource[0], LEO_OFF_LC_SS0_USR, @@ -627,7 +623,7 @@ static int __devinit leo_probe(struct of_device *op, printk(KERN_INFO "%s: leo at %lx:%lx\n", dp->full_name, - par->which_io, par->physbase); + par->which_io, info->fix.smem_start); return 0; diff --git a/drivers/video/logo/Makefile b/drivers/video/logo/Makefile index b91251d1fe41..3b437813584c 100644 --- a/drivers/video/logo/Makefile +++ b/drivers/video/logo/Makefile @@ -37,22 +37,24 @@ extra-y += $(call logo-cfiles,_clut224,ppm) # Gray 256 extra-y += $(call logo-cfiles,_gray256,pgm) +pnmtologo := scripts/pnmtologo + # Create commands like "pnmtologo -t mono -n logo_mac_mono -o ..." quiet_cmd_logo = LOGO $@ - cmd_logo = scripts/pnmtologo \ + cmd_logo = $(pnmtologo) \ -t $(patsubst $*_%,%,$(notdir $(basename $<))) \ -n $(notdir $(basename $<)) -o $@ $< -$(obj)/%_mono.c: $(src)/%_mono.pbm FORCE +$(obj)/%_mono.c: $(src)/%_mono.pbm $(pnmtologo) FORCE $(call if_changed,logo) -$(obj)/%_vga16.c: $(src)/%_vga16.ppm FORCE +$(obj)/%_vga16.c: $(src)/%_vga16.ppm $(pnmtologo) FORCE $(call if_changed,logo) -$(obj)/%_clut224.c: $(src)/%_clut224.ppm FORCE +$(obj)/%_clut224.c: $(src)/%_clut224.ppm $(pnmtologo) FORCE $(call if_changed,logo) -$(obj)/%_gray256.c: $(src)/%_gray256.pgm FORCE +$(obj)/%_gray256.c: $(src)/%_gray256.pgm $(pnmtologo) FORCE $(call if_changed,logo) # Files generated that shall be removed upon make clean diff --git a/drivers/video/logo/logo.c b/drivers/video/logo/logo.c index 2e85a2b52d05..ea7a8ccc830c 100644 --- a/drivers/video/logo/logo.c +++ b/drivers/video/logo/logo.c @@ -21,21 +21,6 @@ #include #endif -extern const struct linux_logo logo_linux_mono; -extern const struct linux_logo logo_linux_vga16; -extern const struct linux_logo logo_linux_clut224; -extern const struct linux_logo logo_blackfin_vga16; -extern const struct linux_logo logo_blackfin_clut224; -extern const struct linux_logo logo_dec_clut224; -extern const struct linux_logo logo_mac_clut224; -extern const struct linux_logo logo_parisc_clut224; -extern const struct linux_logo logo_sgi_clut224; -extern const struct linux_logo logo_sun_clut224; -extern const struct linux_logo logo_superh_mono; -extern const struct linux_logo logo_superh_vga16; -extern const struct linux_logo logo_superh_clut224; -extern const struct linux_logo logo_m32r_clut224; - static int nologo; module_param(nologo, bool, 0); MODULE_PARM_DESC(nologo, "Disables startup logo"); diff --git a/drivers/video/mb862xx/mb862xxfb.c b/drivers/video/mb862xx/mb862xxfb.c index fb64234a3825..a28e3cfbbf70 100644 --- a/drivers/video/mb862xx/mb862xxfb.c +++ b/drivers/video/mb862xx/mb862xxfb.c @@ -19,7 +19,7 @@ #include #include #include -#if defined(CONFIG_PPC_OF) +#if defined(CONFIG_OF) #include #endif #include "mb862xxfb.h" diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c index 16186240c5f2..34e4e7995169 100644 --- a/drivers/video/modedb.c +++ b/drivers/video/modedb.c @@ -264,6 +264,14 @@ static const struct fb_videomode modedb[] = { /* 1280x800, 60 Hz, 47.403 kHz hsync, WXGA 16:10 aspect ratio */ NULL, 60, 1280, 800, 12048, 200, 64, 24, 1, 136, 3, 0, FB_VMODE_NONINTERLACED + }, { + /* 720x576i @ 50 Hz, 15.625 kHz hsync (PAL RGB) */ + NULL, 50, 720, 576, 74074, 64, 16, 39, 5, 64, 5, + 0, FB_VMODE_INTERLACED + }, { + /* 800x520i @ 50 Hz, 15.625 kHz hsync (PAL RGB) */ + NULL, 50, 800, 520, 58823, 144, 64, 72, 28, 80, 5, + 0, FB_VMODE_INTERLACED }, }; diff --git a/drivers/video/mx3fb.c b/drivers/video/mx3fb.c index 9894de1c9b9f..b7af5256e887 100644 --- a/drivers/video/mx3fb.c +++ b/drivers/video/mx3fb.c @@ -706,7 +706,7 @@ static void mx3fb_dma_done(void *arg) dev_dbg(mx3fb->dev, "irq %d callback\n", ichannel->eof_irq); /* We only need one interrupt, it will be re-enabled as needed */ - disable_irq(ichannel->eof_irq); + disable_irq_nosync(ichannel->eof_irq); complete(&mx3_fbi->flip_cmpl); } @@ -1366,7 +1366,7 @@ static int init_fb_chan(struct mx3fb_data *mx3fb, struct idmac_channel *ichan) mx3fb_blank(FB_BLANK_UNBLANK, fbi); - dev_info(dev, "mx3fb: fb registered, using mode %s\n", fb_mode); + dev_info(dev, "registered, using mode %s\n", fb_mode); ret = register_framebuffer(fbi); if (ret < 0) diff --git a/drivers/video/nvidia/nv_setup.c b/drivers/video/nvidia/nv_setup.c index 135ae18bfce8..eef2bb298d9f 100644 --- a/drivers/video/nvidia/nv_setup.c +++ b/drivers/video/nvidia/nv_setup.c @@ -543,8 +543,7 @@ int NVCommonSetup(struct fb_info *info) } else if (analog_on_B) { CRTCnumber = outputBfromCRTC; FlatPanel = 0; - printk("nvidiafb: CRTC %i" - "appears to have a " + printk("nvidiafb: CRTC %i appears to have a " "CRT attached\n", CRTCnumber); } else if (slaved_on_A) { CRTCnumber = 0; diff --git a/drivers/video/offb.c b/drivers/video/offb.c index e1d9eeb1aeaf..4d8c54c23dd7 100644 --- a/drivers/video/offb.c +++ b/drivers/video/offb.c @@ -378,7 +378,6 @@ static void __init offb_init_fb(const char *name, const char *full_name, struct fb_fix_screeninfo *fix; struct fb_var_screeninfo *var; struct fb_info *info; - int size; if (!request_mem_region(res_start, res_size, "offb")) return; @@ -393,15 +392,12 @@ static void __init offb_init_fb(const char *name, const char *full_name, return; } - size = sizeof(struct fb_info) + sizeof(u32) * 16; - - info = kmalloc(size, GFP_ATOMIC); + info = framebuffer_alloc(sizeof(u32) * 16, NULL); if (info == 0) { release_mem_region(res_start, res_size); return; } - memset(info, 0, size); fix = &info->fix; var = &info->var; @@ -497,7 +493,7 @@ static void __init offb_init_fb(const char *name, const char *full_name, iounmap(par->cmap_adr); par->cmap_adr = NULL; iounmap(info->screen_base); - kfree(info); + framebuffer_release(info); release_mem_region(res_start, res_size); return; } diff --git a/drivers/video/omap/hwa742.c b/drivers/video/omap/hwa742.c index 8aa6e47202b9..5d4f34887a22 100644 --- a/drivers/video/omap/hwa742.c +++ b/drivers/video/omap/hwa742.c @@ -133,8 +133,7 @@ struct { struct lcd_ctrl_extif *extif; struct lcd_ctrl *int_ctrl; - void (*power_up)(struct device *dev); - void (*power_down)(struct device *dev); + struct clk *sys_ck; } hwa742; struct lcd_ctrl hwa742_ctrl; @@ -915,14 +914,13 @@ static void hwa742_suspend(void) hwa742_set_update_mode(OMAPFB_UPDATE_DISABLED); /* Enable sleep mode */ hwa742_write_reg(HWA742_POWER_SAVE, 1 << 1); - if (hwa742.power_down != NULL) - hwa742.power_down(hwa742.fbdev->dev); + clk_disable(hwa742.sys_ck); } static void hwa742_resume(void) { - if (hwa742.power_up != NULL) - hwa742.power_up(hwa742.fbdev->dev); + clk_enable(hwa742.sys_ck); + /* Disable sleep mode */ hwa742_write_reg(HWA742_POWER_SAVE, 0); while (1) { @@ -955,14 +953,13 @@ static int hwa742_init(struct omapfb_device *fbdev, int ext_mode, omapfb_conf = fbdev->dev->platform_data; ctrl_conf = omapfb_conf->ctrl_platform_data; - if (ctrl_conf == NULL || ctrl_conf->get_clock_rate == NULL) { + if (ctrl_conf == NULL) { dev_err(fbdev->dev, "HWA742: missing platform data\n"); r = -ENOENT; goto err1; } - hwa742.power_down = ctrl_conf->power_down; - hwa742.power_up = ctrl_conf->power_up; + hwa742.sys_ck = clk_get(NULL, "hwa_sys_ck"); spin_lock_init(&hwa742.req_lock); @@ -972,12 +969,11 @@ static int hwa742_init(struct omapfb_device *fbdev, int ext_mode, if ((r = hwa742.extif->init(fbdev)) < 0) goto err2; - ext_clk = ctrl_conf->get_clock_rate(fbdev->dev); + ext_clk = clk_get_rate(hwa742.sys_ck); if ((r = calc_extif_timings(ext_clk, &extif_mem_div)) < 0) goto err3; hwa742.extif->set_timings(&hwa742.reg_timings); - if (hwa742.power_up != NULL) - hwa742.power_up(fbdev->dev); + clk_enable(hwa742.sys_ck); calc_hwa742_clk_rates(ext_clk, &sys_clk, &pix_clk); if ((r = calc_extif_timings(sys_clk, &extif_mem_div)) < 0) @@ -1040,8 +1036,7 @@ static int hwa742_init(struct omapfb_device *fbdev, int ext_mode, return 0; err4: - if (hwa742.power_down != NULL) - hwa742.power_down(fbdev->dev); + clk_disable(hwa742.sys_ck); err3: hwa742.extif->cleanup(); err2: @@ -1055,8 +1050,7 @@ static void hwa742_cleanup(void) hwa742_set_update_mode(OMAPFB_UPDATE_DISABLED); hwa742.extif->cleanup(); hwa742.int_ctrl->cleanup(); - if (hwa742.power_down != NULL) - hwa742.power_down(hwa742.fbdev->dev); + clk_disable(hwa742.sys_ck); } struct lcd_ctrl hwa742_ctrl = { diff --git a/drivers/video/p9100.c b/drivers/video/p9100.c index 7000f2cd5854..7fa4ab01b0d3 100644 --- a/drivers/video/p9100.c +++ b/drivers/video/p9100.c @@ -134,9 +134,7 @@ struct p9100_par { u32 flags; #define P9100_FLAG_BLANKED 0x00000001 - unsigned long physbase; unsigned long which_io; - unsigned long fbsize; }; /** @@ -224,18 +222,16 @@ static int p9100_mmap(struct fb_info *info, struct vm_area_struct *vma) struct p9100_par *par = (struct p9100_par *)info->par; return sbusfb_mmap_helper(p9100_mmap_map, - par->physbase, par->fbsize, + info->fix.smem_start, info->fix.smem_len, par->which_io, vma); } static int p9100_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) { - struct p9100_par *par = (struct p9100_par *) info->par; - /* Make it look like a cg3. */ return sbusfb_ioctl_helper(cmd, arg, info, - FBTYPE_SUN3COLOR, 8, par->fbsize); + FBTYPE_SUN3COLOR, 8, info->fix.smem_len); } /* @@ -271,7 +267,7 @@ static int __devinit p9100_probe(struct of_device *op, const struct of_device_id spin_lock_init(&par->lock); /* This is the framebuffer and the only resource apps can mmap. */ - par->physbase = op->resource[2].start; + info->fix.smem_start = op->resource[2].start; par->which_io = op->resource[2].flags & IORESOURCE_BITS; sbusfb_fill_var(&info->var, dp, 8); @@ -280,7 +276,7 @@ static int __devinit p9100_probe(struct of_device *op, const struct of_device_id info->var.blue.length = 8; linebytes = of_getintprop_default(dp, "linebytes", info->var.xres); - par->fbsize = PAGE_ALIGN(linebytes * info->var.yres); + info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres); par->regs = of_ioremap(&op->resource[0], 0, sizeof(struct p9100_regs), "p9100 regs"); @@ -290,7 +286,7 @@ static int __devinit p9100_probe(struct of_device *op, const struct of_device_id info->flags = FBINFO_DEFAULT; info->fbops = &p9100_ops; info->screen_base = of_ioremap(&op->resource[2], 0, - par->fbsize, "p9100 ram"); + info->fix.smem_len, "p9100 ram"); if (!info->screen_base) goto out_unmap_regs; @@ -311,7 +307,7 @@ static int __devinit p9100_probe(struct of_device *op, const struct of_device_id printk(KERN_INFO "%s: p9100 at %lx:%lx\n", dp->full_name, - par->which_io, par->physbase); + par->which_io, info->fix.smem_start); return 0; @@ -319,7 +315,7 @@ out_dealloc_cmap: fb_dealloc_cmap(&info->cmap); out_unmap_screen: - of_iounmap(&op->resource[2], info->screen_base, par->fbsize); + of_iounmap(&op->resource[2], info->screen_base, info->fix.smem_len); out_unmap_regs: of_iounmap(&op->resource[0], par->regs, sizeof(struct p9100_regs)); @@ -340,7 +336,7 @@ static int __devexit p9100_remove(struct of_device *op) fb_dealloc_cmap(&info->cmap); of_iounmap(&op->resource[0], par->regs, sizeof(struct p9100_regs)); - of_iounmap(&op->resource[2], info->screen_base, par->fbsize); + of_iounmap(&op->resource[2], info->screen_base, info->fix.smem_len); framebuffer_release(info); diff --git a/drivers/video/pm2fb.c b/drivers/video/pm2fb.c index c6dd924976a4..36436ee6c1a4 100644 --- a/drivers/video/pm2fb.c +++ b/drivers/video/pm2fb.c @@ -1748,7 +1748,7 @@ static void __devexit pm2fb_remove(struct pci_dev *pdev) pci_set_drvdata(pdev, NULL); fb_dealloc_cmap(&info->cmap); kfree(info->pixmap.addr); - kfree(info); + framebuffer_release(info); } static struct pci_device_id pm2fb_id_table[] = { diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c index e00c1dff55de..c0af638fe702 100644 --- a/drivers/video/ps3fb.c +++ b/drivers/video/ps3fb.c @@ -32,25 +32,16 @@ #include #include +#include #include #include #include #include +#include #define DEVICE_NAME "ps3fb" -#define L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC 0x101 -#define L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP 0x102 -#define L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP 0x600 -#define L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT 0x601 -#define L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT_SYNC 0x602 - -#define L1GPU_FB_BLIT_WAIT_FOR_COMPLETION (1ULL << 32) - -#define L1GPU_DISPLAY_SYNC_HSYNC 1 -#define L1GPU_DISPLAY_SYNC_VSYNC 2 - #define GPU_CMD_BUF_SIZE (2 * 1024 * 1024) #define GPU_FB_START (64 * 1024) #define GPU_IOIF (0x0d000000UL) @@ -462,33 +453,27 @@ static void ps3fb_sync_image(struct device *dev, u64 frame_offset, src_offset += GPU_FB_START; mutex_lock(&ps3_gpu_mutex); - status = lv1_gpu_context_attribute(ps3fb.context_handle, - L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT, - dst_offset, GPU_IOIF + src_offset, - L1GPU_FB_BLIT_WAIT_FOR_COMPLETION | - (width << 16) | height, - line_length); + status = lv1_gpu_fb_blit(ps3fb.context_handle, dst_offset, + GPU_IOIF + src_offset, + L1GPU_FB_BLIT_WAIT_FOR_COMPLETION | + (width << 16) | height, + line_length); mutex_unlock(&ps3_gpu_mutex); if (status) - dev_err(dev, - "%s: lv1_gpu_context_attribute FB_BLIT failed: %d\n", - __func__, status); + dev_err(dev, "%s: lv1_gpu_fb_blit failed: %d\n", __func__, + status); #ifdef HEAD_A - status = lv1_gpu_context_attribute(ps3fb.context_handle, - L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP, - 0, frame_offset, 0, 0); + status = lv1_gpu_display_flip(ps3fb.context_handle, 0, frame_offset); if (status) - dev_err(dev, "%s: lv1_gpu_context_attribute FLIP failed: %d\n", - __func__, status); + dev_err(dev, "%s: lv1_gpu_display_flip failed: %d\n", __func__, + status); #endif #ifdef HEAD_B - status = lv1_gpu_context_attribute(ps3fb.context_handle, - L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP, - 1, frame_offset, 0, 0); + status = lv1_gpu_display_flip(ps3fb.context_handle, 1, frame_offset); if (status) - dev_err(dev, "%s: lv1_gpu_context_attribute FLIP failed: %d\n", - __func__, status); + dev_err(dev, "%s: lv1_gpu_display_flip failed: %d\n", __func__, + status); #endif } @@ -956,73 +941,6 @@ static irqreturn_t ps3fb_vsync_interrupt(int irq, void *ptr) } -static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo, - struct device *dev) -{ - int error; - - dev_dbg(dev, "version_driver:%x\n", dinfo->version_driver); - dev_dbg(dev, "irq outlet:%x\n", dinfo->irq.irq_outlet); - dev_dbg(dev, - "version_gpu: %x memory_size: %x ch: %x core_freq: %d " - "mem_freq:%d\n", - dinfo->version_gpu, dinfo->memory_size, dinfo->hardware_channel, - dinfo->nvcore_frequency/1000000, dinfo->memory_frequency/1000000); - - if (dinfo->version_driver != GPU_DRIVER_INFO_VERSION) { - dev_err(dev, "%s: version_driver err:%x\n", __func__, - dinfo->version_driver); - return -EINVAL; - } - - error = ps3_irq_plug_setup(PS3_BINDING_CPU_ANY, dinfo->irq.irq_outlet, - &ps3fb.irq_no); - if (error) { - dev_err(dev, "%s: ps3_alloc_irq failed %d\n", __func__, error); - return error; - } - - error = request_irq(ps3fb.irq_no, ps3fb_vsync_interrupt, IRQF_DISABLED, - DEVICE_NAME, dev); - if (error) { - dev_err(dev, "%s: request_irq failed %d\n", __func__, error); - ps3_irq_plug_destroy(ps3fb.irq_no); - return error; - } - - dinfo->irq.mask = (1 << GPU_INTR_STATUS_VSYNC_1) | - (1 << GPU_INTR_STATUS_FLIP_1); - return 0; -} - -static int ps3fb_xdr_settings(u64 xdr_lpar, struct device *dev) -{ - int status; - - status = lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF, - xdr_lpar, ps3fb_videomemory.size, 0); - if (status) { - dev_err(dev, "%s: lv1_gpu_context_iomap failed: %d\n", - __func__, status); - return -ENXIO; - } - dev_dbg(dev, "video:%p ioif:%lx lpar:%llx size:%lx\n", - ps3fb_videomemory.address, GPU_IOIF, xdr_lpar, - ps3fb_videomemory.size); - - status = lv1_gpu_context_attribute(ps3fb.context_handle, - L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP, - xdr_lpar, GPU_CMD_BUF_SIZE, - GPU_IOIF, 0); - if (status) { - dev_err(dev, - "%s: lv1_gpu_context_attribute FB_SETUP failed: %d\n", - __func__, status); - return -ENXIO; - } - return 0; -} - static struct fb_ops ps3fb_ops = { .fb_open = ps3fb_open, .fb_release = ps3fb_release, @@ -1048,49 +966,18 @@ static struct fb_fix_screeninfo ps3fb_fix __initdata = { .accel = FB_ACCEL_NONE, }; -static int ps3fb_set_sync(struct device *dev) -{ - int status; - -#ifdef HEAD_A - status = lv1_gpu_context_attribute(0x0, - L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC, - 0, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0); - if (status) { - dev_err(dev, - "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: " - "%d\n", - __func__, status); - return -1; - } -#endif -#ifdef HEAD_B - status = lv1_gpu_context_attribute(0x0, - L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC, - 1, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0); - - if (status) { - dev_err(dev, - "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: " - "%d\n", - __func__, status); - return -1; - } -#endif - return 0; -} - static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) { struct fb_info *info; struct ps3fb_par *par; - int retval = -ENOMEM; + int retval; u64 ddr_lpar = 0; u64 lpar_dma_control = 0; u64 lpar_driver_info = 0; u64 lpar_reports = 0; u64 lpar_reports_size = 0; u64 xdr_lpar; + struct gpu_driver_info *dinfo; void *fb_start; int status; struct task_struct *task; @@ -1101,8 +988,8 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) return -ENOMEM; } - status = ps3_open_hv_device(dev); - if (status) { + retval = ps3_open_hv_device(dev); + if (retval) { dev_err(&dev->core, "%s: ps3_open_hv_device failed\n", __func__); goto err; @@ -1116,7 +1003,24 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) atomic_set(&ps3fb.ext_flip, 0); /* for flip with vsync */ init_waitqueue_head(&ps3fb.wait_vsync); - ps3fb_set_sync(&dev->core); +#ifdef HEAD_A + status = lv1_gpu_display_sync(0x0, 0, L1GPU_DISPLAY_SYNC_VSYNC); + if (status) { + dev_err(&dev->core, "%s: lv1_gpu_display_sync failed: %d\n", + __func__, status); + retval = -ENODEV; + goto err_close_device; + } +#endif +#ifdef HEAD_B + status = lv1_gpu_display_sync(0x0, 1, L1GPU_DISPLAY_SYNC_VSYNC); + if (status) { + dev_err(&dev->core, "%s: lv1_gpu_display_sync failed: %d\n", + __func__, status); + retval = -ENODEV; + goto err_close_device; + } +#endif max_ps3fb_size = _ALIGN_UP(GPU_IOIF, 256*1024*1024) - GPU_IOIF; if (ps3fb_videomemory.size > max_ps3fb_size) { @@ -1131,7 +1035,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) if (status) { dev_err(&dev->core, "%s: lv1_gpu_memory_allocate failed: %d\n", __func__, status); - goto err; + goto err_close_device; } dev_dbg(&dev->core, "ddr:lpar:0x%llx\n", ddr_lpar); @@ -1141,33 +1045,85 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) &lpar_reports, &lpar_reports_size); if (status) { dev_err(&dev->core, - "%s: lv1_gpu_context_attribute failed: %d\n", __func__, + "%s: lv1_gpu_context_allocate failed: %d\n", __func__, status); goto err_gpu_memory_free; } /* vsync interrupt */ - ps3fb.dinfo = (void __force *)ioremap(lpar_driver_info, 128 * 1024); - if (!ps3fb.dinfo) { + dinfo = (void __force *)ioremap(lpar_driver_info, 128 * 1024); + if (!dinfo) { dev_err(&dev->core, "%s: ioremap failed\n", __func__); goto err_gpu_context_free; } - retval = ps3fb_vsync_settings(ps3fb.dinfo, &dev->core); - if (retval) + ps3fb.dinfo = dinfo; + dev_dbg(&dev->core, "version_driver:%x\n", dinfo->version_driver); + dev_dbg(&dev->core, "irq outlet:%x\n", dinfo->irq.irq_outlet); + dev_dbg(&dev->core, "version_gpu: %x memory_size: %x ch: %x " + "core_freq: %d mem_freq:%d\n", dinfo->version_gpu, + dinfo->memory_size, dinfo->hardware_channel, + dinfo->nvcore_frequency/1000000, + dinfo->memory_frequency/1000000); + + if (dinfo->version_driver != GPU_DRIVER_INFO_VERSION) { + dev_err(&dev->core, "%s: version_driver err:%x\n", __func__, + dinfo->version_driver); + retval = -EINVAL; goto err_iounmap_dinfo; + } + + retval = ps3_irq_plug_setup(PS3_BINDING_CPU_ANY, dinfo->irq.irq_outlet, + &ps3fb.irq_no); + if (retval) { + dev_err(&dev->core, "%s: ps3_alloc_irq failed %d\n", __func__, + retval); + goto err_iounmap_dinfo; + } + + retval = request_irq(ps3fb.irq_no, ps3fb_vsync_interrupt, + IRQF_DISABLED, DEVICE_NAME, &dev->core); + if (retval) { + dev_err(&dev->core, "%s: request_irq failed %d\n", __func__, + retval); + goto err_destroy_plug; + } + + dinfo->irq.mask = (1 << GPU_INTR_STATUS_VSYNC_1) | + (1 << GPU_INTR_STATUS_FLIP_1); /* Clear memory to prevent kernel info leakage into userspace */ memset(ps3fb_videomemory.address, 0, ps3fb_videomemory.size); xdr_lpar = ps3_mm_phys_to_lpar(__pa(ps3fb_videomemory.address)); - retval = ps3fb_xdr_settings(xdr_lpar, &dev->core); - if (retval) + + status = lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF, + xdr_lpar, ps3fb_videomemory.size, + CBE_IOPTE_PP_W | CBE_IOPTE_PP_R | + CBE_IOPTE_M); + if (status) { + dev_err(&dev->core, "%s: lv1_gpu_context_iomap failed: %d\n", + __func__, status); + retval = -ENXIO; goto err_free_irq; + } + + dev_dbg(&dev->core, "video:%p ioif:%lx lpar:%llx size:%lx\n", + ps3fb_videomemory.address, GPU_IOIF, xdr_lpar, + ps3fb_videomemory.size); + + status = lv1_gpu_fb_setup(ps3fb.context_handle, xdr_lpar, + GPU_CMD_BUF_SIZE, GPU_IOIF); + if (status) { + dev_err(&dev->core, "%s: lv1_gpu_fb_setup failed: %d\n", + __func__, status); + retval = -ENXIO; + goto err_context_unmap; + } info = framebuffer_alloc(sizeof(struct ps3fb_par), &dev->core); if (!info) - goto err_free_irq; + goto err_context_fb_close; par = info->par; par->mode_id = ~ps3fb_mode; /* != ps3fb_mode, to trigger change */ @@ -1210,7 +1166,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) if (retval < 0) goto err_fb_dealloc; - dev->core.driver_data = info; + ps3_system_bus_set_drvdata(dev, info); dev_info(info->device, "%s %s, using %u KiB of video memory\n", dev_driver_string(info->dev), dev_name(info->dev), @@ -1232,8 +1188,14 @@ err_fb_dealloc: fb_dealloc_cmap(&info->cmap); err_framebuffer_release: framebuffer_release(info); +err_context_fb_close: + lv1_gpu_fb_close(ps3fb.context_handle); +err_context_unmap: + lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF, xdr_lpar, + ps3fb_videomemory.size, CBE_IOPTE_M); err_free_irq: free_irq(ps3fb.irq_no, &dev->core); +err_destroy_plug: ps3_irq_plug_destroy(ps3fb.irq_no); err_iounmap_dinfo: iounmap((u8 __force __iomem *)ps3fb.dinfo); @@ -1241,14 +1203,16 @@ err_gpu_context_free: lv1_gpu_context_free(ps3fb.context_handle); err_gpu_memory_free: lv1_gpu_memory_free(ps3fb.memory_handle); +err_close_device: + ps3_close_hv_device(dev); err: return retval; } static int ps3fb_shutdown(struct ps3_system_bus_device *dev) { - int status; - struct fb_info *info = dev->core.driver_data; + struct fb_info *info = ps3_system_bus_get_drvdata(dev); + u64 xdr_lpar = ps3_mm_phys_to_lpar(__pa(ps3fb_videomemory.address)); dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__); @@ -1268,20 +1232,14 @@ static int ps3fb_shutdown(struct ps3_system_bus_device *dev) unregister_framebuffer(info); fb_dealloc_cmap(&info->cmap); framebuffer_release(info); - info = dev->core.driver_data = NULL; + ps3_system_bus_set_drvdata(dev, NULL); } iounmap((u8 __force __iomem *)ps3fb.dinfo); - - status = lv1_gpu_context_free(ps3fb.context_handle); - if (status) - dev_dbg(&dev->core, "lv1_gpu_context_free failed: %d\n", - status); - - status = lv1_gpu_memory_free(ps3fb.memory_handle); - if (status) - dev_dbg(&dev->core, "lv1_gpu_memory_free failed: %d\n", - status); - + lv1_gpu_fb_close(ps3fb.context_handle); + lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF, xdr_lpar, + ps3fb_videomemory.size, CBE_IOPTE_M); + lv1_gpu_context_free(ps3fb.context_handle); + lv1_gpu_memory_free(ps3fb.memory_handle); ps3_close_hv_device(dev); dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__); diff --git a/drivers/video/pxa168fb.c b/drivers/video/pxa168fb.c new file mode 100644 index 000000000000..84d8327e47db --- /dev/null +++ b/drivers/video/pxa168fb.c @@ -0,0 +1,803 @@ +/* + * linux/drivers/video/pxa168fb.c -- Marvell PXA168 LCD Controller + * + * Copyright (C) 2008 Marvell International Ltd. + * All rights reserved. + * + * 2009-02-16 adapted from original version for PXA168/910 + * Jun Nie + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include path/to/file. + */ +static char *link_target(const char *dir, const char *path, const char *ext) +{ + char *target; + char *old_ext; + char *copy; + + copy = kstrdup(path, GFP_KERNEL); + if (!copy) + return NULL; + old_ext = strrchr(copy, '.'); + if (old_ext) + *old_ext = '\0'; + if (dir) + target = kasprintf(GFP_KERNEL, "%s/%s.%s", dir, copy, ext); + else + target = kasprintf(GFP_KERNEL, "%s.%s", copy, ext); + kfree(copy); + + return target; +} + +/* + * Construct a string representing the symbolic link target for the given + * gcov data file name and link type. Depending on the link type and the + * location of the data file, the link target can either point to a + * subdirectory of srctree, objtree or in an external location. + */ +static char *get_link_target(const char *filename, const struct gcov_link *ext) +{ + const char *rel; + char *result; + + if (strncmp(filename, objtree, strlen(objtree)) == 0) { + rel = filename + strlen(objtree) + 1; + if (ext->dir == SRC_TREE) + result = link_target(srctree, rel, ext->ext); + else + result = link_target(objtree, rel, ext->ext); + } else { + /* External compilation. */ + result = link_target(NULL, filename, ext->ext); + } + + return result; +} + +#define SKEW_PREFIX ".tmp_" + +/* + * For a filename .tmp_filename.ext return filename.ext. Needed to compensate + * for filename skewing caused by the mod-versioning mechanism. + */ +static const char *deskew(const char *basename) +{ + if (strncmp(basename, SKEW_PREFIX, sizeof(SKEW_PREFIX) - 1) == 0) + return basename + sizeof(SKEW_PREFIX) - 1; + return basename; +} + +/* + * Create links to additional files (usually .c and .gcno files) which the + * gcov tool expects to find in the same directory as the gcov data file. + */ +static void add_links(struct gcov_node *node, struct dentry *parent) +{ + char *basename; + char *target; + int num; + int i; + + for (num = 0; gcov_link[num].ext; num++) + /* Nothing. */; + node->links = kcalloc(num, sizeof(struct dentry *), GFP_KERNEL); + if (!node->links) + return; + for (i = 0; i < num; i++) { + target = get_link_target(get_node_info(node)->filename, + &gcov_link[i]); + if (!target) + goto out_err; + basename = strrchr(target, '/'); + if (!basename) + goto out_err; + basename++; + node->links[i] = debugfs_create_symlink(deskew(basename), + parent, target); + if (!node->links[i]) + goto out_err; + kfree(target); + } + + return; +out_err: + kfree(target); + while (i-- > 0) + debugfs_remove(node->links[i]); + kfree(node->links); + node->links = NULL; +} + +static const struct file_operations gcov_data_fops = { + .open = gcov_seq_open, + .release = gcov_seq_release, + .read = seq_read, + .llseek = seq_lseek, + .write = gcov_seq_write, +}; + +/* Basic initialization of a new node. */ +static void init_node(struct gcov_node *node, struct gcov_info *info, + const char *name, struct gcov_node *parent) +{ + INIT_LIST_HEAD(&node->list); + INIT_LIST_HEAD(&node->children); + INIT_LIST_HEAD(&node->all); + node->info = info; + node->parent = parent; + if (name) + strcpy(node->name, name); +} + +/* + * Create a new node and associated debugfs entry. Needs to be called with + * node_lock held. + */ +static struct gcov_node *new_node(struct gcov_node *parent, + struct gcov_info *info, const char *name) +{ + struct gcov_node *node; + + node = kzalloc(sizeof(struct gcov_node) + strlen(name) + 1, GFP_KERNEL); + if (!node) { + pr_warning("out of memory\n"); + return NULL; + } + init_node(node, info, name, parent); + /* Differentiate between gcov data file nodes and directory nodes. */ + if (info) { + node->dentry = debugfs_create_file(deskew(node->name), 0600, + parent->dentry, node, &gcov_data_fops); + } else + node->dentry = debugfs_create_dir(node->name, parent->dentry); + if (!node->dentry) { + pr_warning("could not create file\n"); + kfree(node); + return NULL; + } + if (info) + add_links(node, parent->dentry); + list_add(&node->list, &parent->children); + list_add(&node->all, &all_head); + + return node; +} + +/* Remove symbolic links associated with node. */ +static void remove_links(struct gcov_node *node) +{ + int i; + + if (!node->links) + return; + for (i = 0; gcov_link[i].ext; i++) + debugfs_remove(node->links[i]); + kfree(node->links); + node->links = NULL; +} + +/* + * Remove node from all lists and debugfs and release associated resources. + * Needs to be called with node_lock held. + */ +static void release_node(struct gcov_node *node) +{ + list_del(&node->list); + list_del(&node->all); + debugfs_remove(node->dentry); + remove_links(node); + if (node->ghost) + gcov_info_free(node->ghost); + kfree(node); +} + +/* Release node and empty parents. Needs to be called with node_lock held. */ +static void remove_node(struct gcov_node *node) +{ + struct gcov_node *parent; + + while ((node != &root_node) && list_empty(&node->children)) { + parent = node->parent; + release_node(node); + node = parent; + } +} + +/* + * Find child node with given basename. Needs to be called with node_lock + * held. + */ +static struct gcov_node *get_child_by_name(struct gcov_node *parent, + const char *name) +{ + struct gcov_node *node; + + list_for_each_entry(node, &parent->children, list) { + if (strcmp(node->name, name) == 0) + return node; + } + + return NULL; +} + +/* + * write() implementation for reset file. Reset all profiling data to zero + * and remove ghost nodes. + */ +static ssize_t reset_write(struct file *file, const char __user *addr, + size_t len, loff_t *pos) +{ + struct gcov_node *node; + + mutex_lock(&node_lock); +restart: + list_for_each_entry(node, &all_head, all) { + if (node->info) + gcov_info_reset(node->info); + else if (list_empty(&node->children)) { + remove_node(node); + /* Several nodes may have gone - restart loop. */ + goto restart; + } + } + mutex_unlock(&node_lock); + + return len; +} + +/* read() implementation for reset file. Unused. */ +static ssize_t reset_read(struct file *file, char __user *addr, size_t len, + loff_t *pos) +{ + /* Allow read operation so that a recursive copy won't fail. */ + return 0; +} + +static const struct file_operations gcov_reset_fops = { + .write = reset_write, + .read = reset_read, +}; + +/* + * Create a node for a given profiling data set and add it to all lists and + * debugfs. Needs to be called with node_lock held. + */ +static void add_node(struct gcov_info *info) +{ + char *filename; + char *curr; + char *next; + struct gcov_node *parent; + struct gcov_node *node; + + filename = kstrdup(info->filename, GFP_KERNEL); + if (!filename) + return; + parent = &root_node; + /* Create directory nodes along the path. */ + for (curr = filename; (next = strchr(curr, '/')); curr = next + 1) { + if (curr == next) + continue; + *next = 0; + if (strcmp(curr, ".") == 0) + continue; + if (strcmp(curr, "..") == 0) { + if (!parent->parent) + goto err_remove; + parent = parent->parent; + continue; + } + node = get_child_by_name(parent, curr); + if (!node) { + node = new_node(parent, NULL, curr); + if (!node) + goto err_remove; + } + parent = node; + } + /* Create file node. */ + node = new_node(parent, info, curr); + if (!node) + goto err_remove; +out: + kfree(filename); + return; + +err_remove: + remove_node(parent); + goto out; +} + +/* + * The profiling data set associated with this node is being unloaded. Store a + * copy of the profiling data and turn this node into a "ghost". + */ +static int ghost_node(struct gcov_node *node) +{ + node->ghost = gcov_info_dup(node->info); + if (!node->ghost) { + pr_warning("could not save data for '%s' (out of memory)\n", + node->info->filename); + return -ENOMEM; + } + node->info = NULL; + + return 0; +} + +/* + * Profiling data for this node has been loaded again. Add profiling data + * from previous instantiation and turn this node into a regular node. + */ +static void revive_node(struct gcov_node *node, struct gcov_info *info) +{ + if (gcov_info_is_compatible(node->ghost, info)) + gcov_info_add(info, node->ghost); + else { + pr_warning("discarding saved data for '%s' (version changed)\n", + info->filename); + } + gcov_info_free(node->ghost); + node->ghost = NULL; + node->info = info; +} + +/* + * Callback to create/remove profiling files when code compiled with + * -fprofile-arcs is loaded/unloaded. + */ +void gcov_event(enum gcov_action action, struct gcov_info *info) +{ + struct gcov_node *node; + + mutex_lock(&node_lock); + node = get_node_by_name(info->filename); + switch (action) { + case GCOV_ADD: + /* Add new node or revive ghost. */ + if (!node) { + add_node(info); + break; + } + if (gcov_persist) + revive_node(node, info); + else { + pr_warning("could not add '%s' (already exists)\n", + info->filename); + } + break; + case GCOV_REMOVE: + /* Remove node or turn into ghost. */ + if (!node) { + pr_warning("could not remove '%s' (not found)\n", + info->filename); + break; + } + if (gcov_persist) { + if (!ghost_node(node)) + break; + } + remove_node(node); + break; + } + mutex_unlock(&node_lock); +} + +/* Create debugfs entries. */ +static __init int gcov_fs_init(void) +{ + int rc = -EIO; + + init_node(&root_node, NULL, NULL, NULL); + /* + * /sys/kernel/debug/gcov will be parent for the reset control file + * and all profiling files. + */ + root_node.dentry = debugfs_create_dir("gcov", NULL); + if (!root_node.dentry) + goto err_remove; + /* + * Create reset file which resets all profiling counts when written + * to. + */ + reset_dentry = debugfs_create_file("reset", 0600, root_node.dentry, + NULL, &gcov_reset_fops); + if (!reset_dentry) + goto err_remove; + /* Replay previous events to get our fs hierarchy up-to-date. */ + gcov_enable_events(); + return 0; + +err_remove: + pr_err("init failed\n"); + if (root_node.dentry) + debugfs_remove(root_node.dentry); + + return rc; +} +device_initcall(gcov_fs_init); diff --git a/kernel/gcov/gcc_3_4.c b/kernel/gcov/gcc_3_4.c new file mode 100644 index 000000000000..ae5bb4260033 --- /dev/null +++ b/kernel/gcov/gcc_3_4.c @@ -0,0 +1,447 @@ +/* + * This code provides functions to handle gcc's profiling data format + * introduced with gcc 3.4. Future versions of gcc may change the gcov + * format (as happened before), so all format-specific information needs + * to be kept modular and easily exchangeable. + * + * This file is based on gcc-internal definitions. Functions and data + * structures are defined to be compatible with gcc counterparts. + * For a better understanding, refer to gcc source: gcc/gcov-io.h. + * + * Copyright IBM Corp. 2009 + * Author(s): Peter Oberparleiter + * + * Uses gcc-internal data definitions. + */ + +#include +#include +#include +#include +#include +#include "gcov.h" + +/* Symbolic links to be created for each profiling data file. */ +const struct gcov_link gcov_link[] = { + { OBJ_TREE, "gcno" }, /* Link to .gcno file in $(objtree). */ + { 0, NULL}, +}; + +/* + * Determine whether a counter is active. Based on gcc magic. Doesn't change + * at run-time. + */ +static int counter_active(struct gcov_info *info, unsigned int type) +{ + return (1 << type) & info->ctr_mask; +} + +/* Determine number of active counters. Based on gcc magic. */ +static unsigned int num_counter_active(struct gcov_info *info) +{ + unsigned int i; + unsigned int result = 0; + + for (i = 0; i < GCOV_COUNTERS; i++) { + if (counter_active(info, i)) + result++; + } + return result; +} + +/** + * gcov_info_reset - reset profiling data to zero + * @info: profiling data set + */ +void gcov_info_reset(struct gcov_info *info) +{ + unsigned int active = num_counter_active(info); + unsigned int i; + + for (i = 0; i < active; i++) { + memset(info->counts[i].values, 0, + info->counts[i].num * sizeof(gcov_type)); + } +} + +/** + * gcov_info_is_compatible - check if profiling data can be added + * @info1: first profiling data set + * @info2: second profiling data set + * + * Returns non-zero if profiling data can be added, zero otherwise. + */ +int gcov_info_is_compatible(struct gcov_info *info1, struct gcov_info *info2) +{ + return (info1->stamp == info2->stamp); +} + +/** + * gcov_info_add - add up profiling data + * @dest: profiling data set to which data is added + * @source: profiling data set which is added + * + * Adds profiling counts of @source to @dest. + */ +void gcov_info_add(struct gcov_info *dest, struct gcov_info *source) +{ + unsigned int i; + unsigned int j; + + for (i = 0; i < num_counter_active(dest); i++) { + for (j = 0; j < dest->counts[i].num; j++) { + dest->counts[i].values[j] += + source->counts[i].values[j]; + } + } +} + +/* Get size of function info entry. Based on gcc magic. */ +static size_t get_fn_size(struct gcov_info *info) +{ + size_t size; + + size = sizeof(struct gcov_fn_info) + num_counter_active(info) * + sizeof(unsigned int); + if (__alignof__(struct gcov_fn_info) > sizeof(unsigned int)) + size = ALIGN(size, __alignof__(struct gcov_fn_info)); + return size; +} + +/* Get address of function info entry. Based on gcc magic. */ +static struct gcov_fn_info *get_fn_info(struct gcov_info *info, unsigned int fn) +{ + return (struct gcov_fn_info *) + ((char *) info->functions + fn * get_fn_size(info)); +} + +/** + * gcov_info_dup - duplicate profiling data set + * @info: profiling data set to duplicate + * + * Return newly allocated duplicate on success, %NULL on error. + */ +struct gcov_info *gcov_info_dup(struct gcov_info *info) +{ + struct gcov_info *dup; + unsigned int i; + unsigned int active; + + /* Duplicate gcov_info. */ + active = num_counter_active(info); + dup = kzalloc(sizeof(struct gcov_info) + + sizeof(struct gcov_ctr_info) * active, GFP_KERNEL); + if (!dup) + return NULL; + dup->version = info->version; + dup->stamp = info->stamp; + dup->n_functions = info->n_functions; + dup->ctr_mask = info->ctr_mask; + /* Duplicate filename. */ + dup->filename = kstrdup(info->filename, GFP_KERNEL); + if (!dup->filename) + goto err_free; + /* Duplicate table of functions. */ + dup->functions = kmemdup(info->functions, info->n_functions * + get_fn_size(info), GFP_KERNEL); + if (!dup->functions) + goto err_free; + /* Duplicate counter arrays. */ + for (i = 0; i < active ; i++) { + struct gcov_ctr_info *ctr = &info->counts[i]; + size_t size = ctr->num * sizeof(gcov_type); + + dup->counts[i].num = ctr->num; + dup->counts[i].merge = ctr->merge; + dup->counts[i].values = vmalloc(size); + if (!dup->counts[i].values) + goto err_free; + memcpy(dup->counts[i].values, ctr->values, size); + } + return dup; + +err_free: + gcov_info_free(dup); + return NULL; +} + +/** + * gcov_info_free - release memory for profiling data set duplicate + * @info: profiling data set duplicate to free + */ +void gcov_info_free(struct gcov_info *info) +{ + unsigned int active = num_counter_active(info); + unsigned int i; + + for (i = 0; i < active ; i++) + vfree(info->counts[i].values); + kfree(info->functions); + kfree(info->filename); + kfree(info); +} + +/** + * struct type_info - iterator helper array + * @ctr_type: counter type + * @offset: index of the first value of the current function for this type + * + * This array is needed to convert the in-memory data format into the in-file + * data format: + * + * In-memory: + * for each counter type + * for each function + * values + * + * In-file: + * for each function + * for each counter type + * values + * + * See gcc source gcc/gcov-io.h for more information on data organization. + */ +struct type_info { + int ctr_type; + unsigned int offset; +}; + +/** + * struct gcov_iterator - specifies current file position in logical records + * @info: associated profiling data + * @record: record type + * @function: function number + * @type: counter type + * @count: index into values array + * @num_types: number of counter types + * @type_info: helper array to get values-array offset for current function + */ +struct gcov_iterator { + struct gcov_info *info; + + int record; + unsigned int function; + unsigned int type; + unsigned int count; + + int num_types; + struct type_info type_info[0]; +}; + +static struct gcov_fn_info *get_func(struct gcov_iterator *iter) +{ + return get_fn_info(iter->info, iter->function); +} + +static struct type_info *get_type(struct gcov_iterator *iter) +{ + return &iter->type_info[iter->type]; +} + +/** + * gcov_iter_new - allocate and initialize profiling data iterator + * @info: profiling data set to be iterated + * + * Return file iterator on success, %NULL otherwise. + */ +struct gcov_iterator *gcov_iter_new(struct gcov_info *info) +{ + struct gcov_iterator *iter; + + iter = kzalloc(sizeof(struct gcov_iterator) + + num_counter_active(info) * sizeof(struct type_info), + GFP_KERNEL); + if (iter) + iter->info = info; + + return iter; +} + +/** + * gcov_iter_free - release memory for iterator + * @iter: file iterator to free + */ +void gcov_iter_free(struct gcov_iterator *iter) +{ + kfree(iter); +} + +/** + * gcov_iter_get_info - return profiling data set for given file iterator + * @iter: file iterator + */ +struct gcov_info *gcov_iter_get_info(struct gcov_iterator *iter) +{ + return iter->info; +} + +/** + * gcov_iter_start - reset file iterator to starting position + * @iter: file iterator + */ +void gcov_iter_start(struct gcov_iterator *iter) +{ + int i; + + iter->record = 0; + iter->function = 0; + iter->type = 0; + iter->count = 0; + iter->num_types = 0; + for (i = 0; i < GCOV_COUNTERS; i++) { + if (counter_active(iter->info, i)) { + iter->type_info[iter->num_types].ctr_type = i; + iter->type_info[iter->num_types++].offset = 0; + } + } +} + +/* Mapping of logical record number to actual file content. */ +#define RECORD_FILE_MAGIC 0 +#define RECORD_GCOV_VERSION 1 +#define RECORD_TIME_STAMP 2 +#define RECORD_FUNCTION_TAG 3 +#define RECORD_FUNCTON_TAG_LEN 4 +#define RECORD_FUNCTION_IDENT 5 +#define RECORD_FUNCTION_CHECK 6 +#define RECORD_COUNT_TAG 7 +#define RECORD_COUNT_LEN 8 +#define RECORD_COUNT 9 + +/** + * gcov_iter_next - advance file iterator to next logical record + * @iter: file iterator + * + * Return zero if new position is valid, non-zero if iterator has reached end. + */ +int gcov_iter_next(struct gcov_iterator *iter) +{ + switch (iter->record) { + case RECORD_FILE_MAGIC: + case RECORD_GCOV_VERSION: + case RECORD_FUNCTION_TAG: + case RECORD_FUNCTON_TAG_LEN: + case RECORD_FUNCTION_IDENT: + case RECORD_COUNT_TAG: + /* Advance to next record */ + iter->record++; + break; + case RECORD_COUNT: + /* Advance to next count */ + iter->count++; + /* fall through */ + case RECORD_COUNT_LEN: + if (iter->count < get_func(iter)->n_ctrs[iter->type]) { + iter->record = 9; + break; + } + /* Advance to next counter type */ + get_type(iter)->offset += iter->count; + iter->count = 0; + iter->type++; + /* fall through */ + case RECORD_FUNCTION_CHECK: + if (iter->type < iter->num_types) { + iter->record = 7; + break; + } + /* Advance to next function */ + iter->type = 0; + iter->function++; + /* fall through */ + case RECORD_TIME_STAMP: + if (iter->function < iter->info->n_functions) + iter->record = 3; + else + iter->record = -1; + break; + } + /* Check for EOF. */ + if (iter->record == -1) + return -EINVAL; + else + return 0; +} + +/** + * seq_write_gcov_u32 - write 32 bit number in gcov format to seq_file + * @seq: seq_file handle + * @v: value to be stored + * + * Number format defined by gcc: numbers are recorded in the 32 bit + * unsigned binary form of the endianness of the machine generating the + * file. + */ +static int seq_write_gcov_u32(struct seq_file *seq, u32 v) +{ + return seq_write(seq, &v, sizeof(v)); +} + +/** + * seq_write_gcov_u64 - write 64 bit number in gcov format to seq_file + * @seq: seq_file handle + * @v: value to be stored + * + * Number format defined by gcc: numbers are recorded in the 32 bit + * unsigned binary form of the endianness of the machine generating the + * file. 64 bit numbers are stored as two 32 bit numbers, the low part + * first. + */ +static int seq_write_gcov_u64(struct seq_file *seq, u64 v) +{ + u32 data[2]; + + data[0] = (v & 0xffffffffUL); + data[1] = (v >> 32); + return seq_write(seq, data, sizeof(data)); +} + +/** + * gcov_iter_write - write data for current pos to seq_file + * @iter: file iterator + * @seq: seq_file handle + * + * Return zero on success, non-zero otherwise. + */ +int gcov_iter_write(struct gcov_iterator *iter, struct seq_file *seq) +{ + int rc = -EINVAL; + + switch (iter->record) { + case RECORD_FILE_MAGIC: + rc = seq_write_gcov_u32(seq, GCOV_DATA_MAGIC); + break; + case RECORD_GCOV_VERSION: + rc = seq_write_gcov_u32(seq, iter->info->version); + break; + case RECORD_TIME_STAMP: + rc = seq_write_gcov_u32(seq, iter->info->stamp); + break; + case RECORD_FUNCTION_TAG: + rc = seq_write_gcov_u32(seq, GCOV_TAG_FUNCTION); + break; + case RECORD_FUNCTON_TAG_LEN: + rc = seq_write_gcov_u32(seq, 2); + break; + case RECORD_FUNCTION_IDENT: + rc = seq_write_gcov_u32(seq, get_func(iter)->ident); + break; + case RECORD_FUNCTION_CHECK: + rc = seq_write_gcov_u32(seq, get_func(iter)->checksum); + break; + case RECORD_COUNT_TAG: + rc = seq_write_gcov_u32(seq, + GCOV_TAG_FOR_COUNTER(get_type(iter)->ctr_type)); + break; + case RECORD_COUNT_LEN: + rc = seq_write_gcov_u32(seq, + get_func(iter)->n_ctrs[iter->type] * 2); + break; + case RECORD_COUNT: + rc = seq_write_gcov_u64(seq, + iter->info->counts[iter->type]. + values[iter->count + get_type(iter)->offset]); + break; + } + return rc; +} diff --git a/kernel/gcov/gcov.h b/kernel/gcov/gcov.h new file mode 100644 index 000000000000..060073ebf7a6 --- /dev/null +++ b/kernel/gcov/gcov.h @@ -0,0 +1,128 @@ +/* + * Profiling infrastructure declarations. + * + * This file is based on gcc-internal definitions. Data structures are + * defined to be compatible with gcc counterparts. For a better + * understanding, refer to gcc source: gcc/gcov-io.h. + * + * Copyright IBM Corp. 2009 + * Author(s): Peter Oberparleiter + * + * Uses gcc-internal data definitions. + */ + +#ifndef GCOV_H +#define GCOV_H GCOV_H + +#include + +/* + * Profiling data types used for gcc 3.4 and above - these are defined by + * gcc and need to be kept as close to the original definition as possible to + * remain compatible. + */ +#define GCOV_COUNTERS 5 +#define GCOV_DATA_MAGIC ((unsigned int) 0x67636461) +#define GCOV_TAG_FUNCTION ((unsigned int) 0x01000000) +#define GCOV_TAG_COUNTER_BASE ((unsigned int) 0x01a10000) +#define GCOV_TAG_FOR_COUNTER(count) \ + (GCOV_TAG_COUNTER_BASE + ((unsigned int) (count) << 17)) + +#if BITS_PER_LONG >= 64 +typedef long gcov_type; +#else +typedef long long gcov_type; +#endif + +/** + * struct gcov_fn_info - profiling meta data per function + * @ident: object file-unique function identifier + * @checksum: function checksum + * @n_ctrs: number of values per counter type belonging to this function + * + * This data is generated by gcc during compilation and doesn't change + * at run-time. + */ +struct gcov_fn_info { + unsigned int ident; + unsigned int checksum; + unsigned int n_ctrs[0]; +}; + +/** + * struct gcov_ctr_info - profiling data per counter type + * @num: number of counter values for this type + * @values: array of counter values for this type + * @merge: merge function for counter values of this type (unused) + * + * This data is generated by gcc during compilation and doesn't change + * at run-time with the exception of the values array. + */ +struct gcov_ctr_info { + unsigned int num; + gcov_type *values; + void (*merge)(gcov_type *, unsigned int); +}; + +/** + * struct gcov_info - profiling data per object file + * @version: gcov version magic indicating the gcc version used for compilation + * @next: list head for a singly-linked list + * @stamp: time stamp + * @filename: name of the associated gcov data file + * @n_functions: number of instrumented functions + * @functions: function data + * @ctr_mask: mask specifying which counter types are active + * @counts: counter data per counter type + * + * This data is generated by gcc during compilation and doesn't change + * at run-time with the exception of the next pointer. + */ +struct gcov_info { + unsigned int version; + struct gcov_info *next; + unsigned int stamp; + const char *filename; + unsigned int n_functions; + const struct gcov_fn_info *functions; + unsigned int ctr_mask; + struct gcov_ctr_info counts[0]; +}; + +/* Base interface. */ +enum gcov_action { + GCOV_ADD, + GCOV_REMOVE, +}; + +void gcov_event(enum gcov_action action, struct gcov_info *info); +void gcov_enable_events(void); + +/* Iterator control. */ +struct seq_file; +struct gcov_iterator; + +struct gcov_iterator *gcov_iter_new(struct gcov_info *info); +void gcov_iter_free(struct gcov_iterator *iter); +void gcov_iter_start(struct gcov_iterator *iter); +int gcov_iter_next(struct gcov_iterator *iter); +int gcov_iter_write(struct gcov_iterator *iter, struct seq_file *seq); +struct gcov_info *gcov_iter_get_info(struct gcov_iterator *iter); + +/* gcov_info control. */ +void gcov_info_reset(struct gcov_info *info); +int gcov_info_is_compatible(struct gcov_info *info1, struct gcov_info *info2); +void gcov_info_add(struct gcov_info *dest, struct gcov_info *source); +struct gcov_info *gcov_info_dup(struct gcov_info *info); +void gcov_info_free(struct gcov_info *info); + +struct gcov_link { + enum { + OBJ_TREE, + SRC_TREE, + } dir; + const char *ext; +}; +extern const struct gcov_link gcov_link[]; + +#endif /* GCOV_H */ diff --git a/kernel/groups.c b/kernel/groups.c new file mode 100644 index 000000000000..2b45b2ee3964 --- /dev/null +++ b/kernel/groups.c @@ -0,0 +1,288 @@ +/* + * Supplementary group IDs + */ +#include +#include +#include +#include +#include +#include + +/* init to 2 - one for init_task, one to ensure it is never freed */ +struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; + +struct group_info *groups_alloc(int gidsetsize) +{ + struct group_info *group_info; + int nblocks; + int i; + + nblocks = (gidsetsize + NGROUPS_PER_BLOCK - 1) / NGROUPS_PER_BLOCK; + /* Make sure we always allocate at least one indirect block pointer */ + nblocks = nblocks ? : 1; + group_info = kmalloc(sizeof(*group_info) + nblocks*sizeof(gid_t *), GFP_USER); + if (!group_info) + return NULL; + group_info->ngroups = gidsetsize; + group_info->nblocks = nblocks; + atomic_set(&group_info->usage, 1); + + if (gidsetsize <= NGROUPS_SMALL) + group_info->blocks[0] = group_info->small_block; + else { + for (i = 0; i < nblocks; i++) { + gid_t *b; + b = (void *)__get_free_page(GFP_USER); + if (!b) + goto out_undo_partial_alloc; + group_info->blocks[i] = b; + } + } + return group_info; + +out_undo_partial_alloc: + while (--i >= 0) { + free_page((unsigned long)group_info->blocks[i]); + } + kfree(group_info); + return NULL; +} + +EXPORT_SYMBOL(groups_alloc); + +void groups_free(struct group_info *group_info) +{ + if (group_info->blocks[0] != group_info->small_block) { + int i; + for (i = 0; i < group_info->nblocks; i++) + free_page((unsigned long)group_info->blocks[i]); + } + kfree(group_info); +} + +EXPORT_SYMBOL(groups_free); + +/* export the group_info to a user-space array */ +static int groups_to_user(gid_t __user *grouplist, + const struct group_info *group_info) +{ + int i; + unsigned int count = group_info->ngroups; + + for (i = 0; i < group_info->nblocks; i++) { + unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); + unsigned int len = cp_count * sizeof(*grouplist); + + if (copy_to_user(grouplist, group_info->blocks[i], len)) + return -EFAULT; + + grouplist += NGROUPS_PER_BLOCK; + count -= cp_count; + } + return 0; +} + +/* fill a group_info from a user-space array - it must be allocated already */ +static int groups_from_user(struct group_info *group_info, + gid_t __user *grouplist) +{ + int i; + unsigned int count = group_info->ngroups; + + for (i = 0; i < group_info->nblocks; i++) { + unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); + unsigned int len = cp_count * sizeof(*grouplist); + + if (copy_from_user(group_info->blocks[i], grouplist, len)) + return -EFAULT; + + grouplist += NGROUPS_PER_BLOCK; + count -= cp_count; + } + return 0; +} + +/* a simple Shell sort */ +static void groups_sort(struct group_info *group_info) +{ + int base, max, stride; + int gidsetsize = group_info->ngroups; + + for (stride = 1; stride < gidsetsize; stride = 3 * stride + 1) + ; /* nothing */ + stride /= 3; + + while (stride) { + max = gidsetsize - stride; + for (base = 0; base < max; base++) { + int left = base; + int right = left + stride; + gid_t tmp = GROUP_AT(group_info, right); + + while (left >= 0 && GROUP_AT(group_info, left) > tmp) { + GROUP_AT(group_info, right) = + GROUP_AT(group_info, left); + right = left; + left -= stride; + } + GROUP_AT(group_info, right) = tmp; + } + stride /= 3; + } +} + +/* a simple bsearch */ +int groups_search(const struct group_info *group_info, gid_t grp) +{ + unsigned int left, right; + + if (!group_info) + return 0; + + left = 0; + right = group_info->ngroups; + while (left < right) { + unsigned int mid = (left+right)/2; + int cmp = grp - GROUP_AT(group_info, mid); + if (cmp > 0) + left = mid + 1; + else if (cmp < 0) + right = mid; + else + return 1; + } + return 0; +} + +/** + * set_groups - Change a group subscription in a set of credentials + * @new: The newly prepared set of credentials to alter + * @group_info: The group list to install + * + * Validate a group subscription and, if valid, insert it into a set + * of credentials. + */ +int set_groups(struct cred *new, struct group_info *group_info) +{ + int retval; + + retval = security_task_setgroups(group_info); + if (retval) + return retval; + + put_group_info(new->group_info); + groups_sort(group_info); + get_group_info(group_info); + new->group_info = group_info; + return 0; +} + +EXPORT_SYMBOL(set_groups); + +/** + * set_current_groups - Change current's group subscription + * @group_info: The group list to impose + * + * Validate a group subscription and, if valid, impose it upon current's task + * security record. + */ +int set_current_groups(struct group_info *group_info) +{ + struct cred *new; + int ret; + + new = prepare_creds(); + if (!new) + return -ENOMEM; + + ret = set_groups(new, group_info); + if (ret < 0) { + abort_creds(new); + return ret; + } + + return commit_creds(new); +} + +EXPORT_SYMBOL(set_current_groups); + +SYSCALL_DEFINE2(getgroups, int, gidsetsize, gid_t __user *, grouplist) +{ + const struct cred *cred = current_cred(); + int i; + + if (gidsetsize < 0) + return -EINVAL; + + /* no need to grab task_lock here; it cannot change */ + i = cred->group_info->ngroups; + if (gidsetsize) { + if (i > gidsetsize) { + i = -EINVAL; + goto out; + } + if (groups_to_user(grouplist, cred->group_info)) { + i = -EFAULT; + goto out; + } + } +out: + return i; +} + +/* + * SMP: Our groups are copy-on-write. We can set them safely + * without another task interfering. + */ + +SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t __user *, grouplist) +{ + struct group_info *group_info; + int retval; + + if (!capable(CAP_SETGID)) + return -EPERM; + if ((unsigned)gidsetsize > NGROUPS_MAX) + return -EINVAL; + + group_info = groups_alloc(gidsetsize); + if (!group_info) + return -ENOMEM; + retval = groups_from_user(group_info, grouplist); + if (retval) { + put_group_info(group_info); + return retval; + } + + retval = set_current_groups(group_info); + put_group_info(group_info); + + return retval; +} + +/* + * Check whether we're fsgid/egid or in the supplemental group.. + */ +int in_group_p(gid_t grp) +{ + const struct cred *cred = current_cred(); + int retval = 1; + + if (grp != cred->fsgid) + retval = groups_search(cred->group_info, grp); + return retval; +} + +EXPORT_SYMBOL(in_group_p); + +int in_egroup_p(gid_t grp) +{ + const struct cred *cred = current_cred(); + int retval = 1; + + if (grp != cred->egid) + retval = groups_search(cred->group_info, grp); + return retval; +} + +EXPORT_SYMBOL(in_egroup_p); diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c index cb8a15c19583..9002958a96e7 100644 --- a/kernel/hrtimer.c +++ b/kernel/hrtimer.c @@ -43,6 +43,8 @@ #include #include #include +#include +#include #include @@ -193,12 +195,24 @@ struct hrtimer_clock_base *lock_hrtimer_base(const struct hrtimer *timer, * Switch the timer base to the current CPU when possible. */ static inline struct hrtimer_clock_base * -switch_hrtimer_base(struct hrtimer *timer, struct hrtimer_clock_base *base) +switch_hrtimer_base(struct hrtimer *timer, struct hrtimer_clock_base *base, + int pinned) { struct hrtimer_clock_base *new_base; struct hrtimer_cpu_base *new_cpu_base; + int cpu, preferred_cpu = -1; - new_cpu_base = &__get_cpu_var(hrtimer_bases); + cpu = smp_processor_id(); +#if defined(CONFIG_NO_HZ) && defined(CONFIG_SMP) + if (!pinned && get_sysctl_timer_migration() && idle_cpu(cpu)) { + preferred_cpu = get_nohz_load_balancer(); + if (preferred_cpu >= 0) + cpu = preferred_cpu; + } +#endif + +again: + new_cpu_base = &per_cpu(hrtimer_bases, cpu); new_base = &new_cpu_base->clock_base[base->index]; if (base != new_base) { @@ -218,6 +232,40 @@ switch_hrtimer_base(struct hrtimer *timer, struct hrtimer_clock_base *base) timer->base = NULL; spin_unlock(&base->cpu_base->lock); spin_lock(&new_base->cpu_base->lock); + + /* Optimized away for NOHZ=n SMP=n */ + if (cpu == preferred_cpu) { + /* Calculate clock monotonic expiry time */ +#ifdef CONFIG_HIGH_RES_TIMERS + ktime_t expires = ktime_sub(hrtimer_get_expires(timer), + new_base->offset); +#else + ktime_t expires = hrtimer_get_expires(timer); +#endif + + /* + * Get the next event on target cpu from the + * clock events layer. + * This covers the highres=off nohz=on case as well. + */ + ktime_t next = clockevents_get_next_event(cpu); + + ktime_t delta = ktime_sub(expires, next); + + /* + * We do not migrate the timer when it is expiring + * before the next event on the target cpu because + * we cannot reprogram the target cpu hardware and + * we would cause it to fire late. + */ + if (delta.tv64 < 0) { + cpu = smp_processor_id(); + spin_unlock(&new_base->cpu_base->lock); + spin_lock(&base->cpu_base->lock); + timer->base = base; + goto again; + } + } timer->base = new_base; } return new_base; @@ -235,7 +283,7 @@ lock_hrtimer_base(const struct hrtimer *timer, unsigned long *flags) return base; } -# define switch_hrtimer_base(t, b) (b) +# define switch_hrtimer_base(t, b, p) (b) #endif /* !CONFIG_SMP */ @@ -332,6 +380,8 @@ ktime_t ktime_add_safe(const ktime_t lhs, const ktime_t rhs) return res; } +EXPORT_SYMBOL_GPL(ktime_add_safe); + #ifdef CONFIG_DEBUG_OBJECTS_TIMERS static struct debug_obj_descr hrtimer_debug_descr; @@ -907,9 +957,9 @@ int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, ret = remove_hrtimer(timer, base); /* Switch the timer base, if necessary: */ - new_base = switch_hrtimer_base(timer, base); + new_base = switch_hrtimer_base(timer, base, mode & HRTIMER_MODE_PINNED); - if (mode == HRTIMER_MODE_REL) { + if (mode & HRTIMER_MODE_REL) { tim = ktime_add_safe(tim, new_base->get_time()); /* * CONFIG_TIME_LOW_RES is a temporary way for architectures diff --git a/kernel/irq/Makefile b/kernel/irq/Makefile index 3394f8f52964..7d047808419d 100644 --- a/kernel/irq/Makefile +++ b/kernel/irq/Makefile @@ -3,5 +3,5 @@ obj-y := handle.o manage.o spurious.o resend.o chip.o devres.o obj-$(CONFIG_GENERIC_IRQ_PROBE) += autoprobe.o obj-$(CONFIG_PROC_FS) += proc.o obj-$(CONFIG_GENERIC_PENDING_IRQ) += migration.o -obj-$(CONFIG_NUMA_MIGRATE_IRQ_DESC) += numa_migrate.o +obj-$(CONFIG_NUMA_IRQ_DESC) += numa_migrate.o obj-$(CONFIG_PM_SLEEP) += pm.o diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index c687ba4363f2..13c68e71b726 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -359,7 +359,6 @@ handle_level_irq(unsigned int irq, struct irq_desc *desc) spin_lock(&desc->lock); mask_ack_irq(desc, irq); - desc = irq_remap_to_desc(irq, desc); if (unlikely(desc->status & IRQ_INPROGRESS)) goto out_unlock; @@ -438,7 +437,6 @@ handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc) desc->status &= ~IRQ_INPROGRESS; out: desc->chip->eoi(irq); - desc = irq_remap_to_desc(irq, desc); spin_unlock(&desc->lock); } @@ -475,7 +473,6 @@ handle_edge_irq(unsigned int irq, struct irq_desc *desc) !desc->action)) { desc->status |= (IRQ_PENDING | IRQ_MASKED); mask_ack_irq(desc, irq); - desc = irq_remap_to_desc(irq, desc); goto out_unlock; } kstat_incr_irqs_this_cpu(irq, desc); @@ -483,7 +480,6 @@ handle_edge_irq(unsigned int irq, struct irq_desc *desc) /* Start handling the irq */ if (desc->chip->ack) desc->chip->ack(irq); - desc = irq_remap_to_desc(irq, desc); /* Mark the IRQ currently in progress.*/ desc->status |= IRQ_INPROGRESS; @@ -544,10 +540,8 @@ handle_percpu_irq(unsigned int irq, struct irq_desc *desc) if (!noirqdebug) note_interrupt(irq, desc, action_ret); - if (desc->chip->eoi) { + if (desc->chip->eoi) desc->chip->eoi(irq); - desc = irq_remap_to_desc(irq, desc); - } } void @@ -582,10 +576,8 @@ __set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained, /* Uninstall? */ if (handle == handle_bad_irq) { - if (desc->chip != &no_irq_chip) { + if (desc->chip != &no_irq_chip) mask_ack_irq(desc, irq); - desc = irq_remap_to_desc(irq, desc); - } desc->status |= IRQ_DISABLED; desc->depth = 1; } diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c index 26e08754744f..065205bdd920 100644 --- a/kernel/irq/handle.c +++ b/kernel/irq/handle.c @@ -11,14 +11,15 @@ */ #include +#include #include #include #include #include #include #include -#include #include +#include #include "internals.h" @@ -44,7 +45,7 @@ void handle_bad_irq(unsigned int irq, struct irq_desc *desc) #if defined(CONFIG_SMP) && defined(CONFIG_GENERIC_HARDIRQS) static void __init init_irq_default_affinity(void) { - alloc_bootmem_cpumask_var(&irq_default_affinity); + alloc_cpumask_var(&irq_default_affinity, GFP_NOWAIT); cpumask_setall(irq_default_affinity); } #else @@ -81,45 +82,48 @@ static struct irq_desc irq_desc_init = { .lock = __SPIN_LOCK_UNLOCKED(irq_desc_init.lock), }; -void init_kstat_irqs(struct irq_desc *desc, int cpu, int nr) +void __ref init_kstat_irqs(struct irq_desc *desc, int node, int nr) { - int node; void *ptr; - node = cpu_to_node(cpu); - ptr = kzalloc_node(nr * sizeof(*desc->kstat_irqs), GFP_ATOMIC, node); + if (slab_is_available()) + ptr = kzalloc_node(nr * sizeof(*desc->kstat_irqs), + GFP_ATOMIC, node); + else + ptr = alloc_bootmem_node(NODE_DATA(node), + nr * sizeof(*desc->kstat_irqs)); /* * don't overwite if can not get new one * init_copy_kstat_irqs() could still use old one */ if (ptr) { - printk(KERN_DEBUG " alloc kstat_irqs on cpu %d node %d\n", - cpu, node); + printk(KERN_DEBUG " alloc kstat_irqs on node %d\n", node); desc->kstat_irqs = ptr; } } -static void init_one_irq_desc(int irq, struct irq_desc *desc, int cpu) +static void init_one_irq_desc(int irq, struct irq_desc *desc, int node) { memcpy(desc, &irq_desc_init, sizeof(struct irq_desc)); spin_lock_init(&desc->lock); desc->irq = irq; #ifdef CONFIG_SMP - desc->cpu = cpu; + desc->node = node; #endif lockdep_set_class(&desc->lock, &irq_desc_lock_class); - init_kstat_irqs(desc, cpu, nr_cpu_ids); + init_kstat_irqs(desc, node, nr_cpu_ids); if (!desc->kstat_irqs) { printk(KERN_ERR "can not alloc kstat_irqs\n"); BUG_ON(1); } - if (!init_alloc_desc_masks(desc, cpu, false)) { + if (!alloc_desc_masks(desc, node, false)) { printk(KERN_ERR "can not alloc irq_desc cpumasks\n"); BUG_ON(1); } - arch_init_chip_data(desc, cpu); + init_desc_masks(desc); + arch_init_chip_data(desc, node); } /* @@ -146,6 +150,7 @@ int __init early_irq_init(void) { struct irq_desc *desc; int legacy_count; + int node; int i; init_irq_default_affinity(); @@ -156,20 +161,21 @@ int __init early_irq_init(void) desc = irq_desc_legacy; legacy_count = ARRAY_SIZE(irq_desc_legacy); + node = first_online_node; /* allocate irq_desc_ptrs array based on nr_irqs */ - irq_desc_ptrs = alloc_bootmem(nr_irqs * sizeof(void *)); + irq_desc_ptrs = kcalloc(nr_irqs, sizeof(void *), GFP_NOWAIT); /* allocate based on nr_cpu_ids */ - /* FIXME: invert kstat_irgs, and it'd be a per_cpu_alloc'd thing */ - kstat_irqs_legacy = alloc_bootmem(NR_IRQS_LEGACY * nr_cpu_ids * - sizeof(int)); + kstat_irqs_legacy = kzalloc_node(NR_IRQS_LEGACY * nr_cpu_ids * + sizeof(int), GFP_NOWAIT, node); for (i = 0; i < legacy_count; i++) { desc[i].irq = i; desc[i].kstat_irqs = kstat_irqs_legacy + i * nr_cpu_ids; lockdep_set_class(&desc[i].lock, &irq_desc_lock_class); - init_alloc_desc_masks(&desc[i], 0, true); + alloc_desc_masks(&desc[i], node, true); + init_desc_masks(&desc[i]); irq_desc_ptrs[i] = desc + i; } @@ -187,11 +193,10 @@ struct irq_desc *irq_to_desc(unsigned int irq) return NULL; } -struct irq_desc *irq_to_desc_alloc_cpu(unsigned int irq, int cpu) +struct irq_desc * __ref irq_to_desc_alloc_node(unsigned int irq, int node) { struct irq_desc *desc; unsigned long flags; - int node; if (irq >= nr_irqs) { WARN(1, "irq (%d) >= nr_irqs (%d) in irq_to_desc_alloc\n", @@ -210,15 +215,17 @@ struct irq_desc *irq_to_desc_alloc_cpu(unsigned int irq, int cpu) if (desc) goto out_unlock; - node = cpu_to_node(cpu); - desc = kzalloc_node(sizeof(*desc), GFP_ATOMIC, node); - printk(KERN_DEBUG " alloc irq_desc for %d on cpu %d node %d\n", - irq, cpu, node); + if (slab_is_available()) + desc = kzalloc_node(sizeof(*desc), GFP_ATOMIC, node); + else + desc = alloc_bootmem_node(NODE_DATA(node), sizeof(*desc)); + + printk(KERN_DEBUG " alloc irq_desc for %d on node %d\n", irq, node); if (!desc) { printk(KERN_ERR "can not alloc irq_desc\n"); BUG_ON(1); } - init_one_irq_desc(irq, desc, cpu); + init_one_irq_desc(irq, desc, node); irq_desc_ptrs[irq] = desc; @@ -256,7 +263,8 @@ int __init early_irq_init(void) for (i = 0; i < count; i++) { desc[i].irq = i; - init_alloc_desc_masks(&desc[i], 0, true); + alloc_desc_masks(&desc[i], 0, true); + init_desc_masks(&desc[i]); desc[i].kstat_irqs = kstat_irqs_all[i]; } return arch_early_irq_init(); @@ -267,7 +275,7 @@ struct irq_desc *irq_to_desc(unsigned int irq) return (irq < NR_IRQS) ? irq_desc + irq : NULL; } -struct irq_desc *irq_to_desc_alloc_cpu(unsigned int irq, int cpu) +struct irq_desc *irq_to_desc_alloc_node(unsigned int irq, int node) { return irq_to_desc(irq); } @@ -348,9 +356,6 @@ static void warn_no_thread(unsigned int irq, struct irqaction *action) "but no thread function available.", irq, action->name); } -DEFINE_TRACE(irq_handler_entry); -DEFINE_TRACE(irq_handler_exit); - /** * handle_IRQ_event - irq action chain handler * @irq: the interrupt number @@ -453,11 +458,8 @@ unsigned int __do_IRQ(unsigned int irq) /* * No locking required for CPU-local interrupts: */ - if (desc->chip->ack) { + if (desc->chip->ack) desc->chip->ack(irq); - /* get new one */ - desc = irq_remap_to_desc(irq, desc); - } if (likely(!(desc->status & IRQ_DISABLED))) { action_ret = handle_IRQ_event(irq, desc->action); if (!noirqdebug) @@ -468,10 +470,8 @@ unsigned int __do_IRQ(unsigned int irq) } spin_lock(&desc->lock); - if (desc->chip->ack) { + if (desc->chip->ack) desc->chip->ack(irq); - desc = irq_remap_to_desc(irq, desc); - } /* * REPLAY is when Linux resends an IRQ that was dropped earlier * WAITING is used by probe to mark irqs that are being tested diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h index 01ce20eab38f..73468253143b 100644 --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h @@ -16,7 +16,7 @@ extern void __disable_irq(struct irq_desc *desc, unsigned int irq, bool susp); extern void __enable_irq(struct irq_desc *desc, unsigned int irq, bool resume); extern struct lock_class_key irq_desc_lock_class; -extern void init_kstat_irqs(struct irq_desc *desc, int cpu, int nr); +extern void init_kstat_irqs(struct irq_desc *desc, int node, int nr); extern void clear_kstat_irqs(struct irq_desc *desc); extern spinlock_t sparse_irq_lock; @@ -42,6 +42,9 @@ static inline void unregister_handler_proc(unsigned int irq, extern int irq_select_affinity_usr(unsigned int irq); +extern void +irq_set_thread_affinity(struct irq_desc *desc, const struct cpumask *cpumask); + /* * Debugging printout: */ diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 2734eca59243..50da67672901 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -80,7 +80,7 @@ int irq_can_set_affinity(unsigned int irq) return 1; } -static void +void irq_set_thread_affinity(struct irq_desc *desc, const struct cpumask *cpumask) { struct irqaction *action = desc->action; @@ -109,17 +109,22 @@ int irq_set_affinity(unsigned int irq, const struct cpumask *cpumask) spin_lock_irqsave(&desc->lock, flags); #ifdef CONFIG_GENERIC_PENDING_IRQ - if (desc->status & IRQ_MOVE_PCNTXT) - desc->chip->set_affinity(irq, cpumask); + if (desc->status & IRQ_MOVE_PCNTXT) { + if (!desc->chip->set_affinity(irq, cpumask)) { + cpumask_copy(desc->affinity, cpumask); + irq_set_thread_affinity(desc, cpumask); + } + } else { desc->status |= IRQ_MOVE_PENDING; cpumask_copy(desc->pending_mask, cpumask); } #else - cpumask_copy(desc->affinity, cpumask); - desc->chip->set_affinity(irq, cpumask); + if (!desc->chip->set_affinity(irq, cpumask)) { + cpumask_copy(desc->affinity, cpumask); + irq_set_thread_affinity(desc, cpumask); + } #endif - irq_set_thread_affinity(desc, cpumask); desc->status |= IRQ_AFFINITY_SET; spin_unlock_irqrestore(&desc->lock, flags); return 0; @@ -851,7 +856,7 @@ EXPORT_SYMBOL(free_irq); * still called in hard interrupt context and has to check * whether the interrupt originates from the device. If yes it * needs to disable the interrupt on the device and return - * IRQ_THREAD_WAKE which will wake up the handler thread and run + * IRQ_WAKE_THREAD which will wake up the handler thread and run * @thread_fn. This split handler design is necessary to support * shared interrupts. * diff --git a/kernel/irq/migration.c b/kernel/irq/migration.c index e05ad9be43b7..cfe767ca1545 100644 --- a/kernel/irq/migration.c +++ b/kernel/irq/migration.c @@ -1,5 +1,8 @@ #include +#include + +#include "internals.h" void move_masked_irq(int irq) { @@ -39,11 +42,12 @@ void move_masked_irq(int irq) * masking the irqs. */ if (likely(cpumask_any_and(desc->pending_mask, cpu_online_mask) - < nr_cpu_ids)) { - cpumask_and(desc->affinity, - desc->pending_mask, cpu_online_mask); - desc->chip->set_affinity(irq, desc->affinity); - } + < nr_cpu_ids)) + if (!desc->chip->set_affinity(irq, desc->pending_mask)) { + cpumask_copy(desc->affinity, desc->pending_mask); + irq_set_thread_affinity(desc, desc->pending_mask); + } + cpumask_clear(desc->pending_mask); } diff --git a/kernel/irq/numa_migrate.c b/kernel/irq/numa_migrate.c index 44bbdcbaf8d2..2f69bee57bf2 100644 --- a/kernel/irq/numa_migrate.c +++ b/kernel/irq/numa_migrate.c @@ -15,9 +15,9 @@ static void init_copy_kstat_irqs(struct irq_desc *old_desc, struct irq_desc *desc, - int cpu, int nr) + int node, int nr) { - init_kstat_irqs(desc, cpu, nr); + init_kstat_irqs(desc, node, nr); if (desc->kstat_irqs != old_desc->kstat_irqs) memcpy(desc->kstat_irqs, old_desc->kstat_irqs, @@ -34,20 +34,20 @@ static void free_kstat_irqs(struct irq_desc *old_desc, struct irq_desc *desc) } static bool init_copy_one_irq_desc(int irq, struct irq_desc *old_desc, - struct irq_desc *desc, int cpu) + struct irq_desc *desc, int node) { memcpy(desc, old_desc, sizeof(struct irq_desc)); - if (!init_alloc_desc_masks(desc, cpu, false)) { + if (!alloc_desc_masks(desc, node, false)) { printk(KERN_ERR "irq %d: can not get new irq_desc cpumask " "for migration.\n", irq); return false; } spin_lock_init(&desc->lock); - desc->cpu = cpu; + desc->node = node; lockdep_set_class(&desc->lock, &irq_desc_lock_class); - init_copy_kstat_irqs(old_desc, desc, cpu, nr_cpu_ids); + init_copy_kstat_irqs(old_desc, desc, node, nr_cpu_ids); init_copy_desc_masks(old_desc, desc); - arch_init_copy_chip_data(old_desc, desc, cpu); + arch_init_copy_chip_data(old_desc, desc, node); return true; } @@ -59,12 +59,11 @@ static void free_one_irq_desc(struct irq_desc *old_desc, struct irq_desc *desc) } static struct irq_desc *__real_move_irq_desc(struct irq_desc *old_desc, - int cpu) + int node) { struct irq_desc *desc; unsigned int irq; unsigned long flags; - int node; irq = old_desc->irq; @@ -76,7 +75,6 @@ static struct irq_desc *__real_move_irq_desc(struct irq_desc *old_desc, if (desc && old_desc != desc) goto out_unlock; - node = cpu_to_node(cpu); desc = kzalloc_node(sizeof(*desc), GFP_ATOMIC, node); if (!desc) { printk(KERN_ERR "irq %d: can not get new irq_desc " @@ -85,7 +83,7 @@ static struct irq_desc *__real_move_irq_desc(struct irq_desc *old_desc, desc = old_desc; goto out_unlock; } - if (!init_copy_one_irq_desc(irq, old_desc, desc, cpu)) { + if (!init_copy_one_irq_desc(irq, old_desc, desc, node)) { /* still use old one */ kfree(desc); desc = old_desc; @@ -97,9 +95,7 @@ static struct irq_desc *__real_move_irq_desc(struct irq_desc *old_desc, /* free the old one */ free_one_irq_desc(old_desc, desc); - spin_unlock(&old_desc->lock); kfree(old_desc); - spin_lock(&desc->lock); return desc; @@ -109,24 +105,14 @@ out_unlock: return desc; } -struct irq_desc *move_irq_desc(struct irq_desc *desc, int cpu) +struct irq_desc *move_irq_desc(struct irq_desc *desc, int node) { - int old_cpu; - int node, old_node; - /* those all static, do move them */ if (desc->irq < NR_IRQS_LEGACY) return desc; - old_cpu = desc->cpu; - if (old_cpu != cpu) { - node = cpu_to_node(cpu); - old_node = cpu_to_node(old_cpu); - if (old_node != node) - desc = __real_move_irq_desc(desc, cpu); - else - desc->cpu = cpu; - } + if (desc->node != node) + desc = __real_move_irq_desc(desc, node); return desc; } diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c index 374faf9bfdc7..3a29dbe7898e 100644 --- a/kernel/kallsyms.c +++ b/kernel/kallsyms.c @@ -30,12 +30,16 @@ #define all_var 0 #endif -/* These will be re-linked against their real values during the second link stage */ +/* + * These will be re-linked against their real values + * during the second link stage. + */ extern const unsigned long kallsyms_addresses[] __attribute__((weak)); extern const u8 kallsyms_names[] __attribute__((weak)); -/* tell the compiler that the count isn't in the small data section if the arch - * has one (eg: FRV) +/* + * Tell the compiler that the count isn't in the small data section if the arch + * has one (eg: FRV). */ extern const unsigned long kallsyms_num_syms __attribute__((weak, section(".rodata"))); @@ -75,31 +79,37 @@ static int is_ksym_addr(unsigned long addr) return is_kernel_text(addr) || is_kernel_inittext(addr); } -/* expand a compressed symbol data into the resulting uncompressed string, - given the offset to where the symbol is in the compressed stream */ +/* + * Expand a compressed symbol data into the resulting uncompressed string, + * given the offset to where the symbol is in the compressed stream. + */ static unsigned int kallsyms_expand_symbol(unsigned int off, char *result) { int len, skipped_first = 0; const u8 *tptr, *data; - /* get the compressed symbol length from the first symbol byte */ + /* Get the compressed symbol length from the first symbol byte. */ data = &kallsyms_names[off]; len = *data; data++; - /* update the offset to return the offset for the next symbol on - * the compressed stream */ + /* + * Update the offset to return the offset for the next symbol on + * the compressed stream. + */ off += len + 1; - /* for every byte on the compressed symbol data, copy the table - entry for that byte */ - while(len) { - tptr = &kallsyms_token_table[ kallsyms_token_index[*data] ]; + /* + * For every byte on the compressed symbol data, copy the table + * entry for that byte. + */ + while (len) { + tptr = &kallsyms_token_table[kallsyms_token_index[*data]]; data++; len--; while (*tptr) { - if(skipped_first) { + if (skipped_first) { *result = *tptr; result++; } else @@ -110,36 +120,46 @@ static unsigned int kallsyms_expand_symbol(unsigned int off, char *result) *result = '\0'; - /* return to offset to the next symbol */ + /* Return to offset to the next symbol. */ return off; } -/* get symbol type information. This is encoded as a single char at the - * begining of the symbol name */ +/* + * Get symbol type information. This is encoded as a single char at the + * beginning of the symbol name. + */ static char kallsyms_get_symbol_type(unsigned int off) { - /* get just the first code, look it up in the token table, and return the - * first char from this token */ - return kallsyms_token_table[ kallsyms_token_index[ kallsyms_names[off+1] ] ]; + /* + * Get just the first code, look it up in the token table, + * and return the first char from this token. + */ + return kallsyms_token_table[kallsyms_token_index[kallsyms_names[off + 1]]]; } -/* find the offset on the compressed stream given and index in the - * kallsyms array */ +/* + * Find the offset on the compressed stream given and index in the + * kallsyms array. + */ static unsigned int get_symbol_offset(unsigned long pos) { const u8 *name; int i; - /* use the closest marker we have. We have markers every 256 positions, - * so that should be close enough */ - name = &kallsyms_names[ kallsyms_markers[pos>>8] ]; + /* + * Use the closest marker we have. We have markers every 256 positions, + * so that should be close enough. + */ + name = &kallsyms_names[kallsyms_markers[pos >> 8]]; - /* sequentially scan all the symbols up to the point we're searching for. - * Every symbol is stored in a [][ bytes of data] format, so we - * just need to add the len to the current pointer for every symbol we - * wish to skip */ - for(i = 0; i < (pos&0xFF); i++) + /* + * Sequentially scan all the symbols up to the point we're searching + * for. Every symbol is stored in a [][ bytes of data] format, + * so we just need to add the len to the current pointer for every + * symbol we wish to skip. + */ + for (i = 0; i < (pos & 0xFF); i++) name = name + (*name) + 1; return name - kallsyms_names; @@ -190,7 +210,7 @@ static unsigned long get_symbol_pos(unsigned long addr, /* This kernel should never had been booted. */ BUG_ON(!kallsyms_addresses); - /* do a binary search on the sorted kallsyms_addresses array */ + /* Do a binary search on the sorted kallsyms_addresses array. */ low = 0; high = kallsyms_num_syms; @@ -203,15 +223,15 @@ static unsigned long get_symbol_pos(unsigned long addr, } /* - * search for the first aliased symbol. Aliased - * symbols are symbols with the same address + * Search for the first aliased symbol. Aliased + * symbols are symbols with the same address. */ while (low && kallsyms_addresses[low-1] == kallsyms_addresses[low]) --low; symbol_start = kallsyms_addresses[low]; - /* Search for next non-aliased symbol */ + /* Search for next non-aliased symbol. */ for (i = low + 1; i < kallsyms_num_syms; i++) { if (kallsyms_addresses[i] > symbol_start) { symbol_end = kallsyms_addresses[i]; @@ -219,7 +239,7 @@ static unsigned long get_symbol_pos(unsigned long addr, } } - /* if we found no next symbol, we use the end of the section */ + /* If we found no next symbol, we use the end of the section. */ if (!symbol_end) { if (is_kernel_inittext(addr)) symbol_end = (unsigned long)_einittext; @@ -252,10 +272,10 @@ int kallsyms_lookup_size_offset(unsigned long addr, unsigned long *symbolsize, /* * Lookup an address - * - modname is set to NULL if it's in the kernel - * - we guarantee that the returned name is valid until we reschedule even if - * it resides in a module - * - we also guarantee that modname will be valid until rescheduled + * - modname is set to NULL if it's in the kernel. + * - We guarantee that the returned name is valid until we reschedule even if. + * It resides in a module. + * - We also guarantee that modname will be valid until rescheduled. */ const char *kallsyms_lookup(unsigned long addr, unsigned long *symbolsize, @@ -276,7 +296,7 @@ const char *kallsyms_lookup(unsigned long addr, return namebuf; } - /* see if it's in a module */ + /* See if it's in a module. */ return module_address_lookup(addr, symbolsize, offset, modname, namebuf); } @@ -294,7 +314,7 @@ int lookup_symbol_name(unsigned long addr, char *symname) kallsyms_expand_symbol(get_symbol_offset(pos), symname); return 0; } - /* see if it's in a module */ + /* See if it's in a module. */ return lookup_module_symbol_name(addr, symname); } @@ -313,7 +333,7 @@ int lookup_symbol_attrs(unsigned long addr, unsigned long *size, modname[0] = '\0'; return 0; } - /* see if it's in a module */ + /* See if it's in a module. */ return lookup_module_symbol_attrs(addr, size, offset, modname, name); } @@ -342,6 +362,7 @@ int sprint_symbol(char *buffer, unsigned long address) return len; } +EXPORT_SYMBOL_GPL(sprint_symbol); /* Look up a kernel symbol and print it to the kernel messages. */ void __print_symbol(const char *fmt, unsigned long address) @@ -352,13 +373,13 @@ void __print_symbol(const char *fmt, unsigned long address) printk(fmt, buffer); } +EXPORT_SYMBOL(__print_symbol); /* To avoid using get_symbol_offset for every symbol, we carry prefix along. */ -struct kallsym_iter -{ +struct kallsym_iter { loff_t pos; unsigned long value; - unsigned int nameoff; /* If iterating in core kernel symbols */ + unsigned int nameoff; /* If iterating in core kernel symbols. */ char type; char name[KSYM_NAME_LEN]; char module_name[MODULE_NAME_LEN]; @@ -404,7 +425,7 @@ static int update_iter(struct kallsym_iter *iter, loff_t pos) iter->pos = pos; return get_ksymbol_mod(iter); } - + /* If we're not on the desired position, reset to new position. */ if (pos != iter->pos) reset_iter(iter, pos); @@ -439,23 +460,25 @@ static int s_show(struct seq_file *m, void *p) { struct kallsym_iter *iter = m->private; - /* Some debugging symbols have no name. Ignore them. */ + /* Some debugging symbols have no name. Ignore them. */ if (!iter->name[0]) return 0; if (iter->module_name[0]) { char type; - /* Label it "global" if it is exported, - * "local" if not exported. */ + /* + * Label it "global" if it is exported, + * "local" if not exported. + */ type = iter->exported ? toupper(iter->type) : tolower(iter->type); seq_printf(m, "%0*lx %c %s\t[%s]\n", - (int)(2*sizeof(void*)), + (int)(2 * sizeof(void *)), iter->value, type, iter->name, iter->module_name); } else seq_printf(m, "%0*lx %c %s\n", - (int)(2*sizeof(void*)), + (int)(2 * sizeof(void *)), iter->value, iter->type, iter->name); return 0; } @@ -469,9 +492,11 @@ static const struct seq_operations kallsyms_op = { static int kallsyms_open(struct inode *inode, struct file *file) { - /* We keep iterator in m->private, since normal case is to + /* + * We keep iterator in m->private, since normal case is to * s_start from where we left off, so we avoid doing - * using get_symbol_offset for every symbol */ + * using get_symbol_offset for every symbol. + */ struct kallsym_iter *iter; int ret; @@ -500,7 +525,4 @@ static int __init kallsyms_init(void) proc_create("kallsyms", 0444, NULL, &kallsyms_operations); return 0; } -__initcall(kallsyms_init); - -EXPORT_SYMBOL(__print_symbol); -EXPORT_SYMBOL_GPL(sprint_symbol); +device_initcall(kallsyms_init); diff --git a/kernel/kexec.c b/kernel/kexec.c index e4983770913b..ae1c35201cc8 100644 --- a/kernel/kexec.c +++ b/kernel/kexec.c @@ -1448,17 +1448,17 @@ int kernel_kexec(void) goto Restore_console; } suspend_console(); - error = device_suspend(PMSG_FREEZE); + error = dpm_suspend_start(PMSG_FREEZE); if (error) goto Resume_console; - /* At this point, device_suspend() has been called, - * but *not* device_power_down(). We *must* - * device_power_down() now. Otherwise, drivers for + /* At this point, dpm_suspend_start() has been called, + * but *not* dpm_suspend_noirq(). We *must* call + * dpm_suspend_noirq() now. Otherwise, drivers for * some devices (e.g. interrupt controllers) become * desynchronized with the actual state of the * hardware at resume time, and evil weirdness ensues. */ - error = device_power_down(PMSG_FREEZE); + error = dpm_suspend_noirq(PMSG_FREEZE); if (error) goto Resume_devices; error = disable_nonboot_cpus(); @@ -1486,9 +1486,9 @@ int kernel_kexec(void) local_irq_enable(); Enable_cpus: enable_nonboot_cpus(); - device_power_up(PMSG_RESTORE); + dpm_resume_noirq(PMSG_RESTORE); Resume_devices: - device_resume(PMSG_RESTORE); + dpm_resume_end(PMSG_RESTORE); Resume_console: resume_console(); thaw_processes(); diff --git a/kernel/kfifo.c b/kernel/kfifo.c index bc41ad0f24f8..26539e3228e5 100644 --- a/kernel/kfifo.c +++ b/kernel/kfifo.c @@ -72,9 +72,9 @@ struct kfifo *kfifo_alloc(unsigned int size, gfp_t gfp_mask, spinlock_t *lock) /* * round up to the next power of 2, since our 'let the indices - * wrap' tachnique works only in this case. + * wrap' technique works only in this case. */ - if (size & (size - 1)) { + if (!is_power_of_2(size)) { BUG_ON(size > 0x80000000); size = roundup_pow_of_two(size); } diff --git a/kernel/kthread.c b/kernel/kthread.c index 4ebaf8519abf..9b1a7de26979 100644 --- a/kernel/kthread.c +++ b/kernel/kthread.c @@ -9,11 +9,12 @@ #include #include #include +#include #include #include #include #include -#include +#include #define KTHREAD_NICE_LEVEL (-5) @@ -21,15 +22,11 @@ static DEFINE_SPINLOCK(kthread_create_lock); static LIST_HEAD(kthread_create_list); struct task_struct *kthreadd_task; -DEFINE_TRACE(sched_kthread_stop); -DEFINE_TRACE(sched_kthread_stop_ret); - struct kthread_create_info { /* Information passed to kthread() from kthreadd. */ int (*threadfn)(void *data); void *data; - struct completion started; /* Result passed back to kthread_create() from kthreadd. */ struct task_struct *result; @@ -38,17 +35,13 @@ struct kthread_create_info struct list_head list; }; -struct kthread_stop_info -{ - struct task_struct *k; - int err; - struct completion done; +struct kthread { + int should_stop; + struct completion exited; }; -/* Thread stopping is done by setthing this var: lock serializes - * multiple kthread_stop calls. */ -static DEFINE_MUTEX(kthread_stop_lock); -static struct kthread_stop_info kthread_stop_info; +#define to_kthread(tsk) \ + container_of((tsk)->vfork_done, struct kthread, exited) /** * kthread_should_stop - should this kthread return now? @@ -59,36 +52,35 @@ static struct kthread_stop_info kthread_stop_info; */ int kthread_should_stop(void) { - return (kthread_stop_info.k == current); + return to_kthread(current)->should_stop; } EXPORT_SYMBOL(kthread_should_stop); static int kthread(void *_create) { - struct kthread_create_info *create = _create; - int (*threadfn)(void *data); - void *data; - int ret = -EINTR; - /* Copy data: it's on kthread's stack */ - threadfn = create->threadfn; - data = create->data; + struct kthread_create_info *create = _create; + int (*threadfn)(void *data) = create->threadfn; + void *data = create->data; + struct kthread self; + int ret; + + self.should_stop = 0; + init_completion(&self.exited); + current->vfork_done = &self.exited; /* OK, tell user we're spawned, wait for stop or wakeup */ __set_current_state(TASK_UNINTERRUPTIBLE); create->result = current; - complete(&create->started); + complete(&create->done); schedule(); - if (!kthread_should_stop()) + ret = -EINTR; + if (!self.should_stop) ret = threadfn(data); - /* It might have exited on its own, w/o kthread_stop. Check. */ - if (kthread_should_stop()) { - kthread_stop_info.err = ret; - complete(&kthread_stop_info.done); - } - return 0; + /* we can't just return, we must preserve "self" on stack */ + do_exit(ret); } static void create_kthread(struct kthread_create_info *create) @@ -97,11 +89,10 @@ static void create_kthread(struct kthread_create_info *create) /* We want our own signal handler (we take no signals by default). */ pid = kernel_thread(kthread, create, CLONE_FS | CLONE_FILES | SIGCHLD); - if (pid < 0) + if (pid < 0) { create->result = ERR_PTR(pid); - else - wait_for_completion(&create->started); - complete(&create->done); + complete(&create->done); + } } /** @@ -132,7 +123,6 @@ struct task_struct *kthread_create(int (*threadfn)(void *data), create.threadfn = threadfn; create.data = data; - init_completion(&create.started); init_completion(&create.done); spin_lock(&kthread_create_lock); @@ -200,30 +190,22 @@ EXPORT_SYMBOL(kthread_bind); */ int kthread_stop(struct task_struct *k) { + struct kthread *kthread; int ret; - mutex_lock(&kthread_stop_lock); - - /* It could exit after stop_info.k set, but before wake_up_process. */ + trace_sched_kthread_stop(k); get_task_struct(k); - trace_sched_kthread_stop(k); + kthread = to_kthread(k); + barrier(); /* it might have exited */ + if (k->vfork_done != NULL) { + kthread->should_stop = 1; + wake_up_process(k); + wait_for_completion(&kthread->exited); + } + ret = k->exit_code; - /* Must init completion *before* thread sees kthread_stop_info.k */ - init_completion(&kthread_stop_info.done); - smp_wmb(); - - /* Now set kthread_should_stop() to true, and wake it up. */ - kthread_stop_info.k = k; - wake_up_process(k); put_task_struct(k); - - /* Once it dies, reset stop ptr, gather result and we're done. */ - wait_for_completion(&kthread_stop_info.done); - kthread_stop_info.k = NULL; - ret = kthread_stop_info.err; - mutex_unlock(&kthread_stop_lock); - trace_sched_kthread_stop_ret(ret); return ret; @@ -239,6 +221,7 @@ int kthreadd(void *unused) ignore_signals(tsk); set_user_nice(tsk, KTHREAD_NICE_LEVEL); set_cpus_allowed_ptr(tsk, cpu_all_mask); + set_mems_allowed(node_possible_map); current->flags |= PF_NOFREEZE | PF_FREEZER_NOSIG; diff --git a/kernel/lockdep.c b/kernel/lockdep.c index accb40cdb12a..8bbeef996c76 100644 --- a/kernel/lockdep.c +++ b/kernel/lockdep.c @@ -42,12 +42,14 @@ #include #include #include -#include #include #include "lockdep_internals.h" +#define CREATE_TRACE_POINTS +#include + #ifdef CONFIG_PROVE_LOCKING int prove_locking = 1; module_param(prove_locking, int, 0644); @@ -2935,8 +2937,6 @@ void lock_set_class(struct lockdep_map *lock, const char *name, } EXPORT_SYMBOL_GPL(lock_set_class); -DEFINE_TRACE(lock_acquire); - /* * We are not always called with irqs disabled - do that here, * and also avoid lockdep recursion: @@ -2963,8 +2963,6 @@ void lock_acquire(struct lockdep_map *lock, unsigned int subclass, } EXPORT_SYMBOL_GPL(lock_acquire); -DEFINE_TRACE(lock_release); - void lock_release(struct lockdep_map *lock, int nested, unsigned long ip) { @@ -3105,6 +3103,8 @@ found_it: hlock->holdtime_stamp = now; } + trace_lock_acquired(lock, ip, waittime); + stats = get_lock_stats(hlock_class(hlock)); if (waittime) { if (hlock->read) @@ -3120,8 +3120,6 @@ found_it: lock->ip = ip; } -DEFINE_TRACE(lock_contended); - void lock_contended(struct lockdep_map *lock, unsigned long ip) { unsigned long flags; @@ -3143,14 +3141,10 @@ void lock_contended(struct lockdep_map *lock, unsigned long ip) } EXPORT_SYMBOL_GPL(lock_contended); -DEFINE_TRACE(lock_acquired); - void lock_acquired(struct lockdep_map *lock, unsigned long ip) { unsigned long flags; - trace_lock_acquired(lock, ip); - if (unlikely(!lock_stat)) return; diff --git a/kernel/module.c b/kernel/module.c index e797812a4d95..38928fcaff2b 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -18,6 +18,7 @@ */ #include #include +#include #include #include #include @@ -52,6 +53,7 @@ #include #include #include +#include #if 0 #define DEBUGP printk @@ -72,6 +74,9 @@ DEFINE_MUTEX(module_mutex); EXPORT_SYMBOL_GPL(module_mutex); static LIST_HEAD(modules); +/* Block module loading/unloading? */ +int modules_disabled = 0; + /* Waiting for a module to finish initializing? */ static DECLARE_WAIT_QUEUE_HEAD(module_wq); @@ -429,6 +434,7 @@ static void *percpu_modalloc(unsigned long size, unsigned long align, unsigned long extra; unsigned int i; void *ptr; + int cpu; if (align > PAGE_SIZE) { printk(KERN_WARNING "%s: per-cpu alignment %li > %li\n", @@ -458,6 +464,11 @@ static void *percpu_modalloc(unsigned long size, unsigned long align, if (!split_block(i, size)) return NULL; + /* add the per-cpu scanning areas */ + for_each_possible_cpu(cpu) + kmemleak_alloc(ptr + per_cpu_offset(cpu), size, 0, + GFP_KERNEL); + /* Mark allocated */ pcpu_size[i] = -pcpu_size[i]; return ptr; @@ -472,6 +483,7 @@ static void percpu_modfree(void *freeme) { unsigned int i; void *ptr = __per_cpu_start + block_size(pcpu_size[0]); + int cpu; /* First entry is core kernel percpu data. */ for (i = 1; i < pcpu_num_used; ptr += block_size(pcpu_size[i]), i++) { @@ -483,6 +495,10 @@ static void percpu_modfree(void *freeme) BUG(); free: + /* remove the per-cpu scanning areas */ + for_each_possible_cpu(cpu) + kmemleak_free(freeme + per_cpu_offset(cpu)); + /* Merge with previous? */ if (pcpu_size[i-1] >= 0) { pcpu_size[i-1] += pcpu_size[i]; @@ -777,7 +793,7 @@ SYSCALL_DEFINE2(delete_module, const char __user *, name_user, char name[MODULE_NAME_LEN]; int ret, forced = 0; - if (!capable(CAP_SYS_MODULE)) + if (!capable(CAP_SYS_MODULE) || modules_disabled) return -EPERM; if (strncpy_from_user(name, name_user, MODULE_NAME_LEN-1) < 0) @@ -1489,9 +1505,6 @@ static void free_module(struct module *mod) /* Free any allocated parameters. */ destroy_params(mod->kp, mod->num_kp); - /* release any pointers to mcount in this module */ - ftrace_release(mod->module_core, mod->core_size); - /* This may be NULL, but that's OK */ module_free(mod, mod->module_init); kfree(mod->args); @@ -1878,6 +1891,36 @@ static void *module_alloc_update_bounds(unsigned long size) return ret; } +#ifdef CONFIG_DEBUG_KMEMLEAK +static void kmemleak_load_module(struct module *mod, Elf_Ehdr *hdr, + Elf_Shdr *sechdrs, char *secstrings) +{ + unsigned int i; + + /* only scan the sections containing data */ + kmemleak_scan_area(mod->module_core, (unsigned long)mod - + (unsigned long)mod->module_core, + sizeof(struct module), GFP_KERNEL); + + for (i = 1; i < hdr->e_shnum; i++) { + if (!(sechdrs[i].sh_flags & SHF_ALLOC)) + continue; + if (strncmp(secstrings + sechdrs[i].sh_name, ".data", 5) != 0 + && strncmp(secstrings + sechdrs[i].sh_name, ".bss", 4) != 0) + continue; + + kmemleak_scan_area(mod->module_core, sechdrs[i].sh_addr - + (unsigned long)mod->module_core, + sechdrs[i].sh_size, GFP_KERNEL); + } +} +#else +static inline void kmemleak_load_module(struct module *mod, Elf_Ehdr *hdr, + Elf_Shdr *sechdrs, char *secstrings) +{ +} +#endif + /* Allocate and load the module: note that size of section 0 is always zero, and we rely on this for optional sections. */ static noinline struct module *load_module(void __user *umod, @@ -1892,11 +1935,9 @@ static noinline struct module *load_module(void __user *umod, unsigned int symindex = 0; unsigned int strindex = 0; unsigned int modindex, versindex, infoindex, pcpuindex; - unsigned int num_mcount; struct module *mod; long err = 0; void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */ - unsigned long *mseg; mm_segment_t old_fs; DEBUGP("load_module: umod=%p, len=%lu, uargs=%p\n", @@ -2050,6 +2091,12 @@ static noinline struct module *load_module(void __user *umod, /* Do the allocs. */ ptr = module_alloc_update_bounds(mod->core_size); + /* + * The pointer to this block is stored in the module structure + * which is inside the block. Just mark it as not being a + * leak. + */ + kmemleak_not_leak(ptr); if (!ptr) { err = -ENOMEM; goto free_percpu; @@ -2058,6 +2105,13 @@ static noinline struct module *load_module(void __user *umod, mod->module_core = ptr; ptr = module_alloc_update_bounds(mod->init_size); + /* + * The pointer to this block is stored in the module structure + * which is inside the block. This block doesn't need to be + * scanned as it contains data and code that will be freed + * after the module is initialized. + */ + kmemleak_ignore(ptr); if (!ptr && mod->init_size) { err = -ENOMEM; goto free_core; @@ -2088,6 +2142,7 @@ static noinline struct module *load_module(void __user *umod, } /* Module has been moved. */ mod = (void *)sechdrs[modindex].sh_addr; + kmemleak_load_module(mod, hdr, sechdrs, secstrings); #if defined(CONFIG_MODULE_UNLOAD) && defined(CONFIG_SMP) mod->refptr = percpu_modalloc(sizeof(local_t), __alignof__(local_t), @@ -2161,6 +2216,10 @@ static noinline struct module *load_module(void __user *umod, mod->unused_gpl_crcs = section_addr(hdr, sechdrs, secstrings, "__kcrctab_unused_gpl"); #endif +#ifdef CONFIG_CONSTRUCTORS + mod->ctors = section_objs(hdr, sechdrs, secstrings, ".ctors", + sizeof(*mod->ctors), &mod->num_ctors); +#endif #ifdef CONFIG_MARKERS mod->markers = section_objs(hdr, sechdrs, secstrings, "__markers", @@ -2172,7 +2231,19 @@ static noinline struct module *load_module(void __user *umod, sizeof(*mod->tracepoints), &mod->num_tracepoints); #endif - +#ifdef CONFIG_EVENT_TRACING + mod->trace_events = section_objs(hdr, sechdrs, secstrings, + "_ftrace_events", + sizeof(*mod->trace_events), + &mod->num_trace_events); +#endif +#ifdef CONFIG_FTRACE_MCOUNT_RECORD + /* sechdrs[0].sh_size is always zero */ + mod->ftrace_callsites = section_objs(hdr, sechdrs, secstrings, + "__mcount_loc", + sizeof(*mod->ftrace_callsites), + &mod->num_ftrace_callsites); +#endif #ifdef CONFIG_MODVERSIONS if ((mod->num_syms && !mod->crcs) || (mod->num_gpl_syms && !mod->gpl_crcs) @@ -2237,11 +2308,6 @@ static noinline struct module *load_module(void __user *umod, dynamic_debug_setup(debug, num_debug); } - /* sechdrs[0].sh_size is always zero */ - mseg = section_objs(hdr, sechdrs, secstrings, "__mcount_loc", - sizeof(*mseg), &num_mcount); - ftrace_init_module(mod, mseg, mseg + num_mcount); - err = module_finalize(hdr, sechdrs, mod); if (err < 0) goto cleanup; @@ -2302,7 +2368,6 @@ static noinline struct module *load_module(void __user *umod, cleanup: kobject_del(&mod->mkobj.kobj); kobject_put(&mod->mkobj.kobj); - ftrace_release(mod->module_core, mod->core_size); free_unload: module_unload_free(mod); #if defined(CONFIG_MODULE_UNLOAD) && defined(CONFIG_SMP) @@ -2328,6 +2393,17 @@ static noinline struct module *load_module(void __user *umod, goto free_hdr; } +/* Call module constructors. */ +static void do_mod_ctors(struct module *mod) +{ +#ifdef CONFIG_CONSTRUCTORS + unsigned long i; + + for (i = 0; i < mod->num_ctors; i++) + mod->ctors[i](); +#endif +} + /* This is where the real work happens */ SYSCALL_DEFINE3(init_module, void __user *, umod, unsigned long, len, const char __user *, uargs) @@ -2336,7 +2412,7 @@ SYSCALL_DEFINE3(init_module, void __user *, umod, int ret = 0; /* Must have permission */ - if (!capable(CAP_SYS_MODULE)) + if (!capable(CAP_SYS_MODULE) || modules_disabled) return -EPERM; /* Only one module load at a time, please */ @@ -2356,6 +2432,7 @@ SYSCALL_DEFINE3(init_module, void __user *, umod, blocking_notifier_call_chain(&module_notify_list, MODULE_STATE_COMING, mod); + do_mod_ctors(mod); /* Start the module */ if (mod->init != NULL) ret = do_one_initcall(mod->init); @@ -2394,6 +2471,7 @@ SYSCALL_DEFINE3(init_module, void __user *, umod, mutex_lock(&module_mutex); /* Drop initial reference. */ module_put(mod); + trim_init_extable(mod); module_free(mod, mod->module_init); mod->module_init = NULL; mod->init_size = 0; @@ -2837,7 +2915,7 @@ void print_modules(void) struct module *mod; char buf[8]; - printk("Modules linked in:"); + printk(KERN_DEFAULT "Modules linked in:"); /* Most callers should already have preempt disabled, but make sure */ preempt_disable(); list_for_each_entry_rcu(mod, &modules, list) diff --git a/kernel/mutex.c b/kernel/mutex.c index 507cf2b5e9f1..947b3ad551f8 100644 --- a/kernel/mutex.c +++ b/kernel/mutex.c @@ -89,7 +89,7 @@ __mutex_lock_slowpath(atomic_t *lock_count); * * This function is similar to (but not equivalent to) down(). */ -void inline __sched mutex_lock(struct mutex *lock) +void __sched mutex_lock(struct mutex *lock) { might_sleep(); /* @@ -249,7 +249,9 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass, /* didnt get the lock, go to sleep: */ spin_unlock_mutex(&lock->wait_lock, flags); - __schedule(); + preempt_enable_no_resched(); + schedule(); + preempt_disable(); spin_lock_mutex(&lock->wait_lock, flags); } @@ -471,5 +473,28 @@ int __sched mutex_trylock(struct mutex *lock) return ret; } - EXPORT_SYMBOL(mutex_trylock); + +/** + * atomic_dec_and_mutex_lock - return holding mutex if we dec to 0 + * @cnt: the atomic which we are to dec + * @lock: the mutex to return holding if we dec to 0 + * + * return true and hold lock if we dec to 0, return false otherwise + */ +int atomic_dec_and_mutex_lock(atomic_t *cnt, struct mutex *lock) +{ + /* dec if we can't possibly hit 0 */ + if (atomic_add_unless(cnt, -1, 1)) + return 0; + /* we might hit 0, so take the lock */ + mutex_lock(lock); + if (!atomic_dec_and_test(cnt)) { + /* when we actually did the dec, we didn't hit 0 */ + mutex_unlock(lock); + return 0; + } + /* we hit 0, and we hold the lock */ + return 1; +} +EXPORT_SYMBOL(atomic_dec_and_mutex_lock); diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c index 63598dca2d0c..09b4ff9711b2 100644 --- a/kernel/nsproxy.c +++ b/kernel/nsproxy.c @@ -26,19 +26,14 @@ static struct kmem_cache *nsproxy_cachep; struct nsproxy init_nsproxy = INIT_NSPROXY(init_nsproxy); -/* - * creates a copy of "orig" with refcount 1. - */ -static inline struct nsproxy *clone_nsproxy(struct nsproxy *orig) +static inline struct nsproxy *create_nsproxy(void) { - struct nsproxy *ns; + struct nsproxy *nsproxy; - ns = kmem_cache_alloc(nsproxy_cachep, GFP_KERNEL); - if (ns) { - memcpy(ns, orig, sizeof(struct nsproxy)); - atomic_set(&ns->count, 1); - } - return ns; + nsproxy = kmem_cache_alloc(nsproxy_cachep, GFP_KERNEL); + if (nsproxy) + atomic_set(&nsproxy->count, 1); + return nsproxy; } /* @@ -52,7 +47,7 @@ static struct nsproxy *create_new_namespaces(unsigned long flags, struct nsproxy *new_nsp; int err; - new_nsp = clone_nsproxy(tsk->nsproxy); + new_nsp = create_nsproxy(); if (!new_nsp) return ERR_PTR(-ENOMEM); diff --git a/kernel/params.c b/kernel/params.c index de273ec85bd2..7f6912ced2ba 100644 --- a/kernel/params.c +++ b/kernel/params.c @@ -24,9 +24,6 @@ #include #include -/* We abuse the high bits of "perm" to record whether we kmalloc'ed. */ -#define KPARAM_KMALLOCED 0x80000000 - #if 0 #define DEBUGP printk #else @@ -220,13 +217,13 @@ int param_set_charp(const char *val, struct kernel_param *kp) return -ENOSPC; } - if (kp->perm & KPARAM_KMALLOCED) + if (kp->flags & KPARAM_KMALLOCED) kfree(*(char **)kp->arg); /* This is a hack. We can't need to strdup in early boot, and we * don't need to; this mangled commandline is preserved. */ if (slab_is_available()) { - kp->perm |= KPARAM_KMALLOCED; + kp->flags |= KPARAM_KMALLOCED; *(char **)kp->arg = kstrdup(val, GFP_KERNEL); if (!kp->arg) return -ENOMEM; @@ -241,44 +238,63 @@ int param_get_charp(char *buffer, struct kernel_param *kp) return sprintf(buffer, "%s", *((char **)kp->arg)); } +/* Actually could be a bool or an int, for historical reasons. */ int param_set_bool(const char *val, struct kernel_param *kp) { + bool v; + /* No equals means "set"... */ if (!val) val = "1"; /* One of =[yYnN01] */ switch (val[0]) { case 'y': case 'Y': case '1': - *(int *)kp->arg = 1; - return 0; + v = true; + break; case 'n': case 'N': case '0': - *(int *)kp->arg = 0; - return 0; + v = false; + break; + default: + return -EINVAL; } - return -EINVAL; + + if (kp->flags & KPARAM_ISBOOL) + *(bool *)kp->arg = v; + else + *(int *)kp->arg = v; + return 0; } int param_get_bool(char *buffer, struct kernel_param *kp) { + bool val; + if (kp->flags & KPARAM_ISBOOL) + val = *(bool *)kp->arg; + else + val = *(int *)kp->arg; + /* Y and N chosen as being relatively non-coder friendly */ - return sprintf(buffer, "%c", (*(int *)kp->arg) ? 'Y' : 'N'); + return sprintf(buffer, "%c", val ? 'Y' : 'N'); } +/* This one must be bool. */ int param_set_invbool(const char *val, struct kernel_param *kp) { - int boolval, ret; + int ret; + bool boolval; struct kernel_param dummy; dummy.arg = &boolval; + dummy.flags = KPARAM_ISBOOL; ret = param_set_bool(val, &dummy); if (ret == 0) - *(int *)kp->arg = !boolval; + *(bool *)kp->arg = !boolval; return ret; } int param_get_invbool(char *buffer, struct kernel_param *kp) { - return sprintf(buffer, "%c", (*(int *)kp->arg) ? 'N' : 'Y'); + return sprintf(buffer, "%c", (*(bool *)kp->arg) ? 'N' : 'Y'); } /* We break the rule and mangle the string. */ @@ -591,7 +607,7 @@ void destroy_params(const struct kernel_param *params, unsigned num) unsigned int i; for (i = 0; i < num; i++) - if (params[i].perm & KPARAM_KMALLOCED) + if (params[i].flags & KPARAM_KMALLOCED) kfree(*(char **)params[i].arg); } diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c new file mode 100644 index 000000000000..1a933a221ea4 --- /dev/null +++ b/kernel/perf_counter.c @@ -0,0 +1,4383 @@ +/* + * Performance counter core code + * + * Copyright (C) 2008 Thomas Gleixner + * Copyright (C) 2008-2009 Red Hat, Inc., Ingo Molnar + * Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra + * Copyright © 2009 Paul Mackerras, IBM Corp. + * + * For licensing details see kernel-base/COPYING + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* + * Each CPU has a list of per CPU counters: + */ +DEFINE_PER_CPU(struct perf_cpu_context, perf_cpu_context); + +int perf_max_counters __read_mostly = 1; +static int perf_reserved_percpu __read_mostly; +static int perf_overcommit __read_mostly = 1; + +static atomic_t nr_counters __read_mostly; +static atomic_t nr_mmap_counters __read_mostly; +static atomic_t nr_comm_counters __read_mostly; + +/* + * perf counter paranoia level: + * 0 - not paranoid + * 1 - disallow cpu counters to unpriv + * 2 - disallow kernel profiling to unpriv + */ +int sysctl_perf_counter_paranoid __read_mostly; + +static inline bool perf_paranoid_cpu(void) +{ + return sysctl_perf_counter_paranoid > 0; +} + +static inline bool perf_paranoid_kernel(void) +{ + return sysctl_perf_counter_paranoid > 1; +} + +int sysctl_perf_counter_mlock __read_mostly = 512; /* 'free' kb per user */ + +/* + * max perf counter sample rate + */ +int sysctl_perf_counter_sample_rate __read_mostly = 100000; + +static atomic64_t perf_counter_id; + +/* + * Lock for (sysadmin-configurable) counter reservations: + */ +static DEFINE_SPINLOCK(perf_resource_lock); + +/* + * Architecture provided APIs - weak aliases: + */ +extern __weak const struct pmu *hw_perf_counter_init(struct perf_counter *counter) +{ + return NULL; +} + +void __weak hw_perf_disable(void) { barrier(); } +void __weak hw_perf_enable(void) { barrier(); } + +void __weak hw_perf_counter_setup(int cpu) { barrier(); } + +int __weak +hw_perf_group_sched_in(struct perf_counter *group_leader, + struct perf_cpu_context *cpuctx, + struct perf_counter_context *ctx, int cpu) +{ + return 0; +} + +void __weak perf_counter_print_debug(void) { } + +static DEFINE_PER_CPU(int, disable_count); + +void __perf_disable(void) +{ + __get_cpu_var(disable_count)++; +} + +bool __perf_enable(void) +{ + return !--__get_cpu_var(disable_count); +} + +void perf_disable(void) +{ + __perf_disable(); + hw_perf_disable(); +} + +void perf_enable(void) +{ + if (__perf_enable()) + hw_perf_enable(); +} + +static void get_ctx(struct perf_counter_context *ctx) +{ + WARN_ON(!atomic_inc_not_zero(&ctx->refcount)); +} + +static void free_ctx(struct rcu_head *head) +{ + struct perf_counter_context *ctx; + + ctx = container_of(head, struct perf_counter_context, rcu_head); + kfree(ctx); +} + +static void put_ctx(struct perf_counter_context *ctx) +{ + if (atomic_dec_and_test(&ctx->refcount)) { + if (ctx->parent_ctx) + put_ctx(ctx->parent_ctx); + if (ctx->task) + put_task_struct(ctx->task); + call_rcu(&ctx->rcu_head, free_ctx); + } +} + +/* + * Get the perf_counter_context for a task and lock it. + * This has to cope with with the fact that until it is locked, + * the context could get moved to another task. + */ +static struct perf_counter_context * +perf_lock_task_context(struct task_struct *task, unsigned long *flags) +{ + struct perf_counter_context *ctx; + + rcu_read_lock(); + retry: + ctx = rcu_dereference(task->perf_counter_ctxp); + if (ctx) { + /* + * If this context is a clone of another, it might + * get swapped for another underneath us by + * perf_counter_task_sched_out, though the + * rcu_read_lock() protects us from any context + * getting freed. Lock the context and check if it + * got swapped before we could get the lock, and retry + * if so. If we locked the right context, then it + * can't get swapped on us any more. + */ + spin_lock_irqsave(&ctx->lock, *flags); + if (ctx != rcu_dereference(task->perf_counter_ctxp)) { + spin_unlock_irqrestore(&ctx->lock, *flags); + goto retry; + } + + if (!atomic_inc_not_zero(&ctx->refcount)) { + spin_unlock_irqrestore(&ctx->lock, *flags); + ctx = NULL; + } + } + rcu_read_unlock(); + return ctx; +} + +/* + * Get the context for a task and increment its pin_count so it + * can't get swapped to another task. This also increments its + * reference count so that the context can't get freed. + */ +static struct perf_counter_context *perf_pin_task_context(struct task_struct *task) +{ + struct perf_counter_context *ctx; + unsigned long flags; + + ctx = perf_lock_task_context(task, &flags); + if (ctx) { + ++ctx->pin_count; + spin_unlock_irqrestore(&ctx->lock, flags); + } + return ctx; +} + +static void perf_unpin_context(struct perf_counter_context *ctx) +{ + unsigned long flags; + + spin_lock_irqsave(&ctx->lock, flags); + --ctx->pin_count; + spin_unlock_irqrestore(&ctx->lock, flags); + put_ctx(ctx); +} + +/* + * Add a counter from the lists for its context. + * Must be called with ctx->mutex and ctx->lock held. + */ +static void +list_add_counter(struct perf_counter *counter, struct perf_counter_context *ctx) +{ + struct perf_counter *group_leader = counter->group_leader; + + /* + * Depending on whether it is a standalone or sibling counter, + * add it straight to the context's counter list, or to the group + * leader's sibling list: + */ + if (group_leader == counter) + list_add_tail(&counter->list_entry, &ctx->counter_list); + else { + list_add_tail(&counter->list_entry, &group_leader->sibling_list); + group_leader->nr_siblings++; + } + + list_add_rcu(&counter->event_entry, &ctx->event_list); + ctx->nr_counters++; +} + +/* + * Remove a counter from the lists for its context. + * Must be called with ctx->mutex and ctx->lock held. + */ +static void +list_del_counter(struct perf_counter *counter, struct perf_counter_context *ctx) +{ + struct perf_counter *sibling, *tmp; + + if (list_empty(&counter->list_entry)) + return; + ctx->nr_counters--; + + list_del_init(&counter->list_entry); + list_del_rcu(&counter->event_entry); + + if (counter->group_leader != counter) + counter->group_leader->nr_siblings--; + + /* + * If this was a group counter with sibling counters then + * upgrade the siblings to singleton counters by adding them + * to the context list directly: + */ + list_for_each_entry_safe(sibling, tmp, + &counter->sibling_list, list_entry) { + + list_move_tail(&sibling->list_entry, &ctx->counter_list); + sibling->group_leader = sibling; + } +} + +static void +counter_sched_out(struct perf_counter *counter, + struct perf_cpu_context *cpuctx, + struct perf_counter_context *ctx) +{ + if (counter->state != PERF_COUNTER_STATE_ACTIVE) + return; + + counter->state = PERF_COUNTER_STATE_INACTIVE; + counter->tstamp_stopped = ctx->time; + counter->pmu->disable(counter); + counter->oncpu = -1; + + if (!is_software_counter(counter)) + cpuctx->active_oncpu--; + ctx->nr_active--; + if (counter->attr.exclusive || !cpuctx->active_oncpu) + cpuctx->exclusive = 0; +} + +static void +group_sched_out(struct perf_counter *group_counter, + struct perf_cpu_context *cpuctx, + struct perf_counter_context *ctx) +{ + struct perf_counter *counter; + + if (group_counter->state != PERF_COUNTER_STATE_ACTIVE) + return; + + counter_sched_out(group_counter, cpuctx, ctx); + + /* + * Schedule out siblings (if any): + */ + list_for_each_entry(counter, &group_counter->sibling_list, list_entry) + counter_sched_out(counter, cpuctx, ctx); + + if (group_counter->attr.exclusive) + cpuctx->exclusive = 0; +} + +/* + * Cross CPU call to remove a performance counter + * + * We disable the counter on the hardware level first. After that we + * remove it from the context list. + */ +static void __perf_counter_remove_from_context(void *info) +{ + struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context); + struct perf_counter *counter = info; + struct perf_counter_context *ctx = counter->ctx; + + /* + * If this is a task context, we need to check whether it is + * the current task context of this cpu. If not it has been + * scheduled out before the smp call arrived. + */ + if (ctx->task && cpuctx->task_ctx != ctx) + return; + + spin_lock(&ctx->lock); + /* + * Protect the list operation against NMI by disabling the + * counters on a global level. + */ + perf_disable(); + + counter_sched_out(counter, cpuctx, ctx); + + list_del_counter(counter, ctx); + + if (!ctx->task) { + /* + * Allow more per task counters with respect to the + * reservation: + */ + cpuctx->max_pertask = + min(perf_max_counters - ctx->nr_counters, + perf_max_counters - perf_reserved_percpu); + } + + perf_enable(); + spin_unlock(&ctx->lock); +} + + +/* + * Remove the counter from a task's (or a CPU's) list of counters. + * + * Must be called with ctx->mutex held. + * + * CPU counters are removed with a smp call. For task counters we only + * call when the task is on a CPU. + * + * If counter->ctx is a cloned context, callers must make sure that + * every task struct that counter->ctx->task could possibly point to + * remains valid. This is OK when called from perf_release since + * that only calls us on the top-level context, which can't be a clone. + * When called from perf_counter_exit_task, it's OK because the + * context has been detached from its task. + */ +static void perf_counter_remove_from_context(struct perf_counter *counter) +{ + struct perf_counter_context *ctx = counter->ctx; + struct task_struct *task = ctx->task; + + if (!task) { + /* + * Per cpu counters are removed via an smp call and + * the removal is always sucessful. + */ + smp_call_function_single(counter->cpu, + __perf_counter_remove_from_context, + counter, 1); + return; + } + +retry: + task_oncpu_function_call(task, __perf_counter_remove_from_context, + counter); + + spin_lock_irq(&ctx->lock); + /* + * If the context is active we need to retry the smp call. + */ + if (ctx->nr_active && !list_empty(&counter->list_entry)) { + spin_unlock_irq(&ctx->lock); + goto retry; + } + + /* + * The lock prevents that this context is scheduled in so we + * can remove the counter safely, if the call above did not + * succeed. + */ + if (!list_empty(&counter->list_entry)) { + list_del_counter(counter, ctx); + } + spin_unlock_irq(&ctx->lock); +} + +static inline u64 perf_clock(void) +{ + return cpu_clock(smp_processor_id()); +} + +/* + * Update the record of the current time in a context. + */ +static void update_context_time(struct perf_counter_context *ctx) +{ + u64 now = perf_clock(); + + ctx->time += now - ctx->timestamp; + ctx->timestamp = now; +} + +/* + * Update the total_time_enabled and total_time_running fields for a counter. + */ +static void update_counter_times(struct perf_counter *counter) +{ + struct perf_counter_context *ctx = counter->ctx; + u64 run_end; + + if (counter->state < PERF_COUNTER_STATE_INACTIVE) + return; + + counter->total_time_enabled = ctx->time - counter->tstamp_enabled; + + if (counter->state == PERF_COUNTER_STATE_INACTIVE) + run_end = counter->tstamp_stopped; + else + run_end = ctx->time; + + counter->total_time_running = run_end - counter->tstamp_running; +} + +/* + * Update total_time_enabled and total_time_running for all counters in a group. + */ +static void update_group_times(struct perf_counter *leader) +{ + struct perf_counter *counter; + + update_counter_times(leader); + list_for_each_entry(counter, &leader->sibling_list, list_entry) + update_counter_times(counter); +} + +/* + * Cross CPU call to disable a performance counter + */ +static void __perf_counter_disable(void *info) +{ + struct perf_counter *counter = info; + struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context); + struct perf_counter_context *ctx = counter->ctx; + + /* + * If this is a per-task counter, need to check whether this + * counter's task is the current task on this cpu. + */ + if (ctx->task && cpuctx->task_ctx != ctx) + return; + + spin_lock(&ctx->lock); + + /* + * If the counter is on, turn it off. + * If it is in error state, leave it in error state. + */ + if (counter->state >= PERF_COUNTER_STATE_INACTIVE) { + update_context_time(ctx); + update_counter_times(counter); + if (counter == counter->group_leader) + group_sched_out(counter, cpuctx, ctx); + else + counter_sched_out(counter, cpuctx, ctx); + counter->state = PERF_COUNTER_STATE_OFF; + } + + spin_unlock(&ctx->lock); +} + +/* + * Disable a counter. + * + * If counter->ctx is a cloned context, callers must make sure that + * every task struct that counter->ctx->task could possibly point to + * remains valid. This condition is satisifed when called through + * perf_counter_for_each_child or perf_counter_for_each because they + * hold the top-level counter's child_mutex, so any descendant that + * goes to exit will block in sync_child_counter. + * When called from perf_pending_counter it's OK because counter->ctx + * is the current context on this CPU and preemption is disabled, + * hence we can't get into perf_counter_task_sched_out for this context. + */ +static void perf_counter_disable(struct perf_counter *counter) +{ + struct perf_counter_context *ctx = counter->ctx; + struct task_struct *task = ctx->task; + + if (!task) { + /* + * Disable the counter on the cpu that it's on + */ + smp_call_function_single(counter->cpu, __perf_counter_disable, + counter, 1); + return; + } + + retry: + task_oncpu_function_call(task, __perf_counter_disable, counter); + + spin_lock_irq(&ctx->lock); + /* + * If the counter is still active, we need to retry the cross-call. + */ + if (counter->state == PERF_COUNTER_STATE_ACTIVE) { + spin_unlock_irq(&ctx->lock); + goto retry; + } + + /* + * Since we have the lock this context can't be scheduled + * in, so we can change the state safely. + */ + if (counter->state == PERF_COUNTER_STATE_INACTIVE) { + update_counter_times(counter); + counter->state = PERF_COUNTER_STATE_OFF; + } + + spin_unlock_irq(&ctx->lock); +} + +static int +counter_sched_in(struct perf_counter *counter, + struct perf_cpu_context *cpuctx, + struct perf_counter_context *ctx, + int cpu) +{ + if (counter->state <= PERF_COUNTER_STATE_OFF) + return 0; + + counter->state = PERF_COUNTER_STATE_ACTIVE; + counter->oncpu = cpu; /* TODO: put 'cpu' into cpuctx->cpu */ + /* + * The new state must be visible before we turn it on in the hardware: + */ + smp_wmb(); + + if (counter->pmu->enable(counter)) { + counter->state = PERF_COUNTER_STATE_INACTIVE; + counter->oncpu = -1; + return -EAGAIN; + } + + counter->tstamp_running += ctx->time - counter->tstamp_stopped; + + if (!is_software_counter(counter)) + cpuctx->active_oncpu++; + ctx->nr_active++; + + if (counter->attr.exclusive) + cpuctx->exclusive = 1; + + return 0; +} + +static int +group_sched_in(struct perf_counter *group_counter, + struct perf_cpu_context *cpuctx, + struct perf_counter_context *ctx, + int cpu) +{ + struct perf_counter *counter, *partial_group; + int ret; + + if (group_counter->state == PERF_COUNTER_STATE_OFF) + return 0; + + ret = hw_perf_group_sched_in(group_counter, cpuctx, ctx, cpu); + if (ret) + return ret < 0 ? ret : 0; + + if (counter_sched_in(group_counter, cpuctx, ctx, cpu)) + return -EAGAIN; + + /* + * Schedule in siblings as one group (if any): + */ + list_for_each_entry(counter, &group_counter->sibling_list, list_entry) { + if (counter_sched_in(counter, cpuctx, ctx, cpu)) { + partial_group = counter; + goto group_error; + } + } + + return 0; + +group_error: + /* + * Groups can be scheduled in as one unit only, so undo any + * partial group before returning: + */ + list_for_each_entry(counter, &group_counter->sibling_list, list_entry) { + if (counter == partial_group) + break; + counter_sched_out(counter, cpuctx, ctx); + } + counter_sched_out(group_counter, cpuctx, ctx); + + return -EAGAIN; +} + +/* + * Return 1 for a group consisting entirely of software counters, + * 0 if the group contains any hardware counters. + */ +static int is_software_only_group(struct perf_counter *leader) +{ + struct perf_counter *counter; + + if (!is_software_counter(leader)) + return 0; + + list_for_each_entry(counter, &leader->sibling_list, list_entry) + if (!is_software_counter(counter)) + return 0; + + return 1; +} + +/* + * Work out whether we can put this counter group on the CPU now. + */ +static int group_can_go_on(struct perf_counter *counter, + struct perf_cpu_context *cpuctx, + int can_add_hw) +{ + /* + * Groups consisting entirely of software counters can always go on. + */ + if (is_software_only_group(counter)) + return 1; + /* + * If an exclusive group is already on, no other hardware + * counters can go on. + */ + if (cpuctx->exclusive) + return 0; + /* + * If this group is exclusive and there are already + * counters on the CPU, it can't go on. + */ + if (counter->attr.exclusive && cpuctx->active_oncpu) + return 0; + /* + * Otherwise, try to add it if all previous groups were able + * to go on. + */ + return can_add_hw; +} + +static void add_counter_to_ctx(struct perf_counter *counter, + struct perf_counter_context *ctx) +{ + list_add_counter(counter, ctx); + counter->tstamp_enabled = ctx->time; + counter->tstamp_running = ctx->time; + counter->tstamp_stopped = ctx->time; +} + +/* + * Cross CPU call to install and enable a performance counter + * + * Must be called with ctx->mutex held + */ +static void __perf_install_in_context(void *info) +{ + struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context); + struct perf_counter *counter = info; + struct perf_counter_context *ctx = counter->ctx; + struct perf_counter *leader = counter->group_leader; + int cpu = smp_processor_id(); + int err; + + /* + * If this is a task context, we need to check whether it is + * the current task context of this cpu. If not it has been + * scheduled out before the smp call arrived. + * Or possibly this is the right context but it isn't + * on this cpu because it had no counters. + */ + if (ctx->task && cpuctx->task_ctx != ctx) { + if (cpuctx->task_ctx || ctx->task != current) + return; + cpuctx->task_ctx = ctx; + } + + spin_lock(&ctx->lock); + ctx->is_active = 1; + update_context_time(ctx); + + /* + * Protect the list operation against NMI by disabling the + * counters on a global level. NOP for non NMI based counters. + */ + perf_disable(); + + add_counter_to_ctx(counter, ctx); + + /* + * Don't put the counter on if it is disabled or if + * it is in a group and the group isn't on. + */ + if (counter->state != PERF_COUNTER_STATE_INACTIVE || + (leader != counter && leader->state != PERF_COUNTER_STATE_ACTIVE)) + goto unlock; + + /* + * An exclusive counter can't go on if there are already active + * hardware counters, and no hardware counter can go on if there + * is already an exclusive counter on. + */ + if (!group_can_go_on(counter, cpuctx, 1)) + err = -EEXIST; + else + err = counter_sched_in(counter, cpuctx, ctx, cpu); + + if (err) { + /* + * This counter couldn't go on. If it is in a group + * then we have to pull the whole group off. + * If the counter group is pinned then put it in error state. + */ + if (leader != counter) + group_sched_out(leader, cpuctx, ctx); + if (leader->attr.pinned) { + update_group_times(leader); + leader->state = PERF_COUNTER_STATE_ERROR; + } + } + + if (!err && !ctx->task && cpuctx->max_pertask) + cpuctx->max_pertask--; + + unlock: + perf_enable(); + + spin_unlock(&ctx->lock); +} + +/* + * Attach a performance counter to a context + * + * First we add the counter to the list with the hardware enable bit + * in counter->hw_config cleared. + * + * If the counter is attached to a task which is on a CPU we use a smp + * call to enable it in the task context. The task might have been + * scheduled away, but we check this in the smp call again. + * + * Must be called with ctx->mutex held. + */ +static void +perf_install_in_context(struct perf_counter_context *ctx, + struct perf_counter *counter, + int cpu) +{ + struct task_struct *task = ctx->task; + + if (!task) { + /* + * Per cpu counters are installed via an smp call and + * the install is always sucessful. + */ + smp_call_function_single(cpu, __perf_install_in_context, + counter, 1); + return; + } + +retry: + task_oncpu_function_call(task, __perf_install_in_context, + counter); + + spin_lock_irq(&ctx->lock); + /* + * we need to retry the smp call. + */ + if (ctx->is_active && list_empty(&counter->list_entry)) { + spin_unlock_irq(&ctx->lock); + goto retry; + } + + /* + * The lock prevents that this context is scheduled in so we + * can add the counter safely, if it the call above did not + * succeed. + */ + if (list_empty(&counter->list_entry)) + add_counter_to_ctx(counter, ctx); + spin_unlock_irq(&ctx->lock); +} + +/* + * Cross CPU call to enable a performance counter + */ +static void __perf_counter_enable(void *info) +{ + struct perf_counter *counter = info; + struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context); + struct perf_counter_context *ctx = counter->ctx; + struct perf_counter *leader = counter->group_leader; + int err; + + /* + * If this is a per-task counter, need to check whether this + * counter's task is the current task on this cpu. + */ + if (ctx->task && cpuctx->task_ctx != ctx) { + if (cpuctx->task_ctx || ctx->task != current) + return; + cpuctx->task_ctx = ctx; + } + + spin_lock(&ctx->lock); + ctx->is_active = 1; + update_context_time(ctx); + + if (counter->state >= PERF_COUNTER_STATE_INACTIVE) + goto unlock; + counter->state = PERF_COUNTER_STATE_INACTIVE; + counter->tstamp_enabled = ctx->time - counter->total_time_enabled; + + /* + * If the counter is in a group and isn't the group leader, + * then don't put it on unless the group is on. + */ + if (leader != counter && leader->state != PERF_COUNTER_STATE_ACTIVE) + goto unlock; + + if (!group_can_go_on(counter, cpuctx, 1)) { + err = -EEXIST; + } else { + perf_disable(); + if (counter == leader) + err = group_sched_in(counter, cpuctx, ctx, + smp_processor_id()); + else + err = counter_sched_in(counter, cpuctx, ctx, + smp_processor_id()); + perf_enable(); + } + + if (err) { + /* + * If this counter can't go on and it's part of a + * group, then the whole group has to come off. + */ + if (leader != counter) + group_sched_out(leader, cpuctx, ctx); + if (leader->attr.pinned) { + update_group_times(leader); + leader->state = PERF_COUNTER_STATE_ERROR; + } + } + + unlock: + spin_unlock(&ctx->lock); +} + +/* + * Enable a counter. + * + * If counter->ctx is a cloned context, callers must make sure that + * every task struct that counter->ctx->task could possibly point to + * remains valid. This condition is satisfied when called through + * perf_counter_for_each_child or perf_counter_for_each as described + * for perf_counter_disable. + */ +static void perf_counter_enable(struct perf_counter *counter) +{ + struct perf_counter_context *ctx = counter->ctx; + struct task_struct *task = ctx->task; + + if (!task) { + /* + * Enable the counter on the cpu that it's on + */ + smp_call_function_single(counter->cpu, __perf_counter_enable, + counter, 1); + return; + } + + spin_lock_irq(&ctx->lock); + if (counter->state >= PERF_COUNTER_STATE_INACTIVE) + goto out; + + /* + * If the counter is in error state, clear that first. + * That way, if we see the counter in error state below, we + * know that it has gone back into error state, as distinct + * from the task having been scheduled away before the + * cross-call arrived. + */ + if (counter->state == PERF_COUNTER_STATE_ERROR) + counter->state = PERF_COUNTER_STATE_OFF; + + retry: + spin_unlock_irq(&ctx->lock); + task_oncpu_function_call(task, __perf_counter_enable, counter); + + spin_lock_irq(&ctx->lock); + + /* + * If the context is active and the counter is still off, + * we need to retry the cross-call. + */ + if (ctx->is_active && counter->state == PERF_COUNTER_STATE_OFF) + goto retry; + + /* + * Since we have the lock this context can't be scheduled + * in, so we can change the state safely. + */ + if (counter->state == PERF_COUNTER_STATE_OFF) { + counter->state = PERF_COUNTER_STATE_INACTIVE; + counter->tstamp_enabled = + ctx->time - counter->total_time_enabled; + } + out: + spin_unlock_irq(&ctx->lock); +} + +static int perf_counter_refresh(struct perf_counter *counter, int refresh) +{ + /* + * not supported on inherited counters + */ + if (counter->attr.inherit) + return -EINVAL; + + atomic_add(refresh, &counter->event_limit); + perf_counter_enable(counter); + + return 0; +} + +void __perf_counter_sched_out(struct perf_counter_context *ctx, + struct perf_cpu_context *cpuctx) +{ + struct perf_counter *counter; + + spin_lock(&ctx->lock); + ctx->is_active = 0; + if (likely(!ctx->nr_counters)) + goto out; + update_context_time(ctx); + + perf_disable(); + if (ctx->nr_active) { + list_for_each_entry(counter, &ctx->counter_list, list_entry) { + if (counter != counter->group_leader) + counter_sched_out(counter, cpuctx, ctx); + else + group_sched_out(counter, cpuctx, ctx); + } + } + perf_enable(); + out: + spin_unlock(&ctx->lock); +} + +/* + * Test whether two contexts are equivalent, i.e. whether they + * have both been cloned from the same version of the same context + * and they both have the same number of enabled counters. + * If the number of enabled counters is the same, then the set + * of enabled counters should be the same, because these are both + * inherited contexts, therefore we can't access individual counters + * in them directly with an fd; we can only enable/disable all + * counters via prctl, or enable/disable all counters in a family + * via ioctl, which will have the same effect on both contexts. + */ +static int context_equiv(struct perf_counter_context *ctx1, + struct perf_counter_context *ctx2) +{ + return ctx1->parent_ctx && ctx1->parent_ctx == ctx2->parent_ctx + && ctx1->parent_gen == ctx2->parent_gen + && !ctx1->pin_count && !ctx2->pin_count; +} + +/* + * Called from scheduler to remove the counters of the current task, + * with interrupts disabled. + * + * We stop each counter and update the counter value in counter->count. + * + * This does not protect us against NMI, but disable() + * sets the disabled bit in the control field of counter _before_ + * accessing the counter control register. If a NMI hits, then it will + * not restart the counter. + */ +void perf_counter_task_sched_out(struct task_struct *task, + struct task_struct *next, int cpu) +{ + struct perf_cpu_context *cpuctx = &per_cpu(perf_cpu_context, cpu); + struct perf_counter_context *ctx = task->perf_counter_ctxp; + struct perf_counter_context *next_ctx; + struct perf_counter_context *parent; + struct pt_regs *regs; + int do_switch = 1; + + regs = task_pt_regs(task); + perf_swcounter_event(PERF_COUNT_SW_CONTEXT_SWITCHES, 1, 1, regs, 0); + + if (likely(!ctx || !cpuctx->task_ctx)) + return; + + update_context_time(ctx); + + rcu_read_lock(); + parent = rcu_dereference(ctx->parent_ctx); + next_ctx = next->perf_counter_ctxp; + if (parent && next_ctx && + rcu_dereference(next_ctx->parent_ctx) == parent) { + /* + * Looks like the two contexts are clones, so we might be + * able to optimize the context switch. We lock both + * contexts and check that they are clones under the + * lock (including re-checking that neither has been + * uncloned in the meantime). It doesn't matter which + * order we take the locks because no other cpu could + * be trying to lock both of these tasks. + */ + spin_lock(&ctx->lock); + spin_lock_nested(&next_ctx->lock, SINGLE_DEPTH_NESTING); + if (context_equiv(ctx, next_ctx)) { + /* + * XXX do we need a memory barrier of sorts + * wrt to rcu_dereference() of perf_counter_ctxp + */ + task->perf_counter_ctxp = next_ctx; + next->perf_counter_ctxp = ctx; + ctx->task = next; + next_ctx->task = task; + do_switch = 0; + } + spin_unlock(&next_ctx->lock); + spin_unlock(&ctx->lock); + } + rcu_read_unlock(); + + if (do_switch) { + __perf_counter_sched_out(ctx, cpuctx); + cpuctx->task_ctx = NULL; + } +} + +/* + * Called with IRQs disabled + */ +static void __perf_counter_task_sched_out(struct perf_counter_context *ctx) +{ + struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context); + + if (!cpuctx->task_ctx) + return; + + if (WARN_ON_ONCE(ctx != cpuctx->task_ctx)) + return; + + __perf_counter_sched_out(ctx, cpuctx); + cpuctx->task_ctx = NULL; +} + +/* + * Called with IRQs disabled + */ +static void perf_counter_cpu_sched_out(struct perf_cpu_context *cpuctx) +{ + __perf_counter_sched_out(&cpuctx->ctx, cpuctx); +} + +static void +__perf_counter_sched_in(struct perf_counter_context *ctx, + struct perf_cpu_context *cpuctx, int cpu) +{ + struct perf_counter *counter; + int can_add_hw = 1; + + spin_lock(&ctx->lock); + ctx->is_active = 1; + if (likely(!ctx->nr_counters)) + goto out; + + ctx->timestamp = perf_clock(); + + perf_disable(); + + /* + * First go through the list and put on any pinned groups + * in order to give them the best chance of going on. + */ + list_for_each_entry(counter, &ctx->counter_list, list_entry) { + if (counter->state <= PERF_COUNTER_STATE_OFF || + !counter->attr.pinned) + continue; + if (counter->cpu != -1 && counter->cpu != cpu) + continue; + + if (counter != counter->group_leader) + counter_sched_in(counter, cpuctx, ctx, cpu); + else { + if (group_can_go_on(counter, cpuctx, 1)) + group_sched_in(counter, cpuctx, ctx, cpu); + } + + /* + * If this pinned group hasn't been scheduled, + * put it in error state. + */ + if (counter->state == PERF_COUNTER_STATE_INACTIVE) { + update_group_times(counter); + counter->state = PERF_COUNTER_STATE_ERROR; + } + } + + list_for_each_entry(counter, &ctx->counter_list, list_entry) { + /* + * Ignore counters in OFF or ERROR state, and + * ignore pinned counters since we did them already. + */ + if (counter->state <= PERF_COUNTER_STATE_OFF || + counter->attr.pinned) + continue; + + /* + * Listen to the 'cpu' scheduling filter constraint + * of counters: + */ + if (counter->cpu != -1 && counter->cpu != cpu) + continue; + + if (counter != counter->group_leader) { + if (counter_sched_in(counter, cpuctx, ctx, cpu)) + can_add_hw = 0; + } else { + if (group_can_go_on(counter, cpuctx, can_add_hw)) { + if (group_sched_in(counter, cpuctx, ctx, cpu)) + can_add_hw = 0; + } + } + } + perf_enable(); + out: + spin_unlock(&ctx->lock); +} + +/* + * Called from scheduler to add the counters of the current task + * with interrupts disabled. + * + * We restore the counter value and then enable it. + * + * This does not protect us against NMI, but enable() + * sets the enabled bit in the control field of counter _before_ + * accessing the counter control register. If a NMI hits, then it will + * keep the counter running. + */ +void perf_counter_task_sched_in(struct task_struct *task, int cpu) +{ + struct perf_cpu_context *cpuctx = &per_cpu(perf_cpu_context, cpu); + struct perf_counter_context *ctx = task->perf_counter_ctxp; + + if (likely(!ctx)) + return; + if (cpuctx->task_ctx == ctx) + return; + __perf_counter_sched_in(ctx, cpuctx, cpu); + cpuctx->task_ctx = ctx; +} + +static void perf_counter_cpu_sched_in(struct perf_cpu_context *cpuctx, int cpu) +{ + struct perf_counter_context *ctx = &cpuctx->ctx; + + __perf_counter_sched_in(ctx, cpuctx, cpu); +} + +#define MAX_INTERRUPTS (~0ULL) + +static void perf_log_throttle(struct perf_counter *counter, int enable); +static void perf_log_period(struct perf_counter *counter, u64 period); + +static void perf_adjust_period(struct perf_counter *counter, u64 events) +{ + struct hw_perf_counter *hwc = &counter->hw; + u64 period, sample_period; + s64 delta; + + events *= hwc->sample_period; + period = div64_u64(events, counter->attr.sample_freq); + + delta = (s64)(period - hwc->sample_period); + delta = (delta + 7) / 8; /* low pass filter */ + + sample_period = hwc->sample_period + delta; + + if (!sample_period) + sample_period = 1; + + perf_log_period(counter, sample_period); + + hwc->sample_period = sample_period; +} + +static void perf_ctx_adjust_freq(struct perf_counter_context *ctx) +{ + struct perf_counter *counter; + struct hw_perf_counter *hwc; + u64 interrupts, freq; + + spin_lock(&ctx->lock); + list_for_each_entry(counter, &ctx->counter_list, list_entry) { + if (counter->state != PERF_COUNTER_STATE_ACTIVE) + continue; + + hwc = &counter->hw; + + interrupts = hwc->interrupts; + hwc->interrupts = 0; + + /* + * unthrottle counters on the tick + */ + if (interrupts == MAX_INTERRUPTS) { + perf_log_throttle(counter, 1); + counter->pmu->unthrottle(counter); + interrupts = 2*sysctl_perf_counter_sample_rate/HZ; + } + + if (!counter->attr.freq || !counter->attr.sample_freq) + continue; + + /* + * if the specified freq < HZ then we need to skip ticks + */ + if (counter->attr.sample_freq < HZ) { + freq = counter->attr.sample_freq; + + hwc->freq_count += freq; + hwc->freq_interrupts += interrupts; + + if (hwc->freq_count < HZ) + continue; + + interrupts = hwc->freq_interrupts; + hwc->freq_interrupts = 0; + hwc->freq_count -= HZ; + } else + freq = HZ; + + perf_adjust_period(counter, freq * interrupts); + + /* + * In order to avoid being stalled by an (accidental) huge + * sample period, force reset the sample period if we didn't + * get any events in this freq period. + */ + if (!interrupts) { + perf_disable(); + counter->pmu->disable(counter); + atomic64_set(&hwc->period_left, 0); + counter->pmu->enable(counter); + perf_enable(); + } + } + spin_unlock(&ctx->lock); +} + +/* + * Round-robin a context's counters: + */ +static void rotate_ctx(struct perf_counter_context *ctx) +{ + struct perf_counter *counter; + + if (!ctx->nr_counters) + return; + + spin_lock(&ctx->lock); + /* + * Rotate the first entry last (works just fine for group counters too): + */ + perf_disable(); + list_for_each_entry(counter, &ctx->counter_list, list_entry) { + list_move_tail(&counter->list_entry, &ctx->counter_list); + break; + } + perf_enable(); + + spin_unlock(&ctx->lock); +} + +void perf_counter_task_tick(struct task_struct *curr, int cpu) +{ + struct perf_cpu_context *cpuctx; + struct perf_counter_context *ctx; + + if (!atomic_read(&nr_counters)) + return; + + cpuctx = &per_cpu(perf_cpu_context, cpu); + ctx = curr->perf_counter_ctxp; + + perf_ctx_adjust_freq(&cpuctx->ctx); + if (ctx) + perf_ctx_adjust_freq(ctx); + + perf_counter_cpu_sched_out(cpuctx); + if (ctx) + __perf_counter_task_sched_out(ctx); + + rotate_ctx(&cpuctx->ctx); + if (ctx) + rotate_ctx(ctx); + + perf_counter_cpu_sched_in(cpuctx, cpu); + if (ctx) + perf_counter_task_sched_in(curr, cpu); +} + +/* + * Cross CPU call to read the hardware counter + */ +static void __read(void *info) +{ + struct perf_counter *counter = info; + struct perf_counter_context *ctx = counter->ctx; + unsigned long flags; + + local_irq_save(flags); + if (ctx->is_active) + update_context_time(ctx); + counter->pmu->read(counter); + update_counter_times(counter); + local_irq_restore(flags); +} + +static u64 perf_counter_read(struct perf_counter *counter) +{ + /* + * If counter is enabled and currently active on a CPU, update the + * value in the counter structure: + */ + if (counter->state == PERF_COUNTER_STATE_ACTIVE) { + smp_call_function_single(counter->oncpu, + __read, counter, 1); + } else if (counter->state == PERF_COUNTER_STATE_INACTIVE) { + update_counter_times(counter); + } + + return atomic64_read(&counter->count); +} + +/* + * Initialize the perf_counter context in a task_struct: + */ +static void +__perf_counter_init_context(struct perf_counter_context *ctx, + struct task_struct *task) +{ + memset(ctx, 0, sizeof(*ctx)); + spin_lock_init(&ctx->lock); + mutex_init(&ctx->mutex); + INIT_LIST_HEAD(&ctx->counter_list); + INIT_LIST_HEAD(&ctx->event_list); + atomic_set(&ctx->refcount, 1); + ctx->task = task; +} + +static struct perf_counter_context *find_get_context(pid_t pid, int cpu) +{ + struct perf_counter_context *parent_ctx; + struct perf_counter_context *ctx; + struct perf_cpu_context *cpuctx; + struct task_struct *task; + unsigned long flags; + int err; + + /* + * If cpu is not a wildcard then this is a percpu counter: + */ + if (cpu != -1) { + /* Must be root to operate on a CPU counter: */ + if (perf_paranoid_cpu() && !capable(CAP_SYS_ADMIN)) + return ERR_PTR(-EACCES); + + if (cpu < 0 || cpu > num_possible_cpus()) + return ERR_PTR(-EINVAL); + + /* + * We could be clever and allow to attach a counter to an + * offline CPU and activate it when the CPU comes up, but + * that's for later. + */ + if (!cpu_isset(cpu, cpu_online_map)) + return ERR_PTR(-ENODEV); + + cpuctx = &per_cpu(perf_cpu_context, cpu); + ctx = &cpuctx->ctx; + get_ctx(ctx); + + return ctx; + } + + rcu_read_lock(); + if (!pid) + task = current; + else + task = find_task_by_vpid(pid); + if (task) + get_task_struct(task); + rcu_read_unlock(); + + if (!task) + return ERR_PTR(-ESRCH); + + /* + * Can't attach counters to a dying task. + */ + err = -ESRCH; + if (task->flags & PF_EXITING) + goto errout; + + /* Reuse ptrace permission checks for now. */ + err = -EACCES; + if (!ptrace_may_access(task, PTRACE_MODE_READ)) + goto errout; + + retry: + ctx = perf_lock_task_context(task, &flags); + if (ctx) { + parent_ctx = ctx->parent_ctx; + if (parent_ctx) { + put_ctx(parent_ctx); + ctx->parent_ctx = NULL; /* no longer a clone */ + } + spin_unlock_irqrestore(&ctx->lock, flags); + } + + if (!ctx) { + ctx = kmalloc(sizeof(struct perf_counter_context), GFP_KERNEL); + err = -ENOMEM; + if (!ctx) + goto errout; + __perf_counter_init_context(ctx, task); + get_ctx(ctx); + if (cmpxchg(&task->perf_counter_ctxp, NULL, ctx)) { + /* + * We raced with some other task; use + * the context they set. + */ + kfree(ctx); + goto retry; + } + get_task_struct(task); + } + + put_task_struct(task); + return ctx; + + errout: + put_task_struct(task); + return ERR_PTR(err); +} + +static void free_counter_rcu(struct rcu_head *head) +{ + struct perf_counter *counter; + + counter = container_of(head, struct perf_counter, rcu_head); + if (counter->ns) + put_pid_ns(counter->ns); + kfree(counter); +} + +static void perf_pending_sync(struct perf_counter *counter); + +static void free_counter(struct perf_counter *counter) +{ + perf_pending_sync(counter); + + atomic_dec(&nr_counters); + if (counter->attr.mmap) + atomic_dec(&nr_mmap_counters); + if (counter->attr.comm) + atomic_dec(&nr_comm_counters); + + if (counter->destroy) + counter->destroy(counter); + + put_ctx(counter->ctx); + call_rcu(&counter->rcu_head, free_counter_rcu); +} + +/* + * Called when the last reference to the file is gone. + */ +static int perf_release(struct inode *inode, struct file *file) +{ + struct perf_counter *counter = file->private_data; + struct perf_counter_context *ctx = counter->ctx; + + file->private_data = NULL; + + WARN_ON_ONCE(ctx->parent_ctx); + mutex_lock(&ctx->mutex); + perf_counter_remove_from_context(counter); + mutex_unlock(&ctx->mutex); + + mutex_lock(&counter->owner->perf_counter_mutex); + list_del_init(&counter->owner_entry); + mutex_unlock(&counter->owner->perf_counter_mutex); + put_task_struct(counter->owner); + + free_counter(counter); + + return 0; +} + +/* + * Read the performance counter - simple non blocking version for now + */ +static ssize_t +perf_read_hw(struct perf_counter *counter, char __user *buf, size_t count) +{ + u64 values[4]; + int n; + + /* + * Return end-of-file for a read on a counter that is in + * error state (i.e. because it was pinned but it couldn't be + * scheduled on to the CPU at some point). + */ + if (counter->state == PERF_COUNTER_STATE_ERROR) + return 0; + + WARN_ON_ONCE(counter->ctx->parent_ctx); + mutex_lock(&counter->child_mutex); + values[0] = perf_counter_read(counter); + n = 1; + if (counter->attr.read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) + values[n++] = counter->total_time_enabled + + atomic64_read(&counter->child_total_time_enabled); + if (counter->attr.read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) + values[n++] = counter->total_time_running + + atomic64_read(&counter->child_total_time_running); + if (counter->attr.read_format & PERF_FORMAT_ID) + values[n++] = counter->id; + mutex_unlock(&counter->child_mutex); + + if (count < n * sizeof(u64)) + return -EINVAL; + count = n * sizeof(u64); + + if (copy_to_user(buf, values, count)) + return -EFAULT; + + return count; +} + +static ssize_t +perf_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) +{ + struct perf_counter *counter = file->private_data; + + return perf_read_hw(counter, buf, count); +} + +static unsigned int perf_poll(struct file *file, poll_table *wait) +{ + struct perf_counter *counter = file->private_data; + struct perf_mmap_data *data; + unsigned int events = POLL_HUP; + + rcu_read_lock(); + data = rcu_dereference(counter->data); + if (data) + events = atomic_xchg(&data->poll, 0); + rcu_read_unlock(); + + poll_wait(file, &counter->waitq, wait); + + return events; +} + +static void perf_counter_reset(struct perf_counter *counter) +{ + (void)perf_counter_read(counter); + atomic64_set(&counter->count, 0); + perf_counter_update_userpage(counter); +} + +/* + * Holding the top-level counter's child_mutex means that any + * descendant process that has inherited this counter will block + * in sync_child_counter if it goes to exit, thus satisfying the + * task existence requirements of perf_counter_enable/disable. + */ +static void perf_counter_for_each_child(struct perf_counter *counter, + void (*func)(struct perf_counter *)) +{ + struct perf_counter *child; + + WARN_ON_ONCE(counter->ctx->parent_ctx); + mutex_lock(&counter->child_mutex); + func(counter); + list_for_each_entry(child, &counter->child_list, child_list) + func(child); + mutex_unlock(&counter->child_mutex); +} + +static void perf_counter_for_each(struct perf_counter *counter, + void (*func)(struct perf_counter *)) +{ + struct perf_counter_context *ctx = counter->ctx; + struct perf_counter *sibling; + + WARN_ON_ONCE(ctx->parent_ctx); + mutex_lock(&ctx->mutex); + counter = counter->group_leader; + + perf_counter_for_each_child(counter, func); + func(counter); + list_for_each_entry(sibling, &counter->sibling_list, list_entry) + perf_counter_for_each_child(counter, func); + mutex_unlock(&ctx->mutex); +} + +static int perf_counter_period(struct perf_counter *counter, u64 __user *arg) +{ + struct perf_counter_context *ctx = counter->ctx; + unsigned long size; + int ret = 0; + u64 value; + + if (!counter->attr.sample_period) + return -EINVAL; + + size = copy_from_user(&value, arg, sizeof(value)); + if (size != sizeof(value)) + return -EFAULT; + + if (!value) + return -EINVAL; + + spin_lock_irq(&ctx->lock); + if (counter->attr.freq) { + if (value > sysctl_perf_counter_sample_rate) { + ret = -EINVAL; + goto unlock; + } + + counter->attr.sample_freq = value; + } else { + perf_log_period(counter, value); + + counter->attr.sample_period = value; + counter->hw.sample_period = value; + } +unlock: + spin_unlock_irq(&ctx->lock); + + return ret; +} + +static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct perf_counter *counter = file->private_data; + void (*func)(struct perf_counter *); + u32 flags = arg; + + switch (cmd) { + case PERF_COUNTER_IOC_ENABLE: + func = perf_counter_enable; + break; + case PERF_COUNTER_IOC_DISABLE: + func = perf_counter_disable; + break; + case PERF_COUNTER_IOC_RESET: + func = perf_counter_reset; + break; + + case PERF_COUNTER_IOC_REFRESH: + return perf_counter_refresh(counter, arg); + + case PERF_COUNTER_IOC_PERIOD: + return perf_counter_period(counter, (u64 __user *)arg); + + default: + return -ENOTTY; + } + + if (flags & PERF_IOC_FLAG_GROUP) + perf_counter_for_each(counter, func); + else + perf_counter_for_each_child(counter, func); + + return 0; +} + +int perf_counter_task_enable(void) +{ + struct perf_counter *counter; + + mutex_lock(¤t->perf_counter_mutex); + list_for_each_entry(counter, ¤t->perf_counter_list, owner_entry) + perf_counter_for_each_child(counter, perf_counter_enable); + mutex_unlock(¤t->perf_counter_mutex); + + return 0; +} + +int perf_counter_task_disable(void) +{ + struct perf_counter *counter; + + mutex_lock(¤t->perf_counter_mutex); + list_for_each_entry(counter, ¤t->perf_counter_list, owner_entry) + perf_counter_for_each_child(counter, perf_counter_disable); + mutex_unlock(¤t->perf_counter_mutex); + + return 0; +} + +/* + * Callers need to ensure there can be no nesting of this function, otherwise + * the seqlock logic goes bad. We can not serialize this because the arch + * code calls this from NMI context. + */ +void perf_counter_update_userpage(struct perf_counter *counter) +{ + struct perf_counter_mmap_page *userpg; + struct perf_mmap_data *data; + + rcu_read_lock(); + data = rcu_dereference(counter->data); + if (!data) + goto unlock; + + userpg = data->user_page; + + /* + * Disable preemption so as to not let the corresponding user-space + * spin too long if we get preempted. + */ + preempt_disable(); + ++userpg->lock; + barrier(); + userpg->index = counter->hw.idx; + userpg->offset = atomic64_read(&counter->count); + if (counter->state == PERF_COUNTER_STATE_ACTIVE) + userpg->offset -= atomic64_read(&counter->hw.prev_count); + + barrier(); + ++userpg->lock; + preempt_enable(); +unlock: + rcu_read_unlock(); +} + +static int perf_mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) +{ + struct perf_counter *counter = vma->vm_file->private_data; + struct perf_mmap_data *data; + int ret = VM_FAULT_SIGBUS; + + if (vmf->flags & FAULT_FLAG_MKWRITE) { + if (vmf->pgoff == 0) + ret = 0; + return ret; + } + + rcu_read_lock(); + data = rcu_dereference(counter->data); + if (!data) + goto unlock; + + if (vmf->pgoff == 0) { + vmf->page = virt_to_page(data->user_page); + } else { + int nr = vmf->pgoff - 1; + + if ((unsigned)nr > data->nr_pages) + goto unlock; + + if (vmf->flags & FAULT_FLAG_WRITE) + goto unlock; + + vmf->page = virt_to_page(data->data_pages[nr]); + } + + get_page(vmf->page); + vmf->page->mapping = vma->vm_file->f_mapping; + vmf->page->index = vmf->pgoff; + + ret = 0; +unlock: + rcu_read_unlock(); + + return ret; +} + +static int perf_mmap_data_alloc(struct perf_counter *counter, int nr_pages) +{ + struct perf_mmap_data *data; + unsigned long size; + int i; + + WARN_ON(atomic_read(&counter->mmap_count)); + + size = sizeof(struct perf_mmap_data); + size += nr_pages * sizeof(void *); + + data = kzalloc(size, GFP_KERNEL); + if (!data) + goto fail; + + data->user_page = (void *)get_zeroed_page(GFP_KERNEL); + if (!data->user_page) + goto fail_user_page; + + for (i = 0; i < nr_pages; i++) { + data->data_pages[i] = (void *)get_zeroed_page(GFP_KERNEL); + if (!data->data_pages[i]) + goto fail_data_pages; + } + + data->nr_pages = nr_pages; + atomic_set(&data->lock, -1); + + rcu_assign_pointer(counter->data, data); + + return 0; + +fail_data_pages: + for (i--; i >= 0; i--) + free_page((unsigned long)data->data_pages[i]); + + free_page((unsigned long)data->user_page); + +fail_user_page: + kfree(data); + +fail: + return -ENOMEM; +} + +static void perf_mmap_free_page(unsigned long addr) +{ + struct page *page = virt_to_page(addr); + + page->mapping = NULL; + __free_page(page); +} + +static void __perf_mmap_data_free(struct rcu_head *rcu_head) +{ + struct perf_mmap_data *data; + int i; + + data = container_of(rcu_head, struct perf_mmap_data, rcu_head); + + perf_mmap_free_page((unsigned long)data->user_page); + for (i = 0; i < data->nr_pages; i++) + perf_mmap_free_page((unsigned long)data->data_pages[i]); + + kfree(data); +} + +static void perf_mmap_data_free(struct perf_counter *counter) +{ + struct perf_mmap_data *data = counter->data; + + WARN_ON(atomic_read(&counter->mmap_count)); + + rcu_assign_pointer(counter->data, NULL); + call_rcu(&data->rcu_head, __perf_mmap_data_free); +} + +static void perf_mmap_open(struct vm_area_struct *vma) +{ + struct perf_counter *counter = vma->vm_file->private_data; + + atomic_inc(&counter->mmap_count); +} + +static void perf_mmap_close(struct vm_area_struct *vma) +{ + struct perf_counter *counter = vma->vm_file->private_data; + + WARN_ON_ONCE(counter->ctx->parent_ctx); + if (atomic_dec_and_mutex_lock(&counter->mmap_count, &counter->mmap_mutex)) { + struct user_struct *user = current_user(); + + atomic_long_sub(counter->data->nr_pages + 1, &user->locked_vm); + vma->vm_mm->locked_vm -= counter->data->nr_locked; + perf_mmap_data_free(counter); + mutex_unlock(&counter->mmap_mutex); + } +} + +static struct vm_operations_struct perf_mmap_vmops = { + .open = perf_mmap_open, + .close = perf_mmap_close, + .fault = perf_mmap_fault, + .page_mkwrite = perf_mmap_fault, +}; + +static int perf_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct perf_counter *counter = file->private_data; + unsigned long user_locked, user_lock_limit; + struct user_struct *user = current_user(); + unsigned long locked, lock_limit; + unsigned long vma_size; + unsigned long nr_pages; + long user_extra, extra; + int ret = 0; + + if (!(vma->vm_flags & VM_SHARED)) + return -EINVAL; + + vma_size = vma->vm_end - vma->vm_start; + nr_pages = (vma_size / PAGE_SIZE) - 1; + + /* + * If we have data pages ensure they're a power-of-two number, so we + * can do bitmasks instead of modulo. + */ + if (nr_pages != 0 && !is_power_of_2(nr_pages)) + return -EINVAL; + + if (vma_size != PAGE_SIZE * (1 + nr_pages)) + return -EINVAL; + + if (vma->vm_pgoff != 0) + return -EINVAL; + + WARN_ON_ONCE(counter->ctx->parent_ctx); + mutex_lock(&counter->mmap_mutex); + if (atomic_inc_not_zero(&counter->mmap_count)) { + if (nr_pages != counter->data->nr_pages) + ret = -EINVAL; + goto unlock; + } + + user_extra = nr_pages + 1; + user_lock_limit = sysctl_perf_counter_mlock >> (PAGE_SHIFT - 10); + + /* + * Increase the limit linearly with more CPUs: + */ + user_lock_limit *= num_online_cpus(); + + user_locked = atomic_long_read(&user->locked_vm) + user_extra; + + extra = 0; + if (user_locked > user_lock_limit) + extra = user_locked - user_lock_limit; + + lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur; + lock_limit >>= PAGE_SHIFT; + locked = vma->vm_mm->locked_vm + extra; + + if ((locked > lock_limit) && !capable(CAP_IPC_LOCK)) { + ret = -EPERM; + goto unlock; + } + + WARN_ON(counter->data); + ret = perf_mmap_data_alloc(counter, nr_pages); + if (ret) + goto unlock; + + atomic_set(&counter->mmap_count, 1); + atomic_long_add(user_extra, &user->locked_vm); + vma->vm_mm->locked_vm += extra; + counter->data->nr_locked = extra; + if (vma->vm_flags & VM_WRITE) + counter->data->writable = 1; + +unlock: + mutex_unlock(&counter->mmap_mutex); + + vma->vm_flags |= VM_RESERVED; + vma->vm_ops = &perf_mmap_vmops; + + return ret; +} + +static int perf_fasync(int fd, struct file *filp, int on) +{ + struct inode *inode = filp->f_path.dentry->d_inode; + struct perf_counter *counter = filp->private_data; + int retval; + + mutex_lock(&inode->i_mutex); + retval = fasync_helper(fd, filp, on, &counter->fasync); + mutex_unlock(&inode->i_mutex); + + if (retval < 0) + return retval; + + return 0; +} + +static const struct file_operations perf_fops = { + .release = perf_release, + .read = perf_read, + .poll = perf_poll, + .unlocked_ioctl = perf_ioctl, + .compat_ioctl = perf_ioctl, + .mmap = perf_mmap, + .fasync = perf_fasync, +}; + +/* + * Perf counter wakeup + * + * If there's data, ensure we set the poll() state and publish everything + * to user-space before waking everybody up. + */ + +void perf_counter_wakeup(struct perf_counter *counter) +{ + wake_up_all(&counter->waitq); + + if (counter->pending_kill) { + kill_fasync(&counter->fasync, SIGIO, counter->pending_kill); + counter->pending_kill = 0; + } +} + +/* + * Pending wakeups + * + * Handle the case where we need to wakeup up from NMI (or rq->lock) context. + * + * The NMI bit means we cannot possibly take locks. Therefore, maintain a + * single linked list and use cmpxchg() to add entries lockless. + */ + +static void perf_pending_counter(struct perf_pending_entry *entry) +{ + struct perf_counter *counter = container_of(entry, + struct perf_counter, pending); + + if (counter->pending_disable) { + counter->pending_disable = 0; + perf_counter_disable(counter); + } + + if (counter->pending_wakeup) { + counter->pending_wakeup = 0; + perf_counter_wakeup(counter); + } +} + +#define PENDING_TAIL ((struct perf_pending_entry *)-1UL) + +static DEFINE_PER_CPU(struct perf_pending_entry *, perf_pending_head) = { + PENDING_TAIL, +}; + +static void perf_pending_queue(struct perf_pending_entry *entry, + void (*func)(struct perf_pending_entry *)) +{ + struct perf_pending_entry **head; + + if (cmpxchg(&entry->next, NULL, PENDING_TAIL) != NULL) + return; + + entry->func = func; + + head = &get_cpu_var(perf_pending_head); + + do { + entry->next = *head; + } while (cmpxchg(head, entry->next, entry) != entry->next); + + set_perf_counter_pending(); + + put_cpu_var(perf_pending_head); +} + +static int __perf_pending_run(void) +{ + struct perf_pending_entry *list; + int nr = 0; + + list = xchg(&__get_cpu_var(perf_pending_head), PENDING_TAIL); + while (list != PENDING_TAIL) { + void (*func)(struct perf_pending_entry *); + struct perf_pending_entry *entry = list; + + list = list->next; + + func = entry->func; + entry->next = NULL; + /* + * Ensure we observe the unqueue before we issue the wakeup, + * so that we won't be waiting forever. + * -- see perf_not_pending(). + */ + smp_wmb(); + + func(entry); + nr++; + } + + return nr; +} + +static inline int perf_not_pending(struct perf_counter *counter) +{ + /* + * If we flush on whatever cpu we run, there is a chance we don't + * need to wait. + */ + get_cpu(); + __perf_pending_run(); + put_cpu(); + + /* + * Ensure we see the proper queue state before going to sleep + * so that we do not miss the wakeup. -- see perf_pending_handle() + */ + smp_rmb(); + return counter->pending.next == NULL; +} + +static void perf_pending_sync(struct perf_counter *counter) +{ + wait_event(counter->waitq, perf_not_pending(counter)); +} + +void perf_counter_do_pending(void) +{ + __perf_pending_run(); +} + +/* + * Callchain support -- arch specific + */ + +__weak struct perf_callchain_entry *perf_callchain(struct pt_regs *regs) +{ + return NULL; +} + +/* + * Output + */ + +struct perf_output_handle { + struct perf_counter *counter; + struct perf_mmap_data *data; + unsigned long head; + unsigned long offset; + int nmi; + int sample; + int locked; + unsigned long flags; +}; + +static bool perf_output_space(struct perf_mmap_data *data, + unsigned int offset, unsigned int head) +{ + unsigned long tail; + unsigned long mask; + + if (!data->writable) + return true; + + mask = (data->nr_pages << PAGE_SHIFT) - 1; + /* + * Userspace could choose to issue a mb() before updating the tail + * pointer. So that all reads will be completed before the write is + * issued. + */ + tail = ACCESS_ONCE(data->user_page->data_tail); + smp_rmb(); + + offset = (offset - tail) & mask; + head = (head - tail) & mask; + + if ((int)(head - offset) < 0) + return false; + + return true; +} + +static void perf_output_wakeup(struct perf_output_handle *handle) +{ + atomic_set(&handle->data->poll, POLL_IN); + + if (handle->nmi) { + handle->counter->pending_wakeup = 1; + perf_pending_queue(&handle->counter->pending, + perf_pending_counter); + } else + perf_counter_wakeup(handle->counter); +} + +/* + * Curious locking construct. + * + * We need to ensure a later event doesn't publish a head when a former + * event isn't done writing. However since we need to deal with NMIs we + * cannot fully serialize things. + * + * What we do is serialize between CPUs so we only have to deal with NMI + * nesting on a single CPU. + * + * We only publish the head (and generate a wakeup) when the outer-most + * event completes. + */ +static void perf_output_lock(struct perf_output_handle *handle) +{ + struct perf_mmap_data *data = handle->data; + int cpu; + + handle->locked = 0; + + local_irq_save(handle->flags); + cpu = smp_processor_id(); + + if (in_nmi() && atomic_read(&data->lock) == cpu) + return; + + while (atomic_cmpxchg(&data->lock, -1, cpu) != -1) + cpu_relax(); + + handle->locked = 1; +} + +static void perf_output_unlock(struct perf_output_handle *handle) +{ + struct perf_mmap_data *data = handle->data; + unsigned long head; + int cpu; + + data->done_head = data->head; + + if (!handle->locked) + goto out; + +again: + /* + * The xchg implies a full barrier that ensures all writes are done + * before we publish the new head, matched by a rmb() in userspace when + * reading this position. + */ + while ((head = atomic_long_xchg(&data->done_head, 0))) + data->user_page->data_head = head; + + /* + * NMI can happen here, which means we can miss a done_head update. + */ + + cpu = atomic_xchg(&data->lock, -1); + WARN_ON_ONCE(cpu != smp_processor_id()); + + /* + * Therefore we have to validate we did not indeed do so. + */ + if (unlikely(atomic_long_read(&data->done_head))) { + /* + * Since we had it locked, we can lock it again. + */ + while (atomic_cmpxchg(&data->lock, -1, cpu) != -1) + cpu_relax(); + + goto again; + } + + if (atomic_xchg(&data->wakeup, 0)) + perf_output_wakeup(handle); +out: + local_irq_restore(handle->flags); +} + +static void perf_output_copy(struct perf_output_handle *handle, + const void *buf, unsigned int len) +{ + unsigned int pages_mask; + unsigned int offset; + unsigned int size; + void **pages; + + offset = handle->offset; + pages_mask = handle->data->nr_pages - 1; + pages = handle->data->data_pages; + + do { + unsigned int page_offset; + int nr; + + nr = (offset >> PAGE_SHIFT) & pages_mask; + page_offset = offset & (PAGE_SIZE - 1); + size = min_t(unsigned int, PAGE_SIZE - page_offset, len); + + memcpy(pages[nr] + page_offset, buf, size); + + len -= size; + buf += size; + offset += size; + } while (len); + + handle->offset = offset; + + /* + * Check we didn't copy past our reservation window, taking the + * possible unsigned int wrap into account. + */ + WARN_ON_ONCE(((long)(handle->head - handle->offset)) < 0); +} + +#define perf_output_put(handle, x) \ + perf_output_copy((handle), &(x), sizeof(x)) + +static int perf_output_begin(struct perf_output_handle *handle, + struct perf_counter *counter, unsigned int size, + int nmi, int sample) +{ + struct perf_mmap_data *data; + unsigned int offset, head; + int have_lost; + struct { + struct perf_event_header header; + u64 id; + u64 lost; + } lost_event; + + /* + * For inherited counters we send all the output towards the parent. + */ + if (counter->parent) + counter = counter->parent; + + rcu_read_lock(); + data = rcu_dereference(counter->data); + if (!data) + goto out; + + handle->data = data; + handle->counter = counter; + handle->nmi = nmi; + handle->sample = sample; + + if (!data->nr_pages) + goto fail; + + have_lost = atomic_read(&data->lost); + if (have_lost) + size += sizeof(lost_event); + + perf_output_lock(handle); + + do { + offset = head = atomic_long_read(&data->head); + head += size; + if (unlikely(!perf_output_space(data, offset, head))) + goto fail; + } while (atomic_long_cmpxchg(&data->head, offset, head) != offset); + + handle->offset = offset; + handle->head = head; + + if ((offset >> PAGE_SHIFT) != (head >> PAGE_SHIFT)) + atomic_set(&data->wakeup, 1); + + if (have_lost) { + lost_event.header.type = PERF_EVENT_LOST; + lost_event.header.misc = 0; + lost_event.header.size = sizeof(lost_event); + lost_event.id = counter->id; + lost_event.lost = atomic_xchg(&data->lost, 0); + + perf_output_put(handle, lost_event); + } + + return 0; + +fail: + atomic_inc(&data->lost); + perf_output_unlock(handle); +out: + rcu_read_unlock(); + + return -ENOSPC; +} + +static void perf_output_end(struct perf_output_handle *handle) +{ + struct perf_counter *counter = handle->counter; + struct perf_mmap_data *data = handle->data; + + int wakeup_events = counter->attr.wakeup_events; + + if (handle->sample && wakeup_events) { + int events = atomic_inc_return(&data->events); + if (events >= wakeup_events) { + atomic_sub(wakeup_events, &data->events); + atomic_set(&data->wakeup, 1); + } + } + + perf_output_unlock(handle); + rcu_read_unlock(); +} + +static u32 perf_counter_pid(struct perf_counter *counter, struct task_struct *p) +{ + /* + * only top level counters have the pid namespace they were created in + */ + if (counter->parent) + counter = counter->parent; + + return task_tgid_nr_ns(p, counter->ns); +} + +static u32 perf_counter_tid(struct perf_counter *counter, struct task_struct *p) +{ + /* + * only top level counters have the pid namespace they were created in + */ + if (counter->parent) + counter = counter->parent; + + return task_pid_nr_ns(p, counter->ns); +} + +static void perf_counter_output(struct perf_counter *counter, int nmi, + struct perf_sample_data *data) +{ + int ret; + u64 sample_type = counter->attr.sample_type; + struct perf_output_handle handle; + struct perf_event_header header; + u64 ip; + struct { + u32 pid, tid; + } tid_entry; + struct { + u64 id; + u64 counter; + } group_entry; + struct perf_callchain_entry *callchain = NULL; + int callchain_size = 0; + u64 time; + struct { + u32 cpu, reserved; + } cpu_entry; + + header.type = 0; + header.size = sizeof(header); + + header.misc = PERF_EVENT_MISC_OVERFLOW; + header.misc |= perf_misc_flags(data->regs); + + if (sample_type & PERF_SAMPLE_IP) { + ip = perf_instruction_pointer(data->regs); + header.type |= PERF_SAMPLE_IP; + header.size += sizeof(ip); + } + + if (sample_type & PERF_SAMPLE_TID) { + /* namespace issues */ + tid_entry.pid = perf_counter_pid(counter, current); + tid_entry.tid = perf_counter_tid(counter, current); + + header.type |= PERF_SAMPLE_TID; + header.size += sizeof(tid_entry); + } + + if (sample_type & PERF_SAMPLE_TIME) { + /* + * Maybe do better on x86 and provide cpu_clock_nmi() + */ + time = sched_clock(); + + header.type |= PERF_SAMPLE_TIME; + header.size += sizeof(u64); + } + + if (sample_type & PERF_SAMPLE_ADDR) { + header.type |= PERF_SAMPLE_ADDR; + header.size += sizeof(u64); + } + + if (sample_type & PERF_SAMPLE_ID) { + header.type |= PERF_SAMPLE_ID; + header.size += sizeof(u64); + } + + if (sample_type & PERF_SAMPLE_CPU) { + header.type |= PERF_SAMPLE_CPU; + header.size += sizeof(cpu_entry); + + cpu_entry.cpu = raw_smp_processor_id(); + } + + if (sample_type & PERF_SAMPLE_PERIOD) { + header.type |= PERF_SAMPLE_PERIOD; + header.size += sizeof(u64); + } + + if (sample_type & PERF_SAMPLE_GROUP) { + header.type |= PERF_SAMPLE_GROUP; + header.size += sizeof(u64) + + counter->nr_siblings * sizeof(group_entry); + } + + if (sample_type & PERF_SAMPLE_CALLCHAIN) { + callchain = perf_callchain(data->regs); + + if (callchain) { + callchain_size = (1 + callchain->nr) * sizeof(u64); + + header.type |= PERF_SAMPLE_CALLCHAIN; + header.size += callchain_size; + } + } + + ret = perf_output_begin(&handle, counter, header.size, nmi, 1); + if (ret) + return; + + perf_output_put(&handle, header); + + if (sample_type & PERF_SAMPLE_IP) + perf_output_put(&handle, ip); + + if (sample_type & PERF_SAMPLE_TID) + perf_output_put(&handle, tid_entry); + + if (sample_type & PERF_SAMPLE_TIME) + perf_output_put(&handle, time); + + if (sample_type & PERF_SAMPLE_ADDR) + perf_output_put(&handle, data->addr); + + if (sample_type & PERF_SAMPLE_ID) + perf_output_put(&handle, counter->id); + + if (sample_type & PERF_SAMPLE_CPU) + perf_output_put(&handle, cpu_entry); + + if (sample_type & PERF_SAMPLE_PERIOD) + perf_output_put(&handle, data->period); + + /* + * XXX PERF_SAMPLE_GROUP vs inherited counters seems difficult. + */ + if (sample_type & PERF_SAMPLE_GROUP) { + struct perf_counter *leader, *sub; + u64 nr = counter->nr_siblings; + + perf_output_put(&handle, nr); + + leader = counter->group_leader; + list_for_each_entry(sub, &leader->sibling_list, list_entry) { + if (sub != counter) + sub->pmu->read(sub); + + group_entry.id = sub->id; + group_entry.counter = atomic64_read(&sub->count); + + perf_output_put(&handle, group_entry); + } + } + + if (callchain) + perf_output_copy(&handle, callchain, callchain_size); + + perf_output_end(&handle); +} + +/* + * fork tracking + */ + +struct perf_fork_event { + struct task_struct *task; + + struct { + struct perf_event_header header; + + u32 pid; + u32 ppid; + } event; +}; + +static void perf_counter_fork_output(struct perf_counter *counter, + struct perf_fork_event *fork_event) +{ + struct perf_output_handle handle; + int size = fork_event->event.header.size; + struct task_struct *task = fork_event->task; + int ret = perf_output_begin(&handle, counter, size, 0, 0); + + if (ret) + return; + + fork_event->event.pid = perf_counter_pid(counter, task); + fork_event->event.ppid = perf_counter_pid(counter, task->real_parent); + + perf_output_put(&handle, fork_event->event); + perf_output_end(&handle); +} + +static int perf_counter_fork_match(struct perf_counter *counter) +{ + if (counter->attr.comm || counter->attr.mmap) + return 1; + + return 0; +} + +static void perf_counter_fork_ctx(struct perf_counter_context *ctx, + struct perf_fork_event *fork_event) +{ + struct perf_counter *counter; + + if (system_state != SYSTEM_RUNNING || list_empty(&ctx->event_list)) + return; + + rcu_read_lock(); + list_for_each_entry_rcu(counter, &ctx->event_list, event_entry) { + if (perf_counter_fork_match(counter)) + perf_counter_fork_output(counter, fork_event); + } + rcu_read_unlock(); +} + +static void perf_counter_fork_event(struct perf_fork_event *fork_event) +{ + struct perf_cpu_context *cpuctx; + struct perf_counter_context *ctx; + + cpuctx = &get_cpu_var(perf_cpu_context); + perf_counter_fork_ctx(&cpuctx->ctx, fork_event); + put_cpu_var(perf_cpu_context); + + rcu_read_lock(); + /* + * doesn't really matter which of the child contexts the + * events ends up in. + */ + ctx = rcu_dereference(current->perf_counter_ctxp); + if (ctx) + perf_counter_fork_ctx(ctx, fork_event); + rcu_read_unlock(); +} + +void perf_counter_fork(struct task_struct *task) +{ + struct perf_fork_event fork_event; + + if (!atomic_read(&nr_comm_counters) && + !atomic_read(&nr_mmap_counters)) + return; + + fork_event = (struct perf_fork_event){ + .task = task, + .event = { + .header = { + .type = PERF_EVENT_FORK, + .size = sizeof(fork_event.event), + }, + }, + }; + + perf_counter_fork_event(&fork_event); +} + +/* + * comm tracking + */ + +struct perf_comm_event { + struct task_struct *task; + char *comm; + int comm_size; + + struct { + struct perf_event_header header; + + u32 pid; + u32 tid; + } event; +}; + +static void perf_counter_comm_output(struct perf_counter *counter, + struct perf_comm_event *comm_event) +{ + struct perf_output_handle handle; + int size = comm_event->event.header.size; + int ret = perf_output_begin(&handle, counter, size, 0, 0); + + if (ret) + return; + + comm_event->event.pid = perf_counter_pid(counter, comm_event->task); + comm_event->event.tid = perf_counter_tid(counter, comm_event->task); + + perf_output_put(&handle, comm_event->event); + perf_output_copy(&handle, comm_event->comm, + comm_event->comm_size); + perf_output_end(&handle); +} + +static int perf_counter_comm_match(struct perf_counter *counter) +{ + if (counter->attr.comm) + return 1; + + return 0; +} + +static void perf_counter_comm_ctx(struct perf_counter_context *ctx, + struct perf_comm_event *comm_event) +{ + struct perf_counter *counter; + + if (system_state != SYSTEM_RUNNING || list_empty(&ctx->event_list)) + return; + + rcu_read_lock(); + list_for_each_entry_rcu(counter, &ctx->event_list, event_entry) { + if (perf_counter_comm_match(counter)) + perf_counter_comm_output(counter, comm_event); + } + rcu_read_unlock(); +} + +static void perf_counter_comm_event(struct perf_comm_event *comm_event) +{ + struct perf_cpu_context *cpuctx; + struct perf_counter_context *ctx; + unsigned int size; + char *comm = comm_event->task->comm; + + size = ALIGN(strlen(comm)+1, sizeof(u64)); + + comm_event->comm = comm; + comm_event->comm_size = size; + + comm_event->event.header.size = sizeof(comm_event->event) + size; + + cpuctx = &get_cpu_var(perf_cpu_context); + perf_counter_comm_ctx(&cpuctx->ctx, comm_event); + put_cpu_var(perf_cpu_context); + + rcu_read_lock(); + /* + * doesn't really matter which of the child contexts the + * events ends up in. + */ + ctx = rcu_dereference(current->perf_counter_ctxp); + if (ctx) + perf_counter_comm_ctx(ctx, comm_event); + rcu_read_unlock(); +} + +void perf_counter_comm(struct task_struct *task) +{ + struct perf_comm_event comm_event; + + if (!atomic_read(&nr_comm_counters)) + return; + + comm_event = (struct perf_comm_event){ + .task = task, + .event = { + .header = { .type = PERF_EVENT_COMM, }, + }, + }; + + perf_counter_comm_event(&comm_event); +} + +/* + * mmap tracking + */ + +struct perf_mmap_event { + struct vm_area_struct *vma; + + const char *file_name; + int file_size; + + struct { + struct perf_event_header header; + + u32 pid; + u32 tid; + u64 start; + u64 len; + u64 pgoff; + } event; +}; + +static void perf_counter_mmap_output(struct perf_counter *counter, + struct perf_mmap_event *mmap_event) +{ + struct perf_output_handle handle; + int size = mmap_event->event.header.size; + int ret = perf_output_begin(&handle, counter, size, 0, 0); + + if (ret) + return; + + mmap_event->event.pid = perf_counter_pid(counter, current); + mmap_event->event.tid = perf_counter_tid(counter, current); + + perf_output_put(&handle, mmap_event->event); + perf_output_copy(&handle, mmap_event->file_name, + mmap_event->file_size); + perf_output_end(&handle); +} + +static int perf_counter_mmap_match(struct perf_counter *counter, + struct perf_mmap_event *mmap_event) +{ + if (counter->attr.mmap) + return 1; + + return 0; +} + +static void perf_counter_mmap_ctx(struct perf_counter_context *ctx, + struct perf_mmap_event *mmap_event) +{ + struct perf_counter *counter; + + if (system_state != SYSTEM_RUNNING || list_empty(&ctx->event_list)) + return; + + rcu_read_lock(); + list_for_each_entry_rcu(counter, &ctx->event_list, event_entry) { + if (perf_counter_mmap_match(counter, mmap_event)) + perf_counter_mmap_output(counter, mmap_event); + } + rcu_read_unlock(); +} + +static void perf_counter_mmap_event(struct perf_mmap_event *mmap_event) +{ + struct perf_cpu_context *cpuctx; + struct perf_counter_context *ctx; + struct vm_area_struct *vma = mmap_event->vma; + struct file *file = vma->vm_file; + unsigned int size; + char tmp[16]; + char *buf = NULL; + const char *name; + + if (file) { + buf = kzalloc(PATH_MAX, GFP_KERNEL); + if (!buf) { + name = strncpy(tmp, "//enomem", sizeof(tmp)); + goto got_name; + } + name = d_path(&file->f_path, buf, PATH_MAX); + if (IS_ERR(name)) { + name = strncpy(tmp, "//toolong", sizeof(tmp)); + goto got_name; + } + } else { + name = arch_vma_name(mmap_event->vma); + if (name) + goto got_name; + + if (!vma->vm_mm) { + name = strncpy(tmp, "[vdso]", sizeof(tmp)); + goto got_name; + } + + name = strncpy(tmp, "//anon", sizeof(tmp)); + goto got_name; + } + +got_name: + size = ALIGN(strlen(name)+1, sizeof(u64)); + + mmap_event->file_name = name; + mmap_event->file_size = size; + + mmap_event->event.header.size = sizeof(mmap_event->event) + size; + + cpuctx = &get_cpu_var(perf_cpu_context); + perf_counter_mmap_ctx(&cpuctx->ctx, mmap_event); + put_cpu_var(perf_cpu_context); + + rcu_read_lock(); + /* + * doesn't really matter which of the child contexts the + * events ends up in. + */ + ctx = rcu_dereference(current->perf_counter_ctxp); + if (ctx) + perf_counter_mmap_ctx(ctx, mmap_event); + rcu_read_unlock(); + + kfree(buf); +} + +void __perf_counter_mmap(struct vm_area_struct *vma) +{ + struct perf_mmap_event mmap_event; + + if (!atomic_read(&nr_mmap_counters)) + return; + + mmap_event = (struct perf_mmap_event){ + .vma = vma, + .event = { + .header = { .type = PERF_EVENT_MMAP, }, + .start = vma->vm_start, + .len = vma->vm_end - vma->vm_start, + .pgoff = vma->vm_pgoff, + }, + }; + + perf_counter_mmap_event(&mmap_event); +} + +/* + * Log sample_period changes so that analyzing tools can re-normalize the + * event flow. + */ + +struct freq_event { + struct perf_event_header header; + u64 time; + u64 id; + u64 period; +}; + +static void perf_log_period(struct perf_counter *counter, u64 period) +{ + struct perf_output_handle handle; + struct freq_event event; + int ret; + + if (counter->hw.sample_period == period) + return; + + if (counter->attr.sample_type & PERF_SAMPLE_PERIOD) + return; + + event = (struct freq_event) { + .header = { + .type = PERF_EVENT_PERIOD, + .misc = 0, + .size = sizeof(event), + }, + .time = sched_clock(), + .id = counter->id, + .period = period, + }; + + ret = perf_output_begin(&handle, counter, sizeof(event), 1, 0); + if (ret) + return; + + perf_output_put(&handle, event); + perf_output_end(&handle); +} + +/* + * IRQ throttle logging + */ + +static void perf_log_throttle(struct perf_counter *counter, int enable) +{ + struct perf_output_handle handle; + int ret; + + struct { + struct perf_event_header header; + u64 time; + u64 id; + } throttle_event = { + .header = { + .type = PERF_EVENT_THROTTLE + 1, + .misc = 0, + .size = sizeof(throttle_event), + }, + .time = sched_clock(), + .id = counter->id, + }; + + ret = perf_output_begin(&handle, counter, sizeof(throttle_event), 1, 0); + if (ret) + return; + + perf_output_put(&handle, throttle_event); + perf_output_end(&handle); +} + +/* + * Generic counter overflow handling, sampling. + */ + +int perf_counter_overflow(struct perf_counter *counter, int nmi, + struct perf_sample_data *data) +{ + int events = atomic_read(&counter->event_limit); + int throttle = counter->pmu->unthrottle != NULL; + struct hw_perf_counter *hwc = &counter->hw; + int ret = 0; + + if (!throttle) { + hwc->interrupts++; + } else { + if (hwc->interrupts != MAX_INTERRUPTS) { + hwc->interrupts++; + if (HZ * hwc->interrupts > + (u64)sysctl_perf_counter_sample_rate) { + hwc->interrupts = MAX_INTERRUPTS; + perf_log_throttle(counter, 0); + ret = 1; + } + } else { + /* + * Keep re-disabling counters even though on the previous + * pass we disabled it - just in case we raced with a + * sched-in and the counter got enabled again: + */ + ret = 1; + } + } + + if (counter->attr.freq) { + u64 now = sched_clock(); + s64 delta = now - hwc->freq_stamp; + + hwc->freq_stamp = now; + + if (delta > 0 && delta < TICK_NSEC) + perf_adjust_period(counter, NSEC_PER_SEC / (int)delta); + } + + /* + * XXX event_limit might not quite work as expected on inherited + * counters + */ + + counter->pending_kill = POLL_IN; + if (events && atomic_dec_and_test(&counter->event_limit)) { + ret = 1; + counter->pending_kill = POLL_HUP; + if (nmi) { + counter->pending_disable = 1; + perf_pending_queue(&counter->pending, + perf_pending_counter); + } else + perf_counter_disable(counter); + } + + perf_counter_output(counter, nmi, data); + return ret; +} + +/* + * Generic software counter infrastructure + */ + +static void perf_swcounter_update(struct perf_counter *counter) +{ + struct hw_perf_counter *hwc = &counter->hw; + u64 prev, now; + s64 delta; + +again: + prev = atomic64_read(&hwc->prev_count); + now = atomic64_read(&hwc->count); + if (atomic64_cmpxchg(&hwc->prev_count, prev, now) != prev) + goto again; + + delta = now - prev; + + atomic64_add(delta, &counter->count); + atomic64_sub(delta, &hwc->period_left); +} + +static void perf_swcounter_set_period(struct perf_counter *counter) +{ + struct hw_perf_counter *hwc = &counter->hw; + s64 left = atomic64_read(&hwc->period_left); + s64 period = hwc->sample_period; + + if (unlikely(left <= -period)) { + left = period; + atomic64_set(&hwc->period_left, left); + hwc->last_period = period; + } + + if (unlikely(left <= 0)) { + left += period; + atomic64_add(period, &hwc->period_left); + hwc->last_period = period; + } + + atomic64_set(&hwc->prev_count, -left); + atomic64_set(&hwc->count, -left); +} + +static enum hrtimer_restart perf_swcounter_hrtimer(struct hrtimer *hrtimer) +{ + enum hrtimer_restart ret = HRTIMER_RESTART; + struct perf_sample_data data; + struct perf_counter *counter; + u64 period; + + counter = container_of(hrtimer, struct perf_counter, hw.hrtimer); + counter->pmu->read(counter); + + data.addr = 0; + data.regs = get_irq_regs(); + /* + * In case we exclude kernel IPs or are somehow not in interrupt + * context, provide the next best thing, the user IP. + */ + if ((counter->attr.exclude_kernel || !data.regs) && + !counter->attr.exclude_user) + data.regs = task_pt_regs(current); + + if (data.regs) { + if (perf_counter_overflow(counter, 0, &data)) + ret = HRTIMER_NORESTART; + } + + period = max_t(u64, 10000, counter->hw.sample_period); + hrtimer_forward_now(hrtimer, ns_to_ktime(period)); + + return ret; +} + +static void perf_swcounter_overflow(struct perf_counter *counter, + int nmi, struct perf_sample_data *data) +{ + data->period = counter->hw.last_period; + + perf_swcounter_update(counter); + perf_swcounter_set_period(counter); + if (perf_counter_overflow(counter, nmi, data)) + /* soft-disable the counter */ + ; +} + +static int perf_swcounter_is_counting(struct perf_counter *counter) +{ + struct perf_counter_context *ctx; + unsigned long flags; + int count; + + if (counter->state == PERF_COUNTER_STATE_ACTIVE) + return 1; + + if (counter->state != PERF_COUNTER_STATE_INACTIVE) + return 0; + + /* + * If the counter is inactive, it could be just because + * its task is scheduled out, or because it's in a group + * which could not go on the PMU. We want to count in + * the first case but not the second. If the context is + * currently active then an inactive software counter must + * be the second case. If it's not currently active then + * we need to know whether the counter was active when the + * context was last active, which we can determine by + * comparing counter->tstamp_stopped with ctx->time. + * + * We are within an RCU read-side critical section, + * which protects the existence of *ctx. + */ + ctx = counter->ctx; + spin_lock_irqsave(&ctx->lock, flags); + count = 1; + /* Re-check state now we have the lock */ + if (counter->state < PERF_COUNTER_STATE_INACTIVE || + counter->ctx->is_active || + counter->tstamp_stopped < ctx->time) + count = 0; + spin_unlock_irqrestore(&ctx->lock, flags); + return count; +} + +static int perf_swcounter_match(struct perf_counter *counter, + enum perf_type_id type, + u32 event, struct pt_regs *regs) +{ + if (!perf_swcounter_is_counting(counter)) + return 0; + + if (counter->attr.type != type) + return 0; + if (counter->attr.config != event) + return 0; + + if (regs) { + if (counter->attr.exclude_user && user_mode(regs)) + return 0; + + if (counter->attr.exclude_kernel && !user_mode(regs)) + return 0; + } + + return 1; +} + +static void perf_swcounter_add(struct perf_counter *counter, u64 nr, + int nmi, struct perf_sample_data *data) +{ + int neg = atomic64_add_negative(nr, &counter->hw.count); + + if (counter->hw.sample_period && !neg && data->regs) + perf_swcounter_overflow(counter, nmi, data); +} + +static void perf_swcounter_ctx_event(struct perf_counter_context *ctx, + enum perf_type_id type, + u32 event, u64 nr, int nmi, + struct perf_sample_data *data) +{ + struct perf_counter *counter; + + if (system_state != SYSTEM_RUNNING || list_empty(&ctx->event_list)) + return; + + rcu_read_lock(); + list_for_each_entry_rcu(counter, &ctx->event_list, event_entry) { + if (perf_swcounter_match(counter, type, event, data->regs)) + perf_swcounter_add(counter, nr, nmi, data); + } + rcu_read_unlock(); +} + +static int *perf_swcounter_recursion_context(struct perf_cpu_context *cpuctx) +{ + if (in_nmi()) + return &cpuctx->recursion[3]; + + if (in_irq()) + return &cpuctx->recursion[2]; + + if (in_softirq()) + return &cpuctx->recursion[1]; + + return &cpuctx->recursion[0]; +} + +static void do_perf_swcounter_event(enum perf_type_id type, u32 event, + u64 nr, int nmi, + struct perf_sample_data *data) +{ + struct perf_cpu_context *cpuctx = &get_cpu_var(perf_cpu_context); + int *recursion = perf_swcounter_recursion_context(cpuctx); + struct perf_counter_context *ctx; + + if (*recursion) + goto out; + + (*recursion)++; + barrier(); + + perf_swcounter_ctx_event(&cpuctx->ctx, type, event, + nr, nmi, data); + rcu_read_lock(); + /* + * doesn't really matter which of the child contexts the + * events ends up in. + */ + ctx = rcu_dereference(current->perf_counter_ctxp); + if (ctx) + perf_swcounter_ctx_event(ctx, type, event, nr, nmi, data); + rcu_read_unlock(); + + barrier(); + (*recursion)--; + +out: + put_cpu_var(perf_cpu_context); +} + +void +perf_swcounter_event(u32 event, u64 nr, int nmi, struct pt_regs *regs, u64 addr) +{ + struct perf_sample_data data = { + .regs = regs, + .addr = addr, + }; + + do_perf_swcounter_event(PERF_TYPE_SOFTWARE, event, nr, nmi, &data); +} + +static void perf_swcounter_read(struct perf_counter *counter) +{ + perf_swcounter_update(counter); +} + +static int perf_swcounter_enable(struct perf_counter *counter) +{ + perf_swcounter_set_period(counter); + return 0; +} + +static void perf_swcounter_disable(struct perf_counter *counter) +{ + perf_swcounter_update(counter); +} + +static const struct pmu perf_ops_generic = { + .enable = perf_swcounter_enable, + .disable = perf_swcounter_disable, + .read = perf_swcounter_read, +}; + +/* + * Software counter: cpu wall time clock + */ + +static void cpu_clock_perf_counter_update(struct perf_counter *counter) +{ + int cpu = raw_smp_processor_id(); + s64 prev; + u64 now; + + now = cpu_clock(cpu); + prev = atomic64_read(&counter->hw.prev_count); + atomic64_set(&counter->hw.prev_count, now); + atomic64_add(now - prev, &counter->count); +} + +static int cpu_clock_perf_counter_enable(struct perf_counter *counter) +{ + struct hw_perf_counter *hwc = &counter->hw; + int cpu = raw_smp_processor_id(); + + atomic64_set(&hwc->prev_count, cpu_clock(cpu)); + hrtimer_init(&hwc->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + hwc->hrtimer.function = perf_swcounter_hrtimer; + if (hwc->sample_period) { + u64 period = max_t(u64, 10000, hwc->sample_period); + __hrtimer_start_range_ns(&hwc->hrtimer, + ns_to_ktime(period), 0, + HRTIMER_MODE_REL, 0); + } + + return 0; +} + +static void cpu_clock_perf_counter_disable(struct perf_counter *counter) +{ + if (counter->hw.sample_period) + hrtimer_cancel(&counter->hw.hrtimer); + cpu_clock_perf_counter_update(counter); +} + +static void cpu_clock_perf_counter_read(struct perf_counter *counter) +{ + cpu_clock_perf_counter_update(counter); +} + +static const struct pmu perf_ops_cpu_clock = { + .enable = cpu_clock_perf_counter_enable, + .disable = cpu_clock_perf_counter_disable, + .read = cpu_clock_perf_counter_read, +}; + +/* + * Software counter: task time clock + */ + +static void task_clock_perf_counter_update(struct perf_counter *counter, u64 now) +{ + u64 prev; + s64 delta; + + prev = atomic64_xchg(&counter->hw.prev_count, now); + delta = now - prev; + atomic64_add(delta, &counter->count); +} + +static int task_clock_perf_counter_enable(struct perf_counter *counter) +{ + struct hw_perf_counter *hwc = &counter->hw; + u64 now; + + now = counter->ctx->time; + + atomic64_set(&hwc->prev_count, now); + hrtimer_init(&hwc->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + hwc->hrtimer.function = perf_swcounter_hrtimer; + if (hwc->sample_period) { + u64 period = max_t(u64, 10000, hwc->sample_period); + __hrtimer_start_range_ns(&hwc->hrtimer, + ns_to_ktime(period), 0, + HRTIMER_MODE_REL, 0); + } + + return 0; +} + +static void task_clock_perf_counter_disable(struct perf_counter *counter) +{ + if (counter->hw.sample_period) + hrtimer_cancel(&counter->hw.hrtimer); + task_clock_perf_counter_update(counter, counter->ctx->time); + +} + +static void task_clock_perf_counter_read(struct perf_counter *counter) +{ + u64 time; + + if (!in_nmi()) { + update_context_time(counter->ctx); + time = counter->ctx->time; + } else { + u64 now = perf_clock(); + u64 delta = now - counter->ctx->timestamp; + time = counter->ctx->time + delta; + } + + task_clock_perf_counter_update(counter, time); +} + +static const struct pmu perf_ops_task_clock = { + .enable = task_clock_perf_counter_enable, + .disable = task_clock_perf_counter_disable, + .read = task_clock_perf_counter_read, +}; + +#ifdef CONFIG_EVENT_PROFILE +void perf_tpcounter_event(int event_id) +{ + struct perf_sample_data data = { + .regs = get_irq_regs(); + .addr = 0, + }; + + if (!data.regs) + data.regs = task_pt_regs(current); + + do_perf_swcounter_event(PERF_TYPE_TRACEPOINT, event_id, 1, 1, &data); +} +EXPORT_SYMBOL_GPL(perf_tpcounter_event); + +extern int ftrace_profile_enable(int); +extern void ftrace_profile_disable(int); + +static void tp_perf_counter_destroy(struct perf_counter *counter) +{ + ftrace_profile_disable(perf_event_id(&counter->attr)); +} + +static const struct pmu *tp_perf_counter_init(struct perf_counter *counter) +{ + int event_id = perf_event_id(&counter->attr); + int ret; + + ret = ftrace_profile_enable(event_id); + if (ret) + return NULL; + + counter->destroy = tp_perf_counter_destroy; + + return &perf_ops_generic; +} +#else +static const struct pmu *tp_perf_counter_init(struct perf_counter *counter) +{ + return NULL; +} +#endif + +static const struct pmu *sw_perf_counter_init(struct perf_counter *counter) +{ + const struct pmu *pmu = NULL; + + /* + * Software counters (currently) can't in general distinguish + * between user, kernel and hypervisor events. + * However, context switches and cpu migrations are considered + * to be kernel events, and page faults are never hypervisor + * events. + */ + switch (counter->attr.config) { + case PERF_COUNT_SW_CPU_CLOCK: + pmu = &perf_ops_cpu_clock; + + break; + case PERF_COUNT_SW_TASK_CLOCK: + /* + * If the user instantiates this as a per-cpu counter, + * use the cpu_clock counter instead. + */ + if (counter->ctx->task) + pmu = &perf_ops_task_clock; + else + pmu = &perf_ops_cpu_clock; + + break; + case PERF_COUNT_SW_PAGE_FAULTS: + case PERF_COUNT_SW_PAGE_FAULTS_MIN: + case PERF_COUNT_SW_PAGE_FAULTS_MAJ: + case PERF_COUNT_SW_CONTEXT_SWITCHES: + case PERF_COUNT_SW_CPU_MIGRATIONS: + pmu = &perf_ops_generic; + break; + } + + return pmu; +} + +/* + * Allocate and initialize a counter structure + */ +static struct perf_counter * +perf_counter_alloc(struct perf_counter_attr *attr, + int cpu, + struct perf_counter_context *ctx, + struct perf_counter *group_leader, + gfp_t gfpflags) +{ + const struct pmu *pmu; + struct perf_counter *counter; + struct hw_perf_counter *hwc; + long err; + + counter = kzalloc(sizeof(*counter), gfpflags); + if (!counter) + return ERR_PTR(-ENOMEM); + + /* + * Single counters are their own group leaders, with an + * empty sibling list: + */ + if (!group_leader) + group_leader = counter; + + mutex_init(&counter->child_mutex); + INIT_LIST_HEAD(&counter->child_list); + + INIT_LIST_HEAD(&counter->list_entry); + INIT_LIST_HEAD(&counter->event_entry); + INIT_LIST_HEAD(&counter->sibling_list); + init_waitqueue_head(&counter->waitq); + + mutex_init(&counter->mmap_mutex); + + counter->cpu = cpu; + counter->attr = *attr; + counter->group_leader = group_leader; + counter->pmu = NULL; + counter->ctx = ctx; + counter->oncpu = -1; + + counter->ns = get_pid_ns(current->nsproxy->pid_ns); + counter->id = atomic64_inc_return(&perf_counter_id); + + counter->state = PERF_COUNTER_STATE_INACTIVE; + + if (attr->disabled) + counter->state = PERF_COUNTER_STATE_OFF; + + pmu = NULL; + + hwc = &counter->hw; + hwc->sample_period = attr->sample_period; + if (attr->freq && attr->sample_freq) + hwc->sample_period = 1; + + atomic64_set(&hwc->period_left, hwc->sample_period); + + /* + * we currently do not support PERF_SAMPLE_GROUP on inherited counters + */ + if (attr->inherit && (attr->sample_type & PERF_SAMPLE_GROUP)) + goto done; + + switch (attr->type) { + case PERF_TYPE_RAW: + case PERF_TYPE_HARDWARE: + case PERF_TYPE_HW_CACHE: + pmu = hw_perf_counter_init(counter); + break; + + case PERF_TYPE_SOFTWARE: + pmu = sw_perf_counter_init(counter); + break; + + case PERF_TYPE_TRACEPOINT: + pmu = tp_perf_counter_init(counter); + break; + + default: + break; + } +done: + err = 0; + if (!pmu) + err = -EINVAL; + else if (IS_ERR(pmu)) + err = PTR_ERR(pmu); + + if (err) { + if (counter->ns) + put_pid_ns(counter->ns); + kfree(counter); + return ERR_PTR(err); + } + + counter->pmu = pmu; + + atomic_inc(&nr_counters); + if (counter->attr.mmap) + atomic_inc(&nr_mmap_counters); + if (counter->attr.comm) + atomic_inc(&nr_comm_counters); + + return counter; +} + +static int perf_copy_attr(struct perf_counter_attr __user *uattr, + struct perf_counter_attr *attr) +{ + int ret; + u32 size; + + if (!access_ok(VERIFY_WRITE, uattr, PERF_ATTR_SIZE_VER0)) + return -EFAULT; + + /* + * zero the full structure, so that a short copy will be nice. + */ + memset(attr, 0, sizeof(*attr)); + + ret = get_user(size, &uattr->size); + if (ret) + return ret; + + if (size > PAGE_SIZE) /* silly large */ + goto err_size; + + if (!size) /* abi compat */ + size = PERF_ATTR_SIZE_VER0; + + if (size < PERF_ATTR_SIZE_VER0) + goto err_size; + + /* + * If we're handed a bigger struct than we know of, + * ensure all the unknown bits are 0. + */ + if (size > sizeof(*attr)) { + unsigned long val; + unsigned long __user *addr; + unsigned long __user *end; + + addr = PTR_ALIGN((void __user *)uattr + sizeof(*attr), + sizeof(unsigned long)); + end = PTR_ALIGN((void __user *)uattr + size, + sizeof(unsigned long)); + + for (; addr < end; addr += sizeof(unsigned long)) { + ret = get_user(val, addr); + if (ret) + return ret; + if (val) + goto err_size; + } + } + + ret = copy_from_user(attr, uattr, size); + if (ret) + return -EFAULT; + + /* + * If the type exists, the corresponding creation will verify + * the attr->config. + */ + if (attr->type >= PERF_TYPE_MAX) + return -EINVAL; + + if (attr->__reserved_1 || attr->__reserved_2 || attr->__reserved_3) + return -EINVAL; + + if (attr->sample_type & ~(PERF_SAMPLE_MAX-1)) + return -EINVAL; + + if (attr->read_format & ~(PERF_FORMAT_MAX-1)) + return -EINVAL; + +out: + return ret; + +err_size: + put_user(sizeof(*attr), &uattr->size); + ret = -E2BIG; + goto out; +} + +/** + * sys_perf_counter_open - open a performance counter, associate it to a task/cpu + * + * @attr_uptr: event type attributes for monitoring/sampling + * @pid: target pid + * @cpu: target cpu + * @group_fd: group leader counter fd + */ +SYSCALL_DEFINE5(perf_counter_open, + struct perf_counter_attr __user *, attr_uptr, + pid_t, pid, int, cpu, int, group_fd, unsigned long, flags) +{ + struct perf_counter *counter, *group_leader; + struct perf_counter_attr attr; + struct perf_counter_context *ctx; + struct file *counter_file = NULL; + struct file *group_file = NULL; + int fput_needed = 0; + int fput_needed2 = 0; + int ret; + + /* for future expandability... */ + if (flags) + return -EINVAL; + + ret = perf_copy_attr(attr_uptr, &attr); + if (ret) + return ret; + + if (!attr.exclude_kernel) { + if (perf_paranoid_kernel() && !capable(CAP_SYS_ADMIN)) + return -EACCES; + } + + if (attr.freq) { + if (attr.sample_freq > sysctl_perf_counter_sample_rate) + return -EINVAL; + } + + /* + * Get the target context (task or percpu): + */ + ctx = find_get_context(pid, cpu); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + + /* + * Look up the group leader (we will attach this counter to it): + */ + group_leader = NULL; + if (group_fd != -1) { + ret = -EINVAL; + group_file = fget_light(group_fd, &fput_needed); + if (!group_file) + goto err_put_context; + if (group_file->f_op != &perf_fops) + goto err_put_context; + + group_leader = group_file->private_data; + /* + * Do not allow a recursive hierarchy (this new sibling + * becoming part of another group-sibling): + */ + if (group_leader->group_leader != group_leader) + goto err_put_context; + /* + * Do not allow to attach to a group in a different + * task or CPU context: + */ + if (group_leader->ctx != ctx) + goto err_put_context; + /* + * Only a group leader can be exclusive or pinned + */ + if (attr.exclusive || attr.pinned) + goto err_put_context; + } + + counter = perf_counter_alloc(&attr, cpu, ctx, group_leader, + GFP_KERNEL); + ret = PTR_ERR(counter); + if (IS_ERR(counter)) + goto err_put_context; + + ret = anon_inode_getfd("[perf_counter]", &perf_fops, counter, 0); + if (ret < 0) + goto err_free_put_context; + + counter_file = fget_light(ret, &fput_needed2); + if (!counter_file) + goto err_free_put_context; + + counter->filp = counter_file; + WARN_ON_ONCE(ctx->parent_ctx); + mutex_lock(&ctx->mutex); + perf_install_in_context(ctx, counter, cpu); + ++ctx->generation; + mutex_unlock(&ctx->mutex); + + counter->owner = current; + get_task_struct(current); + mutex_lock(¤t->perf_counter_mutex); + list_add_tail(&counter->owner_entry, ¤t->perf_counter_list); + mutex_unlock(¤t->perf_counter_mutex); + + fput_light(counter_file, fput_needed2); + +out_fput: + fput_light(group_file, fput_needed); + + return ret; + +err_free_put_context: + kfree(counter); + +err_put_context: + put_ctx(ctx); + + goto out_fput; +} + +/* + * inherit a counter from parent task to child task: + */ +static struct perf_counter * +inherit_counter(struct perf_counter *parent_counter, + struct task_struct *parent, + struct perf_counter_context *parent_ctx, + struct task_struct *child, + struct perf_counter *group_leader, + struct perf_counter_context *child_ctx) +{ + struct perf_counter *child_counter; + + /* + * Instead of creating recursive hierarchies of counters, + * we link inherited counters back to the original parent, + * which has a filp for sure, which we use as the reference + * count: + */ + if (parent_counter->parent) + parent_counter = parent_counter->parent; + + child_counter = perf_counter_alloc(&parent_counter->attr, + parent_counter->cpu, child_ctx, + group_leader, GFP_KERNEL); + if (IS_ERR(child_counter)) + return child_counter; + get_ctx(child_ctx); + + /* + * Make the child state follow the state of the parent counter, + * not its attr.disabled bit. We hold the parent's mutex, + * so we won't race with perf_counter_{en, dis}able_family. + */ + if (parent_counter->state >= PERF_COUNTER_STATE_INACTIVE) + child_counter->state = PERF_COUNTER_STATE_INACTIVE; + else + child_counter->state = PERF_COUNTER_STATE_OFF; + + if (parent_counter->attr.freq) + child_counter->hw.sample_period = parent_counter->hw.sample_period; + + /* + * Link it up in the child's context: + */ + add_counter_to_ctx(child_counter, child_ctx); + + child_counter->parent = parent_counter; + /* + * inherit into child's child as well: + */ + child_counter->attr.inherit = 1; + + /* + * Get a reference to the parent filp - we will fput it + * when the child counter exits. This is safe to do because + * we are in the parent and we know that the filp still + * exists and has a nonzero count: + */ + atomic_long_inc(&parent_counter->filp->f_count); + + /* + * Link this into the parent counter's child list + */ + WARN_ON_ONCE(parent_counter->ctx->parent_ctx); + mutex_lock(&parent_counter->child_mutex); + list_add_tail(&child_counter->child_list, &parent_counter->child_list); + mutex_unlock(&parent_counter->child_mutex); + + return child_counter; +} + +static int inherit_group(struct perf_counter *parent_counter, + struct task_struct *parent, + struct perf_counter_context *parent_ctx, + struct task_struct *child, + struct perf_counter_context *child_ctx) +{ + struct perf_counter *leader; + struct perf_counter *sub; + struct perf_counter *child_ctr; + + leader = inherit_counter(parent_counter, parent, parent_ctx, + child, NULL, child_ctx); + if (IS_ERR(leader)) + return PTR_ERR(leader); + list_for_each_entry(sub, &parent_counter->sibling_list, list_entry) { + child_ctr = inherit_counter(sub, parent, parent_ctx, + child, leader, child_ctx); + if (IS_ERR(child_ctr)) + return PTR_ERR(child_ctr); + } + return 0; +} + +static void sync_child_counter(struct perf_counter *child_counter, + struct perf_counter *parent_counter) +{ + u64 child_val; + + child_val = atomic64_read(&child_counter->count); + + /* + * Add back the child's count to the parent's count: + */ + atomic64_add(child_val, &parent_counter->count); + atomic64_add(child_counter->total_time_enabled, + &parent_counter->child_total_time_enabled); + atomic64_add(child_counter->total_time_running, + &parent_counter->child_total_time_running); + + /* + * Remove this counter from the parent's list + */ + WARN_ON_ONCE(parent_counter->ctx->parent_ctx); + mutex_lock(&parent_counter->child_mutex); + list_del_init(&child_counter->child_list); + mutex_unlock(&parent_counter->child_mutex); + + /* + * Release the parent counter, if this was the last + * reference to it. + */ + fput(parent_counter->filp); +} + +static void +__perf_counter_exit_task(struct perf_counter *child_counter, + struct perf_counter_context *child_ctx) +{ + struct perf_counter *parent_counter; + + update_counter_times(child_counter); + perf_counter_remove_from_context(child_counter); + + parent_counter = child_counter->parent; + /* + * It can happen that parent exits first, and has counters + * that are still around due to the child reference. These + * counters need to be zapped - but otherwise linger. + */ + if (parent_counter) { + sync_child_counter(child_counter, parent_counter); + free_counter(child_counter); + } +} + +/* + * When a child task exits, feed back counter values to parent counters. + */ +void perf_counter_exit_task(struct task_struct *child) +{ + struct perf_counter *child_counter, *tmp; + struct perf_counter_context *child_ctx; + unsigned long flags; + + if (likely(!child->perf_counter_ctxp)) + return; + + local_irq_save(flags); + /* + * We can't reschedule here because interrupts are disabled, + * and either child is current or it is a task that can't be + * scheduled, so we are now safe from rescheduling changing + * our context. + */ + child_ctx = child->perf_counter_ctxp; + __perf_counter_task_sched_out(child_ctx); + + /* + * Take the context lock here so that if find_get_context is + * reading child->perf_counter_ctxp, we wait until it has + * incremented the context's refcount before we do put_ctx below. + */ + spin_lock(&child_ctx->lock); + child->perf_counter_ctxp = NULL; + if (child_ctx->parent_ctx) { + /* + * This context is a clone; unclone it so it can't get + * swapped to another process while we're removing all + * the counters from it. + */ + put_ctx(child_ctx->parent_ctx); + child_ctx->parent_ctx = NULL; + } + spin_unlock(&child_ctx->lock); + local_irq_restore(flags); + + /* + * We can recurse on the same lock type through: + * + * __perf_counter_exit_task() + * sync_child_counter() + * fput(parent_counter->filp) + * perf_release() + * mutex_lock(&ctx->mutex) + * + * But since its the parent context it won't be the same instance. + */ + mutex_lock_nested(&child_ctx->mutex, SINGLE_DEPTH_NESTING); + +again: + list_for_each_entry_safe(child_counter, tmp, &child_ctx->counter_list, + list_entry) + __perf_counter_exit_task(child_counter, child_ctx); + + /* + * If the last counter was a group counter, it will have appended all + * its siblings to the list, but we obtained 'tmp' before that which + * will still point to the list head terminating the iteration. + */ + if (!list_empty(&child_ctx->counter_list)) + goto again; + + mutex_unlock(&child_ctx->mutex); + + put_ctx(child_ctx); +} + +/* + * free an unexposed, unused context as created by inheritance by + * init_task below, used by fork() in case of fail. + */ +void perf_counter_free_task(struct task_struct *task) +{ + struct perf_counter_context *ctx = task->perf_counter_ctxp; + struct perf_counter *counter, *tmp; + + if (!ctx) + return; + + mutex_lock(&ctx->mutex); +again: + list_for_each_entry_safe(counter, tmp, &ctx->counter_list, list_entry) { + struct perf_counter *parent = counter->parent; + + if (WARN_ON_ONCE(!parent)) + continue; + + mutex_lock(&parent->child_mutex); + list_del_init(&counter->child_list); + mutex_unlock(&parent->child_mutex); + + fput(parent->filp); + + list_del_counter(counter, ctx); + free_counter(counter); + } + + if (!list_empty(&ctx->counter_list)) + goto again; + + mutex_unlock(&ctx->mutex); + + put_ctx(ctx); +} + +/* + * Initialize the perf_counter context in task_struct + */ +int perf_counter_init_task(struct task_struct *child) +{ + struct perf_counter_context *child_ctx, *parent_ctx; + struct perf_counter_context *cloned_ctx; + struct perf_counter *counter; + struct task_struct *parent = current; + int inherited_all = 1; + int ret = 0; + + child->perf_counter_ctxp = NULL; + + mutex_init(&child->perf_counter_mutex); + INIT_LIST_HEAD(&child->perf_counter_list); + + if (likely(!parent->perf_counter_ctxp)) + return 0; + + /* + * This is executed from the parent task context, so inherit + * counters that have been marked for cloning. + * First allocate and initialize a context for the child. + */ + + child_ctx = kmalloc(sizeof(struct perf_counter_context), GFP_KERNEL); + if (!child_ctx) + return -ENOMEM; + + __perf_counter_init_context(child_ctx, child); + child->perf_counter_ctxp = child_ctx; + get_task_struct(child); + + /* + * If the parent's context is a clone, pin it so it won't get + * swapped under us. + */ + parent_ctx = perf_pin_task_context(parent); + + /* + * No need to check if parent_ctx != NULL here; since we saw + * it non-NULL earlier, the only reason for it to become NULL + * is if we exit, and since we're currently in the middle of + * a fork we can't be exiting at the same time. + */ + + /* + * Lock the parent list. No need to lock the child - not PID + * hashed yet and not running, so nobody can access it. + */ + mutex_lock(&parent_ctx->mutex); + + /* + * We dont have to disable NMIs - we are only looking at + * the list, not manipulating it: + */ + list_for_each_entry_rcu(counter, &parent_ctx->event_list, event_entry) { + if (counter != counter->group_leader) + continue; + + if (!counter->attr.inherit) { + inherited_all = 0; + continue; + } + + ret = inherit_group(counter, parent, parent_ctx, + child, child_ctx); + if (ret) { + inherited_all = 0; + break; + } + } + + if (inherited_all) { + /* + * Mark the child context as a clone of the parent + * context, or of whatever the parent is a clone of. + * Note that if the parent is a clone, it could get + * uncloned at any point, but that doesn't matter + * because the list of counters and the generation + * count can't have changed since we took the mutex. + */ + cloned_ctx = rcu_dereference(parent_ctx->parent_ctx); + if (cloned_ctx) { + child_ctx->parent_ctx = cloned_ctx; + child_ctx->parent_gen = parent_ctx->parent_gen; + } else { + child_ctx->parent_ctx = parent_ctx; + child_ctx->parent_gen = parent_ctx->generation; + } + get_ctx(child_ctx->parent_ctx); + } + + mutex_unlock(&parent_ctx->mutex); + + perf_unpin_context(parent_ctx); + + return ret; +} + +static void __cpuinit perf_counter_init_cpu(int cpu) +{ + struct perf_cpu_context *cpuctx; + + cpuctx = &per_cpu(perf_cpu_context, cpu); + __perf_counter_init_context(&cpuctx->ctx, NULL); + + spin_lock(&perf_resource_lock); + cpuctx->max_pertask = perf_max_counters - perf_reserved_percpu; + spin_unlock(&perf_resource_lock); + + hw_perf_counter_setup(cpu); +} + +#ifdef CONFIG_HOTPLUG_CPU +static void __perf_counter_exit_cpu(void *info) +{ + struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context); + struct perf_counter_context *ctx = &cpuctx->ctx; + struct perf_counter *counter, *tmp; + + list_for_each_entry_safe(counter, tmp, &ctx->counter_list, list_entry) + __perf_counter_remove_from_context(counter); +} +static void perf_counter_exit_cpu(int cpu) +{ + struct perf_cpu_context *cpuctx = &per_cpu(perf_cpu_context, cpu); + struct perf_counter_context *ctx = &cpuctx->ctx; + + mutex_lock(&ctx->mutex); + smp_call_function_single(cpu, __perf_counter_exit_cpu, NULL, 1); + mutex_unlock(&ctx->mutex); +} +#else +static inline void perf_counter_exit_cpu(int cpu) { } +#endif + +static int __cpuinit +perf_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu) +{ + unsigned int cpu = (long)hcpu; + + switch (action) { + + case CPU_UP_PREPARE: + case CPU_UP_PREPARE_FROZEN: + perf_counter_init_cpu(cpu); + break; + + case CPU_DOWN_PREPARE: + case CPU_DOWN_PREPARE_FROZEN: + perf_counter_exit_cpu(cpu); + break; + + default: + break; + } + + return NOTIFY_OK; +} + +/* + * This has to have a higher priority than migration_notifier in sched.c. + */ +static struct notifier_block __cpuinitdata perf_cpu_nb = { + .notifier_call = perf_cpu_notify, + .priority = 20, +}; + +void __init perf_counter_init(void) +{ + perf_cpu_notify(&perf_cpu_nb, (unsigned long)CPU_UP_PREPARE, + (void *)(long)smp_processor_id()); + register_cpu_notifier(&perf_cpu_nb); +} + +static ssize_t perf_show_reserve_percpu(struct sysdev_class *class, char *buf) +{ + return sprintf(buf, "%d\n", perf_reserved_percpu); +} + +static ssize_t +perf_set_reserve_percpu(struct sysdev_class *class, + const char *buf, + size_t count) +{ + struct perf_cpu_context *cpuctx; + unsigned long val; + int err, cpu, mpt; + + err = strict_strtoul(buf, 10, &val); + if (err) + return err; + if (val > perf_max_counters) + return -EINVAL; + + spin_lock(&perf_resource_lock); + perf_reserved_percpu = val; + for_each_online_cpu(cpu) { + cpuctx = &per_cpu(perf_cpu_context, cpu); + spin_lock_irq(&cpuctx->ctx.lock); + mpt = min(perf_max_counters - cpuctx->ctx.nr_counters, + perf_max_counters - perf_reserved_percpu); + cpuctx->max_pertask = mpt; + spin_unlock_irq(&cpuctx->ctx.lock); + } + spin_unlock(&perf_resource_lock); + + return count; +} + +static ssize_t perf_show_overcommit(struct sysdev_class *class, char *buf) +{ + return sprintf(buf, "%d\n", perf_overcommit); +} + +static ssize_t +perf_set_overcommit(struct sysdev_class *class, const char *buf, size_t count) +{ + unsigned long val; + int err; + + err = strict_strtoul(buf, 10, &val); + if (err) + return err; + if (val > 1) + return -EINVAL; + + spin_lock(&perf_resource_lock); + perf_overcommit = val; + spin_unlock(&perf_resource_lock); + + return count; +} + +static SYSDEV_CLASS_ATTR( + reserve_percpu, + 0644, + perf_show_reserve_percpu, + perf_set_reserve_percpu + ); + +static SYSDEV_CLASS_ATTR( + overcommit, + 0644, + perf_show_overcommit, + perf_set_overcommit + ); + +static struct attribute *perfclass_attrs[] = { + &attr_reserve_percpu.attr, + &attr_overcommit.attr, + NULL +}; + +static struct attribute_group perfclass_attr_group = { + .attrs = perfclass_attrs, + .name = "perf_counters", +}; + +static int __init perf_counter_sysfs_init(void) +{ + return sysfs_create_group(&cpu_sysdev_class.kset.kobj, + &perfclass_attr_group); +} +device_initcall(perf_counter_sysfs_init); diff --git a/kernel/pid.c b/kernel/pid.c index b2e5f78fd281..31310b5d3f50 100644 --- a/kernel/pid.c +++ b/kernel/pid.c @@ -378,26 +378,15 @@ EXPORT_SYMBOL(pid_task); /* * Must be called under rcu_read_lock() or with tasklist_lock read-held. */ -struct task_struct *find_task_by_pid_type_ns(int type, int nr, - struct pid_namespace *ns) +struct task_struct *find_task_by_pid_ns(pid_t nr, struct pid_namespace *ns) { - return pid_task(find_pid_ns(nr, ns), type); + return pid_task(find_pid_ns(nr, ns), PIDTYPE_PID); } -EXPORT_SYMBOL(find_task_by_pid_type_ns); - struct task_struct *find_task_by_vpid(pid_t vnr) { - return find_task_by_pid_type_ns(PIDTYPE_PID, vnr, - current->nsproxy->pid_ns); + return find_task_by_pid_ns(vnr, current->nsproxy->pid_ns); } -EXPORT_SYMBOL(find_task_by_vpid); - -struct task_struct *find_task_by_pid_ns(pid_t nr, struct pid_namespace *ns) -{ - return find_task_by_pid_type_ns(PIDTYPE_PID, nr, ns); -} -EXPORT_SYMBOL(find_task_by_pid_ns); struct pid *get_task_pid(struct task_struct *task, enum pid_type type) { diff --git a/kernel/pid_namespace.c b/kernel/pid_namespace.c index 2d1001b4858d..821722ae58a7 100644 --- a/kernel/pid_namespace.c +++ b/kernel/pid_namespace.c @@ -67,9 +67,10 @@ err_alloc: return NULL; } -static struct pid_namespace *create_pid_namespace(unsigned int level) +static struct pid_namespace *create_pid_namespace(struct pid_namespace *parent_pid_ns) { struct pid_namespace *ns; + unsigned int level = parent_pid_ns->level + 1; int i; ns = kmem_cache_zalloc(pid_ns_cachep, GFP_KERNEL); @@ -86,6 +87,7 @@ static struct pid_namespace *create_pid_namespace(unsigned int level) kref_init(&ns->kref); ns->level = level; + ns->parent = get_pid_ns(parent_pid_ns); set_bit(0, ns->pidmap[0].page); atomic_set(&ns->pidmap[0].nr_free, BITS_PER_PAGE - 1); @@ -114,25 +116,11 @@ static void destroy_pid_namespace(struct pid_namespace *ns) struct pid_namespace *copy_pid_ns(unsigned long flags, struct pid_namespace *old_ns) { - struct pid_namespace *new_ns; - - BUG_ON(!old_ns); - new_ns = get_pid_ns(old_ns); if (!(flags & CLONE_NEWPID)) - goto out; - - new_ns = ERR_PTR(-EINVAL); + return get_pid_ns(old_ns); if (flags & CLONE_THREAD) - goto out_put; - - new_ns = create_pid_namespace(old_ns->level + 1); - if (!IS_ERR(new_ns)) - new_ns->parent = get_pid_ns(old_ns); - -out_put: - put_pid_ns(old_ns); -out: - return new_ns; + return ERR_PTR(-EINVAL); + return create_pid_namespace(old_ns); } void free_pid_ns(struct kref *kref) diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig index 23bd4daeb96b..72067cbdb37f 100644 --- a/kernel/power/Kconfig +++ b/kernel/power/Kconfig @@ -116,9 +116,13 @@ config SUSPEND_FREEZER Turning OFF this setting is NOT recommended! If in doubt, say Y. +config HIBERNATION_NVS + bool + config HIBERNATION bool "Hibernation (aka 'suspend to disk')" depends on PM && SWAP && ARCH_HIBERNATION_POSSIBLE + select HIBERNATION_NVS if HAS_IOMEM ---help--- Enable the suspend to disk (STD) functionality, which is usually called "hibernation" in user interfaces. STD checkpoints the diff --git a/kernel/power/Makefile b/kernel/power/Makefile index 720ea4f781bd..c3b81c30e5d5 100644 --- a/kernel/power/Makefile +++ b/kernel/power/Makefile @@ -6,6 +6,9 @@ endif obj-$(CONFIG_PM) += main.o obj-$(CONFIG_PM_SLEEP) += console.o obj-$(CONFIG_FREEZER) += process.o -obj-$(CONFIG_HIBERNATION) += swsusp.o disk.o snapshot.o swap.o user.o +obj-$(CONFIG_SUSPEND) += suspend.o +obj-$(CONFIG_PM_TEST_SUSPEND) += suspend_test.o +obj-$(CONFIG_HIBERNATION) += swsusp.o hibernate.o snapshot.o swap.o user.o +obj-$(CONFIG_HIBERNATION_NVS) += hibernate_nvs.o obj-$(CONFIG_MAGIC_SYSRQ) += poweroff.o diff --git a/kernel/power/disk.c b/kernel/power/hibernate.c similarity index 96% rename from kernel/power/disk.c rename to kernel/power/hibernate.c index 5cb080e7eebd..81d2e7464893 100644 --- a/kernel/power/disk.c +++ b/kernel/power/hibernate.c @@ -1,12 +1,12 @@ /* - * kernel/power/disk.c - Suspend-to-disk support. + * kernel/power/hibernate.c - Hibernation (a.k.a suspend-to-disk) support. * * Copyright (c) 2003 Patrick Mochel * Copyright (c) 2003 Open Source Development Lab * Copyright (c) 2004 Pavel Machek + * Copyright (c) 2009 Rafael J. Wysocki, Novell Inc. * * This file is released under the GPLv2. - * */ #include @@ -215,13 +215,13 @@ static int create_image(int platform_mode) if (error) return error; - /* At this point, device_suspend() has been called, but *not* - * device_power_down(). We *must* call device_power_down() now. + /* At this point, dpm_suspend_start() has been called, but *not* + * dpm_suspend_noirq(). We *must* call dpm_suspend_noirq() now. * Otherwise, drivers for some devices (e.g. interrupt controllers) * become desynchronized with the actual state of the hardware * at resume time, and evil weirdness ensues. */ - error = device_power_down(PMSG_FREEZE); + error = dpm_suspend_noirq(PMSG_FREEZE); if (error) { printk(KERN_ERR "PM: Some devices failed to power down, " "aborting hibernation\n"); @@ -262,7 +262,7 @@ static int create_image(int platform_mode) Power_up: sysdev_resume(); - /* NOTE: device_power_up() is just a resume() for devices + /* NOTE: dpm_resume_noirq() is just a resume() for devices * that suspended with irqs off ... no overall powerup. */ @@ -275,7 +275,7 @@ static int create_image(int platform_mode) Platform_finish: platform_finish(platform_mode); - device_power_up(in_suspend ? + dpm_resume_noirq(in_suspend ? (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); return error; @@ -304,7 +304,7 @@ int hibernation_snapshot(int platform_mode) goto Close; suspend_console(); - error = device_suspend(PMSG_FREEZE); + error = dpm_suspend_start(PMSG_FREEZE); if (error) goto Recover_platform; @@ -315,7 +315,7 @@ int hibernation_snapshot(int platform_mode) /* Control returns here after successful restore */ Resume_devices: - device_resume(in_suspend ? + dpm_resume_end(in_suspend ? (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); resume_console(); Close: @@ -339,7 +339,7 @@ static int resume_target_kernel(bool platform_mode) { int error; - error = device_power_down(PMSG_QUIESCE); + error = dpm_suspend_noirq(PMSG_QUIESCE); if (error) { printk(KERN_ERR "PM: Some devices failed to power down, " "aborting resume\n"); @@ -394,7 +394,7 @@ static int resume_target_kernel(bool platform_mode) Cleanup: platform_restore_cleanup(platform_mode); - device_power_up(PMSG_RECOVER); + dpm_resume_noirq(PMSG_RECOVER); return error; } @@ -414,10 +414,10 @@ int hibernation_restore(int platform_mode) pm_prepare_console(); suspend_console(); - error = device_suspend(PMSG_QUIESCE); + error = dpm_suspend_start(PMSG_QUIESCE); if (!error) { error = resume_target_kernel(platform_mode); - device_resume(PMSG_RECOVER); + dpm_resume_end(PMSG_RECOVER); } resume_console(); pm_restore_console(); @@ -447,14 +447,14 @@ int hibernation_platform_enter(void) entering_platform_hibernation = true; suspend_console(); - error = device_suspend(PMSG_HIBERNATE); + error = dpm_suspend_start(PMSG_HIBERNATE); if (error) { if (hibernation_ops->recover) hibernation_ops->recover(); goto Resume_devices; } - error = device_power_down(PMSG_HIBERNATE); + error = dpm_suspend_noirq(PMSG_HIBERNATE); if (error) goto Resume_devices; @@ -479,11 +479,11 @@ int hibernation_platform_enter(void) Platofrm_finish: hibernation_ops->finish(); - device_power_up(PMSG_RESTORE); + dpm_suspend_noirq(PMSG_RESTORE); Resume_devices: entering_platform_hibernation = false; - device_resume(PMSG_RESTORE); + dpm_resume_end(PMSG_RESTORE); resume_console(); Close: diff --git a/kernel/power/hibernate_nvs.c b/kernel/power/hibernate_nvs.c new file mode 100644 index 000000000000..39ac698ef836 --- /dev/null +++ b/kernel/power/hibernate_nvs.c @@ -0,0 +1,135 @@ +/* + * linux/kernel/power/hibernate_nvs.c - Routines for handling NVS memory + * + * Copyright (C) 2008,2009 Rafael J. Wysocki , Novell Inc. + * + * This file is released under the GPLv2. + */ + +#include +#include +#include +#include +#include + +/* + * Platforms, like ACPI, may want us to save some memory used by them during + * hibernation and to restore the contents of this memory during the subsequent + * resume. The code below implements a mechanism allowing us to do that. + */ + +struct nvs_page { + unsigned long phys_start; + unsigned int size; + void *kaddr; + void *data; + struct list_head node; +}; + +static LIST_HEAD(nvs_list); + +/** + * hibernate_nvs_register - register platform NVS memory region to save + * @start - physical address of the region + * @size - size of the region + * + * The NVS region need not be page-aligned (both ends) and we arrange + * things so that the data from page-aligned addresses in this region will + * be copied into separate RAM pages. + */ +int hibernate_nvs_register(unsigned long start, unsigned long size) +{ + struct nvs_page *entry, *next; + + while (size > 0) { + unsigned int nr_bytes; + + entry = kzalloc(sizeof(struct nvs_page), GFP_KERNEL); + if (!entry) + goto Error; + + list_add_tail(&entry->node, &nvs_list); + entry->phys_start = start; + nr_bytes = PAGE_SIZE - (start & ~PAGE_MASK); + entry->size = (size < nr_bytes) ? size : nr_bytes; + + start += entry->size; + size -= entry->size; + } + return 0; + + Error: + list_for_each_entry_safe(entry, next, &nvs_list, node) { + list_del(&entry->node); + kfree(entry); + } + return -ENOMEM; +} + +/** + * hibernate_nvs_free - free data pages allocated for saving NVS regions + */ +void hibernate_nvs_free(void) +{ + struct nvs_page *entry; + + list_for_each_entry(entry, &nvs_list, node) + if (entry->data) { + free_page((unsigned long)entry->data); + entry->data = NULL; + if (entry->kaddr) { + iounmap(entry->kaddr); + entry->kaddr = NULL; + } + } +} + +/** + * hibernate_nvs_alloc - allocate memory necessary for saving NVS regions + */ +int hibernate_nvs_alloc(void) +{ + struct nvs_page *entry; + + list_for_each_entry(entry, &nvs_list, node) { + entry->data = (void *)__get_free_page(GFP_KERNEL); + if (!entry->data) { + hibernate_nvs_free(); + return -ENOMEM; + } + } + return 0; +} + +/** + * hibernate_nvs_save - save NVS memory regions + */ +void hibernate_nvs_save(void) +{ + struct nvs_page *entry; + + printk(KERN_INFO "PM: Saving platform NVS memory\n"); + + list_for_each_entry(entry, &nvs_list, node) + if (entry->data) { + entry->kaddr = ioremap(entry->phys_start, entry->size); + memcpy(entry->data, entry->kaddr, entry->size); + } +} + +/** + * hibernate_nvs_restore - restore NVS memory regions + * + * This function is going to be called with interrupts disabled, so it + * cannot iounmap the virtual addresses used to access the NVS region. + */ +void hibernate_nvs_restore(void) +{ + struct nvs_page *entry; + + printk(KERN_INFO "PM: Restoring platform NVS memory\n"); + + list_for_each_entry(entry, &nvs_list, node) + if (entry->data) + memcpy(entry->kaddr, entry->data, entry->size); +} diff --git a/kernel/power/main.c b/kernel/power/main.c index 868028280d13..f710e36930cc 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -8,20 +8,9 @@ * */ -#include -#include #include #include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include #include "power.h" @@ -119,373 +108,6 @@ power_attr(pm_test); #endif /* CONFIG_PM_SLEEP */ -#ifdef CONFIG_SUSPEND - -static int suspend_test(int level) -{ -#ifdef CONFIG_PM_DEBUG - if (pm_test_level == level) { - printk(KERN_INFO "suspend debug: Waiting for 5 seconds.\n"); - mdelay(5000); - return 1; - } -#endif /* !CONFIG_PM_DEBUG */ - return 0; -} - -#ifdef CONFIG_PM_TEST_SUSPEND - -/* - * We test the system suspend code by setting an RTC wakealarm a short - * time in the future, then suspending. Suspending the devices won't - * normally take long ... some systems only need a few milliseconds. - * - * The time it takes is system-specific though, so when we test this - * during system bootup we allow a LOT of time. - */ -#define TEST_SUSPEND_SECONDS 5 - -static unsigned long suspend_test_start_time; - -static void suspend_test_start(void) -{ - /* FIXME Use better timebase than "jiffies", ideally a clocksource. - * What we want is a hardware counter that will work correctly even - * during the irqs-are-off stages of the suspend/resume cycle... - */ - suspend_test_start_time = jiffies; -} - -static void suspend_test_finish(const char *label) -{ - long nj = jiffies - suspend_test_start_time; - unsigned msec; - - msec = jiffies_to_msecs(abs(nj)); - pr_info("PM: %s took %d.%03d seconds\n", label, - msec / 1000, msec % 1000); - - /* Warning on suspend means the RTC alarm period needs to be - * larger -- the system was sooo slooowwww to suspend that the - * alarm (should have) fired before the system went to sleep! - * - * Warning on either suspend or resume also means the system - * has some performance issues. The stack dump of a WARN_ON - * is more likely to get the right attention than a printk... - */ - WARN(msec > (TEST_SUSPEND_SECONDS * 1000), "Component: %s\n", label); -} - -#else - -static void suspend_test_start(void) -{ -} - -static void suspend_test_finish(const char *label) -{ -} - -#endif - -/* This is just an arbitrary number */ -#define FREE_PAGE_NUMBER (100) - -static struct platform_suspend_ops *suspend_ops; - -/** - * suspend_set_ops - Set the global suspend method table. - * @ops: Pointer to ops structure. - */ - -void suspend_set_ops(struct platform_suspend_ops *ops) -{ - mutex_lock(&pm_mutex); - suspend_ops = ops; - mutex_unlock(&pm_mutex); -} - -/** - * suspend_valid_only_mem - generic memory-only valid callback - * - * Platform drivers that implement mem suspend only and only need - * to check for that in their .valid callback can use this instead - * of rolling their own .valid callback. - */ -int suspend_valid_only_mem(suspend_state_t state) -{ - return state == PM_SUSPEND_MEM; -} - -/** - * suspend_prepare - Do prep work before entering low-power state. - * - * This is common code that is called for each state that we're entering. - * Run suspend notifiers, allocate a console and stop all processes. - */ -static int suspend_prepare(void) -{ - int error; - unsigned int free_pages; - - if (!suspend_ops || !suspend_ops->enter) - return -EPERM; - - pm_prepare_console(); - - error = pm_notifier_call_chain(PM_SUSPEND_PREPARE); - if (error) - goto Finish; - - error = usermodehelper_disable(); - if (error) - goto Finish; - - if (suspend_freeze_processes()) { - error = -EAGAIN; - goto Thaw; - } - - free_pages = global_page_state(NR_FREE_PAGES); - if (free_pages < FREE_PAGE_NUMBER) { - pr_debug("PM: free some memory\n"); - shrink_all_memory(FREE_PAGE_NUMBER - free_pages); - if (nr_free_pages() < FREE_PAGE_NUMBER) { - error = -ENOMEM; - printk(KERN_ERR "PM: No enough memory\n"); - } - } - if (!error) - return 0; - - Thaw: - suspend_thaw_processes(); - usermodehelper_enable(); - Finish: - pm_notifier_call_chain(PM_POST_SUSPEND); - pm_restore_console(); - return error; -} - -/* default implementation */ -void __attribute__ ((weak)) arch_suspend_disable_irqs(void) -{ - local_irq_disable(); -} - -/* default implementation */ -void __attribute__ ((weak)) arch_suspend_enable_irqs(void) -{ - local_irq_enable(); -} - -/** - * suspend_enter - enter the desired system sleep state. - * @state: state to enter - * - * This function should be called after devices have been suspended. - */ -static int suspend_enter(suspend_state_t state) -{ - int error; - - if (suspend_ops->prepare) { - error = suspend_ops->prepare(); - if (error) - return error; - } - - error = device_power_down(PMSG_SUSPEND); - if (error) { - printk(KERN_ERR "PM: Some devices failed to power down\n"); - goto Platfrom_finish; - } - - if (suspend_ops->prepare_late) { - error = suspend_ops->prepare_late(); - if (error) - goto Power_up_devices; - } - - if (suspend_test(TEST_PLATFORM)) - goto Platform_wake; - - error = disable_nonboot_cpus(); - if (error || suspend_test(TEST_CPUS)) - goto Enable_cpus; - - arch_suspend_disable_irqs(); - BUG_ON(!irqs_disabled()); - - error = sysdev_suspend(PMSG_SUSPEND); - if (!error) { - if (!suspend_test(TEST_CORE)) - error = suspend_ops->enter(state); - sysdev_resume(); - } - - arch_suspend_enable_irqs(); - BUG_ON(irqs_disabled()); - - Enable_cpus: - enable_nonboot_cpus(); - - Platform_wake: - if (suspend_ops->wake) - suspend_ops->wake(); - - Power_up_devices: - device_power_up(PMSG_RESUME); - - Platfrom_finish: - if (suspend_ops->finish) - suspend_ops->finish(); - - return error; -} - -/** - * suspend_devices_and_enter - suspend devices and enter the desired system - * sleep state. - * @state: state to enter - */ -int suspend_devices_and_enter(suspend_state_t state) -{ - int error; - - if (!suspend_ops) - return -ENOSYS; - - if (suspend_ops->begin) { - error = suspend_ops->begin(state); - if (error) - goto Close; - } - suspend_console(); - suspend_test_start(); - error = device_suspend(PMSG_SUSPEND); - if (error) { - printk(KERN_ERR "PM: Some devices failed to suspend\n"); - goto Recover_platform; - } - suspend_test_finish("suspend devices"); - if (suspend_test(TEST_DEVICES)) - goto Recover_platform; - - suspend_enter(state); - - Resume_devices: - suspend_test_start(); - device_resume(PMSG_RESUME); - suspend_test_finish("resume devices"); - resume_console(); - Close: - if (suspend_ops->end) - suspend_ops->end(); - return error; - - Recover_platform: - if (suspend_ops->recover) - suspend_ops->recover(); - goto Resume_devices; -} - -/** - * suspend_finish - Do final work before exiting suspend sequence. - * - * Call platform code to clean up, restart processes, and free the - * console that we've allocated. This is not called for suspend-to-disk. - */ -static void suspend_finish(void) -{ - suspend_thaw_processes(); - usermodehelper_enable(); - pm_notifier_call_chain(PM_POST_SUSPEND); - pm_restore_console(); -} - - - - -static const char * const pm_states[PM_SUSPEND_MAX] = { - [PM_SUSPEND_STANDBY] = "standby", - [PM_SUSPEND_MEM] = "mem", -}; - -static inline int valid_state(suspend_state_t state) -{ - /* All states need lowlevel support and need to be valid - * to the lowlevel implementation, no valid callback - * implies that none are valid. */ - if (!suspend_ops || !suspend_ops->valid || !suspend_ops->valid(state)) - return 0; - return 1; -} - - -/** - * enter_state - Do common work of entering low-power state. - * @state: pm_state structure for state we're entering. - * - * Make sure we're the only ones trying to enter a sleep state. Fail - * if someone has beat us to it, since we don't want anything weird to - * happen when we wake up. - * Then, do the setup for suspend, enter the state, and cleaup (after - * we've woken up). - */ -static int enter_state(suspend_state_t state) -{ - int error; - - if (!valid_state(state)) - return -ENODEV; - - if (!mutex_trylock(&pm_mutex)) - return -EBUSY; - - printk(KERN_INFO "PM: Syncing filesystems ... "); - sys_sync(); - printk("done.\n"); - - pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]); - error = suspend_prepare(); - if (error) - goto Unlock; - - if (suspend_test(TEST_FREEZER)) - goto Finish; - - pr_debug("PM: Entering %s sleep\n", pm_states[state]); - error = suspend_devices_and_enter(state); - - Finish: - pr_debug("PM: Finishing wakeup.\n"); - suspend_finish(); - Unlock: - mutex_unlock(&pm_mutex); - return error; -} - - -/** - * pm_suspend - Externally visible function for suspending system. - * @state: Enumerated value of state to enter. - * - * Determine whether or not value is within range, get state - * structure, and enter (above). - */ - -int pm_suspend(suspend_state_t state) -{ - if (state > PM_SUSPEND_ON && state <= PM_SUSPEND_MAX) - return enter_state(state); - return -EINVAL; -} - -EXPORT_SYMBOL(pm_suspend); - -#endif /* CONFIG_SUSPEND */ - struct kobject *power_kobj; /** @@ -498,7 +120,6 @@ struct kobject *power_kobj; * store() accepts one of those strings, translates it into the * proper enumerated value, and initiates a suspend transition. */ - static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { @@ -596,7 +217,6 @@ static struct attribute_group attr_group = { .attrs = g, }; - static int __init pm_init(void) { power_kobj = kobject_create_and_add("power", NULL); @@ -606,144 +226,3 @@ static int __init pm_init(void) } core_initcall(pm_init); - - -#ifdef CONFIG_PM_TEST_SUSPEND - -#include - -/* - * To test system suspend, we need a hands-off mechanism to resume the - * system. RTCs wake alarms are a common self-contained mechanism. - */ - -static void __init test_wakealarm(struct rtc_device *rtc, suspend_state_t state) -{ - static char err_readtime[] __initdata = - KERN_ERR "PM: can't read %s time, err %d\n"; - static char err_wakealarm [] __initdata = - KERN_ERR "PM: can't set %s wakealarm, err %d\n"; - static char err_suspend[] __initdata = - KERN_ERR "PM: suspend test failed, error %d\n"; - static char info_test[] __initdata = - KERN_INFO "PM: test RTC wakeup from '%s' suspend\n"; - - unsigned long now; - struct rtc_wkalrm alm; - int status; - - /* this may fail if the RTC hasn't been initialized */ - status = rtc_read_time(rtc, &alm.time); - if (status < 0) { - printk(err_readtime, dev_name(&rtc->dev), status); - return; - } - rtc_tm_to_time(&alm.time, &now); - - memset(&alm, 0, sizeof alm); - rtc_time_to_tm(now + TEST_SUSPEND_SECONDS, &alm.time); - alm.enabled = true; - - status = rtc_set_alarm(rtc, &alm); - if (status < 0) { - printk(err_wakealarm, dev_name(&rtc->dev), status); - return; - } - - if (state == PM_SUSPEND_MEM) { - printk(info_test, pm_states[state]); - status = pm_suspend(state); - if (status == -ENODEV) - state = PM_SUSPEND_STANDBY; - } - if (state == PM_SUSPEND_STANDBY) { - printk(info_test, pm_states[state]); - status = pm_suspend(state); - } - if (status < 0) - printk(err_suspend, status); - - /* Some platforms can't detect that the alarm triggered the - * wakeup, or (accordingly) disable it after it afterwards. - * It's supposed to give oneshot behavior; cope. - */ - alm.enabled = false; - rtc_set_alarm(rtc, &alm); -} - -static int __init has_wakealarm(struct device *dev, void *name_ptr) -{ - struct rtc_device *candidate = to_rtc_device(dev); - - if (!candidate->ops->set_alarm) - return 0; - if (!device_may_wakeup(candidate->dev.parent)) - return 0; - - *(const char **)name_ptr = dev_name(dev); - return 1; -} - -/* - * Kernel options like "test_suspend=mem" force suspend/resume sanity tests - * at startup time. They're normally disabled, for faster boot and because - * we can't know which states really work on this particular system. - */ -static suspend_state_t test_state __initdata = PM_SUSPEND_ON; - -static char warn_bad_state[] __initdata = - KERN_WARNING "PM: can't test '%s' suspend state\n"; - -static int __init setup_test_suspend(char *value) -{ - unsigned i; - - /* "=mem" ==> "mem" */ - value++; - for (i = 0; i < PM_SUSPEND_MAX; i++) { - if (!pm_states[i]) - continue; - if (strcmp(pm_states[i], value) != 0) - continue; - test_state = (__force suspend_state_t) i; - return 0; - } - printk(warn_bad_state, value); - return 0; -} -__setup("test_suspend", setup_test_suspend); - -static int __init test_suspend(void) -{ - static char warn_no_rtc[] __initdata = - KERN_WARNING "PM: no wakealarm-capable RTC driver is ready\n"; - - char *pony = NULL; - struct rtc_device *rtc = NULL; - - /* PM is initialized by now; is that state testable? */ - if (test_state == PM_SUSPEND_ON) - goto done; - if (!valid_state(test_state)) { - printk(warn_bad_state, pm_states[test_state]); - goto done; - } - - /* RTCs have initialized by now too ... can we use one? */ - class_find_device(rtc_class, NULL, &pony, has_wakealarm); - if (pony) - rtc = rtc_class_open(pony); - if (!rtc) { - printk(warn_no_rtc); - goto done; - } - - /* go for it */ - test_wakealarm(rtc, test_state); - rtc_class_close(rtc); -done: - return 0; -} -late_initcall(test_suspend); - -#endif /* CONFIG_PM_TEST_SUSPEND */ diff --git a/kernel/power/power.h b/kernel/power/power.h index 46b5ec7a3afb..26d5a26f82e3 100644 --- a/kernel/power/power.h +++ b/kernel/power/power.h @@ -45,7 +45,7 @@ static inline char *check_image_kernel(struct swsusp_info *info) */ #define SPARE_PAGES ((1024 * 1024) >> PAGE_SHIFT) -/* kernel/power/disk.c */ +/* kernel/power/hibernate.c */ extern int hibernation_snapshot(int platform_mode); extern int hibernation_restore(int platform_mode); extern int hibernation_platform_enter(void); @@ -74,7 +74,7 @@ extern asmlinkage int swsusp_arch_resume(void); extern int create_basic_memory_bitmaps(void); extern void free_basic_memory_bitmaps(void); -extern unsigned int count_data_pages(void); +extern int swsusp_shrink_memory(void); /** * Auxiliary structure used for reading the snapshot image data and @@ -147,9 +147,8 @@ extern int swsusp_swap_in_use(void); */ #define SF_PLATFORM_MODE 1 -/* kernel/power/disk.c */ +/* kernel/power/hibernate.c */ extern int swsusp_check(void); -extern int swsusp_shrink_memory(void); extern void swsusp_free(void); extern int swsusp_read(unsigned int *flags_p); extern int swsusp_write(unsigned int flags); @@ -161,22 +160,36 @@ extern void swsusp_show_speed(struct timeval *, struct timeval *, unsigned int, char *); #ifdef CONFIG_SUSPEND -/* kernel/power/main.c */ +/* kernel/power/suspend.c */ +extern const char *const pm_states[]; + +extern bool valid_state(suspend_state_t state); extern int suspend_devices_and_enter(suspend_state_t state); +extern int enter_state(suspend_state_t state); #else /* !CONFIG_SUSPEND */ static inline int suspend_devices_and_enter(suspend_state_t state) { return -ENOSYS; } +static inline int enter_state(suspend_state_t state) { return -ENOSYS; } +static inline bool valid_state(suspend_state_t state) { return false; } #endif /* !CONFIG_SUSPEND */ +#ifdef CONFIG_PM_TEST_SUSPEND +/* kernel/power/suspend_test.c */ +extern void suspend_test_start(void); +extern void suspend_test_finish(const char *label); +#else /* !CONFIG_PM_TEST_SUSPEND */ +static inline void suspend_test_start(void) {} +static inline void suspend_test_finish(const char *label) {} +#endif /* !CONFIG_PM_TEST_SUSPEND */ + #ifdef CONFIG_PM_SLEEP /* kernel/power/main.c */ extern int pm_notifier_call_chain(unsigned long val); #endif #ifdef CONFIG_HIGHMEM -unsigned int count_highmem_pages(void); int restore_highmem(void); #else static inline unsigned int count_highmem_pages(void) { return 0; } diff --git a/kernel/power/poweroff.c b/kernel/power/poweroff.c index 97890831e1b5..e8b337006276 100644 --- a/kernel/power/poweroff.c +++ b/kernel/power/poweroff.c @@ -34,7 +34,7 @@ static struct sysrq_key_op sysrq_poweroff_op = { .handler = handle_poweroff, .help_msg = "powerOff", .action_msg = "Power Off", - .enable_mask = SYSRQ_ENABLE_BOOT, + .enable_mask = SYSRQ_ENABLE_BOOT, }; static int pm_sysrq_init(void) diff --git a/kernel/power/process.c b/kernel/power/process.c index ca634019497a..da2072d73811 100644 --- a/kernel/power/process.c +++ b/kernel/power/process.c @@ -117,9 +117,12 @@ int freeze_processes(void) if (error) goto Exit; printk("done."); + + oom_killer_disable(); Exit: BUG_ON(in_atomic()); printk("\n"); + return error; } @@ -145,6 +148,8 @@ static void thaw_tasks(bool nosig_only) void thaw_processes(void) { + oom_killer_enable(); + printk("Restarting tasks ... "); thaw_tasks(true); thaw_tasks(false); diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index 33e2e4a819f9..523a451b45d3 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c @@ -39,6 +39,14 @@ static int swsusp_page_is_free(struct page *); static void swsusp_set_page_forbidden(struct page *); static void swsusp_unset_page_forbidden(struct page *); +/* + * Preferred image size in bytes (tunable via /sys/power/image_size). + * When it is set to N, swsusp will do its best to ensure the image + * size will not exceed N bytes, but if that is impossible, it will + * try to create the smallest image possible. + */ +unsigned long image_size = 500 * 1024 * 1024; + /* List of PBEs needed for restoring the pages that were allocated before * the suspend and included in the suspend image, but have also been * allocated by the "resume" kernel, so their contents cannot be written @@ -840,7 +848,7 @@ static struct page *saveable_highmem_page(struct zone *zone, unsigned long pfn) * pages. */ -unsigned int count_highmem_pages(void) +static unsigned int count_highmem_pages(void) { struct zone *zone; unsigned int n = 0; @@ -902,7 +910,7 @@ static struct page *saveable_page(struct zone *zone, unsigned long pfn) * pages. */ -unsigned int count_data_pages(void) +static unsigned int count_data_pages(void) { struct zone *zone; unsigned long pfn, max_zone_pfn; @@ -1058,6 +1066,74 @@ void swsusp_free(void) buffer = NULL; } +/** + * swsusp_shrink_memory - Try to free as much memory as needed + * + * ... but do not OOM-kill anyone + * + * Notice: all userland should be stopped before it is called, or + * livelock is possible. + */ + +#define SHRINK_BITE 10000 +static inline unsigned long __shrink_memory(long tmp) +{ + if (tmp > SHRINK_BITE) + tmp = SHRINK_BITE; + return shrink_all_memory(tmp); +} + +int swsusp_shrink_memory(void) +{ + long tmp; + struct zone *zone; + unsigned long pages = 0; + unsigned int i = 0; + char *p = "-\\|/"; + struct timeval start, stop; + + printk(KERN_INFO "PM: Shrinking memory... "); + do_gettimeofday(&start); + do { + long size, highmem_size; + + highmem_size = count_highmem_pages(); + size = count_data_pages() + PAGES_FOR_IO + SPARE_PAGES; + tmp = size; + size += highmem_size; + for_each_populated_zone(zone) { + tmp += snapshot_additional_pages(zone); + if (is_highmem(zone)) { + highmem_size -= + zone_page_state(zone, NR_FREE_PAGES); + } else { + tmp -= zone_page_state(zone, NR_FREE_PAGES); + tmp += zone->lowmem_reserve[ZONE_NORMAL]; + } + } + + if (highmem_size < 0) + highmem_size = 0; + + tmp += highmem_size; + if (tmp > 0) { + tmp = __shrink_memory(tmp); + if (!tmp) + return -ENOMEM; + pages += tmp; + } else if (size > image_size / PAGE_SIZE) { + tmp = __shrink_memory(size - (image_size / PAGE_SIZE)); + pages += tmp; + } + printk("\b%c", p[i++%4]); + } while (tmp > 0); + do_gettimeofday(&stop); + printk("\bdone (%lu pages freed)\n", pages); + swsusp_show_speed(&start, &stop, pages, "Freed"); + + return 0; +} + #ifdef CONFIG_HIGHMEM /** * count_pages_for_highmem - compute the number of non-highmem pages diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c new file mode 100644 index 000000000000..6f10dfc2d3e9 --- /dev/null +++ b/kernel/power/suspend.c @@ -0,0 +1,300 @@ +/* + * kernel/power/suspend.c - Suspend to RAM and standby functionality. + * + * Copyright (c) 2003 Patrick Mochel + * Copyright (c) 2003 Open Source Development Lab + * Copyright (c) 2009 Rafael J. Wysocki , Novell Inc. + * + * This file is released under the GPLv2. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "power.h" + +const char *const pm_states[PM_SUSPEND_MAX] = { + [PM_SUSPEND_STANDBY] = "standby", + [PM_SUSPEND_MEM] = "mem", +}; + +static struct platform_suspend_ops *suspend_ops; + +/** + * suspend_set_ops - Set the global suspend method table. + * @ops: Pointer to ops structure. + */ +void suspend_set_ops(struct platform_suspend_ops *ops) +{ + mutex_lock(&pm_mutex); + suspend_ops = ops; + mutex_unlock(&pm_mutex); +} + +bool valid_state(suspend_state_t state) +{ + /* + * All states need lowlevel support and need to be valid to the lowlevel + * implementation, no valid callback implies that none are valid. + */ + return suspend_ops && suspend_ops->valid && suspend_ops->valid(state); +} + +/** + * suspend_valid_only_mem - generic memory-only valid callback + * + * Platform drivers that implement mem suspend only and only need + * to check for that in their .valid callback can use this instead + * of rolling their own .valid callback. + */ +int suspend_valid_only_mem(suspend_state_t state) +{ + return state == PM_SUSPEND_MEM; +} + +static int suspend_test(int level) +{ +#ifdef CONFIG_PM_DEBUG + if (pm_test_level == level) { + printk(KERN_INFO "suspend debug: Waiting for 5 seconds.\n"); + mdelay(5000); + return 1; + } +#endif /* !CONFIG_PM_DEBUG */ + return 0; +} + +/** + * suspend_prepare - Do prep work before entering low-power state. + * + * This is common code that is called for each state that we're entering. + * Run suspend notifiers, allocate a console and stop all processes. + */ +static int suspend_prepare(void) +{ + int error; + + if (!suspend_ops || !suspend_ops->enter) + return -EPERM; + + pm_prepare_console(); + + error = pm_notifier_call_chain(PM_SUSPEND_PREPARE); + if (error) + goto Finish; + + error = usermodehelper_disable(); + if (error) + goto Finish; + + error = suspend_freeze_processes(); + if (!error) + return 0; + + suspend_thaw_processes(); + usermodehelper_enable(); + Finish: + pm_notifier_call_chain(PM_POST_SUSPEND); + pm_restore_console(); + return error; +} + +/* default implementation */ +void __attribute__ ((weak)) arch_suspend_disable_irqs(void) +{ + local_irq_disable(); +} + +/* default implementation */ +void __attribute__ ((weak)) arch_suspend_enable_irqs(void) +{ + local_irq_enable(); +} + +/** + * suspend_enter - enter the desired system sleep state. + * @state: state to enter + * + * This function should be called after devices have been suspended. + */ +static int suspend_enter(suspend_state_t state) +{ + int error; + + if (suspend_ops->prepare) { + error = suspend_ops->prepare(); + if (error) + return error; + } + + error = dpm_suspend_noirq(PMSG_SUSPEND); + if (error) { + printk(KERN_ERR "PM: Some devices failed to power down\n"); + goto Platfrom_finish; + } + + if (suspend_ops->prepare_late) { + error = suspend_ops->prepare_late(); + if (error) + goto Power_up_devices; + } + + if (suspend_test(TEST_PLATFORM)) + goto Platform_wake; + + error = disable_nonboot_cpus(); + if (error || suspend_test(TEST_CPUS)) + goto Enable_cpus; + + arch_suspend_disable_irqs(); + BUG_ON(!irqs_disabled()); + + error = sysdev_suspend(PMSG_SUSPEND); + if (!error) { + if (!suspend_test(TEST_CORE)) + error = suspend_ops->enter(state); + sysdev_resume(); + } + + arch_suspend_enable_irqs(); + BUG_ON(irqs_disabled()); + + Enable_cpus: + enable_nonboot_cpus(); + + Platform_wake: + if (suspend_ops->wake) + suspend_ops->wake(); + + Power_up_devices: + dpm_resume_noirq(PMSG_RESUME); + + Platfrom_finish: + if (suspend_ops->finish) + suspend_ops->finish(); + + return error; +} + +/** + * suspend_devices_and_enter - suspend devices and enter the desired system + * sleep state. + * @state: state to enter + */ +int suspend_devices_and_enter(suspend_state_t state) +{ + int error; + + if (!suspend_ops) + return -ENOSYS; + + if (suspend_ops->begin) { + error = suspend_ops->begin(state); + if (error) + goto Close; + } + suspend_console(); + suspend_test_start(); + error = dpm_suspend_start(PMSG_SUSPEND); + if (error) { + printk(KERN_ERR "PM: Some devices failed to suspend\n"); + goto Recover_platform; + } + suspend_test_finish("suspend devices"); + if (suspend_test(TEST_DEVICES)) + goto Recover_platform; + + suspend_enter(state); + + Resume_devices: + suspend_test_start(); + dpm_resume_end(PMSG_RESUME); + suspend_test_finish("resume devices"); + resume_console(); + Close: + if (suspend_ops->end) + suspend_ops->end(); + return error; + + Recover_platform: + if (suspend_ops->recover) + suspend_ops->recover(); + goto Resume_devices; +} + +/** + * suspend_finish - Do final work before exiting suspend sequence. + * + * Call platform code to clean up, restart processes, and free the + * console that we've allocated. This is not called for suspend-to-disk. + */ +static void suspend_finish(void) +{ + suspend_thaw_processes(); + usermodehelper_enable(); + pm_notifier_call_chain(PM_POST_SUSPEND); + pm_restore_console(); +} + +/** + * enter_state - Do common work of entering low-power state. + * @state: pm_state structure for state we're entering. + * + * Make sure we're the only ones trying to enter a sleep state. Fail + * if someone has beat us to it, since we don't want anything weird to + * happen when we wake up. + * Then, do the setup for suspend, enter the state, and cleaup (after + * we've woken up). + */ +int enter_state(suspend_state_t state) +{ + int error; + + if (!valid_state(state)) + return -ENODEV; + + if (!mutex_trylock(&pm_mutex)) + return -EBUSY; + + printk(KERN_INFO "PM: Syncing filesystems ... "); + sys_sync(); + printk("done.\n"); + + pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]); + error = suspend_prepare(); + if (error) + goto Unlock; + + if (suspend_test(TEST_FREEZER)) + goto Finish; + + pr_debug("PM: Entering %s sleep\n", pm_states[state]); + error = suspend_devices_and_enter(state); + + Finish: + pr_debug("PM: Finishing wakeup.\n"); + suspend_finish(); + Unlock: + mutex_unlock(&pm_mutex); + return error; +} + +/** + * pm_suspend - Externally visible function for suspending system. + * @state: Enumerated value of state to enter. + * + * Determine whether or not value is within range, get state + * structure, and enter (above). + */ +int pm_suspend(suspend_state_t state) +{ + if (state > PM_SUSPEND_ON && state <= PM_SUSPEND_MAX) + return enter_state(state); + return -EINVAL; +} +EXPORT_SYMBOL(pm_suspend); diff --git a/kernel/power/suspend_test.c b/kernel/power/suspend_test.c new file mode 100644 index 000000000000..17d8bb1acf9c --- /dev/null +++ b/kernel/power/suspend_test.c @@ -0,0 +1,187 @@ +/* + * kernel/power/suspend_test.c - Suspend to RAM and standby test facility. + * + * Copyright (c) 2009 Pavel Machek + * + * This file is released under the GPLv2. + */ + +#include +#include + +#include "power.h" + +/* + * We test the system suspend code by setting an RTC wakealarm a short + * time in the future, then suspending. Suspending the devices won't + * normally take long ... some systems only need a few milliseconds. + * + * The time it takes is system-specific though, so when we test this + * during system bootup we allow a LOT of time. + */ +#define TEST_SUSPEND_SECONDS 5 + +static unsigned long suspend_test_start_time; + +void suspend_test_start(void) +{ + /* FIXME Use better timebase than "jiffies", ideally a clocksource. + * What we want is a hardware counter that will work correctly even + * during the irqs-are-off stages of the suspend/resume cycle... + */ + suspend_test_start_time = jiffies; +} + +void suspend_test_finish(const char *label) +{ + long nj = jiffies - suspend_test_start_time; + unsigned msec; + + msec = jiffies_to_msecs(abs(nj)); + pr_info("PM: %s took %d.%03d seconds\n", label, + msec / 1000, msec % 1000); + + /* Warning on suspend means the RTC alarm period needs to be + * larger -- the system was sooo slooowwww to suspend that the + * alarm (should have) fired before the system went to sleep! + * + * Warning on either suspend or resume also means the system + * has some performance issues. The stack dump of a WARN_ON + * is more likely to get the right attention than a printk... + */ + WARN(msec > (TEST_SUSPEND_SECONDS * 1000), "Component: %s\n", label); +} + +/* + * To test system suspend, we need a hands-off mechanism to resume the + * system. RTCs wake alarms are a common self-contained mechanism. + */ + +static void __init test_wakealarm(struct rtc_device *rtc, suspend_state_t state) +{ + static char err_readtime[] __initdata = + KERN_ERR "PM: can't read %s time, err %d\n"; + static char err_wakealarm [] __initdata = + KERN_ERR "PM: can't set %s wakealarm, err %d\n"; + static char err_suspend[] __initdata = + KERN_ERR "PM: suspend test failed, error %d\n"; + static char info_test[] __initdata = + KERN_INFO "PM: test RTC wakeup from '%s' suspend\n"; + + unsigned long now; + struct rtc_wkalrm alm; + int status; + + /* this may fail if the RTC hasn't been initialized */ + status = rtc_read_time(rtc, &alm.time); + if (status < 0) { + printk(err_readtime, dev_name(&rtc->dev), status); + return; + } + rtc_tm_to_time(&alm.time, &now); + + memset(&alm, 0, sizeof alm); + rtc_time_to_tm(now + TEST_SUSPEND_SECONDS, &alm.time); + alm.enabled = true; + + status = rtc_set_alarm(rtc, &alm); + if (status < 0) { + printk(err_wakealarm, dev_name(&rtc->dev), status); + return; + } + + if (state == PM_SUSPEND_MEM) { + printk(info_test, pm_states[state]); + status = pm_suspend(state); + if (status == -ENODEV) + state = PM_SUSPEND_STANDBY; + } + if (state == PM_SUSPEND_STANDBY) { + printk(info_test, pm_states[state]); + status = pm_suspend(state); + } + if (status < 0) + printk(err_suspend, status); + + /* Some platforms can't detect that the alarm triggered the + * wakeup, or (accordingly) disable it after it afterwards. + * It's supposed to give oneshot behavior; cope. + */ + alm.enabled = false; + rtc_set_alarm(rtc, &alm); +} + +static int __init has_wakealarm(struct device *dev, void *name_ptr) +{ + struct rtc_device *candidate = to_rtc_device(dev); + + if (!candidate->ops->set_alarm) + return 0; + if (!device_may_wakeup(candidate->dev.parent)) + return 0; + + *(const char **)name_ptr = dev_name(dev); + return 1; +} + +/* + * Kernel options like "test_suspend=mem" force suspend/resume sanity tests + * at startup time. They're normally disabled, for faster boot and because + * we can't know which states really work on this particular system. + */ +static suspend_state_t test_state __initdata = PM_SUSPEND_ON; + +static char warn_bad_state[] __initdata = + KERN_WARNING "PM: can't test '%s' suspend state\n"; + +static int __init setup_test_suspend(char *value) +{ + unsigned i; + + /* "=mem" ==> "mem" */ + value++; + for (i = 0; i < PM_SUSPEND_MAX; i++) { + if (!pm_states[i]) + continue; + if (strcmp(pm_states[i], value) != 0) + continue; + test_state = (__force suspend_state_t) i; + return 0; + } + printk(warn_bad_state, value); + return 0; +} +__setup("test_suspend", setup_test_suspend); + +static int __init test_suspend(void) +{ + static char warn_no_rtc[] __initdata = + KERN_WARNING "PM: no wakealarm-capable RTC driver is ready\n"; + + char *pony = NULL; + struct rtc_device *rtc = NULL; + + /* PM is initialized by now; is that state testable? */ + if (test_state == PM_SUSPEND_ON) + goto done; + if (!valid_state(test_state)) { + printk(warn_bad_state, pm_states[test_state]); + goto done; + } + + /* RTCs have initialized by now too ... can we use one? */ + class_find_device(rtc_class, NULL, &pony, has_wakealarm); + if (pony) + rtc = rtc_class_open(pony); + if (!rtc) { + printk(warn_no_rtc); + goto done; + } + + /* go for it */ + test_wakealarm(rtc, test_state); + rtc_class_close(rtc); +done: + return 0; +} +late_initcall(test_suspend); diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c index 78c35047586d..6a07f4dbf2f8 100644 --- a/kernel/power/swsusp.c +++ b/kernel/power/swsusp.c @@ -55,14 +55,6 @@ #include "power.h" -/* - * Preferred image size in bytes (tunable via /sys/power/image_size). - * When it is set to N, swsusp will do its best to ensure the image - * size will not exceed N bytes, but if that is impossible, it will - * try to create the smallest image possible. - */ -unsigned long image_size = 500 * 1024 * 1024; - int in_suspend __nosavedata = 0; /** @@ -194,193 +186,3 @@ void swsusp_show_speed(struct timeval *start, struct timeval *stop, centisecs / 100, centisecs % 100, kps / 1000, (kps % 1000) / 10); } - -/** - * swsusp_shrink_memory - Try to free as much memory as needed - * - * ... but do not OOM-kill anyone - * - * Notice: all userland should be stopped before it is called, or - * livelock is possible. - */ - -#define SHRINK_BITE 10000 -static inline unsigned long __shrink_memory(long tmp) -{ - if (tmp > SHRINK_BITE) - tmp = SHRINK_BITE; - return shrink_all_memory(tmp); -} - -int swsusp_shrink_memory(void) -{ - long tmp; - struct zone *zone; - unsigned long pages = 0; - unsigned int i = 0; - char *p = "-\\|/"; - struct timeval start, stop; - - printk(KERN_INFO "PM: Shrinking memory... "); - do_gettimeofday(&start); - do { - long size, highmem_size; - - highmem_size = count_highmem_pages(); - size = count_data_pages() + PAGES_FOR_IO + SPARE_PAGES; - tmp = size; - size += highmem_size; - for_each_populated_zone(zone) { - tmp += snapshot_additional_pages(zone); - if (is_highmem(zone)) { - highmem_size -= - zone_page_state(zone, NR_FREE_PAGES); - } else { - tmp -= zone_page_state(zone, NR_FREE_PAGES); - tmp += zone->lowmem_reserve[ZONE_NORMAL]; - } - } - - if (highmem_size < 0) - highmem_size = 0; - - tmp += highmem_size; - if (tmp > 0) { - tmp = __shrink_memory(tmp); - if (!tmp) - return -ENOMEM; - pages += tmp; - } else if (size > image_size / PAGE_SIZE) { - tmp = __shrink_memory(size - (image_size / PAGE_SIZE)); - pages += tmp; - } - printk("\b%c", p[i++%4]); - } while (tmp > 0); - do_gettimeofday(&stop); - printk("\bdone (%lu pages freed)\n", pages); - swsusp_show_speed(&start, &stop, pages, "Freed"); - - return 0; -} - -/* - * Platforms, like ACPI, may want us to save some memory used by them during - * hibernation and to restore the contents of this memory during the subsequent - * resume. The code below implements a mechanism allowing us to do that. - */ - -struct nvs_page { - unsigned long phys_start; - unsigned int size; - void *kaddr; - void *data; - struct list_head node; -}; - -static LIST_HEAD(nvs_list); - -/** - * hibernate_nvs_register - register platform NVS memory region to save - * @start - physical address of the region - * @size - size of the region - * - * The NVS region need not be page-aligned (both ends) and we arrange - * things so that the data from page-aligned addresses in this region will - * be copied into separate RAM pages. - */ -int hibernate_nvs_register(unsigned long start, unsigned long size) -{ - struct nvs_page *entry, *next; - - while (size > 0) { - unsigned int nr_bytes; - - entry = kzalloc(sizeof(struct nvs_page), GFP_KERNEL); - if (!entry) - goto Error; - - list_add_tail(&entry->node, &nvs_list); - entry->phys_start = start; - nr_bytes = PAGE_SIZE - (start & ~PAGE_MASK); - entry->size = (size < nr_bytes) ? size : nr_bytes; - - start += entry->size; - size -= entry->size; - } - return 0; - - Error: - list_for_each_entry_safe(entry, next, &nvs_list, node) { - list_del(&entry->node); - kfree(entry); - } - return -ENOMEM; -} - -/** - * hibernate_nvs_free - free data pages allocated for saving NVS regions - */ -void hibernate_nvs_free(void) -{ - struct nvs_page *entry; - - list_for_each_entry(entry, &nvs_list, node) - if (entry->data) { - free_page((unsigned long)entry->data); - entry->data = NULL; - if (entry->kaddr) { - iounmap(entry->kaddr); - entry->kaddr = NULL; - } - } -} - -/** - * hibernate_nvs_alloc - allocate memory necessary for saving NVS regions - */ -int hibernate_nvs_alloc(void) -{ - struct nvs_page *entry; - - list_for_each_entry(entry, &nvs_list, node) { - entry->data = (void *)__get_free_page(GFP_KERNEL); - if (!entry->data) { - hibernate_nvs_free(); - return -ENOMEM; - } - } - return 0; -} - -/** - * hibernate_nvs_save - save NVS memory regions - */ -void hibernate_nvs_save(void) -{ - struct nvs_page *entry; - - printk(KERN_INFO "PM: Saving platform NVS memory\n"); - - list_for_each_entry(entry, &nvs_list, node) - if (entry->data) { - entry->kaddr = ioremap(entry->phys_start, entry->size); - memcpy(entry->data, entry->kaddr, entry->size); - } -} - -/** - * hibernate_nvs_restore - restore NVS memory regions - * - * This function is going to be called with interrupts disabled, so it - * cannot iounmap the virtual addresses used to access the NVS region. - */ -void hibernate_nvs_restore(void) -{ - struct nvs_page *entry; - - printk(KERN_INFO "PM: Restoring platform NVS memory\n"); - - list_for_each_entry(entry, &nvs_list, node) - if (entry->data) - memcpy(entry->kaddr, entry->data, entry->size); -} diff --git a/kernel/printk.c b/kernel/printk.c index 5052b5497c67..b4d97b54c1ec 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -687,20 +687,35 @@ asmlinkage int vprintk(const char *fmt, va_list args) sizeof(printk_buf) - printed_len, fmt, args); + p = printk_buf; + + /* Do we have a loglevel in the string? */ + if (p[0] == '<') { + unsigned char c = p[1]; + if (c && p[2] == '>') { + switch (c) { + case '0' ... '7': /* loglevel */ + current_log_level = c - '0'; + /* Fallthrough - make sure we're on a new line */ + case 'd': /* KERN_DEFAULT */ + if (!new_text_line) { + emit_log_char('\n'); + new_text_line = 1; + } + /* Fallthrough - skip the loglevel */ + case 'c': /* KERN_CONT */ + p += 3; + break; + } + } + } + /* * Copy the output into log_buf. If the caller didn't provide * appropriate log level tags, we insert them here */ - for (p = printk_buf; *p; p++) { + for ( ; *p; p++) { if (new_text_line) { - /* If a token, set current_log_level and skip over */ - if (p[0] == '<' && p[1] >= '0' && p[1] <= '7' && - p[2] == '>') { - current_log_level = p[1] - '0'; - p += 3; - printed_len -= 3; - } - /* Always output the token */ emit_log_char('<'); emit_log_char(current_log_level + '0'); diff --git a/kernel/profile.c b/kernel/profile.c index 7724e0409bae..69911b5745eb 100644 --- a/kernel/profile.c +++ b/kernel/profile.c @@ -111,12 +111,6 @@ int __ref profile_init(void) /* only text is profiled */ prof_len = (_etext - _stext) >> prof_shift; buffer_bytes = prof_len*sizeof(atomic_t); - if (!slab_is_available()) { - prof_buffer = alloc_bootmem(buffer_bytes); - alloc_bootmem_cpumask_var(&prof_cpu_mask); - cpumask_copy(prof_cpu_mask, cpu_possible_mask); - return 0; - } if (!alloc_cpumask_var(&prof_cpu_mask, GFP_KERNEL)) return -ENOMEM; @@ -371,7 +365,7 @@ static int __cpuinit profile_cpu_callback(struct notifier_block *info, node = cpu_to_node(cpu); per_cpu(cpu_profile_flip, cpu) = 0; if (!per_cpu(cpu_profile_hits, cpu)[1]) { - page = alloc_pages_node(node, + page = alloc_pages_exact_node(node, GFP_KERNEL | __GFP_ZERO, 0); if (!page) @@ -379,7 +373,7 @@ static int __cpuinit profile_cpu_callback(struct notifier_block *info, per_cpu(cpu_profile_hits, cpu)[1] = page_address(page); } if (!per_cpu(cpu_profile_hits, cpu)[0]) { - page = alloc_pages_node(node, + page = alloc_pages_exact_node(node, GFP_KERNEL | __GFP_ZERO, 0); if (!page) @@ -570,14 +564,14 @@ static int create_hash_tables(void) int node = cpu_to_node(cpu); struct page *page; - page = alloc_pages_node(node, + page = alloc_pages_exact_node(node, GFP_KERNEL | __GFP_ZERO | GFP_THISNODE, 0); if (!page) goto out_cleanup; per_cpu(cpu_profile_hits, cpu)[1] = (struct profile_hit *)page_address(page); - page = alloc_pages_node(node, + page = alloc_pages_exact_node(node, GFP_KERNEL | __GFP_ZERO | GFP_THISNODE, 0); if (!page) diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 42c317874cfa..61c78b2c07ba 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -24,16 +24,6 @@ #include -/* - * Initialize a new task whose father had been ptraced. - * - * Called from copy_process(). - */ -void ptrace_fork(struct task_struct *child, unsigned long clone_flags) -{ - arch_ptrace_fork(child, clone_flags); -} - /* * ptrace a task: make the debugger its new parent and * move it to the ptrace list. @@ -177,66 +167,82 @@ bool ptrace_may_access(struct task_struct *task, unsigned int mode) int ptrace_attach(struct task_struct *task) { int retval; - unsigned long flags; audit_ptrace(task); retval = -EPERM; + if (unlikely(task->flags & PF_KTHREAD)) + goto out; if (same_thread_group(task, current)) goto out; - /* Protect exec's credential calculations against our interference; - * SUID, SGID and LSM creds get determined differently under ptrace. + /* + * Protect exec's credential calculations against our interference; + * interference; SUID, SGID and LSM creds get determined differently + * under ptrace. */ - retval = mutex_lock_interruptible(&task->cred_exec_mutex); - if (retval < 0) + retval = mutex_lock_interruptible(&task->cred_guard_mutex); + if (retval < 0) goto out; - retval = -EPERM; -repeat: - /* - * Nasty, nasty. - * - * We want to hold both the task-lock and the - * tasklist_lock for writing at the same time. - * But that's against the rules (tasklist_lock - * is taken for reading by interrupts on other - * cpu's that may have task_lock). - */ task_lock(task); - if (!write_trylock_irqsave(&tasklist_lock, flags)) { - task_unlock(task); - do { - cpu_relax(); - } while (!write_can_lock(&tasklist_lock)); - goto repeat; - } - - if (!task->mm) - goto bad; - /* the same process cannot be attached many times */ - if (task->ptrace & PT_PTRACED) - goto bad; retval = __ptrace_may_access(task, PTRACE_MODE_ATTACH); + task_unlock(task); if (retval) - goto bad; + goto unlock_creds; - /* Go */ - task->ptrace |= PT_PTRACED; + write_lock_irq(&tasklist_lock); + retval = -EPERM; + if (unlikely(task->exit_state)) + goto unlock_tasklist; + if (task->ptrace) + goto unlock_tasklist; + + task->ptrace = PT_PTRACED; if (capable(CAP_SYS_PTRACE)) task->ptrace |= PT_PTRACE_CAP; __ptrace_link(task, current); - send_sig_info(SIGSTOP, SEND_SIG_FORCED, task); -bad: - write_unlock_irqrestore(&tasklist_lock, flags); - task_unlock(task); - mutex_unlock(&task->cred_exec_mutex); + + retval = 0; +unlock_tasklist: + write_unlock_irq(&tasklist_lock); +unlock_creds: + mutex_unlock(&task->cred_guard_mutex); out: return retval; } +/** + * ptrace_traceme -- helper for PTRACE_TRACEME + * + * Performs checks and sets PT_PTRACED. + * Should be used by all ptrace implementations for PTRACE_TRACEME. + */ +int ptrace_traceme(void) +{ + int ret = -EPERM; + + write_lock_irq(&tasklist_lock); + /* Are we already being traced? */ + if (!current->ptrace) { + ret = security_ptrace_traceme(current->parent); + /* + * Check PF_EXITING to ensure ->real_parent has not passed + * exit_ptrace(). Otherwise we don't report the error but + * pretend ->real_parent untraces us right after return. + */ + if (!ret && !(current->real_parent->flags & PF_EXITING)) { + current->ptrace = PT_PTRACED; + __ptrace_link(current, current->real_parent); + } + } + write_unlock_irq(&tasklist_lock); + + return ret; +} + /* * Called with irqs disabled, returns true if childs should reap themselves. */ @@ -418,37 +424,33 @@ static int ptrace_setoptions(struct task_struct *child, long data) static int ptrace_getsiginfo(struct task_struct *child, siginfo_t *info) { + unsigned long flags; int error = -ESRCH; - read_lock(&tasklist_lock); - if (likely(child->sighand != NULL)) { + if (lock_task_sighand(child, &flags)) { error = -EINVAL; - spin_lock_irq(&child->sighand->siglock); if (likely(child->last_siginfo != NULL)) { *info = *child->last_siginfo; error = 0; } - spin_unlock_irq(&child->sighand->siglock); + unlock_task_sighand(child, &flags); } - read_unlock(&tasklist_lock); return error; } static int ptrace_setsiginfo(struct task_struct *child, const siginfo_t *info) { + unsigned long flags; int error = -ESRCH; - read_lock(&tasklist_lock); - if (likely(child->sighand != NULL)) { + if (lock_task_sighand(child, &flags)) { error = -EINVAL; - spin_lock_irq(&child->sighand->siglock); if (likely(child->last_siginfo != NULL)) { *child->last_siginfo = *info; error = 0; } - spin_unlock_irq(&child->sighand->siglock); + unlock_task_sighand(child, &flags); } - read_unlock(&tasklist_lock); return error; } @@ -575,72 +577,16 @@ int ptrace_request(struct task_struct *child, long request, return ret; } -/** - * ptrace_traceme -- helper for PTRACE_TRACEME - * - * Performs checks and sets PT_PTRACED. - * Should be used by all ptrace implementations for PTRACE_TRACEME. - */ -int ptrace_traceme(void) -{ - int ret = -EPERM; - - /* - * Are we already being traced? - */ -repeat: - task_lock(current); - if (!(current->ptrace & PT_PTRACED)) { - /* - * See ptrace_attach() comments about the locking here. - */ - unsigned long flags; - if (!write_trylock_irqsave(&tasklist_lock, flags)) { - task_unlock(current); - do { - cpu_relax(); - } while (!write_can_lock(&tasklist_lock)); - goto repeat; - } - - ret = security_ptrace_traceme(current->parent); - - /* - * Check PF_EXITING to ensure ->real_parent has not passed - * exit_ptrace(). Otherwise we don't report the error but - * pretend ->real_parent untraces us right after return. - */ - if (!ret && !(current->real_parent->flags & PF_EXITING)) { - current->ptrace |= PT_PTRACED; - __ptrace_link(current, current->real_parent); - } - - write_unlock_irqrestore(&tasklist_lock, flags); - } - task_unlock(current); - return ret; -} - -/** - * ptrace_get_task_struct -- grab a task struct reference for ptrace - * @pid: process id to grab a task_struct reference of - * - * This function is a helper for ptrace implementations. It checks - * permissions and then grabs a task struct for use of the actual - * ptrace implementation. - * - * Returns the task_struct for @pid or an ERR_PTR() on failure. - */ -struct task_struct *ptrace_get_task_struct(pid_t pid) +static struct task_struct *ptrace_get_task_struct(pid_t pid) { struct task_struct *child; - read_lock(&tasklist_lock); + rcu_read_lock(); child = find_task_by_vpid(pid); if (child) get_task_struct(child); + rcu_read_unlock(); - read_unlock(&tasklist_lock); if (!child) return ERR_PTR(-ESRCH); return child; diff --git a/kernel/rcupreempt.c b/kernel/rcupreempt.c index ce97a4df64d3..beb0e659adcc 100644 --- a/kernel/rcupreempt.c +++ b/kernel/rcupreempt.c @@ -1356,17 +1356,11 @@ static int rcu_sched_grace_period(void *arg) rcu_ctrlblk.sched_sleep = rcu_sched_sleeping; spin_unlock_irqrestore(&rcu_ctrlblk.schedlock, flags); - ret = 0; + ret = 0; /* unused */ __wait_event_interruptible(rcu_ctrlblk.sched_wq, rcu_ctrlblk.sched_sleep != rcu_sched_sleeping, ret); - /* - * Signals would prevent us from sleeping, and we cannot - * do much with them in any case. So flush them. - */ - if (ret) - flush_signals(current); couldsleepnext = 0; } while (!kthread_should_stop()); diff --git a/kernel/rcutree.c b/kernel/rcutree.c index d2a372fb0b9b..0dccfbba6d26 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -1259,31 +1259,44 @@ static int __rcu_pending(struct rcu_state *rsp, struct rcu_data *rdp) check_cpu_stall(rsp, rdp); /* Is the RCU core waiting for a quiescent state from this CPU? */ - if (rdp->qs_pending) + if (rdp->qs_pending) { + rdp->n_rp_qs_pending++; return 1; + } /* Does this CPU have callbacks ready to invoke? */ - if (cpu_has_callbacks_ready_to_invoke(rdp)) + if (cpu_has_callbacks_ready_to_invoke(rdp)) { + rdp->n_rp_cb_ready++; return 1; + } /* Has RCU gone idle with this CPU needing another grace period? */ - if (cpu_needs_another_gp(rsp, rdp)) + if (cpu_needs_another_gp(rsp, rdp)) { + rdp->n_rp_cpu_needs_gp++; return 1; + } /* Has another RCU grace period completed? */ - if (ACCESS_ONCE(rsp->completed) != rdp->completed) /* outside of lock */ + if (ACCESS_ONCE(rsp->completed) != rdp->completed) { /* outside lock */ + rdp->n_rp_gp_completed++; return 1; + } /* Has a new RCU grace period started? */ - if (ACCESS_ONCE(rsp->gpnum) != rdp->gpnum) /* outside of lock */ + if (ACCESS_ONCE(rsp->gpnum) != rdp->gpnum) { /* outside lock */ + rdp->n_rp_gp_started++; return 1; + } /* Has an RCU GP gone long enough to send resched IPIs &c? */ if (ACCESS_ONCE(rsp->completed) != ACCESS_ONCE(rsp->gpnum) && - ((long)(ACCESS_ONCE(rsp->jiffies_force_qs) - jiffies) < 0)) + ((long)(ACCESS_ONCE(rsp->jiffies_force_qs) - jiffies) < 0)) { + rdp->n_rp_need_fqs++; return 1; + } /* nothing to do */ + rdp->n_rp_need_nothing++; return 0; } diff --git a/kernel/rcutree_trace.c b/kernel/rcutree_trace.c index 4b1875ba9404..fe1dcdbf1ca3 100644 --- a/kernel/rcutree_trace.c +++ b/kernel/rcutree_trace.c @@ -213,7 +213,63 @@ static struct file_operations rcugp_fops = { .release = single_release, }; -static struct dentry *rcudir, *datadir, *datadir_csv, *hierdir, *gpdir; +static void print_one_rcu_pending(struct seq_file *m, struct rcu_data *rdp) +{ + seq_printf(m, "%3d%cnp=%ld " + "qsp=%ld cbr=%ld cng=%ld gpc=%ld gps=%ld nf=%ld nn=%ld\n", + rdp->cpu, + cpu_is_offline(rdp->cpu) ? '!' : ' ', + rdp->n_rcu_pending, + rdp->n_rp_qs_pending, + rdp->n_rp_cb_ready, + rdp->n_rp_cpu_needs_gp, + rdp->n_rp_gp_completed, + rdp->n_rp_gp_started, + rdp->n_rp_need_fqs, + rdp->n_rp_need_nothing); +} + +static void print_rcu_pendings(struct seq_file *m, struct rcu_state *rsp) +{ + int cpu; + struct rcu_data *rdp; + + for_each_possible_cpu(cpu) { + rdp = rsp->rda[cpu]; + if (rdp->beenonline) + print_one_rcu_pending(m, rdp); + } +} + +static int show_rcu_pending(struct seq_file *m, void *unused) +{ + seq_puts(m, "rcu:\n"); + print_rcu_pendings(m, &rcu_state); + seq_puts(m, "rcu_bh:\n"); + print_rcu_pendings(m, &rcu_bh_state); + return 0; +} + +static int rcu_pending_open(struct inode *inode, struct file *file) +{ + return single_open(file, show_rcu_pending, NULL); +} + +static struct file_operations rcu_pending_fops = { + .owner = THIS_MODULE, + .open = rcu_pending_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static struct dentry *rcudir; +static struct dentry *datadir; +static struct dentry *datadir_csv; +static struct dentry *gpdir; +static struct dentry *hierdir; +static struct dentry *rcu_pendingdir; + static int __init rcuclassic_trace_init(void) { rcudir = debugfs_create_dir("rcu", NULL); @@ -238,6 +294,11 @@ static int __init rcuclassic_trace_init(void) NULL, &rcuhier_fops); if (!hierdir) goto free_out; + + rcu_pendingdir = debugfs_create_file("rcu_pending", 0444, rcudir, + NULL, &rcu_pending_fops); + if (!rcu_pendingdir) + goto free_out; return 0; free_out: if (datadir) @@ -257,6 +318,7 @@ static void __exit rcuclassic_trace_cleanup(void) debugfs_remove(datadir_csv); debugfs_remove(gpdir); debugfs_remove(hierdir); + debugfs_remove(rcu_pendingdir); debugfs_remove(rcudir); } diff --git a/kernel/res_counter.c b/kernel/res_counter.c index bf8e7534c803..e1338f074314 100644 --- a/kernel/res_counter.c +++ b/kernel/res_counter.c @@ -18,7 +18,7 @@ void res_counter_init(struct res_counter *counter, struct res_counter *parent) { spin_lock_init(&counter->lock); - counter->limit = (unsigned long long)LLONG_MAX; + counter->limit = RESOURCE_MAX; counter->parent = parent; } @@ -133,6 +133,16 @@ int res_counter_memparse_write_strategy(const char *buf, unsigned long long *res) { char *end; + + /* return RESOURCE_MAX(unlimited) if "-1" is specified */ + if (*buf == '-') { + *res = simple_strtoull(buf + 1, &end, 10); + if (*res != 1 || *end != '\0') + return -EINVAL; + *res = RESOURCE_MAX; + return 0; + } + /* FIXME - make memparse() take const char* args */ *res = memparse((char *)buf, &end); if (*end != '\0') diff --git a/kernel/rtmutex.c b/kernel/rtmutex.c index 69d9cb921ffa..fcd107a78c5a 100644 --- a/kernel/rtmutex.c +++ b/kernel/rtmutex.c @@ -300,7 +300,8 @@ static int rt_mutex_adjust_prio_chain(struct task_struct *task, * assigned pending owner [which might not have taken the * lock yet]: */ -static inline int try_to_steal_lock(struct rt_mutex *lock) +static inline int try_to_steal_lock(struct rt_mutex *lock, + struct task_struct *task) { struct task_struct *pendowner = rt_mutex_owner(lock); struct rt_mutex_waiter *next; @@ -309,11 +310,11 @@ static inline int try_to_steal_lock(struct rt_mutex *lock) if (!rt_mutex_owner_pending(lock)) return 0; - if (pendowner == current) + if (pendowner == task) return 1; spin_lock_irqsave(&pendowner->pi_lock, flags); - if (current->prio >= pendowner->prio) { + if (task->prio >= pendowner->prio) { spin_unlock_irqrestore(&pendowner->pi_lock, flags); return 0; } @@ -338,21 +339,21 @@ static inline int try_to_steal_lock(struct rt_mutex *lock) * We are going to steal the lock and a waiter was * enqueued on the pending owners pi_waiters queue. So * we have to enqueue this waiter into - * current->pi_waiters list. This covers the case, - * where current is boosted because it holds another + * task->pi_waiters list. This covers the case, + * where task is boosted because it holds another * lock and gets unboosted because the booster is * interrupted, so we would delay a waiter with higher - * priority as current->normal_prio. + * priority as task->normal_prio. * * Note: in the rare case of a SCHED_OTHER task changing * its priority and thus stealing the lock, next->task - * might be current: + * might be task: */ - if (likely(next->task != current)) { - spin_lock_irqsave(¤t->pi_lock, flags); - plist_add(&next->pi_list_entry, ¤t->pi_waiters); - __rt_mutex_adjust_prio(current); - spin_unlock_irqrestore(¤t->pi_lock, flags); + if (likely(next->task != task)) { + spin_lock_irqsave(&task->pi_lock, flags); + plist_add(&next->pi_list_entry, &task->pi_waiters); + __rt_mutex_adjust_prio(task); + spin_unlock_irqrestore(&task->pi_lock, flags); } return 1; } @@ -389,7 +390,7 @@ static int try_to_take_rt_mutex(struct rt_mutex *lock) */ mark_rt_mutex_waiters(lock); - if (rt_mutex_owner(lock) && !try_to_steal_lock(lock)) + if (rt_mutex_owner(lock) && !try_to_steal_lock(lock, current)) return 0; /* We got the lock. */ @@ -411,6 +412,7 @@ static int try_to_take_rt_mutex(struct rt_mutex *lock) */ static int task_blocks_on_rt_mutex(struct rt_mutex *lock, struct rt_mutex_waiter *waiter, + struct task_struct *task, int detect_deadlock) { struct task_struct *owner = rt_mutex_owner(lock); @@ -418,21 +420,21 @@ static int task_blocks_on_rt_mutex(struct rt_mutex *lock, unsigned long flags; int chain_walk = 0, res; - spin_lock_irqsave(¤t->pi_lock, flags); - __rt_mutex_adjust_prio(current); - waiter->task = current; + spin_lock_irqsave(&task->pi_lock, flags); + __rt_mutex_adjust_prio(task); + waiter->task = task; waiter->lock = lock; - plist_node_init(&waiter->list_entry, current->prio); - plist_node_init(&waiter->pi_list_entry, current->prio); + plist_node_init(&waiter->list_entry, task->prio); + plist_node_init(&waiter->pi_list_entry, task->prio); /* Get the top priority waiter on the lock */ if (rt_mutex_has_waiters(lock)) top_waiter = rt_mutex_top_waiter(lock); plist_add(&waiter->list_entry, &lock->wait_list); - current->pi_blocked_on = waiter; + task->pi_blocked_on = waiter; - spin_unlock_irqrestore(¤t->pi_lock, flags); + spin_unlock_irqrestore(&task->pi_lock, flags); if (waiter == rt_mutex_top_waiter(lock)) { spin_lock_irqsave(&owner->pi_lock, flags); @@ -460,7 +462,7 @@ static int task_blocks_on_rt_mutex(struct rt_mutex *lock, spin_unlock(&lock->wait_lock); res = rt_mutex_adjust_prio_chain(owner, detect_deadlock, lock, waiter, - current); + task); spin_lock(&lock->wait_lock); @@ -605,6 +607,85 @@ void rt_mutex_adjust_pi(struct task_struct *task) rt_mutex_adjust_prio_chain(task, 0, NULL, NULL, task); } +/** + * __rt_mutex_slowlock() - Perform the wait-wake-try-to-take loop + * @lock: the rt_mutex to take + * @state: the state the task should block in (TASK_INTERRUPTIBLE + * or TASK_UNINTERRUPTIBLE) + * @timeout: the pre-initialized and started timer, or NULL for none + * @waiter: the pre-initialized rt_mutex_waiter + * @detect_deadlock: passed to task_blocks_on_rt_mutex + * + * lock->wait_lock must be held by the caller. + */ +static int __sched +__rt_mutex_slowlock(struct rt_mutex *lock, int state, + struct hrtimer_sleeper *timeout, + struct rt_mutex_waiter *waiter, + int detect_deadlock) +{ + int ret = 0; + + for (;;) { + /* Try to acquire the lock: */ + if (try_to_take_rt_mutex(lock)) + break; + + /* + * TASK_INTERRUPTIBLE checks for signals and + * timeout. Ignored otherwise. + */ + if (unlikely(state == TASK_INTERRUPTIBLE)) { + /* Signal pending? */ + if (signal_pending(current)) + ret = -EINTR; + if (timeout && !timeout->task) + ret = -ETIMEDOUT; + if (ret) + break; + } + + /* + * waiter->task is NULL the first time we come here and + * when we have been woken up by the previous owner + * but the lock got stolen by a higher prio task. + */ + if (!waiter->task) { + ret = task_blocks_on_rt_mutex(lock, waiter, current, + detect_deadlock); + /* + * If we got woken up by the owner then start loop + * all over without going into schedule to try + * to get the lock now: + */ + if (unlikely(!waiter->task)) { + /* + * Reset the return value. We might + * have returned with -EDEADLK and the + * owner released the lock while we + * were walking the pi chain. + */ + ret = 0; + continue; + } + if (unlikely(ret)) + break; + } + + spin_unlock(&lock->wait_lock); + + debug_rt_mutex_print_deadlock(waiter); + + if (waiter->task) + schedule_rt_mutex(lock); + + spin_lock(&lock->wait_lock); + set_current_state(state); + } + + return ret; +} + /* * Slow path lock function: */ @@ -636,62 +717,8 @@ rt_mutex_slowlock(struct rt_mutex *lock, int state, timeout->task = NULL; } - for (;;) { - /* Try to acquire the lock: */ - if (try_to_take_rt_mutex(lock)) - break; - - /* - * TASK_INTERRUPTIBLE checks for signals and - * timeout. Ignored otherwise. - */ - if (unlikely(state == TASK_INTERRUPTIBLE)) { - /* Signal pending? */ - if (signal_pending(current)) - ret = -EINTR; - if (timeout && !timeout->task) - ret = -ETIMEDOUT; - if (ret) - break; - } - - /* - * waiter.task is NULL the first time we come here and - * when we have been woken up by the previous owner - * but the lock got stolen by a higher prio task. - */ - if (!waiter.task) { - ret = task_blocks_on_rt_mutex(lock, &waiter, - detect_deadlock); - /* - * If we got woken up by the owner then start loop - * all over without going into schedule to try - * to get the lock now: - */ - if (unlikely(!waiter.task)) { - /* - * Reset the return value. We might - * have returned with -EDEADLK and the - * owner released the lock while we - * were walking the pi chain. - */ - ret = 0; - continue; - } - if (unlikely(ret)) - break; - } - - spin_unlock(&lock->wait_lock); - - debug_rt_mutex_print_deadlock(&waiter); - - if (waiter.task) - schedule_rt_mutex(lock); - - spin_lock(&lock->wait_lock); - set_current_state(state); - } + ret = __rt_mutex_slowlock(lock, state, timeout, &waiter, + detect_deadlock); set_current_state(TASK_RUNNING); @@ -864,9 +891,9 @@ int __sched rt_mutex_lock_interruptible(struct rt_mutex *lock, EXPORT_SYMBOL_GPL(rt_mutex_lock_interruptible); /** - * rt_mutex_lock_interruptible_ktime - lock a rt_mutex interruptible - * the timeout structure is provided - * by the caller + * rt_mutex_timed_lock - lock a rt_mutex interruptible + * the timeout structure is provided + * by the caller * * @lock: the rt_mutex to be locked * @timeout: timeout structure or NULL (no timeout) @@ -875,7 +902,7 @@ EXPORT_SYMBOL_GPL(rt_mutex_lock_interruptible); * Returns: * 0 on success * -EINTR when interrupted by a signal - * -ETIMEOUT when the timeout expired + * -ETIMEDOUT when the timeout expired * -EDEADLK when the lock would deadlock (when deadlock detection is on) */ int @@ -913,7 +940,7 @@ void __sched rt_mutex_unlock(struct rt_mutex *lock) } EXPORT_SYMBOL_GPL(rt_mutex_unlock); -/*** +/** * rt_mutex_destroy - mark a mutex unusable * @lock: the mutex to be destroyed * @@ -985,6 +1012,59 @@ void rt_mutex_proxy_unlock(struct rt_mutex *lock, rt_mutex_deadlock_account_unlock(proxy_owner); } +/** + * rt_mutex_start_proxy_lock() - Start lock acquisition for another task + * @lock: the rt_mutex to take + * @waiter: the pre-initialized rt_mutex_waiter + * @task: the task to prepare + * @detect_deadlock: perform deadlock detection (1) or not (0) + * + * Returns: + * 0 - task blocked on lock + * 1 - acquired the lock for task, caller should wake it up + * <0 - error + * + * Special API call for FUTEX_REQUEUE_PI support. + */ +int rt_mutex_start_proxy_lock(struct rt_mutex *lock, + struct rt_mutex_waiter *waiter, + struct task_struct *task, int detect_deadlock) +{ + int ret; + + spin_lock(&lock->wait_lock); + + mark_rt_mutex_waiters(lock); + + if (!rt_mutex_owner(lock) || try_to_steal_lock(lock, task)) { + /* We got the lock for task. */ + debug_rt_mutex_lock(lock); + + rt_mutex_set_owner(lock, task, 0); + + rt_mutex_deadlock_account_lock(lock, task); + return 1; + } + + ret = task_blocks_on_rt_mutex(lock, waiter, task, detect_deadlock); + + + if (ret && !waiter->task) { + /* + * Reset the return value. We might have + * returned with -EDEADLK and the owner + * released the lock while we were walking the + * pi chain. Let the waiter sort it out. + */ + ret = 0; + } + spin_unlock(&lock->wait_lock); + + debug_rt_mutex_print_deadlock(waiter); + + return ret; +} + /** * rt_mutex_next_owner - return the next owner of the lock * @@ -1004,3 +1084,57 @@ struct task_struct *rt_mutex_next_owner(struct rt_mutex *lock) return rt_mutex_top_waiter(lock)->task; } + +/** + * rt_mutex_finish_proxy_lock() - Complete lock acquisition + * @lock: the rt_mutex we were woken on + * @to: the timeout, null if none. hrtimer should already have + * been started. + * @waiter: the pre-initialized rt_mutex_waiter + * @detect_deadlock: perform deadlock detection (1) or not (0) + * + * Complete the lock acquisition started our behalf by another thread. + * + * Returns: + * 0 - success + * <0 - error, one of -EINTR, -ETIMEDOUT, or -EDEADLK + * + * Special API call for PI-futex requeue support + */ +int rt_mutex_finish_proxy_lock(struct rt_mutex *lock, + struct hrtimer_sleeper *to, + struct rt_mutex_waiter *waiter, + int detect_deadlock) +{ + int ret; + + spin_lock(&lock->wait_lock); + + set_current_state(TASK_INTERRUPTIBLE); + + ret = __rt_mutex_slowlock(lock, TASK_INTERRUPTIBLE, to, waiter, + detect_deadlock); + + set_current_state(TASK_RUNNING); + + if (unlikely(waiter->task)) + remove_waiter(lock, waiter); + + /* + * try_to_take_rt_mutex() sets the waiter bit unconditionally. We might + * have to fix that up. + */ + fixup_rt_mutex_waiters(lock); + + spin_unlock(&lock->wait_lock); + + /* + * Readjust priority, when we did not get the lock. We might have been + * the pending owner and boosted. Since we did not take the lock, the + * PI boost has to go. + */ + if (unlikely(ret)) + rt_mutex_adjust_prio(current); + + return ret; +} diff --git a/kernel/rtmutex_common.h b/kernel/rtmutex_common.h index e124bf5800ea..97a2f81866af 100644 --- a/kernel/rtmutex_common.h +++ b/kernel/rtmutex_common.h @@ -120,6 +120,14 @@ extern void rt_mutex_init_proxy_locked(struct rt_mutex *lock, struct task_struct *proxy_owner); extern void rt_mutex_proxy_unlock(struct rt_mutex *lock, struct task_struct *proxy_owner); +extern int rt_mutex_start_proxy_lock(struct rt_mutex *lock, + struct rt_mutex_waiter *waiter, + struct task_struct *task, + int detect_deadlock); +extern int rt_mutex_finish_proxy_lock(struct rt_mutex *lock, + struct hrtimer_sleeper *to, + struct rt_mutex_waiter *waiter, + int detect_deadlock); #ifdef CONFIG_DEBUG_RT_MUTEXES # include "rtmutex-debug.h" diff --git a/kernel/sched.c b/kernel/sched.c index 26efa475bdc1..7c9098d186e6 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -68,17 +69,18 @@ #include #include #include -#include #include #include #include -#include #include #include #include "sched_cpupri.h" +#define CREATE_TRACE_POINTS +#include + /* * Convert user-nice values [ -20 ... 0 ... 19 ] * to static priority [ MAX_RT_PRIO..MAX_PRIO-1 ], @@ -118,12 +120,6 @@ */ #define RUNTIME_INF ((u64)~0ULL) -DEFINE_TRACE(sched_wait_task); -DEFINE_TRACE(sched_wakeup); -DEFINE_TRACE(sched_wakeup_new); -DEFINE_TRACE(sched_switch); -DEFINE_TRACE(sched_migrate_task); - #ifdef CONFIG_SMP static void double_rq_lock(struct rq *rq1, struct rq *rq2); @@ -244,7 +240,7 @@ static void start_rt_bandwidth(struct rt_bandwidth *rt_b) hard = hrtimer_get_expires(&rt_b->rt_period_timer); delta = ktime_to_ns(ktime_sub(hard, soft)); __hrtimer_start_range_ns(&rt_b->rt_period_timer, soft, delta, - HRTIMER_MODE_ABS, 0); + HRTIMER_MODE_ABS_PINNED, 0); } spin_unlock(&rt_b->rt_runtime_lock); } @@ -584,6 +580,7 @@ struct rq { struct load_weight load; unsigned long nr_load_updates; u64 nr_switches; + u64 nr_migrations_in; struct cfs_rq cfs; struct rt_rq rt; @@ -630,6 +627,10 @@ struct rq { struct list_head migration_queue; #endif + /* calc_load related fields */ + unsigned long calc_load_update; + long calc_load_active; + #ifdef CONFIG_SCHED_HRTICK #ifdef CONFIG_SMP int hrtick_csd_pending; @@ -692,7 +693,7 @@ static inline int cpu_of(struct rq *rq) #define task_rq(p) cpu_rq(task_cpu(p)) #define cpu_curr(cpu) (cpu_rq(cpu)->curr) -static inline void update_rq_clock(struct rq *rq) +inline void update_rq_clock(struct rq *rq) { rq->clock = sched_clock_cpu(cpu_of(rq)); } @@ -1154,7 +1155,7 @@ static __init void init_hrtick(void) static void hrtick_start(struct rq *rq, u64 delay) { __hrtimer_start_range_ns(&rq->hrtick_timer, ns_to_ktime(delay), 0, - HRTIMER_MODE_REL, 0); + HRTIMER_MODE_REL_PINNED, 0); } static inline void init_hrtick(void) @@ -1728,6 +1729,8 @@ static void cfs_rq_set_shares(struct cfs_rq *cfs_rq, unsigned long shares) } #endif +static void calc_load_account_active(struct rq *this_rq); + #include "sched_stats.h" #include "sched_idletask.c" #include "sched_fair.c" @@ -1958,7 +1961,7 @@ void set_task_cpu(struct task_struct *p, unsigned int new_cpu) clock_offset = old_rq->clock - new_rq->clock; - trace_sched_migrate_task(p, task_cpu(p), new_cpu); + trace_sched_migrate_task(p, new_cpu); #ifdef CONFIG_SCHEDSTATS if (p->se.wait_start) @@ -1967,12 +1970,17 @@ void set_task_cpu(struct task_struct *p, unsigned int new_cpu) p->se.sleep_start -= clock_offset; if (p->se.block_start) p->se.block_start -= clock_offset; +#endif if (old_cpu != new_cpu) { - schedstat_inc(p, se.nr_migrations); + p->se.nr_migrations++; + new_rq->nr_migrations_in++; +#ifdef CONFIG_SCHEDSTATS if (task_hot(p, old_rq->clock, NULL)) schedstat_inc(p, se.nr_forced2_migrations); - } #endif + perf_swcounter_event(PERF_COUNT_SW_CPU_MIGRATIONS, + 1, 1, NULL, 0); + } p->se.vruntime -= old_cfsrq->min_vruntime - new_cfsrq->min_vruntime; @@ -2014,6 +2022,49 @@ migrate_task(struct task_struct *p, int dest_cpu, struct migration_req *req) return 1; } +/* + * wait_task_context_switch - wait for a thread to complete at least one + * context switch. + * + * @p must not be current. + */ +void wait_task_context_switch(struct task_struct *p) +{ + unsigned long nvcsw, nivcsw, flags; + int running; + struct rq *rq; + + nvcsw = p->nvcsw; + nivcsw = p->nivcsw; + for (;;) { + /* + * The runqueue is assigned before the actual context + * switch. We need to take the runqueue lock. + * + * We could check initially without the lock but it is + * very likely that we need to take the lock in every + * iteration. + */ + rq = task_rq_lock(p, &flags); + running = task_running(rq, p); + task_rq_unlock(rq, &flags); + + if (likely(!running)) + break; + /* + * The switch count is incremented before the actual + * context switch. We thus wait for two switches to be + * sure at least one completed. + */ + if ((p->nvcsw - nvcsw) > 1) + break; + if ((p->nivcsw - nivcsw) > 1) + break; + + cpu_relax(); + } +} + /* * wait_task_inactive - wait for a thread to unschedule. * @@ -2142,6 +2193,7 @@ void kick_process(struct task_struct *p) smp_send_reschedule(cpu); preempt_enable(); } +EXPORT_SYMBOL_GPL(kick_process); /* * Return a low guess at the load of a migration-source cpu weighted @@ -2324,6 +2376,27 @@ static int sched_balance_self(int cpu, int flag) #endif /* CONFIG_SMP */ +/** + * task_oncpu_function_call - call a function on the cpu on which a task runs + * @p: the task to evaluate + * @func: the function to be called + * @info: the function call argument + * + * Calls the function @func when the task is currently running. This might + * be on the current CPU, which just calls the function directly + */ +void task_oncpu_function_call(struct task_struct *p, + void (*func) (void *info), void *info) +{ + int cpu; + + preempt_disable(); + cpu = task_cpu(p); + if (task_curr(p)) + smp_call_function_single(cpu, func, info, 1); + preempt_enable(); +} + /*** * try_to_wake_up - wake up a thread * @p: the to-be-woken-up thread @@ -2458,6 +2531,17 @@ out: return success; } +/** + * wake_up_process - Wake up a specific process + * @p: The process to be woken up. + * + * Attempt to wake up the nominated process and move it to the set of runnable + * processes. Returns 1 if the process was woken up, 0 if it was already + * running. + * + * It may be assumed that this function implies a write memory barrier before + * changing the task state if and only if any tasks are woken up. + */ int wake_up_process(struct task_struct *p) { return try_to_wake_up(p, TASK_ALL, 0); @@ -2480,6 +2564,7 @@ static void __sched_fork(struct task_struct *p) p->se.exec_start = 0; p->se.sum_exec_runtime = 0; p->se.prev_sum_exec_runtime = 0; + p->se.nr_migrations = 0; p->se.last_wakeup = 0; p->se.avg_overlap = 0; p->se.start_runtime = 0; @@ -2710,6 +2795,7 @@ static void finish_task_switch(struct rq *rq, struct task_struct *prev) */ prev_state = prev->state; finish_arch_switch(prev); + perf_counter_task_sched_in(current, cpu_of(rq)); finish_lock_switch(rq, prev); #ifdef CONFIG_SMP if (post_schedule) @@ -2766,7 +2852,7 @@ context_switch(struct rq *rq, struct task_struct *prev, * combine the page table reload and the switch backend into * one hypercall. */ - arch_enter_lazy_cpu_mode(); + arch_start_context_switch(prev); if (unlikely(!mm)) { next->active_mm = oldmm; @@ -2856,19 +2942,81 @@ unsigned long nr_iowait(void) return sum; } -unsigned long nr_active(void) +/* Variables and functions for calc_load */ +static atomic_long_t calc_load_tasks; +static unsigned long calc_load_update; +unsigned long avenrun[3]; +EXPORT_SYMBOL(avenrun); + +/** + * get_avenrun - get the load average array + * @loads: pointer to dest load array + * @offset: offset to add + * @shift: shift count to shift the result left + * + * These values are estimates at best, so no need for locking. + */ +void get_avenrun(unsigned long *loads, unsigned long offset, int shift) { - unsigned long i, running = 0, uninterruptible = 0; + loads[0] = (avenrun[0] + offset) << shift; + loads[1] = (avenrun[1] + offset) << shift; + loads[2] = (avenrun[2] + offset) << shift; +} - for_each_online_cpu(i) { - running += cpu_rq(i)->nr_running; - uninterruptible += cpu_rq(i)->nr_uninterruptible; +static unsigned long +calc_load(unsigned long load, unsigned long exp, unsigned long active) +{ + load *= exp; + load += active * (FIXED_1 - exp); + return load >> FSHIFT; +} + +/* + * calc_load - update the avenrun load estimates 10 ticks after the + * CPUs have updated calc_load_tasks. + */ +void calc_global_load(void) +{ + unsigned long upd = calc_load_update + 10; + long active; + + if (time_before(jiffies, upd)) + return; + + active = atomic_long_read(&calc_load_tasks); + active = active > 0 ? active * FIXED_1 : 0; + + avenrun[0] = calc_load(avenrun[0], EXP_1, active); + avenrun[1] = calc_load(avenrun[1], EXP_5, active); + avenrun[2] = calc_load(avenrun[2], EXP_15, active); + + calc_load_update += LOAD_FREQ; +} + +/* + * Either called from update_cpu_load() or from a cpu going idle + */ +static void calc_load_account_active(struct rq *this_rq) +{ + long nr_active, delta; + + nr_active = this_rq->nr_running; + nr_active += (long) this_rq->nr_uninterruptible; + + if (nr_active != this_rq->calc_load_active) { + delta = nr_active - this_rq->calc_load_active; + this_rq->calc_load_active = nr_active; + atomic_long_add(delta, &calc_load_tasks); } +} - if (unlikely((long)uninterruptible < 0)) - uninterruptible = 0; - - return running + uninterruptible; +/* + * Externally visible per-cpu scheduler statistics: + * cpu_nr_migrations(cpu) - number of migrations into that cpu + */ +u64 cpu_nr_migrations(int cpu) +{ + return cpu_rq(cpu)->nr_migrations_in; } /* @@ -2899,6 +3047,11 @@ static void update_cpu_load(struct rq *this_rq) new_load += scale-1; this_rq->cpu_load[i] = (old_load*(scale-1) + new_load) >> i; } + + if (time_after_eq(jiffies, this_rq->calc_load_update)) { + this_rq->calc_load_update += LOAD_FREQ; + calc_load_account_active(this_rq); + } } #ifdef CONFIG_SMP @@ -4240,10 +4393,131 @@ static void active_load_balance(struct rq *busiest_rq, int busiest_cpu) static struct { atomic_t load_balancer; cpumask_var_t cpu_mask; + cpumask_var_t ilb_grp_nohz_mask; } nohz ____cacheline_aligned = { .load_balancer = ATOMIC_INIT(-1), }; +int get_nohz_load_balancer(void) +{ + return atomic_read(&nohz.load_balancer); +} + +#if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT) +/** + * lowest_flag_domain - Return lowest sched_domain containing flag. + * @cpu: The cpu whose lowest level of sched domain is to + * be returned. + * @flag: The flag to check for the lowest sched_domain + * for the given cpu. + * + * Returns the lowest sched_domain of a cpu which contains the given flag. + */ +static inline struct sched_domain *lowest_flag_domain(int cpu, int flag) +{ + struct sched_domain *sd; + + for_each_domain(cpu, sd) + if (sd && (sd->flags & flag)) + break; + + return sd; +} + +/** + * for_each_flag_domain - Iterates over sched_domains containing the flag. + * @cpu: The cpu whose domains we're iterating over. + * @sd: variable holding the value of the power_savings_sd + * for cpu. + * @flag: The flag to filter the sched_domains to be iterated. + * + * Iterates over all the scheduler domains for a given cpu that has the 'flag' + * set, starting from the lowest sched_domain to the highest. + */ +#define for_each_flag_domain(cpu, sd, flag) \ + for (sd = lowest_flag_domain(cpu, flag); \ + (sd && (sd->flags & flag)); sd = sd->parent) + +/** + * is_semi_idle_group - Checks if the given sched_group is semi-idle. + * @ilb_group: group to be checked for semi-idleness + * + * Returns: 1 if the group is semi-idle. 0 otherwise. + * + * We define a sched_group to be semi idle if it has atleast one idle-CPU + * and atleast one non-idle CPU. This helper function checks if the given + * sched_group is semi-idle or not. + */ +static inline int is_semi_idle_group(struct sched_group *ilb_group) +{ + cpumask_and(nohz.ilb_grp_nohz_mask, nohz.cpu_mask, + sched_group_cpus(ilb_group)); + + /* + * A sched_group is semi-idle when it has atleast one busy cpu + * and atleast one idle cpu. + */ + if (cpumask_empty(nohz.ilb_grp_nohz_mask)) + return 0; + + if (cpumask_equal(nohz.ilb_grp_nohz_mask, sched_group_cpus(ilb_group))) + return 0; + + return 1; +} +/** + * find_new_ilb - Finds the optimum idle load balancer for nomination. + * @cpu: The cpu which is nominating a new idle_load_balancer. + * + * Returns: Returns the id of the idle load balancer if it exists, + * Else, returns >= nr_cpu_ids. + * + * This algorithm picks the idle load balancer such that it belongs to a + * semi-idle powersavings sched_domain. The idea is to try and avoid + * completely idle packages/cores just for the purpose of idle load balancing + * when there are other idle cpu's which are better suited for that job. + */ +static int find_new_ilb(int cpu) +{ + struct sched_domain *sd; + struct sched_group *ilb_group; + + /* + * Have idle load balancer selection from semi-idle packages only + * when power-aware load balancing is enabled + */ + if (!(sched_smt_power_savings || sched_mc_power_savings)) + goto out_done; + + /* + * Optimize for the case when we have no idle CPUs or only one + * idle CPU. Don't walk the sched_domain hierarchy in such cases + */ + if (cpumask_weight(nohz.cpu_mask) < 2) + goto out_done; + + for_each_flag_domain(cpu, sd, SD_POWERSAVINGS_BALANCE) { + ilb_group = sd->groups; + + do { + if (is_semi_idle_group(ilb_group)) + return cpumask_first(nohz.ilb_grp_nohz_mask); + + ilb_group = ilb_group->next; + + } while (ilb_group != sd->groups); + } + +out_done: + return cpumask_first(nohz.cpu_mask); +} +#else /* (CONFIG_SCHED_MC || CONFIG_SCHED_SMT) */ +static inline int find_new_ilb(int call_cpu) +{ + return cpumask_first(nohz.cpu_mask); +} +#endif + /* * This routine will try to nominate the ilb (idle load balancing) * owner among the cpus whose ticks are stopped. ilb owner will do the idle @@ -4298,8 +4572,24 @@ int select_nohz_load_balancer(int stop_tick) /* make me the ilb owner */ if (atomic_cmpxchg(&nohz.load_balancer, -1, cpu) == -1) return 1; - } else if (atomic_read(&nohz.load_balancer) == cpu) + } else if (atomic_read(&nohz.load_balancer) == cpu) { + int new_ilb; + + if (!(sched_smt_power_savings || + sched_mc_power_savings)) + return 1; + /* + * Check to see if there is a more power-efficient + * ilb. + */ + new_ilb = find_new_ilb(cpu); + if (new_ilb < nr_cpu_ids && new_ilb != cpu) { + atomic_set(&nohz.load_balancer, -1); + resched_cpu(new_ilb); + return 0; + } return 1; + } } else { if (!cpumask_test_cpu(cpu, nohz.cpu_mask)) return 0; @@ -4468,15 +4758,7 @@ static inline void trigger_load_balance(struct rq *rq, int cpu) } if (atomic_read(&nohz.load_balancer) == -1) { - /* - * simple selection for now: Nominate the - * first cpu in the nohz list to be the next - * ilb owner. - * - * TBD: Traverse the sched domains and nominate - * the nearest cpu in the nohz.cpu_mask. - */ - int ilb = cpumask_first(nohz.cpu_mask); + int ilb = find_new_ilb(cpu); if (ilb < nr_cpu_ids) resched_cpu(ilb); @@ -4840,6 +5122,8 @@ void scheduler_tick(void) curr->sched_class->task_tick(rq, curr, 0); spin_unlock(&rq->lock); + perf_counter_task_tick(curr, cpu); + #ifdef CONFIG_SMP rq->idle_at_tick = idle_cpu(cpu); trigger_load_balance(rq, cpu); @@ -5007,13 +5291,15 @@ pick_next_task(struct rq *rq) /* * schedule() is the main scheduler function. */ -asmlinkage void __sched __schedule(void) +asmlinkage void __sched schedule(void) { struct task_struct *prev, *next; unsigned long *switch_count; struct rq *rq; int cpu; +need_resched: + preempt_disable(); cpu = smp_processor_id(); rq = cpu_rq(cpu); rcu_qsctr_inc(cpu); @@ -5053,6 +5339,7 @@ need_resched_nonpreemptible: if (likely(prev != next)) { sched_info_switch(prev, next); + perf_counter_task_sched_out(prev, next, cpu); rq->nr_switches++; rq->curr = next; @@ -5070,15 +5357,9 @@ need_resched_nonpreemptible: if (unlikely(reacquire_kernel_lock(current) < 0)) goto need_resched_nonpreemptible; -} -asmlinkage void __sched schedule(void) -{ -need_resched: - preempt_disable(); - __schedule(); preempt_enable_no_resched(); - if (unlikely(test_thread_flag(TIF_NEED_RESCHED))) + if (need_resched()) goto need_resched; } EXPORT_SYMBOL(schedule); @@ -5221,7 +5502,7 @@ EXPORT_SYMBOL(default_wake_function); * started to run but is not in state TASK_RUNNING. try_to_wake_up() returns * zero in this (rare) case, and we handle it by continuing to scan the queue. */ -void __wake_up_common(wait_queue_head_t *q, unsigned int mode, +static void __wake_up_common(wait_queue_head_t *q, unsigned int mode, int nr_exclusive, int sync, void *key) { wait_queue_t *curr, *next; @@ -5241,6 +5522,9 @@ void __wake_up_common(wait_queue_head_t *q, unsigned int mode, * @mode: which threads * @nr_exclusive: how many wake-one or wake-many threads to wake up * @key: is directly passed to the wakeup function + * + * It may be assumed that this function implies a write memory barrier before + * changing the task state if and only if any tasks are woken up. */ void __wake_up(wait_queue_head_t *q, unsigned int mode, int nr_exclusive, void *key) @@ -5279,6 +5563,9 @@ void __wake_up_locked_key(wait_queue_head_t *q, unsigned int mode, void *key) * with each other. This can prevent needless bouncing between CPUs. * * On UP it can prevent extra preemption. + * + * It may be assumed that this function implies a write memory barrier before + * changing the task state if and only if any tasks are woken up. */ void __wake_up_sync_key(wait_queue_head_t *q, unsigned int mode, int nr_exclusive, void *key) @@ -5315,6 +5602,9 @@ EXPORT_SYMBOL_GPL(__wake_up_sync); /* For internal use only */ * awakened in the same order in which they were queued. * * See also complete_all(), wait_for_completion() and related routines. + * + * It may be assumed that this function implies a write memory barrier before + * changing the task state if and only if any tasks are woken up. */ void complete(struct completion *x) { @@ -5332,6 +5622,9 @@ EXPORT_SYMBOL(complete); * @x: holds the state of this particular completion * * This will wake up all threads waiting on this particular completion event. + * + * It may be assumed that this function implies a write memory barrier before + * changing the task state if and only if any tasks are woken up. */ void complete_all(struct completion *x) { @@ -6490,8 +6783,9 @@ void sched_show_task(struct task_struct *p) #ifdef CONFIG_DEBUG_STACK_USAGE free = stack_not_used(p); #endif - printk(KERN_CONT "%5lu %5d %6d\n", free, - task_pid_nr(p), task_pid_nr(p->real_parent)); + printk(KERN_CONT "%5lu %5d %6d 0x%08lx\n", free, + task_pid_nr(p), task_pid_nr(p->real_parent), + (unsigned long)task_thread_info(p)->flags); show_stack(p, NULL); } @@ -6752,7 +7046,7 @@ static int migration_thread(void *data) if (cpu_is_offline(cpu)) { spin_unlock_irq(&rq->lock); - goto wait_to_die; + break; } if (rq->active_balance) { @@ -6778,16 +7072,7 @@ static int migration_thread(void *data) complete(&req->done); } __set_current_state(TASK_RUNNING); - return 0; -wait_to_die: - /* Wait for kthread_stop */ - set_current_state(TASK_INTERRUPTIBLE); - while (!kthread_should_stop()) { - schedule(); - set_current_state(TASK_INTERRUPTIBLE); - } - __set_current_state(TASK_RUNNING); return 0; } @@ -6970,6 +7255,14 @@ static void migrate_dead_tasks(unsigned int dead_cpu) } } + +/* + * remove the tasks which were accounted by rq from calc_load_tasks. + */ +static void calc_global_load_remove(struct rq *rq) +{ + atomic_long_sub(rq->calc_load_active, &calc_load_tasks); +} #endif /* CONFIG_HOTPLUG_CPU */ #if defined(CONFIG_SCHED_DEBUG) && defined(CONFIG_SYSCTL) @@ -7193,6 +7486,7 @@ migration_call(struct notifier_block *nfb, unsigned long action, void *hcpu) rq = task_rq_lock(p, &flags); __setscheduler(rq, p, SCHED_FIFO, MAX_RT_PRIO-1); task_rq_unlock(rq, &flags); + get_task_struct(p); cpu_rq(cpu)->migration_thread = p; break; @@ -7204,6 +7498,8 @@ migration_call(struct notifier_block *nfb, unsigned long action, void *hcpu) /* Update our root-domain */ rq = cpu_rq(cpu); spin_lock_irqsave(&rq->lock, flags); + rq->calc_load_update = calc_load_update; + rq->calc_load_active = 0; if (rq->rd) { BUG_ON(!cpumask_test_cpu(cpu, rq->rd->span)); @@ -7221,6 +7517,7 @@ migration_call(struct notifier_block *nfb, unsigned long action, void *hcpu) kthread_bind(cpu_rq(cpu)->migration_thread, cpumask_any(cpu_online_mask)); kthread_stop(cpu_rq(cpu)->migration_thread); + put_task_struct(cpu_rq(cpu)->migration_thread); cpu_rq(cpu)->migration_thread = NULL; break; @@ -7230,6 +7527,7 @@ migration_call(struct notifier_block *nfb, unsigned long action, void *hcpu) migrate_live_tasks(cpu); rq = cpu_rq(cpu); kthread_stop(rq->migration_thread); + put_task_struct(rq->migration_thread); rq->migration_thread = NULL; /* Idle task back to normal (off runqueue, low prio) */ spin_lock_irq(&rq->lock); @@ -7243,7 +7541,7 @@ migration_call(struct notifier_block *nfb, unsigned long action, void *hcpu) cpuset_unlock(); migrate_nr_uninterruptible(rq); BUG_ON(rq->nr_running != 0); - + calc_global_load_remove(rq); /* * No need to migrate the tasks: it was best-effort if * they didn't take sched_hotcpu_mutex. Just wake up @@ -7279,8 +7577,10 @@ migration_call(struct notifier_block *nfb, unsigned long action, void *hcpu) return NOTIFY_OK; } -/* Register at highest priority so that task migration (migrate_all_tasks) - * happens before everything else. +/* + * Register at high priority so that task migration (migrate_all_tasks) + * happens before everything else. This has to be lower priority than + * the notifier in the perf_counter subsystem, though. */ static struct notifier_block __cpuinitdata migration_notifier = { .notifier_call = migration_call, @@ -7523,26 +7823,23 @@ static void rq_attach_root(struct rq *rq, struct root_domain *rd) free_rootdomain(old_rd); } -static int __init_refok init_rootdomain(struct root_domain *rd, bool bootmem) +static int init_rootdomain(struct root_domain *rd, bool bootmem) { + gfp_t gfp = GFP_KERNEL; + memset(rd, 0, sizeof(*rd)); - if (bootmem) { - alloc_bootmem_cpumask_var(&def_root_domain.span); - alloc_bootmem_cpumask_var(&def_root_domain.online); - alloc_bootmem_cpumask_var(&def_root_domain.rto_mask); - cpupri_init(&rd->cpupri, true); - return 0; - } + if (bootmem) + gfp = GFP_NOWAIT; - if (!alloc_cpumask_var(&rd->span, GFP_KERNEL)) + if (!alloc_cpumask_var(&rd->span, gfp)) goto out; - if (!alloc_cpumask_var(&rd->online, GFP_KERNEL)) + if (!alloc_cpumask_var(&rd->online, gfp)) goto free_span; - if (!alloc_cpumask_var(&rd->rto_mask, GFP_KERNEL)) + if (!alloc_cpumask_var(&rd->rto_mask, gfp)) goto free_online; - if (cpupri_init(&rd->cpupri, false) != 0) + if (cpupri_init(&rd->cpupri, bootmem) != 0) goto free_rto_mask; return 0; @@ -7753,8 +8050,9 @@ int sched_smt_power_savings = 0, sched_mc_power_savings = 0; /* * The cpus mask in sched_group and sched_domain hangs off the end. - * FIXME: use cpumask_var_t or dynamic percpu alloc to avoid wasting space - * for nr_cpu_ids < CONFIG_NR_CPUS. + * + * ( See the the comments in include/linux/sched.h:struct sched_group + * and struct sched_domain. ) */ struct static_sched_group { struct sched_group sg; @@ -7875,7 +8173,7 @@ static void init_numa_sched_groups_power(struct sched_group *group_head) struct sched_domain *sd; sd = &per_cpu(phys_domains, j).sd; - if (j != cpumask_first(sched_group_cpus(sd->groups))) { + if (j != group_first_cpu(sd->groups)) { /* * Only add "power" once for each * physical package. @@ -7953,7 +8251,7 @@ static void init_sched_groups_power(int cpu, struct sched_domain *sd) WARN_ON(!sd || !sd->groups); - if (cpu != cpumask_first(sched_group_cpus(sd->groups))) + if (cpu != group_first_cpu(sd->groups)) return; child = sd->child; @@ -8731,6 +9029,8 @@ void __init sched_init_smp(void) } #endif /* CONFIG_SMP */ +const_debug unsigned int sysctl_timer_migration = 1; + int in_sched_functions(unsigned long addr) { return in_lock_functions(addr) || @@ -8865,7 +9165,7 @@ void __init sched_init(void) * we use alloc_bootmem(). */ if (alloc_size) { - ptr = (unsigned long)alloc_bootmem(alloc_size); + ptr = (unsigned long)kzalloc(alloc_size, GFP_NOWAIT); #ifdef CONFIG_FAIR_GROUP_SCHED init_task_group.se = (struct sched_entity **)ptr; @@ -8938,6 +9238,8 @@ void __init sched_init(void) rq = cpu_rq(i); spin_lock_init(&rq->lock); rq->nr_running = 0; + rq->calc_load_active = 0; + rq->calc_load_update = jiffies + LOAD_FREQ; init_cfs_rq(&rq->cfs, rq); init_rt_rq(&rq->rt, rq); #ifdef CONFIG_FAIR_GROUP_SCHED @@ -8958,7 +9260,7 @@ void __init sched_init(void) * 1024) and two child groups A0 and A1 (of weight 1024 each), * then A0's share of the cpu resource is: * - * A0's bandwidth = 1024 / (10*1024 + 1024 + 1024) = 8.33% + * A0's bandwidth = 1024 / (10*1024 + 1024 + 1024) = 8.33% * * We achieve this by letting init_task_group's tasks sit * directly in rq->cfs (i.e init_task_group->se[] = NULL). @@ -9045,20 +9347,26 @@ void __init sched_init(void) * when this runqueue becomes "idle". */ init_idle(current, smp_processor_id()); + + calc_load_update = jiffies + LOAD_FREQ; + /* * During early bootup we pretend to be a normal task: */ current->sched_class = &fair_sched_class; /* Allocate the nohz_cpu_mask if CONFIG_CPUMASK_OFFSTACK */ - alloc_bootmem_cpumask_var(&nohz_cpu_mask); + alloc_cpumask_var(&nohz_cpu_mask, GFP_NOWAIT); #ifdef CONFIG_SMP #ifdef CONFIG_NO_HZ - alloc_bootmem_cpumask_var(&nohz.cpu_mask); + alloc_cpumask_var(&nohz.cpu_mask, GFP_NOWAIT); + alloc_cpumask_var(&nohz.ilb_grp_nohz_mask, GFP_NOWAIT); #endif - alloc_bootmem_cpumask_var(&cpu_isolated_map); + alloc_cpumask_var(&cpu_isolated_map, GFP_NOWAIT); #endif /* SMP */ + perf_counter_init(); + scheduler_running = 1; } @@ -9800,6 +10108,13 @@ static int sched_rt_global_constraints(void) if (sysctl_sched_rt_period <= 0) return -EINVAL; + /* + * There's always some RT tasks in the root group + * -- migration, kstopmachine etc.. + */ + if (sysctl_sched_rt_runtime == 0) + return -EBUSY; + spin_lock_irqsave(&def_rt_bandwidth.rt_runtime_lock, flags); for_each_possible_cpu(i) { struct rt_rq *rt_rq = &cpu_rq(i)->rt; diff --git a/kernel/sched_cpupri.c b/kernel/sched_cpupri.c index 344712a5e3ed..e6c251790dde 100644 --- a/kernel/sched_cpupri.c +++ b/kernel/sched_cpupri.c @@ -152,10 +152,14 @@ void cpupri_set(struct cpupri *cp, int cpu, int newpri) * * Returns: -ENOMEM if memory fails. */ -int __init_refok cpupri_init(struct cpupri *cp, bool bootmem) +int cpupri_init(struct cpupri *cp, bool bootmem) { + gfp_t gfp = GFP_KERNEL; int i; + if (bootmem) + gfp = GFP_NOWAIT; + memset(cp, 0, sizeof(*cp)); for (i = 0; i < CPUPRI_NR_PRIORITIES; i++) { @@ -163,9 +167,7 @@ int __init_refok cpupri_init(struct cpupri *cp, bool bootmem) spin_lock_init(&vec->lock); vec->count = 0; - if (bootmem) - alloc_bootmem_cpumask_var(&vec->mask); - else if (!zalloc_cpumask_var(&vec->mask, GFP_KERNEL)) + if (!zalloc_cpumask_var(&vec->mask, gfp)) goto cleanup; } diff --git a/kernel/sched_debug.c b/kernel/sched_debug.c index 467ca72f1657..70c7e0b79946 100644 --- a/kernel/sched_debug.c +++ b/kernel/sched_debug.c @@ -162,7 +162,7 @@ void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq) { s64 MIN_vruntime = -1, min_vruntime, max_vruntime = -1, spread, rq0_min_vruntime, spread0; - struct rq *rq = &per_cpu(runqueues, cpu); + struct rq *rq = cpu_rq(cpu); struct sched_entity *last; unsigned long flags; @@ -191,7 +191,7 @@ void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq) if (last) max_vruntime = last->vruntime; min_vruntime = cfs_rq->min_vruntime; - rq0_min_vruntime = per_cpu(runqueues, 0).cfs.min_vruntime; + rq0_min_vruntime = cpu_rq(0)->cfs.min_vruntime; spin_unlock_irqrestore(&rq->lock, flags); SEQ_printf(m, " .%-30s: %Ld.%06ld\n", "MIN_vruntime", SPLIT_NS(MIN_vruntime)); @@ -248,7 +248,7 @@ void print_rt_rq(struct seq_file *m, int cpu, struct rt_rq *rt_rq) static void print_cpu(struct seq_file *m, int cpu) { - struct rq *rq = &per_cpu(runqueues, cpu); + struct rq *rq = cpu_rq(cpu); #ifdef CONFIG_X86 { diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c index 3816f217f119..ba7fd6e9556f 100644 --- a/kernel/sched_fair.c +++ b/kernel/sched_fair.c @@ -430,12 +430,13 @@ static u64 sched_slice(struct cfs_rq *cfs_rq, struct sched_entity *se) for_each_sched_entity(se) { struct load_weight *load; + struct load_weight lw; cfs_rq = cfs_rq_of(se); load = &cfs_rq->load; if (unlikely(!se->on_rq)) { - struct load_weight lw = cfs_rq->load; + lw = cfs_rq->load; update_load_add(&lw, se->load.weight); load = &lw; @@ -1487,17 +1488,10 @@ static void check_preempt_wakeup(struct rq *rq, struct task_struct *p, int sync) find_matching_se(&se, &pse); - while (se) { - BUG_ON(!pse); + BUG_ON(!pse); - if (wakeup_preempt_entity(se, pse) == 1) { - resched_task(curr); - break; - } - - se = parent_entity(se); - pse = parent_entity(pse); - } + if (wakeup_preempt_entity(se, pse) == 1) + resched_task(curr); } static struct task_struct *pick_next_task_fair(struct rq *rq) diff --git a/kernel/sched_idletask.c b/kernel/sched_idletask.c index 8a21a2e28c13..499672c10cbd 100644 --- a/kernel/sched_idletask.c +++ b/kernel/sched_idletask.c @@ -22,7 +22,8 @@ static void check_preempt_curr_idle(struct rq *rq, struct task_struct *p, int sy static struct task_struct *pick_next_task_idle(struct rq *rq) { schedstat_inc(rq, sched_goidle); - + /* adjust the active tasks as we might go into a long sleep */ + calc_load_account_active(rq); return rq->idle; } diff --git a/kernel/signal.c b/kernel/signal.c index d8034737db4c..ccf1ceedaebe 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include @@ -41,8 +41,6 @@ static struct kmem_cache *sigqueue_cachep; -DEFINE_TRACE(sched_signal_send); - static void __user *sig_handler(struct task_struct *t, int sig) { return t->sighand->action[sig - 1].sa.sa_handler; @@ -249,14 +247,19 @@ void flush_sigqueue(struct sigpending *queue) /* * Flush all pending signals for a task. */ +void __flush_signals(struct task_struct *t) +{ + clear_tsk_thread_flag(t, TIF_SIGPENDING); + flush_sigqueue(&t->pending); + flush_sigqueue(&t->signal->shared_pending); +} + void flush_signals(struct task_struct *t) { unsigned long flags; spin_lock_irqsave(&t->sighand->siglock, flags); - clear_tsk_thread_flag(t, TIF_SIGPENDING); - flush_sigqueue(&t->pending); - flush_sigqueue(&t->signal->shared_pending); + __flush_signals(t); spin_unlock_irqrestore(&t->sighand->siglock, flags); } @@ -829,6 +832,7 @@ static int __send_signal(int sig, struct siginfo *info, struct task_struct *t, { struct sigpending *pending; struct sigqueue *q; + int override_rlimit; trace_sched_signal_send(sig, t); @@ -860,9 +864,13 @@ static int __send_signal(int sig, struct siginfo *info, struct task_struct *t, make sure at least one signal gets delivered and don't pass on the info struct. */ - q = __sigqueue_alloc(t, GFP_ATOMIC, (sig < SIGRTMIN && - (is_si_special(info) || - info->si_code >= 0))); + if (sig < SIGRTMIN) + override_rlimit = (is_si_special(info) || info->si_code >= 0); + else + override_rlimit = 0; + + q = __sigqueue_alloc(t, GFP_ATOMIC | __GFP_NOTRACK_FALSE_POSITIVE, + override_rlimit); if (q) { list_add_tail(&q->list, &pending->list); switch ((unsigned long) info) { @@ -1402,7 +1410,7 @@ int do_notify_parent(struct task_struct *tsk, int sig) /* do_notify_parent_cldstop should have been called instead. */ BUG_ON(task_is_stopped_or_traced(tsk)); - BUG_ON(!tsk->ptrace && + BUG_ON(!task_ptrace(tsk) && (tsk->group_leader != tsk || !thread_group_empty(tsk))); info.si_signo = sig; @@ -1441,7 +1449,7 @@ int do_notify_parent(struct task_struct *tsk, int sig) psig = tsk->parent->sighand; spin_lock_irqsave(&psig->siglock, flags); - if (!tsk->ptrace && sig == SIGCHLD && + if (!task_ptrace(tsk) && sig == SIGCHLD && (psig->action[SIGCHLD-1].sa.sa_handler == SIG_IGN || (psig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDWAIT))) { /* @@ -1478,7 +1486,7 @@ static void do_notify_parent_cldstop(struct task_struct *tsk, int why) struct task_struct *parent; struct sighand_struct *sighand; - if (tsk->ptrace & PT_PTRACED) + if (task_ptrace(tsk)) parent = tsk->parent; else { tsk = tsk->group_leader; @@ -1491,7 +1499,7 @@ static void do_notify_parent_cldstop(struct task_struct *tsk, int why) * see comment in do_notify_parent() abot the following 3 lines */ rcu_read_lock(); - info.si_pid = task_pid_nr_ns(tsk, tsk->parent->nsproxy->pid_ns); + info.si_pid = task_pid_nr_ns(tsk, parent->nsproxy->pid_ns); info.si_uid = __task_cred(tsk)->uid; rcu_read_unlock(); @@ -1527,7 +1535,7 @@ static void do_notify_parent_cldstop(struct task_struct *tsk, int why) static inline int may_ptrace_stop(void) { - if (!likely(current->ptrace & PT_PTRACED)) + if (!likely(task_ptrace(current))) return 0; /* * Are we in the middle of do_coredump? @@ -1745,7 +1753,7 @@ static int do_signal_stop(int signr) static int ptrace_signal(int signr, siginfo_t *info, struct pt_regs *regs, void *cookie) { - if (!(current->ptrace & PT_PTRACED)) + if (!task_ptrace(current)) return signr; ptrace_signal_deliver(regs, cookie); @@ -2278,24 +2286,17 @@ SYSCALL_DEFINE2(kill, pid_t, pid, int, sig) return kill_something_info(sig, &info, pid); } -static int do_tkill(pid_t tgid, pid_t pid, int sig) +static int +do_send_specific(pid_t tgid, pid_t pid, int sig, struct siginfo *info) { - int error; - struct siginfo info; struct task_struct *p; unsigned long flags; - - error = -ESRCH; - info.si_signo = sig; - info.si_errno = 0; - info.si_code = SI_TKILL; - info.si_pid = task_tgid_vnr(current); - info.si_uid = current_uid(); + int error = -ESRCH; rcu_read_lock(); p = find_task_by_vpid(pid); if (p && (tgid <= 0 || task_tgid_vnr(p) == tgid)) { - error = check_kill_permission(sig, &info, p); + error = check_kill_permission(sig, info, p); /* * The null signal is a permissions and process existence * probe. No signal is actually delivered. @@ -2305,7 +2306,7 @@ static int do_tkill(pid_t tgid, pid_t pid, int sig) * signal is private anyway. */ if (!error && sig && lock_task_sighand(p, &flags)) { - error = specific_send_sig_info(sig, &info, p); + error = specific_send_sig_info(sig, info, p); unlock_task_sighand(p, &flags); } } @@ -2314,6 +2315,19 @@ static int do_tkill(pid_t tgid, pid_t pid, int sig) return error; } +static int do_tkill(pid_t tgid, pid_t pid, int sig) +{ + struct siginfo info; + + info.si_signo = sig; + info.si_errno = 0; + info.si_code = SI_TKILL; + info.si_pid = task_tgid_vnr(current); + info.si_uid = current_uid(); + + return do_send_specific(tgid, pid, sig, &info); +} + /** * sys_tgkill - send signal to one specific thread * @tgid: the thread group ID of the thread @@ -2363,6 +2377,32 @@ SYSCALL_DEFINE3(rt_sigqueueinfo, pid_t, pid, int, sig, return kill_proc_info(sig, &info, pid); } +long do_rt_tgsigqueueinfo(pid_t tgid, pid_t pid, int sig, siginfo_t *info) +{ + /* This is only valid for single tasks */ + if (pid <= 0 || tgid <= 0) + return -EINVAL; + + /* Not even root can pretend to send signals from the kernel. + Nor can they impersonate a kill(), which adds source info. */ + if (info->si_code >= 0) + return -EPERM; + info->si_signo = sig; + + return do_send_specific(tgid, pid, sig, info); +} + +SYSCALL_DEFINE4(rt_tgsigqueueinfo, pid_t, tgid, pid_t, pid, int, sig, + siginfo_t __user *, uinfo) +{ + siginfo_t info; + + if (copy_from_user(&info, uinfo, sizeof(siginfo_t))) + return -EFAULT; + + return do_rt_tgsigqueueinfo(tgid, pid, sig, &info); +} + int do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact) { struct task_struct *t = current; diff --git a/kernel/slow-work.c b/kernel/slow-work.c index b28d19135f43..09d7519557d3 100644 --- a/kernel/slow-work.c +++ b/kernel/slow-work.c @@ -318,6 +318,15 @@ cant_get_ref: } EXPORT_SYMBOL(slow_work_enqueue); +/* + * Schedule a cull of the thread pool at some time in the near future + */ +static void slow_work_schedule_cull(void) +{ + mod_timer(&slow_work_cull_timer, + round_jiffies(jiffies + SLOW_WORK_CULL_TIMEOUT)); +} + /* * Worker thread culling algorithm */ @@ -335,8 +344,7 @@ static bool slow_work_cull_thread(void) list_empty(&vslow_work_queue) && atomic_read(&slow_work_thread_count) > slow_work_min_threads) { - mod_timer(&slow_work_cull_timer, - jiffies + SLOW_WORK_CULL_TIMEOUT); + slow_work_schedule_cull(); do_cull = true; } } @@ -372,8 +380,8 @@ static int slow_work_thread(void *_data) vsmax *= atomic_read(&slow_work_thread_count); vsmax /= 100; - prepare_to_wait(&slow_work_thread_wq, &wait, - TASK_INTERRUPTIBLE); + prepare_to_wait_exclusive(&slow_work_thread_wq, &wait, + TASK_INTERRUPTIBLE); if (!freezing(current) && !slow_work_threads_should_exit && !slow_work_available(vsmax) && @@ -393,8 +401,7 @@ static int slow_work_thread(void *_data) list_empty(&vslow_work_queue) && atomic_read(&slow_work_thread_count) > slow_work_min_threads) - mod_timer(&slow_work_cull_timer, - jiffies + SLOW_WORK_CULL_TIMEOUT); + slow_work_schedule_cull(); continue; } @@ -458,7 +465,7 @@ static void slow_work_new_thread_execute(struct slow_work *work) if (atomic_dec_and_test(&slow_work_thread_count)) BUG(); /* we're running on a slow work thread... */ mod_timer(&slow_work_oom_timer, - jiffies + SLOW_WORK_OOM_TIMEOUT); + round_jiffies(jiffies + SLOW_WORK_OOM_TIMEOUT)); } else { /* ratelimit the starting of new threads */ mod_timer(&slow_work_oom_timer, jiffies + 1); @@ -502,8 +509,7 @@ static int slow_work_min_threads_sysctl(struct ctl_table *table, int write, if (n < 0 && !slow_work_may_not_start_new_thread) slow_work_enqueue(&slow_work_new_thread); else if (n > 0) - mod_timer(&slow_work_cull_timer, - jiffies + SLOW_WORK_CULL_TIMEOUT); + slow_work_schedule_cull(); } mutex_unlock(&slow_work_user_lock); } @@ -529,8 +535,7 @@ static int slow_work_max_threads_sysctl(struct ctl_table *table, int write, atomic_read(&slow_work_thread_count); if (n < 0) - mod_timer(&slow_work_cull_timer, - jiffies + SLOW_WORK_CULL_TIMEOUT); + slow_work_schedule_cull(); } mutex_unlock(&slow_work_user_lock); } diff --git a/kernel/softirq.c b/kernel/softirq.c index b525dd348511..3a94905fa5d2 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -24,7 +24,9 @@ #include #include #include -#include + +#define CREATE_TRACE_POINTS +#include #include /* @@ -186,9 +188,6 @@ EXPORT_SYMBOL(local_bh_enable_ip); */ #define MAX_SOFTIRQ_RESTART 10 -DEFINE_TRACE(softirq_entry); -DEFINE_TRACE(softirq_exit); - asmlinkage void __do_softirq(void) { struct softirq_action *h; @@ -214,6 +213,7 @@ restart: do { if (pending & 1) { int prev_count = preempt_count(); + kstat_incr_softirqs_this_cpu(h - softirq_vec); trace_softirq_entry(h, softirq_vec); h->action(h); @@ -383,6 +383,17 @@ void __tasklet_hi_schedule(struct tasklet_struct *t) EXPORT_SYMBOL(__tasklet_hi_schedule); +void __tasklet_hi_schedule_first(struct tasklet_struct *t) +{ + BUG_ON(!irqs_disabled()); + + t->next = __get_cpu_var(tasklet_hi_vec).head; + __get_cpu_var(tasklet_hi_vec).head = t; + __raise_softirq_irqoff(HI_SOFTIRQ); +} + +EXPORT_SYMBOL(__tasklet_hi_schedule_first); + static void tasklet_action(struct softirq_action *a) { struct tasklet_struct *list; @@ -828,7 +839,7 @@ int __init __weak arch_early_irq_init(void) return 0; } -int __weak arch_init_chip_data(struct irq_desc *desc, int cpu) +int __weak arch_init_chip_data(struct irq_desc *desc, int node) { return 0; } diff --git a/kernel/sys.c b/kernel/sys.c index e7998cf31498..b3f1097c76fa 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -1112,289 +1113,6 @@ out: return err; } -/* - * Supplementary group IDs - */ - -/* init to 2 - one for init_task, one to ensure it is never freed */ -struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; - -struct group_info *groups_alloc(int gidsetsize) -{ - struct group_info *group_info; - int nblocks; - int i; - - nblocks = (gidsetsize + NGROUPS_PER_BLOCK - 1) / NGROUPS_PER_BLOCK; - /* Make sure we always allocate at least one indirect block pointer */ - nblocks = nblocks ? : 1; - group_info = kmalloc(sizeof(*group_info) + nblocks*sizeof(gid_t *), GFP_USER); - if (!group_info) - return NULL; - group_info->ngroups = gidsetsize; - group_info->nblocks = nblocks; - atomic_set(&group_info->usage, 1); - - if (gidsetsize <= NGROUPS_SMALL) - group_info->blocks[0] = group_info->small_block; - else { - for (i = 0; i < nblocks; i++) { - gid_t *b; - b = (void *)__get_free_page(GFP_USER); - if (!b) - goto out_undo_partial_alloc; - group_info->blocks[i] = b; - } - } - return group_info; - -out_undo_partial_alloc: - while (--i >= 0) { - free_page((unsigned long)group_info->blocks[i]); - } - kfree(group_info); - return NULL; -} - -EXPORT_SYMBOL(groups_alloc); - -void groups_free(struct group_info *group_info) -{ - if (group_info->blocks[0] != group_info->small_block) { - int i; - for (i = 0; i < group_info->nblocks; i++) - free_page((unsigned long)group_info->blocks[i]); - } - kfree(group_info); -} - -EXPORT_SYMBOL(groups_free); - -/* export the group_info to a user-space array */ -static int groups_to_user(gid_t __user *grouplist, - const struct group_info *group_info) -{ - int i; - unsigned int count = group_info->ngroups; - - for (i = 0; i < group_info->nblocks; i++) { - unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); - unsigned int len = cp_count * sizeof(*grouplist); - - if (copy_to_user(grouplist, group_info->blocks[i], len)) - return -EFAULT; - - grouplist += NGROUPS_PER_BLOCK; - count -= cp_count; - } - return 0; -} - -/* fill a group_info from a user-space array - it must be allocated already */ -static int groups_from_user(struct group_info *group_info, - gid_t __user *grouplist) -{ - int i; - unsigned int count = group_info->ngroups; - - for (i = 0; i < group_info->nblocks; i++) { - unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); - unsigned int len = cp_count * sizeof(*grouplist); - - if (copy_from_user(group_info->blocks[i], grouplist, len)) - return -EFAULT; - - grouplist += NGROUPS_PER_BLOCK; - count -= cp_count; - } - return 0; -} - -/* a simple Shell sort */ -static void groups_sort(struct group_info *group_info) -{ - int base, max, stride; - int gidsetsize = group_info->ngroups; - - for (stride = 1; stride < gidsetsize; stride = 3 * stride + 1) - ; /* nothing */ - stride /= 3; - - while (stride) { - max = gidsetsize - stride; - for (base = 0; base < max; base++) { - int left = base; - int right = left + stride; - gid_t tmp = GROUP_AT(group_info, right); - - while (left >= 0 && GROUP_AT(group_info, left) > tmp) { - GROUP_AT(group_info, right) = - GROUP_AT(group_info, left); - right = left; - left -= stride; - } - GROUP_AT(group_info, right) = tmp; - } - stride /= 3; - } -} - -/* a simple bsearch */ -int groups_search(const struct group_info *group_info, gid_t grp) -{ - unsigned int left, right; - - if (!group_info) - return 0; - - left = 0; - right = group_info->ngroups; - while (left < right) { - unsigned int mid = (left+right)/2; - int cmp = grp - GROUP_AT(group_info, mid); - if (cmp > 0) - left = mid + 1; - else if (cmp < 0) - right = mid; - else - return 1; - } - return 0; -} - -/** - * set_groups - Change a group subscription in a set of credentials - * @new: The newly prepared set of credentials to alter - * @group_info: The group list to install - * - * Validate a group subscription and, if valid, insert it into a set - * of credentials. - */ -int set_groups(struct cred *new, struct group_info *group_info) -{ - int retval; - - retval = security_task_setgroups(group_info); - if (retval) - return retval; - - put_group_info(new->group_info); - groups_sort(group_info); - get_group_info(group_info); - new->group_info = group_info; - return 0; -} - -EXPORT_SYMBOL(set_groups); - -/** - * set_current_groups - Change current's group subscription - * @group_info: The group list to impose - * - * Validate a group subscription and, if valid, impose it upon current's task - * security record. - */ -int set_current_groups(struct group_info *group_info) -{ - struct cred *new; - int ret; - - new = prepare_creds(); - if (!new) - return -ENOMEM; - - ret = set_groups(new, group_info); - if (ret < 0) { - abort_creds(new); - return ret; - } - - return commit_creds(new); -} - -EXPORT_SYMBOL(set_current_groups); - -SYSCALL_DEFINE2(getgroups, int, gidsetsize, gid_t __user *, grouplist) -{ - const struct cred *cred = current_cred(); - int i; - - if (gidsetsize < 0) - return -EINVAL; - - /* no need to grab task_lock here; it cannot change */ - i = cred->group_info->ngroups; - if (gidsetsize) { - if (i > gidsetsize) { - i = -EINVAL; - goto out; - } - if (groups_to_user(grouplist, cred->group_info)) { - i = -EFAULT; - goto out; - } - } -out: - return i; -} - -/* - * SMP: Our groups are copy-on-write. We can set them safely - * without another task interfering. - */ - -SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t __user *, grouplist) -{ - struct group_info *group_info; - int retval; - - if (!capable(CAP_SETGID)) - return -EPERM; - if ((unsigned)gidsetsize > NGROUPS_MAX) - return -EINVAL; - - group_info = groups_alloc(gidsetsize); - if (!group_info) - return -ENOMEM; - retval = groups_from_user(group_info, grouplist); - if (retval) { - put_group_info(group_info); - return retval; - } - - retval = set_current_groups(group_info); - put_group_info(group_info); - - return retval; -} - -/* - * Check whether we're fsgid/egid or in the supplemental group.. - */ -int in_group_p(gid_t grp) -{ - const struct cred *cred = current_cred(); - int retval = 1; - - if (grp != cred->fsgid) - retval = groups_search(cred->group_info, grp); - return retval; -} - -EXPORT_SYMBOL(in_group_p); - -int in_egroup_p(gid_t grp) -{ - const struct cred *cred = current_cred(); - int retval = 1; - - if (grp != cred->egid) - retval = groups_search(cred->group_info, grp); - return retval; -} - -EXPORT_SYMBOL(in_egroup_p); - DECLARE_RWSEM(uts_sem); SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name) @@ -1793,6 +1511,12 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, case PR_SET_TSC: error = SET_TSC_CTL(arg2); break; + case PR_TASK_PERF_COUNTERS_DISABLE: + error = perf_counter_task_disable(); + break; + case PR_TASK_PERF_COUNTERS_ENABLE: + error = perf_counter_task_enable(); + break; case PR_GET_TIMERSLACK: error = current->timer_slack_ns; break; diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c index 27dad2967387..68320f6b07b5 100644 --- a/kernel/sys_ni.c +++ b/kernel/sys_ni.c @@ -175,3 +175,6 @@ cond_syscall(compat_sys_timerfd_settime); cond_syscall(compat_sys_timerfd_gettime); cond_syscall(sys_eventfd); cond_syscall(sys_eventfd2); + +/* performance counters: */ +cond_syscall(sys_perf_counter_open); diff --git a/kernel/sysctl.c b/kernel/sysctl.c index b2970d56fb76..62e4ff9968b5 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -49,6 +50,7 @@ #include #include #include +#include #include #include @@ -114,6 +116,7 @@ static int ngroups_max = NGROUPS_MAX; #ifdef CONFIG_MODULES extern char modprobe_path[]; +extern int modules_disabled; #endif #ifdef CONFIG_CHR_DEV_SG extern int sg_big_buff; @@ -326,6 +329,14 @@ static struct ctl_table kern_table[] = { .mode = 0644, .proc_handler = &proc_dointvec, }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "timer_migration", + .data = &sysctl_timer_migration, + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, #endif { .ctl_name = CTL_UNNUMBERED, @@ -534,6 +545,17 @@ static struct ctl_table kern_table[] = { .proc_handler = &proc_dostring, .strategy = &sysctl_string, }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "modules_disabled", + .data = &modules_disabled, + .maxlen = sizeof(int), + .mode = 0644, + /* only handle a transition from default "0" to "1" */ + .proc_handler = &proc_dointvec_minmax, + .extra1 = &one, + .extra2 = &one, + }, #endif #if defined(CONFIG_HOTPLUG) && defined(CONFIG_NET) { @@ -729,6 +751,14 @@ static struct ctl_table kern_table[] = { .mode = 0444, .proc_handler = &proc_dointvec, }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "bootloader_version", + .data = &bootloader_version, + .maxlen = sizeof (int), + .mode = 0444, + .proc_handler = &proc_dointvec, + }, { .ctl_name = CTL_UNNUMBERED, .procname = "kstack_depth_to_print", @@ -912,6 +942,43 @@ static struct ctl_table kern_table[] = { .child = slow_work_sysctls, }, #endif +#ifdef CONFIG_PERF_COUNTERS + { + .ctl_name = CTL_UNNUMBERED, + .procname = "perf_counter_paranoid", + .data = &sysctl_perf_counter_paranoid, + .maxlen = sizeof(sysctl_perf_counter_paranoid), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "perf_counter_mlock_kb", + .data = &sysctl_perf_counter_mlock, + .maxlen = sizeof(sysctl_perf_counter_mlock), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "perf_counter_max_sample_rate", + .data = &sysctl_perf_counter_sample_rate, + .maxlen = sizeof(sysctl_perf_counter_sample_rate), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, +#endif +#ifdef CONFIG_KMEMCHECK + { + .ctl_name = CTL_UNNUMBERED, + .procname = "kmemcheck", + .data = &kmemcheck_enabled, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, +#endif + /* * NOTE: do not add new entries to this table unless you have read * Documentation/sysctl/ctl_unnumbered.txt @@ -1225,7 +1292,6 @@ static struct ctl_table vm_table[] = { .strategy = &sysctl_jiffies, }, #endif -#ifdef CONFIG_SECURITY { .ctl_name = CTL_UNNUMBERED, .procname = "mmap_min_addr", @@ -1234,7 +1300,6 @@ static struct ctl_table vm_table[] = { .mode = 0644, .proc_handler = &proc_doulongvec_minmax, }, -#endif #ifdef CONFIG_NUMA { .ctl_name = CTL_UNNUMBERED, @@ -1272,7 +1337,6 @@ static struct ctl_table vm_table[] = { .extra2 = &one, }, #endif -#ifdef CONFIG_UNEVICTABLE_LRU { .ctl_name = CTL_UNNUMBERED, .procname = "scan_unevictable_pages", @@ -1281,7 +1345,6 @@ static struct ctl_table vm_table[] = { .mode = 0644, .proc_handler = &scan_unevictable_handler, }, -#endif /* * NOTE: do not add new entries to this table unless you have read * Documentation/sysctl/ctl_unnumbered.txt @@ -2220,7 +2283,7 @@ static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table, void *data) { #define TMPBUFLEN 21 - int *i, vleft, first=1, neg, val; + int *i, vleft, first = 1, neg; unsigned long lval; size_t left, len; @@ -2273,8 +2336,6 @@ static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table, len = p-buf; if ((len < left) && *p && !isspace(*p)) break; - if (neg) - val = -val; s += len; left -= len; diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c index d13be216a790..1ad6dd461119 100644 --- a/kernel/time/clockevents.c +++ b/kernel/time/clockevents.c @@ -18,6 +18,7 @@ #include #include #include +#include /* The registered clock event devices */ static LIST_HEAD(clockevent_devices); @@ -54,6 +55,7 @@ unsigned long clockevent_delta2ns(unsigned long latch, return (unsigned long) clc; } +EXPORT_SYMBOL_GPL(clockevent_delta2ns); /** * clockevents_set_mode - set the operating mode of a clock event device @@ -187,6 +189,7 @@ void clockevents_register_device(struct clock_event_device *dev) spin_unlock(&clockevents_lock); } +EXPORT_SYMBOL_GPL(clockevents_register_device); /* * Noop handler when we shut down an event device @@ -251,4 +254,15 @@ void clockevents_notify(unsigned long reason, void *arg) spin_unlock(&clockevents_lock); } EXPORT_SYMBOL_GPL(clockevents_notify); + +ktime_t clockevents_get_next_event(int cpu) +{ + struct tick_device *td; + struct clock_event_device *dev; + + td = &per_cpu(tick_cpu_device, cpu); + dev = td->evtdev; + + return dev->next_event; +} #endif diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c index ecfd7b5187e0..592bf584d1d2 100644 --- a/kernel/time/clocksource.c +++ b/kernel/time/clocksource.c @@ -402,9 +402,6 @@ int clocksource_register(struct clocksource *c) unsigned long flags; int ret; - /* save mult_orig on registration */ - c->mult_orig = c->mult; - spin_lock_irqsave(&clocksource_lock, flags); ret = clocksource_enqueue(c); if (!ret) @@ -512,6 +509,18 @@ static ssize_t sysfs_override_clocksource(struct sys_device *dev, } } + /* + * Check to make sure we don't switch to a non-highres capable + * clocksource if the tick code is in oneshot mode (highres or nohz) + */ + if (tick_oneshot_mode_active() && + !(ovr->flags & CLOCK_SOURCE_VALID_FOR_HRES)) { + printk(KERN_WARNING "%s clocksource is not HRT compatible. " + "Cannot switch while in HRT/NOHZ mode\n", ovr->name); + ovr = NULL; + override_name[0] = 0; + } + /* Reselect, when the override name has changed */ if (ovr != clocksource_override) { clocksource_override = ovr; @@ -540,7 +549,13 @@ sysfs_show_available_clocksources(struct sys_device *dev, spin_lock_irq(&clocksource_lock); list_for_each_entry(src, &clocksource_list, list) { - count += snprintf(buf + count, + /* + * Don't show non-HRES clocksource if the tick code is + * in one shot mode (highres=on or nohz=on) + */ + if (!tick_oneshot_mode_active() || + (src->flags & CLOCK_SOURCE_VALID_FOR_HRES)) + count += snprintf(buf + count, max((ssize_t)PAGE_SIZE - count, (ssize_t)0), "%s ", src->name); } diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c index 118a3b3b3f9a..877dbedc3118 100644 --- a/kernel/time/tick-broadcast.c +++ b/kernel/time/tick-broadcast.c @@ -27,7 +27,7 @@ * timer stops in C3 state. */ -struct tick_device tick_broadcast_device; +static struct tick_device tick_broadcast_device; /* FIXME: Use cpumask_var_t. */ static DECLARE_BITMAP(tick_broadcast_mask, NR_CPUS); static DECLARE_BITMAP(tmpmask, NR_CPUS); diff --git a/kernel/time/tick-oneshot.c b/kernel/time/tick-oneshot.c index 2e8de678e767..a96c0e2b89cf 100644 --- a/kernel/time/tick-oneshot.c +++ b/kernel/time/tick-oneshot.c @@ -128,6 +128,23 @@ int tick_switch_to_oneshot(void (*handler)(struct clock_event_device *)) return 0; } +/** + * tick_check_oneshot_mode - check whether the system is in oneshot mode + * + * returns 1 when either nohz or highres are enabled. otherwise 0. + */ +int tick_oneshot_mode_active(void) +{ + unsigned long flags; + int ret; + + local_irq_save(flags); + ret = __get_cpu_var(tick_cpu_device).mode == TICKDEV_MODE_ONESHOT; + local_irq_restore(flags); + + return ret; +} + #ifdef CONFIG_HIGH_RES_TIMERS /** * tick_init_highres - switch to high resolution mode diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index d3f1ef4d5cbe..e0f59a21c061 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -222,6 +222,15 @@ void tick_nohz_stop_sched_tick(int inidle) cpu = smp_processor_id(); ts = &per_cpu(tick_cpu_sched, cpu); + + /* + * Call to tick_nohz_start_idle stops the last_update_time from being + * updated. Thus, it must not be called in the event we are called from + * irq_exit() with the prior state different than idle. + */ + if (!inidle && !ts->inidle) + goto end; + now = tick_nohz_start_idle(ts); /* @@ -239,9 +248,6 @@ void tick_nohz_stop_sched_tick(int inidle) if (unlikely(ts->nohz_mode == NOHZ_MODE_INACTIVE)) goto end; - if (!inidle && !ts->inidle) - goto end; - ts->inidle = 1; if (need_resched()) @@ -349,7 +355,7 @@ void tick_nohz_stop_sched_tick(int inidle) if (ts->nohz_mode == NOHZ_MODE_HIGHRES) { hrtimer_start(&ts->sched_timer, expires, - HRTIMER_MODE_ABS); + HRTIMER_MODE_ABS_PINNED); /* Check, if the timer was already in the past */ if (hrtimer_active(&ts->sched_timer)) goto out; @@ -395,7 +401,7 @@ static void tick_nohz_restart(struct tick_sched *ts, ktime_t now) if (ts->nohz_mode == NOHZ_MODE_HIGHRES) { hrtimer_start_expires(&ts->sched_timer, - HRTIMER_MODE_ABS); + HRTIMER_MODE_ABS_PINNED); /* Check, if the timer was already in the past */ if (hrtimer_active(&ts->sched_timer)) break; @@ -698,7 +704,8 @@ void tick_setup_sched_timer(void) for (;;) { hrtimer_forward(&ts->sched_timer, now, tick_period); - hrtimer_start_expires(&ts->sched_timer, HRTIMER_MODE_ABS); + hrtimer_start_expires(&ts->sched_timer, + HRTIMER_MODE_ABS_PINNED); /* Check, if the timer was already in the past */ if (hrtimer_active(&ts->sched_timer)) break; diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 687dff49f6e7..e8c77d9c633a 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -22,7 +22,7 @@ /* * This read-write spinlock protects us from races in SMP while - * playing with xtime and avenrun. + * playing with xtime. */ __cacheline_aligned_in_smp DEFINE_SEQLOCK(xtime_lock); @@ -77,6 +77,10 @@ static void clocksource_forward_now(void) clock->cycle_last = cycle_now; nsec = cyc2ns(clock, cycle_delta); + + /* If arch requires, add in gettimeoffset() */ + nsec += arch_gettimeoffset(); + timespec_add_ns(&xtime, nsec); nsec = ((s64)cycle_delta * clock->mult_orig) >> clock->shift; @@ -111,6 +115,9 @@ void getnstimeofday(struct timespec *ts) /* convert to nanoseconds: */ nsecs = cyc2ns(clock, cycle_delta); + /* If arch requires, add in gettimeoffset() */ + nsecs += arch_gettimeoffset(); + } while (read_seqretry(&xtime_lock, seq)); timespec_add_ns(ts, nsecs); diff --git a/kernel/timer.c b/kernel/timer.c index cffffad01c31..54d3912f8cad 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -37,6 +37,8 @@ #include #include #include +#include +#include #include #include @@ -604,13 +606,12 @@ static struct tvec_base *lock_timer_base(struct timer_list *timer, } static inline int -__mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only) +__mod_timer(struct timer_list *timer, unsigned long expires, + bool pending_only, int pinned) { struct tvec_base *base, *new_base; unsigned long flags; - int ret; - - ret = 0; + int ret = 0 , cpu; timer_stats_timer_set_start_info(timer); BUG_ON(!timer->function); @@ -629,6 +630,18 @@ __mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only) new_base = __get_cpu_var(tvec_bases); + cpu = smp_processor_id(); + +#if defined(CONFIG_NO_HZ) && defined(CONFIG_SMP) + if (!pinned && get_sysctl_timer_migration() && idle_cpu(cpu)) { + int preferred_cpu = get_nohz_load_balancer(); + + if (preferred_cpu >= 0) + cpu = preferred_cpu; + } +#endif + new_base = per_cpu(tvec_bases, cpu); + if (base != new_base) { /* * We are trying to schedule the timer on the local CPU. @@ -668,7 +681,7 @@ out_unlock: */ int mod_timer_pending(struct timer_list *timer, unsigned long expires) { - return __mod_timer(timer, expires, true); + return __mod_timer(timer, expires, true, TIMER_NOT_PINNED); } EXPORT_SYMBOL(mod_timer_pending); @@ -702,10 +715,32 @@ int mod_timer(struct timer_list *timer, unsigned long expires) if (timer->expires == expires && timer_pending(timer)) return 1; - return __mod_timer(timer, expires, false); + return __mod_timer(timer, expires, false, TIMER_NOT_PINNED); } EXPORT_SYMBOL(mod_timer); +/** + * mod_timer_pinned - modify a timer's timeout + * @timer: the timer to be modified + * @expires: new timeout in jiffies + * + * mod_timer_pinned() is a way to update the expire field of an + * active timer (if the timer is inactive it will be activated) + * and not allow the timer to be migrated to a different CPU. + * + * mod_timer_pinned(timer, expires) is equivalent to: + * + * del_timer(timer); timer->expires = expires; add_timer(timer); + */ +int mod_timer_pinned(struct timer_list *timer, unsigned long expires) +{ + if (timer->expires == expires && timer_pending(timer)) + return 1; + + return __mod_timer(timer, expires, false, TIMER_PINNED); +} +EXPORT_SYMBOL(mod_timer_pinned); + /** * add_timer - start a timer * @timer: the timer to be added @@ -756,6 +791,7 @@ void add_timer_on(struct timer_list *timer, int cpu) wake_up_idle_cpu(cpu); spin_unlock_irqrestore(&base->lock, flags); } +EXPORT_SYMBOL_GPL(add_timer_on); /** * del_timer - deactive a timer. @@ -1015,6 +1051,9 @@ cascade: index = slot = timer_jiffies & TVN_MASK; do { list_for_each_entry(nte, varp->vec + slot, entry) { + if (tbase_get_deferrable(nte->base)) + continue; + found = 1; if (time_before(nte->expires, expires)) expires = nte->expires; @@ -1122,47 +1161,6 @@ void update_process_times(int user_tick) run_posix_cpu_timers(p); } -/* - * Nr of active tasks - counted in fixed-point numbers - */ -static unsigned long count_active_tasks(void) -{ - return nr_active() * FIXED_1; -} - -/* - * Hmm.. Changed this, as the GNU make sources (load.c) seems to - * imply that avenrun[] is the standard name for this kind of thing. - * Nothing else seems to be standardized: the fractional size etc - * all seem to differ on different machines. - * - * Requires xtime_lock to access. - */ -unsigned long avenrun[3]; - -EXPORT_SYMBOL(avenrun); - -/* - * calc_load - given tick count, update the avenrun load estimates. - * This is called while holding a write_lock on xtime_lock. - */ -static inline void calc_load(unsigned long ticks) -{ - unsigned long active_tasks; /* fixed-point */ - static int count = LOAD_FREQ; - - count -= ticks; - if (unlikely(count < 0)) { - active_tasks = count_active_tasks(); - do { - CALC_LOAD(avenrun[0], EXP_1, active_tasks); - CALC_LOAD(avenrun[1], EXP_5, active_tasks); - CALC_LOAD(avenrun[2], EXP_15, active_tasks); - count += LOAD_FREQ; - } while (count < 0); - } -} - /* * This function runs timers and the timer-tq in bottom half context. */ @@ -1170,6 +1168,8 @@ static void run_timer_softirq(struct softirq_action *h) { struct tvec_base *base = __get_cpu_var(tvec_bases); + perf_counter_do_pending(); + hrtimer_run_pending(); if (time_after_eq(jiffies, base->timer_jiffies)) @@ -1186,16 +1186,6 @@ void run_local_timers(void) softlockup_tick(); } -/* - * Called by the timer interrupt. xtime_lock must already be taken - * by the timer IRQ! - */ -static inline void update_times(unsigned long ticks) -{ - update_wall_time(); - calc_load(ticks); -} - /* * The 64-bit jiffies value is not atomic - you MUST NOT read it * without sampling the sequence number in xtime_lock. @@ -1205,7 +1195,8 @@ static inline void update_times(unsigned long ticks) void do_timer(unsigned long ticks) { jiffies_64 += ticks; - update_times(ticks); + update_wall_time(); + calc_global_load(); } #ifdef __ARCH_WANT_SYS_ALARM @@ -1353,7 +1344,7 @@ signed long __sched schedule_timeout(signed long timeout) expire = timeout + jiffies; setup_timer_on_stack(&timer, process_timeout, (unsigned long)current); - __mod_timer(&timer, expire, false); + __mod_timer(&timer, expire, false, TIMER_NOT_PINNED); schedule(); del_singleshot_timer_sync(&timer); @@ -1406,37 +1397,17 @@ int do_sysinfo(struct sysinfo *info) { unsigned long mem_total, sav_total; unsigned int mem_unit, bitcount; - unsigned long seq; + struct timespec tp; memset(info, 0, sizeof(struct sysinfo)); - do { - struct timespec tp; - seq = read_seqbegin(&xtime_lock); + ktime_get_ts(&tp); + monotonic_to_bootbased(&tp); + info->uptime = tp.tv_sec + (tp.tv_nsec ? 1 : 0); - /* - * This is annoying. The below is the same thing - * posix_get_clock_monotonic() does, but it wants to - * take the lock which we want to cover the loads stuff - * too. - */ + get_avenrun(info->loads, 0, SI_LOAD_SHIFT - FSHIFT); - getnstimeofday(&tp); - tp.tv_sec += wall_to_monotonic.tv_sec; - tp.tv_nsec += wall_to_monotonic.tv_nsec; - monotonic_to_bootbased(&tp); - if (tp.tv_nsec - NSEC_PER_SEC >= 0) { - tp.tv_nsec = tp.tv_nsec - NSEC_PER_SEC; - tp.tv_sec++; - } - info->uptime = tp.tv_sec + (tp.tv_nsec ? 1 : 0); - - info->loads[0] = avenrun[0] << (SI_LOAD_SHIFT - FSHIFT); - info->loads[1] = avenrun[1] << (SI_LOAD_SHIFT - FSHIFT); - info->loads[2] = avenrun[2] << (SI_LOAD_SHIFT - FSHIFT); - - info->procs = nr_threads; - } while (read_seqretry(&xtime_lock, seq)); + info->procs = nr_threads; si_meminfo(info); si_swapinfo(info); diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig index 417d1985e299..1551f47e7669 100644 --- a/kernel/trace/Kconfig +++ b/kernel/trace/Kconfig @@ -18,6 +18,13 @@ config HAVE_FUNCTION_TRACER config HAVE_FUNCTION_GRAPH_TRACER bool +config HAVE_FUNCTION_GRAPH_FP_TEST + bool + help + An arch may pass in a unique value (frame pointer) to both the + entering and exiting of a function. On exit, the value is compared + and if it does not match, then it will panic the kernel. + config HAVE_FUNCTION_TRACE_MCOUNT_TEST bool help @@ -48,6 +55,21 @@ config FTRACE_NMI_ENTER depends on HAVE_FTRACE_NMI_ENTER default y +config EVENT_TRACING + select CONTEXT_SWITCH_TRACER + bool + +config CONTEXT_SWITCH_TRACER + select MARKERS + bool + +# All tracer options should select GENERIC_TRACER. For those options that are +# enabled by all tracers (context switch and event tracer) they select TRACING. +# This allows those options to appear when no other tracer is selected. But the +# options do not appear when something else selects it. We need the two options +# GENERIC_TRACER and TRACING to avoid circular dependencies to accomplish the +# hidding of the automatic options options. + config TRACING bool select DEBUG_FS @@ -56,6 +78,11 @@ config TRACING select TRACEPOINTS select NOP_TRACER select BINARY_PRINTF + select EVENT_TRACING + +config GENERIC_TRACER + bool + select TRACING # # Minimum requirements an architecture has to meet for us to @@ -73,14 +100,20 @@ config TRACING_SUPPORT if TRACING_SUPPORT -menu "Tracers" +menuconfig FTRACE + bool "Tracers" + default y if DEBUG_KERNEL + help + Enable the kernel tracing infrastructure. + +if FTRACE config FUNCTION_TRACER bool "Kernel Function Tracer" depends on HAVE_FUNCTION_TRACER select FRAME_POINTER select KALLSYMS - select TRACING + select GENERIC_TRACER select CONTEXT_SWITCH_TRACER help Enable the kernel to trace every kernel function. This is done @@ -95,6 +128,7 @@ config FUNCTION_GRAPH_TRACER bool "Kernel Function Graph Tracer" depends on HAVE_FUNCTION_GRAPH_TRACER depends on FUNCTION_TRACER + depends on !X86_32 || !CC_OPTIMIZE_FOR_SIZE default y help Enable the kernel to trace a function at both its return @@ -104,13 +138,14 @@ config FUNCTION_GRAPH_TRACER the return value. This is done by setting the current return address on the current task structure into a stack of calls. + config IRQSOFF_TRACER bool "Interrupts-off Latency Tracer" default n depends on TRACE_IRQFLAGS_SUPPORT depends on GENERIC_TIME select TRACE_IRQFLAGS - select TRACING + select GENERIC_TRACER select TRACER_MAX_TRACE help This option measures the time spent in irqs-off critical @@ -120,7 +155,7 @@ config IRQSOFF_TRACER disabled by default and can be runtime (re-)started via: - echo 0 > /debugfs/tracing/tracing_max_latency + echo 0 > /sys/kernel/debug/tracing/tracing_max_latency (Note that kernel size and overhead increases with this option enabled. This option and the preempt-off timing option can be @@ -131,7 +166,7 @@ config PREEMPT_TRACER default n depends on GENERIC_TIME depends on PREEMPT - select TRACING + select GENERIC_TRACER select TRACER_MAX_TRACE help This option measures the time spent in preemption off critical @@ -141,7 +176,7 @@ config PREEMPT_TRACER disabled by default and can be runtime (re-)started via: - echo 0 > /debugfs/tracing/tracing_max_latency + echo 0 > /sys/kernel/debug/tracing/tracing_max_latency (Note that kernel size and overhead increases with this option enabled. This option and the irqs-off timing option can be @@ -150,7 +185,7 @@ config PREEMPT_TRACER config SYSPROF_TRACER bool "Sysprof Tracer" depends on X86 - select TRACING + select GENERIC_TRACER select CONTEXT_SWITCH_TRACER help This tracer provides the trace needed by the 'Sysprof' userspace @@ -158,40 +193,33 @@ config SYSPROF_TRACER config SCHED_TRACER bool "Scheduling Latency Tracer" - select TRACING + select GENERIC_TRACER select CONTEXT_SWITCH_TRACER select TRACER_MAX_TRACE help This tracer tracks the latency of the highest priority task to be scheduled in, starting from the point it has woken up. -config CONTEXT_SWITCH_TRACER - bool "Trace process context switches" - select TRACING - select MARKERS - help - This tracer gets called from the context switch and records - all switching of tasks. - -config EVENT_TRACER - bool "Trace various events in the kernel" +config ENABLE_DEFAULT_TRACERS + bool "Trace process context switches and events" + depends on !GENERIC_TRACER select TRACING help This tracer hooks to various trace points in the kernel allowing the user to pick and choose which trace point they - want to trace. + want to trace. It also includes the sched_switch tracer plugin. config FTRACE_SYSCALLS bool "Trace syscalls" depends on HAVE_FTRACE_SYSCALLS - select TRACING + select GENERIC_TRACER select KALLSYMS help Basic tracer to catch the syscall entry and exit events. config BOOT_TRACER bool "Trace boot initcalls" - select TRACING + select GENERIC_TRACER select CONTEXT_SWITCH_TRACER help This tracer helps developers to optimize boot times: it records @@ -207,34 +235,61 @@ config BOOT_TRACER to enable this on bootup. config TRACE_BRANCH_PROFILING + bool + select GENERIC_TRACER + +choice + prompt "Branch Profiling" + default BRANCH_PROFILE_NONE + help + The branch profiling is a software profiler. It will add hooks + into the C conditionals to test which path a branch takes. + + The likely/unlikely profiler only looks at the conditions that + are annotated with a likely or unlikely macro. + + The "all branch" profiler will profile every if statement in the + kernel. This profiler will also enable the likely/unlikely + profiler as well. + + Either of the above profilers add a bit of overhead to the system. + If unsure choose "No branch profiling". + +config BRANCH_PROFILE_NONE + bool "No branch profiling" + help + No branch profiling. Branch profiling adds a bit of overhead. + Only enable it if you want to analyse the branching behavior. + Otherwise keep it disabled. + +config PROFILE_ANNOTATED_BRANCHES bool "Trace likely/unlikely profiler" - select TRACING + select TRACE_BRANCH_PROFILING help This tracer profiles all the the likely and unlikely macros in the kernel. It will display the results in: - /debugfs/tracing/profile_annotated_branch + /sys/kernel/debug/tracing/profile_annotated_branch Note: this will add a significant overhead, only turn this on if you need to profile the system's use of these macros. - Say N if unsure. - config PROFILE_ALL_BRANCHES bool "Profile all if conditionals" - depends on TRACE_BRANCH_PROFILING + select TRACE_BRANCH_PROFILING help This tracer profiles all branch conditions. Every if () taken in the kernel is recorded whether it hit or miss. The results will be displayed in: - /debugfs/tracing/profile_branch + /sys/kernel/debug/tracing/profile_branch + + This option also enables the likely/unlikely profiler. This configuration, when enabled, will impose a great overhead on the system. This should only be enabled when the system is to be analyzed - - Say N if unsure. +endchoice config TRACING_BRANCHES bool @@ -261,7 +316,7 @@ config BRANCH_TRACER config POWER_TRACER bool "Trace power consumption behavior" depends on X86 - select TRACING + select GENERIC_TRACER help This tracer helps developers to analyze and optimize the kernels power management decisions, specifically the C-state and P-state @@ -276,7 +331,7 @@ config STACK_TRACER select KALLSYMS help This special tracer records the maximum stack footprint of the - kernel and displays it in debugfs/tracing/stack_trace. + kernel and displays it in /sys/kernel/debug/tracing/stack_trace. This tracer works by hooking into every function call that the kernel executes, and keeping a maximum stack depth value and @@ -295,14 +350,14 @@ config STACK_TRACER config HW_BRANCH_TRACER depends on HAVE_HW_BRANCH_TRACER bool "Trace hw branches" - select TRACING + select GENERIC_TRACER help This tracer records all branches on the system in a circular buffer giving access to the last N branches for each cpu. config KMEMTRACE bool "Trace SLAB allocations" - select TRACING + select GENERIC_TRACER help kmemtrace provides tracing for slab allocator functions, such as kmalloc, kfree, kmem_cache_alloc, kmem_cache_free etc.. Collected @@ -322,7 +377,7 @@ config KMEMTRACE config WORKQUEUE_TRACER bool "Trace workqueues" - select TRACING + select GENERIC_TRACER help The workqueue tracer provides some statistical informations about each cpu workqueue thread such as the number of the @@ -338,7 +393,7 @@ config BLK_DEV_IO_TRACE select RELAY select DEBUG_FS select TRACEPOINTS - select TRACING + select GENERIC_TRACER select STACKTRACE help Say Y here if you want to be able to trace the block layer actions @@ -375,6 +430,20 @@ config DYNAMIC_FTRACE were made. If so, it runs stop_machine (stops all CPUS) and modifies the code to jump over the call to ftrace. +config FUNCTION_PROFILER + bool "Kernel function profiler" + depends on FUNCTION_TRACER + default n + help + This option enables the kernel function profiler. A file is created + in debugfs called function_profile_enabled which defaults to zero. + When a 1 is echoed into this file profiling begins, and when a + zero is entered, profiling stops. A file in the trace_stats + directory called functions, that show the list of functions that + have been hit and their counters. + + If in doubt, say N + config FTRACE_MCOUNT_RECORD def_bool y depends on DYNAMIC_FTRACE @@ -385,7 +454,7 @@ config FTRACE_SELFTEST config FTRACE_STARTUP_TEST bool "Perform a startup test on ftrace" - depends on TRACING + depends on GENERIC_TRACER select FTRACE_SELFTEST help This option performs a series of startup tests on ftrace. On bootup @@ -396,7 +465,7 @@ config FTRACE_STARTUP_TEST config MMIOTRACE bool "Memory mapped IO tracing" depends on HAVE_MMIOTRACE_SUPPORT && PCI - select TRACING + select GENERIC_TRACER help Mmiotrace traces Memory Mapped I/O access and is meant for debugging and reverse engineering. It is called from the ioremap @@ -416,7 +485,23 @@ config MMIOTRACE_TEST Say N, unless you absolutely know what you are doing. -endmenu +config RING_BUFFER_BENCHMARK + tristate "Ring buffer benchmark stress tester" + depends on RING_BUFFER + help + This option creates a test to stress the ring buffer and bench mark it. + It creates its own ring buffer such that it will not interfer with + any other users of the ring buffer (such as ftrace). It then creates + a producer and consumer that will run for 10 seconds and sleep for + 10 seconds. Each interval it will print out the number of events + it recorded and give a rough estimate of how long each iteration took. + + It does not disable interrupts or raise its priority, so it may be + affected by processes that are running. + + If unsure, say N + +endif # FTRACE endif # TRACING_SUPPORT diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile index 2630f5121ec1..844164dca90a 100644 --- a/kernel/trace/Makefile +++ b/kernel/trace/Makefile @@ -15,11 +15,17 @@ ifdef CONFIG_TRACING_BRANCHES KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING endif +# +# Make the trace clocks available generally: it's infrastructure +# relied on by ptrace for example: +# +obj-y += trace_clock.o + obj-$(CONFIG_FUNCTION_TRACER) += libftrace.o obj-$(CONFIG_RING_BUFFER) += ring_buffer.o +obj-$(CONFIG_RING_BUFFER_BENCHMARK) += ring_buffer_benchmark.o obj-$(CONFIG_TRACING) += trace.o -obj-$(CONFIG_TRACING) += trace_clock.o obj-$(CONFIG_TRACING) += trace_output.o obj-$(CONFIG_TRACING) += trace_stat.o obj-$(CONFIG_TRACING) += trace_printk.o @@ -39,12 +45,14 @@ obj-$(CONFIG_HW_BRANCH_TRACER) += trace_hw_branches.o obj-$(CONFIG_POWER_TRACER) += trace_power.o obj-$(CONFIG_KMEMTRACE) += kmemtrace.o obj-$(CONFIG_WORKQUEUE_TRACER) += trace_workqueue.o -obj-$(CONFIG_BLK_DEV_IO_TRACE) += blktrace.o -obj-$(CONFIG_EVENT_TRACER) += trace_events.o -obj-$(CONFIG_EVENT_TRACER) += events.o -obj-$(CONFIG_EVENT_TRACER) += trace_export.o +obj-$(CONFIG_BLK_DEV_IO_TRACE) += blktrace.o +ifeq ($(CONFIG_BLOCK),y) +obj-$(CONFIG_EVENT_TRACING) += blktrace.o +endif +obj-$(CONFIG_EVENT_TRACING) += trace_events.o +obj-$(CONFIG_EVENT_TRACING) += trace_export.o obj-$(CONFIG_FTRACE_SYSCALLS) += trace_syscalls.o obj-$(CONFIG_EVENT_PROFILE) += trace_event_profile.o -obj-$(CONFIG_EVENT_TRACER) += trace_events_filter.o +obj-$(CONFIG_EVENT_TRACING) += trace_events_filter.o libftrace-y := ftrace.o diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c index 921ef5d1f0ba..39af8af6fc30 100644 --- a/kernel/trace/blktrace.c +++ b/kernel/trace/blktrace.c @@ -23,10 +23,14 @@ #include #include #include -#include #include + +#include + #include "trace_output.h" +#ifdef CONFIG_BLK_DEV_IO_TRACE + static unsigned int blktrace_seq __read_mostly = 1; static struct trace_array *blk_tr; @@ -147,7 +151,7 @@ static int act_log_check(struct blk_trace *bt, u32 what, sector_t sector, { if (((bt->act_mask << BLK_TC_SHIFT) & what) == 0) return 1; - if (sector < bt->start_lba || sector > bt->end_lba) + if (sector && (sector < bt->start_lba || sector > bt->end_lba)) return 1; if (bt->pid && pid != bt->pid) return 1; @@ -192,7 +196,7 @@ static void __blk_add_trace(struct blk_trace *bt, sector_t sector, int bytes, what |= MASK_TC_BIT(rw, DISCARD); pid = tsk->pid; - if (unlikely(act_log_check(bt, what, sector, pid))) + if (act_log_check(bt, what, sector, pid)) return; cpu = raw_smp_processor_id(); @@ -262,6 +266,7 @@ static void blk_trace_free(struct blk_trace *bt) { debugfs_remove(bt->msg_file); debugfs_remove(bt->dropped_file); + debugfs_remove(bt->dir); relay_close(bt->rchan); free_percpu(bt->sequence); free_percpu(bt->msg_data); @@ -403,11 +408,29 @@ static struct rchan_callbacks blk_relay_callbacks = { .remove_buf_file = blk_remove_buf_file_callback, }; +static void blk_trace_setup_lba(struct blk_trace *bt, + struct block_device *bdev) +{ + struct hd_struct *part = NULL; + + if (bdev) + part = bdev->bd_part; + + if (part) { + bt->start_lba = part->start_sect; + bt->end_lba = part->start_sect + part->nr_sects; + } else { + bt->start_lba = 0; + bt->end_lba = -1ULL; + } +} + /* * Setup everything required to start tracing */ int do_blk_trace_setup(struct request_queue *q, char *name, dev_t dev, - struct blk_user_trace_setup *buts) + struct block_device *bdev, + struct blk_user_trace_setup *buts) { struct blk_trace *old_bt, *bt = NULL; struct dentry *dir = NULL; @@ -480,10 +503,13 @@ int do_blk_trace_setup(struct request_queue *q, char *name, dev_t dev, if (!bt->act_mask) bt->act_mask = (u16) -1; - bt->start_lba = buts->start_lba; - bt->end_lba = buts->end_lba; - if (!bt->end_lba) - bt->end_lba = -1ULL; + blk_trace_setup_lba(bt, bdev); + + /* overwrite with user settings */ + if (buts->start_lba) + bt->start_lba = buts->start_lba; + if (buts->end_lba) + bt->end_lba = buts->end_lba; bt->pid = buts->pid; bt->trace_state = Blktrace_setup; @@ -505,6 +531,7 @@ err: } int blk_trace_setup(struct request_queue *q, char *name, dev_t dev, + struct block_device *bdev, char __user *arg) { struct blk_user_trace_setup buts; @@ -514,7 +541,7 @@ int blk_trace_setup(struct request_queue *q, char *name, dev_t dev, if (ret) return -EFAULT; - ret = do_blk_trace_setup(q, name, dev, &buts); + ret = do_blk_trace_setup(q, name, dev, bdev, &buts); if (ret) return ret; @@ -582,7 +609,7 @@ int blk_trace_ioctl(struct block_device *bdev, unsigned cmd, char __user *arg) switch (cmd) { case BLKTRACESETUP: bdevname(bdev, b); - ret = blk_trace_setup(q, b, bdev->bd_dev, arg); + ret = blk_trace_setup(q, b, bdev->bd_dev, bdev, arg); break; case BLKTRACESTART: start = 1; @@ -642,12 +669,12 @@ static void blk_add_trace_rq(struct request_queue *q, struct request *rq, if (blk_pc_request(rq)) { what |= BLK_TC_ACT(BLK_TC_PC); - __blk_add_trace(bt, 0, rq->data_len, rw, what, rq->errors, - rq->cmd_len, rq->cmd); + __blk_add_trace(bt, 0, blk_rq_bytes(rq), rw, + what, rq->errors, rq->cmd_len, rq->cmd); } else { what |= BLK_TC_ACT(BLK_TC_FS); - __blk_add_trace(bt, rq->hard_sector, rq->hard_nr_sectors << 9, - rw, what, rq->errors, 0, NULL); + __blk_add_trace(bt, blk_rq_pos(rq), blk_rq_bytes(rq), rw, + what, rq->errors, 0, NULL); } } @@ -809,7 +836,6 @@ static void blk_add_trace_split(struct request_queue *q, struct bio *bio, * @bio: the source bio * @dev: target device * @from: source sector - * @to: target sector * * Description: * Device mapper or raid target sometimes need to split a bio because @@ -817,7 +843,7 @@ static void blk_add_trace_split(struct request_queue *q, struct bio *bio, * **/ static void blk_add_trace_remap(struct request_queue *q, struct bio *bio, - dev_t dev, sector_t from, sector_t to) + dev_t dev, sector_t from) { struct blk_trace *bt = q->blk_trace; struct blk_io_trace_remap r; @@ -825,12 +851,13 @@ static void blk_add_trace_remap(struct request_queue *q, struct bio *bio, if (likely(!bt)) return; - r.device = cpu_to_be32(dev); - r.device_from = cpu_to_be32(bio->bi_bdev->bd_dev); - r.sector = cpu_to_be64(to); + r.device_from = cpu_to_be32(dev); + r.device_to = cpu_to_be32(bio->bi_bdev->bd_dev); + r.sector_from = cpu_to_be64(from); - __blk_add_trace(bt, from, bio->bi_size, bio->bi_rw, BLK_TA_REMAP, - !bio_flagged(bio, BIO_UPTODATE), sizeof(r), &r); + __blk_add_trace(bt, bio->bi_sector, bio->bi_size, bio->bi_rw, + BLK_TA_REMAP, !bio_flagged(bio, BIO_UPTODATE), + sizeof(r), &r); } /** @@ -854,11 +881,11 @@ void blk_add_driver_data(struct request_queue *q, return; if (blk_pc_request(rq)) - __blk_add_trace(bt, 0, rq->data_len, 0, BLK_TA_DRV_DATA, - rq->errors, len, data); + __blk_add_trace(bt, 0, blk_rq_bytes(rq), 0, + BLK_TA_DRV_DATA, rq->errors, len, data); else - __blk_add_trace(bt, rq->hard_sector, rq->hard_nr_sectors << 9, - 0, BLK_TA_DRV_DATA, rq->errors, len, data); + __blk_add_trace(bt, blk_rq_pos(rq), blk_rq_bytes(rq), 0, + BLK_TA_DRV_DATA, rq->errors, len, data); } EXPORT_SYMBOL_GPL(blk_add_driver_data); @@ -971,6 +998,16 @@ static inline const void *pdu_start(const struct trace_entry *ent) return te_blk_io_trace(ent) + 1; } +static inline u32 t_action(const struct trace_entry *ent) +{ + return te_blk_io_trace(ent)->action; +} + +static inline u32 t_bytes(const struct trace_entry *ent) +{ + return te_blk_io_trace(ent)->bytes; +} + static inline u32 t_sec(const struct trace_entry *ent) { return te_blk_io_trace(ent)->bytes >> 9; @@ -996,11 +1033,11 @@ static void get_pdu_remap(const struct trace_entry *ent, struct blk_io_trace_remap *r) { const struct blk_io_trace_remap *__r = pdu_start(ent); - __u64 sector = __r->sector; + __u64 sector_from = __r->sector_from; - r->device = be32_to_cpu(__r->device); r->device_from = be32_to_cpu(__r->device_from); - r->sector = be64_to_cpu(sector); + r->device_to = be32_to_cpu(__r->device_to); + r->sector_from = be64_to_cpu(sector_from); } typedef int (blk_log_action_t) (struct trace_iterator *iter, const char *act); @@ -1031,36 +1068,98 @@ static int blk_log_action(struct trace_iterator *iter, const char *act) MAJOR(t->device), MINOR(t->device), act, rwbs); } +static int blk_log_dump_pdu(struct trace_seq *s, const struct trace_entry *ent) +{ + const unsigned char *pdu_buf; + int pdu_len; + int i, end, ret; + + pdu_buf = pdu_start(ent); + pdu_len = te_blk_io_trace(ent)->pdu_len; + + if (!pdu_len) + return 1; + + /* find the last zero that needs to be printed */ + for (end = pdu_len - 1; end >= 0; end--) + if (pdu_buf[end]) + break; + end++; + + if (!trace_seq_putc(s, '(')) + return 0; + + for (i = 0; i < pdu_len; i++) { + + ret = trace_seq_printf(s, "%s%02x", + i == 0 ? "" : " ", pdu_buf[i]); + if (!ret) + return ret; + + /* + * stop when the rest is just zeroes and indicate so + * with a ".." appended + */ + if (i == end && end != pdu_len - 1) + return trace_seq_puts(s, " ..) "); + } + + return trace_seq_puts(s, ") "); +} + static int blk_log_generic(struct trace_seq *s, const struct trace_entry *ent) { char cmd[TASK_COMM_LEN]; trace_find_cmdline(ent->pid, cmd); - if (t_sec(ent)) - return trace_seq_printf(s, "%llu + %u [%s]\n", - t_sector(ent), t_sec(ent), cmd); - return trace_seq_printf(s, "[%s]\n", cmd); + if (t_action(ent) & BLK_TC_ACT(BLK_TC_PC)) { + int ret; + + ret = trace_seq_printf(s, "%u ", t_bytes(ent)); + if (!ret) + return 0; + ret = blk_log_dump_pdu(s, ent); + if (!ret) + return 0; + return trace_seq_printf(s, "[%s]\n", cmd); + } else { + if (t_sec(ent)) + return trace_seq_printf(s, "%llu + %u [%s]\n", + t_sector(ent), t_sec(ent), cmd); + return trace_seq_printf(s, "[%s]\n", cmd); + } } static int blk_log_with_error(struct trace_seq *s, const struct trace_entry *ent) { - if (t_sec(ent)) - return trace_seq_printf(s, "%llu + %u [%d]\n", t_sector(ent), - t_sec(ent), t_error(ent)); - return trace_seq_printf(s, "%llu [%d]\n", t_sector(ent), t_error(ent)); + if (t_action(ent) & BLK_TC_ACT(BLK_TC_PC)) { + int ret; + + ret = blk_log_dump_pdu(s, ent); + if (ret) + return trace_seq_printf(s, "[%d]\n", t_error(ent)); + return 0; + } else { + if (t_sec(ent)) + return trace_seq_printf(s, "%llu + %u [%d]\n", + t_sector(ent), + t_sec(ent), t_error(ent)); + return trace_seq_printf(s, "%llu [%d]\n", + t_sector(ent), t_error(ent)); + } } static int blk_log_remap(struct trace_seq *s, const struct trace_entry *ent) { - struct blk_io_trace_remap r = { .device = 0, }; + struct blk_io_trace_remap r = { .device_from = 0, }; get_pdu_remap(ent, &r); return trace_seq_printf(s, "%llu + %u <- (%d,%d) %llu\n", - t_sector(ent), - t_sec(ent), MAJOR(r.device), MINOR(r.device), - (unsigned long long)r.sector); + t_sector(ent), t_sec(ent), + MAJOR(r.device_from), MINOR(r.device_from), + (unsigned long long)r.sector_from); } static int blk_log_plug(struct trace_seq *s, const struct trace_entry *ent) @@ -1117,7 +1216,6 @@ static void blk_tracer_print_header(struct seq_file *m) static void blk_tracer_start(struct trace_array *tr) { blk_tracer_enabled = true; - trace_flags &= ~TRACE_ITER_CONTEXT_INFO; } static int blk_tracer_init(struct trace_array *tr) @@ -1130,7 +1228,6 @@ static int blk_tracer_init(struct trace_array *tr) static void blk_tracer_stop(struct trace_array *tr) { blk_tracer_enabled = false; - trace_flags |= TRACE_ITER_CONTEXT_INFO; } static void blk_tracer_reset(struct trace_array *tr) @@ -1182,7 +1279,7 @@ static enum print_line_t print_one_line(struct trace_iterator *iter, } if (unlikely(what == 0 || what >= ARRAY_SIZE(what2act))) - ret = trace_seq_printf(s, "Bad pc action %x\n", what); + ret = trace_seq_printf(s, "Unknown action %x\n", what); else { ret = log_action(iter, what2act[what].act[long_act]); if (ret) @@ -1195,9 +1292,6 @@ out: static enum print_line_t blk_trace_event_print(struct trace_iterator *iter, int flags) { - if (!trace_print_context(iter)) - return TRACE_TYPE_PARTIAL_LINE; - return print_one_line(iter, false); } @@ -1232,6 +1326,18 @@ static enum print_line_t blk_tracer_print_line(struct trace_iterator *iter) return print_one_line(iter, true); } +static int blk_tracer_set_flag(u32 old_flags, u32 bit, int set) +{ + /* don't output context-info for blk_classic output */ + if (bit == TRACE_BLK_OPT_CLASSIC) { + if (set) + trace_flags &= ~TRACE_ITER_CONTEXT_INFO; + else + trace_flags |= TRACE_ITER_CONTEXT_INFO; + } + return 0; +} + static struct tracer blk_tracer __read_mostly = { .name = "blk", .init = blk_tracer_init, @@ -1241,6 +1347,7 @@ static struct tracer blk_tracer __read_mostly = { .print_header = blk_tracer_print_header, .print_line = blk_tracer_print_line, .flags = &blk_tracer_flags, + .set_flag = blk_tracer_set_flag, }; static struct trace_event trace_blk_event = { @@ -1285,7 +1392,8 @@ static int blk_trace_remove_queue(struct request_queue *q) /* * Setup everything required to start tracing */ -static int blk_trace_setup_queue(struct request_queue *q, dev_t dev) +static int blk_trace_setup_queue(struct request_queue *q, + struct block_device *bdev) { struct blk_trace *old_bt, *bt = NULL; int ret = -ENOMEM; @@ -1298,9 +1406,10 @@ static int blk_trace_setup_queue(struct request_queue *q, dev_t dev) if (!bt->msg_data) goto free_bt; - bt->dev = dev; + bt->dev = bdev->bd_dev; bt->act_mask = (u16)-1; - bt->end_lba = -1ULL; + + blk_trace_setup_lba(bt, bdev); old_bt = xchg(&q->blk_trace, bt); if (old_bt != NULL) { @@ -1517,7 +1626,7 @@ static ssize_t sysfs_blk_trace_attr_store(struct device *dev, if (attr == &dev_attr_enable) { if (value) - ret = blk_trace_setup_queue(q, bdev->bd_dev); + ret = blk_trace_setup_queue(q, bdev); else ret = blk_trace_remove_queue(q); goto out_unlock_bdev; @@ -1525,7 +1634,7 @@ static ssize_t sysfs_blk_trace_attr_store(struct device *dev, ret = 0; if (q->blk_trace == NULL) - ret = blk_trace_setup_queue(q, bdev->bd_dev); + ret = blk_trace_setup_queue(q, bdev); if (ret == 0) { if (attr == &dev_attr_act_mask) @@ -1548,3 +1657,77 @@ out: return ret ? ret : count; } +int blk_trace_init_sysfs(struct device *dev) +{ + return sysfs_create_group(&dev->kobj, &blk_trace_attr_group); +} + +#endif /* CONFIG_BLK_DEV_IO_TRACE */ + +#ifdef CONFIG_EVENT_TRACING + +void blk_dump_cmd(char *buf, struct request *rq) +{ + int i, end; + int len = rq->cmd_len; + unsigned char *cmd = rq->cmd; + + if (!blk_pc_request(rq)) { + buf[0] = '\0'; + return; + } + + for (end = len - 1; end >= 0; end--) + if (cmd[end]) + break; + end++; + + for (i = 0; i < len; i++) { + buf += sprintf(buf, "%s%02x", i == 0 ? "" : " ", cmd[i]); + if (i == end && end != len - 1) { + sprintf(buf, " .."); + break; + } + } +} + +void blk_fill_rwbs(char *rwbs, u32 rw, int bytes) +{ + int i = 0; + + if (rw & WRITE) + rwbs[i++] = 'W'; + else if (rw & 1 << BIO_RW_DISCARD) + rwbs[i++] = 'D'; + else if (bytes) + rwbs[i++] = 'R'; + else + rwbs[i++] = 'N'; + + if (rw & 1 << BIO_RW_AHEAD) + rwbs[i++] = 'A'; + if (rw & 1 << BIO_RW_BARRIER) + rwbs[i++] = 'B'; + if (rw & 1 << BIO_RW_SYNCIO) + rwbs[i++] = 'S'; + if (rw & 1 << BIO_RW_META) + rwbs[i++] = 'M'; + + rwbs[i] = '\0'; +} + +void blk_fill_rwbs_rq(char *rwbs, struct request *rq) +{ + int rw = rq->cmd_flags & 0x03; + int bytes; + + if (blk_discard_rq(rq)) + rw |= (1 << BIO_RW_DISCARD); + + bytes = blk_rq_bytes(rq); + + blk_fill_rwbs(rwbs, rw, bytes); +} + +#endif /* CONFIG_EVENT_TRACING */ + diff --git a/kernel/trace/events.c b/kernel/trace/events.c deleted file mode 100644 index 246f2aa6dc46..000000000000 --- a/kernel/trace/events.c +++ /dev/null @@ -1,14 +0,0 @@ -/* - * This is the place to register all trace points as events. - */ - -#include - -#include - -#include "trace_output.h" - -#include "trace_events_stage_1.h" -#include "trace_events_stage_2.h" -#include "trace_events_stage_3.h" - diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index f1ed080406c3..3718d55fb4c3 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -29,11 +29,13 @@ #include #include -#include +#include #include +#include -#include "trace.h" +#include "trace_output.h" +#include "trace_stat.h" #define FTRACE_WARN_ON(cond) \ do { \ @@ -68,7 +70,7 @@ static DEFINE_MUTEX(ftrace_lock); static struct ftrace_ops ftrace_list_end __read_mostly = { - .func = ftrace_stub, + .func = ftrace_stub, }; static struct ftrace_ops *ftrace_list __read_mostly = &ftrace_list_end; @@ -240,6 +242,580 @@ static void ftrace_update_pid_func(void) #endif } +#ifdef CONFIG_FUNCTION_PROFILER +struct ftrace_profile { + struct hlist_node node; + unsigned long ip; + unsigned long counter; +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + unsigned long long time; +#endif +}; + +struct ftrace_profile_page { + struct ftrace_profile_page *next; + unsigned long index; + struct ftrace_profile records[]; +}; + +struct ftrace_profile_stat { + atomic_t disabled; + struct hlist_head *hash; + struct ftrace_profile_page *pages; + struct ftrace_profile_page *start; + struct tracer_stat stat; +}; + +#define PROFILE_RECORDS_SIZE \ + (PAGE_SIZE - offsetof(struct ftrace_profile_page, records)) + +#define PROFILES_PER_PAGE \ + (PROFILE_RECORDS_SIZE / sizeof(struct ftrace_profile)) + +static int ftrace_profile_bits __read_mostly; +static int ftrace_profile_enabled __read_mostly; + +/* ftrace_profile_lock - synchronize the enable and disable of the profiler */ +static DEFINE_MUTEX(ftrace_profile_lock); + +static DEFINE_PER_CPU(struct ftrace_profile_stat, ftrace_profile_stats); + +#define FTRACE_PROFILE_HASH_SIZE 1024 /* must be power of 2 */ + +static void * +function_stat_next(void *v, int idx) +{ + struct ftrace_profile *rec = v; + struct ftrace_profile_page *pg; + + pg = (struct ftrace_profile_page *)((unsigned long)rec & PAGE_MASK); + + again: + rec++; + if ((void *)rec >= (void *)&pg->records[pg->index]) { + pg = pg->next; + if (!pg) + return NULL; + rec = &pg->records[0]; + if (!rec->counter) + goto again; + } + + return rec; +} + +static void *function_stat_start(struct tracer_stat *trace) +{ + struct ftrace_profile_stat *stat = + container_of(trace, struct ftrace_profile_stat, stat); + + if (!stat || !stat->start) + return NULL; + + return function_stat_next(&stat->start->records[0], 0); +} + +#ifdef CONFIG_FUNCTION_GRAPH_TRACER +/* function graph compares on total time */ +static int function_stat_cmp(void *p1, void *p2) +{ + struct ftrace_profile *a = p1; + struct ftrace_profile *b = p2; + + if (a->time < b->time) + return -1; + if (a->time > b->time) + return 1; + else + return 0; +} +#else +/* not function graph compares against hits */ +static int function_stat_cmp(void *p1, void *p2) +{ + struct ftrace_profile *a = p1; + struct ftrace_profile *b = p2; + + if (a->counter < b->counter) + return -1; + if (a->counter > b->counter) + return 1; + else + return 0; +} +#endif + +static int function_stat_headers(struct seq_file *m) +{ +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + seq_printf(m, " Function " + "Hit Time Avg\n" + " -------- " + "--- ---- ---\n"); +#else + seq_printf(m, " Function Hit\n" + " -------- ---\n"); +#endif + return 0; +} + +static int function_stat_show(struct seq_file *m, void *v) +{ + struct ftrace_profile *rec = v; + char str[KSYM_SYMBOL_LEN]; +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + static DEFINE_MUTEX(mutex); + static struct trace_seq s; + unsigned long long avg; +#endif + + kallsyms_lookup(rec->ip, NULL, NULL, NULL, str); + seq_printf(m, " %-30.30s %10lu", str, rec->counter); + +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + seq_printf(m, " "); + avg = rec->time; + do_div(avg, rec->counter); + + mutex_lock(&mutex); + trace_seq_init(&s); + trace_print_graph_duration(rec->time, &s); + trace_seq_puts(&s, " "); + trace_print_graph_duration(avg, &s); + trace_print_seq(m, &s); + mutex_unlock(&mutex); +#endif + seq_putc(m, '\n'); + + return 0; +} + +static void ftrace_profile_reset(struct ftrace_profile_stat *stat) +{ + struct ftrace_profile_page *pg; + + pg = stat->pages = stat->start; + + while (pg) { + memset(pg->records, 0, PROFILE_RECORDS_SIZE); + pg->index = 0; + pg = pg->next; + } + + memset(stat->hash, 0, + FTRACE_PROFILE_HASH_SIZE * sizeof(struct hlist_head)); +} + +int ftrace_profile_pages_init(struct ftrace_profile_stat *stat) +{ + struct ftrace_profile_page *pg; + int functions; + int pages; + int i; + + /* If we already allocated, do nothing */ + if (stat->pages) + return 0; + + stat->pages = (void *)get_zeroed_page(GFP_KERNEL); + if (!stat->pages) + return -ENOMEM; + +#ifdef CONFIG_DYNAMIC_FTRACE + functions = ftrace_update_tot_cnt; +#else + /* + * We do not know the number of functions that exist because + * dynamic tracing is what counts them. With past experience + * we have around 20K functions. That should be more than enough. + * It is highly unlikely we will execute every function in + * the kernel. + */ + functions = 20000; +#endif + + pg = stat->start = stat->pages; + + pages = DIV_ROUND_UP(functions, PROFILES_PER_PAGE); + + for (i = 0; i < pages; i++) { + pg->next = (void *)get_zeroed_page(GFP_KERNEL); + if (!pg->next) + goto out_free; + pg = pg->next; + } + + return 0; + + out_free: + pg = stat->start; + while (pg) { + unsigned long tmp = (unsigned long)pg; + + pg = pg->next; + free_page(tmp); + } + + free_page((unsigned long)stat->pages); + stat->pages = NULL; + stat->start = NULL; + + return -ENOMEM; +} + +static int ftrace_profile_init_cpu(int cpu) +{ + struct ftrace_profile_stat *stat; + int size; + + stat = &per_cpu(ftrace_profile_stats, cpu); + + if (stat->hash) { + /* If the profile is already created, simply reset it */ + ftrace_profile_reset(stat); + return 0; + } + + /* + * We are profiling all functions, but usually only a few thousand + * functions are hit. We'll make a hash of 1024 items. + */ + size = FTRACE_PROFILE_HASH_SIZE; + + stat->hash = kzalloc(sizeof(struct hlist_head) * size, GFP_KERNEL); + + if (!stat->hash) + return -ENOMEM; + + if (!ftrace_profile_bits) { + size--; + + for (; size; size >>= 1) + ftrace_profile_bits++; + } + + /* Preallocate the function profiling pages */ + if (ftrace_profile_pages_init(stat) < 0) { + kfree(stat->hash); + stat->hash = NULL; + return -ENOMEM; + } + + return 0; +} + +static int ftrace_profile_init(void) +{ + int cpu; + int ret = 0; + + for_each_online_cpu(cpu) { + ret = ftrace_profile_init_cpu(cpu); + if (ret) + break; + } + + return ret; +} + +/* interrupts must be disabled */ +static struct ftrace_profile * +ftrace_find_profiled_func(struct ftrace_profile_stat *stat, unsigned long ip) +{ + struct ftrace_profile *rec; + struct hlist_head *hhd; + struct hlist_node *n; + unsigned long key; + + key = hash_long(ip, ftrace_profile_bits); + hhd = &stat->hash[key]; + + if (hlist_empty(hhd)) + return NULL; + + hlist_for_each_entry_rcu(rec, n, hhd, node) { + if (rec->ip == ip) + return rec; + } + + return NULL; +} + +static void ftrace_add_profile(struct ftrace_profile_stat *stat, + struct ftrace_profile *rec) +{ + unsigned long key; + + key = hash_long(rec->ip, ftrace_profile_bits); + hlist_add_head_rcu(&rec->node, &stat->hash[key]); +} + +/* + * The memory is already allocated, this simply finds a new record to use. + */ +static struct ftrace_profile * +ftrace_profile_alloc(struct ftrace_profile_stat *stat, unsigned long ip) +{ + struct ftrace_profile *rec = NULL; + + /* prevent recursion (from NMIs) */ + if (atomic_inc_return(&stat->disabled) != 1) + goto out; + + /* + * Try to find the function again since an NMI + * could have added it + */ + rec = ftrace_find_profiled_func(stat, ip); + if (rec) + goto out; + + if (stat->pages->index == PROFILES_PER_PAGE) { + if (!stat->pages->next) + goto out; + stat->pages = stat->pages->next; + } + + rec = &stat->pages->records[stat->pages->index++]; + rec->ip = ip; + ftrace_add_profile(stat, rec); + + out: + atomic_dec(&stat->disabled); + + return rec; +} + +static void +function_profile_call(unsigned long ip, unsigned long parent_ip) +{ + struct ftrace_profile_stat *stat; + struct ftrace_profile *rec; + unsigned long flags; + + if (!ftrace_profile_enabled) + return; + + local_irq_save(flags); + + stat = &__get_cpu_var(ftrace_profile_stats); + if (!stat->hash || !ftrace_profile_enabled) + goto out; + + rec = ftrace_find_profiled_func(stat, ip); + if (!rec) { + rec = ftrace_profile_alloc(stat, ip); + if (!rec) + goto out; + } + + rec->counter++; + out: + local_irq_restore(flags); +} + +#ifdef CONFIG_FUNCTION_GRAPH_TRACER +static int profile_graph_entry(struct ftrace_graph_ent *trace) +{ + function_profile_call(trace->func, 0); + return 1; +} + +static void profile_graph_return(struct ftrace_graph_ret *trace) +{ + struct ftrace_profile_stat *stat; + unsigned long long calltime; + struct ftrace_profile *rec; + unsigned long flags; + + local_irq_save(flags); + stat = &__get_cpu_var(ftrace_profile_stats); + if (!stat->hash || !ftrace_profile_enabled) + goto out; + + calltime = trace->rettime - trace->calltime; + + if (!(trace_flags & TRACE_ITER_GRAPH_TIME)) { + int index; + + index = trace->depth; + + /* Append this call time to the parent time to subtract */ + if (index) + current->ret_stack[index - 1].subtime += calltime; + + if (current->ret_stack[index].subtime < calltime) + calltime -= current->ret_stack[index].subtime; + else + calltime = 0; + } + + rec = ftrace_find_profiled_func(stat, trace->func); + if (rec) + rec->time += calltime; + + out: + local_irq_restore(flags); +} + +static int register_ftrace_profiler(void) +{ + return register_ftrace_graph(&profile_graph_return, + &profile_graph_entry); +} + +static void unregister_ftrace_profiler(void) +{ + unregister_ftrace_graph(); +} +#else +static struct ftrace_ops ftrace_profile_ops __read_mostly = +{ + .func = function_profile_call, +}; + +static int register_ftrace_profiler(void) +{ + return register_ftrace_function(&ftrace_profile_ops); +} + +static void unregister_ftrace_profiler(void) +{ + unregister_ftrace_function(&ftrace_profile_ops); +} +#endif /* CONFIG_FUNCTION_GRAPH_TRACER */ + +static ssize_t +ftrace_profile_write(struct file *filp, const char __user *ubuf, + size_t cnt, loff_t *ppos) +{ + unsigned long val; + char buf[64]; /* big enough to hold a number */ + int ret; + + if (cnt >= sizeof(buf)) + return -EINVAL; + + if (copy_from_user(&buf, ubuf, cnt)) + return -EFAULT; + + buf[cnt] = 0; + + ret = strict_strtoul(buf, 10, &val); + if (ret < 0) + return ret; + + val = !!val; + + mutex_lock(&ftrace_profile_lock); + if (ftrace_profile_enabled ^ val) { + if (val) { + ret = ftrace_profile_init(); + if (ret < 0) { + cnt = ret; + goto out; + } + + ret = register_ftrace_profiler(); + if (ret < 0) { + cnt = ret; + goto out; + } + ftrace_profile_enabled = 1; + } else { + ftrace_profile_enabled = 0; + /* + * unregister_ftrace_profiler calls stop_machine + * so this acts like an synchronize_sched. + */ + unregister_ftrace_profiler(); + } + } + out: + mutex_unlock(&ftrace_profile_lock); + + filp->f_pos += cnt; + + return cnt; +} + +static ssize_t +ftrace_profile_read(struct file *filp, char __user *ubuf, + size_t cnt, loff_t *ppos) +{ + char buf[64]; /* big enough to hold a number */ + int r; + + r = sprintf(buf, "%u\n", ftrace_profile_enabled); + return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); +} + +static const struct file_operations ftrace_profile_fops = { + .open = tracing_open_generic, + .read = ftrace_profile_read, + .write = ftrace_profile_write, +}; + +/* used to initialize the real stat files */ +static struct tracer_stat function_stats __initdata = { + .name = "functions", + .stat_start = function_stat_start, + .stat_next = function_stat_next, + .stat_cmp = function_stat_cmp, + .stat_headers = function_stat_headers, + .stat_show = function_stat_show +}; + +static void ftrace_profile_debugfs(struct dentry *d_tracer) +{ + struct ftrace_profile_stat *stat; + struct dentry *entry; + char *name; + int ret; + int cpu; + + for_each_possible_cpu(cpu) { + stat = &per_cpu(ftrace_profile_stats, cpu); + + /* allocate enough for function name + cpu number */ + name = kmalloc(32, GFP_KERNEL); + if (!name) { + /* + * The files created are permanent, if something happens + * we still do not free memory. + */ + kfree(stat); + WARN(1, + "Could not allocate stat file for cpu %d\n", + cpu); + return; + } + stat->stat = function_stats; + snprintf(name, 32, "function%d", cpu); + stat->stat.name = name; + ret = register_stat_tracer(&stat->stat); + if (ret) { + WARN(1, + "Could not register function stat for cpu %d\n", + cpu); + kfree(name); + return; + } + } + + entry = debugfs_create_file("function_profile_enabled", 0644, + d_tracer, NULL, &ftrace_profile_fops); + if (!entry) + pr_warning("Could not create debugfs " + "'function_profile_enabled' entry\n"); +} + +#else /* CONFIG_FUNCTION_PROFILER */ +static void ftrace_profile_debugfs(struct dentry *d_tracer) +{ +} +#endif /* CONFIG_FUNCTION_PROFILER */ + /* set when tracing only a pid */ struct pid *ftrace_pid_trace; static struct pid * const ftrace_swapper_pid = &init_struct_pid; @@ -261,7 +837,6 @@ struct ftrace_func_probe { struct rcu_head rcu; }; - enum { FTRACE_ENABLE_CALLS = (1 << 0), FTRACE_DISABLE_CALLS = (1 << 1), @@ -346,30 +921,6 @@ static void ftrace_free_rec(struct dyn_ftrace *rec) rec->flags |= FTRACE_FL_FREE; } -void ftrace_release(void *start, unsigned long size) -{ - struct dyn_ftrace *rec; - struct ftrace_page *pg; - unsigned long s = (unsigned long)start; - unsigned long e = s + size; - - if (ftrace_disabled || !start) - return; - - mutex_lock(&ftrace_lock); - do_for_each_ftrace_rec(pg, rec) { - if ((rec->ip >= s) && (rec->ip < e)) { - /* - * rec->ip is changed in ftrace_free_rec() - * It should not between s and e if record was freed. - */ - FTRACE_WARN_ON(rec->flags & FTRACE_FL_FREE); - ftrace_free_rec(rec); - } - } while_for_each_ftrace_rec(); - mutex_unlock(&ftrace_lock); -} - static struct dyn_ftrace *ftrace_alloc_dyn_node(unsigned long ip) { struct dyn_ftrace *rec; @@ -673,6 +1224,13 @@ static void ftrace_shutdown(int command) return; ftrace_start_up--; + /* + * Just warn in case of unbalance, no need to kill ftrace, it's not + * critical but the ftrace_call callers may be never nopped again after + * further ftrace uses. + */ + WARN_ON_ONCE(ftrace_start_up < 0); + if (!ftrace_start_up) command |= FTRACE_DISABLE_CALLS; @@ -1408,7 +1966,7 @@ function_trace_probe_call(unsigned long ip, unsigned long parent_ip) static struct ftrace_ops trace_probe_ops __read_mostly = { - .func = function_trace_probe_call, + .func = function_trace_probe_call, }; static int ftrace_probe_registered; @@ -1823,6 +2381,45 @@ void ftrace_set_notrace(unsigned char *buf, int len, int reset) ftrace_set_regex(buf, len, reset, 0); } +/* + * command line interface to allow users to set filters on boot up. + */ +#define FTRACE_FILTER_SIZE COMMAND_LINE_SIZE +static char ftrace_notrace_buf[FTRACE_FILTER_SIZE] __initdata; +static char ftrace_filter_buf[FTRACE_FILTER_SIZE] __initdata; + +static int __init set_ftrace_notrace(char *str) +{ + strncpy(ftrace_notrace_buf, str, FTRACE_FILTER_SIZE); + return 1; +} +__setup("ftrace_notrace=", set_ftrace_notrace); + +static int __init set_ftrace_filter(char *str) +{ + strncpy(ftrace_filter_buf, str, FTRACE_FILTER_SIZE); + return 1; +} +__setup("ftrace_filter=", set_ftrace_filter); + +static void __init set_ftrace_early_filter(char *buf, int enable) +{ + char *func; + + while (buf) { + func = strsep(&buf, ","); + ftrace_set_regex(func, strlen(func), 0, enable); + } +} + +static void __init set_ftrace_early_filters(void) +{ + if (ftrace_filter_buf[0]) + set_ftrace_early_filter(ftrace_filter_buf, 1); + if (ftrace_notrace_buf[0]) + set_ftrace_early_filter(ftrace_notrace_buf, 0); +} + static int ftrace_regex_release(struct inode *inode, struct file *file, int enable) { @@ -2128,38 +2725,23 @@ static const struct file_operations ftrace_graph_fops = { static __init int ftrace_init_dyn_debugfs(struct dentry *d_tracer) { - struct dentry *entry; - entry = debugfs_create_file("available_filter_functions", 0444, - d_tracer, NULL, &ftrace_avail_fops); - if (!entry) - pr_warning("Could not create debugfs " - "'available_filter_functions' entry\n"); + trace_create_file("available_filter_functions", 0444, + d_tracer, NULL, &ftrace_avail_fops); - entry = debugfs_create_file("failures", 0444, - d_tracer, NULL, &ftrace_failures_fops); - if (!entry) - pr_warning("Could not create debugfs 'failures' entry\n"); + trace_create_file("failures", 0444, + d_tracer, NULL, &ftrace_failures_fops); - entry = debugfs_create_file("set_ftrace_filter", 0644, d_tracer, - NULL, &ftrace_filter_fops); - if (!entry) - pr_warning("Could not create debugfs " - "'set_ftrace_filter' entry\n"); + trace_create_file("set_ftrace_filter", 0644, d_tracer, + NULL, &ftrace_filter_fops); - entry = debugfs_create_file("set_ftrace_notrace", 0644, d_tracer, + trace_create_file("set_ftrace_notrace", 0644, d_tracer, NULL, &ftrace_notrace_fops); - if (!entry) - pr_warning("Could not create debugfs " - "'set_ftrace_notrace' entry\n"); #ifdef CONFIG_FUNCTION_GRAPH_TRACER - entry = debugfs_create_file("set_graph_function", 0444, d_tracer, + trace_create_file("set_graph_function", 0444, d_tracer, NULL, &ftrace_graph_fops); - if (!entry) - pr_warning("Could not create debugfs " - "'set_graph_function' entry\n"); #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ return 0; @@ -2197,14 +2779,72 @@ static int ftrace_convert_nops(struct module *mod, return 0; } -void ftrace_init_module(struct module *mod, - unsigned long *start, unsigned long *end) +#ifdef CONFIG_MODULES +void ftrace_release(void *start, void *end) +{ + struct dyn_ftrace *rec; + struct ftrace_page *pg; + unsigned long s = (unsigned long)start; + unsigned long e = (unsigned long)end; + + if (ftrace_disabled || !start || start == end) + return; + + mutex_lock(&ftrace_lock); + do_for_each_ftrace_rec(pg, rec) { + if ((rec->ip >= s) && (rec->ip < e)) { + /* + * rec->ip is changed in ftrace_free_rec() + * It should not between s and e if record was freed. + */ + FTRACE_WARN_ON(rec->flags & FTRACE_FL_FREE); + ftrace_free_rec(rec); + } + } while_for_each_ftrace_rec(); + mutex_unlock(&ftrace_lock); +} + +static void ftrace_init_module(struct module *mod, + unsigned long *start, unsigned long *end) { if (ftrace_disabled || start == end) return; ftrace_convert_nops(mod, start, end); } +static int ftrace_module_notify(struct notifier_block *self, + unsigned long val, void *data) +{ + struct module *mod = data; + + switch (val) { + case MODULE_STATE_COMING: + ftrace_init_module(mod, mod->ftrace_callsites, + mod->ftrace_callsites + + mod->num_ftrace_callsites); + break; + case MODULE_STATE_GOING: + ftrace_release(mod->ftrace_callsites, + mod->ftrace_callsites + + mod->num_ftrace_callsites); + break; + } + + return 0; +} +#else +static int ftrace_module_notify(struct notifier_block *self, + unsigned long val, void *data) +{ + return 0; +} +#endif /* CONFIG_MODULES */ + +struct notifier_block ftrace_module_nb = { + .notifier_call = ftrace_module_notify, + .priority = 0, +}; + extern unsigned long __start_mcount_loc[]; extern unsigned long __stop_mcount_loc[]; @@ -2236,6 +2876,12 @@ void __init ftrace_init(void) __start_mcount_loc, __stop_mcount_loc); + ret = register_module_notifier(&ftrace_module_nb); + if (ret) + pr_warning("Failed to register trace ftrace module notifier\n"); + + set_ftrace_early_filters(); + return; failed: ftrace_disabled = 1; @@ -2417,7 +3063,6 @@ static const struct file_operations ftrace_pid_fops = { static __init int ftrace_init_debugfs(void) { struct dentry *d_tracer; - struct dentry *entry; d_tracer = tracing_init_dentry(); if (!d_tracer) @@ -2425,11 +3070,11 @@ static __init int ftrace_init_debugfs(void) ftrace_init_dyn_debugfs(d_tracer); - entry = debugfs_create_file("set_ftrace_pid", 0644, d_tracer, - NULL, &ftrace_pid_fops); - if (!entry) - pr_warning("Could not create debugfs " - "'set_ftrace_pid' entry\n"); + trace_create_file("set_ftrace_pid", 0644, d_tracer, + NULL, &ftrace_pid_fops); + + ftrace_profile_debugfs(d_tracer); + return 0; } fs_initcall(ftrace_init_debugfs); @@ -2538,7 +3183,7 @@ ftrace_enable_sysctl(struct ctl_table *table, int write, #ifdef CONFIG_FUNCTION_GRAPH_TRACER -static atomic_t ftrace_graph_active; +static int ftrace_graph_active; static struct notifier_block ftrace_suspend_notifier; int ftrace_graph_entry_stub(struct ftrace_graph_ent *trace) @@ -2580,12 +3225,12 @@ static int alloc_retstack_tasklist(struct ftrace_ret_stack **ret_stack_list) } if (t->ret_stack == NULL) { - t->curr_ret_stack = -1; - /* Make sure IRQs see the -1 first: */ - barrier(); - t->ret_stack = ret_stack_list[start++]; atomic_set(&t->tracing_graph_pause, 0); atomic_set(&t->trace_overrun, 0); + t->curr_ret_stack = -1; + /* Make sure the tasks see the -1 first: */ + smp_wmb(); + t->ret_stack = ret_stack_list[start++]; } } while_each_thread(g, t); @@ -2643,8 +3288,10 @@ static int start_graph_tracing(void) return -ENOMEM; /* The cpu_boot init_task->ret_stack will never be freed */ - for_each_online_cpu(cpu) - ftrace_graph_init_task(idle_task(cpu)); + for_each_online_cpu(cpu) { + if (!idle_task(cpu)->ret_stack) + ftrace_graph_init_task(idle_task(cpu)); + } do { ret = alloc_retstack_tasklist(ret_stack_list); @@ -2690,7 +3337,7 @@ int register_ftrace_graph(trace_func_graph_ret_t retfunc, mutex_lock(&ftrace_lock); /* we currently allow only one tracer registered at a time */ - if (atomic_read(&ftrace_graph_active)) { + if (ftrace_graph_active) { ret = -EBUSY; goto out; } @@ -2698,10 +3345,10 @@ int register_ftrace_graph(trace_func_graph_ret_t retfunc, ftrace_suspend_notifier.notifier_call = ftrace_suspend_notifier_call; register_pm_notifier(&ftrace_suspend_notifier); - atomic_inc(&ftrace_graph_active); + ftrace_graph_active++; ret = start_graph_tracing(); if (ret) { - atomic_dec(&ftrace_graph_active); + ftrace_graph_active--; goto out; } @@ -2719,10 +3366,10 @@ void unregister_ftrace_graph(void) { mutex_lock(&ftrace_lock); - if (!unlikely(atomic_read(&ftrace_graph_active))) + if (unlikely(!ftrace_graph_active)) goto out; - atomic_dec(&ftrace_graph_active); + ftrace_graph_active--; unregister_trace_sched_switch(ftrace_graph_probe_sched_switch); ftrace_graph_return = (trace_func_graph_ret_t)ftrace_stub; ftrace_graph_entry = ftrace_graph_entry_stub; @@ -2736,18 +3383,25 @@ void unregister_ftrace_graph(void) /* Allocate a return stack for newly created task */ void ftrace_graph_init_task(struct task_struct *t) { - if (atomic_read(&ftrace_graph_active)) { - t->ret_stack = kmalloc(FTRACE_RETFUNC_DEPTH + /* Make sure we do not use the parent ret_stack */ + t->ret_stack = NULL; + + if (ftrace_graph_active) { + struct ftrace_ret_stack *ret_stack; + + ret_stack = kmalloc(FTRACE_RETFUNC_DEPTH * sizeof(struct ftrace_ret_stack), GFP_KERNEL); - if (!t->ret_stack) + if (!ret_stack) return; t->curr_ret_stack = -1; atomic_set(&t->tracing_graph_pause, 0); atomic_set(&t->trace_overrun, 0); t->ftrace_timestamp = 0; - } else - t->ret_stack = NULL; + /* make curr_ret_stack visable before we add the ret_stack */ + smp_wmb(); + t->ret_stack = ret_stack; + } } void ftrace_graph_exit_task(struct task_struct *t) diff --git a/kernel/trace/kmemtrace.c b/kernel/trace/kmemtrace.c index 5011f4d91e37..1edaa9516e81 100644 --- a/kernel/trace/kmemtrace.c +++ b/kernel/trace/kmemtrace.c @@ -12,7 +12,7 @@ #include #include -#include +#include #include "trace_output.h" #include "trace.h" @@ -42,6 +42,7 @@ static inline void kmemtrace_alloc(enum kmemtrace_type_id type_id, gfp_t gfp_flags, int node) { + struct ftrace_event_call *call = &event_kmem_alloc; struct trace_array *tr = kmemtrace_array; struct kmemtrace_alloc_entry *entry; struct ring_buffer_event *event; @@ -62,7 +63,8 @@ static inline void kmemtrace_alloc(enum kmemtrace_type_id type_id, entry->gfp_flags = gfp_flags; entry->node = node; - ring_buffer_unlock_commit(tr->buffer, event); + if (!filter_check_discard(call, entry, tr->buffer, event)) + ring_buffer_unlock_commit(tr->buffer, event); trace_wake_up(); } @@ -71,6 +73,7 @@ static inline void kmemtrace_free(enum kmemtrace_type_id type_id, unsigned long call_site, const void *ptr) { + struct ftrace_event_call *call = &event_kmem_free; struct trace_array *tr = kmemtrace_array; struct kmemtrace_free_entry *entry; struct ring_buffer_event *event; @@ -86,7 +89,8 @@ static inline void kmemtrace_free(enum kmemtrace_type_id type_id, entry->call_site = call_site; entry->ptr = ptr; - ring_buffer_unlock_commit(tr->buffer, event); + if (!filter_check_discard(call, entry, tr->buffer, event)) + ring_buffer_unlock_commit(tr->buffer, event); trace_wake_up(); } @@ -182,7 +186,7 @@ static int kmem_trace_init(struct trace_array *tr) int cpu; kmemtrace_array = tr; - for_each_cpu_mask(cpu, cpu_possible_map) + for_each_cpu(cpu, cpu_possible_mask) tracing_reset(tr, cpu); kmemtrace_start_probes(); diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index 960cbf44c844..04dac2638258 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -21,6 +22,28 @@ #include "trace.h" +/* + * The ring buffer header is special. We must manually up keep it. + */ +int ring_buffer_print_entry_header(struct trace_seq *s) +{ + int ret; + + ret = trace_seq_printf(s, "# compressed entry header\n"); + ret = trace_seq_printf(s, "\ttype_len : 5 bits\n"); + ret = trace_seq_printf(s, "\ttime_delta : 27 bits\n"); + ret = trace_seq_printf(s, "\tarray : 32 bits\n"); + ret = trace_seq_printf(s, "\n"); + ret = trace_seq_printf(s, "\tpadding : type == %d\n", + RINGBUF_TYPE_PADDING); + ret = trace_seq_printf(s, "\ttime_extend : type == %d\n", + RINGBUF_TYPE_TIME_EXTEND); + ret = trace_seq_printf(s, "\tdata max type_len == %d\n", + RINGBUF_TYPE_DATA_TYPE_LEN_MAX); + + return ret; +} + /* * The ring buffer is made up of a list of pages. A separate list of pages is * allocated for each CPU. A writer may only write to a buffer that is @@ -182,7 +205,11 @@ EXPORT_SYMBOL_GPL(tracing_is_on); #define RB_EVNT_HDR_SIZE (offsetof(struct ring_buffer_event, array)) #define RB_ALIGNMENT 4U -#define RB_MAX_SMALL_DATA 28 +#define RB_MAX_SMALL_DATA (RB_ALIGNMENT * RINGBUF_TYPE_DATA_TYPE_LEN_MAX) +#define RB_EVNT_MIN_SIZE 8U /* two 32bit words */ + +/* define RINGBUF_TYPE_DATA for 'case RINGBUF_TYPE_DATA:' */ +#define RINGBUF_TYPE_DATA 0 ... RINGBUF_TYPE_DATA_TYPE_LEN_MAX enum { RB_LEN_TIME_EXTEND = 8, @@ -191,48 +218,28 @@ enum { static inline int rb_null_event(struct ring_buffer_event *event) { - return event->type == RINGBUF_TYPE_PADDING && event->time_delta == 0; + return event->type_len == RINGBUF_TYPE_PADDING + && event->time_delta == 0; } static inline int rb_discarded_event(struct ring_buffer_event *event) { - return event->type == RINGBUF_TYPE_PADDING && event->time_delta; + return event->type_len == RINGBUF_TYPE_PADDING && event->time_delta; } static void rb_event_set_padding(struct ring_buffer_event *event) { - event->type = RINGBUF_TYPE_PADDING; + event->type_len = RINGBUF_TYPE_PADDING; event->time_delta = 0; } -/** - * ring_buffer_event_discard - discard an event in the ring buffer - * @buffer: the ring buffer - * @event: the event to discard - * - * Sometimes a event that is in the ring buffer needs to be ignored. - * This function lets the user discard an event in the ring buffer - * and then that event will not be read later. - * - * Note, it is up to the user to be careful with this, and protect - * against races. If the user discards an event that has been consumed - * it is possible that it could corrupt the ring buffer. - */ -void ring_buffer_event_discard(struct ring_buffer_event *event) -{ - event->type = RINGBUF_TYPE_PADDING; - /* time delta must be non zero */ - if (!event->time_delta) - event->time_delta = 1; -} - static unsigned rb_event_data_length(struct ring_buffer_event *event) { unsigned length; - if (event->len) - length = event->len * RB_ALIGNMENT; + if (event->type_len) + length = event->type_len * RB_ALIGNMENT; else length = event->array[0]; return length + RB_EVNT_HDR_SIZE; @@ -242,12 +249,12 @@ rb_event_data_length(struct ring_buffer_event *event) static unsigned rb_event_length(struct ring_buffer_event *event) { - switch (event->type) { + switch (event->type_len) { case RINGBUF_TYPE_PADDING: if (rb_null_event(event)) /* undefined */ return -1; - return rb_event_data_length(event); + return event->array[0] + RB_EVNT_HDR_SIZE; case RINGBUF_TYPE_TIME_EXTEND: return RB_LEN_TIME_EXTEND; @@ -271,7 +278,7 @@ rb_event_length(struct ring_buffer_event *event) unsigned ring_buffer_event_length(struct ring_buffer_event *event) { unsigned length = rb_event_length(event); - if (event->type != RINGBUF_TYPE_DATA) + if (event->type_len > RINGBUF_TYPE_DATA_TYPE_LEN_MAX) return length; length -= RB_EVNT_HDR_SIZE; if (length > RB_MAX_SMALL_DATA + sizeof(event->array[0])) @@ -284,9 +291,9 @@ EXPORT_SYMBOL_GPL(ring_buffer_event_length); static void * rb_event_data(struct ring_buffer_event *event) { - BUG_ON(event->type != RINGBUF_TYPE_DATA); + BUG_ON(event->type_len > RINGBUF_TYPE_DATA_TYPE_LEN_MAX); /* If length is in len field, then array[0] has the data */ - if (event->len) + if (event->type_len) return (void *)&event->array[0]; /* Otherwise length is in array[0] and array[1] has the data */ return (void *)&event->array[1]; @@ -316,9 +323,10 @@ struct buffer_data_page { }; struct buffer_page { + struct list_head list; /* list of buffer pages */ local_t write; /* index for next write */ unsigned read; /* index for next read */ - struct list_head list; /* list of free pages */ + local_t entries; /* entries on this page */ struct buffer_data_page *page; /* Actual data page */ }; @@ -361,6 +369,34 @@ static inline int test_time_stamp(u64 delta) #define BUF_PAGE_SIZE (PAGE_SIZE - BUF_PAGE_HDR_SIZE) +/* Max payload is BUF_PAGE_SIZE - header (8bytes) */ +#define BUF_MAX_DATA_SIZE (BUF_PAGE_SIZE - (sizeof(u32) * 2)) + +/* Max number of timestamps that can fit on a page */ +#define RB_TIMESTAMPS_PER_PAGE (BUF_PAGE_SIZE / RB_LEN_TIME_STAMP) + +int ring_buffer_print_page_header(struct trace_seq *s) +{ + struct buffer_data_page field; + int ret; + + ret = trace_seq_printf(s, "\tfield: u64 timestamp;\t" + "offset:0;\tsize:%u;\n", + (unsigned int)sizeof(field.time_stamp)); + + ret = trace_seq_printf(s, "\tfield: local_t commit;\t" + "offset:%u;\tsize:%u;\n", + (unsigned int)offsetof(typeof(field), commit), + (unsigned int)sizeof(field.commit)); + + ret = trace_seq_printf(s, "\tfield: char data;\t" + "offset:%u;\tsize:%u;\n", + (unsigned int)offsetof(typeof(field), data), + (unsigned int)BUF_PAGE_SIZE); + + return ret; +} + /* * head_page == tail_page && head == tail then buffer is empty. */ @@ -375,8 +411,13 @@ struct ring_buffer_per_cpu { struct buffer_page *tail_page; /* write to tail */ struct buffer_page *commit_page; /* committed pages */ struct buffer_page *reader_page; + unsigned long nmi_dropped; + unsigned long commit_overrun; unsigned long overrun; - unsigned long entries; + unsigned long read; + local_t entries; + local_t committing; + local_t commits; u64 write_stamp; u64 read_stamp; atomic_t record_disabled; @@ -389,6 +430,8 @@ struct ring_buffer { atomic_t record_disabled; cpumask_var_t cpumask; + struct lock_class_key *reader_lock_key; + struct mutex mutex; struct ring_buffer_per_cpu **buffers; @@ -420,13 +463,18 @@ struct ring_buffer_iter { /* Up this if you want to test the TIME_EXTENTS and normalization */ #define DEBUG_SHIFT 0 +static inline u64 rb_time_stamp(struct ring_buffer *buffer, int cpu) +{ + /* shift to debug/test normalization and TIME_EXTENTS */ + return buffer->clock() << DEBUG_SHIFT; +} + u64 ring_buffer_time_stamp(struct ring_buffer *buffer, int cpu) { u64 time; preempt_disable_notrace(); - /* shift to debug/test normalization and TIME_EXTENTS */ - time = buffer->clock() << DEBUG_SHIFT; + time = rb_time_stamp(buffer, cpu); preempt_enable_no_resched_notrace(); return time; @@ -523,6 +571,7 @@ rb_allocate_cpu_buffer(struct ring_buffer *buffer, int cpu) cpu_buffer->cpu = cpu; cpu_buffer->buffer = buffer; spin_lock_init(&cpu_buffer->reader_lock); + lockdep_set_class(&cpu_buffer->reader_lock, buffer->reader_lock_key); cpu_buffer->lock = (raw_spinlock_t)__RAW_SPIN_LOCK_UNLOCKED; INIT_LIST_HEAD(&cpu_buffer->pages); @@ -572,12 +621,6 @@ static void rb_free_cpu_buffer(struct ring_buffer_per_cpu *cpu_buffer) kfree(cpu_buffer); } -/* - * Causes compile errors if the struct buffer_page gets bigger - * than the struct page. - */ -extern int ring_buffer_page_too_big(void); - #ifdef CONFIG_HOTPLUG_CPU static int rb_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu); @@ -593,17 +636,13 @@ static int rb_cpu_notify(struct notifier_block *self, * when the buffer wraps. If this flag is not set, the buffer will * drop data when the tail hits the head. */ -struct ring_buffer *ring_buffer_alloc(unsigned long size, unsigned flags) +struct ring_buffer *__ring_buffer_alloc(unsigned long size, unsigned flags, + struct lock_class_key *key) { struct ring_buffer *buffer; int bsize; int cpu; - /* Paranoid! Optimizes out when all is well */ - if (sizeof(struct buffer_page) > sizeof(struct page)) - ring_buffer_page_too_big(); - - /* keep it in its own cache line */ buffer = kzalloc(ALIGN(sizeof(*buffer), cache_line_size()), GFP_KERNEL); @@ -616,10 +655,11 @@ struct ring_buffer *ring_buffer_alloc(unsigned long size, unsigned flags) buffer->pages = DIV_ROUND_UP(size, BUF_PAGE_SIZE); buffer->flags = flags; buffer->clock = trace_clock_local; + buffer->reader_lock_key = key; /* need at least two pages */ - if (buffer->pages == 1) - buffer->pages++; + if (buffer->pages < 2) + buffer->pages = 2; /* * In case of non-hotplug cpu, if the ring-buffer is allocated @@ -673,7 +713,7 @@ struct ring_buffer *ring_buffer_alloc(unsigned long size, unsigned flags) kfree(buffer); return NULL; } -EXPORT_SYMBOL_GPL(ring_buffer_alloc); +EXPORT_SYMBOL_GPL(__ring_buffer_alloc); /** * ring_buffer_free - free a ring buffer. @@ -947,31 +987,6 @@ static inline unsigned rb_head_size(struct ring_buffer_per_cpu *cpu_buffer) return rb_page_commit(cpu_buffer->head_page); } -/* - * When the tail hits the head and the buffer is in overwrite mode, - * the head jumps to the next page and all content on the previous - * page is discarded. But before doing so, we update the overrun - * variable of the buffer. - */ -static void rb_update_overflow(struct ring_buffer_per_cpu *cpu_buffer) -{ - struct ring_buffer_event *event; - unsigned long head; - - for (head = 0; head < rb_head_size(cpu_buffer); - head += rb_event_length(event)) { - - event = __rb_page_index(cpu_buffer->head_page, head); - if (RB_WARN_ON(cpu_buffer, rb_null_event(event))) - return; - /* Only count data entries */ - if (event->type != RINGBUF_TYPE_DATA) - continue; - cpu_buffer->overrun++; - cpu_buffer->entries--; - } -} - static inline void rb_inc_page(struct ring_buffer_per_cpu *cpu_buffer, struct buffer_page **bpage) { @@ -988,12 +1003,12 @@ rb_event_index(struct ring_buffer_event *event) { unsigned long addr = (unsigned long)event; - return (addr & ~PAGE_MASK) - (PAGE_SIZE - BUF_PAGE_SIZE); + return (addr & ~PAGE_MASK) - BUF_PAGE_HDR_SIZE; } -static int -rb_is_commit(struct ring_buffer_per_cpu *cpu_buffer, - struct ring_buffer_event *event) +static inline int +rb_event_is_commit(struct ring_buffer_per_cpu *cpu_buffer, + struct ring_buffer_event *event) { unsigned long addr = (unsigned long)event; unsigned long index; @@ -1005,31 +1020,6 @@ rb_is_commit(struct ring_buffer_per_cpu *cpu_buffer, rb_commit_index(cpu_buffer) == index; } -static void -rb_set_commit_event(struct ring_buffer_per_cpu *cpu_buffer, - struct ring_buffer_event *event) -{ - unsigned long addr = (unsigned long)event; - unsigned long index; - - index = rb_event_index(event); - addr &= PAGE_MASK; - - while (cpu_buffer->commit_page->page != (void *)addr) { - if (RB_WARN_ON(cpu_buffer, - cpu_buffer->commit_page == cpu_buffer->tail_page)) - return; - cpu_buffer->commit_page->page->commit = - cpu_buffer->commit_page->write; - rb_inc_page(cpu_buffer, &cpu_buffer->commit_page); - cpu_buffer->write_stamp = - cpu_buffer->commit_page->page->time_stamp; - } - - /* Now set the commit to the event's index */ - local_set(&cpu_buffer->commit_page->page->commit, index); -} - static void rb_set_commit_to_write(struct ring_buffer_per_cpu *cpu_buffer) { @@ -1110,28 +1100,21 @@ static void rb_update_event(struct ring_buffer_event *event, unsigned type, unsigned length) { - event->type = type; + event->type_len = type; switch (type) { case RINGBUF_TYPE_PADDING: - break; - case RINGBUF_TYPE_TIME_EXTEND: - event->len = DIV_ROUND_UP(RB_LEN_TIME_EXTEND, RB_ALIGNMENT); - break; - case RINGBUF_TYPE_TIME_STAMP: - event->len = DIV_ROUND_UP(RB_LEN_TIME_STAMP, RB_ALIGNMENT); break; - case RINGBUF_TYPE_DATA: + case 0: length -= RB_EVNT_HDR_SIZE; - if (length > RB_MAX_SMALL_DATA) { - event->len = 0; + if (length > RB_MAX_SMALL_DATA) event->array[0] = length; - } else - event->len = DIV_ROUND_UP(length, RB_ALIGNMENT); + else + event->type_len = DIV_ROUND_UP(length, RB_ALIGNMENT); break; default: BUG(); @@ -1155,16 +1138,178 @@ static unsigned rb_calculate_event_length(unsigned length) return length; } +static inline void +rb_reset_tail(struct ring_buffer_per_cpu *cpu_buffer, + struct buffer_page *tail_page, + unsigned long tail, unsigned long length) +{ + struct ring_buffer_event *event; + + /* + * Only the event that crossed the page boundary + * must fill the old tail_page with padding. + */ + if (tail >= BUF_PAGE_SIZE) { + local_sub(length, &tail_page->write); + return; + } + + event = __rb_page_index(tail_page, tail); + kmemcheck_annotate_bitfield(event, bitfield); + + /* + * If this event is bigger than the minimum size, then + * we need to be careful that we don't subtract the + * write counter enough to allow another writer to slip + * in on this page. + * We put in a discarded commit instead, to make sure + * that this space is not used again. + * + * If we are less than the minimum size, we don't need to + * worry about it. + */ + if (tail > (BUF_PAGE_SIZE - RB_EVNT_MIN_SIZE)) { + /* No room for any events */ + + /* Mark the rest of the page with padding */ + rb_event_set_padding(event); + + /* Set the write back to the previous setting */ + local_sub(length, &tail_page->write); + return; + } + + /* Put in a discarded event */ + event->array[0] = (BUF_PAGE_SIZE - tail) - RB_EVNT_HDR_SIZE; + event->type_len = RINGBUF_TYPE_PADDING; + /* time delta must be non zero */ + event->time_delta = 1; + /* Account for this as an entry */ + local_inc(&tail_page->entries); + local_inc(&cpu_buffer->entries); + + /* Set write to end of buffer */ + length = (tail + length) - BUF_PAGE_SIZE; + local_sub(length, &tail_page->write); +} + +static struct ring_buffer_event * +rb_move_tail(struct ring_buffer_per_cpu *cpu_buffer, + unsigned long length, unsigned long tail, + struct buffer_page *commit_page, + struct buffer_page *tail_page, u64 *ts) +{ + struct buffer_page *next_page, *head_page, *reader_page; + struct ring_buffer *buffer = cpu_buffer->buffer; + bool lock_taken = false; + unsigned long flags; + + next_page = tail_page; + + local_irq_save(flags); + /* + * Since the write to the buffer is still not + * fully lockless, we must be careful with NMIs. + * The locks in the writers are taken when a write + * crosses to a new page. The locks protect against + * races with the readers (this will soon be fixed + * with a lockless solution). + * + * Because we can not protect against NMIs, and we + * want to keep traces reentrant, we need to manage + * what happens when we are in an NMI. + * + * NMIs can happen after we take the lock. + * If we are in an NMI, only take the lock + * if it is not already taken. Otherwise + * simply fail. + */ + if (unlikely(in_nmi())) { + if (!__raw_spin_trylock(&cpu_buffer->lock)) { + cpu_buffer->nmi_dropped++; + goto out_reset; + } + } else + __raw_spin_lock(&cpu_buffer->lock); + + lock_taken = true; + + rb_inc_page(cpu_buffer, &next_page); + + head_page = cpu_buffer->head_page; + reader_page = cpu_buffer->reader_page; + + /* we grabbed the lock before incrementing */ + if (RB_WARN_ON(cpu_buffer, next_page == reader_page)) + goto out_reset; + + /* + * If for some reason, we had an interrupt storm that made + * it all the way around the buffer, bail, and warn + * about it. + */ + if (unlikely(next_page == commit_page)) { + cpu_buffer->commit_overrun++; + goto out_reset; + } + + if (next_page == head_page) { + if (!(buffer->flags & RB_FL_OVERWRITE)) + goto out_reset; + + /* tail_page has not moved yet? */ + if (tail_page == cpu_buffer->tail_page) { + /* count overflows */ + cpu_buffer->overrun += + local_read(&head_page->entries); + + rb_inc_page(cpu_buffer, &head_page); + cpu_buffer->head_page = head_page; + cpu_buffer->head_page->read = 0; + } + } + + /* + * If the tail page is still the same as what we think + * it is, then it is up to us to update the tail + * pointer. + */ + if (tail_page == cpu_buffer->tail_page) { + local_set(&next_page->write, 0); + local_set(&next_page->entries, 0); + local_set(&next_page->page->commit, 0); + cpu_buffer->tail_page = next_page; + + /* reread the time stamp */ + *ts = rb_time_stamp(buffer, cpu_buffer->cpu); + cpu_buffer->tail_page->page->time_stamp = *ts; + } + + rb_reset_tail(cpu_buffer, tail_page, tail, length); + + __raw_spin_unlock(&cpu_buffer->lock); + local_irq_restore(flags); + + /* fail and let the caller try again */ + return ERR_PTR(-EAGAIN); + + out_reset: + /* reset write */ + rb_reset_tail(cpu_buffer, tail_page, tail, length); + + if (likely(lock_taken)) + __raw_spin_unlock(&cpu_buffer->lock); + local_irq_restore(flags); + return NULL; +} + static struct ring_buffer_event * __rb_reserve_next(struct ring_buffer_per_cpu *cpu_buffer, unsigned type, unsigned long length, u64 *ts) { - struct buffer_page *tail_page, *head_page, *reader_page, *commit_page; - unsigned long tail, write; - struct ring_buffer *buffer = cpu_buffer->buffer; + struct buffer_page *tail_page, *commit_page; struct ring_buffer_event *event; - unsigned long flags; - bool lock_taken = false; + unsigned long tail, write; commit_page = cpu_buffer->commit_page; /* we just need to protect against interrupts */ @@ -1174,139 +1319,60 @@ __rb_reserve_next(struct ring_buffer_per_cpu *cpu_buffer, tail = write - length; /* See if we shot pass the end of this buffer page */ - if (write > BUF_PAGE_SIZE) { - struct buffer_page *next_page = tail_page; - - local_irq_save(flags); - /* - * Since the write to the buffer is still not - * fully lockless, we must be careful with NMIs. - * The locks in the writers are taken when a write - * crosses to a new page. The locks protect against - * races with the readers (this will soon be fixed - * with a lockless solution). - * - * Because we can not protect against NMIs, and we - * want to keep traces reentrant, we need to manage - * what happens when we are in an NMI. - * - * NMIs can happen after we take the lock. - * If we are in an NMI, only take the lock - * if it is not already taken. Otherwise - * simply fail. - */ - if (unlikely(in_nmi())) { - if (!__raw_spin_trylock(&cpu_buffer->lock)) - goto out_reset; - } else - __raw_spin_lock(&cpu_buffer->lock); - - lock_taken = true; - - rb_inc_page(cpu_buffer, &next_page); - - head_page = cpu_buffer->head_page; - reader_page = cpu_buffer->reader_page; - - /* we grabbed the lock before incrementing */ - if (RB_WARN_ON(cpu_buffer, next_page == reader_page)) - goto out_reset; - - /* - * If for some reason, we had an interrupt storm that made - * it all the way around the buffer, bail, and warn - * about it. - */ - if (unlikely(next_page == commit_page)) { - WARN_ON_ONCE(1); - goto out_reset; - } - - if (next_page == head_page) { - if (!(buffer->flags & RB_FL_OVERWRITE)) - goto out_reset; - - /* tail_page has not moved yet? */ - if (tail_page == cpu_buffer->tail_page) { - /* count overflows */ - rb_update_overflow(cpu_buffer); - - rb_inc_page(cpu_buffer, &head_page); - cpu_buffer->head_page = head_page; - cpu_buffer->head_page->read = 0; - } - } - - /* - * If the tail page is still the same as what we think - * it is, then it is up to us to update the tail - * pointer. - */ - if (tail_page == cpu_buffer->tail_page) { - local_set(&next_page->write, 0); - local_set(&next_page->page->commit, 0); - cpu_buffer->tail_page = next_page; - - /* reread the time stamp */ - *ts = ring_buffer_time_stamp(buffer, cpu_buffer->cpu); - cpu_buffer->tail_page->page->time_stamp = *ts; - } - - /* - * The actual tail page has moved forward. - */ - if (tail < BUF_PAGE_SIZE) { - /* Mark the rest of the page with padding */ - event = __rb_page_index(tail_page, tail); - rb_event_set_padding(event); - } - - if (tail <= BUF_PAGE_SIZE) - /* Set the write back to the previous setting */ - local_set(&tail_page->write, tail); - - /* - * If this was a commit entry that failed, - * increment that too - */ - if (tail_page == cpu_buffer->commit_page && - tail == rb_commit_index(cpu_buffer)) { - rb_set_commit_to_write(cpu_buffer); - } - - __raw_spin_unlock(&cpu_buffer->lock); - local_irq_restore(flags); - - /* fail and let the caller try again */ - return ERR_PTR(-EAGAIN); - } + if (write > BUF_PAGE_SIZE) + return rb_move_tail(cpu_buffer, length, tail, + commit_page, tail_page, ts); /* We reserved something on the buffer */ - if (RB_WARN_ON(cpu_buffer, write > BUF_PAGE_SIZE)) - return NULL; - event = __rb_page_index(tail_page, tail); + kmemcheck_annotate_bitfield(event, bitfield); rb_update_event(event, type, length); + /* The passed in type is zero for DATA */ + if (likely(!type)) + local_inc(&tail_page->entries); + /* - * If this is a commit and the tail is zero, then update - * this page's time stamp. + * If this is the first commit on the page, then update + * its timestamp. */ - if (!tail && rb_is_commit(cpu_buffer, event)) - cpu_buffer->commit_page->page->time_stamp = *ts; + if (!tail) + tail_page->page->time_stamp = *ts; return event; +} - out_reset: - /* reset write */ - if (tail <= BUF_PAGE_SIZE) - local_set(&tail_page->write, tail); +static inline int +rb_try_to_discard(struct ring_buffer_per_cpu *cpu_buffer, + struct ring_buffer_event *event) +{ + unsigned long new_index, old_index; + struct buffer_page *bpage; + unsigned long index; + unsigned long addr; - if (likely(lock_taken)) - __raw_spin_unlock(&cpu_buffer->lock); - local_irq_restore(flags); - return NULL; + new_index = rb_event_index(event); + old_index = new_index + rb_event_length(event); + addr = (unsigned long)event; + addr &= PAGE_MASK; + + bpage = cpu_buffer->tail_page; + + if (bpage->page == (void *)addr && rb_page_write(bpage) == old_index) { + /* + * This is on the tail page. It is possible that + * a write could come in and move the tail page + * and write to the next page. That is fine + * because we just shorten what is on this page. + */ + index = local_cmpxchg(&bpage->write, old_index, new_index); + if (index == old_index) + return 1; + } + + /* could not discard */ + return 0; } static int @@ -1341,26 +1407,33 @@ rb_add_time_stamp(struct ring_buffer_per_cpu *cpu_buffer, return -EAGAIN; /* Only a commited time event can update the write stamp */ - if (rb_is_commit(cpu_buffer, event)) { + if (rb_event_is_commit(cpu_buffer, event)) { /* - * If this is the first on the page, then we need to - * update the page itself, and just put in a zero. + * If this is the first on the page, then it was + * updated with the page itself. Try to discard it + * and if we can't just make it zero. */ if (rb_event_index(event)) { event->time_delta = *delta & TS_MASK; event->array[0] = *delta >> TS_SHIFT; } else { - cpu_buffer->commit_page->page->time_stamp = *ts; - event->time_delta = 0; - event->array[0] = 0; + /* try to discard, since we do not need this */ + if (!rb_try_to_discard(cpu_buffer, event)) { + /* nope, just zero it */ + event->time_delta = 0; + event->array[0] = 0; + } } cpu_buffer->write_stamp = *ts; /* let the caller know this was the commit */ ret = 1; } else { - /* Darn, this is just wasted space */ - event->time_delta = 0; - event->array[0] = 0; + /* Try to discard the event */ + if (!rb_try_to_discard(cpu_buffer, event)) { + /* Darn, this is just wasted space */ + event->time_delta = 0; + event->array[0] = 0; + } ret = 0; } @@ -1369,15 +1442,56 @@ rb_add_time_stamp(struct ring_buffer_per_cpu *cpu_buffer, return ret; } +static void rb_start_commit(struct ring_buffer_per_cpu *cpu_buffer) +{ + local_inc(&cpu_buffer->committing); + local_inc(&cpu_buffer->commits); +} + +static void rb_end_commit(struct ring_buffer_per_cpu *cpu_buffer) +{ + unsigned long commits; + + if (RB_WARN_ON(cpu_buffer, + !local_read(&cpu_buffer->committing))) + return; + + again: + commits = local_read(&cpu_buffer->commits); + /* synchronize with interrupts */ + barrier(); + if (local_read(&cpu_buffer->committing) == 1) + rb_set_commit_to_write(cpu_buffer); + + local_dec(&cpu_buffer->committing); + + /* synchronize with interrupts */ + barrier(); + + /* + * Need to account for interrupts coming in between the + * updating of the commit page and the clearing of the + * committing counter. + */ + if (unlikely(local_read(&cpu_buffer->commits) != commits) && + !local_read(&cpu_buffer->committing)) { + local_inc(&cpu_buffer->committing); + goto again; + } +} + static struct ring_buffer_event * rb_reserve_next_event(struct ring_buffer_per_cpu *cpu_buffer, - unsigned type, unsigned long length) + unsigned long length) { struct ring_buffer_event *event; - u64 ts, delta; + u64 ts, delta = 0; int commit = 0; int nr_loops = 0; + rb_start_commit(cpu_buffer); + + length = rb_calculate_event_length(length); again: /* * We allow for interrupts to reenter here and do a trace. @@ -1389,9 +1503,9 @@ rb_reserve_next_event(struct ring_buffer_per_cpu *cpu_buffer, * Bail! */ if (RB_WARN_ON(cpu_buffer, ++nr_loops > 1000)) - return NULL; + goto out_fail; - ts = ring_buffer_time_stamp(cpu_buffer->buffer, cpu_buffer->cpu); + ts = rb_time_stamp(cpu_buffer->buffer, cpu_buffer->cpu); /* * Only the first commit can update the timestamp. @@ -1401,61 +1515,82 @@ rb_reserve_next_event(struct ring_buffer_per_cpu *cpu_buffer, * also be made. But only the entry that did the actual * commit will be something other than zero. */ - if (cpu_buffer->tail_page == cpu_buffer->commit_page && - rb_page_write(cpu_buffer->tail_page) == - rb_commit_index(cpu_buffer)) { + if (likely(cpu_buffer->tail_page == cpu_buffer->commit_page && + rb_page_write(cpu_buffer->tail_page) == + rb_commit_index(cpu_buffer))) { + u64 diff; - delta = ts - cpu_buffer->write_stamp; + diff = ts - cpu_buffer->write_stamp; - /* make sure this delta is calculated here */ + /* make sure this diff is calculated here */ barrier(); /* Did the write stamp get updated already? */ if (unlikely(ts < cpu_buffer->write_stamp)) - delta = 0; + goto get_event; - if (test_time_stamp(delta)) { + delta = diff; + if (unlikely(test_time_stamp(delta))) { commit = rb_add_time_stamp(cpu_buffer, &ts, &delta); - if (commit == -EBUSY) - return NULL; + goto out_fail; if (commit == -EAGAIN) goto again; RB_WARN_ON(cpu_buffer, commit < 0); } - } else - /* Non commits have zero deltas */ - delta = 0; - - event = __rb_reserve_next(cpu_buffer, type, length, &ts); - if (PTR_ERR(event) == -EAGAIN) - goto again; - - if (!event) { - if (unlikely(commit)) - /* - * Ouch! We needed a timestamp and it was commited. But - * we didn't get our event reserved. - */ - rb_set_commit_to_write(cpu_buffer); - return NULL; } - /* - * If the timestamp was commited, make the commit our entry - * now so that we will update it when needed. - */ - if (commit) - rb_set_commit_event(cpu_buffer, event); - else if (!rb_is_commit(cpu_buffer, event)) + get_event: + event = __rb_reserve_next(cpu_buffer, 0, length, &ts); + if (unlikely(PTR_ERR(event) == -EAGAIN)) + goto again; + + if (!event) + goto out_fail; + + if (!rb_event_is_commit(cpu_buffer, event)) delta = 0; event->time_delta = delta; return event; + + out_fail: + rb_end_commit(cpu_buffer); + return NULL; +} + +#define TRACE_RECURSIVE_DEPTH 16 + +static int trace_recursive_lock(void) +{ + current->trace_recursion++; + + if (likely(current->trace_recursion < TRACE_RECURSIVE_DEPTH)) + return 0; + + /* Disable all tracing before we do anything else */ + tracing_off_permanent(); + + printk_once(KERN_WARNING "Tracing recursion: depth[%ld]:" + "HC[%lu]:SC[%lu]:NMI[%lu]\n", + current->trace_recursion, + hardirq_count() >> HARDIRQ_SHIFT, + softirq_count() >> SOFTIRQ_SHIFT, + in_nmi()); + + WARN_ON_ONCE(1); + return -1; +} + +static void trace_recursive_unlock(void) +{ + WARN_ON_ONCE(!current->trace_recursion); + + current->trace_recursion--; } static DEFINE_PER_CPU(int, rb_need_resched); @@ -1491,6 +1626,9 @@ ring_buffer_lock_reserve(struct ring_buffer *buffer, unsigned long length) /* If we are tracing schedule, we don't want to recurse */ resched = ftrace_preempt_disable(); + if (trace_recursive_lock()) + goto out_nocheck; + cpu = raw_smp_processor_id(); if (!cpumask_test_cpu(cpu, buffer->cpumask)) @@ -1501,11 +1639,10 @@ ring_buffer_lock_reserve(struct ring_buffer *buffer, unsigned long length) if (atomic_read(&cpu_buffer->record_disabled)) goto out; - length = rb_calculate_event_length(length); - if (length > BUF_PAGE_SIZE) + if (length > BUF_MAX_DATA_SIZE) goto out; - event = rb_reserve_next_event(cpu_buffer, RINGBUF_TYPE_DATA, length); + event = rb_reserve_next_event(cpu_buffer, length); if (!event) goto out; @@ -1520,6 +1657,9 @@ ring_buffer_lock_reserve(struct ring_buffer *buffer, unsigned long length) return event; out: + trace_recursive_unlock(); + + out_nocheck: ftrace_preempt_enable(resched); return NULL; } @@ -1528,15 +1668,16 @@ EXPORT_SYMBOL_GPL(ring_buffer_lock_reserve); static void rb_commit(struct ring_buffer_per_cpu *cpu_buffer, struct ring_buffer_event *event) { - cpu_buffer->entries++; + local_inc(&cpu_buffer->entries); - /* Only process further if we own the commit */ - if (!rb_is_commit(cpu_buffer, event)) - return; + /* + * The event first in the commit queue updates the + * time stamp. + */ + if (rb_event_is_commit(cpu_buffer, event)) + cpu_buffer->write_stamp += event->time_delta; - cpu_buffer->write_stamp += event->time_delta; - - rb_set_commit_to_write(cpu_buffer); + rb_end_commit(cpu_buffer); } /** @@ -1558,6 +1699,8 @@ int ring_buffer_unlock_commit(struct ring_buffer *buffer, rb_commit(cpu_buffer, event); + trace_recursive_unlock(); + /* * Only the last preempt count needs to restore preemption. */ @@ -1570,6 +1713,93 @@ int ring_buffer_unlock_commit(struct ring_buffer *buffer, } EXPORT_SYMBOL_GPL(ring_buffer_unlock_commit); +static inline void rb_event_discard(struct ring_buffer_event *event) +{ + /* array[0] holds the actual length for the discarded event */ + event->array[0] = rb_event_data_length(event) - RB_EVNT_HDR_SIZE; + event->type_len = RINGBUF_TYPE_PADDING; + /* time delta must be non zero */ + if (!event->time_delta) + event->time_delta = 1; +} + +/** + * ring_buffer_event_discard - discard any event in the ring buffer + * @event: the event to discard + * + * Sometimes a event that is in the ring buffer needs to be ignored. + * This function lets the user discard an event in the ring buffer + * and then that event will not be read later. + * + * Note, it is up to the user to be careful with this, and protect + * against races. If the user discards an event that has been consumed + * it is possible that it could corrupt the ring buffer. + */ +void ring_buffer_event_discard(struct ring_buffer_event *event) +{ + rb_event_discard(event); +} +EXPORT_SYMBOL_GPL(ring_buffer_event_discard); + +/** + * ring_buffer_commit_discard - discard an event that has not been committed + * @buffer: the ring buffer + * @event: non committed event to discard + * + * This is similar to ring_buffer_event_discard but must only be + * performed on an event that has not been committed yet. The difference + * is that this will also try to free the event from the ring buffer + * if another event has not been added behind it. + * + * If another event has been added behind it, it will set the event + * up as discarded, and perform the commit. + * + * If this function is called, do not call ring_buffer_unlock_commit on + * the event. + */ +void ring_buffer_discard_commit(struct ring_buffer *buffer, + struct ring_buffer_event *event) +{ + struct ring_buffer_per_cpu *cpu_buffer; + int cpu; + + /* The event is discarded regardless */ + rb_event_discard(event); + + cpu = smp_processor_id(); + cpu_buffer = buffer->buffers[cpu]; + + /* + * This must only be called if the event has not been + * committed yet. Thus we can assume that preemption + * is still disabled. + */ + RB_WARN_ON(buffer, !local_read(&cpu_buffer->committing)); + + if (!rb_try_to_discard(cpu_buffer, event)) + goto out; + + /* + * The commit is still visible by the reader, so we + * must increment entries. + */ + local_inc(&cpu_buffer->entries); + out: + rb_end_commit(cpu_buffer); + + trace_recursive_unlock(); + + /* + * Only the last preempt count needs to restore preemption. + */ + if (preempt_count() == 1) + ftrace_preempt_enable(per_cpu(rb_need_resched, cpu)); + else + preempt_enable_no_resched_notrace(); + +} +EXPORT_SYMBOL_GPL(ring_buffer_discard_commit); + /** * ring_buffer_write - write data to the buffer without reserving * @buffer: The ring buffer to write to. @@ -1589,7 +1819,6 @@ int ring_buffer_write(struct ring_buffer *buffer, { struct ring_buffer_per_cpu *cpu_buffer; struct ring_buffer_event *event; - unsigned long event_length; void *body; int ret = -EBUSY; int cpu, resched; @@ -1612,9 +1841,10 @@ int ring_buffer_write(struct ring_buffer *buffer, if (atomic_read(&cpu_buffer->record_disabled)) goto out; - event_length = rb_calculate_event_length(length); - event = rb_reserve_next_event(cpu_buffer, - RINGBUF_TYPE_DATA, event_length); + if (length > BUF_MAX_DATA_SIZE) + goto out; + + event = rb_reserve_next_event(cpu_buffer, length); if (!event) goto out; @@ -1728,7 +1958,8 @@ unsigned long ring_buffer_entries_cpu(struct ring_buffer *buffer, int cpu) return 0; cpu_buffer = buffer->buffers[cpu]; - ret = cpu_buffer->entries; + ret = (local_read(&cpu_buffer->entries) - cpu_buffer->overrun) + - cpu_buffer->read; return ret; } @@ -1754,6 +1985,47 @@ unsigned long ring_buffer_overrun_cpu(struct ring_buffer *buffer, int cpu) } EXPORT_SYMBOL_GPL(ring_buffer_overrun_cpu); +/** + * ring_buffer_nmi_dropped_cpu - get the number of nmis that were dropped + * @buffer: The ring buffer + * @cpu: The per CPU buffer to get the number of overruns from + */ +unsigned long ring_buffer_nmi_dropped_cpu(struct ring_buffer *buffer, int cpu) +{ + struct ring_buffer_per_cpu *cpu_buffer; + unsigned long ret; + + if (!cpumask_test_cpu(cpu, buffer->cpumask)) + return 0; + + cpu_buffer = buffer->buffers[cpu]; + ret = cpu_buffer->nmi_dropped; + + return ret; +} +EXPORT_SYMBOL_GPL(ring_buffer_nmi_dropped_cpu); + +/** + * ring_buffer_commit_overrun_cpu - get the number of overruns caused by commits + * @buffer: The ring buffer + * @cpu: The per CPU buffer to get the number of overruns from + */ +unsigned long +ring_buffer_commit_overrun_cpu(struct ring_buffer *buffer, int cpu) +{ + struct ring_buffer_per_cpu *cpu_buffer; + unsigned long ret; + + if (!cpumask_test_cpu(cpu, buffer->cpumask)) + return 0; + + cpu_buffer = buffer->buffers[cpu]; + ret = cpu_buffer->commit_overrun; + + return ret; +} +EXPORT_SYMBOL_GPL(ring_buffer_commit_overrun_cpu); + /** * ring_buffer_entries - get the number of entries in a buffer * @buffer: The ring buffer @@ -1770,7 +2042,8 @@ unsigned long ring_buffer_entries(struct ring_buffer *buffer) /* if you care about this being correct, lock the buffer */ for_each_buffer_cpu(buffer, cpu) { cpu_buffer = buffer->buffers[cpu]; - entries += cpu_buffer->entries; + entries += (local_read(&cpu_buffer->entries) - + cpu_buffer->overrun) - cpu_buffer->read; } return entries; @@ -1862,7 +2135,7 @@ rb_update_read_stamp(struct ring_buffer_per_cpu *cpu_buffer, { u64 delta; - switch (event->type) { + switch (event->type_len) { case RINGBUF_TYPE_PADDING: return; @@ -1893,7 +2166,7 @@ rb_update_iter_read_stamp(struct ring_buffer_iter *iter, { u64 delta; - switch (event->type) { + switch (event->type_len) { case RINGBUF_TYPE_PADDING: return; @@ -1966,6 +2239,7 @@ rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer) cpu_buffer->reader_page->list.prev = reader->list.prev; local_set(&cpu_buffer->reader_page->write, 0); + local_set(&cpu_buffer->reader_page->entries, 0); local_set(&cpu_buffer->reader_page->page->commit, 0); /* Make the reader page now replace the head */ @@ -2008,8 +2282,9 @@ static void rb_advance_reader(struct ring_buffer_per_cpu *cpu_buffer) event = rb_reader_event(cpu_buffer); - if (event->type == RINGBUF_TYPE_DATA || rb_discarded_event(event)) - cpu_buffer->entries--; + if (event->type_len <= RINGBUF_TYPE_DATA_TYPE_LEN_MAX + || rb_discarded_event(event)) + cpu_buffer->read++; rb_update_read_stamp(cpu_buffer, event); @@ -2031,8 +2306,8 @@ static void rb_advance_iter(struct ring_buffer_iter *iter) * Check if we are at the end of the buffer. */ if (iter->head >= rb_page_size(iter->head_page)) { - if (RB_WARN_ON(buffer, - iter->head_page == cpu_buffer->commit_page)) + /* discarded commits can make the page empty */ + if (iter->head_page == cpu_buffer->commit_page) return; rb_inc_iter(iter); return; @@ -2075,12 +2350,10 @@ rb_buffer_peek(struct ring_buffer *buffer, int cpu, u64 *ts) /* * We repeat when a timestamp is encountered. It is possible * to get multiple timestamps from an interrupt entering just - * as one timestamp is about to be written. The max times - * that this can happen is the number of nested interrupts we - * can have. Nesting 10 deep of interrupts is clearly - * an anomaly. + * as one timestamp is about to be written, or from discarded + * commits. The most that we can have is the number on a single page. */ - if (RB_WARN_ON(cpu_buffer, ++nr_loops > 10)) + if (RB_WARN_ON(cpu_buffer, ++nr_loops > RB_TIMESTAMPS_PER_PAGE)) return NULL; reader = rb_get_reader_page(cpu_buffer); @@ -2089,7 +2362,7 @@ rb_buffer_peek(struct ring_buffer *buffer, int cpu, u64 *ts) event = rb_reader_event(cpu_buffer); - switch (event->type) { + switch (event->type_len) { case RINGBUF_TYPE_PADDING: if (rb_null_event(event)) RB_WARN_ON(cpu_buffer, 1); @@ -2146,14 +2419,14 @@ rb_iter_peek(struct ring_buffer_iter *iter, u64 *ts) again: /* - * We repeat when a timestamp is encountered. It is possible - * to get multiple timestamps from an interrupt entering just - * as one timestamp is about to be written. The max times - * that this can happen is the number of nested interrupts we - * can have. Nesting 10 deep of interrupts is clearly - * an anomaly. + * We repeat when a timestamp is encountered. + * We can get multiple timestamps by nested interrupts or also + * if filtering is on (discarding commits). Since discarding + * commits can be frequent we can get a lot of timestamps. + * But we limit them by not adding timestamps if they begin + * at the start of a page. */ - if (RB_WARN_ON(cpu_buffer, ++nr_loops > 10)) + if (RB_WARN_ON(cpu_buffer, ++nr_loops > RB_TIMESTAMPS_PER_PAGE)) return NULL; if (rb_per_cpu_empty(cpu_buffer)) @@ -2161,7 +2434,7 @@ rb_iter_peek(struct ring_buffer_iter *iter, u64 *ts) event = rb_iter_head_event(iter); - switch (event->type) { + switch (event->type_len) { case RINGBUF_TYPE_PADDING: if (rb_null_event(event)) { rb_inc_iter(iter); @@ -2196,6 +2469,21 @@ rb_iter_peek(struct ring_buffer_iter *iter, u64 *ts) } EXPORT_SYMBOL_GPL(ring_buffer_iter_peek); +static inline int rb_ok_to_lock(void) +{ + /* + * If an NMI die dumps out the content of the ring buffer + * do not grab locks. We also permanently disable the ring + * buffer too. A one time deal is all you get from reading + * the ring buffer from an NMI. + */ + if (likely(!in_nmi() && !oops_in_progress)) + return 1; + + tracing_off_permanent(); + return 0; +} + /** * ring_buffer_peek - peek at the next event to be read * @buffer: The ring buffer to read @@ -2211,16 +2499,22 @@ ring_buffer_peek(struct ring_buffer *buffer, int cpu, u64 *ts) struct ring_buffer_per_cpu *cpu_buffer = buffer->buffers[cpu]; struct ring_buffer_event *event; unsigned long flags; + int dolock; if (!cpumask_test_cpu(cpu, buffer->cpumask)) return NULL; + dolock = rb_ok_to_lock(); again: - spin_lock_irqsave(&cpu_buffer->reader_lock, flags); + local_irq_save(flags); + if (dolock) + spin_lock(&cpu_buffer->reader_lock); event = rb_buffer_peek(buffer, cpu, ts); - spin_unlock_irqrestore(&cpu_buffer->reader_lock, flags); + if (dolock) + spin_unlock(&cpu_buffer->reader_lock); + local_irq_restore(flags); - if (event && event->type == RINGBUF_TYPE_PADDING) { + if (event && event->type_len == RINGBUF_TYPE_PADDING) { cpu_relax(); goto again; } @@ -2248,7 +2542,7 @@ ring_buffer_iter_peek(struct ring_buffer_iter *iter, u64 *ts) event = rb_iter_peek(iter, ts); spin_unlock_irqrestore(&cpu_buffer->reader_lock, flags); - if (event && event->type == RINGBUF_TYPE_PADDING) { + if (event && event->type_len == RINGBUF_TYPE_PADDING) { cpu_relax(); goto again; } @@ -2270,6 +2564,9 @@ ring_buffer_consume(struct ring_buffer *buffer, int cpu, u64 *ts) struct ring_buffer_per_cpu *cpu_buffer; struct ring_buffer_event *event = NULL; unsigned long flags; + int dolock; + + dolock = rb_ok_to_lock(); again: /* might be called in atomic */ @@ -2279,7 +2576,9 @@ ring_buffer_consume(struct ring_buffer *buffer, int cpu, u64 *ts) goto out; cpu_buffer = buffer->buffers[cpu]; - spin_lock_irqsave(&cpu_buffer->reader_lock, flags); + local_irq_save(flags); + if (dolock) + spin_lock(&cpu_buffer->reader_lock); event = rb_buffer_peek(buffer, cpu, ts); if (!event) @@ -2288,12 +2587,14 @@ ring_buffer_consume(struct ring_buffer *buffer, int cpu, u64 *ts) rb_advance_reader(cpu_buffer); out_unlock: - spin_unlock_irqrestore(&cpu_buffer->reader_lock, flags); + if (dolock) + spin_unlock(&cpu_buffer->reader_lock); + local_irq_restore(flags); out: preempt_enable(); - if (event && event->type == RINGBUF_TYPE_PADDING) { + if (event && event->type_len == RINGBUF_TYPE_PADDING) { cpu_relax(); goto again; } @@ -2386,7 +2687,7 @@ ring_buffer_read(struct ring_buffer_iter *iter, u64 *ts) out: spin_unlock_irqrestore(&cpu_buffer->reader_lock, flags); - if (event && event->type == RINGBUF_TYPE_PADDING) { + if (event && event->type_len == RINGBUF_TYPE_PADDING) { cpu_relax(); goto again; } @@ -2411,6 +2712,7 @@ rb_reset_cpu(struct ring_buffer_per_cpu *cpu_buffer) cpu_buffer->head_page = list_entry(cpu_buffer->pages.next, struct buffer_page, list); local_set(&cpu_buffer->head_page->write, 0); + local_set(&cpu_buffer->head_page->entries, 0); local_set(&cpu_buffer->head_page->page->commit, 0); cpu_buffer->head_page->read = 0; @@ -2420,11 +2722,17 @@ rb_reset_cpu(struct ring_buffer_per_cpu *cpu_buffer) INIT_LIST_HEAD(&cpu_buffer->reader_page->list); local_set(&cpu_buffer->reader_page->write, 0); + local_set(&cpu_buffer->reader_page->entries, 0); local_set(&cpu_buffer->reader_page->page->commit, 0); cpu_buffer->reader_page->read = 0; + cpu_buffer->nmi_dropped = 0; + cpu_buffer->commit_overrun = 0; cpu_buffer->overrun = 0; - cpu_buffer->entries = 0; + cpu_buffer->read = 0; + local_set(&cpu_buffer->entries, 0); + local_set(&cpu_buffer->committing, 0); + local_set(&cpu_buffer->commits, 0); cpu_buffer->write_stamp = 0; cpu_buffer->read_stamp = 0; @@ -2443,6 +2751,8 @@ void ring_buffer_reset_cpu(struct ring_buffer *buffer, int cpu) if (!cpumask_test_cpu(cpu, buffer->cpumask)) return; + atomic_inc(&cpu_buffer->record_disabled); + spin_lock_irqsave(&cpu_buffer->reader_lock, flags); __raw_spin_lock(&cpu_buffer->lock); @@ -2452,6 +2762,8 @@ void ring_buffer_reset_cpu(struct ring_buffer *buffer, int cpu) __raw_spin_unlock(&cpu_buffer->lock); spin_unlock_irqrestore(&cpu_buffer->reader_lock, flags); + + atomic_dec(&cpu_buffer->record_disabled); } EXPORT_SYMBOL_GPL(ring_buffer_reset_cpu); @@ -2475,12 +2787,25 @@ EXPORT_SYMBOL_GPL(ring_buffer_reset); int ring_buffer_empty(struct ring_buffer *buffer) { struct ring_buffer_per_cpu *cpu_buffer; + unsigned long flags; + int dolock; int cpu; + int ret; + + dolock = rb_ok_to_lock(); /* yes this is racy, but if you don't like the race, lock the buffer */ for_each_buffer_cpu(buffer, cpu) { cpu_buffer = buffer->buffers[cpu]; - if (!rb_per_cpu_empty(cpu_buffer)) + local_irq_save(flags); + if (dolock) + spin_lock(&cpu_buffer->reader_lock); + ret = rb_per_cpu_empty(cpu_buffer); + if (dolock) + spin_unlock(&cpu_buffer->reader_lock); + local_irq_restore(flags); + + if (!ret) return 0; } @@ -2496,14 +2821,23 @@ EXPORT_SYMBOL_GPL(ring_buffer_empty); int ring_buffer_empty_cpu(struct ring_buffer *buffer, int cpu) { struct ring_buffer_per_cpu *cpu_buffer; + unsigned long flags; + int dolock; int ret; if (!cpumask_test_cpu(cpu, buffer->cpumask)) return 1; - cpu_buffer = buffer->buffers[cpu]; - ret = rb_per_cpu_empty(cpu_buffer); + dolock = rb_ok_to_lock(); + cpu_buffer = buffer->buffers[cpu]; + local_irq_save(flags); + if (dolock) + spin_lock(&cpu_buffer->reader_lock); + ret = rb_per_cpu_empty(cpu_buffer); + if (dolock) + spin_unlock(&cpu_buffer->reader_lock); + local_irq_restore(flags); return ret; } @@ -2578,28 +2912,6 @@ out: } EXPORT_SYMBOL_GPL(ring_buffer_swap_cpu); -static void rb_remove_entries(struct ring_buffer_per_cpu *cpu_buffer, - struct buffer_data_page *bpage, - unsigned int offset) -{ - struct ring_buffer_event *event; - unsigned long head; - - __raw_spin_lock(&cpu_buffer->lock); - for (head = offset; head < local_read(&bpage->commit); - head += rb_event_length(event)) { - - event = __rb_data_page_index(bpage, head); - if (RB_WARN_ON(cpu_buffer, rb_null_event(event))) - return; - /* Only count data entries */ - if (event->type != RINGBUF_TYPE_DATA) - continue; - cpu_buffer->entries--; - } - __raw_spin_unlock(&cpu_buffer->lock); -} - /** * ring_buffer_alloc_read_page - allocate a page to read from buffer * @buffer: the buffer to allocate for. @@ -2630,6 +2942,7 @@ void *ring_buffer_alloc_read_page(struct ring_buffer *buffer) return bpage; } +EXPORT_SYMBOL_GPL(ring_buffer_alloc_read_page); /** * ring_buffer_free_read_page - free an allocated read page @@ -2642,6 +2955,7 @@ void ring_buffer_free_read_page(struct ring_buffer *buffer, void *data) { free_page((unsigned long)data); } +EXPORT_SYMBOL_GPL(ring_buffer_free_read_page); /** * ring_buffer_read_page - extract a page from the ring buffer @@ -2768,16 +3082,17 @@ int ring_buffer_read_page(struct ring_buffer *buffer, /* we copied everything to the beginning */ read = 0; } else { + /* update the entry counter */ + cpu_buffer->read += local_read(&reader->entries); + /* swap the pages */ rb_init_page(bpage); bpage = reader->page; reader->page = *data_page; local_set(&reader->write, 0); + local_set(&reader->entries, 0); reader->read = 0; *data_page = bpage; - - /* update the entry counter */ - rb_remove_entries(cpu_buffer, bpage, read); } ret = read; @@ -2787,6 +3102,7 @@ int ring_buffer_read_page(struct ring_buffer *buffer, out: return ret; } +EXPORT_SYMBOL_GPL(ring_buffer_read_page); static ssize_t rb_simple_read(struct file *filp, char __user *ubuf, @@ -2845,14 +3161,11 @@ static const struct file_operations rb_simple_fops = { static __init int rb_init_debugfs(void) { struct dentry *d_tracer; - struct dentry *entry; d_tracer = tracing_init_dentry(); - entry = debugfs_create_file("tracing_on", 0644, d_tracer, - &ring_buffer_flags, &rb_simple_fops); - if (!entry) - pr_warning("Could not create debugfs 'tracing_on' entry\n"); + trace_create_file("tracing_on", 0644, d_tracer, + &ring_buffer_flags, &rb_simple_fops); return 0; } @@ -2870,7 +3183,7 @@ static int rb_cpu_notify(struct notifier_block *self, switch (action) { case CPU_UP_PREPARE: case CPU_UP_PREPARE_FROZEN: - if (cpu_isset(cpu, *buffer->cpumask)) + if (cpumask_test_cpu(cpu, buffer->cpumask)) return NOTIFY_OK; buffer->buffers[cpu] = @@ -2881,7 +3194,7 @@ static int rb_cpu_notify(struct notifier_block *self, return NOTIFY_OK; } smp_wmb(); - cpu_set(cpu, *buffer->cpumask); + cpumask_set_cpu(cpu, buffer->cpumask); break; case CPU_DOWN_PREPARE: case CPU_DOWN_PREPARE_FROZEN: diff --git a/kernel/trace/ring_buffer_benchmark.c b/kernel/trace/ring_buffer_benchmark.c new file mode 100644 index 000000000000..573d3cc762c3 --- /dev/null +++ b/kernel/trace/ring_buffer_benchmark.c @@ -0,0 +1,419 @@ +/* + * ring buffer tester and benchmark + * + * Copyright (C) 2009 Steven Rostedt + */ +#include +#include +#include +#include +#include + +struct rb_page { + u64 ts; + local_t commit; + char data[4080]; +}; + +/* run time and sleep time in seconds */ +#define RUN_TIME 10 +#define SLEEP_TIME 10 + +/* number of events for writer to wake up the reader */ +static int wakeup_interval = 100; + +static int reader_finish; +static struct completion read_start; +static struct completion read_done; + +static struct ring_buffer *buffer; +static struct task_struct *producer; +static struct task_struct *consumer; +static unsigned long read; + +static int disable_reader; +module_param(disable_reader, uint, 0644); +MODULE_PARM_DESC(disable_reader, "only run producer"); + +static int read_events; + +static int kill_test; + +#define KILL_TEST() \ + do { \ + if (!kill_test) { \ + kill_test = 1; \ + WARN_ON(1); \ + } \ + } while (0) + +enum event_status { + EVENT_FOUND, + EVENT_DROPPED, +}; + +static enum event_status read_event(int cpu) +{ + struct ring_buffer_event *event; + int *entry; + u64 ts; + + event = ring_buffer_consume(buffer, cpu, &ts); + if (!event) + return EVENT_DROPPED; + + entry = ring_buffer_event_data(event); + if (*entry != cpu) { + KILL_TEST(); + return EVENT_DROPPED; + } + + read++; + return EVENT_FOUND; +} + +static enum event_status read_page(int cpu) +{ + struct ring_buffer_event *event; + struct rb_page *rpage; + unsigned long commit; + void *bpage; + int *entry; + int ret; + int inc; + int i; + + bpage = ring_buffer_alloc_read_page(buffer); + if (!bpage) + return EVENT_DROPPED; + + ret = ring_buffer_read_page(buffer, &bpage, PAGE_SIZE, cpu, 1); + if (ret >= 0) { + rpage = bpage; + commit = local_read(&rpage->commit); + for (i = 0; i < commit && !kill_test; i += inc) { + + if (i >= (PAGE_SIZE - offsetof(struct rb_page, data))) { + KILL_TEST(); + break; + } + + inc = -1; + event = (void *)&rpage->data[i]; + switch (event->type_len) { + case RINGBUF_TYPE_PADDING: + /* failed writes may be discarded events */ + if (!event->time_delta) + KILL_TEST(); + inc = event->array[0] + 4; + break; + case RINGBUF_TYPE_TIME_EXTEND: + inc = 8; + break; + case 0: + entry = ring_buffer_event_data(event); + if (*entry != cpu) { + KILL_TEST(); + break; + } + read++; + if (!event->array[0]) { + KILL_TEST(); + break; + } + inc = event->array[0] + 4; + break; + default: + entry = ring_buffer_event_data(event); + if (*entry != cpu) { + KILL_TEST(); + break; + } + read++; + inc = ((event->type_len + 1) * 4); + } + if (kill_test) + break; + + if (inc <= 0) { + KILL_TEST(); + break; + } + } + } + ring_buffer_free_read_page(buffer, bpage); + + if (ret < 0) + return EVENT_DROPPED; + return EVENT_FOUND; +} + +static void ring_buffer_consumer(void) +{ + /* toggle between reading pages and events */ + read_events ^= 1; + + read = 0; + while (!reader_finish && !kill_test) { + int found; + + do { + int cpu; + + found = 0; + for_each_online_cpu(cpu) { + enum event_status stat; + + if (read_events) + stat = read_event(cpu); + else + stat = read_page(cpu); + + if (kill_test) + break; + if (stat == EVENT_FOUND) + found = 1; + } + } while (found && !kill_test); + + set_current_state(TASK_INTERRUPTIBLE); + if (reader_finish) + break; + + schedule(); + __set_current_state(TASK_RUNNING); + } + reader_finish = 0; + complete(&read_done); +} + +static void ring_buffer_producer(void) +{ + struct timeval start_tv; + struct timeval end_tv; + unsigned long long time; + unsigned long long entries; + unsigned long long overruns; + unsigned long missed = 0; + unsigned long hit = 0; + unsigned long avg; + int cnt = 0; + + /* + * Hammer the buffer for 10 secs (this may + * make the system stall) + */ + trace_printk("Starting ring buffer hammer\n"); + do_gettimeofday(&start_tv); + do { + struct ring_buffer_event *event; + int *entry; + + event = ring_buffer_lock_reserve(buffer, 10); + if (!event) { + missed++; + } else { + hit++; + entry = ring_buffer_event_data(event); + *entry = smp_processor_id(); + ring_buffer_unlock_commit(buffer, event); + } + do_gettimeofday(&end_tv); + + cnt++; + if (consumer && !(cnt % wakeup_interval)) + wake_up_process(consumer); + +#ifndef CONFIG_PREEMPT + /* + * If we are a non preempt kernel, the 10 second run will + * stop everything while it runs. Instead, we will call + * cond_resched and also add any time that was lost by a + * rescedule. + * + * Do a cond resched at the same frequency we would wake up + * the reader. + */ + if (cnt % wakeup_interval) + cond_resched(); +#endif + + } while (end_tv.tv_sec < (start_tv.tv_sec + RUN_TIME) && !kill_test); + trace_printk("End ring buffer hammer\n"); + + if (consumer) { + /* Init both completions here to avoid races */ + init_completion(&read_start); + init_completion(&read_done); + /* the completions must be visible before the finish var */ + smp_wmb(); + reader_finish = 1; + /* finish var visible before waking up the consumer */ + smp_wmb(); + wake_up_process(consumer); + wait_for_completion(&read_done); + } + + time = end_tv.tv_sec - start_tv.tv_sec; + time *= USEC_PER_SEC; + time += (long long)((long)end_tv.tv_usec - (long)start_tv.tv_usec); + + entries = ring_buffer_entries(buffer); + overruns = ring_buffer_overruns(buffer); + + if (kill_test) + trace_printk("ERROR!\n"); + trace_printk("Time: %lld (usecs)\n", time); + trace_printk("Overruns: %lld\n", overruns); + if (disable_reader) + trace_printk("Read: (reader disabled)\n"); + else + trace_printk("Read: %ld (by %s)\n", read, + read_events ? "events" : "pages"); + trace_printk("Entries: %lld\n", entries); + trace_printk("Total: %lld\n", entries + overruns + read); + trace_printk("Missed: %ld\n", missed); + trace_printk("Hit: %ld\n", hit); + + /* Convert time from usecs to millisecs */ + do_div(time, USEC_PER_MSEC); + if (time) + hit /= (long)time; + else + trace_printk("TIME IS ZERO??\n"); + + trace_printk("Entries per millisec: %ld\n", hit); + + if (hit) { + /* Calculate the average time in nanosecs */ + avg = NSEC_PER_MSEC / hit; + trace_printk("%ld ns per entry\n", avg); + } + + if (missed) { + if (time) + missed /= (long)time; + + trace_printk("Total iterations per millisec: %ld\n", + hit + missed); + + /* it is possible that hit + missed will overflow and be zero */ + if (!(hit + missed)) { + trace_printk("hit + missed overflowed and totalled zero!\n"); + hit--; /* make it non zero */ + } + + /* Caculate the average time in nanosecs */ + avg = NSEC_PER_MSEC / (hit + missed); + trace_printk("%ld ns per entry\n", avg); + } +} + +static void wait_to_die(void) +{ + set_current_state(TASK_INTERRUPTIBLE); + while (!kthread_should_stop()) { + schedule(); + set_current_state(TASK_INTERRUPTIBLE); + } + __set_current_state(TASK_RUNNING); +} + +static int ring_buffer_consumer_thread(void *arg) +{ + while (!kthread_should_stop() && !kill_test) { + complete(&read_start); + + ring_buffer_consumer(); + + set_current_state(TASK_INTERRUPTIBLE); + if (kthread_should_stop() || kill_test) + break; + + schedule(); + __set_current_state(TASK_RUNNING); + } + __set_current_state(TASK_RUNNING); + + if (kill_test) + wait_to_die(); + + return 0; +} + +static int ring_buffer_producer_thread(void *arg) +{ + init_completion(&read_start); + + while (!kthread_should_stop() && !kill_test) { + ring_buffer_reset(buffer); + + if (consumer) { + smp_wmb(); + wake_up_process(consumer); + wait_for_completion(&read_start); + } + + ring_buffer_producer(); + + trace_printk("Sleeping for 10 secs\n"); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ * SLEEP_TIME); + __set_current_state(TASK_RUNNING); + } + + if (kill_test) + wait_to_die(); + + return 0; +} + +static int __init ring_buffer_benchmark_init(void) +{ + int ret; + + /* make a one meg buffer in overwite mode */ + buffer = ring_buffer_alloc(1000000, RB_FL_OVERWRITE); + if (!buffer) + return -ENOMEM; + + if (!disable_reader) { + consumer = kthread_create(ring_buffer_consumer_thread, + NULL, "rb_consumer"); + ret = PTR_ERR(consumer); + if (IS_ERR(consumer)) + goto out_fail; + } + + producer = kthread_run(ring_buffer_producer_thread, + NULL, "rb_producer"); + ret = PTR_ERR(producer); + + if (IS_ERR(producer)) + goto out_kill; + + return 0; + + out_kill: + if (consumer) + kthread_stop(consumer); + + out_fail: + ring_buffer_free(buffer); + return ret; +} + +static void __exit ring_buffer_benchmark_exit(void) +{ + kthread_stop(producer); + if (consumer) + kthread_stop(consumer); + ring_buffer_free(buffer); +} + +module_init(ring_buffer_benchmark_init); +module_exit(ring_buffer_benchmark_exit); + +MODULE_AUTHOR("Steven Rostedt"); +MODULE_DESCRIPTION("ring_buffer_benchmark"); +MODULE_LICENSE("GPL"); diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index cda81ec58d9f..076fa6f0ee48 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -171,6 +171,13 @@ static struct trace_array global_trace; static DEFINE_PER_CPU(struct trace_array_cpu, global_trace_cpu); +int filter_current_check_discard(struct ftrace_event_call *call, void *rec, + struct ring_buffer_event *event) +{ + return filter_check_discard(call, rec, global_trace.buffer, event); +} +EXPORT_SYMBOL_GPL(filter_current_check_discard); + cycle_t ftrace_now(int cpu) { u64 ts; @@ -255,7 +262,8 @@ static DECLARE_WAIT_QUEUE_HEAD(trace_wait); /* trace_flags holds trace_options default values */ unsigned long trace_flags = TRACE_ITER_PRINT_PARENT | TRACE_ITER_PRINTK | - TRACE_ITER_ANNOTATE | TRACE_ITER_CONTEXT_INFO | TRACE_ITER_SLEEP_TIME; + TRACE_ITER_ANNOTATE | TRACE_ITER_CONTEXT_INFO | TRACE_ITER_SLEEP_TIME | + TRACE_ITER_GRAPH_TIME; /** * trace_wake_up - wake up tasks waiting for trace input @@ -317,6 +325,7 @@ static const char *trace_options[] = { "latency-format", "global-clock", "sleep-time", + "graph-time", NULL }; @@ -335,7 +344,7 @@ static raw_spinlock_t ftrace_max_lock = /* * Copy the new maximum trace into the separate maximum-trace * structure. (this way the maximum trace is permanently saved, - * for later retrieval via /debugfs/tracing/latency_trace) + * for later retrieval via /sys/kernel/debug/tracing/latency_trace) */ static void __update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu) @@ -402,17 +411,6 @@ static ssize_t trace_seq_to_buffer(struct trace_seq *s, void *buf, size_t cnt) return cnt; } -static void -trace_print_seq(struct seq_file *m, struct trace_seq *s) -{ - int len = s->len >= PAGE_SIZE ? PAGE_SIZE - 1 : s->len; - - s->buffer[len] = 0; - seq_puts(m, s->buffer); - - trace_seq_init(s); -} - /** * update_max_tr - snapshot all trace buffers from global_trace to max_tr * @tr: tracer @@ -641,6 +639,16 @@ void tracing_reset_online_cpus(struct trace_array *tr) tracing_reset(tr, cpu); } +void tracing_reset_current(int cpu) +{ + tracing_reset(&global_trace, cpu); +} + +void tracing_reset_current_online_cpus(void) +{ + tracing_reset_online_cpus(&global_trace); +} + #define SAVED_CMDLINES 128 #define NO_CMDLINE_MAP UINT_MAX static unsigned map_pid_to_cmdline[PID_MAX_DEFAULT+1]; @@ -800,6 +808,7 @@ void trace_find_cmdline(int pid, char comm[]) return; } + preempt_disable(); __raw_spin_lock(&trace_cmdline_lock); map = map_pid_to_cmdline[pid]; if (map != NO_CMDLINE_MAP) @@ -808,6 +817,7 @@ void trace_find_cmdline(int pid, char comm[]) strcpy(comm, "<...>"); __raw_spin_unlock(&trace_cmdline_lock); + preempt_enable(); } void tracing_record_cmdline(struct task_struct *tsk) @@ -840,7 +850,7 @@ tracing_generic_entry_update(struct trace_entry *entry, unsigned long flags, } struct ring_buffer_event *trace_buffer_lock_reserve(struct trace_array *tr, - unsigned char type, + int type, unsigned long len, unsigned long flags, int pc) { @@ -883,30 +893,40 @@ void trace_buffer_unlock_commit(struct trace_array *tr, } struct ring_buffer_event * -trace_current_buffer_lock_reserve(unsigned char type, unsigned long len, +trace_current_buffer_lock_reserve(int type, unsigned long len, unsigned long flags, int pc) { return trace_buffer_lock_reserve(&global_trace, type, len, flags, pc); } +EXPORT_SYMBOL_GPL(trace_current_buffer_lock_reserve); void trace_current_buffer_unlock_commit(struct ring_buffer_event *event, unsigned long flags, int pc) { - return __trace_buffer_unlock_commit(&global_trace, event, flags, pc, 1); + __trace_buffer_unlock_commit(&global_trace, event, flags, pc, 1); } +EXPORT_SYMBOL_GPL(trace_current_buffer_unlock_commit); void trace_nowake_buffer_unlock_commit(struct ring_buffer_event *event, unsigned long flags, int pc) { - return __trace_buffer_unlock_commit(&global_trace, event, flags, pc, 0); + __trace_buffer_unlock_commit(&global_trace, event, flags, pc, 0); } +EXPORT_SYMBOL_GPL(trace_nowake_buffer_unlock_commit); + +void trace_current_buffer_discard_commit(struct ring_buffer_event *event) +{ + ring_buffer_discard_commit(global_trace.buffer, event); +} +EXPORT_SYMBOL_GPL(trace_current_buffer_discard_commit); void trace_function(struct trace_array *tr, unsigned long ip, unsigned long parent_ip, unsigned long flags, int pc) { + struct ftrace_event_call *call = &event_function; struct ring_buffer_event *event; struct ftrace_entry *entry; @@ -921,7 +941,9 @@ trace_function(struct trace_array *tr, entry = ring_buffer_event_data(event); entry->ip = ip; entry->parent_ip = parent_ip; - ring_buffer_unlock_commit(tr->buffer, event); + + if (!filter_check_discard(call, entry, tr->buffer, event)) + ring_buffer_unlock_commit(tr->buffer, event); } #ifdef CONFIG_FUNCTION_GRAPH_TRACER @@ -930,6 +952,7 @@ static int __trace_graph_entry(struct trace_array *tr, unsigned long flags, int pc) { + struct ftrace_event_call *call = &event_funcgraph_entry; struct ring_buffer_event *event; struct ftrace_graph_ent_entry *entry; @@ -942,7 +965,8 @@ static int __trace_graph_entry(struct trace_array *tr, return 0; entry = ring_buffer_event_data(event); entry->graph_ent = *trace; - ring_buffer_unlock_commit(global_trace.buffer, event); + if (!filter_current_check_discard(call, entry, event)) + ring_buffer_unlock_commit(global_trace.buffer, event); return 1; } @@ -952,6 +976,7 @@ static void __trace_graph_return(struct trace_array *tr, unsigned long flags, int pc) { + struct ftrace_event_call *call = &event_funcgraph_exit; struct ring_buffer_event *event; struct ftrace_graph_ret_entry *entry; @@ -964,7 +989,8 @@ static void __trace_graph_return(struct trace_array *tr, return; entry = ring_buffer_event_data(event); entry->ret = *trace; - ring_buffer_unlock_commit(global_trace.buffer, event); + if (!filter_current_check_discard(call, entry, event)) + ring_buffer_unlock_commit(global_trace.buffer, event); } #endif @@ -982,6 +1008,7 @@ static void __ftrace_trace_stack(struct trace_array *tr, int skip, int pc) { #ifdef CONFIG_STACKTRACE + struct ftrace_event_call *call = &event_kernel_stack; struct ring_buffer_event *event; struct stack_entry *entry; struct stack_trace trace; @@ -999,7 +1026,8 @@ static void __ftrace_trace_stack(struct trace_array *tr, trace.entries = entry->caller; save_stack_trace(&trace); - ring_buffer_unlock_commit(tr->buffer, event); + if (!filter_check_discard(call, entry, tr->buffer, event)) + ring_buffer_unlock_commit(tr->buffer, event); #endif } @@ -1024,6 +1052,7 @@ static void ftrace_trace_userstack(struct trace_array *tr, unsigned long flags, int pc) { #ifdef CONFIG_STACKTRACE + struct ftrace_event_call *call = &event_user_stack; struct ring_buffer_event *event; struct userstack_entry *entry; struct stack_trace trace; @@ -1045,7 +1074,8 @@ static void ftrace_trace_userstack(struct trace_array *tr, trace.entries = entry->caller; save_stack_trace_user(&trace); - ring_buffer_unlock_commit(tr->buffer, event); + if (!filter_check_discard(call, entry, tr->buffer, event)) + ring_buffer_unlock_commit(tr->buffer, event); #endif } @@ -1089,6 +1119,7 @@ tracing_sched_switch_trace(struct trace_array *tr, struct task_struct *next, unsigned long flags, int pc) { + struct ftrace_event_call *call = &event_context_switch; struct ring_buffer_event *event; struct ctx_switch_entry *entry; @@ -1104,7 +1135,9 @@ tracing_sched_switch_trace(struct trace_array *tr, entry->next_prio = next->prio; entry->next_state = next->state; entry->next_cpu = task_cpu(next); - trace_buffer_unlock_commit(tr, event, flags, pc); + + if (!filter_check_discard(call, entry, tr->buffer, event)) + trace_buffer_unlock_commit(tr, event, flags, pc); } void @@ -1113,6 +1146,7 @@ tracing_sched_wakeup_trace(struct trace_array *tr, struct task_struct *curr, unsigned long flags, int pc) { + struct ftrace_event_call *call = &event_wakeup; struct ring_buffer_event *event; struct ctx_switch_entry *entry; @@ -1129,7 +1163,8 @@ tracing_sched_wakeup_trace(struct trace_array *tr, entry->next_state = wakee->state; entry->next_cpu = task_cpu(wakee); - ring_buffer_unlock_commit(tr->buffer, event); + if (!filter_check_discard(call, entry, tr->buffer, event)) + ring_buffer_unlock_commit(tr->buffer, event); ftrace_trace_stack(tr, flags, 6, pc); ftrace_trace_userstack(tr, flags, pc); } @@ -1230,11 +1265,13 @@ int trace_vbprintk(unsigned long ip, const char *fmt, va_list args) (raw_spinlock_t)__RAW_SPIN_LOCK_UNLOCKED; static u32 trace_buf[TRACE_BUF_SIZE]; + struct ftrace_event_call *call = &event_bprint; struct ring_buffer_event *event; struct trace_array *tr = &global_trace; struct trace_array_cpu *data; struct bprint_entry *entry; unsigned long flags; + int disable; int resched; int cpu, len = 0, size, pc; @@ -1249,7 +1286,8 @@ int trace_vbprintk(unsigned long ip, const char *fmt, va_list args) cpu = raw_smp_processor_id(); data = tr->data[cpu]; - if (unlikely(atomic_read(&data->disabled))) + disable = atomic_inc_return(&data->disabled); + if (unlikely(disable != 1)) goto out; /* Lockdep uses trace_printk for lock tracing */ @@ -1269,13 +1307,15 @@ int trace_vbprintk(unsigned long ip, const char *fmt, va_list args) entry->fmt = fmt; memcpy(entry->buf, trace_buf, sizeof(u32) * len); - ring_buffer_unlock_commit(tr->buffer, event); + if (!filter_check_discard(call, entry, tr->buffer, event)) + ring_buffer_unlock_commit(tr->buffer, event); out_unlock: __raw_spin_unlock(&trace_buf_lock); local_irq_restore(flags); out: + atomic_dec_return(&data->disabled); ftrace_preempt_enable(resched); unpause_graph_tracing(); @@ -1288,12 +1328,14 @@ int trace_vprintk(unsigned long ip, const char *fmt, va_list args) static raw_spinlock_t trace_buf_lock = __RAW_SPIN_LOCK_UNLOCKED; static char trace_buf[TRACE_BUF_SIZE]; + struct ftrace_event_call *call = &event_print; struct ring_buffer_event *event; struct trace_array *tr = &global_trace; struct trace_array_cpu *data; int cpu, len = 0, size, pc; struct print_entry *entry; unsigned long irq_flags; + int disable; if (tracing_disabled || tracing_selftest_running) return 0; @@ -1303,7 +1345,8 @@ int trace_vprintk(unsigned long ip, const char *fmt, va_list args) cpu = raw_smp_processor_id(); data = tr->data[cpu]; - if (unlikely(atomic_read(&data->disabled))) + disable = atomic_inc_return(&data->disabled); + if (unlikely(disable != 1)) goto out; pause_graph_tracing(); @@ -1323,13 +1366,15 @@ int trace_vprintk(unsigned long ip, const char *fmt, va_list args) memcpy(&entry->buf, trace_buf, len); entry->buf[len] = 0; - ring_buffer_unlock_commit(tr->buffer, event); + if (!filter_check_discard(call, entry, tr->buffer, event)) + ring_buffer_unlock_commit(tr->buffer, event); out_unlock: __raw_spin_unlock(&trace_buf_lock); raw_local_irq_restore(irq_flags); unpause_graph_tracing(); out: + atomic_dec_return(&data->disabled); preempt_enable_notrace(); return len; @@ -1526,12 +1571,14 @@ static void *s_start(struct seq_file *m, loff_t *pos) p = s_next(m, p, &l); } + trace_event_read_lock(); return p; } static void s_stop(struct seq_file *m, void *p) { atomic_dec(&trace_record_cmdline_disabled); + trace_event_read_unlock(); } static void print_lat_help_header(struct seq_file *m) @@ -1774,6 +1821,7 @@ static int trace_empty(struct trace_iterator *iter) return 1; } +/* Called with trace_event_read_lock() held. */ static enum print_line_t print_trace_line(struct trace_iterator *iter) { enum print_line_t ret; @@ -2143,11 +2191,12 @@ tracing_cpumask_write(struct file *filp, const char __user *ubuf, if (!alloc_cpumask_var(&tracing_cpumask_new, GFP_KERNEL)) return -ENOMEM; - mutex_lock(&tracing_cpumask_update_lock); err = cpumask_parse_user(ubuf, count, tracing_cpumask_new); if (err) goto err_unlock; + mutex_lock(&tracing_cpumask_update_lock); + local_irq_disable(); __raw_spin_lock(&ftrace_max_lock); for_each_tracing_cpu(cpu) { @@ -2175,8 +2224,7 @@ tracing_cpumask_write(struct file *filp, const char __user *ubuf, return count; err_unlock: - mutex_unlock(&tracing_cpumask_update_lock); - free_cpumask_var(tracing_cpumask); + free_cpumask_var(tracing_cpumask_new); return err; } @@ -2366,21 +2414,20 @@ static const struct file_operations tracing_iter_fops = { static const char readme_msg[] = "tracing mini-HOWTO:\n\n" - "# mkdir /debug\n" - "# mount -t debugfs nodev /debug\n\n" - "# cat /debug/tracing/available_tracers\n" + "# mount -t debugfs nodev /sys/kernel/debug\n\n" + "# cat /sys/kernel/debug/tracing/available_tracers\n" "wakeup preemptirqsoff preemptoff irqsoff function sched_switch nop\n\n" - "# cat /debug/tracing/current_tracer\n" + "# cat /sys/kernel/debug/tracing/current_tracer\n" "nop\n" - "# echo sched_switch > /debug/tracing/current_tracer\n" - "# cat /debug/tracing/current_tracer\n" + "# echo sched_switch > /sys/kernel/debug/tracing/current_tracer\n" + "# cat /sys/kernel/debug/tracing/current_tracer\n" "sched_switch\n" - "# cat /debug/tracing/trace_options\n" + "# cat /sys/kernel/debug/tracing/trace_options\n" "noprint-parent nosym-offset nosym-addr noverbose\n" - "# echo print-parent > /debug/tracing/trace_options\n" - "# echo 1 > /debug/tracing/tracing_enabled\n" - "# cat /debug/tracing/trace > /tmp/trace.txt\n" - "# echo 0 > /debug/tracing/tracing_enabled\n" + "# echo print-parent > /sys/kernel/debug/tracing/trace_options\n" + "# echo 1 > /sys/kernel/debug/tracing/tracing_enabled\n" + "# cat /sys/kernel/debug/tracing/trace > /tmp/trace.txt\n" + "# echo 0 > /sys/kernel/debug/tracing/tracing_enabled\n" ; static ssize_t @@ -2396,6 +2443,56 @@ static const struct file_operations tracing_readme_fops = { .read = tracing_readme_read, }; +static ssize_t +tracing_saved_cmdlines_read(struct file *file, char __user *ubuf, + size_t cnt, loff_t *ppos) +{ + char *buf_comm; + char *file_buf; + char *buf; + int len = 0; + int pid; + int i; + + file_buf = kmalloc(SAVED_CMDLINES*(16+TASK_COMM_LEN), GFP_KERNEL); + if (!file_buf) + return -ENOMEM; + + buf_comm = kmalloc(TASK_COMM_LEN, GFP_KERNEL); + if (!buf_comm) { + kfree(file_buf); + return -ENOMEM; + } + + buf = file_buf; + + for (i = 0; i < SAVED_CMDLINES; i++) { + int r; + + pid = map_cmdline_to_pid[i]; + if (pid == -1 || pid == NO_CMDLINE_MAP) + continue; + + trace_find_cmdline(pid, buf_comm); + r = sprintf(buf, "%d %s\n", pid, buf_comm); + buf += r; + len += r; + } + + len = simple_read_from_buffer(ubuf, cnt, ppos, + file_buf, len); + + kfree(file_buf); + kfree(buf_comm); + + return len; +} + +static const struct file_operations tracing_saved_cmdlines_fops = { + .open = tracing_open_generic, + .read = tracing_saved_cmdlines_read, +}; + static ssize_t tracing_ctrl_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) @@ -2728,6 +2825,9 @@ static int tracing_open_pipe(struct inode *inode, struct file *filp) /* trace pipe does not show start of buffer */ cpumask_setall(iter->started); + if (trace_flags & TRACE_ITER_LATENCY_FMT) + iter->iter_flags |= TRACE_FILE_LAT_FMT; + iter->cpu_file = cpu_file; iter->tr = &global_trace; mutex_init(&iter->mutex); @@ -2915,6 +3015,7 @@ waitagain: offsetof(struct trace_iterator, seq)); iter->pos = -1; + trace_event_read_lock(); while (find_next_entry_inc(iter) != NULL) { enum print_line_t ret; int len = iter->seq.len; @@ -2931,6 +3032,7 @@ waitagain: if (iter->seq.len >= cnt) break; } + trace_event_read_unlock(); /* Now copy what we have to the user */ sret = trace_seq_to_user(&iter->seq, ubuf, cnt); @@ -3053,6 +3155,8 @@ static ssize_t tracing_splice_read_pipe(struct file *filp, goto out_err; } + trace_event_read_lock(); + /* Fill as many pages as possible. */ for (i = 0, rem = len; i < PIPE_BUFFERS && rem; i++) { pages[i] = alloc_page(GFP_KERNEL); @@ -3075,6 +3179,7 @@ static ssize_t tracing_splice_read_pipe(struct file *filp, trace_seq_init(&iter->seq); } + trace_event_read_unlock(); mutex_unlock(&iter->mutex); spd.nr_pages = i; @@ -3425,7 +3530,7 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos, .spd_release = buffer_spd_release, }; struct buffer_ref *ref; - int size, i; + int entries, size, i; size_t ret; if (*ppos & (PAGE_SIZE - 1)) { @@ -3440,7 +3545,9 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos, len &= PAGE_MASK; } - for (i = 0; i < PIPE_BUFFERS && len; i++, len -= PAGE_SIZE) { + entries = ring_buffer_entries_cpu(info->tr->buffer, info->cpu); + + for (i = 0; i < PIPE_BUFFERS && len && entries; i++, len -= PAGE_SIZE) { struct page *page; int r; @@ -3457,7 +3564,7 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos, } r = ring_buffer_read_page(ref->buffer, &ref->page, - len, info->cpu, 0); + len, info->cpu, 1); if (r < 0) { ring_buffer_free_read_page(ref->buffer, ref->page); @@ -3481,6 +3588,8 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos, spd.partial[i].private = (unsigned long)ref; spd.nr_pages++; *ppos += PAGE_SIZE; + + entries = ring_buffer_entries_cpu(info->tr->buffer, info->cpu); } spd.nr_pages = i; @@ -3508,6 +3617,45 @@ static const struct file_operations tracing_buffers_fops = { .llseek = no_llseek, }; +static ssize_t +tracing_stats_read(struct file *filp, char __user *ubuf, + size_t count, loff_t *ppos) +{ + unsigned long cpu = (unsigned long)filp->private_data; + struct trace_array *tr = &global_trace; + struct trace_seq *s; + unsigned long cnt; + + s = kmalloc(sizeof(*s), GFP_KERNEL); + if (!s) + return ENOMEM; + + trace_seq_init(s); + + cnt = ring_buffer_entries_cpu(tr->buffer, cpu); + trace_seq_printf(s, "entries: %ld\n", cnt); + + cnt = ring_buffer_overrun_cpu(tr->buffer, cpu); + trace_seq_printf(s, "overrun: %ld\n", cnt); + + cnt = ring_buffer_commit_overrun_cpu(tr->buffer, cpu); + trace_seq_printf(s, "commit overrun: %ld\n", cnt); + + cnt = ring_buffer_nmi_dropped_cpu(tr->buffer, cpu); + trace_seq_printf(s, "nmi dropped: %ld\n", cnt); + + count = simple_read_from_buffer(ubuf, count, ppos, s->buffer, s->len); + + kfree(s); + + return count; +} + +static const struct file_operations tracing_stats_fops = { + .open = tracing_open_generic, + .read = tracing_stats_read, +}; + #ifdef CONFIG_DYNAMIC_FTRACE int __weak ftrace_arch_read_dyn_info(char *buf, int size) @@ -3597,7 +3745,7 @@ struct dentry *tracing_dentry_percpu(void) static void tracing_init_debugfs_percpu(long cpu) { struct dentry *d_percpu = tracing_dentry_percpu(); - struct dentry *entry, *d_cpu; + struct dentry *d_cpu; /* strlen(cpu) + MAX(log10(cpu)) + '\0' */ char cpu_dir[7]; @@ -3612,21 +3760,18 @@ static void tracing_init_debugfs_percpu(long cpu) } /* per cpu trace_pipe */ - entry = debugfs_create_file("trace_pipe", 0444, d_cpu, - (void *) cpu, &tracing_pipe_fops); - if (!entry) - pr_warning("Could not create debugfs 'trace_pipe' entry\n"); + trace_create_file("trace_pipe", 0444, d_cpu, + (void *) cpu, &tracing_pipe_fops); /* per cpu trace */ - entry = debugfs_create_file("trace", 0644, d_cpu, - (void *) cpu, &tracing_fops); - if (!entry) - pr_warning("Could not create debugfs 'trace' entry\n"); + trace_create_file("trace", 0644, d_cpu, + (void *) cpu, &tracing_fops); - entry = debugfs_create_file("trace_pipe_raw", 0444, d_cpu, - (void *) cpu, &tracing_buffers_fops); - if (!entry) - pr_warning("Could not create debugfs 'trace_pipe_raw' entry\n"); + trace_create_file("trace_pipe_raw", 0444, d_cpu, + (void *) cpu, &tracing_buffers_fops); + + trace_create_file("stats", 0444, d_cpu, + (void *) cpu, &tracing_stats_fops); } #ifdef CONFIG_FTRACE_SELFTEST @@ -3782,6 +3927,22 @@ static const struct file_operations trace_options_core_fops = { .write = trace_options_core_write, }; +struct dentry *trace_create_file(const char *name, + mode_t mode, + struct dentry *parent, + void *data, + const struct file_operations *fops) +{ + struct dentry *ret; + + ret = debugfs_create_file(name, mode, parent, data, fops); + if (!ret) + pr_warning("Could not create debugfs '%s' entry\n", name); + + return ret; +} + + static struct dentry *trace_options_init_dentry(void) { struct dentry *d_tracer; @@ -3809,7 +3970,6 @@ create_trace_option_file(struct trace_option_dentry *topt, struct tracer_opt *opt) { struct dentry *t_options; - struct dentry *entry; t_options = trace_options_init_dentry(); if (!t_options) @@ -3818,11 +3978,9 @@ create_trace_option_file(struct trace_option_dentry *topt, topt->flags = flags; topt->opt = opt; - entry = debugfs_create_file(opt->name, 0644, t_options, topt, + topt->entry = trace_create_file(opt->name, 0644, t_options, topt, &trace_options_fops); - topt->entry = entry; - } static struct trace_option_dentry * @@ -3877,123 +4035,84 @@ static struct dentry * create_trace_option_core_file(const char *option, long index) { struct dentry *t_options; - struct dentry *entry; t_options = trace_options_init_dentry(); if (!t_options) return NULL; - entry = debugfs_create_file(option, 0644, t_options, (void *)index, + return trace_create_file(option, 0644, t_options, (void *)index, &trace_options_core_fops); - - return entry; } static __init void create_trace_options_dir(void) { struct dentry *t_options; - struct dentry *entry; int i; t_options = trace_options_init_dentry(); if (!t_options) return; - for (i = 0; trace_options[i]; i++) { - entry = create_trace_option_core_file(trace_options[i], i); - if (!entry) - pr_warning("Could not create debugfs %s entry\n", - trace_options[i]); - } + for (i = 0; trace_options[i]; i++) + create_trace_option_core_file(trace_options[i], i); } static __init int tracer_init_debugfs(void) { struct dentry *d_tracer; - struct dentry *entry; int cpu; d_tracer = tracing_init_dentry(); - entry = debugfs_create_file("tracing_enabled", 0644, d_tracer, - &global_trace, &tracing_ctrl_fops); - if (!entry) - pr_warning("Could not create debugfs 'tracing_enabled' entry\n"); + trace_create_file("tracing_enabled", 0644, d_tracer, + &global_trace, &tracing_ctrl_fops); - entry = debugfs_create_file("trace_options", 0644, d_tracer, - NULL, &tracing_iter_fops); - if (!entry) - pr_warning("Could not create debugfs 'trace_options' entry\n"); + trace_create_file("trace_options", 0644, d_tracer, + NULL, &tracing_iter_fops); - create_trace_options_dir(); + trace_create_file("tracing_cpumask", 0644, d_tracer, + NULL, &tracing_cpumask_fops); - entry = debugfs_create_file("tracing_cpumask", 0644, d_tracer, - NULL, &tracing_cpumask_fops); - if (!entry) - pr_warning("Could not create debugfs 'tracing_cpumask' entry\n"); + trace_create_file("trace", 0644, d_tracer, + (void *) TRACE_PIPE_ALL_CPU, &tracing_fops); - entry = debugfs_create_file("trace", 0644, d_tracer, - (void *) TRACE_PIPE_ALL_CPU, &tracing_fops); - if (!entry) - pr_warning("Could not create debugfs 'trace' entry\n"); + trace_create_file("available_tracers", 0444, d_tracer, + &global_trace, &show_traces_fops); - entry = debugfs_create_file("available_tracers", 0444, d_tracer, - &global_trace, &show_traces_fops); - if (!entry) - pr_warning("Could not create debugfs 'available_tracers' entry\n"); + trace_create_file("current_tracer", 0644, d_tracer, + &global_trace, &set_tracer_fops); - entry = debugfs_create_file("current_tracer", 0444, d_tracer, - &global_trace, &set_tracer_fops); - if (!entry) - pr_warning("Could not create debugfs 'current_tracer' entry\n"); + trace_create_file("tracing_max_latency", 0644, d_tracer, + &tracing_max_latency, &tracing_max_lat_fops); - entry = debugfs_create_file("tracing_max_latency", 0644, d_tracer, - &tracing_max_latency, - &tracing_max_lat_fops); - if (!entry) - pr_warning("Could not create debugfs " - "'tracing_max_latency' entry\n"); + trace_create_file("tracing_thresh", 0644, d_tracer, + &tracing_thresh, &tracing_max_lat_fops); - entry = debugfs_create_file("tracing_thresh", 0644, d_tracer, - &tracing_thresh, &tracing_max_lat_fops); - if (!entry) - pr_warning("Could not create debugfs " - "'tracing_thresh' entry\n"); - entry = debugfs_create_file("README", 0644, d_tracer, - NULL, &tracing_readme_fops); - if (!entry) - pr_warning("Could not create debugfs 'README' entry\n"); + trace_create_file("README", 0444, d_tracer, + NULL, &tracing_readme_fops); - entry = debugfs_create_file("trace_pipe", 0444, d_tracer, + trace_create_file("trace_pipe", 0444, d_tracer, (void *) TRACE_PIPE_ALL_CPU, &tracing_pipe_fops); - if (!entry) - pr_warning("Could not create debugfs " - "'trace_pipe' entry\n"); - entry = debugfs_create_file("buffer_size_kb", 0644, d_tracer, - &global_trace, &tracing_entries_fops); - if (!entry) - pr_warning("Could not create debugfs " - "'buffer_size_kb' entry\n"); + trace_create_file("buffer_size_kb", 0644, d_tracer, + &global_trace, &tracing_entries_fops); - entry = debugfs_create_file("trace_marker", 0220, d_tracer, - NULL, &tracing_mark_fops); - if (!entry) - pr_warning("Could not create debugfs " - "'trace_marker' entry\n"); + trace_create_file("trace_marker", 0220, d_tracer, + NULL, &tracing_mark_fops); + + trace_create_file("saved_cmdlines", 0444, d_tracer, + NULL, &tracing_saved_cmdlines_fops); #ifdef CONFIG_DYNAMIC_FTRACE - entry = debugfs_create_file("dyn_ftrace_total_info", 0444, d_tracer, - &ftrace_update_tot_cnt, - &tracing_dyn_info_fops); - if (!entry) - pr_warning("Could not create debugfs " - "'dyn_ftrace_total_info' entry\n"); + trace_create_file("dyn_ftrace_total_info", 0444, d_tracer, + &ftrace_update_tot_cnt, &tracing_dyn_info_fops); #endif #ifdef CONFIG_SYSPROF_TRACER init_tracer_sysprof_debugfs(d_tracer); #endif + create_trace_options_dir(); + for_each_tracing_cpu(cpu) tracing_init_debugfs_percpu(cpu); @@ -4064,7 +4183,8 @@ trace_printk_seq(struct trace_seq *s) static void __ftrace_dump(bool disable_tracing) { - static DEFINE_SPINLOCK(ftrace_dump_lock); + static raw_spinlock_t ftrace_dump_lock = + (raw_spinlock_t)__RAW_SPIN_LOCK_UNLOCKED; /* use static because iter can be a bit big for the stack */ static struct trace_iterator iter; unsigned int old_userobj; @@ -4073,7 +4193,8 @@ static void __ftrace_dump(bool disable_tracing) int cnt = 0, cpu; /* only one dump */ - spin_lock_irqsave(&ftrace_dump_lock, flags); + local_irq_save(flags); + __raw_spin_lock(&ftrace_dump_lock); if (dump_ran) goto out; @@ -4145,7 +4266,8 @@ static void __ftrace_dump(bool disable_tracing) } out: - spin_unlock_irqrestore(&ftrace_dump_lock, flags); + __raw_spin_unlock(&ftrace_dump_lock); + local_irq_restore(flags); } /* By default: disable tracing after the dump */ diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index e685ac2b2ba1..6e735d4771f8 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h @@ -9,9 +9,12 @@ #include #include #include -#include +#include #include +#include +#include + enum trace_type { __TRACE_FIRST_TYPE = 0, @@ -41,20 +44,6 @@ enum trace_type { __TRACE_LAST_TYPE, }; -/* - * The trace entry - the most basic unit of tracing. This is what - * is printed in the end as a single line in the trace output, such as: - * - * bash-15816 [01] 235.197585: idle_cpu <- irq_enter - */ -struct trace_entry { - unsigned char type; - unsigned char flags; - unsigned char preempt_count; - int pid; - int tgid; -}; - /* * Function trace entry - function address and parent function addres: */ @@ -263,8 +252,6 @@ struct trace_array_cpu { char comm[TASK_COMM_LEN]; }; -struct trace_iterator; - /* * The trace array - an array of per-CPU trace arrays. This is the * highest level data structure that individual tracers deal with. @@ -339,15 +326,6 @@ extern void __ftrace_bad_type(void); __ftrace_bad_type(); \ } while (0) -/* Return values for print_line callback */ -enum print_line_t { - TRACE_TYPE_PARTIAL_LINE = 0, /* Retry after flushing the seq */ - TRACE_TYPE_HANDLED = 1, - TRACE_TYPE_UNHANDLED = 2, /* Relay to other output functions */ - TRACE_TYPE_NO_CONSUME = 3 /* Handled but ask to not consume */ -}; - - /* * An option specific to a tracer. This is a boolean value. * The bit is the bit index that sets its value on the @@ -423,60 +401,30 @@ struct tracer { struct tracer_stat *stats; }; -struct trace_seq { - unsigned char buffer[PAGE_SIZE]; - unsigned int len; - unsigned int readpos; -}; - -static inline void -trace_seq_init(struct trace_seq *s) -{ - s->len = 0; - s->readpos = 0; -} - #define TRACE_PIPE_ALL_CPU -1 -/* - * Trace iterator - used by printout routines who present trace - * results to users and which routines might sleep, etc: - */ -struct trace_iterator { - struct trace_array *tr; - struct tracer *trace; - void *private; - int cpu_file; - struct mutex mutex; - struct ring_buffer_iter *buffer_iter[NR_CPUS]; - - /* The below is zeroed out in pipe_read */ - struct trace_seq seq; - struct trace_entry *ent; - int cpu; - u64 ts; - - unsigned long iter_flags; - loff_t pos; - long idx; - - cpumask_var_t started; -}; - int tracer_init(struct tracer *t, struct trace_array *tr); int tracing_is_enabled(void); void trace_wake_up(void); void tracing_reset(struct trace_array *tr, int cpu); void tracing_reset_online_cpus(struct trace_array *tr); +void tracing_reset_current(int cpu); +void tracing_reset_current_online_cpus(void); int tracing_open_generic(struct inode *inode, struct file *filp); +struct dentry *trace_create_file(const char *name, + mode_t mode, + struct dentry *parent, + void *data, + const struct file_operations *fops); + struct dentry *tracing_init_dentry(void); void init_tracer_sysprof_debugfs(struct dentry *d_tracer); struct ring_buffer_event; struct ring_buffer_event *trace_buffer_lock_reserve(struct trace_array *tr, - unsigned char type, + int type, unsigned long len, unsigned long flags, int pc); @@ -484,14 +432,6 @@ void trace_buffer_unlock_commit(struct trace_array *tr, struct ring_buffer_event *event, unsigned long flags, int pc); -struct ring_buffer_event * -trace_current_buffer_lock_reserve(unsigned char type, unsigned long len, - unsigned long flags, int pc); -void trace_current_buffer_unlock_commit(struct ring_buffer_event *event, - unsigned long flags, int pc); -void trace_nowake_buffer_unlock_commit(struct ring_buffer_event *event, - unsigned long flags, int pc); - struct trace_entry *tracing_get_trace_entry(struct trace_array *tr, struct trace_array_cpu *data); @@ -514,7 +454,6 @@ void tracing_sched_switch_trace(struct trace_array *tr, struct task_struct *prev, struct task_struct *next, unsigned long flags, int pc); -void tracing_record_cmdline(struct task_struct *tsk); void tracing_sched_wakeup_trace(struct trace_array *tr, struct task_struct *wakee, @@ -599,6 +538,8 @@ extern int trace_selftest_startup_sysprof(struct tracer *trace, struct trace_array *tr); extern int trace_selftest_startup_branch(struct tracer *trace, struct trace_array *tr); +extern int trace_selftest_startup_hw_branches(struct tracer *trace, + struct trace_array *tr); #endif /* CONFIG_FTRACE_STARTUP_TEST */ extern void *head_page(struct trace_array_cpu *data); @@ -613,6 +554,8 @@ extern unsigned long trace_flags; /* Standard output formatting function used for function return traces */ #ifdef CONFIG_FUNCTION_GRAPH_TRACER extern enum print_line_t print_graph_function(struct trace_iterator *iter); +extern enum print_line_t +trace_print_graph_duration(unsigned long long duration, struct trace_seq *s); #ifdef CONFIG_DYNAMIC_FTRACE /* TODO: make this variable */ @@ -644,7 +587,6 @@ static inline int ftrace_graph_addr(unsigned long addr) return 1; } #endif /* CONFIG_DYNAMIC_FTRACE */ - #else /* CONFIG_FUNCTION_GRAPH_TRACER */ static inline enum print_line_t print_graph_function(struct trace_iterator *iter) @@ -692,6 +634,7 @@ enum trace_iterator_flags { TRACE_ITER_LATENCY_FMT = 0x40000, TRACE_ITER_GLOBAL_CLK = 0x80000, TRACE_ITER_SLEEP_TIME = 0x100000, + TRACE_ITER_GRAPH_TIME = 0x200000, }; /* @@ -790,103 +733,113 @@ struct ftrace_event_field { char *type; int offset; int size; + int is_signed; }; -struct ftrace_event_call { - char *name; - char *system; - struct dentry *dir; - int enabled; - int (*regfunc)(void); - void (*unregfunc)(void); - int id; - int (*raw_init)(void); - int (*show_format)(struct trace_seq *s); - int (*define_fields)(void); - struct list_head fields; +struct event_filter { + int n_preds; struct filter_pred **preds; - -#ifdef CONFIG_EVENT_PROFILE - atomic_t profile_count; - int (*profile_enable)(struct ftrace_event_call *); - void (*profile_disable)(struct ftrace_event_call *); -#endif + char *filter_string; }; struct event_subsystem { struct list_head list; const char *name; struct dentry *entry; - struct filter_pred **preds; + void *filter; }; -#define events_for_each(event) \ - for (event = __start_ftrace_events; \ - (unsigned long)event < (unsigned long)__stop_ftrace_events; \ - event++) - -#define MAX_FILTER_PRED 8 - struct filter_pred; -typedef int (*filter_pred_fn_t) (struct filter_pred *pred, void *event); +typedef int (*filter_pred_fn_t) (struct filter_pred *pred, void *event, + int val1, int val2); struct filter_pred { filter_pred_fn_t fn; u64 val; - char *str_val; + char str_val[MAX_FILTER_STR_VAL]; int str_len; char *field_name; int offset; int not; - int or; - int compound; - int clear; + int op; + int pop_n; }; -int trace_define_field(struct ftrace_event_call *call, char *type, - char *name, int offset, int size); -extern void filter_free_pred(struct filter_pred *pred); -extern void filter_print_preds(struct filter_pred **preds, +extern void print_event_filter(struct ftrace_event_call *call, struct trace_seq *s); -extern int filter_parse(char **pbuf, struct filter_pred *pred); -extern int filter_add_pred(struct ftrace_event_call *call, - struct filter_pred *pred); -extern void filter_free_preds(struct ftrace_event_call *call); -extern int filter_match_preds(struct ftrace_event_call *call, void *rec); -extern void filter_free_subsystem_preds(struct event_subsystem *system); -extern int filter_add_subsystem_pred(struct event_subsystem *system, - struct filter_pred *pred); +extern int apply_event_filter(struct ftrace_event_call *call, + char *filter_string); +extern int apply_subsystem_event_filter(struct event_subsystem *system, + char *filter_string); +extern void print_subsystem_event_filter(struct event_subsystem *system, + struct trace_seq *s); -void event_trace_printk(unsigned long ip, const char *fmt, ...); -extern struct ftrace_event_call __start_ftrace_events[]; -extern struct ftrace_event_call __stop_ftrace_events[]; +static inline int +filter_check_discard(struct ftrace_event_call *call, void *rec, + struct ring_buffer *buffer, + struct ring_buffer_event *event) +{ + if (unlikely(call->filter_active) && !filter_match_preds(call, rec)) { + ring_buffer_discard_commit(buffer, event); + return 1; + } -#define for_each_event(event) \ - for (event = __start_ftrace_events; \ - (unsigned long)event < (unsigned long)__stop_ftrace_events; \ - event++) + return 0; +} + +#define DEFINE_COMPARISON_PRED(type) \ +static int filter_pred_##type(struct filter_pred *pred, void *event, \ + int val1, int val2) \ +{ \ + type *addr = (type *)(event + pred->offset); \ + type val = (type)pred->val; \ + int match = 0; \ + \ + switch (pred->op) { \ + case OP_LT: \ + match = (*addr < val); \ + break; \ + case OP_LE: \ + match = (*addr <= val); \ + break; \ + case OP_GT: \ + match = (*addr > val); \ + break; \ + case OP_GE: \ + match = (*addr >= val); \ + break; \ + default: \ + break; \ + } \ + \ + return match; \ +} + +#define DEFINE_EQUALITY_PRED(size) \ +static int filter_pred_##size(struct filter_pred *pred, void *event, \ + int val1, int val2) \ +{ \ + u##size *addr = (u##size *)(event + pred->offset); \ + u##size val = (u##size)pred->val; \ + int match; \ + \ + match = (val == *addr) ^ pred->not; \ + \ + return match; \ +} + +extern struct mutex event_mutex; +extern struct list_head ftrace_events; extern const char *__start___trace_bprintk_fmt[]; extern const char *__stop___trace_bprintk_fmt[]; -/* - * The double __builtin_constant_p is because gcc will give us an error - * if we try to allocate the static variable to fmt if it is not a - * constant. Even with the outer if statement optimizing out. - */ -#define event_trace_printk(ip, fmt, args...) \ -do { \ - __trace_printk_check_format(fmt, ##args); \ - tracing_record_cmdline(current); \ - if (__builtin_constant_p(fmt)) { \ - static const char *trace_printk_fmt \ - __attribute__((section("__trace_printk_fmt"))) = \ - __builtin_constant_p(fmt) ? fmt : NULL; \ - \ - __trace_bprintk(ip, trace_printk_fmt, ##args); \ - } else \ - __trace_printk(ip, fmt, ##args); \ -} while (0) +#undef TRACE_EVENT_FORMAT +#define TRACE_EVENT_FORMAT(call, proto, args, fmt, tstruct, tpfmt) \ + extern struct ftrace_event_call event_##call; +#undef TRACE_EVENT_FORMAT_NOFILTER +#define TRACE_EVENT_FORMAT_NOFILTER(call, proto, args, fmt, tstruct, tpfmt) +#include "trace_event_types.h" #endif /* _LINUX_KERNEL_TRACE_H */ diff --git a/kernel/trace/trace_boot.c b/kernel/trace/trace_boot.c index 7a30fc4c3642..a29ef23ffb47 100644 --- a/kernel/trace/trace_boot.c +++ b/kernel/trace/trace_boot.c @@ -9,6 +9,7 @@ #include #include #include +#include #include "trace.h" #include "trace_output.h" @@ -67,7 +68,7 @@ initcall_call_print_line(struct trace_iterator *iter) trace_assign_type(field, entry); call = &field->boot_call; ts = iter->ts; - nsec_rem = do_div(ts, 1000000000); + nsec_rem = do_div(ts, NSEC_PER_SEC); ret = trace_seq_printf(s, "[%5ld.%09ld] calling %s @ %i\n", (unsigned long)ts, nsec_rem, call->func, call->caller); @@ -92,7 +93,7 @@ initcall_ret_print_line(struct trace_iterator *iter) trace_assign_type(field, entry); init_ret = &field->boot_ret; ts = iter->ts; - nsec_rem = do_div(ts, 1000000000); + nsec_rem = do_div(ts, NSEC_PER_SEC); ret = trace_seq_printf(s, "[%5ld.%09ld] initcall %s " "returned %d after %llu msecs\n", diff --git a/kernel/trace/trace_branch.c b/kernel/trace/trace_branch.c index 8333715e4066..7a7a9fd249a9 100644 --- a/kernel/trace/trace_branch.c +++ b/kernel/trace/trace_branch.c @@ -30,6 +30,7 @@ static struct trace_array *branch_tracer; static void probe_likely_condition(struct ftrace_branch_data *f, int val, int expect) { + struct ftrace_event_call *call = &event_branch; struct trace_array *tr = branch_tracer; struct ring_buffer_event *event; struct trace_branch *entry; @@ -73,7 +74,8 @@ probe_likely_condition(struct ftrace_branch_data *f, int val, int expect) entry->line = f->line; entry->correct = val == expect; - ring_buffer_unlock_commit(tr->buffer, event); + if (!filter_check_discard(call, entry, tr->buffer, event)) + ring_buffer_unlock_commit(tr->buffer, event); out: atomic_dec(&tr->data[cpu]->disabled); @@ -271,7 +273,7 @@ static int branch_stat_show(struct seq_file *m, void *v) return 0; } -static void *annotated_branch_stat_start(void) +static void *annotated_branch_stat_start(struct tracer_stat *trace) { return __start_annotated_branch_profile; } @@ -346,7 +348,7 @@ static int all_branch_stat_headers(struct seq_file *m) return 0; } -static void *all_branch_stat_start(void) +static void *all_branch_stat_start(struct tracer_stat *trace) { return __start_branch_profile; } diff --git a/kernel/trace/trace_event_profile.c b/kernel/trace/trace_event_profile.c index 22cba9970776..5b5895afecfe 100644 --- a/kernel/trace/trace_event_profile.c +++ b/kernel/trace/trace_event_profile.c @@ -10,22 +10,30 @@ int ftrace_profile_enable(int event_id) { struct ftrace_event_call *event; + int ret = -EINVAL; - for_each_event(event) { - if (event->id == event_id) - return event->profile_enable(event); + mutex_lock(&event_mutex); + list_for_each_entry(event, &ftrace_events, list) { + if (event->id == event_id) { + ret = event->profile_enable(event); + break; + } } + mutex_unlock(&event_mutex); - return -EINVAL; + return ret; } void ftrace_profile_disable(int event_id) { struct ftrace_event_call *event; - for_each_event(event) { - if (event->id == event_id) - return event->profile_disable(event); + mutex_lock(&event_mutex); + list_for_each_entry(event, &ftrace_events, list) { + if (event->id == event_id) { + event->profile_disable(event); + break; + } } + mutex_unlock(&event_mutex); } - diff --git a/kernel/trace/trace_event_types.h b/kernel/trace/trace_event_types.h index fd78bee71dd7..5e32e375134d 100644 --- a/kernel/trace/trace_event_types.h +++ b/kernel/trace/trace_event_types.h @@ -57,7 +57,7 @@ TRACE_EVENT_FORMAT(context_switch, TRACE_CTX, ctx_switch_entry, ignore, TP_RAW_FMT("%u:%u:%u ==+ %u:%u:%u [%03u]") ); -TRACE_EVENT_FORMAT(special, TRACE_SPECIAL, special_entry, ignore, +TRACE_EVENT_FORMAT_NOFILTER(special, TRACE_SPECIAL, special_entry, ignore, TRACE_STRUCT( TRACE_FIELD(unsigned long, arg1, arg1) TRACE_FIELD(unsigned long, arg2, arg2) @@ -122,8 +122,10 @@ TRACE_EVENT_FORMAT(print, TRACE_PRINT, print_entry, ignore, TRACE_EVENT_FORMAT(branch, TRACE_BRANCH, trace_branch, ignore, TRACE_STRUCT( TRACE_FIELD(unsigned int, line, line) - TRACE_FIELD_SPECIAL(char func[TRACE_FUNC_SIZE+1], func, func) - TRACE_FIELD_SPECIAL(char file[TRACE_FUNC_SIZE+1], file, file) + TRACE_FIELD_SPECIAL(char func[TRACE_FUNC_SIZE+1], func, + TRACE_FUNC_SIZE+1, func) + TRACE_FIELD_SPECIAL(char file[TRACE_FUNC_SIZE+1], file, + TRACE_FUNC_SIZE+1, file) TRACE_FIELD(char, correct, correct) ), TP_RAW_FMT("%u:%s:%s (%u)") @@ -139,8 +141,8 @@ TRACE_EVENT_FORMAT(hw_branch, TRACE_HW_BRANCHES, hw_branch_entry, ignore, TRACE_EVENT_FORMAT(power, TRACE_POWER, trace_power, ignore, TRACE_STRUCT( - TRACE_FIELD(ktime_t, state_data.stamp, stamp) - TRACE_FIELD(ktime_t, state_data.end, end) + TRACE_FIELD_SIGN(ktime_t, state_data.stamp, stamp, 1) + TRACE_FIELD_SIGN(ktime_t, state_data.end, end, 1) TRACE_FIELD(int, state_data.type, type) TRACE_FIELD(int, state_data.state, state) ), diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 576f4fa2af0d..aa08be69a1b6 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c @@ -8,19 +8,25 @@ * */ +#include +#include +#include #include #include #include #include +#include #include "trace_output.h" #define TRACE_SYSTEM "TRACE_SYSTEM" -static DEFINE_MUTEX(event_mutex); +DEFINE_MUTEX(event_mutex); + +LIST_HEAD(ftrace_events); int trace_define_field(struct ftrace_event_call *call, char *type, - char *name, int offset, int size) + char *name, int offset, int size, int is_signed) { struct ftrace_event_field *field; @@ -38,6 +44,7 @@ int trace_define_field(struct ftrace_event_call *call, char *type, field->offset = offset; field->size = size; + field->is_signed = is_signed; list_add(&field->link, &call->fields); return 0; @@ -51,47 +58,94 @@ err: return -ENOMEM; } +EXPORT_SYMBOL_GPL(trace_define_field); -static void ftrace_clear_events(void) +#ifdef CONFIG_MODULES + +static void trace_destroy_fields(struct ftrace_event_call *call) { - struct ftrace_event_call *call = (void *)__start_ftrace_events; + struct ftrace_event_field *field, *next; - - while ((unsigned long)call < (unsigned long)__stop_ftrace_events) { - - if (call->enabled) { - call->enabled = 0; - call->unregfunc(); - } - call++; + list_for_each_entry_safe(field, next, &call->fields, link) { + list_del(&field->link); + kfree(field->type); + kfree(field->name); + kfree(field); } } +#endif /* CONFIG_MODULES */ + static void ftrace_event_enable_disable(struct ftrace_event_call *call, int enable) { - switch (enable) { case 0: if (call->enabled) { call->enabled = 0; + tracing_stop_cmdline_record(); call->unregfunc(); } break; case 1: if (!call->enabled) { call->enabled = 1; + tracing_start_cmdline_record(); call->regfunc(); } break; } } +static void ftrace_clear_events(void) +{ + struct ftrace_event_call *call; + + mutex_lock(&event_mutex); + list_for_each_entry(call, &ftrace_events, list) { + ftrace_event_enable_disable(call, 0); + } + mutex_unlock(&event_mutex); +} + +/* + * __ftrace_set_clr_event(NULL, NULL, NULL, set) will set/unset all events. + */ +static int __ftrace_set_clr_event(const char *match, const char *sub, + const char *event, int set) +{ + struct ftrace_event_call *call; + int ret = -EINVAL; + + mutex_lock(&event_mutex); + list_for_each_entry(call, &ftrace_events, list) { + + if (!call->name || !call->regfunc) + continue; + + if (match && + strcmp(match, call->name) != 0 && + strcmp(match, call->system) != 0) + continue; + + if (sub && strcmp(sub, call->system) != 0) + continue; + + if (event && strcmp(event, call->name) != 0) + continue; + + ftrace_event_enable_disable(call, set); + + ret = 0; + } + mutex_unlock(&event_mutex); + + return ret; +} + static int ftrace_set_clr_event(char *buf, int set) { - struct ftrace_event_call *call = __start_ftrace_events; char *event = NULL, *sub = NULL, *match; - int ret = -EINVAL; /* * The buf format can be : @@ -117,30 +171,24 @@ static int ftrace_set_clr_event(char *buf, int set) event = NULL; } - mutex_lock(&event_mutex); - for_each_event(call) { + return __ftrace_set_clr_event(match, sub, event, set); +} - if (!call->name || !call->regfunc) - continue; - - if (match && - strcmp(match, call->name) != 0 && - strcmp(match, call->system) != 0) - continue; - - if (sub && strcmp(sub, call->system) != 0) - continue; - - if (event && strcmp(event, call->name) != 0) - continue; - - ftrace_event_enable_disable(call, set); - - ret = 0; - } - mutex_unlock(&event_mutex); - - return ret; +/** + * trace_set_clr_event - enable or disable an event + * @system: system name to match (NULL for any system) + * @event: event name to match (NULL for all events, within system) + * @set: 1 to enable, 0 to disable + * + * This is a way for other parts of the kernel to enable or disable + * event recording. + * + * Returns 0 on success, -EINVAL if the parameters do not match any + * registered events. + */ +int trace_set_clr_event(const char *system, const char *event, int set) +{ + return __ftrace_set_clr_event(NULL, system, event, set); } /* 128 should be much more than enough */ @@ -224,15 +272,17 @@ ftrace_event_write(struct file *file, const char __user *ubuf, static void * t_next(struct seq_file *m, void *v, loff_t *pos) { - struct ftrace_event_call *call = m->private; - struct ftrace_event_call *next = call; + struct list_head *list = m->private; + struct ftrace_event_call *call; (*pos)++; for (;;) { - if ((unsigned long)call >= (unsigned long)__stop_ftrace_events) + if (list == &ftrace_events) return NULL; + call = list_entry(list, struct ftrace_event_call, list); + /* * The ftrace subsystem is for showing formats only. * They can not be enabled or disabled via the event files. @@ -240,45 +290,51 @@ t_next(struct seq_file *m, void *v, loff_t *pos) if (call->regfunc) break; - call++; - next = call; + list = list->next; } - m->private = ++next; + m->private = list->next; return call; } static void *t_start(struct seq_file *m, loff_t *pos) { + mutex_lock(&event_mutex); + if (*pos == 0) + m->private = ftrace_events.next; return t_next(m, NULL, pos); } static void * s_next(struct seq_file *m, void *v, loff_t *pos) { - struct ftrace_event_call *call = m->private; - struct ftrace_event_call *next; + struct list_head *list = m->private; + struct ftrace_event_call *call; (*pos)++; retry: - if ((unsigned long)call >= (unsigned long)__stop_ftrace_events) + if (list == &ftrace_events) return NULL; + call = list_entry(list, struct ftrace_event_call, list); + if (!call->enabled) { - call++; + list = list->next; goto retry; } - next = call; - m->private = ++next; + m->private = list->next; return call; } static void *s_start(struct seq_file *m, loff_t *pos) { + mutex_lock(&event_mutex); + if (*pos == 0) + m->private = ftrace_events.next; return s_next(m, NULL, pos); } @@ -295,12 +351,12 @@ static int t_show(struct seq_file *m, void *v) static void t_stop(struct seq_file *m, void *p) { + mutex_unlock(&event_mutex); } static int ftrace_event_seq_open(struct inode *inode, struct file *file) { - int ret; const struct seq_operations *seq_ops; if ((file->f_mode & FMODE_WRITE) && @@ -308,13 +364,7 @@ ftrace_event_seq_open(struct inode *inode, struct file *file) ftrace_clear_events(); seq_ops = inode->i_private; - ret = seq_open(file, seq_ops); - if (!ret) { - struct seq_file *m = file->private_data; - - m->private = __start_ftrace_events; - } - return ret; + return seq_open(file, seq_ops); } static ssize_t @@ -374,8 +424,93 @@ event_enable_write(struct file *filp, const char __user *ubuf, size_t cnt, return cnt; } +static ssize_t +system_enable_read(struct file *filp, char __user *ubuf, size_t cnt, + loff_t *ppos) +{ + const char set_to_char[4] = { '?', '0', '1', 'X' }; + const char *system = filp->private_data; + struct ftrace_event_call *call; + char buf[2]; + int set = 0; + int ret; + + mutex_lock(&event_mutex); + list_for_each_entry(call, &ftrace_events, list) { + if (!call->name || !call->regfunc) + continue; + + if (system && strcmp(call->system, system) != 0) + continue; + + /* + * We need to find out if all the events are set + * or if all events or cleared, or if we have + * a mixture. + */ + set |= (1 << !!call->enabled); + + /* + * If we have a mixture, no need to look further. + */ + if (set == 3) + break; + } + mutex_unlock(&event_mutex); + + buf[0] = set_to_char[set]; + buf[1] = '\n'; + + ret = simple_read_from_buffer(ubuf, cnt, ppos, buf, 2); + + return ret; +} + +static ssize_t +system_enable_write(struct file *filp, const char __user *ubuf, size_t cnt, + loff_t *ppos) +{ + const char *system = filp->private_data; + unsigned long val; + char buf[64]; + ssize_t ret; + + if (cnt >= sizeof(buf)) + return -EINVAL; + + if (copy_from_user(&buf, ubuf, cnt)) + return -EFAULT; + + buf[cnt] = 0; + + ret = strict_strtoul(buf, 10, &val); + if (ret < 0) + return ret; + + ret = tracing_update_buffers(); + if (ret < 0) + return ret; + + if (val != 0 && val != 1) + return -EINVAL; + + ret = __ftrace_set_clr_event(NULL, system, NULL, val); + if (ret) + goto out; + + ret = cnt; + +out: + *ppos += cnt; + + return ret; +} + +extern char *__bad_type_size(void); + #undef FIELD #define FIELD(type, name) \ + sizeof(type) != sizeof(field.name) ? __bad_type_size() : \ #type, "common_" #name, offsetof(typeof(field), name), \ sizeof(field.name) @@ -391,7 +526,7 @@ static int trace_write_header(struct trace_seq *s) "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n" "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n" "\n", - FIELD(unsigned char, type), + FIELD(unsigned short, type), FIELD(unsigned char, flags), FIELD(unsigned char, preempt_count), FIELD(int, pid), @@ -481,7 +616,7 @@ event_filter_read(struct file *filp, char __user *ubuf, size_t cnt, trace_seq_init(s); - filter_print_preds(call->preds, s); + print_event_filter(call, s); r = simple_read_from_buffer(ubuf, cnt, ppos, s->buffer, s->len); kfree(s); @@ -494,38 +629,26 @@ event_filter_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) { struct ftrace_event_call *call = filp->private_data; - char buf[64], *pbuf = buf; - struct filter_pred *pred; + char *buf; int err; - if (cnt >= sizeof(buf)) + if (cnt >= PAGE_SIZE) return -EINVAL; - if (copy_from_user(&buf, ubuf, cnt)) - return -EFAULT; - buf[cnt] = '\0'; - - pred = kzalloc(sizeof(*pred), GFP_KERNEL); - if (!pred) + buf = (char *)__get_free_page(GFP_TEMPORARY); + if (!buf) return -ENOMEM; - err = filter_parse(&pbuf, pred); - if (err < 0) { - filter_free_pred(pred); - return err; + if (copy_from_user(buf, ubuf, cnt)) { + free_page((unsigned long) buf); + return -EFAULT; } + buf[cnt] = '\0'; - if (pred->clear) { - filter_free_preds(call); - filter_free_pred(pred); - return cnt; - } - - err = filter_add_pred(call, pred); - if (err < 0) { - filter_free_pred(pred); + err = apply_event_filter(call, buf); + free_page((unsigned long) buf); + if (err < 0) return err; - } *ppos += cnt; @@ -549,7 +672,7 @@ subsystem_filter_read(struct file *filp, char __user *ubuf, size_t cnt, trace_seq_init(s); - filter_print_preds(system->preds, s); + print_subsystem_event_filter(system, s); r = simple_read_from_buffer(ubuf, cnt, ppos, s->buffer, s->len); kfree(s); @@ -562,45 +685,56 @@ subsystem_filter_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) { struct event_subsystem *system = filp->private_data; - char buf[64], *pbuf = buf; - struct filter_pred *pred; + char *buf; int err; - if (cnt >= sizeof(buf)) + if (cnt >= PAGE_SIZE) return -EINVAL; - if (copy_from_user(&buf, ubuf, cnt)) - return -EFAULT; - buf[cnt] = '\0'; - - pred = kzalloc(sizeof(*pred), GFP_KERNEL); - if (!pred) + buf = (char *)__get_free_page(GFP_TEMPORARY); + if (!buf) return -ENOMEM; - err = filter_parse(&pbuf, pred); - if (err < 0) { - filter_free_pred(pred); - return err; + if (copy_from_user(buf, ubuf, cnt)) { + free_page((unsigned long) buf); + return -EFAULT; } + buf[cnt] = '\0'; - if (pred->clear) { - filter_free_subsystem_preds(system); - filter_free_pred(pred); - return cnt; - } - - err = filter_add_subsystem_pred(system, pred); - if (err < 0) { - filter_free_subsystem_preds(system); - filter_free_pred(pred); + err = apply_subsystem_event_filter(system, buf); + free_page((unsigned long) buf); + if (err < 0) return err; - } *ppos += cnt; return cnt; } +static ssize_t +show_header(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) +{ + int (*func)(struct trace_seq *s) = filp->private_data; + struct trace_seq *s; + int r; + + if (*ppos) + return 0; + + s = kmalloc(sizeof(*s), GFP_KERNEL); + if (!s) + return -ENOMEM; + + trace_seq_init(s); + + func(s); + r = simple_read_from_buffer(ubuf, cnt, ppos, s->buffer, s->len); + + kfree(s); + + return r; +} + static const struct seq_operations show_event_seq_ops = { .start = t_start, .next = t_next, @@ -658,6 +792,17 @@ static const struct file_operations ftrace_subsystem_filter_fops = { .write = subsystem_filter_write, }; +static const struct file_operations ftrace_system_enable_fops = { + .open = tracing_open_generic, + .read = system_enable_read, + .write = system_enable_write, +}; + +static const struct file_operations ftrace_show_header_fops = { + .open = tracing_open_generic, + .read = show_header, +}; + static struct dentry *event_trace_events_dir(void) { static struct dentry *d_tracer; @@ -684,6 +829,7 @@ static struct dentry * event_subsystem_dir(const char *name, struct dentry *d_events) { struct event_subsystem *system; + struct dentry *entry; /* First see if we did not already create this dir */ list_for_each_entry(system, &event_subsystems, list) { @@ -707,16 +853,46 @@ event_subsystem_dir(const char *name, struct dentry *d_events) return d_events; } - system->name = name; + system->name = kstrdup(name, GFP_KERNEL); + if (!system->name) { + debugfs_remove(system->entry); + kfree(system); + return d_events; + } + list_add(&system->list, &event_subsystems); - system->preds = NULL; + system->filter = NULL; + + system->filter = kzalloc(sizeof(struct event_filter), GFP_KERNEL); + if (!system->filter) { + pr_warning("Could not allocate filter for subsystem " + "'%s'\n", name); + return system->entry; + } + + entry = debugfs_create_file("filter", 0644, system->entry, system, + &ftrace_subsystem_filter_fops); + if (!entry) { + kfree(system->filter); + system->filter = NULL; + pr_warning("Could not create debugfs " + "'%s/filter' entry\n", name); + } + + entry = trace_create_file("enable", 0644, system->entry, + (void *)system->name, + &ftrace_system_enable_fops); return system->entry; } static int -event_create_dir(struct ftrace_event_call *call, struct dentry *d_events) +event_create_dir(struct ftrace_event_call *call, struct dentry *d_events, + const struct file_operations *id, + const struct file_operations *enable, + const struct file_operations *filter, + const struct file_operations *format) { struct dentry *entry; int ret; @@ -725,7 +901,7 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events) * If the trace point header did not define TRACE_SYSTEM * then the system would be called "TRACE_SYSTEM". */ - if (strcmp(call->system, "TRACE_SYSTEM") != 0) + if (strcmp(call->system, TRACE_SYSTEM) != 0) d_events = event_subsystem_dir(call->system, d_events); if (call->raw_init) { @@ -744,21 +920,13 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events) return -1; } - if (call->regfunc) { - entry = debugfs_create_file("enable", 0644, call->dir, call, - &ftrace_enable_fops); - if (!entry) - pr_warning("Could not create debugfs " - "'%s/enable' entry\n", call->name); - } + if (call->regfunc) + entry = trace_create_file("enable", 0644, call->dir, call, + enable); - if (call->id) { - entry = debugfs_create_file("id", 0444, call->dir, call, - &ftrace_event_id_fops); - if (!entry) - pr_warning("Could not create debugfs '%s/id' entry\n", - call->name); - } + if (call->id) + entry = trace_create_file("id", 0444, call->dir, call, + id); if (call->define_fields) { ret = call->define_fields(); @@ -767,32 +935,195 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events) " events/%s\n", call->name); return ret; } - entry = debugfs_create_file("filter", 0644, call->dir, call, - &ftrace_event_filter_fops); - if (!entry) - pr_warning("Could not create debugfs " - "'%s/filter' entry\n", call->name); + entry = trace_create_file("filter", 0644, call->dir, call, + filter); } /* A trace may not want to export its format */ if (!call->show_format) return 0; - entry = debugfs_create_file("format", 0444, call->dir, call, - &ftrace_event_format_fops); - if (!entry) - pr_warning("Could not create debugfs " - "'%s/format' entry\n", call->name); + entry = trace_create_file("format", 0444, call->dir, call, + format); return 0; } +#define for_each_event(event, start, end) \ + for (event = start; \ + (unsigned long)event < (unsigned long)end; \ + event++) + +#ifdef CONFIG_MODULES + +static LIST_HEAD(ftrace_module_file_list); + +/* + * Modules must own their file_operations to keep up with + * reference counting. + */ +struct ftrace_module_file_ops { + struct list_head list; + struct module *mod; + struct file_operations id; + struct file_operations enable; + struct file_operations format; + struct file_operations filter; +}; + +static struct ftrace_module_file_ops * +trace_create_file_ops(struct module *mod) +{ + struct ftrace_module_file_ops *file_ops; + + /* + * This is a bit of a PITA. To allow for correct reference + * counting, modules must "own" their file_operations. + * To do this, we allocate the file operations that will be + * used in the event directory. + */ + + file_ops = kmalloc(sizeof(*file_ops), GFP_KERNEL); + if (!file_ops) + return NULL; + + file_ops->mod = mod; + + file_ops->id = ftrace_event_id_fops; + file_ops->id.owner = mod; + + file_ops->enable = ftrace_enable_fops; + file_ops->enable.owner = mod; + + file_ops->filter = ftrace_event_filter_fops; + file_ops->filter.owner = mod; + + file_ops->format = ftrace_event_format_fops; + file_ops->format.owner = mod; + + list_add(&file_ops->list, &ftrace_module_file_list); + + return file_ops; +} + +static void trace_module_add_events(struct module *mod) +{ + struct ftrace_module_file_ops *file_ops = NULL; + struct ftrace_event_call *call, *start, *end; + struct dentry *d_events; + + start = mod->trace_events; + end = mod->trace_events + mod->num_trace_events; + + if (start == end) + return; + + d_events = event_trace_events_dir(); + if (!d_events) + return; + + for_each_event(call, start, end) { + /* The linker may leave blanks */ + if (!call->name) + continue; + + /* + * This module has events, create file ops for this module + * if not already done. + */ + if (!file_ops) { + file_ops = trace_create_file_ops(mod); + if (!file_ops) + return; + } + call->mod = mod; + list_add(&call->list, &ftrace_events); + event_create_dir(call, d_events, + &file_ops->id, &file_ops->enable, + &file_ops->filter, &file_ops->format); + } +} + +static void trace_module_remove_events(struct module *mod) +{ + struct ftrace_module_file_ops *file_ops; + struct ftrace_event_call *call, *p; + bool found = false; + + down_write(&trace_event_mutex); + list_for_each_entry_safe(call, p, &ftrace_events, list) { + if (call->mod == mod) { + found = true; + ftrace_event_enable_disable(call, 0); + if (call->event) + __unregister_ftrace_event(call->event); + debugfs_remove_recursive(call->dir); + list_del(&call->list); + trace_destroy_fields(call); + destroy_preds(call); + } + } + + /* Now free the file_operations */ + list_for_each_entry(file_ops, &ftrace_module_file_list, list) { + if (file_ops->mod == mod) + break; + } + if (&file_ops->list != &ftrace_module_file_list) { + list_del(&file_ops->list); + kfree(file_ops); + } + + /* + * It is safest to reset the ring buffer if the module being unloaded + * registered any events. + */ + if (found) + tracing_reset_current_online_cpus(); + up_write(&trace_event_mutex); +} + +static int trace_module_notify(struct notifier_block *self, + unsigned long val, void *data) +{ + struct module *mod = data; + + mutex_lock(&event_mutex); + switch (val) { + case MODULE_STATE_COMING: + trace_module_add_events(mod); + break; + case MODULE_STATE_GOING: + trace_module_remove_events(mod); + break; + } + mutex_unlock(&event_mutex); + + return 0; +} +#else +static int trace_module_notify(struct notifier_block *self, + unsigned long val, void *data) +{ + return 0; +} +#endif /* CONFIG_MODULES */ + +struct notifier_block trace_module_nb = { + .notifier_call = trace_module_notify, + .priority = 0, +}; + +extern struct ftrace_event_call __start_ftrace_events[]; +extern struct ftrace_event_call __stop_ftrace_events[]; + static __init int event_trace_init(void) { - struct ftrace_event_call *call = __start_ftrace_events; + struct ftrace_event_call *call; struct dentry *d_tracer; struct dentry *entry; struct dentry *d_events; + int ret; d_tracer = tracing_init_dentry(); if (!d_tracer) @@ -816,13 +1147,243 @@ static __init int event_trace_init(void) if (!d_events) return 0; - for_each_event(call) { + /* ring buffer internal formats */ + trace_create_file("header_page", 0444, d_events, + ring_buffer_print_page_header, + &ftrace_show_header_fops); + + trace_create_file("header_event", 0444, d_events, + ring_buffer_print_entry_header, + &ftrace_show_header_fops); + + trace_create_file("enable", 0644, d_events, + NULL, &ftrace_system_enable_fops); + + for_each_event(call, __start_ftrace_events, __stop_ftrace_events) { /* The linker may leave blanks */ if (!call->name) continue; - event_create_dir(call, d_events); + list_add(&call->list, &ftrace_events); + event_create_dir(call, d_events, &ftrace_event_id_fops, + &ftrace_enable_fops, &ftrace_event_filter_fops, + &ftrace_event_format_fops); } + ret = register_module_notifier(&trace_module_nb); + if (ret) + pr_warning("Failed to register trace events module notifier\n"); + return 0; } fs_initcall(event_trace_init); + +#ifdef CONFIG_FTRACE_STARTUP_TEST + +static DEFINE_SPINLOCK(test_spinlock); +static DEFINE_SPINLOCK(test_spinlock_irq); +static DEFINE_MUTEX(test_mutex); + +static __init void test_work(struct work_struct *dummy) +{ + spin_lock(&test_spinlock); + spin_lock_irq(&test_spinlock_irq); + udelay(1); + spin_unlock_irq(&test_spinlock_irq); + spin_unlock(&test_spinlock); + + mutex_lock(&test_mutex); + msleep(1); + mutex_unlock(&test_mutex); +} + +static __init int event_test_thread(void *unused) +{ + void *test_malloc; + + test_malloc = kmalloc(1234, GFP_KERNEL); + if (!test_malloc) + pr_info("failed to kmalloc\n"); + + schedule_on_each_cpu(test_work); + + kfree(test_malloc); + + set_current_state(TASK_INTERRUPTIBLE); + while (!kthread_should_stop()) + schedule(); + + return 0; +} + +/* + * Do various things that may trigger events. + */ +static __init void event_test_stuff(void) +{ + struct task_struct *test_thread; + + test_thread = kthread_run(event_test_thread, NULL, "test-events"); + msleep(1); + kthread_stop(test_thread); +} + +/* + * For every trace event defined, we will test each trace point separately, + * and then by groups, and finally all trace points. + */ +static __init void event_trace_self_tests(void) +{ + struct ftrace_event_call *call; + struct event_subsystem *system; + int ret; + + pr_info("Running tests on trace events:\n"); + + list_for_each_entry(call, &ftrace_events, list) { + + /* Only test those that have a regfunc */ + if (!call->regfunc) + continue; + + pr_info("Testing event %s: ", call->name); + + /* + * If an event is already enabled, someone is using + * it and the self test should not be on. + */ + if (call->enabled) { + pr_warning("Enabled event during self test!\n"); + WARN_ON_ONCE(1); + continue; + } + + ftrace_event_enable_disable(call, 1); + event_test_stuff(); + ftrace_event_enable_disable(call, 0); + + pr_cont("OK\n"); + } + + /* Now test at the sub system level */ + + pr_info("Running tests on trace event systems:\n"); + + list_for_each_entry(system, &event_subsystems, list) { + + /* the ftrace system is special, skip it */ + if (strcmp(system->name, "ftrace") == 0) + continue; + + pr_info("Testing event system %s: ", system->name); + + ret = __ftrace_set_clr_event(NULL, system->name, NULL, 1); + if (WARN_ON_ONCE(ret)) { + pr_warning("error enabling system %s\n", + system->name); + continue; + } + + event_test_stuff(); + + ret = __ftrace_set_clr_event(NULL, system->name, NULL, 0); + if (WARN_ON_ONCE(ret)) + pr_warning("error disabling system %s\n", + system->name); + + pr_cont("OK\n"); + } + + /* Test with all events enabled */ + + pr_info("Running tests on all trace events:\n"); + pr_info("Testing all events: "); + + ret = __ftrace_set_clr_event(NULL, NULL, NULL, 1); + if (WARN_ON_ONCE(ret)) { + pr_warning("error enabling all events\n"); + return; + } + + event_test_stuff(); + + /* reset sysname */ + ret = __ftrace_set_clr_event(NULL, NULL, NULL, 0); + if (WARN_ON_ONCE(ret)) { + pr_warning("error disabling all events\n"); + return; + } + + pr_cont("OK\n"); +} + +#ifdef CONFIG_FUNCTION_TRACER + +static DEFINE_PER_CPU(atomic_t, test_event_disable); + +static void +function_test_events_call(unsigned long ip, unsigned long parent_ip) +{ + struct ring_buffer_event *event; + struct ftrace_entry *entry; + unsigned long flags; + long disabled; + int resched; + int cpu; + int pc; + + pc = preempt_count(); + resched = ftrace_preempt_disable(); + cpu = raw_smp_processor_id(); + disabled = atomic_inc_return(&per_cpu(test_event_disable, cpu)); + + if (disabled != 1) + goto out; + + local_save_flags(flags); + + event = trace_current_buffer_lock_reserve(TRACE_FN, sizeof(*entry), + flags, pc); + if (!event) + goto out; + entry = ring_buffer_event_data(event); + entry->ip = ip; + entry->parent_ip = parent_ip; + + trace_nowake_buffer_unlock_commit(event, flags, pc); + + out: + atomic_dec(&per_cpu(test_event_disable, cpu)); + ftrace_preempt_enable(resched); +} + +static struct ftrace_ops trace_ops __initdata = +{ + .func = function_test_events_call, +}; + +static __init void event_trace_self_test_with_function(void) +{ + register_ftrace_function(&trace_ops); + pr_info("Running tests again, along with the function tracer\n"); + event_trace_self_tests(); + unregister_ftrace_function(&trace_ops); +} +#else +static __init void event_trace_self_test_with_function(void) +{ +} +#endif + +static __init int event_trace_self_tests_init(void) +{ + + event_trace_self_tests(); + + event_trace_self_test_with_function(); + + return 0; +} + +late_initcall(event_trace_self_tests_init); + +#endif diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c index e03cbf1e38f3..936c621bbf46 100644 --- a/kernel/trace/trace_events_filter.c +++ b/kernel/trace/trace_events_filter.c @@ -22,55 +22,136 @@ #include #include #include +#include #include "trace.h" #include "trace_output.h" -static int filter_pred_64(struct filter_pred *pred, void *event) +enum filter_op_ids { - u64 *addr = (u64 *)(event + pred->offset); - u64 val = (u64)pred->val; - int match; + OP_OR, + OP_AND, + OP_NE, + OP_EQ, + OP_LT, + OP_LE, + OP_GT, + OP_GE, + OP_NONE, + OP_OPEN_PAREN, +}; - match = (val == *addr) ^ pred->not; +struct filter_op { + int id; + char *string; + int precedence; +}; - return match; +static struct filter_op filter_ops[] = { + { OP_OR, "||", 1 }, + { OP_AND, "&&", 2 }, + { OP_NE, "!=", 4 }, + { OP_EQ, "==", 4 }, + { OP_LT, "<", 5 }, + { OP_LE, "<=", 5 }, + { OP_GT, ">", 5 }, + { OP_GE, ">=", 5 }, + { OP_NONE, "OP_NONE", 0 }, + { OP_OPEN_PAREN, "(", 0 }, +}; + +enum { + FILT_ERR_NONE, + FILT_ERR_INVALID_OP, + FILT_ERR_UNBALANCED_PAREN, + FILT_ERR_TOO_MANY_OPERANDS, + FILT_ERR_OPERAND_TOO_LONG, + FILT_ERR_FIELD_NOT_FOUND, + FILT_ERR_ILLEGAL_FIELD_OP, + FILT_ERR_ILLEGAL_INTVAL, + FILT_ERR_BAD_SUBSYS_FILTER, + FILT_ERR_TOO_MANY_PREDS, + FILT_ERR_MISSING_FIELD, + FILT_ERR_INVALID_FILTER, +}; + +static char *err_text[] = { + "No error", + "Invalid operator", + "Unbalanced parens", + "Too many operands", + "Operand too long", + "Field not found", + "Illegal operation for field type", + "Illegal integer value", + "Couldn't find or set field in one of a subsystem's events", + "Too many terms in predicate expression", + "Missing field name and/or value", + "Meaningless filter expression", +}; + +struct opstack_op { + int op; + struct list_head list; +}; + +struct postfix_elt { + int op; + char *operand; + struct list_head list; +}; + +struct filter_parse_state { + struct filter_op *ops; + struct list_head opstack; + struct list_head postfix; + int lasterr; + int lasterr_pos; + + struct { + char *string; + unsigned int cnt; + unsigned int tail; + } infix; + + struct { + char string[MAX_FILTER_STR_VAL]; + int pos; + unsigned int tail; + } operand; +}; + +DEFINE_COMPARISON_PRED(s64); +DEFINE_COMPARISON_PRED(u64); +DEFINE_COMPARISON_PRED(s32); +DEFINE_COMPARISON_PRED(u32); +DEFINE_COMPARISON_PRED(s16); +DEFINE_COMPARISON_PRED(u16); +DEFINE_COMPARISON_PRED(s8); +DEFINE_COMPARISON_PRED(u8); + +DEFINE_EQUALITY_PRED(64); +DEFINE_EQUALITY_PRED(32); +DEFINE_EQUALITY_PRED(16); +DEFINE_EQUALITY_PRED(8); + +static int filter_pred_and(struct filter_pred *pred __attribute((unused)), + void *event __attribute((unused)), + int val1, int val2) +{ + return val1 && val2; } -static int filter_pred_32(struct filter_pred *pred, void *event) +static int filter_pred_or(struct filter_pred *pred __attribute((unused)), + void *event __attribute((unused)), + int val1, int val2) { - u32 *addr = (u32 *)(event + pred->offset); - u32 val = (u32)pred->val; - int match; - - match = (val == *addr) ^ pred->not; - - return match; + return val1 || val2; } -static int filter_pred_16(struct filter_pred *pred, void *event) -{ - u16 *addr = (u16 *)(event + pred->offset); - u16 val = (u16)pred->val; - int match; - - match = (val == *addr) ^ pred->not; - - return match; -} - -static int filter_pred_8(struct filter_pred *pred, void *event) -{ - u8 *addr = (u8 *)(event + pred->offset); - u8 val = (u8)pred->val; - int match; - - match = (val == *addr) ^ pred->not; - - return match; -} - -static int filter_pred_string(struct filter_pred *pred, void *event) +/* Filter predicate for fixed sized arrays of characters */ +static int filter_pred_string(struct filter_pred *pred, void *event, + int val1, int val2) { char *addr = (char *)(event + pred->offset); int cmp, match; @@ -82,59 +163,154 @@ static int filter_pred_string(struct filter_pred *pred, void *event) return match; } +/* + * Filter predicate for dynamic sized arrays of characters. + * These are implemented through a list of strings at the end + * of the entry. + * Also each of these strings have a field in the entry which + * contains its offset from the beginning of the entry. + * We have then first to get this field, dereference it + * and add it to the address of the entry, and at last we have + * the address of the string. + */ +static int filter_pred_strloc(struct filter_pred *pred, void *event, + int val1, int val2) +{ + unsigned short str_loc = *(unsigned short *)(event + pred->offset); + char *addr = (char *)(event + str_loc); + int cmp, match; + + cmp = strncmp(addr, pred->str_val, pred->str_len); + + match = (!cmp) ^ pred->not; + + return match; +} + +static int filter_pred_none(struct filter_pred *pred, void *event, + int val1, int val2) +{ + return 0; +} + /* return 1 if event matches, 0 otherwise (discard) */ int filter_match_preds(struct ftrace_event_call *call, void *rec) { - int i, matched, and_failed = 0; - struct filter_pred *pred; - - for (i = 0; i < MAX_FILTER_PRED; i++) { - if (call->preds[i]) { - pred = call->preds[i]; - if (and_failed && !pred->or) - continue; - matched = pred->fn(pred, rec); - if (!matched && !pred->or) { - and_failed = 1; - continue; - } else if (matched && pred->or) - return 1; - } else - break; - } - - if (and_failed) - return 0; - - return 1; -} - -void filter_print_preds(struct filter_pred **preds, struct trace_seq *s) -{ - char *field_name; + struct event_filter *filter = call->filter; + int match, top = 0, val1 = 0, val2 = 0; + int stack[MAX_FILTER_PRED]; struct filter_pred *pred; int i; - if (!preds) { - trace_seq_printf(s, "none\n"); - return; + for (i = 0; i < filter->n_preds; i++) { + pred = filter->preds[i]; + if (!pred->pop_n) { + match = pred->fn(pred, rec, val1, val2); + stack[top++] = match; + continue; + } + if (pred->pop_n > top) { + WARN_ON_ONCE(1); + return 0; + } + val1 = stack[--top]; + val2 = stack[--top]; + match = pred->fn(pred, rec, val1, val2); + stack[top++] = match; } - for (i = 0; i < MAX_FILTER_PRED; i++) { - if (preds[i]) { - pred = preds[i]; - field_name = pred->field_name; - if (i) - trace_seq_printf(s, pred->or ? "|| " : "&& "); - trace_seq_printf(s, "%s ", field_name); - trace_seq_printf(s, pred->not ? "!= " : "== "); - if (pred->str_val) - trace_seq_printf(s, "%s\n", pred->str_val); - else - trace_seq_printf(s, "%llu\n", pred->val); - } else - break; - } + return stack[--top]; +} +EXPORT_SYMBOL_GPL(filter_match_preds); + +static void parse_error(struct filter_parse_state *ps, int err, int pos) +{ + ps->lasterr = err; + ps->lasterr_pos = pos; +} + +static void remove_filter_string(struct event_filter *filter) +{ + kfree(filter->filter_string); + filter->filter_string = NULL; +} + +static int replace_filter_string(struct event_filter *filter, + char *filter_string) +{ + kfree(filter->filter_string); + filter->filter_string = kstrdup(filter_string, GFP_KERNEL); + if (!filter->filter_string) + return -ENOMEM; + + return 0; +} + +static int append_filter_string(struct event_filter *filter, + char *string) +{ + int newlen; + char *new_filter_string; + + BUG_ON(!filter->filter_string); + newlen = strlen(filter->filter_string) + strlen(string) + 1; + new_filter_string = kmalloc(newlen, GFP_KERNEL); + if (!new_filter_string) + return -ENOMEM; + + strcpy(new_filter_string, filter->filter_string); + strcat(new_filter_string, string); + kfree(filter->filter_string); + filter->filter_string = new_filter_string; + + return 0; +} + +static void append_filter_err(struct filter_parse_state *ps, + struct event_filter *filter) +{ + int pos = ps->lasterr_pos; + char *buf, *pbuf; + + buf = (char *)__get_free_page(GFP_TEMPORARY); + if (!buf) + return; + + append_filter_string(filter, "\n"); + memset(buf, ' ', PAGE_SIZE); + if (pos > PAGE_SIZE - 128) + pos = 0; + buf[pos] = '^'; + pbuf = &buf[pos] + 1; + + sprintf(pbuf, "\nparse_error: %s\n", err_text[ps->lasterr]); + append_filter_string(filter, buf); + free_page((unsigned long) buf); +} + +void print_event_filter(struct ftrace_event_call *call, struct trace_seq *s) +{ + struct event_filter *filter = call->filter; + + mutex_lock(&event_mutex); + if (filter->filter_string) + trace_seq_printf(s, "%s\n", filter->filter_string); + else + trace_seq_printf(s, "none\n"); + mutex_unlock(&event_mutex); +} + +void print_subsystem_event_filter(struct event_subsystem *system, + struct trace_seq *s) +{ + struct event_filter *filter = system->filter; + + mutex_lock(&event_mutex); + if (filter->filter_string) + trace_seq_printf(s, "%s\n", filter->filter_string); + else + trace_seq_printf(s, "none\n"); + mutex_unlock(&event_mutex); } static struct ftrace_event_field * @@ -150,284 +326,829 @@ find_event_field(struct ftrace_event_call *call, char *name) return NULL; } -void filter_free_pred(struct filter_pred *pred) +static void filter_free_pred(struct filter_pred *pred) { if (!pred) return; kfree(pred->field_name); - kfree(pred->str_val); kfree(pred); } -void filter_free_preds(struct ftrace_event_call *call) +static void filter_clear_pred(struct filter_pred *pred) { - int i; - - if (call->preds) { - for (i = 0; i < MAX_FILTER_PRED; i++) - filter_free_pred(call->preds[i]); - kfree(call->preds); - call->preds = NULL; - } + kfree(pred->field_name); + pred->field_name = NULL; + pred->str_len = 0; } -void filter_free_subsystem_preds(struct event_subsystem *system) +static int filter_set_pred(struct filter_pred *dest, + struct filter_pred *src, + filter_pred_fn_t fn) { - struct ftrace_event_call *call = __start_ftrace_events; - int i; - - if (system->preds) { - for (i = 0; i < MAX_FILTER_PRED; i++) - filter_free_pred(system->preds[i]); - kfree(system->preds); - system->preds = NULL; - } - - events_for_each(call) { - if (!call->name || !call->regfunc) - continue; - - if (!strcmp(call->system, system->name)) - filter_free_preds(call); - } -} - -static int __filter_add_pred(struct ftrace_event_call *call, - struct filter_pred *pred) -{ - int i; - - if (call->preds && !pred->compound) - filter_free_preds(call); - - if (!call->preds) { - call->preds = kzalloc(MAX_FILTER_PRED * sizeof(pred), - GFP_KERNEL); - if (!call->preds) + *dest = *src; + if (src->field_name) { + dest->field_name = kstrdup(src->field_name, GFP_KERNEL); + if (!dest->field_name) return -ENOMEM; } - - for (i = 0; i < MAX_FILTER_PRED; i++) { - if (!call->preds[i]) { - call->preds[i] = pred; - return 0; - } - } - - return -ENOSPC; -} - -static int is_string_field(const char *type) -{ - if (strchr(type, '[') && strstr(type, "char")) - return 1; + dest->fn = fn; return 0; } -int filter_add_pred(struct ftrace_event_call *call, struct filter_pred *pred) +static void filter_disable_preds(struct ftrace_event_call *call) { - struct ftrace_event_field *field; - - field = find_event_field(call, pred->field_name); - if (!field) - return -EINVAL; - - pred->offset = field->offset; - - if (is_string_field(field->type)) { - if (!pred->str_val) - return -EINVAL; - pred->fn = filter_pred_string; - pred->str_len = field->size; - return __filter_add_pred(call, pred); - } else { - if (pred->str_val) - return -EINVAL; - } - - switch (field->size) { - case 8: - pred->fn = filter_pred_64; - break; - case 4: - pred->fn = filter_pred_32; - break; - case 2: - pred->fn = filter_pred_16; - break; - case 1: - pred->fn = filter_pred_8; - break; - default: - return -EINVAL; - } - - return __filter_add_pred(call, pred); -} - -static struct filter_pred *copy_pred(struct filter_pred *pred) -{ - struct filter_pred *new_pred = kmalloc(sizeof(*pred), GFP_KERNEL); - if (!new_pred) - return NULL; - - memcpy(new_pred, pred, sizeof(*pred)); - - if (pred->field_name) { - new_pred->field_name = kstrdup(pred->field_name, GFP_KERNEL); - if (!new_pred->field_name) { - kfree(new_pred); - return NULL; - } - } - - if (pred->str_val) { - new_pred->str_val = kstrdup(pred->str_val, GFP_KERNEL); - if (!new_pred->str_val) { - filter_free_pred(new_pred); - return NULL; - } - } - - return new_pred; -} - -int filter_add_subsystem_pred(struct event_subsystem *system, - struct filter_pred *pred) -{ - struct ftrace_event_call *call = __start_ftrace_events; - struct filter_pred *event_pred; + struct event_filter *filter = call->filter; int i; - if (system->preds && !pred->compound) - filter_free_subsystem_preds(system); + call->filter_active = 0; + filter->n_preds = 0; - if (!system->preds) { - system->preds = kzalloc(MAX_FILTER_PRED * sizeof(pred), - GFP_KERNEL); - if (!system->preds) - return -ENOMEM; - } + for (i = 0; i < MAX_FILTER_PRED; i++) + filter->preds[i]->fn = filter_pred_none; +} + +void destroy_preds(struct ftrace_event_call *call) +{ + struct event_filter *filter = call->filter; + int i; for (i = 0; i < MAX_FILTER_PRED; i++) { - if (!system->preds[i]) { - system->preds[i] = pred; - break; - } + if (filter->preds[i]) + filter_free_pred(filter->preds[i]); } + kfree(filter->preds); + kfree(filter->filter_string); + kfree(filter); + call->filter = NULL; +} - if (i == MAX_FILTER_PRED) - return -ENOSPC; +int init_preds(struct ftrace_event_call *call) +{ + struct event_filter *filter; + struct filter_pred *pred; + int i; - events_for_each(call) { - int err; + filter = call->filter = kzalloc(sizeof(*filter), GFP_KERNEL); + if (!call->filter) + return -ENOMEM; - if (!call->name || !call->regfunc) - continue; + call->filter_active = 0; + filter->n_preds = 0; - if (strcmp(call->system, system->name)) - continue; + filter->preds = kzalloc(MAX_FILTER_PRED * sizeof(pred), GFP_KERNEL); + if (!filter->preds) + goto oom; - if (!find_event_field(call, pred->field_name)) - continue; - - event_pred = copy_pred(pred); - if (!event_pred) - goto oom; - - err = filter_add_pred(call, event_pred); - if (err) - filter_free_pred(event_pred); - if (err == -ENOMEM) + for (i = 0; i < MAX_FILTER_PRED; i++) { + pred = kzalloc(sizeof(*pred), GFP_KERNEL); + if (!pred) goto oom; + pred->fn = filter_pred_none; + filter->preds[i] = pred; } return 0; oom: - system->preds[i] = NULL; + destroy_preds(call); + return -ENOMEM; } +EXPORT_SYMBOL_GPL(init_preds); -int filter_parse(char **pbuf, struct filter_pred *pred) +static void filter_free_subsystem_preds(struct event_subsystem *system) { - char *tmp, *tok, *val_str = NULL; - int tok_n = 0; + struct event_filter *filter = system->filter; + struct ftrace_event_call *call; + int i; - /* field ==/!= number, or/and field ==/!= number, number */ - while ((tok = strsep(pbuf, " \n"))) { - if (tok_n == 0) { - if (!strcmp(tok, "0")) { - pred->clear = 1; - return 0; - } else if (!strcmp(tok, "&&")) { - pred->or = 0; - pred->compound = 1; - } else if (!strcmp(tok, "||")) { - pred->or = 1; - pred->compound = 1; - } else - pred->field_name = tok; - tok_n = 1; - continue; - } - if (tok_n == 1) { - if (!pred->field_name) - pred->field_name = tok; - else if (!strcmp(tok, "!=")) - pred->not = 1; - else if (!strcmp(tok, "==")) - pred->not = 0; - else { - pred->field_name = NULL; - return -EINVAL; - } - tok_n = 2; - continue; - } - if (tok_n == 2) { - if (pred->compound) { - if (!strcmp(tok, "!=")) - pred->not = 1; - else if (!strcmp(tok, "==")) - pred->not = 0; - else { - pred->field_name = NULL; - return -EINVAL; - } - } else { - val_str = tok; - break; /* done */ - } - tok_n = 3; - continue; - } - if (tok_n == 3) { - val_str = tok; - break; /* done */ - } + if (filter->n_preds) { + for (i = 0; i < filter->n_preds; i++) + filter_free_pred(filter->preds[i]); + kfree(filter->preds); + filter->preds = NULL; + filter->n_preds = 0; } - if (!val_str) { - pred->field_name = NULL; - return -EINVAL; + list_for_each_entry(call, &ftrace_events, list) { + if (!call->define_fields) + continue; + + if (!strcmp(call->system, system->name)) { + filter_disable_preds(call); + remove_filter_string(call->filter); + } + } +} + +static int filter_add_pred_fn(struct filter_parse_state *ps, + struct ftrace_event_call *call, + struct filter_pred *pred, + filter_pred_fn_t fn) +{ + struct event_filter *filter = call->filter; + int idx, err; + + if (filter->n_preds == MAX_FILTER_PRED) { + parse_error(ps, FILT_ERR_TOO_MANY_PREDS, 0); + return -ENOSPC; } - pred->field_name = kstrdup(pred->field_name, GFP_KERNEL); - if (!pred->field_name) - return -ENOMEM; + idx = filter->n_preds; + filter_clear_pred(filter->preds[idx]); + err = filter_set_pred(filter->preds[idx], pred, fn); + if (err) + return err; - pred->val = simple_strtoull(val_str, &tmp, 0); - if (tmp == val_str) { - pred->str_val = kstrdup(val_str, GFP_KERNEL); - if (!pred->str_val) - return -ENOMEM; - } else if (*tmp != '\0') - return -EINVAL; + filter->n_preds++; + call->filter_active = 1; return 0; } +enum { + FILTER_STATIC_STRING = 1, + FILTER_DYN_STRING +}; + +static int is_string_field(const char *type) +{ + if (strstr(type, "__data_loc") && strstr(type, "char")) + return FILTER_DYN_STRING; + + if (strchr(type, '[') && strstr(type, "char")) + return FILTER_STATIC_STRING; + + return 0; +} + +static int is_legal_op(struct ftrace_event_field *field, int op) +{ + if (is_string_field(field->type) && (op != OP_EQ && op != OP_NE)) + return 0; + + return 1; +} + +static filter_pred_fn_t select_comparison_fn(int op, int field_size, + int field_is_signed) +{ + filter_pred_fn_t fn = NULL; + + switch (field_size) { + case 8: + if (op == OP_EQ || op == OP_NE) + fn = filter_pred_64; + else if (field_is_signed) + fn = filter_pred_s64; + else + fn = filter_pred_u64; + break; + case 4: + if (op == OP_EQ || op == OP_NE) + fn = filter_pred_32; + else if (field_is_signed) + fn = filter_pred_s32; + else + fn = filter_pred_u32; + break; + case 2: + if (op == OP_EQ || op == OP_NE) + fn = filter_pred_16; + else if (field_is_signed) + fn = filter_pred_s16; + else + fn = filter_pred_u16; + break; + case 1: + if (op == OP_EQ || op == OP_NE) + fn = filter_pred_8; + else if (field_is_signed) + fn = filter_pred_s8; + else + fn = filter_pred_u8; + break; + } + + return fn; +} + +static int filter_add_pred(struct filter_parse_state *ps, + struct ftrace_event_call *call, + struct filter_pred *pred) +{ + struct ftrace_event_field *field; + filter_pred_fn_t fn; + unsigned long long val; + int string_type; + int ret; + + pred->fn = filter_pred_none; + + if (pred->op == OP_AND) { + pred->pop_n = 2; + return filter_add_pred_fn(ps, call, pred, filter_pred_and); + } else if (pred->op == OP_OR) { + pred->pop_n = 2; + return filter_add_pred_fn(ps, call, pred, filter_pred_or); + } + + field = find_event_field(call, pred->field_name); + if (!field) { + parse_error(ps, FILT_ERR_FIELD_NOT_FOUND, 0); + return -EINVAL; + } + + pred->offset = field->offset; + + if (!is_legal_op(field, pred->op)) { + parse_error(ps, FILT_ERR_ILLEGAL_FIELD_OP, 0); + return -EINVAL; + } + + string_type = is_string_field(field->type); + if (string_type) { + if (string_type == FILTER_STATIC_STRING) + fn = filter_pred_string; + else + fn = filter_pred_strloc; + pred->str_len = field->size; + if (pred->op == OP_NE) + pred->not = 1; + return filter_add_pred_fn(ps, call, pred, fn); + } else { + if (field->is_signed) + ret = strict_strtoll(pred->str_val, 0, &val); + else + ret = strict_strtoull(pred->str_val, 0, &val); + if (ret) { + parse_error(ps, FILT_ERR_ILLEGAL_INTVAL, 0); + return -EINVAL; + } + pred->val = val; + } + + fn = select_comparison_fn(pred->op, field->size, field->is_signed); + if (!fn) { + parse_error(ps, FILT_ERR_INVALID_OP, 0); + return -EINVAL; + } + + if (pred->op == OP_NE) + pred->not = 1; + + return filter_add_pred_fn(ps, call, pred, fn); +} + +static int filter_add_subsystem_pred(struct filter_parse_state *ps, + struct event_subsystem *system, + struct filter_pred *pred, + char *filter_string) +{ + struct event_filter *filter = system->filter; + struct ftrace_event_call *call; + int err = 0; + + if (!filter->preds) { + filter->preds = kzalloc(MAX_FILTER_PRED * sizeof(pred), + GFP_KERNEL); + + if (!filter->preds) + return -ENOMEM; + } + + if (filter->n_preds == MAX_FILTER_PRED) { + parse_error(ps, FILT_ERR_TOO_MANY_PREDS, 0); + return -ENOSPC; + } + + filter->preds[filter->n_preds] = pred; + filter->n_preds++; + + list_for_each_entry(call, &ftrace_events, list) { + + if (!call->define_fields) + continue; + + if (strcmp(call->system, system->name)) + continue; + + err = filter_add_pred(ps, call, pred); + if (err) { + filter_free_subsystem_preds(system); + parse_error(ps, FILT_ERR_BAD_SUBSYS_FILTER, 0); + goto out; + } + replace_filter_string(call->filter, filter_string); + } +out: + return err; +} + +static void parse_init(struct filter_parse_state *ps, + struct filter_op *ops, + char *infix_string) +{ + memset(ps, '\0', sizeof(*ps)); + + ps->infix.string = infix_string; + ps->infix.cnt = strlen(infix_string); + ps->ops = ops; + + INIT_LIST_HEAD(&ps->opstack); + INIT_LIST_HEAD(&ps->postfix); +} + +static char infix_next(struct filter_parse_state *ps) +{ + ps->infix.cnt--; + + return ps->infix.string[ps->infix.tail++]; +} + +static char infix_peek(struct filter_parse_state *ps) +{ + if (ps->infix.tail == strlen(ps->infix.string)) + return 0; + + return ps->infix.string[ps->infix.tail]; +} + +static void infix_advance(struct filter_parse_state *ps) +{ + ps->infix.cnt--; + ps->infix.tail++; +} + +static inline int is_precedence_lower(struct filter_parse_state *ps, + int a, int b) +{ + return ps->ops[a].precedence < ps->ops[b].precedence; +} + +static inline int is_op_char(struct filter_parse_state *ps, char c) +{ + int i; + + for (i = 0; strcmp(ps->ops[i].string, "OP_NONE"); i++) { + if (ps->ops[i].string[0] == c) + return 1; + } + + return 0; +} + +static int infix_get_op(struct filter_parse_state *ps, char firstc) +{ + char nextc = infix_peek(ps); + char opstr[3]; + int i; + + opstr[0] = firstc; + opstr[1] = nextc; + opstr[2] = '\0'; + + for (i = 0; strcmp(ps->ops[i].string, "OP_NONE"); i++) { + if (!strcmp(opstr, ps->ops[i].string)) { + infix_advance(ps); + return ps->ops[i].id; + } + } + + opstr[1] = '\0'; + + for (i = 0; strcmp(ps->ops[i].string, "OP_NONE"); i++) { + if (!strcmp(opstr, ps->ops[i].string)) + return ps->ops[i].id; + } + + return OP_NONE; +} + +static inline void clear_operand_string(struct filter_parse_state *ps) +{ + memset(ps->operand.string, '\0', MAX_FILTER_STR_VAL); + ps->operand.tail = 0; +} + +static inline int append_operand_char(struct filter_parse_state *ps, char c) +{ + if (ps->operand.tail == MAX_FILTER_STR_VAL - 1) + return -EINVAL; + + ps->operand.string[ps->operand.tail++] = c; + + return 0; +} + +static int filter_opstack_push(struct filter_parse_state *ps, int op) +{ + struct opstack_op *opstack_op; + + opstack_op = kmalloc(sizeof(*opstack_op), GFP_KERNEL); + if (!opstack_op) + return -ENOMEM; + + opstack_op->op = op; + list_add(&opstack_op->list, &ps->opstack); + + return 0; +} + +static int filter_opstack_empty(struct filter_parse_state *ps) +{ + return list_empty(&ps->opstack); +} + +static int filter_opstack_top(struct filter_parse_state *ps) +{ + struct opstack_op *opstack_op; + + if (filter_opstack_empty(ps)) + return OP_NONE; + + opstack_op = list_first_entry(&ps->opstack, struct opstack_op, list); + + return opstack_op->op; +} + +static int filter_opstack_pop(struct filter_parse_state *ps) +{ + struct opstack_op *opstack_op; + int op; + + if (filter_opstack_empty(ps)) + return OP_NONE; + + opstack_op = list_first_entry(&ps->opstack, struct opstack_op, list); + op = opstack_op->op; + list_del(&opstack_op->list); + + kfree(opstack_op); + + return op; +} + +static void filter_opstack_clear(struct filter_parse_state *ps) +{ + while (!filter_opstack_empty(ps)) + filter_opstack_pop(ps); +} + +static char *curr_operand(struct filter_parse_state *ps) +{ + return ps->operand.string; +} + +static int postfix_append_operand(struct filter_parse_state *ps, char *operand) +{ + struct postfix_elt *elt; + + elt = kmalloc(sizeof(*elt), GFP_KERNEL); + if (!elt) + return -ENOMEM; + + elt->op = OP_NONE; + elt->operand = kstrdup(operand, GFP_KERNEL); + if (!elt->operand) { + kfree(elt); + return -ENOMEM; + } + + list_add_tail(&elt->list, &ps->postfix); + + return 0; +} + +static int postfix_append_op(struct filter_parse_state *ps, int op) +{ + struct postfix_elt *elt; + + elt = kmalloc(sizeof(*elt), GFP_KERNEL); + if (!elt) + return -ENOMEM; + + elt->op = op; + elt->operand = NULL; + + list_add_tail(&elt->list, &ps->postfix); + + return 0; +} + +static void postfix_clear(struct filter_parse_state *ps) +{ + struct postfix_elt *elt; + + while (!list_empty(&ps->postfix)) { + elt = list_first_entry(&ps->postfix, struct postfix_elt, list); + kfree(elt->operand); + list_del(&elt->list); + } +} + +static int filter_parse(struct filter_parse_state *ps) +{ + int in_string = 0; + int op, top_op; + char ch; + + while ((ch = infix_next(ps))) { + if (ch == '"') { + in_string ^= 1; + continue; + } + + if (in_string) + goto parse_operand; + + if (isspace(ch)) + continue; + + if (is_op_char(ps, ch)) { + op = infix_get_op(ps, ch); + if (op == OP_NONE) { + parse_error(ps, FILT_ERR_INVALID_OP, 0); + return -EINVAL; + } + + if (strlen(curr_operand(ps))) { + postfix_append_operand(ps, curr_operand(ps)); + clear_operand_string(ps); + } + + while (!filter_opstack_empty(ps)) { + top_op = filter_opstack_top(ps); + if (!is_precedence_lower(ps, top_op, op)) { + top_op = filter_opstack_pop(ps); + postfix_append_op(ps, top_op); + continue; + } + break; + } + + filter_opstack_push(ps, op); + continue; + } + + if (ch == '(') { + filter_opstack_push(ps, OP_OPEN_PAREN); + continue; + } + + if (ch == ')') { + if (strlen(curr_operand(ps))) { + postfix_append_operand(ps, curr_operand(ps)); + clear_operand_string(ps); + } + + top_op = filter_opstack_pop(ps); + while (top_op != OP_NONE) { + if (top_op == OP_OPEN_PAREN) + break; + postfix_append_op(ps, top_op); + top_op = filter_opstack_pop(ps); + } + if (top_op == OP_NONE) { + parse_error(ps, FILT_ERR_UNBALANCED_PAREN, 0); + return -EINVAL; + } + continue; + } +parse_operand: + if (append_operand_char(ps, ch)) { + parse_error(ps, FILT_ERR_OPERAND_TOO_LONG, 0); + return -EINVAL; + } + } + + if (strlen(curr_operand(ps))) + postfix_append_operand(ps, curr_operand(ps)); + + while (!filter_opstack_empty(ps)) { + top_op = filter_opstack_pop(ps); + if (top_op == OP_NONE) + break; + if (top_op == OP_OPEN_PAREN) { + parse_error(ps, FILT_ERR_UNBALANCED_PAREN, 0); + return -EINVAL; + } + postfix_append_op(ps, top_op); + } + + return 0; +} + +static struct filter_pred *create_pred(int op, char *operand1, char *operand2) +{ + struct filter_pred *pred; + + pred = kzalloc(sizeof(*pred), GFP_KERNEL); + if (!pred) + return NULL; + + pred->field_name = kstrdup(operand1, GFP_KERNEL); + if (!pred->field_name) { + kfree(pred); + return NULL; + } + + strcpy(pred->str_val, operand2); + pred->str_len = strlen(operand2); + + pred->op = op; + + return pred; +} + +static struct filter_pred *create_logical_pred(int op) +{ + struct filter_pred *pred; + + pred = kzalloc(sizeof(*pred), GFP_KERNEL); + if (!pred) + return NULL; + + pred->op = op; + + return pred; +} + +static int check_preds(struct filter_parse_state *ps) +{ + int n_normal_preds = 0, n_logical_preds = 0; + struct postfix_elt *elt; + + list_for_each_entry(elt, &ps->postfix, list) { + if (elt->op == OP_NONE) + continue; + + if (elt->op == OP_AND || elt->op == OP_OR) { + n_logical_preds++; + continue; + } + n_normal_preds++; + } + + if (!n_normal_preds || n_logical_preds >= n_normal_preds) { + parse_error(ps, FILT_ERR_INVALID_FILTER, 0); + return -EINVAL; + } + + return 0; +} + +static int replace_preds(struct event_subsystem *system, + struct ftrace_event_call *call, + struct filter_parse_state *ps, + char *filter_string) +{ + char *operand1 = NULL, *operand2 = NULL; + struct filter_pred *pred; + struct postfix_elt *elt; + int err; + + err = check_preds(ps); + if (err) + return err; + + list_for_each_entry(elt, &ps->postfix, list) { + if (elt->op == OP_NONE) { + if (!operand1) + operand1 = elt->operand; + else if (!operand2) + operand2 = elt->operand; + else { + parse_error(ps, FILT_ERR_TOO_MANY_OPERANDS, 0); + return -EINVAL; + } + continue; + } + + if (elt->op == OP_AND || elt->op == OP_OR) { + pred = create_logical_pred(elt->op); + if (call) { + err = filter_add_pred(ps, call, pred); + filter_free_pred(pred); + } else + err = filter_add_subsystem_pred(ps, system, + pred, filter_string); + if (err) + return err; + + operand1 = operand2 = NULL; + continue; + } + + if (!operand1 || !operand2) { + parse_error(ps, FILT_ERR_MISSING_FIELD, 0); + return -EINVAL; + } + + pred = create_pred(elt->op, operand1, operand2); + if (call) { + err = filter_add_pred(ps, call, pred); + filter_free_pred(pred); + } else + err = filter_add_subsystem_pred(ps, system, pred, + filter_string); + if (err) + return err; + + operand1 = operand2 = NULL; + } + + return 0; +} + +int apply_event_filter(struct ftrace_event_call *call, char *filter_string) +{ + int err; + + struct filter_parse_state *ps; + + mutex_lock(&event_mutex); + + if (!strcmp(strstrip(filter_string), "0")) { + filter_disable_preds(call); + remove_filter_string(call->filter); + mutex_unlock(&event_mutex); + return 0; + } + + err = -ENOMEM; + ps = kzalloc(sizeof(*ps), GFP_KERNEL); + if (!ps) + goto out_unlock; + + filter_disable_preds(call); + replace_filter_string(call->filter, filter_string); + + parse_init(ps, filter_ops, filter_string); + err = filter_parse(ps); + if (err) { + append_filter_err(ps, call->filter); + goto out; + } + + err = replace_preds(NULL, call, ps, filter_string); + if (err) + append_filter_err(ps, call->filter); + +out: + filter_opstack_clear(ps); + postfix_clear(ps); + kfree(ps); +out_unlock: + mutex_unlock(&event_mutex); + + return err; +} + +int apply_subsystem_event_filter(struct event_subsystem *system, + char *filter_string) +{ + int err; + + struct filter_parse_state *ps; + + mutex_lock(&event_mutex); + + if (!strcmp(strstrip(filter_string), "0")) { + filter_free_subsystem_preds(system); + remove_filter_string(system->filter); + mutex_unlock(&event_mutex); + return 0; + } + + err = -ENOMEM; + ps = kzalloc(sizeof(*ps), GFP_KERNEL); + if (!ps) + goto out_unlock; + + filter_free_subsystem_preds(system); + replace_filter_string(system->filter, filter_string); + + parse_init(ps, filter_ops, filter_string); + err = filter_parse(ps); + if (err) { + append_filter_err(ps, system->filter); + goto out; + } + + err = replace_preds(system, NULL, ps, filter_string); + if (err) + append_filter_err(ps, system->filter); + +out: + filter_opstack_clear(ps); + postfix_clear(ps); + kfree(ps); +out_unlock: + mutex_unlock(&event_mutex); + + return err; +} diff --git a/kernel/trace/trace_events_stage_1.h b/kernel/trace/trace_events_stage_1.h deleted file mode 100644 index 38985f9b379c..000000000000 --- a/kernel/trace/trace_events_stage_1.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Stage 1 of the trace events. - * - * Override the macros in to include the following: - * - * struct ftrace_raw_ { - * struct trace_entry ent; - * ; - * []; - * [...] - * }; - * - * The is created by the __field(type, item) macro or - * the __array(type2, item2, len) macro. - * We simply do "type item;", and that will create the fields - * in the structure. - */ - -#undef TRACE_FORMAT -#define TRACE_FORMAT(call, proto, args, fmt) - -#undef __array -#define __array(type, item, len) type item[len]; - -#undef __field -#define __field(type, item) type item; - -#undef TP_STRUCT__entry -#define TP_STRUCT__entry(args...) args - -#undef TRACE_EVENT -#define TRACE_EVENT(name, proto, args, tstruct, assign, print) \ - struct ftrace_raw_##name { \ - struct trace_entry ent; \ - tstruct \ - }; \ - static struct ftrace_event_call event_##name - -#include diff --git a/kernel/trace/trace_events_stage_2.h b/kernel/trace/trace_events_stage_2.h deleted file mode 100644 index d363c6672c6c..000000000000 --- a/kernel/trace/trace_events_stage_2.h +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Stage 2 of the trace events. - * - * Override the macros in to include the following: - * - * enum print_line_t - * ftrace_raw_output_(struct trace_iterator *iter, int flags) - * { - * struct trace_seq *s = &iter->seq; - * struct ftrace_raw_ *field; <-- defined in stage 1 - * struct trace_entry *entry; - * int ret; - * - * entry = iter->ent; - * - * if (entry->type != event_.id) { - * WARN_ON_ONCE(1); - * return TRACE_TYPE_UNHANDLED; - * } - * - * field = (typeof(field))entry; - * - * ret = trace_seq_printf(s, "\n"); - * if (!ret) - * return TRACE_TYPE_PARTIAL_LINE; - * - * return TRACE_TYPE_HANDLED; - * } - * - * This is the method used to print the raw event to the trace - * output format. Note, this is not needed if the data is read - * in binary. - */ - -#undef __entry -#define __entry field - -#undef TP_printk -#define TP_printk(fmt, args...) fmt "\n", args - -#undef TRACE_EVENT -#define TRACE_EVENT(call, proto, args, tstruct, assign, print) \ -enum print_line_t \ -ftrace_raw_output_##call(struct trace_iterator *iter, int flags) \ -{ \ - struct trace_seq *s = &iter->seq; \ - struct ftrace_raw_##call *field; \ - struct trace_entry *entry; \ - int ret; \ - \ - entry = iter->ent; \ - \ - if (entry->type != event_##call.id) { \ - WARN_ON_ONCE(1); \ - return TRACE_TYPE_UNHANDLED; \ - } \ - \ - field = (typeof(field))entry; \ - \ - ret = trace_seq_printf(s, #call ": " print); \ - if (!ret) \ - return TRACE_TYPE_PARTIAL_LINE; \ - \ - return TRACE_TYPE_HANDLED; \ -} - -#include - -/* - * Setup the showing format of trace point. - * - * int - * ftrace_format_##call(struct trace_seq *s) - * { - * struct ftrace_raw_##call field; - * int ret; - * - * ret = trace_seq_printf(s, #type " " #item ";" - * " offset:%u; size:%u;\n", - * offsetof(struct ftrace_raw_##call, item), - * sizeof(field.type)); - * - * } - */ - -#undef TP_STRUCT__entry -#define TP_STRUCT__entry(args...) args - -#undef __field -#define __field(type, item) \ - ret = trace_seq_printf(s, "\tfield:" #type " " #item ";\t" \ - "offset:%u;\tsize:%u;\n", \ - (unsigned int)offsetof(typeof(field), item), \ - (unsigned int)sizeof(field.item)); \ - if (!ret) \ - return 0; - -#undef __array -#define __array(type, item, len) \ - ret = trace_seq_printf(s, "\tfield:" #type " " #item "[" #len "];\t" \ - "offset:%u;\tsize:%u;\n", \ - (unsigned int)offsetof(typeof(field), item), \ - (unsigned int)sizeof(field.item)); \ - if (!ret) \ - return 0; - -#undef __entry -#define __entry REC - -#undef TP_printk -#define TP_printk(fmt, args...) "%s, %s\n", #fmt, __stringify(args) - -#undef TP_fast_assign -#define TP_fast_assign(args...) args - -#undef TRACE_EVENT -#define TRACE_EVENT(call, proto, args, tstruct, func, print) \ -static int \ -ftrace_format_##call(struct trace_seq *s) \ -{ \ - struct ftrace_raw_##call field; \ - int ret; \ - \ - tstruct; \ - \ - trace_seq_printf(s, "\nprint fmt: " print); \ - \ - return ret; \ -} - -#include - -#undef __field -#define __field(type, item) \ - ret = trace_define_field(event_call, #type, #item, \ - offsetof(typeof(field), item), \ - sizeof(field.item)); \ - if (ret) \ - return ret; - -#undef __array -#define __array(type, item, len) \ - ret = trace_define_field(event_call, #type "[" #len "]", #item, \ - offsetof(typeof(field), item), \ - sizeof(field.item)); \ - if (ret) \ - return ret; - -#define __common_field(type, item) \ - ret = trace_define_field(event_call, #type, "common_" #item, \ - offsetof(typeof(field.ent), item), \ - sizeof(field.ent.item)); \ - if (ret) \ - return ret; - -#undef TRACE_EVENT -#define TRACE_EVENT(call, proto, args, tstruct, func, print) \ -int \ -ftrace_define_fields_##call(void) \ -{ \ - struct ftrace_raw_##call field; \ - struct ftrace_event_call *event_call = &event_##call; \ - int ret; \ - \ - __common_field(unsigned char, type); \ - __common_field(unsigned char, flags); \ - __common_field(unsigned char, preempt_count); \ - __common_field(int, pid); \ - __common_field(int, tgid); \ - \ - tstruct; \ - \ - return ret; \ -} - -#include diff --git a/kernel/trace/trace_events_stage_3.h b/kernel/trace/trace_events_stage_3.h deleted file mode 100644 index 9d2fa78cecca..000000000000 --- a/kernel/trace/trace_events_stage_3.h +++ /dev/null @@ -1,281 +0,0 @@ -/* - * Stage 3 of the trace events. - * - * Override the macros in to include the following: - * - * static void ftrace_event_(proto) - * { - * event_trace_printk(_RET_IP_, ": " ); - * } - * - * static int ftrace_reg_event_(void) - * { - * int ret; - * - * ret = register_trace_(ftrace_event_); - * if (!ret) - * pr_info("event trace: Could not activate trace point " - * "probe to "); - * return ret; - * } - * - * static void ftrace_unreg_event_(void) - * { - * unregister_trace_(ftrace_event_); - * } - * - * For those macros defined with TRACE_FORMAT: - * - * static struct ftrace_event_call __used - * __attribute__((__aligned__(4))) - * __attribute__((section("_ftrace_events"))) event_ = { - * .name = "", - * .regfunc = ftrace_reg_event_, - * .unregfunc = ftrace_unreg_event_, - * } - * - * - * For those macros defined with TRACE_EVENT: - * - * static struct ftrace_event_call event_; - * - * static void ftrace_raw_event_(proto) - * { - * struct ring_buffer_event *event; - * struct ftrace_raw_ *entry; <-- defined in stage 1 - * unsigned long irq_flags; - * int pc; - * - * local_save_flags(irq_flags); - * pc = preempt_count(); - * - * event = trace_current_buffer_lock_reserve(event_.id, - * sizeof(struct ftrace_raw_), - * irq_flags, pc); - * if (!event) - * return; - * entry = ring_buffer_event_data(event); - * - * ; <-- Here we assign the entries by the __field and - * __array macros. - * - * trace_current_buffer_unlock_commit(event, irq_flags, pc); - * } - * - * static int ftrace_raw_reg_event_(void) - * { - * int ret; - * - * ret = register_trace_(ftrace_raw_event_); - * if (!ret) - * pr_info("event trace: Could not activate trace point " - * "probe to "); - * return ret; - * } - * - * static void ftrace_unreg_event_(void) - * { - * unregister_trace_(ftrace_raw_event_); - * } - * - * static struct trace_event ftrace_event_type_ = { - * .trace = ftrace_raw_output_, <-- stage 2 - * }; - * - * static int ftrace_raw_init_event_(void) - * { - * int id; - * - * id = register_ftrace_event(&ftrace_event_type_); - * if (!id) - * return -ENODEV; - * event_.id = id; - * return 0; - * } - * - * static struct ftrace_event_call __used - * __attribute__((__aligned__(4))) - * __attribute__((section("_ftrace_events"))) event_ = { - * .name = "", - * .system = "", - * .raw_init = ftrace_raw_init_event_, - * .regfunc = ftrace_reg_event_, - * .unregfunc = ftrace_unreg_event_, - * .show_format = ftrace_format_, - * } - * - */ - -#undef TP_FMT -#define TP_FMT(fmt, args...) fmt "\n", ##args - -#ifdef CONFIG_EVENT_PROFILE -#define _TRACE_PROFILE(call, proto, args) \ -static void ftrace_profile_##call(proto) \ -{ \ - extern void perf_tpcounter_event(int); \ - perf_tpcounter_event(event_##call.id); \ -} \ - \ -static int ftrace_profile_enable_##call(struct ftrace_event_call *call) \ -{ \ - int ret = 0; \ - \ - if (!atomic_inc_return(&call->profile_count)) \ - ret = register_trace_##call(ftrace_profile_##call); \ - \ - return ret; \ -} \ - \ -static void ftrace_profile_disable_##call(struct ftrace_event_call *call) \ -{ \ - if (atomic_add_negative(-1, &call->profile_count)) \ - unregister_trace_##call(ftrace_profile_##call); \ -} - -#define _TRACE_PROFILE_INIT(call) \ - .profile_count = ATOMIC_INIT(-1), \ - .profile_enable = ftrace_profile_enable_##call, \ - .profile_disable = ftrace_profile_disable_##call, - -#else -#define _TRACE_PROFILE(call, proto, args) -#define _TRACE_PROFILE_INIT(call) -#endif - -#define _TRACE_FORMAT(call, proto, args, fmt) \ -static void ftrace_event_##call(proto) \ -{ \ - event_trace_printk(_RET_IP_, #call ": " fmt); \ -} \ - \ -static int ftrace_reg_event_##call(void) \ -{ \ - int ret; \ - \ - ret = register_trace_##call(ftrace_event_##call); \ - if (ret) \ - pr_info("event trace: Could not activate trace point " \ - "probe to " #call "\n"); \ - return ret; \ -} \ - \ -static void ftrace_unreg_event_##call(void) \ -{ \ - unregister_trace_##call(ftrace_event_##call); \ -} \ - \ -static struct ftrace_event_call event_##call; \ - \ -static int ftrace_init_event_##call(void) \ -{ \ - int id; \ - \ - id = register_ftrace_event(NULL); \ - if (!id) \ - return -ENODEV; \ - event_##call.id = id; \ - return 0; \ -} - -#undef TRACE_FORMAT -#define TRACE_FORMAT(call, proto, args, fmt) \ -_TRACE_FORMAT(call, PARAMS(proto), PARAMS(args), PARAMS(fmt)) \ -_TRACE_PROFILE(call, PARAMS(proto), PARAMS(args)) \ -static struct ftrace_event_call __used \ -__attribute__((__aligned__(4))) \ -__attribute__((section("_ftrace_events"))) event_##call = { \ - .name = #call, \ - .system = __stringify(TRACE_SYSTEM), \ - .raw_init = ftrace_init_event_##call, \ - .regfunc = ftrace_reg_event_##call, \ - .unregfunc = ftrace_unreg_event_##call, \ - _TRACE_PROFILE_INIT(call) \ -} - -#undef __entry -#define __entry entry - -#undef TRACE_EVENT -#define TRACE_EVENT(call, proto, args, tstruct, assign, print) \ -_TRACE_PROFILE(call, PARAMS(proto), PARAMS(args)) \ - \ -static struct ftrace_event_call event_##call; \ - \ -static void ftrace_raw_event_##call(proto) \ -{ \ - struct ftrace_event_call *call = &event_##call; \ - struct ring_buffer_event *event; \ - struct ftrace_raw_##call *entry; \ - unsigned long irq_flags; \ - int pc; \ - \ - local_save_flags(irq_flags); \ - pc = preempt_count(); \ - \ - event = trace_current_buffer_lock_reserve(event_##call.id, \ - sizeof(struct ftrace_raw_##call), \ - irq_flags, pc); \ - if (!event) \ - return; \ - entry = ring_buffer_event_data(event); \ - \ - assign; \ - \ - if (call->preds && !filter_match_preds(call, entry)) \ - ring_buffer_event_discard(event); \ - \ - trace_nowake_buffer_unlock_commit(event, irq_flags, pc); \ - \ -} \ - \ -static int ftrace_raw_reg_event_##call(void) \ -{ \ - int ret; \ - \ - ret = register_trace_##call(ftrace_raw_event_##call); \ - if (ret) \ - pr_info("event trace: Could not activate trace point " \ - "probe to " #call "\n"); \ - return ret; \ -} \ - \ -static void ftrace_raw_unreg_event_##call(void) \ -{ \ - unregister_trace_##call(ftrace_raw_event_##call); \ -} \ - \ -static struct trace_event ftrace_event_type_##call = { \ - .trace = ftrace_raw_output_##call, \ -}; \ - \ -static int ftrace_raw_init_event_##call(void) \ -{ \ - int id; \ - \ - id = register_ftrace_event(&ftrace_event_type_##call); \ - if (!id) \ - return -ENODEV; \ - event_##call.id = id; \ - INIT_LIST_HEAD(&event_##call.fields); \ - return 0; \ -} \ - \ -static struct ftrace_event_call __used \ -__attribute__((__aligned__(4))) \ -__attribute__((section("_ftrace_events"))) event_##call = { \ - .name = #call, \ - .system = __stringify(TRACE_SYSTEM), \ - .raw_init = ftrace_raw_init_event_##call, \ - .regfunc = ftrace_raw_reg_event_##call, \ - .unregfunc = ftrace_raw_unreg_event_##call, \ - .show_format = ftrace_format_##call, \ - .define_fields = ftrace_define_fields_##call, \ - _TRACE_PROFILE_INIT(call) \ -} - -#include - -#undef _TRACE_PROFILE -#undef _TRACE_PROFILE_INIT - diff --git a/kernel/trace/trace_export.c b/kernel/trace/trace_export.c index 07a22c33ebf3..d06cf898dc86 100644 --- a/kernel/trace/trace_export.c +++ b/kernel/trace/trace_export.c @@ -19,8 +19,12 @@ #undef TRACE_STRUCT #define TRACE_STRUCT(args...) args +extern void __bad_type_size(void); + #undef TRACE_FIELD #define TRACE_FIELD(type, item, assign) \ + if (sizeof(type) != sizeof(field.item)) \ + __bad_type_size(); \ ret = trace_seq_printf(s, "\tfield:" #type " " #item ";\t" \ "offset:%u;\tsize:%u;\n", \ (unsigned int)offsetof(typeof(field), item), \ @@ -30,7 +34,7 @@ #undef TRACE_FIELD_SPECIAL -#define TRACE_FIELD_SPECIAL(type_item, item, cmd) \ +#define TRACE_FIELD_SPECIAL(type_item, item, len, cmd) \ ret = trace_seq_printf(s, "\tfield special:" #type_item ";\t" \ "offset:%u;\tsize:%u;\n", \ (unsigned int)offsetof(typeof(field), item), \ @@ -46,6 +50,9 @@ if (!ret) \ return 0; +#undef TRACE_FIELD_SIGN +#define TRACE_FIELD_SIGN(type, item, assign, is_signed) \ + TRACE_FIELD(type, item, assign) #undef TP_RAW_FMT #define TP_RAW_FMT(args...) args @@ -65,6 +72,22 @@ ftrace_format_##call(struct trace_seq *s) \ return ret; \ } +#undef TRACE_EVENT_FORMAT_NOFILTER +#define TRACE_EVENT_FORMAT_NOFILTER(call, proto, args, fmt, tstruct, \ + tpfmt) \ +static int \ +ftrace_format_##call(struct trace_seq *s) \ +{ \ + struct args field; \ + int ret; \ + \ + tstruct; \ + \ + trace_seq_printf(s, "\nprint fmt: \"%s\"\n", tpfmt); \ + \ + return ret; \ +} + #include "trace_event_types.h" #undef TRACE_ZERO_CHAR @@ -78,6 +101,10 @@ ftrace_format_##call(struct trace_seq *s) \ #define TRACE_FIELD(type, item, assign)\ entry->item = assign; +#undef TRACE_FIELD_SIGN +#define TRACE_FIELD_SIGN(type, item, assign, is_signed) \ + TRACE_FIELD(type, item, assign) + #undef TP_CMD #define TP_CMD(cmd...) cmd @@ -85,18 +112,95 @@ ftrace_format_##call(struct trace_seq *s) \ #define TRACE_ENTRY entry #undef TRACE_FIELD_SPECIAL -#define TRACE_FIELD_SPECIAL(type_item, item, cmd) \ +#define TRACE_FIELD_SPECIAL(type_item, item, len, cmd) \ cmd; #undef TRACE_EVENT_FORMAT #define TRACE_EVENT_FORMAT(call, proto, args, fmt, tstruct, tpfmt) \ +int ftrace_define_fields_##call(void); \ +static int ftrace_raw_init_event_##call(void); \ \ -static struct ftrace_event_call __used \ +struct ftrace_event_call __used \ +__attribute__((__aligned__(4))) \ +__attribute__((section("_ftrace_events"))) event_##call = { \ + .name = #call, \ + .id = proto, \ + .system = __stringify(TRACE_SYSTEM), \ + .raw_init = ftrace_raw_init_event_##call, \ + .show_format = ftrace_format_##call, \ + .define_fields = ftrace_define_fields_##call, \ +}; \ +static int ftrace_raw_init_event_##call(void) \ +{ \ + INIT_LIST_HEAD(&event_##call.fields); \ + init_preds(&event_##call); \ + return 0; \ +} \ + +#undef TRACE_EVENT_FORMAT_NOFILTER +#define TRACE_EVENT_FORMAT_NOFILTER(call, proto, args, fmt, tstruct, \ + tpfmt) \ + \ +struct ftrace_event_call __used \ __attribute__((__aligned__(4))) \ __attribute__((section("_ftrace_events"))) event_##call = { \ .name = #call, \ .id = proto, \ .system = __stringify(TRACE_SYSTEM), \ .show_format = ftrace_format_##call, \ -} +}; + +#include "trace_event_types.h" + +#undef TRACE_FIELD +#define TRACE_FIELD(type, item, assign) \ + ret = trace_define_field(event_call, #type, #item, \ + offsetof(typeof(field), item), \ + sizeof(field.item), is_signed_type(type)); \ + if (ret) \ + return ret; + +#undef TRACE_FIELD_SPECIAL +#define TRACE_FIELD_SPECIAL(type, item, len, cmd) \ + ret = trace_define_field(event_call, #type "[" #len "]", #item, \ + offsetof(typeof(field), item), \ + sizeof(field.item), 0); \ + if (ret) \ + return ret; + +#undef TRACE_FIELD_SIGN +#define TRACE_FIELD_SIGN(type, item, assign, is_signed) \ + ret = trace_define_field(event_call, #type, #item, \ + offsetof(typeof(field), item), \ + sizeof(field.item), is_signed); \ + if (ret) \ + return ret; + +#undef TRACE_FIELD_ZERO_CHAR +#define TRACE_FIELD_ZERO_CHAR(item) + +#undef TRACE_EVENT_FORMAT +#define TRACE_EVENT_FORMAT(call, proto, args, fmt, tstruct, tpfmt) \ +int \ +ftrace_define_fields_##call(void) \ +{ \ + struct ftrace_event_call *event_call = &event_##call; \ + struct args field; \ + int ret; \ + \ + __common_field(unsigned char, type, 0); \ + __common_field(unsigned char, flags, 0); \ + __common_field(unsigned char, preempt_count, 0); \ + __common_field(int, pid, 1); \ + __common_field(int, tgid, 1); \ + \ + tstruct; \ + \ + return ret; \ +} + +#undef TRACE_EVENT_FORMAT_NOFILTER +#define TRACE_EVENT_FORMAT_NOFILTER(call, proto, args, fmt, tstruct, \ + tpfmt) + #include "trace_event_types.h" diff --git a/kernel/trace/trace_functions.c b/kernel/trace/trace_functions.c index c9a0b7df44ff..90f134764837 100644 --- a/kernel/trace/trace_functions.c +++ b/kernel/trace/trace_functions.c @@ -193,9 +193,11 @@ static void tracing_start_function_trace(void) static void tracing_stop_function_trace(void) { ftrace_function_enabled = 0; - /* OK if they are not registered */ - unregister_ftrace_function(&trace_stack_ops); - unregister_ftrace_function(&trace_ops); + + if (func_flags.val & TRACE_FUNC_OPT_STACK) + unregister_ftrace_function(&trace_stack_ops); + else + unregister_ftrace_function(&trace_ops); } static int func_set_flag(u32 old_flags, u32 bit, int set) diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c index d28687e7b3a7..d2249abafb53 100644 --- a/kernel/trace/trace_functions_graph.c +++ b/kernel/trace/trace_functions_graph.c @@ -57,7 +57,8 @@ static struct tracer_flags tracer_flags = { /* Add a function return address to the trace stack on thread info.*/ int -ftrace_push_return_trace(unsigned long ret, unsigned long func, int *depth) +ftrace_push_return_trace(unsigned long ret, unsigned long func, int *depth, + unsigned long frame_pointer) { unsigned long long calltime; int index; @@ -65,6 +66,12 @@ ftrace_push_return_trace(unsigned long ret, unsigned long func, int *depth) if (!current->ret_stack) return -EBUSY; + /* + * We must make sure the ret_stack is tested before we read + * anything else. + */ + smp_rmb(); + /* The return trace stack is full */ if (current->curr_ret_stack == FTRACE_RETFUNC_DEPTH - 1) { atomic_inc(¤t->trace_overrun); @@ -78,14 +85,17 @@ ftrace_push_return_trace(unsigned long ret, unsigned long func, int *depth) current->ret_stack[index].ret = ret; current->ret_stack[index].func = func; current->ret_stack[index].calltime = calltime; + current->ret_stack[index].subtime = 0; + current->ret_stack[index].fp = frame_pointer; *depth = index; return 0; } /* Retrieve a function return address to the trace stack on thread info.*/ -void -ftrace_pop_return_trace(struct ftrace_graph_ret *trace, unsigned long *ret) +static void +ftrace_pop_return_trace(struct ftrace_graph_ret *trace, unsigned long *ret, + unsigned long frame_pointer) { int index; @@ -99,28 +109,52 @@ ftrace_pop_return_trace(struct ftrace_graph_ret *trace, unsigned long *ret) return; } +#ifdef CONFIG_HAVE_FUNCTION_GRAPH_FP_TEST + /* + * The arch may choose to record the frame pointer used + * and check it here to make sure that it is what we expect it + * to be. If gcc does not set the place holder of the return + * address in the frame pointer, and does a copy instead, then + * the function graph trace will fail. This test detects this + * case. + * + * Currently, x86_32 with optimize for size (-Os) makes the latest + * gcc do the above. + */ + if (unlikely(current->ret_stack[index].fp != frame_pointer)) { + ftrace_graph_stop(); + WARN(1, "Bad frame pointer: expected %lx, received %lx\n" + " from func %pF return to %lx\n", + current->ret_stack[index].fp, + frame_pointer, + (void *)current->ret_stack[index].func, + current->ret_stack[index].ret); + *ret = (unsigned long)panic; + return; + } +#endif + *ret = current->ret_stack[index].ret; trace->func = current->ret_stack[index].func; trace->calltime = current->ret_stack[index].calltime; trace->overrun = atomic_read(¤t->trace_overrun); trace->depth = index; - barrier(); - current->curr_ret_stack--; - } /* * Send the trace to the ring-buffer. * @return the original return address. */ -unsigned long ftrace_return_to_handler(void) +unsigned long ftrace_return_to_handler(unsigned long frame_pointer) { struct ftrace_graph_ret trace; unsigned long ret; - ftrace_pop_return_trace(&trace, &ret); + ftrace_pop_return_trace(&trace, &ret, frame_pointer); trace.rettime = trace_clock_local(); ftrace_graph_return(&trace); + barrier(); + current->curr_ret_stack--; if (unlikely(!ret)) { ftrace_graph_stop(); @@ -426,8 +460,8 @@ print_graph_irq(struct trace_iterator *iter, unsigned long addr, return TRACE_TYPE_HANDLED; } -static enum print_line_t -print_graph_duration(unsigned long long duration, struct trace_seq *s) +enum print_line_t +trace_print_graph_duration(unsigned long long duration, struct trace_seq *s) { unsigned long nsecs_rem = do_div(duration, 1000); /* log10(ULONG_MAX) + '\0' */ @@ -464,12 +498,23 @@ print_graph_duration(unsigned long long duration, struct trace_seq *s) if (!ret) return TRACE_TYPE_PARTIAL_LINE; } + return TRACE_TYPE_HANDLED; +} + +static enum print_line_t +print_graph_duration(unsigned long long duration, struct trace_seq *s) +{ + int ret; + + ret = trace_print_graph_duration(duration, s); + if (ret != TRACE_TYPE_HANDLED) + return ret; ret = trace_seq_printf(s, "| "); if (!ret) return TRACE_TYPE_PARTIAL_LINE; - return TRACE_TYPE_HANDLED; + return TRACE_TYPE_HANDLED; } /* Case of a leaf function on its call entry */ diff --git a/kernel/trace/trace_hw_branches.c b/kernel/trace/trace_hw_branches.c index 7bfdf4c2347f..ca7d7c4d0c2a 100644 --- a/kernel/trace/trace_hw_branches.c +++ b/kernel/trace/trace_hw_branches.c @@ -1,10 +1,9 @@ /* - * h/w branch tracer for x86 based on bts + * h/w branch tracer for x86 based on BTS * * Copyright (C) 2008-2009 Intel Corporation. * Markus Metzger , 2008-2009 */ -#include #include #include #include @@ -15,110 +14,119 @@ #include -#include "trace.h" #include "trace_output.h" +#include "trace.h" -#define SIZEOF_BTS (1 << 13) +#define BTS_BUFFER_SIZE (1 << 13) -/* - * The tracer lock protects the below per-cpu tracer array. - * It needs to be held to: - * - start tracing on all cpus - * - stop tracing on all cpus - * - start tracing on a single hotplug cpu - * - stop tracing on a single hotplug cpu - * - read the trace from all cpus - * - read the trace from a single cpu - */ -static DEFINE_SPINLOCK(bts_tracer_lock); static DEFINE_PER_CPU(struct bts_tracer *, tracer); -static DEFINE_PER_CPU(unsigned char[SIZEOF_BTS], buffer); +static DEFINE_PER_CPU(unsigned char[BTS_BUFFER_SIZE], buffer); #define this_tracer per_cpu(tracer, smp_processor_id()) -#define this_buffer per_cpu(buffer, smp_processor_id()) -static int __read_mostly trace_hw_branches_enabled; +static int trace_hw_branches_enabled __read_mostly; +static int trace_hw_branches_suspended __read_mostly; static struct trace_array *hw_branch_trace __read_mostly; -/* - * Start tracing on the current cpu. - * The argument is ignored. - * - * pre: bts_tracer_lock must be locked. - */ -static void bts_trace_start_cpu(void *arg) +static void bts_trace_init_cpu(int cpu) { - if (this_tracer) - ds_release_bts(this_tracer); + per_cpu(tracer, cpu) = + ds_request_bts_cpu(cpu, per_cpu(buffer, cpu), BTS_BUFFER_SIZE, + NULL, (size_t)-1, BTS_KERNEL); - this_tracer = - ds_request_bts(/* task = */ NULL, this_buffer, SIZEOF_BTS, - /* ovfl = */ NULL, /* th = */ (size_t)-1, - BTS_KERNEL); - if (IS_ERR(this_tracer)) { - this_tracer = NULL; - return; + if (IS_ERR(per_cpu(tracer, cpu))) + per_cpu(tracer, cpu) = NULL; +} + +static int bts_trace_init(struct trace_array *tr) +{ + int cpu; + + hw_branch_trace = tr; + trace_hw_branches_enabled = 0; + + get_online_cpus(); + for_each_online_cpu(cpu) { + bts_trace_init_cpu(cpu); + + if (likely(per_cpu(tracer, cpu))) + trace_hw_branches_enabled = 1; } + trace_hw_branches_suspended = 0; + put_online_cpus(); + + /* If we could not enable tracing on a single cpu, we fail. */ + return trace_hw_branches_enabled ? 0 : -EOPNOTSUPP; +} + +static void bts_trace_reset(struct trace_array *tr) +{ + int cpu; + + get_online_cpus(); + for_each_online_cpu(cpu) { + if (likely(per_cpu(tracer, cpu))) { + ds_release_bts(per_cpu(tracer, cpu)); + per_cpu(tracer, cpu) = NULL; + } + } + trace_hw_branches_enabled = 0; + trace_hw_branches_suspended = 0; + put_online_cpus(); } static void bts_trace_start(struct trace_array *tr) { - spin_lock(&bts_tracer_lock); + int cpu; - on_each_cpu(bts_trace_start_cpu, NULL, 1); - trace_hw_branches_enabled = 1; - - spin_unlock(&bts_tracer_lock); -} - -/* - * Stop tracing on the current cpu. - * The argument is ignored. - * - * pre: bts_tracer_lock must be locked. - */ -static void bts_trace_stop_cpu(void *arg) -{ - if (this_tracer) { - ds_release_bts(this_tracer); - this_tracer = NULL; - } + get_online_cpus(); + for_each_online_cpu(cpu) + if (likely(per_cpu(tracer, cpu))) + ds_resume_bts(per_cpu(tracer, cpu)); + trace_hw_branches_suspended = 0; + put_online_cpus(); } static void bts_trace_stop(struct trace_array *tr) { - spin_lock(&bts_tracer_lock); + int cpu; - trace_hw_branches_enabled = 0; - on_each_cpu(bts_trace_stop_cpu, NULL, 1); - - spin_unlock(&bts_tracer_lock); + get_online_cpus(); + for_each_online_cpu(cpu) + if (likely(per_cpu(tracer, cpu))) + ds_suspend_bts(per_cpu(tracer, cpu)); + trace_hw_branches_suspended = 1; + put_online_cpus(); } static int __cpuinit bts_hotcpu_handler(struct notifier_block *nfb, unsigned long action, void *hcpu) { - unsigned int cpu = (unsigned long)hcpu; - - spin_lock(&bts_tracer_lock); - - if (!trace_hw_branches_enabled) - goto out; + int cpu = (long)hcpu; switch (action) { case CPU_ONLINE: case CPU_DOWN_FAILED: - smp_call_function_single(cpu, bts_trace_start_cpu, NULL, 1); + /* The notification is sent with interrupts enabled. */ + if (trace_hw_branches_enabled) { + bts_trace_init_cpu(cpu); + + if (trace_hw_branches_suspended && + likely(per_cpu(tracer, cpu))) + ds_suspend_bts(per_cpu(tracer, cpu)); + } break; + case CPU_DOWN_PREPARE: - smp_call_function_single(cpu, bts_trace_stop_cpu, NULL, 1); - break; + /* The notification is sent with interrupts enabled. */ + if (likely(per_cpu(tracer, cpu))) { + ds_release_bts(per_cpu(tracer, cpu)); + per_cpu(tracer, cpu) = NULL; + } } - out: - spin_unlock(&bts_tracer_lock); return NOTIFY_DONE; } @@ -126,20 +134,6 @@ static struct notifier_block bts_hotcpu_notifier __cpuinitdata = { .notifier_call = bts_hotcpu_handler }; -static int bts_trace_init(struct trace_array *tr) -{ - hw_branch_trace = tr; - - bts_trace_start(tr); - - return 0; -} - -static void bts_trace_reset(struct trace_array *tr) -{ - bts_trace_stop(tr); -} - static void bts_trace_print_header(struct seq_file *m) { seq_puts(m, "# CPU# TO <- FROM\n"); @@ -147,10 +141,10 @@ static void bts_trace_print_header(struct seq_file *m) static enum print_line_t bts_trace_print_line(struct trace_iterator *iter) { + unsigned long symflags = TRACE_ITER_SYM_OFFSET; struct trace_entry *entry = iter->ent; struct trace_seq *seq = &iter->seq; struct hw_branch_entry *it; - unsigned long symflags = TRACE_ITER_SYM_OFFSET; trace_assign_type(it, entry); @@ -168,6 +162,7 @@ static enum print_line_t bts_trace_print_line(struct trace_iterator *iter) void trace_hw_branch(u64 from, u64 to) { + struct ftrace_event_call *call = &event_hw_branch; struct trace_array *tr = hw_branch_trace; struct ring_buffer_event *event; struct hw_branch_entry *entry; @@ -194,7 +189,8 @@ void trace_hw_branch(u64 from, u64 to) entry->ent.type = TRACE_HW_BRANCHES; entry->from = from; entry->to = to; - trace_buffer_unlock_commit(tr, event, 0, 0); + if (!filter_check_discard(call, entry, tr->buffer, event)) + trace_buffer_unlock_commit(tr, event, 0, 0); out: atomic_dec(&tr->data[cpu]->disabled); @@ -224,11 +220,11 @@ static void trace_bts_at(const struct bts_trace *trace, void *at) /* * Collect the trace on the current cpu and write it into the ftrace buffer. * - * pre: bts_tracer_lock must be locked + * pre: tracing must be suspended on the current cpu */ static void trace_bts_cpu(void *arg) { - struct trace_array *tr = (struct trace_array *) arg; + struct trace_array *tr = (struct trace_array *)arg; const struct bts_trace *trace; unsigned char *at; @@ -241,10 +237,9 @@ static void trace_bts_cpu(void *arg) if (unlikely(!this_tracer)) return; - ds_suspend_bts(this_tracer); trace = ds_read_bts(this_tracer); if (!trace) - goto out; + return; for (at = trace->ds.top; (void *)at < trace->ds.end; at += trace->ds.size) @@ -253,18 +248,27 @@ static void trace_bts_cpu(void *arg) for (at = trace->ds.begin; (void *)at < trace->ds.top; at += trace->ds.size) trace_bts_at(trace, at); - -out: - ds_resume_bts(this_tracer); } static void trace_bts_prepare(struct trace_iterator *iter) { - spin_lock(&bts_tracer_lock); + int cpu; + get_online_cpus(); + for_each_online_cpu(cpu) + if (likely(per_cpu(tracer, cpu))) + ds_suspend_bts(per_cpu(tracer, cpu)); + /* + * We need to collect the trace on the respective cpu since ftrace + * implicitly adds the record for the current cpu. + * Once that is more flexible, we could collect the data from any cpu. + */ on_each_cpu(trace_bts_cpu, iter->tr, 1); - spin_unlock(&bts_tracer_lock); + for_each_online_cpu(cpu) + if (likely(per_cpu(tracer, cpu))) + ds_resume_bts(per_cpu(tracer, cpu)); + put_online_cpus(); } static void trace_bts_close(struct trace_iterator *iter) @@ -274,11 +278,11 @@ static void trace_bts_close(struct trace_iterator *iter) void trace_hw_branch_oops(void) { - spin_lock(&bts_tracer_lock); - - trace_bts_cpu(hw_branch_trace); - - spin_unlock(&bts_tracer_lock); + if (this_tracer) { + ds_suspend_bts_noirq(this_tracer); + trace_bts_cpu(hw_branch_trace); + ds_resume_bts_noirq(this_tracer); + } } struct tracer bts_tracer __read_mostly = @@ -291,7 +295,10 @@ struct tracer bts_tracer __read_mostly = .start = bts_trace_start, .stop = bts_trace_stop, .open = trace_bts_prepare, - .close = trace_bts_close + .close = trace_bts_close, +#ifdef CONFIG_FTRACE_SELFTEST + .selftest = trace_selftest_startup_hw_branches, +#endif /* CONFIG_FTRACE_SELFTEST */ }; __init static int init_bts_trace(void) diff --git a/kernel/trace/trace_mmiotrace.c b/kernel/trace/trace_mmiotrace.c index 8e37fcddd8b4..d53b45ed0806 100644 --- a/kernel/trace/trace_mmiotrace.c +++ b/kernel/trace/trace_mmiotrace.c @@ -9,6 +9,8 @@ #include #include #include +#include + #include #include "trace.h" @@ -174,7 +176,7 @@ static enum print_line_t mmio_print_rw(struct trace_iterator *iter) struct mmiotrace_rw *rw; struct trace_seq *s = &iter->seq; unsigned long long t = ns2usecs(iter->ts); - unsigned long usec_rem = do_div(t, 1000000ULL); + unsigned long usec_rem = do_div(t, USEC_PER_SEC); unsigned secs = (unsigned long)t; int ret = 1; @@ -221,7 +223,7 @@ static enum print_line_t mmio_print_map(struct trace_iterator *iter) struct mmiotrace_map *m; struct trace_seq *s = &iter->seq; unsigned long long t = ns2usecs(iter->ts); - unsigned long usec_rem = do_div(t, 1000000ULL); + unsigned long usec_rem = do_div(t, USEC_PER_SEC); unsigned secs = (unsigned long)t; int ret; diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c index 64b54a59c55b..7938f3ae93e3 100644 --- a/kernel/trace/trace_output.c +++ b/kernel/trace/trace_output.c @@ -14,11 +14,25 @@ /* must be a power of 2 */ #define EVENT_HASHSIZE 128 -static DEFINE_MUTEX(trace_event_mutex); +DECLARE_RWSEM(trace_event_mutex); + +DEFINE_PER_CPU(struct trace_seq, ftrace_event_seq); +EXPORT_PER_CPU_SYMBOL(ftrace_event_seq); + static struct hlist_head event_hash[EVENT_HASHSIZE] __read_mostly; static int next_event_type = __TRACE_LAST_TYPE + 1; +void trace_print_seq(struct seq_file *m, struct trace_seq *s) +{ + int len = s->len >= PAGE_SIZE ? PAGE_SIZE - 1 : s->len; + + s->buffer[len] = 0; + seq_puts(m, s->buffer); + + trace_seq_init(s); +} + enum print_line_t trace_print_bprintk_msg_only(struct trace_iterator *iter) { struct trace_seq *s = &iter->seq; @@ -84,6 +98,39 @@ trace_seq_printf(struct trace_seq *s, const char *fmt, ...) return len; } +EXPORT_SYMBOL_GPL(trace_seq_printf); + +/** + * trace_seq_vprintf - sequence printing of trace information + * @s: trace sequence descriptor + * @fmt: printf format string + * + * The tracer may use either sequence operations or its own + * copy to user routines. To simplify formating of a trace + * trace_seq_printf is used to store strings into a special + * buffer (@s). Then the output may be either used by + * the sequencer or pulled into another buffer. + */ +int +trace_seq_vprintf(struct trace_seq *s, const char *fmt, va_list args) +{ + int len = (PAGE_SIZE - 1) - s->len; + int ret; + + if (!len) + return 0; + + ret = vsnprintf(s->buffer + s->len, len, fmt, args); + + /* If we can't write it all, don't bother writing anything */ + if (ret >= len) + return 0; + + s->len += ret; + + return len; +} +EXPORT_SYMBOL_GPL(trace_seq_vprintf); int trace_seq_bprintf(struct trace_seq *s, const char *fmt, const u32 *binary) { @@ -201,6 +248,67 @@ int trace_seq_path(struct trace_seq *s, struct path *path) return 0; } +const char * +ftrace_print_flags_seq(struct trace_seq *p, const char *delim, + unsigned long flags, + const struct trace_print_flags *flag_array) +{ + unsigned long mask; + const char *str; + const char *ret = p->buffer + p->len; + int i; + + for (i = 0; flag_array[i].name && flags; i++) { + + mask = flag_array[i].mask; + if ((flags & mask) != mask) + continue; + + str = flag_array[i].name; + flags &= ~mask; + if (p->len && delim) + trace_seq_puts(p, delim); + trace_seq_puts(p, str); + } + + /* check for left over flags */ + if (flags) { + if (p->len && delim) + trace_seq_puts(p, delim); + trace_seq_printf(p, "0x%lx", flags); + } + + trace_seq_putc(p, 0); + + return ret; +} +EXPORT_SYMBOL(ftrace_print_flags_seq); + +const char * +ftrace_print_symbols_seq(struct trace_seq *p, unsigned long val, + const struct trace_print_flags *symbol_array) +{ + int i; + const char *ret = p->buffer + p->len; + + for (i = 0; symbol_array[i].name; i++) { + + if (val != symbol_array[i].mask) + continue; + + trace_seq_puts(p, symbol_array[i].name); + break; + } + + if (!p->len) + trace_seq_printf(p, "0x%lx", val); + + trace_seq_putc(p, 0); + + return ret; +} +EXPORT_SYMBOL(ftrace_print_symbols_seq); + #ifdef CONFIG_KRETPROBES static inline const char *kretprobed(const char *name) { @@ -311,17 +419,20 @@ seq_print_userip_objs(const struct userstack_entry *entry, struct trace_seq *s, if (ip == ULONG_MAX || !ret) break; - if (i && ret) - ret = trace_seq_puts(s, " <- "); + if (ret) + ret = trace_seq_puts(s, " => "); if (!ip) { if (ret) ret = trace_seq_puts(s, "??"); + if (ret) + ret = trace_seq_puts(s, "\n"); continue; } if (!ret) break; if (ret) ret = seq_print_user_ip(s, mm, ip, sym_flags); + ret = trace_seq_puts(s, "\n"); } if (mm) @@ -455,6 +566,7 @@ static int task_state_char(unsigned long state) * @type: the type of event to look for * * Returns an event of type @type otherwise NULL + * Called with trace_event_read_lock() held. */ struct trace_event *ftrace_find_event(int type) { @@ -464,7 +576,7 @@ struct trace_event *ftrace_find_event(int type) key = type & (EVENT_HASHSIZE - 1); - hlist_for_each_entry_rcu(event, n, &event_hash[key], node) { + hlist_for_each_entry(event, n, &event_hash[key], node) { if (event->type == type) return event; } @@ -472,6 +584,46 @@ struct trace_event *ftrace_find_event(int type) return NULL; } +static LIST_HEAD(ftrace_event_list); + +static int trace_search_list(struct list_head **list) +{ + struct trace_event *e; + int last = __TRACE_LAST_TYPE; + + if (list_empty(&ftrace_event_list)) { + *list = &ftrace_event_list; + return last + 1; + } + + /* + * We used up all possible max events, + * lets see if somebody freed one. + */ + list_for_each_entry(e, &ftrace_event_list, list) { + if (e->type != last + 1) + break; + last++; + } + + /* Did we used up all 65 thousand events??? */ + if ((last + 1) > FTRACE_MAX_EVENT) + return 0; + + *list = &e->list; + return last + 1; +} + +void trace_event_read_lock(void) +{ + down_read(&trace_event_mutex); +} + +void trace_event_read_unlock(void) +{ + up_read(&trace_event_mutex); +} + /** * register_ftrace_event - register output for an event type * @event: the event type to register @@ -492,22 +644,42 @@ int register_ftrace_event(struct trace_event *event) unsigned key; int ret = 0; - mutex_lock(&trace_event_mutex); + down_write(&trace_event_mutex); - if (!event) { - ret = next_event_type++; + if (WARN_ON(!event)) goto out; - } - if (!event->type) - event->type = next_event_type++; - else if (event->type > __TRACE_LAST_TYPE) { + INIT_LIST_HEAD(&event->list); + + if (!event->type) { + struct list_head *list = NULL; + + if (next_event_type > FTRACE_MAX_EVENT) { + + event->type = trace_search_list(&list); + if (!event->type) + goto out; + + } else { + + event->type = next_event_type++; + list = &ftrace_event_list; + } + + if (WARN_ON(ftrace_find_event(event->type))) + goto out; + + list_add_tail(&event->list, list); + + } else if (event->type > __TRACE_LAST_TYPE) { printk(KERN_WARNING "Need to add type to trace.h\n"); WARN_ON(1); - } - - if (ftrace_find_event(event->type)) goto out; + } else { + /* Is this event already used */ + if (ftrace_find_event(event->type)) + goto out; + } if (event->trace == NULL) event->trace = trace_nop_print; @@ -520,14 +692,25 @@ int register_ftrace_event(struct trace_event *event) key = event->type & (EVENT_HASHSIZE - 1); - hlist_add_head_rcu(&event->node, &event_hash[key]); + hlist_add_head(&event->node, &event_hash[key]); ret = event->type; out: - mutex_unlock(&trace_event_mutex); + up_write(&trace_event_mutex); return ret; } +EXPORT_SYMBOL_GPL(register_ftrace_event); + +/* + * Used by module code with the trace_event_mutex held for write. + */ +int __unregister_ftrace_event(struct trace_event *event) +{ + hlist_del(&event->node); + list_del(&event->list); + return 0; +} /** * unregister_ftrace_event - remove a no longer used event @@ -535,12 +718,13 @@ int register_ftrace_event(struct trace_event *event) */ int unregister_ftrace_event(struct trace_event *event) { - mutex_lock(&trace_event_mutex); - hlist_del(&event->node); - mutex_unlock(&trace_event_mutex); + down_write(&trace_event_mutex); + __unregister_ftrace_event(event); + up_write(&trace_event_mutex); return 0; } +EXPORT_SYMBOL_GPL(unregister_ftrace_event); /* * Standard events @@ -833,14 +1017,16 @@ static enum print_line_t trace_stack_print(struct trace_iterator *iter, trace_assign_type(field, iter->ent); + if (!trace_seq_puts(s, "\n")) + goto partial; for (i = 0; i < FTRACE_STACK_ENTRIES; i++) { - if (i) { - if (!trace_seq_puts(s, " <= ")) - goto partial; + if (!field->caller[i] || (field->caller[i] == ULONG_MAX)) + break; + if (!trace_seq_puts(s, " => ")) + goto partial; - if (!seq_print_ip_sym(s, field->caller[i], flags)) - goto partial; - } + if (!seq_print_ip_sym(s, field->caller[i], flags)) + goto partial; if (!trace_seq_puts(s, "\n")) goto partial; } @@ -868,10 +1054,10 @@ static enum print_line_t trace_user_stack_print(struct trace_iterator *iter, trace_assign_type(field, iter->ent); - if (!seq_print_userip_objs(field, s, flags)) + if (!trace_seq_puts(s, "\n")) goto partial; - if (!trace_seq_putc(s, '\n')) + if (!seq_print_userip_objs(field, s, flags)) goto partial; return TRACE_TYPE_HANDLED; diff --git a/kernel/trace/trace_output.h b/kernel/trace/trace_output.h index e0bde39c2dd9..d38bec4a9c30 100644 --- a/kernel/trace/trace_output.h +++ b/kernel/trace/trace_output.h @@ -1,41 +1,17 @@ #ifndef __TRACE_EVENTS_H #define __TRACE_EVENTS_H +#include #include "trace.h" -typedef enum print_line_t (*trace_print_func)(struct trace_iterator *iter, - int flags); - -struct trace_event { - struct hlist_node node; - int type; - trace_print_func trace; - trace_print_func raw; - trace_print_func hex; - trace_print_func binary; -}; - extern enum print_line_t trace_print_bprintk_msg_only(struct trace_iterator *iter); extern enum print_line_t trace_print_printk_msg_only(struct trace_iterator *iter); -extern int trace_seq_printf(struct trace_seq *s, const char *fmt, ...) - __attribute__ ((format (printf, 2, 3))); -extern int -trace_seq_bprintf(struct trace_seq *s, const char *fmt, const u32 *binary); extern int seq_print_ip_sym(struct trace_seq *s, unsigned long ip, unsigned long sym_flags); -extern ssize_t trace_seq_to_user(struct trace_seq *s, char __user *ubuf, - size_t cnt); -extern int trace_seq_puts(struct trace_seq *s, const char *str); -extern int trace_seq_putc(struct trace_seq *s, unsigned char c); -extern int trace_seq_putmem(struct trace_seq *s, const void *mem, size_t len); -extern int trace_seq_putmem_hex(struct trace_seq *s, const void *mem, - size_t len); -extern void *trace_seq_reserve(struct trace_seq *s, size_t len); -extern int trace_seq_path(struct trace_seq *s, struct path *path); extern int seq_print_userip_objs(const struct userstack_entry *entry, struct trace_seq *s, unsigned long sym_flags); extern int seq_print_user_ip(struct trace_seq *s, struct mm_struct *mm, @@ -44,13 +20,17 @@ extern int seq_print_user_ip(struct trace_seq *s, struct mm_struct *mm, extern int trace_print_context(struct trace_iterator *iter); extern int trace_print_lat_context(struct trace_iterator *iter); +extern void trace_event_read_lock(void); +extern void trace_event_read_unlock(void); extern struct trace_event *ftrace_find_event(int type); -extern int register_ftrace_event(struct trace_event *event); -extern int unregister_ftrace_event(struct trace_event *event); extern enum print_line_t trace_nop_print(struct trace_iterator *iter, int flags); +/* used by module unregistering */ +extern int __unregister_ftrace_event(struct trace_event *event); +extern struct rw_semaphore trace_event_mutex; + #define MAX_MEMHEX_BYTES 8 #define HEX_CHARS (MAX_MEMHEX_BYTES*2 + 1) diff --git a/kernel/trace/trace_power.c b/kernel/trace/trace_power.c index 118439709fb7..8a30d9874cd4 100644 --- a/kernel/trace/trace_power.c +++ b/kernel/trace/trace_power.c @@ -36,6 +36,7 @@ static void probe_power_start(struct power_trace *it, unsigned int type, static void probe_power_end(struct power_trace *it) { + struct ftrace_event_call *call = &event_power; struct ring_buffer_event *event; struct trace_power *entry; struct trace_array_cpu *data; @@ -54,7 +55,8 @@ static void probe_power_end(struct power_trace *it) goto out; entry = ring_buffer_event_data(event); entry->state_data = *it; - trace_buffer_unlock_commit(tr, event, 0, 0); + if (!filter_check_discard(call, entry, tr->buffer, event)) + trace_buffer_unlock_commit(tr, event, 0, 0); out: preempt_enable(); } @@ -62,6 +64,7 @@ static void probe_power_end(struct power_trace *it) static void probe_power_mark(struct power_trace *it, unsigned int type, unsigned int level) { + struct ftrace_event_call *call = &event_power; struct ring_buffer_event *event; struct trace_power *entry; struct trace_array_cpu *data; @@ -84,7 +87,8 @@ static void probe_power_mark(struct power_trace *it, unsigned int type, goto out; entry = ring_buffer_event_data(event); entry->state_data = *it; - trace_buffer_unlock_commit(tr, event, 0, 0); + if (!filter_check_discard(call, entry, tr->buffer, event)) + trace_buffer_unlock_commit(tr, event, 0, 0); out: preempt_enable(); } diff --git a/kernel/trace/trace_printk.c b/kernel/trace/trace_printk.c index eb81556107fe..9bece9687b62 100644 --- a/kernel/trace/trace_printk.c +++ b/kernel/trace/trace_printk.c @@ -245,17 +245,13 @@ static const struct file_operations ftrace_formats_fops = { static __init int init_trace_printk_function_export(void) { struct dentry *d_tracer; - struct dentry *entry; d_tracer = tracing_init_dentry(); if (!d_tracer) return 0; - entry = debugfs_create_file("printk_formats", 0444, d_tracer, + trace_create_file("printk_formats", 0444, d_tracer, NULL, &ftrace_formats_fops); - if (!entry) - pr_warning("Could not create debugfs " - "'printk_formats' entry\n"); return 0; } diff --git a/kernel/trace/trace_sched_switch.c b/kernel/trace/trace_sched_switch.c index 9117cea6f1ae..a98106dd979c 100644 --- a/kernel/trace/trace_sched_switch.c +++ b/kernel/trace/trace_sched_switch.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include "trace.h" @@ -29,13 +29,13 @@ probe_sched_switch(struct rq *__rq, struct task_struct *prev, int cpu; int pc; - if (!sched_ref || sched_stopped) + if (unlikely(!sched_ref)) return; tracing_record_cmdline(prev); tracing_record_cmdline(next); - if (!tracer_enabled) + if (!tracer_enabled || sched_stopped) return; pc = preempt_count(); @@ -56,15 +56,15 @@ probe_sched_wakeup(struct rq *__rq, struct task_struct *wakee, int success) unsigned long flags; int cpu, pc; - if (!likely(tracer_enabled)) + if (unlikely(!sched_ref)) + return; + + tracing_record_cmdline(current); + + if (!tracer_enabled || sched_stopped) return; pc = preempt_count(); - tracing_record_cmdline(current); - - if (sched_stopped) - return; - local_irq_save(flags); cpu = raw_smp_processor_id(); data = ctx_trace->data[cpu]; diff --git a/kernel/trace/trace_sched_wakeup.c b/kernel/trace/trace_sched_wakeup.c index 5bc00e8f153e..eacb27225173 100644 --- a/kernel/trace/trace_sched_wakeup.c +++ b/kernel/trace/trace_sched_wakeup.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include "trace.h" @@ -138,9 +138,6 @@ probe_wakeup_sched_switch(struct rq *rq, struct task_struct *prev, pc = preempt_count(); - /* The task we are waiting for is waking up */ - data = wakeup_trace->data[wakeup_cpu]; - /* disable local data, not wakeup_cpu data */ cpu = raw_smp_processor_id(); disabled = atomic_inc_return(&wakeup_trace->data[cpu]->disabled); @@ -154,6 +151,9 @@ probe_wakeup_sched_switch(struct rq *rq, struct task_struct *prev, if (unlikely(!tracer_enabled || next != wakeup_task)) goto out_unlock; + /* The task we are waiting for is waking up */ + data = wakeup_trace->data[wakeup_cpu]; + trace_function(wakeup_trace, CALLER_ADDR0, CALLER_ADDR1, flags, pc); tracing_sched_switch_trace(wakeup_trace, prev, next, flags, pc); diff --git a/kernel/trace/trace_selftest.c b/kernel/trace/trace_selftest.c index 08f4eb2763d1..00dd6485bdd7 100644 --- a/kernel/trace/trace_selftest.c +++ b/kernel/trace/trace_selftest.c @@ -16,6 +16,7 @@ static inline int trace_valid_entry(struct trace_entry *entry) case TRACE_BRANCH: case TRACE_GRAPH_ENT: case TRACE_GRAPH_RET: + case TRACE_HW_BRANCHES: return 1; } return 0; @@ -188,6 +189,7 @@ int trace_selftest_startup_dynamic_tracing(struct tracer *trace, #else # define trace_selftest_startup_dynamic_tracing(trace, tr, func) ({ 0; }) #endif /* CONFIG_DYNAMIC_FTRACE */ + /* * Simple verification test of ftrace function tracer. * Enable ftrace, sleep 1/10 second, and then read the trace @@ -749,3 +751,59 @@ trace_selftest_startup_branch(struct tracer *trace, struct trace_array *tr) return ret; } #endif /* CONFIG_BRANCH_TRACER */ + +#ifdef CONFIG_HW_BRANCH_TRACER +int +trace_selftest_startup_hw_branches(struct tracer *trace, + struct trace_array *tr) +{ + struct trace_iterator *iter; + struct tracer tracer; + unsigned long count; + int ret; + + if (!trace->open) { + printk(KERN_CONT "missing open function..."); + return -1; + } + + ret = tracer_init(trace, tr); + if (ret) { + warn_failed_init_tracer(trace, ret); + return ret; + } + + /* + * The hw-branch tracer needs to collect the trace from the various + * cpu trace buffers - before tracing is stopped. + */ + iter = kzalloc(sizeof(*iter), GFP_KERNEL); + if (!iter) + return -ENOMEM; + + memcpy(&tracer, trace, sizeof(tracer)); + + iter->trace = &tracer; + iter->tr = tr; + iter->pos = -1; + mutex_init(&iter->mutex); + + trace->open(iter); + + mutex_destroy(&iter->mutex); + kfree(iter); + + tracing_stop(); + + ret = trace_test_buffer(tr, &count); + trace->reset(tr); + tracing_start(); + + if (!ret && !count) { + printk(KERN_CONT "no entries found.."); + ret = -1; + } + + return ret; +} +#endif /* CONFIG_HW_BRANCH_TRACER */ diff --git a/kernel/trace/trace_stack.c b/kernel/trace/trace_stack.c index c750f65f9661..2d7aebd71dbd 100644 --- a/kernel/trace/trace_stack.c +++ b/kernel/trace/trace_stack.c @@ -265,7 +265,7 @@ static int t_show(struct seq_file *m, void *v) seq_printf(m, " Depth Size Location" " (%d entries)\n" " ----- ---- --------\n", - max_stack_trace.nr_entries); + max_stack_trace.nr_entries - 1); if (!stack_tracer_enabled && !max_stack_size) print_disabled(m); @@ -352,19 +352,14 @@ __setup("stacktrace", enable_stacktrace); static __init int stack_trace_init(void) { struct dentry *d_tracer; - struct dentry *entry; d_tracer = tracing_init_dentry(); - entry = debugfs_create_file("stack_max_size", 0644, d_tracer, - &max_stack_size, &stack_max_size_fops); - if (!entry) - pr_warning("Could not create debugfs 'stack_max_size' entry\n"); + trace_create_file("stack_max_size", 0644, d_tracer, + &max_stack_size, &stack_max_size_fops); - entry = debugfs_create_file("stack_trace", 0444, d_tracer, - NULL, &stack_trace_fops); - if (!entry) - pr_warning("Could not create debugfs 'stack_trace' entry\n"); + trace_create_file("stack_trace", 0444, d_tracer, + NULL, &stack_trace_fops); if (stack_tracer_enabled) register_ftrace_function(&trace_ops); diff --git a/kernel/trace/trace_stat.c b/kernel/trace/trace_stat.c index acdebd771a93..c00643733f4c 100644 --- a/kernel/trace/trace_stat.c +++ b/kernel/trace/trace_stat.c @@ -1,7 +1,7 @@ /* * Infrastructure for statistic tracing (histogram output). * - * Copyright (C) 2008 Frederic Weisbecker + * Copyright (C) 2008-2009 Frederic Weisbecker * * Based on the code from trace_branch.c which is * Copyright (C) 2008 Steven Rostedt @@ -10,22 +10,27 @@ #include +#include #include #include "trace_stat.h" #include "trace.h" -/* List of stat entries from a tracer */ -struct trace_stat_list { - struct list_head list; +/* + * List of stat red-black nodes from a tracer + * We use a such tree to sort quickly the stat + * entries from the tracer. + */ +struct stat_node { + struct rb_node node; void *stat; }; /* A stat session is the stats output in one file */ -struct tracer_stat_session { +struct stat_session { struct list_head session_list; struct tracer_stat *ts; - struct list_head stat_list; + struct rb_root stat_root; struct mutex stat_mutex; struct dentry *file; }; @@ -37,18 +42,48 @@ static DEFINE_MUTEX(all_stat_sessions_mutex); /* The root directory for all stat files */ static struct dentry *stat_dir; - -static void reset_stat_session(struct tracer_stat_session *session) +/* + * Iterate through the rbtree using a post order traversal path + * to release the next node. + * It won't necessary release one at each iteration + * but it will at least advance closer to the next one + * to be released. + */ +static struct rb_node *release_next(struct rb_node *node) { - struct trace_stat_list *node, *next; + struct stat_node *snode; + struct rb_node *parent = rb_parent(node); - list_for_each_entry_safe(node, next, &session->stat_list, list) - kfree(node); + if (node->rb_left) + return node->rb_left; + else if (node->rb_right) + return node->rb_right; + else { + if (!parent) + ; + else if (parent->rb_left == node) + parent->rb_left = NULL; + else + parent->rb_right = NULL; - INIT_LIST_HEAD(&session->stat_list); + snode = container_of(node, struct stat_node, node); + kfree(snode); + + return parent; + } } -static void destroy_session(struct tracer_stat_session *session) +static void reset_stat_session(struct stat_session *session) +{ + struct rb_node *node = session->stat_root.rb_node; + + while (node) + node = release_next(node); + + session->stat_root = RB_ROOT; +} + +static void destroy_session(struct stat_session *session) { debugfs_remove(session->file); reset_stat_session(session); @@ -56,25 +91,60 @@ static void destroy_session(struct tracer_stat_session *session) kfree(session); } -/* - * For tracers that don't provide a stat_cmp callback. - * This one will force an immediate insertion on tail of - * the list. - */ -static int dummy_cmp(void *p1, void *p2) +typedef int (*cmp_stat_t)(void *, void *); + +static int insert_stat(struct rb_root *root, void *stat, cmp_stat_t cmp) { - return 1; + struct rb_node **new = &(root->rb_node), *parent = NULL; + struct stat_node *data; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + data->stat = stat; + + /* + * Figure out where to put new node + * This is a descendent sorting + */ + while (*new) { + struct stat_node *this; + int result; + + this = container_of(*new, struct stat_node, node); + result = cmp(data->stat, this->stat); + + parent = *new; + if (result >= 0) + new = &((*new)->rb_left); + else + new = &((*new)->rb_right); + } + + rb_link_node(&data->node, parent, new); + rb_insert_color(&data->node, root); + return 0; } /* - * Initialize the stat list at each trace_stat file opening. + * For tracers that don't provide a stat_cmp callback. + * This one will force an insertion as right-most node + * in the rbtree. + */ +static int dummy_cmp(void *p1, void *p2) +{ + return -1; +} + +/* + * Initialize the stat rbtree at each trace_stat file opening. * All of these copies and sorting are required on all opening * since the stats could have changed between two file sessions. */ -static int stat_seq_init(struct tracer_stat_session *session) +static int stat_seq_init(struct stat_session *session) { - struct trace_stat_list *iter_entry, *new_entry; struct tracer_stat *ts = session->ts; + struct rb_root *root = &session->stat_root; void *stat; int ret = 0; int i; @@ -85,29 +155,16 @@ static int stat_seq_init(struct tracer_stat_session *session) if (!ts->stat_cmp) ts->stat_cmp = dummy_cmp; - stat = ts->stat_start(); + stat = ts->stat_start(ts); if (!stat) goto exit; - /* - * The first entry. Actually this is the second, but the first - * one (the stat_list head) is pointless. - */ - new_entry = kmalloc(sizeof(struct trace_stat_list), GFP_KERNEL); - if (!new_entry) { - ret = -ENOMEM; + ret = insert_stat(root, stat, ts->stat_cmp); + if (ret) goto exit; - } - - INIT_LIST_HEAD(&new_entry->list); - - list_add(&new_entry->list, &session->stat_list); - - new_entry->stat = stat; /* - * Iterate over the tracer stat entries and store them in a sorted - * list. + * Iterate over the tracer stat entries and store them in an rbtree. */ for (i = 1; ; i++) { stat = ts->stat_next(stat, i); @@ -116,36 +173,16 @@ static int stat_seq_init(struct tracer_stat_session *session) if (!stat) break; - new_entry = kmalloc(sizeof(struct trace_stat_list), GFP_KERNEL); - if (!new_entry) { - ret = -ENOMEM; - goto exit_free_list; - } - - INIT_LIST_HEAD(&new_entry->list); - new_entry->stat = stat; - - list_for_each_entry_reverse(iter_entry, &session->stat_list, - list) { - - /* Insertion with a descendent sorting */ - if (ts->stat_cmp(iter_entry->stat, - new_entry->stat) >= 0) { - - list_add(&new_entry->list, &iter_entry->list); - break; - } - } - - /* The current larger value */ - if (list_empty(&new_entry->list)) - list_add(&new_entry->list, &session->stat_list); + ret = insert_stat(root, stat, ts->stat_cmp); + if (ret) + goto exit_free_rbtree; } + exit: mutex_unlock(&session->stat_mutex); return ret; -exit_free_list: +exit_free_rbtree: reset_stat_session(session); mutex_unlock(&session->stat_mutex); return ret; @@ -154,38 +191,51 @@ exit_free_list: static void *stat_seq_start(struct seq_file *s, loff_t *pos) { - struct tracer_stat_session *session = s->private; + struct stat_session *session = s->private; + struct rb_node *node; + int i; - /* Prevent from tracer switch or stat_list modification */ + /* Prevent from tracer switch or rbtree modification */ mutex_lock(&session->stat_mutex); /* If we are in the beginning of the file, print the headers */ - if (!*pos && session->ts->stat_headers) + if (!*pos && session->ts->stat_headers) { + (*pos)++; return SEQ_START_TOKEN; + } - return seq_list_start(&session->stat_list, *pos); + node = rb_first(&session->stat_root); + for (i = 0; node && i < *pos; i++) + node = rb_next(node); + + (*pos)++; + + return node; } static void *stat_seq_next(struct seq_file *s, void *p, loff_t *pos) { - struct tracer_stat_session *session = s->private; + struct stat_session *session = s->private; + struct rb_node *node = p; + + (*pos)++; if (p == SEQ_START_TOKEN) - return seq_list_start(&session->stat_list, *pos); + return rb_first(&session->stat_root); - return seq_list_next(p, &session->stat_list, pos); + return rb_next(node); } static void stat_seq_stop(struct seq_file *s, void *p) { - struct tracer_stat_session *session = s->private; + struct stat_session *session = s->private; mutex_unlock(&session->stat_mutex); } static int stat_seq_show(struct seq_file *s, void *v) { - struct tracer_stat_session *session = s->private; - struct trace_stat_list *l = list_entry(v, struct trace_stat_list, list); + struct stat_session *session = s->private; + struct stat_node *l = container_of(v, struct stat_node, node); if (v == SEQ_START_TOKEN) return session->ts->stat_headers(s); @@ -205,7 +255,7 @@ static int tracing_stat_open(struct inode *inode, struct file *file) { int ret; - struct tracer_stat_session *session = inode->i_private; + struct stat_session *session = inode->i_private; ret = seq_open(file, &trace_stat_seq_ops); if (!ret) { @@ -218,11 +268,11 @@ static int tracing_stat_open(struct inode *inode, struct file *file) } /* - * Avoid consuming memory with our now useless list. + * Avoid consuming memory with our now useless rbtree. */ static int tracing_stat_release(struct inode *i, struct file *f) { - struct tracer_stat_session *session = i->i_private; + struct stat_session *session = i->i_private; mutex_lock(&session->stat_mutex); reset_stat_session(session); @@ -251,7 +301,7 @@ static int tracing_stat_init(void) return 0; } -static int init_stat_file(struct tracer_stat_session *session) +static int init_stat_file(struct stat_session *session) { if (!stat_dir && tracing_stat_init()) return -ENODEV; @@ -266,7 +316,7 @@ static int init_stat_file(struct tracer_stat_session *session) int register_stat_tracer(struct tracer_stat *trace) { - struct tracer_stat_session *session, *node, *tmp; + struct stat_session *session, *node; int ret; if (!trace) @@ -277,7 +327,7 @@ int register_stat_tracer(struct tracer_stat *trace) /* Already registered? */ mutex_lock(&all_stat_sessions_mutex); - list_for_each_entry_safe(node, tmp, &all_stat_sessions, session_list) { + list_for_each_entry(node, &all_stat_sessions, session_list) { if (node->ts == trace) { mutex_unlock(&all_stat_sessions_mutex); return -EINVAL; @@ -286,15 +336,13 @@ int register_stat_tracer(struct tracer_stat *trace) mutex_unlock(&all_stat_sessions_mutex); /* Init the session */ - session = kmalloc(sizeof(struct tracer_stat_session), GFP_KERNEL); + session = kzalloc(sizeof(*session), GFP_KERNEL); if (!session) return -ENOMEM; session->ts = trace; INIT_LIST_HEAD(&session->session_list); - INIT_LIST_HEAD(&session->stat_list); mutex_init(&session->stat_mutex); - session->file = NULL; ret = init_stat_file(session); if (ret) { @@ -312,7 +360,7 @@ int register_stat_tracer(struct tracer_stat *trace) void unregister_stat_tracer(struct tracer_stat *trace) { - struct tracer_stat_session *node, *tmp; + struct stat_session *node, *tmp; mutex_lock(&all_stat_sessions_mutex); list_for_each_entry_safe(node, tmp, &all_stat_sessions, session_list) { diff --git a/kernel/trace/trace_stat.h b/kernel/trace/trace_stat.h index 202274cf7f3d..f3546a2cd826 100644 --- a/kernel/trace/trace_stat.h +++ b/kernel/trace/trace_stat.h @@ -12,7 +12,7 @@ struct tracer_stat { /* The name of your stat file */ const char *name; /* Iteration over statistic entries */ - void *(*stat_start)(void); + void *(*stat_start)(struct tracer_stat *trace); void *(*stat_next)(void *prev, int idx); /* Compare two entries for stats sorting */ int (*stat_cmp)(void *p1, void *p2); diff --git a/kernel/trace/trace_sysprof.c b/kernel/trace/trace_sysprof.c index 91fd19c2149f..f6693969287d 100644 --- a/kernel/trace/trace_sysprof.c +++ b/kernel/trace/trace_sysprof.c @@ -203,7 +203,8 @@ static void start_stack_timer(void *unused) hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); hrtimer->function = stack_trace_timer_fn; - hrtimer_start(hrtimer, ns_to_ktime(sample_period), HRTIMER_MODE_REL); + hrtimer_start(hrtimer, ns_to_ktime(sample_period), + HRTIMER_MODE_REL_PINNED); } static void start_stack_timers(void) @@ -321,11 +322,7 @@ static const struct file_operations sysprof_sample_fops = { void init_tracer_sysprof_debugfs(struct dentry *d_tracer) { - struct dentry *entry; - entry = debugfs_create_file("sysprof_sample_period", 0644, + trace_create_file("sysprof_sample_period", 0644, d_tracer, NULL, &sysprof_sample_fops); - if (entry) - return; - pr_warning("Could not create debugfs 'sysprof_sample_period' entry\n"); } diff --git a/kernel/trace/trace_workqueue.c b/kernel/trace/trace_workqueue.c index 797201e4a137..97fcea4acce1 100644 --- a/kernel/trace/trace_workqueue.c +++ b/kernel/trace/trace_workqueue.c @@ -6,7 +6,7 @@ */ -#include +#include #include #include #include "trace_stat.h" @@ -16,8 +16,6 @@ /* A cpu workqueue thread */ struct cpu_workqueue_stats { struct list_head list; -/* Useful to know if we print the cpu headers */ - bool first_entry; int cpu; pid_t pid; /* Can be inserted from interrupt or user context, need to be atomic */ @@ -47,12 +45,11 @@ probe_workqueue_insertion(struct task_struct *wq_thread, struct work_struct *work) { int cpu = cpumask_first(&wq_thread->cpus_allowed); - struct cpu_workqueue_stats *node, *next; + struct cpu_workqueue_stats *node; unsigned long flags; spin_lock_irqsave(&workqueue_cpu_stat(cpu)->lock, flags); - list_for_each_entry_safe(node, next, &workqueue_cpu_stat(cpu)->list, - list) { + list_for_each_entry(node, &workqueue_cpu_stat(cpu)->list, list) { if (node->pid == wq_thread->pid) { atomic_inc(&node->inserted); goto found; @@ -69,12 +66,11 @@ probe_workqueue_execution(struct task_struct *wq_thread, struct work_struct *work) { int cpu = cpumask_first(&wq_thread->cpus_allowed); - struct cpu_workqueue_stats *node, *next; + struct cpu_workqueue_stats *node; unsigned long flags; spin_lock_irqsave(&workqueue_cpu_stat(cpu)->lock, flags); - list_for_each_entry_safe(node, next, &workqueue_cpu_stat(cpu)->list, - list) { + list_for_each_entry(node, &workqueue_cpu_stat(cpu)->list, list) { if (node->pid == wq_thread->pid) { node->executed++; goto found; @@ -105,8 +101,6 @@ static void probe_workqueue_creation(struct task_struct *wq_thread, int cpu) cws->pid = wq_thread->pid; spin_lock_irqsave(&workqueue_cpu_stat(cpu)->lock, flags); - if (list_empty(&workqueue_cpu_stat(cpu)->list)) - cws->first_entry = true; list_add_tail(&cws->list, &workqueue_cpu_stat(cpu)->list); spin_unlock_irqrestore(&workqueue_cpu_stat(cpu)->lock, flags); } @@ -152,7 +146,7 @@ static struct cpu_workqueue_stats *workqueue_stat_start_cpu(int cpu) return ret; } -static void *workqueue_stat_start(void) +static void *workqueue_stat_start(struct tracer_stat *trace) { int cpu; void *ret = NULL; @@ -191,16 +185,9 @@ static void *workqueue_stat_next(void *prev, int idx) static int workqueue_stat_show(struct seq_file *s, void *p) { struct cpu_workqueue_stats *cws = p; - unsigned long flags; - int cpu = cws->cpu; struct pid *pid; struct task_struct *tsk; - spin_lock_irqsave(&workqueue_cpu_stat(cpu)->lock, flags); - if (&cws->list == workqueue_cpu_stat(cpu)->list.next) - seq_printf(s, "\n"); - spin_unlock_irqrestore(&workqueue_cpu_stat(cpu)->lock, flags); - pid = find_get_pid(cws->pid); if (pid) { tsk = get_pid_task(pid, PIDTYPE_PID); diff --git a/kernel/user.c b/kernel/user.c index 850e0ba41c1e..2c000e7132ac 100644 --- a/kernel/user.c +++ b/kernel/user.c @@ -75,21 +75,6 @@ static void uid_hash_remove(struct user_struct *up) put_user_ns(up->user_ns); } -static struct user_struct *uid_hash_find(uid_t uid, struct hlist_head *hashent) -{ - struct user_struct *user; - struct hlist_node *h; - - hlist_for_each_entry(user, h, hashent, uidhash_node) { - if (user->uid == uid) { - atomic_inc(&user->__count); - return user; - } - } - - return NULL; -} - #ifdef CONFIG_USER_SCHED static void sched_destroy_user(struct user_struct *up) @@ -119,6 +104,23 @@ static int sched_create_user(struct user_struct *up) { return 0; } #if defined(CONFIG_USER_SCHED) && defined(CONFIG_SYSFS) +static struct user_struct *uid_hash_find(uid_t uid, struct hlist_head *hashent) +{ + struct user_struct *user; + struct hlist_node *h; + + hlist_for_each_entry(user, h, hashent, uidhash_node) { + if (user->uid == uid) { + /* possibly resurrect an "almost deleted" object */ + if (atomic_inc_return(&user->__count) == 1) + cancel_delayed_work(&user->work); + return user; + } + } + + return NULL; +} + static struct kset *uids_kset; /* represents the /sys/kernel/uids/ directory */ static DEFINE_MUTEX(uids_mutex); @@ -283,12 +285,12 @@ int __init uids_sysfs_init(void) return uids_user_create(&root_user); } -/* work function to remove sysfs directory for a user and free up +/* delayed work function to remove sysfs directory for a user and free up * corresponding structures. */ static void cleanup_user_struct(struct work_struct *w) { - struct user_struct *up = container_of(w, struct user_struct, work); + struct user_struct *up = container_of(w, struct user_struct, work.work); unsigned long flags; int remove_user = 0; @@ -297,15 +299,12 @@ static void cleanup_user_struct(struct work_struct *w) */ uids_mutex_lock(); - local_irq_save(flags); - - if (atomic_dec_and_lock(&up->__count, &uidhash_lock)) { + spin_lock_irqsave(&uidhash_lock, flags); + if (atomic_read(&up->__count) == 0) { uid_hash_remove(up); remove_user = 1; - spin_unlock_irqrestore(&uidhash_lock, flags); - } else { - local_irq_restore(flags); } + spin_unlock_irqrestore(&uidhash_lock, flags); if (!remove_user) goto done; @@ -331,16 +330,28 @@ done: */ static void free_user(struct user_struct *up, unsigned long flags) { - /* restore back the count */ - atomic_inc(&up->__count); spin_unlock_irqrestore(&uidhash_lock, flags); - - INIT_WORK(&up->work, cleanup_user_struct); - schedule_work(&up->work); + INIT_DELAYED_WORK(&up->work, cleanup_user_struct); + schedule_delayed_work(&up->work, msecs_to_jiffies(1000)); } #else /* CONFIG_USER_SCHED && CONFIG_SYSFS */ +static struct user_struct *uid_hash_find(uid_t uid, struct hlist_head *hashent) +{ + struct user_struct *user; + struct hlist_node *h; + + hlist_for_each_entry(user, h, hashent, uidhash_node) { + if (user->uid == uid) { + atomic_inc(&user->__count); + return user; + } + } + + return NULL; +} + int uids_sysfs_init(void) { return 0; } static inline int uids_user_create(struct user_struct *up) { return 0; } static inline void uids_mutex_lock(void) { } diff --git a/kernel/utsname.c b/kernel/utsname.c index 815237a55af8..8a82b4b8ea52 100644 --- a/kernel/utsname.c +++ b/kernel/utsname.c @@ -15,6 +15,16 @@ #include #include +static struct uts_namespace *create_uts_ns(void) +{ + struct uts_namespace *uts_ns; + + uts_ns = kmalloc(sizeof(struct uts_namespace), GFP_KERNEL); + if (uts_ns) + kref_init(&uts_ns->kref); + return uts_ns; +} + /* * Clone a new ns copying an original utsname, setting refcount to 1 * @old_ns: namespace to clone @@ -24,14 +34,13 @@ static struct uts_namespace *clone_uts_ns(struct uts_namespace *old_ns) { struct uts_namespace *ns; - ns = kmalloc(sizeof(struct uts_namespace), GFP_KERNEL); + ns = create_uts_ns(); if (!ns) return ERR_PTR(-ENOMEM); down_read(&uts_sem); memcpy(&ns->name, &old_ns->name, sizeof(ns->name)); up_read(&uts_sem); - kref_init(&ns->kref); return ns; } diff --git a/kernel/wait.c b/kernel/wait.c index 42a2dbc181c8..ea7c3b4275cf 100644 --- a/kernel/wait.c +++ b/kernel/wait.c @@ -154,7 +154,7 @@ void abort_exclusive_wait(wait_queue_head_t *q, wait_queue_t *wait, if (!list_empty(&wait->task_list)) list_del_init(&wait->task_list); else if (waitqueue_active(q)) - __wake_up_common(q, mode, 1, 0, key); + __wake_up_locked_key(q, mode, key); spin_unlock_irqrestore(&q->lock, flags); } EXPORT_SYMBOL(abort_exclusive_wait); diff --git a/kernel/workqueue.c b/kernel/workqueue.c index f71fb2a08950..0668795d8818 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -33,7 +33,8 @@ #include #include #include -#include +#define CREATE_TRACE_POINTS +#include /* * The per-CPU workqueue (if single thread, we always use the first @@ -124,8 +125,6 @@ struct cpu_workqueue_struct *get_wq_data(struct work_struct *work) return (void *) (atomic_long_read(&work->data) & WORK_STRUCT_WQ_DATA_MASK); } -DEFINE_TRACE(workqueue_insertion); - static void insert_work(struct cpu_workqueue_struct *cwq, struct work_struct *work, struct list_head *head) { @@ -262,8 +261,6 @@ int queue_delayed_work_on(int cpu, struct workqueue_struct *wq, } EXPORT_SYMBOL_GPL(queue_delayed_work_on); -DEFINE_TRACE(workqueue_execution); - static void run_workqueue(struct cpu_workqueue_struct *cwq) { spin_lock_irq(&cwq->lock); @@ -753,8 +750,6 @@ init_cpu_workqueue(struct workqueue_struct *wq, int cpu) return cwq; } -DEFINE_TRACE(workqueue_creation); - static int create_workqueue_thread(struct cpu_workqueue_struct *cwq, int cpu) { struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 }; @@ -860,8 +855,6 @@ struct workqueue_struct *__create_workqueue_key(const char *name, } EXPORT_SYMBOL_GPL(__create_workqueue_key); -DEFINE_TRACE(workqueue_destruction); - static void cleanup_workqueue_thread(struct cpu_workqueue_struct *cwq) { /* diff --git a/lib/Kconfig b/lib/Kconfig index 8ade0a7a91e0..bb1326d3839c 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -10,6 +10,9 @@ menu "Library routines" config BITREVERSE tristate +config RATIONAL + boolean + config GENERIC_FIND_FIRST_BIT bool @@ -191,4 +194,10 @@ config DISABLE_OBSOLETE_CPUMASK_FUNCTIONS config NLATTR bool +# +# Generic 64-bit atomic support is selected if needed +# +config GENERIC_ATOMIC64 + bool + endmenu diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 6cdcf38f2da9..4c32b1a1a06e 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -300,7 +300,7 @@ config DEBUG_OBJECTS_ENABLE_DEFAULT config DEBUG_SLAB bool "Debug slab memory allocations" - depends on DEBUG_KERNEL && SLAB + depends on DEBUG_KERNEL && SLAB && !KMEMCHECK help Say Y here to have the kernel do limited verification on memory allocation as well as poisoning memory on free to catch use of freed @@ -312,7 +312,7 @@ config DEBUG_SLAB_LEAK config SLUB_DEBUG_ON bool "SLUB debugging on by default" - depends on SLUB && SLUB_DEBUG + depends on SLUB && SLUB_DEBUG && !KMEMCHECK default n help Boot with debugging on by default. SLUB boots by default with @@ -336,6 +336,39 @@ config SLUB_STATS out which slabs are relevant to a particular load. Try running: slabinfo -DA +config DEBUG_KMEMLEAK + bool "Kernel memory leak detector" + depends on DEBUG_KERNEL && EXPERIMENTAL && (X86 || ARM) && \ + !MEMORY_HOTPLUG + select DEBUG_FS if SYSFS + select STACKTRACE if STACKTRACE_SUPPORT + select KALLSYMS + help + Say Y here if you want to enable the memory leak + detector. The memory allocation/freeing is traced in a way + similar to the Boehm's conservative garbage collector, the + difference being that the orphan objects are not freed but + only shown in /sys/kernel/debug/kmemleak. Enabling this + feature will introduce an overhead to memory + allocations. See Documentation/kmemleak.txt for more + details. + + Enabling DEBUG_SLAB or SLUB_DEBUG may increase the chances + of finding leaks due to the slab objects poisoning. + + In order to access the kmemleak file, debugfs needs to be + mounted (usually at /sys/kernel/debug). + +config DEBUG_KMEMLEAK_TEST + tristate "Simple test for the kernel memory leak detector" + depends on DEBUG_KMEMLEAK + help + Say Y or M here to build a test for the kernel memory leak + detector. This option enables a module that explicitly leaks + memory. + + If unsure, say N. + config DEBUG_PREEMPT bool "Debug preemptible kernel" depends on DEBUG_KERNEL && PREEMPT && (TRACE_IRQFLAGS_SUPPORT || PPC64) @@ -440,7 +473,7 @@ config LOCKDEP bool depends on DEBUG_KERNEL && TRACE_IRQFLAGS_SUPPORT && STACKTRACE_SUPPORT && LOCKDEP_SUPPORT select STACKTRACE - select FRAME_POINTER if !X86 && !MIPS && !PPC && !ARM_UNWIND && !S390 + select FRAME_POINTER if !MIPS && !PPC && !ARM_UNWIND && !S390 select KALLSYMS select KALLSYMS_ALL @@ -964,3 +997,5 @@ config DMA_API_DEBUG source "samples/Kconfig" source "lib/Kconfig.kgdb" + +source "lib/Kconfig.kmemcheck" diff --git a/lib/Kconfig.kmemcheck b/lib/Kconfig.kmemcheck new file mode 100644 index 000000000000..603c81b66549 --- /dev/null +++ b/lib/Kconfig.kmemcheck @@ -0,0 +1,91 @@ +config HAVE_ARCH_KMEMCHECK + bool + +menuconfig KMEMCHECK + bool "kmemcheck: trap use of uninitialized memory" + depends on DEBUG_KERNEL + depends on !X86_USE_3DNOW + depends on SLUB || SLAB + depends on !CC_OPTIMIZE_FOR_SIZE + depends on !FUNCTION_TRACER + select FRAME_POINTER + select STACKTRACE + default n + help + This option enables tracing of dynamically allocated kernel memory + to see if memory is used before it has been given an initial value. + Be aware that this requires half of your memory for bookkeeping and + will insert extra code at *every* read and write to tracked memory + thus slow down the kernel code (but user code is unaffected). + + The kernel may be started with kmemcheck=0 or kmemcheck=1 to disable + or enable kmemcheck at boot-time. If the kernel is started with + kmemcheck=0, the large memory and CPU overhead is not incurred. + +choice + prompt "kmemcheck: default mode at boot" + depends on KMEMCHECK + default KMEMCHECK_ONESHOT_BY_DEFAULT + help + This option controls the default behaviour of kmemcheck when the + kernel boots and no kmemcheck= parameter is given. + +config KMEMCHECK_DISABLED_BY_DEFAULT + bool "disabled" + depends on KMEMCHECK + +config KMEMCHECK_ENABLED_BY_DEFAULT + bool "enabled" + depends on KMEMCHECK + +config KMEMCHECK_ONESHOT_BY_DEFAULT + bool "one-shot" + depends on KMEMCHECK + help + In one-shot mode, only the first error detected is reported before + kmemcheck is disabled. + +endchoice + +config KMEMCHECK_QUEUE_SIZE + int "kmemcheck: error queue size" + depends on KMEMCHECK + default 64 + help + Select the maximum number of errors to store in the queue. Since + errors can occur virtually anywhere and in any context, we need a + temporary storage area which is guarantueed not to generate any + other faults. The queue will be emptied as soon as a tasklet may + be scheduled. If the queue is full, new error reports will be + lost. + +config KMEMCHECK_SHADOW_COPY_SHIFT + int "kmemcheck: shadow copy size (5 => 32 bytes, 6 => 64 bytes)" + depends on KMEMCHECK + range 2 8 + default 5 + help + Select the number of shadow bytes to save along with each entry of + the queue. These bytes indicate what parts of an allocation are + initialized, uninitialized, etc. and will be displayed when an + error is detected to help the debugging of a particular problem. + +config KMEMCHECK_PARTIAL_OK + bool "kmemcheck: allow partially uninitialized memory" + depends on KMEMCHECK + default y + help + This option works around certain GCC optimizations that produce + 32-bit reads from 16-bit variables where the upper 16 bits are + thrown away afterwards. This may of course also hide some real + bugs. + +config KMEMCHECK_BITOPS_OK + bool "kmemcheck: allow bit-field manipulation" + depends on KMEMCHECK + default n + help + This option silences warnings that would be generated for bit-field + accesses where not all the bits are initialized at the same time. + This may also hide some real bugs. + diff --git a/lib/Makefile b/lib/Makefile index 33a40e40e3ee..b6d1857bbf08 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -21,7 +21,7 @@ lib-y += kobject.o kref.o klist.o obj-y += bcd.o div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \ bust_spinlocks.o hexdump.o kasprintf.o bitmap.o scatterlist.o \ - string_helpers.o + string_helpers.o gcd.o ifeq ($(CONFIG_DEBUG_KOBJECT),y) CFLAGS_kobject.o += -DDEBUG @@ -50,6 +50,7 @@ ifneq ($(CONFIG_HAVE_DEC_LOCK),y) endif obj-$(CONFIG_BITREVERSE) += bitrev.o +obj-$(CONFIG_RATIONAL) += rational.o obj-$(CONFIG_CRC_CCITT) += crc-ccitt.o obj-$(CONFIG_CRC16) += crc16.o obj-$(CONFIG_CRC_T10DIF)+= crc-t10dif.o @@ -92,6 +93,10 @@ obj-$(CONFIG_NLATTR) += nlattr.o obj-$(CONFIG_DMA_API_DEBUG) += dma-debug.o +obj-$(CONFIG_GENERIC_CSUM) += checksum.o + +obj-$(CONFIG_GENERIC_ATOMIC64) += atomic64.o + hostprogs-y := gen_crc32table clean-files := crc32table.h diff --git a/lib/atomic64.c b/lib/atomic64.c new file mode 100644 index 000000000000..c5e725562416 --- /dev/null +++ b/lib/atomic64.c @@ -0,0 +1,175 @@ +/* + * Generic implementation of 64-bit atomics using spinlocks, + * useful on processors that don't have 64-bit atomic instructions. + * + * Copyright © 2009 Paul Mackerras, IBM Corp. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include +#include +#include +#include +#include + +/* + * We use a hashed array of spinlocks to provide exclusive access + * to each atomic64_t variable. Since this is expected to used on + * systems with small numbers of CPUs (<= 4 or so), we use a + * relatively small array of 16 spinlocks to avoid wasting too much + * memory on the spinlock array. + */ +#define NR_LOCKS 16 + +/* + * Ensure each lock is in a separate cacheline. + */ +static union { + spinlock_t lock; + char pad[L1_CACHE_BYTES]; +} atomic64_lock[NR_LOCKS] __cacheline_aligned_in_smp; + +static inline spinlock_t *lock_addr(const atomic64_t *v) +{ + unsigned long addr = (unsigned long) v; + + addr >>= L1_CACHE_SHIFT; + addr ^= (addr >> 8) ^ (addr >> 16); + return &atomic64_lock[addr & (NR_LOCKS - 1)].lock; +} + +long long atomic64_read(const atomic64_t *v) +{ + unsigned long flags; + spinlock_t *lock = lock_addr(v); + long long val; + + spin_lock_irqsave(lock, flags); + val = v->counter; + spin_unlock_irqrestore(lock, flags); + return val; +} + +void atomic64_set(atomic64_t *v, long long i) +{ + unsigned long flags; + spinlock_t *lock = lock_addr(v); + + spin_lock_irqsave(lock, flags); + v->counter = i; + spin_unlock_irqrestore(lock, flags); +} + +void atomic64_add(long long a, atomic64_t *v) +{ + unsigned long flags; + spinlock_t *lock = lock_addr(v); + + spin_lock_irqsave(lock, flags); + v->counter += a; + spin_unlock_irqrestore(lock, flags); +} + +long long atomic64_add_return(long long a, atomic64_t *v) +{ + unsigned long flags; + spinlock_t *lock = lock_addr(v); + long long val; + + spin_lock_irqsave(lock, flags); + val = v->counter += a; + spin_unlock_irqrestore(lock, flags); + return val; +} + +void atomic64_sub(long long a, atomic64_t *v) +{ + unsigned long flags; + spinlock_t *lock = lock_addr(v); + + spin_lock_irqsave(lock, flags); + v->counter -= a; + spin_unlock_irqrestore(lock, flags); +} + +long long atomic64_sub_return(long long a, atomic64_t *v) +{ + unsigned long flags; + spinlock_t *lock = lock_addr(v); + long long val; + + spin_lock_irqsave(lock, flags); + val = v->counter -= a; + spin_unlock_irqrestore(lock, flags); + return val; +} + +long long atomic64_dec_if_positive(atomic64_t *v) +{ + unsigned long flags; + spinlock_t *lock = lock_addr(v); + long long val; + + spin_lock_irqsave(lock, flags); + val = v->counter - 1; + if (val >= 0) + v->counter = val; + spin_unlock_irqrestore(lock, flags); + return val; +} + +long long atomic64_cmpxchg(atomic64_t *v, long long o, long long n) +{ + unsigned long flags; + spinlock_t *lock = lock_addr(v); + long long val; + + spin_lock_irqsave(lock, flags); + val = v->counter; + if (val == o) + v->counter = n; + spin_unlock_irqrestore(lock, flags); + return val; +} + +long long atomic64_xchg(atomic64_t *v, long long new) +{ + unsigned long flags; + spinlock_t *lock = lock_addr(v); + long long val; + + spin_lock_irqsave(lock, flags); + val = v->counter; + v->counter = new; + spin_unlock_irqrestore(lock, flags); + return val; +} + +int atomic64_add_unless(atomic64_t *v, long long a, long long u) +{ + unsigned long flags; + spinlock_t *lock = lock_addr(v); + int ret = 1; + + spin_lock_irqsave(lock, flags); + if (v->counter != u) { + v->counter += a; + ret = 0; + } + spin_unlock_irqrestore(lock, flags); + return ret; +} + +static int init_atomic64_lock(void) +{ + int i; + + for (i = 0; i < NR_LOCKS; ++i) + spin_lock_init(&atomic64_lock[i].lock); + return 0; +} + +pure_initcall(init_atomic64_lock); diff --git a/lib/checksum.c b/lib/checksum.c new file mode 100644 index 000000000000..b2e2fd468461 --- /dev/null +++ b/lib/checksum.c @@ -0,0 +1,201 @@ +/* + * + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * IP/TCP/UDP checksumming routines + * + * Authors: Jorge Cwik, + * Arnt Gulbrandsen, + * Tom May, + * Andreas Schwab, + * Lots of code moved from tcp.c and ip.c; see those files + * for more names. + * + * 03/02/96 Jes Sorensen, Andreas Schwab, Roman Hodek: + * Fixed some nasty bugs, causing some horrible crashes. + * A: At some points, the sum (%0) was used as + * length-counter instead of the length counter + * (%1). Thanks to Roman Hodek for pointing this out. + * B: GCC seems to mess up if one uses too many + * data-registers to hold input values and one tries to + * specify d0 and d1 as scratch registers. Letting gcc + * choose these registers itself solves the problem. + * + * 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. + */ + +/* Revised by Kenneth Albanowski for m68knommu. Basic problem: unaligned access + kills, so most of the assembly has to go. */ + +#include +#include + +#include + +static inline unsigned short from32to16(unsigned long x) +{ + /* add up 16-bit and 16-bit for 16+c bit */ + x = (x & 0xffff) + (x >> 16); + /* add up carry.. */ + x = (x & 0xffff) + (x >> 16); + return x; +} + +static unsigned int do_csum(const unsigned char *buff, int len) +{ + int odd, count; + unsigned long result = 0; + + if (len <= 0) + goto out; + odd = 1 & (unsigned long) buff; + if (odd) { +#ifdef __LITTLE_ENDIAN + result = *buff; +#else + result += (*buff << 8); +#endif + len--; + buff++; + } + count = len >> 1; /* nr of 16-bit words.. */ + if (count) { + if (2 & (unsigned long) buff) { + result += *(unsigned short *) buff; + count--; + len -= 2; + buff += 2; + } + count >>= 1; /* nr of 32-bit words.. */ + if (count) { + unsigned long carry = 0; + do { + unsigned long w = *(unsigned int *) buff; + count--; + buff += 4; + result += carry; + result += w; + carry = (w > result); + } while (count); + result += carry; + result = (result & 0xffff) + (result >> 16); + } + if (len & 2) { + result += *(unsigned short *) buff; + buff += 2; + } + } + if (len & 1) +#ifdef __LITTLE_ENDIAN + result += *buff; +#else + result += (*buff << 8); +#endif + result = from32to16(result); + if (odd) + result = ((result >> 8) & 0xff) | ((result & 0xff) << 8); +out: + return result; +} + +/* + * This is a version of ip_compute_csum() optimized for IP headers, + * which always checksum on 4 octet boundaries. + */ +__sum16 ip_fast_csum(const void *iph, unsigned int ihl) +{ + return (__force __sum16)~do_csum(iph, ihl*4); +} +EXPORT_SYMBOL(ip_fast_csum); + +/* + * computes the checksum of a memory block at buff, length len, + * and adds in "sum" (32-bit) + * + * returns a 32-bit number suitable for feeding into itself + * or csum_tcpudp_magic + * + * this function must be called with even lengths, except + * for the last fragment, which may be odd + * + * it's best to have buff aligned on a 32-bit boundary + */ +__wsum csum_partial(const void *buff, int len, __wsum wsum) +{ + unsigned int sum = (__force unsigned int)wsum; + unsigned int result = do_csum(buff, len); + + /* add in old sum, and carry.. */ + result += sum; + if (sum > result) + result += 1; + return (__force __wsum)result; +} +EXPORT_SYMBOL(csum_partial); + +/* + * this routine is used for miscellaneous IP-like checksums, mainly + * in icmp.c + */ +__sum16 ip_compute_csum(const void *buff, int len) +{ + return (__force __sum16)~do_csum(buff, len); +} +EXPORT_SYMBOL(ip_compute_csum); + +/* + * copy from fs while checksumming, otherwise like csum_partial + */ +__wsum +csum_partial_copy_from_user(const void __user *src, void *dst, int len, + __wsum sum, int *csum_err) +{ + int missing; + + missing = __copy_from_user(dst, src, len); + if (missing) { + memset(dst + len - missing, 0, missing); + *csum_err = -EFAULT; + } else + *csum_err = 0; + + return csum_partial(dst, len, sum); +} +EXPORT_SYMBOL(csum_partial_copy_from_user); + +/* + * copy from ds while checksumming, otherwise like csum_partial + */ +__wsum +csum_partial_copy(const void *src, void *dst, int len, __wsum sum) +{ + memcpy(dst, src, len); + return csum_partial(dst, len, sum); +} +EXPORT_SYMBOL(csum_partial_copy); + +#ifndef csum_tcpudp_nofold +__wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr, + unsigned short len, + unsigned short proto, + __wsum sum) +{ + unsigned long long s = (__force u32)sum; + + s += (__force u32)saddr; + s += (__force u32)daddr; +#ifdef __BIG_ENDIAN + s += proto + len; +#else + s += (proto + len) << 8; +#endif + s += (s >> 32); + return (__force __wsum)s; +} +EXPORT_SYMBOL(csum_tcpudp_nofold); +#endif diff --git a/lib/cpumask.c b/lib/cpumask.c index eb23aaa0c7b8..7bb4142a502f 100644 --- a/lib/cpumask.c +++ b/lib/cpumask.c @@ -92,15 +92,8 @@ int cpumask_any_but(const struct cpumask *mask, unsigned int cpu) */ bool alloc_cpumask_var_node(cpumask_var_t *mask, gfp_t flags, int node) { - if (likely(slab_is_available())) - *mask = kmalloc_node(cpumask_size(), flags, node); - else { -#ifdef CONFIG_DEBUG_PER_CPU_MAPS - printk(KERN_ERR - "=> alloc_cpumask_var: kmalloc not available!\n"); -#endif - *mask = NULL; - } + *mask = kmalloc_node(cpumask_size(), flags, node); + #ifdef CONFIG_DEBUG_PER_CPU_MAPS if (!*mask) { printk(KERN_ERR "=> alloc_cpumask_var: failed!\n"); diff --git a/lib/dec_and_lock.c b/lib/dec_and_lock.c index a65c31455541..e73822aa6e9a 100644 --- a/lib/dec_and_lock.c +++ b/lib/dec_and_lock.c @@ -19,11 +19,10 @@ */ int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock) { -#ifdef CONFIG_SMP /* Subtract 1 from counter unless that drops it to 0 (ie. it was 1) */ if (atomic_add_unless(atomic, -1, 1)) return 0; -#endif + /* Otherwise do it the slow way */ spin_lock(lock); if (atomic_dec_and_test(atomic)) diff --git a/lib/dma-debug.c b/lib/dma-debug.c index 69da09a085a1..3b93129a968c 100644 --- a/lib/dma-debug.c +++ b/lib/dma-debug.c @@ -23,9 +23,11 @@ #include #include #include +#include #include #include #include +#include #include #include @@ -85,6 +87,7 @@ static u32 show_num_errors = 1; static u32 num_free_entries; static u32 min_free_entries; +static u32 nr_total_entries; /* number of preallocated entries requested by kernel cmdline */ static u32 req_entries; @@ -97,6 +100,16 @@ static struct dentry *show_all_errors_dent __read_mostly; static struct dentry *show_num_errors_dent __read_mostly; static struct dentry *num_free_entries_dent __read_mostly; static struct dentry *min_free_entries_dent __read_mostly; +static struct dentry *filter_dent __read_mostly; + +/* per-driver filter related state */ + +#define NAME_MAX_LEN 64 + +static char current_driver_name[NAME_MAX_LEN] __read_mostly; +static struct device_driver *current_driver __read_mostly; + +static DEFINE_RWLOCK(driver_name_lock); static const char *type2name[4] = { "single", "page", "scather-gather", "coherent" }; @@ -104,6 +117,11 @@ static const char *type2name[4] = { "single", "page", static const char *dir2name[4] = { "DMA_BIDIRECTIONAL", "DMA_TO_DEVICE", "DMA_FROM_DEVICE", "DMA_NONE" }; +/* little merge helper - remove it after the merge window */ +#ifndef BUS_NOTIFY_UNBOUND_DRIVER +#define BUS_NOTIFY_UNBOUND_DRIVER 0x0005 +#endif + /* * The access to some variables in this macro is racy. We can't use atomic_t * here because all these variables are exported to debugfs. Some of them even @@ -121,15 +139,54 @@ static inline void dump_entry_trace(struct dma_debug_entry *entry) { #ifdef CONFIG_STACKTRACE if (entry) { - printk(KERN_WARNING "Mapped at:\n"); + pr_warning("Mapped at:\n"); print_stack_trace(&entry->stacktrace, 0); } #endif } +static bool driver_filter(struct device *dev) +{ + struct device_driver *drv; + unsigned long flags; + bool ret; + + /* driver filter off */ + if (likely(!current_driver_name[0])) + return true; + + /* driver filter on and initialized */ + if (current_driver && dev->driver == current_driver) + return true; + + if (current_driver || !current_driver_name[0]) + return false; + + /* driver filter on but not yet initialized */ + drv = get_driver(dev->driver); + if (!drv) + return false; + + /* lock to protect against change of current_driver_name */ + read_lock_irqsave(&driver_name_lock, flags); + + ret = false; + if (drv->name && + strncmp(current_driver_name, drv->name, NAME_MAX_LEN - 1) == 0) { + current_driver = drv; + ret = true; + } + + read_unlock_irqrestore(&driver_name_lock, flags); + put_driver(drv); + + return ret; +} + #define err_printk(dev, entry, format, arg...) do { \ error_count += 1; \ - if (show_all_errors || show_num_errors > 0) { \ + if (driver_filter(dev) && \ + (show_all_errors || show_num_errors > 0)) { \ WARN(1, "%s %s: " format, \ dev_driver_string(dev), \ dev_name(dev) , ## arg); \ @@ -185,15 +242,51 @@ static void put_hash_bucket(struct hash_bucket *bucket, static struct dma_debug_entry *hash_bucket_find(struct hash_bucket *bucket, struct dma_debug_entry *ref) { - struct dma_debug_entry *entry; + struct dma_debug_entry *entry, *ret = NULL; + int matches = 0, match_lvl, last_lvl = 0; list_for_each_entry(entry, &bucket->list, list) { - if ((entry->dev_addr == ref->dev_addr) && - (entry->dev == ref->dev)) + if ((entry->dev_addr != ref->dev_addr) || + (entry->dev != ref->dev)) + continue; + + /* + * Some drivers map the same physical address multiple + * times. Without a hardware IOMMU this results in the + * same device addresses being put into the dma-debug + * hash multiple times too. This can result in false + * positives being reported. Therfore we implement a + * best-fit algorithm here which returns the entry from + * the hash which fits best to the reference value + * instead of the first-fit. + */ + matches += 1; + match_lvl = 0; + entry->size == ref->size ? ++match_lvl : 0; + entry->type == ref->type ? ++match_lvl : 0; + entry->direction == ref->direction ? ++match_lvl : 0; + entry->sg_call_ents == ref->sg_call_ents ? ++match_lvl : 0; + + if (match_lvl == 4) { + /* perfect-fit - return the result */ return entry; + } else if (match_lvl > last_lvl) { + /* + * We found an entry that fits better then the + * previous one + */ + last_lvl = match_lvl; + ret = entry; + } } - return NULL; + /* + * If we have multiple matches but no perfect-fit, just return + * NULL. + */ + ret = (matches == 1) ? ret : NULL; + + return ret; } /* @@ -257,6 +350,21 @@ static void add_dma_entry(struct dma_debug_entry *entry) put_hash_bucket(bucket, &flags); } +static struct dma_debug_entry *__dma_entry_alloc(void) +{ + struct dma_debug_entry *entry; + + entry = list_entry(free_entries.next, struct dma_debug_entry, list); + list_del(&entry->list); + memset(entry, 0, sizeof(*entry)); + + num_free_entries -= 1; + if (num_free_entries < min_free_entries) + min_free_entries = num_free_entries; + + return entry; +} + /* struct dma_entry allocator * * The next two functions implement the allocator for @@ -270,15 +378,12 @@ static struct dma_debug_entry *dma_entry_alloc(void) spin_lock_irqsave(&free_entries_lock, flags); if (list_empty(&free_entries)) { - printk(KERN_ERR "DMA-API: debugging out of memory " - "- disabling\n"); + pr_err("DMA-API: debugging out of memory - disabling\n"); global_disable = true; goto out; } - entry = list_entry(free_entries.next, struct dma_debug_entry, list); - list_del(&entry->list); - memset(entry, 0, sizeof(*entry)); + entry = __dma_entry_alloc(); #ifdef CONFIG_STACKTRACE entry->stacktrace.max_entries = DMA_DEBUG_STACKTRACE_ENTRIES; @@ -286,9 +391,6 @@ static struct dma_debug_entry *dma_entry_alloc(void) entry->stacktrace.skip = 2; save_stack_trace(&entry->stacktrace); #endif - num_free_entries -= 1; - if (num_free_entries < min_free_entries) - min_free_entries = num_free_entries; out: spin_unlock_irqrestore(&free_entries_lock, flags); @@ -310,6 +412,53 @@ static void dma_entry_free(struct dma_debug_entry *entry) spin_unlock_irqrestore(&free_entries_lock, flags); } +int dma_debug_resize_entries(u32 num_entries) +{ + int i, delta, ret = 0; + unsigned long flags; + struct dma_debug_entry *entry; + LIST_HEAD(tmp); + + spin_lock_irqsave(&free_entries_lock, flags); + + if (nr_total_entries < num_entries) { + delta = num_entries - nr_total_entries; + + spin_unlock_irqrestore(&free_entries_lock, flags); + + for (i = 0; i < delta; i++) { + entry = kzalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) + break; + + list_add_tail(&entry->list, &tmp); + } + + spin_lock_irqsave(&free_entries_lock, flags); + + list_splice(&tmp, &free_entries); + nr_total_entries += i; + num_free_entries += i; + } else { + delta = nr_total_entries - num_entries; + + for (i = 0; i < delta && !list_empty(&free_entries); i++) { + entry = __dma_entry_alloc(); + kfree(entry); + } + + nr_total_entries -= i; + } + + if (nr_total_entries != num_entries) + ret = 1; + + spin_unlock_irqrestore(&free_entries_lock, flags); + + return ret; +} +EXPORT_SYMBOL(dma_debug_resize_entries); + /* * DMA-API debugging init code * @@ -334,8 +483,7 @@ static int prealloc_memory(u32 num_entries) num_free_entries = num_entries; min_free_entries = num_entries; - printk(KERN_INFO "DMA-API: preallocated %d debug entries\n", - num_entries); + pr_info("DMA-API: preallocated %d debug entries\n", num_entries); return 0; @@ -349,11 +497,102 @@ out_err: return -ENOMEM; } +static ssize_t filter_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + char buf[NAME_MAX_LEN + 1]; + unsigned long flags; + int len; + + if (!current_driver_name[0]) + return 0; + + /* + * We can't copy to userspace directly because current_driver_name can + * only be read under the driver_name_lock with irqs disabled. So + * create a temporary copy first. + */ + read_lock_irqsave(&driver_name_lock, flags); + len = scnprintf(buf, NAME_MAX_LEN + 1, "%s\n", current_driver_name); + read_unlock_irqrestore(&driver_name_lock, flags); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t filter_write(struct file *file, const char __user *userbuf, + size_t count, loff_t *ppos) +{ + char buf[NAME_MAX_LEN]; + unsigned long flags; + size_t len; + int i; + + /* + * We can't copy from userspace directly. Access to + * current_driver_name is protected with a write_lock with irqs + * disabled. Since copy_from_user can fault and may sleep we + * need to copy to temporary buffer first + */ + len = min(count, (size_t)(NAME_MAX_LEN - 1)); + if (copy_from_user(buf, userbuf, len)) + return -EFAULT; + + buf[len] = 0; + + write_lock_irqsave(&driver_name_lock, flags); + + /* + * Now handle the string we got from userspace very carefully. + * The rules are: + * - only use the first token we got + * - token delimiter is everything looking like a space + * character (' ', '\n', '\t' ...) + * + */ + if (!isalnum(buf[0])) { + /* + * If the first character userspace gave us is not + * alphanumerical then assume the filter should be + * switched off. + */ + if (current_driver_name[0]) + pr_info("DMA-API: switching off dma-debug driver filter\n"); + current_driver_name[0] = 0; + current_driver = NULL; + goto out_unlock; + } + + /* + * Now parse out the first token and use it as the name for the + * driver to filter for. + */ + for (i = 0; i < NAME_MAX_LEN; ++i) { + current_driver_name[i] = buf[i]; + if (isspace(buf[i]) || buf[i] == ' ' || buf[i] == 0) + break; + } + current_driver_name[i] = 0; + current_driver = NULL; + + pr_info("DMA-API: enable driver filter for driver [%s]\n", + current_driver_name); + +out_unlock: + write_unlock_irqrestore(&driver_name_lock, flags); + + return count; +} + +const struct file_operations filter_fops = { + .read = filter_read, + .write = filter_write, +}; + static int dma_debug_fs_init(void) { dma_debug_dent = debugfs_create_dir("dma-api", NULL); if (!dma_debug_dent) { - printk(KERN_ERR "DMA-API: can not create debugfs directory\n"); + pr_err("DMA-API: can not create debugfs directory\n"); return -ENOMEM; } @@ -392,6 +631,11 @@ static int dma_debug_fs_init(void) if (!min_free_entries_dent) goto out_err; + filter_dent = debugfs_create_file("driver_filter", 0644, + dma_debug_dent, NULL, &filter_fops); + if (!filter_dent) + goto out_err; + return 0; out_err: @@ -400,9 +644,64 @@ out_err: return -ENOMEM; } +static int device_dma_allocations(struct device *dev) +{ + struct dma_debug_entry *entry; + unsigned long flags; + int count = 0, i; + + local_irq_save(flags); + + for (i = 0; i < HASH_SIZE; ++i) { + spin_lock(&dma_entry_hash[i].lock); + list_for_each_entry(entry, &dma_entry_hash[i].list, list) { + if (entry->dev == dev) + count += 1; + } + spin_unlock(&dma_entry_hash[i].lock); + } + + local_irq_restore(flags); + + return count; +} + +static int dma_debug_device_change(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct device *dev = data; + int count; + + + switch (action) { + case BUS_NOTIFY_UNBOUND_DRIVER: + count = device_dma_allocations(dev); + if (count == 0) + break; + err_printk(dev, NULL, "DMA-API: device driver has pending " + "DMA allocations while released from device " + "[count=%d]\n", count); + break; + default: + break; + } + + return 0; +} + void dma_debug_add_bus(struct bus_type *bus) { - /* FIXME: register notifier */ + struct notifier_block *nb; + + nb = kzalloc(sizeof(struct notifier_block), GFP_KERNEL); + if (nb == NULL) { + pr_err("dma_debug_add_bus: out of memory\n"); + return; + } + + nb->notifier_call = dma_debug_device_change; + + bus_register_notifier(bus, nb); } /* @@ -421,8 +720,7 @@ void dma_debug_init(u32 num_entries) } if (dma_debug_fs_init() != 0) { - printk(KERN_ERR "DMA-API: error creating debugfs entries " - "- disabling\n"); + pr_err("DMA-API: error creating debugfs entries - disabling\n"); global_disable = true; return; @@ -432,14 +730,15 @@ void dma_debug_init(u32 num_entries) num_entries = req_entries; if (prealloc_memory(num_entries) != 0) { - printk(KERN_ERR "DMA-API: debugging out of memory error " - "- disabled\n"); + pr_err("DMA-API: debugging out of memory error - disabled\n"); global_disable = true; return; } - printk(KERN_INFO "DMA-API: debugging enabled by kernel config\n"); + nr_total_entries = num_free_entries; + + pr_info("DMA-API: debugging enabled by kernel config\n"); } static __init int dma_debug_cmdline(char *str) @@ -448,8 +747,7 @@ static __init int dma_debug_cmdline(char *str) return -EINVAL; if (strncmp(str, "off", 3) == 0) { - printk(KERN_INFO "DMA-API: debugging disabled on kernel " - "command line\n"); + pr_info("DMA-API: debugging disabled on kernel command line\n"); global_disable = true; } @@ -576,72 +874,68 @@ static void check_for_illegal_area(struct device *dev, void *addr, u64 size) "[addr=%p] [size=%llu]\n", addr, size); } -static void check_sync(struct device *dev, dma_addr_t addr, - u64 size, u64 offset, int direction, bool to_cpu) +static void check_sync(struct device *dev, + struct dma_debug_entry *ref, + bool to_cpu) { - struct dma_debug_entry ref = { - .dev = dev, - .dev_addr = addr, - .size = size, - .direction = direction, - }; struct dma_debug_entry *entry; struct hash_bucket *bucket; unsigned long flags; - bucket = get_hash_bucket(&ref, &flags); + bucket = get_hash_bucket(ref, &flags); - entry = hash_bucket_find(bucket, &ref); + entry = hash_bucket_find(bucket, ref); if (!entry) { err_printk(dev, NULL, "DMA-API: device driver tries " "to sync DMA memory it has not allocated " "[device address=0x%016llx] [size=%llu bytes]\n", - (unsigned long long)addr, size); + (unsigned long long)ref->dev_addr, ref->size); goto out; } - if ((offset + size) > entry->size) { + if (ref->size > entry->size) { err_printk(dev, entry, "DMA-API: device driver syncs" " DMA memory outside allocated range " "[device address=0x%016llx] " - "[allocation size=%llu bytes] [sync offset=%llu] " - "[sync size=%llu]\n", entry->dev_addr, entry->size, - offset, size); + "[allocation size=%llu bytes] " + "[sync offset+size=%llu]\n", + entry->dev_addr, entry->size, + ref->size); } - if (direction != entry->direction) { + if (ref->direction != entry->direction) { err_printk(dev, entry, "DMA-API: device driver syncs " "DMA memory with different direction " "[device address=0x%016llx] [size=%llu bytes] " "[mapped with %s] [synced with %s]\n", - (unsigned long long)addr, entry->size, + (unsigned long long)ref->dev_addr, entry->size, dir2name[entry->direction], - dir2name[direction]); + dir2name[ref->direction]); } if (entry->direction == DMA_BIDIRECTIONAL) goto out; if (to_cpu && !(entry->direction == DMA_FROM_DEVICE) && - !(direction == DMA_TO_DEVICE)) + !(ref->direction == DMA_TO_DEVICE)) err_printk(dev, entry, "DMA-API: device driver syncs " "device read-only DMA memory for cpu " "[device address=0x%016llx] [size=%llu bytes] " "[mapped with %s] [synced with %s]\n", - (unsigned long long)addr, entry->size, + (unsigned long long)ref->dev_addr, entry->size, dir2name[entry->direction], - dir2name[direction]); + dir2name[ref->direction]); if (!to_cpu && !(entry->direction == DMA_TO_DEVICE) && - !(direction == DMA_FROM_DEVICE)) + !(ref->direction == DMA_FROM_DEVICE)) err_printk(dev, entry, "DMA-API: device driver syncs " "device write-only DMA memory to device " "[device address=0x%016llx] [size=%llu bytes] " "[mapped with %s] [synced with %s]\n", - (unsigned long long)addr, entry->size, + (unsigned long long)ref->dev_addr, entry->size, dir2name[entry->direction], - dir2name[direction]); + dir2name[ref->direction]); out: put_hash_bucket(bucket, &flags); @@ -723,15 +1017,15 @@ void debug_dma_map_sg(struct device *dev, struct scatterlist *sg, entry->type = dma_debug_sg; entry->dev = dev; entry->paddr = sg_phys(s); - entry->size = s->length; - entry->dev_addr = s->dma_address; + entry->size = sg_dma_len(s); + entry->dev_addr = sg_dma_address(s); entry->direction = direction; entry->sg_call_ents = nents; entry->sg_mapped_ents = mapped_ents; if (!PageHighMem(sg_page(s))) { check_for_stack(dev, sg_virt(s)); - check_for_illegal_area(dev, sg_virt(s), s->length); + check_for_illegal_area(dev, sg_virt(s), sg_dma_len(s)); } add_dma_entry(entry); @@ -739,13 +1033,30 @@ void debug_dma_map_sg(struct device *dev, struct scatterlist *sg, } EXPORT_SYMBOL(debug_dma_map_sg); +static int get_nr_mapped_entries(struct device *dev, + struct dma_debug_entry *ref) +{ + struct dma_debug_entry *entry; + struct hash_bucket *bucket; + unsigned long flags; + int mapped_ents; + + bucket = get_hash_bucket(ref, &flags); + entry = hash_bucket_find(bucket, ref); + mapped_ents = 0; + + if (entry) + mapped_ents = entry->sg_mapped_ents; + put_hash_bucket(bucket, &flags); + + return mapped_ents; +} + void debug_dma_unmap_sg(struct device *dev, struct scatterlist *sglist, int nelems, int dir) { - struct dma_debug_entry *entry; struct scatterlist *s; int mapped_ents = 0, i; - unsigned long flags; if (unlikely(global_disable)) return; @@ -756,24 +1067,17 @@ void debug_dma_unmap_sg(struct device *dev, struct scatterlist *sglist, .type = dma_debug_sg, .dev = dev, .paddr = sg_phys(s), - .dev_addr = s->dma_address, - .size = s->length, + .dev_addr = sg_dma_address(s), + .size = sg_dma_len(s), .direction = dir, - .sg_call_ents = 0, + .sg_call_ents = nelems, }; if (mapped_ents && i >= mapped_ents) break; - if (mapped_ents == 0) { - struct hash_bucket *bucket; - ref.sg_call_ents = nelems; - bucket = get_hash_bucket(&ref, &flags); - entry = hash_bucket_find(bucket, &ref); - if (entry) - mapped_ents = entry->sg_mapped_ents; - put_hash_bucket(bucket, &flags); - } + if (!i) + mapped_ents = get_nr_mapped_entries(dev, &ref); check_unmap(&ref); } @@ -828,10 +1132,19 @@ EXPORT_SYMBOL(debug_dma_free_coherent); void debug_dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size, int direction) { + struct dma_debug_entry ref; + if (unlikely(global_disable)) return; - check_sync(dev, dma_handle, size, 0, direction, true); + ref.type = dma_debug_single; + ref.dev = dev; + ref.dev_addr = dma_handle; + ref.size = size; + ref.direction = direction; + ref.sg_call_ents = 0; + + check_sync(dev, &ref, true); } EXPORT_SYMBOL(debug_dma_sync_single_for_cpu); @@ -839,10 +1152,19 @@ void debug_dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size, int direction) { + struct dma_debug_entry ref; + if (unlikely(global_disable)) return; - check_sync(dev, dma_handle, size, 0, direction, false); + ref.type = dma_debug_single; + ref.dev = dev; + ref.dev_addr = dma_handle; + ref.size = size; + ref.direction = direction; + ref.sg_call_ents = 0; + + check_sync(dev, &ref, false); } EXPORT_SYMBOL(debug_dma_sync_single_for_device); @@ -851,10 +1173,19 @@ void debug_dma_sync_single_range_for_cpu(struct device *dev, unsigned long offset, size_t size, int direction) { + struct dma_debug_entry ref; + if (unlikely(global_disable)) return; - check_sync(dev, dma_handle, size, offset, direction, true); + ref.type = dma_debug_single; + ref.dev = dev; + ref.dev_addr = dma_handle; + ref.size = offset + size; + ref.direction = direction; + ref.sg_call_ents = 0; + + check_sync(dev, &ref, true); } EXPORT_SYMBOL(debug_dma_sync_single_range_for_cpu); @@ -863,10 +1194,19 @@ void debug_dma_sync_single_range_for_device(struct device *dev, unsigned long offset, size_t size, int direction) { + struct dma_debug_entry ref; + if (unlikely(global_disable)) return; - check_sync(dev, dma_handle, size, offset, direction, false); + ref.type = dma_debug_single; + ref.dev = dev; + ref.dev_addr = dma_handle; + ref.size = offset + size; + ref.direction = direction; + ref.sg_call_ents = 0; + + check_sync(dev, &ref, false); } EXPORT_SYMBOL(debug_dma_sync_single_range_for_device); @@ -874,14 +1214,30 @@ void debug_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems, int direction) { struct scatterlist *s; - int i; + int mapped_ents = 0, i; if (unlikely(global_disable)) return; for_each_sg(sg, s, nelems, i) { - check_sync(dev, s->dma_address, s->dma_length, 0, - direction, true); + + struct dma_debug_entry ref = { + .type = dma_debug_sg, + .dev = dev, + .paddr = sg_phys(s), + .dev_addr = sg_dma_address(s), + .size = sg_dma_len(s), + .direction = direction, + .sg_call_ents = nelems, + }; + + if (!i) + mapped_ents = get_nr_mapped_entries(dev, &ref); + + if (i >= mapped_ents) + break; + + check_sync(dev, &ref, true); } } EXPORT_SYMBOL(debug_dma_sync_sg_for_cpu); @@ -890,15 +1246,48 @@ void debug_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems, int direction) { struct scatterlist *s; - int i; + int mapped_ents = 0, i; if (unlikely(global_disable)) return; for_each_sg(sg, s, nelems, i) { - check_sync(dev, s->dma_address, s->dma_length, 0, - direction, false); + + struct dma_debug_entry ref = { + .type = dma_debug_sg, + .dev = dev, + .paddr = sg_phys(s), + .dev_addr = sg_dma_address(s), + .size = sg_dma_len(s), + .direction = direction, + .sg_call_ents = nelems, + }; + if (!i) + mapped_ents = get_nr_mapped_entries(dev, &ref); + + if (i >= mapped_ents) + break; + + check_sync(dev, &ref, false); } } EXPORT_SYMBOL(debug_dma_sync_sg_for_device); +static int __init dma_debug_driver_setup(char *str) +{ + int i; + + for (i = 0; i < NAME_MAX_LEN - 1; ++i, ++str) { + current_driver_name[i] = *str; + if (*str == 0) + break; + } + + if (current_driver_name[0]) + pr_info("DMA-API: enable driver filter for driver [%s]\n", + current_driver_name); + + + return 1; +} +__setup("dma_debug_driver=", dma_debug_driver_setup); diff --git a/lib/extable.c b/lib/extable.c index 179c08745595..4cac81ec225e 100644 --- a/lib/extable.c +++ b/lib/extable.c @@ -39,7 +39,26 @@ void sort_extable(struct exception_table_entry *start, sort(start, finish - start, sizeof(struct exception_table_entry), cmp_ex, NULL); } -#endif + +#ifdef CONFIG_MODULES +/* + * If the exception table is sorted, any referring to the module init + * will be at the beginning or the end. + */ +void trim_init_extable(struct module *m) +{ + /*trim the beginning*/ + while (m->num_exentries && within_module_init(m->extable[0].insn, m)) { + m->extable++; + m->num_exentries--; + } + /*trim the end*/ + while (m->num_exentries && + within_module_init(m->extable[m->num_exentries-1].insn, m)) + m->num_exentries--; +} +#endif /* CONFIG_MODULES */ +#endif /* !ARCH_HAS_SORT_EXTABLE */ #ifndef ARCH_HAS_SEARCH_EXTABLE /* diff --git a/lib/gcd.c b/lib/gcd.c new file mode 100644 index 000000000000..f879033d9822 --- /dev/null +++ b/lib/gcd.c @@ -0,0 +1,18 @@ +#include +#include +#include + +/* Greatest common divisor */ +unsigned long gcd(unsigned long a, unsigned long b) +{ + unsigned long r; + + if (a < b) + swap(a, b); + while ((r = a % b) != 0) { + a = b; + b = r; + } + return b; +} +EXPORT_SYMBOL_GPL(gcd); diff --git a/lib/genalloc.c b/lib/genalloc.c index f6d276db2d58..eed2bdb865e7 100644 --- a/lib/genalloc.c +++ b/lib/genalloc.c @@ -85,7 +85,6 @@ void gen_pool_destroy(struct gen_pool *pool) int bit, end_bit; - write_lock(&pool->lock); list_for_each_safe(_chunk, _next_chunk, &pool->chunks) { chunk = list_entry(_chunk, struct gen_pool_chunk, next_chunk); list_del(&chunk->next_chunk); diff --git a/lib/hexdump.c b/lib/hexdump.c index f07c0db81d26..39af2560f765 100644 --- a/lib/hexdump.c +++ b/lib/hexdump.c @@ -65,7 +65,8 @@ void hex_dump_to_buffer(const void *buf, size_t len, int rowsize, for (j = 0; j < ngroups; j++) lx += scnprintf(linebuf + lx, linebuflen - lx, - "%16.16llx ", (unsigned long long)*(ptr8 + j)); + "%s%16.16llx", j ? " " : "", + (unsigned long long)*(ptr8 + j)); ascii_column = 17 * ngroups + 2; break; } @@ -76,7 +77,7 @@ void hex_dump_to_buffer(const void *buf, size_t len, int rowsize, for (j = 0; j < ngroups; j++) lx += scnprintf(linebuf + lx, linebuflen - lx, - "%8.8x ", *(ptr4 + j)); + "%s%8.8x", j ? " " : "", *(ptr4 + j)); ascii_column = 9 * ngroups + 2; break; } @@ -87,19 +88,21 @@ void hex_dump_to_buffer(const void *buf, size_t len, int rowsize, for (j = 0; j < ngroups; j++) lx += scnprintf(linebuf + lx, linebuflen - lx, - "%4.4x ", *(ptr2 + j)); + "%s%4.4x", j ? " " : "", *(ptr2 + j)); ascii_column = 5 * ngroups + 2; break; } default: - for (j = 0; (j < rowsize) && (j < len) && (lx + 4) < linebuflen; - j++) { + for (j = 0; (j < len) && (lx + 3) <= linebuflen; j++) { ch = ptr[j]; linebuf[lx++] = hex_asc_hi(ch); linebuf[lx++] = hex_asc_lo(ch); linebuf[lx++] = ' '; } + if (j) + lx--; + ascii_column = 3 * rowsize + 2; break; } @@ -108,7 +111,7 @@ void hex_dump_to_buffer(const void *buf, size_t len, int rowsize, while (lx < (linebuflen - 1) && lx < (ascii_column - 1)) linebuf[lx++] = ' '; - for (j = 0; (j < rowsize) && (j < len) && (lx + 2) < linebuflen; j++) + for (j = 0; (j < len) && (lx + 2) < linebuflen; j++) linebuf[lx++] = (isascii(ptr[j]) && isprint(ptr[j])) ? ptr[j] : '.'; nil: diff --git a/lib/kobject.c b/lib/kobject.c index bacf6fe4f7a0..b512b746d2af 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -793,11 +793,16 @@ static struct kset *kset_create(const char *name, struct kobject *parent_kobj) { struct kset *kset; + int retval; kset = kzalloc(sizeof(*kset), GFP_KERNEL); if (!kset) return NULL; - kobject_set_name(&kset->kobj, name); + retval = kobject_set_name(&kset->kobj, name); + if (retval) { + kfree(kset); + return NULL; + } kset->uevent_ops = uevent_ops; kset->kobj.parent = parent_kobj; diff --git a/lib/radix-tree.c b/lib/radix-tree.c index 4bb42a0344ec..23abbd93cae1 100644 --- a/lib/radix-tree.c +++ b/lib/radix-tree.c @@ -351,20 +351,12 @@ int radix_tree_insert(struct radix_tree_root *root, } EXPORT_SYMBOL(radix_tree_insert); -/** - * radix_tree_lookup_slot - lookup a slot in a radix tree - * @root: radix tree root - * @index: index key - * - * Returns: the slot corresponding to the position @index in the - * radix tree @root. This is useful for update-if-exists operations. - * - * This function can be called under rcu_read_lock iff the slot is not - * modified by radix_tree_replace_slot, otherwise it must be called - * exclusive from other writers. Any dereference of the slot must be done - * using radix_tree_deref_slot. +/* + * is_slot == 1 : search for the slot. + * is_slot == 0 : search for the node. */ -void **radix_tree_lookup_slot(struct radix_tree_root *root, unsigned long index) +static void *radix_tree_lookup_element(struct radix_tree_root *root, + unsigned long index, int is_slot) { unsigned int height, shift; struct radix_tree_node *node, **slot; @@ -376,7 +368,7 @@ void **radix_tree_lookup_slot(struct radix_tree_root *root, unsigned long index) if (!radix_tree_is_indirect_ptr(node)) { if (index > 0) return NULL; - return (void **)&root->rnode; + return is_slot ? (void *)&root->rnode : node; } node = radix_tree_indirect_to_ptr(node); @@ -397,7 +389,25 @@ void **radix_tree_lookup_slot(struct radix_tree_root *root, unsigned long index) height--; } while (height > 0); - return (void **)slot; + return is_slot ? (void *)slot:node; +} + +/** + * radix_tree_lookup_slot - lookup a slot in a radix tree + * @root: radix tree root + * @index: index key + * + * Returns: the slot corresponding to the position @index in the + * radix tree @root. This is useful for update-if-exists operations. + * + * This function can be called under rcu_read_lock iff the slot is not + * modified by radix_tree_replace_slot, otherwise it must be called + * exclusive from other writers. Any dereference of the slot must be done + * using radix_tree_deref_slot. + */ +void **radix_tree_lookup_slot(struct radix_tree_root *root, unsigned long index) +{ + return (void **)radix_tree_lookup_element(root, index, 1); } EXPORT_SYMBOL(radix_tree_lookup_slot); @@ -415,38 +425,7 @@ EXPORT_SYMBOL(radix_tree_lookup_slot); */ void *radix_tree_lookup(struct radix_tree_root *root, unsigned long index) { - unsigned int height, shift; - struct radix_tree_node *node, **slot; - - node = rcu_dereference(root->rnode); - if (node == NULL) - return NULL; - - if (!radix_tree_is_indirect_ptr(node)) { - if (index > 0) - return NULL; - return node; - } - node = radix_tree_indirect_to_ptr(node); - - height = node->height; - if (index > radix_tree_maxindex(height)) - return NULL; - - shift = (height-1) * RADIX_TREE_MAP_SHIFT; - - do { - slot = (struct radix_tree_node **) - (node->slots + ((index>>shift) & RADIX_TREE_MAP_MASK)); - node = rcu_dereference(*slot); - if (node == NULL) - return NULL; - - shift -= RADIX_TREE_MAP_SHIFT; - height--; - } while (height > 0); - - return node; + return radix_tree_lookup_element(root, index, 0); } EXPORT_SYMBOL(radix_tree_lookup); @@ -666,6 +645,43 @@ unsigned long radix_tree_next_hole(struct radix_tree_root *root, } EXPORT_SYMBOL(radix_tree_next_hole); +/** + * radix_tree_prev_hole - find the prev hole (not-present entry) + * @root: tree root + * @index: index key + * @max_scan: maximum range to search + * + * Search backwards in the range [max(index-max_scan+1, 0), index] + * for the first hole. + * + * Returns: the index of the hole if found, otherwise returns an index + * outside of the set specified (in which case 'index - return >= max_scan' + * will be true). In rare cases of wrap-around, LONG_MAX will be returned. + * + * radix_tree_next_hole may be called under rcu_read_lock. However, like + * radix_tree_gang_lookup, this will not atomically search a snapshot of + * the tree at a single point in time. For example, if a hole is created + * at index 10, then subsequently a hole is created at index 5, + * radix_tree_prev_hole covering both indexes may return 5 if called under + * rcu_read_lock. + */ +unsigned long radix_tree_prev_hole(struct radix_tree_root *root, + unsigned long index, unsigned long max_scan) +{ + unsigned long i; + + for (i = 0; i < max_scan; i++) { + if (!radix_tree_lookup(root, index)) + break; + index--; + if (index == LONG_MAX) + break; + } + + return index; +} +EXPORT_SYMBOL(radix_tree_prev_hole); + static unsigned int __lookup(struct radix_tree_node *slot, void ***results, unsigned long index, unsigned int max_items, unsigned long *next_index) diff --git a/lib/rational.c b/lib/rational.c new file mode 100644 index 000000000000..b3c099b5478e --- /dev/null +++ b/lib/rational.c @@ -0,0 +1,62 @@ +/* + * rational fractions + * + * Copyright (C) 2009 emlix GmbH, Oskar Schirmer + * + * helper functions when coping with rational numbers + */ + +#include + +/* + * calculate best rational approximation for a given fraction + * taking into account restricted register size, e.g. to find + * appropriate values for a pll with 5 bit denominator and + * 8 bit numerator register fields, trying to set up with a + * frequency ratio of 3.1415, one would say: + * + * rational_best_approximation(31415, 10000, + * (1 << 8) - 1, (1 << 5) - 1, &n, &d); + * + * you may look at given_numerator as a fixed point number, + * with the fractional part size described in given_denominator. + * + * for theoretical background, see: + * http://en.wikipedia.org/wiki/Continued_fraction + */ + +void rational_best_approximation( + unsigned long given_numerator, unsigned long given_denominator, + unsigned long max_numerator, unsigned long max_denominator, + unsigned long *best_numerator, unsigned long *best_denominator) +{ + unsigned long n, d, n0, d0, n1, d1; + n = given_numerator; + d = given_denominator; + n0 = d1 = 0; + n1 = d0 = 1; + for (;;) { + unsigned long t, a; + if ((n1 > max_numerator) || (d1 > max_denominator)) { + n1 = n0; + d1 = d0; + break; + } + if (d == 0) + break; + t = d; + a = n / d; + d = n % d; + n = t; + t = n0 + a * n1; + n0 = n1; + n1 = t; + t = d0 + a * d1; + d0 = d1; + d1 = t; + } + *best_numerator = n1; + *best_denominator = d1; +} + +EXPORT_SYMBOL(rational_best_approximation); diff --git a/lib/rbtree.c b/lib/rbtree.c index f653659e0bc1..e2aa3be29858 100644 --- a/lib/rbtree.c +++ b/lib/rbtree.c @@ -231,24 +231,8 @@ void rb_erase(struct rb_node *node, struct rb_root *root) node = node->rb_right; while ((left = node->rb_left) != NULL) node = left; - child = node->rb_right; - parent = rb_parent(node); - color = rb_color(node); - if (child) - rb_set_parent(child, parent); - if (parent == old) { - parent->rb_right = child; - parent = node; - } else - parent->rb_left = child; - - node->rb_parent_color = old->rb_parent_color; - node->rb_right = old->rb_right; - node->rb_left = old->rb_left; - - if (rb_parent(old)) - { + if (rb_parent(old)) { if (rb_parent(old)->rb_left == old) rb_parent(old)->rb_left = node; else @@ -256,9 +240,25 @@ void rb_erase(struct rb_node *node, struct rb_root *root) } else root->rb_node = node; - rb_set_parent(old->rb_left, node); - if (old->rb_right) + child = node->rb_right; + parent = rb_parent(node); + color = rb_color(node); + + if (parent == old) { + parent = node; + } else { + if (child) + rb_set_parent(child, parent); + parent->rb_left = child; + + node->rb_right = old->rb_right; rb_set_parent(old->rb_right, node); + } + + node->rb_parent_color = old->rb_parent_color; + node->rb_left = old->rb_left; + rb_set_parent(old->rb_left, node); + goto color; } diff --git a/lib/swiotlb.c b/lib/swiotlb.c index 2b0b5a7d2ced..bffe6d7ef9d9 100644 --- a/lib/swiotlb.c +++ b/lib/swiotlb.c @@ -60,8 +60,8 @@ enum dma_sync_target { int swiotlb_force; /* - * Used to do a quick range check in swiotlb_unmap_single and - * swiotlb_sync_single_*, to see if the memory was in fact allocated by this + * Used to do a quick range check in unmap_single and + * sync_single_*, to see if the memory was in fact allocated by this * API. */ static char *io_tlb_start, *io_tlb_end; @@ -129,7 +129,7 @@ dma_addr_t __weak swiotlb_phys_to_bus(struct device *hwdev, phys_addr_t paddr) return paddr; } -phys_addr_t __weak swiotlb_bus_to_phys(dma_addr_t baddr) +phys_addr_t __weak swiotlb_bus_to_phys(struct device *hwdev, dma_addr_t baddr) { return baddr; } @@ -140,9 +140,15 @@ static dma_addr_t swiotlb_virt_to_bus(struct device *hwdev, return swiotlb_phys_to_bus(hwdev, virt_to_phys(address)); } -static void *swiotlb_bus_to_virt(dma_addr_t address) +void * __weak swiotlb_bus_to_virt(struct device *hwdev, dma_addr_t address) { - return phys_to_virt(swiotlb_bus_to_phys(address)); + return phys_to_virt(swiotlb_bus_to_phys(hwdev, address)); +} + +int __weak swiotlb_arch_address_needs_mapping(struct device *hwdev, + dma_addr_t addr, size_t size) +{ + return !is_buffer_dma_capable(dma_get_mask(hwdev), addr, size); } int __weak swiotlb_arch_range_needs_mapping(phys_addr_t paddr, size_t size) @@ -309,10 +315,10 @@ cleanup1: return -ENOMEM; } -static int +static inline int address_needs_mapping(struct device *hwdev, dma_addr_t addr, size_t size) { - return !is_buffer_dma_capable(dma_get_mask(hwdev), addr, size); + return swiotlb_arch_address_needs_mapping(hwdev, addr, size); } static inline int range_needs_mapping(phys_addr_t paddr, size_t size) @@ -341,7 +347,7 @@ static void swiotlb_bounce(phys_addr_t phys, char *dma_addr, size_t size, unsigned long flags; while (size) { - sz = min(PAGE_SIZE - offset, size); + sz = min_t(size_t, PAGE_SIZE - offset, size); local_irq_save(flags); buffer = kmap_atomic(pfn_to_page(pfn), @@ -476,7 +482,7 @@ found: * dma_addr is the kernel virtual address of the bounce buffer to unmap. */ static void -unmap_single(struct device *hwdev, char *dma_addr, size_t size, int dir) +do_unmap_single(struct device *hwdev, char *dma_addr, size_t size, int dir) { unsigned long flags; int i, count, nslots = ALIGN(size, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT; @@ -560,7 +566,6 @@ swiotlb_alloc_coherent(struct device *hwdev, size_t size, size)) { /* * The allocated memory isn't reachable by the device. - * Fall back on swiotlb_map_single(). */ free_pages((unsigned long) ret, order); ret = NULL; @@ -568,9 +573,8 @@ swiotlb_alloc_coherent(struct device *hwdev, size_t size, if (!ret) { /* * We are either out of memory or the device can't DMA - * to GFP_DMA memory; fall back on - * swiotlb_map_single(), which will grab memory from - * the lowest available address range. + * to GFP_DMA memory; fall back on map_single(), which + * will grab memory from the lowest available address range. */ ret = map_single(hwdev, 0, size, DMA_FROM_DEVICE); if (!ret) @@ -587,7 +591,7 @@ swiotlb_alloc_coherent(struct device *hwdev, size_t size, (unsigned long long)dev_addr); /* DMA_TO_DEVICE to avoid memcpy in unmap_single */ - unmap_single(hwdev, ret, size, DMA_TO_DEVICE); + do_unmap_single(hwdev, ret, size, DMA_TO_DEVICE); return NULL; } *dma_handle = dev_addr; @@ -604,7 +608,7 @@ swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr, free_pages((unsigned long) vaddr, get_order(size)); else /* DMA_TO_DEVICE to avoid memcpy in unmap_single */ - unmap_single(hwdev, vaddr, size, DMA_TO_DEVICE); + do_unmap_single(hwdev, vaddr, size, DMA_TO_DEVICE); } EXPORT_SYMBOL(swiotlb_free_coherent); @@ -634,7 +638,7 @@ swiotlb_full(struct device *dev, size_t size, int dir, int do_panic) * physical address to use is returned. * * Once the device is given the dma address, the device owns this memory until - * either swiotlb_unmap_single or swiotlb_dma_sync_single is performed. + * either swiotlb_unmap_page or swiotlb_dma_sync_single is performed. */ dma_addr_t swiotlb_map_page(struct device *dev, struct page *page, unsigned long offset, size_t size, @@ -642,18 +646,17 @@ dma_addr_t swiotlb_map_page(struct device *dev, struct page *page, struct dma_attrs *attrs) { phys_addr_t phys = page_to_phys(page) + offset; - void *ptr = page_address(page) + offset; dma_addr_t dev_addr = swiotlb_phys_to_bus(dev, phys); void *map; BUG_ON(dir == DMA_NONE); /* - * If the pointer passed in happens to be in the device's DMA window, + * If the address happens to be in the device's DMA window, * we can safely return the device addr and not worry about bounce * buffering it. */ if (!address_needs_mapping(dev, dev_addr, size) && - !range_needs_mapping(virt_to_phys(ptr), size)) + !range_needs_mapping(phys, size)) return dev_addr; /* @@ -679,23 +682,35 @@ EXPORT_SYMBOL_GPL(swiotlb_map_page); /* * Unmap a single streaming mode DMA translation. The dma_addr and size must - * match what was provided for in a previous swiotlb_map_single call. All + * match what was provided for in a previous swiotlb_map_page call. All * other usages are undefined. * * After this call, reads by the cpu to the buffer are guaranteed to see * whatever the device wrote there. */ +static void unmap_single(struct device *hwdev, dma_addr_t dev_addr, + size_t size, int dir) +{ + char *dma_addr = swiotlb_bus_to_virt(hwdev, dev_addr); + + BUG_ON(dir == DMA_NONE); + + if (is_swiotlb_buffer(dma_addr)) { + do_unmap_single(hwdev, dma_addr, size, dir); + return; + } + + if (dir != DMA_FROM_DEVICE) + return; + + dma_mark_clean(dma_addr, size); +} + void swiotlb_unmap_page(struct device *hwdev, dma_addr_t dev_addr, size_t size, enum dma_data_direction dir, struct dma_attrs *attrs) { - char *dma_addr = swiotlb_bus_to_virt(dev_addr); - - BUG_ON(dir == DMA_NONE); - if (is_swiotlb_buffer(dma_addr)) - unmap_single(hwdev, dma_addr, size, dir); - else if (dir == DMA_FROM_DEVICE) - dma_mark_clean(dma_addr, size); + unmap_single(hwdev, dev_addr, size, dir); } EXPORT_SYMBOL_GPL(swiotlb_unmap_page); @@ -703,7 +718,7 @@ EXPORT_SYMBOL_GPL(swiotlb_unmap_page); * Make physical memory consistent for a single streaming mode DMA translation * after a transfer. * - * If you perform a swiotlb_map_single() but wish to interrogate the buffer + * If you perform a swiotlb_map_page() but wish to interrogate the buffer * using the cpu, yet do not wish to teardown the dma mapping, you must * call this function before doing so. At the next point you give the dma * address back to the card, you must first perform a @@ -713,13 +728,19 @@ static void swiotlb_sync_single(struct device *hwdev, dma_addr_t dev_addr, size_t size, int dir, int target) { - char *dma_addr = swiotlb_bus_to_virt(dev_addr); + char *dma_addr = swiotlb_bus_to_virt(hwdev, dev_addr); BUG_ON(dir == DMA_NONE); - if (is_swiotlb_buffer(dma_addr)) + + if (is_swiotlb_buffer(dma_addr)) { sync_single(hwdev, dma_addr, size, dir, target); - else if (dir == DMA_FROM_DEVICE) - dma_mark_clean(dma_addr, size); + return; + } + + if (dir != DMA_FROM_DEVICE) + return; + + dma_mark_clean(dma_addr, size); } void @@ -746,13 +767,7 @@ swiotlb_sync_single_range(struct device *hwdev, dma_addr_t dev_addr, unsigned long offset, size_t size, int dir, int target) { - char *dma_addr = swiotlb_bus_to_virt(dev_addr) + offset; - - BUG_ON(dir == DMA_NONE); - if (is_swiotlb_buffer(dma_addr)) - sync_single(hwdev, dma_addr, size, dir, target); - else if (dir == DMA_FROM_DEVICE) - dma_mark_clean(dma_addr, size); + swiotlb_sync_single(hwdev, dev_addr + offset, size, dir, target); } void @@ -777,7 +792,7 @@ EXPORT_SYMBOL_GPL(swiotlb_sync_single_range_for_device); /* * Map a set of buffers described by scatterlist in streaming mode for DMA. - * This is the scatter-gather version of the above swiotlb_map_single + * This is the scatter-gather version of the above swiotlb_map_page * interface. Here the scatter gather list elements are each tagged with the * appropriate dma address and length. They are obtained via * sg_dma_{address,length}(SG). @@ -788,7 +803,7 @@ EXPORT_SYMBOL_GPL(swiotlb_sync_single_range_for_device); * The routine returns the number of addr/length pairs actually * used, at most nents. * - * Device ownership issues as mentioned above for swiotlb_map_single are the + * Device ownership issues as mentioned above for swiotlb_map_page are the * same here. */ int @@ -836,7 +851,7 @@ EXPORT_SYMBOL(swiotlb_map_sg); /* * Unmap a set of streaming mode DMA translations. Again, cpu read rules - * concerning calls here are the same as for swiotlb_unmap_single() above. + * concerning calls here are the same as for swiotlb_unmap_page() above. */ void swiotlb_unmap_sg_attrs(struct device *hwdev, struct scatterlist *sgl, @@ -847,13 +862,9 @@ swiotlb_unmap_sg_attrs(struct device *hwdev, struct scatterlist *sgl, BUG_ON(dir == DMA_NONE); - for_each_sg(sgl, sg, nelems, i) { - if (sg->dma_address != swiotlb_phys_to_bus(hwdev, sg_phys(sg))) - unmap_single(hwdev, swiotlb_bus_to_virt(sg->dma_address), - sg->dma_length, dir); - else if (dir == DMA_FROM_DEVICE) - dma_mark_clean(swiotlb_bus_to_virt(sg->dma_address), sg->dma_length); - } + for_each_sg(sgl, sg, nelems, i) + unmap_single(hwdev, sg->dma_address, sg->dma_length, dir); + } EXPORT_SYMBOL(swiotlb_unmap_sg_attrs); @@ -879,15 +890,9 @@ swiotlb_sync_sg(struct device *hwdev, struct scatterlist *sgl, struct scatterlist *sg; int i; - BUG_ON(dir == DMA_NONE); - - for_each_sg(sgl, sg, nelems, i) { - if (sg->dma_address != swiotlb_phys_to_bus(hwdev, sg_phys(sg))) - sync_single(hwdev, swiotlb_bus_to_virt(sg->dma_address), + for_each_sg(sgl, sg, nelems, i) + swiotlb_sync_single(hwdev, sg->dma_address, sg->dma_length, dir, target); - else if (dir == DMA_FROM_DEVICE) - dma_mark_clean(swiotlb_bus_to_virt(sg->dma_address), sg->dma_length); - } } void diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 7536acea135b..756ccafa9cec 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -408,6 +408,8 @@ enum format_type { FORMAT_TYPE_LONG_LONG, FORMAT_TYPE_ULONG, FORMAT_TYPE_LONG, + FORMAT_TYPE_UBYTE, + FORMAT_TYPE_BYTE, FORMAT_TYPE_USHORT, FORMAT_TYPE_SHORT, FORMAT_TYPE_UINT, @@ -573,12 +575,15 @@ static char *string(char *buf, char *end, char *s, struct printf_spec spec) } static char *symbol_string(char *buf, char *end, void *ptr, - struct printf_spec spec) + struct printf_spec spec, char ext) { unsigned long value = (unsigned long) ptr; #ifdef CONFIG_KALLSYMS char sym[KSYM_SYMBOL_LEN]; - sprint_symbol(sym, value); + if (ext != 'f') + sprint_symbol(sym, value); + else + kallsyms_lookup(value, NULL, NULL, NULL, sym); return string(buf, end, sym, spec); #else spec.field_width = 2*sizeof(void *); @@ -690,7 +695,8 @@ static char *ip4_addr_string(char *buf, char *end, u8 *addr, * * Right now we handle: * - * - 'F' For symbolic function descriptor pointers + * - 'F' For symbolic function descriptor pointers with offset + * - 'f' For simple symbolic function names without offset * - 'S' For symbolic direct pointers * - 'R' For a struct resource pointer, it prints the range of * addresses (not the name nor the flags) @@ -713,10 +719,11 @@ static char *pointer(const char *fmt, char *buf, char *end, void *ptr, switch (*fmt) { case 'F': + case 'f': ptr = dereference_function_descriptor(ptr); /* Fallthrough */ case 'S': - return symbol_string(buf, end, ptr, spec); + return symbol_string(buf, end, ptr, spec, *fmt); case 'R': return resource_string(buf, end, ptr, spec); case 'm': @@ -853,11 +860,15 @@ qualifier: spec->qualifier = -1; if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt == 'Z' || *fmt == 'z' || *fmt == 't') { - spec->qualifier = *fmt; - ++fmt; - if (spec->qualifier == 'l' && *fmt == 'l') { - spec->qualifier = 'L'; - ++fmt; + spec->qualifier = *fmt++; + if (unlikely(spec->qualifier == *fmt)) { + if (spec->qualifier == 'l') { + spec->qualifier = 'L'; + ++fmt; + } else if (spec->qualifier == 'h') { + spec->qualifier = 'H'; + ++fmt; + } } } @@ -919,6 +930,11 @@ qualifier: spec->type = FORMAT_TYPE_SIZE_T; } else if (spec->qualifier == 't') { spec->type = FORMAT_TYPE_PTRDIFF; + } else if (spec->qualifier == 'H') { + if (spec->flags & SIGN) + spec->type = FORMAT_TYPE_BYTE; + else + spec->type = FORMAT_TYPE_UBYTE; } else if (spec->qualifier == 'h') { if (spec->flags & SIGN) spec->type = FORMAT_TYPE_SHORT; @@ -943,7 +959,8 @@ qualifier: * * This function follows C99 vsnprintf, but has some extensions: * %pS output the name of a text symbol - * %pF output the name of a function pointer + * %pF output the name of a function pointer with its offset + * %pf output the name of a function pointer without its offset * %pR output the address range in a struct resource * * The return value is the number of characters which would @@ -1087,6 +1104,12 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) case FORMAT_TYPE_PTRDIFF: num = va_arg(args, ptrdiff_t); break; + case FORMAT_TYPE_UBYTE: + num = (unsigned char) va_arg(args, int); + break; + case FORMAT_TYPE_BYTE: + num = (signed char) va_arg(args, int); + break; case FORMAT_TYPE_USHORT: num = (unsigned short) va_arg(args, int); break; @@ -1363,6 +1386,10 @@ do { \ case FORMAT_TYPE_PTRDIFF: save_arg(ptrdiff_t); break; + case FORMAT_TYPE_UBYTE: + case FORMAT_TYPE_BYTE: + save_arg(char); + break; case FORMAT_TYPE_USHORT: case FORMAT_TYPE_SHORT: save_arg(short); @@ -1391,7 +1418,8 @@ EXPORT_SYMBOL_GPL(vbin_printf); * * The format follows C99 vsnprintf, but has some extensions: * %pS output the name of a text symbol - * %pF output the name of a function pointer + * %pF output the name of a function pointer with its offset + * %pf output the name of a function pointer without its offset * %pR output the address range in a struct resource * %n is ignored * @@ -1538,6 +1566,12 @@ int bstr_printf(char *buf, size_t size, const char *fmt, const u32 *bin_buf) case FORMAT_TYPE_PTRDIFF: num = get_arg(ptrdiff_t); break; + case FORMAT_TYPE_UBYTE: + num = get_arg(unsigned char); + break; + case FORMAT_TYPE_BYTE: + num = get_arg(signed char); + break; case FORMAT_TYPE_USHORT: num = get_arg(unsigned short); break; diff --git a/mm/Kconfig b/mm/Kconfig index c2b57d81e153..c948d4ca8bde 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -128,11 +128,11 @@ config SPARSEMEM_VMEMMAP config MEMORY_HOTPLUG bool "Allow for memory hot-add" depends on SPARSEMEM || X86_64_ACPI_NUMA - depends on HOTPLUG && !HIBERNATION && ARCH_ENABLE_MEMORY_HOTPLUG + depends on HOTPLUG && !(HIBERNATION && !S390) && ARCH_ENABLE_MEMORY_HOTPLUG depends on (IA64 || X86 || PPC64 || SUPERH || S390) comment "Memory hotplug is currently incompatible with Software Suspend" - depends on SPARSEMEM && HOTPLUG && HIBERNATION + depends on SPARSEMEM && HOTPLUG && HIBERNATION && !S390 config MEMORY_HOTPLUG_SPARSE def_bool y @@ -203,29 +203,36 @@ config VIRT_TO_BUS def_bool y depends on !ARCH_NO_VIRT_TO_BUS -config UNEVICTABLE_LRU - bool "Add LRU list to track non-evictable pages" - default y - help - Keeps unevictable pages off of the active and inactive pageout - lists, so kswapd will not waste CPU time or have its balancing - algorithms thrown off by scanning these pages. Selecting this - will use one page flag and increase the code size a little, - say Y unless you know what you are doing. - - See Documentation/vm/unevictable-lru.txt for more information. - config HAVE_MLOCK bool default y if MMU=y config HAVE_MLOCKED_PAGE_BIT bool - default y if HAVE_MLOCK=y && UNEVICTABLE_LRU=y + default y if HAVE_MLOCK=y config MMU_NOTIFIER bool +config DEFAULT_MMAP_MIN_ADDR + int "Low address space to protect from user allocation" + default 4096 + help + This is the portion of low virtual memory which should be protected + from userspace allocation. Keeping a user from writing to low pages + can help reduce the impact of kernel NULL pointer bugs. + + For most ia64, ppc64 and x86 users with lots of address space + a value of 65536 is reasonable and should cause no problems. + On arm and other archs it should not be higher than 32768. + Programs which use vm86 functionality would either need additional + permissions from either the LSM or the capabilities module or have + this protection disabled. + + This value can be changed after boot using the + /proc/sys/vm/mmap_min_addr tunable. + + config NOMMU_INITIAL_TRIM_EXCESS int "Turn on mmap() excess space trimming before booting" depends on !MMU diff --git a/mm/Kconfig.debug b/mm/Kconfig.debug index bb01e298f260..aa99fd1f7109 100644 --- a/mm/Kconfig.debug +++ b/mm/Kconfig.debug @@ -2,6 +2,7 @@ config DEBUG_PAGEALLOC bool "Debug page memory allocations" depends on DEBUG_KERNEL && ARCH_SUPPORTS_DEBUG_PAGEALLOC depends on !HIBERNATION || !PPC && !SPARC + depends on !KMEMCHECK ---help--- Unmap pages from the kernel linear mapping after free_pages(). This results in a large slowdown, but helps to find certain types diff --git a/mm/Makefile b/mm/Makefile index ec73c68b6015..5e0bd6426693 100644 --- a/mm/Makefile +++ b/mm/Makefile @@ -12,6 +12,7 @@ obj-y := bootmem.o filemap.o mempool.o oom_kill.o fadvise.o \ readahead.o swap.o truncate.o vmscan.o shmem.o \ prio_tree.o util.o mmzone.o vmstat.o backing-dev.o \ page_isolation.o mm_init.o $(mmu-y) +obj-y += init-mm.o obj-$(CONFIG_PROC_PAGE_MONITOR) += pagewalk.o obj-$(CONFIG_BOUNCE) += bounce.o @@ -27,6 +28,7 @@ obj-$(CONFIG_MMU_NOTIFIER) += mmu_notifier.o obj-$(CONFIG_PAGE_POISONING) += debug-pagealloc.o obj-$(CONFIG_SLAB) += slab.o obj-$(CONFIG_SLUB) += slub.o +obj-$(CONFIG_KMEMCHECK) += kmemcheck.o obj-$(CONFIG_FAILSLAB) += failslab.o obj-$(CONFIG_MEMORY_HOTPLUG) += memory_hotplug.o obj-$(CONFIG_FS_XIP) += filemap_xip.o @@ -38,3 +40,5 @@ obj-$(CONFIG_SMP) += allocpercpu.o endif obj-$(CONFIG_QUICKLIST) += quicklist.o obj-$(CONFIG_CGROUP_MEM_RES_CTLR) += memcontrol.o page_cgroup.o +obj-$(CONFIG_DEBUG_KMEMLEAK) += kmemleak.o +obj-$(CONFIG_DEBUG_KMEMLEAK_TEST) += kmemleak-test.o diff --git a/mm/bootmem.c b/mm/bootmem.c index daf92713f7de..d2a9ce952768 100644 --- a/mm/bootmem.c +++ b/mm/bootmem.c @@ -532,12 +532,19 @@ static void * __init alloc_arch_preferred_bootmem(bootmem_data_t *bdata, unsigned long size, unsigned long align, unsigned long goal, unsigned long limit) { -#ifdef CONFIG_HAVE_ARCH_BOOTMEM - bootmem_data_t *p_bdata; + if (WARN_ON_ONCE(slab_is_available())) + return kzalloc(size, GFP_NOWAIT); - p_bdata = bootmem_arch_preferred_node(bdata, size, align, goal, limit); - if (p_bdata) - return alloc_bootmem_core(p_bdata, size, align, goal, limit); +#ifdef CONFIG_HAVE_ARCH_BOOTMEM + { + bootmem_data_t *p_bdata; + + p_bdata = bootmem_arch_preferred_node(bdata, size, align, + goal, limit); + if (p_bdata) + return alloc_bootmem_core(p_bdata, size, align, + goal, limit); + } #endif return NULL; } @@ -662,6 +669,9 @@ static void * __init ___alloc_bootmem_node(bootmem_data_t *bdata, void * __init __alloc_bootmem_node(pg_data_t *pgdat, unsigned long size, unsigned long align, unsigned long goal) { + if (WARN_ON_ONCE(slab_is_available())) + return kzalloc_node(size, GFP_NOWAIT, pgdat->node_id); + return ___alloc_bootmem_node(pgdat->bdata, size, align, goal, 0); } @@ -693,6 +703,9 @@ void * __init __alloc_bootmem_node_nopanic(pg_data_t *pgdat, unsigned long size, { void *ptr; + if (WARN_ON_ONCE(slab_is_available())) + return kzalloc_node(size, GFP_NOWAIT, pgdat->node_id); + ptr = alloc_arch_preferred_bootmem(pgdat->bdata, size, align, goal, 0); if (ptr) return ptr; @@ -745,6 +758,9 @@ void * __init __alloc_bootmem_low(unsigned long size, unsigned long align, void * __init __alloc_bootmem_low_node(pg_data_t *pgdat, unsigned long size, unsigned long align, unsigned long goal) { + if (WARN_ON_ONCE(slab_is_available())) + return kzalloc_node(size, GFP_NOWAIT, pgdat->node_id); + return ___alloc_bootmem_node(pgdat->bdata, size, align, goal, ARCH_LOW_ADDRESS_LIMIT); } diff --git a/mm/bounce.c b/mm/bounce.c index e590272fe7a8..a2b76a588e34 100644 --- a/mm/bounce.c +++ b/mm/bounce.c @@ -13,17 +13,15 @@ #include #include #include -#include -#include #include +#include + #define POOL_SIZE 64 #define ISA_POOL_SIZE 16 static mempool_t *page_pool, *isa_page_pool; -DEFINE_TRACE(block_bio_bounce); - #ifdef CONFIG_HIGHMEM static __init int init_emergency_pool(void) { @@ -192,7 +190,7 @@ static void __blk_queue_bounce(struct request_queue *q, struct bio **bio_orig, /* * is destination page below bounce pfn? */ - if (page_to_pfn(page) <= q->bounce_pfn) + if (page_to_pfn(page) <= queue_bounce_pfn(q)) continue; /* @@ -284,7 +282,7 @@ void blk_queue_bounce(struct request_queue *q, struct bio **bio_orig) * don't waste time iterating over bio segments */ if (!(q->bounce_gfp & GFP_DMA)) { - if (q->bounce_pfn >= blk_max_pfn) + if (queue_bounce_pfn(q) >= blk_max_pfn) return; pool = page_pool; } else { diff --git a/mm/fadvise.c b/mm/fadvise.c index 54a0f8040afa..e43359214f6f 100644 --- a/mm/fadvise.c +++ b/mm/fadvise.c @@ -101,7 +101,7 @@ SYSCALL_DEFINE(fadvise64_64)(int fd, loff_t offset, loff_t len, int advice) ret = force_page_cache_readahead(mapping, file, start_index, - max_sane_readahead(nrpages)); + nrpages); if (ret > 0) ret = 0; break; diff --git a/mm/filemap.c b/mm/filemap.c index 1b60f30cebfa..22396713feb9 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -521,7 +521,7 @@ struct page *__page_cache_alloc(gfp_t gfp) { if (cpuset_do_page_mem_spread()) { int n = cpuset_mem_spread_node(); - return alloc_pages_node(n, gfp, 0); + return alloc_pages_exact_node(n, gfp, 0); } return alloc_pages(gfp, 0); } @@ -1004,9 +1004,6 @@ EXPORT_SYMBOL(grab_cache_page_nowait); static void shrink_readahead_size_eio(struct file *filp, struct file_ra_state *ra) { - if (!ra->ra_pages) - return; - ra->ra_pages /= 4; } @@ -1390,8 +1387,7 @@ do_readahead(struct address_space *mapping, struct file *filp, if (!mapping || !mapping->a_ops || !mapping->a_ops->readpage) return -EINVAL; - force_page_cache_readahead(mapping, filp, index, - max_sane_readahead(nr)); + force_page_cache_readahead(mapping, filp, index, nr); return 0; } @@ -1457,6 +1453,73 @@ static int page_cache_read(struct file *file, pgoff_t offset) #define MMAP_LOTSAMISS (100) +/* + * Synchronous readahead happens when we don't even find + * a page in the page cache at all. + */ +static void do_sync_mmap_readahead(struct vm_area_struct *vma, + struct file_ra_state *ra, + struct file *file, + pgoff_t offset) +{ + unsigned long ra_pages; + struct address_space *mapping = file->f_mapping; + + /* If we don't want any read-ahead, don't bother */ + if (VM_RandomReadHint(vma)) + return; + + if (VM_SequentialReadHint(vma) || + offset - 1 == (ra->prev_pos >> PAGE_CACHE_SHIFT)) { + page_cache_sync_readahead(mapping, ra, file, offset, + ra->ra_pages); + return; + } + + if (ra->mmap_miss < INT_MAX) + ra->mmap_miss++; + + /* + * Do we miss much more than hit in this file? If so, + * stop bothering with read-ahead. It will only hurt. + */ + if (ra->mmap_miss > MMAP_LOTSAMISS) + return; + + /* + * mmap read-around + */ + ra_pages = max_sane_readahead(ra->ra_pages); + if (ra_pages) { + ra->start = max_t(long, 0, offset - ra_pages/2); + ra->size = ra_pages; + ra->async_size = 0; + ra_submit(ra, mapping, file); + } +} + +/* + * Asynchronous readahead happens when we find the page and PG_readahead, + * so we want to possibly extend the readahead further.. + */ +static void do_async_mmap_readahead(struct vm_area_struct *vma, + struct file_ra_state *ra, + struct file *file, + struct page *page, + pgoff_t offset) +{ + struct address_space *mapping = file->f_mapping; + + /* If we don't want any read-ahead, don't bother */ + if (VM_RandomReadHint(vma)) + return; + if (ra->mmap_miss > 0) + ra->mmap_miss--; + if (PageReadahead(page)) + page_cache_async_readahead(mapping, ra, file, + page, offset, ra->ra_pages); +} + /** * filemap_fault - read in file data for page fault handling * @vma: vma in which the fault was taken @@ -1476,78 +1539,44 @@ int filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) struct address_space *mapping = file->f_mapping; struct file_ra_state *ra = &file->f_ra; struct inode *inode = mapping->host; + pgoff_t offset = vmf->pgoff; struct page *page; pgoff_t size; - int did_readaround = 0; int ret = 0; size = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; - if (vmf->pgoff >= size) + if (offset >= size) return VM_FAULT_SIGBUS; - /* If we don't want any read-ahead, don't bother */ - if (VM_RandomReadHint(vma)) - goto no_cached_page; - /* * Do we have something in the page cache already? */ -retry_find: - page = find_lock_page(mapping, vmf->pgoff); - /* - * For sequential accesses, we use the generic readahead logic. - */ - if (VM_SequentialReadHint(vma)) { - if (!page) { - page_cache_sync_readahead(mapping, ra, file, - vmf->pgoff, 1); - page = find_lock_page(mapping, vmf->pgoff); - if (!page) - goto no_cached_page; - } - if (PageReadahead(page)) { - page_cache_async_readahead(mapping, ra, file, page, - vmf->pgoff, 1); - } - } - - if (!page) { - unsigned long ra_pages; - - ra->mmap_miss++; - + page = find_get_page(mapping, offset); + if (likely(page)) { /* - * Do we miss much more than hit in this file? If so, - * stop bothering with read-ahead. It will only hurt. + * We found the page, so try async readahead before + * waiting for the lock. */ - if (ra->mmap_miss > MMAP_LOTSAMISS) + do_async_mmap_readahead(vma, ra, file, page, offset); + lock_page(page); + + /* Did it get truncated? */ + if (unlikely(page->mapping != mapping)) { + unlock_page(page); + put_page(page); goto no_cached_page; - - /* - * To keep the pgmajfault counter straight, we need to - * check did_readaround, as this is an inner loop. - */ - if (!did_readaround) { - ret = VM_FAULT_MAJOR; - count_vm_event(PGMAJFAULT); } - did_readaround = 1; - ra_pages = max_sane_readahead(file->f_ra.ra_pages); - if (ra_pages) { - pgoff_t start = 0; - - if (vmf->pgoff > ra_pages / 2) - start = vmf->pgoff - ra_pages / 2; - do_page_cache_readahead(mapping, file, start, ra_pages); - } - page = find_lock_page(mapping, vmf->pgoff); + } else { + /* No page in the page cache at all */ + do_sync_mmap_readahead(vma, ra, file, offset); + count_vm_event(PGMAJFAULT); + ret = VM_FAULT_MAJOR; +retry_find: + page = find_lock_page(mapping, offset); if (!page) goto no_cached_page; } - if (!did_readaround) - ra->mmap_miss--; - /* * We have a locked page in the page cache, now we need to check * that it's up-to-date. If not, it is going to be due to an error. @@ -1555,18 +1584,18 @@ retry_find: if (unlikely(!PageUptodate(page))) goto page_not_uptodate; - /* Must recheck i_size under page lock */ + /* + * Found the page and have a reference on it. + * We must recheck i_size under page lock. + */ size = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; - if (unlikely(vmf->pgoff >= size)) { + if (unlikely(offset >= size)) { unlock_page(page); page_cache_release(page); return VM_FAULT_SIGBUS; } - /* - * Found the page and have a reference on it. - */ - ra->prev_pos = (loff_t)page->index << PAGE_CACHE_SHIFT; + ra->prev_pos = (loff_t)offset << PAGE_CACHE_SHIFT; vmf->page = page; return ret | VM_FAULT_LOCKED; @@ -1575,7 +1604,7 @@ no_cached_page: * We're only likely to ever get here if MADV_RANDOM is in * effect. */ - error = page_cache_read(file, vmf->pgoff); + error = page_cache_read(file, offset); /* * The page we want has now been added to the page cache. @@ -1595,12 +1624,6 @@ no_cached_page: return VM_FAULT_SIGBUS; page_not_uptodate: - /* IO error path */ - if (!did_readaround) { - ret = VM_FAULT_MAJOR; - count_vm_event(PGMAJFAULT); - } - /* * Umm, take care of errors if the page isn't up-to-date. * Try to re-read it _once_. We do this synchronously, diff --git a/mm/highmem.c b/mm/highmem.c index 68eb1d9b63fa..25878cc49daa 100644 --- a/mm/highmem.c +++ b/mm/highmem.c @@ -26,7 +26,6 @@ #include #include #include -#include #include /* diff --git a/mm/hugetlb.c b/mm/hugetlb.c index e83ad2c9228c..d0351e31f474 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -578,41 +578,6 @@ static void free_huge_page(struct page *page) hugetlb_put_quota(mapping, 1); } -/* - * Increment or decrement surplus_huge_pages. Keep node-specific counters - * balanced by operating on them in a round-robin fashion. - * Returns 1 if an adjustment was made. - */ -static int adjust_pool_surplus(struct hstate *h, int delta) -{ - static int prev_nid; - int nid = prev_nid; - int ret = 0; - - VM_BUG_ON(delta != -1 && delta != 1); - do { - nid = next_node(nid, node_online_map); - if (nid == MAX_NUMNODES) - nid = first_node(node_online_map); - - /* To shrink on this node, there must be a surplus page */ - if (delta < 0 && !h->surplus_huge_pages_node[nid]) - continue; - /* Surplus cannot exceed the total number of pages */ - if (delta > 0 && h->surplus_huge_pages_node[nid] >= - h->nr_huge_pages_node[nid]) - continue; - - h->surplus_huge_pages += delta; - h->surplus_huge_pages_node[nid] += delta; - ret = 1; - break; - } while (nid != prev_nid); - - prev_nid = nid; - return ret; -} - static void prep_new_huge_page(struct hstate *h, struct page *page, int nid) { set_compound_page_dtor(page, free_huge_page); @@ -623,6 +588,34 @@ static void prep_new_huge_page(struct hstate *h, struct page *page, int nid) put_page(page); /* free it into the hugepage allocator */ } +static void prep_compound_gigantic_page(struct page *page, unsigned long order) +{ + int i; + int nr_pages = 1 << order; + struct page *p = page + 1; + + /* we rely on prep_new_huge_page to set the destructor */ + set_compound_order(page, order); + __SetPageHead(page); + for (i = 1; i < nr_pages; i++, p = mem_map_next(p, page, i)) { + __SetPageTail(p); + p->first_page = page; + } +} + +int PageHuge(struct page *page) +{ + compound_page_dtor *dtor; + + if (!PageCompound(page)) + return 0; + + page = compound_head(page); + dtor = get_compound_page_dtor(page); + + return dtor == free_huge_page; +} + static struct page *alloc_fresh_huge_page_node(struct hstate *h, int nid) { struct page *page; @@ -630,7 +623,7 @@ static struct page *alloc_fresh_huge_page_node(struct hstate *h, int nid) if (h->order >= MAX_ORDER) return NULL; - page = alloc_pages_node(nid, + page = alloc_pages_exact_node(nid, htlb_alloc_mask|__GFP_COMP|__GFP_THISNODE| __GFP_REPEAT|__GFP_NOWARN, huge_page_order(h)); @@ -649,7 +642,7 @@ static struct page *alloc_fresh_huge_page_node(struct hstate *h, int nid) * Use a helper variable to find the next node and then * copy it back to hugetlb_next_nid afterwards: * otherwise there's a window in which a racer might - * pass invalid nid MAX_NUMNODES to alloc_pages_node. + * pass invalid nid MAX_NUMNODES to alloc_pages_exact_node. * But we don't need to use a spin_lock here: it really * doesn't matter if occasionally a racer chooses the * same nid as we do. Move nid forward in the mask even @@ -875,7 +868,7 @@ static void return_unused_surplus_pages(struct hstate *h, * can no longer free unreserved surplus pages. This occurs when * the nodes with surplus pages have no free pages. */ - unsigned long remaining_iterations = num_online_nodes(); + unsigned long remaining_iterations = nr_online_nodes; /* Uncommit the reservation */ h->resv_huge_pages -= unused_resv_pages; @@ -904,7 +897,7 @@ static void return_unused_surplus_pages(struct hstate *h, h->surplus_huge_pages--; h->surplus_huge_pages_node[nid]--; nr_pages--; - remaining_iterations = num_online_nodes(); + remaining_iterations = nr_online_nodes; } } } @@ -1140,6 +1133,41 @@ static inline void try_to_free_low(struct hstate *h, unsigned long count) } #endif +/* + * Increment or decrement surplus_huge_pages. Keep node-specific counters + * balanced by operating on them in a round-robin fashion. + * Returns 1 if an adjustment was made. + */ +static int adjust_pool_surplus(struct hstate *h, int delta) +{ + static int prev_nid; + int nid = prev_nid; + int ret = 0; + + VM_BUG_ON(delta != -1 && delta != 1); + do { + nid = next_node(nid, node_online_map); + if (nid == MAX_NUMNODES) + nid = first_node(node_online_map); + + /* To shrink on this node, there must be a surplus page */ + if (delta < 0 && !h->surplus_huge_pages_node[nid]) + continue; + /* Surplus cannot exceed the total number of pages */ + if (delta > 0 && h->surplus_huge_pages_node[nid] >= + h->nr_huge_pages_node[nid]) + continue; + + h->surplus_huge_pages += delta; + h->surplus_huge_pages_node[nid] += delta; + ret = 1; + break; + } while (nid != prev_nid); + + prev_nid = nid; + return ret; +} + #define persistent_huge_pages(h) (h->nr_huge_pages - h->surplus_huge_pages) static unsigned long set_max_huge_pages(struct hstate *h, unsigned long count) { @@ -1957,7 +1985,7 @@ static struct page *hugetlbfs_pagecache_page(struct hstate *h, } static int hugetlb_no_page(struct mm_struct *mm, struct vm_area_struct *vma, - unsigned long address, pte_t *ptep, int write_access) + unsigned long address, pte_t *ptep, unsigned int flags) { struct hstate *h = hstate_vma(vma); int ret = VM_FAULT_SIGBUS; @@ -2025,7 +2053,7 @@ retry: * any allocations necessary to record that reservation occur outside * the spinlock. */ - if (write_access && !(vma->vm_flags & VM_SHARED)) + if ((flags & FAULT_FLAG_WRITE) && !(vma->vm_flags & VM_SHARED)) if (vma_needs_reservation(h, vma, address) < 0) { ret = VM_FAULT_OOM; goto backout_unlocked; @@ -2044,7 +2072,7 @@ retry: && (vma->vm_flags & VM_SHARED))); set_huge_pte_at(mm, address, ptep, new_pte); - if (write_access && !(vma->vm_flags & VM_SHARED)) { + if ((flags & FAULT_FLAG_WRITE) && !(vma->vm_flags & VM_SHARED)) { /* Optimization, do the COW without a second fault */ ret = hugetlb_cow(mm, vma, address, ptep, new_pte, page); } @@ -2063,7 +2091,7 @@ backout_unlocked: } int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma, - unsigned long address, int write_access) + unsigned long address, unsigned int flags) { pte_t *ptep; pte_t entry; @@ -2084,7 +2112,7 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma, mutex_lock(&hugetlb_instantiation_mutex); entry = huge_ptep_get(ptep); if (huge_pte_none(entry)) { - ret = hugetlb_no_page(mm, vma, address, ptep, write_access); + ret = hugetlb_no_page(mm, vma, address, ptep, flags); goto out_mutex; } @@ -2098,7 +2126,7 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma, * page now as it is used to determine if a reservation has been * consumed. */ - if (write_access && !pte_write(entry)) { + if ((flags & FAULT_FLAG_WRITE) && !pte_write(entry)) { if (vma_needs_reservation(h, vma, address) < 0) { ret = VM_FAULT_OOM; goto out_mutex; @@ -2115,7 +2143,7 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma, goto out_page_table_lock; - if (write_access) { + if (flags & FAULT_FLAG_WRITE) { if (!pte_write(entry)) { ret = hugetlb_cow(mm, vma, address, ptep, entry, pagecache_page); @@ -2124,7 +2152,8 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma, entry = pte_mkdirty(entry); } entry = pte_mkyoung(entry); - if (huge_ptep_set_access_flags(vma, address, ptep, entry, write_access)) + if (huge_ptep_set_access_flags(vma, address, ptep, entry, + flags & FAULT_FLAG_WRITE)) update_mmu_cache(vma, address, entry); out_page_table_lock: diff --git a/mm/init-mm.c b/mm/init-mm.c new file mode 100644 index 000000000000..57aba0da9668 --- /dev/null +++ b/mm/init-mm.c @@ -0,0 +1,20 @@ +#include +#include +#include +#include +#include +#include + +#include +#include + +struct mm_struct init_mm = { + .mm_rb = RB_ROOT, + .pgd = swapper_pg_dir, + .mm_users = ATOMIC_INIT(2), + .mm_count = ATOMIC_INIT(1), + .mmap_sem = __RWSEM_INITIALIZER(init_mm.mmap_sem), + .page_table_lock = __SPIN_LOCK_UNLOCKED(init_mm.page_table_lock), + .mmlist = LIST_HEAD_INIT(init_mm.mmlist), + .cpu_vm_mask = CPU_MASK_ALL, +}; diff --git a/mm/internal.h b/mm/internal.h index 987bb03fbdd8..f290c4db528b 100644 --- a/mm/internal.h +++ b/mm/internal.h @@ -16,9 +16,6 @@ void free_pgtables(struct mmu_gather *tlb, struct vm_area_struct *start_vma, unsigned long floor, unsigned long ceiling); -extern void prep_compound_page(struct page *page, unsigned long order); -extern void prep_compound_gigantic_page(struct page *page, unsigned long order); - static inline void set_page_count(struct page *page, int v) { atomic_set(&page->_count, v); @@ -51,6 +48,8 @@ extern void putback_lru_page(struct page *page); */ extern unsigned long highest_memmap_pfn; extern void __free_pages_bootmem(struct page *page, unsigned int order); +extern void prep_compound_page(struct page *page, unsigned long order); + /* * function for dealing with page's order in buddy system. @@ -74,7 +73,6 @@ static inline void munlock_vma_pages_all(struct vm_area_struct *vma) } #endif -#ifdef CONFIG_UNEVICTABLE_LRU /* * unevictable_migrate_page() called only from migrate_page_copy() to * migrate unevictable flag to new page. @@ -86,11 +84,6 @@ static inline void unevictable_migrate_page(struct page *new, struct page *old) if (TestClearPageUnevictable(old)) SetPageUnevictable(new); } -#else -static inline void unevictable_migrate_page(struct page *new, struct page *old) -{ -} -#endif #ifdef CONFIG_HAVE_MLOCKED_PAGE_BIT /* @@ -150,23 +143,6 @@ static inline void mlock_migrate_page(struct page *newpage, struct page *page) } } -/* - * free_page_mlock() -- clean up attempts to free and mlocked() page. - * Page should not be on lru, so no need to fix that up. - * free_pages_check() will verify... - */ -static inline void free_page_mlock(struct page *page) -{ - if (unlikely(TestClearPageMlocked(page))) { - unsigned long flags; - - local_irq_save(flags); - __dec_zone_page_state(page, NR_MLOCK); - __count_vm_event(UNEVICTABLE_MLOCKFREED); - local_irq_restore(flags); - } -} - #else /* CONFIG_HAVE_MLOCKED_PAGE_BIT */ static inline int is_mlocked_vma(struct vm_area_struct *v, struct page *p) { @@ -175,7 +151,6 @@ static inline int is_mlocked_vma(struct vm_area_struct *v, struct page *p) static inline void clear_page_mlock(struct page *page) { } static inline void mlock_vma_page(struct page *page) { } static inline void mlock_migrate_page(struct page *new, struct page *old) { } -static inline void free_page_mlock(struct page *page) { } #endif /* CONFIG_HAVE_MLOCKED_PAGE_BIT */ @@ -284,4 +259,8 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long start, int len, int flags, struct page **pages, struct vm_area_struct **vmas); +#define ZONE_RECLAIM_NOSCAN -2 +#define ZONE_RECLAIM_FULL -1 +#define ZONE_RECLAIM_SOME 0 +#define ZONE_RECLAIM_SUCCESS 1 #endif diff --git a/mm/kmemcheck.c b/mm/kmemcheck.c new file mode 100644 index 000000000000..fd814fd61319 --- /dev/null +++ b/mm/kmemcheck.c @@ -0,0 +1,122 @@ +#include +#include +#include +#include +#include + +void kmemcheck_alloc_shadow(struct page *page, int order, gfp_t flags, int node) +{ + struct page *shadow; + int pages; + int i; + + pages = 1 << order; + + /* + * With kmemcheck enabled, we need to allocate a memory area for the + * shadow bits as well. + */ + shadow = alloc_pages_node(node, flags | __GFP_NOTRACK, order); + if (!shadow) { + if (printk_ratelimit()) + printk(KERN_ERR "kmemcheck: failed to allocate " + "shadow bitmap\n"); + return; + } + + for(i = 0; i < pages; ++i) + page[i].shadow = page_address(&shadow[i]); + + /* + * Mark it as non-present for the MMU so that our accesses to + * this memory will trigger a page fault and let us analyze + * the memory accesses. + */ + kmemcheck_hide_pages(page, pages); +} + +void kmemcheck_free_shadow(struct page *page, int order) +{ + struct page *shadow; + int pages; + int i; + + if (!kmemcheck_page_is_tracked(page)) + return; + + pages = 1 << order; + + kmemcheck_show_pages(page, pages); + + shadow = virt_to_page(page[0].shadow); + + for(i = 0; i < pages; ++i) + page[i].shadow = NULL; + + __free_pages(shadow, order); +} + +void kmemcheck_slab_alloc(struct kmem_cache *s, gfp_t gfpflags, void *object, + size_t size) +{ + /* + * Has already been memset(), which initializes the shadow for us + * as well. + */ + if (gfpflags & __GFP_ZERO) + return; + + /* No need to initialize the shadow of a non-tracked slab. */ + if (s->flags & SLAB_NOTRACK) + return; + + if (!kmemcheck_enabled || gfpflags & __GFP_NOTRACK) { + /* + * Allow notracked objects to be allocated from + * tracked caches. Note however that these objects + * will still get page faults on access, they just + * won't ever be flagged as uninitialized. If page + * faults are not acceptable, the slab cache itself + * should be marked NOTRACK. + */ + kmemcheck_mark_initialized(object, size); + } else if (!s->ctor) { + /* + * New objects should be marked uninitialized before + * they're returned to the called. + */ + kmemcheck_mark_uninitialized(object, size); + } +} + +void kmemcheck_slab_free(struct kmem_cache *s, void *object, size_t size) +{ + /* TODO: RCU freeing is unsupported for now; hide false positives. */ + if (!s->ctor && !(s->flags & SLAB_DESTROY_BY_RCU)) + kmemcheck_mark_freed(object, size); +} + +void kmemcheck_pagealloc_alloc(struct page *page, unsigned int order, + gfp_t gfpflags) +{ + int pages; + + if (gfpflags & (__GFP_HIGHMEM | __GFP_NOTRACK)) + return; + + pages = 1 << order; + + /* + * NOTE: We choose to track GFP_ZERO pages too; in fact, they + * can become uninitialized by copying uninitialized memory + * into them. + */ + + /* XXX: Can use zone->node for node? */ + kmemcheck_alloc_shadow(page, order, gfpflags, -1); + + if (gfpflags & __GFP_ZERO) + kmemcheck_mark_initialized_pages(page, pages); + else + kmemcheck_mark_uninitialized_pages(page, pages); +} diff --git a/mm/kmemleak-test.c b/mm/kmemleak-test.c new file mode 100644 index 000000000000..d5292fc6f523 --- /dev/null +++ b/mm/kmemleak-test.c @@ -0,0 +1,111 @@ +/* + * mm/kmemleak-test.c + * + * Copyright (C) 2008 ARM Limited + * Written by Catalin Marinas + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +struct test_node { + long header[25]; + struct list_head list; + long footer[25]; +}; + +static LIST_HEAD(test_list); +static DEFINE_PER_CPU(void *, test_pointer); + +/* + * Some very simple testing. This function needs to be extended for + * proper testing. + */ +static int __init kmemleak_test_init(void) +{ + struct test_node *elem; + int i; + + printk(KERN_INFO "Kmemleak testing\n"); + + /* make some orphan objects */ + pr_info("kmemleak: kmalloc(32) = %p\n", kmalloc(32, GFP_KERNEL)); + pr_info("kmemleak: kmalloc(32) = %p\n", kmalloc(32, GFP_KERNEL)); + pr_info("kmemleak: kmalloc(1024) = %p\n", kmalloc(1024, GFP_KERNEL)); + pr_info("kmemleak: kmalloc(1024) = %p\n", kmalloc(1024, GFP_KERNEL)); + pr_info("kmemleak: kmalloc(2048) = %p\n", kmalloc(2048, GFP_KERNEL)); + pr_info("kmemleak: kmalloc(2048) = %p\n", kmalloc(2048, GFP_KERNEL)); + pr_info("kmemleak: kmalloc(4096) = %p\n", kmalloc(4096, GFP_KERNEL)); + pr_info("kmemleak: kmalloc(4096) = %p\n", kmalloc(4096, GFP_KERNEL)); +#ifndef CONFIG_MODULES + pr_info("kmemleak: kmem_cache_alloc(files_cachep) = %p\n", + kmem_cache_alloc(files_cachep, GFP_KERNEL)); + pr_info("kmemleak: kmem_cache_alloc(files_cachep) = %p\n", + kmem_cache_alloc(files_cachep, GFP_KERNEL)); +#endif + pr_info("kmemleak: vmalloc(64) = %p\n", vmalloc(64)); + pr_info("kmemleak: vmalloc(64) = %p\n", vmalloc(64)); + pr_info("kmemleak: vmalloc(64) = %p\n", vmalloc(64)); + pr_info("kmemleak: vmalloc(64) = %p\n", vmalloc(64)); + pr_info("kmemleak: vmalloc(64) = %p\n", vmalloc(64)); + + /* + * Add elements to a list. They should only appear as orphan + * after the module is removed. + */ + for (i = 0; i < 10; i++) { + elem = kmalloc(sizeof(*elem), GFP_KERNEL); + pr_info("kmemleak: kmalloc(sizeof(*elem)) = %p\n", elem); + if (!elem) + return -ENOMEM; + memset(elem, 0, sizeof(*elem)); + INIT_LIST_HEAD(&elem->list); + + list_add_tail(&elem->list, &test_list); + } + + for_each_possible_cpu(i) { + per_cpu(test_pointer, i) = kmalloc(129, GFP_KERNEL); + pr_info("kmemleak: kmalloc(129) = %p\n", + per_cpu(test_pointer, i)); + } + + return 0; +} +module_init(kmemleak_test_init); + +static void __exit kmemleak_test_exit(void) +{ + struct test_node *elem, *tmp; + + /* + * Remove the list elements without actually freeing the + * memory. + */ + list_for_each_entry_safe(elem, tmp, &test_list, list) + list_del(&elem->list); +} +module_exit(kmemleak_test_exit); + +MODULE_LICENSE("GPL"); diff --git a/mm/kmemleak.c b/mm/kmemleak.c new file mode 100644 index 000000000000..c96f2c8700aa --- /dev/null +++ b/mm/kmemleak.c @@ -0,0 +1,1497 @@ +/* + * mm/kmemleak.c + * + * Copyright (C) 2008 ARM Limited + * Written by Catalin Marinas + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * For more information on the algorithm and kmemleak usage, please see + * Documentation/kmemleak.txt. + * + * Notes on locking + * ---------------- + * + * The following locks and mutexes are used by kmemleak: + * + * - kmemleak_lock (rwlock): protects the object_list modifications and + * accesses to the object_tree_root. The object_list is the main list + * holding the metadata (struct kmemleak_object) for the allocated memory + * blocks. The object_tree_root is a priority search tree used to look-up + * metadata based on a pointer to the corresponding memory block. The + * kmemleak_object structures are added to the object_list and + * object_tree_root in the create_object() function called from the + * kmemleak_alloc() callback and removed in delete_object() called from the + * kmemleak_free() callback + * - kmemleak_object.lock (spinlock): protects a kmemleak_object. Accesses to + * the metadata (e.g. count) are protected by this lock. Note that some + * members of this structure may be protected by other means (atomic or + * kmemleak_lock). This lock is also held when scanning the corresponding + * memory block to avoid the kernel freeing it via the kmemleak_free() + * callback. This is less heavyweight than holding a global lock like + * kmemleak_lock during scanning + * - scan_mutex (mutex): ensures that only one thread may scan the memory for + * unreferenced objects at a time. The gray_list contains the objects which + * are already referenced or marked as false positives and need to be + * scanned. This list is only modified during a scanning episode when the + * scan_mutex is held. At the end of a scan, the gray_list is always empty. + * Note that the kmemleak_object.use_count is incremented when an object is + * added to the gray_list and therefore cannot be freed + * - kmemleak_mutex (mutex): prevents multiple users of the "kmemleak" debugfs + * file together with modifications to the memory scanning parameters + * including the scan_thread pointer + * + * The kmemleak_object structures have a use_count incremented or decremented + * using the get_object()/put_object() functions. When the use_count becomes + * 0, this count can no longer be incremented and put_object() schedules the + * kmemleak_object freeing via an RCU callback. All calls to the get_object() + * function must be protected by rcu_read_lock() to avoid accessing a freed + * structure. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +/* + * Kmemleak configuration and common defines. + */ +#define MAX_TRACE 16 /* stack trace length */ +#define REPORTS_NR 50 /* maximum number of reported leaks */ +#define MSECS_MIN_AGE 5000 /* minimum object age for reporting */ +#define MSECS_SCAN_YIELD 10 /* CPU yielding period */ +#define SECS_FIRST_SCAN 60 /* delay before the first scan */ +#define SECS_SCAN_WAIT 600 /* subsequent auto scanning delay */ + +#define BYTES_PER_POINTER sizeof(void *) + +/* GFP bitmask for kmemleak internal allocations */ +#define GFP_KMEMLEAK_MASK (GFP_KERNEL | GFP_ATOMIC) + +/* scanning area inside a memory block */ +struct kmemleak_scan_area { + struct hlist_node node; + unsigned long offset; + size_t length; +}; + +/* + * Structure holding the metadata for each allocated memory block. + * Modifications to such objects should be made while holding the + * object->lock. Insertions or deletions from object_list, gray_list or + * tree_node are already protected by the corresponding locks or mutex (see + * the notes on locking above). These objects are reference-counted + * (use_count) and freed using the RCU mechanism. + */ +struct kmemleak_object { + spinlock_t lock; + unsigned long flags; /* object status flags */ + struct list_head object_list; + struct list_head gray_list; + struct prio_tree_node tree_node; + struct rcu_head rcu; /* object_list lockless traversal */ + /* object usage count; object freed when use_count == 0 */ + atomic_t use_count; + unsigned long pointer; + size_t size; + /* minimum number of a pointers found before it is considered leak */ + int min_count; + /* the total number of pointers found pointing to this object */ + int count; + /* memory ranges to be scanned inside an object (empty for all) */ + struct hlist_head area_list; + unsigned long trace[MAX_TRACE]; + unsigned int trace_len; + unsigned long jiffies; /* creation timestamp */ + pid_t pid; /* pid of the current task */ + char comm[TASK_COMM_LEN]; /* executable name */ +}; + +/* flag representing the memory block allocation status */ +#define OBJECT_ALLOCATED (1 << 0) +/* flag set after the first reporting of an unreference object */ +#define OBJECT_REPORTED (1 << 1) +/* flag set to not scan the object */ +#define OBJECT_NO_SCAN (1 << 2) + +/* the list of all allocated objects */ +static LIST_HEAD(object_list); +/* the list of gray-colored objects (see color_gray comment below) */ +static LIST_HEAD(gray_list); +/* prio search tree for object boundaries */ +static struct prio_tree_root object_tree_root; +/* rw_lock protecting the access to object_list and prio_tree_root */ +static DEFINE_RWLOCK(kmemleak_lock); + +/* allocation caches for kmemleak internal data */ +static struct kmem_cache *object_cache; +static struct kmem_cache *scan_area_cache; + +/* set if tracing memory operations is enabled */ +static atomic_t kmemleak_enabled = ATOMIC_INIT(0); +/* set in the late_initcall if there were no errors */ +static atomic_t kmemleak_initialized = ATOMIC_INIT(0); +/* enables or disables early logging of the memory operations */ +static atomic_t kmemleak_early_log = ATOMIC_INIT(1); +/* set if a fata kmemleak error has occurred */ +static atomic_t kmemleak_error = ATOMIC_INIT(0); + +/* minimum and maximum address that may be valid pointers */ +static unsigned long min_addr = ULONG_MAX; +static unsigned long max_addr; + +/* used for yielding the CPU to other tasks during scanning */ +static unsigned long next_scan_yield; +static struct task_struct *scan_thread; +static unsigned long jiffies_scan_yield; +static unsigned long jiffies_min_age; +/* delay between automatic memory scannings */ +static signed long jiffies_scan_wait; +/* enables or disables the task stacks scanning */ +static int kmemleak_stack_scan; +/* mutex protecting the memory scanning */ +static DEFINE_MUTEX(scan_mutex); +/* mutex protecting the access to the /sys/kernel/debug/kmemleak file */ +static DEFINE_MUTEX(kmemleak_mutex); + +/* number of leaks reported (for limitation purposes) */ +static int reported_leaks; + +/* + * Early object allocation/freeing logging. Kmemleak is initialized after the + * kernel allocator. However, both the kernel allocator and kmemleak may + * allocate memory blocks which need to be tracked. Kmemleak defines an + * arbitrary buffer to hold the allocation/freeing information before it is + * fully initialized. + */ + +/* kmemleak operation type for early logging */ +enum { + KMEMLEAK_ALLOC, + KMEMLEAK_FREE, + KMEMLEAK_NOT_LEAK, + KMEMLEAK_IGNORE, + KMEMLEAK_SCAN_AREA, + KMEMLEAK_NO_SCAN +}; + +/* + * Structure holding the information passed to kmemleak callbacks during the + * early logging. + */ +struct early_log { + int op_type; /* kmemleak operation type */ + const void *ptr; /* allocated/freed memory block */ + size_t size; /* memory block size */ + int min_count; /* minimum reference count */ + unsigned long offset; /* scan area offset */ + size_t length; /* scan area length */ +}; + +/* early logging buffer and current position */ +static struct early_log early_log[200]; +static int crt_early_log; + +static void kmemleak_disable(void); + +/* + * Print a warning and dump the stack trace. + */ +#define kmemleak_warn(x...) do { \ + pr_warning(x); \ + dump_stack(); \ +} while (0) + +/* + * Macro invoked when a serious kmemleak condition occured and cannot be + * recovered from. Kmemleak will be disabled and further allocation/freeing + * tracing no longer available. + */ +#define kmemleak_stop(x...) do { \ + kmemleak_warn(x); \ + kmemleak_disable(); \ +} while (0) + +/* + * Object colors, encoded with count and min_count: + * - white - orphan object, not enough references to it (count < min_count) + * - gray - not orphan, not marked as false positive (min_count == 0) or + * sufficient references to it (count >= min_count) + * - black - ignore, it doesn't contain references (e.g. text section) + * (min_count == -1). No function defined for this color. + * Newly created objects don't have any color assigned (object->count == -1) + * before the next memory scan when they become white. + */ +static int color_white(const struct kmemleak_object *object) +{ + return object->count != -1 && object->count < object->min_count; +} + +static int color_gray(const struct kmemleak_object *object) +{ + return object->min_count != -1 && object->count >= object->min_count; +} + +/* + * Objects are considered referenced if their color is gray and they have not + * been deleted. + */ +static int referenced_object(struct kmemleak_object *object) +{ + return (object->flags & OBJECT_ALLOCATED) && color_gray(object); +} + +/* + * Objects are considered unreferenced only if their color is white, they have + * not be deleted and have a minimum age to avoid false positives caused by + * pointers temporarily stored in CPU registers. + */ +static int unreferenced_object(struct kmemleak_object *object) +{ + return (object->flags & OBJECT_ALLOCATED) && color_white(object) && + time_is_before_eq_jiffies(object->jiffies + jiffies_min_age); +} + +/* + * Printing of the (un)referenced objects information, either to the seq file + * or to the kernel log. The print_referenced/print_unreferenced functions + * must be called with the object->lock held. + */ +#define print_helper(seq, x...) do { \ + struct seq_file *s = (seq); \ + if (s) \ + seq_printf(s, x); \ + else \ + pr_info(x); \ +} while (0) + +static void print_referenced(struct kmemleak_object *object) +{ + pr_info("referenced object 0x%08lx (size %zu)\n", + object->pointer, object->size); +} + +static void print_unreferenced(struct seq_file *seq, + struct kmemleak_object *object) +{ + int i; + + print_helper(seq, "unreferenced object 0x%08lx (size %zu):\n", + object->pointer, object->size); + print_helper(seq, " comm \"%s\", pid %d, jiffies %lu\n", + object->comm, object->pid, object->jiffies); + print_helper(seq, " backtrace:\n"); + + for (i = 0; i < object->trace_len; i++) { + void *ptr = (void *)object->trace[i]; + print_helper(seq, " [<%p>] %pS\n", ptr, ptr); + } +} + +/* + * Print the kmemleak_object information. This function is used mainly for + * debugging special cases when kmemleak operations. It must be called with + * the object->lock held. + */ +static void dump_object_info(struct kmemleak_object *object) +{ + struct stack_trace trace; + + trace.nr_entries = object->trace_len; + trace.entries = object->trace; + + pr_notice("Object 0x%08lx (size %zu):\n", + object->tree_node.start, object->size); + pr_notice(" comm \"%s\", pid %d, jiffies %lu\n", + object->comm, object->pid, object->jiffies); + pr_notice(" min_count = %d\n", object->min_count); + pr_notice(" count = %d\n", object->count); + pr_notice(" backtrace:\n"); + print_stack_trace(&trace, 4); +} + +/* + * Look-up a memory block metadata (kmemleak_object) in the priority search + * tree based on a pointer value. If alias is 0, only values pointing to the + * beginning of the memory block are allowed. The kmemleak_lock must be held + * when calling this function. + */ +static struct kmemleak_object *lookup_object(unsigned long ptr, int alias) +{ + struct prio_tree_node *node; + struct prio_tree_iter iter; + struct kmemleak_object *object; + + prio_tree_iter_init(&iter, &object_tree_root, ptr, ptr); + node = prio_tree_next(&iter); + if (node) { + object = prio_tree_entry(node, struct kmemleak_object, + tree_node); + if (!alias && object->pointer != ptr) { + kmemleak_warn("Found object by alias"); + object = NULL; + } + } else + object = NULL; + + return object; +} + +/* + * Increment the object use_count. Return 1 if successful or 0 otherwise. Note + * that once an object's use_count reached 0, the RCU freeing was already + * registered and the object should no longer be used. This function must be + * called under the protection of rcu_read_lock(). + */ +static int get_object(struct kmemleak_object *object) +{ + return atomic_inc_not_zero(&object->use_count); +} + +/* + * RCU callback to free a kmemleak_object. + */ +static void free_object_rcu(struct rcu_head *rcu) +{ + struct hlist_node *elem, *tmp; + struct kmemleak_scan_area *area; + struct kmemleak_object *object = + container_of(rcu, struct kmemleak_object, rcu); + + /* + * Once use_count is 0 (guaranteed by put_object), there is no other + * code accessing this object, hence no need for locking. + */ + hlist_for_each_entry_safe(area, elem, tmp, &object->area_list, node) { + hlist_del(elem); + kmem_cache_free(scan_area_cache, area); + } + kmem_cache_free(object_cache, object); +} + +/* + * Decrement the object use_count. Once the count is 0, free the object using + * an RCU callback. Since put_object() may be called via the kmemleak_free() -> + * delete_object() path, the delayed RCU freeing ensures that there is no + * recursive call to the kernel allocator. Lock-less RCU object_list traversal + * is also possible. + */ +static void put_object(struct kmemleak_object *object) +{ + if (!atomic_dec_and_test(&object->use_count)) + return; + + /* should only get here after delete_object was called */ + WARN_ON(object->flags & OBJECT_ALLOCATED); + + call_rcu(&object->rcu, free_object_rcu); +} + +/* + * Look up an object in the prio search tree and increase its use_count. + */ +static struct kmemleak_object *find_and_get_object(unsigned long ptr, int alias) +{ + unsigned long flags; + struct kmemleak_object *object = NULL; + + rcu_read_lock(); + read_lock_irqsave(&kmemleak_lock, flags); + if (ptr >= min_addr && ptr < max_addr) + object = lookup_object(ptr, alias); + read_unlock_irqrestore(&kmemleak_lock, flags); + + /* check whether the object is still available */ + if (object && !get_object(object)) + object = NULL; + rcu_read_unlock(); + + return object; +} + +/* + * Create the metadata (struct kmemleak_object) corresponding to an allocated + * memory block and add it to the object_list and object_tree_root. + */ +static void create_object(unsigned long ptr, size_t size, int min_count, + gfp_t gfp) +{ + unsigned long flags; + struct kmemleak_object *object; + struct prio_tree_node *node; + struct stack_trace trace; + + object = kmem_cache_alloc(object_cache, gfp & GFP_KMEMLEAK_MASK); + if (!object) { + kmemleak_stop("Cannot allocate a kmemleak_object structure\n"); + return; + } + + INIT_LIST_HEAD(&object->object_list); + INIT_LIST_HEAD(&object->gray_list); + INIT_HLIST_HEAD(&object->area_list); + spin_lock_init(&object->lock); + atomic_set(&object->use_count, 1); + object->flags = OBJECT_ALLOCATED; + object->pointer = ptr; + object->size = size; + object->min_count = min_count; + object->count = -1; /* no color initially */ + object->jiffies = jiffies; + + /* task information */ + if (in_irq()) { + object->pid = 0; + strncpy(object->comm, "hardirq", sizeof(object->comm)); + } else if (in_softirq()) { + object->pid = 0; + strncpy(object->comm, "softirq", sizeof(object->comm)); + } else { + object->pid = current->pid; + /* + * There is a small chance of a race with set_task_comm(), + * however using get_task_comm() here may cause locking + * dependency issues with current->alloc_lock. In the worst + * case, the command line is not correct. + */ + strncpy(object->comm, current->comm, sizeof(object->comm)); + } + + /* kernel backtrace */ + trace.max_entries = MAX_TRACE; + trace.nr_entries = 0; + trace.entries = object->trace; + trace.skip = 1; + save_stack_trace(&trace); + object->trace_len = trace.nr_entries; + + INIT_PRIO_TREE_NODE(&object->tree_node); + object->tree_node.start = ptr; + object->tree_node.last = ptr + size - 1; + + write_lock_irqsave(&kmemleak_lock, flags); + min_addr = min(min_addr, ptr); + max_addr = max(max_addr, ptr + size); + node = prio_tree_insert(&object_tree_root, &object->tree_node); + /* + * The code calling the kernel does not yet have the pointer to the + * memory block to be able to free it. However, we still hold the + * kmemleak_lock here in case parts of the kernel started freeing + * random memory blocks. + */ + if (node != &object->tree_node) { + unsigned long flags; + + kmemleak_stop("Cannot insert 0x%lx into the object search tree " + "(already existing)\n", ptr); + object = lookup_object(ptr, 1); + spin_lock_irqsave(&object->lock, flags); + dump_object_info(object); + spin_unlock_irqrestore(&object->lock, flags); + + goto out; + } + list_add_tail_rcu(&object->object_list, &object_list); +out: + write_unlock_irqrestore(&kmemleak_lock, flags); +} + +/* + * Remove the metadata (struct kmemleak_object) for a memory block from the + * object_list and object_tree_root and decrement its use_count. + */ +static void delete_object(unsigned long ptr) +{ + unsigned long flags; + struct kmemleak_object *object; + + write_lock_irqsave(&kmemleak_lock, flags); + object = lookup_object(ptr, 0); + if (!object) { + kmemleak_warn("Freeing unknown object at 0x%08lx\n", + ptr); + write_unlock_irqrestore(&kmemleak_lock, flags); + return; + } + prio_tree_remove(&object_tree_root, &object->tree_node); + list_del_rcu(&object->object_list); + write_unlock_irqrestore(&kmemleak_lock, flags); + + WARN_ON(!(object->flags & OBJECT_ALLOCATED)); + WARN_ON(atomic_read(&object->use_count) < 1); + + /* + * Locking here also ensures that the corresponding memory block + * cannot be freed when it is being scanned. + */ + spin_lock_irqsave(&object->lock, flags); + if (object->flags & OBJECT_REPORTED) + print_referenced(object); + object->flags &= ~OBJECT_ALLOCATED; + spin_unlock_irqrestore(&object->lock, flags); + put_object(object); +} + +/* + * Make a object permanently as gray-colored so that it can no longer be + * reported as a leak. This is used in general to mark a false positive. + */ +static void make_gray_object(unsigned long ptr) +{ + unsigned long flags; + struct kmemleak_object *object; + + object = find_and_get_object(ptr, 0); + if (!object) { + kmemleak_warn("Graying unknown object at 0x%08lx\n", ptr); + return; + } + + spin_lock_irqsave(&object->lock, flags); + object->min_count = 0; + spin_unlock_irqrestore(&object->lock, flags); + put_object(object); +} + +/* + * Mark the object as black-colored so that it is ignored from scans and + * reporting. + */ +static void make_black_object(unsigned long ptr) +{ + unsigned long flags; + struct kmemleak_object *object; + + object = find_and_get_object(ptr, 0); + if (!object) { + kmemleak_warn("Blacking unknown object at 0x%08lx\n", ptr); + return; + } + + spin_lock_irqsave(&object->lock, flags); + object->min_count = -1; + spin_unlock_irqrestore(&object->lock, flags); + put_object(object); +} + +/* + * Add a scanning area to the object. If at least one such area is added, + * kmemleak will only scan these ranges rather than the whole memory block. + */ +static void add_scan_area(unsigned long ptr, unsigned long offset, + size_t length, gfp_t gfp) +{ + unsigned long flags; + struct kmemleak_object *object; + struct kmemleak_scan_area *area; + + object = find_and_get_object(ptr, 0); + if (!object) { + kmemleak_warn("Adding scan area to unknown object at 0x%08lx\n", + ptr); + return; + } + + area = kmem_cache_alloc(scan_area_cache, gfp & GFP_KMEMLEAK_MASK); + if (!area) { + kmemleak_warn("Cannot allocate a scan area\n"); + goto out; + } + + spin_lock_irqsave(&object->lock, flags); + if (offset + length > object->size) { + kmemleak_warn("Scan area larger than object 0x%08lx\n", ptr); + dump_object_info(object); + kmem_cache_free(scan_area_cache, area); + goto out_unlock; + } + + INIT_HLIST_NODE(&area->node); + area->offset = offset; + area->length = length; + + hlist_add_head(&area->node, &object->area_list); +out_unlock: + spin_unlock_irqrestore(&object->lock, flags); +out: + put_object(object); +} + +/* + * Set the OBJECT_NO_SCAN flag for the object corresponding to the give + * pointer. Such object will not be scanned by kmemleak but references to it + * are searched. + */ +static void object_no_scan(unsigned long ptr) +{ + unsigned long flags; + struct kmemleak_object *object; + + object = find_and_get_object(ptr, 0); + if (!object) { + kmemleak_warn("Not scanning unknown object at 0x%08lx\n", ptr); + return; + } + + spin_lock_irqsave(&object->lock, flags); + object->flags |= OBJECT_NO_SCAN; + spin_unlock_irqrestore(&object->lock, flags); + put_object(object); +} + +/* + * Log an early kmemleak_* call to the early_log buffer. These calls will be + * processed later once kmemleak is fully initialized. + */ +static void log_early(int op_type, const void *ptr, size_t size, + int min_count, unsigned long offset, size_t length) +{ + unsigned long flags; + struct early_log *log; + + if (crt_early_log >= ARRAY_SIZE(early_log)) { + kmemleak_stop("Early log buffer exceeded\n"); + return; + } + + /* + * There is no need for locking since the kernel is still in UP mode + * at this stage. Disabling the IRQs is enough. + */ + local_irq_save(flags); + log = &early_log[crt_early_log]; + log->op_type = op_type; + log->ptr = ptr; + log->size = size; + log->min_count = min_count; + log->offset = offset; + log->length = length; + crt_early_log++; + local_irq_restore(flags); +} + +/* + * Memory allocation function callback. This function is called from the + * kernel allocators when a new block is allocated (kmem_cache_alloc, kmalloc, + * vmalloc etc.). + */ +void kmemleak_alloc(const void *ptr, size_t size, int min_count, gfp_t gfp) +{ + pr_debug("%s(0x%p, %zu, %d)\n", __func__, ptr, size, min_count); + + if (atomic_read(&kmemleak_enabled) && ptr && !IS_ERR(ptr)) + create_object((unsigned long)ptr, size, min_count, gfp); + else if (atomic_read(&kmemleak_early_log)) + log_early(KMEMLEAK_ALLOC, ptr, size, min_count, 0, 0); +} +EXPORT_SYMBOL_GPL(kmemleak_alloc); + +/* + * Memory freeing function callback. This function is called from the kernel + * allocators when a block is freed (kmem_cache_free, kfree, vfree etc.). + */ +void kmemleak_free(const void *ptr) +{ + pr_debug("%s(0x%p)\n", __func__, ptr); + + if (atomic_read(&kmemleak_enabled) && ptr && !IS_ERR(ptr)) + delete_object((unsigned long)ptr); + else if (atomic_read(&kmemleak_early_log)) + log_early(KMEMLEAK_FREE, ptr, 0, 0, 0, 0); +} +EXPORT_SYMBOL_GPL(kmemleak_free); + +/* + * Mark an already allocated memory block as a false positive. This will cause + * the block to no longer be reported as leak and always be scanned. + */ +void kmemleak_not_leak(const void *ptr) +{ + pr_debug("%s(0x%p)\n", __func__, ptr); + + if (atomic_read(&kmemleak_enabled) && ptr && !IS_ERR(ptr)) + make_gray_object((unsigned long)ptr); + else if (atomic_read(&kmemleak_early_log)) + log_early(KMEMLEAK_NOT_LEAK, ptr, 0, 0, 0, 0); +} +EXPORT_SYMBOL(kmemleak_not_leak); + +/* + * Ignore a memory block. This is usually done when it is known that the + * corresponding block is not a leak and does not contain any references to + * other allocated memory blocks. + */ +void kmemleak_ignore(const void *ptr) +{ + pr_debug("%s(0x%p)\n", __func__, ptr); + + if (atomic_read(&kmemleak_enabled) && ptr && !IS_ERR(ptr)) + make_black_object((unsigned long)ptr); + else if (atomic_read(&kmemleak_early_log)) + log_early(KMEMLEAK_IGNORE, ptr, 0, 0, 0, 0); +} +EXPORT_SYMBOL(kmemleak_ignore); + +/* + * Limit the range to be scanned in an allocated memory block. + */ +void kmemleak_scan_area(const void *ptr, unsigned long offset, size_t length, + gfp_t gfp) +{ + pr_debug("%s(0x%p)\n", __func__, ptr); + + if (atomic_read(&kmemleak_enabled) && ptr && !IS_ERR(ptr)) + add_scan_area((unsigned long)ptr, offset, length, gfp); + else if (atomic_read(&kmemleak_early_log)) + log_early(KMEMLEAK_SCAN_AREA, ptr, 0, 0, offset, length); +} +EXPORT_SYMBOL(kmemleak_scan_area); + +/* + * Inform kmemleak not to scan the given memory block. + */ +void kmemleak_no_scan(const void *ptr) +{ + pr_debug("%s(0x%p)\n", __func__, ptr); + + if (atomic_read(&kmemleak_enabled) && ptr && !IS_ERR(ptr)) + object_no_scan((unsigned long)ptr); + else if (atomic_read(&kmemleak_early_log)) + log_early(KMEMLEAK_NO_SCAN, ptr, 0, 0, 0, 0); +} +EXPORT_SYMBOL(kmemleak_no_scan); + +/* + * Yield the CPU so that other tasks get a chance to run. The yielding is + * rate-limited to avoid excessive number of calls to the schedule() function + * during memory scanning. + */ +static void scan_yield(void) +{ + might_sleep(); + + if (time_is_before_eq_jiffies(next_scan_yield)) { + schedule(); + next_scan_yield = jiffies + jiffies_scan_yield; + } +} + +/* + * Memory scanning is a long process and it needs to be interruptable. This + * function checks whether such interrupt condition occured. + */ +static int scan_should_stop(void) +{ + if (!atomic_read(&kmemleak_enabled)) + return 1; + + /* + * This function may be called from either process or kthread context, + * hence the need to check for both stop conditions. + */ + if (current->mm) + return signal_pending(current); + else + return kthread_should_stop(); + + return 0; +} + +/* + * Scan a memory block (exclusive range) for valid pointers and add those + * found to the gray list. + */ +static void scan_block(void *_start, void *_end, + struct kmemleak_object *scanned) +{ + unsigned long *ptr; + unsigned long *start = PTR_ALIGN(_start, BYTES_PER_POINTER); + unsigned long *end = _end - (BYTES_PER_POINTER - 1); + + for (ptr = start; ptr < end; ptr++) { + unsigned long flags; + unsigned long pointer = *ptr; + struct kmemleak_object *object; + + if (scan_should_stop()) + break; + + /* + * When scanning a memory block with a corresponding + * kmemleak_object, the CPU yielding is handled in the calling + * code since it holds the object->lock to avoid the block + * freeing. + */ + if (!scanned) + scan_yield(); + + object = find_and_get_object(pointer, 1); + if (!object) + continue; + if (object == scanned) { + /* self referenced, ignore */ + put_object(object); + continue; + } + + /* + * Avoid the lockdep recursive warning on object->lock being + * previously acquired in scan_object(). These locks are + * enclosed by scan_mutex. + */ + spin_lock_irqsave_nested(&object->lock, flags, + SINGLE_DEPTH_NESTING); + if (!color_white(object)) { + /* non-orphan, ignored or new */ + spin_unlock_irqrestore(&object->lock, flags); + put_object(object); + continue; + } + + /* + * Increase the object's reference count (number of pointers + * to the memory block). If this count reaches the required + * minimum, the object's color will become gray and it will be + * added to the gray_list. + */ + object->count++; + if (color_gray(object)) + list_add_tail(&object->gray_list, &gray_list); + else + put_object(object); + spin_unlock_irqrestore(&object->lock, flags); + } +} + +/* + * Scan a memory block corresponding to a kmemleak_object. A condition is + * that object->use_count >= 1. + */ +static void scan_object(struct kmemleak_object *object) +{ + struct kmemleak_scan_area *area; + struct hlist_node *elem; + unsigned long flags; + + /* + * Once the object->lock is aquired, the corresponding memory block + * cannot be freed (the same lock is aquired in delete_object). + */ + spin_lock_irqsave(&object->lock, flags); + if (object->flags & OBJECT_NO_SCAN) + goto out; + if (!(object->flags & OBJECT_ALLOCATED)) + /* already freed object */ + goto out; + if (hlist_empty(&object->area_list)) + scan_block((void *)object->pointer, + (void *)(object->pointer + object->size), object); + else + hlist_for_each_entry(area, elem, &object->area_list, node) + scan_block((void *)(object->pointer + area->offset), + (void *)(object->pointer + area->offset + + area->length), object); +out: + spin_unlock_irqrestore(&object->lock, flags); +} + +/* + * Scan data sections and all the referenced memory blocks allocated via the + * kernel's standard allocators. This function must be called with the + * scan_mutex held. + */ +static void kmemleak_scan(void) +{ + unsigned long flags; + struct kmemleak_object *object, *tmp; + struct task_struct *task; + int i; + + /* prepare the kmemleak_object's */ + rcu_read_lock(); + list_for_each_entry_rcu(object, &object_list, object_list) { + spin_lock_irqsave(&object->lock, flags); +#ifdef DEBUG + /* + * With a few exceptions there should be a maximum of + * 1 reference to any object at this point. + */ + if (atomic_read(&object->use_count) > 1) { + pr_debug("object->use_count = %d\n", + atomic_read(&object->use_count)); + dump_object_info(object); + } +#endif + /* reset the reference count (whiten the object) */ + object->count = 0; + if (color_gray(object) && get_object(object)) + list_add_tail(&object->gray_list, &gray_list); + + spin_unlock_irqrestore(&object->lock, flags); + } + rcu_read_unlock(); + + /* data/bss scanning */ + scan_block(_sdata, _edata, NULL); + scan_block(__bss_start, __bss_stop, NULL); + +#ifdef CONFIG_SMP + /* per-cpu sections scanning */ + for_each_possible_cpu(i) + scan_block(__per_cpu_start + per_cpu_offset(i), + __per_cpu_end + per_cpu_offset(i), NULL); +#endif + + /* + * Struct page scanning for each node. The code below is not yet safe + * with MEMORY_HOTPLUG. + */ + for_each_online_node(i) { + pg_data_t *pgdat = NODE_DATA(i); + unsigned long start_pfn = pgdat->node_start_pfn; + unsigned long end_pfn = start_pfn + pgdat->node_spanned_pages; + unsigned long pfn; + + for (pfn = start_pfn; pfn < end_pfn; pfn++) { + struct page *page; + + if (!pfn_valid(pfn)) + continue; + page = pfn_to_page(pfn); + /* only scan if page is in use */ + if (page_count(page) == 0) + continue; + scan_block(page, page + 1, NULL); + } + } + + /* + * Scanning the task stacks may introduce false negatives and it is + * not enabled by default. + */ + if (kmemleak_stack_scan) { + read_lock(&tasklist_lock); + for_each_process(task) + scan_block(task_stack_page(task), + task_stack_page(task) + THREAD_SIZE, NULL); + read_unlock(&tasklist_lock); + } + + /* + * Scan the objects already referenced from the sections scanned + * above. More objects will be referenced and, if there are no memory + * leaks, all the objects will be scanned. The list traversal is safe + * for both tail additions and removals from inside the loop. The + * kmemleak objects cannot be freed from outside the loop because their + * use_count was increased. + */ + object = list_entry(gray_list.next, typeof(*object), gray_list); + while (&object->gray_list != &gray_list) { + scan_yield(); + + /* may add new objects to the list */ + if (!scan_should_stop()) + scan_object(object); + + tmp = list_entry(object->gray_list.next, typeof(*object), + gray_list); + + /* remove the object from the list and release it */ + list_del(&object->gray_list); + put_object(object); + + object = tmp; + } + WARN_ON(!list_empty(&gray_list)); +} + +/* + * Thread function performing automatic memory scanning. Unreferenced objects + * at the end of a memory scan are reported but only the first time. + */ +static int kmemleak_scan_thread(void *arg) +{ + static int first_run = 1; + + pr_info("Automatic memory scanning thread started\n"); + + /* + * Wait before the first scan to allow the system to fully initialize. + */ + if (first_run) { + first_run = 0; + ssleep(SECS_FIRST_SCAN); + } + + while (!kthread_should_stop()) { + struct kmemleak_object *object; + signed long timeout = jiffies_scan_wait; + + mutex_lock(&scan_mutex); + + kmemleak_scan(); + reported_leaks = 0; + + rcu_read_lock(); + list_for_each_entry_rcu(object, &object_list, object_list) { + unsigned long flags; + + if (reported_leaks >= REPORTS_NR) + break; + spin_lock_irqsave(&object->lock, flags); + if (!(object->flags & OBJECT_REPORTED) && + unreferenced_object(object)) { + print_unreferenced(NULL, object); + object->flags |= OBJECT_REPORTED; + reported_leaks++; + } else if ((object->flags & OBJECT_REPORTED) && + referenced_object(object)) { + print_referenced(object); + object->flags &= ~OBJECT_REPORTED; + } + spin_unlock_irqrestore(&object->lock, flags); + } + rcu_read_unlock(); + + mutex_unlock(&scan_mutex); + /* wait before the next scan */ + while (timeout && !kthread_should_stop()) + timeout = schedule_timeout_interruptible(timeout); + } + + pr_info("Automatic memory scanning thread ended\n"); + + return 0; +} + +/* + * Start the automatic memory scanning thread. This function must be called + * with the kmemleak_mutex held. + */ +void start_scan_thread(void) +{ + if (scan_thread) + return; + scan_thread = kthread_run(kmemleak_scan_thread, NULL, "kmemleak"); + if (IS_ERR(scan_thread)) { + pr_warning("Failed to create the scan thread\n"); + scan_thread = NULL; + } +} + +/* + * Stop the automatic memory scanning thread. This function must be called + * with the kmemleak_mutex held. + */ +void stop_scan_thread(void) +{ + if (scan_thread) { + kthread_stop(scan_thread); + scan_thread = NULL; + } +} + +/* + * Iterate over the object_list and return the first valid object at or after + * the required position with its use_count incremented. The function triggers + * a memory scanning when the pos argument points to the first position. + */ +static void *kmemleak_seq_start(struct seq_file *seq, loff_t *pos) +{ + struct kmemleak_object *object; + loff_t n = *pos; + + if (!n) { + kmemleak_scan(); + reported_leaks = 0; + } + if (reported_leaks >= REPORTS_NR) + return NULL; + + rcu_read_lock(); + list_for_each_entry_rcu(object, &object_list, object_list) { + if (n-- > 0) + continue; + if (get_object(object)) + goto out; + } + object = NULL; +out: + rcu_read_unlock(); + return object; +} + +/* + * Return the next object in the object_list. The function decrements the + * use_count of the previous object and increases that of the next one. + */ +static void *kmemleak_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + struct kmemleak_object *prev_obj = v; + struct kmemleak_object *next_obj = NULL; + struct list_head *n = &prev_obj->object_list; + + ++(*pos); + if (reported_leaks >= REPORTS_NR) + goto out; + + rcu_read_lock(); + list_for_each_continue_rcu(n, &object_list) { + next_obj = list_entry(n, struct kmemleak_object, object_list); + if (get_object(next_obj)) + break; + } + rcu_read_unlock(); +out: + put_object(prev_obj); + return next_obj; +} + +/* + * Decrement the use_count of the last object required, if any. + */ +static void kmemleak_seq_stop(struct seq_file *seq, void *v) +{ + if (v) + put_object(v); +} + +/* + * Print the information for an unreferenced object to the seq file. + */ +static int kmemleak_seq_show(struct seq_file *seq, void *v) +{ + struct kmemleak_object *object = v; + unsigned long flags; + + spin_lock_irqsave(&object->lock, flags); + if (!unreferenced_object(object)) + goto out; + print_unreferenced(seq, object); + reported_leaks++; +out: + spin_unlock_irqrestore(&object->lock, flags); + return 0; +} + +static const struct seq_operations kmemleak_seq_ops = { + .start = kmemleak_seq_start, + .next = kmemleak_seq_next, + .stop = kmemleak_seq_stop, + .show = kmemleak_seq_show, +}; + +static int kmemleak_open(struct inode *inode, struct file *file) +{ + int ret = 0; + + if (!atomic_read(&kmemleak_enabled)) + return -EBUSY; + + ret = mutex_lock_interruptible(&kmemleak_mutex); + if (ret < 0) + goto out; + if (file->f_mode & FMODE_READ) { + ret = mutex_lock_interruptible(&scan_mutex); + if (ret < 0) + goto kmemleak_unlock; + ret = seq_open(file, &kmemleak_seq_ops); + if (ret < 0) + goto scan_unlock; + } + return ret; + +scan_unlock: + mutex_unlock(&scan_mutex); +kmemleak_unlock: + mutex_unlock(&kmemleak_mutex); +out: + return ret; +} + +static int kmemleak_release(struct inode *inode, struct file *file) +{ + int ret = 0; + + if (file->f_mode & FMODE_READ) { + seq_release(inode, file); + mutex_unlock(&scan_mutex); + } + mutex_unlock(&kmemleak_mutex); + + return ret; +} + +/* + * File write operation to configure kmemleak at run-time. The following + * commands can be written to the /sys/kernel/debug/kmemleak file: + * off - disable kmemleak (irreversible) + * stack=on - enable the task stacks scanning + * stack=off - disable the tasks stacks scanning + * scan=on - start the automatic memory scanning thread + * scan=off - stop the automatic memory scanning thread + * scan=... - set the automatic memory scanning period in seconds (0 to + * disable it) + */ +static ssize_t kmemleak_write(struct file *file, const char __user *user_buf, + size_t size, loff_t *ppos) +{ + char buf[64]; + int buf_size; + + if (!atomic_read(&kmemleak_enabled)) + return -EBUSY; + + buf_size = min(size, (sizeof(buf) - 1)); + if (strncpy_from_user(buf, user_buf, buf_size) < 0) + return -EFAULT; + buf[buf_size] = 0; + + if (strncmp(buf, "off", 3) == 0) + kmemleak_disable(); + else if (strncmp(buf, "stack=on", 8) == 0) + kmemleak_stack_scan = 1; + else if (strncmp(buf, "stack=off", 9) == 0) + kmemleak_stack_scan = 0; + else if (strncmp(buf, "scan=on", 7) == 0) + start_scan_thread(); + else if (strncmp(buf, "scan=off", 8) == 0) + stop_scan_thread(); + else if (strncmp(buf, "scan=", 5) == 0) { + unsigned long secs; + int err; + + err = strict_strtoul(buf + 5, 0, &secs); + if (err < 0) + return err; + stop_scan_thread(); + if (secs) { + jiffies_scan_wait = msecs_to_jiffies(secs * 1000); + start_scan_thread(); + } + } else + return -EINVAL; + + /* ignore the rest of the buffer, only one command at a time */ + *ppos += size; + return size; +} + +static const struct file_operations kmemleak_fops = { + .owner = THIS_MODULE, + .open = kmemleak_open, + .read = seq_read, + .write = kmemleak_write, + .llseek = seq_lseek, + .release = kmemleak_release, +}; + +/* + * Perform the freeing of the kmemleak internal objects after waiting for any + * current memory scan to complete. + */ +static int kmemleak_cleanup_thread(void *arg) +{ + struct kmemleak_object *object; + + mutex_lock(&kmemleak_mutex); + stop_scan_thread(); + mutex_unlock(&kmemleak_mutex); + + mutex_lock(&scan_mutex); + rcu_read_lock(); + list_for_each_entry_rcu(object, &object_list, object_list) + delete_object(object->pointer); + rcu_read_unlock(); + mutex_unlock(&scan_mutex); + + return 0; +} + +/* + * Start the clean-up thread. + */ +static void kmemleak_cleanup(void) +{ + struct task_struct *cleanup_thread; + + cleanup_thread = kthread_run(kmemleak_cleanup_thread, NULL, + "kmemleak-clean"); + if (IS_ERR(cleanup_thread)) + pr_warning("Failed to create the clean-up thread\n"); +} + +/* + * Disable kmemleak. No memory allocation/freeing will be traced once this + * function is called. Disabling kmemleak is an irreversible operation. + */ +static void kmemleak_disable(void) +{ + /* atomically check whether it was already invoked */ + if (atomic_cmpxchg(&kmemleak_error, 0, 1)) + return; + + /* stop any memory operation tracing */ + atomic_set(&kmemleak_early_log, 0); + atomic_set(&kmemleak_enabled, 0); + + /* check whether it is too early for a kernel thread */ + if (atomic_read(&kmemleak_initialized)) + kmemleak_cleanup(); + + pr_info("Kernel memory leak detector disabled\n"); +} + +/* + * Allow boot-time kmemleak disabling (enabled by default). + */ +static int kmemleak_boot_config(char *str) +{ + if (!str) + return -EINVAL; + if (strcmp(str, "off") == 0) + kmemleak_disable(); + else if (strcmp(str, "on") != 0) + return -EINVAL; + return 0; +} +early_param("kmemleak", kmemleak_boot_config); + +/* + * Kmemleak initialization. + */ +void __init kmemleak_init(void) +{ + int i; + unsigned long flags; + + jiffies_scan_yield = msecs_to_jiffies(MSECS_SCAN_YIELD); + jiffies_min_age = msecs_to_jiffies(MSECS_MIN_AGE); + jiffies_scan_wait = msecs_to_jiffies(SECS_SCAN_WAIT * 1000); + + object_cache = KMEM_CACHE(kmemleak_object, SLAB_NOLEAKTRACE); + scan_area_cache = KMEM_CACHE(kmemleak_scan_area, SLAB_NOLEAKTRACE); + INIT_PRIO_TREE_ROOT(&object_tree_root); + + /* the kernel is still in UP mode, so disabling the IRQs is enough */ + local_irq_save(flags); + if (!atomic_read(&kmemleak_error)) { + atomic_set(&kmemleak_enabled, 1); + atomic_set(&kmemleak_early_log, 0); + } + local_irq_restore(flags); + + /* + * This is the point where tracking allocations is safe. Automatic + * scanning is started during the late initcall. Add the early logged + * callbacks to the kmemleak infrastructure. + */ + for (i = 0; i < crt_early_log; i++) { + struct early_log *log = &early_log[i]; + + switch (log->op_type) { + case KMEMLEAK_ALLOC: + kmemleak_alloc(log->ptr, log->size, log->min_count, + GFP_KERNEL); + break; + case KMEMLEAK_FREE: + kmemleak_free(log->ptr); + break; + case KMEMLEAK_NOT_LEAK: + kmemleak_not_leak(log->ptr); + break; + case KMEMLEAK_IGNORE: + kmemleak_ignore(log->ptr); + break; + case KMEMLEAK_SCAN_AREA: + kmemleak_scan_area(log->ptr, log->offset, log->length, + GFP_KERNEL); + break; + case KMEMLEAK_NO_SCAN: + kmemleak_no_scan(log->ptr); + break; + default: + WARN_ON(1); + } + } +} + +/* + * Late initialization function. + */ +static int __init kmemleak_late_init(void) +{ + struct dentry *dentry; + + atomic_set(&kmemleak_initialized, 1); + + if (atomic_read(&kmemleak_error)) { + /* + * Some error occured and kmemleak was disabled. There is a + * small chance that kmemleak_disable() was called immediately + * after setting kmemleak_initialized and we may end up with + * two clean-up threads but serialized by scan_mutex. + */ + kmemleak_cleanup(); + return -ENOMEM; + } + + dentry = debugfs_create_file("kmemleak", S_IRUGO, NULL, NULL, + &kmemleak_fops); + if (!dentry) + pr_warning("Failed to create the debugfs kmemleak file\n"); + mutex_lock(&kmemleak_mutex); + start_scan_thread(); + mutex_unlock(&kmemleak_mutex); + + pr_info("Kernel memory leak detector initialized\n"); + + return 0; +} +late_initcall(kmemleak_late_init); diff --git a/mm/maccess.c b/mm/maccess.c index ac40796cfb15..9073695ff25f 100644 --- a/mm/maccess.c +++ b/mm/maccess.c @@ -39,7 +39,7 @@ EXPORT_SYMBOL_GPL(probe_kernel_read); * Safely write to address @dst from the buffer at @src. If a kernel fault * happens, handle that and return -EFAULT. */ -long probe_kernel_write(void *dst, void *src, size_t size) +long notrace __weak probe_kernel_write(void *dst, void *src, size_t size) { long ret; mm_segment_t old_fs = get_fs(); diff --git a/mm/madvise.c b/mm/madvise.c index b9ce574827c8..76eb4193acdd 100644 --- a/mm/madvise.c +++ b/mm/madvise.c @@ -123,8 +123,7 @@ static long madvise_willneed(struct vm_area_struct * vma, end = vma->vm_end; end = ((end - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff; - force_page_cache_readahead(file->f_mapping, - file, start, max_sane_readahead(end - start)); + force_page_cache_readahead(file->f_mapping, file, start, end - start); return 0; } @@ -239,12 +238,30 @@ madvise_vma(struct vm_area_struct *vma, struct vm_area_struct **prev, break; default: - error = -EINVAL; + BUG(); break; } return error; } +static int +madvise_behavior_valid(int behavior) +{ + switch (behavior) { + case MADV_DOFORK: + case MADV_DONTFORK: + case MADV_NORMAL: + case MADV_SEQUENTIAL: + case MADV_RANDOM: + case MADV_REMOVE: + case MADV_WILLNEED: + case MADV_DONTNEED: + return 1; + + default: + return 0; + } +} /* * The madvise(2) system call. * @@ -290,6 +307,9 @@ SYSCALL_DEFINE3(madvise, unsigned long, start, size_t, len_in, int, behavior) int write; size_t len; + if (!madvise_behavior_valid(behavior)) + return error; + write = madvise_need_mmap_write(behavior); if (write) down_write(¤t->mm->mmap_sem); diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 78eb8552818b..e2fa20dadf40 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -45,7 +45,7 @@ struct cgroup_subsys mem_cgroup_subsys __read_mostly; #define MEM_CGROUP_RECLAIM_RETRIES 5 #ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP -/* Turned on only when memory cgroup is enabled && really_do_swap_account = 0 */ +/* Turned on only when memory cgroup is enabled && really_do_swap_account = 1 */ int do_swap_account __read_mostly; static int really_do_swap_account __initdata = 1; /* for remember boot option*/ #else @@ -62,7 +62,8 @@ enum mem_cgroup_stat_index { * For MEM_CONTAINER_TYPE_ALL, usage = pagecache + rss. */ MEM_CGROUP_STAT_CACHE, /* # of pages charged as cache */ - MEM_CGROUP_STAT_RSS, /* # of pages charged as rss */ + MEM_CGROUP_STAT_RSS, /* # of pages charged as anon rss */ + MEM_CGROUP_STAT_MAPPED_FILE, /* # of pages charged as file rss */ MEM_CGROUP_STAT_PGPGIN_COUNT, /* # of pages paged in */ MEM_CGROUP_STAT_PGPGOUT_COUNT, /* # of pages paged out */ @@ -176,6 +177,9 @@ struct mem_cgroup { unsigned int swappiness; + /* set when res.limit == memsw.limit */ + bool memsw_is_minimum; + /* * statistics. This must be placed at the end of memcg. */ @@ -188,6 +192,7 @@ enum charge_type { MEM_CGROUP_CHARGE_TYPE_SHMEM, /* used by page migration of shmem */ MEM_CGROUP_CHARGE_TYPE_FORCE, /* used by force_empty */ MEM_CGROUP_CHARGE_TYPE_SWAPOUT, /* for accounting swapcache */ + MEM_CGROUP_CHARGE_TYPE_DROP, /* a page was unused swap cache */ NR_CHARGE_TYPE, }; @@ -570,6 +575,17 @@ int mem_cgroup_inactive_anon_is_low(struct mem_cgroup *memcg) return 0; } +int mem_cgroup_inactive_file_is_low(struct mem_cgroup *memcg) +{ + unsigned long active; + unsigned long inactive; + + inactive = mem_cgroup_get_local_zonestat(memcg, LRU_INACTIVE_FILE); + active = mem_cgroup_get_local_zonestat(memcg, LRU_ACTIVE_FILE); + + return (active > inactive); +} + unsigned long mem_cgroup_zone_nr_pages(struct mem_cgroup *memcg, struct zone *zone, enum lru_list lru) @@ -633,6 +649,7 @@ unsigned long mem_cgroup_isolate_pages(unsigned long nr_to_scan, int zid = zone_idx(z); struct mem_cgroup_per_zone *mz; int lru = LRU_FILE * !!file + !!active; + int ret; BUG_ON(!mem_cont); mz = mem_cgroup_zoneinfo(mem_cont, nid, zid); @@ -650,9 +667,19 @@ unsigned long mem_cgroup_isolate_pages(unsigned long nr_to_scan, continue; scan++; - if (__isolate_lru_page(page, mode, file) == 0) { + ret = __isolate_lru_page(page, mode, file); + switch (ret) { + case 0: list_move(&page->lru, dst); + mem_cgroup_del_lru(page); nr_taken++; + break; + case -EBUSY: + /* we don't affect global LRU but rotate in our LRU */ + mem_cgroup_rotate_lru_list(page, page_lru(page)); + break; + default: + break; } } @@ -834,6 +861,10 @@ static int mem_cgroup_hierarchical_reclaim(struct mem_cgroup *root_mem, int ret, total = 0; int loop = 0; + /* If memsw_is_minimum==1, swap-out is of-no-use. */ + if (root_mem->memsw_is_minimum) + noswap = true; + while (loop < 2) { victim = mem_cgroup_select_victim(root_mem); if (victim == root_mem) @@ -889,6 +920,44 @@ static void record_last_oom(struct mem_cgroup *mem) mem_cgroup_walk_tree(mem, NULL, record_last_oom_cb); } +/* + * Currently used to update mapped file statistics, but the routine can be + * generalized to update other statistics as well. + */ +void mem_cgroup_update_mapped_file_stat(struct page *page, int val) +{ + struct mem_cgroup *mem; + struct mem_cgroup_stat *stat; + struct mem_cgroup_stat_cpu *cpustat; + int cpu; + struct page_cgroup *pc; + + if (!page_is_file_cache(page)) + return; + + pc = lookup_page_cgroup(page); + if (unlikely(!pc)) + return; + + lock_page_cgroup(pc); + mem = pc->mem_cgroup; + if (!mem) + goto done; + + if (!PageCgroupUsed(pc)) + goto done; + + /* + * Preemption is already disabled, we don't need get_cpu() + */ + cpu = smp_processor_id(); + stat = &mem->stat; + cpustat = &stat->cpustat[cpu]; + + __mem_cgroup_stat_add_safe(cpustat, MEM_CGROUP_STAT_MAPPED_FILE, val); +done: + unlock_page_cgroup(pc); +} /* * Unlike exported interface, "oom" parameter is added. if oom==true, @@ -1087,6 +1156,10 @@ static int mem_cgroup_move_account(struct page_cgroup *pc, struct mem_cgroup_per_zone *from_mz, *to_mz; int nid, zid; int ret = -EBUSY; + struct page *page; + int cpu; + struct mem_cgroup_stat *stat; + struct mem_cgroup_stat_cpu *cpustat; VM_BUG_ON(from == to); VM_BUG_ON(PageLRU(pc->page)); @@ -1107,6 +1180,23 @@ static int mem_cgroup_move_account(struct page_cgroup *pc, res_counter_uncharge(&from->res, PAGE_SIZE); mem_cgroup_charge_statistics(from, pc, false); + + page = pc->page; + if (page_is_file_cache(page) && page_mapped(page)) { + cpu = smp_processor_id(); + /* Update mapped_file data for mem_cgroup "from" */ + stat = &from->stat; + cpustat = &stat->cpustat[cpu]; + __mem_cgroup_stat_add_safe(cpustat, MEM_CGROUP_STAT_MAPPED_FILE, + -1); + + /* Update mapped_file data for mem_cgroup "to" */ + stat = &to->stat; + cpustat = &stat->cpustat[cpu]; + __mem_cgroup_stat_add_safe(cpustat, MEM_CGROUP_STAT_MAPPED_FILE, + 1); + } + if (do_swap_account) res_counter_uncharge(&from->memsw, PAGE_SIZE); css_put(&from->css); @@ -1422,6 +1512,7 @@ __mem_cgroup_uncharge_common(struct page *page, enum charge_type ctype) switch (ctype) { case MEM_CGROUP_CHARGE_TYPE_MAPPED: + case MEM_CGROUP_CHARGE_TYPE_DROP: if (page_mapped(page)) goto unlock_out; break; @@ -1485,18 +1576,23 @@ void mem_cgroup_uncharge_cache_page(struct page *page) * called after __delete_from_swap_cache() and drop "page" account. * memcg information is recorded to swap_cgroup of "ent" */ -void mem_cgroup_uncharge_swapcache(struct page *page, swp_entry_t ent) +void +mem_cgroup_uncharge_swapcache(struct page *page, swp_entry_t ent, bool swapout) { struct mem_cgroup *memcg; + int ctype = MEM_CGROUP_CHARGE_TYPE_SWAPOUT; + + if (!swapout) /* this was a swap cache but the swap is unused ! */ + ctype = MEM_CGROUP_CHARGE_TYPE_DROP; + + memcg = __mem_cgroup_uncharge_common(page, ctype); - memcg = __mem_cgroup_uncharge_common(page, - MEM_CGROUP_CHARGE_TYPE_SWAPOUT); /* record memcg information */ - if (do_swap_account && memcg) { + if (do_swap_account && swapout && memcg) { swap_cgroup_record(ent, css_id(&memcg->css)); mem_cgroup_get(memcg); } - if (memcg) + if (swapout && memcg) css_put(&memcg->css); } #endif @@ -1674,6 +1770,12 @@ static int mem_cgroup_resize_limit(struct mem_cgroup *memcg, break; } ret = res_counter_set_limit(&memcg->res, val); + if (!ret) { + if (memswlimit == val) + memcg->memsw_is_minimum = true; + else + memcg->memsw_is_minimum = false; + } mutex_unlock(&set_limit_mutex); if (!ret) @@ -1692,16 +1794,14 @@ static int mem_cgroup_resize_limit(struct mem_cgroup *memcg, return ret; } -int mem_cgroup_resize_memsw_limit(struct mem_cgroup *memcg, - unsigned long long val) +static int mem_cgroup_resize_memsw_limit(struct mem_cgroup *memcg, + unsigned long long val) { int retry_count; u64 memlimit, oldusage, curusage; int children = mem_cgroup_count_children(memcg); int ret = -EBUSY; - if (!do_swap_account) - return -EINVAL; /* see mem_cgroup_resize_res_limit */ retry_count = children * MEM_CGROUP_RECLAIM_RETRIES; oldusage = res_counter_read_u64(&memcg->memsw, RES_USAGE); @@ -1723,6 +1823,12 @@ int mem_cgroup_resize_memsw_limit(struct mem_cgroup *memcg, break; } ret = res_counter_set_limit(&memcg->memsw, val); + if (!ret) { + if (memlimit == val) + memcg->memsw_is_minimum = true; + else + memcg->memsw_is_minimum = false; + } mutex_unlock(&set_limit_mutex); if (!ret) @@ -1936,8 +2042,7 @@ static u64 mem_cgroup_read(struct cgroup *cont, struct cftype *cft) val = res_counter_read_u64(&mem->res, name); break; case _MEMSWAP: - if (do_swap_account) - val = res_counter_read_u64(&mem->memsw, name); + val = res_counter_read_u64(&mem->memsw, name); break; default: BUG(); @@ -2035,6 +2140,7 @@ static int mem_cgroup_reset(struct cgroup *cont, unsigned int event) enum { MCS_CACHE, MCS_RSS, + MCS_MAPPED_FILE, MCS_PGPGIN, MCS_PGPGOUT, MCS_INACTIVE_ANON, @@ -2055,6 +2161,7 @@ struct { } memcg_stat_strings[NR_MCS_STAT] = { {"cache", "total_cache"}, {"rss", "total_rss"}, + {"mapped_file", "total_mapped_file"}, {"pgpgin", "total_pgpgin"}, {"pgpgout", "total_pgpgout"}, {"inactive_anon", "total_inactive_anon"}, @@ -2075,6 +2182,8 @@ static int mem_cgroup_get_local_stat(struct mem_cgroup *mem, void *data) s->stat[MCS_CACHE] += val * PAGE_SIZE; val = mem_cgroup_read_stat(&mem->stat, MEM_CGROUP_STAT_RSS); s->stat[MCS_RSS] += val * PAGE_SIZE; + val = mem_cgroup_read_stat(&mem->stat, MEM_CGROUP_STAT_MAPPED_FILE); + s->stat[MCS_MAPPED_FILE] += val * PAGE_SIZE; val = mem_cgroup_read_stat(&mem->stat, MEM_CGROUP_STAT_PGPGIN_COUNT); s->stat[MCS_PGPGIN] += val; val = mem_cgroup_read_stat(&mem->stat, MEM_CGROUP_STAT_PGPGOUT_COUNT); diff --git a/mm/memory.c b/mm/memory.c index 4126dd16778c..f46ac18ba231 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -1310,8 +1310,11 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm, cond_resched(); while (!(page = follow_page(vma, start, foll_flags))) { int ret; + ret = handle_mm_fault(mm, vma, start, - foll_flags & FOLL_WRITE); + (foll_flags & FOLL_WRITE) ? + FAULT_FLAG_WRITE : 0); + if (ret & VM_FAULT_ERROR) { if (ret & VM_FAULT_OOM) return i ? i : -ENOMEM; @@ -1360,6 +1363,56 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm, return i; } +/** + * get_user_pages() - pin user pages in memory + * @tsk: task_struct of target task + * @mm: mm_struct of target mm + * @start: starting user address + * @len: number of pages from start to pin + * @write: whether pages will be written to by the caller + * @force: whether to force write access even if user mapping is + * readonly. This will result in the page being COWed even + * in MAP_SHARED mappings. You do not want this. + * @pages: array that receives pointers to the pages pinned. + * Should be at least nr_pages long. Or NULL, if caller + * only intends to ensure the pages are faulted in. + * @vmas: array of pointers to vmas corresponding to each page. + * Or NULL if the caller does not require them. + * + * Returns number of pages pinned. This may be fewer than the number + * requested. If len is 0 or negative, returns 0. If no pages + * were pinned, returns -errno. Each page returned must be released + * with a put_page() call when it is finished with. vmas will only + * remain valid while mmap_sem is held. + * + * Must be called with mmap_sem held for read or write. + * + * get_user_pages walks a process's page tables and takes a reference to + * each struct page that each user address corresponds to at a given + * instant. That is, it takes the page that would be accessed if a user + * thread accesses the given user virtual address at that instant. + * + * This does not guarantee that the page exists in the user mappings when + * get_user_pages returns, and there may even be a completely different + * page there in some cases (eg. if mmapped pagecache has been invalidated + * and subsequently re faulted). However it does guarantee that the page + * won't be freed completely. And mostly callers simply care that the page + * contains data that was valid *at some point in time*. Typically, an IO + * or similar operation cannot guarantee anything stronger anyway because + * locks can't be held over the syscall boundary. + * + * If write=0, the page must not be written to. If the page is written to, + * set_page_dirty (or set_page_dirty_lock, as appropriate) must be called + * after the page is finished with, and before put_page is called. + * + * get_user_pages is typically used for fewer-copy IO operations, to get a + * handle on the memory by some means other than accesses via the user virtual + * addresses. The pages may be submitted for DMA to devices or accessed via + * their kernel linear mapping (via the kmap APIs). Care should be taken to + * use the correct cache flushing APIs. + * + * See also get_user_pages_fast, for performance critical applications. + */ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long start, int len, int write, int force, struct page **pages, struct vm_area_struct **vmas) @@ -2446,7 +2499,7 @@ int vmtruncate_range(struct inode *inode, loff_t offset, loff_t end) */ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma, unsigned long address, pte_t *page_table, pmd_t *pmd, - int write_access, pte_t orig_pte) + unsigned int flags, pte_t orig_pte) { spinlock_t *ptl; struct page *page; @@ -2466,7 +2519,7 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma, delayacct_set_flag(DELAYACCT_PF_SWAPIN); page = lookup_swap_cache(entry); if (!page) { - grab_swap_token(); /* Contend for token _before_ read-in */ + grab_swap_token(mm); /* Contend for token _before_ read-in */ page = swapin_readahead(entry, GFP_HIGHUSER_MOVABLE, vma, address); if (!page) { @@ -2522,9 +2575,9 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma, inc_mm_counter(mm, anon_rss); pte = mk_pte(page, vma->vm_page_prot); - if (write_access && reuse_swap_page(page)) { + if ((flags & FAULT_FLAG_WRITE) && reuse_swap_page(page)) { pte = maybe_mkwrite(pte_mkdirty(pte), vma); - write_access = 0; + flags &= ~FAULT_FLAG_WRITE; } flush_icache_page(vma, page); set_pte_at(mm, address, page_table, pte); @@ -2537,7 +2590,7 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma, try_to_free_swap(page); unlock_page(page); - if (write_access) { + if (flags & FAULT_FLAG_WRITE) { ret |= do_wp_page(mm, vma, address, page_table, pmd, ptl, pte); if (ret & VM_FAULT_ERROR) ret &= VM_FAULT_ERROR; @@ -2566,7 +2619,7 @@ out_page: */ static int do_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma, unsigned long address, pte_t *page_table, pmd_t *pmd, - int write_access) + unsigned int flags) { struct page *page; spinlock_t *ptl; @@ -2726,7 +2779,7 @@ static int __do_fault(struct mm_struct *mm, struct vm_area_struct *vma, * due to the bad i386 page protection. But it's valid * for other architectures too. * - * Note that if write_access is true, we either now have + * Note that if FAULT_FLAG_WRITE is set, we either now have * an exclusive copy of the page, or this is a shared mapping, * so we can make it writable and dirty to avoid having to * handle that later. @@ -2797,11 +2850,10 @@ unwritable_page: static int do_linear_fault(struct mm_struct *mm, struct vm_area_struct *vma, unsigned long address, pte_t *page_table, pmd_t *pmd, - int write_access, pte_t orig_pte) + unsigned int flags, pte_t orig_pte) { pgoff_t pgoff = (((address & PAGE_MASK) - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff; - unsigned int flags = (write_access ? FAULT_FLAG_WRITE : 0); pte_unmap(page_table); return __do_fault(mm, vma, address, pmd, pgoff, flags, orig_pte); @@ -2818,12 +2870,12 @@ static int do_linear_fault(struct mm_struct *mm, struct vm_area_struct *vma, */ static int do_nonlinear_fault(struct mm_struct *mm, struct vm_area_struct *vma, unsigned long address, pte_t *page_table, pmd_t *pmd, - int write_access, pte_t orig_pte) + unsigned int flags, pte_t orig_pte) { - unsigned int flags = FAULT_FLAG_NONLINEAR | - (write_access ? FAULT_FLAG_WRITE : 0); pgoff_t pgoff; + flags |= FAULT_FLAG_NONLINEAR; + if (!pte_unmap_same(mm, pmd, page_table, orig_pte)) return 0; @@ -2854,7 +2906,7 @@ static int do_nonlinear_fault(struct mm_struct *mm, struct vm_area_struct *vma, */ static inline int handle_pte_fault(struct mm_struct *mm, struct vm_area_struct *vma, unsigned long address, - pte_t *pte, pmd_t *pmd, int write_access) + pte_t *pte, pmd_t *pmd, unsigned int flags) { pte_t entry; spinlock_t *ptl; @@ -2865,30 +2917,30 @@ static inline int handle_pte_fault(struct mm_struct *mm, if (vma->vm_ops) { if (likely(vma->vm_ops->fault)) return do_linear_fault(mm, vma, address, - pte, pmd, write_access, entry); + pte, pmd, flags, entry); } return do_anonymous_page(mm, vma, address, - pte, pmd, write_access); + pte, pmd, flags); } if (pte_file(entry)) return do_nonlinear_fault(mm, vma, address, - pte, pmd, write_access, entry); + pte, pmd, flags, entry); return do_swap_page(mm, vma, address, - pte, pmd, write_access, entry); + pte, pmd, flags, entry); } ptl = pte_lockptr(mm, pmd); spin_lock(ptl); if (unlikely(!pte_same(*pte, entry))) goto unlock; - if (write_access) { + if (flags & FAULT_FLAG_WRITE) { if (!pte_write(entry)) return do_wp_page(mm, vma, address, pte, pmd, ptl, entry); entry = pte_mkdirty(entry); } entry = pte_mkyoung(entry); - if (ptep_set_access_flags(vma, address, pte, entry, write_access)) { + if (ptep_set_access_flags(vma, address, pte, entry, flags & FAULT_FLAG_WRITE)) { update_mmu_cache(vma, address, entry); } else { /* @@ -2897,7 +2949,7 @@ static inline int handle_pte_fault(struct mm_struct *mm, * This still avoids useless tlb flushes for .text page faults * with threads. */ - if (write_access) + if (flags & FAULT_FLAG_WRITE) flush_tlb_page(vma, address); } unlock: @@ -2909,7 +2961,7 @@ unlock: * By the time we get here, we already hold the mm semaphore */ int handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma, - unsigned long address, int write_access) + unsigned long address, unsigned int flags) { pgd_t *pgd; pud_t *pud; @@ -2921,7 +2973,7 @@ int handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma, count_vm_event(PGFAULT); if (unlikely(is_vm_hugetlb_page(vma))) - return hugetlb_fault(mm, vma, address, write_access); + return hugetlb_fault(mm, vma, address, flags); pgd = pgd_offset(mm, address); pud = pud_alloc(mm, pgd, address); @@ -2934,7 +2986,7 @@ int handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma, if (!pte) return VM_FAULT_OOM; - return handle_pte_fault(mm, vma, address, pte, pmd, write_access); + return handle_pte_fault(mm, vma, address, pte, pmd, flags); } #ifndef __PAGETABLE_PUD_FOLDED @@ -3053,22 +3105,13 @@ int in_gate_area_no_task(unsigned long addr) #endif /* __HAVE_ARCH_GATE_AREA */ -#ifdef CONFIG_HAVE_IOREMAP_PROT -int follow_phys(struct vm_area_struct *vma, - unsigned long address, unsigned int flags, - unsigned long *prot, resource_size_t *phys) +static int follow_pte(struct mm_struct *mm, unsigned long address, + pte_t **ptepp, spinlock_t **ptlp) { pgd_t *pgd; pud_t *pud; pmd_t *pmd; - pte_t *ptep, pte; - spinlock_t *ptl; - resource_size_t phys_addr = 0; - struct mm_struct *mm = vma->vm_mm; - int ret = -EINVAL; - - if (!(vma->vm_flags & (VM_IO | VM_PFNMAP))) - goto out; + pte_t *ptep; pgd = pgd_offset(mm, address); if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd))) @@ -3086,22 +3129,71 @@ int follow_phys(struct vm_area_struct *vma, if (pmd_huge(*pmd)) goto out; - ptep = pte_offset_map_lock(mm, pmd, address, &ptl); + ptep = pte_offset_map_lock(mm, pmd, address, ptlp); if (!ptep) goto out; - - pte = *ptep; - if (!pte_present(pte)) + if (!pte_present(*ptep)) goto unlock; + *ptepp = ptep; + return 0; +unlock: + pte_unmap_unlock(ptep, *ptlp); +out: + return -EINVAL; +} + +/** + * follow_pfn - look up PFN at a user virtual address + * @vma: memory mapping + * @address: user virtual address + * @pfn: location to store found PFN + * + * Only IO mappings and raw PFN mappings are allowed. + * + * Returns zero and the pfn at @pfn on success, -ve otherwise. + */ +int follow_pfn(struct vm_area_struct *vma, unsigned long address, + unsigned long *pfn) +{ + int ret = -EINVAL; + spinlock_t *ptl; + pte_t *ptep; + + if (!(vma->vm_flags & (VM_IO | VM_PFNMAP))) + return ret; + + ret = follow_pte(vma->vm_mm, address, &ptep, &ptl); + if (ret) + return ret; + *pfn = pte_pfn(*ptep); + pte_unmap_unlock(ptep, ptl); + return 0; +} +EXPORT_SYMBOL(follow_pfn); + +#ifdef CONFIG_HAVE_IOREMAP_PROT +int follow_phys(struct vm_area_struct *vma, + unsigned long address, unsigned int flags, + unsigned long *prot, resource_size_t *phys) +{ + int ret = -EINVAL; + pte_t *ptep, pte; + spinlock_t *ptl; + + if (!(vma->vm_flags & (VM_IO | VM_PFNMAP))) + goto out; + + if (follow_pte(vma->vm_mm, address, &ptep, &ptl)) + goto out; + pte = *ptep; + if ((flags & FOLL_WRITE) && !pte_write(pte)) goto unlock; - phys_addr = pte_pfn(pte); - phys_addr <<= PAGE_SHIFT; /* Shift here to avoid overflow on PAE */ *prot = pgprot_val(pte_pgprot(pte)); - *phys = phys_addr; - ret = 0; + *phys = (resource_size_t)pte_pfn(pte) << PAGE_SHIFT; + ret = 0; unlock: pte_unmap_unlock(ptep, ptl); out: diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index c083cf5fd6df..e4412a676c88 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c @@ -422,7 +422,8 @@ int online_pages(unsigned long pfn, unsigned long nr_pages) zone->present_pages += onlined_pages; zone->zone_pgdat->node_present_pages += onlined_pages; - setup_per_zone_pages_min(); + setup_per_zone_wmarks(); + calculate_zone_inactive_ratio(zone); if (onlined_pages) { kswapd_run(zone_to_nid(zone)); node_set_state(zone_to_nid(zone), N_HIGH_MEMORY); @@ -832,6 +833,9 @@ repeat: totalram_pages -= offlined_pages; num_physpages -= offlined_pages; + setup_per_zone_wmarks(); + calculate_zone_inactive_ratio(zone); + vm_total_pages = nr_free_pagecache_pages(); writeback_set_ratelimit(); diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 3eb4a6fdc043..e08e2c4da63a 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -182,13 +182,54 @@ static int mpol_new_bind(struct mempolicy *pol, const nodemask_t *nodes) return 0; } -/* Create a new policy */ +/* + * mpol_set_nodemask is called after mpol_new() to set up the nodemask, if + * any, for the new policy. mpol_new() has already validated the nodes + * parameter with respect to the policy mode and flags. But, we need to + * handle an empty nodemask with MPOL_PREFERRED here. + * + * Must be called holding task's alloc_lock to protect task's mems_allowed + * and mempolicy. May also be called holding the mmap_semaphore for write. + */ +static int mpol_set_nodemask(struct mempolicy *pol, const nodemask_t *nodes) +{ + nodemask_t cpuset_context_nmask; + int ret; + + /* if mode is MPOL_DEFAULT, pol is NULL. This is right. */ + if (pol == NULL) + return 0; + + VM_BUG_ON(!nodes); + if (pol->mode == MPOL_PREFERRED && nodes_empty(*nodes)) + nodes = NULL; /* explicit local allocation */ + else { + if (pol->flags & MPOL_F_RELATIVE_NODES) + mpol_relative_nodemask(&cpuset_context_nmask, nodes, + &cpuset_current_mems_allowed); + else + nodes_and(cpuset_context_nmask, *nodes, + cpuset_current_mems_allowed); + if (mpol_store_user_nodemask(pol)) + pol->w.user_nodemask = *nodes; + else + pol->w.cpuset_mems_allowed = + cpuset_current_mems_allowed; + } + + ret = mpol_ops[pol->mode].create(pol, + nodes ? &cpuset_context_nmask : NULL); + return ret; +} + +/* + * This function just creates a new policy, does some check and simple + * initialization. You must invoke mpol_set_nodemask() to set nodes. + */ static struct mempolicy *mpol_new(unsigned short mode, unsigned short flags, nodemask_t *nodes) { struct mempolicy *policy; - nodemask_t cpuset_context_nmask; - int ret; pr_debug("setting mode %d flags %d nodes[0] %lx\n", mode, flags, nodes ? nodes_addr(*nodes)[0] : -1); @@ -210,7 +251,6 @@ static struct mempolicy *mpol_new(unsigned short mode, unsigned short flags, if (((flags & MPOL_F_STATIC_NODES) || (flags & MPOL_F_RELATIVE_NODES))) return ERR_PTR(-EINVAL); - nodes = NULL; /* flag local alloc */ } } else if (nodes_empty(*nodes)) return ERR_PTR(-EINVAL); @@ -221,30 +261,6 @@ static struct mempolicy *mpol_new(unsigned short mode, unsigned short flags, policy->mode = mode; policy->flags = flags; - if (nodes) { - /* - * cpuset related setup doesn't apply to local allocation - */ - cpuset_update_task_memory_state(); - if (flags & MPOL_F_RELATIVE_NODES) - mpol_relative_nodemask(&cpuset_context_nmask, nodes, - &cpuset_current_mems_allowed); - else - nodes_and(cpuset_context_nmask, *nodes, - cpuset_current_mems_allowed); - if (mpol_store_user_nodemask(policy)) - policy->w.user_nodemask = *nodes; - else - policy->w.cpuset_mems_allowed = - cpuset_mems_allowed(current); - } - - ret = mpol_ops[mode].create(policy, - nodes ? &cpuset_context_nmask : NULL); - if (ret < 0) { - kmem_cache_free(policy_cache, policy); - return ERR_PTR(ret); - } return policy; } @@ -324,6 +340,8 @@ static void mpol_rebind_policy(struct mempolicy *pol, /* * Wrapper for mpol_rebind_policy() that just requires task * pointer, and updates task mempolicy. + * + * Called with task's alloc_lock held. */ void mpol_rebind_task(struct task_struct *tsk, const nodemask_t *new) @@ -600,8 +618,9 @@ static void mpol_set_task_struct_flag(void) static long do_set_mempolicy(unsigned short mode, unsigned short flags, nodemask_t *nodes) { - struct mempolicy *new; + struct mempolicy *new, *old; struct mm_struct *mm = current->mm; + int ret; new = mpol_new(mode, flags, nodes); if (IS_ERR(new)) @@ -615,20 +634,33 @@ static long do_set_mempolicy(unsigned short mode, unsigned short flags, */ if (mm) down_write(&mm->mmap_sem); - mpol_put(current->mempolicy); + task_lock(current); + ret = mpol_set_nodemask(new, nodes); + if (ret) { + task_unlock(current); + if (mm) + up_write(&mm->mmap_sem); + mpol_put(new); + return ret; + } + old = current->mempolicy; current->mempolicy = new; mpol_set_task_struct_flag(); if (new && new->mode == MPOL_INTERLEAVE && nodes_weight(new->v.nodes)) current->il_next = first_node(new->v.nodes); + task_unlock(current); if (mm) up_write(&mm->mmap_sem); + mpol_put(old); return 0; } /* * Return nodemask for policy for get_mempolicy() query + * + * Called with task's alloc_lock held */ static void get_policy_nodemask(struct mempolicy *p, nodemask_t *nodes) { @@ -674,7 +706,6 @@ static long do_get_mempolicy(int *policy, nodemask_t *nmask, struct vm_area_struct *vma = NULL; struct mempolicy *pol = current->mempolicy; - cpuset_update_task_memory_state(); if (flags & ~(unsigned long)(MPOL_F_NODE|MPOL_F_ADDR|MPOL_F_MEMS_ALLOWED)) return -EINVAL; @@ -683,7 +714,9 @@ static long do_get_mempolicy(int *policy, nodemask_t *nmask, if (flags & (MPOL_F_NODE|MPOL_F_ADDR)) return -EINVAL; *policy = 0; /* just so it's initialized */ + task_lock(current); *nmask = cpuset_current_mems_allowed; + task_unlock(current); return 0; } @@ -738,8 +771,11 @@ static long do_get_mempolicy(int *policy, nodemask_t *nmask, } err = 0; - if (nmask) + if (nmask) { + task_lock(current); get_policy_nodemask(pol, nmask); + task_unlock(current); + } out: mpol_cond_put(pol); @@ -767,7 +803,7 @@ static void migrate_page_add(struct page *page, struct list_head *pagelist, static struct page *new_node_page(struct page *page, unsigned long node, int **x) { - return alloc_pages_node(node, GFP_HIGHUSER_MOVABLE, 0); + return alloc_pages_exact_node(node, GFP_HIGHUSER_MOVABLE, 0); } /* @@ -979,6 +1015,14 @@ static long do_mbind(unsigned long start, unsigned long len, return err; } down_write(&mm->mmap_sem); + task_lock(current); + err = mpol_set_nodemask(new, nmask); + task_unlock(current); + if (err) { + up_write(&mm->mmap_sem); + mpol_put(new); + return err; + } vma = check_range(mm, start, end, nmask, flags | MPOL_MF_INVERT, &pagelist); @@ -1545,8 +1589,6 @@ alloc_page_vma(gfp_t gfp, struct vm_area_struct *vma, unsigned long addr) struct mempolicy *pol = get_vma_policy(current, vma, addr); struct zonelist *zl; - cpuset_update_task_memory_state(); - if (unlikely(pol->mode == MPOL_INTERLEAVE)) { unsigned nid; @@ -1593,8 +1635,6 @@ struct page *alloc_pages_current(gfp_t gfp, unsigned order) { struct mempolicy *pol = current->mempolicy; - if ((gfp & __GFP_WAIT) && !in_interrupt()) - cpuset_update_task_memory_state(); if (!pol || in_interrupt() || (gfp & __GFP_THISNODE)) pol = &default_policy; @@ -1854,6 +1894,8 @@ restart: */ void mpol_shared_policy_init(struct shared_policy *sp, struct mempolicy *mpol) { + int ret; + sp->root = RB_ROOT; /* empty tree == default mempolicy */ spin_lock_init(&sp->lock); @@ -1863,9 +1905,19 @@ void mpol_shared_policy_init(struct shared_policy *sp, struct mempolicy *mpol) /* contextualize the tmpfs mount point mempolicy */ new = mpol_new(mpol->mode, mpol->flags, &mpol->w.user_nodemask); - mpol_put(mpol); /* drop our ref on sb mpol */ - if (IS_ERR(new)) + if (IS_ERR(new)) { + mpol_put(mpol); /* drop our ref on sb mpol */ return; /* no valid nodemask intersection */ + } + + task_lock(current); + ret = mpol_set_nodemask(new, &mpol->w.user_nodemask); + task_unlock(current); + mpol_put(mpol); /* drop our ref on sb mpol */ + if (ret) { + mpol_put(new); + return; + } /* Create pseudo-vma that contains just the policy */ memset(&pvma, 0, sizeof(struct vm_area_struct)); @@ -2086,8 +2138,19 @@ int mpol_parse_str(char *str, struct mempolicy **mpol, int no_context) new = mpol_new(mode, mode_flags, &nodes); if (IS_ERR(new)) err = 1; - else if (no_context) - new->w.user_nodemask = nodes; /* save for contextualization */ + else { + int ret; + + task_lock(current); + ret = mpol_set_nodemask(new, &nodes); + task_unlock(current); + if (ret) + err = 1; + else if (no_context) { + /* save for contextualization */ + new->w.user_nodemask = nodes; + } + } out: /* Restore string for error message */ diff --git a/mm/migrate.c b/mm/migrate.c index 068655d8f883..939888f9ddab 100644 --- a/mm/migrate.c +++ b/mm/migrate.c @@ -802,7 +802,7 @@ static struct page *new_page_node(struct page *p, unsigned long private, *result = &pm->status; - return alloc_pages_node(pm->node, + return alloc_pages_exact_node(pm->node, GFP_HIGHUSER_MOVABLE | GFP_THISNODE, 0); } @@ -820,7 +820,6 @@ static int do_move_page_to_node_array(struct mm_struct *mm, struct page_to_node *pp; LIST_HEAD(pagelist); - migrate_prep(); down_read(&mm->mmap_sem); /* @@ -907,6 +906,9 @@ static int do_pages_move(struct mm_struct *mm, struct task_struct *task, pm = (struct page_to_node *)__get_free_page(GFP_KERNEL); if (!pm) goto out; + + migrate_prep(); + /* * Store a chunk of page_to_node array in a page, * but keep the last one as a marker diff --git a/mm/mlock.c b/mm/mlock.c index cbe9e0581b75..45eb650b9654 100644 --- a/mm/mlock.c +++ b/mm/mlock.c @@ -31,7 +31,6 @@ int can_do_mlock(void) } EXPORT_SYMBOL(can_do_mlock); -#ifdef CONFIG_UNEVICTABLE_LRU /* * Mlocked pages are marked with PageMlocked() flag for efficient testing * in vmscan and, possibly, the fault path; and to support semi-accurate @@ -261,27 +260,6 @@ static int __mlock_posix_error_return(long retval) return retval; } -#else /* CONFIG_UNEVICTABLE_LRU */ - -/* - * Just make pages present if VM_LOCKED. No-op if unlocking. - */ -static long __mlock_vma_pages_range(struct vm_area_struct *vma, - unsigned long start, unsigned long end, - int mlock) -{ - if (mlock && (vma->vm_flags & VM_LOCKED)) - return make_pages_present(start, end); - return 0; -} - -static inline int __mlock_posix_error_return(long retval) -{ - return 0; -} - -#endif /* CONFIG_UNEVICTABLE_LRU */ - /** * mlock_vma_pages_range() - mlock pages in specified vma range. * @vma - the vma containing the specfied address range @@ -629,52 +607,43 @@ void user_shm_unlock(size_t size, struct user_struct *user) free_uid(user); } -void *alloc_locked_buffer(size_t size) +int account_locked_memory(struct mm_struct *mm, struct rlimit *rlim, + size_t size) { - unsigned long rlim, vm, pgsz; - void *buffer = NULL; + unsigned long lim, vm, pgsz; + int error = -ENOMEM; pgsz = PAGE_ALIGN(size) >> PAGE_SHIFT; - down_write(¤t->mm->mmap_sem); + down_write(&mm->mmap_sem); - rlim = current->signal->rlim[RLIMIT_AS].rlim_cur >> PAGE_SHIFT; - vm = current->mm->total_vm + pgsz; - if (rlim < vm) + lim = rlim[RLIMIT_AS].rlim_cur >> PAGE_SHIFT; + vm = mm->total_vm + pgsz; + if (lim < vm) goto out; - rlim = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur >> PAGE_SHIFT; - vm = current->mm->locked_vm + pgsz; - if (rlim < vm) + lim = rlim[RLIMIT_MEMLOCK].rlim_cur >> PAGE_SHIFT; + vm = mm->locked_vm + pgsz; + if (lim < vm) goto out; - buffer = kzalloc(size, GFP_KERNEL); - if (!buffer) - goto out; - - current->mm->total_vm += pgsz; - current->mm->locked_vm += pgsz; + mm->total_vm += pgsz; + mm->locked_vm += pgsz; + error = 0; out: - up_write(¤t->mm->mmap_sem); - return buffer; + up_write(&mm->mmap_sem); + return error; } -void release_locked_buffer(void *buffer, size_t size) +void refund_locked_memory(struct mm_struct *mm, size_t size) { unsigned long pgsz = PAGE_ALIGN(size) >> PAGE_SHIFT; - down_write(¤t->mm->mmap_sem); + down_write(&mm->mmap_sem); - current->mm->total_vm -= pgsz; - current->mm->locked_vm -= pgsz; + mm->total_vm -= pgsz; + mm->locked_vm -= pgsz; - up_write(¤t->mm->mmap_sem); -} - -void free_locked_buffer(void *buffer, size_t size) -{ - release_locked_buffer(buffer, size); - - kfree(buffer); + up_write(&mm->mmap_sem); } diff --git a/mm/mmap.c b/mm/mmap.c index 6b7b1a95944b..34579b23ebd5 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -87,6 +88,9 @@ int sysctl_overcommit_ratio = 50; /* default is 50% */ int sysctl_max_map_count __read_mostly = DEFAULT_MAX_MAP_COUNT; struct percpu_counter vm_committed_as; +/* amount of vm to protect from userspace access */ +unsigned long mmap_min_addr = CONFIG_DEFAULT_MMAP_MIN_ADDR; + /* * Check that a process has enough memory to allocate a new virtual * mapping. 0 means there is enough memory for the allocation to @@ -1219,6 +1223,8 @@ munmap_back: if (correct_wcount) atomic_inc(&inode->i_writecount); out: + perf_counter_mmap(vma); + mm->total_vm += len >> PAGE_SHIFT; vm_stat_account(mm, vm_flags, file, len >> PAGE_SHIFT); if (vm_flags & VM_LOCKED) { @@ -2305,6 +2311,8 @@ int install_special_mapping(struct mm_struct *mm, mm->total_vm += len >> PAGE_SHIFT; + perf_counter_mmap(vma); + return 0; } diff --git a/mm/mprotect.c b/mm/mprotect.c index 258197b76fb4..d80311baeb2d 100644 --- a/mm/mprotect.c +++ b/mm/mprotect.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -299,6 +300,7 @@ SYSCALL_DEFINE3(mprotect, unsigned long, start, size_t, len, error = mprotect_fixup(vma, &prev, nstart, tmp, newflags); if (error) goto out; + perf_counter_mmap(vma); nstart = tmp; if (nstart < prev->vm_end) diff --git a/mm/nommu.c b/mm/nommu.c index b571ef707428..2fd2ad5da98e 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -69,6 +69,9 @@ int sysctl_max_map_count = DEFAULT_MAX_MAP_COUNT; int sysctl_nr_trim_pages = CONFIG_NOMMU_INITIAL_TRIM_EXCESS; int heap_stack_gap = 0; +/* amount of vm to protect from userspace access */ +unsigned long mmap_min_addr = CONFIG_DEFAULT_MMAP_MIN_ADDR; + atomic_long_t mmap_pages_allocated; EXPORT_SYMBOL(mem_map); diff --git a/mm/oom_kill.c b/mm/oom_kill.c index a7b2460e922b..175a67a78a99 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c @@ -58,6 +58,7 @@ unsigned long badness(struct task_struct *p, unsigned long uptime) unsigned long points, cpu_time, run_time; struct mm_struct *mm; struct task_struct *child; + int oom_adj; task_lock(p); mm = p->mm; @@ -65,6 +66,11 @@ unsigned long badness(struct task_struct *p, unsigned long uptime) task_unlock(p); return 0; } + oom_adj = mm->oom_adj; + if (oom_adj == OOM_DISABLE) { + task_unlock(p); + return 0; + } /* * The memory size of the process is the basis for the badness. @@ -148,15 +154,15 @@ unsigned long badness(struct task_struct *p, unsigned long uptime) points /= 8; /* - * Adjust the score by oomkilladj. + * Adjust the score by oom_adj. */ - if (p->oomkilladj) { - if (p->oomkilladj > 0) { + if (oom_adj) { + if (oom_adj > 0) { if (!points) points = 1; - points <<= p->oomkilladj; + points <<= oom_adj; } else - points >>= -(p->oomkilladj); + points >>= -(oom_adj); } #ifdef DEBUG @@ -251,11 +257,8 @@ static struct task_struct *select_bad_process(unsigned long *ppoints, *ppoints = ULONG_MAX; } - if (p->oomkilladj == OOM_DISABLE) - continue; - points = badness(p, uptime.tv_sec); - if (points > *ppoints || !chosen) { + if (points > *ppoints) { chosen = p; *ppoints = points; } @@ -304,8 +307,7 @@ static void dump_tasks(const struct mem_cgroup *mem) } printk(KERN_INFO "[%5d] %5d %5d %8lu %8lu %3d %3d %s\n", p->pid, __task_cred(p)->uid, p->tgid, mm->total_vm, - get_mm_rss(mm), (int)task_cpu(p), p->oomkilladj, - p->comm); + get_mm_rss(mm), (int)task_cpu(p), mm->oom_adj, p->comm); task_unlock(p); } while_each_thread(g, p); } @@ -323,11 +325,8 @@ static void __oom_kill_task(struct task_struct *p, int verbose) return; } - if (!p->mm) { - WARN_ON(1); - printk(KERN_WARNING "tried to kill an mm-less task!\n"); + if (!p->mm) return; - } if (verbose) printk(KERN_ERR "Killed process %d (%s)\n", @@ -349,28 +348,13 @@ static int oom_kill_task(struct task_struct *p) struct mm_struct *mm; struct task_struct *g, *q; + task_lock(p); mm = p->mm; - - /* WARNING: mm may not be dereferenced since we did not obtain its - * value from get_task_mm(p). This is OK since all we need to do is - * compare mm to q->mm below. - * - * Furthermore, even if mm contains a non-NULL value, p->mm may - * change to NULL at any time since we do not hold task_lock(p). - * However, this is of no concern to us. - */ - - if (mm == NULL) + if (!mm || mm->oom_adj == OOM_DISABLE) { + task_unlock(p); return 1; - - /* - * Don't kill the process if any threads are set to OOM_DISABLE - */ - do_each_thread(g, q) { - if (q->mm == mm && q->oomkilladj == OOM_DISABLE) - return 1; - } while_each_thread(g, q); - + } + task_unlock(p); __oom_kill_task(p, 1); /* @@ -393,10 +377,11 @@ static int oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order, struct task_struct *c; if (printk_ratelimit()) { - printk(KERN_WARNING "%s invoked oom-killer: " - "gfp_mask=0x%x, order=%d, oomkilladj=%d\n", - current->comm, gfp_mask, order, current->oomkilladj); task_lock(current); + printk(KERN_WARNING "%s invoked oom-killer: " + "gfp_mask=0x%x, order=%d, oom_adj=%d\n", + current->comm, gfp_mask, order, + current->mm ? current->mm->oom_adj : OOM_DISABLE); cpuset_print_task_mems_allowed(current); task_unlock(current); dump_stack(); @@ -409,8 +394,9 @@ static int oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order, /* * If the task is already exiting, don't alarm the sysadmin or kill * its children or threads, just set TIF_MEMDIE so it can die quickly + * if its mm is still attached. */ - if (p->flags & PF_EXITING) { + if (p->mm && (p->flags & PF_EXITING)) { __oom_kill_task(p, 0); return 0; } diff --git a/mm/page-writeback.c b/mm/page-writeback.c index bb553c3e955d..7b0dcea4935b 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -265,18 +265,19 @@ static void bdi_writeout_fraction(struct backing_dev_info *bdi, * This avoids exceeding the total dirty_limit when the floating averages * fluctuate too quickly. */ -static void -clip_bdi_dirty_limit(struct backing_dev_info *bdi, long dirty, long *pbdi_dirty) +static void clip_bdi_dirty_limit(struct backing_dev_info *bdi, + unsigned long dirty, unsigned long *pbdi_dirty) { - long avail_dirty; + unsigned long avail_dirty; - avail_dirty = dirty - - (global_page_state(NR_FILE_DIRTY) + + avail_dirty = global_page_state(NR_FILE_DIRTY) + global_page_state(NR_WRITEBACK) + global_page_state(NR_UNSTABLE_NFS) + - global_page_state(NR_WRITEBACK_TEMP)); + global_page_state(NR_WRITEBACK_TEMP); - if (avail_dirty < 0) + if (avail_dirty < dirty) + avail_dirty = dirty - avail_dirty; + else avail_dirty = 0; avail_dirty += bdi_stat(bdi, BDI_RECLAIMABLE) + @@ -299,10 +300,10 @@ static inline void task_dirties_fraction(struct task_struct *tsk, * * dirty -= (dirty/8) * p_{t} */ -static void task_dirty_limit(struct task_struct *tsk, long *pdirty) +static void task_dirty_limit(struct task_struct *tsk, unsigned long *pdirty) { long numerator, denominator; - long dirty = *pdirty; + unsigned long dirty = *pdirty; u64 inv = dirty >> 3; task_dirties_fraction(tsk, &numerator, &denominator); diff --git a/mm/page_alloc.c b/mm/page_alloc.c index fe753ecf2aa5..5d714f8fb303 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -46,6 +47,7 @@ #include #include #include +#include #include #include @@ -71,6 +73,7 @@ unsigned long totalram_pages __read_mostly; unsigned long totalreserve_pages __read_mostly; unsigned long highest_memmap_pfn __read_mostly; int percpu_pagelist_fraction; +gfp_t gfp_allowed_mask __read_mostly = GFP_BOOT_MASK; #ifdef CONFIG_HUGETLB_PAGE_SIZE_VARIABLE int pageblock_order __read_mostly; @@ -149,10 +152,6 @@ static unsigned long __meminitdata dma_reserve; static int __meminitdata nr_nodemap_entries; static unsigned long __meminitdata arch_zone_lowest_possible_pfn[MAX_NR_ZONES]; static unsigned long __meminitdata arch_zone_highest_possible_pfn[MAX_NR_ZONES]; -#ifdef CONFIG_MEMORY_HOTPLUG_RESERVE - static unsigned long __meminitdata node_boundary_start_pfn[MAX_NUMNODES]; - static unsigned long __meminitdata node_boundary_end_pfn[MAX_NUMNODES]; -#endif /* CONFIG_MEMORY_HOTPLUG_RESERVE */ static unsigned long __initdata required_kernelcore; static unsigned long __initdata required_movablecore; static unsigned long __meminitdata zone_movable_pfn[MAX_NUMNODES]; @@ -164,17 +163,25 @@ static unsigned long __meminitdata dma_reserve; #if MAX_NUMNODES > 1 int nr_node_ids __read_mostly = MAX_NUMNODES; +int nr_online_nodes __read_mostly = 1; EXPORT_SYMBOL(nr_node_ids); +EXPORT_SYMBOL(nr_online_nodes); #endif int page_group_by_mobility_disabled __read_mostly; static void set_pageblock_migratetype(struct page *page, int migratetype) { + + if (unlikely(page_group_by_mobility_disabled)) + migratetype = MIGRATE_UNMOVABLE; + set_pageblock_flags_group(page, (unsigned long)migratetype, PB_migrate, PB_migrate_end); } +bool oom_killer_disabled __read_mostly; + #ifdef CONFIG_DEBUG_VM static int page_outside_zone_boundaries(struct zone *zone, struct page *page) { @@ -297,23 +304,6 @@ void prep_compound_page(struct page *page, unsigned long order) } } -#ifdef CONFIG_HUGETLBFS -void prep_compound_gigantic_page(struct page *page, unsigned long order) -{ - int i; - int nr_pages = 1 << order; - struct page *p = page + 1; - - set_compound_page_dtor(page, free_compound_page); - set_compound_order(page, order); - __SetPageHead(page); - for (i = 1; i < nr_pages; i++, p = mem_map_next(p, page, i)) { - __SetPageTail(p); - p->first_page = page; - } -} -#endif - static int destroy_compound_page(struct page *page, unsigned long order) { int i; @@ -420,7 +410,7 @@ static inline int page_is_buddy(struct page *page, struct page *buddy, return 0; if (PageBuddy(buddy) && page_order(buddy) == order) { - BUG_ON(page_count(buddy) != 0); + VM_BUG_ON(page_count(buddy) != 0); return 1; } return 0; @@ -451,22 +441,22 @@ static inline int page_is_buddy(struct page *page, struct page *buddy, */ static inline void __free_one_page(struct page *page, - struct zone *zone, unsigned int order) + struct zone *zone, unsigned int order, + int migratetype) { unsigned long page_idx; - int order_size = 1 << order; - int migratetype = get_pageblock_migratetype(page); if (unlikely(PageCompound(page))) if (unlikely(destroy_compound_page(page, order))) return; + VM_BUG_ON(migratetype == -1); + page_idx = page_to_pfn(page) & ((1 << MAX_ORDER) - 1); - VM_BUG_ON(page_idx & (order_size - 1)); + VM_BUG_ON(page_idx & ((1 << order) - 1)); VM_BUG_ON(bad_range(zone, page)); - __mod_zone_page_state(zone, NR_FREE_PAGES, order_size); while (order < MAX_ORDER-1) { unsigned long combined_idx; struct page *buddy; @@ -490,12 +480,26 @@ static inline void __free_one_page(struct page *page, zone->free_area[order].nr_free++; } +#ifdef CONFIG_HAVE_MLOCKED_PAGE_BIT +/* + * free_page_mlock() -- clean up attempts to free and mlocked() page. + * Page should not be on lru, so no need to fix that up. + * free_pages_check() will verify... + */ +static inline void free_page_mlock(struct page *page) +{ + __dec_zone_page_state(page, NR_MLOCK); + __count_vm_event(UNEVICTABLE_MLOCKFREED); +} +#else +static void free_page_mlock(struct page *page) { } +#endif + static inline int free_pages_check(struct page *page) { - free_page_mlock(page); if (unlikely(page_mapcount(page) | (page->mapping != NULL) | - (page_count(page) != 0) | + (atomic_read(&page->_count) != 0) | (page->flags & PAGE_FLAGS_CHECK_AT_FREE))) { bad_page(page); return 1; @@ -522,6 +526,8 @@ static void free_pages_bulk(struct zone *zone, int count, spin_lock(&zone->lock); zone_clear_flag(zone, ZONE_ALL_UNRECLAIMABLE); zone->pages_scanned = 0; + + __mod_zone_page_state(zone, NR_FREE_PAGES, count << order); while (count--) { struct page *page; @@ -529,17 +535,20 @@ static void free_pages_bulk(struct zone *zone, int count, page = list_entry(list->prev, struct page, lru); /* have to delete it as __free_one_page list manipulates */ list_del(&page->lru); - __free_one_page(page, zone, order); + __free_one_page(page, zone, order, page_private(page)); } spin_unlock(&zone->lock); } -static void free_one_page(struct zone *zone, struct page *page, int order) +static void free_one_page(struct zone *zone, struct page *page, int order, + int migratetype) { spin_lock(&zone->lock); zone_clear_flag(zone, ZONE_ALL_UNRECLAIMABLE); zone->pages_scanned = 0; - __free_one_page(page, zone, order); + + __mod_zone_page_state(zone, NR_FREE_PAGES, 1 << order); + __free_one_page(page, zone, order, migratetype); spin_unlock(&zone->lock); } @@ -548,6 +557,9 @@ static void __free_pages_ok(struct page *page, unsigned int order) unsigned long flags; int i; int bad = 0; + int wasMlocked = TestClearPageMlocked(page); + + kmemcheck_free_shadow(page, order); for (i = 0 ; i < (1 << order) ; ++i) bad += free_pages_check(page + i); @@ -563,8 +575,11 @@ static void __free_pages_ok(struct page *page, unsigned int order) kernel_map_pages(page, 1 << order, 0); local_irq_save(flags); + if (unlikely(wasMlocked)) + free_page_mlock(page); __count_vm_events(PGFREE, 1 << order); - free_one_page(page_zone(page), page, order); + free_one_page(page_zone(page), page, order, + get_pageblock_migratetype(page)); local_irq_restore(flags); } @@ -635,7 +650,7 @@ static int prep_new_page(struct page *page, int order, gfp_t gfp_flags) { if (unlikely(page_mapcount(page) | (page->mapping != NULL) | - (page_count(page) != 0) | + (atomic_read(&page->_count) != 0) | (page->flags & PAGE_FLAGS_CHECK_AT_PREP))) { bad_page(page); return 1; @@ -660,7 +675,8 @@ static int prep_new_page(struct page *page, int order, gfp_t gfp_flags) * Go through the free lists for the given migratetype and remove * the smallest available page from the freelists */ -static struct page *__rmqueue_smallest(struct zone *zone, unsigned int order, +static inline +struct page *__rmqueue_smallest(struct zone *zone, unsigned int order, int migratetype) { unsigned int current_order; @@ -678,7 +694,6 @@ static struct page *__rmqueue_smallest(struct zone *zone, unsigned int order, list_del(&page->lru); rmv_page_order(page); area->nr_free--; - __mod_zone_page_state(zone, NR_FREE_PAGES, - (1UL << order)); expand(zone, page, order, current_order, area, migratetype); return page; } @@ -769,8 +784,8 @@ static int move_freepages_block(struct zone *zone, struct page *page, } /* Remove an element from the buddy allocator from the fallback list */ -static struct page *__rmqueue_fallback(struct zone *zone, int order, - int start_migratetype) +static inline struct page * +__rmqueue_fallback(struct zone *zone, int order, int start_migratetype) { struct free_area * area; int current_order; @@ -818,8 +833,6 @@ static struct page *__rmqueue_fallback(struct zone *zone, int order, /* Remove the page from the freelists */ list_del(&page->lru); rmv_page_order(page); - __mod_zone_page_state(zone, NR_FREE_PAGES, - -(1UL << order)); if (current_order == pageblock_order) set_pageblock_migratetype(page, @@ -830,8 +843,7 @@ static struct page *__rmqueue_fallback(struct zone *zone, int order, } } - /* Use MIGRATE_RESERVE rather than fail an allocation */ - return __rmqueue_smallest(zone, order, MIGRATE_RESERVE); + return NULL; } /* @@ -843,11 +855,23 @@ static struct page *__rmqueue(struct zone *zone, unsigned int order, { struct page *page; +retry_reserve: page = __rmqueue_smallest(zone, order, migratetype); - if (unlikely(!page)) + if (unlikely(!page) && migratetype != MIGRATE_RESERVE) { page = __rmqueue_fallback(zone, order, migratetype); + /* + * Use MIGRATE_RESERVE rather than fail an allocation. goto + * is used because __rmqueue_smallest is an inline function + * and we want just one call site + */ + if (!page) { + migratetype = MIGRATE_RESERVE; + goto retry_reserve; + } + } + return page; } @@ -881,6 +905,7 @@ static int rmqueue_bulk(struct zone *zone, unsigned int order, set_page_private(page, migratetype); list = &page->lru; } + __mod_zone_page_state(zone, NR_FREE_PAGES, -(i << order)); spin_unlock(&zone->lock); return i; } @@ -996,6 +1021,9 @@ static void free_hot_cold_page(struct page *page, int cold) struct zone *zone = page_zone(page); struct per_cpu_pages *pcp; unsigned long flags; + int wasMlocked = TestClearPageMlocked(page); + + kmemcheck_free_shadow(page, 0); if (PageAnon(page)) page->mapping = NULL; @@ -1010,13 +1038,16 @@ static void free_hot_cold_page(struct page *page, int cold) kernel_map_pages(page, 1, 0); pcp = &zone_pcp(zone, get_cpu())->pcp; + set_page_private(page, get_pageblock_migratetype(page)); local_irq_save(flags); + if (unlikely(wasMlocked)) + free_page_mlock(page); __count_vm_event(PGFREE); + if (cold) list_add_tail(&page->lru, &pcp->list); else list_add(&page->lru, &pcp->list); - set_page_private(page, get_pageblock_migratetype(page)); pcp->count++; if (pcp->count >= pcp->high) { free_pages_bulk(zone, pcp->batch, &pcp->list, 0); @@ -1050,6 +1081,16 @@ void split_page(struct page *page, unsigned int order) VM_BUG_ON(PageCompound(page)); VM_BUG_ON(!page_count(page)); + +#ifdef CONFIG_KMEMCHECK + /* + * Split shadow pages too, because free(page[0]) would + * otherwise free the whole shadow. + */ + if (kmemcheck_page_is_tracked(page)) + split_page(virt_to_page(page[0].shadow), order); +#endif + for (i = 1; i < (1 << order); i++) set_page_refcounted(page + i); } @@ -1059,14 +1100,15 @@ void split_page(struct page *page, unsigned int order) * we cheat by calling it from here, in the order > 0 path. Saves a branch * or two. */ -static struct page *buffered_rmqueue(struct zone *preferred_zone, - struct zone *zone, int order, gfp_t gfp_flags) +static inline +struct page *buffered_rmqueue(struct zone *preferred_zone, + struct zone *zone, int order, gfp_t gfp_flags, + int migratetype) { unsigned long flags; struct page *page; int cold = !!(gfp_flags & __GFP_COLD); int cpu; - int migratetype = allocflags_to_migratetype(gfp_flags); again: cpu = get_cpu(); @@ -1103,8 +1145,22 @@ again: list_del(&page->lru); pcp->count--; } else { + if (unlikely(gfp_flags & __GFP_NOFAIL)) { + /* + * __GFP_NOFAIL is not to be used in new code. + * + * All __GFP_NOFAIL callers should be fixed so that they + * properly detect and handle allocation failures. + * + * We most definitely don't want callers attempting to + * allocate greater than order-1 page units with + * __GFP_NOFAIL. + */ + WARN_ON_ONCE(order > 1); + } spin_lock_irqsave(&zone->lock, flags); page = __rmqueue(zone, order, migratetype); + __mod_zone_page_state(zone, NR_FREE_PAGES, -(1 << order)); spin_unlock(&zone->lock); if (!page) goto failed; @@ -1126,10 +1182,15 @@ failed: return NULL; } -#define ALLOC_NO_WATERMARKS 0x01 /* don't check watermarks at all */ -#define ALLOC_WMARK_MIN 0x02 /* use pages_min watermark */ -#define ALLOC_WMARK_LOW 0x04 /* use pages_low watermark */ -#define ALLOC_WMARK_HIGH 0x08 /* use pages_high watermark */ +/* The ALLOC_WMARK bits are used as an index to zone->watermark */ +#define ALLOC_WMARK_MIN WMARK_MIN +#define ALLOC_WMARK_LOW WMARK_LOW +#define ALLOC_WMARK_HIGH WMARK_HIGH +#define ALLOC_NO_WATERMARKS 0x04 /* don't check watermarks at all */ + +/* Mask to get the watermark bits */ +#define ALLOC_WMARK_MASK (ALLOC_NO_WATERMARKS-1) + #define ALLOC_HARDER 0x10 /* try to alloc harder */ #define ALLOC_HIGH 0x20 /* __GFP_HIGH set */ #define ALLOC_CPUSET 0x40 /* check for correct cpuset */ @@ -1387,23 +1448,18 @@ static void zlc_mark_zone_full(struct zonelist *zonelist, struct zoneref *z) */ static struct page * get_page_from_freelist(gfp_t gfp_mask, nodemask_t *nodemask, unsigned int order, - struct zonelist *zonelist, int high_zoneidx, int alloc_flags) + struct zonelist *zonelist, int high_zoneidx, int alloc_flags, + struct zone *preferred_zone, int migratetype) { struct zoneref *z; struct page *page = NULL; int classzone_idx; - struct zone *zone, *preferred_zone; + struct zone *zone; nodemask_t *allowednodes = NULL;/* zonelist_cache approximation */ int zlc_active = 0; /* set if using zonelist_cache */ int did_zlc_setup = 0; /* just call zlc_setup() one time */ - (void)first_zones_zonelist(zonelist, high_zoneidx, nodemask, - &preferred_zone); - if (!preferred_zone) - return NULL; - classzone_idx = zone_idx(preferred_zone); - zonelist_scan: /* * Scan zonelist, looking for a zone with enough free. @@ -1418,31 +1474,49 @@ zonelist_scan: !cpuset_zone_allowed_softwall(zone, gfp_mask)) goto try_next_zone; + BUILD_BUG_ON(ALLOC_NO_WATERMARKS < NR_WMARK); if (!(alloc_flags & ALLOC_NO_WATERMARKS)) { unsigned long mark; - if (alloc_flags & ALLOC_WMARK_MIN) - mark = zone->pages_min; - else if (alloc_flags & ALLOC_WMARK_LOW) - mark = zone->pages_low; - else - mark = zone->pages_high; - if (!zone_watermark_ok(zone, order, mark, - classzone_idx, alloc_flags)) { - if (!zone_reclaim_mode || - !zone_reclaim(zone, gfp_mask, order)) + int ret; + + mark = zone->watermark[alloc_flags & ALLOC_WMARK_MASK]; + if (zone_watermark_ok(zone, order, mark, + classzone_idx, alloc_flags)) + goto try_this_zone; + + if (zone_reclaim_mode == 0) + goto this_zone_full; + + ret = zone_reclaim(zone, gfp_mask, order); + switch (ret) { + case ZONE_RECLAIM_NOSCAN: + /* did not scan */ + goto try_next_zone; + case ZONE_RECLAIM_FULL: + /* scanned but unreclaimable */ + goto this_zone_full; + default: + /* did we reclaim enough */ + if (!zone_watermark_ok(zone, order, mark, + classzone_idx, alloc_flags)) goto this_zone_full; } } - page = buffered_rmqueue(preferred_zone, zone, order, gfp_mask); +try_this_zone: + page = buffered_rmqueue(preferred_zone, zone, order, + gfp_mask, migratetype); if (page) break; this_zone_full: if (NUMA_BUILD) zlc_mark_zone_full(zonelist, z); try_next_zone: - if (NUMA_BUILD && !did_zlc_setup) { - /* we do zlc_setup after the first zone is tried */ + if (NUMA_BUILD && !did_zlc_setup && nr_online_nodes > 1) { + /* + * we do zlc_setup after the first zone is tried but only + * if there are multiple nodes make it worthwhile + */ allowednodes = zlc_setup(zonelist, alloc_flags); zlc_active = 1; did_zlc_setup = 1; @@ -1457,47 +1531,217 @@ try_next_zone: return page; } -/* - * This is the 'heart' of the zoned buddy allocator. - */ -struct page * -__alloc_pages_internal(gfp_t gfp_mask, unsigned int order, - struct zonelist *zonelist, nodemask_t *nodemask) +static inline int +should_alloc_retry(gfp_t gfp_mask, unsigned int order, + unsigned long pages_reclaimed) +{ + /* Do not loop if specifically requested */ + if (gfp_mask & __GFP_NORETRY) + return 0; + + /* + * In this implementation, order <= PAGE_ALLOC_COSTLY_ORDER + * means __GFP_NOFAIL, but that may not be true in other + * implementations. + */ + if (order <= PAGE_ALLOC_COSTLY_ORDER) + return 1; + + /* + * For order > PAGE_ALLOC_COSTLY_ORDER, if __GFP_REPEAT is + * specified, then we retry until we no longer reclaim any pages + * (above), or we've reclaimed an order of pages at least as + * large as the allocation's order. In both cases, if the + * allocation still fails, we stop retrying. + */ + if (gfp_mask & __GFP_REPEAT && pages_reclaimed < (1 << order)) + return 1; + + /* + * Don't let big-order allocations loop unless the caller + * explicitly requests that. + */ + if (gfp_mask & __GFP_NOFAIL) + return 1; + + return 0; +} + +static inline struct page * +__alloc_pages_may_oom(gfp_t gfp_mask, unsigned int order, + struct zonelist *zonelist, enum zone_type high_zoneidx, + nodemask_t *nodemask, struct zone *preferred_zone, + int migratetype) { - const gfp_t wait = gfp_mask & __GFP_WAIT; - enum zone_type high_zoneidx = gfp_zone(gfp_mask); - struct zoneref *z; - struct zone *zone; struct page *page; - struct reclaim_state reclaim_state; - struct task_struct *p = current; - int do_retry; - int alloc_flags; - unsigned long did_some_progress; - unsigned long pages_reclaimed = 0; - lockdep_trace_alloc(gfp_mask); - - might_sleep_if(wait); - - if (should_fail_alloc_page(gfp_mask, order)) - return NULL; - -restart: - z = zonelist->_zonerefs; /* the list of zones suitable for gfp_mask */ - - if (unlikely(!z->zone)) { - /* - * Happens if we have an empty zonelist as a result of - * GFP_THISNODE being used on a memoryless node - */ + /* Acquire the OOM killer lock for the zones in zonelist */ + if (!try_set_zone_oom(zonelist, gfp_mask)) { + schedule_timeout_uninterruptible(1); return NULL; } - page = get_page_from_freelist(gfp_mask|__GFP_HARDWALL, nodemask, order, - zonelist, high_zoneidx, ALLOC_WMARK_LOW|ALLOC_CPUSET); + /* + * Go through the zonelist yet one more time, keep very high watermark + * here, this is only to catch a parallel oom killing, we must fail if + * we're still under heavy pressure. + */ + page = get_page_from_freelist(gfp_mask|__GFP_HARDWALL, nodemask, + order, zonelist, high_zoneidx, + ALLOC_WMARK_HIGH|ALLOC_CPUSET, + preferred_zone, migratetype); if (page) - goto got_pg; + goto out; + + /* The OOM killer will not help higher order allocs */ + if (order > PAGE_ALLOC_COSTLY_ORDER && !(gfp_mask & __GFP_NOFAIL)) + goto out; + + /* Exhausted what can be done so it's blamo time */ + out_of_memory(zonelist, gfp_mask, order); + +out: + clear_zonelist_oom(zonelist, gfp_mask); + return page; +} + +/* The really slow allocator path where we enter direct reclaim */ +static inline struct page * +__alloc_pages_direct_reclaim(gfp_t gfp_mask, unsigned int order, + struct zonelist *zonelist, enum zone_type high_zoneidx, + nodemask_t *nodemask, int alloc_flags, struct zone *preferred_zone, + int migratetype, unsigned long *did_some_progress) +{ + struct page *page = NULL; + struct reclaim_state reclaim_state; + struct task_struct *p = current; + + cond_resched(); + + /* We now go into synchronous reclaim */ + cpuset_memory_pressure_bump(); + + /* + * The task's cpuset might have expanded its set of allowable nodes + */ + p->flags |= PF_MEMALLOC; + lockdep_set_current_reclaim_state(gfp_mask); + reclaim_state.reclaimed_slab = 0; + p->reclaim_state = &reclaim_state; + + *did_some_progress = try_to_free_pages(zonelist, order, gfp_mask, nodemask); + + p->reclaim_state = NULL; + lockdep_clear_current_reclaim_state(); + p->flags &= ~PF_MEMALLOC; + + cond_resched(); + + if (order != 0) + drain_all_pages(); + + if (likely(*did_some_progress)) + page = get_page_from_freelist(gfp_mask, nodemask, order, + zonelist, high_zoneidx, + alloc_flags, preferred_zone, + migratetype); + return page; +} + +/* + * This is called in the allocator slow-path if the allocation request is of + * sufficient urgency to ignore watermarks and take other desperate measures + */ +static inline struct page * +__alloc_pages_high_priority(gfp_t gfp_mask, unsigned int order, + struct zonelist *zonelist, enum zone_type high_zoneidx, + nodemask_t *nodemask, struct zone *preferred_zone, + int migratetype) +{ + struct page *page; + + do { + page = get_page_from_freelist(gfp_mask, nodemask, order, + zonelist, high_zoneidx, ALLOC_NO_WATERMARKS, + preferred_zone, migratetype); + + if (!page && gfp_mask & __GFP_NOFAIL) + congestion_wait(WRITE, HZ/50); + } while (!page && (gfp_mask & __GFP_NOFAIL)); + + return page; +} + +static inline +void wake_all_kswapd(unsigned int order, struct zonelist *zonelist, + enum zone_type high_zoneidx) +{ + struct zoneref *z; + struct zone *zone; + + for_each_zone_zonelist(zone, z, zonelist, high_zoneidx) + wakeup_kswapd(zone, order); +} + +static inline int +gfp_to_alloc_flags(gfp_t gfp_mask) +{ + struct task_struct *p = current; + int alloc_flags = ALLOC_WMARK_MIN | ALLOC_CPUSET; + const gfp_t wait = gfp_mask & __GFP_WAIT; + + /* __GFP_HIGH is assumed to be the same as ALLOC_HIGH to save a branch. */ + BUILD_BUG_ON(__GFP_HIGH != ALLOC_HIGH); + + /* + * The caller may dip into page reserves a bit more if the caller + * cannot run direct reclaim, or if the caller has realtime scheduling + * policy or is asking for __GFP_HIGH memory. GFP_ATOMIC requests will + * set both ALLOC_HARDER (!wait) and ALLOC_HIGH (__GFP_HIGH). + */ + alloc_flags |= (gfp_mask & __GFP_HIGH); + + if (!wait) { + alloc_flags |= ALLOC_HARDER; + /* + * Ignore cpuset if GFP_ATOMIC (!wait) rather than fail alloc. + * See also cpuset_zone_allowed() comment in kernel/cpuset.c. + */ + alloc_flags &= ~ALLOC_CPUSET; + } else if (unlikely(rt_task(p))) + alloc_flags |= ALLOC_HARDER; + + if (likely(!(gfp_mask & __GFP_NOMEMALLOC))) { + if (!in_interrupt() && + ((p->flags & PF_MEMALLOC) || + unlikely(test_thread_flag(TIF_MEMDIE)))) + alloc_flags |= ALLOC_NO_WATERMARKS; + } + + return alloc_flags; +} + +static inline struct page * +__alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order, + struct zonelist *zonelist, enum zone_type high_zoneidx, + nodemask_t *nodemask, struct zone *preferred_zone, + int migratetype) +{ + const gfp_t wait = gfp_mask & __GFP_WAIT; + struct page *page = NULL; + int alloc_flags; + unsigned long pages_reclaimed = 0; + unsigned long did_some_progress; + struct task_struct *p = current; + + /* + * In the slowpath, we sanity check order to avoid ever trying to + * reclaim >= MAX_ORDER areas which will never succeed. Callers may + * be using allocators in order of preference for an area that is + * too large. + */ + if (WARN_ON_ONCE(order >= MAX_ORDER)) + return NULL; /* * GFP_THISNODE (meaning __GFP_THISNODE, __GFP_NORETRY and @@ -1510,154 +1754,83 @@ restart: if (NUMA_BUILD && (gfp_mask & GFP_THISNODE) == GFP_THISNODE) goto nopage; - for_each_zone_zonelist(zone, z, zonelist, high_zoneidx) - wakeup_kswapd(zone, order); + wake_all_kswapd(order, zonelist, high_zoneidx); /* * OK, we're below the kswapd watermark and have kicked background * reclaim. Now things get more complex, so set up alloc_flags according * to how we want to proceed. - * - * The caller may dip into page reserves a bit more if the caller - * cannot run direct reclaim, or if the caller has realtime scheduling - * policy or is asking for __GFP_HIGH memory. GFP_ATOMIC requests will - * set both ALLOC_HARDER (!wait) and ALLOC_HIGH (__GFP_HIGH). */ - alloc_flags = ALLOC_WMARK_MIN; - if ((unlikely(rt_task(p)) && !in_interrupt()) || !wait) - alloc_flags |= ALLOC_HARDER; - if (gfp_mask & __GFP_HIGH) - alloc_flags |= ALLOC_HIGH; - if (wait) - alloc_flags |= ALLOC_CPUSET; + alloc_flags = gfp_to_alloc_flags(gfp_mask); - /* - * Go through the zonelist again. Let __GFP_HIGH and allocations - * coming from realtime tasks go deeper into reserves. - * - * This is the last chance, in general, before the goto nopage. - * Ignore cpuset if GFP_ATOMIC (!wait) rather than fail alloc. - * See also cpuset_zone_allowed() comment in kernel/cpuset.c. - */ +restart: + /* This is the last chance, in general, before the goto nopage. */ page = get_page_from_freelist(gfp_mask, nodemask, order, zonelist, - high_zoneidx, alloc_flags); + high_zoneidx, alloc_flags & ~ALLOC_NO_WATERMARKS, + preferred_zone, migratetype); if (page) goto got_pg; - /* This allocation should allow future memory freeing. */ - rebalance: - if (((p->flags & PF_MEMALLOC) || unlikely(test_thread_flag(TIF_MEMDIE))) - && !in_interrupt()) { - if (!(gfp_mask & __GFP_NOMEMALLOC)) { -nofail_alloc: - /* go through the zonelist yet again, ignoring mins */ - page = get_page_from_freelist(gfp_mask, nodemask, order, - zonelist, high_zoneidx, ALLOC_NO_WATERMARKS); - if (page) - goto got_pg; - if (gfp_mask & __GFP_NOFAIL) { - congestion_wait(WRITE, HZ/50); - goto nofail_alloc; - } - } - goto nopage; + /* Allocate without watermarks if the context allows */ + if (alloc_flags & ALLOC_NO_WATERMARKS) { + page = __alloc_pages_high_priority(gfp_mask, order, + zonelist, high_zoneidx, nodemask, + preferred_zone, migratetype); + if (page) + goto got_pg; } /* Atomic allocations - we can't balance anything */ if (!wait) goto nopage; - cond_resched(); + /* Avoid recursion of direct reclaim */ + if (p->flags & PF_MEMALLOC) + goto nopage; + + /* Try direct reclaim and then allocating */ + page = __alloc_pages_direct_reclaim(gfp_mask, order, + zonelist, high_zoneidx, + nodemask, + alloc_flags, preferred_zone, + migratetype, &did_some_progress); + if (page) + goto got_pg; - /* We now go into synchronous reclaim */ - cpuset_memory_pressure_bump(); /* - * The task's cpuset might have expanded its set of allowable nodes + * If we failed to make any progress reclaiming, then we are + * running out of options and have to consider going OOM */ - cpuset_update_task_memory_state(); - p->flags |= PF_MEMALLOC; + if (!did_some_progress) { + if ((gfp_mask & __GFP_FS) && !(gfp_mask & __GFP_NORETRY)) { + if (oom_killer_disabled) + goto nopage; + page = __alloc_pages_may_oom(gfp_mask, order, + zonelist, high_zoneidx, + nodemask, preferred_zone, + migratetype); + if (page) + goto got_pg; - lockdep_set_current_reclaim_state(gfp_mask); - reclaim_state.reclaimed_slab = 0; - p->reclaim_state = &reclaim_state; + /* + * The OOM killer does not trigger for high-order + * ~__GFP_NOFAIL allocations so if no progress is being + * made, there are no other options and retrying is + * unlikely to help. + */ + if (order > PAGE_ALLOC_COSTLY_ORDER && + !(gfp_mask & __GFP_NOFAIL)) + goto nopage; - did_some_progress = try_to_free_pages(zonelist, order, - gfp_mask, nodemask); - - p->reclaim_state = NULL; - lockdep_clear_current_reclaim_state(); - p->flags &= ~PF_MEMALLOC; - - cond_resched(); - - if (order != 0) - drain_all_pages(); - - if (likely(did_some_progress)) { - page = get_page_from_freelist(gfp_mask, nodemask, order, - zonelist, high_zoneidx, alloc_flags); - if (page) - goto got_pg; - } else if ((gfp_mask & __GFP_FS) && !(gfp_mask & __GFP_NORETRY)) { - if (!try_set_zone_oom(zonelist, gfp_mask)) { - schedule_timeout_uninterruptible(1); goto restart; } - - /* - * Go through the zonelist yet one more time, keep - * very high watermark here, this is only to catch - * a parallel oom killing, we must fail if we're still - * under heavy pressure. - */ - page = get_page_from_freelist(gfp_mask|__GFP_HARDWALL, nodemask, - order, zonelist, high_zoneidx, - ALLOC_WMARK_HIGH|ALLOC_CPUSET); - if (page) { - clear_zonelist_oom(zonelist, gfp_mask); - goto got_pg; - } - - /* The OOM killer will not help higher order allocs so fail */ - if (order > PAGE_ALLOC_COSTLY_ORDER) { - clear_zonelist_oom(zonelist, gfp_mask); - goto nopage; - } - - out_of_memory(zonelist, gfp_mask, order); - clear_zonelist_oom(zonelist, gfp_mask); - goto restart; } - /* - * Don't let big-order allocations loop unless the caller explicitly - * requests that. Wait for some write requests to complete then retry. - * - * In this implementation, order <= PAGE_ALLOC_COSTLY_ORDER - * means __GFP_NOFAIL, but that may not be true in other - * implementations. - * - * For order > PAGE_ALLOC_COSTLY_ORDER, if __GFP_REPEAT is - * specified, then we retry until we no longer reclaim any pages - * (above), or we've reclaimed an order of pages at least as - * large as the allocation's order. In both cases, if the - * allocation still fails, we stop retrying. - */ + /* Check if we should retry the allocation */ pages_reclaimed += did_some_progress; - do_retry = 0; - if (!(gfp_mask & __GFP_NORETRY)) { - if (order <= PAGE_ALLOC_COSTLY_ORDER) { - do_retry = 1; - } else { - if (gfp_mask & __GFP_REPEAT && - pages_reclaimed < (1 << order)) - do_retry = 1; - } - if (gfp_mask & __GFP_NOFAIL) - do_retry = 1; - } - if (do_retry) { + if (should_alloc_retry(gfp_mask, order, pages_reclaimed)) { + /* Wait for some write requests to complete then retry */ congestion_wait(WRITE, HZ/50); goto rebalance; } @@ -1670,10 +1843,60 @@ nopage: dump_stack(); show_mem(); } + return page; got_pg: + if (kmemcheck_enabled) + kmemcheck_pagealloc_alloc(page, order, gfp_mask); + return page; + +} + +/* + * This is the 'heart' of the zoned buddy allocator. + */ +struct page * +__alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order, + struct zonelist *zonelist, nodemask_t *nodemask) +{ + enum zone_type high_zoneidx = gfp_zone(gfp_mask); + struct zone *preferred_zone; + struct page *page; + int migratetype = allocflags_to_migratetype(gfp_mask); + + gfp_mask &= gfp_allowed_mask; + + lockdep_trace_alloc(gfp_mask); + + might_sleep_if(gfp_mask & __GFP_WAIT); + + if (should_fail_alloc_page(gfp_mask, order)) + return NULL; + + /* + * Check the zones suitable for the gfp_mask contain at least one + * valid zone. It's possible to have an empty zonelist as a result + * of GFP_THISNODE and a memoryless node + */ + if (unlikely(!zonelist->_zonerefs->zone)) + return NULL; + + /* The preferred zone is used for statistics later */ + first_zones_zonelist(zonelist, high_zoneidx, nodemask, &preferred_zone); + if (!preferred_zone) + return NULL; + + /* First allocation attempt */ + page = get_page_from_freelist(gfp_mask|__GFP_HARDWALL, nodemask, order, + zonelist, high_zoneidx, ALLOC_WMARK_LOW|ALLOC_CPUSET, + preferred_zone, migratetype); + if (unlikely(!page)) + page = __alloc_pages_slowpath(gfp_mask, order, + zonelist, high_zoneidx, nodemask, + preferred_zone, migratetype); + return page; } -EXPORT_SYMBOL(__alloc_pages_internal); +EXPORT_SYMBOL(__alloc_pages_nodemask); /* * Common helper functions. @@ -1802,7 +2025,7 @@ static unsigned int nr_free_zone_pages(int offset) for_each_zone_zonelist(zone, z, zonelist, offset) { unsigned long size = zone->present_pages; - unsigned long high = zone->pages_high; + unsigned long high = high_wmark_pages(zone); if (size > high) sum += size - high; } @@ -1894,19 +2117,14 @@ void show_free_areas(void) printk("Active_anon:%lu active_file:%lu inactive_anon:%lu\n" " inactive_file:%lu" -//TODO: check/adjust line lengths -#ifdef CONFIG_UNEVICTABLE_LRU " unevictable:%lu" -#endif " dirty:%lu writeback:%lu unstable:%lu\n" " free:%lu slab:%lu mapped:%lu pagetables:%lu bounce:%lu\n", global_page_state(NR_ACTIVE_ANON), global_page_state(NR_ACTIVE_FILE), global_page_state(NR_INACTIVE_ANON), global_page_state(NR_INACTIVE_FILE), -#ifdef CONFIG_UNEVICTABLE_LRU global_page_state(NR_UNEVICTABLE), -#endif global_page_state(NR_FILE_DIRTY), global_page_state(NR_WRITEBACK), global_page_state(NR_UNSTABLE_NFS), @@ -1930,25 +2148,21 @@ void show_free_areas(void) " inactive_anon:%lukB" " active_file:%lukB" " inactive_file:%lukB" -#ifdef CONFIG_UNEVICTABLE_LRU " unevictable:%lukB" -#endif " present:%lukB" " pages_scanned:%lu" " all_unreclaimable? %s" "\n", zone->name, K(zone_page_state(zone, NR_FREE_PAGES)), - K(zone->pages_min), - K(zone->pages_low), - K(zone->pages_high), + K(min_wmark_pages(zone)), + K(low_wmark_pages(zone)), + K(high_wmark_pages(zone)), K(zone_page_state(zone, NR_ACTIVE_ANON)), K(zone_page_state(zone, NR_INACTIVE_ANON)), K(zone_page_state(zone, NR_ACTIVE_FILE)), K(zone_page_state(zone, NR_INACTIVE_FILE)), -#ifdef CONFIG_UNEVICTABLE_LRU K(zone_page_state(zone, NR_UNEVICTABLE)), -#endif K(zone->present_pages), zone->pages_scanned, (zone_is_all_unreclaimable(zone) ? "yes" : "no") @@ -2106,7 +2320,7 @@ int numa_zonelist_order_handler(ctl_table *table, int write, } -#define MAX_NODE_LOAD (num_online_nodes()) +#define MAX_NODE_LOAD (nr_online_nodes) static int node_load[MAX_NUMNODES]; /** @@ -2315,7 +2529,7 @@ static void build_zonelists(pg_data_t *pgdat) /* NUMA-aware ordering of nodes */ local_node = pgdat->node_id; - load = num_online_nodes(); + load = nr_online_nodes; prev_node = local_node; nodes_clear(used_mask); @@ -2466,7 +2680,7 @@ void build_all_zonelists(void) printk("Built %i zonelists in %s order, mobility grouping %s. " "Total pages: %ld\n", - num_online_nodes(), + nr_online_nodes, zonelist_order_name[current_zonelist_order], page_group_by_mobility_disabled ? "off" : "on", vm_total_pages); @@ -2545,8 +2759,8 @@ static inline unsigned long wait_table_bits(unsigned long size) /* * Mark a number of pageblocks as MIGRATE_RESERVE. The number - * of blocks reserved is based on zone->pages_min. The memory within the - * reserve will tend to store contiguous free pages. Setting min_free_kbytes + * of blocks reserved is based on min_wmark_pages(zone). The memory within + * the reserve will tend to store contiguous free pages. Setting min_free_kbytes * higher will lead to a bigger reserve which will get freed as contiguous * blocks as reclaim kicks in */ @@ -2559,7 +2773,7 @@ static void setup_zone_migrate_reserve(struct zone *zone) /* Get the start pfn, end pfn and the number of blocks to reserve */ start_pfn = zone->zone_start_pfn; end_pfn = start_pfn + zone->spanned_pages; - reserve = roundup(zone->pages_min, pageblock_nr_pages) >> + reserve = roundup(min_wmark_pages(zone), pageblock_nr_pages) >> pageblock_order; for (pfn = start_pfn; pfn < end_pfn; pfn += pageblock_nr_pages) { @@ -2812,7 +3026,7 @@ bad: if (dzone == zone) break; kfree(zone_pcp(dzone, cpu)); - zone_pcp(dzone, cpu) = NULL; + zone_pcp(dzone, cpu) = &boot_pageset[cpu]; } return -ENOMEM; } @@ -2827,7 +3041,7 @@ static inline void free_zone_pagesets(int cpu) /* Free per_cpu_pageset if it is slab allocated */ if (pset != &boot_pageset[cpu]) kfree(pset); - zone_pcp(zone, cpu) = NULL; + zone_pcp(zone, cpu) = &boot_pageset[cpu]; } } @@ -3102,64 +3316,6 @@ void __init sparse_memory_present_with_active_regions(int nid) early_node_map[i].end_pfn); } -/** - * push_node_boundaries - Push node boundaries to at least the requested boundary - * @nid: The nid of the node to push the boundary for - * @start_pfn: The start pfn of the node - * @end_pfn: The end pfn of the node - * - * In reserve-based hot-add, mem_map is allocated that is unused until hotadd - * time. Specifically, on x86_64, SRAT will report ranges that can potentially - * be hotplugged even though no physical memory exists. This function allows - * an arch to push out the node boundaries so mem_map is allocated that can - * be used later. - */ -#ifdef CONFIG_MEMORY_HOTPLUG_RESERVE -void __init push_node_boundaries(unsigned int nid, - unsigned long start_pfn, unsigned long end_pfn) -{ - mminit_dprintk(MMINIT_TRACE, "zoneboundary", - "Entering push_node_boundaries(%u, %lu, %lu)\n", - nid, start_pfn, end_pfn); - - /* Initialise the boundary for this node if necessary */ - if (node_boundary_end_pfn[nid] == 0) - node_boundary_start_pfn[nid] = -1UL; - - /* Update the boundaries */ - if (node_boundary_start_pfn[nid] > start_pfn) - node_boundary_start_pfn[nid] = start_pfn; - if (node_boundary_end_pfn[nid] < end_pfn) - node_boundary_end_pfn[nid] = end_pfn; -} - -/* If necessary, push the node boundary out for reserve hotadd */ -static void __meminit account_node_boundary(unsigned int nid, - unsigned long *start_pfn, unsigned long *end_pfn) -{ - mminit_dprintk(MMINIT_TRACE, "zoneboundary", - "Entering account_node_boundary(%u, %lu, %lu)\n", - nid, *start_pfn, *end_pfn); - - /* Return if boundary information has not been provided */ - if (node_boundary_end_pfn[nid] == 0) - return; - - /* Check the boundaries and update if necessary */ - if (node_boundary_start_pfn[nid] < *start_pfn) - *start_pfn = node_boundary_start_pfn[nid]; - if (node_boundary_end_pfn[nid] > *end_pfn) - *end_pfn = node_boundary_end_pfn[nid]; -} -#else -void __init push_node_boundaries(unsigned int nid, - unsigned long start_pfn, unsigned long end_pfn) {} - -static void __meminit account_node_boundary(unsigned int nid, - unsigned long *start_pfn, unsigned long *end_pfn) {} -#endif - - /** * get_pfn_range_for_nid - Return the start and end page frames for a node * @nid: The nid to return the range for. If MAX_NUMNODES, the min and max PFN are returned. @@ -3185,9 +3341,6 @@ void __meminit get_pfn_range_for_nid(unsigned int nid, if (*start_pfn == -1UL) *start_pfn = 0; - - /* Push the node boundaries out if requested */ - account_node_boundary(nid, start_pfn, end_pfn); } /* @@ -3552,7 +3705,7 @@ static void __paginginit free_area_init_core(struct pglist_data *pgdat, zone_pcp_init(zone); for_each_lru(l) { INIT_LIST_HEAD(&zone->lru[l].list); - zone->lru[l].nr_scan = 0; + zone->lru[l].nr_saved_scan = 0; } zone->reclaim_stat.recent_rotated[0] = 0; zone->reclaim_stat.recent_rotated[1] = 0; @@ -3793,10 +3946,6 @@ void __init remove_all_active_ranges(void) { memset(early_node_map, 0, sizeof(early_node_map)); nr_nodemap_entries = 0; -#ifdef CONFIG_MEMORY_HOTPLUG_RESERVE - memset(node_boundary_start_pfn, 0, sizeof(node_boundary_start_pfn)); - memset(node_boundary_end_pfn, 0, sizeof(node_boundary_end_pfn)); -#endif /* CONFIG_MEMORY_HOTPLUG_RESERVE */ } /* Compare two active node_active_regions */ @@ -4093,6 +4242,11 @@ void __init free_area_init_nodes(unsigned long *max_zone_pfn) early_node_map[i].start_pfn, early_node_map[i].end_pfn); + /* + * find_zone_movable_pfns_for_nodes/early_calculate_totalpages init + * that node_mask, clear it at first + */ + nodes_clear(node_states[N_HIGH_MEMORY]); /* Initialise every node */ mminit_verify_pageflags_layout(); setup_nr_node_ids(); @@ -4227,8 +4381,8 @@ static void calculate_totalreserve_pages(void) max = zone->lowmem_reserve[j]; } - /* we treat pages_high as reserved pages. */ - max += zone->pages_high; + /* we treat the high watermark as reserved pages. */ + max += high_wmark_pages(zone); if (max > zone->present_pages) max = zone->present_pages; @@ -4278,12 +4432,13 @@ static void setup_per_zone_lowmem_reserve(void) } /** - * setup_per_zone_pages_min - called when min_free_kbytes changes. + * setup_per_zone_wmarks - called when min_free_kbytes changes + * or when memory is hot-{added|removed} * - * Ensures that the pages_{min,low,high} values for each zone are set correctly - * with respect to min_free_kbytes. + * Ensures that the watermark[min,low,high] values for each zone are set + * correctly with respect to min_free_kbytes. */ -void setup_per_zone_pages_min(void) +void setup_per_zone_wmarks(void) { unsigned long pages_min = min_free_kbytes >> (PAGE_SHIFT - 10); unsigned long lowmem_pages = 0; @@ -4308,7 +4463,7 @@ void setup_per_zone_pages_min(void) * need highmem pages, so cap pages_min to a small * value here. * - * The (pages_high-pages_low) and (pages_low-pages_min) + * The WMARK_HIGH-WMARK_LOW and (WMARK_LOW-WMARK_MIN) * deltas controls asynch page reclaim, and so should * not be capped for highmem. */ @@ -4319,17 +4474,17 @@ void setup_per_zone_pages_min(void) min_pages = SWAP_CLUSTER_MAX; if (min_pages > 128) min_pages = 128; - zone->pages_min = min_pages; + zone->watermark[WMARK_MIN] = min_pages; } else { /* * If it's a lowmem zone, reserve a number of pages * proportionate to the zone's size. */ - zone->pages_min = tmp; + zone->watermark[WMARK_MIN] = tmp; } - zone->pages_low = zone->pages_min + (tmp >> 2); - zone->pages_high = zone->pages_min + (tmp >> 1); + zone->watermark[WMARK_LOW] = min_wmark_pages(zone) + (tmp >> 2); + zone->watermark[WMARK_HIGH] = min_wmark_pages(zone) + (tmp >> 1); setup_zone_migrate_reserve(zone); spin_unlock_irqrestore(&zone->lock, flags); } @@ -4339,8 +4494,6 @@ void setup_per_zone_pages_min(void) } /** - * setup_per_zone_inactive_ratio - called when min_free_kbytes changes. - * * The inactive anon list should be small enough that the VM never has to * do too much work, but large enough that each inactive page has a chance * to be referenced again before it is swapped out. @@ -4361,21 +4514,26 @@ void setup_per_zone_pages_min(void) * 1TB 101 10GB * 10TB 320 32GB */ -static void setup_per_zone_inactive_ratio(void) +void calculate_zone_inactive_ratio(struct zone *zone) +{ + unsigned int gb, ratio; + + /* Zone size in gigabytes */ + gb = zone->present_pages >> (30 - PAGE_SHIFT); + if (gb) + ratio = int_sqrt(10 * gb); + else + ratio = 1; + + zone->inactive_ratio = ratio; +} + +static void __init setup_per_zone_inactive_ratio(void) { struct zone *zone; - for_each_zone(zone) { - unsigned int gb, ratio; - - /* Zone size in gigabytes */ - gb = zone->present_pages >> (30 - PAGE_SHIFT); - ratio = int_sqrt(10 * gb); - if (!ratio) - ratio = 1; - - zone->inactive_ratio = ratio; - } + for_each_zone(zone) + calculate_zone_inactive_ratio(zone); } /* @@ -4402,7 +4560,7 @@ static void setup_per_zone_inactive_ratio(void) * 8192MB: 11584k * 16384MB: 16384k */ -static int __init init_per_zone_pages_min(void) +static int __init init_per_zone_wmark_min(void) { unsigned long lowmem_kbytes; @@ -4413,12 +4571,12 @@ static int __init init_per_zone_pages_min(void) min_free_kbytes = 128; if (min_free_kbytes > 65536) min_free_kbytes = 65536; - setup_per_zone_pages_min(); + setup_per_zone_wmarks(); setup_per_zone_lowmem_reserve(); setup_per_zone_inactive_ratio(); return 0; } -module_init(init_per_zone_pages_min) +module_init(init_per_zone_wmark_min) /* * min_free_kbytes_sysctl_handler - just a wrapper around proc_dointvec() so @@ -4430,7 +4588,7 @@ int min_free_kbytes_sysctl_handler(ctl_table *table, int write, { proc_dointvec(table, write, file, buffer, length, ppos); if (write) - setup_per_zone_pages_min(); + setup_per_zone_wmarks(); return 0; } @@ -4474,7 +4632,7 @@ int sysctl_min_slab_ratio_sysctl_handler(ctl_table *table, int write, * whenever sysctl_lowmem_reserve_ratio changes. * * The reserve ratio obviously has absolutely no relation with the - * pages_min watermarks. The lowmem reserve ratio can only make sense + * minimum watermarks. The lowmem reserve ratio can only make sense * if in function of the boot time zone sizes. */ int lowmem_reserve_ratio_sysctl_handler(ctl_table *table, int write, @@ -4501,7 +4659,7 @@ int percpu_pagelist_fraction_sysctl_handler(ctl_table *table, int write, ret = proc_dointvec_minmax(table, write, file, buffer, length, ppos); if (!write || (ret == -EINVAL)) return ret; - for_each_zone(zone) { + for_each_populated_zone(zone) { for_each_online_cpu(cpu) { unsigned long high; high = zone->present_pages / percpu_pagelist_fraction; @@ -4581,23 +4739,13 @@ void *__init alloc_large_system_hash(const char *tablename, else if (hashdist) table = __vmalloc(size, GFP_ATOMIC, PAGE_KERNEL); else { - unsigned long order = get_order(size); - table = (void*) __get_free_pages(GFP_ATOMIC, order); /* * If bucketsize is not a power-of-two, we may free - * some pages at the end of hash table. + * some pages at the end of hash table which + * alloc_pages_exact() automatically does */ - if (table) { - unsigned long alloc_end = (unsigned long)table + - (PAGE_SIZE << order); - unsigned long used = (unsigned long)table + - PAGE_ALIGN(size); - split_page(virt_to_page(table), order); - while (used < alloc_end) { - free_page(used); - used += PAGE_SIZE; - } - } + if (get_order(size) < MAX_ORDER) + table = alloc_pages_exact(size, GFP_ATOMIC); } } while (!table && size > PAGE_SIZE && --log2qty); @@ -4615,6 +4763,16 @@ void *__init alloc_large_system_hash(const char *tablename, if (_hash_mask) *_hash_mask = (1 << log2qty) - 1; + /* + * If hashdist is set, the table allocation is done with __vmalloc() + * which invokes the kmemleak_alloc() callback. This function may also + * be called before the slab and kmemleak are initialised when + * kmemleak simply buffers the request to be executed later + * (GFP_ATOMIC flag ignored in this case). + */ + if (!hashdist) + kmemleak_alloc(table, size, 1, GFP_ATOMIC); + return table; } diff --git a/mm/page_cgroup.c b/mm/page_cgroup.c index 791905c991df..f22b4ebbd8dc 100644 --- a/mm/page_cgroup.c +++ b/mm/page_cgroup.c @@ -69,7 +69,7 @@ static int __init alloc_node_page_cgroup(int nid) return 0; } -void __init page_cgroup_init(void) +void __init page_cgroup_init_flatmem(void) { int nid, fail; @@ -83,12 +83,12 @@ void __init page_cgroup_init(void) goto fail; } printk(KERN_INFO "allocated %ld bytes of page_cgroup\n", total_usage); - printk(KERN_INFO "please try cgroup_disable=memory option if you" - " don't want\n"); + printk(KERN_INFO "please try 'cgroup_disable=memory' option if you" + " don't want memory cgroups\n"); return; fail: - printk(KERN_CRIT "allocation of page_cgroup was failed.\n"); - printk(KERN_CRIT "please try cgroup_disable=memory boot option\n"); + printk(KERN_CRIT "allocation of page_cgroup failed.\n"); + printk(KERN_CRIT "please try 'cgroup_disable=memory' boot option\n"); panic("Out of memory"); } @@ -99,6 +99,8 @@ struct page_cgroup *lookup_page_cgroup(struct page *page) unsigned long pfn = page_to_pfn(page); struct mem_section *section = __pfn_to_section(pfn); + if (!section->page_cgroup) + return NULL; return section->page_cgroup + pfn; } @@ -113,16 +115,11 @@ static int __init_refok init_section_page_cgroup(unsigned long pfn) if (!section->page_cgroup) { nid = page_to_nid(pfn_to_page(pfn)); table_size = sizeof(struct page_cgroup) * PAGES_PER_SECTION; - if (slab_is_available()) { - base = kmalloc_node(table_size, - GFP_KERNEL | __GFP_NOWARN, nid); - if (!base) - base = vmalloc_node(table_size, nid); - } else { - base = __alloc_bootmem_node_nopanic(NODE_DATA(nid), - table_size, - PAGE_SIZE, __pa(MAX_DMA_ADDRESS)); - } + VM_BUG_ON(!slab_is_available()); + base = kmalloc_node(table_size, + GFP_KERNEL | __GFP_NOWARN, nid); + if (!base) + base = vmalloc_node(table_size, nid); } else { /* * We don't have to allocate page_cgroup again, but @@ -257,14 +254,14 @@ void __init page_cgroup_init(void) fail = init_section_page_cgroup(pfn); } if (fail) { - printk(KERN_CRIT "try cgroup_disable=memory boot option\n"); + printk(KERN_CRIT "try 'cgroup_disable=memory' boot option\n"); panic("Out of memory"); } else { hotplug_memory_notifier(page_cgroup_callback, 0); } printk(KERN_INFO "allocated %ld bytes of page_cgroup\n", total_usage); - printk(KERN_INFO "please try cgroup_disable=memory option if you don't" - " want\n"); + printk(KERN_INFO "please try 'cgroup_disable=memory' option if you don't" + " want memory cgroups\n"); } void __meminit pgdat_page_cgroup_init(struct pglist_data *pgdat) @@ -314,8 +311,6 @@ static int swap_cgroup_prepare(int type) struct swap_cgroup_ctrl *ctrl; unsigned long idx, max; - if (!do_swap_account) - return 0; ctrl = &swap_cgroup_ctrl[type]; for (idx = 0; idx < ctrl->length; idx++) { @@ -352,9 +347,6 @@ unsigned short swap_cgroup_record(swp_entry_t ent, unsigned short id) struct swap_cgroup *sc; unsigned short old; - if (!do_swap_account) - return 0; - ctrl = &swap_cgroup_ctrl[type]; mappage = ctrl->map[idx]; @@ -383,9 +375,6 @@ unsigned short lookup_swap_cgroup(swp_entry_t ent) struct swap_cgroup *sc; unsigned short ret; - if (!do_swap_account) - return 0; - ctrl = &swap_cgroup_ctrl[type]; mappage = ctrl->map[idx]; sc = page_address(mappage); diff --git a/mm/page_io.c b/mm/page_io.c index 3023c475e041..c6f3e5071de3 100644 --- a/mm/page_io.c +++ b/mm/page_io.c @@ -120,7 +120,7 @@ out: return ret; } -int swap_readpage(struct file *file, struct page *page) +int swap_readpage(struct page *page) { struct bio *bio; int ret = 0; diff --git a/mm/percpu.c b/mm/percpu.c index 1aa5d8fbca12..c0b2c1a76e81 100644 --- a/mm/percpu.c +++ b/mm/percpu.c @@ -23,7 +23,7 @@ * Allocation is done in offset-size areas of single unit space. Ie, * an area of 512 bytes at 6k in c1 occupies 512 bytes at 6k of c1:u0, * c1:u1, c1:u2 and c1:u3. Percpu access can be done by configuring - * percpu base registers UNIT_SIZE apart. + * percpu base registers pcpu_unit_size apart. * * There are usually many small percpu allocations many of them as * small as 4 bytes. The allocator organizes chunks into lists @@ -38,8 +38,8 @@ * region and negative allocated. Allocation inside a chunk is done * by scanning this map sequentially and serving the first matching * entry. This is mostly copied from the percpu_modalloc() allocator. - * Chunks are also linked into a rb tree to ease address to chunk - * mapping during free. + * Chunks can be determined from the address using the index field + * in the page struct. The index field contains a pointer to the chunk. * * To use this allocator, arch code should do the followings. * @@ -61,7 +61,6 @@ #include #include #include -#include #include #include #include @@ -88,7 +87,6 @@ struct pcpu_chunk { struct list_head list; /* linked to pcpu_slot lists */ - struct rb_node rb_node; /* key is chunk->vm->addr */ int free_size; /* free bytes in the chunk */ int contig_hint; /* max contiguous size hint */ struct vm_struct *vm; /* mapped vmalloc region */ @@ -110,9 +108,21 @@ static size_t pcpu_chunk_struct_size __read_mostly; void *pcpu_base_addr __read_mostly; EXPORT_SYMBOL_GPL(pcpu_base_addr); -/* optional reserved chunk, only accessible for reserved allocations */ +/* + * The first chunk which always exists. Note that unlike other + * chunks, this one can be allocated and mapped in several different + * ways and thus often doesn't live in the vmalloc area. + */ +static struct pcpu_chunk *pcpu_first_chunk; + +/* + * Optional reserved chunk. This chunk reserves part of the first + * chunk and serves it for reserved allocations. The amount of + * reserved offset is in pcpu_reserved_chunk_limit. When reserved + * area doesn't exist, the following variables contain NULL and 0 + * respectively. + */ static struct pcpu_chunk *pcpu_reserved_chunk; -/* offset limit of the reserved chunk */ static int pcpu_reserved_chunk_limit; /* @@ -121,7 +131,7 @@ static int pcpu_reserved_chunk_limit; * There are two locks - pcpu_alloc_mutex and pcpu_lock. The former * protects allocation/reclaim paths, chunks and chunk->page arrays. * The latter is a spinlock and protects the index data structures - - * chunk slots, rbtree, chunks and area maps in chunks. + * chunk slots, chunks and area maps in chunks. * * During allocation, pcpu_alloc_mutex is kept locked all the time and * pcpu_lock is grabbed and released as necessary. All actual memory @@ -140,7 +150,6 @@ static DEFINE_MUTEX(pcpu_alloc_mutex); /* protects whole alloc and reclaim */ static DEFINE_SPINLOCK(pcpu_lock); /* protects index data structures */ static struct list_head *pcpu_slot __read_mostly; /* chunk list slots */ -static struct rb_root pcpu_addr_root = RB_ROOT; /* chunks by address */ /* reclaim work to release fully free chunks, scheduled from free path */ static void pcpu_reclaim(struct work_struct *work); @@ -191,6 +200,18 @@ static bool pcpu_chunk_page_occupied(struct pcpu_chunk *chunk, return *pcpu_chunk_pagep(chunk, 0, page_idx) != NULL; } +/* set the pointer to a chunk in a page struct */ +static void pcpu_set_page_chunk(struct page *page, struct pcpu_chunk *pcpu) +{ + page->index = (unsigned long)pcpu; +} + +/* obtain pointer to a chunk from a page struct */ +static struct pcpu_chunk *pcpu_get_page_chunk(struct page *page) +{ + return (struct pcpu_chunk *)page->index; +} + /** * pcpu_mem_alloc - allocate memory * @size: bytes to allocate @@ -257,93 +278,26 @@ static void pcpu_chunk_relocate(struct pcpu_chunk *chunk, int oslot) } } -static struct rb_node **pcpu_chunk_rb_search(void *addr, - struct rb_node **parentp) -{ - struct rb_node **p = &pcpu_addr_root.rb_node; - struct rb_node *parent = NULL; - struct pcpu_chunk *chunk; - - while (*p) { - parent = *p; - chunk = rb_entry(parent, struct pcpu_chunk, rb_node); - - if (addr < chunk->vm->addr) - p = &(*p)->rb_left; - else if (addr > chunk->vm->addr) - p = &(*p)->rb_right; - else - break; - } - - if (parentp) - *parentp = parent; - return p; -} - /** - * pcpu_chunk_addr_search - search for chunk containing specified address - * @addr: address to search for - * - * Look for chunk which might contain @addr. More specifically, it - * searchs for the chunk with the highest start address which isn't - * beyond @addr. - * - * CONTEXT: - * pcpu_lock. + * pcpu_chunk_addr_search - determine chunk containing specified address + * @addr: address for which the chunk needs to be determined. * * RETURNS: * The address of the found chunk. */ static struct pcpu_chunk *pcpu_chunk_addr_search(void *addr) { - struct rb_node *n, *parent; - struct pcpu_chunk *chunk; + void *first_start = pcpu_first_chunk->vm->addr; - /* is it in the reserved chunk? */ - if (pcpu_reserved_chunk) { - void *start = pcpu_reserved_chunk->vm->addr; - - if (addr >= start && addr < start + pcpu_reserved_chunk_limit) + /* is it in the first chunk? */ + if (addr >= first_start && addr < first_start + pcpu_chunk_size) { + /* is it in the reserved area? */ + if (addr < first_start + pcpu_reserved_chunk_limit) return pcpu_reserved_chunk; + return pcpu_first_chunk; } - /* nah... search the regular ones */ - n = *pcpu_chunk_rb_search(addr, &parent); - if (!n) { - /* no exactly matching chunk, the parent is the closest */ - n = parent; - BUG_ON(!n); - } - chunk = rb_entry(n, struct pcpu_chunk, rb_node); - - if (addr < chunk->vm->addr) { - /* the parent was the next one, look for the previous one */ - n = rb_prev(n); - BUG_ON(!n); - chunk = rb_entry(n, struct pcpu_chunk, rb_node); - } - - return chunk; -} - -/** - * pcpu_chunk_addr_insert - insert chunk into address rb tree - * @new: chunk to insert - * - * Insert @new into address rb tree. - * - * CONTEXT: - * pcpu_lock. - */ -static void pcpu_chunk_addr_insert(struct pcpu_chunk *new) -{ - struct rb_node **p, *parent; - - p = pcpu_chunk_rb_search(new->vm->addr, &parent); - BUG_ON(*p); - rb_link_node(&new->rb_node, parent, p); - rb_insert_color(&new->rb_node, &pcpu_addr_root); + return pcpu_get_page_chunk(vmalloc_to_page(addr)); } /** @@ -755,6 +709,7 @@ static int pcpu_populate_chunk(struct pcpu_chunk *chunk, int off, int size) alloc_mask, 0); if (!*pagep) goto err; + pcpu_set_page_chunk(*pagep, chunk); } } @@ -879,7 +834,6 @@ restart: spin_lock_irq(&pcpu_lock); pcpu_chunk_relocate(chunk, -1); - pcpu_chunk_addr_insert(chunk); goto restart; area_found: @@ -968,7 +922,6 @@ static void pcpu_reclaim(struct work_struct *work) if (chunk == list_first_entry(head, struct pcpu_chunk, list)) continue; - rb_erase(&chunk->rb_node, &pcpu_addr_root); list_move(&chunk->list, &todo); } @@ -1147,7 +1100,8 @@ size_t __init pcpu_setup_first_chunk(pcpu_get_page_fn_t get_page_fn, if (reserved_size) { schunk->free_size = reserved_size; - pcpu_reserved_chunk = schunk; /* not for dynamic alloc */ + pcpu_reserved_chunk = schunk; + pcpu_reserved_chunk_limit = static_size + reserved_size; } else { schunk->free_size = dyn_size; dyn_size = 0; /* dynamic area covered */ @@ -1158,8 +1112,6 @@ size_t __init pcpu_setup_first_chunk(pcpu_get_page_fn_t get_page_fn, if (schunk->free_size) schunk->map[schunk->map_used++] = schunk->free_size; - pcpu_reserved_chunk_limit = static_size + schunk->free_size; - /* init dynamic chunk if necessary */ if (dyn_size) { dchunk = alloc_bootmem(sizeof(struct pcpu_chunk)); @@ -1226,13 +1178,8 @@ size_t __init pcpu_setup_first_chunk(pcpu_get_page_fn_t get_page_fn, } /* link the first chunk in */ - if (!dchunk) { - pcpu_chunk_relocate(schunk, -1); - pcpu_chunk_addr_insert(schunk); - } else { - pcpu_chunk_relocate(dchunk, -1); - pcpu_chunk_addr_insert(dchunk); - } + pcpu_first_chunk = dchunk ?: schunk; + pcpu_chunk_relocate(pcpu_first_chunk, -1); /* we're done */ pcpu_base_addr = (void *)pcpu_chunk_addr(schunk, 0, 0); diff --git a/mm/readahead.c b/mm/readahead.c index 133b6d525513..aa1aa2345235 100644 --- a/mm/readahead.c +++ b/mm/readahead.c @@ -133,15 +133,12 @@ out: } /* - * do_page_cache_readahead actually reads a chunk of disk. It allocates all + * __do_page_cache_readahead() actually reads a chunk of disk. It allocates all * the pages first, then submits them all for I/O. This avoids the very bad * behaviour which would occur if page allocations are causing VM writeback. * We really don't want to intermingle reads and writes like that. * * Returns the number of pages requested, or the maximum amount of I/O allowed. - * - * do_page_cache_readahead() returns -1 if it encountered request queue - * congestion. */ static int __do_page_cache_readahead(struct address_space *mapping, struct file *filp, @@ -210,6 +207,7 @@ int force_page_cache_readahead(struct address_space *mapping, struct file *filp, if (unlikely(!mapping->a_ops->readpage && !mapping->a_ops->readpages)) return -EINVAL; + nr_to_read = max_sane_readahead(nr_to_read); while (nr_to_read) { int err; @@ -230,22 +228,6 @@ int force_page_cache_readahead(struct address_space *mapping, struct file *filp, return ret; } -/* - * This version skips the IO if the queue is read-congested, and will tell the - * block layer to abandon the readahead if request allocation would block. - * - * force_page_cache_readahead() will ignore queue congestion and will block on - * request queues. - */ -int do_page_cache_readahead(struct address_space *mapping, struct file *filp, - pgoff_t offset, unsigned long nr_to_read) -{ - if (bdi_read_congested(mapping->backing_dev_info)) - return -1; - - return __do_page_cache_readahead(mapping, filp, offset, nr_to_read, 0); -} - /* * Given a desired number of PAGE_CACHE_SIZE readahead pages, return a * sensible upper limit. @@ -259,7 +241,7 @@ unsigned long max_sane_readahead(unsigned long nr) /* * Submit IO for the read-ahead request in file_ra_state. */ -static unsigned long ra_submit(struct file_ra_state *ra, +unsigned long ra_submit(struct file_ra_state *ra, struct address_space *mapping, struct file *filp) { int actual; @@ -347,6 +329,59 @@ static unsigned long get_next_ra_size(struct file_ra_state *ra, * it approaches max_readhead. */ +/* + * Count contiguously cached pages from @offset-1 to @offset-@max, + * this count is a conservative estimation of + * - length of the sequential read sequence, or + * - thrashing threshold in memory tight systems + */ +static pgoff_t count_history_pages(struct address_space *mapping, + struct file_ra_state *ra, + pgoff_t offset, unsigned long max) +{ + pgoff_t head; + + rcu_read_lock(); + head = radix_tree_prev_hole(&mapping->page_tree, offset - 1, max); + rcu_read_unlock(); + + return offset - 1 - head; +} + +/* + * page cache context based read-ahead + */ +static int try_context_readahead(struct address_space *mapping, + struct file_ra_state *ra, + pgoff_t offset, + unsigned long req_size, + unsigned long max) +{ + pgoff_t size; + + size = count_history_pages(mapping, ra, offset, max); + + /* + * no history pages: + * it could be a random read + */ + if (!size) + return 0; + + /* + * starts from beginning of file: + * it is a strong indication of long-run stream (or whole-file-read) + */ + if (size >= offset) + size *= 2; + + ra->start = offset; + ra->size = get_init_ra_size(size + req_size, max); + ra->async_size = ra->size; + + return 1; +} + /* * A minimal readahead algorithm for trivial sequential/random reads. */ @@ -356,34 +391,26 @@ ondemand_readahead(struct address_space *mapping, bool hit_readahead_marker, pgoff_t offset, unsigned long req_size) { - int max = ra->ra_pages; /* max readahead pages */ - pgoff_t prev_offset; - int sequential; + unsigned long max = max_sane_readahead(ra->ra_pages); + + /* + * start of file + */ + if (!offset) + goto initial_readahead; /* * It's the expected callback offset, assume sequential access. * Ramp up sizes, and push forward the readahead window. */ - if (offset && (offset == (ra->start + ra->size - ra->async_size) || - offset == (ra->start + ra->size))) { + if ((offset == (ra->start + ra->size - ra->async_size) || + offset == (ra->start + ra->size))) { ra->start += ra->size; ra->size = get_next_ra_size(ra, max); ra->async_size = ra->size; goto readit; } - prev_offset = ra->prev_pos >> PAGE_CACHE_SHIFT; - sequential = offset - prev_offset <= 1UL || req_size > max; - - /* - * Standalone, small read. - * Read as is, and do not pollute the readahead state. - */ - if (!hit_readahead_marker && !sequential) { - return __do_page_cache_readahead(mapping, filp, - offset, req_size, 0); - } - /* * Hit a marked page without valid readahead state. * E.g. interleaved reads. @@ -394,7 +421,7 @@ ondemand_readahead(struct address_space *mapping, pgoff_t start; rcu_read_lock(); - start = radix_tree_next_hole(&mapping->page_tree, offset,max+1); + start = radix_tree_next_hole(&mapping->page_tree, offset+1,max); rcu_read_unlock(); if (!start || start - offset > max) @@ -402,23 +429,53 @@ ondemand_readahead(struct address_space *mapping, ra->start = start; ra->size = start - offset; /* old async_size */ + ra->size += req_size; ra->size = get_next_ra_size(ra, max); ra->async_size = ra->size; goto readit; } /* - * It may be one of - * - first read on start of file - * - sequential cache miss - * - oversize random read - * Start readahead for it. + * oversize read */ + if (req_size > max) + goto initial_readahead; + + /* + * sequential cache miss + */ + if (offset - (ra->prev_pos >> PAGE_CACHE_SHIFT) <= 1UL) + goto initial_readahead; + + /* + * Query the page cache and look for the traces(cached history pages) + * that a sequential stream would leave behind. + */ + if (try_context_readahead(mapping, ra, offset, req_size, max)) + goto readit; + + /* + * standalone, small random read + * Read as is, and do not pollute the readahead state. + */ + return __do_page_cache_readahead(mapping, filp, offset, req_size, 0); + +initial_readahead: ra->start = offset; ra->size = get_init_ra_size(req_size, max); ra->async_size = ra->size > req_size ? ra->size - req_size : ra->size; readit: + /* + * Will this read hit the readahead marker made by itself? + * If so, trigger the readahead marker hit now, and merge + * the resulted next readahead window into the current one. + */ + if (offset == ra->start && ra->size == ra->async_size) { + ra->async_size = get_next_ra_size(ra, max); + ra->size += ra->async_size; + } + return ra_submit(ra, mapping, filp); } diff --git a/mm/rmap.c b/mm/rmap.c index 23122af32611..836c6c63e1f2 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -333,7 +333,9 @@ static int page_mapped_in_vma(struct page *page, struct vm_area_struct *vma) * repeatedly from either page_referenced_anon or page_referenced_file. */ static int page_referenced_one(struct page *page, - struct vm_area_struct *vma, unsigned int *mapcount) + struct vm_area_struct *vma, + unsigned int *mapcount, + unsigned long *vm_flags) { struct mm_struct *mm = vma->vm_mm; unsigned long address; @@ -381,11 +383,14 @@ out_unmap: (*mapcount)--; pte_unmap_unlock(pte, ptl); out: + if (referenced) + *vm_flags |= vma->vm_flags; return referenced; } static int page_referenced_anon(struct page *page, - struct mem_cgroup *mem_cont) + struct mem_cgroup *mem_cont, + unsigned long *vm_flags) { unsigned int mapcount; struct anon_vma *anon_vma; @@ -405,7 +410,8 @@ static int page_referenced_anon(struct page *page, */ if (mem_cont && !mm_match_cgroup(vma->vm_mm, mem_cont)) continue; - referenced += page_referenced_one(page, vma, &mapcount); + referenced += page_referenced_one(page, vma, + &mapcount, vm_flags); if (!mapcount) break; } @@ -418,6 +424,7 @@ static int page_referenced_anon(struct page *page, * page_referenced_file - referenced check for object-based rmap * @page: the page we're checking references on. * @mem_cont: target memory controller + * @vm_flags: collect encountered vma->vm_flags who actually referenced the page * * For an object-based mapped page, find all the places it is mapped and * check/clear the referenced flag. This is done by following the page->mapping @@ -427,7 +434,8 @@ static int page_referenced_anon(struct page *page, * This function is only called from page_referenced for object-based pages. */ static int page_referenced_file(struct page *page, - struct mem_cgroup *mem_cont) + struct mem_cgroup *mem_cont, + unsigned long *vm_flags) { unsigned int mapcount; struct address_space *mapping = page->mapping; @@ -467,7 +475,8 @@ static int page_referenced_file(struct page *page, */ if (mem_cont && !mm_match_cgroup(vma->vm_mm, mem_cont)) continue; - referenced += page_referenced_one(page, vma, &mapcount); + referenced += page_referenced_one(page, vma, + &mapcount, vm_flags); if (!mapcount) break; } @@ -481,29 +490,35 @@ static int page_referenced_file(struct page *page, * @page: the page to test * @is_locked: caller holds lock on the page * @mem_cont: target memory controller + * @vm_flags: collect encountered vma->vm_flags who actually referenced the page * * Quick test_and_clear_referenced for all mappings to a page, * returns the number of ptes which referenced the page. */ -int page_referenced(struct page *page, int is_locked, - struct mem_cgroup *mem_cont) +int page_referenced(struct page *page, + int is_locked, + struct mem_cgroup *mem_cont, + unsigned long *vm_flags) { int referenced = 0; if (TestClearPageReferenced(page)) referenced++; + *vm_flags = 0; if (page_mapped(page) && page->mapping) { if (PageAnon(page)) - referenced += page_referenced_anon(page, mem_cont); + referenced += page_referenced_anon(page, mem_cont, + vm_flags); else if (is_locked) - referenced += page_referenced_file(page, mem_cont); + referenced += page_referenced_file(page, mem_cont, + vm_flags); else if (!trylock_page(page)) referenced++; else { if (page->mapping) - referenced += - page_referenced_file(page, mem_cont); + referenced += page_referenced_file(page, + mem_cont, vm_flags); unlock_page(page); } } @@ -688,8 +703,10 @@ void page_add_new_anon_rmap(struct page *page, */ void page_add_file_rmap(struct page *page) { - if (atomic_inc_and_test(&page->_mapcount)) + if (atomic_inc_and_test(&page->_mapcount)) { __inc_zone_page_state(page, NR_FILE_MAPPED); + mem_cgroup_update_mapped_file_stat(page, 1); + } } #ifdef CONFIG_DEBUG_VM @@ -738,6 +755,7 @@ void page_remove_rmap(struct page *page) mem_cgroup_uncharge_page(page); __dec_zone_page_state(page, PageAnon(page) ? NR_ANON_PAGES : NR_FILE_MAPPED); + mem_cgroup_update_mapped_file_stat(page, -1); /* * It would be tidy to reset the PageAnon mapping here, * but that might overwrite a racing page_add_anon_rmap @@ -1202,7 +1220,6 @@ int try_to_unmap(struct page *page, int migration) return ret; } -#ifdef CONFIG_UNEVICTABLE_LRU /** * try_to_munlock - try to munlock a page * @page: the page to be munlocked @@ -1226,4 +1243,4 @@ int try_to_munlock(struct page *page) else return try_to_unmap_file(page, 1, 0); } -#endif + diff --git a/mm/shmem.c b/mm/shmem.c index b25f95ce3db7..d713239ce2ce 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -1097,7 +1097,7 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc) shmem_swp_unmap(entry); unlock: spin_unlock(&info->lock); - swap_free(swap); + swapcache_free(swap, NULL); redirty: set_page_dirty(page); if (wbc->for_reclaim) @@ -1558,6 +1558,7 @@ static struct inode *shmem_get_inode(struct super_block *sb, int mode, spin_lock_init(&info->lock); info->flags = flags & VM_NORESERVE; INIT_LIST_HEAD(&info->swaplist); + cache_no_acl(inode); switch (mode & S_IFMT) { default: @@ -2388,7 +2389,6 @@ static void shmem_destroy_inode(struct inode *inode) /* only struct inode is valid if it's an inline symlink */ mpol_free_shared_policy(&SHMEM_I(inode)->policy); } - shmem_acl_destroy_inode(inode); kmem_cache_free(shmem_inode_cachep, SHMEM_I(inode)); } @@ -2397,10 +2397,6 @@ static void init_once(void *foo) struct shmem_inode_info *p = (struct shmem_inode_info *) foo; inode_init_once(&p->vfs_inode); -#ifdef CONFIG_TMPFS_POSIX_ACL - p->i_acl = NULL; - p->i_default_acl = NULL; -#endif } static int init_inodecache(void) @@ -2612,7 +2608,7 @@ int shmem_unuse(swp_entry_t entry, struct page *page) * @size: size to be set for the file * @flags: VM_NORESERVE suppresses pre-accounting of the entire object size */ -struct file *shmem_file_setup(char *name, loff_t size, unsigned long flags) +struct file *shmem_file_setup(const char *name, loff_t size, unsigned long flags) { int error; struct file *file; @@ -2659,6 +2655,7 @@ struct file *shmem_file_setup(char *name, loff_t size, unsigned long flags) if (error) goto close_file; #endif + ima_counts_get(file); return file; close_file: @@ -2684,7 +2681,6 @@ int shmem_zero_setup(struct vm_area_struct *vma) if (IS_ERR(file)) return PTR_ERR(file); - ima_shm_check(file); if (vma->vm_file) fput(vma->vm_file); vma->vm_file = file; diff --git a/mm/shmem_acl.c b/mm/shmem_acl.c index 8e5aadd7dcd6..606a8e757a42 100644 --- a/mm/shmem_acl.c +++ b/mm/shmem_acl.c @@ -22,11 +22,11 @@ shmem_get_acl(struct inode *inode, int type) spin_lock(&inode->i_lock); switch(type) { case ACL_TYPE_ACCESS: - acl = posix_acl_dup(SHMEM_I(inode)->i_acl); + acl = posix_acl_dup(inode->i_acl); break; case ACL_TYPE_DEFAULT: - acl = posix_acl_dup(SHMEM_I(inode)->i_default_acl); + acl = posix_acl_dup(inode->i_default_acl); break; } spin_unlock(&inode->i_lock); @@ -45,13 +45,13 @@ shmem_set_acl(struct inode *inode, int type, struct posix_acl *acl) spin_lock(&inode->i_lock); switch(type) { case ACL_TYPE_ACCESS: - free = SHMEM_I(inode)->i_acl; - SHMEM_I(inode)->i_acl = posix_acl_dup(acl); + free = inode->i_acl; + inode->i_acl = posix_acl_dup(acl); break; case ACL_TYPE_DEFAULT: - free = SHMEM_I(inode)->i_default_acl; - SHMEM_I(inode)->i_default_acl = posix_acl_dup(acl); + free = inode->i_default_acl; + inode->i_default_acl = posix_acl_dup(acl); break; } spin_unlock(&inode->i_lock); @@ -154,23 +154,6 @@ shmem_acl_init(struct inode *inode, struct inode *dir) return generic_acl_init(inode, dir, &shmem_acl_ops); } -/** - * shmem_acl_destroy_inode - destroy acls hanging off the in-memory inode - * - * This is done before destroying the actual inode. - */ - -void -shmem_acl_destroy_inode(struct inode *inode) -{ - if (SHMEM_I(inode)->i_acl) - posix_acl_release(SHMEM_I(inode)->i_acl); - SHMEM_I(inode)->i_acl = NULL; - if (SHMEM_I(inode)->i_default_acl) - posix_acl_release(SHMEM_I(inode)->i_default_acl); - SHMEM_I(inode)->i_default_acl = NULL; -} - /** * shmem_check_acl - check_acl() callback for generic_permission() */ diff --git a/mm/slab.c b/mm/slab.c index 9a90b00d2f91..e74a16e4ced6 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -102,17 +102,19 @@ #include #include #include -#include +#include #include #include #include #include +#include #include #include #include #include #include #include +#include #include #include @@ -178,13 +180,13 @@ SLAB_STORE_USER | \ SLAB_RECLAIM_ACCOUNT | SLAB_PANIC | \ SLAB_DESTROY_BY_RCU | SLAB_MEM_SPREAD | \ - SLAB_DEBUG_OBJECTS) + SLAB_DEBUG_OBJECTS | SLAB_NOLEAKTRACE | SLAB_NOTRACK) #else # define CREATE_MASK (SLAB_HWCACHE_ALIGN | \ SLAB_CACHE_DMA | \ SLAB_RECLAIM_ACCOUNT | SLAB_PANIC | \ SLAB_DESTROY_BY_RCU | SLAB_MEM_SPREAD | \ - SLAB_DEBUG_OBJECTS) + SLAB_DEBUG_OBJECTS | SLAB_NOLEAKTRACE | SLAB_NOTRACK) #endif /* @@ -315,7 +317,7 @@ static int drain_freelist(struct kmem_cache *cache, struct kmem_list3 *l3, int tofree); static void free_block(struct kmem_cache *cachep, void **objpp, int len, int node); -static int enable_cpucache(struct kmem_cache *cachep); +static int enable_cpucache(struct kmem_cache *cachep, gfp_t gfp); static void cache_reap(struct work_struct *unused); /* @@ -373,87 +375,6 @@ static void kmem_list3_init(struct kmem_list3 *parent) MAKE_LIST((cachep), (&(ptr)->slabs_free), slabs_free, nodeid); \ } while (0) -/* - * struct kmem_cache - * - * manages a cache. - */ - -struct kmem_cache { -/* 1) per-cpu data, touched during every alloc/free */ - struct array_cache *array[NR_CPUS]; -/* 2) Cache tunables. Protected by cache_chain_mutex */ - unsigned int batchcount; - unsigned int limit; - unsigned int shared; - - unsigned int buffer_size; - u32 reciprocal_buffer_size; -/* 3) touched by every alloc & free from the backend */ - - unsigned int flags; /* constant flags */ - unsigned int num; /* # of objs per slab */ - -/* 4) cache_grow/shrink */ - /* order of pgs per slab (2^n) */ - unsigned int gfporder; - - /* force GFP flags, e.g. GFP_DMA */ - gfp_t gfpflags; - - size_t colour; /* cache colouring range */ - unsigned int colour_off; /* colour offset */ - struct kmem_cache *slabp_cache; - unsigned int slab_size; - unsigned int dflags; /* dynamic flags */ - - /* constructor func */ - void (*ctor)(void *obj); - -/* 5) cache creation/removal */ - const char *name; - struct list_head next; - -/* 6) statistics */ -#if STATS - unsigned long num_active; - unsigned long num_allocations; - unsigned long high_mark; - unsigned long grown; - unsigned long reaped; - unsigned long errors; - unsigned long max_freeable; - unsigned long node_allocs; - unsigned long node_frees; - unsigned long node_overflow; - atomic_t allochit; - atomic_t allocmiss; - atomic_t freehit; - atomic_t freemiss; -#endif -#if DEBUG - /* - * If debugging is enabled, then the allocator can add additional - * fields and/or padding to every object. buffer_size contains the total - * object size including these internal fields, the following two - * variables contain the offset to the user object and its size. - */ - int obj_offset; - int obj_size; -#endif - /* - * We put nodelists[] at the end of kmem_cache, because we want to size - * this array to nr_node_ids slots instead of MAX_NUMNODES - * (see kmem_cache_init()) - * We still use [MAX_NUMNODES] and not [1] or [0] because cache_cache - * is statically defined, so we reserve the max number of nodes. - */ - struct kmem_list3 *nodelists[MAX_NUMNODES]; - /* - * Do not add fields after nodelists[] - */ -}; - #define CFLGS_OFF_SLAB (0x80000000UL) #define OFF_SLAB(x) ((x)->flags & CFLGS_OFF_SLAB) @@ -752,6 +673,7 @@ static enum { NONE, PARTIAL_AC, PARTIAL_L3, + EARLY, FULL } g_cpucache_up; @@ -760,7 +682,7 @@ static enum { */ int slab_is_available(void) { - return g_cpucache_up == FULL; + return g_cpucache_up >= EARLY; } static DEFINE_PER_CPU(struct delayed_work, reap_work); @@ -890,7 +812,6 @@ static void __slab_error(const char *function, struct kmem_cache *cachep, */ static int use_alien_caches __read_mostly = 1; -static int numa_platform __read_mostly = 1; static int __init noaliencache_setup(char *s) { use_alien_caches = 0; @@ -958,12 +879,20 @@ static void __cpuinit start_cpu_timer(int cpu) } static struct array_cache *alloc_arraycache(int node, int entries, - int batchcount) + int batchcount, gfp_t gfp) { int memsize = sizeof(void *) * entries + sizeof(struct array_cache); struct array_cache *nc = NULL; - nc = kmalloc_node(memsize, GFP_KERNEL, node); + nc = kmalloc_node(memsize, gfp, node); + /* + * The array_cache structures contain pointers to free object. + * However, when such objects are allocated or transfered to another + * cache the pointers are not cleared and they could be counted as + * valid references during a kmemleak scan. Therefore, kmemleak must + * not scan such objects. + */ + kmemleak_no_scan(nc); if (nc) { nc->avail = 0; nc->limit = entries; @@ -1003,7 +932,7 @@ static int transfer_objects(struct array_cache *to, #define drain_alien_cache(cachep, alien) do { } while (0) #define reap_alien(cachep, l3) do { } while (0) -static inline struct array_cache **alloc_alien_cache(int node, int limit) +static inline struct array_cache **alloc_alien_cache(int node, int limit, gfp_t gfp) { return (struct array_cache **)BAD_ALIEN_MAGIC; } @@ -1034,7 +963,7 @@ static inline void *____cache_alloc_node(struct kmem_cache *cachep, static void *____cache_alloc_node(struct kmem_cache *, gfp_t, int); static void *alternate_node_alloc(struct kmem_cache *, gfp_t); -static struct array_cache **alloc_alien_cache(int node, int limit) +static struct array_cache **alloc_alien_cache(int node, int limit, gfp_t gfp) { struct array_cache **ac_ptr; int memsize = sizeof(void *) * nr_node_ids; @@ -1042,14 +971,14 @@ static struct array_cache **alloc_alien_cache(int node, int limit) if (limit > 1) limit = 12; - ac_ptr = kmalloc_node(memsize, GFP_KERNEL, node); + ac_ptr = kmalloc_node(memsize, gfp, node); if (ac_ptr) { for_each_node(i) { if (i == node || !node_online(i)) { ac_ptr[i] = NULL; continue; } - ac_ptr[i] = alloc_arraycache(node, limit, 0xbaadf00d); + ac_ptr[i] = alloc_arraycache(node, limit, 0xbaadf00d, gfp); if (!ac_ptr[i]) { for (i--; i >= 0; i--) kfree(ac_ptr[i]); @@ -1282,20 +1211,20 @@ static int __cpuinit cpuup_prepare(long cpu) struct array_cache **alien = NULL; nc = alloc_arraycache(node, cachep->limit, - cachep->batchcount); + cachep->batchcount, GFP_KERNEL); if (!nc) goto bad; if (cachep->shared) { shared = alloc_arraycache(node, cachep->shared * cachep->batchcount, - 0xbaadf00d); + 0xbaadf00d, GFP_KERNEL); if (!shared) { kfree(nc); goto bad; } } if (use_alien_caches) { - alien = alloc_alien_cache(node, cachep->limit); + alien = alloc_alien_cache(node, cachep->limit, GFP_KERNEL); if (!alien) { kfree(shared); kfree(nc); @@ -1399,10 +1328,9 @@ static void init_list(struct kmem_cache *cachep, struct kmem_list3 *list, { struct kmem_list3 *ptr; - ptr = kmalloc_node(sizeof(struct kmem_list3), GFP_KERNEL, nodeid); + ptr = kmalloc_node(sizeof(struct kmem_list3), GFP_NOWAIT, nodeid); BUG_ON(!ptr); - local_irq_disable(); memcpy(ptr, list, sizeof(struct kmem_list3)); /* * Do not assume that spinlocks can be initialized via memcpy: @@ -1411,7 +1339,6 @@ static void init_list(struct kmem_cache *cachep, struct kmem_list3 *list, MAKE_ALL_LISTS(cachep, ptr, nodeid); cachep->nodelists[nodeid] = ptr; - local_irq_enable(); } /* @@ -1443,10 +1370,8 @@ void __init kmem_cache_init(void) int order; int node; - if (num_possible_nodes() == 1) { + if (num_possible_nodes() == 1) use_alien_caches = 0; - numa_platform = 0; - } for (i = 0; i < NUM_INIT_LISTS; i++) { kmem_list3_init(&initkmem_list3[i]); @@ -1575,9 +1500,8 @@ void __init kmem_cache_init(void) { struct array_cache *ptr; - ptr = kmalloc(sizeof(struct arraycache_init), GFP_KERNEL); + ptr = kmalloc(sizeof(struct arraycache_init), GFP_NOWAIT); - local_irq_disable(); BUG_ON(cpu_cache_get(&cache_cache) != &initarray_cache.cache); memcpy(ptr, cpu_cache_get(&cache_cache), sizeof(struct arraycache_init)); @@ -1587,11 +1511,9 @@ void __init kmem_cache_init(void) spin_lock_init(&ptr->lock); cache_cache.array[smp_processor_id()] = ptr; - local_irq_enable(); - ptr = kmalloc(sizeof(struct arraycache_init), GFP_KERNEL); + ptr = kmalloc(sizeof(struct arraycache_init), GFP_NOWAIT); - local_irq_disable(); BUG_ON(cpu_cache_get(malloc_sizes[INDEX_AC].cs_cachep) != &initarray_generic.cache); memcpy(ptr, cpu_cache_get(malloc_sizes[INDEX_AC].cs_cachep), @@ -1603,7 +1525,6 @@ void __init kmem_cache_init(void) malloc_sizes[INDEX_AC].cs_cachep->array[smp_processor_id()] = ptr; - local_irq_enable(); } /* 5) Replace the bootstrap kmem_list3's */ { @@ -1622,19 +1543,22 @@ void __init kmem_cache_init(void) } } - /* 6) resize the head arrays to their final sizes */ - { - struct kmem_cache *cachep; - mutex_lock(&cache_chain_mutex); - list_for_each_entry(cachep, &cache_chain, next) - if (enable_cpucache(cachep)) - BUG(); - mutex_unlock(&cache_chain_mutex); - } + g_cpucache_up = EARLY; /* Annotate slab for lockdep -- annotate the malloc caches */ init_lock_keys(); +} +void __init kmem_cache_init_late(void) +{ + struct kmem_cache *cachep; + + /* 6) resize the head arrays to their final sizes */ + mutex_lock(&cache_chain_mutex); + list_for_each_entry(cachep, &cache_chain, next) + if (enable_cpucache(cachep, GFP_NOWAIT)) + BUG(); + mutex_unlock(&cache_chain_mutex); /* Done! */ g_cpucache_up = FULL; @@ -1689,7 +1613,7 @@ static void *kmem_getpages(struct kmem_cache *cachep, gfp_t flags, int nodeid) if (cachep->flags & SLAB_RECLAIM_ACCOUNT) flags |= __GFP_RECLAIMABLE; - page = alloc_pages_node(nodeid, flags, cachep->gfporder); + page = alloc_pages_exact_node(nodeid, flags | __GFP_NOTRACK, cachep->gfporder); if (!page) return NULL; @@ -1702,6 +1626,16 @@ static void *kmem_getpages(struct kmem_cache *cachep, gfp_t flags, int nodeid) NR_SLAB_UNRECLAIMABLE, nr_pages); for (i = 0; i < nr_pages; i++) __SetPageSlab(page + i); + + if (kmemcheck_enabled && !(cachep->flags & SLAB_NOTRACK)) { + kmemcheck_alloc_shadow(page, cachep->gfporder, flags, nodeid); + + if (cachep->ctor) + kmemcheck_mark_uninitialized_pages(page, nr_pages); + else + kmemcheck_mark_unallocated_pages(page, nr_pages); + } + return page_address(page); } @@ -1714,6 +1648,8 @@ static void kmem_freepages(struct kmem_cache *cachep, void *addr) struct page *page = virt_to_page(addr); const unsigned long nr_freed = i; + kmemcheck_free_shadow(page, cachep->gfporder); + if (cachep->flags & SLAB_RECLAIM_ACCOUNT) sub_zone_page_state(page_zone(page), NR_SLAB_RECLAIMABLE, nr_freed); @@ -2064,10 +2000,10 @@ static size_t calculate_slab_order(struct kmem_cache *cachep, return left_over; } -static int __init_refok setup_cpu_cache(struct kmem_cache *cachep) +static int __init_refok setup_cpu_cache(struct kmem_cache *cachep, gfp_t gfp) { if (g_cpucache_up == FULL) - return enable_cpucache(cachep); + return enable_cpucache(cachep, gfp); if (g_cpucache_up == NONE) { /* @@ -2089,7 +2025,7 @@ static int __init_refok setup_cpu_cache(struct kmem_cache *cachep) g_cpucache_up = PARTIAL_AC; } else { cachep->array[smp_processor_id()] = - kmalloc(sizeof(struct arraycache_init), GFP_KERNEL); + kmalloc(sizeof(struct arraycache_init), gfp); if (g_cpucache_up == PARTIAL_AC) { set_up_list3s(cachep, SIZE_L3); @@ -2099,7 +2035,7 @@ static int __init_refok setup_cpu_cache(struct kmem_cache *cachep) for_each_online_node(node) { cachep->nodelists[node] = kmalloc_node(sizeof(struct kmem_list3), - GFP_KERNEL, node); + gfp, node); BUG_ON(!cachep->nodelists[node]); kmem_list3_init(cachep->nodelists[node]); } @@ -2153,6 +2089,7 @@ kmem_cache_create (const char *name, size_t size, size_t align, { size_t left_over, slab_size, ralign; struct kmem_cache *cachep = NULL, *pc; + gfp_t gfp; /* * Sanity checks... these are all serious usage bugs. @@ -2168,8 +2105,10 @@ kmem_cache_create (const char *name, size_t size, size_t align, * We use cache_chain_mutex to ensure a consistent view of * cpu_online_mask as well. Please see cpuup_callback */ - get_online_cpus(); - mutex_lock(&cache_chain_mutex); + if (slab_is_available()) { + get_online_cpus(); + mutex_lock(&cache_chain_mutex); + } list_for_each_entry(pc, &cache_chain, next) { char tmp; @@ -2278,8 +2217,13 @@ kmem_cache_create (const char *name, size_t size, size_t align, */ align = ralign; + if (slab_is_available()) + gfp = GFP_KERNEL; + else + gfp = GFP_NOWAIT; + /* Get cache's description obj. */ - cachep = kmem_cache_zalloc(&cache_cache, GFP_KERNEL); + cachep = kmem_cache_zalloc(&cache_cache, gfp); if (!cachep) goto oops; @@ -2353,6 +2297,15 @@ kmem_cache_create (const char *name, size_t size, size_t align, /* really off slab. No need for manual alignment */ slab_size = cachep->num * sizeof(kmem_bufctl_t) + sizeof(struct slab); + +#ifdef CONFIG_PAGE_POISONING + /* If we're going to use the generic kernel_map_pages() + * poisoning, then it's going to smash the contents of + * the redzone and userword anyhow, so switch them off. + */ + if (size % PAGE_SIZE == 0 && flags & SLAB_POISON) + flags &= ~(SLAB_RED_ZONE | SLAB_STORE_USER); +#endif } cachep->colour_off = cache_line_size(); @@ -2382,7 +2335,7 @@ kmem_cache_create (const char *name, size_t size, size_t align, cachep->ctor = ctor; cachep->name = name; - if (setup_cpu_cache(cachep)) { + if (setup_cpu_cache(cachep, gfp)) { __kmem_cache_destroy(cachep); cachep = NULL; goto oops; @@ -2394,8 +2347,10 @@ oops: if (!cachep && (flags & SLAB_PANIC)) panic("kmem_cache_create(): failed to create slab `%s'\n", name); - mutex_unlock(&cache_chain_mutex); - put_online_cpus(); + if (slab_is_available()) { + mutex_unlock(&cache_chain_mutex); + put_online_cpus(); + } return cachep; } EXPORT_SYMBOL(kmem_cache_create); @@ -2621,6 +2576,14 @@ static struct slab *alloc_slabmgmt(struct kmem_cache *cachep, void *objp, /* Slab management obj is off-slab. */ slabp = kmem_cache_alloc_node(cachep->slabp_cache, local_flags, nodeid); + /* + * If the first object in the slab is leaked (it's allocated + * but no one has a reference to it), we want to make sure + * kmemleak does not treat the ->s_mem pointer as a reference + * to the object. Otherwise we will not report the leak. + */ + kmemleak_scan_area(slabp, offsetof(struct slab, list), + sizeof(struct list_head), local_flags); if (!slabp) return NULL; } else { @@ -3141,6 +3104,12 @@ static inline void *____cache_alloc(struct kmem_cache *cachep, gfp_t flags) STATS_INC_ALLOCMISS(cachep); objp = cache_alloc_refill(cachep, flags); } + /* + * To avoid a false negative, if an object that is in one of the + * per-CPU caches is leaked, we need to make sure kmemleak doesn't + * treat the array pointers as a reference to the object. + */ + kmemleak_erase(&ac->entry[ac->avail]); return objp; } @@ -3219,7 +3188,7 @@ retry: if (local_flags & __GFP_WAIT) local_irq_enable(); kmem_flagcheck(cache, flags); - obj = kmem_getpages(cache, local_flags, -1); + obj = kmem_getpages(cache, local_flags, numa_node_id()); if (local_flags & __GFP_WAIT) local_irq_disable(); if (obj) { @@ -3327,6 +3296,8 @@ __cache_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid, unsigned long save_flags; void *ptr; + flags &= gfp_allowed_mask; + lockdep_trace_alloc(flags); if (slab_should_failslab(cachep, flags)) @@ -3360,6 +3331,11 @@ __cache_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid, out: local_irq_restore(save_flags); ptr = cache_alloc_debugcheck_after(cachep, flags, ptr, caller); + kmemleak_alloc_recursive(ptr, obj_size(cachep), 1, cachep->flags, + flags); + + if (likely(ptr)) + kmemcheck_slab_alloc(cachep, flags, ptr, obj_size(cachep)); if (unlikely((flags & __GFP_ZERO) && ptr)) memset(ptr, 0, obj_size(cachep)); @@ -3405,6 +3381,8 @@ __cache_alloc(struct kmem_cache *cachep, gfp_t flags, void *caller) unsigned long save_flags; void *objp; + flags &= gfp_allowed_mask; + lockdep_trace_alloc(flags); if (slab_should_failslab(cachep, flags)) @@ -3415,8 +3393,13 @@ __cache_alloc(struct kmem_cache *cachep, gfp_t flags, void *caller) objp = __do_cache_alloc(cachep, flags); local_irq_restore(save_flags); objp = cache_alloc_debugcheck_after(cachep, flags, objp, caller); + kmemleak_alloc_recursive(objp, obj_size(cachep), 1, cachep->flags, + flags); prefetchw(objp); + if (likely(objp)) + kmemcheck_slab_alloc(cachep, flags, objp, obj_size(cachep)); + if (unlikely((flags & __GFP_ZERO) && objp)) memset(objp, 0, obj_size(cachep)); @@ -3530,8 +3513,11 @@ static inline void __cache_free(struct kmem_cache *cachep, void *objp) struct array_cache *ac = cpu_cache_get(cachep); check_irq_off(); + kmemleak_free_recursive(objp, cachep->flags); objp = cache_free_debugcheck(cachep, objp, __builtin_return_address(0)); + kmemcheck_slab_free(cachep, objp, obj_size(cachep)); + /* * Skip calling cache_free_alien() when the platform is not numa. * This will avoid cache misses that happen while accessing slabp (which @@ -3539,7 +3525,7 @@ static inline void __cache_free(struct kmem_cache *cachep, void *objp) * variable to skip the call, which is mostly likely to be present in * the cache. */ - if (numa_platform && cache_free_alien(cachep, objp)) + if (nr_online_nodes > 1 && cache_free_alien(cachep, objp)) return; if (likely(ac->avail < ac->limit)) { @@ -3802,7 +3788,7 @@ EXPORT_SYMBOL_GPL(kmem_cache_name); /* * This initializes kmem_list3 or resizes various caches for all nodes. */ -static int alloc_kmemlist(struct kmem_cache *cachep) +static int alloc_kmemlist(struct kmem_cache *cachep, gfp_t gfp) { int node; struct kmem_list3 *l3; @@ -3812,7 +3798,7 @@ static int alloc_kmemlist(struct kmem_cache *cachep) for_each_online_node(node) { if (use_alien_caches) { - new_alien = alloc_alien_cache(node, cachep->limit); + new_alien = alloc_alien_cache(node, cachep->limit, gfp); if (!new_alien) goto fail; } @@ -3821,7 +3807,7 @@ static int alloc_kmemlist(struct kmem_cache *cachep) if (cachep->shared) { new_shared = alloc_arraycache(node, cachep->shared*cachep->batchcount, - 0xbaadf00d); + 0xbaadf00d, gfp); if (!new_shared) { free_alien_cache(new_alien); goto fail; @@ -3850,7 +3836,7 @@ static int alloc_kmemlist(struct kmem_cache *cachep) free_alien_cache(new_alien); continue; } - l3 = kmalloc_node(sizeof(struct kmem_list3), GFP_KERNEL, node); + l3 = kmalloc_node(sizeof(struct kmem_list3), gfp, node); if (!l3) { free_alien_cache(new_alien); kfree(new_shared); @@ -3906,18 +3892,18 @@ static void do_ccupdate_local(void *info) /* Always called with the cache_chain_mutex held */ static int do_tune_cpucache(struct kmem_cache *cachep, int limit, - int batchcount, int shared) + int batchcount, int shared, gfp_t gfp) { struct ccupdate_struct *new; int i; - new = kzalloc(sizeof(*new), GFP_KERNEL); + new = kzalloc(sizeof(*new), gfp); if (!new) return -ENOMEM; for_each_online_cpu(i) { new->new[i] = alloc_arraycache(cpu_to_node(i), limit, - batchcount); + batchcount, gfp); if (!new->new[i]) { for (i--; i >= 0; i--) kfree(new->new[i]); @@ -3944,11 +3930,11 @@ static int do_tune_cpucache(struct kmem_cache *cachep, int limit, kfree(ccold); } kfree(new); - return alloc_kmemlist(cachep); + return alloc_kmemlist(cachep, gfp); } /* Called with cache_chain_mutex held always */ -static int enable_cpucache(struct kmem_cache *cachep) +static int enable_cpucache(struct kmem_cache *cachep, gfp_t gfp) { int err; int limit, shared; @@ -3994,7 +3980,7 @@ static int enable_cpucache(struct kmem_cache *cachep) if (limit > 32) limit = 32; #endif - err = do_tune_cpucache(cachep, limit, (limit + 1) / 2, shared); + err = do_tune_cpucache(cachep, limit, (limit + 1) / 2, shared, gfp); if (err) printk(KERN_ERR "enable_cpucache failed for %s, error %d.\n", cachep->name, -err); @@ -4300,7 +4286,8 @@ ssize_t slabinfo_write(struct file *file, const char __user * buffer, res = 0; } else { res = do_tune_cpucache(cachep, limit, - batchcount, shared); + batchcount, shared, + GFP_KERNEL); } break; } diff --git a/mm/slob.c b/mm/slob.c index f92e66d558bd..c78742defdc6 100644 --- a/mm/slob.c +++ b/mm/slob.c @@ -46,7 +46,7 @@ * NUMA support in SLOB is fairly simplistic, pushing most of the real * logic down to the page allocator, and simply doing the node accounting * on the upper levels. In the event that a node id is explicitly - * provided, alloc_pages_node() with the specified node id is used + * provided, alloc_pages_exact_node() with the specified node id is used * instead. The common case (or when the node id isn't explicitly provided) * will default to the current node, as per numa_node_id(). * @@ -66,7 +66,8 @@ #include #include #include -#include +#include +#include #include /* @@ -132,17 +133,17 @@ static LIST_HEAD(free_slob_large); */ static inline int is_slob_page(struct slob_page *sp) { - return PageSlobPage((struct page *)sp); + return PageSlab((struct page *)sp); } static inline void set_slob_page(struct slob_page *sp) { - __SetPageSlobPage((struct page *)sp); + __SetPageSlab((struct page *)sp); } static inline void clear_slob_page(struct slob_page *sp) { - __ClearPageSlobPage((struct page *)sp); + __ClearPageSlab((struct page *)sp); } static inline struct slob_page *slob_page(const void *addr) @@ -243,7 +244,7 @@ static void *slob_new_pages(gfp_t gfp, int order, int node) #ifdef CONFIG_NUMA if (node != -1) - page = alloc_pages_node(node, gfp, order); + page = alloc_pages_exact_node(node, gfp, order); else #endif page = alloc_pages(gfp, order); @@ -509,6 +510,7 @@ void *__kmalloc_node(size_t size, gfp_t gfp, int node) size, PAGE_SIZE << order, gfp, node); } + kmemleak_alloc(ret, size, 1, gfp); return ret; } EXPORT_SYMBOL(__kmalloc_node); @@ -521,6 +523,7 @@ void kfree(const void *block) if (unlikely(ZERO_OR_NULL_PTR(block))) return; + kmemleak_free(block); sp = slob_page(block); if (is_slob_page(sp)) { @@ -584,12 +587,14 @@ struct kmem_cache *kmem_cache_create(const char *name, size_t size, } else if (flags & SLAB_PANIC) panic("Cannot create slab cache %s\n", name); + kmemleak_alloc(c, sizeof(struct kmem_cache), 1, GFP_KERNEL); return c; } EXPORT_SYMBOL(kmem_cache_create); void kmem_cache_destroy(struct kmem_cache *c) { + kmemleak_free(c); slob_free(c, sizeof(struct kmem_cache)); } EXPORT_SYMBOL(kmem_cache_destroy); @@ -613,6 +618,7 @@ void *kmem_cache_alloc_node(struct kmem_cache *c, gfp_t flags, int node) if (c->ctor) c->ctor(b); + kmemleak_alloc_recursive(b, c->size, 1, c->flags, flags); return b; } EXPORT_SYMBOL(kmem_cache_alloc_node); @@ -635,6 +641,7 @@ static void kmem_rcu_free(struct rcu_head *head) void kmem_cache_free(struct kmem_cache *c, void *b) { + kmemleak_free_recursive(b, c->flags); if (unlikely(c->flags & SLAB_DESTROY_BY_RCU)) { struct slob_rcu *slob_rcu; slob_rcu = b + (c->size - sizeof(struct slob_rcu)); diff --git a/mm/slub.c b/mm/slub.c index 65ffda5934b0..819f056b39c6 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -17,9 +17,11 @@ #include #include #include -#include +#include +#include #include #include +#include #include #include #include @@ -143,10 +145,10 @@ * Set of flags that will prevent slab merging */ #define SLUB_NEVER_MERGE (SLAB_RED_ZONE | SLAB_POISON | SLAB_STORE_USER | \ - SLAB_TRACE | SLAB_DESTROY_BY_RCU) + SLAB_TRACE | SLAB_DESTROY_BY_RCU | SLAB_NOLEAKTRACE) #define SLUB_MERGE_SAME (SLAB_DEBUG_FREE | SLAB_RECLAIM_ACCOUNT | \ - SLAB_CACHE_DMA) + SLAB_CACHE_DMA | SLAB_NOTRACK) #ifndef ARCH_KMALLOC_MINALIGN #define ARCH_KMALLOC_MINALIGN __alignof__(unsigned long long) @@ -832,6 +834,11 @@ static inline unsigned long slabs_node(struct kmem_cache *s, int node) return atomic_long_read(&n->nr_slabs); } +static inline unsigned long node_nr_slabs(struct kmem_cache_node *n) +{ + return atomic_long_read(&n->nr_slabs); +} + static inline void inc_slabs_node(struct kmem_cache *s, int node, int objects) { struct kmem_cache_node *n = get_node(s, node); @@ -1050,6 +1057,8 @@ static inline unsigned long kmem_cache_flags(unsigned long objsize, static inline unsigned long slabs_node(struct kmem_cache *s, int node) { return 0; } +static inline unsigned long node_nr_slabs(struct kmem_cache_node *n) + { return 0; } static inline void inc_slabs_node(struct kmem_cache *s, int node, int objects) {} static inline void dec_slabs_node(struct kmem_cache *s, int node, @@ -1064,6 +1073,8 @@ static inline struct page *alloc_slab_page(gfp_t flags, int node, { int order = oo_order(oo); + flags |= __GFP_NOTRACK; + if (node == -1) return alloc_pages(flags, order); else @@ -1074,11 +1085,17 @@ static struct page *allocate_slab(struct kmem_cache *s, gfp_t flags, int node) { struct page *page; struct kmem_cache_order_objects oo = s->oo; + gfp_t alloc_gfp; flags |= s->allocflags; - page = alloc_slab_page(flags | __GFP_NOWARN | __GFP_NORETRY, node, - oo); + /* + * Let the initial higher-order allocation fail under memory pressure + * so we fall-back to the minimum order allocation. + */ + alloc_gfp = (flags | __GFP_NOWARN | __GFP_NORETRY) & ~__GFP_NOFAIL; + + page = alloc_slab_page(alloc_gfp, node, oo); if (unlikely(!page)) { oo = s->min; /* @@ -1091,6 +1108,24 @@ static struct page *allocate_slab(struct kmem_cache *s, gfp_t flags, int node) stat(get_cpu_slab(s, raw_smp_processor_id()), ORDER_FALLBACK); } + + if (kmemcheck_enabled + && !(s->flags & (SLAB_NOTRACK | DEBUG_DEFAULT_FLAGS))) + { + int pages = 1 << oo_order(oo); + + kmemcheck_alloc_shadow(page, oo_order(oo), flags, node); + + /* + * Objects from caches that have a constructor don't get + * cleared when they're allocated, so we need to do it here. + */ + if (s->ctor) + kmemcheck_mark_uninitialized_pages(page, pages); + else + kmemcheck_mark_unallocated_pages(page, pages); + } + page->objects = oo_objects(oo); mod_zone_page_state(page_zone(page), (s->flags & SLAB_RECLAIM_ACCOUNT) ? @@ -1164,6 +1199,8 @@ static void __free_slab(struct kmem_cache *s, struct page *page) __ClearPageSlubDebug(page); } + kmemcheck_free_shadow(page, compound_order(page)); + mod_zone_page_state(page_zone(page), (s->flags & SLAB_RECLAIM_ACCOUNT) ? NR_SLAB_RECLAIMABLE : NR_SLAB_UNRECLAIMABLE, @@ -1484,6 +1521,65 @@ static inline int node_match(struct kmem_cache_cpu *c, int node) return 1; } +static int count_free(struct page *page) +{ + return page->objects - page->inuse; +} + +static unsigned long count_partial(struct kmem_cache_node *n, + int (*get_count)(struct page *)) +{ + unsigned long flags; + unsigned long x = 0; + struct page *page; + + spin_lock_irqsave(&n->list_lock, flags); + list_for_each_entry(page, &n->partial, lru) + x += get_count(page); + spin_unlock_irqrestore(&n->list_lock, flags); + return x; +} + +static inline unsigned long node_nr_objs(struct kmem_cache_node *n) +{ +#ifdef CONFIG_SLUB_DEBUG + return atomic_long_read(&n->total_objects); +#else + return 0; +#endif +} + +static noinline void +slab_out_of_memory(struct kmem_cache *s, gfp_t gfpflags, int nid) +{ + int node; + + printk(KERN_WARNING + "SLUB: Unable to allocate memory on node %d (gfp=0x%x)\n", + nid, gfpflags); + printk(KERN_WARNING " cache: %s, object size: %d, buffer size: %d, " + "default order: %d, min order: %d\n", s->name, s->objsize, + s->size, oo_order(s->oo), oo_order(s->min)); + + for_each_online_node(node) { + struct kmem_cache_node *n = get_node(s, node); + unsigned long nr_slabs; + unsigned long nr_objs; + unsigned long nr_free; + + if (!n) + continue; + + nr_free = count_partial(n, count_free); + nr_slabs = node_nr_slabs(n); + nr_objs = node_nr_objs(n); + + printk(KERN_WARNING + " node %d: slabs: %ld, objs: %ld, free: %ld\n", + node, nr_slabs, nr_objs, nr_free); + } +} + /* * Slow path. The lockless freelist is empty or we need to perform * debugging duties. @@ -1565,6 +1661,8 @@ new_slab: c->page = new; goto load_freelist; } + if (!(gfpflags & __GFP_NOWARN) && printk_ratelimit()) + slab_out_of_memory(s, gfpflags, node); return NULL; debug: if (!alloc_debug_processing(s, c->page, object, addr)) @@ -1594,6 +1692,8 @@ static __always_inline void *slab_alloc(struct kmem_cache *s, unsigned long flags; unsigned int objsize; + gfpflags &= gfp_allowed_mask; + lockdep_trace_alloc(gfpflags); might_sleep_if(gfpflags & __GFP_WAIT); @@ -1617,6 +1717,9 @@ static __always_inline void *slab_alloc(struct kmem_cache *s, if (unlikely((gfpflags & __GFP_ZERO) && object)) memset(object, 0, objsize); + kmemcheck_slab_alloc(s, gfpflags, object, c->objsize); + kmemleak_alloc_recursive(object, objsize, 1, s->flags, gfpflags); + return object; } @@ -1746,8 +1849,10 @@ static __always_inline void slab_free(struct kmem_cache *s, struct kmem_cache_cpu *c; unsigned long flags; + kmemleak_free_recursive(x, s->flags); local_irq_save(flags); c = get_cpu_slab(s, smp_processor_id()); + kmemcheck_slab_free(s, object, c->objsize); debug_check_no_locks_freed(object, c->objsize); if (!(s->flags & SLAB_DEBUG_OBJECTS)) debug_check_no_obj_freed(object, c->objsize); @@ -2557,13 +2662,16 @@ static struct kmem_cache *create_kmalloc_cache(struct kmem_cache *s, if (gfp_flags & SLUB_DMA) flags = SLAB_CACHE_DMA; - down_write(&slub_lock); + /* + * This function is called with IRQs disabled during early-boot on + * single CPU so there's no need to take slub_lock here. + */ if (!kmem_cache_open(s, gfp_flags, name, size, ARCH_KMALLOC_MINALIGN, flags, NULL)) goto panic; list_add(&s->list, &slab_caches); - up_write(&slub_lock); + if (sysfs_slab_add(s)) goto panic; return s; @@ -2596,6 +2704,7 @@ static noinline struct kmem_cache *dma_kmalloc_cache(int index, gfp_t flags) struct kmem_cache *s; char *text; size_t realsize; + unsigned long slabflags; s = kmalloc_caches_dma[index]; if (s) @@ -2617,9 +2726,18 @@ static noinline struct kmem_cache *dma_kmalloc_cache(int index, gfp_t flags) (unsigned int)realsize); s = kmalloc(kmem_size, flags & ~SLUB_DMA); + /* + * Must defer sysfs creation to a workqueue because we don't know + * what context we are called from. Before sysfs comes up, we don't + * need to do anything because our sysfs initcall will start by + * adding all existing slabs to sysfs. + */ + slabflags = SLAB_CACHE_DMA|SLAB_NOTRACK; + if (slab_state >= SYSFS) + slabflags |= __SYSFS_ADD_DEFERRED; + if (!s || !text || !kmem_cache_open(s, flags, text, - realsize, ARCH_KMALLOC_MINALIGN, - SLAB_CACHE_DMA|__SYSFS_ADD_DEFERRED, NULL)) { + realsize, ARCH_KMALLOC_MINALIGN, slabflags, NULL)) { kfree(s); kfree(text); goto unlock_out; @@ -2628,7 +2746,8 @@ static noinline struct kmem_cache *dma_kmalloc_cache(int index, gfp_t flags) list_add(&s->list, &slab_caches); kmalloc_caches_dma[index] = s; - schedule_work(&sysfs_add_work); + if (slab_state >= SYSFS) + schedule_work(&sysfs_add_work); unlock_out: up_write(&slub_lock); @@ -2713,9 +2832,10 @@ EXPORT_SYMBOL(__kmalloc); static void *kmalloc_large_node(size_t size, gfp_t flags, int node) { - struct page *page = alloc_pages_node(node, flags | __GFP_COMP, - get_order(size)); + struct page *page; + flags |= __GFP_COMP | __GFP_NOTRACK; + page = alloc_pages_node(node, flags, get_order(size)); if (page) return page_address(page); else @@ -3021,7 +3141,7 @@ void __init kmem_cache_init(void) * kmem_cache_open for slab_state == DOWN. */ create_kmalloc_cache(&kmalloc_caches[0], "kmem_cache_node", - sizeof(struct kmem_cache_node), GFP_KERNEL); + sizeof(struct kmem_cache_node), GFP_NOWAIT); kmalloc_caches[0].refcount = -1; caches++; @@ -3034,16 +3154,16 @@ void __init kmem_cache_init(void) /* Caches that are not of the two-to-the-power-of size */ if (KMALLOC_MIN_SIZE <= 64) { create_kmalloc_cache(&kmalloc_caches[1], - "kmalloc-96", 96, GFP_KERNEL); + "kmalloc-96", 96, GFP_NOWAIT); caches++; create_kmalloc_cache(&kmalloc_caches[2], - "kmalloc-192", 192, GFP_KERNEL); + "kmalloc-192", 192, GFP_NOWAIT); caches++; } for (i = KMALLOC_SHIFT_LOW; i < SLUB_PAGE_SHIFT; i++) { create_kmalloc_cache(&kmalloc_caches[i], - "kmalloc", 1 << i, GFP_KERNEL); + "kmalloc", 1 << i, GFP_NOWAIT); caches++; } @@ -3080,7 +3200,7 @@ void __init kmem_cache_init(void) /* Provide the correct kmalloc names now that the caches are up */ for (i = KMALLOC_SHIFT_LOW; i < SLUB_PAGE_SHIFT; i++) kmalloc_caches[i]. name = - kasprintf(GFP_KERNEL, "kmalloc-%d", 1 << i); + kasprintf(GFP_NOWAIT, "kmalloc-%d", 1 << i); #ifdef CONFIG_SMP register_cpu_notifier(&slab_notifier); @@ -3098,6 +3218,10 @@ void __init kmem_cache_init(void) nr_cpu_ids, nr_node_ids); } +void __init kmem_cache_init_late(void) +{ +} + /* * Find a mergeable slab cache */ @@ -3318,20 +3442,6 @@ void *__kmalloc_node_track_caller(size_t size, gfp_t gfpflags, } #ifdef CONFIG_SLUB_DEBUG -static unsigned long count_partial(struct kmem_cache_node *n, - int (*get_count)(struct page *)) -{ - unsigned long flags; - unsigned long x = 0; - struct page *page; - - spin_lock_irqsave(&n->list_lock, flags); - list_for_each_entry(page, &n->partial, lru) - x += get_count(page); - spin_unlock_irqrestore(&n->list_lock, flags); - return x; -} - static int count_inuse(struct page *page) { return page->inuse; @@ -3342,11 +3452,6 @@ static int count_total(struct page *page) return page->objects; } -static int count_free(struct page *page) -{ - return page->objects - page->inuse; -} - static int validate_slab(struct kmem_cache *s, struct page *page, unsigned long *map) { @@ -3715,7 +3820,7 @@ static int list_locations(struct kmem_cache *s, char *buf, to_cpumask(l->cpus)); } - if (num_online_nodes() > 1 && !nodes_empty(l->nodes) && + if (nr_online_nodes > 1 && !nodes_empty(l->nodes) && len < PAGE_SIZE - 60) { len += sprintf(buf + len, " nodes="); len += nodelist_scnprintf(buf + len, PAGE_SIZE - len - 50, @@ -4390,6 +4495,8 @@ static char *create_unique_id(struct kmem_cache *s) *p++ = 'a'; if (s->flags & SLAB_DEBUG_FREE) *p++ = 'F'; + if (!(s->flags & SLAB_NOTRACK)) + *p++ = 't'; if (p != name + 1) *p++ = '-'; p += sprintf(p, "%07d", s->size); diff --git a/mm/swap_state.c b/mm/swap_state.c index 1416e7e9e02d..42cd38eba79f 100644 --- a/mm/swap_state.c +++ b/mm/swap_state.c @@ -124,7 +124,6 @@ void __delete_from_swap_cache(struct page *page) /** * add_to_swap - allocate swap space for a page * @page: page we want to move to swap - * @gfp_mask: memory allocation flags * * Allocate swap space for the page and add the page to the * swap cache. Caller needs to hold the page lock. @@ -162,11 +161,11 @@ int add_to_swap(struct page *page) return 1; case -EEXIST: /* Raced with "speculative" read_swap_cache_async */ - swap_free(entry); + swapcache_free(entry, NULL); continue; default: /* -ENOMEM radix-tree allocation failure */ - swap_free(entry); + swapcache_free(entry, NULL); return 0; } } @@ -188,8 +187,7 @@ void delete_from_swap_cache(struct page *page) __delete_from_swap_cache(page); spin_unlock_irq(&swapper_space.tree_lock); - mem_cgroup_uncharge_swapcache(page, entry); - swap_free(entry); + swapcache_free(entry, page); page_cache_release(page); } @@ -293,7 +291,10 @@ struct page *read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask, /* * Swap entry may have been freed since our caller observed it. */ - if (!swap_duplicate(entry)) + err = swapcache_prepare(entry); + if (err == -EEXIST) /* seems racy */ + continue; + if (err) /* swp entry is obsolete ? */ break; /* @@ -312,12 +313,12 @@ struct page *read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask, * Initiate read into locked page and return. */ lru_cache_add_anon(new_page); - swap_readpage(NULL, new_page); + swap_readpage(new_page); return new_page; } ClearPageSwapBacked(new_page); __clear_page_locked(new_page); - swap_free(entry); + swapcache_free(entry, NULL); } while (err != -ENOMEM); if (new_page) diff --git a/mm/swapfile.c b/mm/swapfile.c index 312fafe0ab6e..d1ade1a48ee7 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -53,6 +53,59 @@ static struct swap_info_struct swap_info[MAX_SWAPFILES]; static DEFINE_MUTEX(swapon_mutex); +/* For reference count accounting in swap_map */ +/* enum for swap_map[] handling. internal use only */ +enum { + SWAP_MAP = 0, /* ops for reference from swap users */ + SWAP_CACHE, /* ops for reference from swap cache */ +}; + +static inline int swap_count(unsigned short ent) +{ + return ent & SWAP_COUNT_MASK; +} + +static inline bool swap_has_cache(unsigned short ent) +{ + return !!(ent & SWAP_HAS_CACHE); +} + +static inline unsigned short encode_swapmap(int count, bool has_cache) +{ + unsigned short ret = count; + + if (has_cache) + return SWAP_HAS_CACHE | ret; + return ret; +} + +/* returnes 1 if swap entry is freed */ +static int +__try_to_reclaim_swap(struct swap_info_struct *si, unsigned long offset) +{ + int type = si - swap_info; + swp_entry_t entry = swp_entry(type, offset); + struct page *page; + int ret = 0; + + page = find_get_page(&swapper_space, entry.val); + if (!page) + return 0; + /* + * This function is called from scan_swap_map() and it's called + * by vmscan.c at reclaiming pages. So, we hold a lock on a page, here. + * We have to use trylock for avoiding deadlock. This is a special + * case and you should use try_to_free_swap() with explicit lock_page() + * in usual operations. + */ + if (trylock_page(page)) { + ret = try_to_free_swap(page); + unlock_page(page); + } + page_cache_release(page); + return ret; +} + /* * We need this because the bdev->unplug_fn can sleep and we cannot * hold swap_lock while calling the unplug_fn. And swap_lock @@ -167,7 +220,8 @@ static int wait_for_discard(void *word) #define SWAPFILE_CLUSTER 256 #define LATENCY_LIMIT 256 -static inline unsigned long scan_swap_map(struct swap_info_struct *si) +static inline unsigned long scan_swap_map(struct swap_info_struct *si, + int cache) { unsigned long offset; unsigned long scan_base; @@ -273,6 +327,19 @@ checks: goto no_page; if (offset > si->highest_bit) scan_base = offset = si->lowest_bit; + + /* reuse swap entry of cache-only swap if not busy. */ + if (vm_swap_full() && si->swap_map[offset] == SWAP_HAS_CACHE) { + int swap_was_freed; + spin_unlock(&swap_lock); + swap_was_freed = __try_to_reclaim_swap(si, offset); + spin_lock(&swap_lock); + /* entry was freed successfully, try to use this again */ + if (swap_was_freed) + goto checks; + goto scan; /* check next one */ + } + if (si->swap_map[offset]) goto scan; @@ -285,7 +352,10 @@ checks: si->lowest_bit = si->max; si->highest_bit = 0; } - si->swap_map[offset] = 1; + if (cache == SWAP_CACHE) /* at usual swap-out via vmscan.c */ + si->swap_map[offset] = encode_swapmap(0, true); + else /* at suspend */ + si->swap_map[offset] = encode_swapmap(1, false); si->cluster_next = offset + 1; si->flags -= SWP_SCANNING; @@ -351,6 +421,10 @@ scan: spin_lock(&swap_lock); goto checks; } + if (vm_swap_full() && si->swap_map[offset] == SWAP_HAS_CACHE) { + spin_lock(&swap_lock); + goto checks; + } if (unlikely(--latency_ration < 0)) { cond_resched(); latency_ration = LATENCY_LIMIT; @@ -362,6 +436,10 @@ scan: spin_lock(&swap_lock); goto checks; } + if (vm_swap_full() && si->swap_map[offset] == SWAP_HAS_CACHE) { + spin_lock(&swap_lock); + goto checks; + } if (unlikely(--latency_ration < 0)) { cond_resched(); latency_ration = LATENCY_LIMIT; @@ -401,7 +479,8 @@ swp_entry_t get_swap_page(void) continue; swap_list.next = next; - offset = scan_swap_map(si); + /* This is called for allocating swap entry for cache */ + offset = scan_swap_map(si, SWAP_CACHE); if (offset) { spin_unlock(&swap_lock); return swp_entry(type, offset); @@ -415,6 +494,7 @@ noswap: return (swp_entry_t) {0}; } +/* The only caller of this function is now susupend routine */ swp_entry_t get_swap_page_of_type(int type) { struct swap_info_struct *si; @@ -424,7 +504,8 @@ swp_entry_t get_swap_page_of_type(int type) si = swap_info + type; if (si->flags & SWP_WRITEOK) { nr_swap_pages--; - offset = scan_swap_map(si); + /* This is called for allocating swap entry, not cache */ + offset = scan_swap_map(si, SWAP_MAP); if (offset) { spin_unlock(&swap_lock); return swp_entry(type, offset); @@ -471,26 +552,40 @@ out: return NULL; } -static int swap_entry_free(struct swap_info_struct *p, swp_entry_t ent) +static int swap_entry_free(struct swap_info_struct *p, + swp_entry_t ent, int cache) { unsigned long offset = swp_offset(ent); - int count = p->swap_map[offset]; + int count = swap_count(p->swap_map[offset]); + bool has_cache; - if (count < SWAP_MAP_MAX) { - count--; - p->swap_map[offset] = count; - if (!count) { - if (offset < p->lowest_bit) - p->lowest_bit = offset; - if (offset > p->highest_bit) - p->highest_bit = offset; - if (p->prio > swap_info[swap_list.next].prio) - swap_list.next = p - swap_info; - nr_swap_pages++; - p->inuse_pages--; - mem_cgroup_uncharge_swap(ent); + has_cache = swap_has_cache(p->swap_map[offset]); + + if (cache == SWAP_MAP) { /* dropping usage count of swap */ + if (count < SWAP_MAP_MAX) { + count--; + p->swap_map[offset] = encode_swapmap(count, has_cache); } + } else { /* dropping swap cache flag */ + VM_BUG_ON(!has_cache); + p->swap_map[offset] = encode_swapmap(count, false); + } + /* return code. */ + count = p->swap_map[offset]; + /* free if no reference */ + if (!count) { + if (offset < p->lowest_bit) + p->lowest_bit = offset; + if (offset > p->highest_bit) + p->highest_bit = offset; + if (p->prio > swap_info[swap_list.next].prio) + swap_list.next = p - swap_info; + nr_swap_pages++; + p->inuse_pages--; + } + if (!swap_count(count)) + mem_cgroup_uncharge_swap(ent); return count; } @@ -504,11 +599,35 @@ void swap_free(swp_entry_t entry) p = swap_info_get(entry); if (p) { - swap_entry_free(p, entry); + swap_entry_free(p, entry, SWAP_MAP); spin_unlock(&swap_lock); } } +/* + * Called after dropping swapcache to decrease refcnt to swap entries. + */ +void swapcache_free(swp_entry_t entry, struct page *page) +{ + struct swap_info_struct *p; + int ret; + + p = swap_info_get(entry); + if (p) { + ret = swap_entry_free(p, entry, SWAP_CACHE); + if (page) { + bool swapout; + if (ret) + swapout = true; /* the end of swap out */ + else + swapout = false; /* no more swap users! */ + mem_cgroup_uncharge_swapcache(page, entry, swapout); + } + spin_unlock(&swap_lock); + } + return; +} + /* * How many references to page are currently swapped out? */ @@ -521,8 +640,7 @@ static inline int page_swapcount(struct page *page) entry.val = page_private(page); p = swap_info_get(entry); if (p) { - /* Subtract the 1 for the swap cache itself */ - count = p->swap_map[swp_offset(entry)] - 1; + count = swap_count(p->swap_map[swp_offset(entry)]); spin_unlock(&swap_lock); } return count; @@ -584,7 +702,7 @@ int free_swap_and_cache(swp_entry_t entry) p = swap_info_get(entry); if (p) { - if (swap_entry_free(p, entry) == 1) { + if (swap_entry_free(p, entry, SWAP_MAP) == SWAP_HAS_CACHE) { page = find_get_page(&swapper_space, entry.val); if (page && !trylock_page(page)) { page_cache_release(page); @@ -891,7 +1009,7 @@ static unsigned int find_next_to_unuse(struct swap_info_struct *si, i = 1; } count = si->swap_map[i]; - if (count && count != SWAP_MAP_BAD) + if (count && swap_count(count) != SWAP_MAP_BAD) break; } return i; @@ -995,13 +1113,13 @@ static int try_to_unuse(unsigned int type) */ shmem = 0; swcount = *swap_map; - if (swcount > 1) { + if (swap_count(swcount)) { if (start_mm == &init_mm) shmem = shmem_unuse(entry, page); else retval = unuse_mm(start_mm, entry, page); } - if (*swap_map > 1) { + if (swap_count(*swap_map)) { int set_start_mm = (*swap_map >= swcount); struct list_head *p = &start_mm->mmlist; struct mm_struct *new_start_mm = start_mm; @@ -1011,7 +1129,7 @@ static int try_to_unuse(unsigned int type) atomic_inc(&new_start_mm->mm_users); atomic_inc(&prev_mm->mm_users); spin_lock(&mmlist_lock); - while (*swap_map > 1 && !retval && !shmem && + while (swap_count(*swap_map) && !retval && !shmem && (p = p->next) != &start_mm->mmlist) { mm = list_entry(p, struct mm_struct, mmlist); if (!atomic_inc_not_zero(&mm->mm_users)) @@ -1023,14 +1141,16 @@ static int try_to_unuse(unsigned int type) cond_resched(); swcount = *swap_map; - if (swcount <= 1) + if (!swap_count(swcount)) /* any usage ? */ ; else if (mm == &init_mm) { set_start_mm = 1; shmem = shmem_unuse(entry, page); } else retval = unuse_mm(mm, entry, page); - if (set_start_mm && *swap_map < swcount) { + + if (set_start_mm && + swap_count(*swap_map) < swcount) { mmput(new_start_mm); atomic_inc(&mm->mm_users); new_start_mm = mm; @@ -1057,21 +1177,25 @@ static int try_to_unuse(unsigned int type) } /* - * How could swap count reach 0x7fff when the maximum - * pid is 0x7fff, and there's no way to repeat a swap - * page within an mm (except in shmem, where it's the - * shared object which takes the reference count)? - * We believe SWAP_MAP_MAX cannot occur in Linux 2.4. - * + * How could swap count reach 0x7ffe ? + * There's no way to repeat a swap page within an mm + * (except in shmem, where it's the shared object which takes + * the reference count)? + * We believe SWAP_MAP_MAX cannot occur.(if occur, unsigned + * short is too small....) * If that's wrong, then we should worry more about * exit_mmap() and do_munmap() cases described above: * we might be resetting SWAP_MAP_MAX too early here. * We know "Undead"s can happen, they're okay, so don't * report them; but do report if we reset SWAP_MAP_MAX. */ - if (*swap_map == SWAP_MAP_MAX) { + /* We might release the lock_page() in unuse_mm(). */ + if (!PageSwapCache(page) || page_private(page) != entry.val) + goto retry; + + if (swap_count(*swap_map) == SWAP_MAP_MAX) { spin_lock(&swap_lock); - *swap_map = 1; + *swap_map = encode_swapmap(0, true); spin_unlock(&swap_lock); reset_overflow = 1; } @@ -1089,7 +1213,8 @@ static int try_to_unuse(unsigned int type) * pages would be incorrect if swap supported "shared * private" pages, but they are handled by tmpfs files. */ - if ((*swap_map > 1) && PageDirty(page) && PageSwapCache(page)) { + if (swap_count(*swap_map) && + PageDirty(page) && PageSwapCache(page)) { struct writeback_control wbc = { .sync_mode = WB_SYNC_NONE, }; @@ -1116,6 +1241,7 @@ static int try_to_unuse(unsigned int type) * mark page dirty so shrink_page_list will preserve it. */ SetPageDirty(page); +retry: unlock_page(page); page_cache_release(page); @@ -1942,15 +2068,23 @@ void si_swapinfo(struct sysinfo *val) * * Note: if swap_map[] reaches SWAP_MAP_MAX the entries are treated as * "permanent", but will be reclaimed by the next swapoff. + * Returns error code in following case. + * - success -> 0 + * - swp_entry is invalid -> EINVAL + * - swp_entry is migration entry -> EINVAL + * - swap-cache reference is requested but there is already one. -> EEXIST + * - swap-cache reference is requested but the entry is not used. -> ENOENT */ -int swap_duplicate(swp_entry_t entry) +static int __swap_duplicate(swp_entry_t entry, bool cache) { struct swap_info_struct * p; unsigned long offset, type; - int result = 0; + int result = -EINVAL; + int count; + bool has_cache; if (is_migration_entry(entry)) - return 1; + return -EINVAL; type = swp_type(entry); if (type >= nr_swapfiles) @@ -1959,17 +2093,40 @@ int swap_duplicate(swp_entry_t entry) offset = swp_offset(entry); spin_lock(&swap_lock); - if (offset < p->max && p->swap_map[offset]) { - if (p->swap_map[offset] < SWAP_MAP_MAX - 1) { - p->swap_map[offset]++; - result = 1; - } else if (p->swap_map[offset] <= SWAP_MAP_MAX) { + + if (unlikely(offset >= p->max)) + goto unlock_out; + + count = swap_count(p->swap_map[offset]); + has_cache = swap_has_cache(p->swap_map[offset]); + + if (cache == SWAP_CACHE) { /* called for swapcache/swapin-readahead */ + + /* set SWAP_HAS_CACHE if there is no cache and entry is used */ + if (!has_cache && count) { + p->swap_map[offset] = encode_swapmap(count, true); + result = 0; + } else if (has_cache) /* someone added cache */ + result = -EEXIST; + else if (!count) /* no users */ + result = -ENOENT; + + } else if (count || has_cache) { + if (count < SWAP_MAP_MAX - 1) { + p->swap_map[offset] = encode_swapmap(count + 1, + has_cache); + result = 0; + } else if (count <= SWAP_MAP_MAX) { if (swap_overflow++ < 5) - printk(KERN_WARNING "swap_dup: swap entry overflow\n"); - p->swap_map[offset] = SWAP_MAP_MAX; - result = 1; + printk(KERN_WARNING + "swap_dup: swap entry overflow\n"); + p->swap_map[offset] = encode_swapmap(SWAP_MAP_MAX, + has_cache); + result = 0; } - } + } else + result = -ENOENT; /* unused swap entry */ +unlock_out: spin_unlock(&swap_lock); out: return result; @@ -1978,6 +2135,27 @@ bad_file: printk(KERN_ERR "swap_dup: %s%08lx\n", Bad_file, entry.val); goto out; } +/* + * increase reference count of swap entry by 1. + */ +void swap_duplicate(swp_entry_t entry) +{ + __swap_duplicate(entry, SWAP_MAP); +} + +/* + * @entry: swap entry for which we allocate swap cache. + * + * Called when allocating swap cache for exising swap entry, + * This can return error codes. Returns 0 at success. + * -EBUSY means there is a swap cache. + * Note: return code is different from swap_duplicate(). + */ +int swapcache_prepare(swp_entry_t entry) +{ + return __swap_duplicate(entry, SWAP_CACHE); +} + struct swap_info_struct * get_swap_info_struct(unsigned type) @@ -2016,7 +2194,7 @@ int valid_swaphandles(swp_entry_t entry, unsigned long *offset) /* Don't read in free or bad pages */ if (!si->swap_map[toff]) break; - if (si->swap_map[toff] == SWAP_MAP_BAD) + if (swap_count(si->swap_map[toff]) == SWAP_MAP_BAD) break; } /* Count contiguous allocated slots below our target */ @@ -2024,7 +2202,7 @@ int valid_swaphandles(swp_entry_t entry, unsigned long *offset) /* Don't read in free or bad pages */ if (!si->swap_map[toff]) break; - if (si->swap_map[toff] == SWAP_MAP_BAD) + if (swap_count(si->swap_map[toff]) == SWAP_MAP_BAD) break; } spin_unlock(&swap_lock); diff --git a/mm/thrash.c b/mm/thrash.c index c4c5205a9c35..2372d4ed5dd8 100644 --- a/mm/thrash.c +++ b/mm/thrash.c @@ -26,47 +26,45 @@ static DEFINE_SPINLOCK(swap_token_lock); struct mm_struct *swap_token_mm; static unsigned int global_faults; -void grab_swap_token(void) +void grab_swap_token(struct mm_struct *mm) { int current_interval; global_faults++; - current_interval = global_faults - current->mm->faultstamp; + current_interval = global_faults - mm->faultstamp; if (!spin_trylock(&swap_token_lock)) return; /* First come first served */ if (swap_token_mm == NULL) { - current->mm->token_priority = current->mm->token_priority + 2; - swap_token_mm = current->mm; + mm->token_priority = mm->token_priority + 2; + swap_token_mm = mm; goto out; } - if (current->mm != swap_token_mm) { - if (current_interval < current->mm->last_interval) - current->mm->token_priority++; + if (mm != swap_token_mm) { + if (current_interval < mm->last_interval) + mm->token_priority++; else { - if (likely(current->mm->token_priority > 0)) - current->mm->token_priority--; + if (likely(mm->token_priority > 0)) + mm->token_priority--; } /* Check if we deserve the token */ - if (current->mm->token_priority > - swap_token_mm->token_priority) { - current->mm->token_priority += 2; - swap_token_mm = current->mm; + if (mm->token_priority > swap_token_mm->token_priority) { + mm->token_priority += 2; + swap_token_mm = mm; } } else { /* Token holder came in again! */ - current->mm->token_priority += 2; + mm->token_priority += 2; } out: - current->mm->faultstamp = global_faults; - current->mm->last_interval = current_interval; + mm->faultstamp = global_faults; + mm->last_interval = current_interval; spin_unlock(&swap_token_lock); -return; } /* Called on process exit. */ diff --git a/mm/truncate.c b/mm/truncate.c index 12e1579f9165..ccc3ecf7cb98 100644 --- a/mm/truncate.c +++ b/mm/truncate.c @@ -267,8 +267,21 @@ void truncate_inode_pages(struct address_space *mapping, loff_t lstart) } EXPORT_SYMBOL(truncate_inode_pages); -unsigned long __invalidate_mapping_pages(struct address_space *mapping, - pgoff_t start, pgoff_t end, bool be_atomic) +/** + * invalidate_mapping_pages - Invalidate all the unlocked pages of one inode + * @mapping: the address_space which holds the pages to invalidate + * @start: the offset 'from' which to invalidate + * @end: the offset 'to' which to invalidate (inclusive) + * + * This function only removes the unlocked pages, if you want to + * remove all the pages of one inode, you must call truncate_inode_pages. + * + * invalidate_mapping_pages() will not block on IO activity. It will not + * invalidate pages which are dirty, locked, under writeback or mapped into + * pagetables. + */ +unsigned long invalidate_mapping_pages(struct address_space *mapping, + pgoff_t start, pgoff_t end) { struct pagevec pvec; pgoff_t next = start; @@ -309,30 +322,10 @@ unlock: break; } pagevec_release(&pvec); - if (likely(!be_atomic)) - cond_resched(); + cond_resched(); } return ret; } - -/** - * invalidate_mapping_pages - Invalidate all the unlocked pages of one inode - * @mapping: the address_space which holds the pages to invalidate - * @start: the offset 'from' which to invalidate - * @end: the offset 'to' which to invalidate (inclusive) - * - * This function only removes the unlocked pages, if you want to - * remove all the pages of one inode, you must call truncate_inode_pages. - * - * invalidate_mapping_pages() will not block on IO activity. It will not - * invalidate pages which are dirty, locked, under writeback or mapped into - * pagetables. - */ -unsigned long invalidate_mapping_pages(struct address_space *mapping, - pgoff_t start, pgoff_t end) -{ - return __invalidate_mapping_pages(mapping, start, end, false); -} EXPORT_SYMBOL(invalidate_mapping_pages); /* diff --git a/mm/util.c b/mm/util.c index 55bef160b9f1..7c35ad95f927 100644 --- a/mm/util.c +++ b/mm/util.c @@ -4,9 +4,11 @@ #include #include #include -#include #include +#define CREATE_TRACE_POINTS +#include + /** * kstrdup - allocate space for and copy an existing string * @s: the string to duplicate @@ -166,6 +168,10 @@ EXPORT_SYMBOL(krealloc); * * The memory of the object @p points to is zeroed before freed. * If @p is %NULL, kzfree() does nothing. + * + * Note: this function zeroes the whole allocated buffer which can be a good + * deal bigger than the requested buffer size passed to kmalloc(). So be + * careful when using this function in performance sensitive code. */ void kzfree(const void *p) { @@ -231,13 +237,21 @@ void arch_pick_mmap_layout(struct mm_struct *mm) * @pages: array that receives pointers to the pages pinned. * Should be at least nr_pages long. * - * Attempt to pin user pages in memory without taking mm->mmap_sem. - * If not successful, it will fall back to taking the lock and - * calling get_user_pages(). - * * Returns number of pages pinned. This may be fewer than the number * requested. If nr_pages is 0 or negative, returns 0. If no pages * were pinned, returns -errno. + * + * get_user_pages_fast provides equivalent functionality to get_user_pages, + * operating on current and current->mm, with force=0 and vma=NULL. However + * unlike get_user_pages, it must be called without mmap_sem held. + * + * get_user_pages_fast may take mmap_sem and page table locks, so no + * assumptions can be made about lack of locking. get_user_pages_fast is to be + * implemented in a way that is advantageous (vs get_user_pages()) when the + * user memory area is already faulted in and present in ptes. However if the + * pages have to be faulted in, it may turn out to be slightly slower so + * callers need to carefully consider what to use. On many architectures, + * get_user_pages_fast simply falls back to get_user_pages. */ int __attribute__((weak)) get_user_pages_fast(unsigned long start, int nr_pages, int write, struct page **pages) @@ -255,13 +269,6 @@ int __attribute__((weak)) get_user_pages_fast(unsigned long start, EXPORT_SYMBOL_GPL(get_user_pages_fast); /* Tracepoints definitions. */ -DEFINE_TRACE(kmalloc); -DEFINE_TRACE(kmem_cache_alloc); -DEFINE_TRACE(kmalloc_node); -DEFINE_TRACE(kmem_cache_alloc_node); -DEFINE_TRACE(kfree); -DEFINE_TRACE(kmem_cache_free); - EXPORT_TRACEPOINT_SYMBOL(kmalloc); EXPORT_TRACEPOINT_SYMBOL(kmem_cache_alloc); EXPORT_TRACEPOINT_SYMBOL(kmalloc_node); diff --git a/mm/vmalloc.c b/mm/vmalloc.c index 083716ea38c9..f8189a4b3e13 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -23,8 +23,8 @@ #include #include #include -#include #include +#include #include #include @@ -1032,7 +1032,7 @@ void __init vmalloc_init(void) /* Import existing vmlist entries. */ for (tmp = vmlist; tmp; tmp = tmp->next) { - va = alloc_bootmem(sizeof(struct vmap_area)); + va = kzalloc(sizeof(struct vmap_area), GFP_NOWAIT); va->flags = tmp->flags | VM_VM_AREA; va->va_start = (unsigned long)tmp->addr; va->va_end = va->va_start + tmp->size; @@ -1327,6 +1327,9 @@ static void __vunmap(const void *addr, int deallocate_pages) void vfree(const void *addr) { BUG_ON(in_interrupt()); + + kmemleak_free(addr); + __vunmap(addr, 1); } EXPORT_SYMBOL(vfree); @@ -1439,8 +1442,17 @@ fail: void *__vmalloc_area(struct vm_struct *area, gfp_t gfp_mask, pgprot_t prot) { - return __vmalloc_area_node(area, gfp_mask, prot, -1, - __builtin_return_address(0)); + void *addr = __vmalloc_area_node(area, gfp_mask, prot, -1, + __builtin_return_address(0)); + + /* + * A ref_count = 3 is needed because the vm_struct and vmap_area + * structures allocated in the __get_vm_area_node() function contain + * references to the virtual address of the vmalloc'ed block. + */ + kmemleak_alloc(addr, area->size - PAGE_SIZE, 3, gfp_mask); + + return addr; } /** @@ -1459,6 +1471,8 @@ static void *__vmalloc_node(unsigned long size, gfp_t gfp_mask, pgprot_t prot, int node, void *caller) { struct vm_struct *area; + void *addr; + unsigned long real_size = size; size = PAGE_ALIGN(size); if (!size || (size >> PAGE_SHIFT) > num_physpages) @@ -1470,7 +1484,16 @@ static void *__vmalloc_node(unsigned long size, gfp_t gfp_mask, pgprot_t prot, if (!area) return NULL; - return __vmalloc_area_node(area, gfp_mask, prot, node, caller); + addr = __vmalloc_area_node(area, gfp_mask, prot, node, caller); + + /* + * A ref_count = 3 is needed because the vm_struct and vmap_area + * structures allocated in the __get_vm_area_node() function contain + * references to the virtual address of the vmalloc'ed block. + */ + kmemleak_alloc(addr, real_size, 3, gfp_mask); + + return addr; } void *__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot) diff --git a/mm/vmscan.c b/mm/vmscan.c index d254306562cd..54155268dfca 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -470,8 +470,7 @@ static int __remove_mapping(struct address_space *mapping, struct page *page) swp_entry_t swap = { .val = page_private(page) }; __delete_from_swap_cache(page); spin_unlock_irq(&mapping->tree_lock); - mem_cgroup_uncharge_swapcache(page, swap); - swap_free(swap); + swapcache_free(swap, page); } else { __remove_from_page_cache(page); spin_unlock_irq(&mapping->tree_lock); @@ -514,7 +513,6 @@ int remove_mapping(struct address_space *mapping, struct page *page) * * lru_lock must not be held, interrupts must be enabled. */ -#ifdef CONFIG_UNEVICTABLE_LRU void putback_lru_page(struct page *page) { int lru; @@ -568,20 +566,6 @@ redo: put_page(page); /* drop ref from isolate */ } -#else /* CONFIG_UNEVICTABLE_LRU */ - -void putback_lru_page(struct page *page) -{ - int lru; - VM_BUG_ON(PageLRU(page)); - - lru = !!TestClearPageActive(page) + page_is_file_cache(page); - lru_cache_add_lru(page, lru); - put_page(page); -} -#endif /* CONFIG_UNEVICTABLE_LRU */ - - /* * shrink_page_list() returns the number of reclaimed pages */ @@ -593,6 +577,7 @@ static unsigned long shrink_page_list(struct list_head *page_list, struct pagevec freed_pvec; int pgactivate = 0; unsigned long nr_reclaimed = 0; + unsigned long vm_flags; cond_resched(); @@ -643,7 +628,8 @@ static unsigned long shrink_page_list(struct list_head *page_list, goto keep_locked; } - referenced = page_referenced(page, 1, sc->mem_cgroup); + referenced = page_referenced(page, 1, + sc->mem_cgroup, &vm_flags); /* In active use or really unfreeable? Activate it. */ if (sc->order <= PAGE_ALLOC_COSTLY_ORDER && referenced && page_mapping_inuse(page)) @@ -851,7 +837,6 @@ int __isolate_lru_page(struct page *page, int mode, int file) */ ClearPageLRU(page); ret = 0; - mem_cgroup_del_lru(page); } return ret; @@ -899,12 +884,14 @@ static unsigned long isolate_lru_pages(unsigned long nr_to_scan, switch (__isolate_lru_page(page, mode, file)) { case 0: list_move(&page->lru, dst); + mem_cgroup_del_lru(page); nr_taken++; break; case -EBUSY: /* else it is being freed elsewhere */ list_move(&page->lru, src); + mem_cgroup_rotate_lru_list(page, page_lru(page)); continue; default: @@ -943,18 +930,11 @@ static unsigned long isolate_lru_pages(unsigned long nr_to_scan, /* Check that we have not crossed a zone boundary. */ if (unlikely(page_zone_id(cursor_page) != zone_id)) continue; - switch (__isolate_lru_page(cursor_page, mode, file)) { - case 0: + if (__isolate_lru_page(cursor_page, mode, file) == 0) { list_move(&cursor_page->lru, dst); + mem_cgroup_del_lru(cursor_page); nr_taken++; scan++; - break; - - case -EBUSY: - /* else it is being freed elsewhere */ - list_move(&cursor_page->lru, src); - default: - break; /* ! on LRU or wrong list */ } } } @@ -1061,6 +1041,19 @@ static unsigned long shrink_inactive_list(unsigned long max_scan, unsigned long nr_scanned = 0; unsigned long nr_reclaimed = 0; struct zone_reclaim_stat *reclaim_stat = get_reclaim_stat(zone, sc); + int lumpy_reclaim = 0; + + /* + * If we need a large contiguous chunk of memory, or have + * trouble getting a small set of contiguous pages, we + * will reclaim both active and inactive pages. + * + * We use the same threshold as pageout congestion_wait below. + */ + if (sc->order > PAGE_ALLOC_COSTLY_ORDER) + lumpy_reclaim = 1; + else if (sc->order && priority < DEF_PRIORITY - 2) + lumpy_reclaim = 1; pagevec_init(&pvec, 1); @@ -1073,19 +1066,7 @@ static unsigned long shrink_inactive_list(unsigned long max_scan, unsigned long nr_freed; unsigned long nr_active; unsigned int count[NR_LRU_LISTS] = { 0, }; - int mode = ISOLATE_INACTIVE; - - /* - * If we need a large contiguous chunk of memory, or have - * trouble getting a small set of contiguous pages, we - * will reclaim both active and inactive pages. - * - * We use the same threshold as pageout congestion_wait below. - */ - if (sc->order > PAGE_ALLOC_COSTLY_ORDER) - mode = ISOLATE_BOTH; - else if (sc->order && priority < DEF_PRIORITY - 2) - mode = ISOLATE_BOTH; + int mode = lumpy_reclaim ? ISOLATE_BOTH : ISOLATE_INACTIVE; nr_taken = sc->isolate_pages(sc->swap_cluster_max, &page_list, &nr_scan, sc->order, mode, @@ -1122,7 +1103,7 @@ static unsigned long shrink_inactive_list(unsigned long max_scan, * but that should be acceptable to the caller */ if (nr_freed < nr_taken && !current_is_kswapd() && - sc->order > PAGE_ALLOC_COSTLY_ORDER) { + lumpy_reclaim) { congestion_wait(WRITE, HZ/10); /* @@ -1217,18 +1198,54 @@ static inline void note_zone_scanning_priority(struct zone *zone, int priority) * But we had to alter page->flags anyway. */ +static void move_active_pages_to_lru(struct zone *zone, + struct list_head *list, + enum lru_list lru) +{ + unsigned long pgmoved = 0; + struct pagevec pvec; + struct page *page; + + pagevec_init(&pvec, 1); + + while (!list_empty(list)) { + page = lru_to_page(list); + prefetchw_prev_lru_page(page, list, flags); + + VM_BUG_ON(PageLRU(page)); + SetPageLRU(page); + + VM_BUG_ON(!PageActive(page)); + if (!is_active_lru(lru)) + ClearPageActive(page); /* we are de-activating */ + + list_move(&page->lru, &zone->lru[lru].list); + mem_cgroup_add_lru_list(page, lru); + pgmoved++; + + if (!pagevec_add(&pvec, page) || list_empty(list)) { + spin_unlock_irq(&zone->lru_lock); + if (buffer_heads_over_limit) + pagevec_strip(&pvec); + __pagevec_release(&pvec); + spin_lock_irq(&zone->lru_lock); + } + } + __mod_zone_page_state(zone, NR_LRU_BASE + lru, pgmoved); + if (!is_active_lru(lru)) + __count_vm_events(PGDEACTIVATE, pgmoved); +} static void shrink_active_list(unsigned long nr_pages, struct zone *zone, struct scan_control *sc, int priority, int file) { unsigned long pgmoved; - int pgdeactivate = 0; unsigned long pgscanned; + unsigned long vm_flags; LIST_HEAD(l_hold); /* The pages which were snipped off */ + LIST_HEAD(l_active); LIST_HEAD(l_inactive); struct page *page; - struct pagevec pvec; - enum lru_list lru; struct zone_reclaim_stat *reclaim_stat = get_reclaim_stat(zone, sc); lru_add_drain(); @@ -1245,13 +1262,14 @@ static void shrink_active_list(unsigned long nr_pages, struct zone *zone, } reclaim_stat->recent_scanned[!!file] += pgmoved; + __count_zone_vm_events(PGREFILL, zone, pgscanned); if (file) __mod_zone_page_state(zone, NR_ACTIVE_FILE, -pgmoved); else __mod_zone_page_state(zone, NR_ACTIVE_ANON, -pgmoved); spin_unlock_irq(&zone->lru_lock); - pgmoved = 0; + pgmoved = 0; /* count referenced (mapping) mapped pages */ while (!list_empty(&l_hold)) { cond_resched(); page = lru_to_page(&l_hold); @@ -1264,58 +1282,44 @@ static void shrink_active_list(unsigned long nr_pages, struct zone *zone, /* page_referenced clears PageReferenced */ if (page_mapping_inuse(page) && - page_referenced(page, 0, sc->mem_cgroup)) + page_referenced(page, 0, sc->mem_cgroup, &vm_flags)) { pgmoved++; + /* + * Identify referenced, file-backed active pages and + * give them one more trip around the active list. So + * that executable code get better chances to stay in + * memory under moderate memory pressure. Anon pages + * are not likely to be evicted by use-once streaming + * IO, plus JVM can create lots of anon VM_EXEC pages, + * so we ignore them here. + */ + if ((vm_flags & VM_EXEC) && !PageAnon(page)) { + list_add(&page->lru, &l_active); + continue; + } + } list_add(&page->lru, &l_inactive); } /* - * Move the pages to the [file or anon] inactive list. + * Move pages back to the lru list. */ - pagevec_init(&pvec, 1); - lru = LRU_BASE + file * LRU_FILE; - spin_lock_irq(&zone->lru_lock); /* - * Count referenced pages from currently used mappings as - * rotated, even though they are moved to the inactive list. - * This helps balance scan pressure between file and anonymous - * pages in get_scan_ratio. + * Count referenced pages from currently used mappings as rotated, + * even though only some of them are actually re-activated. This + * helps balance scan pressure between file and anonymous pages in + * get_scan_ratio. */ reclaim_stat->recent_rotated[!!file] += pgmoved; - pgmoved = 0; - while (!list_empty(&l_inactive)) { - page = lru_to_page(&l_inactive); - prefetchw_prev_lru_page(page, &l_inactive, flags); - VM_BUG_ON(PageLRU(page)); - SetPageLRU(page); - VM_BUG_ON(!PageActive(page)); - ClearPageActive(page); + move_active_pages_to_lru(zone, &l_active, + LRU_ACTIVE + file * LRU_FILE); + move_active_pages_to_lru(zone, &l_inactive, + LRU_BASE + file * LRU_FILE); - list_move(&page->lru, &zone->lru[lru].list); - mem_cgroup_add_lru_list(page, lru); - pgmoved++; - if (!pagevec_add(&pvec, page)) { - __mod_zone_page_state(zone, NR_LRU_BASE + lru, pgmoved); - spin_unlock_irq(&zone->lru_lock); - pgdeactivate += pgmoved; - pgmoved = 0; - if (buffer_heads_over_limit) - pagevec_strip(&pvec); - __pagevec_release(&pvec); - spin_lock_irq(&zone->lru_lock); - } - } - __mod_zone_page_state(zone, NR_LRU_BASE + lru, pgmoved); - pgdeactivate += pgmoved; - __count_zone_vm_events(PGREFILL, zone, pgscanned); - __count_vm_events(PGDEACTIVATE, pgdeactivate); spin_unlock_irq(&zone->lru_lock); - if (buffer_heads_over_limit) - pagevec_strip(&pvec); - pagevec_release(&pvec); } static int inactive_anon_is_low_global(struct zone *zone) @@ -1350,12 +1354,48 @@ static int inactive_anon_is_low(struct zone *zone, struct scan_control *sc) return low; } +static int inactive_file_is_low_global(struct zone *zone) +{ + unsigned long active, inactive; + + active = zone_page_state(zone, NR_ACTIVE_FILE); + inactive = zone_page_state(zone, NR_INACTIVE_FILE); + + return (active > inactive); +} + +/** + * inactive_file_is_low - check if file pages need to be deactivated + * @zone: zone to check + * @sc: scan control of this context + * + * When the system is doing streaming IO, memory pressure here + * ensures that active file pages get deactivated, until more + * than half of the file pages are on the inactive list. + * + * Once we get to that situation, protect the system's working + * set from being evicted by disabling active file page aging. + * + * This uses a different ratio than the anonymous pages, because + * the page cache uses a use-once replacement algorithm. + */ +static int inactive_file_is_low(struct zone *zone, struct scan_control *sc) +{ + int low; + + if (scanning_global_lru(sc)) + low = inactive_file_is_low_global(zone); + else + low = mem_cgroup_inactive_file_is_low(sc->mem_cgroup); + return low; +} + static unsigned long shrink_list(enum lru_list lru, unsigned long nr_to_scan, struct zone *zone, struct scan_control *sc, int priority) { int file = is_file_lru(lru); - if (lru == LRU_ACTIVE_FILE) { + if (lru == LRU_ACTIVE_FILE && inactive_file_is_low(zone, sc)) { shrink_active_list(nr_to_scan, zone, sc, priority, file); return 0; } @@ -1384,13 +1424,6 @@ static void get_scan_ratio(struct zone *zone, struct scan_control *sc, unsigned long ap, fp; struct zone_reclaim_stat *reclaim_stat = get_reclaim_stat(zone, sc); - /* If we have no swap space, do not bother scanning anon pages. */ - if (!sc->may_swap || (nr_swap_pages <= 0)) { - percent[0] = 0; - percent[1] = 100; - return; - } - anon = zone_nr_pages(zone, sc, LRU_ACTIVE_ANON) + zone_nr_pages(zone, sc, LRU_INACTIVE_ANON); file = zone_nr_pages(zone, sc, LRU_ACTIVE_FILE) + @@ -1400,7 +1433,7 @@ static void get_scan_ratio(struct zone *zone, struct scan_control *sc, free = zone_page_state(zone, NR_FREE_PAGES); /* If we have very few page cache pages, force-scan anon pages. */ - if (unlikely(file + free <= zone->pages_high)) { + if (unlikely(file + free <= high_wmark_pages(zone))) { percent[0] = 100; percent[1] = 0; return; @@ -1455,6 +1488,26 @@ static void get_scan_ratio(struct zone *zone, struct scan_control *sc, percent[1] = 100 - percent[0]; } +/* + * Smallish @nr_to_scan's are deposited in @nr_saved_scan, + * until we collected @swap_cluster_max pages to scan. + */ +static unsigned long nr_scan_try_batch(unsigned long nr_to_scan, + unsigned long *nr_saved_scan, + unsigned long swap_cluster_max) +{ + unsigned long nr; + + *nr_saved_scan += nr_to_scan; + nr = *nr_saved_scan; + + if (nr >= swap_cluster_max) + *nr_saved_scan = 0; + else + nr = 0; + + return nr; +} /* * This is a basic per-zone page freer. Used by both kswapd and direct reclaim. @@ -1468,26 +1521,30 @@ static void shrink_zone(int priority, struct zone *zone, enum lru_list l; unsigned long nr_reclaimed = sc->nr_reclaimed; unsigned long swap_cluster_max = sc->swap_cluster_max; + int noswap = 0; - get_scan_ratio(zone, sc, percent); + /* If we have no swap space, do not bother scanning anon pages. */ + if (!sc->may_swap || (nr_swap_pages <= 0)) { + noswap = 1; + percent[0] = 0; + percent[1] = 100; + } else + get_scan_ratio(zone, sc, percent); for_each_evictable_lru(l) { int file = is_file_lru(l); unsigned long scan; scan = zone_nr_pages(zone, sc, l); - if (priority) { + if (priority || noswap) { scan >>= priority; scan = (scan * percent[file]) / 100; } - if (scanning_global_lru(sc)) { - zone->lru[l].nr_scan += scan; - nr[l] = zone->lru[l].nr_scan; - if (nr[l] >= swap_cluster_max) - zone->lru[l].nr_scan = 0; - else - nr[l] = 0; - } else + if (scanning_global_lru(sc)) + nr[l] = nr_scan_try_batch(scan, + &zone->lru[l].nr_saved_scan, + swap_cluster_max); + else nr[l] = scan; } @@ -1521,7 +1578,7 @@ static void shrink_zone(int priority, struct zone *zone, * Even if we did not try to evict anon pages at all, we want to * rebalance the anon lru active/inactive ratio. */ - if (inactive_anon_is_low(zone, sc)) + if (inactive_anon_is_low(zone, sc) && nr_swap_pages > 0) shrink_active_list(SWAP_CLUSTER_MAX, zone, sc, priority, 0); throttle_vm_writeout(sc->gfp_mask); @@ -1532,11 +1589,13 @@ static void shrink_zone(int priority, struct zone *zone, * try to reclaim pages from zones which will satisfy the caller's allocation * request. * - * We reclaim from a zone even if that zone is over pages_high. Because: + * We reclaim from a zone even if that zone is over high_wmark_pages(zone). + * Because: * a) The caller may be trying to free *extra* pages to satisfy a higher-order * allocation or - * b) The zones may be over pages_high but they must go *over* pages_high to - * satisfy the `incremental min' zone defense algorithm. + * b) The target zone may be at high_wmark_pages(zone) but the lower zones + * must go *over* high_wmark_pages(zone) to satisfy the `incremental min' + * zone defense algorithm. * * If a zone is deemed to be full of pinned pages then just give it a light * scan then give up on it. @@ -1742,7 +1801,7 @@ unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *mem_cont, /* * For kswapd, balance_pgdat() will work across all this node's zones until - * they are all at pages_high. + * they are all at high_wmark_pages(zone). * * Returns the number of pages which were actually freed. * @@ -1755,11 +1814,11 @@ unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *mem_cont, * the zone for when the problem goes away. * * kswapd scans the zones in the highmem->normal->dma direction. It skips - * zones which have free_pages > pages_high, but once a zone is found to have - * free_pages <= pages_high, we scan that zone and the lower zones regardless - * of the number of free pages in the lower zones. This interoperates with - * the page allocator fallback scheme to ensure that aging of pages is balanced - * across the zones. + * zones which have free_pages > high_wmark_pages(zone), but once a zone is + * found to have free_pages <= high_wmark_pages(zone), we scan that zone and the + * lower zones regardless of the number of free pages in the lower zones. This + * interoperates with the page allocator fallback scheme to ensure that aging + * of pages is balanced across the zones. */ static unsigned long balance_pgdat(pg_data_t *pgdat, int order) { @@ -1780,7 +1839,8 @@ static unsigned long balance_pgdat(pg_data_t *pgdat, int order) }; /* * temp_priority is used to remember the scanning priority at which - * this zone was successfully refilled to free_pages == pages_high. + * this zone was successfully refilled to + * free_pages == high_wmark_pages(zone). */ int temp_priority[MAX_NR_ZONES]; @@ -1825,8 +1885,8 @@ loop_again: shrink_active_list(SWAP_CLUSTER_MAX, zone, &sc, priority, 0); - if (!zone_watermark_ok(zone, order, zone->pages_high, - 0, 0)) { + if (!zone_watermark_ok(zone, order, + high_wmark_pages(zone), 0, 0)) { end_zone = i; break; } @@ -1860,8 +1920,8 @@ loop_again: priority != DEF_PRIORITY) continue; - if (!zone_watermark_ok(zone, order, zone->pages_high, - end_zone, 0)) + if (!zone_watermark_ok(zone, order, + high_wmark_pages(zone), end_zone, 0)) all_zones_ok = 0; temp_priority[i] = priority; sc.nr_scanned = 0; @@ -1870,8 +1930,8 @@ loop_again: * We put equal pressure on every zone, unless one * zone has way too many pages free already. */ - if (!zone_watermark_ok(zone, order, 8*zone->pages_high, - end_zone, 0)) + if (!zone_watermark_ok(zone, order, + 8*high_wmark_pages(zone), end_zone, 0)) shrink_zone(priority, zone, &sc); reclaim_state->reclaimed_slab = 0; nr_slab = shrink_slab(sc.nr_scanned, GFP_KERNEL, @@ -2037,7 +2097,7 @@ void wakeup_kswapd(struct zone *zone, int order) return; pgdat = zone->zone_pgdat; - if (zone_watermark_ok(zone, order, zone->pages_low, 0, 0)) + if (zone_watermark_ok(zone, order, low_wmark_pages(zone), 0, 0)) return; if (pgdat->kswapd_max_order < order) pgdat->kswapd_max_order = order; @@ -2056,7 +2116,7 @@ unsigned long global_lru_pages(void) + global_page_state(NR_INACTIVE_FILE); } -#ifdef CONFIG_PM +#ifdef CONFIG_HIBERNATION /* * Helper function for shrink_all_memory(). Tries to reclaim 'nr_pages' pages * from LRU lists system-wide, for given pass and priority. @@ -2084,11 +2144,11 @@ static void shrink_all_zones(unsigned long nr_pages, int prio, l == LRU_ACTIVE_FILE)) continue; - zone->lru[l].nr_scan += (lru_pages >> prio) + 1; - if (zone->lru[l].nr_scan >= nr_pages || pass > 3) { + zone->lru[l].nr_saved_scan += (lru_pages >> prio) + 1; + if (zone->lru[l].nr_saved_scan >= nr_pages || pass > 3) { unsigned long nr_to_scan; - zone->lru[l].nr_scan = 0; + zone->lru[l].nr_saved_scan = 0; nr_to_scan = min(nr_pages, lru_pages); nr_reclaimed += shrink_list(l, nr_to_scan, zone, sc, prio); @@ -2196,7 +2256,7 @@ out: return sc.nr_reclaimed; } -#endif +#endif /* CONFIG_HIBERNATION */ /* It's optimal to keep kswapds on the same CPUs as their memory, but not required for correctness. So if the last cpu in a node goes @@ -2290,6 +2350,48 @@ int sysctl_min_unmapped_ratio = 1; */ int sysctl_min_slab_ratio = 5; +static inline unsigned long zone_unmapped_file_pages(struct zone *zone) +{ + unsigned long file_mapped = zone_page_state(zone, NR_FILE_MAPPED); + unsigned long file_lru = zone_page_state(zone, NR_INACTIVE_FILE) + + zone_page_state(zone, NR_ACTIVE_FILE); + + /* + * It's possible for there to be more file mapped pages than + * accounted for by the pages on the file LRU lists because + * tmpfs pages accounted for as ANON can also be FILE_MAPPED + */ + return (file_lru > file_mapped) ? (file_lru - file_mapped) : 0; +} + +/* Work out how many page cache pages we can reclaim in this reclaim_mode */ +static long zone_pagecache_reclaimable(struct zone *zone) +{ + long nr_pagecache_reclaimable; + long delta = 0; + + /* + * If RECLAIM_SWAP is set, then all file pages are considered + * potentially reclaimable. Otherwise, we have to worry about + * pages like swapcache and zone_unmapped_file_pages() provides + * a better estimate + */ + if (zone_reclaim_mode & RECLAIM_SWAP) + nr_pagecache_reclaimable = zone_page_state(zone, NR_FILE_PAGES); + else + nr_pagecache_reclaimable = zone_unmapped_file_pages(zone); + + /* If we can't clean pages, remove dirty pages from consideration */ + if (!(zone_reclaim_mode & RECLAIM_WRITE)) + delta += zone_page_state(zone, NR_FILE_DIRTY); + + /* Watch for any possible underflows due to delta */ + if (unlikely(delta > nr_pagecache_reclaimable)) + delta = nr_pagecache_reclaimable; + + return nr_pagecache_reclaimable - delta; +} + /* * Try to free up some pages from this zone through reclaim. */ @@ -2324,9 +2426,7 @@ static int __zone_reclaim(struct zone *zone, gfp_t gfp_mask, unsigned int order) reclaim_state.reclaimed_slab = 0; p->reclaim_state = &reclaim_state; - if (zone_page_state(zone, NR_FILE_PAGES) - - zone_page_state(zone, NR_FILE_MAPPED) > - zone->min_unmapped_pages) { + if (zone_pagecache_reclaimable(zone) > zone->min_unmapped_pages) { /* * Free memory by calling shrink zone with increasing * priorities until we have enough memory freed. @@ -2384,20 +2484,18 @@ int zone_reclaim(struct zone *zone, gfp_t gfp_mask, unsigned int order) * if less than a specified percentage of the zone is used by * unmapped file backed pages. */ - if (zone_page_state(zone, NR_FILE_PAGES) - - zone_page_state(zone, NR_FILE_MAPPED) <= zone->min_unmapped_pages - && zone_page_state(zone, NR_SLAB_RECLAIMABLE) - <= zone->min_slab_pages) - return 0; + if (zone_pagecache_reclaimable(zone) <= zone->min_unmapped_pages && + zone_page_state(zone, NR_SLAB_RECLAIMABLE) <= zone->min_slab_pages) + return ZONE_RECLAIM_FULL; if (zone_is_all_unreclaimable(zone)) - return 0; + return ZONE_RECLAIM_FULL; /* * Do not scan if the allocation should not be delayed. */ if (!(gfp_mask & __GFP_WAIT) || (current->flags & PF_MEMALLOC)) - return 0; + return ZONE_RECLAIM_NOSCAN; /* * Only run zone reclaim on the local zone or on zones that do not @@ -2407,18 +2505,21 @@ int zone_reclaim(struct zone *zone, gfp_t gfp_mask, unsigned int order) */ node_id = zone_to_nid(zone); if (node_state(node_id, N_CPU) && node_id != numa_node_id()) - return 0; + return ZONE_RECLAIM_NOSCAN; if (zone_test_and_set_flag(zone, ZONE_RECLAIM_LOCKED)) - return 0; + return ZONE_RECLAIM_NOSCAN; + ret = __zone_reclaim(zone, gfp_mask, order); zone_clear_flag(zone, ZONE_RECLAIM_LOCKED); + if (!ret) + count_vm_event(PGSCAN_ZONE_RECLAIM_FAILED); + return ret; } #endif -#ifdef CONFIG_UNEVICTABLE_LRU /* * page_evictable - test whether a page is evictable * @page: the page to test @@ -2665,4 +2766,3 @@ void scan_unevictable_unregister_node(struct node *node) sysdev_remove_file(&node->sysdev, &attr_scan_unevictable_pages); } -#endif diff --git a/mm/vmstat.c b/mm/vmstat.c index 74d66dba0cbe..138bed53706e 100644 --- a/mm/vmstat.c +++ b/mm/vmstat.c @@ -629,10 +629,8 @@ static const char * const vmstat_text[] = { "nr_active_anon", "nr_inactive_file", "nr_active_file", -#ifdef CONFIG_UNEVICTABLE_LRU "nr_unevictable", "nr_mlock", -#endif "nr_anon_pages", "nr_mapped", "nr_file_pages", @@ -675,6 +673,9 @@ static const char * const vmstat_text[] = { TEXTS_FOR_ZONES("pgscan_kswapd") TEXTS_FOR_ZONES("pgscan_direct") +#ifdef CONFIG_NUMA + "zone_reclaim_failed", +#endif "pginodesteal", "slabs_scanned", "kswapd_steal", @@ -687,7 +688,6 @@ static const char * const vmstat_text[] = { "htlb_buddy_alloc_success", "htlb_buddy_alloc_fail", #endif -#ifdef CONFIG_UNEVICTABLE_LRU "unevictable_pgs_culled", "unevictable_pgs_scanned", "unevictable_pgs_rescued", @@ -697,7 +697,6 @@ static const char * const vmstat_text[] = { "unevictable_pgs_stranded", "unevictable_pgs_mlockfreed", #endif -#endif }; static void zoneinfo_show_print(struct seq_file *m, pg_data_t *pgdat, @@ -710,18 +709,14 @@ static void zoneinfo_show_print(struct seq_file *m, pg_data_t *pgdat, "\n min %lu" "\n low %lu" "\n high %lu" - "\n scanned %lu (aa: %lu ia: %lu af: %lu if: %lu)" + "\n scanned %lu" "\n spanned %lu" "\n present %lu", zone_page_state(zone, NR_FREE_PAGES), - zone->pages_min, - zone->pages_low, - zone->pages_high, + min_wmark_pages(zone), + low_wmark_pages(zone), + high_wmark_pages(zone), zone->pages_scanned, - zone->lru[LRU_ACTIVE_ANON].nr_scan, - zone->lru[LRU_INACTIVE_ANON].nr_scan, - zone->lru[LRU_ACTIVE_FILE].nr_scan, - zone->lru[LRU_INACTIVE_FILE].nr_scan, zone->spanned_pages, zone->present_pages); diff --git a/net/802/fddi.c b/net/802/fddi.c index 539e6064e6d4..3ef0ab0a543a 100644 --- a/net/802/fddi.c +++ b/net/802/fddi.c @@ -185,10 +185,6 @@ static const struct header_ops fddi_header_ops = { static void fddi_setup(struct net_device *dev) { dev->header_ops = &fddi_header_ops; -#ifdef CONFIG_COMPAT_NET_DEV_OPS - dev->change_mtu = fddi_change_mtu, -#endif - dev->type = ARPHRD_FDDI; dev->hard_header_len = FDDI_K_SNAP_HLEN+3; /* Assume 802.2 SNAP hdr len + 3 pad bytes */ dev->mtu = FDDI_K_SNAP_DLEN; /* Assume max payload of 802.2 SNAP frame */ diff --git a/net/802/hippi.c b/net/802/hippi.c index 313b9ebf92ee..cd3e8e929529 100644 --- a/net/802/hippi.c +++ b/net/802/hippi.c @@ -193,11 +193,6 @@ static const struct header_ops hippi_header_ops = { static void hippi_setup(struct net_device *dev) { -#ifdef CONFIG_COMPAT_NET_DEV_OPS - dev->change_mtu = hippi_change_mtu; - dev->set_mac_address = hippi_mac_addr; - dev->neigh_setup = hippi_neigh_setup_dev; -#endif dev->header_ops = &hippi_header_ops; /* diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index d1e10546eb85..fe649081fbdc 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -378,13 +378,13 @@ static void vlan_sync_address(struct net_device *dev, * the new address */ if (compare_ether_addr(vlandev->dev_addr, vlan->real_dev_addr) && !compare_ether_addr(vlandev->dev_addr, dev->dev_addr)) - dev_unicast_delete(dev, vlandev->dev_addr, ETH_ALEN); + dev_unicast_delete(dev, vlandev->dev_addr); /* vlan address was equal to the old address and is different from * the new address */ if (!compare_ether_addr(vlandev->dev_addr, vlan->real_dev_addr) && compare_ether_addr(vlandev->dev_addr, dev->dev_addr)) - dev_unicast_add(dev, vlandev->dev_addr, ETH_ALEN); + dev_unicast_add(dev, vlandev->dev_addr); memcpy(vlan->real_dev_addr, dev->dev_addr, ETH_ALEN); } @@ -758,7 +758,7 @@ static void __exit vlan_cleanup_module(void) BUG_ON(!hlist_empty(&vlan_group_hash[i])); unregister_pernet_gen_device(vlan_net_id, &vlan_net_ops); - synchronize_net(); + rcu_barrier(); /* Wait for completion of call_rcu()'s */ vlan_gvrp_uninit(); } diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c index c67fe6f75653..7f7de1a04de6 100644 --- a/net/8021q/vlan_core.c +++ b/net/8021q/vlan_core.c @@ -114,9 +114,9 @@ int vlan_gro_receive(struct napi_struct *napi, struct vlan_group *grp, EXPORT_SYMBOL(vlan_gro_receive); int vlan_gro_frags(struct napi_struct *napi, struct vlan_group *grp, - unsigned int vlan_tci, struct napi_gro_fraginfo *info) + unsigned int vlan_tci) { - struct sk_buff *skb = napi_fraginfo_skb(napi, info); + struct sk_buff *skb = napi_frags_skb(napi); if (!skb) return NET_RX_DROP; diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index b4b9068e55a7..96bad8f233e2 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -290,7 +290,7 @@ static int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev, static int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct net_device_stats *stats = &dev->stats; + struct netdev_queue *txq = netdev_get_tx_queue(dev, 0); struct vlan_ethhdr *veth = (struct vlan_ethhdr *)(skb->data); /* Handle non-VLAN frames if they are sent to us, for example by DHCP. @@ -309,7 +309,7 @@ static int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) vlan_tci |= vlan_dev_get_egress_qos_mask(dev, skb); skb = __vlan_put_tag(skb, vlan_tci); if (!skb) { - stats->tx_dropped++; + txq->tx_dropped++; return NETDEV_TX_OK; } @@ -317,8 +317,8 @@ static int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) vlan_dev_info(dev)->cnt_inc_headroom_on_tx++; } - stats->tx_packets++; - stats->tx_bytes += skb->len; + txq->tx_packets++; + txq->tx_bytes += skb->len; skb->dev = vlan_dev_info(dev)->real_dev; dev_queue_xmit(skb); @@ -328,15 +328,15 @@ static int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) static int vlan_dev_hwaccel_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct net_device_stats *stats = &dev->stats; + struct netdev_queue *txq = netdev_get_tx_queue(dev, 0); u16 vlan_tci; vlan_tci = vlan_dev_info(dev)->vlan_id; vlan_tci |= vlan_dev_get_egress_qos_mask(dev, skb); skb = __vlan_hwaccel_put_tag(skb, vlan_tci); - stats->tx_packets++; - stats->tx_bytes += skb->len; + txq->tx_packets++; + txq->tx_bytes += skb->len; skb->dev = vlan_dev_info(dev)->real_dev; dev_queue_xmit(skb); @@ -441,7 +441,7 @@ static int vlan_dev_open(struct net_device *dev) return -ENETDOWN; if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr)) { - err = dev_unicast_add(real_dev, dev->dev_addr, ETH_ALEN); + err = dev_unicast_add(real_dev, dev->dev_addr); if (err < 0) goto out; } @@ -470,7 +470,7 @@ clear_allmulti: dev_set_allmulti(real_dev, -1); del_unicast: if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr)) - dev_unicast_delete(real_dev, dev->dev_addr, ETH_ALEN); + dev_unicast_delete(real_dev, dev->dev_addr); out: netif_carrier_off(dev); return err; @@ -492,7 +492,7 @@ static int vlan_dev_stop(struct net_device *dev) dev_set_promiscuity(real_dev, -1); if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr)) - dev_unicast_delete(real_dev, dev->dev_addr, dev->addr_len); + dev_unicast_delete(real_dev, dev->dev_addr); netif_carrier_off(dev); return 0; @@ -511,13 +511,13 @@ static int vlan_dev_set_mac_address(struct net_device *dev, void *p) goto out; if (compare_ether_addr(addr->sa_data, real_dev->dev_addr)) { - err = dev_unicast_add(real_dev, addr->sa_data, ETH_ALEN); + err = dev_unicast_add(real_dev, addr->sa_data); if (err < 0) return err; } if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr)) - dev_unicast_delete(real_dev, dev->dev_addr, ETH_ALEN); + dev_unicast_delete(real_dev, dev->dev_addr); out: memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); @@ -644,7 +644,6 @@ static int vlan_dev_init(struct net_device *dev) dev->hard_header_len = real_dev->hard_header_len + VLAN_HLEN; dev->netdev_ops = &vlan_netdev_ops; } - netdev_resync_ops(dev); if (is_vlan_dev(real_dev)) subclass = 1; @@ -671,13 +670,7 @@ static int vlan_ethtool_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { const struct vlan_dev_info *vlan = vlan_dev_info(dev); - struct net_device *real_dev = vlan->real_dev; - - if (!real_dev->ethtool_ops || - !real_dev->ethtool_ops->get_settings) - return -EOPNOTSUPP; - - return real_dev->ethtool_ops->get_settings(real_dev, cmd); + return dev_ethtool_get_settings(vlan->real_dev, cmd); } static void vlan_ethtool_get_drvinfo(struct net_device *dev, @@ -691,24 +684,13 @@ static void vlan_ethtool_get_drvinfo(struct net_device *dev, static u32 vlan_ethtool_get_rx_csum(struct net_device *dev) { const struct vlan_dev_info *vlan = vlan_dev_info(dev); - struct net_device *real_dev = vlan->real_dev; - - if (real_dev->ethtool_ops == NULL || - real_dev->ethtool_ops->get_rx_csum == NULL) - return 0; - return real_dev->ethtool_ops->get_rx_csum(real_dev); + return dev_ethtool_get_rx_csum(vlan->real_dev); } static u32 vlan_ethtool_get_flags(struct net_device *dev) { const struct vlan_dev_info *vlan = vlan_dev_info(dev); - struct net_device *real_dev = vlan->real_dev; - - if (!(real_dev->features & NETIF_F_HW_VLAN_RX) || - real_dev->ethtool_ops == NULL || - real_dev->ethtool_ops->get_flags == NULL) - return 0; - return real_dev->ethtool_ops->get_flags(real_dev); + return dev_ethtool_get_flags(vlan->real_dev); } static const struct ethtool_ops vlan_ethtool_ops = { @@ -756,6 +738,7 @@ void vlan_setup(struct net_device *dev) ether_setup(dev); dev->priv_flags |= IFF_802_1Q_VLAN; + dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; dev->tx_queue_len = 0; dev->netdev_ops = &vlan_netdev_ops; diff --git a/net/8021q/vlanproc.c b/net/8021q/vlanproc.c index 3628e0a81b40..b55a091a33df 100644 --- a/net/8021q/vlanproc.c +++ b/net/8021q/vlanproc.c @@ -279,13 +279,14 @@ static int vlandev_seq_show(struct seq_file *seq, void *offset) { struct net_device *vlandev = (struct net_device *) seq->private; const struct vlan_dev_info *dev_info = vlan_dev_info(vlandev); - struct net_device_stats *stats = &vlandev->stats; + const struct net_device_stats *stats; static const char fmt[] = "%30s %12lu\n"; int i; if (!is_vlan_dev(vlandev)) return 0; + stats = dev_get_stats(vlandev); seq_printf(seq, "%s VID: %d REORDER_HDR: %i dev->priv_flags: %hx\n", vlandev->name, dev_info->vlan_id, diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c index bb8579a141a8..a49484e67e1d 100644 --- a/net/9p/trans_virtio.c +++ b/net/9p/trans_virtio.c @@ -246,7 +246,7 @@ static int p9_virtio_probe(struct virtio_device *vdev) chan->vdev = vdev; /* We expect one virtqueue, for requests. */ - chan->vq = vdev->config->find_vq(vdev, 0, req_done); + chan->vq = virtio_find_single_vq(vdev, req_done, "requests"); if (IS_ERR(chan->vq)) { err = PTR_ERR(chan->vq); goto out_free_vq; @@ -261,7 +261,7 @@ static int p9_virtio_probe(struct virtio_device *vdev) return 0; out_free_vq: - vdev->config->del_vq(chan->vq); + vdev->config->del_vqs(vdev); fail: mutex_lock(&virtio_9p_lock); chan_index--; @@ -332,7 +332,7 @@ static void p9_virtio_remove(struct virtio_device *vdev) BUG_ON(chan->inuse); if (chan->initialized) { - vdev->config->del_vq(chan->vq); + vdev->config->del_vqs(vdev); chan->initialized = false; } } diff --git a/net/Kconfig b/net/Kconfig index c19f549c8e74..7051b9710675 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -179,6 +179,7 @@ source "net/lapb/Kconfig" source "net/econet/Kconfig" source "net/wanrouter/Kconfig" source "net/phonet/Kconfig" +source "net/ieee802154/Kconfig" source "net/sched/Kconfig" source "net/dcb/Kconfig" diff --git a/net/Makefile b/net/Makefile index 9e00a55a901b..ba324aefda73 100644 --- a/net/Makefile +++ b/net/Makefile @@ -60,6 +60,7 @@ obj-$(CONFIG_NET_9P) += 9p/ ifneq ($(CONFIG_DCB),) obj-y += dcb/ endif +obj-y += ieee802154/ ifeq ($(CONFIG_NET),y) obj-$(CONFIG_SYSCTL) += sysctl_net.o diff --git a/net/appletalk/atalk_proc.c b/net/appletalk/atalk_proc.c index fd8e0847b254..80caad1a31a5 100644 --- a/net/appletalk/atalk_proc.c +++ b/net/appletalk/atalk_proc.c @@ -204,8 +204,8 @@ static int atalk_seq_socket_show(struct seq_file *seq, void *v) "%02X %d\n", s->sk_type, ntohs(at->src_net), at->src_node, at->src_port, ntohs(at->dest_net), at->dest_node, at->dest_port, - atomic_read(&s->sk_wmem_alloc), - atomic_read(&s->sk_rmem_alloc), + sk_wmem_alloc_get(s), + sk_rmem_alloc_get(s), s->sk_state, SOCK_INODE(s->sk_socket)->i_uid); out: return 0; diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index d6a9243641af..590b83963622 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -162,8 +162,7 @@ static void atalk_destroy_timer(unsigned long data) { struct sock *sk = (struct sock *)data; - if (atomic_read(&sk->sk_wmem_alloc) || - atomic_read(&sk->sk_rmem_alloc)) { + if (sk_has_allocations(sk)) { sk->sk_timer.expires = jiffies + SOCK_DESTROY_TIME; add_timer(&sk->sk_timer); } else @@ -175,8 +174,7 @@ static inline void atalk_destroy_socket(struct sock *sk) atalk_remove_socket(sk); skb_queue_purge(&sk->sk_receive_queue); - if (atomic_read(&sk->sk_wmem_alloc) || - atomic_read(&sk->sk_rmem_alloc)) { + if (sk_has_allocations(sk)) { setup_timer(&sk->sk_timer, atalk_destroy_timer, (unsigned long)sk); sk->sk_timer.expires = jiffies + SOCK_DESTROY_TIME; @@ -939,6 +937,7 @@ static unsigned long atalk_sum_skb(const struct sk_buff *skb, int offset, int len, unsigned long sum) { int start = skb_headlen(skb); + struct sk_buff *frag_iter; int i, copy; /* checksum stuff in header space */ @@ -977,26 +976,22 @@ static unsigned long atalk_sum_skb(const struct sk_buff *skb, int offset, start = end; } - if (skb_shinfo(skb)->frag_list) { - struct sk_buff *list = skb_shinfo(skb)->frag_list; + skb_walk_frags(skb, frag_iter) { + int end; - for (; list; list = list->next) { - int end; + WARN_ON(start > offset + len); - WARN_ON(start > offset + len); - - end = start + list->len; - if ((copy = end - offset) > 0) { - if (copy > len) - copy = len; - sum = atalk_sum_skb(list, offset - start, - copy, sum); - if ((len -= copy) == 0) - return sum; - offset += copy; - } - start = end; + end = start + frag_iter->len; + if ((copy = end - offset) > 0) { + if (copy > len) + copy = len; + sum = atalk_sum_skb(frag_iter, offset - start, + copy, sum); + if ((len -= copy) == 0) + return sum; + offset += copy; } + start = end; } BUG_ON(len > 0); @@ -1753,8 +1748,7 @@ static int atalk_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) switch (cmd) { /* Protocol layer */ case TIOCOUTQ: { - long amount = sk->sk_sndbuf - - atomic_read(&sk->sk_wmem_alloc); + long amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk); if (amount < 0) amount = 0; diff --git a/net/appletalk/dev.c b/net/appletalk/dev.c index 72277d70c980..6c8016f61866 100644 --- a/net/appletalk/dev.c +++ b/net/appletalk/dev.c @@ -9,21 +9,10 @@ #include #include -#ifdef CONFIG_COMPAT_NET_DEV_OPS -static int ltalk_change_mtu(struct net_device *dev, int mtu) -{ - return -EINVAL; -} -#endif - static void ltalk_setup(struct net_device *dev) { /* Fill in the fields of the device structure with localtalk-generic values. */ -#ifdef CONFIG_COMPAT_NET_DEV_OPS - dev->change_mtu = ltalk_change_mtu; -#endif - dev->type = ARPHRD_LOCALTLK; dev->hard_header_len = LTALK_HLEN; dev->mtu = LTALK_MTU; diff --git a/net/atm/br2684.c b/net/atm/br2684.c index 3100a8940afc..2912665fc58c 100644 --- a/net/atm/br2684.c +++ b/net/atm/br2684.c @@ -228,7 +228,7 @@ static int br2684_start_xmit(struct sk_buff *skb, struct net_device *dev) struct br2684_dev *brdev = BRPRIV(dev); struct br2684_vcc *brvcc; - pr_debug("br2684_start_xmit, skb->dst=%p\n", skb->dst); + pr_debug("br2684_start_xmit, skb_dst(skb)=%p\n", skb_dst(skb)); read_lock(&devs_lock); brvcc = pick_outgoing_vcc(skb, brdev); if (brvcc == NULL) { @@ -445,9 +445,10 @@ free_skb: */ static int br2684_regvcc(struct atm_vcc *atmvcc, void __user * arg) { + struct sk_buff_head queue; int err; struct br2684_vcc *brvcc; - struct sk_buff *skb; + struct sk_buff *skb, *tmp; struct sk_buff_head *rq; struct br2684_dev *brdev; struct net_device *net_dev; @@ -505,29 +506,20 @@ static int br2684_regvcc(struct atm_vcc *atmvcc, void __user * arg) barrier(); atmvcc->push = br2684_push; + __skb_queue_head_init(&queue); rq = &sk_atm(atmvcc)->sk_receive_queue; spin_lock_irqsave(&rq->lock, flags); - if (skb_queue_empty(rq)) { - skb = NULL; - } else { - /* NULL terminate the list. */ - rq->prev->next = NULL; - skb = rq->next; - } - rq->prev = rq->next = (struct sk_buff *)rq; - rq->qlen = 0; + skb_queue_splice_init(rq, &queue); spin_unlock_irqrestore(&rq->lock, flags); - while (skb) { - struct sk_buff *next = skb->next; + skb_queue_walk_safe(&queue, skb, tmp) { + struct net_device *dev = skb->dev; + + dev->stats.rx_bytes -= skb->len; + dev->stats.rx_packets--; - skb->next = skb->prev = NULL; br2684_push(atmvcc, skb); - skb->dev->stats.rx_bytes -= skb->len; - skb->dev->stats.rx_packets--; - - skb = next; } __module_get(THIS_MODULE); return 0; diff --git a/net/atm/clip.c b/net/atm/clip.c index 3dc0a3a42a57..e65a3b1477f8 100644 --- a/net/atm/clip.c +++ b/net/atm/clip.c @@ -369,16 +369,16 @@ static int clip_start_xmit(struct sk_buff *skb, struct net_device *dev) unsigned long flags; pr_debug("clip_start_xmit (skb %p)\n", skb); - if (!skb->dst) { - printk(KERN_ERR "clip_start_xmit: skb->dst == NULL\n"); + if (!skb_dst(skb)) { + printk(KERN_ERR "clip_start_xmit: skb_dst(skb) == NULL\n"); dev_kfree_skb(skb); dev->stats.tx_dropped++; return 0; } - if (!skb->dst->neighbour) { + if (!skb_dst(skb)->neighbour) { #if 0 - skb->dst->neighbour = clip_find_neighbour(skb->dst, 1); - if (!skb->dst->neighbour) { + skb_dst(skb)->neighbour = clip_find_neighbour(skb_dst(skb), 1); + if (!skb_dst(skb)->neighbour) { dev_kfree_skb(skb); /* lost that one */ dev->stats.tx_dropped++; return 0; @@ -389,7 +389,7 @@ static int clip_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_dropped++; return 0; } - entry = NEIGH2ENTRY(skb->dst->neighbour); + entry = NEIGH2ENTRY(skb_dst(skb)->neighbour); if (!entry->vccs) { if (time_after(jiffies, entry->expires)) { /* should be resolved */ @@ -406,7 +406,7 @@ static int clip_start_xmit(struct sk_buff *skb, struct net_device *dev) } pr_debug("neigh %p, vccs %p\n", entry, entry->vccs); ATM_SKB(skb)->vcc = vcc = entry->vccs->vcc; - pr_debug("using neighbour %p, vcc %p\n", skb->dst->neighbour, vcc); + pr_debug("using neighbour %p, vcc %p\n", skb_dst(skb)->neighbour, vcc); if (entry->vccs->encap) { void *here; @@ -445,9 +445,9 @@ static int clip_start_xmit(struct sk_buff *skb, struct net_device *dev) static int clip_mkip(struct atm_vcc *vcc, int timeout) { + struct sk_buff_head *rq, queue; struct clip_vcc *clip_vcc; - struct sk_buff *skb; - struct sk_buff_head *rq; + struct sk_buff *skb, *tmp; unsigned long flags; if (!vcc->push) @@ -469,39 +469,28 @@ static int clip_mkip(struct atm_vcc *vcc, int timeout) vcc->push = clip_push; vcc->pop = clip_pop; + __skb_queue_head_init(&queue); rq = &sk_atm(vcc)->sk_receive_queue; spin_lock_irqsave(&rq->lock, flags); - if (skb_queue_empty(rq)) { - skb = NULL; - } else { - /* NULL terminate the list. */ - rq->prev->next = NULL; - skb = rq->next; - } - rq->prev = rq->next = (struct sk_buff *)rq; - rq->qlen = 0; + skb_queue_splice_init(rq, &queue); spin_unlock_irqrestore(&rq->lock, flags); /* re-process everything received between connection setup and MKIP */ - while (skb) { - struct sk_buff *next = skb->next; - - skb->next = skb->prev = NULL; + skb_queue_walk_safe(&queue, skb, tmp) { if (!clip_devs) { atm_return(vcc, skb->truesize); kfree_skb(skb); } else { + struct net_device *dev = skb->dev; unsigned int len = skb->len; skb_get(skb); clip_push(vcc, skb); - skb->dev->stats.rx_packets--; - skb->dev->stats.rx_bytes -= len; + dev->stats.rx_packets--; + dev->stats.rx_bytes -= len; kfree_skb(skb); } - - skb = next; } return 0; } @@ -568,6 +557,7 @@ static void clip_setup(struct net_device *dev) /* without any more elaborate queuing. 100 is a reasonable */ /* compromise between decent burst-tolerance and protection */ /* against memory hogs. */ + dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; } static int clip_create(int number) diff --git a/net/atm/common.c b/net/atm/common.c index d34edbe754c8..c1c97936192c 100644 --- a/net/atm/common.c +++ b/net/atm/common.c @@ -62,15 +62,15 @@ static struct sk_buff *alloc_tx(struct atm_vcc *vcc,unsigned int size) struct sk_buff *skb; struct sock *sk = sk_atm(vcc); - if (atomic_read(&sk->sk_wmem_alloc) && !atm_may_send(vcc, size)) { + if (sk_wmem_alloc_get(sk) && !atm_may_send(vcc, size)) { pr_debug("Sorry: wmem_alloc = %d, size = %d, sndbuf = %d\n", - atomic_read(&sk->sk_wmem_alloc), size, + sk_wmem_alloc_get(sk), size, sk->sk_sndbuf); return NULL; } - while (!(skb = alloc_skb(size,GFP_KERNEL))) schedule(); - pr_debug("AlTx %d += %d\n", atomic_read(&sk->sk_wmem_alloc), - skb->truesize); + while (!(skb = alloc_skb(size, GFP_KERNEL))) + schedule(); + pr_debug("AlTx %d += %d\n", sk_wmem_alloc_get(sk), skb->truesize); atomic_add(skb->truesize, &sk->sk_wmem_alloc); return skb; } @@ -145,7 +145,7 @@ int vcc_create(struct net *net, struct socket *sock, int protocol, int family) memset(&vcc->local,0,sizeof(struct sockaddr_atmsvc)); memset(&vcc->remote,0,sizeof(struct sockaddr_atmsvc)); vcc->qos.txtp.max_sdu = 1 << 16; /* for meta VCs */ - atomic_set(&sk->sk_wmem_alloc, 0); + atomic_set(&sk->sk_wmem_alloc, 1); atomic_set(&sk->sk_rmem_alloc, 0); vcc->push = NULL; vcc->pop = NULL; diff --git a/net/atm/ioctl.c b/net/atm/ioctl.c index 76ed3c8d26e6..4da8892ced5f 100644 --- a/net/atm/ioctl.c +++ b/net/atm/ioctl.c @@ -63,8 +63,7 @@ static int do_vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg error = -EINVAL; goto done; } - error = put_user(sk->sk_sndbuf - - atomic_read(&sk->sk_wmem_alloc), + error = put_user(sk->sk_sndbuf - sk_wmem_alloc_get(sk), (int __user *) argp) ? -EFAULT : 0; goto done; case SIOCINQ: diff --git a/net/atm/lec.c b/net/atm/lec.c index 199b6bb79f42..ff2e594dca9b 100644 --- a/net/atm/lec.c +++ b/net/atm/lec.c @@ -34,7 +34,6 @@ /* Proxy LEC knows about bridging */ #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) -#include #include "../bridge/br_private.h" static unsigned char bridge_ula_lec[] = { 0x01, 0x80, 0xc2, 0x00, 0x00 }; @@ -271,7 +270,8 @@ static int lec_start_xmit(struct sk_buff *skb, struct net_device *dev) printk("%s:No lecd attached\n", dev->name); dev->stats.tx_errors++; netif_stop_queue(dev); - return -EUNATCH; + kfree_skb(skb); + return NETDEV_TX_OK; } pr_debug("skbuff head:%lx data:%lx tail:%lx end:%lx\n", @@ -518,18 +518,14 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb) case l_should_bridge: #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) { - struct net_bridge_fdb_entry *f; - pr_debug("%s: bridge zeppelin asks about %pM\n", dev->name, mesg->content.proxy.mac_addr); - if (br_fdb_get_hook == NULL || dev->br_port == NULL) + if (br_fdb_test_addr_hook == NULL) break; - f = br_fdb_get_hook(dev->br_port->br, - mesg->content.proxy.mac_addr); - if (f != NULL && f->dst->dev != dev - && f->dst->state == BR_STATE_FORWARDING) { + if (br_fdb_test_addr_hook(dev, + mesg->content.proxy.mac_addr)) { /* hit from bridge table, send LE_ARP_RESPONSE */ struct sk_buff *skb2; struct sock *sk; @@ -540,10 +536,8 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb) skb2 = alloc_skb(sizeof(struct atmlec_msg), GFP_ATOMIC); - if (skb2 == NULL) { - br_fdb_put_hook(f); + if (skb2 == NULL) break; - } skb2->len = sizeof(struct atmlec_msg); skb_copy_to_linear_data(skb2, mesg, sizeof(*mesg)); @@ -552,8 +546,6 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb) skb_queue_tail(&sk->sk_receive_queue, skb2); sk->sk_data_ready(sk, skb2->len); } - if (f != NULL) - br_fdb_put_hook(f); } #endif /* defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) */ break; diff --git a/net/atm/proc.c b/net/atm/proc.c index e7b3b273907d..38de5ff61ecd 100644 --- a/net/atm/proc.c +++ b/net/atm/proc.c @@ -204,8 +204,8 @@ static void vcc_info(struct seq_file *seq, struct atm_vcc *vcc) seq_printf(seq, "%3d", sk->sk_family); } seq_printf(seq, " %04lx %5d %7d/%7d %7d/%7d [%d]\n", vcc->flags, sk->sk_err, - atomic_read(&sk->sk_wmem_alloc), sk->sk_sndbuf, - atomic_read(&sk->sk_rmem_alloc), sk->sk_rcvbuf, + sk_wmem_alloc_get(sk), sk->sk_sndbuf, + sk_rmem_alloc_get(sk), sk->sk_rcvbuf, atomic_read(&sk->sk_refcnt)); } diff --git a/net/atm/raw.c b/net/atm/raw.c index b0a2d8cb6744..cbfcc71a17b1 100644 --- a/net/atm/raw.c +++ b/net/atm/raw.c @@ -33,7 +33,7 @@ static void atm_pop_raw(struct atm_vcc *vcc,struct sk_buff *skb) struct sock *sk = sk_atm(vcc); pr_debug("APopR (%d) %d -= %d\n", vcc->vci, - atomic_read(&sk->sk_wmem_alloc), skb->truesize); + sk_wmem_alloc_get(sk), skb->truesize); atomic_sub(skb->truesize, &sk->sk_wmem_alloc); dev_kfree_skb_any(skb); sk->sk_write_space(sk); diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index fd9d06f291dc..da0f64f82b57 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -330,8 +330,7 @@ void ax25_destroy_socket(ax25_cb *ax25) } if (ax25->sk != NULL) { - if (atomic_read(&ax25->sk->sk_wmem_alloc) || - atomic_read(&ax25->sk->sk_rmem_alloc)) { + if (sk_has_allocations(ax25->sk)) { /* Defer: outstanding buffers */ setup_timer(&ax25->dtimer, ax25_destroy_timer, (unsigned long)ax25); @@ -1691,7 +1690,8 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) switch (cmd) { case TIOCOUTQ: { long amount; - amount = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc); + + amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk); if (amount < 0) amount = 0; res = put_user(amount, (int __user *)argp); @@ -1781,8 +1781,8 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) ax25_info.idletimer = ax25_display_timer(&ax25->idletimer) / (60 * HZ); ax25_info.n2count = ax25->n2count; ax25_info.state = ax25->state; - ax25_info.rcv_q = atomic_read(&sk->sk_rmem_alloc); - ax25_info.snd_q = atomic_read(&sk->sk_wmem_alloc); + ax25_info.rcv_q = sk_wmem_alloc_get(sk); + ax25_info.snd_q = sk_rmem_alloc_get(sk); ax25_info.vs = ax25->vs; ax25_info.vr = ax25->vr; ax25_info.va = ax25->va; @@ -1922,8 +1922,8 @@ static int ax25_info_show(struct seq_file *seq, void *v) if (ax25->sk != NULL) { seq_printf(seq, " %d %d %lu\n", - atomic_read(&ax25->sk->sk_wmem_alloc), - atomic_read(&ax25->sk->sk_rmem_alloc), + sk_wmem_alloc_get(ax25->sk), + sk_rmem_alloc_get(ax25->sk), sock_i_ino(ax25->sk)); } else { seq_puts(seq, " * * *\n"); diff --git a/net/ax25/ax25_in.c b/net/ax25/ax25_in.c index 5f1d2107a1dd..de56d3983de0 100644 --- a/net/ax25/ax25_in.c +++ b/net/ax25/ax25_in.c @@ -437,8 +437,7 @@ free: int ax25_kiss_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *ptype, struct net_device *orig_dev) { - skb->sk = NULL; /* Initially we don't know who it's for */ - skb->destructor = NULL; /* Who initializes this, dammit?! */ + skb_orphan(skb); if (!net_eq(dev_net(dev), &init_net)) { kfree_skb(skb); diff --git a/net/bluetooth/Kconfig b/net/bluetooth/Kconfig index 7725da95a767..59fdb1d2e8ed 100644 --- a/net/bluetooth/Kconfig +++ b/net/bluetooth/Kconfig @@ -3,8 +3,9 @@ # menuconfig BT - depends on NET && !S390 tristate "Bluetooth subsystem support" + depends on NET && !S390 + depends on RFKILL || !RFKILL help Bluetooth is low-cost, low-power, short-range wireless technology. It was designed as a replacement for cables and other short-range diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index 02b9baa1930b..0250e0600150 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c @@ -337,7 +337,7 @@ int bt_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) if (sk->sk_state == BT_LISTEN) return -EINVAL; - amount = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc); + amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk); if (amount < 0) amount = 0; err = put_user(amount, (int __user *) arg); diff --git a/net/bluetooth/cmtp/capi.c b/net/bluetooth/cmtp/capi.c index 78958c0f9a40..97f8d68d574d 100644 --- a/net/bluetooth/cmtp/capi.c +++ b/net/bluetooth/cmtp/capi.c @@ -382,7 +382,7 @@ static void cmtp_reset_ctr(struct capi_ctr *ctrl) BT_DBG("ctrl %p", ctrl); - capi_ctr_reseted(ctrl); + capi_ctr_down(ctrl); atomic_inc(&session->terminate); cmtp_schedule(session); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index cd061510b6bd..406ad07cdea1 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -476,6 +477,11 @@ int hci_dev_open(__u16 dev) hci_req_lock(hdev); + if (hdev->rfkill && rfkill_blocked(hdev->rfkill)) { + ret = -ERFKILL; + goto done; + } + if (test_bit(HCI_UP, &hdev->flags)) { ret = -EALREADY; goto done; @@ -813,6 +819,24 @@ int hci_get_dev_info(void __user *arg) /* ---- Interface to HCI drivers ---- */ +static int hci_rfkill_set_block(void *data, bool blocked) +{ + struct hci_dev *hdev = data; + + BT_DBG("%p name %s blocked %d", hdev, hdev->name, blocked); + + if (!blocked) + return 0; + + hci_dev_do_close(hdev); + + return 0; +} + +static const struct rfkill_ops hci_rfkill_ops = { + .set_block = hci_rfkill_set_block, +}; + /* Alloc HCI device */ struct hci_dev *hci_alloc_dev(void) { @@ -844,7 +868,8 @@ int hci_register_dev(struct hci_dev *hdev) struct list_head *head = &hci_dev_list, *p; int i, id = 0; - BT_DBG("%p name %s type %d owner %p", hdev, hdev->name, hdev->type, hdev->owner); + BT_DBG("%p name %s type %d owner %p", hdev, hdev->name, + hdev->type, hdev->owner); if (!hdev->open || !hdev->close || !hdev->destruct) return -EINVAL; @@ -900,6 +925,15 @@ int hci_register_dev(struct hci_dev *hdev) hci_register_sysfs(hdev); + hdev->rfkill = rfkill_alloc(hdev->name, &hdev->dev, + RFKILL_TYPE_BLUETOOTH, &hci_rfkill_ops, hdev); + if (hdev->rfkill) { + if (rfkill_register(hdev->rfkill) < 0) { + rfkill_destroy(hdev->rfkill); + hdev->rfkill = NULL; + } + } + hci_notify(hdev, HCI_DEV_REG); return id; @@ -924,6 +958,11 @@ int hci_unregister_dev(struct hci_dev *hdev) hci_notify(hdev, HCI_DEV_UNREG); + if (hdev->rfkill) { + rfkill_unregister(hdev->rfkill); + rfkill_destroy(hdev->rfkill); + } + hci_unregister_sysfs(hdev); __hci_dev_put(hdev); diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index ca4d3b40d5ce..bd0a4c1bced0 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -40,10 +40,10 @@ #include #include #include +#include #include #include -#include #include #include @@ -52,7 +52,7 @@ #define VERSION "2.13" -static u32 l2cap_feat_mask = 0x0080; +static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN; static u8 l2cap_fixed_chan[8] = { 0x02, }; static const struct proto_ops l2cap_sock_ops; @@ -134,7 +134,8 @@ static inline struct sock *l2cap_get_chan_by_scid(struct l2cap_chan_list *l, u16 struct sock *s; read_lock(&l->lock); s = __l2cap_get_chan_by_scid(l, cid); - if (s) bh_lock_sock(s); + if (s) + bh_lock_sock(s); read_unlock(&l->lock); return s; } @@ -154,17 +155,18 @@ static inline struct sock *l2cap_get_chan_by_ident(struct l2cap_chan_list *l, u8 struct sock *s; read_lock(&l->lock); s = __l2cap_get_chan_by_ident(l, ident); - if (s) bh_lock_sock(s); + if (s) + bh_lock_sock(s); read_unlock(&l->lock); return s; } static u16 l2cap_alloc_cid(struct l2cap_chan_list *l) { - u16 cid = 0x0040; + u16 cid = L2CAP_CID_DYN_START; - for (; cid < 0xffff; cid++) { - if(!__l2cap_get_chan_by_scid(l, cid)) + for (; cid < L2CAP_CID_DYN_END; cid++) { + if (!__l2cap_get_chan_by_scid(l, cid)) return cid; } @@ -204,7 +206,8 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct so { struct l2cap_chan_list *l = &conn->chan_list; - BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid); + BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, + l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid); conn->disc_reason = 0x13; @@ -215,13 +218,13 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct so l2cap_pi(sk)->scid = l2cap_alloc_cid(l); } else if (sk->sk_type == SOCK_DGRAM) { /* Connectionless socket */ - l2cap_pi(sk)->scid = 0x0002; - l2cap_pi(sk)->dcid = 0x0002; + l2cap_pi(sk)->scid = L2CAP_CID_CONN_LESS; + l2cap_pi(sk)->dcid = L2CAP_CID_CONN_LESS; l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU; } else { /* Raw socket can send/recv signalling messages only */ - l2cap_pi(sk)->scid = 0x0001; - l2cap_pi(sk)->dcid = 0x0001; + l2cap_pi(sk)->scid = L2CAP_CID_SIGNALING; + l2cap_pi(sk)->dcid = L2CAP_CID_SIGNALING; l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU; } @@ -272,7 +275,7 @@ static inline int l2cap_check_security(struct sock *sk) if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH) auth_type = HCI_AT_NO_BONDING_MITM; else - auth_type = HCI_AT_NO_BONDING; + auth_type = HCI_AT_NO_BONDING; if (l2cap_pi(sk)->sec_level == BT_SECURITY_LOW) l2cap_pi(sk)->sec_level = BT_SECURITY_SDP; @@ -588,7 +591,8 @@ static inline struct sock *l2cap_get_sock_by_psm(int state, __le16 psm, bdaddr_t struct sock *s; read_lock(&l2cap_sk_list.lock); s = __l2cap_get_sock_by_psm(state, psm, src); - if (s) bh_lock_sock(s); + if (s) + bh_lock_sock(s); read_unlock(&l2cap_sk_list.lock); return s; } @@ -808,7 +812,7 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) goto done; } - if (la.l2_psm && btohs(la.l2_psm) < 0x1001 && + if (la.l2_psm && __le16_to_cpu(la.l2_psm) < 0x1001 && !capable(CAP_NET_BIND_SERVICE)) { err = -EACCES; goto done; @@ -825,7 +829,8 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) l2cap_pi(sk)->sport = la.l2_psm; sk->sk_state = BT_BOUND; - if (btohs(la.l2_psm) == 0x0001 || btohs(la.l2_psm) == 0x0003) + if (__le16_to_cpu(la.l2_psm) == 0x0001 || + __le16_to_cpu(la.l2_psm) == 0x0003) l2cap_pi(sk)->sec_level = BT_SECURITY_SDP; } @@ -844,12 +849,13 @@ static int l2cap_do_connect(struct sock *sk) struct hci_conn *hcon; struct hci_dev *hdev; __u8 auth_type; - int err = 0; + int err; BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst), l2cap_pi(sk)->psm); - if (!(hdev = hci_get_route(dst, src))) + hdev = hci_get_route(dst, src); + if (!hdev) return -EHOSTUNREACH; hci_dev_lock_bh(hdev); @@ -950,7 +956,7 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al goto done; } - switch(sk->sk_state) { + switch (sk->sk_state) { case BT_CONNECT: case BT_CONNECT2: case BT_CONFIG: @@ -975,7 +981,8 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al bacpy(&bt_sk(sk)->dst, &la.l2_bdaddr); l2cap_pi(sk)->psm = la.l2_psm; - if ((err = l2cap_do_connect(sk))) + err = l2cap_do_connect(sk); + if (err) goto done; wait: @@ -1009,9 +1016,9 @@ static int l2cap_sock_listen(struct socket *sock, int backlog) write_lock_bh(&l2cap_sk_list.lock); for (psm = 0x1001; psm < 0x1100; psm += 2) - if (!__l2cap_get_sock_by_addr(htobs(psm), src)) { - l2cap_pi(sk)->psm = htobs(psm); - l2cap_pi(sk)->sport = htobs(psm); + if (!__l2cap_get_sock_by_addr(cpu_to_le16(psm), src)) { + l2cap_pi(sk)->psm = cpu_to_le16(psm); + l2cap_pi(sk)->sport = cpu_to_le16(psm); err = 0; break; } @@ -1100,11 +1107,11 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *l if (peer) { la->l2_psm = l2cap_pi(sk)->psm; bacpy(&la->l2_bdaddr, &bt_sk(sk)->dst); - la->l2_cid = htobs(l2cap_pi(sk)->dcid); + la->l2_cid = cpu_to_le16(l2cap_pi(sk)->dcid); } else { la->l2_psm = l2cap_pi(sk)->sport; bacpy(&la->l2_bdaddr, &bt_sk(sk)->src); - la->l2_cid = htobs(l2cap_pi(sk)->scid); + la->l2_cid = cpu_to_le16(l2cap_pi(sk)->scid); } return 0; @@ -1114,7 +1121,7 @@ static inline int l2cap_do_send(struct sock *sk, struct msghdr *msg, int len) { struct l2cap_conn *conn = l2cap_pi(sk)->conn; struct sk_buff *skb, **frag; - int err, hlen, count, sent=0; + int err, hlen, count, sent = 0; struct l2cap_hdr *lh; BT_DBG("sk %p len %d", sk, len); @@ -1167,8 +1174,8 @@ static inline int l2cap_do_send(struct sock *sk, struct msghdr *msg, int len) frag = &(*frag)->next; } - - if ((err = hci_send_acl(conn->hcon, skb, 0)) < 0) + err = hci_send_acl(conn->hcon, skb, 0); + if (err < 0) goto fail; return sent; @@ -1556,7 +1563,7 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb) { struct l2cap_chan_list *l = &conn->chan_list; struct sk_buff *nskb; - struct sock * sk; + struct sock *sk; BT_DBG("conn %p", conn); @@ -1568,8 +1575,8 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb) /* Don't send frame to the socket it came from */ if (skb->sk == sk) continue; - - if (!(nskb = skb_clone(skb, GFP_ATOMIC))) + nskb = skb_clone(skb, GFP_ATOMIC); + if (!nskb) continue; if (sock_queue_rcv_skb(sk, nskb)) @@ -1587,7 +1594,8 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, struct l2cap_hdr *lh; int len, count; - BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d", conn, code, ident, dlen); + BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d", + conn, code, ident, dlen); len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen; count = min_t(unsigned int, conn->mtu, len); @@ -1598,7 +1606,7 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); lh->len = cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen); - lh->cid = cpu_to_le16(0x0001); + lh->cid = cpu_to_le16(L2CAP_CID_SIGNALING); cmd = (struct l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE); cmd->code = code; @@ -1739,8 +1747,8 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data) while (len >= L2CAP_CONF_OPT_SIZE) { len -= l2cap_get_conf_opt(&req, &type, &olen, &val); - hint = type & 0x80; - type &= 0x7f; + hint = type & L2CAP_CONF_HINT; + type &= L2CAP_CONF_MASK; switch (type) { case L2CAP_CONF_MTU: @@ -1966,10 +1974,12 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status); if (scid) { - if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid))) + sk = l2cap_get_chan_by_scid(&conn->chan_list, scid); + if (!sk) return 0; } else { - if (!(sk = l2cap_get_chan_by_ident(&conn->chan_list, cmd->ident))) + sk = l2cap_get_chan_by_ident(&conn->chan_list, cmd->ident); + if (!sk) return 0; } @@ -2012,7 +2022,8 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr BT_DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags); - if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid))) + sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid); + if (!sk) return -ENOENT; if (sk->sk_state == BT_DISCONN) @@ -2079,9 +2090,11 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr flags = __le16_to_cpu(rsp->flags); result = __le16_to_cpu(rsp->result); - BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x", scid, flags, result); + BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x", + scid, flags, result); - if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid))) + sk = l2cap_get_chan_by_scid(&conn->chan_list, scid); + if (!sk) return 0; switch (result) { @@ -2142,7 +2155,8 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid); - if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid))) + sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid); + if (!sk) return 0; rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); @@ -2169,7 +2183,8 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid); - if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid))) + sk = l2cap_get_chan_by_scid(&conn->chan_list, scid); + if (!sk) return 0; l2cap_chan_del(sk, 0); @@ -2230,7 +2245,7 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm if (type == L2CAP_IT_FEAT_MASK) { conn->feat_mask = get_unaligned_le32(rsp->data); - if (conn->feat_mask & 0x0080) { + if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) { struct l2cap_info_req req; req.type = cpu_to_le16(L2CAP_IT_FIXED_CHAN); @@ -2403,7 +2418,8 @@ drop: kfree_skb(skb); done: - if (sk) bh_unlock_sock(sk); + if (sk) + bh_unlock_sock(sk); return 0; } @@ -2420,11 +2436,11 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) BT_DBG("len %d, cid 0x%4.4x", len, cid); switch (cid) { - case 0x0001: + case L2CAP_CID_SIGNALING: l2cap_sig_channel(conn, skb); break; - case 0x0002: + case L2CAP_CID_CONN_LESS: psm = get_unaligned((__le16 *) skb->data); skb_pull(skb, 2); l2cap_conless_channel(conn, psm, skb); @@ -2650,7 +2666,8 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl } /* Allocate skb for the complete frame (with header) */ - if (!(conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC))) + conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC); + if (!conn->rx_skb) goto drop; skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len), @@ -2704,13 +2721,13 @@ static ssize_t l2cap_sysfs_show(struct class *dev, char *buf) str += sprintf(str, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d %d\n", batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst), - sk->sk_state, btohs(pi->psm), pi->scid, pi->dcid, - pi->imtu, pi->omtu, pi->sec_level); + sk->sk_state, __le16_to_cpu(pi->psm), pi->scid, + pi->dcid, pi->imtu, pi->omtu, pi->sec_level); } read_unlock_bh(&l2cap_sk_list.lock); - return (str - buf); + return str - buf; } static CLASS_ATTR(l2cap, S_IRUGO, l2cap_sysfs_show, NULL); diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index 374536e050aa..e50566ebf9f9 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -679,7 +679,7 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst bacpy(&addr.l2_bdaddr, dst); addr.l2_family = AF_BLUETOOTH; - addr.l2_psm = htobs(RFCOMM_PSM); + addr.l2_psm = cpu_to_le16(RFCOMM_PSM); addr.l2_cid = 0; *err = kernel_connect(sock, (struct sockaddr *) &addr, sizeof(addr), O_NONBLOCK); if (*err == 0 || *err == -EINPROGRESS) @@ -852,9 +852,9 @@ static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d } if (cr && channel_mtu >= 0) - pn->mtu = htobs(channel_mtu); + pn->mtu = cpu_to_le16(channel_mtu); else - pn->mtu = htobs(d->mtu); + pn->mtu = cpu_to_le16(d->mtu); *ptr = __fcs(buf); ptr++; @@ -1056,7 +1056,7 @@ static void rfcomm_make_uih(struct sk_buff *skb, u8 addr) if (len > 127) { hdr = (void *) skb_push(skb, 4); - put_unaligned(htobs(__len16(len)), (__le16 *) &hdr->len); + put_unaligned(cpu_to_le16(__len16(len)), (__le16 *) &hdr->len); } else { hdr = (void *) skb_push(skb, 3); hdr->len = __len8(len); @@ -1289,7 +1289,7 @@ static int rfcomm_apply_pn(struct rfcomm_dlc *d, int cr, struct rfcomm_pn *pn) d->priority = pn->priority; - d->mtu = btohs(pn->mtu); + d->mtu = __le16_to_cpu(pn->mtu); if (cr && d->mtu > s->mtu) d->mtu = s->mtu; @@ -1922,7 +1922,7 @@ static int rfcomm_add_listener(bdaddr_t *ba) /* Bind socket */ bacpy(&addr.l2_bdaddr, ba); addr.l2_family = AF_BLUETOOTH; - addr.l2_psm = htobs(RFCOMM_PSM); + addr.l2_psm = cpu_to_le16(RFCOMM_PSM); addr.l2_cid = 0; err = kernel_bind(sock, (struct sockaddr *) &addr, sizeof(addr)); if (err < 0) { diff --git a/net/bridge/br.c b/net/bridge/br.c index 4d2c1f1cb524..9aac5213105a 100644 --- a/net/bridge/br.c +++ b/net/bridge/br.c @@ -65,8 +65,9 @@ static int __init br_init(void) brioctl_set(br_ioctl_deviceless_stub); br_handle_frame_hook = br_handle_frame; - br_fdb_get_hook = br_fdb_get; - br_fdb_put_hook = br_fdb_put; +#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) + br_fdb_test_addr_hook = br_fdb_test_addr; +#endif return 0; err_out4: @@ -95,8 +96,9 @@ static void __exit br_deinit(void) synchronize_net(); br_netfilter_fini(); - br_fdb_get_hook = NULL; - br_fdb_put_hook = NULL; +#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) + br_fdb_test_addr_hook = NULL; +#endif br_handle_frame_hook = NULL; br_fdb_fini(); diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index a48f5efdb6bf..57bf05c353bc 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c @@ -71,10 +71,17 @@ static inline int br_mac_hash(const unsigned char *mac) return jhash_1word(key, fdb_salt) & (BR_HASH_SIZE - 1); } +static void fdb_rcu_free(struct rcu_head *head) +{ + struct net_bridge_fdb_entry *ent + = container_of(head, struct net_bridge_fdb_entry, rcu); + kmem_cache_free(br_fdb_cache, ent); +} + static inline void fdb_delete(struct net_bridge_fdb_entry *f) { hlist_del_rcu(&f->hlist); - br_fdb_put(f); + call_rcu(&f->rcu, fdb_rcu_free); } void br_fdb_changeaddr(struct net_bridge_port *p, const unsigned char *newaddr) @@ -226,33 +233,26 @@ struct net_bridge_fdb_entry *__br_fdb_get(struct net_bridge *br, return NULL; } -/* Interface used by ATM hook that keeps a ref count */ -struct net_bridge_fdb_entry *br_fdb_get(struct net_bridge *br, - unsigned char *addr) +#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) +/* Interface used by ATM LANE hook to test + * if an addr is on some other bridge port */ +int br_fdb_test_addr(struct net_device *dev, unsigned char *addr) { struct net_bridge_fdb_entry *fdb; + int ret; + + if (!dev->br_port) + return 0; rcu_read_lock(); - fdb = __br_fdb_get(br, addr); - if (fdb && !atomic_inc_not_zero(&fdb->use_count)) - fdb = NULL; + fdb = __br_fdb_get(dev->br_port->br, addr); + ret = fdb && fdb->dst->dev != dev && + fdb->dst->state == BR_STATE_FORWARDING; rcu_read_unlock(); - return fdb; -} -static void fdb_rcu_free(struct rcu_head *head) -{ - struct net_bridge_fdb_entry *ent - = container_of(head, struct net_bridge_fdb_entry, rcu); - kmem_cache_free(br_fdb_cache, ent); -} - -/* Set entry up for deletion with RCU */ -void br_fdb_put(struct net_bridge_fdb_entry *ent) -{ - if (atomic_dec_and_test(&ent->use_count)) - call_rcu(&ent->rcu, fdb_rcu_free); + return ret; } +#endif /* CONFIG_ATM_LANE */ /* * Fill buffer with forwarding table records in @@ -326,7 +326,6 @@ static struct net_bridge_fdb_entry *fdb_create(struct hlist_head *head, fdb = kmem_cache_alloc(br_fdb_cache, GFP_ATOMIC); if (fdb) { memcpy(fdb->addr.addr, addr, ETH_ALEN); - atomic_set(&fdb->use_count, 1); hlist_add_head_rcu(&fdb->hlist, head); fdb->dst = source; @@ -398,7 +397,7 @@ void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source, if (unlikely(fdb->is_local)) { if (net_ratelimit()) printk(KERN_WARNING "%s: received packet with " - " own address as source address\n", + "own address as source address\n", source->dev->name); } else { /* fastpath: update of existing entry */ diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index e4a418fcb35b..d22f611e4004 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -228,6 +228,7 @@ int nf_bridge_copy_header(struct sk_buff *skb) static int br_nf_pre_routing_finish_ipv6(struct sk_buff *skb) { struct nf_bridge_info *nf_bridge = skb->nf_bridge; + struct rtable *rt; if (nf_bridge->mask & BRNF_PKT_TYPE) { skb->pkt_type = PACKET_OTHERHOST; @@ -235,12 +236,13 @@ static int br_nf_pre_routing_finish_ipv6(struct sk_buff *skb) } nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING; - skb->rtable = bridge_parent_rtable(nf_bridge->physindev); - if (!skb->rtable) { + rt = bridge_parent_rtable(nf_bridge->physindev); + if (!rt) { kfree_skb(skb); return 0; } - dst_hold(&skb->rtable->u.dst); + dst_hold(&rt->u.dst); + skb_dst_set(skb, &rt->u.dst); skb->dev = nf_bridge->physindev; nf_bridge_push_encap_header(skb); @@ -320,7 +322,7 @@ static int br_nf_pre_routing_finish_bridge(struct sk_buff *skb) skb->dev = bridge_parent(skb->dev); if (skb->dev) { - struct dst_entry *dst = skb->dst; + struct dst_entry *dst = skb_dst(skb); nf_bridge_pull_encap_header(skb); @@ -338,6 +340,7 @@ static int br_nf_pre_routing_finish(struct sk_buff *skb) struct net_device *dev = skb->dev; struct iphdr *iph = ip_hdr(skb); struct nf_bridge_info *nf_bridge = skb->nf_bridge; + struct rtable *rt; int err; if (nf_bridge->mask & BRNF_PKT_TYPE) { @@ -347,7 +350,6 @@ static int br_nf_pre_routing_finish(struct sk_buff *skb) nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING; if (dnat_took_place(skb)) { if ((err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, dev))) { - struct rtable *rt; struct flowi fl = { .nl_u = { .ip4_u = { @@ -373,7 +375,7 @@ static int br_nf_pre_routing_finish(struct sk_buff *skb) /* - Bridged-and-DNAT'ed traffic doesn't * require ip_forwarding. */ if (((struct dst_entry *)rt)->dev == dev) { - skb->dst = (struct dst_entry *)rt; + skb_dst_set(skb, (struct dst_entry *)rt); goto bridged_dnat; } /* we are sure that forwarding is disabled, so printing @@ -387,7 +389,7 @@ free_skb: kfree_skb(skb); return 0; } else { - if (skb->dst->dev == dev) { + if (skb_dst(skb)->dev == dev) { bridged_dnat: /* Tell br_nf_local_out this is a * bridged frame */ @@ -404,12 +406,13 @@ bridged_dnat: skb->pkt_type = PACKET_HOST; } } else { - skb->rtable = bridge_parent_rtable(nf_bridge->physindev); - if (!skb->rtable) { + rt = bridge_parent_rtable(nf_bridge->physindev); + if (!rt) { kfree_skb(skb); return 0; } - dst_hold(&skb->rtable->u.dst); + dst_hold(&rt->u.dst); + skb_dst_set(skb, &rt->u.dst); } skb->dev = nf_bridge->physindev; @@ -628,10 +631,10 @@ static unsigned int br_nf_local_in(unsigned int hook, struct sk_buff *skb, const struct net_device *out, int (*okfn)(struct sk_buff *)) { - if (skb->rtable && skb->rtable == bridge_parent_rtable(in)) { - dst_release(&skb->rtable->u.dst); - skb->rtable = NULL; - } + struct rtable *rt = skb_rtable(skb); + + if (rt && rt == bridge_parent_rtable(in)) + skb_dst_drop(skb); return NF_ACCEPT; } @@ -846,7 +849,7 @@ static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff *skb, return NF_ACCEPT; #ifdef CONFIG_NETFILTER_DEBUG - if (skb->dst == NULL) { + if (skb_dst(skb) == NULL) { printk(KERN_INFO "br_netfilter post_routing: skb->dst == NULL\n"); goto print_error; } diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index b6c3b71974dc..d5b5537272b4 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -51,7 +51,6 @@ struct net_bridge_fdb_entry struct net_bridge_port *dst; struct rcu_head rcu; - atomic_t use_count; unsigned long ageing_timer; mac_addr addr; unsigned char is_local; @@ -154,9 +153,7 @@ extern void br_fdb_delete_by_port(struct net_bridge *br, const struct net_bridge_port *p, int do_all); extern struct net_bridge_fdb_entry *__br_fdb_get(struct net_bridge *br, const unsigned char *addr); -extern struct net_bridge_fdb_entry *br_fdb_get(struct net_bridge *br, - unsigned char *addr); -extern void br_fdb_put(struct net_bridge_fdb_entry *ent); +extern int br_fdb_test_addr(struct net_device *dev, unsigned char *addr); extern int br_fdb_fillbuf(struct net_bridge *br, void *buf, unsigned long count, unsigned long off); extern int br_fdb_insert(struct net_bridge *br, @@ -242,10 +239,9 @@ extern void br_stp_port_timer_init(struct net_bridge_port *p); extern unsigned long br_timer_value(const struct timer_list *timer); /* br.c */ -extern struct net_bridge_fdb_entry *(*br_fdb_get_hook)(struct net_bridge *br, - unsigned char *addr); -extern void (*br_fdb_put_hook)(struct net_bridge_fdb_entry *ent); - +#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) +extern int (*br_fdb_test_addr_hook)(struct net_device *dev, unsigned char *addr); +#endif /* br_netlink.c */ extern int br_netlink_init(void); diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c index 603d89248e71..ee4820aa1843 100644 --- a/net/bridge/br_sysfs_br.c +++ b/net/bridge/br_sysfs_br.c @@ -172,7 +172,8 @@ static ssize_t store_stp_state(struct device *d, if (endp == buf) return -EINVAL; - rtnl_lock(); + if (!rtnl_trylock()) + return restart_syscall(); br_stp_set_enabled(br, val); rtnl_unlock(); diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c index 02b2d50cce4d..4a3cdf8f3813 100644 --- a/net/bridge/br_sysfs_if.c +++ b/net/bridge/br_sysfs_if.c @@ -189,7 +189,8 @@ static ssize_t brport_store(struct kobject * kobj, val = simple_strtoul(buf, &endp, 0); if (endp != buf) { - rtnl_lock(); + if (!rtnl_trylock()) + return restart_syscall(); if (p->dev && p->br && brport_attr->store) { spin_lock_bh(&p->br->lock); ret = brport_attr->store(p, val); diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index 820252aee81f..37928d5f2840 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c @@ -142,6 +142,12 @@ static inline int ebt_basic_match(struct ebt_entry *e, struct ethhdr *h, return 0; } +static inline __pure +struct ebt_entry *ebt_next_entry(const struct ebt_entry *entry) +{ + return (void *)entry + entry->next_offset; +} + /* Do some firewalling */ unsigned int ebt_do_table (unsigned int hook, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, @@ -164,7 +170,7 @@ unsigned int ebt_do_table (unsigned int hook, struct sk_buff *skb, mtpar.in = tgpar.in = in; mtpar.out = tgpar.out = out; mtpar.hotdrop = &hotdrop; - tgpar.hooknum = hook; + mtpar.hooknum = tgpar.hooknum = hook; read_lock_bh(&table->lock); private = table->private; @@ -249,8 +255,7 @@ letsreturn: /* jump to a udc */ cs[sp].n = i + 1; cs[sp].chaininfo = chaininfo; - cs[sp].e = (struct ebt_entry *) - (((char *)point) + point->next_offset); + cs[sp].e = ebt_next_entry(point); i = 0; chaininfo = (struct ebt_entries *) (base + verdict); #ifdef CONFIG_NETFILTER_DEBUG @@ -266,8 +271,7 @@ letsreturn: sp++; continue; letscontinue: - point = (struct ebt_entry *) - (((char *)point) + point->next_offset); + point = ebt_next_entry(point); i++; } @@ -787,7 +791,7 @@ static int check_chainloops(struct ebt_entries *chain, struct ebt_cl_stack *cl_s /* this can't be 0, so the loop test is correct */ cl_s[i].cs.n = pos + 1; pos = 0; - cl_s[i].cs.e = ((void *)e + e->next_offset); + cl_s[i].cs.e = ebt_next_entry(e); e = (struct ebt_entry *)(hlp2->data); nentries = hlp2->nentries; cl_s[i].from = chain_nr; @@ -797,7 +801,7 @@ static int check_chainloops(struct ebt_entries *chain, struct ebt_cl_stack *cl_s continue; } letscontinue: - e = (void *)e + e->next_offset; + e = ebt_next_entry(e); pos++; } return 0; diff --git a/net/can/af_can.c b/net/can/af_can.c index 10f0528c3bf5..e733725b11d4 100644 --- a/net/can/af_can.c +++ b/net/can/af_can.c @@ -903,6 +903,8 @@ static __exit void can_exit(void) } spin_unlock(&can_rcvlists_lock); + rcu_barrier(); /* Wait for completion of call_rcu()'s */ + kmem_cache_destroy(rcv_cache); } diff --git a/net/core/datagram.c b/net/core/datagram.c index b01a76abe1d2..58abee1f1df1 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c @@ -260,7 +260,9 @@ int skb_kill_datagram(struct sock *sk, struct sk_buff *skb, unsigned int flags) spin_unlock_bh(&sk->sk_receive_queue.lock); } - skb_free_datagram(sk, skb); + kfree_skb(skb); + sk_mem_reclaim_partial(sk); + return err; } @@ -280,6 +282,7 @@ int skb_copy_datagram_iovec(const struct sk_buff *skb, int offset, { int start = skb_headlen(skb); int i, copy = start - offset; + struct sk_buff *frag_iter; /* Copy header. */ if (copy > 0) { @@ -320,28 +323,24 @@ int skb_copy_datagram_iovec(const struct sk_buff *skb, int offset, start = end; } - if (skb_shinfo(skb)->frag_list) { - struct sk_buff *list = skb_shinfo(skb)->frag_list; + skb_walk_frags(skb, frag_iter) { + int end; - for (; list; list = list->next) { - int end; + WARN_ON(start > offset + len); - WARN_ON(start > offset + len); - - end = start + list->len; - if ((copy = end - offset) > 0) { - if (copy > len) - copy = len; - if (skb_copy_datagram_iovec(list, - offset - start, - to, copy)) - goto fault; - if ((len -= copy) == 0) - return 0; - offset += copy; - } - start = end; + end = start + frag_iter->len; + if ((copy = end - offset) > 0) { + if (copy > len) + copy = len; + if (skb_copy_datagram_iovec(frag_iter, + offset - start, + to, copy)) + goto fault; + if ((len -= copy) == 0) + return 0; + offset += copy; } + start = end; } if (!len) return 0; @@ -351,30 +350,34 @@ fault: } /** - * skb_copy_datagram_from_iovec - Copy a datagram from an iovec. + * skb_copy_datagram_const_iovec - Copy a datagram to an iovec. * @skb: buffer to copy - * @offset: offset in the buffer to start copying to - * @from: io vector to copy to - * @len: amount of data to copy to buffer from iovec + * @offset: offset in the buffer to start copying from + * @to: io vector to copy to + * @to_offset: offset in the io vector to start copying to + * @len: amount of data to copy from buffer to iovec * * Returns 0 or -EFAULT. - * Note: the iovec is modified during the copy. + * Note: the iovec is not modified during the copy. */ -int skb_copy_datagram_from_iovec(struct sk_buff *skb, int offset, - struct iovec *from, int len) +int skb_copy_datagram_const_iovec(const struct sk_buff *skb, int offset, + const struct iovec *to, int to_offset, + int len) { int start = skb_headlen(skb); int i, copy = start - offset; + struct sk_buff *frag_iter; /* Copy header. */ if (copy > 0) { if (copy > len) copy = len; - if (memcpy_fromiovec(skb->data + offset, from, copy)) + if (memcpy_toiovecend(to, skb->data + offset, to_offset, copy)) goto fault; if ((len -= copy) == 0) return 0; offset += copy; + to_offset += copy; } /* Copy paged appendix. Hmm... why does this look so complicated? */ @@ -393,8 +396,99 @@ int skb_copy_datagram_from_iovec(struct sk_buff *skb, int offset, if (copy > len) copy = len; vaddr = kmap(page); - err = memcpy_fromiovec(vaddr + frag->page_offset + - offset - start, from, copy); + err = memcpy_toiovecend(to, vaddr + frag->page_offset + + offset - start, to_offset, copy); + kunmap(page); + if (err) + goto fault; + if (!(len -= copy)) + return 0; + offset += copy; + to_offset += copy; + } + start = end; + } + + skb_walk_frags(skb, frag_iter) { + int end; + + WARN_ON(start > offset + len); + + end = start + frag_iter->len; + if ((copy = end - offset) > 0) { + if (copy > len) + copy = len; + if (skb_copy_datagram_const_iovec(frag_iter, + offset - start, + to, to_offset, + copy)) + goto fault; + if ((len -= copy) == 0) + return 0; + offset += copy; + to_offset += copy; + } + start = end; + } + if (!len) + return 0; + +fault: + return -EFAULT; +} +EXPORT_SYMBOL(skb_copy_datagram_const_iovec); + +/** + * skb_copy_datagram_from_iovec - Copy a datagram from an iovec. + * @skb: buffer to copy + * @offset: offset in the buffer to start copying to + * @from: io vector to copy to + * @from_offset: offset in the io vector to start copying from + * @len: amount of data to copy to buffer from iovec + * + * Returns 0 or -EFAULT. + * Note: the iovec is not modified during the copy. + */ +int skb_copy_datagram_from_iovec(struct sk_buff *skb, int offset, + const struct iovec *from, int from_offset, + int len) +{ + int start = skb_headlen(skb); + int i, copy = start - offset; + struct sk_buff *frag_iter; + + /* Copy header. */ + if (copy > 0) { + if (copy > len) + copy = len; + if (memcpy_fromiovecend(skb->data + offset, from, from_offset, + copy)) + goto fault; + if ((len -= copy) == 0) + return 0; + offset += copy; + from_offset += copy; + } + + /* Copy paged appendix. Hmm... why does this look so complicated? */ + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + int end; + + WARN_ON(start > offset + len); + + end = start + skb_shinfo(skb)->frags[i].size; + if ((copy = end - offset) > 0) { + int err; + u8 *vaddr; + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + struct page *page = frag->page; + + if (copy > len) + copy = len; + vaddr = kmap(page); + err = memcpy_fromiovecend(vaddr + frag->page_offset + + offset - start, + from, from_offset, copy); kunmap(page); if (err) goto fault; @@ -402,32 +496,32 @@ int skb_copy_datagram_from_iovec(struct sk_buff *skb, int offset, if (!(len -= copy)) return 0; offset += copy; + from_offset += copy; } start = end; } - if (skb_shinfo(skb)->frag_list) { - struct sk_buff *list = skb_shinfo(skb)->frag_list; + skb_walk_frags(skb, frag_iter) { + int end; - for (; list; list = list->next) { - int end; + WARN_ON(start > offset + len); - WARN_ON(start > offset + len); - - end = start + list->len; - if ((copy = end - offset) > 0) { - if (copy > len) - copy = len; - if (skb_copy_datagram_from_iovec(list, - offset - start, - from, copy)) - goto fault; - if ((len -= copy) == 0) - return 0; - offset += copy; - } - start = end; + end = start + frag_iter->len; + if ((copy = end - offset) > 0) { + if (copy > len) + copy = len; + if (skb_copy_datagram_from_iovec(frag_iter, + offset - start, + from, + from_offset, + copy)) + goto fault; + if ((len -= copy) == 0) + return 0; + offset += copy; + from_offset += copy; } + start = end; } if (!len) return 0; @@ -442,8 +536,9 @@ static int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset, __wsum *csump) { int start = skb_headlen(skb); - int pos = 0; int i, copy = start - offset; + struct sk_buff *frag_iter; + int pos = 0; /* Copy header. */ if (copy > 0) { @@ -494,33 +589,29 @@ static int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset, start = end; } - if (skb_shinfo(skb)->frag_list) { - struct sk_buff *list = skb_shinfo(skb)->frag_list; + skb_walk_frags(skb, frag_iter) { + int end; - for (; list; list=list->next) { - int end; + WARN_ON(start > offset + len); - WARN_ON(start > offset + len); - - end = start + list->len; - if ((copy = end - offset) > 0) { - __wsum csum2 = 0; - if (copy > len) - copy = len; - if (skb_copy_and_csum_datagram(list, - offset - start, - to, copy, - &csum2)) - goto fault; - *csump = csum_block_add(*csump, csum2, pos); - if ((len -= copy) == 0) - return 0; - offset += copy; - to += copy; - pos += copy; - } - start = end; + end = start + frag_iter->len; + if ((copy = end - offset) > 0) { + __wsum csum2 = 0; + if (copy > len) + copy = len; + if (skb_copy_and_csum_datagram(frag_iter, + offset - start, + to, copy, + &csum2)) + goto fault; + *csump = csum_block_add(*csump, csum2, pos); + if ((len -= copy) == 0) + return 0; + offset += copy; + to += copy; + pos += copy; } + start = end; } if (!len) return 0; diff --git a/net/core/dev.c b/net/core/dev.c index e2e9e4af3ace..60b572812278 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -126,6 +126,7 @@ #include #include #include +#include #include "net-sysfs.h" @@ -268,7 +269,8 @@ static const unsigned short netdev_lock_type[] = ARPHRD_IRDA, ARPHRD_FCPP, ARPHRD_FCAL, ARPHRD_FCPL, ARPHRD_FCFABRIC, ARPHRD_IEEE802_TR, ARPHRD_IEEE80211, ARPHRD_IEEE80211_PRISM, ARPHRD_IEEE80211_RADIOTAP, ARPHRD_PHONET, - ARPHRD_PHONET_PIPE, ARPHRD_VOID, ARPHRD_NONE}; + ARPHRD_PHONET_PIPE, ARPHRD_IEEE802154, ARPHRD_IEEE802154_PHY, + ARPHRD_VOID, ARPHRD_NONE}; static const char *netdev_lock_name[] = {"_xmit_NETROM", "_xmit_ETHER", "_xmit_EETHER", "_xmit_AX25", @@ -285,7 +287,8 @@ static const char *netdev_lock_name[] = "_xmit_IRDA", "_xmit_FCPP", "_xmit_FCAL", "_xmit_FCPL", "_xmit_FCFABRIC", "_xmit_IEEE802_TR", "_xmit_IEEE80211", "_xmit_IEEE80211_PRISM", "_xmit_IEEE80211_RADIOTAP", "_xmit_PHONET", - "_xmit_PHONET_PIPE", "_xmit_VOID", "_xmit_NONE"}; + "_xmit_PHONET_PIPE", "_xmit_IEEE802154", "_xmit_IEEE802154_PHY", + "_xmit_VOID", "_xmit_NONE"}; static struct lock_class_key netdev_xmit_lock_key[ARRAY_SIZE(netdev_lock_type)]; static struct lock_class_key netdev_addr_lock_key[ARRAY_SIZE(netdev_lock_type)]; @@ -1047,7 +1050,7 @@ void dev_load(struct net *net, const char *name) int dev_open(struct net_device *dev) { const struct net_device_ops *ops = dev->netdev_ops; - int ret = 0; + int ret; ASSERT_RTNL(); @@ -1064,6 +1067,11 @@ int dev_open(struct net_device *dev) if (!netif_device_present(dev)) return -ENODEV; + ret = call_netdevice_notifiers(NETDEV_PRE_UP, dev); + ret = notifier_to_errno(ret); + if (ret) + return ret; + /* * Call device private open method */ @@ -1688,7 +1696,16 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, goto gso; } + /* + * If device doesnt need skb->dst, release it right now while + * its hot in this cpu cache + */ + if (dev->priv_flags & IFF_XMIT_DST_RELEASE) + skb_dst_drop(skb); + rc = ops->ndo_start_xmit(skb, dev); + if (rc == 0) + txq_trans_update(txq); /* * TODO: if skb_orphan() was called by * dev->hard_start_xmit() (for example, the unmodified @@ -1718,6 +1735,7 @@ gso: skb->next = nskb; return rc; } + txq_trans_update(txq); if (unlikely(netif_tx_queue_stopped(txq) && skb->next)) return NETDEV_TX_BUSY; } while (skb->next); @@ -1735,8 +1753,12 @@ u16 skb_tx_hash(const struct net_device *dev, const struct sk_buff *skb) { u32 hash; - if (skb_rx_queue_recorded(skb)) - return skb_get_rx_queue(skb) % dev->real_num_tx_queues; + if (skb_rx_queue_recorded(skb)) { + hash = skb_get_rx_queue(skb); + while (unlikely (hash >= dev->real_num_tx_queues)) + hash -= dev->real_num_tx_queues; + return hash; + } if (skb->sk && skb->sk->sk_hash) hash = skb->sk->sk_hash; @@ -1800,7 +1822,7 @@ int dev_queue_xmit(struct sk_buff *skb) if (netif_needs_gso(dev, skb)) goto gso; - if (skb_shinfo(skb)->frag_list && + if (skb_has_frags(skb) && !(dev->features & NETIF_F_FRAGLIST) && __skb_linearize(skb)) goto out_kfree_skb; @@ -2049,11 +2071,13 @@ static inline int deliver_skb(struct sk_buff *skb, } #if defined(CONFIG_BRIDGE) || defined (CONFIG_BRIDGE_MODULE) -/* These hooks defined here for ATM */ -struct net_bridge; -struct net_bridge_fdb_entry *(*br_fdb_get_hook)(struct net_bridge *br, - unsigned char *addr); -void (*br_fdb_put_hook)(struct net_bridge_fdb_entry *ent) __read_mostly; + +#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) +/* This hook is defined here for ATM LANE */ +int (*br_fdb_test_addr_hook)(struct net_device *dev, + unsigned char *addr) __read_mostly; +EXPORT_SYMBOL(br_fdb_test_addr_hook); +#endif /* * If bridge module is loaded call bridging hook. @@ -2061,6 +2085,8 @@ void (*br_fdb_put_hook)(struct net_bridge_fdb_entry *ent) __read_mostly; */ struct sk_buff *(*br_handle_frame_hook)(struct net_bridge_port *p, struct sk_buff *skb) __read_mostly; +EXPORT_SYMBOL(br_handle_frame_hook); + static inline struct sk_buff *handle_bridge(struct sk_buff *skb, struct packet_type **pt_prev, int *ret, struct net_device *orig_dev) @@ -2284,8 +2310,6 @@ ncls: if (!skb) goto out; - skb_orphan(skb); - type = skb->protocol; list_for_each_entry_rcu(ptype, &ptype_base[ntohs(type) & PTYPE_HASH_MASK], list) { @@ -2374,26 +2398,6 @@ void napi_gro_flush(struct napi_struct *napi) } EXPORT_SYMBOL(napi_gro_flush); -void *skb_gro_header(struct sk_buff *skb, unsigned int hlen) -{ - unsigned int offset = skb_gro_offset(skb); - - hlen += offset; - if (hlen <= skb_headlen(skb)) - return skb->data + offset; - - if (unlikely(!skb_shinfo(skb)->nr_frags || - skb_shinfo(skb)->frags[0].size <= - hlen - skb_headlen(skb) || - PageHighMem(skb_shinfo(skb)->frags[0].page))) - return pskb_may_pull(skb, hlen) ? skb->data + offset : NULL; - - return page_address(skb_shinfo(skb)->frags[0].page) + - skb_shinfo(skb)->frags[0].page_offset + - offset - skb_headlen(skb); -} -EXPORT_SYMBOL(skb_gro_header); - int dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb) { struct sk_buff **pp = NULL; @@ -2407,7 +2411,7 @@ int dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb) if (!(skb->dev->features & NETIF_F_GRO)) goto normal; - if (skb_is_gso(skb) || skb_shinfo(skb)->frag_list) + if (skb_is_gso(skb) || skb_has_frags(skb)) goto normal; rcu_read_lock(); @@ -2456,10 +2460,25 @@ int dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb) ret = GRO_HELD; pull: - if (unlikely(!pskb_may_pull(skb, skb_gro_offset(skb)))) { - if (napi->gro_list == skb) - napi->gro_list = skb->next; - ret = GRO_DROP; + if (skb_headlen(skb) < skb_gro_offset(skb)) { + int grow = skb_gro_offset(skb) - skb_headlen(skb); + + BUG_ON(skb->end - skb->tail < grow); + + memcpy(skb_tail_pointer(skb), NAPI_GRO_CB(skb)->frag0, grow); + + skb->tail += grow; + skb->data_len -= grow; + + skb_shinfo(skb)->frags[0].page_offset += grow; + skb_shinfo(skb)->frags[0].size -= grow; + + if (unlikely(!skb_shinfo(skb)->frags[0].size)) { + put_page(skb_shinfo(skb)->frags[0].page); + memmove(skb_shinfo(skb)->frags, + skb_shinfo(skb)->frags + 1, + --skb_shinfo(skb)->nr_frags); + } } ok: @@ -2509,6 +2528,22 @@ int napi_skb_finish(int ret, struct sk_buff *skb) } EXPORT_SYMBOL(napi_skb_finish); +void skb_gro_reset_offset(struct sk_buff *skb) +{ + NAPI_GRO_CB(skb)->data_offset = 0; + NAPI_GRO_CB(skb)->frag0 = NULL; + NAPI_GRO_CB(skb)->frag0_len = 0; + + if (skb->mac_header == skb->tail && + !PageHighMem(skb_shinfo(skb)->frags[0].page)) { + NAPI_GRO_CB(skb)->frag0 = + page_address(skb_shinfo(skb)->frags[0].page) + + skb_shinfo(skb)->frags[0].page_offset; + NAPI_GRO_CB(skb)->frag0_len = skb_shinfo(skb)->frags[0].size; + } +} +EXPORT_SYMBOL(skb_gro_reset_offset); + int napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb) { skb_gro_reset_offset(skb); @@ -2526,16 +2561,10 @@ void napi_reuse_skb(struct napi_struct *napi, struct sk_buff *skb) } EXPORT_SYMBOL(napi_reuse_skb); -struct sk_buff *napi_fraginfo_skb(struct napi_struct *napi, - struct napi_gro_fraginfo *info) +struct sk_buff *napi_get_frags(struct napi_struct *napi) { struct net_device *dev = napi->dev; struct sk_buff *skb = napi->skb; - struct ethhdr *eth; - skb_frag_t *frag; - int i; - - napi->skb = NULL; if (!skb) { skb = netdev_alloc_skb(dev, GRO_MAX_HEAD + NET_IP_ALIGN); @@ -2543,47 +2572,14 @@ struct sk_buff *napi_fraginfo_skb(struct napi_struct *napi, goto out; skb_reserve(skb, NET_IP_ALIGN); + + napi->skb = skb; } - BUG_ON(info->nr_frags > MAX_SKB_FRAGS); - frag = info->frags; - - for (i = 0; i < info->nr_frags; i++) { - skb_fill_page_desc(skb, i, frag->page, frag->page_offset, - frag->size); - frag++; - } - skb_shinfo(skb)->nr_frags = info->nr_frags; - - skb->data_len = info->len; - skb->len += info->len; - skb->truesize += info->len; - - skb_reset_mac_header(skb); - skb_gro_reset_offset(skb); - - eth = skb_gro_header(skb, sizeof(*eth)); - if (!eth) { - napi_reuse_skb(napi, skb); - skb = NULL; - goto out; - } - - skb_gro_pull(skb, sizeof(*eth)); - - /* - * This works because the only protocols we care about don't require - * special handling. We'll fix it up properly at the end. - */ - skb->protocol = eth->h_proto; - - skb->ip_summed = info->ip_summed; - skb->csum = info->csum; - out: return skb; } -EXPORT_SYMBOL(napi_fraginfo_skb); +EXPORT_SYMBOL(napi_get_frags); int napi_frags_finish(struct napi_struct *napi, struct sk_buff *skb, int ret) { @@ -2613,9 +2609,46 @@ int napi_frags_finish(struct napi_struct *napi, struct sk_buff *skb, int ret) } EXPORT_SYMBOL(napi_frags_finish); -int napi_gro_frags(struct napi_struct *napi, struct napi_gro_fraginfo *info) +struct sk_buff *napi_frags_skb(struct napi_struct *napi) { - struct sk_buff *skb = napi_fraginfo_skb(napi, info); + struct sk_buff *skb = napi->skb; + struct ethhdr *eth; + unsigned int hlen; + unsigned int off; + + napi->skb = NULL; + + skb_reset_mac_header(skb); + skb_gro_reset_offset(skb); + + off = skb_gro_offset(skb); + hlen = off + sizeof(*eth); + eth = skb_gro_header_fast(skb, off); + if (skb_gro_header_hard(skb, hlen)) { + eth = skb_gro_header_slow(skb, hlen, off); + if (unlikely(!eth)) { + napi_reuse_skb(napi, skb); + skb = NULL; + goto out; + } + } + + skb_gro_pull(skb, sizeof(*eth)); + + /* + * This works because the only protocols we care about don't require + * special handling. We'll fix it up properly at the end. + */ + skb->protocol = eth->h_proto; + +out: + return skb; +} +EXPORT_SYMBOL(napi_frags_skb); + +int napi_gro_frags(struct napi_struct *napi) +{ + struct sk_buff *skb = napi_frags_skb(napi); if (!skb) return NET_RX_DROP; @@ -2719,7 +2752,7 @@ void netif_napi_del(struct napi_struct *napi) struct sk_buff *skb, *next; list_del_init(&napi->dev_list); - kfree_skb(napi->skb); + napi_free_frags(napi); for (skb = napi->gro_list; skb; skb = next) { next = skb->next; @@ -2773,8 +2806,10 @@ static void net_rx_action(struct softirq_action *h) * accidently calling ->poll() when NAPI is not scheduled. */ work = 0; - if (test_bit(NAPI_STATE_SCHED, &n->state)) + if (test_bit(NAPI_STATE_SCHED, &n->state)) { work = n->poll(n, weight); + trace_napi_poll(n); + } WARN_ON_ONCE(work > weight); @@ -3424,10 +3459,10 @@ void __dev_set_rx_mode(struct net_device *dev) /* Unicast addresses changes may only happen under the rtnl, * therefore calling __dev_set_promiscuity here is safe. */ - if (dev->uc_count > 0 && !dev->uc_promisc) { + if (dev->uc.count > 0 && !dev->uc_promisc) { __dev_set_promiscuity(dev, 1); dev->uc_promisc = 1; - } else if (dev->uc_count == 0 && dev->uc_promisc) { + } else if (dev->uc.count == 0 && dev->uc_promisc) { __dev_set_promiscuity(dev, -1); dev->uc_promisc = 0; } @@ -3444,6 +3479,316 @@ void dev_set_rx_mode(struct net_device *dev) netif_addr_unlock_bh(dev); } +/* hw addresses list handling functions */ + +static int __hw_addr_add(struct netdev_hw_addr_list *list, unsigned char *addr, + int addr_len, unsigned char addr_type) +{ + struct netdev_hw_addr *ha; + int alloc_size; + + if (addr_len > MAX_ADDR_LEN) + return -EINVAL; + + list_for_each_entry(ha, &list->list, list) { + if (!memcmp(ha->addr, addr, addr_len) && + ha->type == addr_type) { + ha->refcount++; + return 0; + } + } + + + alloc_size = sizeof(*ha); + if (alloc_size < L1_CACHE_BYTES) + alloc_size = L1_CACHE_BYTES; + ha = kmalloc(alloc_size, GFP_ATOMIC); + if (!ha) + return -ENOMEM; + memcpy(ha->addr, addr, addr_len); + ha->type = addr_type; + ha->refcount = 1; + ha->synced = false; + list_add_tail_rcu(&ha->list, &list->list); + list->count++; + return 0; +} + +static void ha_rcu_free(struct rcu_head *head) +{ + struct netdev_hw_addr *ha; + + ha = container_of(head, struct netdev_hw_addr, rcu_head); + kfree(ha); +} + +static int __hw_addr_del(struct netdev_hw_addr_list *list, unsigned char *addr, + int addr_len, unsigned char addr_type) +{ + struct netdev_hw_addr *ha; + + list_for_each_entry(ha, &list->list, list) { + if (!memcmp(ha->addr, addr, addr_len) && + (ha->type == addr_type || !addr_type)) { + if (--ha->refcount) + return 0; + list_del_rcu(&ha->list); + call_rcu(&ha->rcu_head, ha_rcu_free); + list->count--; + return 0; + } + } + return -ENOENT; +} + +static int __hw_addr_add_multiple(struct netdev_hw_addr_list *to_list, + struct netdev_hw_addr_list *from_list, + int addr_len, + unsigned char addr_type) +{ + int err; + struct netdev_hw_addr *ha, *ha2; + unsigned char type; + + list_for_each_entry(ha, &from_list->list, list) { + type = addr_type ? addr_type : ha->type; + err = __hw_addr_add(to_list, ha->addr, addr_len, type); + if (err) + goto unroll; + } + return 0; + +unroll: + list_for_each_entry(ha2, &from_list->list, list) { + if (ha2 == ha) + break; + type = addr_type ? addr_type : ha2->type; + __hw_addr_del(to_list, ha2->addr, addr_len, type); + } + return err; +} + +static void __hw_addr_del_multiple(struct netdev_hw_addr_list *to_list, + struct netdev_hw_addr_list *from_list, + int addr_len, + unsigned char addr_type) +{ + struct netdev_hw_addr *ha; + unsigned char type; + + list_for_each_entry(ha, &from_list->list, list) { + type = addr_type ? addr_type : ha->type; + __hw_addr_del(to_list, ha->addr, addr_len, addr_type); + } +} + +static int __hw_addr_sync(struct netdev_hw_addr_list *to_list, + struct netdev_hw_addr_list *from_list, + int addr_len) +{ + int err = 0; + struct netdev_hw_addr *ha, *tmp; + + list_for_each_entry_safe(ha, tmp, &from_list->list, list) { + if (!ha->synced) { + err = __hw_addr_add(to_list, ha->addr, + addr_len, ha->type); + if (err) + break; + ha->synced = true; + ha->refcount++; + } else if (ha->refcount == 1) { + __hw_addr_del(to_list, ha->addr, addr_len, ha->type); + __hw_addr_del(from_list, ha->addr, addr_len, ha->type); + } + } + return err; +} + +static void __hw_addr_unsync(struct netdev_hw_addr_list *to_list, + struct netdev_hw_addr_list *from_list, + int addr_len) +{ + struct netdev_hw_addr *ha, *tmp; + + list_for_each_entry_safe(ha, tmp, &from_list->list, list) { + if (ha->synced) { + __hw_addr_del(to_list, ha->addr, + addr_len, ha->type); + ha->synced = false; + __hw_addr_del(from_list, ha->addr, + addr_len, ha->type); + } + } +} + +static void __hw_addr_flush(struct netdev_hw_addr_list *list) +{ + struct netdev_hw_addr *ha, *tmp; + + list_for_each_entry_safe(ha, tmp, &list->list, list) { + list_del_rcu(&ha->list); + call_rcu(&ha->rcu_head, ha_rcu_free); + } + list->count = 0; +} + +static void __hw_addr_init(struct netdev_hw_addr_list *list) +{ + INIT_LIST_HEAD(&list->list); + list->count = 0; +} + +/* Device addresses handling functions */ + +static void dev_addr_flush(struct net_device *dev) +{ + /* rtnl_mutex must be held here */ + + __hw_addr_flush(&dev->dev_addrs); + dev->dev_addr = NULL; +} + +static int dev_addr_init(struct net_device *dev) +{ + unsigned char addr[MAX_ADDR_LEN]; + struct netdev_hw_addr *ha; + int err; + + /* rtnl_mutex must be held here */ + + __hw_addr_init(&dev->dev_addrs); + memset(addr, 0, sizeof(addr)); + err = __hw_addr_add(&dev->dev_addrs, addr, sizeof(addr), + NETDEV_HW_ADDR_T_LAN); + if (!err) { + /* + * Get the first (previously created) address from the list + * and set dev_addr pointer to this location. + */ + ha = list_first_entry(&dev->dev_addrs.list, + struct netdev_hw_addr, list); + dev->dev_addr = ha->addr; + } + return err; +} + +/** + * dev_addr_add - Add a device address + * @dev: device + * @addr: address to add + * @addr_type: address type + * + * Add a device address to the device or increase the reference count if + * it already exists. + * + * The caller must hold the rtnl_mutex. + */ +int dev_addr_add(struct net_device *dev, unsigned char *addr, + unsigned char addr_type) +{ + int err; + + ASSERT_RTNL(); + + err = __hw_addr_add(&dev->dev_addrs, addr, dev->addr_len, addr_type); + if (!err) + call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); + return err; +} +EXPORT_SYMBOL(dev_addr_add); + +/** + * dev_addr_del - Release a device address. + * @dev: device + * @addr: address to delete + * @addr_type: address type + * + * Release reference to a device address and remove it from the device + * if the reference count drops to zero. + * + * The caller must hold the rtnl_mutex. + */ +int dev_addr_del(struct net_device *dev, unsigned char *addr, + unsigned char addr_type) +{ + int err; + struct netdev_hw_addr *ha; + + ASSERT_RTNL(); + + /* + * We can not remove the first address from the list because + * dev->dev_addr points to that. + */ + ha = list_first_entry(&dev->dev_addrs.list, + struct netdev_hw_addr, list); + if (ha->addr == dev->dev_addr && ha->refcount == 1) + return -ENOENT; + + err = __hw_addr_del(&dev->dev_addrs, addr, dev->addr_len, + addr_type); + if (!err) + call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); + return err; +} +EXPORT_SYMBOL(dev_addr_del); + +/** + * dev_addr_add_multiple - Add device addresses from another device + * @to_dev: device to which addresses will be added + * @from_dev: device from which addresses will be added + * @addr_type: address type - 0 means type will be used from from_dev + * + * Add device addresses of the one device to another. + ** + * The caller must hold the rtnl_mutex. + */ +int dev_addr_add_multiple(struct net_device *to_dev, + struct net_device *from_dev, + unsigned char addr_type) +{ + int err; + + ASSERT_RTNL(); + + if (from_dev->addr_len != to_dev->addr_len) + return -EINVAL; + err = __hw_addr_add_multiple(&to_dev->dev_addrs, &from_dev->dev_addrs, + to_dev->addr_len, addr_type); + if (!err) + call_netdevice_notifiers(NETDEV_CHANGEADDR, to_dev); + return err; +} +EXPORT_SYMBOL(dev_addr_add_multiple); + +/** + * dev_addr_del_multiple - Delete device addresses by another device + * @to_dev: device where the addresses will be deleted + * @from_dev: device by which addresses the addresses will be deleted + * @addr_type: address type - 0 means type will used from from_dev + * + * Deletes addresses in to device by the list of addresses in from device. + * + * The caller must hold the rtnl_mutex. + */ +int dev_addr_del_multiple(struct net_device *to_dev, + struct net_device *from_dev, + unsigned char addr_type) +{ + ASSERT_RTNL(); + + if (from_dev->addr_len != to_dev->addr_len) + return -EINVAL; + __hw_addr_del_multiple(&to_dev->dev_addrs, &from_dev->dev_addrs, + to_dev->addr_len, addr_type); + call_netdevice_notifiers(NETDEV_CHANGEADDR, to_dev); + return 0; +} +EXPORT_SYMBOL(dev_addr_del_multiple); + +/* multicast addresses handling functions */ + int __dev_addr_delete(struct dev_addr_list **list, int *count, void *addr, int alen, int glbl) { @@ -3506,24 +3851,22 @@ int __dev_addr_add(struct dev_addr_list **list, int *count, * dev_unicast_delete - Release secondary unicast address. * @dev: device * @addr: address to delete - * @alen: length of @addr * * Release reference to a secondary unicast address and remove it * from the device if the reference count drops to zero. * * The caller must hold the rtnl_mutex. */ -int dev_unicast_delete(struct net_device *dev, void *addr, int alen) +int dev_unicast_delete(struct net_device *dev, void *addr) { int err; ASSERT_RTNL(); - netif_addr_lock_bh(dev); - err = __dev_addr_delete(&dev->uc_list, &dev->uc_count, addr, alen, 0); + err = __hw_addr_del(&dev->uc, addr, dev->addr_len, + NETDEV_HW_ADDR_T_UNICAST); if (!err) __dev_set_rx_mode(dev); - netif_addr_unlock_bh(dev); return err; } EXPORT_SYMBOL(dev_unicast_delete); @@ -3532,24 +3875,22 @@ EXPORT_SYMBOL(dev_unicast_delete); * dev_unicast_add - add a secondary unicast address * @dev: device * @addr: address to add - * @alen: length of @addr * * Add a secondary unicast address to the device or increase * the reference count if it already exists. * * The caller must hold the rtnl_mutex. */ -int dev_unicast_add(struct net_device *dev, void *addr, int alen) +int dev_unicast_add(struct net_device *dev, void *addr) { int err; ASSERT_RTNL(); - netif_addr_lock_bh(dev); - err = __dev_addr_add(&dev->uc_list, &dev->uc_count, addr, alen, 0); + err = __hw_addr_add(&dev->uc, addr, dev->addr_len, + NETDEV_HW_ADDR_T_UNICAST); if (!err) __dev_set_rx_mode(dev); - netif_addr_unlock_bh(dev); return err; } EXPORT_SYMBOL(dev_unicast_add); @@ -3606,8 +3947,7 @@ void __dev_addr_unsync(struct dev_addr_list **to, int *to_count, * @from: source device * * Add newly added addresses to the destination device and release - * addresses that have no users left. The source device must be - * locked by netif_tx_lock_bh. + * addresses that have no users left. * * This function is intended to be called from the dev->set_rx_mode * function of layered software devices. @@ -3616,12 +3956,14 @@ int dev_unicast_sync(struct net_device *to, struct net_device *from) { int err = 0; - netif_addr_lock_bh(to); - err = __dev_addr_sync(&to->uc_list, &to->uc_count, - &from->uc_list, &from->uc_count); + ASSERT_RTNL(); + + if (to->addr_len != from->addr_len) + return -EINVAL; + + err = __hw_addr_sync(&to->uc, &from->uc, to->addr_len); if (!err) __dev_set_rx_mode(to); - netif_addr_unlock_bh(to); return err; } EXPORT_SYMBOL(dev_unicast_sync); @@ -3637,18 +3979,31 @@ EXPORT_SYMBOL(dev_unicast_sync); */ void dev_unicast_unsync(struct net_device *to, struct net_device *from) { - netif_addr_lock_bh(from); - netif_addr_lock(to); + ASSERT_RTNL(); - __dev_addr_unsync(&to->uc_list, &to->uc_count, - &from->uc_list, &from->uc_count); + if (to->addr_len != from->addr_len) + return; + + __hw_addr_unsync(&to->uc, &from->uc, to->addr_len); __dev_set_rx_mode(to); - - netif_addr_unlock(to); - netif_addr_unlock_bh(from); } EXPORT_SYMBOL(dev_unicast_unsync); +static void dev_unicast_flush(struct net_device *dev) +{ + /* rtnl_mutex must be held here */ + + __hw_addr_flush(&dev->uc); +} + +static void dev_unicast_init(struct net_device *dev) +{ + /* rtnl_mutex must be held here */ + + __hw_addr_init(&dev->uc); +} + + static void __dev_addr_discard(struct dev_addr_list **list) { struct dev_addr_list *tmp; @@ -3667,9 +4022,6 @@ static void dev_addr_discard(struct net_device *dev) { netif_addr_lock_bh(dev); - __dev_addr_discard(&dev->uc_list); - dev->uc_count = 0; - __dev_addr_discard(&dev->mc_list); dev->mc_count = 0; @@ -3853,7 +4205,7 @@ static int dev_ifsioc_locked(struct net *net, struct ifreq *ifr, unsigned int cm switch (cmd) { case SIOCGIFFLAGS: /* Get interface flags */ - ifr->ifr_flags = dev_get_flags(dev); + ifr->ifr_flags = (short) dev_get_flags(dev); return 0; case SIOCGIFMETRIC: /* Get the metric on the interface @@ -4262,6 +4614,7 @@ static void rollback_registered(struct net_device *dev) /* * Flush the unicast and multicast chains */ + dev_unicast_flush(dev); dev_addr_discard(dev); if (dev->netdev_ops->ndo_uninit) @@ -4333,39 +4686,6 @@ unsigned long netdev_fix_features(unsigned long features, const char *name) } EXPORT_SYMBOL(netdev_fix_features); -/* Some devices need to (re-)set their netdev_ops inside - * ->init() or similar. If that happens, we have to setup - * the compat pointers again. - */ -void netdev_resync_ops(struct net_device *dev) -{ -#ifdef CONFIG_COMPAT_NET_DEV_OPS - const struct net_device_ops *ops = dev->netdev_ops; - - dev->init = ops->ndo_init; - dev->uninit = ops->ndo_uninit; - dev->open = ops->ndo_open; - dev->change_rx_flags = ops->ndo_change_rx_flags; - dev->set_rx_mode = ops->ndo_set_rx_mode; - dev->set_multicast_list = ops->ndo_set_multicast_list; - dev->set_mac_address = ops->ndo_set_mac_address; - dev->validate_addr = ops->ndo_validate_addr; - dev->do_ioctl = ops->ndo_do_ioctl; - dev->set_config = ops->ndo_set_config; - dev->change_mtu = ops->ndo_change_mtu; - dev->neigh_setup = ops->ndo_neigh_setup; - dev->tx_timeout = ops->ndo_tx_timeout; - dev->get_stats = ops->ndo_get_stats; - dev->vlan_rx_register = ops->ndo_vlan_rx_register; - dev->vlan_rx_add_vid = ops->ndo_vlan_rx_add_vid; - dev->vlan_rx_kill_vid = ops->ndo_vlan_rx_kill_vid; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = ops->ndo_poll_controller; -#endif -#endif -} -EXPORT_SYMBOL(netdev_resync_ops); - /** * register_netdevice - register a network device * @dev: device to register @@ -4405,23 +4725,6 @@ int register_netdevice(struct net_device *dev) dev->iflink = -1; -#ifdef CONFIG_COMPAT_NET_DEV_OPS - /* Netdevice_ops API compatibility support. - * This is temporary until all network devices are converted. - */ - if (dev->netdev_ops) { - netdev_resync_ops(dev); - } else { - char drivername[64]; - pr_info("%s (%s): not using net_device_ops yet\n", - dev->name, netdev_drivername(dev, drivername, 64)); - - /* This works only because net_device_ops and the - compatibility structure are the same. */ - dev->netdev_ops = (void *) &(dev->init); - } -#endif - /* Init, if this function is available */ if (dev->netdev_ops->ndo_init) { ret = dev->netdev_ops->ndo_init(dev); @@ -4707,13 +5010,30 @@ void netdev_run_todo(void) * the internal statistics structure is used. */ const struct net_device_stats *dev_get_stats(struct net_device *dev) - { +{ const struct net_device_ops *ops = dev->netdev_ops; if (ops->ndo_get_stats) return ops->ndo_get_stats(dev); - else - return &dev->stats; + else { + unsigned long tx_bytes = 0, tx_packets = 0, tx_dropped = 0; + struct net_device_stats *stats = &dev->stats; + unsigned int i; + struct netdev_queue *txq; + + for (i = 0; i < dev->num_tx_queues; i++) { + txq = netdev_get_tx_queue(dev, i); + tx_bytes += txq->tx_bytes; + tx_packets += txq->tx_packets; + tx_dropped += txq->tx_dropped; + } + if (tx_bytes || tx_packets || tx_dropped) { + stats->tx_bytes = tx_bytes; + stats->tx_packets = tx_packets; + stats->tx_dropped = tx_dropped; + } + return stats; + } } EXPORT_SYMBOL(dev_get_stats); @@ -4748,18 +5068,18 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name, struct netdev_queue *tx; struct net_device *dev; size_t alloc_size; - void *p; + struct net_device *p; BUG_ON(strlen(name) >= sizeof(dev->name)); alloc_size = sizeof(struct net_device); if (sizeof_priv) { /* ensure 32-byte alignment of private area */ - alloc_size = (alloc_size + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST; + alloc_size = ALIGN(alloc_size, NETDEV_ALIGN); alloc_size += sizeof_priv; } /* ensure 32-byte alignment of whole construct */ - alloc_size += NETDEV_ALIGN_CONST; + alloc_size += NETDEV_ALIGN - 1; p = kzalloc(alloc_size, GFP_KERNEL); if (!p) { @@ -4771,13 +5091,17 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name, if (!tx) { printk(KERN_ERR "alloc_netdev: Unable to allocate " "tx qdiscs.\n"); - kfree(p); - return NULL; + goto free_p; } - dev = (struct net_device *) - (((long)p + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST); + dev = PTR_ALIGN(p, NETDEV_ALIGN); dev->padded = (char *)dev - (char *)p; + + if (dev_addr_init(dev)) + goto free_tx; + + dev_unicast_init(dev); + dev_net_set(dev, &init_net); dev->_tx = tx; @@ -4789,9 +5113,17 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name, netdev_init_queues(dev); INIT_LIST_HEAD(&dev->napi_list); + dev->priv_flags = IFF_XMIT_DST_RELEASE; setup(dev); strcpy(dev->name, name); return dev; + +free_tx: + kfree(tx); + +free_p: + kfree(p); + return NULL; } EXPORT_SYMBOL(alloc_netdev_mq); @@ -4811,6 +5143,9 @@ void free_netdev(struct net_device *dev) kfree(dev->_tx); + /* Flush device addresses */ + dev_addr_flush(dev); + list_for_each_entry_safe(p, n, &dev->napi_list, dev_list) netif_napi_del(p); @@ -4970,6 +5305,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char /* * Flush the unicast and multicast chains */ + dev_unicast_flush(dev); dev_addr_discard(dev); netdev_unregister_kobject(dev); @@ -5325,12 +5661,6 @@ EXPORT_SYMBOL(net_enable_timestamp); EXPORT_SYMBOL(net_disable_timestamp); EXPORT_SYMBOL(dev_get_flags); -#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) -EXPORT_SYMBOL(br_handle_frame_hook); -EXPORT_SYMBOL(br_fdb_get_hook); -EXPORT_SYMBOL(br_fdb_put_hook); -#endif - EXPORT_SYMBOL(dev_load); EXPORT_PER_CPU_SYMBOL(softnet_data); diff --git a/net/core/drop_monitor.c b/net/core/drop_monitor.c index 9fd0dc3cca99..9d66fa953ab7 100644 --- a/net/core/drop_monitor.c +++ b/net/core/drop_monitor.c @@ -22,8 +22,10 @@ #include #include #include +#include -#include +#include +#include #include @@ -38,7 +40,8 @@ static void send_dm_alert(struct work_struct *unused); * and the work handle that will send up * netlink alerts */ -struct sock *dm_sock; +static int trace_state = TRACE_OFF; +static spinlock_t trace_state_lock = SPIN_LOCK_UNLOCKED; struct per_cpu_dm_data { struct work_struct dm_alert_work; @@ -47,11 +50,18 @@ struct per_cpu_dm_data { struct timer_list send_timer; }; +struct dm_hw_stat_delta { + struct net_device *dev; + struct list_head list; + struct rcu_head rcu; + unsigned long last_drop_val; +}; + static struct genl_family net_drop_monitor_family = { .id = GENL_ID_GENERATE, .hdrsize = 0, .name = "NET_DM", - .version = 1, + .version = 2, .maxattr = NET_DM_CMD_MAX, }; @@ -59,19 +69,24 @@ static DEFINE_PER_CPU(struct per_cpu_dm_data, dm_cpu_data); static int dm_hit_limit = 64; static int dm_delay = 1; - +static unsigned long dm_hw_check_delta = 2*HZ; +static LIST_HEAD(hw_stats_list); static void reset_per_cpu_data(struct per_cpu_dm_data *data) { size_t al; struct net_dm_alert_msg *msg; + struct nlattr *nla; al = sizeof(struct net_dm_alert_msg); al += dm_hit_limit * sizeof(struct net_dm_drop_point); + al += sizeof(struct nlattr); + data->skb = genlmsg_new(al, GFP_KERNEL); genlmsg_put(data->skb, 0, 0, &net_drop_monitor_family, 0, NET_DM_CMD_ALERT); - msg = __nla_reserve_nohdr(data->skb, sizeof(struct net_dm_alert_msg)); + nla = nla_reserve(data->skb, NLA_UNSPEC, sizeof(struct net_dm_alert_msg)); + msg = nla_data(nla); memset(msg, 0, al); atomic_set(&data->dm_hit_count, dm_hit_limit); } @@ -111,10 +126,11 @@ static void sched_send_work(unsigned long unused) schedule_work(&data->dm_alert_work); } -static void trace_kfree_skb_hit(struct sk_buff *skb, void *location) +static void trace_drop_common(struct sk_buff *skb, void *location) { struct net_dm_alert_msg *msg; struct nlmsghdr *nlh; + struct nlattr *nla; int i; struct per_cpu_dm_data *data = &__get_cpu_var(dm_cpu_data); @@ -127,7 +143,8 @@ static void trace_kfree_skb_hit(struct sk_buff *skb, void *location) } nlh = (struct nlmsghdr *)data->skb->data; - msg = genlmsg_data(nlmsg_data(nlh)); + nla = genlmsg_data(nlmsg_data(nlh)); + msg = nla_data(nla); for (i = 0; i < msg->entries; i++) { if (!memcmp(&location, msg->points[i].pc, sizeof(void *))) { msg->points[i].count++; @@ -139,6 +156,7 @@ static void trace_kfree_skb_hit(struct sk_buff *skb, void *location) * We need to create a new entry */ __nla_reserve_nohdr(data->skb, sizeof(struct net_dm_drop_point)); + nla->nla_len += NLA_ALIGN(sizeof(struct net_dm_drop_point)); memcpy(msg->points[msg->entries].pc, &location, sizeof(void *)); msg->points[msg->entries].count = 1; msg->entries++; @@ -152,24 +170,80 @@ out: return; } +static void trace_kfree_skb_hit(struct sk_buff *skb, void *location) +{ + trace_drop_common(skb, location); +} + +static void trace_napi_poll_hit(struct napi_struct *napi) +{ + struct dm_hw_stat_delta *new_stat; + + /* + * Ratelimit our check time to dm_hw_check_delta jiffies + */ + if (!time_after(jiffies, napi->dev->last_rx + dm_hw_check_delta)) + return; + + rcu_read_lock(); + list_for_each_entry_rcu(new_stat, &hw_stats_list, list) { + if ((new_stat->dev == napi->dev) && + (napi->dev->stats.rx_dropped != new_stat->last_drop_val)) { + trace_drop_common(NULL, NULL); + new_stat->last_drop_val = napi->dev->stats.rx_dropped; + break; + } + } + rcu_read_unlock(); +} + + +static void free_dm_hw_stat(struct rcu_head *head) +{ + struct dm_hw_stat_delta *n; + n = container_of(head, struct dm_hw_stat_delta, rcu); + kfree(n); +} + static int set_all_monitor_traces(int state) { int rc = 0; + struct dm_hw_stat_delta *new_stat = NULL; + struct dm_hw_stat_delta *temp; + + spin_lock(&trace_state_lock); switch (state) { case TRACE_ON: rc |= register_trace_kfree_skb(trace_kfree_skb_hit); + rc |= register_trace_napi_poll(trace_napi_poll_hit); break; case TRACE_OFF: rc |= unregister_trace_kfree_skb(trace_kfree_skb_hit); + rc |= unregister_trace_napi_poll(trace_napi_poll_hit); tracepoint_synchronize_unregister(); + + /* + * Clean the device list + */ + list_for_each_entry_safe(new_stat, temp, &hw_stats_list, list) { + if (new_stat->dev == NULL) { + list_del_rcu(&new_stat->list); + call_rcu(&new_stat->rcu, free_dm_hw_stat); + } + } break; default: rc = 1; break; } + if (!rc) + trace_state = state; + + spin_unlock(&trace_state_lock); + if (rc) return -EINPROGRESS; return rc; @@ -197,6 +271,44 @@ static int net_dm_cmd_trace(struct sk_buff *skb, return -ENOTSUPP; } +static int dropmon_net_event(struct notifier_block *ev_block, + unsigned long event, void *ptr) +{ + struct net_device *dev = ptr; + struct dm_hw_stat_delta *new_stat = NULL; + struct dm_hw_stat_delta *tmp; + + switch (event) { + case NETDEV_REGISTER: + new_stat = kzalloc(sizeof(struct dm_hw_stat_delta), GFP_KERNEL); + + if (!new_stat) + goto out; + + new_stat->dev = dev; + INIT_RCU_HEAD(&new_stat->rcu); + spin_lock(&trace_state_lock); + list_add_rcu(&new_stat->list, &hw_stats_list); + spin_unlock(&trace_state_lock); + break; + case NETDEV_UNREGISTER: + spin_lock(&trace_state_lock); + list_for_each_entry_safe(new_stat, tmp, &hw_stats_list, list) { + if (new_stat->dev == dev) { + new_stat->dev = NULL; + if (trace_state == TRACE_OFF) { + list_del_rcu(&new_stat->list); + call_rcu(&new_stat->rcu, free_dm_hw_stat); + break; + } + } + } + spin_unlock(&trace_state_lock); + break; + } +out: + return NOTIFY_DONE; +} static struct genl_ops dropmon_ops[] = { { @@ -213,6 +325,10 @@ static struct genl_ops dropmon_ops[] = { }, }; +static struct notifier_block dropmon_net_notifier = { + .notifier_call = dropmon_net_event +}; + static int __init init_net_drop_monitor(void) { int cpu; @@ -236,12 +352,18 @@ static int __init init_net_drop_monitor(void) ret = genl_register_ops(&net_drop_monitor_family, &dropmon_ops[i]); if (ret) { - printk(KERN_CRIT "failed to register operation %d\n", + printk(KERN_CRIT "Failed to register operation %d\n", dropmon_ops[i].cmd); goto out_unreg; } } + rc = register_netdevice_notifier(&dropmon_net_notifier); + if (rc < 0) { + printk(KERN_CRIT "Failed to register netdevice notifier\n"); + goto out_unreg; + } + rc = 0; for_each_present_cpu(cpu) { @@ -252,6 +374,7 @@ static int __init init_net_drop_monitor(void) data->send_timer.data = cpu; data->send_timer.function = sched_send_work; } + goto out; out_unreg: diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index 98691e1466b8..bd309384f8b8 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c @@ -299,7 +299,7 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) } else if (rule->action == FR_ACT_GOTO) goto errout_free; - err = ops->configure(rule, skb, nlh, frh, tb); + err = ops->configure(rule, skb, frh, tb); if (err < 0) goto errout_free; @@ -500,7 +500,7 @@ static int fib_nl_fill_rule(struct sk_buff *skb, struct fib_rule *rule, if (rule->target) NLA_PUT_U32(skb, FRA_GOTO, rule->target); - if (ops->fill(rule, skb, nlh, frh) < 0) + if (ops->fill(rule, skb, frh) < 0) goto nla_put_failure; return nlmsg_end(skb, nlh); diff --git a/net/core/gen_estimator.c b/net/core/gen_estimator.c index 6d62d4618cfc..78e5bfc454ae 100644 --- a/net/core/gen_estimator.c +++ b/net/core/gen_estimator.c @@ -128,12 +128,12 @@ static void est_timer(unsigned long arg) npackets = e->bstats->packets; brate = (nbytes - e->last_bytes)<<(7 - idx); e->last_bytes = nbytes; - e->avbps += ((s64)(brate - e->avbps)) >> e->ewma_log; + e->avbps += (brate >> e->ewma_log) - (e->avbps >> e->ewma_log); e->rate_est->bps = (e->avbps+0xF)>>5; rate = (npackets - e->last_packets)<<(12 - idx); e->last_packets = npackets; - e->avpps += ((long)rate - (long)e->avpps) >> e->ewma_log; + e->avpps += (rate >> e->ewma_log) - (e->avpps >> e->ewma_log); e->rate_est->pps = (e->avpps+0x1FF)>>10; skip: read_unlock(&est_lock); diff --git a/net/core/iovec.c b/net/core/iovec.c index 4c9c0121c9da..16ad45d4882b 100644 --- a/net/core/iovec.c +++ b/net/core/iovec.c @@ -97,6 +97,31 @@ int memcpy_toiovec(struct iovec *iov, unsigned char *kdata, int len) return 0; } +/* + * Copy kernel to iovec. Returns -EFAULT on error. + */ + +int memcpy_toiovecend(const struct iovec *iov, unsigned char *kdata, + int offset, int len) +{ + int copy; + for (; len > 0; ++iov) { + /* Skip over the finished iovecs */ + if (unlikely(offset >= iov->iov_len)) { + offset -= iov->iov_len; + continue; + } + copy = min_t(unsigned int, iov->iov_len - offset, len); + if (copy_to_user(iov->iov_base + offset, kdata, copy)) + return -EFAULT; + offset = 0; + kdata += copy; + len -= copy; + } + + return 0; +} + /* * Copy iovec to kernel. Returns -EFAULT on error. * @@ -122,10 +147,11 @@ int memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len) } /* - * For use with ip_build_xmit + * Copy iovec from kernel. Returns -EFAULT on error. */ -int memcpy_fromiovecend(unsigned char *kdata, struct iovec *iov, int offset, - int len) + +int memcpy_fromiovecend(unsigned char *kdata, const struct iovec *iov, + int offset, int len) { /* Skip over the finished iovecs */ while (offset >= iov->iov_len) { @@ -236,3 +262,4 @@ EXPORT_SYMBOL(csum_partial_copy_fromiovecend); EXPORT_SYMBOL(memcpy_fromiovec); EXPORT_SYMBOL(memcpy_fromiovecend); EXPORT_SYMBOL(memcpy_toiovec); +EXPORT_SYMBOL(memcpy_toiovecend); diff --git a/net/core/neighbour.c b/net/core/neighbour.c index a1cbce7fdae5..163b4f5b0365 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -771,6 +771,28 @@ static __inline__ int neigh_max_probes(struct neighbour *n) p->ucast_probes + p->app_probes + p->mcast_probes); } +static void neigh_invalidate(struct neighbour *neigh) +{ + struct sk_buff *skb; + + NEIGH_CACHE_STAT_INC(neigh->tbl, res_failed); + NEIGH_PRINTK2("neigh %p is failed.\n", neigh); + neigh->updated = jiffies; + + /* It is very thin place. report_unreachable is very complicated + routine. Particularly, it can hit the same neighbour entry! + + So that, we try to be accurate and avoid dead loop. --ANK + */ + while (neigh->nud_state == NUD_FAILED && + (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) { + write_unlock(&neigh->lock); + neigh->ops->error_report(neigh, skb); + write_lock(&neigh->lock); + } + skb_queue_purge(&neigh->arp_queue); +} + /* Called when a timer expires for a neighbour entry. */ static void neigh_timer_handler(unsigned long arg) @@ -835,26 +857,9 @@ static void neigh_timer_handler(unsigned long arg) if ((neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) && atomic_read(&neigh->probes) >= neigh_max_probes(neigh)) { - struct sk_buff *skb; - neigh->nud_state = NUD_FAILED; - neigh->updated = jiffies; notify = 1; - NEIGH_CACHE_STAT_INC(neigh->tbl, res_failed); - NEIGH_PRINTK2("neigh %p is failed.\n", neigh); - - /* It is very thin place. report_unreachable is very complicated - routine. Particularly, it can hit the same neighbour entry! - - So that, we try to be accurate and avoid dead loop. --ANK - */ - while (neigh->nud_state == NUD_FAILED && - (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) { - write_unlock(&neigh->lock); - neigh->ops->error_report(neigh, skb); - write_lock(&neigh->lock); - } - skb_queue_purge(&neigh->arp_queue); + neigh_invalidate(neigh); } if (neigh->nud_state & NUD_IN_TIMER) { @@ -1001,6 +1006,11 @@ int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new, neigh->nud_state = new; err = 0; notify = old & NUD_VALID; + if ((old & (NUD_INCOMPLETE | NUD_PROBE)) && + (new & NUD_FAILED)) { + neigh_invalidate(neigh); + notify = 1; + } goto out; } @@ -1088,8 +1098,8 @@ int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new, struct neighbour *n1 = neigh; write_unlock_bh(&neigh->lock); /* On shaper/eql skb->dst->neighbour != neigh :( */ - if (skb->dst && skb->dst->neighbour) - n1 = skb->dst->neighbour; + if (skb_dst(skb) && skb_dst(skb)->neighbour) + n1 = skb_dst(skb)->neighbour; n1->output(skb); write_lock_bh(&neigh->lock); } @@ -1182,7 +1192,7 @@ EXPORT_SYMBOL(neigh_compat_output); int neigh_resolve_output(struct sk_buff *skb) { - struct dst_entry *dst = skb->dst; + struct dst_entry *dst = skb_dst(skb); struct neighbour *neigh; int rc = 0; @@ -1229,7 +1239,7 @@ EXPORT_SYMBOL(neigh_resolve_output); int neigh_connected_output(struct sk_buff *skb) { int err; - struct dst_entry *dst = skb->dst; + struct dst_entry *dst = skb_dst(skb); struct neighbour *neigh = dst->neighbour; struct net_device *dev = neigh->dev; @@ -1298,8 +1308,7 @@ void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p, if (time_before(tbl->proxy_timer.expires, sched_next)) sched_next = tbl->proxy_timer.expires; } - dst_release(skb->dst); - skb->dst = NULL; + skb_dst_drop(skb); dev_hold(skb->dev); __skb_queue_tail(&tbl->proxy_queue, skb); mod_timer(&tbl->proxy_timer, sched_next); diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index 2da59a0ac4ac..3994680c08b9 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -78,7 +78,7 @@ static ssize_t netdev_store(struct device *dev, struct device_attribute *attr, goto err; if (!rtnl_trylock()) - return -ERESTARTSYS; + return restart_syscall(); if (dev_isalive(net)) { if ((ret = (*set)(net, new)) == 0) @@ -225,7 +225,8 @@ static ssize_t store_ifalias(struct device *dev, struct device_attribute *attr, if (len > 0 && buf[len - 1] == '\n') --count; - rtnl_lock(); + if (!rtnl_trylock()) + return restart_syscall(); ret = dev_set_alias(netdev, buf, count); rtnl_unlock(); @@ -238,7 +239,8 @@ static ssize_t show_ifalias(struct device *dev, const struct net_device *netdev = to_net_dev(dev); ssize_t ret = 0; - rtnl_lock(); + if (!rtnl_trylock()) + return restart_syscall(); if (netdev->ifalias) ret = sprintf(buf, "%s\n", netdev->ifalias); rtnl_unlock(); @@ -497,7 +499,6 @@ int netdev_register_kobject(struct net_device *net) dev->platform_data = net; dev->groups = groups; - BUILD_BUG_ON(BUS_ID_SIZE < IFNAMSIZ); dev_set_name(dev, "%s", net->name); #ifdef CONFIG_SYSFS diff --git a/net/core/net-traces.c b/net/core/net-traces.c index c8fb45665e4f..f1e982c508bb 100644 --- a/net/core/net-traces.c +++ b/net/core/net-traces.c @@ -19,11 +19,14 @@ #include #include #include -#include #include #include +#define CREATE_TRACE_POINTS +#include +#include -DEFINE_TRACE(kfree_skb); EXPORT_TRACEPOINT_SYMBOL_GPL(kfree_skb); + +EXPORT_TRACEPOINT_SYMBOL_GPL(napi_poll); diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index e3bebd36f053..b7292a2719dc 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -115,41 +115,34 @@ static void net_free(struct net *net) kmem_cache_free(net_cachep, net); } -struct net *copy_net_ns(unsigned long flags, struct net *old_net) +static struct net *net_create(void) { - struct net *new_net = NULL; - int err; - - get_net(old_net); - - if (!(flags & CLONE_NEWNET)) - return old_net; - - err = -ENOMEM; - new_net = net_alloc(); - if (!new_net) - goto out_err; + struct net *net; + int rv; + net = net_alloc(); + if (!net) + return ERR_PTR(-ENOMEM); mutex_lock(&net_mutex); - err = setup_net(new_net); - if (!err) { + rv = setup_net(net); + if (rv == 0) { rtnl_lock(); - list_add_tail(&new_net->list, &net_namespace_list); + list_add_tail(&net->list, &net_namespace_list); rtnl_unlock(); } mutex_unlock(&net_mutex); + if (rv < 0) { + net_free(net); + return ERR_PTR(rv); + } + return net; +} - if (err) - goto out_free; -out: - put_net(old_net); - return new_net; - -out_free: - net_free(new_net); -out_err: - new_net = ERR_PTR(err); - goto out; +struct net *copy_net_ns(unsigned long flags, struct net *old_net) +{ + if (!(flags & CLONE_NEWNET)) + return get_net(old_net); + return net_create(); } static void cleanup_net(struct work_struct *work) @@ -203,9 +196,7 @@ struct net *copy_net_ns(unsigned long flags, struct net *old_net) static int __init net_ns_init(void) { struct net_generic *ng; - int err; - printk(KERN_INFO "net_namespace: %zd bytes\n", sizeof(struct net)); #ifdef CONFIG_NET_NS net_cachep = kmem_cache_create("net_namespace", sizeof(struct net), SMP_CACHE_BYTES, @@ -224,15 +215,14 @@ static int __init net_ns_init(void) rcu_assign_pointer(init_net.gen, ng); mutex_lock(&net_mutex); - err = setup_net(&init_net); + if (setup_net(&init_net)) + panic("Could not setup the initial network namespace"); rtnl_lock(); list_add_tail(&init_net.list, &net_namespace_list); rtnl_unlock(); mutex_unlock(&net_mutex); - if (err) - panic("Could not setup the initial network namespace"); return 0; } diff --git a/net/core/netpoll.c b/net/core/netpoll.c index 64f51eec6576..9675f312830d 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -24,6 +24,7 @@ #include #include #include +#include /* * We maintain a small pool of fully-sized skbs, to make sure the @@ -137,6 +138,7 @@ static int poll_one_napi(struct netpoll_info *npinfo, set_bit(NAPI_STATE_NPSVC, &napi->state); work = napi->poll(napi, budget); + trace_napi_poll(napi); clear_bit(NAPI_STATE_NPSVC, &napi->state); atomic_dec(&trapped); @@ -300,8 +302,11 @@ static void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb) for (tries = jiffies_to_usecs(1)/USEC_PER_POLL; tries > 0; --tries) { if (__netif_tx_trylock(txq)) { - if (!netif_tx_queue_stopped(txq)) + if (!netif_tx_queue_stopped(txq)) { status = ops->ndo_start_xmit(skb, dev); + if (status == NETDEV_TX_OK) + txq_trans_update(txq); + } __netif_tx_unlock(txq); if (status == NETDEV_TX_OK) diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 0666a827bc62..19b8c20e98a4 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -3438,6 +3438,7 @@ static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev) retry_now: ret = (*xmit)(pkt_dev->skb, odev); if (likely(ret == NETDEV_TX_OK)) { + txq_trans_update(txq); pkt_dev->last_ok = 1; pkt_dev->sofar++; pkt_dev->seq_num++; @@ -3690,8 +3691,7 @@ out1: #ifdef CONFIG_XFRM free_SAs(pkt_dev); #endif - if (pkt_dev->flows) - vfree(pkt_dev->flows); + vfree(pkt_dev->flows); kfree(pkt_dev); return err; } @@ -3790,8 +3790,7 @@ static int pktgen_remove_device(struct pktgen_thread *t, #ifdef CONFIG_XFRM free_SAs(pkt_dev); #endif - if (pkt_dev->flows) - vfree(pkt_dev->flows); + vfree(pkt_dev->flows); kfree(pkt_dev); return 0; } diff --git a/net/core/skb_dma_map.c b/net/core/skb_dma_map.c index 86234923a3b7..79687dfd6957 100644 --- a/net/core/skb_dma_map.c +++ b/net/core/skb_dma_map.c @@ -20,7 +20,7 @@ int skb_dma_map(struct device *dev, struct sk_buff *skb, if (dma_mapping_error(dev, map)) goto out_err; - sp->dma_maps[0] = map; + sp->dma_head = map; for (i = 0; i < sp->nr_frags; i++) { skb_frag_t *fp = &sp->frags[i]; @@ -28,9 +28,8 @@ int skb_dma_map(struct device *dev, struct sk_buff *skb, fp->size, dir); if (dma_mapping_error(dev, map)) goto unwind; - sp->dma_maps[i + 1] = map; + sp->dma_maps[i] = map; } - sp->num_dma_maps = i + 1; return 0; @@ -38,10 +37,10 @@ unwind: while (--i >= 0) { skb_frag_t *fp = &sp->frags[i]; - dma_unmap_page(dev, sp->dma_maps[i + 1], + dma_unmap_page(dev, sp->dma_maps[i], fp->size, dir); } - dma_unmap_single(dev, sp->dma_maps[0], + dma_unmap_single(dev, sp->dma_head, skb_headlen(skb), dir); out_err: return -ENOMEM; @@ -54,12 +53,12 @@ void skb_dma_unmap(struct device *dev, struct sk_buff *skb, struct skb_shared_info *sp = skb_shinfo(skb); int i; - dma_unmap_single(dev, sp->dma_maps[0], + dma_unmap_single(dev, sp->dma_head, skb_headlen(skb), dir); for (i = 0; i < sp->nr_frags; i++) { skb_frag_t *fp = &sp->frags[i]; - dma_unmap_page(dev, sp->dma_maps[i + 1], + dma_unmap_page(dev, sp->dma_maps[i], fp->size, dir); } } diff --git a/net/core/skbuff.c b/net/core/skbuff.c index e505b5392e1e..9e0597d189b0 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -65,7 +66,7 @@ #include #include -#include +#include #include "kmap_skb.h" @@ -201,6 +202,12 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask, skb->data = data; skb_reset_tail_pointer(skb); skb->end = skb->tail + size; + kmemcheck_annotate_bitfield(skb, flags1); + kmemcheck_annotate_bitfield(skb, flags2); +#ifdef NET_SKBUFF_DATA_USES_OFFSET + skb->mac_header = ~0U; +#endif + /* make sure we initialize shinfo sequentially */ shinfo = skb_shinfo(skb); atomic_set(&shinfo->dataref, 1); @@ -210,13 +217,15 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask, shinfo->gso_type = 0; shinfo->ip6_frag_id = 0; shinfo->tx_flags.flags = 0; - shinfo->frag_list = NULL; + skb_frag_list_init(skb); memset(&shinfo->hwtstamps, 0, sizeof(shinfo->hwtstamps)); if (fclone) { struct sk_buff *child = skb + 1; atomic_t *fclone_ref = (atomic_t *) (child + 1); + kmemcheck_annotate_bitfield(child, flags1); + kmemcheck_annotate_bitfield(child, flags2); skb->fclone = SKB_FCLONE_ORIG; atomic_set(fclone_ref, 1); @@ -323,7 +332,7 @@ static void skb_clone_fraglist(struct sk_buff *skb) { struct sk_buff *list; - for (list = skb_shinfo(skb)->frag_list; list; list = list->next) + skb_walk_frags(skb, list) skb_get(list); } @@ -338,7 +347,7 @@ static void skb_release_data(struct sk_buff *skb) put_page(skb_shinfo(skb)->frags[i].page); } - if (skb_shinfo(skb)->frag_list) + if (skb_has_frags(skb)) skb_drop_fraglist(skb); kfree(skb->head); @@ -381,7 +390,7 @@ static void kfree_skbmem(struct sk_buff *skb) static void skb_release_head_state(struct sk_buff *skb) { - dst_release(skb->dst); + skb_dst_drop(skb); #ifdef CONFIG_XFRM secpath_put(skb->sp); #endif @@ -503,7 +512,7 @@ int skb_recycle_check(struct sk_buff *skb, int skb_size) shinfo->gso_type = 0; shinfo->ip6_frag_id = 0; shinfo->tx_flags.flags = 0; - shinfo->frag_list = NULL; + skb_frag_list_init(skb); memset(&shinfo->hwtstamps, 0, sizeof(shinfo->hwtstamps)); memset(skb, 0, offsetof(struct sk_buff, tail)); @@ -521,13 +530,12 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old) new->transport_header = old->transport_header; new->network_header = old->network_header; new->mac_header = old->mac_header; - new->dst = dst_clone(old->dst); + skb_dst_set(new, dst_clone(skb_dst(old))); #ifdef CONFIG_XFRM new->sp = secpath_get(old->sp); #endif memcpy(new->cb, old->cb, sizeof(old->cb)); - new->csum_start = old->csum_start; - new->csum_offset = old->csum_offset; + new->csum = old->csum; new->local_df = old->local_df; new->pkt_type = old->pkt_type; new->ip_summed = old->ip_summed; @@ -538,6 +546,7 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old) #endif new->protocol = old->protocol; new->mark = old->mark; + new->iif = old->iif; __nf_copy(new, old); #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \ defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE) @@ -550,10 +559,17 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old) #endif #endif new->vlan_tci = old->vlan_tci; +#if defined(CONFIG_MAC80211) || defined(CONFIG_MAC80211_MODULE) + new->do_not_encrypt = old->do_not_encrypt; +#endif skb_copy_secmark(new, old); } +/* + * You should not add any new code to this function. Add it to + * __copy_skb_header above instead. + */ static struct sk_buff *__skb_clone(struct sk_buff *n, struct sk_buff *skb) { #define C(x) n->x = skb->x @@ -569,16 +585,11 @@ static struct sk_buff *__skb_clone(struct sk_buff *n, struct sk_buff *skb) n->cloned = 1; n->nohdr = 0; n->destructor = NULL; - C(iif); C(tail); C(end); C(head); C(data); C(truesize); -#if defined(CONFIG_MAC80211) || defined(CONFIG_MAC80211_MODULE) - C(do_not_encrypt); - C(requeue); -#endif atomic_set(&n->users, 1); atomic_inc(&(skb_shinfo(skb)->dataref)); @@ -633,6 +644,9 @@ struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask) n = kmem_cache_alloc(skbuff_head_cache, gfp_mask); if (!n) return NULL; + + kmemcheck_annotate_bitfield(n, flags1); + kmemcheck_annotate_bitfield(n, flags2); n->fclone = SKB_FCLONE_UNAVAILABLE; } @@ -655,7 +669,8 @@ static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old) /* {transport,network,mac}_header are relative to skb->head */ new->transport_header += offset; new->network_header += offset; - new->mac_header += offset; + if (skb_mac_header_was_set(new)) + new->mac_header += offset; #endif skb_shinfo(new)->gso_size = skb_shinfo(old)->gso_size; skb_shinfo(new)->gso_segs = skb_shinfo(old)->gso_segs; @@ -755,7 +770,7 @@ struct sk_buff *pskb_copy(struct sk_buff *skb, gfp_t gfp_mask) skb_shinfo(n)->nr_frags = i; } - if (skb_shinfo(skb)->frag_list) { + if (skb_has_frags(skb)) { skb_shinfo(n)->frag_list = skb_shinfo(skb)->frag_list; skb_clone_fraglist(n); } @@ -818,7 +833,7 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail, for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) get_page(skb_shinfo(skb)->frags[i].page); - if (skb_shinfo(skb)->frag_list) + if (skb_has_frags(skb)) skb_clone_fraglist(skb); skb_release_data(skb); @@ -837,7 +852,8 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail, skb->tail += off; skb->transport_header += off; skb->network_header += off; - skb->mac_header += off; + if (skb_mac_header_was_set(skb)) + skb->mac_header += off; skb->csum_start += nhead; skb->cloned = 0; skb->hdr_len = 0; @@ -929,7 +945,8 @@ struct sk_buff *skb_copy_expand(const struct sk_buff *skb, #ifdef NET_SKBUFF_DATA_USES_OFFSET n->transport_header += off; n->network_header += off; - n->mac_header += off; + if (skb_mac_header_was_set(skb)) + n->mac_header += off; #endif return n; @@ -1090,7 +1107,7 @@ drop_pages: for (; i < nfrags; i++) put_page(skb_shinfo(skb)->frags[i].page); - if (skb_shinfo(skb)->frag_list) + if (skb_has_frags(skb)) skb_drop_fraglist(skb); goto done; } @@ -1185,7 +1202,7 @@ unsigned char *__pskb_pull_tail(struct sk_buff *skb, int delta) /* Optimization: no fragments, no reasons to preestimate * size of pulled pages. Superb. */ - if (!skb_shinfo(skb)->frag_list) + if (!skb_has_frags(skb)) goto pull_pages; /* Estimate size of pulled pages. */ @@ -1282,8 +1299,9 @@ EXPORT_SYMBOL(__pskb_pull_tail); int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len) { - int i, copy; int start = skb_headlen(skb); + struct sk_buff *frag_iter; + int i, copy; if (offset > (int)skb->len - len) goto fault; @@ -1325,28 +1343,23 @@ int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len) start = end; } - if (skb_shinfo(skb)->frag_list) { - struct sk_buff *list = skb_shinfo(skb)->frag_list; + skb_walk_frags(skb, frag_iter) { + int end; - for (; list; list = list->next) { - int end; + WARN_ON(start > offset + len); - WARN_ON(start > offset + len); - - end = start + list->len; - if ((copy = end - offset) > 0) { - if (copy > len) - copy = len; - if (skb_copy_bits(list, offset - start, - to, copy)) - goto fault; - if ((len -= copy) == 0) - return 0; - offset += copy; - to += copy; - } - start = end; + end = start + frag_iter->len; + if ((copy = end - offset) > 0) { + if (copy > len) + copy = len; + if (skb_copy_bits(frag_iter, offset - start, to, copy)) + goto fault; + if ((len -= copy) == 0) + return 0; + offset += copy; + to += copy; } + start = end; } if (!len) return 0; @@ -1531,6 +1544,7 @@ int skb_splice_bits(struct sk_buff *skb, unsigned int offset, .ops = &sock_pipe_buf_ops, .spd_release = sock_spd_release, }; + struct sk_buff *frag_iter; struct sock *sk = skb->sk; /* @@ -1545,13 +1559,11 @@ int skb_splice_bits(struct sk_buff *skb, unsigned int offset, /* * now see if we have a frag_list to map */ - if (skb_shinfo(skb)->frag_list) { - struct sk_buff *list = skb_shinfo(skb)->frag_list; - - for (; list && tlen; list = list->next) { - if (__skb_splice_bits(list, &offset, &tlen, &spd, sk)) - break; - } + skb_walk_frags(skb, frag_iter) { + if (!tlen) + break; + if (__skb_splice_bits(frag_iter, &offset, &tlen, &spd, sk)) + break; } done: @@ -1590,8 +1602,9 @@ done: int skb_store_bits(struct sk_buff *skb, int offset, const void *from, int len) { - int i, copy; int start = skb_headlen(skb); + struct sk_buff *frag_iter; + int i, copy; if (offset > (int)skb->len - len) goto fault; @@ -1632,28 +1645,24 @@ int skb_store_bits(struct sk_buff *skb, int offset, const void *from, int len) start = end; } - if (skb_shinfo(skb)->frag_list) { - struct sk_buff *list = skb_shinfo(skb)->frag_list; + skb_walk_frags(skb, frag_iter) { + int end; - for (; list; list = list->next) { - int end; + WARN_ON(start > offset + len); - WARN_ON(start > offset + len); - - end = start + list->len; - if ((copy = end - offset) > 0) { - if (copy > len) - copy = len; - if (skb_store_bits(list, offset - start, - from, copy)) - goto fault; - if ((len -= copy) == 0) - return 0; - offset += copy; - from += copy; - } - start = end; + end = start + frag_iter->len; + if ((copy = end - offset) > 0) { + if (copy > len) + copy = len; + if (skb_store_bits(frag_iter, offset - start, + from, copy)) + goto fault; + if ((len -= copy) == 0) + return 0; + offset += copy; + from += copy; } + start = end; } if (!len) return 0; @@ -1670,6 +1679,7 @@ __wsum skb_checksum(const struct sk_buff *skb, int offset, { int start = skb_headlen(skb); int i, copy = start - offset; + struct sk_buff *frag_iter; int pos = 0; /* Checksum header. */ @@ -1709,29 +1719,25 @@ __wsum skb_checksum(const struct sk_buff *skb, int offset, start = end; } - if (skb_shinfo(skb)->frag_list) { - struct sk_buff *list = skb_shinfo(skb)->frag_list; + skb_walk_frags(skb, frag_iter) { + int end; - for (; list; list = list->next) { - int end; + WARN_ON(start > offset + len); - WARN_ON(start > offset + len); - - end = start + list->len; - if ((copy = end - offset) > 0) { - __wsum csum2; - if (copy > len) - copy = len; - csum2 = skb_checksum(list, offset - start, - copy, 0); - csum = csum_block_add(csum, csum2, pos); - if ((len -= copy) == 0) - return csum; - offset += copy; - pos += copy; - } - start = end; + end = start + frag_iter->len; + if ((copy = end - offset) > 0) { + __wsum csum2; + if (copy > len) + copy = len; + csum2 = skb_checksum(frag_iter, offset - start, + copy, 0); + csum = csum_block_add(csum, csum2, pos); + if ((len -= copy) == 0) + return csum; + offset += copy; + pos += copy; } + start = end; } BUG_ON(len); @@ -1746,6 +1752,7 @@ __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, { int start = skb_headlen(skb); int i, copy = start - offset; + struct sk_buff *frag_iter; int pos = 0; /* Copy header. */ @@ -1790,31 +1797,27 @@ __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, start = end; } - if (skb_shinfo(skb)->frag_list) { - struct sk_buff *list = skb_shinfo(skb)->frag_list; + skb_walk_frags(skb, frag_iter) { + __wsum csum2; + int end; - for (; list; list = list->next) { - __wsum csum2; - int end; + WARN_ON(start > offset + len); - WARN_ON(start > offset + len); - - end = start + list->len; - if ((copy = end - offset) > 0) { - if (copy > len) - copy = len; - csum2 = skb_copy_and_csum_bits(list, - offset - start, - to, copy, 0); - csum = csum_block_add(csum, csum2, pos); - if ((len -= copy) == 0) - return csum; - offset += copy; - to += copy; - pos += copy; - } - start = end; + end = start + frag_iter->len; + if ((copy = end - offset) > 0) { + if (copy > len) + copy = len; + csum2 = skb_copy_and_csum_bits(frag_iter, + offset - start, + to, copy, 0); + csum = csum_block_add(csum, csum2, pos); + if ((len -= copy) == 0) + return csum; + offset += copy; + to += copy; + pos += copy; } + start = end; } BUG_ON(len); return csum; @@ -2324,8 +2327,7 @@ next_skb: st->frag_data = NULL; } - if (st->root_skb == st->cur_skb && - skb_shinfo(st->root_skb)->frag_list) { + if (st->root_skb == st->cur_skb && skb_has_frags(st->root_skb)) { st->cur_skb = skb_shinfo(st->root_skb)->frag_list; st->frag_idx = 0; goto next_skb; @@ -2636,7 +2638,7 @@ struct sk_buff *skb_segment(struct sk_buff *skb, int features) } else skb_get(fskb2); - BUG_ON(skb_shinfo(nskb)->frag_list); + SKB_FRAG_ASSERT(nskb); skb_shinfo(nskb)->frag_list = fskb2; } @@ -2661,30 +2663,40 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb) { struct sk_buff *p = *head; struct sk_buff *nskb; + struct skb_shared_info *skbinfo = skb_shinfo(skb); + struct skb_shared_info *pinfo = skb_shinfo(p); unsigned int headroom; unsigned int len = skb_gro_len(skb); + unsigned int offset = skb_gro_offset(skb); + unsigned int headlen = skb_headlen(skb); if (p->len + len >= 65536) return -E2BIG; - if (skb_shinfo(p)->frag_list) + if (pinfo->frag_list) goto merge; - else if (skb_headlen(skb) <= skb_gro_offset(skb)) { - if (skb_shinfo(p)->nr_frags + skb_shinfo(skb)->nr_frags > - MAX_SKB_FRAGS) + else if (headlen <= offset) { + skb_frag_t *frag; + skb_frag_t *frag2; + int i = skbinfo->nr_frags; + int nr_frags = pinfo->nr_frags + i; + + offset -= headlen; + + if (nr_frags > MAX_SKB_FRAGS) return -E2BIG; - skb_shinfo(skb)->frags[0].page_offset += - skb_gro_offset(skb) - skb_headlen(skb); - skb_shinfo(skb)->frags[0].size -= - skb_gro_offset(skb) - skb_headlen(skb); + pinfo->nr_frags = nr_frags; + skbinfo->nr_frags = 0; - memcpy(skb_shinfo(p)->frags + skb_shinfo(p)->nr_frags, - skb_shinfo(skb)->frags, - skb_shinfo(skb)->nr_frags * sizeof(skb_frag_t)); + frag = pinfo->frags + nr_frags; + frag2 = skbinfo->frags + i; + do { + *--frag = *--frag2; + } while (--i); - skb_shinfo(p)->nr_frags += skb_shinfo(skb)->nr_frags; - skb_shinfo(skb)->nr_frags = 0; + frag->page_offset += offset; + frag->size -= offset; skb->truesize -= skb->data_len; skb->len -= skb->data_len; @@ -2715,7 +2727,7 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb) *NAPI_GRO_CB(nskb) = *NAPI_GRO_CB(p); skb_shinfo(nskb)->frag_list = p; - skb_shinfo(nskb)->gso_size = skb_shinfo(p)->gso_size; + skb_shinfo(nskb)->gso_size = pinfo->gso_size; skb_header_release(p); nskb->prev = p; @@ -2730,16 +2742,13 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb) p = nskb; merge: - if (skb_gro_offset(skb) > skb_headlen(skb)) { - skb_shinfo(skb)->frags[0].page_offset += - skb_gro_offset(skb) - skb_headlen(skb); - skb_shinfo(skb)->frags[0].size -= - skb_gro_offset(skb) - skb_headlen(skb); - skb_gro_reset_offset(skb); - skb_gro_pull(skb, skb_headlen(skb)); + if (offset > headlen) { + skbinfo->frags[0].page_offset += offset - headlen; + skbinfo->frags[0].size -= offset - headlen; + offset = headlen; } - __skb_pull(skb, skb_gro_offset(skb)); + __skb_pull(skb, offset); p->prev->next = skb; p->prev = skb; @@ -2786,6 +2795,7 @@ __skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len) { int start = skb_headlen(skb); int i, copy = start - offset; + struct sk_buff *frag_iter; int elt = 0; if (copy > 0) { @@ -2819,26 +2829,22 @@ __skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len) start = end; } - if (skb_shinfo(skb)->frag_list) { - struct sk_buff *list = skb_shinfo(skb)->frag_list; + skb_walk_frags(skb, frag_iter) { + int end; - for (; list; list = list->next) { - int end; + WARN_ON(start > offset + len); - WARN_ON(start > offset + len); - - end = start + list->len; - if ((copy = end - offset) > 0) { - if (copy > len) - copy = len; - elt += __skb_to_sgvec(list, sg+elt, offset - start, - copy); - if ((len -= copy) == 0) - return elt; - offset += copy; - } - start = end; + end = start + frag_iter->len; + if ((copy = end - offset) > 0) { + if (copy > len) + copy = len; + elt += __skb_to_sgvec(frag_iter, sg+elt, offset - start, + copy); + if ((len -= copy) == 0) + return elt; + offset += copy; } + start = end; } BUG_ON(len); return elt; @@ -2886,7 +2892,7 @@ int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer) return -ENOMEM; /* Easy case. Most of packets will go this way. */ - if (!skb_shinfo(skb)->frag_list) { + if (!skb_has_frags(skb)) { /* A little of trouble, not enough of space for trailer. * This should not happen, when stack is tuned to generate * good frames. OK, on miss we reallocate and reserve even more @@ -2921,7 +2927,7 @@ int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer) if (skb1->next == NULL && tailbits) { if (skb_shinfo(skb1)->nr_frags || - skb_shinfo(skb1)->frag_list || + skb_has_frags(skb1) || skb_tailroom(skb1) < tailbits) ntail = tailbits + 128; } @@ -2930,7 +2936,7 @@ int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer) skb_cloned(skb1) || ntail || skb_shinfo(skb1)->nr_frags || - skb_shinfo(skb1)->frag_list) { + skb_has_frags(skb1)) { struct sk_buff *skb2; /* Fuck, we are miserable poor guys... */ @@ -3016,12 +3022,12 @@ EXPORT_SYMBOL_GPL(skb_tstamp_tx); */ bool skb_partial_csum_set(struct sk_buff *skb, u16 start, u16 off) { - if (unlikely(start > skb->len - 2) || - unlikely((int)start + off > skb->len - 2)) { + if (unlikely(start > skb_headlen(skb)) || + unlikely((int)start + off > skb_headlen(skb) - 2)) { if (net_ratelimit()) printk(KERN_WARNING "bad partial csum: csum=%u/%u len=%u\n", - start, off, skb->len); + start, off, skb_headlen(skb)); return false; } skb->ip_summed = CHECKSUM_PARTIAL; diff --git a/net/core/sock.c b/net/core/sock.c index 7dbf3ffb35cc..b0ba569bc973 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -155,6 +155,7 @@ static const char *af_family_key_strings[AF_MAX+1] = { "sk_lock-27" , "sk_lock-28" , "sk_lock-AF_CAN" , "sk_lock-AF_TIPC" , "sk_lock-AF_BLUETOOTH", "sk_lock-IUCV" , "sk_lock-AF_RXRPC" , "sk_lock-AF_ISDN" , "sk_lock-AF_PHONET" , + "sk_lock-AF_IEEE802154", "sk_lock-AF_MAX" }; static const char *af_family_slock_key_strings[AF_MAX+1] = { @@ -170,6 +171,7 @@ static const char *af_family_slock_key_strings[AF_MAX+1] = { "slock-27" , "slock-28" , "slock-AF_CAN" , "slock-AF_TIPC" , "slock-AF_BLUETOOTH", "slock-AF_IUCV" , "slock-AF_RXRPC" , "slock-AF_ISDN" , "slock-AF_PHONET" , + "slock-AF_IEEE802154", "slock-AF_MAX" }; static const char *af_family_clock_key_strings[AF_MAX+1] = { @@ -185,6 +187,7 @@ static const char *af_family_clock_key_strings[AF_MAX+1] = { "clock-27" , "clock-28" , "clock-AF_CAN" , "clock-AF_TIPC" , "clock-AF_BLUETOOTH", "clock-AF_IUCV" , "clock-AF_RXRPC" , "clock-AF_ISDN" , "clock-AF_PHONET" , + "clock-AF_IEEE802154", "clock-AF_MAX" }; @@ -212,6 +215,7 @@ __u32 sysctl_rmem_default __read_mostly = SK_RMEM_MAX; /* Maximal space eaten by iovec or ancilliary data plus some space */ int sysctl_optmem_max __read_mostly = sizeof(unsigned long)*(2*UIO_MAXIOV+512); +EXPORT_SYMBOL(sysctl_optmem_max); static int sock_set_timeout(long *timeo_p, char __user *optval, int optlen) { @@ -444,7 +448,7 @@ static inline void sock_valbool_flag(struct sock *sk, int bit, int valbool) int sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen) { - struct sock *sk=sock->sk; + struct sock *sk = sock->sk; int val; int valbool; struct linger ling; @@ -463,15 +467,15 @@ int sock_setsockopt(struct socket *sock, int level, int optname, if (get_user(val, (int __user *)optval)) return -EFAULT; - valbool = val?1:0; + valbool = val ? 1 : 0; lock_sock(sk); - switch(optname) { + switch (optname) { case SO_DEBUG: - if (val && !capable(CAP_NET_ADMIN)) { + if (val && !capable(CAP_NET_ADMIN)) ret = -EACCES; - } else + else sock_valbool_flag(sk, SOCK_DBG, valbool); break; case SO_REUSEADDR: @@ -582,7 +586,7 @@ set_rcvbuf: ret = -EINVAL; /* 1003.1g */ break; } - if (copy_from_user(&ling,optval,sizeof(ling))) { + if (copy_from_user(&ling, optval, sizeof(ling))) { ret = -EFAULT; break; } @@ -690,9 +694,8 @@ set_rcvbuf: case SO_MARK: if (!capable(CAP_NET_ADMIN)) ret = -EPERM; - else { + else sk->sk_mark = val; - } break; /* We implement the SO_SNDLOWAT etc to @@ -704,6 +707,7 @@ set_rcvbuf: release_sock(sk); return ret; } +EXPORT_SYMBOL(sock_setsockopt); int sock_getsockopt(struct socket *sock, int level, int optname, @@ -727,7 +731,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname, memset(&v, 0, sizeof(v)); - switch(optname) { + switch (optname) { case SO_DEBUG: v.val = sock_flag(sk, SOCK_DBG); break; @@ -762,7 +766,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname, case SO_ERROR: v.val = -sock_error(sk); - if (v.val==0) + if (v.val == 0) v.val = xchg(&sk->sk_err_soft, 0); break; @@ -816,7 +820,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname, break; case SO_RCVTIMEO: - lv=sizeof(struct timeval); + lv = sizeof(struct timeval); if (sk->sk_rcvtimeo == MAX_SCHEDULE_TIMEOUT) { v.tm.tv_sec = 0; v.tm.tv_usec = 0; @@ -827,7 +831,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname, break; case SO_SNDTIMEO: - lv=sizeof(struct timeval); + lv = sizeof(struct timeval); if (sk->sk_sndtimeo == MAX_SCHEDULE_TIMEOUT) { v.tm.tv_sec = 0; v.tm.tv_usec = 0; @@ -842,7 +846,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname, break; case SO_SNDLOWAT: - v.val=1; + v.val = 1; break; case SO_PASSCRED: @@ -941,6 +945,8 @@ static struct sock *sk_prot_alloc(struct proto *prot, gfp_t priority, sk = kmalloc(prot->obj_size, priority); if (sk != NULL) { + kmemcheck_annotate_bitfield(sk, flags); + if (security_sk_alloc(sk, family, priority)) goto out_free; @@ -1002,8 +1008,9 @@ struct sock *sk_alloc(struct net *net, int family, gfp_t priority, return sk; } +EXPORT_SYMBOL(sk_alloc); -void sk_free(struct sock *sk) +static void __sk_free(struct sock *sk) { struct sk_filter *filter; @@ -1027,6 +1034,18 @@ void sk_free(struct sock *sk) sk_prot_free(sk->sk_prot_creator, sk); } +void sk_free(struct sock *sk) +{ + /* + * We substract one from sk_wmem_alloc and can know if + * some packets are still in some tx queue. + * If not null, sock_wfree() will call __sk_free(sk) later + */ + if (atomic_dec_and_test(&sk->sk_wmem_alloc)) + __sk_free(sk); +} +EXPORT_SYMBOL(sk_free); + /* * Last sock_put should drop referrence to sk->sk_net. It has already * been dropped in sk_change_net. Taking referrence to stopping namespace @@ -1065,7 +1084,10 @@ struct sock *sk_clone(const struct sock *sk, const gfp_t priority) newsk->sk_backlog.head = newsk->sk_backlog.tail = NULL; atomic_set(&newsk->sk_rmem_alloc, 0); - atomic_set(&newsk->sk_wmem_alloc, 0); + /* + * sk_wmem_alloc set to one (see sk_free() and sock_wfree()) + */ + atomic_set(&newsk->sk_wmem_alloc, 1); atomic_set(&newsk->sk_omem_alloc, 0); skb_queue_head_init(&newsk->sk_receive_queue); skb_queue_head_init(&newsk->sk_write_queue); @@ -1126,7 +1148,6 @@ struct sock *sk_clone(const struct sock *sk, const gfp_t priority) out: return newsk; } - EXPORT_SYMBOL_GPL(sk_clone); void sk_setup_caps(struct sock *sk, struct dst_entry *dst) @@ -1170,13 +1191,20 @@ void __init sk_init(void) void sock_wfree(struct sk_buff *skb) { struct sock *sk = skb->sk; + int res; /* In case it might be waiting for more memory. */ - atomic_sub(skb->truesize, &sk->sk_wmem_alloc); + res = atomic_sub_return(skb->truesize, &sk->sk_wmem_alloc); if (!sock_flag(sk, SOCK_USE_WRITE_QUEUE)) sk->sk_write_space(sk); - sock_put(sk); + /* + * if sk_wmem_alloc reached 0, we are last user and should + * free this sock, as sk_free() call could not do it. + */ + if (res == 0) + __sk_free(sk); } +EXPORT_SYMBOL(sock_wfree); /* * Read buffer destructor automatically called from kfree_skb. @@ -1188,6 +1216,7 @@ void sock_rfree(struct sk_buff *skb) atomic_sub(skb->truesize, &sk->sk_rmem_alloc); sk_mem_uncharge(skb->sk, skb->truesize); } +EXPORT_SYMBOL(sock_rfree); int sock_i_uid(struct sock *sk) @@ -1199,6 +1228,7 @@ int sock_i_uid(struct sock *sk) read_unlock(&sk->sk_callback_lock); return uid; } +EXPORT_SYMBOL(sock_i_uid); unsigned long sock_i_ino(struct sock *sk) { @@ -1209,6 +1239,7 @@ unsigned long sock_i_ino(struct sock *sk) read_unlock(&sk->sk_callback_lock); return ino; } +EXPORT_SYMBOL(sock_i_ino); /* * Allocate a skb from the socket's send buffer. @@ -1217,7 +1248,7 @@ struct sk_buff *sock_wmalloc(struct sock *sk, unsigned long size, int force, gfp_t priority) { if (force || atomic_read(&sk->sk_wmem_alloc) < sk->sk_sndbuf) { - struct sk_buff * skb = alloc_skb(size, priority); + struct sk_buff *skb = alloc_skb(size, priority); if (skb) { skb_set_owner_w(skb, sk); return skb; @@ -1225,6 +1256,7 @@ struct sk_buff *sock_wmalloc(struct sock *sk, unsigned long size, int force, } return NULL; } +EXPORT_SYMBOL(sock_wmalloc); /* * Allocate a skb from the socket's receive buffer. @@ -1261,6 +1293,7 @@ void *sock_kmalloc(struct sock *sk, int size, gfp_t priority) } return NULL; } +EXPORT_SYMBOL(sock_kmalloc); /* * Free an option memory block. @@ -1270,11 +1303,12 @@ void sock_kfree_s(struct sock *sk, void *mem, int size) kfree(mem); atomic_sub(size, &sk->sk_omem_alloc); } +EXPORT_SYMBOL(sock_kfree_s); /* It is almost wait_for_tcp_memory minus release_sock/lock_sock. I think, these locks should be removed for datagram sockets. */ -static long sock_wait_for_wmem(struct sock * sk, long timeo) +static long sock_wait_for_wmem(struct sock *sk, long timeo) { DEFINE_WAIT(wait); @@ -1392,6 +1426,7 @@ struct sk_buff *sock_alloc_send_skb(struct sock *sk, unsigned long size, { return sock_alloc_send_pskb(sk, size, 0, noblock, errcode); } +EXPORT_SYMBOL(sock_alloc_send_skb); static void __lock_sock(struct sock *sk) { @@ -1460,7 +1495,6 @@ int sk_wait_data(struct sock *sk, long *timeo) finish_wait(sk->sk_sleep, &wait); return rc; } - EXPORT_SYMBOL(sk_wait_data); /** @@ -1541,7 +1575,6 @@ suppress_allocation: atomic_sub(amt, prot->memory_allocated); return 0; } - EXPORT_SYMBOL(__sk_mem_schedule); /** @@ -1560,7 +1593,6 @@ void __sk_mem_reclaim(struct sock *sk) (atomic_read(prot->memory_allocated) < prot->sysctl_mem[0])) *prot->memory_pressure = 0; } - EXPORT_SYMBOL(__sk_mem_reclaim); @@ -1575,78 +1607,92 @@ int sock_no_bind(struct socket *sock, struct sockaddr *saddr, int len) { return -EOPNOTSUPP; } +EXPORT_SYMBOL(sock_no_bind); int sock_no_connect(struct socket *sock, struct sockaddr *saddr, int len, int flags) { return -EOPNOTSUPP; } +EXPORT_SYMBOL(sock_no_connect); int sock_no_socketpair(struct socket *sock1, struct socket *sock2) { return -EOPNOTSUPP; } +EXPORT_SYMBOL(sock_no_socketpair); int sock_no_accept(struct socket *sock, struct socket *newsock, int flags) { return -EOPNOTSUPP; } +EXPORT_SYMBOL(sock_no_accept); int sock_no_getname(struct socket *sock, struct sockaddr *saddr, int *len, int peer) { return -EOPNOTSUPP; } +EXPORT_SYMBOL(sock_no_getname); -unsigned int sock_no_poll(struct file * file, struct socket *sock, poll_table *pt) +unsigned int sock_no_poll(struct file *file, struct socket *sock, poll_table *pt) { return 0; } +EXPORT_SYMBOL(sock_no_poll); int sock_no_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { return -EOPNOTSUPP; } +EXPORT_SYMBOL(sock_no_ioctl); int sock_no_listen(struct socket *sock, int backlog) { return -EOPNOTSUPP; } +EXPORT_SYMBOL(sock_no_listen); int sock_no_shutdown(struct socket *sock, int how) { return -EOPNOTSUPP; } +EXPORT_SYMBOL(sock_no_shutdown); int sock_no_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen) { return -EOPNOTSUPP; } +EXPORT_SYMBOL(sock_no_setsockopt); int sock_no_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen) { return -EOPNOTSUPP; } +EXPORT_SYMBOL(sock_no_getsockopt); int sock_no_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, size_t len) { return -EOPNOTSUPP; } +EXPORT_SYMBOL(sock_no_sendmsg); int sock_no_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, size_t len, int flags) { return -EOPNOTSUPP; } +EXPORT_SYMBOL(sock_no_recvmsg); int sock_no_mmap(struct file *file, struct socket *sock, struct vm_area_struct *vma) { /* Mirror missing mmap method error code */ return -ENODEV; } +EXPORT_SYMBOL(sock_no_mmap); ssize_t sock_no_sendpage(struct socket *sock, struct page *page, int offset, size_t size, int flags) { @@ -1660,6 +1706,7 @@ ssize_t sock_no_sendpage(struct socket *sock, struct page *page, int offset, siz kunmap(page); return res; } +EXPORT_SYMBOL(sock_no_sendpage); /* * Default Socket Callbacks @@ -1723,6 +1770,7 @@ void sk_send_sigurg(struct sock *sk) if (send_sigurg(&sk->sk_socket->file->f_owner)) sk_wake_async(sk, SOCK_WAKE_URG, POLL_PRI); } +EXPORT_SYMBOL(sk_send_sigurg); void sk_reset_timer(struct sock *sk, struct timer_list* timer, unsigned long expires) @@ -1730,7 +1778,6 @@ void sk_reset_timer(struct sock *sk, struct timer_list* timer, if (!mod_timer(timer, expires)) sock_hold(sk); } - EXPORT_SYMBOL(sk_reset_timer); void sk_stop_timer(struct sock *sk, struct timer_list* timer) @@ -1738,7 +1785,6 @@ void sk_stop_timer(struct sock *sk, struct timer_list* timer) if (timer_pending(timer) && del_timer(timer)) __sock_put(sk); } - EXPORT_SYMBOL(sk_stop_timer); void sock_init_data(struct socket *sock, struct sock *sk) @@ -1795,8 +1841,10 @@ void sock_init_data(struct socket *sock, struct sock *sk) sk->sk_stamp = ktime_set(-1L, 0); atomic_set(&sk->sk_refcnt, 1); + atomic_set(&sk->sk_wmem_alloc, 1); atomic_set(&sk->sk_drops, 0); } +EXPORT_SYMBOL(sock_init_data); void lock_sock_nested(struct sock *sk, int subclass) { @@ -1812,7 +1860,6 @@ void lock_sock_nested(struct sock *sk, int subclass) mutex_acquire(&sk->sk_lock.dep_map, subclass, 0, _RET_IP_); local_bh_enable(); } - EXPORT_SYMBOL(lock_sock_nested); void release_sock(struct sock *sk) @@ -1895,7 +1942,6 @@ int sock_common_getsockopt(struct socket *sock, int level, int optname, return sk->sk_prot->getsockopt(sk, level, optname, optval, optlen); } - EXPORT_SYMBOL(sock_common_getsockopt); #ifdef CONFIG_COMPAT @@ -1925,7 +1971,6 @@ int sock_common_recvmsg(struct kiocb *iocb, struct socket *sock, msg->msg_namelen = addr_len; return err; } - EXPORT_SYMBOL(sock_common_recvmsg); /* @@ -1938,7 +1983,6 @@ int sock_common_setsockopt(struct socket *sock, int level, int optname, return sk->sk_prot->setsockopt(sk, level, optname, optval, optlen); } - EXPORT_SYMBOL(sock_common_setsockopt); #ifdef CONFIG_COMPAT @@ -1989,7 +2033,6 @@ void sk_common_release(struct sock *sk) sk_refcnt_debug_release(sk); sock_put(sk); } - EXPORT_SYMBOL(sk_common_release); static DEFINE_RWLOCK(proto_list_lock); @@ -2171,7 +2214,6 @@ out_free_sock_slab: out: return -ENOBUFS; } - EXPORT_SYMBOL(proto_register); void proto_unregister(struct proto *prot) @@ -2198,7 +2240,6 @@ void proto_unregister(struct proto *prot) prot->twsk_prot->twsk_slab = NULL; } } - EXPORT_SYMBOL(proto_unregister); #ifdef CONFIG_PROC_FS @@ -2324,33 +2365,3 @@ static int __init proto_init(void) subsys_initcall(proto_init); #endif /* PROC_FS */ - -EXPORT_SYMBOL(sk_alloc); -EXPORT_SYMBOL(sk_free); -EXPORT_SYMBOL(sk_send_sigurg); -EXPORT_SYMBOL(sock_alloc_send_skb); -EXPORT_SYMBOL(sock_init_data); -EXPORT_SYMBOL(sock_kfree_s); -EXPORT_SYMBOL(sock_kmalloc); -EXPORT_SYMBOL(sock_no_accept); -EXPORT_SYMBOL(sock_no_bind); -EXPORT_SYMBOL(sock_no_connect); -EXPORT_SYMBOL(sock_no_getname); -EXPORT_SYMBOL(sock_no_getsockopt); -EXPORT_SYMBOL(sock_no_ioctl); -EXPORT_SYMBOL(sock_no_listen); -EXPORT_SYMBOL(sock_no_mmap); -EXPORT_SYMBOL(sock_no_poll); -EXPORT_SYMBOL(sock_no_recvmsg); -EXPORT_SYMBOL(sock_no_sendmsg); -EXPORT_SYMBOL(sock_no_sendpage); -EXPORT_SYMBOL(sock_no_setsockopt); -EXPORT_SYMBOL(sock_no_shutdown); -EXPORT_SYMBOL(sock_no_socketpair); -EXPORT_SYMBOL(sock_rfree); -EXPORT_SYMBOL(sock_setsockopt); -EXPORT_SYMBOL(sock_wfree); -EXPORT_SYMBOL(sock_wmalloc); -EXPORT_SYMBOL(sock_i_uid); -EXPORT_SYMBOL(sock_i_ino); -EXPORT_SYMBOL(sysctl_optmem_max); diff --git a/net/core/stream.c b/net/core/stream.c index 8727cead64ad..a37debfeb1b2 100644 --- a/net/core/stream.c +++ b/net/core/stream.c @@ -33,7 +33,8 @@ void sk_stream_write_space(struct sock *sk) clear_bit(SOCK_NOSPACE, &sock->flags); if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) - wake_up_interruptible(sk->sk_sleep); + wake_up_interruptible_poll(sk->sk_sleep, POLLOUT | + POLLWRNORM | POLLWRBAND); if (sock->fasync_list && !(sk->sk_shutdown & SEND_SHUTDOWN)) sock_wake_async(sock, SOCK_WAKE_SPACE, POLL_OUT); } diff --git a/net/core/user_dma.c b/net/core/user_dma.c index 164b090d5ac3..25d717ebc92e 100644 --- a/net/core/user_dma.c +++ b/net/core/user_dma.c @@ -51,6 +51,7 @@ int dma_skb_copy_datagram_iovec(struct dma_chan *chan, { int start = skb_headlen(skb); int i, copy = start - offset; + struct sk_buff *frag_iter; dma_cookie_t cookie = 0; /* Copy header. */ @@ -94,31 +95,28 @@ int dma_skb_copy_datagram_iovec(struct dma_chan *chan, start = end; } - if (skb_shinfo(skb)->frag_list) { - struct sk_buff *list = skb_shinfo(skb)->frag_list; + skb_walk_frags(skb, frag_iter) { + int end; - for (; list; list = list->next) { - int end; + WARN_ON(start > offset + len); - WARN_ON(start > offset + len); - - end = start + list->len; - copy = end - offset; - if (copy > 0) { - if (copy > len) - copy = len; - cookie = dma_skb_copy_datagram_iovec(chan, list, - offset - start, to, copy, - pinned_list); - if (cookie < 0) - goto fault; - len -= copy; - if (len == 0) - goto end; - offset += copy; - } - start = end; + end = start + frag_iter->len; + copy = end - offset; + if (copy > 0) { + if (copy > len) + copy = len; + cookie = dma_skb_copy_datagram_iovec(chan, frag_iter, + offset - start, + to, copy, + pinned_list); + if (cookie < 0) + goto fault; + len -= copy; + if (len == 0) + goto end; + offset += copy; } + start = end; } end: diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index d1dd95289b89..a0a36c9e6cce 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -452,7 +452,7 @@ static struct dst_entry* dccp_v4_route_skb(struct net *net, struct sock *sk, struct sk_buff *skb) { struct rtable *rt; - struct flowi fl = { .oif = skb->rtable->rt_iif, + struct flowi fl = { .oif = skb_rtable(skb)->rt_iif, .nl_u = { .ip4_u = { .daddr = ip_hdr(skb)->saddr, .saddr = ip_hdr(skb)->daddr, @@ -507,14 +507,14 @@ static void dccp_v4_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb) const struct iphdr *rxiph; struct sk_buff *skb; struct dst_entry *dst; - struct net *net = dev_net(rxskb->dst->dev); + struct net *net = dev_net(skb_dst(rxskb)->dev); struct sock *ctl_sk = net->dccp.v4_ctl_sk; /* Never send a reset in response to a reset. */ if (dccp_hdr(rxskb)->dccph_type == DCCP_PKT_RESET) return; - if (rxskb->rtable->rt_type != RTN_LOCAL) + if (skb_rtable(rxskb)->rt_type != RTN_LOCAL) return; dst = dccp_v4_route_skb(net, ctl_sk, rxskb); @@ -528,7 +528,7 @@ static void dccp_v4_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb) rxiph = ip_hdr(rxskb); dccp_hdr(skb)->dccph_checksum = dccp_v4_csum_finish(skb, rxiph->saddr, rxiph->daddr); - skb->dst = dst_clone(dst); + skb_dst_set(skb, dst_clone(dst)); bh_lock_sock(ctl_sk); err = ip_build_and_send_pkt(skb, ctl_sk, @@ -567,7 +567,7 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb); /* Never answer to DCCP_PKT_REQUESTs send to broadcast or multicast */ - if (skb->rtable->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) + if (skb_rtable(skb)->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) return 0; /* discard, don't send a reset here */ if (dccp_bad_service_code(sk, service)) { diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index b963f35c65f6..3e70faab2989 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -85,7 +85,7 @@ static inline __u32 dccp_v6_init_sequence(struct sk_buff *skb) } static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, - int type, int code, int offset, __be32 info) + u8 type, u8 code, int offset, __be32 info) { struct ipv6hdr *hdr = (struct ipv6hdr *)skb->data; const struct dccp_hdr *dh = (struct dccp_hdr *)(skb->data + offset); @@ -314,8 +314,9 @@ static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb) struct ipv6hdr *rxip6h; struct sk_buff *skb; struct flowi fl; - struct net *net = dev_net(rxskb->dst->dev); + struct net *net = dev_net(skb_dst(rxskb)->dev); struct sock *ctl_sk = net->dccp.v6_ctl_sk; + struct dst_entry *dst; if (dccp_hdr(rxskb)->dccph_type == DCCP_PKT_RESET) return; @@ -342,8 +343,9 @@ static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb) security_skb_classify_flow(rxskb, &fl); /* sk = NULL, but it is safe for now. RST socket required. */ - if (!ip6_dst_lookup(ctl_sk, &skb->dst, &fl)) { - if (xfrm_lookup(net, &skb->dst, &fl, NULL, 0) >= 0) { + if (!ip6_dst_lookup(ctl_sk, &dst, &fl)) { + if (xfrm_lookup(net, &dst, &fl, NULL, 0) >= 0) { + skb_dst_set(skb, dst); ip6_xmit(ctl_sk, skb, &fl, NULL, 0); DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS); DCCP_INC_STATS_BH(DCCP_MIB_OUTRSTS); diff --git a/net/dccp/output.c b/net/dccp/output.c index 36bcc00654d3..c0e88c16d088 100644 --- a/net/dccp/output.c +++ b/net/dccp/output.c @@ -350,7 +350,7 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst, /* Reserve space for headers. */ skb_reserve(skb, sk->sk_prot->max_header); - skb->dst = dst_clone(dst); + skb_dst_set(skb, dst_clone(dst)); dreq = dccp_rsk(req); if (inet_rsk(req)->acked) /* increase ISS upon retransmission */ diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c index 9647d911f916..d351b8db0df5 100644 --- a/net/decnet/af_decnet.c +++ b/net/decnet/af_decnet.c @@ -1075,6 +1075,7 @@ static int dn_accept(struct socket *sock, struct socket *newsock, int flags) int err = 0; unsigned char type; long timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK); + struct dst_entry *dst; lock_sock(sk); @@ -1102,8 +1103,9 @@ static int dn_accept(struct socket *sock, struct socket *newsock, int flags) } release_sock(sk); - dst_release(xchg(&newsk->sk_dst_cache, skb->dst)); - skb->dst = NULL; + dst = skb_dst(skb); + dst_release(xchg(&newsk->sk_dst_cache, dst)); + skb_dst_set(skb, NULL); DN_SK(newsk)->state = DN_CR; DN_SK(newsk)->addrrem = cb->src_port; @@ -1238,7 +1240,7 @@ static int dn_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) return val; case TIOCOUTQ: - amount = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc); + amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk); if (amount < 0) amount = 0; err = put_user(amount, (int __user *)arg); @@ -1250,14 +1252,8 @@ static int dn_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) if (skb) { amount = skb->len; } else { - skb = sk->sk_receive_queue.next; - for (;;) { - if (skb == - (struct sk_buff *)&sk->sk_receive_queue) - break; + skb_queue_walk(&sk->sk_receive_queue, skb) amount += skb->len; - skb = skb->next; - } } release_sock(sk); err = put_user(amount, (int __user *)arg); @@ -1644,13 +1640,13 @@ static int __dn_getsockopt(struct socket *sock, int level,int optname, char __us static int dn_data_ready(struct sock *sk, struct sk_buff_head *q, int flags, int target) { - struct sk_buff *skb = q->next; + struct sk_buff *skb; int len = 0; if (flags & MSG_OOB) return !skb_queue_empty(q) ? 1 : 0; - while(skb != (struct sk_buff *)q) { + skb_queue_walk(q, skb) { struct dn_skb_cb *cb = DN_SKB_CB(skb); len += skb->len; @@ -1666,8 +1662,6 @@ static int dn_data_ready(struct sock *sk, struct sk_buff_head *q, int flags, int /* minimum data length for read exceeded */ if (len >= target) return 1; - - skb = skb->next; } return 0; @@ -1683,7 +1677,7 @@ static int dn_recvmsg(struct kiocb *iocb, struct socket *sock, size_t target = size > 1 ? 1 : 0; size_t copied = 0; int rv = 0; - struct sk_buff *skb, *nskb; + struct sk_buff *skb, *n; struct dn_skb_cb *cb = NULL; unsigned char eor = 0; long timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); @@ -1758,7 +1752,7 @@ static int dn_recvmsg(struct kiocb *iocb, struct socket *sock, finish_wait(sk->sk_sleep, &wait); } - for(skb = queue->next; skb != (struct sk_buff *)queue; skb = nskb) { + skb_queue_walk_safe(queue, skb, n) { unsigned int chunk = skb->len; cb = DN_SKB_CB(skb); @@ -1775,7 +1769,6 @@ static int dn_recvmsg(struct kiocb *iocb, struct socket *sock, skb_pull(skb, chunk); eor = cb->nsp_flags & 0x40; - nskb = skb->next; if (skb->len == 0) { skb_unlink(skb, queue); diff --git a/net/decnet/dn_neigh.c b/net/decnet/dn_neigh.c index 05b5aa05e50e..923786bd6d01 100644 --- a/net/decnet/dn_neigh.c +++ b/net/decnet/dn_neigh.c @@ -204,7 +204,7 @@ static void dn_short_error_report(struct neighbour *neigh, struct sk_buff *skb) static int dn_neigh_output_packet(struct sk_buff *skb) { - struct dst_entry *dst = skb->dst; + struct dst_entry *dst = skb_dst(skb); struct dn_route *rt = (struct dn_route *)dst; struct neighbour *neigh = dst->neighbour; struct net_device *dev = neigh->dev; @@ -224,7 +224,7 @@ static int dn_neigh_output_packet(struct sk_buff *skb) static int dn_long_output(struct sk_buff *skb) { - struct dst_entry *dst = skb->dst; + struct dst_entry *dst = skb_dst(skb); struct neighbour *neigh = dst->neighbour; struct net_device *dev = neigh->dev; int headroom = dev->hard_header_len + sizeof(struct dn_long_packet) + 3; @@ -270,7 +270,7 @@ static int dn_long_output(struct sk_buff *skb) static int dn_short_output(struct sk_buff *skb) { - struct dst_entry *dst = skb->dst; + struct dst_entry *dst = skb_dst(skb); struct neighbour *neigh = dst->neighbour; struct net_device *dev = neigh->dev; int headroom = dev->hard_header_len + sizeof(struct dn_short_packet) + 2; @@ -313,7 +313,7 @@ static int dn_short_output(struct sk_buff *skb) */ static int dn_phase3_output(struct sk_buff *skb) { - struct dst_entry *dst = skb->dst; + struct dst_entry *dst = skb_dst(skb); struct neighbour *neigh = dst->neighbour; struct net_device *dev = neigh->dev; int headroom = dev->hard_header_len + sizeof(struct dn_short_packet) + 2; diff --git a/net/decnet/dn_nsp_in.c b/net/decnet/dn_nsp_in.c index 5d8a2a56fd39..932408dca86d 100644 --- a/net/decnet/dn_nsp_in.c +++ b/net/decnet/dn_nsp_in.c @@ -578,6 +578,7 @@ out: static __inline__ int dn_queue_skb(struct sock *sk, struct sk_buff *skb, int sig, struct sk_buff_head *queue) { int err; + int skb_len; /* Cast skb->rcvbuf to unsigned... It's pointless, but reduces number of warnings when compiling with -W --ANK @@ -592,22 +593,12 @@ static __inline__ int dn_queue_skb(struct sock *sk, struct sk_buff *skb, int sig if (err) goto out; + skb_len = skb->len; skb_set_owner_r(skb, sk); skb_queue_tail(queue, skb); - /* This code only runs from BH or BH protected context. - * Therefore the plain read_lock is ok here. -DaveM - */ - read_lock(&sk->sk_callback_lock); - if (!sock_flag(sk, SOCK_DEAD)) { - struct socket *sock = sk->sk_socket; - wake_up_interruptible(sk->sk_sleep); - if (sock && sock->fasync_list && - !test_bit(SOCK_ASYNC_WAITDATA, &sock->flags)) - __kill_fasync(sock->fasync_list, sig, - (sig == SIGURG) ? POLL_PRI : POLL_IN); - } - read_unlock(&sk->sk_callback_lock); + if (!sock_flag(sk, SOCK_DEAD)) + sk->sk_data_ready(sk, skb_len); out: return err; } diff --git a/net/decnet/dn_nsp_out.c b/net/decnet/dn_nsp_out.c index 2013c25b7f5a..a65e929ce76c 100644 --- a/net/decnet/dn_nsp_out.c +++ b/net/decnet/dn_nsp_out.c @@ -85,7 +85,7 @@ static void dn_nsp_send(struct sk_buff *skb) dst = sk_dst_check(sk, 0); if (dst) { try_again: - skb->dst = dst; + skb_dst_set(skb, dst); dst_output(skb); return; } @@ -382,7 +382,7 @@ int dn_nsp_check_xmit_queue(struct sock *sk, struct sk_buff *skb, struct sk_buff { struct dn_skb_cb *cb = DN_SKB_CB(skb); struct dn_scp *scp = DN_SK(sk); - struct sk_buff *skb2, *list, *ack = NULL; + struct sk_buff *skb2, *n, *ack = NULL; int wakeup = 0; int try_retrans = 0; unsigned long reftime = cb->stamp; @@ -390,9 +390,7 @@ int dn_nsp_check_xmit_queue(struct sock *sk, struct sk_buff *skb, struct sk_buff unsigned short xmit_count; unsigned short segnum; - skb2 = q->next; - list = (struct sk_buff *)q; - while(list != skb2) { + skb_queue_walk_safe(q, skb2, n) { struct dn_skb_cb *cb2 = DN_SKB_CB(skb2); if (dn_before_or_equal(cb2->segnum, acknum)) @@ -400,8 +398,6 @@ int dn_nsp_check_xmit_queue(struct sock *sk, struct sk_buff *skb, struct sk_buff /* printk(KERN_DEBUG "ack: %s %04x %04x\n", ack ? "ACK" : "SKIP", (int)cb2->segnum, (int)acknum); */ - skb2 = skb2->next; - if (ack == NULL) continue; @@ -586,7 +582,7 @@ static __inline__ void dn_nsp_do_disc(struct sock *sk, unsigned char msgflg, * to be able to send disc packets out which have no socket * associations. */ - skb->dst = dst_clone(dst); + skb_dst_set(skb, dst_clone(dst)); dst_output(skb); } @@ -615,7 +611,7 @@ void dn_nsp_return_disc(struct sk_buff *skb, unsigned char msgflg, int ddl = 0; gfp_t gfp = GFP_ATOMIC; - dn_nsp_do_disc(NULL, msgflg, reason, gfp, skb->dst, ddl, + dn_nsp_do_disc(NULL, msgflg, reason, gfp, skb_dst(skb), ddl, NULL, cb->src_port, cb->dst_port); } diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index 0cc4394117df..1d6ca8a98dc6 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -678,7 +678,7 @@ out: static int dn_output(struct sk_buff *skb) { - struct dst_entry *dst = skb->dst; + struct dst_entry *dst = skb_dst(skb); struct dn_route *rt = (struct dn_route *)dst; struct net_device *dev = dst->dev; struct dn_skb_cb *cb = DN_SKB_CB(skb); @@ -717,7 +717,7 @@ error: static int dn_forward(struct sk_buff *skb) { struct dn_skb_cb *cb = DN_SKB_CB(skb); - struct dst_entry *dst = skb->dst; + struct dst_entry *dst = skb_dst(skb); struct dn_dev *dn_db = dst->dev->dn_ptr; struct dn_route *rt; struct neighbour *neigh = dst->neighbour; @@ -730,7 +730,7 @@ static int dn_forward(struct sk_buff *skb) goto drop; /* Ensure that we have enough space for headers */ - rt = (struct dn_route *)skb->dst; + rt = (struct dn_route *)skb_dst(skb); header_len = dn_db->use_long ? 21 : 6; if (skb_cow(skb, LL_RESERVED_SPACE(rt->u.dst.dev)+header_len)) goto drop; @@ -1392,7 +1392,8 @@ make_route: goto e_neighbour; hash = dn_hash(rt->fl.fld_src, rt->fl.fld_dst); - dn_insert_route(rt, hash, (struct dn_route **)&skb->dst); + dn_insert_route(rt, hash, &rt); + skb_dst_set(skb, &rt->u.dst); done: if (neigh) @@ -1424,7 +1425,7 @@ static int dn_route_input(struct sk_buff *skb) struct dn_skb_cb *cb = DN_SKB_CB(skb); unsigned hash = dn_hash(cb->src, cb->dst); - if (skb->dst) + if (skb_dst(skb)) return 0; rcu_read_lock(); @@ -1437,7 +1438,7 @@ static int dn_route_input(struct sk_buff *skb) (rt->fl.iif == cb->iif)) { dst_use(&rt->u.dst, jiffies); rcu_read_unlock(); - skb->dst = (struct dst_entry *)rt; + skb_dst_set(skb, (struct dst_entry *)rt); return 0; } } @@ -1449,7 +1450,7 @@ static int dn_route_input(struct sk_buff *skb) static int dn_rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event, int nowait, unsigned int flags) { - struct dn_route *rt = (struct dn_route *)skb->dst; + struct dn_route *rt = (struct dn_route *)skb_dst(skb); struct rtmsg *r; struct nlmsghdr *nlh; unsigned char *b = skb_tail_pointer(skb); @@ -1554,7 +1555,7 @@ static int dn_cache_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, void err = dn_route_input(skb); local_bh_enable(); memset(cb, 0, sizeof(struct dn_skb_cb)); - rt = (struct dn_route *)skb->dst; + rt = (struct dn_route *)skb_dst(skb); if (!err && -rt->u.dst.error) err = rt->u.dst.error; } else { @@ -1570,7 +1571,7 @@ static int dn_cache_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, void skb->dev = NULL; if (err) goto out_free; - skb->dst = &rt->u.dst; + skb_dst_set(skb, &rt->u.dst); if (rtm->rtm_flags & RTM_F_NOTIFY) rt->rt_flags |= RTCF_NOTIFY; @@ -1622,15 +1623,15 @@ int dn_cache_dump(struct sk_buff *skb, struct netlink_callback *cb) rt = rcu_dereference(rt->u.dst.dn_next), idx++) { if (idx < s_idx) continue; - skb->dst = dst_clone(&rt->u.dst); + skb_dst_set(skb, dst_clone(&rt->u.dst)); if (dn_rt_fill_info(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, RTM_NEWROUTE, 1, NLM_F_MULTI) <= 0) { - dst_release(xchg(&skb->dst, NULL)); + skb_dst_drop(skb); rcu_read_unlock_bh(); goto done; } - dst_release(xchg(&skb->dst, NULL)); + skb_dst_drop(skb); } rcu_read_unlock_bh(); } diff --git a/net/decnet/dn_rules.c b/net/decnet/dn_rules.c index 14fbca55e908..72495f25269f 100644 --- a/net/decnet/dn_rules.c +++ b/net/decnet/dn_rules.c @@ -115,7 +115,7 @@ static int dn_fib_rule_match(struct fib_rule *rule, struct flowi *fl, int flags) } static int dn_fib_rule_configure(struct fib_rule *rule, struct sk_buff *skb, - struct nlmsghdr *nlh, struct fib_rule_hdr *frh, + struct fib_rule_hdr *frh, struct nlattr **tb) { int err = -EINVAL; @@ -192,7 +192,7 @@ unsigned dnet_addr_type(__le16 addr) } static int dn_fib_rule_fill(struct fib_rule *rule, struct sk_buff *skb, - struct nlmsghdr *nlh, struct fib_rule_hdr *frh) + struct fib_rule_hdr *frh) { struct dn_fib_rule *r = (struct dn_fib_rule *)rule; diff --git a/net/dsa/slave.c b/net/dsa/slave.c index ed131181215d..2175e6d5cc8d 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -67,7 +67,7 @@ static int dsa_slave_open(struct net_device *dev) return -ENETDOWN; if (compare_ether_addr(dev->dev_addr, master->dev_addr)) { - err = dev_unicast_add(master, dev->dev_addr, ETH_ALEN); + err = dev_unicast_add(master, dev->dev_addr); if (err < 0) goto out; } @@ -90,7 +90,7 @@ clear_allmulti: dev_set_allmulti(master, -1); del_unicast: if (compare_ether_addr(dev->dev_addr, master->dev_addr)) - dev_unicast_delete(master, dev->dev_addr, ETH_ALEN); + dev_unicast_delete(master, dev->dev_addr); out: return err; } @@ -108,7 +108,7 @@ static int dsa_slave_close(struct net_device *dev) dev_set_promiscuity(master, -1); if (compare_ether_addr(dev->dev_addr, master->dev_addr)) - dev_unicast_delete(master, dev->dev_addr, ETH_ALEN); + dev_unicast_delete(master, dev->dev_addr); return 0; } @@ -147,13 +147,13 @@ static int dsa_slave_set_mac_address(struct net_device *dev, void *a) goto out; if (compare_ether_addr(addr->sa_data, master->dev_addr)) { - err = dev_unicast_add(master, addr->sa_data, ETH_ALEN); + err = dev_unicast_add(master, addr->sa_data); if (err < 0) return err; } if (compare_ether_addr(dev->dev_addr, master->dev_addr)) - dev_unicast_delete(master, dev->dev_addr, ETH_ALEN); + dev_unicast_delete(master, dev->dev_addr); out: memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); diff --git a/net/econet/af_econet.c b/net/econet/af_econet.c index 6f479fa522c3..2e1f836d4240 100644 --- a/net/econet/af_econet.c +++ b/net/econet/af_econet.c @@ -540,8 +540,7 @@ static void econet_destroy_timer(unsigned long data) { struct sock *sk=(struct sock *)data; - if (!atomic_read(&sk->sk_wmem_alloc) && - !atomic_read(&sk->sk_rmem_alloc)) { + if (!sk_has_allocations(sk)) { sk_free(sk); return; } @@ -579,8 +578,7 @@ static int econet_release(struct socket *sock) skb_queue_purge(&sk->sk_receive_queue); - if (atomic_read(&sk->sk_rmem_alloc) || - atomic_read(&sk->sk_wmem_alloc)) { + if (sk_has_allocations(sk)) { sk->sk_timer.data = (unsigned long)sk; sk->sk_timer.expires = jiffies + HZ; sk->sk_timer.function = econet_destroy_timer; @@ -901,15 +899,10 @@ static void aun_tx_ack(unsigned long seq, int result) struct ec_cb *eb; spin_lock_irqsave(&aun_queue_lock, flags); - skb = skb_peek(&aun_queue); - while (skb && skb != (struct sk_buff *)&aun_queue) - { - struct sk_buff *newskb = skb->next; + skb_queue_walk(&aun_queue, skb) { eb = (struct ec_cb *)&skb->cb; if (eb->seq == seq) goto foundit; - - skb = newskb; } spin_unlock_irqrestore(&aun_queue_lock, flags); printk(KERN_DEBUG "AUN: unknown sequence %ld\n", seq); @@ -982,23 +975,18 @@ static void aun_data_available(struct sock *sk, int slen) static void ab_cleanup(unsigned long h) { - struct sk_buff *skb; + struct sk_buff *skb, *n; unsigned long flags; spin_lock_irqsave(&aun_queue_lock, flags); - skb = skb_peek(&aun_queue); - while (skb && skb != (struct sk_buff *)&aun_queue) - { - struct sk_buff *newskb = skb->next; + skb_queue_walk_safe(&aun_queue, skb, n) { struct ec_cb *eb = (struct ec_cb *)&skb->cb; - if ((jiffies - eb->start) > eb->timeout) - { + if ((jiffies - eb->start) > eb->timeout) { tx_result(skb->sk, eb->cookie, ECTYPE_TRANSMIT_NOT_PRESENT); skb_unlink(skb, &aun_queue); kfree_skb(skb); } - skb = newskb; } spin_unlock_irqrestore(&aun_queue_lock, flags); diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c index 280352aba403..5a883affecd3 100644 --- a/net/ethernet/eth.c +++ b/net/ethernet/eth.c @@ -337,11 +337,6 @@ const struct header_ops eth_header_ops ____cacheline_aligned = { void ether_setup(struct net_device *dev) { dev->header_ops = ð_header_ops; -#ifdef CONFIG_COMPAT_NET_DEV_OPS - dev->change_mtu = eth_change_mtu; - dev->set_mac_address = eth_mac_addr; - dev->validate_addr = eth_validate_addr; -#endif dev->type = ARPHRD_ETHER; dev->hard_header_len = ETH_HLEN; dev->mtu = ETH_DATA_LEN; diff --git a/net/ieee802154/Kconfig b/net/ieee802154/Kconfig new file mode 100644 index 000000000000..1c1de97d264a --- /dev/null +++ b/net/ieee802154/Kconfig @@ -0,0 +1,12 @@ +config IEEE802154 + tristate "IEEE Std 802.15.4 Low-Rate Wireless Personal Area Networks support (EXPERIMENTAL)" + depends on EXPERIMENTAL + ---help--- + IEEE Std 802.15.4 defines a low data rate, low power and low + complexity short range wireless personal area networks. It was + designed to organise networks of sensors, switches, etc automation + devices. Maximum allowed data rate is 250 kb/s and typical personal + operating space around 10m. + + Say Y here to compile LR-WPAN support into the kernel or say M to + compile it as modules. diff --git a/net/ieee802154/Makefile b/net/ieee802154/Makefile new file mode 100644 index 000000000000..f99338a26100 --- /dev/null +++ b/net/ieee802154/Makefile @@ -0,0 +1,5 @@ +obj-$(CONFIG_IEEE802154) += nl802154.o af_802154.o +nl802154-y := netlink.o nl_policy.o +af_802154-y := af_ieee802154.o raw.o dgram.o + +ccflags-y += -Wall -DDEBUG diff --git a/net/ieee802154/af802154.h b/net/ieee802154/af802154.h new file mode 100644 index 000000000000..b1ec52537522 --- /dev/null +++ b/net/ieee802154/af802154.h @@ -0,0 +1,36 @@ +/* + * Internal interfaces for ieee 802.15.4 address family. + * + * Copyright 2007, 2008, 2009 Siemens AG + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Written by: + * Sergey Lapin + * Dmitry Eremin-Solenikov + */ + +#ifndef AF802154_H +#define AF802154_H + +struct sk_buff; +struct net_devce; +extern struct proto ieee802154_raw_prot; +extern struct proto ieee802154_dgram_prot; +void ieee802154_raw_deliver(struct net_device *dev, struct sk_buff *skb); +int ieee802154_dgram_deliver(struct net_device *dev, struct sk_buff *skb); +struct net_device *ieee802154_get_dev(struct net *net, + struct ieee802154_addr *addr); + +#endif diff --git a/net/ieee802154/af_ieee802154.c b/net/ieee802154/af_ieee802154.c new file mode 100644 index 000000000000..3bb6bdb1dac1 --- /dev/null +++ b/net/ieee802154/af_ieee802154.c @@ -0,0 +1,366 @@ +/* + * IEEE802154.4 socket interface + * + * Copyright 2007, 2008 Siemens AG + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Written by: + * Sergey Lapin + * Maxim Gorbachyov + */ + +#include +#include +#include +#include +#include +#include /* For TIOCOUTQ/INQ */ +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "af802154.h" + +/* + * Utility function for families + */ +struct net_device *ieee802154_get_dev(struct net *net, + struct ieee802154_addr *addr) +{ + struct net_device *dev = NULL; + struct net_device *tmp; + u16 pan_id, short_addr; + + switch (addr->addr_type) { + case IEEE802154_ADDR_LONG: + rtnl_lock(); + dev = dev_getbyhwaddr(net, ARPHRD_IEEE802154, addr->hwaddr); + if (dev) + dev_hold(dev); + rtnl_unlock(); + break; + case IEEE802154_ADDR_SHORT: + if (addr->pan_id == 0xffff || + addr->short_addr == IEEE802154_ADDR_UNDEF || + addr->short_addr == 0xffff) + break; + + rtnl_lock(); + + for_each_netdev(net, tmp) { + if (tmp->type != ARPHRD_IEEE802154) + continue; + + pan_id = ieee802154_mlme_ops(tmp)->get_pan_id(tmp); + short_addr = + ieee802154_mlme_ops(tmp)->get_short_addr(tmp); + + if (pan_id == addr->pan_id && + short_addr == addr->short_addr) { + dev = tmp; + dev_hold(dev); + break; + } + } + + rtnl_unlock(); + break; + default: + pr_warning("Unsupported ieee802154 address type: %d\n", + addr->addr_type); + break; + } + + return dev; +} + +static int ieee802154_sock_release(struct socket *sock) +{ + struct sock *sk = sock->sk; + + if (sk) { + sock->sk = NULL; + sk->sk_prot->close(sk, 0); + } + return 0; +} +static int ieee802154_sock_sendmsg(struct kiocb *iocb, struct socket *sock, + struct msghdr *msg, size_t len) +{ + struct sock *sk = sock->sk; + + return sk->sk_prot->sendmsg(iocb, sk, msg, len); +} + +static int ieee802154_sock_bind(struct socket *sock, struct sockaddr *uaddr, + int addr_len) +{ + struct sock *sk = sock->sk; + + if (sk->sk_prot->bind) + return sk->sk_prot->bind(sk, uaddr, addr_len); + + return sock_no_bind(sock, uaddr, addr_len); +} + +static int ieee802154_sock_connect(struct socket *sock, struct sockaddr *uaddr, + int addr_len, int flags) +{ + struct sock *sk = sock->sk; + + if (uaddr->sa_family == AF_UNSPEC) + return sk->sk_prot->disconnect(sk, flags); + + return sk->sk_prot->connect(sk, uaddr, addr_len); +} + +static int ieee802154_dev_ioctl(struct sock *sk, struct ifreq __user *arg, + unsigned int cmd) +{ + struct ifreq ifr; + int ret = -EINVAL; + struct net_device *dev; + + if (copy_from_user(&ifr, arg, sizeof(struct ifreq))) + return -EFAULT; + + ifr.ifr_name[IFNAMSIZ-1] = 0; + + dev_load(sock_net(sk), ifr.ifr_name); + dev = dev_get_by_name(sock_net(sk), ifr.ifr_name); + if (dev->type == ARPHRD_IEEE802154 || + dev->type == ARPHRD_IEEE802154_PHY) + ret = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, cmd); + + if (!ret && copy_to_user(arg, &ifr, sizeof(struct ifreq))) + ret = -EFAULT; + dev_put(dev); + + return ret; +} + +static int ieee802154_sock_ioctl(struct socket *sock, unsigned int cmd, + unsigned long arg) +{ + struct sock *sk = sock->sk; + + switch (cmd) { + case SIOCGSTAMP: + return sock_get_timestamp(sk, (struct timeval __user *)arg); + case SIOCGSTAMPNS: + return sock_get_timestampns(sk, (struct timespec __user *)arg); + case SIOCGIFADDR: + case SIOCSIFADDR: + return ieee802154_dev_ioctl(sk, (struct ifreq __user *)arg, + cmd); + default: + if (!sk->sk_prot->ioctl) + return -ENOIOCTLCMD; + return sk->sk_prot->ioctl(sk, cmd, arg); + } +} + +static const struct proto_ops ieee802154_raw_ops = { + .family = PF_IEEE802154, + .owner = THIS_MODULE, + .release = ieee802154_sock_release, + .bind = ieee802154_sock_bind, + .connect = ieee802154_sock_connect, + .socketpair = sock_no_socketpair, + .accept = sock_no_accept, + .getname = sock_no_getname, + .poll = datagram_poll, + .ioctl = ieee802154_sock_ioctl, + .listen = sock_no_listen, + .shutdown = sock_no_shutdown, + .setsockopt = sock_common_setsockopt, + .getsockopt = sock_common_getsockopt, + .sendmsg = ieee802154_sock_sendmsg, + .recvmsg = sock_common_recvmsg, + .mmap = sock_no_mmap, + .sendpage = sock_no_sendpage, +#ifdef CONFIG_COMPAT + .compat_setsockopt = compat_sock_common_setsockopt, + .compat_getsockopt = compat_sock_common_getsockopt, +#endif +}; + +static const struct proto_ops ieee802154_dgram_ops = { + .family = PF_IEEE802154, + .owner = THIS_MODULE, + .release = ieee802154_sock_release, + .bind = ieee802154_sock_bind, + .connect = ieee802154_sock_connect, + .socketpair = sock_no_socketpair, + .accept = sock_no_accept, + .getname = sock_no_getname, + .poll = datagram_poll, + .ioctl = ieee802154_sock_ioctl, + .listen = sock_no_listen, + .shutdown = sock_no_shutdown, + .setsockopt = sock_common_setsockopt, + .getsockopt = sock_common_getsockopt, + .sendmsg = ieee802154_sock_sendmsg, + .recvmsg = sock_common_recvmsg, + .mmap = sock_no_mmap, + .sendpage = sock_no_sendpage, +#ifdef CONFIG_COMPAT + .compat_setsockopt = compat_sock_common_setsockopt, + .compat_getsockopt = compat_sock_common_getsockopt, +#endif +}; + + +/* + * Create a socket. Initialise the socket, blank the addresses + * set the state. + */ +static int ieee802154_create(struct net *net, struct socket *sock, + int protocol) +{ + struct sock *sk; + int rc; + struct proto *proto; + const struct proto_ops *ops; + + if (net != &init_net) + return -EAFNOSUPPORT; + + switch (sock->type) { + case SOCK_RAW: + proto = &ieee802154_raw_prot; + ops = &ieee802154_raw_ops; + break; + case SOCK_DGRAM: + proto = &ieee802154_dgram_prot; + ops = &ieee802154_dgram_ops; + break; + default: + rc = -ESOCKTNOSUPPORT; + goto out; + } + + rc = -ENOMEM; + sk = sk_alloc(net, PF_IEEE802154, GFP_KERNEL, proto); + if (!sk) + goto out; + rc = 0; + + sock->ops = ops; + + sock_init_data(sock, sk); + /* FIXME: sk->sk_destruct */ + sk->sk_family = PF_IEEE802154; + + /* Checksums on by default */ + sock_set_flag(sk, SOCK_ZAPPED); + + if (sk->sk_prot->hash) + sk->sk_prot->hash(sk); + + if (sk->sk_prot->init) { + rc = sk->sk_prot->init(sk); + if (rc) + sk_common_release(sk); + } +out: + return rc; +} + +static struct net_proto_family ieee802154_family_ops = { + .family = PF_IEEE802154, + .create = ieee802154_create, + .owner = THIS_MODULE, +}; + +static int ieee802154_rcv(struct sk_buff *skb, struct net_device *dev, + struct packet_type *pt, struct net_device *orig_dev) +{ + if (!netif_running(dev)) + return -ENODEV; + pr_debug("got frame, type %d, dev %p\n", dev->type, dev); +#ifdef DEBUG + print_hex_dump_bytes("ieee802154_rcv ", DUMP_PREFIX_NONE, skb->data, skb->len); +#endif + + if (!net_eq(dev_net(dev), &init_net)) + goto drop; + + ieee802154_raw_deliver(dev, skb); + + if (dev->type != ARPHRD_IEEE802154) + goto drop; + + if (skb->pkt_type != PACKET_OTHERHOST) + return ieee802154_dgram_deliver(dev, skb); + +drop: + kfree_skb(skb); + return NET_RX_DROP; +} + + +static struct packet_type ieee802154_packet_type = { + .type = __constant_htons(ETH_P_IEEE802154), + .func = ieee802154_rcv, +}; + +static int __init af_ieee802154_init(void) +{ + int rc = -EINVAL; + + rc = proto_register(&ieee802154_raw_prot, 1); + if (rc) + goto out; + + rc = proto_register(&ieee802154_dgram_prot, 1); + if (rc) + goto err_dgram; + + /* Tell SOCKET that we are alive */ + rc = sock_register(&ieee802154_family_ops); + if (rc) + goto err_sock; + dev_add_pack(&ieee802154_packet_type); + + rc = 0; + goto out; + +err_sock: + proto_unregister(&ieee802154_dgram_prot); +err_dgram: + proto_unregister(&ieee802154_raw_prot); +out: + return rc; +} +static void __exit af_ieee802154_remove(void) +{ + dev_remove_pack(&ieee802154_packet_type); + sock_unregister(PF_IEEE802154); + proto_unregister(&ieee802154_dgram_prot); + proto_unregister(&ieee802154_raw_prot); +} + +module_init(af_ieee802154_init); +module_exit(af_ieee802154_remove); + +MODULE_LICENSE("GPL"); +MODULE_ALIAS_NETPROTO(PF_IEEE802154); diff --git a/net/ieee802154/dgram.c b/net/ieee802154/dgram.c new file mode 100644 index 000000000000..14d39840dd62 --- /dev/null +++ b/net/ieee802154/dgram.c @@ -0,0 +1,395 @@ +/* + * ZigBee socket interface + * + * Copyright 2007, 2008 Siemens AG + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Written by: + * Sergey Lapin + * Dmitry Eremin-Solenikov + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "af802154.h" + +static HLIST_HEAD(dgram_head); +static DEFINE_RWLOCK(dgram_lock); + +struct dgram_sock { + struct sock sk; + + int bound; + struct ieee802154_addr src_addr; + struct ieee802154_addr dst_addr; +}; + +static inline struct dgram_sock *dgram_sk(const struct sock *sk) +{ + return container_of(sk, struct dgram_sock, sk); +} + + +static void dgram_hash(struct sock *sk) +{ + write_lock_bh(&dgram_lock); + sk_add_node(sk, &dgram_head); + sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); + write_unlock_bh(&dgram_lock); +} + +static void dgram_unhash(struct sock *sk) +{ + write_lock_bh(&dgram_lock); + if (sk_del_node_init(sk)) + sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); + write_unlock_bh(&dgram_lock); +} + +static int dgram_init(struct sock *sk) +{ + struct dgram_sock *ro = dgram_sk(sk); + + ro->dst_addr.addr_type = IEEE802154_ADDR_LONG; + ro->dst_addr.pan_id = 0xffff; + memset(&ro->dst_addr.hwaddr, 0xff, sizeof(ro->dst_addr.hwaddr)); + return 0; +} + +static void dgram_close(struct sock *sk, long timeout) +{ + sk_common_release(sk); +} + +static int dgram_bind(struct sock *sk, struct sockaddr *uaddr, int len) +{ + struct sockaddr_ieee802154 *addr = (struct sockaddr_ieee802154 *)uaddr; + struct dgram_sock *ro = dgram_sk(sk); + int err = 0; + struct net_device *dev; + + ro->bound = 0; + + if (len < sizeof(*addr)) + return -EINVAL; + + if (addr->family != AF_IEEE802154) + return -EINVAL; + + lock_sock(sk); + + dev = ieee802154_get_dev(sock_net(sk), &addr->addr); + if (!dev) { + err = -ENODEV; + goto out; + } + + if (dev->type != ARPHRD_IEEE802154) { + err = -ENODEV; + goto out_put; + } + + memcpy(&ro->src_addr, &addr->addr, sizeof(struct ieee802154_addr)); + + ro->bound = 1; +out_put: + dev_put(dev); +out: + release_sock(sk); + + return err; +} + +static int dgram_ioctl(struct sock *sk, int cmd, unsigned long arg) +{ + switch (cmd) { + case SIOCOUTQ: + { + int amount = sk_wmem_alloc_get(sk); + + return put_user(amount, (int __user *)arg); + } + + case SIOCINQ: + { + struct sk_buff *skb; + unsigned long amount; + + amount = 0; + spin_lock_bh(&sk->sk_receive_queue.lock); + skb = skb_peek(&sk->sk_receive_queue); + if (skb != NULL) { + /* + * We will only return the amount + * of this packet since that is all + * that will be read. + */ + /* FIXME: parse the header for more correct value */ + amount = skb->len - (3+8+8); + } + spin_unlock_bh(&sk->sk_receive_queue.lock); + return put_user(amount, (int __user *)arg); + } + + } + return -ENOIOCTLCMD; +} + +/* FIXME: autobind */ +static int dgram_connect(struct sock *sk, struct sockaddr *uaddr, + int len) +{ + struct sockaddr_ieee802154 *addr = (struct sockaddr_ieee802154 *)uaddr; + struct dgram_sock *ro = dgram_sk(sk); + int err = 0; + + if (len < sizeof(*addr)) + return -EINVAL; + + if (addr->family != AF_IEEE802154) + return -EINVAL; + + lock_sock(sk); + + if (!ro->bound) { + err = -ENETUNREACH; + goto out; + } + + memcpy(&ro->dst_addr, &addr->addr, sizeof(struct ieee802154_addr)); + +out: + release_sock(sk); + return err; +} + +static int dgram_disconnect(struct sock *sk, int flags) +{ + struct dgram_sock *ro = dgram_sk(sk); + + lock_sock(sk); + + ro->dst_addr.addr_type = IEEE802154_ADDR_LONG; + memset(&ro->dst_addr.hwaddr, 0xff, sizeof(ro->dst_addr.hwaddr)); + + release_sock(sk); + + return 0; +} + +static int dgram_sendmsg(struct kiocb *iocb, struct sock *sk, + struct msghdr *msg, size_t size) +{ + struct net_device *dev; + unsigned mtu; + struct sk_buff *skb; + struct dgram_sock *ro = dgram_sk(sk); + int err; + + if (msg->msg_flags & MSG_OOB) { + pr_debug("msg->msg_flags = 0x%x\n", msg->msg_flags); + return -EOPNOTSUPP; + } + + if (!ro->bound) + dev = dev_getfirstbyhwtype(sock_net(sk), ARPHRD_IEEE802154); + else + dev = ieee802154_get_dev(sock_net(sk), &ro->src_addr); + + if (!dev) { + pr_debug("no dev\n"); + err = -ENXIO; + goto out; + } + mtu = dev->mtu; + pr_debug("name = %s, mtu = %u\n", dev->name, mtu); + + skb = sock_alloc_send_skb(sk, LL_ALLOCATED_SPACE(dev) + size, + msg->msg_flags & MSG_DONTWAIT, + &err); + if (!skb) + goto out_dev; + + skb_reserve(skb, LL_RESERVED_SPACE(dev)); + + skb_reset_network_header(skb); + + mac_cb(skb)->flags = IEEE802154_FC_TYPE_DATA | MAC_CB_FLAG_ACKREQ; + mac_cb(skb)->seq = ieee802154_mlme_ops(dev)->get_dsn(dev); + err = dev_hard_header(skb, dev, ETH_P_IEEE802154, &ro->dst_addr, + ro->bound ? &ro->src_addr : NULL, size); + if (err < 0) + goto out_skb; + + skb_reset_mac_header(skb); + + err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size); + if (err < 0) + goto out_skb; + + if (size > mtu) { + pr_debug("size = %Zu, mtu = %u\n", size, mtu); + err = -EINVAL; + goto out_skb; + } + + skb->dev = dev; + skb->sk = sk; + skb->protocol = htons(ETH_P_IEEE802154); + + dev_put(dev); + + err = dev_queue_xmit(skb); + if (err > 0) + err = net_xmit_errno(err); + + return err ?: size; + +out_skb: + kfree_skb(skb); +out_dev: + dev_put(dev); +out: + return err; +} + +static int dgram_recvmsg(struct kiocb *iocb, struct sock *sk, + struct msghdr *msg, size_t len, int noblock, int flags, + int *addr_len) +{ + size_t copied = 0; + int err = -EOPNOTSUPP; + struct sk_buff *skb; + + skb = skb_recv_datagram(sk, flags, noblock, &err); + if (!skb) + goto out; + + copied = skb->len; + if (len < copied) { + msg->msg_flags |= MSG_TRUNC; + copied = len; + } + + /* FIXME: skip headers if necessary ?! */ + err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); + if (err) + goto done; + + sock_recv_timestamp(msg, sk, skb); + + if (flags & MSG_TRUNC) + copied = skb->len; +done: + skb_free_datagram(sk, skb); +out: + if (err) + return err; + return copied; +} + +static int dgram_rcv_skb(struct sock *sk, struct sk_buff *skb) +{ + if (sock_queue_rcv_skb(sk, skb) < 0) { + atomic_inc(&sk->sk_drops); + kfree_skb(skb); + return NET_RX_DROP; + } + + return NET_RX_SUCCESS; +} + +static inline int ieee802154_match_sock(u8 *hw_addr, u16 pan_id, + u16 short_addr, struct dgram_sock *ro) +{ + if (!ro->bound) + return 1; + + if (ro->src_addr.addr_type == IEEE802154_ADDR_LONG && + !memcmp(ro->src_addr.hwaddr, hw_addr, IEEE802154_ADDR_LEN)) + return 1; + + if (ro->src_addr.addr_type == IEEE802154_ADDR_SHORT && + pan_id == ro->src_addr.pan_id && + short_addr == ro->src_addr.short_addr) + return 1; + + return 0; +} + +int ieee802154_dgram_deliver(struct net_device *dev, struct sk_buff *skb) +{ + struct sock *sk, *prev = NULL; + struct hlist_node *node; + int ret = NET_RX_SUCCESS; + u16 pan_id, short_addr; + + /* Data frame processing */ + BUG_ON(dev->type != ARPHRD_IEEE802154); + + pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev); + short_addr = ieee802154_mlme_ops(dev)->get_short_addr(dev); + + read_lock(&dgram_lock); + sk_for_each(sk, node, &dgram_head) { + if (ieee802154_match_sock(dev->dev_addr, pan_id, short_addr, + dgram_sk(sk))) { + if (prev) { + struct sk_buff *clone; + clone = skb_clone(skb, GFP_ATOMIC); + if (clone) + dgram_rcv_skb(prev, clone); + } + + prev = sk; + } + } + + if (prev) + dgram_rcv_skb(prev, skb); + else { + kfree_skb(skb); + ret = NET_RX_DROP; + } + read_unlock(&dgram_lock); + + return ret; +} + +struct proto ieee802154_dgram_prot = { + .name = "IEEE-802.15.4-MAC", + .owner = THIS_MODULE, + .obj_size = sizeof(struct dgram_sock), + .init = dgram_init, + .close = dgram_close, + .bind = dgram_bind, + .sendmsg = dgram_sendmsg, + .recvmsg = dgram_recvmsg, + .hash = dgram_hash, + .unhash = dgram_unhash, + .connect = dgram_connect, + .disconnect = dgram_disconnect, + .ioctl = dgram_ioctl, +}; + diff --git a/net/ieee802154/netlink.c b/net/ieee802154/netlink.c new file mode 100644 index 000000000000..105ad10876af --- /dev/null +++ b/net/ieee802154/netlink.c @@ -0,0 +1,523 @@ +/* + * Netlink inteface for IEEE 802.15.4 stack + * + * Copyright 2007, 2008 Siemens AG + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Written by: + * Sergey Lapin + * Dmitry Eremin-Solenikov + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static unsigned int ieee802154_seq_num; + +static struct genl_family ieee802154_coordinator_family = { + .id = GENL_ID_GENERATE, + .hdrsize = 0, + .name = IEEE802154_NL_NAME, + .version = 1, + .maxattr = IEEE802154_ATTR_MAX, +}; + +static struct genl_multicast_group ieee802154_coord_mcgrp = { + .name = IEEE802154_MCAST_COORD_NAME, +}; + +static struct genl_multicast_group ieee802154_beacon_mcgrp = { + .name = IEEE802154_MCAST_BEACON_NAME, +}; + +/* Requests to userspace */ +static struct sk_buff *ieee802154_nl_create(int flags, u8 req) +{ + void *hdr; + struct sk_buff *msg = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); + + if (!msg) + return NULL; + + hdr = genlmsg_put(msg, 0, ieee802154_seq_num++, + &ieee802154_coordinator_family, flags, req); + if (!hdr) { + nlmsg_free(msg); + return NULL; + } + + return msg; +} + +static int ieee802154_nl_finish(struct sk_buff *msg) +{ + /* XXX: nlh is right at the start of msg */ + void *hdr = genlmsg_data(NLMSG_DATA(msg->data)); + + if (!genlmsg_end(msg, hdr)) + goto out; + + return genlmsg_multicast(msg, 0, ieee802154_coord_mcgrp.id, + GFP_ATOMIC); +out: + nlmsg_free(msg); + return -ENOBUFS; +} + +int ieee802154_nl_assoc_indic(struct net_device *dev, + struct ieee802154_addr *addr, u8 cap) +{ + struct sk_buff *msg; + + pr_debug("%s\n", __func__); + + if (addr->addr_type != IEEE802154_ADDR_LONG) { + pr_err("%s: received non-long source address!\n", __func__); + return -EINVAL; + } + + msg = ieee802154_nl_create(0, IEEE802154_ASSOCIATE_INDIC); + if (!msg) + return -ENOBUFS; + + NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); + NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); + NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, + dev->dev_addr); + + NLA_PUT(msg, IEEE802154_ATTR_SRC_HW_ADDR, IEEE802154_ADDR_LEN, + addr->hwaddr); + + NLA_PUT_U8(msg, IEEE802154_ATTR_CAPABILITY, cap); + + return ieee802154_nl_finish(msg); + +nla_put_failure: + nlmsg_free(msg); + return -ENOBUFS; +} +EXPORT_SYMBOL(ieee802154_nl_assoc_indic); + +int ieee802154_nl_assoc_confirm(struct net_device *dev, u16 short_addr, + u8 status) +{ + struct sk_buff *msg; + + pr_debug("%s\n", __func__); + + msg = ieee802154_nl_create(0, IEEE802154_ASSOCIATE_CONF); + if (!msg) + return -ENOBUFS; + + NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); + NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); + NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, + dev->dev_addr); + + NLA_PUT_U16(msg, IEEE802154_ATTR_SHORT_ADDR, short_addr); + NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status); + + return ieee802154_nl_finish(msg); + +nla_put_failure: + nlmsg_free(msg); + return -ENOBUFS; +} +EXPORT_SYMBOL(ieee802154_nl_assoc_confirm); + +int ieee802154_nl_disassoc_indic(struct net_device *dev, + struct ieee802154_addr *addr, u8 reason) +{ + struct sk_buff *msg; + + pr_debug("%s\n", __func__); + + msg = ieee802154_nl_create(0, IEEE802154_DISASSOCIATE_INDIC); + if (!msg) + return -ENOBUFS; + + NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); + NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); + NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, + dev->dev_addr); + + if (addr->addr_type == IEEE802154_ADDR_LONG) + NLA_PUT(msg, IEEE802154_ATTR_SRC_HW_ADDR, IEEE802154_ADDR_LEN, + addr->hwaddr); + else + NLA_PUT_U16(msg, IEEE802154_ATTR_SRC_SHORT_ADDR, + addr->short_addr); + + NLA_PUT_U8(msg, IEEE802154_ATTR_REASON, reason); + + return ieee802154_nl_finish(msg); + +nla_put_failure: + nlmsg_free(msg); + return -ENOBUFS; +} +EXPORT_SYMBOL(ieee802154_nl_disassoc_indic); + +int ieee802154_nl_disassoc_confirm(struct net_device *dev, u8 status) +{ + struct sk_buff *msg; + + pr_debug("%s\n", __func__); + + msg = ieee802154_nl_create(0, IEEE802154_DISASSOCIATE_CONF); + if (!msg) + return -ENOBUFS; + + NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); + NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); + NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, + dev->dev_addr); + + NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status); + + return ieee802154_nl_finish(msg); + +nla_put_failure: + nlmsg_free(msg); + return -ENOBUFS; +} +EXPORT_SYMBOL(ieee802154_nl_disassoc_confirm); + +int ieee802154_nl_beacon_indic(struct net_device *dev, + u16 panid, u16 coord_addr) +{ + struct sk_buff *msg; + + pr_debug("%s\n", __func__); + + msg = ieee802154_nl_create(0, IEEE802154_BEACON_NOTIFY_INDIC); + if (!msg) + return -ENOBUFS; + + NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); + NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); + NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, + dev->dev_addr); + NLA_PUT_U16(msg, IEEE802154_ATTR_COORD_SHORT_ADDR, coord_addr); + NLA_PUT_U16(msg, IEEE802154_ATTR_COORD_PAN_ID, panid); + + return ieee802154_nl_finish(msg); + +nla_put_failure: + nlmsg_free(msg); + return -ENOBUFS; +} +EXPORT_SYMBOL(ieee802154_nl_beacon_indic); + +int ieee802154_nl_scan_confirm(struct net_device *dev, + u8 status, u8 scan_type, u32 unscanned, + u8 *edl/* , struct list_head *pan_desc_list */) +{ + struct sk_buff *msg; + + pr_debug("%s\n", __func__); + + msg = ieee802154_nl_create(0, IEEE802154_SCAN_CONF); + if (!msg) + return -ENOBUFS; + + NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); + NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); + NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, + dev->dev_addr); + + NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status); + NLA_PUT_U8(msg, IEEE802154_ATTR_SCAN_TYPE, scan_type); + NLA_PUT_U32(msg, IEEE802154_ATTR_CHANNELS, unscanned); + + if (edl) + NLA_PUT(msg, IEEE802154_ATTR_ED_LIST, 27, edl); + + return ieee802154_nl_finish(msg); + +nla_put_failure: + nlmsg_free(msg); + return -ENOBUFS; +} +EXPORT_SYMBOL(ieee802154_nl_scan_confirm); + +/* Requests from userspace */ +static struct net_device *ieee802154_nl_get_dev(struct genl_info *info) +{ + struct net_device *dev; + + if (info->attrs[IEEE802154_ATTR_DEV_NAME]) { + char name[IFNAMSIZ + 1]; + nla_strlcpy(name, info->attrs[IEEE802154_ATTR_DEV_NAME], + sizeof(name)); + dev = dev_get_by_name(&init_net, name); + } else if (info->attrs[IEEE802154_ATTR_DEV_INDEX]) + dev = dev_get_by_index(&init_net, + nla_get_u32(info->attrs[IEEE802154_ATTR_DEV_INDEX])); + else + return NULL; + + if (dev->type != ARPHRD_IEEE802154) { + dev_put(dev); + return NULL; + } + + return dev; +} + +static int ieee802154_associate_req(struct sk_buff *skb, + struct genl_info *info) +{ + struct net_device *dev; + struct ieee802154_addr addr; + int ret = -EINVAL; + + if (!info->attrs[IEEE802154_ATTR_CHANNEL] || + !info->attrs[IEEE802154_ATTR_COORD_PAN_ID] || + (!info->attrs[IEEE802154_ATTR_COORD_HW_ADDR] && + !info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]) || + !info->attrs[IEEE802154_ATTR_CAPABILITY]) + return -EINVAL; + + dev = ieee802154_nl_get_dev(info); + if (!dev) + return -ENODEV; + + if (info->attrs[IEEE802154_ATTR_COORD_HW_ADDR]) { + addr.addr_type = IEEE802154_ADDR_LONG; + nla_memcpy(addr.hwaddr, + info->attrs[IEEE802154_ATTR_COORD_HW_ADDR], + IEEE802154_ADDR_LEN); + } else { + addr.addr_type = IEEE802154_ADDR_SHORT; + addr.short_addr = nla_get_u16( + info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]); + } + addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]); + + ret = ieee802154_mlme_ops(dev)->assoc_req(dev, &addr, + nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]), + nla_get_u8(info->attrs[IEEE802154_ATTR_CAPABILITY])); + + dev_put(dev); + return ret; +} + +static int ieee802154_associate_resp(struct sk_buff *skb, + struct genl_info *info) +{ + struct net_device *dev; + struct ieee802154_addr addr; + int ret = -EINVAL; + + if (!info->attrs[IEEE802154_ATTR_STATUS] || + !info->attrs[IEEE802154_ATTR_DEST_HW_ADDR] || + !info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]) + return -EINVAL; + + dev = ieee802154_nl_get_dev(info); + if (!dev) + return -ENODEV; + + addr.addr_type = IEEE802154_ADDR_LONG; + nla_memcpy(addr.hwaddr, info->attrs[IEEE802154_ATTR_DEST_HW_ADDR], + IEEE802154_ADDR_LEN); + addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev); + + + ret = ieee802154_mlme_ops(dev)->assoc_resp(dev, &addr, + nla_get_u16(info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]), + nla_get_u8(info->attrs[IEEE802154_ATTR_STATUS])); + + dev_put(dev); + return ret; +} + +static int ieee802154_disassociate_req(struct sk_buff *skb, + struct genl_info *info) +{ + struct net_device *dev; + struct ieee802154_addr addr; + int ret = -EINVAL; + + if ((!info->attrs[IEEE802154_ATTR_DEST_HW_ADDR] && + !info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]) || + !info->attrs[IEEE802154_ATTR_REASON]) + return -EINVAL; + + dev = ieee802154_nl_get_dev(info); + if (!dev) + return -ENODEV; + + if (info->attrs[IEEE802154_ATTR_DEST_HW_ADDR]) { + addr.addr_type = IEEE802154_ADDR_LONG; + nla_memcpy(addr.hwaddr, + info->attrs[IEEE802154_ATTR_DEST_HW_ADDR], + IEEE802154_ADDR_LEN); + } else { + addr.addr_type = IEEE802154_ADDR_SHORT; + addr.short_addr = nla_get_u16( + info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]); + } + addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev); + + ret = ieee802154_mlme_ops(dev)->disassoc_req(dev, &addr, + nla_get_u8(info->attrs[IEEE802154_ATTR_REASON])); + + dev_put(dev); + return ret; +} + +/* + * PANid, channel, beacon_order = 15, superframe_order = 15, + * PAN_coordinator, battery_life_extension = 0, + * coord_realignment = 0, security_enable = 0 +*/ +static int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info) +{ + struct net_device *dev; + struct ieee802154_addr addr; + + u8 channel, bcn_ord, sf_ord; + int pan_coord, blx, coord_realign; + int ret; + + if (!info->attrs[IEEE802154_ATTR_COORD_PAN_ID] || + !info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR] || + !info->attrs[IEEE802154_ATTR_CHANNEL] || + !info->attrs[IEEE802154_ATTR_BCN_ORD] || + !info->attrs[IEEE802154_ATTR_SF_ORD] || + !info->attrs[IEEE802154_ATTR_PAN_COORD] || + !info->attrs[IEEE802154_ATTR_BAT_EXT] || + !info->attrs[IEEE802154_ATTR_COORD_REALIGN] + ) + return -EINVAL; + + dev = ieee802154_nl_get_dev(info); + if (!dev) + return -ENODEV; + + addr.addr_type = IEEE802154_ADDR_SHORT; + addr.short_addr = nla_get_u16( + info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]); + addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]); + + channel = nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]); + bcn_ord = nla_get_u8(info->attrs[IEEE802154_ATTR_BCN_ORD]); + sf_ord = nla_get_u8(info->attrs[IEEE802154_ATTR_SF_ORD]); + pan_coord = nla_get_u8(info->attrs[IEEE802154_ATTR_PAN_COORD]); + blx = nla_get_u8(info->attrs[IEEE802154_ATTR_BAT_EXT]); + coord_realign = nla_get_u8(info->attrs[IEEE802154_ATTR_COORD_REALIGN]); + + ret = ieee802154_mlme_ops(dev)->start_req(dev, &addr, channel, + bcn_ord, sf_ord, pan_coord, blx, coord_realign); + + dev_put(dev); + return ret; +} + +static int ieee802154_scan_req(struct sk_buff *skb, struct genl_info *info) +{ + struct net_device *dev; + int ret; + u8 type; + u32 channels; + u8 duration; + + if (!info->attrs[IEEE802154_ATTR_SCAN_TYPE] || + !info->attrs[IEEE802154_ATTR_CHANNELS] || + !info->attrs[IEEE802154_ATTR_DURATION]) + return -EINVAL; + + dev = ieee802154_nl_get_dev(info); + if (!dev) + return -ENODEV; + + type = nla_get_u8(info->attrs[IEEE802154_ATTR_SCAN_TYPE]); + channels = nla_get_u32(info->attrs[IEEE802154_ATTR_CHANNELS]); + duration = nla_get_u8(info->attrs[IEEE802154_ATTR_DURATION]); + + ret = ieee802154_mlme_ops(dev)->scan_req(dev, type, channels, + duration); + + dev_put(dev); + return ret; +} + +#define IEEE802154_OP(_cmd, _func) \ + { \ + .cmd = _cmd, \ + .policy = ieee802154_policy, \ + .doit = _func, \ + .dumpit = NULL, \ + .flags = GENL_ADMIN_PERM, \ + } + +static struct genl_ops ieee802154_coordinator_ops[] = { + IEEE802154_OP(IEEE802154_ASSOCIATE_REQ, ieee802154_associate_req), + IEEE802154_OP(IEEE802154_ASSOCIATE_RESP, ieee802154_associate_resp), + IEEE802154_OP(IEEE802154_DISASSOCIATE_REQ, ieee802154_disassociate_req), + IEEE802154_OP(IEEE802154_SCAN_REQ, ieee802154_scan_req), + IEEE802154_OP(IEEE802154_START_REQ, ieee802154_start_req), +}; + +static int __init ieee802154_nl_init(void) +{ + int rc; + int i; + + rc = genl_register_family(&ieee802154_coordinator_family); + if (rc) + goto fail; + + rc = genl_register_mc_group(&ieee802154_coordinator_family, + &ieee802154_coord_mcgrp); + if (rc) + goto fail; + + rc = genl_register_mc_group(&ieee802154_coordinator_family, + &ieee802154_beacon_mcgrp); + if (rc) + goto fail; + + + for (i = 0; i < ARRAY_SIZE(ieee802154_coordinator_ops); i++) { + rc = genl_register_ops(&ieee802154_coordinator_family, + &ieee802154_coordinator_ops[i]); + if (rc) + goto fail; + } + + return 0; + +fail: + genl_unregister_family(&ieee802154_coordinator_family); + return rc; +} +module_init(ieee802154_nl_init); + +static void __exit ieee802154_nl_exit(void) +{ + genl_unregister_family(&ieee802154_coordinator_family); +} +module_exit(ieee802154_nl_exit); + diff --git a/net/ieee802154/nl_policy.c b/net/ieee802154/nl_policy.c new file mode 100644 index 000000000000..c7d71d1adcac --- /dev/null +++ b/net/ieee802154/nl_policy.c @@ -0,0 +1,52 @@ +/* + * nl802154.h + * + * Copyright (C) 2007, 2008 Siemens AG + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include +#include +#include + +#define NLA_HW_ADDR NLA_U64 + +struct nla_policy ieee802154_policy[IEEE802154_ATTR_MAX + 1] = { + [IEEE802154_ATTR_DEV_NAME] = { .type = NLA_STRING, }, + [IEEE802154_ATTR_DEV_INDEX] = { .type = NLA_U32, }, + + [IEEE802154_ATTR_STATUS] = { .type = NLA_U8, }, + [IEEE802154_ATTR_SHORT_ADDR] = { .type = NLA_U16, }, + [IEEE802154_ATTR_HW_ADDR] = { .type = NLA_HW_ADDR, }, + [IEEE802154_ATTR_PAN_ID] = { .type = NLA_U16, }, + [IEEE802154_ATTR_CHANNEL] = { .type = NLA_U8, }, + [IEEE802154_ATTR_COORD_SHORT_ADDR] = { .type = NLA_U16, }, + [IEEE802154_ATTR_COORD_HW_ADDR] = { .type = NLA_HW_ADDR, }, + [IEEE802154_ATTR_COORD_PAN_ID] = { .type = NLA_U16, }, + [IEEE802154_ATTR_SRC_SHORT_ADDR] = { .type = NLA_U16, }, + [IEEE802154_ATTR_SRC_HW_ADDR] = { .type = NLA_HW_ADDR, }, + [IEEE802154_ATTR_SRC_PAN_ID] = { .type = NLA_U16, }, + [IEEE802154_ATTR_DEST_SHORT_ADDR] = { .type = NLA_U16, }, + [IEEE802154_ATTR_DEST_HW_ADDR] = { .type = NLA_HW_ADDR, }, + [IEEE802154_ATTR_DEST_PAN_ID] = { .type = NLA_U16, }, + + [IEEE802154_ATTR_CAPABILITY] = { .type = NLA_U8, }, + [IEEE802154_ATTR_REASON] = { .type = NLA_U8, }, + [IEEE802154_ATTR_SCAN_TYPE] = { .type = NLA_U8, }, + [IEEE802154_ATTR_CHANNELS] = { .type = NLA_U32, }, + [IEEE802154_ATTR_DURATION] = { .type = NLA_U8, }, + [IEEE802154_ATTR_ED_LIST] = { .len = 27 }, +}; diff --git a/net/ieee802154/raw.c b/net/ieee802154/raw.c new file mode 100644 index 000000000000..fca44d59f97e --- /dev/null +++ b/net/ieee802154/raw.c @@ -0,0 +1,254 @@ +/* + * Raw IEEE 802.15.4 sockets + * + * Copyright 2007, 2008 Siemens AG + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Written by: + * Sergey Lapin + * Dmitry Eremin-Solenikov + */ + +#include +#include +#include +#include +#include +#include + +#include "af802154.h" + +static HLIST_HEAD(raw_head); +static DEFINE_RWLOCK(raw_lock); + +static void raw_hash(struct sock *sk) +{ + write_lock_bh(&raw_lock); + sk_add_node(sk, &raw_head); + sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); + write_unlock_bh(&raw_lock); +} + +static void raw_unhash(struct sock *sk) +{ + write_lock_bh(&raw_lock); + if (sk_del_node_init(sk)) + sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); + write_unlock_bh(&raw_lock); +} + +static void raw_close(struct sock *sk, long timeout) +{ + sk_common_release(sk); +} + +static int raw_bind(struct sock *sk, struct sockaddr *uaddr, int len) +{ + struct sockaddr_ieee802154 *addr = (struct sockaddr_ieee802154 *)uaddr; + int err = 0; + struct net_device *dev = NULL; + + if (len < sizeof(*addr)) + return -EINVAL; + + if (addr->family != AF_IEEE802154) + return -EINVAL; + + lock_sock(sk); + + dev = ieee802154_get_dev(sock_net(sk), &addr->addr); + if (!dev) { + err = -ENODEV; + goto out; + } + + if (dev->type != ARPHRD_IEEE802154_PHY && + dev->type != ARPHRD_IEEE802154) { + err = -ENODEV; + goto out_put; + } + + sk->sk_bound_dev_if = dev->ifindex; + sk_dst_reset(sk); + +out_put: + dev_put(dev); +out: + release_sock(sk); + + return err; +} + +static int raw_connect(struct sock *sk, struct sockaddr *uaddr, + int addr_len) +{ + return -ENOTSUPP; +} + +static int raw_disconnect(struct sock *sk, int flags) +{ + return 0; +} + +static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, + size_t size) +{ + struct net_device *dev; + unsigned mtu; + struct sk_buff *skb; + int err; + + if (msg->msg_flags & MSG_OOB) { + pr_debug("msg->msg_flags = 0x%x\n", msg->msg_flags); + return -EOPNOTSUPP; + } + + lock_sock(sk); + if (!sk->sk_bound_dev_if) + dev = dev_getfirstbyhwtype(sock_net(sk), ARPHRD_IEEE802154); + else + dev = dev_get_by_index(sock_net(sk), sk->sk_bound_dev_if); + release_sock(sk); + + if (!dev) { + pr_debug("no dev\n"); + err = -ENXIO; + goto out; + } + + mtu = dev->mtu; + pr_debug("name = %s, mtu = %u\n", dev->name, mtu); + + if (size > mtu) { + pr_debug("size = %Zu, mtu = %u\n", size, mtu); + err = -EINVAL; + goto out_dev; + } + + skb = sock_alloc_send_skb(sk, LL_ALLOCATED_SPACE(dev) + size, + msg->msg_flags & MSG_DONTWAIT, &err); + if (!skb) + goto out_dev; + + skb_reserve(skb, LL_RESERVED_SPACE(dev)); + + skb_reset_mac_header(skb); + skb_reset_network_header(skb); + + err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size); + if (err < 0) + goto out_skb; + + skb->dev = dev; + skb->sk = sk; + skb->protocol = htons(ETH_P_IEEE802154); + + dev_put(dev); + + err = dev_queue_xmit(skb); + if (err > 0) + err = net_xmit_errno(err); + + return err ?: size; + +out_skb: + kfree_skb(skb); +out_dev: + dev_put(dev); +out: + return err; +} + +static int raw_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, + size_t len, int noblock, int flags, int *addr_len) +{ + size_t copied = 0; + int err = -EOPNOTSUPP; + struct sk_buff *skb; + + skb = skb_recv_datagram(sk, flags, noblock, &err); + if (!skb) + goto out; + + copied = skb->len; + if (len < copied) { + msg->msg_flags |= MSG_TRUNC; + copied = len; + } + + err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); + if (err) + goto done; + + sock_recv_timestamp(msg, sk, skb); + + if (flags & MSG_TRUNC) + copied = skb->len; +done: + skb_free_datagram(sk, skb); +out: + if (err) + return err; + return copied; +} + +static int raw_rcv_skb(struct sock *sk, struct sk_buff *skb) +{ + if (sock_queue_rcv_skb(sk, skb) < 0) { + atomic_inc(&sk->sk_drops); + kfree_skb(skb); + return NET_RX_DROP; + } + + return NET_RX_SUCCESS; +} + + +void ieee802154_raw_deliver(struct net_device *dev, struct sk_buff *skb) +{ + struct sock *sk; + struct hlist_node *node; + + read_lock(&raw_lock); + sk_for_each(sk, node, &raw_head) { + bh_lock_sock(sk); + if (!sk->sk_bound_dev_if || + sk->sk_bound_dev_if == dev->ifindex) { + + struct sk_buff *clone; + + clone = skb_clone(skb, GFP_ATOMIC); + if (clone) + raw_rcv_skb(sk, clone); + } + bh_unlock_sock(sk); + } + read_unlock(&raw_lock); +} + +struct proto ieee802154_raw_prot = { + .name = "IEEE-802.15.4-RAW", + .owner = THIS_MODULE, + .obj_size = sizeof(struct sock), + .close = raw_close, + .bind = raw_bind, + .sendmsg = raw_sendmsg, + .recvmsg = raw_recvmsg, + .hash = raw_hash, + .unhash = raw_unhash, + .connect = raw_connect, + .disconnect = raw_disconnect, +}; + diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig index 5b919f7b45db..70491d9035eb 100644 --- a/net/ipv4/Kconfig +++ b/net/ipv4/Kconfig @@ -273,29 +273,20 @@ config IP_PIMSM_V2 you want to play with it. config ARPD - bool "IP: ARP daemon support (EXPERIMENTAL)" - depends on EXPERIMENTAL + bool "IP: ARP daemon support" ---help--- - Normally, the kernel maintains an internal cache which maps IP - addresses to hardware addresses on the local network, so that - Ethernet/Token Ring/ etc. frames are sent to the proper address on - the physical networking layer. For small networks having a few - hundred directly connected hosts or less, keeping this address - resolution (ARP) cache inside the kernel works well. However, - maintaining an internal ARP cache does not work well for very large - switched networks, and will use a lot of kernel memory if TCP/IP - connections are made to many machines on the network. + The kernel maintains an internal cache which maps IP addresses to + hardware addresses on the local network, so that Ethernet/Token Ring/ + etc. frames are sent to the proper address on the physical networking + layer. Normally, kernel uses the ARP protocol to resolve these + mappings. - If you say Y here, the kernel's internal ARP cache will never grow - to more than 256 entries (the oldest entries are expired in a LIFO - manner) and communication will be attempted with the user space ARP - daemon arpd. Arpd then answers the address resolution request either - from its own cache or by asking the net. + Saying Y here adds support to have an user space daemon to do this + resolution instead. This is useful for implementing an alternate + address resolution protocol (e.g. NHRP on mGRE tunnels) and also for + testing purposes. - This code is experimental and also obsolete. If you want to use it, - you need to find a version of the daemon arpd on the net somewhere, - and you should also say Y to "Kernel/User network link driver", - below. If unsure, say N. + If unsure, say N. config SYN_COOKIES bool "IP: TCP syncookie support (disabled per default)" diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 7f03373b8c07..566ea6c4321d 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -116,7 +116,6 @@ #include #endif -extern void ip_mc_drop_socket(struct sock *sk); /* The inetsw table contains everything that inet_create needs to * build a new socket. @@ -375,6 +374,7 @@ lookup_protocol: inet->uc_ttl = -1; inet->mc_loop = 1; inet->mc_ttl = 1; + inet->mc_all = 1; inet->mc_index = 0; inet->mc_list = NULL; @@ -1003,8 +1003,6 @@ void inet_register_protosw(struct inet_protosw *p) out: spin_unlock_bh(&inetsw_lock); - synchronize_net(); - return; out_permanent: @@ -1248,13 +1246,20 @@ static struct sk_buff **inet_gro_receive(struct sk_buff **head, struct sk_buff **pp = NULL; struct sk_buff *p; struct iphdr *iph; + unsigned int hlen; + unsigned int off; + unsigned int id; int flush = 1; int proto; - int id; - iph = skb_gro_header(skb, sizeof(*iph)); - if (unlikely(!iph)) - goto out; + off = skb_gro_offset(skb); + hlen = off + sizeof(*iph); + iph = skb_gro_header_fast(skb, off); + if (skb_gro_header_hard(skb, hlen)) { + iph = skb_gro_header_slow(skb, hlen, off); + if (unlikely(!iph)) + goto out; + } proto = iph->protocol & (MAX_INET_PROTOS - 1); @@ -1269,9 +1274,9 @@ static struct sk_buff **inet_gro_receive(struct sk_buff **head, if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl))) goto out_unlock; - flush = ntohs(iph->tot_len) != skb_gro_len(skb) || - iph->frag_off != htons(IP_DF); - id = ntohs(iph->id); + id = ntohl(*(u32 *)&iph->id); + flush = (u16)((ntohl(*(u32 *)iph) ^ skb_gro_len(skb)) | (id ^ IP_DF)); + id >>= 16; for (p = *head; p; p = p->next) { struct iphdr *iph2; diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index f11931c18381..8a3881e28aca 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -468,13 +468,13 @@ int arp_find(unsigned char *haddr, struct sk_buff *skb) __be32 paddr; struct neighbour *n; - if (!skb->dst) { + if (!skb_dst(skb)) { printk(KERN_DEBUG "arp_find is called with dst==NULL\n"); kfree_skb(skb); return 1; } - paddr = skb->rtable->rt_gateway; + paddr = skb_rtable(skb)->rt_gateway; if (arp_set_predefined(inet_addr_type(dev_net(dev), paddr), haddr, paddr, dev)) return 0; @@ -817,7 +817,7 @@ static int arp_process(struct sk_buff *skb) if (arp->ar_op == htons(ARPOP_REQUEST) && ip_route_input(skb, tip, sip, 0, dev) == 0) { - rt = skb->rtable; + rt = skb_rtable(skb); addr_type = rt->rt_type; if (addr_type == RTN_LOCAL) { diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 126bb911880f..3863c3a4223f 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -1347,7 +1347,8 @@ static int devinet_sysctl_forward(ctl_table *ctl, int write, struct net *net = ctl->extra2; if (valp != &IPV4_DEVCONF_DFLT(net, FORWARDING)) { - rtnl_lock(); + if (!rtnl_trylock()) + return restart_syscall(); if (valp == &IPV4_DEVCONF_ALL(net, FORWARDING)) { inet_forward_change(net); } else if (*valp) { diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index cafcc49d0993..e2f950592566 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -40,7 +40,6 @@ #include #include #include -#include #include #include #include diff --git a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c index ded8c44fb848..ecd39454235c 100644 --- a/net/ipv4/fib_hash.c +++ b/net/ipv4/fib_hash.c @@ -263,7 +263,6 @@ fn_hash_lookup(struct fib_table *tb, const struct flowi *flp, struct fib_result err = fib_semantic_match(&f->fn_alias, flp, res, - f->fn_key, fz->fz_mask, fz->fz_order); if (err <= 0) goto out; diff --git a/net/ipv4/fib_lookup.h b/net/ipv4/fib_lookup.h index 2c1623d2768b..637b133973bd 100644 --- a/net/ipv4/fib_lookup.h +++ b/net/ipv4/fib_lookup.h @@ -22,8 +22,7 @@ struct fib_alias { /* Exported by fib_semantics.c */ extern int fib_semantic_match(struct list_head *head, const struct flowi *flp, - struct fib_result *res, __be32 zone, __be32 mask, - int prefixlen); + struct fib_result *res, int prefixlen); extern void fib_release_info(struct fib_info *); extern struct fib_info *fib_create_info(struct fib_config *cfg); extern int fib_nh_match(struct fib_config *cfg, struct fib_info *fi); diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c index 6080d7120821..92d9d97ec5e3 100644 --- a/net/ipv4/fib_rules.c +++ b/net/ipv4/fib_rules.c @@ -134,7 +134,7 @@ static const struct nla_policy fib4_rule_policy[FRA_MAX+1] = { }; static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb, - struct nlmsghdr *nlh, struct fib_rule_hdr *frh, + struct fib_rule_hdr *frh, struct nlattr **tb) { struct net *net = sock_net(skb->sk); @@ -209,7 +209,7 @@ static int fib4_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh, } static int fib4_rule_fill(struct fib_rule *rule, struct sk_buff *skb, - struct nlmsghdr *nlh, struct fib_rule_hdr *frh) + struct fib_rule_hdr *frh) { struct fib4_rule *rule4 = (struct fib4_rule *) rule; diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index f831df500907..9b096d6ff3f2 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -866,8 +866,7 @@ failure: /* Note! fib_semantic_match intentionally uses RCU list functions. */ int fib_semantic_match(struct list_head *head, const struct flowi *flp, - struct fib_result *res, __be32 zone, __be32 mask, - int prefixlen) + struct fib_result *res, int prefixlen) { struct fib_alias *fa; int nh_sel = 0; diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 33c7c85dfe40..012cf5a68581 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -123,6 +123,7 @@ struct tnode { union { struct rcu_head rcu; struct work_struct work; + struct tnode *tnode_free; }; struct node *child[0]; }; @@ -161,6 +162,8 @@ static void tnode_put_child_reorg(struct tnode *tn, int i, struct node *n, static struct node *resize(struct trie *t, struct tnode *tn); static struct tnode *inflate(struct trie *t, struct tnode *tn); static struct tnode *halve(struct trie *t, struct tnode *tn); +/* tnodes to free after resize(); protected by RTNL */ +static struct tnode *tnode_free_head; static struct kmem_cache *fn_alias_kmem __read_mostly; static struct kmem_cache *trie_leaf_kmem __read_mostly; @@ -385,6 +388,24 @@ static inline void tnode_free(struct tnode *tn) call_rcu(&tn->rcu, __tnode_free_rcu); } +static void tnode_free_safe(struct tnode *tn) +{ + BUG_ON(IS_LEAF(tn)); + tn->tnode_free = tnode_free_head; + tnode_free_head = tn; +} + +static void tnode_free_flush(void) +{ + struct tnode *tn; + + while ((tn = tnode_free_head)) { + tnode_free_head = tn->tnode_free; + tn->tnode_free = NULL; + tnode_free(tn); + } +} + static struct leaf *leaf_new(void) { struct leaf *l = kmem_cache_alloc(trie_leaf_kmem, GFP_KERNEL); @@ -495,7 +516,7 @@ static struct node *resize(struct trie *t, struct tnode *tn) /* No children */ if (tn->empty_children == tnode_child_length(tn)) { - tnode_free(tn); + tnode_free_safe(tn); return NULL; } /* One child */ @@ -509,7 +530,7 @@ static struct node *resize(struct trie *t, struct tnode *tn) /* compress one level */ node_set_parent(n, NULL); - tnode_free(tn); + tnode_free_safe(tn); return n; } /* @@ -670,7 +691,7 @@ static struct node *resize(struct trie *t, struct tnode *tn) /* compress one level */ node_set_parent(n, NULL); - tnode_free(tn); + tnode_free_safe(tn); return n; } @@ -756,7 +777,7 @@ static struct tnode *inflate(struct trie *t, struct tnode *tn) put_child(t, tn, 2*i, inode->child[0]); put_child(t, tn, 2*i+1, inode->child[1]); - tnode_free(inode); + tnode_free_safe(inode); continue; } @@ -801,9 +822,9 @@ static struct tnode *inflate(struct trie *t, struct tnode *tn) put_child(t, tn, 2*i, resize(t, left)); put_child(t, tn, 2*i+1, resize(t, right)); - tnode_free(inode); + tnode_free_safe(inode); } - tnode_free(oldtnode); + tnode_free_safe(oldtnode); return tn; nomem: { @@ -885,7 +906,7 @@ static struct tnode *halve(struct trie *t, struct tnode *tn) put_child(t, newBinNode, 1, right); put_child(t, tn, i/2, resize(t, newBinNode)); } - tnode_free(oldtnode); + tnode_free_safe(oldtnode); return tn; nomem: { @@ -983,13 +1004,12 @@ fib_find_node(struct trie *t, u32 key) return NULL; } -static struct node *trie_rebalance(struct trie *t, struct tnode *tn) +static void trie_rebalance(struct trie *t, struct tnode *tn) { int wasfull; t_key cindex, key; struct tnode *tp; - preempt_disable(); key = tn->key; while (tn != NULL && (tp = node_parent((struct node *)tn)) != NULL) { @@ -1001,6 +1021,7 @@ static struct node *trie_rebalance(struct trie *t, struct tnode *tn) (struct node *)tn, wasfull); tp = node_parent((struct node *) tn); + tnode_free_flush(); if (!tp) break; tn = tp; @@ -1010,8 +1031,10 @@ static struct node *trie_rebalance(struct trie *t, struct tnode *tn) if (IS_TNODE(tn)) tn = (struct tnode *)resize(t, (struct tnode *)tn); - preempt_enable(); - return (struct node *)tn; + rcu_assign_pointer(t->trie, (struct node *)tn); + tnode_free_flush(); + + return; } /* only used from updater-side */ @@ -1159,7 +1182,7 @@ static struct list_head *fib_insert_node(struct trie *t, u32 key, int plen) /* Rebalance the trie */ - rcu_assign_pointer(t->trie, trie_rebalance(t, tp)); + trie_rebalance(t, tp); done: return fa_head; } @@ -1351,8 +1374,7 @@ static int check_leaf(struct trie *t, struct leaf *l, if (l->key != (key & ntohl(mask))) continue; - err = fib_semantic_match(&li->falh, flp, res, - htonl(l->key), mask, plen); + err = fib_semantic_match(&li->falh, flp, res, plen); #ifdef CONFIG_IP_FIB_TRIE_STATS if (err <= 0) @@ -1579,7 +1601,7 @@ static void trie_leaf_remove(struct trie *t, struct leaf *l) if (tp) { t_key cindex = tkey_extract_bits(l->key, tp->pos, tp->bits); put_child(t, (struct tnode *)tp, cindex, NULL); - rcu_assign_pointer(t->trie, trie_rebalance(t, tp)); + trie_rebalance(t, tp); } else rcu_assign_pointer(t->trie, NULL); diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 3f50807237e0..97c410e84388 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -356,7 +356,7 @@ static void icmp_push_reply(struct icmp_bxm *icmp_param, static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb) { struct ipcm_cookie ipc; - struct rtable *rt = skb->rtable; + struct rtable *rt = skb_rtable(skb); struct net *net = dev_net(rt->u.dst.dev); struct sock *sk; struct inet_sock *inet; @@ -416,7 +416,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) struct iphdr *iph; int room; struct icmp_bxm icmp_param; - struct rtable *rt = skb_in->rtable; + struct rtable *rt = skb_rtable(skb_in); struct ipcm_cookie ipc; __be32 saddr; u8 tos; @@ -591,13 +591,13 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) goto relookup_failed; /* Ugh! */ - odst = skb_in->dst; + odst = skb_dst(skb_in); err = ip_route_input(skb_in, fl.fl4_dst, fl.fl4_src, RT_TOS(tos), rt2->u.dst.dev); dst_release(&rt2->u.dst); - rt2 = skb_in->rtable; - skb_in->dst = odst; + rt2 = skb_rtable(skb_in); + skb_dst_set(skb_in, odst); } if (err) @@ -659,7 +659,7 @@ static void icmp_unreach(struct sk_buff *skb) u32 info = 0; struct net *net; - net = dev_net(skb->dst->dev); + net = dev_net(skb_dst(skb)->dev); /* * Incomplete header ? @@ -822,7 +822,7 @@ static void icmp_echo(struct sk_buff *skb) { struct net *net; - net = dev_net(skb->dst->dev); + net = dev_net(skb_dst(skb)->dev); if (!net->ipv4.sysctl_icmp_echo_ignore_all) { struct icmp_bxm icmp_param; @@ -873,7 +873,7 @@ static void icmp_timestamp(struct sk_buff *skb) out: return; out_err: - ICMP_INC_STATS_BH(dev_net(skb->dst->dev), ICMP_MIB_INERRORS); + ICMP_INC_STATS_BH(dev_net(skb_dst(skb)->dev), ICMP_MIB_INERRORS); goto out; } @@ -926,7 +926,7 @@ static void icmp_address(struct sk_buff *skb) static void icmp_address_reply(struct sk_buff *skb) { - struct rtable *rt = skb->rtable; + struct rtable *rt = skb_rtable(skb); struct net_device *dev = skb->dev; struct in_device *in_dev; struct in_ifaddr *ifa; @@ -970,7 +970,7 @@ static void icmp_discard(struct sk_buff *skb) int icmp_rcv(struct sk_buff *skb) { struct icmphdr *icmph; - struct rtable *rt = skb->rtable; + struct rtable *rt = skb_rtable(skb); struct net *net = dev_net(rt->u.dst.dev); if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) { diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 9eb6219af615..01b4284ed694 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -311,7 +311,7 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, int size) return NULL; } - skb->dst = &rt->u.dst; + skb_dst_set(skb, &rt->u.dst); skb->dev = dev; skb_reserve(skb, LL_RESERVED_SPACE(dev)); @@ -659,7 +659,7 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc, return -1; } - skb->dst = &rt->u.dst; + skb_dst_set(skb, &rt->u.dst); skb_reserve(skb, LL_RESERVED_SPACE(dev)); @@ -948,7 +948,7 @@ int igmp_rcv(struct sk_buff *skb) case IGMPV2_HOST_MEMBERSHIP_REPORT: case IGMPV3_HOST_MEMBERSHIP_REPORT: /* Is it our report looped back? */ - if (skb->rtable->fl.iif == 0) + if (skb_rtable(skb)->fl.iif == 0) break; /* don't rely on MC router hearing unicast reports */ if (skb->pkt_type == PACKET_MULTICAST || @@ -2196,7 +2196,7 @@ int ip_mc_sf_allow(struct sock *sk, __be32 loc_addr, __be32 rmt_addr, int dif) break; } if (!pmc) - return 1; + return inet->mc_all; psl = pmc->sflist; if (!psl) return pmc->sfmode == MCAST_EXCLUDE; diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c index 588a7796e3e3..a706a47f4dbb 100644 --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c @@ -156,10 +156,10 @@ static int inet_csk_diag_fill(struct sock *sk, r->idiag_inode = sock_i_ino(sk); if (minfo) { - minfo->idiag_rmem = atomic_read(&sk->sk_rmem_alloc); + minfo->idiag_rmem = sk_rmem_alloc_get(sk); minfo->idiag_wmem = sk->sk_wmem_queued; minfo->idiag_fmem = sk->sk_forward_alloc; - minfo->idiag_tmem = atomic_read(&sk->sk_wmem_alloc); + minfo->idiag_tmem = sk_wmem_alloc_get(sk); } handler->idiag_get_info(sk, r, info); @@ -198,8 +198,6 @@ static int inet_twsk_diag_fill(struct inet_timewait_sock *tw, tmo = 0; r->idiag_family = tw->tw_family; - r->idiag_state = tw->tw_state; - r->idiag_timer = 0; r->idiag_retrans = 0; r->id.idiag_if = tw->tw_bound_dev_if; r->id.idiag_cookie[0] = (u32)(unsigned long)tw; diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c index 8554d0ea1719..61283f928825 100644 --- a/net/ipv4/inet_timewait_sock.c +++ b/net/ipv4/inet_timewait_sock.c @@ -9,6 +9,7 @@ */ #include +#include #include #include #include @@ -49,19 +50,22 @@ static void __inet_twsk_kill(struct inet_timewait_sock *tw, inet_twsk_put(tw); } +static noinline void inet_twsk_free(struct inet_timewait_sock *tw) +{ + struct module *owner = tw->tw_prot->owner; + twsk_destructor((struct sock *)tw); +#ifdef SOCK_REFCNT_DEBUG + pr_debug("%s timewait_sock %p released\n", tw->tw_prot->name, tw); +#endif + release_net(twsk_net(tw)); + kmem_cache_free(tw->tw_prot->twsk_prot->twsk_slab, tw); + module_put(owner); +} + void inet_twsk_put(struct inet_timewait_sock *tw) { - if (atomic_dec_and_test(&tw->tw_refcnt)) { - struct module *owner = tw->tw_prot->owner; - twsk_destructor((struct sock *)tw); -#ifdef SOCK_REFCNT_DEBUG - printk(KERN_DEBUG "%s timewait_sock %p released\n", - tw->tw_prot->name, tw); -#endif - release_net(twsk_net(tw)); - kmem_cache_free(tw->tw_prot->twsk_prot->twsk_slab, tw); - module_put(owner); - } + if (atomic_dec_and_test(&tw->tw_refcnt)) + inet_twsk_free(tw); } EXPORT_SYMBOL_GPL(inet_twsk_put); @@ -117,6 +121,8 @@ struct inet_timewait_sock *inet_twsk_alloc(const struct sock *sk, const int stat if (tw != NULL) { const struct inet_sock *inet = inet_sk(sk); + kmemcheck_annotate_bitfield(tw, flags); + /* Give us an identity. */ tw->tw_daddr = inet->daddr; tw->tw_rcv_saddr = inet->rcv_saddr; diff --git a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c index df3fe50bbf0d..a2991bc8e32e 100644 --- a/net/ipv4/ip_forward.c +++ b/net/ipv4/ip_forward.c @@ -42,7 +42,7 @@ static int ip_forward_finish(struct sk_buff *skb) { struct ip_options * opt = &(IPCB(skb)->opt); - IP_INC_STATS_BH(dev_net(skb->dst->dev), IPSTATS_MIB_OUTFORWDATAGRAMS); + IP_INC_STATS_BH(dev_net(skb_dst(skb)->dev), IPSTATS_MIB_OUTFORWDATAGRAMS); if (unlikely(opt->optlen)) ip_forward_options(skb); @@ -81,7 +81,7 @@ int ip_forward(struct sk_buff *skb) if (!xfrm4_route_forward(skb)) goto drop; - rt = skb->rtable; + rt = skb_rtable(skb); if (opt->is_strictroute && rt->rt_dst != rt->rt_gateway) goto sr_failed; @@ -123,7 +123,7 @@ sr_failed: too_many_hops: /* Tell the sender its packet died... */ - IP_INC_STATS_BH(dev_net(skb->dst->dev), IPSTATS_MIB_INHDRERRORS); + IP_INC_STATS_BH(dev_net(skb_dst(skb)->dev), IPSTATS_MIB_INHDRERRORS); icmp_send(skb, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL, 0); drop: kfree_skb(skb); diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 7985346653bd..575f9bd51ccd 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -507,7 +507,7 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev, /* If the first fragment is fragmented itself, we split * it to two chunks: the first with data and paged part * and the second, holding only fragments. */ - if (skb_shinfo(head)->frag_list) { + if (skb_has_frags(head)) { struct sk_buff *clone; int i, plen = 0; @@ -516,7 +516,7 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev, clone->next = head->next; head->next = clone; skb_shinfo(clone)->frag_list = skb_shinfo(head)->frag_list; - skb_shinfo(head)->frag_list = NULL; + skb_frag_list_init(head); for (i=0; inr_frags; i++) plen += skb_shinfo(head)->frags[i].size; clone->len = clone->data_len = head->data_len - plen; @@ -573,7 +573,7 @@ int ip_defrag(struct sk_buff *skb, u32 user) struct ipq *qp; struct net *net; - net = skb->dev ? dev_net(skb->dev) : dev_net(skb->dst->dev); + net = skb->dev ? dev_net(skb->dev) : dev_net(skb_dst(skb)->dev); IP_INC_STATS_BH(net, IPSTATS_MIB_REASMREQDS); /* Start by cleaning up the memory. */ diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index e62510d5ea5a..44e2a3d2359a 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -602,7 +602,7 @@ static int ipgre_rcv(struct sk_buff *skb) #ifdef CONFIG_NET_IPGRE_BROADCAST if (ipv4_is_multicast(iph->daddr)) { /* Looped back packet, drop it! */ - if (skb->rtable->fl.iif == 0) + if (skb_rtable(skb)->fl.iif == 0) goto drop; stats->multicast++; skb->pkt_type = PACKET_BROADCAST; @@ -643,8 +643,7 @@ static int ipgre_rcv(struct sk_buff *skb) stats->rx_packets++; stats->rx_bytes += len; skb->dev = tunnel->dev; - dst_release(skb->dst); - skb->dst = NULL; + skb_dst_drop(skb); nf_reset(skb); skb_reset_network_header(skb); @@ -698,13 +697,13 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) if ((dst = tiph->daddr) == 0) { /* NBMA tunnel */ - if (skb->dst == NULL) { + if (skb_dst(skb) == NULL) { stats->tx_fifo_errors++; goto tx_error; } if (skb->protocol == htons(ETH_P_IP)) { - rt = skb->rtable; + rt = skb_rtable(skb); if ((dst = rt->rt_gateway) == 0) goto tx_error_icmp; } @@ -712,7 +711,7 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) else if (skb->protocol == htons(ETH_P_IPV6)) { struct in6_addr *addr6; int addr_type; - struct neighbour *neigh = skb->dst->neighbour; + struct neighbour *neigh = skb_dst(skb)->neighbour; if (neigh == NULL) goto tx_error; @@ -766,10 +765,10 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) if (df) mtu = dst_mtu(&rt->u.dst) - dev->hard_header_len - tunnel->hlen; else - mtu = skb->dst ? dst_mtu(skb->dst) : dev->mtu; + mtu = skb_dst(skb) ? dst_mtu(skb_dst(skb)) : dev->mtu; - if (skb->dst) - skb->dst->ops->update_pmtu(skb->dst, mtu); + if (skb_dst(skb)) + skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu); if (skb->protocol == htons(ETH_P_IP)) { df |= (old_iph->frag_off&htons(IP_DF)); @@ -783,14 +782,14 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) } #ifdef CONFIG_IPV6 else if (skb->protocol == htons(ETH_P_IPV6)) { - struct rt6_info *rt6 = (struct rt6_info *)skb->dst; + struct rt6_info *rt6 = (struct rt6_info *)skb_dst(skb); - if (rt6 && mtu < dst_mtu(skb->dst) && mtu >= IPV6_MIN_MTU) { + if (rt6 && mtu < dst_mtu(skb_dst(skb)) && mtu >= IPV6_MIN_MTU) { if ((tunnel->parms.iph.daddr && !ipv4_is_multicast(tunnel->parms.iph.daddr)) || rt6->rt6i_dst.plen == 128) { rt6->rt6i_flags |= RTF_MODIFIED; - skb->dst->metrics[RTAX_MTU-1] = mtu; + skb_dst(skb)->metrics[RTAX_MTU-1] = mtu; } } @@ -837,8 +836,8 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED | IPSKB_REROUTED); - dst_release(skb->dst); - skb->dst = &rt->u.dst; + skb_dst_drop(skb); + skb_dst_set(skb, &rt->u.dst); /* * Push down and install the IPIP header. @@ -1238,6 +1237,7 @@ static void ipgre_tunnel_setup(struct net_device *dev) dev->iflink = 0; dev->addr_len = 4; dev->features |= NETIF_F_NETNS_LOCAL; + dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; } static int ipgre_tunnel_init(struct net_device *dev) diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index 1a58a6fa1dc0..490ce20faf38 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -329,7 +329,7 @@ static int ip_rcv_finish(struct sk_buff *skb) * Initialise the virtual path cache for the packet. It describes * how the packet travels inside Linux networking. */ - if (skb->dst == NULL) { + if (skb_dst(skb) == NULL) { int err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, skb->dev); if (unlikely(err)) { @@ -344,9 +344,9 @@ static int ip_rcv_finish(struct sk_buff *skb) } #ifdef CONFIG_NET_CLS_ROUTE - if (unlikely(skb->dst->tclassid)) { + if (unlikely(skb_dst(skb)->tclassid)) { struct ip_rt_acct *st = per_cpu_ptr(ip_rt_acct, smp_processor_id()); - u32 idx = skb->dst->tclassid; + u32 idx = skb_dst(skb)->tclassid; st[idx&0xFF].o_packets++; st[idx&0xFF].o_bytes += skb->len; st[(idx>>16)&0xFF].i_packets++; @@ -357,11 +357,13 @@ static int ip_rcv_finish(struct sk_buff *skb) if (iph->ihl > 5 && ip_rcv_options(skb)) goto drop; - rt = skb->rtable; - if (rt->rt_type == RTN_MULTICAST) - IP_INC_STATS_BH(dev_net(rt->u.dst.dev), IPSTATS_MIB_INMCASTPKTS); - else if (rt->rt_type == RTN_BROADCAST) - IP_INC_STATS_BH(dev_net(rt->u.dst.dev), IPSTATS_MIB_INBCASTPKTS); + rt = skb_rtable(skb); + if (rt->rt_type == RTN_MULTICAST) { + IP_UPD_PO_STATS_BH(dev_net(rt->u.dst.dev), IPSTATS_MIB_INMCAST, + skb->len); + } else if (rt->rt_type == RTN_BROADCAST) + IP_UPD_PO_STATS_BH(dev_net(rt->u.dst.dev), IPSTATS_MIB_INBCAST, + skb->len); return dst_input(skb); @@ -384,7 +386,8 @@ int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, if (skb->pkt_type == PACKET_OTHERHOST) goto drop; - IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INRECEIVES); + + IP_UPD_PO_STATS_BH(dev_net(dev), IPSTATS_MIB_IN, skb->len); if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) { IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INDISCARDS); diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index 2c88da6e7862..94bf105ef3c9 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c @@ -102,7 +102,7 @@ int ip_options_echo(struct ip_options * dopt, struct sk_buff * skb) sptr = skb_network_header(skb); dptr = dopt->__data; - daddr = skb->rtable->rt_spec_dst; + daddr = skb_rtable(skb)->rt_spec_dst; if (sopt->rr) { optlen = sptr[sopt->rr+1]; @@ -143,7 +143,7 @@ int ip_options_echo(struct ip_options * dopt, struct sk_buff * skb) __be32 addr; memcpy(&addr, sptr+soffset-1, 4); - if (inet_addr_type(dev_net(skb->dst->dev), addr) != RTN_LOCAL) { + if (inet_addr_type(dev_net(skb_dst(skb)->dev), addr) != RTN_LOCAL) { dopt->ts_needtime = 1; soffset += 8; } @@ -257,7 +257,7 @@ int ip_options_compile(struct net *net, struct rtable *rt = NULL; if (skb != NULL) { - rt = skb->rtable; + rt = skb_rtable(skb); optptr = (unsigned char *)&(ip_hdr(skb)[1]); } else optptr = opt->__data; @@ -550,7 +550,7 @@ void ip_forward_options(struct sk_buff *skb) { struct ip_options * opt = &(IPCB(skb)->opt); unsigned char * optptr; - struct rtable *rt = skb->rtable; + struct rtable *rt = skb_rtable(skb); unsigned char *raw = skb_network_header(skb); if (opt->rr_needaddr) { @@ -598,7 +598,7 @@ int ip_options_rcv_srr(struct sk_buff *skb) __be32 nexthop; struct iphdr *iph = ip_hdr(skb); unsigned char *optptr = skb_network_header(skb) + opt->srr; - struct rtable *rt = skb->rtable; + struct rtable *rt = skb_rtable(skb); struct rtable *rt2; int err; @@ -623,13 +623,13 @@ int ip_options_rcv_srr(struct sk_buff *skb) } memcpy(&nexthop, &optptr[srrptr-1], 4); - rt = skb->rtable; - skb->rtable = NULL; + rt = skb_rtable(skb); + skb_dst_set(skb, NULL); err = ip_route_input(skb, nexthop, iph->saddr, iph->tos, skb->dev); - rt2 = skb->rtable; + rt2 = skb_rtable(skb); if (err || (rt2->rt_type != RTN_UNICAST && rt2->rt_type != RTN_LOCAL)) { ip_rt_put(rt2); - skb->rtable = rt; + skb_dst_set(skb, &rt->u.dst); return -EINVAL; } ip_rt_put(rt); diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 3e7e910c7c0f..247026282669 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -95,7 +95,7 @@ int __ip_local_out(struct sk_buff *skb) iph->tot_len = htons(skb->len); ip_send_check(iph); - return nf_hook(PF_INET, NF_INET_LOCAL_OUT, skb, NULL, skb->dst->dev, + return nf_hook(PF_INET, NF_INET_LOCAL_OUT, skb, NULL, skb_dst(skb)->dev, dst_output); } @@ -118,7 +118,7 @@ static int ip_dev_loopback_xmit(struct sk_buff *newskb) __skb_pull(newskb, skb_network_offset(newskb)); newskb->pkt_type = PACKET_LOOPBACK; newskb->ip_summed = CHECKSUM_UNNECESSARY; - WARN_ON(!newskb->dst); + WARN_ON(!skb_dst(newskb)); netif_rx(newskb); return 0; } @@ -140,7 +140,7 @@ int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk, __be32 saddr, __be32 daddr, struct ip_options *opt) { struct inet_sock *inet = inet_sk(sk); - struct rtable *rt = skb->rtable; + struct rtable *rt = skb_rtable(skb); struct iphdr *iph; /* Build the IP header. */ @@ -176,15 +176,15 @@ EXPORT_SYMBOL_GPL(ip_build_and_send_pkt); static inline int ip_finish_output2(struct sk_buff *skb) { - struct dst_entry *dst = skb->dst; + struct dst_entry *dst = skb_dst(skb); struct rtable *rt = (struct rtable *)dst; struct net_device *dev = dst->dev; unsigned int hh_len = LL_RESERVED_SPACE(dev); - if (rt->rt_type == RTN_MULTICAST) - IP_INC_STATS(dev_net(dev), IPSTATS_MIB_OUTMCASTPKTS); - else if (rt->rt_type == RTN_BROADCAST) - IP_INC_STATS(dev_net(dev), IPSTATS_MIB_OUTBCASTPKTS); + if (rt->rt_type == RTN_MULTICAST) { + IP_UPD_PO_STATS(dev_net(dev), IPSTATS_MIB_OUTMCAST, skb->len); + } else if (rt->rt_type == RTN_BROADCAST) + IP_UPD_PO_STATS(dev_net(dev), IPSTATS_MIB_OUTBCAST, skb->len); /* Be paranoid, rather than too clever. */ if (unlikely(skb_headroom(skb) < hh_len && dev->header_ops)) { @@ -217,14 +217,14 @@ static inline int ip_skb_dst_mtu(struct sk_buff *skb) struct inet_sock *inet = skb->sk ? inet_sk(skb->sk) : NULL; return (inet && inet->pmtudisc == IP_PMTUDISC_PROBE) ? - skb->dst->dev->mtu : dst_mtu(skb->dst); + skb_dst(skb)->dev->mtu : dst_mtu(skb_dst(skb)); } static int ip_finish_output(struct sk_buff *skb) { #if defined(CONFIG_NETFILTER) && defined(CONFIG_XFRM) /* Policy lookup after SNAT yielded a new policy */ - if (skb->dst->xfrm != NULL) { + if (skb_dst(skb)->xfrm != NULL) { IPCB(skb)->flags |= IPSKB_REROUTED; return dst_output(skb); } @@ -238,13 +238,13 @@ static int ip_finish_output(struct sk_buff *skb) int ip_mc_output(struct sk_buff *skb) { struct sock *sk = skb->sk; - struct rtable *rt = skb->rtable; + struct rtable *rt = skb_rtable(skb); struct net_device *dev = rt->u.dst.dev; /* * If the indicated interface is up and running, send the packet. */ - IP_INC_STATS(dev_net(dev), IPSTATS_MIB_OUTREQUESTS); + IP_UPD_PO_STATS(dev_net(dev), IPSTATS_MIB_OUT, skb->len); skb->dev = dev; skb->protocol = htons(ETH_P_IP); @@ -296,9 +296,9 @@ int ip_mc_output(struct sk_buff *skb) int ip_output(struct sk_buff *skb) { - struct net_device *dev = skb->dst->dev; + struct net_device *dev = skb_dst(skb)->dev; - IP_INC_STATS(dev_net(dev), IPSTATS_MIB_OUTREQUESTS); + IP_UPD_PO_STATS(dev_net(dev), IPSTATS_MIB_OUT, skb->len); skb->dev = dev; skb->protocol = htons(ETH_P_IP); @@ -319,7 +319,7 @@ int ip_queue_xmit(struct sk_buff *skb, int ipfragok) /* Skip all of this if the packet is already routed, * f.e. by something like SCTP. */ - rt = skb->rtable; + rt = skb_rtable(skb); if (rt != NULL) goto packet_routed; @@ -355,7 +355,7 @@ int ip_queue_xmit(struct sk_buff *skb, int ipfragok) } sk_setup_caps(sk, &rt->u.dst); } - skb->dst = dst_clone(&rt->u.dst); + skb_dst_set(skb, dst_clone(&rt->u.dst)); packet_routed: if (opt && opt->is_strictroute && rt->rt_dst != rt->rt_gateway) @@ -401,8 +401,8 @@ static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from) to->pkt_type = from->pkt_type; to->priority = from->priority; to->protocol = from->protocol; - dst_release(to->dst); - to->dst = dst_clone(from->dst); + skb_dst_drop(to); + skb_dst_set(to, dst_clone(skb_dst(from))); to->dev = from->dev; to->mark = from->mark; @@ -440,7 +440,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) unsigned int mtu, hlen, left, len, ll_rs, pad; int offset; __be16 not_last_frag; - struct rtable *rt = skb->rtable; + struct rtable *rt = skb_rtable(skb); int err = 0; dev = rt->u.dst.dev; @@ -474,7 +474,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) * LATER: this step can be merged to real generation of fragments, * we can switch to copy when see the first bad fragment. */ - if (skb_shinfo(skb)->frag_list) { + if (skb_has_frags(skb)) { struct sk_buff *frag; int first_len = skb_pagelen(skb); int truesizes = 0; @@ -485,7 +485,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) skb_cloned(skb)) goto slow_path; - for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next) { + skb_walk_frags(skb, frag) { /* Correct geometry. */ if (frag->len > mtu || ((frag->len & 7) && frag->next) || @@ -498,7 +498,6 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) BUG_ON(frag->sk); if (skb->sk) { - sock_hold(skb->sk); frag->sk = skb->sk; frag->destructor = sock_wfree; truesizes += frag->truesize; @@ -510,7 +509,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) err = 0; offset = 0; frag = skb_shinfo(skb)->frag_list; - skb_shinfo(skb)->frag_list = NULL; + skb_frag_list_init(skb); skb->data_len = first_len - skb_headlen(skb); skb->truesize -= truesizes; skb->len = first_len; @@ -1294,7 +1293,7 @@ int ip_push_pending_frames(struct sock *sk) * on dst refcount */ inet->cork.dst = NULL; - skb->dst = &rt->u.dst; + skb_dst_set(skb, &rt->u.dst); if (iph->protocol == IPPROTO_ICMP) icmp_out_count(net, ((struct icmphdr *) @@ -1362,7 +1361,7 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar } replyopts; struct ipcm_cookie ipc; __be32 daddr; - struct rtable *rt = skb->rtable; + struct rtable *rt = skb_rtable(skb); if (ip_options_echo(&replyopts.opt, skb)) return; diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 43c05854d752..fc7993e9061f 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -57,7 +57,7 @@ static void ip_cmsg_recv_pktinfo(struct msghdr *msg, struct sk_buff *skb) { struct in_pktinfo info; - struct rtable *rt = skb->rtable; + struct rtable *rt = skb_rtable(skb); info.ipi_addr.s_addr = ip_hdr(skb)->daddr; if (rt) { @@ -157,38 +157,39 @@ void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb) /* Ordered by supposed usage frequency */ if (flags & 1) ip_cmsg_recv_pktinfo(msg, skb); - if ((flags>>=1) == 0) + if ((flags >>= 1) == 0) return; if (flags & 1) ip_cmsg_recv_ttl(msg, skb); - if ((flags>>=1) == 0) + if ((flags >>= 1) == 0) return; if (flags & 1) ip_cmsg_recv_tos(msg, skb); - if ((flags>>=1) == 0) + if ((flags >>= 1) == 0) return; if (flags & 1) ip_cmsg_recv_opts(msg, skb); - if ((flags>>=1) == 0) + if ((flags >>= 1) == 0) return; if (flags & 1) ip_cmsg_recv_retopts(msg, skb); - if ((flags>>=1) == 0) + if ((flags >>= 1) == 0) return; if (flags & 1) ip_cmsg_recv_security(msg, skb); - if ((flags>>=1) == 0) + if ((flags >>= 1) == 0) return; if (flags & 1) ip_cmsg_recv_dstaddr(msg, skb); } +EXPORT_SYMBOL(ip_cmsg_recv); int ip_cmsg_send(struct net *net, struct msghdr *msg, struct ipcm_cookie *ipc) { @@ -203,7 +204,8 @@ int ip_cmsg_send(struct net *net, struct msghdr *msg, struct ipcm_cookie *ipc) switch (cmsg->cmsg_type) { case IP_RETOPTS: err = cmsg->cmsg_len - CMSG_ALIGN(sizeof(struct cmsghdr)); - err = ip_options_get(net, &ipc->opt, CMSG_DATA(cmsg), err < 40 ? err : 40); + err = ip_options_get(net, &ipc->opt, CMSG_DATA(cmsg), + err < 40 ? err : 40); if (err) return err; break; @@ -238,7 +240,8 @@ int ip_cmsg_send(struct net *net, struct msghdr *msg, struct ipcm_cookie *ipc) struct ip_ra_chain *ip_ra_chain; DEFINE_RWLOCK(ip_ra_lock); -int ip_ra_control(struct sock *sk, unsigned char on, void (*destructor)(struct sock *)) +int ip_ra_control(struct sock *sk, unsigned char on, + void (*destructor)(struct sock *)) { struct ip_ra_chain *ra, *new_ra, **rap; @@ -248,7 +251,7 @@ int ip_ra_control(struct sock *sk, unsigned char on, void (*destructor)(struct s new_ra = on ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL; write_lock_bh(&ip_ra_lock); - for (rap = &ip_ra_chain; (ra=*rap) != NULL; rap = &ra->next) { + for (rap = &ip_ra_chain; (ra = *rap) != NULL; rap = &ra->next) { if (ra->sk == sk) { if (on) { write_unlock_bh(&ip_ra_lock); @@ -416,7 +419,8 @@ int ip_recv_error(struct sock *sk, struct msghdr *msg, int len) /* Reset and regenerate socket error */ spin_lock_bh(&sk->sk_error_queue.lock); sk->sk_err = 0; - if ((skb2 = skb_peek(&sk->sk_error_queue)) != NULL) { + skb2 = skb_peek(&sk->sk_error_queue); + if (skb2 != NULL) { sk->sk_err = SKB_EXT_ERR(skb2)->ee.ee_errno; spin_unlock_bh(&sk->sk_error_queue.lock); sk->sk_error_report(sk); @@ -431,8 +435,8 @@ out: /* - * Socket option code for IP. This is the end of the line after any TCP,UDP etc options on - * an IP socket. + * Socket option code for IP. This is the end of the line after any + * TCP,UDP etc options on an IP socket. */ static int do_ip_setsockopt(struct sock *sk, int level, @@ -449,6 +453,7 @@ static int do_ip_setsockopt(struct sock *sk, int level, (1<= sizeof(int)) { @@ -474,7 +479,7 @@ static int do_ip_setsockopt(struct sock *sk, int level, switch (optname) { case IP_OPTIONS: { - struct ip_options * opt = NULL; + struct ip_options *opt = NULL; if (optlen > 40 || optlen < 0) goto e_inval; err = ip_options_get_from_user(sock_net(sk), &opt, @@ -556,9 +561,9 @@ static int do_ip_setsockopt(struct sock *sk, int level, } break; case IP_TTL: - if (optlen<1) + if (optlen < 1) goto e_inval; - if (val != -1 && (val < 1 || val>255)) + if (val != -1 && (val < 0 || val > 255)) goto e_inval; inet->uc_ttl = val; break; @@ -570,7 +575,7 @@ static int do_ip_setsockopt(struct sock *sk, int level, inet->hdrincl = val ? 1 : 0; break; case IP_MTU_DISCOVER: - if (val<0 || val>3) + if (val < 0 || val > 3) goto e_inval; inet->pmtudisc = val; break; @@ -582,7 +587,7 @@ static int do_ip_setsockopt(struct sock *sk, int level, case IP_MULTICAST_TTL: if (sk->sk_type == SOCK_STREAM) goto e_inval; - if (optlen<1) + if (optlen < 1) goto e_inval; if (val == -1) val = 1; @@ -591,7 +596,7 @@ static int do_ip_setsockopt(struct sock *sk, int level, inet->mc_ttl = val; break; case IP_MULTICAST_LOOP: - if (optlen<1) + if (optlen < 1) goto e_inval; inet->mc_loop = !!val; break; @@ -613,7 +618,8 @@ static int do_ip_setsockopt(struct sock *sk, int level, } else { memset(&mreq, 0, sizeof(mreq)); if (optlen >= sizeof(struct in_addr) && - copy_from_user(&mreq.imr_address, optval, sizeof(struct in_addr))) + copy_from_user(&mreq.imr_address, optval, + sizeof(struct in_addr))) break; } @@ -677,7 +683,6 @@ static int do_ip_setsockopt(struct sock *sk, int level, } case IP_MSFILTER: { - extern int sysctl_igmp_max_msf; struct ip_msfilter *msf; if (optlen < IP_MSFILTER_SIZE(0)) @@ -831,7 +836,6 @@ static int do_ip_setsockopt(struct sock *sk, int level, } case MCAST_MSFILTER: { - extern int sysctl_igmp_max_msf; struct sockaddr_in *psin; struct ip_msfilter *msf = NULL; struct group_filter *gsf = NULL; @@ -849,9 +853,9 @@ static int do_ip_setsockopt(struct sock *sk, int level, break; } err = -EFAULT; - if (copy_from_user(gsf, optval, optlen)) { + if (copy_from_user(gsf, optval, optlen)) goto mc_msf_out; - } + /* numsrc >= (4G-140)/128 overflow in 32 bits */ if (gsf->gf_numsrc >= 0x1ffffff || gsf->gf_numsrc > sysctl_igmp_max_msf) { @@ -879,7 +883,7 @@ static int do_ip_setsockopt(struct sock *sk, int level, msf->imsf_fmode = gsf->gf_fmode; msf->imsf_numsrc = gsf->gf_numsrc; err = -EADDRNOTAVAIL; - for (i=0; igf_numsrc; ++i) { + for (i = 0; i < gsf->gf_numsrc; ++i) { psin = (struct sockaddr_in *)&gsf->gf_slist[i]; if (psin->sin_family != AF_INET) @@ -890,17 +894,24 @@ static int do_ip_setsockopt(struct sock *sk, int level, gsf = NULL; err = ip_mc_msfilter(sk, msf, ifindex); - mc_msf_out: +mc_msf_out: kfree(msf); kfree(gsf); break; } + case IP_MULTICAST_ALL: + if (optlen < 1) + goto e_inval; + if (val != 0 && val != 1) + goto e_inval; + inet->mc_all = val; + break; case IP_ROUTER_ALERT: err = ip_ra_control(sk, val ? 1 : 0, NULL); break; case IP_FREEBIND: - if (optlen<1) + if (optlen < 1) goto e_inval; inet->freebind = !!val; break; @@ -957,6 +968,7 @@ int ip_setsockopt(struct sock *sk, int level, #endif return err; } +EXPORT_SYMBOL(ip_setsockopt); #ifdef CONFIG_COMPAT int compat_ip_setsockopt(struct sock *sk, int level, int optname, @@ -986,13 +998,12 @@ int compat_ip_setsockopt(struct sock *sk, int level, int optname, #endif return err; } - EXPORT_SYMBOL(compat_ip_setsockopt); #endif /* - * Get the options. Note for future reference. The GET of IP options gets the - * _received_ ones. The set sets the _sent_ ones. + * Get the options. Note for future reference. The GET of IP options gets + * the _received_ ones. The set sets the _sent_ ones. */ static int do_ip_getsockopt(struct sock *sk, int level, int optname, @@ -1143,10 +1154,14 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname, return -EFAULT; } err = ip_mc_gsfget(sk, &gsf, - (struct group_filter __user *)optval, optlen); + (struct group_filter __user *)optval, + optlen); release_sock(sk); return err; } + case IP_MULTICAST_ALL: + val = inet->mc_all; + break; case IP_PKTOPTIONS: { struct msghdr msg; @@ -1187,7 +1202,7 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname, } release_sock(sk); - if (len < sizeof(int) && len > 0 && val>=0 && val<=255) { + if (len < sizeof(int) && len > 0 && val >= 0 && val <= 255) { unsigned char ucval = (unsigned char)val; len = 1; if (put_user(len, optlen)) @@ -1230,6 +1245,7 @@ int ip_getsockopt(struct sock *sk, int level, #endif return err; } +EXPORT_SYMBOL(ip_getsockopt); #ifdef CONFIG_COMPAT int compat_ip_getsockopt(struct sock *sk, int level, int optname, @@ -1262,11 +1278,5 @@ int compat_ip_getsockopt(struct sock *sk, int level, int optname, #endif return err; } - EXPORT_SYMBOL(compat_ip_getsockopt); #endif - -EXPORT_SYMBOL(ip_cmsg_recv); - -EXPORT_SYMBOL(ip_getsockopt); -EXPORT_SYMBOL(ip_setsockopt); diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index 88bf051d0cbb..f8d04c256454 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -160,6 +160,9 @@ static char user_dev_name[IFNAMSIZ] __initdata = { 0, }; /* Protocols supported by available interfaces */ static int ic_proto_have_if __initdata = 0; +/* MTU for boot device */ +static int ic_dev_mtu __initdata = 0; + #ifdef IPCONFIG_DYNAMIC static DEFINE_SPINLOCK(ic_recv_lock); static volatile int ic_got_reply __initdata = 0; /* Proto(s) that replied */ @@ -286,7 +289,7 @@ set_sockaddr(struct sockaddr_in *sin, __be32 addr, __be16 port) sin->sin_port = port; } -static int __init ic_dev_ioctl(unsigned int cmd, struct ifreq *arg) +static int __init ic_devinet_ioctl(unsigned int cmd, struct ifreq *arg) { int res; @@ -297,6 +300,17 @@ static int __init ic_dev_ioctl(unsigned int cmd, struct ifreq *arg) return res; } +static int __init ic_dev_ioctl(unsigned int cmd, struct ifreq *arg) +{ + int res; + + mm_segment_t oldfs = get_fs(); + set_fs(get_ds()); + res = dev_ioctl(&init_net, cmd, (struct ifreq __user *) arg); + set_fs(oldfs); + return res; +} + static int __init ic_route_ioctl(unsigned int cmd, struct rtentry *arg) { int res; @@ -321,20 +335,31 @@ static int __init ic_setup_if(void) memset(&ir, 0, sizeof(ir)); strcpy(ir.ifr_ifrn.ifrn_name, ic_dev->name); set_sockaddr(sin, ic_myaddr, 0); - if ((err = ic_dev_ioctl(SIOCSIFADDR, &ir)) < 0) { + if ((err = ic_devinet_ioctl(SIOCSIFADDR, &ir)) < 0) { printk(KERN_ERR "IP-Config: Unable to set interface address (%d).\n", err); return -1; } set_sockaddr(sin, ic_netmask, 0); - if ((err = ic_dev_ioctl(SIOCSIFNETMASK, &ir)) < 0) { + if ((err = ic_devinet_ioctl(SIOCSIFNETMASK, &ir)) < 0) { printk(KERN_ERR "IP-Config: Unable to set interface netmask (%d).\n", err); return -1; } set_sockaddr(sin, ic_myaddr | ~ic_netmask, 0); - if ((err = ic_dev_ioctl(SIOCSIFBRDADDR, &ir)) < 0) { + if ((err = ic_devinet_ioctl(SIOCSIFBRDADDR, &ir)) < 0) { printk(KERN_ERR "IP-Config: Unable to set interface broadcast address (%d).\n", err); return -1; } + /* Handle the case where we need non-standard MTU on the boot link (a network + * using jumbo frames, for instance). If we can't set the mtu, don't error + * out, we'll try to muddle along. + */ + if (ic_dev_mtu != 0) { + strcpy(ir.ifr_name, ic_dev->name); + ir.ifr_mtu = ic_dev_mtu; + if ((err = ic_dev_ioctl(SIOCSIFMTU, &ir)) < 0) + printk(KERN_ERR "IP-Config: Unable to set interface mtu to %d (%d).\n", + ic_dev_mtu, err); + } return 0; } @@ -623,6 +648,7 @@ ic_dhcp_init_options(u8 *options) 12, /* Host name */ 15, /* Domain name */ 17, /* Boot path */ + 26, /* MTU */ 40, /* NIS domain name */ }; @@ -798,6 +824,7 @@ static void __init ic_do_bootp_ext(u8 *ext) { u8 servers; int i; + u16 mtu; #ifdef IPCONFIG_DEBUG u8 *c; @@ -837,6 +864,10 @@ static void __init ic_do_bootp_ext(u8 *ext) if (!root_server_path[0]) ic_bootp_string(root_server_path, ext+1, *ext, sizeof(root_server_path)); break; + case 26: /* Interface MTU */ + memcpy(&mtu, ext+1, sizeof(mtu)); + ic_dev_mtu = ntohs(mtu); + break; case 40: /* NIS Domain name (_not_ DNS) */ ic_bootp_string(utsname()->domainname, ext+1, *ext, __NEW_UTS_LEN); break; @@ -1403,6 +1434,8 @@ static int __init ip_auto_config(void) printk(",\n bootserver=%pI4", &ic_servaddr); printk(", rootserver=%pI4", &root_server_addr); printk(", rootpath=%s", root_server_path); + if (ic_dev_mtu) + printk(", mtu=%d", ic_dev_mtu); printk("\n"); #endif /* !SILENT */ diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 9054139795af..93e2b787da20 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -370,8 +370,7 @@ static int ipip_rcv(struct sk_buff *skb) tunnel->dev->stats.rx_packets++; tunnel->dev->stats.rx_bytes += skb->len; skb->dev = tunnel->dev; - dst_release(skb->dst); - skb->dst = NULL; + skb_dst_drop(skb); nf_reset(skb); ipip_ecn_decapsulate(iph, skb); netif_rx(skb); @@ -416,7 +415,7 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) if (!dst) { /* NBMA tunnel */ - if ((rt = skb->rtable) == NULL) { + if ((rt = skb_rtable(skb)) == NULL) { stats->tx_fifo_errors++; goto tx_error; } @@ -447,15 +446,15 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) if (tiph->frag_off) mtu = dst_mtu(&rt->u.dst) - sizeof(struct iphdr); else - mtu = skb->dst ? dst_mtu(skb->dst) : dev->mtu; + mtu = skb_dst(skb) ? dst_mtu(skb_dst(skb)) : dev->mtu; if (mtu < 68) { stats->collisions++; ip_rt_put(rt); goto tx_error; } - if (skb->dst) - skb->dst->ops->update_pmtu(skb->dst, mtu); + if (skb_dst(skb)) + skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu); df |= (old_iph->frag_off&htons(IP_DF)); @@ -502,8 +501,8 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED | IPSKB_REROUTED); - dst_release(skb->dst); - skb->dst = &rt->u.dst; + skb_dst_drop(skb); + skb_dst_set(skb, &rt->u.dst); /* * Push down and install the IPIP header. @@ -713,6 +712,7 @@ static void ipip_tunnel_setup(struct net_device *dev) dev->iflink = 0; dev->addr_len = 4; dev->features |= NETIF_F_NETNS_LOCAL; + dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; } static void ipip_tunnel_init(struct net_device *dev) diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 13e9dd3012b3..9a8da5ed92b7 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -226,9 +226,10 @@ static void reg_vif_setup(struct net_device *dev) dev->flags = IFF_NOARP; dev->netdev_ops = ®_vif_netdev_ops, dev->destructor = free_netdev; + dev->features |= NETIF_F_NETNS_LOCAL; } -static struct net_device *ipmr_reg_vif(void) +static struct net_device *ipmr_reg_vif(struct net *net) { struct net_device *dev; struct in_device *in_dev; @@ -238,6 +239,8 @@ static struct net_device *ipmr_reg_vif(void) if (dev == NULL) return NULL; + dev_net_set(dev, net); + if (register_netdevice(dev)) { free_netdev(dev); return NULL; @@ -448,7 +451,7 @@ static int vif_add(struct net *net, struct vifctl *vifc, int mrtsock) */ if (net->ipv4.mroute_reg_vif_num >= 0) return -EADDRINUSE; - dev = ipmr_reg_vif(); + dev = ipmr_reg_vif(net); if (!dev) return -ENOBUFS; err = dev_set_allmulti(dev, 1); @@ -651,7 +654,7 @@ static int ipmr_cache_report(struct net *net, ip_hdr(skb)->protocol = 0; /* Flag to the kernel this is a route add */ msg = (struct igmpmsg *)skb_network_header(skb); msg->im_vif = vifi; - skb->dst = dst_clone(pkt->dst); + skb_dst_set(skb, dst_clone(skb_dst(pkt))); /* * Add our header @@ -1031,16 +1034,6 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, int if (v != net->ipv4.mroute_do_pim) { net->ipv4.mroute_do_pim = v; net->ipv4.mroute_do_assert = v; -#ifdef CONFIG_IP_PIMSM_V2 - if (net->ipv4.mroute_do_pim) - ret = inet_add_protocol(&pim_protocol, - IPPROTO_PIM); - else - ret = inet_del_protocol(&pim_protocol, - IPPROTO_PIM); - if (ret < 0) - ret = -EAGAIN; -#endif } rtnl_unlock(); return ret; @@ -1201,7 +1194,7 @@ static void ip_encap(struct sk_buff *skb, __be32 saddr, __be32 daddr) iph->protocol = IPPROTO_IPIP; iph->ihl = 5; iph->tot_len = htons(skb->len); - ip_select_ident(iph, skb->dst, NULL); + ip_select_ident(iph, skb_dst(skb), NULL); ip_send_check(iph); memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); @@ -1212,7 +1205,7 @@ static inline int ipmr_forward_finish(struct sk_buff *skb) { struct ip_options * opt = &(IPCB(skb)->opt); - IP_INC_STATS_BH(dev_net(skb->dst->dev), IPSTATS_MIB_OUTFORWDATAGRAMS); + IP_INC_STATS_BH(dev_net(skb_dst(skb)->dev), IPSTATS_MIB_OUTFORWDATAGRAMS); if (unlikely(opt->optlen)) ip_forward_options(skb); @@ -1290,8 +1283,8 @@ static void ipmr_queue_xmit(struct sk_buff *skb, struct mfc_cache *c, int vifi) vif->pkt_out++; vif->bytes_out += skb->len; - dst_release(skb->dst); - skb->dst = &rt->u.dst; + skb_dst_drop(skb); + skb_dst_set(skb, &rt->u.dst); ip_decrease_ttl(ip_hdr(skb)); /* FIXME: forward and output firewalls used to be called here. @@ -1354,7 +1347,7 @@ static int ip_mr_forward(struct sk_buff *skb, struct mfc_cache *cache, int local if (net->ipv4.vif_table[vif].dev != skb->dev) { int true_vifi; - if (skb->rtable->fl.iif == 0) { + if (skb_rtable(skb)->fl.iif == 0) { /* It is our own packet, looped back. Very complicated situation... @@ -1430,7 +1423,7 @@ int ip_mr_input(struct sk_buff *skb) { struct mfc_cache *cache; struct net *net = dev_net(skb->dev); - int local = skb->rtable->rt_flags&RTCF_LOCAL; + int local = skb_rtable(skb)->rt_flags & RTCF_LOCAL; /* Packet is looped back after forward, it should not be forwarded second time, but still can be delivered locally. @@ -1543,8 +1536,7 @@ static int __pim_rcv(struct sk_buff *skb, unsigned int pimlen) skb->protocol = htons(ETH_P_IP); skb->ip_summed = 0; skb->pkt_type = PACKET_HOST; - dst_release(skb->dst); - skb->dst = NULL; + skb_dst_drop(skb); reg_dev->stats.rx_bytes += skb->len; reg_dev->stats.rx_packets++; nf_reset(skb); @@ -1646,7 +1638,7 @@ int ipmr_get_route(struct net *net, { int err; struct mfc_cache *cache; - struct rtable *rt = skb->rtable; + struct rtable *rt = skb_rtable(skb); read_lock(&mrt_lock); cache = ipmr_cache_find(net, rt->rt_src, rt->rt_dst); @@ -1955,6 +1947,7 @@ static const struct file_operations ipmr_mfc_fops = { #ifdef CONFIG_IP_PIMSM_V2 static struct net_protocol pim_protocol = { .handler = pim_rcv, + .netns_ok = 1, }; #endif @@ -2041,8 +2034,19 @@ int __init ip_mr_init(void) err = register_netdevice_notifier(&ip_mr_notifier); if (err) goto reg_notif_fail; +#ifdef CONFIG_IP_PIMSM_V2 + if (inet_add_protocol(&pim_protocol, IPPROTO_PIM) < 0) { + printk(KERN_ERR "ip_mr_init: can't add PIM protocol\n"); + err = -EAGAIN; + goto add_proto_fail; + } +#endif return 0; +#ifdef CONFIG_IP_PIMSM_V2 +add_proto_fail: + unregister_netdevice_notifier(&ip_mr_notifier); +#endif reg_notif_fail: del_timer(&ipmr_expire_timer); unregister_pernet_subsys(&ipmr_net_ops); diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c index fdf6811c31a2..1725dc0ef688 100644 --- a/net/ipv4/netfilter.c +++ b/net/ipv4/netfilter.c @@ -12,7 +12,7 @@ /* route_me_harder function, used by iptable_nat, iptable_mangle + ip_queue */ int ip_route_me_harder(struct sk_buff *skb, unsigned addr_type) { - struct net *net = dev_net(skb->dst->dev); + struct net *net = dev_net(skb_dst(skb)->dev); const struct iphdr *iph = ip_hdr(skb); struct rtable *rt; struct flowi fl = {}; @@ -41,8 +41,8 @@ int ip_route_me_harder(struct sk_buff *skb, unsigned addr_type) return -1; /* Drop old route. */ - dst_release(skb->dst); - skb->dst = &rt->u.dst; + skb_dst_drop(skb); + skb_dst_set(skb, &rt->u.dst); } else { /* non-local src, find valid iif to satisfy * rp-filter when calling ip_route_input. */ @@ -50,7 +50,7 @@ int ip_route_me_harder(struct sk_buff *skb, unsigned addr_type) if (ip_route_output_key(net, &rt, &fl) != 0) return -1; - odst = skb->dst; + odst = skb_dst(skb); if (ip_route_input(skb, iph->daddr, iph->saddr, RT_TOS(iph->tos), rt->u.dst.dev) != 0) { dst_release(&rt->u.dst); @@ -60,18 +60,22 @@ int ip_route_me_harder(struct sk_buff *skb, unsigned addr_type) dst_release(odst); } - if (skb->dst->error) + if (skb_dst(skb)->error) return -1; #ifdef CONFIG_XFRM if (!(IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED) && - xfrm_decode_session(skb, &fl, AF_INET) == 0) - if (xfrm_lookup(net, &skb->dst, &fl, skb->sk, 0)) + xfrm_decode_session(skb, &fl, AF_INET) == 0) { + struct dst_entry *dst = skb_dst(skb); + skb_dst_set(skb, NULL); + if (xfrm_lookup(net, &dst, &fl, skb->sk, 0)) return -1; + skb_dst_set(skb, dst); + } #endif /* Change in oif may mean change in hh_len. */ - hh_len = skb->dst->dev->hard_header_len; + hh_len = skb_dst(skb)->dev->hard_header_len; if (skb_headroom(skb) < hh_len && pskb_expand_head(skb, hh_len - skb_headroom(skb), 0, GFP_ATOMIC)) return -1; @@ -92,7 +96,7 @@ int ip_xfrm_me_harder(struct sk_buff *skb) if (xfrm_decode_session(skb, &fl, AF_INET) < 0) return -1; - dst = skb->dst; + dst = skb_dst(skb); if (dst->xfrm) dst = ((struct xfrm_dst *)dst)->route; dst_hold(dst); @@ -100,11 +104,11 @@ int ip_xfrm_me_harder(struct sk_buff *skb) if (xfrm_lookup(dev_net(dst->dev), &dst, &fl, skb->sk, 0) < 0) return -1; - dst_release(skb->dst); - skb->dst = dst; + skb_dst_drop(skb); + skb_dst_set(skb, dst); /* Change in oif may mean change in hh_len. */ - hh_len = skb->dst->dev->hard_header_len; + hh_len = skb_dst(skb)->dev->hard_header_len; if (skb_headroom(skb) < hh_len && pskb_expand_head(skb, hh_len - skb_headroom(skb), 0, GFP_ATOMIC)) return -1; diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 831fe1879dc0..7505dff4ffdf 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -231,6 +231,12 @@ static inline struct arpt_entry *get_entry(void *base, unsigned int offset) return (struct arpt_entry *)(base + offset); } +static inline __pure +struct arpt_entry *arpt_next_entry(const struct arpt_entry *entry) +{ + return (void *)entry + entry->next_offset; +} + unsigned int arpt_do_table(struct sk_buff *skb, unsigned int hook, const struct net_device *in, @@ -267,67 +273,64 @@ unsigned int arpt_do_table(struct sk_buff *skb, arp = arp_hdr(skb); do { - if (arp_packet_match(arp, skb->dev, indev, outdev, &e->arp)) { - struct arpt_entry_target *t; - int hdr_len; + struct arpt_entry_target *t; + int hdr_len; - hdr_len = sizeof(*arp) + (2 * sizeof(struct in_addr)) + - (2 * skb->dev->addr_len); - - ADD_COUNTER(e->counters, hdr_len, 1); - - t = arpt_get_target(e); - - /* Standard target? */ - if (!t->u.kernel.target->target) { - int v; - - v = ((struct arpt_standard_target *)t)->verdict; - if (v < 0) { - /* Pop from stack? */ - if (v != ARPT_RETURN) { - verdict = (unsigned)(-v) - 1; - break; - } - e = back; - back = get_entry(table_base, - back->comefrom); - continue; - } - if (table_base + v - != (void *)e + e->next_offset) { - /* Save old back ptr in next entry */ - struct arpt_entry *next - = (void *)e + e->next_offset; - next->comefrom = - (void *)back - table_base; - - /* set back pointer to next entry */ - back = next; - } - - e = get_entry(table_base, v); - } else { - /* Targets which reenter must return - * abs. verdicts - */ - tgpar.target = t->u.kernel.target; - tgpar.targinfo = t->data; - verdict = t->u.kernel.target->target(skb, - &tgpar); - - /* Target might have changed stuff. */ - arp = arp_hdr(skb); - - if (verdict == ARPT_CONTINUE) - e = (void *)e + e->next_offset; - else - /* Verdict */ - break; - } - } else { - e = (void *)e + e->next_offset; + if (!arp_packet_match(arp, skb->dev, indev, outdev, &e->arp)) { + e = arpt_next_entry(e); + continue; } + + hdr_len = sizeof(*arp) + (2 * sizeof(struct in_addr)) + + (2 * skb->dev->addr_len); + ADD_COUNTER(e->counters, hdr_len, 1); + + t = arpt_get_target(e); + + /* Standard target? */ + if (!t->u.kernel.target->target) { + int v; + + v = ((struct arpt_standard_target *)t)->verdict; + if (v < 0) { + /* Pop from stack? */ + if (v != ARPT_RETURN) { + verdict = (unsigned)(-v) - 1; + break; + } + e = back; + back = get_entry(table_base, back->comefrom); + continue; + } + if (table_base + v + != arpt_next_entry(e)) { + /* Save old back ptr in next entry */ + struct arpt_entry *next = arpt_next_entry(e); + next->comefrom = (void *)back - table_base; + + /* set back pointer to next entry */ + back = next; + } + + e = get_entry(table_base, v); + continue; + } + + /* Targets which reenter must return + * abs. verdicts + */ + tgpar.target = t->u.kernel.target; + tgpar.targinfo = t->data; + verdict = t->u.kernel.target->target(skb, &tgpar); + + /* Target might have changed stuff. */ + arp = arp_hdr(skb); + + if (verdict == ARPT_CONTINUE) + e = arpt_next_entry(e); + else + /* Verdict */ + break; } while (!hotdrop); xt_info_rdunlock_bh(); diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c index 5f22c91c6e15..c156db215987 100644 --- a/net/ipv4/netfilter/ip_queue.c +++ b/net/ipv4/netfilter/ip_queue.c @@ -596,7 +596,7 @@ static int __init ip_queue_init(void) #ifdef CONFIG_SYSCTL ipq_sysctl_header = register_sysctl_paths(net_ipv4_ctl_path, ipq_table); #endif - status = nf_register_queue_handler(PF_INET, &nfqh); + status = nf_register_queue_handler(NFPROTO_IPV4, &nfqh); if (status < 0) { printk(KERN_ERR "ip_queue: failed to register queue handler\n"); goto cleanup_sysctl; diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 2ec8d7290c40..fdefae6b5dfc 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -238,8 +238,8 @@ static struct nf_loginfo trace_loginfo = { /* Mildly perf critical (only if packet tracing is on) */ static inline int get_chainname_rulenum(struct ipt_entry *s, struct ipt_entry *e, - char *hookname, char **chainname, - char **comment, unsigned int *rulenum) + const char *hookname, const char **chainname, + const char **comment, unsigned int *rulenum) { struct ipt_standard_target *t = (void *)ipt_get_target(s); @@ -257,8 +257,8 @@ get_chainname_rulenum(struct ipt_entry *s, struct ipt_entry *e, && unconditional(&s->ip)) { /* Tail of chains: STANDARD target (return/policy) */ *comment = *chainname == hookname - ? (char *)comments[NF_IP_TRACE_COMMENT_POLICY] - : (char *)comments[NF_IP_TRACE_COMMENT_RETURN]; + ? comments[NF_IP_TRACE_COMMENT_POLICY] + : comments[NF_IP_TRACE_COMMENT_RETURN]; } return 1; } else @@ -277,14 +277,14 @@ static void trace_packet(struct sk_buff *skb, { void *table_base; const struct ipt_entry *root; - char *hookname, *chainname, *comment; + const char *hookname, *chainname, *comment; unsigned int rulenum = 0; - table_base = (void *)private->entries[smp_processor_id()]; + table_base = private->entries[smp_processor_id()]; root = get_entry(table_base, private->hook_entry[hook]); - hookname = chainname = (char *)hooknames[hook]; - comment = (char *)comments[NF_IP_TRACE_COMMENT_RULE]; + hookname = chainname = hooknames[hook]; + comment = comments[NF_IP_TRACE_COMMENT_RULE]; IPT_ENTRY_ITERATE(root, private->size - private->hook_entry[hook], @@ -297,6 +297,12 @@ static void trace_packet(struct sk_buff *skb, } #endif +static inline __pure +struct ipt_entry *ipt_next_entry(const struct ipt_entry *entry) +{ + return (void *)entry + entry->next_offset; +} + /* Returns one of the generic firewall policies, like NF_ACCEPT. */ unsigned int ipt_do_table(struct sk_buff *skb, @@ -305,6 +311,8 @@ ipt_do_table(struct sk_buff *skb, const struct net_device *out, struct xt_table *table) { +#define tb_comefrom ((struct ipt_entry *)table_base)->comefrom + static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long)))); const struct iphdr *ip; u_int16_t datalen; @@ -335,7 +343,7 @@ ipt_do_table(struct sk_buff *skb, mtpar.in = tgpar.in = in; mtpar.out = tgpar.out = out; mtpar.family = tgpar.family = NFPROTO_IPV4; - tgpar.hooknum = hook; + mtpar.hooknum = tgpar.hooknum = hook; IP_NF_ASSERT(table->valid_hooks & (1 << hook)); xt_info_rdlock_bh(); @@ -348,92 +356,84 @@ ipt_do_table(struct sk_buff *skb, back = get_entry(table_base, private->underflow[hook]); do { + struct ipt_entry_target *t; + IP_NF_ASSERT(e); IP_NF_ASSERT(back); - if (ip_packet_match(ip, indev, outdev, - &e->ip, mtpar.fragoff)) { - struct ipt_entry_target *t; + if (!ip_packet_match(ip, indev, outdev, + &e->ip, mtpar.fragoff) || + IPT_MATCH_ITERATE(e, do_match, skb, &mtpar) != 0) { + e = ipt_next_entry(e); + continue; + } - if (IPT_MATCH_ITERATE(e, do_match, skb, &mtpar) != 0) - goto no_match; + ADD_COUNTER(e->counters, ntohs(ip->tot_len), 1); - ADD_COUNTER(e->counters, ntohs(ip->tot_len), 1); - - t = ipt_get_target(e); - IP_NF_ASSERT(t->u.kernel.target); + t = ipt_get_target(e); + IP_NF_ASSERT(t->u.kernel.target); #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \ defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE) - /* The packet is traced: log it */ - if (unlikely(skb->nf_trace)) - trace_packet(skb, hook, in, out, - table->name, private, e); + /* The packet is traced: log it */ + if (unlikely(skb->nf_trace)) + trace_packet(skb, hook, in, out, + table->name, private, e); #endif - /* Standard target? */ - if (!t->u.kernel.target->target) { - int v; + /* Standard target? */ + if (!t->u.kernel.target->target) { + int v; - v = ((struct ipt_standard_target *)t)->verdict; - if (v < 0) { - /* Pop from stack? */ - if (v != IPT_RETURN) { - verdict = (unsigned)(-v) - 1; - break; - } - e = back; - back = get_entry(table_base, - back->comefrom); - continue; - } - if (table_base + v != (void *)e + e->next_offset - && !(e->ip.flags & IPT_F_GOTO)) { - /* Save old back ptr in next entry */ - struct ipt_entry *next - = (void *)e + e->next_offset; - next->comefrom - = (void *)back - table_base; - /* set back pointer to next entry */ - back = next; - } - - e = get_entry(table_base, v); - } else { - /* Targets which reenter must return - abs. verdicts */ - tgpar.target = t->u.kernel.target; - tgpar.targinfo = t->data; -#ifdef CONFIG_NETFILTER_DEBUG - ((struct ipt_entry *)table_base)->comefrom - = 0xeeeeeeec; -#endif - verdict = t->u.kernel.target->target(skb, - &tgpar); -#ifdef CONFIG_NETFILTER_DEBUG - if (((struct ipt_entry *)table_base)->comefrom - != 0xeeeeeeec - && verdict == IPT_CONTINUE) { - printk("Target %s reentered!\n", - t->u.kernel.target->name); - verdict = NF_DROP; - } - ((struct ipt_entry *)table_base)->comefrom - = 0x57acc001; -#endif - /* Target might have changed stuff. */ - ip = ip_hdr(skb); - datalen = skb->len - ip->ihl * 4; - - if (verdict == IPT_CONTINUE) - e = (void *)e + e->next_offset; - else - /* Verdict */ + v = ((struct ipt_standard_target *)t)->verdict; + if (v < 0) { + /* Pop from stack? */ + if (v != IPT_RETURN) { + verdict = (unsigned)(-v) - 1; break; + } + e = back; + back = get_entry(table_base, back->comefrom); + continue; + } + if (table_base + v != ipt_next_entry(e) + && !(e->ip.flags & IPT_F_GOTO)) { + /* Save old back ptr in next entry */ + struct ipt_entry *next = ipt_next_entry(e); + next->comefrom = (void *)back - table_base; + /* set back pointer to next entry */ + back = next; } - } else { - no_match: - e = (void *)e + e->next_offset; + e = get_entry(table_base, v); + continue; } + + /* Targets which reenter must return + abs. verdicts */ + tgpar.target = t->u.kernel.target; + tgpar.targinfo = t->data; + + +#ifdef CONFIG_NETFILTER_DEBUG + tb_comefrom = 0xeeeeeeec; +#endif + verdict = t->u.kernel.target->target(skb, &tgpar); +#ifdef CONFIG_NETFILTER_DEBUG + if (tb_comefrom != 0xeeeeeeec && verdict == IPT_CONTINUE) { + printk("Target %s reentered!\n", + t->u.kernel.target->name); + verdict = NF_DROP; + } + tb_comefrom = 0x57acc001; +#endif + /* Target might have changed stuff. */ + ip = ip_hdr(skb); + datalen = skb->len - ip->ihl * 4; + + if (verdict == IPT_CONTINUE) + e = ipt_next_entry(e); + else + /* Verdict */ + break; } while (!hotdrop); xt_info_rdunlock_bh(); @@ -444,6 +444,8 @@ ipt_do_table(struct sk_buff *skb, return NF_DROP; else return verdict; #endif + +#undef tb_comefrom } /* Figures out from what hook each rule can be called: returns 0 if @@ -2158,7 +2160,7 @@ static bool icmp_checkentry(const struct xt_mtchk_param *par) static struct xt_target ipt_standard_target __read_mostly = { .name = IPT_STANDARD_TARGET, .targetsize = sizeof(int), - .family = AF_INET, + .family = NFPROTO_IPV4, #ifdef CONFIG_COMPAT .compatsize = sizeof(compat_int_t), .compat_from_user = compat_standard_from_user, @@ -2170,7 +2172,7 @@ static struct xt_target ipt_error_target __read_mostly = { .name = IPT_ERROR_TARGET, .target = ipt_error, .targetsize = IPT_FUNCTION_MAXNAMELEN, - .family = AF_INET, + .family = NFPROTO_IPV4, }; static struct nf_sockopt_ops ipt_sockopts = { @@ -2196,17 +2198,17 @@ static struct xt_match icmp_matchstruct __read_mostly = { .matchsize = sizeof(struct ipt_icmp), .checkentry = icmp_checkentry, .proto = IPPROTO_ICMP, - .family = AF_INET, + .family = NFPROTO_IPV4, }; static int __net_init ip_tables_net_init(struct net *net) { - return xt_proto_init(net, AF_INET); + return xt_proto_init(net, NFPROTO_IPV4); } static void __net_exit ip_tables_net_exit(struct net *net) { - xt_proto_fini(net, AF_INET); + xt_proto_fini(net, NFPROTO_IPV4); } static struct pernet_operations ip_tables_net_ops = { diff --git a/net/ipv4/netfilter/ipt_MASQUERADE.c b/net/ipv4/netfilter/ipt_MASQUERADE.c index f389f60cb105..dada0863946d 100644 --- a/net/ipv4/netfilter/ipt_MASQUERADE.c +++ b/net/ipv4/netfilter/ipt_MASQUERADE.c @@ -27,9 +27,6 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Netfilter Core Team "); MODULE_DESCRIPTION("Xtables: automatic-address SNAT"); -/* Lock protects masq region inside conntrack */ -static DEFINE_RWLOCK(masq_lock); - /* FIXME: Multiple targets. --RR */ static bool masquerade_tg_check(const struct xt_tgchk_param *par) { @@ -72,16 +69,14 @@ masquerade_tg(struct sk_buff *skb, const struct xt_target_param *par) return NF_ACCEPT; mr = par->targinfo; - rt = skb->rtable; + rt = skb_rtable(skb); newsrc = inet_select_addr(par->out, rt->rt_gateway, RT_SCOPE_UNIVERSE); if (!newsrc) { printk("MASQUERADE: %s ate my IP address\n", par->out->name); return NF_DROP; } - write_lock_bh(&masq_lock); nat->masq_index = par->out->ifindex; - write_unlock_bh(&masq_lock); /* Transfer from original range. */ newrange = ((struct nf_nat_range) @@ -97,16 +92,11 @@ static int device_cmp(struct nf_conn *i, void *ifindex) { const struct nf_conn_nat *nat = nfct_nat(i); - int ret; if (!nat) return 0; - read_lock_bh(&masq_lock); - ret = (nat->masq_index == (int)(long)ifindex); - read_unlock_bh(&masq_lock); - - return ret; + return nat->masq_index == (int)(long)ifindex; } static int masq_device_event(struct notifier_block *this, diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c index 0b4b6e0ff2b9..c93ae44bff2a 100644 --- a/net/ipv4/netfilter/ipt_REJECT.c +++ b/net/ipv4/netfilter/ipt_REJECT.c @@ -108,17 +108,16 @@ static void send_reset(struct sk_buff *oldskb, int hook) addr_type = RTN_LOCAL; /* ip_route_me_harder expects skb->dst to be set */ - dst_hold(oldskb->dst); - nskb->dst = oldskb->dst; + skb_dst_set(nskb, dst_clone(skb_dst(oldskb))); if (ip_route_me_harder(nskb, addr_type)) goto free_nskb; - niph->ttl = dst_metric(nskb->dst, RTAX_HOPLIMIT); + niph->ttl = dst_metric(skb_dst(nskb), RTAX_HOPLIMIT); nskb->ip_summed = CHECKSUM_NONE; /* "Never happens" */ - if (nskb->len > dst_mtu(nskb->dst)) + if (nskb->len > dst_mtu(skb_dst(nskb))) goto free_nskb; nf_ct_attach(nskb, oldskb); diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c index 23b2c2ee869a..d71ba7677344 100644 --- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c +++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c @@ -82,18 +82,10 @@ static int icmp_packet(struct nf_conn *ct, u_int8_t pf, unsigned int hooknum) { - /* Try to delete connection immediately after all replies: - won't actually vanish as we still have skb, and del_timer - means this will only run once even if count hits zero twice - (theoretically possible with SMP) */ - if (CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY) { - if (atomic_dec_and_test(&ct->proto.icmp.count)) - nf_ct_kill_acct(ct, ctinfo, skb); - } else { - atomic_inc(&ct->proto.icmp.count); - nf_conntrack_event_cache(IPCT_PROTOINFO_VOLATILE, ct); - nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_icmp_timeout); - } + /* Do not immediately delete the connection after the first + successful reply to avoid excessive conntrackd traffic + and also to handle correctly ICMP echo reply duplicates. */ + nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_icmp_timeout); return NF_ACCEPT; } @@ -117,7 +109,6 @@ static bool icmp_new(struct nf_conn *ct, const struct sk_buff *skb, nf_ct_dump_tuple_ip(&ct->tuplehash[0].tuple); return false; } - atomic_set(&ct->proto.icmp.count, 0); return true; } diff --git a/net/ipv4/netfilter/nf_nat_helper.c b/net/ipv4/netfilter/nf_nat_helper.c index cf7a42bf9820..155c008626c8 100644 --- a/net/ipv4/netfilter/nf_nat_helper.c +++ b/net/ipv4/netfilter/nf_nat_helper.c @@ -140,7 +140,7 @@ nf_nat_mangle_tcp_packet(struct sk_buff *skb, const char *rep_buffer, unsigned int rep_len) { - struct rtable *rt = skb->rtable; + struct rtable *rt = skb_rtable(skb); struct iphdr *iph; struct tcphdr *tcph; int oldlen, datalen; @@ -218,7 +218,7 @@ nf_nat_mangle_udp_packet(struct sk_buff *skb, const char *rep_buffer, unsigned int rep_len) { - struct rtable *rt = skb->rtable; + struct rtable *rt = skb_rtable(skb); struct iphdr *iph; struct udphdr *udph; int datalen, oldlen; diff --git a/net/ipv4/netfilter/nf_nat_proto_sctp.c b/net/ipv4/netfilter/nf_nat_proto_sctp.c index 65e470bc6123..3fc598eeeb1a 100644 --- a/net/ipv4/netfilter/nf_nat_proto_sctp.c +++ b/net/ipv4/netfilter/nf_nat_proto_sctp.c @@ -33,6 +33,7 @@ sctp_manip_pkt(struct sk_buff *skb, enum nf_nat_manip_type maniptype) { const struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff); + struct sk_buff *frag; sctp_sctphdr_t *hdr; unsigned int hdroff = iphdroff + iph->ihl*4; __be32 oldip, newip; @@ -57,8 +58,8 @@ sctp_manip_pkt(struct sk_buff *skb, } crc32 = sctp_start_cksum((u8 *)hdr, skb_headlen(skb) - hdroff); - for (skb = skb_shinfo(skb)->frag_list; skb; skb = skb->next) - crc32 = sctp_update_cksum((u8 *)skb->data, skb_headlen(skb), + skb_walk_frags(skb, frag) + crc32 = sctp_update_cksum((u8 *)frag->data, skb_headlen(frag), crc32); crc32 = sctp_end_cksum(crc32); hdr->checksum = crc32; diff --git a/net/ipv4/netfilter/nf_nat_standalone.c b/net/ipv4/netfilter/nf_nat_standalone.c index b7dd695691a0..5567bd0d0750 100644 --- a/net/ipv4/netfilter/nf_nat_standalone.c +++ b/net/ipv4/netfilter/nf_nat_standalone.c @@ -167,10 +167,9 @@ nf_nat_in(unsigned int hooknum, ret = nf_nat_fn(hooknum, skb, in, out, okfn); if (ret != NF_DROP && ret != NF_STOLEN && - daddr != ip_hdr(skb)->daddr) { - dst_release(skb->dst); - skb->dst = NULL; - } + daddr != ip_hdr(skb)->daddr) + skb_dst_drop(skb); + return ret; } diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index cf0cdeeb1db0..f25542c48b7d 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c @@ -90,14 +90,14 @@ static const struct file_operations sockstat_seq_fops = { /* snmp items */ static const struct snmp_mib snmp4_ipstats_list[] = { - SNMP_MIB_ITEM("InReceives", IPSTATS_MIB_INRECEIVES), + SNMP_MIB_ITEM("InReceives", IPSTATS_MIB_INPKTS), SNMP_MIB_ITEM("InHdrErrors", IPSTATS_MIB_INHDRERRORS), SNMP_MIB_ITEM("InAddrErrors", IPSTATS_MIB_INADDRERRORS), SNMP_MIB_ITEM("ForwDatagrams", IPSTATS_MIB_OUTFORWDATAGRAMS), SNMP_MIB_ITEM("InUnknownProtos", IPSTATS_MIB_INUNKNOWNPROTOS), SNMP_MIB_ITEM("InDiscards", IPSTATS_MIB_INDISCARDS), SNMP_MIB_ITEM("InDelivers", IPSTATS_MIB_INDELIVERS), - SNMP_MIB_ITEM("OutRequests", IPSTATS_MIB_OUTREQUESTS), + SNMP_MIB_ITEM("OutRequests", IPSTATS_MIB_OUTPKTS), SNMP_MIB_ITEM("OutDiscards", IPSTATS_MIB_OUTDISCARDS), SNMP_MIB_ITEM("OutNoRoutes", IPSTATS_MIB_OUTNOROUTES), SNMP_MIB_ITEM("ReasmTimeout", IPSTATS_MIB_REASMTIMEOUT), @@ -118,6 +118,12 @@ static const struct snmp_mib snmp4_ipextstats_list[] = { SNMP_MIB_ITEM("OutMcastPkts", IPSTATS_MIB_OUTMCASTPKTS), SNMP_MIB_ITEM("InBcastPkts", IPSTATS_MIB_INBCASTPKTS), SNMP_MIB_ITEM("OutBcastPkts", IPSTATS_MIB_OUTBCASTPKTS), + SNMP_MIB_ITEM("InOctets", IPSTATS_MIB_INOCTETS), + SNMP_MIB_ITEM("OutOctets", IPSTATS_MIB_OUTOCTETS), + SNMP_MIB_ITEM("InMcastOctets", IPSTATS_MIB_INMCASTOCTETS), + SNMP_MIB_ITEM("OutMcastOctets", IPSTATS_MIB_OUTMCASTOCTETS), + SNMP_MIB_ITEM("InBcastOctets", IPSTATS_MIB_INBCASTOCTETS), + SNMP_MIB_ITEM("OutBcastOctets", IPSTATS_MIB_OUTBCASTOCTETS), SNMP_MIB_SENTINEL }; diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index f774651f0a47..2979f14bb188 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -343,7 +343,7 @@ static int raw_send_hdrinc(struct sock *sk, void *from, size_t length, skb->priority = sk->sk_priority; skb->mark = sk->sk_mark; - skb->dst = dst_clone(&rt->u.dst); + skb_dst_set(skb, dst_clone(&rt->u.dst)); skb_reset_network_header(skb); iph = ip_hdr(skb); @@ -799,7 +799,8 @@ static int raw_ioctl(struct sock *sk, int cmd, unsigned long arg) { switch (cmd) { case SIOCOUTQ: { - int amount = atomic_read(&sk->sk_wmem_alloc); + int amount = sk_wmem_alloc_get(sk); + return put_user(amount, (int __user *)arg); } case SIOCINQ: { @@ -935,8 +936,8 @@ static void raw_sock_seq_show(struct seq_file *seq, struct sock *sp, int i) seq_printf(seq, "%4d: %08X:%04X %08X:%04X" " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %d\n", i, src, srcp, dest, destp, sp->sk_state, - atomic_read(&sp->sk_wmem_alloc), - atomic_read(&sp->sk_rmem_alloc), + sk_wmem_alloc_get(sp), + sk_rmem_alloc_get(sp), 0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp), atomic_read(&sp->sk_refcnt), sp, atomic_read(&sp->sk_drops)); } diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 28205e5bfa9b..278f46f5011b 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -131,8 +131,8 @@ static int ip_rt_min_advmss __read_mostly = 256; static int ip_rt_secret_interval __read_mostly = 10 * 60 * HZ; static int rt_chain_length_max __read_mostly = 20; -static void rt_worker_func(struct work_struct *work); -static DECLARE_DELAYED_WORK(expires_work, rt_worker_func); +static struct delayed_work expires_work; +static unsigned long expires_ljiffies; /* * Interface to generic destination cache. @@ -787,9 +787,12 @@ static void rt_check_expire(void) struct rtable *rth, *aux, **rthp; unsigned long samples = 0; unsigned long sum = 0, sum2 = 0; + unsigned long delta; u64 mult; - mult = ((u64)ip_rt_gc_interval) << rt_hash_log; + delta = jiffies - expires_ljiffies; + expires_ljiffies = jiffies; + mult = ((u64)delta) << rt_hash_log; if (ip_rt_gc_timeout > 1) do_div(mult, ip_rt_gc_timeout); goal = (unsigned int)mult; @@ -1064,7 +1067,8 @@ work_done: out: return 0; } -static int rt_intern_hash(unsigned hash, struct rtable *rt, struct rtable **rp) +static int rt_intern_hash(unsigned hash, struct rtable *rt, + struct rtable **rp, struct sk_buff *skb) { struct rtable *rth, **rthp; unsigned long now; @@ -1081,8 +1085,35 @@ restart: now = jiffies; if (!rt_caching(dev_net(rt->u.dst.dev))) { - rt_drop(rt); - return 0; + /* + * If we're not caching, just tell the caller we + * were successful and don't touch the route. The + * caller hold the sole reference to the cache entry, and + * it will be released when the caller is done with it. + * If we drop it here, the callers have no way to resolve routes + * when we're not caching. Instead, just point *rp at rt, so + * the caller gets a single use out of the route + * Note that we do rt_free on this new route entry, so that + * once its refcount hits zero, we are still able to reap it + * (Thanks Alexey) + * Note also the rt_free uses call_rcu. We don't actually + * need rcu protection here, this is just our path to get + * on the route gc list. + */ + + if (rt->rt_type == RTN_UNICAST || rt->fl.iif == 0) { + int err = arp_bind_neighbour(&rt->u.dst); + if (err) { + if (net_ratelimit()) + printk(KERN_WARNING + "Neighbour table failure & not caching routes.\n"); + rt_drop(rt); + return err; + } + } + + rt_free(rt); + goto skip_hashing; } rthp = &rt_hash_table[hash].chain; @@ -1114,7 +1145,10 @@ restart: spin_unlock_bh(rt_hash_lock_addr(hash)); rt_drop(rt); - *rp = rth; + if (rp) + *rp = rth; + else + skb_dst_set(skb, &rth->u.dst); return 0; } @@ -1196,7 +1230,8 @@ restart: #if RT_CACHE_DEBUG >= 2 if (rt->u.dst.rt_next) { struct rtable *trt; - printk(KERN_DEBUG "rt_cache @%02x: %pI4", hash, &rt->rt_dst); + printk(KERN_DEBUG "rt_cache @%02x: %pI4", + hash, &rt->rt_dst); for (trt = rt->u.dst.rt_next; trt; trt = trt->u.dst.rt_next) printk(" . %pI4", &trt->rt_dst); printk("\n"); @@ -1210,7 +1245,12 @@ restart: rcu_assign_pointer(rt_hash_table[hash].chain, rt); spin_unlock_bh(rt_hash_lock_addr(hash)); - *rp = rt; + +skip_hashing: + if (rp) + *rp = rt; + else + skb_dst_set(skb, &rt->u.dst); return 0; } @@ -1407,7 +1447,7 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw, &netevent); rt_del(hash, rth); - if (!rt_intern_hash(hash, rt, &rt)) + if (!rt_intern_hash(hash, rt, &rt, NULL)) ip_rt_put(rt); goto do_next; } @@ -1473,7 +1513,7 @@ static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst) void ip_rt_send_redirect(struct sk_buff *skb) { - struct rtable *rt = skb->rtable; + struct rtable *rt = skb_rtable(skb); struct in_device *in_dev = in_dev_get(rt->u.dst.dev); if (!in_dev) @@ -1521,7 +1561,7 @@ out: static int ip_error(struct sk_buff *skb) { - struct rtable *rt = skb->rtable; + struct rtable *rt = skb_rtable(skb); unsigned long now; int code; @@ -1698,7 +1738,7 @@ static void ipv4_link_failure(struct sk_buff *skb) icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0); - rt = skb->rtable; + rt = skb_rtable(skb); if (rt) dst_set_expires(&rt->u.dst, 0); } @@ -1858,7 +1898,7 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr, in_dev_put(in_dev); hash = rt_hash(daddr, saddr, dev->ifindex, rt_genid(dev_net(dev))); - return rt_intern_hash(hash, rth, &skb->rtable); + return rt_intern_hash(hash, rth, NULL, skb); e_nobufs: in_dev_put(in_dev); @@ -2019,7 +2059,7 @@ static int ip_mkroute_input(struct sk_buff *skb, /* put it into the cache */ hash = rt_hash(daddr, saddr, fl->iif, rt_genid(dev_net(rth->u.dst.dev))); - return rt_intern_hash(hash, rth, &skb->rtable); + return rt_intern_hash(hash, rth, NULL, skb); } /* @@ -2175,7 +2215,7 @@ local_input: } rth->rt_type = res.type; hash = rt_hash(daddr, saddr, fl.iif, rt_genid(net)); - err = rt_intern_hash(hash, rth, &skb->rtable); + err = rt_intern_hash(hash, rth, NULL, skb); goto done; no_route: @@ -2244,7 +2284,7 @@ int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr, dst_use(&rth->u.dst, jiffies); RT_CACHE_STAT_INC(in_hit); rcu_read_unlock(); - skb->rtable = rth; + skb_dst_set(skb, &rth->u.dst); return 0; } RT_CACHE_STAT_INC(in_hlist_search); @@ -2420,7 +2460,7 @@ static int ip_mkroute_output(struct rtable **rp, if (err == 0) { hash = rt_hash(oldflp->fl4_dst, oldflp->fl4_src, oldflp->oif, rt_genid(dev_net(dev_out))); - err = rt_intern_hash(hash, rth, rp); + err = rt_intern_hash(hash, rth, rp, NULL); } return err; @@ -2763,7 +2803,7 @@ static int rt_fill_info(struct net *net, struct sk_buff *skb, u32 pid, u32 seq, int event, int nowait, unsigned int flags) { - struct rtable *rt = skb->rtable; + struct rtable *rt = skb_rtable(skb); struct rtmsg *r; struct nlmsghdr *nlh; long expires; @@ -2907,7 +2947,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void err = ip_route_input(skb, dst, src, rtm->rtm_tos, dev); local_bh_enable(); - rt = skb->rtable; + rt = skb_rtable(skb); if (err == 0 && rt->u.dst.error) err = -rt->u.dst.error; } else { @@ -2927,7 +2967,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void if (err) goto errout_free; - skb->rtable = rt; + skb_dst_set(skb, &rt->u.dst); if (rtm->rtm_flags & RTM_F_NOTIFY) rt->rt_flags |= RTCF_NOTIFY; @@ -2968,15 +3008,15 @@ int ip_rt_dump(struct sk_buff *skb, struct netlink_callback *cb) continue; if (rt_is_expired(rt)) continue; - skb->dst = dst_clone(&rt->u.dst); + skb_dst_set(skb, dst_clone(&rt->u.dst)); if (rt_fill_info(net, skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, RTM_NEWROUTE, 1, NLM_F_MULTI) <= 0) { - dst_release(xchg(&skb->dst, NULL)); + skb_dst_drop(skb); rcu_read_unlock_bh(); goto done; } - dst_release(xchg(&skb->dst, NULL)); + skb_dst_drop(skb); } rcu_read_unlock_bh(); } @@ -3390,6 +3430,8 @@ int __init ip_rt_init(void) /* All the timers, started at system startup tend to synchronize. Perturb it a bit. */ + INIT_DELAYED_WORK_DEFERRABLE(&expires_work, rt_worker_func); + expires_ljiffies = jiffies; schedule_delayed_work(&expires_work, net_random() % ip_rt_gc_interval + ip_rt_gc_interval); diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index b35a950d2e06..cd2b97f1b6e1 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c @@ -161,13 +161,12 @@ static __u16 const msstab[] = { */ __u32 cookie_v4_init_sequence(struct sock *sk, struct sk_buff *skb, __u16 *mssp) { - struct tcp_sock *tp = tcp_sk(sk); const struct iphdr *iph = ip_hdr(skb); const struct tcphdr *th = tcp_hdr(skb); int mssind; const __u16 mss = *mssp; - tp->last_synq_overflow = jiffies; + tcp_synq_overflow(sk); /* XXX sort msstab[] by probability? Binary search? */ for (mssind = 0; mss > msstab[mssind + 1]; mssind++) @@ -268,7 +267,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, if (!sysctl_tcp_syncookies || !th->ack) goto out; - if (time_after(jiffies, tp->last_synq_overflow + TCP_TIMEOUT_INIT) || + if (tcp_synq_no_recent_overflow(sk) || (mss = cookie_check(skb, cookie)) == 0) { NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_SYNCOOKIESFAILED); goto out; diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 7a0f0b27bf1f..17b89c523f9d 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -439,12 +439,14 @@ int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg) !tp->urg_data || before(tp->urg_seq, tp->copied_seq) || !before(tp->urg_seq, tp->rcv_nxt)) { + struct sk_buff *skb; + answ = tp->rcv_nxt - tp->copied_seq; /* Subtract 1, if FIN is in queue. */ - if (answ && !skb_queue_empty(&sk->sk_receive_queue)) - answ -= - tcp_hdr((struct sk_buff *)sk->sk_receive_queue.prev)->fin; + skb = skb_peek_tail(&sk->sk_receive_queue); + if (answ && skb) + answ -= tcp_hdr(skb)->fin; } else answ = tp->urg_seq - tp->copied_seq; release_sock(sk); @@ -1382,11 +1384,7 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, /* Next get a buffer. */ - skb = skb_peek(&sk->sk_receive_queue); - do { - if (!skb) - break; - + skb_queue_walk(&sk->sk_receive_queue, skb) { /* Now that we have two receive queues this * shouldn't happen. */ @@ -1403,8 +1401,7 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, if (tcp_hdr(skb)->fin) goto found_fin_ok; WARN_ON(!(flags & MSG_PEEK)); - skb = skb->next; - } while (skb != (struct sk_buff *)&sk->sk_receive_queue); + } /* Well, if we have backlog, try to process it now yet. */ @@ -2518,20 +2515,30 @@ struct sk_buff **tcp_gro_receive(struct sk_buff **head, struct sk_buff *skb) unsigned int thlen; unsigned int flags; unsigned int mss = 1; + unsigned int hlen; + unsigned int off; int flush = 1; int i; - th = skb_gro_header(skb, sizeof(*th)); - if (unlikely(!th)) - goto out; + off = skb_gro_offset(skb); + hlen = off + sizeof(*th); + th = skb_gro_header_fast(skb, off); + if (skb_gro_header_hard(skb, hlen)) { + th = skb_gro_header_slow(skb, hlen, off); + if (unlikely(!th)) + goto out; + } thlen = th->doff * 4; if (thlen < sizeof(*th)) goto out; - th = skb_gro_header(skb, thlen); - if (unlikely(!th)) - goto out; + hlen = off + thlen; + if (skb_gro_header_hard(skb, hlen)) { + th = skb_gro_header_slow(skb, hlen, off); + if (unlikely(!th)) + goto out; + } skb_gro_pull(skb, thlen); @@ -2544,7 +2551,7 @@ struct sk_buff **tcp_gro_receive(struct sk_buff **head, struct sk_buff *skb) th2 = tcp_hdr(p); - if ((th->source ^ th2->source) | (th->dest ^ th2->dest)) { + if (*(u32 *)&th->source ^ *(u32 *)&th2->source) { NAPI_GRO_CB(p)->same_flow = 0; continue; } @@ -2559,14 +2566,14 @@ found: flush |= flags & TCP_FLAG_CWR; flush |= (flags ^ tcp_flag_word(th2)) & ~(TCP_FLAG_CWR | TCP_FLAG_FIN | TCP_FLAG_PSH); - flush |= (th->ack_seq ^ th2->ack_seq) | (th->window ^ th2->window); - for (i = sizeof(*th); !flush && i < thlen; i += 4) + flush |= th->ack_seq ^ th2->ack_seq; + for (i = sizeof(*th); i < thlen; i += 4) flush |= *(u32 *)((u8 *)th + i) ^ *(u32 *)((u8 *)th2 + i); mss = skb_shinfo(p)->gso_size; - flush |= (len > mss) | !len; + flush |= (len - 1) >= mss; flush |= (ntohl(th2->seq) + skb_gro_len(p)) ^ ntohl(th->seq); if (flush || skb_gro_receive(head, skb)) { diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index eec3e6f9956c..2bdb0da237e6 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -77,7 +77,7 @@ int sysctl_tcp_window_scaling __read_mostly = 1; int sysctl_tcp_sack __read_mostly = 1; int sysctl_tcp_fack __read_mostly = 1; int sysctl_tcp_reordering __read_mostly = TCP_FASTRETRANS_THRESH; -int sysctl_tcp_ecn __read_mostly; +int sysctl_tcp_ecn __read_mostly = 2; int sysctl_tcp_dsack __read_mostly = 1; int sysctl_tcp_app_win __read_mostly = 31; int sysctl_tcp_adv_win_scale __read_mostly = 2; @@ -4426,7 +4426,7 @@ drop: } __skb_queue_head(&tp->out_of_order_queue, skb); } else { - struct sk_buff *skb1 = tp->out_of_order_queue.prev; + struct sk_buff *skb1 = skb_peek_tail(&tp->out_of_order_queue); u32 seq = TCP_SKB_CB(skb)->seq; u32 end_seq = TCP_SKB_CB(skb)->end_seq; @@ -4443,15 +4443,18 @@ drop: } /* Find place to insert this segment. */ - do { + while (1) { if (!after(TCP_SKB_CB(skb1)->seq, seq)) break; - } while ((skb1 = skb1->prev) != - (struct sk_buff *)&tp->out_of_order_queue); + if (skb_queue_is_first(&tp->out_of_order_queue, skb1)) { + skb1 = NULL; + break; + } + skb1 = skb_queue_prev(&tp->out_of_order_queue, skb1); + } /* Do skb overlap to previous one? */ - if (skb1 != (struct sk_buff *)&tp->out_of_order_queue && - before(seq, TCP_SKB_CB(skb1)->end_seq)) { + if (skb1 && before(seq, TCP_SKB_CB(skb1)->end_seq)) { if (!after(end_seq, TCP_SKB_CB(skb1)->end_seq)) { /* All the bits are present. Drop. */ __kfree_skb(skb); @@ -4463,15 +4466,26 @@ drop: tcp_dsack_set(sk, seq, TCP_SKB_CB(skb1)->end_seq); } else { - skb1 = skb1->prev; + if (skb_queue_is_first(&tp->out_of_order_queue, + skb1)) + skb1 = NULL; + else + skb1 = skb_queue_prev( + &tp->out_of_order_queue, + skb1); } } - __skb_queue_after(&tp->out_of_order_queue, skb1, skb); + if (!skb1) + __skb_queue_head(&tp->out_of_order_queue, skb); + else + __skb_queue_after(&tp->out_of_order_queue, skb1, skb); /* And clean segments covered by new one as whole. */ - while ((skb1 = skb->next) != - (struct sk_buff *)&tp->out_of_order_queue && - after(end_seq, TCP_SKB_CB(skb1)->seq)) { + while (!skb_queue_is_last(&tp->out_of_order_queue, skb)) { + skb1 = skb_queue_next(&tp->out_of_order_queue, skb); + + if (!after(end_seq, TCP_SKB_CB(skb1)->seq)) + break; if (before(end_seq, TCP_SKB_CB(skb1)->end_seq)) { tcp_dsack_extend(sk, TCP_SKB_CB(skb1)->seq, end_seq); @@ -4492,7 +4506,10 @@ add_sack: static struct sk_buff *tcp_collapse_one(struct sock *sk, struct sk_buff *skb, struct sk_buff_head *list) { - struct sk_buff *next = skb->next; + struct sk_buff *next = NULL; + + if (!skb_queue_is_last(list, skb)) + next = skb_queue_next(list, skb); __skb_unlink(skb, list); __kfree_skb(skb); @@ -4503,6 +4520,9 @@ static struct sk_buff *tcp_collapse_one(struct sock *sk, struct sk_buff *skb, /* Collapse contiguous sequence of skbs head..tail with * sequence numbers start..end. + * + * If tail is NULL, this means until the end of the list. + * * Segments with FIN/SYN are not collapsed (only because this * simplifies code) */ @@ -4511,15 +4531,23 @@ tcp_collapse(struct sock *sk, struct sk_buff_head *list, struct sk_buff *head, struct sk_buff *tail, u32 start, u32 end) { - struct sk_buff *skb; + struct sk_buff *skb, *n; + bool end_of_skbs; /* First, check that queue is collapsible and find * the point where collapsing can be useful. */ - for (skb = head; skb != tail;) { + skb = head; +restart: + end_of_skbs = true; + skb_queue_walk_from_safe(list, skb, n) { + if (skb == tail) + break; /* No new bits? It is possible on ofo queue. */ if (!before(start, TCP_SKB_CB(skb)->end_seq)) { skb = tcp_collapse_one(sk, skb, list); - continue; + if (!skb) + break; + goto restart; } /* The first skb to collapse is: @@ -4529,16 +4557,24 @@ tcp_collapse(struct sock *sk, struct sk_buff_head *list, */ if (!tcp_hdr(skb)->syn && !tcp_hdr(skb)->fin && (tcp_win_from_space(skb->truesize) > skb->len || - before(TCP_SKB_CB(skb)->seq, start) || - (skb->next != tail && - TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb->next)->seq))) + before(TCP_SKB_CB(skb)->seq, start))) { + end_of_skbs = false; break; + } + + if (!skb_queue_is_last(list, skb)) { + struct sk_buff *next = skb_queue_next(list, skb); + if (next != tail && + TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(next)->seq) { + end_of_skbs = false; + break; + } + } /* Decided to skip this, advance start seq. */ start = TCP_SKB_CB(skb)->end_seq; - skb = skb->next; } - if (skb == tail || tcp_hdr(skb)->syn || tcp_hdr(skb)->fin) + if (end_of_skbs || tcp_hdr(skb)->syn || tcp_hdr(skb)->fin) return; while (before(start, end)) { @@ -4583,7 +4619,8 @@ tcp_collapse(struct sock *sk, struct sk_buff_head *list, } if (!before(start, TCP_SKB_CB(skb)->end_seq)) { skb = tcp_collapse_one(sk, skb, list); - if (skb == tail || + if (!skb || + skb == tail || tcp_hdr(skb)->syn || tcp_hdr(skb)->fin) return; @@ -4610,17 +4647,21 @@ static void tcp_collapse_ofo_queue(struct sock *sk) head = skb; for (;;) { - skb = skb->next; + struct sk_buff *next = NULL; + + if (!skb_queue_is_last(&tp->out_of_order_queue, skb)) + next = skb_queue_next(&tp->out_of_order_queue, skb); + skb = next; /* Segment is terminated when we see gap or when * we are at the end of all the queue. */ - if (skb == (struct sk_buff *)&tp->out_of_order_queue || + if (!skb || after(TCP_SKB_CB(skb)->seq, end) || before(TCP_SKB_CB(skb)->end_seq, start)) { tcp_collapse(sk, &tp->out_of_order_queue, head, skb, start, end); head = skb; - if (skb == (struct sk_buff *)&tp->out_of_order_queue) + if (!skb) break; /* Start new segment */ start = TCP_SKB_CB(skb)->seq; @@ -4681,10 +4722,11 @@ static int tcp_prune_queue(struct sock *sk) tp->rcv_ssthresh = min(tp->rcv_ssthresh, 4U * tp->advmss); tcp_collapse_ofo_queue(sk); - tcp_collapse(sk, &sk->sk_receive_queue, - sk->sk_receive_queue.next, - (struct sk_buff *)&sk->sk_receive_queue, - tp->copied_seq, tp->rcv_nxt); + if (!skb_queue_empty(&sk->sk_receive_queue)) + tcp_collapse(sk, &sk->sk_receive_queue, + skb_peek(&sk->sk_receive_queue), + NULL, + tp->copied_seq, tp->rcv_nxt); sk_mem_reclaim(sk); if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf) diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 5d427f86b414..5a1ca2698c88 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -546,7 +546,7 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) if (th->rst) return; - if (skb->rtable->rt_type != RTN_LOCAL) + if (skb_rtable(skb)->rt_type != RTN_LOCAL) return; /* Swap the send and the receive. */ @@ -590,7 +590,7 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) arg.csumoffset = offsetof(struct tcphdr, check) / 2; arg.flags = (sk && inet_sk(sk)->transparent) ? IP_REPLY_ARG_NOSRCCHECK : 0; - net = dev_net(skb->dst->dev); + net = dev_net(skb_dst(skb)->dev); ip_send_reply(net->ipv4.tcp_sock, skb, &arg, arg.iov[0].iov_len); @@ -617,7 +617,7 @@ static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack, ]; } rep; struct ip_reply_arg arg; - struct net *net = dev_net(skb->dst->dev); + struct net *net = dev_net(skb_dst(skb)->dev); memset(&rep.th, 0, sizeof(struct tcphdr)); memset(&arg, 0, sizeof(arg)); @@ -1185,7 +1185,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) #endif /* Never answer to SYNs send to broadcast or multicast */ - if (skb->rtable->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) + if (skb_rtable(skb)->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) goto drop; /* TW buckets are converted to open requests without @@ -1593,7 +1593,7 @@ process: #endif { if (!tcp_prequeue(sk, skb)) - ret = tcp_v4_do_rcv(sk, skb); + ret = tcp_v4_do_rcv(sk, skb); } } else sk_add_backlog(sk, skb); @@ -2343,7 +2343,7 @@ void tcp4_proc_exit(void) struct sk_buff **tcp4_gro_receive(struct sk_buff **head, struct sk_buff *skb) { - struct iphdr *iph = ip_hdr(skb); + struct iphdr *iph = skb_gro_network_header(skb); switch (skb->ip_summed) { case CHECKSUM_COMPLETE: diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 59aec609cec6..416fc4c2e7eb 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -288,7 +288,7 @@ static inline void TCP_ECN_send_syn(struct sock *sk, struct sk_buff *skb) struct tcp_sock *tp = tcp_sk(sk); tp->ecn_flags = 0; - if (sysctl_tcp_ecn) { + if (sysctl_tcp_ecn == 1) { TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_ECE | TCPCB_FLAG_CWR; tp->ecn_flags = TCP_ECN_OK; } @@ -2202,7 +2202,7 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst, /* Reserve space for headers. */ skb_reserve(skb, MAX_TCP_HEADER); - skb->dst = dst_clone(dst); + skb_dst_set(skb, dst_clone(dst)); mss = dst_metric(dst, RTAX_ADVMSS); if (tp->rx_opt.user_mss && tp->rx_opt.user_mss < mss) diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 7a1d1ce22e66..80e3812837ad 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -328,7 +328,7 @@ static inline struct sock *__udp4_lib_lookup_skb(struct sk_buff *skb, if (unlikely(sk = skb_steal_sock(skb))) return sk; else - return __udp4_lib_lookup(dev_net(skb->dst->dev), iph->saddr, sport, + return __udp4_lib_lookup(dev_net(skb_dst(skb)->dev), iph->saddr, sport, iph->daddr, dport, inet_iif(skb), udptable); } @@ -840,7 +840,8 @@ int udp_ioctl(struct sock *sk, int cmd, unsigned long arg) switch (cmd) { case SIOCOUTQ: { - int amount = atomic_read(&sk->sk_wmem_alloc); + int amount = sk_wmem_alloc_get(sk); + return put_user(amount, (int __user *)arg); } @@ -1237,7 +1238,7 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, struct sock *sk; struct udphdr *uh; unsigned short ulen; - struct rtable *rt = (struct rtable*)skb->dst; + struct rtable *rt = skb_rtable(skb); __be32 saddr, daddr; struct net *net = dev_net(skb->dev); @@ -1721,8 +1722,8 @@ static void udp4_format_sock(struct sock *sp, struct seq_file *f, seq_printf(f, "%4d: %08X:%04X %08X:%04X" " %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), + sk_wmem_alloc_get(sp), + sk_rmem_alloc_get(sp), 0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp), atomic_read(&sp->sk_refcnt), sp, atomic_read(&sp->sk_drops), len); diff --git a/net/ipv4/xfrm4_input.c b/net/ipv4/xfrm4_input.c index 4ec2162a437e..f9f922a0ba88 100644 --- a/net/ipv4/xfrm4_input.c +++ b/net/ipv4/xfrm4_input.c @@ -23,7 +23,7 @@ int xfrm4_extract_input(struct xfrm_state *x, struct sk_buff *skb) static inline int xfrm4_rcv_encap_finish(struct sk_buff *skb) { - if (skb->dst == NULL) { + if (skb_dst(skb) == NULL) { const struct iphdr *iph = ip_hdr(skb); if (ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, diff --git a/net/ipv4/xfrm4_mode_tunnel.c b/net/ipv4/xfrm4_mode_tunnel.c index 7135279f3f84..3444f3b34eca 100644 --- a/net/ipv4/xfrm4_mode_tunnel.c +++ b/net/ipv4/xfrm4_mode_tunnel.c @@ -28,7 +28,7 @@ static inline void ipip_ecn_decapsulate(struct sk_buff *skb) */ static int xfrm4_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) { - struct dst_entry *dst = skb->dst; + struct dst_entry *dst = skb_dst(skb); struct iphdr *top_iph; int flags; @@ -41,7 +41,7 @@ static int xfrm4_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) top_iph->ihl = 5; top_iph->version = 4; - top_iph->protocol = xfrm_af2proto(skb->dst->ops->family); + top_iph->protocol = xfrm_af2proto(skb_dst(skb)->ops->family); /* DS disclosed */ top_iph->tos = INET_ECN_encapsulate(XFRM_MODE_SKB_CB(skb)->tos, diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c index 8c3180adddbf..c908bd99bcba 100644 --- a/net/ipv4/xfrm4_output.c +++ b/net/ipv4/xfrm4_output.c @@ -29,7 +29,7 @@ static int xfrm4_tunnel_check_size(struct sk_buff *skb) if (!(ip_hdr(skb)->frag_off & htons(IP_DF)) || skb->local_df) goto out; - dst = skb->dst; + dst = skb_dst(skb); mtu = dst_mtu(dst); if (skb->len > mtu) { icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu)); @@ -72,7 +72,7 @@ EXPORT_SYMBOL(xfrm4_prepare_output); static int xfrm4_output_finish(struct sk_buff *skb) { #ifdef CONFIG_NETFILTER - if (!skb->dst->xfrm) { + if (!skb_dst(skb)->xfrm) { IPCB(skb)->flags |= IPSKB_REROUTED; return dst_output(skb); } @@ -87,6 +87,6 @@ static int xfrm4_output_finish(struct sk_buff *skb) int xfrm4_output(struct sk_buff *skb) { return NF_HOOK_COND(PF_INET, NF_INET_POST_ROUTING, skb, - NULL, skb->dst->dev, xfrm4_output_finish, + NULL, skb_dst(skb)->dev, xfrm4_output_finish, !(IPCB(skb)->flags & IPSKB_REROUTED)); } diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig index ca8cb326d1d2..ead6c7a42f44 100644 --- a/net/ipv6/Kconfig +++ b/net/ipv6/Kconfig @@ -168,7 +168,7 @@ config IPV6_SIT into IPv4 packets. This is useful if you want to connect two IPv6 networks over an IPv4-only path. - Saying M here will produce a module called sit.ko. If unsure, say Y. + Saying M here will produce a module called sit. If unsure, say Y. config IPV6_NDISC_NODETYPE bool diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index a8218bc1806a..8c1e86afbbf5 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -503,7 +503,7 @@ static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int old) return 0; if (!rtnl_trylock()) - return -ERESTARTSYS; + return restart_syscall(); if (p == &net->ipv6.devconf_all->forwarding) { __s32 newf = net->ipv6.devconf_all->forwarding; @@ -591,7 +591,6 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, { struct inet6_ifaddr *ifa = NULL; struct rt6_info *rt; - struct net *net = dev_net(idev->dev); int hash; int err = 0; int addr_type = ipv6_addr_type(addr); @@ -608,7 +607,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, goto out2; } - if (idev->cnf.disable_ipv6 || net->ipv6.devconf_all->disable_ipv6) { + if (idev->cnf.disable_ipv6) { err = -EACCES; goto out2; } @@ -1520,6 +1519,8 @@ static int addrconf_ifid_infiniband(u8 *eui, struct net_device *dev) int __ipv6_isatap_ifid(u8 *eui, __be32 addr) { + if (addr == 0) + return -1; eui[0] = (ipv4_is_zeronet(addr) || ipv4_is_private_10(addr) || ipv4_is_loopback(addr) || ipv4_is_linklocal_169(addr) || ipv4_is_private_172(addr) || ipv4_is_test_192(addr) || @@ -1750,6 +1751,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len) __u32 prefered_lft; int addr_type; struct inet6_dev *in6_dev; + struct net *net = dev_net(dev); pinfo = (struct prefix_info *) opt; @@ -1807,7 +1809,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len) if (addrconf_finite_timeout(rt_expires)) rt_expires *= HZ; - rt = rt6_lookup(dev_net(dev), &pinfo->prefix, NULL, + rt = rt6_lookup(net, &pinfo->prefix, NULL, dev->ifindex, 1); if (rt && addrconf_is_prefix_route(rt)) { @@ -1844,7 +1846,6 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len) struct inet6_ifaddr * ifp; struct in6_addr addr; int create = 0, update_lft = 0; - struct net *net = dev_net(dev); if (pinfo->prefix_len == 64) { memcpy(&addr, &pinfo->prefix, 8); @@ -2765,7 +2766,7 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags) spin_unlock_bh(&ifp->lock); read_unlock_bh(&idev->lock); /* - * If the defice is not ready: + * If the device is not ready: * - keep it tentative if it is a permanent address. * - otherwise, kill it. */ @@ -3986,6 +3987,75 @@ static int addrconf_sysctl_forward_strategy(ctl_table *table, return addrconf_fixup_forwarding(table, valp, val); } +static void dev_disable_change(struct inet6_dev *idev) +{ + if (!idev || !idev->dev) + return; + + if (idev->cnf.disable_ipv6) + addrconf_notify(NULL, NETDEV_DOWN, idev->dev); + else + addrconf_notify(NULL, NETDEV_UP, idev->dev); +} + +static void addrconf_disable_change(struct net *net, __s32 newf) +{ + struct net_device *dev; + struct inet6_dev *idev; + + read_lock(&dev_base_lock); + for_each_netdev(net, dev) { + rcu_read_lock(); + idev = __in6_dev_get(dev); + if (idev) { + int changed = (!idev->cnf.disable_ipv6) ^ (!newf); + idev->cnf.disable_ipv6 = newf; + if (changed) + dev_disable_change(idev); + } + rcu_read_unlock(); + } + read_unlock(&dev_base_lock); +} + +static int addrconf_disable_ipv6(struct ctl_table *table, int *p, int old) +{ + struct net *net; + + net = (struct net *)table->extra2; + + if (p == &net->ipv6.devconf_dflt->disable_ipv6) + return 0; + + if (!rtnl_trylock()) + return restart_syscall(); + + if (p == &net->ipv6.devconf_all->disable_ipv6) { + __s32 newf = net->ipv6.devconf_all->disable_ipv6; + net->ipv6.devconf_dflt->disable_ipv6 = newf; + addrconf_disable_change(net, newf); + } else if ((!*p) ^ (!old)) + dev_disable_change((struct inet6_dev *)table->extra1); + + rtnl_unlock(); + return 0; +} + +static +int addrconf_sysctl_disable(ctl_table *ctl, int write, struct file * filp, + void __user *buffer, size_t *lenp, loff_t *ppos) +{ + int *valp = ctl->data; + int val = *valp; + int ret; + + ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos); + + if (write) + ret = addrconf_disable_ipv6(ctl, valp, val); + return ret; +} + static struct addrconf_sysctl_table { struct ctl_table_header *sysctl_header; @@ -4223,7 +4293,8 @@ static struct addrconf_sysctl_table .data = &ipv6_devconf.disable_ipv6, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = proc_dointvec, + .proc_handler = addrconf_sysctl_disable, + .strategy = sysctl_intvec, }, { .ctl_name = CTL_UNNUMBERED, @@ -4344,6 +4415,10 @@ static int addrconf_init_net(struct net *net) dflt = kmemdup(dflt, sizeof(ipv6_devconf_dflt), GFP_KERNEL); if (dflt == NULL) goto err_alloc_dflt; + } else { + /* these will be inherited by all namespaces */ + dflt->autoconf = ipv6_defaults.autoconf; + dflt->disable_ipv6 = ipv6_defaults.disable_ipv6; } net->ipv6.devconf_all = all; diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 61f55386a236..85b3d0036afd 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -72,9 +72,21 @@ MODULE_LICENSE("GPL"); static struct list_head inetsw6[SOCK_MAX]; static DEFINE_SPINLOCK(inetsw6_lock); -static int disable_ipv6 = 0; -module_param_named(disable, disable_ipv6, int, 0); -MODULE_PARM_DESC(disable, "Disable IPv6 such that it is non-functional"); +struct ipv6_params ipv6_defaults = { + .disable_ipv6 = 0, + .autoconf = 1, +}; + +static int disable_ipv6_mod = 0; + +module_param_named(disable, disable_ipv6_mod, int, 0444); +MODULE_PARM_DESC(disable, "Disable IPv6 module such that it is non-functional"); + +module_param_named(disable_ipv6, ipv6_defaults.disable_ipv6, int, 0444); +MODULE_PARM_DESC(disable_ipv6, "Disable IPv6 on all interfaces"); + +module_param_named(autoconf, ipv6_defaults.autoconf, int, 0444); +MODULE_PARM_DESC(autoconf, "Enable IPv6 address autoconfiguration on all interfaces"); static __inline__ struct ipv6_pinfo *inet6_sk_generic(struct sock *sk) { @@ -817,13 +829,20 @@ static struct sk_buff **ipv6_gro_receive(struct sk_buff **head, struct sk_buff *p; struct ipv6hdr *iph; unsigned int nlen; + unsigned int hlen; + unsigned int off; int flush = 1; int proto; __wsum csum; - iph = skb_gro_header(skb, sizeof(*iph)); - if (unlikely(!iph)) - goto out; + off = skb_gro_offset(skb); + hlen = off + sizeof(*iph); + iph = skb_gro_header_fast(skb, off); + if (skb_gro_header_hard(skb, hlen)) { + iph = skb_gro_header_slow(skb, hlen, off); + if (unlikely(!iph)) + goto out; + } skb_gro_pull(skb, sizeof(*iph)); skb_set_transport_header(skb, skb_gro_offset(skb)); @@ -1031,7 +1050,7 @@ static int __init inet6_init(void) for(r = &inetsw6[0]; r < &inetsw6[SOCK_MAX]; ++r) INIT_LIST_HEAD(r); - if (disable_ipv6) { + if (disable_ipv6_mod) { printk(KERN_INFO "IPv6: Loaded, but administratively disabled, " "reboot required to enable\n"); @@ -1220,7 +1239,7 @@ module_init(inet6_init); static void __exit inet6_exit(void) { - if (disable_ipv6) + if (disable_ipv6_mod) return; /* First of all disallow new sockets creation. */ diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index 52449f7a1b71..86f42a288c4b 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c @@ -405,7 +405,7 @@ out: } static void ah6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, - int type, int code, int offset, __be32 info) + u8 type, u8 code, int offset, __be32 info) { struct net *net = dev_net(skb->dev); struct ipv6hdr *iph = (struct ipv6hdr*)skb->data; diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index c2f250150db1..678bb95b1525 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c @@ -354,7 +354,7 @@ static u32 esp6_get_mtu(struct xfrm_state *x, int mtu) } static void esp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, - int type, int code, int offset, __be32 info) + u8 type, u8 code, int offset, __be32 info) { struct net *net = dev_net(skb->dev); struct ipv6hdr *iph = (struct ipv6hdr*)skb->data; diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index 1c7f400a3cfe..4aae658e5501 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c @@ -277,7 +277,7 @@ static int ipv6_destopt_rcv(struct sk_buff *skb) if (!pskb_may_pull(skb, skb_transport_offset(skb) + 8) || !pskb_may_pull(skb, (skb_transport_offset(skb) + ((skb_transport_header(skb)[1] + 1) << 3)))) { - IP6_INC_STATS_BH(dev_net(skb->dst->dev), ip6_dst_idev(skb->dst), + IP6_INC_STATS_BH(dev_net(skb_dst(skb)->dev), ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_INHDRERRORS); kfree_skb(skb); return -1; @@ -288,7 +288,7 @@ static int ipv6_destopt_rcv(struct sk_buff *skb) dstbuf = opt->dst1; #endif - dst = dst_clone(skb->dst); + dst = dst_clone(skb_dst(skb)); if (ip6_parse_tlv(tlvprocdestopt_lst, skb)) { dst_release(dst); skb->transport_header += (skb_transport_header(skb)[1] + 1) << 3; @@ -333,7 +333,7 @@ static int ipv6_rthdr_rcv(struct sk_buff *skb) if (!pskb_may_pull(skb, skb_transport_offset(skb) + 8) || !pskb_may_pull(skb, (skb_transport_offset(skb) + ((skb_transport_header(skb)[1] + 1) << 3)))) { - IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst), + IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_INHDRERRORS); kfree_skb(skb); return -1; @@ -343,7 +343,7 @@ static int ipv6_rthdr_rcv(struct sk_buff *skb) if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr) || skb->pkt_type != PACKET_HOST) { - IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst), + IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_INADDRERRORS); kfree_skb(skb); return -1; @@ -358,7 +358,7 @@ looped_back: * processed by own */ if (!addr) { - IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst), + IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_INADDRERRORS); kfree_skb(skb); return -1; @@ -384,7 +384,7 @@ looped_back: goto unknown_rh; /* Silently discard invalid RTH type 2 */ if (hdr->hdrlen != 2 || hdr->segments_left != 1) { - IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst), + IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_INHDRERRORS); kfree_skb(skb); return -1; @@ -403,7 +403,7 @@ looped_back: n = hdr->hdrlen >> 1; if (hdr->segments_left > n) { - IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst), + IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_INHDRERRORS); icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, ((&hdr->segments_left) - @@ -417,7 +417,7 @@ looped_back: if (skb_cloned(skb)) { /* the copy is a forwarded packet */ if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) { - IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst), + IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_OUTDISCARDS); kfree_skb(skb); return -1; @@ -440,13 +440,13 @@ looped_back: if (xfrm6_input_addr(skb, (xfrm_address_t *)addr, (xfrm_address_t *)&ipv6_hdr(skb)->saddr, IPPROTO_ROUTING) < 0) { - IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst), + IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_INADDRERRORS); kfree_skb(skb); return -1; } - if (!ipv6_chk_home_addr(dev_net(skb->dst->dev), addr)) { - IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst), + if (!ipv6_chk_home_addr(dev_net(skb_dst(skb)->dev), addr)) { + IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_INADDRERRORS); kfree_skb(skb); return -1; @@ -458,7 +458,7 @@ looped_back: } if (ipv6_addr_is_multicast(addr)) { - IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst), + IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_INADDRERRORS); kfree_skb(skb); return -1; @@ -468,17 +468,17 @@ looped_back: ipv6_addr_copy(addr, &ipv6_hdr(skb)->daddr); ipv6_addr_copy(&ipv6_hdr(skb)->daddr, &daddr); - dst_release(xchg(&skb->dst, NULL)); + skb_dst_drop(skb); ip6_route_input(skb); - if (skb->dst->error) { + if (skb_dst(skb)->error) { skb_push(skb, skb->data - skb_network_header(skb)); dst_input(skb); return -1; } - if (skb->dst->dev->flags&IFF_LOOPBACK) { + if (skb_dst(skb)->dev->flags&IFF_LOOPBACK) { if (ipv6_hdr(skb)->hop_limit <= 1) { - IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst), + IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_INHDRERRORS); icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, 0, skb->dev); @@ -494,7 +494,7 @@ looped_back: return -1; unknown_rh: - IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst), IPSTATS_MIB_INHDRERRORS); + IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_INHDRERRORS); icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->type) - skb_network_header(skb)); return -1; @@ -552,11 +552,11 @@ void ipv6_exthdrs_exit(void) **********************************/ /* - * Note: we cannot rely on skb->dst before we assign it in ip6_route_input(). + * Note: we cannot rely on skb_dst(skb) before we assign it in ip6_route_input(). */ static inline struct inet6_dev *ipv6_skb_idev(struct sk_buff *skb) { - return skb->dst ? ip6_dst_idev(skb->dst) : __in6_dev_get(skb->dev); + return skb_dst(skb) ? ip6_dst_idev(skb_dst(skb)) : __in6_dev_get(skb->dev); } /* Router Alert as of RFC 2711 */ @@ -581,7 +581,7 @@ static int ipv6_hop_jumbo(struct sk_buff *skb, int optoff) { const unsigned char *nh = skb_network_header(skb); u32 pkt_len; - struct net *net = dev_net(skb->dst->dev); + struct net *net = dev_net(skb_dst(skb)->dev); if (nh[optoff + 1] != 4 || (optoff & 3) != 2) { LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n", diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c index f5de3f9dc692..00a7a5e4ac97 100644 --- a/net/ipv6/fib6_rules.c +++ b/net/ipv6/fib6_rules.c @@ -151,7 +151,7 @@ static const struct nla_policy fib6_rule_policy[FRA_MAX+1] = { }; static int fib6_rule_configure(struct fib_rule *rule, struct sk_buff *skb, - struct nlmsghdr *nlh, struct fib_rule_hdr *frh, + struct fib_rule_hdr *frh, struct nlattr **tb) { int err = -EINVAL; @@ -211,7 +211,7 @@ static int fib6_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh, } static int fib6_rule_fill(struct fib_rule *rule, struct sk_buff *skb, - struct nlmsghdr *nlh, struct fib_rule_hdr *frh) + struct fib_rule_hdr *frh) { struct fib6_rule *rule6 = (struct fib6_rule *) rule; diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 36dff8807183..eab62a7a8f06 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -117,7 +117,7 @@ static __inline__ void icmpv6_xmit_unlock(struct sock *sk) /* * Slightly more convenient version of icmpv6_send. */ -void icmpv6_param_prob(struct sk_buff *skb, int code, int pos) +void icmpv6_param_prob(struct sk_buff *skb, u8 code, int pos) { icmpv6_send(skb, ICMPV6_PARAMPROB, code, pos, skb->dev); kfree_skb(skb); @@ -161,7 +161,7 @@ static int is_ineligible(struct sk_buff *skb) /* * Check the ICMP output rate limit */ -static inline int icmpv6_xrlim_allow(struct sock *sk, int type, +static inline int icmpv6_xrlim_allow(struct sock *sk, u8 type, struct flowi *fl) { struct dst_entry *dst; @@ -305,7 +305,7 @@ static inline void mip6_addr_swap(struct sk_buff *skb) {} /* * Send an ICMP message in response to a packet in error */ -void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, +void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info, struct net_device *dev) { struct net *net = dev_net(skb->dev); @@ -590,7 +590,7 @@ out: icmpv6_xmit_unlock(sk); } -static void icmpv6_notify(struct sk_buff *skb, int type, int code, __be32 info) +static void icmpv6_notify(struct sk_buff *skb, u8 type, u8 code, __be32 info) { struct inet6_protocol *ipprot; int inner_offset; @@ -643,7 +643,7 @@ static int icmpv6_rcv(struct sk_buff *skb) struct in6_addr *saddr, *daddr; struct ipv6hdr *orig_hdr; struct icmp6hdr *hdr; - int type; + u8 type; if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) { struct sec_path *sp = skb_sec_path(skb); @@ -914,7 +914,7 @@ static const struct icmp6_err { }, }; -int icmpv6_err_convert(int type, int code, int *err) +int icmpv6_err_convert(u8 type, u8 code, int *err) { int fatal = 0; diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c index 3c3732d50c1a..cc4797dd8325 100644 --- a/net/ipv6/inet6_connection_sock.c +++ b/net/ipv6/inet6_connection_sock.c @@ -228,7 +228,7 @@ int inet6_csk_xmit(struct sk_buff *skb, int ipfragok) __inet6_csk_dst_store(sk, dst, NULL, NULL); } - skb->dst = dst_clone(dst); + skb_dst_set(skb, dst_clone(dst)); /* Restore final destination back after routing done */ ipv6_addr_copy(&fl.fl6_dst, &np->daddr); diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index 8f04bd9da274..c3a07d75b5f5 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c @@ -48,7 +48,7 @@ inline int ip6_rcv_finish( struct sk_buff *skb) { - if (skb->dst == NULL) + if (skb_dst(skb) == NULL) ip6_route_input(skb); return dst_input(skb); @@ -70,7 +70,7 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt idev = __in6_dev_get(skb->dev); - IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INRECEIVES); + IP6_UPD_PO_STATS_BH(net, idev, IPSTATS_MIB_IN, skb->len); if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL || !idev || unlikely(idev->cnf.disable_ipv6)) { @@ -91,7 +91,7 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt * arrived via the sending interface (ethX), because of the * nature of scoping architecture. --yoshfuji */ - IP6CB(skb)->iif = skb->dst ? ip6_dst_idev(skb->dst)->dev->ifindex : dev->ifindex; + IP6CB(skb)->iif = skb_dst(skb) ? ip6_dst_idev(skb_dst(skb))->dev->ifindex : dev->ifindex; if (unlikely(!pskb_may_pull(skb, sizeof(*hdr)))) goto err; @@ -161,7 +161,7 @@ static int ip6_input_finish(struct sk_buff *skb) int nexthdr, raw; u8 hash; struct inet6_dev *idev; - struct net *net = dev_net(skb->dst->dev); + struct net *net = dev_net(skb_dst(skb)->dev); /* * Parse extension headers @@ -169,7 +169,7 @@ static int ip6_input_finish(struct sk_buff *skb) rcu_read_lock(); resubmit: - idev = ip6_dst_idev(skb->dst); + idev = ip6_dst_idev(skb_dst(skb)); if (!pskb_pull(skb, skb_transport_offset(skb))) goto discard; nhoff = IP6CB(skb)->nhoff; @@ -242,8 +242,9 @@ int ip6_mc_input(struct sk_buff *skb) struct ipv6hdr *hdr; int deliver; - IP6_INC_STATS_BH(dev_net(skb->dst->dev), - ip6_dst_idev(skb->dst), IPSTATS_MIB_INMCASTPKTS); + IP6_UPD_PO_STATS_BH(dev_net(skb_dst(skb)->dev), + ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_INMCAST, + skb->len); hdr = ipv6_hdr(skb); deliver = ipv6_chk_mcast_addr(skb->dev, &hdr->daddr, NULL); diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 9fb49c3b518a..7c76e3d18215 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -78,7 +78,7 @@ int __ip6_local_out(struct sk_buff *skb) len = 0; ipv6_hdr(skb)->payload_len = htons(len); - return nf_hook(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, skb->dst->dev, + return nf_hook(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, skb_dst(skb)->dev, dst_output); } @@ -96,7 +96,7 @@ EXPORT_SYMBOL_GPL(ip6_local_out); static int ip6_output_finish(struct sk_buff *skb) { - struct dst_entry *dst = skb->dst; + struct dst_entry *dst = skb_dst(skb); if (dst->hh) return neigh_hh_output(dst->hh, skb); @@ -117,7 +117,7 @@ static int ip6_dev_loopback_xmit(struct sk_buff *newskb) __skb_pull(newskb, skb_network_offset(newskb)); newskb->pkt_type = PACKET_LOOPBACK; newskb->ip_summed = CHECKSUM_UNNECESSARY; - WARN_ON(!newskb->dst); + WARN_ON(!skb_dst(newskb)); netif_rx(newskb); return 0; @@ -126,7 +126,7 @@ static int ip6_dev_loopback_xmit(struct sk_buff *newskb) static int ip6_output2(struct sk_buff *skb) { - struct dst_entry *dst = skb->dst; + struct dst_entry *dst = skb_dst(skb); struct net_device *dev = dst->dev; skb->protocol = htons(ETH_P_IPV6); @@ -134,7 +134,7 @@ static int ip6_output2(struct sk_buff *skb) if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr)) { struct ipv6_pinfo* np = skb->sk ? inet6_sk(skb->sk) : NULL; - struct inet6_dev *idev = ip6_dst_idev(skb->dst); + struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb)); if (!(dev->flags & IFF_LOOPBACK) && (!np || np->mc_loop) && ((mroute6_socket(dev_net(dev)) && @@ -159,7 +159,8 @@ static int ip6_output2(struct sk_buff *skb) } } - IP6_INC_STATS(dev_net(dev), idev, IPSTATS_MIB_OUTMCASTPKTS); + IP6_UPD_PO_STATS(dev_net(dev), idev, IPSTATS_MIB_OUTMCAST, + skb->len); } return NF_HOOK(PF_INET6, NF_INET_POST_ROUTING, skb, NULL, skb->dev, @@ -171,21 +172,21 @@ static inline int ip6_skb_dst_mtu(struct sk_buff *skb) struct ipv6_pinfo *np = skb->sk ? inet6_sk(skb->sk) : NULL; return (np && np->pmtudisc == IPV6_PMTUDISC_PROBE) ? - skb->dst->dev->mtu : dst_mtu(skb->dst); + skb_dst(skb)->dev->mtu : dst_mtu(skb_dst(skb)); } int ip6_output(struct sk_buff *skb) { - struct inet6_dev *idev = ip6_dst_idev(skb->dst); + struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb)); if (unlikely(idev->cnf.disable_ipv6)) { - IP6_INC_STATS(dev_net(skb->dst->dev), idev, + IP6_INC_STATS(dev_net(skb_dst(skb)->dev), idev, IPSTATS_MIB_OUTDISCARDS); kfree_skb(skb); return 0; } if ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) || - dst_allfrag(skb->dst)) + dst_allfrag(skb_dst(skb))) return ip6_fragment(skb, ip6_output2); else return ip6_output2(skb); @@ -201,7 +202,7 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, struct net *net = sock_net(sk); struct ipv6_pinfo *np = inet6_sk(sk); struct in6_addr *first_hop = &fl->fl6_dst; - struct dst_entry *dst = skb->dst; + struct dst_entry *dst = skb_dst(skb); struct ipv6hdr *hdr; u8 proto = fl->proto; int seg_len = skb->len; @@ -221,7 +222,7 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, if (skb_headroom(skb) < head_room) { struct sk_buff *skb2 = skb_realloc_headroom(skb, head_room); if (skb2 == NULL) { - IP6_INC_STATS(net, ip6_dst_idev(skb->dst), + IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_OUTDISCARDS); kfree_skb(skb); return -ENOBUFS; @@ -275,8 +276,8 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, mtu = dst_mtu(dst); if ((skb->len <= mtu) || skb->local_df || skb_is_gso(skb)) { - IP6_INC_STATS(net, ip6_dst_idev(skb->dst), - IPSTATS_MIB_OUTREQUESTS); + IP6_UPD_PO_STATS(net, ip6_dst_idev(skb_dst(skb)), + IPSTATS_MIB_OUT, skb->len); return NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, dst->dev, dst_output); } @@ -285,7 +286,7 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, printk(KERN_DEBUG "IPv6: sending pkt_too_big to self\n"); skb->dev = dst->dev; icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev); - IP6_INC_STATS(net, ip6_dst_idev(skb->dst), IPSTATS_MIB_FRAGFAILS); + IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_FRAGFAILS); kfree_skb(skb); return -EMSGSIZE; } @@ -415,7 +416,7 @@ static inline int ip6_forward_finish(struct sk_buff *skb) int ip6_forward(struct sk_buff *skb) { - struct dst_entry *dst = skb->dst; + struct dst_entry *dst = skb_dst(skb); struct ipv6hdr *hdr = ipv6_hdr(skb); struct inet6_skb_parm *opt = IP6CB(skb); struct net *net = dev_net(dst->dev); @@ -484,7 +485,7 @@ int ip6_forward(struct sk_buff *skb) IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_INDISCARDS); goto drop; } - dst = skb->dst; + dst = skb_dst(skb); /* IPv6 specs say nothing about it, but it is clear that we cannot send redirects to source routed frames. @@ -565,8 +566,8 @@ static void ip6_copy_metadata(struct sk_buff *to, struct sk_buff *from) to->pkt_type = from->pkt_type; to->priority = from->priority; to->protocol = from->protocol; - dst_release(to->dst); - to->dst = dst_clone(from->dst); + skb_dst_drop(to); + skb_dst_set(to, dst_clone(skb_dst(from))); to->dev = from->dev; to->mark = from->mark; @@ -623,7 +624,7 @@ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr) static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) { struct sk_buff *frag; - struct rt6_info *rt = (struct rt6_info*)skb->dst; + struct rt6_info *rt = (struct rt6_info*)skb_dst(skb); struct ipv6_pinfo *np = skb->sk ? inet6_sk(skb->sk) : NULL; struct ipv6hdr *tmp_hdr; struct frag_hdr *fh; @@ -631,7 +632,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) __be32 frag_id = 0; int ptr, offset = 0, err=0; u8 *prevhdr, nexthdr = 0; - struct net *net = dev_net(skb->dst->dev); + struct net *net = dev_net(skb_dst(skb)->dev); hlen = ip6_find_1stfragopt(skb, &prevhdr); nexthdr = *prevhdr; @@ -643,9 +644,9 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) * check should be redundant, but it's free.) */ if (!skb->local_df) { - skb->dev = skb->dst->dev; + skb->dev = skb_dst(skb)->dev; icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev); - IP6_INC_STATS(net, ip6_dst_idev(skb->dst), + IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_FRAGFAILS); kfree_skb(skb); return -EMSGSIZE; @@ -657,7 +658,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) } mtu -= hlen + sizeof(struct frag_hdr); - if (skb_shinfo(skb)->frag_list) { + if (skb_has_frags(skb)) { int first_len = skb_pagelen(skb); int truesizes = 0; @@ -666,7 +667,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) skb_cloned(skb)) goto slow_path; - for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next) { + skb_walk_frags(skb, frag) { /* Correct geometry. */ if (frag->len > mtu || ((frag->len & 7) && frag->next) || @@ -679,7 +680,6 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) BUG_ON(frag->sk); if (skb->sk) { - sock_hold(skb->sk); frag->sk = skb->sk; frag->destructor = sock_wfree; truesizes += frag->truesize; @@ -689,13 +689,13 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) err = 0; offset = 0; frag = skb_shinfo(skb)->frag_list; - skb_shinfo(skb)->frag_list = NULL; + skb_frag_list_init(skb); /* BUILD HEADER */ *prevhdr = NEXTHDR_FRAGMENT; tmp_hdr = kmemdup(skb_network_header(skb), hlen, GFP_ATOMIC); if (!tmp_hdr) { - IP6_INC_STATS(net, ip6_dst_idev(skb->dst), + IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_FRAGFAILS); return -ENOMEM; } @@ -808,7 +808,7 @@ slow_path: if ((frag = alloc_skb(len+hlen+sizeof(struct frag_hdr)+LL_ALLOCATED_SPACE(rt->u.dst.dev), GFP_ATOMIC)) == NULL) { NETDEBUG(KERN_INFO "IPv6: frag: no memory for new fragment!\n"); - IP6_INC_STATS(net, ip6_dst_idev(skb->dst), + IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_FRAGFAILS); err = -ENOMEM; goto fail; @@ -872,16 +872,16 @@ slow_path: if (err) goto fail; - IP6_INC_STATS(net, ip6_dst_idev(skb->dst), + IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_FRAGCREATES); } - IP6_INC_STATS(net, ip6_dst_idev(skb->dst), + IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_FRAGOKS); kfree_skb(skb); return err; fail: - IP6_INC_STATS(net, ip6_dst_idev(skb->dst), + IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_FRAGFAILS); kfree_skb(skb); return err; @@ -1515,10 +1515,10 @@ int ip6_push_pending_frames(struct sock *sk) skb->priority = sk->sk_priority; skb->mark = sk->sk_mark; - skb->dst = dst_clone(&rt->u.dst); - IP6_INC_STATS(net, rt->rt6i_idev, IPSTATS_MIB_OUTREQUESTS); + skb_dst_set(skb, dst_clone(&rt->u.dst)); + IP6_UPD_PO_STATS(net, rt->rt6i_idev, IPSTATS_MIB_OUT, skb->len); if (proto == IPPROTO_ICMPV6) { - struct inet6_dev *idev = ip6_dst_idev(skb->dst); + struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb)); ICMP6MSGOUT_INC_STATS_BH(net, idev, icmp6_hdr(skb)->icmp6_type); ICMP6_INC_STATS_BH(net, idev, ICMP6_MIB_OUTMSGS); @@ -1544,8 +1544,8 @@ void ip6_flush_pending_frames(struct sock *sk) struct sk_buff *skb; while ((skb = __skb_dequeue_tail(&sk->sk_write_queue)) != NULL) { - if (skb->dst) - IP6_INC_STATS(sock_net(sk), ip6_dst_idev(skb->dst), + if (skb_dst(skb)) + IP6_INC_STATS(sock_net(sk), ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_OUTDISCARDS); kfree_skb(skb); } diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index d994c55a5b16..51f410e7775a 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -394,13 +394,13 @@ parse_tlv_tnl_enc_lim(struct sk_buff *skb, __u8 * raw) static int ip6_tnl_err(struct sk_buff *skb, __u8 ipproto, struct inet6_skb_parm *opt, - int *type, int *code, int *msg, __u32 *info, int offset) + u8 *type, u8 *code, int *msg, __u32 *info, int offset) { struct ipv6hdr *ipv6h = (struct ipv6hdr *) skb->data; struct ip6_tnl *t; int rel_msg = 0; - int rel_type = ICMPV6_DEST_UNREACH; - int rel_code = ICMPV6_ADDR_UNREACH; + u8 rel_type = ICMPV6_DEST_UNREACH; + u8 rel_code = ICMPV6_ADDR_UNREACH; __u32 rel_info = 0; __u16 len; int err = -ENOENT; @@ -488,11 +488,11 @@ out: static int ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, - int type, int code, int offset, __be32 info) + u8 type, u8 code, int offset, __be32 info) { int rel_msg = 0; - int rel_type = type; - int rel_code = code; + u8 rel_type = type; + u8 rel_code = code; __u32 rel_info = ntohl(info); int err; struct sk_buff *skb2; @@ -532,8 +532,8 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, if (!skb2) return 0; - dst_release(skb2->dst); - skb2->dst = NULL; + skb_dst_drop(skb2); + skb_pull(skb2, offset); skb_reset_network_header(skb2); eiph = ip_hdr(skb2); @@ -560,21 +560,21 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, ip_rt_put(rt); goto out; } - skb2->dst = (struct dst_entry *)rt; + skb_dst_set(skb2, (struct dst_entry *)rt); } else { ip_rt_put(rt); if (ip_route_input(skb2, eiph->daddr, eiph->saddr, eiph->tos, skb2->dev) || - skb2->dst->dev->type != ARPHRD_TUNNEL) + skb_dst(skb2)->dev->type != ARPHRD_TUNNEL) goto out; } /* change mtu on this route */ if (rel_type == ICMP_DEST_UNREACH && rel_code == ICMP_FRAG_NEEDED) { - if (rel_info > dst_mtu(skb2->dst)) + if (rel_info > dst_mtu(skb_dst(skb2))) goto out; - skb2->dst->ops->update_pmtu(skb2->dst, rel_info); + skb_dst(skb2)->ops->update_pmtu(skb_dst(skb2), rel_info); } icmp_send(skb2, rel_type, rel_code, htonl(rel_info)); @@ -586,11 +586,11 @@ out: static int ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, - int type, int code, int offset, __be32 info) + u8 type, u8 code, int offset, __be32 info) { int rel_msg = 0; - int rel_type = type; - int rel_code = code; + u8 rel_type = type; + u8 rel_code = code; __u32 rel_info = ntohl(info); int err; @@ -606,8 +606,7 @@ ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, if (!skb2) return 0; - dst_release(skb2->dst); - skb2->dst = NULL; + skb_dst_drop(skb2); skb_pull(skb2, offset); skb_reset_network_header(skb2); @@ -720,8 +719,7 @@ static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol, skb->pkt_type = PACKET_HOST; memset(skb->cb, 0, sizeof(struct inet6_skb_parm)); skb->dev = t->dev; - dst_release(skb->dst); - skb->dst = NULL; + skb_dst_drop(skb); nf_reset(skb); dscp_ecn_decapsulate(t, ipv6h, skb); @@ -885,8 +883,8 @@ static int ip6_tnl_xmit2(struct sk_buff *skb, } if (mtu < IPV6_MIN_MTU) mtu = IPV6_MIN_MTU; - if (skb->dst) - skb->dst->ops->update_pmtu(skb->dst, mtu); + if (skb_dst(skb)) + skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu); if (skb->len > mtu) { *pmtu = mtu; err = -EMSGSIZE; @@ -910,8 +908,8 @@ static int ip6_tnl_xmit2(struct sk_buff *skb, kfree_skb(skb); skb = new_skb; } - dst_release(skb->dst); - skb->dst = dst_clone(dst); + skb_dst_drop(skb); + skb_dst_set(skb, dst_clone(dst)); skb->transport_header = skb->network_header; @@ -1100,8 +1098,8 @@ static void ip6_tnl_link_config(struct ip6_tnl *t) struct ip6_tnl_parm *p = &t->parms; struct flowi *fl = &t->fl; - memcpy(&dev->dev_addr, &p->laddr, sizeof(struct in6_addr)); - memcpy(&dev->broadcast, &p->raddr, sizeof(struct in6_addr)); + memcpy(dev->dev_addr, &p->laddr, sizeof(struct in6_addr)); + memcpy(dev->broadcast, &p->raddr, sizeof(struct in6_addr)); /* Set up flowi template */ ipv6_addr_copy(&fl->fl6_src, &p->laddr); diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 228be551e9c1..c769f155c698 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -398,10 +398,9 @@ static int pim6_rcv(struct sk_buff *skb) skb->protocol = htons(ETH_P_IPV6); skb->ip_summed = 0; skb->pkt_type = PACKET_HOST; - dst_release(skb->dst); + skb_dst_drop(skb); reg_dev->stats.rx_bytes += skb->len; reg_dev->stats.rx_packets++; - skb->dst = NULL; nf_reset(skb); netif_rx(skb); dev_put(reg_dev); @@ -442,6 +441,7 @@ static void reg_vif_setup(struct net_device *dev) dev->flags = IFF_NOARP; dev->netdev_ops = ®_vif_netdev_ops; dev->destructor = free_netdev; + dev->features |= NETIF_F_NETNS_LOCAL; } static struct net_device *ip6mr_reg_vif(struct net *net) @@ -849,7 +849,7 @@ static int ip6mr_cache_report(struct net *net, struct sk_buff *pkt, mifi_t mifi, ipv6_addr_copy(&msg->im6_src, &ipv6_hdr(pkt)->saddr); ipv6_addr_copy(&msg->im6_dst, &ipv6_hdr(pkt)->daddr); - skb->dst = dst_clone(pkt->dst); + skb_dst_set(skb, dst_clone(skb_dst(pkt))); skb->ip_summed = CHECKSUM_UNNECESSARY; } @@ -1078,7 +1078,18 @@ int __init ip6_mr_init(void) err = register_netdevice_notifier(&ip6_mr_notifier); if (err) goto reg_notif_fail; +#ifdef CONFIG_IPV6_PIMSM_V2 + if (inet6_add_protocol(&pim6_protocol, IPPROTO_PIM) < 0) { + printk(KERN_ERR "ip6_mr_init: can't add PIM protocol\n"); + err = -EAGAIN; + goto add_proto_fail; + } +#endif return 0; +#ifdef CONFIG_IPV6_PIMSM_V2 +add_proto_fail: + unregister_netdevice_notifier(&ip6_mr_notifier); +#endif reg_notif_fail: del_timer(&ipmr_expire_timer); unregister_pernet_subsys(&ip6mr_net_ops); @@ -1364,14 +1375,6 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, int if (v != net->ipv6.mroute_do_pim) { net->ipv6.mroute_do_pim = v; net->ipv6.mroute_do_assert = v; - if (net->ipv6.mroute_do_pim) - ret = inet6_add_protocol(&pim6_protocol, - IPPROTO_PIM); - else - ret = inet6_del_protocol(&pim6_protocol, - IPPROTO_PIM); - if (ret < 0) - ret = -EAGAIN; } rtnl_unlock(); return ret; @@ -1487,7 +1490,7 @@ int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg) static inline int ip6mr_forward2_finish(struct sk_buff *skb) { - IP6_INC_STATS_BH(dev_net(skb->dst->dev), ip6_dst_idev(skb->dst), + IP6_INC_STATS_BH(dev_net(skb_dst(skb)->dev), ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_OUTFORWDATAGRAMS); return dst_output(skb); } @@ -1532,8 +1535,8 @@ static int ip6mr_forward2(struct sk_buff *skb, struct mfc6_cache *c, int vifi) if (!dst) goto out_free; - dst_release(skb->dst); - skb->dst = dst; + skb_dst_drop(skb); + skb_dst_set(skb, dst); /* * RFC1584 teaches, that DVMRP/PIM router must deliver packets locally @@ -1722,7 +1725,7 @@ int ip6mr_get_route(struct net *net, { int err; struct mfc6_cache *cache; - struct rt6_info *rt = (struct rt6_info *)skb->dst; + struct rt6_info *rt = (struct rt6_info *)skb_dst(skb); read_lock(&mrt_lock); cache = ip6mr_cache_find(net, &rt->rt6i_src.addr, &rt->rt6i_dst.addr); diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c index 3a0b3be7ece5..79c172f1ff01 100644 --- a/net/ipv6/ipcomp6.c +++ b/net/ipv6/ipcomp6.c @@ -51,7 +51,7 @@ #include static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, - int type, int code, int offset, __be32 info) + u8 type, u8 code, int offset, __be32 info) { __be32 spi; struct ipv6hdr *iph = (struct ipv6hdr*)skb->data; diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index a51fb33e6864..4b264ed40a8c 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -1448,8 +1448,10 @@ static void mld_sendpack(struct sk_buff *skb) struct net *net = dev_net(skb->dev); int err; struct flowi fl; + struct dst_entry *dst; + + IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len); - IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTREQUESTS); payload_len = (skb->tail - skb->network_header) - sizeof(*pip6); mldlen = skb->tail - skb->transport_header; pip6->payload_len = htons(payload_len); @@ -1458,9 +1460,9 @@ static void mld_sendpack(struct sk_buff *skb) IPPROTO_ICMPV6, csum_partial(skb_transport_header(skb), mldlen, 0)); - skb->dst = icmp6_dst_alloc(skb->dev, NULL, &ipv6_hdr(skb)->daddr); + dst = icmp6_dst_alloc(skb->dev, NULL, &ipv6_hdr(skb)->daddr); - if (!skb->dst) { + if (!dst) { err = -ENOMEM; goto err_out; } @@ -1469,17 +1471,20 @@ static void mld_sendpack(struct sk_buff *skb) &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, skb->dev->ifindex); - err = xfrm_lookup(net, &skb->dst, &fl, NULL, 0); + err = xfrm_lookup(net, &dst, &fl, NULL, 0); + skb_dst_set(skb, dst); if (err) goto err_out; + payload_len = skb->len; + err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, skb->dev, dst_output); out: if (!err) { ICMP6MSGOUT_INC_STATS_BH(net, idev, ICMPV6_MLD2_REPORT); ICMP6_INC_STATS_BH(net, idev, ICMP6_MIB_OUTMSGS); - IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_OUTMCASTPKTS); + IP6_UPD_PO_STATS_BH(net, idev, IPSTATS_MIB_OUTMCAST, payload_len); } else IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_OUTDISCARDS); @@ -1772,11 +1777,8 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) IPV6_TLV_ROUTERALERT, 2, 0, 0, IPV6_TLV_PADN, 0 }; struct flowi fl; + struct dst_entry *dst; - rcu_read_lock(); - IP6_INC_STATS(net, __in6_dev_get(dev), - IPSTATS_MIB_OUTREQUESTS); - rcu_read_unlock(); if (type == ICMPV6_MGM_REDUCTION) snd_addr = &in6addr_linklocal_allrouters; else @@ -1786,6 +1788,11 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) payload_len = len + sizeof(ra); full_len = sizeof(struct ipv6hdr) + payload_len; + rcu_read_lock(); + IP6_UPD_PO_STATS(net, __in6_dev_get(dev), + IPSTATS_MIB_OUT, full_len); + rcu_read_unlock(); + skb = sock_alloc_send_skb(sk, LL_ALLOCATED_SPACE(dev) + full_len, 1, &err); if (skb == NULL) { @@ -1824,8 +1831,8 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) idev = in6_dev_get(skb->dev); - skb->dst = icmp6_dst_alloc(skb->dev, NULL, &ipv6_hdr(skb)->daddr); - if (!skb->dst) { + dst = icmp6_dst_alloc(skb->dev, NULL, &ipv6_hdr(skb)->daddr); + if (!dst) { err = -ENOMEM; goto err_out; } @@ -1834,17 +1841,18 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, skb->dev->ifindex); - err = xfrm_lookup(net, &skb->dst, &fl, NULL, 0); + err = xfrm_lookup(net, &dst, &fl, NULL, 0); if (err) goto err_out; + skb_dst_set(skb, dst); err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, skb->dev, dst_output); out: if (!err) { ICMP6MSGOUT_INC_STATS(net, idev, type); ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS); - IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTMCASTPKTS); + IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUTMCAST, full_len); } else IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTDISCARDS); diff --git a/net/ipv6/mip6.c b/net/ipv6/mip6.c index f995e19c87a9..f797e8c6f3b3 100644 --- a/net/ipv6/mip6.c +++ b/net/ipv6/mip6.c @@ -54,7 +54,7 @@ static inline void *mip6_padn(__u8 *data, __u8 padlen) return data + padlen; } -static inline void mip6_param_prob(struct sk_buff *skb, int code, int pos) +static inline void mip6_param_prob(struct sk_buff *skb, u8 code, int pos) { icmpv6_send(skb, ICMPV6_PARAMPROB, code, pos, skb->dev); } diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 9f061d1adbc2..9eb68e92cc18 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -465,8 +465,8 @@ struct sk_buff *ndisc_build_skb(struct net_device *dev, 1, &err); if (!skb) { ND_PRINTK0(KERN_ERR - "ICMPv6 ND: %s() failed to allocate an skb.\n", - __func__); + "ICMPv6 ND: %s() failed to allocate an skb, err=%d.\n", + __func__, err); return NULL; } @@ -530,10 +530,10 @@ void ndisc_send_skb(struct sk_buff *skb, return; } - skb->dst = dst; + skb_dst_set(skb, dst); idev = in6_dev_get(dst->dev); - IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTREQUESTS); + IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len); err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, dst->dev, dst_output); @@ -658,6 +658,7 @@ void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr, &icmp6h, NULL, send_sllao ? ND_OPT_SOURCE_LL_ADDR : 0); } +EXPORT_SYMBOL(ndisc_send_rs); static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb) @@ -1561,8 +1562,8 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, 1, &err); if (buff == NULL) { ND_PRINTK0(KERN_ERR - "ICMPv6 Redirect: %s() failed to allocate an skb.\n", - __func__); + "ICMPv6 Redirect: %s() failed to allocate an skb, err=%d.\n", + __func__, err); goto release; } @@ -1611,9 +1612,9 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, len, IPPROTO_ICMPV6, csum_partial(icmph, len, 0)); - buff->dst = dst; + skb_dst_set(buff, dst); idev = in6_dev_get(dst->dev); - IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTREQUESTS); + IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len); err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, buff, NULL, dst->dev, dst_output); if (!err) { diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c index 834cea69fb53..d5ed92b14346 100644 --- a/net/ipv6/netfilter.c +++ b/net/ipv6/netfilter.c @@ -12,7 +12,7 @@ int ip6_route_me_harder(struct sk_buff *skb) { - struct net *net = dev_net(skb->dst->dev); + struct net *net = dev_net(skb_dst(skb)->dev); struct ipv6hdr *iph = ipv6_hdr(skb); struct dst_entry *dst; struct flowi fl = { @@ -28,9 +28,15 @@ int ip6_route_me_harder(struct sk_buff *skb) #ifdef CONFIG_XFRM if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) && - xfrm_decode_session(skb, &fl, AF_INET6) == 0) - if (xfrm_lookup(net, &skb->dst, &fl, skb->sk, 0)) + xfrm_decode_session(skb, &fl, AF_INET6) == 0) { + struct dst_entry *dst2 = skb_dst(skb); + + if (xfrm_lookup(net, &dst2, &fl, skb->sk, 0)) { + skb_dst_set(skb, NULL); return -1; + } + skb_dst_set(skb, dst2); + } #endif if (dst->error) { @@ -41,9 +47,9 @@ int ip6_route_me_harder(struct sk_buff *skb) } /* Drop old route. */ - dst_release(skb->dst); + skb_dst_drop(skb); - skb->dst = dst; + skb_dst_set(skb, dst); return 0; } EXPORT_SYMBOL(ip6_route_me_harder); diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c index b693f841aeb4..1cf3f0c6a959 100644 --- a/net/ipv6/netfilter/ip6_queue.c +++ b/net/ipv6/netfilter/ip6_queue.c @@ -598,7 +598,7 @@ static int __init ip6_queue_init(void) #ifdef CONFIG_SYSCTL ipq_sysctl_header = register_sysctl_paths(net_ipv6_ctl_path, ipq_table); #endif - status = nf_register_queue_handler(PF_INET6, &nfqh); + status = nf_register_queue_handler(NFPROTO_IPV6, &nfqh); if (status < 0) { printk(KERN_ERR "ip6_queue: failed to register queue handler\n"); goto cleanup_sysctl; diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 219e165aea10..ced1f2c0cb65 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -270,8 +270,8 @@ static struct nf_loginfo trace_loginfo = { /* Mildly perf critical (only if packet tracing is on) */ static inline int get_chainname_rulenum(struct ip6t_entry *s, struct ip6t_entry *e, - char *hookname, char **chainname, - char **comment, unsigned int *rulenum) + const char *hookname, const char **chainname, + const char **comment, unsigned int *rulenum) { struct ip6t_standard_target *t = (void *)ip6t_get_target(s); @@ -289,8 +289,8 @@ get_chainname_rulenum(struct ip6t_entry *s, struct ip6t_entry *e, && unconditional(&s->ipv6)) { /* Tail of chains: STANDARD target (return/policy) */ *comment = *chainname == hookname - ? (char *)comments[NF_IP6_TRACE_COMMENT_POLICY] - : (char *)comments[NF_IP6_TRACE_COMMENT_RETURN]; + ? comments[NF_IP6_TRACE_COMMENT_POLICY] + : comments[NF_IP6_TRACE_COMMENT_RETURN]; } return 1; } else @@ -309,14 +309,14 @@ static void trace_packet(struct sk_buff *skb, { void *table_base; const struct ip6t_entry *root; - char *hookname, *chainname, *comment; + const char *hookname, *chainname, *comment; unsigned int rulenum = 0; - table_base = (void *)private->entries[smp_processor_id()]; + table_base = private->entries[smp_processor_id()]; root = get_entry(table_base, private->hook_entry[hook]); - hookname = chainname = (char *)hooknames[hook]; - comment = (char *)comments[NF_IP6_TRACE_COMMENT_RULE]; + hookname = chainname = hooknames[hook]; + comment = comments[NF_IP6_TRACE_COMMENT_RULE]; IP6T_ENTRY_ITERATE(root, private->size - private->hook_entry[hook], @@ -329,6 +329,12 @@ static void trace_packet(struct sk_buff *skb, } #endif +static inline __pure struct ip6t_entry * +ip6t_next_entry(const struct ip6t_entry *entry) +{ + return (void *)entry + entry->next_offset; +} + /* Returns one of the generic firewall policies, like NF_ACCEPT. */ unsigned int ip6t_do_table(struct sk_buff *skb, @@ -337,6 +343,8 @@ ip6t_do_table(struct sk_buff *skb, const struct net_device *out, struct xt_table *table) { +#define tb_comefrom ((struct ip6t_entry *)table_base)->comefrom + static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long)))); bool hotdrop = false; /* Initializing verdict to NF_DROP keeps gcc happy. */ @@ -361,7 +369,7 @@ ip6t_do_table(struct sk_buff *skb, mtpar.in = tgpar.in = in; mtpar.out = tgpar.out = out; mtpar.family = tgpar.family = NFPROTO_IPV6; - tgpar.hooknum = hook; + mtpar.hooknum = tgpar.hooknum = hook; IP_NF_ASSERT(table->valid_hooks & (1 << hook)); @@ -375,96 +383,86 @@ ip6t_do_table(struct sk_buff *skb, back = get_entry(table_base, private->underflow[hook]); do { + struct ip6t_entry_target *t; + IP_NF_ASSERT(e); IP_NF_ASSERT(back); - if (ip6_packet_match(skb, indev, outdev, &e->ipv6, - &mtpar.thoff, &mtpar.fragoff, &hotdrop)) { - struct ip6t_entry_target *t; + if (!ip6_packet_match(skb, indev, outdev, &e->ipv6, + &mtpar.thoff, &mtpar.fragoff, &hotdrop) || + IP6T_MATCH_ITERATE(e, do_match, skb, &mtpar) != 0) { + e = ip6t_next_entry(e); + continue; + } - if (IP6T_MATCH_ITERATE(e, do_match, skb, &mtpar) != 0) - goto no_match; + ADD_COUNTER(e->counters, + ntohs(ipv6_hdr(skb)->payload_len) + + sizeof(struct ipv6hdr), 1); - ADD_COUNTER(e->counters, - ntohs(ipv6_hdr(skb)->payload_len) + - sizeof(struct ipv6hdr), 1); - - t = ip6t_get_target(e); - IP_NF_ASSERT(t->u.kernel.target); + t = ip6t_get_target(e); + IP_NF_ASSERT(t->u.kernel.target); #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \ defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE) - /* The packet is traced: log it */ - if (unlikely(skb->nf_trace)) - trace_packet(skb, hook, in, out, - table->name, private, e); + /* The packet is traced: log it */ + if (unlikely(skb->nf_trace)) + trace_packet(skb, hook, in, out, + table->name, private, e); #endif - /* Standard target? */ - if (!t->u.kernel.target->target) { - int v; + /* Standard target? */ + if (!t->u.kernel.target->target) { + int v; - v = ((struct ip6t_standard_target *)t)->verdict; - if (v < 0) { - /* Pop from stack? */ - if (v != IP6T_RETURN) { - verdict = (unsigned)(-v) - 1; - break; - } - e = back; - back = get_entry(table_base, - back->comefrom); - continue; - } - if (table_base + v != (void *)e + e->next_offset - && !(e->ipv6.flags & IP6T_F_GOTO)) { - /* Save old back ptr in next entry */ - struct ip6t_entry *next - = (void *)e + e->next_offset; - next->comefrom - = (void *)back - table_base; - /* set back pointer to next entry */ - back = next; - } - - e = get_entry(table_base, v); - } else { - /* Targets which reenter must return - abs. verdicts */ - tgpar.target = t->u.kernel.target; - tgpar.targinfo = t->data; - -#ifdef CONFIG_NETFILTER_DEBUG - ((struct ip6t_entry *)table_base)->comefrom - = 0xeeeeeeec; -#endif - verdict = t->u.kernel.target->target(skb, - &tgpar); - -#ifdef CONFIG_NETFILTER_DEBUG - if (((struct ip6t_entry *)table_base)->comefrom - != 0xeeeeeeec - && verdict == IP6T_CONTINUE) { - printk("Target %s reentered!\n", - t->u.kernel.target->name); - verdict = NF_DROP; - } - ((struct ip6t_entry *)table_base)->comefrom - = 0x57acc001; -#endif - if (verdict == IP6T_CONTINUE) - e = (void *)e + e->next_offset; - else - /* Verdict */ + v = ((struct ip6t_standard_target *)t)->verdict; + if (v < 0) { + /* Pop from stack? */ + if (v != IP6T_RETURN) { + verdict = (unsigned)(-v) - 1; break; + } + e = back; + back = get_entry(table_base, back->comefrom); + continue; + } + if (table_base + v != ip6t_next_entry(e) + && !(e->ipv6.flags & IP6T_F_GOTO)) { + /* Save old back ptr in next entry */ + struct ip6t_entry *next = ip6t_next_entry(e); + next->comefrom = (void *)back - table_base; + /* set back pointer to next entry */ + back = next; } - } else { - no_match: - e = (void *)e + e->next_offset; + e = get_entry(table_base, v); + continue; } + + /* Targets which reenter must return + abs. verdicts */ + tgpar.target = t->u.kernel.target; + tgpar.targinfo = t->data; + +#ifdef CONFIG_NETFILTER_DEBUG + tb_comefrom = 0xeeeeeeec; +#endif + verdict = t->u.kernel.target->target(skb, &tgpar); + +#ifdef CONFIG_NETFILTER_DEBUG + if (tb_comefrom != 0xeeeeeeec && verdict == IP6T_CONTINUE) { + printk("Target %s reentered!\n", + t->u.kernel.target->name); + verdict = NF_DROP; + } + tb_comefrom = 0x57acc001; +#endif + if (verdict == IP6T_CONTINUE) + e = ip6t_next_entry(e); + else + /* Verdict */ + break; } while (!hotdrop); #ifdef CONFIG_NETFILTER_DEBUG - ((struct ip6t_entry *)table_base)->comefrom = NETFILTER_LINK_POISON; + tb_comefrom = NETFILTER_LINK_POISON; #endif xt_info_rdunlock_bh(); @@ -475,6 +473,8 @@ ip6t_do_table(struct sk_buff *skb, return NF_DROP; else return verdict; #endif + +#undef tb_comefrom } /* Figures out from what hook each rule can be called: returns 0 if @@ -2191,7 +2191,7 @@ static bool icmp6_checkentry(const struct xt_mtchk_param *par) static struct xt_target ip6t_standard_target __read_mostly = { .name = IP6T_STANDARD_TARGET, .targetsize = sizeof(int), - .family = AF_INET6, + .family = NFPROTO_IPV6, #ifdef CONFIG_COMPAT .compatsize = sizeof(compat_int_t), .compat_from_user = compat_standard_from_user, @@ -2203,7 +2203,7 @@ static struct xt_target ip6t_error_target __read_mostly = { .name = IP6T_ERROR_TARGET, .target = ip6t_error, .targetsize = IP6T_FUNCTION_MAXNAMELEN, - .family = AF_INET6, + .family = NFPROTO_IPV6, }; static struct nf_sockopt_ops ip6t_sockopts = { @@ -2229,17 +2229,17 @@ static struct xt_match icmp6_matchstruct __read_mostly = { .matchsize = sizeof(struct ip6t_icmp), .checkentry = icmp6_checkentry, .proto = IPPROTO_ICMPV6, - .family = AF_INET6, + .family = NFPROTO_IPV6, }; static int __net_init ip6_tables_net_init(struct net *net) { - return xt_proto_init(net, AF_INET6); + return xt_proto_init(net, NFPROTO_IPV6); } static void __net_exit ip6_tables_net_exit(struct net *net) { - xt_proto_fini(net, AF_INET6); + xt_proto_fini(net, NFPROTO_IPV6); } static struct pernet_operations ip6_tables_net_ops = { diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c index 5a2d0a41694a..5a7f00cd15ce 100644 --- a/net/ipv6/netfilter/ip6t_REJECT.c +++ b/net/ipv6/netfilter/ip6t_REJECT.c @@ -112,7 +112,7 @@ static void send_reset(struct net *net, struct sk_buff *oldskb) return; } - nskb->dst = dst; + skb_dst_set(nskb, dst); skb_reserve(nskb, hh_len + dst->header_len); diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c index 9903227bf37c..642dcb127bab 100644 --- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c +++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c @@ -95,18 +95,10 @@ static int icmpv6_packet(struct nf_conn *ct, u_int8_t pf, unsigned int hooknum) { - /* Try to delete connection immediately after all replies: - won't actually vanish as we still have skb, and del_timer - means this will only run once even if count hits zero twice - (theoretically possible with SMP) */ - if (CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY) { - if (atomic_dec_and_test(&ct->proto.icmp.count)) - nf_ct_kill_acct(ct, ctinfo, skb); - } else { - atomic_inc(&ct->proto.icmp.count); - nf_conntrack_event_cache(IPCT_PROTOINFO_VOLATILE, ct); - nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_icmpv6_timeout); - } + /* Do not immediately delete the connection after the first + successful reply to avoid excessive conntrackd traffic + and also to handle correctly ICMP echo reply duplicates. */ + nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_icmpv6_timeout); return NF_ACCEPT; } @@ -132,7 +124,6 @@ static bool icmpv6_new(struct nf_conn *ct, const struct sk_buff *skb, type + 128); return false; } - atomic_set(&ct->proto.icmp.count, 0); return true; } diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index 058a5e4a60c3..f3aba255ad9f 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c @@ -409,7 +409,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev) /* If the first fragment is fragmented itself, we split * it to two chunks: the first with data and paged part * and the second, holding only fragments. */ - if (skb_shinfo(head)->frag_list) { + if (skb_has_frags(head)) { struct sk_buff *clone; int i, plen = 0; @@ -420,7 +420,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev) clone->next = head->next; head->next = clone; skb_shinfo(clone)->frag_list = skb_shinfo(head)->frag_list; - skb_shinfo(head)->frag_list = NULL; + skb_frag_list_init(head); for (i=0; inr_frags; i++) plen += skb_shinfo(head)->frags[i].size; clone->len = clone->data_len = head->data_len - plen; diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index 97c17fdd6f75..590ddefb7ffc 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c @@ -61,7 +61,7 @@ static const struct file_operations sockstat6_seq_fops = { static struct snmp_mib snmp6_ipstats_list[] = { /* ipv6 mib according to RFC 2465 */ - SNMP_MIB_ITEM("Ip6InReceives", IPSTATS_MIB_INRECEIVES), + SNMP_MIB_ITEM("Ip6InReceives", IPSTATS_MIB_INPKTS), SNMP_MIB_ITEM("Ip6InHdrErrors", IPSTATS_MIB_INHDRERRORS), SNMP_MIB_ITEM("Ip6InTooBigErrors", IPSTATS_MIB_INTOOBIGERRORS), SNMP_MIB_ITEM("Ip6InNoRoutes", IPSTATS_MIB_INNOROUTES), @@ -71,7 +71,7 @@ static struct snmp_mib snmp6_ipstats_list[] = { SNMP_MIB_ITEM("Ip6InDiscards", IPSTATS_MIB_INDISCARDS), SNMP_MIB_ITEM("Ip6InDelivers", IPSTATS_MIB_INDELIVERS), SNMP_MIB_ITEM("Ip6OutForwDatagrams", IPSTATS_MIB_OUTFORWDATAGRAMS), - SNMP_MIB_ITEM("Ip6OutRequests", IPSTATS_MIB_OUTREQUESTS), + SNMP_MIB_ITEM("Ip6OutRequests", IPSTATS_MIB_OUTPKTS), SNMP_MIB_ITEM("Ip6OutDiscards", IPSTATS_MIB_OUTDISCARDS), SNMP_MIB_ITEM("Ip6OutNoRoutes", IPSTATS_MIB_OUTNOROUTES), SNMP_MIB_ITEM("Ip6ReasmTimeout", IPSTATS_MIB_REASMTIMEOUT), @@ -83,6 +83,12 @@ static struct snmp_mib snmp6_ipstats_list[] = { SNMP_MIB_ITEM("Ip6FragCreates", IPSTATS_MIB_FRAGCREATES), SNMP_MIB_ITEM("Ip6InMcastPkts", IPSTATS_MIB_INMCASTPKTS), SNMP_MIB_ITEM("Ip6OutMcastPkts", IPSTATS_MIB_OUTMCASTPKTS), + SNMP_MIB_ITEM("Ip6InOctets", IPSTATS_MIB_INOCTETS), + SNMP_MIB_ITEM("Ip6OutOctets", IPSTATS_MIB_OUTOCTETS), + SNMP_MIB_ITEM("Ip6InMcastOctets", IPSTATS_MIB_INMCASTOCTETS), + SNMP_MIB_ITEM("Ip6OutMcastOctets", IPSTATS_MIB_OUTMCASTOCTETS), + SNMP_MIB_ITEM("Ip6InBcastOctets", IPSTATS_MIB_INBCASTOCTETS), + SNMP_MIB_ITEM("Ip6OutBcastOctets", IPSTATS_MIB_OUTBCASTOCTETS), SNMP_MIB_SENTINEL }; diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 61f6827e5906..d6c3c1c34b2d 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -310,7 +310,7 @@ out: static void rawv6_err(struct sock *sk, struct sk_buff *skb, struct inet6_skb_parm *opt, - int type, int code, int offset, __be32 info) + u8 type, u8 code, int offset, __be32 info) { struct inet_sock *inet = inet_sk(sk); struct ipv6_pinfo *np = inet6_sk(sk); @@ -343,7 +343,7 @@ static void rawv6_err(struct sock *sk, struct sk_buff *skb, } void raw6_icmp_error(struct sk_buff *skb, int nexthdr, - int type, int code, int inner_offset, __be32 info) + u8 type, u8 code, int inner_offset, __be32 info) { struct sock *sk; int hash; @@ -625,7 +625,7 @@ static int rawv6_send_hdrinc(struct sock *sk, void *from, int length, skb->priority = sk->sk_priority; skb->mark = sk->sk_mark; - skb->dst = dst_clone(&rt->u.dst); + skb_dst_set(skb, dst_clone(&rt->u.dst)); skb_put(skb, length); skb_reset_network_header(skb); @@ -638,7 +638,7 @@ static int rawv6_send_hdrinc(struct sock *sk, void *from, int length, if (err) goto error_fault; - IP6_INC_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUTREQUESTS); + IP6_UPD_PO_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUT, skb->len); err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, rt->u.dst.dev, dst_output); if (err > 0) @@ -1130,7 +1130,8 @@ static int rawv6_ioctl(struct sock *sk, int cmd, unsigned long arg) switch(cmd) { case SIOCOUTQ: { - int amount = atomic_read(&sk->sk_wmem_alloc); + int amount = sk_wmem_alloc_get(sk); + return put_user(amount, (int __user *)arg); } case SIOCINQ: @@ -1236,8 +1237,8 @@ static void raw6_sock_seq_show(struct seq_file *seq, struct sock *sp, int i) dest->s6_addr32[0], dest->s6_addr32[1], dest->s6_addr32[2], dest->s6_addr32[3], destp, sp->sk_state, - atomic_read(&sp->sk_wmem_alloc), - atomic_read(&sp->sk_rmem_alloc), + sk_wmem_alloc_get(sp), + sk_rmem_alloc_get(sp), 0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp), diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index e9ac7a12f595..2642a41a8535 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -267,7 +267,7 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, struct sk_buff *prev, *next; struct net_device *dev; int offset, end; - struct net *net = dev_net(skb->dst->dev); + struct net *net = dev_net(skb_dst(skb)->dev); if (fq->q.last_in & INET_FRAG_COMPLETE) goto err; @@ -277,7 +277,7 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, ((u8 *)(fhdr + 1) - (u8 *)(ipv6_hdr(skb) + 1))); if ((unsigned int)end > IPV6_MAXPLEN) { - IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst), + IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_INHDRERRORS); icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, ((u8 *)&fhdr->frag_off - @@ -310,7 +310,7 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, /* RFC2460 says always send parameter problem in * this case. -DaveM */ - IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst), + IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_INHDRERRORS); icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, offsetof(struct ipv6hdr, payload_len)); @@ -434,7 +434,7 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, return -1; err: - IP6_INC_STATS(net, ip6_dst_idev(skb->dst), + IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_REASMFAILS); kfree_skb(skb); return -1; @@ -494,7 +494,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev, /* If the first fragment is fragmented itself, we split * it to two chunks: the first with data and paged part * and the second, holding only fragments. */ - if (skb_shinfo(head)->frag_list) { + if (skb_has_frags(head)) { struct sk_buff *clone; int i, plen = 0; @@ -503,7 +503,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev, clone->next = head->next; head->next = clone; skb_shinfo(clone)->frag_list = skb_shinfo(head)->frag_list; - skb_shinfo(head)->frag_list = NULL; + skb_frag_list_init(head); for (i=0; inr_frags; i++) plen += skb_shinfo(head)->frags[i].size; clone->len = clone->data_len = head->data_len - plen; @@ -576,9 +576,9 @@ static int ipv6_frag_rcv(struct sk_buff *skb) struct frag_hdr *fhdr; struct frag_queue *fq; struct ipv6hdr *hdr = ipv6_hdr(skb); - struct net *net = dev_net(skb->dst->dev); + struct net *net = dev_net(skb_dst(skb)->dev); - IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst), IPSTATS_MIB_REASMREQDS); + IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_REASMREQDS); /* Jumbo payload inhibits frag. header */ if (hdr->payload_len==0) @@ -595,17 +595,17 @@ static int ipv6_frag_rcv(struct sk_buff *skb) /* It is not a fragmented frame */ skb->transport_header += sizeof(struct frag_hdr); IP6_INC_STATS_BH(net, - ip6_dst_idev(skb->dst), IPSTATS_MIB_REASMOKS); + ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_REASMOKS); IP6CB(skb)->nhoff = (u8 *)fhdr - skb_network_header(skb); return 1; } if (atomic_read(&net->ipv6.frags.mem) > net->ipv6.frags.high_thresh) - ip6_evictor(net, ip6_dst_idev(skb->dst)); + ip6_evictor(net, ip6_dst_idev(skb_dst(skb))); if ((fq = fq_find(net, fhdr->identification, &hdr->saddr, &hdr->daddr, - ip6_dst_idev(skb->dst))) != NULL) { + ip6_dst_idev(skb_dst(skb)))) != NULL) { int ret; spin_lock(&fq->q.lock); @@ -617,12 +617,12 @@ static int ipv6_frag_rcv(struct sk_buff *skb) return ret; } - IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst), IPSTATS_MIB_REASMFAILS); + IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_REASMFAILS); kfree_skb(skb); return -1; fail_hdr: - IP6_INC_STATS(net, ip6_dst_idev(skb->dst), IPSTATS_MIB_INHDRERRORS); + IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_INHDRERRORS); icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb_network_header_len(skb)); return -1; } diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 032a5ec391c5..1473ee0a1f51 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -800,7 +800,7 @@ void ip6_route_input(struct sk_buff *skb) if (rt6_need_strict(&iph->daddr) && skb->dev->type != ARPHRD_PIMREG) flags |= RT6_LOOKUP_F_IFACE; - skb->dst = fib6_rule_lookup(net, &fl, flags, ip6_pol_route_input); + skb_dst_set(skb, fib6_rule_lookup(net, &fl, flags, ip6_pol_route_input)); } static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table *table, @@ -911,7 +911,7 @@ static void ip6_link_failure(struct sk_buff *skb) icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0, skb->dev); - rt = (struct rt6_info *) skb->dst; + rt = (struct rt6_info *) skb_dst(skb); if (rt) { if (rt->rt6i_flags&RTF_CACHE) { dst_set_expires(&rt->u.dst, 0); @@ -1865,10 +1865,10 @@ int ipv6_route_ioctl(struct net *net, unsigned int cmd, void __user *arg) * Drop the packet on the floor */ -static int ip6_pkt_drop(struct sk_buff *skb, int code, int ipstats_mib_noroutes) +static int ip6_pkt_drop(struct sk_buff *skb, u8 code, int ipstats_mib_noroutes) { int type; - struct dst_entry *dst = skb->dst; + struct dst_entry *dst = skb_dst(skb); switch (ipstats_mib_noroutes) { case IPSTATS_MIB_INNOROUTES: type = ipv6_addr_type(&ipv6_hdr(skb)->daddr); @@ -1895,7 +1895,7 @@ static int ip6_pkt_discard(struct sk_buff *skb) static int ip6_pkt_discard_out(struct sk_buff *skb) { - skb->dev = skb->dst->dev; + skb->dev = skb_dst(skb)->dev; return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_OUTNOROUTES); } @@ -1908,7 +1908,7 @@ static int ip6_pkt_prohibit(struct sk_buff *skb) static int ip6_pkt_prohibit_out(struct sk_buff *skb) { - skb->dev = skb->dst->dev; + skb->dev = skb_dst(skb)->dev; return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES); } @@ -2366,7 +2366,7 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr)); rt = (struct rt6_info*) ip6_route_output(net, NULL, &fl); - skb->dst = &rt->u.dst; + skb_dst_set(skb, &rt->u.dst); err = rt6_fill_node(net, skb, rt, &fl.fl6_dst, &fl.fl6_src, iif, RTM_NEWROUTE, NETLINK_CB(in_skb).pid, diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 664ab82e03b2..68e52308e552 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -15,6 +15,7 @@ * Roger Venning : 6to4 support * Nate Thompson : 6to4 support * Fred Templin : isatap support + * Sascha Hlusiak : stateless autoconf for isatap */ #include @@ -80,7 +81,7 @@ struct sit_net { static DEFINE_RWLOCK(ipip6_lock); static struct ip_tunnel * ipip6_tunnel_lookup(struct net *net, - __be32 remote, __be32 local) + struct net_device *dev, __be32 remote, __be32 local) { unsigned h0 = HASH(remote); unsigned h1 = HASH(local); @@ -89,18 +90,25 @@ static struct ip_tunnel * ipip6_tunnel_lookup(struct net *net, for (t = sitn->tunnels_r_l[h0^h1]; t; t = t->next) { if (local == t->parms.iph.saddr && - remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP)) + remote == t->parms.iph.daddr && + (!dev || !t->parms.link || dev->iflink == t->parms.link) && + (t->dev->flags & IFF_UP)) return t; } for (t = sitn->tunnels_r[h0]; t; t = t->next) { - if (remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP)) + if (remote == t->parms.iph.daddr && + (!dev || !t->parms.link || dev->iflink == t->parms.link) && + (t->dev->flags & IFF_UP)) return t; } for (t = sitn->tunnels_l[h1]; t; t = t->next) { - if (local == t->parms.iph.saddr && (t->dev->flags&IFF_UP)) + if (local == t->parms.iph.saddr && + (!dev || !t->parms.link || dev->iflink == t->parms.link) && + (t->dev->flags & IFF_UP)) return t; } - if ((t = sitn->tunnels_wc[0]) != NULL && (t->dev->flags&IFF_UP)) + t = sitn->tunnels_wc[0]; + if ((t != NULL) && (t->dev->flags & IFF_UP)) return t; return NULL; } @@ -165,8 +173,14 @@ static struct ip_tunnel * ipip6_tunnel_locate(struct net *net, struct sit_net *sitn = net_generic(net, sit_net_id); for (tp = __ipip6_bucket(sitn, parms); (t = *tp) != NULL; tp = &t->next) { - if (local == t->parms.iph.saddr && remote == t->parms.iph.daddr) - return t; + if (local == t->parms.iph.saddr && + remote == t->parms.iph.daddr && + parms->link == t->parms.link) { + if (create) + return NULL; + else + return t; + } } if (!create) goto failed; @@ -209,6 +223,44 @@ failed: return NULL; } +static void ipip6_tunnel_rs_timer(unsigned long data) +{ + struct ip_tunnel_prl_entry *p = (struct ip_tunnel_prl_entry *) data; + struct inet6_dev *ifp; + struct inet6_ifaddr *addr; + + spin_lock(&p->lock); + ifp = __in6_dev_get(p->tunnel->dev); + + read_lock_bh(&ifp->lock); + for (addr = ifp->addr_list; addr; addr = addr->if_next) { + struct in6_addr rtr; + + if (!(ipv6_addr_type(&addr->addr) & IPV6_ADDR_LINKLOCAL)) + continue; + + /* Send RS to guessed linklocal address of router + * + * Better: send to ff02::2 encapsuled in unicast directly + * to router-v4 instead of guessing the v6 address. + * + * Cisco/Windows seem to not set the u/l bit correctly, + * so we won't guess right. + */ + ipv6_addr_set(&rtr, htonl(0xFE800000), 0, 0, 0); + if (!__ipv6_isatap_ifid(rtr.s6_addr + 8, + p->addr)) { + ndisc_send_rs(p->tunnel->dev, &addr->addr, &rtr); + } + } + read_unlock_bh(&ifp->lock); + + mod_timer(&p->rs_timer, jiffies + HZ * p->rs_delay); + spin_unlock(&p->lock); + + return; +} + static struct ip_tunnel_prl_entry * __ipip6_tunnel_locate_prl(struct ip_tunnel *t, __be32 addr) { @@ -267,6 +319,7 @@ static int ipip6_tunnel_get_prl(struct ip_tunnel *t, continue; kp[c].addr = prl->addr; kp[c].flags = prl->flags; + kp[c].rs_delay = prl->rs_delay; c++; if (kprl.addr != htonl(INADDR_ANY)) break; @@ -316,11 +369,23 @@ ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg) } p->next = t->prl; + p->tunnel = t; t->prl = p; t->prl_count++; + + spin_lock_init(&p->lock); + setup_timer(&p->rs_timer, ipip6_tunnel_rs_timer, (unsigned long) p); update: p->addr = a->addr; p->flags = a->flags; + p->rs_delay = a->rs_delay; + if (p->rs_delay == 0) + p->rs_delay = IPTUNNEL_RS_DEFAULT_DELAY; + spin_lock(&p->lock); + del_timer(&p->rs_timer); + if (p->flags & PRL_DEFAULT) + mod_timer(&p->rs_timer, jiffies + 1); + spin_unlock(&p->lock); out: write_unlock(&ipip6_lock); return err; @@ -339,6 +404,9 @@ ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a) if ((*p)->addr == a->addr) { x = *p; *p = x->next; + spin_lock(&x->lock); + del_timer(&x->rs_timer); + spin_unlock(&x->lock); kfree(x); t->prl_count--; goto out; @@ -349,13 +417,16 @@ ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a) while (t->prl) { x = t->prl; t->prl = t->prl->next; + spin_lock(&x->lock); + del_timer(&x->rs_timer); + spin_unlock(&x->lock); kfree(x); t->prl_count--; } } out: write_unlock(&ipip6_lock); - return 0; + return err; } static int @@ -446,7 +517,10 @@ static int ipip6_err(struct sk_buff *skb, u32 info) err = -ENOENT; read_lock(&ipip6_lock); - t = ipip6_tunnel_lookup(dev_net(skb->dev), iph->daddr, iph->saddr); + t = ipip6_tunnel_lookup(dev_net(skb->dev), + skb->dev, + iph->daddr, + iph->saddr); if (t == NULL || t->parms.iph.daddr == 0) goto out; @@ -481,8 +555,9 @@ static int ipip6_rcv(struct sk_buff *skb) iph = ip_hdr(skb); read_lock(&ipip6_lock); - if ((tunnel = ipip6_tunnel_lookup(dev_net(skb->dev), - iph->saddr, iph->daddr)) != NULL) { + tunnel = ipip6_tunnel_lookup(dev_net(skb->dev), skb->dev, + iph->saddr, iph->daddr); + if (tunnel != NULL) { secpath_reset(skb); skb->mac_header = skb->network_header; skb_reset_network_header(skb); @@ -500,8 +575,7 @@ static int ipip6_rcv(struct sk_buff *skb) tunnel->dev->stats.rx_packets++; tunnel->dev->stats.rx_bytes += skb->len; skb->dev = tunnel->dev; - dst_release(skb->dst); - skb->dst = NULL; + skb_dst_drop(skb); nf_reset(skb); ipip6_ecn_decapsulate(iph, skb); netif_rx(skb); @@ -563,8 +637,8 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) if (dev->priv_flags & IFF_ISATAP) { struct neighbour *neigh = NULL; - if (skb->dst) - neigh = skb->dst->neighbour; + if (skb_dst(skb)) + neigh = skb_dst(skb)->neighbour; if (neigh == NULL) { if (net_ratelimit()) @@ -588,8 +662,8 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) if (!dst) { struct neighbour *neigh = NULL; - if (skb->dst) - neigh = skb->dst->neighbour; + if (skb_dst(skb)) + neigh = skb_dst(skb)->neighbour; if (neigh == NULL) { if (net_ratelimit()) @@ -639,7 +713,7 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) if (tiph->frag_off) mtu = dst_mtu(&rt->u.dst) - sizeof(struct iphdr); else - mtu = skb->dst ? dst_mtu(skb->dst) : dev->mtu; + mtu = skb_dst(skb) ? dst_mtu(skb_dst(skb)) : dev->mtu; if (mtu < 68) { stats->collisions++; @@ -648,8 +722,8 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) } if (mtu < IPV6_MIN_MTU) mtu = IPV6_MIN_MTU; - if (tunnel->parms.iph.daddr && skb->dst) - skb->dst->ops->update_pmtu(skb->dst, mtu); + if (tunnel->parms.iph.daddr && skb_dst(skb)) + skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu); if (skb->len > mtu) { icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, dev); @@ -693,8 +767,8 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) skb_reset_network_header(skb); memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); IPCB(skb)->flags = 0; - dst_release(skb->dst); - skb->dst = &rt->u.dst; + skb_dst_drop(skb); + skb_dst_set(skb, &rt->u.dst); /* * Push down and install the IPIP header. diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index 711175e0571f..8c2513982b61 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c @@ -131,7 +131,7 @@ __u32 cookie_v6_init_sequence(struct sock *sk, struct sk_buff *skb, __u16 *mssp) int mssind; const __u16 mss = *mssp; - tcp_sk(sk)->last_synq_overflow = jiffies; + tcp_synq_overflow(sk); for (mssind = 0; mss > msstab[mssind + 1]; mssind++) ; @@ -175,7 +175,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) if (!sysctl_tcp_syncookies || !th->ack) goto out; - if (time_after(jiffies, tp->last_synq_overflow + TCP_TIMEOUT_INIT) || + if (tcp_synq_no_recent_overflow(sk) || (mss = cookie_check(skb, cookie)) == 0) { NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_SYNCOOKIESFAILED); goto out; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 4b5aa1854260..58810c65b635 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -317,7 +317,7 @@ failure: } static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, - int type, int code, int offset, __be32 info) + u8 type, u8 code, int offset, __be32 info) { struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data; const struct tcphdr *th = (struct tcphdr *)(skb->data+offset); @@ -941,9 +941,10 @@ static int tcp_v6_gso_send_check(struct sk_buff *skb) return 0; } -struct sk_buff **tcp6_gro_receive(struct sk_buff **head, struct sk_buff *skb) +static struct sk_buff **tcp6_gro_receive(struct sk_buff **head, + struct sk_buff *skb) { - struct ipv6hdr *iph = ipv6_hdr(skb); + struct ipv6hdr *iph = skb_gro_network_header(skb); switch (skb->ip_summed) { case CHECKSUM_COMPLETE: @@ -961,9 +962,8 @@ struct sk_buff **tcp6_gro_receive(struct sk_buff **head, struct sk_buff *skb) return tcp_gro_receive(head, skb); } -EXPORT_SYMBOL(tcp6_gro_receive); -int tcp6_gro_complete(struct sk_buff *skb) +static int tcp6_gro_complete(struct sk_buff *skb) { struct ipv6hdr *iph = ipv6_hdr(skb); struct tcphdr *th = tcp_hdr(skb); @@ -974,7 +974,6 @@ int tcp6_gro_complete(struct sk_buff *skb) return tcp_gro_complete(skb); } -EXPORT_SYMBOL(tcp6_gro_complete); static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts, struct tcp_md5sig_key *key, int rst) @@ -982,9 +981,10 @@ static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win, struct tcphdr *th = tcp_hdr(skb), *t1; struct sk_buff *buff; struct flowi fl; - struct net *net = dev_net(skb->dst->dev); + struct net *net = dev_net(skb_dst(skb)->dev); struct sock *ctl_sk = net->ipv6.tcp_sk; unsigned int tot_len = sizeof(struct tcphdr); + struct dst_entry *dst; __be32 *topt; if (ts) @@ -1053,8 +1053,9 @@ static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win, * Underlying function will use this to retrieve the network * namespace */ - if (!ip6_dst_lookup(ctl_sk, &buff->dst, &fl)) { - if (xfrm_lookup(net, &buff->dst, &fl, NULL, 0) >= 0) { + if (!ip6_dst_lookup(ctl_sk, &dst, &fl)) { + if (xfrm_lookup(net, &dst, &fl, NULL, 0) >= 0) { + skb_dst_set(buff, dst); ip6_xmit(ctl_sk, buff, &fl, NULL, 0); TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS); if (rst) diff --git a/net/ipv6/tunnel6.c b/net/ipv6/tunnel6.c index 669f280989c3..633ad789effc 100644 --- a/net/ipv6/tunnel6.c +++ b/net/ipv6/tunnel6.c @@ -124,7 +124,7 @@ drop: } static void tunnel6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, - int type, int code, int offset, __be32 info) + u8 type, u8 code, int offset, __be32 info) { struct xfrm6_tunnel *handler; diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 8905712cfbb8..33b59bd92c4d 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -177,10 +177,9 @@ static struct sock *__udp6_lib_lookup_skb(struct sk_buff *skb, if (unlikely(sk = skb_steal_sock(skb))) return sk; - else - return __udp6_lib_lookup(dev_net(skb->dst->dev), &iph->saddr, sport, - &iph->daddr, dport, inet6_iif(skb), - udptable); + return __udp6_lib_lookup(dev_net(skb_dst(skb)->dev), &iph->saddr, sport, + &iph->daddr, dport, inet6_iif(skb), + udptable); } /* @@ -313,7 +312,7 @@ csum_copy_err: } void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt, - int type, int code, int offset, __be32 info, + u8 type, u8 code, int offset, __be32 info, struct udp_table *udptable) { struct ipv6_pinfo *np; @@ -347,8 +346,8 @@ out: } static __inline__ void udpv6_err(struct sk_buff *skb, - struct inet6_skb_parm *opt, int type, - int code, int offset, __be32 info ) + struct inet6_skb_parm *opt, u8 type, + u8 code, int offset, __be32 info ) { __udp6_lib_err(skb, opt, type, code, offset, info, &udp_table); } @@ -1062,8 +1061,8 @@ static void udp6_sock_seq_show(struct seq_file *seq, struct sock *sp, int bucket dest->s6_addr32[0], dest->s6_addr32[1], dest->s6_addr32[2], dest->s6_addr32[3], destp, sp->sk_state, - atomic_read(&sp->sk_wmem_alloc), - atomic_read(&sp->sk_rmem_alloc), + sk_wmem_alloc_get(sp), + sk_rmem_alloc_get(sp), 0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp), diff --git a/net/ipv6/udp_impl.h b/net/ipv6/udp_impl.h index 23779208c334..6bb303471e20 100644 --- a/net/ipv6/udp_impl.h +++ b/net/ipv6/udp_impl.h @@ -9,7 +9,7 @@ extern int __udp6_lib_rcv(struct sk_buff *, struct udp_table *, int ); extern void __udp6_lib_err(struct sk_buff *, struct inet6_skb_parm *, - int , int , int , __be32 , struct udp_table *); + u8 , u8 , int , __be32 , struct udp_table *); extern int udp_v6_get_port(struct sock *sk, unsigned short snum); diff --git a/net/ipv6/udplite.c b/net/ipv6/udplite.c index ba162a824585..4818c48688f2 100644 --- a/net/ipv6/udplite.c +++ b/net/ipv6/udplite.c @@ -20,7 +20,7 @@ static int udplitev6_rcv(struct sk_buff *skb) static void udplitev6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, - int type, int code, int offset, __be32 info) + u8 type, u8 code, int offset, __be32 info) { __udp6_lib_err(skb, opt, type, code, offset, info, &udplite_table); } diff --git a/net/ipv6/xfrm6_mode_tunnel.c b/net/ipv6/xfrm6_mode_tunnel.c index e20529b4c825..3927832227b9 100644 --- a/net/ipv6/xfrm6_mode_tunnel.c +++ b/net/ipv6/xfrm6_mode_tunnel.c @@ -31,7 +31,7 @@ static inline void ipip6_ecn_decapsulate(struct sk_buff *skb) */ static int xfrm6_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) { - struct dst_entry *dst = skb->dst; + struct dst_entry *dst = skb_dst(skb); struct ipv6hdr *top_iph; int dsfield; @@ -45,7 +45,7 @@ static int xfrm6_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) memcpy(top_iph->flow_lbl, XFRM_MODE_SKB_CB(skb)->flow_lbl, sizeof(top_iph->flow_lbl)); - top_iph->nexthdr = xfrm_af2proto(skb->dst->ops->family); + top_iph->nexthdr = xfrm_af2proto(skb_dst(skb)->ops->family); dsfield = XFRM_MODE_SKB_CB(skb)->tos; dsfield = INET_ECN_encapsulate(dsfield, dsfield); diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c index 5ee5a031bc93..c4f4eef032a3 100644 --- a/net/ipv6/xfrm6_output.c +++ b/net/ipv6/xfrm6_output.c @@ -30,7 +30,7 @@ EXPORT_SYMBOL(xfrm6_find_1stfragopt); static int xfrm6_tunnel_check_size(struct sk_buff *skb) { int mtu, ret = 0; - struct dst_entry *dst = skb->dst; + struct dst_entry *dst = skb_dst(skb); mtu = dst_mtu(dst); if (mtu < IPV6_MIN_MTU) @@ -90,6 +90,6 @@ static int xfrm6_output_finish(struct sk_buff *skb) int xfrm6_output(struct sk_buff *skb) { - return NF_HOOK(PF_INET6, NF_INET_POST_ROUTING, skb, NULL, skb->dst->dev, + return NF_HOOK(PF_INET6, NF_INET_POST_ROUTING, skb, NULL, skb_dst(skb)->dev, xfrm6_output_finish); } diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c index 80193db224d9..81a95c00e503 100644 --- a/net/ipv6/xfrm6_tunnel.c +++ b/net/ipv6/xfrm6_tunnel.c @@ -262,7 +262,7 @@ static int xfrm6_tunnel_rcv(struct sk_buff *skb) } static int xfrm6_tunnel_err(struct sk_buff *skb, struct inet6_skb_parm *opt, - int type, int code, int offset, __be32 info) + u8 type, u8 code, int offset, __be32 info) { /* xfrm6_tunnel native err handling */ switch (type) { diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c index 1627050e29fd..417b0e309495 100644 --- a/net/ipx/af_ipx.c +++ b/net/ipx/af_ipx.c @@ -1835,7 +1835,7 @@ static int ipx_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) switch (cmd) { case TIOCOUTQ: - amount = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc); + amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk); if (amount < 0) amount = 0; rc = put_user(amount, (int __user *)argp); diff --git a/net/ipx/ipx_proc.c b/net/ipx/ipx_proc.c index 5ed97ad0e2e3..576178482f89 100644 --- a/net/ipx/ipx_proc.c +++ b/net/ipx/ipx_proc.c @@ -280,8 +280,8 @@ static int ipx_seq_socket_show(struct seq_file *seq, void *v) } seq_printf(seq, "%08X %08X %02X %03d\n", - atomic_read(&s->sk_wmem_alloc), - atomic_read(&s->sk_rmem_alloc), + sk_wmem_alloc_get(s), + sk_rmem_alloc_get(s), s->sk_state, SOCK_INODE(s->sk_socket)->i_uid); out: return 0; diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c index 3eb5bcc75f99..cb762c8723ea 100644 --- a/net/irda/af_irda.c +++ b/net/irda/af_irda.c @@ -913,9 +913,6 @@ static int irda_accept(struct socket *sock, struct socket *newsock, int flags) /* Clean up the original one to keep it in listen state */ irttp_listen(self->tsap); - /* Wow ! What is that ? Jean II */ - skb->sk = NULL; - skb->destructor = NULL; kfree_skb(skb); sk->sk_ack_backlog--; @@ -1762,7 +1759,8 @@ static int irda_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) switch (cmd) { case TIOCOUTQ: { long amount; - amount = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc); + + amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk); if (amount < 0) amount = 0; if (put_user(amount, (unsigned int __user *)arg)) diff --git a/net/irda/ircomm/ircomm_lmp.c b/net/irda/ircomm/ircomm_lmp.c index 67c99d20857f..7ba96618660e 100644 --- a/net/irda/ircomm/ircomm_lmp.c +++ b/net/irda/ircomm/ircomm_lmp.c @@ -196,6 +196,7 @@ static int ircomm_lmp_data_request(struct ircomm_cb *self, /* Don't forget to refcount it - see ircomm_tty_do_softint() */ skb_get(skb); + skb_orphan(skb); skb->destructor = ircomm_lmp_flow_control; if ((self->pkt_count++ > 7) && (self->flow_status == FLOW_START)) { diff --git a/net/irda/irlap_frame.c b/net/irda/irlap_frame.c index 2562ebc1b22c..7af2e74deda8 100644 --- a/net/irda/irlap_frame.c +++ b/net/irda/irlap_frame.c @@ -982,17 +982,12 @@ void irlap_resend_rejected_frames(struct irlap_cb *self, int command) { struct sk_buff *tx_skb; struct sk_buff *skb; - int count; IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == LAP_MAGIC, return;); - /* Initialize variables */ - count = skb_queue_len(&self->wx_list); - /* Resend unacknowledged frame(s) */ - skb = skb_peek(&self->wx_list); - while (skb != NULL) { + skb_queue_walk(&self->wx_list, skb) { irlap_wait_min_turn_around(self, &self->qos_tx); /* We copy the skb to be retransmitted since we will have to @@ -1011,21 +1006,12 @@ void irlap_resend_rejected_frames(struct irlap_cb *self, int command) /* * Set poll bit on the last frame retransmitted */ - if (count-- == 1) + if (skb_queue_is_last(&self->wx_list, skb)) tx_skb->data[1] |= PF_BIT; /* Set p/f bit */ else tx_skb->data[1] &= ~PF_BIT; /* Clear p/f bit */ irlap_send_i_frame(self, tx_skb, command); - - /* - * If our skb is the last buffer in the list, then - * we are finished, if not, move to the next sk-buffer - */ - if (skb == skb_peek_tail(&self->wx_list)) - skb = NULL; - else - skb = skb->next; } #if 0 /* Not yet */ /* diff --git a/net/irda/irnetlink.c b/net/irda/irnetlink.c index 2f05ec1037ab..8dd7ed7e7c1f 100644 --- a/net/irda/irnetlink.c +++ b/net/irda/irnetlink.c @@ -87,7 +87,7 @@ static int irda_nl_get_mode(struct sk_buff *skb, struct genl_info *info) if (!dev) return -ENODEV; - msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!msg) { dev_put(dev); return -ENOMEM; @@ -148,21 +148,8 @@ static struct genl_ops irda_nl_ops[] = { int irda_nl_register(void) { - int err, i; - - err = genl_register_family(&irda_nl_family); - if (err) - return err; - - for (i = 0; i < ARRAY_SIZE(irda_nl_ops); i++) { - err = genl_register_ops(&irda_nl_family, &irda_nl_ops[i]); - if (err) - goto err_out; - } - return 0; - err_out: - genl_unregister_family(&irda_nl_family); - return err; + return genl_register_family_with_ops(&irda_nl_family, + irda_nl_ops, ARRAY_SIZE(irda_nl_ops)); } void irda_nl_unregister(void) diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index b51c9187c347..6be5f92d1094 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c @@ -1,11 +1,12 @@ /* - * linux/net/iucv/af_iucv.c - * * IUCV protocol stack for Linux on zSeries * - * Copyright 2006 IBM Corporation + * Copyright IBM Corp. 2006, 2009 * * Author(s): Jennifer Hunt + * Hendrik Brueckner + * PM functions: + * Ursula Braun */ #define KMSG_COMPONENT "af_iucv" @@ -29,10 +30,7 @@ #include #include -#define CONFIG_IUCV_SOCK_DEBUG 1 - -#define IPRMDATA 0x80 -#define VERSION "1.0" +#define VERSION "1.1" static char iucv_userid[80]; @@ -44,6 +42,51 @@ static struct proto iucv_proto = { .obj_size = sizeof(struct iucv_sock), }; +/* special AF_IUCV IPRM messages */ +static const u8 iprm_shutdown[8] = + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}; + +#define TRGCLS_SIZE (sizeof(((struct iucv_message *)0)->class)) + +/* macros to set/get socket control buffer at correct offset */ +#define CB_TAG(skb) ((skb)->cb) /* iucv message tag */ +#define CB_TAG_LEN (sizeof(((struct iucv_message *) 0)->tag)) +#define CB_TRGCLS(skb) ((skb)->cb + CB_TAG_LEN) /* iucv msg target class */ +#define CB_TRGCLS_LEN (TRGCLS_SIZE) + +#define __iucv_sock_wait(sk, condition, timeo, ret) \ +do { \ + DEFINE_WAIT(__wait); \ + long __timeo = timeo; \ + ret = 0; \ + while (!(condition)) { \ + prepare_to_wait(sk->sk_sleep, &__wait, TASK_INTERRUPTIBLE); \ + if (!__timeo) { \ + ret = -EAGAIN; \ + break; \ + } \ + if (signal_pending(current)) { \ + ret = sock_intr_errno(__timeo); \ + break; \ + } \ + release_sock(sk); \ + __timeo = schedule_timeout(__timeo); \ + lock_sock(sk); \ + ret = sock_error(sk); \ + if (ret) \ + break; \ + } \ + finish_wait(sk->sk_sleep, &__wait); \ +} while (0) + +#define iucv_sock_wait(sk, condition, timeo) \ +({ \ + int __ret = 0; \ + if (!(condition)) \ + __iucv_sock_wait(sk, condition, timeo, __ret); \ + __ret; \ +}) + static void iucv_sock_kill(struct sock *sk); static void iucv_sock_close(struct sock *sk); @@ -54,6 +97,7 @@ static void iucv_callback_connack(struct iucv_path *, u8 ipuser[16]); static int iucv_callback_connreq(struct iucv_path *, u8 ipvmid[8], u8 ipuser[16]); static void iucv_callback_connrej(struct iucv_path *, u8 ipuser[16]); +static void iucv_callback_shutdown(struct iucv_path *, u8 ipuser[16]); static struct iucv_sock_list iucv_sk_list = { .lock = __RW_LOCK_UNLOCKED(iucv_sk_list.lock), @@ -65,7 +109,8 @@ static struct iucv_handler af_iucv_handler = { .path_complete = iucv_callback_connack, .path_severed = iucv_callback_connrej, .message_pending = iucv_callback_rx, - .message_complete = iucv_callback_txdone + .message_complete = iucv_callback_txdone, + .path_quiesced = iucv_callback_shutdown, }; static inline void high_nmcpy(unsigned char *dst, char *src) @@ -78,6 +123,195 @@ static inline void low_nmcpy(unsigned char *dst, char *src) memcpy(&dst[8], src, 8); } +static int afiucv_pm_prepare(struct device *dev) +{ +#ifdef CONFIG_PM_DEBUG + printk(KERN_WARNING "afiucv_pm_prepare\n"); +#endif + return 0; +} + +static void afiucv_pm_complete(struct device *dev) +{ +#ifdef CONFIG_PM_DEBUG + printk(KERN_WARNING "afiucv_pm_complete\n"); +#endif + return; +} + +/** + * afiucv_pm_freeze() - Freeze PM callback + * @dev: AFIUCV dummy device + * + * Sever all established IUCV communication pathes + */ +static int afiucv_pm_freeze(struct device *dev) +{ + struct iucv_sock *iucv; + struct sock *sk; + struct hlist_node *node; + int err = 0; + +#ifdef CONFIG_PM_DEBUG + printk(KERN_WARNING "afiucv_pm_freeze\n"); +#endif + read_lock(&iucv_sk_list.lock); + sk_for_each(sk, node, &iucv_sk_list.head) { + iucv = iucv_sk(sk); + skb_queue_purge(&iucv->send_skb_q); + skb_queue_purge(&iucv->backlog_skb_q); + switch (sk->sk_state) { + case IUCV_SEVERED: + case IUCV_DISCONN: + case IUCV_CLOSING: + case IUCV_CONNECTED: + if (iucv->path) { + err = iucv_path_sever(iucv->path, NULL); + iucv_path_free(iucv->path); + iucv->path = NULL; + } + break; + case IUCV_OPEN: + case IUCV_BOUND: + case IUCV_LISTEN: + case IUCV_CLOSED: + default: + break; + } + } + read_unlock(&iucv_sk_list.lock); + return err; +} + +/** + * afiucv_pm_restore_thaw() - Thaw and restore PM callback + * @dev: AFIUCV dummy device + * + * socket clean up after freeze + */ +static int afiucv_pm_restore_thaw(struct device *dev) +{ + struct iucv_sock *iucv; + struct sock *sk; + struct hlist_node *node; + +#ifdef CONFIG_PM_DEBUG + printk(KERN_WARNING "afiucv_pm_restore_thaw\n"); +#endif + read_lock(&iucv_sk_list.lock); + sk_for_each(sk, node, &iucv_sk_list.head) { + iucv = iucv_sk(sk); + switch (sk->sk_state) { + case IUCV_CONNECTED: + sk->sk_err = EPIPE; + sk->sk_state = IUCV_DISCONN; + sk->sk_state_change(sk); + break; + case IUCV_DISCONN: + case IUCV_SEVERED: + case IUCV_CLOSING: + case IUCV_LISTEN: + case IUCV_BOUND: + case IUCV_OPEN: + default: + break; + } + } + read_unlock(&iucv_sk_list.lock); + return 0; +} + +static struct dev_pm_ops afiucv_pm_ops = { + .prepare = afiucv_pm_prepare, + .complete = afiucv_pm_complete, + .freeze = afiucv_pm_freeze, + .thaw = afiucv_pm_restore_thaw, + .restore = afiucv_pm_restore_thaw, +}; + +static struct device_driver af_iucv_driver = { + .owner = THIS_MODULE, + .name = "afiucv", + .bus = &iucv_bus, + .pm = &afiucv_pm_ops, +}; + +/* dummy device used as trigger for PM functions */ +static struct device *af_iucv_dev; + +/** + * iucv_msg_length() - Returns the length of an iucv message. + * @msg: Pointer to struct iucv_message, MUST NOT be NULL + * + * The function returns the length of the specified iucv message @msg of data + * stored in a buffer and of data stored in the parameter list (PRMDATA). + * + * For IUCV_IPRMDATA, AF_IUCV uses the following convention to transport socket + * data: + * PRMDATA[0..6] socket data (max 7 bytes); + * PRMDATA[7] socket data length value (len is 0xff - PRMDATA[7]) + * + * The socket data length is computed by substracting the socket data length + * value from 0xFF. + * If the socket data len is greater 7, then PRMDATA can be used for special + * notifications (see iucv_sock_shutdown); and further, + * if the socket data len is > 7, the function returns 8. + * + * Use this function to allocate socket buffers to store iucv message data. + */ +static inline size_t iucv_msg_length(struct iucv_message *msg) +{ + size_t datalen; + + if (msg->flags & IUCV_IPRMDATA) { + datalen = 0xff - msg->rmmsg[7]; + return (datalen < 8) ? datalen : 8; + } + return msg->length; +} + +/** + * iucv_sock_in_state() - check for specific states + * @sk: sock structure + * @state: first iucv sk state + * @state: second iucv sk state + * + * Returns true if the socket in either in the first or second state. + */ +static int iucv_sock_in_state(struct sock *sk, int state, int state2) +{ + return (sk->sk_state == state || sk->sk_state == state2); +} + +/** + * iucv_below_msglim() - function to check if messages can be sent + * @sk: sock structure + * + * Returns true if the send queue length is lower than the message limit. + * Always returns true if the socket is not connected (no iucv path for + * checking the message limit). + */ +static inline int iucv_below_msglim(struct sock *sk) +{ + struct iucv_sock *iucv = iucv_sk(sk); + + if (sk->sk_state != IUCV_CONNECTED) + return 1; + return (skb_queue_len(&iucv->send_skb_q) < iucv->path->msglim); +} + +/** + * iucv_sock_wake_msglim() - Wake up thread waiting on msg limit + */ +static void iucv_sock_wake_msglim(struct sock *sk) +{ + read_lock(&sk->sk_callback_lock); + if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) + wake_up_interruptible_all(sk->sk_sleep); + sk_wake_async(sk, SOCK_WAKE_SPACE, POLL_OUT); + read_unlock(&sk->sk_callback_lock); +} + /* Timers */ static void iucv_sock_timeout(unsigned long arg) { @@ -169,7 +403,9 @@ static void iucv_sock_close(struct sock *sk) timeo = sk->sk_lingertime; else timeo = IUCV_DISCONN_TIMEOUT; - err = iucv_sock_wait_state(sk, IUCV_CLOSED, 0, timeo); + err = iucv_sock_wait(sk, + iucv_sock_in_state(sk, IUCV_CLOSED, 0), + timeo); } case IUCV_CLOSING: /* fall through */ @@ -225,6 +461,8 @@ static struct sock *iucv_sock_alloc(struct socket *sock, int proto, gfp_t prio) spin_lock_init(&iucv_sk(sk)->message_q.lock); skb_queue_head_init(&iucv_sk(sk)->backlog_skb_q); iucv_sk(sk)->send_tag = 0; + iucv_sk(sk)->flags = 0; + iucv_sk(sk)->msglimit = IUCV_QUEUELEN_DEFAULT; iucv_sk(sk)->path = NULL; memset(&iucv_sk(sk)->src_user_id , 0, 32); @@ -248,11 +486,22 @@ static int iucv_sock_create(struct net *net, struct socket *sock, int protocol) { struct sock *sk; - if (sock->type != SOCK_STREAM) - return -ESOCKTNOSUPPORT; + if (protocol && protocol != PF_IUCV) + return -EPROTONOSUPPORT; sock->state = SS_UNCONNECTED; - sock->ops = &iucv_sock_ops; + + switch (sock->type) { + case SOCK_STREAM: + sock->ops = &iucv_sock_ops; + break; + case SOCK_SEQPACKET: + /* currently, proto ops can handle both sk types */ + sock->ops = &iucv_sock_ops; + break; + default: + return -ESOCKTNOSUPPORT; + } sk = iucv_sock_alloc(sock, protocol, GFP_KERNEL); if (!sk) @@ -337,39 +586,6 @@ struct sock *iucv_accept_dequeue(struct sock *parent, struct socket *newsock) return NULL; } -int iucv_sock_wait_state(struct sock *sk, int state, int state2, - unsigned long timeo) -{ - DECLARE_WAITQUEUE(wait, current); - int err = 0; - - add_wait_queue(sk->sk_sleep, &wait); - while (sk->sk_state != state && sk->sk_state != state2) { - set_current_state(TASK_INTERRUPTIBLE); - - if (!timeo) { - err = -EAGAIN; - break; - } - - if (signal_pending(current)) { - err = sock_intr_errno(timeo); - break; - } - - release_sock(sk); - timeo = schedule_timeout(timeo); - lock_sock(sk); - - err = sock_error(sk); - if (err) - break; - } - set_current_state(TASK_RUNNING); - remove_wait_queue(sk->sk_sleep, &wait); - return err; -} - /* Bind an unbound socket */ static int iucv_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len) @@ -463,11 +679,9 @@ static int iucv_sock_connect(struct socket *sock, struct sockaddr *addr, if (sk->sk_state != IUCV_OPEN && sk->sk_state != IUCV_BOUND) return -EBADFD; - if (sk->sk_type != SOCK_STREAM) + if (sk->sk_type != SOCK_STREAM && sk->sk_type != SOCK_SEQPACKET) return -EINVAL; - iucv = iucv_sk(sk); - if (sk->sk_state == IUCV_OPEN) { err = iucv_sock_autobind(sk); if (unlikely(err)) @@ -486,8 +700,8 @@ static int iucv_sock_connect(struct socket *sock, struct sockaddr *addr, iucv = iucv_sk(sk); /* Create path. */ - iucv->path = iucv_path_alloc(IUCV_QUEUELEN_DEFAULT, - IPRMDATA, GFP_KERNEL); + iucv->path = iucv_path_alloc(iucv->msglimit, + IUCV_IPRMDATA, GFP_KERNEL); if (!iucv->path) { err = -ENOMEM; goto done; @@ -516,13 +730,13 @@ static int iucv_sock_connect(struct socket *sock, struct sockaddr *addr, } if (sk->sk_state != IUCV_CONNECTED) { - err = iucv_sock_wait_state(sk, IUCV_CONNECTED, IUCV_DISCONN, - sock_sndtimeo(sk, flags & O_NONBLOCK)); + err = iucv_sock_wait(sk, iucv_sock_in_state(sk, IUCV_CONNECTED, + IUCV_DISCONN), + sock_sndtimeo(sk, flags & O_NONBLOCK)); } if (sk->sk_state == IUCV_DISCONN) { - release_sock(sk); - return -ECONNREFUSED; + err = -ECONNREFUSED; } if (err) { @@ -545,7 +759,10 @@ static int iucv_sock_listen(struct socket *sock, int backlog) lock_sock(sk); err = -EINVAL; - if (sk->sk_state != IUCV_BOUND || sock->type != SOCK_STREAM) + if (sk->sk_state != IUCV_BOUND) + goto done; + + if (sock->type != SOCK_STREAM && sock->type != SOCK_SEQPACKET) goto done; sk->sk_max_ack_backlog = backlog; @@ -636,6 +853,30 @@ static int iucv_sock_getname(struct socket *sock, struct sockaddr *addr, return 0; } +/** + * iucv_send_iprm() - Send socket data in parameter list of an iucv message. + * @path: IUCV path + * @msg: Pointer to a struct iucv_message + * @skb: The socket data to send, skb->len MUST BE <= 7 + * + * Send the socket data in the parameter list in the iucv message + * (IUCV_IPRMDATA). The socket data is stored at index 0 to 6 in the parameter + * list and the socket data len at index 7 (last byte). + * See also iucv_msg_length(). + * + * Returns the error code from the iucv_message_send() call. + */ +static int iucv_send_iprm(struct iucv_path *path, struct iucv_message *msg, + struct sk_buff *skb) +{ + u8 prmdata[8]; + + memcpy(prmdata, (void *) skb->data, skb->len); + prmdata[7] = 0xff - (u8) skb->len; + return iucv_message_send(path, msg, IUCV_IPRMDATA, 0, + (void *) prmdata, 8); +} + static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len) { @@ -643,9 +884,13 @@ static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct iucv_sock *iucv = iucv_sk(sk); struct sk_buff *skb; struct iucv_message txmsg; + struct cmsghdr *cmsg; + int cmsg_done; + long timeo; char user_id[9]; char appl_id[9]; int err; + int noblock = msg->msg_flags & MSG_DONTWAIT; err = sock_error(sk); if (err) @@ -654,6 +899,10 @@ static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock, if (msg->msg_flags & MSG_OOB) return -EOPNOTSUPP; + /* SOCK_SEQPACKET: we do not support segmented records */ + if (sk->sk_type == SOCK_SEQPACKET && !(msg->msg_flags & MSG_EOR)) + return -EOPNOTSUPP; + lock_sock(sk); if (sk->sk_shutdown & SEND_SHUTDOWN) { @@ -661,42 +910,119 @@ static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock, goto out; } - if (sk->sk_state == IUCV_CONNECTED) { - if (!(skb = sock_alloc_send_skb(sk, len, - msg->msg_flags & MSG_DONTWAIT, - &err))) - goto out; + /* Return if the socket is not in connected state */ + if (sk->sk_state != IUCV_CONNECTED) { + err = -ENOTCONN; + goto out; + } - if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) { - err = -EFAULT; - goto fail; + /* initialize defaults */ + cmsg_done = 0; /* check for duplicate headers */ + txmsg.class = 0; + + /* iterate over control messages */ + for (cmsg = CMSG_FIRSTHDR(msg); cmsg; + cmsg = CMSG_NXTHDR(msg, cmsg)) { + + if (!CMSG_OK(msg, cmsg)) { + err = -EINVAL; + goto out; } - 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); - err = iucv_message_send(iucv->path, &txmsg, 0, 0, - (void *) skb->data, skb->len); - if (err) { - if (err == 3) { - user_id[8] = 0; - memcpy(user_id, iucv->dst_user_id, 8); - appl_id[8] = 0; - memcpy(appl_id, iucv->dst_name, 8); - pr_err("Application %s on z/VM guest %s" - " exceeds message limit\n", - user_id, appl_id); + if (cmsg->cmsg_level != SOL_IUCV) + continue; + + if (cmsg->cmsg_type & cmsg_done) { + err = -EINVAL; + goto out; + } + cmsg_done |= cmsg->cmsg_type; + + switch (cmsg->cmsg_type) { + case SCM_IUCV_TRGCLS: + if (cmsg->cmsg_len != CMSG_LEN(TRGCLS_SIZE)) { + err = -EINVAL; + goto out; } + + /* set iucv message target class */ + memcpy(&txmsg.class, + (void *) CMSG_DATA(cmsg), TRGCLS_SIZE); + + break; + + default: + err = -EINVAL; + goto out; + break; + } + } + + /* allocate one skb for each iucv message: + * this is fine for SOCK_SEQPACKET (unless we want to support + * segmented records using the MSG_EOR flag), but + * for SOCK_STREAM we might want to improve it in future */ + skb = sock_alloc_send_skb(sk, len, noblock, &err); + if (!skb) + goto out; + if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) { + err = -EFAULT; + goto fail; + } + + /* wait if outstanding messages for iucv path has reached */ + timeo = sock_sndtimeo(sk, noblock); + err = iucv_sock_wait(sk, iucv_below_msglim(sk), timeo); + if (err) + goto fail; + + /* return -ECONNRESET if the socket is no longer connected */ + if (sk->sk_state != IUCV_CONNECTED) { + err = -ECONNRESET; + goto fail; + } + + /* increment and save iucv message tag for msg_completion cbk */ + txmsg.tag = iucv->send_tag++; + memcpy(CB_TAG(skb), &txmsg.tag, CB_TAG_LEN); + skb_queue_tail(&iucv->send_skb_q, skb); + + if (((iucv->path->flags & IUCV_IPRMDATA) & iucv->flags) + && skb->len <= 7) { + err = iucv_send_iprm(iucv->path, &txmsg, skb); + + /* on success: there is no message_complete callback + * for an IPRMDATA msg; remove skb from send queue */ + if (err == 0) { + skb_unlink(skb, &iucv->send_skb_q); + kfree_skb(skb); + } + + /* this error should never happen since the + * IUCV_IPRMDATA path flag is set... sever path */ + if (err == 0x15) { + iucv_path_sever(iucv->path, NULL); skb_unlink(skb, &iucv->send_skb_q); err = -EPIPE; goto fail; } - - } else { - err = -ENOTCONN; - goto out; + } else + err = iucv_message_send(iucv->path, &txmsg, 0, 0, + (void *) skb->data, skb->len); + if (err) { + if (err == 3) { + user_id[8] = 0; + memcpy(user_id, iucv->dst_user_id, 8); + appl_id[8] = 0; + memcpy(appl_id, iucv->dst_name, 8); + pr_err("Application %s on z/VM guest %s" + " exceeds message limit\n", + appl_id, user_id); + err = -EAGAIN; + } else + err = -EPIPE; + skb_unlink(skb, &iucv->send_skb_q); + goto fail; } release_sock(sk); @@ -725,6 +1051,10 @@ static int iucv_fragment_skb(struct sock *sk, struct sk_buff *skb, int len) if (!nskb) return -ENOMEM; + /* copy target class to control buffer of new skb */ + memcpy(CB_TRGCLS(nskb), CB_TRGCLS(skb), CB_TRGCLS_LEN); + + /* copy data fragment */ memcpy(nskb->data, skb->data + copied, size); copied += size; dataleft -= size; @@ -744,19 +1074,33 @@ static void iucv_process_message(struct sock *sk, struct sk_buff *skb, struct iucv_message *msg) { int rc; + unsigned int len; - if (msg->flags & IPRMDATA) { - skb->data = NULL; - skb->len = 0; + len = iucv_msg_length(msg); + + /* store msg target class in the second 4 bytes of skb ctrl buffer */ + /* Note: the first 4 bytes are reserved for msg tag */ + memcpy(CB_TRGCLS(skb), &msg->class, CB_TRGCLS_LEN); + + /* check for special IPRM messages (e.g. iucv_sock_shutdown) */ + if ((msg->flags & IUCV_IPRMDATA) && len > 7) { + if (memcmp(msg->rmmsg, iprm_shutdown, 8) == 0) { + skb->data = NULL; + skb->len = 0; + } } else { - rc = iucv_message_receive(path, msg, 0, skb->data, - msg->length, NULL); + rc = iucv_message_receive(path, msg, msg->flags & IUCV_IPRMDATA, + skb->data, len, NULL); if (rc) { kfree_skb(skb); return; } - if (skb->truesize >= sk->sk_rcvbuf / 4) { - rc = iucv_fragment_skb(sk, skb, msg->length); + /* we need to fragment iucv messages for SOCK_STREAM only; + * for SOCK_SEQPACKET, it is only relevant if we support + * record segmentation using MSG_EOR (see also recvmsg()) */ + if (sk->sk_type == SOCK_STREAM && + skb->truesize >= sk->sk_rcvbuf / 4) { + rc = iucv_fragment_skb(sk, skb, len); kfree_skb(skb); skb = NULL; if (rc) { @@ -767,7 +1111,7 @@ static void iucv_process_message(struct sock *sk, struct sk_buff *skb, } else { skb_reset_transport_header(skb); skb_reset_network_header(skb); - skb->len = msg->length; + skb->len = len; } } @@ -782,7 +1126,7 @@ static void iucv_process_message_q(struct sock *sk) struct sock_msg_q *p, *n; list_for_each_entry_safe(p, n, &iucv->message_q.list, list) { - skb = alloc_skb(p->msg.length, GFP_ATOMIC | GFP_DMA); + skb = alloc_skb(iucv_msg_length(&p->msg), GFP_ATOMIC | GFP_DMA); if (!skb) break; iucv_process_message(sk, skb, p->path, &p->msg); @@ -799,7 +1143,7 @@ static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock, int noblock = flags & MSG_DONTWAIT; struct sock *sk = sock->sk; struct iucv_sock *iucv = iucv_sk(sk); - int target, copied = 0; + unsigned int copied, rlen; struct sk_buff *skb, *rskb, *cskb; int err = 0; @@ -812,8 +1156,6 @@ static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock, if (flags & (MSG_OOB)) return -EOPNOTSUPP; - target = sock_rcvlowat(sk, flags & MSG_WAITALL, len); - /* receive/dequeue next skb: * the function understands MSG_PEEK and, thus, does not dequeue skb */ skb = skb_recv_datagram(sk, flags, noblock, &err); @@ -823,25 +1165,45 @@ static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock, return err; } - copied = min_t(unsigned int, skb->len, len); + rlen = skb->len; /* real length of skb */ + copied = min_t(unsigned int, rlen, len); cskb = skb; if (memcpy_toiovec(msg->msg_iov, cskb->data, copied)) { - skb_queue_head(&sk->sk_receive_queue, skb); - if (copied == 0) - return -EFAULT; - goto done; + if (!(flags & MSG_PEEK)) + skb_queue_head(&sk->sk_receive_queue, skb); + return -EFAULT; } - len -= copied; + /* SOCK_SEQPACKET: set MSG_TRUNC if recv buf size is too small */ + if (sk->sk_type == SOCK_SEQPACKET) { + if (copied < rlen) + msg->msg_flags |= MSG_TRUNC; + /* each iucv message contains a complete record */ + msg->msg_flags |= MSG_EOR; + } + + /* create control message to store iucv msg target class: + * get the trgcls from the control buffer of the skb due to + * fragmentation of original iucv message. */ + err = put_cmsg(msg, SOL_IUCV, SCM_IUCV_TRGCLS, + CB_TRGCLS_LEN, CB_TRGCLS(skb)); + if (err) { + if (!(flags & MSG_PEEK)) + skb_queue_head(&sk->sk_receive_queue, skb); + return err; + } /* Mark read part of skb as used */ if (!(flags & MSG_PEEK)) { - skb_pull(skb, copied); - if (skb->len) { - skb_queue_head(&sk->sk_receive_queue, skb); - goto done; + /* SOCK_STREAM: re-queue skb if it contains unreceived data */ + if (sk->sk_type == SOCK_STREAM) { + skb_pull(skb, copied); + if (skb->len) { + skb_queue_head(&sk->sk_receive_queue, skb); + goto done; + } } kfree_skb(skb); @@ -866,7 +1228,11 @@ static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock, } done: - return err ? : copied; + /* SOCK_SEQPACKET: return real length if MSG_TRUNC is set */ + if (sk->sk_type == SOCK_SEQPACKET && (flags & MSG_TRUNC)) + copied = rlen; + + return copied; } static inline unsigned int iucv_accept_poll(struct sock *parent) @@ -928,7 +1294,6 @@ static int iucv_sock_shutdown(struct socket *sock, int how) struct iucv_sock *iucv = iucv_sk(sk); struct iucv_message txmsg; int err = 0; - u8 prmmsg[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}; how++; @@ -953,7 +1318,7 @@ static int iucv_sock_shutdown(struct socket *sock, int how) txmsg.class = 0; txmsg.tag = 0; err = iucv_message_send(iucv->path, &txmsg, IUCV_IPRMDATA, 0, - (void *) prmmsg, 8); + (void *) iprm_shutdown, 8); if (err) { switch (err) { case 1: @@ -1007,6 +1372,98 @@ static int iucv_sock_release(struct socket *sock) return err; } +/* getsockopt and setsockopt */ +static int iucv_sock_setsockopt(struct socket *sock, int level, int optname, + char __user *optval, int optlen) +{ + struct sock *sk = sock->sk; + struct iucv_sock *iucv = iucv_sk(sk); + int val; + int rc; + + if (level != SOL_IUCV) + return -ENOPROTOOPT; + + if (optlen < sizeof(int)) + return -EINVAL; + + if (get_user(val, (int __user *) optval)) + return -EFAULT; + + rc = 0; + + lock_sock(sk); + switch (optname) { + case SO_IPRMDATA_MSG: + if (val) + iucv->flags |= IUCV_IPRMDATA; + else + iucv->flags &= ~IUCV_IPRMDATA; + break; + case SO_MSGLIMIT: + switch (sk->sk_state) { + case IUCV_OPEN: + case IUCV_BOUND: + if (val < 1 || val > (u16)(~0)) + rc = -EINVAL; + else + iucv->msglimit = val; + break; + default: + rc = -EINVAL; + break; + } + break; + default: + rc = -ENOPROTOOPT; + break; + } + release_sock(sk); + + return rc; +} + +static int iucv_sock_getsockopt(struct socket *sock, int level, int optname, + char __user *optval, int __user *optlen) +{ + struct sock *sk = sock->sk; + struct iucv_sock *iucv = iucv_sk(sk); + int val, len; + + if (level != SOL_IUCV) + return -ENOPROTOOPT; + + if (get_user(len, optlen)) + return -EFAULT; + + if (len < 0) + return -EINVAL; + + len = min_t(unsigned int, len, sizeof(int)); + + switch (optname) { + case SO_IPRMDATA_MSG: + val = (iucv->flags & IUCV_IPRMDATA) ? 1 : 0; + break; + case SO_MSGLIMIT: + lock_sock(sk); + val = (iucv->path != NULL) ? iucv->path->msglim /* connected */ + : iucv->msglimit; /* default */ + release_sock(sk); + break; + default: + return -ENOPROTOOPT; + } + + if (put_user(len, optlen)) + return -EFAULT; + if (copy_to_user(optval, &val, len)) + return -EFAULT; + + return 0; +} + + /* Callback wrappers - called from iucv base support */ static int iucv_callback_connreq(struct iucv_path *path, u8 ipvmid[8], u8 ipuser[16]) @@ -1060,7 +1517,7 @@ static int iucv_callback_connreq(struct iucv_path *path, } /* Create the new socket */ - nsk = iucv_sock_alloc(NULL, SOCK_STREAM, GFP_ATOMIC); + nsk = iucv_sock_alloc(NULL, sk->sk_type, GFP_ATOMIC); if (!nsk) { err = iucv_path_sever(path, user_data); iucv_path_free(path); @@ -1083,7 +1540,9 @@ static int iucv_callback_connreq(struct iucv_path *path, memcpy(nuser_data + 8, niucv->src_name, 8); ASCEBC(nuser_data + 8, 8); - path->msglim = IUCV_QUEUELEN_DEFAULT; + /* set message limit for path based on msglimit of accepting socket */ + niucv->msglimit = iucv->msglimit; + path->msglim = iucv->msglimit; err = iucv_path_accept(path, &af_iucv_handler, nuser_data, nsk); if (err) { err = iucv_path_sever(path, user_data); @@ -1131,19 +1590,17 @@ static void iucv_callback_rx(struct iucv_path *path, struct iucv_message *msg) goto save_message; len = atomic_read(&sk->sk_rmem_alloc); - len += msg->length + sizeof(struct sk_buff); + len += iucv_msg_length(msg) + sizeof(struct sk_buff); if (len > sk->sk_rcvbuf) goto save_message; - skb = alloc_skb(msg->length, GFP_ATOMIC | GFP_DMA); + skb = alloc_skb(iucv_msg_length(msg), GFP_ATOMIC | GFP_DMA); if (!skb) goto save_message; iucv_process_message(sk, skb, path, msg); goto out_unlock; - return; - save_message: save_msg = kzalloc(sizeof(struct sock_msg_q), GFP_ATOMIC | GFP_DMA); if (!save_msg) @@ -1170,7 +1627,7 @@ static void iucv_callback_txdone(struct iucv_path *path, spin_lock_irqsave(&list->lock, flags); while (list_skb != (struct sk_buff *)list) { - if (!memcmp(&msg->tag, list_skb->cb, 4)) { + if (!memcmp(&msg->tag, CB_TAG(list_skb), CB_TAG_LEN)) { this = list_skb; break; } @@ -1181,7 +1638,11 @@ static void iucv_callback_txdone(struct iucv_path *path, spin_unlock_irqrestore(&list->lock, flags); - kfree_skb(this); + if (this) { + kfree_skb(this); + /* wake up any process waiting for sending */ + iucv_sock_wake_msglim(sk); + } } BUG_ON(!this); @@ -1206,6 +1667,21 @@ static void iucv_callback_connrej(struct iucv_path *path, u8 ipuser[16]) sk->sk_state_change(sk); } +/* called if the other communication side shuts down its RECV direction; + * in turn, the callback sets SEND_SHUTDOWN to disable sending of data. + */ +static void iucv_callback_shutdown(struct iucv_path *path, u8 ipuser[16]) +{ + struct sock *sk = path->private; + + bh_lock_sock(sk); + if (sk->sk_state != IUCV_CLOSED) { + sk->sk_shutdown |= SEND_SHUTDOWN; + sk->sk_state_change(sk); + } + bh_unlock_sock(sk); +} + static struct proto_ops iucv_sock_ops = { .family = PF_IUCV, .owner = THIS_MODULE, @@ -1222,8 +1698,8 @@ static struct proto_ops iucv_sock_ops = { .mmap = sock_no_mmap, .socketpair = sock_no_socketpair, .shutdown = iucv_sock_shutdown, - .setsockopt = sock_no_setsockopt, - .getsockopt = sock_no_getsockopt + .setsockopt = iucv_sock_setsockopt, + .getsockopt = iucv_sock_getsockopt, }; static struct net_proto_family iucv_sock_family_ops = { @@ -1258,8 +1734,30 @@ static int __init afiucv_init(void) err = sock_register(&iucv_sock_family_ops); if (err) goto out_proto; + /* establish dummy device */ + err = driver_register(&af_iucv_driver); + if (err) + goto out_sock; + af_iucv_dev = kzalloc(sizeof(struct device), GFP_KERNEL); + if (!af_iucv_dev) { + err = -ENOMEM; + goto out_driver; + } + dev_set_name(af_iucv_dev, "af_iucv"); + af_iucv_dev->bus = &iucv_bus; + af_iucv_dev->parent = iucv_root; + af_iucv_dev->release = (void (*)(struct device *))kfree; + af_iucv_dev->driver = &af_iucv_driver; + err = device_register(af_iucv_dev); + if (err) + goto out_driver; + return 0; +out_driver: + driver_unregister(&af_iucv_driver); +out_sock: + sock_unregister(PF_IUCV); out_proto: proto_unregister(&iucv_proto); out_iucv: @@ -1270,6 +1768,8 @@ out: static void __exit afiucv_exit(void) { + device_unregister(af_iucv_dev); + driver_unregister(&af_iucv_driver); sock_unregister(PF_IUCV); proto_unregister(&iucv_proto); iucv_unregister(&af_iucv_handler, 0); diff --git a/net/iucv/iucv.c b/net/iucv/iucv.c index a35240f61ec3..c833481d32e3 100644 --- a/net/iucv/iucv.c +++ b/net/iucv/iucv.c @@ -1,7 +1,8 @@ /* * IUCV base infrastructure. * - * Copyright 2001, 2006 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Copyright IBM Corp. 2001, 2009 + * * Author(s): * Original source: * Alan Altmark (Alan_Altmark@us.ibm.com) Sept. 2000 @@ -10,6 +11,8 @@ * Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com) * Rewritten for af_iucv: * Martin Schwidefsky + * PM functions: + * Ursula Braun (ursula.braun@de.ibm.com) * * Documentation used: * The original source @@ -45,6 +48,7 @@ #include #include #include +#include #include #include #include @@ -75,9 +79,24 @@ static int iucv_bus_match(struct device *dev, struct device_driver *drv) return 0; } +static int iucv_pm_prepare(struct device *); +static void iucv_pm_complete(struct device *); +static int iucv_pm_freeze(struct device *); +static int iucv_pm_thaw(struct device *); +static int iucv_pm_restore(struct device *); + +static struct dev_pm_ops iucv_pm_ops = { + .prepare = iucv_pm_prepare, + .complete = iucv_pm_complete, + .freeze = iucv_pm_freeze, + .thaw = iucv_pm_thaw, + .restore = iucv_pm_restore, +}; + struct bus_type iucv_bus = { .name = "iucv", .match = iucv_bus_match, + .pm = &iucv_pm_ops, }; EXPORT_SYMBOL(iucv_bus); @@ -147,6 +166,7 @@ enum iucv_command_codes { IUCV_RESUME = 14, IUCV_SEVER = 15, IUCV_SETMASK = 16, + IUCV_SETCONTROLMASK = 17, }; /* @@ -280,6 +300,7 @@ union iucv_param { * Anchor for per-cpu IUCV command parameter block. */ static union iucv_param *iucv_param[NR_CPUS]; +static union iucv_param *iucv_param_irq[NR_CPUS]; /** * iucv_call_b2f0 @@ -358,11 +379,23 @@ static void iucv_allow_cpu(void *data) * 0x10 - Flag to allow priority message completion interrupts * 0x08 - Flag to allow IUCV control interrupts */ - parm = iucv_param[cpu]; + parm = iucv_param_irq[cpu]; memset(parm, 0, sizeof(union iucv_param)); parm->set_mask.ipmask = 0xf8; iucv_call_b2f0(IUCV_SETMASK, parm); + /* + * Enable all iucv control interrupts. + * ipmask contains bits for the different interrupts + * 0x80 - Flag to allow pending connections interrupts + * 0x40 - Flag to allow connection complete interrupts + * 0x20 - Flag to allow connection severed interrupts + * 0x10 - Flag to allow connection quiesced interrupts + * 0x08 - Flag to allow connection resumed interrupts + */ + memset(parm, 0, sizeof(union iucv_param)); + parm->set_mask.ipmask = 0xf8; + iucv_call_b2f0(IUCV_SETCONTROLMASK, parm); /* Set indication that iucv interrupts are allowed for this cpu. */ cpu_set(cpu, iucv_irq_cpumask); } @@ -379,7 +412,7 @@ static void iucv_block_cpu(void *data) union iucv_param *parm; /* Disable all iucv interrupts. */ - parm = iucv_param[cpu]; + parm = iucv_param_irq[cpu]; memset(parm, 0, sizeof(union iucv_param)); iucv_call_b2f0(IUCV_SETMASK, parm); @@ -387,6 +420,31 @@ static void iucv_block_cpu(void *data) cpu_clear(cpu, iucv_irq_cpumask); } +/** + * iucv_block_cpu_almost + * @data: unused + * + * Allow connection-severed interrupts only on this cpu. + */ +static void iucv_block_cpu_almost(void *data) +{ + int cpu = smp_processor_id(); + union iucv_param *parm; + + /* Allow iucv control interrupts only */ + parm = iucv_param_irq[cpu]; + memset(parm, 0, sizeof(union iucv_param)); + parm->set_mask.ipmask = 0x08; + iucv_call_b2f0(IUCV_SETMASK, parm); + /* Allow iucv-severed interrupt only */ + memset(parm, 0, sizeof(union iucv_param)); + parm->set_mask.ipmask = 0x20; + iucv_call_b2f0(IUCV_SETCONTROLMASK, parm); + + /* Clear indication that iucv interrupts are allowed for this cpu. */ + cpu_clear(cpu, iucv_irq_cpumask); +} + /** * iucv_declare_cpu * @data: unused @@ -403,7 +461,7 @@ static void iucv_declare_cpu(void *data) return; /* Declare interrupt buffer. */ - parm = iucv_param[cpu]; + parm = iucv_param_irq[cpu]; memset(parm, 0, sizeof(union iucv_param)); parm->db.ipbfadr1 = virt_to_phys(iucv_irq_data[cpu]); rc = iucv_call_b2f0(IUCV_DECLARE_BUFFER, parm); @@ -460,7 +518,7 @@ static void iucv_retrieve_cpu(void *data) iucv_block_cpu(NULL); /* Retrieve interrupt buffer. */ - parm = iucv_param[cpu]; + parm = iucv_param_irq[cpu]; iucv_call_b2f0(IUCV_RETRIEVE_BUFFER, parm); /* Clear indication that an iucv buffer exists for this cpu. */ @@ -574,11 +632,22 @@ static int __cpuinit iucv_cpu_notify(struct notifier_block *self, iucv_irq_data[cpu] = NULL; return NOTIFY_BAD; } + iucv_param_irq[cpu] = kmalloc_node(sizeof(union iucv_param), + GFP_KERNEL|GFP_DMA, cpu_to_node(cpu)); + if (!iucv_param_irq[cpu]) { + kfree(iucv_param[cpu]); + iucv_param[cpu] = NULL; + kfree(iucv_irq_data[cpu]); + iucv_irq_data[cpu] = NULL; + return NOTIFY_BAD; + } break; case CPU_UP_CANCELED: case CPU_UP_CANCELED_FROZEN: case CPU_DEAD: case CPU_DEAD_FROZEN: + kfree(iucv_param_irq[cpu]); + iucv_param_irq[cpu] = NULL; kfree(iucv_param[cpu]); iucv_param[cpu] = NULL; kfree(iucv_irq_data[cpu]); @@ -625,7 +694,7 @@ static int iucv_sever_pathid(u16 pathid, u8 userdata[16]) { union iucv_param *parm; - parm = iucv_param[smp_processor_id()]; + parm = iucv_param_irq[smp_processor_id()]; memset(parm, 0, sizeof(union iucv_param)); if (userdata) memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser)); @@ -746,6 +815,28 @@ void iucv_unregister(struct iucv_handler *handler, int smp) } EXPORT_SYMBOL(iucv_unregister); +static int iucv_reboot_event(struct notifier_block *this, + unsigned long event, void *ptr) +{ + int i, rc; + + get_online_cpus(); + on_each_cpu(iucv_block_cpu, NULL, 1); + preempt_disable(); + for (i = 0; i < iucv_max_pathid; i++) { + if (iucv_path_table[i]) + rc = iucv_sever_pathid(i, NULL); + } + preempt_enable(); + put_online_cpus(); + iucv_disable(); + return NOTIFY_DONE; +} + +static struct notifier_block iucv_reboot_notifier = { + .notifier_call = iucv_reboot_event, +}; + /** * iucv_path_accept * @path: address of iucv path structure @@ -765,6 +856,10 @@ int iucv_path_accept(struct iucv_path *path, struct iucv_handler *handler, int rc; local_bh_disable(); + if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { + rc = -EIO; + goto out; + } /* Prepare parameter block. */ parm = iucv_param[smp_processor_id()]; memset(parm, 0, sizeof(union iucv_param)); @@ -780,6 +875,7 @@ int iucv_path_accept(struct iucv_path *path, struct iucv_handler *handler, path->msglim = parm->ctrl.ipmsglim; path->flags = parm->ctrl.ipflags1; } +out: local_bh_enable(); return rc; } @@ -809,6 +905,10 @@ int iucv_path_connect(struct iucv_path *path, struct iucv_handler *handler, spin_lock_bh(&iucv_table_lock); iucv_cleanup_queue(); + if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { + rc = -EIO; + goto out; + } parm = iucv_param[smp_processor_id()]; memset(parm, 0, sizeof(union iucv_param)); parm->ctrl.ipmsglim = path->msglim; @@ -843,6 +943,7 @@ int iucv_path_connect(struct iucv_path *path, struct iucv_handler *handler, rc = -EIO; } } +out: spin_unlock_bh(&iucv_table_lock); return rc; } @@ -864,12 +965,17 @@ int iucv_path_quiesce(struct iucv_path *path, u8 userdata[16]) int rc; local_bh_disable(); + if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { + rc = -EIO; + goto out; + } parm = iucv_param[smp_processor_id()]; memset(parm, 0, sizeof(union iucv_param)); if (userdata) memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser)); parm->ctrl.ippathid = path->pathid; rc = iucv_call_b2f0(IUCV_QUIESCE, parm); +out: local_bh_enable(); return rc; } @@ -891,12 +997,17 @@ int iucv_path_resume(struct iucv_path *path, u8 userdata[16]) int rc; local_bh_disable(); + if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { + rc = -EIO; + goto out; + } parm = iucv_param[smp_processor_id()]; memset(parm, 0, sizeof(union iucv_param)); if (userdata) memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser)); parm->ctrl.ippathid = path->pathid; rc = iucv_call_b2f0(IUCV_RESUME, parm); +out: local_bh_enable(); return rc; } @@ -915,15 +1026,18 @@ int iucv_path_sever(struct iucv_path *path, u8 userdata[16]) int rc; preempt_disable(); + if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { + rc = -EIO; + goto out; + } if (iucv_active_cpu != smp_processor_id()) spin_lock_bh(&iucv_table_lock); rc = iucv_sever_pathid(path->pathid, userdata); - if (!rc) { - iucv_path_table[path->pathid] = NULL; - list_del_init(&path->list); - } + iucv_path_table[path->pathid] = NULL; + list_del_init(&path->list); if (iucv_active_cpu != smp_processor_id()) spin_unlock_bh(&iucv_table_lock); +out: preempt_enable(); return rc; } @@ -946,6 +1060,10 @@ int iucv_message_purge(struct iucv_path *path, struct iucv_message *msg, int rc; local_bh_disable(); + if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { + rc = -EIO; + goto out; + } parm = iucv_param[smp_processor_id()]; memset(parm, 0, sizeof(union iucv_param)); parm->purge.ippathid = path->pathid; @@ -957,6 +1075,7 @@ int iucv_message_purge(struct iucv_path *path, struct iucv_message *msg, msg->audit = (*(u32 *) &parm->purge.ipaudit) >> 8; msg->tag = parm->purge.ipmsgtag; } +out: local_bh_enable(); return rc; } @@ -1033,6 +1152,10 @@ int __iucv_message_receive(struct iucv_path *path, struct iucv_message *msg, if (msg->flags & IUCV_IPRMDATA) return iucv_message_receive_iprmdata(path, msg, flags, buffer, size, residual); + if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { + rc = -EIO; + goto out; + } parm = iucv_param[smp_processor_id()]; memset(parm, 0, sizeof(union iucv_param)); parm->db.ipbfadr1 = (u32)(addr_t) buffer; @@ -1048,6 +1171,7 @@ int __iucv_message_receive(struct iucv_path *path, struct iucv_message *msg, if (residual) *residual = parm->db.ipbfln1f; } +out: return rc; } EXPORT_SYMBOL(__iucv_message_receive); @@ -1101,6 +1225,10 @@ int iucv_message_reject(struct iucv_path *path, struct iucv_message *msg) int rc; local_bh_disable(); + if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { + rc = -EIO; + goto out; + } parm = iucv_param[smp_processor_id()]; memset(parm, 0, sizeof(union iucv_param)); parm->db.ippathid = path->pathid; @@ -1108,6 +1236,7 @@ int iucv_message_reject(struct iucv_path *path, struct iucv_message *msg) parm->db.iptrgcls = msg->class; parm->db.ipflags1 = (IUCV_IPTRGCLS | IUCV_IPFGMID | IUCV_IPFGPID); rc = iucv_call_b2f0(IUCV_REJECT, parm); +out: local_bh_enable(); return rc; } @@ -1135,6 +1264,10 @@ int iucv_message_reply(struct iucv_path *path, struct iucv_message *msg, int rc; local_bh_disable(); + if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { + rc = -EIO; + goto out; + } parm = iucv_param[smp_processor_id()]; memset(parm, 0, sizeof(union iucv_param)); if (flags & IUCV_IPRMDATA) { @@ -1152,6 +1285,7 @@ int iucv_message_reply(struct iucv_path *path, struct iucv_message *msg, parm->db.iptrgcls = msg->class; } rc = iucv_call_b2f0(IUCV_REPLY, parm); +out: local_bh_enable(); return rc; } @@ -1180,6 +1314,10 @@ int __iucv_message_send(struct iucv_path *path, struct iucv_message *msg, union iucv_param *parm; int rc; + if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { + rc = -EIO; + goto out; + } parm = iucv_param[smp_processor_id()]; memset(parm, 0, sizeof(union iucv_param)); if (flags & IUCV_IPRMDATA) { @@ -1202,6 +1340,7 @@ int __iucv_message_send(struct iucv_path *path, struct iucv_message *msg, rc = iucv_call_b2f0(IUCV_SEND, parm); if (!rc) msg->id = parm->db.ipmsgid; +out: return rc; } EXPORT_SYMBOL(__iucv_message_send); @@ -1262,6 +1401,10 @@ int iucv_message_send2way(struct iucv_path *path, struct iucv_message *msg, int rc; local_bh_disable(); + if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { + rc = -EIO; + goto out; + } parm = iucv_param[smp_processor_id()]; memset(parm, 0, sizeof(union iucv_param)); if (flags & IUCV_IPRMDATA) { @@ -1287,6 +1430,7 @@ int iucv_message_send2way(struct iucv_path *path, struct iucv_message *msg, rc = iucv_call_b2f0(IUCV_SEND, parm); if (!rc) msg->id = parm->db.ipmsgid; +out: local_bh_enable(); return rc; } @@ -1378,6 +1522,8 @@ static void iucv_path_complete(struct iucv_irq_data *data) struct iucv_path_complete *ipc = (void *) data; struct iucv_path *path = iucv_path_table[ipc->ippathid]; + if (path) + path->flags = ipc->ipflags1; if (path && path->handler && path->handler->path_complete) path->handler->path_complete(path, ipc->ipuser); } @@ -1413,7 +1559,7 @@ static void iucv_path_severed(struct iucv_irq_data *data) else { iucv_sever_pathid(path->pathid, NULL); iucv_path_table[path->pathid] = NULL; - list_del_init(&path->list); + list_del(&path->list); iucv_path_free(path); } } @@ -1675,6 +1821,130 @@ static void iucv_external_interrupt(u16 code) spin_unlock(&iucv_queue_lock); } +static int iucv_pm_prepare(struct device *dev) +{ + int rc = 0; + +#ifdef CONFIG_PM_DEBUG + printk(KERN_INFO "iucv_pm_prepare\n"); +#endif + if (dev->driver && dev->driver->pm && dev->driver->pm->prepare) + rc = dev->driver->pm->prepare(dev); + return rc; +} + +static void iucv_pm_complete(struct device *dev) +{ +#ifdef CONFIG_PM_DEBUG + printk(KERN_INFO "iucv_pm_complete\n"); +#endif + if (dev->driver && dev->driver->pm && dev->driver->pm->complete) + dev->driver->pm->complete(dev); +} + +/** + * iucv_path_table_empty() - determine if iucv path table is empty + * + * Returns 0 if there are still iucv pathes defined + * 1 if there are no iucv pathes defined + */ +int iucv_path_table_empty(void) +{ + int i; + + for (i = 0; i < iucv_max_pathid; i++) { + if (iucv_path_table[i]) + return 0; + } + return 1; +} + +/** + * iucv_pm_freeze() - Freeze PM callback + * @dev: iucv-based device + * + * disable iucv interrupts + * invoke callback function of the iucv-based driver + * shut down iucv, if no iucv-pathes are established anymore + */ +static int iucv_pm_freeze(struct device *dev) +{ + int cpu; + int rc = 0; + +#ifdef CONFIG_PM_DEBUG + printk(KERN_WARNING "iucv_pm_freeze\n"); +#endif + for_each_cpu_mask_nr(cpu, iucv_irq_cpumask) + smp_call_function_single(cpu, iucv_block_cpu_almost, NULL, 1); + if (dev->driver && dev->driver->pm && dev->driver->pm->freeze) + rc = dev->driver->pm->freeze(dev); + if (iucv_path_table_empty()) + iucv_disable(); + return rc; +} + +/** + * iucv_pm_thaw() - Thaw PM callback + * @dev: iucv-based device + * + * make iucv ready for use again: allocate path table, declare interrupt buffers + * and enable iucv interrupts + * invoke callback function of the iucv-based driver + */ +static int iucv_pm_thaw(struct device *dev) +{ + int rc = 0; + +#ifdef CONFIG_PM_DEBUG + printk(KERN_WARNING "iucv_pm_thaw\n"); +#endif + if (!iucv_path_table) { + rc = iucv_enable(); + if (rc) + goto out; + } + if (cpus_empty(iucv_irq_cpumask)) { + if (iucv_nonsmp_handler) + /* enable interrupts on one cpu */ + iucv_allow_cpu(NULL); + else + /* enable interrupts on all cpus */ + iucv_setmask_mp(); + } + if (dev->driver && dev->driver->pm && dev->driver->pm->thaw) + rc = dev->driver->pm->thaw(dev); +out: + return rc; +} + +/** + * iucv_pm_restore() - Restore PM callback + * @dev: iucv-based device + * + * make iucv ready for use again: allocate path table, declare interrupt buffers + * and enable iucv interrupts + * invoke callback function of the iucv-based driver + */ +static int iucv_pm_restore(struct device *dev) +{ + int rc = 0; + +#ifdef CONFIG_PM_DEBUG + printk(KERN_WARNING "iucv_pm_restore %p\n", iucv_path_table); +#endif + if (cpus_empty(iucv_irq_cpumask)) { + rc = iucv_query_maxconn(); + rc = iucv_enable(); + if (rc) + goto out; + } + if (dev->driver && dev->driver->pm && dev->driver->pm->restore) + rc = dev->driver->pm->restore(dev); +out: + return rc; +} + /** * iucv_init * @@ -1717,23 +1987,37 @@ static int __init iucv_init(void) rc = -ENOMEM; goto out_free; } + iucv_param_irq[cpu] = kmalloc_node(sizeof(union iucv_param), + GFP_KERNEL|GFP_DMA, cpu_to_node(cpu)); + if (!iucv_param_irq[cpu]) { + rc = -ENOMEM; + goto out_free; + } + } rc = register_hotcpu_notifier(&iucv_cpu_notifier); if (rc) goto out_free; + rc = register_reboot_notifier(&iucv_reboot_notifier); + if (rc) + goto out_cpu; ASCEBC(iucv_error_no_listener, 16); ASCEBC(iucv_error_no_memory, 16); ASCEBC(iucv_error_pathid, 16); iucv_available = 1; rc = bus_register(&iucv_bus); if (rc) - goto out_cpu; + goto out_reboot; return 0; +out_reboot: + unregister_reboot_notifier(&iucv_reboot_notifier); out_cpu: unregister_hotcpu_notifier(&iucv_cpu_notifier); out_free: for_each_possible_cpu(cpu) { + kfree(iucv_param_irq[cpu]); + iucv_param_irq[cpu] = NULL; kfree(iucv_param[cpu]); iucv_param[cpu] = NULL; kfree(iucv_irq_data[cpu]); @@ -1762,8 +2046,11 @@ static void __exit iucv_exit(void) list_for_each_entry_safe(p, n, &iucv_work_queue, list) kfree(p); spin_unlock_irq(&iucv_queue_lock); + unregister_reboot_notifier(&iucv_reboot_notifier); unregister_hotcpu_notifier(&iucv_cpu_notifier); for_each_possible_cpu(cpu) { + kfree(iucv_param_irq[cpu]); + iucv_param_irq[cpu] = NULL; kfree(iucv_param[cpu]); iucv_param[cpu] = NULL; kfree(iucv_irq_data[cpu]); diff --git a/net/key/af_key.c b/net/key/af_key.c index 643c1be2d02e..dba9abd27f90 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -3662,8 +3662,8 @@ static int pfkey_seq_show(struct seq_file *f, void *v) seq_printf(f ,"%p %-6d %-6u %-6u %-6u %-6lu\n", s, atomic_read(&s->sk_refcnt), - atomic_read(&s->sk_rmem_alloc), - atomic_read(&s->sk_wmem_alloc), + sk_rmem_alloc_get(s), + sk_wmem_alloc_get(s), sock_i_uid(s), sock_i_ino(s) ); diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index febae702685c..9208cf5f2bd5 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c @@ -935,7 +935,7 @@ static int llc_ui_getname(struct socket *sock, struct sockaddr *uaddr, if (llc->dev) { sllc.sllc_arphrd = llc->dev->type; - memcpy(&sllc.sllc_mac, &llc->dev->dev_addr, + memcpy(&sllc.sllc_mac, llc->dev->dev_addr, IFHWADDRLEN); } } diff --git a/net/llc/llc_conn.c b/net/llc/llc_conn.c index 3477624a4906..c6bab39b018e 100644 --- a/net/llc/llc_conn.c +++ b/net/llc/llc_conn.c @@ -79,10 +79,6 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb) if (unlikely(!ev->ind_prim && !ev->cfm_prim)) { /* indicate or confirm not required */ - /* XXX this is not very pretty, perhaps we should store - * XXX indicate/confirm-needed state in the llc_conn_state_ev - * XXX control block of the SKB instead? -DaveM - */ if (!skb->next) goto out_kfree_skb; goto out_skb_put; diff --git a/net/llc/llc_proc.c b/net/llc/llc_proc.c index d208b3396d94..f97be471fe2e 100644 --- a/net/llc/llc_proc.c +++ b/net/llc/llc_proc.c @@ -134,8 +134,8 @@ static int llc_seq_socket_show(struct seq_file *seq, void *v) seq_printf(seq, "@%02X ", llc->sap->laddr.lsap); llc_ui_format_mac(seq, llc->daddr.mac); seq_printf(seq, "@%02X %8d %8d %2d %3d %4d\n", llc->daddr.lsap, - atomic_read(&sk->sk_wmem_alloc), - atomic_read(&sk->sk_rmem_alloc) - llc->copied_seq, + sk_wmem_alloc_get(sk), + sk_rmem_alloc_get(sk) - llc->copied_seq, sk->sk_state, sk->sk_socket ? SOCK_INODE(sk->sk_socket)->i_uid : -1, llc->link); diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index ecc3faf9f11a..ba2643a43c73 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig @@ -1,16 +1,35 @@ config MAC80211 tristate "Generic IEEE 802.11 Networking Stack (mac80211)" + depends on CFG80211 select CRYPTO select CRYPTO_ECB select CRYPTO_ARC4 select CRYPTO_AES select CRC32 select WIRELESS_EXT - select CFG80211 ---help--- This option enables the hardware independent IEEE 802.11 networking stack. +comment "CFG80211 needs to be enabled for MAC80211" + depends on CFG80211=n + +config MAC80211_DEFAULT_PS + bool "enable powersave by default" + depends on MAC80211 + default y + help + This option enables powersave mode by default. + + If this causes your applications to misbehave you should fix your + applications instead -- they need to register their network + latency requirement, see Documentation/power/pm_qos_interface.txt. + +config MAC80211_DEFAULT_PS_VALUE + int + default 1 if MAC80211_DEFAULT_PS + default 0 + menu "Rate control algorithm selection" depends on MAC80211 != n diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index 07656d830bc4..bc064d7933ff 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c @@ -16,12 +16,12 @@ #include #include #include "ieee80211_i.h" +#include "driver-ops.h" void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, u16 initiator, u16 reason) { struct ieee80211_local *local = sta->local; - struct ieee80211_hw *hw = &local->hw; int i; /* check if TID is in operational state */ @@ -41,8 +41,8 @@ void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, sta->sta.addr, tid); #endif /* CONFIG_MAC80211_HT_DEBUG */ - if (local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_STOP, - &sta->sta, tid, NULL)) + if (drv_ampdu_action(local, IEEE80211_AMPDU_RX_STOP, + &sta->sta, tid, NULL)) printk(KERN_DEBUG "HW problem - can not stop rx " "aggregation for tid %d\n", tid); @@ -68,6 +68,7 @@ void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, spin_lock_bh(&sta->lock); /* free resources */ kfree(sta->ampdu_mlme.tid_rx[tid]->reorder_buf); + kfree(sta->ampdu_mlme.tid_rx[tid]->reorder_time); if (!sta->ampdu_mlme.tid_rx[tid]->shutdown) { kfree(sta->ampdu_mlme.tid_rx[tid]); @@ -268,19 +269,23 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, /* prepare reordering buffer */ tid_agg_rx->reorder_buf = kcalloc(buf_size, sizeof(struct sk_buff *), GFP_ATOMIC); - if (!tid_agg_rx->reorder_buf) { + tid_agg_rx->reorder_time = + kcalloc(buf_size, sizeof(unsigned long), GFP_ATOMIC); + if (!tid_agg_rx->reorder_buf || !tid_agg_rx->reorder_time) { #ifdef CONFIG_MAC80211_HT_DEBUG if (net_ratelimit()) printk(KERN_ERR "can not allocate reordering buffer " "to tid %d\n", tid); #endif + kfree(tid_agg_rx->reorder_buf); + kfree(tid_agg_rx->reorder_time); kfree(sta->ampdu_mlme.tid_rx[tid]); + sta->ampdu_mlme.tid_rx[tid] = NULL; goto end; } - if (local->ops->ampdu_action) - ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_START, - &sta->sta, tid, &start_seq_num); + ret = drv_ampdu_action(local, IEEE80211_AMPDU_RX_START, + &sta->sta, tid, &start_seq_num); #ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "Rx A-MPDU request on tid %d result %d\n", tid, ret); #endif /* CONFIG_MAC80211_HT_DEBUG */ diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 947aaaad35d2..9e5762ad307d 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -16,6 +16,7 @@ #include #include #include "ieee80211_i.h" +#include "driver-ops.h" #include "wme.h" /** @@ -131,11 +132,14 @@ static int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, state = &sta->ampdu_mlme.tid_state_tx[tid]; + if (*state == HT_AGG_STATE_OPERATIONAL) + sta->ampdu_mlme.addba_req_num[tid] = 0; + *state = HT_AGG_STATE_REQ_STOP_BA_MSK | (initiator << HT_AGG_STATE_INITIATOR_SHIFT); - ret = local->ops->ampdu_action(&local->hw, IEEE80211_AMPDU_TX_STOP, - &sta->sta, tid, NULL); + ret = drv_ampdu_action(local, IEEE80211_AMPDU_TX_STOP, + &sta->sta, tid, NULL); /* HW shall not deny going back to legacy */ if (WARN_ON(ret)) { @@ -306,8 +310,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) start_seq_num = sta->tid_seq[tid]; - ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_START, - &sta->sta, tid, &start_seq_num); + ret = drv_ampdu_action(local, IEEE80211_AMPDU_TX_START, + &sta->sta, tid, &start_seq_num); if (ret) { #ifdef CONFIG_MAC80211_HT_DEBUG @@ -336,6 +340,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) sta->ampdu_mlme.tid_tx[tid]->dialog_token, sta->ampdu_mlme.tid_tx[tid]->ssn, 0x40, 5000); + sta->ampdu_mlme.addba_req_num[tid]++; /* activate the timer for the recipient's addBA response */ sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.expires = jiffies + ADDBA_RESP_INTERVAL; @@ -418,8 +423,8 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local, ieee80211_agg_splice_finish(local, sta, tid); spin_unlock(&local->ampdu_lock); - local->ops->ampdu_action(&local->hw, IEEE80211_AMPDU_TX_OPERATIONAL, - &sta->sta, tid, NULL); + drv_ampdu_action(local, IEEE80211_AMPDU_TX_OPERATIONAL, + &sta->sta, tid, NULL); } void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid) @@ -605,7 +610,6 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) *state = HT_AGG_STATE_IDLE; /* from now on packets are no longer put onto sta->pending */ - sta->ampdu_mlme.addba_req_num[tid] = 0; kfree(sta->ampdu_mlme.tid_tx[tid]); sta->ampdu_mlme.tid_tx[tid] = NULL; @@ -688,7 +692,6 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local, sta->ampdu_mlme.addba_req_num[tid] = 0; } else { - sta->ampdu_mlme.addba_req_num[tid]++; ___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR); } spin_unlock_bh(&sta->lock); diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index e677b751d468..3f47276caeb8 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -13,6 +13,7 @@ #include #include #include "ieee80211_i.h" +#include "driver-ops.h" #include "cfg.h" #include "rate.h" #include "mesh.h" @@ -111,7 +112,7 @@ static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex, } static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, - u8 key_idx, u8 *mac_addr, + u8 key_idx, const u8 *mac_addr, struct key_params *params) { struct ieee80211_sub_if_data *sdata; @@ -140,7 +141,8 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, return -EINVAL; } - key = ieee80211_key_alloc(alg, key_idx, params->key_len, params->key); + key = ieee80211_key_alloc(alg, key_idx, params->key_len, params->key, + params->seq_len, params->seq); if (!key) return -ENOMEM; @@ -165,7 +167,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, } static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, - u8 key_idx, u8 *mac_addr) + u8 key_idx, const u8 *mac_addr) { struct ieee80211_sub_if_data *sdata; struct sta_info *sta; @@ -207,7 +209,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, } static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, - u8 key_idx, u8 *mac_addr, void *cookie, + u8 key_idx, const u8 *mac_addr, void *cookie, void (*callback)(void *cookie, struct key_params *params)) { @@ -245,12 +247,10 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, iv32 = key->u.tkip.tx.iv32; iv16 = key->u.tkip.tx.iv16; - if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE && - sdata->local->ops->get_tkip_seq) - sdata->local->ops->get_tkip_seq( - local_to_hw(sdata->local), - key->conf.hw_key_idx, - &iv32, &iv16); + if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) + drv_get_tkip_seq(sdata->local, + key->conf.hw_key_idx, + &iv32, &iv16); seq[0] = iv16 & 0xff; seq[1] = (iv16 >> 8) & 0xff; @@ -451,18 +451,11 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata, * This is a kludge. beacon interval should really be part * of the beacon information. */ - if (params->interval && (sdata->local->hw.conf.beacon_int != - params->interval)) { - sdata->local->hw.conf.beacon_int = params->interval; - err = ieee80211_hw_config(sdata->local, - IEEE80211_CONF_CHANGE_BEACON_INTERVAL); - if (err < 0) - return err; - /* - * We updated some parameter so if below bails out - * it's not an error. - */ - err = 0; + if (params->interval && + (sdata->vif.bss_conf.beacon_int != params->interval)) { + sdata->vif.bss_conf.beacon_int = params->interval; + ieee80211_bss_info_change_notify(sdata, + BSS_CHANGED_BEACON_INT); } /* Need to have a beacon head if we don't have one yet */ @@ -528,8 +521,9 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata, kfree(old); - return ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON | - IEEE80211_IFCC_BEACON_ENABLED); + ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED | + BSS_CHANGED_BEACON); + return 0; } static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev, @@ -580,7 +574,8 @@ static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev) synchronize_rcu(); kfree(old); - return ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON_ENABLED); + ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); + return 0; } /* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */ @@ -635,35 +630,46 @@ static void sta_apply_parameters(struct ieee80211_local *local, int i, j; struct ieee80211_supported_band *sband; struct ieee80211_sub_if_data *sdata = sta->sdata; + u32 mask, set; sband = local->hw.wiphy->bands[local->oper_channel->band]; - /* - * FIXME: updating the flags is racy when this function is - * called from ieee80211_change_station(), this will - * be resolved in a future patch. - */ + spin_lock_bh(&sta->lock); + mask = params->sta_flags_mask; + set = params->sta_flags_set; - if (params->station_flags & STATION_FLAG_CHANGED) { - spin_lock_bh(&sta->lock); + if (mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) { sta->flags &= ~WLAN_STA_AUTHORIZED; - if (params->station_flags & STATION_FLAG_AUTHORIZED) + if (set & BIT(NL80211_STA_FLAG_AUTHORIZED)) sta->flags |= WLAN_STA_AUTHORIZED; - - sta->flags &= ~WLAN_STA_SHORT_PREAMBLE; - if (params->station_flags & STATION_FLAG_SHORT_PREAMBLE) - sta->flags |= WLAN_STA_SHORT_PREAMBLE; - - sta->flags &= ~WLAN_STA_WME; - if (params->station_flags & STATION_FLAG_WME) - sta->flags |= WLAN_STA_WME; - - sta->flags &= ~WLAN_STA_MFP; - if (params->station_flags & STATION_FLAG_MFP) - sta->flags |= WLAN_STA_MFP; - spin_unlock_bh(&sta->lock); } + if (mask & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) { + sta->flags &= ~WLAN_STA_SHORT_PREAMBLE; + if (set & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) + sta->flags |= WLAN_STA_SHORT_PREAMBLE; + } + + if (mask & BIT(NL80211_STA_FLAG_WME)) { + sta->flags &= ~WLAN_STA_WME; + if (set & BIT(NL80211_STA_FLAG_WME)) + sta->flags |= WLAN_STA_WME; + } + + if (mask & BIT(NL80211_STA_FLAG_MFP)) { + sta->flags &= ~WLAN_STA_MFP; + if (set & BIT(NL80211_STA_FLAG_MFP)) + sta->flags |= WLAN_STA_MFP; + } + spin_unlock_bh(&sta->lock); + + /* + * cfg80211 validates this (1-2007) and allows setting the AID + * only when creating a new station entry + */ + if (params->aid) + sta->sta.aid = params->aid; + /* * FIXME: updating the following information is racy when this * function is called from ieee80211_change_station(). @@ -671,12 +677,6 @@ static void sta_apply_parameters(struct ieee80211_local *local, * maybe we should just reject attemps to change it. */ - if (params->aid) { - sta->sta.aid = params->aid; - if (sta->sta.aid > IEEE80211_MAX_AID) - sta->sta.aid = 0; /* XXX: should this be an error? */ - } - if (params->listen_interval >= 0) sta->listen_interval = params->listen_interval; @@ -1120,10 +1120,10 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy, p.cw_max = params->cwmax; p.cw_min = params->cwmin; p.txop = params->txop; - if (local->ops->conf_tx(local_to_hw(local), params->queue, &p)) { + if (drv_conf_tx(local, params->queue, &p)) { printk(KERN_DEBUG "%s: failed to set TX queue " - "parameters for queue %d\n", local->mdev->name, - params->queue); + "parameters for queue %d\n", + wiphy_name(local->hw.wiphy), params->queue); return -EINVAL; } @@ -1167,7 +1167,8 @@ static int ieee80211_scan(struct wiphy *wiphy, if (sdata->vif.type != NL80211_IFTYPE_STATION && sdata->vif.type != NL80211_IFTYPE_ADHOC && - sdata->vif.type != NL80211_IFTYPE_MESH_POINT) + sdata->vif.type != NL80211_IFTYPE_MESH_POINT && + (sdata->vif.type != NL80211_IFTYPE_AP || sdata->u.ap.beacon)) return -EOPNOTSUPP; return ieee80211_request_scan(sdata, req); @@ -1255,9 +1256,22 @@ static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev, sdata->u.mgd.flags |= IEEE80211_STA_AUTO_SSID_SEL; ret = ieee80211_sta_set_extra_ie(sdata, req->ie, req->ie_len); - if (ret) + if (ret && ret != -EALREADY) return ret; + if (req->use_mfp) { + sdata->u.mgd.mfp = IEEE80211_MFP_REQUIRED; + sdata->u.mgd.flags |= IEEE80211_STA_MFP_ENABLED; + } else { + sdata->u.mgd.mfp = IEEE80211_MFP_DISABLED; + sdata->u.mgd.flags &= ~IEEE80211_STA_MFP_ENABLED; + } + + if (req->control_port) + sdata->u.mgd.flags |= IEEE80211_STA_CONTROL_PORT; + else + sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT; + sdata->u.mgd.flags |= IEEE80211_STA_EXT_SME; sdata->u.mgd.state = IEEE80211_STA_MLME_ASSOCIATE; ieee80211_sta_req_auth(sdata); @@ -1267,25 +1281,106 @@ static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev, static int ieee80211_deauth(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_deauth_request *req) { - struct ieee80211_sub_if_data *sdata; + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - /* TODO: req->ie */ + /* TODO: req->ie, req->peer_addr */ return ieee80211_sta_deauthenticate(sdata, req->reason_code); } static int ieee80211_disassoc(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_disassoc_request *req) { - struct ieee80211_sub_if_data *sdata; + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - /* TODO: req->ie */ + /* TODO: req->ie, req->peer_addr */ return ieee80211_sta_disassociate(sdata, req->reason_code); } +static int ieee80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_ibss_params *params) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + return ieee80211_ibss_join(sdata, params); +} + +static int ieee80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + return ieee80211_ibss_leave(sdata); +} + +static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) +{ + struct ieee80211_local *local = wiphy_priv(wiphy); + int err; + + if (changed & WIPHY_PARAM_RTS_THRESHOLD) { + err = drv_set_rts_threshold(local, wiphy->rts_threshold); + + if (err) + return err; + } + + if (changed & WIPHY_PARAM_RETRY_SHORT) + local->hw.conf.short_frame_max_tx_count = wiphy->retry_short; + if (changed & WIPHY_PARAM_RETRY_LONG) + local->hw.conf.long_frame_max_tx_count = wiphy->retry_long; + if (changed & + (WIPHY_PARAM_RETRY_SHORT | WIPHY_PARAM_RETRY_LONG)) + ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_RETRY_LIMITS); + + return 0; +} + +static int ieee80211_set_tx_power(struct wiphy *wiphy, + enum tx_power_setting type, int dbm) +{ + struct ieee80211_local *local = wiphy_priv(wiphy); + struct ieee80211_channel *chan = local->hw.conf.channel; + u32 changes = 0; + + switch (type) { + case TX_POWER_AUTOMATIC: + local->user_power_level = -1; + break; + case TX_POWER_LIMITED: + if (dbm < 0) + return -EINVAL; + local->user_power_level = dbm; + break; + case TX_POWER_FIXED: + if (dbm < 0) + return -EINVAL; + /* TODO: move to cfg80211 when it knows the channel */ + if (dbm > chan->max_power) + return -EINVAL; + local->user_power_level = dbm; + break; + } + + ieee80211_hw_config(local, changes); + + return 0; +} + +static int ieee80211_get_tx_power(struct wiphy *wiphy, int *dbm) +{ + struct ieee80211_local *local = wiphy_priv(wiphy); + + *dbm = local->hw.conf.power_level; + + return 0; +} + +static void ieee80211_rfkill_poll(struct wiphy *wiphy) +{ + struct ieee80211_local *local = wiphy_priv(wiphy); + + drv_rfkill_poll(local); +} + struct cfg80211_ops mac80211_config_ops = { .add_virtual_intf = ieee80211_add_iface, .del_virtual_intf = ieee80211_del_iface, @@ -1322,4 +1417,10 @@ struct cfg80211_ops mac80211_config_ops = { .assoc = ieee80211_assoc, .deauth = ieee80211_deauth, .disassoc = ieee80211_disassoc, + .join_ibss = ieee80211_join_ibss, + .leave_ibss = ieee80211_leave_ibss, + .set_wiphy_params = ieee80211_set_wiphy_params, + .set_tx_power = ieee80211_set_tx_power, + .get_tx_power = ieee80211_get_tx_power, + .rfkill_poll = ieee80211_rfkill_poll, }; diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 210b9b6fecd2..6c439cd5ccea 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -10,6 +10,7 @@ #include #include #include "ieee80211_i.h" +#include "driver-ops.h" #include "rate.h" #include "debugfs.h" @@ -51,14 +52,6 @@ static const struct file_operations name## _ops = { \ DEBUGFS_READONLY_FILE(frequency, 20, "%d", local->hw.conf.channel->center_freq); -DEBUGFS_READONLY_FILE(rts_threshold, 20, "%d", - local->rts_threshold); -DEBUGFS_READONLY_FILE(fragmentation_threshold, 20, "%d", - local->fragmentation_threshold); -DEBUGFS_READONLY_FILE(short_retry_limit, 20, "%d", - local->hw.conf.short_frame_max_tx_count); -DEBUGFS_READONLY_FILE(long_retry_limit, 20, "%d", - local->hw.conf.long_frame_max_tx_count); DEBUGFS_READONLY_FILE(total_ps_buffered, 20, "%d", local->total_ps_buffered); DEBUGFS_READONLY_FILE(wep_iv, 20, "%#08x", @@ -70,11 +63,10 @@ static ssize_t tsf_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct ieee80211_local *local = file->private_data; - u64 tsf = 0; + u64 tsf; char buf[100]; - if (local->ops->get_tsf) - tsf = local->ops->get_tsf(local_to_hw(local)); + tsf = drv_get_tsf(local); snprintf(buf, sizeof(buf), "0x%016llx\n", (unsigned long long) tsf); @@ -97,13 +89,13 @@ static ssize_t tsf_write(struct file *file, if (strncmp(buf, "reset", 5) == 0) { if (local->ops->reset_tsf) { - local->ops->reset_tsf(local_to_hw(local)); + drv_reset_tsf(local); printk(KERN_INFO "%s: debugfs reset TSF\n", wiphy_name(local->hw.wiphy)); } } else { tsf = simple_strtoul(buf, NULL, 0); if (local->ops->set_tsf) { - local->ops->set_tsf(local_to_hw(local), tsf); + drv_set_tsf(local, tsf); printk(KERN_INFO "%s: debugfs set TSF to %#018llx\n", wiphy_name(local->hw.wiphy), tsf); } } @@ -135,6 +127,65 @@ static const struct file_operations reset_ops = { .open = mac80211_open_file_generic, }; +static ssize_t noack_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ieee80211_local *local = file->private_data; + int res; + char buf[10]; + + res = scnprintf(buf, sizeof(buf), "%d\n", local->wifi_wme_noack_test); + + return simple_read_from_buffer(user_buf, count, ppos, buf, res); +} + +static ssize_t noack_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ieee80211_local *local = file->private_data; + char buf[10]; + size_t len; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EFAULT; + buf[len] = '\0'; + + local->wifi_wme_noack_test = !!simple_strtoul(buf, NULL, 0); + + return count; +} + +static const struct file_operations noack_ops = { + .read = noack_read, + .write = noack_write, + .open = mac80211_open_file_generic +}; + +static ssize_t queues_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ieee80211_local *local = file->private_data; + unsigned long flags; + char buf[IEEE80211_MAX_QUEUES * 20]; + int q, res = 0; + + spin_lock_irqsave(&local->queue_stop_reason_lock, flags); + for (q = 0; q < local->hw.queues; q++) + res += sprintf(buf + res, "%02d: %#.8lx/%d\n", q, + local->queue_stop_reasons[q], + __netif_subqueue_stopped(local->mdev, q)); + spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); + + return simple_read_from_buffer(user_buf, count, ppos, buf, res); +} + +static const struct file_operations queues_ops = { + .read = queues_read, + .open = mac80211_open_file_generic +}; + /* statistics stuff */ #define DEBUGFS_STATS_FILE(name, buflen, fmt, value...) \ @@ -150,14 +201,12 @@ static ssize_t format_devstat_counter(struct ieee80211_local *local, char buf[20]; int res; - if (!local->ops->get_stats) - return -EOPNOTSUPP; - rtnl_lock(); - res = local->ops->get_stats(local_to_hw(local), &stats); + res = drv_get_stats(local, &stats); rtnl_unlock(); - if (!res) - res = printvalue(&stats, buf, sizeof(buf)); + if (res) + return res; + res = printvalue(&stats, buf, sizeof(buf)); return simple_read_from_buffer(userbuf, count, ppos, buf, res); } @@ -269,14 +318,12 @@ void debugfs_hw_add(struct ieee80211_local *local) local->debugfs.keys = debugfs_create_dir("keys", phyd); DEBUGFS_ADD(frequency); - DEBUGFS_ADD(rts_threshold); - DEBUGFS_ADD(fragmentation_threshold); - DEBUGFS_ADD(short_retry_limit); - DEBUGFS_ADD(long_retry_limit); DEBUGFS_ADD(total_ps_buffered); DEBUGFS_ADD(wep_iv); DEBUGFS_ADD(tsf); + DEBUGFS_ADD(queues); DEBUGFS_ADD_MODE(reset, 0200); + DEBUGFS_ADD(noack); statsd = debugfs_create_dir("statistics", phyd); local->debugfs.statistics = statsd; @@ -324,14 +371,12 @@ void debugfs_hw_add(struct ieee80211_local *local) void debugfs_hw_del(struct ieee80211_local *local) { DEBUGFS_DEL(frequency); - DEBUGFS_DEL(rts_threshold); - DEBUGFS_DEL(fragmentation_threshold); - DEBUGFS_DEL(short_retry_limit); - DEBUGFS_DEL(long_retry_limit); DEBUGFS_DEL(total_ps_buffered); DEBUGFS_DEL(wep_iv); DEBUGFS_DEL(tsf); + DEBUGFS_DEL(queues); DEBUGFS_DEL(reset); + DEBUGFS_DEL(noack); DEBUGFS_STATS_DEL(transmitted_fragment_count); DEBUGFS_STATS_DEL(multicast_transmitted_frame_count); diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h new file mode 100644 index 000000000000..b13446afd48f --- /dev/null +++ b/net/mac80211/driver-ops.h @@ -0,0 +1,191 @@ +#ifndef __MAC80211_DRIVER_OPS +#define __MAC80211_DRIVER_OPS + +#include +#include "ieee80211_i.h" + +static inline int drv_tx(struct ieee80211_local *local, struct sk_buff *skb) +{ + return local->ops->tx(&local->hw, skb); +} + +static inline int drv_start(struct ieee80211_local *local) +{ + return local->ops->start(&local->hw); +} + +static inline void drv_stop(struct ieee80211_local *local) +{ + local->ops->stop(&local->hw); +} + +static inline int drv_add_interface(struct ieee80211_local *local, + struct ieee80211_if_init_conf *conf) +{ + return local->ops->add_interface(&local->hw, conf); +} + +static inline void drv_remove_interface(struct ieee80211_local *local, + struct ieee80211_if_init_conf *conf) +{ + local->ops->remove_interface(&local->hw, conf); +} + +static inline int drv_config(struct ieee80211_local *local, u32 changed) +{ + return local->ops->config(&local->hw, changed); +} + +static inline void drv_bss_info_changed(struct ieee80211_local *local, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, + u32 changed) +{ + if (local->ops->bss_info_changed) + local->ops->bss_info_changed(&local->hw, vif, info, changed); +} + +static inline void drv_configure_filter(struct ieee80211_local *local, + unsigned int changed_flags, + unsigned int *total_flags, + int mc_count, + struct dev_addr_list *mc_list) +{ + local->ops->configure_filter(&local->hw, changed_flags, total_flags, + mc_count, mc_list); +} + +static inline int drv_set_tim(struct ieee80211_local *local, + struct ieee80211_sta *sta, bool set) +{ + if (local->ops->set_tim) + return local->ops->set_tim(&local->hw, sta, set); + return 0; +} + +static inline int drv_set_key(struct ieee80211_local *local, + enum set_key_cmd cmd, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key) +{ + return local->ops->set_key(&local->hw, cmd, vif, sta, key); +} + +static inline void drv_update_tkip_key(struct ieee80211_local *local, + struct ieee80211_key_conf *conf, + const u8 *address, u32 iv32, + u16 *phase1key) +{ + if (local->ops->update_tkip_key) + local->ops->update_tkip_key(&local->hw, conf, address, + iv32, phase1key); +} + +static inline int drv_hw_scan(struct ieee80211_local *local, + struct cfg80211_scan_request *req) +{ + return local->ops->hw_scan(&local->hw, req); +} + +static inline void drv_sw_scan_start(struct ieee80211_local *local) +{ + if (local->ops->sw_scan_start) + local->ops->sw_scan_start(&local->hw); +} + +static inline void drv_sw_scan_complete(struct ieee80211_local *local) +{ + if (local->ops->sw_scan_complete) + local->ops->sw_scan_complete(&local->hw); +} + +static inline int drv_get_stats(struct ieee80211_local *local, + struct ieee80211_low_level_stats *stats) +{ + if (!local->ops->get_stats) + return -EOPNOTSUPP; + return local->ops->get_stats(&local->hw, stats); +} + +static inline void drv_get_tkip_seq(struct ieee80211_local *local, + u8 hw_key_idx, u32 *iv32, u16 *iv16) +{ + if (local->ops->get_tkip_seq) + local->ops->get_tkip_seq(&local->hw, hw_key_idx, iv32, iv16); +} + +static inline int drv_set_rts_threshold(struct ieee80211_local *local, + u32 value) +{ + if (local->ops->set_rts_threshold) + return local->ops->set_rts_threshold(&local->hw, value); + return 0; +} + +static inline void drv_sta_notify(struct ieee80211_local *local, + struct ieee80211_vif *vif, + enum sta_notify_cmd cmd, + struct ieee80211_sta *sta) +{ + if (local->ops->sta_notify) + local->ops->sta_notify(&local->hw, vif, cmd, sta); +} + +static inline int drv_conf_tx(struct ieee80211_local *local, u16 queue, + const struct ieee80211_tx_queue_params *params) +{ + if (local->ops->conf_tx) + return local->ops->conf_tx(&local->hw, queue, params); + return -EOPNOTSUPP; +} + +static inline int drv_get_tx_stats(struct ieee80211_local *local, + struct ieee80211_tx_queue_stats *stats) +{ + return local->ops->get_tx_stats(&local->hw, stats); +} + +static inline u64 drv_get_tsf(struct ieee80211_local *local) +{ + if (local->ops->get_tsf) + return local->ops->get_tsf(&local->hw); + return -1ULL; +} + +static inline void drv_set_tsf(struct ieee80211_local *local, u64 tsf) +{ + if (local->ops->set_tsf) + local->ops->set_tsf(&local->hw, tsf); +} + +static inline void drv_reset_tsf(struct ieee80211_local *local) +{ + if (local->ops->reset_tsf) + local->ops->reset_tsf(&local->hw); +} + +static inline int drv_tx_last_beacon(struct ieee80211_local *local) +{ + if (local->ops->tx_last_beacon) + return local->ops->tx_last_beacon(&local->hw); + return 1; +} + +static inline int drv_ampdu_action(struct ieee80211_local *local, + enum ieee80211_ampdu_mlme_action action, + struct ieee80211_sta *sta, u16 tid, + u16 *ssn) +{ + if (local->ops->ampdu_action) + return local->ops->ampdu_action(&local->hw, action, + sta, tid, ssn); + return -EOPNOTSUPP; +} + + +static inline void drv_rfkill_poll(struct ieee80211_local *local) +{ + if (local->ops->rfkill_poll) + local->ops->rfkill_poll(&local->hw); +} +#endif /* __MAC80211_DRIVER_OPS */ diff --git a/net/mac80211/event.c b/net/mac80211/event.c index 0d95561c0ee0..f288d01a6344 100644 --- a/net/mac80211/event.c +++ b/net/mac80211/event.c @@ -12,12 +12,12 @@ #include "ieee80211_i.h" /* - * indicate a failed Michael MIC to userspace; the passed packet - * (in the variable hdr) must be long enough to extract the TKIP - * fields like TSC + * Indicate a failed Michael MIC to userspace. If the caller knows the TSC of + * the frame that generated the MIC failure (i.e., if it was provided by the + * driver or is still in the frame), it should provide that information. */ void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int keyidx, - struct ieee80211_hdr *hdr) + struct ieee80211_hdr *hdr, const u8 *tsc) { union iwreq_data wrqu; char *buf = kmalloc(128, GFP_ATOMIC); @@ -34,8 +34,9 @@ void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int ke kfree(buf); } - /* - * TODO: re-add support for sending MIC failure indication - * with all info via nl80211 - */ + cfg80211_michael_mic_failure(sdata->dev, hdr->addr2, + (hdr->addr1[0] & 0x01) ? + NL80211_KEYTYPE_GROUP : + NL80211_KEYTYPE_PAIRWISE, + keyidx, tsc); } diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 4e3c72f20de7..0891bfb06996 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c @@ -14,7 +14,6 @@ */ #include -#include #include #include "ieee80211_i.h" #include "rate.h" @@ -83,89 +82,6 @@ void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband, ht_cap->mcs.rx_mask[32/8] |= 1; } -/* - * ieee80211_enable_ht should be called only after the operating band - * has been determined as ht configuration depends on the hw's - * HT abilities for a specific band. - */ -u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, - struct ieee80211_ht_info *hti, - u16 ap_ht_cap_flags) -{ - struct ieee80211_local *local = sdata->local; - struct ieee80211_supported_band *sband; - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - struct ieee80211_bss_ht_conf ht; - struct sta_info *sta; - u32 changed = 0; - bool enable_ht = true, ht_changed; - enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; - - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; - - memset(&ht, 0, sizeof(ht)); - - /* HT is not supported */ - if (!sband->ht_cap.ht_supported) - enable_ht = false; - - /* check that channel matches the right operating channel */ - if (local->hw.conf.channel->center_freq != - ieee80211_channel_to_frequency(hti->control_chan)) - enable_ht = false; - - if (enable_ht) { - channel_type = NL80211_CHAN_HT20; - - if (!(ap_ht_cap_flags & IEEE80211_HT_CAP_40MHZ_INTOLERANT) && - (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) && - (hti->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) { - switch(hti->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { - case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: - channel_type = NL80211_CHAN_HT40PLUS; - break; - case IEEE80211_HT_PARAM_CHA_SEC_BELOW: - channel_type = NL80211_CHAN_HT40MINUS; - break; - } - } - } - - ht_changed = conf_is_ht(&local->hw.conf) != enable_ht || - channel_type != local->hw.conf.channel_type; - - local->oper_channel_type = channel_type; - - if (ht_changed) { - /* channel_type change automatically detected */ - ieee80211_hw_config(local, 0); - - rcu_read_lock(); - - sta = sta_info_get(local, ifmgd->bssid); - if (sta) - rate_control_rate_update(local, sband, sta, - IEEE80211_RC_HT_CHANGED); - - rcu_read_unlock(); - - } - - /* disable HT */ - if (!enable_ht) - return 0; - - ht.operation_mode = le16_to_cpu(hti->operation_mode); - - /* if bss configuration changed store the new one */ - if (memcmp(&sdata->vif.bss_conf.ht, &ht, sizeof(ht))) { - changed |= BSS_CHANGED_HT; - sdata->vif.bss_conf.ht = ht; - } - - return changed; -} - void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta) { int i; diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 3201e1f96365..0b30277eb366 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -22,6 +22,7 @@ #include #include "ieee80211_i.h" +#include "driver-ops.h" #include "rate.h" #define IEEE80211_SCAN_INTERVAL (2 * HZ) @@ -59,74 +60,65 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata, sdata->u.ibss.bssid, 0); } -static int __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, - const u8 *bssid, const int beacon_int, - const int freq, - const size_t supp_rates_len, - const u8 *supp_rates, - const u16 capability, u64 tsf) +static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, + const u8 *bssid, const int beacon_int, + struct ieee80211_channel *chan, + const u32 basic_rates, + const u16 capability, u64 tsf) { struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; struct ieee80211_local *local = sdata->local; - int res = 0, rates, i, j; + int rates, i; struct sk_buff *skb; struct ieee80211_mgmt *mgmt; u8 *pos; struct ieee80211_supported_band *sband; - union iwreq_data wrqu; + u32 bss_change; + u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; - if (local->ops->reset_tsf) { - /* Reset own TSF to allow time synchronization work. */ - local->ops->reset_tsf(local_to_hw(local)); - } + /* Reset own TSF to allow time synchronization work. */ + drv_reset_tsf(local); - if ((ifibss->flags & IEEE80211_IBSS_PREV_BSSID_SET) && - memcmp(ifibss->bssid, bssid, ETH_ALEN) == 0) - return res; + skb = ifibss->skb; + rcu_assign_pointer(ifibss->presp, NULL); + synchronize_rcu(); + skb->data = skb->head; + skb->len = 0; + skb_reset_tail_pointer(skb); + skb_reserve(skb, sdata->local->hw.extra_tx_headroom); - skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); - if (!skb) { - printk(KERN_DEBUG "%s: failed to allocate buffer for probe " - "response\n", sdata->dev->name); - return -ENOMEM; - } - - if (!(ifibss->flags & IEEE80211_IBSS_PREV_BSSID_SET)) { - /* Remove possible STA entries from other IBSS networks. */ - sta_info_flush_delayed(sdata); - } + if (memcmp(ifibss->bssid, bssid, ETH_ALEN)) + sta_info_flush(sdata->local, sdata); memcpy(ifibss->bssid, bssid, ETH_ALEN); - res = ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID); - if (res) - return res; - local->hw.conf.beacon_int = beacon_int >= 10 ? beacon_int : 10; + sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0; - sdata->drop_unencrypted = capability & - WLAN_CAPABILITY_PRIVACY ? 1 : 0; + local->oper_channel = chan; + local->oper_channel_type = NL80211_CHAN_NO_HT; + ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); - res = ieee80211_set_freq(sdata, freq); + sband = local->hw.wiphy->bands[chan->band]; - if (res) - return res; - - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + /* build supported rates array */ + pos = supp_rates; + for (i = 0; i < sband->n_bitrates; i++) { + int rate = sband->bitrates[i].bitrate; + u8 basic = 0; + if (basic_rates & BIT(i)) + basic = 0x80; + *pos++ = basic | (u8) (rate / 5); + } /* Build IBSS probe response */ - - skb_reserve(skb, local->hw.extra_tx_headroom); - - mgmt = (struct ieee80211_mgmt *) - skb_put(skb, 24 + sizeof(mgmt->u.beacon)); + mgmt = (void *) skb_put(skb, 24 + sizeof(mgmt->u.beacon)); memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon)); mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_RESP); memset(mgmt->da, 0xff, ETH_ALEN); memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); memcpy(mgmt->bssid, ifibss->bssid, ETH_ALEN); - mgmt->u.beacon.beacon_int = - cpu_to_le16(local->hw.conf.beacon_int); + mgmt->u.beacon.beacon_int = cpu_to_le16(beacon_int); mgmt->u.beacon.timestamp = cpu_to_le64(tsf); mgmt->u.beacon.capab_info = cpu_to_le16(capability); @@ -135,7 +127,7 @@ static int __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, *pos++ = ifibss->ssid_len; memcpy(pos, ifibss->ssid, ifibss->ssid_len); - rates = supp_rates_len; + rates = sband->n_bitrates; if (rates > 8) rates = 8; pos = skb_put(skb, 2 + rates); @@ -147,7 +139,7 @@ static int __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, pos = skb_put(skb, 2 + 1); *pos++ = WLAN_EID_DS_PARAMS; *pos++ = 1; - *pos++ = ieee80211_frequency_to_channel(freq); + *pos++ = ieee80211_frequency_to_channel(chan->center_freq); } pos = skb_put(skb, 2 + 2); @@ -157,51 +149,73 @@ static int __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, *pos++ = 0; *pos++ = 0; - if (supp_rates_len > 8) { - rates = supp_rates_len - 8; + if (sband->n_bitrates > 8) { + rates = sband->n_bitrates - 8; pos = skb_put(skb, 2 + rates); *pos++ = WLAN_EID_EXT_SUPP_RATES; *pos++ = rates; memcpy(pos, &supp_rates[8], rates); } - ifibss->probe_resp = skb; + if (ifibss->ie_len) + memcpy(skb_put(skb, ifibss->ie_len), + ifibss->ie, ifibss->ie_len); - ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON | - IEEE80211_IFCC_BEACON_ENABLED); + rcu_assign_pointer(ifibss->presp, skb); + sdata->vif.bss_conf.beacon_int = beacon_int; + bss_change = BSS_CHANGED_BEACON_INT; + bss_change |= ieee80211_reset_erp_info(sdata); + bss_change |= BSS_CHANGED_BSSID; + bss_change |= BSS_CHANGED_BEACON; + bss_change |= BSS_CHANGED_BEACON_ENABLED; + ieee80211_bss_info_change_notify(sdata, bss_change); - rates = 0; - for (i = 0; i < supp_rates_len; i++) { - int bitrate = (supp_rates[i] & 0x7f) * 5; - for (j = 0; j < sband->n_bitrates; j++) - if (sband->bitrates[j].bitrate == bitrate) - rates |= BIT(j); - } + ieee80211_sta_def_wmm_params(sdata, sband->n_bitrates, supp_rates); - ieee80211_sta_def_wmm_params(sdata, supp_rates_len, supp_rates); - - ifibss->flags |= IEEE80211_IBSS_PREV_BSSID_SET; ifibss->state = IEEE80211_IBSS_MLME_JOINED; - mod_timer(&ifibss->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL); + mod_timer(&ifibss->timer, + round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL)); - memset(&wrqu, 0, sizeof(wrqu)); - memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); - wireless_send_event(sdata->dev, SIOCGIWAP, &wrqu, NULL); - - return res; + cfg80211_inform_bss_frame(local->hw.wiphy, local->hw.conf.channel, + mgmt, skb->len, 0, GFP_KERNEL); + cfg80211_ibss_joined(sdata->dev, ifibss->bssid, GFP_KERNEL); } -static int ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, - struct ieee80211_bss *bss) +static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, + struct ieee80211_bss *bss) { - return __ieee80211_sta_join_ibss(sdata, - bss->cbss.bssid, - bss->cbss.beacon_interval, - bss->cbss.channel->center_freq, - bss->supp_rates_len, bss->supp_rates, - bss->cbss.capability, - bss->cbss.tsf); + struct ieee80211_supported_band *sband; + u32 basic_rates; + int i, j; + u16 beacon_int = bss->cbss.beacon_interval; + + if (beacon_int < 10) + beacon_int = 10; + + sband = sdata->local->hw.wiphy->bands[bss->cbss.channel->band]; + + basic_rates = 0; + + for (i = 0; i < bss->supp_rates_len; i++) { + int rate = (bss->supp_rates[i] & 0x7f) * 5; + bool is_basic = !!(bss->supp_rates[i] & 0x80); + + for (j = 0; j < sband->n_bitrates; j++) { + if (sband->bitrates[j].bitrate == rate) { + if (is_basic) + basic_rates |= BIT(j); + break; + } + } + } + + __ieee80211_sta_join_ibss(sdata, bss->cbss.bssid, + beacon_int, + bss->cbss.channel, + basic_rates, + bss->cbss.capability, + bss->cbss.tsf); } static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, @@ -277,7 +291,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, goto put_bss; /* we use a fixed BSSID */ - if (sdata->u.ibss.flags & IEEE80211_IBSS_BSSID_SET) + if (sdata->u.ibss.bssid) goto put_bss; /* not an IBSS */ @@ -322,12 +336,13 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, bitrates[rx_status->rate_idx].bitrate; rx_timestamp = rx_status->mactime + (24 * 8 * 10 / rate); - } else if (local && local->ops && local->ops->get_tsf) - /* second best option: get current TSF */ - rx_timestamp = local->ops->get_tsf(local_to_hw(local)); - else - /* can't merge without knowing the TSF */ - rx_timestamp = -1LLU; + } else { + /* + * second best option: get current TSF + * (will return -1 if not supported) + */ + rx_timestamp = drv_get_tsf(local); + } #ifdef CONFIG_MAC80211_IBSS_DEBUG printk(KERN_DEBUG "RX beacon SA=%pM BSSID=" @@ -369,13 +384,14 @@ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, struct sta_info *sta; int band = local->hw.conf.channel->band; - /* TODO: Could consider removing the least recently used entry and - * allow new one to be added. */ + /* + * XXX: Consider removing the least recently used entry and + * allow new one to be added. + */ if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) { - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: No room for a new IBSS STA " - "entry %pM\n", sdata->dev->name, addr); - } + if (net_ratelimit()) + printk(KERN_DEBUG "%s: No room for a new IBSS STA entry %pM\n", + sdata->dev->name, addr); return NULL; } @@ -432,41 +448,33 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; - mod_timer(&ifibss->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL); + mod_timer(&ifibss->timer, + round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL)); ieee80211_sta_expire(sdata, IEEE80211_IBSS_INACTIVITY_LIMIT); + if (ieee80211_sta_active_ibss(sdata)) return; - if ((ifibss->flags & IEEE80211_IBSS_BSSID_SET) && - (!(ifibss->flags & IEEE80211_IBSS_AUTO_CHANNEL_SEL))) + if (ifibss->fixed_channel) return; printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other " "IBSS networks with same SSID (merge)\n", sdata->dev->name); - /* XXX maybe racy? */ - if (sdata->local->scan_req) - return; - - memcpy(sdata->local->int_scan_req.ssids[0].ssid, - ifibss->ssid, IEEE80211_MAX_SSID_LEN); - sdata->local->int_scan_req.ssids[0].ssid_len = ifibss->ssid_len; - ieee80211_request_scan(sdata, &sdata->local->int_scan_req); + ieee80211_request_internal_scan(sdata, ifibss->ssid, ifibss->ssid_len); } -static int ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) +static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; struct ieee80211_local *local = sdata->local; struct ieee80211_supported_band *sband; - u8 *pos; u8 bssid[ETH_ALEN]; - u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; u16 capability; int i; - if (ifibss->flags & IEEE80211_IBSS_BSSID_SET) { + if (ifibss->fixed_bssid) { memcpy(bssid, ifibss->bssid, ETH_ALEN); } else { /* Generate random, not broadcast, locally administered BSSID. Mix in @@ -482,10 +490,7 @@ static int ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %pM\n", sdata->dev->name, bssid); - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; - - if (local->hw.conf.beacon_int == 0) - local->hw.conf.beacon_int = 100; + sband = local->hw.wiphy->bands[ifibss->channel->band]; capability = WLAN_CAPABILITY_IBSS; @@ -494,29 +499,20 @@ static int ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) else sdata->drop_unencrypted = 0; - pos = supp_rates; - for (i = 0; i < sband->n_bitrates; i++) { - int rate = sband->bitrates[i].bitrate; - *pos++ = (u8) (rate / 5); - } - - return __ieee80211_sta_join_ibss(sdata, - bssid, local->hw.conf.beacon_int, - local->hw.conf.channel->center_freq, - sband->n_bitrates, supp_rates, - capability, 0); + __ieee80211_sta_join_ibss(sdata, bssid, sdata->vif.bss_conf.beacon_int, + ifibss->channel, 3, /* first two are basic */ + capability, 0); } -static int ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) +static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; struct ieee80211_local *local = sdata->local; struct ieee80211_bss *bss; + struct ieee80211_channel *chan = NULL; const u8 *bssid = NULL; int active_ibss; - - if (ifibss->ssid_len == 0) - return -EINVAL; + u16 capability; active_ibss = ieee80211_sta_active_ibss(sdata); #ifdef CONFIG_MAC80211_IBSS_DEBUG @@ -525,14 +521,23 @@ static int ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) #endif /* CONFIG_MAC80211_IBSS_DEBUG */ if (active_ibss) - return 0; + return; - if (ifibss->flags & IEEE80211_IBSS_BSSID_SET) + capability = WLAN_CAPABILITY_IBSS; + if (sdata->default_key) + capability |= WLAN_CAPABILITY_PRIVACY; + + if (ifibss->fixed_bssid) bssid = ifibss->bssid; - bss = (void *)cfg80211_get_bss(local->hw.wiphy, NULL, bssid, + if (ifibss->fixed_channel) + chan = ifibss->channel; + if (!is_zero_ether_addr(ifibss->bssid)) + bssid = ifibss->bssid; + bss = (void *)cfg80211_get_bss(local->hw.wiphy, chan, bssid, ifibss->ssid, ifibss->ssid_len, - WLAN_CAPABILITY_IBSS, - WLAN_CAPABILITY_IBSS); + WLAN_CAPABILITY_IBSS | + WLAN_CAPABILITY_PRIVACY, + capability); #ifdef CONFIG_MAC80211_IBSS_DEBUG if (bss) @@ -540,18 +545,14 @@ static int ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) "%pM\n", bss->cbss.bssid, ifibss->bssid); #endif /* CONFIG_MAC80211_IBSS_DEBUG */ - if (bss && - (!(ifibss->flags & IEEE80211_IBSS_PREV_BSSID_SET) || - memcmp(ifibss->bssid, bss->cbss.bssid, ETH_ALEN))) { - int ret; - + if (bss && memcmp(ifibss->bssid, bss->cbss.bssid, ETH_ALEN)) { printk(KERN_DEBUG "%s: Selected IBSS BSSID %pM" " based on configured SSID\n", sdata->dev->name, bss->cbss.bssid); - ret = ieee80211_sta_join_ibss(sdata, bss); + ieee80211_sta_join_ibss(sdata, bss); ieee80211_rx_bss_put(local, bss); - return ret; + return; } else if (bss) ieee80211_rx_bss_put(local, bss); @@ -562,29 +563,24 @@ static int ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) /* Selected IBSS not found in current scan results - try to scan */ if (ifibss->state == IEEE80211_IBSS_MLME_JOINED && !ieee80211_sta_active_ibss(sdata)) { - mod_timer(&ifibss->timer, jiffies + - IEEE80211_IBSS_MERGE_INTERVAL); - } else if (time_after(jiffies, local->last_scan_completed + + mod_timer(&ifibss->timer, + round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL)); + } else if (time_after(jiffies, ifibss->last_scan_completed + IEEE80211_SCAN_INTERVAL)) { printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to " "join\n", sdata->dev->name); - /* XXX maybe racy? */ - if (local->scan_req) - return -EBUSY; - - memcpy(local->int_scan_req.ssids[0].ssid, - ifibss->ssid, IEEE80211_MAX_SSID_LEN); - local->int_scan_req.ssids[0].ssid_len = ifibss->ssid_len; - return ieee80211_request_scan(sdata, &local->int_scan_req); + ieee80211_request_internal_scan(sdata, ifibss->ssid, + ifibss->ssid_len); } else if (ifibss->state != IEEE80211_IBSS_MLME_JOINED) { int interval = IEEE80211_SCAN_INTERVAL; if (time_after(jiffies, ifibss->ibss_join_req + IEEE80211_IBSS_JOIN_TIMEOUT)) { - if (!(local->oper_channel->flags & - IEEE80211_CHAN_NO_IBSS)) - return ieee80211_sta_create_ibss(sdata); + if (!(local->oper_channel->flags & IEEE80211_CHAN_NO_IBSS)) { + ieee80211_sta_create_ibss(sdata); + return; + } printk(KERN_DEBUG "%s: IBSS not allowed on" " %d MHz\n", sdata->dev->name, local->hw.conf.channel->center_freq); @@ -595,11 +591,9 @@ static int ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) } ifibss->state = IEEE80211_IBSS_MLME_SEARCH; - mod_timer(&ifibss->timer, jiffies + interval); - return 0; + mod_timer(&ifibss->timer, + round_jiffies(jiffies + interval)); } - - return 0; } static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, @@ -614,13 +608,10 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, u8 *pos, *end; if (ifibss->state != IEEE80211_IBSS_MLME_JOINED || - len < 24 + 2 || !ifibss->probe_resp) + len < 24 + 2 || !ifibss->presp) return; - if (local->ops->tx_last_beacon) - tx_last_beacon = local->ops->tx_last_beacon(local_to_hw(local)); - else - tx_last_beacon = 1; + tx_last_beacon = drv_tx_last_beacon(local); #ifdef CONFIG_MAC80211_IBSS_DEBUG printk(KERN_DEBUG "%s: RX ProbeReq SA=%pM DA=%pM BSSID=%pM" @@ -649,13 +640,13 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, } if (pos[1] != 0 && (pos[1] != ifibss->ssid_len || - memcmp(pos + 2, ifibss->ssid, ifibss->ssid_len) != 0)) { + !memcmp(pos + 2, ifibss->ssid, ifibss->ssid_len))) { /* Ignore ProbeReq for foreign SSID */ return; } /* Reply with ProbeResp */ - skb = skb_copy(ifibss->probe_resp, GFP_KERNEL); + skb = skb_copy(ifibss->presp, GFP_KERNEL); if (!skb) return; @@ -746,6 +737,9 @@ static void ieee80211_ibss_work(struct work_struct *work) struct ieee80211_if_ibss *ifibss; struct sk_buff *skb; + if (WARN_ON(local->suspended)) + return; + if (!netif_running(sdata->dev)) return; @@ -782,10 +776,36 @@ static void ieee80211_ibss_timer(unsigned long data) struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; struct ieee80211_local *local = sdata->local; + if (local->quiescing) { + ifibss->timer_running = true; + return; + } + set_bit(IEEE80211_IBSS_REQ_RUN, &ifibss->request); queue_work(local->hw.workqueue, &ifibss->work); } +#ifdef CONFIG_PM +void ieee80211_ibss_quiesce(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; + + cancel_work_sync(&ifibss->work); + if (del_timer_sync(&ifibss->timer)) + ifibss->timer_running = true; +} + +void ieee80211_ibss_restart(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; + + if (ifibss->timer_running) { + add_timer(&ifibss->timer); + ifibss->timer_running = false; + } +} +#endif + void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; @@ -794,89 +814,25 @@ void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata) setup_timer(&ifibss->timer, ieee80211_ibss_timer, (unsigned long) sdata); skb_queue_head_init(&ifibss->skb_queue); - - ifibss->flags |= IEEE80211_IBSS_AUTO_BSSID_SEL | - IEEE80211_IBSS_AUTO_CHANNEL_SEL; -} - -int ieee80211_ibss_commit(struct ieee80211_sub_if_data *sdata) -{ - struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; - - ifibss->flags &= ~IEEE80211_IBSS_PREV_BSSID_SET; - - if (ifibss->ssid_len) - ifibss->flags |= IEEE80211_IBSS_SSID_SET; - else - ifibss->flags &= ~IEEE80211_IBSS_SSID_SET; - - ifibss->ibss_join_req = jiffies; - ifibss->state = IEEE80211_IBSS_MLME_SEARCH; - set_bit(IEEE80211_IBSS_REQ_RUN, &ifibss->request); - - return 0; -} - -int ieee80211_ibss_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len) -{ - struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; - - if (len > IEEE80211_MAX_SSID_LEN) - return -EINVAL; - - if (ifibss->ssid_len != len || memcmp(ifibss->ssid, ssid, len) != 0) { - memset(ifibss->ssid, 0, sizeof(ifibss->ssid)); - memcpy(ifibss->ssid, ssid, len); - ifibss->ssid_len = len; - } - - return ieee80211_ibss_commit(sdata); -} - -int ieee80211_ibss_get_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t *len) -{ - struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; - - memcpy(ssid, ifibss->ssid, ifibss->ssid_len); - *len = ifibss->ssid_len; - - return 0; -} - -int ieee80211_ibss_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid) -{ - struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; - - if (is_valid_ether_addr(bssid)) { - memcpy(ifibss->bssid, bssid, ETH_ALEN); - ifibss->flags |= IEEE80211_IBSS_BSSID_SET; - } else { - memset(ifibss->bssid, 0, ETH_ALEN); - ifibss->flags &= ~IEEE80211_IBSS_BSSID_SET; - } - - if (netif_running(sdata->dev)) { - if (ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID)) { - printk(KERN_DEBUG "%s: Failed to config new BSSID to " - "the low-level driver\n", sdata->dev->name); - } - } - - return ieee80211_ibss_commit(sdata); } /* scan finished notification */ void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local) { - struct ieee80211_sub_if_data *sdata = local->scan_sdata; - struct ieee80211_if_ibss *ifibss; + struct ieee80211_sub_if_data *sdata; - if (sdata && sdata->vif.type == NL80211_IFTYPE_ADHOC) { - ifibss = &sdata->u.ibss; - if ((!(ifibss->flags & IEEE80211_IBSS_PREV_BSSID_SET)) || - !ieee80211_sta_active_ibss(sdata)) - ieee80211_sta_find_ibss(sdata); + mutex_lock(&local->iflist_mtx); + list_for_each_entry(sdata, &local->interfaces, list) { + if (!netif_running(sdata->dev)) + continue; + if (sdata->vif.type != NL80211_IFTYPE_ADHOC) + continue; + if (!sdata->u.ibss.ssid_len) + continue; + sdata->u.ibss.last_scan_completed = jiffies; + ieee80211_sta_find_ibss(sdata); } + mutex_unlock(&local->iflist_mtx); } ieee80211_rx_result @@ -906,3 +862,86 @@ ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, return RX_DROP_MONITOR; } + +int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, + struct cfg80211_ibss_params *params) +{ + struct sk_buff *skb; + + if (params->bssid) { + memcpy(sdata->u.ibss.bssid, params->bssid, ETH_ALEN); + sdata->u.ibss.fixed_bssid = true; + } else + sdata->u.ibss.fixed_bssid = false; + + sdata->vif.bss_conf.beacon_int = params->beacon_interval; + + sdata->u.ibss.channel = params->channel; + sdata->u.ibss.fixed_channel = params->channel_fixed; + + if (params->ie) { + sdata->u.ibss.ie = kmemdup(params->ie, params->ie_len, + GFP_KERNEL); + if (sdata->u.ibss.ie) + sdata->u.ibss.ie_len = params->ie_len; + } + + skb = dev_alloc_skb(sdata->local->hw.extra_tx_headroom + + 36 /* bitrates */ + + 34 /* SSID */ + + 3 /* DS params */ + + 4 /* IBSS params */ + + params->ie_len); + if (!skb) + return -ENOMEM; + + sdata->u.ibss.skb = skb; + sdata->u.ibss.state = IEEE80211_IBSS_MLME_SEARCH; + sdata->u.ibss.ibss_join_req = jiffies; + + memcpy(sdata->u.ibss.ssid, params->ssid, IEEE80211_MAX_SSID_LEN); + + /* + * The ssid_len setting below is used to see whether + * we are active, and we need all other settings + * before that may get visible. + */ + mb(); + + sdata->u.ibss.ssid_len = params->ssid_len; + + ieee80211_recalc_idle(sdata->local); + + set_bit(IEEE80211_IBSS_REQ_RUN, &sdata->u.ibss.request); + queue_work(sdata->local->hw.workqueue, &sdata->u.ibss.work); + + return 0; +} + +int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata) +{ + struct sk_buff *skb; + + del_timer_sync(&sdata->u.ibss.timer); + clear_bit(IEEE80211_IBSS_REQ_RUN, &sdata->u.ibss.request); + cancel_work_sync(&sdata->u.ibss.work); + clear_bit(IEEE80211_IBSS_REQ_RUN, &sdata->u.ibss.request); + + sta_info_flush(sdata->local, sdata); + + /* remove beacon */ + kfree(sdata->u.ibss.ie); + skb = sdata->u.ibss.presp; + rcu_assign_pointer(sdata->u.ibss.presp, NULL); + ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); + synchronize_rcu(); + kfree_skb(skb); + + skb_queue_purge(&sdata->u.ibss.skb_queue); + memset(sdata->u.ibss.bssid, 0, ETH_ALEN); + sdata->u.ibss.ssid_len = 0; + + ieee80211_recalc_idle(sdata->local); + + return 0; +} diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index e6ed78cb16b3..68eb5052179a 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include "key.h" @@ -236,7 +235,7 @@ struct mesh_preq_queue { #define IEEE80211_STA_ASSOCIATED BIT(4) #define IEEE80211_STA_PROBEREQ_POLL BIT(5) #define IEEE80211_STA_CREATE_IBSS BIT(6) -/* hole at 7, please re-use */ +#define IEEE80211_STA_CONTROL_PORT BIT(7) #define IEEE80211_STA_WMM_ENABLED BIT(8) /* hole at 9, please re-use */ #define IEEE80211_STA_AUTO_SSID_SEL BIT(10) @@ -249,9 +248,8 @@ struct mesh_preq_queue { #define IEEE80211_STA_EXT_SME BIT(17) /* flags for MLME request */ #define IEEE80211_STA_REQ_SCAN 0 -#define IEEE80211_STA_REQ_DIRECT_PROBE 1 -#define IEEE80211_STA_REQ_AUTH 2 -#define IEEE80211_STA_REQ_RUN 3 +#define IEEE80211_STA_REQ_AUTH 1 +#define IEEE80211_STA_REQ_RUN 2 /* bitfield of allowed auth algs */ #define IEEE80211_AUTH_ALG_OPEN BIT(0) @@ -295,6 +293,9 @@ struct ieee80211_if_managed { int auth_tries; /* retries for auth req */ int assoc_tries; /* retries for assoc req */ + unsigned long timers_running; /* used for quiesce/restart */ + bool powersave; /* powersave requested for this iface */ + unsigned long request; unsigned long last_probe; @@ -306,6 +307,8 @@ struct ieee80211_if_managed { int auth_alg; /* currently used IEEE 802.11 authentication algorithm */ int auth_transaction; + u32 beacon_crc; + enum { IEEE80211_MFP_DISABLED, IEEE80211_MFP_OPTIONAL, @@ -319,14 +322,6 @@ struct ieee80211_if_managed { size_t sme_auth_ie_len; }; -enum ieee80211_ibss_flags { - IEEE80211_IBSS_AUTO_CHANNEL_SEL = BIT(0), - IEEE80211_IBSS_AUTO_BSSID_SEL = BIT(1), - IEEE80211_IBSS_BSSID_SET = BIT(2), - IEEE80211_IBSS_PREV_BSSID_SET = BIT(3), - IEEE80211_IBSS_SSID_SET = BIT(4), -}; - enum ieee80211_ibss_request { IEEE80211_IBSS_REQ_RUN = 0, }; @@ -337,17 +332,23 @@ struct ieee80211_if_ibss { struct sk_buff_head skb_queue; - u8 ssid[IEEE80211_MAX_SSID_LEN]; - u8 ssid_len; + unsigned long request; + unsigned long last_scan_completed; - u32 flags; + bool timer_running; + + bool fixed_bssid; + bool fixed_channel; u8 bssid[ETH_ALEN]; - - unsigned long request; + u8 ssid[IEEE80211_MAX_SSID_LEN]; + u8 ssid_len, ie_len; + u8 *ie; + struct ieee80211_channel *channel; unsigned long ibss_join_req; - struct sk_buff *probe_resp; /* ProbeResp template for IBSS */ + /* probe response/beacon for IBSS */ + struct sk_buff *presp, *skb; enum { IEEE80211_IBSS_MLME_SEARCH, @@ -361,6 +362,8 @@ struct ieee80211_if_mesh { struct timer_list mesh_path_timer; struct sk_buff_head skb_queue; + unsigned long timers_running; + bool housekeeping; u8 mesh_id[IEEE80211_MAX_MESH_ID_LEN]; @@ -430,6 +433,12 @@ struct ieee80211_sub_if_data { int drop_unencrypted; + /* + * keep track of whether the HT opmode (stored in + * vif.bss_info.ht_operation_mode) is valid. + */ + bool ht_opmode_valid; + /* Fragment table for host-based reassembly */ struct ieee80211_fragment_entry fragments[IEEE80211_FRAGMENT_MAX]; unsigned int fragment_next; @@ -580,6 +589,7 @@ enum queue_stop_reason { IEEE80211_QUEUE_STOP_REASON_AGGREGATION, IEEE80211_QUEUE_STOP_REASON_SUSPEND, IEEE80211_QUEUE_STOP_REASON_PENDING, + IEEE80211_QUEUE_STOP_REASON_SKB_ADD, }; struct ieee80211_master_priv { @@ -606,6 +616,21 @@ struct ieee80211_local { unsigned int filter_flags; /* FIF_* */ struct iw_statistics wstats; bool tim_in_locked_section; /* see ieee80211_beacon_get() */ + + /* + * suspended is true if we finished all the suspend _and_ we have + * not yet come up from resume. This is to be used by mac80211 + * to ensure driver sanity during suspend and mac80211's own + * sanity. It can eventually be used for WoW as well. + */ + bool suspended; + + /* + * quiescing is true during the suspend process _only_ to + * ease timer cancelling etc. + */ + bool quiescing; + int tx_headroom; /* required headroom for hardware/radiotap */ /* Tasklet and skb queue to process calls from IRQ mode. All frames @@ -626,8 +651,6 @@ struct ieee80211_local { spinlock_t sta_lock; unsigned long num_sta; struct list_head sta_list; - struct list_head sta_flush_list; - struct work_struct sta_flush_work; struct sta_info *sta_hash[STA_HASH_SIZE]; struct timer_list sta_cleanup; @@ -647,9 +670,6 @@ struct ieee80211_local { struct rate_control_ref *rate_ctrl; - int rts_threshold; - int fragmentation_threshold; - struct crypto_blkcipher *wep_tx_tfm; struct crypto_blkcipher *wep_rx_tfm; u32 wep_iv; @@ -666,15 +686,18 @@ struct ieee80211_local { /* Scanning and BSS list */ + struct mutex scan_mtx; bool sw_scanning, hw_scanning; struct cfg80211_ssid scan_ssid; struct cfg80211_scan_request int_scan_req; struct cfg80211_scan_request *scan_req; struct ieee80211_channel *scan_channel; + const u8 *orig_ies; + int orig_ies_len; int scan_channel_idx; + int scan_ies_len; enum { SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state; - unsigned long last_scan_completed; struct delayed_work scan_work; struct ieee80211_sub_if_data *scan_sdata; enum nl80211_channel_type oper_channel_type; @@ -736,28 +759,33 @@ struct ieee80211_local { int wifi_wme_noack_test; unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */ - bool powersave; bool pspolling; + /* + * PS can only be enabled when we have exactly one managed + * interface (and monitors) in PS, this then points there. + */ + struct ieee80211_sub_if_data *ps_sdata; struct work_struct dynamic_ps_enable_work; struct work_struct dynamic_ps_disable_work; struct timer_list dynamic_ps_timer; + struct notifier_block network_latency_notifier; int user_power_level; /* in dBm */ int power_constr_level; /* in dBm */ + struct work_struct restart_work; + #ifdef CONFIG_MAC80211_DEBUGFS struct local_debugfsdentries { struct dentry *rcdir; struct dentry *rcname; struct dentry *frequency; - struct dentry *rts_threshold; - struct dentry *fragmentation_threshold; - struct dentry *short_retry_limit; - struct dentry *long_retry_limit; struct dentry *total_ps_buffered; struct dentry *wep_iv; struct dentry *tsf; + struct dentry *queues; struct dentry *reset; + struct dentry *noack; struct dentry *statistics; struct local_debugfsdentries_statsdentries { struct dentry *transmitted_fragment_count; @@ -830,7 +858,7 @@ struct ieee802_11_elems { u8 *fh_params; u8 *ds_params; u8 *cf_params; - u8 *tim; + struct ieee80211_tim_ie *tim; u8 *ibss_params; u8 *challenge; u8 *wpa; @@ -903,7 +931,6 @@ static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr) int ieee80211_hw_config(struct ieee80211_local *local, u32 changed); -int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed); void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx); void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, u32 changed); @@ -927,12 +954,16 @@ int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason); void ieee80211_send_pspoll(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata); +void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency); +int ieee80211_max_network_latency(struct notifier_block *nb, + unsigned long data, void *dummy); +void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, + struct ieee80211_channel_sw_ie *sw_elem, + struct ieee80211_bss *bss); +void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata); +void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata); /* IBSS code */ -int ieee80211_ibss_commit(struct ieee80211_sub_if_data *sdata); -int ieee80211_ibss_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len); -int ieee80211_ibss_get_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t *len); -int ieee80211_ibss_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid); void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local); void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata); ieee80211_rx_result @@ -940,14 +971,22 @@ ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, struct ieee80211_rx_status *rx_status); struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, u8 *bssid, u8 *addr, u32 supp_rates); +int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, + struct cfg80211_ibss_params *params); +int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata); +void ieee80211_ibss_quiesce(struct ieee80211_sub_if_data *sdata); +void ieee80211_ibss_restart(struct ieee80211_sub_if_data *sdata); /* scan/BSS handling */ void ieee80211_scan_work(struct work_struct *work); +int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata, + const u8 *ssid, u8 ssid_len); int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, struct cfg80211_scan_request *req); int ieee80211_scan_results(struct ieee80211_local *local, struct iw_request_info *info, char *buf, size_t len); +void ieee80211_scan_cancel(struct ieee80211_local *local); ieee80211_rx_result ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, @@ -956,9 +995,6 @@ int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata, const char *ie, size_t len); void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local); -void ieee80211_scan_failed(struct ieee80211_local *local); -int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata, - struct cfg80211_scan_request *req); struct ieee80211_bss * ieee80211_bss_info_update(struct ieee80211_local *local, struct ieee80211_rx_status *rx_status, @@ -983,6 +1019,8 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, enum nl80211_iftype type); void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata); void ieee80211_remove_interfaces(struct ieee80211_local *local); +u32 __ieee80211_recalc_idle(struct ieee80211_local *local); +void ieee80211_recalc_idle(struct ieee80211_local *local); /* tx handling */ void ieee80211_clear_tx_pending(struct ieee80211_local *local); @@ -995,9 +1033,6 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev); void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband, struct ieee80211_ht_cap *ht_cap_ie, struct ieee80211_sta_ht_cap *ht_cap); -u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, - struct ieee80211_ht_info *hti, - u16 ap_ht_cap_flags); void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 ssn); void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, const u8 *da, u16 tid, @@ -1027,24 +1062,23 @@ int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, size_t len); -void ieee80211_chswitch_timer(unsigned long data); -void ieee80211_chswitch_work(struct work_struct *work); -void ieee80211_process_chanswitch(struct ieee80211_sub_if_data *sdata, - struct ieee80211_channel_sw_ie *sw_elem, - struct ieee80211_bss *bss); -void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, - u16 capab_info, u8 *pwr_constr_elem, - u8 pwr_constr_elem_len); -/* Suspend/resume */ +/* Suspend/resume and hw reconfiguration */ +int ieee80211_reconfig(struct ieee80211_local *local); + #ifdef CONFIG_PM int __ieee80211_suspend(struct ieee80211_hw *hw); -int __ieee80211_resume(struct ieee80211_hw *hw); + +static inline int __ieee80211_resume(struct ieee80211_hw *hw) +{ + return ieee80211_reconfig(hw_to_local(hw)); +} #else static inline int __ieee80211_suspend(struct ieee80211_hw *hw) { return 0; } + static inline int __ieee80211_resume(struct ieee80211_hw *hw) { return 0; @@ -1053,20 +1087,20 @@ static inline int __ieee80211_resume(struct ieee80211_hw *hw) /* utility functions/constants */ extern void *mac80211_wiphy_privid; /* for wiphy privid */ -extern const unsigned char rfc1042_header[6]; -extern const unsigned char bridge_tunnel_header[6]; u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len, enum nl80211_iftype type); int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, int rate, int erp, int short_preamble); void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int keyidx, - struct ieee80211_hdr *hdr); + struct ieee80211_hdr *hdr, const u8 *tsc); void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata); void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, int encrypt); void ieee802_11_parse_elems(u8 *start, size_t len, struct ieee802_11_elems *elems); -int ieee80211_set_freq(struct ieee80211_sub_if_data *sdata, int freq); +u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, + struct ieee802_11_elems *elems, + u64 filter, u32 crc); u32 ieee80211_mandatory_rates(struct ieee80211_local *local, enum ieee80211_band band); @@ -1088,14 +1122,20 @@ void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, enum queue_stop_reason reason); void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue, enum queue_stop_reason reason); +void ieee80211_add_pending_skb(struct ieee80211_local *local, + struct sk_buff *skb); +int ieee80211_add_pending_skbs(struct ieee80211_local *local, + struct sk_buff_head *skbs); void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, u16 transaction, u16 auth_alg, u8 *extra, size_t extra_len, const u8 *bssid, int encrypt); +int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, + const u8 *ie, size_t ie_len); void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, - u8 *ssid, size_t ssid_len, - u8 *ie, size_t ie_len); + const u8 *ssid, size_t ssid_len, + const u8 *ie, size_t ie_len); void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, const size_t supp_rates_len, diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 91e8e1bacaaa..b7c8a4484298 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -20,6 +20,7 @@ #include "debugfs_netdev.h" #include "mesh.h" #include "led.h" +#include "driver-ops.h" /** * DOC: Interface list locking @@ -164,14 +165,12 @@ static int ieee80211_open(struct net_device *dev) } if (local->open_count == 0) { - res = 0; - if (local->ops->start) - res = local->ops->start(local_to_hw(local)); + res = drv_start(local); if (res) goto err_del_bss; /* we're brought up, everything changes */ hw_reconf_flags = ~0; - ieee80211_led_radio(local, local->hw.conf.radio_enabled); + ieee80211_led_radio(local, true); } /* @@ -199,8 +198,8 @@ static int ieee80211_open(struct net_device *dev) * Validate the MAC address for this device. */ if (!is_valid_ether_addr(dev->dev_addr)) { - if (!local->open_count && local->ops->stop) - local->ops->stop(local_to_hw(local)); + if (!local->open_count) + drv_stop(local); return -EADDRNOTAVAIL; } @@ -235,17 +234,13 @@ static int ieee80211_open(struct net_device *dev) netif_addr_unlock_bh(local->mdev); break; case NL80211_IFTYPE_STATION: - case NL80211_IFTYPE_ADHOC: - if (sdata->vif.type == NL80211_IFTYPE_STATION) - sdata->u.mgd.flags &= ~IEEE80211_STA_PREV_BSSID_SET; - else - sdata->u.ibss.flags &= ~IEEE80211_IBSS_PREV_BSSID_SET; + sdata->u.mgd.flags &= ~IEEE80211_STA_PREV_BSSID_SET; /* fall through */ default: conf.vif = &sdata->vif; conf.type = sdata->vif.type; conf.mac_addr = dev->dev_addr; - res = local->ops->add_interface(local_to_hw(local), &conf); + res = drv_add_interface(local, &conf); if (res) goto err_stop; @@ -306,6 +301,8 @@ static int ieee80211_open(struct net_device *dev) if (sdata->flags & IEEE80211_SDATA_PROMISC) atomic_inc(&local->iff_promiscs); + hw_reconf_flags |= __ieee80211_recalc_idle(local); + local->open_count++; if (hw_reconf_flags) { ieee80211_hw_config(local, hw_reconf_flags); @@ -317,6 +314,8 @@ static int ieee80211_open(struct net_device *dev) ieee80211_set_wmm_default(sdata); } + ieee80211_recalc_ps(local, -1); + /* * ieee80211_sta_work is disabled while network interface * is down. Therefore, some configuration changes may not @@ -325,17 +324,15 @@ static int ieee80211_open(struct net_device *dev) */ if (sdata->vif.type == NL80211_IFTYPE_STATION) queue_work(local->hw.workqueue, &sdata->u.mgd.work); - else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) - queue_work(local->hw.workqueue, &sdata->u.ibss.work); netif_tx_start_all_queues(dev); return 0; err_del_interface: - local->ops->remove_interface(local_to_hw(local), &conf); + drv_remove_interface(local, &conf); err_stop: - if (!local->open_count && local->ops->stop) - local->ops->stop(local_to_hw(local)); + if (!local->open_count) + drv_stop(local); err_del_bss: sdata->bss = NULL; if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) @@ -497,7 +494,6 @@ static int ieee80211_stop(struct net_device *dev) /* fall through */ case NL80211_IFTYPE_ADHOC: if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { - memset(sdata->u.ibss.bssid, 0, ETH_ALEN); del_timer_sync(&sdata->u.ibss.timer); cancel_work_sync(&sdata->u.ibss.work); synchronize_rcu(); @@ -549,19 +545,22 @@ static int ieee80211_stop(struct net_device *dev) conf.mac_addr = dev->dev_addr; /* disable all keys for as long as this netdev is down */ ieee80211_disable_keys(sdata); - local->ops->remove_interface(local_to_hw(local), &conf); + drv_remove_interface(local, &conf); } sdata->bss = NULL; + hw_reconf_flags |= __ieee80211_recalc_idle(local); + + ieee80211_recalc_ps(local, -1); + if (local->open_count == 0) { if (netif_running(local->mdev)) dev_close(local->mdev); - if (local->ops->stop) - local->ops->stop(local_to_hw(local)); + drv_stop(local); - ieee80211_led_radio(local, 0); + ieee80211_led_radio(local, false); flush_workqueue(local->hw.workqueue); @@ -649,7 +648,8 @@ static void ieee80211_teardown_sdata(struct net_device *dev) mesh_rmc_free(sdata); break; case NL80211_IFTYPE_ADHOC: - kfree_skb(sdata->u.ibss.probe_resp); + if (WARN_ON(sdata->u.ibss.presp)) + kfree_skb(sdata->u.ibss.presp); break; case NL80211_IFTYPE_STATION: kfree(sdata->u.mgd.extra_ie); @@ -896,3 +896,74 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local) unregister_netdevice(sdata->dev); } } + +static u32 ieee80211_idle_off(struct ieee80211_local *local, + const char *reason) +{ + if (!(local->hw.conf.flags & IEEE80211_CONF_IDLE)) + return 0; + +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG + printk(KERN_DEBUG "%s: device no longer idle - %s\n", + wiphy_name(local->hw.wiphy), reason); +#endif + + local->hw.conf.flags &= ~IEEE80211_CONF_IDLE; + return IEEE80211_CONF_CHANGE_IDLE; +} + +static u32 ieee80211_idle_on(struct ieee80211_local *local) +{ + if (local->hw.conf.flags & IEEE80211_CONF_IDLE) + return 0; + +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG + printk(KERN_DEBUG "%s: device now idle\n", + wiphy_name(local->hw.wiphy)); +#endif + + local->hw.conf.flags |= IEEE80211_CONF_IDLE; + return IEEE80211_CONF_CHANGE_IDLE; +} + +u32 __ieee80211_recalc_idle(struct ieee80211_local *local) +{ + struct ieee80211_sub_if_data *sdata; + int count = 0; + + if (local->hw_scanning || local->sw_scanning) + return ieee80211_idle_off(local, "scanning"); + + list_for_each_entry(sdata, &local->interfaces, list) { + if (!netif_running(sdata->dev)) + continue; + /* do not count disabled managed interfaces */ + if (sdata->vif.type == NL80211_IFTYPE_STATION && + sdata->u.mgd.state == IEEE80211_STA_MLME_DISABLED) + continue; + /* do not count unused IBSS interfaces */ + if (sdata->vif.type == NL80211_IFTYPE_ADHOC && + !sdata->u.ibss.ssid_len) + continue; + /* count everything else */ + count++; + } + + if (!count) + return ieee80211_idle_on(local); + else + return ieee80211_idle_off(local, "in use"); + + return 0; +} + +void ieee80211_recalc_idle(struct ieee80211_local *local) +{ + u32 chg; + + mutex_lock(&local->iflist_mtx); + chg = __ieee80211_recalc_idle(local); + mutex_unlock(&local->iflist_mtx); + if (chg) + ieee80211_hw_config(local, chg); +} diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 687acf23054d..ce267565e180 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -16,6 +16,7 @@ #include #include #include "ieee80211_i.h" +#include "driver-ops.h" #include "debugfs_key.h" #include "aes_ccm.h" #include "aes_cmac.h" @@ -136,8 +137,7 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key) struct ieee80211_sub_if_data, u.ap); - ret = key->local->ops->set_key(local_to_hw(key->local), SET_KEY, - &sdata->vif, sta, &key->conf); + ret = drv_set_key(key->local, SET_KEY, &sdata->vif, sta, &key->conf); if (!ret) { spin_lock(&todo_lock); @@ -179,8 +179,8 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) struct ieee80211_sub_if_data, u.ap); - ret = key->local->ops->set_key(local_to_hw(key->local), DISABLE_KEY, - &sdata->vif, sta, &key->conf); + ret = drv_set_key(key->local, DISABLE_KEY, &sdata->vif, + sta, &key->conf); if (ret) printk(KERN_ERR "mac80211-%s: failed to remove key " @@ -290,9 +290,11 @@ static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg, int idx, size_t key_len, - const u8 *key_data) + const u8 *key_data, + size_t seq_len, const u8 *seq) { struct ieee80211_key *key; + int i, j; BUG_ON(idx < 0 || idx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS); @@ -318,14 +320,31 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg, case ALG_TKIP: key->conf.iv_len = TKIP_IV_LEN; key->conf.icv_len = TKIP_ICV_LEN; + if (seq) { + for (i = 0; i < NUM_RX_DATA_QUEUES; i++) { + key->u.tkip.rx[i].iv32 = + get_unaligned_le32(&seq[2]); + key->u.tkip.rx[i].iv16 = + get_unaligned_le16(seq); + } + } break; case ALG_CCMP: key->conf.iv_len = CCMP_HDR_LEN; key->conf.icv_len = CCMP_MIC_LEN; + if (seq) { + for (i = 0; i < NUM_RX_DATA_QUEUES; i++) + for (j = 0; j < CCMP_PN_LEN; j++) + key->u.ccmp.rx_pn[i][j] = + seq[CCMP_PN_LEN - j - 1]; + } break; case ALG_AES_CMAC: key->conf.iv_len = 0; key->conf.icv_len = sizeof(struct ieee80211_mmie); + if (seq) + for (j = 0; j < 6; j++) + key->u.aes_cmac.rx_pn[j] = seq[6 - j - 1]; break; } memcpy(key->conf.key, key_data, key_len); diff --git a/net/mac80211/key.h b/net/mac80211/key.h index 215d3ef42a4f..9572e00f532c 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h @@ -144,7 +144,8 @@ struct ieee80211_key { struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg, int idx, size_t key_len, - const u8 *key_data); + const u8 *key_data, + size_t seq_len, const u8 *seq); /* * Insert a key into data structures (sdata, sta if necessary) * to make it used, free old key. diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 14134193cd17..092a017b237e 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -21,10 +21,12 @@ #include #include #include +#include #include #include #include "ieee80211_i.h" +#include "driver-ops.h" #include "rate.h" #include "mesh.h" #include "wep.h" @@ -80,10 +82,9 @@ void ieee80211_configure_filter(struct ieee80211_local *local) /* be a bit nasty */ new_flags |= (1<<31); - local->ops->configure_filter(local_to_hw(local), - changed_flags, &new_flags, - local->mdev->mc_count, - local->mdev->mc_list); + drv_configure_filter(local, changed_flags, &new_flags, + local->mdev->mc_count, + local->mdev->mc_list); WARN_ON(new_flags & (1<<31)); @@ -151,93 +152,19 @@ static void ieee80211_master_set_multicast_list(struct net_device *dev) ieee80211_configure_filter(local); } -/* everything else */ - -int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed) -{ - struct ieee80211_local *local = sdata->local; - struct ieee80211_if_conf conf; - - if (WARN_ON(!netif_running(sdata->dev))) - return 0; - - memset(&conf, 0, sizeof(conf)); - - if (sdata->vif.type == NL80211_IFTYPE_STATION) - conf.bssid = sdata->u.mgd.bssid; - else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) - conf.bssid = sdata->u.ibss.bssid; - else if (sdata->vif.type == NL80211_IFTYPE_AP) - conf.bssid = sdata->dev->dev_addr; - else if (ieee80211_vif_is_mesh(&sdata->vif)) { - static const u8 zero[ETH_ALEN] = { 0 }; - conf.bssid = zero; - } else { - WARN_ON(1); - return -EINVAL; - } - - if (!local->ops->config_interface) - return 0; - - switch (sdata->vif.type) { - case NL80211_IFTYPE_AP: - case NL80211_IFTYPE_ADHOC: - case NL80211_IFTYPE_MESH_POINT: - break; - default: - /* do not warn to simplify caller in scan.c */ - changed &= ~IEEE80211_IFCC_BEACON_ENABLED; - if (WARN_ON(changed & IEEE80211_IFCC_BEACON)) - return -EINVAL; - changed &= ~IEEE80211_IFCC_BEACON; - break; - } - - if (changed & IEEE80211_IFCC_BEACON_ENABLED) { - if (local->sw_scanning) { - conf.enable_beacon = false; - } else { - /* - * Beacon should be enabled, but AP mode must - * check whether there is a beacon configured. - */ - switch (sdata->vif.type) { - case NL80211_IFTYPE_AP: - conf.enable_beacon = - !!rcu_dereference(sdata->u.ap.beacon); - break; - case NL80211_IFTYPE_ADHOC: - conf.enable_beacon = !!sdata->u.ibss.probe_resp; - break; - case NL80211_IFTYPE_MESH_POINT: - conf.enable_beacon = true; - break; - default: - /* not reached */ - WARN_ON(1); - break; - } - } - } - - conf.changed = changed; - - return local->ops->config_interface(local_to_hw(local), - &sdata->vif, &conf); -} - int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) { - struct ieee80211_channel *chan; + struct ieee80211_channel *chan, *scan_chan; int ret = 0; int power; enum nl80211_channel_type channel_type; might_sleep(); - if (local->sw_scanning) { - chan = local->scan_channel; + scan_chan = local->scan_channel; + + if (scan_chan) { + chan = scan_chan; channel_type = NL80211_CHAN_NO_HT; } else { chan = local->oper_channel; @@ -251,7 +178,7 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) changed |= IEEE80211_CONF_CHANGE_CHANNEL; } - if (local->sw_scanning) + if (scan_chan) power = chan->max_power; else power = local->power_constr_level ? @@ -267,7 +194,7 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) } if (changed && local->open_count) { - ret = local->ops->config(local_to_hw(local), changed); + ret = drv_config(local, changed); /* * Goal: * HW reconfiguration should never fail, the driver has told @@ -292,18 +219,78 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, u32 changed) { struct ieee80211_local *local = sdata->local; - - if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) - return; + static const u8 zero[ETH_ALEN] = { 0 }; if (!changed) return; - if (local->ops->bss_info_changed) - local->ops->bss_info_changed(local_to_hw(local), - &sdata->vif, - &sdata->vif.bss_conf, - changed); + if (sdata->vif.type == NL80211_IFTYPE_STATION) { + /* + * While not associated, claim a BSSID of all-zeroes + * so that drivers don't do any weird things with the + * BSSID at that time. + */ + if (sdata->vif.bss_conf.assoc) + sdata->vif.bss_conf.bssid = sdata->u.mgd.bssid; + else + sdata->vif.bss_conf.bssid = zero; + } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) + sdata->vif.bss_conf.bssid = sdata->u.ibss.bssid; + else if (sdata->vif.type == NL80211_IFTYPE_AP) + sdata->vif.bss_conf.bssid = sdata->dev->dev_addr; + else if (ieee80211_vif_is_mesh(&sdata->vif)) { + sdata->vif.bss_conf.bssid = zero; + } else { + WARN_ON(1); + return; + } + + switch (sdata->vif.type) { + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_MESH_POINT: + break; + default: + /* do not warn to simplify caller in scan.c */ + changed &= ~BSS_CHANGED_BEACON_ENABLED; + if (WARN_ON(changed & BSS_CHANGED_BEACON)) + return; + break; + } + + if (changed & BSS_CHANGED_BEACON_ENABLED) { + if (local->sw_scanning) { + sdata->vif.bss_conf.enable_beacon = false; + } else { + /* + * Beacon should be enabled, but AP mode must + * check whether there is a beacon configured. + */ + switch (sdata->vif.type) { + case NL80211_IFTYPE_AP: + sdata->vif.bss_conf.enable_beacon = + !!rcu_dereference(sdata->u.ap.beacon); + break; + case NL80211_IFTYPE_ADHOC: + sdata->vif.bss_conf.enable_beacon = + !!rcu_dereference(sdata->u.ibss.presp); + break; + case NL80211_IFTYPE_MESH_POINT: + sdata->vif.bss_conf.enable_beacon = true; + break; + default: + /* not reached */ + WARN_ON(1); + break; + } + } + } + + drv_bss_info_changed(local, &sdata->vif, + &sdata->vif.bss_conf, changed); + + /* DEPRECATED */ + local->hw.conf.beacon_int = sdata->vif.bss_conf.beacon_int; } u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata) @@ -382,60 +369,12 @@ static void ieee80211_tasklet_handler(unsigned long data) } } -/* Remove added headers (e.g., QoS control), encryption header/MIC, etc. to - * make a prepared TX frame (one that has been given to hw) to look like brand - * new IEEE 802.11 frame that is ready to go through TX processing again. - */ -static void ieee80211_remove_tx_extra(struct ieee80211_local *local, - struct ieee80211_key *key, - struct sk_buff *skb) -{ - unsigned int hdrlen, iv_len, mic_len; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - - hdrlen = ieee80211_hdrlen(hdr->frame_control); - - if (!key) - goto no_key; - - switch (key->conf.alg) { - case ALG_WEP: - iv_len = WEP_IV_LEN; - mic_len = WEP_ICV_LEN; - break; - case ALG_TKIP: - iv_len = TKIP_IV_LEN; - mic_len = TKIP_ICV_LEN; - break; - case ALG_CCMP: - iv_len = CCMP_HDR_LEN; - mic_len = CCMP_MIC_LEN; - break; - default: - goto no_key; - } - - if (skb->len >= hdrlen + mic_len && - !(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) - skb_trim(skb, skb->len - mic_len); - if (skb->len >= hdrlen + iv_len) { - memmove(skb->data + iv_len, skb->data, hdrlen); - hdr = (struct ieee80211_hdr *)skb_pull(skb, iv_len); - } - -no_key: - if (ieee80211_is_data_qos(hdr->frame_control)) { - hdr->frame_control &= ~cpu_to_le16(IEEE80211_STYPE_QOS_DATA); - memmove(skb->data + IEEE80211_QOS_CTL_LEN, skb->data, - hdrlen - IEEE80211_QOS_CTL_LEN); - skb_pull(skb, IEEE80211_QOS_CTL_LEN); - } -} - static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, struct sta_info *sta, struct sk_buff *skb) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + sta->tx_filtered_count++; /* @@ -477,16 +416,15 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, */ if (test_sta_flags(sta, WLAN_STA_PS) && skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) { - ieee80211_remove_tx_extra(local, sta->key, skb); skb_queue_tail(&sta->tx_filtered, skb); return; } - if (!test_sta_flags(sta, WLAN_STA_PS) && !skb->requeue) { + if (!test_sta_flags(sta, WLAN_STA_PS) && + !(info->flags & IEEE80211_TX_INTFL_RETRIED)) { /* Software retry the packet once */ - skb->requeue = 1; - ieee80211_remove_tx_extra(local, sta->key, skb); - dev_queue_xmit(skb); + info->flags |= IEEE80211_TX_INTFL_RETRIED; + ieee80211_add_pending_skb(local, skb); return; } @@ -696,6 +634,28 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) } EXPORT_SYMBOL(ieee80211_tx_status); +static void ieee80211_restart_work(struct work_struct *work) +{ + struct ieee80211_local *local = + container_of(work, struct ieee80211_local, restart_work); + + rtnl_lock(); + ieee80211_reconfig(local); + rtnl_unlock(); +} + +void ieee80211_restart_hw(struct ieee80211_hw *hw) +{ + struct ieee80211_local *local = hw_to_local(hw); + + /* use this reason, __ieee80211_resume will unblock it */ + ieee80211_stop_queues_by_reason(hw, + IEEE80211_QUEUE_STOP_REASON_SUSPEND); + + schedule_work(&local->restart_work); +} +EXPORT_SYMBOL(ieee80211_restart_hw); + struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, const struct ieee80211_ops *ops) { @@ -718,9 +678,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, * +-------------------------+ * */ - priv_size = ((sizeof(struct ieee80211_local) + - NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST) + - priv_data_len; + priv_size = ALIGN(sizeof(*local), NETDEV_ALIGN) + priv_data_len; wiphy = wiphy_new(&mac80211_config_ops, priv_size); @@ -728,17 +686,16 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, return NULL; wiphy->privid = mac80211_wiphy_privid; - wiphy->max_scan_ssids = 4; + /* Yes, putting cfg80211_bss into ieee80211_bss is a hack */ wiphy->bss_priv_size = sizeof(struct ieee80211_bss) - sizeof(struct cfg80211_bss); local = wiphy_priv(wiphy); + local->hw.wiphy = wiphy; - local->hw.priv = (char *)local + - ((sizeof(struct ieee80211_local) + - NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST); + local->hw.priv = (char *)local + ALIGN(sizeof(*local), NETDEV_ALIGN); BUG_ON(!ops->tx); BUG_ON(!ops->start); @@ -752,15 +709,14 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, /* set up some defaults */ local->hw.queues = 1; local->hw.max_rates = 1; - local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; - local->fragmentation_threshold = IEEE80211_MAX_FRAG_THRESHOLD; - local->hw.conf.long_frame_max_tx_count = 4; - local->hw.conf.short_frame_max_tx_count = 7; + local->hw.conf.long_frame_max_tx_count = wiphy->retry_long; + local->hw.conf.short_frame_max_tx_count = wiphy->retry_short; local->hw.conf.radio_enabled = true; local->user_power_level = -1; INIT_LIST_HEAD(&local->interfaces); mutex_init(&local->iflist_mtx); + mutex_init(&local->scan_mtx); spin_lock_init(&local->key_lock); @@ -768,6 +724,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work); + INIT_WORK(&local->restart_work, ieee80211_restart_work); + INIT_WORK(&local->dynamic_ps_enable_work, ieee80211_dynamic_ps_enable_work); INIT_WORK(&local->dynamic_ps_disable_work, @@ -821,7 +779,17 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) enum ieee80211_band band; struct net_device *mdev; struct ieee80211_master_priv *mpriv; - int channels, i, j; + int channels, i, j, max_bitrates; + bool supp_ht; + static const u32 cipher_suites[] = { + WLAN_CIPHER_SUITE_WEP40, + WLAN_CIPHER_SUITE_WEP104, + WLAN_CIPHER_SUITE_TKIP, + WLAN_CIPHER_SUITE_CCMP, + + /* keep last -- depends on hw flags! */ + WLAN_CIPHER_SUITE_AES_CMAC + }; /* * generic code guarantees at least one band, @@ -829,18 +797,25 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) * that hw.conf.channel is assigned */ channels = 0; + max_bitrates = 0; + supp_ht = false; for (band = 0; band < IEEE80211_NUM_BANDS; band++) { struct ieee80211_supported_band *sband; sband = local->hw.wiphy->bands[band]; - if (sband && !local->oper_channel) { + if (!sband) + continue; + if (!local->oper_channel) { /* init channel we're on */ local->hw.conf.channel = - local->oper_channel = - local->scan_channel = &sband->channels[0]; + local->oper_channel = &sband->channels[0]; + local->hw.conf.channel_type = NL80211_CHAN_NO_HT; } - if (sband) - channels += sband->n_channels; + channels += sband->n_channels; + + if (max_bitrates < sband->n_bitrates) + max_bitrates = sband->n_bitrates; + supp_ht = supp_ht || sband->ht_cap.ht_supported; } local->int_scan_req.n_channels = channels; @@ -860,6 +835,37 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC; + /* + * Calculate scan IE length -- we need this to alloc + * memory and to subtract from the driver limit. It + * includes the (extended) supported rates and HT + * information -- SSID is the driver's responsibility. + */ + local->scan_ies_len = 4 + max_bitrates; /* (ext) supp rates */ + if (supp_ht) + local->scan_ies_len += 2 + sizeof(struct ieee80211_ht_cap); + + if (!local->ops->hw_scan) { + /* For hw_scan, driver needs to set these up. */ + local->hw.wiphy->max_scan_ssids = 4; + local->hw.wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; + } + + /* + * If the driver supports any scan IEs, then assume the + * limit includes the IEs mac80211 will add, otherwise + * leave it at zero and let the driver sort it out; we + * still pass our IEs to the driver but userspace will + * not be allowed to in that case. + */ + if (local->hw.wiphy->max_scan_ie_len) + local->hw.wiphy->max_scan_ie_len -= local->scan_ies_len; + + local->hw.wiphy->cipher_suites = cipher_suites; + local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); + if (!(local->hw.flags & IEEE80211_HW_MFP_CAPABLE)) + local->hw.wiphy->n_cipher_suites--; + result = wiphy_register(local->hw.wiphy); if (result < 0) goto fail_wiphy_register; @@ -898,9 +904,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) debugfs_hw_add(local); - if (local->hw.conf.beacon_int < 10) - local->hw.conf.beacon_int = 100; - if (local->hw.max_listen_interval == 0) local->hw.max_listen_interval = 1; @@ -965,25 +968,38 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) } } + local->network_latency_notifier.notifier_call = + ieee80211_max_network_latency; + result = pm_qos_add_notifier(PM_QOS_NETWORK_LATENCY, + &local->network_latency_notifier); + + if (result) { + rtnl_lock(); + goto fail_pm_qos; + } + return 0; -fail_rate: + fail_pm_qos: + ieee80211_led_exit(local); + ieee80211_remove_interfaces(local); + fail_rate: unregister_netdevice(local->mdev); local->mdev = NULL; -fail_dev: + fail_dev: rtnl_unlock(); ieee80211_wep_free(local); -fail_wep: + fail_wep: sta_info_stop(local); -fail_sta_info: + fail_sta_info: debugfs_hw_del(local); destroy_workqueue(local->hw.workqueue); -fail_workqueue: + fail_workqueue: if (local->mdev) free_netdev(local->mdev); -fail_mdev_alloc: + fail_mdev_alloc: wiphy_unregister(local->hw.wiphy); -fail_wiphy_register: + fail_wiphy_register: kfree(local->int_scan_req.channels); return result; } @@ -996,6 +1012,9 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) tasklet_kill(&local->tx_pending_tasklet); tasklet_kill(&local->tasklet); + pm_qos_remove_notifier(PM_QOS_NETWORK_LATENCY, + &local->network_latency_notifier); + rtnl_lock(); /* @@ -1038,6 +1057,7 @@ void ieee80211_free_hw(struct ieee80211_hw *hw) struct ieee80211_local *local = hw_to_local(hw); mutex_destroy(&local->iflist_mtx); + mutex_destroy(&local->scan_mtx); wiphy_free(local->hw.wiphy); } diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 9a3e5de0410a..fc712e60705d 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -21,6 +21,9 @@ #define CAPAB_OFFSET 17 #define ACCEPT_PLINKS 0x80 +#define TMR_RUNNING_HK 0 +#define TMR_RUNNING_MP 1 + int mesh_allocated; static struct kmem_cache *rm_cache; @@ -45,6 +48,12 @@ static void ieee80211_mesh_housekeeping_timer(unsigned long data) struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; ifmsh->housekeeping = true; + + if (local->quiescing) { + set_bit(TMR_RUNNING_HK, &ifmsh->timers_running); + return; + } + queue_work(local->hw.workqueue, &ifmsh->work); } @@ -343,6 +352,11 @@ static void ieee80211_mesh_path_timer(unsigned long data) struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct ieee80211_local *local = sdata->local; + if (local->quiescing) { + set_bit(TMR_RUNNING_MP, &ifmsh->timers_running); + return; + } + queue_work(local->hw.workqueue, &ifmsh->work); } @@ -417,13 +431,39 @@ static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata, free_plinks = mesh_plink_availables(sdata); if (free_plinks != sdata->u.mesh.accepting_plinks) - ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON); + ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); ifmsh->housekeeping = false; mod_timer(&ifmsh->housekeeping_timer, round_jiffies(jiffies + IEEE80211_MESH_HOUSEKEEPING_INTERVAL)); } +#ifdef CONFIG_PM +void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; + + /* might restart the timer but that doesn't matter */ + cancel_work_sync(&ifmsh->work); + + /* use atomic bitops in case both timers fire at the same time */ + + if (del_timer_sync(&ifmsh->housekeeping_timer)) + set_bit(TMR_RUNNING_HK, &ifmsh->timers_running); + if (del_timer_sync(&ifmsh->mesh_path_timer)) + set_bit(TMR_RUNNING_MP, &ifmsh->timers_running); +} + +void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; + + if (test_and_clear_bit(TMR_RUNNING_HK, &ifmsh->timers_running)) + add_timer(&ifmsh->housekeeping_timer); + if (test_and_clear_bit(TMR_RUNNING_MP, &ifmsh->timers_running)) + add_timer(&ifmsh->mesh_path_timer); +} +#endif void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) { @@ -432,8 +472,8 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) ifmsh->housekeeping = true; queue_work(local->hw.workqueue, &ifmsh->work); - ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON | - IEEE80211_IFCC_BEACON_ENABLED); + ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON | + BSS_CHANGED_BEACON_ENABLED); } void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index d891d7ddccd7..c7d72819cdd2 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -191,12 +191,8 @@ struct mesh_rmc { #define PLINK_CATEGORY 30 #define MESH_PATH_SEL_CATEGORY 32 -/* Mesh Header Flags */ -#define IEEE80211S_FLAGS_AE 0x3 - /* Public interfaces */ /* Various */ -int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr); int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr, struct ieee80211_sub_if_data *sdata); int mesh_rmc_check(u8 *addr, struct ieee80211s_hdr *mesh_hdr, @@ -267,6 +263,8 @@ void mesh_path_timer(unsigned long data); void mesh_path_flush_by_nexthop(struct sta_info *sta); void mesh_path_discard_frame(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata); +void mesh_path_quiesce(struct ieee80211_sub_if_data *sdata); +void mesh_path_restart(struct ieee80211_sub_if_data *sdata); #ifdef CONFIG_MAC80211_MESH extern int mesh_allocated; @@ -294,10 +292,20 @@ static inline void mesh_path_activate(struct mesh_path *mpath) void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local); +void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata); +void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata); +void mesh_plink_quiesce(struct sta_info *sta); +void mesh_plink_restart(struct sta_info *sta); #else #define mesh_allocated 0 static inline void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) {} +static inline void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata) +{} +static inline void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata) +{} +static inline void mesh_plink_quiesce(struct sta_info *sta) {} +static inline void mesh_plink_restart(struct sta_info *sta) {} #endif #endif /* IEEE80211S_H */ diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 60b35accda91..003cb470ac84 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -836,8 +836,14 @@ void mesh_path_timer(unsigned long data) mpath = rcu_dereference(mpath); if (!mpath) goto endmpathtimer; - spin_lock_bh(&mpath->state_lock); sdata = mpath->sdata; + + if (sdata->local->quiescing) { + rcu_read_unlock(); + return; + } + + spin_lock_bh(&mpath->state_lock); if (mpath->flags & MESH_PATH_RESOLVED || (!(mpath->flags & MESH_PATH_RESOLVING))) mpath->flags &= ~(MESH_PATH_RESOLVING | MESH_PATH_RESOLVED); diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index a8bbdeca013a..cb14253587f1 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -266,6 +266,11 @@ static void mesh_plink_timer(unsigned long data) */ sta = (struct sta_info *) data; + if (sta->sdata->local->quiescing) { + sta->plink_timer_was_running = true; + return; + } + spin_lock_bh(&sta->lock); if (sta->ignore_plink_timer) { sta->ignore_plink_timer = false; @@ -322,6 +327,22 @@ static void mesh_plink_timer(unsigned long data) } } +#ifdef CONFIG_PM +void mesh_plink_quiesce(struct sta_info *sta) +{ + if (del_timer_sync(&sta->plink_timer)) + sta->plink_timer_was_running = true; +} + +void mesh_plink_restart(struct sta_info *sta) +{ + if (sta->plink_timer_was_running) { + add_timer(&sta->plink_timer); + sta->plink_timer_was_running = false; + } +} +#endif + static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout) { sta->plink_timer.expires = jiffies + (HZ * timeout / 1000); diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 132938b073dc..aca22b00b6a3 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -17,10 +17,13 @@ #include #include #include +#include +#include #include #include #include "ieee80211_i.h" +#include "driver-ops.h" #include "rate.h" #include "led.h" @@ -30,9 +33,13 @@ #define IEEE80211_ASSOC_TIMEOUT (HZ / 5) #define IEEE80211_ASSOC_MAX_TRIES 3 #define IEEE80211_MONITORING_INTERVAL (2 * HZ) +#define IEEE80211_PROBE_WAIT (HZ / 5) #define IEEE80211_PROBE_IDLE_TIME (60 * HZ) #define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ) +#define TMR_RUNNING_TIMER 0 +#define TMR_RUNNING_CHANSW 1 + /* utils */ static int ecw2cw(int ecw) { @@ -80,6 +87,92 @@ static int ieee80211_compatible_rates(struct ieee80211_bss *bss, return count; } +/* + * ieee80211_enable_ht should be called only after the operating band + * has been determined as ht configuration depends on the hw's + * HT abilities for a specific band. + */ +static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, + struct ieee80211_ht_info *hti, + u16 ap_ht_cap_flags) +{ + struct ieee80211_local *local = sdata->local; + struct ieee80211_supported_band *sband; + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + struct sta_info *sta; + u32 changed = 0; + u16 ht_opmode; + bool enable_ht = true, ht_changed; + enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; + + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + + /* HT is not supported */ + if (!sband->ht_cap.ht_supported) + enable_ht = false; + + /* check that channel matches the right operating channel */ + if (local->hw.conf.channel->center_freq != + ieee80211_channel_to_frequency(hti->control_chan)) + enable_ht = false; + + if (enable_ht) { + channel_type = NL80211_CHAN_HT20; + + if (!(ap_ht_cap_flags & IEEE80211_HT_CAP_40MHZ_INTOLERANT) && + (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) && + (hti->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) { + switch(hti->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { + case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: + if (!(local->hw.conf.channel->flags & + IEEE80211_CHAN_NO_HT40PLUS)) + channel_type = NL80211_CHAN_HT40PLUS; + break; + case IEEE80211_HT_PARAM_CHA_SEC_BELOW: + if (!(local->hw.conf.channel->flags & + IEEE80211_CHAN_NO_HT40MINUS)) + channel_type = NL80211_CHAN_HT40MINUS; + break; + } + } + } + + ht_changed = conf_is_ht(&local->hw.conf) != enable_ht || + channel_type != local->hw.conf.channel_type; + + local->oper_channel_type = channel_type; + + if (ht_changed) { + /* channel_type change automatically detected */ + ieee80211_hw_config(local, 0); + + rcu_read_lock(); + + sta = sta_info_get(local, ifmgd->bssid); + if (sta) + rate_control_rate_update(local, sband, sta, + IEEE80211_RC_HT_CHANGED); + + rcu_read_unlock(); + } + + /* disable HT */ + if (!enable_ht) + return 0; + + ht_opmode = le16_to_cpu(hti->operation_mode); + + /* if bss configuration changed store the new one */ + if (!sdata->ht_opmode_valid || + sdata->vif.bss_conf.ht_operation_mode != ht_opmode) { + changed |= BSS_CHANGED_HT; + sdata->vif.bss_conf.ht_operation_mode = ht_opmode; + sdata->ht_opmode_valid = true; + } + + return changed; +} + /* frame sending functions */ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) @@ -263,13 +356,13 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: - if (flags & IEEE80211_CHAN_NO_FAT_ABOVE) { + if (flags & IEEE80211_CHAN_NO_HT40PLUS) { cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; cap &= ~IEEE80211_HT_CAP_SGI_40; } break; case IEEE80211_HT_PARAM_CHA_SEC_BELOW: - if (flags & IEEE80211_CHAN_NO_FAT_BELOW) { + if (flags & IEEE80211_CHAN_NO_HT40MINUS) { cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; cap &= ~IEEE80211_HT_CAP_SGI_40; } @@ -325,6 +418,10 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, /* u.deauth.reason_code == u.disassoc.reason_code */ mgmt->u.deauth.reason_code = cpu_to_le16(reason); + if (stype == IEEE80211_STYPE_DEAUTH) + cfg80211_send_deauth(sdata->dev, (u8 *) mgmt, skb->len); + else + cfg80211_send_disassoc(sdata->dev, (u8 *) mgmt, skb->len); ieee80211_tx_skb(sdata, skb, ifmgd->flags & IEEE80211_STA_MFP_ENABLED); } @@ -359,6 +456,277 @@ void ieee80211_send_pspoll(struct ieee80211_local *local, ieee80211_tx_skb(sdata, skb, 0); } +void ieee80211_send_nullfunc(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + int powersave) +{ + struct sk_buff *skb; + struct ieee80211_hdr *nullfunc; + __le16 fc; + + if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) + return; + + skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24); + if (!skb) { + printk(KERN_DEBUG "%s: failed to allocate buffer for nullfunc " + "frame\n", sdata->dev->name); + return; + } + skb_reserve(skb, local->hw.extra_tx_headroom); + + nullfunc = (struct ieee80211_hdr *) skb_put(skb, 24); + memset(nullfunc, 0, 24); + fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC | + IEEE80211_FCTL_TODS); + if (powersave) + fc |= cpu_to_le16(IEEE80211_FCTL_PM); + nullfunc->frame_control = fc; + memcpy(nullfunc->addr1, sdata->u.mgd.bssid, ETH_ALEN); + memcpy(nullfunc->addr2, sdata->dev->dev_addr, ETH_ALEN); + memcpy(nullfunc->addr3, sdata->u.mgd.bssid, ETH_ALEN); + + ieee80211_tx_skb(sdata, skb, 0); +} + +/* spectrum management related things */ +static void ieee80211_chswitch_work(struct work_struct *work) +{ + struct ieee80211_sub_if_data *sdata = + container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work); + struct ieee80211_bss *bss; + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + + if (!netif_running(sdata->dev)) + return; + + bss = ieee80211_rx_bss_get(sdata->local, ifmgd->bssid, + sdata->local->hw.conf.channel->center_freq, + ifmgd->ssid, ifmgd->ssid_len); + if (!bss) + goto exit; + + sdata->local->oper_channel = sdata->local->csa_channel; + /* XXX: shouldn't really modify cfg80211-owned data! */ + if (!ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL)) + bss->cbss.channel = sdata->local->oper_channel; + + ieee80211_rx_bss_put(sdata->local, bss); +exit: + ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; + ieee80211_wake_queues_by_reason(&sdata->local->hw, + IEEE80211_QUEUE_STOP_REASON_CSA); +} + +static void ieee80211_chswitch_timer(unsigned long data) +{ + struct ieee80211_sub_if_data *sdata = + (struct ieee80211_sub_if_data *) data; + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + + if (sdata->local->quiescing) { + set_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running); + return; + } + + queue_work(sdata->local->hw.workqueue, &ifmgd->chswitch_work); +} + +void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, + struct ieee80211_channel_sw_ie *sw_elem, + struct ieee80211_bss *bss) +{ + struct ieee80211_channel *new_ch; + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num); + + if (ifmgd->state != IEEE80211_STA_MLME_ASSOCIATED) + return; + + if (sdata->local->sw_scanning || sdata->local->hw_scanning) + return; + + /* Disregard subsequent beacons if we are already running a timer + processing a CSA */ + + if (ifmgd->flags & IEEE80211_STA_CSA_RECEIVED) + return; + + new_ch = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq); + if (!new_ch || new_ch->flags & IEEE80211_CHAN_DISABLED) + return; + + sdata->local->csa_channel = new_ch; + + if (sw_elem->count <= 1) { + queue_work(sdata->local->hw.workqueue, &ifmgd->chswitch_work); + } else { + ieee80211_stop_queues_by_reason(&sdata->local->hw, + IEEE80211_QUEUE_STOP_REASON_CSA); + ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; + mod_timer(&ifmgd->chswitch_timer, + jiffies + + msecs_to_jiffies(sw_elem->count * + bss->cbss.beacon_interval)); + } +} + +static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, + u16 capab_info, u8 *pwr_constr_elem, + u8 pwr_constr_elem_len) +{ + struct ieee80211_conf *conf = &sdata->local->hw.conf; + + if (!(capab_info & WLAN_CAPABILITY_SPECTRUM_MGMT)) + return; + + /* Power constraint IE length should be 1 octet */ + if (pwr_constr_elem_len != 1) + return; + + if ((*pwr_constr_elem <= conf->channel->max_power) && + (*pwr_constr_elem != sdata->local->power_constr_level)) { + sdata->local->power_constr_level = *pwr_constr_elem; + ieee80211_hw_config(sdata->local, 0); + } +} + +/* powersave */ +static void ieee80211_enable_ps(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_conf *conf = &local->hw.conf; + + /* + * If we are scanning right now then the parameters will + * take effect when scan finishes. + */ + if (local->hw_scanning || local->sw_scanning) + return; + + if (conf->dynamic_ps_timeout > 0 && + !(local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)) { + mod_timer(&local->dynamic_ps_timer, jiffies + + msecs_to_jiffies(conf->dynamic_ps_timeout)); + } else { + if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) + ieee80211_send_nullfunc(local, sdata, 1); + conf->flags |= IEEE80211_CONF_PS; + ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); + } +} + +static void ieee80211_change_ps(struct ieee80211_local *local) +{ + struct ieee80211_conf *conf = &local->hw.conf; + + if (local->ps_sdata) { + ieee80211_enable_ps(local, local->ps_sdata); + } else if (conf->flags & IEEE80211_CONF_PS) { + conf->flags &= ~IEEE80211_CONF_PS; + ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); + del_timer_sync(&local->dynamic_ps_timer); + cancel_work_sync(&local->dynamic_ps_enable_work); + } +} + +/* need to hold RTNL or interface lock */ +void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) +{ + struct ieee80211_sub_if_data *sdata, *found = NULL; + int count = 0; + + if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS)) { + local->ps_sdata = NULL; + return; + } + + list_for_each_entry(sdata, &local->interfaces, list) { + if (!netif_running(sdata->dev)) + continue; + if (sdata->vif.type != NL80211_IFTYPE_STATION) + continue; + found = sdata; + count++; + } + + if (count == 1 && found->u.mgd.powersave && + (found->u.mgd.flags & IEEE80211_STA_ASSOCIATED) && + !(found->u.mgd.flags & IEEE80211_STA_PROBEREQ_POLL)) { + s32 beaconint_us; + + if (latency < 0) + latency = pm_qos_requirement(PM_QOS_NETWORK_LATENCY); + + beaconint_us = ieee80211_tu_to_usec( + found->vif.bss_conf.beacon_int); + + if (beaconint_us > latency) { + local->ps_sdata = NULL; + } else { + u8 dtimper = found->vif.bss_conf.dtim_period; + int maxslp = 1; + + if (dtimper > 1) + maxslp = min_t(int, dtimper, + latency / beaconint_us); + + local->hw.conf.max_sleep_period = maxslp; + local->ps_sdata = found; + } + } else { + local->ps_sdata = NULL; + } + + ieee80211_change_ps(local); +} + +void ieee80211_dynamic_ps_disable_work(struct work_struct *work) +{ + struct ieee80211_local *local = + container_of(work, struct ieee80211_local, + dynamic_ps_disable_work); + + if (local->hw.conf.flags & IEEE80211_CONF_PS) { + local->hw.conf.flags &= ~IEEE80211_CONF_PS; + ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); + } + + ieee80211_wake_queues_by_reason(&local->hw, + IEEE80211_QUEUE_STOP_REASON_PS); +} + +void ieee80211_dynamic_ps_enable_work(struct work_struct *work) +{ + struct ieee80211_local *local = + container_of(work, struct ieee80211_local, + dynamic_ps_enable_work); + struct ieee80211_sub_if_data *sdata = local->ps_sdata; + + /* can only happen when PS was just disabled anyway */ + if (!sdata) + return; + + if (local->hw.conf.flags & IEEE80211_CONF_PS) + return; + + if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) + ieee80211_send_nullfunc(local, sdata, 1); + + local->hw.conf.flags |= IEEE80211_CONF_PS; + ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); +} + +void ieee80211_dynamic_ps_timer(unsigned long data) +{ + struct ieee80211_local *local = (void *) data; + + if (local->quiescing) + return; + + queue_work(local->hw.workqueue, &local->dynamic_ps_enable_work); +} + /* MLME */ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, struct ieee80211_if_managed *ifmgd, @@ -424,41 +792,16 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, #ifdef CONFIG_MAC80211_VERBOSE_DEBUG printk(KERN_DEBUG "%s: WMM queue=%d aci=%d acm=%d aifs=%d " "cWmin=%d cWmax=%d txop=%d\n", - local->mdev->name, queue, aci, acm, params.aifs, params.cw_min, - params.cw_max, params.txop); + wiphy_name(local->hw.wiphy), queue, aci, acm, + params.aifs, params.cw_min, params.cw_max, params.txop); #endif - if (local->ops->conf_tx && - local->ops->conf_tx(local_to_hw(local), queue, ¶ms)) { + if (drv_conf_tx(local, queue, ¶ms) && local->ops->conf_tx) printk(KERN_DEBUG "%s: failed to set TX queue " - "parameters for queue %d\n", local->mdev->name, queue); - } + "parameters for queue %d\n", + wiphy_name(local->hw.wiphy), queue); } } -static bool ieee80211_check_tim(struct ieee802_11_elems *elems, u16 aid) -{ - u8 mask; - u8 index, indexn1, indexn2; - struct ieee80211_tim_ie *tim = (struct ieee80211_tim_ie *) elems->tim; - - if (unlikely(!tim || elems->tim_len < 4)) - return false; - - aid &= 0x3fff; - index = aid / 8; - mask = 1 << (aid & 7); - - indexn1 = tim->bitmap_ctrl & 0xfe; - indexn2 = elems->tim_len + indexn1 - 4; - - if (index < indexn1 || index > indexn2) - return false; - - index -= indexn1; - - return !!(tim->virtual_map[index] & mask); -} - static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, u16 capab, bool erp_valid, u8 erp) { @@ -610,6 +953,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, sdata->vif.bss_conf.timestamp = bss->cbss.tsf; sdata->vif.bss_conf.dtim_period = bss->dtim_period; + bss_info_changed |= BSS_CHANGED_BEACON_INT; bss_info_changed |= ieee80211_handle_bss_capability(sdata, bss->cbss.capability, bss->has_erp_value, bss->erp_value); @@ -632,20 +976,17 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, * changed or not. */ bss_info_changed |= BSS_CHANGED_BASIC_RATES; + + /* And the BSSID changed - we're associated now */ + bss_info_changed |= BSS_CHANGED_BSSID; + ieee80211_bss_info_change_notify(sdata, bss_info_changed); - if (local->powersave) { - if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) && - local->hw.conf.dynamic_ps_timeout > 0) { - mod_timer(&local->dynamic_ps_timer, jiffies + - msecs_to_jiffies( - local->hw.conf.dynamic_ps_timeout)); - } else { - if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) - ieee80211_send_nullfunc(local, sdata, 1); - conf->flags |= IEEE80211_CONF_PS; - ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); - } + /* will be same as sdata */ + if (local->ps_sdata) { + mutex_lock(&local->iflist_mtx); + ieee80211_recalc_ps(local, -1); + mutex_unlock(&local->iflist_mtx); } netif_tx_start_all_queues(sdata->dev); @@ -664,7 +1005,8 @@ static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata) printk(KERN_DEBUG "%s: direct probe to AP %pM timed out\n", sdata->dev->name, ifmgd->bssid); ifmgd->state = IEEE80211_STA_MLME_DISABLED; - ieee80211_sta_send_apinfo(sdata); + ieee80211_recalc_idle(local); + cfg80211_send_auth_timeout(sdata->dev, ifmgd->bssid); /* * Most likely AP is not in the range so remove the @@ -689,8 +1031,6 @@ static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata) ifmgd->state = IEEE80211_STA_MLME_DIRECT_PROBE; - set_bit(IEEE80211_STA_REQ_DIRECT_PROBE, &ifmgd->request); - /* Direct probe is sent to broadcast address as some APs * will not answer to direct packet in unassociated state. */ @@ -714,7 +1054,8 @@ static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata) " timed out\n", sdata->dev->name, ifmgd->bssid); ifmgd->state = IEEE80211_STA_MLME_DISABLED; - ieee80211_sta_send_apinfo(sdata); + ieee80211_recalc_idle(local); + cfg80211_send_auth_timeout(sdata->dev, ifmgd->bssid); ieee80211_rx_bss_remove(sdata, ifmgd->bssid, sdata->local->hw.conf.channel->center_freq, ifmgd->ssid, ifmgd->ssid_len); @@ -761,14 +1102,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, struct sta_info *sta; u32 changed = 0, config_changed = 0; - rcu_read_lock(); - - sta = sta_info_get(local, ifmgd->bssid); - if (!sta) { - rcu_read_unlock(); - return; - } - if (deauth) { ifmgd->direct_probe_tries = 0; ifmgd->auth_tries = 0; @@ -779,7 +1112,11 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, netif_tx_stop_all_queues(sdata->dev); netif_carrier_off(sdata->dev); - ieee80211_sta_tear_down_BA_sessions(sta); + rcu_read_lock(); + sta = sta_info_get(local, ifmgd->bssid); + if (sta) + ieee80211_sta_tear_down_BA_sessions(sta); + rcu_read_unlock(); bss = ieee80211_rx_bss_get(local, ifmgd->bssid, conf->channel->center_freq, @@ -815,11 +1152,16 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, ifmgd->ssid, ifmgd->ssid_len); } - rcu_read_unlock(); + ieee80211_set_wmm_default(sdata); + + ieee80211_recalc_idle(local); /* channel(_type) changes are handled by ieee80211_hw_config */ local->oper_channel_type = NL80211_CHAN_NO_HT; + /* on the next assoc, re-program HT parameters */ + sdata->ht_opmode_valid = false; + local->power_constr_level = 0; del_timer_sync(&local->dynamic_ps_timer); @@ -831,6 +1173,9 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, } ieee80211_hw_config(local, config_changed); + + /* And the BSSID changed -- not very interesting here */ + changed |= BSS_CHANGED_BSSID; ieee80211_bss_info_change_notify(sdata, changed); rcu_read_lock(); @@ -897,7 +1242,8 @@ static void ieee80211_associate(struct ieee80211_sub_if_data *sdata) " timed out\n", sdata->dev->name, ifmgd->bssid); ifmgd->state = IEEE80211_STA_MLME_DISABLED; - ieee80211_sta_send_apinfo(sdata); + ieee80211_recalc_idle(local); + cfg80211_send_assoc_timeout(sdata->dev, ifmgd->bssid); ieee80211_rx_bss_remove(sdata, ifmgd->bssid, sdata->local->hw.conf.channel->center_freq, ifmgd->ssid, ifmgd->ssid_len); @@ -917,6 +1263,7 @@ static void ieee80211_associate(struct ieee80211_sub_if_data *sdata) printk(KERN_DEBUG "%s: mismatch in privacy configuration and " "mixed-cell disabled - abort association\n", sdata->dev->name); ifmgd->state = IEEE80211_STA_MLME_DISABLED; + ieee80211_recalc_idle(local); return; } @@ -948,6 +1295,17 @@ void ieee80211_beacon_loss_work(struct work_struct *work) u.mgd.beacon_loss_work); struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + /* + * The driver has already reported this event and we have + * already sent a probe request. Maybe the AP died and the + * driver keeps reporting until we disassociate... We have + * to ignore that because otherwise we would continually + * reset the timer and never check whether we received a + * probe response! + */ + if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) + return; + #ifdef CONFIG_MAC80211_VERBOSE_DEBUG if (net_ratelimit()) { printk(KERN_DEBUG "%s: driver reports beacon loss from AP %pM " @@ -957,10 +1315,15 @@ void ieee80211_beacon_loss_work(struct work_struct *work) #endif ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL; + + mutex_lock(&sdata->local->iflist_mtx); + ieee80211_recalc_ps(sdata->local, -1); + mutex_unlock(&sdata->local->iflist_mtx); + ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid, ifmgd->ssid_len, NULL, 0); - mod_timer(&ifmgd->timer, jiffies + IEEE80211_MONITORING_INTERVAL); + mod_timer(&ifmgd->timer, jiffies + IEEE80211_PROBE_WAIT); } void ieee80211_beacon_loss(struct ieee80211_vif *vif) @@ -977,6 +1340,7 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata) struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; struct sta_info *sta; + unsigned long last_rx; bool disassoc = false; /* TODO: start monitoring current AP signal quality and number of @@ -993,17 +1357,21 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata) printk(KERN_DEBUG "%s: No STA entry for own AP %pM\n", sdata->dev->name, ifmgd->bssid); disassoc = true; - goto unlock; + rcu_read_unlock(); + goto out; } + last_rx = sta->last_rx; + rcu_read_unlock(); + if ((ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) && - time_after(jiffies, sta->last_rx + IEEE80211_MONITORING_INTERVAL)) { + time_after(jiffies, last_rx + IEEE80211_PROBE_WAIT)) { printk(KERN_DEBUG "%s: no probe response from AP %pM " "- disassociating\n", sdata->dev->name, ifmgd->bssid); disassoc = true; ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL; - goto unlock; + goto out; } /* @@ -1022,27 +1390,31 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata) } #endif ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL; + mutex_lock(&local->iflist_mtx); + ieee80211_recalc_ps(local, -1); + mutex_unlock(&local->iflist_mtx); ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid, ifmgd->ssid_len, NULL, 0); - goto unlock; - + mod_timer(&ifmgd->timer, jiffies + IEEE80211_PROBE_WAIT); + goto out; } - if (time_after(jiffies, sta->last_rx + IEEE80211_PROBE_IDLE_TIME)) { + if (time_after(jiffies, last_rx + IEEE80211_PROBE_IDLE_TIME)) { ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL; + mutex_lock(&local->iflist_mtx); + ieee80211_recalc_ps(local, -1); + mutex_unlock(&local->iflist_mtx); ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid, ifmgd->ssid_len, NULL, 0); } - unlock: - rcu_read_unlock(); - - if (disassoc) + out: + if (!disassoc) + mod_timer(&ifmgd->timer, + jiffies + IEEE80211_MONITORING_INTERVAL); + else ieee80211_set_disassoc(sdata, true, true, WLAN_REASON_PREV_AUTH_NOT_VALID); - else - mod_timer(&ifmgd->timer, jiffies + - IEEE80211_MONITORING_INTERVAL); } @@ -1055,6 +1427,7 @@ static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata) if (ifmgd->flags & IEEE80211_STA_EXT_SME) { /* Wait for SME to request association */ ifmgd->state = IEEE80211_STA_MLME_DISABLED; + ieee80211_recalc_idle(sdata->local); } else ieee80211_associate(sdata); } @@ -1187,7 +1560,7 @@ static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, ieee80211_set_disassoc(sdata, true, false, 0); ifmgd->flags &= ~IEEE80211_STA_AUTHENTICATED; - cfg80211_send_rx_deauth(sdata->dev, (u8 *) mgmt, len); + cfg80211_send_deauth(sdata->dev, (u8 *) mgmt, len); } @@ -1218,7 +1591,7 @@ static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, } ieee80211_set_disassoc(sdata, false, false, reason_code); - cfg80211_send_rx_disassoc(sdata->dev, (u8 *) mgmt, len); + cfg80211_send_disassoc(sdata->dev, (u8 *) mgmt, len); } @@ -1287,6 +1660,12 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, * association next time. This works around some broken APs * which do not correctly reject reassociation requests. */ ifmgd->flags &= ~IEEE80211_STA_PREV_BSSID_SET; + cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, len); + if (ifmgd->flags & IEEE80211_STA_EXT_SME) { + /* Wait for SME to decide what to do next */ + ifmgd->state = IEEE80211_STA_MLME_DISABLED; + ieee80211_recalc_idle(local); + } return; } @@ -1340,8 +1719,9 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, * to between the sta_info_alloc() and sta_info_insert() above. */ - set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP | - WLAN_STA_AUTHORIZED); + set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP); + if (!(ifmgd->flags & IEEE80211_STA_CONTROL_PORT)) + set_sta_flags(sta, WLAN_STA_AUTHORIZED); rates = 0; basic_rates = 0; @@ -1421,6 +1801,8 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, if (elems.wmm_param) ieee80211_sta_wmm_params(local, ifmgd, elems.wmm_param, elems.wmm_param_len); + else + ieee80211_set_wmm_default(sdata); if (elems.ht_info_elem && elems.wmm_param && (ifmgd->flags & IEEE80211_STA_WMM_ENABLED) && @@ -1476,7 +1858,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN) == 0)) { struct ieee80211_channel_sw_ie *sw_elem = (struct ieee80211_channel_sw_ie *)elems->ch_switch_elem; - ieee80211_process_chanswitch(sdata, sw_elem, bss); + ieee80211_sta_process_chanswitch(sdata, sw_elem, bss); } ieee80211_rx_bss_put(local, bss); @@ -1507,57 +1889,98 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, false); /* direct probe may be part of the association flow */ - if (test_and_clear_bit(IEEE80211_STA_REQ_DIRECT_PROBE, - &ifmgd->request)) { + if (ifmgd->state == IEEE80211_STA_MLME_DIRECT_PROBE) { printk(KERN_DEBUG "%s direct probe responded\n", sdata->dev->name); ieee80211_authenticate(sdata); } - if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) + if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) { ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL; + mutex_lock(&sdata->local->iflist_mtx); + ieee80211_recalc_ps(sdata->local, -1); + mutex_unlock(&sdata->local->iflist_mtx); + } } +/* + * This is the canonical list of information elements we care about, + * the filter code also gives us all changes to the Microsoft OUI + * (00:50:F2) vendor IE which is used for WMM which we need to track. + * + * We implement beacon filtering in software since that means we can + * avoid processing the frame here and in cfg80211, and userspace + * will not be able to tell whether the hardware supports it or not. + * + * XXX: This list needs to be dynamic -- userspace needs to be able to + * add items it requires. It also needs to be able to tell us to + * look out for other vendor IEs. + */ +static const u64 care_about_ies = + (1ULL << WLAN_EID_COUNTRY) | + (1ULL << WLAN_EID_ERP_INFO) | + (1ULL << WLAN_EID_CHANNEL_SWITCH) | + (1ULL << WLAN_EID_PWR_CONSTRAINT) | + (1ULL << WLAN_EID_HT_CAPABILITY) | + (1ULL << WLAN_EID_HT_INFORMATION); + static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, size_t len, struct ieee80211_rx_status *rx_status) { - struct ieee80211_if_managed *ifmgd; + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; size_t baselen; struct ieee802_11_elems elems; struct ieee80211_local *local = sdata->local; u32 changed = 0; - bool erp_valid, directed_tim; + bool erp_valid, directed_tim = false; u8 erp_value = 0; + u32 ncrc; /* Process beacon from the current BSS */ baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt; if (baselen > len) return; - ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems); - - ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, true); - - if (sdata->vif.type != NL80211_IFTYPE_STATION) + if (rx_status->freq != local->hw.conf.channel->center_freq) return; - ifmgd = &sdata->u.mgd; - if (!(ifmgd->flags & IEEE80211_STA_ASSOCIATED) || memcmp(ifmgd->bssid, mgmt->bssid, ETH_ALEN) != 0) return; - if (rx_status->freq != local->hw.conf.channel->center_freq) - return; + if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) { +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG + if (net_ratelimit()) { + printk(KERN_DEBUG "%s: cancelling probereq poll due " + "to a received beacon\n", sdata->dev->name); + } +#endif + ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL; + mutex_lock(&local->iflist_mtx); + ieee80211_recalc_ps(local, -1); + mutex_unlock(&local->iflist_mtx); + } - ieee80211_sta_wmm_params(local, ifmgd, elems.wmm_param, - elems.wmm_param_len); + ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4); + ncrc = ieee802_11_parse_elems_crc(mgmt->u.beacon.variable, + len - baselen, &elems, + care_about_ies, ncrc); + + if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) + directed_tim = ieee80211_check_tim(elems.tim, elems.tim_len, + ifmgd->aid); + + if (ncrc != ifmgd->beacon_crc) { + ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, + true); + + ieee80211_sta_wmm_params(local, ifmgd, elems.wmm_param, + elems.wmm_param_len); + } if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) { - directed_tim = ieee80211_check_tim(&elems, ifmgd->aid); - if (directed_tim) { if (local->hw.conf.dynamic_ps_timeout > 0) { local->hw.conf.flags &= ~IEEE80211_CONF_PS; @@ -1580,6 +2003,10 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, } } + if (ncrc == ifmgd->beacon_crc) + return; + ifmgd->beacon_crc = ncrc; + if (elems.erp_info && elems.erp_info_len >= 1) { erp_valid = true; erp_value = elems.erp_info[0]; @@ -1714,6 +2141,11 @@ static void ieee80211_sta_timer(unsigned long data) struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; + if (local->quiescing) { + set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running); + return; + } + set_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request); queue_work(local->hw.workqueue, &ifmgd->work); } @@ -1723,10 +2155,8 @@ static void ieee80211_sta_reset_auth(struct ieee80211_sub_if_data *sdata) struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; - if (local->ops->reset_tsf) { - /* Reset own TSF to allow time synchronization work. */ - local->ops->reset_tsf(local_to_hw(local)); - } + /* Reset own TSF to allow time synchronization work. */ + drv_reset_tsf(local); ifmgd->wmm_last_param_set = -1; /* allow any WMM update */ @@ -1787,7 +2217,10 @@ static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata) capa_mask, capa_val); if (bss) { - ieee80211_set_freq(sdata, bss->cbss.channel->center_freq); + local->oper_channel = bss->cbss.channel; + local->oper_channel_type = NL80211_CHAN_NO_HT; + ieee80211_hw_config(local, 0); + if (!(ifmgd->flags & IEEE80211_STA_SSID_SET)) ieee80211_sta_set_ssid(sdata, bss->ssid, bss->ssid_len); @@ -1814,25 +2247,18 @@ static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata) return 0; } else { if (ifmgd->assoc_scan_tries < IEEE80211_ASSOC_SCANS_MAX_TRIES) { - ifmgd->assoc_scan_tries++; - /* XXX maybe racy? */ - if (local->scan_req) - return -1; - memcpy(local->int_scan_req.ssids[0].ssid, - ifmgd->ssid, IEEE80211_MAX_SSID_LEN); - if (ifmgd->flags & IEEE80211_STA_AUTO_SSID_SEL) - local->int_scan_req.ssids[0].ssid_len = 0; - else - local->int_scan_req.ssids[0].ssid_len = ifmgd->ssid_len; - if (ieee80211_start_scan(sdata, &local->int_scan_req)) - ieee80211_scan_failed(local); + ifmgd->assoc_scan_tries++; + + ieee80211_request_internal_scan(sdata, ifmgd->ssid, + ssid_len); ifmgd->state = IEEE80211_STA_MLME_AUTHENTICATE; set_bit(IEEE80211_STA_REQ_AUTH, &ifmgd->request); } else { ifmgd->assoc_scan_tries = 0; ifmgd->state = IEEE80211_STA_MLME_DISABLED; + ieee80211_recalc_idle(local); } } return -1; @@ -1855,6 +2281,17 @@ static void ieee80211_sta_work(struct work_struct *work) if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) return; + + /* + * Nothing should have been stuffed into the workqueue during + * the suspend->resume cycle. If this WARN is seen then there + * is a bug with either the driver suspend or something in + * mac80211 stuffing into the workqueue which we haven't yet + * cleared during mac80211's suspend cycle. + */ + if (WARN_ON(local->suspended)) + return; + ifmgd = &sdata->u.mgd; while ((skb = skb_dequeue(&ifmgd->skb_queue))) @@ -1864,14 +2301,8 @@ static void ieee80211_sta_work(struct work_struct *work) ifmgd->state != IEEE80211_STA_MLME_AUTHENTICATE && ifmgd->state != IEEE80211_STA_MLME_ASSOCIATE && test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request)) { - /* - * The call to ieee80211_start_scan can fail but ieee80211_request_scan - * (which queued ieee80211_sta_work) did not return an error. Thus, call - * ieee80211_scan_failed here if ieee80211_start_scan fails in order to - * notify the scan requester. - */ - if (ieee80211_start_scan(sdata, local->scan_req)) - ieee80211_scan_failed(local); + queue_delayed_work(local->hw.workqueue, &local->scan_work, + round_jiffies_relative(0)); return; } @@ -1882,6 +2313,8 @@ static void ieee80211_sta_work(struct work_struct *work) } else if (!test_and_clear_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request)) return; + ieee80211_recalc_idle(local); + switch (ifmgd->state) { case IEEE80211_STA_MLME_DISABLED: break; @@ -1926,10 +2359,43 @@ static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata) } } +#ifdef CONFIG_PM +void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + + /* + * we need to use atomic bitops for the running bits + * only because both timers might fire at the same + * time -- the code here is properly synchronised. + */ + + cancel_work_sync(&ifmgd->work); + cancel_work_sync(&ifmgd->beacon_loss_work); + if (del_timer_sync(&ifmgd->timer)) + set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running); + + cancel_work_sync(&ifmgd->chswitch_work); + if (del_timer_sync(&ifmgd->chswitch_timer)) + set_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running); +} + +void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + + if (test_and_clear_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running)) + add_timer(&ifmgd->timer); + if (test_and_clear_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running)) + add_timer(&ifmgd->chswitch_timer); +} +#endif + /* interface setup */ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_managed *ifmgd; + u32 hw_flags; ifmgd = &sdata->u.mgd; INIT_WORK(&ifmgd->work, ieee80211_sta_work); @@ -1949,6 +2415,13 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) IEEE80211_STA_AUTO_CHANNEL_SEL; if (sdata->local->hw.queues >= 4) ifmgd->flags |= IEEE80211_STA_WMM_ENABLED; + + hw_flags = sdata->local->hw.flags; + + if (hw_flags & IEEE80211_HW_SUPPORTS_PS) { + ifmgd->powersave = CONFIG_MAC80211_DEFAULT_PS_VALUE; + sdata->local->hw.conf.dynamic_ps_timeout = 500; + } } /* configuration hooks */ @@ -1969,6 +2442,14 @@ void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata) ieee80211_set_disassoc(sdata, true, true, WLAN_REASON_DEAUTH_LEAVING); + if (ifmgd->ssid_len == 0) { + /* + * Only allow association to be started if a valid SSID + * is configured. + */ + return; + } + if (!(ifmgd->flags & IEEE80211_STA_EXT_SME) || ifmgd->state != IEEE80211_STA_MLME_ASSOCIATE) set_bit(IEEE80211_STA_REQ_AUTH, &ifmgd->request); @@ -2000,6 +2481,10 @@ int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size ifmgd = &sdata->u.mgd; if (ifmgd->ssid_len != len || memcmp(ifmgd->ssid, ssid, len) != 0) { + if (ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED) + ieee80211_set_disassoc(sdata, true, true, + WLAN_REASON_DEAUTH_LEAVING); + /* * Do not use reassociation if SSID is changed (different ESS). */ @@ -2024,6 +2509,11 @@ int ieee80211_sta_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + if (compare_ether_addr(bssid, ifmgd->bssid) != 0 && + ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED) + ieee80211_set_disassoc(sdata, true, true, + WLAN_REASON_DEAUTH_LEAVING); + if (is_valid_ether_addr(bssid)) { memcpy(ifmgd->bssid, bssid, ETH_ALEN); ifmgd->flags |= IEEE80211_STA_BSSID_SET; @@ -2032,13 +2522,6 @@ int ieee80211_sta_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid) ifmgd->flags &= ~IEEE80211_STA_BSSID_SET; } - if (netif_running(sdata->dev)) { - if (ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID)) { - printk(KERN_DEBUG "%s: Failed to config new BSSID to " - "the low-level driver\n", sdata->dev->name); - } - } - return ieee80211_sta_commit(sdata); } @@ -2047,6 +2530,13 @@ int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata, { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + if (len == 0 && ifmgd->extra_ie_len == 0) + return -EALREADY; + + if (len == ifmgd->extra_ie_len && ifmgd->extra_ie && + memcmp(ifmgd->extra_ie, ie, len) == 0) + return -EALREADY; + kfree(ifmgd->extra_ie); if (len == 0) { ifmgd->extra_ie = NULL; @@ -2068,9 +2558,6 @@ int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason printk(KERN_DEBUG "%s: deauthenticating by local choice (reason=%d)\n", sdata->dev->name, reason); - if (sdata->vif.type != NL80211_IFTYPE_STATION) - return -EINVAL; - ieee80211_set_disassoc(sdata, true, true, reason); return 0; } @@ -2082,9 +2569,6 @@ int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason) printk(KERN_DEBUG "%s: disassociating by local choice (reason=%d)\n", sdata->dev->name, reason); - if (sdata->vif.type != NL80211_IFTYPE_STATION) - return -EINVAL; - if (!(ifmgd->flags & IEEE80211_STA_ASSOCIATED)) return -ENOLINK; @@ -2104,75 +2588,17 @@ void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local) rcu_read_unlock(); } -void ieee80211_dynamic_ps_disable_work(struct work_struct *work) +int ieee80211_max_network_latency(struct notifier_block *nb, + unsigned long data, void *dummy) { + s32 latency_usec = (s32) data; struct ieee80211_local *local = - container_of(work, struct ieee80211_local, - dynamic_ps_disable_work); + container_of(nb, struct ieee80211_local, + network_latency_notifier); - if (local->hw.conf.flags & IEEE80211_CONF_PS) { - local->hw.conf.flags &= ~IEEE80211_CONF_PS; - ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); - } + mutex_lock(&local->iflist_mtx); + ieee80211_recalc_ps(local, latency_usec); + mutex_unlock(&local->iflist_mtx); - ieee80211_wake_queues_by_reason(&local->hw, - IEEE80211_QUEUE_STOP_REASON_PS); -} - -void ieee80211_dynamic_ps_enable_work(struct work_struct *work) -{ - struct ieee80211_local *local = - container_of(work, struct ieee80211_local, - dynamic_ps_enable_work); - /* XXX: using scan_sdata is completely broken! */ - struct ieee80211_sub_if_data *sdata = local->scan_sdata; - - if (local->hw.conf.flags & IEEE80211_CONF_PS) - return; - - if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK && sdata) - ieee80211_send_nullfunc(local, sdata, 1); - - local->hw.conf.flags |= IEEE80211_CONF_PS; - ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); -} - -void ieee80211_dynamic_ps_timer(unsigned long data) -{ - struct ieee80211_local *local = (void *) data; - - queue_work(local->hw.workqueue, &local->dynamic_ps_enable_work); -} - -void ieee80211_send_nullfunc(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata, - int powersave) -{ - struct sk_buff *skb; - struct ieee80211_hdr *nullfunc; - __le16 fc; - - if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) - return; - - skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24); - if (!skb) { - printk(KERN_DEBUG "%s: failed to allocate buffer for nullfunc " - "frame\n", sdata->dev->name); - return; - } - skb_reserve(skb, local->hw.extra_tx_headroom); - - nullfunc = (struct ieee80211_hdr *) skb_put(skb, 24); - memset(nullfunc, 0, 24); - fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC | - IEEE80211_FCTL_TODS); - if (powersave) - fc |= cpu_to_le16(IEEE80211_FCTL_PM); - nullfunc->frame_control = fc; - memcpy(nullfunc->addr1, sdata->u.mgd.bssid, ETH_ALEN); - memcpy(nullfunc->addr2, sdata->dev->dev_addr, ETH_ALEN); - memcpy(nullfunc->addr3, sdata->u.mgd.bssid, ETH_ALEN); - - ieee80211_tx_skb(sdata, skb, 0); + return 0; } diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index 81985d27cbda..7a549f9deb96 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c @@ -2,6 +2,8 @@ #include #include "ieee80211_i.h" +#include "mesh.h" +#include "driver-ops.h" #include "led.h" int __ieee80211_suspend(struct ieee80211_hw *hw) @@ -12,11 +14,30 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) struct sta_info *sta; unsigned long flags; + ieee80211_scan_cancel(local); + ieee80211_stop_queues_by_reason(hw, IEEE80211_QUEUE_STOP_REASON_SUSPEND); + /* flush out all packets */ + synchronize_net(); + + local->quiescing = true; + /* make quiescing visible to timers everywhere */ + mb(); + flush_workqueue(local->hw.workqueue); + /* Don't try to run timers while suspended. */ + del_timer_sync(&local->sta_cleanup); + + /* + * Note that this particular timer doesn't need to be + * restarted at resume. + */ + cancel_work_sync(&local->dynamic_ps_enable_work); + del_timer_sync(&local->dynamic_ps_timer); + /* disable keys */ list_for_each_entry(sdata, &local->interfaces, list) ieee80211_disable_keys(sdata); @@ -34,157 +55,70 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) rcu_read_unlock(); - /* remove STAs */ - if (local->ops->sta_notify) { - spin_lock_irqsave(&local->sta_lock, flags); - list_for_each_entry(sta, &local->sta_list, list) { - if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) - sdata = container_of(sdata->bss, - struct ieee80211_sub_if_data, - u.ap); - - local->ops->sta_notify(hw, &sdata->vif, - STA_NOTIFY_REMOVE, &sta->sta); - } - spin_unlock_irqrestore(&local->sta_lock, flags); - } - - /* remove all interfaces */ - list_for_each_entry(sdata, &local->interfaces, list) { - if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && - sdata->vif.type != NL80211_IFTYPE_MONITOR && - netif_running(sdata->dev)) { - conf.vif = &sdata->vif; - conf.type = sdata->vif.type; - conf.mac_addr = sdata->dev->dev_addr; - local->ops->remove_interface(hw, &conf); - } - } - /* flush again, in case driver queued work */ flush_workqueue(local->hw.workqueue); - /* stop hardware */ + /* stop hardware - this must stop RX */ if (local->open_count) { ieee80211_led_radio(local, false); - local->ops->stop(hw); - } - return 0; -} - -int __ieee80211_resume(struct ieee80211_hw *hw) -{ - struct ieee80211_local *local = hw_to_local(hw); - struct ieee80211_sub_if_data *sdata; - struct ieee80211_if_init_conf conf; - struct sta_info *sta; - unsigned long flags; - int res; - - /* restart hardware */ - if (local->open_count) { - res = local->ops->start(hw); - - ieee80211_led_radio(local, hw->conf.radio_enabled); + drv_stop(local); } - /* add interfaces */ - list_for_each_entry(sdata, &local->interfaces, list) { - if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && - sdata->vif.type != NL80211_IFTYPE_MONITOR && - netif_running(sdata->dev)) { - conf.vif = &sdata->vif; - conf.type = sdata->vif.type; - conf.mac_addr = sdata->dev->dev_addr; - res = local->ops->add_interface(hw, &conf); - } - } - - /* add STAs back */ - if (local->ops->sta_notify) { - spin_lock_irqsave(&local->sta_lock, flags); - list_for_each_entry(sta, &local->sta_list, list) { + /* remove STAs */ + spin_lock_irqsave(&local->sta_lock, flags); + list_for_each_entry(sta, &local->sta_list, list) { + if (local->ops->sta_notify) { + sdata = sta->sdata; if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) sdata = container_of(sdata->bss, struct ieee80211_sub_if_data, u.ap); - local->ops->sta_notify(hw, &sdata->vif, - STA_NOTIFY_ADD, &sta->sta); + drv_sta_notify(local, &sdata->vif, STA_NOTIFY_REMOVE, + &sta->sta); } - spin_unlock_irqrestore(&local->sta_lock, flags); + + mesh_plink_quiesce(sta); } + spin_unlock_irqrestore(&local->sta_lock, flags); - /* Clear Suspend state so that ADDBA requests can be processed */ - - rcu_read_lock(); - - if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { - list_for_each_entry_rcu(sta, &local->sta_list, list) { - clear_sta_flags(sta, WLAN_STA_SUSPEND); - } - } - - rcu_read_unlock(); - - /* add back keys */ - list_for_each_entry(sdata, &local->interfaces, list) - if (netif_running(sdata->dev)) - ieee80211_enable_keys(sdata); - - /* setup RTS threshold */ - if (local->ops->set_rts_threshold) - local->ops->set_rts_threshold(hw, local->rts_threshold); - - /* reconfigure hardware */ - ieee80211_hw_config(local, ~0); - - netif_addr_lock_bh(local->mdev); - ieee80211_configure_filter(local); - netif_addr_unlock_bh(local->mdev); - - /* Finally also reconfigure all the BSS information */ + /* remove all interfaces */ list_for_each_entry(sdata, &local->interfaces, list) { - u32 changed = ~0; - if (!netif_running(sdata->dev)) - continue; - switch (sdata->vif.type) { + switch(sdata->vif.type) { case NL80211_IFTYPE_STATION: - /* disable beacon change bits */ - changed &= ~IEEE80211_IFCC_BEACON; - /* fall through */ - case NL80211_IFTYPE_ADHOC: - case NL80211_IFTYPE_AP: - case NL80211_IFTYPE_MESH_POINT: - /* - * Driver's config_interface can fail if rfkill is - * enabled. Accommodate this return code. - * FIXME: When mac80211 has knowledge of rfkill - * state the code below can change back to: - * WARN(ieee80211_if_config(sdata, changed)); - * ieee80211_bss_info_change_notify(sdata, ~0); - */ - if (ieee80211_if_config(sdata, changed)) - printk(KERN_DEBUG "%s: failed to configure interface during resume\n", - sdata->dev->name); - else - ieee80211_bss_info_change_notify(sdata, ~0); + ieee80211_sta_quiesce(sdata); break; - case NL80211_IFTYPE_WDS: + case NL80211_IFTYPE_ADHOC: + ieee80211_ibss_quiesce(sdata); + break; + case NL80211_IFTYPE_MESH_POINT: + ieee80211_mesh_quiesce(sdata); break; case NL80211_IFTYPE_AP_VLAN: case NL80211_IFTYPE_MONITOR: - /* ignore virtual */ - break; - case NL80211_IFTYPE_UNSPECIFIED: - case __NL80211_IFTYPE_AFTER_LAST: - WARN_ON(1); + /* don't tell driver about this */ + continue; + default: break; } + + if (!netif_running(sdata->dev)) + continue; + + conf.vif = &sdata->vif; + conf.type = sdata->vif.type; + conf.mac_addr = sdata->dev->dev_addr; + drv_remove_interface(local, &conf); } - ieee80211_wake_queues_by_reason(hw, - IEEE80211_QUEUE_STOP_REASON_SUSPEND); + local->suspended = true; + local->quiescing = false; return 0; } + +/* + * __ieee80211_resume() is a static inline which just calls + * ieee80211_reconfig(), which is also needed for hardware + * hang/firmware failure/etc. recovery. + */ diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index d9233ec50610..b218b98fba7f 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c @@ -80,8 +80,7 @@ use_low_rate(struct sk_buff *skb) fc = le16_to_cpu(hdr->frame_control); return ((info->flags & IEEE80211_TX_CTL_NO_ACK) || - (fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA || - is_multicast_ether_addr(hdr->addr1)); + (fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA); } @@ -216,7 +215,7 @@ minstrel_get_next_sample(struct minstrel_sta_info *mi) unsigned int sample_ndx; sample_ndx = SAMPLE_TBL(mi, mi->sample_idx, mi->sample_column); mi->sample_idx++; - if (mi->sample_idx > (mi->n_rates - 2)) { + if ((int) mi->sample_idx > (mi->n_rates - 2)) { mi->sample_idx = 0; mi->sample_column++; if (mi->sample_column >= SAMPLE_COLUMNS) @@ -245,7 +244,10 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta, if (!sta || !mi || use_low_rate(skb)) { ar[0].idx = rate_lowest_index(sband, sta); - ar[0].count = mp->max_retry; + if (info->flags & IEEE80211_TX_CTL_NO_ACK) + ar[0].count = 1; + else + ar[0].count = mp->max_retry; return; } diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c index 8bef9a1262ff..a0bef767ceb5 100644 --- a/net/mac80211/rc80211_pid_algo.c +++ b/net/mac80211/rc80211_pid_algo.c @@ -289,13 +289,15 @@ rate_control_pid_get_rate(void *priv, struct ieee80211_sta *sta, info->control.rates[0].count = txrc->hw->conf.short_frame_max_tx_count; - /* Send management frames and broadcast/multicast data using lowest - * rate. */ + /* Send management frames and NO_ACK data using lowest rate. */ fc = le16_to_cpu(hdr->frame_control); if (!sta || !spinfo || (fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA || - is_multicast_ether_addr(hdr->addr1)) { + info->flags & IEEE80211_TX_CTL_NO_ACK) { info->control.rates[0].idx = rate_lowest_index(sband, sta); + if (info->flags & IEEE80211_TX_CTL_NO_ACK) + info->control.rates[0].count = 1; + return; } diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 9776f73c51ad..de5bba7f910a 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -19,6 +19,7 @@ #include #include "ieee80211_i.h" +#include "driver-ops.h" #include "led.h" #include "mesh.h" #include "wep.h" @@ -629,15 +630,6 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) * possible. */ - if (!ieee80211_has_protected(hdr->frame_control)) { - if (!ieee80211_is_mgmt(hdr->frame_control) || - rx->sta == NULL || !test_sta_flags(rx->sta, WLAN_STA_MFP)) - return RX_CONTINUE; - mmie_keyidx = ieee80211_get_mmie_keyidx(rx->skb); - if (mmie_keyidx < 0) - return RX_CONTINUE; - } - /* * No point in finding a key and decrypting if the frame is neither * addressed to us nor a multicast frame. @@ -648,8 +640,14 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) if (rx->sta) stakey = rcu_dereference(rx->sta->key); + if (!ieee80211_has_protected(hdr->frame_control)) + mmie_keyidx = ieee80211_get_mmie_keyidx(rx->skb); + if (!is_multicast_ether_addr(hdr->addr1) && stakey) { rx->key = stakey; + /* Skip decryption if the frame is not protected. */ + if (!ieee80211_has_protected(hdr->frame_control)) + return RX_CONTINUE; } else if (mmie_keyidx >= 0) { /* Broadcast/multicast robust management frame / BIP */ if ((rx->status->flag & RX_FLAG_DECRYPTED) && @@ -660,6 +658,21 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) mmie_keyidx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS) return RX_DROP_MONITOR; /* unexpected BIP keyidx */ rx->key = rcu_dereference(rx->sdata->keys[mmie_keyidx]); + } else if (!ieee80211_has_protected(hdr->frame_control)) { + /* + * The frame was not protected, so skip decryption. However, we + * need to set rx->key if there is a key that could have been + * used so that the frame may be dropped if encryption would + * have been expected. + */ + struct ieee80211_key *key = NULL; + if (ieee80211_is_mgmt(hdr->frame_control) && + is_multicast_ether_addr(hdr->addr1) && + (key = rcu_dereference(rx->sdata->default_mgmt_key))) + rx->key = key; + else if ((key = rcu_dereference(rx->sdata->default_key))) + rx->key = key; + return RX_CONTINUE; } else { /* * The device doesn't give us the IV so we won't be @@ -773,9 +786,7 @@ static void ap_sta_ps_start(struct sta_info *sta) atomic_inc(&sdata->bss->num_sta_ps); set_and_clear_sta_flags(sta, WLAN_STA_PS, WLAN_STA_PSPOLL); - if (local->ops->sta_notify) - local->ops->sta_notify(local_to_hw(local), &sdata->vif, - STA_NOTIFY_SLEEP, &sta->sta); + drv_sta_notify(local, &sdata->vif, STA_NOTIFY_SLEEP, &sta->sta); #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "%s: STA %pM aid %d enters power save mode\n", sdata->dev->name, sta->sta.addr, sta->sta.aid); @@ -786,15 +797,12 @@ static int ap_sta_ps_end(struct sta_info *sta) { struct ieee80211_sub_if_data *sdata = sta->sdata; struct ieee80211_local *local = sdata->local; - struct sk_buff *skb; - int sent = 0; + int sent, buffered; atomic_dec(&sdata->bss->num_sta_ps); clear_sta_flags(sta, WLAN_STA_PS | WLAN_STA_PSPOLL); - if (local->ops->sta_notify) - local->ops->sta_notify(local_to_hw(local), &sdata->vif, - STA_NOTIFY_AWAKE, &sta->sta); + drv_sta_notify(local, &sdata->vif, STA_NOTIFY_AWAKE, &sta->sta); if (!skb_queue_empty(&sta->ps_tx_buf)) sta_info_clear_tim_bit(sta); @@ -805,22 +813,16 @@ static int ap_sta_ps_end(struct sta_info *sta) #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ /* Send all buffered frames to the station */ - while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) { - sent++; - skb->requeue = 1; - dev_queue_xmit(skb); - } - while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) { - local->total_ps_buffered--; - sent++; + sent = ieee80211_add_pending_skbs(local, &sta->tx_filtered); + buffered = ieee80211_add_pending_skbs(local, &sta->ps_tx_buf); + sent += buffered; + local->total_ps_buffered -= buffered; + #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - printk(KERN_DEBUG "%s: STA %pM aid %d send PS frame " - "since STA not sleeping anymore\n", sdata->dev->name, - sta->sta.addr, sta->sta.aid); + printk(KERN_DEBUG "%s: STA %pM aid %d sending %d filtered/%d PS frames " + "since STA not sleeping anymore\n", sdata->dev->name, + sta->sta.addr, sta->sta.aid, sent - buffered, buffered); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ - skb->requeue = 1; - dev_queue_xmit(skb); - } return sent; } @@ -1212,109 +1214,38 @@ ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc) /* Drop unencrypted frames if key is set. */ if (unlikely(!ieee80211_has_protected(fc) && !ieee80211_is_nullfunc(fc) && - (!ieee80211_is_mgmt(fc) || - (ieee80211_is_unicast_robust_mgmt_frame(rx->skb) && - rx->sta && test_sta_flags(rx->sta, WLAN_STA_MFP))) && - (rx->key || rx->sdata->drop_unencrypted))) - return -EACCES; - /* BIP does not use Protected field, so need to check MMIE */ - if (unlikely(rx->sta && test_sta_flags(rx->sta, WLAN_STA_MFP) && - ieee80211_is_multicast_robust_mgmt_frame(rx->skb) && - ieee80211_get_mmie_keyidx(rx->skb) < 0 && + ieee80211_is_data(fc) && (rx->key || rx->sdata->drop_unencrypted))) return -EACCES; + if (rx->sta && test_sta_flags(rx->sta, WLAN_STA_MFP)) { + if (unlikely(ieee80211_is_unicast_robust_mgmt_frame(rx->skb) && + rx->key)) + return -EACCES; + /* BIP does not use Protected field, so need to check MMIE */ + if (unlikely(ieee80211_is_multicast_robust_mgmt_frame(rx->skb) + && ieee80211_get_mmie_keyidx(rx->skb) < 0 && + rx->key)) + return -EACCES; + /* + * When using MFP, Action frames are not allowed prior to + * having configured keys. + */ + if (unlikely(ieee80211_is_action(fc) && !rx->key && + ieee80211_is_robust_mgmt_frame( + (struct ieee80211_hdr *) rx->skb->data))) + return -EACCES; + } return 0; } static int -ieee80211_data_to_8023(struct ieee80211_rx_data *rx) +__ieee80211_data_to_8023(struct ieee80211_rx_data *rx) { struct net_device *dev = rx->dev; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; - u16 hdrlen, ethertype; - u8 *payload; - u8 dst[ETH_ALEN]; - u8 src[ETH_ALEN] __aligned(2); - struct sk_buff *skb = rx->skb; struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - if (unlikely(!ieee80211_is_data_present(hdr->frame_control))) - return -1; - - hdrlen = ieee80211_hdrlen(hdr->frame_control); - - /* convert IEEE 802.11 header + possible LLC headers into Ethernet - * header - * IEEE 802.11 address fields: - * ToDS FromDS Addr1 Addr2 Addr3 Addr4 - * 0 0 DA SA BSSID n/a - * 0 1 DA BSSID SA n/a - * 1 0 BSSID SA DA n/a - * 1 1 RA TA DA SA - */ - memcpy(dst, ieee80211_get_DA(hdr), ETH_ALEN); - memcpy(src, ieee80211_get_SA(hdr), ETH_ALEN); - - switch (hdr->frame_control & - cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) { - case cpu_to_le16(IEEE80211_FCTL_TODS): - if (unlikely(sdata->vif.type != NL80211_IFTYPE_AP && - sdata->vif.type != NL80211_IFTYPE_AP_VLAN)) - return -1; - break; - case cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS): - if (unlikely(sdata->vif.type != NL80211_IFTYPE_WDS && - sdata->vif.type != NL80211_IFTYPE_MESH_POINT)) - return -1; - if (ieee80211_vif_is_mesh(&sdata->vif)) { - struct ieee80211s_hdr *meshdr = (struct ieee80211s_hdr *) - (skb->data + hdrlen); - hdrlen += ieee80211_get_mesh_hdrlen(meshdr); - if (meshdr->flags & MESH_FLAGS_AE_A5_A6) { - memcpy(dst, meshdr->eaddr1, ETH_ALEN); - memcpy(src, meshdr->eaddr2, ETH_ALEN); - } - } - break; - case cpu_to_le16(IEEE80211_FCTL_FROMDS): - if (sdata->vif.type != NL80211_IFTYPE_STATION || - (is_multicast_ether_addr(dst) && - !compare_ether_addr(src, dev->dev_addr))) - return -1; - break; - case cpu_to_le16(0): - if (sdata->vif.type != NL80211_IFTYPE_ADHOC) - return -1; - break; - } - - if (unlikely(skb->len - hdrlen < 8)) - return -1; - - payload = skb->data + hdrlen; - ethertype = (payload[6] << 8) | payload[7]; - - if (likely((compare_ether_addr(payload, rfc1042_header) == 0 && - ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || - compare_ether_addr(payload, bridge_tunnel_header) == 0)) { - /* remove RFC1042 or Bridge-Tunnel encapsulation and - * replace EtherType */ - skb_pull(skb, hdrlen + 6); - memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); - memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); - } else { - struct ethhdr *ehdr; - __be16 len; - - skb_pull(skb, hdrlen); - len = htons(skb->len); - ehdr = (struct ethhdr *) skb_push(skb, sizeof(struct ethhdr)); - memcpy(ehdr->h_dest, dst, ETH_ALEN); - memcpy(ehdr->h_source, src, ETH_ALEN); - ehdr->h_proto = len; - } - return 0; + return ieee80211_data_to_8023(rx->skb, dev->dev_addr, sdata->vif.type); } /* @@ -1397,7 +1328,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) * mac80211. That also explains the __skb_push() * below. */ - align = (unsigned long)skb->data & 3; + align = ((unsigned long)(skb->data + sizeof(struct ethhdr))) & 3; if (align) { if (WARN_ON(skb_headroom(skb) < 3)) { dev_kfree_skb(skb); @@ -1453,7 +1384,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx) if (!(rx->flags & IEEE80211_RX_AMSDU)) return RX_CONTINUE; - err = ieee80211_data_to_8023(rx); + err = __ieee80211_data_to_8023(rx); if (unlikely(err)) return RX_DROP_UNUSABLE; @@ -1639,7 +1570,7 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx) if (unlikely(!ieee80211_is_data_present(hdr->frame_control))) return RX_DROP_MONITOR; - err = ieee80211_data_to_8023(rx); + err = __ieee80211_data_to_8023(rx); if (unlikely(err)) return RX_DROP_UNUSABLE; @@ -1827,6 +1758,9 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) sizeof(mgmt->u.action.u.chan_switch))) return RX_DROP_MONITOR; + if (sdata->vif.type != NL80211_IFTYPE_STATION) + return RX_DROP_MONITOR; + if (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN)) return RX_DROP_MONITOR; @@ -1837,7 +1771,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) if (!bss) return RX_DROP_MONITOR; - ieee80211_process_chanswitch(sdata, + ieee80211_sta_process_chanswitch(sdata, &mgmt->u.action.u.chan_switch.sw_elem, bss); ieee80211_rx_bss_put(local, bss); break; @@ -1932,7 +1866,7 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev, !ieee80211_is_auth(hdr->frame_control)) goto ignore; - mac80211_ev_michael_mic_failure(rx->sdata, keyidx, hdr); + mac80211_ev_michael_mic_failure(rx->sdata, keyidx, hdr, NULL); ignore: dev_kfree_skb(rx->skb); rx->skb = NULL; @@ -2287,6 +2221,43 @@ static inline u16 seq_sub(u16 sq1, u16 sq2) } +static void ieee80211_release_reorder_frame(struct ieee80211_hw *hw, + struct tid_ampdu_rx *tid_agg_rx, + int index) +{ + struct ieee80211_supported_band *sband; + struct ieee80211_rate *rate; + struct ieee80211_rx_status status; + + if (!tid_agg_rx->reorder_buf[index]) + goto no_frame; + + /* release the reordered frames to stack */ + memcpy(&status, tid_agg_rx->reorder_buf[index]->cb, sizeof(status)); + sband = hw->wiphy->bands[status.band]; + if (status.flag & RX_FLAG_HT) + rate = sband->bitrates; /* TODO: HT rates */ + else + rate = &sband->bitrates[status.rate_idx]; + __ieee80211_rx_handle_packet(hw, tid_agg_rx->reorder_buf[index], + &status, rate); + tid_agg_rx->stored_mpdu_num--; + tid_agg_rx->reorder_buf[index] = NULL; + +no_frame: + tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num); +} + + +/* + * Timeout (in jiffies) for skb's that are waiting in the RX reorder buffer. If + * the skb was added to the buffer longer than this time ago, the earlier + * frames that have not yet been received are assumed to be lost and the skb + * can be released for processing. This may also release other skb's from the + * reorder buffer if there are no additional gaps between the frames. + */ +#define HT_RX_REORDER_BUF_TIMEOUT (HZ / 10) + /* * As it function blongs to Rx path it must be called with * the proper rcu_read_lock protection for its flow. @@ -2298,12 +2269,8 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, u16 mpdu_seq_num, int bar_req) { - struct ieee80211_local *local = hw_to_local(hw); - struct ieee80211_rx_status status; u16 head_seq_num, buf_size; int index; - struct ieee80211_supported_band *sband; - struct ieee80211_rate *rate; buf_size = tid_agg_rx->buf_size; head_seq_num = tid_agg_rx->head_seq_num; @@ -2328,28 +2295,8 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % tid_agg_rx->buf_size; - - if (tid_agg_rx->reorder_buf[index]) { - /* release the reordered frames to stack */ - memcpy(&status, - tid_agg_rx->reorder_buf[index]->cb, - sizeof(status)); - sband = local->hw.wiphy->bands[status.band]; - if (status.flag & RX_FLAG_HT) { - /* TODO: HT rates */ - rate = sband->bitrates; - } else { - rate = &sband->bitrates - [status.rate_idx]; - } - __ieee80211_rx_handle_packet(hw, - tid_agg_rx->reorder_buf[index], - &status, rate); - tid_agg_rx->stored_mpdu_num--; - tid_agg_rx->reorder_buf[index] = NULL; - } - tid_agg_rx->head_seq_num = - seq_inc(tid_agg_rx->head_seq_num); + ieee80211_release_reorder_frame(hw, tid_agg_rx, + index); } if (bar_req) return 1; @@ -2376,26 +2323,50 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, /* put the frame in the reordering buffer */ tid_agg_rx->reorder_buf[index] = skb; + tid_agg_rx->reorder_time[index] = jiffies; memcpy(tid_agg_rx->reorder_buf[index]->cb, rxstatus, sizeof(*rxstatus)); tid_agg_rx->stored_mpdu_num++; /* release the buffer until next missing frame */ index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % tid_agg_rx->buf_size; - while (tid_agg_rx->reorder_buf[index]) { - /* release the reordered frame back to stack */ - memcpy(&status, tid_agg_rx->reorder_buf[index]->cb, - sizeof(status)); - sband = local->hw.wiphy->bands[status.band]; - if (status.flag & RX_FLAG_HT) - rate = sband->bitrates; /* TODO: HT rates */ - else - rate = &sband->bitrates[status.rate_idx]; - __ieee80211_rx_handle_packet(hw, tid_agg_rx->reorder_buf[index], - &status, rate); - tid_agg_rx->stored_mpdu_num--; - tid_agg_rx->reorder_buf[index] = NULL; - tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num); + if (!tid_agg_rx->reorder_buf[index] && + tid_agg_rx->stored_mpdu_num > 1) { + /* + * No buffers ready to be released, but check whether any + * frames in the reorder buffer have timed out. + */ + int j; + int skipped = 1; + for (j = (index + 1) % tid_agg_rx->buf_size; j != index; + j = (j + 1) % tid_agg_rx->buf_size) { + if (tid_agg_rx->reorder_buf[j] == NULL) { + skipped++; + continue; + } + if (!time_after(jiffies, tid_agg_rx->reorder_time[j] + + HZ / 10)) + break; + +#ifdef CONFIG_MAC80211_HT_DEBUG + if (net_ratelimit()) + printk(KERN_DEBUG "%s: release an RX reorder " + "frame due to timeout on earlier " + "frames\n", + wiphy_name(hw->wiphy)); +#endif + ieee80211_release_reorder_frame(hw, tid_agg_rx, j); + + /* + * Increment the head seq# also for the skipped slots. + */ + tid_agg_rx->head_seq_num = + (tid_agg_rx->head_seq_num + skipped) & + SEQ_MASK; + skipped = 0; + } + } else while (tid_agg_rx->reorder_buf[index]) { + ieee80211_release_reorder_frame(hw, tid_agg_rx, index); index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % tid_agg_rx->buf_size; } @@ -2517,6 +2488,18 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, return; } + /* + * In theory, the block ack reordering should happen after duplicate + * removal (ieee80211_rx_h_check(), which is an RX handler). As such, + * the call to ieee80211_rx_reorder_ampdu() should really be moved to + * happen as a new RX handler between ieee80211_rx_h_check and + * ieee80211_rx_h_decrypt. This cleanup may eventually happen, but for + * the time being, the call can be here since RX reorder buf processing + * will implicitly skip duplicates. We could, in theory at least, + * process frames that ieee80211_rx_h_passive_scan would drop (e.g., + * frames from other than operational channel), but that should not + * happen in normal networks. + */ if (!ieee80211_rx_reorder_ampdu(local, skb, status)) __ieee80211_rx_handle_packet(hw, skb, status, rate); diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 3bf9839f5916..2a8d09ad17ff 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -21,6 +21,7 @@ #include #include "ieee80211_i.h" +#include "driver-ops.h" #include "mesh.h" #define IEEE80211_PROBE_DELAY (HZ / 33) @@ -202,18 +203,6 @@ ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, return RX_QUEUED; } -void ieee80211_scan_failed(struct ieee80211_local *local) -{ - if (WARN_ON(!local->scan_req)) - return; - - /* notify cfg80211 about the failed scan */ - if (local->scan_req != &local->int_scan_req) - cfg80211_scan_done(local->scan_req, true); - - local->scan_req = NULL; -} - /* * inform AP that we will go to sleep so that it will buffer the frames * while we scan @@ -253,7 +242,7 @@ static void ieee80211_scan_ps_disable(struct ieee80211_sub_if_data *sdata) { struct ieee80211_local *local = sdata->local; - if (!local->powersave) + if (!local->ps_sdata) ieee80211_send_nullfunc(local, sdata, 0); else { /* @@ -274,51 +263,62 @@ static void ieee80211_scan_ps_disable(struct ieee80211_sub_if_data *sdata) } } +static void ieee80211_restore_scan_ies(struct ieee80211_local *local) +{ + kfree(local->scan_req->ie); + local->scan_req->ie = local->orig_ies; + local->scan_req->ie_len = local->orig_ies_len; +} + void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_sub_if_data *sdata; + bool was_hw_scan; - if (WARN_ON(!local->hw_scanning && !local->sw_scanning)) - return; + mutex_lock(&local->scan_mtx); - if (WARN_ON(!local->scan_req)) + if (WARN_ON(!local->hw_scanning && !local->sw_scanning)) { + mutex_unlock(&local->scan_mtx); return; + } + + if (WARN_ON(!local->scan_req)) { + mutex_unlock(&local->scan_mtx); + return; + } + + if (local->hw_scanning) + ieee80211_restore_scan_ies(local); if (local->scan_req != &local->int_scan_req) cfg80211_scan_done(local->scan_req, aborted); local->scan_req = NULL; - local->last_scan_completed = jiffies; - - if (local->hw_scanning) { - local->hw_scanning = false; - /* - * Somebody might have requested channel change during scan - * that we won't have acted upon, try now. ieee80211_hw_config - * will set the flag based on actual changes. - */ - ieee80211_hw_config(local, 0); - goto done; - } - + was_hw_scan = local->hw_scanning; + local->hw_scanning = false; local->sw_scanning = false; + local->scan_channel = NULL; + + /* we only have to protect scan_req and hw/sw scan */ + mutex_unlock(&local->scan_mtx); + ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); + if (was_hw_scan) + goto done; netif_tx_lock_bh(local->mdev); netif_addr_lock(local->mdev); local->filter_flags &= ~FIF_BCN_PRBRESP_PROMISC; - local->ops->configure_filter(local_to_hw(local), - FIF_BCN_PRBRESP_PROMISC, - &local->filter_flags, - local->mdev->mc_count, - local->mdev->mc_list); + drv_configure_filter(local, FIF_BCN_PRBRESP_PROMISC, + &local->filter_flags, + local->mdev->mc_count, + local->mdev->mc_list); netif_addr_unlock(local->mdev); netif_tx_unlock_bh(local->mdev); - if (local->ops->sw_scan_complete) - local->ops->sw_scan_complete(local_to_hw(local)); + drv_sw_scan_complete(local); mutex_lock(&local->iflist_mtx); list_for_each_entry(sdata, &local->interfaces, list) { @@ -338,18 +338,160 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) if (sdata->vif.type == NL80211_IFTYPE_AP || sdata->vif.type == NL80211_IFTYPE_ADHOC || sdata->vif.type == NL80211_IFTYPE_MESH_POINT) - ieee80211_if_config(sdata, - IEEE80211_IFCC_BEACON_ENABLED); + ieee80211_bss_info_change_notify( + sdata, BSS_CHANGED_BEACON_ENABLED); } mutex_unlock(&local->iflist_mtx); done: + ieee80211_recalc_idle(local); ieee80211_mlme_notify_scan_completed(local); ieee80211_ibss_notify_scan_completed(local); ieee80211_mesh_notify_scan_completed(local); } EXPORT_SYMBOL(ieee80211_scan_completed); +static int ieee80211_start_sw_scan(struct ieee80211_local *local) +{ + struct ieee80211_sub_if_data *sdata; + + /* + * Hardware/driver doesn't support hw_scan, so use software + * scanning instead. First send a nullfunc frame with power save + * bit on so that AP will buffer the frames for us while we are not + * listening, then send probe requests to each channel and wait for + * the responses. After all channels are scanned, tune back to the + * original channel and send a nullfunc frame with power save bit + * off to trigger the AP to send us all the buffered frames. + * + * Note that while local->sw_scanning is true everything else but + * nullfunc frames and probe requests will be dropped in + * ieee80211_tx_h_check_assoc(). + */ + drv_sw_scan_start(local); + + mutex_lock(&local->iflist_mtx); + list_for_each_entry(sdata, &local->interfaces, list) { + if (!netif_running(sdata->dev)) + continue; + + /* disable beaconing */ + if (sdata->vif.type == NL80211_IFTYPE_AP || + sdata->vif.type == NL80211_IFTYPE_ADHOC || + sdata->vif.type == NL80211_IFTYPE_MESH_POINT) + ieee80211_bss_info_change_notify( + sdata, BSS_CHANGED_BEACON_ENABLED); + + if (sdata->vif.type == NL80211_IFTYPE_STATION) { + if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED) { + netif_tx_stop_all_queues(sdata->dev); + ieee80211_scan_ps_enable(sdata); + } + } else + netif_tx_stop_all_queues(sdata->dev); + } + mutex_unlock(&local->iflist_mtx); + + local->scan_state = SCAN_SET_CHANNEL; + local->scan_channel_idx = 0; + + netif_addr_lock_bh(local->mdev); + local->filter_flags |= FIF_BCN_PRBRESP_PROMISC; + drv_configure_filter(local, FIF_BCN_PRBRESP_PROMISC, + &local->filter_flags, + local->mdev->mc_count, + local->mdev->mc_list); + netif_addr_unlock_bh(local->mdev); + + /* TODO: start scan as soon as all nullfunc frames are ACKed */ + queue_delayed_work(local->hw.workqueue, &local->scan_work, + IEEE80211_CHANNEL_TIME); + + return 0; +} + + +static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, + struct cfg80211_scan_request *req) +{ + struct ieee80211_local *local = sdata->local; + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + int rc; + + if (local->scan_req) + return -EBUSY; + + if (local->ops->hw_scan) { + u8 *ies; + int ielen; + + ies = kmalloc(2 + IEEE80211_MAX_SSID_LEN + + local->scan_ies_len + req->ie_len, GFP_KERNEL); + if (!ies) + return -ENOMEM; + + ielen = ieee80211_build_preq_ies(local, ies, + req->ie, req->ie_len); + local->orig_ies = req->ie; + local->orig_ies_len = req->ie_len; + req->ie = ies; + req->ie_len = ielen; + } + + local->scan_req = req; + local->scan_sdata = sdata; + + if (req != &local->int_scan_req && + sdata->vif.type == NL80211_IFTYPE_STATION && + (ifmgd->state == IEEE80211_STA_MLME_DIRECT_PROBE || + ifmgd->state == IEEE80211_STA_MLME_AUTHENTICATE || + ifmgd->state == IEEE80211_STA_MLME_ASSOCIATE)) { + /* actually wait for the assoc to finish/time out */ + set_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request); + return 0; + } + + if (local->ops->hw_scan) + local->hw_scanning = true; + else + local->sw_scanning = true; + /* + * Kicking off the scan need not be protected, + * only the scan variable stuff, since now + * local->scan_req is assigned and other callers + * will abort their scan attempts. + * + * This avoids getting a scan_mtx -> iflist_mtx + * dependency, so that the scan completed calls + * have more locking freedom. + */ + + ieee80211_recalc_idle(local); + mutex_unlock(&local->scan_mtx); + + if (local->ops->hw_scan) + rc = drv_hw_scan(local, local->scan_req); + else + rc = ieee80211_start_sw_scan(local); + + mutex_lock(&local->scan_mtx); + + if (rc) { + if (local->ops->hw_scan) { + local->hw_scanning = false; + ieee80211_restore_scan_ies(local); + } else + local->sw_scanning = false; + + ieee80211_recalc_idle(local); + + local->scan_req = NULL; + local->scan_sdata = NULL; + } + + return rc; +} + void ieee80211_scan_work(struct work_struct *work) { struct ieee80211_local *local = @@ -359,17 +501,41 @@ void ieee80211_scan_work(struct work_struct *work) int skip, i; unsigned long next_delay = 0; + mutex_lock(&local->scan_mtx); + if (!sdata || !local->scan_req) { + mutex_unlock(&local->scan_mtx); + return; + } + + if (local->scan_req && !(local->sw_scanning || local->hw_scanning)) { + struct cfg80211_scan_request *req = local->scan_req; + int rc; + + local->scan_req = NULL; + + rc = __ieee80211_start_scan(sdata, req); + mutex_unlock(&local->scan_mtx); + + if (rc) + ieee80211_scan_completed(&local->hw, true); + return; + } + + mutex_unlock(&local->scan_mtx); + /* * Avoid re-scheduling when the sdata is going away. */ - if (!netif_running(sdata->dev)) + if (!netif_running(sdata->dev)) { + ieee80211_scan_completed(&local->hw, true); return; + } switch (local->scan_state) { case SCAN_SET_CHANNEL: /* if no more bands/channels left, complete scan */ if (local->scan_channel_idx >= local->scan_req->n_channels) { - ieee80211_scan_completed(local_to_hw(local), false); + ieee80211_scan_completed(&local->hw, false); return; } skip = 0; @@ -393,24 +559,39 @@ void ieee80211_scan_work(struct work_struct *work) if (skip) break; - next_delay = IEEE80211_PROBE_DELAY + - usecs_to_jiffies(local->hw.channel_change_time); + /* + * Probe delay is used to update the NAV, cf. 11.1.3.2.2 + * (which unfortunately doesn't say _why_ step a) is done, + * but it waits for the probe delay or until a frame is + * received - and the received frame would update the NAV). + * For now, we do not support waiting until a frame is + * received. + * + * In any case, it is not necessary for a passive scan. + */ + if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN || + !local->scan_req->n_ssids) { + next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; + break; + } + + next_delay = IEEE80211_PROBE_DELAY; local->scan_state = SCAN_SEND_PROBE; break; case SCAN_SEND_PROBE: - next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; - local->scan_state = SCAN_SET_CHANNEL; - - if (local->scan_channel->flags & IEEE80211_CHAN_PASSIVE_SCAN || - !local->scan_req->n_ssids) - break; for (i = 0; i < local->scan_req->n_ssids; i++) ieee80211_send_probe_req( sdata, NULL, local->scan_req->ssids[i].ssid, local->scan_req->ssids[i].ssid_len, local->scan_req->ie, local->scan_req->ie_len); + + /* + * After sending probe requests, wait for probe responses + * on the channel. + */ next_delay = IEEE80211_CHANNEL_TIME; + local->scan_state = SCAN_SET_CHANNEL; break; } @@ -418,150 +599,53 @@ void ieee80211_scan_work(struct work_struct *work) next_delay); } - -int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata, - struct cfg80211_scan_request *req) -{ - struct ieee80211_local *local = scan_sdata->local; - struct ieee80211_sub_if_data *sdata; - - if (!req) - return -EINVAL; - - if (local->scan_req && local->scan_req != req) - return -EBUSY; - - local->scan_req = req; - - /* MLME-SCAN.request (page 118) page 144 (11.1.3.1) - * BSSType: INFRASTRUCTURE, INDEPENDENT, ANY_BSS - * BSSID: MACAddress - * SSID - * ScanType: ACTIVE, PASSIVE - * ProbeDelay: delay (in microseconds) to be used prior to transmitting - * a Probe frame during active scanning - * ChannelList - * MinChannelTime (>= ProbeDelay), in TU - * MaxChannelTime: (>= MinChannelTime), in TU - */ - - /* MLME-SCAN.confirm - * BSSDescriptionSet - * ResultCode: SUCCESS, INVALID_PARAMETERS - */ - - if (local->sw_scanning || local->hw_scanning) { - if (local->scan_sdata == scan_sdata) - return 0; - return -EBUSY; - } - - if (local->ops->hw_scan) { - int rc; - - local->hw_scanning = true; - rc = local->ops->hw_scan(local_to_hw(local), req); - if (rc) { - local->hw_scanning = false; - return rc; - } - local->scan_sdata = scan_sdata; - return 0; - } - - /* - * Hardware/driver doesn't support hw_scan, so use software - * scanning instead. First send a nullfunc frame with power save - * bit on so that AP will buffer the frames for us while we are not - * listening, then send probe requests to each channel and wait for - * the responses. After all channels are scanned, tune back to the - * original channel and send a nullfunc frame with power save bit - * off to trigger the AP to send us all the buffered frames. - * - * Note that while local->sw_scanning is true everything else but - * nullfunc frames and probe requests will be dropped in - * ieee80211_tx_h_check_assoc(). - */ - local->sw_scanning = true; - if (local->ops->sw_scan_start) - local->ops->sw_scan_start(local_to_hw(local)); - - mutex_lock(&local->iflist_mtx); - list_for_each_entry(sdata, &local->interfaces, list) { - if (!netif_running(sdata->dev)) - continue; - - /* disable beaconing */ - if (sdata->vif.type == NL80211_IFTYPE_AP || - sdata->vif.type == NL80211_IFTYPE_ADHOC || - sdata->vif.type == NL80211_IFTYPE_MESH_POINT) - ieee80211_if_config(sdata, - IEEE80211_IFCC_BEACON_ENABLED); - - if (sdata->vif.type == NL80211_IFTYPE_STATION) { - if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED) { - netif_tx_stop_all_queues(sdata->dev); - ieee80211_scan_ps_enable(sdata); - } - } else - netif_tx_stop_all_queues(sdata->dev); - } - mutex_unlock(&local->iflist_mtx); - - local->scan_state = SCAN_SET_CHANNEL; - local->scan_channel_idx = 0; - local->scan_sdata = scan_sdata; - local->scan_req = req; - - netif_addr_lock_bh(local->mdev); - local->filter_flags |= FIF_BCN_PRBRESP_PROMISC; - local->ops->configure_filter(local_to_hw(local), - FIF_BCN_PRBRESP_PROMISC, - &local->filter_flags, - local->mdev->mc_count, - local->mdev->mc_list); - netif_addr_unlock_bh(local->mdev); - - /* TODO: start scan as soon as all nullfunc frames are ACKed */ - queue_delayed_work(local->hw.workqueue, &local->scan_work, - IEEE80211_CHANNEL_TIME); - - return 0; -} - - int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, struct cfg80211_scan_request *req) +{ + int res; + + mutex_lock(&sdata->local->scan_mtx); + res = __ieee80211_start_scan(sdata, req); + mutex_unlock(&sdata->local->scan_mtx); + + return res; +} + +int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata, + const u8 *ssid, u8 ssid_len) { struct ieee80211_local *local = sdata->local; - struct ieee80211_if_managed *ifmgd; + int ret = -EBUSY; - if (!req) - return -EINVAL; + mutex_lock(&local->scan_mtx); - if (local->scan_req && local->scan_req != req) - return -EBUSY; + /* busy scanning */ + if (local->scan_req) + goto unlock; - local->scan_req = req; + memcpy(local->int_scan_req.ssids[0].ssid, ssid, IEEE80211_MAX_SSID_LEN); + local->int_scan_req.ssids[0].ssid_len = ssid_len; - if (sdata->vif.type != NL80211_IFTYPE_STATION) - return ieee80211_start_scan(sdata, req); + ret = __ieee80211_start_scan(sdata, &sdata->local->int_scan_req); + unlock: + mutex_unlock(&local->scan_mtx); + return ret; +} + +void ieee80211_scan_cancel(struct ieee80211_local *local) +{ + bool swscan; + + cancel_delayed_work_sync(&local->scan_work); /* - * STA has a state machine that might need to defer scanning - * while it's trying to associate/authenticate, therefore we - * queue it up to the state machine in that case. + * Only call this function when a scan can't be + * queued -- mostly at suspend under RTNL. */ + mutex_lock(&local->scan_mtx); + swscan = local->sw_scanning; + mutex_unlock(&local->scan_mtx); - if (local->sw_scanning || local->hw_scanning) { - if (local->scan_sdata == sdata) - return 0; - return -EBUSY; - } - - ifmgd = &sdata->u.mgd; - set_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request); - queue_work(local->hw.workqueue, &ifmgd->work); - - return 0; + if (swscan) + ieee80211_scan_completed(&local->hw, true); } diff --git a/net/mac80211/spectmgmt.c b/net/mac80211/spectmgmt.c index 5f7a2624ed74..68953033403d 100644 --- a/net/mac80211/spectmgmt.c +++ b/net/mac80211/spectmgmt.c @@ -15,7 +15,7 @@ */ #include -#include +#include #include #include "ieee80211_i.h" #include "sta_info.h" @@ -84,104 +84,3 @@ void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, mgmt->sa, mgmt->bssid, mgmt->u.action.u.measurement.dialog_token); } - -void ieee80211_chswitch_work(struct work_struct *work) -{ - struct ieee80211_sub_if_data *sdata = - container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work); - struct ieee80211_bss *bss; - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - - if (!netif_running(sdata->dev)) - return; - - bss = ieee80211_rx_bss_get(sdata->local, ifmgd->bssid, - sdata->local->hw.conf.channel->center_freq, - ifmgd->ssid, ifmgd->ssid_len); - if (!bss) - goto exit; - - sdata->local->oper_channel = sdata->local->csa_channel; - /* XXX: shouldn't really modify cfg80211-owned data! */ - if (!ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL)) - bss->cbss.channel = sdata->local->oper_channel; - - ieee80211_rx_bss_put(sdata->local, bss); -exit: - ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; - ieee80211_wake_queues_by_reason(&sdata->local->hw, - IEEE80211_QUEUE_STOP_REASON_CSA); -} - -void ieee80211_chswitch_timer(unsigned long data) -{ - struct ieee80211_sub_if_data *sdata = - (struct ieee80211_sub_if_data *) data; - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - - queue_work(sdata->local->hw.workqueue, &ifmgd->chswitch_work); -} - -void ieee80211_process_chanswitch(struct ieee80211_sub_if_data *sdata, - struct ieee80211_channel_sw_ie *sw_elem, - struct ieee80211_bss *bss) -{ - struct ieee80211_channel *new_ch; - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num); - - /* FIXME: Handle ADHOC later */ - if (sdata->vif.type != NL80211_IFTYPE_STATION) - return; - - if (ifmgd->state != IEEE80211_STA_MLME_ASSOCIATED) - return; - - if (sdata->local->sw_scanning || sdata->local->hw_scanning) - return; - - /* Disregard subsequent beacons if we are already running a timer - processing a CSA */ - - if (ifmgd->flags & IEEE80211_STA_CSA_RECEIVED) - return; - - new_ch = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq); - if (!new_ch || new_ch->flags & IEEE80211_CHAN_DISABLED) - return; - - sdata->local->csa_channel = new_ch; - - if (sw_elem->count <= 1) { - queue_work(sdata->local->hw.workqueue, &ifmgd->chswitch_work); - } else { - ieee80211_stop_queues_by_reason(&sdata->local->hw, - IEEE80211_QUEUE_STOP_REASON_CSA); - ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; - mod_timer(&ifmgd->chswitch_timer, - jiffies + - msecs_to_jiffies(sw_elem->count * - bss->cbss.beacon_interval)); - } -} - -void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, - u16 capab_info, u8 *pwr_constr_elem, - u8 pwr_constr_elem_len) -{ - struct ieee80211_conf *conf = &sdata->local->hw.conf; - - if (!(capab_info & WLAN_CAPABILITY_SPECTRUM_MGMT)) - return; - - /* Power constraint IE length should be 1 octet */ - if (pwr_constr_elem_len != 1) - return; - - if ((*pwr_constr_elem <= conf->channel->max_power) && - (*pwr_constr_elem != sdata->local->power_constr_level)) { - sdata->local->power_constr_level = *pwr_constr_elem; - ieee80211_hw_config(sdata->local, 0); - } -} - diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index c5f14e6bbde2..a360bceeba59 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -19,6 +19,7 @@ #include #include "ieee80211_i.h" +#include "driver-ops.h" #include "rate.h" #include "sta_info.h" #include "debugfs_sta.h" @@ -43,6 +44,15 @@ * When the insertion fails (sta_info_insert()) returns non-zero), the * structure will have been freed by sta_info_insert()! * + * sta entries are added by mac80211 when you establish a link with a + * peer. This means different things for the different type of interfaces + * we support. For a regular station this mean we add the AP sta when we + * receive an assocation response from the AP. For IBSS this occurs when + * we receive a probe response or a beacon from target IBSS network. For + * WDS we add the sta for the peer imediately upon device open. When using + * AP mode we add stations for each respective station upon request from + * userspace through nl80211. + * * Because there are debugfs entries for each station, and adding those * must be able to sleep, it is also possible to "pin" a station entry, * that means it can be removed from the hash table but not be freed. @@ -292,6 +302,9 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, skb_queue_head_init(&sta->ps_tx_buf); skb_queue_head_init(&sta->tx_filtered); + for (i = 0; i < NUM_RX_DATA_QUEUES; i++) + sta->last_seq_ctrl[i] = cpu_to_le16(USHORT_MAX); + #ifdef CONFIG_MAC80211_VERBOSE_DEBUG printk(KERN_DEBUG "%s: Allocated STA %pM\n", wiphy_name(local->hw.wiphy), sta->sta.addr); @@ -346,8 +359,7 @@ int sta_info_insert(struct sta_info *sta) struct ieee80211_sub_if_data, u.ap); - local->ops->sta_notify(local_to_hw(local), &sdata->vif, - STA_NOTIFY_ADD, &sta->sta); + drv_sta_notify(local, &sdata->vif, STA_NOTIFY_ADD, &sta->sta); } #ifdef CONFIG_MAC80211_VERBOSE_DEBUG @@ -405,8 +417,7 @@ static void __sta_info_set_tim_bit(struct ieee80211_if_ap *bss, if (sta->local->ops->set_tim) { sta->local->tim_in_locked_section = true; - sta->local->ops->set_tim(local_to_hw(sta->local), - &sta->sta, true); + drv_set_tim(sta->local, &sta->sta, true); sta->local->tim_in_locked_section = false; } } @@ -431,8 +442,7 @@ static void __sta_info_clear_tim_bit(struct ieee80211_if_ap *bss, if (sta->local->ops->set_tim) { sta->local->tim_in_locked_section = true; - sta->local->ops->set_tim(local_to_hw(sta->local), - &sta->sta, false); + drv_set_tim(sta->local, &sta->sta, false); sta->local->tim_in_locked_section = false; } } @@ -482,8 +492,8 @@ static void __sta_info_unlink(struct sta_info **sta) struct ieee80211_sub_if_data, u.ap); - local->ops->sta_notify(local_to_hw(local), &sdata->vif, - STA_NOTIFY_REMOVE, &(*sta)->sta); + drv_sta_notify(local, &sdata->vif, STA_NOTIFY_REMOVE, + &(*sta)->sta); } if (ieee80211_vif_is_mesh(&sdata->vif)) { @@ -543,9 +553,8 @@ void sta_info_unlink(struct sta_info **sta) spin_unlock_irqrestore(&local->sta_lock, flags); } -static inline int sta_info_buffer_expired(struct ieee80211_local *local, - struct sta_info *sta, - struct sk_buff *skb) +static int sta_info_buffer_expired(struct sta_info *sta, + struct sk_buff *skb) { struct ieee80211_tx_info *info; int timeout; @@ -556,8 +565,9 @@ static inline int sta_info_buffer_expired(struct ieee80211_local *local, info = IEEE80211_SKB_CB(skb); /* Timeout: (2 * listen_interval * beacon_int * 1024 / 1000000) sec */ - timeout = (sta->listen_interval * local->hw.conf.beacon_int * 32 / - 15625) * HZ; + timeout = (sta->listen_interval * + sta->sdata->vif.bss_conf.beacon_int * + 32 / 15625) * HZ; if (timeout < STA_TX_BUFFER_EXPIRE) timeout = STA_TX_BUFFER_EXPIRE; return time_after(jiffies, info->control.jiffies + timeout); @@ -577,7 +587,7 @@ static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local, for (;;) { spin_lock_irqsave(&sta->ps_tx_buf.lock, flags); skb = skb_peek(&sta->ps_tx_buf); - if (sta_info_buffer_expired(local, sta, skb)) + if (sta_info_buffer_expired(sta, skb)) skb = __skb_dequeue(&sta->ps_tx_buf); else skb = NULL; @@ -610,6 +620,9 @@ static void sta_info_cleanup(unsigned long data) sta_info_cleanup_expire_buffered(local, sta); rcu_read_unlock(); + if (local->quiescing) + return; + local->sta_cleanup.expires = round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); add_timer(&local->sta_cleanup); @@ -686,41 +699,10 @@ static void sta_info_debugfs_add_work(struct work_struct *work) } #endif -static void __ieee80211_run_pending_flush(struct ieee80211_local *local) -{ - struct sta_info *sta; - unsigned long flags; - - ASSERT_RTNL(); - - spin_lock_irqsave(&local->sta_lock, flags); - while (!list_empty(&local->sta_flush_list)) { - sta = list_first_entry(&local->sta_flush_list, - struct sta_info, list); - list_del(&sta->list); - spin_unlock_irqrestore(&local->sta_lock, flags); - sta_info_destroy(sta); - spin_lock_irqsave(&local->sta_lock, flags); - } - spin_unlock_irqrestore(&local->sta_lock, flags); -} - -static void ieee80211_sta_flush_work(struct work_struct *work) -{ - struct ieee80211_local *local = - container_of(work, struct ieee80211_local, sta_flush_work); - - rtnl_lock(); - __ieee80211_run_pending_flush(local); - rtnl_unlock(); -} - void sta_info_init(struct ieee80211_local *local) { spin_lock_init(&local->sta_lock); INIT_LIST_HEAD(&local->sta_list); - INIT_LIST_HEAD(&local->sta_flush_list); - INIT_WORK(&local->sta_flush_work, ieee80211_sta_flush_work); setup_timer(&local->sta_cleanup, sta_info_cleanup, (unsigned long)local); @@ -741,7 +723,6 @@ int sta_info_start(struct ieee80211_local *local) void sta_info_stop(struct ieee80211_local *local) { del_timer(&local->sta_cleanup); - cancel_work_sync(&local->sta_flush_work); #ifdef CONFIG_MAC80211_DEBUGFS /* * Make sure the debugfs adding work isn't pending after this @@ -752,10 +733,7 @@ void sta_info_stop(struct ieee80211_local *local) cancel_work_sync(&local->sta_debugfs_add); #endif - rtnl_lock(); sta_info_flush(local, NULL); - __ieee80211_run_pending_flush(local); - rtnl_unlock(); } /** @@ -767,7 +745,7 @@ void sta_info_stop(struct ieee80211_local *local) * @sdata: matching rule for the net device (sta->dev) or %NULL to match all STAs */ int sta_info_flush(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata) + struct ieee80211_sub_if_data *sdata) { struct sta_info *sta, *tmp; LIST_HEAD(tmp_list); @@ -775,7 +753,6 @@ int sta_info_flush(struct ieee80211_local *local, unsigned long flags; might_sleep(); - ASSERT_RTNL(); spin_lock_irqsave(&local->sta_lock, flags); list_for_each_entry_safe(sta, tmp, &local->sta_list, list) { @@ -795,39 +772,6 @@ int sta_info_flush(struct ieee80211_local *local, return ret; } -/** - * sta_info_flush_delayed - flush matching STA entries from the STA table - * - * This function unlinks all stations for a given interface and queues - * them for freeing. Note that the workqueue function scheduled here has - * to run before any new keys can be added to the system to avoid set_key() - * callback ordering issues. - * - * @sdata: the interface - */ -void sta_info_flush_delayed(struct ieee80211_sub_if_data *sdata) -{ - struct ieee80211_local *local = sdata->local; - struct sta_info *sta, *tmp; - unsigned long flags; - bool work = false; - - spin_lock_irqsave(&local->sta_lock, flags); - list_for_each_entry_safe(sta, tmp, &local->sta_list, list) { - if (sdata == sta->sdata) { - __sta_info_unlink(&sta); - if (sta) { - list_add_tail(&sta->list, - &local->sta_flush_list); - work = true; - } - } - } - if (work) - schedule_work(&local->sta_flush_work); - spin_unlock_irqrestore(&local->sta_lock, flags); -} - void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, unsigned long exp_time) { diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 5534d489f506..49a1a1f76511 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -88,6 +88,7 @@ struct tid_ampdu_tx { * struct tid_ampdu_rx - TID aggregation information (Rx). * * @reorder_buf: buffer to reorder incoming aggregated MPDUs + * @reorder_time: jiffies when skb was added * @session_timer: check if peer keeps Tx-ing on the TID (by timeout value) * @head_seq_num: head sequence number in reordering buffer. * @stored_mpdu_num: number of MPDUs in reordering buffer @@ -99,6 +100,7 @@ struct tid_ampdu_tx { */ struct tid_ampdu_rx { struct sk_buff **reorder_buf; + unsigned long *reorder_time; struct timer_list session_timer; u16 head_seq_num; u16 stored_mpdu_num; @@ -214,6 +216,7 @@ struct sta_ampdu_mlme { * @plink_state: peer link state * @plink_timeout: timeout of peer link * @plink_timer: peer link watch timer + * @plink_timer_was_running: used by suspend/resume to restore timers * @debugfs: debug filesystem info * @sta: station information we share with the driver */ @@ -291,6 +294,7 @@ struct sta_info { __le16 reason; u8 plink_retries; bool ignore_plink_timer; + bool plink_timer_was_running; enum plink_state plink_state; u32 plink_timeout; struct timer_list plink_timer; @@ -442,8 +446,7 @@ void sta_info_init(struct ieee80211_local *local); int sta_info_start(struct ieee80211_local *local); void sta_info_stop(struct ieee80211_local *local); int sta_info_flush(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata); -void sta_info_flush_delayed(struct ieee80211_sub_if_data *sdata); + struct ieee80211_sub_if_data *sdata); void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, unsigned long exp_time); diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c index 38fa111d2dc6..964b7faa7f17 100644 --- a/net/mac80211/tkip.c +++ b/net/mac80211/tkip.c @@ -13,6 +13,7 @@ #include #include +#include "driver-ops.h" #include "key.h" #include "tkip.h" #include "wep.h" @@ -307,9 +308,8 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, if (is_multicast_ether_addr(ra)) sta_addr = bcast; - key->local->ops->update_tkip_key( - local_to_hw(key->local), &key->conf, - sta_addr, iv32, key->u.tkip.rx[queue].p1k); + drv_update_tkip_key(key->local, &key->conf, sta_addr, + iv32, key->u.tkip.rx[queue].p1k); } } diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 63656266d567..d238a8939a09 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -25,6 +25,7 @@ #include #include "ieee80211_i.h" +#include "driver-ops.h" #include "led.h" #include "mesh.h" #include "wep.h" @@ -399,6 +400,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) sta_info_set_tim_bit(sta); info->control.jiffies = jiffies; + info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; skb_queue_tail(&sta->ps_tx_buf, tx->skb); return TX_QUEUED; } @@ -409,8 +411,24 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) sta->sta.addr); } #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ - clear_sta_flags(sta, WLAN_STA_PSPOLL); + if (test_and_clear_sta_flags(sta, WLAN_STA_PSPOLL)) { + /* + * The sleeping station with pending data is now snoozing. + * It queried us for its buffered frames and will go back + * to deep sleep once it got everything. + * + * inform the driver, in case the hardware does powersave + * frame filtering and keeps a station blacklist on its own + * (e.g: p54), so that frames can be delivered unimpeded. + * + * Note: It should be safe to disable the filter now. + * As, it is really unlikely that we still have any pending + * frame for this station in the hw's buffers/fifos left, + * that is not rejected with a unsuccessful tx_status yet. + */ + info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; + } return TX_CONTINUE; } @@ -429,7 +447,7 @@ ieee80211_tx_h_ps_buf(struct ieee80211_tx_data *tx) static ieee80211_tx_result debug_noinline ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) { - struct ieee80211_key *key; + struct ieee80211_key *key = NULL; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; @@ -500,7 +518,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) sband = tx->local->hw.wiphy->bands[tx->channel->band]; len = min_t(int, tx->skb->len + FCS_LEN, - tx->local->fragmentation_threshold); + tx->local->hw.wiphy->frag_threshold); /* set up the tx rate control struct we give the RC algo */ txrc.hw = local_to_hw(tx->local); @@ -511,8 +529,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) txrc.max_rate_idx = tx->sdata->max_ratectrl_rateidx; /* set up RTS protection if desired */ - if (tx->local->rts_threshold < IEEE80211_MAX_RTS_THRESHOLD && - len > tx->local->rts_threshold) { + if (len > tx->local->hw.wiphy->rts_threshold) { txrc.rts = rts = true; } @@ -542,6 +559,10 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) if (unlikely(!info->control.rates[0].count)) info->control.rates[0].count = 1; + if (WARN_ON_ONCE((info->control.rates[0].count > 1) && + (info->flags & IEEE80211_TX_CTL_NO_ACK))) + info->control.rates[0].count = 1; + if (is_multicast_ether_addr(hdr->addr1)) { /* * XXX: verify the rate is in the basic rateset @@ -754,7 +775,7 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) struct sk_buff *skb = tx->skb; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_hdr *hdr = (void *)skb->data; - int frag_threshold = tx->local->fragmentation_threshold; + int frag_threshold = tx->local->hw.wiphy->frag_threshold; int hdrlen; int fragnum; @@ -852,6 +873,8 @@ ieee80211_tx_h_calculate_duration(struct ieee80211_tx_data *tx) do { hdr = (void *) skb->data; + if (unlikely(ieee80211_is_pspoll(hdr->frame_control))) + break; /* must not overwrite AID */ next_len = skb->next ? skb->next->len : 0; group_addr = is_multicast_ether_addr(hdr->addr1); @@ -885,9 +908,8 @@ ieee80211_tx_h_stats(struct ieee80211_tx_data *tx) * deal with packet injection down monitor interface * with Radiotap Header -- only called for monitor mode interface */ -static ieee80211_tx_result -__ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, - struct sk_buff *skb) +static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, + struct sk_buff *skb) { /* * this is the moment to interpret and discard the radiotap header that @@ -938,7 +960,7 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, * on transmission */ if (skb->len < (iterator.max_length + FCS_LEN)) - return TX_DROP; + return false; skb_trim(skb, skb->len - FCS_LEN); } @@ -960,7 +982,7 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, } if (ret != -ENOENT) /* ie, if we didn't simply run out of fields */ - return TX_DROP; + return false; /* * remove the radiotap header @@ -969,7 +991,7 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, */ skb_pull(skb, iterator.max_length); - return TX_CONTINUE; + return true; } /* @@ -1003,7 +1025,7 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx, /* process and remove the injection radiotap header */ sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED)) { - if (__ieee80211_parse_tx_radiotap(tx, skb) == TX_DROP) + if (!__ieee80211_parse_tx_radiotap(tx, skb)) return TX_DROP; /* @@ -1067,12 +1089,15 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx, info->flags |= IEEE80211_TX_CTL_NO_ACK; } else { tx->flags |= IEEE80211_TX_UNICAST; - info->flags &= ~IEEE80211_TX_CTL_NO_ACK; + if (unlikely(local->wifi_wme_noack_test)) + info->flags |= IEEE80211_TX_CTL_NO_ACK; + else + info->flags &= ~IEEE80211_TX_CTL_NO_ACK; } if (tx->flags & IEEE80211_TX_FRAGMENTED) { if ((tx->flags & IEEE80211_TX_UNICAST) && - skb->len + FCS_LEN > local->fragmentation_threshold && + skb->len + FCS_LEN > local->hw.wiphy->frag_threshold && !(info->flags & IEEE80211_TX_CTL_AMPDU)) tx->flags |= IEEE80211_TX_FRAGMENTED; else @@ -1147,7 +1172,7 @@ static int __ieee80211_tx(struct ieee80211_local *local, next = skb->next; len = skb->len; - ret = local->ops->tx(local_to_hw(local), skb); + ret = drv_tx(local, skb); if (WARN_ON(ret != NETDEV_TX_OK && skb->len != len)) { dev_kfree_skb(skb); ret = NETDEV_TX_OK; @@ -1213,7 +1238,6 @@ static void ieee80211_tx(struct net_device *dev, struct sk_buff *skb, bool txpending) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct sta_info *sta; struct ieee80211_tx_data tx; ieee80211_tx_result res_prepare; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); @@ -1245,7 +1269,6 @@ static void ieee80211_tx(struct net_device *dev, struct sk_buff *skb, return; } - sta = tx.sta; tx.channel = local->hw.conf.channel; info->band = tx.channel->band; @@ -1392,7 +1415,8 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev) } if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) && - local->hw.conf.dynamic_ps_timeout > 0) { + local->hw.conf.dynamic_ps_timeout > 0 && + !local->sw_scanning && !local->hw_scanning && local->ps_sdata) { if (local->hw.conf.flags & IEEE80211_CONF_PS) { ieee80211_stop_queues_by_reason(&local->hw, IEEE80211_QUEUE_STOP_REASON_PS); @@ -1591,7 +1615,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_local *local = sdata->local; - int ret = 1, head_need; + int ret = NETDEV_TX_BUSY, head_need; u16 ethertype, hdrlen, meshhdrlen = 0; __le16 fc; struct ieee80211_hdr hdr; @@ -2086,18 +2110,18 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; struct ieee80211_hdr *hdr; + struct sk_buff *presp = rcu_dereference(ifibss->presp); - if (!ifibss->probe_resp) + if (!presp) goto out; - skb = skb_copy(ifibss->probe_resp, GFP_ATOMIC); + skb = skb_copy(presp, GFP_ATOMIC); if (!skb) goto out; hdr = (struct ieee80211_hdr *) skb->data; hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON); - } else if (ieee80211_vif_is_mesh(&sdata->vif)) { struct ieee80211_mgmt *mgmt; u8 *pos; @@ -2117,7 +2141,7 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); /* BSSID is left zeroed, wildcard value */ mgmt->u.beacon.beacon_int = - cpu_to_le16(local->hw.conf.beacon_int); + cpu_to_le16(sdata->vif.bss_conf.beacon_int); mgmt->u.beacon.capab_info = 0x0; /* 0x0 for MPs */ pos = skb_put(skb, 2); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index fdf432f14554..915e77769312 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -20,27 +20,21 @@ #include #include #include +#include #include #include #include #include "ieee80211_i.h" +#include "driver-ops.h" #include "rate.h" #include "mesh.h" #include "wme.h" +#include "led.h" /* privid for wiphys to determine whether they belong to us or not */ void *mac80211_wiphy_privid = &mac80211_wiphy_privid; -/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ -/* Ethernet-II snap header (RFC1042 for most EtherTypes) */ -const unsigned char rfc1042_header[] __aligned(2) = - { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; - -/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ -const unsigned char bridge_tunnel_header[] __aligned(2) = - { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; - struct ieee80211_hw *wiphy_to_ieee80211_hw(struct wiphy *wiphy) { struct ieee80211_local *local; @@ -100,70 +94,6 @@ u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len, return NULL; } -unsigned int ieee80211_hdrlen(__le16 fc) -{ - unsigned int hdrlen = 24; - - if (ieee80211_is_data(fc)) { - if (ieee80211_has_a4(fc)) - hdrlen = 30; - if (ieee80211_is_data_qos(fc)) - hdrlen += IEEE80211_QOS_CTL_LEN; - goto out; - } - - if (ieee80211_is_ctl(fc)) { - /* - * ACK and CTS are 10 bytes, all others 16. To see how - * to get this condition consider - * subtype mask: 0b0000000011110000 (0x00F0) - * ACK subtype: 0b0000000011010000 (0x00D0) - * CTS subtype: 0b0000000011000000 (0x00C0) - * bits that matter: ^^^ (0x00E0) - * value of those: 0b0000000011000000 (0x00C0) - */ - if ((fc & cpu_to_le16(0x00E0)) == cpu_to_le16(0x00C0)) - hdrlen = 10; - else - hdrlen = 16; - } -out: - return hdrlen; -} -EXPORT_SYMBOL(ieee80211_hdrlen); - -unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb) -{ - const struct ieee80211_hdr *hdr = (const struct ieee80211_hdr *)skb->data; - unsigned int hdrlen; - - if (unlikely(skb->len < 10)) - return 0; - hdrlen = ieee80211_hdrlen(hdr->frame_control); - if (unlikely(hdrlen > skb->len)) - return 0; - return hdrlen; -} -EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb); - -int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr) -{ - int ae = meshhdr->flags & IEEE80211S_FLAGS_AE; - /* 7.1.3.5a.2 */ - switch (ae) { - case 0: - return 6; - case 1: - return 12; - case 2: - return 18; - case 3: - return 24; - default: - return 6; - } -} - void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx) { struct sk_buff *skb = tx->skb; @@ -411,6 +341,52 @@ void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue) } EXPORT_SYMBOL(ieee80211_stop_queue); +void ieee80211_add_pending_skb(struct ieee80211_local *local, + struct sk_buff *skb) +{ + struct ieee80211_hw *hw = &local->hw; + unsigned long flags; + int queue = skb_get_queue_mapping(skb); + + spin_lock_irqsave(&local->queue_stop_reason_lock, flags); + __ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD); + __ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_PENDING); + skb_queue_tail(&local->pending[queue], skb); + __ieee80211_wake_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD); + spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); +} + +int ieee80211_add_pending_skbs(struct ieee80211_local *local, + struct sk_buff_head *skbs) +{ + struct ieee80211_hw *hw = &local->hw; + struct sk_buff *skb; + unsigned long flags; + int queue, ret = 0, i; + + spin_lock_irqsave(&local->queue_stop_reason_lock, flags); + for (i = 0; i < hw->queues; i++) + __ieee80211_stop_queue(hw, i, + IEEE80211_QUEUE_STOP_REASON_SKB_ADD); + + while ((skb = skb_dequeue(skbs))) { + ret++; + queue = skb_get_queue_mapping(skb); + skb_queue_tail(&local->pending[queue], skb); + } + + for (i = 0; i < hw->queues; i++) { + if (ret) + __ieee80211_stop_queue(hw, i, + IEEE80211_QUEUE_STOP_REASON_PENDING); + __ieee80211_wake_queue(hw, i, + IEEE80211_QUEUE_STOP_REASON_SKB_ADD); + } + spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); + + return ret; +} + void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, enum queue_stop_reason reason) { @@ -535,9 +511,17 @@ EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic); void ieee802_11_parse_elems(u8 *start, size_t len, struct ieee802_11_elems *elems) +{ + ieee802_11_parse_elems_crc(start, len, elems, 0, 0); +} + +u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, + struct ieee802_11_elems *elems, + u64 filter, u32 crc) { size_t left = len; u8 *pos = start; + bool calc_crc = filter != 0; memset(elems, 0, sizeof(*elems)); elems->ie_start = start; @@ -551,7 +535,10 @@ void ieee802_11_parse_elems(u8 *start, size_t len, left -= 2; if (elen > left) - return; + break; + + if (calc_crc && id < 64 && (filter & BIT(id))) + crc = crc32_be(crc, pos - 2, elen + 2); switch (id) { case WLAN_EID_SSID: @@ -575,8 +562,10 @@ void ieee802_11_parse_elems(u8 *start, size_t len, elems->cf_params_len = elen; break; case WLAN_EID_TIM: - elems->tim = pos; - elems->tim_len = elen; + if (elen >= sizeof(struct ieee80211_tim_ie)) { + elems->tim = (void *)pos; + elems->tim_len = elen; + } break; case WLAN_EID_IBSS_PARAMS: elems->ibss_params = pos; @@ -586,15 +575,20 @@ void ieee802_11_parse_elems(u8 *start, size_t len, elems->challenge = pos; elems->challenge_len = elen; break; - case WLAN_EID_WPA: + case WLAN_EID_VENDOR_SPECIFIC: if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 && pos[2] == 0xf2) { /* Microsoft OUI (00:50:F2) */ + + if (calc_crc) + crc = crc32_be(crc, pos - 2, elen + 2); + if (pos[3] == 1) { /* OUI Type 1 - WPA IE */ elems->wpa = pos; elems->wpa_len = elen; } else if (elen >= 5 && pos[3] == 2) { + /* OUI Type 2 - WMM IE */ if (pos[4] == 0) { elems->wmm_info = pos; elems->wmm_info_len = elen; @@ -679,32 +673,70 @@ void ieee802_11_parse_elems(u8 *start, size_t len, left -= elen; pos += elen; } + + return crc; } void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata) { struct ieee80211_local *local = sdata->local; struct ieee80211_tx_queue_params qparam; - int i; + int queue; + bool use_11b; + int aCWmin, aCWmax; if (!local->ops->conf_tx) return; memset(&qparam, 0, sizeof(qparam)); - qparam.aifs = 2; + use_11b = (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) && + !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE); - if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ && - !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)) - qparam.cw_min = 31; - else - qparam.cw_min = 15; + for (queue = 0; queue < local_to_hw(local)->queues; queue++) { + /* Set defaults according to 802.11-2007 Table 7-37 */ + aCWmax = 1023; + if (use_11b) + aCWmin = 31; + else + aCWmin = 15; - qparam.cw_max = 1023; - qparam.txop = 0; + switch (queue) { + case 3: /* AC_BK */ + qparam.cw_max = aCWmax; + qparam.cw_min = aCWmin; + qparam.txop = 0; + qparam.aifs = 7; + break; + default: /* never happens but let's not leave undefined */ + case 2: /* AC_BE */ + qparam.cw_max = aCWmax; + qparam.cw_min = aCWmin; + qparam.txop = 0; + qparam.aifs = 3; + break; + case 1: /* AC_VI */ + qparam.cw_max = aCWmin; + qparam.cw_min = (aCWmin + 1) / 2 - 1; + if (use_11b) + qparam.txop = 6016/32; + else + qparam.txop = 3008/32; + qparam.aifs = 2; + break; + case 0: /* AC_VO */ + qparam.cw_max = (aCWmin + 1) / 2 - 1; + qparam.cw_min = (aCWmin + 1) / 4 - 1; + if (use_11b) + qparam.txop = 3264/32; + else + qparam.txop = 1504/32; + qparam.aifs = 2; + break; + } - for (i = 0; i < local_to_hw(local)->queues; i++) - local->ops->conf_tx(local_to_hw(local), i, &qparam); + drv_conf_tx(local, queue, &qparam); + } } void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, @@ -742,31 +774,6 @@ void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, dev_queue_xmit(skb); } -int ieee80211_set_freq(struct ieee80211_sub_if_data *sdata, int freqMHz) -{ - int ret = -EINVAL; - struct ieee80211_channel *chan; - struct ieee80211_local *local = sdata->local; - - chan = ieee80211_get_channel(local->hw.wiphy, freqMHz); - - if (chan && !(chan->flags & IEEE80211_CHAN_DISABLED)) { - if (sdata->vif.type == NL80211_IFTYPE_ADHOC && - chan->flags & IEEE80211_CHAN_NO_IBSS) - return ret; - local->oper_channel = chan; - local->oper_channel_type = NL80211_CHAN_NO_HT; - - if (local->sw_scanning || local->hw_scanning) - ret = 0; - else - ret = ieee80211_hw_config( - local, IEEE80211_CONF_CHANGE_CHANNEL); - } - - return ret; -} - u32 ieee80211_mandatory_rates(struct ieee80211_local *local, enum ieee80211_band band) { @@ -831,16 +838,73 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, ieee80211_tx_skb(sdata, skb, encrypt); } +int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, + const u8 *ie, size_t ie_len) +{ + struct ieee80211_supported_band *sband; + u8 *pos, *supp_rates_len, *esupp_rates_len = NULL; + int i; + + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + + pos = buffer; + + *pos++ = WLAN_EID_SUPP_RATES; + supp_rates_len = pos; + *pos++ = 0; + + for (i = 0; i < sband->n_bitrates; i++) { + struct ieee80211_rate *rate = &sband->bitrates[i]; + + if (esupp_rates_len) { + *esupp_rates_len += 1; + } else if (*supp_rates_len == 8) { + *pos++ = WLAN_EID_EXT_SUPP_RATES; + esupp_rates_len = pos; + *pos++ = 1; + } else + *supp_rates_len += 1; + + *pos++ = rate->bitrate / 5; + } + + if (sband->ht_cap.ht_supported) { + __le16 tmp = cpu_to_le16(sband->ht_cap.cap); + + *pos++ = WLAN_EID_HT_CAPABILITY; + *pos++ = sizeof(struct ieee80211_ht_cap); + memset(pos, 0, sizeof(struct ieee80211_ht_cap)); + memcpy(pos, &tmp, sizeof(u16)); + pos += sizeof(u16); + /* TODO: needs a define here for << 2 */ + *pos++ = sband->ht_cap.ampdu_factor | + (sband->ht_cap.ampdu_density << 2); + memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); + pos += sizeof(sband->ht_cap.mcs); + pos += 2 + 4 + 1; /* ext info, BF cap, antsel */ + } + + /* + * If adding more here, adjust code in main.c + * that calculates local->scan_ies_len. + */ + + if (ie) { + memcpy(pos, ie, ie_len); + pos += ie_len; + } + + return pos - buffer; +} + void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, - u8 *ssid, size_t ssid_len, - u8 *ie, size_t ie_len) + const u8 *ssid, size_t ssid_len, + const u8 *ie, size_t ie_len) { struct ieee80211_local *local = sdata->local; - struct ieee80211_supported_band *sband; struct sk_buff *skb; struct ieee80211_mgmt *mgmt; - u8 *pos, *supp_rates, *esupp_rates = NULL; - int i; + u8 *pos; skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200 + ie_len); @@ -867,31 +931,9 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, *pos++ = WLAN_EID_SSID; *pos++ = ssid_len; memcpy(pos, ssid, ssid_len); + pos += ssid_len; - supp_rates = skb_put(skb, 2); - supp_rates[0] = WLAN_EID_SUPP_RATES; - supp_rates[1] = 0; - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; - - for (i = 0; i < sband->n_bitrates; i++) { - struct ieee80211_rate *rate = &sband->bitrates[i]; - if (esupp_rates) { - pos = skb_put(skb, 1); - esupp_rates[1]++; - } else if (supp_rates[1] == 8) { - esupp_rates = skb_put(skb, 3); - esupp_rates[0] = WLAN_EID_EXT_SUPP_RATES; - esupp_rates[1] = 1; - pos = &esupp_rates[2]; - } else { - pos = skb_put(skb, 1); - supp_rates[1]++; - } - *pos = rate->bitrate / 5; - } - - if (ie) - memcpy(skb_put(skb, ie_len), ie, ie_len); + skb_put(skb, ieee80211_build_preq_ies(local, pos, ie, ie_len)); ieee80211_tx_skb(sdata, skb, 0); } @@ -931,3 +973,151 @@ u32 ieee80211_sta_get_rates(struct ieee80211_local *local, } return supp_rates; } + +int ieee80211_reconfig(struct ieee80211_local *local) +{ + struct ieee80211_hw *hw = &local->hw; + struct ieee80211_sub_if_data *sdata; + struct ieee80211_if_init_conf conf; + struct sta_info *sta; + unsigned long flags; + int res; + bool from_suspend = local->suspended; + + /* + * We're going to start the hardware, at that point + * we are no longer suspended and can RX frames. + */ + local->suspended = false; + + /* restart hardware */ + if (local->open_count) { + res = drv_start(local); + + ieee80211_led_radio(local, true); + } + + /* add interfaces */ + list_for_each_entry(sdata, &local->interfaces, list) { + if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && + sdata->vif.type != NL80211_IFTYPE_MONITOR && + netif_running(sdata->dev)) { + conf.vif = &sdata->vif; + conf.type = sdata->vif.type; + conf.mac_addr = sdata->dev->dev_addr; + res = drv_add_interface(local, &conf); + } + } + + /* add STAs back */ + if (local->ops->sta_notify) { + spin_lock_irqsave(&local->sta_lock, flags); + list_for_each_entry(sta, &local->sta_list, list) { + sdata = sta->sdata; + if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) + sdata = container_of(sdata->bss, + struct ieee80211_sub_if_data, + u.ap); + + drv_sta_notify(local, &sdata->vif, STA_NOTIFY_ADD, + &sta->sta); + } + spin_unlock_irqrestore(&local->sta_lock, flags); + } + + /* Clear Suspend state so that ADDBA requests can be processed */ + + rcu_read_lock(); + + if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { + list_for_each_entry_rcu(sta, &local->sta_list, list) { + clear_sta_flags(sta, WLAN_STA_SUSPEND); + } + } + + rcu_read_unlock(); + + /* setup RTS threshold */ + drv_set_rts_threshold(local, hw->wiphy->rts_threshold); + + /* reconfigure hardware */ + ieee80211_hw_config(local, ~0); + + netif_addr_lock_bh(local->mdev); + ieee80211_configure_filter(local); + netif_addr_unlock_bh(local->mdev); + + /* Finally also reconfigure all the BSS information */ + list_for_each_entry(sdata, &local->interfaces, list) { + u32 changed = ~0; + if (!netif_running(sdata->dev)) + continue; + switch (sdata->vif.type) { + case NL80211_IFTYPE_STATION: + /* disable beacon change bits */ + changed &= ~(BSS_CHANGED_BEACON | + BSS_CHANGED_BEACON_ENABLED); + /* fall through */ + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_MESH_POINT: + ieee80211_bss_info_change_notify(sdata, changed); + break; + case NL80211_IFTYPE_WDS: + break; + case NL80211_IFTYPE_AP_VLAN: + case NL80211_IFTYPE_MONITOR: + /* ignore virtual */ + break; + case NL80211_IFTYPE_UNSPECIFIED: + case __NL80211_IFTYPE_AFTER_LAST: + WARN_ON(1); + break; + } + } + + /* add back keys */ + list_for_each_entry(sdata, &local->interfaces, list) + if (netif_running(sdata->dev)) + ieee80211_enable_keys(sdata); + + ieee80211_wake_queues_by_reason(hw, + IEEE80211_QUEUE_STOP_REASON_SUSPEND); + + /* + * If this is for hw restart things are still running. + * We may want to change that later, however. + */ + if (!from_suspend) + return 0; + +#ifdef CONFIG_PM + local->suspended = false; + + list_for_each_entry(sdata, &local->interfaces, list) { + switch(sdata->vif.type) { + case NL80211_IFTYPE_STATION: + ieee80211_sta_restart(sdata); + break; + case NL80211_IFTYPE_ADHOC: + ieee80211_ibss_restart(sdata); + break; + case NL80211_IFTYPE_MESH_POINT: + ieee80211_mesh_restart(sdata); + break; + default: + break; + } + } + + add_timer(&local->sta_cleanup); + + spin_lock_irqsave(&local->sta_lock, flags); + list_for_each_entry(sta, &local->sta_list, list) + mesh_plink_restart(sta); + spin_unlock_irqrestore(&local->sta_lock, flags); +#else + WARN_ON(1); +#endif + return 0; +} diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index 959aa8379ccf..1da81f456744 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c @@ -27,100 +27,6 @@ #include "aes_ccm.h" -static int ieee80211_set_encryption(struct ieee80211_sub_if_data *sdata, u8 *sta_addr, - int idx, int alg, int remove, - int set_tx_key, const u8 *_key, - size_t key_len) -{ - struct ieee80211_local *local = sdata->local; - struct sta_info *sta; - struct ieee80211_key *key; - int err; - - if (alg == ALG_AES_CMAC) { - if (idx < NUM_DEFAULT_KEYS || - idx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS) { - printk(KERN_DEBUG "%s: set_encrypt - invalid idx=%d " - "(BIP)\n", sdata->dev->name, idx); - return -EINVAL; - } - } else if (idx < 0 || idx >= NUM_DEFAULT_KEYS) { - printk(KERN_DEBUG "%s: set_encrypt - invalid idx=%d\n", - sdata->dev->name, idx); - return -EINVAL; - } - - if (remove) { - rcu_read_lock(); - - err = 0; - - if (is_broadcast_ether_addr(sta_addr)) { - key = sdata->keys[idx]; - } else { - sta = sta_info_get(local, sta_addr); - if (!sta) { - err = -ENOENT; - goto out_unlock; - } - key = sta->key; - } - - ieee80211_key_free(key); - } else { - key = ieee80211_key_alloc(alg, idx, key_len, _key); - if (!key) - return -ENOMEM; - - sta = NULL; - err = 0; - - rcu_read_lock(); - - if (!is_broadcast_ether_addr(sta_addr)) { - set_tx_key = 0; - /* - * According to the standard, the key index of a - * pairwise key must be zero. However, some AP are - * broken when it comes to WEP key indices, so we - * work around this. - */ - if (idx != 0 && alg != ALG_WEP) { - ieee80211_key_free(key); - err = -EINVAL; - goto out_unlock; - } - - sta = sta_info_get(local, sta_addr); - if (!sta) { - ieee80211_key_free(key); - err = -ENOENT; - goto out_unlock; - } - } - - if (alg == ALG_WEP && - key_len != LEN_WEP40 && key_len != LEN_WEP104) { - ieee80211_key_free(key); - err = -EINVAL; - goto out_unlock; - } - - ieee80211_key_link(key, sdata, sta); - - if (set_tx_key || (!sta && !sdata->default_key && key)) - ieee80211_set_default_key(sdata, idx); - if (alg == ALG_AES_CMAC && - (set_tx_key || (!sta && !sdata->default_mgmt_key && key))) - ieee80211_set_default_mgmt_key(sdata, idx); - } - - out_unlock: - rcu_read_unlock(); - - return err; -} - static int ieee80211_ioctl_siwgenie(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *extra) @@ -131,11 +37,13 @@ static int ieee80211_ioctl_siwgenie(struct net_device *dev, if (sdata->vif.type == NL80211_IFTYPE_STATION) { int ret = ieee80211_sta_set_extra_ie(sdata, extra, data->length); - if (ret) + if (ret && ret != -EALREADY) return ret; sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL; sdata->u.mgd.flags &= ~IEEE80211_STA_EXT_SME; - ieee80211_sta_req_auth(sdata); + sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT; + if (ret != -EALREADY) + ieee80211_sta_req_auth(sdata); return 0; } @@ -147,34 +55,54 @@ static int ieee80211_ioctl_siwfreq(struct net_device *dev, struct iw_freq *freq, char *extra) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = sdata->local; + struct ieee80211_channel *chan; if (sdata->vif.type == NL80211_IFTYPE_ADHOC) - sdata->u.ibss.flags &= ~IEEE80211_IBSS_AUTO_CHANNEL_SEL; + return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra); else if (sdata->vif.type == NL80211_IFTYPE_STATION) sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_CHANNEL_SEL; /* freq->e == 0: freq->m = channel; otherwise freq = m * 10^e */ if (freq->e == 0) { if (freq->m < 0) { - if (sdata->vif.type == NL80211_IFTYPE_ADHOC) - sdata->u.ibss.flags |= - IEEE80211_IBSS_AUTO_CHANNEL_SEL; - else if (sdata->vif.type == NL80211_IFTYPE_STATION) + if (sdata->vif.type == NL80211_IFTYPE_STATION) sdata->u.mgd.flags |= IEEE80211_STA_AUTO_CHANNEL_SEL; return 0; } else - return ieee80211_set_freq(sdata, + chan = ieee80211_get_channel(local->hw.wiphy, ieee80211_channel_to_frequency(freq->m)); } else { int i, div = 1000000; for (i = 0; i < freq->e; i++) div /= 10; - if (div > 0) - return ieee80211_set_freq(sdata, freq->m / div); - else + if (div <= 0) return -EINVAL; + chan = ieee80211_get_channel(local->hw.wiphy, freq->m / div); } + + if (!chan) + return -EINVAL; + + if (chan->flags & IEEE80211_CHAN_DISABLED) + return -EINVAL; + + /* + * no change except maybe auto -> fixed, ignore the HT + * setting so you can fix a channel you're on already + */ + if (local->oper_channel == chan) + return 0; + + if (sdata->vif.type == NL80211_IFTYPE_STATION) + ieee80211_sta_req_auth(sdata); + + local->oper_channel = chan; + local->oper_channel_type = NL80211_CHAN_NO_HT; + ieee80211_hw_config(local, 0); + + return 0; } @@ -183,8 +111,12 @@ static int ieee80211_ioctl_giwfreq(struct net_device *dev, struct iw_freq *freq, char *extra) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - freq->m = local->hw.conf.channel->center_freq; + if (sdata->vif.type == NL80211_IFTYPE_ADHOC) + return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra); + + freq->m = local->oper_channel->center_freq; freq->e = 6; return 0; @@ -195,15 +127,17 @@ static int ieee80211_ioctl_siwessid(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *ssid) { - struct ieee80211_sub_if_data *sdata; + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); size_t len = data->length; int ret; + if (sdata->vif.type == NL80211_IFTYPE_ADHOC) + return cfg80211_ibss_wext_siwessid(dev, info, data, ssid); + /* iwconfig uses nul termination in SSID.. */ if (len > 0 && ssid[len - 1] == '\0') len--; - sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (sdata->vif.type == NL80211_IFTYPE_STATION) { if (data->flags) sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_SSID_SEL; @@ -215,10 +149,10 @@ static int ieee80211_ioctl_siwessid(struct net_device *dev, return ret; sdata->u.mgd.flags &= ~IEEE80211_STA_EXT_SME; + sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT; ieee80211_sta_req_auth(sdata); return 0; - } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) - return ieee80211_ibss_set_ssid(sdata, ssid, len); + } return -EOPNOTSUPP; } @@ -229,9 +163,13 @@ static int ieee80211_ioctl_giwessid(struct net_device *dev, struct iw_point *data, char *ssid) { size_t len; - struct ieee80211_sub_if_data *sdata; + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + if (sdata->vif.type == NL80211_IFTYPE_ADHOC) + return cfg80211_ibss_wext_giwessid(dev, info, data, ssid); + if (sdata->vif.type == NL80211_IFTYPE_STATION) { int res = ieee80211_sta_get_ssid(sdata, ssid, &len); if (res == 0) { @@ -240,14 +178,6 @@ static int ieee80211_ioctl_giwessid(struct net_device *dev, } else data->flags = 0; return res; - } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { - int res = ieee80211_ibss_get_ssid(sdata, ssid, &len); - if (res == 0) { - data->length = len; - data->flags = 1; - } else - data->flags = 0; - return res; } return -EOPNOTSUPP; @@ -258,9 +188,11 @@ static int ieee80211_ioctl_siwap(struct net_device *dev, struct iw_request_info *info, struct sockaddr *ap_addr, char *extra) { - struct ieee80211_sub_if_data *sdata; + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + if (sdata->vif.type == NL80211_IFTYPE_ADHOC) + return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra); - sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (sdata->vif.type == NL80211_IFTYPE_STATION) { int ret; @@ -275,18 +207,9 @@ static int ieee80211_ioctl_siwap(struct net_device *dev, if (ret) return ret; sdata->u.mgd.flags &= ~IEEE80211_STA_EXT_SME; + sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT; ieee80211_sta_req_auth(sdata); return 0; - } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { - if (is_zero_ether_addr((u8 *) &ap_addr->sa_data)) - sdata->u.ibss.flags |= IEEE80211_IBSS_AUTO_BSSID_SEL | - IEEE80211_IBSS_AUTO_CHANNEL_SEL; - else if (is_broadcast_ether_addr((u8 *) &ap_addr->sa_data)) - sdata->u.ibss.flags |= IEEE80211_IBSS_AUTO_BSSID_SEL; - else - sdata->u.ibss.flags &= ~IEEE80211_IBSS_AUTO_BSSID_SEL; - - return ieee80211_ibss_set_bssid(sdata, (u8 *) &ap_addr->sa_data); } else if (sdata->vif.type == NL80211_IFTYPE_WDS) { /* * If it is necessary to update the WDS peer address @@ -312,9 +235,11 @@ static int ieee80211_ioctl_giwap(struct net_device *dev, struct iw_request_info *info, struct sockaddr *ap_addr, char *extra) { - struct ieee80211_sub_if_data *sdata; + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + if (sdata->vif.type == NL80211_IFTYPE_ADHOC) + return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra); - sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (sdata->vif.type == NL80211_IFTYPE_STATION) { if (sdata->u.mgd.state == IEEE80211_STA_MLME_ASSOCIATED) { ap_addr->sa_family = ARPHRD_ETHER; @@ -322,13 +247,6 @@ static int ieee80211_ioctl_giwap(struct net_device *dev, } else memset(&ap_addr->sa_data, 0, ETH_ALEN); return 0; - } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { - if (sdata->u.ibss.state == IEEE80211_IBSS_MLME_JOINED) { - ap_addr->sa_family = ARPHRD_ETHER; - memcpy(&ap_addr->sa_data, sdata->u.ibss.bssid, ETH_ALEN); - } else - memset(&ap_addr->sa_data, 0, ETH_ALEN); - return 0; } else if (sdata->vif.type == NL80211_IFTYPE_WDS) { ap_addr->sa_family = ARPHRD_ETHER; memcpy(&ap_addr->sa_data, sdata->u.wds.remote_addr, ETH_ALEN); @@ -411,334 +329,6 @@ static int ieee80211_ioctl_giwrate(struct net_device *dev, return 0; } -static int ieee80211_ioctl_siwtxpower(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *data, char *extra) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_channel* chan = local->hw.conf.channel; - bool reconf = false; - u32 reconf_flags = 0; - int new_power_level; - - if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) - return -EINVAL; - if (data->txpower.flags & IW_TXPOW_RANGE) - return -EINVAL; - if (!chan) - return -EINVAL; - - /* only change when not disabling */ - if (!data->txpower.disabled) { - if (data->txpower.fixed) { - if (data->txpower.value < 0) - return -EINVAL; - new_power_level = data->txpower.value; - /* - * Debatable, but we cannot do a fixed power - * level above the regulatory constraint. - * Use "iwconfig wlan0 txpower 15dBm" instead. - */ - if (new_power_level > chan->max_power) - return -EINVAL; - } else { - /* - * Automatic power level setting, max being the value - * passed in from userland. - */ - if (data->txpower.value < 0) - new_power_level = -1; - else - new_power_level = data->txpower.value; - } - - reconf = true; - - /* - * ieee80211_hw_config() will limit to the channel's - * max power and possibly power constraint from AP. - */ - local->user_power_level = new_power_level; - } - - if (local->hw.conf.radio_enabled != !(data->txpower.disabled)) { - local->hw.conf.radio_enabled = !(data->txpower.disabled); - reconf_flags |= IEEE80211_CONF_CHANGE_RADIO_ENABLED; - ieee80211_led_radio(local, local->hw.conf.radio_enabled); - } - - if (reconf || reconf_flags) - ieee80211_hw_config(local, reconf_flags); - - return 0; -} - -static int ieee80211_ioctl_giwtxpower(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *data, char *extra) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - - data->txpower.fixed = 1; - data->txpower.disabled = !(local->hw.conf.radio_enabled); - data->txpower.value = local->hw.conf.power_level; - data->txpower.flags = IW_TXPOW_DBM; - - return 0; -} - -static int ieee80211_ioctl_siwrts(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *rts, char *extra) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - - if (rts->disabled) - local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; - else if (!rts->fixed) - /* if the rts value is not fixed, then take default */ - local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; - else if (rts->value < 0 || rts->value > IEEE80211_MAX_RTS_THRESHOLD) - return -EINVAL; - else - local->rts_threshold = rts->value; - - /* If the wlan card performs RTS/CTS in hardware/firmware, - * configure it here */ - - if (local->ops->set_rts_threshold) - local->ops->set_rts_threshold(local_to_hw(local), - local->rts_threshold); - - return 0; -} - -static int ieee80211_ioctl_giwrts(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *rts, char *extra) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - - rts->value = local->rts_threshold; - rts->disabled = (rts->value >= IEEE80211_MAX_RTS_THRESHOLD); - rts->fixed = 1; - - return 0; -} - - -static int ieee80211_ioctl_siwfrag(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *frag, char *extra) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - - if (frag->disabled) - local->fragmentation_threshold = IEEE80211_MAX_FRAG_THRESHOLD; - else if (!frag->fixed) - local->fragmentation_threshold = IEEE80211_MAX_FRAG_THRESHOLD; - else if (frag->value < 256 || - frag->value > IEEE80211_MAX_FRAG_THRESHOLD) - return -EINVAL; - else { - /* Fragment length must be even, so strip LSB. */ - local->fragmentation_threshold = frag->value & ~0x1; - } - - return 0; -} - -static int ieee80211_ioctl_giwfrag(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *frag, char *extra) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - - frag->value = local->fragmentation_threshold; - frag->disabled = (frag->value >= IEEE80211_MAX_FRAG_THRESHOLD); - frag->fixed = 1; - - return 0; -} - - -static int ieee80211_ioctl_siwretry(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *retry, char *extra) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - - if (retry->disabled || - (retry->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT) - return -EINVAL; - - if (retry->flags & IW_RETRY_MAX) { - local->hw.conf.long_frame_max_tx_count = retry->value; - } else if (retry->flags & IW_RETRY_MIN) { - local->hw.conf.short_frame_max_tx_count = retry->value; - } else { - local->hw.conf.long_frame_max_tx_count = retry->value; - local->hw.conf.short_frame_max_tx_count = retry->value; - } - - ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_RETRY_LIMITS); - - return 0; -} - - -static int ieee80211_ioctl_giwretry(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *retry, char *extra) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - - retry->disabled = 0; - if (retry->flags == 0 || retry->flags & IW_RETRY_MIN) { - /* first return min value, iwconfig will ask max value - * later if needed */ - retry->flags |= IW_RETRY_LIMIT; - retry->value = local->hw.conf.short_frame_max_tx_count; - if (local->hw.conf.long_frame_max_tx_count != - local->hw.conf.short_frame_max_tx_count) - retry->flags |= IW_RETRY_MIN; - return 0; - } - if (retry->flags & IW_RETRY_MAX) { - retry->flags = IW_RETRY_LIMIT | IW_RETRY_MAX; - retry->value = local->hw.conf.long_frame_max_tx_count; - } - - return 0; -} - -static int ieee80211_ioctl_siwmlme(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *extra) -{ - struct ieee80211_sub_if_data *sdata; - struct iw_mlme *mlme = (struct iw_mlme *) extra; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - if (!(sdata->vif.type == NL80211_IFTYPE_STATION)) - return -EINVAL; - - switch (mlme->cmd) { - case IW_MLME_DEAUTH: - /* TODO: mlme->addr.sa_data */ - return ieee80211_sta_deauthenticate(sdata, mlme->reason_code); - case IW_MLME_DISASSOC: - /* TODO: mlme->addr.sa_data */ - return ieee80211_sta_disassociate(sdata, mlme->reason_code); - default: - return -EOPNOTSUPP; - } -} - - -static int ieee80211_ioctl_siwencode(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *erq, char *keybuf) -{ - struct ieee80211_sub_if_data *sdata; - int idx, i, alg = ALG_WEP; - u8 bcaddr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - int remove = 0, ret; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - idx = erq->flags & IW_ENCODE_INDEX; - if (idx == 0) { - if (sdata->default_key) - for (i = 0; i < NUM_DEFAULT_KEYS; i++) { - if (sdata->default_key == sdata->keys[i]) { - idx = i; - break; - } - } - } else if (idx < 1 || idx > 4) - return -EINVAL; - else - idx--; - - if (erq->flags & IW_ENCODE_DISABLED) - remove = 1; - else if (erq->length == 0) { - /* No key data - just set the default TX key index */ - ieee80211_set_default_key(sdata, idx); - return 0; - } - - ret = ieee80211_set_encryption( - sdata, bcaddr, - idx, alg, remove, - !sdata->default_key, - keybuf, erq->length); - - if (!ret) { - if (remove) - sdata->u.mgd.flags &= ~IEEE80211_STA_TKIP_WEP_USED; - else - sdata->u.mgd.flags |= IEEE80211_STA_TKIP_WEP_USED; - } - - return ret; -} - - -static int ieee80211_ioctl_giwencode(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *erq, char *key) -{ - struct ieee80211_sub_if_data *sdata; - int idx, i; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - idx = erq->flags & IW_ENCODE_INDEX; - if (idx < 1 || idx > 4) { - idx = -1; - if (!sdata->default_key) - idx = 0; - else for (i = 0; i < NUM_DEFAULT_KEYS; i++) { - if (sdata->default_key == sdata->keys[i]) { - idx = i; - break; - } - } - if (idx < 0) - return -EINVAL; - } else - idx--; - - erq->flags = idx + 1; - - if (!sdata->keys[idx]) { - erq->length = 0; - erq->flags |= IW_ENCODE_DISABLED; - return 0; - } - - memcpy(key, sdata->keys[idx]->conf.key, - min_t(int, erq->length, sdata->keys[idx]->conf.keylen)); - erq->length = sdata->keys[idx]->conf.keylen; - erq->flags |= IW_ENCODE_ENABLED; - - if (sdata->vif.type == NL80211_IFTYPE_STATION) { - switch (sdata->u.mgd.auth_alg) { - case WLAN_AUTH_OPEN: - case WLAN_AUTH_LEAP: - erq->flags |= IW_ENCODE_OPEN; - break; - case WLAN_AUTH_SHARED_KEY: - erq->flags |= IW_ENCODE_RESTRICTED; - break; - } - } - - return 0; -} - static int ieee80211_ioctl_siwpower(struct net_device *dev, struct iw_request_info *info, struct iw_param *wrq, @@ -747,7 +337,7 @@ static int ieee80211_ioctl_siwpower(struct net_device *dev, struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_conf *conf = &local->hw.conf; - int ret = 0, timeout = 0; + int timeout = 0; bool ps; if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS)) @@ -779,42 +369,18 @@ static int ieee80211_ioctl_siwpower(struct net_device *dev, timeout = wrq->value / 1000; set: - if (ps == local->powersave && timeout == conf->dynamic_ps_timeout) - return ret; + if (ps == sdata->u.mgd.powersave && timeout == conf->dynamic_ps_timeout) + return 0; - local->powersave = ps; + sdata->u.mgd.powersave = ps; conf->dynamic_ps_timeout = timeout; if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) - ret = ieee80211_hw_config(local, - IEEE80211_CONF_CHANGE_DYNPS_TIMEOUT); + ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); - if (!(sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED)) - return ret; + ieee80211_recalc_ps(local, -1); - if (conf->dynamic_ps_timeout > 0 && - !(local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)) { - mod_timer(&local->dynamic_ps_timer, jiffies + - msecs_to_jiffies(conf->dynamic_ps_timeout)); - } else { - if (local->powersave) { - if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) - ieee80211_send_nullfunc(local, sdata, 1); - conf->flags |= IEEE80211_CONF_PS; - ret = ieee80211_hw_config(local, - IEEE80211_CONF_CHANGE_PS); - } else { - conf->flags &= ~IEEE80211_CONF_PS; - ret = ieee80211_hw_config(local, - IEEE80211_CONF_CHANGE_PS); - if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) - ieee80211_send_nullfunc(local, sdata, 0); - del_timer_sync(&local->dynamic_ps_timer); - cancel_work_sync(&local->dynamic_ps_enable_work); - } - } - - return ret; + return 0; } static int ieee80211_ioctl_giwpower(struct net_device *dev, @@ -822,9 +388,9 @@ static int ieee80211_ioctl_giwpower(struct net_device *dev, union iwreq_data *wrqu, char *extra) { - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - wrqu->power.disabled = !local->powersave; + wrqu->power.disabled = !sdata->u.mgd.powersave; return 0; } @@ -997,82 +563,6 @@ static int ieee80211_ioctl_giwauth(struct net_device *dev, } -static int ieee80211_ioctl_siwencodeext(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *erq, char *extra) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; - int uninitialized_var(alg), idx, i, remove = 0; - - switch (ext->alg) { - case IW_ENCODE_ALG_NONE: - remove = 1; - break; - case IW_ENCODE_ALG_WEP: - alg = ALG_WEP; - break; - case IW_ENCODE_ALG_TKIP: - alg = ALG_TKIP; - break; - case IW_ENCODE_ALG_CCMP: - alg = ALG_CCMP; - break; - case IW_ENCODE_ALG_AES_CMAC: - alg = ALG_AES_CMAC; - break; - default: - return -EOPNOTSUPP; - } - - if (erq->flags & IW_ENCODE_DISABLED) - remove = 1; - - idx = erq->flags & IW_ENCODE_INDEX; - if (alg == ALG_AES_CMAC) { - if (idx < NUM_DEFAULT_KEYS + 1 || - idx > NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS) { - idx = -1; - if (!sdata->default_mgmt_key) - idx = 0; - else for (i = NUM_DEFAULT_KEYS; - i < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS; - i++) { - if (sdata->default_mgmt_key == sdata->keys[i]) - { - idx = i; - break; - } - } - if (idx < 0) - return -EINVAL; - } else - idx--; - } else { - if (idx < 1 || idx > 4) { - idx = -1; - if (!sdata->default_key) - idx = 0; - else for (i = 0; i < NUM_DEFAULT_KEYS; i++) { - if (sdata->default_key == sdata->keys[i]) { - idx = i; - break; - } - } - if (idx < 0) - return -EINVAL; - } else - idx--; - } - - return ieee80211_set_encryption(sdata, ext->addr.sa_data, idx, alg, - remove, - ext->ext_flags & - IW_ENCODE_EXT_SET_TX_KEY, - ext->key, ext->key_len); -} - - /* Structures to export the Wireless Handlers */ static const iw_handler ieee80211_handler[] = @@ -1099,7 +589,7 @@ static const iw_handler ieee80211_handler[] = (iw_handler) NULL, /* SIOCGIWTHRSPY */ (iw_handler) ieee80211_ioctl_siwap, /* SIOCSIWAP */ (iw_handler) ieee80211_ioctl_giwap, /* SIOCGIWAP */ - (iw_handler) ieee80211_ioctl_siwmlme, /* SIOCSIWMLME */ + (iw_handler) cfg80211_wext_siwmlme, /* SIOCSIWMLME */ (iw_handler) NULL, /* SIOCGIWAPLIST */ (iw_handler) cfg80211_wext_siwscan, /* SIOCSIWSCAN */ (iw_handler) cfg80211_wext_giwscan, /* SIOCGIWSCAN */ @@ -1111,16 +601,16 @@ static const iw_handler ieee80211_handler[] = (iw_handler) NULL, /* -- hole -- */ (iw_handler) ieee80211_ioctl_siwrate, /* SIOCSIWRATE */ (iw_handler) ieee80211_ioctl_giwrate, /* SIOCGIWRATE */ - (iw_handler) ieee80211_ioctl_siwrts, /* SIOCSIWRTS */ - (iw_handler) ieee80211_ioctl_giwrts, /* SIOCGIWRTS */ - (iw_handler) ieee80211_ioctl_siwfrag, /* SIOCSIWFRAG */ - (iw_handler) ieee80211_ioctl_giwfrag, /* SIOCGIWFRAG */ - (iw_handler) ieee80211_ioctl_siwtxpower, /* SIOCSIWTXPOW */ - (iw_handler) ieee80211_ioctl_giwtxpower, /* SIOCGIWTXPOW */ - (iw_handler) ieee80211_ioctl_siwretry, /* SIOCSIWRETRY */ - (iw_handler) ieee80211_ioctl_giwretry, /* SIOCGIWRETRY */ - (iw_handler) ieee80211_ioctl_siwencode, /* SIOCSIWENCODE */ - (iw_handler) ieee80211_ioctl_giwencode, /* SIOCGIWENCODE */ + (iw_handler) cfg80211_wext_siwrts, /* SIOCSIWRTS */ + (iw_handler) cfg80211_wext_giwrts, /* SIOCGIWRTS */ + (iw_handler) cfg80211_wext_siwfrag, /* SIOCSIWFRAG */ + (iw_handler) cfg80211_wext_giwfrag, /* SIOCGIWFRAG */ + (iw_handler) cfg80211_wext_siwtxpower, /* SIOCSIWTXPOW */ + (iw_handler) cfg80211_wext_giwtxpower, /* SIOCGIWTXPOW */ + (iw_handler) cfg80211_wext_siwretry, /* SIOCSIWRETRY */ + (iw_handler) cfg80211_wext_giwretry, /* SIOCGIWRETRY */ + (iw_handler) cfg80211_wext_siwencode, /* SIOCSIWENCODE */ + (iw_handler) cfg80211_wext_giwencode, /* SIOCGIWENCODE */ (iw_handler) ieee80211_ioctl_siwpower, /* SIOCSIWPOWER */ (iw_handler) ieee80211_ioctl_giwpower, /* SIOCGIWPOWER */ (iw_handler) NULL, /* -- hole -- */ @@ -1129,7 +619,7 @@ static const iw_handler ieee80211_handler[] = (iw_handler) NULL, /* SIOCGIWGENIE */ (iw_handler) ieee80211_ioctl_siwauth, /* SIOCSIWAUTH */ (iw_handler) ieee80211_ioctl_giwauth, /* SIOCGIWAUTH */ - (iw_handler) ieee80211_ioctl_siwencodeext, /* SIOCSIWENCODEEXT */ + (iw_handler) cfg80211_wext_siwencodeext, /* SIOCSIWENCODEEXT */ (iw_handler) NULL, /* SIOCGIWENCODEEXT */ (iw_handler) NULL, /* SIOCSIWPMKSA */ (iw_handler) NULL, /* -- hole -- */ diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index 0b8ad1f4ecdd..116a923b14d6 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c @@ -23,34 +23,6 @@ */ const int ieee802_1d_to_ac[8] = { 2, 3, 3, 2, 1, 1, 0, 0 }; -static const char llc_ip_hdr[8] = {0xAA, 0xAA, 0x3, 0, 0, 0, 0x08, 0}; - -/* Given a data frame determine the 802.1p/1d tag to use. */ -static unsigned int classify_1d(struct sk_buff *skb) -{ - unsigned int dscp; - - /* skb->priority values from 256->263 are magic values to - * directly indicate a specific 802.1d priority. This is used - * to allow 802.1d priority to be passed directly in from VLAN - * tags, etc. - */ - if (skb->priority >= 256 && skb->priority <= 263) - return skb->priority - 256; - - switch (skb->protocol) { - case htons(ETH_P_IP): - dscp = ip_hdr(skb)->tos & 0xfc; - break; - - default: - return 0; - } - - return dscp >> 5; -} - - static int wme_downgrade_ac(struct sk_buff *skb) { switch (skb->priority) { @@ -94,7 +66,7 @@ static u16 classify80211(struct ieee80211_local *local, struct sk_buff *skb) /* use the data classifier to determine what 802.1d tag the * data frame has */ - skb->priority = classify_1d(skb); + skb->priority = cfg80211_classify8021d(skb); /* in case we are a client verify acm is not set for this ac */ while (unlikely(local->wmm_acm & BIT(skb->priority))) { @@ -129,11 +101,11 @@ u16 ieee80211_select_queue(struct net_device *dev, struct sk_buff *skb) * Now we know the 1d priority, fill in the QoS header if * there is one (and we haven't done this before). */ - if (!skb->requeue && ieee80211_is_data_qos(hdr->frame_control)) { + if (ieee80211_is_data_qos(hdr->frame_control)) { u8 *p = ieee80211_get_qos_ctl(hdr); u8 ack_policy = 0; tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; - if (local->wifi_wme_noack_test) + if (unlikely(local->wifi_wme_noack_test)) ack_policy |= QOS_CONTROL_ACK_POLICY_NOACK << QOS_CONTROL_ACK_POLICY_SHIFT; /* qos header is 2 bytes, second reserved */ diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 4f8bfea278f2..dcfae8884b86 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -122,7 +122,7 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx) return RX_DROP_UNUSABLE; mac80211_ev_michael_mic_failure(rx->sdata, rx->key->conf.keyidx, - (void *) skb->data); + (void *) skb->data, NULL); return RX_DROP_UNUSABLE; } diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index cb3ad741ebf8..634d14affc8d 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -327,7 +327,7 @@ config NETFILTER_XT_TARGET_CONNMARK If you want to compile it as a module, say M here and read . The module will be called - ipt_CONNMARK.ko. If unsure, say `N'. + ipt_CONNMARK. If unsure, say `N'. config NETFILTER_XT_TARGET_CONNSECMARK tristate '"CONNSECMARK" target support' @@ -584,7 +584,7 @@ config NETFILTER_XT_MATCH_CONNMARK If you want to compile it as a module, say M here and read . The module will be called - ipt_connmark.ko. If unsure, say `N'. + ipt_connmark. If unsure, say `N'. config NETFILTER_XT_MATCH_CONNTRACK tristate '"conntrack" connection tracking match support' @@ -917,6 +917,19 @@ config NETFILTER_XT_MATCH_U32 Details and examples are in the kernel module source. +config NETFILTER_XT_MATCH_OSF + tristate '"osf" Passive OS fingerprint match' + depends on NETFILTER_ADVANCED && NETFILTER_NETLINK + help + This option selects the Passive OS Fingerprinting match module + that allows to passively match the remote operating system by + analyzing incoming TCP SYN packets. + + Rules and loading software can be downloaded from + http://www.ioremap.net/projects/osf + + To compile it as a module, choose M here. If unsure, say N. + endif # NETFILTER_XTABLES endmenu diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index 6282060fbda9..49f62ee4e9ff 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile @@ -77,6 +77,7 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_LIMIT) += xt_limit.o obj-$(CONFIG_NETFILTER_XT_MATCH_MAC) += xt_mac.o obj-$(CONFIG_NETFILTER_XT_MATCH_MARK) += xt_mark.o obj-$(CONFIG_NETFILTER_XT_MATCH_MULTIPORT) += xt_multiport.o +obj-$(CONFIG_NETFILTER_XT_MATCH_OSF) += xt_osf.o obj-$(CONFIG_NETFILTER_XT_MATCH_OWNER) += xt_owner.o obj-$(CONFIG_NETFILTER_XT_MATCH_PHYSDEV) += xt_physdev.o obj-$(CONFIG_NETFILTER_XT_MATCH_PKTTYPE) += xt_pkttype.o diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index e01061f49cdc..7c1333c67ff3 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c @@ -3345,22 +3345,8 @@ static struct genl_ops ip_vs_genl_ops[] __read_mostly = { static int __init ip_vs_genl_register(void) { - int ret, i; - - ret = genl_register_family(&ip_vs_genl_family); - if (ret) - return ret; - - for (i = 0; i < ARRAY_SIZE(ip_vs_genl_ops); i++) { - ret = genl_register_ops(&ip_vs_genl_family, &ip_vs_genl_ops[i]); - if (ret) - goto err_out; - } - return 0; - -err_out: - genl_unregister_family(&ip_vs_genl_family); - return ret; + return genl_register_family_with_ops(&ip_vs_genl_family, + ip_vs_genl_ops, ARRAY_SIZE(ip_vs_genl_ops)); } static void ip_vs_genl_unregister(void) diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c index 425ab144f15d..5874657af7f2 100644 --- a/net/netfilter/ipvs/ip_vs_xmit.c +++ b/net/netfilter/ipvs/ip_vs_xmit.c @@ -260,8 +260,8 @@ ip_vs_bypass_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, ip_send_check(ip_hdr(skb)); /* drop old route */ - dst_release(skb->dst); - skb->dst = &rt->u.dst; + skb_dst_drop(skb); + skb_dst_set(skb, &rt->u.dst); /* Another hack: avoid icmp_send in ip_fragment */ skb->local_df = 1; @@ -324,8 +324,8 @@ ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, } /* drop old route */ - dst_release(skb->dst); - skb->dst = &rt->u.dst; + skb_dst_drop(skb); + skb_dst_set(skb, &rt->u.dst); /* Another hack: avoid icmp_send in ip_fragment */ skb->local_df = 1; @@ -388,8 +388,8 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, goto tx_error_put; /* drop old route */ - dst_release(skb->dst); - skb->dst = &rt->u.dst; + skb_dst_drop(skb); + skb_dst_set(skb, &rt->u.dst); /* mangle the packet */ if (pp->dnat_handler && !pp->dnat_handler(skb, pp, cp)) @@ -465,8 +465,8 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, goto tx_error_put; /* drop old route */ - dst_release(skb->dst); - skb->dst = &rt->u.dst; + skb_dst_drop(skb); + skb_dst_set(skb, &rt->u.dst); /* mangle the packet */ if (pp->dnat_handler && !pp->dnat_handler(skb, pp, cp)) @@ -553,8 +553,8 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, IP_VS_DBG_RL("ip_vs_tunnel_xmit(): mtu less than 68\n"); goto tx_error; } - if (skb->dst) - skb->dst->ops->update_pmtu(skb->dst, mtu); + if (skb_dst(skb)) + skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu); df |= (old_iph->frag_off & htons(IP_DF)); @@ -596,8 +596,8 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); /* drop old route */ - dst_release(skb->dst); - skb->dst = &rt->u.dst; + skb_dst_drop(skb); + skb_dst_set(skb, &rt->u.dst); /* * Push down and install the IPIP header. @@ -665,8 +665,8 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, IP_VS_DBG_RL("ip_vs_tunnel_xmit_v6(): mtu less than 1280\n"); goto tx_error; } - if (skb->dst) - skb->dst->ops->update_pmtu(skb->dst, mtu); + if (skb_dst(skb)) + skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu); if (mtu < ntohs(old_iph->payload_len) + sizeof(struct ipv6hdr)) { icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev); @@ -702,8 +702,8 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); /* drop old route */ - dst_release(skb->dst); - skb->dst = &rt->u.dst; + skb_dst_drop(skb); + skb_dst_set(skb, &rt->u.dst); /* * Push down and install the IPIP header. @@ -775,8 +775,8 @@ ip_vs_dr_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, ip_send_check(ip_hdr(skb)); /* drop old route */ - dst_release(skb->dst); - skb->dst = &rt->u.dst; + skb_dst_drop(skb); + skb_dst_set(skb, &rt->u.dst); /* Another hack: avoid icmp_send in ip_fragment */ skb->local_df = 1; @@ -828,8 +828,8 @@ ip_vs_dr_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, } /* drop old route */ - dst_release(skb->dst); - skb->dst = &rt->u.dst; + skb_dst_drop(skb); + skb_dst_set(skb, &rt->u.dst); /* Another hack: avoid icmp_send in ip_fragment */ skb->local_df = 1; @@ -900,8 +900,8 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, goto tx_error_put; /* drop the old route when skb is not shared */ - dst_release(skb->dst); - skb->dst = &rt->u.dst; + skb_dst_drop(skb); + skb_dst_set(skb, &rt->u.dst); ip_vs_nat_icmp(skb, pp, cp, 0); @@ -975,8 +975,8 @@ ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, goto tx_error_put; /* drop the old route when skb is not shared */ - dst_release(skb->dst); - skb->dst = &rt->u.dst; + skb_dst_drop(skb); + skb_dst_set(skb, &rt->u.dst); ip_vs_nat_icmp_v6(skb, pp, cp, 0); diff --git a/net/netfilter/nf_conntrack_acct.c b/net/netfilter/nf_conntrack_acct.c index 9fe8982bd7c9..4a1d94aac20b 100644 --- a/net/netfilter/nf_conntrack_acct.c +++ b/net/netfilter/nf_conntrack_acct.c @@ -116,7 +116,7 @@ int nf_conntrack_acct_init(struct net *net) if (net_eq(net, &init_net)) { #ifdef CONFIG_NF_CT_ACCT printk(KERN_WARNING "CONFIG_NF_CT_ACCT is deprecated and will be removed soon. Please use\n"); - printk(KERN_WARNING "nf_conntrack.acct=1 kernel paramater, acct=1 nf_conntrack module option or\n"); + printk(KERN_WARNING "nf_conntrack.acct=1 kernel parameter, acct=1 nf_conntrack module option or\n"); printk(KERN_WARNING "sysctl net.netfilter.nf_conntrack_acct=1 to enable it.\n"); #endif diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 8020db6274b8..7508f11c5b39 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -182,10 +183,6 @@ destroy_conntrack(struct nf_conntrack *nfct) NF_CT_ASSERT(atomic_read(&nfct->use) == 0); NF_CT_ASSERT(!timer_pending(&ct->timeout)); - if (!test_bit(IPS_DYING_BIT, &ct->status)) - nf_conntrack_event(IPCT_DESTROY, ct); - set_bit(IPS_DYING_BIT, &ct->status); - /* To make sure we don't get any weird locking issues here: * destroy_conntrack() MUST NOT be called with a write lock * to nf_conntrack_lock!!! -HW */ @@ -219,27 +216,70 @@ destroy_conntrack(struct nf_conntrack *nfct) nf_conntrack_free(ct); } -static void death_by_timeout(unsigned long ul_conntrack) +void nf_ct_delete_from_lists(struct nf_conn *ct) { - struct nf_conn *ct = (void *)ul_conntrack; struct net *net = nf_ct_net(ct); - struct nf_conn_help *help = nfct_help(ct); - struct nf_conntrack_helper *helper; - - if (help) { - rcu_read_lock(); - helper = rcu_dereference(help->helper); - if (helper && helper->destroy) - helper->destroy(ct); - rcu_read_unlock(); - } + nf_ct_helper_destroy(ct); spin_lock_bh(&nf_conntrack_lock); /* Inside lock so preempt is disabled on module removal path. * Otherwise we can get spurious warnings. */ NF_CT_STAT_INC(net, delete_list); clean_from_lists(ct); spin_unlock_bh(&nf_conntrack_lock); +} +EXPORT_SYMBOL_GPL(nf_ct_delete_from_lists); + +static void death_by_event(unsigned long ul_conntrack) +{ + struct nf_conn *ct = (void *)ul_conntrack; + struct net *net = nf_ct_net(ct); + + if (nf_conntrack_event(IPCT_DESTROY, ct) < 0) { + /* bad luck, let's retry again */ + ct->timeout.expires = jiffies + + (random32() % net->ct.sysctl_events_retry_timeout); + add_timer(&ct->timeout); + return; + } + /* we've got the event delivered, now it's dying */ + set_bit(IPS_DYING_BIT, &ct->status); + spin_lock(&nf_conntrack_lock); + hlist_nulls_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode); + spin_unlock(&nf_conntrack_lock); + nf_ct_put(ct); +} + +void nf_ct_insert_dying_list(struct nf_conn *ct) +{ + struct net *net = nf_ct_net(ct); + + /* add this conntrack to the dying list */ + spin_lock_bh(&nf_conntrack_lock); + hlist_nulls_add_head(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode, + &net->ct.dying); + spin_unlock_bh(&nf_conntrack_lock); + /* set a new timer to retry event delivery */ + setup_timer(&ct->timeout, death_by_event, (unsigned long)ct); + ct->timeout.expires = jiffies + + (random32() % net->ct.sysctl_events_retry_timeout); + add_timer(&ct->timeout); +} +EXPORT_SYMBOL_GPL(nf_ct_insert_dying_list); + +static void death_by_timeout(unsigned long ul_conntrack) +{ + struct nf_conn *ct = (void *)ul_conntrack; + + if (!test_bit(IPS_DYING_BIT, &ct->status) && + unlikely(nf_conntrack_event(IPCT_DESTROY, ct) < 0)) { + /* destroy event was not delivered */ + nf_ct_delete_from_lists(ct); + nf_ct_insert_dying_list(ct); + return; + } + set_bit(IPS_DYING_BIT, &ct->status); + nf_ct_delete_from_lists(ct); nf_ct_put(ct); } @@ -295,7 +335,8 @@ begin: h = __nf_conntrack_find(net, tuple); if (h) { ct = nf_ct_tuplehash_to_ctrack(h); - if (unlikely(!atomic_inc_not_zero(&ct->ct_general.use))) + if (unlikely(nf_ct_is_dying(ct) || + !atomic_inc_not_zero(&ct->ct_general.use))) h = NULL; else { if (unlikely(!nf_ct_tuple_equal(tuple, &h->tuple))) { @@ -385,7 +426,6 @@ __nf_conntrack_confirm(struct sk_buff *skb) /* Remove from unconfirmed list */ hlist_nulls_del_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode); - __nf_conntrack_hash_insert(ct, hash, repl_hash); /* Timer relative to confirmation time, not original setting time, otherwise we'd get timer wrap in weird delay cases. */ @@ -393,16 +433,20 @@ __nf_conntrack_confirm(struct sk_buff *skb) add_timer(&ct->timeout); atomic_inc(&ct->ct_general.use); set_bit(IPS_CONFIRMED_BIT, &ct->status); + + /* Since the lookup is lockless, hash insertion must be done after + * starting the timer and setting the CONFIRMED bit. The RCU barriers + * guarantee that no other CPU can find the conntrack before the above + * stores are visible. + */ + __nf_conntrack_hash_insert(ct, hash, repl_hash); NF_CT_STAT_INC(net, insert); spin_unlock_bh(&nf_conntrack_lock); + help = nfct_help(ct); if (help && help->helper) nf_conntrack_event_cache(IPCT_HELPER, ct); -#ifdef CONFIG_NF_NAT_NEEDED - if (test_bit(IPS_SRC_NAT_DONE_BIT, &ct->status) || - test_bit(IPS_DST_NAT_DONE_BIT, &ct->status)) - nf_conntrack_event_cache(IPCT_NATINFO, ct); -#endif + nf_conntrack_event_cache(master_ct(ct) ? IPCT_RELATED : IPCT_NEW, ct); return NF_ACCEPT; @@ -467,7 +511,8 @@ static noinline int early_drop(struct net *net, unsigned int hash) cnt++; } - if (ct && unlikely(!atomic_inc_not_zero(&ct->ct_general.use))) + if (ct && unlikely(nf_ct_is_dying(ct) || + !atomic_inc_not_zero(&ct->ct_general.use))) ct = NULL; if (ct || cnt >= NF_CT_EVICTION_RANGE) break; @@ -523,6 +568,7 @@ struct nf_conn *nf_conntrack_alloc(struct net *net, return ERR_PTR(-ENOMEM); } + spin_lock_init(&ct->lock); atomic_set(&ct->ct_general.use, 1); ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple = *orig; ct->tuplehash[IP_CT_DIR_REPLY].tuple = *repl; @@ -580,6 +626,7 @@ init_conntrack(struct net *net, } nf_ct_acct_ext_add(ct, GFP_ATOMIC); + nf_ct_ecache_ext_add(ct, GFP_ATOMIC); spin_lock_bh(&nf_conntrack_lock); exp = nf_ct_find_expectation(net, tuple); @@ -807,13 +854,9 @@ void __nf_ct_refresh_acct(struct nf_conn *ct, unsigned long extra_jiffies, int do_acct) { - int event = 0; - NF_CT_ASSERT(ct->timeout.data == (unsigned long)ct); NF_CT_ASSERT(skb); - spin_lock_bh(&nf_conntrack_lock); - /* Only update if this is not a fixed timeout */ if (test_bit(IPS_FIXED_TIMEOUT_BIT, &ct->status)) goto acct; @@ -821,19 +864,14 @@ void __nf_ct_refresh_acct(struct nf_conn *ct, /* If not in hash table, timer will not be active yet */ if (!nf_ct_is_confirmed(ct)) { ct->timeout.expires = extra_jiffies; - event = IPCT_REFRESH; } else { unsigned long newtime = jiffies + extra_jiffies; /* Only update the timeout if the new timeout is at least HZ jiffies from the old timeout. Need del_timer for race avoidance (may already be dying). */ - if (newtime - ct->timeout.expires >= HZ - && del_timer(&ct->timeout)) { - ct->timeout.expires = newtime; - add_timer(&ct->timeout); - event = IPCT_REFRESH; - } + if (newtime - ct->timeout.expires >= HZ) + mod_timer_pending(&ct->timeout, newtime); } acct: @@ -842,17 +880,13 @@ acct: acct = nf_conn_acct_find(ct); if (acct) { + spin_lock_bh(&ct->lock); acct[CTINFO2DIR(ctinfo)].packets++; acct[CTINFO2DIR(ctinfo)].bytes += skb->len - skb_network_offset(skb); + spin_unlock_bh(&ct->lock); } } - - spin_unlock_bh(&nf_conntrack_lock); - - /* must be unlocked when calling event cache */ - if (event) - nf_conntrack_event_cache(event, ct); } EXPORT_SYMBOL_GPL(__nf_ct_refresh_acct); @@ -864,14 +898,14 @@ bool __nf_ct_kill_acct(struct nf_conn *ct, if (do_acct) { struct nf_conn_counter *acct; - spin_lock_bh(&nf_conntrack_lock); acct = nf_conn_acct_find(ct); if (acct) { + spin_lock_bh(&ct->lock); acct[CTINFO2DIR(ctinfo)].packets++; acct[CTINFO2DIR(ctinfo)].bytes += skb->len - skb_network_offset(skb); + spin_unlock_bh(&ct->lock); } - spin_unlock_bh(&nf_conntrack_lock); } if (del_timer(&ct->timeout)) { @@ -1001,15 +1035,22 @@ struct __nf_ct_flush_report { int report; }; -static int kill_all(struct nf_conn *i, void *data) +static int kill_report(struct nf_conn *i, void *data) { struct __nf_ct_flush_report *fr = (struct __nf_ct_flush_report *)data; - /* get_next_corpse sets the dying bit for us */ - nf_conntrack_event_report(IPCT_DESTROY, - i, - fr->pid, - fr->report); + /* If we fail to deliver the event, death_by_timeout() will retry */ + if (nf_conntrack_event_report(IPCT_DESTROY, i, + fr->pid, fr->report) < 0) + return 1; + + /* Avoid the delivery of the destroy event in death_by_timeout(). */ + set_bit(IPS_DYING_BIT, &i->status); + return 1; +} + +static int kill_all(struct nf_conn *i, void *data) +{ return 1; } @@ -1023,15 +1064,30 @@ void nf_ct_free_hashtable(void *hash, int vmalloced, unsigned int size) } EXPORT_SYMBOL_GPL(nf_ct_free_hashtable); -void nf_conntrack_flush(struct net *net, u32 pid, int report) +void nf_conntrack_flush_report(struct net *net, u32 pid, int report) { struct __nf_ct_flush_report fr = { .pid = pid, .report = report, }; - nf_ct_iterate_cleanup(net, kill_all, &fr); + nf_ct_iterate_cleanup(net, kill_report, &fr); +} +EXPORT_SYMBOL_GPL(nf_conntrack_flush_report); + +static void nf_ct_release_dying_list(void) +{ + struct nf_conntrack_tuple_hash *h; + struct nf_conn *ct; + struct hlist_nulls_node *n; + + spin_lock_bh(&nf_conntrack_lock); + hlist_nulls_for_each_entry(h, n, &init_net.ct.dying, hnnode) { + ct = nf_ct_tuplehash_to_ctrack(h); + /* never fails to remove them, no listeners at this point */ + nf_ct_kill(ct); + } + spin_unlock_bh(&nf_conntrack_lock); } -EXPORT_SYMBOL_GPL(nf_conntrack_flush); static void nf_conntrack_cleanup_init_net(void) { @@ -1042,10 +1098,9 @@ static void nf_conntrack_cleanup_init_net(void) static void nf_conntrack_cleanup_net(struct net *net) { - nf_ct_event_cache_flush(net); - nf_conntrack_ecache_fini(net); i_see_dead_people: - nf_conntrack_flush(net, 0, 0); + nf_ct_iterate_cleanup(net, kill_all, NULL); + nf_ct_release_dying_list(); if (atomic_read(&net->ct.count) != 0) { schedule(); goto i_see_dead_people; @@ -1056,6 +1111,7 @@ static void nf_conntrack_cleanup_net(struct net *net) nf_ct_free_hashtable(net->ct.hash, net->ct.hash_vmalloc, nf_conntrack_htable_size); + nf_conntrack_ecache_fini(net); nf_conntrack_acct_fini(net); nf_conntrack_expect_fini(net); free_percpu(net->ct.stat); @@ -1220,20 +1276,24 @@ err_cache: return ret; } +/* + * We need to use special "null" values, not used in hash table + */ +#define UNCONFIRMED_NULLS_VAL ((1<<30)+0) +#define DYING_NULLS_VAL ((1<<30)+1) + static int nf_conntrack_init_net(struct net *net) { int ret; atomic_set(&net->ct.count, 0); - INIT_HLIST_NULLS_HEAD(&net->ct.unconfirmed, 0); + INIT_HLIST_NULLS_HEAD(&net->ct.unconfirmed, UNCONFIRMED_NULLS_VAL); + INIT_HLIST_NULLS_HEAD(&net->ct.dying, DYING_NULLS_VAL); net->ct.stat = alloc_percpu(struct ip_conntrack_stat); if (!net->ct.stat) { ret = -ENOMEM; goto err_stat; } - ret = nf_conntrack_ecache_init(net); - if (ret < 0) - goto err_ecache; net->ct.hash = nf_ct_alloc_hashtable(&nf_conntrack_htable_size, &net->ct.hash_vmalloc, 1); if (!net->ct.hash) { @@ -1247,6 +1307,9 @@ static int nf_conntrack_init_net(struct net *net) ret = nf_conntrack_acct_init(net); if (ret < 0) goto err_acct; + ret = nf_conntrack_ecache_init(net); + if (ret < 0) + goto err_ecache; /* Set up fake conntrack: - to never be deleted, not in any hashes */ @@ -1259,14 +1322,14 @@ static int nf_conntrack_init_net(struct net *net) return 0; +err_ecache: + nf_conntrack_acct_fini(net); err_acct: nf_conntrack_expect_fini(net); err_expect: nf_ct_free_hashtable(net->ct.hash, net->ct.hash_vmalloc, nf_conntrack_htable_size); err_hash: - nf_conntrack_ecache_fini(net); -err_ecache: free_percpu(net->ct.stat); err_stat: return ret; diff --git a/net/netfilter/nf_conntrack_ecache.c b/net/netfilter/nf_conntrack_ecache.c index dee4190209cc..aee560b4768d 100644 --- a/net/netfilter/nf_conntrack_ecache.c +++ b/net/netfilter/nf_conntrack_ecache.c @@ -16,121 +16,245 @@ #include #include #include -#include #include #include #include #include +#include -ATOMIC_NOTIFIER_HEAD(nf_conntrack_chain); -EXPORT_SYMBOL_GPL(nf_conntrack_chain); +static DEFINE_MUTEX(nf_ct_ecache_mutex); -ATOMIC_NOTIFIER_HEAD(nf_ct_expect_chain); -EXPORT_SYMBOL_GPL(nf_ct_expect_chain); +struct nf_ct_event_notifier *nf_conntrack_event_cb __read_mostly; +EXPORT_SYMBOL_GPL(nf_conntrack_event_cb); + +struct nf_exp_event_notifier *nf_expect_event_cb __read_mostly; +EXPORT_SYMBOL_GPL(nf_expect_event_cb); /* deliver cached events and clear cache entry - must be called with locally * disabled softirqs */ -static inline void -__nf_ct_deliver_cached_events(struct nf_conntrack_ecache *ecache) +void nf_ct_deliver_cached_events(struct nf_conn *ct) { - if (nf_ct_is_confirmed(ecache->ct) && !nf_ct_is_dying(ecache->ct) - && ecache->events) { + unsigned long events; + struct nf_ct_event_notifier *notify; + struct nf_conntrack_ecache *e; + + rcu_read_lock(); + notify = rcu_dereference(nf_conntrack_event_cb); + if (notify == NULL) + goto out_unlock; + + e = nf_ct_ecache_find(ct); + if (e == NULL) + goto out_unlock; + + events = xchg(&e->cache, 0); + + if (nf_ct_is_confirmed(ct) && !nf_ct_is_dying(ct) && events) { struct nf_ct_event item = { - .ct = ecache->ct, + .ct = ct, .pid = 0, .report = 0 }; + int ret; + /* We make a copy of the missed event cache without taking + * the lock, thus we may send missed events twice. However, + * this does not harm and it happens very rarely. */ + unsigned long missed = e->missed; - atomic_notifier_call_chain(&nf_conntrack_chain, - ecache->events, - &item); + ret = notify->fcn(events | missed, &item); + if (unlikely(ret < 0 || missed)) { + spin_lock_bh(&ct->lock); + if (ret < 0) + e->missed |= events; + else + e->missed &= ~missed; + spin_unlock_bh(&ct->lock); + } } - ecache->events = 0; - nf_ct_put(ecache->ct); - ecache->ct = NULL; -} - -/* Deliver all cached events for a particular conntrack. This is called - * by code prior to async packet handling for freeing the skb */ -void nf_ct_deliver_cached_events(const struct nf_conn *ct) -{ - struct net *net = nf_ct_net(ct); - struct nf_conntrack_ecache *ecache; - - local_bh_disable(); - ecache = per_cpu_ptr(net->ct.ecache, raw_smp_processor_id()); - if (ecache->ct == ct) - __nf_ct_deliver_cached_events(ecache); - local_bh_enable(); +out_unlock: + rcu_read_unlock(); } EXPORT_SYMBOL_GPL(nf_ct_deliver_cached_events); -/* Deliver cached events for old pending events, if current conntrack != old */ -void __nf_ct_event_cache_init(struct nf_conn *ct) +int nf_conntrack_register_notifier(struct nf_ct_event_notifier *new) { - struct net *net = nf_ct_net(ct); - struct nf_conntrack_ecache *ecache; + int ret = 0; + struct nf_ct_event_notifier *notify; - /* take care of delivering potentially old events */ - ecache = per_cpu_ptr(net->ct.ecache, raw_smp_processor_id()); - BUG_ON(ecache->ct == ct); - if (ecache->ct) - __nf_ct_deliver_cached_events(ecache); - /* initialize for this conntrack/packet */ - ecache->ct = ct; - nf_conntrack_get(&ct->ct_general); -} -EXPORT_SYMBOL_GPL(__nf_ct_event_cache_init); - -/* flush the event cache - touches other CPU's data and must not be called - * while packets are still passing through the code */ -void nf_ct_event_cache_flush(struct net *net) -{ - struct nf_conntrack_ecache *ecache; - int cpu; - - for_each_possible_cpu(cpu) { - ecache = per_cpu_ptr(net->ct.ecache, cpu); - if (ecache->ct) - nf_ct_put(ecache->ct); + mutex_lock(&nf_ct_ecache_mutex); + notify = rcu_dereference(nf_conntrack_event_cb); + if (notify != NULL) { + ret = -EBUSY; + goto out_unlock; } + rcu_assign_pointer(nf_conntrack_event_cb, new); + mutex_unlock(&nf_ct_ecache_mutex); + return ret; + +out_unlock: + mutex_unlock(&nf_ct_ecache_mutex); + return ret; } +EXPORT_SYMBOL_GPL(nf_conntrack_register_notifier); + +void nf_conntrack_unregister_notifier(struct nf_ct_event_notifier *new) +{ + struct nf_ct_event_notifier *notify; + + mutex_lock(&nf_ct_ecache_mutex); + notify = rcu_dereference(nf_conntrack_event_cb); + BUG_ON(notify != new); + rcu_assign_pointer(nf_conntrack_event_cb, NULL); + mutex_unlock(&nf_ct_ecache_mutex); +} +EXPORT_SYMBOL_GPL(nf_conntrack_unregister_notifier); + +int nf_ct_expect_register_notifier(struct nf_exp_event_notifier *new) +{ + int ret = 0; + struct nf_exp_event_notifier *notify; + + mutex_lock(&nf_ct_ecache_mutex); + notify = rcu_dereference(nf_expect_event_cb); + if (notify != NULL) { + ret = -EBUSY; + goto out_unlock; + } + rcu_assign_pointer(nf_expect_event_cb, new); + mutex_unlock(&nf_ct_ecache_mutex); + return ret; + +out_unlock: + mutex_unlock(&nf_ct_ecache_mutex); + return ret; +} +EXPORT_SYMBOL_GPL(nf_ct_expect_register_notifier); + +void nf_ct_expect_unregister_notifier(struct nf_exp_event_notifier *new) +{ + struct nf_exp_event_notifier *notify; + + mutex_lock(&nf_ct_ecache_mutex); + notify = rcu_dereference(nf_expect_event_cb); + BUG_ON(notify != new); + rcu_assign_pointer(nf_expect_event_cb, NULL); + mutex_unlock(&nf_ct_ecache_mutex); +} +EXPORT_SYMBOL_GPL(nf_ct_expect_unregister_notifier); + +#define NF_CT_EVENTS_DEFAULT 1 +static int nf_ct_events __read_mostly = NF_CT_EVENTS_DEFAULT; +static int nf_ct_events_retry_timeout __read_mostly = 15*HZ; + +#ifdef CONFIG_SYSCTL +static struct ctl_table event_sysctl_table[] = { + { + .ctl_name = CTL_UNNUMBERED, + .procname = "nf_conntrack_events", + .data = &init_net.ct.sysctl_events, + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "nf_conntrack_events_retry_timeout", + .data = &init_net.ct.sysctl_events_retry_timeout, + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = proc_dointvec_jiffies, + }, + {} +}; +#endif /* CONFIG_SYSCTL */ + +static struct nf_ct_ext_type event_extend __read_mostly = { + .len = sizeof(struct nf_conntrack_ecache), + .align = __alignof__(struct nf_conntrack_ecache), + .id = NF_CT_EXT_ECACHE, +}; + +#ifdef CONFIG_SYSCTL +static int nf_conntrack_event_init_sysctl(struct net *net) +{ + struct ctl_table *table; + + table = kmemdup(event_sysctl_table, sizeof(event_sysctl_table), + GFP_KERNEL); + if (!table) + goto out; + + table[0].data = &net->ct.sysctl_events; + table[1].data = &net->ct.sysctl_events_retry_timeout; + + net->ct.event_sysctl_header = + register_net_sysctl_table(net, + nf_net_netfilter_sysctl_path, table); + if (!net->ct.event_sysctl_header) { + printk(KERN_ERR "nf_ct_event: can't register to sysctl.\n"); + goto out_register; + } + return 0; + +out_register: + kfree(table); +out: + return -ENOMEM; +} + +static void nf_conntrack_event_fini_sysctl(struct net *net) +{ + struct ctl_table *table; + + table = net->ct.event_sysctl_header->ctl_table_arg; + unregister_net_sysctl_table(net->ct.event_sysctl_header); + kfree(table); +} +#else +static int nf_conntrack_event_init_sysctl(struct net *net) +{ + return 0; +} + +static void nf_conntrack_event_fini_sysctl(struct net *net) +{ +} +#endif /* CONFIG_SYSCTL */ int nf_conntrack_ecache_init(struct net *net) { - net->ct.ecache = alloc_percpu(struct nf_conntrack_ecache); - if (!net->ct.ecache) - return -ENOMEM; + int ret; + + net->ct.sysctl_events = nf_ct_events; + net->ct.sysctl_events_retry_timeout = nf_ct_events_retry_timeout; + + if (net_eq(net, &init_net)) { + ret = nf_ct_extend_register(&event_extend); + if (ret < 0) { + printk(KERN_ERR "nf_ct_event: Unable to register " + "event extension.\n"); + goto out_extend_register; + } + } + + ret = nf_conntrack_event_init_sysctl(net); + if (ret < 0) + goto out_sysctl; + return 0; + +out_sysctl: + if (net_eq(net, &init_net)) + nf_ct_extend_unregister(&event_extend); +out_extend_register: + return ret; } void nf_conntrack_ecache_fini(struct net *net) { - free_percpu(net->ct.ecache); + nf_conntrack_event_fini_sysctl(net); + if (net_eq(net, &init_net)) + nf_ct_extend_unregister(&event_extend); } - -int nf_conntrack_register_notifier(struct notifier_block *nb) -{ - return atomic_notifier_chain_register(&nf_conntrack_chain, nb); -} -EXPORT_SYMBOL_GPL(nf_conntrack_register_notifier); - -int nf_conntrack_unregister_notifier(struct notifier_block *nb) -{ - return atomic_notifier_chain_unregister(&nf_conntrack_chain, nb); -} -EXPORT_SYMBOL_GPL(nf_conntrack_unregister_notifier); - -int nf_ct_expect_register_notifier(struct notifier_block *nb) -{ - return atomic_notifier_chain_register(&nf_ct_expect_chain, nb); -} -EXPORT_SYMBOL_GPL(nf_ct_expect_register_notifier); - -int nf_ct_expect_unregister_notifier(struct notifier_block *nb) -{ - return atomic_notifier_chain_unregister(&nf_ct_expect_chain, nb); -} -EXPORT_SYMBOL_GPL(nf_ct_expect_unregister_notifier); diff --git a/net/netfilter/nf_conntrack_ftp.c b/net/netfilter/nf_conntrack_ftp.c index 00fecc385f9b..5509dd1f14cf 100644 --- a/net/netfilter/nf_conntrack_ftp.c +++ b/net/netfilter/nf_conntrack_ftp.c @@ -338,11 +338,9 @@ static void update_nl_seq(struct nf_conn *ct, u32 nl_seq, if (info->seq_aft_nl_num[dir] < NUM_SEQ_TO_REMEMBER) { info->seq_aft_nl[dir][info->seq_aft_nl_num[dir]++] = nl_seq; - nf_conntrack_event_cache(IPCT_HELPINFO_VOLATILE, ct); } else if (oldest != NUM_SEQ_TO_REMEMBER && after(nl_seq, info->seq_aft_nl[dir][oldest])) { info->seq_aft_nl[dir][oldest] = nl_seq; - nf_conntrack_event_cache(IPCT_HELPINFO_VOLATILE, ct); } } diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c index 0fa5a422959f..65c2a7bc3afc 100644 --- a/net/netfilter/nf_conntrack_helper.c +++ b/net/netfilter/nf_conntrack_helper.c @@ -136,6 +136,20 @@ static inline int unhelp(struct nf_conntrack_tuple_hash *i, return 0; } +void nf_ct_helper_destroy(struct nf_conn *ct) +{ + struct nf_conn_help *help = nfct_help(ct); + struct nf_conntrack_helper *helper; + + if (help) { + rcu_read_lock(); + helper = rcu_dereference(help->helper); + if (helper && helper->destroy) + helper->destroy(ct); + rcu_read_unlock(); + } +} + int nf_conntrack_helper_register(struct nf_conntrack_helper *me) { unsigned int h = helper_hash(&me->tuple); diff --git a/net/netfilter/nf_conntrack_netbios_ns.c b/net/netfilter/nf_conntrack_netbios_ns.c index 8a3875e36ec2..497b2224536f 100644 --- a/net/netfilter/nf_conntrack_netbios_ns.c +++ b/net/netfilter/nf_conntrack_netbios_ns.c @@ -48,7 +48,7 @@ static int help(struct sk_buff *skb, unsigned int protoff, { struct nf_conntrack_expect *exp; struct iphdr *iph = ip_hdr(skb); - struct rtable *rt = skb->rtable; + struct rtable *rt = skb_rtable(skb); struct in_device *in_dev; __be32 mask = 0; diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index c523f0b8cee5..49479d194570 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include @@ -144,7 +143,7 @@ nla_put_failure: } static inline int -ctnetlink_dump_protoinfo(struct sk_buff *skb, const struct nf_conn *ct) +ctnetlink_dump_protoinfo(struct sk_buff *skb, struct nf_conn *ct) { struct nf_conntrack_l4proto *l4proto; struct nlattr *nest_proto; @@ -346,23 +345,21 @@ nla_put_failure: return -1; } -#define tuple(ct, dir) (&(ct)->tuplehash[dir].tuple) - static int ctnetlink_fill_info(struct sk_buff *skb, u32 pid, u32 seq, - int event, int nowait, - const struct nf_conn *ct) + int event, struct nf_conn *ct) { struct nlmsghdr *nlh; struct nfgenmsg *nfmsg; struct nlattr *nest_parms; - unsigned char *b = skb_tail_pointer(skb); + unsigned int flags = pid ? NLM_F_MULTI : 0; event |= NFNL_SUBSYS_CTNETLINK << 8; - nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(struct nfgenmsg)); - nfmsg = NLMSG_DATA(nlh); + nlh = nlmsg_put(skb, pid, seq, event, sizeof(*nfmsg), flags); + if (nlh == NULL) + goto nlmsg_failure; - nlh->nlmsg_flags = (nowait && pid) ? NLM_F_MULTI : 0; + nfmsg = nlmsg_data(nlh); nfmsg->nfgen_family = nf_ct_l3num(ct); nfmsg->version = NFNETLINK_V0; nfmsg->res_id = 0; @@ -370,14 +367,14 @@ ctnetlink_fill_info(struct sk_buff *skb, u32 pid, u32 seq, nest_parms = nla_nest_start(skb, CTA_TUPLE_ORIG | NLA_F_NESTED); if (!nest_parms) goto nla_put_failure; - if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_ORIGINAL)) < 0) + if (ctnetlink_dump_tuples(skb, nf_ct_tuple(ct, IP_CT_DIR_ORIGINAL)) < 0) goto nla_put_failure; nla_nest_end(skb, nest_parms); nest_parms = nla_nest_start(skb, CTA_TUPLE_REPLY | NLA_F_NESTED); if (!nest_parms) goto nla_put_failure; - if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_REPLY)) < 0) + if (ctnetlink_dump_tuples(skb, nf_ct_tuple(ct, IP_CT_DIR_REPLY)) < 0) goto nla_put_failure; nla_nest_end(skb, nest_parms); @@ -395,132 +392,109 @@ ctnetlink_fill_info(struct sk_buff *skb, u32 pid, u32 seq, ctnetlink_dump_nat_seq_adj(skb, ct) < 0) goto nla_put_failure; - nlh->nlmsg_len = skb_tail_pointer(skb) - b; + nlmsg_end(skb, nlh); return skb->len; nlmsg_failure: nla_put_failure: - nlmsg_trim(skb, b); + nlmsg_cancel(skb, nlh); return -1; } #ifdef CONFIG_NF_CONNTRACK_EVENTS -/* - * The general structure of a ctnetlink event is - * - * CTA_TUPLE_ORIG - * - * CTA_TUPLE_REPLY - * - * CTA_ID - * ... - * CTA_PROTOINFO - * - * CTA_TUPLE_MASTER - * - * - * Therefore the formular is - * - * size = sizeof(headers) + sizeof(generic_nlas) + 3 * sizeof(tuple_nlas) - * + sizeof(protoinfo_nlas) - */ -static struct sk_buff * -ctnetlink_alloc_skb(const struct nf_conntrack_tuple *tuple, gfp_t gfp) +static inline size_t +ctnetlink_proto_size(const struct nf_conn *ct) { struct nf_conntrack_l3proto *l3proto; struct nf_conntrack_l4proto *l4proto; - int len; - -#define NLA_TYPE_SIZE(type) nla_total_size(sizeof(type)) - - /* proto independant part */ - len = NLMSG_SPACE(sizeof(struct nfgenmsg)) - + 3 * nla_total_size(0) /* CTA_TUPLE_ORIG|REPL|MASTER */ - + 3 * nla_total_size(0) /* CTA_TUPLE_IP */ - + 3 * nla_total_size(0) /* CTA_TUPLE_PROTO */ - + 3 * NLA_TYPE_SIZE(u_int8_t) /* CTA_PROTO_NUM */ - + NLA_TYPE_SIZE(u_int32_t) /* CTA_ID */ - + NLA_TYPE_SIZE(u_int32_t) /* CTA_STATUS */ -#ifdef CONFIG_NF_CT_ACCT - + 2 * nla_total_size(0) /* CTA_COUNTERS_ORIG|REPL */ - + 2 * NLA_TYPE_SIZE(uint64_t) /* CTA_COUNTERS_PACKETS */ - + 2 * NLA_TYPE_SIZE(uint64_t) /* CTA_COUNTERS_BYTES */ -#endif - + NLA_TYPE_SIZE(u_int32_t) /* CTA_TIMEOUT */ - + nla_total_size(0) /* CTA_PROTOINFO */ - + nla_total_size(0) /* CTA_HELP */ - + nla_total_size(NF_CT_HELPER_NAME_LEN) /* CTA_HELP_NAME */ -#ifdef CONFIG_NF_CONNTRACK_SECMARK - + NLA_TYPE_SIZE(u_int32_t) /* CTA_SECMARK */ -#endif -#ifdef CONFIG_NF_NAT_NEEDED - + 2 * nla_total_size(0) /* CTA_NAT_SEQ_ADJ_ORIG|REPL */ - + 2 * NLA_TYPE_SIZE(u_int32_t) /* CTA_NAT_SEQ_CORRECTION_POS */ - + 2 * NLA_TYPE_SIZE(u_int32_t) /* CTA_NAT_SEQ_CORRECTION_BEFORE */ - + 2 * NLA_TYPE_SIZE(u_int32_t) /* CTA_NAT_SEQ_CORRECTION_AFTER */ -#endif -#ifdef CONFIG_NF_CONNTRACK_MARK - + NLA_TYPE_SIZE(u_int32_t) /* CTA_MARK */ -#endif - ; - -#undef NLA_TYPE_SIZE + size_t len = 0; rcu_read_lock(); - l3proto = __nf_ct_l3proto_find(tuple->src.l3num); + l3proto = __nf_ct_l3proto_find(nf_ct_l3num(ct)); len += l3proto->nla_size; - l4proto = __nf_ct_l4proto_find(tuple->src.l3num, tuple->dst.protonum); + l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct)); len += l4proto->nla_size; rcu_read_unlock(); - return alloc_skb(len, gfp); + return len; } -static int ctnetlink_conntrack_event(struct notifier_block *this, - unsigned long events, void *ptr) +static inline size_t +ctnetlink_nlmsg_size(const struct nf_conn *ct) +{ + return NLMSG_ALIGN(sizeof(struct nfgenmsg)) + + 3 * nla_total_size(0) /* CTA_TUPLE_ORIG|REPL|MASTER */ + + 3 * nla_total_size(0) /* CTA_TUPLE_IP */ + + 3 * nla_total_size(0) /* CTA_TUPLE_PROTO */ + + 3 * nla_total_size(sizeof(u_int8_t)) /* CTA_PROTO_NUM */ + + nla_total_size(sizeof(u_int32_t)) /* CTA_ID */ + + nla_total_size(sizeof(u_int32_t)) /* CTA_STATUS */ +#ifdef CONFIG_NF_CT_ACCT + + 2 * nla_total_size(0) /* CTA_COUNTERS_ORIG|REPL */ + + 2 * nla_total_size(sizeof(uint64_t)) /* CTA_COUNTERS_PACKETS */ + + 2 * nla_total_size(sizeof(uint64_t)) /* CTA_COUNTERS_BYTES */ +#endif + + nla_total_size(sizeof(u_int32_t)) /* CTA_TIMEOUT */ + + nla_total_size(0) /* CTA_PROTOINFO */ + + nla_total_size(0) /* CTA_HELP */ + + nla_total_size(NF_CT_HELPER_NAME_LEN) /* CTA_HELP_NAME */ +#ifdef CONFIG_NF_CONNTRACK_SECMARK + + nla_total_size(sizeof(u_int32_t)) /* CTA_SECMARK */ +#endif +#ifdef CONFIG_NF_NAT_NEEDED + + 2 * nla_total_size(0) /* CTA_NAT_SEQ_ADJ_ORIG|REPL */ + + 6 * nla_total_size(sizeof(u_int32_t)) /* CTA_NAT_SEQ_OFFSET */ +#endif +#ifdef CONFIG_NF_CONNTRACK_MARK + + nla_total_size(sizeof(u_int32_t)) /* CTA_MARK */ +#endif + + ctnetlink_proto_size(ct) + ; +} + +static int +ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item) { struct nlmsghdr *nlh; struct nfgenmsg *nfmsg; struct nlattr *nest_parms; - struct nf_ct_event *item = (struct nf_ct_event *)ptr; struct nf_conn *ct = item->ct; struct sk_buff *skb; unsigned int type; - sk_buff_data_t b; unsigned int flags = 0, group; + int err; /* ignore our fake conntrack entry */ if (ct == &nf_conntrack_untracked) - return NOTIFY_DONE; + return 0; - if (events & IPCT_DESTROY) { + if (events & (1 << IPCT_DESTROY)) { type = IPCTNL_MSG_CT_DELETE; group = NFNLGRP_CONNTRACK_DESTROY; - } else if (events & (IPCT_NEW | IPCT_RELATED)) { + } else if (events & ((1 << IPCT_NEW) | (1 << IPCT_RELATED))) { type = IPCTNL_MSG_CT_NEW; flags = NLM_F_CREATE|NLM_F_EXCL; group = NFNLGRP_CONNTRACK_NEW; - } else if (events & (IPCT_STATUS | IPCT_PROTOINFO)) { + } else if (events) { type = IPCTNL_MSG_CT_NEW; group = NFNLGRP_CONNTRACK_UPDATE; } else - return NOTIFY_DONE; + return 0; if (!item->report && !nfnetlink_has_listeners(group)) - return NOTIFY_DONE; + return 0; - skb = ctnetlink_alloc_skb(tuple(ct, IP_CT_DIR_ORIGINAL), GFP_ATOMIC); - if (!skb) + skb = nlmsg_new(ctnetlink_nlmsg_size(ct), GFP_ATOMIC); + if (skb == NULL) goto errout; - b = skb->tail; - type |= NFNL_SUBSYS_CTNETLINK << 8; - nlh = NLMSG_PUT(skb, item->pid, 0, type, sizeof(struct nfgenmsg)); - nfmsg = NLMSG_DATA(nlh); + nlh = nlmsg_put(skb, item->pid, 0, type, sizeof(*nfmsg), flags); + if (nlh == NULL) + goto nlmsg_failure; - nlh->nlmsg_flags = flags; + nfmsg = nlmsg_data(nlh); nfmsg->nfgen_family = nf_ct_l3num(ct); nfmsg->version = NFNETLINK_V0; nfmsg->res_id = 0; @@ -529,14 +503,14 @@ static int ctnetlink_conntrack_event(struct notifier_block *this, nest_parms = nla_nest_start(skb, CTA_TUPLE_ORIG | NLA_F_NESTED); if (!nest_parms) goto nla_put_failure; - if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_ORIGINAL)) < 0) + if (ctnetlink_dump_tuples(skb, nf_ct_tuple(ct, IP_CT_DIR_ORIGINAL)) < 0) goto nla_put_failure; nla_nest_end(skb, nest_parms); nest_parms = nla_nest_start(skb, CTA_TUPLE_REPLY | NLA_F_NESTED); if (!nest_parms) goto nla_put_failure; - if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_REPLY)) < 0) + if (ctnetlink_dump_tuples(skb, nf_ct_tuple(ct, IP_CT_DIR_REPLY)) < 0) goto nla_put_failure; nla_nest_end(skb, nest_parms); @@ -546,7 +520,7 @@ static int ctnetlink_conntrack_event(struct notifier_block *this, if (ctnetlink_dump_status(skb, ct) < 0) goto nla_put_failure; - if (events & IPCT_DESTROY) { + if (events & (1 << IPCT_DESTROY)) { if (ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 || ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0) goto nla_put_failure; @@ -554,47 +528,51 @@ static int ctnetlink_conntrack_event(struct notifier_block *this, if (ctnetlink_dump_timeout(skb, ct) < 0) goto nla_put_failure; - if (events & IPCT_PROTOINFO + if (events & (1 << IPCT_PROTOINFO) && ctnetlink_dump_protoinfo(skb, ct) < 0) goto nla_put_failure; - if ((events & IPCT_HELPER || nfct_help(ct)) + if ((events & (1 << IPCT_HELPER) || nfct_help(ct)) && ctnetlink_dump_helpinfo(skb, ct) < 0) goto nla_put_failure; #ifdef CONFIG_NF_CONNTRACK_SECMARK - if ((events & IPCT_SECMARK || ct->secmark) + if ((events & (1 << IPCT_SECMARK) || ct->secmark) && ctnetlink_dump_secmark(skb, ct) < 0) goto nla_put_failure; #endif - if (events & IPCT_RELATED && + if (events & (1 << IPCT_RELATED) && ctnetlink_dump_master(skb, ct) < 0) goto nla_put_failure; - if (events & IPCT_NATSEQADJ && + if (events & (1 << IPCT_NATSEQADJ) && ctnetlink_dump_nat_seq_adj(skb, ct) < 0) goto nla_put_failure; } #ifdef CONFIG_NF_CONNTRACK_MARK - if ((events & IPCT_MARK || ct->mark) + if ((events & (1 << IPCT_MARK) || ct->mark) && ctnetlink_dump_mark(skb, ct) < 0) goto nla_put_failure; #endif rcu_read_unlock(); - nlh->nlmsg_len = skb->tail - b; - nfnetlink_send(skb, item->pid, group, item->report); - return NOTIFY_DONE; + nlmsg_end(skb, nlh); + err = nfnetlink_send(skb, item->pid, group, item->report, GFP_ATOMIC); + if (err == -ENOBUFS || err == -EAGAIN) + return -ENOBUFS; + + return 0; nla_put_failure: rcu_read_unlock(); + nlmsg_cancel(skb, nlh); nlmsg_failure: kfree_skb(skb); errout: nfnetlink_set_err(0, group, -ENOBUFS); - return NOTIFY_DONE; + return 0; } #endif /* CONFIG_NF_CONNTRACK_EVENTS */ @@ -611,7 +589,7 @@ ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb) struct nf_conn *ct, *last; struct nf_conntrack_tuple_hash *h; struct hlist_nulls_node *n; - struct nfgenmsg *nfmsg = NLMSG_DATA(cb->nlh); + struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh); u_int8_t l3proto = nfmsg->nfgen_family; rcu_read_lock(); @@ -637,8 +615,7 @@ restart: } if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, - IPCTNL_MSG_CT_NEW, - 1, ct) < 0) { + IPCTNL_MSG_CT_NEW, ct) < 0) { cb->args[1] = (unsigned long)ct; goto out; } @@ -792,7 +769,7 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, struct nf_conntrack_tuple_hash *h; struct nf_conntrack_tuple tuple; struct nf_conn *ct; - struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); + struct nfgenmsg *nfmsg = nlmsg_data(nlh); u_int8_t u3 = nfmsg->nfgen_family; int err = 0; @@ -802,9 +779,9 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY, u3); else { /* Flush the whole table */ - nf_conntrack_flush(&init_net, - NETLINK_CB(skb).pid, - nlmsg_report(nlh)); + nf_conntrack_flush_report(&init_net, + NETLINK_CB(skb).pid, + nlmsg_report(nlh)); return 0; } @@ -825,10 +802,15 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, } } - nf_conntrack_event_report(IPCT_DESTROY, - ct, - NETLINK_CB(skb).pid, - nlmsg_report(nlh)); + if (nf_conntrack_event_report(IPCT_DESTROY, ct, + NETLINK_CB(skb).pid, + nlmsg_report(nlh)) < 0) { + nf_ct_delete_from_lists(ct); + /* we failed to report the event, try later */ + nf_ct_insert_dying_list(ct); + nf_ct_put(ct); + return 0; + } /* death_by_timeout would report the event again */ set_bit(IPS_DYING_BIT, &ct->status); @@ -847,7 +829,7 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, struct nf_conntrack_tuple tuple; struct nf_conn *ct; struct sk_buff *skb2 = NULL; - struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); + struct nfgenmsg *nfmsg = nlmsg_data(nlh); u_int8_t u3 = nfmsg->nfgen_family; int err = 0; @@ -872,15 +854,15 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, ct = nf_ct_tuplehash_to_ctrack(h); err = -ENOMEM; - skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); - if (!skb2) { + skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (skb2 == NULL) { nf_ct_put(ct); return -ENOMEM; } rcu_read_lock(); err = ctnetlink_fill_info(skb2, NETLINK_CB(skb).pid, nlh->nlmsg_seq, - IPCTNL_MSG_CT_NEW, 1, ct); + IPCTNL_MSG_CT_NEW, ct); rcu_read_unlock(); nf_ct_put(ct); if (err <= 0) @@ -1280,6 +1262,7 @@ ctnetlink_create_conntrack(struct nlattr *cda[], } nf_ct_acct_ext_add(ct, GFP_ATOMIC); + nf_ct_ecache_ext_add(ct, GFP_ATOMIC); #if defined(CONFIG_NF_CONNTRACK_MARK) if (cda[CTA_MARK]) @@ -1325,7 +1308,7 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, { struct nf_conntrack_tuple otuple, rtuple; struct nf_conntrack_tuple_hash *h = NULL; - struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); + struct nfgenmsg *nfmsg = nlmsg_data(nlh); u_int8_t u3 = nfmsg->nfgen_family; int err = 0; @@ -1367,13 +1350,13 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, else events = IPCT_NEW; - nf_conntrack_event_report(IPCT_STATUS | - IPCT_HELPER | - IPCT_PROTOINFO | - IPCT_NATSEQADJ | - IPCT_MARK | events, - ct, NETLINK_CB(skb).pid, - nlmsg_report(nlh)); + nf_conntrack_eventmask_report((1 << IPCT_STATUS) | + (1 << IPCT_HELPER) | + (1 << IPCT_PROTOINFO) | + (1 << IPCT_NATSEQADJ) | + (1 << IPCT_MARK) | events, + ct, NETLINK_CB(skb).pid, + nlmsg_report(nlh)); nf_ct_put(ct); } else spin_unlock_bh(&nf_conntrack_lock); @@ -1392,13 +1375,13 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, if (err == 0) { nf_conntrack_get(&ct->ct_general); spin_unlock_bh(&nf_conntrack_lock); - nf_conntrack_event_report(IPCT_STATUS | - IPCT_HELPER | - IPCT_PROTOINFO | - IPCT_NATSEQADJ | - IPCT_MARK, - ct, NETLINK_CB(skb).pid, - nlmsg_report(nlh)); + nf_conntrack_eventmask_report((1 << IPCT_STATUS) | + (1 << IPCT_HELPER) | + (1 << IPCT_PROTOINFO) | + (1 << IPCT_NATSEQADJ) | + (1 << IPCT_MARK), + ct, NETLINK_CB(skb).pid, + nlmsg_report(nlh)); nf_ct_put(ct); } else spin_unlock_bh(&nf_conntrack_lock); @@ -1503,19 +1486,18 @@ nla_put_failure: static int ctnetlink_exp_fill_info(struct sk_buff *skb, u32 pid, u32 seq, - int event, - int nowait, - const struct nf_conntrack_expect *exp) + int event, const struct nf_conntrack_expect *exp) { struct nlmsghdr *nlh; struct nfgenmsg *nfmsg; - unsigned char *b = skb_tail_pointer(skb); + unsigned int flags = pid ? NLM_F_MULTI : 0; event |= NFNL_SUBSYS_CTNETLINK_EXP << 8; - nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(struct nfgenmsg)); - nfmsg = NLMSG_DATA(nlh); + nlh = nlmsg_put(skb, pid, seq, event, sizeof(*nfmsg), flags); + if (nlh == NULL) + goto nlmsg_failure; - nlh->nlmsg_flags = (nowait && pid) ? NLM_F_MULTI : 0; + nfmsg = nlmsg_data(nlh); nfmsg->nfgen_family = exp->tuple.src.l3num; nfmsg->version = NFNETLINK_V0; nfmsg->res_id = 0; @@ -1523,49 +1505,46 @@ ctnetlink_exp_fill_info(struct sk_buff *skb, u32 pid, u32 seq, if (ctnetlink_exp_dump_expect(skb, exp) < 0) goto nla_put_failure; - nlh->nlmsg_len = skb_tail_pointer(skb) - b; + nlmsg_end(skb, nlh); return skb->len; nlmsg_failure: nla_put_failure: - nlmsg_trim(skb, b); + nlmsg_cancel(skb, nlh); return -1; } #ifdef CONFIG_NF_CONNTRACK_EVENTS -static int ctnetlink_expect_event(struct notifier_block *this, - unsigned long events, void *ptr) +static int +ctnetlink_expect_event(unsigned int events, struct nf_exp_event *item) { struct nlmsghdr *nlh; struct nfgenmsg *nfmsg; - struct nf_exp_event *item = (struct nf_exp_event *)ptr; struct nf_conntrack_expect *exp = item->exp; struct sk_buff *skb; unsigned int type; - sk_buff_data_t b; int flags = 0; - if (events & IPEXP_NEW) { + if (events & (1 << IPEXP_NEW)) { type = IPCTNL_MSG_EXP_NEW; flags = NLM_F_CREATE|NLM_F_EXCL; } else - return NOTIFY_DONE; + return 0; if (!item->report && !nfnetlink_has_listeners(NFNLGRP_CONNTRACK_EXP_NEW)) - return NOTIFY_DONE; + return 0; - skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC); - if (!skb) + skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); + if (skb == NULL) goto errout; - b = skb->tail; - type |= NFNL_SUBSYS_CTNETLINK_EXP << 8; - nlh = NLMSG_PUT(skb, item->pid, 0, type, sizeof(struct nfgenmsg)); - nfmsg = NLMSG_DATA(nlh); + nlh = nlmsg_put(skb, item->pid, 0, type, sizeof(*nfmsg), flags); + if (nlh == NULL) + goto nlmsg_failure; - nlh->nlmsg_flags = flags; + nfmsg = nlmsg_data(nlh); nfmsg->nfgen_family = exp->tuple.src.l3num; nfmsg->version = NFNETLINK_V0; nfmsg->res_id = 0; @@ -1575,17 +1554,19 @@ static int ctnetlink_expect_event(struct notifier_block *this, goto nla_put_failure; rcu_read_unlock(); - nlh->nlmsg_len = skb->tail - b; - nfnetlink_send(skb, item->pid, NFNLGRP_CONNTRACK_EXP_NEW, item->report); - return NOTIFY_DONE; + nlmsg_end(skb, nlh); + nfnetlink_send(skb, item->pid, NFNLGRP_CONNTRACK_EXP_NEW, + item->report, GFP_ATOMIC); + return 0; nla_put_failure: rcu_read_unlock(); + nlmsg_cancel(skb, nlh); nlmsg_failure: kfree_skb(skb); errout: nfnetlink_set_err(0, 0, -ENOBUFS); - return NOTIFY_DONE; + return 0; } #endif static int ctnetlink_exp_done(struct netlink_callback *cb) @@ -1600,7 +1581,7 @@ ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb) { struct net *net = &init_net; struct nf_conntrack_expect *exp, *last; - struct nfgenmsg *nfmsg = NLMSG_DATA(cb->nlh); + struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh); struct hlist_node *n; u_int8_t l3proto = nfmsg->nfgen_family; @@ -1617,10 +1598,11 @@ restart: continue; cb->args[1] = 0; } - if (ctnetlink_exp_fill_info(skb, NETLINK_CB(cb->skb).pid, + if (ctnetlink_exp_fill_info(skb, + NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, IPCTNL_MSG_EXP_NEW, - 1, exp) < 0) { + exp) < 0) { if (!atomic_inc_not_zero(&exp->use)) continue; cb->args[1] = (unsigned long)exp; @@ -1652,7 +1634,7 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, struct nf_conntrack_tuple tuple; struct nf_conntrack_expect *exp; struct sk_buff *skb2; - struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); + struct nfgenmsg *nfmsg = nlmsg_data(nlh); u_int8_t u3 = nfmsg->nfgen_family; int err = 0; @@ -1683,14 +1665,13 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, } err = -ENOMEM; - skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); - if (!skb2) + skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (skb2 == NULL) goto out; rcu_read_lock(); err = ctnetlink_exp_fill_info(skb2, NETLINK_CB(skb).pid, - nlh->nlmsg_seq, IPCTNL_MSG_EXP_NEW, - 1, exp); + nlh->nlmsg_seq, IPCTNL_MSG_EXP_NEW, exp); rcu_read_unlock(); if (err <= 0) goto free; @@ -1713,7 +1694,7 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, struct nf_conntrack_expect *exp; struct nf_conntrack_tuple tuple; struct nf_conntrack_helper *h; - struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); + struct nfgenmsg *nfmsg = nlmsg_data(nlh); struct hlist_node *n, *next; u_int8_t u3 = nfmsg->nfgen_family; unsigned int i; @@ -1854,7 +1835,7 @@ ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb, { struct nf_conntrack_tuple tuple; struct nf_conntrack_expect *exp; - struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); + struct nfgenmsg *nfmsg = nlmsg_data(nlh); u_int8_t u3 = nfmsg->nfgen_family; int err = 0; @@ -1891,12 +1872,12 @@ ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb, } #ifdef CONFIG_NF_CONNTRACK_EVENTS -static struct notifier_block ctnl_notifier = { - .notifier_call = ctnetlink_conntrack_event, +static struct nf_ct_event_notifier ctnl_notifier = { + .fcn = ctnetlink_conntrack_event, }; -static struct notifier_block ctnl_notifier_exp = { - .notifier_call = ctnetlink_expect_event, +static struct nf_exp_event_notifier ctnl_notifier_exp = { + .fcn = ctnetlink_expect_event, }; #endif diff --git a/net/netfilter/nf_conntrack_proto_dccp.c b/net/netfilter/nf_conntrack_proto_dccp.c index aee0d6bea309..1b816a2ea813 100644 --- a/net/netfilter/nf_conntrack_proto_dccp.c +++ b/net/netfilter/nf_conntrack_proto_dccp.c @@ -25,8 +25,6 @@ #include #include -static DEFINE_RWLOCK(dccp_lock); - /* Timeouts are based on values from RFC4340: * * - REQUEST: @@ -492,7 +490,7 @@ static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb, return NF_ACCEPT; } - write_lock_bh(&dccp_lock); + spin_lock_bh(&ct->lock); role = ct->proto.dccp.role[dir]; old_state = ct->proto.dccp.state; @@ -536,13 +534,13 @@ static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb, ct->proto.dccp.last_dir = dir; ct->proto.dccp.last_pkt = type; - write_unlock_bh(&dccp_lock); + spin_unlock_bh(&ct->lock); if (LOG_INVALID(net, IPPROTO_DCCP)) nf_log_packet(pf, 0, skb, NULL, NULL, NULL, "nf_ct_dccp: invalid packet ignored "); return NF_ACCEPT; case CT_DCCP_INVALID: - write_unlock_bh(&dccp_lock); + spin_unlock_bh(&ct->lock); if (LOG_INVALID(net, IPPROTO_DCCP)) nf_log_packet(pf, 0, skb, NULL, NULL, NULL, "nf_ct_dccp: invalid state transition "); @@ -552,7 +550,7 @@ static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb, ct->proto.dccp.last_dir = dir; ct->proto.dccp.last_pkt = type; ct->proto.dccp.state = new_state; - write_unlock_bh(&dccp_lock); + spin_unlock_bh(&ct->lock); if (new_state != old_state) nf_conntrack_event_cache(IPCT_PROTOINFO, ct); @@ -621,36 +619,39 @@ static int dccp_print_tuple(struct seq_file *s, ntohs(tuple->dst.u.dccp.port)); } -static int dccp_print_conntrack(struct seq_file *s, const struct nf_conn *ct) +static int dccp_print_conntrack(struct seq_file *s, struct nf_conn *ct) { return seq_printf(s, "%s ", dccp_state_names[ct->proto.dccp.state]); } #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) static int dccp_to_nlattr(struct sk_buff *skb, struct nlattr *nla, - const struct nf_conn *ct) + struct nf_conn *ct) { struct nlattr *nest_parms; - read_lock_bh(&dccp_lock); + spin_lock_bh(&ct->lock); nest_parms = nla_nest_start(skb, CTA_PROTOINFO_DCCP | NLA_F_NESTED); if (!nest_parms) goto nla_put_failure; NLA_PUT_U8(skb, CTA_PROTOINFO_DCCP_STATE, ct->proto.dccp.state); NLA_PUT_U8(skb, CTA_PROTOINFO_DCCP_ROLE, ct->proto.dccp.role[IP_CT_DIR_ORIGINAL]); + NLA_PUT_BE64(skb, CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ, + cpu_to_be64(ct->proto.dccp.handshake_seq)); nla_nest_end(skb, nest_parms); - read_unlock_bh(&dccp_lock); + spin_unlock_bh(&ct->lock); return 0; nla_put_failure: - read_unlock_bh(&dccp_lock); + spin_unlock_bh(&ct->lock); return -1; } static const struct nla_policy dccp_nla_policy[CTA_PROTOINFO_DCCP_MAX + 1] = { [CTA_PROTOINFO_DCCP_STATE] = { .type = NLA_U8 }, [CTA_PROTOINFO_DCCP_ROLE] = { .type = NLA_U8 }, + [CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ] = { .type = NLA_U64 }, }; static int nlattr_to_dccp(struct nlattr *cda[], struct nf_conn *ct) @@ -674,7 +675,7 @@ static int nlattr_to_dccp(struct nlattr *cda[], struct nf_conn *ct) return -EINVAL; } - write_lock_bh(&dccp_lock); + spin_lock_bh(&ct->lock); ct->proto.dccp.state = nla_get_u8(tb[CTA_PROTOINFO_DCCP_STATE]); if (nla_get_u8(tb[CTA_PROTOINFO_DCCP_ROLE]) == CT_DCCP_ROLE_CLIENT) { ct->proto.dccp.role[IP_CT_DIR_ORIGINAL] = CT_DCCP_ROLE_CLIENT; @@ -683,7 +684,11 @@ static int nlattr_to_dccp(struct nlattr *cda[], struct nf_conn *ct) ct->proto.dccp.role[IP_CT_DIR_ORIGINAL] = CT_DCCP_ROLE_SERVER; ct->proto.dccp.role[IP_CT_DIR_REPLY] = CT_DCCP_ROLE_CLIENT; } - write_unlock_bh(&dccp_lock); + if (tb[CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ]) { + ct->proto.dccp.handshake_seq = + be64_to_cpu(nla_get_be64(tb[CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ])); + } + spin_unlock_bh(&ct->lock); return 0; } diff --git a/net/netfilter/nf_conntrack_proto_gre.c b/net/netfilter/nf_conntrack_proto_gre.c index 117b80112fcb..a54a0af0edba 100644 --- a/net/netfilter/nf_conntrack_proto_gre.c +++ b/net/netfilter/nf_conntrack_proto_gre.c @@ -176,7 +176,7 @@ static bool gre_invert_tuple(struct nf_conntrack_tuple *tuple, static bool gre_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff, struct nf_conntrack_tuple *tuple) { - struct net *net = dev_net(skb->dev ? skb->dev : skb->dst->dev); + struct net *net = dev_net(skb->dev ? skb->dev : skb_dst(skb)->dev); const struct gre_hdr_pptp *pgrehdr; struct gre_hdr_pptp _pgrehdr; __be16 srckey; @@ -219,8 +219,7 @@ static int gre_print_tuple(struct seq_file *s, } /* print private data for conntrack */ -static int gre_print_conntrack(struct seq_file *s, - const struct nf_conn *ct) +static int gre_print_conntrack(struct seq_file *s, struct nf_conn *ct) { return seq_printf(s, "timeout=%u, stream_timeout=%u ", (ct->proto.gre.timeout / HZ), diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c index 101b4ad9e817..c10e6f36e31e 100644 --- a/net/netfilter/nf_conntrack_proto_sctp.c +++ b/net/netfilter/nf_conntrack_proto_sctp.c @@ -25,9 +25,6 @@ #include #include -/* Protects ct->proto.sctp */ -static DEFINE_RWLOCK(sctp_lock); - /* FIXME: Examine ipfilter's timeouts and conntrack transitions more closely. They're more complex. --RR @@ -164,13 +161,13 @@ static int sctp_print_tuple(struct seq_file *s, } /* Print out the private part of the conntrack. */ -static int sctp_print_conntrack(struct seq_file *s, const struct nf_conn *ct) +static int sctp_print_conntrack(struct seq_file *s, struct nf_conn *ct) { enum sctp_conntrack state; - read_lock_bh(&sctp_lock); + spin_lock_bh(&ct->lock); state = ct->proto.sctp.state; - read_unlock_bh(&sctp_lock); + spin_unlock_bh(&ct->lock); return seq_printf(s, "%s ", sctp_conntrack_names[state]); } @@ -318,7 +315,7 @@ static int sctp_packet(struct nf_conn *ct, } old_state = new_state = SCTP_CONNTRACK_NONE; - write_lock_bh(&sctp_lock); + spin_lock_bh(&ct->lock); for_each_sctp_chunk (skb, sch, _sch, offset, dataoff, count) { /* Special cases of Verification tag check (Sec 8.5.1) */ if (sch->type == SCTP_CID_INIT) { @@ -371,7 +368,7 @@ static int sctp_packet(struct nf_conn *ct, if (old_state != new_state) nf_conntrack_event_cache(IPCT_PROTOINFO, ct); } - write_unlock_bh(&sctp_lock); + spin_unlock_bh(&ct->lock); nf_ct_refresh_acct(ct, ctinfo, skb, sctp_timeouts[new_state]); @@ -386,7 +383,7 @@ static int sctp_packet(struct nf_conn *ct, return NF_ACCEPT; out_unlock: - write_unlock_bh(&sctp_lock); + spin_unlock_bh(&ct->lock); out: return -NF_ACCEPT; } @@ -469,11 +466,11 @@ static bool sctp_new(struct nf_conn *ct, const struct sk_buff *skb, #include static int sctp_to_nlattr(struct sk_buff *skb, struct nlattr *nla, - const struct nf_conn *ct) + struct nf_conn *ct) { struct nlattr *nest_parms; - read_lock_bh(&sctp_lock); + spin_lock_bh(&ct->lock); nest_parms = nla_nest_start(skb, CTA_PROTOINFO_SCTP | NLA_F_NESTED); if (!nest_parms) goto nla_put_failure; @@ -488,14 +485,14 @@ static int sctp_to_nlattr(struct sk_buff *skb, struct nlattr *nla, CTA_PROTOINFO_SCTP_VTAG_REPLY, ct->proto.sctp.vtag[IP_CT_DIR_REPLY]); - read_unlock_bh(&sctp_lock); + spin_unlock_bh(&ct->lock); nla_nest_end(skb, nest_parms); return 0; nla_put_failure: - read_unlock_bh(&sctp_lock); + spin_unlock_bh(&ct->lock); return -1; } @@ -527,13 +524,13 @@ static int nlattr_to_sctp(struct nlattr *cda[], struct nf_conn *ct) !tb[CTA_PROTOINFO_SCTP_VTAG_REPLY]) return -EINVAL; - write_lock_bh(&sctp_lock); + spin_lock_bh(&ct->lock); ct->proto.sctp.state = nla_get_u8(tb[CTA_PROTOINFO_SCTP_STATE]); ct->proto.sctp.vtag[IP_CT_DIR_ORIGINAL] = nla_get_be32(tb[CTA_PROTOINFO_SCTP_VTAG_ORIGINAL]); ct->proto.sctp.vtag[IP_CT_DIR_REPLY] = nla_get_be32(tb[CTA_PROTOINFO_SCTP_VTAG_REPLY]); - write_unlock_bh(&sctp_lock); + spin_unlock_bh(&ct->lock); return 0; } diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index 97a6e93d742e..33fc0a443f3d 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c @@ -29,9 +29,6 @@ #include #include -/* Protects ct->proto.tcp */ -static DEFINE_RWLOCK(tcp_lock); - /* "Be conservative in what you do, be liberal in what you accept from others." If it's non-zero, we mark only out of window RST segments as INVALID. */ @@ -59,7 +56,7 @@ static const char *const tcp_conntrack_names[] = { "LAST_ACK", "TIME_WAIT", "CLOSE", - "LISTEN" + "SYN_SENT2", }; #define SECS * HZ @@ -82,6 +79,7 @@ static unsigned int tcp_timeouts[TCP_CONNTRACK_MAX] __read_mostly = { [TCP_CONNTRACK_LAST_ACK] = 30 SECS, [TCP_CONNTRACK_TIME_WAIT] = 2 MINS, [TCP_CONNTRACK_CLOSE] = 10 SECS, + [TCP_CONNTRACK_SYN_SENT2] = 2 MINS, }; #define sNO TCP_CONNTRACK_NONE @@ -93,7 +91,7 @@ static unsigned int tcp_timeouts[TCP_CONNTRACK_MAX] __read_mostly = { #define sLA TCP_CONNTRACK_LAST_ACK #define sTW TCP_CONNTRACK_TIME_WAIT #define sCL TCP_CONNTRACK_CLOSE -#define sLI TCP_CONNTRACK_LISTEN +#define sS2 TCP_CONNTRACK_SYN_SENT2 #define sIV TCP_CONNTRACK_MAX #define sIG TCP_CONNTRACK_IGNORE @@ -123,6 +121,7 @@ enum tcp_bit_set { * * NONE: initial state * SYN_SENT: SYN-only packet seen + * SYN_SENT2: SYN-only packet seen from reply dir, simultaneous open * SYN_RECV: SYN-ACK packet seen * ESTABLISHED: ACK packet seen * FIN_WAIT: FIN packet seen @@ -131,26 +130,24 @@ enum tcp_bit_set { * TIME_WAIT: last ACK seen * CLOSE: closed connection (RST) * - * LISTEN state is not used. - * * Packets marked as IGNORED (sIG): * if they may be either invalid or valid * and the receiver may send back a connection * closing RST or a SYN/ACK. * * Packets marked as INVALID (sIV): - * if they are invalid - * or we do not support the request (simultaneous open) + * if we regard them as truly invalid packets */ static const u8 tcp_conntracks[2][6][TCP_CONNTRACK_MAX] = { { /* ORIGINAL */ -/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ -/*syn*/ { sSS, sSS, sIG, sIG, sIG, sIG, sIG, sSS, sSS, sIV }, +/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sS2 */ +/*syn*/ { sSS, sSS, sIG, sIG, sIG, sIG, sIG, sSS, sSS, sS2 }, /* * sNO -> sSS Initialize a new connection * sSS -> sSS Retransmitted SYN - * sSR -> sIG Late retransmitted SYN? + * sS2 -> sS2 Late retransmitted SYN + * sSR -> sIG * sES -> sIG Error: SYNs in window outside the SYN_SENT state * are errors. Receiver will reply with RST * and close the connection. @@ -161,22 +158,30 @@ static const u8 tcp_conntracks[2][6][TCP_CONNTRACK_MAX] = { * sTW -> sSS Reopened connection (RFC 1122). * sCL -> sSS */ -/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ -/*synack*/ { sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV }, +/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sS2 */ +/*synack*/ { sIV, sIV, sIG, sIG, sIG, sIG, sIG, sIG, sIG, sSR }, /* - * A SYN/ACK from the client is always invalid: - * - either it tries to set up a simultaneous open, which is - * not supported; - * - or the firewall has just been inserted between the two hosts - * during the session set-up. The SYN will be retransmitted - * by the true client (or it'll time out). + * sNO -> sIV Too late and no reason to do anything + * sSS -> sIV Client can't send SYN and then SYN/ACK + * sS2 -> sSR SYN/ACK sent to SYN2 in simultaneous open + * sSR -> sIG + * sES -> sIG Error: SYNs in window outside the SYN_SENT state + * are errors. Receiver will reply with RST + * and close the connection. + * Or we are not in sync and hold a dead connection. + * sFW -> sIG + * sCW -> sIG + * sLA -> sIG + * sTW -> sIG + * sCL -> sIG */ -/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ +/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sS2 */ /*fin*/ { sIV, sIV, sFW, sFW, sLA, sLA, sLA, sTW, sCL, sIV }, /* * sNO -> sIV Too late and no reason to do anything... * sSS -> sIV Client migth not send FIN in this state: * we enforce waiting for a SYN/ACK reply first. + * sS2 -> sIV * sSR -> sFW Close started. * sES -> sFW * sFW -> sLA FIN seen in both directions, waiting for @@ -187,11 +192,12 @@ static const u8 tcp_conntracks[2][6][TCP_CONNTRACK_MAX] = { * sTW -> sTW * sCL -> sCL */ -/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ +/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sS2 */ /*ack*/ { sES, sIV, sES, sES, sCW, sCW, sTW, sTW, sCL, sIV }, /* * sNO -> sES Assumed. * sSS -> sIV ACK is invalid: we haven't seen a SYN/ACK yet. + * sS2 -> sIV * sSR -> sES Established state is reached. * sES -> sES :-) * sFW -> sCW Normal close request answered by ACK. @@ -200,29 +206,31 @@ static const u8 tcp_conntracks[2][6][TCP_CONNTRACK_MAX] = { * sTW -> sTW Retransmitted last ACK. Remain in the same state. * sCL -> sCL */ -/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ -/*rst*/ { sIV, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sIV }, +/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sS2 */ +/*rst*/ { sIV, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL }, /*none*/ { sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV } }, { /* REPLY */ -/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ -/*syn*/ { sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV }, +/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sS2 */ +/*syn*/ { sIV, sS2, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sS2 }, /* * sNO -> sIV Never reached. - * sSS -> sIV Simultaneous open, not supported - * sSR -> sIV Simultaneous open, not supported. - * sES -> sIV Server may not initiate a connection. + * sSS -> sS2 Simultaneous open + * sS2 -> sS2 Retransmitted simultaneous SYN + * sSR -> sIV Invalid SYN packets sent by the server + * sES -> sIV * sFW -> sIV * sCW -> sIV * sLA -> sIV * sTW -> sIV Reopened connection, but server may not do it. * sCL -> sIV */ -/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ -/*synack*/ { sIV, sSR, sSR, sIG, sIG, sIG, sIG, sIG, sIG, sIV }, +/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sS2 */ +/*synack*/ { sIV, sSR, sSR, sIG, sIG, sIG, sIG, sIG, sIG, sSR }, /* * sSS -> sSR Standard open. + * sS2 -> sSR Simultaneous open * sSR -> sSR Retransmitted SYN/ACK. * sES -> sIG Late retransmitted SYN/ACK? * sFW -> sIG Might be SYN/ACK answering ignored SYN @@ -231,10 +239,11 @@ static const u8 tcp_conntracks[2][6][TCP_CONNTRACK_MAX] = { * sTW -> sIG * sCL -> sIG */ -/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ +/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sS2 */ /*fin*/ { sIV, sIV, sFW, sFW, sLA, sLA, sLA, sTW, sCL, sIV }, /* * sSS -> sIV Server might not send FIN in this state. + * sS2 -> sIV * sSR -> sFW Close started. * sES -> sFW * sFW -> sLA FIN seen in both directions. @@ -243,10 +252,11 @@ static const u8 tcp_conntracks[2][6][TCP_CONNTRACK_MAX] = { * sTW -> sTW * sCL -> sCL */ -/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ -/*ack*/ { sIV, sIG, sSR, sES, sCW, sCW, sTW, sTW, sCL, sIV }, +/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sS2 */ +/*ack*/ { sIV, sIG, sSR, sES, sCW, sCW, sTW, sTW, sCL, sIG }, /* * sSS -> sIG Might be a half-open connection. + * sS2 -> sIG * sSR -> sSR Might answer late resent SYN. * sES -> sES :-) * sFW -> sCW Normal close request answered by ACK. @@ -255,8 +265,8 @@ static const u8 tcp_conntracks[2][6][TCP_CONNTRACK_MAX] = { * sTW -> sTW Retransmitted last ACK. * sCL -> sCL */ -/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ -/*rst*/ { sIV, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sIV }, +/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sS2 */ +/*rst*/ { sIV, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL }, /*none*/ { sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV } } }; @@ -296,13 +306,13 @@ static int tcp_print_tuple(struct seq_file *s, } /* Print out the private part of the conntrack. */ -static int tcp_print_conntrack(struct seq_file *s, const struct nf_conn *ct) +static int tcp_print_conntrack(struct seq_file *s, struct nf_conn *ct) { enum tcp_conntrack state; - read_lock_bh(&tcp_lock); + spin_lock_bh(&ct->lock); state = ct->proto.tcp.state; - read_unlock_bh(&tcp_lock); + spin_unlock_bh(&ct->lock); return seq_printf(s, "%s ", tcp_conntrack_names[state]); } @@ -521,13 +531,14 @@ static bool tcp_in_window(const struct nf_conn *ct, receiver->td_end, receiver->td_maxend, receiver->td_maxwin, receiver->td_scale); - if (sender->td_end == 0) { + if (sender->td_maxwin == 0) { /* * Initialize sender data. */ - if (tcph->syn && tcph->ack) { + if (tcph->syn) { /* - * Outgoing SYN-ACK in reply to a SYN. + * SYN-ACK in reply to a SYN + * or SYN from reply direction in simultaneous open. */ sender->td_end = sender->td_maxend = end; @@ -543,6 +554,9 @@ static bool tcp_in_window(const struct nf_conn *ct, && receiver->flags & IP_CT_TCP_FLAG_WINDOW_SCALE)) sender->td_scale = receiver->td_scale = 0; + if (!tcph->ack) + /* Simultaneous open */ + return true; } else { /* * We are in the middle of a connection, @@ -716,14 +730,14 @@ void nf_conntrack_tcp_update(const struct sk_buff *skb, end = segment_seq_plus_len(ntohl(tcph->seq), skb->len, dataoff, tcph); - write_lock_bh(&tcp_lock); + spin_lock_bh(&ct->lock); /* * We have to worry for the ack in the reply packet only... */ if (after(end, ct->proto.tcp.seen[dir].td_end)) ct->proto.tcp.seen[dir].td_end = end; ct->proto.tcp.last_end = end; - write_unlock_bh(&tcp_lock); + spin_unlock_bh(&ct->lock); pr_debug("tcp_update: sender end=%u maxend=%u maxwin=%u scale=%i " "receiver end=%u maxend=%u maxwin=%u scale=%i\n", sender->td_end, sender->td_maxend, sender->td_maxwin, @@ -832,7 +846,7 @@ static int tcp_packet(struct nf_conn *ct, th = skb_header_pointer(skb, dataoff, sizeof(_tcph), &_tcph); BUG_ON(th == NULL); - write_lock_bh(&tcp_lock); + spin_lock_bh(&ct->lock); old_state = ct->proto.tcp.state; dir = CTINFO2DIR(ctinfo); index = get_conntrack_index(th); @@ -862,7 +876,7 @@ static int tcp_packet(struct nf_conn *ct, && ct->proto.tcp.last_index == TCP_RST_SET)) { /* Attempt to reopen a closed/aborted connection. * Delete this connection and look up again. */ - write_unlock_bh(&tcp_lock); + spin_unlock_bh(&ct->lock); /* Only repeat if we can actually remove the timer. * Destruction may already be in progress in process @@ -898,7 +912,7 @@ static int tcp_packet(struct nf_conn *ct, * that the client cannot but retransmit its SYN and * thus initiate a clean new session. */ - write_unlock_bh(&tcp_lock); + spin_unlock_bh(&ct->lock); if (LOG_INVALID(net, IPPROTO_TCP)) nf_log_packet(pf, 0, skb, NULL, NULL, NULL, "nf_ct_tcp: killing out of sync session "); @@ -911,7 +925,7 @@ static int tcp_packet(struct nf_conn *ct, ct->proto.tcp.last_end = segment_seq_plus_len(ntohl(th->seq), skb->len, dataoff, th); - write_unlock_bh(&tcp_lock); + spin_unlock_bh(&ct->lock); if (LOG_INVALID(net, IPPROTO_TCP)) nf_log_packet(pf, 0, skb, NULL, NULL, NULL, "nf_ct_tcp: invalid packet ignored "); @@ -920,7 +934,7 @@ static int tcp_packet(struct nf_conn *ct, /* Invalid packet */ pr_debug("nf_ct_tcp: Invalid dir=%i index=%u ostate=%u\n", dir, get_conntrack_index(th), old_state); - write_unlock_bh(&tcp_lock); + spin_unlock_bh(&ct->lock); if (LOG_INVALID(net, IPPROTO_TCP)) nf_log_packet(pf, 0, skb, NULL, NULL, NULL, "nf_ct_tcp: invalid state "); @@ -930,7 +944,7 @@ static int tcp_packet(struct nf_conn *ct, && (ct->proto.tcp.seen[!dir].flags & IP_CT_TCP_FLAG_MAXACK_SET) && before(ntohl(th->seq), ct->proto.tcp.seen[!dir].td_maxack)) { /* Invalid RST */ - write_unlock_bh(&tcp_lock); + spin_unlock_bh(&ct->lock); if (LOG_INVALID(net, IPPROTO_TCP)) nf_log_packet(pf, 0, skb, NULL, NULL, NULL, "nf_ct_tcp: invalid RST "); @@ -961,7 +975,7 @@ static int tcp_packet(struct nf_conn *ct, if (!tcp_in_window(ct, &ct->proto.tcp, dir, index, skb, dataoff, th, pf)) { - write_unlock_bh(&tcp_lock); + spin_unlock_bh(&ct->lock); return -NF_ACCEPT; } in_window: @@ -990,9 +1004,8 @@ static int tcp_packet(struct nf_conn *ct, timeout = nf_ct_tcp_timeout_unacknowledged; else timeout = tcp_timeouts[new_state]; - write_unlock_bh(&tcp_lock); + spin_unlock_bh(&ct->lock); - nf_conntrack_event_cache(IPCT_PROTOINFO_VOLATILE, ct); if (new_state != old_state) nf_conntrack_event_cache(IPCT_PROTOINFO, ct); @@ -1086,7 +1099,7 @@ static bool tcp_new(struct nf_conn *ct, const struct sk_buff *skb, ct->proto.tcp.seen[1].td_end = 0; ct->proto.tcp.seen[1].td_maxend = 0; - ct->proto.tcp.seen[1].td_maxwin = 1; + ct->proto.tcp.seen[1].td_maxwin = 0; ct->proto.tcp.seen[1].td_scale = 0; /* tcp_packet will set them */ @@ -1108,12 +1121,12 @@ static bool tcp_new(struct nf_conn *ct, const struct sk_buff *skb, #include static int tcp_to_nlattr(struct sk_buff *skb, struct nlattr *nla, - const struct nf_conn *ct) + struct nf_conn *ct) { struct nlattr *nest_parms; struct nf_ct_tcp_flags tmp = {}; - read_lock_bh(&tcp_lock); + spin_lock_bh(&ct->lock); nest_parms = nla_nest_start(skb, CTA_PROTOINFO_TCP | NLA_F_NESTED); if (!nest_parms) goto nla_put_failure; @@ -1133,14 +1146,14 @@ static int tcp_to_nlattr(struct sk_buff *skb, struct nlattr *nla, tmp.flags = ct->proto.tcp.seen[1].flags; NLA_PUT(skb, CTA_PROTOINFO_TCP_FLAGS_REPLY, sizeof(struct nf_ct_tcp_flags), &tmp); - read_unlock_bh(&tcp_lock); + spin_unlock_bh(&ct->lock); nla_nest_end(skb, nest_parms); return 0; nla_put_failure: - read_unlock_bh(&tcp_lock); + spin_unlock_bh(&ct->lock); return -1; } @@ -1171,7 +1184,7 @@ static int nlattr_to_tcp(struct nlattr *cda[], struct nf_conn *ct) nla_get_u8(tb[CTA_PROTOINFO_TCP_STATE]) >= TCP_CONNTRACK_MAX) return -EINVAL; - write_lock_bh(&tcp_lock); + spin_lock_bh(&ct->lock); if (tb[CTA_PROTOINFO_TCP_STATE]) ct->proto.tcp.state = nla_get_u8(tb[CTA_PROTOINFO_TCP_STATE]); @@ -1198,7 +1211,7 @@ static int nlattr_to_tcp(struct nlattr *cda[], struct nf_conn *ct) ct->proto.tcp.seen[1].td_scale = nla_get_u8(tb[CTA_PROTOINFO_TCP_WSCALE_REPLY]); } - write_unlock_bh(&tcp_lock); + spin_unlock_bh(&ct->lock); return 0; } @@ -1327,6 +1340,13 @@ static struct ctl_table tcp_compat_sysctl_table[] = { .mode = 0644, .proc_handler = proc_dointvec_jiffies, }, + { + .procname = "ip_conntrack_tcp_timeout_syn_sent2", + .data = &tcp_timeouts[TCP_CONNTRACK_SYN_SENT2], + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = proc_dointvec_jiffies, + }, { .procname = "ip_conntrack_tcp_timeout_syn_recv", .data = &tcp_timeouts[TCP_CONNTRACK_SYN_RECV], diff --git a/net/netfilter/nf_log.c b/net/netfilter/nf_log.c index beb37311e1a5..4e620305f28c 100644 --- a/net/netfilter/nf_log.c +++ b/net/netfilter/nf_log.c @@ -47,7 +47,6 @@ int nf_log_register(u_int8_t pf, struct nf_logger *logger) mutex_lock(&nf_log_mutex); if (pf == NFPROTO_UNSPEC) { - int i; for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) list_add_tail(&(logger->list[i]), &(nf_loggers_l[i])); } else { @@ -216,7 +215,7 @@ static const struct file_operations nflog_file_ops = { #endif /* PROC_FS */ #ifdef CONFIG_SYSCTL -struct ctl_path nf_log_sysctl_path[] = { +static struct ctl_path nf_log_sysctl_path[] = { { .procname = "net", .ctl_name = CTL_NET, }, { .procname = "netfilter", .ctl_name = NET_NETFILTER, }, { .procname = "nf_log", .ctl_name = CTL_UNNUMBERED, }, @@ -228,19 +227,26 @@ static struct ctl_table nf_log_sysctl_table[NFPROTO_NUMPROTO+1]; static struct ctl_table_header *nf_log_dir_header; static int nf_log_proc_dostring(ctl_table *table, int write, struct file *filp, - void *buffer, size_t *lenp, loff_t *ppos) + void __user *buffer, size_t *lenp, loff_t *ppos) { const struct nf_logger *logger; + char buf[NFLOGGER_NAME_LEN]; + size_t size = *lenp; int r = 0; int tindex = (unsigned long)table->extra1; if (write) { - if (!strcmp(buffer, "NONE")) { + if (size > sizeof(buf)) + size = sizeof(buf); + if (copy_from_user(buf, buffer, size)) + return -EFAULT; + + if (!strcmp(buf, "NONE")) { nf_log_unbind_pf(tindex); return 0; } mutex_lock(&nf_log_mutex); - logger = __find_logger(tindex, buffer); + logger = __find_logger(tindex, buf); if (logger == NULL) { mutex_unlock(&nf_log_mutex); return -ENOENT; @@ -248,14 +254,14 @@ static int nf_log_proc_dostring(ctl_table *table, int write, struct file *filp, rcu_assign_pointer(nf_loggers[tindex], logger); mutex_unlock(&nf_log_mutex); } else { - rcu_read_lock(); - logger = rcu_dereference(nf_loggers[tindex]); + mutex_lock(&nf_log_mutex); + logger = nf_loggers[tindex]; if (!logger) table->data = "NONE"; else table->data = logger->name; r = proc_dostring(table, write, filp, buffer, lenp, ppos); - rcu_read_unlock(); + mutex_unlock(&nf_log_mutex); } return r; diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c index 4f2310c93e01..3a6fd77f7761 100644 --- a/net/netfilter/nf_queue.c +++ b/net/netfilter/nf_queue.c @@ -204,10 +204,10 @@ int nf_queue(struct sk_buff *skb, queuenum); switch (pf) { - case AF_INET: + case NFPROTO_IPV4: skb->protocol = htons(ETH_P_IP); break; - case AF_INET6: + case NFPROTO_IPV6: skb->protocol = htons(ETH_P_IPV6); break; } diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c index b8ab37ad7ed5..92761a988375 100644 --- a/net/netfilter/nfnetlink.c +++ b/net/netfilter/nfnetlink.c @@ -107,9 +107,10 @@ int nfnetlink_has_listeners(unsigned int group) } EXPORT_SYMBOL_GPL(nfnetlink_has_listeners); -int nfnetlink_send(struct sk_buff *skb, u32 pid, unsigned group, int echo) +int nfnetlink_send(struct sk_buff *skb, u32 pid, + unsigned group, int echo, gfp_t flags) { - return nlmsg_notify(nfnl, skb, pid, group, echo, gfp_any()); + return nlmsg_notify(nfnl, skb, pid, group, echo, flags); } EXPORT_SYMBOL_GPL(nfnetlink_send); @@ -136,7 +137,7 @@ static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) return -EPERM; /* All the messages must at least contain nfgenmsg */ - if (nlh->nlmsg_len < NLMSG_SPACE(sizeof(struct nfgenmsg))) + if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(struct nfgenmsg))) return 0; type = nlh->nlmsg_type; @@ -160,19 +161,14 @@ replay: { int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg)); u_int8_t cb_id = NFNL_MSG_TYPE(nlh->nlmsg_type); - u_int16_t attr_count = ss->cb[cb_id].attr_count; - struct nlattr *cda[attr_count+1]; + struct nlattr *cda[ss->cb[cb_id].attr_count + 1]; + struct nlattr *attr = (void *)nlh + min_len; + int attrlen = nlh->nlmsg_len - min_len; - if (likely(nlh->nlmsg_len >= min_len)) { - struct nlattr *attr = (void *)nlh + NLMSG_ALIGN(min_len); - int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len); - - err = nla_parse(cda, attr_count, attr, attrlen, - ss->cb[cb_id].policy); - if (err < 0) - return err; - } else - return -EINVAL; + err = nla_parse(cda, ss->cb[cb_id].attr_count, + attr, attrlen, ss->cb[cb_id].policy); + if (err < 0) + return err; err = nc->call(nfnl, skb, nlh, cda); if (err == -EAGAIN) diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index 8c860112ce05..71daa0934b6c 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -1,6 +1,6 @@ /* * This is a module which is used for queueing packets and communicating with - * userspace via nfetlink. + * userspace via nfnetlink. * * (C) 2005 by Harald Welte * (C) 2007 by Patrick McHardy @@ -932,6 +932,8 @@ static void __exit nfnetlink_queue_fini(void) #endif nfnetlink_subsys_unregister(&nfqnl_subsys); netlink_unregister_notifier(&nfqnl_rtnl_notifier); + + rcu_barrier(); /* Wait for completion of call_rcu()'s */ } MODULE_DESCRIPTION("netfilter packet queue handler"); diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index 150e5cf62f85..025d1a0af78b 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -329,6 +329,32 @@ int xt_find_revision(u8 af, const char *name, u8 revision, int target, } EXPORT_SYMBOL_GPL(xt_find_revision); +static char *textify_hooks(char *buf, size_t size, unsigned int mask) +{ + static const char *const names[] = { + "PREROUTING", "INPUT", "FORWARD", + "OUTPUT", "POSTROUTING", "BROUTING", + }; + unsigned int i; + char *p = buf; + bool np = false; + int res; + + *p = '\0'; + for (i = 0; i < ARRAY_SIZE(names); ++i) { + if (!(mask & (1 << i))) + continue; + res = snprintf(p, size, "%s%s", np ? "/" : "", names[i]); + if (res > 0) { + size -= res; + p += res; + } + np = true; + } + + return buf; +} + int xt_check_match(struct xt_mtchk_param *par, unsigned int size, u_int8_t proto, bool inv_proto) { @@ -338,26 +364,30 @@ int xt_check_match(struct xt_mtchk_param *par, * ebt_among is exempt from centralized matchsize checking * because it uses a dynamic-size data set. */ - printk("%s_tables: %s match: invalid size %Zu != %u\n", + pr_err("%s_tables: %s match: invalid size %Zu != %u\n", xt_prefix[par->family], par->match->name, XT_ALIGN(par->match->matchsize), size); return -EINVAL; } if (par->match->table != NULL && strcmp(par->match->table, par->table) != 0) { - printk("%s_tables: %s match: only valid in %s table, not %s\n", + pr_err("%s_tables: %s match: only valid in %s table, not %s\n", xt_prefix[par->family], par->match->name, par->match->table, par->table); return -EINVAL; } if (par->match->hooks && (par->hook_mask & ~par->match->hooks) != 0) { - printk("%s_tables: %s match: bad hook_mask %#x/%#x\n", + char used[64], allow[64]; + + pr_err("%s_tables: %s match: used from hooks %s, but only " + "valid from %s\n", xt_prefix[par->family], par->match->name, - par->hook_mask, par->match->hooks); + textify_hooks(used, sizeof(used), par->hook_mask), + textify_hooks(allow, sizeof(allow), par->match->hooks)); return -EINVAL; } if (par->match->proto && (par->match->proto != proto || inv_proto)) { - printk("%s_tables: %s match: only valid for protocol %u\n", + pr_err("%s_tables: %s match: only valid for protocol %u\n", xt_prefix[par->family], par->match->name, par->match->proto); return -EINVAL; @@ -484,26 +514,30 @@ int xt_check_target(struct xt_tgchk_param *par, unsigned int size, u_int8_t proto, bool inv_proto) { if (XT_ALIGN(par->target->targetsize) != size) { - printk("%s_tables: %s target: invalid size %Zu != %u\n", + pr_err("%s_tables: %s target: invalid size %Zu != %u\n", xt_prefix[par->family], par->target->name, XT_ALIGN(par->target->targetsize), size); return -EINVAL; } if (par->target->table != NULL && strcmp(par->target->table, par->table) != 0) { - printk("%s_tables: %s target: only valid in %s table, not %s\n", + pr_err("%s_tables: %s target: only valid in %s table, not %s\n", xt_prefix[par->family], par->target->name, par->target->table, par->table); return -EINVAL; } if (par->target->hooks && (par->hook_mask & ~par->target->hooks) != 0) { - printk("%s_tables: %s target: bad hook_mask %#x/%#x\n", + char used[64], allow[64]; + + pr_err("%s_tables: %s target: used from hooks %s, but only " + "usable from %s\n", xt_prefix[par->family], par->target->name, - par->hook_mask, par->target->hooks); + textify_hooks(used, sizeof(used), par->hook_mask), + textify_hooks(allow, sizeof(allow), par->target->hooks)); return -EINVAL; } if (par->target->proto && (par->target->proto != proto || inv_proto)) { - printk("%s_tables: %s target: only valid for protocol %u\n", + pr_err("%s_tables: %s target: only valid for protocol %u\n", xt_prefix[par->family], par->target->name, par->target->proto); return -EINVAL; diff --git a/net/netfilter/xt_NFQUEUE.c b/net/netfilter/xt_NFQUEUE.c index f9977b3311f7..f28f6a5fc02d 100644 --- a/net/netfilter/xt_NFQUEUE.c +++ b/net/netfilter/xt_NFQUEUE.c @@ -11,6 +11,10 @@ #include #include +#include +#include +#include + #include #include #include @@ -23,6 +27,8 @@ MODULE_ALIAS("ipt_NFQUEUE"); MODULE_ALIAS("ip6t_NFQUEUE"); MODULE_ALIAS("arpt_NFQUEUE"); +static u32 jhash_initval __read_mostly; + static unsigned int nfqueue_tg(struct sk_buff *skb, const struct xt_target_param *par) { @@ -31,32 +37,105 @@ nfqueue_tg(struct sk_buff *skb, const struct xt_target_param *par) return NF_QUEUE_NR(tinfo->queuenum); } +static u32 hash_v4(const struct sk_buff *skb) +{ + const struct iphdr *iph = ip_hdr(skb); + __be32 ipaddr; + + /* packets in either direction go into same queue */ + ipaddr = iph->saddr ^ iph->daddr; + + return jhash_2words((__force u32)ipaddr, iph->protocol, jhash_initval); +} + +static unsigned int +nfqueue_tg4_v1(struct sk_buff *skb, const struct xt_target_param *par) +{ + const struct xt_NFQ_info_v1 *info = par->targinfo; + u32 queue = info->queuenum; + + if (info->queues_total > 1) + queue = hash_v4(skb) % info->queues_total + queue; + return NF_QUEUE_NR(queue); +} + +#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE) +static u32 hash_v6(const struct sk_buff *skb) +{ + const struct ipv6hdr *ip6h = ipv6_hdr(skb); + __be32 addr[4]; + + addr[0] = ip6h->saddr.s6_addr32[0] ^ ip6h->daddr.s6_addr32[0]; + addr[1] = ip6h->saddr.s6_addr32[1] ^ ip6h->daddr.s6_addr32[1]; + addr[2] = ip6h->saddr.s6_addr32[2] ^ ip6h->daddr.s6_addr32[2]; + addr[3] = ip6h->saddr.s6_addr32[3] ^ ip6h->daddr.s6_addr32[3]; + + return jhash2((__force u32 *)addr, ARRAY_SIZE(addr), jhash_initval); +} + +static unsigned int +nfqueue_tg6_v1(struct sk_buff *skb, const struct xt_target_param *par) +{ + const struct xt_NFQ_info_v1 *info = par->targinfo; + u32 queue = info->queuenum; + + if (info->queues_total > 1) + queue = hash_v6(skb) % info->queues_total + queue; + return NF_QUEUE_NR(queue); +} +#endif + +static bool nfqueue_tg_v1_check(const struct xt_tgchk_param *par) +{ + const struct xt_NFQ_info_v1 *info = par->targinfo; + u32 maxid; + + if (info->queues_total == 0) { + pr_err("NFQUEUE: number of total queues is 0\n"); + return false; + } + maxid = info->queues_total - 1 + info->queuenum; + if (maxid > 0xffff) { + pr_err("NFQUEUE: number of queues (%u) out of range (got %u)\n", + info->queues_total, maxid); + return false; + } + return true; +} + static struct xt_target nfqueue_tg_reg[] __read_mostly = { { .name = "NFQUEUE", + .family = NFPROTO_UNSPEC, + .target = nfqueue_tg, + .targetsize = sizeof(struct xt_NFQ_info), + .me = THIS_MODULE, + }, + { + .name = "NFQUEUE", + .revision = 1, .family = NFPROTO_IPV4, - .target = nfqueue_tg, - .targetsize = sizeof(struct xt_NFQ_info), + .checkentry = nfqueue_tg_v1_check, + .target = nfqueue_tg4_v1, + .targetsize = sizeof(struct xt_NFQ_info_v1), .me = THIS_MODULE, }, +#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE) { .name = "NFQUEUE", + .revision = 1, .family = NFPROTO_IPV6, - .target = nfqueue_tg, - .targetsize = sizeof(struct xt_NFQ_info), - .me = THIS_MODULE, - }, - { - .name = "NFQUEUE", - .family = NFPROTO_ARP, - .target = nfqueue_tg, - .targetsize = sizeof(struct xt_NFQ_info), + .checkentry = nfqueue_tg_v1_check, + .target = nfqueue_tg6_v1, + .targetsize = sizeof(struct xt_NFQ_info_v1), .me = THIS_MODULE, }, +#endif }; static int __init nfqueue_tg_init(void) { + get_random_bytes(&jhash_initval, sizeof(jhash_initval)); return xt_register_targets(nfqueue_tg_reg, ARRAY_SIZE(nfqueue_tg_reg)); } diff --git a/net/netfilter/xt_TCPMSS.c b/net/netfilter/xt_TCPMSS.c index 4f3b1f808795..eda64c1cb1e5 100644 --- a/net/netfilter/xt_TCPMSS.c +++ b/net/netfilter/xt_TCPMSS.c @@ -73,11 +73,11 @@ tcpmss_mangle_packet(struct sk_buff *skb, } if (info->mss == XT_TCPMSS_CLAMP_PMTU) { - if (dst_mtu(skb->dst) <= minlen) { + if (dst_mtu(skb_dst(skb)) <= minlen) { if (net_ratelimit()) printk(KERN_ERR "xt_TCPMSS: " "unknown or invalid path-MTU (%u)\n", - dst_mtu(skb->dst)); + dst_mtu(skb_dst(skb))); return -1; } if (in_mtu <= minlen) { @@ -86,7 +86,7 @@ tcpmss_mangle_packet(struct sk_buff *skb, "invalid path-MTU (%u)\n", in_mtu); return -1; } - newmss = min(dst_mtu(skb->dst), in_mtu) - minlen; + newmss = min(dst_mtu(skb_dst(skb)), in_mtu) - minlen; } else newmss = info->mss; diff --git a/net/netfilter/xt_cluster.c b/net/netfilter/xt_cluster.c index 69a639f35403..225ee3ecd69d 100644 --- a/net/netfilter/xt_cluster.c +++ b/net/netfilter/xt_cluster.c @@ -15,14 +15,14 @@ #include #include -static inline u_int32_t nf_ct_orig_ipv4_src(const struct nf_conn *ct) +static inline u32 nf_ct_orig_ipv4_src(const struct nf_conn *ct) { - return ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip; + return (__force u32)ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip; } -static inline const void *nf_ct_orig_ipv6_src(const struct nf_conn *ct) +static inline const u32 *nf_ct_orig_ipv6_src(const struct nf_conn *ct) { - return ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip6; + return (__force u32 *)ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip6; } static inline u_int32_t diff --git a/net/netfilter/xt_osf.c b/net/netfilter/xt_osf.c new file mode 100644 index 000000000000..863e40977a4d --- /dev/null +++ b/net/netfilter/xt_osf.c @@ -0,0 +1,428 @@ +/* + * Copyright (c) 2003+ Evgeniy Polyakov + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +struct xt_osf_finger { + struct rcu_head rcu_head; + struct list_head finger_entry; + struct xt_osf_user_finger finger; +}; + +enum osf_fmatch_states { + /* Packet does not match the fingerprint */ + FMATCH_WRONG = 0, + /* Packet matches the fingerprint */ + FMATCH_OK, + /* Options do not match the fingerprint, but header does */ + FMATCH_OPT_WRONG, +}; + +/* + * Indexed by dont-fragment bit. + * It is the only constant value in the fingerprint. + */ +static struct list_head xt_osf_fingers[2]; + +static const struct nla_policy xt_osf_policy[OSF_ATTR_MAX + 1] = { + [OSF_ATTR_FINGER] = { .len = sizeof(struct xt_osf_user_finger) }, +}; + +static void xt_osf_finger_free_rcu(struct rcu_head *rcu_head) +{ + struct xt_osf_finger *f = container_of(rcu_head, struct xt_osf_finger, rcu_head); + + kfree(f); +} + +static int xt_osf_add_callback(struct sock *ctnl, struct sk_buff *skb, + struct nlmsghdr *nlh, struct nlattr *osf_attrs[]) +{ + struct xt_osf_user_finger *f; + struct xt_osf_finger *kf = NULL, *sf; + int err = 0; + + if (!osf_attrs[OSF_ATTR_FINGER]) + return -EINVAL; + + if (!(nlh->nlmsg_flags & NLM_F_CREATE)) + return -EINVAL; + + f = nla_data(osf_attrs[OSF_ATTR_FINGER]); + + kf = kmalloc(sizeof(struct xt_osf_finger), GFP_KERNEL); + if (!kf) + return -ENOMEM; + + memcpy(&kf->finger, f, sizeof(struct xt_osf_user_finger)); + + list_for_each_entry(sf, &xt_osf_fingers[!!f->df], finger_entry) { + if (memcmp(&sf->finger, f, sizeof(struct xt_osf_user_finger))) + continue; + + kfree(kf); + kf = NULL; + + if (nlh->nlmsg_flags & NLM_F_EXCL) + err = -EEXIST; + break; + } + + /* + * We are protected by nfnl mutex. + */ + if (kf) + list_add_tail_rcu(&kf->finger_entry, &xt_osf_fingers[!!f->df]); + + return err; +} + +static int xt_osf_remove_callback(struct sock *ctnl, struct sk_buff *skb, + struct nlmsghdr *nlh, struct nlattr *osf_attrs[]) +{ + struct xt_osf_user_finger *f; + struct xt_osf_finger *sf; + int err = ENOENT; + + if (!osf_attrs[OSF_ATTR_FINGER]) + return -EINVAL; + + f = nla_data(osf_attrs[OSF_ATTR_FINGER]); + + list_for_each_entry(sf, &xt_osf_fingers[!!f->df], finger_entry) { + if (memcmp(&sf->finger, f, sizeof(struct xt_osf_user_finger))) + continue; + + /* + * We are protected by nfnl mutex. + */ + list_del_rcu(&sf->finger_entry); + call_rcu(&sf->rcu_head, xt_osf_finger_free_rcu); + + err = 0; + break; + } + + return err; +} + +static const struct nfnl_callback xt_osf_nfnetlink_callbacks[OSF_MSG_MAX] = { + [OSF_MSG_ADD] = { + .call = xt_osf_add_callback, + .attr_count = OSF_ATTR_MAX, + .policy = xt_osf_policy, + }, + [OSF_MSG_REMOVE] = { + .call = xt_osf_remove_callback, + .attr_count = OSF_ATTR_MAX, + .policy = xt_osf_policy, + }, +}; + +static const struct nfnetlink_subsystem xt_osf_nfnetlink = { + .name = "osf", + .subsys_id = NFNL_SUBSYS_OSF, + .cb_count = OSF_MSG_MAX, + .cb = xt_osf_nfnetlink_callbacks, +}; + +static inline int xt_osf_ttl(const struct sk_buff *skb, const struct xt_osf_info *info, + unsigned char f_ttl) +{ + const struct iphdr *ip = ip_hdr(skb); + + if (info->flags & XT_OSF_TTL) { + if (info->ttl == XT_OSF_TTL_TRUE) + return ip->ttl == f_ttl; + if (info->ttl == XT_OSF_TTL_NOCHECK) + return 1; + else if (ip->ttl <= f_ttl) + return 1; + else { + struct in_device *in_dev = __in_dev_get_rcu(skb->dev); + int ret = 0; + + for_ifa(in_dev) { + if (inet_ifa_match(ip->saddr, ifa)) { + ret = (ip->ttl == f_ttl); + break; + } + } + endfor_ifa(in_dev); + + return ret; + } + } + + return ip->ttl == f_ttl; +} + +static bool xt_osf_match_packet(const struct sk_buff *skb, + const struct xt_match_param *p) +{ + const struct xt_osf_info *info = p->matchinfo; + const struct iphdr *ip = ip_hdr(skb); + const struct tcphdr *tcp; + struct tcphdr _tcph; + int fmatch = FMATCH_WRONG, fcount = 0; + unsigned int optsize = 0, check_WSS = 0; + u16 window, totlen, mss = 0; + bool df; + const unsigned char *optp = NULL, *_optp = NULL; + unsigned char opts[MAX_IPOPTLEN]; + const struct xt_osf_finger *kf; + const struct xt_osf_user_finger *f; + + if (!info) + return false; + + tcp = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(struct tcphdr), &_tcph); + if (!tcp) + return false; + + if (!tcp->syn) + return false; + + totlen = ntohs(ip->tot_len); + df = ntohs(ip->frag_off) & IP_DF; + window = ntohs(tcp->window); + + if (tcp->doff * 4 > sizeof(struct tcphdr)) { + optsize = tcp->doff * 4 - sizeof(struct tcphdr); + + _optp = optp = skb_header_pointer(skb, ip_hdrlen(skb) + + sizeof(struct tcphdr), optsize, opts); + } + + rcu_read_lock(); + list_for_each_entry_rcu(kf, &xt_osf_fingers[df], finger_entry) { + f = &kf->finger; + + if (!(info->flags & XT_OSF_LOG) && strcmp(info->genre, f->genre)) + continue; + + optp = _optp; + fmatch = FMATCH_WRONG; + + if (totlen == f->ss && xt_osf_ttl(skb, info, f->ttl)) { + int foptsize, optnum; + + /* + * Should not happen if userspace parser was written correctly. + */ + if (f->wss.wc >= OSF_WSS_MAX) + continue; + + /* Check options */ + + foptsize = 0; + for (optnum = 0; optnum < f->opt_num; ++optnum) + foptsize += f->opt[optnum].length; + + if (foptsize > MAX_IPOPTLEN || + optsize > MAX_IPOPTLEN || + optsize != foptsize) + continue; + + check_WSS = f->wss.wc; + + for (optnum = 0; optnum < f->opt_num; ++optnum) { + if (f->opt[optnum].kind == (*optp)) { + __u32 len = f->opt[optnum].length; + const __u8 *optend = optp + len; + int loop_cont = 0; + + fmatch = FMATCH_OK; + + switch (*optp) { + case OSFOPT_MSS: + mss = optp[3]; + mss <<= 8; + mss |= optp[2]; + + mss = ntohs(mss); + break; + case OSFOPT_TS: + loop_cont = 1; + break; + } + + optp = optend; + } else + fmatch = FMATCH_OPT_WRONG; + + if (fmatch != FMATCH_OK) + break; + } + + if (fmatch != FMATCH_OPT_WRONG) { + fmatch = FMATCH_WRONG; + + switch (check_WSS) { + case OSF_WSS_PLAIN: + if (f->wss.val == 0 || window == f->wss.val) + fmatch = FMATCH_OK; + break; + case OSF_WSS_MSS: + /* + * Some smart modems decrease mangle MSS to + * SMART_MSS_2, so we check standard, decreased + * and the one provided in the fingerprint MSS + * values. + */ +#define SMART_MSS_1 1460 +#define SMART_MSS_2 1448 + if (window == f->wss.val * mss || + window == f->wss.val * SMART_MSS_1 || + window == f->wss.val * SMART_MSS_2) + fmatch = FMATCH_OK; + break; + case OSF_WSS_MTU: + if (window == f->wss.val * (mss + 40) || + window == f->wss.val * (SMART_MSS_1 + 40) || + window == f->wss.val * (SMART_MSS_2 + 40)) + fmatch = FMATCH_OK; + break; + case OSF_WSS_MODULO: + if ((window % f->wss.val) == 0) + fmatch = FMATCH_OK; + break; + } + } + + if (fmatch != FMATCH_OK) + continue; + + fcount++; + + if (info->flags & XT_OSF_LOG) + nf_log_packet(p->hooknum, 0, skb, p->in, p->out, NULL, + "%s [%s:%s] : %pi4:%d -> %pi4:%d hops=%d\n", + f->genre, f->version, f->subtype, + &ip->saddr, ntohs(tcp->source), + &ip->daddr, ntohs(tcp->dest), + f->ttl - ip->ttl); + + if ((info->flags & XT_OSF_LOG) && + info->loglevel == XT_OSF_LOGLEVEL_FIRST) + break; + } + } + rcu_read_unlock(); + + if (!fcount && (info->flags & XT_OSF_LOG)) + nf_log_packet(p->hooknum, 0, skb, p->in, p->out, NULL, + "Remote OS is not known: %pi4:%u -> %pi4:%u\n", + &ip->saddr, ntohs(tcp->source), + &ip->daddr, ntohs(tcp->dest)); + + if (fcount) + fmatch = FMATCH_OK; + + return fmatch == FMATCH_OK; +} + +static struct xt_match xt_osf_match = { + .name = "osf", + .revision = 0, + .family = NFPROTO_IPV4, + .proto = IPPROTO_TCP, + .hooks = (1 << NF_INET_LOCAL_IN) | + (1 << NF_INET_PRE_ROUTING) | + (1 << NF_INET_FORWARD), + .match = xt_osf_match_packet, + .matchsize = sizeof(struct xt_osf_info), + .me = THIS_MODULE, +}; + +static int __init xt_osf_init(void) +{ + int err = -EINVAL; + int i; + + for (i=0; ifinger_entry); + call_rcu(&f->rcu_head, xt_osf_finger_free_rcu); + } + } + rcu_read_unlock(); + + rcu_barrier(); +} + +module_init(xt_osf_init); +module_exit(xt_osf_fini); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Evgeniy Polyakov "); +MODULE_DESCRIPTION("Passive OS fingerprint matching."); +MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_OSF); diff --git a/net/netfilter/xt_policy.c b/net/netfilter/xt_policy.c index 328bd20ddd25..4cbfebda8fa1 100644 --- a/net/netfilter/xt_policy.c +++ b/net/netfilter/xt_policy.c @@ -86,7 +86,7 @@ match_policy_out(const struct sk_buff *skb, const struct xt_policy_info *info, unsigned short family) { const struct xt_policy_elem *e; - const struct dst_entry *dst = skb->dst; + const struct dst_entry *dst = skb_dst(skb); int strict = info->flags & XT_POLICY_MATCH_STRICT; int i, pos; diff --git a/net/netfilter/xt_quota.c b/net/netfilter/xt_quota.c index 01dd07b764ec..98fc190e8f0e 100644 --- a/net/netfilter/xt_quota.c +++ b/net/netfilter/xt_quota.c @@ -54,6 +54,7 @@ static bool quota_mt_check(const struct xt_mtchk_param *par) if (q->master == NULL) return -ENOMEM; + q->master->quota = q->quota; return true; } diff --git a/net/netfilter/xt_rateest.c b/net/netfilter/xt_rateest.c index 220a1d588ee0..4fc6a917f6de 100644 --- a/net/netfilter/xt_rateest.c +++ b/net/netfilter/xt_rateest.c @@ -66,7 +66,7 @@ xt_rateest_mt(const struct sk_buff *skb, const struct xt_match_param *par) if (info->flags & XT_RATEEST_MATCH_BPS) ret &= bps1 == bps2; if (info->flags & XT_RATEEST_MATCH_PPS) - ret &= pps2 == pps2; + ret &= pps1 == pps2; break; } diff --git a/net/netfilter/xt_realm.c b/net/netfilter/xt_realm.c index 67419287bc7e..484d1689bfde 100644 --- a/net/netfilter/xt_realm.c +++ b/net/netfilter/xt_realm.c @@ -25,7 +25,7 @@ static bool realm_mt(const struct sk_buff *skb, const struct xt_match_param *par) { const struct xt_realm_info *info = par->matchinfo; - const struct dst_entry *dst = skb->dst; + const struct dst_entry *dst = skb_dst(skb); return (info->id == (dst->tclassid & info->mask)) ^ info->invert; } diff --git a/net/netfilter/xt_socket.c b/net/netfilter/xt_socket.c index 1acc089be7e9..ebf00ad5b194 100644 --- a/net/netfilter/xt_socket.c +++ b/net/netfilter/xt_socket.c @@ -22,6 +22,8 @@ #include #include +#include + #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) #define XT_SOCKET_HAVE_CONNTRACK 1 #include @@ -86,7 +88,8 @@ extract_icmp_fields(const struct sk_buff *skb, static bool -socket_mt(const struct sk_buff *skb, const struct xt_match_param *par) +socket_match(const struct sk_buff *skb, const struct xt_match_param *par, + const struct xt_socket_mtinfo1 *info) { const struct iphdr *iph = ip_hdr(skb); struct udphdr _hdr, *hp = NULL; @@ -141,10 +144,24 @@ socket_mt(const struct sk_buff *skb, const struct xt_match_param *par) sk = nf_tproxy_get_sock_v4(dev_net(skb->dev), protocol, saddr, daddr, sport, dport, par->in, false); if (sk != NULL) { - bool wildcard = (sk->sk_state != TCP_TIME_WAIT && inet_sk(sk)->rcv_saddr == 0); + bool wildcard; + bool transparent = true; + + /* Ignore sockets listening on INADDR_ANY */ + wildcard = (sk->sk_state != TCP_TIME_WAIT && + inet_sk(sk)->rcv_saddr == 0); + + /* Ignore non-transparent sockets, + if XT_SOCKET_TRANSPARENT is used */ + if (info && info->flags & XT_SOCKET_TRANSPARENT) + transparent = ((sk->sk_state != TCP_TIME_WAIT && + inet_sk(sk)->transparent) || + (sk->sk_state == TCP_TIME_WAIT && + inet_twsk(sk)->tw_transparent)); nf_tproxy_put_sock(sk); - if (wildcard) + + if (wildcard || !transparent) sk = NULL; } @@ -157,23 +174,47 @@ socket_mt(const struct sk_buff *skb, const struct xt_match_param *par) return (sk != NULL); } -static struct xt_match socket_mt_reg __read_mostly = { - .name = "socket", - .family = AF_INET, - .match = socket_mt, - .hooks = 1 << NF_INET_PRE_ROUTING, - .me = THIS_MODULE, +static bool +socket_mt_v0(const struct sk_buff *skb, const struct xt_match_param *par) +{ + return socket_match(skb, par, NULL); +} + +static bool +socket_mt_v1(const struct sk_buff *skb, const struct xt_match_param *par) +{ + return socket_match(skb, par, par->matchinfo); +} + +static struct xt_match socket_mt_reg[] __read_mostly = { + { + .name = "socket", + .revision = 0, + .family = NFPROTO_IPV4, + .match = socket_mt_v0, + .hooks = 1 << NF_INET_PRE_ROUTING, + .me = THIS_MODULE, + }, + { + .name = "socket", + .revision = 1, + .family = NFPROTO_IPV4, + .match = socket_mt_v1, + .matchsize = sizeof(struct xt_socket_mtinfo1), + .hooks = 1 << NF_INET_PRE_ROUTING, + .me = THIS_MODULE, + }, }; static int __init socket_mt_init(void) { nf_defrag_ipv4_enable(); - return xt_register_match(&socket_mt_reg); + return xt_register_matches(socket_mt_reg, ARRAY_SIZE(socket_mt_reg)); } static void __exit socket_mt_exit(void) { - xt_unregister_match(&socket_mt_reg); + xt_unregister_matches(socket_mt_reg, ARRAY_SIZE(socket_mt_reg)); } module_init(socket_mt_init); diff --git a/net/netlabel/netlabel_cipso_v4.c b/net/netlabel/netlabel_cipso_v4.c index bf1ab1a6790d..e639298bc9c8 100644 --- a/net/netlabel/netlabel_cipso_v4.c +++ b/net/netlabel/netlabel_cipso_v4.c @@ -785,18 +785,6 @@ static struct genl_ops netlbl_cipsov4_ops[] = { */ int __init netlbl_cipsov4_genl_init(void) { - int ret_val, i; - - ret_val = genl_register_family(&netlbl_cipsov4_gnl_family); - if (ret_val != 0) - return ret_val; - - for (i = 0; i < ARRAY_SIZE(netlbl_cipsov4_ops); i++) { - ret_val = genl_register_ops(&netlbl_cipsov4_gnl_family, - &netlbl_cipsov4_ops[i]); - if (ret_val != 0) - return ret_val; - } - - return 0; + return genl_register_family_with_ops(&netlbl_cipsov4_gnl_family, + netlbl_cipsov4_ops, ARRAY_SIZE(netlbl_cipsov4_ops)); } diff --git a/net/netlabel/netlabel_mgmt.c b/net/netlabel/netlabel_mgmt.c index 1821c5d50fb8..8203623e65ad 100644 --- a/net/netlabel/netlabel_mgmt.c +++ b/net/netlabel/netlabel_mgmt.c @@ -779,18 +779,6 @@ static struct genl_ops netlbl_mgmt_genl_ops[] = { */ int __init netlbl_mgmt_genl_init(void) { - int ret_val, i; - - ret_val = genl_register_family(&netlbl_mgmt_gnl_family); - if (ret_val != 0) - return ret_val; - - for (i = 0; i < ARRAY_SIZE(netlbl_mgmt_genl_ops); i++) { - ret_val = genl_register_ops(&netlbl_mgmt_gnl_family, - &netlbl_mgmt_genl_ops[i]); - if (ret_val != 0) - return ret_val; - } - - return 0; + return genl_register_family_with_ops(&netlbl_mgmt_gnl_family, + netlbl_mgmt_genl_ops, ARRAY_SIZE(netlbl_mgmt_genl_ops)); } diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c index f3c5c68c6848..fb357f010189 100644 --- a/net/netlabel/netlabel_unlabeled.c +++ b/net/netlabel/netlabel_unlabeled.c @@ -1478,20 +1478,8 @@ static struct genl_ops netlbl_unlabel_genl_ops[] = { */ int __init netlbl_unlabel_genl_init(void) { - int ret_val, i; - - ret_val = genl_register_family(&netlbl_unlabel_gnl_family); - if (ret_val != 0) - return ret_val; - - for (i = 0; i < ARRAY_SIZE(netlbl_unlabel_genl_ops); i++) { - ret_val = genl_register_ops(&netlbl_unlabel_gnl_family, - &netlbl_unlabel_genl_ops[i]); - if (ret_val != 0) - return ret_val; - } - - return 0; + return genl_register_family_with_ops(&netlbl_unlabel_gnl_family, + netlbl_unlabel_genl_ops, ARRAY_SIZE(netlbl_unlabel_genl_ops)); } /* diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 8b6bbb3032b0..2936fa3b6dc8 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1914,8 +1914,8 @@ static int netlink_seq_show(struct seq_file *seq, void *v) s->sk_protocol, nlk->pid, nlk->groups ? (u32)nlk->groups[0] : 0, - atomic_read(&s->sk_rmem_alloc), - atomic_read(&s->sk_wmem_alloc), + sk_rmem_alloc_get(s), + sk_wmem_alloc_get(s), nlk->cb, atomic_read(&s->sk_refcnt), atomic_read(&s->sk_drops) diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index 1d3dd30099df..eed4c6a8afc0 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -383,6 +383,52 @@ errout: return err; } +/** + * genl_register_family_with_ops - register a generic netlink family + * @family: generic netlink family + * @ops: operations to be registered + * @n_ops: number of elements to register + * + * Registers the specified family and operations from the specified table. + * Only one family may be registered with the same family name or identifier. + * + * The family id may equal GENL_ID_GENERATE causing an unique id to + * be automatically generated and assigned. + * + * Either a doit or dumpit callback must be specified for every registered + * operation or the function will fail. Only one operation structure per + * command identifier may be registered. + * + * See include/net/genetlink.h for more documenation on the operations + * structure. + * + * This is equivalent to calling genl_register_family() followed by + * genl_register_ops() for every operation entry in the table taking + * care to unregister the family on error path. + * + * Return 0 on success or a negative error code. + */ +int genl_register_family_with_ops(struct genl_family *family, + struct genl_ops *ops, size_t n_ops) +{ + int err, i; + + err = genl_register_family(family); + if (err) + return err; + + for (i = 0; i < n_ops; ++i, ++ops) { + err = genl_register_ops(family, ops); + if (err) + goto err_out; + } + return 0; +err_out: + genl_unregister_family(family); + return err; +} +EXPORT_SYMBOL(genl_register_family_with_ops); + /** * genl_unregister_family - unregister generic netlink family * @family: generic netlink family diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c index 3be0e016ab7d..ce51ce012cda 100644 --- a/net/netrom/af_netrom.c +++ b/net/netrom/af_netrom.c @@ -286,8 +286,7 @@ void nr_destroy_socket(struct sock *sk) kfree_skb(skb); } - if (atomic_read(&sk->sk_wmem_alloc) || - atomic_read(&sk->sk_rmem_alloc)) { + if (sk_has_allocations(sk)) { /* Defer: outstanding buffers */ sk->sk_timer.function = nr_destroy_timer; sk->sk_timer.expires = jiffies + 2 * HZ; @@ -1206,7 +1205,7 @@ static int nr_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) long amount; lock_sock(sk); - amount = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc); + amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk); if (amount < 0) amount = 0; release_sock(sk); @@ -1342,8 +1341,8 @@ static int nr_info_show(struct seq_file *seq, void *v) nr->n2count, nr->n2, nr->window, - atomic_read(&s->sk_wmem_alloc), - atomic_read(&s->sk_rmem_alloc), + sk_wmem_alloc_get(s), + sk_rmem_alloc_get(s), s->sk_socket ? SOCK_INODE(s->sk_socket)->i_ino : 0L); bh_unlock_sock(s); diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index f546e81acc45..ebe5718baa31 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -39,6 +39,7 @@ * will simply extend the hardware address * byte arrays at the end of sockaddr_ll * and packet_mreq. + * Johann Baudy : Added TX RING. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -157,7 +158,25 @@ struct packet_mreq_max }; #ifdef CONFIG_PACKET_MMAP -static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing); +static int packet_set_ring(struct sock *sk, struct tpacket_req *req, + int closing, int tx_ring); + +struct packet_ring_buffer { + char * *pg_vec; + unsigned int head; + unsigned int frames_per_block; + unsigned int frame_size; + unsigned int frame_max; + + unsigned int pg_vec_order; + unsigned int pg_vec_pages; + unsigned int pg_vec_len; + + atomic_t pending; +}; + +struct packet_sock; +static int tpacket_snd(struct packet_sock *po, struct msghdr *msg); #endif static void packet_flush_mclist(struct sock *sk); @@ -167,11 +186,8 @@ struct packet_sock { struct sock sk; struct tpacket_stats stats; #ifdef CONFIG_PACKET_MMAP - char * *pg_vec; - unsigned int head; - unsigned int frames_per_block; - unsigned int frame_size; - unsigned int frame_max; + struct packet_ring_buffer rx_ring; + struct packet_ring_buffer tx_ring; int copy_thresh; #endif struct packet_type prot_hook; @@ -185,12 +201,10 @@ struct packet_sock { struct packet_mclist *mclist; #ifdef CONFIG_PACKET_MMAP atomic_t mapped; - unsigned int pg_vec_order; - unsigned int pg_vec_pages; - unsigned int pg_vec_len; enum tpacket_versions tp_version; unsigned int tp_hdrlen; unsigned int tp_reserve; + unsigned int tp_loss:1; #endif }; @@ -206,35 +220,6 @@ struct packet_skb_cb { #ifdef CONFIG_PACKET_MMAP -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; - - 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 { @@ -247,12 +232,88 @@ static void __packet_set_status(struct packet_sock *po, void *frame, int status) switch (po->tp_version) { case TPACKET_V1: h.h1->tp_status = status; + flush_dcache_page(virt_to_page(&h.h1->tp_status)); break; case TPACKET_V2: h.h2->tp_status = status; + flush_dcache_page(virt_to_page(&h.h2->tp_status)); break; + default: + printk(KERN_ERR "TPACKET version not supported\n"); + BUG(); + } + + smp_wmb(); +} + +static int __packet_get_status(struct packet_sock *po, void *frame) +{ + union { + struct tpacket_hdr *h1; + struct tpacket2_hdr *h2; + void *raw; + } h; + + smp_rmb(); + + h.raw = frame; + switch (po->tp_version) { + case TPACKET_V1: + flush_dcache_page(virt_to_page(&h.h1->tp_status)); + return h.h1->tp_status; + case TPACKET_V2: + flush_dcache_page(virt_to_page(&h.h2->tp_status)); + return h.h2->tp_status; + default: + printk(KERN_ERR "TPACKET version not supported\n"); + BUG(); + return 0; } } + +static void *packet_lookup_frame(struct packet_sock *po, + struct packet_ring_buffer *rb, + unsigned int position, + int status) +{ + unsigned int pg_vec_pos, frame_offset; + union { + struct tpacket_hdr *h1; + struct tpacket2_hdr *h2; + void *raw; + } h; + + pg_vec_pos = position / rb->frames_per_block; + frame_offset = position % rb->frames_per_block; + + h.raw = rb->pg_vec[pg_vec_pos] + (frame_offset * rb->frame_size); + + if (status != __packet_get_status(po, h.raw)) + return NULL; + + return h.raw; +} + +static inline void *packet_current_frame(struct packet_sock *po, + struct packet_ring_buffer *rb, + int status) +{ + return packet_lookup_frame(po, rb, rb->head, status); +} + +static inline void *packet_previous_frame(struct packet_sock *po, + struct packet_ring_buffer *rb, + int status) +{ + unsigned int previous = rb->head ? rb->head - 1 : rb->frame_max; + return packet_lookup_frame(po, rb, previous, status); +} + +static inline void packet_increment_head(struct packet_ring_buffer *buff) +{ + buff->head = buff->head != buff->frame_max ? buff->head+1 : 0; +} + #endif static inline struct packet_sock *pkt_sk(struct sock *sk) @@ -311,8 +372,7 @@ static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev, struct goto oom; /* drop any routing info */ - dst_release(skb->dst); - skb->dst = NULL; + skb_dst_drop(skb); /* drop conntrack reference */ nf_reset(skb); @@ -560,8 +620,7 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet skb_set_owner_r(skb, sk); skb->dev = NULL; - dst_release(skb->dst); - skb->dst = NULL; + skb_dst_drop(skb); /* drop conntrack reference */ nf_reset(skb); @@ -648,7 +707,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe macoff = netoff - maclen; } - if (macoff + snaplen > po->frame_size) { + if (macoff + snaplen > po->rx_ring.frame_size) { if (po->copy_thresh && atomic_read(&sk->sk_rmem_alloc) + skb->truesize < (unsigned)sk->sk_rcvbuf) { @@ -661,16 +720,16 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe if (copy_skb) skb_set_owner_r(copy_skb, sk); } - snaplen = po->frame_size - macoff; + snaplen = po->rx_ring.frame_size - macoff; if ((int)snaplen < 0) snaplen = 0; } spin_lock(&sk->sk_receive_queue.lock); - h.raw = packet_lookup_frame(po, po->head, TP_STATUS_KERNEL); + h.raw = packet_current_frame(po, &po->rx_ring, TP_STATUS_KERNEL); if (!h.raw) goto ring_is_full; - po->head = po->head != po->frame_max ? po->head+1 : 0; + packet_increment_head(&po->rx_ring); po->stats.tp_packets++; if (copy_skb) { status |= TP_STATUS_COPY; @@ -727,7 +786,6 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe __packet_set_status(po, h.raw, status); smp_mb(); - { struct page *p_start, *p_end; u8 *h_end = h.raw + macoff + snaplen - 1; @@ -760,10 +818,249 @@ ring_is_full: goto drop_n_restore; } +static void tpacket_destruct_skb(struct sk_buff *skb) +{ + struct packet_sock *po = pkt_sk(skb->sk); + void * ph; + + BUG_ON(skb == NULL); + + if (likely(po->tx_ring.pg_vec)) { + ph = skb_shinfo(skb)->destructor_arg; + BUG_ON(__packet_get_status(po, ph) != TP_STATUS_SENDING); + BUG_ON(atomic_read(&po->tx_ring.pending) == 0); + atomic_dec(&po->tx_ring.pending); + __packet_set_status(po, ph, TP_STATUS_AVAILABLE); + } + + sock_wfree(skb); +} + +static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff * skb, + void * frame, struct net_device *dev, int size_max, + __be16 proto, unsigned char * addr) +{ + union { + struct tpacket_hdr *h1; + struct tpacket2_hdr *h2; + void *raw; + } ph; + int to_write, offset, len, tp_len, nr_frags, len_max; + struct socket *sock = po->sk.sk_socket; + struct page *page; + void *data; + int err; + + ph.raw = frame; + + skb->protocol = proto; + skb->dev = dev; + skb->priority = po->sk.sk_priority; + skb_shinfo(skb)->destructor_arg = ph.raw; + + switch (po->tp_version) { + case TPACKET_V2: + tp_len = ph.h2->tp_len; + break; + default: + tp_len = ph.h1->tp_len; + break; + } + if (unlikely(tp_len > size_max)) { + printk(KERN_ERR "packet size is too long (%d > %d)\n", + tp_len, size_max); + return -EMSGSIZE; + } + + skb_reserve(skb, LL_RESERVED_SPACE(dev)); + skb_reset_network_header(skb); + + data = ph.raw + po->tp_hdrlen - sizeof(struct sockaddr_ll); + to_write = tp_len; + + if (sock->type == SOCK_DGRAM) { + err = dev_hard_header(skb, dev, ntohs(proto), addr, + NULL, tp_len); + if (unlikely(err < 0)) + return -EINVAL; + } else if (dev->hard_header_len ) { + /* net device doesn't like empty head */ + if (unlikely(tp_len <= dev->hard_header_len)) { + printk(KERN_ERR "packet size is too short " + "(%d < %d)\n", tp_len, + dev->hard_header_len); + return -EINVAL; + } + + skb_push(skb, dev->hard_header_len); + err = skb_store_bits(skb, 0, data, + dev->hard_header_len); + if (unlikely(err)) + return err; + + data += dev->hard_header_len; + to_write -= dev->hard_header_len; + } + + err = -EFAULT; + page = virt_to_page(data); + offset = offset_in_page(data); + len_max = PAGE_SIZE - offset; + len = ((to_write > len_max) ? len_max : to_write); + + skb->data_len = to_write; + skb->len += to_write; + skb->truesize += to_write; + atomic_add(to_write, &po->sk.sk_wmem_alloc); + + while (likely(to_write)) { + nr_frags = skb_shinfo(skb)->nr_frags; + + if (unlikely(nr_frags >= MAX_SKB_FRAGS)) { + printk(KERN_ERR "Packet exceed the number " + "of skb frags(%lu)\n", + MAX_SKB_FRAGS); + return -EFAULT; + } + + flush_dcache_page(page); + get_page(page); + skb_fill_page_desc(skb, + nr_frags, + page++, offset, len); + to_write -= len; + offset = 0; + len_max = PAGE_SIZE; + len = ((to_write > len_max) ? len_max : to_write); + } + + return tp_len; +} + +static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) +{ + struct socket *sock; + struct sk_buff *skb; + struct net_device *dev; + __be16 proto; + int ifindex, err, reserve = 0; + void * ph; + struct sockaddr_ll *saddr=(struct sockaddr_ll *)msg->msg_name; + int tp_len, size_max; + unsigned char *addr; + int len_sum = 0; + int status = 0; + + sock = po->sk.sk_socket; + + mutex_lock(&po->pg_vec_lock); + + err = -EBUSY; + if (saddr == NULL) { + ifindex = po->ifindex; + proto = po->num; + addr = NULL; + } else { + err = -EINVAL; + if (msg->msg_namelen < sizeof(struct sockaddr_ll)) + goto out; + if (msg->msg_namelen < (saddr->sll_halen + + offsetof(struct sockaddr_ll, + sll_addr))) + goto out; + ifindex = saddr->sll_ifindex; + proto = saddr->sll_protocol; + addr = saddr->sll_addr; + } + + dev = dev_get_by_index(sock_net(&po->sk), ifindex); + err = -ENXIO; + if (unlikely(dev == NULL)) + goto out; + + reserve = dev->hard_header_len; + + err = -ENETDOWN; + if (unlikely(!(dev->flags & IFF_UP))) + goto out_put; + + size_max = po->tx_ring.frame_size + - sizeof(struct skb_shared_info) + - po->tp_hdrlen + - LL_ALLOCATED_SPACE(dev) + - sizeof(struct sockaddr_ll); + + if (size_max > dev->mtu + reserve) + size_max = dev->mtu + reserve; + + do { + ph = packet_current_frame(po, &po->tx_ring, + TP_STATUS_SEND_REQUEST); + + if (unlikely(ph == NULL)) { + schedule(); + continue; + } + + status = TP_STATUS_SEND_REQUEST; + skb = sock_alloc_send_skb(&po->sk, + LL_ALLOCATED_SPACE(dev) + + sizeof(struct sockaddr_ll), + 0, &err); + + if (unlikely(skb == NULL)) + goto out_status; + + tp_len = tpacket_fill_skb(po, skb, ph, dev, size_max, proto, + addr); + + if (unlikely(tp_len < 0)) { + if (po->tp_loss) { + __packet_set_status(po, ph, + TP_STATUS_AVAILABLE); + packet_increment_head(&po->tx_ring); + kfree_skb(skb); + continue; + } else { + status = TP_STATUS_WRONG_FORMAT; + err = tp_len; + goto out_status; + } + } + + skb->destructor = tpacket_destruct_skb; + __packet_set_status(po, ph, TP_STATUS_SENDING); + atomic_inc(&po->tx_ring.pending); + + status = TP_STATUS_SEND_REQUEST; + err = dev_queue_xmit(skb); + if (unlikely(err > 0 && (err = net_xmit_errno(err)) != 0)) + goto out_xmit; + packet_increment_head(&po->tx_ring); + len_sum += tp_len; + } + while (likely((ph != NULL) || ((!(msg->msg_flags & MSG_DONTWAIT)) + && (atomic_read(&po->tx_ring.pending)))) + ); + + err = len_sum; + goto out_put; + +out_xmit: + skb->destructor = sock_wfree; + atomic_dec(&po->tx_ring.pending); +out_status: + __packet_set_status(po, ph, status); + kfree_skb(skb); +out_put: + dev_put(dev); +out: + mutex_unlock(&po->pg_vec_lock); + return err; +} #endif - -static int packet_sendmsg(struct kiocb *iocb, struct socket *sock, +static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len) { struct sock *sk = sock->sk; @@ -854,6 +1151,19 @@ out: return err; } +static int packet_sendmsg(struct kiocb *iocb, struct socket *sock, + struct msghdr *msg, size_t len) +{ +#ifdef CONFIG_PACKET_MMAP + struct sock *sk = sock->sk; + struct packet_sock *po = pkt_sk(sk); + if (po->tx_ring.pg_vec) + return tpacket_snd(po, msg); + else +#endif + return packet_snd(sock, msg, len); +} + /* * Close a PACKET socket. This is fairly simple. We immediately go * to 'closed' state and remove our protocol entry in the device list. @@ -864,6 +1174,9 @@ static int packet_release(struct socket *sock) struct sock *sk = sock->sk; struct packet_sock *po; struct net *net; +#ifdef CONFIG_PACKET_MMAP + struct tpacket_req req; +#endif if (!sk) return 0; @@ -893,11 +1206,13 @@ static int packet_release(struct socket *sock) packet_flush_mclist(sk); #ifdef CONFIG_PACKET_MMAP - if (po->pg_vec) { - struct tpacket_req req; - memset(&req, 0, sizeof(req)); - packet_set_ring(sk, &req, 1); - } + memset(&req, 0, sizeof(req)); + + if (po->rx_ring.pg_vec) + packet_set_ring(sk, &req, 1, 0); + + if (po->tx_ring.pg_vec) + packet_set_ring(sk, &req, 1, 1); #endif /* @@ -1253,9 +1568,9 @@ static int packet_dev_mc(struct net_device *dev, struct packet_mclist *i, switch (i->type) { case PACKET_MR_MULTICAST: if (what > 0) - dev_mc_add(dev, i->addr, i->alen, 0); + return dev_mc_add(dev, i->addr, i->alen, 0); else - dev_mc_delete(dev, i->addr, i->alen, 0); + return dev_mc_delete(dev, i->addr, i->alen, 0); break; case PACKET_MR_PROMISC: return dev_set_promiscuity(dev, what); @@ -1263,6 +1578,12 @@ static int packet_dev_mc(struct net_device *dev, struct packet_mclist *i, case PACKET_MR_ALLMULTI: return dev_set_allmulti(dev, what); break; + case PACKET_MR_UNICAST: + if (what > 0) + return dev_unicast_add(dev, i->addr); + else + return dev_unicast_delete(dev, i->addr); + break; default:; } return 0; @@ -1391,7 +1712,7 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv if (level != SOL_PACKET) return -ENOPROTOOPT; - switch(optname) { + switch (optname) { case PACKET_ADD_MEMBERSHIP: case PACKET_DROP_MEMBERSHIP: { @@ -1415,6 +1736,7 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv #ifdef CONFIG_PACKET_MMAP case PACKET_RX_RING: + case PACKET_TX_RING: { struct tpacket_req req; @@ -1422,7 +1744,7 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv return -EINVAL; if (copy_from_user(&req,optval,sizeof(req))) return -EFAULT; - return packet_set_ring(sk, &req, 0); + return packet_set_ring(sk, &req, 0, optname == PACKET_TX_RING); } case PACKET_COPY_THRESH: { @@ -1442,7 +1764,7 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv if (optlen != sizeof(val)) return -EINVAL; - if (po->pg_vec) + if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) return -EBUSY; if (copy_from_user(&val, optval, sizeof(val))) return -EFAULT; @@ -1461,13 +1783,26 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv if (optlen != sizeof(val)) return -EINVAL; - if (po->pg_vec) + if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) return -EBUSY; if (copy_from_user(&val, optval, sizeof(val))) return -EFAULT; po->tp_reserve = val; return 0; } + case PACKET_LOSS: + { + unsigned int val; + + if (optlen != sizeof(val)) + return -EINVAL; + if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) + return -EBUSY; + if (copy_from_user(&val, optval, sizeof(val))) + return -EFAULT; + po->tp_loss = !!val; + return 0; + } #endif case PACKET_AUXDATA: { @@ -1517,7 +1852,7 @@ static int packet_getsockopt(struct socket *sock, int level, int optname, if (len < 0) return -EINVAL; - switch(optname) { + switch (optname) { case PACKET_STATISTICS: if (len > sizeof(struct tpacket_stats)) len = sizeof(struct tpacket_stats); @@ -1573,6 +1908,12 @@ static int packet_getsockopt(struct socket *sock, int level, int optname, val = po->tp_reserve; data = &val; break; + case PACKET_LOSS: + if (len > sizeof(unsigned int)) + len = sizeof(unsigned int); + val = po->tp_loss; + data = &val; + break; #endif default: return -ENOPROTOOPT; @@ -1643,10 +1984,11 @@ static int packet_ioctl(struct socket *sock, unsigned int cmd, { struct sock *sk = sock->sk; - switch(cmd) { + switch (cmd) { case SIOCOUTQ: { - int amount = atomic_read(&sk->sk_wmem_alloc); + int amount = sk_wmem_alloc_get(sk); + return put_user(amount, (int __user *)arg); } case SIOCINQ: @@ -1705,13 +2047,17 @@ static unsigned int packet_poll(struct file * file, struct socket *sock, unsigned int mask = datagram_poll(file, sock, wait); spin_lock_bh(&sk->sk_receive_queue.lock); - if (po->pg_vec) { - unsigned last = po->head ? po->head-1 : po->frame_max; - - if (packet_lookup_frame(po, last, TP_STATUS_USER)) + if (po->rx_ring.pg_vec) { + if (!packet_previous_frame(po, &po->rx_ring, TP_STATUS_KERNEL)) mask |= POLLIN | POLLRDNORM; } spin_unlock_bh(&sk->sk_receive_queue.lock); + spin_lock_bh(&sk->sk_write_queue.lock); + if (po->tx_ring.pg_vec) { + if (packet_current_frame(po, &po->tx_ring, TP_STATUS_AVAILABLE)) + mask |= POLLOUT | POLLWRNORM; + } + spin_unlock_bh(&sk->sk_write_queue.lock); return mask; } @@ -1788,21 +2134,33 @@ out_free_pgvec: goto out; } -static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing) +static int packet_set_ring(struct sock *sk, struct tpacket_req *req, + int closing, int tx_ring) { char **pg_vec = NULL; struct packet_sock *po = pkt_sk(sk); int was_running, order = 0; + struct packet_ring_buffer *rb; + struct sk_buff_head *rb_queue; __be16 num; - int err = 0; + int err; + + rb = tx_ring ? &po->tx_ring : &po->rx_ring; + rb_queue = tx_ring ? &sk->sk_write_queue : &sk->sk_receive_queue; + + err = -EBUSY; + if (!closing) { + if (atomic_read(&po->mapped)) + goto out; + if (atomic_read(&rb->pending)) + goto out; + } if (req->tp_block_nr) { - int i; - /* Sanity tests and some calculations */ - - if (unlikely(po->pg_vec)) - return -EBUSY; + err = -EBUSY; + if (unlikely(rb->pg_vec)) + goto out; switch (po->tp_version) { case TPACKET_V1: @@ -1813,42 +2171,35 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing break; } + err = -EINVAL; if (unlikely((int)req->tp_block_size <= 0)) - return -EINVAL; + goto out; if (unlikely(req->tp_block_size & (PAGE_SIZE - 1))) - return -EINVAL; + goto out; if (unlikely(req->tp_frame_size < po->tp_hdrlen + - po->tp_reserve)) - return -EINVAL; + po->tp_reserve)) + goto out; if (unlikely(req->tp_frame_size & (TPACKET_ALIGNMENT - 1))) - return -EINVAL; + goto out; - po->frames_per_block = req->tp_block_size/req->tp_frame_size; - if (unlikely(po->frames_per_block <= 0)) - return -EINVAL; - if (unlikely((po->frames_per_block * req->tp_block_nr) != - req->tp_frame_nr)) - return -EINVAL; + rb->frames_per_block = req->tp_block_size/req->tp_frame_size; + if (unlikely(rb->frames_per_block <= 0)) + goto out; + if (unlikely((rb->frames_per_block * req->tp_block_nr) != + req->tp_frame_nr)) + goto out; err = -ENOMEM; order = get_order(req->tp_block_size); pg_vec = alloc_pg_vec(req, order); if (unlikely(!pg_vec)) goto out; - - for (i = 0; i < req->tp_block_nr; i++) { - void *ptr = pg_vec[i]; - int k; - - for (k = 0; k < po->frames_per_block; k++) { - __packet_set_status(po, ptr, TP_STATUS_KERNEL); - ptr += req->tp_frame_size; - } - } - /* Done */ - } else { + } + /* Done */ + else { + err = -EINVAL; if (unlikely(req->tp_frame_nr)) - return -EINVAL; + goto out; } lock_sock(sk); @@ -1872,23 +2223,24 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing if (closing || atomic_read(&po->mapped) == 0) { err = 0; #define XC(a, b) ({ __typeof__ ((a)) __t; __t = (a); (a) = (b); __t; }) + spin_lock_bh(&rb_queue->lock); + pg_vec = XC(rb->pg_vec, pg_vec); + rb->frame_max = (req->tp_frame_nr - 1); + rb->head = 0; + rb->frame_size = req->tp_frame_size; + spin_unlock_bh(&rb_queue->lock); - spin_lock_bh(&sk->sk_receive_queue.lock); - pg_vec = XC(po->pg_vec, pg_vec); - po->frame_max = (req->tp_frame_nr - 1); - po->head = 0; - po->frame_size = req->tp_frame_size; - spin_unlock_bh(&sk->sk_receive_queue.lock); + order = XC(rb->pg_vec_order, order); + req->tp_block_nr = XC(rb->pg_vec_len, req->tp_block_nr); - order = XC(po->pg_vec_order, order); - req->tp_block_nr = XC(po->pg_vec_len, req->tp_block_nr); - - po->pg_vec_pages = req->tp_block_size/PAGE_SIZE; - po->prot_hook.func = po->pg_vec ? tpacket_rcv : packet_rcv; - skb_queue_purge(&sk->sk_receive_queue); + rb->pg_vec_pages = req->tp_block_size/PAGE_SIZE; + po->prot_hook.func = (po->rx_ring.pg_vec) ? + tpacket_rcv : packet_rcv; + skb_queue_purge(rb_queue); #undef XC if (atomic_read(&po->mapped)) - printk(KERN_DEBUG "packet_mmap: vma is busy: %d\n", atomic_read(&po->mapped)); + printk(KERN_DEBUG "packet_mmap: vma is busy: %d\n", + atomic_read(&po->mapped)); } mutex_unlock(&po->pg_vec_lock); @@ -1909,11 +2261,13 @@ out: return err; } -static int packet_mmap(struct file *file, struct socket *sock, struct vm_area_struct *vma) +static int packet_mmap(struct file *file, struct socket *sock, + struct vm_area_struct *vma) { struct sock *sk = sock->sk; struct packet_sock *po = pkt_sk(sk); - unsigned long size; + unsigned long size, expected_size; + struct packet_ring_buffer *rb; unsigned long start; int err = -EINVAL; int i; @@ -1921,26 +2275,43 @@ static int packet_mmap(struct file *file, struct socket *sock, struct vm_area_st if (vma->vm_pgoff) return -EINVAL; - size = vma->vm_end - vma->vm_start; - mutex_lock(&po->pg_vec_lock); - if (po->pg_vec == NULL) + + expected_size = 0; + for (rb = &po->rx_ring; rb <= &po->tx_ring; rb++) { + if (rb->pg_vec) { + expected_size += rb->pg_vec_len + * rb->pg_vec_pages + * PAGE_SIZE; + } + } + + if (expected_size == 0) goto out; - if (size != po->pg_vec_len*po->pg_vec_pages*PAGE_SIZE) + + size = vma->vm_end - vma->vm_start; + if (size != expected_size) goto out; start = vma->vm_start; - for (i = 0; i < po->pg_vec_len; i++) { - struct page *page = virt_to_page(po->pg_vec[i]); - int pg_num; + for (rb = &po->rx_ring; rb <= &po->tx_ring; rb++) { + if (rb->pg_vec == NULL) + continue; - for (pg_num = 0; pg_num < po->pg_vec_pages; pg_num++, page++) { - err = vm_insert_page(vma, start, page); - if (unlikely(err)) - goto out; - start += PAGE_SIZE; + for (i = 0; i < rb->pg_vec_len; i++) { + struct page *page = virt_to_page(rb->pg_vec[i]); + int pg_num; + + for (pg_num = 0; pg_num < rb->pg_vec_pages; + pg_num++,page++) { + err = vm_insert_page(vma, start, page); + if (unlikely(err)) + goto out; + start += PAGE_SIZE; + } } } + atomic_inc(&po->mapped); vma->vm_ops = &packet_mmap_ops; err = 0; diff --git a/net/phonet/pep-gprs.c b/net/phonet/pep-gprs.c index 4aa888584d20..480839dfc560 100644 --- a/net/phonet/pep-gprs.c +++ b/net/phonet/pep-gprs.c @@ -115,10 +115,10 @@ static int gprs_recv(struct gprs_dev *gp, struct sk_buff *skb) rskb->truesize += rskb->len; /* Avoid nested fragments */ - for (fs = skb_shinfo(skb)->frag_list; fs; fs = fs->next) + skb_walk_frags(skb, fs) flen += fs->len; skb->next = skb_shinfo(skb)->frag_list; - skb_shinfo(skb)->frag_list = NULL; + skb_frag_list_init(skb); skb->len -= flen; skb->data_len -= flen; skb->truesize -= flen; @@ -212,8 +212,9 @@ static int gprs_xmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_bytes += len; } - if (!pep_writeable(sk)) - netif_stop_queue(dev); + netif_stop_queue(dev); + if (pep_writeable(sk)) + netif_wake_queue(dev); return 0; } diff --git a/net/phonet/pep.c b/net/phonet/pep.c index 8ad2b5333881..eef833ea6d7b 100644 --- a/net/phonet/pep.c +++ b/net/phonet/pep.c @@ -940,10 +940,10 @@ int pep_write(struct sock *sk, struct sk_buff *skb) rskb->truesize += rskb->len; /* Avoid nested fragments */ - for (fs = skb_shinfo(skb)->frag_list; fs; fs = fs->next) + skb_walk_frags(skb, fs) flen += fs->len; skb->next = skb_shinfo(skb)->frag_list; - skb_shinfo(skb)->frag_list = NULL; + skb_frag_list_init(skb); skb->len -= flen; skb->data_len -= flen; skb->truesize -= flen; diff --git a/net/rds/af_rds.c b/net/rds/af_rds.c index 20cf16fc572f..b11e7e527864 100644 --- a/net/rds/af_rds.c +++ b/net/rds/af_rds.c @@ -35,7 +35,6 @@ #include #include #include -#include #include #include "rds.h" diff --git a/net/rds/connection.c b/net/rds/connection.c index 273f064930a8..d14445c48304 100644 --- a/net/rds/connection.c +++ b/net/rds/connection.c @@ -148,14 +148,12 @@ static struct rds_connection *__rds_conn_create(__be32 laddr, __be32 faddr, if (conn) goto out; - conn = kmem_cache_alloc(rds_conn_slab, gfp); + conn = kmem_cache_zalloc(rds_conn_slab, gfp); if (conn == NULL) { conn = ERR_PTR(-ENOMEM); goto out; } - memset(conn, 0, sizeof(*conn)); - INIT_HLIST_NODE(&conn->c_hash_node); conn->c_version = RDS_PROTOCOL_3_0; conn->c_laddr = laddr; diff --git a/net/rds/ib.c b/net/rds/ib.c index 4933b380985e..b9bcd32431e1 100644 --- a/net/rds/ib.c +++ b/net/rds/ib.c @@ -224,8 +224,8 @@ static int rds_ib_laddr_check(__be32 addr) * IB and iWARP capable NICs. */ cm_id = rdma_create_id(NULL, NULL, RDMA_PS_TCP); - if (!cm_id) - return -EADDRNOTAVAIL; + if (IS_ERR(cm_id)) + return PTR_ERR(cm_id); memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; diff --git a/net/rds/ib.h b/net/rds/ib.h index 069206cae733..455ae73047fe 100644 --- a/net/rds/ib.h +++ b/net/rds/ib.h @@ -333,7 +333,7 @@ int rds_ib_xmit_rdma(struct rds_connection *conn, struct rds_rdma_op *op); void rds_ib_send_add_credits(struct rds_connection *conn, unsigned int credits); void rds_ib_advertise_credits(struct rds_connection *conn, unsigned int posted); int rds_ib_send_grab_credits(struct rds_ib_connection *ic, u32 wanted, - u32 *adv_credits, int need_posted); + u32 *adv_credits, int need_posted, int max_posted); /* ib_stats.c */ DECLARE_PER_CPU(struct rds_ib_statistics, rds_ib_stats); diff --git a/net/rds/ib_recv.c b/net/rds/ib_recv.c index 36d931573ff4..5709bad28329 100644 --- a/net/rds/ib_recv.c +++ b/net/rds/ib_recv.c @@ -524,7 +524,7 @@ void rds_ib_attempt_ack(struct rds_ib_connection *ic) } /* Can we get a send credit? */ - if (!rds_ib_send_grab_credits(ic, 1, &adv_credits, 0)) { + if (!rds_ib_send_grab_credits(ic, 1, &adv_credits, 0, RDS_MAX_ADV_CREDIT)) { rds_ib_stats_inc(s_ib_tx_throttle); clear_bit(IB_ACK_IN_FLIGHT, &ic->i_ack_flags); return; diff --git a/net/rds/ib_ring.c b/net/rds/ib_ring.c index 99a6ccae964c..ff97e8eda858 100644 --- a/net/rds/ib_ring.c +++ b/net/rds/ib_ring.c @@ -137,7 +137,7 @@ int rds_ib_ring_empty(struct rds_ib_work_ring *ring) int rds_ib_ring_low(struct rds_ib_work_ring *ring) { - return __rds_ib_ring_used(ring) <= (ring->w_nr >> 2); + return __rds_ib_ring_used(ring) <= (ring->w_nr >> 1); } /* diff --git a/net/rds/ib_send.c b/net/rds/ib_send.c index cb6c52cb1c4c..23bf830db2d5 100644 --- a/net/rds/ib_send.c +++ b/net/rds/ib_send.c @@ -311,7 +311,7 @@ void rds_ib_send_cq_comp_handler(struct ib_cq *cq, void *context) * and using atomic_cmpxchg when updating the two counters. */ int rds_ib_send_grab_credits(struct rds_ib_connection *ic, - u32 wanted, u32 *adv_credits, int need_posted) + u32 wanted, u32 *adv_credits, int need_posted, int max_posted) { unsigned int avail, posted, got = 0, advertise; long oldval, newval; @@ -351,7 +351,7 @@ try_again: * available. */ if (posted && (got || need_posted)) { - advertise = min_t(unsigned int, posted, RDS_MAX_ADV_CREDIT); + advertise = min_t(unsigned int, posted, max_posted); newval -= IB_SET_POST_CREDITS(advertise); } @@ -498,7 +498,7 @@ int rds_ib_xmit(struct rds_connection *conn, struct rds_message *rm, credit_alloc = work_alloc; if (ic->i_flowctl) { - credit_alloc = rds_ib_send_grab_credits(ic, work_alloc, &posted, 0); + credit_alloc = rds_ib_send_grab_credits(ic, work_alloc, &posted, 0, RDS_MAX_ADV_CREDIT); adv_credits += posted; if (credit_alloc < work_alloc) { rds_ib_ring_unalloc(&ic->i_send_ring, work_alloc - credit_alloc); @@ -506,7 +506,7 @@ int rds_ib_xmit(struct rds_connection *conn, struct rds_message *rm, flow_controlled++; } if (work_alloc == 0) { - rds_ib_ring_unalloc(&ic->i_send_ring, work_alloc); + set_bit(RDS_LL_SEND_FULL, &conn->c_flags); rds_ib_stats_inc(s_ib_tx_throttle); ret = -ENOMEM; goto out; @@ -571,7 +571,7 @@ int rds_ib_xmit(struct rds_connection *conn, struct rds_message *rm, /* * Update adv_credits since we reset the ACK_REQUIRED bit. */ - rds_ib_send_grab_credits(ic, 0, &posted, 1); + rds_ib_send_grab_credits(ic, 0, &posted, 1, RDS_MAX_ADV_CREDIT - adv_credits); adv_credits += posted; BUG_ON(adv_credits > 255); } else if (ic->i_rm != rm) diff --git a/net/rds/info.c b/net/rds/info.c index 1d885535214d..62aeef37aefe 100644 --- a/net/rds/info.c +++ b/net/rds/info.c @@ -188,10 +188,7 @@ int rds_info_getsockopt(struct socket *sock, int optname, char __user *optval, ret = -ENOMEM; goto out; } - down_read(¤t->mm->mmap_sem); - ret = get_user_pages(current, current->mm, start, nr_pages, 1, 0, - pages, NULL); - up_read(¤t->mm->mmap_sem); + ret = get_user_pages_fast(start, nr_pages, 1, pages); if (ret != nr_pages) { if (ret > 0) nr_pages = ret; diff --git a/net/rds/iw.c b/net/rds/iw.c index b732efb5b634..d16e1cbc8e83 100644 --- a/net/rds/iw.c +++ b/net/rds/iw.c @@ -233,8 +233,8 @@ static int rds_iw_laddr_check(__be32 addr) * IB and iWARP capable NICs. */ cm_id = rdma_create_id(NULL, NULL, RDMA_PS_TCP); - if (!cm_id) - return -EADDRNOTAVAIL; + if (IS_ERR(cm_id)) + return PTR_ERR(cm_id); memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; diff --git a/net/rds/iw.h b/net/rds/iw.h index b4fb27252895..0715dde323e7 100644 --- a/net/rds/iw.h +++ b/net/rds/iw.h @@ -361,7 +361,7 @@ int rds_iw_xmit_rdma(struct rds_connection *conn, struct rds_rdma_op *op); void rds_iw_send_add_credits(struct rds_connection *conn, unsigned int credits); void rds_iw_advertise_credits(struct rds_connection *conn, unsigned int posted); int rds_iw_send_grab_credits(struct rds_iw_connection *ic, u32 wanted, - u32 *adv_credits, int need_posted); + u32 *adv_credits, int need_posted, int max_posted); /* ib_stats.c */ DECLARE_PER_CPU(struct rds_iw_statistics, rds_iw_stats); diff --git a/net/rds/iw_recv.c b/net/rds/iw_recv.c index fde470fa50d5..8683f5f66c4b 100644 --- a/net/rds/iw_recv.c +++ b/net/rds/iw_recv.c @@ -524,7 +524,7 @@ void rds_iw_attempt_ack(struct rds_iw_connection *ic) } /* Can we get a send credit? */ - if (!rds_iw_send_grab_credits(ic, 1, &adv_credits, 0)) { + if (!rds_iw_send_grab_credits(ic, 1, &adv_credits, 0, RDS_MAX_ADV_CREDIT)) { rds_iw_stats_inc(s_iw_tx_throttle); clear_bit(IB_ACK_IN_FLIGHT, &ic->i_ack_flags); return; diff --git a/net/rds/iw_ring.c b/net/rds/iw_ring.c index d422d4b5deef..da8e3b63f663 100644 --- a/net/rds/iw_ring.c +++ b/net/rds/iw_ring.c @@ -137,7 +137,7 @@ int rds_iw_ring_empty(struct rds_iw_work_ring *ring) int rds_iw_ring_low(struct rds_iw_work_ring *ring) { - return __rds_iw_ring_used(ring) <= (ring->w_nr >> 2); + return __rds_iw_ring_used(ring) <= (ring->w_nr >> 1); } diff --git a/net/rds/iw_send.c b/net/rds/iw_send.c index 22dd38ffd608..44a6a0551f28 100644 --- a/net/rds/iw_send.c +++ b/net/rds/iw_send.c @@ -347,7 +347,7 @@ void rds_iw_send_cq_comp_handler(struct ib_cq *cq, void *context) * and using atomic_cmpxchg when updating the two counters. */ int rds_iw_send_grab_credits(struct rds_iw_connection *ic, - u32 wanted, u32 *adv_credits, int need_posted) + u32 wanted, u32 *adv_credits, int need_posted, int max_posted) { unsigned int avail, posted, got = 0, advertise; long oldval, newval; @@ -387,7 +387,7 @@ try_again: * available. */ if (posted && (got || need_posted)) { - advertise = min_t(unsigned int, posted, RDS_MAX_ADV_CREDIT); + advertise = min_t(unsigned int, posted, max_posted); newval -= IB_SET_POST_CREDITS(advertise); } @@ -541,7 +541,7 @@ int rds_iw_xmit(struct rds_connection *conn, struct rds_message *rm, credit_alloc = work_alloc; if (ic->i_flowctl) { - credit_alloc = rds_iw_send_grab_credits(ic, work_alloc, &posted, 0); + credit_alloc = rds_iw_send_grab_credits(ic, work_alloc, &posted, 0, RDS_MAX_ADV_CREDIT); adv_credits += posted; if (credit_alloc < work_alloc) { rds_iw_ring_unalloc(&ic->i_send_ring, work_alloc - credit_alloc); @@ -549,7 +549,7 @@ int rds_iw_xmit(struct rds_connection *conn, struct rds_message *rm, flow_controlled++; } if (work_alloc == 0) { - rds_iw_ring_unalloc(&ic->i_send_ring, work_alloc); + set_bit(RDS_LL_SEND_FULL, &conn->c_flags); rds_iw_stats_inc(s_iw_tx_throttle); ret = -ENOMEM; goto out; @@ -614,7 +614,7 @@ int rds_iw_xmit(struct rds_connection *conn, struct rds_message *rm, /* * Update adv_credits since we reset the ACK_REQUIRED bit. */ - rds_iw_send_grab_credits(ic, 0, &posted, 1); + rds_iw_send_grab_credits(ic, 0, &posted, 1, RDS_MAX_ADV_CREDIT - adv_credits); adv_credits += posted; BUG_ON(adv_credits > 255); } else if (ic->i_rm != rm) diff --git a/net/rds/rdma.c b/net/rds/rdma.c index eaeeb91e1119..8dc83d2caa58 100644 --- a/net/rds/rdma.c +++ b/net/rds/rdma.c @@ -150,12 +150,9 @@ static int rds_pin_pages(unsigned long user_addr, unsigned int nr_pages, { int ret; - down_read(¤t->mm->mmap_sem); - ret = get_user_pages(current, current->mm, user_addr, - nr_pages, write, 0, pages, NULL); - up_read(¤t->mm->mmap_sem); + ret = get_user_pages_fast(user_addr, nr_pages, write, pages); - if (0 <= ret && (unsigned) ret < nr_pages) { + if (ret >= 0 && ret < nr_pages) { while (ret--) put_page(pages[ret]); ret = -EFAULT; diff --git a/net/rds/rdma_transport.c b/net/rds/rdma_transport.c index 7b19024f9706..7d0f901c93d5 100644 --- a/net/rds/rdma_transport.c +++ b/net/rds/rdma_transport.c @@ -34,7 +34,7 @@ #include "rdma_transport.h" -static struct rdma_cm_id *rds_iw_listen_id; +static struct rdma_cm_id *rds_rdma_listen_id; int rds_rdma_cm_event_handler(struct rdma_cm_id *cm_id, struct rdma_cm_event *event) @@ -161,7 +161,7 @@ static int __init rds_rdma_listen_init(void) rdsdebug("cm %p listening on port %u\n", cm_id, RDS_PORT); - rds_iw_listen_id = cm_id; + rds_rdma_listen_id = cm_id; cm_id = NULL; out: if (cm_id) @@ -171,10 +171,10 @@ out: static void rds_rdma_listen_stop(void) { - if (rds_iw_listen_id) { - rdsdebug("cm %p\n", rds_iw_listen_id); - rdma_destroy_id(rds_iw_listen_id); - rds_iw_listen_id = NULL; + if (rds_rdma_listen_id) { + rdsdebug("cm %p\n", rds_rdma_listen_id); + rdma_destroy_id(rds_rdma_listen_id); + rds_rdma_listen_id = NULL; } } diff --git a/net/rds/rds.h b/net/rds/rds.h index 71794449ca4e..dbe111236783 100644 --- a/net/rds/rds.h +++ b/net/rds/rds.h @@ -132,7 +132,7 @@ struct rds_connection { #define RDS_FLAG_CONG_BITMAP 0x01 #define RDS_FLAG_ACK_REQUIRED 0x02 #define RDS_FLAG_RETRANSMITTED 0x04 -#define RDS_MAX_ADV_CREDIT 127 +#define RDS_MAX_ADV_CREDIT 255 /* * Maximum space available for extension headers. diff --git a/net/rds/send.c b/net/rds/send.c index 104fe033203d..a4a7f428cd76 100644 --- a/net/rds/send.c +++ b/net/rds/send.c @@ -854,11 +854,6 @@ int rds_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, rm->m_daddr = daddr; - /* Parse any control messages the user may have included. */ - ret = rds_cmsg_send(rs, rm, msg, &allocated_mr); - if (ret) - goto out; - /* rds_conn_create has a spinlock that runs with IRQ off. * Caching the conn in the socket helps a lot. */ if (rs->rs_conn && rs->rs_conn->c_faddr == daddr) @@ -874,6 +869,11 @@ int rds_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, rs->rs_conn = conn; } + /* Parse any control messages the user may have included. */ + ret = rds_cmsg_send(rs, rm, msg, &allocated_mr); + if (ret) + goto out; + if ((rm->m_rdma_cookie || rm->m_rdma_op) && conn->c_trans->xmit_rdma == NULL) { if (printk_ratelimit()) diff --git a/net/rfkill/Kconfig b/net/rfkill/Kconfig index 7f807b30cfbb..eaf765876458 100644 --- a/net/rfkill/Kconfig +++ b/net/rfkill/Kconfig @@ -10,22 +10,15 @@ menuconfig RFKILL To compile this driver as a module, choose M here: the module will be called rfkill. -config RFKILL_INPUT - tristate "Input layer to RF switch connector" - depends on RFKILL && INPUT - help - Say Y here if you want kernel automatically toggle state - of RF switches on and off when user presses appropriate - button or a key on the keyboard. Without this module you - need a some kind of userspace application to control - state of the switches. - - To compile this driver as a module, choose M here: the - module will be called rfkill-input. - # LED trigger support config RFKILL_LEDS bool - depends on RFKILL && LEDS_TRIGGERS + depends on RFKILL + depends on LEDS_TRIGGERS = y || RFKILL = LEDS_TRIGGERS default y +config RFKILL_INPUT + bool "RF switch input support" if EMBEDDED + depends on RFKILL + depends on INPUT = y || RFKILL = INPUT + default y if !EMBEDDED diff --git a/net/rfkill/Makefile b/net/rfkill/Makefile index b38c430be057..662105352691 100644 --- a/net/rfkill/Makefile +++ b/net/rfkill/Makefile @@ -2,5 +2,6 @@ # Makefile for the RF switch subsystem. # -obj-$(CONFIG_RFKILL) += rfkill.o -obj-$(CONFIG_RFKILL_INPUT) += rfkill-input.o +rfkill-y += core.o +rfkill-$(CONFIG_RFKILL_INPUT) += input.o +obj-$(CONFIG_RFKILL) += rfkill.o diff --git a/net/rfkill/core.c b/net/rfkill/core.c new file mode 100644 index 000000000000..79693fe2001e --- /dev/null +++ b/net/rfkill/core.c @@ -0,0 +1,1225 @@ +/* + * Copyright (C) 2006 - 2007 Ivo van Doorn + * Copyright (C) 2007 Dmitry Torokhov + * Copyright 2009 Johannes Berg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rfkill.h" + +#define POLL_INTERVAL (5 * HZ) + +#define RFKILL_BLOCK_HW BIT(0) +#define RFKILL_BLOCK_SW BIT(1) +#define RFKILL_BLOCK_SW_PREV BIT(2) +#define RFKILL_BLOCK_ANY (RFKILL_BLOCK_HW |\ + RFKILL_BLOCK_SW |\ + RFKILL_BLOCK_SW_PREV) +#define RFKILL_BLOCK_SW_SETCALL BIT(31) + +struct rfkill { + spinlock_t lock; + + const char *name; + enum rfkill_type type; + + unsigned long state; + + u32 idx; + + bool registered; + bool persistent; + + const struct rfkill_ops *ops; + void *data; + +#ifdef CONFIG_RFKILL_LEDS + struct led_trigger led_trigger; + const char *ledtrigname; +#endif + + struct device dev; + struct list_head node; + + struct delayed_work poll_work; + struct work_struct uevent_work; + struct work_struct sync_work; +}; +#define to_rfkill(d) container_of(d, struct rfkill, dev) + +struct rfkill_int_event { + struct list_head list; + struct rfkill_event ev; +}; + +struct rfkill_data { + struct list_head list; + struct list_head events; + struct mutex mtx; + wait_queue_head_t read_wait; + bool input_handler; +}; + + +MODULE_AUTHOR("Ivo van Doorn "); +MODULE_AUTHOR("Johannes Berg "); +MODULE_DESCRIPTION("RF switch support"); +MODULE_LICENSE("GPL"); + + +/* + * The locking here should be made much smarter, we currently have + * a bit of a stupid situation because drivers might want to register + * the rfkill struct under their own lock, and take this lock during + * rfkill method calls -- which will cause an AB-BA deadlock situation. + * + * To fix that, we need to rework this code here to be mostly lock-free + * and only use the mutex for list manipulations, not to protect the + * various other global variables. Then we can avoid holding the mutex + * around driver operations, and all is happy. + */ +static LIST_HEAD(rfkill_list); /* list of registered rf switches */ +static DEFINE_MUTEX(rfkill_global_mutex); +static LIST_HEAD(rfkill_fds); /* list of open fds of /dev/rfkill */ + +static unsigned int rfkill_default_state = 1; +module_param_named(default_state, rfkill_default_state, uint, 0444); +MODULE_PARM_DESC(default_state, + "Default initial state for all radio types, 0 = radio off"); + +static struct { + bool cur, sav; +} rfkill_global_states[NUM_RFKILL_TYPES]; + +static bool rfkill_epo_lock_active; + + +#ifdef CONFIG_RFKILL_LEDS +static void rfkill_led_trigger_event(struct rfkill *rfkill) +{ + struct led_trigger *trigger; + + if (!rfkill->registered) + return; + + trigger = &rfkill->led_trigger; + + if (rfkill->state & RFKILL_BLOCK_ANY) + led_trigger_event(trigger, LED_OFF); + else + led_trigger_event(trigger, LED_FULL); +} + +static void rfkill_led_trigger_activate(struct led_classdev *led) +{ + struct rfkill *rfkill; + + rfkill = container_of(led->trigger, struct rfkill, led_trigger); + + rfkill_led_trigger_event(rfkill); +} + +const char *rfkill_get_led_trigger_name(struct rfkill *rfkill) +{ + return rfkill->led_trigger.name; +} +EXPORT_SYMBOL(rfkill_get_led_trigger_name); + +void rfkill_set_led_trigger_name(struct rfkill *rfkill, const char *name) +{ + BUG_ON(!rfkill); + + rfkill->ledtrigname = name; +} +EXPORT_SYMBOL(rfkill_set_led_trigger_name); + +static int rfkill_led_trigger_register(struct rfkill *rfkill) +{ + rfkill->led_trigger.name = rfkill->ledtrigname + ? : dev_name(&rfkill->dev); + rfkill->led_trigger.activate = rfkill_led_trigger_activate; + return led_trigger_register(&rfkill->led_trigger); +} + +static void rfkill_led_trigger_unregister(struct rfkill *rfkill) +{ + led_trigger_unregister(&rfkill->led_trigger); +} +#else +static void rfkill_led_trigger_event(struct rfkill *rfkill) +{ +} + +static inline int rfkill_led_trigger_register(struct rfkill *rfkill) +{ + return 0; +} + +static inline void rfkill_led_trigger_unregister(struct rfkill *rfkill) +{ +} +#endif /* CONFIG_RFKILL_LEDS */ + +static void rfkill_fill_event(struct rfkill_event *ev, struct rfkill *rfkill, + enum rfkill_operation op) +{ + unsigned long flags; + + ev->idx = rfkill->idx; + ev->type = rfkill->type; + ev->op = op; + + spin_lock_irqsave(&rfkill->lock, flags); + ev->hard = !!(rfkill->state & RFKILL_BLOCK_HW); + ev->soft = !!(rfkill->state & (RFKILL_BLOCK_SW | + RFKILL_BLOCK_SW_PREV)); + spin_unlock_irqrestore(&rfkill->lock, flags); +} + +static void rfkill_send_events(struct rfkill *rfkill, enum rfkill_operation op) +{ + struct rfkill_data *data; + struct rfkill_int_event *ev; + + list_for_each_entry(data, &rfkill_fds, list) { + ev = kzalloc(sizeof(*ev), GFP_KERNEL); + if (!ev) + continue; + rfkill_fill_event(&ev->ev, rfkill, op); + mutex_lock(&data->mtx); + list_add_tail(&ev->list, &data->events); + mutex_unlock(&data->mtx); + wake_up_interruptible(&data->read_wait); + } +} + +static void rfkill_event(struct rfkill *rfkill) +{ + if (!rfkill->registered) + return; + + kobject_uevent(&rfkill->dev.kobj, KOBJ_CHANGE); + + /* also send event to /dev/rfkill */ + rfkill_send_events(rfkill, RFKILL_OP_CHANGE); +} + +static bool __rfkill_set_hw_state(struct rfkill *rfkill, + bool blocked, bool *change) +{ + unsigned long flags; + bool prev, any; + + BUG_ON(!rfkill); + + spin_lock_irqsave(&rfkill->lock, flags); + prev = !!(rfkill->state & RFKILL_BLOCK_HW); + if (blocked) + rfkill->state |= RFKILL_BLOCK_HW; + else + rfkill->state &= ~RFKILL_BLOCK_HW; + *change = prev != blocked; + any = rfkill->state & RFKILL_BLOCK_ANY; + spin_unlock_irqrestore(&rfkill->lock, flags); + + rfkill_led_trigger_event(rfkill); + + return any; +} + +/** + * rfkill_set_block - wrapper for set_block method + * + * @rfkill: the rfkill struct to use + * @blocked: the new software state + * + * Calls the set_block method (when applicable) and handles notifications + * etc. as well. + */ +static void rfkill_set_block(struct rfkill *rfkill, bool blocked) +{ + unsigned long flags; + int err; + + if (unlikely(rfkill->dev.power.power_state.event & PM_EVENT_SLEEP)) + return; + + /* + * Some platforms (...!) generate input events which affect the + * _hard_ kill state -- whenever something tries to change the + * current software state query the hardware state too. + */ + if (rfkill->ops->query) + rfkill->ops->query(rfkill, rfkill->data); + + spin_lock_irqsave(&rfkill->lock, flags); + if (rfkill->state & RFKILL_BLOCK_SW) + rfkill->state |= RFKILL_BLOCK_SW_PREV; + else + rfkill->state &= ~RFKILL_BLOCK_SW_PREV; + + if (blocked) + rfkill->state |= RFKILL_BLOCK_SW; + else + rfkill->state &= ~RFKILL_BLOCK_SW; + + rfkill->state |= RFKILL_BLOCK_SW_SETCALL; + spin_unlock_irqrestore(&rfkill->lock, flags); + + err = rfkill->ops->set_block(rfkill->data, blocked); + + spin_lock_irqsave(&rfkill->lock, flags); + if (err) { + /* + * Failed -- reset status to _prev, this may be different + * from what set set _PREV to earlier in this function + * if rfkill_set_sw_state was invoked. + */ + if (rfkill->state & RFKILL_BLOCK_SW_PREV) + rfkill->state |= RFKILL_BLOCK_SW; + else + rfkill->state &= ~RFKILL_BLOCK_SW; + } + rfkill->state &= ~RFKILL_BLOCK_SW_SETCALL; + rfkill->state &= ~RFKILL_BLOCK_SW_PREV; + spin_unlock_irqrestore(&rfkill->lock, flags); + + rfkill_led_trigger_event(rfkill); + rfkill_event(rfkill); +} + +#ifdef CONFIG_RFKILL_INPUT +static atomic_t rfkill_input_disabled = ATOMIC_INIT(0); + +/** + * __rfkill_switch_all - Toggle state of all switches of given type + * @type: type of interfaces to be affected + * @state: the new state + * + * This function sets the state of all switches of given type, + * unless a specific switch is claimed by userspace (in which case, + * that switch is left alone) or suspended. + * + * Caller must have acquired rfkill_global_mutex. + */ +static void __rfkill_switch_all(const enum rfkill_type type, bool blocked) +{ + struct rfkill *rfkill; + + rfkill_global_states[type].cur = blocked; + list_for_each_entry(rfkill, &rfkill_list, node) { + if (rfkill->type != type) + continue; + + rfkill_set_block(rfkill, blocked); + } +} + +/** + * rfkill_switch_all - Toggle state of all switches of given type + * @type: type of interfaces to be affected + * @state: the new state + * + * Acquires rfkill_global_mutex and calls __rfkill_switch_all(@type, @state). + * Please refer to __rfkill_switch_all() for details. + * + * Does nothing if the EPO lock is active. + */ +void rfkill_switch_all(enum rfkill_type type, bool blocked) +{ + if (atomic_read(&rfkill_input_disabled)) + return; + + mutex_lock(&rfkill_global_mutex); + + if (!rfkill_epo_lock_active) + __rfkill_switch_all(type, blocked); + + mutex_unlock(&rfkill_global_mutex); +} + +/** + * rfkill_epo - emergency power off all transmitters + * + * This kicks all non-suspended rfkill devices to RFKILL_STATE_SOFT_BLOCKED, + * ignoring everything in its path but rfkill_global_mutex and rfkill->mutex. + * + * The global state before the EPO is saved and can be restored later + * using rfkill_restore_states(). + */ +void rfkill_epo(void) +{ + struct rfkill *rfkill; + int i; + + if (atomic_read(&rfkill_input_disabled)) + return; + + mutex_lock(&rfkill_global_mutex); + + rfkill_epo_lock_active = true; + list_for_each_entry(rfkill, &rfkill_list, node) + rfkill_set_block(rfkill, true); + + for (i = 0; i < NUM_RFKILL_TYPES; i++) { + rfkill_global_states[i].sav = rfkill_global_states[i].cur; + rfkill_global_states[i].cur = true; + } + + mutex_unlock(&rfkill_global_mutex); +} + +/** + * rfkill_restore_states - restore global states + * + * Restore (and sync switches to) the global state from the + * states in rfkill_default_states. This can undo the effects of + * a call to rfkill_epo(). + */ +void rfkill_restore_states(void) +{ + int i; + + if (atomic_read(&rfkill_input_disabled)) + return; + + mutex_lock(&rfkill_global_mutex); + + rfkill_epo_lock_active = false; + for (i = 0; i < NUM_RFKILL_TYPES; i++) + __rfkill_switch_all(i, rfkill_global_states[i].sav); + mutex_unlock(&rfkill_global_mutex); +} + +/** + * rfkill_remove_epo_lock - unlock state changes + * + * Used by rfkill-input manually unlock state changes, when + * the EPO switch is deactivated. + */ +void rfkill_remove_epo_lock(void) +{ + if (atomic_read(&rfkill_input_disabled)) + return; + + mutex_lock(&rfkill_global_mutex); + rfkill_epo_lock_active = false; + mutex_unlock(&rfkill_global_mutex); +} + +/** + * rfkill_is_epo_lock_active - returns true EPO is active + * + * Returns 0 (false) if there is NOT an active EPO contidion, + * and 1 (true) if there is an active EPO contition, which + * locks all radios in one of the BLOCKED states. + * + * Can be called in atomic context. + */ +bool rfkill_is_epo_lock_active(void) +{ + return rfkill_epo_lock_active; +} + +/** + * rfkill_get_global_sw_state - returns global state for a type + * @type: the type to get the global state of + * + * Returns the current global state for a given wireless + * device type. + */ +bool rfkill_get_global_sw_state(const enum rfkill_type type) +{ + return rfkill_global_states[type].cur; +} +#endif + + +bool rfkill_set_hw_state(struct rfkill *rfkill, bool blocked) +{ + bool ret, change; + + ret = __rfkill_set_hw_state(rfkill, blocked, &change); + + if (!rfkill->registered) + return ret; + + if (change) + schedule_work(&rfkill->uevent_work); + + return ret; +} +EXPORT_SYMBOL(rfkill_set_hw_state); + +static void __rfkill_set_sw_state(struct rfkill *rfkill, bool blocked) +{ + u32 bit = RFKILL_BLOCK_SW; + + /* if in a ops->set_block right now, use other bit */ + if (rfkill->state & RFKILL_BLOCK_SW_SETCALL) + bit = RFKILL_BLOCK_SW_PREV; + + if (blocked) + rfkill->state |= bit; + else + rfkill->state &= ~bit; +} + +bool rfkill_set_sw_state(struct rfkill *rfkill, bool blocked) +{ + unsigned long flags; + bool prev, hwblock; + + BUG_ON(!rfkill); + + spin_lock_irqsave(&rfkill->lock, flags); + prev = !!(rfkill->state & RFKILL_BLOCK_SW); + __rfkill_set_sw_state(rfkill, blocked); + hwblock = !!(rfkill->state & RFKILL_BLOCK_HW); + blocked = blocked || hwblock; + spin_unlock_irqrestore(&rfkill->lock, flags); + + if (!rfkill->registered) + return blocked; + + if (prev != blocked && !hwblock) + schedule_work(&rfkill->uevent_work); + + rfkill_led_trigger_event(rfkill); + + return blocked; +} +EXPORT_SYMBOL(rfkill_set_sw_state); + +void rfkill_init_sw_state(struct rfkill *rfkill, bool blocked) +{ + unsigned long flags; + + BUG_ON(!rfkill); + BUG_ON(rfkill->registered); + + spin_lock_irqsave(&rfkill->lock, flags); + __rfkill_set_sw_state(rfkill, blocked); + rfkill->persistent = true; + spin_unlock_irqrestore(&rfkill->lock, flags); +} +EXPORT_SYMBOL(rfkill_init_sw_state); + +void rfkill_set_states(struct rfkill *rfkill, bool sw, bool hw) +{ + unsigned long flags; + bool swprev, hwprev; + + BUG_ON(!rfkill); + + spin_lock_irqsave(&rfkill->lock, flags); + + /* + * No need to care about prev/setblock ... this is for uevent only + * and that will get triggered by rfkill_set_block anyway. + */ + swprev = !!(rfkill->state & RFKILL_BLOCK_SW); + hwprev = !!(rfkill->state & RFKILL_BLOCK_HW); + __rfkill_set_sw_state(rfkill, sw); + + spin_unlock_irqrestore(&rfkill->lock, flags); + + if (!rfkill->registered) { + rfkill->persistent = true; + } else { + if (swprev != sw || hwprev != hw) + schedule_work(&rfkill->uevent_work); + + rfkill_led_trigger_event(rfkill); + } +} +EXPORT_SYMBOL(rfkill_set_states); + +static ssize_t rfkill_name_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rfkill *rfkill = to_rfkill(dev); + + return sprintf(buf, "%s\n", rfkill->name); +} + +static const char *rfkill_get_type_str(enum rfkill_type type) +{ + switch (type) { + case RFKILL_TYPE_WLAN: + return "wlan"; + case RFKILL_TYPE_BLUETOOTH: + return "bluetooth"; + case RFKILL_TYPE_UWB: + return "ultrawideband"; + case RFKILL_TYPE_WIMAX: + return "wimax"; + case RFKILL_TYPE_WWAN: + return "wwan"; + default: + BUG(); + } + + BUILD_BUG_ON(NUM_RFKILL_TYPES != RFKILL_TYPE_WWAN + 1); +} + +static ssize_t rfkill_type_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rfkill *rfkill = to_rfkill(dev); + + return sprintf(buf, "%s\n", rfkill_get_type_str(rfkill->type)); +} + +static ssize_t rfkill_idx_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rfkill *rfkill = to_rfkill(dev); + + return sprintf(buf, "%d\n", rfkill->idx); +} + +static ssize_t rfkill_persistent_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rfkill *rfkill = to_rfkill(dev); + + return sprintf(buf, "%d\n", rfkill->persistent); +} + +static u8 user_state_from_blocked(unsigned long state) +{ + if (state & RFKILL_BLOCK_HW) + return RFKILL_USER_STATE_HARD_BLOCKED; + if (state & RFKILL_BLOCK_SW) + return RFKILL_USER_STATE_SOFT_BLOCKED; + + return RFKILL_USER_STATE_UNBLOCKED; +} + +static ssize_t rfkill_state_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rfkill *rfkill = to_rfkill(dev); + unsigned long flags; + u32 state; + + spin_lock_irqsave(&rfkill->lock, flags); + state = rfkill->state; + spin_unlock_irqrestore(&rfkill->lock, flags); + + return sprintf(buf, "%d\n", user_state_from_blocked(state)); +} + +static ssize_t rfkill_state_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + /* + * The intention was that userspace can only take control over + * a given device when/if rfkill-input doesn't control it due + * to user_claim. Since user_claim is currently unsupported, + * we never support changing the state from userspace -- this + * can be implemented again later. + */ + + return -EPERM; +} + +static ssize_t rfkill_claim_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%d\n", 0); +} + +static ssize_t rfkill_claim_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + return -EOPNOTSUPP; +} + +static struct device_attribute rfkill_dev_attrs[] = { + __ATTR(name, S_IRUGO, rfkill_name_show, NULL), + __ATTR(type, S_IRUGO, rfkill_type_show, NULL), + __ATTR(index, S_IRUGO, rfkill_idx_show, NULL), + __ATTR(persistent, S_IRUGO, rfkill_persistent_show, NULL), + __ATTR(state, S_IRUGO|S_IWUSR, rfkill_state_show, rfkill_state_store), + __ATTR(claim, S_IRUGO|S_IWUSR, rfkill_claim_show, rfkill_claim_store), + __ATTR_NULL +}; + +static void rfkill_release(struct device *dev) +{ + struct rfkill *rfkill = to_rfkill(dev); + + kfree(rfkill); +} + +static int rfkill_dev_uevent(struct device *dev, struct kobj_uevent_env *env) +{ + struct rfkill *rfkill = to_rfkill(dev); + unsigned long flags; + u32 state; + int error; + + error = add_uevent_var(env, "RFKILL_NAME=%s", rfkill->name); + if (error) + return error; + error = add_uevent_var(env, "RFKILL_TYPE=%s", + rfkill_get_type_str(rfkill->type)); + if (error) + return error; + spin_lock_irqsave(&rfkill->lock, flags); + state = rfkill->state; + spin_unlock_irqrestore(&rfkill->lock, flags); + error = add_uevent_var(env, "RFKILL_STATE=%d", + user_state_from_blocked(state)); + return error; +} + +void rfkill_pause_polling(struct rfkill *rfkill) +{ + BUG_ON(!rfkill); + + if (!rfkill->ops->poll) + return; + + cancel_delayed_work_sync(&rfkill->poll_work); +} +EXPORT_SYMBOL(rfkill_pause_polling); + +void rfkill_resume_polling(struct rfkill *rfkill) +{ + BUG_ON(!rfkill); + + if (!rfkill->ops->poll) + return; + + schedule_work(&rfkill->poll_work.work); +} +EXPORT_SYMBOL(rfkill_resume_polling); + +static int rfkill_suspend(struct device *dev, pm_message_t state) +{ + struct rfkill *rfkill = to_rfkill(dev); + + rfkill_pause_polling(rfkill); + + return 0; +} + +static int rfkill_resume(struct device *dev) +{ + struct rfkill *rfkill = to_rfkill(dev); + bool cur; + + if (!rfkill->persistent) { + cur = !!(rfkill->state & RFKILL_BLOCK_SW); + rfkill_set_block(rfkill, cur); + } + + rfkill_resume_polling(rfkill); + + return 0; +} + +static struct class rfkill_class = { + .name = "rfkill", + .dev_release = rfkill_release, + .dev_attrs = rfkill_dev_attrs, + .dev_uevent = rfkill_dev_uevent, + .suspend = rfkill_suspend, + .resume = rfkill_resume, +}; + +bool rfkill_blocked(struct rfkill *rfkill) +{ + unsigned long flags; + u32 state; + + spin_lock_irqsave(&rfkill->lock, flags); + state = rfkill->state; + spin_unlock_irqrestore(&rfkill->lock, flags); + + return !!(state & RFKILL_BLOCK_ANY); +} +EXPORT_SYMBOL(rfkill_blocked); + + +struct rfkill * __must_check rfkill_alloc(const char *name, + struct device *parent, + const enum rfkill_type type, + const struct rfkill_ops *ops, + void *ops_data) +{ + struct rfkill *rfkill; + struct device *dev; + + if (WARN_ON(!ops)) + return NULL; + + if (WARN_ON(!ops->set_block)) + return NULL; + + if (WARN_ON(!name)) + return NULL; + + if (WARN_ON(type == RFKILL_TYPE_ALL || type >= NUM_RFKILL_TYPES)) + return NULL; + + rfkill = kzalloc(sizeof(*rfkill), GFP_KERNEL); + if (!rfkill) + return NULL; + + spin_lock_init(&rfkill->lock); + INIT_LIST_HEAD(&rfkill->node); + rfkill->type = type; + rfkill->name = name; + rfkill->ops = ops; + rfkill->data = ops_data; + + dev = &rfkill->dev; + dev->class = &rfkill_class; + dev->parent = parent; + device_initialize(dev); + + return rfkill; +} +EXPORT_SYMBOL(rfkill_alloc); + +static void rfkill_poll(struct work_struct *work) +{ + struct rfkill *rfkill; + + rfkill = container_of(work, struct rfkill, poll_work.work); + + /* + * Poll hardware state -- driver will use one of the + * rfkill_set{,_hw,_sw}_state functions and use its + * return value to update the current status. + */ + rfkill->ops->poll(rfkill, rfkill->data); + + schedule_delayed_work(&rfkill->poll_work, + round_jiffies_relative(POLL_INTERVAL)); +} + +static void rfkill_uevent_work(struct work_struct *work) +{ + struct rfkill *rfkill; + + rfkill = container_of(work, struct rfkill, uevent_work); + + mutex_lock(&rfkill_global_mutex); + rfkill_event(rfkill); + mutex_unlock(&rfkill_global_mutex); +} + +static void rfkill_sync_work(struct work_struct *work) +{ + struct rfkill *rfkill; + bool cur; + + rfkill = container_of(work, struct rfkill, sync_work); + + mutex_lock(&rfkill_global_mutex); + cur = rfkill_global_states[rfkill->type].cur; + rfkill_set_block(rfkill, cur); + mutex_unlock(&rfkill_global_mutex); +} + +int __must_check rfkill_register(struct rfkill *rfkill) +{ + static unsigned long rfkill_no; + struct device *dev = &rfkill->dev; + int error; + + BUG_ON(!rfkill); + + mutex_lock(&rfkill_global_mutex); + + if (rfkill->registered) { + error = -EALREADY; + goto unlock; + } + + rfkill->idx = rfkill_no; + dev_set_name(dev, "rfkill%lu", rfkill_no); + rfkill_no++; + + list_add_tail(&rfkill->node, &rfkill_list); + + error = device_add(dev); + if (error) + goto remove; + + error = rfkill_led_trigger_register(rfkill); + if (error) + goto devdel; + + rfkill->registered = true; + + INIT_DELAYED_WORK(&rfkill->poll_work, rfkill_poll); + INIT_WORK(&rfkill->uevent_work, rfkill_uevent_work); + INIT_WORK(&rfkill->sync_work, rfkill_sync_work); + + if (rfkill->ops->poll) + schedule_delayed_work(&rfkill->poll_work, + round_jiffies_relative(POLL_INTERVAL)); + + if (!rfkill->persistent || rfkill_epo_lock_active) { + schedule_work(&rfkill->sync_work); + } else { +#ifdef CONFIG_RFKILL_INPUT + bool soft_blocked = !!(rfkill->state & RFKILL_BLOCK_SW); + + if (!atomic_read(&rfkill_input_disabled)) + __rfkill_switch_all(rfkill->type, soft_blocked); +#endif + } + + rfkill_send_events(rfkill, RFKILL_OP_ADD); + + mutex_unlock(&rfkill_global_mutex); + return 0; + + devdel: + device_del(&rfkill->dev); + remove: + list_del_init(&rfkill->node); + unlock: + mutex_unlock(&rfkill_global_mutex); + return error; +} +EXPORT_SYMBOL(rfkill_register); + +void rfkill_unregister(struct rfkill *rfkill) +{ + BUG_ON(!rfkill); + + if (rfkill->ops->poll) + cancel_delayed_work_sync(&rfkill->poll_work); + + cancel_work_sync(&rfkill->uevent_work); + cancel_work_sync(&rfkill->sync_work); + + rfkill->registered = false; + + device_del(&rfkill->dev); + + mutex_lock(&rfkill_global_mutex); + rfkill_send_events(rfkill, RFKILL_OP_DEL); + list_del_init(&rfkill->node); + mutex_unlock(&rfkill_global_mutex); + + rfkill_led_trigger_unregister(rfkill); +} +EXPORT_SYMBOL(rfkill_unregister); + +void rfkill_destroy(struct rfkill *rfkill) +{ + if (rfkill) + put_device(&rfkill->dev); +} +EXPORT_SYMBOL(rfkill_destroy); + +static int rfkill_fop_open(struct inode *inode, struct file *file) +{ + struct rfkill_data *data; + struct rfkill *rfkill; + struct rfkill_int_event *ev, *tmp; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + INIT_LIST_HEAD(&data->events); + mutex_init(&data->mtx); + init_waitqueue_head(&data->read_wait); + + mutex_lock(&rfkill_global_mutex); + mutex_lock(&data->mtx); + /* + * start getting events from elsewhere but hold mtx to get + * startup events added first + */ + list_add(&data->list, &rfkill_fds); + + list_for_each_entry(rfkill, &rfkill_list, node) { + ev = kzalloc(sizeof(*ev), GFP_KERNEL); + if (!ev) + goto free; + rfkill_fill_event(&ev->ev, rfkill, RFKILL_OP_ADD); + list_add_tail(&ev->list, &data->events); + } + mutex_unlock(&data->mtx); + mutex_unlock(&rfkill_global_mutex); + + file->private_data = data; + + return nonseekable_open(inode, file); + + free: + mutex_unlock(&data->mtx); + mutex_unlock(&rfkill_global_mutex); + mutex_destroy(&data->mtx); + list_for_each_entry_safe(ev, tmp, &data->events, list) + kfree(ev); + kfree(data); + return -ENOMEM; +} + +static unsigned int rfkill_fop_poll(struct file *file, poll_table *wait) +{ + struct rfkill_data *data = file->private_data; + unsigned int res = POLLOUT | POLLWRNORM; + + poll_wait(file, &data->read_wait, wait); + + mutex_lock(&data->mtx); + if (!list_empty(&data->events)) + res = POLLIN | POLLRDNORM; + mutex_unlock(&data->mtx); + + return res; +} + +static bool rfkill_readable(struct rfkill_data *data) +{ + bool r; + + mutex_lock(&data->mtx); + r = !list_empty(&data->events); + mutex_unlock(&data->mtx); + + return r; +} + +static ssize_t rfkill_fop_read(struct file *file, char __user *buf, + size_t count, loff_t *pos) +{ + struct rfkill_data *data = file->private_data; + struct rfkill_int_event *ev; + unsigned long sz; + int ret; + + mutex_lock(&data->mtx); + + while (list_empty(&data->events)) { + if (file->f_flags & O_NONBLOCK) { + ret = -EAGAIN; + goto out; + } + mutex_unlock(&data->mtx); + ret = wait_event_interruptible(data->read_wait, + rfkill_readable(data)); + mutex_lock(&data->mtx); + + if (ret) + goto out; + } + + ev = list_first_entry(&data->events, struct rfkill_int_event, + list); + + sz = min_t(unsigned long, sizeof(ev->ev), count); + ret = sz; + if (copy_to_user(buf, &ev->ev, sz)) + ret = -EFAULT; + + list_del(&ev->list); + kfree(ev); + out: + mutex_unlock(&data->mtx); + return ret; +} + +static ssize_t rfkill_fop_write(struct file *file, const char __user *buf, + size_t count, loff_t *pos) +{ + struct rfkill *rfkill; + struct rfkill_event ev; + + /* we don't need the 'hard' variable but accept it */ + if (count < sizeof(ev) - 1) + return -EINVAL; + + if (copy_from_user(&ev, buf, sizeof(ev) - 1)) + return -EFAULT; + + if (ev.op != RFKILL_OP_CHANGE && ev.op != RFKILL_OP_CHANGE_ALL) + return -EINVAL; + + if (ev.type >= NUM_RFKILL_TYPES) + return -EINVAL; + + mutex_lock(&rfkill_global_mutex); + + if (ev.op == RFKILL_OP_CHANGE_ALL) { + if (ev.type == RFKILL_TYPE_ALL) { + enum rfkill_type i; + for (i = 0; i < NUM_RFKILL_TYPES; i++) + rfkill_global_states[i].cur = ev.soft; + } else { + rfkill_global_states[ev.type].cur = ev.soft; + } + } + + list_for_each_entry(rfkill, &rfkill_list, node) { + if (rfkill->idx != ev.idx && ev.op != RFKILL_OP_CHANGE_ALL) + continue; + + if (rfkill->type != ev.type && ev.type != RFKILL_TYPE_ALL) + continue; + + rfkill_set_block(rfkill, ev.soft); + } + mutex_unlock(&rfkill_global_mutex); + + return count; +} + +static int rfkill_fop_release(struct inode *inode, struct file *file) +{ + struct rfkill_data *data = file->private_data; + struct rfkill_int_event *ev, *tmp; + + mutex_lock(&rfkill_global_mutex); + list_del(&data->list); + mutex_unlock(&rfkill_global_mutex); + + mutex_destroy(&data->mtx); + list_for_each_entry_safe(ev, tmp, &data->events, list) + kfree(ev); + +#ifdef CONFIG_RFKILL_INPUT + if (data->input_handler) + if (atomic_dec_return(&rfkill_input_disabled) == 0) + printk(KERN_DEBUG "rfkill: input handler enabled\n"); +#endif + + kfree(data); + + return 0; +} + +#ifdef CONFIG_RFKILL_INPUT +static long rfkill_fop_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct rfkill_data *data = file->private_data; + + if (_IOC_TYPE(cmd) != RFKILL_IOC_MAGIC) + return -ENOSYS; + + if (_IOC_NR(cmd) != RFKILL_IOC_NOINPUT) + return -ENOSYS; + + mutex_lock(&data->mtx); + + if (!data->input_handler) { + if (atomic_inc_return(&rfkill_input_disabled) == 1) + printk(KERN_DEBUG "rfkill: input handler disabled\n"); + data->input_handler = true; + } + + mutex_unlock(&data->mtx); + + return 0; +} +#endif + +static const struct file_operations rfkill_fops = { + .open = rfkill_fop_open, + .read = rfkill_fop_read, + .write = rfkill_fop_write, + .poll = rfkill_fop_poll, + .release = rfkill_fop_release, +#ifdef CONFIG_RFKILL_INPUT + .unlocked_ioctl = rfkill_fop_ioctl, + .compat_ioctl = rfkill_fop_ioctl, +#endif +}; + +static struct miscdevice rfkill_miscdev = { + .name = "rfkill", + .fops = &rfkill_fops, + .minor = MISC_DYNAMIC_MINOR, +}; + +static int __init rfkill_init(void) +{ + int error; + int i; + + for (i = 0; i < NUM_RFKILL_TYPES; i++) + rfkill_global_states[i].cur = !rfkill_default_state; + + error = class_register(&rfkill_class); + if (error) + goto out; + + error = misc_register(&rfkill_miscdev); + if (error) { + class_unregister(&rfkill_class); + goto out; + } + +#ifdef CONFIG_RFKILL_INPUT + error = rfkill_handler_init(); + if (error) { + misc_deregister(&rfkill_miscdev); + class_unregister(&rfkill_class); + goto out; + } +#endif + + out: + return error; +} +subsys_initcall(rfkill_init); + +static void __exit rfkill_exit(void) +{ +#ifdef CONFIG_RFKILL_INPUT + rfkill_handler_exit(); +#endif + misc_deregister(&rfkill_miscdev); + class_unregister(&rfkill_class); +} +module_exit(rfkill_exit); diff --git a/net/rfkill/input.c b/net/rfkill/input.c new file mode 100644 index 000000000000..a7295ad5f9cb --- /dev/null +++ b/net/rfkill/input.c @@ -0,0 +1,342 @@ +/* + * Input layer to RF Kill interface connector + * + * Copyright (c) 2007 Dmitry Torokhov + * Copyright 2009 Johannes Berg + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * If you ever run into a situation in which you have a SW_ type rfkill + * input device, then you can revive code that was removed in the patch + * "rfkill-input: remove unused code". + */ + +#include +#include +#include +#include +#include +#include + +#include "rfkill.h" + +enum rfkill_input_master_mode { + RFKILL_INPUT_MASTER_UNLOCK = 0, + RFKILL_INPUT_MASTER_RESTORE = 1, + RFKILL_INPUT_MASTER_UNBLOCKALL = 2, + NUM_RFKILL_INPUT_MASTER_MODES +}; + +/* Delay (in ms) between consecutive switch ops */ +#define RFKILL_OPS_DELAY 200 + +static enum rfkill_input_master_mode rfkill_master_switch_mode = + RFKILL_INPUT_MASTER_UNBLOCKALL; +module_param_named(master_switch_mode, rfkill_master_switch_mode, uint, 0); +MODULE_PARM_DESC(master_switch_mode, + "SW_RFKILL_ALL ON should: 0=do nothing (only unlock); 1=restore; 2=unblock all"); + +static spinlock_t rfkill_op_lock; +static bool rfkill_op_pending; +static unsigned long rfkill_sw_pending[BITS_TO_LONGS(NUM_RFKILL_TYPES)]; +static unsigned long rfkill_sw_state[BITS_TO_LONGS(NUM_RFKILL_TYPES)]; + +enum rfkill_sched_op { + RFKILL_GLOBAL_OP_EPO = 0, + RFKILL_GLOBAL_OP_RESTORE, + RFKILL_GLOBAL_OP_UNLOCK, + RFKILL_GLOBAL_OP_UNBLOCK, +}; + +static enum rfkill_sched_op rfkill_master_switch_op; +static enum rfkill_sched_op rfkill_op; + +static void __rfkill_handle_global_op(enum rfkill_sched_op op) +{ + unsigned int i; + + switch (op) { + case RFKILL_GLOBAL_OP_EPO: + rfkill_epo(); + break; + case RFKILL_GLOBAL_OP_RESTORE: + rfkill_restore_states(); + break; + case RFKILL_GLOBAL_OP_UNLOCK: + rfkill_remove_epo_lock(); + break; + case RFKILL_GLOBAL_OP_UNBLOCK: + rfkill_remove_epo_lock(); + for (i = 0; i < NUM_RFKILL_TYPES; i++) + rfkill_switch_all(i, false); + break; + default: + /* memory corruption or bug, fail safely */ + rfkill_epo(); + WARN(1, "Unknown requested operation %d! " + "rfkill Emergency Power Off activated\n", + op); + } +} + +static void __rfkill_handle_normal_op(const enum rfkill_type type, + const bool complement) +{ + bool blocked; + + blocked = rfkill_get_global_sw_state(type); + if (complement) + blocked = !blocked; + + rfkill_switch_all(type, blocked); +} + +static void rfkill_op_handler(struct work_struct *work) +{ + unsigned int i; + bool c; + + spin_lock_irq(&rfkill_op_lock); + do { + if (rfkill_op_pending) { + enum rfkill_sched_op op = rfkill_op; + rfkill_op_pending = false; + memset(rfkill_sw_pending, 0, + sizeof(rfkill_sw_pending)); + spin_unlock_irq(&rfkill_op_lock); + + __rfkill_handle_global_op(op); + + spin_lock_irq(&rfkill_op_lock); + + /* + * handle global ops first -- during unlocked period + * we might have gotten a new global op. + */ + if (rfkill_op_pending) + continue; + } + + if (rfkill_is_epo_lock_active()) + continue; + + for (i = 0; i < NUM_RFKILL_TYPES; i++) { + if (__test_and_clear_bit(i, rfkill_sw_pending)) { + c = __test_and_clear_bit(i, rfkill_sw_state); + spin_unlock_irq(&rfkill_op_lock); + + __rfkill_handle_normal_op(i, c); + + spin_lock_irq(&rfkill_op_lock); + } + } + } while (rfkill_op_pending); + spin_unlock_irq(&rfkill_op_lock); +} + +static DECLARE_DELAYED_WORK(rfkill_op_work, rfkill_op_handler); +static unsigned long rfkill_last_scheduled; + +static unsigned long rfkill_ratelimit(const unsigned long last) +{ + const unsigned long delay = msecs_to_jiffies(RFKILL_OPS_DELAY); + return (time_after(jiffies, last + delay)) ? 0 : delay; +} + +static void rfkill_schedule_ratelimited(void) +{ + if (delayed_work_pending(&rfkill_op_work)) + return; + schedule_delayed_work(&rfkill_op_work, + rfkill_ratelimit(rfkill_last_scheduled)); + rfkill_last_scheduled = jiffies; +} + +static void rfkill_schedule_global_op(enum rfkill_sched_op op) +{ + unsigned long flags; + + spin_lock_irqsave(&rfkill_op_lock, flags); + rfkill_op = op; + rfkill_op_pending = true; + if (op == RFKILL_GLOBAL_OP_EPO && !rfkill_is_epo_lock_active()) { + /* bypass the limiter for EPO */ + cancel_delayed_work(&rfkill_op_work); + schedule_delayed_work(&rfkill_op_work, 0); + rfkill_last_scheduled = jiffies; + } else + rfkill_schedule_ratelimited(); + spin_unlock_irqrestore(&rfkill_op_lock, flags); +} + +static void rfkill_schedule_toggle(enum rfkill_type type) +{ + unsigned long flags; + + if (rfkill_is_epo_lock_active()) + return; + + spin_lock_irqsave(&rfkill_op_lock, flags); + if (!rfkill_op_pending) { + __set_bit(type, rfkill_sw_pending); + __change_bit(type, rfkill_sw_state); + rfkill_schedule_ratelimited(); + } + spin_unlock_irqrestore(&rfkill_op_lock, flags); +} + +static void rfkill_schedule_evsw_rfkillall(int state) +{ + if (state) + rfkill_schedule_global_op(rfkill_master_switch_op); + else + rfkill_schedule_global_op(RFKILL_GLOBAL_OP_EPO); +} + +static void rfkill_event(struct input_handle *handle, unsigned int type, + unsigned int code, int data) +{ + if (type == EV_KEY && data == 1) { + switch (code) { + case KEY_WLAN: + rfkill_schedule_toggle(RFKILL_TYPE_WLAN); + break; + case KEY_BLUETOOTH: + rfkill_schedule_toggle(RFKILL_TYPE_BLUETOOTH); + break; + case KEY_UWB: + rfkill_schedule_toggle(RFKILL_TYPE_UWB); + break; + case KEY_WIMAX: + rfkill_schedule_toggle(RFKILL_TYPE_WIMAX); + break; + } + } else if (type == EV_SW && code == SW_RFKILL_ALL) + rfkill_schedule_evsw_rfkillall(data); +} + +static int rfkill_connect(struct input_handler *handler, struct input_dev *dev, + const struct input_device_id *id) +{ + struct input_handle *handle; + int error; + + handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL); + if (!handle) + return -ENOMEM; + + handle->dev = dev; + handle->handler = handler; + handle->name = "rfkill"; + + /* causes rfkill_start() to be called */ + error = input_register_handle(handle); + if (error) + goto err_free_handle; + + error = input_open_device(handle); + if (error) + goto err_unregister_handle; + + return 0; + + err_unregister_handle: + input_unregister_handle(handle); + err_free_handle: + kfree(handle); + return error; +} + +static void rfkill_start(struct input_handle *handle) +{ + /* + * Take event_lock to guard against configuration changes, we + * should be able to deal with concurrency with rfkill_event() + * just fine (which event_lock will also avoid). + */ + spin_lock_irq(&handle->dev->event_lock); + + if (test_bit(EV_SW, handle->dev->evbit) && + test_bit(SW_RFKILL_ALL, handle->dev->swbit)) + rfkill_schedule_evsw_rfkillall(test_bit(SW_RFKILL_ALL, + handle->dev->sw)); + + spin_unlock_irq(&handle->dev->event_lock); +} + +static void rfkill_disconnect(struct input_handle *handle) +{ + input_close_device(handle); + input_unregister_handle(handle); + kfree(handle); +} + +static const struct input_device_id rfkill_ids[] = { + { + .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, + .evbit = { BIT_MASK(EV_KEY) }, + .keybit = { [BIT_WORD(KEY_WLAN)] = BIT_MASK(KEY_WLAN) }, + }, + { + .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, + .evbit = { BIT_MASK(EV_KEY) }, + .keybit = { [BIT_WORD(KEY_BLUETOOTH)] = BIT_MASK(KEY_BLUETOOTH) }, + }, + { + .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, + .evbit = { BIT_MASK(EV_KEY) }, + .keybit = { [BIT_WORD(KEY_UWB)] = BIT_MASK(KEY_UWB) }, + }, + { + .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, + .evbit = { BIT_MASK(EV_KEY) }, + .keybit = { [BIT_WORD(KEY_WIMAX)] = BIT_MASK(KEY_WIMAX) }, + }, + { + .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_SWBIT, + .evbit = { BIT(EV_SW) }, + .swbit = { [BIT_WORD(SW_RFKILL_ALL)] = BIT_MASK(SW_RFKILL_ALL) }, + }, + { } +}; + +static struct input_handler rfkill_handler = { + .name = "rfkill", + .event = rfkill_event, + .connect = rfkill_connect, + .start = rfkill_start, + .disconnect = rfkill_disconnect, + .id_table = rfkill_ids, +}; + +int __init rfkill_handler_init(void) +{ + switch (rfkill_master_switch_mode) { + case RFKILL_INPUT_MASTER_UNBLOCKALL: + rfkill_master_switch_op = RFKILL_GLOBAL_OP_UNBLOCK; + break; + case RFKILL_INPUT_MASTER_RESTORE: + rfkill_master_switch_op = RFKILL_GLOBAL_OP_RESTORE; + break; + case RFKILL_INPUT_MASTER_UNLOCK: + rfkill_master_switch_op = RFKILL_GLOBAL_OP_UNLOCK; + break; + default: + return -EINVAL; + } + + spin_lock_init(&rfkill_op_lock); + + /* Avoid delay at first schedule */ + rfkill_last_scheduled = + jiffies - msecs_to_jiffies(RFKILL_OPS_DELAY) - 1; + return input_register_handler(&rfkill_handler); +} + +void __exit rfkill_handler_exit(void) +{ + input_unregister_handler(&rfkill_handler); + cancel_delayed_work_sync(&rfkill_op_work); +} diff --git a/net/rfkill/rfkill-input.c b/net/rfkill/rfkill-input.c deleted file mode 100644 index 84efde97c5a7..000000000000 --- a/net/rfkill/rfkill-input.c +++ /dev/null @@ -1,459 +0,0 @@ -/* - * Input layer to RF Kill interface connector - * - * Copyright (c) 2007 Dmitry Torokhov - */ - -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "rfkill-input.h" - -MODULE_AUTHOR("Dmitry Torokhov "); -MODULE_DESCRIPTION("Input layer to RF switch connector"); -MODULE_LICENSE("GPL"); - -enum rfkill_input_master_mode { - RFKILL_INPUT_MASTER_DONOTHING = 0, - RFKILL_INPUT_MASTER_RESTORE = 1, - RFKILL_INPUT_MASTER_UNBLOCKALL = 2, - RFKILL_INPUT_MASTER_MAX, /* marker */ -}; - -/* Delay (in ms) between consecutive switch ops */ -#define RFKILL_OPS_DELAY 200 - -static enum rfkill_input_master_mode rfkill_master_switch_mode = - RFKILL_INPUT_MASTER_UNBLOCKALL; -module_param_named(master_switch_mode, rfkill_master_switch_mode, uint, 0); -MODULE_PARM_DESC(master_switch_mode, - "SW_RFKILL_ALL ON should: 0=do nothing; 1=restore; 2=unblock all"); - -enum rfkill_global_sched_op { - RFKILL_GLOBAL_OP_EPO = 0, - RFKILL_GLOBAL_OP_RESTORE, - RFKILL_GLOBAL_OP_UNLOCK, - RFKILL_GLOBAL_OP_UNBLOCK, -}; - -/* - * Currently, the code marked with RFKILL_NEED_SWSET is inactive. - * If handling of EV_SW SW_WLAN/WWAN/BLUETOOTH/etc is needed in the - * future, when such events are added, that code will be necessary. - */ - -struct rfkill_task { - struct delayed_work dwork; - - /* ensures that task is serialized */ - struct mutex mutex; - - /* protects everything below */ - spinlock_t lock; - - /* pending regular switch operations (1=pending) */ - unsigned long sw_pending[BITS_TO_LONGS(RFKILL_TYPE_MAX)]; - -#ifdef RFKILL_NEED_SWSET - /* set operation pending (1=pending) */ - unsigned long sw_setpending[BITS_TO_LONGS(RFKILL_TYPE_MAX)]; - - /* desired state for pending set operation (1=unblock) */ - unsigned long sw_newstate[BITS_TO_LONGS(RFKILL_TYPE_MAX)]; -#endif - - /* should the state be complemented (1=yes) */ - unsigned long sw_togglestate[BITS_TO_LONGS(RFKILL_TYPE_MAX)]; - - bool global_op_pending; - enum rfkill_global_sched_op op; - - /* last time it was scheduled */ - unsigned long last_scheduled; -}; - -static void __rfkill_handle_global_op(enum rfkill_global_sched_op op) -{ - unsigned int i; - - switch (op) { - case RFKILL_GLOBAL_OP_EPO: - rfkill_epo(); - break; - case RFKILL_GLOBAL_OP_RESTORE: - rfkill_restore_states(); - break; - case RFKILL_GLOBAL_OP_UNLOCK: - rfkill_remove_epo_lock(); - break; - case RFKILL_GLOBAL_OP_UNBLOCK: - rfkill_remove_epo_lock(); - for (i = 0; i < RFKILL_TYPE_MAX; i++) - rfkill_switch_all(i, RFKILL_STATE_UNBLOCKED); - break; - default: - /* memory corruption or bug, fail safely */ - rfkill_epo(); - WARN(1, "Unknown requested operation %d! " - "rfkill Emergency Power Off activated\n", - op); - } -} - -#ifdef RFKILL_NEED_SWSET -static void __rfkill_handle_normal_op(const enum rfkill_type type, - const bool sp, const bool s, const bool c) -{ - enum rfkill_state state; - - if (sp) - state = (s) ? RFKILL_STATE_UNBLOCKED : - RFKILL_STATE_SOFT_BLOCKED; - else - state = rfkill_get_global_state(type); - - if (c) - state = rfkill_state_complement(state); - - rfkill_switch_all(type, state); -} -#else -static void __rfkill_handle_normal_op(const enum rfkill_type type, - const bool c) -{ - enum rfkill_state state; - - state = rfkill_get_global_state(type); - if (c) - state = rfkill_state_complement(state); - - rfkill_switch_all(type, state); -} -#endif - -static void rfkill_task_handler(struct work_struct *work) -{ - struct rfkill_task *task = container_of(work, - struct rfkill_task, dwork.work); - bool doit = true; - - mutex_lock(&task->mutex); - - spin_lock_irq(&task->lock); - while (doit) { - if (task->global_op_pending) { - enum rfkill_global_sched_op op = task->op; - task->global_op_pending = false; - memset(task->sw_pending, 0, sizeof(task->sw_pending)); - spin_unlock_irq(&task->lock); - - __rfkill_handle_global_op(op); - - /* make sure we do at least one pass with - * !task->global_op_pending */ - spin_lock_irq(&task->lock); - continue; - } else if (!rfkill_is_epo_lock_active()) { - unsigned int i = 0; - - while (!task->global_op_pending && - i < RFKILL_TYPE_MAX) { - if (test_and_clear_bit(i, task->sw_pending)) { - bool c; -#ifdef RFKILL_NEED_SWSET - bool sp, s; - sp = test_and_clear_bit(i, - task->sw_setpending); - s = test_bit(i, task->sw_newstate); -#endif - c = test_and_clear_bit(i, - task->sw_togglestate); - spin_unlock_irq(&task->lock); - -#ifdef RFKILL_NEED_SWSET - __rfkill_handle_normal_op(i, sp, s, c); -#else - __rfkill_handle_normal_op(i, c); -#endif - - spin_lock_irq(&task->lock); - } - i++; - } - } - doit = task->global_op_pending; - } - spin_unlock_irq(&task->lock); - - mutex_unlock(&task->mutex); -} - -static struct rfkill_task rfkill_task = { - .dwork = __DELAYED_WORK_INITIALIZER(rfkill_task.dwork, - rfkill_task_handler), - .mutex = __MUTEX_INITIALIZER(rfkill_task.mutex), - .lock = __SPIN_LOCK_UNLOCKED(rfkill_task.lock), -}; - -static unsigned long rfkill_ratelimit(const unsigned long last) -{ - const unsigned long delay = msecs_to_jiffies(RFKILL_OPS_DELAY); - return (time_after(jiffies, last + delay)) ? 0 : delay; -} - -static void rfkill_schedule_ratelimited(void) -{ - if (!delayed_work_pending(&rfkill_task.dwork)) { - schedule_delayed_work(&rfkill_task.dwork, - rfkill_ratelimit(rfkill_task.last_scheduled)); - rfkill_task.last_scheduled = jiffies; - } -} - -static void rfkill_schedule_global_op(enum rfkill_global_sched_op op) -{ - unsigned long flags; - - spin_lock_irqsave(&rfkill_task.lock, flags); - rfkill_task.op = op; - rfkill_task.global_op_pending = true; - if (op == RFKILL_GLOBAL_OP_EPO && !rfkill_is_epo_lock_active()) { - /* bypass the limiter for EPO */ - cancel_delayed_work(&rfkill_task.dwork); - schedule_delayed_work(&rfkill_task.dwork, 0); - rfkill_task.last_scheduled = jiffies; - } else - rfkill_schedule_ratelimited(); - spin_unlock_irqrestore(&rfkill_task.lock, flags); -} - -#ifdef RFKILL_NEED_SWSET -/* Use this if you need to add EV_SW SW_WLAN/WWAN/BLUETOOTH/etc handling */ - -static void rfkill_schedule_set(enum rfkill_type type, - enum rfkill_state desired_state) -{ - unsigned long flags; - - if (rfkill_is_epo_lock_active()) - return; - - spin_lock_irqsave(&rfkill_task.lock, flags); - if (!rfkill_task.global_op_pending) { - set_bit(type, rfkill_task.sw_pending); - set_bit(type, rfkill_task.sw_setpending); - clear_bit(type, rfkill_task.sw_togglestate); - if (desired_state) - set_bit(type, rfkill_task.sw_newstate); - else - clear_bit(type, rfkill_task.sw_newstate); - rfkill_schedule_ratelimited(); - } - spin_unlock_irqrestore(&rfkill_task.lock, flags); -} -#endif - -static void rfkill_schedule_toggle(enum rfkill_type type) -{ - unsigned long flags; - - if (rfkill_is_epo_lock_active()) - return; - - spin_lock_irqsave(&rfkill_task.lock, flags); - if (!rfkill_task.global_op_pending) { - set_bit(type, rfkill_task.sw_pending); - change_bit(type, rfkill_task.sw_togglestate); - rfkill_schedule_ratelimited(); - } - spin_unlock_irqrestore(&rfkill_task.lock, flags); -} - -static void rfkill_schedule_evsw_rfkillall(int state) -{ - if (state) { - switch (rfkill_master_switch_mode) { - case RFKILL_INPUT_MASTER_UNBLOCKALL: - rfkill_schedule_global_op(RFKILL_GLOBAL_OP_UNBLOCK); - break; - case RFKILL_INPUT_MASTER_RESTORE: - rfkill_schedule_global_op(RFKILL_GLOBAL_OP_RESTORE); - break; - case RFKILL_INPUT_MASTER_DONOTHING: - rfkill_schedule_global_op(RFKILL_GLOBAL_OP_UNLOCK); - break; - default: - /* memory corruption or driver bug! fail safely */ - rfkill_schedule_global_op(RFKILL_GLOBAL_OP_EPO); - WARN(1, "Unknown rfkill_master_switch_mode (%d), " - "driver bug or memory corruption detected!\n", - rfkill_master_switch_mode); - break; - } - } else - rfkill_schedule_global_op(RFKILL_GLOBAL_OP_EPO); -} - -static void rfkill_event(struct input_handle *handle, unsigned int type, - unsigned int code, int data) -{ - if (type == EV_KEY && data == 1) { - enum rfkill_type t; - - switch (code) { - case KEY_WLAN: - t = RFKILL_TYPE_WLAN; - break; - case KEY_BLUETOOTH: - t = RFKILL_TYPE_BLUETOOTH; - break; - case KEY_UWB: - t = RFKILL_TYPE_UWB; - break; - case KEY_WIMAX: - t = RFKILL_TYPE_WIMAX; - break; - default: - return; - } - rfkill_schedule_toggle(t); - return; - } else if (type == EV_SW) { - switch (code) { - case SW_RFKILL_ALL: - rfkill_schedule_evsw_rfkillall(data); - return; - default: - return; - } - } -} - -static int rfkill_connect(struct input_handler *handler, struct input_dev *dev, - const struct input_device_id *id) -{ - struct input_handle *handle; - int error; - - handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL); - if (!handle) - return -ENOMEM; - - handle->dev = dev; - handle->handler = handler; - handle->name = "rfkill"; - - /* causes rfkill_start() to be called */ - error = input_register_handle(handle); - if (error) - goto err_free_handle; - - error = input_open_device(handle); - if (error) - goto err_unregister_handle; - - return 0; - - err_unregister_handle: - input_unregister_handle(handle); - err_free_handle: - kfree(handle); - return error; -} - -static void rfkill_start(struct input_handle *handle) -{ - /* Take event_lock to guard against configuration changes, we - * should be able to deal with concurrency with rfkill_event() - * just fine (which event_lock will also avoid). */ - spin_lock_irq(&handle->dev->event_lock); - - if (test_bit(EV_SW, handle->dev->evbit)) { - if (test_bit(SW_RFKILL_ALL, handle->dev->swbit)) - rfkill_schedule_evsw_rfkillall(test_bit(SW_RFKILL_ALL, - handle->dev->sw)); - /* add resync for further EV_SW events here */ - } - - spin_unlock_irq(&handle->dev->event_lock); -} - -static void rfkill_disconnect(struct input_handle *handle) -{ - input_close_device(handle); - input_unregister_handle(handle); - kfree(handle); -} - -static const struct input_device_id rfkill_ids[] = { - { - .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, - .evbit = { BIT_MASK(EV_KEY) }, - .keybit = { [BIT_WORD(KEY_WLAN)] = BIT_MASK(KEY_WLAN) }, - }, - { - .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, - .evbit = { BIT_MASK(EV_KEY) }, - .keybit = { [BIT_WORD(KEY_BLUETOOTH)] = BIT_MASK(KEY_BLUETOOTH) }, - }, - { - .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, - .evbit = { BIT_MASK(EV_KEY) }, - .keybit = { [BIT_WORD(KEY_UWB)] = BIT_MASK(KEY_UWB) }, - }, - { - .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, - .evbit = { BIT_MASK(EV_KEY) }, - .keybit = { [BIT_WORD(KEY_WIMAX)] = BIT_MASK(KEY_WIMAX) }, - }, - { - .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_SWBIT, - .evbit = { BIT(EV_SW) }, - .swbit = { [BIT_WORD(SW_RFKILL_ALL)] = BIT_MASK(SW_RFKILL_ALL) }, - }, - { } -}; - -static struct input_handler rfkill_handler = { - .event = rfkill_event, - .connect = rfkill_connect, - .disconnect = rfkill_disconnect, - .start = rfkill_start, - .name = "rfkill", - .id_table = rfkill_ids, -}; - -static int __init rfkill_handler_init(void) -{ - if (rfkill_master_switch_mode >= RFKILL_INPUT_MASTER_MAX) - return -EINVAL; - - /* - * The penalty to not doing this is a possible RFKILL_OPS_DELAY delay - * at the first use. Acceptable, but if we can avoid it, why not? - */ - rfkill_task.last_scheduled = - jiffies - msecs_to_jiffies(RFKILL_OPS_DELAY) - 1; - return input_register_handler(&rfkill_handler); -} - -static void __exit rfkill_handler_exit(void) -{ - input_unregister_handler(&rfkill_handler); - cancel_delayed_work_sync(&rfkill_task.dwork); - rfkill_remove_epo_lock(); -} - -module_init(rfkill_handler_init); -module_exit(rfkill_handler_exit); diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c deleted file mode 100644 index 3eaa39403c13..000000000000 --- a/net/rfkill/rfkill.c +++ /dev/null @@ -1,882 +0,0 @@ -/* - * Copyright (C) 2006 - 2007 Ivo van Doorn - * Copyright (C) 2007 Dmitry Torokhov - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -/* Get declaration of rfkill_switch_all() to shut up sparse. */ -#include "rfkill-input.h" - - -MODULE_AUTHOR("Ivo van Doorn "); -MODULE_VERSION("1.0"); -MODULE_DESCRIPTION("RF switch support"); -MODULE_LICENSE("GPL"); - -static LIST_HEAD(rfkill_list); /* list of registered rf switches */ -static DEFINE_MUTEX(rfkill_global_mutex); - -static unsigned int rfkill_default_state = RFKILL_STATE_UNBLOCKED; -module_param_named(default_state, rfkill_default_state, uint, 0444); -MODULE_PARM_DESC(default_state, - "Default initial state for all radio types, 0 = radio off"); - -struct rfkill_gsw_state { - enum rfkill_state current_state; - enum rfkill_state default_state; -}; - -static struct rfkill_gsw_state rfkill_global_states[RFKILL_TYPE_MAX]; -static unsigned long rfkill_states_lockdflt[BITS_TO_LONGS(RFKILL_TYPE_MAX)]; -static bool rfkill_epo_lock_active; - - -#ifdef CONFIG_RFKILL_LEDS -static void rfkill_led_trigger(struct rfkill *rfkill, - enum rfkill_state state) -{ - struct led_trigger *led = &rfkill->led_trigger; - - if (!led->name) - return; - if (state != RFKILL_STATE_UNBLOCKED) - led_trigger_event(led, LED_OFF); - else - led_trigger_event(led, LED_FULL); -} - -static void rfkill_led_trigger_activate(struct led_classdev *led) -{ - struct rfkill *rfkill = container_of(led->trigger, - struct rfkill, led_trigger); - - rfkill_led_trigger(rfkill, rfkill->state); -} -#endif /* CONFIG_RFKILL_LEDS */ - -static void rfkill_uevent(struct rfkill *rfkill) -{ - kobject_uevent(&rfkill->dev.kobj, KOBJ_CHANGE); -} - -static void update_rfkill_state(struct rfkill *rfkill) -{ - enum rfkill_state newstate, oldstate; - - if (rfkill->get_state) { - mutex_lock(&rfkill->mutex); - if (!rfkill->get_state(rfkill->data, &newstate)) { - oldstate = rfkill->state; - rfkill->state = newstate; - if (oldstate != newstate) - rfkill_uevent(rfkill); - } - mutex_unlock(&rfkill->mutex); - } -} - -/** - * rfkill_toggle_radio - wrapper for toggle_radio hook - * @rfkill: the rfkill struct to use - * @force: calls toggle_radio even if cache says it is not needed, - * and also makes sure notifications of the state will be - * sent even if it didn't change - * @state: the new state to call toggle_radio() with - * - * Calls rfkill->toggle_radio, enforcing the API for toggle_radio - * calls and handling all the red tape such as issuing notifications - * if the call is successful. - * - * Suspended devices are not touched at all, and -EAGAIN is returned. - * - * Note that the @force parameter cannot override a (possibly cached) - * state of RFKILL_STATE_HARD_BLOCKED. Any device making use of - * RFKILL_STATE_HARD_BLOCKED implements either get_state() or - * rfkill_force_state(), so the cache either is bypassed or valid. - * - * Note that we do call toggle_radio for RFKILL_STATE_SOFT_BLOCKED - * even if the radio is in RFKILL_STATE_HARD_BLOCKED state, so as to - * give the driver a hint that it should double-BLOCK the transmitter. - * - * Caller must have acquired rfkill->mutex. - */ -static int rfkill_toggle_radio(struct rfkill *rfkill, - enum rfkill_state state, - int force) -{ - int retval = 0; - enum rfkill_state oldstate, newstate; - - if (unlikely(rfkill->dev.power.power_state.event & PM_EVENT_SLEEP)) - return -EBUSY; - - oldstate = rfkill->state; - - if (rfkill->get_state && !force && - !rfkill->get_state(rfkill->data, &newstate)) - rfkill->state = newstate; - - switch (state) { - case RFKILL_STATE_HARD_BLOCKED: - /* typically happens when refreshing hardware state, - * such as on resume */ - state = RFKILL_STATE_SOFT_BLOCKED; - break; - case RFKILL_STATE_UNBLOCKED: - /* force can't override this, only rfkill_force_state() can */ - if (rfkill->state == RFKILL_STATE_HARD_BLOCKED) - return -EPERM; - break; - case RFKILL_STATE_SOFT_BLOCKED: - /* nothing to do, we want to give drivers the hint to double - * BLOCK even a transmitter that is already in state - * RFKILL_STATE_HARD_BLOCKED */ - break; - default: - WARN(1, KERN_WARNING - "rfkill: illegal state %d passed as parameter " - "to rfkill_toggle_radio\n", state); - return -EINVAL; - } - - if (force || state != rfkill->state) { - retval = rfkill->toggle_radio(rfkill->data, state); - /* never allow a HARD->SOFT downgrade! */ - if (!retval && rfkill->state != RFKILL_STATE_HARD_BLOCKED) - rfkill->state = state; - } - - if (force || rfkill->state != oldstate) - rfkill_uevent(rfkill); - - return retval; -} - -/** - * __rfkill_switch_all - Toggle state of all switches of given type - * @type: type of interfaces to be affected - * @state: the new state - * - * This function toggles the state of all switches of given type, - * unless a specific switch is claimed by userspace (in which case, - * that switch is left alone) or suspended. - * - * Caller must have acquired rfkill_global_mutex. - */ -static void __rfkill_switch_all(const enum rfkill_type type, - const enum rfkill_state state) -{ - struct rfkill *rfkill; - - if (WARN((state >= RFKILL_STATE_MAX || type >= RFKILL_TYPE_MAX), - KERN_WARNING - "rfkill: illegal state %d or type %d " - "passed as parameter to __rfkill_switch_all\n", - state, type)) - return; - - rfkill_global_states[type].current_state = state; - list_for_each_entry(rfkill, &rfkill_list, node) { - if ((!rfkill->user_claim) && (rfkill->type == type)) { - mutex_lock(&rfkill->mutex); - rfkill_toggle_radio(rfkill, state, 0); - mutex_unlock(&rfkill->mutex); - } - } -} - -/** - * rfkill_switch_all - Toggle state of all switches of given type - * @type: type of interfaces to be affected - * @state: the new state - * - * Acquires rfkill_global_mutex and calls __rfkill_switch_all(@type, @state). - * Please refer to __rfkill_switch_all() for details. - * - * Does nothing if the EPO lock is active. - */ -void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state) -{ - mutex_lock(&rfkill_global_mutex); - if (!rfkill_epo_lock_active) - __rfkill_switch_all(type, state); - mutex_unlock(&rfkill_global_mutex); -} -EXPORT_SYMBOL(rfkill_switch_all); - -/** - * rfkill_epo - emergency power off all transmitters - * - * This kicks all non-suspended rfkill devices to RFKILL_STATE_SOFT_BLOCKED, - * ignoring everything in its path but rfkill_global_mutex and rfkill->mutex. - * - * The global state before the EPO is saved and can be restored later - * using rfkill_restore_states(). - */ -void rfkill_epo(void) -{ - struct rfkill *rfkill; - int i; - - mutex_lock(&rfkill_global_mutex); - - rfkill_epo_lock_active = true; - list_for_each_entry(rfkill, &rfkill_list, node) { - mutex_lock(&rfkill->mutex); - rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1); - mutex_unlock(&rfkill->mutex); - } - for (i = 0; i < RFKILL_TYPE_MAX; i++) { - rfkill_global_states[i].default_state = - rfkill_global_states[i].current_state; - rfkill_global_states[i].current_state = - RFKILL_STATE_SOFT_BLOCKED; - } - mutex_unlock(&rfkill_global_mutex); -} -EXPORT_SYMBOL_GPL(rfkill_epo); - -/** - * rfkill_restore_states - restore global states - * - * Restore (and sync switches to) the global state from the - * states in rfkill_default_states. This can undo the effects of - * a call to rfkill_epo(). - */ -void rfkill_restore_states(void) -{ - int i; - - mutex_lock(&rfkill_global_mutex); - - rfkill_epo_lock_active = false; - for (i = 0; i < RFKILL_TYPE_MAX; i++) - __rfkill_switch_all(i, rfkill_global_states[i].default_state); - mutex_unlock(&rfkill_global_mutex); -} -EXPORT_SYMBOL_GPL(rfkill_restore_states); - -/** - * rfkill_remove_epo_lock - unlock state changes - * - * Used by rfkill-input manually unlock state changes, when - * the EPO switch is deactivated. - */ -void rfkill_remove_epo_lock(void) -{ - mutex_lock(&rfkill_global_mutex); - rfkill_epo_lock_active = false; - mutex_unlock(&rfkill_global_mutex); -} -EXPORT_SYMBOL_GPL(rfkill_remove_epo_lock); - -/** - * rfkill_is_epo_lock_active - returns true EPO is active - * - * Returns 0 (false) if there is NOT an active EPO contidion, - * and 1 (true) if there is an active EPO contition, which - * locks all radios in one of the BLOCKED states. - * - * Can be called in atomic context. - */ -bool rfkill_is_epo_lock_active(void) -{ - return rfkill_epo_lock_active; -} -EXPORT_SYMBOL_GPL(rfkill_is_epo_lock_active); - -/** - * rfkill_get_global_state - returns global state for a type - * @type: the type to get the global state of - * - * Returns the current global state for a given wireless - * device type. - */ -enum rfkill_state rfkill_get_global_state(const enum rfkill_type type) -{ - return rfkill_global_states[type].current_state; -} -EXPORT_SYMBOL_GPL(rfkill_get_global_state); - -/** - * rfkill_force_state - Force the internal rfkill radio state - * @rfkill: pointer to the rfkill class to modify. - * @state: the current radio state the class should be forced to. - * - * This function updates the internal state of the radio cached - * by the rfkill class. It should be used when the driver gets - * a notification by the firmware/hardware of the current *real* - * state of the radio rfkill switch. - * - * Devices which are subject to external changes on their rfkill - * state (such as those caused by a hardware rfkill line) MUST - * have their driver arrange to call rfkill_force_state() as soon - * as possible after such a change. - * - * This function may not be called from an atomic context. - */ -int rfkill_force_state(struct rfkill *rfkill, enum rfkill_state state) -{ - enum rfkill_state oldstate; - - BUG_ON(!rfkill); - if (WARN((state >= RFKILL_STATE_MAX), - KERN_WARNING - "rfkill: illegal state %d passed as parameter " - "to rfkill_force_state\n", state)) - return -EINVAL; - - mutex_lock(&rfkill->mutex); - - oldstate = rfkill->state; - rfkill->state = state; - - if (state != oldstate) - rfkill_uevent(rfkill); - - mutex_unlock(&rfkill->mutex); - - return 0; -} -EXPORT_SYMBOL(rfkill_force_state); - -static ssize_t rfkill_name_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct rfkill *rfkill = to_rfkill(dev); - - return sprintf(buf, "%s\n", rfkill->name); -} - -static const char *rfkill_get_type_str(enum rfkill_type type) -{ - switch (type) { - case RFKILL_TYPE_WLAN: - return "wlan"; - case RFKILL_TYPE_BLUETOOTH: - return "bluetooth"; - case RFKILL_TYPE_UWB: - return "ultrawideband"; - case RFKILL_TYPE_WIMAX: - return "wimax"; - case RFKILL_TYPE_WWAN: - return "wwan"; - default: - BUG(); - } -} - -static ssize_t rfkill_type_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct rfkill *rfkill = to_rfkill(dev); - - return sprintf(buf, "%s\n", rfkill_get_type_str(rfkill->type)); -} - -static ssize_t rfkill_state_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct rfkill *rfkill = to_rfkill(dev); - - update_rfkill_state(rfkill); - return sprintf(buf, "%d\n", rfkill->state); -} - -static ssize_t rfkill_state_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct rfkill *rfkill = to_rfkill(dev); - unsigned long state; - int error; - - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - error = strict_strtoul(buf, 0, &state); - if (error) - return error; - - /* RFKILL_STATE_HARD_BLOCKED is illegal here... */ - if (state != RFKILL_STATE_UNBLOCKED && - state != RFKILL_STATE_SOFT_BLOCKED) - return -EINVAL; - - error = mutex_lock_killable(&rfkill->mutex); - if (error) - return error; - - if (!rfkill_epo_lock_active) - error = rfkill_toggle_radio(rfkill, state, 0); - else - error = -EPERM; - - mutex_unlock(&rfkill->mutex); - - return error ? error : count; -} - -static ssize_t rfkill_claim_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct rfkill *rfkill = to_rfkill(dev); - - return sprintf(buf, "%d\n", rfkill->user_claim); -} - -static ssize_t rfkill_claim_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct rfkill *rfkill = to_rfkill(dev); - unsigned long claim_tmp; - bool claim; - int error; - - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - if (rfkill->user_claim_unsupported) - return -EOPNOTSUPP; - - error = strict_strtoul(buf, 0, &claim_tmp); - if (error) - return error; - claim = !!claim_tmp; - - /* - * Take the global lock to make sure the kernel is not in - * the middle of rfkill_switch_all - */ - error = mutex_lock_killable(&rfkill_global_mutex); - if (error) - return error; - - if (rfkill->user_claim != claim) { - if (!claim && !rfkill_epo_lock_active) { - mutex_lock(&rfkill->mutex); - rfkill_toggle_radio(rfkill, - rfkill_global_states[rfkill->type].current_state, - 0); - mutex_unlock(&rfkill->mutex); - } - rfkill->user_claim = claim; - } - - mutex_unlock(&rfkill_global_mutex); - - return error ? error : count; -} - -static struct device_attribute rfkill_dev_attrs[] = { - __ATTR(name, S_IRUGO, rfkill_name_show, NULL), - __ATTR(type, S_IRUGO, rfkill_type_show, NULL), - __ATTR(state, S_IRUGO|S_IWUSR, rfkill_state_show, rfkill_state_store), - __ATTR(claim, S_IRUGO|S_IWUSR, rfkill_claim_show, rfkill_claim_store), - __ATTR_NULL -}; - -static void rfkill_release(struct device *dev) -{ - struct rfkill *rfkill = to_rfkill(dev); - - kfree(rfkill); - module_put(THIS_MODULE); -} - -#ifdef CONFIG_PM -static int rfkill_suspend(struct device *dev, pm_message_t state) -{ - struct rfkill *rfkill = to_rfkill(dev); - - /* mark class device as suspended */ - if (dev->power.power_state.event != state.event) - dev->power.power_state = state; - - /* store state for the resume handler */ - rfkill->state_for_resume = rfkill->state; - - return 0; -} - -static int rfkill_resume(struct device *dev) -{ - struct rfkill *rfkill = to_rfkill(dev); - enum rfkill_state newstate; - - if (dev->power.power_state.event != PM_EVENT_ON) { - mutex_lock(&rfkill->mutex); - - dev->power.power_state.event = PM_EVENT_ON; - - /* - * rfkill->state could have been modified before we got - * called, and won't be updated by rfkill_toggle_radio() - * in force mode. Sync it FIRST. - */ - if (rfkill->get_state && - !rfkill->get_state(rfkill->data, &newstate)) - rfkill->state = newstate; - - /* - * If we are under EPO, kick transmitter offline, - * otherwise restore to pre-suspend state. - * - * Issue a notification in any case - */ - rfkill_toggle_radio(rfkill, - rfkill_epo_lock_active ? - RFKILL_STATE_SOFT_BLOCKED : - rfkill->state_for_resume, - 1); - - mutex_unlock(&rfkill->mutex); - } - - return 0; -} -#else -#define rfkill_suspend NULL -#define rfkill_resume NULL -#endif - -static int rfkill_dev_uevent(struct device *dev, struct kobj_uevent_env *env) -{ - struct rfkill *rfkill = to_rfkill(dev); - int error; - - error = add_uevent_var(env, "RFKILL_NAME=%s", rfkill->name); - if (error) - return error; - error = add_uevent_var(env, "RFKILL_TYPE=%s", - rfkill_get_type_str(rfkill->type)); - if (error) - return error; - error = add_uevent_var(env, "RFKILL_STATE=%d", rfkill->state); - return error; -} - -static struct class rfkill_class = { - .name = "rfkill", - .dev_release = rfkill_release, - .dev_attrs = rfkill_dev_attrs, - .suspend = rfkill_suspend, - .resume = rfkill_resume, - .dev_uevent = rfkill_dev_uevent, -}; - -static int rfkill_check_duplicity(const struct rfkill *rfkill) -{ - struct rfkill *p; - unsigned long seen[BITS_TO_LONGS(RFKILL_TYPE_MAX)]; - - memset(seen, 0, sizeof(seen)); - - list_for_each_entry(p, &rfkill_list, node) { - if (WARN((p == rfkill), KERN_WARNING - "rfkill: illegal attempt to register " - "an already registered rfkill struct\n")) - return -EEXIST; - set_bit(p->type, seen); - } - - /* 0: first switch of its kind */ - return (test_bit(rfkill->type, seen)) ? 1 : 0; -} - -static int rfkill_add_switch(struct rfkill *rfkill) -{ - int error; - - mutex_lock(&rfkill_global_mutex); - - error = rfkill_check_duplicity(rfkill); - if (error < 0) - goto unlock_out; - - if (!error) { - /* lock default after first use */ - set_bit(rfkill->type, rfkill_states_lockdflt); - rfkill_global_states[rfkill->type].current_state = - rfkill_global_states[rfkill->type].default_state; - } - - rfkill_toggle_radio(rfkill, - rfkill_global_states[rfkill->type].current_state, - 0); - - list_add_tail(&rfkill->node, &rfkill_list); - - error = 0; -unlock_out: - mutex_unlock(&rfkill_global_mutex); - - return error; -} - -static void rfkill_remove_switch(struct rfkill *rfkill) -{ - mutex_lock(&rfkill_global_mutex); - list_del_init(&rfkill->node); - mutex_unlock(&rfkill_global_mutex); - - mutex_lock(&rfkill->mutex); - rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1); - mutex_unlock(&rfkill->mutex); -} - -/** - * rfkill_allocate - allocate memory for rfkill structure. - * @parent: device that has rf switch on it - * @type: type of the switch (RFKILL_TYPE_*) - * - * This function should be called by the network driver when it needs - * rfkill structure. Once the structure is allocated the driver should - * finish its initialization by setting the name, private data, enable_radio - * and disable_radio methods and then register it with rfkill_register(). - * - * NOTE: If registration fails the structure shoudl be freed by calling - * rfkill_free() otherwise rfkill_unregister() should be used. - */ -struct rfkill * __must_check rfkill_allocate(struct device *parent, - enum rfkill_type type) -{ - struct rfkill *rfkill; - struct device *dev; - - if (WARN((type >= RFKILL_TYPE_MAX), - KERN_WARNING - "rfkill: illegal type %d passed as parameter " - "to rfkill_allocate\n", type)) - return NULL; - - rfkill = kzalloc(sizeof(struct rfkill), GFP_KERNEL); - if (!rfkill) - return NULL; - - mutex_init(&rfkill->mutex); - INIT_LIST_HEAD(&rfkill->node); - rfkill->type = type; - - dev = &rfkill->dev; - dev->class = &rfkill_class; - dev->parent = parent; - device_initialize(dev); - - __module_get(THIS_MODULE); - - return rfkill; -} -EXPORT_SYMBOL(rfkill_allocate); - -/** - * rfkill_free - Mark rfkill structure for deletion - * @rfkill: rfkill structure to be destroyed - * - * Decrements reference count of the rfkill structure so it is destroyed. - * Note that rfkill_free() should _not_ be called after rfkill_unregister(). - */ -void rfkill_free(struct rfkill *rfkill) -{ - if (rfkill) - put_device(&rfkill->dev); -} -EXPORT_SYMBOL(rfkill_free); - -static void rfkill_led_trigger_register(struct rfkill *rfkill) -{ -#ifdef CONFIG_RFKILL_LEDS - int error; - - if (!rfkill->led_trigger.name) - rfkill->led_trigger.name = dev_name(&rfkill->dev); - if (!rfkill->led_trigger.activate) - rfkill->led_trigger.activate = rfkill_led_trigger_activate; - error = led_trigger_register(&rfkill->led_trigger); - if (error) - rfkill->led_trigger.name = NULL; -#endif /* CONFIG_RFKILL_LEDS */ -} - -static void rfkill_led_trigger_unregister(struct rfkill *rfkill) -{ -#ifdef CONFIG_RFKILL_LEDS - if (rfkill->led_trigger.name) { - led_trigger_unregister(&rfkill->led_trigger); - rfkill->led_trigger.name = NULL; - } -#endif -} - -/** - * rfkill_register - Register a rfkill structure. - * @rfkill: rfkill structure to be registered - * - * This function should be called by the network driver when the rfkill - * structure needs to be registered. Immediately from registration the - * switch driver should be able to service calls to toggle_radio. - */ -int __must_check rfkill_register(struct rfkill *rfkill) -{ - static atomic_t rfkill_no = ATOMIC_INIT(0); - struct device *dev = &rfkill->dev; - int error; - - if (WARN((!rfkill || !rfkill->toggle_radio || - rfkill->type >= RFKILL_TYPE_MAX || - rfkill->state >= RFKILL_STATE_MAX), - KERN_WARNING - "rfkill: attempt to register a " - "badly initialized rfkill struct\n")) - return -EINVAL; - - dev_set_name(dev, "rfkill%ld", (long)atomic_inc_return(&rfkill_no) - 1); - - rfkill_led_trigger_register(rfkill); - - error = rfkill_add_switch(rfkill); - if (error) { - rfkill_led_trigger_unregister(rfkill); - return error; - } - - error = device_add(dev); - if (error) { - rfkill_remove_switch(rfkill); - rfkill_led_trigger_unregister(rfkill); - return error; - } - - return 0; -} -EXPORT_SYMBOL(rfkill_register); - -/** - * rfkill_unregister - Unregister a rfkill structure. - * @rfkill: rfkill structure to be unregistered - * - * This function should be called by the network driver during device - * teardown to destroy rfkill structure. Note that rfkill_free() should - * _not_ be called after rfkill_unregister(). - */ -void rfkill_unregister(struct rfkill *rfkill) -{ - BUG_ON(!rfkill); - device_del(&rfkill->dev); - rfkill_remove_switch(rfkill); - rfkill_led_trigger_unregister(rfkill); - put_device(&rfkill->dev); -} -EXPORT_SYMBOL(rfkill_unregister); - -/** - * rfkill_set_default - set initial value for a switch type - * @type - the type of switch to set the default state of - * @state - the new default state for that group of switches - * - * Sets the initial state rfkill should use for a given type. - * The following initial states are allowed: RFKILL_STATE_SOFT_BLOCKED - * and RFKILL_STATE_UNBLOCKED. - * - * This function is meant to be used by platform drivers for platforms - * that can save switch state across power down/reboot. - * - * The default state for each switch type can be changed exactly once. - * After a switch of that type is registered, the default state cannot - * be changed anymore. This guards against multiple drivers it the - * same platform trying to set the initial switch default state, which - * is not allowed. - * - * Returns -EPERM if the state has already been set once or is in use, - * so drivers likely want to either ignore or at most printk(KERN_NOTICE) - * if this function returns -EPERM. - * - * Returns 0 if the new default state was set, or an error if it - * could not be set. - */ -int rfkill_set_default(enum rfkill_type type, enum rfkill_state state) -{ - int error; - - if (WARN((type >= RFKILL_TYPE_MAX || - (state != RFKILL_STATE_SOFT_BLOCKED && - state != RFKILL_STATE_UNBLOCKED)), - KERN_WARNING - "rfkill: illegal state %d or type %d passed as " - "parameter to rfkill_set_default\n", state, type)) - return -EINVAL; - - mutex_lock(&rfkill_global_mutex); - - if (!test_and_set_bit(type, rfkill_states_lockdflt)) { - rfkill_global_states[type].default_state = state; - rfkill_global_states[type].current_state = state; - error = 0; - } else - error = -EPERM; - - mutex_unlock(&rfkill_global_mutex); - return error; -} -EXPORT_SYMBOL_GPL(rfkill_set_default); - -/* - * Rfkill module initialization/deinitialization. - */ -static int __init rfkill_init(void) -{ - int error; - int i; - - /* RFKILL_STATE_HARD_BLOCKED is illegal here... */ - if (rfkill_default_state != RFKILL_STATE_SOFT_BLOCKED && - rfkill_default_state != RFKILL_STATE_UNBLOCKED) - return -EINVAL; - - for (i = 0; i < RFKILL_TYPE_MAX; i++) - rfkill_global_states[i].default_state = rfkill_default_state; - - error = class_register(&rfkill_class); - if (error) { - printk(KERN_ERR "rfkill: unable to register rfkill class\n"); - return error; - } - - return 0; -} - -static void __exit rfkill_exit(void) -{ - class_unregister(&rfkill_class); -} - -subsys_initcall(rfkill_init); -module_exit(rfkill_exit); diff --git a/net/rfkill/rfkill-input.h b/net/rfkill/rfkill.h similarity index 60% rename from net/rfkill/rfkill-input.h rename to net/rfkill/rfkill.h index fe8df6b5b935..d1117cb6e4de 100644 --- a/net/rfkill/rfkill-input.h +++ b/net/rfkill/rfkill.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2007 Ivo van Doorn + * Copyright 2009 Johannes Berg */ /* @@ -11,11 +12,16 @@ #ifndef __RFKILL_INPUT_H #define __RFKILL_INPUT_H -void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state); +/* core code */ +void rfkill_switch_all(const enum rfkill_type type, bool blocked); void rfkill_epo(void); void rfkill_restore_states(void); void rfkill_remove_epo_lock(void); bool rfkill_is_epo_lock_active(void); -enum rfkill_state rfkill_get_global_state(const enum rfkill_type type); +bool rfkill_get_global_sw_state(const enum rfkill_type type); + +/* input handler */ +int rfkill_handler_init(void); +void rfkill_handler_exit(void); #endif /* __RFKILL_INPUT_H */ diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index 877a7f65f707..6bd8e93869ed 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c @@ -356,8 +356,7 @@ void rose_destroy_socket(struct sock *sk) kfree_skb(skb); } - if (atomic_read(&sk->sk_wmem_alloc) || - atomic_read(&sk->sk_rmem_alloc)) { + if (sk_has_allocations(sk)) { /* Defer: outstanding buffers */ setup_timer(&sk->sk_timer, rose_destroy_timer, (unsigned long)sk); @@ -1310,7 +1309,8 @@ static int rose_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) switch (cmd) { case TIOCOUTQ: { long amount; - amount = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc); + + amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk); if (amount < 0) amount = 0; return put_user(amount, (unsigned int __user *) argp); @@ -1481,8 +1481,8 @@ static int rose_info_show(struct seq_file *seq, void *v) rose->hb / HZ, ax25_display_timer(&rose->idletimer) / (60 * HZ), rose->idle / (60 * HZ), - atomic_read(&s->sk_wmem_alloc), - atomic_read(&s->sk_rmem_alloc), + sk_wmem_alloc_get(s), + sk_rmem_alloc_get(s), s->sk_socket ? SOCK_INODE(s->sk_socket)->i_ino : 0L); } diff --git a/net/rose/rose_dev.c b/net/rose/rose_dev.c index 7dcf2569613b..389d6e0d7740 100644 --- a/net/rose/rose_dev.c +++ b/net/rose/rose_dev.c @@ -137,7 +137,7 @@ static int rose_xmit(struct sk_buff *skb, struct net_device *dev) if (!netif_running(dev)) { printk(KERN_ERR "ROSE: rose_xmit - called when iface is down\n"); - return 1; + return NETDEV_TX_BUSY; } dev_kfree_skb(skb); stats->tx_errors++; diff --git a/net/rxrpc/ar-connection.c b/net/rxrpc/ar-connection.c index 67e38a056240..9f1ce841a0bb 100644 --- a/net/rxrpc/ar-connection.c +++ b/net/rxrpc/ar-connection.c @@ -444,6 +444,11 @@ int rxrpc_connect_call(struct rxrpc_sock *rx, conn = list_entry(bundle->avail_conns.next, struct rxrpc_connection, bundle_link); + if (conn->state >= RXRPC_CONN_REMOTELY_ABORTED) { + list_del_init(&conn->bundle_link); + bundle->num_conns--; + continue; + } if (--conn->avail_calls == 0) list_move(&conn->bundle_link, &bundle->busy_conns); @@ -461,6 +466,11 @@ int rxrpc_connect_call(struct rxrpc_sock *rx, conn = list_entry(bundle->unused_conns.next, struct rxrpc_connection, bundle_link); + if (conn->state >= RXRPC_CONN_REMOTELY_ABORTED) { + list_del_init(&conn->bundle_link); + bundle->num_conns--; + continue; + } ASSERTCMP(conn->avail_calls, ==, RXRPC_MAXCALLS); conn->avail_calls = RXRPC_MAXCALLS - 1; ASSERT(conn->channels[0] == NULL && diff --git a/net/rxrpc/ar-connevent.c b/net/rxrpc/ar-connevent.c index dc5cb1e19509..0505cdc4d6d4 100644 --- a/net/rxrpc/ar-connevent.c +++ b/net/rxrpc/ar-connevent.c @@ -150,11 +150,15 @@ static int rxrpc_process_event(struct rxrpc_connection *conn, u32 serial; int loop, ret; - if (conn->state >= RXRPC_CONN_REMOTELY_ABORTED) + if (conn->state >= RXRPC_CONN_REMOTELY_ABORTED) { + kleave(" = -ECONNABORTED [%u]", conn->state); return -ECONNABORTED; + } serial = ntohl(sp->hdr.serial); + _enter("{%d},{%u,%%%u},", conn->debug_id, sp->hdr.type, serial); + switch (sp->hdr.type) { case RXRPC_PACKET_TYPE_ABORT: if (skb_copy_bits(skb, 0, &tmp, sizeof(tmp)) < 0) @@ -199,6 +203,7 @@ static int rxrpc_process_event(struct rxrpc_connection *conn, return 0; default: + _leave(" = -EPROTO [%u]", sp->hdr.type); return -EPROTO; } } diff --git a/net/sched/act_police.c b/net/sched/act_police.c index f8f047b61245..723964c3ee4f 100644 --- a/net/sched/act_police.c +++ b/net/sched/act_police.c @@ -294,6 +294,8 @@ static int tcf_act_police(struct sk_buff *skb, struct tc_action *a, if (police->tcfp_ewma_rate && police->tcf_rate_est.bps >= police->tcfp_ewma_rate) { police->tcf_qstats.overlimits++; + if (police->tcf_action == TC_ACT_SHOT) + police->tcf_qstats.drops++; spin_unlock(&police->tcf_lock); return police->tcf_action; } @@ -327,6 +329,8 @@ static int tcf_act_police(struct sk_buff *skb, struct tc_action *a, } police->tcf_qstats.overlimits++; + if (police->tcf_action == TC_ACT_SHOT) + police->tcf_qstats.drops++; spin_unlock(&police->tcf_lock); return police->tcf_action; } diff --git a/net/sched/cls_cgroup.c b/net/sched/cls_cgroup.c index e5becb92b3e7..e4877ca6727c 100644 --- a/net/sched/cls_cgroup.c +++ b/net/sched/cls_cgroup.c @@ -62,13 +62,7 @@ static u64 read_classid(struct cgroup *cgrp, struct cftype *cft) static int write_classid(struct cgroup *cgrp, struct cftype *cft, u64 value) { - if (!cgroup_lock_live_group(cgrp)) - return -ENODEV; - cgrp_cls_state(cgrp)->classid = (u32) value; - - cgroup_unlock(); - return 0; } diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c index 0ef4e3065bcd..9402a7fd3785 100644 --- a/net/sched/cls_flow.c +++ b/net/sched/cls_flow.c @@ -84,7 +84,7 @@ static u32 flow_get_dst(const struct sk_buff *skb) case htons(ETH_P_IPV6): return ntohl(ipv6_hdr(skb)->daddr.s6_addr32[3]); default: - return addr_fold(skb->dst) ^ (__force u16)skb->protocol; + return addr_fold(skb_dst(skb)) ^ (__force u16)skb->protocol; } } @@ -163,7 +163,7 @@ static u32 flow_get_proto_dst(const struct sk_buff *skb) break; } default: - res = addr_fold(skb->dst) ^ (__force u16)skb->protocol; + res = addr_fold(skb_dst(skb)) ^ (__force u16)skb->protocol; } return res; @@ -251,8 +251,8 @@ fallback: static u32 flow_get_rtclassid(const struct sk_buff *skb) { #ifdef CONFIG_NET_CLS_ROUTE - if (skb->dst) - return skb->dst->tclassid; + if (skb_dst(skb)) + return skb_dst(skb)->tclassid; #endif return 0; } diff --git a/net/sched/cls_route.c b/net/sched/cls_route.c index bdf1f4172eef..dd872d5383ef 100644 --- a/net/sched/cls_route.c +++ b/net/sched/cls_route.c @@ -137,7 +137,7 @@ static int route4_classify(struct sk_buff *skb, struct tcf_proto *tp, u32 id, h; int iif, dont_cache = 0; - if ((dst = skb->dst) == NULL) + if ((dst = skb_dst(skb)) == NULL) goto failure; id = dst->tclassid; diff --git a/net/sched/em_meta.c b/net/sched/em_meta.c index fad596bf32d7..18d85d259104 100644 --- a/net/sched/em_meta.c +++ b/net/sched/em_meta.c @@ -246,11 +246,11 @@ META_COLLECTOR(int_tcindex) META_COLLECTOR(int_rtclassid) { - if (unlikely(skb->dst == NULL)) + if (unlikely(skb_dst(skb) == NULL)) *err = -1; else #ifdef CONFIG_NET_CLS_ROUTE - dst->value = skb->dst->tclassid; + dst->value = skb_dst(skb)->tclassid; #else dst->value = 0; #endif @@ -258,10 +258,10 @@ META_COLLECTOR(int_rtclassid) META_COLLECTOR(int_rtiif) { - if (unlikely(skb->rtable == NULL)) + if (unlikely(skb_rtable(skb) == NULL)) *err = -1; else - dst->value = skb->rtable->fl.iif; + dst->value = skb_rtable(skb)->fl.iif; } /************************************************************************** @@ -349,13 +349,13 @@ META_COLLECTOR(int_sk_type) META_COLLECTOR(int_sk_rmem_alloc) { SKIP_NONLOCAL(skb); - dst->value = atomic_read(&skb->sk->sk_rmem_alloc); + dst->value = sk_rmem_alloc_get(skb->sk); } META_COLLECTOR(int_sk_wmem_alloc) { SKIP_NONLOCAL(skb); - dst->value = atomic_read(&skb->sk->sk_wmem_alloc); + dst->value = sk_wmem_alloc_get(skb->sk); } META_COLLECTOR(int_sk_omem_alloc) diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 32009793307b..24d17ce9c294 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -484,7 +484,7 @@ void qdisc_watchdog_schedule(struct qdisc_watchdog *wd, psched_time_t expires) wd->qdisc->flags |= TCQ_F_THROTTLED; time = ktime_set(0, 0); - time = ktime_add_ns(time, PSCHED_US2NS(expires)); + time = ktime_add_ns(time, PSCHED_TICKS2NS(expires)); hrtimer_start(&wd->timer, time, HRTIMER_MODE_ABS); } EXPORT_SYMBOL(qdisc_watchdog_schedule); @@ -1680,7 +1680,7 @@ static int psched_show(struct seq_file *seq, void *v) hrtimer_get_res(CLOCK_MONOTONIC, &ts); seq_printf(seq, "%08x %08x %08x %08x\n", - (u32)NSEC_PER_USEC, (u32)PSCHED_US2NS(1), + (u32)NSEC_PER_USEC, (u32)PSCHED_TICKS2NS(1), 1000000, (u32)NSEC_PER_SEC/(u32)ktime_to_ns(timespec_to_ktime(ts))); diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c index d728d8111732..23a167670fd5 100644 --- a/net/sched/sch_cbq.c +++ b/net/sched/sch_cbq.c @@ -509,7 +509,7 @@ static void cbq_ovl_delay(struct cbq_class *cl) q->pmask |= (1<delay_timer) && ktime_to_ns(ktime_sub( hrtimer_get_expires(&q->delay_timer), @@ -620,7 +620,7 @@ static enum hrtimer_restart cbq_undelay(struct hrtimer *timer) ktime_t time; time = ktime_set(0, 0); - time = ktime_add_ns(time, PSCHED_US2NS(now + delay)); + time = ktime_add_ns(time, PSCHED_TICKS2NS(now + delay)); hrtimer_start(&q->delay_timer, time, HRTIMER_MODE_ABS); } diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 5f5efe4e6072..27d03816ec3e 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -196,6 +196,21 @@ void __qdisc_run(struct Qdisc *q) clear_bit(__QDISC_STATE_RUNNING, &q->state); } +unsigned long dev_trans_start(struct net_device *dev) +{ + unsigned long val, res = dev->trans_start; + unsigned int i; + + for (i = 0; i < dev->num_tx_queues; i++) { + val = netdev_get_tx_queue(dev, i)->trans_start; + if (val && time_after(val, res)) + res = val; + } + dev->trans_start = res; + return res; +} +EXPORT_SYMBOL(dev_trans_start); + static void dev_watchdog(unsigned long arg) { struct net_device *dev = (struct net_device *)arg; @@ -205,25 +220,30 @@ static void dev_watchdog(unsigned long arg) if (netif_device_present(dev) && netif_running(dev) && netif_carrier_ok(dev)) { - int some_queue_stopped = 0; + int some_queue_timedout = 0; unsigned int i; + unsigned long trans_start; for (i = 0; i < dev->num_tx_queues; i++) { struct netdev_queue *txq; txq = netdev_get_tx_queue(dev, i); - if (netif_tx_queue_stopped(txq)) { - some_queue_stopped = 1; + /* + * old device drivers set dev->trans_start + */ + trans_start = txq->trans_start ? : dev->trans_start; + if (netif_tx_queue_stopped(txq) && + time_after(jiffies, (trans_start + + dev->watchdog_timeo))) { + some_queue_timedout = 1; break; } } - if (some_queue_stopped && - time_after(jiffies, (dev->trans_start + - dev->watchdog_timeo))) { + if (some_queue_timedout) { char drivername[64]; - WARN_ONCE(1, KERN_INFO "NETDEV WATCHDOG: %s (%s): transmit timed out\n", - dev->name, netdev_drivername(dev, drivername, 64)); + WARN_ONCE(1, KERN_INFO "NETDEV WATCHDOG: %s (%s): transmit queue %u timed out\n", + dev->name, netdev_drivername(dev, drivername, 64), i); dev->netdev_ops->ndo_tx_timeout(dev); } if (!mod_timer(&dev->watchdog_timer, @@ -602,8 +622,10 @@ static void transition_one_qdisc(struct net_device *dev, clear_bit(__QDISC_STATE_DEACTIVATED, &new_qdisc->state); rcu_assign_pointer(dev_queue->qdisc, new_qdisc); - if (need_watchdog_p && new_qdisc != &noqueue_qdisc) + if (need_watchdog_p && new_qdisc != &noqueue_qdisc) { + dev_queue->trans_start = 0; *need_watchdog_p = 1; + } } void dev_activate(struct net_device *dev) diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c index 5022f9c1f34b..362c2811b2df 100644 --- a/net/sched/sch_hfsc.c +++ b/net/sched/sch_hfsc.c @@ -372,7 +372,7 @@ cftree_update(struct hfsc_class *cl) * ism: (psched_us/byte) << ISM_SHIFT * dx: psched_us * - * The clock source resolution with ktime is 1.024us. + * The clock source resolution with ktime and PSCHED_SHIFT 10 is 1.024us. * * sm and ism are scaled in order to keep effective digits. * SM_SHIFT and ISM_SHIFT are selected to keep at least 4 effective @@ -383,9 +383,11 @@ cftree_update(struct hfsc_class *cl) * bytes/1.024us 12.8e-3 128e-3 1280e-3 12800e-3 128000e-3 * * 1.024us/byte 78.125 7.8125 0.78125 0.078125 0.0078125 + * + * So, for PSCHED_SHIFT 10 we need: SM_SHIFT 20, ISM_SHIFT 18. */ -#define SM_SHIFT 20 -#define ISM_SHIFT 18 +#define SM_SHIFT (30 - PSCHED_SHIFT) +#define ISM_SHIFT (8 + PSCHED_SHIFT) #define SM_MASK ((1ULL << SM_SHIFT) - 1) #define ISM_MASK ((1ULL << ISM_SHIFT) - 1) diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c index 33133d27b539..8706920a6d45 100644 --- a/net/sched/sch_sfq.c +++ b/net/sched/sch_sfq.c @@ -149,7 +149,7 @@ static unsigned sfq_hash(struct sfq_sched_data *q, struct sk_buff *skb) break; } default: - h = (unsigned long)skb->dst ^ skb->protocol; + h = (unsigned long)skb_dst(skb) ^ skb->protocol; h2 = (unsigned long)skb->sk; } diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c index 3b6418297231..9c002b6e0533 100644 --- a/net/sched/sch_teql.c +++ b/net/sched/sch_teql.c @@ -58,7 +58,6 @@ struct teql_master struct net_device *dev; struct Qdisc *slaves; struct list_head master_list; - struct net_device_stats stats; }; struct teql_sched_data @@ -223,7 +222,7 @@ __teql_resolve(struct sk_buff *skb, struct sk_buff *skb_res, struct net_device * { struct netdev_queue *dev_queue = netdev_get_tx_queue(dev, 0); struct teql_sched_data *q = qdisc_priv(dev_queue->qdisc); - struct neighbour *mn = skb->dst->neighbour; + struct neighbour *mn = skb_dst(skb)->neighbour; struct neighbour *n = q->ncache; if (mn->tbl == NULL) @@ -263,8 +262,8 @@ static inline int teql_resolve(struct sk_buff *skb, return -ENODEV; if (dev->header_ops == NULL || - skb->dst == NULL || - skb->dst->neighbour == NULL) + skb_dst(skb) == NULL || + skb_dst(skb)->neighbour == NULL) return 0; return __teql_resolve(skb, skb_res, dev); } @@ -272,6 +271,7 @@ static inline int teql_resolve(struct sk_buff *skb, static int teql_master_xmit(struct sk_buff *skb, struct net_device *dev) { struct teql_master *master = netdev_priv(dev); + struct netdev_queue *txq = netdev_get_tx_queue(dev, 0); struct Qdisc *start, *q; int busy; int nores; @@ -308,11 +308,12 @@ restart: if (!netif_tx_queue_stopped(slave_txq) && !netif_tx_queue_frozen(slave_txq) && slave_ops->ndo_start_xmit(skb, slave) == 0) { + txq_trans_update(slave_txq); __netif_tx_unlock(slave_txq); master->slaves = NEXT_SLAVE(q); netif_wake_queue(dev); - master->stats.tx_packets++; - master->stats.tx_bytes += length; + txq->tx_packets++; + txq->tx_bytes += length; return 0; } __netif_tx_unlock(slave_txq); @@ -337,12 +338,12 @@ restart: if (busy) { netif_stop_queue(dev); - return 1; + return NETDEV_TX_BUSY; } - master->stats.tx_errors++; + dev->stats.tx_errors++; drop: - master->stats.tx_dropped++; + txq->tx_dropped++; dev_kfree_skb(skb); return 0; } @@ -395,12 +396,6 @@ static int teql_master_close(struct net_device *dev) return 0; } -static struct net_device_stats *teql_master_stats(struct net_device *dev) -{ - struct teql_master *m = netdev_priv(dev); - return &m->stats; -} - static int teql_master_mtu(struct net_device *dev, int new_mtu) { struct teql_master *m = netdev_priv(dev); @@ -425,7 +420,6 @@ static const struct net_device_ops teql_netdev_ops = { .ndo_open = teql_master_open, .ndo_stop = teql_master_close, .ndo_start_xmit = teql_master_xmit, - .ndo_get_stats = teql_master_stats, .ndo_change_mtu = teql_master_mtu, }; diff --git a/net/sctp/associola.c b/net/sctp/associola.c index f4b23043b610..525864bf4f07 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -293,7 +293,8 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a * told otherwise. */ asoc->peer.ipv4_address = 1; - asoc->peer.ipv6_address = 1; + if (asoc->base.sk->sk_family == PF_INET6) + asoc->peer.ipv6_address = 1; INIT_LIST_HEAD(&asoc->asocs); asoc->autoclose = sp->autoclose; @@ -566,6 +567,21 @@ void sctp_assoc_rm_peer(struct sctp_association *asoc, if (asoc->init_last_sent_to == peer) asoc->init_last_sent_to = NULL; + /* If we remove the transport an SHUTDOWN was last sent to, set it + * to NULL. Combined with the update of the retran path above, this + * will cause the next SHUTDOWN to be sent to the next available + * transport, maintaining the cycle. + */ + if (asoc->shutdown_last_sent_to == peer) + asoc->shutdown_last_sent_to = NULL; + + /* If we remove the transport an ASCONF was last sent to, set it to + * NULL. + */ + if (asoc->addip_last_asconf && + asoc->addip_last_asconf->transport == peer) + asoc->addip_last_asconf->transport = NULL; + asoc->peer.transport_count--; sctp_transport_free(peer); @@ -1268,49 +1284,21 @@ void sctp_assoc_update_retran_path(struct sctp_association *asoc) ntohs(t->ipaddr.v4.sin_port)); } -/* Choose the transport for sending a INIT packet. */ -struct sctp_transport *sctp_assoc_choose_init_transport( - struct sctp_association *asoc) +/* Choose the transport for sending retransmit packet. */ +struct sctp_transport *sctp_assoc_choose_alter_transport( + struct sctp_association *asoc, struct sctp_transport *last_sent_to) { - struct sctp_transport *t; - - /* Use the retran path. If the last INIT was sent over the + /* If this is the first time packet is sent, use the active path, + * else use the retran path. If the last packet was sent over the * retran path, update the retran path and use it. */ - if (!asoc->init_last_sent_to) { - t = asoc->peer.active_path; - } else { - if (asoc->init_last_sent_to == asoc->peer.retran_path) - sctp_assoc_update_retran_path(asoc); - t = asoc->peer.retran_path; - } - - SCTP_DEBUG_PRINTK_IPADDR("sctp_assoc_update_retran_path:association" - " %p addr: ", - " port: %d\n", - asoc, - (&t->ipaddr), - ntohs(t->ipaddr.v4.sin_port)); - - return t; -} - -/* Choose the transport for sending a SHUTDOWN packet. */ -struct sctp_transport *sctp_assoc_choose_shutdown_transport( - struct sctp_association *asoc) -{ - /* If this is the first time SHUTDOWN is sent, use the active path, - * else use the retran path. If the last SHUTDOWN was sent over the - * retran path, update the retran path and use it. - */ - if (!asoc->shutdown_last_sent_to) + if (!last_sent_to) return asoc->peer.active_path; else { - if (asoc->shutdown_last_sent_to == asoc->peer.retran_path) + if (last_sent_to == asoc->peer.retran_path) sctp_assoc_update_retran_path(asoc); return asoc->peer.retran_path; } - } /* Update the association's pmtu and frag_point by going through all the @@ -1482,6 +1470,10 @@ int sctp_assoc_set_id(struct sctp_association *asoc, gfp_t gfp) { int assoc_id; int error = 0; + + /* If the id is already assigned, keep it. */ + if (asoc->assoc_id) + return error; retry: if (unlikely(!idr_pre_get(&sctp_assocs_id, gfp))) return -ENOMEM; diff --git a/net/sctp/input.c b/net/sctp/input.c index d2e98803ffe3..c0c973e67add 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -81,13 +81,13 @@ static void sctp_add_backlog(struct sock *sk, struct sk_buff *skb); /* Calculate the SCTP checksum of an SCTP packet. */ static inline int sctp_rcv_checksum(struct sk_buff *skb) { - struct sk_buff *list = skb_shinfo(skb)->frag_list; struct sctphdr *sh = sctp_hdr(skb); __le32 cmp = sh->checksum; + struct sk_buff *list; __le32 val; __u32 tmp = sctp_start_cksum((__u8 *)sh, skb_headlen(skb)); - for (; list; list = list->next) + skb_walk_frags(skb, list) tmp = sctp_update_cksum((__u8 *)list->data, skb_headlen(list), tmp); diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index a63de3f7f185..6a4b19094143 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -133,7 +133,7 @@ static struct notifier_block sctp_inet6addr_notifier = { /* ICMP error handler. */ SCTP_STATIC void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, - int type, int code, int offset, __be32 info) + u8 type, u8 code, int offset, __be32 info) { struct inet6_dev *idev; struct sock *sk; diff --git a/net/sctp/output.c b/net/sctp/output.c index 7d08f522ec84..b76411444515 100644 --- a/net/sctp/output.c +++ b/net/sctp/output.c @@ -405,13 +405,14 @@ int sctp_packet_transmit(struct sctp_packet *packet) sctp_assoc_sync_pmtu(asoc); } } - nskb->dst = dst_clone(tp->dst); - if (!nskb->dst) + dst = dst_clone(tp->dst); + skb_dst_set(nskb, dst); + if (dst) goto no_route; - dst = nskb->dst; /* Build the SCTP header. */ sh = (struct sctphdr *)skb_push(nskb, sizeof(struct sctphdr)); + skb_reset_transport_header(nskb); sh->source = htons(packet->source_port); sh->dest = htons(packet->destination_port); @@ -527,15 +528,25 @@ int sctp_packet_transmit(struct sctp_packet *packet) * Note: Adler-32 is no longer applicable, as has been replaced * by CRC32-C as described in . */ - if (!sctp_checksum_disable && !(dst->dev->features & NETIF_F_NO_CSUM)) { + if (!sctp_checksum_disable && + !(dst->dev->features & (NETIF_F_NO_CSUM | NETIF_F_SCTP_CSUM))) { __u32 crc32 = sctp_start_cksum((__u8 *)sh, cksum_buf_len); /* 3) Put the resultant value into the checksum field in the * common header, and leave the rest of the bits unchanged. */ sh->checksum = sctp_end_cksum(crc32); - } else - nskb->ip_summed = CHECKSUM_UNNECESSARY; + } else { + if (dst->dev->features & NETIF_F_SCTP_CSUM) { + /* no need to seed psuedo checksum for SCTP */ + nskb->ip_summed = CHECKSUM_PARTIAL; + nskb->csum_start = (skb_transport_header(nskb) - + nskb->head); + nskb->csum_offset = offsetof(struct sctphdr, checksum); + } else { + nskb->ip_summed = CHECKSUM_UNNECESSARY; + } + } /* IP layer ECN support * From RFC 2481 diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 8eb3e61cb701..79cbd47f4df7 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -393,7 +393,7 @@ static int sctp_v4_addr_valid(union sctp_addr *addr, return 0; /* Is this a broadcast address? */ - if (skb && skb->rtable->rt_flags & RTCF_BROADCAST) + if (skb && skb_rtable(skb)->rt_flags & RTCF_BROADCAST) return 0; return 1; @@ -572,7 +572,7 @@ static void sctp_v4_get_saddr(struct sctp_sock *sk, /* What interface did this skb arrive on? */ static int sctp_v4_skb_iif(const struct sk_buff *skb) { - return skb->rtable->rt_iif; + return skb_rtable(skb)->rt_iif; } /* Was this packet marked by Explicit Congestion Notification? */ @@ -848,8 +848,8 @@ static inline int sctp_v4_xmit(struct sk_buff *skb, SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, src:%pI4, dst:%pI4\n", __func__, skb, skb->len, - &skb->rtable->rt_src, - &skb->rtable->rt_dst); + &skb_rtable(skb)->rt_src, + &skb_rtable(skb)->rt_dst); inet->pmtudisc = transport->param_flags & SPP_PMTUD_ENABLE ? IP_PMTUDISC_DO : IP_PMTUDISC_DONT; @@ -1370,6 +1370,8 @@ SCTP_STATIC __exit void sctp_exit(void) sctp_proc_exit(); cleanup_sctp_mibs(); + rcu_barrier(); /* Wait for completion of call_rcu()'s */ + kmem_cache_destroy(sctp_chunk_cachep); kmem_cache_destroy(sctp_bucket_cachep); } diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 6851ee94e974..61cc6075b0df 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -2864,19 +2864,19 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc, switch (addr_param->v4.param_hdr.type) { case SCTP_PARAM_IPV6_ADDRESS: if (!asoc->peer.ipv6_address) - return SCTP_ERROR_INV_PARAM; + return SCTP_ERROR_DNS_FAILED; break; case SCTP_PARAM_IPV4_ADDRESS: if (!asoc->peer.ipv4_address) - return SCTP_ERROR_INV_PARAM; + return SCTP_ERROR_DNS_FAILED; break; default: - return SCTP_ERROR_INV_PARAM; + return SCTP_ERROR_DNS_FAILED; } af = sctp_get_af_specific(param_type2af(addr_param->v4.param_hdr.type)); if (unlikely(!af)) - return SCTP_ERROR_INV_PARAM; + return SCTP_ERROR_DNS_FAILED; af->from_addr_param(&addr, addr_param, htons(asoc->peer.port), 0); @@ -2886,7 +2886,7 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc, * make sure we check for that) */ if (!af->is_any(&addr) && !af->addr_valid(&addr, NULL, asconf->skb)) - return SCTP_ERROR_INV_PARAM; + return SCTP_ERROR_DNS_FAILED; switch (asconf_param->param_hdr.type) { case SCTP_PARAM_ADD_IP: @@ -2954,12 +2954,12 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc, peer = sctp_assoc_lookup_paddr(asoc, &addr); if (!peer) - return SCTP_ERROR_INV_PARAM; + return SCTP_ERROR_DNS_FAILED; sctp_assoc_set_primary(asoc, peer); break; default: - return SCTP_ERROR_INV_PARAM; + return SCTP_ERROR_UNKNOWN_PARAM; break; } @@ -3273,7 +3273,7 @@ int sctp_process_asconf_ack(struct sctp_association *asoc, retval = 1; break; - case SCTP_ERROR_INV_PARAM: + case SCTP_ERROR_UNKNOWN_PARAM: /* Disable sending this type of asconf parameter in * future. */ diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index e2020eb2c8ca..86426aac1600 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -686,7 +686,8 @@ static void sctp_cmd_setup_t2(sctp_cmd_seq_t *cmds, { struct sctp_transport *t; - t = sctp_assoc_choose_shutdown_transport(asoc); + t = sctp_assoc_choose_alter_transport(asoc, + asoc->shutdown_last_sent_to); asoc->shutdown_last_sent_to = t; asoc->timeouts[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] = t->rto; chunk->transport = t; @@ -777,7 +778,7 @@ static void sctp_cmd_setup_t4(sctp_cmd_seq_t *cmds, { struct sctp_transport *t; - t = asoc->peer.active_path; + t = sctp_assoc_choose_alter_transport(asoc, chunk->transport); asoc->timeouts[SCTP_EVENT_TIMEOUT_T4_RTO] = t->rto; chunk->transport = t; } @@ -1379,7 +1380,8 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, case SCTP_CMD_INIT_CHOOSE_TRANSPORT: chunk = cmd->obj.ptr; - t = sctp_assoc_choose_init_transport(asoc); + t = sctp_assoc_choose_alter_transport(asoc, + asoc->init_last_sent_to); asoc->init_last_sent_to = t; chunk->transport = t; t->init_sent_count++; diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 55a61aa69662..7288192f7df5 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -5432,9 +5432,13 @@ sctp_disposition_t sctp_sf_t2_timer_expire(const struct sctp_endpoint *ep, if (!reply) goto nomem; - /* Do some failure management (Section 8.2). */ - sctp_add_cmd_sf(commands, SCTP_CMD_STRIKE, - SCTP_TRANSPORT(asoc->shutdown_last_sent_to)); + /* Do some failure management (Section 8.2). + * If we remove the transport an SHUTDOWN was last sent to, don't + * do failure management. + */ + if (asoc->shutdown_last_sent_to) + sctp_add_cmd_sf(commands, SCTP_CMD_STRIKE, + SCTP_TRANSPORT(asoc->shutdown_last_sent_to)); /* Set the transport for the SHUTDOWN/ACK chunk and the timeout for * the T2-shutdown timer. @@ -5471,7 +5475,9 @@ sctp_disposition_t sctp_sf_t4_timer_expire( * detection on the appropriate destination address as defined in * RFC2960 [5] section 8.1 and 8.2. */ - sctp_add_cmd_sf(commands, SCTP_CMD_STRIKE, SCTP_TRANSPORT(transport)); + if (transport) + sctp_add_cmd_sf(commands, SCTP_CMD_STRIKE, + SCTP_TRANSPORT(transport)); /* Reconfig T4 timer and transport. */ sctp_add_cmd_sf(commands, SCTP_CMD_SETUP_T4, SCTP_CHUNK(chunk)); diff --git a/net/sctp/sm_statetable.c b/net/sctp/sm_statetable.c index 5c8186d88c61..6d9b3aafcc5d 100644 --- a/net/sctp/sm_statetable.c +++ b/net/sctp/sm_statetable.c @@ -698,7 +698,7 @@ chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = { TYPE_SCTP_FUNC(sctp_sf_do_prm_asconf), \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ TYPE_SCTP_FUNC(sctp_sf_error_shutdown), \ -} /* TYPE_SCTP_PRIMITIVE_REQUESTHEARTBEAT */ +} /* TYPE_SCTP_PRIMITIVE_ASCONF */ /* The primary index for this table is the primitive type. * The secondary index for this table is the state. diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 5fb3a8c9792e..35ba035970a2 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -130,7 +130,7 @@ static inline int sctp_wspace(struct sctp_association *asoc) if (asoc->ep->sndbuf_policy) amt = asoc->sndbuf_used; else - amt = atomic_read(&asoc->base.sk->sk_wmem_alloc); + amt = sk_wmem_alloc_get(asoc->base.sk); if (amt >= asoc->base.sk->sk_sndbuf) { if (asoc->base.sk->sk_userlocks & SOCK_SNDBUF_LOCK) @@ -1100,6 +1100,15 @@ static int __sctp_connect(struct sock* sk, goto out_free; } + /* In case the user of sctp_connectx() wants an association + * id back, assign one now. + */ + if (assoc_id) { + err = sctp_assoc_set_id(asoc, GFP_KERNEL); + if (err < 0) + goto out_free; + } + err = sctp_primitive_ASSOCIATE(asoc, NULL); if (err < 0) { goto out_free; @@ -1120,7 +1129,7 @@ static int __sctp_connect(struct sock* sk, timeo = sock_sndtimeo(sk, f_flags & O_NONBLOCK); err = sctp_wait_for_connect(asoc, &timeo); - if (!err && assoc_id) + if ((err == 0 || err == -EINPROGRESS) && assoc_id) *assoc_id = asoc->assoc_id; /* Don't free association on exit. */ @@ -1264,6 +1273,34 @@ SCTP_STATIC int sctp_setsockopt_connectx(struct sock* sk, return assoc_id; } +/* + * New (hopefully final) interface for the API. The option buffer is used + * both for the returned association id and the addresses. + */ +SCTP_STATIC int sctp_getsockopt_connectx3(struct sock* sk, int len, + char __user *optval, + int __user *optlen) +{ + sctp_assoc_t assoc_id = 0; + int err = 0; + + if (len < sizeof(assoc_id)) + return -EINVAL; + + err = __sctp_setsockopt_connectx(sk, + (struct sockaddr __user *)(optval + sizeof(assoc_id)), + len - sizeof(assoc_id), &assoc_id); + + if (err == 0 || err == -EINPROGRESS) { + if (copy_to_user(optval, &assoc_id, sizeof(assoc_id))) + return -EFAULT; + if (put_user(sizeof(assoc_id), optlen)) + return -EFAULT; + } + + return err; +} + /* API 3.1.4 close() - UDP Style Syntax * Applications use close() to perform graceful shutdown (as described in * Section 10.1 of [SCTP]) on ALL the associations currently represented @@ -1844,7 +1881,7 @@ static int sctp_skb_pull(struct sk_buff *skb, int len) len -= skb_len; __skb_pull(skb, skb_len); - for (list = skb_shinfo(skb)->frag_list; list; list = list->next) { + skb_walk_frags(skb, list) { rlen = sctp_skb_pull(list, len); skb->len -= (len-rlen); skb->data_len -= (len-rlen); @@ -5578,6 +5615,9 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, retval = sctp_getsockopt_local_addrs(sk, len, optval, optlen); break; + case SCTP_SOCKOPT_CONNECTX3: + retval = sctp_getsockopt_connectx3(sk, len, optval, optlen); + break; case SCTP_DEFAULT_SEND_PARAM: retval = sctp_getsockopt_default_send_param(sk, len, optval, optlen); @@ -6483,7 +6523,7 @@ static int sctp_writeable(struct sock *sk) { int amt = 0; - amt = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc); + amt = sk->sk_sndbuf - sk_wmem_alloc_get(sk); if (amt < 0) amt = 0; return amt; @@ -6620,7 +6660,7 @@ static void sctp_sock_rfree_frag(struct sk_buff *skb) goto done; /* Don't forget the fragments. */ - for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next) + skb_walk_frags(skb, frag) sctp_sock_rfree_frag(frag); done: @@ -6635,7 +6675,7 @@ static void sctp_skb_set_owner_r_frag(struct sk_buff *skb, struct sock *sk) goto done; /* Don't forget the fragments. */ - for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next) + skb_walk_frags(skb, frag) sctp_skb_set_owner_r_frag(frag, sk); done: diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c index f58e994e6852..63eabbc71298 100644 --- a/net/sctp/sysctl.c +++ b/net/sctp/sysctl.c @@ -49,8 +49,8 @@ static int zero = 0; static int one = 1; static int timer_max = 86400000; /* ms in one day */ static int int_max = INT_MAX; -static long sack_timer_min = 1; -static long sack_timer_max = 500; +static int sack_timer_min = 1; +static int sack_timer_max = 500; extern int sysctl_sctp_mem[3]; extern int sysctl_sctp_rmem[3]; @@ -223,7 +223,7 @@ static ctl_table sctp_table[] = { .ctl_name = NET_SCTP_SACK_TIMEOUT, .procname = "sack_timeout", .data = &sctp_sack_timeout, - .maxlen = sizeof(long), + .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec_minmax, .strategy = sysctl_intvec, diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c index 5f186ca550d7..8b3560fd876d 100644 --- a/net/sctp/ulpevent.c +++ b/net/sctp/ulpevent.c @@ -976,9 +976,8 @@ static void sctp_ulpevent_receive_data(struct sctp_ulpevent *event, * In general, the skb passed from IP can have only 1 level of * fragments. But we allow multiple levels of fragments. */ - for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next) { + skb_walk_frags(skb, frag) sctp_ulpevent_receive_data(sctp_skb2event(frag), asoc); - } } /* Do accounting for bytes just read by user and release the references to @@ -1003,7 +1002,7 @@ static void sctp_ulpevent_release_data(struct sctp_ulpevent *event) goto done; /* Don't forget the fragments. */ - for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next) { + skb_walk_frags(skb, frag) { /* NOTE: skb_shinfos are recursive. Although IP returns * skb's with only 1 level of fragments, SCTP reassembly can * increase the levels. @@ -1026,7 +1025,7 @@ static void sctp_ulpevent_release_frag_data(struct sctp_ulpevent *event) goto done; /* Don't forget the fragments. */ - for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next) { + skb_walk_frags(skb, frag) { /* NOTE: skb_shinfos are recursive. Although IP returns * skb's with only 1 level of fragments, SCTP reassembly can * increase the levels. diff --git a/net/sunrpc/Makefile b/net/sunrpc/Makefile index 5369aa369b35..db73fd2a3f0e 100644 --- a/net/sunrpc/Makefile +++ b/net/sunrpc/Makefile @@ -13,5 +13,6 @@ sunrpc-y := clnt.o xprt.o socklib.o xprtsock.o sched.o \ rpcb_clnt.o timer.o xdr.o \ sunrpc_syms.o cache.o rpc_pipe.o \ svc_xprt.o +sunrpc-$(CONFIG_NFS_V4_1) += backchannel_rqst.o bc_svc.o sunrpc-$(CONFIG_PROC_FS) += stats.o sunrpc-$(CONFIG_SYSCTL) += sysctl.o diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index e630b38a6047..66d458fc6920 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -1548,6 +1548,7 @@ static void __exit exit_rpcsec_gss(void) { gss_svc_shutdown(); rpcauth_unregister(&authgss_ops); + rcu_barrier(); /* Wait for completion of call_rcu()'s */ } MODULE_LICENSE("GPL"); diff --git a/net/sunrpc/backchannel_rqst.c b/net/sunrpc/backchannel_rqst.c new file mode 100644 index 000000000000..553621fb2c41 --- /dev/null +++ b/net/sunrpc/backchannel_rqst.c @@ -0,0 +1,281 @@ +/****************************************************************************** + +(c) 2007 Network Appliance, Inc. All Rights Reserved. +(c) 2009 NetApp. All Rights Reserved. + +NetApp provides this source code under the GPL v2 License. +The GPL v2 license is available at +http://opensource.org/licenses/gpl-license.php. + +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 +#include + +#ifdef RPC_DEBUG +#define RPCDBG_FACILITY RPCDBG_TRANS +#endif + +#if defined(CONFIG_NFS_V4_1) + +/* + * Helper routines that track the number of preallocation elements + * on the transport. + */ +static inline int xprt_need_to_requeue(struct rpc_xprt *xprt) +{ + return xprt->bc_alloc_count > 0; +} + +static inline void xprt_inc_alloc_count(struct rpc_xprt *xprt, unsigned int n) +{ + xprt->bc_alloc_count += n; +} + +static inline int xprt_dec_alloc_count(struct rpc_xprt *xprt, unsigned int n) +{ + return xprt->bc_alloc_count -= n; +} + +/* + * Free the preallocated rpc_rqst structure and the memory + * buffers hanging off of it. + */ +static void xprt_free_allocation(struct rpc_rqst *req) +{ + struct xdr_buf *xbufp; + + dprintk("RPC: free allocations for req= %p\n", req); + BUG_ON(test_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state)); + xbufp = &req->rq_private_buf; + free_page((unsigned long)xbufp->head[0].iov_base); + xbufp = &req->rq_snd_buf; + free_page((unsigned long)xbufp->head[0].iov_base); + list_del(&req->rq_bc_pa_list); + kfree(req); +} + +/* + * Preallocate up to min_reqs structures and related buffers for use + * by the backchannel. This function can be called multiple times + * when creating new sessions that use the same rpc_xprt. The + * preallocated buffers are added to the pool of resources used by + * the rpc_xprt. Anyone of these resources may be used used by an + * incoming callback request. It's up to the higher levels in the + * stack to enforce that the maximum number of session slots is not + * being exceeded. + * + * Some callback arguments can be large. For example, a pNFS server + * using multiple deviceids. The list can be unbound, but the client + * has the ability to tell the server the maximum size of the callback + * requests. Each deviceID is 16 bytes, so allocate one page + * for the arguments to have enough room to receive a number of these + * deviceIDs. The NFS client indicates to the pNFS server that its + * callback requests can be up to 4096 bytes in size. + */ +int xprt_setup_backchannel(struct rpc_xprt *xprt, unsigned int min_reqs) +{ + struct page *page_rcv = NULL, *page_snd = NULL; + struct xdr_buf *xbufp = NULL; + struct rpc_rqst *req, *tmp; + struct list_head tmp_list; + int i; + + dprintk("RPC: setup backchannel transport\n"); + + /* + * We use a temporary list to keep track of the preallocated + * buffers. Once we're done building the list we splice it + * into the backchannel preallocation list off of the rpc_xprt + * struct. This helps minimize the amount of time the list + * lock is held on the rpc_xprt struct. It also makes cleanup + * easier in case of memory allocation errors. + */ + INIT_LIST_HEAD(&tmp_list); + for (i = 0; i < min_reqs; i++) { + /* Pre-allocate one backchannel rpc_rqst */ + req = kzalloc(sizeof(struct rpc_rqst), GFP_KERNEL); + if (req == NULL) { + printk(KERN_ERR "Failed to create bc rpc_rqst\n"); + goto out_free; + } + + /* Add the allocated buffer to the tmp list */ + dprintk("RPC: adding req= %p\n", req); + list_add(&req->rq_bc_pa_list, &tmp_list); + + req->rq_xprt = xprt; + INIT_LIST_HEAD(&req->rq_list); + INIT_LIST_HEAD(&req->rq_bc_list); + + /* Preallocate one XDR receive buffer */ + page_rcv = alloc_page(GFP_KERNEL); + if (page_rcv == NULL) { + printk(KERN_ERR "Failed to create bc receive xbuf\n"); + goto out_free; + } + xbufp = &req->rq_rcv_buf; + xbufp->head[0].iov_base = page_address(page_rcv); + xbufp->head[0].iov_len = PAGE_SIZE; + xbufp->tail[0].iov_base = NULL; + xbufp->tail[0].iov_len = 0; + xbufp->page_len = 0; + xbufp->len = PAGE_SIZE; + xbufp->buflen = PAGE_SIZE; + + /* Preallocate one XDR send buffer */ + page_snd = alloc_page(GFP_KERNEL); + if (page_snd == NULL) { + printk(KERN_ERR "Failed to create bc snd xbuf\n"); + goto out_free; + } + + xbufp = &req->rq_snd_buf; + xbufp->head[0].iov_base = page_address(page_snd); + xbufp->head[0].iov_len = 0; + xbufp->tail[0].iov_base = NULL; + xbufp->tail[0].iov_len = 0; + xbufp->page_len = 0; + xbufp->len = 0; + xbufp->buflen = PAGE_SIZE; + } + + /* + * Add the temporary list to the backchannel preallocation list + */ + spin_lock_bh(&xprt->bc_pa_lock); + list_splice(&tmp_list, &xprt->bc_pa_list); + xprt_inc_alloc_count(xprt, min_reqs); + spin_unlock_bh(&xprt->bc_pa_lock); + + dprintk("RPC: setup backchannel transport done\n"); + return 0; + +out_free: + /* + * Memory allocation failed, free the temporary list + */ + list_for_each_entry_safe(req, tmp, &tmp_list, rq_bc_pa_list) + xprt_free_allocation(req); + + dprintk("RPC: setup backchannel transport failed\n"); + return -1; +} +EXPORT_SYMBOL(xprt_setup_backchannel); + +/* + * Destroys the backchannel preallocated structures. + * Since these structures may have been allocated by multiple calls + * to xprt_setup_backchannel, we only destroy up to the maximum number + * of reqs specified by the caller. + * @xprt: the transport holding the preallocated strucures + * @max_reqs the maximum number of preallocated structures to destroy + */ +void xprt_destroy_backchannel(struct rpc_xprt *xprt, unsigned int max_reqs) +{ + struct rpc_rqst *req = NULL, *tmp = NULL; + + dprintk("RPC: destroy backchannel transport\n"); + + BUG_ON(max_reqs == 0); + spin_lock_bh(&xprt->bc_pa_lock); + xprt_dec_alloc_count(xprt, max_reqs); + list_for_each_entry_safe(req, tmp, &xprt->bc_pa_list, rq_bc_pa_list) { + dprintk("RPC: req=%p\n", req); + xprt_free_allocation(req); + if (--max_reqs == 0) + break; + } + spin_unlock_bh(&xprt->bc_pa_lock); + + dprintk("RPC: backchannel list empty= %s\n", + list_empty(&xprt->bc_pa_list) ? "true" : "false"); +} +EXPORT_SYMBOL(xprt_destroy_backchannel); + +/* + * One or more rpc_rqst structure have been preallocated during the + * backchannel setup. Buffer space for the send and private XDR buffers + * has been preallocated as well. Use xprt_alloc_bc_request to allocate + * to this request. Use xprt_free_bc_request to return it. + * + * We know that we're called in soft interrupt context, grab the spin_lock + * since there is no need to grab the bottom half spin_lock. + * + * Return an available rpc_rqst, otherwise NULL if non are available. + */ +struct rpc_rqst *xprt_alloc_bc_request(struct rpc_xprt *xprt) +{ + struct rpc_rqst *req; + + dprintk("RPC: allocate a backchannel request\n"); + spin_lock(&xprt->bc_pa_lock); + if (!list_empty(&xprt->bc_pa_list)) { + req = list_first_entry(&xprt->bc_pa_list, struct rpc_rqst, + rq_bc_pa_list); + list_del(&req->rq_bc_pa_list); + } else { + req = NULL; + } + spin_unlock(&xprt->bc_pa_lock); + + if (req != NULL) { + set_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state); + req->rq_reply_bytes_recvd = 0; + req->rq_bytes_sent = 0; + memcpy(&req->rq_private_buf, &req->rq_rcv_buf, + sizeof(req->rq_private_buf)); + } + dprintk("RPC: backchannel req=%p\n", req); + return req; +} + +/* + * Return the preallocated rpc_rqst structure and XDR buffers + * associated with this rpc_task. + */ +void xprt_free_bc_request(struct rpc_rqst *req) +{ + struct rpc_xprt *xprt = req->rq_xprt; + + dprintk("RPC: free backchannel req=%p\n", req); + + smp_mb__before_clear_bit(); + BUG_ON(!test_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state)); + clear_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state); + smp_mb__after_clear_bit(); + + if (!xprt_need_to_requeue(xprt)) { + /* + * The last remaining session was destroyed while this + * entry was in use. Free the entry and don't attempt + * to add back to the list because there is no need to + * have anymore preallocated entries. + */ + dprintk("RPC: Last session removed req=%p\n", req); + xprt_free_allocation(req); + return; + } + + /* + * Return it to the list of preallocations so that it + * may be reused by a new callback request. + */ + spin_lock_bh(&xprt->bc_pa_lock); + list_add(&req->rq_bc_pa_list, &xprt->bc_pa_list); + spin_unlock_bh(&xprt->bc_pa_lock); +} + +#endif /* CONFIG_NFS_V4_1 */ diff --git a/net/sunrpc/bc_svc.c b/net/sunrpc/bc_svc.c new file mode 100644 index 000000000000..13f214f53120 --- /dev/null +++ b/net/sunrpc/bc_svc.c @@ -0,0 +1,81 @@ +/****************************************************************************** + +(c) 2007 Network Appliance, Inc. All Rights Reserved. +(c) 2009 NetApp. All Rights Reserved. + +NetApp provides this source code under the GPL v2 License. +The GPL v2 license is available at +http://opensource.org/licenses/gpl-license.php. + +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. + +******************************************************************************/ + +/* + * The NFSv4.1 callback service helper routines. + * They implement the transport level processing required to send the + * reply over an existing open connection previously established by the client. + */ + +#if defined(CONFIG_NFS_V4_1) + +#include + +#include +#include +#include + +#define RPCDBG_FACILITY RPCDBG_SVCDSP + +void bc_release_request(struct rpc_task *task) +{ + struct rpc_rqst *req = task->tk_rqstp; + + dprintk("RPC: bc_release_request: task= %p\n", task); + + /* + * Release this request only if it's a backchannel + * preallocated request + */ + if (!bc_prealloc(req)) + return; + xprt_free_bc_request(req); +} + +/* Empty callback ops */ +static const struct rpc_call_ops nfs41_callback_ops = { +}; + + +/* + * Send the callback reply + */ +int bc_send(struct rpc_rqst *req) +{ + struct rpc_task *task; + int ret; + + dprintk("RPC: bc_send req= %p\n", req); + task = rpc_run_bc_task(req, &nfs41_callback_ops); + if (IS_ERR(task)) + ret = PTR_ERR(task); + else { + BUG_ON(atomic_read(&task->tk_count) != 1); + ret = task->tk_status; + rpc_put_task(task); + } + return ret; + dprintk("RPC: bc_send ret= %d \n", ret); +} + +#endif /* CONFIG_NFS_V4_1 */ diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index 20029a79a5de..ff0c23053d2f 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -488,7 +488,7 @@ static void do_cache_clean(struct work_struct *work) { int delay = 5; if (cache_clean() == -1) - delay = 30*HZ; + delay = round_jiffies_relative(30*HZ); if (list_empty(&cache_list)) delay = 0; diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 5abab094441f..5bc2f45bddf0 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -36,7 +36,9 @@ #include #include #include +#include +#include "sunrpc.h" #ifdef RPC_DEBUG # define RPCDBG_FACILITY RPCDBG_CALL @@ -63,6 +65,9 @@ static void call_decode(struct rpc_task *task); static void call_bind(struct rpc_task *task); static void call_bind_status(struct rpc_task *task); static void call_transmit(struct rpc_task *task); +#if defined(CONFIG_NFS_V4_1) +static void call_bc_transmit(struct rpc_task *task); +#endif /* CONFIG_NFS_V4_1 */ static void call_status(struct rpc_task *task); static void call_transmit_status(struct rpc_task *task); static void call_refresh(struct rpc_task *task); @@ -613,6 +618,50 @@ rpc_call_async(struct rpc_clnt *clnt, const struct rpc_message *msg, int flags, } EXPORT_SYMBOL_GPL(rpc_call_async); +#if defined(CONFIG_NFS_V4_1) +/** + * rpc_run_bc_task - Allocate a new RPC task for backchannel use, then run + * rpc_execute against it + * @ops: RPC call ops + */ +struct rpc_task *rpc_run_bc_task(struct rpc_rqst *req, + const struct rpc_call_ops *tk_ops) +{ + struct rpc_task *task; + struct xdr_buf *xbufp = &req->rq_snd_buf; + struct rpc_task_setup task_setup_data = { + .callback_ops = tk_ops, + }; + + dprintk("RPC: rpc_run_bc_task req= %p\n", req); + /* + * Create an rpc_task to send the data + */ + task = rpc_new_task(&task_setup_data); + if (!task) { + xprt_free_bc_request(req); + goto out; + } + task->tk_rqstp = req; + + /* + * Set up the xdr_buf length. + * This also indicates that the buffer is XDR encoded already. + */ + xbufp->len = xbufp->head[0].iov_len + xbufp->page_len + + xbufp->tail[0].iov_len; + + task->tk_action = call_bc_transmit; + atomic_inc(&task->tk_count); + BUG_ON(atomic_read(&task->tk_count) != 2); + rpc_execute(task); + +out: + dprintk("RPC: rpc_run_bc_task: task= %p\n", task); + return task; +} +#endif /* CONFIG_NFS_V4_1 */ + void rpc_call_start(struct rpc_task *task) { @@ -694,6 +743,19 @@ void rpc_force_rebind(struct rpc_clnt *clnt) } EXPORT_SYMBOL_GPL(rpc_force_rebind); +/* + * Restart an (async) RPC call from the call_prepare state. + * Usually called from within the exit handler. + */ +void +rpc_restart_call_prepare(struct rpc_task *task) +{ + if (RPC_ASSASSINATED(task)) + return; + task->tk_action = rpc_prepare_task; +} +EXPORT_SYMBOL_GPL(rpc_restart_call_prepare); + /* * Restart an (async) RPC call. Usually called from within the * exit handler. @@ -1085,7 +1147,7 @@ call_transmit(struct rpc_task *task) * in order to allow access to the socket to other RPC requests. */ call_transmit_status(task); - if (task->tk_msg.rpc_proc->p_decode != NULL) + if (rpc_reply_expected(task)) return; task->tk_action = rpc_exit_task; rpc_wake_up_queued_task(&task->tk_xprt->pending, task); @@ -1120,6 +1182,72 @@ call_transmit_status(struct rpc_task *task) } } +#if defined(CONFIG_NFS_V4_1) +/* + * 5b. Send the backchannel RPC reply. On error, drop the reply. In + * addition, disconnect on connectivity errors. + */ +static void +call_bc_transmit(struct rpc_task *task) +{ + struct rpc_rqst *req = task->tk_rqstp; + + BUG_ON(task->tk_status != 0); + task->tk_status = xprt_prepare_transmit(task); + if (task->tk_status == -EAGAIN) { + /* + * Could not reserve the transport. Try again after the + * transport is released. + */ + task->tk_status = 0; + task->tk_action = call_bc_transmit; + return; + } + + task->tk_action = rpc_exit_task; + if (task->tk_status < 0) { + printk(KERN_NOTICE "RPC: Could not send backchannel reply " + "error: %d\n", task->tk_status); + return; + } + + xprt_transmit(task); + xprt_end_transmit(task); + dprint_status(task); + switch (task->tk_status) { + case 0: + /* Success */ + break; + case -EHOSTDOWN: + case -EHOSTUNREACH: + case -ENETUNREACH: + case -ETIMEDOUT: + /* + * Problem reaching the server. Disconnect and let the + * forechannel reestablish the connection. The server will + * have to retransmit the backchannel request and we'll + * reprocess it. Since these ops are idempotent, there's no + * need to cache our reply at this time. + */ + printk(KERN_NOTICE "RPC: Could not send backchannel reply " + "error: %d\n", task->tk_status); + xprt_conditional_disconnect(task->tk_xprt, + req->rq_connect_cookie); + break; + default: + /* + * We were unable to reply and will have to drop the + * request. The server should reconnect and retransmit. + */ + BUG_ON(task->tk_status == -EAGAIN); + printk(KERN_NOTICE "RPC: Could not send backchannel reply " + "error: %d\n", task->tk_status); + break; + } + rpc_wake_up_queued_task(&req->rq_xprt->pending, task); +} +#endif /* CONFIG_NFS_V4_1 */ + /* * 6. Sort out the RPC call status */ @@ -1130,8 +1258,8 @@ call_status(struct rpc_task *task) struct rpc_rqst *req = task->tk_rqstp; int status; - if (req->rq_received > 0 && !req->rq_bytes_sent) - task->tk_status = req->rq_received; + if (req->rq_reply_bytes_recvd > 0 && !req->rq_bytes_sent) + task->tk_status = req->rq_reply_bytes_recvd; dprint_status(task); @@ -1248,7 +1376,7 @@ call_decode(struct rpc_task *task) /* * Ensure that we see all writes made by xprt_complete_rqst() - * before it changed req->rq_received. + * before it changed req->rq_reply_bytes_recvd. */ smp_rmb(); req->rq_rcv_buf.len = req->rq_private_buf.len; @@ -1289,7 +1417,7 @@ out_retry: task->tk_status = 0; /* Note: rpc_verify_header() may have freed the RPC slot */ if (task->tk_rqstp == req) { - req->rq_received = req->rq_rcv_buf.len = 0; + req->rq_reply_bytes_recvd = req->rq_rcv_buf.len = 0; if (task->tk_client->cl_discrtry) xprt_conditional_disconnect(task->tk_xprt, req->rq_connect_cookie); @@ -1377,13 +1505,14 @@ rpc_verify_header(struct rpc_task *task) } if ((len -= 3) < 0) goto out_overflow; - p += 1; /* skip XID */ + p += 1; /* skip XID */ if ((n = ntohl(*p++)) != RPC_REPLY) { dprintk("RPC: %5u %s: not an RPC reply: %x\n", - task->tk_pid, __func__, n); + task->tk_pid, __func__, n); goto out_garbage; } + if ((n = ntohl(*p++)) != RPC_MSG_ACCEPTED) { if (--len < 0) goto out_overflow; diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index ff50a0546865..1102ce1251f7 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -569,7 +569,7 @@ EXPORT_SYMBOL_GPL(rpc_delay); /* * Helper to call task->tk_ops->rpc_call_prepare */ -static void rpc_prepare_task(struct rpc_task *task) +void rpc_prepare_task(struct rpc_task *task) { task->tk_ops->rpc_call_prepare(task, task->tk_calldata); } diff --git a/net/sunrpc/stats.c b/net/sunrpc/stats.c index 1ef6e46d9da2..1b4e6791ecf3 100644 --- a/net/sunrpc/stats.c +++ b/net/sunrpc/stats.c @@ -141,12 +141,14 @@ EXPORT_SYMBOL_GPL(rpc_free_iostats); void rpc_count_iostats(struct rpc_task *task) { struct rpc_rqst *req = task->tk_rqstp; - struct rpc_iostats *stats = task->tk_client->cl_metrics; + struct rpc_iostats *stats; struct rpc_iostats *op_metrics; long rtt, execute, queue; - if (!stats || !req) + if (!task->tk_client || !task->tk_client->cl_metrics || !req) return; + + stats = task->tk_client->cl_metrics; op_metrics = &stats[task->tk_msg.rpc_proc->p_statidx]; op_metrics->om_ops++; @@ -154,7 +156,7 @@ void rpc_count_iostats(struct rpc_task *task) op_metrics->om_timeouts += task->tk_timeouts; op_metrics->om_bytes_sent += task->tk_bytes_sent; - op_metrics->om_bytes_recv += req->rq_received; + op_metrics->om_bytes_recv += req->rq_reply_bytes_recvd; queue = (long)req->rq_xtime - task->tk_start; if (queue < 0) diff --git a/net/sunrpc/sunrpc.h b/net/sunrpc/sunrpc.h new file mode 100644 index 000000000000..5d9dd742264b --- /dev/null +++ b/net/sunrpc/sunrpc.h @@ -0,0 +1,37 @@ +/****************************************************************************** + +(c) 2008 NetApp. All Rights Reserved. + +NetApp provides this source code under the GPL v2 License. +The GPL v2 license is available at +http://opensource.org/licenses/gpl-license.php. + +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. + +******************************************************************************/ + +/* + * Functions and macros used internally by RPC + */ + +#ifndef _NET_SUNRPC_SUNRPC_H +#define _NET_SUNRPC_SUNRPC_H + +static inline int rpc_reply_expected(struct rpc_task *task) +{ + return (task->tk_msg.rpc_proc != NULL) && + (task->tk_msg.rpc_proc->p_decode != NULL); +} + +#endif /* _NET_SUNRPC_SUNRPC_H */ + diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 8847add6ca16..952f206ff307 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -25,6 +25,7 @@ #include #include #include +#include #define RPCDBG_FACILITY RPCDBG_SVCDSP @@ -124,7 +125,7 @@ svc_pool_map_choose_mode(void) { unsigned int node; - if (num_online_nodes() > 1) { + if (nr_online_nodes > 1) { /* * Actually have multiple NUMA nodes, * so split pools on NUMA node boundaries @@ -486,6 +487,10 @@ svc_destroy(struct svc_serv *serv) if (svc_serv_is_pooled(serv)) svc_pool_map_put(); +#if defined(CONFIG_NFS_V4_1) + svc_sock_destroy(serv->bc_xprt); +#endif /* CONFIG_NFS_V4_1 */ + svc_unregister(serv); kfree(serv->sv_pools); kfree(serv); @@ -970,20 +975,18 @@ svc_printk(struct svc_rqst *rqstp, const char *fmt, ...) } /* - * Process the RPC request. + * Common routine for processing the RPC request. */ -int -svc_process(struct svc_rqst *rqstp) +static int +svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv) { struct svc_program *progp; struct svc_version *versp = NULL; /* compiler food */ struct svc_procedure *procp = NULL; - struct kvec * argv = &rqstp->rq_arg.head[0]; - struct kvec * resv = &rqstp->rq_res.head[0]; struct svc_serv *serv = rqstp->rq_server; kxdrproc_t xdr; __be32 *statp; - u32 dir, prog, vers, proc; + u32 prog, vers, proc; __be32 auth_stat, rpc_stat; int auth_res; __be32 *reply_statp; @@ -993,19 +996,6 @@ svc_process(struct svc_rqst *rqstp) if (argv->iov_len < 6*4) goto err_short_len; - /* setup response xdr_buf. - * Initially it has just one page - */ - rqstp->rq_resused = 1; - resv->iov_base = page_address(rqstp->rq_respages[0]); - resv->iov_len = 0; - rqstp->rq_res.pages = rqstp->rq_respages + 1; - rqstp->rq_res.len = 0; - rqstp->rq_res.page_base = 0; - rqstp->rq_res.page_len = 0; - rqstp->rq_res.buflen = PAGE_SIZE; - rqstp->rq_res.tail[0].iov_base = NULL; - rqstp->rq_res.tail[0].iov_len = 0; /* Will be turned off only in gss privacy case: */ rqstp->rq_splice_ok = 1; /* Will be turned off only when NFSv4 Sessions are used */ @@ -1014,17 +1004,13 @@ svc_process(struct svc_rqst *rqstp) /* Setup reply header */ rqstp->rq_xprt->xpt_ops->xpo_prep_reply_hdr(rqstp); - rqstp->rq_xid = svc_getu32(argv); svc_putu32(resv, rqstp->rq_xid); - dir = svc_getnl(argv); vers = svc_getnl(argv); /* First words of reply: */ svc_putnl(resv, 1); /* REPLY */ - if (dir != 0) /* direction != CALL */ - goto err_bad_dir; if (vers != 2) /* RPC version number */ goto err_bad_rpc; @@ -1147,7 +1133,7 @@ svc_process(struct svc_rqst *rqstp) sendit: if (svc_authorise(rqstp)) goto dropit; - return svc_send(rqstp); + return 1; /* Caller can now send it */ dropit: svc_authorise(rqstp); /* doesn't hurt to call this twice */ @@ -1161,12 +1147,6 @@ err_short_len: goto dropit; /* drop request */ -err_bad_dir: - svc_printk(rqstp, "bad direction %d, dropping request\n", dir); - - serv->sv_stats->rpcbadfmt++; - goto dropit; /* drop request */ - err_bad_rpc: serv->sv_stats->rpcbadfmt++; svc_putnl(resv, 1); /* REJECT */ @@ -1219,6 +1199,100 @@ err_bad: } EXPORT_SYMBOL_GPL(svc_process); +/* + * Process the RPC request. + */ +int +svc_process(struct svc_rqst *rqstp) +{ + struct kvec *argv = &rqstp->rq_arg.head[0]; + struct kvec *resv = &rqstp->rq_res.head[0]; + struct svc_serv *serv = rqstp->rq_server; + u32 dir; + int error; + + /* + * Setup response xdr_buf. + * Initially it has just one page + */ + rqstp->rq_resused = 1; + resv->iov_base = page_address(rqstp->rq_respages[0]); + resv->iov_len = 0; + rqstp->rq_res.pages = rqstp->rq_respages + 1; + rqstp->rq_res.len = 0; + rqstp->rq_res.page_base = 0; + rqstp->rq_res.page_len = 0; + rqstp->rq_res.buflen = PAGE_SIZE; + rqstp->rq_res.tail[0].iov_base = NULL; + rqstp->rq_res.tail[0].iov_len = 0; + + rqstp->rq_xid = svc_getu32(argv); + + dir = svc_getnl(argv); + if (dir != 0) { + /* direction != CALL */ + svc_printk(rqstp, "bad direction %d, dropping request\n", dir); + serv->sv_stats->rpcbadfmt++; + svc_drop(rqstp); + return 0; + } + + error = svc_process_common(rqstp, argv, resv); + if (error <= 0) + return error; + + return svc_send(rqstp); +} + +#if defined(CONFIG_NFS_V4_1) +/* + * Process a backchannel RPC request that arrived over an existing + * outbound connection + */ +int +bc_svc_process(struct svc_serv *serv, struct rpc_rqst *req, + struct svc_rqst *rqstp) +{ + struct kvec *argv = &rqstp->rq_arg.head[0]; + struct kvec *resv = &rqstp->rq_res.head[0]; + int error; + + /* Build the svc_rqst used by the common processing routine */ + rqstp->rq_xprt = serv->bc_xprt; + rqstp->rq_xid = req->rq_xid; + rqstp->rq_prot = req->rq_xprt->prot; + rqstp->rq_server = serv; + + rqstp->rq_addrlen = sizeof(req->rq_xprt->addr); + memcpy(&rqstp->rq_addr, &req->rq_xprt->addr, rqstp->rq_addrlen); + memcpy(&rqstp->rq_arg, &req->rq_rcv_buf, sizeof(rqstp->rq_arg)); + memcpy(&rqstp->rq_res, &req->rq_snd_buf, sizeof(rqstp->rq_res)); + + /* reset result send buffer "put" position */ + resv->iov_len = 0; + + if (rqstp->rq_prot != IPPROTO_TCP) { + printk(KERN_ERR "No support for Non-TCP transports!\n"); + BUG(); + } + + /* + * Skip the next two words because they've already been + * processed in the trasport + */ + svc_getu32(argv); /* XID */ + svc_getnl(argv); /* CALLDIR */ + + error = svc_process_common(rqstp, argv, resv); + if (error <= 0) + return error; + + memcpy(&req->rq_snd_buf, &rqstp->rq_res, sizeof(req->rq_snd_buf)); + return bc_send(req); +} +EXPORT_SYMBOL(bc_svc_process); +#endif /* CONFIG_NFS_V4_1 */ + /* * Return (transport-specific) limit on the rpc payload. */ diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index c200d92e57e4..6f33d33cc064 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c @@ -11,6 +11,7 @@ #include #include #include +#include #define RPCDBG_FACILITY RPCDBG_SVCXPRT @@ -1097,36 +1098,58 @@ struct svc_xprt *svc_find_xprt(struct svc_serv *serv, const char *xcl_name, } EXPORT_SYMBOL_GPL(svc_find_xprt); -/* - * Format a buffer with a list of the active transports. A zero for - * the buflen parameter disables target buffer overflow checking. +static int svc_one_xprt_name(const struct svc_xprt *xprt, + char *pos, int remaining) +{ + int len; + + len = snprintf(pos, remaining, "%s %u\n", + xprt->xpt_class->xcl_name, + svc_xprt_local_port(xprt)); + if (len >= remaining) + return -ENAMETOOLONG; + return len; +} + +/** + * svc_xprt_names - format a buffer with a list of transport names + * @serv: pointer to an RPC service + * @buf: pointer to a buffer to be filled in + * @buflen: length of buffer to be filled in + * + * Fills in @buf with a string containing a list of transport names, + * each name terminated with '\n'. + * + * Returns positive length of the filled-in string on success; otherwise + * a negative errno value is returned if an error occurs. */ -int svc_xprt_names(struct svc_serv *serv, char *buf, int buflen) +int svc_xprt_names(struct svc_serv *serv, char *buf, const int buflen) { struct svc_xprt *xprt; - char xprt_str[64]; - int totlen = 0; - int len; + int len, totlen; + char *pos; /* Sanity check args */ if (!serv) return 0; spin_lock_bh(&serv->sv_lock); + + pos = buf; + totlen = 0; list_for_each_entry(xprt, &serv->sv_permsocks, xpt_list) { - len = snprintf(xprt_str, sizeof(xprt_str), - "%s %d\n", xprt->xpt_class->xcl_name, - svc_xprt_local_port(xprt)); - /* If the string was truncated, replace with error string */ - if (len >= sizeof(xprt_str)) - strcpy(xprt_str, "name-too-long\n"); - /* Don't overflow buffer */ - len = strlen(xprt_str); - if (buflen && (len + totlen >= buflen)) + len = svc_one_xprt_name(xprt, pos, buflen - totlen); + if (len < 0) { + *buf = '\0'; + totlen = len; + } + if (len <= 0) break; - strcpy(buf+totlen, xprt_str); + + pos += len; totlen += len; } + spin_unlock_bh(&serv->sv_lock); return totlen; } diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 9d504234af4a..23128ee191ae 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -240,42 +240,76 @@ out: /* * Report socket names for nfsdfs */ -static int one_sock_name(char *buf, struct svc_sock *svsk) +static int svc_one_sock_name(struct svc_sock *svsk, char *buf, int remaining) { + const struct sock *sk = svsk->sk_sk; + const char *proto_name = sk->sk_protocol == IPPROTO_UDP ? + "udp" : "tcp"; int len; - switch(svsk->sk_sk->sk_family) { - case AF_INET: - len = sprintf(buf, "ipv4 %s %pI4 %d\n", - svsk->sk_sk->sk_protocol == IPPROTO_UDP ? - "udp" : "tcp", - &inet_sk(svsk->sk_sk)->rcv_saddr, - inet_sk(svsk->sk_sk)->num); + switch (sk->sk_family) { + case PF_INET: + len = snprintf(buf, remaining, "ipv4 %s %pI4 %d\n", + proto_name, + &inet_sk(sk)->rcv_saddr, + inet_sk(sk)->num); + break; + case PF_INET6: + len = snprintf(buf, remaining, "ipv6 %s %pI6 %d\n", + proto_name, + &inet6_sk(sk)->rcv_saddr, + inet_sk(sk)->num); break; default: - len = sprintf(buf, "*unknown-%d*\n", - svsk->sk_sk->sk_family); + len = snprintf(buf, remaining, "*unknown-%d*\n", + sk->sk_family); + } + + if (len >= remaining) { + *buf = '\0'; + return -ENAMETOOLONG; } return len; } -int -svc_sock_names(char *buf, struct svc_serv *serv, char *toclose) +/** + * svc_sock_names - construct a list of listener names in a string + * @serv: pointer to RPC service + * @buf: pointer to a buffer to fill in with socket names + * @buflen: size of the buffer to be filled + * @toclose: pointer to '\0'-terminated C string containing the name + * of a listener to be closed + * + * Fills in @buf with a '\n'-separated list of names of listener + * sockets. If @toclose is not NULL, the socket named by @toclose + * is closed, and is not included in the output list. + * + * Returns positive length of the socket name string, or a negative + * errno value on error. + */ +int svc_sock_names(struct svc_serv *serv, char *buf, const size_t buflen, + const char *toclose) { struct svc_sock *svsk, *closesk = NULL; int len = 0; if (!serv) return 0; + spin_lock_bh(&serv->sv_lock); list_for_each_entry(svsk, &serv->sv_permsocks, sk_xprt.xpt_list) { - int onelen = one_sock_name(buf+len, svsk); - if (toclose && strcmp(toclose, buf+len) == 0) + int onelen = svc_one_sock_name(svsk, buf + len, buflen - len); + if (onelen < 0) { + len = onelen; + break; + } + if (toclose && strcmp(toclose, buf + len) == 0) closesk = svsk; else len += onelen; } spin_unlock_bh(&serv->sv_lock); + if (closesk) /* Should unregister with portmap, but you cannot * unregister just one protocol... @@ -346,6 +380,7 @@ static void svc_sock_setbufsize(struct socket *sock, unsigned int snd, sock->sk->sk_sndbuf = snd * 2; sock->sk->sk_rcvbuf = rcv * 2; sock->sk->sk_userlocks |= SOCK_SNDBUF_LOCK|SOCK_RCVBUF_LOCK; + sock->sk->sk_write_space(sock->sk); release_sock(sock->sk); #endif } @@ -387,6 +422,15 @@ static void svc_write_space(struct sock *sk) } } +static void svc_tcp_write_space(struct sock *sk) +{ + struct socket *sock = sk->sk_socket; + + if (sk_stream_wspace(sk) >= sk_stream_min_wspace(sk) && sock) + clear_bit(SOCK_NOSPACE, &sock->flags); + svc_write_space(sk); +} + /* * Copy the UDP datagram's destination address to the rqstp structure. * The 'destination' address in this case is the address to which the @@ -427,13 +471,14 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp) long all[SVC_PKTINFO_SPACE / sizeof(long)]; } buffer; struct cmsghdr *cmh = &buffer.hdr; - int err, len; struct msghdr msg = { .msg_name = svc_addr(rqstp), .msg_control = cmh, .msg_controllen = sizeof(buffer), .msg_flags = MSG_DONTWAIT, }; + size_t len; + int err; if (test_and_clear_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags)) /* udp sockets need large rcvbuf as all pending @@ -465,8 +510,8 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp) return -EAGAIN; } len = svc_addr_len(svc_addr(rqstp)); - if (len < 0) - return len; + if (len == 0) + return -EAFNOSUPPORT; rqstp->rq_addrlen = len; if (skb->tstamp.tv64 == 0) { skb->tstamp = ktime_get_real(); @@ -980,25 +1025,16 @@ static void svc_tcp_prep_reply_hdr(struct svc_rqst *rqstp) static int svc_tcp_has_wspace(struct svc_xprt *xprt) { struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt); - struct svc_serv *serv = svsk->sk_xprt.xpt_server; + struct svc_serv *serv = svsk->sk_xprt.xpt_server; int required; - int wspace; - /* - * Set the SOCK_NOSPACE flag before checking the available - * sock space. - */ + if (test_bit(XPT_LISTENER, &xprt->xpt_flags)) + return 1; + required = atomic_read(&xprt->xpt_reserved) + serv->sv_max_mesg; + if (sk_stream_wspace(svsk->sk_sk) >= required) + return 1; set_bit(SOCK_NOSPACE, &svsk->sk_sock->flags); - required = atomic_read(&svsk->sk_xprt.xpt_reserved) + serv->sv_max_mesg; - wspace = sk_stream_wspace(svsk->sk_sk); - - if (wspace < sk_stream_min_wspace(svsk->sk_sk)) - return 0; - if (required * 2 > wspace) - return 0; - - clear_bit(SOCK_NOSPACE, &svsk->sk_sock->flags); - return 1; + return 0; } static struct svc_xprt *svc_tcp_create(struct svc_serv *serv, @@ -1054,7 +1090,7 @@ static void svc_tcp_init(struct svc_sock *svsk, struct svc_serv *serv) dprintk("setting up TCP socket for reading\n"); sk->sk_state_change = svc_tcp_state_change; sk->sk_data_ready = svc_tcp_data_ready; - sk->sk_write_space = svc_write_space; + sk->sk_write_space = svc_tcp_write_space; svsk->sk_reclen = 0; svsk->sk_tcplen = 0; @@ -1148,9 +1184,19 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv, return svsk; } -int svc_addsock(struct svc_serv *serv, - int fd, - char *name_return) +/** + * svc_addsock - add a listener socket to an RPC service + * @serv: pointer to RPC service to which to add a new listener + * @fd: file descriptor of the new listener + * @name_return: pointer to buffer to fill in with name of listener + * @len: size of the buffer + * + * Fills in socket name and returns positive length of name if successful. + * Name is terminated with '\n'. On error, returns a negative errno + * value. + */ +int svc_addsock(struct svc_serv *serv, const int fd, char *name_return, + const size_t len) { int err = 0; struct socket *so = sockfd_lookup(fd, &err); @@ -1190,7 +1236,7 @@ int svc_addsock(struct svc_serv *serv, sockfd_put(so); return err; } - return one_sock_name(name_return, svsk); + return svc_one_sock_name(svsk, name_return, len); } EXPORT_SYMBOL_GPL(svc_addsock); @@ -1327,3 +1373,42 @@ static void svc_sock_free(struct svc_xprt *xprt) sock_release(svsk->sk_sock); kfree(svsk); } + +/* + * Create a svc_xprt. + * + * For internal use only (e.g. nfsv4.1 backchannel). + * Callers should typically use the xpo_create() method. + */ +struct svc_xprt *svc_sock_create(struct svc_serv *serv, int prot) +{ + struct svc_sock *svsk; + struct svc_xprt *xprt = NULL; + + dprintk("svc: %s\n", __func__); + svsk = kzalloc(sizeof(*svsk), GFP_KERNEL); + if (!svsk) + goto out; + + xprt = &svsk->sk_xprt; + if (prot == IPPROTO_TCP) + svc_xprt_init(&svc_tcp_class, xprt, serv); + else if (prot == IPPROTO_UDP) + svc_xprt_init(&svc_udp_class, xprt, serv); + else + BUG(); +out: + dprintk("svc: %s return %p\n", __func__, xprt); + return xprt; +} +EXPORT_SYMBOL_GPL(svc_sock_create); + +/* + * Destroy a svc_sock. + */ +void svc_sock_destroy(struct svc_xprt *xprt) +{ + if (xprt) + kfree(container_of(xprt, struct svc_sock, sk_xprt)); +} +EXPORT_SYMBOL_GPL(svc_sock_destroy); diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 06ca058572f2..f412a852bc73 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -12,8 +12,9 @@ * - Next, the caller puts together the RPC message, stuffs it into * the request struct, and calls xprt_transmit(). * - xprt_transmit sends the message and installs the caller on the - * transport's wait list. At the same time, it installs a timer that - * is run after the packet's timeout has expired. + * transport's wait list. At the same time, if a reply is expected, + * it installs a timer that is run after the packet's timeout has + * expired. * - When a packet arrives, the data_ready handler walks the list of * pending requests for that transport. If a matching XID is found, the * caller is woken up, and the timer removed. @@ -46,6 +47,8 @@ #include #include +#include "sunrpc.h" + /* * Local variables */ @@ -192,8 +195,8 @@ EXPORT_SYMBOL_GPL(xprt_load_transport); */ int xprt_reserve_xprt(struct rpc_task *task) { - struct rpc_xprt *xprt = task->tk_xprt; struct rpc_rqst *req = task->tk_rqstp; + struct rpc_xprt *xprt = req->rq_xprt; if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) { if (task == xprt->snd_task) @@ -803,9 +806,10 @@ void xprt_complete_rqst(struct rpc_task *task, int copied) list_del_init(&req->rq_list); req->rq_private_buf.len = copied; - /* Ensure all writes are done before we update req->rq_received */ + /* Ensure all writes are done before we update */ + /* req->rq_reply_bytes_recvd */ smp_wmb(); - req->rq_received = copied; + req->rq_reply_bytes_recvd = copied; rpc_wake_up_queued_task(&xprt->pending, task); } EXPORT_SYMBOL_GPL(xprt_complete_rqst); @@ -820,7 +824,7 @@ static void xprt_timer(struct rpc_task *task) dprintk("RPC: %5u xprt_timer\n", task->tk_pid); spin_lock_bh(&xprt->transport_lock); - if (!req->rq_received) { + if (!req->rq_reply_bytes_recvd) { if (xprt->ops->timer) xprt->ops->timer(task); } else @@ -842,8 +846,8 @@ int xprt_prepare_transmit(struct rpc_task *task) dprintk("RPC: %5u xprt_prepare_transmit\n", task->tk_pid); spin_lock_bh(&xprt->transport_lock); - if (req->rq_received && !req->rq_bytes_sent) { - err = req->rq_received; + if (req->rq_reply_bytes_recvd && !req->rq_bytes_sent) { + err = req->rq_reply_bytes_recvd; goto out_unlock; } if (!xprt->ops->reserve_xprt(task)) @@ -855,7 +859,7 @@ out_unlock: void xprt_end_transmit(struct rpc_task *task) { - xprt_release_write(task->tk_xprt, task); + xprt_release_write(task->tk_rqstp->rq_xprt, task); } /** @@ -872,8 +876,11 @@ void xprt_transmit(struct rpc_task *task) dprintk("RPC: %5u xprt_transmit(%u)\n", task->tk_pid, req->rq_slen); - if (!req->rq_received) { - if (list_empty(&req->rq_list)) { + if (!req->rq_reply_bytes_recvd) { + if (list_empty(&req->rq_list) && rpc_reply_expected(task)) { + /* + * Add to the list only if we're expecting a reply + */ spin_lock_bh(&xprt->transport_lock); /* Update the softirq receive buffer */ memcpy(&req->rq_private_buf, &req->rq_rcv_buf, @@ -908,8 +915,13 @@ void xprt_transmit(struct rpc_task *task) /* Don't race with disconnect */ if (!xprt_connected(xprt)) task->tk_status = -ENOTCONN; - else if (!req->rq_received) + else if (!req->rq_reply_bytes_recvd && rpc_reply_expected(task)) { + /* + * Sleep on the pending queue since + * we're expecting a reply. + */ rpc_sleep_on(&xprt->pending, task, xprt_timer); + } spin_unlock_bh(&xprt->transport_lock); } @@ -982,11 +994,17 @@ static void xprt_request_init(struct rpc_task *task, struct rpc_xprt *xprt) */ void xprt_release(struct rpc_task *task) { - struct rpc_xprt *xprt = task->tk_xprt; + struct rpc_xprt *xprt; struct rpc_rqst *req; + int is_bc_request; if (!(req = task->tk_rqstp)) return; + + /* Preallocated backchannel request? */ + is_bc_request = bc_prealloc(req); + + xprt = req->rq_xprt; rpc_count_iostats(task); spin_lock_bh(&xprt->transport_lock); xprt->ops->release_xprt(xprt, task); @@ -999,10 +1017,19 @@ void xprt_release(struct rpc_task *task) mod_timer(&xprt->timer, xprt->last_used + xprt->idle_timeout); spin_unlock_bh(&xprt->transport_lock); - xprt->ops->buf_free(req->rq_buffer); + if (!bc_prealloc(req)) + xprt->ops->buf_free(req->rq_buffer); task->tk_rqstp = NULL; if (req->rq_release_snd_buf) req->rq_release_snd_buf(req); + + /* + * Early exit if this is a backchannel preallocated request. + * There is no need to have it added to the RPC slot list. + */ + if (is_bc_request) + return; + memset(req, 0, sizeof(*req)); /* mark unused */ dprintk("RPC: %5u release request %p\n", task->tk_pid, req); @@ -1049,6 +1076,11 @@ found: INIT_LIST_HEAD(&xprt->free); INIT_LIST_HEAD(&xprt->recv); +#if defined(CONFIG_NFS_V4_1) + spin_lock_init(&xprt->bc_pa_lock); + INIT_LIST_HEAD(&xprt->bc_pa_list); +#endif /* CONFIG_NFS_V4_1 */ + INIT_WORK(&xprt->task_cleanup, xprt_autoclose); setup_timer(&xprt->timer, xprt_init_autodisconnect, (unsigned long)xprt); diff --git a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c index 42a6f9f20285..9e884383134f 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c +++ b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c @@ -397,14 +397,14 @@ static int rdma_read_xdr(struct svcxprt_rdma *xprt, if (!ch) return 0; - /* 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; + /* Allocate temporary reply and chunk maps */ + rpl_map = svc_rdma_get_req_map(); + chl_map = svc_rdma_get_req_map(); + if (!xprt->sc_frmr_pg_list_len) sge_count = map_read_chunks(xprt, rqstp, hdr_ctxt, rmsgp, rpl_map, chl_map, ch_count, diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index e18596146013..83c73c4d017a 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -34,6 +34,9 @@ #include #include #include +#ifdef CONFIG_NFS_V4_1 +#include +#endif #include #include @@ -270,6 +273,13 @@ struct sock_xprt { #define TCP_RCV_COPY_FRAGHDR (1UL << 1) #define TCP_RCV_COPY_XID (1UL << 2) #define TCP_RCV_COPY_DATA (1UL << 3) +#define TCP_RCV_READ_CALLDIR (1UL << 4) +#define TCP_RCV_COPY_CALLDIR (1UL << 5) + +/* + * TCP RPC flags + */ +#define TCP_RPC_REPLY (1UL << 6) static inline struct sockaddr *xs_addr(struct rpc_xprt *xprt) { @@ -918,7 +928,7 @@ static void xs_udp_data_ready(struct sock *sk, int len) UDPX_INC_STATS_BH(sk, UDP_MIB_INDATAGRAMS); /* Something worked... */ - dst_confirm(skb->dst); + dst_confirm(skb_dst(skb)); xprt_adjust_cwnd(task, copied); xprt_update_rtt(task); @@ -956,7 +966,7 @@ static inline void xs_tcp_read_fraghdr(struct rpc_xprt *xprt, struct xdr_skb_rea transport->tcp_offset = 0; /* Sanity check of the record length */ - if (unlikely(transport->tcp_reclen < 4)) { + if (unlikely(transport->tcp_reclen < 8)) { dprintk("RPC: invalid TCP record fragment length\n"); xprt_force_disconnect(xprt); return; @@ -991,33 +1001,77 @@ static inline void xs_tcp_read_xid(struct sock_xprt *transport, struct xdr_skb_r if (used != len) return; transport->tcp_flags &= ~TCP_RCV_COPY_XID; - transport->tcp_flags |= TCP_RCV_COPY_DATA; + transport->tcp_flags |= TCP_RCV_READ_CALLDIR; transport->tcp_copied = 4; - dprintk("RPC: reading reply for XID %08x\n", + dprintk("RPC: reading %s XID %08x\n", + (transport->tcp_flags & TCP_RPC_REPLY) ? "reply for" + : "request with", ntohl(transport->tcp_xid)); xs_tcp_check_fraghdr(transport); } -static inline void xs_tcp_read_request(struct rpc_xprt *xprt, struct xdr_skb_reader *desc) +static inline void xs_tcp_read_calldir(struct sock_xprt *transport, + struct xdr_skb_reader *desc) { - struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); - struct rpc_rqst *req; + size_t len, used; + u32 offset; + __be32 calldir; + + /* + * We want transport->tcp_offset to be 8 at the end of this routine + * (4 bytes for the xid and 4 bytes for the call/reply flag). + * When this function is called for the first time, + * transport->tcp_offset is 4 (after having already read the xid). + */ + offset = transport->tcp_offset - sizeof(transport->tcp_xid); + len = sizeof(calldir) - offset; + dprintk("RPC: reading CALL/REPLY flag (%Zu bytes)\n", len); + used = xdr_skb_read_bits(desc, &calldir, len); + transport->tcp_offset += used; + if (used != len) + return; + transport->tcp_flags &= ~TCP_RCV_READ_CALLDIR; + transport->tcp_flags |= TCP_RCV_COPY_CALLDIR; + transport->tcp_flags |= TCP_RCV_COPY_DATA; + /* + * We don't yet have the XDR buffer, so we will write the calldir + * out after we get the buffer from the 'struct rpc_rqst' + */ + if (ntohl(calldir) == RPC_REPLY) + transport->tcp_flags |= TCP_RPC_REPLY; + else + transport->tcp_flags &= ~TCP_RPC_REPLY; + dprintk("RPC: reading %s CALL/REPLY flag %08x\n", + (transport->tcp_flags & TCP_RPC_REPLY) ? + "reply for" : "request with", calldir); + xs_tcp_check_fraghdr(transport); +} + +static inline void xs_tcp_read_common(struct rpc_xprt *xprt, + struct xdr_skb_reader *desc, + struct rpc_rqst *req) +{ + struct sock_xprt *transport = + container_of(xprt, struct sock_xprt, xprt); struct xdr_buf *rcvbuf; size_t len; ssize_t r; - /* Find and lock the request corresponding to this xid */ - spin_lock(&xprt->transport_lock); - req = xprt_lookup_rqst(xprt, transport->tcp_xid); - if (!req) { - transport->tcp_flags &= ~TCP_RCV_COPY_DATA; - dprintk("RPC: XID %08x request not found!\n", - ntohl(transport->tcp_xid)); - spin_unlock(&xprt->transport_lock); - return; + rcvbuf = &req->rq_private_buf; + + if (transport->tcp_flags & TCP_RCV_COPY_CALLDIR) { + /* + * Save the RPC direction in the XDR buffer + */ + __be32 calldir = transport->tcp_flags & TCP_RPC_REPLY ? + htonl(RPC_REPLY) : 0; + + memcpy(rcvbuf->head[0].iov_base + transport->tcp_copied, + &calldir, sizeof(calldir)); + transport->tcp_copied += sizeof(calldir); + transport->tcp_flags &= ~TCP_RCV_COPY_CALLDIR; } - rcvbuf = &req->rq_private_buf; len = desc->count; if (len > transport->tcp_reclen - transport->tcp_offset) { struct xdr_skb_reader my_desc; @@ -1054,7 +1108,7 @@ static inline void xs_tcp_read_request(struct rpc_xprt *xprt, struct xdr_skb_rea "tcp_offset = %u, tcp_reclen = %u\n", xprt, transport->tcp_copied, transport->tcp_offset, transport->tcp_reclen); - goto out; + return; } dprintk("RPC: XID %08x read %Zd bytes\n", @@ -1070,11 +1124,125 @@ static inline void xs_tcp_read_request(struct rpc_xprt *xprt, struct xdr_skb_rea transport->tcp_flags &= ~TCP_RCV_COPY_DATA; } -out: + return; +} + +/* + * Finds the request corresponding to the RPC xid and invokes the common + * tcp read code to read the data. + */ +static inline int xs_tcp_read_reply(struct rpc_xprt *xprt, + struct xdr_skb_reader *desc) +{ + struct sock_xprt *transport = + container_of(xprt, struct sock_xprt, xprt); + struct rpc_rqst *req; + + dprintk("RPC: read reply XID %08x\n", ntohl(transport->tcp_xid)); + + /* Find and lock the request corresponding to this xid */ + spin_lock(&xprt->transport_lock); + req = xprt_lookup_rqst(xprt, transport->tcp_xid); + if (!req) { + dprintk("RPC: XID %08x request not found!\n", + ntohl(transport->tcp_xid)); + spin_unlock(&xprt->transport_lock); + return -1; + } + + xs_tcp_read_common(xprt, desc, req); + if (!(transport->tcp_flags & TCP_RCV_COPY_DATA)) xprt_complete_rqst(req->rq_task, transport->tcp_copied); + spin_unlock(&xprt->transport_lock); - xs_tcp_check_fraghdr(transport); + return 0; +} + +#if defined(CONFIG_NFS_V4_1) +/* + * Obtains an rpc_rqst previously allocated and invokes the common + * tcp read code to read the data. The result is placed in the callback + * queue. + * If we're unable to obtain the rpc_rqst we schedule the closing of the + * connection and return -1. + */ +static inline int xs_tcp_read_callback(struct rpc_xprt *xprt, + struct xdr_skb_reader *desc) +{ + struct sock_xprt *transport = + container_of(xprt, struct sock_xprt, xprt); + struct rpc_rqst *req; + + req = xprt_alloc_bc_request(xprt); + if (req == NULL) { + printk(KERN_WARNING "Callback slot table overflowed\n"); + xprt_force_disconnect(xprt); + return -1; + } + + req->rq_xid = transport->tcp_xid; + dprintk("RPC: read callback XID %08x\n", ntohl(req->rq_xid)); + xs_tcp_read_common(xprt, desc, req); + + if (!(transport->tcp_flags & TCP_RCV_COPY_DATA)) { + struct svc_serv *bc_serv = xprt->bc_serv; + + /* + * Add callback request to callback list. The callback + * service sleeps on the sv_cb_waitq waiting for new + * requests. Wake it up after adding enqueing the + * request. + */ + dprintk("RPC: add callback request to list\n"); + spin_lock(&bc_serv->sv_cb_lock); + list_add(&req->rq_bc_list, &bc_serv->sv_cb_list); + spin_unlock(&bc_serv->sv_cb_lock); + wake_up(&bc_serv->sv_cb_waitq); + } + + req->rq_private_buf.len = transport->tcp_copied; + + return 0; +} + +static inline int _xs_tcp_read_data(struct rpc_xprt *xprt, + struct xdr_skb_reader *desc) +{ + struct sock_xprt *transport = + container_of(xprt, struct sock_xprt, xprt); + + return (transport->tcp_flags & TCP_RPC_REPLY) ? + xs_tcp_read_reply(xprt, desc) : + xs_tcp_read_callback(xprt, desc); +} +#else +static inline int _xs_tcp_read_data(struct rpc_xprt *xprt, + struct xdr_skb_reader *desc) +{ + return xs_tcp_read_reply(xprt, desc); +} +#endif /* CONFIG_NFS_V4_1 */ + +/* + * Read data off the transport. This can be either an RPC_CALL or an + * RPC_REPLY. Relay the processing to helper functions. + */ +static void xs_tcp_read_data(struct rpc_xprt *xprt, + struct xdr_skb_reader *desc) +{ + struct sock_xprt *transport = + container_of(xprt, struct sock_xprt, xprt); + + if (_xs_tcp_read_data(xprt, desc) == 0) + xs_tcp_check_fraghdr(transport); + else { + /* + * The transport_lock protects the request handling. + * There's no need to hold it to update the tcp_flags. + */ + transport->tcp_flags &= ~TCP_RCV_COPY_DATA; + } } static inline void xs_tcp_read_discard(struct sock_xprt *transport, struct xdr_skb_reader *desc) @@ -1114,9 +1282,14 @@ static int xs_tcp_data_recv(read_descriptor_t *rd_desc, struct sk_buff *skb, uns xs_tcp_read_xid(transport, &desc); continue; } + /* Read in the call/reply flag */ + if (transport->tcp_flags & TCP_RCV_READ_CALLDIR) { + xs_tcp_read_calldir(transport, &desc); + continue; + } /* Read in the request data */ if (transport->tcp_flags & TCP_RCV_COPY_DATA) { - xs_tcp_read_request(xprt, &desc); + xs_tcp_read_data(xprt, &desc); continue; } /* Skip over any trailing bytes on short reads */ @@ -1792,6 +1965,7 @@ static void xs_tcp_setup_socket(struct rpc_xprt *xprt, */ set_bit(XPRT_CONNECTION_CLOSE, &xprt->state); xprt_force_disconnect(xprt); + break; case -ECONNREFUSED: case -ECONNRESET: case -ENETUNREACH: @@ -2010,6 +2184,9 @@ static struct rpc_xprt_ops xs_tcp_ops = { .buf_free = rpc_free, .send_request = xs_tcp_send_request, .set_retrans_timeout = xprt_set_retrans_timeout_def, +#if defined(CONFIG_NFS_V4_1) + .release_request = bc_release_request, +#endif /* CONFIG_NFS_V4_1 */ .close = xs_tcp_close, .destroy = xs_destroy, .print_stats = xs_tcp_print_stats, diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c index f72ba774c246..524ba5696d4d 100644 --- a/net/tipc/eth_media.c +++ b/net/tipc/eth_media.c @@ -167,7 +167,7 @@ static int enable_bearer(struct tipc_bearer *tb_ptr) tb_ptr->mtu = dev->mtu; tb_ptr->blocked = 0; tb_ptr->addr.type = htonl(TIPC_MEDIA_TYPE_ETH); - memcpy(&tb_ptr->addr.dev_addr, &dev->dev_addr, ETH_ALEN); + memcpy(&tb_ptr->addr.dev_addr, dev->dev_addr, ETH_ALEN); return 0; } diff --git a/net/tipc/netlink.c b/net/tipc/netlink.c index c387217bb230..3c57005e44d1 100644 --- a/net/tipc/netlink.c +++ b/net/tipc/netlink.c @@ -68,7 +68,7 @@ static int handle_cmd(struct sk_buff *skb, struct genl_info *info) return 0; } -static struct genl_family family = { +static struct genl_family tipc_genl_family = { .id = GENL_ID_GENERATE, .name = TIPC_GENL_NAME, .version = TIPC_GENL_VERSION, @@ -76,39 +76,33 @@ static struct genl_family family = { .maxattr = 0, }; -static struct genl_ops ops = { +static struct genl_ops tipc_genl_ops = { .cmd = TIPC_GENL_CMD, .doit = handle_cmd, }; -static int family_registered = 0; +static int tipc_genl_family_registered; int tipc_netlink_start(void) { + int res; + res = genl_register_family_with_ops(&tipc_genl_family, + &tipc_genl_ops, 1); + if (res) { + err("Failed to register netlink interface\n"); + return res; + } - if (genl_register_family(&family)) - goto err; - - family_registered = 1; - - if (genl_register_ops(&family, &ops)) - goto err_unregister; - + tipc_genl_family_registered = 1; return 0; - - err_unregister: - genl_unregister_family(&family); - family_registered = 0; - err: - err("Failed to register netlink interface\n"); - return -EFAULT; } void tipc_netlink_stop(void) { - if (family_registered) { - genl_unregister_family(&family); - family_registered = 0; - } + if (!tipc_genl_family_registered) + return; + + genl_unregister_family(&tipc_genl_family); + tipc_genl_family_registered = 0; } diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 9dcc6e7f96ec..36d4e44d6233 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -1946,7 +1946,7 @@ static int unix_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) switch (cmd) { case SIOCOUTQ: - amount = atomic_read(&sk->sk_wmem_alloc); + amount = sk_wmem_alloc_get(sk); err = put_user(amount, (int __user *)arg); break; case SIOCINQ: diff --git a/net/wimax/Kconfig b/net/wimax/Kconfig index 1b46747a5f5a..e4d97ab476d5 100644 --- a/net/wimax/Kconfig +++ b/net/wimax/Kconfig @@ -1,23 +1,10 @@ # # WiMAX LAN device configuration # -# Note the ugly 'depends on' on WIMAX: that disallows RFKILL to be a -# module if WIMAX is to be linked in. The WiMAX code is done in such a -# way that it doesn't require and explicit dependency on RFKILL in -# case an embedded system wants to rip it out. -# -# As well, enablement of the RFKILL code means we need the INPUT layer -# support to inject events coming from hw rfkill switches. That -# dependency could be killed if input.h provided appropriate means to -# work when input is disabled. - -comment "WiMAX Wireless Broadband support requires CONFIG_INPUT enabled" - depends on INPUT = n && RFKILL != n menuconfig WIMAX tristate "WiMAX Wireless Broadband support" - depends on (y && RFKILL != m) || m - depends on (INPUT && RFKILL != n) || RFKILL = n + depends on RFKILL || !RFKILL help Select to configure support for devices that provide diff --git a/net/wimax/Makefile b/net/wimax/Makefile index 5b80b941c2c9..8f1510d0cc2b 100644 --- a/net/wimax/Makefile +++ b/net/wimax/Makefile @@ -6,6 +6,7 @@ wimax-y := \ op-msg.o \ op-reset.o \ op-rfkill.o \ + op-state-get.o \ stack.o wimax-$(CONFIG_DEBUG_FS) += debugfs.o diff --git a/net/wimax/debug-levels.h b/net/wimax/debug-levels.h index 1c29123a3aa9..0975adba6b71 100644 --- a/net/wimax/debug-levels.h +++ b/net/wimax/debug-levels.h @@ -36,6 +36,7 @@ enum d_module { D_SUBMODULE_DECLARE(op_msg), D_SUBMODULE_DECLARE(op_reset), D_SUBMODULE_DECLARE(op_rfkill), + D_SUBMODULE_DECLARE(op_state_get), D_SUBMODULE_DECLARE(stack), }; diff --git a/net/wimax/debugfs.c b/net/wimax/debugfs.c index 94d216a46407..6c9bedb7431e 100644 --- a/net/wimax/debugfs.c +++ b/net/wimax/debugfs.c @@ -61,6 +61,7 @@ int wimax_debugfs_add(struct wimax_dev *wimax_dev) __debugfs_register("wimax_dl_", op_msg, dentry); __debugfs_register("wimax_dl_", op_reset, dentry); __debugfs_register("wimax_dl_", op_rfkill, dentry); + __debugfs_register("wimax_dl_", op_state_get, dentry); __debugfs_register("wimax_dl_", stack, dentry); result = 0; out: diff --git a/net/wimax/op-msg.c b/net/wimax/op-msg.c index 9ad4d893a566..d631a17186bc 100644 --- a/net/wimax/op-msg.c +++ b/net/wimax/op-msg.c @@ -108,6 +108,12 @@ * Don't use skb_push()/skb_pull()/skb_reserve() on the skb, as * wimax_msg_send() depends on skb->data being placed at the * beginning of the user message. + * + * Unlike other WiMAX stack calls, this call can be used way early, + * even before wimax_dev_add() is called, as long as the + * wimax_dev->net_dev pointer is set to point to a proper + * net_dev. This is so that drivers can use it early in case they need + * to send stuff around or communicate with user space. */ struct sk_buff *wimax_msg_alloc(struct wimax_dev *wimax_dev, const char *pipe_name, @@ -115,7 +121,7 @@ struct sk_buff *wimax_msg_alloc(struct wimax_dev *wimax_dev, gfp_t gfp_flags) { int result; - struct device *dev = wimax_dev->net_dev->dev.parent; + struct device *dev = wimax_dev_to_dev(wimax_dev); size_t msg_size; void *genl_msg; struct sk_buff *skb; @@ -161,7 +167,6 @@ error_genlmsg_put: error_new: nlmsg_free(skb); return ERR_PTR(result); - } EXPORT_SYMBOL_GPL(wimax_msg_alloc); @@ -256,10 +261,16 @@ EXPORT_SYMBOL_GPL(wimax_msg_len); * Don't use skb_push()/skb_pull()/skb_reserve() on the skb, as * wimax_msg_send() depends on skb->data being placed at the * beginning of the user message. + * + * Unlike other WiMAX stack calls, this call can be used way early, + * even before wimax_dev_add() is called, as long as the + * wimax_dev->net_dev pointer is set to point to a proper + * net_dev. This is so that drivers can use it early in case they need + * to send stuff around or communicate with user space. */ int wimax_msg_send(struct wimax_dev *wimax_dev, struct sk_buff *skb) { - struct device *dev = wimax_dev->net_dev->dev.parent; + struct device *dev = wimax_dev_to_dev(wimax_dev); void *msg = skb->data; size_t size = skb->len; might_sleep(); diff --git a/net/wimax/op-rfkill.c b/net/wimax/op-rfkill.c index 2b75aee04217..70ef4df863b9 100644 --- a/net/wimax/op-rfkill.c +++ b/net/wimax/op-rfkill.c @@ -29,8 +29,8 @@ * A non-polled generic rfkill device is embedded into the WiMAX * subsystem's representation of a device. * - * FIXME: Need polled support? use a timer or add the implementation - * to the stack. + * FIXME: Need polled support? Let drivers provide a poll routine + * and hand it to rfkill ops then? * * All device drivers have to do is after wimax_dev_init(), call * wimax_report_rfkill_hw() and wimax_report_rfkill_sw() to update @@ -43,7 +43,7 @@ * wimax_rfkill() Kernel calling wimax_rfkill() * __wimax_rf_toggle_radio() * - * wimax_rfkill_toggle_radio() RF-Kill subsytem calling + * wimax_rfkill_set_radio_block() RF-Kill subsytem calling * __wimax_rf_toggle_radio() * * __wimax_rf_toggle_radio() @@ -65,15 +65,11 @@ #include #include #include -#include #include "wimax-internal.h" #define D_SUBMODULE op_rfkill #include "debug-levels.h" -#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) - - /** * wimax_report_rfkill_hw - Reports changes in the hardware RF switch * @@ -99,7 +95,6 @@ void wimax_report_rfkill_hw(struct wimax_dev *wimax_dev, int result; struct device *dev = wimax_dev_to_dev(wimax_dev); enum wimax_st wimax_state; - enum rfkill_state rfkill_state; d_fnstart(3, dev, "(wimax_dev %p state %u)\n", wimax_dev, state); BUG_ON(state == WIMAX_RF_QUERY); @@ -112,16 +107,16 @@ void wimax_report_rfkill_hw(struct wimax_dev *wimax_dev, if (state != wimax_dev->rf_hw) { wimax_dev->rf_hw = state; - rfkill_state = state == WIMAX_RF_ON ? - RFKILL_STATE_OFF : RFKILL_STATE_ON; if (wimax_dev->rf_hw == WIMAX_RF_ON && wimax_dev->rf_sw == WIMAX_RF_ON) wimax_state = WIMAX_ST_READY; else wimax_state = WIMAX_ST_RADIO_OFF; + + result = rfkill_set_hw_state(wimax_dev->rfkill, + state == WIMAX_RF_OFF); + __wimax_state_change(wimax_dev, wimax_state); - input_report_key(wimax_dev->rfkill_input, KEY_WIMAX, - rfkill_state); } error_not_ready: mutex_unlock(&wimax_dev->mutex); @@ -174,6 +169,7 @@ void wimax_report_rfkill_sw(struct wimax_dev *wimax_dev, else wimax_state = WIMAX_ST_RADIO_OFF; __wimax_state_change(wimax_dev, wimax_state); + rfkill_set_sw_state(wimax_dev->rfkill, state == WIMAX_RF_OFF); } error_not_ready: mutex_unlock(&wimax_dev->mutex); @@ -249,36 +245,31 @@ out_no_change: * * NOTE: This call will block until the operation is completed. */ -static -int wimax_rfkill_toggle_radio(void *data, enum rfkill_state state) +static int wimax_rfkill_set_radio_block(void *data, bool blocked) { int result; struct wimax_dev *wimax_dev = data; struct device *dev = wimax_dev_to_dev(wimax_dev); enum wimax_rf_state rf_state; - d_fnstart(3, dev, "(wimax_dev %p state %u)\n", wimax_dev, state); - switch (state) { - case RFKILL_STATE_ON: + d_fnstart(3, dev, "(wimax_dev %p blocked %u)\n", wimax_dev, blocked); + rf_state = WIMAX_RF_ON; + if (blocked) rf_state = WIMAX_RF_OFF; - break; - case RFKILL_STATE_OFF: - rf_state = WIMAX_RF_ON; - break; - default: - BUG(); - } mutex_lock(&wimax_dev->mutex); if (wimax_dev->state <= __WIMAX_ST_QUIESCING) - result = 0; /* just pretend it didn't happen */ + result = 0; else result = __wimax_rf_toggle_radio(wimax_dev, rf_state); mutex_unlock(&wimax_dev->mutex); - d_fnend(3, dev, "(wimax_dev %p state %u) = %d\n", - wimax_dev, state, result); + d_fnend(3, dev, "(wimax_dev %p blocked %u) = %d\n", + wimax_dev, blocked, result); return result; } +static const struct rfkill_ops wimax_rfkill_ops = { + .set_block = wimax_rfkill_set_radio_block, +}; /** * wimax_rfkill - Set the software RF switch state for a WiMAX device @@ -322,6 +313,7 @@ int wimax_rfkill(struct wimax_dev *wimax_dev, enum wimax_rf_state state) result = __wimax_rf_toggle_radio(wimax_dev, state); if (result < 0) goto error; + rfkill_set_sw_state(wimax_dev->rfkill, state == WIMAX_RF_OFF); break; case WIMAX_RF_QUERY: break; @@ -349,41 +341,20 @@ int wimax_rfkill_add(struct wimax_dev *wimax_dev) { int result; struct rfkill *rfkill; - struct input_dev *input_dev; struct device *dev = wimax_dev_to_dev(wimax_dev); d_fnstart(3, dev, "(wimax_dev %p)\n", wimax_dev); /* Initialize RF Kill */ result = -ENOMEM; - rfkill = rfkill_allocate(dev, RFKILL_TYPE_WIMAX); + rfkill = rfkill_alloc(wimax_dev->name, dev, RFKILL_TYPE_WIMAX, + &wimax_rfkill_ops, wimax_dev); if (rfkill == NULL) goto error_rfkill_allocate; + + d_printf(1, dev, "rfkill %p\n", rfkill); + wimax_dev->rfkill = rfkill; - rfkill->name = wimax_dev->name; - rfkill->state = RFKILL_STATE_OFF; - rfkill->data = wimax_dev; - rfkill->toggle_radio = wimax_rfkill_toggle_radio; - rfkill->user_claim_unsupported = 1; - - /* Initialize the input device for the hw key */ - input_dev = input_allocate_device(); - if (input_dev == NULL) - goto error_input_allocate; - wimax_dev->rfkill_input = input_dev; - d_printf(1, dev, "rfkill %p input %p\n", rfkill, input_dev); - - input_dev->name = wimax_dev->name; - /* FIXME: get a real device bus ID and stuff? do we care? */ - input_dev->id.bustype = BUS_HOST; - input_dev->id.vendor = 0xffff; - input_dev->evbit[0] = BIT(EV_KEY); - set_bit(KEY_WIMAX, input_dev->keybit); - - /* Register both */ - result = input_register_device(wimax_dev->rfkill_input); - if (result < 0) - goto error_input_register; result = rfkill_register(wimax_dev->rfkill); if (result < 0) goto error_rfkill_register; @@ -395,17 +366,8 @@ int wimax_rfkill_add(struct wimax_dev *wimax_dev) d_fnend(3, dev, "(wimax_dev %p) = 0\n", wimax_dev); return 0; - /* if rfkill_register() suceeds, can't use rfkill_free() any - * more, only rfkill_unregister() [it owns the refcount]; with - * the input device we have the same issue--hence the if. */ error_rfkill_register: - input_unregister_device(wimax_dev->rfkill_input); - wimax_dev->rfkill_input = NULL; -error_input_register: - if (wimax_dev->rfkill_input) - input_free_device(wimax_dev->rfkill_input); -error_input_allocate: - rfkill_free(wimax_dev->rfkill); + rfkill_destroy(wimax_dev->rfkill); error_rfkill_allocate: d_fnend(3, dev, "(wimax_dev %p) = %d\n", wimax_dev, result); return result; @@ -424,45 +386,12 @@ void wimax_rfkill_rm(struct wimax_dev *wimax_dev) { struct device *dev = wimax_dev_to_dev(wimax_dev); d_fnstart(3, dev, "(wimax_dev %p)\n", wimax_dev); - rfkill_unregister(wimax_dev->rfkill); /* frees */ - input_unregister_device(wimax_dev->rfkill_input); + rfkill_unregister(wimax_dev->rfkill); + rfkill_destroy(wimax_dev->rfkill); d_fnend(3, dev, "(wimax_dev %p)\n", wimax_dev); } -#else /* #ifdef CONFIG_RFKILL */ - -void wimax_report_rfkill_hw(struct wimax_dev *wimax_dev, - enum wimax_rf_state state) -{ -} -EXPORT_SYMBOL_GPL(wimax_report_rfkill_hw); - -void wimax_report_rfkill_sw(struct wimax_dev *wimax_dev, - enum wimax_rf_state state) -{ -} -EXPORT_SYMBOL_GPL(wimax_report_rfkill_sw); - -int wimax_rfkill(struct wimax_dev *wimax_dev, - enum wimax_rf_state state) -{ - return WIMAX_RF_ON << 1 | WIMAX_RF_ON; -} -EXPORT_SYMBOL_GPL(wimax_rfkill); - -int wimax_rfkill_add(struct wimax_dev *wimax_dev) -{ - return 0; -} - -void wimax_rfkill_rm(struct wimax_dev *wimax_dev) -{ -} - -#endif /* #ifdef CONFIG_RFKILL */ - - /* * Exporting to user space over generic netlink * diff --git a/net/wimax/op-state-get.c b/net/wimax/op-state-get.c new file mode 100644 index 000000000000..a76b8fcb056d --- /dev/null +++ b/net/wimax/op-state-get.c @@ -0,0 +1,86 @@ +/* + * Linux WiMAX + * Implement and export a method for getting a WiMAX device current state + * + * Copyright (C) 2009 Paulius Zaleckas + * + * Based on previous WiMAX core work by: + * Copyright (C) 2008 Intel Corporation + * Inaky Perez-Gonzalez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include +#include +#include +#include +#include "wimax-internal.h" + +#define D_SUBMODULE op_state_get +#include "debug-levels.h" + + +static const +struct nla_policy wimax_gnl_state_get_policy[WIMAX_GNL_ATTR_MAX + 1] = { + [WIMAX_GNL_STGET_IFIDX] = { + .type = NLA_U32, + }, +}; + + +/* + * Exporting to user space over generic netlink + * + * Parse the state get command from user space, return a combination + * value that describe the current state. + * + * No attributes. + */ +static +int wimax_gnl_doit_state_get(struct sk_buff *skb, struct genl_info *info) +{ + int result, ifindex; + struct wimax_dev *wimax_dev; + struct device *dev; + + d_fnstart(3, NULL, "(skb %p info %p)\n", skb, info); + result = -ENODEV; + if (info->attrs[WIMAX_GNL_STGET_IFIDX] == NULL) { + printk(KERN_ERR "WIMAX_GNL_OP_STATE_GET: can't find IFIDX " + "attribute\n"); + goto error_no_wimax_dev; + } + ifindex = nla_get_u32(info->attrs[WIMAX_GNL_STGET_IFIDX]); + wimax_dev = wimax_dev_get_by_genl_info(info, ifindex); + if (wimax_dev == NULL) + goto error_no_wimax_dev; + dev = wimax_dev_to_dev(wimax_dev); + /* Execute the operation and send the result back to user space */ + result = wimax_state_get(wimax_dev); + dev_put(wimax_dev->net_dev); +error_no_wimax_dev: + d_fnend(3, NULL, "(skb %p info %p) = %d\n", skb, info, result); + return result; +} + + +struct genl_ops wimax_gnl_state_get = { + .cmd = WIMAX_GNL_OP_STATE_GET, + .flags = GENL_ADMIN_PERM, + .policy = wimax_gnl_state_get_policy, + .doit = wimax_gnl_doit_state_get, + .dumpit = NULL, +}; diff --git a/net/wimax/stack.c b/net/wimax/stack.c index 933e1422b09f..79fb7d7c640f 100644 --- a/net/wimax/stack.c +++ b/net/wimax/stack.c @@ -402,13 +402,15 @@ EXPORT_SYMBOL_GPL(wimax_dev_init); extern struct genl_ops wimax_gnl_msg_from_user, wimax_gnl_reset, - wimax_gnl_rfkill; + wimax_gnl_rfkill, + wimax_gnl_state_get; static struct genl_ops *wimax_gnl_ops[] = { &wimax_gnl_msg_from_user, &wimax_gnl_reset, &wimax_gnl_rfkill, + &wimax_gnl_state_get, }; @@ -533,6 +535,7 @@ struct d_level D_LEVEL[] = { D_SUBMODULE_DEFINE(op_msg), D_SUBMODULE_DEFINE(op_reset), D_SUBMODULE_DEFINE(op_rfkill), + D_SUBMODULE_DEFINE(op_state_get), D_SUBMODULE_DEFINE(stack), }; size_t D_LEVEL_SIZE = ARRAY_SIZE(D_LEVEL); diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig index 3c3bc9e579ed..4428dd5e911d 100644 --- a/net/wireless/Kconfig +++ b/net/wireless/Kconfig @@ -1,5 +1,6 @@ config CFG80211 - tristate "Improved wireless configuration API" + tristate "Improved wireless configuration API" + depends on RFKILL || !RFKILL config CFG80211_REG_DEBUG bool "cfg80211 regulatory debugging" @@ -10,6 +11,14 @@ config CFG80211_REG_DEBUG If unsure, say N. +config CFG80211_DEBUGFS + bool "cfg80211 DebugFS entries" + depends on CFG80211 && DEBUG_FS + ---help--- + You can enable this if you want to debugfs entries for cfg80211. + + If unsure, say N. + config WIRELESS_OLD_REGULATORY bool "Old wireless static regulatory definitions" default n diff --git a/net/wireless/Makefile b/net/wireless/Makefile index 6d1e7b27b752..f78c4832a9ca 100644 --- a/net/wireless/Makefile +++ b/net/wireless/Makefile @@ -5,7 +5,8 @@ obj-$(CONFIG_LIB80211_CRYPT_WEP) += lib80211_crypt_wep.o obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o -cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o mlme.o +cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o mlme.o ibss.o +cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o ccflags-y += -D__CHECK_ENDIAN__ diff --git a/net/wireless/core.c b/net/wireless/core.c index d1f556535f6d..d5850292b3df 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -1,7 +1,7 @@ /* * This is the linux wireless configuration interface. * - * Copyright 2006-2008 Johannes Berg + * Copyright 2006-2009 Johannes Berg */ #include @@ -12,12 +12,13 @@ #include #include #include +#include #include #include -#include #include "nl80211.h" #include "core.h" #include "sysfs.h" +#include "debugfs.h" /* name for sysfs, %d is appended */ #define PHY_NAME "phy" @@ -227,9 +228,44 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, return 0; } +static void cfg80211_rfkill_poll(struct rfkill *rfkill, void *data) +{ + struct cfg80211_registered_device *drv = data; + + drv->ops->rfkill_poll(&drv->wiphy); +} + +static int cfg80211_rfkill_set_block(void *data, bool blocked) +{ + struct cfg80211_registered_device *drv = data; + struct wireless_dev *wdev; + + if (!blocked) + return 0; + + rtnl_lock(); + mutex_lock(&drv->devlist_mtx); + + list_for_each_entry(wdev, &drv->netdev_list, list) + dev_close(wdev->netdev); + + mutex_unlock(&drv->devlist_mtx); + rtnl_unlock(); + + return 0; +} + +static void cfg80211_rfkill_sync_work(struct work_struct *work) +{ + struct cfg80211_registered_device *drv; + + drv = container_of(work, struct cfg80211_registered_device, rfkill_sync); + cfg80211_rfkill_set_block(drv, rfkill_blocked(drv->rfkill)); +} + /* exported functions */ -struct wiphy *wiphy_new(struct cfg80211_ops *ops, int sizeof_priv) +struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) { static int wiphy_counter; @@ -274,6 +310,28 @@ struct wiphy *wiphy_new(struct cfg80211_ops *ops, int sizeof_priv) drv->wiphy.dev.class = &ieee80211_class; drv->wiphy.dev.platform_data = drv; + drv->rfkill_ops.set_block = cfg80211_rfkill_set_block; + drv->rfkill = rfkill_alloc(dev_name(&drv->wiphy.dev), + &drv->wiphy.dev, RFKILL_TYPE_WLAN, + &drv->rfkill_ops, drv); + + if (!drv->rfkill) { + kfree(drv); + return NULL; + } + + INIT_WORK(&drv->rfkill_sync, cfg80211_rfkill_sync_work); + + /* + * Initialize wiphy parameters to IEEE 802.11 MIB default values. + * Fragmentation and RTS threshold are disabled by default with the + * special -1 value. + */ + drv->wiphy.retry_short = 7; + drv->wiphy.retry_long = 4; + drv->wiphy.frag_threshold = (u32) -1; + drv->wiphy.rts_threshold = (u32) -1; + return &drv->wiphy; } EXPORT_SYMBOL(wiphy_new); @@ -337,17 +395,23 @@ int wiphy_register(struct wiphy *wiphy) /* check and set up bitrates */ ieee80211_set_bitrate_flags(wiphy); + res = device_add(&drv->wiphy.dev); + if (res) + return res; + + res = rfkill_register(drv->rfkill); + if (res) + goto out_rm_dev; + mutex_lock(&cfg80211_mutex); /* set up regulatory info */ wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE); - res = device_add(&drv->wiphy.dev); - if (res) - goto out_unlock; - list_add(&drv->list, &cfg80211_drv_list); + mutex_unlock(&cfg80211_mutex); + /* add to debugfs */ drv->wiphy.debugfsdir = debugfs_create_dir(wiphy_name(&drv->wiphy), @@ -366,17 +430,41 @@ int wiphy_register(struct wiphy *wiphy) nl80211_send_reg_change_event(&request); } - res = 0; -out_unlock: - mutex_unlock(&cfg80211_mutex); + cfg80211_debugfs_drv_add(drv); + + return 0; + + out_rm_dev: + device_del(&drv->wiphy.dev); return res; } EXPORT_SYMBOL(wiphy_register); +void wiphy_rfkill_start_polling(struct wiphy *wiphy) +{ + struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy); + + if (!drv->ops->rfkill_poll) + return; + drv->rfkill_ops.poll = cfg80211_rfkill_poll; + rfkill_resume_polling(drv->rfkill); +} +EXPORT_SYMBOL(wiphy_rfkill_start_polling); + +void wiphy_rfkill_stop_polling(struct wiphy *wiphy) +{ + struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy); + + rfkill_pause_polling(drv->rfkill); +} +EXPORT_SYMBOL(wiphy_rfkill_stop_polling); + void wiphy_unregister(struct wiphy *wiphy) { struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy); + rfkill_unregister(drv->rfkill); + /* protect the device list */ mutex_lock(&cfg80211_mutex); @@ -396,6 +484,8 @@ void wiphy_unregister(struct wiphy *wiphy) /* unlock again before freeing */ mutex_unlock(&drv->mtx); + cfg80211_debugfs_drv_del(drv); + /* If this device got a regulatory hint tell core its * free to listen now to a new shiny device regulatory hint */ reg_device_remove(wiphy); @@ -411,6 +501,7 @@ EXPORT_SYMBOL(wiphy_unregister); void cfg80211_dev_free(struct cfg80211_registered_device *drv) { struct cfg80211_internal_bss *scan, *tmp; + rfkill_destroy(drv->rfkill); mutex_destroy(&drv->mtx); mutex_destroy(&drv->devlist_mtx); list_for_each_entry_safe(scan, tmp, &drv->bss_list, list) @@ -424,6 +515,15 @@ void wiphy_free(struct wiphy *wiphy) } EXPORT_SYMBOL(wiphy_free); +void wiphy_rfkill_set_hw_state(struct wiphy *wiphy, bool blocked) +{ + struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy); + + if (rfkill_set_hw_state(drv->rfkill, blocked)) + schedule_work(&drv->rfkill_sync); +} +EXPORT_SYMBOL(wiphy_rfkill_set_hw_state); + static int cfg80211_netdev_notifier_call(struct notifier_block * nb, unsigned long state, void *ndev) @@ -432,7 +532,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, struct cfg80211_registered_device *rdev; if (!dev->ieee80211_ptr) - return 0; + return NOTIFY_DONE; rdev = wiphy_to_dev(dev->ieee80211_ptr->wiphy); @@ -448,8 +548,28 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, "symlink to netdev!\n"); } dev->ieee80211_ptr->netdev = dev; +#ifdef CONFIG_WIRELESS_EXT + dev->ieee80211_ptr->wext.default_key = -1; + dev->ieee80211_ptr->wext.default_mgmt_key = -1; +#endif mutex_unlock(&rdev->devlist_mtx); break; + case NETDEV_GOING_DOWN: + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) + break; + if (!dev->ieee80211_ptr->ssid_len) + break; + cfg80211_leave_ibss(rdev, dev, true); + break; + case NETDEV_UP: +#ifdef CONFIG_WIRELESS_EXT + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) + break; + if (!dev->ieee80211_ptr->wext.ibss.ssid_len) + break; + cfg80211_join_ibss(rdev, dev, &dev->ieee80211_ptr->wext.ibss); + break; +#endif case NETDEV_UNREGISTER: mutex_lock(&rdev->devlist_mtx); if (!list_empty(&dev->ieee80211_ptr->list)) { @@ -458,9 +578,13 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, } mutex_unlock(&rdev->devlist_mtx); break; + case NETDEV_PRE_UP: + if (rfkill_blocked(rdev->rfkill)) + return notifier_from_errno(-ERFKILL); + break; } - return 0; + return NOTIFY_DONE; } static struct notifier_block cfg80211_netdev_notifier = { diff --git a/net/wireless/core.h b/net/wireless/core.h index 0a592e4295f0..bfa340c7abb5 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -1,7 +1,7 @@ /* * Wireless configuration interface internals. * - * Copyright 2006, 2007 Johannes Berg + * Copyright 2006-2009 Johannes Berg */ #ifndef __NET_WIRELESS_CORE_H #define __NET_WIRELESS_CORE_H @@ -10,14 +10,15 @@ #include #include #include -#include +#include +#include +#include #include -#include #include #include "reg.h" struct cfg80211_registered_device { - struct cfg80211_ops *ops; + const struct cfg80211_ops *ops; struct list_head list; /* we hold this mutex during any call so that * we cannot do multiple calls at once, and also @@ -25,6 +26,11 @@ struct cfg80211_registered_device { * any call is in progress */ struct mutex mtx; + /* rfkill support */ + struct rfkill_ops rfkill_ops; + struct rfkill *rfkill; + struct work_struct rfkill_sync; + /* ISO / IEC 3166 alpha2 for which this device is receiving * country IEs on, this can help disregard country IEs from APs * on the same alpha2 quickly. The alpha2 may differ from @@ -52,6 +58,17 @@ struct cfg80211_registered_device { struct cfg80211_scan_request *scan_req; /* protected by RTNL */ unsigned long suspend_at; +#ifdef CONFIG_CFG80211_DEBUGFS + /* Debugfs entries */ + struct wiphy_debugfsdentries { + struct dentry *rts_threshold; + struct dentry *fragmentation_threshold; + struct dentry *short_retry_limit; + struct dentry *long_retry_limit; + struct dentry *ht40allow_map; + } debugfs; +#endif + /* must be last because of the way we do wiphy_priv(), * and it should at least be aligned to NETDEV_ALIGN */ struct wiphy wiphy __attribute__((__aligned__(NETDEV_ALIGN))); @@ -74,10 +91,7 @@ bool wiphy_idx_valid(int wiphy_idx) extern struct mutex cfg80211_mutex; extern struct list_head cfg80211_drv_list; -static inline void assert_cfg80211_lock(void) -{ - WARN_ON(!mutex_is_locked(&cfg80211_mutex)); -} +#define assert_cfg80211_lock() WARN_ON(!mutex_is_locked(&cfg80211_mutex)) /* * You can use this to mark a wiphy_idx as not having an associated wiphy. @@ -148,4 +162,16 @@ void cfg80211_bss_expire(struct cfg80211_registered_device *dev); void cfg80211_bss_age(struct cfg80211_registered_device *dev, unsigned long age_secs); +/* IBSS */ +int cfg80211_join_ibss(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct cfg80211_ibss_params *params); +void cfg80211_clear_ibss(struct net_device *dev, bool nowext); +int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, + struct net_device *dev, bool nowext); + +/* internal helpers */ +int cfg80211_validate_key_settings(struct key_params *params, int key_idx, + const u8 *mac_addr); + #endif /* __NET_WIRELESS_CORE_H */ diff --git a/net/wireless/debugfs.c b/net/wireless/debugfs.c new file mode 100644 index 000000000000..679ddfcec1ee --- /dev/null +++ b/net/wireless/debugfs.c @@ -0,0 +1,131 @@ +/* + * cfg80211 debugfs + * + * Copyright 2009 Luis R. Rodriguez + * Copyright 2007 Johannes Berg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "core.h" +#include "debugfs.h" + +static int cfg80211_open_file_generic(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +#define DEBUGFS_READONLY_FILE(name, buflen, fmt, value...) \ +static ssize_t name## _read(struct file *file, char __user *userbuf, \ + size_t count, loff_t *ppos) \ +{ \ + struct wiphy *wiphy= file->private_data; \ + char buf[buflen]; \ + int res; \ + \ + res = scnprintf(buf, buflen, fmt "\n", ##value); \ + return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ +} \ + \ +static const struct file_operations name## _ops = { \ + .read = name## _read, \ + .open = cfg80211_open_file_generic, \ +}; + +DEBUGFS_READONLY_FILE(rts_threshold, 20, "%d", + wiphy->rts_threshold) +DEBUGFS_READONLY_FILE(fragmentation_threshold, 20, "%d", + wiphy->frag_threshold); +DEBUGFS_READONLY_FILE(short_retry_limit, 20, "%d", + wiphy->retry_short) +DEBUGFS_READONLY_FILE(long_retry_limit, 20, "%d", + wiphy->retry_long); + +static int ht_print_chan(struct ieee80211_channel *chan, + char *buf, int buf_size, int offset) +{ + if (WARN_ON(offset > buf_size)) + return 0; + + if (chan->flags & IEEE80211_CHAN_DISABLED) + return snprintf(buf + offset, + buf_size - offset, + "%d Disabled\n", + chan->center_freq); + + return snprintf(buf + offset, + buf_size - offset, + "%d HT40 %c%c\n", + chan->center_freq, + (chan->flags & IEEE80211_CHAN_NO_HT40MINUS) ? ' ' : '-', + (chan->flags & IEEE80211_CHAN_NO_HT40PLUS) ? ' ' : '+'); +} + +static ssize_t ht40allow_map_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct wiphy *wiphy = file->private_data; + char *buf; + unsigned int offset = 0, buf_size = PAGE_SIZE, i, r; + enum ieee80211_band band; + struct ieee80211_supported_band *sband; + + buf = kzalloc(buf_size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + mutex_lock(&cfg80211_mutex); + + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + sband = wiphy->bands[band]; + if (!sband) + continue; + for (i = 0; i < sband->n_channels; i++) + offset += ht_print_chan(&sband->channels[i], + buf, buf_size, offset); + } + + mutex_unlock(&cfg80211_mutex); + + r = simple_read_from_buffer(user_buf, count, ppos, buf, offset); + + kfree(buf); + + return r; +} + +static const struct file_operations ht40allow_map_ops = { + .read = ht40allow_map_read, + .open = cfg80211_open_file_generic, +}; + +#define DEBUGFS_ADD(name) \ + drv->debugfs.name = debugfs_create_file(#name, S_IRUGO, phyd, \ + &drv->wiphy, &name## _ops); +#define DEBUGFS_DEL(name) \ + debugfs_remove(drv->debugfs.name); \ + drv->debugfs.name = NULL; + +void cfg80211_debugfs_drv_add(struct cfg80211_registered_device *drv) +{ + struct dentry *phyd = drv->wiphy.debugfsdir; + + DEBUGFS_ADD(rts_threshold); + DEBUGFS_ADD(fragmentation_threshold); + DEBUGFS_ADD(short_retry_limit); + DEBUGFS_ADD(long_retry_limit); + DEBUGFS_ADD(ht40allow_map); +} + +void cfg80211_debugfs_drv_del(struct cfg80211_registered_device *drv) +{ + DEBUGFS_DEL(rts_threshold); + DEBUGFS_DEL(fragmentation_threshold); + DEBUGFS_DEL(short_retry_limit); + DEBUGFS_DEL(long_retry_limit); + DEBUGFS_DEL(ht40allow_map); +} diff --git a/net/wireless/debugfs.h b/net/wireless/debugfs.h new file mode 100644 index 000000000000..c226983ae66b --- /dev/null +++ b/net/wireless/debugfs.h @@ -0,0 +1,14 @@ +#ifndef __CFG80211_DEBUGFS_H +#define __CFG80211_DEBUGFS_H + +#ifdef CONFIG_CFG80211_DEBUGFS +void cfg80211_debugfs_drv_add(struct cfg80211_registered_device *drv); +void cfg80211_debugfs_drv_del(struct cfg80211_registered_device *drv); +#else +static inline +void cfg80211_debugfs_drv_add(struct cfg80211_registered_device *drv) {} +static inline +void cfg80211_debugfs_drv_del(struct cfg80211_registered_device *drv) {} +#endif + +#endif /* __CFG80211_DEBUGFS_H */ diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c new file mode 100644 index 000000000000..a4a1c3498ff2 --- /dev/null +++ b/net/wireless/ibss.c @@ -0,0 +1,369 @@ +/* + * Some IBSS support code for cfg80211. + * + * Copyright 2009 Johannes Berg + */ + +#include +#include +#include +#include "nl80211.h" + + +void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_bss *bss; +#ifdef CONFIG_WIRELESS_EXT + union iwreq_data wrqu; +#endif + + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) + return; + + if (WARN_ON(!wdev->ssid_len)) + return; + + if (memcmp(bssid, wdev->bssid, ETH_ALEN) == 0) + return; + + bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, + wdev->ssid, wdev->ssid_len, + WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS); + + if (WARN_ON(!bss)) + return; + + if (wdev->current_bss) { + cfg80211_unhold_bss(wdev->current_bss); + cfg80211_put_bss(wdev->current_bss); + } + + cfg80211_hold_bss(bss); + wdev->current_bss = bss; + memcpy(wdev->bssid, bssid, ETH_ALEN); + + nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid, gfp); +#ifdef CONFIG_WIRELESS_EXT + memset(&wrqu, 0, sizeof(wrqu)); + memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); + wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); +#endif +} +EXPORT_SYMBOL(cfg80211_ibss_joined); + +int cfg80211_join_ibss(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct cfg80211_ibss_params *params) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + int err; + + if (wdev->ssid_len) + return -EALREADY; + +#ifdef CONFIG_WIRELESS_EXT + wdev->wext.ibss.channel = params->channel; +#endif + err = rdev->ops->join_ibss(&rdev->wiphy, dev, params); + + if (err) + return err; + + memcpy(wdev->ssid, params->ssid, params->ssid_len); + wdev->ssid_len = params->ssid_len; + + return 0; +} + +void cfg80211_clear_ibss(struct net_device *dev, bool nowext) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + if (wdev->current_bss) { + cfg80211_unhold_bss(wdev->current_bss); + cfg80211_put_bss(wdev->current_bss); + } + + wdev->current_bss = NULL; + wdev->ssid_len = 0; + memset(wdev->bssid, 0, ETH_ALEN); +#ifdef CONFIG_WIRELESS_EXT + if (!nowext) + wdev->wext.ibss.ssid_len = 0; +#endif +} + +int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, + struct net_device *dev, bool nowext) +{ + int err; + + err = rdev->ops->leave_ibss(&rdev->wiphy, dev); + + if (err) + return err; + + cfg80211_clear_ibss(dev, nowext); + + return 0; +} + +#ifdef CONFIG_WIRELESS_EXT +static int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev) +{ + enum ieee80211_band band; + int i; + + if (!wdev->wext.ibss.beacon_interval) + wdev->wext.ibss.beacon_interval = 100; + + /* try to find an IBSS channel if none requested ... */ + if (!wdev->wext.ibss.channel) { + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + struct ieee80211_supported_band *sband; + struct ieee80211_channel *chan; + + sband = rdev->wiphy.bands[band]; + if (!sband) + continue; + + for (i = 0; i < sband->n_channels; i++) { + chan = &sband->channels[i]; + if (chan->flags & IEEE80211_CHAN_NO_IBSS) + continue; + if (chan->flags & IEEE80211_CHAN_DISABLED) + continue; + wdev->wext.ibss.channel = chan; + break; + } + + if (wdev->wext.ibss.channel) + break; + } + + if (!wdev->wext.ibss.channel) + return -EINVAL; + } + + /* don't join -- SSID is not there */ + if (!wdev->wext.ibss.ssid_len) + return 0; + + if (!netif_running(wdev->netdev)) + return 0; + + return cfg80211_join_ibss(wiphy_to_dev(wdev->wiphy), + wdev->netdev, &wdev->wext.ibss); +} + +int cfg80211_ibss_wext_siwfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *freq, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct ieee80211_channel *chan; + int err; + + /* call only for ibss! */ + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) + return -EINVAL; + + if (!wiphy_to_dev(wdev->wiphy)->ops->join_ibss) + return -EOPNOTSUPP; + + chan = cfg80211_wext_freq(wdev->wiphy, freq); + if (chan && IS_ERR(chan)) + return PTR_ERR(chan); + + if (chan && + (chan->flags & IEEE80211_CHAN_NO_IBSS || + chan->flags & IEEE80211_CHAN_DISABLED)) + return -EINVAL; + + if (wdev->wext.ibss.channel == chan) + return 0; + + if (wdev->ssid_len) { + err = cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), + dev, true); + if (err) + return err; + } + + if (chan) { + wdev->wext.ibss.channel = chan; + wdev->wext.ibss.channel_fixed = true; + } else { + /* cfg80211_ibss_wext_join will pick one if needed */ + wdev->wext.ibss.channel_fixed = false; + } + + return cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev); +} +/* temporary symbol - mark GPL - in the future the handler won't be */ +EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwfreq); + +int cfg80211_ibss_wext_giwfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *freq, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct ieee80211_channel *chan = NULL; + + /* call only for ibss! */ + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) + return -EINVAL; + + if (wdev->current_bss) + chan = wdev->current_bss->channel; + else if (wdev->wext.ibss.channel) + chan = wdev->wext.ibss.channel; + + if (chan) { + freq->m = chan->center_freq; + freq->e = 6; + return 0; + } + + /* no channel if not joining */ + return -EINVAL; +} +/* temporary symbol - mark GPL - in the future the handler won't be */ +EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_giwfreq); + +int cfg80211_ibss_wext_siwessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *ssid) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + size_t len = data->length; + int err; + + /* call only for ibss! */ + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) + return -EINVAL; + + if (!wiphy_to_dev(wdev->wiphy)->ops->join_ibss) + return -EOPNOTSUPP; + + if (wdev->ssid_len) { + err = cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), + dev, true); + if (err) + return err; + } + + /* iwconfig uses nul termination in SSID.. */ + if (len > 0 && ssid[len - 1] == '\0') + len--; + + wdev->wext.ibss.ssid = wdev->ssid; + memcpy(wdev->wext.ibss.ssid, ssid, len); + wdev->wext.ibss.ssid_len = len; + + return cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev); +} +/* temporary symbol - mark GPL - in the future the handler won't be */ +EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwessid); + +int cfg80211_ibss_wext_giwessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *ssid) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + /* call only for ibss! */ + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) + return -EINVAL; + + data->flags = 0; + + if (wdev->ssid_len) { + data->flags = 1; + data->length = wdev->ssid_len; + memcpy(ssid, wdev->ssid, data->length); + } else if (wdev->wext.ibss.ssid && wdev->wext.ibss.ssid_len) { + data->flags = 1; + data->length = wdev->wext.ibss.ssid_len; + memcpy(ssid, wdev->wext.ibss.ssid, data->length); + } + + return 0; +} +/* temporary symbol - mark GPL - in the future the handler won't be */ +EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_giwessid); + +int cfg80211_ibss_wext_siwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *ap_addr, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + u8 *bssid = ap_addr->sa_data; + int err; + + /* call only for ibss! */ + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) + return -EINVAL; + + if (!wiphy_to_dev(wdev->wiphy)->ops->join_ibss) + return -EOPNOTSUPP; + + if (ap_addr->sa_family != ARPHRD_ETHER) + return -EINVAL; + + /* automatic mode */ + if (is_zero_ether_addr(bssid) || is_broadcast_ether_addr(bssid)) + bssid = NULL; + + /* both automatic */ + if (!bssid && !wdev->wext.ibss.bssid) + return 0; + + /* fixed already - and no change */ + if (wdev->wext.ibss.bssid && bssid && + compare_ether_addr(bssid, wdev->wext.ibss.bssid) == 0) + return 0; + + if (wdev->ssid_len) { + err = cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), + dev, true); + if (err) + return err; + } + + if (bssid) { + memcpy(wdev->wext.bssid, bssid, ETH_ALEN); + wdev->wext.ibss.bssid = wdev->wext.bssid; + } else + wdev->wext.ibss.bssid = NULL; + + return cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev); +} +/* temporary symbol - mark GPL - in the future the handler won't be */ +EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwap); + +int cfg80211_ibss_wext_giwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *ap_addr, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + /* call only for ibss! */ + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) + return -EINVAL; + + ap_addr->sa_family = ARPHRD_ETHER; + + if (wdev->wext.ibss.bssid) { + memcpy(ap_addr->sa_data, wdev->wext.ibss.bssid, ETH_ALEN); + return 0; + } + + memcpy(ap_addr->sa_data, wdev->bssid, ETH_ALEN); + return 0; +} +/* temporary symbol - mark GPL - in the future the handler won't be */ +EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_giwap); +#endif diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index bec5721b6f99..42184361a109 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -28,19 +28,55 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len) } EXPORT_SYMBOL(cfg80211_send_rx_assoc); -void cfg80211_send_rx_deauth(struct net_device *dev, const u8 *buf, size_t len) +void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len) { struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); - nl80211_send_rx_deauth(rdev, dev, buf, len); + nl80211_send_deauth(rdev, dev, buf, len); } -EXPORT_SYMBOL(cfg80211_send_rx_deauth); +EXPORT_SYMBOL(cfg80211_send_deauth); -void cfg80211_send_rx_disassoc(struct net_device *dev, const u8 *buf, - size_t len) +void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len) { struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); - nl80211_send_rx_disassoc(rdev, dev, buf, len); + nl80211_send_disassoc(rdev, dev, buf, len); } -EXPORT_SYMBOL(cfg80211_send_rx_disassoc); +EXPORT_SYMBOL(cfg80211_send_disassoc); + +static void cfg80211_wext_disconnected(struct net_device *dev) +{ +#ifdef CONFIG_WIRELESS_EXT + union iwreq_data wrqu; + memset(&wrqu, 0, sizeof(wrqu)); + wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); +#endif +} + +void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr) +{ + struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + nl80211_send_auth_timeout(rdev, dev, addr); + cfg80211_wext_disconnected(dev); +} +EXPORT_SYMBOL(cfg80211_send_auth_timeout); + +void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr) +{ + struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + nl80211_send_assoc_timeout(rdev, dev, addr); + cfg80211_wext_disconnected(dev); +} +EXPORT_SYMBOL(cfg80211_send_assoc_timeout); + +void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr, + enum nl80211_key_type key_type, int key_id, + const u8 *tsc) +{ + struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + nl80211_michael_mic_failure(rdev, dev, addr, key_type, key_id, tsc); +} +EXPORT_SYMBOL(cfg80211_michael_mic_failure); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 2456e4ee445e..241bddd0b4f1 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -1,7 +1,7 @@ /* * This is the new netlink-based wireless configuration interface. * - * Copyright 2006, 2007 Johannes Berg + * Copyright 2006-2009 Johannes Berg */ #include @@ -57,10 +57,14 @@ static int get_drv_dev_by_info_ifindex(struct nlattr **attrs, static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { [NL80211_ATTR_WIPHY] = { .type = NLA_U32 }, [NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING, - .len = BUS_ID_SIZE-1 }, + .len = 20-1 }, [NL80211_ATTR_WIPHY_TXQ_PARAMS] = { .type = NLA_NESTED }, [NL80211_ATTR_WIPHY_FREQ] = { .type = NLA_U32 }, [NL80211_ATTR_WIPHY_CHANNEL_TYPE] = { .type = NLA_U32 }, + [NL80211_ATTR_WIPHY_RETRY_SHORT] = { .type = NLA_U8 }, + [NL80211_ATTR_WIPHY_RETRY_LONG] = { .type = NLA_U8 }, + [NL80211_ATTR_WIPHY_FRAG_THRESHOLD] = { .type = NLA_U32 }, + [NL80211_ATTR_WIPHY_RTS_THRESHOLD] = { .type = NLA_U32 }, [NL80211_ATTR_IFTYPE] = { .type = NLA_U32 }, [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 }, @@ -73,6 +77,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { [NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 }, [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 }, [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG }, + [NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 }, [NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 }, [NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 }, @@ -116,8 +121,45 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { .len = IEEE80211_MAX_SSID_LEN }, [NL80211_ATTR_AUTH_TYPE] = { .type = NLA_U32 }, [NL80211_ATTR_REASON_CODE] = { .type = NLA_U16 }, + [NL80211_ATTR_FREQ_FIXED] = { .type = NLA_FLAG }, + [NL80211_ATTR_TIMED_OUT] = { .type = NLA_FLAG }, + [NL80211_ATTR_USE_MFP] = { .type = NLA_U32 }, + [NL80211_ATTR_STA_FLAGS2] = { + .len = sizeof(struct nl80211_sta_flag_update), + }, + [NL80211_ATTR_CONTROL_PORT] = { .type = NLA_FLAG }, }; +/* IE validation */ +static bool is_valid_ie_attr(const struct nlattr *attr) +{ + const u8 *pos; + int len; + + if (!attr) + return true; + + pos = nla_data(attr); + len = nla_len(attr); + + while (len) { + u8 elemlen; + + if (len < 2) + return false; + len -= 2; + + elemlen = pos[1]; + if (elemlen > len) + return false; + + len -= elemlen; + pos += 2 + elemlen; + } + + return true; +} + /* message building helper */ static inline void *nl80211hdr_put(struct sk_buff *skb, u32 pid, u32 seq, int flags, u8 cmd) @@ -126,6 +168,30 @@ static inline void *nl80211hdr_put(struct sk_buff *skb, u32 pid, u32 seq, return genlmsg_put(skb, pid, seq, &nl80211_fam, flags, cmd); } +static int nl80211_msg_put_channel(struct sk_buff *msg, + struct ieee80211_channel *chan) +{ + NLA_PUT_U32(msg, NL80211_FREQUENCY_ATTR_FREQ, + chan->center_freq); + + if (chan->flags & IEEE80211_CHAN_DISABLED) + NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_DISABLED); + if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) + NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_PASSIVE_SCAN); + if (chan->flags & IEEE80211_CHAN_NO_IBSS) + NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_NO_IBSS); + if (chan->flags & IEEE80211_CHAN_RADAR) + NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_RADAR); + + NLA_PUT_U32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER, + DBM_TO_MBM(chan->max_power)); + + return 0; + + nla_put_failure: + return -ENOBUFS; +} + /* netlink command implementations */ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, @@ -149,8 +215,24 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->wiphy_idx); NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy)); + + NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT, + dev->wiphy.retry_short); + NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_LONG, + dev->wiphy.retry_long); + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, + dev->wiphy.frag_threshold); + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, + dev->wiphy.rts_threshold); + NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS, dev->wiphy.max_scan_ssids); + NLA_PUT_U16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN, + dev->wiphy.max_scan_ie_len); + + NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES, + sizeof(u32) * dev->wiphy.n_cipher_suites, + dev->wiphy.cipher_suites); nl_modes = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_IFTYPES); if (!nl_modes) @@ -202,20 +284,9 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, goto nla_put_failure; chan = &dev->wiphy.bands[band]->channels[i]; - NLA_PUT_U32(msg, NL80211_FREQUENCY_ATTR_FREQ, - chan->center_freq); - if (chan->flags & IEEE80211_CHAN_DISABLED) - NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_DISABLED); - if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) - NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_PASSIVE_SCAN); - if (chan->flags & IEEE80211_CHAN_NO_IBSS) - NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_NO_IBSS); - if (chan->flags & IEEE80211_CHAN_RADAR) - NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_RADAR); - - NLA_PUT_U32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER, - DBM_TO_MBM(chan->max_power)); + if (nl80211_msg_put_channel(msg, chan)) + goto nla_put_failure; nla_nest_end(msg, nl_freq); } @@ -273,6 +344,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, CMD(assoc, ASSOCIATE); CMD(deauth, DEAUTHENTICATE); CMD(disassoc, DISASSOCIATE); + CMD(join_ibss, JOIN_IBSS); #undef CMD nla_nest_end(msg, nl_cmds); @@ -317,7 +389,7 @@ static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info) if (IS_ERR(dev)) return PTR_ERR(dev); - msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!msg) goto out_err; @@ -365,6 +437,9 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) struct cfg80211_registered_device *rdev; int result = 0, rem_txq_params = 0; struct nlattr *nl_txq_params; + u32 changed; + u8 retry_short = 0, retry_long = 0; + u32 frag_threshold = 0, rts_threshold = 0; rtnl_lock(); @@ -418,7 +493,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; struct ieee80211_channel *chan; struct ieee80211_sta_ht_cap *ht_cap; - u32 freq, sec_freq; + u32 freq; if (!rdev->ops->set_channel) { result = -EOPNOTSUPP; @@ -444,33 +519,28 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) goto bad_res; - if (channel_type == NL80211_CHAN_HT40MINUS) - sec_freq = freq - 20; - else if (channel_type == NL80211_CHAN_HT40PLUS) - sec_freq = freq + 20; - else - sec_freq = 0; + if (channel_type == NL80211_CHAN_HT40MINUS && + (chan->flags & IEEE80211_CHAN_NO_HT40MINUS)) + goto bad_res; + else if (channel_type == NL80211_CHAN_HT40PLUS && + (chan->flags & IEEE80211_CHAN_NO_HT40PLUS)) + goto bad_res; + + /* + * At this point we know if that if HT40 was requested + * we are allowed to use it and the extension channel + * exists. + */ ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap; - /* no HT capabilities */ - if (channel_type != NL80211_CHAN_NO_HT && - !ht_cap->ht_supported) - goto bad_res; - - if (sec_freq) { - struct ieee80211_channel *schan; - - /* no 40 MHz capabilities */ + /* no HT capabilities or intolerant */ + if (channel_type != NL80211_CHAN_NO_HT) { + if (!ht_cap->ht_supported) + goto bad_res; if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) || (ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT)) goto bad_res; - - schan = ieee80211_get_channel(&rdev->wiphy, sec_freq); - - /* Secondary channel not allowed */ - if (!schan || schan->flags & IEEE80211_CHAN_DISABLED) - goto bad_res; } result = rdev->ops->set_channel(&rdev->wiphy, chan, @@ -479,6 +549,84 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) goto bad_res; } + changed = 0; + + if (info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]) { + retry_short = nla_get_u8( + info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]); + if (retry_short == 0) { + result = -EINVAL; + goto bad_res; + } + changed |= WIPHY_PARAM_RETRY_SHORT; + } + + if (info->attrs[NL80211_ATTR_WIPHY_RETRY_LONG]) { + retry_long = nla_get_u8( + info->attrs[NL80211_ATTR_WIPHY_RETRY_LONG]); + if (retry_long == 0) { + result = -EINVAL; + goto bad_res; + } + changed |= WIPHY_PARAM_RETRY_LONG; + } + + if (info->attrs[NL80211_ATTR_WIPHY_FRAG_THRESHOLD]) { + frag_threshold = nla_get_u32( + info->attrs[NL80211_ATTR_WIPHY_FRAG_THRESHOLD]); + if (frag_threshold < 256) { + result = -EINVAL; + goto bad_res; + } + if (frag_threshold != (u32) -1) { + /* + * Fragments (apart from the last one) are required to + * have even length. Make the fragmentation code + * simpler by stripping LSB should someone try to use + * odd threshold value. + */ + frag_threshold &= ~0x1; + } + changed |= WIPHY_PARAM_FRAG_THRESHOLD; + } + + if (info->attrs[NL80211_ATTR_WIPHY_RTS_THRESHOLD]) { + rts_threshold = nla_get_u32( + info->attrs[NL80211_ATTR_WIPHY_RTS_THRESHOLD]); + changed |= WIPHY_PARAM_RTS_THRESHOLD; + } + + if (changed) { + u8 old_retry_short, old_retry_long; + u32 old_frag_threshold, old_rts_threshold; + + if (!rdev->ops->set_wiphy_params) { + result = -EOPNOTSUPP; + goto bad_res; + } + + old_retry_short = rdev->wiphy.retry_short; + old_retry_long = rdev->wiphy.retry_long; + old_frag_threshold = rdev->wiphy.frag_threshold; + old_rts_threshold = rdev->wiphy.rts_threshold; + + if (changed & WIPHY_PARAM_RETRY_SHORT) + rdev->wiphy.retry_short = retry_short; + if (changed & WIPHY_PARAM_RETRY_LONG) + rdev->wiphy.retry_long = retry_long; + if (changed & WIPHY_PARAM_FRAG_THRESHOLD) + rdev->wiphy.frag_threshold = frag_threshold; + if (changed & WIPHY_PARAM_RTS_THRESHOLD) + rdev->wiphy.rts_threshold = rts_threshold; + + result = rdev->ops->set_wiphy_params(&rdev->wiphy, changed); + if (result) { + rdev->wiphy.retry_short = old_retry_short; + rdev->wiphy.retry_long = old_retry_long; + rdev->wiphy.frag_threshold = old_frag_threshold; + rdev->wiphy.rts_threshold = old_rts_threshold; + } + } bad_res: mutex_unlock(&rdev->mtx); @@ -489,6 +637,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags, + struct cfg80211_registered_device *rdev, struct net_device *dev) { void *hdr; @@ -498,6 +647,7 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags, return -1; NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, dev->name); NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, dev->ieee80211_ptr->iftype); return genlmsg_end(msg, hdr); @@ -532,7 +682,7 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * } if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, NLM_F_MULTI, - wdev->netdev) < 0) { + dev, wdev->netdev) < 0) { mutex_unlock(&dev->devlist_mtx); goto out; } @@ -562,11 +712,12 @@ static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info) if (err) return err; - msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!msg) goto out_err; - if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0, netdev) < 0) + if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0, + dev, netdev) < 0) goto out_free; dev_put(netdev); @@ -616,7 +767,7 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) struct cfg80211_registered_device *drv; struct vif_params params; int err, ifindex; - enum nl80211_iftype type; + enum nl80211_iftype otype, ntype; struct net_device *dev; u32 _flags, *flags = NULL; bool change = false; @@ -630,30 +781,27 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) goto unlock_rtnl; ifindex = dev->ifindex; - type = dev->ieee80211_ptr->iftype; + otype = ntype = dev->ieee80211_ptr->iftype; dev_put(dev); if (info->attrs[NL80211_ATTR_IFTYPE]) { - enum nl80211_iftype ntype; - ntype = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); - if (type != ntype) + if (otype != ntype) change = true; - type = ntype; - if (type > NL80211_IFTYPE_MAX) { + if (ntype > NL80211_IFTYPE_MAX) { err = -EINVAL; goto unlock; } } if (!drv->ops->change_virtual_intf || - !(drv->wiphy.interface_modes & (1 << type))) { + !(drv->wiphy.interface_modes & (1 << ntype))) { err = -EOPNOTSUPP; goto unlock; } if (info->attrs[NL80211_ATTR_MESH_ID]) { - if (type != NL80211_IFTYPE_MESH_POINT) { + if (ntype != NL80211_IFTYPE_MESH_POINT) { err = -EINVAL; goto unlock; } @@ -663,7 +811,7 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) } if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) { - if (type != NL80211_IFTYPE_MONITOR) { + if (ntype != NL80211_IFTYPE_MONITOR) { err = -EINVAL; goto unlock; } @@ -678,12 +826,17 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) if (change) err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, - type, flags, ¶ms); + ntype, flags, ¶ms); else err = 0; dev = __dev_get_by_index(&init_net, ifindex); - WARN_ON(!dev || (!err && dev->ieee80211_ptr->iftype != type)); + WARN_ON(!dev || (!err && dev->ieee80211_ptr->iftype != ntype)); + + if (dev && !err && (ntype != otype)) { + if (otype == NL80211_IFTYPE_ADHOC) + cfg80211_clear_ibss(dev, false); + } unlock: cfg80211_put_dev(drv); @@ -832,7 +985,7 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) goto out; } - msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!msg) { err = -ENOMEM; goto out; @@ -920,6 +1073,14 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) } err = func(&drv->wiphy, dev, key_idx); +#ifdef CONFIG_WIRELESS_EXT + if (!err) { + if (func == drv->ops->set_default_key) + dev->ieee80211_ptr->wext.default_key = key_idx; + else + dev->ieee80211_ptr->wext.default_mgmt_key = key_idx; + } +#endif out: cfg80211_put_dev(drv); @@ -934,7 +1095,7 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *drv; - int err; + int err, i; struct net_device *dev; struct key_params params; u8 key_idx = 0; @@ -950,6 +1111,11 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) params.key_len = nla_len(info->attrs[NL80211_ATTR_KEY_DATA]); } + if (info->attrs[NL80211_ATTR_KEY_SEQ]) { + params.seq = nla_data(info->attrs[NL80211_ATTR_KEY_SEQ]); + params.seq_len = nla_len(info->attrs[NL80211_ATTR_KEY_SEQ]); + } + if (info->attrs[NL80211_ATTR_KEY_IDX]) key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); @@ -958,51 +1124,23 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NL80211_ATTR_MAC]) mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); - if (key_idx > 5) + if (cfg80211_validate_key_settings(¶ms, key_idx, mac_addr)) return -EINVAL; - /* - * Disallow pairwise keys with non-zero index unless it's WEP - * (because current deployments use pairwise WEP keys with - * non-zero indizes but 802.11i clearly specifies to use zero) - */ - if (mac_addr && key_idx && - params.cipher != WLAN_CIPHER_SUITE_WEP40 && - params.cipher != WLAN_CIPHER_SUITE_WEP104) - return -EINVAL; - - /* TODO: add definitions for the lengths to linux/ieee80211.h */ - switch (params.cipher) { - case WLAN_CIPHER_SUITE_WEP40: - if (params.key_len != 5) - return -EINVAL; - break; - case WLAN_CIPHER_SUITE_TKIP: - if (params.key_len != 32) - return -EINVAL; - break; - case WLAN_CIPHER_SUITE_CCMP: - if (params.key_len != 16) - return -EINVAL; - break; - case WLAN_CIPHER_SUITE_WEP104: - if (params.key_len != 13) - return -EINVAL; - break; - case WLAN_CIPHER_SUITE_AES_CMAC: - if (params.key_len != 16) - return -EINVAL; - break; - default: - return -EINVAL; - } - rtnl_lock(); err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); if (err) goto unlock_rtnl; + for (i = 0; i < drv->wiphy.n_cipher_suites; i++) + if (params.cipher == drv->wiphy.cipher_suites[i]) + break; + if (i == drv->wiphy.n_cipher_suites) { + err = -EINVAL; + goto out; + } + if (!drv->ops->add_key) { err = -EOPNOTSUPP; goto out; @@ -1049,6 +1187,15 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) err = drv->ops->del_key(&drv->wiphy, dev, key_idx, mac_addr); +#ifdef CONFIG_WIRELESS_EXT + if (!err) { + if (key_idx == dev->ieee80211_ptr->wext.default_key) + dev->ieee80211_ptr->wext.default_key = -1; + else if (key_idx == dev->ieee80211_ptr->wext.default_mgmt_key) + dev->ieee80211_ptr->wext.default_mgmt_key = -1; + } +#endif + out: cfg80211_put_dev(drv); dev_put(dev); @@ -1069,6 +1216,9 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) struct beacon_parameters params; int haveinfo = 0; + if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_BEACON_TAIL])) + return -EINVAL; + rtnl_lock(); err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); @@ -1186,15 +1336,36 @@ static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = { [NL80211_STA_FLAG_AUTHORIZED] = { .type = NLA_FLAG }, [NL80211_STA_FLAG_SHORT_PREAMBLE] = { .type = NLA_FLAG }, [NL80211_STA_FLAG_WME] = { .type = NLA_FLAG }, + [NL80211_STA_FLAG_MFP] = { .type = NLA_FLAG }, }; -static int parse_station_flags(struct nlattr *nla, u32 *staflags) +static int parse_station_flags(struct genl_info *info, + struct station_parameters *params) { struct nlattr *flags[NL80211_STA_FLAG_MAX + 1]; + struct nlattr *nla; int flag; - *staflags = 0; + /* + * Try parsing the new attribute first so userspace + * can specify both for older kernels. + */ + nla = info->attrs[NL80211_ATTR_STA_FLAGS2]; + if (nla) { + struct nl80211_sta_flag_update *sta_flags; + sta_flags = nla_data(nla); + params->sta_flags_mask = sta_flags->mask; + params->sta_flags_set = sta_flags->set; + if ((params->sta_flags_mask | + params->sta_flags_set) & BIT(__NL80211_STA_FLAG_INVALID)) + return -EINVAL; + return 0; + } + + /* if present, parse the old attribute */ + + nla = info->attrs[NL80211_ATTR_STA_FLAGS]; if (!nla) return 0; @@ -1202,11 +1373,12 @@ static int parse_station_flags(struct nlattr *nla, u32 *staflags) nla, sta_flags_policy)) return -EINVAL; - *staflags = STATION_FLAG_CHANGED; + params->sta_flags_mask = (1 << __NL80211_STA_FLAG_AFTER_LAST) - 1; + params->sta_flags_mask &= ~1; for (flag = 1; flag <= NL80211_STA_FLAG_MAX; flag++) if (flags[flag]) - *staflags |= (1<sta_flags_set |= (1<attrs[NL80211_ATTR_HT_CAPABILITY]); - if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS], - ¶ms.station_flags)) + if (parse_station_flags(info, ¶ms)) return -EINVAL; if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) @@ -1517,6 +1688,51 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) goto out_rtnl; err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, ¶ms.vlan); + if (err) + goto out; + + /* validate settings */ + err = 0; + + switch (dev->ieee80211_ptr->iftype) { + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_AP_VLAN: + /* disallow mesh-specific things */ + if (params.plink_action) + err = -EINVAL; + break; + case NL80211_IFTYPE_STATION: + /* disallow everything but AUTHORIZED flag */ + if (params.plink_action) + err = -EINVAL; + if (params.vlan) + err = -EINVAL; + if (params.supported_rates) + err = -EINVAL; + if (params.ht_capa) + err = -EINVAL; + if (params.listen_interval >= 0) + err = -EINVAL; + if (params.sta_flags_mask & ~BIT(NL80211_STA_FLAG_AUTHORIZED)) + err = -EINVAL; + break; + case NL80211_IFTYPE_MESH_POINT: + /* disallow things mesh doesn't support */ + if (params.vlan) + err = -EINVAL; + if (params.ht_capa) + err = -EINVAL; + if (params.listen_interval >= 0) + err = -EINVAL; + if (params.supported_rates) + err = -EINVAL; + if (params.sta_flags_mask) + err = -EINVAL; + break; + default: + err = -EINVAL; + } + if (err) goto out; @@ -1551,9 +1767,6 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) if (!info->attrs[NL80211_ATTR_MAC]) return -EINVAL; - if (!info->attrs[NL80211_ATTR_STA_AID]) - return -EINVAL; - if (!info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]) return -EINVAL; @@ -1567,13 +1780,18 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); params.listen_interval = nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]); - params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]); + + if (info->attrs[NL80211_ATTR_STA_AID]) { + params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]); + if (!params.aid || params.aid > IEEE80211_MAX_AID) + return -EINVAL; + } + if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) params.ht_capa = nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); - if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS], - ¶ms.station_flags)) + if (parse_station_flags(info, ¶ms)) return -EINVAL; rtnl_lock(); @@ -1583,6 +1801,38 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) goto out_rtnl; err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, ¶ms.vlan); + if (err) + goto out; + + /* validate settings */ + err = 0; + + switch (dev->ieee80211_ptr->iftype) { + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_AP_VLAN: + /* all ok but must have AID */ + if (!params.aid) + err = -EINVAL; + break; + case NL80211_IFTYPE_MESH_POINT: + /* disallow things mesh doesn't support */ + if (params.vlan) + err = -EINVAL; + if (params.aid) + err = -EINVAL; + if (params.ht_capa) + err = -EINVAL; + if (params.listen_interval >= 0) + err = -EINVAL; + if (params.supported_rates) + err = -EINVAL; + if (params.sta_flags_mask) + err = -EINVAL; + break; + default: + err = -EINVAL; + } + if (err) goto out; @@ -1625,6 +1875,13 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) if (err) goto out_rtnl; + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) { + err = -EINVAL; + goto out; + } + if (!drv->ops->del_station) { err = -EOPNOTSUPP; goto out; @@ -1808,7 +2065,7 @@ static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) if (err) goto out; - msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!msg) goto out; @@ -2124,7 +2381,7 @@ static int nl80211_get_mesh_params(struct sk_buff *skb, goto out; /* Draw up a netlink message to send back */ - msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!msg) { err = -ENOBUFS; goto out; @@ -2302,7 +2559,7 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) if (!cfg80211_regdomain) goto out; - msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!msg) { err = -ENOBUFS; goto out; @@ -2385,18 +2642,24 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) rem_reg_rules) { num_rules++; if (num_rules > NL80211_MAX_SUPP_REG_RULES) - goto bad_reg; + return -EINVAL; } - if (!reg_is_valid_request(alpha2)) - return -EINVAL; + mutex_lock(&cfg80211_mutex); + + if (!reg_is_valid_request(alpha2)) { + r = -EINVAL; + goto bad_reg; + } size_of_regd = sizeof(struct ieee80211_regdomain) + (num_rules * sizeof(struct ieee80211_reg_rule)); rd = kzalloc(size_of_regd, GFP_KERNEL); - if (!rd) - return -ENOMEM; + if (!rd) { + r = -ENOMEM; + goto bad_reg; + } rd->n_reg_rules = num_rules; rd->alpha2[0] = alpha2[0]; @@ -2413,20 +2676,24 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) rule_idx++; - if (rule_idx > NL80211_MAX_SUPP_REG_RULES) + if (rule_idx > NL80211_MAX_SUPP_REG_RULES) { + r = -EINVAL; goto bad_reg; + } } BUG_ON(rule_idx != num_rules); - mutex_lock(&cfg80211_mutex); r = set_regdom(rd); + mutex_unlock(&cfg80211_mutex); + return r; bad_reg: + mutex_unlock(&cfg80211_mutex); kfree(rd); - return -EINVAL; + return r; } static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) @@ -2442,6 +2709,9 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) enum ieee80211_band band; size_t ie_len; + if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) + return -EINVAL; + rtnl_lock(); err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); @@ -2492,6 +2762,11 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) else ie_len = 0; + if (ie_len > wiphy->max_scan_ie_len) { + err = -EINVAL; + goto out; + } + request = kzalloc(sizeof(*request) + sizeof(*ssid) * n_ssids + sizeof(channel) * n_channels @@ -2554,7 +2829,8 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NL80211_ATTR_IE]) { request->ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); - memcpy(request->ie, nla_data(info->attrs[NL80211_ATTR_IE]), + memcpy((void *)request->ie, + nla_data(info->attrs[NL80211_ATTR_IE]), request->ie_len); } @@ -2710,6 +2986,15 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) struct wiphy *wiphy; int err; + if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) + return -EINVAL; + + if (!info->attrs[NL80211_ATTR_MAC]) + return -EINVAL; + + if (!info->attrs[NL80211_ATTR_AUTH_TYPE]) + return -EINVAL; + rtnl_lock(); err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); @@ -2731,11 +3016,6 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) goto out; } - if (!info->attrs[NL80211_ATTR_MAC]) { - err = -EINVAL; - goto out; - } - wiphy = &drv->wiphy; memset(&req, 0, sizeof(req)); @@ -2761,13 +3041,10 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); } - if (info->attrs[NL80211_ATTR_AUTH_TYPE]) { - req.auth_type = - nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]); - if (!nl80211_valid_auth_type(req.auth_type)) { - err = -EINVAL; - goto out; - } + req.auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]); + if (!nl80211_valid_auth_type(req.auth_type)) { + err = -EINVAL; + goto out; } err = drv->ops->auth(&drv->wiphy, dev, &req); @@ -2788,6 +3065,13 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) struct wiphy *wiphy; int err; + if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) + return -EINVAL; + + if (!info->attrs[NL80211_ATTR_MAC] || + !info->attrs[NL80211_ATTR_SSID]) + return -EINVAL; + rtnl_lock(); err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); @@ -2809,12 +3093,6 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) goto out; } - if (!info->attrs[NL80211_ATTR_MAC] || - !info->attrs[NL80211_ATTR_SSID]) { - err = -EINVAL; - goto out; - } - wiphy = &drv->wiphy; memset(&req, 0, sizeof(req)); @@ -2838,6 +3116,19 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); } + if (info->attrs[NL80211_ATTR_USE_MFP]) { + enum nl80211_mfp use_mfp = + nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]); + if (use_mfp == NL80211_MFP_REQUIRED) + req.use_mfp = true; + else if (use_mfp != NL80211_MFP_NO) { + err = -EINVAL; + goto out; + } + } + + req.control_port = info->attrs[NL80211_ATTR_CONTROL_PORT]; + err = drv->ops->assoc(&drv->wiphy, dev, &req); out: @@ -2856,6 +3147,15 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) struct wiphy *wiphy; int err; + if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) + return -EINVAL; + + if (!info->attrs[NL80211_ATTR_MAC]) + return -EINVAL; + + if (!info->attrs[NL80211_ATTR_REASON_CODE]) + return -EINVAL; + rtnl_lock(); err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); @@ -2877,24 +3177,16 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) goto out; } - if (!info->attrs[NL80211_ATTR_MAC]) { - err = -EINVAL; - goto out; - } - wiphy = &drv->wiphy; memset(&req, 0, sizeof(req)); req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); - if (info->attrs[NL80211_ATTR_REASON_CODE]) { - req.reason_code = - nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); - if (req.reason_code == 0) { - /* Reason Code 0 is reserved */ - err = -EINVAL; - goto out; - } + req.reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); + if (req.reason_code == 0) { + /* Reason Code 0 is reserved */ + err = -EINVAL; + goto out; } if (info->attrs[NL80211_ATTR_IE]) { @@ -2920,6 +3212,15 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) struct wiphy *wiphy; int err; + if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) + return -EINVAL; + + if (!info->attrs[NL80211_ATTR_MAC]) + return -EINVAL; + + if (!info->attrs[NL80211_ATTR_REASON_CODE]) + return -EINVAL; + rtnl_lock(); err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); @@ -2941,24 +3242,16 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) goto out; } - if (!info->attrs[NL80211_ATTR_MAC]) { - err = -EINVAL; - goto out; - } - wiphy = &drv->wiphy; memset(&req, 0, sizeof(req)); req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); - if (info->attrs[NL80211_ATTR_REASON_CODE]) { - req.reason_code = - nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); - if (req.reason_code == 0) { - /* Reason Code 0 is reserved */ - err = -EINVAL; - goto out; - } + req.reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); + if (req.reason_code == 0) { + /* Reason Code 0 is reserved */ + err = -EINVAL; + goto out; } if (info->attrs[NL80211_ATTR_IE]) { @@ -2976,6 +3269,124 @@ unlock_rtnl: return err; } +static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *drv; + struct net_device *dev; + struct cfg80211_ibss_params ibss; + struct wiphy *wiphy; + int err; + + memset(&ibss, 0, sizeof(ibss)); + + if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) + return -EINVAL; + + if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] || + !info->attrs[NL80211_ATTR_SSID] || + !nla_len(info->attrs[NL80211_ATTR_SSID])) + return -EINVAL; + + ibss.beacon_interval = 100; + + if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) { + ibss.beacon_interval = + nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]); + if (ibss.beacon_interval < 1 || ibss.beacon_interval > 10000) + return -EINVAL; + } + + rtnl_lock(); + + err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); + if (err) + goto unlock_rtnl; + + if (!drv->ops->join_ibss) { + err = -EOPNOTSUPP; + goto out; + } + + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) { + err = -EOPNOTSUPP; + goto out; + } + + if (!netif_running(dev)) { + err = -ENETDOWN; + goto out; + } + + wiphy = &drv->wiphy; + + if (info->attrs[NL80211_ATTR_MAC]) + ibss.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); + ibss.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); + ibss.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); + + if (info->attrs[NL80211_ATTR_IE]) { + ibss.ie = nla_data(info->attrs[NL80211_ATTR_IE]); + ibss.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); + } + + ibss.channel = ieee80211_get_channel(wiphy, + nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); + if (!ibss.channel || + ibss.channel->flags & IEEE80211_CHAN_NO_IBSS || + ibss.channel->flags & IEEE80211_CHAN_DISABLED) { + err = -EINVAL; + goto out; + } + + ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED]; + + err = cfg80211_join_ibss(drv, dev, &ibss); + +out: + cfg80211_put_dev(drv); + dev_put(dev); +unlock_rtnl: + rtnl_unlock(); + return err; +} + +static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *drv; + struct net_device *dev; + int err; + + rtnl_lock(); + + err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); + if (err) + goto unlock_rtnl; + + if (!drv->ops->leave_ibss) { + err = -EOPNOTSUPP; + goto out; + } + + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) { + err = -EOPNOTSUPP; + goto out; + } + + if (!netif_running(dev)) { + err = -ENETDOWN; + goto out; + } + + err = cfg80211_leave_ibss(drv, dev, false); + +out: + cfg80211_put_dev(drv); + dev_put(dev); +unlock_rtnl: + rtnl_unlock(); + return err; +} + static struct genl_ops nl80211_ops[] = { { .cmd = NL80211_CMD_GET_WIPHY, @@ -3177,6 +3588,18 @@ static struct genl_ops nl80211_ops[] = { .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, }, + { + .cmd = NL80211_CMD_JOIN_IBSS, + .doit = nl80211_join_ibss, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = NL80211_CMD_LEAVE_IBSS, + .doit = nl80211_leave_ibss, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + }, }; static struct genl_multicast_group nl80211_mlme_mcgrp = { .name = "mlme", @@ -3199,7 +3622,7 @@ void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev) { struct sk_buff *msg; - msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!msg) return; @@ -3211,11 +3634,43 @@ void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev) genlmsg_multicast(msg, 0, nl80211_config_mcgrp.id, GFP_KERNEL); } +static int nl80211_add_scan_req(struct sk_buff *msg, + struct cfg80211_registered_device *rdev) +{ + struct cfg80211_scan_request *req = rdev->scan_req; + struct nlattr *nest; + int i; + + if (WARN_ON(!req)) + return 0; + + nest = nla_nest_start(msg, NL80211_ATTR_SCAN_SSIDS); + if (!nest) + goto nla_put_failure; + for (i = 0; i < req->n_ssids; i++) + NLA_PUT(msg, i, req->ssids[i].ssid_len, req->ssids[i].ssid); + nla_nest_end(msg, nest); + + nest = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES); + if (!nest) + goto nla_put_failure; + for (i = 0; i < req->n_channels; i++) + NLA_PUT_U32(msg, i, req->channels[i]->center_freq); + nla_nest_end(msg, nest); + + if (req->ie) + NLA_PUT(msg, NL80211_ATTR_IE, req->ie_len, req->ie); + + return 0; + nla_put_failure: + return -ENOBUFS; +} + static int nl80211_send_scan_donemsg(struct sk_buff *msg, - struct cfg80211_registered_device *rdev, - struct net_device *netdev, - u32 pid, u32 seq, int flags, - u32 cmd) + struct cfg80211_registered_device *rdev, + struct net_device *netdev, + u32 pid, u32 seq, int flags, + u32 cmd) { void *hdr; @@ -3226,7 +3681,8 @@ static int nl80211_send_scan_donemsg(struct sk_buff *msg, NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); - /* XXX: we should probably bounce back the request? */ + /* ignore errors and send incomplete event anyway */ + nl80211_add_scan_req(msg, rdev); return genlmsg_end(msg, hdr); @@ -3240,7 +3696,7 @@ void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, { struct sk_buff *msg; - msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!msg) return; @@ -3258,7 +3714,7 @@ void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, { struct sk_buff *msg; - msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!msg) return; @@ -3280,7 +3736,7 @@ void nl80211_send_reg_change_event(struct regulatory_request *request) struct sk_buff *msg; void *hdr; - msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!msg) return; @@ -3334,7 +3790,7 @@ static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev, struct sk_buff *msg; void *hdr; - msg = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); if (!msg) return; @@ -3375,38 +3831,208 @@ void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev, nl80211_send_mlme_event(rdev, netdev, buf, len, NL80211_CMD_ASSOCIATE); } -void nl80211_send_rx_deauth(struct cfg80211_registered_device *rdev, - struct net_device *netdev, const u8 *buf, - size_t len) +void nl80211_send_deauth(struct cfg80211_registered_device *rdev, + struct net_device *netdev, const u8 *buf, size_t len) { nl80211_send_mlme_event(rdev, netdev, buf, len, NL80211_CMD_DEAUTHENTICATE); } -void nl80211_send_rx_disassoc(struct cfg80211_registered_device *rdev, - struct net_device *netdev, const u8 *buf, - size_t len) +void nl80211_send_disassoc(struct cfg80211_registered_device *rdev, + struct net_device *netdev, const u8 *buf, + size_t len) { nl80211_send_mlme_event(rdev, netdev, buf, len, NL80211_CMD_DISASSOCIATE); } +static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev, + struct net_device *netdev, int cmd, + const u8 *addr) +{ + struct sk_buff *msg; + void *hdr; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); + if (!msg) + return; + + hdr = nl80211hdr_put(msg, 0, 0, 0, cmd); + if (!hdr) { + nlmsg_free(msg); + return; + } + + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); + NLA_PUT_FLAG(msg, NL80211_ATTR_TIMED_OUT); + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); + + if (genlmsg_end(msg, hdr) < 0) { + nlmsg_free(msg); + return; + } + + genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, GFP_ATOMIC); + return; + + nla_put_failure: + genlmsg_cancel(msg, hdr); + nlmsg_free(msg); +} + +void nl80211_send_auth_timeout(struct cfg80211_registered_device *rdev, + struct net_device *netdev, const u8 *addr) +{ + nl80211_send_mlme_timeout(rdev, netdev, NL80211_CMD_AUTHENTICATE, + addr); +} + +void nl80211_send_assoc_timeout(struct cfg80211_registered_device *rdev, + struct net_device *netdev, const u8 *addr) +{ + nl80211_send_mlme_timeout(rdev, netdev, NL80211_CMD_ASSOCIATE, addr); +} + +void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev, + struct net_device *netdev, const u8 *bssid, + gfp_t gfp) +{ + struct sk_buff *msg; + void *hdr; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); + if (!msg) + return; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_JOIN_IBSS); + if (!hdr) { + nlmsg_free(msg); + return; + } + + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid); + + if (genlmsg_end(msg, hdr) < 0) { + nlmsg_free(msg); + return; + } + + genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp); + return; + + nla_put_failure: + genlmsg_cancel(msg, hdr); + nlmsg_free(msg); +} + +void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, + struct net_device *netdev, const u8 *addr, + enum nl80211_key_type key_type, int key_id, + const u8 *tsc) +{ + struct sk_buff *msg; + void *hdr; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); + if (!msg) + return; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_MICHAEL_MIC_FAILURE); + if (!hdr) { + nlmsg_free(msg); + return; + } + + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); + if (addr) + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); + NLA_PUT_U32(msg, NL80211_ATTR_KEY_TYPE, key_type); + NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_id); + if (tsc) + NLA_PUT(msg, NL80211_ATTR_KEY_SEQ, 6, tsc); + + if (genlmsg_end(msg, hdr) < 0) { + nlmsg_free(msg); + return; + } + + genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, GFP_ATOMIC); + return; + + nla_put_failure: + genlmsg_cancel(msg, hdr); + nlmsg_free(msg); +} + +void nl80211_send_beacon_hint_event(struct wiphy *wiphy, + struct ieee80211_channel *channel_before, + struct ieee80211_channel *channel_after) +{ + struct sk_buff *msg; + void *hdr; + struct nlattr *nl_freq; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); + if (!msg) + return; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_REG_BEACON_HINT); + if (!hdr) { + nlmsg_free(msg); + return; + } + + /* + * Since we are applying the beacon hint to a wiphy we know its + * wiphy_idx is valid + */ + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, get_wiphy_idx(wiphy)); + + /* Before */ + nl_freq = nla_nest_start(msg, NL80211_ATTR_FREQ_BEFORE); + if (!nl_freq) + goto nla_put_failure; + if (nl80211_msg_put_channel(msg, channel_before)) + goto nla_put_failure; + nla_nest_end(msg, nl_freq); + + /* After */ + nl_freq = nla_nest_start(msg, NL80211_ATTR_FREQ_AFTER); + if (!nl_freq) + goto nla_put_failure; + if (nl80211_msg_put_channel(msg, channel_after)) + goto nla_put_failure; + nla_nest_end(msg, nl_freq); + + if (genlmsg_end(msg, hdr) < 0) { + nlmsg_free(msg); + return; + } + + genlmsg_multicast(msg, 0, nl80211_regulatory_mcgrp.id, GFP_ATOMIC); + + return; + +nla_put_failure: + genlmsg_cancel(msg, hdr); + nlmsg_free(msg); +} + /* initialisation/exit functions */ int nl80211_init(void) { - int err, i; + int err; - err = genl_register_family(&nl80211_fam); + err = genl_register_family_with_ops(&nl80211_fam, + nl80211_ops, ARRAY_SIZE(nl80211_ops)); if (err) return err; - for (i = 0; i < ARRAY_SIZE(nl80211_ops); i++) { - err = genl_register_ops(&nl80211_fam, &nl80211_ops[i]); - if (err) - goto err_out; - } - err = genl_register_mc_group(&nl80211_fam, &nl80211_config_mcgrp); if (err) goto err_out; diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index b77af4ab80be..5c12ad13499b 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h @@ -17,11 +17,31 @@ extern void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev, extern void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev, struct net_device *netdev, const u8 *buf, size_t len); -extern void nl80211_send_rx_deauth(struct cfg80211_registered_device *rdev, - struct net_device *netdev, - const u8 *buf, size_t len); -extern void nl80211_send_rx_disassoc(struct cfg80211_registered_device *rdev, - struct net_device *netdev, - const u8 *buf, size_t len); +extern void nl80211_send_deauth(struct cfg80211_registered_device *rdev, + struct net_device *netdev, + const u8 *buf, size_t len); +extern void nl80211_send_disassoc(struct cfg80211_registered_device *rdev, + struct net_device *netdev, + const u8 *buf, size_t len); +extern void nl80211_send_auth_timeout(struct cfg80211_registered_device *rdev, + struct net_device *netdev, + const u8 *addr); +extern void nl80211_send_assoc_timeout(struct cfg80211_registered_device *rdev, + struct net_device *netdev, + const u8 *addr); +extern void +nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, + struct net_device *netdev, const u8 *addr, + enum nl80211_key_type key_type, + int key_id, const u8 *tsc); + +extern void +nl80211_send_beacon_hint_event(struct wiphy *wiphy, + struct ieee80211_channel *channel_before, + struct ieee80211_channel *channel_after); + +void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev, + struct net_device *netdev, const u8 *bssid, + gfp_t gfp); #endif /* __NET_WIRELESS_NL80211_H */ diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 487cb627ddba..5e14371cda70 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -37,7 +37,6 @@ #include #include #include -#include #include #include "core.h" #include "reg.h" @@ -49,12 +48,6 @@ static struct regulatory_request *last_request; /* To trigger userspace events */ static struct platform_device *reg_pdev; -/* Keep the ordering from large to small */ -static u32 supported_bandwidths[] = { - MHZ_TO_KHZ(40), - MHZ_TO_KHZ(20), -}; - /* * Central wireless core regulatory domains, we only need two, * the current one and a world regulatory domain in case we have no @@ -389,6 +382,8 @@ static int call_crda(const char *alpha2) /* Used by nl80211 before kmalloc'ing our regulatory domain */ bool reg_is_valid_request(const char *alpha2) { + assert_cfg80211_lock(); + if (!last_request) return false; @@ -436,19 +431,20 @@ static bool is_valid_rd(const struct ieee80211_regdomain *rd) return true; } -/* Returns value in KHz */ -static u32 freq_max_bandwidth(const struct ieee80211_freq_range *freq_range, - u32 freq) +static bool reg_does_bw_fit(const struct ieee80211_freq_range *freq_range, + u32 center_freq_khz, + u32 bw_khz) { - unsigned int i; - for (i = 0; i < ARRAY_SIZE(supported_bandwidths); i++) { - u32 start_freq_khz = freq - supported_bandwidths[i]/2; - u32 end_freq_khz = freq + supported_bandwidths[i]/2; - if (start_freq_khz >= freq_range->start_freq_khz && - end_freq_khz <= freq_range->end_freq_khz) - return supported_bandwidths[i]; - } - return 0; + u32 start_freq_khz, end_freq_khz; + + start_freq_khz = center_freq_khz - (bw_khz/2); + end_freq_khz = center_freq_khz + (bw_khz/2); + + if (start_freq_khz >= freq_range->start_freq_khz && + end_freq_khz <= freq_range->end_freq_khz) + return true; + + return false; } /** @@ -848,14 +844,17 @@ static u32 map_regdom_flags(u32 rd_flags) static int freq_reg_info_regd(struct wiphy *wiphy, u32 center_freq, - u32 *bandwidth, + u32 desired_bw_khz, const struct ieee80211_reg_rule **reg_rule, const struct ieee80211_regdomain *custom_regd) { int i; bool band_rule_found = false; const struct ieee80211_regdomain *regd; - u32 max_bandwidth = 0; + bool bw_fits = false; + + if (!desired_bw_khz) + desired_bw_khz = MHZ_TO_KHZ(20); regd = custom_regd ? custom_regd : cfg80211_regdomain; @@ -888,38 +887,54 @@ static int freq_reg_info_regd(struct wiphy *wiphy, if (!band_rule_found) band_rule_found = freq_in_rule_band(fr, center_freq); - max_bandwidth = freq_max_bandwidth(fr, center_freq); + bw_fits = reg_does_bw_fit(fr, + center_freq, + desired_bw_khz); - if (max_bandwidth && *bandwidth <= max_bandwidth) { + if (band_rule_found && bw_fits) { *reg_rule = rr; - *bandwidth = max_bandwidth; - break; + return 0; } } if (!band_rule_found) return -ERANGE; - return !max_bandwidth; + return -EINVAL; } EXPORT_SYMBOL(freq_reg_info); -int freq_reg_info(struct wiphy *wiphy, u32 center_freq, u32 *bandwidth, - const struct ieee80211_reg_rule **reg_rule) +int freq_reg_info(struct wiphy *wiphy, + u32 center_freq, + u32 desired_bw_khz, + const struct ieee80211_reg_rule **reg_rule) { assert_cfg80211_lock(); - return freq_reg_info_regd(wiphy, center_freq, - bandwidth, reg_rule, NULL); + return freq_reg_info_regd(wiphy, + center_freq, + desired_bw_khz, + reg_rule, + NULL); } +/* + * Note that right now we assume the desired channel bandwidth + * is always 20 MHz for each individual channel (HT40 uses 20 MHz + * per channel, the primary and the extension channel). To support + * smaller custom bandwidths such as 5 MHz or 10 MHz we'll need a + * new ieee80211_channel.target_bw and re run the regulatory check + * on the wiphy with the target_bw specified. Then we can simply use + * that below for the desired_bw_khz below. + */ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, unsigned int chan_idx) { int r; - u32 flags; - u32 max_bandwidth = 0; + u32 flags, bw_flags = 0; + u32 desired_bw_khz = MHZ_TO_KHZ(20); const struct ieee80211_reg_rule *reg_rule = NULL; const struct ieee80211_power_rule *power_rule = NULL; + const struct ieee80211_freq_range *freq_range = NULL; struct ieee80211_supported_band *sband; struct ieee80211_channel *chan; struct wiphy *request_wiphy = NULL; @@ -934,8 +949,10 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, flags = chan->orig_flags; - r = freq_reg_info(wiphy, MHZ_TO_KHZ(chan->center_freq), - &max_bandwidth, ®_rule); + r = freq_reg_info(wiphy, + MHZ_TO_KHZ(chan->center_freq), + desired_bw_khz, + ®_rule); if (r) { /* @@ -978,6 +995,10 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, } power_rule = ®_rule->power_rule; + freq_range = ®_rule->freq_range; + + if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(40)) + bw_flags = IEEE80211_CHAN_NO_HT40; if (last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER && request_wiphy && request_wiphy == wiphy && @@ -988,19 +1009,19 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, * settings */ chan->flags = chan->orig_flags = - map_regdom_flags(reg_rule->flags); + map_regdom_flags(reg_rule->flags) | bw_flags; chan->max_antenna_gain = chan->orig_mag = (int) MBI_TO_DBI(power_rule->max_antenna_gain); - chan->max_bandwidth = KHZ_TO_MHZ(max_bandwidth); + chan->max_bandwidth = KHZ_TO_MHZ(desired_bw_khz); chan->max_power = chan->orig_mpwr = (int) MBM_TO_DBM(power_rule->max_eirp); return; } - chan->flags = flags | map_regdom_flags(reg_rule->flags); + chan->flags = flags | bw_flags | map_regdom_flags(reg_rule->flags); chan->max_antenna_gain = min(chan->orig_mag, (int) MBI_TO_DBI(power_rule->max_antenna_gain)); - chan->max_bandwidth = KHZ_TO_MHZ(max_bandwidth); + chan->max_bandwidth = KHZ_TO_MHZ(desired_bw_khz); if (chan->orig_mpwr) chan->max_power = min(chan->orig_mpwr, (int) MBM_TO_DBM(power_rule->max_eirp)); @@ -1050,18 +1071,10 @@ static void handle_reg_beacon(struct wiphy *wiphy, unsigned int chan_idx, struct reg_beacon *reg_beacon) { -#ifdef CONFIG_CFG80211_REG_DEBUG -#define REG_DEBUG_BEACON_FLAG(desc) \ - printk(KERN_DEBUG "cfg80211: Enabling " desc " on " \ - "frequency: %d MHz (Ch %d) on %s\n", \ - reg_beacon->chan.center_freq, \ - ieee80211_frequency_to_channel(reg_beacon->chan.center_freq), \ - wiphy_name(wiphy)); -#else -#define REG_DEBUG_BEACON_FLAG(desc) do {} while (0) -#endif struct ieee80211_supported_band *sband; struct ieee80211_channel *chan; + bool channel_changed = false; + struct ieee80211_channel chan_before; assert_cfg80211_lock(); @@ -1071,18 +1084,28 @@ static void handle_reg_beacon(struct wiphy *wiphy, if (likely(chan->center_freq != reg_beacon->chan.center_freq)) return; - if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) { - chan->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; - REG_DEBUG_BEACON_FLAG("active scanning"); - } - - if (chan->flags & IEEE80211_CHAN_NO_IBSS) { - chan->flags &= ~IEEE80211_CHAN_NO_IBSS; - REG_DEBUG_BEACON_FLAG("beaconing"); - } + if (chan->beacon_found) + return; chan->beacon_found = true; -#undef REG_DEBUG_BEACON_FLAG + + chan_before.center_freq = chan->center_freq; + chan_before.flags = chan->flags; + + if ((chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) && + !(chan->orig_flags & IEEE80211_CHAN_PASSIVE_SCAN)) { + chan->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; + channel_changed = true; + } + + if ((chan->flags & IEEE80211_CHAN_NO_IBSS) && + !(chan->orig_flags & IEEE80211_CHAN_NO_IBSS)) { + chan->flags &= ~IEEE80211_CHAN_NO_IBSS; + channel_changed = true; + } + + if (channel_changed) + nl80211_send_beacon_hint_event(wiphy, &chan_before, chan); } /* @@ -1155,6 +1178,93 @@ static void reg_process_beacons(struct wiphy *wiphy) wiphy_update_beacon_reg(wiphy); } +static bool is_ht40_not_allowed(struct ieee80211_channel *chan) +{ + if (!chan) + return true; + if (chan->flags & IEEE80211_CHAN_DISABLED) + return true; + /* This would happen when regulatory rules disallow HT40 completely */ + if (IEEE80211_CHAN_NO_HT40 == (chan->flags & (IEEE80211_CHAN_NO_HT40))) + return true; + return false; +} + +static void reg_process_ht_flags_channel(struct wiphy *wiphy, + enum ieee80211_band band, + unsigned int chan_idx) +{ + struct ieee80211_supported_band *sband; + struct ieee80211_channel *channel; + struct ieee80211_channel *channel_before = NULL, *channel_after = NULL; + unsigned int i; + + assert_cfg80211_lock(); + + sband = wiphy->bands[band]; + BUG_ON(chan_idx >= sband->n_channels); + channel = &sband->channels[chan_idx]; + + if (is_ht40_not_allowed(channel)) { + channel->flags |= IEEE80211_CHAN_NO_HT40; + return; + } + + /* + * We need to ensure the extension channels exist to + * be able to use HT40- or HT40+, this finds them (or not) + */ + for (i = 0; i < sband->n_channels; i++) { + struct ieee80211_channel *c = &sband->channels[i]; + if (c->center_freq == (channel->center_freq - 20)) + channel_before = c; + if (c->center_freq == (channel->center_freq + 20)) + channel_after = c; + } + + /* + * Please note that this assumes target bandwidth is 20 MHz, + * if that ever changes we also need to change the below logic + * to include that as well. + */ + if (is_ht40_not_allowed(channel_before)) + channel->flags |= IEEE80211_CHAN_NO_HT40MINUS; + else + channel->flags &= ~IEEE80211_CHAN_NO_HT40MINUS; + + if (is_ht40_not_allowed(channel_after)) + channel->flags |= IEEE80211_CHAN_NO_HT40PLUS; + else + channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS; +} + +static void reg_process_ht_flags_band(struct wiphy *wiphy, + enum ieee80211_band band) +{ + unsigned int i; + struct ieee80211_supported_band *sband; + + BUG_ON(!wiphy->bands[band]); + sband = wiphy->bands[band]; + + for (i = 0; i < sband->n_channels; i++) + reg_process_ht_flags_channel(wiphy, band, i); +} + +static void reg_process_ht_flags(struct wiphy *wiphy) +{ + enum ieee80211_band band; + + if (!wiphy) + return; + + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + if (wiphy->bands[band]) + reg_process_ht_flags_band(wiphy, band); + } + +} + void wiphy_update_regulatory(struct wiphy *wiphy, enum nl80211_reg_initiator initiator) { @@ -1168,6 +1278,7 @@ void wiphy_update_regulatory(struct wiphy *wiphy, } out: reg_process_beacons(wiphy); + reg_process_ht_flags(wiphy); if (wiphy->reg_notifier) wiphy->reg_notifier(wiphy, last_request); } @@ -1178,9 +1289,11 @@ static void handle_channel_custom(struct wiphy *wiphy, const struct ieee80211_regdomain *regd) { int r; - u32 max_bandwidth = 0; + u32 desired_bw_khz = MHZ_TO_KHZ(20); + u32 bw_flags = 0; const struct ieee80211_reg_rule *reg_rule = NULL; const struct ieee80211_power_rule *power_rule = NULL; + const struct ieee80211_freq_range *freq_range = NULL; struct ieee80211_supported_band *sband; struct ieee80211_channel *chan; @@ -1190,8 +1303,11 @@ static void handle_channel_custom(struct wiphy *wiphy, BUG_ON(chan_idx >= sband->n_channels); chan = &sband->channels[chan_idx]; - r = freq_reg_info_regd(wiphy, MHZ_TO_KHZ(chan->center_freq), - &max_bandwidth, ®_rule, regd); + r = freq_reg_info_regd(wiphy, + MHZ_TO_KHZ(chan->center_freq), + desired_bw_khz, + ®_rule, + regd); if (r) { chan->flags = IEEE80211_CHAN_DISABLED; @@ -1199,10 +1315,14 @@ static void handle_channel_custom(struct wiphy *wiphy, } power_rule = ®_rule->power_rule; + freq_range = ®_rule->freq_range; - chan->flags |= map_regdom_flags(reg_rule->flags); + if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(40)) + bw_flags = IEEE80211_CHAN_NO_HT40; + + chan->flags |= map_regdom_flags(reg_rule->flags) | bw_flags; chan->max_antenna_gain = (int) MBI_TO_DBI(power_rule->max_antenna_gain); - chan->max_bandwidth = KHZ_TO_MHZ(max_bandwidth); + chan->max_bandwidth = KHZ_TO_MHZ(desired_bw_khz); chan->max_power = (int) MBM_TO_DBM(power_rule->max_eirp); } @@ -1224,13 +1344,22 @@ void wiphy_apply_custom_regulatory(struct wiphy *wiphy, const struct ieee80211_regdomain *regd) { enum ieee80211_band band; + unsigned int bands_set = 0; mutex_lock(&cfg80211_mutex); for (band = 0; band < IEEE80211_NUM_BANDS; band++) { - if (wiphy->bands[band]) - handle_band_custom(wiphy, band, regd); + if (!wiphy->bands[band]) + continue; + handle_band_custom(wiphy, band, regd); + bands_set++; } mutex_unlock(&cfg80211_mutex); + + /* + * no point in calling this if it won't have any effect + * on your device's supportd bands. + */ + WARN_ON(!bands_set); } EXPORT_SYMBOL(wiphy_apply_custom_regulatory); @@ -2000,7 +2129,12 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) * driver wanted to the wiphy to deal with conflicts */ - BUG_ON(request_wiphy->regd); + /* + * Userspace could have sent two replies with only + * one kernel request. + */ + if (request_wiphy->regd) + return -EALREADY; r = reg_copy_regd(&request_wiphy->regd, rd); if (r) @@ -2042,7 +2176,13 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) * the country IE rd with what CRDA believes that country should have */ - BUG_ON(!country_ie_regdomain); + /* + * Userspace could have sent two replies with only + * one kernel request. By the second reply we would have + * already processed and consumed the country_ie_regdomain. + */ + if (!country_ie_regdomain) + return -EALREADY; BUG_ON(rd == country_ie_regdomain); /* @@ -2119,14 +2259,14 @@ void reg_device_remove(struct wiphy *wiphy) assert_cfg80211_lock(); + kfree(wiphy->regd); + if (last_request) request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); - kfree(wiphy->regd); - if (!last_request || !request_wiphy) - return; - if (request_wiphy != wiphy) + if (!request_wiphy || request_wiphy != wiphy) return; + last_request->wiphy_idx = WIPHY_IDX_STALE; last_request->country_ie_env = ENVIRON_ANY; } diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 1f260c40b6ca..e95b638b919f 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -29,13 +29,14 @@ void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted) goto out; WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req); - wiphy_to_dev(request->wiphy)->scan_req = NULL; if (aborted) nl80211_send_scan_aborted(wiphy_to_dev(request->wiphy), dev); else nl80211_send_scan_done(wiphy_to_dev(request->wiphy), dev); + wiphy_to_dev(request->wiphy)->scan_req = NULL; + #ifdef CONFIG_WIRELESS_EXT if (!aborted) { memset(&wrqu, 0, sizeof(wrqu)); @@ -377,18 +378,16 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev, size_t used = dev->wiphy.bss_priv_size + sizeof(*res); size_t ielen = res->pub.len_information_elements; - if (ksize(found) >= used + ielen) { + if (!found->ies_allocated && ksize(found) >= used + ielen) { memcpy(found->pub.information_elements, res->pub.information_elements, ielen); found->pub.len_information_elements = ielen; } else { u8 *ies = found->pub.information_elements; - if (found->ies_allocated) { - if (ksize(ies) < ielen) - ies = krealloc(ies, ielen, - GFP_ATOMIC); - } else + if (found->ies_allocated) + ies = krealloc(ies, ielen, GFP_ATOMIC); + else ies = kmalloc(ielen, GFP_ATOMIC); if (ies) { @@ -415,6 +414,55 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev, return found; } +struct cfg80211_bss* +cfg80211_inform_bss(struct wiphy *wiphy, + struct ieee80211_channel *channel, + const u8 *bssid, + u64 timestamp, u16 capability, u16 beacon_interval, + const u8 *ie, size_t ielen, + s32 signal, gfp_t gfp) +{ + struct cfg80211_internal_bss *res; + size_t privsz; + + if (WARN_ON(!wiphy)) + return NULL; + + privsz = wiphy->bss_priv_size; + + if (WARN_ON(wiphy->signal_type == NL80211_BSS_SIGNAL_UNSPEC && + (signal < 0 || signal > 100))) + return NULL; + + res = kzalloc(sizeof(*res) + privsz + ielen, gfp); + if (!res) + return NULL; + + memcpy(res->pub.bssid, bssid, ETH_ALEN); + res->pub.channel = channel; + res->pub.signal = signal; + res->pub.tsf = timestamp; + res->pub.beacon_interval = beacon_interval; + res->pub.capability = capability; + /* point to after the private area */ + res->pub.information_elements = (u8 *)res + sizeof(*res) + privsz; + memcpy(res->pub.information_elements, ie, ielen); + res->pub.len_information_elements = ielen; + + kref_init(&res->ref); + + res = cfg80211_bss_update(wiphy_to_dev(wiphy), res, 0); + if (!res) + return NULL; + + if (res->pub.capability & WLAN_CAPABILITY_ESS) + regulatory_hint_found_beacon(wiphy, channel, gfp); + + /* cfg80211_bss_update gives us a referenced result */ + return &res->pub; +} +EXPORT_SYMBOL(cfg80211_inform_bss); + struct cfg80211_bss * cfg80211_inform_bss_frame(struct wiphy *wiphy, struct ieee80211_channel *channel, @@ -605,7 +653,7 @@ int cfg80211_wext_siwscan(struct net_device *dev, cfg80211_put_dev(rdev); return err; } -EXPORT_SYMBOL(cfg80211_wext_siwscan); +EXPORT_SYMBOL_GPL(cfg80211_wext_siwscan); static void ieee80211_scan_add_ies(struct iw_request_info *info, struct cfg80211_bss *bss, @@ -914,5 +962,5 @@ int cfg80211_wext_giwscan(struct net_device *dev, cfg80211_put_dev(rdev); return res; } -EXPORT_SYMBOL(cfg80211_wext_giwscan); +EXPORT_SYMBOL_GPL(cfg80211_wext_giwscan); #endif diff --git a/net/wireless/util.c b/net/wireless/util.c index 487cdd9bcffc..25550692dda6 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -1,10 +1,12 @@ /* * Wireless utility functions * - * Copyright 2007 Johannes Berg + * Copyright 2007-2009 Johannes Berg */ -#include -#include +#include +#include +#include +#include #include "core.h" struct ieee80211_rate * @@ -138,3 +140,365 @@ void ieee80211_set_bitrate_flags(struct wiphy *wiphy) if (wiphy->bands[band]) set_mandatory_flags_band(wiphy->bands[band], band); } + +int cfg80211_validate_key_settings(struct key_params *params, int key_idx, + const u8 *mac_addr) +{ + if (key_idx > 5) + return -EINVAL; + + /* + * Disallow pairwise keys with non-zero index unless it's WEP + * (because current deployments use pairwise WEP keys with + * non-zero indizes but 802.11i clearly specifies to use zero) + */ + if (mac_addr && key_idx && + params->cipher != WLAN_CIPHER_SUITE_WEP40 && + params->cipher != WLAN_CIPHER_SUITE_WEP104) + return -EINVAL; + + switch (params->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + if (params->key_len != WLAN_KEY_LEN_WEP40) + return -EINVAL; + break; + case WLAN_CIPHER_SUITE_TKIP: + if (params->key_len != WLAN_KEY_LEN_TKIP) + return -EINVAL; + break; + case WLAN_CIPHER_SUITE_CCMP: + if (params->key_len != WLAN_KEY_LEN_CCMP) + return -EINVAL; + break; + case WLAN_CIPHER_SUITE_WEP104: + if (params->key_len != WLAN_KEY_LEN_WEP104) + return -EINVAL; + break; + case WLAN_CIPHER_SUITE_AES_CMAC: + if (params->key_len != WLAN_KEY_LEN_AES_CMAC) + return -EINVAL; + break; + default: + return -EINVAL; + } + + if (params->seq) { + switch (params->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + /* These ciphers do not use key sequence */ + return -EINVAL; + case WLAN_CIPHER_SUITE_TKIP: + case WLAN_CIPHER_SUITE_CCMP: + case WLAN_CIPHER_SUITE_AES_CMAC: + if (params->seq_len != 6) + return -EINVAL; + break; + } + } + + return 0; +} + +/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ +/* Ethernet-II snap header (RFC1042 for most EtherTypes) */ +const unsigned char rfc1042_header[] __aligned(2) = + { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; +EXPORT_SYMBOL(rfc1042_header); + +/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ +const unsigned char bridge_tunnel_header[] __aligned(2) = + { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; +EXPORT_SYMBOL(bridge_tunnel_header); + +unsigned int ieee80211_hdrlen(__le16 fc) +{ + unsigned int hdrlen = 24; + + if (ieee80211_is_data(fc)) { + if (ieee80211_has_a4(fc)) + hdrlen = 30; + if (ieee80211_is_data_qos(fc)) + hdrlen += IEEE80211_QOS_CTL_LEN; + goto out; + } + + if (ieee80211_is_ctl(fc)) { + /* + * ACK and CTS are 10 bytes, all others 16. To see how + * to get this condition consider + * subtype mask: 0b0000000011110000 (0x00F0) + * ACK subtype: 0b0000000011010000 (0x00D0) + * CTS subtype: 0b0000000011000000 (0x00C0) + * bits that matter: ^^^ (0x00E0) + * value of those: 0b0000000011000000 (0x00C0) + */ + if ((fc & cpu_to_le16(0x00E0)) == cpu_to_le16(0x00C0)) + hdrlen = 10; + else + hdrlen = 16; + } +out: + return hdrlen; +} +EXPORT_SYMBOL(ieee80211_hdrlen); + +unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb) +{ + const struct ieee80211_hdr *hdr = + (const struct ieee80211_hdr *)skb->data; + unsigned int hdrlen; + + if (unlikely(skb->len < 10)) + return 0; + hdrlen = ieee80211_hdrlen(hdr->frame_control); + if (unlikely(hdrlen > skb->len)) + return 0; + return hdrlen; +} +EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb); + +static int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr) +{ + int ae = meshhdr->flags & MESH_FLAGS_AE; + /* 7.1.3.5a.2 */ + switch (ae) { + case 0: + return 6; + case 1: + return 12; + case 2: + return 18; + case 3: + return 24; + default: + return 6; + } +} + +int ieee80211_data_to_8023(struct sk_buff *skb, u8 *addr, + enum nl80211_iftype iftype) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + u16 hdrlen, ethertype; + u8 *payload; + u8 dst[ETH_ALEN]; + u8 src[ETH_ALEN] __aligned(2); + + if (unlikely(!ieee80211_is_data_present(hdr->frame_control))) + return -1; + + hdrlen = ieee80211_hdrlen(hdr->frame_control); + + /* convert IEEE 802.11 header + possible LLC headers into Ethernet + * header + * IEEE 802.11 address fields: + * ToDS FromDS Addr1 Addr2 Addr3 Addr4 + * 0 0 DA SA BSSID n/a + * 0 1 DA BSSID SA n/a + * 1 0 BSSID SA DA n/a + * 1 1 RA TA DA SA + */ + memcpy(dst, ieee80211_get_DA(hdr), ETH_ALEN); + memcpy(src, ieee80211_get_SA(hdr), ETH_ALEN); + + switch (hdr->frame_control & + cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) { + case cpu_to_le16(IEEE80211_FCTL_TODS): + if (unlikely(iftype != NL80211_IFTYPE_AP && + iftype != NL80211_IFTYPE_AP_VLAN)) + return -1; + break; + case cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS): + if (unlikely(iftype != NL80211_IFTYPE_WDS && + iftype != NL80211_IFTYPE_MESH_POINT)) + return -1; + if (iftype == NL80211_IFTYPE_MESH_POINT) { + struct ieee80211s_hdr *meshdr = + (struct ieee80211s_hdr *) (skb->data + hdrlen); + hdrlen += ieee80211_get_mesh_hdrlen(meshdr); + if (meshdr->flags & MESH_FLAGS_AE_A5_A6) { + memcpy(dst, meshdr->eaddr1, ETH_ALEN); + memcpy(src, meshdr->eaddr2, ETH_ALEN); + } + } + break; + case cpu_to_le16(IEEE80211_FCTL_FROMDS): + if (iftype != NL80211_IFTYPE_STATION || + (is_multicast_ether_addr(dst) && + !compare_ether_addr(src, addr))) + return -1; + break; + case cpu_to_le16(0): + if (iftype != NL80211_IFTYPE_ADHOC) + return -1; + break; + } + + if (unlikely(skb->len - hdrlen < 8)) + return -1; + + payload = skb->data + hdrlen; + ethertype = (payload[6] << 8) | payload[7]; + + if (likely((compare_ether_addr(payload, rfc1042_header) == 0 && + ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || + compare_ether_addr(payload, bridge_tunnel_header) == 0)) { + /* remove RFC1042 or Bridge-Tunnel encapsulation and + * replace EtherType */ + skb_pull(skb, hdrlen + 6); + memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); + memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); + } else { + struct ethhdr *ehdr; + __be16 len; + + skb_pull(skb, hdrlen); + len = htons(skb->len); + ehdr = (struct ethhdr *) skb_push(skb, sizeof(struct ethhdr)); + memcpy(ehdr->h_dest, dst, ETH_ALEN); + memcpy(ehdr->h_source, src, ETH_ALEN); + ehdr->h_proto = len; + } + return 0; +} +EXPORT_SYMBOL(ieee80211_data_to_8023); + +int ieee80211_data_from_8023(struct sk_buff *skb, u8 *addr, + enum nl80211_iftype iftype, u8 *bssid, bool qos) +{ + struct ieee80211_hdr hdr; + u16 hdrlen, ethertype; + __le16 fc; + const u8 *encaps_data; + int encaps_len, skip_header_bytes; + int nh_pos, h_pos; + int head_need; + + if (unlikely(skb->len < ETH_HLEN)) + return -EINVAL; + + nh_pos = skb_network_header(skb) - skb->data; + h_pos = skb_transport_header(skb) - skb->data; + + /* convert Ethernet header to proper 802.11 header (based on + * operation mode) */ + ethertype = (skb->data[12] << 8) | skb->data[13]; + fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA); + + switch (iftype) { + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_AP_VLAN: + fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS); + /* DA BSSID SA */ + memcpy(hdr.addr1, skb->data, ETH_ALEN); + memcpy(hdr.addr2, addr, ETH_ALEN); + memcpy(hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN); + hdrlen = 24; + break; + case NL80211_IFTYPE_STATION: + fc |= cpu_to_le16(IEEE80211_FCTL_TODS); + /* BSSID SA DA */ + memcpy(hdr.addr1, bssid, ETH_ALEN); + memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); + memcpy(hdr.addr3, skb->data, ETH_ALEN); + hdrlen = 24; + break; + case NL80211_IFTYPE_ADHOC: + /* DA SA BSSID */ + memcpy(hdr.addr1, skb->data, ETH_ALEN); + memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); + memcpy(hdr.addr3, bssid, ETH_ALEN); + hdrlen = 24; + break; + default: + return -EOPNOTSUPP; + } + + if (qos) { + fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA); + hdrlen += 2; + } + + hdr.frame_control = fc; + hdr.duration_id = 0; + hdr.seq_ctrl = 0; + + skip_header_bytes = ETH_HLEN; + if (ethertype == ETH_P_AARP || ethertype == ETH_P_IPX) { + encaps_data = bridge_tunnel_header; + encaps_len = sizeof(bridge_tunnel_header); + skip_header_bytes -= 2; + } else if (ethertype > 0x600) { + encaps_data = rfc1042_header; + encaps_len = sizeof(rfc1042_header); + skip_header_bytes -= 2; + } else { + encaps_data = NULL; + encaps_len = 0; + } + + skb_pull(skb, skip_header_bytes); + nh_pos -= skip_header_bytes; + h_pos -= skip_header_bytes; + + head_need = hdrlen + encaps_len - skb_headroom(skb); + + if (head_need > 0 || skb_cloned(skb)) { + head_need = max(head_need, 0); + if (head_need) + skb_orphan(skb); + + if (pskb_expand_head(skb, head_need, 0, GFP_ATOMIC)) { + printk(KERN_ERR "failed to reallocate Tx buffer\n"); + return -ENOMEM; + } + skb->truesize += head_need; + } + + if (encaps_data) { + memcpy(skb_push(skb, encaps_len), encaps_data, encaps_len); + nh_pos += encaps_len; + h_pos += encaps_len; + } + + memcpy(skb_push(skb, hdrlen), &hdr, hdrlen); + + nh_pos += hdrlen; + h_pos += hdrlen; + + /* Update skb pointers to various headers since this modified frame + * is going to go through Linux networking code that may potentially + * need things like pointer to IP header. */ + skb_set_mac_header(skb, 0); + skb_set_network_header(skb, nh_pos); + skb_set_transport_header(skb, h_pos); + + return 0; +} +EXPORT_SYMBOL(ieee80211_data_from_8023); + +/* Given a data frame determine the 802.1p/1d tag to use. */ +unsigned int cfg80211_classify8021d(struct sk_buff *skb) +{ + unsigned int dscp; + + /* skb->priority values from 256->263 are magic values to + * directly indicate a specific 802.1d priority. This is used + * to allow 802.1d priority to be passed directly in from VLAN + * tags, etc. + */ + if (skb->priority >= 256 && skb->priority <= 263) + return skb->priority - 256; + + switch (skb->protocol) { + case htons(ETH_P_IP): + dscp = ip_hdr(skb)->tos & 0xfc; + break; + default: + return 0; + } + + return dscp >> 5; +} +EXPORT_SYMBOL(cfg80211_classify8021d); diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 0fd1db6e95bb..d030c5315672 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -5,13 +5,14 @@ * into cfg80211, when that happens all the exports here go away and * we directly assign the wireless handlers of wireless interfaces. * - * Copyright 2008 Johannes Berg + * Copyright 2008-2009 Johannes Berg */ #include #include +#include +#include #include -#include #include #include "core.h" @@ -57,7 +58,7 @@ int cfg80211_wext_giwname(struct net_device *dev, return 0; } -EXPORT_SYMBOL(cfg80211_wext_giwname); +EXPORT_SYMBOL_GPL(cfg80211_wext_giwname); int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info, u32 *mode, char *extra) @@ -108,7 +109,7 @@ int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info, return ret; } -EXPORT_SYMBOL(cfg80211_wext_siwmode); +EXPORT_SYMBOL_GPL(cfg80211_wext_siwmode); int cfg80211_wext_giwmode(struct net_device *dev, struct iw_request_info *info, u32 *mode, char *extra) @@ -143,7 +144,7 @@ int cfg80211_wext_giwmode(struct net_device *dev, struct iw_request_info *info, } return 0; } -EXPORT_SYMBOL(cfg80211_wext_giwmode); +EXPORT_SYMBOL_GPL(cfg80211_wext_giwmode); int cfg80211_wext_giwrange(struct net_device *dev, @@ -206,7 +207,6 @@ int cfg80211_wext_giwrange(struct net_device *dev, range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; - for (band = 0; band < IEEE80211_NUM_BANDS; band ++) { int i; struct ieee80211_supported_band *sband; @@ -240,4 +240,590 @@ int cfg80211_wext_giwrange(struct net_device *dev, return 0; } -EXPORT_SYMBOL(cfg80211_wext_giwrange); +EXPORT_SYMBOL_GPL(cfg80211_wext_giwrange); + +int cfg80211_wext_siwmlme(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct iw_mlme *mlme = (struct iw_mlme *)extra; + struct cfg80211_registered_device *rdev; + union { + struct cfg80211_disassoc_request disassoc; + struct cfg80211_deauth_request deauth; + } cmd; + + if (!wdev) + return -EOPNOTSUPP; + + rdev = wiphy_to_dev(wdev->wiphy); + + if (wdev->iftype != NL80211_IFTYPE_STATION) + return -EINVAL; + + if (mlme->addr.sa_family != ARPHRD_ETHER) + return -EINVAL; + + memset(&cmd, 0, sizeof(cmd)); + + switch (mlme->cmd) { + case IW_MLME_DEAUTH: + if (!rdev->ops->deauth) + return -EOPNOTSUPP; + cmd.deauth.peer_addr = mlme->addr.sa_data; + cmd.deauth.reason_code = mlme->reason_code; + return rdev->ops->deauth(wdev->wiphy, dev, &cmd.deauth); + case IW_MLME_DISASSOC: + if (!rdev->ops->disassoc) + return -EOPNOTSUPP; + cmd.disassoc.peer_addr = mlme->addr.sa_data; + cmd.disassoc.reason_code = mlme->reason_code; + return rdev->ops->disassoc(wdev->wiphy, dev, &cmd.disassoc); + default: + return -EOPNOTSUPP; + } +} +EXPORT_SYMBOL_GPL(cfg80211_wext_siwmlme); + + +/** + * cfg80211_wext_freq - get wext frequency for non-"auto" + * @wiphy: the wiphy + * @freq: the wext freq encoding + * + * Returns a channel, %NULL for auto, or an ERR_PTR for errors! + */ +struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy, + struct iw_freq *freq) +{ + struct ieee80211_channel *chan; + int f; + + /* + * Parse frequency - return NULL for auto and + * -EINVAL for impossible things. + */ + if (freq->e == 0) { + if (freq->m < 0) + return NULL; + f = ieee80211_channel_to_frequency(freq->m); + } else { + int i, div = 1000000; + for (i = 0; i < freq->e; i++) + div /= 10; + if (div <= 0) + return ERR_PTR(-EINVAL); + f = freq->m / div; + } + + /* + * Look up channel struct and return -EINVAL when + * it cannot be found. + */ + chan = ieee80211_get_channel(wiphy, f); + if (!chan) + return ERR_PTR(-EINVAL); + return chan; +} +EXPORT_SYMBOL_GPL(cfg80211_wext_freq); + +int cfg80211_wext_siwrts(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rts, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + u32 orts = wdev->wiphy->rts_threshold; + int err; + + if (rts->disabled || !rts->fixed) + wdev->wiphy->rts_threshold = (u32) -1; + else if (rts->value < 0) + return -EINVAL; + else + wdev->wiphy->rts_threshold = rts->value; + + err = rdev->ops->set_wiphy_params(wdev->wiphy, + WIPHY_PARAM_RTS_THRESHOLD); + if (err) + wdev->wiphy->rts_threshold = orts; + + return err; +} +EXPORT_SYMBOL_GPL(cfg80211_wext_siwrts); + +int cfg80211_wext_giwrts(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rts, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + rts->value = wdev->wiphy->rts_threshold; + rts->disabled = rts->value == (u32) -1; + rts->fixed = 1; + + return 0; +} +EXPORT_SYMBOL_GPL(cfg80211_wext_giwrts); + +int cfg80211_wext_siwfrag(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *frag, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + u32 ofrag = wdev->wiphy->frag_threshold; + int err; + + if (frag->disabled || !frag->fixed) + wdev->wiphy->frag_threshold = (u32) -1; + else if (frag->value < 256) + return -EINVAL; + else { + /* Fragment length must be even, so strip LSB. */ + wdev->wiphy->frag_threshold = frag->value & ~0x1; + } + + err = rdev->ops->set_wiphy_params(wdev->wiphy, + WIPHY_PARAM_FRAG_THRESHOLD); + if (err) + wdev->wiphy->frag_threshold = ofrag; + + return err; +} +EXPORT_SYMBOL_GPL(cfg80211_wext_siwfrag); + +int cfg80211_wext_giwfrag(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *frag, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + frag->value = wdev->wiphy->frag_threshold; + frag->disabled = frag->value == (u32) -1; + frag->fixed = 1; + + return 0; +} +EXPORT_SYMBOL_GPL(cfg80211_wext_giwfrag); + +int cfg80211_wext_siwretry(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *retry, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + u32 changed = 0; + u8 olong = wdev->wiphy->retry_long; + u8 oshort = wdev->wiphy->retry_short; + int err; + + if (retry->disabled || + (retry->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT) + return -EINVAL; + + if (retry->flags & IW_RETRY_LONG) { + wdev->wiphy->retry_long = retry->value; + changed |= WIPHY_PARAM_RETRY_LONG; + } else if (retry->flags & IW_RETRY_SHORT) { + wdev->wiphy->retry_short = retry->value; + changed |= WIPHY_PARAM_RETRY_SHORT; + } else { + wdev->wiphy->retry_short = retry->value; + wdev->wiphy->retry_long = retry->value; + changed |= WIPHY_PARAM_RETRY_LONG; + changed |= WIPHY_PARAM_RETRY_SHORT; + } + + if (!changed) + return 0; + + err = rdev->ops->set_wiphy_params(wdev->wiphy, changed); + if (err) { + wdev->wiphy->retry_short = oshort; + wdev->wiphy->retry_long = olong; + } + + return err; +} +EXPORT_SYMBOL_GPL(cfg80211_wext_siwretry); + +int cfg80211_wext_giwretry(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *retry, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + retry->disabled = 0; + + if (retry->flags == 0 || (retry->flags & IW_RETRY_SHORT)) { + /* + * First return short value, iwconfig will ask long value + * later if needed + */ + retry->flags |= IW_RETRY_LIMIT; + retry->value = wdev->wiphy->retry_short; + if (wdev->wiphy->retry_long != wdev->wiphy->retry_short) + retry->flags |= IW_RETRY_LONG; + + return 0; + } + + if (retry->flags & IW_RETRY_LONG) { + retry->flags = IW_RETRY_LIMIT | IW_RETRY_LONG; + retry->value = wdev->wiphy->retry_long; + } + + return 0; +} +EXPORT_SYMBOL_GPL(cfg80211_wext_giwretry); + +static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev, + struct net_device *dev, const u8 *addr, + bool remove, bool tx_key, int idx, + struct key_params *params) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + int err; + + if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC) { + if (!rdev->ops->set_default_mgmt_key) + return -EOPNOTSUPP; + + if (idx < 4 || idx > 5) + return -EINVAL; + } else if (idx < 0 || idx > 3) + return -EINVAL; + + if (remove) { + err = rdev->ops->del_key(&rdev->wiphy, dev, idx, addr); + if (!err) { + if (idx == wdev->wext.default_key) + wdev->wext.default_key = -1; + else if (idx == wdev->wext.default_mgmt_key) + wdev->wext.default_mgmt_key = -1; + } + /* + * Applications using wireless extensions expect to be + * able to delete keys that don't exist, so allow that. + */ + if (err == -ENOENT) + return 0; + + return err; + } else { + if (addr) + tx_key = false; + + if (cfg80211_validate_key_settings(params, idx, addr)) + return -EINVAL; + + err = rdev->ops->add_key(&rdev->wiphy, dev, idx, addr, params); + if (err) + return err; + + if (tx_key || (!addr && wdev->wext.default_key == -1)) { + err = rdev->ops->set_default_key(&rdev->wiphy, + dev, idx); + if (!err) + wdev->wext.default_key = idx; + return err; + } + + if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC && + (tx_key || (!addr && wdev->wext.default_mgmt_key == -1))) { + err = rdev->ops->set_default_mgmt_key(&rdev->wiphy, + dev, idx); + if (!err) + wdev->wext.default_mgmt_key = idx; + return err; + } + + return 0; + } +} + +int cfg80211_wext_siwencode(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *erq, char *keybuf) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + int idx, err; + bool remove = false; + struct key_params params; + + /* no use -- only MFP (set_default_mgmt_key) is optional */ + if (!rdev->ops->del_key || + !rdev->ops->add_key || + !rdev->ops->set_default_key) + return -EOPNOTSUPP; + + idx = erq->flags & IW_ENCODE_INDEX; + if (idx == 0) { + idx = wdev->wext.default_key; + if (idx < 0) + idx = 0; + } else if (idx < 1 || idx > 4) + return -EINVAL; + else + idx--; + + if (erq->flags & IW_ENCODE_DISABLED) + remove = true; + else if (erq->length == 0) { + /* No key data - just set the default TX key index */ + err = rdev->ops->set_default_key(&rdev->wiphy, dev, idx); + if (!err) + wdev->wext.default_key = idx; + return err; + } + + memset(¶ms, 0, sizeof(params)); + params.key = keybuf; + params.key_len = erq->length; + if (erq->length == 5) + params.cipher = WLAN_CIPHER_SUITE_WEP40; + else if (erq->length == 13) + params.cipher = WLAN_CIPHER_SUITE_WEP104; + else if (!remove) + return -EINVAL; + + return cfg80211_set_encryption(rdev, dev, NULL, remove, + wdev->wext.default_key == -1, + idx, ¶ms); +} +EXPORT_SYMBOL_GPL(cfg80211_wext_siwencode); + +int cfg80211_wext_siwencodeext(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *erq, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; + const u8 *addr; + int idx; + bool remove = false; + struct key_params params; + u32 cipher; + + /* no use -- only MFP (set_default_mgmt_key) is optional */ + if (!rdev->ops->del_key || + !rdev->ops->add_key || + !rdev->ops->set_default_key) + return -EOPNOTSUPP; + + switch (ext->alg) { + case IW_ENCODE_ALG_NONE: + remove = true; + cipher = 0; + break; + case IW_ENCODE_ALG_WEP: + if (ext->key_len == 5) + cipher = WLAN_CIPHER_SUITE_WEP40; + else if (ext->key_len == 13) + cipher = WLAN_CIPHER_SUITE_WEP104; + else + return -EINVAL; + break; + case IW_ENCODE_ALG_TKIP: + cipher = WLAN_CIPHER_SUITE_TKIP; + break; + case IW_ENCODE_ALG_CCMP: + cipher = WLAN_CIPHER_SUITE_CCMP; + break; + case IW_ENCODE_ALG_AES_CMAC: + cipher = WLAN_CIPHER_SUITE_AES_CMAC; + break; + default: + return -EOPNOTSUPP; + } + + if (erq->flags & IW_ENCODE_DISABLED) + remove = true; + + idx = erq->flags & IW_ENCODE_INDEX; + if (cipher == WLAN_CIPHER_SUITE_AES_CMAC) { + if (idx < 4 || idx > 5) { + idx = wdev->wext.default_mgmt_key; + if (idx < 0) + return -EINVAL; + } else + idx--; + } else { + if (idx < 1 || idx > 4) { + idx = wdev->wext.default_key; + if (idx < 0) + return -EINVAL; + } else + idx--; + } + + addr = ext->addr.sa_data; + if (is_broadcast_ether_addr(addr)) + addr = NULL; + + memset(¶ms, 0, sizeof(params)); + params.key = ext->key; + params.key_len = ext->key_len; + params.cipher = cipher; + + if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) { + params.seq = ext->rx_seq; + params.seq_len = 6; + } + + return cfg80211_set_encryption( + rdev, dev, addr, remove, + ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY, + idx, ¶ms); +} +EXPORT_SYMBOL_GPL(cfg80211_wext_siwencodeext); + +struct giwencode_cookie { + size_t buflen; + char *keybuf; +}; + +static void giwencode_get_key_cb(void *cookie, struct key_params *params) +{ + struct giwencode_cookie *data = cookie; + + if (!params->key) { + data->buflen = 0; + return; + } + + data->buflen = min_t(size_t, data->buflen, params->key_len); + memcpy(data->keybuf, params->key, data->buflen); +} + +int cfg80211_wext_giwencode(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *erq, char *keybuf) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + int idx, err; + struct giwencode_cookie data = { + .keybuf = keybuf, + .buflen = erq->length, + }; + + if (!rdev->ops->get_key) + return -EOPNOTSUPP; + + idx = erq->flags & IW_ENCODE_INDEX; + if (idx == 0) { + idx = wdev->wext.default_key; + if (idx < 0) + idx = 0; + } else if (idx < 1 || idx > 4) + return -EINVAL; + else + idx--; + + erq->flags = idx + 1; + + err = rdev->ops->get_key(&rdev->wiphy, dev, idx, NULL, &data, + giwencode_get_key_cb); + if (!err) { + erq->length = data.buflen; + erq->flags |= IW_ENCODE_ENABLED; + return 0; + } + + if (err == -ENOENT) { + erq->flags |= IW_ENCODE_DISABLED; + erq->length = 0; + return 0; + } + + return err; +} +EXPORT_SYMBOL_GPL(cfg80211_wext_giwencode); + +int cfg80211_wext_siwtxpower(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *data, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + enum tx_power_setting type; + int dbm = 0; + + if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) + return -EINVAL; + if (data->txpower.flags & IW_TXPOW_RANGE) + return -EINVAL; + + if (!rdev->ops->set_tx_power) + return -EOPNOTSUPP; + + /* only change when not disabling */ + if (!data->txpower.disabled) { + rfkill_set_sw_state(rdev->rfkill, false); + + if (data->txpower.fixed) { + /* + * wext doesn't support negative values, see + * below where it's for automatic + */ + if (data->txpower.value < 0) + return -EINVAL; + dbm = data->txpower.value; + type = TX_POWER_FIXED; + /* TODO: do regulatory check! */ + } else { + /* + * Automatic power level setting, max being the value + * passed in from userland. + */ + if (data->txpower.value < 0) { + type = TX_POWER_AUTOMATIC; + } else { + dbm = data->txpower.value; + type = TX_POWER_LIMITED; + } + } + } else { + rfkill_set_sw_state(rdev->rfkill, true); + schedule_work(&rdev->rfkill_sync); + return 0; + } + + return rdev->ops->set_tx_power(wdev->wiphy, type, dbm);; +} +EXPORT_SYMBOL_GPL(cfg80211_wext_siwtxpower); + +int cfg80211_wext_giwtxpower(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *data, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + int err, val; + + if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) + return -EINVAL; + if (data->txpower.flags & IW_TXPOW_RANGE) + return -EINVAL; + + if (!rdev->ops->get_tx_power) + return -EOPNOTSUPP; + + err = rdev->ops->get_tx_power(wdev->wiphy, &val); + if (err) + return err; + + /* well... oh well */ + data->txpower.fixed = 1; + data->txpower.disabled = rfkill_blocked(rdev->rfkill); + data->txpower.value = val; + data->txpower.flags = IW_TXPOW_DBM; + + return 0; +} +EXPORT_SYMBOL_GPL(cfg80211_wext_giwtxpower); diff --git a/net/wireless/wext.c b/net/wireless/wext.c index 0e59f9ae9b81..252c2010c2e2 100644 --- a/net/wireless/wext.c +++ b/net/wireless/wext.c @@ -636,8 +636,10 @@ static void wireless_seq_printf_stats(struct seq_file *seq, /* * Print info for /proc/net/wireless (print all entries) */ -static int wireless_seq_show(struct seq_file *seq, void *v) +static int wireless_dev_seq_show(struct seq_file *seq, void *v) { + might_sleep(); + if (v == SEQ_START_TOKEN) seq_printf(seq, "Inter-| sta-| Quality | Discarded " "packets | Missed | WE\n" @@ -649,14 +651,46 @@ static int wireless_seq_show(struct seq_file *seq, void *v) return 0; } +static void *wireless_dev_seq_start(struct seq_file *seq, loff_t *pos) +{ + struct net *net = seq_file_net(seq); + loff_t off; + struct net_device *dev; + + rtnl_lock(); + if (!*pos) + return SEQ_START_TOKEN; + + off = 1; + for_each_netdev(net, dev) + if (off++ == *pos) + return dev; + return NULL; +} + +static void *wireless_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + struct net *net = seq_file_net(seq); + + ++*pos; + + return v == SEQ_START_TOKEN ? + first_net_device(net) : next_net_device(v); +} + +static void wireless_dev_seq_stop(struct seq_file *seq, void *v) +{ + rtnl_unlock(); +} + static const struct seq_operations wireless_seq_ops = { - .start = dev_seq_start, - .next = dev_seq_next, - .stop = dev_seq_stop, - .show = wireless_seq_show, + .start = wireless_dev_seq_start, + .next = wireless_dev_seq_next, + .stop = wireless_dev_seq_stop, + .show = wireless_dev_seq_show, }; -static int wireless_seq_open(struct inode *inode, struct file *file) +static int seq_open_wireless(struct inode *inode, struct file *file) { return seq_open_net(inode, file, &wireless_seq_ops, sizeof(struct seq_net_private)); @@ -664,7 +698,7 @@ static int wireless_seq_open(struct inode *inode, struct file *file) static const struct file_operations wireless_seq_fops = { .owner = THIS_MODULE, - .open = wireless_seq_open, + .open = seq_open_wireless, .read = seq_read, .llseek = seq_lseek, .release = seq_release_net, diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index ed80af8ca5fb..21cdc872004e 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c @@ -332,14 +332,14 @@ static unsigned int x25_new_lci(struct x25_neigh *nb) /* * Deferred destroy. */ -void x25_destroy_socket(struct sock *); +static void __x25_destroy_socket(struct sock *); /* * handler for deferred kills. */ static void x25_destroy_timer(unsigned long data) { - x25_destroy_socket((struct sock *)data); + x25_destroy_socket_from_timer((struct sock *)data); } /* @@ -349,12 +349,10 @@ static void x25_destroy_timer(unsigned long data) * will touch it and we are (fairly 8-) ) safe. * Not static as it's used by the timer */ -void x25_destroy_socket(struct sock *sk) +static void __x25_destroy_socket(struct sock *sk) { struct sk_buff *skb; - sock_hold(sk); - lock_sock(sk); x25_stop_heartbeat(sk); x25_stop_timer(sk); @@ -374,8 +372,7 @@ void x25_destroy_socket(struct sock *sk) kfree_skb(skb); } - if (atomic_read(&sk->sk_wmem_alloc) || - atomic_read(&sk->sk_rmem_alloc)) { + if (sk_has_allocations(sk)) { /* Defer: outstanding buffers */ sk->sk_timer.expires = jiffies + 10 * HZ; sk->sk_timer.function = x25_destroy_timer; @@ -385,7 +382,22 @@ void x25_destroy_socket(struct sock *sk) /* drop last reference so sock_put will free */ __sock_put(sk); } +} +void x25_destroy_socket_from_timer(struct sock *sk) +{ + sock_hold(sk); + bh_lock_sock(sk); + __x25_destroy_socket(sk); + bh_unlock_sock(sk); + sock_put(sk); +} + +static void x25_destroy_socket(struct sock *sk) +{ + sock_hold(sk); + lock_sock(sk); + __x25_destroy_socket(sk); release_sock(sk); sock_put(sk); } @@ -1259,8 +1271,8 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) switch (cmd) { case TIOCOUTQ: { - int amount = sk->sk_sndbuf - - atomic_read(&sk->sk_wmem_alloc); + int amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk); + if (amount < 0) amount = 0; rc = put_user(amount, (unsigned int __user *)argp); diff --git a/net/x25/x25_proc.c b/net/x25/x25_proc.c index 1afa44d25beb..0a04e62e0e18 100644 --- a/net/x25/x25_proc.c +++ b/net/x25/x25_proc.c @@ -163,8 +163,8 @@ static int x25_seq_socket_show(struct seq_file *seq, void *v) devname, x25->lci & 0x0FFF, x25->state, x25->vs, x25->vr, x25->va, x25_display_timer(s) / HZ, x25->t2 / HZ, x25->t21 / HZ, x25->t22 / HZ, x25->t23 / HZ, - atomic_read(&s->sk_wmem_alloc), - atomic_read(&s->sk_rmem_alloc), + sk_wmem_alloc_get(s), + sk_rmem_alloc_get(s), s->sk_socket ? SOCK_INODE(s->sk_socket)->i_ino : 0L); out: return 0; diff --git a/net/x25/x25_timer.c b/net/x25/x25_timer.c index d3e3e54db936..5c5db1a36399 100644 --- a/net/x25/x25_timer.c +++ b/net/x25/x25_timer.c @@ -113,7 +113,7 @@ static void x25_heartbeat_expiry(unsigned long param) (sk->sk_state == TCP_LISTEN && sock_flag(sk, SOCK_DEAD))) { bh_unlock_sock(sk); - x25_destroy_socket(sk); + x25_destroy_socket_from_timer(sk); return; } break; diff --git a/net/xfrm/xfrm_algo.c b/net/xfrm/xfrm_algo.c index 96036cf2216d..d31ccb487730 100644 --- a/net/xfrm/xfrm_algo.c +++ b/net/xfrm/xfrm_algo.c @@ -696,8 +696,9 @@ int skb_icv_walk(const struct sk_buff *skb, struct hash_desc *desc, { int start = skb_headlen(skb); int i, copy = start - offset; - int err; + struct sk_buff *frag_iter; struct scatterlist sg; + int err; /* Checksum header. */ if (copy > 0) { @@ -742,28 +743,24 @@ int skb_icv_walk(const struct sk_buff *skb, struct hash_desc *desc, start = end; } - if (skb_shinfo(skb)->frag_list) { - struct sk_buff *list = skb_shinfo(skb)->frag_list; + skb_walk_frags(skb, frag_iter) { + int end; - for (; list; list = list->next) { - int end; + WARN_ON(start > offset + len); - WARN_ON(start > offset + len); - - end = start + list->len; - if ((copy = end - offset) > 0) { - if (copy > len) - copy = len; - err = skb_icv_walk(list, desc, offset-start, - copy, icv_update); - if (unlikely(err)) - return err; - if ((len -= copy) == 0) - return 0; - offset += copy; - } - start = end; + end = start + frag_iter->len; + if ((copy = end - offset) > 0) { + if (copy > len) + copy = len; + err = skb_icv_walk(frag_iter, desc, offset-start, + copy, icv_update); + if (unlikely(err)) + return err; + if ((len -= copy) == 0) + return 0; + offset += copy; } + start = end; } BUG_ON(len); return 0; diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c index b4a13178fb40..e0009c17d809 100644 --- a/net/xfrm/xfrm_input.c +++ b/net/xfrm/xfrm_input.c @@ -251,8 +251,7 @@ resume: nf_reset(skb); if (decaps) { - dst_release(skb->dst); - skb->dst = NULL; + skb_dst_drop(skb); netif_rx(skb); return 0; } else { diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c index c235597ba8dd..b9fe13138c07 100644 --- a/net/xfrm/xfrm_output.c +++ b/net/xfrm/xfrm_output.c @@ -22,7 +22,7 @@ static int xfrm_output2(struct sk_buff *skb); static int xfrm_state_check_space(struct xfrm_state *x, struct sk_buff *skb) { - struct dst_entry *dst = skb->dst; + struct dst_entry *dst = skb_dst(skb); int nhead = dst->header_len + LL_RESERVED_SPACE(dst->dev) - skb_headroom(skb); int ntail = dst->dev->needed_tailroom - skb_tailroom(skb); @@ -39,7 +39,7 @@ static int xfrm_state_check_space(struct xfrm_state *x, struct sk_buff *skb) static int xfrm_output_one(struct sk_buff *skb, int err) { - struct dst_entry *dst = skb->dst; + struct dst_entry *dst = skb_dst(skb); struct xfrm_state *x = dst->xfrm; struct net *net = xs_net(x); @@ -94,12 +94,13 @@ resume: goto error_nolock; } - if (!(skb->dst = dst_pop(dst))) { + dst = dst_pop(dst); + if (!dst) { XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR); err = -EHOSTUNREACH; goto error_nolock; } - dst = skb->dst; + skb_dst_set(skb, dst); x = dst->xfrm; } while (x && !(x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL)); @@ -119,16 +120,16 @@ int xfrm_output_resume(struct sk_buff *skb, int err) while (likely((err = xfrm_output_one(skb, err)) == 0)) { nf_reset(skb); - err = skb->dst->ops->local_out(skb); + err = skb_dst(skb)->ops->local_out(skb); if (unlikely(err != 1)) goto out; - if (!skb->dst->xfrm) + if (!skb_dst(skb)->xfrm) return dst_output(skb); - err = nf_hook(skb->dst->ops->family, + err = nf_hook(skb_dst(skb)->ops->family, NF_INET_POST_ROUTING, skb, - NULL, skb->dst->dev, xfrm_output2); + NULL, skb_dst(skb)->dev, xfrm_output2); if (unlikely(err != 1)) goto out; } @@ -179,7 +180,7 @@ static int xfrm_output_gso(struct sk_buff *skb) int xfrm_output(struct sk_buff *skb) { - struct net *net = dev_net(skb->dst->dev); + struct net *net = dev_net(skb_dst(skb)->dev); int err; if (skb_is_gso(skb)) @@ -202,7 +203,7 @@ int xfrm_inner_extract_output(struct xfrm_state *x, struct sk_buff *skb) struct xfrm_mode *inner_mode; if (x->sel.family == AF_UNSPEC) inner_mode = xfrm_ip2inner_mode(x, - xfrm_af2proto(skb->dst->ops->family)); + xfrm_af2proto(skb_dst(skb)->ops->family)); else inner_mode = x->inner_mode; diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 9c068ab3a834..cb81ca35b0d6 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -2027,6 +2027,8 @@ int __xfrm_route_forward(struct sk_buff *skb, unsigned short family) { struct net *net = dev_net(skb->dev); struct flowi fl; + struct dst_entry *dst; + int res; if (xfrm_decode_session(skb, &fl, family) < 0) { /* XXX: we should have something like FWDHDRERROR here. */ @@ -2034,7 +2036,11 @@ int __xfrm_route_forward(struct sk_buff *skb, unsigned short family) return 0; } - return xfrm_lookup(net, &skb->dst, &fl, NULL, 0) == 0; + dst = skb_dst(skb); + + res = xfrm_lookup(net, &dst, &fl, NULL, 0) == 0; + skb_dst_set(skb, dst); + return res; } EXPORT_SYMBOL(__xfrm_route_forward); diff --git a/samples/Kconfig b/samples/Kconfig index 4b02f5a0e656..428b065ba695 100644 --- a/samples/Kconfig +++ b/samples/Kconfig @@ -19,8 +19,15 @@ config SAMPLE_TRACEPOINTS help This build tracepoints example modules. +config SAMPLE_TRACE_EVENTS + tristate "Build trace_events examples -- loadable modules only" + depends on EVENT_TRACING && m + help + This build trace event example modules. + config SAMPLE_KOBJECT - tristate "Build kobject examples" + tristate "Build kobject examples -- loadable modules only" + depends on m help This config option will allow you to build a number of different kobject sample modules showing how to use kobjects, diff --git a/samples/Makefile b/samples/Makefile index 10eaca89fe17..13e4b470b539 100644 --- a/samples/Makefile +++ b/samples/Makefile @@ -1,3 +1,3 @@ # Makefile for Linux samples code -obj-$(CONFIG_SAMPLES) += markers/ kobject/ kprobes/ tracepoints/ +obj-$(CONFIG_SAMPLES) += markers/ kobject/ kprobes/ tracepoints/ trace_events/ diff --git a/samples/firmware_class/firmware_sample_driver.c b/samples/firmware_class/firmware_sample_driver.c deleted file mode 100644 index 219a29896603..000000000000 --- a/samples/firmware_class/firmware_sample_driver.c +++ /dev/null @@ -1,121 +0,0 @@ -/* - * firmware_sample_driver.c - - * - * Copyright (c) 2003 Manuel Estrada Sainz - * - * Sample code on how to use request_firmware() from drivers. - * - */ - -#include -#include -#include -#include -#include -#include - -static struct device ghost_device = { - .bus_id = "ghost0", -}; - - -static void sample_firmware_load(char *firmware, int size) -{ - u8 buf[size+1]; - memcpy(buf, firmware, size); - buf[size] = '\0'; - printk(KERN_INFO "firmware_sample_driver: firmware: %s\n", buf); -} - -static void sample_probe_default(void) -{ - /* uses the default method to get the firmware */ - const struct firmware *fw_entry; - int retval; - - printk(KERN_INFO "firmware_sample_driver: " - "a ghost device got inserted :)\n"); - - retval = request_firmware(&fw_entry, "sample_driver_fw", &ghost_device); - if (retval) { - printk(KERN_ERR - "firmware_sample_driver: Firmware not available\n"); - return; - } - - sample_firmware_load(fw_entry->data, fw_entry->size); - - release_firmware(fw_entry); - - /* finish setting up the device */ -} - -static void sample_probe_specific(void) -{ - int retval; - /* Uses some specific hotplug support to get the firmware from - * userspace directly into the hardware, or via some sysfs file */ - - /* NOTE: This currently doesn't work */ - - printk(KERN_INFO "firmware_sample_driver: " - "a ghost device got inserted :)\n"); - - retval = request_firmware(NULL, "sample_driver_fw", &ghost_device); - if (retval) { - printk(KERN_ERR - "firmware_sample_driver: Firmware load failed\n"); - return; - } - - /* request_firmware blocks until userspace finished, so at - * this point the firmware should be already in the device */ - - /* finish setting up the device */ -} - -static void sample_probe_async_cont(const struct firmware *fw, void *context) -{ - if (!fw) { - printk(KERN_ERR - "firmware_sample_driver: firmware load failed\n"); - return; - } - - printk(KERN_INFO "firmware_sample_driver: device pointer \"%s\"\n", - (char *)context); - sample_firmware_load(fw->data, fw->size); -} - -static void sample_probe_async(void) -{ - /* Let's say that I can't sleep */ - int error; - error = request_firmware_nowait(THIS_MODULE, FW_ACTION_NOHOTPLUG, - "sample_driver_fw", &ghost_device, - "my device pointer", - sample_probe_async_cont); - if (error) - printk(KERN_ERR "firmware_sample_driver:" - " request_firmware_nowait failed\n"); -} - -static int __init sample_init(void) -{ - device_initialize(&ghost_device); - /* since there is no real hardware insertion I just call the - * sample probe functions here */ - sample_probe_specific(); - sample_probe_default(); - sample_probe_async(); - return 0; -} - -static void __exit sample_exit(void) -{ -} - -module_init(sample_init); -module_exit(sample_exit); - -MODULE_LICENSE("GPL"); diff --git a/samples/firmware_class/firmware_sample_firmware_class.c b/samples/firmware_class/firmware_sample_firmware_class.c deleted file mode 100644 index e6cf7a43a297..000000000000 --- a/samples/firmware_class/firmware_sample_firmware_class.c +++ /dev/null @@ -1,204 +0,0 @@ -/* - * firmware_sample_firmware_class.c - - * - * Copyright (c) 2003 Manuel Estrada Sainz - * - * NOTE: This is just a probe of concept, if you think that your driver would - * be well served by this mechanism please contact me first. - * - * DON'T USE THIS CODE AS IS - * - */ - -#include -#include -#include -#include -#include -#include -#include - - -MODULE_AUTHOR("Manuel Estrada Sainz"); -MODULE_DESCRIPTION("Hackish sample for using firmware class directly"); -MODULE_LICENSE("GPL"); - -static inline struct class_device *to_class_dev(struct kobject *obj) -{ - return container_of(obj, struct class_device, kobj); -} - -static inline -struct class_device_attribute *to_class_dev_attr(struct attribute *_attr) -{ - return container_of(_attr, struct class_device_attribute, attr); -} - -struct firmware_priv { - char fw_id[FIRMWARE_NAME_MAX]; - s32 loading:2; - u32 abort:1; -}; - -static ssize_t firmware_loading_show(struct class_device *class_dev, char *buf) -{ - struct firmware_priv *fw_priv = class_get_devdata(class_dev); - return sprintf(buf, "%d\n", fw_priv->loading); -} - -static ssize_t firmware_loading_store(struct class_device *class_dev, - const char *buf, size_t count) -{ - struct firmware_priv *fw_priv = class_get_devdata(class_dev); - int prev_loading = fw_priv->loading; - - fw_priv->loading = simple_strtol(buf, NULL, 10); - - switch (fw_priv->loading) { - case -1: - /* abort load an panic */ - break; - case 1: - /* setup load */ - break; - case 0: - if (prev_loading == 1) { - /* finish load and get the device back to working - * state */ - } - break; - } - - return count; -} -static CLASS_DEVICE_ATTR(loading, 0644, - firmware_loading_show, firmware_loading_store); - -static ssize_t firmware_data_read(struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buffer, loff_t offset, size_t count) -{ - struct class_device *class_dev = to_class_dev(kobj); - struct firmware_priv *fw_priv = class_get_devdata(class_dev); - - /* read from the devices firmware memory */ - - return count; -} -static ssize_t firmware_data_write(struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buffer, loff_t offset, size_t count) -{ - struct class_device *class_dev = to_class_dev(kobj); - struct firmware_priv *fw_priv = class_get_devdata(class_dev); - - /* write to the devices firmware memory */ - - return count; -} -static struct bin_attribute firmware_attr_data = { - .attr = {.name = "data", .mode = 0644}, - .size = 0, - .read = firmware_data_read, - .write = firmware_data_write, -}; -static int fw_setup_class_device(struct class_device *class_dev, - const char *fw_name, - struct device *device) -{ - int retval; - struct firmware_priv *fw_priv; - - fw_priv = kzalloc(sizeof(struct firmware_priv), GFP_KERNEL); - if (!fw_priv) { - retval = -ENOMEM; - goto out; - } - - memset(class_dev, 0, sizeof(*class_dev)); - - strncpy(fw_priv->fw_id, fw_name, FIRMWARE_NAME_MAX); - fw_priv->fw_id[FIRMWARE_NAME_MAX-1] = '\0'; - - strncpy(class_dev->class_id, device->bus_id, BUS_ID_SIZE); - class_dev->class_id[BUS_ID_SIZE-1] = '\0'; - class_dev->dev = device; - - class_dev->class = &firmware_class; - class_set_devdata(class_dev, fw_priv); - retval = class_device_register(class_dev); - if (retval) { - printk(KERN_ERR "%s: class_device_register failed\n", - __func__); - goto error_free_fw_priv; - } - - retval = sysfs_create_bin_file(&class_dev->kobj, &firmware_attr_data); - if (retval) { - printk(KERN_ERR "%s: sysfs_create_bin_file failed\n", - __func__); - goto error_unreg_class_dev; - } - - retval = class_device_create_file(class_dev, - &class_device_attr_loading); - if (retval) { - printk(KERN_ERR "%s: class_device_create_file failed\n", - __func__); - goto error_remove_data; - } - - goto out; - -error_remove_data: - sysfs_remove_bin_file(&class_dev->kobj, &firmware_attr_data); -error_unreg_class_dev: - class_device_unregister(class_dev); -error_free_fw_priv: - kfree(fw_priv); -out: - return retval; -} -static void fw_remove_class_device(struct class_device *class_dev) -{ - struct firmware_priv *fw_priv = class_get_devdata(class_dev); - - class_device_remove_file(class_dev, &class_device_attr_loading); - sysfs_remove_bin_file(&class_dev->kobj, &firmware_attr_data); - class_device_unregister(class_dev); -} - -static struct class_device *class_dev; - -static struct device my_device = { - .bus_id = "my_dev0", -}; - -static int __init firmware_sample_init(void) -{ - int error; - - device_initialize(&my_device); - class_dev = kmalloc(sizeof(struct class_device), GFP_KERNEL); - if (!class_dev) - return -ENOMEM; - - error = fw_setup_class_device(class_dev, "my_firmware_image", - &my_device); - if (error) { - kfree(class_dev); - return error; - } - return 0; - -} -static void __exit firmware_sample_exit(void) -{ - struct firmware_priv *fw_priv = class_get_devdata(class_dev); - fw_remove_class_device(class_dev); - kfree(fw_priv); - kfree(class_dev); -} - -module_init(firmware_sample_init); -module_exit(firmware_sample_exit); diff --git a/samples/trace_events/Makefile b/samples/trace_events/Makefile new file mode 100644 index 000000000000..0f8d92120c4e --- /dev/null +++ b/samples/trace_events/Makefile @@ -0,0 +1,14 @@ +# builds the trace events example kernel modules; +# then to use one (as root): insmod + +# If you include a trace header outside of include/trace/events +# then the file that does the #define CREATE_TRACE_POINTS must +# have that tracer file in its main search path. This is because +# define_trace.h will include it, and must be able to find it from +# the include/trace directory. +# +# Here trace-events-sample.c does the CREATE_TRACE_POINTS. +# +CFLAGS_trace-events-sample.o := -I$(src) + +obj-$(CONFIG_SAMPLE_TRACE_EVENTS) += trace-events-sample.o diff --git a/samples/trace_events/trace-events-sample.c b/samples/trace_events/trace-events-sample.c new file mode 100644 index 000000000000..aabc4e970911 --- /dev/null +++ b/samples/trace_events/trace-events-sample.c @@ -0,0 +1,52 @@ +#include +#include + +/* + * Any file that uses trace points, must include the header. + * But only one file, must include the header by defining + * CREATE_TRACE_POINTS first. This will make the C code that + * creates the handles for the trace points. + */ +#define CREATE_TRACE_POINTS +#include "trace-events-sample.h" + + +static void simple_thread_func(int cnt) +{ + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ); + trace_foo_bar("hello", cnt); +} + +static int simple_thread(void *arg) +{ + int cnt = 0; + + while (!kthread_should_stop()) + simple_thread_func(cnt++); + + return 0; +} + +static struct task_struct *simple_tsk; + +static int __init trace_event_init(void) +{ + simple_tsk = kthread_run(simple_thread, NULL, "event-sample"); + if (IS_ERR(simple_tsk)) + return -1; + + return 0; +} + +static void __exit trace_event_exit(void) +{ + kthread_stop(simple_tsk); +} + +module_init(trace_event_init); +module_exit(trace_event_exit); + +MODULE_AUTHOR("Steven Rostedt"); +MODULE_DESCRIPTION("trace-events-sample"); +MODULE_LICENSE("GPL"); diff --git a/samples/trace_events/trace-events-sample.h b/samples/trace_events/trace-events-sample.h new file mode 100644 index 000000000000..9977a756fb32 --- /dev/null +++ b/samples/trace_events/trace-events-sample.h @@ -0,0 +1,134 @@ +/* + * Notice that this file is not protected like a normal header. + * We also must allow for rereading of this file. The + * + * || defined(TRACE_HEADER_MULTI_READ) + * + * serves this purpose. + */ +#if !defined(_TRACE_EVENT_SAMPLE_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_EVENT_SAMPLE_H + +/* + * All trace headers should include tracepoint.h, until we finally + * make it into a standard header. + */ +#include + +/* + * If TRACE_SYSTEM is defined, that will be the directory created + * in the ftrace directory under /debugfs/tracing/events/ + * + * The define_trace.h below will also look for a file name of + * TRACE_SYSTEM.h where TRACE_SYSTEM is what is defined here. + * In this case, it would look for sample.h + * + * If the header name will be different than the system name + * (as in this case), then you can override the header name that + * define_trace.h will look up by defining TRACE_INCLUDE_FILE + * + * This file is called trace-events-sample.h but we want the system + * to be called "sample". Therefore we must define the name of this + * file: + * + * #define TRACE_INCLUDE_FILE trace-events-sample + * + * As we do an the bottom of this file. + */ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM sample + +/* + * The TRACE_EVENT macro is broken up into 5 parts. + * + * name: name of the trace point. This is also how to enable the tracepoint. + * A function called trace_foo_bar() will be created. + * + * proto: the prototype of the function trace_foo_bar() + * Here it is trace_foo_bar(char *foo, int bar). + * + * args: must match the arguments in the prototype. + * Here it is simply "foo, bar". + * + * struct: This defines the way the data will be stored in the ring buffer. + * There are currently two types of elements. __field and __array. + * a __field is broken up into (type, name). Where type can be any + * type but an array. + * For an array. there are three fields. (type, name, size). The + * type of elements in the array, the name of the field and the size + * of the array. + * + * __array( char, foo, 10) is the same as saying char foo[10]. + * + * fast_assign: This is a C like function that is used to store the items + * into the ring buffer. + * + * printk: This is a way to print out the data in pretty print. This is + * useful if the system crashes and you are logging via a serial line, + * the data can be printed to the console using this "printk" method. + * + * Note, that for both the assign and the printk, __entry is the handler + * to the data structure in the ring buffer, and is defined by the + * TP_STRUCT__entry. + */ +TRACE_EVENT(foo_bar, + + TP_PROTO(char *foo, int bar), + + TP_ARGS(foo, bar), + + TP_STRUCT__entry( + __array( char, foo, 10 ) + __field( int, bar ) + ), + + TP_fast_assign( + strncpy(__entry->foo, foo, 10); + __entry->bar = bar; + ), + + TP_printk("foo %s %d", __entry->foo, __entry->bar) +); +#endif + +/***** NOTICE! The #if protection ends here. *****/ + + +/* + * There are several ways I could have done this. If I left out the + * TRACE_INCLUDE_PATH, then it would default to the kernel source + * include/trace/events directory. + * + * I could specify a path from the define_trace.h file back to this + * file. + * + * #define TRACE_INCLUDE_PATH ../../samples/trace_events + * + * But the safest and easiest way to simply make it use the directory + * that the file is in is to add in the Makefile: + * + * CFLAGS_trace-events-sample.o := -I$(src) + * + * This will make sure the current path is part of the include + * structure for our file so that define_trace.h can find it. + * + * I could have made only the top level directory the include: + * + * CFLAGS_trace-events-sample.o := -I$(PWD) + * + * And then let the path to this directory be the TRACE_INCLUDE_PATH: + * + * #define TRACE_INCLUDE_PATH samples/trace_events + * + * But then if something defines "samples" or "trace_events" as a macro + * then we could risk that being converted too, and give us an unexpected + * result. + */ +#undef TRACE_INCLUDE_PATH +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_PATH . +/* + * TRACE_INCLUDE_FILE is not needed if the filename and TRACE_SYSTEM are equal + */ +#define TRACE_INCLUDE_FILE trace-events-sample +#include diff --git a/scripts/Makefile.headersinst b/scripts/Makefile.headersinst index 095cfc8b9dbf..0fcd83838771 100644 --- a/scripts/Makefile.headersinst +++ b/scripts/Makefile.headersinst @@ -54,8 +54,12 @@ quiet_cmd_remove = REMOVE $(unwanted) cmd_remove = rm -f $(unwanted-file) quiet_cmd_check = CHECK $(printdir) ($(words $(all-files)) files) - cmd_check = $(PERL) $< $(INSTALL_HDR_PATH)/include $(SRCARCH) \ - $(addprefix $(install)/, $(all-files)); \ +# Headers list can be pretty long, xargs helps to avoid +# the "Argument list too long" error. + cmd_check = for f in $(all-files); do \ + echo "$(install)/$${f}"; done \ + | xargs \ + $(PERL) $< $(INSTALL_HDR_PATH)/include $(SRCARCH); \ touch $@ PHONY += __headersinst __headerscheck diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index cba61ca403ca..7a7778746ea6 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -116,6 +116,17 @@ _a_flags = $(KBUILD_CPPFLAGS) $(KBUILD_AFLAGS) $(KBUILD_SUBDIR_ASFLAGS) \ $(asflags-y) $(AFLAGS_$(basetarget).o) _cpp_flags = $(KBUILD_CPPFLAGS) $(cppflags-y) $(CPPFLAGS_$(@F)) +# +# Enable gcov profiling flags for a file, directory or for all files depending +# on variables GCOV_PROFILE_obj.o, GCOV_PROFILE and CONFIG_GCOV_PROFILE_ALL +# (in this order) +# +ifeq ($(CONFIG_GCOV_KERNEL),y) +_c_flags += $(if $(patsubst n%,, \ + $(GCOV_PROFILE_$(basetarget).o)$(GCOV_PROFILE)$(CONFIG_GCOV_PROFILE_ALL)), \ + $(CFLAGS_GCOV)) +endif + # If building the kernel in a separate objtree expand all occurrences # of -Idir to -I$(srctree)/dir except for absolute paths (starting with '/'). @@ -188,20 +199,34 @@ cmd_objcopy = $(OBJCOPY) $(OBJCOPYFLAGS) $(OBJCOPYFLAGS_$(@F)) $< $@ # --------------------------------------------------------------------------- quiet_cmd_gzip = GZIP $@ -cmd_gzip = gzip -f -9 < $< > $@ +cmd_gzip = (cat $(filter-out FORCE,$^) | gzip -f -9 > $@) || \ + (rm -f $@ ; false) # Bzip2 # --------------------------------------------------------------------------- -# Bzip2 does not include size in file... so we have to fake that -size_append=$(CONFIG_SHELL) $(srctree)/scripts/bin_size +# Bzip2 and LZMA do not include size in file... so we have to fake that; +# append the size as a 32-bit littleendian number as gzip does. +size_append = echo -ne $(shell \ +dec_size=0; \ +for F in $1; do \ + fsize=$$(stat -c "%s" $$F); \ + dec_size=$$(expr $$dec_size + $$fsize); \ +done; \ +printf "%08x" $$dec_size | \ + sed 's/\(..\)\(..\)\(..\)\(..\)/\\\\x\4\\\\x\3\\\\x\2\\\\x\1/g' \ +) -quiet_cmd_bzip2 = BZIP2 $@ -cmd_bzip2 = (bzip2 -9 < $< && $(size_append) $<) > $@ || (rm -f $@ ; false) +quiet_cmd_bzip2 = BZIP2 $@ +cmd_bzip2 = (cat $(filter-out FORCE,$^) | \ + bzip2 -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \ + (rm -f $@ ; false) # Lzma # --------------------------------------------------------------------------- quiet_cmd_lzma = LZMA $@ -cmd_lzma = (lzma -9 -c $< && $(size_append) $<) >$@ || (rm -f $@ ; false) +cmd_lzma = (cat $(filter-out FORCE,$^) | \ + lzma -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \ + (rm -f $@ ; false) diff --git a/scripts/basic/docproc.c b/scripts/basic/docproc.c index 35bdc68b6e66..99ca7a698687 100644 --- a/scripts/basic/docproc.c +++ b/scripts/basic/docproc.c @@ -69,7 +69,7 @@ FILELINE * docsection; #define NOFUNCTION "-nofunction" #define NODOCSECTIONS "-no-doc-sections" -char *srctree; +static char *srctree, *kernsrctree; void usage (void) { @@ -77,7 +77,8 @@ void usage (void) fprintf(stderr, "Input is read from file.tmpl. Output is sent to stdout\n"); fprintf(stderr, "doc: frontend when generating kernel documentation\n"); fprintf(stderr, "depend: generate list of files referenced within file\n"); - fprintf(stderr, "Environment variable SRCTREE: absolute path to kernel source tree.\n"); + fprintf(stderr, "Environment variable SRCTREE: absolute path to sources.\n"); + fprintf(stderr, " KBUILD_SRC: absolute path to kernel source tree.\n"); } /* @@ -96,8 +97,8 @@ void exec_kernel_doc(char **svec) exit(1); case 0: memset(real_filename, 0, sizeof(real_filename)); - strncat(real_filename, srctree, PATH_MAX); - strncat(real_filename, KERNELDOCPATH KERNELDOC, + strncat(real_filename, kernsrctree, PATH_MAX); + strncat(real_filename, "/" KERNELDOCPATH KERNELDOC, PATH_MAX - strlen(real_filename)); execvp(real_filename, svec); fprintf(stderr, "exec "); @@ -178,6 +179,7 @@ void find_export_symbols(char * filename) char real_filename[PATH_MAX + 1]; memset(real_filename, 0, sizeof(real_filename)); strncat(real_filename, srctree, PATH_MAX); + strncat(real_filename, "/", PATH_MAX - strlen(real_filename)); strncat(real_filename, filename, PATH_MAX - strlen(real_filename)); sym = add_new_file(filename); @@ -382,6 +384,9 @@ int main(int argc, char *argv[]) srctree = getenv("SRCTREE"); if (!srctree) srctree = getcwd(NULL, 0); + kernsrctree = getenv("KBUILD_SRC"); + if (!kernsrctree || !*kernsrctree) + kernsrctree = srctree; if (argc != 3) { usage(); exit(1); diff --git a/scripts/basic/fixdep.c b/scripts/basic/fixdep.c index 8912c0f5460b..72c15205bb2b 100644 --- a/scripts/basic/fixdep.c +++ b/scripts/basic/fixdep.c @@ -373,10 +373,11 @@ void print_deps(void) void traps(void) { static char test[] __attribute__((aligned(sizeof(int)))) = "CONF"; + int *p = (int *)test; - if (*(int *)test != INT_CONF) { + if (*p != INT_CONF) { fprintf(stderr, "fixdep: sizeof(int) != 4 or wrong endianess? %#x\n", - *(int *)test); + *p); exit(2); } } diff --git a/scripts/bin_size b/scripts/bin_size deleted file mode 100644 index 43e1b360cee6..000000000000 --- a/scripts/bin_size +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh - -if [ $# = 0 ] ; then - echo Usage: $0 file -fi - -size_dec=`stat -c "%s" $1` -size_hex_echo_string=`printf "%08x" $size_dec | - sed 's/\(..\)\(..\)\(..\)\(..\)/\\\\x\4\\\\x\3\\\\x\2\\\\x\1/g'` -/bin/echo -ne $size_hex_echo_string diff --git a/scripts/checksyscalls.sh b/scripts/checksyscalls.sh index 60d00d1c4eee..66ad375612f2 100755 --- a/scripts/checksyscalls.sh +++ b/scripts/checksyscalls.sh @@ -14,6 +14,57 @@ cat << EOF #include #include +/* *at */ +#define __IGNORE_open /* openat */ +#define __IGNORE_link /* linkat */ +#define __IGNORE_unlink /* unlinkat */ +#define __IGNORE_mknod /* mknodat */ +#define __IGNORE_chmod /* fchmodat */ +#define __IGNORE_chown /* fchownat */ +#define __IGNORE_mkdir /* mkdirat */ +#define __IGNORE_rmdir /* unlinkat */ +#define __IGNORE_lchown /* fchownat */ +#define __IGNORE_access /* faccessat */ +#define __IGNORE_rename /* renameat */ +#define __IGNORE_readlink /* readlinkat */ +#define __IGNORE_symlink /* symlinkat */ +#define __IGNORE_utimes /* futimesat */ +#if BITS_PER_LONG == 64 +#define __IGNORE_stat /* fstatat */ +#define __IGNORE_lstat /* fstatat */ +#else +#define __IGNORE_stat64 /* fstatat64 */ +#define __IGNORE_lstat64 /* fstatat64 */ +#endif + +/* CLOEXEC flag */ +#define __IGNORE_pipe /* pipe2 */ +#define __IGNORE_dup2 /* dup3 */ +#define __IGNORE_epoll_create /* epoll_create1 */ +#define __IGNORE_inotify_init /* inotify_init1 */ +#define __IGNORE_eventfd /* eventfd2 */ +#define __IGNORE_signalfd /* signalfd4 */ + +/* MMU */ +#ifndef CONFIG_MMU +#define __IGNORE_madvise +#define __IGNORE_mbind +#define __IGNORE_mincore +#define __IGNORE_mlock +#define __IGNORE_mlockall +#define __IGNORE_munlock +#define __IGNORE_munlockall +#define __IGNORE_mprotect +#define __IGNORE_msync +#define __IGNORE_migrate_pages +#define __IGNORE_move_pages +#define __IGNORE_remap_file_pages +#define __IGNORE_get_mempolicy +#define __IGNORE_set_mempolicy +#define __IGNORE_swapoff +#define __IGNORE_swapon +#endif + /* System calls for 32-bit kernels only */ #if BITS_PER_LONG == 64 #define __IGNORE_sendfile64 @@ -27,6 +78,22 @@ cat << EOF #define __IGNORE_fstatat64 #define __IGNORE_fstatfs64 #define __IGNORE_statfs64 +#define __IGNORE_llseek +#define __IGNORE_mmap2 +#else +#define __IGNORE_sendfile +#define __IGNORE_ftruncate +#define __IGNORE_truncate +#define __IGNORE_stat +#define __IGNORE_lstat +#define __IGNORE_fstat +#define __IGNORE_fcntl +#define __IGNORE_fadvise64 +#define __IGNORE_newfstatat +#define __IGNORE_fstatfs +#define __IGNORE_statfs +#define __IGNORE_lseek +#define __IGNORE_mmap #endif /* i386-specific or historical system calls */ @@ -44,7 +111,6 @@ cat << EOF #define __IGNORE_idle #define __IGNORE_modify_ldt #define __IGNORE_ugetrlimit -#define __IGNORE_mmap2 #define __IGNORE_vm86 #define __IGNORE_vm86old #define __IGNORE_set_thread_area @@ -55,7 +121,6 @@ cat << EOF #define __IGNORE_oldlstat #define __IGNORE_oldolduname #define __IGNORE_olduname -#define __IGNORE_umount2 #define __IGNORE_umount #define __IGNORE_waitpid #define __IGNORE_stime @@ -75,9 +140,12 @@ cat << EOF #define __IGNORE__llseek #define __IGNORE__newselect #define __IGNORE_create_module -#define __IGNORE_delete_module #define __IGNORE_query_module #define __IGNORE_get_kernel_syms +#define __IGNORE_sysfs +#define __IGNORE_uselib +#define __IGNORE__sysctl + /* ... including the "new" 32-bit uid syscalls */ #define __IGNORE_lchown32 #define __IGNORE_getuid32 @@ -99,6 +167,24 @@ cat << EOF #define __IGNORE_setfsuid32 #define __IGNORE_setfsgid32 +/* these can be expressed using other calls */ +#define __IGNORE_alarm /* setitimer */ +#define __IGNORE_creat /* open */ +#define __IGNORE_fork /* clone */ +#define __IGNORE_futimesat /* utimensat */ +#define __IGNORE_getpgrp /* getpgid */ +#define __IGNORE_getdents /* getdents64 */ +#define __IGNORE_pause /* sigsuspend */ +#define __IGNORE_poll /* ppoll */ +#define __IGNORE_select /* pselect6 */ +#define __IGNORE_epoll_wait /* epoll_pwait */ +#define __IGNORE_time /* gettimeofday */ +#define __IGNORE_uname /* newuname */ +#define __IGNORE_ustat /* statfs */ +#define __IGNORE_utime /* utimes */ +#define __IGNORE_vfork /* clone */ +#define __IGNORE_wait4 /* waitid */ + /* sync_file_range had a stupid ABI. Allow sync_file_range2 instead */ #ifdef __NR_sync_file_range2 #define __IGNORE_sync_file_range diff --git a/scripts/config b/scripts/config index db6084b78a10..608d7fdb13e8 100755 --- a/scripts/config +++ b/scripts/config @@ -9,8 +9,10 @@ config options command ... commands: --enable|-e option Enable option --disable|-d option Disable option - --module|-m option Turn option into a module - --state|-s option Print state of option (n,y,m,undef) + --module|-m option Turn option into a module + --set-str option value + Set option to "value" + --state|-s option Print state of option (n,y,m,undef) --enable-after|-E beforeopt option Enable option directly after other option @@ -26,8 +28,6 @@ options: config doesn't check the validity of the .config file. This is done at next make time. -The options need to be already in the file before they can be changed, -but sometimes you can cheat with the --*-after options. EOL exit 1 } @@ -45,8 +45,18 @@ checkarg() { ARG="`echo $ARG | tr a-z A-Z`" } -replace() { - sed -i -e "$@" $FN +set_var() { + local name=$1 new=$2 before=$3 + + name_re="^($name=|# $name is not set)" + before_re="^($before=|# $before is not set)" + if test -n "$before" && grep -Eq "$before_re" "$FN"; then + sed -ri "/$before_re/a $new" "$FN" + elif grep -Eq "$name_re" "$FN"; then + sed -ri "s:$name_re.*:$new:" "$FN" + else + echo "$new" >>"$FN" + fi } if [ "$1" = "--file" ]; then @@ -54,8 +64,7 @@ if [ "$1" = "--file" ]; then if [ "$FN" = "" ] ; then usage fi - shift - shift + shift 2 else FN=.config fi @@ -68,27 +77,39 @@ while [ "$1" != "" ] ; do CMD="$1" shift case "$CMD" in - --enable|-e) + --refresh) + ;; + --*-after) + checkarg "$1" + A=$ARG + checkarg "$2" + B=$ARG + shift 2 + ;; + --*) checkarg "$1" - replace "s/# CONFIG_$ARG is not set/CONFIG_$ARG=y/" shift ;; + esac + case "$CMD" in + --enable|-e) + set_var "CONFIG_$ARG" "CONFIG_$ARG=y" + ;; --disable|-d) - checkarg "$1" - replace "s/CONFIG_$ARG=[my]/# CONFIG_$ARG is not set/" - shift + set_var "CONFIG_$ARG" "# CONFIG_$ARG is not set" ;; --module|-m) - checkarg "$1" - replace "s/CONFIG_$ARG=y/CONFIG_$ARG=m/" \ - -e "s/# CONFIG_$ARG is not set/CONFIG_$ARG=m/" + set_var "CONFIG_$ARG" "CONFIG_$ARG=m" + ;; + + --set-str) + set_var "CONFIG_$ARG" "CONFIG_$ARG=\"$1\"" shift ;; --state|-s) - checkarg "$1" if grep -q "# CONFIG_$ARG is not set" $FN ; then echo n else @@ -101,44 +122,18 @@ while [ "$1" != "" ] ; do echo "$V" fi fi - shift ;; --enable-after|-E) - checkarg "$1" - A=$ARG - checkarg "$2" - B=$ARG - replace "/CONFIG_$A=[my]/aCONFIG_$B=y" \ - -e "/# CONFIG_$ARG is not set/a/CONFIG_$ARG=y" \ - -e "s/# CONFIG_$ARG is not set/CONFIG_$ARG=y/" - shift - shift + set_var "CONFIG_$B" "CONFIG_$B=y" "CONFIG_$A" ;; --disable-after|-D) - checkarg "$1" - A=$ARG - checkarg "$2" - B=$ARG - replace "/CONFIG_$A=[my]/a# CONFIG_$B is not set" \ - -e "/# CONFIG_$ARG is not set/a/# CONFIG_$ARG is not set" \ - -e "s/CONFIG_$ARG=[my]/# CONFIG_$ARG is not set/" - shift - shift + set_var "CONFIG_$B" "# CONFIG_$B is not set" "CONFIG_$A" ;; --module-after|-M) - checkarg "$1" - A=$ARG - checkarg "$2" - B=$ARG - replace "/CONFIG_$A=[my]/aCONFIG_$B=m" \ - -e "/# CONFIG_$ARG is not set/a/CONFIG_$ARG=m" \ - -e "s/CONFIG_$ARG=y/CONFIG_$ARG=m/" \ - -e "s/# CONFIG_$ARG is not set/CONFIG_$ARG=m/" - shift - shift + set_var "CONFIG_$B" "CONFIG_$B=m" "CONFIG_$A" ;; # undocumented because it ignores --file (fixme) diff --git a/scripts/gcc-version.sh b/scripts/gcc-version.sh index cc767b388baf..debecb5561c4 100644 --- a/scripts/gcc-version.sh +++ b/scripts/gcc-version.sh @@ -18,7 +18,7 @@ compiler="$*" if [ ${#compiler} -eq 0 ]; then echo "Error: No compiler specified." - echo -e "Usage:\n\t$0 " + printf "Usage:\n\t$0 \n" exit 1 fi diff --git a/scripts/get_maintainer.pl b/scripts/get_maintainer.pl index 60dc0c48c929..3e733146cd51 100755 --- a/scripts/get_maintainer.pl +++ b/scripts/get_maintainer.pl @@ -13,7 +13,7 @@ use strict; my $P = $0; -my $V = '0.15'; +my $V = '0.16'; use Getopt::Long qw(:config no_auto_abbrev); @@ -55,6 +55,10 @@ foreach my $chief (@penguin_chief) { } my $penguin_chiefs = "\(" . join("|",@penguin_chief_names) . "\)"; +# rfc822 email address - preloaded methods go here. +my $rfc822_lwsp = "(?:(?:\\r\\n)?[ \\t])"; +my $rfc822_char = '[\\000-\\377]'; + if (!GetOptions( 'email!' => \$email, 'git!' => \$email_git, @@ -161,7 +165,7 @@ foreach my $file (@ARGV) { } close(PATCH); if ($file_cnt == @files) { - die "$P: file '${file}' doesn't appear to be a patch. " + warn "$P: file '${file}' doesn't appear to be a patch. " . "Add -f to options?\n"; } @files = sort_and_uniq(@files); @@ -169,6 +173,7 @@ foreach my $file (@ARGV) { } my @email_to = (); +my @list_to = (); my @scm = (); my @web = (); my @subsystem = (); @@ -182,7 +187,7 @@ foreach my $file (@files) { my $exclude = 0; foreach my $line (@typevalue) { - if ($line =~ m/^(\C):(.*)/) { + if ($line =~ m/^(\C):\s*(.*)/) { my $type = $1; my $value = $2; if ($type eq 'X') { @@ -196,7 +201,7 @@ foreach my $file (@files) { if (!$exclude) { my $tvi = 0; foreach my $line (@typevalue) { - if ($line =~ m/^(\C):(.*)/) { + if ($line =~ m/^(\C):\s*(.*)/) { my $type = $1; my $value = $2; if ($type eq 'F') { @@ -215,29 +220,33 @@ foreach my $file (@files) { } -if ($email_git_penguin_chiefs) { +if ($email) { foreach my $chief (@penguin_chief) { if ($chief =~ m/^(.*):(.*)/) { - my $chief_name = $1; - my $chief_addr = $2; + my $email_address; if ($email_usename) { - push(@email_to, format_email($chief_name, $chief_addr)); + $email_address = format_email($1, $2); } else { - push(@email_to, $chief_addr); + $email_address = $2; + } + if ($email_git_penguin_chiefs) { + push(@email_to, $email_address); + } else { + @email_to = grep(!/${email_address}/, @email_to); } } } } -if ($email) { - my $address_cnt = @email_to; - if ($address_cnt == 0 && $email_list) { - push(@email_to, "linux-kernel\@vger.kernel.org"); +if ($email || $email_list) { + my @to = (); + if ($email) { + @to = (@to, @email_to); } - -#Don't sort email address list, but do remove duplicates - @email_to = uniq(@email_to); - output(@email_to); + if ($email_list) { + @to = (@to, @list_to); + } + output(uniq(@to)); } if ($scm) { @@ -307,10 +316,10 @@ Output type options: --multiline => print 1 entry per line Default options: - [--email --git --m --l --multiline] + [--email --git --m --n --l --multiline] Other options: - --version -> show version + --version => show version --help => show this help information EOT @@ -347,6 +356,7 @@ sub format_email { my ($name, $email) = @_; $name =~ s/^\s+|\s+$//g; + $name =~ s/^\"|\"$//g; $email =~ s/^\s+|\s+$//g; my $formatted_email = ""; @@ -366,36 +376,41 @@ sub add_categories { $index = $index - 1; while ($index >= 0) { my $tv = $typevalue[$index]; - if ($tv =~ m/^(\C):(.*)/) { + if ($tv =~ m/^(\C):\s*(.*)/) { my $ptype = $1; my $pvalue = $2; if ($ptype eq "L") { - my $subscr = $pvalue; - if ($subscr =~ m/\s*\(subscribers-only\)/) { + my $list_address = $pvalue; + my $list_additional = ""; + if ($list_address =~ m/([^\s]+)\s+(.*)$/) { + $list_address = $1; + $list_additional = $2; + } + if ($list_additional =~ m/subscribers-only/) { if ($email_subscriber_list) { - $subscr =~ s/\s*\(subscribers-only\)//g; - push(@email_to, $subscr); + push(@list_to, $list_address); } } else { if ($email_list) { - push(@email_to, $pvalue); + push(@list_to, $list_address); } } } elsif ($ptype eq "M") { - if ($email_maintainer) { - if ($index >= 0) { - my $tv = $typevalue[$index - 1]; - if ($tv =~ m/^(\C):(.*)/) { - if ($1 eq "P" && $email_usename) { - push(@email_to, format_email($2, $pvalue)); - } else { - push(@email_to, $pvalue); + my $p_used = 0; + if ($index >= 0) { + my $tv = $typevalue[$index - 1]; + if ($tv =~ m/^(\C):\s*(.*)/) { + if ($1 eq "P") { + if ($email_usename) { + push_email_address(format_email($2, $pvalue)); + $p_used = 1; } } - } else { - push(@email_to, $pvalue); } } + if (!$p_used) { + push_email_addresses($pvalue); + } } elsif ($ptype eq "T") { push(@scm, $pvalue); } elsif ($ptype eq "W") { @@ -412,10 +427,45 @@ sub add_categories { } } +sub push_email_address { + my ($email_address) = @_; + + my $email_name = ""; + if ($email_address =~ m/([^<]+)<(.*\@.*)>$/) { + $email_name = $1; + $email_address = $2; + } + + if ($email_maintainer) { + if ($email_usename && $email_name) { + push(@email_to, format_email($email_name, $email_address)); + } else { + push(@email_to, $email_address); + } + } +} + +sub push_email_addresses { + my ($address) = @_; + + my @address_list = (); + + if (rfc822_valid($address)) { + push_email_address($address); + } elsif (@address_list = rfc822_validlist($address)) { + my $array_count = shift(@address_list); + while (my $entry = shift(@address_list)) { + push_email_address($entry); + } + } else { + warn("Invalid MAINTAINERS address: '" . $address . "'\n"); + } +} + sub which { my ($bin) = @_; - foreach my $path (split /:/, $ENV{PATH}) { + foreach my $path (split(/:/, $ENV{PATH})) { if (-e "$path/$bin") { return "$path/$bin"; } @@ -434,16 +484,21 @@ sub recent_git_signoffs { my @lines = (); if (which("git") eq "") { - die("$P: git not found. Add --nogit to options?\n"); + warn("$P: git not found. Add --nogit to options?\n"); + return; + } + if (!(-d ".git")) { + warn("$P: .git directory not found. Use a git repository for better results.\n"); + warn("$P: perhaps 'git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git'\n"); + return; } $cmd = "git log --since=${email_git_since} -- ${file}"; - $cmd .= " | grep -Pi \"^[-_ a-z]+by:.*\\\@\""; + $cmd .= " | grep -Ei \"^[-_ a-z]+by:.*\\\@.*\$\""; if (!$email_git_penguin_chiefs) { - $cmd .= " | grep -Pv \"${penguin_chiefs}\""; + $cmd .= " | grep -Ev \"${penguin_chiefs}\""; } $cmd .= " | cut -f2- -d\":\""; - $cmd .= " | sed -e \"s/^\\s+//g\""; $cmd .= " | sort | uniq -c | sort -rn"; $output = `${cmd}`; @@ -465,10 +520,6 @@ sub recent_git_signoffs { if ($line =~ m/(.+)<(.+)>/) { my $git_name = $1; my $git_addr = $2; - $git_name =~ tr/^\"//; - $git_name =~ tr/^\\s*//; - $git_name =~ tr/\"$//; - $git_name =~ tr/\\s*$//; if ($email_usename) { push(@email_to, format_email($git_name, $git_addr)); } else { @@ -481,7 +532,6 @@ sub recent_git_signoffs { push(@email_to, $line); } } - return $output; } sub uniq { @@ -513,3 +563,97 @@ sub output { print("\n"); } } + +my $rfc822re; + +sub make_rfc822re { +# Basic lexical tokens are specials, domain_literal, quoted_string, atom, and +# comment. We must allow for rfc822_lwsp (or comments) after each of these. +# This regexp will only work on addresses which have had comments stripped +# and replaced with rfc822_lwsp. + + my $specials = '()<>@,;:\\\\".\\[\\]'; + my $controls = '\\000-\\037\\177'; + + my $dtext = "[^\\[\\]\\r\\\\]"; + my $domain_literal = "\\[(?:$dtext|\\\\.)*\\]$rfc822_lwsp*"; + + my $quoted_string = "\"(?:[^\\\"\\r\\\\]|\\\\.|$rfc822_lwsp)*\"$rfc822_lwsp*"; + +# Use zero-width assertion to spot the limit of an atom. A simple +# $rfc822_lwsp* causes the regexp engine to hang occasionally. + my $atom = "[^$specials $controls]+(?:$rfc822_lwsp+|\\Z|(?=[\\[\"$specials]))"; + my $word = "(?:$atom|$quoted_string)"; + my $localpart = "$word(?:\\.$rfc822_lwsp*$word)*"; + + my $sub_domain = "(?:$atom|$domain_literal)"; + my $domain = "$sub_domain(?:\\.$rfc822_lwsp*$sub_domain)*"; + + my $addr_spec = "$localpart\@$rfc822_lwsp*$domain"; + + my $phrase = "$word*"; + my $route = "(?:\@$domain(?:,\@$rfc822_lwsp*$domain)*:$rfc822_lwsp*)"; + my $route_addr = "\\<$rfc822_lwsp*$route?$addr_spec\\>$rfc822_lwsp*"; + my $mailbox = "(?:$addr_spec|$phrase$route_addr)"; + + my $group = "$phrase:$rfc822_lwsp*(?:$mailbox(?:,\\s*$mailbox)*)?;\\s*"; + my $address = "(?:$mailbox|$group)"; + + return "$rfc822_lwsp*$address"; +} + +sub rfc822_strip_comments { + my $s = shift; +# Recursively remove comments, and replace with a single space. The simpler +# regexps in the Email Addressing FAQ are imperfect - they will miss escaped +# chars in atoms, for example. + + while ($s =~ s/^((?:[^"\\]|\\.)* + (?:"(?:[^"\\]|\\.)*"(?:[^"\\]|\\.)*)*) + \((?:[^()\\]|\\.)*\)/$1 /osx) {} + return $s; +} + +# valid: returns true if the parameter is an RFC822 valid address +# +sub rfc822_valid ($) { + my $s = rfc822_strip_comments(shift); + + if (!$rfc822re) { + $rfc822re = make_rfc822re(); + } + + return $s =~ m/^$rfc822re$/so && $s =~ m/^$rfc822_char*$/; +} + +# validlist: In scalar context, returns true if the parameter is an RFC822 +# valid list of addresses. +# +# In list context, returns an empty list on failure (an invalid +# address was found); otherwise a list whose first element is the +# number of addresses found and whose remaining elements are the +# addresses. This is needed to disambiguate failure (invalid) +# from success with no addresses found, because an empty string is +# a valid list. + +sub rfc822_validlist ($) { + my $s = rfc822_strip_comments(shift); + + if (!$rfc822re) { + $rfc822re = make_rfc822re(); + } + # * null list items are valid according to the RFC + # * the '1' business is to aid in distinguishing failure from no results + + my @r; + if ($s =~ m/^(?:$rfc822re)?(?:,(?:$rfc822re)?)*$/so && + $s =~ m/^$rfc822_char*$/) { + while ($s =~ m/(?:^|,$rfc822_lwsp*)($rfc822re)/gos) { + push @r, $1; + } + return wantarray ? (scalar(@r), @r) : 1; + } + else { + return wantarray ? () : 0; + } +} diff --git a/scripts/gfp-translate b/scripts/gfp-translate new file mode 100644 index 000000000000..073cb6d152a0 --- /dev/null +++ b/scripts/gfp-translate @@ -0,0 +1,81 @@ +#!/bin/bash +# Translate the bits making up a GFP mask +# (c) 2009, Mel Gorman +# Licensed under the terms of the GNU GPL License version 2 +SOURCE= +GFPMASK=none + +# Helper function to report failures and exit +die() { + echo ERROR: $@ + if [ "$TMPFILE" != "" ]; then + rm -f $TMPFILE + fi + exit -1 +} + +usage() { + echo "usage: gfp-translate [-h] [ --source DIRECTORY ] gfpmask" + exit 0 +} + +# Parse command-line arguements +while [ $# -gt 0 ]; do + case $1 in + --source) + SOURCE=$2 + shift 2 + ;; + -h) + usage + ;; + --help) + usage + ;; + *) + GFPMASK=$1 + shift + ;; + esac +done + +# Guess the kernel source directory if it's not set. Preference is in order of +# o current directory +# o /usr/src/linux +if [ "$SOURCE" = "" ]; then + if [ -r "/usr/src/linux/Makefile" ]; then + SOURCE=/usr/src/linux + fi + if [ -r "`pwd`/Makefile" ]; then + SOURCE=`pwd` + fi +fi + +# Confirm that a source directory exists +if [ ! -r "$SOURCE/Makefile" ]; then + die "Could not locate kernel source directory or it is invalid" +fi + +# Confirm that a GFP mask has been specified +if [ "$GFPMASK" = "none" ]; then + usage +fi + +# Extract GFP flags from the kernel source +TMPFILE=`mktemp -t gfptranslate-XXXXXX` || exit 1 +grep "^#define __GFP" $SOURCE/include/linux/gfp.h | sed -e 's/(__force gfp_t)//' | sed -e 's/u)/)/' | grep -v GFP_BITS | sed -e 's/)\//) \//' > $TMPFILE + +# Parse the flags +IFS=" +" +echo Source: $SOURCE +echo Parsing: $GFPMASK +for LINE in `cat $TMPFILE`; do + MASK=`echo $LINE | awk '{print $3}'` + if [ $(($GFPMASK&$MASK)) -ne 0 ]; then + echo $LINE + fi +done + +rm -f $TMPFILE +exit 0 diff --git a/scripts/headers.sh b/scripts/headers.sh index d33426f866db..0308ecc10d5b 100755 --- a/scripts/headers.sh +++ b/scripts/headers.sh @@ -15,19 +15,12 @@ do_command() fi } -# Do not try this architecture -drop="generic um ppc sparc64 cris" - archs=$(ls ${srctree}/arch) for arch in ${archs}; do case ${arch} in um) # no userspace export ;; - ppc) # headers exported by powerpc - ;; - sparc64) # headers exported by sparc - ;; cris) # headers export are known broken ;; *) diff --git a/scripts/headers_check.pl b/scripts/headers_check.pl index 56f90a480899..db1dd7a549f2 100644 --- a/scripts/headers_check.pl +++ b/scripts/headers_check.pl @@ -2,7 +2,7 @@ # # headers_check.pl execute a number of trivial consistency checks # -# Usage: headers_check.pl dir [files...] +# Usage: headers_check.pl dir arch [files...] # dir: dir to look for included files # arch: architecture # files: list of files to check @@ -37,7 +37,7 @@ foreach my $file (@files) { &check_include(); &check_asm_types(); &check_sizetypes(); - &check_prototypes(); + &check_declarations(); # Dropped for now. Too much noise &check_config(); } close FH; @@ -61,16 +61,18 @@ sub check_include } } -sub check_prototypes +sub check_declarations { - if ($line =~ m/^\s*extern\b/) { - printf STDERR "$filename:$lineno: extern's make no sense in userspace\n"; + if ($line =~m/^\s*extern\b/) { + printf STDERR "$filename:$lineno: " . + "userspace cannot call function or variable " . + "defined in the kernel\n"; } } sub check_config { - if ($line =~ m/[^a-zA-Z0-9_]+CONFIG_([a-zA-Z0-9]+)[^a-zA-Z0-9]/) { + if ($line =~ m/[^a-zA-Z0-9_]+CONFIG_([a-zA-Z0-9_]+)[^a-zA-Z0-9_]/) { printf STDERR "$filename:$lineno: leaks CONFIG_$1 to userspace where it is not valid\n"; } } diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c index 6654cbed965b..64343cc084b4 100644 --- a/scripts/kallsyms.c +++ b/scripts/kallsyms.c @@ -23,6 +23,10 @@ #include #include +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) +#endif + #define KSYM_NAME_LEN 128 struct sym_entry { @@ -32,9 +36,23 @@ struct sym_entry { unsigned char *sym; }; +struct text_range { + const char *stext, *etext; + unsigned long long start, end; +}; + +static unsigned long long _text; +static struct text_range text_ranges[] = { + { "_stext", "_etext" }, + { "_sinittext", "_einittext" }, + { "_stext_l1", "_etext_l1" }, /* Blackfin on-chip L1 inst SRAM */ + { "_stext_l2", "_etext_l2" }, /* Blackfin on-chip L2 SRAM */ +}; +#define text_range_text (&text_ranges[0]) +#define text_range_inittext (&text_ranges[1]) + static struct sym_entry *table; static unsigned int table_size, table_cnt; -static unsigned long long _text, _stext, _etext, _sinittext, _einittext; static int all_symbols = 0; static char symbol_prefix_char = '\0'; @@ -61,6 +79,26 @@ static inline int is_arm_mapping_symbol(const char *str) && (str[2] == '\0' || str[2] == '.'); } +static int read_symbol_tr(const char *sym, unsigned long long addr) +{ + size_t i; + struct text_range *tr; + + for (i = 0; i < ARRAY_SIZE(text_ranges); ++i) { + tr = &text_ranges[i]; + + if (strcmp(sym, tr->stext) == 0) { + tr->start = addr; + return 0; + } else if (strcmp(sym, tr->etext) == 0) { + tr->end = addr; + return 0; + } + } + + return 1; +} + static int read_symbol(FILE *in, struct sym_entry *s) { char str[500]; @@ -84,14 +122,8 @@ static int read_symbol(FILE *in, struct sym_entry *s) /* Ignore most absolute/undefined (?) symbols. */ if (strcmp(sym, "_text") == 0) _text = s->addr; - else if (strcmp(sym, "_stext") == 0) - _stext = s->addr; - else if (strcmp(sym, "_etext") == 0) - _etext = s->addr; - else if (strcmp(sym, "_sinittext") == 0) - _sinittext = s->addr; - else if (strcmp(sym, "_einittext") == 0) - _einittext = s->addr; + else if (read_symbol_tr(sym, s->addr) == 0) + /* nothing to do */; else if (toupper(stype) == 'A') { /* Keep these useful absolute symbols */ @@ -127,6 +159,21 @@ static int read_symbol(FILE *in, struct sym_entry *s) return 0; } +static int symbol_valid_tr(struct sym_entry *s) +{ + size_t i; + struct text_range *tr; + + for (i = 0; i < ARRAY_SIZE(text_ranges); ++i) { + tr = &text_ranges[i]; + + if (s->addr >= tr->start && s->addr <= tr->end) + return 1; + } + + return 0; +} + static int symbol_valid(struct sym_entry *s) { /* Symbols which vary between passes. Passes 1 and 2 must have @@ -156,8 +203,7 @@ static int symbol_valid(struct sym_entry *s) /* if --all-symbols is not specified, then symbols outside the text * and inittext sections are discarded */ if (!all_symbols) { - if ((s->addr < _stext || s->addr > _etext) - && (s->addr < _sinittext || s->addr > _einittext)) + if (symbol_valid_tr(s) == 0) return 0; /* Corner case. Discard any symbols with the same value as * _etext _einittext; they can move between pass 1 and 2 when @@ -165,10 +211,10 @@ static int symbol_valid(struct sym_entry *s) * they may get dropped in pass 2, which breaks the kallsyms * rules. */ - if ((s->addr == _etext && - strcmp((char *)s->sym + offset, "_etext")) || - (s->addr == _einittext && - strcmp((char *)s->sym + offset, "_einittext"))) + if ((s->addr == text_range_text->end && + strcmp((char *)s->sym + offset, text_range_text->etext)) || + (s->addr == text_range_inittext->end && + strcmp((char *)s->sym + offset, text_range_inittext->etext))) return 0; } diff --git a/scripts/kconfig/.gitignore b/scripts/kconfig/.gitignore index b49584c932cc..6a36a76e6606 100644 --- a/scripts/kconfig/.gitignore +++ b/scripts/kconfig/.gitignore @@ -8,6 +8,9 @@ lex.*.c zconf.hash.c *.moc lkc_defs.h +gconf.glade.h +*.pot +*.mo # # configuration programs diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile index fa8c2dd9c983..5ddf8becd7a2 100644 --- a/scripts/kconfig/Makefile +++ b/scripts/kconfig/Makefile @@ -83,7 +83,7 @@ help: @echo ' xconfig - Update current config utilising a QT based front-end' @echo ' gconfig - Update current config utilising a GTK based front-end' @echo ' oldconfig - Update current config utilising a provided .config as base' - @echo ' silentoldconfig - Same as oldconfig, but quietly' + @echo ' silentoldconfig - Same as oldconfig, but quietly, additionally update deps' @echo ' randconfig - New config with random answer to all options' @echo ' defconfig - New config with default answer to all options' @echo ' allmodconfig - New config selecting modules when possible' @@ -104,7 +104,7 @@ HOST_EXTRACFLAGS += -DLOCALE # =========================================================================== # Shared Makefile for the various kconfig executables: # conf: Used for defconfig, oldconfig and related targets -# mconf: Used for the mconfig target. +# mconf: Used for the menuconfig target # Utilizes the lxdialog package # qconf: Used for the xconfig target # Based on QT which needs to be installed to compile it diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c index d190092c3b6e..3baaaecd6b13 100644 --- a/scripts/kconfig/conf.c +++ b/scripts/kconfig/conf.c @@ -498,14 +498,15 @@ int main(int ac, char **av) conf_parse(name); //zconfdump(stdout); if (sync_kconfig) { - if (stat(".config", &tmpstat)) { + name = conf_get_configname(); + if (stat(name, &tmpstat)) { fprintf(stderr, _("***\n" "*** You have not yet configured your kernel!\n" - "*** (missing kernel .config file)\n" + "*** (missing kernel config file \"%s\")\n" "***\n" "*** Please run some configurator (e.g. \"make oldconfig\" or\n" "*** \"make menuconfig\" or \"make xconfig\").\n" - "***\n")); + "***\n"), name); exit(1); } } diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c index 273d73888f9d..a04da3459f0f 100644 --- a/scripts/kconfig/confdata.c +++ b/scripts/kconfig/confdata.c @@ -41,6 +41,13 @@ const char *conf_get_configname(void) return name ? name : ".config"; } +const char *conf_get_autoconfig_name(void) +{ + char *name = getenv("KCONFIG_AUTOCONFIG"); + + return name ? name : "include/config/auto.conf"; +} + static char *conf_expand_value(const char *in) { struct symbol *sym; @@ -555,15 +562,14 @@ int conf_write(const char *name) int conf_split_config(void) { - char *name, path[128]; + const char *name; + char path[128]; char *s, *d, c; struct symbol *sym; struct stat sb; int res, i, fd; - name = getenv("KCONFIG_AUTOCONFIG"); - if (!name) - name = "include/config/auto.conf"; + name = conf_get_autoconfig_name(); conf_read_simple(name, S_DEF_AUTO); if (chdir("include/config")) @@ -670,7 +676,7 @@ int conf_write_autoconf(void) { struct symbol *sym; const char *str; - char *name; + const char *name; FILE *out, *out_h; time_t now; int i, l; @@ -773,9 +779,7 @@ int conf_write_autoconf(void) name = "include/linux/autoconf.h"; if (rename(".tmpconfig.h", name)) return 1; - name = getenv("KCONFIG_AUTOCONFIG"); - if (!name) - name = "include/config/auto.conf"; + name = conf_get_autoconfig_name(); /* * This must be the last step, kbuild has a dependency on auto.conf * and this marks the successful completion of the previous steps. diff --git a/scripts/kconfig/lkc.h b/scripts/kconfig/lkc.h index 4a9af6f7886b..f379b0bf8c9e 100644 --- a/scripts/kconfig/lkc.h +++ b/scripts/kconfig/lkc.h @@ -74,6 +74,7 @@ char *zconf_curname(void); /* confdata.c */ const char *conf_get_configname(void); +const char *conf_get_autoconfig_name(void); char *conf_get_default_confname(void); void sym_set_change_count(int count); void sym_add_change_count(int count); diff --git a/scripts/kconfig/lxdialog/checklist.c b/scripts/kconfig/lxdialog/checklist.c index b2a878c936d6..bcc6f19c3a35 100644 --- a/scripts/kconfig/lxdialog/checklist.c +++ b/scripts/kconfig/lxdialog/checklist.c @@ -41,7 +41,8 @@ static void print_item(WINDOW * win, int choice, int selected) wmove(win, choice, check_x); wattrset(win, selected ? dlg.check_selected.atr : dlg.check.atr); - wprintw(win, "(%c)", item_is_tag('X') ? 'X' : ' '); + if (!item_is_tag(':')) + wprintw(win, "(%c)", item_is_tag('X') ? 'X' : ' '); wattrset(win, selected ? dlg.tag_selected.atr : dlg.tag.atr); mvwaddch(win, choice, item_x, item_str()[0]); diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c index 6841e95c0989..3bcacb4bfd3a 100644 --- a/scripts/kconfig/mconf.c +++ b/scripts/kconfig/mconf.c @@ -732,7 +732,12 @@ static void conf_choice(struct menu *menu) for (child = menu->list; child; child = child->next) { if (!menu_is_visible(child)) continue; - item_make("%s", _(menu_get_prompt(child))); + if (child->sym) + item_make("%s", _(menu_get_prompt(child))); + else { + item_make("*** %s ***", _(menu_get_prompt(child))); + item_set_tag(':'); + } item_set_data(child); if (child->sym == active) item_set_selected(1); @@ -748,6 +753,9 @@ static void conf_choice(struct menu *menu) case 0: if (selected) { child = item_data(); + if (!child->sym) + break; + sym_set_tristate_value(child->sym, yes); } return; diff --git a/scripts/kconfig/qconf.cc b/scripts/kconfig/qconf.cc index 5d0fd38b089b..ce7d508c7520 100644 --- a/scripts/kconfig/qconf.cc +++ b/scripts/kconfig/qconf.cc @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -297,10 +298,10 @@ void ConfigLineEdit::show(ConfigItem* i) void ConfigLineEdit::keyPressEvent(QKeyEvent* e) { switch (e->key()) { - case Key_Escape: + case Qt::Key_Escape: break; - case Key_Return: - case Key_Enter: + case Qt::Key_Return: + case Qt::Key_Enter: sym_set_string_value(item->menu->sym, text().latin1()); parent()->updateList(item); break; @@ -639,7 +640,7 @@ void ConfigList::keyPressEvent(QKeyEvent* ev) struct menu *menu; enum prop_type type; - if (ev->key() == Key_Escape && mode != fullMode && mode != listMode) { + if (ev->key() == Qt::Key_Escape && mode != fullMode && mode != listMode) { emit parentSelected(); ev->accept(); return; @@ -652,8 +653,8 @@ void ConfigList::keyPressEvent(QKeyEvent* ev) item = (ConfigItem*)i; switch (ev->key()) { - case Key_Return: - case Key_Enter: + case Qt::Key_Return: + case Qt::Key_Enter: if (item->goParent) { emit parentSelected(); break; @@ -667,16 +668,16 @@ void ConfigList::keyPressEvent(QKeyEvent* ev) emit menuSelected(menu); break; } - case Key_Space: + case Qt::Key_Space: changeValue(item); break; - case Key_N: + case Qt::Key_N: setValue(item, no); break; - case Key_M: + case Qt::Key_M: setValue(item, mod); break; - case Key_Y: + case Qt::Key_Y: setValue(item, yes); break; default: @@ -920,7 +921,7 @@ void ConfigView::updateListAll(void) } ConfigInfoView::ConfigInfoView(QWidget* parent, const char *name) - : Parent(parent, name), menu(0), sym(0) + : Parent(parent, name), sym(0), menu(0) { if (name) { configSettings->beginGroup(name); @@ -1199,7 +1200,7 @@ ConfigSearchWindow::ConfigSearchWindow(ConfigMainWindow* parent, const char *nam layout1->addLayout(layout2); split = new QSplitter(this); - split->setOrientation(QSplitter::Vertical); + split->setOrientation(Qt::Vertical); list = new ConfigView(split, name); list->list->mode = listMode; info = new ConfigInfoView(split, name); @@ -1275,7 +1276,7 @@ ConfigMainWindow::ConfigMainWindow(void) int x, y, width, height; char title[256]; - QWidget *d = configApp->desktop(); + QDesktopWidget *d = configApp->desktop(); snprintf(title, sizeof(title), _("Linux Kernel v%s Configuration"), getenv("KERNELVERSION")); setCaption(title); @@ -1290,14 +1291,14 @@ ConfigMainWindow::ConfigMainWindow(void) move(x, y); split1 = new QSplitter(this); - split1->setOrientation(QSplitter::Horizontal); + split1->setOrientation(Qt::Horizontal); setCentralWidget(split1); menuView = new ConfigView(split1, "menu"); menuList = menuView->list; split2 = new QSplitter(split1); - split2->setOrientation(QSplitter::Vertical); + split2->setOrientation(Qt::Vertical); // create config tree configView = new ConfigView(split2, "config"); @@ -1315,18 +1316,18 @@ ConfigMainWindow::ConfigMainWindow(void) backAction = new QAction("Back", QPixmap(xpm_back), _("Back"), 0, this); connect(backAction, SIGNAL(activated()), SLOT(goBack())); backAction->setEnabled(FALSE); - QAction *quitAction = new QAction("Quit", _("&Quit"), CTRL+Key_Q, this); + QAction *quitAction = new QAction("Quit", _("&Quit"), Qt::CTRL + Qt::Key_Q, this); connect(quitAction, SIGNAL(activated()), SLOT(close())); - QAction *loadAction = new QAction("Load", QPixmap(xpm_load), _("&Load"), CTRL+Key_L, this); + QAction *loadAction = new QAction("Load", QPixmap(xpm_load), _("&Load"), Qt::CTRL + Qt::Key_L, this); connect(loadAction, SIGNAL(activated()), SLOT(loadConfig())); - saveAction = new QAction("Save", QPixmap(xpm_save), _("&Save"), CTRL+Key_S, this); + saveAction = new QAction("Save", QPixmap(xpm_save), _("&Save"), Qt::CTRL + Qt::Key_S, this); connect(saveAction, SIGNAL(activated()), SLOT(saveConfig())); conf_set_changed_callback(conf_changed); // Set saveAction's initial state conf_changed(); QAction *saveAsAction = new QAction("Save As...", _("Save &As..."), 0, this); connect(saveAsAction, SIGNAL(activated()), SLOT(saveConfigAs())); - QAction *searchAction = new QAction("Find", _("&Find"), CTRL+Key_F, this); + QAction *searchAction = new QAction("Find", _("&Find"), Qt::CTRL + Qt::Key_F, this); connect(searchAction, SIGNAL(activated()), SLOT(searchConfig())); QAction *singleViewAction = new QAction("Single View", QPixmap(xpm_single_view), _("Single View"), 0, this); connect(singleViewAction, SIGNAL(activated()), SLOT(showSingleView())); @@ -1447,7 +1448,7 @@ ConfigMainWindow::ConfigMainWindow(void) void ConfigMainWindow::loadConfig(void) { - QString s = QFileDialog::getOpenFileName(".config", NULL, this); + QString s = QFileDialog::getOpenFileName(conf_get_configname(), NULL, this); if (s.isNull()) return; if (conf_read(QFile::encodeName(s))) @@ -1463,7 +1464,7 @@ void ConfigMainWindow::saveConfig(void) void ConfigMainWindow::saveConfigAs(void) { - QString s = QFileDialog::getSaveFileName(".config", NULL, this); + QString s = QFileDialog::getSaveFileName(conf_get_configname(), NULL, this); if (s.isNull()) return; if (conf_write(QFile::encodeName(s))) @@ -1524,6 +1525,8 @@ void ConfigMainWindow::setMenuLink(struct menu *menu) case fullMode: list = configList; break; + default: + break; } if (list) { @@ -1673,6 +1676,9 @@ void ConfigMainWindow::saveSettings(void) case fullMode : entry = "full"; break; + + default: + break; } configSettings->writeEntry("/listMode", entry); diff --git a/scripts/kconfig/util.c b/scripts/kconfig/util.c index 3cc9f9369036..b6b2a46af14c 100644 --- a/scripts/kconfig/util.c +++ b/scripts/kconfig/util.c @@ -46,8 +46,8 @@ int file_write_dep(const char *name) else fprintf(out, "\t%s\n", file->name); } - fprintf(out, "\ninclude/config/auto.conf: \\\n" - "\t$(deps_config)\n\n"); + fprintf(out, "\n%s: \\\n" + "\t$(deps_config)\n\n", conf_get_autoconfig_name()); expr_list_for_each_sym(sym_env_list, e, sym) { struct property *prop; @@ -61,7 +61,7 @@ int file_write_dep(const char *name) if (!value) value = ""; fprintf(out, "ifneq \"$(%s)\" \"%s\"\n", env_sym->name, value); - fprintf(out, "include/config/auto.conf: FORCE\n"); + fprintf(out, "%s: FORCE\n", conf_get_autoconfig_name()); fprintf(out, "endif\n"); } diff --git a/scripts/kernel-doc b/scripts/kernel-doc index 3208a3a7e7fe..ed591e9b7d1d 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -5,7 +5,7 @@ use strict; ## Copyright (c) 1998 Michael Zucchi, All Rights Reserved ## ## Copyright (C) 2000, 1 Tim Waugh ## ## Copyright (C) 2001 Simon Huggins ## -## Copyright (C) 2005-2008 Randy Dunlap ## +## Copyright (C) 2005-2009 Randy Dunlap ## ## ## ## #define enhancements by Armin Kuster ## ## Copyright (c) 2000 MontaVista Software, Inc. ## @@ -85,7 +85,7 @@ use strict; # # /** # * my_function -# **/ +# */ # # If the Description: header tag is omitted, then there must be a blank line # after the last parameter specification. @@ -105,7 +105,7 @@ use strict; # */ # etc. # -# Beside functions you can also write documentation for structs, unions, +# Besides functions you can also write documentation for structs, unions, # enums and typedefs. Instead of the function name you must write the name # of the declaration; the struct/union/enum/typedef must always precede # the name. Nesting of declarations is not supported. @@ -223,7 +223,7 @@ sub usage { } # read arguments -if ($#ARGV==-1) { +if ($#ARGV == -1) { usage(); } @@ -240,12 +240,12 @@ my $man_date = ('January', 'February', 'March', 'April', 'May', 'June', " " . ((localtime)[5]+1900); # Essentially these are globals -# They probably want to be tidied up made more localised or summat. -# CAVEAT EMPTOR! Some of the others I localised may not want to be which +# They probably want to be tidied up, made more localised or something. +# CAVEAT EMPTOR! Some of the others I localised may not want to be, which # could cause "use of undefined value" or other bugs. -my ($function, %function_table,%parametertypes,$declaration_purpose); -my ($type,$declaration_name,$return_type); -my ($newsection,$newcontents,$prototype,$filelist, $brcount, %source_map); +my ($function, %function_table, %parametertypes, $declaration_purpose); +my ($type, $declaration_name, $return_type); +my ($newsection, $newcontents, $prototype, $filelist, $brcount, %source_map); if (defined($ENV{'KBUILD_VERBOSE'})) { $verbose = "$ENV{'KBUILD_VERBOSE'}"; @@ -279,10 +279,10 @@ my $doc_special = "\@\%\$\&"; my $doc_start = '^/\*\*\s*$'; # Allow whitespace at end of comment start. my $doc_end = '\*/'; my $doc_com = '\s*\*\s*'; -my $doc_decl = $doc_com.'(\w+)'; -my $doc_sect = $doc_com.'(['.$doc_special.']?[\w\s]+):(.*)'; -my $doc_content = $doc_com.'(.*)'; -my $doc_block = $doc_com.'DOC:\s*(.*)?'; +my $doc_decl = $doc_com . '(\w+)'; +my $doc_sect = $doc_com . '([' . $doc_special . ']?[\w\s]+):(.*)'; +my $doc_content = $doc_com . '(.*)'; +my $doc_block = $doc_com . 'DOC:\s*(.*)?'; my %constants; my %parameterdescs; @@ -485,12 +485,12 @@ sub output_enum_html(%) { my %args = %{$_[0]}; my ($parameter); my $count; - print "

enum ".$args{'enum'}."

\n"; + print "

enum " . $args{'enum'} . "

\n"; - print "enum ".$args{'enum'}." {
\n"; + print "enum " . $args{'enum'} . " {
\n"; $count = 0; foreach $parameter (@{$args{'parameterlist'}}) { - print " ".$parameter.""; + print " " . $parameter . ""; if ($count != $#{$args{'parameterlist'}}) { $count++; print ",\n"; @@ -502,7 +502,7 @@ sub output_enum_html(%) { print "

Constants

\n"; print "
\n"; foreach $parameter (@{$args{'parameterlist'}}) { - print "
".$parameter."\n"; + print "
" . $parameter . "\n"; print "
"; output_highlight($args{'parameterdescs'}{$parameter}); } @@ -516,9 +516,9 @@ sub output_typedef_html(%) { my %args = %{$_[0]}; my ($parameter); my $count; - print "

typedef ".$args{'typedef'}."

\n"; + print "

typedef " . $args{'typedef'} . "

\n"; - print "typedef ".$args{'typedef'}."\n"; + print "typedef " . $args{'typedef'} . "\n"; output_section_html(@_); print "
\n"; } @@ -528,8 +528,8 @@ sub output_struct_html(%) { my %args = %{$_[0]}; my ($parameter); - print "

".$args{'type'}." ".$args{'struct'}. " - " .$args{'purpose'}."

\n"; - print "".$args{'type'}." ".$args{'struct'}." {
\n"; + print "

" . $args{'type'} . " " . $args{'struct'} . " - " . $args{'purpose'} . "

\n"; + print "" . $args{'type'} . " " . $args{'struct'} . " {
\n"; foreach $parameter (@{$args{'parameterlist'}}) { if ($parameter =~ /^#/) { print "$parameter
\n"; @@ -561,7 +561,7 @@ sub output_struct_html(%) { $parameter_name =~ s/\[.*//; ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; - print "
".$parameter."\n"; + print "
" . $parameter . "\n"; print "
"; output_highlight($args{'parameterdescs'}{$parameter_name}); } @@ -576,9 +576,9 @@ sub output_function_html(%) { my ($parameter, $section); my $count; - print "

" .$args{'function'}." - ".$args{'purpose'}."

\n"; - print "".$args{'functiontype'}."\n"; - print "".$args{'function'}."\n"; + print "

" . $args{'function'} . " - " . $args{'purpose'} . "

\n"; + print "" . $args{'functiontype'} . "\n"; + print "" . $args{'function'} . "\n"; print "("; $count = 0; foreach $parameter (@{$args{'parameterlist'}}) { @@ -587,7 +587,7 @@ sub output_function_html(%) { # pointer-to-function print "$1$parameter) ($2)"; } else { - print "".$type." ".$parameter.""; + print "" . $type . " " . $parameter . ""; } if ($count != $#{$args{'parameterlist'}}) { $count++; @@ -603,7 +603,7 @@ sub output_function_html(%) { $parameter_name =~ s/\[.*//; ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; - print "
".$parameter."\n"; + print "
" . $parameter . "\n"; print "
"; output_highlight($args{'parameterdescs'}{$parameter_name}); } @@ -657,7 +657,7 @@ sub output_function_xml(%) { my $count; my $id; - $id = "API-".$args{'function'}; + $id = "API-" . $args{'function'}; $id =~ s/[^A-Za-z0-9]/-/g; print "\n"; @@ -667,12 +667,12 @@ sub output_function_xml(%) { print " $man_date\n"; print "\n"; print "\n"; - print " ".$args{'function'}."\n"; + print " " . $args{'function'} . "\n"; print " 9\n"; print " " . $kernelversion . "\n"; print "\n"; print "\n"; - print " ".$args{'function'}."\n"; + print " " . $args{'function'} . "\n"; print " \n"; print " "; output_highlight ($args{'purpose'}); @@ -682,8 +682,8 @@ sub output_function_xml(%) { print "\n"; print " Synopsis\n"; print " \n"; - print " ".$args{'functiontype'}." "; - print "".$args{'function'}." \n"; + print " " . $args{'functiontype'} . " "; + print "" . $args{'function'} . " \n"; $count = 0; if ($#{$args{'parameterlist'}} >= 0) { @@ -694,7 +694,7 @@ sub output_function_xml(%) { print " $1$parameter)\n"; print " $2\n"; } else { - print " ".$type; + print " " . $type; print " $parameter\n"; } } @@ -734,7 +734,7 @@ sub output_struct_xml(%) { my ($parameter, $section); my $id; - $id = "API-struct-".$args{'struct'}; + $id = "API-struct-" . $args{'struct'}; $id =~ s/[^A-Za-z0-9]/-/g; print "\n"; @@ -744,12 +744,12 @@ sub output_struct_xml(%) { print " $man_date\n"; print "\n"; print "\n"; - print " ".$args{'type'}." ".$args{'struct'}."\n"; + print " " . $args{'type'} . " " . $args{'struct'} . "\n"; print " 9\n"; print " " . $kernelversion . "\n"; print "\n"; print "\n"; - print " ".$args{'type'}." ".$args{'struct'}."\n"; + print " " . $args{'type'} . " " . $args{'struct'} . "\n"; print " \n"; print " "; output_highlight ($args{'purpose'}); @@ -759,7 +759,7 @@ sub output_struct_xml(%) { print "\n"; print " Synopsis\n"; print " \n"; - print $args{'type'}." ".$args{'struct'}." {\n"; + print $args{'type'} . " " . $args{'struct'} . " {\n"; foreach $parameter (@{$args{'parameterlist'}}) { if ($parameter =~ /^#/) { print "$parameter\n"; @@ -779,7 +779,7 @@ sub output_struct_xml(%) { # bitfield print " $1 $parameter$2;\n"; } else { - print " ".$type." ".$parameter.";\n"; + print " " . $type . " " . $parameter . ";\n"; } } print "};"; @@ -824,7 +824,7 @@ sub output_enum_xml(%) { my $count; my $id; - $id = "API-enum-".$args{'enum'}; + $id = "API-enum-" . $args{'enum'}; $id =~ s/[^A-Za-z0-9]/-/g; print "\n"; @@ -834,12 +834,12 @@ sub output_enum_xml(%) { print " $man_date\n"; print "\n"; print "\n"; - print " enum ".$args{'enum'}."\n"; + print " enum " . $args{'enum'} . "\n"; print " 9\n"; print " " . $kernelversion . "\n"; print "\n"; print "\n"; - print " enum ".$args{'enum'}."\n"; + print " enum " . $args{'enum'} . "\n"; print " \n"; print " "; output_highlight ($args{'purpose'}); @@ -849,7 +849,7 @@ sub output_enum_xml(%) { print "\n"; print " Synopsis\n"; print " \n"; - print "enum ".$args{'enum'}." {\n"; + print "enum " . $args{'enum'} . " {\n"; $count = 0; foreach $parameter (@{$args{'parameterlist'}}) { print " $parameter"; @@ -891,7 +891,7 @@ sub output_typedef_xml(%) { my ($parameter, $section); my $id; - $id = "API-typedef-".$args{'typedef'}; + $id = "API-typedef-" . $args{'typedef'}; $id =~ s/[^A-Za-z0-9]/-/g; print "\n"; @@ -901,11 +901,11 @@ sub output_typedef_xml(%) { print " $man_date\n"; print "\n"; print "\n"; - print " typedef ".$args{'typedef'}."\n"; + print " typedef " . $args{'typedef'} . "\n"; print " 9\n"; print "\n"; print "\n"; - print " typedef ".$args{'typedef'}."\n"; + print " typedef " . $args{'typedef'} . "\n"; print " \n"; print " "; output_highlight ($args{'purpose'}); @@ -914,7 +914,7 @@ sub output_typedef_xml(%) { print "\n"; print " Synopsis\n"; - print " typedef ".$args{'typedef'}.";\n"; + print " typedef " . $args{'typedef'} . ";\n"; print "\n"; output_section_xml(@_); @@ -963,15 +963,15 @@ sub output_function_gnome { my $count; my $id; - $id = $args{'module'}."-".$args{'function'}; + $id = $args{'module'} . "-" . $args{'function'}; $id =~ s/[^A-Za-z0-9]/-/g; print "\n"; - print " ".$args{'function'}."\n"; + print " " . $args{'function'} . "\n"; print " \n"; - print " ".$args{'functiontype'}." "; - print "".$args{'function'}." "; + print " " . $args{'functiontype'} . " "; + print "" . $args{'function'} . " "; print "\n"; $count = 0; @@ -983,7 +983,7 @@ sub output_function_gnome { print " $1 $parameter)\n"; print " $2\n"; } else { - print " ".$type; + print " " . $type; print " $parameter\n"; } } @@ -1043,13 +1043,13 @@ sub output_function_man(%) { print ".TH \"$args{'function'}\" 9 \"$args{'function'}\" \"$man_date\" \"Kernel Hacker's Manual\" LINUX\n"; print ".SH NAME\n"; - print $args{'function'}." \\- ".$args{'purpose'}."\n"; + print $args{'function'} . " \\- " . $args{'purpose'} . "\n"; print ".SH SYNOPSIS\n"; if ($args{'functiontype'} ne "") { - print ".B \"".$args{'functiontype'}."\" ".$args{'function'}."\n"; + print ".B \"" . $args{'functiontype'} . "\" " . $args{'function'} . "\n"; } else { - print ".B \"".$args{'function'}."\n"; + print ".B \"" . $args{'function'} . "\n"; } $count = 0; my $parenth = "("; @@ -1061,10 +1061,10 @@ sub output_function_man(%) { $type = $args{'parametertypes'}{$parameter}; if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { # pointer-to-function - print ".BI \"".$parenth.$1."\" ".$parameter." \") (".$2.")".$post."\"\n"; + print ".BI \"" . $parenth . $1 . "\" " . $parameter . " \") (" . $2 . ")" . $post . "\"\n"; } else { $type =~ s/([^\*])$/$1 /; - print ".BI \"".$parenth.$type."\" ".$parameter." \"".$post."\"\n"; + print ".BI \"" . $parenth . $type . "\" " . $parameter . " \"" . $post . "\"\n"; } $count++; $parenth = ""; @@ -1075,7 +1075,7 @@ sub output_function_man(%) { my $parameter_name = $parameter; $parameter_name =~ s/\[.*//; - print ".IP \"".$parameter."\" 12\n"; + print ".IP \"" . $parameter . "\" 12\n"; output_highlight($args{'parameterdescs'}{$parameter_name}); } foreach $section (@{$args{'sectionlist'}}) { @@ -1094,10 +1094,10 @@ sub output_enum_man(%) { print ".TH \"$args{'module'}\" 9 \"enum $args{'enum'}\" \"$man_date\" \"API Manual\" LINUX\n"; print ".SH NAME\n"; - print "enum ".$args{'enum'}." \\- ".$args{'purpose'}."\n"; + print "enum " . $args{'enum'} . " \\- " . $args{'purpose'} . "\n"; print ".SH SYNOPSIS\n"; - print "enum ".$args{'enum'}." {\n"; + print "enum " . $args{'enum'} . " {\n"; $count = 0; foreach my $parameter (@{$args{'parameterlist'}}) { print ".br\n.BI \" $parameter\"\n"; @@ -1116,7 +1116,7 @@ sub output_enum_man(%) { my $parameter_name = $parameter; $parameter_name =~ s/\[.*//; - print ".IP \"".$parameter."\" 12\n"; + print ".IP \"" . $parameter . "\" 12\n"; output_highlight($args{'parameterdescs'}{$parameter_name}); } foreach $section (@{$args{'sectionlist'}}) { @@ -1131,13 +1131,13 @@ sub output_struct_man(%) { my %args = %{$_[0]}; my ($parameter, $section); - print ".TH \"$args{'module'}\" 9 \"".$args{'type'}." ".$args{'struct'}."\" \"$man_date\" \"API Manual\" LINUX\n"; + print ".TH \"$args{'module'}\" 9 \"" . $args{'type'} . " " . $args{'struct'} . "\" \"$man_date\" \"API Manual\" LINUX\n"; print ".SH NAME\n"; - print $args{'type'}." ".$args{'struct'}." \\- ".$args{'purpose'}."\n"; + print $args{'type'} . " " . $args{'struct'} . " \\- " . $args{'purpose'} . "\n"; print ".SH SYNOPSIS\n"; - print $args{'type'}." ".$args{'struct'}." {\n.br\n"; + print $args{'type'} . " " . $args{'struct'} . " {\n.br\n"; foreach my $parameter (@{$args{'parameterlist'}}) { if ($parameter =~ /^#/) { @@ -1151,13 +1151,13 @@ sub output_struct_man(%) { $type = $args{'parametertypes'}{$parameter}; if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { # pointer-to-function - print ".BI \" ".$1."\" ".$parameter." \") (".$2.")"."\"\n;\n"; + print ".BI \" " . $1 . "\" " . $parameter . " \") (" . $2 . ")" . "\"\n;\n"; } elsif ($type =~ m/^(.*?)\s*(:.*)/) { # bitfield - print ".BI \" ".$1."\ \" ".$parameter.$2." \""."\"\n;\n"; + print ".BI \" " . $1 . "\ \" " . $parameter . $2 . " \"" . "\"\n;\n"; } else { $type =~ s/([^\*])$/$1 /; - print ".BI \" ".$type."\" ".$parameter." \""."\"\n;\n"; + print ".BI \" " . $type . "\" " . $parameter . " \"" . "\"\n;\n"; } print "\n.br\n"; } @@ -1171,7 +1171,7 @@ sub output_struct_man(%) { $parameter_name =~ s/\[.*//; ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; - print ".IP \"".$parameter."\" 12\n"; + print ".IP \"" . $parameter . "\" 12\n"; output_highlight($args{'parameterdescs'}{$parameter_name}); } foreach $section (@{$args{'sectionlist'}}) { @@ -1189,7 +1189,7 @@ sub output_typedef_man(%) { print ".TH \"$args{'module'}\" 9 \"$args{'typedef'}\" \"$man_date\" \"API Manual\" LINUX\n"; print ".SH NAME\n"; - print "typedef ".$args{'typedef'}." \\- ".$args{'purpose'}."\n"; + print "typedef " . $args{'typedef'} . " \\- " . $args{'purpose'} . "\n"; foreach $section (@{$args{'sectionlist'}}) { print ".SH \"$section\"\n"; @@ -1218,13 +1218,13 @@ sub output_function_text(%) { my $start; print "Name:\n\n"; - print $args{'function'}." - ".$args{'purpose'}."\n"; + print $args{'function'} . " - " . $args{'purpose'} . "\n"; print "\nSynopsis:\n\n"; if ($args{'functiontype'} ne "") { - $start = $args{'functiontype'}." ".$args{'function'}." ("; + $start = $args{'functiontype'} . " " . $args{'function'} . " ("; } else { - $start = $args{'function'}." ("; + $start = $args{'function'} . " ("; } print $start; @@ -1233,9 +1233,9 @@ sub output_function_text(%) { $type = $args{'parametertypes'}{$parameter}; if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { # pointer-to-function - print $1.$parameter.") (".$2; + print $1 . $parameter . ") (" . $2; } else { - print $type." ".$parameter; + print $type . " " . $parameter; } if ($count != $#{$args{'parameterlist'}}) { $count++; @@ -1251,7 +1251,7 @@ sub output_function_text(%) { my $parameter_name = $parameter; $parameter_name =~ s/\[.*//; - print $parameter."\n\t".$args{'parameterdescs'}{$parameter_name}."\n"; + print $parameter . "\n\t" . $args{'parameterdescs'}{$parameter_name} . "\n"; } output_section_text(@_); } @@ -1276,8 +1276,8 @@ sub output_enum_text(%) { my $count; print "Enum:\n\n"; - print "enum ".$args{'enum'}." - ".$args{'purpose'}."\n\n"; - print "enum ".$args{'enum'}." {\n"; + print "enum " . $args{'enum'} . " - " . $args{'purpose'} . "\n\n"; + print "enum " . $args{'enum'} . " {\n"; $count = 0; foreach $parameter (@{$args{'parameterlist'}}) { print "\t$parameter"; @@ -1292,7 +1292,7 @@ sub output_enum_text(%) { print "Constants:\n\n"; foreach $parameter (@{$args{'parameterlist'}}) { print "$parameter\n\t"; - print $args{'parameterdescs'}{$parameter}."\n"; + print $args{'parameterdescs'}{$parameter} . "\n"; } output_section_text(@_); @@ -1305,7 +1305,7 @@ sub output_typedef_text(%) { my $count; print "Typedef:\n\n"; - print "typedef ".$args{'typedef'}." - ".$args{'purpose'}."\n"; + print "typedef " . $args{'typedef'} . " - " . $args{'purpose'} . "\n"; output_section_text(@_); } @@ -1314,8 +1314,8 @@ sub output_struct_text(%) { my %args = %{$_[0]}; my ($parameter); - print $args{'type'}." ".$args{'struct'}." - ".$args{'purpose'}."\n\n"; - print $args{'type'}." ".$args{'struct'}." {\n"; + print $args{'type'} . " " . $args{'struct'} . " - " . $args{'purpose'} . "\n\n"; + print $args{'type'} . " " . $args{'struct'} . " {\n"; foreach $parameter (@{$args{'parameterlist'}}) { if ($parameter =~ /^#/) { print "$parameter\n"; @@ -1334,7 +1334,7 @@ sub output_struct_text(%) { # bitfield print "\t$1 $parameter$2;\n"; } else { - print "\t".$type." ".$parameter.";\n"; + print "\t" . $type . " " . $parameter . ";\n"; } } print "};\n\n"; @@ -1348,7 +1348,7 @@ sub output_struct_text(%) { ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; print "$parameter\n\t"; - print $args{'parameterdescs'}{$parameter_name}."\n"; + print $args{'parameterdescs'}{$parameter_name} . "\n"; } print "\n"; output_section_text(@_); @@ -1387,7 +1387,7 @@ sub output_declaration { # generic output function - calls the right one based on current output mode. sub output_blockhead { no strict 'refs'; - my $func = "output_blockhead_".$output_mode; + my $func = "output_blockhead_" . $output_mode; &$func(@_); $section_counter++; } @@ -1398,7 +1398,7 @@ sub output_blockhead { sub dump_declaration($$) { no strict 'refs'; my ($prototype, $file) = @_; - my $func = "dump_".$decl_type; + my $func = "dump_" . $decl_type; &$func(@_); } @@ -1468,6 +1468,8 @@ sub dump_enum($$) { } } + # strip kmemcheck_bitfield_{begin,end}.*; + $members =~ s/kmemcheck_bitfield_.*?;//gos; output_declaration($declaration_name, 'enum', @@ -1645,12 +1647,21 @@ sub push_parameter($$$) { "or member '$param' not " . "described in '$declaration_name'\n"; } - print STDERR "Warning(${file}:$.):". + print STDERR "Warning(${file}:$.):" . " No description found for parameter '$param'\n"; ++$warnings; } } + # strip spaces from $param so that it is one continous string + # on @parameterlist; + # this fixes a problem where check_sections() cannot find + # a parameter like "addr[6 + 2]" because it actually appears + # as "addr[6", "+", "2]" on the parameter list; + # but it's better to maintain the param string unchanged for output, + # so just weaken the string compare in check_sections() to ignore + # "[blah" in a parameter string; + ###$param =~ s/\s*//g; push @parameterlist, $param; $parametertypes{$param} = $type; } @@ -1669,6 +1680,14 @@ sub check_sections($$$$$$) { $prm_clean = $prms[$px]; $prm_clean =~ s/\[.*\]//; $prm_clean =~ s/__attribute__\s*\(\([a-z,_\*\s\(\)]*\)\)//; + # ignore array size in a parameter string; + # however, the original param string may contain + # spaces, e.g.: addr[6 + 2] + # and this appears in @prms as "addr[6" since the + # parameter list is split at spaces; + # hence just ignore "[..." for the sections check; + $prm_clean =~ s/\[.*//; + ##$prm_clean =~ s/^\**//; if ($prm_clean eq $sects[$sx]) { $err = 0; @@ -1828,6 +1847,25 @@ sub reset_state { $state = 0; } +sub tracepoint_munge($) { + my $file = shift; + my $tracepointname = 0; + my $tracepointargs = 0; + + if($prototype =~ m/TRACE_EVENT\((.*?),/) { + $tracepointname = $1; + } + if($prototype =~ m/TP_PROTO\((.*?)\)/) { + $tracepointargs = $1; + } + if (($tracepointname eq 0) || ($tracepointargs eq 0)) { + print STDERR "Warning(${file}:$.): Unrecognized tracepoint format: \n". + "$prototype\n"; + } else { + $prototype = "static inline void trace_$tracepointname($tracepointargs)"; + } +} + sub syscall_munge() { my $void = 0; @@ -1882,6 +1920,9 @@ sub process_state3_function($$) { if ($prototype =~ /SYSCALL_DEFINE/) { syscall_munge(); } + if ($prototype =~ /TRACE_EVENT/) { + tracepoint_munge($file); + } dump_function($prototype, $file); reset_state(); } @@ -1907,7 +1948,7 @@ sub process_state3_type($$) { ($2 eq '{') && $brcount++; ($2 eq '}') && $brcount--; if (($2 eq ';') && ($brcount == 0)) { - dump_declaration($prototype,$file); + dump_declaration($prototype, $file); reset_state(); last; } @@ -2084,7 +2125,7 @@ sub process_file($) { $section = $section_default; $contents = ""; } else { - $contents .= $1."\n"; + $contents .= $1 . "\n"; } } else { # i dont know - bad line? ignore. diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index a3344285ccf4..40e0045876ee 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -641,7 +641,7 @@ static int do_virtio_entry(const char *filename, struct virtio_device_id *id, id->vendor = TO_NATIVE(id->vendor); strcpy(alias, "virtio:"); - ADD(alias, "d", 1, id->device); + ADD(alias, "d", id->device != VIRTIO_DEV_ANY_ID, id->device); ADD(alias, "v", id->vendor != VIRTIO_DEV_ANY_ID, id->vendor); add_wildcard(alias); diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 161b7846733e..4522948a012e 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -763,6 +763,8 @@ static void check_section(const char *modname, struct elf_info *elf, #define ALL_INIT_DATA_SECTIONS \ + ".init.setup$", ".init.rodata$", \ + ".devinit.rodata$", ".cpuinit.rodata$", ".meminit.rodata$" \ ".init.data$", ".devinit.data$", ".cpuinit.data$", ".meminit.data$" #define ALL_EXIT_DATA_SECTIONS \ ".exit.data$", ".devexit.data$", ".cpuexit.data$", ".memexit.data$" @@ -772,21 +774,23 @@ static void check_section(const char *modname, struct elf_info *elf, #define ALL_EXIT_TEXT_SECTIONS \ ".exit.text$", ".devexit.text$", ".cpuexit.text$", ".memexit.text$" -#define ALL_INIT_SECTIONS ALL_INIT_DATA_SECTIONS, ALL_INIT_TEXT_SECTIONS -#define ALL_EXIT_SECTIONS ALL_EXIT_DATA_SECTIONS, ALL_EXIT_TEXT_SECTIONS +#define ALL_INIT_SECTIONS INIT_SECTIONS, DEV_INIT_SECTIONS, \ + CPU_INIT_SECTIONS, MEM_INIT_SECTIONS +#define ALL_EXIT_SECTIONS EXIT_SECTIONS, DEV_EXIT_SECTIONS, \ + CPU_EXIT_SECTIONS, MEM_EXIT_SECTIONS #define DATA_SECTIONS ".data$", ".data.rel$" #define TEXT_SECTIONS ".text$" -#define INIT_SECTIONS ".init.data$", ".init.text$" -#define DEV_INIT_SECTIONS ".devinit.data$", ".devinit.text$" -#define CPU_INIT_SECTIONS ".cpuinit.data$", ".cpuinit.text$" -#define MEM_INIT_SECTIONS ".meminit.data$", ".meminit.text$" +#define INIT_SECTIONS ".init.*" +#define DEV_INIT_SECTIONS ".devinit.*" +#define CPU_INIT_SECTIONS ".cpuinit.*" +#define MEM_INIT_SECTIONS ".meminit.*" -#define EXIT_SECTIONS ".exit.data$", ".exit.text$" -#define DEV_EXIT_SECTIONS ".devexit.data$", ".devexit.text$" -#define CPU_EXIT_SECTIONS ".cpuexit.data$", ".cpuexit.text$" -#define MEM_EXIT_SECTIONS ".memexit.data$", ".memexit.text$" +#define EXIT_SECTIONS ".exit.*" +#define DEV_EXIT_SECTIONS ".devexit.*" +#define CPU_EXIT_SECTIONS ".cpuexit.*" +#define MEM_EXIT_SECTIONS ".memexit.*" /* init data sections */ static const char *init_data_sections[] = { ALL_INIT_DATA_SECTIONS, NULL }; @@ -869,12 +873,36 @@ const struct sectioncheck sectioncheck[] = { .tosec = { INIT_SECTIONS, NULL }, .mismatch = XXXINIT_TO_INIT, }, +/* Do not reference cpuinit code/data from meminit code/data */ +{ + .fromsec = { MEM_INIT_SECTIONS, NULL }, + .tosec = { CPU_INIT_SECTIONS, NULL }, + .mismatch = XXXINIT_TO_INIT, +}, +/* Do not reference meminit code/data from cpuinit code/data */ +{ + .fromsec = { CPU_INIT_SECTIONS, NULL }, + .tosec = { MEM_INIT_SECTIONS, NULL }, + .mismatch = XXXINIT_TO_INIT, +}, /* Do not reference exit code/data from devexit/cpuexit/memexit code/data */ { .fromsec = { DEV_EXIT_SECTIONS, CPU_EXIT_SECTIONS, MEM_EXIT_SECTIONS, NULL }, .tosec = { EXIT_SECTIONS, NULL }, .mismatch = XXXEXIT_TO_EXIT, }, +/* Do not reference cpuexit code/data from memexit code/data */ +{ + .fromsec = { MEM_EXIT_SECTIONS, NULL }, + .tosec = { CPU_EXIT_SECTIONS, NULL }, + .mismatch = XXXEXIT_TO_EXIT, +}, +/* Do not reference memexit code/data from cpuexit code/data */ +{ + .fromsec = { CPU_EXIT_SECTIONS, NULL }, + .tosec = { MEM_EXIT_SECTIONS, NULL }, + .mismatch = XXXEXIT_TO_EXIT, +}, /* Do not use exit code/data from init code */ { .fromsec = { ALL_INIT_SECTIONS, NULL }, @@ -1168,7 +1196,7 @@ static void report_sec_mismatch(const char *modname, enum mismatch mismatch, "The variable %s references\n" "the %s %s%s%s\n" "If the reference is valid then annotate the\n" - "variable with __init* (see linux/init.h) " + "variable with __init* or __refdata (see linux/init.h) " "or name the variable:\n", fromsym, to, sec2annotation(tosec), tosym, to_p); while (*s) diff --git a/scripts/package/builddeb b/scripts/package/builddeb index 1264b8e2829d..01c2d13dd020 100644 --- a/scripts/package/builddeb +++ b/scripts/package/builddeb @@ -1,38 +1,58 @@ #!/bin/sh # -# builddeb 1.2 +# builddeb 1.3 # Copyright 2003 Wichert Akkerman # # Simple script to generate a deb package for a Linux kernel. All the -# complexity of what to do with a kernel after it is installer or removed +# complexity of what to do with a kernel after it is installed or removed # is left to other scripts and packages: they can install scripts in the -# /etc/kernel/{pre,post}{inst,rm}.d/ directories that will be called on -# package install and removal. +# /etc/kernel/{pre,post}{inst,rm}.d/ directories (or an alternative location +# specified in KDEB_HOOKDIR) that will be called on package install and +# removal. set -e +create_package() { + local pname="$1" pdir="$2" + + cp debian/copyright "$pdir/usr/share/doc/$pname/" + + # Fix ownership and permissions + chown -R root:root "$pdir" + chmod -R go-w "$pdir" + + # Create the package + dpkg-gencontrol -isp -p$pname -P"$pdir" + dpkg --build "$pdir" .. +} + # Some variables and settings used throughout the script version=$KERNELRELEASE -revision=`cat .version` +revision=$(cat .version) +if [ -n "$KDEB_PKGVERSION" ]; then + packageversion=$KDEB_PKGVERSION +else + packageversion=$version-$revision +fi tmpdir="$objtree/debian/tmp" fwdir="$objtree/debian/fwtmp" -packagename=linux-$version +packagename=linux-image-$version fwpackagename=linux-firmware-image -if [ "$ARCH" == "um" ] ; then +if [ "$ARCH" = "um" ] ; then packagename=user-mode-linux-$version fi # Setup the directory structure rm -rf "$tmpdir" "$fwdir" -mkdir -p "$tmpdir/DEBIAN" "$tmpdir/lib" "$tmpdir/boot" -mkdir -p "$fwdir/DEBIAN" "$fwdir/lib" -if [ "$ARCH" == "um" ] ; then - mkdir -p "$tmpdir/usr/lib/uml/modules/$version" "$tmpdir/usr/share/doc/$packagename" "$tmpdir/usr/bin" +mkdir -p "$tmpdir/DEBIAN" "$tmpdir/lib" "$tmpdir/boot" "$tmpdir/usr/share/doc/$packagename" +mkdir -p "$fwdir/DEBIAN" "$fwdir/lib" "$fwdir/usr/share/doc/$fwpackagename" +if [ "$ARCH" = "um" ] ; then + mkdir -p "$tmpdir/usr/lib/uml/modules/$version" "$tmpdir/usr/bin" fi # Build and install the kernel -if [ "$ARCH" == "um" ] ; then +if [ "$ARCH" = "um" ] ; then $MAKE linux cp System.map "$tmpdir/usr/lib/uml/modules/$version/System.map" cp .config "$tmpdir/usr/share/doc/$packagename/config" @@ -41,53 +61,100 @@ if [ "$ARCH" == "um" ] ; then else cp System.map "$tmpdir/boot/System.map-$version" cp .config "$tmpdir/boot/config-$version" - cp $KBUILD_IMAGE "$tmpdir/boot/vmlinuz-$version" + # Not all arches include the boot path in KBUILD_IMAGE + if ! cp $KBUILD_IMAGE "$tmpdir/boot/vmlinuz-$version"; then + cp arch/$ARCH/boot/$KBUILD_IMAGE "$tmpdir/boot/vmlinuz-$version" + fi fi if grep -q '^CONFIG_MODULES=y' .config ; then INSTALL_MOD_PATH="$tmpdir" make KBUILD_SRC= modules_install - if [ "$ARCH" == "um" ] ; then + if [ "$ARCH" = "um" ] ; then mv "$tmpdir/lib/modules/$version"/* "$tmpdir/usr/lib/uml/modules/$version/" rmdir "$tmpdir/lib/modules/$version" fi fi # Install the maintainer scripts +# Note: hook scripts under /etc/kernel are also executed by official Debian +# kernel packages, as well as kernel packages built using make-kpkg +debhookdir=${KDEB_HOOKDIR:-/etc/kernel} for script in postinst postrm preinst prerm ; do - mkdir -p "$tmpdir/etc/kernel/$script.d" + mkdir -p "$tmpdir$debhookdir/$script.d" cat < "$tmpdir/DEBIAN/$script" #!/bin/sh set -e -test -d /etc/kernel/$script.d && run-parts --arg="$version" /etc/kernel/$script.d +# Pass maintainer script parameters to hook scripts +export DEB_MAINT_PARAMS="\$@" + +test -d $debhookdir/$script.d && run-parts --arg="$version" $debhookdir/$script.d exit 0 EOF chmod 755 "$tmpdir/DEBIAN/$script" done -name="Kernel Compiler <$(id -nu)@$(hostname -f)>" +# Try to determine maintainer and email values +if [ -n "$DEBEMAIL" ]; then + email=$DEBEMAIL +elif [ -n "$EMAIL" ]; then + email=$EMAIL +else + email=$(id -nu)@$(hostname -f) +fi +if [ -n "$DEBFULLNAME" ]; then + name=$DEBFULLNAME +elif [ -n "$NAME" ]; then + name=$NAME +else + name="Anonymous" +fi +maintainer="$name <$email>" + # Generate a simple changelog template cat < debian/changelog -linux ($version-$revision) unstable; urgency=low +linux-upstream ($packageversion) unstable; urgency=low - * A standard release + * Custom built Linux kernel. - -- $name $(date -R) + -- $maintainer $(date -R) +EOF + +# Generate copyright file +cat < debian/copyright +This is a packacked upstream version of the Linux kernel. + +The sources may be found at most Linux ftp sites, including: +ftp://ftp.kernel.org/pub/linux/kernel + +Copyright: 1991 - 2009 Linus Torvalds and others. + +The git repository for mainline kernel development is at: +git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git + + 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 dated June, 1991. + +On Debian GNU/Linux systems, the complete text of the GNU General Public +License version 2 can be found in \`/usr/share/common-licenses/GPL-2'. EOF # Generate a control file -if [ "$ARCH" == "um" ]; then - cat < debian/control -Source: linux -Section: base +Source: linux-upstream +Section: admin Priority: optional -Maintainer: $name -Standards-Version: 3.6.1 +Maintainer: $maintainer +Standards-Version: 3.8.1 +EOF + +if [ "$ARCH" = "um" ]; then + cat <> debian/control Package: $packagename -Provides: kernel-image-$version, linux-image-$version +Provides: linux-image, linux-image-2.6, linux-modules-$version Architecture: any Description: User Mode Linux kernel, version $version User-mode Linux is a port of the Linux kernel to its own system call @@ -97,30 +164,22 @@ Description: User Mode Linux kernel, version $version many other things. . This package contains the Linux kernel, modules and corresponding other - files version $version + files, version: $version. EOF else -cat < debian/control -Source: linux -Section: base -Priority: optional -Maintainer: $name -Standards-Version: 3.6.1 + cat <> debian/control Package: $packagename -Provides: kernel-image-$version, linux-image-$version +Provides: linux-image, linux-image-2.6, linux-modules-$version Suggests: $fwpackagename Architecture: any Description: Linux kernel, version $version This package contains the Linux kernel, modules and corresponding other - files version $version + files, version: $version. EOF -fi -# Fix some ownership and permissions -chown -R root:root "$tmpdir" -chmod -R go-w "$tmpdir" +fi # Do we have firmware? Move it out of the way and build it into a package. if [ -e "$tmpdir/lib/firmware" ]; then @@ -131,16 +190,12 @@ if [ -e "$tmpdir/lib/firmware" ]; then Package: $fwpackagename Architecture: all Description: Linux kernel firmware, version $version - This package contains firmware from the Linux kernel, version $version + This package contains firmware from the Linux kernel, version $version. EOF - dpkg-gencontrol -isp -p$fwpackagename -P"$fwdir" - dpkg --build "$fwdir" .. + create_package "$fwpackagename" "$fwdir" fi -# Perform the final magic -dpkg-gencontrol -isp -p$packagename -dpkg --build "$tmpdir" .. +create_package "$packagename" "$tmpdir" exit 0 - diff --git a/scripts/pnmtologo.c b/scripts/pnmtologo.c index 6aa2a2483f8d..64f5ddb09ea6 100644 --- a/scripts/pnmtologo.c +++ b/scripts/pnmtologo.c @@ -237,22 +237,22 @@ static void write_header(void) fprintf(out, " * Linux logo %s\n", logoname); fputs(" */\n\n", out); fputs("#include \n\n", out); - fprintf(out, "static unsigned char %s_data[] __initdata = {\n", + fprintf(out, "static const unsigned char %s_data[] __initconst = {\n", logoname); } static void write_footer(void) { fputs("\n};\n\n", out); - fprintf(out, "struct linux_logo %s __initdata = {\n", logoname); - fprintf(out, " .type\t= %s,\n", logo_types[logo_type]); - fprintf(out, " .width\t= %d,\n", logo_width); - fprintf(out, " .height\t= %d,\n", logo_height); + fprintf(out, "const struct linux_logo %s __initconst = {\n", logoname); + fprintf(out, "\t.type\t\t= %s,\n", logo_types[logo_type]); + fprintf(out, "\t.width\t\t= %d,\n", logo_width); + fprintf(out, "\t.height\t\t= %d,\n", logo_height); if (logo_type == LINUX_LOGO_CLUT224) { - fprintf(out, " .clutsize\t= %d,\n", logo_clutsize); - fprintf(out, " .clut\t= %s_clut,\n", logoname); + fprintf(out, "\t.clutsize\t= %d,\n", logo_clutsize); + fprintf(out, "\t.clut\t\t= %s_clut,\n", logoname); } - fprintf(out, " .data\t= %s_data\n", logoname); + fprintf(out, "\t.data\t\t= %s_data\n", logoname); fputs("};\n\n", out); /* close logo file */ @@ -374,7 +374,7 @@ static void write_logo_clut224(void) fputs("\n};\n\n", out); /* write logo clut */ - fprintf(out, "static unsigned char %s_clut[] __initdata = {\n", + fprintf(out, "static const unsigned char %s_clut[] __initconst = {\n", logoname); write_hex_cnt = 0; for (i = 0; i < logo_clutsize; i++) { diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl index 409596eca124..7109e2b5bc0a 100755 --- a/scripts/recordmcount.pl +++ b/scripts/recordmcount.pl @@ -26,7 +26,7 @@ # which will also be the location of that section after final link. # e.g. # -# .section ".text.sched" +# .section ".sched.text", "ax" # .globl my_func # my_func: # [...] @@ -39,7 +39,7 @@ # [...] # # Both relocation offsets for the mcounts in the above example will be -# offset from .text.sched. If we make another file called tmp.s with: +# offset from .sched.text. If we make another file called tmp.s with: # # .section __mcount_loc # .quad my_func + 0x5 @@ -51,7 +51,7 @@ # But this gets hard if my_func is not globl (a static function). # In such a case we have: # -# .section ".text.sched" +# .section ".sched.text", "ax" # my_func: # [...] # call mcount (offset: 0x5) @@ -185,6 +185,19 @@ if ($arch eq "x86_64") { $objcopy .= " -O elf32-i386"; $cc .= " -m32"; +} elsif ($arch eq "s390" && $bits == 32) { + $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_390_32\\s+_mcount\$"; + $alignment = 4; + $ld .= " -m elf_s390"; + $cc .= " -m31"; + +} elsif ($arch eq "s390" && $bits == 64) { + $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_390_(PC|PLT)32DBL\\s+_mcount\\+0x2\$"; + $alignment = 8; + $type = ".quad"; + $ld .= " -m elf64_s390"; + $cc .= " -m64"; + } elsif ($arch eq "sh") { $alignment = 2; @@ -213,6 +226,26 @@ if ($arch eq "x86_64") { if ($is_module eq "0") { $cc .= " -mconstant-gp"; } +} elsif ($arch eq "sparc64") { + # In the objdump output there are giblets like: + # 0000000000000000 : + # As there's some data blobs that get emitted into the + # text section before the first instructions and the first + # real symbols. We don't want to match that, so to combat + # this we use '\w' so we'll match just plain symbol names, + # and not those that also include hex offsets inside of the + # '<>' brackets. Actually the generic function_regex setting + # could safely use this too. + $function_regex = "^([0-9a-fA-F]+)\\s+<(\\w*?)>:"; + + # Sparc64 calls '_mcount' instead of plain 'mcount'. + $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s_mcount\$"; + + $alignment = 8; + $type = ".xword"; + $ld .= " -m elf64_sparc"; + $cc .= " -m64"; + $objcopy .= " -O elf64-sparc"; } else { die "Arch $arch is not supported with CONFIG_FTRACE_MCOUNT_RECORD"; } diff --git a/scripts/setlocalversion b/scripts/setlocalversion index 00790472f641..46989b88d734 100755 --- a/scripts/setlocalversion +++ b/scripts/setlocalversion @@ -39,8 +39,10 @@ if head=`git rev-parse --verify --short HEAD 2>/dev/null`; then printf -- '-svn%s' "`git svn find-rev $head`" fi - # Are there uncommitted changes? - git update-index --refresh --unmerged > /dev/null + # Update index only on r/w media + [ -w . ] && git update-index --refresh --unmerged > /dev/null + + # Check for uncommitted changes if git diff-index --name-only HEAD | grep -v "^scripts/package" \ | read dummy; then printf '%s' -dirty diff --git a/scripts/tracing/draw_functrace.py b/scripts/tracing/draw_functrace.py index 902f9a992620..db40fa04cd51 100644 --- a/scripts/tracing/draw_functrace.py +++ b/scripts/tracing/draw_functrace.py @@ -12,10 +12,9 @@ calls. Only the functions's names and the the call time are provided. Usage: Be sure that you have CONFIG_FUNCTION_TRACER - # mkdir /debugfs - # mount -t debug debug /debug - # echo function > /debug/tracing/current_tracer - $ cat /debug/tracing/trace_pipe > ~/raw_trace_func + # mount -t debugfs nodev /sys/kernel/debug + # echo function > /sys/kernel/debug/tracing/current_tracer + $ cat /sys/kernel/debug/tracing/trace_pipe > ~/raw_trace_func Wait some times but not too much, the script is a bit slow. Break the pipe (Ctrl + Z) $ scripts/draw_functrace.py < raw_trace_func > draw_functrace diff --git a/scripts/unifdef.c b/scripts/unifdef.c index 05a31a6c7e1b..30d459fb0709 100644 --- a/scripts/unifdef.c +++ b/scripts/unifdef.c @@ -678,8 +678,10 @@ eval_unary(const struct ops *ops, int *valp, const char **cpp) if (*cp == '!') { debug("eval%d !", ops - eval_ops); cp++; - if (eval_unary(ops, valp, &cp) == LT_IF) + if (eval_unary(ops, valp, &cp) == LT_IF) { + *cpp = cp; return (LT_IF); + } *valp = !*valp; } else if (*cp == '(') { cp++; @@ -700,13 +702,16 @@ eval_unary(const struct ops *ops, int *valp, const char **cpp) return (LT_IF); cp = skipcomment(cp); sym = findsym(cp); - if (sym < 0) - return (LT_IF); - *valp = (value[sym] != NULL); cp = skipsym(cp); cp = skipcomment(cp); if (*cp++ != ')') return (LT_IF); + if (sym >= 0) + *valp = (value[sym] != NULL); + else { + *cpp = cp; + return (LT_IF); + } keepthis = false; } else if (!endsym(*cp)) { debug("eval%d symbol", ops - eval_ops); @@ -741,11 +746,11 @@ eval_table(const struct ops *ops, int *valp, const char **cpp) const struct op *op; const char *cp; int val; + Linetype lhs, rhs; debug("eval%d", ops - eval_ops); cp = *cpp; - if (ops->inner(ops+1, valp, &cp) == LT_IF) - return (LT_IF); + lhs = ops->inner(ops+1, valp, &cp); for (;;) { cp = skipcomment(cp); for (op = ops->op; op->str != NULL; op++) @@ -755,14 +760,32 @@ eval_table(const struct ops *ops, int *valp, const char **cpp) break; cp += strlen(op->str); debug("eval%d %s", ops - eval_ops, op->str); - if (ops->inner(ops+1, &val, &cp) == LT_IF) - return (LT_IF); - *valp = op->fn(*valp, val); + rhs = ops->inner(ops+1, &val, &cp); + if (op->fn == op_and && (lhs == LT_FALSE || rhs == LT_FALSE)) { + debug("eval%d: and always false", ops - eval_ops); + if (lhs == LT_IF) + *valp = val; + lhs = LT_FALSE; + continue; + } + if (op->fn == op_or && (lhs == LT_TRUE || rhs == LT_TRUE)) { + debug("eval%d: or always true", ops - eval_ops); + if (lhs == LT_IF) + *valp = val; + lhs = LT_TRUE; + continue; + } + if (rhs == LT_IF) + lhs = LT_IF; + if (lhs != LT_IF) + *valp = op->fn(*valp, val); } *cpp = cp; debug("eval%d = %d", ops - eval_ops, *valp); - return (*valp ? LT_TRUE : LT_FALSE); + if (lhs != LT_IF) + lhs = (*valp ? LT_TRUE : LT_FALSE); + return lhs; } /* @@ -773,12 +796,15 @@ eval_table(const struct ops *ops, int *valp, const char **cpp) static Linetype ifeval(const char **cpp) { + const char *cp = *cpp; int ret; int val; debug("eval %s", *cpp); keepthis = killconsts ? false : true; - ret = eval_table(eval_ops, &val, cpp); + ret = eval_table(eval_ops, &val, &cp); + if (ret != LT_IF) + *cpp = cp; debug("eval = %d", val); return (keepthis ? LT_IF : ret); } diff --git a/scripts/ver_linux b/scripts/ver_linux index dbb3037f1346..7de36df4eaa5 100755 --- a/scripts/ver_linux +++ b/scripts/ver_linux @@ -65,7 +65,7 @@ sed -n -e '/^.*\/libc-\([^/]*\)\.so$/{s//\1/;p;q}' < /proc/self/maps ldd -v > /dev/null 2>&1 && ldd -v || ldd --version |head -n 1 | awk \ 'NR==1{print "Dynamic linker (ldd) ", $NF}' -ls -l /usr/lib/lib{g,stdc}++.so 2>/dev/null | awk -F. \ +ls -l /usr/lib/libg++.so /usr/lib/libstdc++.so 2>/dev/null | awk -F. \ '{print "Linux C++ Library " $4"."$5"."$6}' ps --version 2>&1 | grep version | awk \ diff --git a/security/Kconfig b/security/Kconfig index bb244774e9d7..d23c839038f0 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -110,29 +110,9 @@ config SECURITY_ROOTPLUG See for more information about this module. - + If you are unsure how to answer this question, answer N. -config SECURITY_DEFAULT_MMAP_MIN_ADDR - int "Low address space to protect from user allocation" - depends on SECURITY - default 0 - help - This is the portion of low virtual memory which should be protected - from userspace allocation. Keeping a user from writing to low pages - can help reduce the impact of kernel NULL pointer bugs. - - For most ia64, ppc64 and x86 users with lots of address space - a value of 65536 is reasonable and should cause no problems. - On arm and other archs it should not be higher than 32768. - Programs which use vm86 functionality would either need additional - permissions from either the LSM or the capabilities module or have - this protection disabled. - - This value can be changed after boot using the - /proc/sys/vm/mmap_min_addr tunable. - - source security/selinux/Kconfig source security/smack/Kconfig source security/tomoyo/Kconfig diff --git a/security/Makefile b/security/Makefile index fa77021d9778..c67557cdaa85 100644 --- a/security/Makefile +++ b/security/Makefile @@ -16,6 +16,9 @@ obj-$(CONFIG_SECURITYFS) += inode.o # Must precede capability.o in order to stack properly. obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o obj-$(CONFIG_SECURITY_SMACK) += smack/built-in.o +ifeq ($(CONFIG_AUDIT),y) +obj-$(CONFIG_SECURITY_SMACK) += lsm_audit.o +endif obj-$(CONFIG_SECURITY_TOMOYO) += tomoyo/built-in.o obj-$(CONFIG_SECURITY_ROOTPLUG) += root_plug.o obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o diff --git a/security/commoncap.c b/security/commoncap.c index beac0258c2a8..48b7e0228fa3 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -28,6 +28,28 @@ #include #include +/* + * If a non-root user executes a setuid-root binary in + * !secure(SECURE_NOROOT) mode, then we raise capabilities. + * However if fE is also set, then the intent is for only + * the file capabilities to be applied, and the setuid-root + * bit is left on either to change the uid (plausible) or + * to get full privilege on a kernel without file capabilities + * support. So in that case we do not raise capabilities. + * + * Warn if that happens, once per boot. + */ +static void warn_setuid_and_fcaps_mixed(char *fname) +{ + static int warned; + if (!warned) { + printk(KERN_INFO "warning: `%s' has both setuid-root and" + " effective capabilities. Therefore not raising all" + " capabilities.\n", fname); + warned = 1; + } +} + int cap_netlink_send(struct sock *sk, struct sk_buff *skb) { NETLINK_CB(skb).eff_cap = current_cap(); @@ -463,6 +485,15 @@ int cap_bprm_set_creds(struct linux_binprm *bprm) return ret; if (!issecure(SECURE_NOROOT)) { + /* + * If the legacy file capability is set, then don't set privs + * for a setuid root binary run by a non-root user. Do set it + * for a root user just to cause least surprise to an admin. + */ + if (effective && new->uid != 0 && new->euid == 0) { + warn_setuid_and_fcaps_mixed(bprm->filename); + goto skip; + } /* * To support inheritance of root-permissions and suid-root * executables under compatibility mode, we override the @@ -478,6 +509,7 @@ int cap_bprm_set_creds(struct linux_binprm *bprm) if (new->euid == 0) effective = true; } +skip: /* Don't let someone trace a set[ug]id/setpcap binary with the revised * credentials unless they have the appropriate permit diff --git a/security/device_cgroup.c b/security/device_cgroup.c index 5fda7df19723..b8186bac8b7e 100644 --- a/security/device_cgroup.c +++ b/security/device_cgroup.c @@ -490,7 +490,7 @@ int devcgroup_inode_permission(struct inode *inode, int mask) list_for_each_entry_rcu(wh, &dev_cgroup->whitelist, list) { if (wh->type & DEV_ALL) - goto acc_check; + goto found; if ((wh->type & DEV_BLOCK) && !S_ISBLK(inode->i_mode)) continue; if ((wh->type & DEV_CHAR) && !S_ISCHR(inode->i_mode)) @@ -499,11 +499,12 @@ int devcgroup_inode_permission(struct inode *inode, int mask) continue; if (wh->minor != ~0 && wh->minor != iminor(inode)) continue; -acc_check: + if ((mask & MAY_WRITE) && !(wh->access & ACC_WRITE)) continue; if ((mask & MAY_READ) && !(wh->access & ACC_READ)) continue; +found: rcu_read_unlock(); return 0; } @@ -527,7 +528,7 @@ int devcgroup_inode_mknod(int mode, dev_t dev) list_for_each_entry_rcu(wh, &dev_cgroup->whitelist, list) { if (wh->type & DEV_ALL) - goto acc_check; + goto found; if ((wh->type & DEV_BLOCK) && !S_ISBLK(mode)) continue; if ((wh->type & DEV_CHAR) && !S_ISCHR(mode)) @@ -536,9 +537,10 @@ int devcgroup_inode_mknod(int mode, dev_t dev) continue; if (wh->minor != ~0 && wh->minor != MINOR(dev)) continue; -acc_check: + if (!(wh->access & ACC_MKNOD)) continue; +found: rcu_read_unlock(); return 0; } diff --git a/security/inode.c b/security/inode.c index f3b91bfbe4cb..f7496c6a022b 100644 --- a/security/inode.c +++ b/security/inode.c @@ -287,7 +287,7 @@ void securityfs_remove(struct dentry *dentry) { struct dentry *parent; - if (!dentry) + if (!dentry || IS_ERR(dentry)) return; parent = dentry->d_parent; diff --git a/security/integrity/ima/ima_audit.c b/security/integrity/ima/ima_audit.c index 1e082bb987be..ff513ff737f5 100644 --- a/security/integrity/ima/ima_audit.c +++ b/security/integrity/ima/ima_audit.c @@ -22,18 +22,9 @@ static int ima_audit; static int __init ima_audit_setup(char *str) { unsigned long audit; - int rc, result = 0; - char *op = "ima_audit"; - char *cause; - rc = strict_strtoul(str, 0, &audit); - if (rc || audit > 1) - result = 1; - else - ima_audit = audit; - cause = ima_audit ? "enabled" : "not_enabled"; - integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL, - op, cause, result, 0); + if (!strict_strtoul(str, 0, &audit)) + ima_audit = audit ? 1 : 0; return 1; } __setup("ima_audit=", ima_audit_setup); @@ -50,23 +41,14 @@ void integrity_audit_msg(int audit_msgno, struct inode *inode, ab = audit_log_start(current->audit_context, GFP_KERNEL, audit_msgno); audit_log_format(ab, "integrity: pid=%d uid=%u auid=%u ses=%u", - current->pid, current->cred->uid, + current->pid, current_cred()->uid, audit_get_loginuid(current), audit_get_sessionid(current)); audit_log_task_context(ab); - switch (audit_msgno) { - case AUDIT_INTEGRITY_DATA: - case AUDIT_INTEGRITY_METADATA: - case AUDIT_INTEGRITY_PCR: - case AUDIT_INTEGRITY_STATUS: - audit_log_format(ab, " op=%s cause=%s", op, cause); - break; - case AUDIT_INTEGRITY_HASH: - audit_log_format(ab, " op=%s hash=%s", op, cause); - break; - default: - audit_log_format(ab, " op=%s", op); - } + audit_log_format(ab, " op="); + audit_log_string(ab, op); + audit_log_format(ab, " cause="); + audit_log_string(ab, cause); audit_log_format(ab, " comm="); audit_log_untrustedstring(ab, current->comm); if (fname) { diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c index 50d572b74caf..63003a63aaee 100644 --- a/security/integrity/ima/ima_crypto.c +++ b/security/integrity/ima/ima_crypto.c @@ -103,7 +103,7 @@ int ima_calc_template_hash(int template_len, void *template, char *digest) return rc; } -static void ima_pcrread(int idx, u8 *pcr) +static void __init ima_pcrread(int idx, u8 *pcr) { if (!ima_used_chip) return; @@ -115,7 +115,7 @@ static void ima_pcrread(int idx, u8 *pcr) /* * Calculate the boot aggregate hash */ -int ima_calc_boot_aggregate(char *digest) +int __init ima_calc_boot_aggregate(char *digest) { struct hash_desc desc; struct scatterlist sg; diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index ffbe259700b1..6bfc7eaebfda 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c @@ -15,6 +15,7 @@ * implemenents security file system for reporting * current measurement list and IMA statistics */ +#include #include #include #include @@ -84,8 +85,8 @@ static void *ima_measurements_next(struct seq_file *m, void *v, loff_t *pos) * against concurrent list-extension */ rcu_read_lock(); - qe = list_entry(rcu_dereference(qe->later.next), - struct ima_queue_entry, later); + qe = list_entry_rcu(qe->later.next, + struct ima_queue_entry, later); rcu_read_unlock(); (*pos)++; @@ -283,6 +284,9 @@ static atomic_t policy_opencount = ATOMIC_INIT(1); */ int ima_open_policy(struct inode * inode, struct file * filp) { + /* No point in being allowed to open it if you aren't going to write */ + if (!(filp->f_flags & O_WRONLY)) + return -EACCES; if (atomic_dec_and_test(&policy_opencount)) return 0; return -EBUSY; @@ -315,7 +319,7 @@ static struct file_operations ima_measure_policy_ops = { .release = ima_release_policy }; -int ima_fs_init(void) +int __init ima_fs_init(void) { ima_dir = securityfs_create_dir("ima", NULL); if (IS_ERR(ima_dir)) @@ -349,7 +353,7 @@ int ima_fs_init(void) goto out; ima_policy = securityfs_create_file("policy", - S_IRUSR | S_IRGRP | S_IWUSR, + S_IWUSR, ima_dir, NULL, &ima_measure_policy_ops); if (IS_ERR(ima_policy)) diff --git a/security/integrity/ima/ima_iint.c b/security/integrity/ima/ima_iint.c index ec79f1ee992c..b8dd693f8790 100644 --- a/security/integrity/ima/ima_iint.c +++ b/security/integrity/ima/ima_iint.c @@ -196,7 +196,7 @@ static void init_once(void *foo) kref_set(&iint->refcount, 1); } -void ima_iintcache_init(void) +void __init ima_iintcache_init(void) { iint_cache = kmem_cache_create("iint_cache", sizeof(struct ima_iint_cache), 0, diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c index 0b0bb8c978cc..a40da7ae5900 100644 --- a/security/integrity/ima/ima_init.c +++ b/security/integrity/ima/ima_init.c @@ -38,7 +38,7 @@ int ima_used_chip; * a different value.) Violations add a zero entry to the measurement * list and extend the aggregate PCR value with ff...ff's. */ -static void ima_add_boot_aggregate(void) +static void __init ima_add_boot_aggregate(void) { struct ima_template_entry *entry; const char *op = "add_boot_aggregate"; @@ -71,7 +71,7 @@ err_out: audit_cause, result, 0); } -int ima_init(void) +int __init ima_init(void) { u8 pcr_i[IMA_DIGEST_SIZE]; int rc; diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index f4e7266f5aee..6f611874d10e 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -29,20 +29,8 @@ int ima_initialized; char *ima_hash = "sha1"; static int __init hash_setup(char *str) { - const char *op = "hash_setup"; - const char *hash = "sha1"; - int result = 0; - int audit_info = 0; - - if (strncmp(str, "md5", 3) == 0) { - hash = "md5"; - ima_hash = str; - } else if (strncmp(str, "sha1", 4) != 0) { - hash = "invalid_hash_type"; - result = 1; - } - integrity_audit_msg(AUDIT_INTEGRITY_HASH, NULL, NULL, op, hash, - result, audit_info); + if (strncmp(str, "md5", 3) == 0) + ima_hash = "md5"; return 1; } __setup("ima_hash=", hash_setup); @@ -128,10 +116,6 @@ static int get_path_measurement(struct ima_iint_cache *iint, struct file *file, { int rc = 0; - if (IS_ERR(file)) { - pr_info("%s dentry_open failed\n", filename); - return rc; - } iint->opencount++; iint->readcount++; @@ -141,6 +125,15 @@ static int get_path_measurement(struct ima_iint_cache *iint, struct file *file, return rc; } +static void ima_update_counts(struct ima_iint_cache *iint, int mask) +{ + iint->opencount++; + if ((mask & MAY_WRITE) || (mask == 0)) + iint->writecount++; + else if (mask & (MAY_READ | MAY_EXEC)) + iint->readcount++; +} + /** * ima_path_check - based on policy, collect/store measurement. * @path: contains a pointer to the path to be measured @@ -156,10 +149,10 @@ static int get_path_measurement(struct ima_iint_cache *iint, struct file *file, * - Opening a file for read when already open for write, * could result in a file measurement error. * - * Return 0 on success, an error code on failure. - * (Based on the results of appraise_measurement().) + * Always return 0 and audit dentry_open failures. + * (Return code will be based upon measurement appraisal.) */ -int ima_path_check(struct path *path, int mask) +int ima_path_check(struct path *path, int mask, int update_counts) { struct inode *inode = path->dentry->d_inode; struct ima_iint_cache *iint; @@ -173,11 +166,8 @@ int ima_path_check(struct path *path, int mask) return 0; mutex_lock(&iint->mutex); - iint->opencount++; - if ((mask & MAY_WRITE) || (mask == 0)) - iint->writecount++; - else if (mask & (MAY_READ | MAY_EXEC)) - iint->readcount++; + if (update_counts) + ima_update_counts(iint, mask); rc = ima_must_measure(iint, inode, MAY_READ, PATH_CHECK); if (rc < 0) @@ -196,7 +186,19 @@ int ima_path_check(struct path *path, int mask) struct dentry *dentry = dget(path->dentry); struct vfsmount *mnt = mntget(path->mnt); - file = dentry_open(dentry, mnt, O_RDONLY, current->cred); + file = dentry_open(dentry, mnt, O_RDONLY | O_LARGEFILE, + current_cred()); + if (IS_ERR(file)) { + int audit_info = 0; + + integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, + dentry->d_name.name, + "add_measurement", + "dentry_open failed", + 1, audit_info); + file = NULL; + goto out; + } rc = get_path_measurement(iint, file, dentry->d_name.name); } out: @@ -206,6 +208,7 @@ out: kref_put(&iint->refcount, iint_free); return 0; } +EXPORT_SYMBOL_GPL(ima_path_check); static int process_measurement(struct file *file, const unsigned char *filename, int mask, int function) @@ -234,7 +237,16 @@ out: return rc; } -static void opencount_get(struct file *file) +/* + * ima_opens_get - increment file counts + * + * - for IPC shm and shmat file. + * - for nfsd exported files. + * + * Increment the counts for these files to prevent unnecessary + * imbalance messages. + */ +void ima_counts_get(struct file *file) { struct inode *inode = file->f_dentry->d_inode; struct ima_iint_cache *iint; @@ -246,8 +258,14 @@ static void opencount_get(struct file *file) return; mutex_lock(&iint->mutex); iint->opencount++; + if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) + iint->readcount++; + + if (file->f_mode & FMODE_WRITE) + iint->writecount++; mutex_unlock(&iint->mutex); } +EXPORT_SYMBOL_GPL(ima_counts_get); /** * ima_file_mmap - based on policy, collect/store measurement. @@ -272,18 +290,6 @@ int ima_file_mmap(struct file *file, unsigned long prot) return 0; } -/* - * ima_shm_check - IPC shm and shmat create/fput a file - * - * Maintain the opencount for these files to prevent unnecessary - * imbalance messages. - */ -void ima_shm_check(struct file *file) -{ - opencount_get(file); - return; -} - /** * ima_bprm_check - based on policy, collect/store measurement. * @bprm: contains the linux_binprm structure diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index b5291ad5ef56..e1278399b345 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -45,24 +45,30 @@ struct ima_measure_rule_entry { } lsm[MAX_LSM_RULES]; }; -/* Without LSM specific knowledge, the default policy can only be +/* + * Without LSM specific knowledge, the default policy can only be * written in terms of .action, .func, .mask, .fsmagic, and .uid */ + +/* + * The minimum rule set to allow for full TCB coverage. Measures all files + * opened or mmap for exec and everything read by root. Dangerous because + * normal users can easily run the machine out of memory simply building + * and running executables. + */ static struct ima_measure_rule_entry default_rules[] = { - {.action = DONT_MEASURE,.fsmagic = PROC_SUPER_MAGIC, - .flags = IMA_FSMAGIC}, + {.action = DONT_MEASURE,.fsmagic = PROC_SUPER_MAGIC,.flags = IMA_FSMAGIC}, {.action = DONT_MEASURE,.fsmagic = SYSFS_MAGIC,.flags = IMA_FSMAGIC}, {.action = DONT_MEASURE,.fsmagic = DEBUGFS_MAGIC,.flags = IMA_FSMAGIC}, {.action = DONT_MEASURE,.fsmagic = TMPFS_MAGIC,.flags = IMA_FSMAGIC}, - {.action = DONT_MEASURE,.fsmagic = SECURITYFS_MAGIC, - .flags = IMA_FSMAGIC}, - {.action = DONT_MEASURE,.fsmagic = 0xF97CFF8C,.flags = IMA_FSMAGIC}, + {.action = DONT_MEASURE,.fsmagic = SECURITYFS_MAGIC,.flags = IMA_FSMAGIC}, + {.action = DONT_MEASURE,.fsmagic = SELINUX_MAGIC,.flags = IMA_FSMAGIC}, {.action = MEASURE,.func = FILE_MMAP,.mask = MAY_EXEC, .flags = IMA_FUNC | IMA_MASK}, {.action = MEASURE,.func = BPRM_CHECK,.mask = MAY_EXEC, .flags = IMA_FUNC | IMA_MASK}, {.action = MEASURE,.func = PATH_CHECK,.mask = MAY_READ,.uid = 0, - .flags = IMA_FUNC | IMA_MASK | IMA_UID} + .flags = IMA_FUNC | IMA_MASK | IMA_UID}, }; static LIST_HEAD(measure_default_rules); @@ -71,6 +77,14 @@ static struct list_head *ima_measure; static DEFINE_MUTEX(ima_measure_mutex); +static bool ima_use_tcb __initdata; +static int __init default_policy_setup(char *str) +{ + ima_use_tcb = 1; + return 1; +} +__setup("ima_tcb", default_policy_setup); + /** * ima_match_rules - determine whether an inode matches the measure rule. * @rule: a pointer to a rule @@ -96,7 +110,7 @@ static bool ima_match_rules(struct ima_measure_rule_entry *rule, if ((rule->flags & IMA_UID) && rule->uid != tsk->cred->uid) return false; for (i = 0; i < MAX_LSM_RULES; i++) { - int rc; + int rc = 0; u32 osid, sid; if (!rule->lsm[i].rule) @@ -109,7 +123,7 @@ static bool ima_match_rules(struct ima_measure_rule_entry *rule, security_inode_getsecid(inode, &osid); rc = security_filter_rule_match(osid, rule->lsm[i].type, - AUDIT_EQUAL, + Audit_equal, rule->lsm[i].rule, NULL); break; @@ -119,7 +133,7 @@ static bool ima_match_rules(struct ima_measure_rule_entry *rule, security_task_getsecid(tsk, &sid); rc = security_filter_rule_match(sid, rule->lsm[i].type, - AUDIT_EQUAL, + Audit_equal, rule->lsm[i].rule, NULL); default: @@ -164,11 +178,17 @@ int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask) * ima_measure points to either the measure_default_rules or the * the new measure_policy_rules. */ -void ima_init_policy(void) +void __init ima_init_policy(void) { - int i; + int i, entries; - for (i = 0; i < ARRAY_SIZE(default_rules); i++) + /* if !ima_use_tcb set entries = 0 so we load NO default rules */ + if (ima_use_tcb) + entries = ARRAY_SIZE(default_rules); + else + entries = 0; + + for (i = 0; i < entries; i++) list_add_tail(&default_rules[i].list, &measure_default_rules); ima_measure = &measure_default_rules; } @@ -227,7 +247,7 @@ static int ima_lsm_rule_init(struct ima_measure_rule_entry *entry, entry->lsm[lsm_rule].type = audit_type; result = security_filter_rule_init(entry->lsm[lsm_rule].type, - AUDIT_EQUAL, args, + Audit_equal, args, &entry->lsm[lsm_rule].rule); return result; } diff --git a/security/lsm_audit.c b/security/lsm_audit.c new file mode 100644 index 000000000000..94b868494b31 --- /dev/null +++ b/security/lsm_audit.c @@ -0,0 +1,386 @@ +/* + * common LSM auditing functions + * + * Based on code written for SELinux by : + * Stephen Smalley, + * James Morris + * Author : Etienne Basset, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * ipv4_skb_to_auditdata : fill auditdata from skb + * @skb : the skb + * @ad : the audit data to fill + * @proto : the layer 4 protocol + * + * return 0 on success + */ +int ipv4_skb_to_auditdata(struct sk_buff *skb, + struct common_audit_data *ad, u8 *proto) +{ + int ret = 0; + struct iphdr *ih; + + ih = ip_hdr(skb); + if (ih == NULL) + return -EINVAL; + + ad->u.net.v4info.saddr = ih->saddr; + ad->u.net.v4info.daddr = ih->daddr; + + if (proto) + *proto = ih->protocol; + /* non initial fragment */ + if (ntohs(ih->frag_off) & IP_OFFSET) + return 0; + + switch (ih->protocol) { + case IPPROTO_TCP: { + struct tcphdr *th = tcp_hdr(skb); + if (th == NULL) + break; + + ad->u.net.sport = th->source; + ad->u.net.dport = th->dest; + break; + } + case IPPROTO_UDP: { + struct udphdr *uh = udp_hdr(skb); + if (uh == NULL) + break; + + ad->u.net.sport = uh->source; + ad->u.net.dport = uh->dest; + break; + } + case IPPROTO_DCCP: { + struct dccp_hdr *dh = dccp_hdr(skb); + if (dh == NULL) + break; + + ad->u.net.sport = dh->dccph_sport; + ad->u.net.dport = dh->dccph_dport; + break; + } + case IPPROTO_SCTP: { + struct sctphdr *sh = sctp_hdr(skb); + if (sh == NULL) + break; + ad->u.net.sport = sh->source; + ad->u.net.dport = sh->dest; + break; + } + default: + ret = -EINVAL; + } + return ret; +} +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) +/** + * ipv6_skb_to_auditdata : fill auditdata from skb + * @skb : the skb + * @ad : the audit data to fill + * @proto : the layer 4 protocol + * + * return 0 on success + */ +int ipv6_skb_to_auditdata(struct sk_buff *skb, + struct common_audit_data *ad, u8 *proto) +{ + int offset, ret = 0; + struct ipv6hdr *ip6; + u8 nexthdr; + + ip6 = ipv6_hdr(skb); + if (ip6 == NULL) + return -EINVAL; + ipv6_addr_copy(&ad->u.net.v6info.saddr, &ip6->saddr); + ipv6_addr_copy(&ad->u.net.v6info.daddr, &ip6->daddr); + ret = 0; + /* IPv6 can have several extension header before the Transport header + * skip them */ + offset = skb_network_offset(skb); + offset += sizeof(*ip6); + nexthdr = ip6->nexthdr; + offset = ipv6_skip_exthdr(skb, offset, &nexthdr); + if (offset < 0) + return 0; + if (proto) + *proto = nexthdr; + switch (nexthdr) { + case IPPROTO_TCP: { + struct tcphdr _tcph, *th; + + th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph); + if (th == NULL) + break; + + ad->u.net.sport = th->source; + ad->u.net.dport = th->dest; + break; + } + case IPPROTO_UDP: { + struct udphdr _udph, *uh; + + uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph); + if (uh == NULL) + break; + + ad->u.net.sport = uh->source; + ad->u.net.dport = uh->dest; + break; + } + case IPPROTO_DCCP: { + struct dccp_hdr _dccph, *dh; + + dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph); + if (dh == NULL) + break; + + ad->u.net.sport = dh->dccph_sport; + ad->u.net.dport = dh->dccph_dport; + break; + } + case IPPROTO_SCTP: { + struct sctphdr _sctph, *sh; + + sh = skb_header_pointer(skb, offset, sizeof(_sctph), &_sctph); + if (sh == NULL) + break; + ad->u.net.sport = sh->source; + ad->u.net.dport = sh->dest; + break; + } + default: + ret = -EINVAL; + } + return ret; +} +#endif + + +static inline void print_ipv6_addr(struct audit_buffer *ab, + struct in6_addr *addr, __be16 port, + char *name1, char *name2) +{ + if (!ipv6_addr_any(addr)) + audit_log_format(ab, " %s=%pI6", name1, addr); + if (port) + audit_log_format(ab, " %s=%d", name2, ntohs(port)); +} + +static inline void print_ipv4_addr(struct audit_buffer *ab, __be32 addr, + __be16 port, char *name1, char *name2) +{ + if (addr) + audit_log_format(ab, " %s=%pI4", name1, &addr); + if (port) + audit_log_format(ab, " %s=%d", name2, ntohs(port)); +} + +/** + * dump_common_audit_data - helper to dump common audit data + * @a : common audit data + * + */ +static void dump_common_audit_data(struct audit_buffer *ab, + struct common_audit_data *a) +{ + struct inode *inode = NULL; + struct task_struct *tsk = current; + + if (a->tsk) + tsk = a->tsk; + if (tsk && tsk->pid) { + audit_log_format(ab, " pid=%d comm=", tsk->pid); + audit_log_untrustedstring(ab, tsk->comm); + } + + switch (a->type) { + case LSM_AUDIT_DATA_IPC: + audit_log_format(ab, " key=%d ", a->u.ipc_id); + break; + case LSM_AUDIT_DATA_CAP: + audit_log_format(ab, " capability=%d ", a->u.cap); + break; + case LSM_AUDIT_DATA_FS: + if (a->u.fs.path.dentry) { + struct dentry *dentry = a->u.fs.path.dentry; + if (a->u.fs.path.mnt) { + audit_log_d_path(ab, "path=", &a->u.fs.path); + } else { + audit_log_format(ab, " name="); + audit_log_untrustedstring(ab, + dentry->d_name.name); + } + inode = dentry->d_inode; + } else if (a->u.fs.inode) { + struct dentry *dentry; + inode = a->u.fs.inode; + dentry = d_find_alias(inode); + if (dentry) { + audit_log_format(ab, " name="); + audit_log_untrustedstring(ab, + dentry->d_name.name); + dput(dentry); + } + } + if (inode) + audit_log_format(ab, " dev=%s ino=%lu", + inode->i_sb->s_id, + inode->i_ino); + break; + case LSM_AUDIT_DATA_TASK: + tsk = a->u.tsk; + if (tsk && tsk->pid) { + audit_log_format(ab, " pid=%d comm=", tsk->pid); + audit_log_untrustedstring(ab, tsk->comm); + } + break; + case LSM_AUDIT_DATA_NET: + if (a->u.net.sk) { + struct sock *sk = a->u.net.sk; + struct unix_sock *u; + int len = 0; + char *p = NULL; + + switch (sk->sk_family) { + case AF_INET: { + struct inet_sock *inet = inet_sk(sk); + + print_ipv4_addr(ab, inet->rcv_saddr, + inet->sport, + "laddr", "lport"); + print_ipv4_addr(ab, inet->daddr, + inet->dport, + "faddr", "fport"); + break; + } + case AF_INET6: { + struct inet_sock *inet = inet_sk(sk); + struct ipv6_pinfo *inet6 = inet6_sk(sk); + + print_ipv6_addr(ab, &inet6->rcv_saddr, + inet->sport, + "laddr", "lport"); + print_ipv6_addr(ab, &inet6->daddr, + inet->dport, + "faddr", "fport"); + break; + } + case AF_UNIX: + u = unix_sk(sk); + if (u->dentry) { + struct path path = { + .dentry = u->dentry, + .mnt = u->mnt + }; + audit_log_d_path(ab, "path=", &path); + break; + } + if (!u->addr) + break; + len = u->addr->len-sizeof(short); + p = &u->addr->name->sun_path[0]; + audit_log_format(ab, " path="); + if (*p) + audit_log_untrustedstring(ab, p); + else + audit_log_n_hex(ab, p, len); + break; + } + } + + switch (a->u.net.family) { + case AF_INET: + print_ipv4_addr(ab, a->u.net.v4info.saddr, + a->u.net.sport, + "saddr", "src"); + print_ipv4_addr(ab, a->u.net.v4info.daddr, + a->u.net.dport, + "daddr", "dest"); + break; + case AF_INET6: + print_ipv6_addr(ab, &a->u.net.v6info.saddr, + a->u.net.sport, + "saddr", "src"); + print_ipv6_addr(ab, &a->u.net.v6info.daddr, + a->u.net.dport, + "daddr", "dest"); + break; + } + if (a->u.net.netif > 0) { + struct net_device *dev; + + /* NOTE: we always use init's namespace */ + dev = dev_get_by_index(&init_net, a->u.net.netif); + if (dev) { + audit_log_format(ab, " netif=%s", dev->name); + dev_put(dev); + } + } + break; +#ifdef CONFIG_KEYS + case LSM_AUDIT_DATA_KEY: + audit_log_format(ab, " key_serial=%u", a->u.key_struct.key); + if (a->u.key_struct.key_desc) { + audit_log_format(ab, " key_desc="); + audit_log_untrustedstring(ab, a->u.key_struct.key_desc); + } + break; +#endif + } /* switch (a->type) */ +} + +/** + * common_lsm_audit - generic LSM auditing function + * @a: auxiliary audit data + * + * setup the audit buffer for common security information + * uses callback to print LSM specific information + */ +void common_lsm_audit(struct common_audit_data *a) +{ + struct audit_buffer *ab; + + if (a == NULL) + return; + /* we use GFP_ATOMIC so we won't sleep */ + ab = audit_log_start(current->audit_context, GFP_ATOMIC, AUDIT_AVC); + + if (ab == NULL) + return; + + if (a->lsm_pre_audit) + a->lsm_pre_audit(ab, a); + + dump_common_audit_data(ab, a); + + if (a->lsm_post_audit) + a->lsm_post_audit(ab, a); + + audit_log_end(ab); +} diff --git a/security/root_plug.c b/security/root_plug.c index 40fb4f15e27b..2f7ffa67c4d2 100644 --- a/security/root_plug.c +++ b/security/root_plug.c @@ -71,18 +71,6 @@ static int rootplug_bprm_check_security (struct linux_binprm *bprm) } static struct security_operations rootplug_security_ops = { - /* Use the capability functions for some of the hooks */ - .ptrace_may_access = cap_ptrace_may_access, - .ptrace_traceme = cap_ptrace_traceme, - .capget = cap_capget, - .capset = cap_capset, - .capable = cap_capable, - - .bprm_set_creds = cap_bprm_set_creds, - - .task_fix_setuid = cap_task_fix_setuid, - .task_prctl = cap_task_prctl, - .bprm_check_security = rootplug_bprm_check_security, }; diff --git a/security/security.c b/security/security.c index 5284255c5cdf..dc7674fbfc7a 100644 --- a/security/security.c +++ b/security/security.c @@ -26,9 +26,6 @@ extern void security_fixup_ops(struct security_operations *ops); struct security_operations *security_ops; /* Initialized to NULL */ -/* amount of vm to protect from userspace access */ -unsigned long mmap_min_addr = CONFIG_SECURITY_DEFAULT_MMAP_MIN_ADDR; - static inline int verify(struct security_operations *ops) { /* verify the security_operations structure exists */ diff --git a/security/selinux/avc.c b/security/selinux/avc.c index 7f9b5fac8779..b2ab60859832 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c @@ -927,7 +927,7 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid, if (denied) { if (flags & AVC_STRICT) rc = -EACCES; - else if (!selinux_enforcing || security_permissive_sid(ssid)) + else if (!selinux_enforcing || (avd->flags & AVD_FLAGS_PERMISSIVE)) avc_update_node(AVC_CALLBACK_GRANT, requested, ssid, tsid, tclass, avd->seqno); else diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 2fcad7c33eaf..15c2a08a66f1 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1980,10 +1980,6 @@ static int selinux_sysctl(ctl_table *table, int op) u32 tsid, sid; int rc; - rc = secondary_ops->sysctl(table, op); - if (rc) - return rc; - sid = current_sid(); rc = selinux_sysctl_get_sid(table, (op == 0001) ? @@ -2375,10 +2371,8 @@ static void selinux_bprm_committed_creds(struct linux_binprm *bprm) { const struct task_security_struct *tsec = current_security(); struct itimerval itimer; - struct sighand_struct *psig; u32 osid, sid; int rc, i; - unsigned long flags; osid = tsec->osid; sid = tsec->sid; @@ -2398,22 +2392,20 @@ static void selinux_bprm_committed_creds(struct linux_binprm *bprm) memset(&itimer, 0, sizeof itimer); for (i = 0; i < 3; i++) do_setitimer(i, &itimer, NULL); - flush_signals(current); spin_lock_irq(¤t->sighand->siglock); - flush_signal_handlers(current, 1); - sigemptyset(¤t->blocked); - recalc_sigpending(); + if (!(current->signal->flags & SIGNAL_GROUP_EXIT)) { + __flush_signals(current); + flush_signal_handlers(current, 1); + sigemptyset(¤t->blocked); + } spin_unlock_irq(¤t->sighand->siglock); } /* Wake up the parent if it is waiting so that it can recheck * wait permission to the new task SID. */ - read_lock_irq(&tasklist_lock); - psig = current->parent->sighand; - spin_lock_irqsave(&psig->siglock, flags); - wake_up_interruptible(¤t->parent->signal->wait_chldexit); - spin_unlock_irqrestore(&psig->siglock, flags); - read_unlock_irq(&tasklist_lock); + read_lock(&tasklist_lock); + wake_up_interruptible(¤t->real_parent->signal->wait_chldexit); + read_unlock(&tasklist_lock); } /* superblock security operations */ @@ -4503,7 +4495,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, * when the packet is on it's final way out. * NOTE: there appear to be some IPv6 multicast cases where skb->dst * is NULL, in this case go ahead and apply access control. */ - if (skb->dst != NULL && skb->dst->xfrm != NULL) + if (skb_dst(skb) != NULL && skb_dst(skb)->xfrm != NULL) return NF_ACCEPT; #endif secmark_active = selinux_secmark_enabled(); diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index 5c3434f7626f..ca835795a8b3 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h @@ -8,14 +8,13 @@ #ifndef _SELINUX_SECURITY_H_ #define _SELINUX_SECURITY_H_ +#include #include "flask.h" #define SECSID_NULL 0x00000000 /* unspecified SID */ #define SECSID_WILD 0xffffffff /* wildcard SID */ #define SECCLASS_NULL 0x0000 /* no class */ -#define SELINUX_MAGIC 0xf97cff8c - /* Identify specific policy version changes */ #define POLICYDB_VERSION_BASE 15 #define POLICYDB_VERSION_BOOL 16 @@ -91,9 +90,11 @@ struct av_decision { u32 auditallow; u32 auditdeny; u32 seqno; + u32 flags; }; -int security_permissive_sid(u32 sid); +/* definitions of av_decision.flags */ +#define AVD_FLAGS_PERMISSIVE 0x0001 int security_compute_av(u32 ssid, u32 tsid, u16 tclass, u32 requested, diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c index c6875fd3b9d6..dd7cc6de77f9 100644 --- a/security/selinux/nlmsgtab.c +++ b/security/selinux/nlmsgtab.c @@ -112,6 +112,8 @@ static struct nlmsg_perm nlmsg_audit_perms[] = { AUDIT_DEL_RULE, NETLINK_AUDIT_SOCKET__NLMSG_WRITE }, { AUDIT_USER, NETLINK_AUDIT_SOCKET__NLMSG_RELAY }, { AUDIT_SIGNAL_INFO, NETLINK_AUDIT_SOCKET__NLMSG_READ }, + { AUDIT_TRIM, NETLINK_AUDIT_SOCKET__NLMSG_WRITE }, + { AUDIT_MAKE_EQUIV, NETLINK_AUDIT_SOCKET__NLMSG_WRITE }, { AUDIT_TTY_GET, NETLINK_AUDIT_SOCKET__NLMSG_READ }, { AUDIT_TTY_SET, NETLINK_AUDIT_SOCKET__NLMSG_TTY_AUDIT }, }; diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index 2d5136ec3d54..b4fc506e7a87 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -527,10 +527,10 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size) goto out2; length = scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, - "%x %x %x %x %u", + "%x %x %x %x %u %x", avd.allowed, 0xffffffff, avd.auditallow, avd.auditdeny, - avd.seqno); + avd.seqno, avd.flags); out2: kfree(tcon); out: @@ -803,10 +803,6 @@ static ssize_t sel_read_bool(struct file *filep, char __user *buf, goto out; } - if (count > PAGE_SIZE) { - ret = -EINVAL; - goto out; - } page = (char *)get_zeroed_page(GFP_KERNEL); if (!page) { ret = -ENOMEM; diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index deeec6c013ae..500e6f78e115 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -410,6 +410,7 @@ static int context_struct_compute_av(struct context *scontext, avd->auditallow = 0; avd->auditdeny = 0xffffffff; avd->seqno = latest_granting; + avd->flags = 0; /* * Check for all the invalid cases. @@ -528,31 +529,6 @@ inval_class: return 0; } -/* - * Given a sid find if the type has the permissive flag set - */ -int security_permissive_sid(u32 sid) -{ - struct context *context; - u32 type; - int rc; - - read_lock(&policy_rwlock); - - context = sidtab_search(&sidtab, sid); - BUG_ON(!context); - - type = context->type; - /* - * we are intentionally using type here, not type-1, the 0th bit may - * someday indicate that we are globally setting permissive in policy. - */ - rc = ebitmap_get_bit(&policydb.permissive_map, type); - - read_unlock(&policy_rwlock); - return rc; -} - static int security_validtrans_handle_fail(struct context *ocontext, struct context *ncontext, struct context *tcontext, @@ -767,6 +743,10 @@ int security_compute_av(u32 ssid, rc = context_struct_compute_av(scontext, tcontext, tclass, requested, avd); + + /* permissive domain? */ + if (ebitmap_get_bit(&policydb.permissive_map, scontext->type)) + avd->flags |= AVD_FLAGS_PERMISSIVE; out: read_unlock(&policy_rwlock); return rc; diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c index c0eb72013d67..72b18452e1a1 100644 --- a/security/selinux/xfrm.c +++ b/security/selinux/xfrm.c @@ -447,7 +447,7 @@ int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, struct dst_entry *dst; int rc = 0; - dst = skb->dst; + dst = skb_dst(skb); if (dst) { struct dst_entry *dst_test; diff --git a/security/smack/smack.h b/security/smack/smack.h index 42ef313f9856..243bec175be0 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h @@ -20,6 +20,7 @@ #include #include #include +#include /* * Why 23? CIPSO is constrained to 30, so a 32 byte buffer is @@ -178,6 +179,20 @@ struct smack_known { #define MAY_READWRITE (MAY_READ | MAY_WRITE) #define MAY_NOT 0 +/* + * Number of access types used by Smack (rwxa) + */ +#define SMK_NUM_ACCESS_TYPE 4 + +/* + * Smack audit data; is empty if CONFIG_AUDIT not set + * to save some stack + */ +struct smk_audit_info { +#ifdef CONFIG_AUDIT + struct common_audit_data a; +#endif +}; /* * These functions are in smack_lsm.c */ @@ -186,8 +201,8 @@ struct inode_smack *new_inode_smack(char *); /* * These functions are in smack_access.c */ -int smk_access(char *, char *, int); -int smk_curacc(char *, u32); +int smk_access(char *, char *, int, struct smk_audit_info *); +int smk_curacc(char *, u32, struct smk_audit_info *); int smack_to_cipso(const char *, struct smack_cipso *); void smack_from_cipso(u32, char *, char *); char *smack_from_secid(const u32); @@ -237,4 +252,93 @@ static inline char *smk_of_inode(const struct inode *isp) return sip->smk_inode; } +/* + * logging functions + */ +#define SMACK_AUDIT_DENIED 0x1 +#define SMACK_AUDIT_ACCEPT 0x2 +extern int log_policy; + +void smack_log(char *subject_label, char *object_label, + int request, + int result, struct smk_audit_info *auditdata); + +#ifdef CONFIG_AUDIT + +/* + * some inline functions to set up audit data + * they do nothing if CONFIG_AUDIT is not set + * + */ +static inline void smk_ad_init(struct smk_audit_info *a, const char *func, + char type) +{ + memset(a, 0, sizeof(*a)); + a->a.type = type; + a->a.function = func; +} + +static inline void smk_ad_setfield_u_tsk(struct smk_audit_info *a, + struct task_struct *t) +{ + a->a.u.tsk = t; +} +static inline void smk_ad_setfield_u_fs_path_dentry(struct smk_audit_info *a, + struct dentry *d) +{ + a->a.u.fs.path.dentry = d; +} +static inline void smk_ad_setfield_u_fs_path_mnt(struct smk_audit_info *a, + struct vfsmount *m) +{ + a->a.u.fs.path.mnt = m; +} +static inline void smk_ad_setfield_u_fs_inode(struct smk_audit_info *a, + struct inode *i) +{ + a->a.u.fs.inode = i; +} +static inline void smk_ad_setfield_u_fs_path(struct smk_audit_info *a, + struct path p) +{ + a->a.u.fs.path = p; +} +static inline void smk_ad_setfield_u_net_sk(struct smk_audit_info *a, + struct sock *sk) +{ + a->a.u.net.sk = sk; +} + +#else /* no AUDIT */ + +static inline void smk_ad_init(struct smk_audit_info *a, const char *func, + char type) +{ +} +static inline void smk_ad_setfield_u_tsk(struct smk_audit_info *a, + struct task_struct *t) +{ +} +static inline void smk_ad_setfield_u_fs_path_dentry(struct smk_audit_info *a, + struct dentry *d) +{ +} +static inline void smk_ad_setfield_u_fs_path_mnt(struct smk_audit_info *a, + struct vfsmount *m) +{ +} +static inline void smk_ad_setfield_u_fs_inode(struct smk_audit_info *a, + struct inode *i) +{ +} +static inline void smk_ad_setfield_u_fs_path(struct smk_audit_info *a, + struct path p) +{ +} +static inline void smk_ad_setfield_u_net_sk(struct smk_audit_info *a, + struct sock *sk) +{ +} +#endif + #endif /* _SECURITY_SMACK_H */ diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c index ac0a2707f6d4..513dc1aa16dd 100644 --- a/security/smack/smack_access.c +++ b/security/smack/smack_access.c @@ -59,11 +59,18 @@ LIST_HEAD(smack_known_list); */ static u32 smack_next_secid = 10; +/* + * what events do we log + * can be overwritten at run-time by /smack/logging + */ +int log_policy = SMACK_AUDIT_DENIED; + /** * smk_access - determine if a subject has a specific access to an object * @subject_label: a pointer to the subject's Smack label * @object_label: a pointer to the object's Smack label * @request: the access requested, in "MAY" format + * @a : a pointer to the audit data * * This function looks up the subject/object pair in the * access rule list and returns 0 if the access is permitted, @@ -78,10 +85,12 @@ static u32 smack_next_secid = 10; * will be on the list, so checking the pointers may be a worthwhile * optimization. */ -int smk_access(char *subject_label, char *object_label, int request) +int smk_access(char *subject_label, char *object_label, int request, + struct smk_audit_info *a) { u32 may = MAY_NOT; struct smack_rule *srp; + int rc = 0; /* * Hardcoded comparisons. @@ -89,8 +98,10 @@ int smk_access(char *subject_label, char *object_label, int request) * A star subject can't access any object. */ if (subject_label == smack_known_star.smk_known || - strcmp(subject_label, smack_known_star.smk_known) == 0) - return -EACCES; + strcmp(subject_label, smack_known_star.smk_known) == 0) { + rc = -EACCES; + goto out_audit; + } /* * An internet object can be accessed by any subject. * Tasks cannot be assigned the internet label. @@ -100,20 +111,20 @@ int smk_access(char *subject_label, char *object_label, int request) subject_label == smack_known_web.smk_known || strcmp(object_label, smack_known_web.smk_known) == 0 || strcmp(subject_label, smack_known_web.smk_known) == 0) - return 0; + goto out_audit; /* * A star object can be accessed by any subject. */ if (object_label == smack_known_star.smk_known || strcmp(object_label, smack_known_star.smk_known) == 0) - return 0; + goto out_audit; /* * An object can be accessed in any way by a subject * with the same label. */ if (subject_label == object_label || strcmp(subject_label, object_label) == 0) - return 0; + goto out_audit; /* * A hat subject can read any object. * A floor object can be read by any subject. @@ -121,10 +132,10 @@ int smk_access(char *subject_label, char *object_label, int request) if ((request & MAY_ANYREAD) == request) { if (object_label == smack_known_floor.smk_known || strcmp(object_label, smack_known_floor.smk_known) == 0) - return 0; + goto out_audit; if (subject_label == smack_known_hat.smk_known || strcmp(subject_label, smack_known_hat.smk_known) == 0) - return 0; + goto out_audit; } /* * Beyond here an explicit relationship is required. @@ -148,28 +159,36 @@ int smk_access(char *subject_label, char *object_label, int request) * This is a bit map operation. */ if ((request & may) == request) - return 0; + goto out_audit; - return -EACCES; + rc = -EACCES; +out_audit: +#ifdef CONFIG_AUDIT + if (a) + smack_log(subject_label, object_label, request, rc, a); +#endif + return rc; } /** * smk_curacc - determine if current has a specific access to an object * @obj_label: a pointer to the object's Smack label * @mode: the access requested, in "MAY" format + * @a : common audit data * * This function checks the current subject label/object label pair * in the access rule list and returns 0 if the access is permitted, * non zero otherwise. It allows that current may have the capability * to override the rules. */ -int smk_curacc(char *obj_label, u32 mode) +int smk_curacc(char *obj_label, u32 mode, struct smk_audit_info *a) { int rc; + char *sp = current_security(); - rc = smk_access(current_security(), obj_label, mode); + rc = smk_access(sp, obj_label, mode, NULL); if (rc == 0) - return 0; + goto out_audit; /* * Return if a specific label has been designated as the @@ -177,14 +196,105 @@ int smk_curacc(char *obj_label, u32 mode) * have that label. */ if (smack_onlycap != NULL && smack_onlycap != current->cred->security) - return rc; + goto out_audit; if (capable(CAP_MAC_OVERRIDE)) return 0; +out_audit: +#ifdef CONFIG_AUDIT + if (a) + smack_log(sp, obj_label, mode, rc, a); +#endif return rc; } +#ifdef CONFIG_AUDIT +/** + * smack_str_from_perm : helper to transalate an int to a + * readable string + * @string : the string to fill + * @access : the int + * + */ +static inline void smack_str_from_perm(char *string, int access) +{ + int i = 0; + if (access & MAY_READ) + string[i++] = 'r'; + if (access & MAY_WRITE) + string[i++] = 'w'; + if (access & MAY_EXEC) + string[i++] = 'x'; + if (access & MAY_APPEND) + string[i++] = 'a'; + string[i] = '\0'; +} +/** + * smack_log_callback - SMACK specific information + * will be called by generic audit code + * @ab : the audit_buffer + * @a : audit_data + * + */ +static void smack_log_callback(struct audit_buffer *ab, void *a) +{ + struct common_audit_data *ad = a; + struct smack_audit_data *sad = &ad->lsm_priv.smack_audit_data; + audit_log_format(ab, "lsm=SMACK fn=%s action=%s", ad->function, + sad->result ? "denied" : "granted"); + audit_log_format(ab, " subject="); + audit_log_untrustedstring(ab, sad->subject); + audit_log_format(ab, " object="); + audit_log_untrustedstring(ab, sad->object); + audit_log_format(ab, " requested=%s", sad->request); +} + +/** + * smack_log - Audit the granting or denial of permissions. + * @subject_label : smack label of the requester + * @object_label : smack label of the object being accessed + * @request: requested permissions + * @result: result from smk_access + * @a: auxiliary audit data + * + * Audit the granting or denial of permissions in accordance + * with the policy. + */ +void smack_log(char *subject_label, char *object_label, int request, + int result, struct smk_audit_info *ad) +{ + char request_buffer[SMK_NUM_ACCESS_TYPE + 1]; + struct smack_audit_data *sad; + struct common_audit_data *a = &ad->a; + + /* check if we have to log the current event */ + if (result != 0 && (log_policy & SMACK_AUDIT_DENIED) == 0) + return; + if (result == 0 && (log_policy & SMACK_AUDIT_ACCEPT) == 0) + return; + + if (a->function == NULL) + a->function = "unknown"; + + /* end preparing the audit data */ + sad = &a->lsm_priv.smack_audit_data; + smack_str_from_perm(request_buffer, request); + sad->subject = subject_label; + sad->object = object_label; + sad->request = request_buffer; + sad->result = result; + a->lsm_pre_audit = smack_log_callback; + + common_lsm_audit(a); +} +#else /* #ifdef CONFIG_AUDIT */ +void smack_log(char *subject_label, char *object_label, int request, + int result, struct smk_audit_info *ad) +{ +} +#endif + static DEFINE_MUTEX(smack_known_lock); /** @@ -209,7 +319,8 @@ struct smack_known *smk_import_entry(const char *string, int len) if (found) smack[i] = '\0'; else if (i >= len || string[i] > '~' || string[i] <= ' ' || - string[i] == '/') { + string[i] == '/' || string[i] == '"' || + string[i] == '\\' || string[i] == '\'') { smack[i] = '\0'; found = 1; } else diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 98b3195347ab..0023182078c7 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -30,7 +30,6 @@ #include #include #include - #include "smack.h" #define task_security(task) (task_cred_xxx((task), security)) @@ -103,14 +102,24 @@ struct inode_smack *new_inode_smack(char *smack) static int smack_ptrace_may_access(struct task_struct *ctp, unsigned int mode) { int rc; + struct smk_audit_info ad; + char *sp, *tsp; rc = cap_ptrace_may_access(ctp, mode); if (rc != 0) return rc; - rc = smk_access(current_security(), task_security(ctp), MAY_READWRITE); + sp = current_security(); + tsp = task_security(ctp); + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); + smk_ad_setfield_u_tsk(&ad, ctp); + + /* we won't log here, because rc can be overriden */ + rc = smk_access(sp, tsp, MAY_READWRITE, NULL); if (rc != 0 && capable(CAP_MAC_OVERRIDE)) - return 0; + rc = 0; + + smack_log(sp, tsp, MAY_READWRITE, rc, &ad); return rc; } @@ -125,14 +134,24 @@ static int smack_ptrace_may_access(struct task_struct *ctp, unsigned int mode) static int smack_ptrace_traceme(struct task_struct *ptp) { int rc; + struct smk_audit_info ad; + char *sp, *tsp; rc = cap_ptrace_traceme(ptp); if (rc != 0) return rc; - rc = smk_access(task_security(ptp), current_security(), MAY_READWRITE); + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); + smk_ad_setfield_u_tsk(&ad, ptp); + + sp = current_security(); + tsp = task_security(ptp); + /* we won't log here, because rc can be overriden */ + rc = smk_access(tsp, sp, MAY_READWRITE, NULL); if (rc != 0 && has_capability(ptp, CAP_MAC_OVERRIDE)) - return 0; + rc = 0; + + smack_log(tsp, sp, MAY_READWRITE, rc, &ad); return rc; } @@ -327,8 +346,14 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data) static int smack_sb_statfs(struct dentry *dentry) { struct superblock_smack *sbp = dentry->d_sb->s_security; + int rc; + struct smk_audit_info ad; - return smk_curacc(sbp->smk_floor, MAY_READ); + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); + smk_ad_setfield_u_fs_path_dentry(&ad, dentry); + + rc = smk_curacc(sbp->smk_floor, MAY_READ, &ad); + return rc; } /** @@ -346,8 +371,12 @@ static int smack_sb_mount(char *dev_name, struct path *path, char *type, unsigned long flags, void *data) { struct superblock_smack *sbp = path->mnt->mnt_sb->s_security; + struct smk_audit_info ad; - return smk_curacc(sbp->smk_floor, MAY_WRITE); + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); + smk_ad_setfield_u_fs_path(&ad, *path); + + return smk_curacc(sbp->smk_floor, MAY_WRITE, &ad); } /** @@ -361,10 +390,14 @@ static int smack_sb_mount(char *dev_name, struct path *path, static int smack_sb_umount(struct vfsmount *mnt, int flags) { struct superblock_smack *sbp; + struct smk_audit_info ad; + + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); + smk_ad_setfield_u_fs_path_dentry(&ad, mnt->mnt_mountpoint); + smk_ad_setfield_u_fs_path_mnt(&ad, mnt); sbp = mnt->mnt_sb->s_security; - - return smk_curacc(sbp->smk_floor, MAY_WRITE); + return smk_curacc(sbp->smk_floor, MAY_WRITE, &ad); } /* @@ -441,15 +474,20 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir, static int smack_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) { - int rc; char *isp; + struct smk_audit_info ad; + int rc; + + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); + smk_ad_setfield_u_fs_path_dentry(&ad, old_dentry); isp = smk_of_inode(old_dentry->d_inode); - rc = smk_curacc(isp, MAY_WRITE); + rc = smk_curacc(isp, MAY_WRITE, &ad); if (rc == 0 && new_dentry->d_inode != NULL) { isp = smk_of_inode(new_dentry->d_inode); - rc = smk_curacc(isp, MAY_WRITE); + smk_ad_setfield_u_fs_path_dentry(&ad, new_dentry); + rc = smk_curacc(isp, MAY_WRITE, &ad); } return rc; @@ -466,18 +504,24 @@ static int smack_inode_link(struct dentry *old_dentry, struct inode *dir, static int smack_inode_unlink(struct inode *dir, struct dentry *dentry) { struct inode *ip = dentry->d_inode; + struct smk_audit_info ad; int rc; + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); + smk_ad_setfield_u_fs_path_dentry(&ad, dentry); + /* * You need write access to the thing you're unlinking */ - rc = smk_curacc(smk_of_inode(ip), MAY_WRITE); - if (rc == 0) + rc = smk_curacc(smk_of_inode(ip), MAY_WRITE, &ad); + if (rc == 0) { /* * You also need write access to the containing directory */ - rc = smk_curacc(smk_of_inode(dir), MAY_WRITE); - + smk_ad_setfield_u_fs_path_dentry(&ad, NULL); + smk_ad_setfield_u_fs_inode(&ad, dir); + rc = smk_curacc(smk_of_inode(dir), MAY_WRITE, &ad); + } return rc; } @@ -491,17 +535,24 @@ static int smack_inode_unlink(struct inode *dir, struct dentry *dentry) */ static int smack_inode_rmdir(struct inode *dir, struct dentry *dentry) { + struct smk_audit_info ad; int rc; + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); + smk_ad_setfield_u_fs_path_dentry(&ad, dentry); + /* * You need write access to the thing you're removing */ - rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE); - if (rc == 0) + rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad); + if (rc == 0) { /* * You also need write access to the containing directory */ - rc = smk_curacc(smk_of_inode(dir), MAY_WRITE); + smk_ad_setfield_u_fs_path_dentry(&ad, NULL); + smk_ad_setfield_u_fs_inode(&ad, dir); + rc = smk_curacc(smk_of_inode(dir), MAY_WRITE, &ad); + } return rc; } @@ -525,15 +576,19 @@ static int smack_inode_rename(struct inode *old_inode, { int rc; char *isp; + struct smk_audit_info ad; + + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); + smk_ad_setfield_u_fs_path_dentry(&ad, old_dentry); isp = smk_of_inode(old_dentry->d_inode); - rc = smk_curacc(isp, MAY_READWRITE); + rc = smk_curacc(isp, MAY_READWRITE, &ad); if (rc == 0 && new_dentry->d_inode != NULL) { isp = smk_of_inode(new_dentry->d_inode); - rc = smk_curacc(isp, MAY_READWRITE); + smk_ad_setfield_u_fs_path_dentry(&ad, new_dentry); + rc = smk_curacc(isp, MAY_READWRITE, &ad); } - return rc; } @@ -548,13 +603,15 @@ static int smack_inode_rename(struct inode *old_inode, */ static int smack_inode_permission(struct inode *inode, int mask) { + struct smk_audit_info ad; /* * No permission to check. Existence test. Yup, it's there. */ if (mask == 0) return 0; - - return smk_curacc(smk_of_inode(inode), mask); + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); + smk_ad_setfield_u_fs_inode(&ad, inode); + return smk_curacc(smk_of_inode(inode), mask, &ad); } /** @@ -566,13 +623,16 @@ static int smack_inode_permission(struct inode *inode, int mask) */ static int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr) { + struct smk_audit_info ad; /* * Need to allow for clearing the setuid bit. */ if (iattr->ia_valid & ATTR_FORCE) return 0; + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); + smk_ad_setfield_u_fs_path_dentry(&ad, dentry); - return smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE); + return smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad); } /** @@ -584,7 +644,12 @@ static int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr) */ static int smack_inode_getattr(struct vfsmount *mnt, struct dentry *dentry) { - return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ); + struct smk_audit_info ad; + + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); + smk_ad_setfield_u_fs_path_dentry(&ad, dentry); + smk_ad_setfield_u_fs_path_mnt(&ad, mnt); + return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ, &ad); } /** @@ -602,6 +667,7 @@ static int smack_inode_getattr(struct vfsmount *mnt, struct dentry *dentry) static int smack_inode_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { + struct smk_audit_info ad; int rc = 0; if (strcmp(name, XATTR_NAME_SMACK) == 0 || @@ -619,8 +685,11 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name, } else rc = cap_inode_setxattr(dentry, name, value, size, flags); + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); + smk_ad_setfield_u_fs_path_dentry(&ad, dentry); + if (rc == 0) - rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE); + rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad); return rc; } @@ -672,7 +741,12 @@ static void smack_inode_post_setxattr(struct dentry *dentry, const char *name, */ static int smack_inode_getxattr(struct dentry *dentry, const char *name) { - return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ); + struct smk_audit_info ad; + + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); + smk_ad_setfield_u_fs_path_dentry(&ad, dentry); + + return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ, &ad); } /* @@ -686,6 +760,7 @@ static int smack_inode_getxattr(struct dentry *dentry, const char *name) */ static int smack_inode_removexattr(struct dentry *dentry, const char *name) { + struct smk_audit_info ad; int rc = 0; if (strcmp(name, XATTR_NAME_SMACK) == 0 || @@ -696,8 +771,10 @@ static int smack_inode_removexattr(struct dentry *dentry, const char *name) } else rc = cap_inode_removexattr(dentry, name); + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); + smk_ad_setfield_u_fs_path_dentry(&ad, dentry); if (rc == 0) - rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE); + rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad); return rc; } @@ -856,12 +933,16 @@ static int smack_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int rc = 0; + struct smk_audit_info ad; + + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); + smk_ad_setfield_u_fs_path(&ad, file->f_path); if (_IOC_DIR(cmd) & _IOC_WRITE) - rc = smk_curacc(file->f_security, MAY_WRITE); + rc = smk_curacc(file->f_security, MAY_WRITE, &ad); if (rc == 0 && (_IOC_DIR(cmd) & _IOC_READ)) - rc = smk_curacc(file->f_security, MAY_READ); + rc = smk_curacc(file->f_security, MAY_READ, &ad); return rc; } @@ -875,7 +956,11 @@ static int smack_file_ioctl(struct file *file, unsigned int cmd, */ static int smack_file_lock(struct file *file, unsigned int cmd) { - return smk_curacc(file->f_security, MAY_WRITE); + struct smk_audit_info ad; + + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); + smk_ad_setfield_u_fs_path_dentry(&ad, file->f_path.dentry); + return smk_curacc(file->f_security, MAY_WRITE, &ad); } /** @@ -889,8 +974,12 @@ static int smack_file_lock(struct file *file, unsigned int cmd) static int smack_file_fcntl(struct file *file, unsigned int cmd, unsigned long arg) { + struct smk_audit_info ad; int rc; + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); + smk_ad_setfield_u_fs_path(&ad, file->f_path); + switch (cmd) { case F_DUPFD: case F_GETFD: @@ -898,7 +987,7 @@ static int smack_file_fcntl(struct file *file, unsigned int cmd, case F_GETLK: case F_GETOWN: case F_GETSIG: - rc = smk_curacc(file->f_security, MAY_READ); + rc = smk_curacc(file->f_security, MAY_READ, &ad); break; case F_SETFD: case F_SETFL: @@ -906,10 +995,10 @@ static int smack_file_fcntl(struct file *file, unsigned int cmd, case F_SETLKW: case F_SETOWN: case F_SETSIG: - rc = smk_curacc(file->f_security, MAY_WRITE); + rc = smk_curacc(file->f_security, MAY_WRITE, &ad); break; default: - rc = smk_curacc(file->f_security, MAY_READWRITE); + rc = smk_curacc(file->f_security, MAY_READWRITE, &ad); } return rc; @@ -944,14 +1033,21 @@ static int smack_file_send_sigiotask(struct task_struct *tsk, { struct file *file; int rc; + char *tsp = tsk->cred->security; + struct smk_audit_info ad; /* * struct fown_struct is never outside the context of a struct file */ file = container_of(fown, struct file, f_owner); - rc = smk_access(file->f_security, tsk->cred->security, MAY_WRITE); + /* we don't log here as rc can be overriden */ + rc = smk_access(file->f_security, tsp, MAY_WRITE, NULL); if (rc != 0 && has_capability(tsk, CAP_MAC_OVERRIDE)) - return 0; + rc = 0; + + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); + smk_ad_setfield_u_tsk(&ad, tsk); + smack_log(file->f_security, tsp, MAY_WRITE, rc, &ad); return rc; } @@ -964,7 +1060,10 @@ static int smack_file_send_sigiotask(struct task_struct *tsk, static int smack_file_receive(struct file *file) { int may = 0; + struct smk_audit_info ad; + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); + smk_ad_setfield_u_fs_path(&ad, file->f_path); /* * This code relies on bitmasks. */ @@ -973,7 +1072,7 @@ static int smack_file_receive(struct file *file) if (file->f_mode & FMODE_WRITE) may |= MAY_WRITE; - return smk_curacc(file->f_security, may); + return smk_curacc(file->f_security, may, &ad); } /* @@ -1052,6 +1151,22 @@ static int smack_kernel_create_files_as(struct cred *new, return 0; } +/** + * smk_curacc_on_task - helper to log task related access + * @p: the task object + * @access : the access requested + * + * Return 0 if access is permitted + */ +static int smk_curacc_on_task(struct task_struct *p, int access) +{ + struct smk_audit_info ad; + + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); + smk_ad_setfield_u_tsk(&ad, p); + return smk_curacc(task_security(p), access, &ad); +} + /** * smack_task_setpgid - Smack check on setting pgid * @p: the task object @@ -1061,7 +1176,7 @@ static int smack_kernel_create_files_as(struct cred *new, */ static int smack_task_setpgid(struct task_struct *p, pid_t pgid) { - return smk_curacc(task_security(p), MAY_WRITE); + return smk_curacc_on_task(p, MAY_WRITE); } /** @@ -1072,7 +1187,7 @@ static int smack_task_setpgid(struct task_struct *p, pid_t pgid) */ static int smack_task_getpgid(struct task_struct *p) { - return smk_curacc(task_security(p), MAY_READ); + return smk_curacc_on_task(p, MAY_READ); } /** @@ -1083,7 +1198,7 @@ static int smack_task_getpgid(struct task_struct *p) */ static int smack_task_getsid(struct task_struct *p) { - return smk_curacc(task_security(p), MAY_READ); + return smk_curacc_on_task(p, MAY_READ); } /** @@ -1111,7 +1226,7 @@ static int smack_task_setnice(struct task_struct *p, int nice) rc = cap_task_setnice(p, nice); if (rc == 0) - rc = smk_curacc(task_security(p), MAY_WRITE); + rc = smk_curacc_on_task(p, MAY_WRITE); return rc; } @@ -1128,7 +1243,7 @@ static int smack_task_setioprio(struct task_struct *p, int ioprio) rc = cap_task_setioprio(p, ioprio); if (rc == 0) - rc = smk_curacc(task_security(p), MAY_WRITE); + rc = smk_curacc_on_task(p, MAY_WRITE); return rc; } @@ -1140,7 +1255,7 @@ static int smack_task_setioprio(struct task_struct *p, int ioprio) */ static int smack_task_getioprio(struct task_struct *p) { - return smk_curacc(task_security(p), MAY_READ); + return smk_curacc_on_task(p, MAY_READ); } /** @@ -1158,7 +1273,7 @@ static int smack_task_setscheduler(struct task_struct *p, int policy, rc = cap_task_setscheduler(p, policy, lp); if (rc == 0) - rc = smk_curacc(task_security(p), MAY_WRITE); + rc = smk_curacc_on_task(p, MAY_WRITE); return rc; } @@ -1170,7 +1285,7 @@ static int smack_task_setscheduler(struct task_struct *p, int policy, */ static int smack_task_getscheduler(struct task_struct *p) { - return smk_curacc(task_security(p), MAY_READ); + return smk_curacc_on_task(p, MAY_READ); } /** @@ -1181,7 +1296,7 @@ static int smack_task_getscheduler(struct task_struct *p) */ static int smack_task_movememory(struct task_struct *p) { - return smk_curacc(task_security(p), MAY_WRITE); + return smk_curacc_on_task(p, MAY_WRITE); } /** @@ -1199,18 +1314,23 @@ static int smack_task_movememory(struct task_struct *p) static int smack_task_kill(struct task_struct *p, struct siginfo *info, int sig, u32 secid) { + struct smk_audit_info ad; + + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); + smk_ad_setfield_u_tsk(&ad, p); /* * Sending a signal requires that the sender * can write the receiver. */ if (secid == 0) - return smk_curacc(task_security(p), MAY_WRITE); + return smk_curacc(task_security(p), MAY_WRITE, &ad); /* * If the secid isn't 0 we're dealing with some USB IO * specific behavior. This is not clean. For one thing * we can't take privilege into account. */ - return smk_access(smack_from_secid(secid), task_security(p), MAY_WRITE); + return smk_access(smack_from_secid(secid), task_security(p), + MAY_WRITE, &ad); } /** @@ -1221,11 +1341,15 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info, */ static int smack_task_wait(struct task_struct *p) { + struct smk_audit_info ad; + char *sp = current_security(); + char *tsp = task_security(p); int rc; - rc = smk_access(current_security(), task_security(p), MAY_WRITE); + /* we don't log here, we can be overriden */ + rc = smk_access(sp, tsp, MAY_WRITE, NULL); if (rc == 0) - return 0; + goto out_log; /* * Allow the operation to succeed if either task @@ -1239,8 +1363,12 @@ static int smack_task_wait(struct task_struct *p) * the smack value. */ if (capable(CAP_MAC_OVERRIDE) || has_capability(p, CAP_MAC_OVERRIDE)) - return 0; - + rc = 0; + /* we log only if we didn't get overriden */ + out_log: + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); + smk_ad_setfield_u_tsk(&ad, p); + smack_log(sp, tsp, MAY_WRITE, rc, &ad); return rc; } @@ -1456,12 +1584,19 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap) int sk_lbl; char *hostsp; struct socket_smack *ssp = sk->sk_security; + struct smk_audit_info ad; rcu_read_lock(); hostsp = smack_host_label(sap); if (hostsp != NULL) { sk_lbl = SMACK_UNLABELED_SOCKET; - rc = smk_access(ssp->smk_out, hostsp, MAY_WRITE); +#ifdef CONFIG_AUDIT + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_NET); + ad.a.u.net.family = sap->sin_family; + ad.a.u.net.dport = sap->sin_port; + ad.a.u.net.v4info.daddr = sap->sin_addr.s_addr; +#endif + rc = smk_access(ssp->smk_out, hostsp, MAY_WRITE, &ad); } else { sk_lbl = SMACK_CIPSO_SOCKET; rc = 0; @@ -1656,6 +1791,25 @@ static void smack_shm_free_security(struct shmid_kernel *shp) isp->security = NULL; } +/** + * smk_curacc_shm : check if current has access on shm + * @shp : the object + * @access : access requested + * + * Returns 0 if current has the requested access, error code otherwise + */ +static int smk_curacc_shm(struct shmid_kernel *shp, int access) +{ + char *ssp = smack_of_shm(shp); + struct smk_audit_info ad; + +#ifdef CONFIG_AUDIT + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_IPC); + ad.a.u.ipc_id = shp->shm_perm.id; +#endif + return smk_curacc(ssp, access, &ad); +} + /** * smack_shm_associate - Smack access check for shm * @shp: the object @@ -1665,11 +1819,10 @@ static void smack_shm_free_security(struct shmid_kernel *shp) */ static int smack_shm_associate(struct shmid_kernel *shp, int shmflg) { - char *ssp = smack_of_shm(shp); int may; may = smack_flags_to_may(shmflg); - return smk_curacc(ssp, may); + return smk_curacc_shm(shp, may); } /** @@ -1681,7 +1834,6 @@ static int smack_shm_associate(struct shmid_kernel *shp, int shmflg) */ static int smack_shm_shmctl(struct shmid_kernel *shp, int cmd) { - char *ssp; int may; switch (cmd) { @@ -1704,9 +1856,7 @@ static int smack_shm_shmctl(struct shmid_kernel *shp, int cmd) default: return -EINVAL; } - - ssp = smack_of_shm(shp); - return smk_curacc(ssp, may); + return smk_curacc_shm(shp, may); } /** @@ -1720,11 +1870,10 @@ static int smack_shm_shmctl(struct shmid_kernel *shp, int cmd) static int smack_shm_shmat(struct shmid_kernel *shp, char __user *shmaddr, int shmflg) { - char *ssp = smack_of_shm(shp); int may; may = smack_flags_to_may(shmflg); - return smk_curacc(ssp, may); + return smk_curacc_shm(shp, may); } /** @@ -1765,6 +1914,25 @@ static void smack_sem_free_security(struct sem_array *sma) isp->security = NULL; } +/** + * smk_curacc_sem : check if current has access on sem + * @sma : the object + * @access : access requested + * + * Returns 0 if current has the requested access, error code otherwise + */ +static int smk_curacc_sem(struct sem_array *sma, int access) +{ + char *ssp = smack_of_sem(sma); + struct smk_audit_info ad; + +#ifdef CONFIG_AUDIT + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_IPC); + ad.a.u.ipc_id = sma->sem_perm.id; +#endif + return smk_curacc(ssp, access, &ad); +} + /** * smack_sem_associate - Smack access check for sem * @sma: the object @@ -1774,11 +1942,10 @@ static void smack_sem_free_security(struct sem_array *sma) */ static int smack_sem_associate(struct sem_array *sma, int semflg) { - char *ssp = smack_of_sem(sma); int may; may = smack_flags_to_may(semflg); - return smk_curacc(ssp, may); + return smk_curacc_sem(sma, may); } /** @@ -1790,7 +1957,6 @@ static int smack_sem_associate(struct sem_array *sma, int semflg) */ static int smack_sem_semctl(struct sem_array *sma, int cmd) { - char *ssp; int may; switch (cmd) { @@ -1819,8 +1985,7 @@ static int smack_sem_semctl(struct sem_array *sma, int cmd) return -EINVAL; } - ssp = smack_of_sem(sma); - return smk_curacc(ssp, may); + return smk_curacc_sem(sma, may); } /** @@ -1837,9 +2002,7 @@ static int smack_sem_semctl(struct sem_array *sma, int cmd) static int smack_sem_semop(struct sem_array *sma, struct sembuf *sops, unsigned nsops, int alter) { - char *ssp = smack_of_sem(sma); - - return smk_curacc(ssp, MAY_READWRITE); + return smk_curacc_sem(sma, MAY_READWRITE); } /** @@ -1880,6 +2043,25 @@ static char *smack_of_msq(struct msg_queue *msq) return (char *)msq->q_perm.security; } +/** + * smk_curacc_msq : helper to check if current has access on msq + * @msq : the msq + * @access : access requested + * + * return 0 if current has access, error otherwise + */ +static int smk_curacc_msq(struct msg_queue *msq, int access) +{ + char *msp = smack_of_msq(msq); + struct smk_audit_info ad; + +#ifdef CONFIG_AUDIT + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_IPC); + ad.a.u.ipc_id = msq->q_perm.id; +#endif + return smk_curacc(msp, access, &ad); +} + /** * smack_msg_queue_associate - Smack access check for msg_queue * @msq: the object @@ -1889,11 +2071,10 @@ static char *smack_of_msq(struct msg_queue *msq) */ static int smack_msg_queue_associate(struct msg_queue *msq, int msqflg) { - char *msp = smack_of_msq(msq); int may; may = smack_flags_to_may(msqflg); - return smk_curacc(msp, may); + return smk_curacc_msq(msq, may); } /** @@ -1905,7 +2086,6 @@ static int smack_msg_queue_associate(struct msg_queue *msq, int msqflg) */ static int smack_msg_queue_msgctl(struct msg_queue *msq, int cmd) { - char *msp; int may; switch (cmd) { @@ -1927,8 +2107,7 @@ static int smack_msg_queue_msgctl(struct msg_queue *msq, int cmd) return -EINVAL; } - msp = smack_of_msq(msq); - return smk_curacc(msp, may); + return smk_curacc_msq(msq, may); } /** @@ -1942,11 +2121,10 @@ static int smack_msg_queue_msgctl(struct msg_queue *msq, int cmd) static int smack_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg, int msqflg) { - char *msp = smack_of_msq(msq); - int rc; + int may; - rc = smack_flags_to_may(msqflg); - return smk_curacc(msp, rc); + may = smack_flags_to_may(msqflg); + return smk_curacc_msq(msq, may); } /** @@ -1962,9 +2140,7 @@ static int smack_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg, static int smack_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg, struct task_struct *target, long type, int mode) { - char *msp = smack_of_msq(msq); - - return smk_curacc(msp, MAY_READWRITE); + return smk_curacc_msq(msq, MAY_READWRITE); } /** @@ -1977,10 +2153,14 @@ static int smack_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg, static int smack_ipc_permission(struct kern_ipc_perm *ipp, short flag) { char *isp = ipp->security; - int may; + int may = smack_flags_to_may(flag); + struct smk_audit_info ad; - may = smack_flags_to_may(flag); - return smk_curacc(isp, may); +#ifdef CONFIG_AUDIT + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_IPC); + ad.a.u.ipc_id = ipp->id; +#endif + return smk_curacc(isp, may, &ad); } /** @@ -2239,8 +2419,12 @@ static int smack_unix_stream_connect(struct socket *sock, { struct inode *sp = SOCK_INODE(sock); struct inode *op = SOCK_INODE(other); + struct smk_audit_info ad; - return smk_access(smk_of_inode(sp), smk_of_inode(op), MAY_READWRITE); + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_NET); + smk_ad_setfield_u_net_sk(&ad, other->sk); + return smk_access(smk_of_inode(sp), smk_of_inode(op), + MAY_READWRITE, &ad); } /** @@ -2255,8 +2439,11 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other) { struct inode *sp = SOCK_INODE(sock); struct inode *op = SOCK_INODE(other); + struct smk_audit_info ad; - return smk_access(smk_of_inode(sp), smk_of_inode(op), MAY_WRITE); + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_NET); + smk_ad_setfield_u_net_sk(&ad, other->sk); + return smk_access(smk_of_inode(sp), smk_of_inode(op), MAY_WRITE, &ad); } /** @@ -2371,7 +2558,7 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) char smack[SMK_LABELLEN]; char *csp; int rc; - + struct smk_audit_info ad; if (sk->sk_family != PF_INET && sk->sk_family != PF_INET6) return 0; @@ -2389,13 +2576,19 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) netlbl_secattr_destroy(&secattr); +#ifdef CONFIG_AUDIT + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_NET); + ad.a.u.net.family = sk->sk_family; + ad.a.u.net.netif = skb->iif; + ipv4_skb_to_auditdata(skb, &ad.a, NULL); +#endif /* * Receiving a packet requires that the other end * be able to write here. Read access is not required. * This is the simplist possible security model * for networking. */ - rc = smk_access(csp, ssp->smk_in, MAY_WRITE); + rc = smk_access(csp, ssp->smk_in, MAY_WRITE, &ad); if (rc != 0) netlbl_skbuff_err(skb, rc, 0); return rc; @@ -2524,6 +2717,7 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb, struct iphdr *hdr; char smack[SMK_LABELLEN]; int rc; + struct smk_audit_info ad; /* handle mapped IPv4 packets arriving via IPv6 sockets */ if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP)) @@ -2537,11 +2731,17 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb, strncpy(smack, smack_known_huh.smk_known, SMK_MAXLEN); netlbl_secattr_destroy(&secattr); +#ifdef CONFIG_AUDIT + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_NET); + ad.a.u.net.family = family; + ad.a.u.net.netif = skb->iif; + ipv4_skb_to_auditdata(skb, &ad.a, NULL); +#endif /* * Receiving a packet requires that the other end be able to write * here. Read access is not required. */ - rc = smk_access(smack, ssp->smk_in, MAY_WRITE); + rc = smk_access(smack, ssp->smk_in, MAY_WRITE, &ad); if (rc != 0) return rc; @@ -2643,6 +2843,7 @@ static int smack_key_permission(key_ref_t key_ref, const struct cred *cred, key_perm_t perm) { struct key *keyp; + struct smk_audit_info ad; keyp = key_ref_to_ptr(key_ref); if (keyp == NULL) @@ -2658,8 +2859,13 @@ static int smack_key_permission(key_ref_t key_ref, */ if (cred->security == NULL) return -EACCES; - - return smk_access(cred->security, keyp->security, MAY_READWRITE); +#ifdef CONFIG_AUDIT + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_KEY); + ad.a.u.key_struct.key = keyp->serial; + ad.a.u.key_struct.key_desc = keyp->description; +#endif + return smk_access(cred->security, keyp->security, + MAY_READWRITE, &ad); } #endif /* CONFIG_KEYS */ @@ -2828,15 +3034,7 @@ struct security_operations smack_ops = { .ptrace_may_access = smack_ptrace_may_access, .ptrace_traceme = smack_ptrace_traceme, - .capget = cap_capget, - .capset = cap_capset, - .capable = cap_capable, .syslog = smack_syslog, - .settime = cap_settime, - .vm_enough_memory = cap_vm_enough_memory, - - .bprm_set_creds = cap_bprm_set_creds, - .bprm_secureexec = cap_bprm_secureexec, .sb_alloc_security = smack_sb_alloc_security, .sb_free_security = smack_sb_free_security, @@ -2860,8 +3058,6 @@ struct security_operations smack_ops = { .inode_post_setxattr = smack_inode_post_setxattr, .inode_getxattr = smack_inode_getxattr, .inode_removexattr = smack_inode_removexattr, - .inode_need_killpriv = cap_inode_need_killpriv, - .inode_killpriv = cap_inode_killpriv, .inode_getsecurity = smack_inode_getsecurity, .inode_setsecurity = smack_inode_setsecurity, .inode_listsecurity = smack_inode_listsecurity, @@ -2882,7 +3078,6 @@ struct security_operations smack_ops = { .cred_commit = smack_cred_commit, .kernel_act_as = smack_kernel_act_as, .kernel_create_files_as = smack_kernel_create_files_as, - .task_fix_setuid = cap_task_fix_setuid, .task_setpgid = smack_task_setpgid, .task_getpgid = smack_task_getpgid, .task_getsid = smack_task_getsid, @@ -2896,7 +3091,6 @@ struct security_operations smack_ops = { .task_kill = smack_task_kill, .task_wait = smack_task_wait, .task_to_inode = smack_task_to_inode, - .task_prctl = cap_task_prctl, .ipc_permission = smack_ipc_permission, .ipc_getsecid = smack_ipc_getsecid, @@ -2923,9 +3117,6 @@ struct security_operations smack_ops = { .sem_semctl = smack_sem_semctl, .sem_semop = smack_sem_semop, - .netlink_send = cap_netlink_send, - .netlink_recv = cap_netlink_recv, - .d_instantiate = smack_d_instantiate, .getprocattr = smack_getprocattr, diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index e03a7e19c73b..f83a80980726 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c @@ -41,6 +41,7 @@ enum smk_inos { SMK_AMBIENT = 7, /* internet ambient label */ SMK_NETLBLADDR = 8, /* single label hosts */ SMK_ONLYCAP = 9, /* the only "capable" label */ + SMK_LOGGING = 10, /* logging */ }; /* @@ -734,8 +735,8 @@ static void smk_netlbladdr_insert(struct smk_netlbladdr *new) return; } - m = list_entry(rcu_dereference(smk_netlbladdr_list.next), - struct smk_netlbladdr, list); + m = list_entry_rcu(smk_netlbladdr_list.next, + struct smk_netlbladdr, list); /* the comparison '>' is a bit hacky, but works */ if (new->smk_mask.s_addr > m->smk_mask.s_addr) { @@ -748,8 +749,8 @@ static void smk_netlbladdr_insert(struct smk_netlbladdr *new) list_add_rcu(&new->list, &m->list); return; } - m_next = list_entry(rcu_dereference(m->list.next), - struct smk_netlbladdr, list); + m_next = list_entry_rcu(m->list.next, + struct smk_netlbladdr, list); if (new->smk_mask.s_addr > m_next->smk_mask.s_addr) { list_add_rcu(&new->list, &m->list); return; @@ -775,7 +776,7 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, struct sockaddr_in newname; char smack[SMK_LABELLEN]; char *sp; - char data[SMK_NETLBLADDRMAX]; + char data[SMK_NETLBLADDRMAX + 1]; char *host = (char *)&newname.sin_addr.s_addr; int rc; struct netlbl_audit audit_info; @@ -1191,6 +1192,69 @@ static const struct file_operations smk_onlycap_ops = { .write = smk_write_onlycap, }; +/** + * smk_read_logging - read() for /smack/logging + * @filp: file pointer, not actually used + * @buf: where to put the result + * @cn: maximum to send along + * @ppos: where to start + * + * Returns number of bytes read or error code, as appropriate + */ +static ssize_t smk_read_logging(struct file *filp, char __user *buf, + size_t count, loff_t *ppos) +{ + char temp[32]; + ssize_t rc; + + if (*ppos != 0) + return 0; + + sprintf(temp, "%d\n", log_policy); + rc = simple_read_from_buffer(buf, count, ppos, temp, strlen(temp)); + return rc; +} + +/** + * smk_write_logging - write() for /smack/logging + * @file: file pointer, not actually used + * @buf: where to get the data from + * @count: bytes sent + * @ppos: where to start + * + * Returns number of bytes written or error code, as appropriate + */ +static ssize_t smk_write_logging(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + char temp[32]; + int i; + + if (!capable(CAP_MAC_ADMIN)) + return -EPERM; + + if (count >= sizeof(temp) || count == 0) + return -EINVAL; + + if (copy_from_user(temp, buf, count) != 0) + return -EFAULT; + + temp[count] = '\0'; + + if (sscanf(temp, "%d", &i) != 1) + return -EINVAL; + if (i < 0 || i > 3) + return -EINVAL; + log_policy = i; + return count; +} + + + +static const struct file_operations smk_logging_ops = { + .read = smk_read_logging, + .write = smk_write_logging, +}; /** * smk_fill_super - fill the /smackfs superblock * @sb: the empty superblock @@ -1221,6 +1285,8 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent) {"netlabel", &smk_netlbladdr_ops, S_IRUGO|S_IWUSR}, [SMK_ONLYCAP] = {"onlycap", &smk_onlycap_ops, S_IRUGO|S_IWUSR}, + [SMK_LOGGING] = + {"logging", &smk_logging_ops, S_IRUGO|S_IWUSR}, /* last one */ {""} }; diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index ddfb9cccf468..fdd1f4b8c448 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c @@ -28,7 +28,13 @@ static const char *tomoyo_mode_2[4] = { "disabled", "enabled", "enabled", "enabled" }; -/* Table for profile. */ +/* + * tomoyo_control_array is a static data which contains + * + * (1) functionality name used by /sys/kernel/security/tomoyo/profile . + * (2) initial values for "struct tomoyo_profile". + * (3) max values for "struct tomoyo_profile". + */ static struct { const char *keyword; unsigned int current_value; @@ -39,7 +45,13 @@ static struct { [TOMOYO_VERBOSE] = { "TOMOYO_VERBOSE", 1, 1 }, }; -/* Profile table. Memory is allocated as needed. */ +/* + * tomoyo_profile is a structure which is used for holding the mode of access + * controls. TOMOYO has 4 modes: disabled, learning, permissive, enforcing. + * An administrator can define up to 256 profiles. + * The ->profile of "struct tomoyo_domain_info" is used for remembering + * the profile's number (0 - 255) assigned to that domain. + */ static struct tomoyo_profile { unsigned int value[TOMOYO_MAX_CONTROL_INDEX]; const struct tomoyo_path_info *comment; @@ -428,7 +440,6 @@ void tomoyo_fill_path_info(struct tomoyo_path_info *ptr) const char *name = ptr->name; const int len = strlen(name); - ptr->total_len = len; ptr->const_len = tomoyo_const_part_length(name); ptr->is_dir = len && (name[len - 1] == '/'); ptr->is_patterned = (ptr->const_len < len); @@ -866,7 +877,6 @@ static struct tomoyo_profile *tomoyo_find_or_assign_new_profile(const unsigned if (profile >= TOMOYO_MAX_PROFILES) return NULL; - /***** EXCLUSIVE SECTION START *****/ mutex_lock(&lock); ptr = tomoyo_profile_ptr[profile]; if (ptr) @@ -880,7 +890,6 @@ static struct tomoyo_profile *tomoyo_find_or_assign_new_profile(const unsigned tomoyo_profile_ptr[profile] = ptr; ok: mutex_unlock(&lock); - /***** EXCLUSIVE SECTION END *****/ return ptr; } @@ -1009,7 +1018,19 @@ static int tomoyo_read_profile(struct tomoyo_io_buffer *head) return 0; } -/* Structure for policy manager. */ +/* + * tomoyo_policy_manager_entry is a structure which is used for holding list of + * domainnames or programs which are permitted to modify configuration via + * /sys/kernel/security/tomoyo/ interface. + * It has following fields. + * + * (1) "list" which is linked to tomoyo_policy_manager_list . + * (2) "manager" is a domainname or a program's pathname. + * (3) "is_domain" is a bool which is true if "manager" is a domainname, false + * otherwise. + * (4) "is_deleted" is a bool which is true if marked as deleted, false + * otherwise. + */ struct tomoyo_policy_manager_entry { struct list_head list; /* A path to program or a domainname. */ @@ -1018,7 +1039,36 @@ struct tomoyo_policy_manager_entry { bool is_deleted; /* True if this entry is deleted. */ }; -/* The list for "struct tomoyo_policy_manager_entry". */ +/* + * tomoyo_policy_manager_list is used for holding list of domainnames or + * programs which are permitted to modify configuration via + * /sys/kernel/security/tomoyo/ interface. + * + * An entry is added by + * + * # echo ' /sbin/mingetty /bin/login /bin/bash' > \ + * /sys/kernel/security/tomoyo/manager + * (if you want to specify by a domainname) + * + * or + * + * # echo '/usr/lib/ccs/editpolicy' > /sys/kernel/security/tomoyo/manager + * (if you want to specify by a program's location) + * + * and is deleted by + * + * # echo 'delete /sbin/mingetty /bin/login /bin/bash' > \ + * /sys/kernel/security/tomoyo/manager + * + * or + * + * # echo 'delete /usr/lib/ccs/editpolicy' > \ + * /sys/kernel/security/tomoyo/manager + * + * and all entries are retrieved by + * + * # cat /sys/kernel/security/tomoyo/manager + */ static LIST_HEAD(tomoyo_policy_manager_list); static DECLARE_RWSEM(tomoyo_policy_manager_list_lock); @@ -1050,7 +1100,6 @@ static int tomoyo_update_manager_entry(const char *manager, saved_manager = tomoyo_save_name(manager); if (!saved_manager) return -ENOMEM; - /***** EXCLUSIVE SECTION START *****/ down_write(&tomoyo_policy_manager_list_lock); list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) { if (ptr->manager != saved_manager) @@ -1072,7 +1121,6 @@ static int tomoyo_update_manager_entry(const char *manager, error = 0; out: up_write(&tomoyo_policy_manager_list_lock); - /***** EXCLUSIVE SECTION END *****/ return error; } @@ -1117,10 +1165,9 @@ static int tomoyo_read_manager_policy(struct tomoyo_io_buffer *head) list); if (ptr->is_deleted) continue; - if (!tomoyo_io_printf(head, "%s\n", ptr->manager->name)) { - done = false; + done = tomoyo_io_printf(head, "%s\n", ptr->manager->name); + if (!done) break; - } } up_read(&tomoyo_policy_manager_list_lock); head->read_eof = done; @@ -1197,13 +1244,11 @@ static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head, if (sscanf(data, "pid=%u", &pid) == 1) { struct task_struct *p; - /***** CRITICAL SECTION START *****/ read_lock(&tasklist_lock); p = find_task_by_vpid(pid); if (p) domain = tomoyo_real_domain(p); read_unlock(&tasklist_lock); - /***** CRITICAL SECTION END *****/ } else if (!strncmp(data, "domain=", 7)) { if (tomoyo_is_domain_def(data + 7)) { down_read(&tomoyo_domain_list_lock); @@ -1447,15 +1492,14 @@ static int tomoyo_read_domain_policy(struct tomoyo_io_buffer *head) TOMOYO_DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ) ignore_global_allow_read = TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ "\n"; - if (!tomoyo_io_printf(head, - "%s\n" TOMOYO_KEYWORD_USE_PROFILE "%u\n" - "%s%s%s\n", domain->domainname->name, - domain->profile, quota_exceeded, - transition_failed, - ignore_global_allow_read)) { - done = false; + done = tomoyo_io_printf(head, "%s\n" TOMOYO_KEYWORD_USE_PROFILE + "%u\n%s%s%s\n", + domain->domainname->name, + domain->profile, quota_exceeded, + transition_failed, + ignore_global_allow_read); + if (!done) break; - } head->read_step = 2; acl_loop: if (head->read_step == 3) @@ -1463,24 +1507,22 @@ acl_loop: /* Print ACL entries in the domain. */ down_read(&tomoyo_domain_acl_info_list_lock); list_for_each_cookie(apos, head->read_var2, - &domain->acl_info_list) { + &domain->acl_info_list) { struct tomoyo_acl_info *ptr = list_entry(apos, struct tomoyo_acl_info, - list); - if (!tomoyo_print_entry(head, ptr)) { - done = false; + list); + done = tomoyo_print_entry(head, ptr); + if (!done) break; - } } up_read(&tomoyo_domain_acl_info_list_lock); if (!done) break; head->read_step = 3; tail_mark: - if (!tomoyo_io_printf(head, "\n")) { - done = false; + done = tomoyo_io_printf(head, "\n"); + if (!done) break; - } head->read_step = 1; if (head->read_single_domain) break; @@ -1550,11 +1592,10 @@ static int tomoyo_read_domain_profile(struct tomoyo_io_buffer *head) domain = list_entry(pos, struct tomoyo_domain_info, list); if (domain->is_deleted) continue; - if (!tomoyo_io_printf(head, "%u %s\n", domain->profile, - domain->domainname->name)) { - done = false; + done = tomoyo_io_printf(head, "%u %s\n", domain->profile, + domain->domainname->name); + if (!done) break; - } } up_read(&tomoyo_domain_list_lock); head->read_eof = done; @@ -1594,13 +1635,11 @@ static int tomoyo_read_pid(struct tomoyo_io_buffer *head) const int pid = head->read_step; struct task_struct *p; struct tomoyo_domain_info *domain = NULL; - /***** CRITICAL SECTION START *****/ read_lock(&tasklist_lock); p = find_task_by_vpid(pid); if (p) domain = tomoyo_real_domain(p); read_unlock(&tasklist_lock); - /***** CRITICAL SECTION END *****/ if (domain) tomoyo_io_printf(head, "%d %u %s", pid, domain->profile, domain->domainname->name); @@ -2138,7 +2177,13 @@ static ssize_t tomoyo_write(struct file *file, const char __user *buf, return tomoyo_write_control(file, buf, count); } -/* Operations for /sys/kernel/security/tomoyo/ interface. */ +/* + * tomoyo_operations is a "struct file_operations" which is used for handling + * /sys/kernel/security/tomoyo/ interface. + * + * Some files under /sys/kernel/security/tomoyo/ directory accept open(O_RDWR). + * See tomoyo_io_buffer for internals. + */ static const struct file_operations tomoyo_operations = { .open = tomoyo_open, .release = tomoyo_release, diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 678f4ff16aa4..6d6ba09af457 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h @@ -26,16 +26,43 @@ struct dentry; struct vfsmount; -/* Temporary buffer for holding pathnames. */ +/* + * tomoyo_page_buffer is a structure which is used for holding a pathname + * obtained from "struct dentry" and "struct vfsmount" pair. + * As of now, it is 4096 bytes. If users complain that 4096 bytes is too small + * (because TOMOYO escapes non ASCII printable characters using \ooo format), + * we will make the buffer larger. + */ struct tomoyo_page_buffer { char buffer[4096]; }; -/* Structure for holding a token. */ +/* + * tomoyo_path_info is a structure which is used for holding a string data + * used by TOMOYO. + * This structure has several fields for supporting pattern matching. + * + * (1) "name" is the '\0' terminated string data. + * (2) "hash" is full_name_hash(name, strlen(name)). + * This allows tomoyo_pathcmp() to compare by hash before actually compare + * using strcmp(). + * (3) "const_len" is the length of the initial segment of "name" which + * consists entirely of non wildcard characters. In other words, the length + * which we can compare two strings using strncmp(). + * (4) "is_dir" is a bool which is true if "name" ends with "/", + * false otherwise. + * TOMOYO distinguishes directory and non-directory. A directory ends with + * "/" and non-directory does not end with "/". + * (5) "is_patterned" is a bool which is true if "name" contains wildcard + * characters, false otherwise. This allows TOMOYO to use "hash" and + * strcmp() for string comparison if "is_patterned" is false. + * (6) "depth" is calculated using the number of "/" characters in "name". + * This allows TOMOYO to avoid comparing two pathnames which never match + * (e.g. whether "/var/www/html/index.html" matches "/tmp/sh-thd-\$"). + */ struct tomoyo_path_info { const char *name; u32 hash; /* = full_name_hash(name, strlen(name)) */ - u16 total_len; /* = strlen(name) */ u16 const_len; /* = tomoyo_const_part_length(name) */ bool is_dir; /* = tomoyo_strendswith(name, "/") */ bool is_patterned; /* = tomoyo_path_contains_pattern(name) */ @@ -51,7 +78,20 @@ struct tomoyo_path_info { */ #define TOMOYO_MAX_PATHNAME_LEN 4000 -/* Structure for holding requested pathname. */ +/* + * tomoyo_path_info_with_data is a structure which is used for holding a + * pathname obtained from "struct dentry" and "struct vfsmount" pair. + * + * "struct tomoyo_path_info_with_data" consists of "struct tomoyo_path_info" + * and buffer for the pathname, while "struct tomoyo_page_buffer" consists of + * buffer for the pathname only. + * + * "struct tomoyo_path_info_with_data" is intended to allow TOMOYO to release + * both "struct tomoyo_path_info" and buffer for the pathname by single kfree() + * so that we don't need to return two pointers to the caller. If the caller + * puts "struct tomoyo_path_info" on stack memory, we will be able to remove + * "struct tomoyo_path_info_with_data". + */ struct tomoyo_path_info_with_data { /* Keep "head" first, for this pointer is passed to tomoyo_free(). */ struct tomoyo_path_info head; @@ -61,7 +101,15 @@ struct tomoyo_path_info_with_data { }; /* - * Common header for holding ACL entries. + * tomoyo_acl_info is a structure which is used for holding + * + * (1) "list" which is linked to the ->acl_info_list of + * "struct tomoyo_domain_info" + * (2) "type" which tells + * (a) type & 0x7F : type of the entry (either + * "struct tomoyo_single_path_acl_record" or + * "struct tomoyo_double_path_acl_record") + * (b) type & 0x80 : whether the entry is marked as "deleted". * * Packing "struct tomoyo_acl_info" allows * "struct tomoyo_single_path_acl_record" to embed "u16" and @@ -81,7 +129,28 @@ struct tomoyo_acl_info { /* This ACL entry is deleted. */ #define TOMOYO_ACL_DELETED 0x80 -/* Structure for domain information. */ +/* + * tomoyo_domain_info is a structure which is used for holding permissions + * (e.g. "allow_read /lib/libc-2.5.so") given to each domain. + * It has following fields. + * + * (1) "list" which is linked to tomoyo_domain_list . + * (2) "acl_info_list" which is linked to "struct tomoyo_acl_info". + * (3) "domainname" which holds the name of the domain. + * (4) "profile" which remembers profile number assigned to this domain. + * (5) "is_deleted" is a bool which is true if this domain is marked as + * "deleted", false otherwise. + * (6) "quota_warned" is a bool which is used for suppressing warning message + * when learning mode learned too much entries. + * (7) "flags" which remembers this domain's attributes. + * + * A domain's lifecycle is an analogy of files on / directory. + * Multiple domains with the same domainname cannot be created (as with + * creating files with the same filename fails with -EEXIST). + * If a process reached a domain, that process can reside in that domain after + * that domain is marked as "deleted" (as with a process can access an already + * open()ed file after that file was unlink()ed). + */ struct tomoyo_domain_info { struct list_head list; struct list_head acl_info_list; @@ -108,10 +177,18 @@ struct tomoyo_domain_info { #define TOMOYO_DOMAIN_FLAGS_TRANSITION_FAILED 2 /* - * Structure for "allow_read/write", "allow_execute", "allow_read", - * "allow_write", "allow_create", "allow_unlink", "allow_mkdir", "allow_rmdir", - * "allow_mkfifo", "allow_mksock", "allow_mkblock", "allow_mkchar", - * "allow_truncate", "allow_symlink" and "allow_rewrite" directive. + * tomoyo_single_path_acl_record is a structure which is used for holding an + * entry with one pathname operation (e.g. open(), mkdir()). + * It has following fields. + * + * (1) "head" which is a "struct tomoyo_acl_info". + * (2) "perm" which is a bitmask of permitted operations. + * (3) "filename" is the pathname. + * + * Directives held by this structure are "allow_read/write", "allow_execute", + * "allow_read", "allow_write", "allow_create", "allow_unlink", "allow_mkdir", + * "allow_rmdir", "allow_mkfifo", "allow_mksock", "allow_mkblock", + * "allow_mkchar", "allow_truncate", "allow_symlink" and "allow_rewrite". */ struct tomoyo_single_path_acl_record { struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_SINGLE_PATH_ACL */ @@ -120,7 +197,18 @@ struct tomoyo_single_path_acl_record { const struct tomoyo_path_info *filename; }; -/* Structure for "allow_rename" and "allow_link" directive. */ +/* + * tomoyo_double_path_acl_record is a structure which is used for holding an + * entry with two pathnames operation (i.e. link() and rename()). + * It has following fields. + * + * (1) "head" which is a "struct tomoyo_acl_info". + * (2) "perm" which is a bitmask of permitted operations. + * (3) "filename1" is the source/old pathname. + * (4) "filename2" is the destination/new pathname. + * + * Directives held by this structure are "allow_rename" and "allow_link". + */ struct tomoyo_double_path_acl_record { struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_DOUBLE_PATH_ACL */ u8 perm; @@ -153,7 +241,29 @@ struct tomoyo_double_path_acl_record { #define TOMOYO_VERBOSE 2 #define TOMOYO_MAX_CONTROL_INDEX 3 -/* Structure for reading/writing policy via securityfs interfaces. */ +/* + * tomoyo_io_buffer is a structure which is used for reading and modifying + * configuration via /sys/kernel/security/tomoyo/ interface. + * It has many fields. ->read_var1 , ->read_var2 , ->write_var1 are used as + * cursors. + * + * Since the content of /sys/kernel/security/tomoyo/domain_policy is a list of + * "struct tomoyo_domain_info" entries and each "struct tomoyo_domain_info" + * entry has a list of "struct tomoyo_acl_info", we need two cursors when + * reading (one is for traversing tomoyo_domain_list and the other is for + * traversing "struct tomoyo_acl_info"->acl_info_list ). + * + * If a line written to /sys/kernel/security/tomoyo/domain_policy starts with + * "select ", TOMOYO seeks the cursor ->read_var1 and ->write_var1 to the + * domain with the domainname specified by the rest of that line (NULL is set + * if seek failed). + * If a line written to /sys/kernel/security/tomoyo/domain_policy starts with + * "delete ", TOMOYO deletes an entry or a domain specified by the rest of that + * line (->write_var1 is set to NULL if a domain was deleted). + * If a line written to /sys/kernel/security/tomoyo/domain_policy starts with + * neither "select " nor "delete ", an entry or a domain specified by that line + * is appended. + */ struct tomoyo_io_buffer { int (*read) (struct tomoyo_io_buffer *); int (*write) (struct tomoyo_io_buffer *); diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index 2d6748741a26..1d8b16960576 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c @@ -19,11 +19,63 @@ /* The initial domain. */ struct tomoyo_domain_info tomoyo_kernel_domain; -/* The list for "struct tomoyo_domain_info". */ +/* + * tomoyo_domain_list is used for holding list of domains. + * The ->acl_info_list of "struct tomoyo_domain_info" is used for holding + * permissions (e.g. "allow_read /lib/libc-2.5.so") given to each domain. + * + * An entry is added by + * + * # ( echo ""; echo "allow_execute /sbin/init" ) > \ + * /sys/kernel/security/tomoyo/domain_policy + * + * and is deleted by + * + * # ( echo ""; echo "delete allow_execute /sbin/init" ) > \ + * /sys/kernel/security/tomoyo/domain_policy + * + * and all entries are retrieved by + * + * # cat /sys/kernel/security/tomoyo/domain_policy + * + * A domain is added by + * + * # echo "" > /sys/kernel/security/tomoyo/domain_policy + * + * and is deleted by + * + * # echo "delete " > /sys/kernel/security/tomoyo/domain_policy + * + * and all domains are retrieved by + * + * # grep '^' /sys/kernel/security/tomoyo/domain_policy + * + * Normally, a domainname is monotonically getting longer because a domainname + * which the process will belong to if an execve() operation succeeds is + * defined as a concatenation of "current domainname" + "pathname passed to + * execve()". + * See tomoyo_domain_initializer_list and tomoyo_domain_keeper_list for + * exceptions. + */ LIST_HEAD(tomoyo_domain_list); DECLARE_RWSEM(tomoyo_domain_list_lock); -/* Structure for "initialize_domain" and "no_initialize_domain" keyword. */ +/* + * tomoyo_domain_initializer_entry is a structure which is used for holding + * "initialize_domain" and "no_initialize_domain" entries. + * It has following fields. + * + * (1) "list" which is linked to tomoyo_domain_initializer_list . + * (2) "domainname" which is "a domainname" or "the last component of a + * domainname". This field is NULL if "from" clause is not specified. + * (3) "program" which is a program's pathname. + * (4) "is_deleted" is a bool which is true if marked as deleted, false + * otherwise. + * (5) "is_not" is a bool which is true if "no_initialize_domain", false + * otherwise. + * (6) "is_last_name" is a bool which is true if "domainname" is "the last + * component of a domainname", false otherwise. + */ struct tomoyo_domain_initializer_entry { struct list_head list; const struct tomoyo_path_info *domainname; /* This may be NULL */ @@ -34,7 +86,23 @@ struct tomoyo_domain_initializer_entry { bool is_last_name; }; -/* Structure for "keep_domain" and "no_keep_domain" keyword. */ +/* + * tomoyo_domain_keeper_entry is a structure which is used for holding + * "keep_domain" and "no_keep_domain" entries. + * It has following fields. + * + * (1) "list" which is linked to tomoyo_domain_keeper_list . + * (2) "domainname" which is "a domainname" or "the last component of a + * domainname". + * (3) "program" which is a program's pathname. + * This field is NULL if "from" clause is not specified. + * (4) "is_deleted" is a bool which is true if marked as deleted, false + * otherwise. + * (5) "is_not" is a bool which is true if "no_initialize_domain", false + * otherwise. + * (6) "is_last_name" is a bool which is true if "domainname" is "the last + * component of a domainname", false otherwise. + */ struct tomoyo_domain_keeper_entry { struct list_head list; const struct tomoyo_path_info *domainname; @@ -45,7 +113,16 @@ struct tomoyo_domain_keeper_entry { bool is_last_name; }; -/* Structure for "alias" keyword. */ +/* + * tomoyo_alias_entry is a structure which is used for holding "alias" entries. + * It has following fields. + * + * (1) "list" which is linked to tomoyo_alias_list . + * (2) "original_name" which is a dereferenced pathname. + * (3) "aliased_name" which is a symlink's pathname. + * (4) "is_deleted" is a bool which is true if marked as deleted, false + * otherwise. + */ struct tomoyo_alias_entry { struct list_head list; const struct tomoyo_path_info *original_name; @@ -67,14 +144,12 @@ void tomoyo_set_domain_flag(struct tomoyo_domain_info *domain, { /* We need to serialize because this is bitfield operation. */ static DEFINE_SPINLOCK(lock); - /***** CRITICAL SECTION START *****/ spin_lock(&lock); if (!is_delete) domain->flags |= flags; else domain->flags &= ~flags; spin_unlock(&lock); - /***** CRITICAL SECTION END *****/ } /** @@ -94,7 +169,42 @@ const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain) return cp0; } -/* The list for "struct tomoyo_domain_initializer_entry". */ +/* + * tomoyo_domain_initializer_list is used for holding list of programs which + * triggers reinitialization of domainname. Normally, a domainname is + * monotonically getting longer. But sometimes, we restart daemon programs. + * It would be convenient for us that "a daemon started upon system boot" and + * "the daemon restarted from console" belong to the same domain. Thus, TOMOYO + * provides a way to shorten domainnames. + * + * An entry is added by + * + * # echo 'initialize_domain /usr/sbin/httpd' > \ + * /sys/kernel/security/tomoyo/exception_policy + * + * and is deleted by + * + * # echo 'delete initialize_domain /usr/sbin/httpd' > \ + * /sys/kernel/security/tomoyo/exception_policy + * + * and all entries are retrieved by + * + * # grep ^initialize_domain /sys/kernel/security/tomoyo/exception_policy + * + * In the example above, /usr/sbin/httpd will belong to + * " /usr/sbin/httpd" domain. + * + * You may specify a domainname using "from" keyword. + * "initialize_domain /usr/sbin/httpd from /etc/rc.d/init.d/httpd" + * will cause "/usr/sbin/httpd" executed from " /etc/rc.d/init.d/httpd" + * domain to belong to " /usr/sbin/httpd" domain. + * + * You may add "no_" prefix to "initialize_domain". + * "initialize_domain /usr/sbin/httpd" and + * "no_initialize_domain /usr/sbin/httpd from /etc/rc.d/init.d/httpd" + * will cause "/usr/sbin/httpd" to belong to " /usr/sbin/httpd" domain + * unless executed from " /etc/rc.d/init.d/httpd" domain. + */ static LIST_HEAD(tomoyo_domain_initializer_list); static DECLARE_RWSEM(tomoyo_domain_initializer_list_lock); @@ -135,7 +245,6 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname, saved_program = tomoyo_save_name(program); if (!saved_program) return -ENOMEM; - /***** EXCLUSIVE SECTION START *****/ down_write(&tomoyo_domain_initializer_list_lock); list_for_each_entry(ptr, &tomoyo_domain_initializer_list, list) { if (ptr->is_not != is_not || @@ -161,7 +270,6 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname, error = 0; out: up_write(&tomoyo_domain_initializer_list_lock); - /***** EXCLUSIVE SECTION END *****/ return error; } @@ -193,13 +301,12 @@ bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head) from = " from "; domain = ptr->domainname->name; } - if (!tomoyo_io_printf(head, - "%s" TOMOYO_KEYWORD_INITIALIZE_DOMAIN - "%s%s%s\n", no, ptr->program->name, from, - domain)) { - done = false; + done = tomoyo_io_printf(head, + "%s" TOMOYO_KEYWORD_INITIALIZE_DOMAIN + "%s%s%s\n", no, ptr->program->name, + from, domain); + if (!done) break; - } } up_read(&tomoyo_domain_initializer_list_lock); return done; @@ -273,7 +380,44 @@ static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info * return flag; } -/* The list for "struct tomoyo_domain_keeper_entry". */ +/* + * tomoyo_domain_keeper_list is used for holding list of domainnames which + * suppresses domain transition. Normally, a domainname is monotonically + * getting longer. But sometimes, we want to suppress domain transition. + * It would be convenient for us that programs executed from a login session + * belong to the same domain. Thus, TOMOYO provides a way to suppress domain + * transition. + * + * An entry is added by + * + * # echo 'keep_domain /usr/sbin/sshd /bin/bash' > \ + * /sys/kernel/security/tomoyo/exception_policy + * + * and is deleted by + * + * # echo 'delete keep_domain /usr/sbin/sshd /bin/bash' > \ + * /sys/kernel/security/tomoyo/exception_policy + * + * and all entries are retrieved by + * + * # grep ^keep_domain /sys/kernel/security/tomoyo/exception_policy + * + * In the example above, any process which belongs to + * " /usr/sbin/sshd /bin/bash" domain will remain in that domain, + * unless explicitly specified by "initialize_domain" or "no_keep_domain". + * + * You may specify a program using "from" keyword. + * "keep_domain /bin/pwd from /usr/sbin/sshd /bin/bash" + * will cause "/bin/pwd" executed from " /usr/sbin/sshd /bin/bash" + * domain to remain in " /usr/sbin/sshd /bin/bash" domain. + * + * You may add "no_" prefix to "keep_domain". + * "keep_domain /usr/sbin/sshd /bin/bash" and + * "no_keep_domain /usr/bin/passwd from /usr/sbin/sshd /bin/bash" will + * cause "/usr/bin/passwd" to belong to + * " /usr/sbin/sshd /bin/bash /usr/bin/passwd" domain, unless + * explicitly specified by "initialize_domain". + */ static LIST_HEAD(tomoyo_domain_keeper_list); static DECLARE_RWSEM(tomoyo_domain_keeper_list_lock); @@ -296,7 +440,6 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname, struct tomoyo_domain_keeper_entry *ptr; const struct tomoyo_path_info *saved_domainname; const struct tomoyo_path_info *saved_program = NULL; - static DEFINE_MUTEX(lock); int error = -ENOMEM; bool is_last_name = false; @@ -315,7 +458,6 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname, saved_domainname = tomoyo_save_name(domainname); if (!saved_domainname) return -ENOMEM; - /***** EXCLUSIVE SECTION START *****/ down_write(&tomoyo_domain_keeper_list_lock); list_for_each_entry(ptr, &tomoyo_domain_keeper_list, list) { if (ptr->is_not != is_not || @@ -341,7 +483,6 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname, error = 0; out: up_write(&tomoyo_domain_keeper_list_lock); - /***** EXCLUSIVE SECTION END *****/ return error; } @@ -394,13 +535,12 @@ bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head) from = " from "; program = ptr->program->name; } - if (!tomoyo_io_printf(head, - "%s" TOMOYO_KEYWORD_KEEP_DOMAIN - "%s%s%s\n", no, program, from, - ptr->domainname->name)) { - done = false; + done = tomoyo_io_printf(head, + "%s" TOMOYO_KEYWORD_KEEP_DOMAIN + "%s%s%s\n", no, program, from, + ptr->domainname->name); + if (!done) break; - } } up_read(&tomoyo_domain_keeper_list_lock); return done; @@ -446,7 +586,36 @@ static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname, return flag; } -/* The list for "struct tomoyo_alias_entry". */ +/* + * tomoyo_alias_list is used for holding list of symlink's pathnames which are + * allowed to be passed to an execve() request. Normally, the domainname which + * the current process will belong to after execve() succeeds is calculated + * using dereferenced pathnames. But some programs behave differently depending + * on the name passed to argv[0]. For busybox, calculating domainname using + * dereferenced pathnames will cause all programs in the busybox to belong to + * the same domain. Thus, TOMOYO provides a way to allow use of symlink's + * pathname for checking execve()'s permission and calculating domainname which + * the current process will belong to after execve() succeeds. + * + * An entry is added by + * + * # echo 'alias /bin/busybox /bin/cat' > \ + * /sys/kernel/security/tomoyo/exception_policy + * + * and is deleted by + * + * # echo 'delete alias /bin/busybox /bin/cat' > \ + * /sys/kernel/security/tomoyo/exception_policy + * + * and all entries are retrieved by + * + * # grep ^alias /sys/kernel/security/tomoyo/exception_policy + * + * In the example above, if /bin/cat is a symlink to /bin/busybox and execution + * of /bin/cat is requested, permission is checked for /bin/cat rather than + * /bin/busybox and domainname which the current process will belong to after + * execve() succeeds is calculated using /bin/cat rather than /bin/busybox . + */ static LIST_HEAD(tomoyo_alias_list); static DECLARE_RWSEM(tomoyo_alias_list_lock); @@ -476,7 +645,6 @@ static int tomoyo_update_alias_entry(const char *original_name, saved_aliased_name = tomoyo_save_name(aliased_name); if (!saved_original_name || !saved_aliased_name) return -ENOMEM; - /***** EXCLUSIVE SECTION START *****/ down_write(&tomoyo_alias_list_lock); list_for_each_entry(ptr, &tomoyo_alias_list, list) { if (ptr->original_name != saved_original_name || @@ -499,7 +667,6 @@ static int tomoyo_update_alias_entry(const char *original_name, error = 0; out: up_write(&tomoyo_alias_list_lock); - /***** EXCLUSIVE SECTION END *****/ return error; } @@ -522,12 +689,11 @@ bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head) ptr = list_entry(pos, struct tomoyo_alias_entry, list); if (ptr->is_deleted) continue; - if (!tomoyo_io_printf(head, TOMOYO_KEYWORD_ALIAS "%s %s\n", - ptr->original_name->name, - ptr->aliased_name->name)) { - done = false; + done = tomoyo_io_printf(head, TOMOYO_KEYWORD_ALIAS "%s %s\n", + ptr->original_name->name, + ptr->aliased_name->name); + if (!done) break; - } } up_read(&tomoyo_alias_list_lock); return done; @@ -567,7 +733,6 @@ int tomoyo_delete_domain(char *domainname) name.name = domainname; tomoyo_fill_path_info(&name); - /***** EXCLUSIVE SECTION START *****/ down_write(&tomoyo_domain_list_lock); /* Is there an active domain? */ list_for_each_entry(domain, &tomoyo_domain_list, list) { @@ -581,7 +746,6 @@ int tomoyo_delete_domain(char *domainname) break; } up_write(&tomoyo_domain_list_lock); - /***** EXCLUSIVE SECTION END *****/ return 0; } @@ -600,7 +764,6 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * struct tomoyo_domain_info *domain = NULL; const struct tomoyo_path_info *saved_domainname; - /***** EXCLUSIVE SECTION START *****/ down_write(&tomoyo_domain_list_lock); domain = tomoyo_find_domain(domainname); if (domain) @@ -619,7 +782,6 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * domain->domainname != saved_domainname) continue; flag = false; - /***** CRITICAL SECTION START *****/ read_lock(&tasklist_lock); for_each_process(p) { if (tomoyo_real_domain(p) != domain) @@ -628,7 +790,6 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * break; } read_unlock(&tasklist_lock); - /***** CRITICAL SECTION END *****/ if (flag) continue; list_for_each_entry(ptr, &domain->acl_info_list, list) { @@ -651,7 +812,6 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * } out: up_write(&tomoyo_domain_list_lock); - /***** EXCLUSIVE SECTION END *****/ return domain; } @@ -739,7 +899,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm, } /* Check execute permission. */ - retval = tomoyo_check_exec_perm(old_domain, &r, tmp); + retval = tomoyo_check_exec_perm(old_domain, &r); if (retval < 0) goto out; diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index 2316da8ec5bc..5ae3a571559f 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c @@ -14,21 +14,50 @@ #include "realpath.h" #define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE]) -/* Structure for "allow_read" keyword. */ +/* + * tomoyo_globally_readable_file_entry is a structure which is used for holding + * "allow_read" entries. + * It has following fields. + * + * (1) "list" which is linked to tomoyo_globally_readable_list . + * (2) "filename" is a pathname which is allowed to open(O_RDONLY). + * (3) "is_deleted" is a bool which is true if marked as deleted, false + * otherwise. + */ struct tomoyo_globally_readable_file_entry { struct list_head list; const struct tomoyo_path_info *filename; bool is_deleted; }; -/* Structure for "file_pattern" keyword. */ +/* + * tomoyo_pattern_entry is a structure which is used for holding + * "tomoyo_pattern_list" entries. + * It has following fields. + * + * (1) "list" which is linked to tomoyo_pattern_list . + * (2) "pattern" is a pathname pattern which is used for converting pathnames + * to pathname patterns during learning mode. + * (3) "is_deleted" is a bool which is true if marked as deleted, false + * otherwise. + */ struct tomoyo_pattern_entry { struct list_head list; const struct tomoyo_path_info *pattern; bool is_deleted; }; -/* Structure for "deny_rewrite" keyword. */ +/* + * tomoyo_no_rewrite_entry is a structure which is used for holding + * "deny_rewrite" entries. + * It has following fields. + * + * (1) "list" which is linked to tomoyo_no_rewrite_list . + * (2) "pattern" is a pathname which is by default not permitted to modify + * already existing content. + * (3) "is_deleted" is a bool which is true if marked as deleted, false + * otherwise. + */ struct tomoyo_no_rewrite_entry { struct list_head list; const struct tomoyo_path_info *pattern; @@ -141,7 +170,31 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename, struct tomoyo_domain_info * const domain, const bool is_delete); -/* The list for "struct tomoyo_globally_readable_file_entry". */ +/* + * tomoyo_globally_readable_list is used for holding list of pathnames which + * are by default allowed to be open()ed for reading by any process. + * + * An entry is added by + * + * # echo 'allow_read /lib/libc-2.5.so' > \ + * /sys/kernel/security/tomoyo/exception_policy + * + * and is deleted by + * + * # echo 'delete allow_read /lib/libc-2.5.so' > \ + * /sys/kernel/security/tomoyo/exception_policy + * + * and all entries are retrieved by + * + * # grep ^allow_read /sys/kernel/security/tomoyo/exception_policy + * + * In the example above, any process is allowed to + * open("/lib/libc-2.5.so", O_RDONLY). + * One exception is, if the domain which current process belongs to is marked + * as "ignore_global_allow_read", current process can't do so unless explicitly + * given "allow_read /lib/libc-2.5.so" to the domain which current process + * belongs to. + */ static LIST_HEAD(tomoyo_globally_readable_list); static DECLARE_RWSEM(tomoyo_globally_readable_list_lock); @@ -166,7 +219,6 @@ static int tomoyo_update_globally_readable_entry(const char *filename, saved_filename = tomoyo_save_name(filename); if (!saved_filename) return -ENOMEM; - /***** EXCLUSIVE SECTION START *****/ down_write(&tomoyo_globally_readable_list_lock); list_for_each_entry(ptr, &tomoyo_globally_readable_list, list) { if (ptr->filename != saved_filename) @@ -187,7 +239,6 @@ static int tomoyo_update_globally_readable_entry(const char *filename, error = 0; out: up_write(&tomoyo_globally_readable_list_lock); - /***** EXCLUSIVE SECTION END *****/ return error; } @@ -249,17 +300,44 @@ bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head) list); if (ptr->is_deleted) continue; - if (!tomoyo_io_printf(head, TOMOYO_KEYWORD_ALLOW_READ "%s\n", - ptr->filename->name)) { - done = false; + done = tomoyo_io_printf(head, TOMOYO_KEYWORD_ALLOW_READ "%s\n", + ptr->filename->name); + if (!done) break; - } } up_read(&tomoyo_globally_readable_list_lock); return done; } -/* The list for "struct tomoyo_pattern_entry". */ +/* tomoyo_pattern_list is used for holding list of pathnames which are used for + * converting pathnames to pathname patterns during learning mode. + * + * An entry is added by + * + * # echo 'file_pattern /proc/\$/mounts' > \ + * /sys/kernel/security/tomoyo/exception_policy + * + * and is deleted by + * + * # echo 'delete file_pattern /proc/\$/mounts' > \ + * /sys/kernel/security/tomoyo/exception_policy + * + * and all entries are retrieved by + * + * # grep ^file_pattern /sys/kernel/security/tomoyo/exception_policy + * + * In the example above, if a process which belongs to a domain which is in + * learning mode requested open("/proc/1/mounts", O_RDONLY), + * "allow_read /proc/\$/mounts" is automatically added to the domain which that + * process belongs to. + * + * It is not a desirable behavior that we have to use /proc/\$/ instead of + * /proc/self/ when current process needs to access only current process's + * information. As of now, LSM version of TOMOYO is using __d_path() for + * calculating pathname. Non LSM version of TOMOYO is using its own function + * which pretends as if /proc/self/ is not a symlink; so that we can forbid + * current process from accessing other process's information. + */ static LIST_HEAD(tomoyo_pattern_list); static DECLARE_RWSEM(tomoyo_pattern_list_lock); @@ -284,7 +362,6 @@ static int tomoyo_update_file_pattern_entry(const char *pattern, saved_pattern = tomoyo_save_name(pattern); if (!saved_pattern) return -ENOMEM; - /***** EXCLUSIVE SECTION START *****/ down_write(&tomoyo_pattern_list_lock); list_for_each_entry(ptr, &tomoyo_pattern_list, list) { if (saved_pattern != ptr->pattern) @@ -305,7 +382,6 @@ static int tomoyo_update_file_pattern_entry(const char *pattern, error = 0; out: up_write(&tomoyo_pattern_list_lock); - /***** EXCLUSIVE SECTION END *****/ return error; } @@ -373,17 +449,44 @@ bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head) ptr = list_entry(pos, struct tomoyo_pattern_entry, list); if (ptr->is_deleted) continue; - if (!tomoyo_io_printf(head, TOMOYO_KEYWORD_FILE_PATTERN "%s\n", - ptr->pattern->name)) { - done = false; + done = tomoyo_io_printf(head, TOMOYO_KEYWORD_FILE_PATTERN + "%s\n", ptr->pattern->name); + if (!done) break; - } } up_read(&tomoyo_pattern_list_lock); return done; } -/* The list for "struct tomoyo_no_rewrite_entry". */ +/* + * tomoyo_no_rewrite_list is used for holding list of pathnames which are by + * default forbidden to modify already written content of a file. + * + * An entry is added by + * + * # echo 'deny_rewrite /var/log/messages' > \ + * /sys/kernel/security/tomoyo/exception_policy + * + * and is deleted by + * + * # echo 'delete deny_rewrite /var/log/messages' > \ + * /sys/kernel/security/tomoyo/exception_policy + * + * and all entries are retrieved by + * + * # grep ^deny_rewrite /sys/kernel/security/tomoyo/exception_policy + * + * In the example above, if a process requested to rewrite /var/log/messages , + * the process can't rewrite unless the domain which that process belongs to + * has "allow_rewrite /var/log/messages" entry. + * + * It is not a desirable behavior that we have to add "\040(deleted)" suffix + * when we want to allow rewriting already unlink()ed file. As of now, + * LSM version of TOMOYO is using __d_path() for calculating pathname. + * Non LSM version of TOMOYO is using its own function which doesn't append + * " (deleted)" suffix if the file is already unlink()ed; so that we don't + * need to worry whether the file is already unlink()ed or not. + */ static LIST_HEAD(tomoyo_no_rewrite_list); static DECLARE_RWSEM(tomoyo_no_rewrite_list_lock); @@ -407,7 +510,6 @@ static int tomoyo_update_no_rewrite_entry(const char *pattern, saved_pattern = tomoyo_save_name(pattern); if (!saved_pattern) return -ENOMEM; - /***** EXCLUSIVE SECTION START *****/ down_write(&tomoyo_no_rewrite_list_lock); list_for_each_entry(ptr, &tomoyo_no_rewrite_list, list) { if (ptr->pattern != saved_pattern) @@ -428,7 +530,6 @@ static int tomoyo_update_no_rewrite_entry(const char *pattern, error = 0; out: up_write(&tomoyo_no_rewrite_list_lock); - /***** EXCLUSIVE SECTION END *****/ return error; } @@ -489,11 +590,10 @@ bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head) ptr = list_entry(pos, struct tomoyo_no_rewrite_entry, list); if (ptr->is_deleted) continue; - if (!tomoyo_io_printf(head, TOMOYO_KEYWORD_DENY_REWRITE "%s\n", - ptr->pattern->name)) { - done = false; + done = tomoyo_io_printf(head, TOMOYO_KEYWORD_DENY_REWRITE + "%s\n", ptr->pattern->name); + if (!done) break; - } } up_read(&tomoyo_no_rewrite_list_lock); return done; @@ -745,7 +845,6 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename, saved_filename = tomoyo_save_name(filename); if (!saved_filename) return -ENOMEM; - /***** EXCLUSIVE SECTION START *****/ down_write(&tomoyo_domain_acl_info_list_lock); if (is_delete) goto delete; @@ -800,7 +899,6 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename, } out: up_write(&tomoyo_domain_acl_info_list_lock); - /***** EXCLUSIVE SECTION END *****/ return error; } @@ -836,7 +934,6 @@ static int tomoyo_update_double_path_acl(const u8 type, const char *filename1, saved_filename2 = tomoyo_save_name(filename2); if (!saved_filename1 || !saved_filename2) return -ENOMEM; - /***** EXCLUSIVE SECTION START *****/ down_write(&tomoyo_domain_acl_info_list_lock); if (is_delete) goto delete; @@ -884,7 +981,6 @@ static int tomoyo_update_double_path_acl(const u8 type, const char *filename1, } out: up_write(&tomoyo_domain_acl_info_list_lock); - /***** EXCLUSIVE SECTION END *****/ return error; } @@ -1025,13 +1121,11 @@ int tomoyo_check_file_perm(struct tomoyo_domain_info *domain, * * @domain: Pointer to "struct tomoyo_domain_info". * @filename: Check permission for "execute". - * @tmp: Buffer for temporary use. * * Returns 0 on success, negativevalue otherwise. */ int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain, - const struct tomoyo_path_info *filename, - struct tomoyo_page_buffer *tmp) + const struct tomoyo_path_info *filename) { const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); diff --git a/security/tomoyo/realpath.c b/security/tomoyo/realpath.c index 40927a84cb6e..5f2e33263371 100644 --- a/security/tomoyo/realpath.c +++ b/security/tomoyo/realpath.c @@ -220,7 +220,6 @@ void *tomoyo_alloc_element(const unsigned int size) = roundup(size, max(sizeof(void *), sizeof(long))); if (word_aligned_size > PATH_MAX) return NULL; - /***** EXCLUSIVE SECTION START *****/ mutex_lock(&lock); if (buf_used_len + word_aligned_size > PATH_MAX) { if (!tomoyo_quota_for_elements || @@ -251,7 +250,6 @@ void *tomoyo_alloc_element(const unsigned int size) } } mutex_unlock(&lock); - /***** EXCLUSIVE SECTION END *****/ return ptr; } @@ -267,7 +265,16 @@ static unsigned int tomoyo_quota_for_savename; */ #define TOMOYO_MAX_HASH 256 -/* Structure for string data. */ +/* + * tomoyo_name_entry is a structure which is used for linking + * "struct tomoyo_path_info" into tomoyo_name_list . + * + * Since tomoyo_name_list manages a list of strings which are shared by + * multiple processes (whereas "struct tomoyo_path_info" inside + * "struct tomoyo_path_info_with_data" is not shared), a reference counter will + * be added to "struct tomoyo_name_entry" rather than "struct tomoyo_path_info" + * when TOMOYO starts supporting garbage collector. + */ struct tomoyo_name_entry { struct list_head list; struct tomoyo_path_info entry; @@ -281,10 +288,10 @@ struct tomoyo_free_memory_block_list { }; /* - * The list for "struct tomoyo_name_entry". - * - * This list is updated only inside tomoyo_save_name(), thus - * no global mutex exists. + * tomoyo_name_list is used for holding string data used by TOMOYO. + * Since same string data is likely used for multiple times (e.g. + * "/lib/libc-2.5.so"), TOMOYO shares string data in the form of + * "const struct tomoyo_path_info *". */ static struct list_head tomoyo_name_list[TOMOYO_MAX_HASH]; @@ -318,7 +325,6 @@ const struct tomoyo_path_info *tomoyo_save_name(const char *name) return NULL; } hash = full_name_hash((const unsigned char *) name, len - 1); - /***** EXCLUSIVE SECTION START *****/ mutex_lock(&lock); list_for_each_entry(ptr, &tomoyo_name_list[hash % TOMOYO_MAX_HASH], list) { @@ -366,7 +372,6 @@ const struct tomoyo_path_info *tomoyo_save_name(const char *name) } out: mutex_unlock(&lock); - /***** EXCLUSIVE SECTION END *****/ return ptr ? &ptr->entry : NULL; } diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index e42be5c4f055..3194d09fe0f4 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c @@ -262,6 +262,10 @@ static int tomoyo_dentry_open(struct file *f, const struct cred *cred) return tomoyo_check_open_permission(tomoyo_domain(), &f->f_path, flags); } +/* + * tomoyo_security_ops is a "struct security_operations" which is used for + * registering TOMOYO. + */ static struct security_operations tomoyo_security_ops = { .name = "tomoyo", .cred_prepare = tomoyo_cred_prepare, diff --git a/security/tomoyo/tomoyo.h b/security/tomoyo/tomoyo.h index 41c6ebafb9c5..0fd588a629cf 100644 --- a/security/tomoyo/tomoyo.h +++ b/security/tomoyo/tomoyo.h @@ -17,13 +17,11 @@ struct path; struct inode; struct linux_binprm; struct pt_regs; -struct tomoyo_page_buffer; int tomoyo_check_file_perm(struct tomoyo_domain_info *domain, const char *filename, const u8 perm); int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain, - const struct tomoyo_path_info *filename, - struct tomoyo_page_buffer *buf); + const struct tomoyo_path_info *filename); int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, struct path *path, const int flag); int tomoyo_check_1path_perm(struct tomoyo_domain_info *domain, @@ -90,17 +88,10 @@ static inline struct tomoyo_domain_info *tomoyo_domain(void) return current_cred()->security; } -/* Caller holds tasklist_lock spinlock. */ static inline struct tomoyo_domain_info *tomoyo_real_domain(struct task_struct *task) { - /***** CRITICAL SECTION START *****/ - const struct cred *cred = get_task_cred(task); - struct tomoyo_domain_info *domain = cred->security; - - put_cred(cred); - return domain; - /***** CRITICAL SECTION END *****/ + return task_cred_xxx(task, security); } #endif /* !defined(_SECURITY_TOMOYO_TOMOYO_H) */ diff --git a/sound/aoa/fabrics/layout.c b/sound/aoa/fabrics/layout.c index fbf5c933baa4..586965f9605f 100644 --- a/sound/aoa/fabrics/layout.c +++ b/sound/aoa/fabrics/layout.c @@ -1037,7 +1037,7 @@ static int aoa_fabric_layout_probe(struct soundbus_dev *sdev) } ldev->selfptr_headphone.ptr = ldev; ldev->selfptr_lineout.ptr = ldev; - sdev->ofdev.dev.driver_data = ldev; + dev_set_drvdata(&sdev->ofdev.dev, ldev); list_add(&ldev->list, &layouts_list); layouts_list_items++; @@ -1081,7 +1081,7 @@ static int aoa_fabric_layout_probe(struct soundbus_dev *sdev) static int aoa_fabric_layout_remove(struct soundbus_dev *sdev) { - struct layout_dev *ldev = sdev->ofdev.dev.driver_data; + struct layout_dev *ldev = dev_get_drvdata(&sdev->ofdev.dev); int i; for (i=0; iofdev.dev.driver_data; + struct layout_dev *ldev = dev_get_drvdata(&sdev->ofdev.dev); if (ldev->gpio.methods && ldev->gpio.methods->all_amps_off) ldev->gpio.methods->all_amps_off(&ldev->gpio); @@ -1124,7 +1124,7 @@ static int aoa_fabric_layout_suspend(struct soundbus_dev *sdev, pm_message_t sta static int aoa_fabric_layout_resume(struct soundbus_dev *sdev) { - struct layout_dev *ldev = sdev->ofdev.dev.driver_data; + struct layout_dev *ldev = dev_get_drvdata(&sdev->ofdev.dev); if (ldev->gpio.methods && ldev->gpio.methods->all_amps_off) ldev->gpio.methods->all_amps_restore(&ldev->gpio); diff --git a/sound/aoa/soundbus/i2sbus/core.c b/sound/aoa/soundbus/i2sbus/core.c index 418c84c99d69..4e3b819d4993 100644 --- a/sound/aoa/soundbus/i2sbus/core.c +++ b/sound/aoa/soundbus/i2sbus/core.c @@ -358,14 +358,14 @@ static int i2sbus_probe(struct macio_dev* dev, const struct of_device_id *match) return -ENODEV; } - dev->ofdev.dev.driver_data = control; + dev_set_drvdata(&dev->ofdev.dev, control); return 0; } static int i2sbus_remove(struct macio_dev* dev) { - struct i2sbus_control *control = dev->ofdev.dev.driver_data; + struct i2sbus_control *control = dev_get_drvdata(&dev->ofdev.dev); struct i2sbus_dev *i2sdev, *tmp; list_for_each_entry_safe(i2sdev, tmp, &control->list, item) @@ -377,7 +377,7 @@ static int i2sbus_remove(struct macio_dev* dev) #ifdef CONFIG_PM static int i2sbus_suspend(struct macio_dev* dev, pm_message_t state) { - struct i2sbus_control *control = dev->ofdev.dev.driver_data; + struct i2sbus_control *control = dev_get_drvdata(&dev->ofdev.dev); struct codec_info_item *cii; struct i2sbus_dev* i2sdev; int err, ret = 0; @@ -407,7 +407,7 @@ static int i2sbus_suspend(struct macio_dev* dev, pm_message_t state) static int i2sbus_resume(struct macio_dev* dev) { - struct i2sbus_control *control = dev->ofdev.dev.driver_data; + struct i2sbus_control *control = dev_get_drvdata(&dev->ofdev.dev); struct codec_info_item *cii; struct i2sbus_dev* i2sdev; int err, ret = 0; diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c index 5c48e36038f2..dc78272fc39f 100644 --- a/sound/arm/aaci.c +++ b/sound/arm/aaci.c @@ -1089,7 +1089,7 @@ static int __devinit aaci_probe(struct amba_device *dev, struct amba_id *id) goto out; } - aaci->base = ioremap(dev->res.start, SZ_4K); + aaci->base = ioremap(dev->res.start, resource_size(&dev->res)); if (!aaci->base) { ret = -ENOMEM; goto out; diff --git a/sound/core/Kconfig b/sound/core/Kconfig index 7bbdda041a99..6061fb5f4e1c 100644 --- a/sound/core/Kconfig +++ b/sound/core/Kconfig @@ -205,3 +205,5 @@ config SND_PCM_XRUN_DEBUG config SND_VMASTER bool + +source "sound/core/seq/Kconfig" diff --git a/sound/core/init.c b/sound/core/init.c index fd56afe846ed..d5d40d78c409 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -152,15 +152,8 @@ int snd_card_create(int idx, const char *xid, card = kzalloc(sizeof(*card) + extra_size, GFP_KERNEL); if (!card) return -ENOMEM; - if (xid) { - if (!snd_info_check_reserved_words(xid)) { - snd_printk(KERN_ERR - "given id string '%s' is reserved.\n", xid); - err = -EBUSY; - goto __error; - } + if (xid) strlcpy(card->id, xid, sizeof(card->id)); - } err = 0; mutex_lock(&snd_card_mutex); if (idx < 0) { @@ -483,22 +476,28 @@ int snd_card_free(struct snd_card *card) EXPORT_SYMBOL(snd_card_free); -static void choose_default_id(struct snd_card *card) +static void snd_card_set_id_no_lock(struct snd_card *card, const char *nid) { int i, len, idx_flag = 0, loops = SNDRV_CARDS; - char *id, *spos; + const char *spos, *src; + char *id; - id = spos = card->shortname; - while (*id != '\0') { - if (*id == ' ') - spos = id + 1; - id++; + if (nid == NULL) { + id = card->shortname; + spos = src = id; + while (*id != '\0') { + if (*id == ' ') + spos = id + 1; + id++; + } + } else { + spos = src = nid; } id = card->id; while (*spos != '\0' && !isalnum(*spos)) spos++; if (isdigit(*spos)) - *id++ = isalpha(card->shortname[0]) ? card->shortname[0] : 'D'; + *id++ = isalpha(src[0]) ? src[0] : 'D'; while (*spos != '\0' && (size_t)(id - card->id) < sizeof(card->id) - 1) { if (isalnum(*spos)) *id++ = *spos; @@ -513,7 +512,7 @@ static void choose_default_id(struct snd_card *card) while (1) { if (loops-- == 0) { - snd_printk(KERN_ERR "unable to choose default card id (%s)\n", id); + snd_printk(KERN_ERR "unable to set card id (%s)\n", id); strcpy(card->id, card->proc_root->name); return; } @@ -539,14 +538,33 @@ static void choose_default_id(struct snd_card *card) spos = id + len - 2; if ((size_t)len <= sizeof(card->id) - 2) spos++; - *spos++ = '_'; - *spos++ = '1'; - *spos++ = '\0'; + *(char *)spos++ = '_'; + *(char *)spos++ = '1'; + *(char *)spos++ = '\0'; idx_flag++; } } } +/** + * snd_card_set_id - set card identification name + * @card: soundcard structure + * @nid: new identification string + * + * This function sets the card identification and checks for name + * collisions. + */ +void snd_card_set_id(struct snd_card *card, const char *nid) +{ + /* check if user specified own card->id */ + if (card->id[0] != '\0') + return; + mutex_lock(&snd_card_mutex); + snd_card_set_id_no_lock(card, nid); + mutex_unlock(&snd_card_mutex); +} +EXPORT_SYMBOL(snd_card_set_id); + #ifndef CONFIG_SYSFS_DEPRECATED static ssize_t card_id_show_attr(struct device *dev, @@ -640,8 +658,7 @@ int snd_card_register(struct snd_card *card) mutex_unlock(&snd_card_mutex); return 0; } - if (card->id[0] == '\0') - choose_default_id(card); + snd_card_set_id_no_lock(card, card->id[0] == '\0' ? NULL : card->id); snd_cards[card->number] = card; mutex_unlock(&snd_card_mutex); init_info_for_card(card); diff --git a/sound/core/jack.c b/sound/core/jack.c index d54d1a05fe65..f705eec7372a 100644 --- a/sound/core/jack.c +++ b/sound/core/jack.c @@ -63,7 +63,7 @@ static int snd_jack_dev_register(struct snd_device *device) /* Default to the sound card device. */ if (!jack->input_dev->dev.parent) - jack->input_dev->dev.parent = card->dev; + jack->input_dev->dev.parent = snd_card_get_device_link(card); err = input_register_device(jack->input_dev); if (err == 0) diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index dda000b9684c..dbe406b82591 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -617,9 +618,7 @@ static long snd_pcm_oss_bytes(struct snd_pcm_substream *substream, long frames) #else { u64 bsize = (u64)runtime->oss.buffer_bytes * (u64)bytes; - u32 rem; - div64_32(&bsize, buffer_size, &rem); - return (long)bsize; + return div_u64(bsize, buffer_size); } #endif } diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index d659995ac3ac..333e4dd29450 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -126,24 +127,37 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram } #ifdef CONFIG_SND_PCM_XRUN_DEBUG -#define xrun_debug(substream) ((substream)->pstr->xrun_debug) +#define xrun_debug(substream, mask) ((substream)->pstr->xrun_debug & (mask)) #else -#define xrun_debug(substream) 0 +#define xrun_debug(substream, mask) 0 #endif -#define dump_stack_on_xrun(substream) do { \ - if (xrun_debug(substream) > 1) \ - dump_stack(); \ +#define dump_stack_on_xrun(substream) do { \ + if (xrun_debug(substream, 2)) \ + dump_stack(); \ } while (0) +static void pcm_debug_name(struct snd_pcm_substream *substream, + char *name, size_t len) +{ + snprintf(name, len, "pcmC%dD%d%c:%d", + substream->pcm->card->number, + substream->pcm->device, + substream->stream ? 'c' : 'p', + substream->number); +} + static void xrun(struct snd_pcm_substream *substream) { + struct snd_pcm_runtime *runtime = substream->runtime; + + if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) + snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp); snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); - if (xrun_debug(substream)) { - snd_printd(KERN_DEBUG "XRUN: pcmC%dD%d%c\n", - substream->pcm->card->number, - substream->pcm->device, - substream->stream ? 'c' : 'p'); + if (xrun_debug(substream, 1)) { + char name[16]; + pcm_debug_name(substream, name, sizeof(name)); + snd_printd(KERN_DEBUG "XRUN: %s\n", name); dump_stack_on_xrun(substream); } } @@ -154,16 +168,16 @@ snd_pcm_update_hw_ptr_pos(struct snd_pcm_substream *substream, { snd_pcm_uframes_t pos; - if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) - snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp); pos = substream->ops->pointer(substream); if (pos == SNDRV_PCM_POS_XRUN) return pos; /* XRUN */ if (pos >= runtime->buffer_size) { if (printk_ratelimit()) { - snd_printd(KERN_ERR "BUG: stream = %i, pos = 0x%lx, " + char name[16]; + pcm_debug_name(substream, name, sizeof(name)); + snd_printd(KERN_ERR "BUG: %s, pos = 0x%lx, " "buffer size = 0x%lx, period size = 0x%lx\n", - substream->stream, pos, runtime->buffer_size, + name, pos, runtime->buffer_size, runtime->period_size); } pos = 0; @@ -197,7 +211,7 @@ static int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream, #define hw_ptr_error(substream, fmt, args...) \ do { \ - if (xrun_debug(substream)) { \ + if (xrun_debug(substream, 1)) { \ if (printk_ratelimit()) { \ snd_printd("PCM: " fmt, ##args); \ } \ @@ -251,7 +265,7 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream) } /* Do jiffies check only in xrun_debug mode */ - if (!xrun_debug(substream)) + if (!xrun_debug(substream, 4)) goto no_jiffies_check; /* Skip the jiffies check for hardwares with BATCH flag. @@ -261,6 +275,9 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream) if (runtime->hw.info & SNDRV_PCM_INFO_BATCH) goto no_jiffies_check; hdelta = new_hw_ptr - old_hw_ptr; + if (hdelta < runtime->delay) + goto no_jiffies_check; + hdelta -= runtime->delay; jdelta = jiffies - runtime->hw_ptr_jiffies; if (((hdelta * HZ) / runtime->rate) > jdelta + HZ/100) { delta = jdelta / @@ -294,14 +311,20 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream) hw_ptr_interrupt = new_hw_ptr - new_hw_ptr % runtime->period_size; } + runtime->hw_ptr_interrupt = hw_ptr_interrupt; + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && runtime->silence_size > 0) snd_pcm_playback_silence(substream, new_hw_ptr); + if (runtime->status->hw_ptr == new_hw_ptr) + return 0; + runtime->hw_ptr_base = hw_base; runtime->status->hw_ptr = new_hw_ptr; runtime->hw_ptr_jiffies = jiffies; - runtime->hw_ptr_interrupt = hw_ptr_interrupt; + if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) + snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp); return snd_pcm_update_hw_ptr_post(substream, runtime); } @@ -342,8 +365,12 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream) new_hw_ptr = hw_base + pos; } /* Do jiffies check only in xrun_debug mode */ - if (xrun_debug(substream) && - ((delta * HZ) / runtime->rate) > jdelta + HZ/100) { + if (!xrun_debug(substream, 4)) + goto no_jiffies_check; + if (delta < runtime->delay) + goto no_jiffies_check; + delta -= runtime->delay; + if (((delta * HZ) / runtime->rate) > jdelta + HZ/100) { hw_ptr_error(substream, "hw_ptr skipping! " "(pos=%ld, delta=%ld, period=%ld, jdelta=%lu/%lu)\n", @@ -352,13 +379,19 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream) ((delta * HZ) / runtime->rate)); return 0; } + no_jiffies_check: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && runtime->silence_size > 0) snd_pcm_playback_silence(substream, new_hw_ptr); + if (runtime->status->hw_ptr == new_hw_ptr) + return 0; + runtime->hw_ptr_base = hw_base; runtime->status->hw_ptr = new_hw_ptr; runtime->hw_ptr_jiffies = jiffies; + if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) + snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp); return snd_pcm_update_hw_ptr_post(substream, runtime); } @@ -452,7 +485,7 @@ static inline unsigned int muldiv32(unsigned int a, unsigned int b, *r = 0; return UINT_MAX; } - div64_32(&n, c, r); + n = div_u64_rem(n, c, r); if (n >= UINT_MAX) { *r = 0; return UINT_MAX; @@ -1524,6 +1557,23 @@ static int snd_pcm_lib_ioctl_channel_info(struct snd_pcm_substream *substream, return 0; } +static int snd_pcm_lib_ioctl_fifo_size(struct snd_pcm_substream *substream, + void *arg) +{ + struct snd_pcm_hw_params *params = arg; + snd_pcm_format_t format; + int channels, width; + + params->fifo_size = substream->runtime->hw.fifo_size; + if (!(substream->runtime->hw.info & SNDRV_PCM_INFO_FIFO_IN_FRAMES)) { + format = params_format(params); + channels = params_channels(params); + width = snd_pcm_format_physical_width(format); + params->fifo_size /= width * channels; + } + return 0; +} + /** * snd_pcm_lib_ioctl - a generic PCM ioctl callback * @substream: the pcm substream instance @@ -1545,6 +1595,8 @@ int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream, return snd_pcm_lib_ioctl_reset(substream, arg); case SNDRV_PCM_IOCTL1_CHANNEL_INFO: return snd_pcm_lib_ioctl_channel_info(substream, arg); + case SNDRV_PCM_IOCTL1_FIFO_SIZE: + return snd_pcm_lib_ioctl_fifo_size(substream, arg); } return -ENXIO; } diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index b5da656d1ece..ac2150e0670d 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -312,9 +312,18 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream, hw = &substream->runtime->hw; if (!params->info) - params->info = hw->info; - if (!params->fifo_size) - params->fifo_size = hw->fifo_size; + params->info = hw->info & ~SNDRV_PCM_INFO_FIFO_IN_FRAMES; + if (!params->fifo_size) { + if (snd_mask_min(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT]) == + snd_mask_max(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT]) && + snd_mask_min(¶ms->masks[SNDRV_PCM_HW_PARAM_CHANNELS]) == + snd_mask_max(¶ms->masks[SNDRV_PCM_HW_PARAM_CHANNELS])) { + changed = substream->ops->ioctl(substream, + SNDRV_PCM_IOCTL1_FIFO_SIZE, params); + if (changed < 0) + return changed; + } + } params->rmask = 0; return 0; } @@ -587,14 +596,15 @@ int snd_pcm_status(struct snd_pcm_substream *substream, if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { status->avail = snd_pcm_playback_avail(runtime); if (runtime->status->state == SNDRV_PCM_STATE_RUNNING || - runtime->status->state == SNDRV_PCM_STATE_DRAINING) + runtime->status->state == SNDRV_PCM_STATE_DRAINING) { status->delay = runtime->buffer_size - status->avail; - else + status->delay += runtime->delay; + } else status->delay = 0; } else { status->avail = snd_pcm_capture_avail(runtime); if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) - status->delay = status->avail; + status->delay = status->avail + runtime->delay; else status->delay = 0; } @@ -2410,6 +2420,7 @@ static int snd_pcm_delay(struct snd_pcm_substream *substream, n = snd_pcm_playback_hw_avail(runtime); else n = snd_pcm_capture_avail(runtime); + n += runtime->delay; break; case SNDRV_PCM_STATE_XRUN: err = -EPIPE; diff --git a/sound/core/seq/Kconfig b/sound/core/seq/Kconfig new file mode 100644 index 000000000000..b851fd890a89 --- /dev/null +++ b/sound/core/seq/Kconfig @@ -0,0 +1,16 @@ +# define SND_XXX_SEQ to min(SND_SEQUENCER,SND_XXX) + +config SND_RAWMIDI_SEQ + def_tristate SND_SEQUENCER && SND_RAWMIDI + +config SND_OPL3_LIB_SEQ + def_tristate SND_SEQUENCER && SND_OPL3_LIB + +config SND_OPL4_LIB_SEQ + def_tristate SND_SEQUENCER && SND_OPL4_LIB + +config SND_SBAWE_SEQ + def_tristate SND_SEQUENCER && SND_SBAWE + +config SND_EMU10K1_SEQ + def_tristate SND_SEQUENCER && SND_EMU10K1 diff --git a/sound/core/seq/Makefile b/sound/core/seq/Makefile index 069593717fba..1bcb360330e5 100644 --- a/sound/core/seq/Makefile +++ b/sound/core/seq/Makefile @@ -17,14 +17,6 @@ snd-seq-midi-event-objs := seq_midi_event.o snd-seq-dummy-objs := seq_dummy.o snd-seq-virmidi-objs := seq_virmidi.o -# -# this function returns: -# "m" - CONFIG_SND_SEQUENCER is m -# - CONFIG_SND_SEQUENCER is undefined -# otherwise parameter #1 value -# -sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1))) - obj-$(CONFIG_SND_SEQUENCER) += snd-seq.o snd-seq-device.o ifeq ($(CONFIG_SND_SEQUENCER_OSS),y) obj-$(CONFIG_SND_SEQUENCER) += snd-seq-midi-event.o @@ -33,8 +25,8 @@ obj-$(CONFIG_SND_SEQ_DUMMY) += snd-seq-dummy.o # Toplevel Module Dependency obj-$(CONFIG_SND_VIRMIDI) += snd-seq-virmidi.o snd-seq-midi-event.o -obj-$(call sequencer,$(CONFIG_SND_RAWMIDI)) += snd-seq-midi.o snd-seq-midi-event.o -obj-$(call sequencer,$(CONFIG_SND_OPL3_LIB)) += snd-seq-midi-event.o snd-seq-midi-emul.o -obj-$(call sequencer,$(CONFIG_SND_OPL4_LIB)) += snd-seq-midi-event.o snd-seq-midi-emul.o -obj-$(call sequencer,$(CONFIG_SND_SBAWE)) += snd-seq-midi-emul.o snd-seq-virmidi.o -obj-$(call sequencer,$(CONFIG_SND_EMU10K1)) += snd-seq-midi-emul.o snd-seq-virmidi.o +obj-$(CONFIG_SND_RAWMIDI_SEQ) += snd-seq-midi.o snd-seq-midi-event.o +obj-$(CONFIG_SND_OPL3_LIB_SEQ) += snd-seq-midi-event.o snd-seq-midi-emul.o +obj-$(CONFIG_SND_OPL4_LIB_SEQ) += snd-seq-midi-event.o snd-seq-midi-emul.o +obj-$(CONFIG_SND_SBAWE_SEQ) += snd-seq-midi-emul.o snd-seq-virmidi.o +obj-$(CONFIG_SND_EMU10K1_SEQ) += snd-seq-midi-emul.o snd-seq-virmidi.o diff --git a/sound/core/seq/seq_midi_event.c b/sound/core/seq/seq_midi_event.c index 8284f176a342..b5d6ea4904c0 100644 --- a/sound/core/seq/seq_midi_event.c +++ b/sound/core/seq/seq_midi_event.c @@ -504,10 +504,10 @@ static int extra_decode_xrpn(struct snd_midi_event *dev, unsigned char *buf, if (dev->nostat && count < 12) return -ENOMEM; cmd = MIDI_CMD_CONTROL|(ev->data.control.channel & 0x0f); - bytes[0] = ev->data.control.param & 0x007f; - bytes[1] = (ev->data.control.param & 0x3f80) >> 7; - bytes[2] = ev->data.control.value & 0x007f; - bytes[3] = (ev->data.control.value & 0x3f80) >> 7; + bytes[0] = (ev->data.control.param & 0x3f80) >> 7; + bytes[1] = ev->data.control.param & 0x007f; + bytes[2] = (ev->data.control.value & 0x3f80) >> 7; + bytes[3] = ev->data.control.value & 0x007f; if (cmd != dev->lastcmd && !dev->nostat) { if (count < 9) return -ENOMEM; diff --git a/sound/drivers/opl3/Makefile b/sound/drivers/opl3/Makefile index 19767a6a5c54..7f2c2a10c4e5 100644 --- a/sound/drivers/opl3/Makefile +++ b/sound/drivers/opl3/Makefile @@ -7,14 +7,6 @@ snd-opl3-lib-objs := opl3_lib.o opl3_synth.o snd-opl3-synth-y := opl3_seq.o opl3_midi.o opl3_drums.o snd-opl3-synth-$(CONFIG_SND_SEQUENCER_OSS) += opl3_oss.o -# -# this function returns: -# "m" - CONFIG_SND_SEQUENCER is m -# - CONFIG_SND_SEQUENCER is undefined -# otherwise parameter #1 value -# -sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1))) - obj-$(CONFIG_SND_OPL3_LIB) += snd-opl3-lib.o obj-$(CONFIG_SND_OPL4_LIB) += snd-opl3-lib.o -obj-$(call sequencer,$(CONFIG_SND_OPL3_LIB)) += snd-opl3-synth.o +obj-$(CONFIG_SND_OPL3_LIB_SEQ) += snd-opl3-synth.o diff --git a/sound/drivers/opl4/Makefile b/sound/drivers/opl4/Makefile index d178b39ffa60..b94009b0b19f 100644 --- a/sound/drivers/opl4/Makefile +++ b/sound/drivers/opl4/Makefile @@ -6,13 +6,5 @@ snd-opl4-lib-objs := opl4_lib.o opl4_mixer.o opl4_proc.o snd-opl4-synth-objs := opl4_seq.o opl4_synth.o yrw801.o -# -# this function returns: -# "m" - CONFIG_SND_SEQUENCER is m -# - CONFIG_SND_SEQUENCER is undefined -# otherwise parameter #1 value -# -sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1))) - obj-$(CONFIG_SND_OPL4_LIB) += snd-opl4-lib.o -obj-$(call sequencer,$(CONFIG_SND_OPL4_LIB)) += snd-opl4-synth.o +obj-$(CONFIG_SND_OPL4_LIB_SEQ) += snd-opl4-synth.o diff --git a/sound/drivers/pcsp/pcsp.h b/sound/drivers/pcsp/pcsp.h index cdef2664218f..174dd2ff0f22 100644 --- a/sound/drivers/pcsp/pcsp.h +++ b/sound/drivers/pcsp/pcsp.h @@ -10,6 +10,7 @@ #define __PCSP_H__ #include +#include #if defined(CONFIG_MIPS) || defined(CONFIG_X86) /* Use the global PIT lock ! */ #include diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig index c6942a4de99b..51a7e3777e17 100644 --- a/sound/isa/Kconfig +++ b/sound/isa/Kconfig @@ -177,15 +177,18 @@ config SND_ES18XX will be called snd-es18xx. config SND_SC6000 - tristate "Gallant SC-6000, Audio Excel DSP 16" + tristate "Gallant SC-6000/6600/7000 and Audio Excel DSP 16" depends on HAS_IOPORT select SND_WSS_LIB select SND_OPL3_LIB select SND_MPU401_UART help - Say Y here to include support for Gallant SC-6000 card and clones: + Say Y here to include support for Gallant SC-6000, SC-6600, SC-7000 + cards and clones: Audio Excel DSP 16 and Zoltrix AV302. + These cards are based on CompuMedia ASC-9308 or ASC-9408 chips. + To compile this driver as a module, choose M here: the module will be called snd-sc6000. diff --git a/sound/isa/es1688/es1688.c b/sound/isa/es1688/es1688.c index 442b081cafb7..07df201ed8fa 100644 --- a/sound/isa/es1688/es1688.c +++ b/sound/isa/es1688/es1688.c @@ -193,7 +193,7 @@ static int __devexit snd_es1688_remove(struct device *dev, unsigned int n) static struct isa_driver snd_es1688_driver = { .match = snd_es1688_match, .probe = snd_es1688_probe, - .remove = snd_es1688_remove, + .remove = __devexit_p(snd_es1688_remove), #if 0 /* FIXME */ .suspend = snd_es1688_suspend, .resume = snd_es1688_resume, diff --git a/sound/isa/gus/gusextreme.c b/sound/isa/gus/gusextreme.c index 180a8dea6bd9..65e4b18581a6 100644 --- a/sound/isa/gus/gusextreme.c +++ b/sound/isa/gus/gusextreme.c @@ -348,7 +348,7 @@ static int __devexit snd_gusextreme_remove(struct device *dev, unsigned int n) static struct isa_driver snd_gusextreme_driver = { .match = snd_gusextreme_match, .probe = snd_gusextreme_probe, - .remove = snd_gusextreme_remove, + .remove = __devexit_p(snd_gusextreme_remove), #if 0 /* FIXME */ .suspend = snd_gusextreme_suspend, .resume = snd_gusextreme_resume, diff --git a/sound/isa/sb/Makefile b/sound/isa/sb/Makefile index 1098a56b2f4b..faeffceb01b7 100644 --- a/sound/isa/sb/Makefile +++ b/sound/isa/sb/Makefile @@ -13,14 +13,6 @@ snd-sbawe-objs := sbawe.o emu8000.o snd-emu8000-synth-objs := emu8000_synth.o emu8000_callback.o emu8000_patch.o emu8000_pcm.o snd-es968-objs := es968.o -# -# this function returns: -# "m" - CONFIG_SND_SEQUENCER is m -# - CONFIG_SND_SEQUENCER is undefined -# otherwise parameter #1 value -# -sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1))) - # Toplevel Module Dependency obj-$(CONFIG_SND_SB_COMMON) += snd-sb-common.o obj-$(CONFIG_SND_SB16_DSP) += snd-sb16-dsp.o @@ -33,4 +25,4 @@ ifeq ($(CONFIG_SND_SB16_CSP),y) obj-$(CONFIG_SND_SB16) += snd-sb16-csp.o obj-$(CONFIG_SND_SBAWE) += snd-sb16-csp.o endif -obj-$(call sequencer,$(CONFIG_SND_SBAWE)) += snd-emu8000-synth.o +obj-$(CONFIG_SND_SBAWE_SEQ) += snd-emu8000-synth.o diff --git a/sound/isa/sc6000.c b/sound/isa/sc6000.c index 782010608ef4..9a8bbf6dd62a 100644 --- a/sound/isa/sc6000.c +++ b/sound/isa/sc6000.c @@ -2,6 +2,8 @@ * Driver for Gallant SC-6000 soundcard. This card is also known as * Audio Excel DSP 16 or Zoltrix AV302. * These cards use CompuMedia ASC-9308 chip + AD1848 codec. + * SC-6600 and SC-7000 cards are also supported. They are based on + * CompuMedia ASC-9408 chip and CS4231 codec. * * Copyright (C) 2007 Krzysztof Helt * @@ -54,6 +56,7 @@ static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x300, 0x310, 0x320, 0x330 */ static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 5, 7, 9, 10, 0 */ static int dma[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0, 1, 3 */ +static bool joystick[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = false }; module_param_array(index, int, NULL, 0444); MODULE_PARM_DESC(index, "Index value for sc-6000 based soundcard."); @@ -73,6 +76,8 @@ module_param_array(mpu_irq, int, NULL, 0444); MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for sc-6000 driver."); module_param_array(dma, int, NULL, 0444); MODULE_PARM_DESC(dma, "DMA # for sc-6000 driver."); +module_param_array(joystick, bool, NULL, 0444); +MODULE_PARM_DESC(joystick, "Enable gameport."); /* * Commands of SC6000's DSP (SBPRO+special). @@ -191,7 +196,7 @@ static __devinit unsigned char sc6000_mpu_irq_to_softcfg(int mpu_irq) return val; } -static __devinit int sc6000_wait_data(char __iomem *vport) +static int sc6000_wait_data(char __iomem *vport) { int loop = 1000; unsigned char val = 0; @@ -206,7 +211,7 @@ static __devinit int sc6000_wait_data(char __iomem *vport) return -EAGAIN; } -static __devinit int sc6000_read(char __iomem *vport) +static int sc6000_read(char __iomem *vport) { if (sc6000_wait_data(vport)) return -EBUSY; @@ -215,7 +220,7 @@ static __devinit int sc6000_read(char __iomem *vport) } -static __devinit int sc6000_write(char __iomem *vport, int cmd) +static int sc6000_write(char __iomem *vport, int cmd) { unsigned char val; int loop = 500000; @@ -276,8 +281,33 @@ static int __devinit sc6000_dsp_reset(char __iomem *vport) } /* detection and initialization */ -static int __devinit sc6000_cfg_write(char __iomem *vport, - unsigned char softcfg) +static int __devinit sc6000_hw_cfg_write(char __iomem *vport, const int *cfg) +{ + if (sc6000_write(vport, COMMAND_6C) < 0) { + snd_printk(KERN_WARNING "CMD 0x%x: failed!\n", COMMAND_6C); + return -EIO; + } + if (sc6000_write(vport, COMMAND_5C) < 0) { + snd_printk(KERN_ERR "CMD 0x%x: failed!\n", COMMAND_5C); + return -EIO; + } + if (sc6000_write(vport, cfg[0]) < 0) { + snd_printk(KERN_ERR "DATA 0x%x: failed!\n", cfg[0]); + return -EIO; + } + if (sc6000_write(vport, cfg[1]) < 0) { + snd_printk(KERN_ERR "DATA 0x%x: failed!\n", cfg[1]); + return -EIO; + } + if (sc6000_write(vport, COMMAND_C5) < 0) { + snd_printk(KERN_ERR "CMD 0x%x: failed!\n", COMMAND_C5); + return -EIO; + } + + return 0; +} + +static int sc6000_cfg_write(char __iomem *vport, unsigned char softcfg) { if (sc6000_write(vport, WRITE_MDIRQ_CFG)) { @@ -291,7 +321,7 @@ static int __devinit sc6000_cfg_write(char __iomem *vport, return 0; } -static int __devinit sc6000_setup_board(char __iomem *vport, int config) +static int sc6000_setup_board(char __iomem *vport, int config) { int loop = 10; @@ -334,16 +364,39 @@ static int __devinit sc6000_init_mss(char __iomem *vport, int config, return 0; } -static int __devinit sc6000_init_board(char __iomem *vport, int irq, int dma, - char __iomem *vmss_port, int mpu_irq) +static void __devinit sc6000_hw_cfg_encode(char __iomem *vport, int *cfg, + long xport, long xmpu, + long xmss_port, int joystick) +{ + cfg[0] = 0; + cfg[1] = 0; + if (xport == 0x240) + cfg[0] |= 1; + if (xmpu != SNDRV_AUTO_PORT) { + cfg[0] |= (xmpu & 0x30) >> 2; + cfg[1] |= 0x20; + } + if (xmss_port == 0xe80) + cfg[0] |= 0x10; + cfg[0] |= 0x40; /* always set */ + if (!joystick) + cfg[0] |= 0x02; + cfg[1] |= 0x80; /* enable WSS system */ + cfg[1] &= ~0x40; /* disable IDE */ + snd_printd("hw cfg %x, %x\n", cfg[0], cfg[1]); +} + +static int __devinit sc6000_init_board(char __iomem *vport, + char __iomem *vmss_port, int dev) { char answer[15]; char version[2]; - int mss_config = sc6000_irq_to_softcfg(irq) | - sc6000_dma_to_softcfg(dma); + int mss_config = sc6000_irq_to_softcfg(irq[dev]) | + sc6000_dma_to_softcfg(dma[dev]); int config = mss_config | - sc6000_mpu_irq_to_softcfg(mpu_irq); + sc6000_mpu_irq_to_softcfg(mpu_irq[dev]); int err; + int old = 0; err = sc6000_dsp_reset(vport); if (err < 0) { @@ -360,7 +413,6 @@ static int __devinit sc6000_init_board(char __iomem *vport, int irq, int dma, /* * My SC-6000 card return "SC-6000" in DSPCopyright, so * if we have something different, we have to be warned. - * Mine returns "SC-6000A " - KH */ if (strncmp("SC-6000", answer, 7)) snd_printk(KERN_WARNING "Warning: non SC-6000 audio card!\n"); @@ -372,13 +424,32 @@ static int __devinit sc6000_init_board(char __iomem *vport, int irq, int dma, printk(KERN_INFO PFX "Detected model: %s, DSP version %d.%d\n", answer, version[0], version[1]); - /* - * 0x0A == (IRQ 7, DMA 1, MIRQ 0) - */ - err = sc6000_cfg_write(vport, 0x0a); + /* set configuration */ + sc6000_write(vport, COMMAND_5C); + if (sc6000_read(vport) < 0) + old = 1; + + if (!old) { + int cfg[2]; + sc6000_hw_cfg_encode(vport, &cfg[0], port[dev], mpu_port[dev], + mss_port[dev], joystick[dev]); + if (sc6000_hw_cfg_write(vport, cfg) < 0) { + snd_printk(KERN_ERR "sc6000_hw_cfg_write: failed!\n"); + return -EIO; + } + } + err = sc6000_setup_board(vport, config); if (err < 0) { - snd_printk(KERN_ERR "sc6000_cfg_write: failed!\n"); - return -EFAULT; + snd_printk(KERN_ERR "sc6000_setup_board: failed!\n"); + return -ENODEV; + } + + sc6000_dsp_reset(vport); + + if (!old) { + sc6000_write(vport, COMMAND_60); + sc6000_write(vport, 0x02); + sc6000_dsp_reset(vport); } err = sc6000_setup_board(vport, config); @@ -386,10 +457,9 @@ static int __devinit sc6000_init_board(char __iomem *vport, int irq, int dma, snd_printk(KERN_ERR "sc6000_setup_board: failed!\n"); return -ENODEV; } - err = sc6000_init_mss(vport, config, vmss_port, mss_config); if (err < 0) { - snd_printk(KERN_ERR "Can not initialize " + snd_printk(KERN_ERR "Cannot initialize " "Microsoft Sound System mode.\n"); return -ENODEV; } @@ -485,14 +555,16 @@ static int __devinit snd_sc6000_probe(struct device *devptr, unsigned int dev) struct snd_card *card; struct snd_wss *chip; struct snd_opl3 *opl3; - char __iomem *vport; + char __iomem **vport; char __iomem *vmss_port; - err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); + err = snd_card_create(index[dev], id[dev], THIS_MODULE, sizeof(vport), + &card); if (err < 0) return err; + vport = card->private_data; if (xirq == SNDRV_AUTO_IRQ) { xirq = snd_legacy_find_free_irq(possible_irqs); if (xirq < 0) { @@ -517,8 +589,8 @@ static int __devinit snd_sc6000_probe(struct device *devptr, unsigned int dev) err = -EBUSY; goto err_exit; } - vport = devm_ioport_map(devptr, port[dev], 0x10); - if (!vport) { + *vport = devm_ioport_map(devptr, port[dev], 0x10); + if (*vport == NULL) { snd_printk(KERN_ERR PFX "I/O port cannot be iomaped.\n"); err = -EBUSY; @@ -533,7 +605,7 @@ static int __devinit snd_sc6000_probe(struct device *devptr, unsigned int dev) goto err_unmap1; } vmss_port = devm_ioport_map(devptr, mss_port[dev], 4); - if (!vport) { + if (!vmss_port) { snd_printk(KERN_ERR PFX "MSS port I/O cannot be iomaped.\n"); err = -EBUSY; @@ -544,7 +616,7 @@ static int __devinit snd_sc6000_probe(struct device *devptr, unsigned int dev) port[dev], xirq, xdma, mpu_irq[dev] == SNDRV_AUTO_IRQ ? 0 : mpu_irq[dev]); - err = sc6000_init_board(vport, xirq, xdma, vmss_port, mpu_irq[dev]); + err = sc6000_init_board(*vport, vmss_port, dev); if (err < 0) goto err_unmap2; @@ -552,7 +624,6 @@ static int __devinit snd_sc6000_probe(struct device *devptr, unsigned int dev) WSS_HW_DETECT, 0, &chip); if (err < 0) goto err_unmap2; - card->private_data = chip; err = snd_wss_pcm(chip, 0, NULL); if (err < 0) { @@ -608,6 +679,7 @@ static int __devinit snd_sc6000_probe(struct device *devptr, unsigned int dev) return 0; err_unmap2: + sc6000_setup_board(*vport, 0); release_region(mss_port[dev], 4); err_unmap1: release_region(port[dev], 0x10); @@ -618,11 +690,17 @@ err_exit: static int __devexit snd_sc6000_remove(struct device *devptr, unsigned int dev) { + struct snd_card *card = dev_get_drvdata(devptr); + char __iomem **vport = card->private_data; + + if (sc6000_setup_board(*vport, 0) < 0) + snd_printk(KERN_WARNING "sc6000_setup_board failed on exit!\n"); + release_region(port[dev], 0x10); release_region(mss_port[dev], 4); - snd_card_free(dev_get_drvdata(devptr)); dev_set_drvdata(devptr, NULL); + snd_card_free(card); return 0; } diff --git a/sound/mips/sgio2audio.c b/sound/mips/sgio2audio.c index 66f3b48ceafc..e497525bc11b 100644 --- a/sound/mips/sgio2audio.c +++ b/sound/mips/sgio2audio.c @@ -619,8 +619,7 @@ static int snd_sgio2audio_pcm_hw_params(struct snd_pcm_substream *substream, /* hw_free callback */ static int snd_sgio2audio_pcm_hw_free(struct snd_pcm_substream *substream) { - if (substream->runtime->dma_area) - vfree(substream->runtime->dma_area); + vfree(substream->runtime->dma_area); substream->runtime->dma_area = NULL; return 0; } diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig index 1ca7427c4b6d..bcf2a0698d54 100644 --- a/sound/oss/Kconfig +++ b/sound/oss/Kconfig @@ -561,7 +561,7 @@ endif # SOUND_OSS config SOUND_SH_DAC_AUDIO tristate "SuperH DAC audio support" - depends on CPU_SH3 + depends on CPU_SH3 && HIGH_RES_TIMERS config SOUND_SH_DAC_AUDIO_CHANNEL int "DAC channel" diff --git a/sound/oss/msnd.c b/sound/oss/msnd.c index e4282d93a1aa..21eb6dce46df 100644 --- a/sound/oss/msnd.c +++ b/sound/oss/msnd.c @@ -100,7 +100,7 @@ void msnd_fifo_free(msnd_fifo *f) int msnd_fifo_alloc(msnd_fifo *f, size_t n) { msnd_fifo_free(f); - f->data = (char *)vmalloc(n); + f->data = vmalloc(n); f->n = n; f->tail = 0; f->head = 0; diff --git a/sound/oss/pas2_pcm.c b/sound/oss/pas2_pcm.c index 36c3ea62086b..8f7d175767a2 100644 --- a/sound/oss/pas2_pcm.c +++ b/sound/oss/pas2_pcm.c @@ -17,7 +17,7 @@ #include #include -#include +#include #include "sound_config.h" #include "pas2.h" diff --git a/sound/oss/sh_dac_audio.c b/sound/oss/sh_dac_audio.c index 78cfb66e4c59..b2ed8757542a 100644 --- a/sound/oss/sh_dac_audio.c +++ b/sound/oss/sh_dac_audio.c @@ -18,47 +18,36 @@ #include #include #include +#include #include #include #include #include #include -#include -#include +#include #include #include #include #define MODNAME "sh_dac_audio" -#define TMU_TOCR_INIT 0x00 - -#define TMU1_TCR_INIT 0x0020 /* Clock/4, rising edge; interrupt on */ -#define TMU1_TSTR_INIT 0x02 /* Bit to turn on TMU1 */ - #define BUFFER_SIZE 48000 static int rate; static int empty; static char *data_buffer, *buffer_begin, *buffer_end; static int in_use, device_major; +static struct hrtimer hrtimer; +static ktime_t wakeups_per_second; static void dac_audio_start_timer(void) { - u8 tstr; - - tstr = ctrl_inb(TMU_TSTR); - tstr |= TMU1_TSTR_INIT; - ctrl_outb(tstr, TMU_TSTR); + hrtimer_start(&hrtimer, wakeups_per_second, HRTIMER_MODE_REL); } static void dac_audio_stop_timer(void) { - u8 tstr; - - tstr = ctrl_inb(TMU_TSTR); - tstr &= ~TMU1_TSTR_INIT; - ctrl_outb(tstr, TMU_TSTR); + hrtimer_cancel(&hrtimer); } static void dac_audio_reset(void) @@ -77,38 +66,30 @@ static void dac_audio_sync(void) static void dac_audio_start(void) { if (mach_is_hp6xx()) { - u16 v = inw(HD64461_GPADR); + u16 v = __raw_readw(HD64461_GPADR); v &= ~HD64461_GPADR_SPEAKER; - outw(v, HD64461_GPADR); + __raw_writew(v, HD64461_GPADR); } sh_dac_enable(CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL); - ctrl_outw(TMU1_TCR_INIT, TMU1_TCR); } static void dac_audio_stop(void) { dac_audio_stop_timer(); if (mach_is_hp6xx()) { - u16 v = inw(HD64461_GPADR); + u16 v = __raw_readw(HD64461_GPADR); v |= HD64461_GPADR_SPEAKER; - outw(v, HD64461_GPADR); + __raw_writew(v, HD64461_GPADR); } - sh_dac_output(0, CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL); + sh_dac_output(0, CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL); sh_dac_disable(CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL); } static void dac_audio_set_rate(void) { - unsigned long interval; - struct clk *clk; - - clk = clk_get(NULL, "module_clk"); - interval = (clk_get_rate(clk) / 4) / rate; - clk_put(clk); - ctrl_outl(interval, TMU1_TCOR); - ctrl_outl(interval, TMU1_TCNT); + wakeups_per_second = ktime_set(0, 1000000000 / rate); } static int dac_audio_ioctl(struct inode *inode, struct file *file, @@ -265,32 +246,26 @@ const struct file_operations dac_audio_fops = { .release = dac_audio_release, }; -static irqreturn_t timer1_interrupt(int irq, void *dev) +static enum hrtimer_restart sh_dac_audio_timer(struct hrtimer *handle) { - unsigned long timer_status; - - timer_status = ctrl_inw(TMU1_TCR); - timer_status &= ~0x100; - ctrl_outw(timer_status, TMU1_TCR); - if (!empty) { sh_dac_output(*buffer_begin, CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL); buffer_begin++; if (buffer_begin == data_buffer + BUFFER_SIZE) buffer_begin = data_buffer; - if (buffer_begin == buffer_end) { + if (buffer_begin == buffer_end) empty = 1; - dac_audio_stop_timer(); - } } - return IRQ_HANDLED; + + if (!empty) + hrtimer_start(&hrtimer, wakeups_per_second, HRTIMER_MODE_REL); + + return HRTIMER_NORESTART; } static int __init dac_audio_init(void) { - int retval; - if ((device_major = register_sound_dsp(&dac_audio_fops, -1)) < 0) { printk(KERN_ERR "Cannot register dsp device"); return device_major; @@ -306,21 +281,25 @@ static int __init dac_audio_init(void) rate = 8000; dac_audio_set_rate(); - retval = - request_irq(TIMER1_IRQ, timer1_interrupt, IRQF_DISABLED, MODNAME, 0); - if (retval < 0) { - printk(KERN_ERR "sh_dac_audio: IRQ %d request failed\n", - TIMER1_IRQ); - return retval; - } + /* Today: High Resolution Timer driven DAC playback. + * The timer callback gets called once per sample. Ouch. + * + * Future: A much better approach would be to use the + * SH7720 CMT+DMAC+DAC hardware combination like this: + * - Program sample rate using CMT0 or CMT1 + * - Program DMAC to use CMT for timing and output to DAC + * - Play sound using DMAC, let CPU sleep. + * - While at it, rewrite this driver to use ALSA. + */ + + hrtimer_init(&hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + hrtimer.function = sh_dac_audio_timer; return 0; } static void __exit dac_audio_exit(void) { - free_irq(TIMER1_IRQ, 0); - unregister_sound_dsp(device_major); kfree((void *)data_buffer); } diff --git a/sound/parisc/harmony.c b/sound/parisc/harmony.c index 6055fd6d3b38..e924492df21d 100644 --- a/sound/parisc/harmony.c +++ b/sound/parisc/harmony.c @@ -935,7 +935,7 @@ snd_harmony_create(struct snd_card *card, h->iobase = ioremap_nocache(padev->hpa.start, HARMONY_SIZE); if (h->iobase == NULL) { printk(KERN_ERR PFX "unable to remap hpa 0x%lx\n", - padev->hpa.start); + (unsigned long)padev->hpa.start); err = -EBUSY; goto free_and_ret; } @@ -1020,7 +1020,7 @@ static struct parisc_driver snd_harmony_driver = { .name = "harmony", .id_table = snd_harmony_devtable, .probe = snd_harmony_probe, - .remove = snd_harmony_remove, + .remove = __devexit_p(snd_harmony_remove), }; static int __init diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 93422e3a3f0c..748f6b7d90b7 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -275,6 +275,16 @@ config SND_CS5535AUDIO To compile this driver as a module, choose M here: the module will be called snd-cs5535audio. +config SND_CTXFI + tristate "Creative Sound Blaster X-Fi" + select SND_PCM + help + If you want to use soundcards based on Creative Sound Blastr X-Fi + boards with 20k1 or 20k2 chips, say Y here. + + To compile this driver as a module, choose M here: the module + will be called snd-ctxfi. + config SND_DARLA20 tristate "(Echoaudio) Darla20" select FW_LOADER @@ -532,6 +542,9 @@ config SND_HDSP To compile this driver as a module, choose M here: the module will be called snd-hdsp. +comment "Don't forget to add built-in firmwares for HDSP driver" + depends on SND_HDSP=y + config SND_HDSPM tristate "RME Hammerfall DSP MADI" select SND_HWDEP @@ -622,6 +635,16 @@ config SND_KORG1212 To compile this driver as a module, choose M here: the module will be called snd-korg1212. +config SND_LX6464ES + tristate "Digigram LX6464ES" + select SND_PCM + help + Say Y here to include support for Digigram LX6464ES boards. + + To compile this driver as a module, choose M here: the module + will be called snd-lx6464es. + + config SND_MAESTRO3 tristate "ESS Allegro/Maestro3" select SND_AC97_CODEC @@ -764,8 +787,8 @@ config SND_VIRTUOSO select SND_OXYGEN_LIB help Say Y here to include support for sound cards based on the - Asus AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X, and - Essence STX. + Asus AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X, + Essence ST (Deluxe), and Essence STX. Support for the HDAV1.3 (Deluxe) is very experimental. To compile this driver as a module, choose M here: the module diff --git a/sound/pci/Makefile b/sound/pci/Makefile index 65b25d221cd2..ecfc609d2b9f 100644 --- a/sound/pci/Makefile +++ b/sound/pci/Makefile @@ -59,9 +59,11 @@ obj-$(CONFIG_SND) += \ ali5451/ \ au88x0/ \ aw2/ \ + ctxfi/ \ ca0106/ \ cs46xx/ \ cs5535audio/ \ + lx6464es/ \ echoaudio/ \ emu10k1/ \ hda/ \ diff --git a/sound/pci/au88x0/au88x0_core.c b/sound/pci/au88x0/au88x0_core.c index 3906f5afe27a..23f49f356e0f 100644 --- a/sound/pci/au88x0/au88x0_core.c +++ b/sound/pci/au88x0/au88x0_core.c @@ -1255,8 +1255,8 @@ static int inline vortex_adbdma_getlinearpos(vortex_t * vortex, int adbdma) int temp; temp = hwread(vortex->mmio, VORTEX_ADBDMA_STAT + (adbdma << 2)); - temp = (dma->period_virt * dma->period_bytes) + (temp & POS_MASK); - return (temp); + temp = (dma->period_virt * dma->period_bytes) + (temp & (dma->period_bytes - 1)); + return temp; } static void vortex_adbdma_startfifo(vortex_t * vortex, int adbdma) @@ -1504,8 +1504,7 @@ static int inline vortex_wtdma_getlinearpos(vortex_t * vortex, int wtdma) int temp; temp = hwread(vortex->mmio, VORTEX_WTDMA_STAT + (wtdma << 2)); - //temp = (temp & POS_MASK) + (((temp>>WT_SUBBUF_SHIFT) & WT_SUBBUF_MASK)*(dma->cfg0&POS_MASK)); - temp = (temp & POS_MASK) + ((dma->period_virt) * (dma->period_bytes)); + temp = (dma->period_virt * dma->period_bytes) + (temp & (dma->period_bytes - 1)); return temp; } @@ -2441,7 +2440,8 @@ static irqreturn_t vortex_interrupt(int irq, void *dev_id) spin_lock(&vortex->lock); for (i = 0; i < NR_ADB; i++) { if (vortex->dma_adb[i].fifo_status == FIFO_START) { - if (vortex_adbdma_bufshift(vortex, i)) ; + if (!vortex_adbdma_bufshift(vortex, i)) + continue; spin_unlock(&vortex->lock); snd_pcm_period_elapsed(vortex->dma_adb[i]. substream); diff --git a/sound/pci/aw2/aw2-saa7146.c b/sound/pci/aw2/aw2-saa7146.c index 6a3891ab69dd..296123ab74f7 100644 --- a/sound/pci/aw2/aw2-saa7146.c +++ b/sound/pci/aw2/aw2-saa7146.c @@ -108,7 +108,7 @@ void snd_aw2_saa7146_setup(struct snd_aw2_saa7146 *chip, #endif /* WS0_CTRL, WS0_SYNC: input TSL1, I2S */ - /* At initialization WS1 and WS2 are disbaled (configured as input */ + /* At initialization WS1 and WS2 are disabled (configured as input) */ acon1 |= 0 * WS1_CTRL; acon1 |= 0 * WS2_CTRL; diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c index ce3f2e90f4d7..24585c6c6d01 100644 --- a/sound/pci/bt87x.c +++ b/sound/pci/bt87x.c @@ -810,6 +810,8 @@ static struct pci_device_id snd_bt87x_ids[] = { BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x107d, 0x6606, GENERIC), /* Voodoo TV 200 */ BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x121a, 0x3000, GENERIC), + /* Askey Computer Corp. MagicTView'99 */ + BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x144f, 0x3000, GENERIC), /* AVerMedia Studio No. 103, 203, ...? */ BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x1461, 0x0003, AVPHONE98), /* Prolink PixelView PV-M4900 */ diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index bfac30f7929f..57b992a5c057 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -1319,7 +1319,6 @@ static int __devinit snd_ca0106_pcm(struct snd_ca0106 *emu, int device) } pcm->info_flags = 0; - pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; strcpy(pcm->name, "CA0106"); for(substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c index c111efe61c3c..c8c6f437f5b3 100644 --- a/sound/pci/ca0106/ca0106_mixer.c +++ b/sound/pci/ca0106/ca0106_mixer.c @@ -739,7 +739,7 @@ static int __devinit rename_ctl(struct snd_card *card, const char *src, const ch } while (0) static __devinitdata -DECLARE_TLV_DB_SCALE(snd_ca0106_master_db_scale, -6375, 50, 1); +DECLARE_TLV_DB_SCALE(snd_ca0106_master_db_scale, -6375, 25, 1); static char *slave_vols[] __devinitdata = { "Analog Front Playback Volume", @@ -841,6 +841,9 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu) snd_ca0106_master_db_scale); if (!vmaster) return -ENOMEM; + err = snd_ctl_add(card, vmaster); + if (err < 0) + return err; add_slaves(card, vmaster, slave_vols); if (emu->details->spi_dac == 1) { @@ -848,8 +851,13 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu) NULL); if (!vmaster) return -ENOMEM; + err = snd_ctl_add(card, vmaster); + if (err < 0) + return err; add_slaves(card, vmaster, slave_sws); } + + strcpy(card->mixername, "CA0106"); return 0; } diff --git a/sound/pci/ctxfi/Makefile b/sound/pci/ctxfi/Makefile new file mode 100644 index 000000000000..15075f89e98a --- /dev/null +++ b/sound/pci/ctxfi/Makefile @@ -0,0 +1,5 @@ +snd-ctxfi-objs := xfi.o ctatc.o ctvmem.o ctpcm.o ctmixer.o ctresource.o \ + ctsrc.o ctamixer.o ctdaio.o ctimap.o cthardware.o cttimer.o \ + cthw20k2.o cthw20k1.o + +obj-$(CONFIG_SND_CTXFI) += snd-ctxfi.o diff --git a/sound/pci/ctxfi/ct20k1reg.h b/sound/pci/ctxfi/ct20k1reg.h new file mode 100644 index 000000000000..f2e34e3f27ee --- /dev/null +++ b/sound/pci/ctxfi/ct20k1reg.h @@ -0,0 +1,636 @@ +/** + * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. + * + * This source file is released under GPL v2 license (no other versions). + * See the COPYING file included in the main directory of this source + * distribution for the license terms and conditions. + */ + +#ifndef CT20K1REG_H +#define CT20k1REG_H + +/* 20k1 registers */ +#define DSPXRAM_START 0x000000 +#define DSPXRAM_END 0x013FFC +#define DSPAXRAM_START 0x020000 +#define DSPAXRAM_END 0x023FFC +#define DSPYRAM_START 0x040000 +#define DSPYRAM_END 0x04FFFC +#define DSPAYRAM_START 0x020000 +#define DSPAYRAM_END 0x063FFC +#define DSPMICRO_START 0x080000 +#define DSPMICRO_END 0x0B3FFC +#define DSP0IO_START 0x100000 +#define DSP0IO_END 0x101FFC +#define AUDIORINGIPDSP0_START 0x100000 +#define AUDIORINGIPDSP0_END 0x1003FC +#define AUDIORINGOPDSP0_START 0x100400 +#define AUDIORINGOPDSP0_END 0x1007FC +#define AUDPARARINGIODSP0_START 0x100800 +#define AUDPARARINGIODSP0_END 0x100BFC +#define DSP0LOCALHWREG_START 0x100C00 +#define DSP0LOCALHWREG_END 0x100C3C +#define DSP0XYRAMAGINDEX_START 0x100C40 +#define DSP0XYRAMAGINDEX_END 0x100C5C +#define DSP0XYRAMAGMDFR_START 0x100C60 +#define DSP0XYRAMAGMDFR_END 0x100C7C +#define DSP0INTCONTLVEC_START 0x100C80 +#define DSP0INTCONTLVEC_END 0x100CD8 +#define INTCONTLGLOBALREG_START 0x100D1C +#define INTCONTLGLOBALREG_END 0x100D3C +#define HOSTINTFPORTADDRCONTDSP0 0x100D40 +#define HOSTINTFPORTDATADSP0 0x100D44 +#define TIME0PERENBDSP0 0x100D60 +#define TIME0COUNTERDSP0 0x100D64 +#define TIME1PERENBDSP0 0x100D68 +#define TIME1COUNTERDSP0 0x100D6C +#define TIME2PERENBDSP0 0x100D70 +#define TIME2COUNTERDSP0 0x100D74 +#define TIME3PERENBDSP0 0x100D78 +#define TIME3COUNTERDSP0 0x100D7C +#define XRAMINDOPERREFNOUP_STARTDSP0 0x100D80 +#define XRAMINDOPERREFNOUP_ENDDSP0 0x100D9C +#define XRAMINDOPERREFUP_STARTDSP0 0x100DA0 +#define XRAMINDOPERREFUP_ENDDSP0 0x100DBC +#define YRAMINDOPERREFNOUP_STARTDSP0 0x100DC0 +#define YRAMINDOPERREFNOUP_ENDDSP0 0x100DDC +#define YRAMINDOPERREFUP_STARTDSP0 0x100DE0 +#define YRAMINDOPERREFUP_ENDDSP0 0x100DFC +#define DSP0CONDCODE 0x100E00 +#define DSP0STACKFLAG 0x100E04 +#define DSP0PROGCOUNTSTACKPTREG 0x100E08 +#define DSP0PROGCOUNTSTACKDATAREG 0x100E0C +#define DSP0CURLOOPADDRREG 0x100E10 +#define DSP0CURLOOPCOUNT 0x100E14 +#define DSP0TOPLOOPCOUNTSTACK 0x100E18 +#define DSP0TOPLOOPADDRSTACK 0x100E1C +#define DSP0LOOPSTACKPTR 0x100E20 +#define DSP0STASSTACKDATAREG 0x100E24 +#define DSP0STASSTACKPTR 0x100E28 +#define DSP0PROGCOUNT 0x100E2C +#define GLOBDSPDEBGREG 0x100E30 +#define GLOBDSPBREPTRREG 0x100E30 +#define DSP0XYRAMBASE_START 0x100EA0 +#define DSP0XYRAMBASE_END 0x100EBC +#define DSP0XYRAMLENG_START 0x100EC0 +#define DSP0XYRAMLENG_END 0x100EDC +#define SEMAPHOREREGDSP0 0x100EE0 +#define DSP0INTCONTMASKREG 0x100EE4 +#define DSP0INTCONTPENDREG 0x100EE8 +#define DSP0INTCONTSERVINT 0x100EEC +#define DSPINTCONTEXTINTMODREG 0x100EEC +#define GPIODSP0 0x100EFC +#define DMADSPBASEADDRREG_STARTDSP0 0x100F00 +#define DMADSPBASEADDRREG_ENDDSP0 0x100F1C +#define DMAHOSTBASEADDRREG_STARTDSP0 0x100F20 +#define DMAHOSTBASEADDRREG_ENDDSP0 0x100F3C +#define DMADSPCURADDRREG_STARTDSP0 0x100F40 +#define DMADSPCURADDRREG_ENDDSP0 0x100F5C +#define DMAHOSTCURADDRREG_STARTDSP0 0x100F60 +#define DMAHOSTCURADDRREG_ENDDSP0 0x100F7C +#define DMATANXCOUNTREG_STARTDSP0 0x100F80 +#define DMATANXCOUNTREG_ENDDSP0 0x100F9C +#define DMATIMEBUGREG_STARTDSP0 0x100FA0 +#define DMATIMEBUGREG_ENDDSP0 0x100FAC +#define DMACNTLMODFREG_STARTDSP0 0x100FA0 +#define DMACNTLMODFREG_ENDDSP0 0x100FAC + +#define DMAGLOBSTATSREGDSP0 0x100FEC +#define DSP0XGPRAM_START 0x101000 +#define DSP0XGPRAM_END 0x1017FC +#define DSP0YGPRAM_START 0x101800 +#define DSP0YGPRAM_END 0x101FFC + + + + +#define AUDIORINGIPDSP1_START 0x102000 +#define AUDIORINGIPDSP1_END 0x1023FC +#define AUDIORINGOPDSP1_START 0x102400 +#define AUDIORINGOPDSP1_END 0x1027FC +#define AUDPARARINGIODSP1_START 0x102800 +#define AUDPARARINGIODSP1_END 0x102BFC +#define DSP1LOCALHWREG_START 0x102C00 +#define DSP1LOCALHWREG_END 0x102C3C +#define DSP1XYRAMAGINDEX_START 0x102C40 +#define DSP1XYRAMAGINDEX_END 0x102C5C +#define DSP1XYRAMAGMDFR_START 0x102C60 +#define DSP1XYRAMAGMDFR_END 0x102C7C +#define DSP1INTCONTLVEC_START 0x102C80 +#define DSP1INTCONTLVEC_END 0x102CD8 +#define HOSTINTFPORTADDRCONTDSP1 0x102D40 +#define HOSTINTFPORTDATADSP1 0x102D44 +#define TIME0PERENBDSP1 0x102D60 +#define TIME0COUNTERDSP1 0x102D64 +#define TIME1PERENBDSP1 0x102D68 +#define TIME1COUNTERDSP1 0x102D6C +#define TIME2PERENBDSP1 0x102D70 +#define TIME2COUNTERDSP1 0x102D74 +#define TIME3PERENBDSP1 0x102D78 +#define TIME3COUNTERDSP1 0x102D7C +#define XRAMINDOPERREFNOUP_STARTDSP1 0x102D80 +#define XRAMINDOPERREFNOUP_ENDDSP1 0x102D9C +#define XRAMINDOPERREFUP_STARTDSP1 0x102DA0 +#define XRAMINDOPERREFUP_ENDDSP1 0x102DBC +#define YRAMINDOPERREFNOUP_STARTDSP1 0x102DC0 +#define YRAMINDOPERREFNOUP_ENDDSP1 0x102DDC +#define YRAMINDOPERREFUP_STARTDSP1 0x102DE0 +#define YRAMINDOPERREFUP_ENDDSP1 0x102DFC + +#define DSP1CONDCODE 0x102E00 +#define DSP1STACKFLAG 0x102E04 +#define DSP1PROGCOUNTSTACKPTREG 0x102E08 +#define DSP1PROGCOUNTSTACKDATAREG 0x102E0C +#define DSP1CURLOOPADDRREG 0x102E10 +#define DSP1CURLOOPCOUNT 0x102E14 +#define DSP1TOPLOOPCOUNTSTACK 0x102E18 +#define DSP1TOPLOOPADDRSTACK 0x102E1C +#define DSP1LOOPSTACKPTR 0x102E20 +#define DSP1STASSTACKDATAREG 0x102E24 +#define DSP1STASSTACKPTR 0x102E28 +#define DSP1PROGCOUNT 0x102E2C +#define DSP1XYRAMBASE_START 0x102EA0 +#define DSP1XYRAMBASE_END 0x102EBC +#define DSP1XYRAMLENG_START 0x102EC0 +#define DSP1XYRAMLENG_END 0x102EDC +#define SEMAPHOREREGDSP1 0x102EE0 +#define DSP1INTCONTMASKREG 0x102EE4 +#define DSP1INTCONTPENDREG 0x102EE8 +#define DSP1INTCONTSERVINT 0x102EEC +#define GPIODSP1 0x102EFC +#define DMADSPBASEADDRREG_STARTDSP1 0x102F00 +#define DMADSPBASEADDRREG_ENDDSP1 0x102F1C +#define DMAHOSTBASEADDRREG_STARTDSP1 0x102F20 +#define DMAHOSTBASEADDRREG_ENDDSP1 0x102F3C +#define DMADSPCURADDRREG_STARTDSP1 0x102F40 +#define DMADSPCURADDRREG_ENDDSP1 0x102F5C +#define DMAHOSTCURADDRREG_STARTDSP1 0x102F60 +#define DMAHOSTCURADDRREG_ENDDSP1 0x102F7C +#define DMATANXCOUNTREG_STARTDSP1 0x102F80 +#define DMATANXCOUNTREG_ENDDSP1 0x102F9C +#define DMATIMEBUGREG_STARTDSP1 0x102FA0 +#define DMATIMEBUGREG_ENDDSP1 0x102FAC +#define DMACNTLMODFREG_STARTDSP1 0x102FA0 +#define DMACNTLMODFREG_ENDDSP1 0x102FAC + +#define DMAGLOBSTATSREGDSP1 0x102FEC +#define DSP1XGPRAM_START 0x103000 +#define DSP1XGPRAM_END 0x1033FC +#define DSP1YGPRAM_START 0x103400 +#define DSP1YGPRAM_END 0x1037FC + + + +#define AUDIORINGIPDSP2_START 0x104000 +#define AUDIORINGIPDSP2_END 0x1043FC +#define AUDIORINGOPDSP2_START 0x104400 +#define AUDIORINGOPDSP2_END 0x1047FC +#define AUDPARARINGIODSP2_START 0x104800 +#define AUDPARARINGIODSP2_END 0x104BFC +#define DSP2LOCALHWREG_START 0x104C00 +#define DSP2LOCALHWREG_END 0x104C3C +#define DSP2XYRAMAGINDEX_START 0x104C40 +#define DSP2XYRAMAGINDEX_END 0x104C5C +#define DSP2XYRAMAGMDFR_START 0x104C60 +#define DSP2XYRAMAGMDFR_END 0x104C7C +#define DSP2INTCONTLVEC_START 0x104C80 +#define DSP2INTCONTLVEC_END 0x104CD8 +#define HOSTINTFPORTADDRCONTDSP2 0x104D40 +#define HOSTINTFPORTDATADSP2 0x104D44 +#define TIME0PERENBDSP2 0x104D60 +#define TIME0COUNTERDSP2 0x104D64 +#define TIME1PERENBDSP2 0x104D68 +#define TIME1COUNTERDSP2 0x104D6C +#define TIME2PERENBDSP2 0x104D70 +#define TIME2COUNTERDSP2 0x104D74 +#define TIME3PERENBDSP2 0x104D78 +#define TIME3COUNTERDSP2 0x104D7C +#define XRAMINDOPERREFNOUP_STARTDSP2 0x104D80 +#define XRAMINDOPERREFNOUP_ENDDSP2 0x104D9C +#define XRAMINDOPERREFUP_STARTDSP2 0x104DA0 +#define XRAMINDOPERREFUP_ENDDSP2 0x104DBC +#define YRAMINDOPERREFNOUP_STARTDSP2 0x104DC0 +#define YRAMINDOPERREFNOUP_ENDDSP2 0x104DDC +#define YRAMINDOPERREFUP_STARTDSP2 0x104DE0 +#define YRAMINDOPERREFUP_ENDDSP2 0x104DFC +#define DSP2CONDCODE 0x104E00 +#define DSP2STACKFLAG 0x104E04 +#define DSP2PROGCOUNTSTACKPTREG 0x104E08 +#define DSP2PROGCOUNTSTACKDATAREG 0x104E0C +#define DSP2CURLOOPADDRREG 0x104E10 +#define DSP2CURLOOPCOUNT 0x104E14 +#define DSP2TOPLOOPCOUNTSTACK 0x104E18 +#define DSP2TOPLOOPADDRSTACK 0x104E1C +#define DSP2LOOPSTACKPTR 0x104E20 +#define DSP2STASSTACKDATAREG 0x104E24 +#define DSP2STASSTACKPTR 0x104E28 +#define DSP2PROGCOUNT 0x104E2C +#define DSP2XYRAMBASE_START 0x104EA0 +#define DSP2XYRAMBASE_END 0x104EBC +#define DSP2XYRAMLENG_START 0x104EC0 +#define DSP2XYRAMLENG_END 0x104EDC +#define SEMAPHOREREGDSP2 0x104EE0 +#define DSP2INTCONTMASKREG 0x104EE4 +#define DSP2INTCONTPENDREG 0x104EE8 +#define DSP2INTCONTSERVINT 0x104EEC +#define GPIODSP2 0x104EFC +#define DMADSPBASEADDRREG_STARTDSP2 0x104F00 +#define DMADSPBASEADDRREG_ENDDSP2 0x104F1C +#define DMAHOSTBASEADDRREG_STARTDSP2 0x104F20 +#define DMAHOSTBASEADDRREG_ENDDSP2 0x104F3C +#define DMADSPCURADDRREG_STARTDSP2 0x104F40 +#define DMADSPCURADDRREG_ENDDSP2 0x104F5C +#define DMAHOSTCURADDRREG_STARTDSP2 0x104F60 +#define DMAHOSTCURADDRREG_ENDDSP2 0x104F7C +#define DMATANXCOUNTREG_STARTDSP2 0x104F80 +#define DMATANXCOUNTREG_ENDDSP2 0x104F9C +#define DMATIMEBUGREG_STARTDSP2 0x104FA0 +#define DMATIMEBUGREG_ENDDSP2 0x104FAC +#define DMACNTLMODFREG_STARTDSP2 0x104FA0 +#define DMACNTLMODFREG_ENDDSP2 0x104FAC + +#define DMAGLOBSTATSREGDSP2 0x104FEC +#define DSP2XGPRAM_START 0x105000 +#define DSP2XGPRAM_END 0x1051FC +#define DSP2YGPRAM_START 0x105800 +#define DSP2YGPRAM_END 0x1059FC + + + +#define AUDIORINGIPDSP3_START 0x106000 +#define AUDIORINGIPDSP3_END 0x1063FC +#define AUDIORINGOPDSP3_START 0x106400 +#define AUDIORINGOPDSP3_END 0x1067FC +#define AUDPARARINGIODSP3_START 0x106800 +#define AUDPARARINGIODSP3_END 0x106BFC +#define DSP3LOCALHWREG_START 0x106C00 +#define DSP3LOCALHWREG_END 0x106C3C +#define DSP3XYRAMAGINDEX_START 0x106C40 +#define DSP3XYRAMAGINDEX_END 0x106C5C +#define DSP3XYRAMAGMDFR_START 0x106C60 +#define DSP3XYRAMAGMDFR_END 0x106C7C +#define DSP3INTCONTLVEC_START 0x106C80 +#define DSP3INTCONTLVEC_END 0x106CD8 +#define HOSTINTFPORTADDRCONTDSP3 0x106D40 +#define HOSTINTFPORTDATADSP3 0x106D44 +#define TIME0PERENBDSP3 0x106D60 +#define TIME0COUNTERDSP3 0x106D64 +#define TIME1PERENBDSP3 0x106D68 +#define TIME1COUNTERDSP3 0x106D6C +#define TIME2PERENBDSP3 0x106D70 +#define TIME2COUNTERDSP3 0x106D74 +#define TIME3PERENBDSP3 0x106D78 +#define TIME3COUNTERDSP3 0x106D7C +#define XRAMINDOPERREFNOUP_STARTDSP3 0x106D80 +#define XRAMINDOPERREFNOUP_ENDDSP3 0x106D9C +#define XRAMINDOPERREFUP_STARTDSP3 0x106DA0 +#define XRAMINDOPERREFUP_ENDDSP3 0x106DBC +#define YRAMINDOPERREFNOUP_STARTDSP3 0x106DC0 +#define YRAMINDOPERREFNOUP_ENDDSP3 0x106DDC +#define YRAMINDOPERREFUP_STARTDSP3 0x106DE0 +#define YRAMINDOPERREFUP_ENDDSP3 0x100DFC + +#define DSP3CONDCODE 0x106E00 +#define DSP3STACKFLAG 0x106E04 +#define DSP3PROGCOUNTSTACKPTREG 0x106E08 +#define DSP3PROGCOUNTSTACKDATAREG 0x106E0C +#define DSP3CURLOOPADDRREG 0x106E10 +#define DSP3CURLOOPCOUNT 0x106E14 +#define DSP3TOPLOOPCOUNTSTACK 0x106E18 +#define DSP3TOPLOOPADDRSTACK 0x106E1C +#define DSP3LOOPSTACKPTR 0x106E20 +#define DSP3STASSTACKDATAREG 0x106E24 +#define DSP3STASSTACKPTR 0x106E28 +#define DSP3PROGCOUNT 0x106E2C +#define DSP3XYRAMBASE_START 0x106EA0 +#define DSP3XYRAMBASE_END 0x106EBC +#define DSP3XYRAMLENG_START 0x106EC0 +#define DSP3XYRAMLENG_END 0x106EDC +#define SEMAPHOREREGDSP3 0x106EE0 +#define DSP3INTCONTMASKREG 0x106EE4 +#define DSP3INTCONTPENDREG 0x106EE8 +#define DSP3INTCONTSERVINT 0x106EEC +#define GPIODSP3 0x106EFC +#define DMADSPBASEADDRREG_STARTDSP3 0x106F00 +#define DMADSPBASEADDRREG_ENDDSP3 0x106F1C +#define DMAHOSTBASEADDRREG_STARTDSP3 0x106F20 +#define DMAHOSTBASEADDRREG_ENDDSP3 0x106F3C +#define DMADSPCURADDRREG_STARTDSP3 0x106F40 +#define DMADSPCURADDRREG_ENDDSP3 0x106F5C +#define DMAHOSTCURADDRREG_STARTDSP3 0x106F60 +#define DMAHOSTCURADDRREG_ENDDSP3 0x106F7C +#define DMATANXCOUNTREG_STARTDSP3 0x106F80 +#define DMATANXCOUNTREG_ENDDSP3 0x106F9C +#define DMATIMEBUGREG_STARTDSP3 0x106FA0 +#define DMATIMEBUGREG_ENDDSP3 0x106FAC +#define DMACNTLMODFREG_STARTDSP3 0x106FA0 +#define DMACNTLMODFREG_ENDDSP3 0x106FAC + +#define DMAGLOBSTATSREGDSP3 0x106FEC +#define DSP3XGPRAM_START 0x107000 +#define DSP3XGPRAM_END 0x1071FC +#define DSP3YGPRAM_START 0x107800 +#define DSP3YGPRAM_END 0x1079FC + +/* end of DSP reg definitions */ + +#define DSPAIMAP_START 0x108000 +#define DSPAIMAP_END 0x1083FC +#define DSPPIMAP_START 0x108400 +#define DSPPIMAP_END 0x1087FC +#define DSPPOMAP_START 0x108800 +#define DSPPOMAP_END 0x108BFC +#define DSPPOCTL 0x108C00 +#define TKCTL_START 0x110000 +#define TKCTL_END 0x110FFC +#define TKCC_START 0x111000 +#define TKCC_END 0x111FFC +#define TKIMAP_START 0x112000 +#define TKIMAP_END 0x112FFC +#define TKDCTR16 0x113000 +#define TKPB16 0x113004 +#define TKBS16 0x113008 +#define TKDCTR32 0x11300C +#define TKPB32 0x113010 +#define TKBS32 0x113014 +#define ICDCTR16 0x113018 +#define ITBS16 0x11301C +#define ICDCTR32 0x113020 +#define ITBS32 0x113024 +#define ITSTART 0x113028 +#define TKSQ 0x11302C + +#define TKSCCTL_START 0x114000 +#define TKSCCTL_END 0x11403C +#define TKSCADR_START 0x114100 +#define TKSCADR_END 0x11413C +#define TKSCDATAX_START 0x114800 +#define TKSCDATAX_END 0x1149FC +#define TKPCDATAX_START 0x120000 +#define TKPCDATAX_END 0x12FFFC + +#define MALSA 0x130000 +#define MAPPHA 0x130004 +#define MAPPLA 0x130008 +#define MALSB 0x130010 +#define MAPPHB 0x130014 +#define MAPPLB 0x130018 + +#define TANSPORTMAPABREGS_START 0x130020 +#define TANSPORTMAPABREGS_END 0x13A2FC + +#define PTPAHX 0x13B000 +#define PTPALX 0x13B004 + +#define TANSPPAGETABLEPHYADDR015_START 0x13B008 +#define TANSPPAGETABLEPHYADDR015_END 0x13B07C +#define TRNQADRX_START 0x13B100 +#define TRNQADRX_END 0x13B13C +#define TRNQTIMX_START 0x13B200 +#define TRNQTIMX_END 0x13B23C +#define TRNQAPARMX_START 0x13B300 +#define TRNQAPARMX_END 0x13B33C + +#define TRNQCNT 0x13B400 +#define TRNCTL 0x13B404 +#define TRNIS 0x13B408 +#define TRNCURTS 0x13B40C + +#define AMOP_START 0x140000 +#define AMOPLO 0x140000 +#define AMOPHI 0x140004 +#define AMOP_END 0x147FFC +#define PMOP_START 0x148000 +#define PMOPLO 0x148000 +#define PMOPHI 0x148004 +#define PMOP_END 0x14FFFC +#define PCURR_START 0x150000 +#define PCURR_END 0x153FFC +#define PTRAG_START 0x154000 +#define PTRAG_END 0x157FFC +#define PSR_START 0x158000 +#define PSR_END 0x15BFFC + +#define PFSTAT4SEG_START 0x160000 +#define PFSTAT4SEG_END 0x160BFC +#define PFSTAT2SEG_START 0x160C00 +#define PFSTAT2SEG_END 0x1617FC +#define PFTARG4SEG_START 0x164000 +#define PFTARG4SEG_END 0x164BFC +#define PFTARG2SEG_START 0x164C00 +#define PFTARG2SEG_END 0x1657FC +#define PFSR4SEG_START 0x168000 +#define PFSR4SEG_END 0x168BFC +#define PFSR2SEG_START 0x168C00 +#define PFSR2SEG_END 0x1697FC +#define PCURRMS4SEG_START 0x16C000 +#define PCURRMS4SEG_END 0x16CCFC +#define PCURRMS2SEG_START 0x16CC00 +#define PCURRMS2SEG_END 0x16D7FC +#define PTARGMS4SEG_START 0x170000 +#define PTARGMS4SEG_END 0x172FFC +#define PTARGMS2SEG_START 0x173000 +#define PTARGMS2SEG_END 0x1747FC +#define PSRMS4SEG_START 0x170000 +#define PSRMS4SEG_END 0x172FFC +#define PSRMS2SEG_START 0x173000 +#define PSRMS2SEG_END 0x1747FC + +#define PRING_LO_START 0x190000 +#define PRING_LO_END 0x193FFC +#define PRING_HI_START 0x194000 +#define PRING_HI_END 0x197FFC +#define PRING_LO_HI_START 0x198000 +#define PRING_LO_HI 0x198000 +#define PRING_LO_HI_END 0x19BFFC + +#define PINTFIFO 0x1A0000 +#define SRCCTL 0x1B0000 +#define SRCCCR 0x1B0004 +#define SRCIMAP 0x1B0008 +#define SRCODDC 0x1B000C +#define SRCCA 0x1B0010 +#define SRCCF 0x1B0014 +#define SRCSA 0x1B0018 +#define SRCLA 0x1B001C +#define SRCCTLSWR 0x1B0020 + +/* SRC HERE */ +#define SRCALBA 0x1B002C +#define SRCMCTL 0x1B012C +#define SRCCERR 0x1B022C +#define SRCITB 0x1B032C +#define SRCIPM 0x1B082C +#define SRCIP 0x1B102C +#define SRCENBSTAT 0x1B202C +#define SRCENBLO 0x1B212C +#define SRCENBHI 0x1B222C +#define SRCENBS 0x1B232C +#define SRCENB 0x1B282C +#define SRCENB07 0x1B282C +#define SRCENBS07 0x1B302C + +#define SRCDN0Z 0x1B0030 +#define SRCDN0Z0 0x1B0030 +#define SRCDN0Z1 0x1B0034 +#define SRCDN0Z2 0x1B0038 +#define SRCDN0Z3 0x1B003C +#define SRCDN1Z 0x1B0040 +#define SRCDN1Z0 0x1B0040 +#define SRCDN1Z1 0x1B0044 +#define SRCDN1Z2 0x1B0048 +#define SRCDN1Z3 0x1B004C +#define SRCDN1Z4 0x1B0050 +#define SRCDN1Z5 0x1B0054 +#define SRCDN1Z6 0x1B0058 +#define SRCDN1Z7 0x1B005C +#define SRCUPZ 0x1B0060 +#define SRCUPZ0 0x1B0060 +#define SRCUPZ1 0x1B0064 +#define SRCUPZ2 0x1B0068 +#define SRCUPZ3 0x1B006C +#define SRCUPZ4 0x1B0070 +#define SRCUPZ5 0x1B0074 +#define SRCUPZ6 0x1B0078 +#define SRCUPZ7 0x1B007C +#define SRCCD0 0x1B0080 +#define SRCCD1 0x1B0084 +#define SRCCD2 0x1B0088 +#define SRCCD3 0x1B008C +#define SRCCD4 0x1B0090 +#define SRCCD5 0x1B0094 +#define SRCCD6 0x1B0098 +#define SRCCD7 0x1B009C +#define SRCCD8 0x1B00A0 +#define SRCCD9 0x1B00A4 +#define SRCCDA 0x1B00A8 +#define SRCCDB 0x1B00AC +#define SRCCDC 0x1B00B0 +#define SRCCDD 0x1B00B4 +#define SRCCDE 0x1B00B8 +#define SRCCDF 0x1B00BC +#define SRCCD10 0x1B00C0 +#define SRCCD11 0x1B00C4 +#define SRCCD12 0x1B00C8 +#define SRCCD13 0x1B00CC +#define SRCCD14 0x1B00D0 +#define SRCCD15 0x1B00D4 +#define SRCCD16 0x1B00D8 +#define SRCCD17 0x1B00DC +#define SRCCD18 0x1B00E0 +#define SRCCD19 0x1B00E4 +#define SRCCD1A 0x1B00E8 +#define SRCCD1B 0x1B00EC +#define SRCCD1C 0x1B00F0 +#define SRCCD1D 0x1B00F4 +#define SRCCD1E 0x1B00F8 +#define SRCCD1F 0x1B00FC + +#define SRCCONTRBLOCK_START 0x1B0100 +#define SRCCONTRBLOCK_END 0x1BFFFC +#define FILTOP_START 0x1C0000 +#define FILTOP_END 0x1C05FC +#define FILTIMAP_START 0x1C0800 +#define FILTIMAP_END 0x1C0DFC +#define FILTZ1_START 0x1C1000 +#define FILTZ1_END 0x1C15FC +#define FILTZ2_START 0x1C1800 +#define FILTZ2_END 0x1C1DFC +#define DAOIMAP_START 0x1C5000 +#define DAOIMAP 0x1C5000 +#define DAOIMAP_END 0x1C5124 + +#define AC97D 0x1C5400 +#define AC97A 0x1C5404 +#define AC97CTL 0x1C5408 +#define I2SCTL 0x1C5420 + +#define SPOS 0x1C5440 +#define SPOSA 0x1C5440 +#define SPOSB 0x1C5444 +#define SPOSC 0x1C5448 +#define SPOSD 0x1C544C + +#define SPISA 0x1C5450 +#define SPISB 0x1C5454 +#define SPISC 0x1C5458 +#define SPISD 0x1C545C + +#define SPFSCTL 0x1C5460 + +#define SPFS0 0x1C5468 +#define SPFS1 0x1C546C +#define SPFS2 0x1C5470 +#define SPFS3 0x1C5474 +#define SPFS4 0x1C5478 +#define SPFS5 0x1C547C + +#define SPOCTL 0x1C5480 +#define SPICTL 0x1C5484 +#define SPISTS 0x1C5488 +#define SPINTP 0x1C548C +#define SPINTE 0x1C5490 +#define SPUTCTLAB 0x1C5494 +#define SPUTCTLCD 0x1C5498 + +#define SRTSPA 0x1C54C0 +#define SRTSPB 0x1C54C4 +#define SRTSPC 0x1C54C8 +#define SRTSPD 0x1C54CC + +#define SRTSCTL 0x1C54D0 +#define SRTSCTLA 0x1C54D0 +#define SRTSCTLB 0x1C54D4 +#define SRTSCTLC 0x1C54D8 +#define SRTSCTLD 0x1C54DC + +#define SRTI2S 0x1C54E0 +#define SRTICTL 0x1C54F0 + +#define WC 0x1C6000 +#define TIMR 0x1C6004 +# define TIMR_IE (1<<15) +# define TIMR_IP (1<<14) + +#define GIP 0x1C6010 +#define GIE 0x1C6014 +#define DIE 0x1C6018 +#define DIC 0x1C601C +#define GPIO 0x1C6020 +#define GPIOCTL 0x1C6024 +#define GPIP 0x1C6028 +#define GPIE 0x1C602C +#define DSPINT0 0x1C6030 +#define DSPEIOC 0x1C6034 +#define MUADAT 0x1C6040 +#define MUACMD 0x1C6044 +#define MUASTAT 0x1C6044 +#define MUBDAT 0x1C6048 +#define MUBCMD 0x1C604C +#define MUBSTAT 0x1C604C +#define UARTCMA 0x1C6050 +#define UARTCMB 0x1C6054 +#define UARTIP 0x1C6058 +#define UARTIE 0x1C605C +#define PLLCTL 0x1C6060 +#define PLLDCD 0x1C6064 +#define GCTL 0x1C6070 +#define ID0 0x1C6080 +#define ID1 0x1C6084 +#define ID2 0x1C6088 +#define ID3 0x1C608C +#define SDRCTL 0x1C7000 + + +#define I2SA_L 0x0L +#define I2SA_R 0x1L +#define I2SB_L 0x8L +#define I2SB_R 0x9L +#define I2SC_L 0x10L +#define I2SC_R 0x11L +#define I2SD_L 0x18L +#define I2SD_R 0x19L + +#endif /* CT20K1REG_H */ + + diff --git a/sound/pci/ctxfi/ct20k2reg.h b/sound/pci/ctxfi/ct20k2reg.h new file mode 100644 index 000000000000..2d07986f57cc --- /dev/null +++ b/sound/pci/ctxfi/ct20k2reg.h @@ -0,0 +1,85 @@ +/** + * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. + * + * This source file is released under GPL v2 license (no other versions). + * See the COPYING file included in the main directory of this source + * distribution for the license terms and conditions. + */ + +#ifndef _20K2REGISTERS_H_ +#define _20K2REGISTERS_H_ + + +/* Timer Registers */ +#define TIMER_TIMR 0x1B7004 +#define INTERRUPT_GIP 0x1B7010 +#define INTERRUPT_GIE 0x1B7014 + +/* I2C Registers */ +#define I2C_IF_ADDRESS 0x1B9000 +#define I2C_IF_WDATA 0x1B9004 +#define I2C_IF_RDATA 0x1B9008 +#define I2C_IF_STATUS 0x1B900C +#define I2C_IF_WLOCK 0x1B9010 + +/* Global Control Registers */ +#define GLOBAL_CNTL_GCTL 0x1B7090 + +/* PLL Registers */ +#define PLL_CTL 0x1B7080 +#define PLL_STAT 0x1B7084 +#define PLL_ENB 0x1B7088 + +/* SRC Registers */ +#define SRC_CTL 0x1A0000 /* 0x1A0000 + (256 * Chn) */ +#define SRC_CCR 0x1A0004 /* 0x1A0004 + (256 * Chn) */ +#define SRC_IMAP 0x1A0008 /* 0x1A0008 + (256 * Chn) */ +#define SRC_CA 0x1A0010 /* 0x1A0010 + (256 * Chn) */ +#define SRC_CF 0x1A0014 /* 0x1A0014 + (256 * Chn) */ +#define SRC_SA 0x1A0018 /* 0x1A0018 + (256 * Chn) */ +#define SRC_LA 0x1A001C /* 0x1A001C + (256 * Chn) */ +#define SRC_CTLSWR 0x1A0020 /* 0x1A0020 + (256 * Chn) */ +#define SRC_CD 0x1A0080 /* 0x1A0080 + (256 * Chn) + (4 * Regn) */ +#define SRC_MCTL 0x1A012C +#define SRC_IP 0x1A102C /* 0x1A102C + (256 * Regn) */ +#define SRC_ENB 0x1A282C /* 0x1A282C + (256 * Regn) */ +#define SRC_ENBSTAT 0x1A202C +#define SRC_ENBSA 0x1A232C +#define SRC_DN0Z 0x1A0030 +#define SRC_DN1Z 0x1A0040 +#define SRC_UPZ 0x1A0060 + +/* GPIO Registers */ +#define GPIO_DATA 0x1B7020 +#define GPIO_CTRL 0x1B7024 + +/* Virtual memory registers */ +#define VMEM_PTPAL 0x1C6300 /* 0x1C6300 + (16 * Chn) */ +#define VMEM_PTPAH 0x1C6304 /* 0x1C6304 + (16 * Chn) */ +#define VMEM_CTL 0x1C7000 + +/* Transport Registers */ +#define TRANSPORT_ENB 0x1B6000 +#define TRANSPORT_CTL 0x1B6004 +#define TRANSPORT_INT 0x1B6008 + +/* Audio IO */ +#define AUDIO_IO_AIM 0x1B5000 /* 0x1B5000 + (0x04 * Chn) */ +#define AUDIO_IO_TX_CTL 0x1B5400 /* 0x1B5400 + (0x40 * Chn) */ +#define AUDIO_IO_TX_CSTAT_L 0x1B5408 /* 0x1B5408 + (0x40 * Chn) */ +#define AUDIO_IO_TX_CSTAT_H 0x1B540C /* 0x1B540C + (0x40 * Chn) */ +#define AUDIO_IO_RX_CTL 0x1B5410 /* 0x1B5410 + (0x40 * Chn) */ +#define AUDIO_IO_RX_SRT_CTL 0x1B5420 /* 0x1B5420 + (0x40 * Chn) */ +#define AUDIO_IO_MCLK 0x1B5600 +#define AUDIO_IO_TX_BLRCLK 0x1B5604 +#define AUDIO_IO_RX_BLRCLK 0x1B5608 + +/* Mixer */ +#define MIXER_AMOPLO 0x130000 /* 0x130000 + (8 * Chn) [4095 : 0] */ +#define MIXER_AMOPHI 0x130004 /* 0x130004 + (8 * Chn) [4095 : 0] */ +#define MIXER_PRING_LO_HI 0x188000 /* 0x188000 + (4 * Chn) [4095 : 0] */ +#define MIXER_PMOPLO 0x138000 /* 0x138000 + (8 * Chn) [4095 : 0] */ +#define MIXER_PMOPHI 0x138004 /* 0x138004 + (8 * Chn) [4095 : 0] */ +#define MIXER_AR_ENABLE 0x19000C + +#endif diff --git a/sound/pci/ctxfi/ctamixer.c b/sound/pci/ctxfi/ctamixer.c new file mode 100644 index 000000000000..a1db51b3ead8 --- /dev/null +++ b/sound/pci/ctxfi/ctamixer.c @@ -0,0 +1,488 @@ +/** + * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. + * + * This source file is released under GPL v2 license (no other versions). + * See the COPYING file included in the main directory of this source + * distribution for the license terms and conditions. + * + * @File ctamixer.c + * + * @Brief + * This file contains the implementation of the Audio Mixer + * resource management object. + * + * @Author Liu Chun + * @Date May 21 2008 + * + */ + +#include "ctamixer.h" +#include "cthardware.h" +#include + +#define AMIXER_RESOURCE_NUM 256 +#define SUM_RESOURCE_NUM 256 + +#define AMIXER_Y_IMMEDIATE 1 + +#define BLANK_SLOT 4094 + +static int amixer_master(struct rsc *rsc) +{ + rsc->conj = 0; + return rsc->idx = container_of(rsc, struct amixer, rsc)->idx[0]; +} + +static int amixer_next_conj(struct rsc *rsc) +{ + rsc->conj++; + return container_of(rsc, struct amixer, rsc)->idx[rsc->conj]; +} + +static int amixer_index(const struct rsc *rsc) +{ + return container_of(rsc, struct amixer, rsc)->idx[rsc->conj]; +} + +static int amixer_output_slot(const struct rsc *rsc) +{ + return (amixer_index(rsc) << 4) + 0x4; +} + +static struct rsc_ops amixer_basic_rsc_ops = { + .master = amixer_master, + .next_conj = amixer_next_conj, + .index = amixer_index, + .output_slot = amixer_output_slot, +}; + +static int amixer_set_input(struct amixer *amixer, struct rsc *rsc) +{ + struct hw *hw; + + hw = amixer->rsc.hw; + hw->amixer_set_mode(amixer->rsc.ctrl_blk, AMIXER_Y_IMMEDIATE); + amixer->input = rsc; + if (NULL == rsc) + hw->amixer_set_x(amixer->rsc.ctrl_blk, BLANK_SLOT); + else + hw->amixer_set_x(amixer->rsc.ctrl_blk, + rsc->ops->output_slot(rsc)); + + return 0; +} + +/* y is a 14-bit immediate constant */ +static int amixer_set_y(struct amixer *amixer, unsigned int y) +{ + struct hw *hw; + + hw = amixer->rsc.hw; + hw->amixer_set_y(amixer->rsc.ctrl_blk, y); + + return 0; +} + +static int amixer_set_invalid_squash(struct amixer *amixer, unsigned int iv) +{ + struct hw *hw; + + hw = amixer->rsc.hw; + hw->amixer_set_iv(amixer->rsc.ctrl_blk, iv); + + return 0; +} + +static int amixer_set_sum(struct amixer *amixer, struct sum *sum) +{ + struct hw *hw; + + hw = amixer->rsc.hw; + amixer->sum = sum; + if (NULL == sum) { + hw->amixer_set_se(amixer->rsc.ctrl_blk, 0); + } else { + hw->amixer_set_se(amixer->rsc.ctrl_blk, 1); + hw->amixer_set_sadr(amixer->rsc.ctrl_blk, + sum->rsc.ops->index(&sum->rsc)); + } + + return 0; +} + +static int amixer_commit_write(struct amixer *amixer) +{ + struct hw *hw; + unsigned int index; + int i; + struct rsc *input; + struct sum *sum; + + hw = amixer->rsc.hw; + input = amixer->input; + sum = amixer->sum; + + /* Program master and conjugate resources */ + amixer->rsc.ops->master(&amixer->rsc); + if (NULL != input) + input->ops->master(input); + + if (NULL != sum) + sum->rsc.ops->master(&sum->rsc); + + for (i = 0; i < amixer->rsc.msr; i++) { + hw->amixer_set_dirty_all(amixer->rsc.ctrl_blk); + if (NULL != input) { + hw->amixer_set_x(amixer->rsc.ctrl_blk, + input->ops->output_slot(input)); + input->ops->next_conj(input); + } + if (NULL != sum) { + hw->amixer_set_sadr(amixer->rsc.ctrl_blk, + sum->rsc.ops->index(&sum->rsc)); + sum->rsc.ops->next_conj(&sum->rsc); + } + index = amixer->rsc.ops->output_slot(&amixer->rsc); + hw->amixer_commit_write(hw, index, amixer->rsc.ctrl_blk); + amixer->rsc.ops->next_conj(&amixer->rsc); + } + amixer->rsc.ops->master(&amixer->rsc); + if (NULL != input) + input->ops->master(input); + + if (NULL != sum) + sum->rsc.ops->master(&sum->rsc); + + return 0; +} + +static int amixer_commit_raw_write(struct amixer *amixer) +{ + struct hw *hw; + unsigned int index; + + hw = amixer->rsc.hw; + index = amixer->rsc.ops->output_slot(&amixer->rsc); + hw->amixer_commit_write(hw, index, amixer->rsc.ctrl_blk); + + return 0; +} + +static int amixer_get_y(struct amixer *amixer) +{ + struct hw *hw; + + hw = amixer->rsc.hw; + return hw->amixer_get_y(amixer->rsc.ctrl_blk); +} + +static int amixer_setup(struct amixer *amixer, struct rsc *input, + unsigned int scale, struct sum *sum) +{ + amixer_set_input(amixer, input); + amixer_set_y(amixer, scale); + amixer_set_sum(amixer, sum); + amixer_commit_write(amixer); + return 0; +} + +static struct amixer_rsc_ops amixer_ops = { + .set_input = amixer_set_input, + .set_invalid_squash = amixer_set_invalid_squash, + .set_scale = amixer_set_y, + .set_sum = amixer_set_sum, + .commit_write = amixer_commit_write, + .commit_raw_write = amixer_commit_raw_write, + .setup = amixer_setup, + .get_scale = amixer_get_y, +}; + +static int amixer_rsc_init(struct amixer *amixer, + const struct amixer_desc *desc, + struct amixer_mgr *mgr) +{ + int err; + + err = rsc_init(&amixer->rsc, amixer->idx[0], + AMIXER, desc->msr, mgr->mgr.hw); + if (err) + return err; + + /* Set amixer specific operations */ + amixer->rsc.ops = &amixer_basic_rsc_ops; + amixer->ops = &amixer_ops; + amixer->input = NULL; + amixer->sum = NULL; + + amixer_setup(amixer, NULL, 0, NULL); + + return 0; +} + +static int amixer_rsc_uninit(struct amixer *amixer) +{ + amixer_setup(amixer, NULL, 0, NULL); + rsc_uninit(&amixer->rsc); + amixer->ops = NULL; + amixer->input = NULL; + amixer->sum = NULL; + return 0; +} + +static int get_amixer_rsc(struct amixer_mgr *mgr, + const struct amixer_desc *desc, + struct amixer **ramixer) +{ + int err, i; + unsigned int idx; + struct amixer *amixer; + unsigned long flags; + + *ramixer = NULL; + + /* Allocate mem for amixer resource */ + amixer = kzalloc(sizeof(*amixer), GFP_KERNEL); + if (NULL == amixer) { + err = -ENOMEM; + return err; + } + + /* Check whether there are sufficient + * amixer resources to meet request. */ + spin_lock_irqsave(&mgr->mgr_lock, flags); + for (i = 0; i < desc->msr; i++) { + err = mgr_get_resource(&mgr->mgr, 1, &idx); + if (err) + break; + + amixer->idx[i] = idx; + } + spin_unlock_irqrestore(&mgr->mgr_lock, flags); + if (err) { + printk(KERN_ERR "ctxfi: Can't meet AMIXER resource request!\n"); + goto error; + } + + err = amixer_rsc_init(amixer, desc, mgr); + if (err) + goto error; + + *ramixer = amixer; + + return 0; + +error: + spin_lock_irqsave(&mgr->mgr_lock, flags); + for (i--; i >= 0; i--) + mgr_put_resource(&mgr->mgr, 1, amixer->idx[i]); + + spin_unlock_irqrestore(&mgr->mgr_lock, flags); + kfree(amixer); + return err; +} + +static int put_amixer_rsc(struct amixer_mgr *mgr, struct amixer *amixer) +{ + unsigned long flags; + int i; + + spin_lock_irqsave(&mgr->mgr_lock, flags); + for (i = 0; i < amixer->rsc.msr; i++) + mgr_put_resource(&mgr->mgr, 1, amixer->idx[i]); + + spin_unlock_irqrestore(&mgr->mgr_lock, flags); + amixer_rsc_uninit(amixer); + kfree(amixer); + + return 0; +} + +int amixer_mgr_create(void *hw, struct amixer_mgr **ramixer_mgr) +{ + int err; + struct amixer_mgr *amixer_mgr; + + *ramixer_mgr = NULL; + amixer_mgr = kzalloc(sizeof(*amixer_mgr), GFP_KERNEL); + if (NULL == amixer_mgr) + return -ENOMEM; + + err = rsc_mgr_init(&amixer_mgr->mgr, AMIXER, AMIXER_RESOURCE_NUM, hw); + if (err) + goto error; + + spin_lock_init(&amixer_mgr->mgr_lock); + + amixer_mgr->get_amixer = get_amixer_rsc; + amixer_mgr->put_amixer = put_amixer_rsc; + + *ramixer_mgr = amixer_mgr; + + return 0; + +error: + kfree(amixer_mgr); + return err; +} + +int amixer_mgr_destroy(struct amixer_mgr *amixer_mgr) +{ + rsc_mgr_uninit(&amixer_mgr->mgr); + kfree(amixer_mgr); + return 0; +} + +/* SUM resource management */ + +static int sum_master(struct rsc *rsc) +{ + rsc->conj = 0; + return rsc->idx = container_of(rsc, struct sum, rsc)->idx[0]; +} + +static int sum_next_conj(struct rsc *rsc) +{ + rsc->conj++; + return container_of(rsc, struct sum, rsc)->idx[rsc->conj]; +} + +static int sum_index(const struct rsc *rsc) +{ + return container_of(rsc, struct sum, rsc)->idx[rsc->conj]; +} + +static int sum_output_slot(const struct rsc *rsc) +{ + return (sum_index(rsc) << 4) + 0xc; +} + +static struct rsc_ops sum_basic_rsc_ops = { + .master = sum_master, + .next_conj = sum_next_conj, + .index = sum_index, + .output_slot = sum_output_slot, +}; + +static int sum_rsc_init(struct sum *sum, + const struct sum_desc *desc, + struct sum_mgr *mgr) +{ + int err; + + err = rsc_init(&sum->rsc, sum->idx[0], SUM, desc->msr, mgr->mgr.hw); + if (err) + return err; + + sum->rsc.ops = &sum_basic_rsc_ops; + + return 0; +} + +static int sum_rsc_uninit(struct sum *sum) +{ + rsc_uninit(&sum->rsc); + return 0; +} + +static int get_sum_rsc(struct sum_mgr *mgr, + const struct sum_desc *desc, + struct sum **rsum) +{ + int err, i; + unsigned int idx; + struct sum *sum; + unsigned long flags; + + *rsum = NULL; + + /* Allocate mem for sum resource */ + sum = kzalloc(sizeof(*sum), GFP_KERNEL); + if (NULL == sum) { + err = -ENOMEM; + return err; + } + + /* Check whether there are sufficient sum resources to meet request. */ + spin_lock_irqsave(&mgr->mgr_lock, flags); + for (i = 0; i < desc->msr; i++) { + err = mgr_get_resource(&mgr->mgr, 1, &idx); + if (err) + break; + + sum->idx[i] = idx; + } + spin_unlock_irqrestore(&mgr->mgr_lock, flags); + if (err) { + printk(KERN_ERR "ctxfi: Can't meet SUM resource request!\n"); + goto error; + } + + err = sum_rsc_init(sum, desc, mgr); + if (err) + goto error; + + *rsum = sum; + + return 0; + +error: + spin_lock_irqsave(&mgr->mgr_lock, flags); + for (i--; i >= 0; i--) + mgr_put_resource(&mgr->mgr, 1, sum->idx[i]); + + spin_unlock_irqrestore(&mgr->mgr_lock, flags); + kfree(sum); + return err; +} + +static int put_sum_rsc(struct sum_mgr *mgr, struct sum *sum) +{ + unsigned long flags; + int i; + + spin_lock_irqsave(&mgr->mgr_lock, flags); + for (i = 0; i < sum->rsc.msr; i++) + mgr_put_resource(&mgr->mgr, 1, sum->idx[i]); + + spin_unlock_irqrestore(&mgr->mgr_lock, flags); + sum_rsc_uninit(sum); + kfree(sum); + + return 0; +} + +int sum_mgr_create(void *hw, struct sum_mgr **rsum_mgr) +{ + int err; + struct sum_mgr *sum_mgr; + + *rsum_mgr = NULL; + sum_mgr = kzalloc(sizeof(*sum_mgr), GFP_KERNEL); + if (NULL == sum_mgr) + return -ENOMEM; + + err = rsc_mgr_init(&sum_mgr->mgr, SUM, SUM_RESOURCE_NUM, hw); + if (err) + goto error; + + spin_lock_init(&sum_mgr->mgr_lock); + + sum_mgr->get_sum = get_sum_rsc; + sum_mgr->put_sum = put_sum_rsc; + + *rsum_mgr = sum_mgr; + + return 0; + +error: + kfree(sum_mgr); + return err; +} + +int sum_mgr_destroy(struct sum_mgr *sum_mgr) +{ + rsc_mgr_uninit(&sum_mgr->mgr); + kfree(sum_mgr); + return 0; +} + diff --git a/sound/pci/ctxfi/ctamixer.h b/sound/pci/ctxfi/ctamixer.h new file mode 100644 index 000000000000..cc49e5ab4750 --- /dev/null +++ b/sound/pci/ctxfi/ctamixer.h @@ -0,0 +1,96 @@ +/** + * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. + * + * This source file is released under GPL v2 license (no other versions). + * See the COPYING file included in the main directory of this source + * distribution for the license terms and conditions. + * + * @File ctamixer.h + * + * @Brief + * This file contains the definition of the Audio Mixer + * resource management object. + * + * @Author Liu Chun + * @Date May 21 2008 + * + */ + +#ifndef CTAMIXER_H +#define CTAMIXER_H + +#include "ctresource.h" +#include + +/* Define the descriptor of a summation node resource */ +struct sum { + struct rsc rsc; /* Basic resource info */ + unsigned char idx[8]; +}; + +/* Define sum resource request description info */ +struct sum_desc { + unsigned int msr; +}; + +struct sum_mgr { + struct rsc_mgr mgr; /* Basic resource manager info */ + spinlock_t mgr_lock; + + /* request one sum resource */ + int (*get_sum)(struct sum_mgr *mgr, + const struct sum_desc *desc, struct sum **rsum); + /* return one sum resource */ + int (*put_sum)(struct sum_mgr *mgr, struct sum *sum); +}; + +/* Constructor and destructor of daio resource manager */ +int sum_mgr_create(void *hw, struct sum_mgr **rsum_mgr); +int sum_mgr_destroy(struct sum_mgr *sum_mgr); + +/* Define the descriptor of a amixer resource */ +struct amixer_rsc_ops; + +struct amixer { + struct rsc rsc; /* Basic resource info */ + unsigned char idx[8]; + struct rsc *input; /* pointer to a resource acting as source */ + struct sum *sum; /* Put amixer output to this summation node */ + struct amixer_rsc_ops *ops; /* AMixer specific operations */ +}; + +struct amixer_rsc_ops { + int (*set_input)(struct amixer *amixer, struct rsc *rsc); + int (*set_scale)(struct amixer *amixer, unsigned int scale); + int (*set_invalid_squash)(struct amixer *amixer, unsigned int iv); + int (*set_sum)(struct amixer *amixer, struct sum *sum); + int (*commit_write)(struct amixer *amixer); + /* Only for interleaved recording */ + int (*commit_raw_write)(struct amixer *amixer); + int (*setup)(struct amixer *amixer, struct rsc *input, + unsigned int scale, struct sum *sum); + int (*get_scale)(struct amixer *amixer); +}; + +/* Define amixer resource request description info */ +struct amixer_desc { + unsigned int msr; +}; + +struct amixer_mgr { + struct rsc_mgr mgr; /* Basic resource manager info */ + spinlock_t mgr_lock; + + /* request one amixer resource */ + int (*get_amixer)(struct amixer_mgr *mgr, + const struct amixer_desc *desc, + struct amixer **ramixer); + /* return one amixer resource */ + int (*put_amixer)(struct amixer_mgr *mgr, struct amixer *amixer); +}; + +/* Constructor and destructor of amixer resource manager */ +int amixer_mgr_create(void *hw, struct amixer_mgr **ramixer_mgr); +int amixer_mgr_destroy(struct amixer_mgr *amixer_mgr); + +#endif /* CTAMIXER_H */ diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c new file mode 100644 index 000000000000..a49c76647307 --- /dev/null +++ b/sound/pci/ctxfi/ctatc.c @@ -0,0 +1,1713 @@ +/** + * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. + * + * This source file is released under GPL v2 license (no other versions). + * See the COPYING file included in the main directory of this source + * distribution for the license terms and conditions. + * + * @File ctatc.c + * + * @Brief + * This file contains the implementation of the device resource management + * object. + * + * @Author Liu Chun + * @Date Mar 28 2008 + */ + +#include "ctatc.h" +#include "ctpcm.h" +#include "ctmixer.h" +#include "cthardware.h" +#include "ctsrc.h" +#include "ctamixer.h" +#include "ctdaio.h" +#include "cttimer.h" +#include +#include +#include +#include + +#define MONO_SUM_SCALE 0x19a8 /* 2^(-0.5) in 14-bit floating format */ +#define DAIONUM 7 +#define MAX_MULTI_CHN 8 + +#define IEC958_DEFAULT_CON ((IEC958_AES0_NONAUDIO \ + | IEC958_AES0_CON_NOT_COPYRIGHT) \ + | ((IEC958_AES1_CON_MIXER \ + | IEC958_AES1_CON_ORIGINAL) << 8) \ + | (0x10 << 16) \ + | ((IEC958_AES3_CON_FS_48000) << 24)) + +static struct snd_pci_quirk __devinitdata subsys_20k1_list[] = { + SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x0022, "SB055x", CTSB055X), + SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x002f, "SB055x", CTSB055X), + SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x0029, "SB073x", CTSB073X), + SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x0031, "SB073x", CTSB073X), + SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_CREATIVE, 0xf000, 0x6000, + "UAA", CTUAA), + { } /* terminator */ +}; + +static struct snd_pci_quirk __devinitdata subsys_20k2_list[] = { + SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB0760, + "SB0760", CTSB0760), + SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB08801, + "SB0880", CTSB0880), + SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB08802, + "SB0880", CTSB0880), + SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB08803, + "SB0880", CTSB0880), + SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_CREATIVE, 0xf000, + PCI_SUBDEVICE_ID_CREATIVE_HENDRIX, "HENDRIX", + CTHENDRIX), + { } /* terminator */ +}; + +static const char *ct_subsys_name[NUM_CTCARDS] = { + /* 20k1 models */ + [CTSB055X] = "SB055x", + [CTSB073X] = "SB073x", + [CTUAA] = "UAA", + [CT20K1_UNKNOWN] = "Unknown", + /* 20k2 models */ + [CTSB0760] = "SB076x", + [CTHENDRIX] = "Hendrix", + [CTSB0880] = "SB0880", + [CT20K2_UNKNOWN] = "Unknown", +}; + +static struct { + int (*create)(struct ct_atc *atc, + enum CTALSADEVS device, const char *device_name); + int (*destroy)(void *alsa_dev); + const char *public_name; +} alsa_dev_funcs[NUM_CTALSADEVS] = { + [FRONT] = { .create = ct_alsa_pcm_create, + .destroy = NULL, + .public_name = "Front/WaveIn"}, + [SURROUND] = { .create = ct_alsa_pcm_create, + .destroy = NULL, + .public_name = "Surround"}, + [CLFE] = { .create = ct_alsa_pcm_create, + .destroy = NULL, + .public_name = "Center/LFE"}, + [SIDE] = { .create = ct_alsa_pcm_create, + .destroy = NULL, + .public_name = "Side"}, + [IEC958] = { .create = ct_alsa_pcm_create, + .destroy = NULL, + .public_name = "IEC958 Non-audio"}, + + [MIXER] = { .create = ct_alsa_mix_create, + .destroy = NULL, + .public_name = "Mixer"} +}; + +typedef int (*create_t)(void *, void **); +typedef int (*destroy_t)(void *); + +static struct { + int (*create)(void *hw, void **rmgr); + int (*destroy)(void *mgr); +} rsc_mgr_funcs[NUM_RSCTYP] = { + [SRC] = { .create = (create_t)src_mgr_create, + .destroy = (destroy_t)src_mgr_destroy }, + [SRCIMP] = { .create = (create_t)srcimp_mgr_create, + .destroy = (destroy_t)srcimp_mgr_destroy }, + [AMIXER] = { .create = (create_t)amixer_mgr_create, + .destroy = (destroy_t)amixer_mgr_destroy }, + [SUM] = { .create = (create_t)sum_mgr_create, + .destroy = (destroy_t)sum_mgr_destroy }, + [DAIO] = { .create = (create_t)daio_mgr_create, + .destroy = (destroy_t)daio_mgr_destroy } +}; + +static int +atc_pcm_release_resources(struct ct_atc *atc, struct ct_atc_pcm *apcm); + +/* * + * Only mono and interleaved modes are supported now. + * Always allocates a contiguous channel block. + * */ + +static int ct_map_audio_buffer(struct ct_atc *atc, struct ct_atc_pcm *apcm) +{ + struct snd_pcm_runtime *runtime; + struct ct_vm *vm; + + if (NULL == apcm->substream) + return 0; + + runtime = apcm->substream->runtime; + vm = atc->vm; + + apcm->vm_block = vm->map(vm, apcm->substream, runtime->dma_bytes); + + if (NULL == apcm->vm_block) + return -ENOENT; + + return 0; +} + +static void ct_unmap_audio_buffer(struct ct_atc *atc, struct ct_atc_pcm *apcm) +{ + struct ct_vm *vm; + + if (NULL == apcm->vm_block) + return; + + vm = atc->vm; + + vm->unmap(vm, apcm->vm_block); + + apcm->vm_block = NULL; +} + +static unsigned long atc_get_ptp_phys(struct ct_atc *atc, int index) +{ + struct ct_vm *vm; + void *kvirt_addr; + unsigned long phys_addr; + + vm = atc->vm; + kvirt_addr = vm->get_ptp_virt(vm, index); + if (kvirt_addr == NULL) + phys_addr = (~0UL); + else + phys_addr = virt_to_phys(kvirt_addr); + + return phys_addr; +} + +static unsigned int convert_format(snd_pcm_format_t snd_format) +{ + switch (snd_format) { + case SNDRV_PCM_FORMAT_U8: + return SRC_SF_U8; + case SNDRV_PCM_FORMAT_S16_LE: + return SRC_SF_S16; + case SNDRV_PCM_FORMAT_S24_3LE: + return SRC_SF_S24; + case SNDRV_PCM_FORMAT_S32_LE: + return SRC_SF_S32; + case SNDRV_PCM_FORMAT_FLOAT_LE: + return SRC_SF_F32; + default: + printk(KERN_ERR "ctxfi: not recognized snd format is %d \n", + snd_format); + return SRC_SF_S16; + } +} + +static unsigned int +atc_get_pitch(unsigned int input_rate, unsigned int output_rate) +{ + unsigned int pitch; + int b; + + /* get pitch and convert to fixed-point 8.24 format. */ + pitch = (input_rate / output_rate) << 24; + input_rate %= output_rate; + input_rate /= 100; + output_rate /= 100; + for (b = 31; ((b >= 0) && !(input_rate >> b)); ) + b--; + + if (b >= 0) { + input_rate <<= (31 - b); + input_rate /= output_rate; + b = 24 - (31 - b); + if (b >= 0) + input_rate <<= b; + else + input_rate >>= -b; + + pitch |= input_rate; + } + + return pitch; +} + +static int select_rom(unsigned int pitch) +{ + if ((pitch > 0x00428f5c) && (pitch < 0x01b851ec)) { + /* 0.26 <= pitch <= 1.72 */ + return 1; + } else if ((0x01d66666 == pitch) || (0x01d66667 == pitch)) { + /* pitch == 1.8375 */ + return 2; + } else if (0x02000000 == pitch) { + /* pitch == 2 */ + return 3; + } else if ((pitch >= 0x0) && (pitch <= 0x08000000)) { + /* 0 <= pitch <= 8 */ + return 0; + } else { + return -ENOENT; + } +} + +static int atc_pcm_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm) +{ + struct src_mgr *src_mgr = atc->rsc_mgrs[SRC]; + struct amixer_mgr *amixer_mgr = atc->rsc_mgrs[AMIXER]; + struct src_desc desc = {0}; + struct amixer_desc mix_dsc = {0}; + struct src *src; + struct amixer *amixer; + int err; + int n_amixer = apcm->substream->runtime->channels, i = 0; + int device = apcm->substream->pcm->device; + unsigned int pitch; + + /* first release old resources */ + atc_pcm_release_resources(atc, apcm); + + /* Get SRC resource */ + desc.multi = apcm->substream->runtime->channels; + desc.msr = atc->msr; + desc.mode = MEMRD; + err = src_mgr->get_src(src_mgr, &desc, (struct src **)&apcm->src); + if (err) + goto error1; + + pitch = atc_get_pitch(apcm->substream->runtime->rate, + (atc->rsr * atc->msr)); + src = apcm->src; + src->ops->set_pitch(src, pitch); + src->ops->set_rom(src, select_rom(pitch)); + src->ops->set_sf(src, convert_format(apcm->substream->runtime->format)); + src->ops->set_pm(src, (src->ops->next_interleave(src) != NULL)); + + /* Get AMIXER resource */ + n_amixer = (n_amixer < 2) ? 2 : n_amixer; + apcm->amixers = kzalloc(sizeof(void *)*n_amixer, GFP_KERNEL); + if (NULL == apcm->amixers) { + err = -ENOMEM; + goto error1; + } + mix_dsc.msr = atc->msr; + for (i = 0, apcm->n_amixer = 0; i < n_amixer; i++) { + err = amixer_mgr->get_amixer(amixer_mgr, &mix_dsc, + (struct amixer **)&apcm->amixers[i]); + if (err) + goto error1; + + apcm->n_amixer++; + } + + /* Set up device virtual mem map */ + err = ct_map_audio_buffer(atc, apcm); + if (err < 0) + goto error1; + + /* Connect resources */ + src = apcm->src; + for (i = 0; i < n_amixer; i++) { + amixer = apcm->amixers[i]; + mutex_lock(&atc->atc_mutex); + amixer->ops->setup(amixer, &src->rsc, + INIT_VOL, atc->pcm[i+device*2]); + mutex_unlock(&atc->atc_mutex); + src = src->ops->next_interleave(src); + if (NULL == src) + src = apcm->src; + } + + ct_timer_prepare(apcm->timer); + + return 0; + +error1: + atc_pcm_release_resources(atc, apcm); + return err; +} + +static int +atc_pcm_release_resources(struct ct_atc *atc, struct ct_atc_pcm *apcm) +{ + struct src_mgr *src_mgr = atc->rsc_mgrs[SRC]; + struct srcimp_mgr *srcimp_mgr = atc->rsc_mgrs[SRCIMP]; + struct amixer_mgr *amixer_mgr = atc->rsc_mgrs[AMIXER]; + struct sum_mgr *sum_mgr = atc->rsc_mgrs[SUM]; + struct srcimp *srcimp; + int i; + + if (NULL != apcm->srcimps) { + for (i = 0; i < apcm->n_srcimp; i++) { + srcimp = apcm->srcimps[i]; + srcimp->ops->unmap(srcimp); + srcimp_mgr->put_srcimp(srcimp_mgr, srcimp); + apcm->srcimps[i] = NULL; + } + kfree(apcm->srcimps); + apcm->srcimps = NULL; + } + + if (NULL != apcm->srccs) { + for (i = 0; i < apcm->n_srcc; i++) { + src_mgr->put_src(src_mgr, apcm->srccs[i]); + apcm->srccs[i] = NULL; + } + kfree(apcm->srccs); + apcm->srccs = NULL; + } + + if (NULL != apcm->amixers) { + for (i = 0; i < apcm->n_amixer; i++) { + amixer_mgr->put_amixer(amixer_mgr, apcm->amixers[i]); + apcm->amixers[i] = NULL; + } + kfree(apcm->amixers); + apcm->amixers = NULL; + } + + if (NULL != apcm->mono) { + sum_mgr->put_sum(sum_mgr, apcm->mono); + apcm->mono = NULL; + } + + if (NULL != apcm->src) { + src_mgr->put_src(src_mgr, apcm->src); + apcm->src = NULL; + } + + if (NULL != apcm->vm_block) { + /* Undo device virtual mem map */ + ct_unmap_audio_buffer(atc, apcm); + apcm->vm_block = NULL; + } + + return 0; +} + +static int atc_pcm_playback_start(struct ct_atc *atc, struct ct_atc_pcm *apcm) +{ + unsigned int max_cisz; + struct src *src = apcm->src; + + if (apcm->started) + return 0; + apcm->started = 1; + + max_cisz = src->multi * src->rsc.msr; + max_cisz = 0x80 * (max_cisz < 8 ? max_cisz : 8); + + src->ops->set_sa(src, apcm->vm_block->addr); + src->ops->set_la(src, apcm->vm_block->addr + apcm->vm_block->size); + src->ops->set_ca(src, apcm->vm_block->addr + max_cisz); + src->ops->set_cisz(src, max_cisz); + + src->ops->set_bm(src, 1); + src->ops->set_state(src, SRC_STATE_INIT); + src->ops->commit_write(src); + + ct_timer_start(apcm->timer); + return 0; +} + +static int atc_pcm_stop(struct ct_atc *atc, struct ct_atc_pcm *apcm) +{ + struct src *src; + int i; + + ct_timer_stop(apcm->timer); + + src = apcm->src; + src->ops->set_bm(src, 0); + src->ops->set_state(src, SRC_STATE_OFF); + src->ops->commit_write(src); + + if (NULL != apcm->srccs) { + for (i = 0; i < apcm->n_srcc; i++) { + src = apcm->srccs[i]; + src->ops->set_bm(src, 0); + src->ops->set_state(src, SRC_STATE_OFF); + src->ops->commit_write(src); + } + } + + apcm->started = 0; + + return 0; +} + +static int +atc_pcm_playback_position(struct ct_atc *atc, struct ct_atc_pcm *apcm) +{ + struct src *src = apcm->src; + u32 size, max_cisz; + int position; + + if (!src) + return 0; + position = src->ops->get_ca(src); + + size = apcm->vm_block->size; + max_cisz = src->multi * src->rsc.msr; + max_cisz = 128 * (max_cisz < 8 ? max_cisz : 8); + + return (position + size - max_cisz - apcm->vm_block->addr) % size; +} + +struct src_node_conf_t { + unsigned int pitch; + unsigned int msr:8; + unsigned int mix_msr:8; + unsigned int imp_msr:8; + unsigned int vo:1; +}; + +static void setup_src_node_conf(struct ct_atc *atc, struct ct_atc_pcm *apcm, + struct src_node_conf_t *conf, int *n_srcc) +{ + unsigned int pitch; + + /* get pitch and convert to fixed-point 8.24 format. */ + pitch = atc_get_pitch((atc->rsr * atc->msr), + apcm->substream->runtime->rate); + *n_srcc = 0; + + if (1 == atc->msr) { + *n_srcc = apcm->substream->runtime->channels; + conf[0].pitch = pitch; + conf[0].mix_msr = conf[0].imp_msr = conf[0].msr = 1; + conf[0].vo = 1; + } else if (2 == atc->msr) { + if (0x8000000 < pitch) { + /* Need two-stage SRCs, SRCIMPs and + * AMIXERs for converting format */ + conf[0].pitch = (atc->msr << 24); + conf[0].msr = conf[0].mix_msr = 1; + conf[0].imp_msr = atc->msr; + conf[0].vo = 0; + conf[1].pitch = atc_get_pitch(atc->rsr, + apcm->substream->runtime->rate); + conf[1].msr = conf[1].mix_msr = conf[1].imp_msr = 1; + conf[1].vo = 1; + *n_srcc = apcm->substream->runtime->channels * 2; + } else if (0x1000000 < pitch) { + /* Need one-stage SRCs, SRCIMPs and + * AMIXERs for converting format */ + conf[0].pitch = pitch; + conf[0].msr = conf[0].mix_msr + = conf[0].imp_msr = atc->msr; + conf[0].vo = 1; + *n_srcc = apcm->substream->runtime->channels; + } + } +} + +static int +atc_pcm_capture_get_resources(struct ct_atc *atc, struct ct_atc_pcm *apcm) +{ + struct src_mgr *src_mgr = atc->rsc_mgrs[SRC]; + struct srcimp_mgr *srcimp_mgr = atc->rsc_mgrs[SRCIMP]; + struct amixer_mgr *amixer_mgr = atc->rsc_mgrs[AMIXER]; + struct sum_mgr *sum_mgr = atc->rsc_mgrs[SUM]; + struct src_desc src_dsc = {0}; + struct src *src; + struct srcimp_desc srcimp_dsc = {0}; + struct srcimp *srcimp; + struct amixer_desc mix_dsc = {0}; + struct sum_desc sum_dsc = {0}; + unsigned int pitch; + int multi, err, i; + int n_srcimp, n_amixer, n_srcc, n_sum; + struct src_node_conf_t src_node_conf[2] = {{0} }; + + /* first release old resources */ + atc_pcm_release_resources(atc, apcm); + + /* The numbers of converting SRCs and SRCIMPs should be determined + * by pitch value. */ + + multi = apcm->substream->runtime->channels; + + /* get pitch and convert to fixed-point 8.24 format. */ + pitch = atc_get_pitch((atc->rsr * atc->msr), + apcm->substream->runtime->rate); + + setup_src_node_conf(atc, apcm, src_node_conf, &n_srcc); + n_sum = (1 == multi) ? 1 : 0; + n_amixer = n_sum * 2 + n_srcc; + n_srcimp = n_srcc; + if ((multi > 1) && (0x8000000 >= pitch)) { + /* Need extra AMIXERs and SRCIMPs for special treatment + * of interleaved recording of conjugate channels */ + n_amixer += multi * atc->msr; + n_srcimp += multi * atc->msr; + } else { + n_srcimp += multi; + } + + if (n_srcc) { + apcm->srccs = kzalloc(sizeof(void *)*n_srcc, GFP_KERNEL); + if (NULL == apcm->srccs) + return -ENOMEM; + } + if (n_amixer) { + apcm->amixers = kzalloc(sizeof(void *)*n_amixer, GFP_KERNEL); + if (NULL == apcm->amixers) { + err = -ENOMEM; + goto error1; + } + } + apcm->srcimps = kzalloc(sizeof(void *)*n_srcimp, GFP_KERNEL); + if (NULL == apcm->srcimps) { + err = -ENOMEM; + goto error1; + } + + /* Allocate SRCs for sample rate conversion if needed */ + src_dsc.multi = 1; + src_dsc.mode = ARCRW; + for (i = 0, apcm->n_srcc = 0; i < n_srcc; i++) { + src_dsc.msr = src_node_conf[i/multi].msr; + err = src_mgr->get_src(src_mgr, &src_dsc, + (struct src **)&apcm->srccs[i]); + if (err) + goto error1; + + src = apcm->srccs[i]; + pitch = src_node_conf[i/multi].pitch; + src->ops->set_pitch(src, pitch); + src->ops->set_rom(src, select_rom(pitch)); + src->ops->set_vo(src, src_node_conf[i/multi].vo); + + apcm->n_srcc++; + } + + /* Allocate AMIXERs for routing SRCs of conversion if needed */ + for (i = 0, apcm->n_amixer = 0; i < n_amixer; i++) { + if (i < (n_sum*2)) + mix_dsc.msr = atc->msr; + else if (i < (n_sum*2+n_srcc)) + mix_dsc.msr = src_node_conf[(i-n_sum*2)/multi].mix_msr; + else + mix_dsc.msr = 1; + + err = amixer_mgr->get_amixer(amixer_mgr, &mix_dsc, + (struct amixer **)&apcm->amixers[i]); + if (err) + goto error1; + + apcm->n_amixer++; + } + + /* Allocate a SUM resource to mix all input channels together */ + sum_dsc.msr = atc->msr; + err = sum_mgr->get_sum(sum_mgr, &sum_dsc, (struct sum **)&apcm->mono); + if (err) + goto error1; + + pitch = atc_get_pitch((atc->rsr * atc->msr), + apcm->substream->runtime->rate); + /* Allocate SRCIMP resources */ + for (i = 0, apcm->n_srcimp = 0; i < n_srcimp; i++) { + if (i < (n_srcc)) + srcimp_dsc.msr = src_node_conf[i/multi].imp_msr; + else if (1 == multi) + srcimp_dsc.msr = (pitch <= 0x8000000) ? atc->msr : 1; + else + srcimp_dsc.msr = 1; + + err = srcimp_mgr->get_srcimp(srcimp_mgr, &srcimp_dsc, &srcimp); + if (err) + goto error1; + + apcm->srcimps[i] = srcimp; + apcm->n_srcimp++; + } + + /* Allocate a SRC for writing data to host memory */ + src_dsc.multi = apcm->substream->runtime->channels; + src_dsc.msr = 1; + src_dsc.mode = MEMWR; + err = src_mgr->get_src(src_mgr, &src_dsc, (struct src **)&apcm->src); + if (err) + goto error1; + + src = apcm->src; + src->ops->set_pitch(src, pitch); + + /* Set up device virtual mem map */ + err = ct_map_audio_buffer(atc, apcm); + if (err < 0) + goto error1; + + return 0; + +error1: + atc_pcm_release_resources(atc, apcm); + return err; +} + +static int atc_pcm_capture_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm) +{ + struct src *src; + struct amixer *amixer; + struct srcimp *srcimp; + struct ct_mixer *mixer = atc->mixer; + struct sum *mono; + struct rsc *out_ports[8] = {NULL}; + int err, i, j, n_sum, multi; + unsigned int pitch; + int mix_base = 0, imp_base = 0; + + atc_pcm_release_resources(atc, apcm); + + /* Get needed resources. */ + err = atc_pcm_capture_get_resources(atc, apcm); + if (err) + return err; + + /* Connect resources */ + mixer->get_output_ports(mixer, MIX_PCMO_FRONT, + &out_ports[0], &out_ports[1]); + + multi = apcm->substream->runtime->channels; + if (1 == multi) { + mono = apcm->mono; + for (i = 0; i < 2; i++) { + amixer = apcm->amixers[i]; + amixer->ops->setup(amixer, out_ports[i], + MONO_SUM_SCALE, mono); + } + out_ports[0] = &mono->rsc; + n_sum = 1; + mix_base = n_sum * 2; + } + + for (i = 0; i < apcm->n_srcc; i++) { + src = apcm->srccs[i]; + srcimp = apcm->srcimps[imp_base+i]; + amixer = apcm->amixers[mix_base+i]; + srcimp->ops->map(srcimp, src, out_ports[i%multi]); + amixer->ops->setup(amixer, &src->rsc, INIT_VOL, NULL); + out_ports[i%multi] = &amixer->rsc; + } + + pitch = atc_get_pitch((atc->rsr * atc->msr), + apcm->substream->runtime->rate); + + if ((multi > 1) && (pitch <= 0x8000000)) { + /* Special connection for interleaved + * recording with conjugate channels */ + for (i = 0; i < multi; i++) { + out_ports[i]->ops->master(out_ports[i]); + for (j = 0; j < atc->msr; j++) { + amixer = apcm->amixers[apcm->n_srcc+j*multi+i]; + amixer->ops->set_input(amixer, out_ports[i]); + amixer->ops->set_scale(amixer, INIT_VOL); + amixer->ops->set_sum(amixer, NULL); + amixer->ops->commit_raw_write(amixer); + out_ports[i]->ops->next_conj(out_ports[i]); + + srcimp = apcm->srcimps[apcm->n_srcc+j*multi+i]; + srcimp->ops->map(srcimp, apcm->src, + &amixer->rsc); + } + } + } else { + for (i = 0; i < multi; i++) { + srcimp = apcm->srcimps[apcm->n_srcc+i]; + srcimp->ops->map(srcimp, apcm->src, out_ports[i]); + } + } + + ct_timer_prepare(apcm->timer); + + return 0; +} + +static int atc_pcm_capture_start(struct ct_atc *atc, struct ct_atc_pcm *apcm) +{ + struct src *src; + struct src_mgr *src_mgr = atc->rsc_mgrs[SRC]; + int i, multi; + + if (apcm->started) + return 0; + + apcm->started = 1; + multi = apcm->substream->runtime->channels; + /* Set up converting SRCs */ + for (i = 0; i < apcm->n_srcc; i++) { + src = apcm->srccs[i]; + src->ops->set_pm(src, ((i%multi) != (multi-1))); + src_mgr->src_disable(src_mgr, src); + } + + /* Set up recording SRC */ + src = apcm->src; + src->ops->set_sf(src, convert_format(apcm->substream->runtime->format)); + src->ops->set_sa(src, apcm->vm_block->addr); + src->ops->set_la(src, apcm->vm_block->addr + apcm->vm_block->size); + src->ops->set_ca(src, apcm->vm_block->addr); + src_mgr->src_disable(src_mgr, src); + + /* Disable relevant SRCs firstly */ + src_mgr->commit_write(src_mgr); + + /* Enable SRCs respectively */ + for (i = 0; i < apcm->n_srcc; i++) { + src = apcm->srccs[i]; + src->ops->set_state(src, SRC_STATE_RUN); + src->ops->commit_write(src); + src_mgr->src_enable_s(src_mgr, src); + } + src = apcm->src; + src->ops->set_bm(src, 1); + src->ops->set_state(src, SRC_STATE_RUN); + src->ops->commit_write(src); + src_mgr->src_enable_s(src_mgr, src); + + /* Enable relevant SRCs synchronously */ + src_mgr->commit_write(src_mgr); + + ct_timer_start(apcm->timer); + return 0; +} + +static int +atc_pcm_capture_position(struct ct_atc *atc, struct ct_atc_pcm *apcm) +{ + struct src *src = apcm->src; + + if (!src) + return 0; + return src->ops->get_ca(src) - apcm->vm_block->addr; +} + +static int spdif_passthru_playback_get_resources(struct ct_atc *atc, + struct ct_atc_pcm *apcm) +{ + struct src_mgr *src_mgr = atc->rsc_mgrs[SRC]; + struct amixer_mgr *amixer_mgr = atc->rsc_mgrs[AMIXER]; + struct src_desc desc = {0}; + struct amixer_desc mix_dsc = {0}; + struct src *src; + int err; + int n_amixer = apcm->substream->runtime->channels, i; + unsigned int pitch, rsr = atc->pll_rate; + + /* first release old resources */ + atc_pcm_release_resources(atc, apcm); + + /* Get SRC resource */ + desc.multi = apcm->substream->runtime->channels; + desc.msr = 1; + while (apcm->substream->runtime->rate > (rsr * desc.msr)) + desc.msr <<= 1; + + desc.mode = MEMRD; + err = src_mgr->get_src(src_mgr, &desc, (struct src **)&apcm->src); + if (err) + goto error1; + + pitch = atc_get_pitch(apcm->substream->runtime->rate, (rsr * desc.msr)); + src = apcm->src; + src->ops->set_pitch(src, pitch); + src->ops->set_rom(src, select_rom(pitch)); + src->ops->set_sf(src, convert_format(apcm->substream->runtime->format)); + src->ops->set_pm(src, (src->ops->next_interleave(src) != NULL)); + src->ops->set_bp(src, 1); + + /* Get AMIXER resource */ + n_amixer = (n_amixer < 2) ? 2 : n_amixer; + apcm->amixers = kzalloc(sizeof(void *)*n_amixer, GFP_KERNEL); + if (NULL == apcm->amixers) { + err = -ENOMEM; + goto error1; + } + mix_dsc.msr = desc.msr; + for (i = 0, apcm->n_amixer = 0; i < n_amixer; i++) { + err = amixer_mgr->get_amixer(amixer_mgr, &mix_dsc, + (struct amixer **)&apcm->amixers[i]); + if (err) + goto error1; + + apcm->n_amixer++; + } + + /* Set up device virtual mem map */ + err = ct_map_audio_buffer(atc, apcm); + if (err < 0) + goto error1; + + return 0; + +error1: + atc_pcm_release_resources(atc, apcm); + return err; +} + +static int atc_pll_init(struct ct_atc *atc, int rate) +{ + struct hw *hw = atc->hw; + int err; + err = hw->pll_init(hw, rate); + atc->pll_rate = err ? 0 : rate; + return err; +} + +static int +spdif_passthru_playback_setup(struct ct_atc *atc, struct ct_atc_pcm *apcm) +{ + struct dao *dao = container_of(atc->daios[SPDIFOO], struct dao, daio); + unsigned int rate = apcm->substream->runtime->rate; + unsigned int status; + int err = 0; + unsigned char iec958_con_fs; + + switch (rate) { + case 48000: + iec958_con_fs = IEC958_AES3_CON_FS_48000; + break; + case 44100: + iec958_con_fs = IEC958_AES3_CON_FS_44100; + break; + case 32000: + iec958_con_fs = IEC958_AES3_CON_FS_32000; + break; + default: + return -ENOENT; + } + + mutex_lock(&atc->atc_mutex); + dao->ops->get_spos(dao, &status); + if (((status >> 24) & IEC958_AES3_CON_FS) != iec958_con_fs) { + status &= ((~IEC958_AES3_CON_FS) << 24); + status |= (iec958_con_fs << 24); + dao->ops->set_spos(dao, status); + dao->ops->commit_write(dao); + } + if ((rate != atc->pll_rate) && (32000 != rate)) + err = atc_pll_init(atc, rate); + mutex_unlock(&atc->atc_mutex); + + return err; +} + +static int +spdif_passthru_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm) +{ + struct src *src; + struct amixer *amixer; + struct dao *dao; + int err; + int i; + + atc_pcm_release_resources(atc, apcm); + + /* Configure SPDIFOO and PLL to passthrough mode; + * determine pll_rate. */ + err = spdif_passthru_playback_setup(atc, apcm); + if (err) + return err; + + /* Get needed resources. */ + err = spdif_passthru_playback_get_resources(atc, apcm); + if (err) + return err; + + /* Connect resources */ + src = apcm->src; + for (i = 0; i < apcm->n_amixer; i++) { + amixer = apcm->amixers[i]; + amixer->ops->setup(amixer, &src->rsc, INIT_VOL, NULL); + src = src->ops->next_interleave(src); + if (NULL == src) + src = apcm->src; + } + /* Connect to SPDIFOO */ + mutex_lock(&atc->atc_mutex); + dao = container_of(atc->daios[SPDIFOO], struct dao, daio); + amixer = apcm->amixers[0]; + dao->ops->set_left_input(dao, &amixer->rsc); + amixer = apcm->amixers[1]; + dao->ops->set_right_input(dao, &amixer->rsc); + mutex_unlock(&atc->atc_mutex); + + ct_timer_prepare(apcm->timer); + + return 0; +} + +static int atc_select_line_in(struct ct_atc *atc) +{ + struct hw *hw = atc->hw; + struct ct_mixer *mixer = atc->mixer; + struct src *src; + + if (hw->is_adc_source_selected(hw, ADC_LINEIN)) + return 0; + + mixer->set_input_left(mixer, MIX_MIC_IN, NULL); + mixer->set_input_right(mixer, MIX_MIC_IN, NULL); + + hw->select_adc_source(hw, ADC_LINEIN); + + src = atc->srcs[2]; + mixer->set_input_left(mixer, MIX_LINE_IN, &src->rsc); + src = atc->srcs[3]; + mixer->set_input_right(mixer, MIX_LINE_IN, &src->rsc); + + return 0; +} + +static int atc_select_mic_in(struct ct_atc *atc) +{ + struct hw *hw = atc->hw; + struct ct_mixer *mixer = atc->mixer; + struct src *src; + + if (hw->is_adc_source_selected(hw, ADC_MICIN)) + return 0; + + mixer->set_input_left(mixer, MIX_LINE_IN, NULL); + mixer->set_input_right(mixer, MIX_LINE_IN, NULL); + + hw->select_adc_source(hw, ADC_MICIN); + + src = atc->srcs[2]; + mixer->set_input_left(mixer, MIX_MIC_IN, &src->rsc); + src = atc->srcs[3]; + mixer->set_input_right(mixer, MIX_MIC_IN, &src->rsc); + + return 0; +} + +static int atc_have_digit_io_switch(struct ct_atc *atc) +{ + struct hw *hw = atc->hw; + + return hw->have_digit_io_switch(hw); +} + +static int atc_select_digit_io(struct ct_atc *atc) +{ + struct hw *hw = atc->hw; + + if (hw->is_adc_source_selected(hw, ADC_NONE)) + return 0; + + hw->select_adc_source(hw, ADC_NONE); + + return 0; +} + +static int atc_daio_unmute(struct ct_atc *atc, unsigned char state, int type) +{ + struct daio_mgr *daio_mgr = atc->rsc_mgrs[DAIO]; + + if (state) + daio_mgr->daio_enable(daio_mgr, atc->daios[type]); + else + daio_mgr->daio_disable(daio_mgr, atc->daios[type]); + + daio_mgr->commit_write(daio_mgr); + + return 0; +} + +static int +atc_dao_get_status(struct ct_atc *atc, unsigned int *status, int type) +{ + struct dao *dao = container_of(atc->daios[type], struct dao, daio); + return dao->ops->get_spos(dao, status); +} + +static int +atc_dao_set_status(struct ct_atc *atc, unsigned int status, int type) +{ + struct dao *dao = container_of(atc->daios[type], struct dao, daio); + + dao->ops->set_spos(dao, status); + dao->ops->commit_write(dao); + return 0; +} + +static int atc_line_front_unmute(struct ct_atc *atc, unsigned char state) +{ + return atc_daio_unmute(atc, state, LINEO1); +} + +static int atc_line_surround_unmute(struct ct_atc *atc, unsigned char state) +{ + return atc_daio_unmute(atc, state, LINEO4); +} + +static int atc_line_clfe_unmute(struct ct_atc *atc, unsigned char state) +{ + return atc_daio_unmute(atc, state, LINEO3); +} + +static int atc_line_rear_unmute(struct ct_atc *atc, unsigned char state) +{ + return atc_daio_unmute(atc, state, LINEO2); +} + +static int atc_line_in_unmute(struct ct_atc *atc, unsigned char state) +{ + return atc_daio_unmute(atc, state, LINEIM); +} + +static int atc_spdif_out_unmute(struct ct_atc *atc, unsigned char state) +{ + return atc_daio_unmute(atc, state, SPDIFOO); +} + +static int atc_spdif_in_unmute(struct ct_atc *atc, unsigned char state) +{ + return atc_daio_unmute(atc, state, SPDIFIO); +} + +static int atc_spdif_out_get_status(struct ct_atc *atc, unsigned int *status) +{ + return atc_dao_get_status(atc, status, SPDIFOO); +} + +static int atc_spdif_out_set_status(struct ct_atc *atc, unsigned int status) +{ + return atc_dao_set_status(atc, status, SPDIFOO); +} + +static int atc_spdif_out_passthru(struct ct_atc *atc, unsigned char state) +{ + struct dao_desc da_dsc = {0}; + struct dao *dao; + int err; + struct ct_mixer *mixer = atc->mixer; + struct rsc *rscs[2] = {NULL}; + unsigned int spos = 0; + + mutex_lock(&atc->atc_mutex); + dao = container_of(atc->daios[SPDIFOO], struct dao, daio); + da_dsc.msr = state ? 1 : atc->msr; + da_dsc.passthru = state ? 1 : 0; + err = dao->ops->reinit(dao, &da_dsc); + if (state) { + spos = IEC958_DEFAULT_CON; + } else { + mixer->get_output_ports(mixer, MIX_SPDIF_OUT, + &rscs[0], &rscs[1]); + dao->ops->set_left_input(dao, rscs[0]); + dao->ops->set_right_input(dao, rscs[1]); + /* Restore PLL to atc->rsr if needed. */ + if (atc->pll_rate != atc->rsr) + err = atc_pll_init(atc, atc->rsr); + } + dao->ops->set_spos(dao, spos); + dao->ops->commit_write(dao); + mutex_unlock(&atc->atc_mutex); + + return err; +} + +static int atc_release_resources(struct ct_atc *atc) +{ + int i; + struct daio_mgr *daio_mgr = NULL; + struct dao *dao = NULL; + struct dai *dai = NULL; + struct daio *daio = NULL; + struct sum_mgr *sum_mgr = NULL; + struct src_mgr *src_mgr = NULL; + struct srcimp_mgr *srcimp_mgr = NULL; + struct srcimp *srcimp = NULL; + struct ct_mixer *mixer = NULL; + + /* disconnect internal mixer objects */ + if (NULL != atc->mixer) { + mixer = atc->mixer; + mixer->set_input_left(mixer, MIX_LINE_IN, NULL); + mixer->set_input_right(mixer, MIX_LINE_IN, NULL); + mixer->set_input_left(mixer, MIX_MIC_IN, NULL); + mixer->set_input_right(mixer, MIX_MIC_IN, NULL); + mixer->set_input_left(mixer, MIX_SPDIF_IN, NULL); + mixer->set_input_right(mixer, MIX_SPDIF_IN, NULL); + } + + if (NULL != atc->daios) { + daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO]; + for (i = 0; i < atc->n_daio; i++) { + daio = atc->daios[i]; + if (daio->type < LINEIM) { + dao = container_of(daio, struct dao, daio); + dao->ops->clear_left_input(dao); + dao->ops->clear_right_input(dao); + } else { + dai = container_of(daio, struct dai, daio); + /* some thing to do for dai ... */ + } + daio_mgr->put_daio(daio_mgr, daio); + } + kfree(atc->daios); + atc->daios = NULL; + } + + if (NULL != atc->pcm) { + sum_mgr = atc->rsc_mgrs[SUM]; + for (i = 0; i < atc->n_pcm; i++) + sum_mgr->put_sum(sum_mgr, atc->pcm[i]); + + kfree(atc->pcm); + atc->pcm = NULL; + } + + if (NULL != atc->srcs) { + src_mgr = atc->rsc_mgrs[SRC]; + for (i = 0; i < atc->n_src; i++) + src_mgr->put_src(src_mgr, atc->srcs[i]); + + kfree(atc->srcs); + atc->srcs = NULL; + } + + if (NULL != atc->srcimps) { + srcimp_mgr = atc->rsc_mgrs[SRCIMP]; + for (i = 0; i < atc->n_srcimp; i++) { + srcimp = atc->srcimps[i]; + srcimp->ops->unmap(srcimp); + srcimp_mgr->put_srcimp(srcimp_mgr, atc->srcimps[i]); + } + kfree(atc->srcimps); + atc->srcimps = NULL; + } + + return 0; +} + +static int ct_atc_destroy(struct ct_atc *atc) +{ + int i = 0; + + if (NULL == atc) + return 0; + + if (atc->timer) { + ct_timer_free(atc->timer); + atc->timer = NULL; + } + + atc_release_resources(atc); + + /* Destroy internal mixer objects */ + if (NULL != atc->mixer) + ct_mixer_destroy(atc->mixer); + + for (i = 0; i < NUM_RSCTYP; i++) { + if ((NULL != rsc_mgr_funcs[i].destroy) && + (NULL != atc->rsc_mgrs[i])) + rsc_mgr_funcs[i].destroy(atc->rsc_mgrs[i]); + + } + + if (NULL != atc->hw) + destroy_hw_obj((struct hw *)atc->hw); + + /* Destroy device virtual memory manager object */ + if (NULL != atc->vm) { + ct_vm_destroy(atc->vm); + atc->vm = NULL; + } + + kfree(atc); + + return 0; +} + +static int atc_dev_free(struct snd_device *dev) +{ + struct ct_atc *atc = dev->device_data; + return ct_atc_destroy(atc); +} + +static int __devinit atc_identify_card(struct ct_atc *atc) +{ + const struct snd_pci_quirk *p; + const struct snd_pci_quirk *list; + + switch (atc->chip_type) { + case ATC20K1: + atc->chip_name = "20K1"; + list = subsys_20k1_list; + break; + case ATC20K2: + atc->chip_name = "20K2"; + list = subsys_20k2_list; + break; + default: + return -ENOENT; + } + p = snd_pci_quirk_lookup(atc->pci, list); + if (p) { + if (p->value < 0) { + printk(KERN_ERR "ctxfi: " + "Device %04x:%04x is black-listed\n", + atc->pci->subsystem_vendor, + atc->pci->subsystem_device); + return -ENOENT; + } + atc->model = p->value; + } else { + if (atc->chip_type == ATC20K1) + atc->model = CT20K1_UNKNOWN; + else + atc->model = CT20K2_UNKNOWN; + } + atc->model_name = ct_subsys_name[atc->model]; + snd_printd("ctxfi: chip %s model %s (%04x:%04x) is found\n", + atc->chip_name, atc->model_name, + atc->pci->subsystem_vendor, + atc->pci->subsystem_device); + return 0; +} + +int __devinit ct_atc_create_alsa_devs(struct ct_atc *atc) +{ + enum CTALSADEVS i; + int err; + + alsa_dev_funcs[MIXER].public_name = atc->chip_name; + + for (i = 0; i < NUM_CTALSADEVS; i++) { + if (NULL == alsa_dev_funcs[i].create) + continue; + + err = alsa_dev_funcs[i].create(atc, i, + alsa_dev_funcs[i].public_name); + if (err) { + printk(KERN_ERR "ctxfi: " + "Creating alsa device %d failed!\n", i); + return err; + } + } + + return 0; +} + +static int __devinit atc_create_hw_devs(struct ct_atc *atc) +{ + struct hw *hw; + struct card_conf info = {0}; + int i, err; + + err = create_hw_obj(atc->pci, atc->chip_type, atc->model, &hw); + if (err) { + printk(KERN_ERR "Failed to create hw obj!!!\n"); + return err; + } + atc->hw = hw; + + /* Initialize card hardware. */ + info.rsr = atc->rsr; + info.msr = atc->msr; + info.vm_pgt_phys = atc_get_ptp_phys(atc, 0); + err = hw->card_init(hw, &info); + if (err < 0) + return err; + + for (i = 0; i < NUM_RSCTYP; i++) { + if (NULL == rsc_mgr_funcs[i].create) + continue; + + err = rsc_mgr_funcs[i].create(atc->hw, &atc->rsc_mgrs[i]); + if (err) { + printk(KERN_ERR "ctxfi: " + "Failed to create rsc_mgr %d!!!\n", i); + return err; + } + } + + return 0; +} + +static int atc_get_resources(struct ct_atc *atc) +{ + struct daio_desc da_desc = {0}; + struct daio_mgr *daio_mgr; + struct src_desc src_dsc = {0}; + struct src_mgr *src_mgr; + struct srcimp_desc srcimp_dsc = {0}; + struct srcimp_mgr *srcimp_mgr; + struct sum_desc sum_dsc = {0}; + struct sum_mgr *sum_mgr; + int err, i; + + atc->daios = kzalloc(sizeof(void *)*(DAIONUM), GFP_KERNEL); + if (NULL == atc->daios) + return -ENOMEM; + + atc->srcs = kzalloc(sizeof(void *)*(2*2), GFP_KERNEL); + if (NULL == atc->srcs) + return -ENOMEM; + + atc->srcimps = kzalloc(sizeof(void *)*(2*2), GFP_KERNEL); + if (NULL == atc->srcimps) + return -ENOMEM; + + atc->pcm = kzalloc(sizeof(void *)*(2*4), GFP_KERNEL); + if (NULL == atc->pcm) + return -ENOMEM; + + daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO]; + da_desc.msr = atc->msr; + for (i = 0, atc->n_daio = 0; i < DAIONUM-1; i++) { + da_desc.type = i; + err = daio_mgr->get_daio(daio_mgr, &da_desc, + (struct daio **)&atc->daios[i]); + if (err) { + printk(KERN_ERR "ctxfi: Failed to get DAIO " + "resource %d!!!\n", i); + return err; + } + atc->n_daio++; + } + if (atc->model == CTSB073X) + da_desc.type = SPDIFI1; + else + da_desc.type = SPDIFIO; + err = daio_mgr->get_daio(daio_mgr, &da_desc, + (struct daio **)&atc->daios[i]); + if (err) { + printk(KERN_ERR "ctxfi: Failed to get S/PDIF-in resource!!!\n"); + return err; + } + atc->n_daio++; + + src_mgr = atc->rsc_mgrs[SRC]; + src_dsc.multi = 1; + src_dsc.msr = atc->msr; + src_dsc.mode = ARCRW; + for (i = 0, atc->n_src = 0; i < (2*2); i++) { + err = src_mgr->get_src(src_mgr, &src_dsc, + (struct src **)&atc->srcs[i]); + if (err) + return err; + + atc->n_src++; + } + + srcimp_mgr = atc->rsc_mgrs[SRCIMP]; + srcimp_dsc.msr = 8; /* SRCIMPs for S/PDIFIn SRT */ + for (i = 0, atc->n_srcimp = 0; i < (2*1); i++) { + err = srcimp_mgr->get_srcimp(srcimp_mgr, &srcimp_dsc, + (struct srcimp **)&atc->srcimps[i]); + if (err) + return err; + + atc->n_srcimp++; + } + srcimp_dsc.msr = 8; /* SRCIMPs for LINE/MICIn SRT */ + for (i = 0; i < (2*1); i++) { + err = srcimp_mgr->get_srcimp(srcimp_mgr, &srcimp_dsc, + (struct srcimp **)&atc->srcimps[2*1+i]); + if (err) + return err; + + atc->n_srcimp++; + } + + sum_mgr = atc->rsc_mgrs[SUM]; + sum_dsc.msr = atc->msr; + for (i = 0, atc->n_pcm = 0; i < (2*4); i++) { + err = sum_mgr->get_sum(sum_mgr, &sum_dsc, + (struct sum **)&atc->pcm[i]); + if (err) + return err; + + atc->n_pcm++; + } + + return 0; +} + +static void +atc_connect_dai(struct src_mgr *src_mgr, struct dai *dai, + struct src **srcs, struct srcimp **srcimps) +{ + struct rsc *rscs[2] = {NULL}; + struct src *src; + struct srcimp *srcimp; + int i = 0; + + rscs[0] = &dai->daio.rscl; + rscs[1] = &dai->daio.rscr; + for (i = 0; i < 2; i++) { + src = srcs[i]; + srcimp = srcimps[i]; + srcimp->ops->map(srcimp, src, rscs[i]); + src_mgr->src_disable(src_mgr, src); + } + + src_mgr->commit_write(src_mgr); /* Actually disable SRCs */ + + src = srcs[0]; + src->ops->set_pm(src, 1); + for (i = 0; i < 2; i++) { + src = srcs[i]; + src->ops->set_state(src, SRC_STATE_RUN); + src->ops->commit_write(src); + src_mgr->src_enable_s(src_mgr, src); + } + + dai->ops->set_srt_srcl(dai, &(srcs[0]->rsc)); + dai->ops->set_srt_srcr(dai, &(srcs[1]->rsc)); + + dai->ops->set_enb_src(dai, 1); + dai->ops->set_enb_srt(dai, 1); + dai->ops->commit_write(dai); + + src_mgr->commit_write(src_mgr); /* Synchronously enable SRCs */ +} + +static void atc_connect_resources(struct ct_atc *atc) +{ + struct dai *dai; + struct dao *dao; + struct src *src; + struct sum *sum; + struct ct_mixer *mixer; + struct rsc *rscs[2] = {NULL}; + int i, j; + + mixer = atc->mixer; + + for (i = MIX_WAVE_FRONT, j = LINEO1; i <= MIX_SPDIF_OUT; i++, j++) { + mixer->get_output_ports(mixer, i, &rscs[0], &rscs[1]); + dao = container_of(atc->daios[j], struct dao, daio); + dao->ops->set_left_input(dao, rscs[0]); + dao->ops->set_right_input(dao, rscs[1]); + } + + dai = container_of(atc->daios[LINEIM], struct dai, daio); + atc_connect_dai(atc->rsc_mgrs[SRC], dai, + (struct src **)&atc->srcs[2], + (struct srcimp **)&atc->srcimps[2]); + src = atc->srcs[2]; + mixer->set_input_left(mixer, MIX_LINE_IN, &src->rsc); + src = atc->srcs[3]; + mixer->set_input_right(mixer, MIX_LINE_IN, &src->rsc); + + dai = container_of(atc->daios[SPDIFIO], struct dai, daio); + atc_connect_dai(atc->rsc_mgrs[SRC], dai, + (struct src **)&atc->srcs[0], + (struct srcimp **)&atc->srcimps[0]); + + src = atc->srcs[0]; + mixer->set_input_left(mixer, MIX_SPDIF_IN, &src->rsc); + src = atc->srcs[1]; + mixer->set_input_right(mixer, MIX_SPDIF_IN, &src->rsc); + + for (i = MIX_PCMI_FRONT, j = 0; i <= MIX_PCMI_SURROUND; i++, j += 2) { + sum = atc->pcm[j]; + mixer->set_input_left(mixer, i, &sum->rsc); + sum = atc->pcm[j+1]; + mixer->set_input_right(mixer, i, &sum->rsc); + } +} + +#ifdef CONFIG_PM +static int atc_suspend(struct ct_atc *atc, pm_message_t state) +{ + int i; + struct hw *hw = atc->hw; + + snd_power_change_state(atc->card, SNDRV_CTL_POWER_D3hot); + + for (i = FRONT; i < NUM_PCMS; i++) { + if (!atc->pcms[i]) + continue; + + snd_pcm_suspend_all(atc->pcms[i]); + } + + atc_release_resources(atc); + + hw->suspend(hw, state); + + return 0; +} + +static int atc_hw_resume(struct ct_atc *atc) +{ + struct hw *hw = atc->hw; + struct card_conf info = {0}; + + /* Re-initialize card hardware. */ + info.rsr = atc->rsr; + info.msr = atc->msr; + info.vm_pgt_phys = atc_get_ptp_phys(atc, 0); + return hw->resume(hw, &info); +} + +static int atc_resources_resume(struct ct_atc *atc) +{ + struct ct_mixer *mixer; + int err = 0; + + /* Get resources */ + err = atc_get_resources(atc); + if (err < 0) { + atc_release_resources(atc); + return err; + } + + /* Build topology */ + atc_connect_resources(atc); + + mixer = atc->mixer; + mixer->resume(mixer); + + return 0; +} + +static int atc_resume(struct ct_atc *atc) +{ + int err = 0; + + /* Do hardware resume. */ + err = atc_hw_resume(atc); + if (err < 0) { + printk(KERN_ERR "ctxfi: pci_enable_device failed, " + "disabling device\n"); + snd_card_disconnect(atc->card); + return err; + } + + err = atc_resources_resume(atc); + if (err < 0) + return err; + + snd_power_change_state(atc->card, SNDRV_CTL_POWER_D0); + + return 0; +} +#endif + +static struct ct_atc atc_preset __devinitdata = { + .map_audio_buffer = ct_map_audio_buffer, + .unmap_audio_buffer = ct_unmap_audio_buffer, + .pcm_playback_prepare = atc_pcm_playback_prepare, + .pcm_release_resources = atc_pcm_release_resources, + .pcm_playback_start = atc_pcm_playback_start, + .pcm_playback_stop = atc_pcm_stop, + .pcm_playback_position = atc_pcm_playback_position, + .pcm_capture_prepare = atc_pcm_capture_prepare, + .pcm_capture_start = atc_pcm_capture_start, + .pcm_capture_stop = atc_pcm_stop, + .pcm_capture_position = atc_pcm_capture_position, + .spdif_passthru_playback_prepare = spdif_passthru_playback_prepare, + .get_ptp_phys = atc_get_ptp_phys, + .select_line_in = atc_select_line_in, + .select_mic_in = atc_select_mic_in, + .select_digit_io = atc_select_digit_io, + .line_front_unmute = atc_line_front_unmute, + .line_surround_unmute = atc_line_surround_unmute, + .line_clfe_unmute = atc_line_clfe_unmute, + .line_rear_unmute = atc_line_rear_unmute, + .line_in_unmute = atc_line_in_unmute, + .spdif_out_unmute = atc_spdif_out_unmute, + .spdif_in_unmute = atc_spdif_in_unmute, + .spdif_out_get_status = atc_spdif_out_get_status, + .spdif_out_set_status = atc_spdif_out_set_status, + .spdif_out_passthru = atc_spdif_out_passthru, + .have_digit_io_switch = atc_have_digit_io_switch, +#ifdef CONFIG_PM + .suspend = atc_suspend, + .resume = atc_resume, +#endif +}; + +/** + * ct_atc_create - create and initialize a hardware manager + * @card: corresponding alsa card object + * @pci: corresponding kernel pci device object + * @ratc: return created object address in it + * + * Creates and initializes a hardware manager. + * + * Creates kmallocated ct_atc structure. Initializes hardware. + * Returns 0 if suceeds, or negative error code if fails. + */ + +int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci, + unsigned int rsr, unsigned int msr, + int chip_type, struct ct_atc **ratc) +{ + struct ct_atc *atc; + static struct snd_device_ops ops = { + .dev_free = atc_dev_free, + }; + int err; + + *ratc = NULL; + + atc = kzalloc(sizeof(*atc), GFP_KERNEL); + if (NULL == atc) + return -ENOMEM; + + /* Set operations */ + *atc = atc_preset; + + atc->card = card; + atc->pci = pci; + atc->rsr = rsr; + atc->msr = msr; + atc->chip_type = chip_type; + + mutex_init(&atc->atc_mutex); + + /* Find card model */ + err = atc_identify_card(atc); + if (err < 0) { + printk(KERN_ERR "ctatc: Card not recognised\n"); + goto error1; + } + + /* Set up device virtual memory management object */ + err = ct_vm_create(&atc->vm); + if (err < 0) + goto error1; + + /* Create all atc hw devices */ + err = atc_create_hw_devs(atc); + if (err < 0) + goto error1; + + err = ct_mixer_create(atc, (struct ct_mixer **)&atc->mixer); + if (err) { + printk(KERN_ERR "ctxfi: Failed to create mixer obj!!!\n"); + goto error1; + } + + /* Get resources */ + err = atc_get_resources(atc); + if (err < 0) + goto error1; + + /* Build topology */ + atc_connect_resources(atc); + + atc->timer = ct_timer_new(atc); + if (!atc->timer) + goto error1; + + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, atc, &ops); + if (err < 0) + goto error1; + + snd_card_set_dev(card, &pci->dev); + + *ratc = atc; + return 0; + +error1: + ct_atc_destroy(atc); + printk(KERN_ERR "ctxfi: Something wrong!!!\n"); + return err; +} diff --git a/sound/pci/ctxfi/ctatc.h b/sound/pci/ctxfi/ctatc.h new file mode 100644 index 000000000000..9fd8a5708943 --- /dev/null +++ b/sound/pci/ctxfi/ctatc.h @@ -0,0 +1,154 @@ +/** + * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. + * + * This source file is released under GPL v2 license (no other versions). + * See the COPYING file included in the main directory of this source + * distribution for the license terms and conditions. + * + * @File ctatc.h + * + * @Brief + * This file contains the definition of the device resource management object. + * + * @Author Liu Chun + * @Date Mar 28 2008 + * + */ + +#ifndef CTATC_H +#define CTATC_H + +#include +#include +#include +#include +#include + +#include "ctvmem.h" +#include "ctresource.h" + +enum CTALSADEVS { /* Types of alsa devices */ + FRONT, + SURROUND, + CLFE, + SIDE, + IEC958, + MIXER, + NUM_CTALSADEVS /* This should always be the last */ +}; + +struct ct_atc_chip_sub_details { + u16 subsys; + const char *nm_model; +}; + +struct ct_atc_chip_details { + u16 vendor; + u16 device; + const struct ct_atc_chip_sub_details *sub_details; + const char *nm_card; +}; + +struct ct_atc; +struct ct_timer; +struct ct_timer_instance; + +/* alsa pcm stream descriptor */ +struct ct_atc_pcm { + struct snd_pcm_substream *substream; + void (*interrupt)(struct ct_atc_pcm *apcm); + struct ct_timer_instance *timer; + unsigned int started:1; + + /* Only mono and interleaved modes are supported now. */ + struct ct_vm_block *vm_block; + void *src; /* SRC for interacting with host memory */ + void **srccs; /* SRCs for sample rate conversion */ + void **srcimps; /* SRC Input Mappers */ + void **amixers; /* AMIXERs for routing converted data */ + void *mono; /* A SUM resource for mixing chs to one */ + unsigned char n_srcc; /* Number of converting SRCs */ + unsigned char n_srcimp; /* Number of SRC Input Mappers */ + unsigned char n_amixer; /* Number of AMIXERs */ +}; + +/* Chip resource management object */ +struct ct_atc { + struct pci_dev *pci; + struct snd_card *card; + unsigned int rsr; /* reference sample rate in Hz */ + unsigned int msr; /* master sample rate in rsr */ + unsigned int pll_rate; /* current rate of Phase Lock Loop */ + + int chip_type; + int model; + const char *chip_name; + const char *model_name; + + struct ct_vm *vm; /* device virtual memory manager for this card */ + int (*map_audio_buffer)(struct ct_atc *atc, struct ct_atc_pcm *apcm); + void (*unmap_audio_buffer)(struct ct_atc *atc, struct ct_atc_pcm *apcm); + unsigned long (*get_ptp_phys)(struct ct_atc *atc, int index); + + struct mutex atc_mutex; + + int (*pcm_playback_prepare)(struct ct_atc *atc, + struct ct_atc_pcm *apcm); + int (*pcm_playback_start)(struct ct_atc *atc, struct ct_atc_pcm *apcm); + int (*pcm_playback_stop)(struct ct_atc *atc, struct ct_atc_pcm *apcm); + int (*pcm_playback_position)(struct ct_atc *atc, + struct ct_atc_pcm *apcm); + int (*spdif_passthru_playback_prepare)(struct ct_atc *atc, + struct ct_atc_pcm *apcm); + int (*pcm_capture_prepare)(struct ct_atc *atc, struct ct_atc_pcm *apcm); + int (*pcm_capture_start)(struct ct_atc *atc, struct ct_atc_pcm *apcm); + int (*pcm_capture_stop)(struct ct_atc *atc, struct ct_atc_pcm *apcm); + int (*pcm_capture_position)(struct ct_atc *atc, + struct ct_atc_pcm *apcm); + int (*pcm_release_resources)(struct ct_atc *atc, + struct ct_atc_pcm *apcm); + int (*select_line_in)(struct ct_atc *atc); + int (*select_mic_in)(struct ct_atc *atc); + int (*select_digit_io)(struct ct_atc *atc); + int (*line_front_unmute)(struct ct_atc *atc, unsigned char state); + int (*line_surround_unmute)(struct ct_atc *atc, unsigned char state); + int (*line_clfe_unmute)(struct ct_atc *atc, unsigned char state); + int (*line_rear_unmute)(struct ct_atc *atc, unsigned char state); + int (*line_in_unmute)(struct ct_atc *atc, unsigned char state); + int (*spdif_out_unmute)(struct ct_atc *atc, unsigned char state); + int (*spdif_in_unmute)(struct ct_atc *atc, unsigned char state); + int (*spdif_out_get_status)(struct ct_atc *atc, unsigned int *status); + int (*spdif_out_set_status)(struct ct_atc *atc, unsigned int status); + int (*spdif_out_passthru)(struct ct_atc *atc, unsigned char state); + int (*have_digit_io_switch)(struct ct_atc *atc); + + /* Don't touch! Used for internal object. */ + void *rsc_mgrs[NUM_RSCTYP]; /* chip resource managers */ + void *mixer; /* internal mixer object */ + void *hw; /* chip specific hardware access object */ + void **daios; /* digital audio io resources */ + void **pcm; /* SUMs for collecting all pcm stream */ + void **srcs; /* Sample Rate Converters for input signal */ + void **srcimps; /* input mappers for SRCs */ + unsigned char n_daio; + unsigned char n_src; + unsigned char n_srcimp; + unsigned char n_pcm; + + struct ct_timer *timer; + +#ifdef CONFIG_PM + int (*suspend)(struct ct_atc *atc, pm_message_t state); + int (*resume)(struct ct_atc *atc); +#define NUM_PCMS (NUM_CTALSADEVS - 1) + struct snd_pcm *pcms[NUM_PCMS]; +#endif +}; + + +int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci, + unsigned int rsr, unsigned int msr, int chip_type, + struct ct_atc **ratc); +int __devinit ct_atc_create_alsa_devs(struct ct_atc *atc); + +#endif /* CTATC_H */ diff --git a/sound/pci/ctxfi/ctdaio.c b/sound/pci/ctxfi/ctdaio.c new file mode 100644 index 000000000000..082e35c08c02 --- /dev/null +++ b/sound/pci/ctxfi/ctdaio.c @@ -0,0 +1,769 @@ +/** + * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. + * + * This source file is released under GPL v2 license (no other versions). + * See the COPYING file included in the main directory of this source + * distribution for the license terms and conditions. + * + * @File ctdaio.c + * + * @Brief + * This file contains the implementation of Digital Audio Input Output + * resource management object. + * + * @Author Liu Chun + * @Date May 23 2008 + * + */ + +#include "ctdaio.h" +#include "cthardware.h" +#include "ctimap.h" +#include +#include + +#define DAIO_RESOURCE_NUM NUM_DAIOTYP +#define DAIO_OUT_MAX SPDIFOO + +union daio_usage { + struct { + unsigned short lineo1:1; + unsigned short lineo2:1; + unsigned short lineo3:1; + unsigned short lineo4:1; + unsigned short spdifoo:1; + unsigned short lineim:1; + unsigned short spdifio:1; + unsigned short spdifi1:1; + } bf; + unsigned short data; +}; + +struct daio_rsc_idx { + unsigned short left; + unsigned short right; +}; + +struct daio_rsc_idx idx_20k1[NUM_DAIOTYP] = { + [LINEO1] = {.left = 0x00, .right = 0x01}, + [LINEO2] = {.left = 0x18, .right = 0x19}, + [LINEO3] = {.left = 0x08, .right = 0x09}, + [LINEO4] = {.left = 0x10, .right = 0x11}, + [LINEIM] = {.left = 0x1b5, .right = 0x1bd}, + [SPDIFOO] = {.left = 0x20, .right = 0x21}, + [SPDIFIO] = {.left = 0x15, .right = 0x1d}, + [SPDIFI1] = {.left = 0x95, .right = 0x9d}, +}; + +struct daio_rsc_idx idx_20k2[NUM_DAIOTYP] = { + [LINEO1] = {.left = 0x40, .right = 0x41}, + [LINEO2] = {.left = 0x70, .right = 0x71}, + [LINEO3] = {.left = 0x50, .right = 0x51}, + [LINEO4] = {.left = 0x60, .right = 0x61}, + [LINEIM] = {.left = 0x45, .right = 0xc5}, + [SPDIFOO] = {.left = 0x00, .right = 0x01}, + [SPDIFIO] = {.left = 0x05, .right = 0x85}, +}; + +static int daio_master(struct rsc *rsc) +{ + /* Actually, this is not the resource index of DAIO. + * For DAO, it is the input mapper index. And, for DAI, + * it is the output time-slot index. */ + return rsc->conj = rsc->idx; +} + +static int daio_index(const struct rsc *rsc) +{ + return rsc->conj; +} + +static int daio_out_next_conj(struct rsc *rsc) +{ + return rsc->conj += 2; +} + +static int daio_in_next_conj_20k1(struct rsc *rsc) +{ + return rsc->conj += 0x200; +} + +static int daio_in_next_conj_20k2(struct rsc *rsc) +{ + return rsc->conj += 0x100; +} + +static struct rsc_ops daio_out_rsc_ops = { + .master = daio_master, + .next_conj = daio_out_next_conj, + .index = daio_index, + .output_slot = NULL, +}; + +static struct rsc_ops daio_in_rsc_ops_20k1 = { + .master = daio_master, + .next_conj = daio_in_next_conj_20k1, + .index = NULL, + .output_slot = daio_index, +}; + +static struct rsc_ops daio_in_rsc_ops_20k2 = { + .master = daio_master, + .next_conj = daio_in_next_conj_20k2, + .index = NULL, + .output_slot = daio_index, +}; + +static unsigned int daio_device_index(enum DAIOTYP type, struct hw *hw) +{ + switch (hw->chip_type) { + case ATC20K1: + switch (type) { + case SPDIFOO: return 0; + case SPDIFIO: return 0; + case SPDIFI1: return 1; + case LINEO1: return 4; + case LINEO2: return 7; + case LINEO3: return 5; + case LINEO4: return 6; + case LINEIM: return 7; + default: return -EINVAL; + } + case ATC20K2: + switch (type) { + case SPDIFOO: return 0; + case SPDIFIO: return 0; + case LINEO1: return 4; + case LINEO2: return 7; + case LINEO3: return 5; + case LINEO4: return 6; + case LINEIM: return 4; + default: return -EINVAL; + } + default: + return -EINVAL; + } +} + +static int dao_rsc_reinit(struct dao *dao, const struct dao_desc *desc); + +static int dao_spdif_get_spos(struct dao *dao, unsigned int *spos) +{ + ((struct hw *)dao->hw)->dao_get_spos(dao->ctrl_blk, spos); + return 0; +} + +static int dao_spdif_set_spos(struct dao *dao, unsigned int spos) +{ + ((struct hw *)dao->hw)->dao_set_spos(dao->ctrl_blk, spos); + return 0; +} + +static int dao_commit_write(struct dao *dao) +{ + ((struct hw *)dao->hw)->dao_commit_write(dao->hw, + daio_device_index(dao->daio.type, dao->hw), dao->ctrl_blk); + return 0; +} + +static int dao_set_left_input(struct dao *dao, struct rsc *input) +{ + struct imapper *entry; + struct daio *daio = &dao->daio; + int i; + + entry = kzalloc((sizeof(*entry) * daio->rscl.msr), GFP_KERNEL); + if (NULL == entry) + return -ENOMEM; + + /* Program master and conjugate resources */ + input->ops->master(input); + daio->rscl.ops->master(&daio->rscl); + for (i = 0; i < daio->rscl.msr; i++, entry++) { + entry->slot = input->ops->output_slot(input); + entry->user = entry->addr = daio->rscl.ops->index(&daio->rscl); + dao->mgr->imap_add(dao->mgr, entry); + dao->imappers[i] = entry; + + input->ops->next_conj(input); + daio->rscl.ops->next_conj(&daio->rscl); + } + input->ops->master(input); + daio->rscl.ops->master(&daio->rscl); + + return 0; +} + +static int dao_set_right_input(struct dao *dao, struct rsc *input) +{ + struct imapper *entry; + struct daio *daio = &dao->daio; + int i; + + entry = kzalloc((sizeof(*entry) * daio->rscr.msr), GFP_KERNEL); + if (NULL == entry) + return -ENOMEM; + + /* Program master and conjugate resources */ + input->ops->master(input); + daio->rscr.ops->master(&daio->rscr); + for (i = 0; i < daio->rscr.msr; i++, entry++) { + entry->slot = input->ops->output_slot(input); + entry->user = entry->addr = daio->rscr.ops->index(&daio->rscr); + dao->mgr->imap_add(dao->mgr, entry); + dao->imappers[daio->rscl.msr + i] = entry; + + input->ops->next_conj(input); + daio->rscr.ops->next_conj(&daio->rscr); + } + input->ops->master(input); + daio->rscr.ops->master(&daio->rscr); + + return 0; +} + +static int dao_clear_left_input(struct dao *dao) +{ + struct imapper *entry; + struct daio *daio = &dao->daio; + int i; + + if (NULL == dao->imappers[0]) + return 0; + + entry = dao->imappers[0]; + dao->mgr->imap_delete(dao->mgr, entry); + /* Program conjugate resources */ + for (i = 1; i < daio->rscl.msr; i++) { + entry = dao->imappers[i]; + dao->mgr->imap_delete(dao->mgr, entry); + dao->imappers[i] = NULL; + } + + kfree(dao->imappers[0]); + dao->imappers[0] = NULL; + + return 0; +} + +static int dao_clear_right_input(struct dao *dao) +{ + struct imapper *entry; + struct daio *daio = &dao->daio; + int i; + + if (NULL == dao->imappers[daio->rscl.msr]) + return 0; + + entry = dao->imappers[daio->rscl.msr]; + dao->mgr->imap_delete(dao->mgr, entry); + /* Program conjugate resources */ + for (i = 1; i < daio->rscr.msr; i++) { + entry = dao->imappers[daio->rscl.msr + i]; + dao->mgr->imap_delete(dao->mgr, entry); + dao->imappers[daio->rscl.msr + i] = NULL; + } + + kfree(dao->imappers[daio->rscl.msr]); + dao->imappers[daio->rscl.msr] = NULL; + + return 0; +} + +static struct dao_rsc_ops dao_ops = { + .set_spos = dao_spdif_set_spos, + .commit_write = dao_commit_write, + .get_spos = dao_spdif_get_spos, + .reinit = dao_rsc_reinit, + .set_left_input = dao_set_left_input, + .set_right_input = dao_set_right_input, + .clear_left_input = dao_clear_left_input, + .clear_right_input = dao_clear_right_input, +}; + +static int dai_set_srt_srcl(struct dai *dai, struct rsc *src) +{ + src->ops->master(src); + ((struct hw *)dai->hw)->dai_srt_set_srcm(dai->ctrl_blk, + src->ops->index(src)); + return 0; +} + +static int dai_set_srt_srcr(struct dai *dai, struct rsc *src) +{ + src->ops->master(src); + ((struct hw *)dai->hw)->dai_srt_set_srco(dai->ctrl_blk, + src->ops->index(src)); + return 0; +} + +static int dai_set_srt_msr(struct dai *dai, unsigned int msr) +{ + unsigned int rsr; + + for (rsr = 0; msr > 1; msr >>= 1) + rsr++; + + ((struct hw *)dai->hw)->dai_srt_set_rsr(dai->ctrl_blk, rsr); + return 0; +} + +static int dai_set_enb_src(struct dai *dai, unsigned int enb) +{ + ((struct hw *)dai->hw)->dai_srt_set_ec(dai->ctrl_blk, enb); + return 0; +} + +static int dai_set_enb_srt(struct dai *dai, unsigned int enb) +{ + ((struct hw *)dai->hw)->dai_srt_set_et(dai->ctrl_blk, enb); + return 0; +} + +static int dai_commit_write(struct dai *dai) +{ + ((struct hw *)dai->hw)->dai_commit_write(dai->hw, + daio_device_index(dai->daio.type, dai->hw), dai->ctrl_blk); + return 0; +} + +static struct dai_rsc_ops dai_ops = { + .set_srt_srcl = dai_set_srt_srcl, + .set_srt_srcr = dai_set_srt_srcr, + .set_srt_msr = dai_set_srt_msr, + .set_enb_src = dai_set_enb_src, + .set_enb_srt = dai_set_enb_srt, + .commit_write = dai_commit_write, +}; + +static int daio_rsc_init(struct daio *daio, + const struct daio_desc *desc, + void *hw) +{ + int err; + unsigned int idx_l, idx_r; + + switch (((struct hw *)hw)->chip_type) { + case ATC20K1: + idx_l = idx_20k1[desc->type].left; + idx_r = idx_20k1[desc->type].right; + break; + case ATC20K2: + idx_l = idx_20k2[desc->type].left; + idx_r = idx_20k2[desc->type].right; + break; + default: + return -EINVAL; + } + err = rsc_init(&daio->rscl, idx_l, DAIO, desc->msr, hw); + if (err) + return err; + + err = rsc_init(&daio->rscr, idx_r, DAIO, desc->msr, hw); + if (err) + goto error1; + + /* Set daio->rscl/r->ops to daio specific ones */ + if (desc->type <= DAIO_OUT_MAX) { + daio->rscl.ops = daio->rscr.ops = &daio_out_rsc_ops; + } else { + switch (((struct hw *)hw)->chip_type) { + case ATC20K1: + daio->rscl.ops = daio->rscr.ops = &daio_in_rsc_ops_20k1; + break; + case ATC20K2: + daio->rscl.ops = daio->rscr.ops = &daio_in_rsc_ops_20k2; + break; + default: + break; + } + } + daio->type = desc->type; + + return 0; + +error1: + rsc_uninit(&daio->rscl); + return err; +} + +static int daio_rsc_uninit(struct daio *daio) +{ + rsc_uninit(&daio->rscl); + rsc_uninit(&daio->rscr); + + return 0; +} + +static int dao_rsc_init(struct dao *dao, + const struct daio_desc *desc, + struct daio_mgr *mgr) +{ + struct hw *hw = mgr->mgr.hw; + unsigned int conf; + int err; + + err = daio_rsc_init(&dao->daio, desc, mgr->mgr.hw); + if (err) + return err; + + dao->imappers = kzalloc(sizeof(void *)*desc->msr*2, GFP_KERNEL); + if (NULL == dao->imappers) { + err = -ENOMEM; + goto error1; + } + dao->ops = &dao_ops; + dao->mgr = mgr; + dao->hw = hw; + err = hw->dao_get_ctrl_blk(&dao->ctrl_blk); + if (err) + goto error2; + + hw->daio_mgr_dsb_dao(mgr->mgr.ctrl_blk, + daio_device_index(dao->daio.type, hw)); + hw->daio_mgr_commit_write(hw, mgr->mgr.ctrl_blk); + + conf = (desc->msr & 0x7) | (desc->passthru << 3); + hw->daio_mgr_dao_init(mgr->mgr.ctrl_blk, + daio_device_index(dao->daio.type, hw), conf); + hw->daio_mgr_enb_dao(mgr->mgr.ctrl_blk, + daio_device_index(dao->daio.type, hw)); + hw->daio_mgr_commit_write(hw, mgr->mgr.ctrl_blk); + + return 0; + +error2: + kfree(dao->imappers); + dao->imappers = NULL; +error1: + daio_rsc_uninit(&dao->daio); + return err; +} + +static int dao_rsc_uninit(struct dao *dao) +{ + if (NULL != dao->imappers) { + if (NULL != dao->imappers[0]) + dao_clear_left_input(dao); + + if (NULL != dao->imappers[dao->daio.rscl.msr]) + dao_clear_right_input(dao); + + kfree(dao->imappers); + dao->imappers = NULL; + } + ((struct hw *)dao->hw)->dao_put_ctrl_blk(dao->ctrl_blk); + dao->hw = dao->ctrl_blk = NULL; + daio_rsc_uninit(&dao->daio); + + return 0; +} + +static int dao_rsc_reinit(struct dao *dao, const struct dao_desc *desc) +{ + struct daio_mgr *mgr = dao->mgr; + struct daio_desc dsc = {0}; + + dsc.type = dao->daio.type; + dsc.msr = desc->msr; + dsc.passthru = desc->passthru; + dao_rsc_uninit(dao); + return dao_rsc_init(dao, &dsc, mgr); +} + +static int dai_rsc_init(struct dai *dai, + const struct daio_desc *desc, + struct daio_mgr *mgr) +{ + int err; + struct hw *hw = mgr->mgr.hw; + unsigned int rsr, msr; + + err = daio_rsc_init(&dai->daio, desc, mgr->mgr.hw); + if (err) + return err; + + dai->ops = &dai_ops; + dai->hw = mgr->mgr.hw; + err = hw->dai_get_ctrl_blk(&dai->ctrl_blk); + if (err) + goto error1; + + for (rsr = 0, msr = desc->msr; msr > 1; msr >>= 1) + rsr++; + + hw->dai_srt_set_rsr(dai->ctrl_blk, rsr); + hw->dai_srt_set_drat(dai->ctrl_blk, 0); + /* default to disabling control of a SRC */ + hw->dai_srt_set_ec(dai->ctrl_blk, 0); + hw->dai_srt_set_et(dai->ctrl_blk, 0); /* default to disabling SRT */ + hw->dai_commit_write(hw, + daio_device_index(dai->daio.type, dai->hw), dai->ctrl_blk); + + return 0; + +error1: + daio_rsc_uninit(&dai->daio); + return err; +} + +static int dai_rsc_uninit(struct dai *dai) +{ + ((struct hw *)dai->hw)->dai_put_ctrl_blk(dai->ctrl_blk); + dai->hw = dai->ctrl_blk = NULL; + daio_rsc_uninit(&dai->daio); + return 0; +} + +static int daio_mgr_get_rsc(struct rsc_mgr *mgr, enum DAIOTYP type) +{ + if (((union daio_usage *)mgr->rscs)->data & (0x1 << type)) + return -ENOENT; + + ((union daio_usage *)mgr->rscs)->data |= (0x1 << type); + + return 0; +} + +static int daio_mgr_put_rsc(struct rsc_mgr *mgr, enum DAIOTYP type) +{ + ((union daio_usage *)mgr->rscs)->data &= ~(0x1 << type); + + return 0; +} + +static int get_daio_rsc(struct daio_mgr *mgr, + const struct daio_desc *desc, + struct daio **rdaio) +{ + int err; + struct dai *dai = NULL; + struct dao *dao = NULL; + unsigned long flags; + + *rdaio = NULL; + + /* Check whether there are sufficient daio resources to meet request. */ + spin_lock_irqsave(&mgr->mgr_lock, flags); + err = daio_mgr_get_rsc(&mgr->mgr, desc->type); + spin_unlock_irqrestore(&mgr->mgr_lock, flags); + if (err) { + printk(KERN_ERR "Can't meet DAIO resource request!\n"); + return err; + } + + /* Allocate mem for daio resource */ + if (desc->type <= DAIO_OUT_MAX) { + dao = kzalloc(sizeof(*dao), GFP_KERNEL); + if (NULL == dao) { + err = -ENOMEM; + goto error; + } + err = dao_rsc_init(dao, desc, mgr); + if (err) + goto error; + + *rdaio = &dao->daio; + } else { + dai = kzalloc(sizeof(*dai), GFP_KERNEL); + if (NULL == dai) { + err = -ENOMEM; + goto error; + } + err = dai_rsc_init(dai, desc, mgr); + if (err) + goto error; + + *rdaio = &dai->daio; + } + + mgr->daio_enable(mgr, *rdaio); + mgr->commit_write(mgr); + + return 0; + +error: + if (NULL != dao) + kfree(dao); + else if (NULL != dai) + kfree(dai); + + spin_lock_irqsave(&mgr->mgr_lock, flags); + daio_mgr_put_rsc(&mgr->mgr, desc->type); + spin_unlock_irqrestore(&mgr->mgr_lock, flags); + return err; +} + +static int put_daio_rsc(struct daio_mgr *mgr, struct daio *daio) +{ + unsigned long flags; + + mgr->daio_disable(mgr, daio); + mgr->commit_write(mgr); + + spin_lock_irqsave(&mgr->mgr_lock, flags); + daio_mgr_put_rsc(&mgr->mgr, daio->type); + spin_unlock_irqrestore(&mgr->mgr_lock, flags); + + if (daio->type <= DAIO_OUT_MAX) { + dao_rsc_uninit(container_of(daio, struct dao, daio)); + kfree(container_of(daio, struct dao, daio)); + } else { + dai_rsc_uninit(container_of(daio, struct dai, daio)); + kfree(container_of(daio, struct dai, daio)); + } + + return 0; +} + +static int daio_mgr_enb_daio(struct daio_mgr *mgr, struct daio *daio) +{ + struct hw *hw = mgr->mgr.hw; + + if (DAIO_OUT_MAX >= daio->type) { + hw->daio_mgr_enb_dao(mgr->mgr.ctrl_blk, + daio_device_index(daio->type, hw)); + } else { + hw->daio_mgr_enb_dai(mgr->mgr.ctrl_blk, + daio_device_index(daio->type, hw)); + } + return 0; +} + +static int daio_mgr_dsb_daio(struct daio_mgr *mgr, struct daio *daio) +{ + struct hw *hw = mgr->mgr.hw; + + if (DAIO_OUT_MAX >= daio->type) { + hw->daio_mgr_dsb_dao(mgr->mgr.ctrl_blk, + daio_device_index(daio->type, hw)); + } else { + hw->daio_mgr_dsb_dai(mgr->mgr.ctrl_blk, + daio_device_index(daio->type, hw)); + } + return 0; +} + +static int daio_map_op(void *data, struct imapper *entry) +{ + struct rsc_mgr *mgr = &((struct daio_mgr *)data)->mgr; + struct hw *hw = mgr->hw; + + hw->daio_mgr_set_imaparc(mgr->ctrl_blk, entry->slot); + hw->daio_mgr_set_imapnxt(mgr->ctrl_blk, entry->next); + hw->daio_mgr_set_imapaddr(mgr->ctrl_blk, entry->addr); + hw->daio_mgr_commit_write(mgr->hw, mgr->ctrl_blk); + + return 0; +} + +static int daio_imap_add(struct daio_mgr *mgr, struct imapper *entry) +{ + unsigned long flags; + int err; + + spin_lock_irqsave(&mgr->imap_lock, flags); + if ((0 == entry->addr) && (mgr->init_imap_added)) { + input_mapper_delete(&mgr->imappers, mgr->init_imap, + daio_map_op, mgr); + mgr->init_imap_added = 0; + } + err = input_mapper_add(&mgr->imappers, entry, daio_map_op, mgr); + spin_unlock_irqrestore(&mgr->imap_lock, flags); + + return err; +} + +static int daio_imap_delete(struct daio_mgr *mgr, struct imapper *entry) +{ + unsigned long flags; + int err; + + spin_lock_irqsave(&mgr->imap_lock, flags); + err = input_mapper_delete(&mgr->imappers, entry, daio_map_op, mgr); + if (list_empty(&mgr->imappers)) { + input_mapper_add(&mgr->imappers, mgr->init_imap, + daio_map_op, mgr); + mgr->init_imap_added = 1; + } + spin_unlock_irqrestore(&mgr->imap_lock, flags); + + return err; +} + +static int daio_mgr_commit_write(struct daio_mgr *mgr) +{ + struct hw *hw = mgr->mgr.hw; + + hw->daio_mgr_commit_write(hw, mgr->mgr.ctrl_blk); + return 0; +} + +int daio_mgr_create(void *hw, struct daio_mgr **rdaio_mgr) +{ + int err, i; + struct daio_mgr *daio_mgr; + struct imapper *entry; + + *rdaio_mgr = NULL; + daio_mgr = kzalloc(sizeof(*daio_mgr), GFP_KERNEL); + if (NULL == daio_mgr) + return -ENOMEM; + + err = rsc_mgr_init(&daio_mgr->mgr, DAIO, DAIO_RESOURCE_NUM, hw); + if (err) + goto error1; + + spin_lock_init(&daio_mgr->mgr_lock); + spin_lock_init(&daio_mgr->imap_lock); + INIT_LIST_HEAD(&daio_mgr->imappers); + entry = kzalloc(sizeof(*entry), GFP_KERNEL); + if (NULL == entry) { + err = -ENOMEM; + goto error2; + } + entry->slot = entry->addr = entry->next = entry->user = 0; + list_add(&entry->list, &daio_mgr->imappers); + daio_mgr->init_imap = entry; + daio_mgr->init_imap_added = 1; + + daio_mgr->get_daio = get_daio_rsc; + daio_mgr->put_daio = put_daio_rsc; + daio_mgr->daio_enable = daio_mgr_enb_daio; + daio_mgr->daio_disable = daio_mgr_dsb_daio; + daio_mgr->imap_add = daio_imap_add; + daio_mgr->imap_delete = daio_imap_delete; + daio_mgr->commit_write = daio_mgr_commit_write; + + for (i = 0; i < 8; i++) { + ((struct hw *)hw)->daio_mgr_dsb_dao(daio_mgr->mgr.ctrl_blk, i); + ((struct hw *)hw)->daio_mgr_dsb_dai(daio_mgr->mgr.ctrl_blk, i); + } + ((struct hw *)hw)->daio_mgr_commit_write(hw, daio_mgr->mgr.ctrl_blk); + + *rdaio_mgr = daio_mgr; + + return 0; + +error2: + rsc_mgr_uninit(&daio_mgr->mgr); +error1: + kfree(daio_mgr); + return err; +} + +int daio_mgr_destroy(struct daio_mgr *daio_mgr) +{ + unsigned long flags; + + /* free daio input mapper list */ + spin_lock_irqsave(&daio_mgr->imap_lock, flags); + free_input_mapper_list(&daio_mgr->imappers); + spin_unlock_irqrestore(&daio_mgr->imap_lock, flags); + + rsc_mgr_uninit(&daio_mgr->mgr); + kfree(daio_mgr); + + return 0; +} + diff --git a/sound/pci/ctxfi/ctdaio.h b/sound/pci/ctxfi/ctdaio.h new file mode 100644 index 000000000000..0f52ce571ee8 --- /dev/null +++ b/sound/pci/ctxfi/ctdaio.h @@ -0,0 +1,122 @@ +/** + * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. + * + * This source file is released under GPL v2 license (no other versions). + * See the COPYING file included in the main directory of this source + * distribution for the license terms and conditions. + * + * @File ctdaio.h + * + * @Brief + * This file contains the definition of Digital Audio Input Output + * resource management object. + * + * @Author Liu Chun + * @Date May 23 2008 + * + */ + +#ifndef CTDAIO_H +#define CTDAIO_H + +#include "ctresource.h" +#include "ctimap.h" +#include +#include + +/* Define the descriptor of a daio resource */ +enum DAIOTYP { + LINEO1, + LINEO2, + LINEO3, + LINEO4, + SPDIFOO, /* S/PDIF Out (Flexijack/Optical) */ + LINEIM, + SPDIFIO, /* S/PDIF In (Flexijack/Optical) on the card */ + SPDIFI1, /* S/PDIF In on internal Drive Bay */ + NUM_DAIOTYP +}; + +struct dao_rsc_ops; +struct dai_rsc_ops; +struct daio_mgr; + +struct daio { + struct rsc rscl; /* Basic resource info for left TX/RX */ + struct rsc rscr; /* Basic resource info for right TX/RX */ + enum DAIOTYP type; +}; + +struct dao { + struct daio daio; + struct dao_rsc_ops *ops; /* DAO specific operations */ + struct imapper **imappers; + struct daio_mgr *mgr; + void *hw; + void *ctrl_blk; +}; + +struct dai { + struct daio daio; + struct dai_rsc_ops *ops; /* DAI specific operations */ + void *hw; + void *ctrl_blk; +}; + +struct dao_desc { + unsigned int msr:4; + unsigned int passthru:1; +}; + +struct dao_rsc_ops { + int (*set_spos)(struct dao *dao, unsigned int spos); + int (*commit_write)(struct dao *dao); + int (*get_spos)(struct dao *dao, unsigned int *spos); + int (*reinit)(struct dao *dao, const struct dao_desc *desc); + int (*set_left_input)(struct dao *dao, struct rsc *input); + int (*set_right_input)(struct dao *dao, struct rsc *input); + int (*clear_left_input)(struct dao *dao); + int (*clear_right_input)(struct dao *dao); +}; + +struct dai_rsc_ops { + int (*set_srt_srcl)(struct dai *dai, struct rsc *src); + int (*set_srt_srcr)(struct dai *dai, struct rsc *src); + int (*set_srt_msr)(struct dai *dai, unsigned int msr); + int (*set_enb_src)(struct dai *dai, unsigned int enb); + int (*set_enb_srt)(struct dai *dai, unsigned int enb); + int (*commit_write)(struct dai *dai); +}; + +/* Define daio resource request description info */ +struct daio_desc { + unsigned int type:4; + unsigned int msr:4; + unsigned int passthru:1; +}; + +struct daio_mgr { + struct rsc_mgr mgr; /* Basic resource manager info */ + spinlock_t mgr_lock; + spinlock_t imap_lock; + struct list_head imappers; + struct imapper *init_imap; + unsigned int init_imap_added; + + /* request one daio resource */ + int (*get_daio)(struct daio_mgr *mgr, + const struct daio_desc *desc, struct daio **rdaio); + /* return one daio resource */ + int (*put_daio)(struct daio_mgr *mgr, struct daio *daio); + int (*daio_enable)(struct daio_mgr *mgr, struct daio *daio); + int (*daio_disable)(struct daio_mgr *mgr, struct daio *daio); + int (*imap_add)(struct daio_mgr *mgr, struct imapper *entry); + int (*imap_delete)(struct daio_mgr *mgr, struct imapper *entry); + int (*commit_write)(struct daio_mgr *mgr); +}; + +/* Constructor and destructor of daio resource manager */ +int daio_mgr_create(void *hw, struct daio_mgr **rdaio_mgr); +int daio_mgr_destroy(struct daio_mgr *daio_mgr); + +#endif /* CTDAIO_H */ diff --git a/sound/pci/ctxfi/cthardware.c b/sound/pci/ctxfi/cthardware.c new file mode 100644 index 000000000000..8e64f4862e85 --- /dev/null +++ b/sound/pci/ctxfi/cthardware.c @@ -0,0 +1,91 @@ +/** + * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. + * + * This source file is released under GPL v2 license (no other versions). + * See the COPYING file included in the main directory of this source + * distribution for the license terms and conditions. + * + * @File cthardware.c + * + * @Brief + * This file contains the implementation of hardware access methord. + * + * @Author Liu Chun + * @Date Jun 26 2008 + * + */ + +#include "cthardware.h" +#include "cthw20k1.h" +#include "cthw20k2.h" +#include + +int __devinit create_hw_obj(struct pci_dev *pci, enum CHIPTYP chip_type, + enum CTCARDS model, struct hw **rhw) +{ + int err; + + switch (chip_type) { + case ATC20K1: + err = create_20k1_hw_obj(rhw); + break; + case ATC20K2: + err = create_20k2_hw_obj(rhw); + break; + default: + err = -ENODEV; + break; + } + if (err) + return err; + + (*rhw)->pci = pci; + (*rhw)->chip_type = chip_type; + (*rhw)->model = model; + + return 0; +} + +int destroy_hw_obj(struct hw *hw) +{ + int err; + + switch (hw->pci->device) { + case 0x0005: /* 20k1 device */ + err = destroy_20k1_hw_obj(hw); + break; + case 0x000B: /* 20k2 device */ + err = destroy_20k2_hw_obj(hw); + break; + default: + err = -ENODEV; + break; + } + + return err; +} + +unsigned int get_field(unsigned int data, unsigned int field) +{ + int i; + + BUG_ON(!field); + /* @field should always be greater than 0 */ + for (i = 0; !(field & (1 << i)); ) + i++; + + return (data & field) >> i; +} + +void set_field(unsigned int *data, unsigned int field, unsigned int value) +{ + int i; + + BUG_ON(!field); + /* @field should always be greater than 0 */ + for (i = 0; !(field & (1 << i)); ) + i++; + + *data = (*data & (~field)) | ((value << i) & field); +} + diff --git a/sound/pci/ctxfi/cthardware.h b/sound/pci/ctxfi/cthardware.h new file mode 100644 index 000000000000..af55405f5dec --- /dev/null +++ b/sound/pci/ctxfi/cthardware.h @@ -0,0 +1,203 @@ +/** + * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. + * + * This source file is released under GPL v2 license (no other versions). + * See the COPYING file included in the main directory of this source + * distribution for the license terms and conditions. + * + * @File cthardware.h + * + * @Brief + * This file contains the definition of hardware access methord. + * + * @Author Liu Chun + * @Date May 13 2008 + * + */ + +#ifndef CTHARDWARE_H +#define CTHARDWARE_H + +#include +#include + +enum CHIPTYP { + ATC20K1, + ATC20K2, + ATCNONE +}; + +enum CTCARDS { + /* 20k1 models */ + CTSB055X, + CT20K1_MODEL_FIRST = CTSB055X, + CTSB073X, + CTUAA, + CT20K1_UNKNOWN, + /* 20k2 models */ + CTSB0760, + CT20K2_MODEL_FIRST = CTSB0760, + CTHENDRIX, + CTSB0880, + CT20K2_UNKNOWN, + NUM_CTCARDS /* This should always be the last */ +}; + +/* Type of input source for ADC */ +enum ADCSRC{ + ADC_MICIN, + ADC_LINEIN, + ADC_VIDEO, + ADC_AUX, + ADC_NONE /* Switch to digital input */ +}; + +struct card_conf { + /* device virtual mem page table page physical addr + * (supporting one page table page now) */ + unsigned long vm_pgt_phys; + unsigned int rsr; /* reference sample rate in Hzs*/ + unsigned int msr; /* master sample rate in rsrs */ +}; + +struct hw { + int (*card_init)(struct hw *hw, struct card_conf *info); + int (*card_stop)(struct hw *hw); + int (*pll_init)(struct hw *hw, unsigned int rsr); +#ifdef CONFIG_PM + int (*suspend)(struct hw *hw, pm_message_t state); + int (*resume)(struct hw *hw, struct card_conf *info); +#endif + int (*is_adc_source_selected)(struct hw *hw, enum ADCSRC source); + int (*select_adc_source)(struct hw *hw, enum ADCSRC source); + int (*have_digit_io_switch)(struct hw *hw); + + /* SRC operations */ + int (*src_rsc_get_ctrl_blk)(void **rblk); + int (*src_rsc_put_ctrl_blk)(void *blk); + int (*src_set_state)(void *blk, unsigned int state); + int (*src_set_bm)(void *blk, unsigned int bm); + int (*src_set_rsr)(void *blk, unsigned int rsr); + int (*src_set_sf)(void *blk, unsigned int sf); + int (*src_set_wr)(void *blk, unsigned int wr); + int (*src_set_pm)(void *blk, unsigned int pm); + int (*src_set_rom)(void *blk, unsigned int rom); + int (*src_set_vo)(void *blk, unsigned int vo); + int (*src_set_st)(void *blk, unsigned int st); + int (*src_set_ie)(void *blk, unsigned int ie); + int (*src_set_ilsz)(void *blk, unsigned int ilsz); + int (*src_set_bp)(void *blk, unsigned int bp); + int (*src_set_cisz)(void *blk, unsigned int cisz); + int (*src_set_ca)(void *blk, unsigned int ca); + int (*src_set_sa)(void *blk, unsigned int sa); + int (*src_set_la)(void *blk, unsigned int la); + int (*src_set_pitch)(void *blk, unsigned int pitch); + int (*src_set_clear_zbufs)(void *blk, unsigned int clear); + int (*src_set_dirty)(void *blk, unsigned int flags); + int (*src_set_dirty_all)(void *blk); + int (*src_commit_write)(struct hw *hw, unsigned int idx, void *blk); + int (*src_get_ca)(struct hw *hw, unsigned int idx, void *blk); + unsigned int (*src_get_dirty)(void *blk); + unsigned int (*src_dirty_conj_mask)(void); + int (*src_mgr_get_ctrl_blk)(void **rblk); + int (*src_mgr_put_ctrl_blk)(void *blk); + /* syncly enable src @idx */ + int (*src_mgr_enbs_src)(void *blk, unsigned int idx); + /* enable src @idx */ + int (*src_mgr_enb_src)(void *blk, unsigned int idx); + /* disable src @idx */ + int (*src_mgr_dsb_src)(void *blk, unsigned int idx); + int (*src_mgr_commit_write)(struct hw *hw, void *blk); + + /* SRC Input Mapper operations */ + int (*srcimp_mgr_get_ctrl_blk)(void **rblk); + int (*srcimp_mgr_put_ctrl_blk)(void *blk); + int (*srcimp_mgr_set_imaparc)(void *blk, unsigned int slot); + int (*srcimp_mgr_set_imapuser)(void *blk, unsigned int user); + int (*srcimp_mgr_set_imapnxt)(void *blk, unsigned int next); + int (*srcimp_mgr_set_imapaddr)(void *blk, unsigned int addr); + int (*srcimp_mgr_commit_write)(struct hw *hw, void *blk); + + /* AMIXER operations */ + int (*amixer_rsc_get_ctrl_blk)(void **rblk); + int (*amixer_rsc_put_ctrl_blk)(void *blk); + int (*amixer_mgr_get_ctrl_blk)(void **rblk); + int (*amixer_mgr_put_ctrl_blk)(void *blk); + int (*amixer_set_mode)(void *blk, unsigned int mode); + int (*amixer_set_iv)(void *blk, unsigned int iv); + int (*amixer_set_x)(void *blk, unsigned int x); + int (*amixer_set_y)(void *blk, unsigned int y); + int (*amixer_set_sadr)(void *blk, unsigned int sadr); + int (*amixer_set_se)(void *blk, unsigned int se); + int (*amixer_set_dirty)(void *blk, unsigned int flags); + int (*amixer_set_dirty_all)(void *blk); + int (*amixer_commit_write)(struct hw *hw, unsigned int idx, void *blk); + int (*amixer_get_y)(void *blk); + unsigned int (*amixer_get_dirty)(void *blk); + + /* DAIO operations */ + int (*dai_get_ctrl_blk)(void **rblk); + int (*dai_put_ctrl_blk)(void *blk); + int (*dai_srt_set_srco)(void *blk, unsigned int src); + int (*dai_srt_set_srcm)(void *blk, unsigned int src); + int (*dai_srt_set_rsr)(void *blk, unsigned int rsr); + int (*dai_srt_set_drat)(void *blk, unsigned int drat); + int (*dai_srt_set_ec)(void *blk, unsigned int ec); + int (*dai_srt_set_et)(void *blk, unsigned int et); + int (*dai_commit_write)(struct hw *hw, unsigned int idx, void *blk); + int (*dao_get_ctrl_blk)(void **rblk); + int (*dao_put_ctrl_blk)(void *blk); + int (*dao_set_spos)(void *blk, unsigned int spos); + int (*dao_commit_write)(struct hw *hw, unsigned int idx, void *blk); + int (*dao_get_spos)(void *blk, unsigned int *spos); + + int (*daio_mgr_get_ctrl_blk)(struct hw *hw, void **rblk); + int (*daio_mgr_put_ctrl_blk)(void *blk); + int (*daio_mgr_enb_dai)(void *blk, unsigned int idx); + int (*daio_mgr_dsb_dai)(void *blk, unsigned int idx); + int (*daio_mgr_enb_dao)(void *blk, unsigned int idx); + int (*daio_mgr_dsb_dao)(void *blk, unsigned int idx); + int (*daio_mgr_dao_init)(void *blk, unsigned int idx, + unsigned int conf); + int (*daio_mgr_set_imaparc)(void *blk, unsigned int slot); + int (*daio_mgr_set_imapnxt)(void *blk, unsigned int next); + int (*daio_mgr_set_imapaddr)(void *blk, unsigned int addr); + int (*daio_mgr_commit_write)(struct hw *hw, void *blk); + + int (*set_timer_irq)(struct hw *hw, int enable); + int (*set_timer_tick)(struct hw *hw, unsigned int tick); + unsigned int (*get_wc)(struct hw *hw); + + void (*irq_callback)(void *data, unsigned int bit); + void *irq_callback_data; + + struct pci_dev *pci; /* the pci kernel structure of this card */ + int irq; + unsigned long io_base; + unsigned long mem_base; + + enum CHIPTYP chip_type; + enum CTCARDS model; +}; + +int create_hw_obj(struct pci_dev *pci, enum CHIPTYP chip_type, + enum CTCARDS model, struct hw **rhw); +int destroy_hw_obj(struct hw *hw); + +unsigned int get_field(unsigned int data, unsigned int field); +void set_field(unsigned int *data, unsigned int field, unsigned int value); + +/* IRQ bits */ +#define PLL_INT (1 << 10) /* PLL input-clock out-of-range */ +#define FI_INT (1 << 9) /* forced interrupt */ +#define IT_INT (1 << 8) /* timer interrupt */ +#define PCI_INT (1 << 7) /* PCI bus error pending */ +#define URT_INT (1 << 6) /* UART Tx/Rx */ +#define GPI_INT (1 << 5) /* GPI pin */ +#define MIX_INT (1 << 4) /* mixer parameter segment FIFO channels */ +#define DAI_INT (1 << 3) /* DAI (SR-tracker or SPDIF-receiver) */ +#define TP_INT (1 << 2) /* transport priority queue */ +#define DSP_INT (1 << 1) /* DSP */ +#define SRC_INT (1 << 0) /* SRC channels */ + +#endif /* CTHARDWARE_H */ diff --git a/sound/pci/ctxfi/cthw20k1.c b/sound/pci/ctxfi/cthw20k1.c new file mode 100644 index 000000000000..ad3e1d144464 --- /dev/null +++ b/sound/pci/ctxfi/cthw20k1.c @@ -0,0 +1,2297 @@ +/** + * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. + * + * This source file is released under GPL v2 license (no other versions). + * See the COPYING file included in the main directory of this source + * distribution for the license terms and conditions. + * + * @File cthw20k1.c + * + * @Brief + * This file contains the implementation of hardware access methord for 20k1. + * + * @Author Liu Chun + * @Date Jun 24 2008 + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cthw20k1.h" +#include "ct20k1reg.h" + +#if BITS_PER_LONG == 32 +#define CT_XFI_DMA_MASK DMA_BIT_MASK(32) /* 32 bit PTE */ +#else +#define CT_XFI_DMA_MASK DMA_BIT_MASK(64) /* 64 bit PTE */ +#endif + +struct hw20k1 { + struct hw hw; + spinlock_t reg_20k1_lock; + spinlock_t reg_pci_lock; +}; + +static u32 hw_read_20kx(struct hw *hw, u32 reg); +static void hw_write_20kx(struct hw *hw, u32 reg, u32 data); +static u32 hw_read_pci(struct hw *hw, u32 reg); +static void hw_write_pci(struct hw *hw, u32 reg, u32 data); + +/* + * Type definition block. + * The layout of control structures can be directly applied on 20k2 chip. + */ + +/* + * SRC control block definitions. + */ + +/* SRC resource control block */ +#define SRCCTL_STATE 0x00000007 +#define SRCCTL_BM 0x00000008 +#define SRCCTL_RSR 0x00000030 +#define SRCCTL_SF 0x000001C0 +#define SRCCTL_WR 0x00000200 +#define SRCCTL_PM 0x00000400 +#define SRCCTL_ROM 0x00001800 +#define SRCCTL_VO 0x00002000 +#define SRCCTL_ST 0x00004000 +#define SRCCTL_IE 0x00008000 +#define SRCCTL_ILSZ 0x000F0000 +#define SRCCTL_BP 0x00100000 + +#define SRCCCR_CISZ 0x000007FF +#define SRCCCR_CWA 0x001FF800 +#define SRCCCR_D 0x00200000 +#define SRCCCR_RS 0x01C00000 +#define SRCCCR_NAL 0x3E000000 +#define SRCCCR_RA 0xC0000000 + +#define SRCCA_CA 0x03FFFFFF +#define SRCCA_RS 0x1C000000 +#define SRCCA_NAL 0xE0000000 + +#define SRCSA_SA 0x03FFFFFF + +#define SRCLA_LA 0x03FFFFFF + +/* Mixer Parameter Ring ram Low and Hight register. + * Fixed-point value in 8.24 format for parameter channel */ +#define MPRLH_PITCH 0xFFFFFFFF + +/* SRC resource register dirty flags */ +union src_dirty { + struct { + u16 ctl:1; + u16 ccr:1; + u16 sa:1; + u16 la:1; + u16 ca:1; + u16 mpr:1; + u16 czbfs:1; /* Clear Z-Buffers */ + u16 rsv:9; + } bf; + u16 data; +}; + +struct src_rsc_ctrl_blk { + unsigned int ctl; + unsigned int ccr; + unsigned int ca; + unsigned int sa; + unsigned int la; + unsigned int mpr; + union src_dirty dirty; +}; + +/* SRC manager control block */ +union src_mgr_dirty { + struct { + u16 enb0:1; + u16 enb1:1; + u16 enb2:1; + u16 enb3:1; + u16 enb4:1; + u16 enb5:1; + u16 enb6:1; + u16 enb7:1; + u16 enbsa:1; + u16 rsv:7; + } bf; + u16 data; +}; + +struct src_mgr_ctrl_blk { + unsigned int enbsa; + unsigned int enb[8]; + union src_mgr_dirty dirty; +}; + +/* SRCIMP manager control block */ +#define SRCAIM_ARC 0x00000FFF +#define SRCAIM_NXT 0x00FF0000 +#define SRCAIM_SRC 0xFF000000 + +struct srcimap { + unsigned int srcaim; + unsigned int idx; +}; + +/* SRCIMP manager register dirty flags */ +union srcimp_mgr_dirty { + struct { + u16 srcimap:1; + u16 rsv:15; + } bf; + u16 data; +}; + +struct srcimp_mgr_ctrl_blk { + struct srcimap srcimap; + union srcimp_mgr_dirty dirty; +}; + +/* + * Function implementation block. + */ + +static int src_get_rsc_ctrl_blk(void **rblk) +{ + struct src_rsc_ctrl_blk *blk; + + *rblk = NULL; + blk = kzalloc(sizeof(*blk), GFP_KERNEL); + if (NULL == blk) + return -ENOMEM; + + *rblk = blk; + + return 0; +} + +static int src_put_rsc_ctrl_blk(void *blk) +{ + kfree((struct src_rsc_ctrl_blk *)blk); + + return 0; +} + +static int src_set_state(void *blk, unsigned int state) +{ + struct src_rsc_ctrl_blk *ctl = blk; + + set_field(&ctl->ctl, SRCCTL_STATE, state); + ctl->dirty.bf.ctl = 1; + return 0; +} + +static int src_set_bm(void *blk, unsigned int bm) +{ + struct src_rsc_ctrl_blk *ctl = blk; + + set_field(&ctl->ctl, SRCCTL_BM, bm); + ctl->dirty.bf.ctl = 1; + return 0; +} + +static int src_set_rsr(void *blk, unsigned int rsr) +{ + struct src_rsc_ctrl_blk *ctl = blk; + + set_field(&ctl->ctl, SRCCTL_RSR, rsr); + ctl->dirty.bf.ctl = 1; + return 0; +} + +static int src_set_sf(void *blk, unsigned int sf) +{ + struct src_rsc_ctrl_blk *ctl = blk; + + set_field(&ctl->ctl, SRCCTL_SF, sf); + ctl->dirty.bf.ctl = 1; + return 0; +} + +static int src_set_wr(void *blk, unsigned int wr) +{ + struct src_rsc_ctrl_blk *ctl = blk; + + set_field(&ctl->ctl, SRCCTL_WR, wr); + ctl->dirty.bf.ctl = 1; + return 0; +} + +static int src_set_pm(void *blk, unsigned int pm) +{ + struct src_rsc_ctrl_blk *ctl = blk; + + set_field(&ctl->ctl, SRCCTL_PM, pm); + ctl->dirty.bf.ctl = 1; + return 0; +} + +static int src_set_rom(void *blk, unsigned int rom) +{ + struct src_rsc_ctrl_blk *ctl = blk; + + set_field(&ctl->ctl, SRCCTL_ROM, rom); + ctl->dirty.bf.ctl = 1; + return 0; +} + +static int src_set_vo(void *blk, unsigned int vo) +{ + struct src_rsc_ctrl_blk *ctl = blk; + + set_field(&ctl->ctl, SRCCTL_VO, vo); + ctl->dirty.bf.ctl = 1; + return 0; +} + +static int src_set_st(void *blk, unsigned int st) +{ + struct src_rsc_ctrl_blk *ctl = blk; + + set_field(&ctl->ctl, SRCCTL_ST, st); + ctl->dirty.bf.ctl = 1; + return 0; +} + +static int src_set_ie(void *blk, unsigned int ie) +{ + struct src_rsc_ctrl_blk *ctl = blk; + + set_field(&ctl->ctl, SRCCTL_IE, ie); + ctl->dirty.bf.ctl = 1; + return 0; +} + +static int src_set_ilsz(void *blk, unsigned int ilsz) +{ + struct src_rsc_ctrl_blk *ctl = blk; + + set_field(&ctl->ctl, SRCCTL_ILSZ, ilsz); + ctl->dirty.bf.ctl = 1; + return 0; +} + +static int src_set_bp(void *blk, unsigned int bp) +{ + struct src_rsc_ctrl_blk *ctl = blk; + + set_field(&ctl->ctl, SRCCTL_BP, bp); + ctl->dirty.bf.ctl = 1; + return 0; +} + +static int src_set_cisz(void *blk, unsigned int cisz) +{ + struct src_rsc_ctrl_blk *ctl = blk; + + set_field(&ctl->ccr, SRCCCR_CISZ, cisz); + ctl->dirty.bf.ccr = 1; + return 0; +} + +static int src_set_ca(void *blk, unsigned int ca) +{ + struct src_rsc_ctrl_blk *ctl = blk; + + set_field(&ctl->ca, SRCCA_CA, ca); + ctl->dirty.bf.ca = 1; + return 0; +} + +static int src_set_sa(void *blk, unsigned int sa) +{ + struct src_rsc_ctrl_blk *ctl = blk; + + set_field(&ctl->sa, SRCSA_SA, sa); + ctl->dirty.bf.sa = 1; + return 0; +} + +static int src_set_la(void *blk, unsigned int la) +{ + struct src_rsc_ctrl_blk *ctl = blk; + + set_field(&ctl->la, SRCLA_LA, la); + ctl->dirty.bf.la = 1; + return 0; +} + +static int src_set_pitch(void *blk, unsigned int pitch) +{ + struct src_rsc_ctrl_blk *ctl = blk; + + set_field(&ctl->mpr, MPRLH_PITCH, pitch); + ctl->dirty.bf.mpr = 1; + return 0; +} + +static int src_set_clear_zbufs(void *blk, unsigned int clear) +{ + ((struct src_rsc_ctrl_blk *)blk)->dirty.bf.czbfs = (clear ? 1 : 0); + return 0; +} + +static int src_set_dirty(void *blk, unsigned int flags) +{ + ((struct src_rsc_ctrl_blk *)blk)->dirty.data = (flags & 0xffff); + return 0; +} + +static int src_set_dirty_all(void *blk) +{ + ((struct src_rsc_ctrl_blk *)blk)->dirty.data = ~(0x0); + return 0; +} + +#define AR_SLOT_SIZE 4096 +#define AR_SLOT_BLOCK_SIZE 16 +#define AR_PTS_PITCH 6 +#define AR_PARAM_SRC_OFFSET 0x60 + +static unsigned int src_param_pitch_mixer(unsigned int src_idx) +{ + return ((src_idx << 4) + AR_PTS_PITCH + AR_SLOT_SIZE + - AR_PARAM_SRC_OFFSET) % AR_SLOT_SIZE; + +} + +static int src_commit_write(struct hw *hw, unsigned int idx, void *blk) +{ + struct src_rsc_ctrl_blk *ctl = blk; + int i; + + if (ctl->dirty.bf.czbfs) { + /* Clear Z-Buffer registers */ + for (i = 0; i < 8; i++) + hw_write_20kx(hw, SRCUPZ+idx*0x100+i*0x4, 0); + + for (i = 0; i < 4; i++) + hw_write_20kx(hw, SRCDN0Z+idx*0x100+i*0x4, 0); + + for (i = 0; i < 8; i++) + hw_write_20kx(hw, SRCDN1Z+idx*0x100+i*0x4, 0); + + ctl->dirty.bf.czbfs = 0; + } + if (ctl->dirty.bf.mpr) { + /* Take the parameter mixer resource in the same group as that + * the idx src is in for simplicity. Unlike src, all conjugate + * parameter mixer resources must be programmed for + * corresponding conjugate src resources. */ + unsigned int pm_idx = src_param_pitch_mixer(idx); + hw_write_20kx(hw, PRING_LO_HI+4*pm_idx, ctl->mpr); + hw_write_20kx(hw, PMOPLO+8*pm_idx, 0x3); + hw_write_20kx(hw, PMOPHI+8*pm_idx, 0x0); + ctl->dirty.bf.mpr = 0; + } + if (ctl->dirty.bf.sa) { + hw_write_20kx(hw, SRCSA+idx*0x100, ctl->sa); + ctl->dirty.bf.sa = 0; + } + if (ctl->dirty.bf.la) { + hw_write_20kx(hw, SRCLA+idx*0x100, ctl->la); + ctl->dirty.bf.la = 0; + } + if (ctl->dirty.bf.ca) { + hw_write_20kx(hw, SRCCA+idx*0x100, ctl->ca); + ctl->dirty.bf.ca = 0; + } + + /* Write srccf register */ + hw_write_20kx(hw, SRCCF+idx*0x100, 0x0); + + if (ctl->dirty.bf.ccr) { + hw_write_20kx(hw, SRCCCR+idx*0x100, ctl->ccr); + ctl->dirty.bf.ccr = 0; + } + if (ctl->dirty.bf.ctl) { + hw_write_20kx(hw, SRCCTL+idx*0x100, ctl->ctl); + ctl->dirty.bf.ctl = 0; + } + + return 0; +} + +static int src_get_ca(struct hw *hw, unsigned int idx, void *blk) +{ + struct src_rsc_ctrl_blk *ctl = blk; + + ctl->ca = hw_read_20kx(hw, SRCCA+idx*0x100); + ctl->dirty.bf.ca = 0; + + return get_field(ctl->ca, SRCCA_CA); +} + +static unsigned int src_get_dirty(void *blk) +{ + return ((struct src_rsc_ctrl_blk *)blk)->dirty.data; +} + +static unsigned int src_dirty_conj_mask(void) +{ + return 0x20; +} + +static int src_mgr_enbs_src(void *blk, unsigned int idx) +{ + ((struct src_mgr_ctrl_blk *)blk)->enbsa = ~(0x0); + ((struct src_mgr_ctrl_blk *)blk)->dirty.bf.enbsa = 1; + ((struct src_mgr_ctrl_blk *)blk)->enb[idx/32] |= (0x1 << (idx%32)); + return 0; +} + +static int src_mgr_enb_src(void *blk, unsigned int idx) +{ + ((struct src_mgr_ctrl_blk *)blk)->enb[idx/32] |= (0x1 << (idx%32)); + ((struct src_mgr_ctrl_blk *)blk)->dirty.data |= (0x1 << (idx/32)); + return 0; +} + +static int src_mgr_dsb_src(void *blk, unsigned int idx) +{ + ((struct src_mgr_ctrl_blk *)blk)->enb[idx/32] &= ~(0x1 << (idx%32)); + ((struct src_mgr_ctrl_blk *)blk)->dirty.data |= (0x1 << (idx/32)); + return 0; +} + +static int src_mgr_commit_write(struct hw *hw, void *blk) +{ + struct src_mgr_ctrl_blk *ctl = blk; + int i; + unsigned int ret; + + if (ctl->dirty.bf.enbsa) { + do { + ret = hw_read_20kx(hw, SRCENBSTAT); + } while (ret & 0x1); + hw_write_20kx(hw, SRCENBS, ctl->enbsa); + ctl->dirty.bf.enbsa = 0; + } + for (i = 0; i < 8; i++) { + if ((ctl->dirty.data & (0x1 << i))) { + hw_write_20kx(hw, SRCENB+(i*0x100), ctl->enb[i]); + ctl->dirty.data &= ~(0x1 << i); + } + } + + return 0; +} + +static int src_mgr_get_ctrl_blk(void **rblk) +{ + struct src_mgr_ctrl_blk *blk; + + *rblk = NULL; + blk = kzalloc(sizeof(*blk), GFP_KERNEL); + if (NULL == blk) + return -ENOMEM; + + *rblk = blk; + + return 0; +} + +static int src_mgr_put_ctrl_blk(void *blk) +{ + kfree((struct src_mgr_ctrl_blk *)blk); + + return 0; +} + +static int srcimp_mgr_get_ctrl_blk(void **rblk) +{ + struct srcimp_mgr_ctrl_blk *blk; + + *rblk = NULL; + blk = kzalloc(sizeof(*blk), GFP_KERNEL); + if (NULL == blk) + return -ENOMEM; + + *rblk = blk; + + return 0; +} + +static int srcimp_mgr_put_ctrl_blk(void *blk) +{ + kfree((struct srcimp_mgr_ctrl_blk *)blk); + + return 0; +} + +static int srcimp_mgr_set_imaparc(void *blk, unsigned int slot) +{ + struct srcimp_mgr_ctrl_blk *ctl = blk; + + set_field(&ctl->srcimap.srcaim, SRCAIM_ARC, slot); + ctl->dirty.bf.srcimap = 1; + return 0; +} + +static int srcimp_mgr_set_imapuser(void *blk, unsigned int user) +{ + struct srcimp_mgr_ctrl_blk *ctl = blk; + + set_field(&ctl->srcimap.srcaim, SRCAIM_SRC, user); + ctl->dirty.bf.srcimap = 1; + return 0; +} + +static int srcimp_mgr_set_imapnxt(void *blk, unsigned int next) +{ + struct srcimp_mgr_ctrl_blk *ctl = blk; + + set_field(&ctl->srcimap.srcaim, SRCAIM_NXT, next); + ctl->dirty.bf.srcimap = 1; + return 0; +} + +static int srcimp_mgr_set_imapaddr(void *blk, unsigned int addr) +{ + struct srcimp_mgr_ctrl_blk *ctl = blk; + + ctl->srcimap.idx = addr; + ctl->dirty.bf.srcimap = 1; + return 0; +} + +static int srcimp_mgr_commit_write(struct hw *hw, void *blk) +{ + struct srcimp_mgr_ctrl_blk *ctl = blk; + + if (ctl->dirty.bf.srcimap) { + hw_write_20kx(hw, SRCIMAP+ctl->srcimap.idx*0x100, + ctl->srcimap.srcaim); + ctl->dirty.bf.srcimap = 0; + } + + return 0; +} + +/* + * AMIXER control block definitions. + */ + +#define AMOPLO_M 0x00000003 +#define AMOPLO_X 0x0003FFF0 +#define AMOPLO_Y 0xFFFC0000 + +#define AMOPHI_SADR 0x000000FF +#define AMOPHI_SE 0x80000000 + +/* AMIXER resource register dirty flags */ +union amixer_dirty { + struct { + u16 amoplo:1; + u16 amophi:1; + u16 rsv:14; + } bf; + u16 data; +}; + +/* AMIXER resource control block */ +struct amixer_rsc_ctrl_blk { + unsigned int amoplo; + unsigned int amophi; + union amixer_dirty dirty; +}; + +static int amixer_set_mode(void *blk, unsigned int mode) +{ + struct amixer_rsc_ctrl_blk *ctl = blk; + + set_field(&ctl->amoplo, AMOPLO_M, mode); + ctl->dirty.bf.amoplo = 1; + return 0; +} + +static int amixer_set_iv(void *blk, unsigned int iv) +{ + /* 20k1 amixer does not have this field */ + return 0; +} + +static int amixer_set_x(void *blk, unsigned int x) +{ + struct amixer_rsc_ctrl_blk *ctl = blk; + + set_field(&ctl->amoplo, AMOPLO_X, x); + ctl->dirty.bf.amoplo = 1; + return 0; +} + +static int amixer_set_y(void *blk, unsigned int y) +{ + struct amixer_rsc_ctrl_blk *ctl = blk; + + set_field(&ctl->amoplo, AMOPLO_Y, y); + ctl->dirty.bf.amoplo = 1; + return 0; +} + +static int amixer_set_sadr(void *blk, unsigned int sadr) +{ + struct amixer_rsc_ctrl_blk *ctl = blk; + + set_field(&ctl->amophi, AMOPHI_SADR, sadr); + ctl->dirty.bf.amophi = 1; + return 0; +} + +static int amixer_set_se(void *blk, unsigned int se) +{ + struct amixer_rsc_ctrl_blk *ctl = blk; + + set_field(&ctl->amophi, AMOPHI_SE, se); + ctl->dirty.bf.amophi = 1; + return 0; +} + +static int amixer_set_dirty(void *blk, unsigned int flags) +{ + ((struct amixer_rsc_ctrl_blk *)blk)->dirty.data = (flags & 0xffff); + return 0; +} + +static int amixer_set_dirty_all(void *blk) +{ + ((struct amixer_rsc_ctrl_blk *)blk)->dirty.data = ~(0x0); + return 0; +} + +static int amixer_commit_write(struct hw *hw, unsigned int idx, void *blk) +{ + struct amixer_rsc_ctrl_blk *ctl = blk; + + if (ctl->dirty.bf.amoplo || ctl->dirty.bf.amophi) { + hw_write_20kx(hw, AMOPLO+idx*8, ctl->amoplo); + ctl->dirty.bf.amoplo = 0; + hw_write_20kx(hw, AMOPHI+idx*8, ctl->amophi); + ctl->dirty.bf.amophi = 0; + } + + return 0; +} + +static int amixer_get_y(void *blk) +{ + struct amixer_rsc_ctrl_blk *ctl = blk; + + return get_field(ctl->amoplo, AMOPLO_Y); +} + +static unsigned int amixer_get_dirty(void *blk) +{ + return ((struct amixer_rsc_ctrl_blk *)blk)->dirty.data; +} + +static int amixer_rsc_get_ctrl_blk(void **rblk) +{ + struct amixer_rsc_ctrl_blk *blk; + + *rblk = NULL; + blk = kzalloc(sizeof(*blk), GFP_KERNEL); + if (NULL == blk) + return -ENOMEM; + + *rblk = blk; + + return 0; +} + +static int amixer_rsc_put_ctrl_blk(void *blk) +{ + kfree((struct amixer_rsc_ctrl_blk *)blk); + + return 0; +} + +static int amixer_mgr_get_ctrl_blk(void **rblk) +{ + /*amixer_mgr_ctrl_blk_t *blk;*/ + + *rblk = NULL; + /*blk = kzalloc(sizeof(*blk), GFP_KERNEL); + if (NULL == blk) + return -ENOMEM; + + *rblk = blk;*/ + + return 0; +} + +static int amixer_mgr_put_ctrl_blk(void *blk) +{ + /*kfree((amixer_mgr_ctrl_blk_t *)blk);*/ + + return 0; +} + +/* + * DAIO control block definitions. + */ + +/* Receiver Sample Rate Tracker Control register */ +#define SRTCTL_SRCR 0x000000FF +#define SRTCTL_SRCL 0x0000FF00 +#define SRTCTL_RSR 0x00030000 +#define SRTCTL_DRAT 0x000C0000 +#define SRTCTL_RLE 0x10000000 +#define SRTCTL_RLP 0x20000000 +#define SRTCTL_EC 0x40000000 +#define SRTCTL_ET 0x80000000 + +/* DAIO Receiver register dirty flags */ +union dai_dirty { + struct { + u16 srtctl:1; + u16 rsv:15; + } bf; + u16 data; +}; + +/* DAIO Receiver control block */ +struct dai_ctrl_blk { + unsigned int srtctl; + union dai_dirty dirty; +}; + +/* S/PDIF Transmitter register dirty flags */ +union dao_dirty { + struct { + u16 spos:1; + u16 rsv:15; + } bf; + u16 data; +}; + +/* S/PDIF Transmitter control block */ +struct dao_ctrl_blk { + unsigned int spos; /* S/PDIF Output Channel Status Register */ + union dao_dirty dirty; +}; + +/* Audio Input Mapper RAM */ +#define AIM_ARC 0x00000FFF +#define AIM_NXT 0x007F0000 + +struct daoimap { + unsigned int aim; + unsigned int idx; +}; + +/* I2S Transmitter/Receiver Control register */ +#define I2SCTL_EA 0x00000004 +#define I2SCTL_EI 0x00000010 + +/* S/PDIF Transmitter Control register */ +#define SPOCTL_OE 0x00000001 +#define SPOCTL_OS 0x0000000E +#define SPOCTL_RIV 0x00000010 +#define SPOCTL_LIV 0x00000020 +#define SPOCTL_SR 0x000000C0 + +/* S/PDIF Receiver Control register */ +#define SPICTL_EN 0x00000001 +#define SPICTL_I24 0x00000002 +#define SPICTL_IB 0x00000004 +#define SPICTL_SM 0x00000008 +#define SPICTL_VM 0x00000010 + +/* DAIO manager register dirty flags */ +union daio_mgr_dirty { + struct { + u32 i2soctl:4; + u32 i2sictl:4; + u32 spoctl:4; + u32 spictl:4; + u32 daoimap:1; + u32 rsv:15; + } bf; + u32 data; +}; + +/* DAIO manager control block */ +struct daio_mgr_ctrl_blk { + unsigned int i2sctl; + unsigned int spoctl; + unsigned int spictl; + struct daoimap daoimap; + union daio_mgr_dirty dirty; +}; + +static int dai_srt_set_srcr(void *blk, unsigned int src) +{ + struct dai_ctrl_blk *ctl = blk; + + set_field(&ctl->srtctl, SRTCTL_SRCR, src); + ctl->dirty.bf.srtctl = 1; + return 0; +} + +static int dai_srt_set_srcl(void *blk, unsigned int src) +{ + struct dai_ctrl_blk *ctl = blk; + + set_field(&ctl->srtctl, SRTCTL_SRCL, src); + ctl->dirty.bf.srtctl = 1; + return 0; +} + +static int dai_srt_set_rsr(void *blk, unsigned int rsr) +{ + struct dai_ctrl_blk *ctl = blk; + + set_field(&ctl->srtctl, SRTCTL_RSR, rsr); + ctl->dirty.bf.srtctl = 1; + return 0; +} + +static int dai_srt_set_drat(void *blk, unsigned int drat) +{ + struct dai_ctrl_blk *ctl = blk; + + set_field(&ctl->srtctl, SRTCTL_DRAT, drat); + ctl->dirty.bf.srtctl = 1; + return 0; +} + +static int dai_srt_set_ec(void *blk, unsigned int ec) +{ + struct dai_ctrl_blk *ctl = blk; + + set_field(&ctl->srtctl, SRTCTL_EC, ec ? 1 : 0); + ctl->dirty.bf.srtctl = 1; + return 0; +} + +static int dai_srt_set_et(void *blk, unsigned int et) +{ + struct dai_ctrl_blk *ctl = blk; + + set_field(&ctl->srtctl, SRTCTL_ET, et ? 1 : 0); + ctl->dirty.bf.srtctl = 1; + return 0; +} + +static int dai_commit_write(struct hw *hw, unsigned int idx, void *blk) +{ + struct dai_ctrl_blk *ctl = blk; + + if (ctl->dirty.bf.srtctl) { + if (idx < 4) { + /* S/PDIF SRTs */ + hw_write_20kx(hw, SRTSCTL+0x4*idx, ctl->srtctl); + } else { + /* I2S SRT */ + hw_write_20kx(hw, SRTICTL, ctl->srtctl); + } + ctl->dirty.bf.srtctl = 0; + } + + return 0; +} + +static int dai_get_ctrl_blk(void **rblk) +{ + struct dai_ctrl_blk *blk; + + *rblk = NULL; + blk = kzalloc(sizeof(*blk), GFP_KERNEL); + if (NULL == blk) + return -ENOMEM; + + *rblk = blk; + + return 0; +} + +static int dai_put_ctrl_blk(void *blk) +{ + kfree((struct dai_ctrl_blk *)blk); + + return 0; +} + +static int dao_set_spos(void *blk, unsigned int spos) +{ + ((struct dao_ctrl_blk *)blk)->spos = spos; + ((struct dao_ctrl_blk *)blk)->dirty.bf.spos = 1; + return 0; +} + +static int dao_commit_write(struct hw *hw, unsigned int idx, void *blk) +{ + struct dao_ctrl_blk *ctl = blk; + + if (ctl->dirty.bf.spos) { + if (idx < 4) { + /* S/PDIF SPOSx */ + hw_write_20kx(hw, SPOS+0x4*idx, ctl->spos); + } + ctl->dirty.bf.spos = 0; + } + + return 0; +} + +static int dao_get_spos(void *blk, unsigned int *spos) +{ + *spos = ((struct dao_ctrl_blk *)blk)->spos; + return 0; +} + +static int dao_get_ctrl_blk(void **rblk) +{ + struct dao_ctrl_blk *blk; + + *rblk = NULL; + blk = kzalloc(sizeof(*blk), GFP_KERNEL); + if (NULL == blk) + return -ENOMEM; + + *rblk = blk; + + return 0; +} + +static int dao_put_ctrl_blk(void *blk) +{ + kfree((struct dao_ctrl_blk *)blk); + + return 0; +} + +static int daio_mgr_enb_dai(void *blk, unsigned int idx) +{ + struct daio_mgr_ctrl_blk *ctl = blk; + + if (idx < 4) { + /* S/PDIF input */ + set_field(&ctl->spictl, SPICTL_EN << (idx*8), 1); + ctl->dirty.bf.spictl |= (0x1 << idx); + } else { + /* I2S input */ + idx %= 4; + set_field(&ctl->i2sctl, I2SCTL_EI << (idx*8), 1); + ctl->dirty.bf.i2sictl |= (0x1 << idx); + } + return 0; +} + +static int daio_mgr_dsb_dai(void *blk, unsigned int idx) +{ + struct daio_mgr_ctrl_blk *ctl = blk; + + if (idx < 4) { + /* S/PDIF input */ + set_field(&ctl->spictl, SPICTL_EN << (idx*8), 0); + ctl->dirty.bf.spictl |= (0x1 << idx); + } else { + /* I2S input */ + idx %= 4; + set_field(&ctl->i2sctl, I2SCTL_EI << (idx*8), 0); + ctl->dirty.bf.i2sictl |= (0x1 << idx); + } + return 0; +} + +static int daio_mgr_enb_dao(void *blk, unsigned int idx) +{ + struct daio_mgr_ctrl_blk *ctl = blk; + + if (idx < 4) { + /* S/PDIF output */ + set_field(&ctl->spoctl, SPOCTL_OE << (idx*8), 1); + ctl->dirty.bf.spoctl |= (0x1 << idx); + } else { + /* I2S output */ + idx %= 4; + set_field(&ctl->i2sctl, I2SCTL_EA << (idx*8), 1); + ctl->dirty.bf.i2soctl |= (0x1 << idx); + } + return 0; +} + +static int daio_mgr_dsb_dao(void *blk, unsigned int idx) +{ + struct daio_mgr_ctrl_blk *ctl = blk; + + if (idx < 4) { + /* S/PDIF output */ + set_field(&ctl->spoctl, SPOCTL_OE << (idx*8), 0); + ctl->dirty.bf.spoctl |= (0x1 << idx); + } else { + /* I2S output */ + idx %= 4; + set_field(&ctl->i2sctl, I2SCTL_EA << (idx*8), 0); + ctl->dirty.bf.i2soctl |= (0x1 << idx); + } + return 0; +} + +static int daio_mgr_dao_init(void *blk, unsigned int idx, unsigned int conf) +{ + struct daio_mgr_ctrl_blk *ctl = blk; + + if (idx < 4) { + /* S/PDIF output */ + switch ((conf & 0x7)) { + case 0: + set_field(&ctl->spoctl, SPOCTL_SR << (idx*8), 3); + break; /* CDIF */ + case 1: + set_field(&ctl->spoctl, SPOCTL_SR << (idx*8), 0); + break; + case 2: + set_field(&ctl->spoctl, SPOCTL_SR << (idx*8), 1); + break; + case 4: + set_field(&ctl->spoctl, SPOCTL_SR << (idx*8), 2); + break; + default: + break; + } + set_field(&ctl->spoctl, SPOCTL_LIV << (idx*8), + (conf >> 4) & 0x1); /* Non-audio */ + set_field(&ctl->spoctl, SPOCTL_RIV << (idx*8), + (conf >> 4) & 0x1); /* Non-audio */ + set_field(&ctl->spoctl, SPOCTL_OS << (idx*8), + ((conf >> 3) & 0x1) ? 2 : 2); /* Raw */ + + ctl->dirty.bf.spoctl |= (0x1 << idx); + } else { + /* I2S output */ + /*idx %= 4; */ + } + return 0; +} + +static int daio_mgr_set_imaparc(void *blk, unsigned int slot) +{ + struct daio_mgr_ctrl_blk *ctl = blk; + + set_field(&ctl->daoimap.aim, AIM_ARC, slot); + ctl->dirty.bf.daoimap = 1; + return 0; +} + +static int daio_mgr_set_imapnxt(void *blk, unsigned int next) +{ + struct daio_mgr_ctrl_blk *ctl = blk; + + set_field(&ctl->daoimap.aim, AIM_NXT, next); + ctl->dirty.bf.daoimap = 1; + return 0; +} + +static int daio_mgr_set_imapaddr(void *blk, unsigned int addr) +{ + struct daio_mgr_ctrl_blk *ctl = blk; + + ctl->daoimap.idx = addr; + ctl->dirty.bf.daoimap = 1; + return 0; +} + +static int daio_mgr_commit_write(struct hw *hw, void *blk) +{ + struct daio_mgr_ctrl_blk *ctl = blk; + int i; + + if (ctl->dirty.bf.i2sictl || ctl->dirty.bf.i2soctl) { + for (i = 0; i < 4; i++) { + if ((ctl->dirty.bf.i2sictl & (0x1 << i))) + ctl->dirty.bf.i2sictl &= ~(0x1 << i); + + if ((ctl->dirty.bf.i2soctl & (0x1 << i))) + ctl->dirty.bf.i2soctl &= ~(0x1 << i); + } + hw_write_20kx(hw, I2SCTL, ctl->i2sctl); + mdelay(1); + } + if (ctl->dirty.bf.spoctl) { + for (i = 0; i < 4; i++) { + if ((ctl->dirty.bf.spoctl & (0x1 << i))) + ctl->dirty.bf.spoctl &= ~(0x1 << i); + } + hw_write_20kx(hw, SPOCTL, ctl->spoctl); + mdelay(1); + } + if (ctl->dirty.bf.spictl) { + for (i = 0; i < 4; i++) { + if ((ctl->dirty.bf.spictl & (0x1 << i))) + ctl->dirty.bf.spictl &= ~(0x1 << i); + } + hw_write_20kx(hw, SPICTL, ctl->spictl); + mdelay(1); + } + if (ctl->dirty.bf.daoimap) { + hw_write_20kx(hw, DAOIMAP+ctl->daoimap.idx*4, + ctl->daoimap.aim); + ctl->dirty.bf.daoimap = 0; + } + + return 0; +} + +static int daio_mgr_get_ctrl_blk(struct hw *hw, void **rblk) +{ + struct daio_mgr_ctrl_blk *blk; + + *rblk = NULL; + blk = kzalloc(sizeof(*blk), GFP_KERNEL); + if (NULL == blk) + return -ENOMEM; + + blk->i2sctl = hw_read_20kx(hw, I2SCTL); + blk->spoctl = hw_read_20kx(hw, SPOCTL); + blk->spictl = hw_read_20kx(hw, SPICTL); + + *rblk = blk; + + return 0; +} + +static int daio_mgr_put_ctrl_blk(void *blk) +{ + kfree((struct daio_mgr_ctrl_blk *)blk); + + return 0; +} + +/* Timer interrupt */ +static int set_timer_irq(struct hw *hw, int enable) +{ + hw_write_20kx(hw, GIE, enable ? IT_INT : 0); + return 0; +} + +static int set_timer_tick(struct hw *hw, unsigned int ticks) +{ + if (ticks) + ticks |= TIMR_IE | TIMR_IP; + hw_write_20kx(hw, TIMR, ticks); + return 0; +} + +static unsigned int get_wc(struct hw *hw) +{ + return hw_read_20kx(hw, WC); +} + +/* Card hardware initialization block */ +struct dac_conf { + unsigned int msr; /* master sample rate in rsrs */ +}; + +struct adc_conf { + unsigned int msr; /* master sample rate in rsrs */ + unsigned char input; /* the input source of ADC */ + unsigned char mic20db; /* boost mic by 20db if input is microphone */ +}; + +struct daio_conf { + unsigned int msr; /* master sample rate in rsrs */ +}; + +struct trn_conf { + unsigned long vm_pgt_phys; +}; + +static int hw_daio_init(struct hw *hw, const struct daio_conf *info) +{ + u32 i2sorg; + u32 spdorg; + + /* Read I2S CTL. Keep original value. */ + /*i2sorg = hw_read_20kx(hw, I2SCTL);*/ + i2sorg = 0x94040404; /* enable all audio out and I2S-D input */ + /* Program I2S with proper master sample rate and enable + * the correct I2S channel. */ + i2sorg &= 0xfffffffc; + + /* Enable S/PDIF-out-A in fixed 24-bit data + * format and default to 48kHz. */ + /* Disable all before doing any changes. */ + hw_write_20kx(hw, SPOCTL, 0x0); + spdorg = 0x05; + + switch (info->msr) { + case 1: + i2sorg |= 1; + spdorg |= (0x0 << 6); + break; + case 2: + i2sorg |= 2; + spdorg |= (0x1 << 6); + break; + case 4: + i2sorg |= 3; + spdorg |= (0x2 << 6); + break; + default: + i2sorg |= 1; + break; + } + + hw_write_20kx(hw, I2SCTL, i2sorg); + hw_write_20kx(hw, SPOCTL, spdorg); + + /* Enable S/PDIF-in-A in fixed 24-bit data format. */ + /* Disable all before doing any changes. */ + hw_write_20kx(hw, SPICTL, 0x0); + mdelay(1); + spdorg = 0x0a0a0a0a; + hw_write_20kx(hw, SPICTL, spdorg); + mdelay(1); + + return 0; +} + +/* TRANSPORT operations */ +static int hw_trn_init(struct hw *hw, const struct trn_conf *info) +{ + u32 trnctl; + u32 ptp_phys_low, ptp_phys_high; + + /* Set up device page table */ + if ((~0UL) == info->vm_pgt_phys) { + printk(KERN_ERR "Wrong device page table page address!\n"); + return -1; + } + + trnctl = 0x13; /* 32-bit, 4k-size page */ + ptp_phys_low = (u32)info->vm_pgt_phys; + ptp_phys_high = upper_32_bits(info->vm_pgt_phys); + if (sizeof(void *) == 8) /* 64bit address */ + trnctl |= (1 << 2); +#if 0 /* Only 4k h/w pages for simplicitiy */ +#if PAGE_SIZE == 8192 + trnctl |= (1<<5); +#endif +#endif + hw_write_20kx(hw, PTPALX, ptp_phys_low); + hw_write_20kx(hw, PTPAHX, ptp_phys_high); + hw_write_20kx(hw, TRNCTL, trnctl); + hw_write_20kx(hw, TRNIS, 0x200c01); /* realy needed? */ + + return 0; +} + +/* Card initialization */ +#define GCTL_EAC 0x00000001 +#define GCTL_EAI 0x00000002 +#define GCTL_BEP 0x00000004 +#define GCTL_BES 0x00000008 +#define GCTL_DSP 0x00000010 +#define GCTL_DBP 0x00000020 +#define GCTL_ABP 0x00000040 +#define GCTL_TBP 0x00000080 +#define GCTL_SBP 0x00000100 +#define GCTL_FBP 0x00000200 +#define GCTL_XA 0x00000400 +#define GCTL_ET 0x00000800 +#define GCTL_PR 0x00001000 +#define GCTL_MRL 0x00002000 +#define GCTL_SDE 0x00004000 +#define GCTL_SDI 0x00008000 +#define GCTL_SM 0x00010000 +#define GCTL_SR 0x00020000 +#define GCTL_SD 0x00040000 +#define GCTL_SE 0x00080000 +#define GCTL_AID 0x00100000 + +static int hw_pll_init(struct hw *hw, unsigned int rsr) +{ + unsigned int pllctl; + int i; + + pllctl = (48000 == rsr) ? 0x1480a001 : 0x1480a731; + for (i = 0; i < 3; i++) { + if (hw_read_20kx(hw, PLLCTL) == pllctl) + break; + + hw_write_20kx(hw, PLLCTL, pllctl); + mdelay(40); + } + if (i >= 3) { + printk(KERN_ALERT "PLL initialization failed!!!\n"); + return -EBUSY; + } + + return 0; +} + +static int hw_auto_init(struct hw *hw) +{ + unsigned int gctl; + int i; + + gctl = hw_read_20kx(hw, GCTL); + set_field(&gctl, GCTL_EAI, 0); + hw_write_20kx(hw, GCTL, gctl); + set_field(&gctl, GCTL_EAI, 1); + hw_write_20kx(hw, GCTL, gctl); + mdelay(10); + for (i = 0; i < 400000; i++) { + gctl = hw_read_20kx(hw, GCTL); + if (get_field(gctl, GCTL_AID)) + break; + } + if (!get_field(gctl, GCTL_AID)) { + printk(KERN_ALERT "Card Auto-init failed!!!\n"); + return -EBUSY; + } + + return 0; +} + +static int i2c_unlock(struct hw *hw) +{ + if ((hw_read_pci(hw, 0xcc) & 0xff) == 0xaa) + return 0; + + hw_write_pci(hw, 0xcc, 0x8c); + hw_write_pci(hw, 0xcc, 0x0e); + if ((hw_read_pci(hw, 0xcc) & 0xff) == 0xaa) + return 0; + + hw_write_pci(hw, 0xcc, 0xee); + hw_write_pci(hw, 0xcc, 0xaa); + if ((hw_read_pci(hw, 0xcc) & 0xff) == 0xaa) + return 0; + + return -1; +} + +static void i2c_lock(struct hw *hw) +{ + if ((hw_read_pci(hw, 0xcc) & 0xff) == 0xaa) + hw_write_pci(hw, 0xcc, 0x00); +} + +static void i2c_write(struct hw *hw, u32 device, u32 addr, u32 data) +{ + unsigned int ret; + + do { + ret = hw_read_pci(hw, 0xEC); + } while (!(ret & 0x800000)); + hw_write_pci(hw, 0xE0, device); + hw_write_pci(hw, 0xE4, (data << 8) | (addr & 0xff)); +} + +/* DAC operations */ + +static int hw_reset_dac(struct hw *hw) +{ + u32 i; + u16 gpioorg; + unsigned int ret; + + if (i2c_unlock(hw)) + return -1; + + do { + ret = hw_read_pci(hw, 0xEC); + } while (!(ret & 0x800000)); + hw_write_pci(hw, 0xEC, 0x05); /* write to i2c status control */ + + /* To be effective, need to reset the DAC twice. */ + for (i = 0; i < 2; i++) { + /* set gpio */ + mdelay(100); + gpioorg = (u16)hw_read_20kx(hw, GPIO); + gpioorg &= 0xfffd; + hw_write_20kx(hw, GPIO, gpioorg); + mdelay(1); + hw_write_20kx(hw, GPIO, gpioorg | 0x2); + } + + i2c_write(hw, 0x00180080, 0x01, 0x80); + i2c_write(hw, 0x00180080, 0x02, 0x10); + + i2c_lock(hw); + + return 0; +} + +static int hw_dac_init(struct hw *hw, const struct dac_conf *info) +{ + u32 data; + u16 gpioorg; + unsigned int ret; + + if (hw->model == CTSB055X) { + /* SB055x, unmute outputs */ + gpioorg = (u16)hw_read_20kx(hw, GPIO); + gpioorg &= 0xffbf; /* set GPIO6 to low */ + gpioorg |= 2; /* set GPIO1 to high */ + hw_write_20kx(hw, GPIO, gpioorg); + return 0; + } + + /* mute outputs */ + gpioorg = (u16)hw_read_20kx(hw, GPIO); + gpioorg &= 0xffbf; + hw_write_20kx(hw, GPIO, gpioorg); + + hw_reset_dac(hw); + + if (i2c_unlock(hw)) + return -1; + + hw_write_pci(hw, 0xEC, 0x05); /* write to i2c status control */ + do { + ret = hw_read_pci(hw, 0xEC); + } while (!(ret & 0x800000)); + + switch (info->msr) { + case 1: + data = 0x24; + break; + case 2: + data = 0x25; + break; + case 4: + data = 0x26; + break; + default: + data = 0x24; + break; + } + + i2c_write(hw, 0x00180080, 0x06, data); + i2c_write(hw, 0x00180080, 0x09, data); + i2c_write(hw, 0x00180080, 0x0c, data); + i2c_write(hw, 0x00180080, 0x0f, data); + + i2c_lock(hw); + + /* unmute outputs */ + gpioorg = (u16)hw_read_20kx(hw, GPIO); + gpioorg = gpioorg | 0x40; + hw_write_20kx(hw, GPIO, gpioorg); + + return 0; +} + +/* ADC operations */ + +static int is_adc_input_selected_SB055x(struct hw *hw, enum ADCSRC type) +{ + return 0; +} + +static int is_adc_input_selected_SBx(struct hw *hw, enum ADCSRC type) +{ + u32 data; + + data = hw_read_20kx(hw, GPIO); + switch (type) { + case ADC_MICIN: + data = ((data & (0x1<<7)) && (data & (0x1<<8))); + break; + case ADC_LINEIN: + data = (!(data & (0x1<<7)) && (data & (0x1<<8))); + break; + case ADC_NONE: /* Digital I/O */ + data = (!(data & (0x1<<8))); + break; + default: + data = 0; + } + return data; +} + +static int is_adc_input_selected_hendrix(struct hw *hw, enum ADCSRC type) +{ + u32 data; + + data = hw_read_20kx(hw, GPIO); + switch (type) { + case ADC_MICIN: + data = (data & (0x1 << 7)) ? 1 : 0; + break; + case ADC_LINEIN: + data = (data & (0x1 << 7)) ? 0 : 1; + break; + default: + data = 0; + } + return data; +} + +static int hw_is_adc_input_selected(struct hw *hw, enum ADCSRC type) +{ + switch (hw->model) { + case CTSB055X: + return is_adc_input_selected_SB055x(hw, type); + case CTSB073X: + return is_adc_input_selected_hendrix(hw, type); + case CTUAA: + return is_adc_input_selected_hendrix(hw, type); + default: + return is_adc_input_selected_SBx(hw, type); + } +} + +static int +adc_input_select_SB055x(struct hw *hw, enum ADCSRC type, unsigned char boost) +{ + u32 data; + + /* + * check and set the following GPIO bits accordingly + * ADC_Gain = GPIO2 + * DRM_off = GPIO3 + * Mic_Pwr_on = GPIO7 + * Digital_IO_Sel = GPIO8 + * Mic_Sw = GPIO9 + * Aux/MicLine_Sw = GPIO12 + */ + data = hw_read_20kx(hw, GPIO); + data &= 0xec73; + switch (type) { + case ADC_MICIN: + data |= (0x1<<7) | (0x1<<8) | (0x1<<9) ; + data |= boost ? (0x1<<2) : 0; + break; + case ADC_LINEIN: + data |= (0x1<<8); + break; + case ADC_AUX: + data |= (0x1<<8) | (0x1<<12); + break; + case ADC_NONE: + data |= (0x1<<12); /* set to digital */ + break; + default: + return -1; + } + + hw_write_20kx(hw, GPIO, data); + + return 0; +} + + +static int +adc_input_select_SBx(struct hw *hw, enum ADCSRC type, unsigned char boost) +{ + u32 data; + u32 i2c_data; + unsigned int ret; + + if (i2c_unlock(hw)) + return -1; + + do { + ret = hw_read_pci(hw, 0xEC); + } while (!(ret & 0x800000)); /* i2c ready poll */ + /* set i2c access mode as Direct Control */ + hw_write_pci(hw, 0xEC, 0x05); + + data = hw_read_20kx(hw, GPIO); + switch (type) { + case ADC_MICIN: + data |= ((0x1 << 7) | (0x1 << 8)); + i2c_data = 0x1; /* Mic-in */ + break; + case ADC_LINEIN: + data &= ~(0x1 << 7); + data |= (0x1 << 8); + i2c_data = 0x2; /* Line-in */ + break; + case ADC_NONE: + data &= ~(0x1 << 8); + i2c_data = 0x0; /* set to Digital */ + break; + default: + i2c_lock(hw); + return -1; + } + hw_write_20kx(hw, GPIO, data); + i2c_write(hw, 0x001a0080, 0x2a, i2c_data); + if (boost) { + i2c_write(hw, 0x001a0080, 0x1c, 0xe7); /* +12dB boost */ + i2c_write(hw, 0x001a0080, 0x1e, 0xe7); /* +12dB boost */ + } else { + i2c_write(hw, 0x001a0080, 0x1c, 0xcf); /* No boost */ + i2c_write(hw, 0x001a0080, 0x1e, 0xcf); /* No boost */ + } + + i2c_lock(hw); + + return 0; +} + +static int +adc_input_select_hendrix(struct hw *hw, enum ADCSRC type, unsigned char boost) +{ + u32 data; + u32 i2c_data; + unsigned int ret; + + if (i2c_unlock(hw)) + return -1; + + do { + ret = hw_read_pci(hw, 0xEC); + } while (!(ret & 0x800000)); /* i2c ready poll */ + /* set i2c access mode as Direct Control */ + hw_write_pci(hw, 0xEC, 0x05); + + data = hw_read_20kx(hw, GPIO); + switch (type) { + case ADC_MICIN: + data |= (0x1 << 7); + i2c_data = 0x1; /* Mic-in */ + break; + case ADC_LINEIN: + data &= ~(0x1 << 7); + i2c_data = 0x2; /* Line-in */ + break; + default: + i2c_lock(hw); + return -1; + } + hw_write_20kx(hw, GPIO, data); + i2c_write(hw, 0x001a0080, 0x2a, i2c_data); + if (boost) { + i2c_write(hw, 0x001a0080, 0x1c, 0xe7); /* +12dB boost */ + i2c_write(hw, 0x001a0080, 0x1e, 0xe7); /* +12dB boost */ + } else { + i2c_write(hw, 0x001a0080, 0x1c, 0xcf); /* No boost */ + i2c_write(hw, 0x001a0080, 0x1e, 0xcf); /* No boost */ + } + + i2c_lock(hw); + + return 0; +} + +static int hw_adc_input_select(struct hw *hw, enum ADCSRC type) +{ + int state = type == ADC_MICIN; + + switch (hw->model) { + case CTSB055X: + return adc_input_select_SB055x(hw, type, state); + case CTSB073X: + return adc_input_select_hendrix(hw, type, state); + case CTUAA: + return adc_input_select_hendrix(hw, type, state); + default: + return adc_input_select_SBx(hw, type, state); + } +} + +static int adc_init_SB055x(struct hw *hw, int input, int mic20db) +{ + return adc_input_select_SB055x(hw, input, mic20db); +} + +static int adc_init_SBx(struct hw *hw, int input, int mic20db) +{ + u16 gpioorg; + u16 input_source; + u32 adcdata; + unsigned int ret; + + input_source = 0x100; /* default to analog */ + switch (input) { + case ADC_MICIN: + adcdata = 0x1; + input_source = 0x180; /* set GPIO7 to select Mic */ + break; + case ADC_LINEIN: + adcdata = 0x2; + break; + case ADC_VIDEO: + adcdata = 0x4; + break; + case ADC_AUX: + adcdata = 0x8; + break; + case ADC_NONE: + adcdata = 0x0; + input_source = 0x0; /* set to Digital */ + break; + default: + adcdata = 0x0; + break; + } + + if (i2c_unlock(hw)) + return -1; + + do { + ret = hw_read_pci(hw, 0xEC); + } while (!(ret & 0x800000)); /* i2c ready poll */ + hw_write_pci(hw, 0xEC, 0x05); /* write to i2c status control */ + + i2c_write(hw, 0x001a0080, 0x0e, 0x08); + i2c_write(hw, 0x001a0080, 0x18, 0x0a); + i2c_write(hw, 0x001a0080, 0x28, 0x86); + i2c_write(hw, 0x001a0080, 0x2a, adcdata); + + if (mic20db) { + i2c_write(hw, 0x001a0080, 0x1c, 0xf7); + i2c_write(hw, 0x001a0080, 0x1e, 0xf7); + } else { + i2c_write(hw, 0x001a0080, 0x1c, 0xcf); + i2c_write(hw, 0x001a0080, 0x1e, 0xcf); + } + + if (!(hw_read_20kx(hw, ID0) & 0x100)) + i2c_write(hw, 0x001a0080, 0x16, 0x26); + + i2c_lock(hw); + + gpioorg = (u16)hw_read_20kx(hw, GPIO); + gpioorg &= 0xfe7f; + gpioorg |= input_source; + hw_write_20kx(hw, GPIO, gpioorg); + + return 0; +} + +static int hw_adc_init(struct hw *hw, const struct adc_conf *info) +{ + if (hw->model == CTSB055X) + return adc_init_SB055x(hw, info->input, info->mic20db); + else + return adc_init_SBx(hw, info->input, info->mic20db); +} + +static int hw_have_digit_io_switch(struct hw *hw) +{ + /* SB073x and Vista compatible cards have no digit IO switch */ + return !(hw->model == CTSB073X || hw->model == CTUAA); +} + +#define CTLBITS(a, b, c, d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d)) + +#define UAA_CFG_PWRSTATUS 0x44 +#define UAA_CFG_SPACE_FLAG 0xA0 +#define UAA_CORE_CHANGE 0x3FFC +static int uaa_to_xfi(struct pci_dev *pci) +{ + unsigned int bar0, bar1, bar2, bar3, bar4, bar5; + unsigned int cmd, irq, cl_size, l_timer, pwr; + unsigned int is_uaa; + unsigned int data[4] = {0}; + unsigned int io_base; + void *mem_base; + int i; + const u32 CTLX = CTLBITS('C', 'T', 'L', 'X'); + const u32 CTL_ = CTLBITS('C', 'T', 'L', '-'); + const u32 CTLF = CTLBITS('C', 'T', 'L', 'F'); + const u32 CTLi = CTLBITS('C', 'T', 'L', 'i'); + const u32 CTLA = CTLBITS('C', 'T', 'L', 'A'); + const u32 CTLZ = CTLBITS('C', 'T', 'L', 'Z'); + const u32 CTLL = CTLBITS('C', 'T', 'L', 'L'); + + /* By default, Hendrix card UAA Bar0 should be using memory... */ + io_base = pci_resource_start(pci, 0); + mem_base = ioremap(io_base, pci_resource_len(pci, 0)); + if (NULL == mem_base) + return -ENOENT; + + /* Read current mode from Mode Change Register */ + for (i = 0; i < 4; i++) + data[i] = readl(mem_base + UAA_CORE_CHANGE); + + /* Determine current mode... */ + if (data[0] == CTLA) { + is_uaa = ((data[1] == CTLZ && data[2] == CTLL + && data[3] == CTLA) || (data[1] == CTLA + && data[2] == CTLZ && data[3] == CTLL)); + } else if (data[0] == CTLZ) { + is_uaa = (data[1] == CTLL + && data[2] == CTLA && data[3] == CTLA); + } else if (data[0] == CTLL) { + is_uaa = (data[1] == CTLA + && data[2] == CTLA && data[3] == CTLZ); + } else { + is_uaa = 0; + } + + if (!is_uaa) { + /* Not in UAA mode currently. Return directly. */ + iounmap(mem_base); + return 0; + } + + pci_read_config_dword(pci, PCI_BASE_ADDRESS_0, &bar0); + pci_read_config_dword(pci, PCI_BASE_ADDRESS_1, &bar1); + pci_read_config_dword(pci, PCI_BASE_ADDRESS_2, &bar2); + pci_read_config_dword(pci, PCI_BASE_ADDRESS_3, &bar3); + pci_read_config_dword(pci, PCI_BASE_ADDRESS_4, &bar4); + pci_read_config_dword(pci, PCI_BASE_ADDRESS_5, &bar5); + pci_read_config_dword(pci, PCI_INTERRUPT_LINE, &irq); + pci_read_config_dword(pci, PCI_CACHE_LINE_SIZE, &cl_size); + pci_read_config_dword(pci, PCI_LATENCY_TIMER, &l_timer); + pci_read_config_dword(pci, UAA_CFG_PWRSTATUS, &pwr); + pci_read_config_dword(pci, PCI_COMMAND, &cmd); + + /* Set up X-Fi core PCI configuration space. */ + /* Switch to X-Fi config space with BAR0 exposed. */ + pci_write_config_dword(pci, UAA_CFG_SPACE_FLAG, 0x87654321); + /* Copy UAA's BAR5 into X-Fi BAR0 */ + pci_write_config_dword(pci, PCI_BASE_ADDRESS_0, bar5); + /* Switch to X-Fi config space without BAR0 exposed. */ + pci_write_config_dword(pci, UAA_CFG_SPACE_FLAG, 0x12345678); + pci_write_config_dword(pci, PCI_BASE_ADDRESS_1, bar1); + pci_write_config_dword(pci, PCI_BASE_ADDRESS_2, bar2); + pci_write_config_dword(pci, PCI_BASE_ADDRESS_3, bar3); + pci_write_config_dword(pci, PCI_BASE_ADDRESS_4, bar4); + pci_write_config_dword(pci, PCI_INTERRUPT_LINE, irq); + pci_write_config_dword(pci, PCI_CACHE_LINE_SIZE, cl_size); + pci_write_config_dword(pci, PCI_LATENCY_TIMER, l_timer); + pci_write_config_dword(pci, UAA_CFG_PWRSTATUS, pwr); + pci_write_config_dword(pci, PCI_COMMAND, cmd); + + /* Switch to X-Fi mode */ + writel(CTLX, (mem_base + UAA_CORE_CHANGE)); + writel(CTL_, (mem_base + UAA_CORE_CHANGE)); + writel(CTLF, (mem_base + UAA_CORE_CHANGE)); + writel(CTLi, (mem_base + UAA_CORE_CHANGE)); + + iounmap(mem_base); + + return 0; +} + +static irqreturn_t ct_20k1_interrupt(int irq, void *dev_id) +{ + struct hw *hw = dev_id; + unsigned int status; + + status = hw_read_20kx(hw, GIP); + if (!status) + return IRQ_NONE; + + if (hw->irq_callback) + hw->irq_callback(hw->irq_callback_data, status); + + hw_write_20kx(hw, GIP, status); + return IRQ_HANDLED; +} + +static int hw_card_start(struct hw *hw) +{ + int err; + struct pci_dev *pci = hw->pci; + + err = pci_enable_device(pci); + if (err < 0) + return err; + + /* Set DMA transfer mask */ + if (pci_set_dma_mask(pci, CT_XFI_DMA_MASK) < 0 || + pci_set_consistent_dma_mask(pci, CT_XFI_DMA_MASK) < 0) { + printk(KERN_ERR "architecture does not support PCI " + "busmaster DMA with mask 0x%llx\n", + CT_XFI_DMA_MASK); + err = -ENXIO; + goto error1; + } + + if (!hw->io_base) { + err = pci_request_regions(pci, "XFi"); + if (err < 0) + goto error1; + + if (hw->model == CTUAA) + hw->io_base = pci_resource_start(pci, 5); + else + hw->io_base = pci_resource_start(pci, 0); + + } + + /* Switch to X-Fi mode from UAA mode if neeeded */ + if (hw->model == CTUAA) { + err = uaa_to_xfi(pci); + if (err) + goto error2; + + } + + if (hw->irq < 0) { + err = request_irq(pci->irq, ct_20k1_interrupt, IRQF_SHARED, + "ctxfi", hw); + if (err < 0) { + printk(KERN_ERR "XFi: Cannot get irq %d\n", pci->irq); + goto error2; + } + hw->irq = pci->irq; + } + + pci_set_master(pci); + + return 0; + +error2: + pci_release_regions(pci); + hw->io_base = 0; +error1: + pci_disable_device(pci); + return err; +} + +static int hw_card_stop(struct hw *hw) +{ + unsigned int data; + + /* disable transport bus master and queueing of request */ + hw_write_20kx(hw, TRNCTL, 0x00); + + /* disable pll */ + data = hw_read_20kx(hw, PLLCTL); + hw_write_20kx(hw, PLLCTL, (data & (~(0x0F<<12)))); + + /* TODO: Disable interrupt and so on... */ + if (hw->irq >= 0) + synchronize_irq(hw->irq); + return 0; +} + +static int hw_card_shutdown(struct hw *hw) +{ + if (hw->irq >= 0) + free_irq(hw->irq, hw); + + hw->irq = -1; + + if (NULL != ((void *)hw->mem_base)) + iounmap((void *)hw->mem_base); + + hw->mem_base = (unsigned long)NULL; + + if (hw->io_base) + pci_release_regions(hw->pci); + + hw->io_base = 0; + + pci_disable_device(hw->pci); + + return 0; +} + +static int hw_card_init(struct hw *hw, struct card_conf *info) +{ + int err; + unsigned int gctl; + u32 data; + struct dac_conf dac_info = {0}; + struct adc_conf adc_info = {0}; + struct daio_conf daio_info = {0}; + struct trn_conf trn_info = {0}; + + /* Get PCI io port base address and do Hendrix switch if needed. */ + err = hw_card_start(hw); + if (err) + return err; + + /* PLL init */ + err = hw_pll_init(hw, info->rsr); + if (err < 0) + return err; + + /* kick off auto-init */ + err = hw_auto_init(hw); + if (err < 0) + return err; + + /* Enable audio ring */ + gctl = hw_read_20kx(hw, GCTL); + set_field(&gctl, GCTL_EAC, 1); + set_field(&gctl, GCTL_DBP, 1); + set_field(&gctl, GCTL_TBP, 1); + set_field(&gctl, GCTL_FBP, 1); + set_field(&gctl, GCTL_ET, 1); + hw_write_20kx(hw, GCTL, gctl); + mdelay(10); + + /* Reset all global pending interrupts */ + hw_write_20kx(hw, GIE, 0); + /* Reset all SRC pending interrupts */ + hw_write_20kx(hw, SRCIP, 0); + mdelay(30); + + /* Detect the card ID and configure GPIO accordingly. */ + switch (hw->model) { + case CTSB055X: + hw_write_20kx(hw, GPIOCTL, 0x13fe); + break; + case CTSB073X: + hw_write_20kx(hw, GPIOCTL, 0x00e6); + break; + case CTUAA: + hw_write_20kx(hw, GPIOCTL, 0x00c2); + break; + default: + hw_write_20kx(hw, GPIOCTL, 0x01e6); + break; + } + + trn_info.vm_pgt_phys = info->vm_pgt_phys; + err = hw_trn_init(hw, &trn_info); + if (err < 0) + return err; + + daio_info.msr = info->msr; + err = hw_daio_init(hw, &daio_info); + if (err < 0) + return err; + + dac_info.msr = info->msr; + err = hw_dac_init(hw, &dac_info); + if (err < 0) + return err; + + adc_info.msr = info->msr; + adc_info.input = ADC_LINEIN; + adc_info.mic20db = 0; + err = hw_adc_init(hw, &adc_info); + if (err < 0) + return err; + + data = hw_read_20kx(hw, SRCMCTL); + data |= 0x1; /* Enables input from the audio ring */ + hw_write_20kx(hw, SRCMCTL, data); + + return 0; +} + +#ifdef CONFIG_PM +static int hw_suspend(struct hw *hw, pm_message_t state) +{ + struct pci_dev *pci = hw->pci; + + hw_card_stop(hw); + + if (hw->model == CTUAA) { + /* Switch to UAA config space. */ + pci_write_config_dword(pci, UAA_CFG_SPACE_FLAG, 0x0); + } + + pci_disable_device(pci); + pci_save_state(pci); + pci_set_power_state(pci, pci_choose_state(pci, state)); + + return 0; +} + +static int hw_resume(struct hw *hw, struct card_conf *info) +{ + struct pci_dev *pci = hw->pci; + + pci_set_power_state(pci, PCI_D0); + pci_restore_state(pci); + + /* Re-initialize card hardware. */ + return hw_card_init(hw, info); +} +#endif + +static u32 hw_read_20kx(struct hw *hw, u32 reg) +{ + u32 value; + unsigned long flags; + + spin_lock_irqsave( + &container_of(hw, struct hw20k1, hw)->reg_20k1_lock, flags); + outl(reg, hw->io_base + 0x0); + value = inl(hw->io_base + 0x4); + spin_unlock_irqrestore( + &container_of(hw, struct hw20k1, hw)->reg_20k1_lock, flags); + + return value; +} + +static void hw_write_20kx(struct hw *hw, u32 reg, u32 data) +{ + unsigned long flags; + + spin_lock_irqsave( + &container_of(hw, struct hw20k1, hw)->reg_20k1_lock, flags); + outl(reg, hw->io_base + 0x0); + outl(data, hw->io_base + 0x4); + spin_unlock_irqrestore( + &container_of(hw, struct hw20k1, hw)->reg_20k1_lock, flags); + +} + +static u32 hw_read_pci(struct hw *hw, u32 reg) +{ + u32 value; + unsigned long flags; + + spin_lock_irqsave( + &container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags); + outl(reg, hw->io_base + 0x10); + value = inl(hw->io_base + 0x14); + spin_unlock_irqrestore( + &container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags); + + return value; +} + +static void hw_write_pci(struct hw *hw, u32 reg, u32 data) +{ + unsigned long flags; + + spin_lock_irqsave( + &container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags); + outl(reg, hw->io_base + 0x10); + outl(data, hw->io_base + 0x14); + spin_unlock_irqrestore( + &container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags); +} + +static struct hw ct20k1_preset __devinitdata = { + .irq = -1, + + .card_init = hw_card_init, + .card_stop = hw_card_stop, + .pll_init = hw_pll_init, + .is_adc_source_selected = hw_is_adc_input_selected, + .select_adc_source = hw_adc_input_select, + .have_digit_io_switch = hw_have_digit_io_switch, +#ifdef CONFIG_PM + .suspend = hw_suspend, + .resume = hw_resume, +#endif + + .src_rsc_get_ctrl_blk = src_get_rsc_ctrl_blk, + .src_rsc_put_ctrl_blk = src_put_rsc_ctrl_blk, + .src_mgr_get_ctrl_blk = src_mgr_get_ctrl_blk, + .src_mgr_put_ctrl_blk = src_mgr_put_ctrl_blk, + .src_set_state = src_set_state, + .src_set_bm = src_set_bm, + .src_set_rsr = src_set_rsr, + .src_set_sf = src_set_sf, + .src_set_wr = src_set_wr, + .src_set_pm = src_set_pm, + .src_set_rom = src_set_rom, + .src_set_vo = src_set_vo, + .src_set_st = src_set_st, + .src_set_ie = src_set_ie, + .src_set_ilsz = src_set_ilsz, + .src_set_bp = src_set_bp, + .src_set_cisz = src_set_cisz, + .src_set_ca = src_set_ca, + .src_set_sa = src_set_sa, + .src_set_la = src_set_la, + .src_set_pitch = src_set_pitch, + .src_set_dirty = src_set_dirty, + .src_set_clear_zbufs = src_set_clear_zbufs, + .src_set_dirty_all = src_set_dirty_all, + .src_commit_write = src_commit_write, + .src_get_ca = src_get_ca, + .src_get_dirty = src_get_dirty, + .src_dirty_conj_mask = src_dirty_conj_mask, + .src_mgr_enbs_src = src_mgr_enbs_src, + .src_mgr_enb_src = src_mgr_enb_src, + .src_mgr_dsb_src = src_mgr_dsb_src, + .src_mgr_commit_write = src_mgr_commit_write, + + .srcimp_mgr_get_ctrl_blk = srcimp_mgr_get_ctrl_blk, + .srcimp_mgr_put_ctrl_blk = srcimp_mgr_put_ctrl_blk, + .srcimp_mgr_set_imaparc = srcimp_mgr_set_imaparc, + .srcimp_mgr_set_imapuser = srcimp_mgr_set_imapuser, + .srcimp_mgr_set_imapnxt = srcimp_mgr_set_imapnxt, + .srcimp_mgr_set_imapaddr = srcimp_mgr_set_imapaddr, + .srcimp_mgr_commit_write = srcimp_mgr_commit_write, + + .amixer_rsc_get_ctrl_blk = amixer_rsc_get_ctrl_blk, + .amixer_rsc_put_ctrl_blk = amixer_rsc_put_ctrl_blk, + .amixer_mgr_get_ctrl_blk = amixer_mgr_get_ctrl_blk, + .amixer_mgr_put_ctrl_blk = amixer_mgr_put_ctrl_blk, + .amixer_set_mode = amixer_set_mode, + .amixer_set_iv = amixer_set_iv, + .amixer_set_x = amixer_set_x, + .amixer_set_y = amixer_set_y, + .amixer_set_sadr = amixer_set_sadr, + .amixer_set_se = amixer_set_se, + .amixer_set_dirty = amixer_set_dirty, + .amixer_set_dirty_all = amixer_set_dirty_all, + .amixer_commit_write = amixer_commit_write, + .amixer_get_y = amixer_get_y, + .amixer_get_dirty = amixer_get_dirty, + + .dai_get_ctrl_blk = dai_get_ctrl_blk, + .dai_put_ctrl_blk = dai_put_ctrl_blk, + .dai_srt_set_srco = dai_srt_set_srcr, + .dai_srt_set_srcm = dai_srt_set_srcl, + .dai_srt_set_rsr = dai_srt_set_rsr, + .dai_srt_set_drat = dai_srt_set_drat, + .dai_srt_set_ec = dai_srt_set_ec, + .dai_srt_set_et = dai_srt_set_et, + .dai_commit_write = dai_commit_write, + + .dao_get_ctrl_blk = dao_get_ctrl_blk, + .dao_put_ctrl_blk = dao_put_ctrl_blk, + .dao_set_spos = dao_set_spos, + .dao_commit_write = dao_commit_write, + .dao_get_spos = dao_get_spos, + + .daio_mgr_get_ctrl_blk = daio_mgr_get_ctrl_blk, + .daio_mgr_put_ctrl_blk = daio_mgr_put_ctrl_blk, + .daio_mgr_enb_dai = daio_mgr_enb_dai, + .daio_mgr_dsb_dai = daio_mgr_dsb_dai, + .daio_mgr_enb_dao = daio_mgr_enb_dao, + .daio_mgr_dsb_dao = daio_mgr_dsb_dao, + .daio_mgr_dao_init = daio_mgr_dao_init, + .daio_mgr_set_imaparc = daio_mgr_set_imaparc, + .daio_mgr_set_imapnxt = daio_mgr_set_imapnxt, + .daio_mgr_set_imapaddr = daio_mgr_set_imapaddr, + .daio_mgr_commit_write = daio_mgr_commit_write, + + .set_timer_irq = set_timer_irq, + .set_timer_tick = set_timer_tick, + .get_wc = get_wc, +}; + +int __devinit create_20k1_hw_obj(struct hw **rhw) +{ + struct hw20k1 *hw20k1; + + *rhw = NULL; + hw20k1 = kzalloc(sizeof(*hw20k1), GFP_KERNEL); + if (NULL == hw20k1) + return -ENOMEM; + + spin_lock_init(&hw20k1->reg_20k1_lock); + spin_lock_init(&hw20k1->reg_pci_lock); + + hw20k1->hw = ct20k1_preset; + + *rhw = &hw20k1->hw; + + return 0; +} + +int destroy_20k1_hw_obj(struct hw *hw) +{ + if (hw->io_base) + hw_card_shutdown(hw); + + kfree(container_of(hw, struct hw20k1, hw)); + return 0; +} diff --git a/sound/pci/ctxfi/cthw20k1.h b/sound/pci/ctxfi/cthw20k1.h new file mode 100644 index 000000000000..02f72fb448a6 --- /dev/null +++ b/sound/pci/ctxfi/cthw20k1.h @@ -0,0 +1,26 @@ +/** + * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. + * + * This source file is released under GPL v2 license (no other versions). + * See the COPYING file included in the main directory of this source + * distribution for the license terms and conditions. + * + * @File cthw20k1.h + * + * @Brief + * This file contains the definition of hardware access methord. + * + * @Author Liu Chun + * @Date May 13 2008 + * + */ + +#ifndef CTHW20K1_H +#define CTHW20K1_H + +#include "cthardware.h" + +int create_20k1_hw_obj(struct hw **rhw); +int destroy_20k1_hw_obj(struct hw *hw); + +#endif /* CTHW20K1_H */ diff --git a/sound/pci/ctxfi/cthw20k2.c b/sound/pci/ctxfi/cthw20k2.c new file mode 100644 index 000000000000..dec46d04b041 --- /dev/null +++ b/sound/pci/ctxfi/cthw20k2.c @@ -0,0 +1,2176 @@ +/** + * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. + * + * This source file is released under GPL v2 license (no other versions). + * See the COPYING file included in the main directory of this source + * distribution for the license terms and conditions. + * + * @File cthw20k2.c + * + * @Brief + * This file contains the implementation of hardware access methord for 20k2. + * + * @Author Liu Chun + * @Date May 14 2008 + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "cthw20k2.h" +#include "ct20k2reg.h" + +#if BITS_PER_LONG == 32 +#define CT_XFI_DMA_MASK DMA_BIT_MASK(32) /* 32 bit PTE */ +#else +#define CT_XFI_DMA_MASK DMA_BIT_MASK(64) /* 64 bit PTE */ +#endif + +struct hw20k2 { + struct hw hw; + /* for i2c */ + unsigned char dev_id; + unsigned char addr_size; + unsigned char data_size; +}; + +static u32 hw_read_20kx(struct hw *hw, u32 reg); +static void hw_write_20kx(struct hw *hw, u32 reg, u32 data); + +/* + * Type definition block. + * The layout of control structures can be directly applied on 20k2 chip. + */ + +/* + * SRC control block definitions. + */ + +/* SRC resource control block */ +#define SRCCTL_STATE 0x00000007 +#define SRCCTL_BM 0x00000008 +#define SRCCTL_RSR 0x00000030 +#define SRCCTL_SF 0x000001C0 +#define SRCCTL_WR 0x00000200 +#define SRCCTL_PM 0x00000400 +#define SRCCTL_ROM 0x00001800 +#define SRCCTL_VO 0x00002000 +#define SRCCTL_ST 0x00004000 +#define SRCCTL_IE 0x00008000 +#define SRCCTL_ILSZ 0x000F0000 +#define SRCCTL_BP 0x00100000 + +#define SRCCCR_CISZ 0x000007FF +#define SRCCCR_CWA 0x001FF800 +#define SRCCCR_D 0x00200000 +#define SRCCCR_RS 0x01C00000 +#define SRCCCR_NAL 0x3E000000 +#define SRCCCR_RA 0xC0000000 + +#define SRCCA_CA 0x0FFFFFFF +#define SRCCA_RS 0xE0000000 + +#define SRCSA_SA 0x0FFFFFFF + +#define SRCLA_LA 0x0FFFFFFF + +/* Mixer Parameter Ring ram Low and Hight register. + * Fixed-point value in 8.24 format for parameter channel */ +#define MPRLH_PITCH 0xFFFFFFFF + +/* SRC resource register dirty flags */ +union src_dirty { + struct { + u16 ctl:1; + u16 ccr:1; + u16 sa:1; + u16 la:1; + u16 ca:1; + u16 mpr:1; + u16 czbfs:1; /* Clear Z-Buffers */ + u16 rsv:9; + } bf; + u16 data; +}; + +struct src_rsc_ctrl_blk { + unsigned int ctl; + unsigned int ccr; + unsigned int ca; + unsigned int sa; + unsigned int la; + unsigned int mpr; + union src_dirty dirty; +}; + +/* SRC manager control block */ +union src_mgr_dirty { + struct { + u16 enb0:1; + u16 enb1:1; + u16 enb2:1; + u16 enb3:1; + u16 enb4:1; + u16 enb5:1; + u16 enb6:1; + u16 enb7:1; + u16 enbsa:1; + u16 rsv:7; + } bf; + u16 data; +}; + +struct src_mgr_ctrl_blk { + unsigned int enbsa; + unsigned int enb[8]; + union src_mgr_dirty dirty; +}; + +/* SRCIMP manager control block */ +#define SRCAIM_ARC 0x00000FFF +#define SRCAIM_NXT 0x00FF0000 +#define SRCAIM_SRC 0xFF000000 + +struct srcimap { + unsigned int srcaim; + unsigned int idx; +}; + +/* SRCIMP manager register dirty flags */ +union srcimp_mgr_dirty { + struct { + u16 srcimap:1; + u16 rsv:15; + } bf; + u16 data; +}; + +struct srcimp_mgr_ctrl_blk { + struct srcimap srcimap; + union srcimp_mgr_dirty dirty; +}; + +/* + * Function implementation block. + */ + +static int src_get_rsc_ctrl_blk(void **rblk) +{ + struct src_rsc_ctrl_blk *blk; + + *rblk = NULL; + blk = kzalloc(sizeof(*blk), GFP_KERNEL); + if (NULL == blk) + return -ENOMEM; + + *rblk = blk; + + return 0; +} + +static int src_put_rsc_ctrl_blk(void *blk) +{ + kfree(blk); + + return 0; +} + +static int src_set_state(void *blk, unsigned int state) +{ + struct src_rsc_ctrl_blk *ctl = blk; + + set_field(&ctl->ctl, SRCCTL_STATE, state); + ctl->dirty.bf.ctl = 1; + return 0; +} + +static int src_set_bm(void *blk, unsigned int bm) +{ + struct src_rsc_ctrl_blk *ctl = blk; + + set_field(&ctl->ctl, SRCCTL_BM, bm); + ctl->dirty.bf.ctl = 1; + return 0; +} + +static int src_set_rsr(void *blk, unsigned int rsr) +{ + struct src_rsc_ctrl_blk *ctl = blk; + + set_field(&ctl->ctl, SRCCTL_RSR, rsr); + ctl->dirty.bf.ctl = 1; + return 0; +} + +static int src_set_sf(void *blk, unsigned int sf) +{ + struct src_rsc_ctrl_blk *ctl = blk; + + set_field(&ctl->ctl, SRCCTL_SF, sf); + ctl->dirty.bf.ctl = 1; + return 0; +} + +static int src_set_wr(void *blk, unsigned int wr) +{ + struct src_rsc_ctrl_blk *ctl = blk; + + set_field(&ctl->ctl, SRCCTL_WR, wr); + ctl->dirty.bf.ctl = 1; + return 0; +} + +static int src_set_pm(void *blk, unsigned int pm) +{ + struct src_rsc_ctrl_blk *ctl = blk; + + set_field(&ctl->ctl, SRCCTL_PM, pm); + ctl->dirty.bf.ctl = 1; + return 0; +} + +static int src_set_rom(void *blk, unsigned int rom) +{ + struct src_rsc_ctrl_blk *ctl = blk; + + set_field(&ctl->ctl, SRCCTL_ROM, rom); + ctl->dirty.bf.ctl = 1; + return 0; +} + +static int src_set_vo(void *blk, unsigned int vo) +{ + struct src_rsc_ctrl_blk *ctl = blk; + + set_field(&ctl->ctl, SRCCTL_VO, vo); + ctl->dirty.bf.ctl = 1; + return 0; +} + +static int src_set_st(void *blk, unsigned int st) +{ + struct src_rsc_ctrl_blk *ctl = blk; + + set_field(&ctl->ctl, SRCCTL_ST, st); + ctl->dirty.bf.ctl = 1; + return 0; +} + +static int src_set_ie(void *blk, unsigned int ie) +{ + struct src_rsc_ctrl_blk *ctl = blk; + + set_field(&ctl->ctl, SRCCTL_IE, ie); + ctl->dirty.bf.ctl = 1; + return 0; +} + +static int src_set_ilsz(void *blk, unsigned int ilsz) +{ + struct src_rsc_ctrl_blk *ctl = blk; + + set_field(&ctl->ctl, SRCCTL_ILSZ, ilsz); + ctl->dirty.bf.ctl = 1; + return 0; +} + +static int src_set_bp(void *blk, unsigned int bp) +{ + struct src_rsc_ctrl_blk *ctl = blk; + + set_field(&ctl->ctl, SRCCTL_BP, bp); + ctl->dirty.bf.ctl = 1; + return 0; +} + +static int src_set_cisz(void *blk, unsigned int cisz) +{ + struct src_rsc_ctrl_blk *ctl = blk; + + set_field(&ctl->ccr, SRCCCR_CISZ, cisz); + ctl->dirty.bf.ccr = 1; + return 0; +} + +static int src_set_ca(void *blk, unsigned int ca) +{ + struct src_rsc_ctrl_blk *ctl = blk; + + set_field(&ctl->ca, SRCCA_CA, ca); + ctl->dirty.bf.ca = 1; + return 0; +} + +static int src_set_sa(void *blk, unsigned int sa) +{ + struct src_rsc_ctrl_blk *ctl = blk; + + set_field(&ctl->sa, SRCSA_SA, sa); + ctl->dirty.bf.sa = 1; + return 0; +} + +static int src_set_la(void *blk, unsigned int la) +{ + struct src_rsc_ctrl_blk *ctl = blk; + + set_field(&ctl->la, SRCLA_LA, la); + ctl->dirty.bf.la = 1; + return 0; +} + +static int src_set_pitch(void *blk, unsigned int pitch) +{ + struct src_rsc_ctrl_blk *ctl = blk; + + set_field(&ctl->mpr, MPRLH_PITCH, pitch); + ctl->dirty.bf.mpr = 1; + return 0; +} + +static int src_set_clear_zbufs(void *blk, unsigned int clear) +{ + ((struct src_rsc_ctrl_blk *)blk)->dirty.bf.czbfs = (clear ? 1 : 0); + return 0; +} + +static int src_set_dirty(void *blk, unsigned int flags) +{ + ((struct src_rsc_ctrl_blk *)blk)->dirty.data = (flags & 0xffff); + return 0; +} + +static int src_set_dirty_all(void *blk) +{ + ((struct src_rsc_ctrl_blk *)blk)->dirty.data = ~(0x0); + return 0; +} + +#define AR_SLOT_SIZE 4096 +#define AR_SLOT_BLOCK_SIZE 16 +#define AR_PTS_PITCH 6 +#define AR_PARAM_SRC_OFFSET 0x60 + +static unsigned int src_param_pitch_mixer(unsigned int src_idx) +{ + return ((src_idx << 4) + AR_PTS_PITCH + AR_SLOT_SIZE + - AR_PARAM_SRC_OFFSET) % AR_SLOT_SIZE; + +} + +static int src_commit_write(struct hw *hw, unsigned int idx, void *blk) +{ + struct src_rsc_ctrl_blk *ctl = blk; + int i; + + if (ctl->dirty.bf.czbfs) { + /* Clear Z-Buffer registers */ + for (i = 0; i < 8; i++) + hw_write_20kx(hw, SRC_UPZ+idx*0x100+i*0x4, 0); + + for (i = 0; i < 4; i++) + hw_write_20kx(hw, SRC_DN0Z+idx*0x100+i*0x4, 0); + + for (i = 0; i < 8; i++) + hw_write_20kx(hw, SRC_DN1Z+idx*0x100+i*0x4, 0); + + ctl->dirty.bf.czbfs = 0; + } + if (ctl->dirty.bf.mpr) { + /* Take the parameter mixer resource in the same group as that + * the idx src is in for simplicity. Unlike src, all conjugate + * parameter mixer resources must be programmed for + * corresponding conjugate src resources. */ + unsigned int pm_idx = src_param_pitch_mixer(idx); + hw_write_20kx(hw, MIXER_PRING_LO_HI+4*pm_idx, ctl->mpr); + hw_write_20kx(hw, MIXER_PMOPLO+8*pm_idx, 0x3); + hw_write_20kx(hw, MIXER_PMOPHI+8*pm_idx, 0x0); + ctl->dirty.bf.mpr = 0; + } + if (ctl->dirty.bf.sa) { + hw_write_20kx(hw, SRC_SA+idx*0x100, ctl->sa); + ctl->dirty.bf.sa = 0; + } + if (ctl->dirty.bf.la) { + hw_write_20kx(hw, SRC_LA+idx*0x100, ctl->la); + ctl->dirty.bf.la = 0; + } + if (ctl->dirty.bf.ca) { + hw_write_20kx(hw, SRC_CA+idx*0x100, ctl->ca); + ctl->dirty.bf.ca = 0; + } + + /* Write srccf register */ + hw_write_20kx(hw, SRC_CF+idx*0x100, 0x0); + + if (ctl->dirty.bf.ccr) { + hw_write_20kx(hw, SRC_CCR+idx*0x100, ctl->ccr); + ctl->dirty.bf.ccr = 0; + } + if (ctl->dirty.bf.ctl) { + hw_write_20kx(hw, SRC_CTL+idx*0x100, ctl->ctl); + ctl->dirty.bf.ctl = 0; + } + + return 0; +} + +static int src_get_ca(struct hw *hw, unsigned int idx, void *blk) +{ + struct src_rsc_ctrl_blk *ctl = blk; + + ctl->ca = hw_read_20kx(hw, SRC_CA+idx*0x100); + ctl->dirty.bf.ca = 0; + + return get_field(ctl->ca, SRCCA_CA); +} + +static unsigned int src_get_dirty(void *blk) +{ + return ((struct src_rsc_ctrl_blk *)blk)->dirty.data; +} + +static unsigned int src_dirty_conj_mask(void) +{ + return 0x20; +} + +static int src_mgr_enbs_src(void *blk, unsigned int idx) +{ + ((struct src_mgr_ctrl_blk *)blk)->enbsa |= (0x1 << ((idx%128)/4)); + ((struct src_mgr_ctrl_blk *)blk)->dirty.bf.enbsa = 1; + ((struct src_mgr_ctrl_blk *)blk)->enb[idx/32] |= (0x1 << (idx%32)); + return 0; +} + +static int src_mgr_enb_src(void *blk, unsigned int idx) +{ + ((struct src_mgr_ctrl_blk *)blk)->enb[idx/32] |= (0x1 << (idx%32)); + ((struct src_mgr_ctrl_blk *)blk)->dirty.data |= (0x1 << (idx/32)); + return 0; +} + +static int src_mgr_dsb_src(void *blk, unsigned int idx) +{ + ((struct src_mgr_ctrl_blk *)blk)->enb[idx/32] &= ~(0x1 << (idx%32)); + ((struct src_mgr_ctrl_blk *)blk)->dirty.data |= (0x1 << (idx/32)); + return 0; +} + +static int src_mgr_commit_write(struct hw *hw, void *blk) +{ + struct src_mgr_ctrl_blk *ctl = blk; + int i; + unsigned int ret; + + if (ctl->dirty.bf.enbsa) { + do { + ret = hw_read_20kx(hw, SRC_ENBSTAT); + } while (ret & 0x1); + hw_write_20kx(hw, SRC_ENBSA, ctl->enbsa); + ctl->dirty.bf.enbsa = 0; + } + for (i = 0; i < 8; i++) { + if ((ctl->dirty.data & (0x1 << i))) { + hw_write_20kx(hw, SRC_ENB+(i*0x100), ctl->enb[i]); + ctl->dirty.data &= ~(0x1 << i); + } + } + + return 0; +} + +static int src_mgr_get_ctrl_blk(void **rblk) +{ + struct src_mgr_ctrl_blk *blk; + + *rblk = NULL; + blk = kzalloc(sizeof(*blk), GFP_KERNEL); + if (NULL == blk) + return -ENOMEM; + + *rblk = blk; + + return 0; +} + +static int src_mgr_put_ctrl_blk(void *blk) +{ + kfree(blk); + + return 0; +} + +static int srcimp_mgr_get_ctrl_blk(void **rblk) +{ + struct srcimp_mgr_ctrl_blk *blk; + + *rblk = NULL; + blk = kzalloc(sizeof(*blk), GFP_KERNEL); + if (NULL == blk) + return -ENOMEM; + + *rblk = blk; + + return 0; +} + +static int srcimp_mgr_put_ctrl_blk(void *blk) +{ + kfree(blk); + + return 0; +} + +static int srcimp_mgr_set_imaparc(void *blk, unsigned int slot) +{ + struct srcimp_mgr_ctrl_blk *ctl = blk; + + set_field(&ctl->srcimap.srcaim, SRCAIM_ARC, slot); + ctl->dirty.bf.srcimap = 1; + return 0; +} + +static int srcimp_mgr_set_imapuser(void *blk, unsigned int user) +{ + struct srcimp_mgr_ctrl_blk *ctl = blk; + + set_field(&ctl->srcimap.srcaim, SRCAIM_SRC, user); + ctl->dirty.bf.srcimap = 1; + return 0; +} + +static int srcimp_mgr_set_imapnxt(void *blk, unsigned int next) +{ + struct srcimp_mgr_ctrl_blk *ctl = blk; + + set_field(&ctl->srcimap.srcaim, SRCAIM_NXT, next); + ctl->dirty.bf.srcimap = 1; + return 0; +} + +static int srcimp_mgr_set_imapaddr(void *blk, unsigned int addr) +{ + ((struct srcimp_mgr_ctrl_blk *)blk)->srcimap.idx = addr; + ((struct srcimp_mgr_ctrl_blk *)blk)->dirty.bf.srcimap = 1; + return 0; +} + +static int srcimp_mgr_commit_write(struct hw *hw, void *blk) +{ + struct srcimp_mgr_ctrl_blk *ctl = blk; + + if (ctl->dirty.bf.srcimap) { + hw_write_20kx(hw, SRC_IMAP+ctl->srcimap.idx*0x100, + ctl->srcimap.srcaim); + ctl->dirty.bf.srcimap = 0; + } + + return 0; +} + +/* + * AMIXER control block definitions. + */ + +#define AMOPLO_M 0x00000003 +#define AMOPLO_IV 0x00000004 +#define AMOPLO_X 0x0003FFF0 +#define AMOPLO_Y 0xFFFC0000 + +#define AMOPHI_SADR 0x000000FF +#define AMOPHI_SE 0x80000000 + +/* AMIXER resource register dirty flags */ +union amixer_dirty { + struct { + u16 amoplo:1; + u16 amophi:1; + u16 rsv:14; + } bf; + u16 data; +}; + +/* AMIXER resource control block */ +struct amixer_rsc_ctrl_blk { + unsigned int amoplo; + unsigned int amophi; + union amixer_dirty dirty; +}; + +static int amixer_set_mode(void *blk, unsigned int mode) +{ + struct amixer_rsc_ctrl_blk *ctl = blk; + + set_field(&ctl->amoplo, AMOPLO_M, mode); + ctl->dirty.bf.amoplo = 1; + return 0; +} + +static int amixer_set_iv(void *blk, unsigned int iv) +{ + struct amixer_rsc_ctrl_blk *ctl = blk; + + set_field(&ctl->amoplo, AMOPLO_IV, iv); + ctl->dirty.bf.amoplo = 1; + return 0; +} + +static int amixer_set_x(void *blk, unsigned int x) +{ + struct amixer_rsc_ctrl_blk *ctl = blk; + + set_field(&ctl->amoplo, AMOPLO_X, x); + ctl->dirty.bf.amoplo = 1; + return 0; +} + +static int amixer_set_y(void *blk, unsigned int y) +{ + struct amixer_rsc_ctrl_blk *ctl = blk; + + set_field(&ctl->amoplo, AMOPLO_Y, y); + ctl->dirty.bf.amoplo = 1; + return 0; +} + +static int amixer_set_sadr(void *blk, unsigned int sadr) +{ + struct amixer_rsc_ctrl_blk *ctl = blk; + + set_field(&ctl->amophi, AMOPHI_SADR, sadr); + ctl->dirty.bf.amophi = 1; + return 0; +} + +static int amixer_set_se(void *blk, unsigned int se) +{ + struct amixer_rsc_ctrl_blk *ctl = blk; + + set_field(&ctl->amophi, AMOPHI_SE, se); + ctl->dirty.bf.amophi = 1; + return 0; +} + +static int amixer_set_dirty(void *blk, unsigned int flags) +{ + ((struct amixer_rsc_ctrl_blk *)blk)->dirty.data = (flags & 0xffff); + return 0; +} + +static int amixer_set_dirty_all(void *blk) +{ + ((struct amixer_rsc_ctrl_blk *)blk)->dirty.data = ~(0x0); + return 0; +} + +static int amixer_commit_write(struct hw *hw, unsigned int idx, void *blk) +{ + struct amixer_rsc_ctrl_blk *ctl = blk; + + if (ctl->dirty.bf.amoplo || ctl->dirty.bf.amophi) { + hw_write_20kx(hw, MIXER_AMOPLO+idx*8, ctl->amoplo); + ctl->dirty.bf.amoplo = 0; + hw_write_20kx(hw, MIXER_AMOPHI+idx*8, ctl->amophi); + ctl->dirty.bf.amophi = 0; + } + + return 0; +} + +static int amixer_get_y(void *blk) +{ + struct amixer_rsc_ctrl_blk *ctl = blk; + + return get_field(ctl->amoplo, AMOPLO_Y); +} + +static unsigned int amixer_get_dirty(void *blk) +{ + return ((struct amixer_rsc_ctrl_blk *)blk)->dirty.data; +} + +static int amixer_rsc_get_ctrl_blk(void **rblk) +{ + struct amixer_rsc_ctrl_blk *blk; + + *rblk = NULL; + blk = kzalloc(sizeof(*blk), GFP_KERNEL); + if (NULL == blk) + return -ENOMEM; + + *rblk = blk; + + return 0; +} + +static int amixer_rsc_put_ctrl_blk(void *blk) +{ + kfree(blk); + + return 0; +} + +static int amixer_mgr_get_ctrl_blk(void **rblk) +{ + *rblk = NULL; + + return 0; +} + +static int amixer_mgr_put_ctrl_blk(void *blk) +{ + return 0; +} + +/* + * DAIO control block definitions. + */ + +/* Receiver Sample Rate Tracker Control register */ +#define SRTCTL_SRCO 0x000000FF +#define SRTCTL_SRCM 0x0000FF00 +#define SRTCTL_RSR 0x00030000 +#define SRTCTL_DRAT 0x00300000 +#define SRTCTL_EC 0x01000000 +#define SRTCTL_ET 0x10000000 + +/* DAIO Receiver register dirty flags */ +union dai_dirty { + struct { + u16 srt:1; + u16 rsv:15; + } bf; + u16 data; +}; + +/* DAIO Receiver control block */ +struct dai_ctrl_blk { + unsigned int srt; + union dai_dirty dirty; +}; + +/* Audio Input Mapper RAM */ +#define AIM_ARC 0x00000FFF +#define AIM_NXT 0x007F0000 + +struct daoimap { + unsigned int aim; + unsigned int idx; +}; + +/* Audio Transmitter Control and Status register */ +#define ATXCTL_EN 0x00000001 +#define ATXCTL_MODE 0x00000010 +#define ATXCTL_CD 0x00000020 +#define ATXCTL_RAW 0x00000100 +#define ATXCTL_MT 0x00000200 +#define ATXCTL_NUC 0x00003000 +#define ATXCTL_BEN 0x00010000 +#define ATXCTL_BMUX 0x00700000 +#define ATXCTL_B24 0x01000000 +#define ATXCTL_CPF 0x02000000 +#define ATXCTL_RIV 0x10000000 +#define ATXCTL_LIV 0x20000000 +#define ATXCTL_RSAT 0x40000000 +#define ATXCTL_LSAT 0x80000000 + +/* XDIF Transmitter register dirty flags */ +union dao_dirty { + struct { + u16 atxcsl:1; + u16 rsv:15; + } bf; + u16 data; +}; + +/* XDIF Transmitter control block */ +struct dao_ctrl_blk { + /* XDIF Transmitter Channel Status Low Register */ + unsigned int atxcsl; + union dao_dirty dirty; +}; + +/* Audio Receiver Control register */ +#define ARXCTL_EN 0x00000001 + +/* DAIO manager register dirty flags */ +union daio_mgr_dirty { + struct { + u32 atxctl:8; + u32 arxctl:8; + u32 daoimap:1; + u32 rsv:15; + } bf; + u32 data; +}; + +/* DAIO manager control block */ +struct daio_mgr_ctrl_blk { + struct daoimap daoimap; + unsigned int txctl[8]; + unsigned int rxctl[8]; + union daio_mgr_dirty dirty; +}; + +static int dai_srt_set_srco(void *blk, unsigned int src) +{ + struct dai_ctrl_blk *ctl = blk; + + set_field(&ctl->srt, SRTCTL_SRCO, src); + ctl->dirty.bf.srt = 1; + return 0; +} + +static int dai_srt_set_srcm(void *blk, unsigned int src) +{ + struct dai_ctrl_blk *ctl = blk; + + set_field(&ctl->srt, SRTCTL_SRCM, src); + ctl->dirty.bf.srt = 1; + return 0; +} + +static int dai_srt_set_rsr(void *blk, unsigned int rsr) +{ + struct dai_ctrl_blk *ctl = blk; + + set_field(&ctl->srt, SRTCTL_RSR, rsr); + ctl->dirty.bf.srt = 1; + return 0; +} + +static int dai_srt_set_drat(void *blk, unsigned int drat) +{ + struct dai_ctrl_blk *ctl = blk; + + set_field(&ctl->srt, SRTCTL_DRAT, drat); + ctl->dirty.bf.srt = 1; + return 0; +} + +static int dai_srt_set_ec(void *blk, unsigned int ec) +{ + struct dai_ctrl_blk *ctl = blk; + + set_field(&ctl->srt, SRTCTL_EC, ec ? 1 : 0); + ctl->dirty.bf.srt = 1; + return 0; +} + +static int dai_srt_set_et(void *blk, unsigned int et) +{ + struct dai_ctrl_blk *ctl = blk; + + set_field(&ctl->srt, SRTCTL_ET, et ? 1 : 0); + ctl->dirty.bf.srt = 1; + return 0; +} + +static int dai_commit_write(struct hw *hw, unsigned int idx, void *blk) +{ + struct dai_ctrl_blk *ctl = blk; + + if (ctl->dirty.bf.srt) { + hw_write_20kx(hw, AUDIO_IO_RX_SRT_CTL+0x40*idx, ctl->srt); + ctl->dirty.bf.srt = 0; + } + + return 0; +} + +static int dai_get_ctrl_blk(void **rblk) +{ + struct dai_ctrl_blk *blk; + + *rblk = NULL; + blk = kzalloc(sizeof(*blk), GFP_KERNEL); + if (NULL == blk) + return -ENOMEM; + + *rblk = blk; + + return 0; +} + +static int dai_put_ctrl_blk(void *blk) +{ + kfree(blk); + + return 0; +} + +static int dao_set_spos(void *blk, unsigned int spos) +{ + ((struct dao_ctrl_blk *)blk)->atxcsl = spos; + ((struct dao_ctrl_blk *)blk)->dirty.bf.atxcsl = 1; + return 0; +} + +static int dao_commit_write(struct hw *hw, unsigned int idx, void *blk) +{ + struct dao_ctrl_blk *ctl = blk; + + if (ctl->dirty.bf.atxcsl) { + if (idx < 4) { + /* S/PDIF SPOSx */ + hw_write_20kx(hw, AUDIO_IO_TX_CSTAT_L+0x40*idx, + ctl->atxcsl); + } + ctl->dirty.bf.atxcsl = 0; + } + + return 0; +} + +static int dao_get_spos(void *blk, unsigned int *spos) +{ + *spos = ((struct dao_ctrl_blk *)blk)->atxcsl; + return 0; +} + +static int dao_get_ctrl_blk(void **rblk) +{ + struct dao_ctrl_blk *blk; + + *rblk = NULL; + blk = kzalloc(sizeof(*blk), GFP_KERNEL); + if (NULL == blk) + return -ENOMEM; + + *rblk = blk; + + return 0; +} + +static int dao_put_ctrl_blk(void *blk) +{ + kfree(blk); + + return 0; +} + +static int daio_mgr_enb_dai(void *blk, unsigned int idx) +{ + struct daio_mgr_ctrl_blk *ctl = blk; + + set_field(&ctl->rxctl[idx], ARXCTL_EN, 1); + ctl->dirty.bf.arxctl |= (0x1 << idx); + return 0; +} + +static int daio_mgr_dsb_dai(void *blk, unsigned int idx) +{ + struct daio_mgr_ctrl_blk *ctl = blk; + + set_field(&ctl->rxctl[idx], ARXCTL_EN, 0); + + ctl->dirty.bf.arxctl |= (0x1 << idx); + return 0; +} + +static int daio_mgr_enb_dao(void *blk, unsigned int idx) +{ + struct daio_mgr_ctrl_blk *ctl = blk; + + set_field(&ctl->txctl[idx], ATXCTL_EN, 1); + ctl->dirty.bf.atxctl |= (0x1 << idx); + return 0; +} + +static int daio_mgr_dsb_dao(void *blk, unsigned int idx) +{ + struct daio_mgr_ctrl_blk *ctl = blk; + + set_field(&ctl->txctl[idx], ATXCTL_EN, 0); + ctl->dirty.bf.atxctl |= (0x1 << idx); + return 0; +} + +static int daio_mgr_dao_init(void *blk, unsigned int idx, unsigned int conf) +{ + struct daio_mgr_ctrl_blk *ctl = blk; + + if (idx < 4) { + /* S/PDIF output */ + switch ((conf & 0x7)) { + case 1: + set_field(&ctl->txctl[idx], ATXCTL_NUC, 0); + break; + case 2: + set_field(&ctl->txctl[idx], ATXCTL_NUC, 1); + break; + case 4: + set_field(&ctl->txctl[idx], ATXCTL_NUC, 2); + break; + case 8: + set_field(&ctl->txctl[idx], ATXCTL_NUC, 3); + break; + default: + break; + } + /* CDIF */ + set_field(&ctl->txctl[idx], ATXCTL_CD, (!(conf & 0x7))); + /* Non-audio */ + set_field(&ctl->txctl[idx], ATXCTL_LIV, (conf >> 4) & 0x1); + /* Non-audio */ + set_field(&ctl->txctl[idx], ATXCTL_RIV, (conf >> 4) & 0x1); + set_field(&ctl->txctl[idx], ATXCTL_RAW, + ((conf >> 3) & 0x1) ? 0 : 0); + ctl->dirty.bf.atxctl |= (0x1 << idx); + } else { + /* I2S output */ + /*idx %= 4; */ + } + return 0; +} + +static int daio_mgr_set_imaparc(void *blk, unsigned int slot) +{ + struct daio_mgr_ctrl_blk *ctl = blk; + + set_field(&ctl->daoimap.aim, AIM_ARC, slot); + ctl->dirty.bf.daoimap = 1; + return 0; +} + +static int daio_mgr_set_imapnxt(void *blk, unsigned int next) +{ + struct daio_mgr_ctrl_blk *ctl = blk; + + set_field(&ctl->daoimap.aim, AIM_NXT, next); + ctl->dirty.bf.daoimap = 1; + return 0; +} + +static int daio_mgr_set_imapaddr(void *blk, unsigned int addr) +{ + ((struct daio_mgr_ctrl_blk *)blk)->daoimap.idx = addr; + ((struct daio_mgr_ctrl_blk *)blk)->dirty.bf.daoimap = 1; + return 0; +} + +static int daio_mgr_commit_write(struct hw *hw, void *blk) +{ + struct daio_mgr_ctrl_blk *ctl = blk; + unsigned int data; + int i; + + for (i = 0; i < 8; i++) { + if ((ctl->dirty.bf.atxctl & (0x1 << i))) { + data = ctl->txctl[i]; + hw_write_20kx(hw, (AUDIO_IO_TX_CTL+(0x40*i)), data); + ctl->dirty.bf.atxctl &= ~(0x1 << i); + mdelay(1); + } + if ((ctl->dirty.bf.arxctl & (0x1 << i))) { + data = ctl->rxctl[i]; + hw_write_20kx(hw, (AUDIO_IO_RX_CTL+(0x40*i)), data); + ctl->dirty.bf.arxctl &= ~(0x1 << i); + mdelay(1); + } + } + if (ctl->dirty.bf.daoimap) { + hw_write_20kx(hw, AUDIO_IO_AIM+ctl->daoimap.idx*4, + ctl->daoimap.aim); + ctl->dirty.bf.daoimap = 0; + } + + return 0; +} + +static int daio_mgr_get_ctrl_blk(struct hw *hw, void **rblk) +{ + struct daio_mgr_ctrl_blk *blk; + int i; + + *rblk = NULL; + blk = kzalloc(sizeof(*blk), GFP_KERNEL); + if (NULL == blk) + return -ENOMEM; + + for (i = 0; i < 8; i++) { + blk->txctl[i] = hw_read_20kx(hw, AUDIO_IO_TX_CTL+(0x40*i)); + blk->rxctl[i] = hw_read_20kx(hw, AUDIO_IO_RX_CTL+(0x40*i)); + } + + *rblk = blk; + + return 0; +} + +static int daio_mgr_put_ctrl_blk(void *blk) +{ + kfree(blk); + + return 0; +} + +/* Card hardware initialization block */ +struct dac_conf { + unsigned int msr; /* master sample rate in rsrs */ +}; + +struct adc_conf { + unsigned int msr; /* master sample rate in rsrs */ + unsigned char input; /* the input source of ADC */ + unsigned char mic20db; /* boost mic by 20db if input is microphone */ +}; + +struct daio_conf { + unsigned int msr; /* master sample rate in rsrs */ +}; + +struct trn_conf { + unsigned long vm_pgt_phys; +}; + +static int hw_daio_init(struct hw *hw, const struct daio_conf *info) +{ + u32 data; + int i; + + /* Program I2S with proper sample rate and enable the correct I2S + * channel. ED(0/8/16/24): Enable all I2S/I2X master clock output */ + if (1 == info->msr) { + hw_write_20kx(hw, AUDIO_IO_MCLK, 0x01010101); + hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x01010101); + hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0); + } else if (2 == info->msr) { + hw_write_20kx(hw, AUDIO_IO_MCLK, 0x11111111); + /* Specify all playing 96khz + * EA [0] - Enabled + * RTA [4:5] - 96kHz + * EB [8] - Enabled + * RTB [12:13] - 96kHz + * EC [16] - Enabled + * RTC [20:21] - 96kHz + * ED [24] - Enabled + * RTD [28:29] - 96kHz */ + hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x11111111); + hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0); + } else { + printk(KERN_ALERT "ctxfi: ERROR!!! Invalid sampling rate!!!\n"); + return -EINVAL; + } + + for (i = 0; i < 8; i++) { + if (i <= 3) { + /* 1st 3 channels are SPDIFs (SB0960) */ + if (i == 3) + data = 0x1001001; + else + data = 0x1000001; + + hw_write_20kx(hw, (AUDIO_IO_TX_CTL+(0x40*i)), data); + hw_write_20kx(hw, (AUDIO_IO_RX_CTL+(0x40*i)), data); + + /* Initialize the SPDIF Out Channel status registers. + * The value specified here is based on the typical + * values provided in the specification, namely: Clock + * Accuracy of 1000ppm, Sample Rate of 48KHz, + * unspecified source number, Generation status = 1, + * Category code = 0x12 (Digital Signal Mixer), + * Mode = 0, Emph = 0, Copy Permitted, AN = 0 + * (indicating that we're transmitting digital audio, + * and the Professional Use bit is 0. */ + + hw_write_20kx(hw, AUDIO_IO_TX_CSTAT_L+(0x40*i), + 0x02109204); /* Default to 48kHz */ + + hw_write_20kx(hw, AUDIO_IO_TX_CSTAT_H+(0x40*i), 0x0B); + } else { + /* Next 5 channels are I2S (SB0960) */ + data = 0x11; + hw_write_20kx(hw, AUDIO_IO_RX_CTL+(0x40*i), data); + if (2 == info->msr) { + /* Four channels per sample period */ + data |= 0x1000; + } + hw_write_20kx(hw, AUDIO_IO_TX_CTL+(0x40*i), data); + } + } + + return 0; +} + +/* TRANSPORT operations */ +static int hw_trn_init(struct hw *hw, const struct trn_conf *info) +{ + u32 vmctl, data; + u32 ptp_phys_low, ptp_phys_high; + int i; + + /* Set up device page table */ + if ((~0UL) == info->vm_pgt_phys) { + printk(KERN_ALERT "ctxfi: " + "Wrong device page table page address!!!\n"); + return -1; + } + + vmctl = 0x80000C0F; /* 32-bit, 4k-size page */ + ptp_phys_low = (u32)info->vm_pgt_phys; + ptp_phys_high = upper_32_bits(info->vm_pgt_phys); + if (sizeof(void *) == 8) /* 64bit address */ + vmctl |= (3 << 8); + /* Write page table physical address to all PTPAL registers */ + for (i = 0; i < 64; i++) { + hw_write_20kx(hw, VMEM_PTPAL+(16*i), ptp_phys_low); + hw_write_20kx(hw, VMEM_PTPAH+(16*i), ptp_phys_high); + } + /* Enable virtual memory transfer */ + hw_write_20kx(hw, VMEM_CTL, vmctl); + /* Enable transport bus master and queueing of request */ + hw_write_20kx(hw, TRANSPORT_CTL, 0x03); + hw_write_20kx(hw, TRANSPORT_INT, 0x200c01); + /* Enable transport ring */ + data = hw_read_20kx(hw, TRANSPORT_ENB); + hw_write_20kx(hw, TRANSPORT_ENB, (data | 0x03)); + + return 0; +} + +/* Card initialization */ +#define GCTL_AIE 0x00000001 +#define GCTL_UAA 0x00000002 +#define GCTL_DPC 0x00000004 +#define GCTL_DBP 0x00000008 +#define GCTL_ABP 0x00000010 +#define GCTL_TBP 0x00000020 +#define GCTL_SBP 0x00000040 +#define GCTL_FBP 0x00000080 +#define GCTL_ME 0x00000100 +#define GCTL_AID 0x00001000 + +#define PLLCTL_SRC 0x00000007 +#define PLLCTL_SPE 0x00000008 +#define PLLCTL_RD 0x000000F0 +#define PLLCTL_FD 0x0001FF00 +#define PLLCTL_OD 0x00060000 +#define PLLCTL_B 0x00080000 +#define PLLCTL_AS 0x00100000 +#define PLLCTL_LF 0x03E00000 +#define PLLCTL_SPS 0x1C000000 +#define PLLCTL_AD 0x60000000 + +#define PLLSTAT_CCS 0x00000007 +#define PLLSTAT_SPL 0x00000008 +#define PLLSTAT_CRD 0x000000F0 +#define PLLSTAT_CFD 0x0001FF00 +#define PLLSTAT_SL 0x00020000 +#define PLLSTAT_FAS 0x00040000 +#define PLLSTAT_B 0x00080000 +#define PLLSTAT_PD 0x00100000 +#define PLLSTAT_OCA 0x00200000 +#define PLLSTAT_NCA 0x00400000 + +static int hw_pll_init(struct hw *hw, unsigned int rsr) +{ + unsigned int pllenb; + unsigned int pllctl; + unsigned int pllstat; + int i; + + pllenb = 0xB; + hw_write_20kx(hw, PLL_ENB, pllenb); + pllctl = 0x20D00000; + set_field(&pllctl, PLLCTL_FD, 16 - 4); + hw_write_20kx(hw, PLL_CTL, pllctl); + mdelay(40); + pllctl = hw_read_20kx(hw, PLL_CTL); + set_field(&pllctl, PLLCTL_B, 0); + if (48000 == rsr) { + set_field(&pllctl, PLLCTL_FD, 16 - 2); + set_field(&pllctl, PLLCTL_RD, 1 - 1); + } else { /* 44100 */ + set_field(&pllctl, PLLCTL_FD, 147 - 2); + set_field(&pllctl, PLLCTL_RD, 10 - 1); + } + hw_write_20kx(hw, PLL_CTL, pllctl); + mdelay(40); + for (i = 0; i < 1000; i++) { + pllstat = hw_read_20kx(hw, PLL_STAT); + if (get_field(pllstat, PLLSTAT_PD)) + continue; + + if (get_field(pllstat, PLLSTAT_B) != + get_field(pllctl, PLLCTL_B)) + continue; + + if (get_field(pllstat, PLLSTAT_CCS) != + get_field(pllctl, PLLCTL_SRC)) + continue; + + if (get_field(pllstat, PLLSTAT_CRD) != + get_field(pllctl, PLLCTL_RD)) + continue; + + if (get_field(pllstat, PLLSTAT_CFD) != + get_field(pllctl, PLLCTL_FD)) + continue; + + break; + } + if (i >= 1000) { + printk(KERN_ALERT "ctxfi: PLL initialization failed!!!\n"); + return -EBUSY; + } + + return 0; +} + +static int hw_auto_init(struct hw *hw) +{ + unsigned int gctl; + int i; + + gctl = hw_read_20kx(hw, GLOBAL_CNTL_GCTL); + set_field(&gctl, GCTL_AIE, 0); + hw_write_20kx(hw, GLOBAL_CNTL_GCTL, gctl); + set_field(&gctl, GCTL_AIE, 1); + hw_write_20kx(hw, GLOBAL_CNTL_GCTL, gctl); + mdelay(10); + for (i = 0; i < 400000; i++) { + gctl = hw_read_20kx(hw, GLOBAL_CNTL_GCTL); + if (get_field(gctl, GCTL_AID)) + break; + } + if (!get_field(gctl, GCTL_AID)) { + printk(KERN_ALERT "ctxfi: Card Auto-init failed!!!\n"); + return -EBUSY; + } + + return 0; +} + +/* DAC operations */ + +#define CS4382_MC1 0x1 +#define CS4382_MC2 0x2 +#define CS4382_MC3 0x3 +#define CS4382_FC 0x4 +#define CS4382_IC 0x5 +#define CS4382_XC1 0x6 +#define CS4382_VCA1 0x7 +#define CS4382_VCB1 0x8 +#define CS4382_XC2 0x9 +#define CS4382_VCA2 0xA +#define CS4382_VCB2 0xB +#define CS4382_XC3 0xC +#define CS4382_VCA3 0xD +#define CS4382_VCB3 0xE +#define CS4382_XC4 0xF +#define CS4382_VCA4 0x10 +#define CS4382_VCB4 0x11 +#define CS4382_CREV 0x12 + +/* I2C status */ +#define STATE_LOCKED 0x00 +#define STATE_UNLOCKED 0xAA +#define DATA_READY 0x800000 /* Used with I2C_IF_STATUS */ +#define DATA_ABORT 0x10000 /* Used with I2C_IF_STATUS */ + +#define I2C_STATUS_DCM 0x00000001 +#define I2C_STATUS_BC 0x00000006 +#define I2C_STATUS_APD 0x00000008 +#define I2C_STATUS_AB 0x00010000 +#define I2C_STATUS_DR 0x00800000 + +#define I2C_ADDRESS_PTAD 0x0000FFFF +#define I2C_ADDRESS_SLAD 0x007F0000 + +struct regs_cs4382 { + u32 mode_control_1; + u32 mode_control_2; + u32 mode_control_3; + + u32 filter_control; + u32 invert_control; + + u32 mix_control_P1; + u32 vol_control_A1; + u32 vol_control_B1; + + u32 mix_control_P2; + u32 vol_control_A2; + u32 vol_control_B2; + + u32 mix_control_P3; + u32 vol_control_A3; + u32 vol_control_B3; + + u32 mix_control_P4; + u32 vol_control_A4; + u32 vol_control_B4; +}; + +static int hw20k2_i2c_unlock_full_access(struct hw *hw) +{ + u8 UnlockKeySequence_FLASH_FULLACCESS_MODE[2] = {0xB3, 0xD4}; + + /* Send keys for forced BIOS mode */ + hw_write_20kx(hw, I2C_IF_WLOCK, + UnlockKeySequence_FLASH_FULLACCESS_MODE[0]); + hw_write_20kx(hw, I2C_IF_WLOCK, + UnlockKeySequence_FLASH_FULLACCESS_MODE[1]); + /* Check whether the chip is unlocked */ + if (hw_read_20kx(hw, I2C_IF_WLOCK) == STATE_UNLOCKED) + return 0; + + return -1; +} + +static int hw20k2_i2c_lock_chip(struct hw *hw) +{ + /* Write twice */ + hw_write_20kx(hw, I2C_IF_WLOCK, STATE_LOCKED); + hw_write_20kx(hw, I2C_IF_WLOCK, STATE_LOCKED); + if (hw_read_20kx(hw, I2C_IF_WLOCK) == STATE_LOCKED) + return 0; + + return -1; +} + +static int hw20k2_i2c_init(struct hw *hw, u8 dev_id, u8 addr_size, u8 data_size) +{ + struct hw20k2 *hw20k2 = (struct hw20k2 *)hw; + int err; + unsigned int i2c_status; + unsigned int i2c_addr; + + err = hw20k2_i2c_unlock_full_access(hw); + if (err < 0) + return err; + + hw20k2->addr_size = addr_size; + hw20k2->data_size = data_size; + hw20k2->dev_id = dev_id; + + i2c_addr = 0; + set_field(&i2c_addr, I2C_ADDRESS_SLAD, dev_id); + + hw_write_20kx(hw, I2C_IF_ADDRESS, i2c_addr); + + i2c_status = hw_read_20kx(hw, I2C_IF_STATUS); + + set_field(&i2c_status, I2C_STATUS_DCM, 1); /* Direct control mode */ + + hw_write_20kx(hw, I2C_IF_STATUS, i2c_status); + + return 0; +} + +static int hw20k2_i2c_uninit(struct hw *hw) +{ + unsigned int i2c_status; + unsigned int i2c_addr; + + i2c_addr = 0; + set_field(&i2c_addr, I2C_ADDRESS_SLAD, 0x57); /* I2C id */ + + hw_write_20kx(hw, I2C_IF_ADDRESS, i2c_addr); + + i2c_status = hw_read_20kx(hw, I2C_IF_STATUS); + + set_field(&i2c_status, I2C_STATUS_DCM, 0); /* I2C mode */ + + hw_write_20kx(hw, I2C_IF_STATUS, i2c_status); + + return hw20k2_i2c_lock_chip(hw); +} + +static int hw20k2_i2c_wait_data_ready(struct hw *hw) +{ + int i = 0x400000; + unsigned int ret; + + do { + ret = hw_read_20kx(hw, I2C_IF_STATUS); + } while ((!(ret & DATA_READY)) && --i); + + return i; +} + +static int hw20k2_i2c_read(struct hw *hw, u16 addr, u32 *datap) +{ + struct hw20k2 *hw20k2 = (struct hw20k2 *)hw; + unsigned int i2c_status; + + i2c_status = hw_read_20kx(hw, I2C_IF_STATUS); + set_field(&i2c_status, I2C_STATUS_BC, + (4 == hw20k2->addr_size) ? 0 : hw20k2->addr_size); + hw_write_20kx(hw, I2C_IF_STATUS, i2c_status); + if (!hw20k2_i2c_wait_data_ready(hw)) + return -1; + + hw_write_20kx(hw, I2C_IF_WDATA, addr); + if (!hw20k2_i2c_wait_data_ready(hw)) + return -1; + + /* Force a read operation */ + hw_write_20kx(hw, I2C_IF_RDATA, 0); + if (!hw20k2_i2c_wait_data_ready(hw)) + return -1; + + *datap = hw_read_20kx(hw, I2C_IF_RDATA); + + return 0; +} + +static int hw20k2_i2c_write(struct hw *hw, u16 addr, u32 data) +{ + struct hw20k2 *hw20k2 = (struct hw20k2 *)hw; + unsigned int i2c_data = (data << (hw20k2->addr_size * 8)) | addr; + unsigned int i2c_status; + + i2c_status = hw_read_20kx(hw, I2C_IF_STATUS); + + set_field(&i2c_status, I2C_STATUS_BC, + (4 == (hw20k2->addr_size + hw20k2->data_size)) ? + 0 : (hw20k2->addr_size + hw20k2->data_size)); + + hw_write_20kx(hw, I2C_IF_STATUS, i2c_status); + hw20k2_i2c_wait_data_ready(hw); + /* Dummy write to trigger the write oprtation */ + hw_write_20kx(hw, I2C_IF_WDATA, 0); + hw20k2_i2c_wait_data_ready(hw); + + /* This is the real data */ + hw_write_20kx(hw, I2C_IF_WDATA, i2c_data); + hw20k2_i2c_wait_data_ready(hw); + + return 0; +} + +static int hw_dac_init(struct hw *hw, const struct dac_conf *info) +{ + int err; + u32 data; + int i; + struct regs_cs4382 cs_read = {0}; + struct regs_cs4382 cs_def = { + 0x00000001, /* Mode Control 1 */ + 0x00000000, /* Mode Control 2 */ + 0x00000084, /* Mode Control 3 */ + 0x00000000, /* Filter Control */ + 0x00000000, /* Invert Control */ + 0x00000024, /* Mixing Control Pair 1 */ + 0x00000000, /* Vol Control A1 */ + 0x00000000, /* Vol Control B1 */ + 0x00000024, /* Mixing Control Pair 2 */ + 0x00000000, /* Vol Control A2 */ + 0x00000000, /* Vol Control B2 */ + 0x00000024, /* Mixing Control Pair 3 */ + 0x00000000, /* Vol Control A3 */ + 0x00000000, /* Vol Control B3 */ + 0x00000024, /* Mixing Control Pair 4 */ + 0x00000000, /* Vol Control A4 */ + 0x00000000 /* Vol Control B4 */ + }; + + /* Set DAC reset bit as output */ + data = hw_read_20kx(hw, GPIO_CTRL); + data |= 0x02; + hw_write_20kx(hw, GPIO_CTRL, data); + + err = hw20k2_i2c_init(hw, 0x18, 1, 1); + if (err < 0) + goto End; + + for (i = 0; i < 2; i++) { + /* Reset DAC twice just in-case the chip + * didn't initialized properly */ + data = hw_read_20kx(hw, GPIO_DATA); + /* GPIO data bit 1 */ + data &= 0xFFFFFFFD; + hw_write_20kx(hw, GPIO_DATA, data); + mdelay(10); + data |= 0x2; + hw_write_20kx(hw, GPIO_DATA, data); + mdelay(50); + + /* Reset the 2nd time */ + data &= 0xFFFFFFFD; + hw_write_20kx(hw, GPIO_DATA, data); + mdelay(10); + data |= 0x2; + hw_write_20kx(hw, GPIO_DATA, data); + mdelay(50); + + if (hw20k2_i2c_read(hw, CS4382_MC1, &cs_read.mode_control_1)) + continue; + + if (hw20k2_i2c_read(hw, CS4382_MC2, &cs_read.mode_control_2)) + continue; + + if (hw20k2_i2c_read(hw, CS4382_MC3, &cs_read.mode_control_3)) + continue; + + if (hw20k2_i2c_read(hw, CS4382_FC, &cs_read.filter_control)) + continue; + + if (hw20k2_i2c_read(hw, CS4382_IC, &cs_read.invert_control)) + continue; + + if (hw20k2_i2c_read(hw, CS4382_XC1, &cs_read.mix_control_P1)) + continue; + + if (hw20k2_i2c_read(hw, CS4382_VCA1, &cs_read.vol_control_A1)) + continue; + + if (hw20k2_i2c_read(hw, CS4382_VCB1, &cs_read.vol_control_B1)) + continue; + + if (hw20k2_i2c_read(hw, CS4382_XC2, &cs_read.mix_control_P2)) + continue; + + if (hw20k2_i2c_read(hw, CS4382_VCA2, &cs_read.vol_control_A2)) + continue; + + if (hw20k2_i2c_read(hw, CS4382_VCB2, &cs_read.vol_control_B2)) + continue; + + if (hw20k2_i2c_read(hw, CS4382_XC3, &cs_read.mix_control_P3)) + continue; + + if (hw20k2_i2c_read(hw, CS4382_VCA3, &cs_read.vol_control_A3)) + continue; + + if (hw20k2_i2c_read(hw, CS4382_VCB3, &cs_read.vol_control_B3)) + continue; + + if (hw20k2_i2c_read(hw, CS4382_XC4, &cs_read.mix_control_P4)) + continue; + + if (hw20k2_i2c_read(hw, CS4382_VCA4, &cs_read.vol_control_A4)) + continue; + + if (hw20k2_i2c_read(hw, CS4382_VCB4, &cs_read.vol_control_B4)) + continue; + + if (memcmp(&cs_read, &cs_def, sizeof(cs_read))) + continue; + else + break; + } + + if (i >= 2) + goto End; + + /* Note: Every I2C write must have some delay. + * This is not a requirement but the delay works here... */ + hw20k2_i2c_write(hw, CS4382_MC1, 0x80); + hw20k2_i2c_write(hw, CS4382_MC2, 0x10); + if (1 == info->msr) { + hw20k2_i2c_write(hw, CS4382_XC1, 0x24); + hw20k2_i2c_write(hw, CS4382_XC2, 0x24); + hw20k2_i2c_write(hw, CS4382_XC3, 0x24); + hw20k2_i2c_write(hw, CS4382_XC4, 0x24); + } else if (2 == info->msr) { + hw20k2_i2c_write(hw, CS4382_XC1, 0x25); + hw20k2_i2c_write(hw, CS4382_XC2, 0x25); + hw20k2_i2c_write(hw, CS4382_XC3, 0x25); + hw20k2_i2c_write(hw, CS4382_XC4, 0x25); + } else { + hw20k2_i2c_write(hw, CS4382_XC1, 0x26); + hw20k2_i2c_write(hw, CS4382_XC2, 0x26); + hw20k2_i2c_write(hw, CS4382_XC3, 0x26); + hw20k2_i2c_write(hw, CS4382_XC4, 0x26); + } + + return 0; +End: + + hw20k2_i2c_uninit(hw); + return -1; +} + +/* ADC operations */ +#define MAKE_WM8775_ADDR(addr, data) (u32)(((addr<<1)&0xFE)|((data>>8)&0x1)) +#define MAKE_WM8775_DATA(data) (u32)(data&0xFF) + +#define WM8775_IC 0x0B +#define WM8775_MMC 0x0C +#define WM8775_AADCL 0x0E +#define WM8775_AADCR 0x0F +#define WM8775_ADCMC 0x15 +#define WM8775_RESET 0x17 + +static int hw_is_adc_input_selected(struct hw *hw, enum ADCSRC type) +{ + u32 data; + + data = hw_read_20kx(hw, GPIO_DATA); + switch (type) { + case ADC_MICIN: + data = (data & (0x1 << 14)) ? 1 : 0; + break; + case ADC_LINEIN: + data = (data & (0x1 << 14)) ? 0 : 1; + break; + default: + data = 0; + } + return data; +} + +static int hw_adc_input_select(struct hw *hw, enum ADCSRC type) +{ + u32 data; + + data = hw_read_20kx(hw, GPIO_DATA); + switch (type) { + case ADC_MICIN: + data |= (0x1 << 14); + hw_write_20kx(hw, GPIO_DATA, data); + hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x101), + MAKE_WM8775_DATA(0x101)); /* Mic-in */ + hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, 0xE7), + MAKE_WM8775_DATA(0xE7)); /* +12dB boost */ + hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, 0xE7), + MAKE_WM8775_DATA(0xE7)); /* +12dB boost */ + break; + case ADC_LINEIN: + data &= ~(0x1 << 14); + hw_write_20kx(hw, GPIO_DATA, data); + hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x102), + MAKE_WM8775_DATA(0x102)); /* Line-in */ + hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, 0xCF), + MAKE_WM8775_DATA(0xCF)); /* No boost */ + hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, 0xCF), + MAKE_WM8775_DATA(0xCF)); /* No boost */ + break; + default: + break; + } + + return 0; +} + +static int hw_adc_init(struct hw *hw, const struct adc_conf *info) +{ + int err; + u32 mux = 2, data, ctl; + + /* Set ADC reset bit as output */ + data = hw_read_20kx(hw, GPIO_CTRL); + data |= (0x1 << 15); + hw_write_20kx(hw, GPIO_CTRL, data); + + /* Initialize I2C */ + err = hw20k2_i2c_init(hw, 0x1A, 1, 1); + if (err < 0) { + printk(KERN_ALERT "ctxfi: Failure to acquire I2C!!!\n"); + goto error; + } + + /* Make ADC in normal operation */ + data = hw_read_20kx(hw, GPIO_DATA); + data &= ~(0x1 << 15); + mdelay(10); + data |= (0x1 << 15); + hw_write_20kx(hw, GPIO_DATA, data); + mdelay(50); + + /* Set the master mode (256fs) */ + if (1 == info->msr) { + hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_MMC, 0x02), + MAKE_WM8775_DATA(0x02)); + } else if (2 == info->msr) { + hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_MMC, 0x0A), + MAKE_WM8775_DATA(0x0A)); + } else { + printk(KERN_ALERT "ctxfi: Invalid master sampling " + "rate (msr %d)!!!\n", info->msr); + err = -EINVAL; + goto error; + } + + /* Configure GPIO bit 14 change to line-in/mic-in */ + ctl = hw_read_20kx(hw, GPIO_CTRL); + ctl |= 0x1 << 14; + hw_write_20kx(hw, GPIO_CTRL, ctl); + + /* Check using Mic-in or Line-in */ + data = hw_read_20kx(hw, GPIO_DATA); + + if (mux == 1) { + /* Configures GPIO data to select Mic-in */ + data |= 0x1 << 14; + hw_write_20kx(hw, GPIO_DATA, data); + + hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x101), + MAKE_WM8775_DATA(0x101)); /* Mic-in */ + hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, 0xE7), + MAKE_WM8775_DATA(0xE7)); /* +12dB boost */ + hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, 0xE7), + MAKE_WM8775_DATA(0xE7)); /* +12dB boost */ + } else if (mux == 2) { + /* Configures GPIO data to select Line-in */ + data &= ~(0x1 << 14); + hw_write_20kx(hw, GPIO_DATA, data); + + /* Setup ADC */ + hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x102), + MAKE_WM8775_DATA(0x102)); /* Line-in */ + hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, 0xCF), + MAKE_WM8775_DATA(0xCF)); /* No boost */ + hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, 0xCF), + MAKE_WM8775_DATA(0xCF)); /* No boost */ + } else { + printk(KERN_ALERT "ctxfi: ERROR!!! Invalid input mux!!!\n"); + err = -EINVAL; + goto error; + } + + return 0; + +error: + hw20k2_i2c_uninit(hw); + return err; +} + +static int hw_have_digit_io_switch(struct hw *hw) +{ + return 0; +} + +static int hw_card_start(struct hw *hw) +{ + int err = 0; + struct pci_dev *pci = hw->pci; + unsigned int gctl; + + err = pci_enable_device(pci); + if (err < 0) + return err; + + /* Set DMA transfer mask */ + if (pci_set_dma_mask(pci, CT_XFI_DMA_MASK) < 0 || + pci_set_consistent_dma_mask(pci, CT_XFI_DMA_MASK) < 0) { + printk(KERN_ERR "ctxfi: architecture does not support PCI " + "busmaster DMA with mask 0x%llx\n", CT_XFI_DMA_MASK); + err = -ENXIO; + goto error1; + } + + if (!hw->io_base) { + err = pci_request_regions(pci, "XFi"); + if (err < 0) + goto error1; + + hw->io_base = pci_resource_start(hw->pci, 2); + hw->mem_base = (unsigned long)ioremap(hw->io_base, + pci_resource_len(hw->pci, 2)); + if (NULL == (void *)hw->mem_base) { + err = -ENOENT; + goto error2; + } + } + + /* Switch to 20k2 mode from UAA mode. */ + gctl = hw_read_20kx(hw, GLOBAL_CNTL_GCTL); + set_field(&gctl, GCTL_UAA, 0); + hw_write_20kx(hw, GLOBAL_CNTL_GCTL, gctl); + + /*if ((err = request_irq(pci->irq, ct_atc_interrupt, IRQF_SHARED, + atc->chip_details->nm_card, hw))) { + goto error3; + } + hw->irq = pci->irq; + */ + + pci_set_master(pci); + + return 0; + +/*error3: + iounmap((void *)hw->mem_base); + hw->mem_base = (unsigned long)NULL;*/ +error2: + pci_release_regions(pci); + hw->io_base = 0; +error1: + pci_disable_device(pci); + return err; +} + +static int hw_card_stop(struct hw *hw) +{ + unsigned int data; + + /* disable transport bus master and queueing of request */ + hw_write_20kx(hw, TRANSPORT_CTL, 0x00); + + /* disable pll */ + data = hw_read_20kx(hw, PLL_ENB); + hw_write_20kx(hw, PLL_ENB, (data & (~0x07))); + + /* TODO: Disable interrupt and so on... */ + return 0; +} + +static int hw_card_shutdown(struct hw *hw) +{ + if (hw->irq >= 0) + free_irq(hw->irq, hw); + + hw->irq = -1; + + if (NULL != ((void *)hw->mem_base)) + iounmap((void *)hw->mem_base); + + hw->mem_base = (unsigned long)NULL; + + if (hw->io_base) + pci_release_regions(hw->pci); + + hw->io_base = 0; + + pci_disable_device(hw->pci); + + return 0; +} + +static int hw_card_init(struct hw *hw, struct card_conf *info) +{ + int err; + unsigned int gctl; + u32 data = 0; + struct dac_conf dac_info = {0}; + struct adc_conf adc_info = {0}; + struct daio_conf daio_info = {0}; + struct trn_conf trn_info = {0}; + + /* Get PCI io port/memory base address and + * do 20kx core switch if needed. */ + err = hw_card_start(hw); + if (err) + return err; + + /* PLL init */ + err = hw_pll_init(hw, info->rsr); + if (err < 0) + return err; + + /* kick off auto-init */ + err = hw_auto_init(hw); + if (err < 0) + return err; + + gctl = hw_read_20kx(hw, GLOBAL_CNTL_GCTL); + set_field(&gctl, GCTL_DBP, 1); + set_field(&gctl, GCTL_TBP, 1); + set_field(&gctl, GCTL_FBP, 1); + set_field(&gctl, GCTL_DPC, 0); + hw_write_20kx(hw, GLOBAL_CNTL_GCTL, gctl); + + /* Reset all global pending interrupts */ + hw_write_20kx(hw, INTERRUPT_GIE, 0); + /* Reset all SRC pending interrupts */ + hw_write_20kx(hw, SRC_IP, 0); + + /* TODO: detect the card ID and configure GPIO accordingly. */ + /* Configures GPIO (0xD802 0x98028) */ + /*hw_write_20kx(hw, GPIO_CTRL, 0x7F07);*/ + /* Configures GPIO (SB0880) */ + /*hw_write_20kx(hw, GPIO_CTRL, 0xFF07);*/ + hw_write_20kx(hw, GPIO_CTRL, 0xD802); + + /* Enable audio ring */ + hw_write_20kx(hw, MIXER_AR_ENABLE, 0x01); + + trn_info.vm_pgt_phys = info->vm_pgt_phys; + err = hw_trn_init(hw, &trn_info); + if (err < 0) + return err; + + daio_info.msr = info->msr; + err = hw_daio_init(hw, &daio_info); + if (err < 0) + return err; + + dac_info.msr = info->msr; + err = hw_dac_init(hw, &dac_info); + if (err < 0) + return err; + + adc_info.msr = info->msr; + adc_info.input = ADC_LINEIN; + adc_info.mic20db = 0; + err = hw_adc_init(hw, &adc_info); + if (err < 0) + return err; + + data = hw_read_20kx(hw, SRC_MCTL); + data |= 0x1; /* Enables input from the audio ring */ + hw_write_20kx(hw, SRC_MCTL, data); + + return 0; +} + +#ifdef CONFIG_PM +static int hw_suspend(struct hw *hw, pm_message_t state) +{ + struct pci_dev *pci = hw->pci; + + hw_card_stop(hw); + + pci_disable_device(pci); + pci_save_state(pci); + pci_set_power_state(pci, pci_choose_state(pci, state)); + + return 0; +} + +static int hw_resume(struct hw *hw, struct card_conf *info) +{ + struct pci_dev *pci = hw->pci; + + pci_set_power_state(pci, PCI_D0); + pci_restore_state(pci); + + /* Re-initialize card hardware. */ + return hw_card_init(hw, info); +} +#endif + +static u32 hw_read_20kx(struct hw *hw, u32 reg) +{ + return readl((void *)(hw->mem_base + reg)); +} + +static void hw_write_20kx(struct hw *hw, u32 reg, u32 data) +{ + writel(data, (void *)(hw->mem_base + reg)); +} + +static struct hw ct20k2_preset __devinitdata = { + .irq = -1, + + .card_init = hw_card_init, + .card_stop = hw_card_stop, + .pll_init = hw_pll_init, + .is_adc_source_selected = hw_is_adc_input_selected, + .select_adc_source = hw_adc_input_select, + .have_digit_io_switch = hw_have_digit_io_switch, +#ifdef CONFIG_PM + .suspend = hw_suspend, + .resume = hw_resume, +#endif + + .src_rsc_get_ctrl_blk = src_get_rsc_ctrl_blk, + .src_rsc_put_ctrl_blk = src_put_rsc_ctrl_blk, + .src_mgr_get_ctrl_blk = src_mgr_get_ctrl_blk, + .src_mgr_put_ctrl_blk = src_mgr_put_ctrl_blk, + .src_set_state = src_set_state, + .src_set_bm = src_set_bm, + .src_set_rsr = src_set_rsr, + .src_set_sf = src_set_sf, + .src_set_wr = src_set_wr, + .src_set_pm = src_set_pm, + .src_set_rom = src_set_rom, + .src_set_vo = src_set_vo, + .src_set_st = src_set_st, + .src_set_ie = src_set_ie, + .src_set_ilsz = src_set_ilsz, + .src_set_bp = src_set_bp, + .src_set_cisz = src_set_cisz, + .src_set_ca = src_set_ca, + .src_set_sa = src_set_sa, + .src_set_la = src_set_la, + .src_set_pitch = src_set_pitch, + .src_set_dirty = src_set_dirty, + .src_set_clear_zbufs = src_set_clear_zbufs, + .src_set_dirty_all = src_set_dirty_all, + .src_commit_write = src_commit_write, + .src_get_ca = src_get_ca, + .src_get_dirty = src_get_dirty, + .src_dirty_conj_mask = src_dirty_conj_mask, + .src_mgr_enbs_src = src_mgr_enbs_src, + .src_mgr_enb_src = src_mgr_enb_src, + .src_mgr_dsb_src = src_mgr_dsb_src, + .src_mgr_commit_write = src_mgr_commit_write, + + .srcimp_mgr_get_ctrl_blk = srcimp_mgr_get_ctrl_blk, + .srcimp_mgr_put_ctrl_blk = srcimp_mgr_put_ctrl_blk, + .srcimp_mgr_set_imaparc = srcimp_mgr_set_imaparc, + .srcimp_mgr_set_imapuser = srcimp_mgr_set_imapuser, + .srcimp_mgr_set_imapnxt = srcimp_mgr_set_imapnxt, + .srcimp_mgr_set_imapaddr = srcimp_mgr_set_imapaddr, + .srcimp_mgr_commit_write = srcimp_mgr_commit_write, + + .amixer_rsc_get_ctrl_blk = amixer_rsc_get_ctrl_blk, + .amixer_rsc_put_ctrl_blk = amixer_rsc_put_ctrl_blk, + .amixer_mgr_get_ctrl_blk = amixer_mgr_get_ctrl_blk, + .amixer_mgr_put_ctrl_blk = amixer_mgr_put_ctrl_blk, + .amixer_set_mode = amixer_set_mode, + .amixer_set_iv = amixer_set_iv, + .amixer_set_x = amixer_set_x, + .amixer_set_y = amixer_set_y, + .amixer_set_sadr = amixer_set_sadr, + .amixer_set_se = amixer_set_se, + .amixer_set_dirty = amixer_set_dirty, + .amixer_set_dirty_all = amixer_set_dirty_all, + .amixer_commit_write = amixer_commit_write, + .amixer_get_y = amixer_get_y, + .amixer_get_dirty = amixer_get_dirty, + + .dai_get_ctrl_blk = dai_get_ctrl_blk, + .dai_put_ctrl_blk = dai_put_ctrl_blk, + .dai_srt_set_srco = dai_srt_set_srco, + .dai_srt_set_srcm = dai_srt_set_srcm, + .dai_srt_set_rsr = dai_srt_set_rsr, + .dai_srt_set_drat = dai_srt_set_drat, + .dai_srt_set_ec = dai_srt_set_ec, + .dai_srt_set_et = dai_srt_set_et, + .dai_commit_write = dai_commit_write, + + .dao_get_ctrl_blk = dao_get_ctrl_blk, + .dao_put_ctrl_blk = dao_put_ctrl_blk, + .dao_set_spos = dao_set_spos, + .dao_commit_write = dao_commit_write, + .dao_get_spos = dao_get_spos, + + .daio_mgr_get_ctrl_blk = daio_mgr_get_ctrl_blk, + .daio_mgr_put_ctrl_blk = daio_mgr_put_ctrl_blk, + .daio_mgr_enb_dai = daio_mgr_enb_dai, + .daio_mgr_dsb_dai = daio_mgr_dsb_dai, + .daio_mgr_enb_dao = daio_mgr_enb_dao, + .daio_mgr_dsb_dao = daio_mgr_dsb_dao, + .daio_mgr_dao_init = daio_mgr_dao_init, + .daio_mgr_set_imaparc = daio_mgr_set_imaparc, + .daio_mgr_set_imapnxt = daio_mgr_set_imapnxt, + .daio_mgr_set_imapaddr = daio_mgr_set_imapaddr, + .daio_mgr_commit_write = daio_mgr_commit_write, +}; + +int __devinit create_20k2_hw_obj(struct hw **rhw) +{ + struct hw20k2 *hw20k2; + + *rhw = NULL; + hw20k2 = kzalloc(sizeof(*hw20k2), GFP_KERNEL); + if (!hw20k2) + return -ENOMEM; + + hw20k2->hw = ct20k2_preset; + *rhw = &hw20k2->hw; + + return 0; +} + +int destroy_20k2_hw_obj(struct hw *hw) +{ + if (hw->io_base) + hw_card_shutdown(hw); + + kfree(hw); + return 0; +} diff --git a/sound/pci/ctxfi/cthw20k2.h b/sound/pci/ctxfi/cthw20k2.h new file mode 100644 index 000000000000..d2b7daab6815 --- /dev/null +++ b/sound/pci/ctxfi/cthw20k2.h @@ -0,0 +1,26 @@ +/** + * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. + * + * This source file is released under GPL v2 license (no other versions). + * See the COPYING file included in the main directory of this source + * distribution for the license terms and conditions. + * + * @File cthw20k2.h + * + * @Brief + * This file contains the definition of hardware access methord. + * + * @Author Liu Chun + * @Date May 13 2008 + * + */ + +#ifndef CTHW20K2_H +#define CTHW20K2_H + +#include "cthardware.h" + +int create_20k2_hw_obj(struct hw **rhw); +int destroy_20k2_hw_obj(struct hw *hw); + +#endif /* CTHW20K2_H */ diff --git a/sound/pci/ctxfi/ctimap.c b/sound/pci/ctxfi/ctimap.c new file mode 100644 index 000000000000..0b73368a4df6 --- /dev/null +++ b/sound/pci/ctxfi/ctimap.c @@ -0,0 +1,112 @@ +/** + * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. + * + * This source file is released under GPL v2 license (no other versions). + * See the COPYING file included in the main directory of this source + * distribution for the license terms and conditions. + * + * @File ctimap.c + * + * @Brief + * This file contains the implementation of generic input mapper operations + * for input mapper management. + * + * @Author Liu Chun + * @Date May 23 2008 + * + */ + +#include "ctimap.h" +#include + +int input_mapper_add(struct list_head *mappers, struct imapper *entry, + int (*map_op)(void *, struct imapper *), void *data) +{ + struct list_head *pos, *pre, *head; + struct imapper *pre_ent, *pos_ent; + + head = mappers; + + if (list_empty(head)) { + entry->next = entry->addr; + map_op(data, entry); + list_add(&entry->list, head); + return 0; + } + + list_for_each(pos, head) { + pos_ent = list_entry(pos, struct imapper, list); + if (pos_ent->slot > entry->slot) { + /* found a position in list */ + break; + } + } + + if (pos != head) { + pre = pos->prev; + if (pre == head) + pre = head->prev; + + __list_add(&entry->list, pos->prev, pos); + } else { + pre = head->prev; + pos = head->next; + list_add_tail(&entry->list, head); + } + + pre_ent = list_entry(pre, struct imapper, list); + pos_ent = list_entry(pos, struct imapper, list); + + entry->next = pos_ent->addr; + map_op(data, entry); + pre_ent->next = entry->addr; + map_op(data, pre_ent); + + return 0; +} + +int input_mapper_delete(struct list_head *mappers, struct imapper *entry, + int (*map_op)(void *, struct imapper *), void *data) +{ + struct list_head *next, *pre, *head; + struct imapper *pre_ent, *next_ent; + + head = mappers; + + if (list_empty(head)) + return 0; + + pre = (entry->list.prev == head) ? head->prev : entry->list.prev; + next = (entry->list.next == head) ? head->next : entry->list.next; + + if (pre == &entry->list) { + /* entry is the only one node in mappers list */ + entry->next = entry->addr = entry->user = entry->slot = 0; + map_op(data, entry); + list_del(&entry->list); + return 0; + } + + pre_ent = list_entry(pre, struct imapper, list); + next_ent = list_entry(next, struct imapper, list); + + pre_ent->next = next_ent->addr; + map_op(data, pre_ent); + list_del(&entry->list); + + return 0; +} + +void free_input_mapper_list(struct list_head *head) +{ + struct imapper *entry; + struct list_head *pos; + + while (!list_empty(head)) { + pos = head->next; + list_del(pos); + entry = list_entry(pos, struct imapper, list); + kfree(entry); + } +} + diff --git a/sound/pci/ctxfi/ctimap.h b/sound/pci/ctxfi/ctimap.h new file mode 100644 index 000000000000..53ccf9be8b68 --- /dev/null +++ b/sound/pci/ctxfi/ctimap.h @@ -0,0 +1,40 @@ +/** + * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. + * + * This source file is released under GPL v2 license (no other versions). + * See the COPYING file included in the main directory of this source + * distribution for the license terms and conditions. + * + * @File ctimap.h + * + * @Brief + * This file contains the definition of generic input mapper operations + * for input mapper management. + * + * @Author Liu Chun + * @Date May 23 2008 + * + */ + +#ifndef CTIMAP_H +#define CTIMAP_H + +#include + +struct imapper { + unsigned short slot; /* the id of the slot containing input data */ + unsigned short user; /* the id of the user resource consuming data */ + unsigned short addr; /* the input mapper ram id */ + unsigned short next; /* the next input mapper ram id */ + struct list_head list; +}; + +int input_mapper_add(struct list_head *mappers, struct imapper *entry, + int (*map_op)(void *, struct imapper *), void *data); + +int input_mapper_delete(struct list_head *mappers, struct imapper *entry, + int (*map_op)(void *, struct imapper *), void *data); + +void free_input_mapper_list(struct list_head *mappers); + +#endif /* CTIMAP_H */ diff --git a/sound/pci/ctxfi/ctmixer.c b/sound/pci/ctxfi/ctmixer.c new file mode 100644 index 000000000000..f26d7cd9db9f --- /dev/null +++ b/sound/pci/ctxfi/ctmixer.c @@ -0,0 +1,1157 @@ +/** + * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. + * + * This source file is released under GPL v2 license (no other versions). + * See the COPYING file included in the main directory of this source + * distribution for the license terms and conditions. + * + * @File ctmixer.c + * + * @Brief + * This file contains the implementation of alsa mixer device functions. + * + * @Author Liu Chun + * @Date May 28 2008 + * + */ + + +#include "ctmixer.h" +#include "ctamixer.h" +#include +#include +#include +#include +#include +#include + +enum CT_SUM_CTL { + SUM_IN_F, + SUM_IN_R, + SUM_IN_C, + SUM_IN_S, + SUM_IN_F_C, + + NUM_CT_SUMS +}; + +enum CT_AMIXER_CTL { + /* volume control mixers */ + AMIXER_MASTER_F, + AMIXER_MASTER_R, + AMIXER_MASTER_C, + AMIXER_MASTER_S, + AMIXER_PCM_F, + AMIXER_PCM_R, + AMIXER_PCM_C, + AMIXER_PCM_S, + AMIXER_SPDIFI, + AMIXER_LINEIN, + AMIXER_MIC, + AMIXER_SPDIFO, + AMIXER_WAVE_F, + AMIXER_WAVE_R, + AMIXER_WAVE_C, + AMIXER_WAVE_S, + AMIXER_MASTER_F_C, + AMIXER_PCM_F_C, + AMIXER_SPDIFI_C, + AMIXER_LINEIN_C, + AMIXER_MIC_C, + + /* this should always be the last one */ + NUM_CT_AMIXERS +}; + +enum CTALSA_MIXER_CTL { + /* volume control mixers */ + MIXER_MASTER_P, + MIXER_PCM_P, + MIXER_LINEIN_P, + MIXER_MIC_P, + MIXER_SPDIFI_P, + MIXER_SPDIFO_P, + MIXER_WAVEF_P, + MIXER_WAVER_P, + MIXER_WAVEC_P, + MIXER_WAVES_P, + MIXER_MASTER_C, + MIXER_PCM_C, + MIXER_LINEIN_C, + MIXER_MIC_C, + MIXER_SPDIFI_C, + + /* switch control mixers */ + MIXER_PCM_C_S, + MIXER_LINEIN_C_S, + MIXER_MIC_C_S, + MIXER_SPDIFI_C_S, + MIXER_LINEIN_P_S, + MIXER_SPDIFO_P_S, + MIXER_SPDIFI_P_S, + MIXER_WAVEF_P_S, + MIXER_WAVER_P_S, + MIXER_WAVEC_P_S, + MIXER_WAVES_P_S, + MIXER_DIGITAL_IO_S, + MIXER_IEC958_MASK, + MIXER_IEC958_DEFAULT, + MIXER_IEC958_STREAM, + + /* this should always be the last one */ + NUM_CTALSA_MIXERS +}; + +#define VOL_MIXER_START MIXER_MASTER_P +#define VOL_MIXER_END MIXER_SPDIFI_C +#define VOL_MIXER_NUM (VOL_MIXER_END - VOL_MIXER_START + 1) +#define SWH_MIXER_START MIXER_PCM_C_S +#define SWH_MIXER_END MIXER_DIGITAL_IO_S +#define SWH_CAPTURE_START MIXER_PCM_C_S +#define SWH_CAPTURE_END MIXER_SPDIFI_C_S + +#define CHN_NUM 2 + +struct ct_kcontrol_init { + unsigned char ctl; + char *name; +}; + +static struct ct_kcontrol_init +ct_kcontrol_init_table[NUM_CTALSA_MIXERS] = { + [MIXER_MASTER_P] = { + .ctl = 1, + .name = "Master Playback Volume", + }, + [MIXER_MASTER_C] = { + .ctl = 1, + .name = "Master Capture Volume", + }, + [MIXER_PCM_P] = { + .ctl = 1, + .name = "PCM Playback Volume", + }, + [MIXER_PCM_C] = { + .ctl = 1, + .name = "PCM Capture Volume", + }, + [MIXER_LINEIN_P] = { + .ctl = 1, + .name = "Line-in Playback Volume", + }, + [MIXER_LINEIN_C] = { + .ctl = 1, + .name = "Line-in Capture Volume", + }, + [MIXER_MIC_P] = { + .ctl = 1, + .name = "Mic Playback Volume", + }, + [MIXER_MIC_C] = { + .ctl = 1, + .name = "Mic Capture Volume", + }, + [MIXER_SPDIFI_P] = { + .ctl = 1, + .name = "S/PDIF-in Playback Volume", + }, + [MIXER_SPDIFI_C] = { + .ctl = 1, + .name = "S/PDIF-in Capture Volume", + }, + [MIXER_SPDIFO_P] = { + .ctl = 1, + .name = "S/PDIF-out Playback Volume", + }, + [MIXER_WAVEF_P] = { + .ctl = 1, + .name = "Front Playback Volume", + }, + [MIXER_WAVES_P] = { + .ctl = 1, + .name = "Side Playback Volume", + }, + [MIXER_WAVEC_P] = { + .ctl = 1, + .name = "Center/LFE Playback Volume", + }, + [MIXER_WAVER_P] = { + .ctl = 1, + .name = "Surround Playback Volume", + }, + + [MIXER_PCM_C_S] = { + .ctl = 1, + .name = "PCM Capture Switch", + }, + [MIXER_LINEIN_C_S] = { + .ctl = 1, + .name = "Line-in Capture Switch", + }, + [MIXER_MIC_C_S] = { + .ctl = 1, + .name = "Mic Capture Switch", + }, + [MIXER_SPDIFI_C_S] = { + .ctl = 1, + .name = "S/PDIF-in Capture Switch", + }, + [MIXER_LINEIN_P_S] = { + .ctl = 1, + .name = "Line-in Playback Switch", + }, + [MIXER_SPDIFO_P_S] = { + .ctl = 1, + .name = "S/PDIF-out Playback Switch", + }, + [MIXER_SPDIFI_P_S] = { + .ctl = 1, + .name = "S/PDIF-in Playback Switch", + }, + [MIXER_WAVEF_P_S] = { + .ctl = 1, + .name = "Front Playback Switch", + }, + [MIXER_WAVES_P_S] = { + .ctl = 1, + .name = "Side Playback Switch", + }, + [MIXER_WAVEC_P_S] = { + .ctl = 1, + .name = "Center/LFE Playback Switch", + }, + [MIXER_WAVER_P_S] = { + .ctl = 1, + .name = "Surround Playback Switch", + }, + [MIXER_DIGITAL_IO_S] = { + .ctl = 0, + .name = "Digit-IO Playback Switch", + }, +}; + +static void +ct_mixer_recording_select(struct ct_mixer *mixer, enum CT_AMIXER_CTL type); + +static void +ct_mixer_recording_unselect(struct ct_mixer *mixer, enum CT_AMIXER_CTL type); + +static struct snd_kcontrol *kctls[2] = {NULL}; + +static enum CT_AMIXER_CTL get_amixer_index(enum CTALSA_MIXER_CTL alsa_index) +{ + switch (alsa_index) { + case MIXER_MASTER_P: return AMIXER_MASTER_F; + case MIXER_MASTER_C: return AMIXER_MASTER_F_C; + case MIXER_PCM_P: return AMIXER_PCM_F; + case MIXER_PCM_C: + case MIXER_PCM_C_S: return AMIXER_PCM_F_C; + case MIXER_LINEIN_P: return AMIXER_LINEIN; + case MIXER_LINEIN_C: + case MIXER_LINEIN_C_S: return AMIXER_LINEIN_C; + case MIXER_MIC_P: return AMIXER_MIC; + case MIXER_MIC_C: + case MIXER_MIC_C_S: return AMIXER_MIC_C; + case MIXER_SPDIFI_P: return AMIXER_SPDIFI; + case MIXER_SPDIFI_C: + case MIXER_SPDIFI_C_S: return AMIXER_SPDIFI_C; + case MIXER_SPDIFO_P: return AMIXER_SPDIFO; + case MIXER_WAVEF_P: return AMIXER_WAVE_F; + case MIXER_WAVES_P: return AMIXER_WAVE_S; + case MIXER_WAVEC_P: return AMIXER_WAVE_C; + case MIXER_WAVER_P: return AMIXER_WAVE_R; + default: return NUM_CT_AMIXERS; + } +} + +static enum CT_AMIXER_CTL get_recording_amixer(enum CT_AMIXER_CTL index) +{ + switch (index) { + case AMIXER_MASTER_F: return AMIXER_MASTER_F_C; + case AMIXER_PCM_F: return AMIXER_PCM_F_C; + case AMIXER_SPDIFI: return AMIXER_SPDIFI_C; + case AMIXER_LINEIN: return AMIXER_LINEIN_C; + case AMIXER_MIC: return AMIXER_MIC_C; + default: return NUM_CT_AMIXERS; + } +} + +static unsigned char +get_switch_state(struct ct_mixer *mixer, enum CTALSA_MIXER_CTL type) +{ + return (mixer->switch_state & (0x1 << (type - SWH_MIXER_START))) + ? 1 : 0; +} + +static void +set_switch_state(struct ct_mixer *mixer, + enum CTALSA_MIXER_CTL type, unsigned char state) +{ + if (state) + mixer->switch_state |= (0x1 << (type - SWH_MIXER_START)); + else + mixer->switch_state &= ~(0x1 << (type - SWH_MIXER_START)); +} + +#if 0 /* not used */ +/* Map integer value ranging from 0 to 65535 to 14-bit float value ranging + * from 2^-6 to (1+1023/1024) */ +static unsigned int uint16_to_float14(unsigned int x) +{ + unsigned int i; + + if (x < 17) + return 0; + + x *= 2031; + x /= 65535; + x += 16; + + /* i <= 6 */ + for (i = 0; !(x & 0x400); i++) + x <<= 1; + + x = (((7 - i) & 0x7) << 10) | (x & 0x3ff); + + return x; +} + +static unsigned int float14_to_uint16(unsigned int x) +{ + unsigned int e; + + if (!x) + return x; + + e = (x >> 10) & 0x7; + x &= 0x3ff; + x += 1024; + x >>= (7 - e); + x -= 16; + x *= 65535; + x /= 2031; + + return x; +} +#endif /* not used */ + +#define VOL_SCALE 0x1c +#define VOL_MAX 0x100 + +static const DECLARE_TLV_DB_SCALE(ct_vol_db_scale, -6400, 25, 1); + +static int ct_alsa_mix_volume_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 2; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = VOL_MAX; + + return 0; +} + +static int ct_alsa_mix_volume_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct ct_atc *atc = snd_kcontrol_chip(kcontrol); + enum CT_AMIXER_CTL type = get_amixer_index(kcontrol->private_value); + struct amixer *amixer; + int i, val; + + for (i = 0; i < 2; i++) { + amixer = ((struct ct_mixer *)atc->mixer)-> + amixers[type*CHN_NUM+i]; + val = amixer->ops->get_scale(amixer) / VOL_SCALE; + if (val < 0) + val = 0; + else if (val > VOL_MAX) + val = VOL_MAX; + ucontrol->value.integer.value[i] = val; + } + + return 0; +} + +static int ct_alsa_mix_volume_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct ct_atc *atc = snd_kcontrol_chip(kcontrol); + struct ct_mixer *mixer = atc->mixer; + enum CT_AMIXER_CTL type = get_amixer_index(kcontrol->private_value); + struct amixer *amixer; + int i, j, val, oval, change = 0; + + for (i = 0; i < 2; i++) { + val = ucontrol->value.integer.value[i]; + if (val < 0) + val = 0; + else if (val > VOL_MAX) + val = VOL_MAX; + val *= VOL_SCALE; + amixer = mixer->amixers[type*CHN_NUM+i]; + oval = amixer->ops->get_scale(amixer); + if (val != oval) { + amixer->ops->set_scale(amixer, val); + amixer->ops->commit_write(amixer); + change = 1; + /* Synchronize Master/PCM playback AMIXERs. */ + if (AMIXER_MASTER_F == type || AMIXER_PCM_F == type) { + for (j = 1; j < 4; j++) { + amixer = mixer-> + amixers[(type+j)*CHN_NUM+i]; + amixer->ops->set_scale(amixer, val); + amixer->ops->commit_write(amixer); + } + } + } + } + + return change; +} + +static struct snd_kcontrol_new vol_ctl = { + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ, + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .info = ct_alsa_mix_volume_info, + .get = ct_alsa_mix_volume_get, + .put = ct_alsa_mix_volume_put, + .tlv = { .p = ct_vol_db_scale }, +}; + +static void +do_line_mic_switch(struct ct_atc *atc, enum CTALSA_MIXER_CTL type) +{ + + if (MIXER_LINEIN_C_S == type) { + atc->select_line_in(atc); + set_switch_state(atc->mixer, MIXER_MIC_C_S, 0); + snd_ctl_notify(atc->card, SNDRV_CTL_EVENT_MASK_VALUE, + &kctls[1]->id); + } else if (MIXER_MIC_C_S == type) { + atc->select_mic_in(atc); + set_switch_state(atc->mixer, MIXER_LINEIN_C_S, 0); + snd_ctl_notify(atc->card, SNDRV_CTL_EVENT_MASK_VALUE, + &kctls[0]->id); + } +} + +static void +do_digit_io_switch(struct ct_atc *atc, int state) +{ + struct ct_mixer *mixer = atc->mixer; + + if (state) { + atc->select_digit_io(atc); + atc->spdif_out_unmute(atc, + get_switch_state(mixer, MIXER_SPDIFO_P_S)); + atc->spdif_in_unmute(atc, 1); + atc->line_in_unmute(atc, 0); + return; + } + + if (get_switch_state(mixer, MIXER_LINEIN_C_S)) + atc->select_line_in(atc); + else if (get_switch_state(mixer, MIXER_MIC_C_S)) + atc->select_mic_in(atc); + + atc->spdif_out_unmute(atc, 0); + atc->spdif_in_unmute(atc, 0); + atc->line_in_unmute(atc, 1); + return; +} + +static void do_switch(struct ct_atc *atc, enum CTALSA_MIXER_CTL type, int state) +{ + struct ct_mixer *mixer = atc->mixer; + + /* Do changes in mixer. */ + if ((SWH_CAPTURE_START <= type) && (SWH_CAPTURE_END >= type)) { + if (state) { + ct_mixer_recording_select(mixer, + get_amixer_index(type)); + } else { + ct_mixer_recording_unselect(mixer, + get_amixer_index(type)); + } + } + /* Do changes out of mixer. */ + if (state && (MIXER_LINEIN_C_S == type || MIXER_MIC_C_S == type)) + do_line_mic_switch(atc, type); + else if (MIXER_WAVEF_P_S == type) + atc->line_front_unmute(atc, state); + else if (MIXER_WAVES_P_S == type) + atc->line_surround_unmute(atc, state); + else if (MIXER_WAVEC_P_S == type) + atc->line_clfe_unmute(atc, state); + else if (MIXER_WAVER_P_S == type) + atc->line_rear_unmute(atc, state); + else if (MIXER_LINEIN_P_S == type) + atc->line_in_unmute(atc, state); + else if (MIXER_SPDIFO_P_S == type) + atc->spdif_out_unmute(atc, state); + else if (MIXER_SPDIFI_P_S == type) + atc->spdif_in_unmute(atc, state); + else if (MIXER_DIGITAL_IO_S == type) + do_digit_io_switch(atc, state); + + return; +} + +static int ct_alsa_mix_switch_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + uinfo->value.integer.step = 1; + + return 0; +} + +static int ct_alsa_mix_switch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct ct_mixer *mixer = + ((struct ct_atc *)snd_kcontrol_chip(kcontrol))->mixer; + enum CTALSA_MIXER_CTL type = kcontrol->private_value; + + ucontrol->value.integer.value[0] = get_switch_state(mixer, type); + return 0; +} + +static int ct_alsa_mix_switch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct ct_atc *atc = snd_kcontrol_chip(kcontrol); + struct ct_mixer *mixer = atc->mixer; + enum CTALSA_MIXER_CTL type = kcontrol->private_value; + int state; + + state = ucontrol->value.integer.value[0]; + if (get_switch_state(mixer, type) == state) + return 0; + + set_switch_state(mixer, type, state); + do_switch(atc, type, state); + + return 1; +} + +static struct snd_kcontrol_new swh_ctl = { + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .info = ct_alsa_mix_switch_info, + .get = ct_alsa_mix_switch_get, + .put = ct_alsa_mix_switch_put +}; + +static int ct_spdif_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; + uinfo->count = 1; + return 0; +} + +static int ct_spdif_get_mask(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.iec958.status[0] = 0xff; + ucontrol->value.iec958.status[1] = 0xff; + ucontrol->value.iec958.status[2] = 0xff; + ucontrol->value.iec958.status[3] = 0xff; + return 0; +} + +static int ct_spdif_default_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + unsigned int status = SNDRV_PCM_DEFAULT_CON_SPDIF; + + ucontrol->value.iec958.status[0] = (status >> 0) & 0xff; + ucontrol->value.iec958.status[1] = (status >> 8) & 0xff; + ucontrol->value.iec958.status[2] = (status >> 16) & 0xff; + ucontrol->value.iec958.status[3] = (status >> 24) & 0xff; + + return 0; +} + +static int ct_spdif_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct ct_atc *atc = snd_kcontrol_chip(kcontrol); + unsigned int status; + + atc->spdif_out_get_status(atc, &status); + ucontrol->value.iec958.status[0] = (status >> 0) & 0xff; + ucontrol->value.iec958.status[1] = (status >> 8) & 0xff; + ucontrol->value.iec958.status[2] = (status >> 16) & 0xff; + ucontrol->value.iec958.status[3] = (status >> 24) & 0xff; + + return 0; +} + +static int ct_spdif_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct ct_atc *atc = snd_kcontrol_chip(kcontrol); + int change; + unsigned int status, old_status; + + status = (ucontrol->value.iec958.status[0] << 0) | + (ucontrol->value.iec958.status[1] << 8) | + (ucontrol->value.iec958.status[2] << 16) | + (ucontrol->value.iec958.status[3] << 24); + + atc->spdif_out_get_status(atc, &old_status); + change = (old_status != status); + if (change) + atc->spdif_out_set_status(atc, status); + + return change; +} + +static struct snd_kcontrol_new iec958_mask_ctl = { + .access = SNDRV_CTL_ELEM_ACCESS_READ, + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK), + .count = 1, + .info = ct_spdif_info, + .get = ct_spdif_get_mask, + .private_value = MIXER_IEC958_MASK +}; + +static struct snd_kcontrol_new iec958_default_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), + .count = 1, + .info = ct_spdif_info, + .get = ct_spdif_default_get, + .put = ct_spdif_put, + .private_value = MIXER_IEC958_DEFAULT +}; + +static struct snd_kcontrol_new iec958_ctl = { + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, PCM_STREAM), + .count = 1, + .info = ct_spdif_info, + .get = ct_spdif_get, + .put = ct_spdif_put, + .private_value = MIXER_IEC958_STREAM +}; + +#define NUM_IEC958_CTL 3 + +static int +ct_mixer_kcontrol_new(struct ct_mixer *mixer, struct snd_kcontrol_new *new) +{ + struct snd_kcontrol *kctl; + int err; + + kctl = snd_ctl_new1(new, mixer->atc); + if (NULL == kctl) + return -ENOMEM; + + if (SNDRV_CTL_ELEM_IFACE_PCM == kctl->id.iface) + kctl->id.device = IEC958; + + err = snd_ctl_add(mixer->atc->card, kctl); + if (err) + return err; + + switch (new->private_value) { + case MIXER_LINEIN_C_S: + kctls[0] = kctl; break; + case MIXER_MIC_C_S: + kctls[1] = kctl; break; + default: + break; + } + + return 0; +} + +static int ct_mixer_kcontrols_create(struct ct_mixer *mixer) +{ + enum CTALSA_MIXER_CTL type; + struct ct_atc *atc = mixer->atc; + int err; + + /* Create snd kcontrol instances on demand */ + for (type = VOL_MIXER_START; type <= VOL_MIXER_END; type++) { + if (ct_kcontrol_init_table[type].ctl) { + vol_ctl.name = ct_kcontrol_init_table[type].name; + vol_ctl.private_value = (unsigned long)type; + err = ct_mixer_kcontrol_new(mixer, &vol_ctl); + if (err) + return err; + } + } + + ct_kcontrol_init_table[MIXER_DIGITAL_IO_S].ctl = + atc->have_digit_io_switch(atc); + for (type = SWH_MIXER_START; type <= SWH_MIXER_END; type++) { + if (ct_kcontrol_init_table[type].ctl) { + swh_ctl.name = ct_kcontrol_init_table[type].name; + swh_ctl.private_value = (unsigned long)type; + err = ct_mixer_kcontrol_new(mixer, &swh_ctl); + if (err) + return err; + } + } + + err = ct_mixer_kcontrol_new(mixer, &iec958_mask_ctl); + if (err) + return err; + + err = ct_mixer_kcontrol_new(mixer, &iec958_default_ctl); + if (err) + return err; + + err = ct_mixer_kcontrol_new(mixer, &iec958_ctl); + if (err) + return err; + + atc->line_front_unmute(atc, 1); + set_switch_state(mixer, MIXER_WAVEF_P_S, 1); + atc->line_surround_unmute(atc, 0); + set_switch_state(mixer, MIXER_WAVES_P_S, 0); + atc->line_clfe_unmute(atc, 0); + set_switch_state(mixer, MIXER_WAVEC_P_S, 0); + atc->line_rear_unmute(atc, 0); + set_switch_state(mixer, MIXER_WAVER_P_S, 0); + atc->spdif_out_unmute(atc, 0); + set_switch_state(mixer, MIXER_SPDIFO_P_S, 0); + atc->line_in_unmute(atc, 0); + set_switch_state(mixer, MIXER_LINEIN_P_S, 0); + atc->spdif_in_unmute(atc, 0); + set_switch_state(mixer, MIXER_SPDIFI_P_S, 0); + + set_switch_state(mixer, MIXER_PCM_C_S, 1); + set_switch_state(mixer, MIXER_LINEIN_C_S, 1); + set_switch_state(mixer, MIXER_SPDIFI_C_S, 1); + + return 0; +} + +static void +ct_mixer_recording_select(struct ct_mixer *mixer, enum CT_AMIXER_CTL type) +{ + struct amixer *amix_d; + struct sum *sum_c; + int i; + + for (i = 0; i < 2; i++) { + amix_d = mixer->amixers[type*CHN_NUM+i]; + sum_c = mixer->sums[SUM_IN_F_C*CHN_NUM+i]; + amix_d->ops->set_sum(amix_d, sum_c); + amix_d->ops->commit_write(amix_d); + } +} + +static void +ct_mixer_recording_unselect(struct ct_mixer *mixer, enum CT_AMIXER_CTL type) +{ + struct amixer *amix_d; + int i; + + for (i = 0; i < 2; i++) { + amix_d = mixer->amixers[type*CHN_NUM+i]; + amix_d->ops->set_sum(amix_d, NULL); + amix_d->ops->commit_write(amix_d); + } +} + +static int ct_mixer_get_resources(struct ct_mixer *mixer) +{ + struct sum_mgr *sum_mgr; + struct sum *sum; + struct sum_desc sum_desc = {0}; + struct amixer_mgr *amixer_mgr; + struct amixer *amixer; + struct amixer_desc am_desc = {0}; + int err; + int i; + + /* Allocate sum resources for mixer obj */ + sum_mgr = (struct sum_mgr *)mixer->atc->rsc_mgrs[SUM]; + sum_desc.msr = mixer->atc->msr; + for (i = 0; i < (NUM_CT_SUMS * CHN_NUM); i++) { + err = sum_mgr->get_sum(sum_mgr, &sum_desc, &sum); + if (err) { + printk(KERN_ERR "ctxfi:Failed to get sum resources for " + "front output!\n"); + break; + } + mixer->sums[i] = sum; + } + if (err) + goto error1; + + /* Allocate amixer resources for mixer obj */ + amixer_mgr = (struct amixer_mgr *)mixer->atc->rsc_mgrs[AMIXER]; + am_desc.msr = mixer->atc->msr; + for (i = 0; i < (NUM_CT_AMIXERS * CHN_NUM); i++) { + err = amixer_mgr->get_amixer(amixer_mgr, &am_desc, &amixer); + if (err) { + printk(KERN_ERR "ctxfi:Failed to get amixer resources " + "for mixer obj!\n"); + break; + } + mixer->amixers[i] = amixer; + } + if (err) + goto error2; + + return 0; + +error2: + for (i = 0; i < (NUM_CT_AMIXERS * CHN_NUM); i++) { + if (NULL != mixer->amixers[i]) { + amixer = mixer->amixers[i]; + amixer_mgr->put_amixer(amixer_mgr, amixer); + mixer->amixers[i] = NULL; + } + } +error1: + for (i = 0; i < (NUM_CT_SUMS * CHN_NUM); i++) { + if (NULL != mixer->sums[i]) { + sum_mgr->put_sum(sum_mgr, (struct sum *)mixer->sums[i]); + mixer->sums[i] = NULL; + } + } + + return err; +} + +static int ct_mixer_get_mem(struct ct_mixer **rmixer) +{ + struct ct_mixer *mixer; + int err; + + *rmixer = NULL; + /* Allocate mem for mixer obj */ + mixer = kzalloc(sizeof(*mixer), GFP_KERNEL); + if (NULL == mixer) + return -ENOMEM; + + mixer->amixers = kzalloc(sizeof(void *)*(NUM_CT_AMIXERS*CHN_NUM), + GFP_KERNEL); + if (NULL == mixer->amixers) { + err = -ENOMEM; + goto error1; + } + mixer->sums = kzalloc(sizeof(void *)*(NUM_CT_SUMS*CHN_NUM), GFP_KERNEL); + if (NULL == mixer->sums) { + err = -ENOMEM; + goto error2; + } + + *rmixer = mixer; + return 0; + +error2: + kfree(mixer->amixers); +error1: + kfree(mixer); + return err; +} + +static int ct_mixer_topology_build(struct ct_mixer *mixer) +{ + struct sum *sum; + struct amixer *amix_d, *amix_s; + enum CT_AMIXER_CTL i, j; + + /* Build topology from destination to source */ + + /* Set up Master mixer */ + for (i = AMIXER_MASTER_F, j = SUM_IN_F; + i <= AMIXER_MASTER_S; i++, j++) { + amix_d = mixer->amixers[i*CHN_NUM]; + sum = mixer->sums[j*CHN_NUM]; + amix_d->ops->setup(amix_d, &sum->rsc, INIT_VOL, NULL); + amix_d = mixer->amixers[i*CHN_NUM+1]; + sum = mixer->sums[j*CHN_NUM+1]; + amix_d->ops->setup(amix_d, &sum->rsc, INIT_VOL, NULL); + } + + /* Set up Wave-out mixer */ + for (i = AMIXER_WAVE_F, j = AMIXER_MASTER_F; + i <= AMIXER_WAVE_S; i++, j++) { + amix_d = mixer->amixers[i*CHN_NUM]; + amix_s = mixer->amixers[j*CHN_NUM]; + amix_d->ops->setup(amix_d, &amix_s->rsc, INIT_VOL, NULL); + amix_d = mixer->amixers[i*CHN_NUM+1]; + amix_s = mixer->amixers[j*CHN_NUM+1]; + amix_d->ops->setup(amix_d, &amix_s->rsc, INIT_VOL, NULL); + } + + /* Set up S/PDIF-out mixer */ + amix_d = mixer->amixers[AMIXER_SPDIFO*CHN_NUM]; + amix_s = mixer->amixers[AMIXER_MASTER_F*CHN_NUM]; + amix_d->ops->setup(amix_d, &amix_s->rsc, INIT_VOL, NULL); + amix_d = mixer->amixers[AMIXER_SPDIFO*CHN_NUM+1]; + amix_s = mixer->amixers[AMIXER_MASTER_F*CHN_NUM+1]; + amix_d->ops->setup(amix_d, &amix_s->rsc, INIT_VOL, NULL); + + /* Set up PCM-in mixer */ + for (i = AMIXER_PCM_F, j = SUM_IN_F; i <= AMIXER_PCM_S; i++, j++) { + amix_d = mixer->amixers[i*CHN_NUM]; + sum = mixer->sums[j*CHN_NUM]; + amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum); + amix_d = mixer->amixers[i*CHN_NUM+1]; + sum = mixer->sums[j*CHN_NUM+1]; + amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum); + } + + /* Set up Line-in mixer */ + amix_d = mixer->amixers[AMIXER_LINEIN*CHN_NUM]; + sum = mixer->sums[SUM_IN_F*CHN_NUM]; + amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum); + amix_d = mixer->amixers[AMIXER_LINEIN*CHN_NUM+1]; + sum = mixer->sums[SUM_IN_F*CHN_NUM+1]; + amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum); + + /* Set up Mic-in mixer */ + amix_d = mixer->amixers[AMIXER_MIC*CHN_NUM]; + sum = mixer->sums[SUM_IN_F*CHN_NUM]; + amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum); + amix_d = mixer->amixers[AMIXER_MIC*CHN_NUM+1]; + sum = mixer->sums[SUM_IN_F*CHN_NUM+1]; + amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum); + + /* Set up S/PDIF-in mixer */ + amix_d = mixer->amixers[AMIXER_SPDIFI*CHN_NUM]; + sum = mixer->sums[SUM_IN_F*CHN_NUM]; + amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum); + amix_d = mixer->amixers[AMIXER_SPDIFI*CHN_NUM+1]; + sum = mixer->sums[SUM_IN_F*CHN_NUM+1]; + amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum); + + /* Set up Master recording mixer */ + amix_d = mixer->amixers[AMIXER_MASTER_F_C*CHN_NUM]; + sum = mixer->sums[SUM_IN_F_C*CHN_NUM]; + amix_d->ops->setup(amix_d, &sum->rsc, INIT_VOL, NULL); + amix_d = mixer->amixers[AMIXER_MASTER_F_C*CHN_NUM+1]; + sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1]; + amix_d->ops->setup(amix_d, &sum->rsc, INIT_VOL, NULL); + + /* Set up PCM-in recording mixer */ + amix_d = mixer->amixers[AMIXER_PCM_F_C*CHN_NUM]; + sum = mixer->sums[SUM_IN_F_C*CHN_NUM]; + amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum); + amix_d = mixer->amixers[AMIXER_PCM_F_C*CHN_NUM+1]; + sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1]; + amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum); + + /* Set up Line-in recording mixer */ + amix_d = mixer->amixers[AMIXER_LINEIN_C*CHN_NUM]; + sum = mixer->sums[SUM_IN_F_C*CHN_NUM]; + amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum); + amix_d = mixer->amixers[AMIXER_LINEIN_C*CHN_NUM+1]; + sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1]; + amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum); + + /* Set up Mic-in recording mixer */ + amix_d = mixer->amixers[AMIXER_MIC_C*CHN_NUM]; + sum = mixer->sums[SUM_IN_F_C*CHN_NUM]; + amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum); + amix_d = mixer->amixers[AMIXER_MIC_C*CHN_NUM+1]; + sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1]; + amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum); + + /* Set up S/PDIF-in recording mixer */ + amix_d = mixer->amixers[AMIXER_SPDIFI_C*CHN_NUM]; + sum = mixer->sums[SUM_IN_F_C*CHN_NUM]; + amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum); + amix_d = mixer->amixers[AMIXER_SPDIFI_C*CHN_NUM+1]; + sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1]; + amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum); + + return 0; +} + +static int mixer_set_input_port(struct amixer *amixer, struct rsc *rsc) +{ + amixer->ops->set_input(amixer, rsc); + amixer->ops->commit_write(amixer); + + return 0; +} + +static enum CT_AMIXER_CTL port_to_amixer(enum MIXER_PORT_T type) +{ + switch (type) { + case MIX_WAVE_FRONT: return AMIXER_WAVE_F; + case MIX_WAVE_SURROUND: return AMIXER_WAVE_S; + case MIX_WAVE_CENTLFE: return AMIXER_WAVE_C; + case MIX_WAVE_REAR: return AMIXER_WAVE_R; + case MIX_PCMO_FRONT: return AMIXER_MASTER_F_C; + case MIX_SPDIF_OUT: return AMIXER_SPDIFO; + case MIX_LINE_IN: return AMIXER_LINEIN; + case MIX_MIC_IN: return AMIXER_MIC; + case MIX_SPDIF_IN: return AMIXER_SPDIFI; + case MIX_PCMI_FRONT: return AMIXER_PCM_F; + case MIX_PCMI_SURROUND: return AMIXER_PCM_S; + case MIX_PCMI_CENTLFE: return AMIXER_PCM_C; + case MIX_PCMI_REAR: return AMIXER_PCM_R; + default: return 0; + } +} + +static int mixer_get_output_ports(struct ct_mixer *mixer, + enum MIXER_PORT_T type, + struct rsc **rleft, struct rsc **rright) +{ + enum CT_AMIXER_CTL amix = port_to_amixer(type); + + if (NULL != rleft) + *rleft = &((struct amixer *)mixer->amixers[amix*CHN_NUM])->rsc; + + if (NULL != rright) + *rright = + &((struct amixer *)mixer->amixers[amix*CHN_NUM+1])->rsc; + + return 0; +} + +static int mixer_set_input_left(struct ct_mixer *mixer, + enum MIXER_PORT_T type, struct rsc *rsc) +{ + enum CT_AMIXER_CTL amix = port_to_amixer(type); + + mixer_set_input_port(mixer->amixers[amix*CHN_NUM], rsc); + amix = get_recording_amixer(amix); + if (amix < NUM_CT_AMIXERS) + mixer_set_input_port(mixer->amixers[amix*CHN_NUM], rsc); + + return 0; +} + +static int +mixer_set_input_right(struct ct_mixer *mixer, + enum MIXER_PORT_T type, struct rsc *rsc) +{ + enum CT_AMIXER_CTL amix = port_to_amixer(type); + + mixer_set_input_port(mixer->amixers[amix*CHN_NUM+1], rsc); + amix = get_recording_amixer(amix); + if (amix < NUM_CT_AMIXERS) + mixer_set_input_port(mixer->amixers[amix*CHN_NUM+1], rsc); + + return 0; +} + +#ifdef CONFIG_PM +static int mixer_resume(struct ct_mixer *mixer) +{ + int i, state; + struct amixer *amixer; + + /* resume topology and volume gain. */ + for (i = 0; i < NUM_CT_AMIXERS*CHN_NUM; i++) { + amixer = mixer->amixers[i]; + amixer->ops->commit_write(amixer); + } + + /* resume switch state. */ + for (i = SWH_MIXER_START; i <= SWH_MIXER_END; i++) { + state = get_switch_state(mixer, i); + do_switch(mixer->atc, i, state); + } + + return 0; +} +#endif + +int ct_mixer_destroy(struct ct_mixer *mixer) +{ + struct sum_mgr *sum_mgr = (struct sum_mgr *)mixer->atc->rsc_mgrs[SUM]; + struct amixer_mgr *amixer_mgr = + (struct amixer_mgr *)mixer->atc->rsc_mgrs[AMIXER]; + struct amixer *amixer; + int i = 0; + + /* Release amixer resources */ + for (i = 0; i < (NUM_CT_AMIXERS * CHN_NUM); i++) { + if (NULL != mixer->amixers[i]) { + amixer = mixer->amixers[i]; + amixer_mgr->put_amixer(amixer_mgr, amixer); + } + } + + /* Release sum resources */ + for (i = 0; i < (NUM_CT_SUMS * CHN_NUM); i++) { + if (NULL != mixer->sums[i]) + sum_mgr->put_sum(sum_mgr, (struct sum *)mixer->sums[i]); + } + + /* Release mem assigned to mixer object */ + kfree(mixer->sums); + kfree(mixer->amixers); + kfree(mixer); + + return 0; +} + +int ct_mixer_create(struct ct_atc *atc, struct ct_mixer **rmixer) +{ + struct ct_mixer *mixer; + int err; + + *rmixer = NULL; + + /* Allocate mem for mixer obj */ + err = ct_mixer_get_mem(&mixer); + if (err) + return err; + + mixer->switch_state = 0; + mixer->atc = atc; + /* Set operations */ + mixer->get_output_ports = mixer_get_output_ports; + mixer->set_input_left = mixer_set_input_left; + mixer->set_input_right = mixer_set_input_right; +#ifdef CONFIG_PM + mixer->resume = mixer_resume; +#endif + + /* Allocate chip resources for mixer obj */ + err = ct_mixer_get_resources(mixer); + if (err) + goto error; + + /* Build internal mixer topology */ + ct_mixer_topology_build(mixer); + + *rmixer = mixer; + + return 0; + +error: + ct_mixer_destroy(mixer); + return err; +} + +int ct_alsa_mix_create(struct ct_atc *atc, + enum CTALSADEVS device, + const char *device_name) +{ + int err; + + /* Create snd kcontrol instances on demand */ + /* vol_ctl.device = swh_ctl.device = device; */ /* better w/ device 0 */ + err = ct_mixer_kcontrols_create((struct ct_mixer *)atc->mixer); + if (err) + return err; + + strcpy(atc->card->mixername, device_name); + + return 0; +} diff --git a/sound/pci/ctxfi/ctmixer.h b/sound/pci/ctxfi/ctmixer.h new file mode 100644 index 000000000000..b009e989e77d --- /dev/null +++ b/sound/pci/ctxfi/ctmixer.h @@ -0,0 +1,70 @@ +/** + * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. + * + * This source file is released under GPL v2 license (no other versions). + * See the COPYING file included in the main directory of this source + * distribution for the license terms and conditions. + * + * @File ctmixer.h + * + * @Brief + * This file contains the definition of the mixer device functions. + * + * @Author Liu Chun + * @Date Mar 28 2008 + * + */ + +#ifndef CTMIXER_H +#define CTMIXER_H + +#include "ctatc.h" +#include "ctresource.h" + +#define INIT_VOL 0x1c00 + +enum MIXER_PORT_T { + MIX_WAVE_FRONT, + MIX_WAVE_REAR, + MIX_WAVE_CENTLFE, + MIX_WAVE_SURROUND, + MIX_SPDIF_OUT, + MIX_PCMO_FRONT, + MIX_MIC_IN, + MIX_LINE_IN, + MIX_SPDIF_IN, + MIX_PCMI_FRONT, + MIX_PCMI_REAR, + MIX_PCMI_CENTLFE, + MIX_PCMI_SURROUND, + + NUM_MIX_PORTS +}; + +/* alsa mixer descriptor */ +struct ct_mixer { + struct ct_atc *atc; + + void **amixers; /* amixer resources for volume control */ + void **sums; /* sum resources for signal collection */ + unsigned int switch_state; /* A bit-map to indicate state of switches */ + + int (*get_output_ports)(struct ct_mixer *mixer, enum MIXER_PORT_T type, + struct rsc **rleft, struct rsc **rright); + + int (*set_input_left)(struct ct_mixer *mixer, + enum MIXER_PORT_T type, struct rsc *rsc); + int (*set_input_right)(struct ct_mixer *mixer, + enum MIXER_PORT_T type, struct rsc *rsc); +#ifdef CONFIG_PM + int (*resume)(struct ct_mixer *mixer); +#endif +}; + +int ct_alsa_mix_create(struct ct_atc *atc, + enum CTALSADEVS device, + const char *device_name); +int ct_mixer_create(struct ct_atc *atc, struct ct_mixer **rmixer); +int ct_mixer_destroy(struct ct_mixer *mixer); + +#endif /* CTMIXER_H */ diff --git a/sound/pci/ctxfi/ctpcm.c b/sound/pci/ctxfi/ctpcm.c new file mode 100644 index 000000000000..60ea23180acb --- /dev/null +++ b/sound/pci/ctxfi/ctpcm.c @@ -0,0 +1,430 @@ +/** + * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. + * + * This source file is released under GPL v2 license (no other versions). + * See the COPYING file included in the main directory of this source + * distribution for the license terms and conditions. + * + * @File ctpcm.c + * + * @Brief + * This file contains the definition of the pcm device functions. + * + * @Author Liu Chun + * @Date Apr 2 2008 + * + */ + +#include "ctpcm.h" +#include "cttimer.h" +#include + +/* Hardware descriptions for playback */ +static struct snd_pcm_hardware ct_pcm_playback_hw = { + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_PAUSE), + .formats = (SNDRV_PCM_FMTBIT_U8 | + SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_3LE | + SNDRV_PCM_FMTBIT_S32_LE | + SNDRV_PCM_FMTBIT_FLOAT_LE), + .rates = (SNDRV_PCM_RATE_CONTINUOUS | + SNDRV_PCM_RATE_8000_192000), + .rate_min = 8000, + .rate_max = 192000, + .channels_min = 1, + .channels_max = 2, + .buffer_bytes_max = (128*1024), + .period_bytes_min = (64), + .period_bytes_max = (128*1024), + .periods_min = 2, + .periods_max = 1024, + .fifo_size = 0, +}; + +static struct snd_pcm_hardware ct_spdif_passthru_playback_hw = { + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_PAUSE), + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .rates = (SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_32000), + .rate_min = 32000, + .rate_max = 48000, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = (128*1024), + .period_bytes_min = (64), + .period_bytes_max = (128*1024), + .periods_min = 2, + .periods_max = 1024, + .fifo_size = 0, +}; + +/* Hardware descriptions for capture */ +static struct snd_pcm_hardware ct_pcm_capture_hw = { + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_MMAP_VALID), + .formats = (SNDRV_PCM_FMTBIT_U8 | + SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_3LE | + SNDRV_PCM_FMTBIT_S32_LE | + SNDRV_PCM_FMTBIT_FLOAT_LE), + .rates = (SNDRV_PCM_RATE_CONTINUOUS | + SNDRV_PCM_RATE_8000_96000), + .rate_min = 8000, + .rate_max = 96000, + .channels_min = 1, + .channels_max = 2, + .buffer_bytes_max = (128*1024), + .period_bytes_min = (384), + .period_bytes_max = (64*1024), + .periods_min = 2, + .periods_max = 1024, + .fifo_size = 0, +}; + +static void ct_atc_pcm_interrupt(struct ct_atc_pcm *atc_pcm) +{ + struct ct_atc_pcm *apcm = atc_pcm; + + if (NULL == apcm->substream) + return; + + snd_pcm_period_elapsed(apcm->substream); +} + +static void ct_atc_pcm_free_substream(struct snd_pcm_runtime *runtime) +{ + struct ct_atc_pcm *apcm = runtime->private_data; + struct ct_atc *atc = snd_pcm_substream_chip(apcm->substream); + + atc->pcm_release_resources(atc, apcm); + ct_timer_instance_free(apcm->timer); + kfree(apcm); + runtime->private_data = NULL; +} + +/* pcm playback operations */ +static int ct_pcm_playback_open(struct snd_pcm_substream *substream) +{ + struct ct_atc *atc = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + struct ct_atc_pcm *apcm; + int err; + + apcm = kzalloc(sizeof(*apcm), GFP_KERNEL); + if (NULL == apcm) + return -ENOMEM; + + apcm->substream = substream; + apcm->interrupt = ct_atc_pcm_interrupt; + runtime->private_data = apcm; + runtime->private_free = ct_atc_pcm_free_substream; + if (IEC958 == substream->pcm->device) { + runtime->hw = ct_spdif_passthru_playback_hw; + atc->spdif_out_passthru(atc, 1); + } else { + runtime->hw = ct_pcm_playback_hw; + if (FRONT == substream->pcm->device) + runtime->hw.channels_max = 8; + } + + err = snd_pcm_hw_constraint_integer(runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + if (err < 0) { + kfree(apcm); + return err; + } + err = snd_pcm_hw_constraint_minmax(runtime, + SNDRV_PCM_HW_PARAM_BUFFER_BYTES, + 1024, UINT_MAX); + if (err < 0) { + kfree(apcm); + return err; + } + + apcm->timer = ct_timer_instance_new(atc->timer, apcm); + if (!apcm->timer) + return -ENOMEM; + + return 0; +} + +static int ct_pcm_playback_close(struct snd_pcm_substream *substream) +{ + struct ct_atc *atc = snd_pcm_substream_chip(substream); + + /* TODO: Notify mixer inactive. */ + if (IEC958 == substream->pcm->device) + atc->spdif_out_passthru(atc, 0); + + /* The ct_atc_pcm object will be freed by runtime->private_free */ + + return 0; +} + +static int ct_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + struct ct_atc *atc = snd_pcm_substream_chip(substream); + struct ct_atc_pcm *apcm = substream->runtime->private_data; + int err; + + err = snd_pcm_lib_malloc_pages(substream, + params_buffer_bytes(hw_params)); + if (err < 0) + return err; + /* clear previous resources */ + atc->pcm_release_resources(atc, apcm); + return err; +} + +static int ct_pcm_hw_free(struct snd_pcm_substream *substream) +{ + struct ct_atc *atc = snd_pcm_substream_chip(substream); + struct ct_atc_pcm *apcm = substream->runtime->private_data; + + /* clear previous resources */ + atc->pcm_release_resources(atc, apcm); + /* Free snd-allocated pages */ + return snd_pcm_lib_free_pages(substream); +} + + +static int ct_pcm_playback_prepare(struct snd_pcm_substream *substream) +{ + int err; + struct ct_atc *atc = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + struct ct_atc_pcm *apcm = runtime->private_data; + + if (IEC958 == substream->pcm->device) + err = atc->spdif_passthru_playback_prepare(atc, apcm); + else + err = atc->pcm_playback_prepare(atc, apcm); + + if (err < 0) { + printk(KERN_ERR "ctxfi: Preparing pcm playback failed!!!\n"); + return err; + } + + return 0; +} + +static int +ct_pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct ct_atc *atc = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + struct ct_atc_pcm *apcm = runtime->private_data; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + atc->pcm_playback_start(atc, apcm); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + atc->pcm_playback_stop(atc, apcm); + break; + default: + break; + } + + return 0; +} + +static snd_pcm_uframes_t +ct_pcm_playback_pointer(struct snd_pcm_substream *substream) +{ + unsigned long position; + struct ct_atc *atc = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + struct ct_atc_pcm *apcm = runtime->private_data; + + /* Read out playback position */ + position = atc->pcm_playback_position(atc, apcm); + position = bytes_to_frames(runtime, position); + if (position >= runtime->buffer_size) + position = 0; + return position; +} + +/* pcm capture operations */ +static int ct_pcm_capture_open(struct snd_pcm_substream *substream) +{ + struct ct_atc *atc = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + struct ct_atc_pcm *apcm; + int err; + + apcm = kzalloc(sizeof(*apcm), GFP_KERNEL); + if (NULL == apcm) + return -ENOMEM; + + apcm->started = 0; + apcm->substream = substream; + apcm->interrupt = ct_atc_pcm_interrupt; + runtime->private_data = apcm; + runtime->private_free = ct_atc_pcm_free_substream; + runtime->hw = ct_pcm_capture_hw; + runtime->hw.rate_max = atc->rsr * atc->msr; + + err = snd_pcm_hw_constraint_integer(runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + if (err < 0) { + kfree(apcm); + return err; + } + err = snd_pcm_hw_constraint_minmax(runtime, + SNDRV_PCM_HW_PARAM_BUFFER_BYTES, + 1024, UINT_MAX); + if (err < 0) { + kfree(apcm); + return err; + } + + apcm->timer = ct_timer_instance_new(atc->timer, apcm); + if (!apcm->timer) + return -ENOMEM; + + return 0; +} + +static int ct_pcm_capture_close(struct snd_pcm_substream *substream) +{ + /* The ct_atc_pcm object will be freed by runtime->private_free */ + /* TODO: Notify mixer inactive. */ + return 0; +} + +static int ct_pcm_capture_prepare(struct snd_pcm_substream *substream) +{ + int err; + struct ct_atc *atc = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + struct ct_atc_pcm *apcm = runtime->private_data; + + err = atc->pcm_capture_prepare(atc, apcm); + if (err < 0) { + printk(KERN_ERR "ctxfi: Preparing pcm capture failed!!!\n"); + return err; + } + + return 0; +} + +static int +ct_pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct ct_atc *atc = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + struct ct_atc_pcm *apcm = runtime->private_data; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + atc->pcm_capture_start(atc, apcm); + break; + case SNDRV_PCM_TRIGGER_STOP: + atc->pcm_capture_stop(atc, apcm); + break; + default: + atc->pcm_capture_stop(atc, apcm); + break; + } + + return 0; +} + +static snd_pcm_uframes_t +ct_pcm_capture_pointer(struct snd_pcm_substream *substream) +{ + unsigned long position; + struct ct_atc *atc = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + struct ct_atc_pcm *apcm = runtime->private_data; + + /* Read out playback position */ + position = atc->pcm_capture_position(atc, apcm); + position = bytes_to_frames(runtime, position); + if (position >= runtime->buffer_size) + position = 0; + return position; +} + +/* PCM operators for playback */ +static struct snd_pcm_ops ct_pcm_playback_ops = { + .open = ct_pcm_playback_open, + .close = ct_pcm_playback_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = ct_pcm_hw_params, + .hw_free = ct_pcm_hw_free, + .prepare = ct_pcm_playback_prepare, + .trigger = ct_pcm_playback_trigger, + .pointer = ct_pcm_playback_pointer, + .page = snd_pcm_sgbuf_ops_page, +}; + +/* PCM operators for capture */ +static struct snd_pcm_ops ct_pcm_capture_ops = { + .open = ct_pcm_capture_open, + .close = ct_pcm_capture_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = ct_pcm_hw_params, + .hw_free = ct_pcm_hw_free, + .prepare = ct_pcm_capture_prepare, + .trigger = ct_pcm_capture_trigger, + .pointer = ct_pcm_capture_pointer, + .page = snd_pcm_sgbuf_ops_page, +}; + +/* Create ALSA pcm device */ +int ct_alsa_pcm_create(struct ct_atc *atc, + enum CTALSADEVS device, + const char *device_name) +{ + struct snd_pcm *pcm; + int err; + int playback_count, capture_count; + + playback_count = (IEC958 == device) ? 1 : 8; + capture_count = (FRONT == device) ? 1 : 0; + err = snd_pcm_new(atc->card, "ctxfi", device, + playback_count, capture_count, &pcm); + if (err < 0) { + printk(KERN_ERR "ctxfi: snd_pcm_new failed!! Err=%d\n", err); + return err; + } + + pcm->private_data = atc; + pcm->info_flags = 0; + pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; + strlcpy(pcm->name, device_name, sizeof(pcm->name)); + + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &ct_pcm_playback_ops); + + if (FRONT == device) + snd_pcm_set_ops(pcm, + SNDRV_PCM_STREAM_CAPTURE, &ct_pcm_capture_ops); + + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, + snd_dma_pci_data(atc->pci), 128*1024, 128*1024); + +#ifdef CONFIG_PM + atc->pcms[device] = pcm; +#endif + + return 0; +} diff --git a/sound/pci/ctxfi/ctpcm.h b/sound/pci/ctxfi/ctpcm.h new file mode 100644 index 000000000000..178da0dca647 --- /dev/null +++ b/sound/pci/ctxfi/ctpcm.h @@ -0,0 +1,27 @@ +/** + * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. + * + * This source file is released under GPL v2 license (no other versions). + * See the COPYING file included in the main directory of this source + * distribution for the license terms and conditions. + * + * @File ctpcm.h + * + * @Brief + * This file contains the definition of the pcm device functions. + * + * @Author Liu Chun + * @Date Mar 28 2008 + * + */ + +#ifndef CTPCM_H +#define CTPCM_H + +#include "ctatc.h" + +int ct_alsa_pcm_create(struct ct_atc *atc, + enum CTALSADEVS device, + const char *device_name); + +#endif /* CTPCM_H */ diff --git a/sound/pci/ctxfi/ctresource.c b/sound/pci/ctxfi/ctresource.c new file mode 100644 index 000000000000..889c495bb7d1 --- /dev/null +++ b/sound/pci/ctxfi/ctresource.c @@ -0,0 +1,301 @@ +/** + * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. + * + * This source file is released under GPL v2 license (no other versions). + * See the COPYING file included in the main directory of this source + * distribution for the license terms and conditions. + * + * @File ctresource.c + * + * @Brief + * This file contains the implementation of some generic helper functions. + * + * @Author Liu Chun + * @Date May 15 2008 + * + */ + +#include "ctresource.h" +#include "cthardware.h" +#include +#include + +#define AUDIO_SLOT_BLOCK_NUM 256 + +/* Resource allocation based on bit-map management mechanism */ +static int +get_resource(u8 *rscs, unsigned int amount, + unsigned int multi, unsigned int *ridx) +{ + int i, j, k, n; + + /* Check whether there are sufficient resources to meet request. */ + for (i = 0, n = multi; i < amount; i++) { + j = i / 8; + k = i % 8; + if (rscs[j] & ((u8)1 << k)) { + n = multi; + continue; + } + if (!(--n)) + break; /* found sufficient contiguous resources */ + } + + if (i >= amount) { + /* Can not find sufficient contiguous resources */ + return -ENOENT; + } + + /* Mark the contiguous bits in resource bit-map as used */ + for (n = multi; n > 0; n--) { + j = i / 8; + k = i % 8; + rscs[j] |= ((u8)1 << k); + i--; + } + + *ridx = i + 1; + + return 0; +} + +static int put_resource(u8 *rscs, unsigned int multi, unsigned int idx) +{ + unsigned int i, j, k, n; + + /* Mark the contiguous bits in resource bit-map as used */ + for (n = multi, i = idx; n > 0; n--) { + j = i / 8; + k = i % 8; + rscs[j] &= ~((u8)1 << k); + i++; + } + + return 0; +} + +int mgr_get_resource(struct rsc_mgr *mgr, unsigned int n, unsigned int *ridx) +{ + int err; + + if (n > mgr->avail) + return -ENOENT; + + err = get_resource(mgr->rscs, mgr->amount, n, ridx); + if (!err) + mgr->avail -= n; + + return err; +} + +int mgr_put_resource(struct rsc_mgr *mgr, unsigned int n, unsigned int idx) +{ + put_resource(mgr->rscs, n, idx); + mgr->avail += n; + + return 0; +} + +static unsigned char offset_in_audio_slot_block[NUM_RSCTYP] = { + /* SRC channel is at Audio Ring slot 1 every 16 slots. */ + [SRC] = 0x1, + [AMIXER] = 0x4, + [SUM] = 0xc, +}; + +static int rsc_index(const struct rsc *rsc) +{ + return rsc->conj; +} + +static int audio_ring_slot(const struct rsc *rsc) +{ + return (rsc->conj << 4) + offset_in_audio_slot_block[rsc->type]; +} + +static int rsc_next_conj(struct rsc *rsc) +{ + unsigned int i; + for (i = 0; (i < 8) && (!(rsc->msr & (0x1 << i))); ) + i++; + rsc->conj += (AUDIO_SLOT_BLOCK_NUM >> i); + return rsc->conj; +} + +static int rsc_master(struct rsc *rsc) +{ + return rsc->conj = rsc->idx; +} + +static struct rsc_ops rsc_generic_ops = { + .index = rsc_index, + .output_slot = audio_ring_slot, + .master = rsc_master, + .next_conj = rsc_next_conj, +}; + +int rsc_init(struct rsc *rsc, u32 idx, enum RSCTYP type, u32 msr, void *hw) +{ + int err = 0; + + rsc->idx = idx; + rsc->conj = idx; + rsc->type = type; + rsc->msr = msr; + rsc->hw = hw; + rsc->ops = &rsc_generic_ops; + if (NULL == hw) { + rsc->ctrl_blk = NULL; + return 0; + } + + switch (type) { + case SRC: + err = ((struct hw *)hw)->src_rsc_get_ctrl_blk(&rsc->ctrl_blk); + break; + case AMIXER: + err = ((struct hw *)hw)-> + amixer_rsc_get_ctrl_blk(&rsc->ctrl_blk); + break; + case SRCIMP: + case SUM: + case DAIO: + break; + default: + printk(KERN_ERR + "ctxfi: Invalid resource type value %d!\n", type); + return -EINVAL; + } + + if (err) { + printk(KERN_ERR + "ctxfi: Failed to get resource control block!\n"); + return err; + } + + return 0; +} + +int rsc_uninit(struct rsc *rsc) +{ + if ((NULL != rsc->hw) && (NULL != rsc->ctrl_blk)) { + switch (rsc->type) { + case SRC: + ((struct hw *)rsc->hw)-> + src_rsc_put_ctrl_blk(rsc->ctrl_blk); + break; + case AMIXER: + ((struct hw *)rsc->hw)-> + amixer_rsc_put_ctrl_blk(rsc->ctrl_blk); + break; + case SUM: + case DAIO: + break; + default: + printk(KERN_ERR "ctxfi: " + "Invalid resource type value %d!\n", rsc->type); + break; + } + + rsc->hw = rsc->ctrl_blk = NULL; + } + + rsc->idx = rsc->conj = 0; + rsc->type = NUM_RSCTYP; + rsc->msr = 0; + + return 0; +} + +int rsc_mgr_init(struct rsc_mgr *mgr, enum RSCTYP type, + unsigned int amount, void *hw_obj) +{ + int err = 0; + struct hw *hw = hw_obj; + + mgr->type = NUM_RSCTYP; + + mgr->rscs = kzalloc(((amount + 8 - 1) / 8), GFP_KERNEL); + if (NULL == mgr->rscs) + return -ENOMEM; + + switch (type) { + case SRC: + err = hw->src_mgr_get_ctrl_blk(&mgr->ctrl_blk); + break; + case SRCIMP: + err = hw->srcimp_mgr_get_ctrl_blk(&mgr->ctrl_blk); + break; + case AMIXER: + err = hw->amixer_mgr_get_ctrl_blk(&mgr->ctrl_blk); + break; + case DAIO: + err = hw->daio_mgr_get_ctrl_blk(hw, &mgr->ctrl_blk); + break; + case SUM: + break; + default: + printk(KERN_ERR + "ctxfi: Invalid resource type value %d!\n", type); + err = -EINVAL; + goto error; + } + + if (err) { + printk(KERN_ERR + "ctxfi: Failed to get manager control block!\n"); + goto error; + } + + mgr->type = type; + mgr->avail = mgr->amount = amount; + mgr->hw = hw; + + return 0; + +error: + kfree(mgr->rscs); + return err; +} + +int rsc_mgr_uninit(struct rsc_mgr *mgr) +{ + if (NULL != mgr->rscs) { + kfree(mgr->rscs); + mgr->rscs = NULL; + } + + if ((NULL != mgr->hw) && (NULL != mgr->ctrl_blk)) { + switch (mgr->type) { + case SRC: + ((struct hw *)mgr->hw)-> + src_mgr_put_ctrl_blk(mgr->ctrl_blk); + break; + case SRCIMP: + ((struct hw *)mgr->hw)-> + srcimp_mgr_put_ctrl_blk(mgr->ctrl_blk); + break; + case AMIXER: + ((struct hw *)mgr->hw)-> + amixer_mgr_put_ctrl_blk(mgr->ctrl_blk); + break; + case DAIO: + ((struct hw *)mgr->hw)-> + daio_mgr_put_ctrl_blk(mgr->ctrl_blk); + break; + case SUM: + break; + default: + printk(KERN_ERR "ctxfi: " + "Invalid resource type value %d!\n", mgr->type); + break; + } + + mgr->hw = mgr->ctrl_blk = NULL; + } + + mgr->type = NUM_RSCTYP; + mgr->avail = mgr->amount = 0; + + return 0; +} diff --git a/sound/pci/ctxfi/ctresource.h b/sound/pci/ctxfi/ctresource.h new file mode 100644 index 000000000000..0838c2e84f8b --- /dev/null +++ b/sound/pci/ctxfi/ctresource.h @@ -0,0 +1,72 @@ +/** + * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. + * + * This source file is released under GPL v2 license (no other versions). + * See the COPYING file included in the main directory of this source + * distribution for the license terms and conditions. + * + * @File ctresource.h + * + * @Brief + * This file contains the definition of generic hardware resources for + * resource management. + * + * @Author Liu Chun + * @Date May 13 2008 + * + */ + +#ifndef CTRESOURCE_H +#define CTRESOURCE_H + +#include + +enum RSCTYP { + SRC, + SRCIMP, + AMIXER, + SUM, + DAIO, + NUM_RSCTYP /* This must be the last one and less than 16 */ +}; + +struct rsc_ops; + +struct rsc { + u32 idx:12; /* The index of a resource */ + u32 type:4; /* The type (RSCTYP) of a resource */ + u32 conj:12; /* Current conjugate index */ + u32 msr:4; /* The Master Sample Rate a resource working on */ + void *ctrl_blk; /* Chip specific control info block for a resource */ + void *hw; /* Chip specific object for hardware access means */ + struct rsc_ops *ops; /* Generic resource operations */ +}; + +struct rsc_ops { + int (*master)(struct rsc *rsc); /* Move to master resource */ + int (*next_conj)(struct rsc *rsc); /* Move to next conjugate resource */ + int (*index)(const struct rsc *rsc); /* Return the index of resource */ + /* Return the output slot number */ + int (*output_slot)(const struct rsc *rsc); +}; + +int rsc_init(struct rsc *rsc, u32 idx, enum RSCTYP type, u32 msr, void *hw); +int rsc_uninit(struct rsc *rsc); + +struct rsc_mgr { + enum RSCTYP type; /* The type (RSCTYP) of resource to manage */ + unsigned int amount; /* The total amount of a kind of resource */ + unsigned int avail; /* The amount of currently available resources */ + unsigned char *rscs; /* The bit-map for resource allocation */ + void *ctrl_blk; /* Chip specific control info block */ + void *hw; /* Chip specific object for hardware access */ +}; + +/* Resource management is based on bit-map mechanism */ +int rsc_mgr_init(struct rsc_mgr *mgr, enum RSCTYP type, + unsigned int amount, void *hw); +int rsc_mgr_uninit(struct rsc_mgr *mgr); +int mgr_get_resource(struct rsc_mgr *mgr, unsigned int n, unsigned int *ridx); +int mgr_put_resource(struct rsc_mgr *mgr, unsigned int n, unsigned int idx); + +#endif /* CTRESOURCE_H */ diff --git a/sound/pci/ctxfi/ctsrc.c b/sound/pci/ctxfi/ctsrc.c new file mode 100644 index 000000000000..e1c145d8b702 --- /dev/null +++ b/sound/pci/ctxfi/ctsrc.c @@ -0,0 +1,886 @@ +/** + * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. + * + * This source file is released under GPL v2 license (no other versions). + * See the COPYING file included in the main directory of this source + * distribution for the license terms and conditions. + * + * @File ctsrc.c + * + * @Brief + * This file contains the implementation of the Sample Rate Convertor + * resource management object. + * + * @Author Liu Chun + * @Date May 13 2008 + * + */ + +#include "ctsrc.h" +#include "cthardware.h" +#include + +#define SRC_RESOURCE_NUM 64 +#define SRCIMP_RESOURCE_NUM 256 + +static unsigned int conj_mask; + +static int src_default_config_memrd(struct src *src); +static int src_default_config_memwr(struct src *src); +static int src_default_config_arcrw(struct src *src); + +static int (*src_default_config[3])(struct src *) = { + [MEMRD] = src_default_config_memrd, + [MEMWR] = src_default_config_memwr, + [ARCRW] = src_default_config_arcrw +}; + +static int src_set_state(struct src *src, unsigned int state) +{ + struct hw *hw; + + hw = src->rsc.hw; + hw->src_set_state(src->rsc.ctrl_blk, state); + + return 0; +} + +static int src_set_bm(struct src *src, unsigned int bm) +{ + struct hw *hw; + + hw = src->rsc.hw; + hw->src_set_bm(src->rsc.ctrl_blk, bm); + + return 0; +} + +static int src_set_sf(struct src *src, unsigned int sf) +{ + struct hw *hw; + + hw = src->rsc.hw; + hw->src_set_sf(src->rsc.ctrl_blk, sf); + + return 0; +} + +static int src_set_pm(struct src *src, unsigned int pm) +{ + struct hw *hw; + + hw = src->rsc.hw; + hw->src_set_pm(src->rsc.ctrl_blk, pm); + + return 0; +} + +static int src_set_rom(struct src *src, unsigned int rom) +{ + struct hw *hw; + + hw = src->rsc.hw; + hw->src_set_rom(src->rsc.ctrl_blk, rom); + + return 0; +} + +static int src_set_vo(struct src *src, unsigned int vo) +{ + struct hw *hw; + + hw = src->rsc.hw; + hw->src_set_vo(src->rsc.ctrl_blk, vo); + + return 0; +} + +static int src_set_st(struct src *src, unsigned int st) +{ + struct hw *hw; + + hw = src->rsc.hw; + hw->src_set_st(src->rsc.ctrl_blk, st); + + return 0; +} + +static int src_set_bp(struct src *src, unsigned int bp) +{ + struct hw *hw; + + hw = src->rsc.hw; + hw->src_set_bp(src->rsc.ctrl_blk, bp); + + return 0; +} + +static int src_set_cisz(struct src *src, unsigned int cisz) +{ + struct hw *hw; + + hw = src->rsc.hw; + hw->src_set_cisz(src->rsc.ctrl_blk, cisz); + + return 0; +} + +static int src_set_ca(struct src *src, unsigned int ca) +{ + struct hw *hw; + + hw = src->rsc.hw; + hw->src_set_ca(src->rsc.ctrl_blk, ca); + + return 0; +} + +static int src_set_sa(struct src *src, unsigned int sa) +{ + struct hw *hw; + + hw = src->rsc.hw; + hw->src_set_sa(src->rsc.ctrl_blk, sa); + + return 0; +} + +static int src_set_la(struct src *src, unsigned int la) +{ + struct hw *hw; + + hw = src->rsc.hw; + hw->src_set_la(src->rsc.ctrl_blk, la); + + return 0; +} + +static int src_set_pitch(struct src *src, unsigned int pitch) +{ + struct hw *hw; + + hw = src->rsc.hw; + hw->src_set_pitch(src->rsc.ctrl_blk, pitch); + + return 0; +} + +static int src_set_clear_zbufs(struct src *src) +{ + struct hw *hw; + + hw = src->rsc.hw; + hw->src_set_clear_zbufs(src->rsc.ctrl_blk, 1); + + return 0; +} + +static int src_commit_write(struct src *src) +{ + struct hw *hw; + int i; + unsigned int dirty = 0; + + hw = src->rsc.hw; + src->rsc.ops->master(&src->rsc); + if (src->rsc.msr > 1) { + /* Save dirty flags for conjugate resource programming */ + dirty = hw->src_get_dirty(src->rsc.ctrl_blk) & conj_mask; + } + hw->src_commit_write(hw, src->rsc.ops->index(&src->rsc), + src->rsc.ctrl_blk); + + /* Program conjugate parameter mixer resources */ + if (MEMWR == src->mode) + return 0; + + for (i = 1; i < src->rsc.msr; i++) { + src->rsc.ops->next_conj(&src->rsc); + hw->src_set_dirty(src->rsc.ctrl_blk, dirty); + hw->src_commit_write(hw, src->rsc.ops->index(&src->rsc), + src->rsc.ctrl_blk); + } + src->rsc.ops->master(&src->rsc); + + return 0; +} + +static int src_get_ca(struct src *src) +{ + struct hw *hw; + + hw = src->rsc.hw; + return hw->src_get_ca(hw, src->rsc.ops->index(&src->rsc), + src->rsc.ctrl_blk); +} + +static int src_init(struct src *src) +{ + src_default_config[src->mode](src); + + return 0; +} + +static struct src *src_next_interleave(struct src *src) +{ + return src->intlv; +} + +static int src_default_config_memrd(struct src *src) +{ + struct hw *hw = src->rsc.hw; + unsigned int rsr, msr; + + hw->src_set_state(src->rsc.ctrl_blk, SRC_STATE_OFF); + hw->src_set_bm(src->rsc.ctrl_blk, 1); + for (rsr = 0, msr = src->rsc.msr; msr > 1; msr >>= 1) + rsr++; + + hw->src_set_rsr(src->rsc.ctrl_blk, rsr); + hw->src_set_sf(src->rsc.ctrl_blk, SRC_SF_S16); + hw->src_set_wr(src->rsc.ctrl_blk, 0); + hw->src_set_pm(src->rsc.ctrl_blk, 0); + hw->src_set_rom(src->rsc.ctrl_blk, 0); + hw->src_set_vo(src->rsc.ctrl_blk, 0); + hw->src_set_st(src->rsc.ctrl_blk, 0); + hw->src_set_ilsz(src->rsc.ctrl_blk, src->multi - 1); + hw->src_set_cisz(src->rsc.ctrl_blk, 0x80); + hw->src_set_sa(src->rsc.ctrl_blk, 0x0); + hw->src_set_la(src->rsc.ctrl_blk, 0x1000); + hw->src_set_ca(src->rsc.ctrl_blk, 0x80); + hw->src_set_pitch(src->rsc.ctrl_blk, 0x1000000); + hw->src_set_clear_zbufs(src->rsc.ctrl_blk, 1); + + src->rsc.ops->master(&src->rsc); + hw->src_commit_write(hw, src->rsc.ops->index(&src->rsc), + src->rsc.ctrl_blk); + + for (msr = 1; msr < src->rsc.msr; msr++) { + src->rsc.ops->next_conj(&src->rsc); + hw->src_set_pitch(src->rsc.ctrl_blk, 0x1000000); + hw->src_commit_write(hw, src->rsc.ops->index(&src->rsc), + src->rsc.ctrl_blk); + } + src->rsc.ops->master(&src->rsc); + + return 0; +} + +static int src_default_config_memwr(struct src *src) +{ + struct hw *hw = src->rsc.hw; + + hw->src_set_state(src->rsc.ctrl_blk, SRC_STATE_OFF); + hw->src_set_bm(src->rsc.ctrl_blk, 1); + hw->src_set_rsr(src->rsc.ctrl_blk, 0); + hw->src_set_sf(src->rsc.ctrl_blk, SRC_SF_S16); + hw->src_set_wr(src->rsc.ctrl_blk, 1); + hw->src_set_pm(src->rsc.ctrl_blk, 0); + hw->src_set_rom(src->rsc.ctrl_blk, 0); + hw->src_set_vo(src->rsc.ctrl_blk, 0); + hw->src_set_st(src->rsc.ctrl_blk, 0); + hw->src_set_ilsz(src->rsc.ctrl_blk, 0); + hw->src_set_cisz(src->rsc.ctrl_blk, 0x80); + hw->src_set_sa(src->rsc.ctrl_blk, 0x0); + hw->src_set_la(src->rsc.ctrl_blk, 0x1000); + hw->src_set_ca(src->rsc.ctrl_blk, 0x80); + hw->src_set_pitch(src->rsc.ctrl_blk, 0x1000000); + hw->src_set_clear_zbufs(src->rsc.ctrl_blk, 1); + + src->rsc.ops->master(&src->rsc); + hw->src_commit_write(hw, src->rsc.ops->index(&src->rsc), + src->rsc.ctrl_blk); + + return 0; +} + +static int src_default_config_arcrw(struct src *src) +{ + struct hw *hw = src->rsc.hw; + unsigned int rsr, msr; + unsigned int dirty; + + hw->src_set_state(src->rsc.ctrl_blk, SRC_STATE_OFF); + hw->src_set_bm(src->rsc.ctrl_blk, 0); + for (rsr = 0, msr = src->rsc.msr; msr > 1; msr >>= 1) + rsr++; + + hw->src_set_rsr(src->rsc.ctrl_blk, rsr); + hw->src_set_sf(src->rsc.ctrl_blk, SRC_SF_F32); + hw->src_set_wr(src->rsc.ctrl_blk, 0); + hw->src_set_pm(src->rsc.ctrl_blk, 0); + hw->src_set_rom(src->rsc.ctrl_blk, 0); + hw->src_set_vo(src->rsc.ctrl_blk, 0); + hw->src_set_st(src->rsc.ctrl_blk, 0); + hw->src_set_ilsz(src->rsc.ctrl_blk, 0); + hw->src_set_cisz(src->rsc.ctrl_blk, 0x80); + hw->src_set_sa(src->rsc.ctrl_blk, 0x0); + /*hw->src_set_sa(src->rsc.ctrl_blk, 0x100);*/ + hw->src_set_la(src->rsc.ctrl_blk, 0x1000); + /*hw->src_set_la(src->rsc.ctrl_blk, 0x03ffffe0);*/ + hw->src_set_ca(src->rsc.ctrl_blk, 0x80); + hw->src_set_pitch(src->rsc.ctrl_blk, 0x1000000); + hw->src_set_clear_zbufs(src->rsc.ctrl_blk, 1); + + dirty = hw->src_get_dirty(src->rsc.ctrl_blk); + src->rsc.ops->master(&src->rsc); + for (msr = 0; msr < src->rsc.msr; msr++) { + hw->src_set_dirty(src->rsc.ctrl_blk, dirty); + hw->src_commit_write(hw, src->rsc.ops->index(&src->rsc), + src->rsc.ctrl_blk); + src->rsc.ops->next_conj(&src->rsc); + } + src->rsc.ops->master(&src->rsc); + + return 0; +} + +static struct src_rsc_ops src_rsc_ops = { + .set_state = src_set_state, + .set_bm = src_set_bm, + .set_sf = src_set_sf, + .set_pm = src_set_pm, + .set_rom = src_set_rom, + .set_vo = src_set_vo, + .set_st = src_set_st, + .set_bp = src_set_bp, + .set_cisz = src_set_cisz, + .set_ca = src_set_ca, + .set_sa = src_set_sa, + .set_la = src_set_la, + .set_pitch = src_set_pitch, + .set_clr_zbufs = src_set_clear_zbufs, + .commit_write = src_commit_write, + .get_ca = src_get_ca, + .init = src_init, + .next_interleave = src_next_interleave, +}; + +static int +src_rsc_init(struct src *src, u32 idx, + const struct src_desc *desc, struct src_mgr *mgr) +{ + int err; + int i, n; + struct src *p; + + n = (MEMRD == desc->mode) ? desc->multi : 1; + for (i = 0, p = src; i < n; i++, p++) { + err = rsc_init(&p->rsc, idx + i, SRC, desc->msr, mgr->mgr.hw); + if (err) + goto error1; + + /* Initialize src specific rsc operations */ + p->ops = &src_rsc_ops; + p->multi = (0 == i) ? desc->multi : 1; + p->mode = desc->mode; + src_default_config[desc->mode](p); + mgr->src_enable(mgr, p); + p->intlv = p + 1; + } + (--p)->intlv = NULL; /* Set @intlv of the last SRC to NULL */ + + mgr->commit_write(mgr); + + return 0; + +error1: + for (i--, p--; i >= 0; i--, p--) { + mgr->src_disable(mgr, p); + rsc_uninit(&p->rsc); + } + mgr->commit_write(mgr); + return err; +} + +static int src_rsc_uninit(struct src *src, struct src_mgr *mgr) +{ + int i, n; + struct src *p; + + n = (MEMRD == src->mode) ? src->multi : 1; + for (i = 0, p = src; i < n; i++, p++) { + mgr->src_disable(mgr, p); + rsc_uninit(&p->rsc); + p->multi = 0; + p->ops = NULL; + p->mode = NUM_SRCMODES; + p->intlv = NULL; + } + mgr->commit_write(mgr); + + return 0; +} + +static int +get_src_rsc(struct src_mgr *mgr, const struct src_desc *desc, struct src **rsrc) +{ + unsigned int idx = SRC_RESOURCE_NUM; + int err; + struct src *src; + unsigned long flags; + + *rsrc = NULL; + + /* Check whether there are sufficient src resources to meet request. */ + spin_lock_irqsave(&mgr->mgr_lock, flags); + if (MEMRD == desc->mode) + err = mgr_get_resource(&mgr->mgr, desc->multi, &idx); + else + err = mgr_get_resource(&mgr->mgr, 1, &idx); + + spin_unlock_irqrestore(&mgr->mgr_lock, flags); + if (err) { + printk(KERN_ERR "ctxfi: Can't meet SRC resource request!\n"); + return err; + } + + /* Allocate mem for master src resource */ + if (MEMRD == desc->mode) + src = kzalloc(sizeof(*src)*desc->multi, GFP_KERNEL); + else + src = kzalloc(sizeof(*src), GFP_KERNEL); + + if (NULL == src) { + err = -ENOMEM; + goto error1; + } + + err = src_rsc_init(src, idx, desc, mgr); + if (err) + goto error2; + + *rsrc = src; + + return 0; + +error2: + kfree(src); +error1: + spin_lock_irqsave(&mgr->mgr_lock, flags); + if (MEMRD == desc->mode) + mgr_put_resource(&mgr->mgr, desc->multi, idx); + else + mgr_put_resource(&mgr->mgr, 1, idx); + + spin_unlock_irqrestore(&mgr->mgr_lock, flags); + return err; +} + +static int put_src_rsc(struct src_mgr *mgr, struct src *src) +{ + unsigned long flags; + + spin_lock_irqsave(&mgr->mgr_lock, flags); + src->rsc.ops->master(&src->rsc); + if (MEMRD == src->mode) + mgr_put_resource(&mgr->mgr, src->multi, + src->rsc.ops->index(&src->rsc)); + else + mgr_put_resource(&mgr->mgr, 1, src->rsc.ops->index(&src->rsc)); + + spin_unlock_irqrestore(&mgr->mgr_lock, flags); + src_rsc_uninit(src, mgr); + kfree(src); + + return 0; +} + +static int src_enable_s(struct src_mgr *mgr, struct src *src) +{ + struct hw *hw = mgr->mgr.hw; + int i; + + src->rsc.ops->master(&src->rsc); + for (i = 0; i < src->rsc.msr; i++) { + hw->src_mgr_enbs_src(mgr->mgr.ctrl_blk, + src->rsc.ops->index(&src->rsc)); + src->rsc.ops->next_conj(&src->rsc); + } + src->rsc.ops->master(&src->rsc); + + return 0; +} + +static int src_enable(struct src_mgr *mgr, struct src *src) +{ + struct hw *hw = mgr->mgr.hw; + int i; + + src->rsc.ops->master(&src->rsc); + for (i = 0; i < src->rsc.msr; i++) { + hw->src_mgr_enb_src(mgr->mgr.ctrl_blk, + src->rsc.ops->index(&src->rsc)); + src->rsc.ops->next_conj(&src->rsc); + } + src->rsc.ops->master(&src->rsc); + + return 0; +} + +static int src_disable(struct src_mgr *mgr, struct src *src) +{ + struct hw *hw = mgr->mgr.hw; + int i; + + src->rsc.ops->master(&src->rsc); + for (i = 0; i < src->rsc.msr; i++) { + hw->src_mgr_dsb_src(mgr->mgr.ctrl_blk, + src->rsc.ops->index(&src->rsc)); + src->rsc.ops->next_conj(&src->rsc); + } + src->rsc.ops->master(&src->rsc); + + return 0; +} + +static int src_mgr_commit_write(struct src_mgr *mgr) +{ + struct hw *hw = mgr->mgr.hw; + + hw->src_mgr_commit_write(hw, mgr->mgr.ctrl_blk); + + return 0; +} + +int src_mgr_create(void *hw, struct src_mgr **rsrc_mgr) +{ + int err, i; + struct src_mgr *src_mgr; + + *rsrc_mgr = NULL; + src_mgr = kzalloc(sizeof(*src_mgr), GFP_KERNEL); + if (NULL == src_mgr) + return -ENOMEM; + + err = rsc_mgr_init(&src_mgr->mgr, SRC, SRC_RESOURCE_NUM, hw); + if (err) + goto error1; + + spin_lock_init(&src_mgr->mgr_lock); + conj_mask = ((struct hw *)hw)->src_dirty_conj_mask(); + + src_mgr->get_src = get_src_rsc; + src_mgr->put_src = put_src_rsc; + src_mgr->src_enable_s = src_enable_s; + src_mgr->src_enable = src_enable; + src_mgr->src_disable = src_disable; + src_mgr->commit_write = src_mgr_commit_write; + + /* Disable all SRC resources. */ + for (i = 0; i < 256; i++) + ((struct hw *)hw)->src_mgr_dsb_src(src_mgr->mgr.ctrl_blk, i); + + ((struct hw *)hw)->src_mgr_commit_write(hw, src_mgr->mgr.ctrl_blk); + + *rsrc_mgr = src_mgr; + + return 0; + +error1: + kfree(src_mgr); + return err; +} + +int src_mgr_destroy(struct src_mgr *src_mgr) +{ + rsc_mgr_uninit(&src_mgr->mgr); + kfree(src_mgr); + + return 0; +} + +/* SRCIMP resource manager operations */ + +static int srcimp_master(struct rsc *rsc) +{ + rsc->conj = 0; + return rsc->idx = container_of(rsc, struct srcimp, rsc)->idx[0]; +} + +static int srcimp_next_conj(struct rsc *rsc) +{ + rsc->conj++; + return container_of(rsc, struct srcimp, rsc)->idx[rsc->conj]; +} + +static int srcimp_index(const struct rsc *rsc) +{ + return container_of(rsc, struct srcimp, rsc)->idx[rsc->conj]; +} + +static struct rsc_ops srcimp_basic_rsc_ops = { + .master = srcimp_master, + .next_conj = srcimp_next_conj, + .index = srcimp_index, + .output_slot = NULL, +}; + +static int srcimp_map(struct srcimp *srcimp, struct src *src, struct rsc *input) +{ + struct imapper *entry; + int i; + + srcimp->rsc.ops->master(&srcimp->rsc); + src->rsc.ops->master(&src->rsc); + input->ops->master(input); + + /* Program master and conjugate resources */ + for (i = 0; i < srcimp->rsc.msr; i++) { + entry = &srcimp->imappers[i]; + entry->slot = input->ops->output_slot(input); + entry->user = src->rsc.ops->index(&src->rsc); + entry->addr = srcimp->rsc.ops->index(&srcimp->rsc); + srcimp->mgr->imap_add(srcimp->mgr, entry); + srcimp->mapped |= (0x1 << i); + + srcimp->rsc.ops->next_conj(&srcimp->rsc); + input->ops->next_conj(input); + } + + srcimp->rsc.ops->master(&srcimp->rsc); + input->ops->master(input); + + return 0; +} + +static int srcimp_unmap(struct srcimp *srcimp) +{ + int i; + + /* Program master and conjugate resources */ + for (i = 0; i < srcimp->rsc.msr; i++) { + if (srcimp->mapped & (0x1 << i)) { + srcimp->mgr->imap_delete(srcimp->mgr, + &srcimp->imappers[i]); + srcimp->mapped &= ~(0x1 << i); + } + } + + return 0; +} + +static struct srcimp_rsc_ops srcimp_ops = { + .map = srcimp_map, + .unmap = srcimp_unmap +}; + +static int srcimp_rsc_init(struct srcimp *srcimp, + const struct srcimp_desc *desc, + struct srcimp_mgr *mgr) +{ + int err; + + err = rsc_init(&srcimp->rsc, srcimp->idx[0], + SRCIMP, desc->msr, mgr->mgr.hw); + if (err) + return err; + + /* Reserve memory for imapper nodes */ + srcimp->imappers = kzalloc(sizeof(struct imapper)*desc->msr, + GFP_KERNEL); + if (NULL == srcimp->imappers) { + err = -ENOMEM; + goto error1; + } + + /* Set srcimp specific operations */ + srcimp->rsc.ops = &srcimp_basic_rsc_ops; + srcimp->ops = &srcimp_ops; + srcimp->mgr = mgr; + + srcimp->rsc.ops->master(&srcimp->rsc); + + return 0; + +error1: + rsc_uninit(&srcimp->rsc); + return err; +} + +static int srcimp_rsc_uninit(struct srcimp *srcimp) +{ + if (NULL != srcimp->imappers) { + kfree(srcimp->imappers); + srcimp->imappers = NULL; + } + srcimp->ops = NULL; + srcimp->mgr = NULL; + rsc_uninit(&srcimp->rsc); + + return 0; +} + +static int get_srcimp_rsc(struct srcimp_mgr *mgr, + const struct srcimp_desc *desc, + struct srcimp **rsrcimp) +{ + int err, i; + unsigned int idx; + struct srcimp *srcimp; + unsigned long flags; + + *rsrcimp = NULL; + + /* Allocate mem for SRCIMP resource */ + srcimp = kzalloc(sizeof(*srcimp), GFP_KERNEL); + if (NULL == srcimp) { + err = -ENOMEM; + return err; + } + + /* Check whether there are sufficient SRCIMP resources. */ + spin_lock_irqsave(&mgr->mgr_lock, flags); + for (i = 0; i < desc->msr; i++) { + err = mgr_get_resource(&mgr->mgr, 1, &idx); + if (err) + break; + + srcimp->idx[i] = idx; + } + spin_unlock_irqrestore(&mgr->mgr_lock, flags); + if (err) { + printk(KERN_ERR "ctxfi: Can't meet SRCIMP resource request!\n"); + goto error1; + } + + err = srcimp_rsc_init(srcimp, desc, mgr); + if (err) + goto error1; + + *rsrcimp = srcimp; + + return 0; + +error1: + spin_lock_irqsave(&mgr->mgr_lock, flags); + for (i--; i >= 0; i--) + mgr_put_resource(&mgr->mgr, 1, srcimp->idx[i]); + + spin_unlock_irqrestore(&mgr->mgr_lock, flags); + kfree(srcimp); + return err; +} + +static int put_srcimp_rsc(struct srcimp_mgr *mgr, struct srcimp *srcimp) +{ + unsigned long flags; + int i; + + spin_lock_irqsave(&mgr->mgr_lock, flags); + for (i = 0; i < srcimp->rsc.msr; i++) + mgr_put_resource(&mgr->mgr, 1, srcimp->idx[i]); + + spin_unlock_irqrestore(&mgr->mgr_lock, flags); + srcimp_rsc_uninit(srcimp); + kfree(srcimp); + + return 0; +} + +static int srcimp_map_op(void *data, struct imapper *entry) +{ + struct rsc_mgr *mgr = &((struct srcimp_mgr *)data)->mgr; + struct hw *hw = mgr->hw; + + hw->srcimp_mgr_set_imaparc(mgr->ctrl_blk, entry->slot); + hw->srcimp_mgr_set_imapuser(mgr->ctrl_blk, entry->user); + hw->srcimp_mgr_set_imapnxt(mgr->ctrl_blk, entry->next); + hw->srcimp_mgr_set_imapaddr(mgr->ctrl_blk, entry->addr); + hw->srcimp_mgr_commit_write(mgr->hw, mgr->ctrl_blk); + + return 0; +} + +static int srcimp_imap_add(struct srcimp_mgr *mgr, struct imapper *entry) +{ + unsigned long flags; + int err; + + spin_lock_irqsave(&mgr->imap_lock, flags); + if ((0 == entry->addr) && (mgr->init_imap_added)) { + input_mapper_delete(&mgr->imappers, + mgr->init_imap, srcimp_map_op, mgr); + mgr->init_imap_added = 0; + } + err = input_mapper_add(&mgr->imappers, entry, srcimp_map_op, mgr); + spin_unlock_irqrestore(&mgr->imap_lock, flags); + + return err; +} + +static int srcimp_imap_delete(struct srcimp_mgr *mgr, struct imapper *entry) +{ + unsigned long flags; + int err; + + spin_lock_irqsave(&mgr->imap_lock, flags); + err = input_mapper_delete(&mgr->imappers, entry, srcimp_map_op, mgr); + if (list_empty(&mgr->imappers)) { + input_mapper_add(&mgr->imappers, mgr->init_imap, + srcimp_map_op, mgr); + mgr->init_imap_added = 1; + } + spin_unlock_irqrestore(&mgr->imap_lock, flags); + + return err; +} + +int srcimp_mgr_create(void *hw, struct srcimp_mgr **rsrcimp_mgr) +{ + int err; + struct srcimp_mgr *srcimp_mgr; + struct imapper *entry; + + *rsrcimp_mgr = NULL; + srcimp_mgr = kzalloc(sizeof(*srcimp_mgr), GFP_KERNEL); + if (NULL == srcimp_mgr) + return -ENOMEM; + + err = rsc_mgr_init(&srcimp_mgr->mgr, SRCIMP, SRCIMP_RESOURCE_NUM, hw); + if (err) + goto error1; + + spin_lock_init(&srcimp_mgr->mgr_lock); + spin_lock_init(&srcimp_mgr->imap_lock); + INIT_LIST_HEAD(&srcimp_mgr->imappers); + entry = kzalloc(sizeof(*entry), GFP_KERNEL); + if (NULL == entry) { + err = -ENOMEM; + goto error2; + } + entry->slot = entry->addr = entry->next = entry->user = 0; + list_add(&entry->list, &srcimp_mgr->imappers); + srcimp_mgr->init_imap = entry; + srcimp_mgr->init_imap_added = 1; + + srcimp_mgr->get_srcimp = get_srcimp_rsc; + srcimp_mgr->put_srcimp = put_srcimp_rsc; + srcimp_mgr->imap_add = srcimp_imap_add; + srcimp_mgr->imap_delete = srcimp_imap_delete; + + *rsrcimp_mgr = srcimp_mgr; + + return 0; + +error2: + rsc_mgr_uninit(&srcimp_mgr->mgr); +error1: + kfree(srcimp_mgr); + return err; +} + +int srcimp_mgr_destroy(struct srcimp_mgr *srcimp_mgr) +{ + unsigned long flags; + + /* free src input mapper list */ + spin_lock_irqsave(&srcimp_mgr->imap_lock, flags); + free_input_mapper_list(&srcimp_mgr->imappers); + spin_unlock_irqrestore(&srcimp_mgr->imap_lock, flags); + + rsc_mgr_uninit(&srcimp_mgr->mgr); + kfree(srcimp_mgr); + + return 0; +} diff --git a/sound/pci/ctxfi/ctsrc.h b/sound/pci/ctxfi/ctsrc.h new file mode 100644 index 000000000000..259366aabcac --- /dev/null +++ b/sound/pci/ctxfi/ctsrc.h @@ -0,0 +1,149 @@ +/** + * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. + * + * This source file is released under GPL v2 license (no other versions). + * See the COPYING file included in the main directory of this source + * distribution for the license terms and conditions. + * + * @File ctsrc.h + * + * @Brief + * This file contains the definition of the Sample Rate Convertor + * resource management object. + * + * @Author Liu Chun + * @Date May 13 2008 + * + */ + +#ifndef CTSRC_H +#define CTSRC_H + +#include "ctresource.h" +#include "ctimap.h" +#include +#include + +#define SRC_STATE_OFF 0x0 +#define SRC_STATE_INIT 0x4 +#define SRC_STATE_RUN 0x5 + +#define SRC_SF_U8 0x0 +#define SRC_SF_S16 0x1 +#define SRC_SF_S24 0x2 +#define SRC_SF_S32 0x3 +#define SRC_SF_F32 0x4 + +/* Define the descriptor of a src resource */ +enum SRCMODE { + MEMRD, /* Read data from host memory */ + MEMWR, /* Write data to host memory */ + ARCRW, /* Read from and write to audio ring channel */ + NUM_SRCMODES +}; + +struct src_rsc_ops; + +struct src { + struct rsc rsc; /* Basic resource info */ + struct src *intlv; /* Pointer to next interleaved SRC in a series */ + struct src_rsc_ops *ops; /* SRC specific operations */ + /* Number of contiguous srcs for interleaved usage */ + unsigned char multi; + unsigned char mode; /* Working mode of this SRC resource */ +}; + +struct src_rsc_ops { + int (*set_state)(struct src *src, unsigned int state); + int (*set_bm)(struct src *src, unsigned int bm); + int (*set_sf)(struct src *src, unsigned int sf); + int (*set_pm)(struct src *src, unsigned int pm); + int (*set_rom)(struct src *src, unsigned int rom); + int (*set_vo)(struct src *src, unsigned int vo); + int (*set_st)(struct src *src, unsigned int st); + int (*set_bp)(struct src *src, unsigned int bp); + int (*set_cisz)(struct src *src, unsigned int cisz); + int (*set_ca)(struct src *src, unsigned int ca); + int (*set_sa)(struct src *src, unsigned int sa); + int (*set_la)(struct src *src, unsigned int la); + int (*set_pitch)(struct src *src, unsigned int pitch); + int (*set_clr_zbufs)(struct src *src); + int (*commit_write)(struct src *src); + int (*get_ca)(struct src *src); + int (*init)(struct src *src); + struct src* (*next_interleave)(struct src *src); +}; + +/* Define src resource request description info */ +struct src_desc { + /* Number of contiguous master srcs for interleaved usage */ + unsigned char multi; + unsigned char msr; + unsigned char mode; /* Working mode of the requested srcs */ +}; + +/* Define src manager object */ +struct src_mgr { + struct rsc_mgr mgr; /* Basic resource manager info */ + spinlock_t mgr_lock; + + /* request src resource */ + int (*get_src)(struct src_mgr *mgr, + const struct src_desc *desc, struct src **rsrc); + /* return src resource */ + int (*put_src)(struct src_mgr *mgr, struct src *src); + int (*src_enable_s)(struct src_mgr *mgr, struct src *src); + int (*src_enable)(struct src_mgr *mgr, struct src *src); + int (*src_disable)(struct src_mgr *mgr, struct src *src); + int (*commit_write)(struct src_mgr *mgr); +}; + +/* Define the descriptor of a SRC Input Mapper resource */ +struct srcimp_mgr; +struct srcimp_rsc_ops; + +struct srcimp { + struct rsc rsc; + unsigned char idx[8]; + struct imapper *imappers; + unsigned int mapped; /* A bit-map indicating which conj rsc is mapped */ + struct srcimp_mgr *mgr; + struct srcimp_rsc_ops *ops; +}; + +struct srcimp_rsc_ops { + int (*map)(struct srcimp *srcimp, struct src *user, struct rsc *input); + int (*unmap)(struct srcimp *srcimp); +}; + +/* Define SRCIMP resource request description info */ +struct srcimp_desc { + unsigned int msr; +}; + +struct srcimp_mgr { + struct rsc_mgr mgr; /* Basic resource manager info */ + spinlock_t mgr_lock; + spinlock_t imap_lock; + struct list_head imappers; + struct imapper *init_imap; + unsigned int init_imap_added; + + /* request srcimp resource */ + int (*get_srcimp)(struct srcimp_mgr *mgr, + const struct srcimp_desc *desc, + struct srcimp **rsrcimp); + /* return srcimp resource */ + int (*put_srcimp)(struct srcimp_mgr *mgr, struct srcimp *srcimp); + int (*imap_add)(struct srcimp_mgr *mgr, struct imapper *entry); + int (*imap_delete)(struct srcimp_mgr *mgr, struct imapper *entry); +}; + +/* Constructor and destructor of SRC resource manager */ +int src_mgr_create(void *hw, struct src_mgr **rsrc_mgr); +int src_mgr_destroy(struct src_mgr *src_mgr); +/* Constructor and destructor of SRCIMP resource manager */ +int srcimp_mgr_create(void *hw, struct srcimp_mgr **rsrc_mgr); +int srcimp_mgr_destroy(struct srcimp_mgr *srcimp_mgr); + +#endif /* CTSRC_H */ diff --git a/sound/pci/ctxfi/cttimer.c b/sound/pci/ctxfi/cttimer.c new file mode 100644 index 000000000000..93b0aedc36d4 --- /dev/null +++ b/sound/pci/ctxfi/cttimer.c @@ -0,0 +1,443 @@ +/* + * PCM timer handling on ctxfi + * + * This source file is released under GPL v2 license (no other versions). + * See the COPYING file included in the main directory of this source + * distribution for the license terms and conditions. + */ + +#include +#include +#include +#include +#include +#include "ctatc.h" +#include "cthardware.h" +#include "cttimer.h" + +static int use_system_timer; +MODULE_PARM_DESC(use_system_timer, "Foce to use system-timer"); +module_param(use_system_timer, bool, S_IRUGO); + +struct ct_timer_ops { + void (*init)(struct ct_timer_instance *); + void (*prepare)(struct ct_timer_instance *); + void (*start)(struct ct_timer_instance *); + void (*stop)(struct ct_timer_instance *); + void (*free_instance)(struct ct_timer_instance *); + void (*interrupt)(struct ct_timer *); + void (*free_global)(struct ct_timer *); +}; + +/* timer instance -- assigned to each PCM stream */ +struct ct_timer_instance { + spinlock_t lock; + struct ct_timer *timer_base; + struct ct_atc_pcm *apcm; + struct snd_pcm_substream *substream; + struct timer_list timer; + struct list_head instance_list; + struct list_head running_list; + unsigned int position; + unsigned int frag_count; + unsigned int running:1; + unsigned int need_update:1; +}; + +/* timer instance manager */ +struct ct_timer { + spinlock_t lock; /* global timer lock (for xfitimer) */ + spinlock_t list_lock; /* lock for instance list */ + struct ct_atc *atc; + struct ct_timer_ops *ops; + struct list_head instance_head; + struct list_head running_head; + unsigned int wc; /* current wallclock */ + unsigned int irq_handling:1; /* in IRQ handling */ + unsigned int reprogram:1; /* need to reprogram the internval */ + unsigned int running:1; /* global timer running */ +}; + + +/* + * system-timer-based updates + */ + +static void ct_systimer_callback(unsigned long data) +{ + struct ct_timer_instance *ti = (struct ct_timer_instance *)data; + struct snd_pcm_substream *substream = ti->substream; + struct snd_pcm_runtime *runtime = substream->runtime; + struct ct_atc_pcm *apcm = ti->apcm; + unsigned int period_size = runtime->period_size; + unsigned int buffer_size = runtime->buffer_size; + unsigned long flags; + unsigned int position, dist, interval; + + position = substream->ops->pointer(substream); + dist = (position + buffer_size - ti->position) % buffer_size; + if (dist >= period_size || + position / period_size != ti->position / period_size) { + apcm->interrupt(apcm); + ti->position = position; + } + /* Add extra HZ*5/1000 to avoid overrun issue when recording + * at 8kHz in 8-bit format or at 88kHz in 24-bit format. */ + interval = ((period_size - (position % period_size)) + * HZ + (runtime->rate - 1)) / runtime->rate + HZ * 5 / 1000; + spin_lock_irqsave(&ti->lock, flags); + if (ti->running) + mod_timer(&ti->timer, jiffies + interval); + spin_unlock_irqrestore(&ti->lock, flags); +} + +static void ct_systimer_init(struct ct_timer_instance *ti) +{ + setup_timer(&ti->timer, ct_systimer_callback, + (unsigned long)ti); +} + +static void ct_systimer_start(struct ct_timer_instance *ti) +{ + struct snd_pcm_runtime *runtime = ti->substream->runtime; + unsigned long flags; + + spin_lock_irqsave(&ti->lock, flags); + ti->running = 1; + mod_timer(&ti->timer, + jiffies + (runtime->period_size * HZ + + (runtime->rate - 1)) / runtime->rate); + spin_unlock_irqrestore(&ti->lock, flags); +} + +static void ct_systimer_stop(struct ct_timer_instance *ti) +{ + unsigned long flags; + + spin_lock_irqsave(&ti->lock, flags); + ti->running = 0; + del_timer(&ti->timer); + spin_unlock_irqrestore(&ti->lock, flags); +} + +static void ct_systimer_prepare(struct ct_timer_instance *ti) +{ + ct_systimer_stop(ti); + try_to_del_timer_sync(&ti->timer); +} + +#define ct_systimer_free ct_systimer_prepare + +static struct ct_timer_ops ct_systimer_ops = { + .init = ct_systimer_init, + .free_instance = ct_systimer_free, + .prepare = ct_systimer_prepare, + .start = ct_systimer_start, + .stop = ct_systimer_stop, +}; + + +/* + * Handling multiple streams using a global emu20k1 timer irq + */ + +#define CT_TIMER_FREQ 48000 +#define MIN_TICKS 1 +#define MAX_TICKS ((1 << 13) - 1) + +static void ct_xfitimer_irq_rearm(struct ct_timer *atimer, int ticks) +{ + struct hw *hw = atimer->atc->hw; + if (ticks > MAX_TICKS) + ticks = MAX_TICKS; + hw->set_timer_tick(hw, ticks); + if (!atimer->running) + hw->set_timer_irq(hw, 1); + atimer->running = 1; +} + +static void ct_xfitimer_irq_stop(struct ct_timer *atimer) +{ + if (atimer->running) { + struct hw *hw = atimer->atc->hw; + hw->set_timer_irq(hw, 0); + hw->set_timer_tick(hw, 0); + atimer->running = 0; + } +} + +static inline unsigned int ct_xfitimer_get_wc(struct ct_timer *atimer) +{ + struct hw *hw = atimer->atc->hw; + return hw->get_wc(hw); +} + +/* + * reprogram the timer interval; + * checks the running instance list and determines the next timer interval. + * also updates the each stream position, returns the number of streams + * to call snd_pcm_period_elapsed() appropriately + * + * call this inside the lock and irq disabled + */ +static int ct_xfitimer_reprogram(struct ct_timer *atimer, int can_update) +{ + struct ct_timer_instance *ti; + unsigned int min_intr = (unsigned int)-1; + int updates = 0; + unsigned int wc, diff; + + if (list_empty(&atimer->running_head)) { + ct_xfitimer_irq_stop(atimer); + atimer->reprogram = 0; /* clear flag */ + return 0; + } + + wc = ct_xfitimer_get_wc(atimer); + diff = wc - atimer->wc; + atimer->wc = wc; + list_for_each_entry(ti, &atimer->running_head, running_list) { + if (ti->frag_count > diff) + ti->frag_count -= diff; + else { + unsigned int pos; + unsigned int period_size, rate; + + period_size = ti->substream->runtime->period_size; + rate = ti->substream->runtime->rate; + pos = ti->substream->ops->pointer(ti->substream); + if (pos / period_size != ti->position / period_size) { + ti->need_update = 1; + ti->position = pos; + updates++; + } + pos %= period_size; + pos = period_size - pos; + ti->frag_count = div_u64((u64)pos * CT_TIMER_FREQ + + rate - 1, rate); + } + if (ti->need_update && !can_update) + min_intr = 0; /* pending to the next irq */ + if (ti->frag_count < min_intr) + min_intr = ti->frag_count; + } + + if (min_intr < MIN_TICKS) + min_intr = MIN_TICKS; + ct_xfitimer_irq_rearm(atimer, min_intr); + atimer->reprogram = 0; /* clear flag */ + return updates; +} + +/* look through the instance list and call period_elapsed if needed */ +static void ct_xfitimer_check_period(struct ct_timer *atimer) +{ + struct ct_timer_instance *ti; + unsigned long flags; + + spin_lock_irqsave(&atimer->list_lock, flags); + list_for_each_entry(ti, &atimer->instance_head, instance_list) { + if (ti->running && ti->need_update) { + ti->need_update = 0; + ti->apcm->interrupt(ti->apcm); + } + } + spin_unlock_irqrestore(&atimer->list_lock, flags); +} + +/* Handle timer-interrupt */ +static void ct_xfitimer_callback(struct ct_timer *atimer) +{ + int update; + unsigned long flags; + + spin_lock_irqsave(&atimer->lock, flags); + atimer->irq_handling = 1; + do { + update = ct_xfitimer_reprogram(atimer, 1); + spin_unlock(&atimer->lock); + if (update) + ct_xfitimer_check_period(atimer); + spin_lock(&atimer->lock); + } while (atimer->reprogram); + atimer->irq_handling = 0; + spin_unlock_irqrestore(&atimer->lock, flags); +} + +static void ct_xfitimer_prepare(struct ct_timer_instance *ti) +{ + ti->frag_count = ti->substream->runtime->period_size; + ti->running = 0; + ti->need_update = 0; +} + + +/* start/stop the timer */ +static void ct_xfitimer_update(struct ct_timer *atimer) +{ + unsigned long flags; + + spin_lock_irqsave(&atimer->lock, flags); + if (atimer->irq_handling) { + /* reached from IRQ handler; let it handle later */ + atimer->reprogram = 1; + spin_unlock_irqrestore(&atimer->lock, flags); + return; + } + + ct_xfitimer_irq_stop(atimer); + ct_xfitimer_reprogram(atimer, 0); + spin_unlock_irqrestore(&atimer->lock, flags); +} + +static void ct_xfitimer_start(struct ct_timer_instance *ti) +{ + struct ct_timer *atimer = ti->timer_base; + unsigned long flags; + + spin_lock_irqsave(&atimer->lock, flags); + if (list_empty(&ti->running_list)) + atimer->wc = ct_xfitimer_get_wc(atimer); + ti->running = 1; + ti->need_update = 0; + list_add(&ti->running_list, &atimer->running_head); + spin_unlock_irqrestore(&atimer->lock, flags); + ct_xfitimer_update(atimer); +} + +static void ct_xfitimer_stop(struct ct_timer_instance *ti) +{ + struct ct_timer *atimer = ti->timer_base; + unsigned long flags; + + spin_lock_irqsave(&atimer->lock, flags); + list_del_init(&ti->running_list); + ti->running = 0; + spin_unlock_irqrestore(&atimer->lock, flags); + ct_xfitimer_update(atimer); +} + +static void ct_xfitimer_free_global(struct ct_timer *atimer) +{ + ct_xfitimer_irq_stop(atimer); +} + +static struct ct_timer_ops ct_xfitimer_ops = { + .prepare = ct_xfitimer_prepare, + .start = ct_xfitimer_start, + .stop = ct_xfitimer_stop, + .interrupt = ct_xfitimer_callback, + .free_global = ct_xfitimer_free_global, +}; + +/* + * timer instance + */ + +struct ct_timer_instance * +ct_timer_instance_new(struct ct_timer *atimer, struct ct_atc_pcm *apcm) +{ + struct ct_timer_instance *ti; + + ti = kzalloc(sizeof(*ti), GFP_KERNEL); + if (!ti) + return NULL; + spin_lock_init(&ti->lock); + INIT_LIST_HEAD(&ti->instance_list); + INIT_LIST_HEAD(&ti->running_list); + ti->timer_base = atimer; + ti->apcm = apcm; + ti->substream = apcm->substream; + if (atimer->ops->init) + atimer->ops->init(ti); + + spin_lock_irq(&atimer->list_lock); + list_add(&ti->instance_list, &atimer->instance_head); + spin_unlock_irq(&atimer->list_lock); + + return ti; +} + +void ct_timer_prepare(struct ct_timer_instance *ti) +{ + if (ti->timer_base->ops->prepare) + ti->timer_base->ops->prepare(ti); + ti->position = 0; + ti->running = 0; +} + +void ct_timer_start(struct ct_timer_instance *ti) +{ + struct ct_timer *atimer = ti->timer_base; + atimer->ops->start(ti); +} + +void ct_timer_stop(struct ct_timer_instance *ti) +{ + struct ct_timer *atimer = ti->timer_base; + atimer->ops->stop(ti); +} + +void ct_timer_instance_free(struct ct_timer_instance *ti) +{ + struct ct_timer *atimer = ti->timer_base; + + atimer->ops->stop(ti); /* to be sure */ + if (atimer->ops->free_instance) + atimer->ops->free_instance(ti); + + spin_lock_irq(&atimer->list_lock); + list_del(&ti->instance_list); + spin_unlock_irq(&atimer->list_lock); + + kfree(ti); +} + +/* + * timer manager + */ + +static void ct_timer_interrupt(void *data, unsigned int status) +{ + struct ct_timer *timer = data; + + /* Interval timer interrupt */ + if ((status & IT_INT) && timer->ops->interrupt) + timer->ops->interrupt(timer); +} + +struct ct_timer *ct_timer_new(struct ct_atc *atc) +{ + struct ct_timer *atimer; + struct hw *hw; + + atimer = kzalloc(sizeof(*atimer), GFP_KERNEL); + if (!atimer) + return NULL; + spin_lock_init(&atimer->lock); + spin_lock_init(&atimer->list_lock); + INIT_LIST_HEAD(&atimer->instance_head); + INIT_LIST_HEAD(&atimer->running_head); + atimer->atc = atc; + hw = atc->hw; + if (!use_system_timer && hw->set_timer_irq) { + snd_printd(KERN_INFO "ctxfi: Use xfi-native timer\n"); + atimer->ops = &ct_xfitimer_ops; + hw->irq_callback_data = atimer; + hw->irq_callback = ct_timer_interrupt; + } else { + snd_printd(KERN_INFO "ctxfi: Use system timer\n"); + atimer->ops = &ct_systimer_ops; + } + return atimer; +} + +void ct_timer_free(struct ct_timer *atimer) +{ + struct hw *hw = atimer->atc->hw; + hw->irq_callback = NULL; + if (atimer->ops->free_global) + atimer->ops->free_global(atimer); + kfree(atimer); +} + diff --git a/sound/pci/ctxfi/cttimer.h b/sound/pci/ctxfi/cttimer.h new file mode 100644 index 000000000000..979348229291 --- /dev/null +++ b/sound/pci/ctxfi/cttimer.h @@ -0,0 +1,29 @@ +/* + * Timer handling + */ + +#ifndef __CTTIMER_H +#define __CTTIMER_H + +#include +#include +#include + +struct snd_pcm_substream; +struct ct_atc; +struct ct_atc_pcm; + +struct ct_timer; +struct ct_timer_instance; + +struct ct_timer *ct_timer_new(struct ct_atc *atc); +void ct_timer_free(struct ct_timer *atimer); + +struct ct_timer_instance * +ct_timer_instance_new(struct ct_timer *atimer, struct ct_atc_pcm *apcm); +void ct_timer_instance_free(struct ct_timer_instance *ti); +void ct_timer_start(struct ct_timer_instance *ti); +void ct_timer_stop(struct ct_timer_instance *ti); +void ct_timer_prepare(struct ct_timer_instance *ti); + +#endif /* __CTTIMER_H */ diff --git a/sound/pci/ctxfi/ctvmem.c b/sound/pci/ctxfi/ctvmem.c new file mode 100644 index 000000000000..67665a7e43c6 --- /dev/null +++ b/sound/pci/ctxfi/ctvmem.c @@ -0,0 +1,250 @@ +/** + * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. + * + * This source file is released under GPL v2 license (no other versions). + * See the COPYING file included in the main directory of this source + * distribution for the license terms and conditions. + * + * @File ctvmem.c + * + * @Brief + * This file contains the implementation of virtual memory management object + * for card device. + * + * @Author Liu Chun + * @Date Apr 1 2008 + */ + +#include "ctvmem.h" +#include +#include +#include +#include + +#define CT_PTES_PER_PAGE (CT_PAGE_SIZE / sizeof(void *)) +#define CT_ADDRS_PER_PAGE (CT_PTES_PER_PAGE * CT_PAGE_SIZE) + +/* * + * Find or create vm block based on requested @size. + * @size must be page aligned. + * */ +static struct ct_vm_block * +get_vm_block(struct ct_vm *vm, unsigned int size) +{ + struct ct_vm_block *block = NULL, *entry; + struct list_head *pos; + + size = CT_PAGE_ALIGN(size); + if (size > vm->size) { + printk(KERN_ERR "ctxfi: Fail! No sufficient device virtural " + "memory space available!\n"); + return NULL; + } + + mutex_lock(&vm->lock); + list_for_each(pos, &vm->unused) { + entry = list_entry(pos, struct ct_vm_block, list); + if (entry->size >= size) + break; /* found a block that is big enough */ + } + if (pos == &vm->unused) + goto out; + + if (entry->size == size) { + /* Move the vm node from unused list to used list directly */ + list_del(&entry->list); + list_add(&entry->list, &vm->used); + vm->size -= size; + block = entry; + goto out; + } + + block = kzalloc(sizeof(*block), GFP_KERNEL); + if (NULL == block) + goto out; + + block->addr = entry->addr; + block->size = size; + list_add(&block->list, &vm->used); + entry->addr += size; + entry->size -= size; + vm->size -= size; + + out: + mutex_unlock(&vm->lock); + return block; +} + +static void put_vm_block(struct ct_vm *vm, struct ct_vm_block *block) +{ + struct ct_vm_block *entry, *pre_ent; + struct list_head *pos, *pre; + + block->size = CT_PAGE_ALIGN(block->size); + + mutex_lock(&vm->lock); + list_del(&block->list); + vm->size += block->size; + + list_for_each(pos, &vm->unused) { + entry = list_entry(pos, struct ct_vm_block, list); + if (entry->addr >= (block->addr + block->size)) + break; /* found a position */ + } + if (pos == &vm->unused) { + list_add_tail(&block->list, &vm->unused); + entry = block; + } else { + if ((block->addr + block->size) == entry->addr) { + entry->addr = block->addr; + entry->size += block->size; + kfree(block); + } else { + __list_add(&block->list, pos->prev, pos); + entry = block; + } + } + + pos = &entry->list; + pre = pos->prev; + while (pre != &vm->unused) { + entry = list_entry(pos, struct ct_vm_block, list); + pre_ent = list_entry(pre, struct ct_vm_block, list); + if ((pre_ent->addr + pre_ent->size) > entry->addr) + break; + + pre_ent->size += entry->size; + list_del(pos); + kfree(entry); + pos = pre; + pre = pos->prev; + } + mutex_unlock(&vm->lock); +} + +/* Map host addr (kmalloced/vmalloced) to device logical addr. */ +static struct ct_vm_block * +ct_vm_map(struct ct_vm *vm, struct snd_pcm_substream *substream, int size) +{ + struct ct_vm_block *block; + unsigned int pte_start; + unsigned i, pages; + unsigned long *ptp; + + block = get_vm_block(vm, size); + if (block == NULL) { + printk(KERN_ERR "ctxfi: No virtual memory block that is big " + "enough to allocate!\n"); + return NULL; + } + + ptp = vm->ptp[0]; + pte_start = (block->addr >> CT_PAGE_SHIFT); + pages = block->size >> CT_PAGE_SHIFT; + for (i = 0; i < pages; i++) { + unsigned long addr; + addr = snd_pcm_sgbuf_get_addr(substream, i << CT_PAGE_SHIFT); + ptp[pte_start + i] = addr; + } + + block->size = size; + return block; +} + +static void ct_vm_unmap(struct ct_vm *vm, struct ct_vm_block *block) +{ + /* do unmapping */ + put_vm_block(vm, block); +} + +/* * + * return the host (kmalloced) addr of the @index-th device + * page talbe page on success, or NULL on failure. + * The first returned NULL indicates the termination. + * */ +static void * +ct_get_ptp_virt(struct ct_vm *vm, int index) +{ + void *addr; + + addr = (index >= CT_PTP_NUM) ? NULL : vm->ptp[index]; + + return addr; +} + +int ct_vm_create(struct ct_vm **rvm) +{ + struct ct_vm *vm; + struct ct_vm_block *block; + int i; + + *rvm = NULL; + + vm = kzalloc(sizeof(*vm), GFP_KERNEL); + if (NULL == vm) + return -ENOMEM; + + mutex_init(&vm->lock); + + /* Allocate page table pages */ + for (i = 0; i < CT_PTP_NUM; i++) { + vm->ptp[i] = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (NULL == vm->ptp[i]) + break; + } + if (!i) { + /* no page table pages are allocated */ + kfree(vm); + return -ENOMEM; + } + vm->size = CT_ADDRS_PER_PAGE * i; + /* Initialise remaining ptps */ + for (; i < CT_PTP_NUM; i++) + vm->ptp[i] = NULL; + + vm->map = ct_vm_map; + vm->unmap = ct_vm_unmap; + vm->get_ptp_virt = ct_get_ptp_virt; + INIT_LIST_HEAD(&vm->unused); + INIT_LIST_HEAD(&vm->used); + block = kzalloc(sizeof(*block), GFP_KERNEL); + if (NULL != block) { + block->addr = 0; + block->size = vm->size; + list_add(&block->list, &vm->unused); + } + + *rvm = vm; + return 0; +} + +/* The caller must ensure no mapping pages are being used + * by hardware before calling this function */ +void ct_vm_destroy(struct ct_vm *vm) +{ + int i; + struct list_head *pos; + struct ct_vm_block *entry; + + /* free used and unused list nodes */ + while (!list_empty(&vm->used)) { + pos = vm->used.next; + list_del(pos); + entry = list_entry(pos, struct ct_vm_block, list); + kfree(entry); + } + while (!list_empty(&vm->unused)) { + pos = vm->unused.next; + list_del(pos); + entry = list_entry(pos, struct ct_vm_block, list); + kfree(entry); + } + + /* free allocated page table pages */ + for (i = 0; i < CT_PTP_NUM; i++) + kfree(vm->ptp[i]); + + vm->size = 0; + + kfree(vm); +} diff --git a/sound/pci/ctxfi/ctvmem.h b/sound/pci/ctxfi/ctvmem.h new file mode 100644 index 000000000000..01e4fd0386a3 --- /dev/null +++ b/sound/pci/ctxfi/ctvmem.h @@ -0,0 +1,61 @@ +/** + * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. + * + * This source file is released under GPL v2 license (no other versions). + * See the COPYING file included in the main directory of this source + * distribution for the license terms and conditions. + * + * @File ctvmem.h + * + * @Brief + * This file contains the definition of virtual memory management object + * for card device. + * + * @Author Liu Chun + * @Date Mar 28 2008 + */ + +#ifndef CTVMEM_H +#define CTVMEM_H + +#define CT_PTP_NUM 1 /* num of device page table pages */ + +#include +#include + +/* The chip can handle the page table of 4k pages + * (emu20k1 can handle even 8k pages, but we don't use it right now) + */ +#define CT_PAGE_SIZE 4096 +#define CT_PAGE_SHIFT 12 +#define CT_PAGE_MASK (~(PAGE_SIZE - 1)) +#define CT_PAGE_ALIGN(addr) ALIGN(addr, CT_PAGE_SIZE) + +struct ct_vm_block { + unsigned int addr; /* starting logical addr of this block */ + unsigned int size; /* size of this device virtual mem block */ + struct list_head list; +}; + +struct snd_pcm_substream; + +/* Virtual memory management object for card device */ +struct ct_vm { + void *ptp[CT_PTP_NUM]; /* Device page table pages */ + unsigned int size; /* Available addr space in bytes */ + struct list_head unused; /* List of unused blocks */ + struct list_head used; /* List of used blocks */ + struct mutex lock; + + /* Map host addr (kmalloced/vmalloced) to device logical addr. */ + struct ct_vm_block *(*map)(struct ct_vm *, struct snd_pcm_substream *, + int size); + /* Unmap device logical addr area. */ + void (*unmap)(struct ct_vm *, struct ct_vm_block *block); + void *(*get_ptp_virt)(struct ct_vm *vm, int index); +}; + +int ct_vm_create(struct ct_vm **rvm); +void ct_vm_destroy(struct ct_vm *vm); + +#endif /* CTVMEM_H */ diff --git a/sound/pci/ctxfi/xfi.c b/sound/pci/ctxfi/xfi.c new file mode 100644 index 000000000000..76541748e7bc --- /dev/null +++ b/sound/pci/ctxfi/xfi.c @@ -0,0 +1,164 @@ +/* + * xfi linux driver. + * + * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. + * + * This source file is released under GPL v2 license (no other versions). + * See the COPYING file included in the main directory of this source + * distribution for the license terms and conditions. + */ + +#include +#include +#include +#include +#include +#include +#include "ctatc.h" +#include "cthardware.h" + +MODULE_AUTHOR("Creative Technology Ltd"); +MODULE_DESCRIPTION("X-Fi driver version 1.03"); +MODULE_LICENSE("GPL v2"); +MODULE_SUPPORTED_DEVICE("{{Creative Labs, Sound Blaster X-Fi}"); + +static unsigned int reference_rate = 48000; +static unsigned int multiple = 2; +MODULE_PARM_DESC(reference_rate, "Reference rate (default=48000)"); +module_param(reference_rate, uint, S_IRUGO); +MODULE_PARM_DESC(multiple, "Rate multiplier (default=2)"); +module_param(multiple, uint, S_IRUGO); + +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; +static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; +static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; + +module_param_array(index, int, NULL, 0444); +MODULE_PARM_DESC(index, "Index value for Creative X-Fi driver"); +module_param_array(id, charp, NULL, 0444); +MODULE_PARM_DESC(id, "ID string for Creative X-Fi driver"); +module_param_array(enable, bool, NULL, 0444); +MODULE_PARM_DESC(enable, "Enable Creative X-Fi driver"); + +static struct pci_device_id ct_pci_dev_ids[] = { + /* only X-Fi is supported, so... */ + { PCI_DEVICE(PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_20K1), + .driver_data = ATC20K1, + }, + { PCI_DEVICE(PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_20K2), + .driver_data = ATC20K2, + }, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, ct_pci_dev_ids); + +static int __devinit +ct_card_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) +{ + static int dev; + struct snd_card *card; + struct ct_atc *atc; + int err; + + if (dev >= SNDRV_CARDS) + return -ENODEV; + + if (!enable[dev]) { + dev++; + return -ENOENT; + } + err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); + if (err) + return err; + if ((reference_rate != 48000) && (reference_rate != 44100)) { + printk(KERN_ERR "ctxfi: Invalid reference_rate value %u!!!\n", + reference_rate); + printk(KERN_ERR "ctxfi: The valid values for reference_rate " + "are 48000 and 44100, Value 48000 is assumed.\n"); + reference_rate = 48000; + } + if ((multiple != 1) && (multiple != 2)) { + printk(KERN_ERR "ctxfi: Invalid multiple value %u!!!\n", + multiple); + printk(KERN_ERR "ctxfi: The valid values for multiple are " + "1 and 2, Value 2 is assumed.\n"); + multiple = 2; + } + err = ct_atc_create(card, pci, reference_rate, multiple, + pci_id->driver_data, &atc); + if (err < 0) + goto error; + + card->private_data = atc; + + /* Create alsa devices supported by this card */ + err = ct_atc_create_alsa_devs(atc); + if (err < 0) + goto error; + + strcpy(card->driver, "SB-XFi"); + strcpy(card->shortname, "Creative X-Fi"); + snprintf(card->longname, sizeof(card->longname), "%s %s %s", + card->shortname, atc->chip_name, atc->model_name); + + err = snd_card_register(card); + if (err < 0) + goto error; + + pci_set_drvdata(pci, card); + dev++; + + return 0; + +error: + snd_card_free(card); + return err; +} + +static void __devexit ct_card_remove(struct pci_dev *pci) +{ + snd_card_free(pci_get_drvdata(pci)); + pci_set_drvdata(pci, NULL); +} + +#ifdef CONFIG_PM +static int ct_card_suspend(struct pci_dev *pci, pm_message_t state) +{ + struct snd_card *card = pci_get_drvdata(pci); + struct ct_atc *atc = card->private_data; + + return atc->suspend(atc, state); +} + +static int ct_card_resume(struct pci_dev *pci) +{ + struct snd_card *card = pci_get_drvdata(pci); + struct ct_atc *atc = card->private_data; + + return atc->resume(atc); +} +#endif + +static struct pci_driver ct_driver = { + .name = "SB-XFi", + .id_table = ct_pci_dev_ids, + .probe = ct_card_probe, + .remove = __devexit_p(ct_card_remove), +#ifdef CONFIG_PM + .suspend = ct_card_suspend, + .resume = ct_card_resume, +#endif +}; + +static int __init ct_card_init(void) +{ + return pci_register_driver(&ct_driver); +} + +static void __exit ct_card_exit(void) +{ + pci_unregister_driver(&ct_driver); +} + +module_init(ct_card_init) +module_exit(ct_card_exit) diff --git a/sound/pci/emu10k1/Makefile b/sound/pci/emu10k1/Makefile index cf2d5636d8be..fc5591e7777e 100644 --- a/sound/pci/emu10k1/Makefile +++ b/sound/pci/emu10k1/Makefile @@ -9,15 +9,7 @@ snd-emu10k1-objs := emu10k1.o emu10k1_main.o \ snd-emu10k1-synth-objs := emu10k1_synth.o emu10k1_callback.o emu10k1_patch.o snd-emu10k1x-objs := emu10k1x.o -# -# this function returns: -# "m" - CONFIG_SND_SEQUENCER is m -# - CONFIG_SND_SEQUENCER is undefined -# otherwise parameter #1 value -# -sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1))) - # Toplevel Module Dependency obj-$(CONFIG_SND_EMU10K1) += snd-emu10k1.o -obj-$(call sequencer,$(CONFIG_SND_EMU10K1)) += snd-emu10k1-synth.o +obj-$(CONFIG_SND_EMU10K1_SEQ) += snd-emu10k1-synth.o obj-$(CONFIG_SND_EMU10K1X) += snd-emu10k1x.o diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index 1970f0e70f37..4d3ad793e98f 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c @@ -858,7 +858,6 @@ static int __devinit snd_emu10k1x_pcm(struct emu10k1x *emu, int device, struct s } pcm->info_flags = 0; - pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; switch(device) { case 0: strcpy(pcm->name, "EMU10K1X Front"); diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index 78f62fd404c2..55b83ef73c63 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -1736,7 +1736,7 @@ static struct snd_pcm_hardware snd_emu10k1_fx8010_playback = .buffer_bytes_max = (128*1024), .period_bytes_min = 1024, .period_bytes_max = (128*1024), - .periods_min = 1, + .periods_min = 2, .periods_max = 1024, .fifo_size = 0, }; diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index eb2a19b894a0..04438f1d682d 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -2,7 +2,6 @@ menuconfig SND_HDA_INTEL tristate "Intel HD Audio" select SND_PCM select SND_VMASTER - select SND_JACK if INPUT=y || INPUT=SND help Say Y here to include support for Intel "High Definition Audio" (Azalia) and its compatible devices. @@ -39,6 +38,14 @@ config SND_HDA_INPUT_BEEP Say Y here to build a digital beep interface for HD-audio driver. This interface is used to generate digital beeps. +config SND_HDA_INPUT_JACK + bool "Support jack plugging notification via input layer" + depends on INPUT=y || INPUT=SND_HDA_INTEL + select SND_JACK + help + Say Y here to enable the jack plugging notification via + input layer. + config SND_HDA_CODEC_REALTEK bool "Build Realtek HD-audio codec support" default y @@ -139,6 +146,19 @@ config SND_HDA_CODEC_CONEXANT snd-hda-codec-conexant. This module is automatically loaded at probing. +config SND_HDA_CODEC_CA0110 + bool "Build Creative CA0110-IBG codec support" + depends on SND_HDA_INTEL + default y + help + Say Y here to include Creative CA0110-IBG codec support in + snd-hda-intel driver, found on some Creative X-Fi cards. + + When the HD-audio driver is built as a module, the codec + support code is also built as another module, + snd-hda-codec-ca0110. + This module is automatically loaded at probing. + config SND_HDA_CODEC_CMEDIA bool "Build C-Media HD-audio codec support" default y diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index 50f9d0967251..e3081d4586cc 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile @@ -13,6 +13,7 @@ snd-hda-codec-analog-objs := patch_analog.o snd-hda-codec-idt-objs := patch_sigmatel.o snd-hda-codec-si3054-objs := patch_si3054.o snd-hda-codec-atihdmi-objs := patch_atihdmi.o +snd-hda-codec-ca0110-objs := patch_ca0110.o snd-hda-codec-conexant-objs := patch_conexant.o snd-hda-codec-via-objs := patch_via.o snd-hda-codec-nvhdmi-objs := patch_nvhdmi.o @@ -40,6 +41,9 @@ endif ifdef CONFIG_SND_HDA_CODEC_ATIHDMI obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-atihdmi.o endif +ifdef CONFIG_SND_HDA_CODEC_CA0110 +obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-ca0110.o +endif ifdef CONFIG_SND_HDA_CODEC_CONEXANT obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-conexant.o endif diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c index 4de5bacd3929..29272f2e95a0 100644 --- a/sound/pci/hda/hda_beep.c +++ b/sound/pci/hda/hda_beep.c @@ -45,6 +45,46 @@ static void snd_hda_generate_beep(struct work_struct *work) AC_VERB_SET_BEEP_CONTROL, beep->tone); } +/* (non-standard) Linear beep tone calculation for IDT/STAC codecs + * + * The tone frequency of beep generator on IDT/STAC codecs is + * defined from the 8bit tone parameter, in Hz, + * freq = 48000 * (257 - tone) / 1024 + * that is from 12kHz to 93.75kHz in step of 46.875 hz + */ +static int beep_linear_tone(struct hda_beep *beep, int hz) +{ + hz *= 1000; /* fixed point */ + hz = hz - DIGBEEP_HZ_MIN; + if (hz < 0) + hz = 0; /* turn off PC beep*/ + else if (hz >= (DIGBEEP_HZ_MAX - DIGBEEP_HZ_MIN)) + hz = 0xff; + else { + hz /= DIGBEEP_HZ_STEP; + hz++; + } + return hz; +} + +/* HD-audio standard beep tone parameter calculation + * + * The tone frequency in Hz is calculated as + * freq = 48000 / (tone * 4) + * from 47Hz to 12kHz + */ +static int beep_standard_tone(struct hda_beep *beep, int hz) +{ + if (hz <= 0) + return 0; /* disabled */ + hz = 12000 / hz; + if (hz > 0xff) + return 0xff; + if (hz <= 0) + return 1; + return hz; +} + static int snd_hda_beep_event(struct input_dev *dev, unsigned int type, unsigned int code, int hz) { @@ -55,21 +95,14 @@ static int snd_hda_beep_event(struct input_dev *dev, unsigned int type, if (hz) hz = 1000; case SND_TONE: - hz *= 1000; /* fixed point */ - hz = hz - DIGBEEP_HZ_MIN; - if (hz < 0) - hz = 0; /* turn off PC beep*/ - else if (hz >= (DIGBEEP_HZ_MAX - DIGBEEP_HZ_MIN)) - hz = 0xff; - else { - hz /= DIGBEEP_HZ_STEP; - hz++; - } + if (beep->linear_tone) + beep->tone = beep_linear_tone(beep, hz); + else + beep->tone = beep_standard_tone(beep, hz); break; default: return -1; } - beep->tone = hz; /* schedule beep event */ schedule_work(&beep->beep_work); diff --git a/sound/pci/hda/hda_beep.h b/sound/pci/hda/hda_beep.h index 51bf6a5daf39..0c3de787c717 100644 --- a/sound/pci/hda/hda_beep.h +++ b/sound/pci/hda/hda_beep.h @@ -30,8 +30,9 @@ struct hda_beep { struct hda_codec *codec; char phys[32]; int tone; - int nid; - int enabled; + hda_nid_t nid; + unsigned int enabled:1; + unsigned int linear_tone:1; /* linear tone for IDT/STAC codec */ struct work_struct beep_work; /* scheduled task for beep event */ }; diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 8820faf6c9d8..462e2cedaa6a 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -48,6 +48,7 @@ static struct hda_vendor_id hda_vendor_ids[] = { { 0x1095, "Silicon Image" }, { 0x10de, "Nvidia" }, { 0x10ec, "Realtek" }, + { 0x1102, "Creative" }, { 0x1106, "VIA" }, { 0x111d, "IDT" }, { 0x11c1, "LSI" }, @@ -157,6 +158,39 @@ make_codec_cmd(struct hda_codec *codec, hda_nid_t nid, int direct, return val; } +/* + * Send and receive a verb + */ +static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd, + unsigned int *res) +{ + struct hda_bus *bus = codec->bus; + int err; + + if (res) + *res = -1; + again: + snd_hda_power_up(codec); + mutex_lock(&bus->cmd_mutex); + err = bus->ops.command(bus, cmd); + if (!err && res) + *res = bus->ops.get_response(bus); + mutex_unlock(&bus->cmd_mutex); + snd_hda_power_down(codec); + if (res && *res == -1 && bus->rirb_error) { + if (bus->response_reset) { + snd_printd("hda_codec: resetting BUS due to " + "fatal communication error\n"); + bus->ops.bus_reset(bus); + } + goto again; + } + /* clear reset-flag when the communication gets recovered */ + if (!err) + bus->response_reset = 0; + return err; +} + /** * snd_hda_codec_read - send a command and get the response * @codec: the HDA codec @@ -173,18 +207,9 @@ unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid, int direct, unsigned int verb, unsigned int parm) { - struct hda_bus *bus = codec->bus; + unsigned cmd = make_codec_cmd(codec, nid, direct, verb, parm); unsigned int res; - - res = make_codec_cmd(codec, nid, direct, verb, parm); - snd_hda_power_up(codec); - mutex_lock(&bus->cmd_mutex); - if (!bus->ops.command(bus, res)) - res = bus->ops.get_response(bus); - else - res = (unsigned int)-1; - mutex_unlock(&bus->cmd_mutex); - snd_hda_power_down(codec); + codec_exec_verb(codec, cmd, &res); return res; } EXPORT_SYMBOL_HDA(snd_hda_codec_read); @@ -204,17 +229,10 @@ EXPORT_SYMBOL_HDA(snd_hda_codec_read); int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct, unsigned int verb, unsigned int parm) { - struct hda_bus *bus = codec->bus; + unsigned int cmd = make_codec_cmd(codec, nid, direct, verb, parm); unsigned int res; - int err; - - res = make_codec_cmd(codec, nid, direct, verb, parm); - snd_hda_power_up(codec); - mutex_lock(&bus->cmd_mutex); - err = bus->ops.command(bus, res); - mutex_unlock(&bus->cmd_mutex); - snd_hda_power_down(codec); - return err; + return codec_exec_verb(codec, cmd, + codec->bus->sync_write ? &res : NULL); } EXPORT_SYMBOL_HDA(snd_hda_codec_write); @@ -613,7 +631,10 @@ static int get_codec_name(struct hda_codec *codec) const struct hda_vendor_id *c; const char *vendor = NULL; u16 vendor_id = codec->vendor_id >> 16; - char tmp[16], name[32]; + char tmp[16]; + + if (codec->vendor_name) + goto get_chip_name; for (c = hda_vendor_ids; c->id; c++) { if (c->id == vendor_id) { @@ -625,14 +646,21 @@ static int get_codec_name(struct hda_codec *codec) sprintf(tmp, "Generic %04x", vendor_id); vendor = tmp; } + codec->vendor_name = kstrdup(vendor, GFP_KERNEL); + if (!codec->vendor_name) + return -ENOMEM; + + get_chip_name: + if (codec->chip_name) + return 0; + if (codec->preset && codec->preset->name) - snprintf(name, sizeof(name), "%s %s", vendor, - codec->preset->name); - else - snprintf(name, sizeof(name), "%s ID %x", vendor, - codec->vendor_id & 0xffff); - codec->name = kstrdup(name, GFP_KERNEL); - if (!codec->name) + codec->chip_name = kstrdup(codec->preset->name, GFP_KERNEL); + else { + sprintf(tmp, "ID %x", codec->vendor_id & 0xffff); + codec->chip_name = kstrdup(tmp, GFP_KERNEL); + } + if (!codec->chip_name) return -ENOMEM; return 0; } @@ -838,7 +866,8 @@ static void snd_hda_codec_free(struct hda_codec *codec) module_put(codec->owner); free_hda_cache(&codec->amp_cache); free_hda_cache(&codec->cmd_cache); - kfree(codec->name); + kfree(codec->vendor_name); + kfree(codec->chip_name); kfree(codec->modelname); kfree(codec->wcaps); kfree(codec); @@ -943,8 +972,6 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_SUBSYSTEM_ID, 0); } - if (bus->modelname) - codec->modelname = kstrdup(bus->modelname, GFP_KERNEL); /* power-up all before initialization */ hda_set_power_state(codec, @@ -979,15 +1006,16 @@ int snd_hda_codec_configure(struct hda_codec *codec) int err; codec->preset = find_codec_preset(codec); - if (!codec->name) { + if (!codec->vendor_name || !codec->chip_name) { err = get_codec_name(codec); if (err < 0) return err; } /* audio codec should override the mixer name */ if (codec->afg || !*codec->bus->card->mixername) - strlcpy(codec->bus->card->mixername, codec->name, - sizeof(codec->bus->card->mixername)); + snprintf(codec->bus->card->mixername, + sizeof(codec->bus->card->mixername), + "%s %s", codec->vendor_name, codec->chip_name); if (is_generic_config(codec)) { err = snd_hda_parse_generic_codec(codec); @@ -1055,6 +1083,8 @@ EXPORT_SYMBOL_HDA(snd_hda_codec_cleanup_stream); /* FIXME: more better hash key? */ #define HDA_HASH_KEY(nid,dir,idx) (u32)((nid) + ((idx) << 16) + ((dir) << 24)) #define HDA_HASH_PINCAP_KEY(nid) (u32)((nid) + (0x02 << 24)) +#define HDA_HASH_PARPCM_KEY(nid) (u32)((nid) + (0x03 << 24)) +#define HDA_HASH_PARSTR_KEY(nid) (u32)((nid) + (0x04 << 24)) #define INFO_AMP_CAPS (1<<0) #define INFO_AMP_VOL(ch) (1 << (1 + (ch))) @@ -1145,19 +1175,32 @@ int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, } EXPORT_SYMBOL_HDA(snd_hda_override_amp_caps); -u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid) +static unsigned int +query_caps_hash(struct hda_codec *codec, hda_nid_t nid, u32 key, + unsigned int (*func)(struct hda_codec *, hda_nid_t)) { struct hda_amp_info *info; - info = get_alloc_amp_hash(codec, HDA_HASH_PINCAP_KEY(nid)); + info = get_alloc_amp_hash(codec, key); if (!info) return 0; if (!info->head.val) { - info->amp_caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); info->head.val |= INFO_AMP_CAPS; + info->amp_caps = func(codec, nid); } return info->amp_caps; } + +static unsigned int read_pin_cap(struct hda_codec *codec, hda_nid_t nid) +{ + return snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); +} + +u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid) +{ + return query_caps_hash(codec, nid, HDA_HASH_PINCAP_KEY(nid), + read_pin_cap); +} EXPORT_SYMBOL_HDA(snd_hda_query_pin_caps); /* @@ -1432,6 +1475,8 @@ _snd_hda_find_mixer_ctl(struct hda_codec *codec, memset(&id, 0, sizeof(id)); id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; id.index = idx; + if (snd_BUG_ON(strlen(name) >= sizeof(id.name))) + return NULL; strcpy(id.name, name); return snd_ctl_find_id(codec->bus->card, &id); } @@ -2242,28 +2287,22 @@ EXPORT_SYMBOL_HDA(snd_hda_create_spdif_in_ctls); int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, int direct, unsigned int verb, unsigned int parm) { - struct hda_bus *bus = codec->bus; - unsigned int res; - int err; + int err = snd_hda_codec_write(codec, nid, direct, verb, parm); + struct hda_cache_head *c; + u32 key; - res = make_codec_cmd(codec, nid, direct, verb, parm); - snd_hda_power_up(codec); - mutex_lock(&bus->cmd_mutex); - err = bus->ops.command(bus, res); - if (!err) { - struct hda_cache_head *c; - u32 key; - /* parm may contain the verb stuff for get/set amp */ - verb = verb | (parm >> 8); - parm &= 0xff; - key = build_cmd_cache_key(nid, verb); - c = get_alloc_hash(&codec->cmd_cache, key); - if (c) - c->val = parm; - } - mutex_unlock(&bus->cmd_mutex); - snd_hda_power_down(codec); - return err; + if (err < 0) + return err; + /* parm may contain the verb stuff for get/set amp */ + verb = verb | (parm >> 8); + parm &= 0xff; + key = build_cmd_cache_key(nid, verb); + mutex_lock(&codec->bus->cmd_mutex); + c = get_alloc_hash(&codec->cmd_cache, key); + if (c) + c->val = parm; + mutex_unlock(&codec->bus->cmd_mutex); + return 0; } EXPORT_SYMBOL_HDA(snd_hda_codec_write_cache); @@ -2321,7 +2360,8 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, if (wcaps & AC_WCAP_POWER) { unsigned int wid_type = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; - if (wid_type == AC_WID_PIN) { + if (power_state == AC_PWRST_D3 && + wid_type == AC_WID_PIN) { unsigned int pincap; /* * don't power down the widget if it controls @@ -2333,7 +2373,7 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, nid, 0, AC_VERB_GET_EAPD_BTLENABLE, 0); eapd &= 0x02; - if (power_state == AC_PWRST_D3 && eapd) + if (eapd) continue; } } @@ -2544,6 +2584,41 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate, } EXPORT_SYMBOL_HDA(snd_hda_calc_stream_format); +static unsigned int get_pcm_param(struct hda_codec *codec, hda_nid_t nid) +{ + unsigned int val = 0; + if (nid != codec->afg && + (get_wcaps(codec, nid) & AC_WCAP_FORMAT_OVRD)) + val = snd_hda_param_read(codec, nid, AC_PAR_PCM); + if (!val || val == -1) + val = snd_hda_param_read(codec, codec->afg, AC_PAR_PCM); + if (!val || val == -1) + return 0; + return val; +} + +static unsigned int query_pcm_param(struct hda_codec *codec, hda_nid_t nid) +{ + return query_caps_hash(codec, nid, HDA_HASH_PARPCM_KEY(nid), + get_pcm_param); +} + +static unsigned int get_stream_param(struct hda_codec *codec, hda_nid_t nid) +{ + unsigned int streams = snd_hda_param_read(codec, nid, AC_PAR_STREAM); + if (!streams || streams == -1) + streams = snd_hda_param_read(codec, codec->afg, AC_PAR_STREAM); + if (!streams || streams == -1) + return 0; + return streams; +} + +static unsigned int query_stream_param(struct hda_codec *codec, hda_nid_t nid) +{ + return query_caps_hash(codec, nid, HDA_HASH_PARSTR_KEY(nid), + get_stream_param); +} + /** * snd_hda_query_supported_pcm - query the supported PCM rates and formats * @codec: the HDA codec @@ -2562,15 +2637,8 @@ static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, { unsigned int i, val, wcaps; - val = 0; wcaps = get_wcaps(codec, nid); - if (nid != codec->afg && (wcaps & AC_WCAP_FORMAT_OVRD)) { - val = snd_hda_param_read(codec, nid, AC_PAR_PCM); - if (val == -1) - return -EIO; - } - if (!val) - val = snd_hda_param_read(codec, codec->afg, AC_PAR_PCM); + val = query_pcm_param(codec, nid); if (ratesp) { u32 rates = 0; @@ -2592,15 +2660,9 @@ static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, u64 formats = 0; unsigned int streams, bps; - streams = snd_hda_param_read(codec, nid, AC_PAR_STREAM); - if (streams == -1) + streams = query_stream_param(codec, nid); + if (!streams) return -EIO; - if (!streams) { - streams = snd_hda_param_read(codec, codec->afg, - AC_PAR_STREAM); - if (streams == -1) - return -EIO; - } bps = 0; if (streams & AC_SUPFMT_PCM) { @@ -2674,17 +2736,9 @@ int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid, int i; unsigned int val = 0, rate, stream; - if (nid != codec->afg && - (get_wcaps(codec, nid) & AC_WCAP_FORMAT_OVRD)) { - val = snd_hda_param_read(codec, nid, AC_PAR_PCM); - if (val == -1) - return 0; - } - if (!val) { - val = snd_hda_param_read(codec, codec->afg, AC_PAR_PCM); - if (val == -1) - return 0; - } + val = query_pcm_param(codec, nid); + if (!val) + return 0; rate = format & 0xff00; for (i = 0; i < AC_PAR_PCM_RATE_BITS; i++) @@ -2696,12 +2750,8 @@ int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid, if (i >= AC_PAR_PCM_RATE_BITS) return 0; - stream = snd_hda_param_read(codec, nid, AC_PAR_STREAM); - if (stream == -1) - return 0; - if (!stream && nid != codec->afg) - stream = snd_hda_param_read(codec, codec->afg, AC_PAR_STREAM); - if (!stream || stream == -1) + stream = query_stream_param(codec, nid); + if (!stream) return 0; if (stream & AC_SUPFMT_PCM) { @@ -3835,11 +3885,10 @@ EXPORT_SYMBOL_HDA(auto_pin_cfg_labels); /** * snd_hda_suspend - suspend the codecs * @bus: the HDA bus - * @state: suspsend state * * Returns 0 if successful. */ -int snd_hda_suspend(struct hda_bus *bus, pm_message_t state) +int snd_hda_suspend(struct hda_bus *bus) { struct hda_codec *codec; diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 2fdecf4b0eb6..cad79efaabc9 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -574,6 +574,8 @@ struct hda_bus_ops { /* attach a PCM stream */ int (*attach_pcm)(struct hda_bus *bus, struct hda_codec *codec, struct hda_pcm *pcm); + /* reset bus for retry verb */ + void (*bus_reset)(struct hda_bus *bus); #ifdef CONFIG_SND_HDA_POWER_SAVE /* notify power-up/down from codec to controller */ void (*pm_notify)(struct hda_bus *bus); @@ -622,7 +624,13 @@ struct hda_bus { /* misc op flags */ unsigned int needs_damn_long_delay :1; + unsigned int allow_bus_reset:1; /* allow bus reset at fatal error */ + unsigned int sync_write:1; /* sync after verb write */ + /* status for codec/controller */ unsigned int shutdown :1; /* being unloaded */ + unsigned int rirb_error:1; /* error in codec communication */ + unsigned int response_reset:1; /* controller was reset */ + unsigned int in_reset:1; /* during reset operation */ }; /* @@ -747,7 +755,8 @@ struct hda_codec { /* detected preset */ const struct hda_codec_preset *preset; struct module *owner; - const char *name; /* codec name */ + const char *vendor_name; /* codec vendor name */ + const char *chip_name; /* codec chip name */ const char *modelname; /* model name for preset */ /* set by patch */ @@ -905,7 +914,7 @@ void snd_hda_get_codec_name(struct hda_codec *codec, char *name, int namelen); * power management */ #ifdef CONFIG_PM -int snd_hda_suspend(struct hda_bus *bus, pm_message_t state); +int snd_hda_suspend(struct hda_bus *bus); int snd_hda_resume(struct hda_bus *bus); #endif diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index 1c57505c2874..6812fbe80fa4 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c @@ -242,7 +242,8 @@ CODEC_INFO_SHOW(subsystem_id); CODEC_INFO_SHOW(revision_id); CODEC_INFO_SHOW(afg); CODEC_INFO_SHOW(mfg); -CODEC_INFO_STR_SHOW(name); +CODEC_INFO_STR_SHOW(vendor_name); +CODEC_INFO_STR_SHOW(chip_name); CODEC_INFO_STR_SHOW(modelname); #define CODEC_INFO_STORE(type) \ @@ -275,7 +276,8 @@ static ssize_t type##_store(struct device *dev, \ CODEC_INFO_STORE(vendor_id); CODEC_INFO_STORE(subsystem_id); CODEC_INFO_STORE(revision_id); -CODEC_INFO_STR_STORE(name); +CODEC_INFO_STR_STORE(vendor_name); +CODEC_INFO_STR_STORE(chip_name); CODEC_INFO_STR_STORE(modelname); #define CODEC_ACTION_STORE(type) \ @@ -499,7 +501,8 @@ static struct device_attribute codec_attrs[] = { CODEC_ATTR_RW(revision_id), CODEC_ATTR_RO(afg), CODEC_ATTR_RO(mfg), - CODEC_ATTR_RW(name), + CODEC_ATTR_RW(vendor_name), + CODEC_ATTR_RW(chip_name), CODEC_ATTR_RW(modelname), CODEC_ATTR_RW(init_verbs), CODEC_ATTR_RW(hints), diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 3128e1a6bc65..4e9ea7080270 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -128,21 +128,33 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6}," "{ULI, M5461}}"); MODULE_DESCRIPTION("Intel HDA driver"); +#ifdef CONFIG_SND_VERBOSE_PRINTK +#define SFX /* nop */ +#else #define SFX "hda-intel: " - +#endif /* * registers */ #define ICH6_REG_GCAP 0x00 +#define ICH6_GCAP_64OK (1 << 0) /* 64bit address support */ +#define ICH6_GCAP_NSDO (3 << 1) /* # of serial data out signals */ +#define ICH6_GCAP_BSS (31 << 3) /* # of bidirectional streams */ +#define ICH6_GCAP_ISS (15 << 8) /* # of input streams */ +#define ICH6_GCAP_OSS (15 << 12) /* # of output streams */ #define ICH6_REG_VMIN 0x02 #define ICH6_REG_VMAJ 0x03 #define ICH6_REG_OUTPAY 0x04 #define ICH6_REG_INPAY 0x06 #define ICH6_REG_GCTL 0x08 +#define ICH6_GCTL_RESET (1 << 0) /* controller reset */ +#define ICH6_GCTL_FCNTRL (1 << 1) /* flush control */ +#define ICH6_GCTL_UNSOL (1 << 8) /* accept unsol. response enable */ #define ICH6_REG_WAKEEN 0x0c #define ICH6_REG_STATESTS 0x0e #define ICH6_REG_GSTS 0x10 +#define ICH6_GSTS_FSTS (1 << 1) /* flush status */ #define ICH6_REG_INTCTL 0x20 #define ICH6_REG_INTSTS 0x24 #define ICH6_REG_WALCLK 0x30 @@ -150,17 +162,27 @@ MODULE_DESCRIPTION("Intel HDA driver"); #define ICH6_REG_CORBLBASE 0x40 #define ICH6_REG_CORBUBASE 0x44 #define ICH6_REG_CORBWP 0x48 -#define ICH6_REG_CORBRP 0x4A +#define ICH6_REG_CORBRP 0x4a +#define ICH6_CORBRP_RST (1 << 15) /* read pointer reset */ #define ICH6_REG_CORBCTL 0x4c +#define ICH6_CORBCTL_RUN (1 << 1) /* enable DMA */ +#define ICH6_CORBCTL_CMEIE (1 << 0) /* enable memory error irq */ #define ICH6_REG_CORBSTS 0x4d +#define ICH6_CORBSTS_CMEI (1 << 0) /* memory error indication */ #define ICH6_REG_CORBSIZE 0x4e #define ICH6_REG_RIRBLBASE 0x50 #define ICH6_REG_RIRBUBASE 0x54 #define ICH6_REG_RIRBWP 0x58 +#define ICH6_RIRBWP_RST (1 << 15) /* write pointer reset */ #define ICH6_REG_RINTCNT 0x5a #define ICH6_REG_RIRBCTL 0x5c +#define ICH6_RBCTL_IRQ_EN (1 << 0) /* enable IRQ */ +#define ICH6_RBCTL_DMA_EN (1 << 1) /* enable DMA */ +#define ICH6_RBCTL_OVERRUN_EN (1 << 2) /* enable overrun irq */ #define ICH6_REG_RIRBSTS 0x5d +#define ICH6_RBSTS_IRQ (1 << 0) /* response irq */ +#define ICH6_RBSTS_OVERRUN (1 << 2) /* overrun irq */ #define ICH6_REG_RIRBSIZE 0x5e #define ICH6_REG_IC 0x60 @@ -257,16 +279,6 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; #define ICH6_INT_CTRL_EN 0x40000000 /* controller interrupt enable bit */ #define ICH6_INT_GLOBAL_EN 0x80000000 /* global interrupt enable bit */ -/* GCTL unsolicited response enable bit */ -#define ICH6_GCTL_UREN (1<<8) - -/* GCTL reset bit */ -#define ICH6_GCTL_RESET (1<<0) - -/* CORB/RIRB control, read/write pointer */ -#define ICH6_RBCTL_DMA_EN 0x02 /* enable DMA */ -#define ICH6_RBCTL_IRQ_EN 0x01 /* enable IRQ */ -#define ICH6_RBRWP_CLR 0x8000 /* read/write pointer clear */ /* below are so far hardcoded - should read registers in future */ #define ICH6_MAX_CORB_ENTRIES 256 #define ICH6_MAX_RIRB_ENTRIES 256 @@ -512,25 +524,25 @@ static void azx_init_cmd_io(struct azx *chip) /* set the corb write pointer to 0 */ azx_writew(chip, CORBWP, 0); /* reset the corb hw read pointer */ - azx_writew(chip, CORBRP, ICH6_RBRWP_CLR); + azx_writew(chip, CORBRP, ICH6_CORBRP_RST); /* enable corb dma */ - azx_writeb(chip, CORBCTL, ICH6_RBCTL_DMA_EN); + azx_writeb(chip, CORBCTL, ICH6_CORBCTL_RUN); /* RIRB set up */ chip->rirb.addr = chip->rb.addr + 2048; chip->rirb.buf = (u32 *)(chip->rb.area + 2048); + chip->rirb.wp = chip->rirb.rp = chip->rirb.cmds = 0; azx_writel(chip, RIRBLBASE, (u32)chip->rirb.addr); azx_writel(chip, RIRBUBASE, upper_32_bits(chip->rirb.addr)); /* set the rirb size to 256 entries (ULI requires explicitly) */ azx_writeb(chip, RIRBSIZE, 0x02); /* reset the rirb hw write pointer */ - azx_writew(chip, RIRBWP, ICH6_RBRWP_CLR); + azx_writew(chip, RIRBWP, ICH6_RIRBWP_RST); /* set N=1, get RIRB response interrupt for new entry */ azx_writew(chip, RINTCNT, 1); /* enable rirb dma and response irq */ azx_writeb(chip, RIRBCTL, ICH6_RBCTL_DMA_EN | ICH6_RBCTL_IRQ_EN); - chip->rirb.rp = chip->rirb.cmds = 0; } static void azx_free_cmd_io(struct azx *chip) @@ -606,6 +618,7 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus) } if (!chip->rirb.cmds) { smp_rmb(); + bus->rirb_error = 0; return chip->rirb.res; /* the last value */ } if (time_after(jiffies, timeout)) @@ -619,19 +632,21 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus) } if (chip->msi) { - snd_printk(KERN_WARNING "hda_intel: No response from codec, " + snd_printk(KERN_WARNING SFX "No response from codec, " "disabling MSI: last cmd=0x%08x\n", chip->last_cmd); free_irq(chip->irq, chip); chip->irq = -1; pci_disable_msi(chip->pci); chip->msi = 0; - if (azx_acquire_irq(chip, 1) < 0) + if (azx_acquire_irq(chip, 1) < 0) { + bus->rirb_error = 1; return -1; + } goto again; } if (!chip->polling_mode) { - snd_printk(KERN_WARNING "hda_intel: azx_get_response timeout, " + snd_printk(KERN_WARNING SFX "azx_get_response timeout, " "switching to polling mode: last cmd=0x%08x\n", chip->last_cmd); chip->polling_mode = 1; @@ -646,14 +661,23 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus) return -1; } + /* a fatal communication error; need either to reset or to fallback + * to the single_cmd mode + */ + bus->rirb_error = 1; + if (bus->allow_bus_reset && !bus->response_reset && !bus->in_reset) { + bus->response_reset = 1; + return -1; /* give a chance to retry */ + } + snd_printk(KERN_ERR "hda_intel: azx_get_response timeout, " "switching to single_cmd mode: last cmd=0x%08x\n", chip->last_cmd); - chip->rirb.rp = azx_readb(chip, RIRBWP); - chip->rirb.cmds = 0; - /* switch to single_cmd mode */ chip->single_cmd = 1; + bus->response_reset = 0; + /* re-initialize CORB/RIRB */ azx_free_cmd_io(chip); + azx_init_cmd_io(chip); return -1; } @@ -667,12 +691,34 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus) * I left the codes, however, for debugging/testing purposes. */ +/* receive a response */ +static int azx_single_wait_for_response(struct azx *chip) +{ + int timeout = 50; + + while (timeout--) { + /* check IRV busy bit */ + if (azx_readw(chip, IRS) & ICH6_IRS_VALID) { + /* reuse rirb.res as the response return value */ + chip->rirb.res = azx_readl(chip, IR); + return 0; + } + udelay(1); + } + if (printk_ratelimit()) + snd_printd(SFX "get_response timeout: IRS=0x%x\n", + azx_readw(chip, IRS)); + chip->rirb.res = -1; + return -EIO; +} + /* send a command */ static int azx_single_send_cmd(struct hda_bus *bus, u32 val) { struct azx *chip = bus->private_data; int timeout = 50; + bus->rirb_error = 0; while (timeout--) { /* check ICB busy bit */ if (!((azx_readw(chip, IRS) & ICH6_IRS_BUSY))) { @@ -682,7 +728,7 @@ static int azx_single_send_cmd(struct hda_bus *bus, u32 val) azx_writel(chip, IC, val); azx_writew(chip, IRS, azx_readw(chip, IRS) | ICH6_IRS_BUSY); - return 0; + return azx_single_wait_for_response(chip); } udelay(1); } @@ -696,18 +742,7 @@ static int azx_single_send_cmd(struct hda_bus *bus, u32 val) static unsigned int azx_single_get_response(struct hda_bus *bus) { struct azx *chip = bus->private_data; - int timeout = 50; - - while (timeout--) { - /* check IRV busy bit */ - if (azx_readw(chip, IRS) & ICH6_IRS_VALID) - return azx_readl(chip, IR); - udelay(1); - } - if (printk_ratelimit()) - snd_printd(SFX "get_response timeout: IRS=0x%x\n", - azx_readw(chip, IRS)); - return (unsigned int)-1; + return chip->rirb.res; } /* @@ -775,17 +810,17 @@ static int azx_reset(struct azx *chip) /* check to see if controller is ready */ if (!azx_readb(chip, GCTL)) { - snd_printd("azx_reset: controller not ready!\n"); + snd_printd(SFX "azx_reset: controller not ready!\n"); return -EBUSY; } /* Accept unsolicited responses */ - azx_writel(chip, GCTL, azx_readl(chip, GCTL) | ICH6_GCTL_UREN); + azx_writel(chip, GCTL, azx_readl(chip, GCTL) | ICH6_GCTL_UNSOL); /* detect codecs */ if (!chip->codec_mask) { chip->codec_mask = azx_readw(chip, STATESTS); - snd_printdd("codec_mask = 0x%x\n", chip->codec_mask); + snd_printdd(SFX "codec_mask = 0x%x\n", chip->codec_mask); } return 0; @@ -895,8 +930,7 @@ static void azx_init_chip(struct azx *chip) azx_int_enable(chip); /* initialize the codec command I/O */ - if (!chip->single_cmd) - azx_init_cmd_io(chip); + azx_init_cmd_io(chip); /* program the position buffer */ azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr); @@ -953,12 +987,12 @@ static void azx_init_pci(struct azx *chip) case AZX_DRIVER_SCH: pci_read_config_word(chip->pci, INTEL_SCH_HDA_DEVC, &snoop); if (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP) { - pci_write_config_word(chip->pci, INTEL_SCH_HDA_DEVC, \ + pci_write_config_word(chip->pci, INTEL_SCH_HDA_DEVC, snoop & (~INTEL_SCH_HDA_DEVC_NOSNOOP)); pci_read_config_word(chip->pci, INTEL_SCH_HDA_DEVC, &snoop); - snd_printdd("HDA snoop disabled, enabling ... %s\n",\ - (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP) \ + snd_printdd(SFX "HDA snoop disabled, enabling ... %s\n", + (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP) ? "Failed" : "OK"); } break; @@ -1012,7 +1046,7 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id) /* clear rirb int */ status = azx_readb(chip, RIRBSTS); if (status & RIRB_INT_MASK) { - if (!chip->single_cmd && (status & RIRB_INT_RESPONSE)) + if (status & RIRB_INT_RESPONSE) azx_update_rirb(chip); azx_writeb(chip, RIRBSTS, RIRB_INT_MASK); } @@ -1098,7 +1132,7 @@ static int azx_setup_periods(struct azx *chip, pos_align; pos_adj = frames_to_bytes(runtime, pos_adj); if (pos_adj >= period_bytes) { - snd_printk(KERN_WARNING "Too big adjustment %d\n", + snd_printk(KERN_WARNING SFX "Too big adjustment %d\n", bdl_pos_adj[chip->dev_index]); pos_adj = 0; } else { @@ -1122,7 +1156,7 @@ static int azx_setup_periods(struct azx *chip, return 0; error: - snd_printk(KERN_ERR "Too many BDL entries: buffer=%d, period=%d\n", + snd_printk(KERN_ERR SFX "Too many BDL entries: buffer=%d, period=%d\n", azx_dev->bufsize, period_bytes); return -EINVAL; } @@ -1215,7 +1249,7 @@ static int probe_codec(struct azx *chip, int addr) chip->probing = 0; if (res == -1) return -EIO; - snd_printdd("hda_intel: codec #%d probed OK\n", addr); + snd_printdd(SFX "codec #%d probed OK\n", addr); return 0; } @@ -1223,6 +1257,26 @@ static int azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec, struct hda_pcm *cpcm); static void azx_stop_chip(struct azx *chip); +static void azx_bus_reset(struct hda_bus *bus) +{ + struct azx *chip = bus->private_data; + + bus->in_reset = 1; + azx_stop_chip(chip); + azx_init_chip(chip); +#ifdef CONFIG_PM + if (chip->initialized) { + int i; + + for (i = 0; i < AZX_MAX_PCMS; i++) + snd_pcm_suspend_all(chip->pcm[i]); + snd_hda_suspend(chip->bus); + snd_hda_resume(chip->bus); + } +#endif + bus->in_reset = 0; +} + /* * Codec initialization */ @@ -1246,6 +1300,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model, bus_temp.ops.command = azx_send_cmd; bus_temp.ops.get_response = azx_get_response; bus_temp.ops.attach_pcm = azx_attach_pcm_stream; + bus_temp.ops.bus_reset = azx_bus_reset; #ifdef CONFIG_SND_HDA_POWER_SAVE bus_temp.power_save = &power_save; bus_temp.ops.pm_notify = azx_power_notify; @@ -1270,8 +1325,8 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model, /* Some BIOSen give you wrong codec addresses * that don't exist */ - snd_printk(KERN_WARNING - "hda_intel: Codec #%d probe error; " + snd_printk(KERN_WARNING SFX + "Codec #%d probe error; " "disabling it...\n", c); chip->codec_mask &= ~(1 << c); /* More badly, accessing to a non-existing @@ -1487,7 +1542,7 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream) bufsize = snd_pcm_lib_buffer_bytes(substream); period_bytes = snd_pcm_lib_period_bytes(substream); - snd_printdd("azx_pcm_prepare: bufsize=0x%x, format=0x%x\n", + snd_printdd(SFX "azx_pcm_prepare: bufsize=0x%x, format=0x%x\n", bufsize, format_val); if (bufsize != azx_dev->bufsize || @@ -1830,7 +1885,7 @@ azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec, &pcm); if (err < 0) return err; - strcpy(pcm->name, cpcm->name); + strlcpy(pcm->name, cpcm->name, sizeof(pcm->name)); apcm = kzalloc(sizeof(*apcm), GFP_KERNEL); if (apcm == NULL) return -ENOMEM; @@ -1973,7 +2028,7 @@ static int azx_suspend(struct pci_dev *pci, pm_message_t state) for (i = 0; i < AZX_MAX_PCMS; i++) snd_pcm_suspend_all(chip->pcm[i]); if (chip->initialized) - snd_hda_suspend(chip->bus, state); + snd_hda_suspend(chip->bus); azx_stop_chip(chip); if (chip->irq >= 0) { free_irq(chip->irq, chip); @@ -2265,14 +2320,14 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, synchronize_irq(chip->irq); gcap = azx_readw(chip, GCAP); - snd_printdd("chipset global capabilities = 0x%x\n", gcap); + snd_printdd(SFX "chipset global capabilities = 0x%x\n", gcap); /* ATI chips seems buggy about 64bit DMA addresses */ if (chip->driver_type == AZX_DRIVER_ATI) - gcap &= ~0x01; + gcap &= ~ICH6_GCAP_64OK; /* allow 64bit DMA address if supported by H/W */ - if ((gcap & 0x01) && !pci_set_dma_mask(pci, DMA_BIT_MASK(64))) + if ((gcap & ICH6_GCAP_64OK) && !pci_set_dma_mask(pci, DMA_BIT_MASK(64))) pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(64)); else { pci_set_dma_mask(pci, DMA_BIT_MASK(32)); @@ -2309,7 +2364,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, chip->azx_dev = kcalloc(chip->num_streams, sizeof(*chip->azx_dev), GFP_KERNEL); if (!chip->azx_dev) { - snd_printk(KERN_ERR "cannot malloc azx_dev\n"); + snd_printk(KERN_ERR SFX "cannot malloc azx_dev\n"); goto errout; } @@ -2332,11 +2387,9 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, goto errout; } /* allocate CORB/RIRB */ - if (!chip->single_cmd) { - err = azx_alloc_cmd_io(chip); - if (err < 0) - goto errout; - } + err = azx_alloc_cmd_io(chip); + if (err < 0) + goto errout; /* initialize streams */ azx_init_stream(chip); @@ -2359,9 +2412,11 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, } strcpy(card->driver, "HDA-Intel"); - strcpy(card->shortname, driver_short_names[chip->driver_type]); - sprintf(card->longname, "%s at 0x%lx irq %i", - card->shortname, chip->addr, chip->irq); + strlcpy(card->shortname, driver_short_names[chip->driver_type], + sizeof(card->shortname)); + snprintf(card->longname, sizeof(card->longname), + "%s at 0x%lx irq %i", + card->shortname, chip->addr, chip->irq); *rchip = chip; return 0; @@ -2514,6 +2569,20 @@ static struct pci_device_id azx_ids[] = { { PCI_DEVICE(0x10de, 0x0d97), .driver_data = AZX_DRIVER_NVIDIA }, /* Teradici */ { PCI_DEVICE(0x6549, 0x1200), .driver_data = AZX_DRIVER_TERA }, + /* Creative X-Fi (CA0110-IBG) */ +#if !defined(CONFIG_SND_CTXFI) && !defined(CONFIG_SND_CTXFI_MODULE) + /* the following entry conflicts with snd-ctxfi driver, + * as ctxfi driver mutates from HD-audio to native mode with + * a special command sequence. + */ + { PCI_DEVICE(PCI_VENDOR_ID_CREATIVE, PCI_ANY_ID), + .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, + .class_mask = 0xffffff, + .driver_data = AZX_DRIVER_GENERIC }, +#else + /* this entry seems still valid -- i.e. without emu20kx chip */ + { PCI_DEVICE(0x1102, 0x0009), .driver_data = AZX_DRIVER_GENERIC }, +#endif /* AMD Generic, PCI class code and Vendor ID for HD Audio */ { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_ANY_ID), .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index 93d7499350c6..418c5d1badaa 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -466,8 +466,12 @@ static void print_codec_info(struct snd_info_entry *entry, hda_nid_t nid; int i, nodes; - snd_iprintf(buffer, "Codec: %s\n", - codec->name ? codec->name : "Not Set"); + snd_iprintf(buffer, "Codec: "); + if (codec->vendor_name && codec->chip_name) + snd_iprintf(buffer, "%s %s\n", + codec->vendor_name, codec->chip_name); + else + snd_iprintf(buffer, "Not Set\n"); snd_iprintf(buffer, "Address: %d\n", codec->addr); snd_iprintf(buffer, "Function Id: 0x%x\n", codec->function_id); snd_iprintf(buffer, "Vendor Id: 0x%08x\n", codec->vendor_id); diff --git a/sound/pci/hda/patch_ca0110.c b/sound/pci/hda/patch_ca0110.c new file mode 100644 index 000000000000..392d108c3558 --- /dev/null +++ b/sound/pci/hda/patch_ca0110.c @@ -0,0 +1,573 @@ +/* + * HD audio interface patch for Creative X-Fi CA0110-IBG chip + * + * Copyright (c) 2008 Takashi Iwai + * + * This driver 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 driver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include "hda_codec.h" +#include "hda_local.h" + +/* + */ + +struct ca0110_spec { + struct auto_pin_cfg autocfg; + struct hda_multi_out multiout; + hda_nid_t out_pins[AUTO_CFG_MAX_OUTS]; + hda_nid_t dacs[AUTO_CFG_MAX_OUTS]; + hda_nid_t hp_dac; + hda_nid_t input_pins[AUTO_PIN_LAST]; + hda_nid_t adcs[AUTO_PIN_LAST]; + hda_nid_t dig_out; + hda_nid_t dig_in; + unsigned int num_inputs; + const char *input_labels[AUTO_PIN_LAST]; + struct hda_pcm pcm_rec[2]; /* PCM information */ +}; + +/* + * PCM callbacks + */ +static int ca0110_playback_pcm_open(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct ca0110_spec *spec = codec->spec; + return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, + hinfo); +} + +static int ca0110_playback_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream) +{ + struct ca0110_spec *spec = codec->spec; + return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, + stream_tag, format, substream); +} + +static int ca0110_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct ca0110_spec *spec = codec->spec; + return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); +} + +/* + * Digital out + */ +static int ca0110_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct ca0110_spec *spec = codec->spec; + return snd_hda_multi_out_dig_open(codec, &spec->multiout); +} + +static int ca0110_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct ca0110_spec *spec = codec->spec; + return snd_hda_multi_out_dig_close(codec, &spec->multiout); +} + +static int ca0110_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream) +{ + struct ca0110_spec *spec = codec->spec; + return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag, + format, substream); +} + +/* + * Analog capture + */ +static int ca0110_capture_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream) +{ + struct ca0110_spec *spec = codec->spec; + + snd_hda_codec_setup_stream(codec, spec->adcs[substream->number], + stream_tag, 0, format); + return 0; +} + +static int ca0110_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct ca0110_spec *spec = codec->spec; + + snd_hda_codec_cleanup_stream(codec, spec->adcs[substream->number]); + return 0; +} + +/* + */ + +static char *dirstr[2] = { "Playback", "Capture" }; + +static int _add_switch(struct hda_codec *codec, hda_nid_t nid, const char *pfx, + int chan, int dir) +{ + char namestr[44]; + int type = dir ? HDA_INPUT : HDA_OUTPUT; + struct snd_kcontrol_new knew = + HDA_CODEC_MUTE_MONO(namestr, nid, chan, 0, type); + sprintf(namestr, "%s %s Switch", pfx, dirstr[dir]); + return snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec)); +} + +static int _add_volume(struct hda_codec *codec, hda_nid_t nid, const char *pfx, + int chan, int dir) +{ + char namestr[44]; + int type = dir ? HDA_INPUT : HDA_OUTPUT; + struct snd_kcontrol_new knew = + HDA_CODEC_VOLUME_MONO(namestr, nid, chan, 0, type); + sprintf(namestr, "%s %s Volume", pfx, dirstr[dir]); + return snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec)); +} + +#define add_out_switch(codec, nid, pfx) _add_switch(codec, nid, pfx, 3, 0) +#define add_out_volume(codec, nid, pfx) _add_volume(codec, nid, pfx, 3, 0) +#define add_in_switch(codec, nid, pfx) _add_switch(codec, nid, pfx, 3, 1) +#define add_in_volume(codec, nid, pfx) _add_volume(codec, nid, pfx, 3, 1) +#define add_mono_switch(codec, nid, pfx, chan) \ + _add_switch(codec, nid, pfx, chan, 0) +#define add_mono_volume(codec, nid, pfx, chan) \ + _add_volume(codec, nid, pfx, chan, 0) + +static int ca0110_build_controls(struct hda_codec *codec) +{ + struct ca0110_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + static char *prefix[AUTO_CFG_MAX_OUTS] = { + "Front", "Surround", NULL, "Side", "Multi" + }; + hda_nid_t mutenid; + int i, err; + + for (i = 0; i < spec->multiout.num_dacs; i++) { + if (get_wcaps(codec, spec->out_pins[i]) & AC_WCAP_OUT_AMP) + mutenid = spec->out_pins[i]; + else + mutenid = spec->multiout.dac_nids[i]; + if (!prefix[i]) { + err = add_mono_switch(codec, mutenid, + "Center", 1); + if (err < 0) + return err; + err = add_mono_switch(codec, mutenid, + "LFE", 1); + if (err < 0) + return err; + err = add_mono_volume(codec, spec->multiout.dac_nids[i], + "Center", 1); + if (err < 0) + return err; + err = add_mono_volume(codec, spec->multiout.dac_nids[i], + "LFE", 1); + if (err < 0) + return err; + } else { + err = add_out_switch(codec, mutenid, + prefix[i]); + if (err < 0) + return err; + err = add_out_volume(codec, spec->multiout.dac_nids[i], + prefix[i]); + if (err < 0) + return err; + } + } + if (cfg->hp_outs) { + if (get_wcaps(codec, cfg->hp_pins[0]) & AC_WCAP_OUT_AMP) + mutenid = cfg->hp_pins[0]; + else + mutenid = spec->multiout.dac_nids[i]; + + err = add_out_switch(codec, mutenid, "Headphone"); + if (err < 0) + return err; + if (spec->hp_dac) { + err = add_out_volume(codec, spec->hp_dac, "Headphone"); + if (err < 0) + return err; + } + } + for (i = 0; i < spec->num_inputs; i++) { + const char *label = spec->input_labels[i]; + if (get_wcaps(codec, spec->input_pins[i]) & AC_WCAP_IN_AMP) + mutenid = spec->input_pins[i]; + else + mutenid = spec->adcs[i]; + err = add_in_switch(codec, mutenid, label); + if (err < 0) + return err; + err = add_in_volume(codec, spec->adcs[i], label); + if (err < 0) + return err; + } + + if (spec->dig_out) { + err = snd_hda_create_spdif_out_ctls(codec, spec->dig_out); + if (err < 0) + return err; + err = snd_hda_create_spdif_share_sw(codec, &spec->multiout); + if (err < 0) + return err; + spec->multiout.share_spdif = 1; + } + if (spec->dig_in) { + err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in); + if (err < 0) + return err; + err = add_in_volume(codec, spec->dig_in, "IEC958"); + } + return 0; +} + +/* + */ +static struct hda_pcm_stream ca0110_pcm_analog_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 8, + .ops = { + .open = ca0110_playback_pcm_open, + .prepare = ca0110_playback_pcm_prepare, + .cleanup = ca0110_playback_pcm_cleanup + }, +}; + +static struct hda_pcm_stream ca0110_pcm_analog_capture = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + .ops = { + .prepare = ca0110_capture_pcm_prepare, + .cleanup = ca0110_capture_pcm_cleanup + }, +}; + +static struct hda_pcm_stream ca0110_pcm_digital_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + .ops = { + .open = ca0110_dig_playback_pcm_open, + .close = ca0110_dig_playback_pcm_close, + .prepare = ca0110_dig_playback_pcm_prepare + }, +}; + +static struct hda_pcm_stream ca0110_pcm_digital_capture = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, +}; + +static int ca0110_build_pcms(struct hda_codec *codec) +{ + struct ca0110_spec *spec = codec->spec; + struct hda_pcm *info = spec->pcm_rec; + + codec->pcm_info = info; + codec->num_pcms = 0; + + info->name = "CA0110 Analog"; + info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ca0110_pcm_analog_playback; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dacs[0]; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = + spec->multiout.max_channels; + info->stream[SNDRV_PCM_STREAM_CAPTURE] = ca0110_pcm_analog_capture; + info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_inputs; + info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[0]; + codec->num_pcms++; + + if (!spec->dig_out && !spec->dig_in) + return 0; + + info++; + info->name = "CA0110 Digital"; + info->pcm_type = HDA_PCM_TYPE_SPDIF; + if (spec->dig_out) { + info->stream[SNDRV_PCM_STREAM_PLAYBACK] = + ca0110_pcm_digital_playback; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dig_out; + } + if (spec->dig_in) { + info->stream[SNDRV_PCM_STREAM_CAPTURE] = + ca0110_pcm_digital_capture; + info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in; + } + codec->num_pcms++; + + return 0; +} + +static void init_output(struct hda_codec *codec, hda_nid_t pin, hda_nid_t dac) +{ + if (pin) { + snd_hda_codec_write(codec, pin, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP); + if (get_wcaps(codec, pin) & AC_WCAP_OUT_AMP) + snd_hda_codec_write(codec, pin, 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_OUT_UNMUTE); + } + if (dac) + snd_hda_codec_write(codec, dac, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO); +} + +static void init_input(struct hda_codec *codec, hda_nid_t pin, hda_nid_t adc) +{ + if (pin) { + snd_hda_codec_write(codec, pin, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80); + if (get_wcaps(codec, pin) & AC_WCAP_IN_AMP) + snd_hda_codec_write(codec, pin, 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_IN_UNMUTE(0)); + } + if (adc) + snd_hda_codec_write(codec, adc, 0, AC_VERB_SET_AMP_GAIN_MUTE, + AMP_IN_UNMUTE(0)); +} + +static int ca0110_init(struct hda_codec *codec) +{ + struct ca0110_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int i; + + for (i = 0; i < spec->multiout.num_dacs; i++) + init_output(codec, spec->out_pins[i], + spec->multiout.dac_nids[i]); + init_output(codec, cfg->hp_pins[0], spec->hp_dac); + init_output(codec, cfg->dig_out_pins[0], spec->dig_out); + + for (i = 0; i < spec->num_inputs; i++) + init_input(codec, spec->input_pins[i], spec->adcs[i]); + init_input(codec, cfg->dig_in_pin, spec->dig_in); + return 0; +} + +static void ca0110_free(struct hda_codec *codec) +{ + kfree(codec->spec); +} + +static struct hda_codec_ops ca0110_patch_ops = { + .build_controls = ca0110_build_controls, + .build_pcms = ca0110_build_pcms, + .init = ca0110_init, + .free = ca0110_free, +}; + + +static void parse_line_outs(struct hda_codec *codec) +{ + struct ca0110_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int i, n; + unsigned int def_conf; + hda_nid_t nid; + + n = 0; + for (i = 0; i < cfg->line_outs; i++) { + nid = cfg->line_out_pins[i]; + def_conf = snd_hda_codec_get_pincfg(codec, nid); + if (!def_conf) + continue; /* invalid pin */ + if (snd_hda_get_connections(codec, nid, &spec->dacs[i], 1) != 1) + continue; + spec->out_pins[n++] = nid; + } + spec->multiout.dac_nids = spec->dacs; + spec->multiout.num_dacs = n; + spec->multiout.max_channels = n * 2; +} + +static void parse_hp_out(struct hda_codec *codec) +{ + struct ca0110_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int i; + unsigned int def_conf; + hda_nid_t nid, dac; + + if (!cfg->hp_outs) + return; + nid = cfg->hp_pins[0]; + def_conf = snd_hda_codec_get_pincfg(codec, nid); + if (!def_conf) { + cfg->hp_outs = 0; + return; + } + if (snd_hda_get_connections(codec, nid, &dac, 1) != 1) + return; + + for (i = 0; i < cfg->line_outs; i++) + if (dac == spec->dacs[i]) + break; + if (i >= cfg->line_outs) { + spec->hp_dac = dac; + spec->multiout.hp_nid = dac; + } +} + +static void parse_input(struct hda_codec *codec) +{ + struct ca0110_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + hda_nid_t nid, pin; + int n, i, j; + + n = 0; + nid = codec->start_nid; + for (i = 0; i < codec->num_nodes; i++, nid++) { + unsigned int wcaps = get_wcaps(codec, nid); + unsigned int type = (wcaps & AC_WCAP_TYPE) >> + AC_WCAP_TYPE_SHIFT; + if (type != AC_WID_AUD_IN) + continue; + if (snd_hda_get_connections(codec, nid, &pin, 1) != 1) + continue; + if (pin == cfg->dig_in_pin) { + spec->dig_in = nid; + continue; + } + for (j = 0; j < AUTO_PIN_LAST; j++) + if (cfg->input_pins[j] == pin) + break; + if (j >= AUTO_PIN_LAST) + continue; + spec->input_pins[n] = pin; + spec->input_labels[n] = auto_pin_cfg_labels[j]; + spec->adcs[n] = nid; + n++; + } + spec->num_inputs = n; +} + +static void parse_digital(struct hda_codec *codec) +{ + struct ca0110_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + + if (cfg->dig_outs && + snd_hda_get_connections(codec, cfg->dig_out_pins[0], + &spec->dig_out, 1) == 1) + spec->multiout.dig_out_nid = cfg->dig_out_pins[0]; +} + +static int ca0110_parse_auto_config(struct hda_codec *codec) +{ + struct ca0110_spec *spec = codec->spec; + int err; + + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); + if (err < 0) + return err; + + parse_line_outs(codec); + parse_hp_out(codec); + parse_digital(codec); + parse_input(codec); + return 0; +} + + +int patch_ca0110(struct hda_codec *codec) +{ + struct ca0110_spec *spec; + int err; + + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (!spec) + return -ENOMEM; + codec->spec = spec; + + codec->bus->needs_damn_long_delay = 1; + + err = ca0110_parse_auto_config(codec); + if (err < 0) + goto error; + + codec->patch_ops = ca0110_patch_ops; + + return 0; + + error: + kfree(codec->spec); + codec->spec = NULL; + return err; +} + + +/* + * patch entries + */ +static struct hda_codec_preset snd_hda_preset_ca0110[] = { + { .id = 0x1102000a, .name = "CA0110-IBG", .patch = patch_ca0110 }, + { .id = 0x1102000b, .name = "CA0110-IBG", .patch = patch_ca0110 }, + { .id = 0x1102000d, .name = "SB0880 X-Fi", .patch = patch_ca0110 }, + {} /* terminator */ +}; + +MODULE_ALIAS("snd-hda-codec-id:1102000a"); +MODULE_ALIAS("snd-hda-codec-id:1102000b"); +MODULE_ALIAS("snd-hda-codec-id:1102000d"); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Creative CA0110-IBG HD-audio codec"); + +static struct hda_codec_preset_list ca0110_list = { + .preset = snd_hda_preset_ca0110, + .owner = THIS_MODULE, +}; + +static int __init patch_ca0110_init(void) +{ + return snd_hda_add_codec_preset(&ca0110_list); +} + +static void __exit patch_ca0110_exit(void) +{ + snd_hda_delete_codec_preset(&ca0110_list); +} + +module_init(patch_ca0110_init) +module_exit(patch_ca0110_exit) diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 4fcbe21829ab..ac868c59f9e3 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -349,7 +349,7 @@ static int conexant_mux_enum_put(struct snd_kcontrol *kcontrol, &spec->cur_mux[adc_idx]); } -#ifdef CONFIG_SND_JACK +#ifdef CONFIG_SND_HDA_INPUT_JACK static void conexant_free_jack_priv(struct snd_jack *jack) { struct conexant_jack *jacks = jack->private_data; @@ -463,7 +463,7 @@ static int conexant_init(struct hda_codec *codec) static void conexant_free(struct hda_codec *codec) { -#ifdef CONFIG_SND_JACK +#ifdef CONFIG_SND_HDA_INPUT_JACK struct conexant_spec *spec = codec->spec; if (spec->jacks.list) { struct conexant_jack *jacks = spec->jacks.list; diff --git a/sound/pci/hda/patch_nvhdmi.c b/sound/pci/hda/patch_nvhdmi.c index d57d8132a06e..f5792e2eea82 100644 --- a/sound/pci/hda/patch_nvhdmi.c +++ b/sound/pci/hda/patch_nvhdmi.c @@ -35,9 +35,28 @@ struct nvhdmi_spec { struct hda_pcm pcm_rec; }; +#define Nv_VERB_SET_Channel_Allocation 0xF79 +#define Nv_VERB_SET_Info_Frame_Checksum 0xF7A +#define Nv_VERB_SET_Audio_Protection_On 0xF98 +#define Nv_VERB_SET_Audio_Protection_Off 0xF99 + +#define Nv_Master_Convert_nid 0x04 +#define Nv_Master_Pin_nid 0x05 + +static hda_nid_t nvhdmi_convert_nids[4] = { + /*front, rear, clfe, rear_surr */ + 0x6, 0x8, 0xa, 0xc, +}; + static struct hda_verb nvhdmi_basic_init[] = { + /* set audio protect on */ + { 0x1, Nv_VERB_SET_Audio_Protection_On, 0x1}, /* enable digital output on pin widget */ - { 0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x5, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 }, + { 0x7, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 }, + { 0x9, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 }, + { 0xb, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 }, + { 0xd, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 }, {} /* terminator */ }; @@ -66,48 +85,205 @@ static int nvhdmi_init(struct hda_codec *codec) * Digital out */ static int nvhdmi_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) + struct hda_codec *codec, + struct snd_pcm_substream *substream) { struct nvhdmi_spec *spec = codec->spec; return snd_hda_multi_out_dig_open(codec, &spec->multiout); } -static int nvhdmi_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) +static int nvhdmi_dig_playback_pcm_close_8ch(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct nvhdmi_spec *spec = codec->spec; + int i; + + snd_hda_codec_write(codec, Nv_Master_Convert_nid, + 0, AC_VERB_SET_CHANNEL_STREAMID, 0); + for (i = 0; i < 4; i++) { + /* set the stream id */ + snd_hda_codec_write(codec, nvhdmi_convert_nids[i], 0, + AC_VERB_SET_CHANNEL_STREAMID, 0); + /* set the stream format */ + snd_hda_codec_write(codec, nvhdmi_convert_nids[i], 0, + AC_VERB_SET_STREAM_FORMAT, 0); + } + + return snd_hda_multi_out_dig_close(codec, &spec->multiout); +} + +static int nvhdmi_dig_playback_pcm_close_2ch(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) { struct nvhdmi_spec *spec = codec->spec; return snd_hda_multi_out_dig_close(codec, &spec->multiout); } -static int nvhdmi_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) +static int nvhdmi_dig_playback_pcm_prepare_8ch(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream) +{ + int chs; + unsigned int dataDCC1, dataDCC2, chan, chanmask, channel_id; + int i; + + mutex_lock(&codec->spdif_mutex); + + chs = substream->runtime->channels; + chan = chs ? (chs - 1) : 1; + + switch (chs) { + default: + case 0: + case 2: + chanmask = 0x00; + break; + case 4: + chanmask = 0x08; + break; + case 6: + chanmask = 0x0b; + break; + case 8: + chanmask = 0x13; + break; + } + dataDCC1 = AC_DIG1_ENABLE | AC_DIG1_COPYRIGHT; + dataDCC2 = 0x2; + + /* set the Audio InforFrame Channel Allocation */ + snd_hda_codec_write(codec, 0x1, 0, + Nv_VERB_SET_Channel_Allocation, chanmask); + + /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */ + if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) + snd_hda_codec_write(codec, + Nv_Master_Convert_nid, + 0, + AC_VERB_SET_DIGI_CONVERT_1, + codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff); + + /* set the stream id */ + snd_hda_codec_write(codec, Nv_Master_Convert_nid, 0, + AC_VERB_SET_CHANNEL_STREAMID, (stream_tag << 4) | 0x0); + + /* set the stream format */ + snd_hda_codec_write(codec, Nv_Master_Convert_nid, 0, + AC_VERB_SET_STREAM_FORMAT, format); + + /* turn on again (if needed) */ + /* enable and set the channel status audio/data flag */ + if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) { + snd_hda_codec_write(codec, + Nv_Master_Convert_nid, + 0, + AC_VERB_SET_DIGI_CONVERT_1, + codec->spdif_ctls & 0xff); + snd_hda_codec_write(codec, + Nv_Master_Convert_nid, + 0, + AC_VERB_SET_DIGI_CONVERT_2, dataDCC2); + } + + for (i = 0; i < 4; i++) { + if (chs == 2) + channel_id = 0; + else + channel_id = i * 2; + + /* turn off SPDIF once; + *otherwise the IEC958 bits won't be updated + */ + if (codec->spdif_status_reset && + (codec->spdif_ctls & AC_DIG1_ENABLE)) + snd_hda_codec_write(codec, + nvhdmi_convert_nids[i], + 0, + AC_VERB_SET_DIGI_CONVERT_1, + codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff); + /* set the stream id */ + snd_hda_codec_write(codec, + nvhdmi_convert_nids[i], + 0, + AC_VERB_SET_CHANNEL_STREAMID, + (stream_tag << 4) | channel_id); + /* set the stream format */ + snd_hda_codec_write(codec, + nvhdmi_convert_nids[i], + 0, + AC_VERB_SET_STREAM_FORMAT, + format); + /* turn on again (if needed) */ + /* enable and set the channel status audio/data flag */ + if (codec->spdif_status_reset && + (codec->spdif_ctls & AC_DIG1_ENABLE)) { + snd_hda_codec_write(codec, + nvhdmi_convert_nids[i], + 0, + AC_VERB_SET_DIGI_CONVERT_1, + codec->spdif_ctls & 0xff); + snd_hda_codec_write(codec, + nvhdmi_convert_nids[i], + 0, + AC_VERB_SET_DIGI_CONVERT_2, dataDCC2); + } + } + + /* set the Audio Info Frame Checksum */ + snd_hda_codec_write(codec, 0x1, 0, + Nv_VERB_SET_Info_Frame_Checksum, + (0x71 - chan - chanmask)); + + mutex_unlock(&codec->spdif_mutex); + return 0; +} + +static int nvhdmi_dig_playback_pcm_prepare_2ch(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream) { struct nvhdmi_spec *spec = codec->spec; return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag, - format, substream); + format, substream); } -static struct hda_pcm_stream nvhdmi_pcm_digital_playback = { +static struct hda_pcm_stream nvhdmi_pcm_digital_playback_8ch = { .substreams = 1, .channels_min = 2, - .channels_max = 2, - .nid = 0x4, /* NID to query formats and rates and setup streams */ + .channels_max = 8, + .nid = Nv_Master_Convert_nid, .rates = SNDRV_PCM_RATE_48000, .maxbps = 16, .formats = SNDRV_PCM_FMTBIT_S16_LE, .ops = { .open = nvhdmi_dig_playback_pcm_open, - .close = nvhdmi_dig_playback_pcm_close, - .prepare = nvhdmi_dig_playback_pcm_prepare + .close = nvhdmi_dig_playback_pcm_close_8ch, + .prepare = nvhdmi_dig_playback_pcm_prepare_8ch }, }; -static int nvhdmi_build_pcms(struct hda_codec *codec) +static struct hda_pcm_stream nvhdmi_pcm_digital_playback_2ch = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + .nid = Nv_Master_Convert_nid, + .rates = SNDRV_PCM_RATE_48000, + .maxbps = 16, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .ops = { + .open = nvhdmi_dig_playback_pcm_open, + .close = nvhdmi_dig_playback_pcm_close_2ch, + .prepare = nvhdmi_dig_playback_pcm_prepare_2ch + }, +}; + +static int nvhdmi_build_pcms_8ch(struct hda_codec *codec) { struct nvhdmi_spec *spec = codec->spec; struct hda_pcm *info = &spec->pcm_rec; @@ -117,7 +293,24 @@ static int nvhdmi_build_pcms(struct hda_codec *codec) info->name = "NVIDIA HDMI"; info->pcm_type = HDA_PCM_TYPE_HDMI; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = nvhdmi_pcm_digital_playback; + info->stream[SNDRV_PCM_STREAM_PLAYBACK] + = nvhdmi_pcm_digital_playback_8ch; + + return 0; +} + +static int nvhdmi_build_pcms_2ch(struct hda_codec *codec) +{ + struct nvhdmi_spec *spec = codec->spec; + struct hda_pcm *info = &spec->pcm_rec; + + codec->num_pcms = 1; + codec->pcm_info = info; + + info->name = "NVIDIA HDMI"; + info->pcm_type = HDA_PCM_TYPE_HDMI; + info->stream[SNDRV_PCM_STREAM_PLAYBACK] + = nvhdmi_pcm_digital_playback_2ch; return 0; } @@ -127,14 +320,21 @@ static void nvhdmi_free(struct hda_codec *codec) kfree(codec->spec); } -static struct hda_codec_ops nvhdmi_patch_ops = { +static struct hda_codec_ops nvhdmi_patch_ops_8ch = { .build_controls = nvhdmi_build_controls, - .build_pcms = nvhdmi_build_pcms, + .build_pcms = nvhdmi_build_pcms_8ch, .init = nvhdmi_init, .free = nvhdmi_free, }; -static int patch_nvhdmi(struct hda_codec *codec) +static struct hda_codec_ops nvhdmi_patch_ops_2ch = { + .build_controls = nvhdmi_build_controls, + .build_pcms = nvhdmi_build_pcms_2ch, + .init = nvhdmi_init, + .free = nvhdmi_free, +}; + +static int patch_nvhdmi_8ch(struct hda_codec *codec) { struct nvhdmi_spec *spec; @@ -144,13 +344,30 @@ static int patch_nvhdmi(struct hda_codec *codec) codec->spec = spec; - spec->multiout.num_dacs = 0; /* no analog */ - spec->multiout.max_channels = 2; - spec->multiout.dig_out_nid = 0x4; /* NID for copying analog to digital, - * seems to be unused in pure-digital - * case. */ + spec->multiout.num_dacs = 0; /* no analog */ + spec->multiout.max_channels = 8; + spec->multiout.dig_out_nid = Nv_Master_Convert_nid; - codec->patch_ops = nvhdmi_patch_ops; + codec->patch_ops = nvhdmi_patch_ops_8ch; + + return 0; +} + +static int patch_nvhdmi_2ch(struct hda_codec *codec) +{ + struct nvhdmi_spec *spec; + + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; + + codec->spec = spec; + + spec->multiout.num_dacs = 0; /* no analog */ + spec->multiout.max_channels = 2; + spec->multiout.dig_out_nid = Nv_Master_Convert_nid; + + codec->patch_ops = nvhdmi_patch_ops_2ch; return 0; } @@ -159,11 +376,11 @@ static int patch_nvhdmi(struct hda_codec *codec) * patch entries */ static struct hda_codec_preset snd_hda_preset_nvhdmi[] = { - { .id = 0x10de0002, .name = "MCP78 HDMI", .patch = patch_nvhdmi }, - { .id = 0x10de0006, .name = "MCP78 HDMI", .patch = patch_nvhdmi }, - { .id = 0x10de0007, .name = "MCP7A HDMI", .patch = patch_nvhdmi }, - { .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi }, - { .id = 0x10de8001, .name = "MCP73 HDMI", .patch = patch_nvhdmi }, + { .id = 0x10de0002, .name = "MCP78 HDMI", .patch = patch_nvhdmi_8ch }, + { .id = 0x10de0006, .name = "MCP78 HDMI", .patch = patch_nvhdmi_8ch }, + { .id = 0x10de0007, .name = "MCP7A HDMI", .patch = patch_nvhdmi_8ch }, + { .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi_2ch }, + { .id = 0x10de8001, .name = "MCP73 HDMI", .patch = patch_nvhdmi_2ch }, {} /* terminator */ }; diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 0fd258eba3a5..334533197425 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -190,6 +190,7 @@ enum { ALC663_ASUS_MODE6, ALC272_DELL, ALC272_DELL_ZM1, + ALC272_SAMSUNG_NC10, ALC662_AUTO, ALC662_MODEL_LAST, }; @@ -205,6 +206,7 @@ enum { ALC882_ASUS_A7M, ALC885_MACPRO, ALC885_MBP3, + ALC885_MB5, ALC885_IMAC24, ALC882_AUTO, ALC882_MODEL_LAST, @@ -218,9 +220,12 @@ enum { ALC883_6ST_DIG, ALC883_TARGA_DIG, ALC883_TARGA_2ch_DIG, + ALC883_TARGA_8ch_DIG, ALC883_ACER, ALC883_ACER_ASPIRE, ALC888_ACER_ASPIRE_4930G, + ALC888_ACER_ASPIRE_6530G, + ALC888_ACER_ASPIRE_8930G, ALC883_MEDION, ALC883_MEDION_MD2, ALC883_LAPTOP_EAPD, @@ -238,21 +243,25 @@ enum { ALC883_3ST_6ch_INTEL, ALC888_ASUS_M90V, ALC888_ASUS_EEE1601, + ALC889A_MB31, ALC1200_ASUS_P5Q, + ALC883_SONY_VAIO_TT, ALC883_AUTO, ALC883_MODEL_LAST, }; -/* styles of capture selection */ -enum { - CAPT_MUX = 0, /* only mux based */ - CAPT_MIX, /* only mixer based */ - CAPT_1MUX_MIX, /* first mux and other mixers */ -}; - /* for GPIO Poll */ #define GPIO_MASK 0x03 +/* extra amp-initialization sequence types */ +enum { + ALC_INIT_NONE, + ALC_INIT_DEFAULT, + ALC_INIT_GPIO1, + ALC_INIT_GPIO2, + ALC_INIT_GPIO3, +}; + struct alc_spec { /* codec parameterization */ struct snd_kcontrol_new *mixers[5]; /* mixer arrays */ @@ -266,13 +275,13 @@ struct alc_spec { */ unsigned int num_init_verbs; - char *stream_name_analog; /* analog PCM stream */ + char stream_name_analog[16]; /* analog PCM stream */ struct hda_pcm_stream *stream_analog_playback; struct hda_pcm_stream *stream_analog_capture; struct hda_pcm_stream *stream_analog_alt_playback; struct hda_pcm_stream *stream_analog_alt_capture; - char *stream_name_digital; /* digital PCM stream */ + char stream_name_digital[16]; /* digital PCM stream */ struct hda_pcm_stream *stream_digital_playback; struct hda_pcm_stream *stream_digital_capture; @@ -290,7 +299,6 @@ struct alc_spec { hda_nid_t *adc_nids; hda_nid_t *capsrc_nids; hda_nid_t dig_in_nid; /* digital-in NID; optional */ - int capture_style; /* capture style (CAPT_*) */ /* capture source */ unsigned int num_mux_defs; @@ -301,6 +309,8 @@ struct alc_spec { const struct hda_channel_mode *channel_mode; int num_channel_mode; int need_dac_fix; + int const_channel_count; + int ext_channel_count; /* PCM information */ struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */ @@ -322,6 +332,7 @@ struct alc_spec { /* other flags */ unsigned int no_analog :1; /* digital I/O only */ + int init_amp; /* for virtual master */ hda_nid_t vmaster_nid; @@ -355,6 +366,7 @@ struct alc_config_preset { unsigned int num_channel_mode; const struct hda_channel_mode *channel_mode; int need_dac_fix; + int const_channel_count; unsigned int num_mux_defs; const struct hda_input_mux *input_mux; void (*unsol_event)(struct hda_codec *, unsigned int); @@ -400,12 +412,13 @@ static int alc_mux_enum_put(struct snd_kcontrol *kcontrol, unsigned int mux_idx; hda_nid_t nid = spec->capsrc_nids ? spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx]; + unsigned int type; mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx; imux = &spec->input_mux[mux_idx]; - if (spec->capture_style && - !(spec->capture_style == CAPT_1MUX_MIX && !adc_idx)) { + type = (get_wcaps(codec, nid) & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; + if (type == AC_WID_AUD_MIX) { /* Matrix-mixer style (e.g. ALC882) */ unsigned int *cur_val = &spec->cur_mux[adc_idx]; unsigned int i, idx; @@ -449,7 +462,7 @@ static int alc_ch_mode_get(struct snd_kcontrol *kcontrol, struct alc_spec *spec = codec->spec; return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode, spec->num_channel_mode, - spec->multiout.max_channels); + spec->ext_channel_count); } static int alc_ch_mode_put(struct snd_kcontrol *kcontrol, @@ -459,9 +472,12 @@ static int alc_ch_mode_put(struct snd_kcontrol *kcontrol, struct alc_spec *spec = codec->spec; int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode, spec->num_channel_mode, - &spec->multiout.max_channels); - if (err >= 0 && spec->need_dac_fix) - spec->multiout.num_dacs = spec->multiout.max_channels / 2; + &spec->ext_channel_count); + if (err >= 0 && !spec->const_channel_count) { + spec->multiout.max_channels = spec->ext_channel_count; + if (spec->need_dac_fix) + spec->multiout.num_dacs = spec->multiout.max_channels / 2; + } return err; } @@ -841,8 +857,13 @@ static void setup_preset(struct alc_spec *spec, spec->channel_mode = preset->channel_mode; spec->num_channel_mode = preset->num_channel_mode; spec->need_dac_fix = preset->need_dac_fix; + spec->const_channel_count = preset->const_channel_count; - spec->multiout.max_channels = spec->channel_mode[0].channels; + if (preset->const_channel_count) + spec->multiout.max_channels = preset->const_channel_count; + else + spec->multiout.max_channels = spec->channel_mode[0].channels; + spec->ext_channel_count = spec->channel_mode[0].channels; spec->multiout.num_dacs = preset->num_dacs; spec->multiout.dac_nids = preset->dac_nids; @@ -921,23 +942,29 @@ static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid, alc_fix_pll(codec); } -static void alc_sku_automute(struct hda_codec *codec) +static void alc_automute_pin(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; unsigned int present; - unsigned int hp_nid = spec->autocfg.hp_pins[0]; - unsigned int sp_nid = spec->autocfg.speaker_pins[0]; + unsigned int nid = spec->autocfg.hp_pins[0]; + int i; /* need to execute and sync at first */ - snd_hda_codec_read(codec, hp_nid, 0, AC_VERB_SET_PIN_SENSE, 0); - present = snd_hda_codec_read(codec, hp_nid, 0, + snd_hda_codec_read(codec, nid, 0, AC_VERB_SET_PIN_SENSE, 0); + present = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0); - spec->jack_present = (present & 0x80000000) != 0; - snd_hda_codec_write(codec, sp_nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, - spec->jack_present ? 0 : PIN_OUT); + spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0; + for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) { + nid = spec->autocfg.speaker_pins[i]; + if (!nid) + break; + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + spec->jack_present ? 0 : PIN_OUT); + } } -#if 0 /* it's broken in some acses -- temporarily disabled */ +#if 0 /* it's broken in some cases -- temporarily disabled */ static void alc_mic_automute(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -969,16 +996,19 @@ static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res) res >>= 28; else res >>= 26; - if (res == ALC880_HP_EVENT) - alc_sku_automute(codec); - - if (res == ALC880_MIC_EVENT) + switch (res) { + case ALC880_HP_EVENT: + alc_automute_pin(codec); + break; + case ALC880_MIC_EVENT: alc_mic_automute(codec); + break; + } } static void alc_inithook(struct hda_codec *codec) { - alc_sku_automute(codec); + alc_automute_pin(codec); alc_mic_automute(codec); } @@ -1000,69 +1030,21 @@ static void alc888_coef_init(struct hda_codec *codec) AC_VERB_SET_PROC_COEF, 0x3030); } -/* 32-bit subsystem ID for BIOS loading in HD Audio codec. - * 31 ~ 16 : Manufacture ID - * 15 ~ 8 : SKU ID - * 7 ~ 0 : Assembly ID - * port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36 - */ -static void alc_subsystem_id(struct hda_codec *codec, - unsigned int porta, unsigned int porte, - unsigned int portd) +static void alc_auto_init_amp(struct hda_codec *codec, int type) { - unsigned int ass, tmp, i; - unsigned nid; - struct alc_spec *spec = codec->spec; + unsigned int tmp; - ass = codec->subsystem_id & 0xffff; - if ((ass != codec->bus->pci->subsystem_device) && (ass & 1)) - goto do_sku; - - /* - * 31~30 : port conetcivity - * 29~21 : reserve - * 20 : PCBEEP input - * 19~16 : Check sum (15:1) - * 15~1 : Custom - * 0 : override - */ - nid = 0x1d; - if (codec->vendor_id == 0x10ec0260) - nid = 0x17; - ass = snd_hda_codec_get_pincfg(codec, nid); - if (!(ass & 1) && !(ass & 0x100000)) - return; - if ((ass >> 30) != 1) /* no physical connection */ - return; - - /* check sum */ - tmp = 0; - for (i = 1; i < 16; i++) { - if ((ass >> i) & 1) - tmp++; - } - if (((ass >> 16) & 0xf) != tmp) - return; -do_sku: - /* - * 0 : override - * 1 : Swap Jack - * 2 : 0 --> Desktop, 1 --> Laptop - * 3~5 : External Amplifier control - * 7~6 : Reserved - */ - tmp = (ass & 0x38) >> 3; /* external Amp control */ - switch (tmp) { - case 1: + switch (type) { + case ALC_INIT_GPIO1: snd_hda_sequence_write(codec, alc_gpio1_init_verbs); break; - case 3: + case ALC_INIT_GPIO2: snd_hda_sequence_write(codec, alc_gpio2_init_verbs); break; - case 7: + case ALC_INIT_GPIO3: snd_hda_sequence_write(codec, alc_gpio3_init_verbs); break; - case 5: /* set EAPD output high */ + case ALC_INIT_DEFAULT: switch (codec->vendor_id) { case 0x10ec0260: snd_hda_codec_write(codec, 0x0f, 0, @@ -1116,7 +1098,7 @@ do_sku: tmp | 0x2010); break; case 0x10ec0888: - /*alc888_coef_init(codec);*/ /* called in alc_init() */ + alc888_coef_init(codec); break; case 0x10ec0267: case 0x10ec0268: @@ -1131,7 +1113,107 @@ do_sku: tmp | 0x3000); break; } - default: + break; + } +} + +static void alc_init_auto_hp(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + if (!spec->autocfg.hp_pins[0]) + return; + + if (!spec->autocfg.speaker_pins[0]) { + if (spec->autocfg.line_out_pins[0] && + spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) + spec->autocfg.speaker_pins[0] = + spec->autocfg.line_out_pins[0]; + else + return; + } + + snd_printdd("realtek: Enable HP auto-muting on NID 0x%x\n", + spec->autocfg.hp_pins[0]); + snd_hda_codec_write_cache(codec, spec->autocfg.hp_pins[0], 0, + AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | ALC880_HP_EVENT); + spec->unsol_event = alc_sku_unsol_event; +} + +/* check subsystem ID and set up device-specific initialization; + * return 1 if initialized, 0 if invalid SSID + */ +/* 32-bit subsystem ID for BIOS loading in HD Audio codec. + * 31 ~ 16 : Manufacture ID + * 15 ~ 8 : SKU ID + * 7 ~ 0 : Assembly ID + * port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36 + */ +static int alc_subsystem_id(struct hda_codec *codec, + hda_nid_t porta, hda_nid_t porte, + hda_nid_t portd) +{ + unsigned int ass, tmp, i; + unsigned nid; + struct alc_spec *spec = codec->spec; + + ass = codec->subsystem_id & 0xffff; + if ((ass != codec->bus->pci->subsystem_device) && (ass & 1)) + goto do_sku; + + /* invalid SSID, check the special NID pin defcfg instead */ + /* + * 31~30 : port connectivity + * 29~21 : reserve + * 20 : PCBEEP input + * 19~16 : Check sum (15:1) + * 15~1 : Custom + * 0 : override + */ + nid = 0x1d; + if (codec->vendor_id == 0x10ec0260) + nid = 0x17; + ass = snd_hda_codec_get_pincfg(codec, nid); + snd_printd("realtek: No valid SSID, " + "checking pincfg 0x%08x for NID 0x%x\n", + ass, nid); + if (!(ass & 1) && !(ass & 0x100000)) + return 0; + if ((ass >> 30) != 1) /* no physical connection */ + return 0; + + /* check sum */ + tmp = 0; + for (i = 1; i < 16; i++) { + if ((ass >> i) & 1) + tmp++; + } + if (((ass >> 16) & 0xf) != tmp) + return 0; +do_sku: + snd_printd("realtek: Enabling init ASM_ID=0x%04x CODEC_ID=%08x\n", + ass & 0xffff, codec->vendor_id); + /* + * 0 : override + * 1 : Swap Jack + * 2 : 0 --> Desktop, 1 --> Laptop + * 3~5 : External Amplifier control + * 7~6 : Reserved + */ + tmp = (ass & 0x38) >> 3; /* external Amp control */ + switch (tmp) { + case 1: + spec->init_amp = ALC_INIT_GPIO1; + break; + case 3: + spec->init_amp = ALC_INIT_GPIO2; + break; + case 7: + spec->init_amp = ALC_INIT_GPIO3; + break; + case 5: + spec->init_amp = ALC_INIT_DEFAULT; break; } @@ -1139,7 +1221,7 @@ do_sku: * when the external headphone out jack is plugged" */ if (!(ass & 0x8000)) - return; + return 1; /* * 10~8 : Jack location * 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered @@ -1147,14 +1229,6 @@ do_sku: * 15 : 1 --> enable the function "Mute internal speaker * when the external headphone out jack is plugged" */ - if (!spec->autocfg.speaker_pins[0]) { - if (spec->autocfg.line_out_pins[0]) - spec->autocfg.speaker_pins[0] = - spec->autocfg.line_out_pins[0]; - else - return; - } - if (!spec->autocfg.hp_pins[0]) { tmp = (ass >> 11) & 0x3; /* HP to chassis */ if (tmp == 0) @@ -1164,23 +1238,23 @@ do_sku: else if (tmp == 2) spec->autocfg.hp_pins[0] = portd; else - return; + return 1; } - if (spec->autocfg.hp_pins[0]) - snd_hda_codec_write(codec, spec->autocfg.hp_pins[0], 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | ALC880_HP_EVENT); -#if 0 /* it's broken in some acses -- temporarily disabled */ - if (spec->autocfg.input_pins[AUTO_PIN_MIC] && - spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC]) - snd_hda_codec_write(codec, - spec->autocfg.input_pins[AUTO_PIN_MIC], 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | ALC880_MIC_EVENT); -#endif /* disabled */ + alc_init_auto_hp(codec); + return 1; +} - spec->unsol_event = alc_sku_unsol_event; +static void alc_ssid_check(struct hda_codec *codec, + hda_nid_t porta, hda_nid_t porte, hda_nid_t portd) +{ + if (!alc_subsystem_id(codec, porta, porte, portd)) { + struct alc_spec *spec = codec->spec; + snd_printd("realtek: " + "Enable default setup for auto mode as fallback\n"); + spec->init_amp = ALC_INIT_DEFAULT; + alc_init_auto_hp(codec); + } } /* @@ -1315,32 +1389,58 @@ static struct hda_verb alc888_fujitsu_xa3530_verbs[] = { {} }; -static void alc888_fujitsu_xa3530_automute(struct hda_codec *codec) +static void alc_automute_amp(struct hda_codec *codec) { - unsigned int present; - unsigned int bits; - /* Line out presence */ - present = snd_hda_codec_read(codec, 0x17, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - /* HP out presence */ - present = present || snd_hda_codec_read(codec, 0x1b, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? HDA_AMP_MUTE : 0; + struct alc_spec *spec = codec->spec; + unsigned int val, mute; + hda_nid_t nid; + int i; + + spec->jack_present = 0; + for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) { + nid = spec->autocfg.hp_pins[i]; + if (!nid) + break; + val = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_SENSE, 0); + if (val & AC_PINSENSE_PRESENCE) { + spec->jack_present = 1; + break; + } + } + + mute = spec->jack_present ? HDA_AMP_MUTE : 0; /* Toggle internal speakers muting */ - snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); - /* Toggle internal bass muting */ - snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); + for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) { + nid = spec->autocfg.speaker_pins[i]; + if (!nid) + break; + snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, + HDA_AMP_MUTE, mute); + } } -static void alc888_fujitsu_xa3530_unsol_event(struct hda_codec *codec, - unsigned int res) +static void alc_automute_amp_unsol_event(struct hda_codec *codec, + unsigned int res) { - if (res >> 26 == ALC880_HP_EVENT) - alc888_fujitsu_xa3530_automute(codec); + if (codec->vendor_id == 0x10ec0880) + res >>= 28; + else + res >>= 26; + if (res == ALC880_HP_EVENT) + alc_automute_amp(codec); } +static void alc888_fujitsu_xa3530_init_hook(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x17; /* line-out */ + spec->autocfg.hp_pins[1] = 0x1b; /* hp */ + spec->autocfg.speaker_pins[0] = 0x14; /* speaker */ + spec->autocfg.speaker_pins[1] = 0x15; /* bass */ + alc_automute_amp(codec); +} /* * ALC888 Acer Aspire 4930G model @@ -1364,6 +1464,78 @@ static struct hda_verb alc888_acer_aspire_4930g_verbs[] = { { } }; +/* + * ALC888 Acer Aspire 6530G model + */ + +static struct hda_verb alc888_acer_aspire_6530g_verbs[] = { +/* Bias voltage on for external mic port */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN | PIN_VREF80}, +/* Enable unsolicited event for HP jack */ + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, +/* Enable speaker output */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, +/* Enable headphone output */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + { } +}; + +/* + * ALC889 Acer Aspire 8930G model + */ + +static struct hda_verb alc889_acer_aspire_8930g_verbs[] = { +/* Front Mic: set to PIN_IN (empty by default) */ + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, +/* Unselect Front Mic by default in input mixer 3 */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)}, +/* Enable unsolicited event for HP jack */ + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, +/* Connect Internal Front to Front */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, +/* Connect Internal Rear to Rear */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01}, +/* Connect Internal CLFE to CLFE */ + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x16, AC_VERB_SET_CONNECT_SEL, 0x02}, +/* Connect HP out to Front */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, +/* Enable all DACs */ +/* DAC DISABLE/MUTE 1? */ +/* setting bits 1-5 disables DAC nids 0x02-0x06 apparently. Init=0x38 */ + {0x20, AC_VERB_SET_COEF_INDEX, 0x03}, + {0x20, AC_VERB_SET_PROC_COEF, 0x0000}, +/* DAC DISABLE/MUTE 2? */ +/* some bit here disables the other DACs. Init=0x4900 */ + {0x20, AC_VERB_SET_COEF_INDEX, 0x08}, + {0x20, AC_VERB_SET_PROC_COEF, 0x0000}, +/* Enable amplifiers */ + {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, + {0x15, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, +/* DMIC fix + * This laptop has a stereo digital microphone. The mics are only 1cm apart + * which makes the stereo useless. However, either the mic or the ALC889 + * makes the signal become a difference/sum signal instead of standard + * stereo, which is annoying. So instead we flip this bit which makes the + * codec replicate the sum signal to both channels, turning it into a + * normal mono mic. + */ +/* DMIC_CONTROL? Init value = 0x0001 */ + {0x20, AC_VERB_SET_COEF_INDEX, 0x0b}, + {0x20, AC_VERB_SET_PROC_COEF, 0x0003}, + { } +}; + static struct hda_input_mux alc888_2_capture_sources[2] = { /* Front mic only available on one ADC */ { @@ -1385,6 +1557,57 @@ static struct hda_input_mux alc888_2_capture_sources[2] = { } }; +static struct hda_input_mux alc888_acer_aspire_6530_sources[2] = { + /* Interal mic only available on one ADC */ + { + .num_items = 3, + .items = { + { "Ext Mic", 0x0 }, + { "CD", 0x4 }, + { "Int Mic", 0xb }, + }, + }, + { + .num_items = 2, + .items = { + { "Ext Mic", 0x0 }, + { "CD", 0x4 }, + }, + } +}; + +static struct hda_input_mux alc889_capture_sources[3] = { + /* Digital mic only available on first "ADC" */ + { + .num_items = 5, + .items = { + { "Mic", 0x0 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + { "Front Mic", 0xb }, + { "Input Mix", 0xa }, + }, + }, + { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + { "Input Mix", 0xa }, + }, + }, + { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + { "Input Mix", 0xa }, + }, + } +}; + static struct snd_kcontrol_new alc888_base_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), @@ -1407,22 +1630,24 @@ static struct snd_kcontrol_new alc888_base_mixer[] = { { } /* end */ }; -static void alc888_acer_aspire_4930g_automute(struct hda_codec *codec) +static void alc888_acer_aspire_4930g_init_hook(struct hda_codec *codec) { - unsigned int present; - unsigned int bits; - present = snd_hda_codec_read(codec, 0x15, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? HDA_AMP_MUTE : 0; - snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + alc_automute_amp(codec); } -static void alc888_acer_aspire_4930g_unsol_event(struct hda_codec *codec, - unsigned int res) +static void alc889_acer_aspire_8930g_init_hook(struct hda_codec *codec) { - if (res >> 26 == ALC880_HP_EVENT) - alc888_acer_aspire_4930g_automute(codec); + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[1] = 0x16; + spec->autocfg.speaker_pins[2] = 0x1b; + alc_automute_amp(codec); } /* @@ -2390,21 +2615,6 @@ static struct hda_verb alc880_beep_init_verbs[] = { { } }; -/* toggle speaker-output according to the hp-jack state */ -static void alc880_uniwill_hp_automute(struct hda_codec *codec) -{ - unsigned int present; - unsigned char bits; - - present = snd_hda_codec_read(codec, 0x14, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? HDA_AMP_MUTE : 0; - snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); - snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); -} - /* auto-toggle front mic */ static void alc880_uniwill_mic_automute(struct hda_codec *codec) { @@ -2417,9 +2627,14 @@ static void alc880_uniwill_mic_automute(struct hda_codec *codec) snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits); } -static void alc880_uniwill_automute(struct hda_codec *codec) +static void alc880_uniwill_init_hook(struct hda_codec *codec) { - alc880_uniwill_hp_automute(codec); + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x16; + alc_automute_amp(codec); alc880_uniwill_mic_automute(codec); } @@ -2430,24 +2645,22 @@ static void alc880_uniwill_unsol_event(struct hda_codec *codec, * definition. 4bit tag is placed at 28 bit! */ switch (res >> 28) { - case ALC880_HP_EVENT: - alc880_uniwill_hp_automute(codec); - break; case ALC880_MIC_EVENT: alc880_uniwill_mic_automute(codec); break; + default: + alc_automute_amp_unsol_event(codec, res); + break; } } -static void alc880_uniwill_p53_hp_automute(struct hda_codec *codec) +static void alc880_uniwill_p53_init_hook(struct hda_codec *codec) { - unsigned int present; - unsigned char bits; + struct alc_spec *spec = codec->spec; - present = snd_hda_codec_read(codec, 0x14, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? HDA_AMP_MUTE : 0; - snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, HDA_AMP_MUTE, bits); + spec->autocfg.hp_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x15; + alc_automute_amp(codec); } static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec) @@ -2469,10 +2682,10 @@ static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec, /* Looks like the unsol event is incompatible with the standard * definition. 4bit tag is placed at 28 bit! */ - if ((res >> 28) == ALC880_HP_EVENT) - alc880_uniwill_p53_hp_automute(codec); if ((res >> 28) == ALC880_DCVOL_EVENT) alc880_uniwill_p53_dcvol_automute(codec); + else + alc_automute_amp_unsol_event(codec, res); } /* @@ -2542,6 +2755,7 @@ static struct hda_verb alc880_pin_asus_init_verbs[] = { /* Enable GPIO mask and set output */ #define alc880_gpio1_init_verbs alc_gpio1_init_verbs #define alc880_gpio2_init_verbs alc_gpio2_init_verbs +#define alc880_gpio3_init_verbs alc_gpio3_init_verbs /* Clevo m520g init */ static struct hda_verb alc880_pin_clevo_init_verbs[] = { @@ -2704,30 +2918,18 @@ static struct hda_verb alc880_lg_init_verbs[] = { {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* jack sense */ - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | 0x1}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, { } }; /* toggle speaker-output according to the hp-jack state */ -static void alc880_lg_automute(struct hda_codec *codec) +static void alc880_lg_init_hook(struct hda_codec *codec) { - unsigned int present; - unsigned char bits; + struct alc_spec *spec = codec->spec; - present = snd_hda_codec_read(codec, 0x1b, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? HDA_AMP_MUTE : 0; - snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); -} - -static void alc880_lg_unsol_event(struct hda_codec *codec, unsigned int res) -{ - /* Looks like the unsol event is incompatible with the standard - * definition. 4bit tag is placed at 28 bit! - */ - if ((res >> 28) == 0x01) - alc880_lg_automute(codec); + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.speaker_pins[0] = 0x17; + alc_automute_amp(codec); } /* @@ -2801,30 +3003,18 @@ static struct hda_verb alc880_lg_lw_init_verbs[] = { {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* jack sense */ - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | 0x1}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, { } }; /* toggle speaker-output according to the hp-jack state */ -static void alc880_lg_lw_automute(struct hda_codec *codec) +static void alc880_lg_lw_init_hook(struct hda_codec *codec) { - unsigned int present; - unsigned char bits; + struct alc_spec *spec = codec->spec; - present = snd_hda_codec_read(codec, 0x1b, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? HDA_AMP_MUTE : 0; - snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); -} - -static void alc880_lg_lw_unsol_event(struct hda_codec *codec, unsigned int res) -{ - /* Looks like the unsol event is incompatible with the standard - * definition. 4bit tag is placed at 28 bit! - */ - if ((res >> 28) == 0x01) - alc880_lg_lw_automute(codec); + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.speaker_pins[0] = 0x14; + alc_automute_amp(codec); } static struct snd_kcontrol_new alc880_medion_rim_mixer[] = { @@ -2871,16 +3061,10 @@ static struct hda_verb alc880_medion_rim_init_verbs[] = { /* toggle speaker-output according to the hp-jack state */ static void alc880_medion_rim_automute(struct hda_codec *codec) { - unsigned int present; - unsigned char bits; - - present = snd_hda_codec_read(codec, 0x14, 0, - AC_VERB_GET_PIN_SENSE, 0) - & AC_PINSENSE_PRESENCE; - bits = present ? HDA_AMP_MUTE : 0; - snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); - if (present) + struct alc_spec *spec = codec->spec; + alc_automute_amp(codec); + /* toggle EAPD */ + if (spec->jack_present) snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0); else snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 2); @@ -2896,6 +3080,15 @@ static void alc880_medion_rim_unsol_event(struct hda_codec *codec, alc880_medion_rim_automute(codec); } +static void alc880_medion_rim_init_hook(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x1b; + alc880_medion_rim_automute(codec); +} + #ifdef CONFIG_SND_HDA_POWER_SAVE static struct hda_amp_list alc880_loopbacks[] = { { 0x0b, HDA_INPUT, 0 }, @@ -2924,8 +3117,7 @@ static int alc_init(struct hda_codec *codec) unsigned int i; alc_fix_pll(codec); - if (codec->vendor_id == 0x10ec0888) - alc888_coef_init(codec); + alc_auto_init_amp(codec, spec->init_amp); for (i = 0; i < spec->num_init_verbs; i++) snd_hda_sequence_write(codec, spec->init_verbs[i]); @@ -3127,7 +3319,10 @@ static int alc_build_pcms(struct hda_codec *codec) if (spec->no_analog) goto skip_analog; + snprintf(spec->stream_name_analog, sizeof(spec->stream_name_analog), + "%s Analog", codec->chip_name); info->name = spec->stream_name_analog; + if (spec->stream_analog_playback) { if (snd_BUG_ON(!spec->multiout.dac_nids)) return -EINVAL; @@ -3153,6 +3348,9 @@ static int alc_build_pcms(struct hda_codec *codec) skip_analog: /* SPDIF for stream index #1 */ if (spec->multiout.dig_out_nid || spec->dig_in_nid) { + snprintf(spec->stream_name_digital, + sizeof(spec->stream_name_digital), + "%s Digital", codec->chip_name); codec->num_pcms = 2; codec->slave_dig_outs = spec->multiout.slave_dig_outs; info = spec->pcm_rec + 1; @@ -3755,7 +3953,7 @@ static struct alc_config_preset alc880_presets[] = { .channel_mode = alc880_2_jack_modes, .input_mux = &alc880_f1734_capture_source, .unsol_event = alc880_uniwill_p53_unsol_event, - .init_hook = alc880_uniwill_p53_hp_automute, + .init_hook = alc880_uniwill_p53_init_hook, }, [ALC880_ASUS] = { .mixers = { alc880_asus_mixer }, @@ -3832,7 +4030,7 @@ static struct alc_config_preset alc880_presets[] = { .need_dac_fix = 1, .input_mux = &alc880_capture_source, .unsol_event = alc880_uniwill_unsol_event, - .init_hook = alc880_uniwill_automute, + .init_hook = alc880_uniwill_init_hook, }, [ALC880_UNIWILL_P53] = { .mixers = { alc880_uniwill_p53_mixer }, @@ -3844,7 +4042,7 @@ static struct alc_config_preset alc880_presets[] = { .channel_mode = alc880_threestack_modes, .input_mux = &alc880_capture_source, .unsol_event = alc880_uniwill_p53_unsol_event, - .init_hook = alc880_uniwill_p53_hp_automute, + .init_hook = alc880_uniwill_p53_init_hook, }, [ALC880_FUJITSU] = { .mixers = { alc880_fujitsu_mixer }, @@ -3858,7 +4056,7 @@ static struct alc_config_preset alc880_presets[] = { .channel_mode = alc880_2_jack_modes, .input_mux = &alc880_capture_source, .unsol_event = alc880_uniwill_p53_unsol_event, - .init_hook = alc880_uniwill_p53_hp_automute, + .init_hook = alc880_uniwill_p53_init_hook, }, [ALC880_CLEVO] = { .mixers = { alc880_three_stack_mixer }, @@ -3883,8 +4081,8 @@ static struct alc_config_preset alc880_presets[] = { .channel_mode = alc880_lg_ch_modes, .need_dac_fix = 1, .input_mux = &alc880_lg_capture_source, - .unsol_event = alc880_lg_unsol_event, - .init_hook = alc880_lg_automute, + .unsol_event = alc_automute_amp_unsol_event, + .init_hook = alc880_lg_init_hook, #ifdef CONFIG_SND_HDA_POWER_SAVE .loopbacks = alc880_lg_loopbacks, #endif @@ -3899,8 +4097,8 @@ static struct alc_config_preset alc880_presets[] = { .num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes), .channel_mode = alc880_lg_lw_modes, .input_mux = &alc880_lg_lw_capture_source, - .unsol_event = alc880_lg_lw_unsol_event, - .init_hook = alc880_lg_lw_automute, + .unsol_event = alc_automute_amp_unsol_event, + .init_hook = alc880_lg_lw_init_hook, }, [ALC880_MEDION_RIM] = { .mixers = { alc880_medion_rim_mixer }, @@ -3914,7 +4112,7 @@ static struct alc_config_preset alc880_presets[] = { .channel_mode = alc880_2_jack_modes, .input_mux = &alc880_medion_rim_capture_source, .unsol_event = alc880_medion_rim_unsol_event, - .init_hook = alc880_medion_rim_automute, + .init_hook = alc880_medion_rim_init_hook, }, #ifdef CONFIG_SND_DEBUG [ALC880_TEST] = { @@ -4199,7 +4397,6 @@ static void alc880_auto_init_multi_out(struct hda_codec *codec) struct alc_spec *spec = codec->spec; int i; - alc_subsystem_id(codec, 0x15, 0x1b, 0x14); for (i = 0; i < spec->autocfg.line_outs; i++) { hda_nid_t nid = spec->autocfg.line_out_pins[i]; int pin_type = get_pin_type(spec->autocfg.line_out_type); @@ -4304,6 +4501,8 @@ static int alc880_parse_auto_config(struct hda_codec *codec) spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux[0]; + alc_ssid_check(codec, 0x15, 0x1b, 0x14); + return 1; } @@ -4361,8 +4560,8 @@ static int patch_alc880(struct hda_codec *codec) alc880_models, alc880_cfg_tbl); if (board_config < 0) { - printk(KERN_INFO "hda_codec: Unknown model for ALC880, " - "trying auto-probe from BIOS...\n"); + printk(KERN_INFO "hda_codec: Unknown model for %s, " + "trying auto-probe from BIOS...\n", codec->chip_name); board_config = ALC880_AUTO; } @@ -4389,12 +4588,10 @@ static int patch_alc880(struct hda_codec *codec) if (board_config != ALC880_AUTO) setup_preset(spec, &alc880_presets[board_config]); - spec->stream_name_analog = "ALC880 Analog"; spec->stream_analog_playback = &alc880_pcm_analog_playback; spec->stream_analog_capture = &alc880_pcm_analog_capture; spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture; - spec->stream_name_digital = "ALC880 Digital"; spec->stream_digital_playback = &alc880_pcm_digital_playback; spec->stream_digital_capture = &alc880_pcm_digital_capture; @@ -5679,7 +5876,6 @@ static void alc260_auto_init_multi_out(struct hda_codec *codec) struct alc_spec *spec = codec->spec; hda_nid_t nid; - alc_subsystem_id(codec, 0x10, 0x15, 0x0f); nid = spec->autocfg.line_out_pins[0]; if (nid) { int pin_type = get_pin_type(spec->autocfg.line_out_type); @@ -5789,6 +5985,8 @@ static int alc260_parse_auto_config(struct hda_codec *codec) spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux[0]; + alc_ssid_check(codec, 0x10, 0x15, 0x0f); + return 1; } @@ -6006,8 +6204,9 @@ static int patch_alc260(struct hda_codec *codec) alc260_models, alc260_cfg_tbl); if (board_config < 0) { - snd_printd(KERN_INFO "hda_codec: Unknown model for ALC260, " - "trying auto-probe from BIOS...\n"); + snd_printd(KERN_INFO "hda_codec: Unknown model for %s, " + "trying auto-probe from BIOS...\n", + codec->chip_name); board_config = ALC260_AUTO; } @@ -6034,11 +6233,9 @@ static int patch_alc260(struct hda_codec *codec) if (board_config != ALC260_AUTO) setup_preset(spec, &alc260_presets[board_config]); - spec->stream_name_analog = "ALC260 Analog"; spec->stream_analog_playback = &alc260_pcm_analog_playback; spec->stream_analog_capture = &alc260_pcm_analog_capture; - spec->stream_name_digital = "ALC260 Digital"; spec->stream_digital_playback = &alc260_pcm_digital_playback; spec->stream_digital_capture = &alc260_pcm_digital_capture; @@ -6115,6 +6312,16 @@ static struct hda_input_mux alc882_capture_source = { { "CD", 0x4 }, }, }; + +static struct hda_input_mux mb5_capture_source = { + .num_items = 3, + .items = { + { "Mic", 0x1 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + }, +}; + /* * 2ch mode */ @@ -6172,7 +6379,7 @@ static struct hda_channel_mode alc882_sixstack_modes[2] = { }; /* - * macbook pro ALC885 can switch LineIn to LineOut without loosing Mic + * macbook pro ALC885 can switch LineIn to LineOut without losing Mic */ /* @@ -6202,6 +6409,34 @@ static struct hda_channel_mode alc885_mbp_6ch_modes[2] = { { 6, alc885_mbp_ch6_init }, }; +/* + * 2ch + * Speakers/Woofer/HP = Front + * LineIn = Input + */ +static struct hda_verb alc885_mb5_ch2_init[] = { + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + { } /* end */ +}; + +/* + * 6ch mode + * Speakers/HP = Front + * Woofer = LFE + * LineIn = Surround + */ +static struct hda_verb alc885_mb5_ch6_init[] = { + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, + { } /* end */ +}; + +static struct hda_channel_mode alc885_mb5_6ch_modes[2] = { + { 2, alc885_mb5_ch2_init }, + { 6, alc885_mb5_ch6_init }, +}; /* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b @@ -6244,6 +6479,25 @@ static struct snd_kcontrol_new alc885_mbp3_mixer[] = { HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT), { } /* end */ }; + +static struct snd_kcontrol_new alc885_mb5_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("HP Playback Volume", 0x0f, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE ("HP Playback Switch", 0x0f, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("Line Boost", 0x15, 0x00, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x19, 0x00, HDA_INPUT), + { } /* end */ +}; + static struct snd_kcontrol_new alc882_w2jc_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), @@ -6471,6 +6725,55 @@ static struct hda_verb alc882_macpro_init_verbs[] = { { } }; +/* Macbook 5,1 */ +static struct hda_verb alc885_mb5_init_verbs[] = { + /* DACs */ + {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Front mixer */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* Surround mixer */ + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* LFE mixer */ + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* HP mixer */ + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* Front Pin (0x0c) */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x18, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* LFE Pin (0x0e) */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02}, + /* HP Pin (0x0f) */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_CONNECT_SEL, 0x03}, + /* Front Mic pin: input vref at 80% */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Line In pin */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + { } +}; + /* Macbook Pro rev3 */ static struct hda_verb alc885_mbp3_init_verbs[] = { /* Front mixer: unmute input/output amp left and right (volume = 0) */ @@ -6560,45 +6863,23 @@ static struct hda_verb alc885_imac24_init_verbs[] = { }; /* Toggle speaker-output according to the hp-jack state */ -static void alc885_imac24_automute(struct hda_codec *codec) +static void alc885_imac24_automute_init_hook(struct hda_codec *codec) { - unsigned int present; + struct alc_spec *spec = codec->spec; - present = snd_hda_codec_read(codec, 0x14, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - snd_hda_codec_amp_stereo(codec, 0x18, HDA_OUTPUT, 0, - HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); - snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0, - HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + spec->autocfg.hp_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x18; + spec->autocfg.speaker_pins[1] = 0x1a; + alc_automute_amp(codec); } -/* Processes unsolicited events. */ -static void alc885_imac24_unsol_event(struct hda_codec *codec, - unsigned int res) +static void alc885_mbp3_init_hook(struct hda_codec *codec) { - /* Headphone insertion or removal. */ - if ((res >> 26) == ALC880_HP_EVENT) - alc885_imac24_automute(codec); -} + struct alc_spec *spec = codec->spec; -static void alc885_mbp3_automute(struct hda_codec *codec) -{ - unsigned int present; - - present = snd_hda_codec_read(codec, 0x15, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, - HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); - snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, - HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE); - -} -static void alc885_mbp3_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - /* Headphone insertion or removal. */ - if ((res >> 26) == ALC880_HP_EVENT) - alc885_mbp3_automute(codec); + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + alc_automute_amp(codec); } @@ -6623,24 +6904,25 @@ static struct hda_verb alc882_targa_verbs[] = { /* toggle speaker-output according to the hp-jack state */ static void alc882_targa_automute(struct hda_codec *codec) { - unsigned int present; - - present = snd_hda_codec_read(codec, 0x14, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0, - HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + struct alc_spec *spec = codec->spec; + alc_automute_amp(codec); snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA, - present ? 1 : 3); + spec->jack_present ? 1 : 3); +} + +static void alc882_targa_init_hook(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x1b; + alc882_targa_automute(codec); } static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res) { - /* Looks like the unsol event is incompatible with the standard - * definition. 4bit tag is placed at 26 bit! - */ - if (((res >> 26) == ALC880_HP_EVENT)) { + if ((res >> 26) == ALC880_HP_EVENT) alc882_targa_automute(codec); - } } static struct hda_verb alc882_asus_a7j_verbs[] = { @@ -6722,7 +7004,7 @@ static void alc885_macpro_init_hook(struct hda_codec *codec) static void alc885_imac24_init_hook(struct hda_codec *codec) { alc885_macpro_init_hook(codec); - alc885_imac24_automute(codec); + alc885_imac24_automute_init_hook(codec); } /* @@ -6797,7 +7079,7 @@ static struct hda_verb alc882_auto_init_verbs[] = { #define alc882_loopbacks alc880_loopbacks #endif -/* pcm configuration: identiacal with ALC880 */ +/* pcm configuration: identical with ALC880 */ #define alc882_pcm_analog_playback alc880_pcm_analog_playback #define alc882_pcm_analog_capture alc880_pcm_analog_capture #define alc882_pcm_digital_playback alc880_pcm_digital_playback @@ -6815,6 +7097,7 @@ static const char *alc882_models[ALC882_MODEL_LAST] = { [ALC882_ASUS_A7J] = "asus-a7j", [ALC882_ASUS_A7M] = "asus-a7m", [ALC885_MACPRO] = "macpro", + [ALC885_MB5] = "mb5", [ALC885_MBP3] = "mbp3", [ALC885_IMAC24] = "imac24", [ALC882_AUTO] = "auto", @@ -6892,8 +7175,20 @@ static struct alc_config_preset alc882_presets[] = { .input_mux = &alc882_capture_source, .dig_out_nid = ALC882_DIGOUT_NID, .dig_in_nid = ALC882_DIGIN_NID, - .unsol_event = alc885_mbp3_unsol_event, - .init_hook = alc885_mbp3_automute, + .unsol_event = alc_automute_amp_unsol_event, + .init_hook = alc885_mbp3_init_hook, + }, + [ALC885_MB5] = { + .mixers = { alc885_mb5_mixer, alc882_chmode_mixer }, + .init_verbs = { alc885_mb5_init_verbs, + alc880_gpio1_init_verbs }, + .num_dacs = ARRAY_SIZE(alc882_dac_nids), + .dac_nids = alc882_dac_nids, + .channel_mode = alc885_mb5_6ch_modes, + .num_channel_mode = ARRAY_SIZE(alc885_mb5_6ch_modes), + .input_mux = &mb5_capture_source, + .dig_out_nid = ALC882_DIGOUT_NID, + .dig_in_nid = ALC882_DIGIN_NID, }, [ALC885_MACPRO] = { .mixers = { alc882_macpro_mixer }, @@ -6917,7 +7212,7 @@ static struct alc_config_preset alc882_presets[] = { .num_channel_mode = ARRAY_SIZE(alc882_ch_modes), .channel_mode = alc882_ch_modes, .input_mux = &alc882_capture_source, - .unsol_event = alc885_imac24_unsol_event, + .unsol_event = alc_automute_amp_unsol_event, .init_hook = alc885_imac24_init_hook, }, [ALC882_TARGA] = { @@ -6934,7 +7229,7 @@ static struct alc_config_preset alc882_presets[] = { .need_dac_fix = 1, .input_mux = &alc882_capture_source, .unsol_event = alc882_targa_unsol_event, - .init_hook = alc882_targa_automute, + .init_hook = alc882_targa_init_hook, }, [ALC882_ASUS_A7J] = { .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer }, @@ -7014,7 +7309,6 @@ static void alc882_auto_init_multi_out(struct hda_codec *codec) struct alc_spec *spec = codec->spec; int i; - alc_subsystem_id(codec, 0x15, 0x1b, 0x14); for (i = 0; i <= HDA_SIDE; i++) { hda_nid_t nid = spec->autocfg.line_out_pins[i]; int pin_type = get_pin_type(spec->autocfg.line_out_type); @@ -7197,10 +7491,17 @@ static int patch_alc882(struct hda_codec *codec) case 0x106b00a1: /* Macbook (might be wrong - PCI SSID?) */ case 0x106b00a4: /* MacbookPro4,1 */ case 0x106b2c00: /* Macbook Pro rev3 */ - case 0x106b3600: /* Macbook 3.1 */ + /* Macbook 3.1 (0x106b3600) is handled by patch_alc883() */ case 0x106b3800: /* MacbookPro4,1 - latter revision */ board_config = ALC885_MBP3; break; + case 0x106b3f00: /* Macbook 5,1 */ + case 0x106b4000: /* Macbook Pro 5,1 - FIXME: HP jack sense + * seems not working, so apparently + * no perfect solution yet + */ + board_config = ALC885_MB5; + break; default: /* ALC889A is handled better as ALC888-compatible */ if (codec->revision_id == 0x100101 || @@ -7208,8 +7509,9 @@ static int patch_alc882(struct hda_codec *codec) alc_free(codec); return patch_alc883(codec); } - printk(KERN_INFO "hda_codec: Unknown model for ALC882, " - "trying auto-probe from BIOS...\n"); + printk(KERN_INFO "hda_codec: Unknown model for %s, " + "trying auto-probe from BIOS...\n", + codec->chip_name); board_config = ALC882_AUTO; } } @@ -7239,14 +7541,6 @@ static int patch_alc882(struct hda_codec *codec) if (board_config != ALC882_AUTO) setup_preset(spec, &alc882_presets[board_config]); - if (codec->vendor_id == 0x10ec0885) { - spec->stream_name_analog = "ALC885 Analog"; - spec->stream_name_digital = "ALC885 Digital"; - } else { - spec->stream_name_analog = "ALC882 Analog"; - spec->stream_name_digital = "ALC882 Digital"; - } - spec->stream_analog_playback = &alc882_pcm_analog_playback; spec->stream_analog_capture = &alc882_pcm_analog_capture; /* FIXME: setup DAC5 */ @@ -7256,7 +7550,6 @@ static int patch_alc882(struct hda_codec *codec) spec->stream_digital_playback = &alc882_pcm_digital_playback; spec->stream_digital_capture = &alc882_pcm_digital_capture; - spec->capture_style = CAPT_MIX; /* matrix-style capture */ if (!spec->adc_nids && spec->input_mux) { /* check whether NID 0x07 is valid */ unsigned int wcap = get_wcaps(codec, 0x07); @@ -7399,6 +7692,17 @@ static struct hda_input_mux alc883_asus_eee1601_capture_source = { }, }; +static struct hda_input_mux alc889A_mb31_capture_source = { + .num_items = 2, + .items = { + { "Mic", 0x0 }, + /* Front Mic (0x01) unused */ + { "Line", 0x2 }, + /* Line 2 (0x03) unused */ + /* CD (0x04) unsused? */ + }, +}; + /* * 2ch mode */ @@ -7448,6 +7752,73 @@ static struct hda_channel_mode alc883_3ST_6ch_modes[3] = { { 6, alc883_3ST_ch6_init }, }; + +/* + * 2ch mode + */ +static struct hda_verb alc883_4ST_ch2_init[] = { + { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { } /* end */ +}; + +/* + * 4ch mode + */ +static struct hda_verb alc883_4ST_ch4_init[] = { + { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { } /* end */ +}; + +/* + * 6ch mode + */ +static struct hda_verb alc883_4ST_ch6_init[] = { + { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { } /* end */ +}; + +/* + * 8ch mode + */ +static struct hda_verb alc883_4ST_ch8_init[] = { + { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 }, + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { } /* end */ +}; + +static struct hda_channel_mode alc883_4ST_8ch_modes[4] = { + { 2, alc883_4ST_ch2_init }, + { 4, alc883_4ST_ch4_init }, + { 6, alc883_4ST_ch6_init }, + { 8, alc883_4ST_ch8_init }, +}; + + /* * 2ch mode */ @@ -7517,6 +7888,49 @@ static struct hda_channel_mode alc883_sixstack_modes[2] = { { 8, alc883_sixstack_ch8_init }, }; +/* 2ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:front) */ +static struct hda_verb alc889A_mb31_ch2_init[] = { + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */ + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */ + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */ + { } /* end */ +}; + +/* 4ch mode (Speaker:front, Subwoofer:CLFE, Line:CLFE, Headphones:front) */ +static struct hda_verb alc889A_mb31_ch4_init[] = { + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */ + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */ + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */ + { } /* end */ +}; + +/* 5ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:rear) */ +static struct hda_verb alc889A_mb31_ch5_init[] = { + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as rear */ + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */ + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */ + { } /* end */ +}; + +/* 6ch mode (Speaker:front, Subwoofer:off, Line:CLFE, Headphones:Rear) */ +static struct hda_verb alc889A_mb31_ch6_init[] = { + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as front */ + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Subwoofer off */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */ + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */ + { } /* end */ +}; + +static struct hda_channel_mode alc889A_mb31_6ch_modes[4] = { + { 2, alc889A_mb31_ch2_init }, + { 4, alc889A_mb31_ch4_init }, + { 5, alc889A_mb31_ch5_init }, + { 6, alc889A_mb31_ch6_init }, +}; + static struct hda_verb alc883_medion_eapd_verbs[] = { /* eanable EAPD on medion laptop */ {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, @@ -7685,7 +8099,7 @@ static struct snd_kcontrol_new alc883_fivestack_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc883_tagra_mixer[] = { +static struct snd_kcontrol_new alc883_targa_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), @@ -7705,7 +8119,7 @@ static struct snd_kcontrol_new alc883_tagra_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc883_tagra_2ch_mixer[] = { +static struct snd_kcontrol_new alc883_targa_2ch_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), @@ -7770,6 +8184,19 @@ static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = { { } /* end */ }; +static struct snd_kcontrol_new alc888_acer_aspire_6530_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("LFE Playback Volume", 0x0f, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("LFE Playback Switch", 0x0f, 2, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; + static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), @@ -7782,8 +8209,6 @@ static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = { HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT), HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("iSpeaker Playback Switch", 0x1a, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), @@ -7797,6 +8222,42 @@ static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = { { } /* end */ }; +static struct snd_kcontrol_new alc889A_mb31_mixer[] = { + /* Output mixers */ + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x00, + HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x02, HDA_INPUT), + /* Output switches */ + HDA_CODEC_MUTE("Enable Speaker", 0x14, 0x00, HDA_OUTPUT), + HDA_CODEC_MUTE("Enable Headphones", 0x15, 0x00, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("Enable LFE", 0x16, 2, 0x00, HDA_OUTPUT), + /* Boost mixers */ + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT), + HDA_CODEC_VOLUME("Line Boost", 0x1a, 0x00, HDA_INPUT), + /* Input mixers */ + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + { } /* end */ +}; + +static struct snd_kcontrol_new alc883_vaiott_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + static struct hda_bind_ctls alc883_bind_cap_vol = { .ops = &snd_hda_bind_vol, .values = { @@ -7932,16 +8393,14 @@ static struct hda_verb alc883_init_verbs[] = { }; /* toggle speaker-output according to the hp-jack state */ -static void alc883_mitac_hp_automute(struct hda_codec *codec) +static void alc883_mitac_init_hook(struct hda_codec *codec) { - unsigned int present; + struct alc_spec *spec = codec->spec; - present = snd_hda_codec_read(codec, 0x15, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, - HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); - snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0, - HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[1] = 0x17; + alc_automute_amp(codec); } /* auto-toggle front mic */ @@ -7958,25 +8417,6 @@ static void alc883_mitac_mic_automute(struct hda_codec *codec) } */ -static void alc883_mitac_automute(struct hda_codec *codec) -{ - alc883_mitac_hp_automute(codec); - /* alc883_mitac_mic_automute(codec); */ -} - -static void alc883_mitac_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - switch (res >> 26) { - case ALC880_HP_EVENT: - alc883_mitac_hp_automute(codec); - break; - case ALC880_MIC_EVENT: - /* alc883_mitac_mic_automute(codec); */ - break; - } -} - static struct hda_verb alc883_mitac_verbs[] = { /* HP */ {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, @@ -8021,21 +8461,31 @@ static struct hda_verb alc883_2ch_fujitsu_pi2515_verbs[] = { { } /* end */ }; -static struct hda_verb alc883_tagra_verbs[] = { +static struct hda_verb alc883_targa_verbs[] = { {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */ - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */ - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ +/* Connect Line-Out side jack (SPDIF) to Side */ + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, +/* Connect Mic jack to CLFE */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, +/* Connect Line-in jack to Surround */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, +/* Connect HP out jack to Front */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, - {0x01, AC_VERB_SET_GPIO_MASK, 0x03}, - {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03}, - {0x01, AC_VERB_SET_GPIO_DATA, 0x03}, { } /* end */ }; @@ -8094,29 +8544,26 @@ static struct hda_verb alc888_6st_dell_verbs[] = { { } }; -static void alc888_3st_hp_front_automute(struct hda_codec *codec) -{ - unsigned int present, bits; +static struct hda_verb alc883_vaiott_verbs[] = { + /* HP */ + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - present = snd_hda_codec_read(codec, 0x1b, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? HDA_AMP_MUTE : 0; - snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); - snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); - snd_hda_codec_amp_stereo(codec, 0x18, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); -} + /* enable unsolicited event */ + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, -static void alc888_3st_hp_unsol_event(struct hda_codec *codec, - unsigned int res) + { } /* end */ +}; + +static void alc888_3st_hp_init_hook(struct hda_codec *codec) { - switch (res >> 26) { - case ALC880_HP_EVENT: - alc888_3st_hp_front_automute(codec); - break; - } + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[1] = 0x16; + spec->autocfg.speaker_pins[2] = 0x18; + alc_automute_amp(codec); } static struct hda_verb alc888_3st_hp_verbs[] = { @@ -8213,56 +8660,18 @@ static struct hda_verb alc883_medion_md2_verbs[] = { }; /* toggle speaker-output according to the hp-jack state */ -static void alc883_medion_md2_automute(struct hda_codec *codec) +static void alc883_medion_md2_init_hook(struct hda_codec *codec) { - unsigned int present; + struct alc_spec *spec = codec->spec; - present = snd_hda_codec_read(codec, 0x14, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, - HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); -} - -static void alc883_medion_md2_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) == ALC880_HP_EVENT) - alc883_medion_md2_automute(codec); + spec->autocfg.hp_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x15; + alc_automute_amp(codec); } /* toggle speaker-output according to the hp-jack state */ -static void alc883_tagra_automute(struct hda_codec *codec) -{ - unsigned int present; - unsigned char bits; - - present = snd_hda_codec_read(codec, 0x14, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? HDA_AMP_MUTE : 0; - snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); - snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA, - present ? 1 : 3); -} - -static void alc883_tagra_unsol_event(struct hda_codec *codec, unsigned int res) -{ - if ((res >> 26) == ALC880_HP_EVENT) - alc883_tagra_automute(codec); -} - -/* toggle speaker-output according to the hp-jack state */ -static void alc883_clevo_m720_hp_automute(struct hda_codec *codec) -{ - unsigned int present; - unsigned char bits; - - present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0) - & AC_PINSENSE_PRESENCE; - bits = present ? HDA_AMP_MUTE : 0; - snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); -} +#define alc883_targa_init_hook alc882_targa_init_hook +#define alc883_targa_unsol_event alc882_targa_unsol_event static void alc883_clevo_m720_mic_automute(struct hda_codec *codec) { @@ -8274,9 +8683,13 @@ static void alc883_clevo_m720_mic_automute(struct hda_codec *codec) HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); } -static void alc883_clevo_m720_automute(struct hda_codec *codec) +static void alc883_clevo_m720_init_hook(struct hda_codec *codec) { - alc883_clevo_m720_hp_automute(codec); + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + alc_automute_amp(codec); alc883_clevo_m720_mic_automute(codec); } @@ -8284,52 +8697,32 @@ static void alc883_clevo_m720_unsol_event(struct hda_codec *codec, unsigned int res) { switch (res >> 26) { - case ALC880_HP_EVENT: - alc883_clevo_m720_hp_automute(codec); - break; case ALC880_MIC_EVENT: alc883_clevo_m720_mic_automute(codec); break; + default: + alc_automute_amp_unsol_event(codec, res); + break; } } /* toggle speaker-output according to the hp-jack state */ -static void alc883_2ch_fujitsu_pi2515_automute(struct hda_codec *codec) +static void alc883_2ch_fujitsu_pi2515_init_hook(struct hda_codec *codec) { - unsigned int present; - unsigned char bits; + struct alc_spec *spec = codec->spec; - present = snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0) - & AC_PINSENSE_PRESENCE; - bits = present ? HDA_AMP_MUTE : 0; - snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); + spec->autocfg.hp_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x15; + alc_automute_amp(codec); } -static void alc883_2ch_fujitsu_pi2515_unsol_event(struct hda_codec *codec, - unsigned int res) +static void alc883_haier_w66_init_hook(struct hda_codec *codec) { - if ((res >> 26) == ALC880_HP_EVENT) - alc883_2ch_fujitsu_pi2515_automute(codec); -} + struct alc_spec *spec = codec->spec; -static void alc883_haier_w66_automute(struct hda_codec *codec) -{ - unsigned int present; - unsigned char bits; - - present = snd_hda_codec_read(codec, 0x1b, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? 0x80 : 0; - snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, - 0x80, bits); -} - -static void alc883_haier_w66_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) == ALC880_HP_EVENT) - alc883_haier_w66_automute(codec); + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.speaker_pins[0] = 0x14; + alc_automute_amp(codec); } static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec) @@ -8337,8 +8730,8 @@ static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec) unsigned int present; unsigned char bits; - present = snd_hda_codec_read(codec, 0x14, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + present = snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0) + & AC_PINSENSE_PRESENCE; bits = present ? HDA_AMP_MUTE : 0; snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, HDA_AMP_MUTE, bits); @@ -8368,23 +8761,14 @@ static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec, } /* toggle speaker-output according to the hp-jack state */ -static void alc883_acer_aspire_automute(struct hda_codec *codec) +static void alc883_acer_aspire_init_hook(struct hda_codec *codec) { - unsigned int present; + struct alc_spec *spec = codec->spec; - present = snd_hda_codec_read(codec, 0x14, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, - HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); - snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, - HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); -} - -static void alc883_acer_aspire_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) == ALC880_HP_EVENT) - alc883_acer_aspire_automute(codec); + spec->autocfg.hp_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x15; + spec->autocfg.speaker_pins[1] = 0x16; + alc_automute_amp(codec); } static struct hda_verb alc883_acer_eapd_verbs[] = { @@ -8405,75 +8789,39 @@ static struct hda_verb alc883_acer_eapd_verbs[] = { { } }; -static void alc888_6st_dell_front_automute(struct hda_codec *codec) +static void alc888_6st_dell_init_hook(struct hda_codec *codec) { - unsigned int present; + struct alc_spec *spec = codec->spec; - present = snd_hda_codec_read(codec, 0x1b, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, - HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); - snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, - HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); - snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, - HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); - snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0, - HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[1] = 0x15; + spec->autocfg.speaker_pins[2] = 0x16; + spec->autocfg.speaker_pins[3] = 0x17; + alc_automute_amp(codec); } -static void alc888_6st_dell_unsol_event(struct hda_codec *codec, - unsigned int res) +static void alc888_lenovo_sky_init_hook(struct hda_codec *codec) { - switch (res >> 26) { - case ALC880_HP_EVENT: - /* printk(KERN_DEBUG "hp_event\n"); */ - alc888_6st_dell_front_automute(codec); - break; - } + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[1] = 0x15; + spec->autocfg.speaker_pins[2] = 0x16; + spec->autocfg.speaker_pins[3] = 0x17; + spec->autocfg.speaker_pins[4] = 0x1a; + alc_automute_amp(codec); } -static void alc888_lenovo_sky_front_automute(struct hda_codec *codec) +static void alc883_vaiott_init_hook(struct hda_codec *codec) { - unsigned int mute; - unsigned int present; + struct alc_spec *spec = codec->spec; - snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0); - present = snd_hda_codec_read(codec, 0x1b, 0, - AC_VERB_GET_PIN_SENSE, 0); - present = (present & 0x80000000) != 0; - if (present) { - /* mute internal speaker */ - snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, - HDA_AMP_MUTE, HDA_AMP_MUTE); - snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, - HDA_AMP_MUTE, HDA_AMP_MUTE); - snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, - HDA_AMP_MUTE, HDA_AMP_MUTE); - snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0, - HDA_AMP_MUTE, HDA_AMP_MUTE); - snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0, - HDA_AMP_MUTE, HDA_AMP_MUTE); - } else { - /* unmute internal speaker if necessary */ - mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0); - snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, - HDA_AMP_MUTE, mute); - snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, - HDA_AMP_MUTE, mute); - snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, - HDA_AMP_MUTE, mute); - snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0, - HDA_AMP_MUTE, mute); - snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0, - HDA_AMP_MUTE, mute); - } -} - -static void alc883_lenovo_sky_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) == ALC880_HP_EVENT) - alc888_lenovo_sky_front_automute(codec); + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[1] = 0x17; + alc_automute_amp(codec); } /* @@ -8561,39 +8909,33 @@ static void alc883_nb_mic_automute(struct hda_codec *codec) 0x7000 | (0x01 << 8) | (present ? 0x80 : 0)); } -static void alc883_M90V_speaker_automute(struct hda_codec *codec) +static void alc883_M90V_init_hook(struct hda_codec *codec) { - unsigned int present; - unsigned char bits; + struct alc_spec *spec = codec->spec; - present = snd_hda_codec_read(codec, 0x1b, 0, - AC_VERB_GET_PIN_SENSE, 0) - & AC_PINSENSE_PRESENCE; - bits = present ? 0 : PIN_OUT; - snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, - bits); - snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, - bits); - snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, - bits); + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[1] = 0x15; + spec->autocfg.speaker_pins[2] = 0x16; + alc_automute_pin(codec); } static void alc883_mode2_unsol_event(struct hda_codec *codec, unsigned int res) { switch (res >> 26) { - case ALC880_HP_EVENT: - alc883_M90V_speaker_automute(codec); - break; case ALC880_MIC_EVENT: alc883_nb_mic_automute(codec); break; + default: + alc_sku_unsol_event(codec, res); + break; } } static void alc883_mode2_inithook(struct hda_codec *codec) { - alc883_M90V_speaker_automute(codec); + alc883_M90V_init_hook(codec); alc883_nb_mic_automute(codec); } @@ -8610,39 +8952,56 @@ static struct hda_verb alc888_asus_eee1601_verbs[] = { { } /* end */ }; -static void alc883_eee1601_speaker_automute(struct hda_codec *codec) +static void alc883_eee1601_inithook(struct hda_codec *codec) { - unsigned int present; - unsigned char bits; + struct alc_spec *spec = codec->spec; - present = snd_hda_codec_read(codec, 0x14, 0, - AC_VERB_GET_PIN_SENSE, 0) - & AC_PINSENSE_PRESENCE; - bits = present ? 0 : PIN_OUT; - snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, - bits); + spec->autocfg.hp_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x1b; + alc_automute_pin(codec); } -static void alc883_eee1601_unsol_event(struct hda_codec *codec, - unsigned int res) +static struct hda_verb alc889A_mb31_verbs[] = { + /* Init rear pin (used as headphone output) */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4}, /* Apple Headphones */ + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Connect to front */ + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + /* Init line pin (used as output in 4ch and 6ch mode) */ + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02}, /* Connect to CLFE */ + /* Init line 2 pin (used as headphone out by default) */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Use as input */ + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Mute output */ + { } /* end */ +}; + +/* Mute speakers according to the headphone jack state */ +static void alc889A_mb31_automute(struct hda_codec *codec) { - switch (res >> 26) { - case ALC880_HP_EVENT: - alc883_eee1601_speaker_automute(codec); - break; + unsigned int present; + + /* Mute only in 2ch or 4ch mode */ + if (snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_CONNECT_SEL, 0) + == 0x00) { + present = snd_hda_codec_read(codec, 0x15, 0, + AC_VERB_GET_PIN_SENSE, 0) & AC_PINSENSE_PRESENCE; + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); } } -static void alc883_eee1601_inithook(struct hda_codec *codec) +static void alc889A_mb31_unsol_event(struct hda_codec *codec, unsigned int res) { - alc883_eee1601_speaker_automute(codec); + if ((res >> 26) == ALC880_HP_EVENT) + alc889A_mb31_automute(codec); } #ifdef CONFIG_SND_HDA_POWER_SAVE #define alc883_loopbacks alc880_loopbacks #endif -/* pcm configuration: identiacal with ALC880 */ +/* pcm configuration: identical with ALC880 */ #define alc883_pcm_analog_playback alc880_pcm_analog_playback #define alc883_pcm_analog_capture alc880_pcm_analog_capture #define alc883_pcm_analog_alt_capture alc880_pcm_analog_alt_capture @@ -8659,9 +9018,12 @@ static const char *alc883_models[ALC883_MODEL_LAST] = { [ALC883_6ST_DIG] = "6stack-dig", [ALC883_TARGA_DIG] = "targa-dig", [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig", + [ALC883_TARGA_8ch_DIG] = "targa-8ch-dig", [ALC883_ACER] = "acer", [ALC883_ACER_ASPIRE] = "acer-aspire", [ALC888_ACER_ASPIRE_4930G] = "acer-aspire-4930g", + [ALC888_ACER_ASPIRE_6530G] = "acer-aspire-6530g", + [ALC888_ACER_ASPIRE_8930G] = "acer-aspire-8930g", [ALC883_MEDION] = "medion", [ALC883_MEDION_MD2] = "medion-md2", [ALC883_LAPTOP_EAPD] = "laptop-eapd", @@ -8678,6 +9040,8 @@ static const char *alc883_models[ALC883_MODEL_LAST] = { [ALC888_FUJITSU_XA3530] = "fujitsu-xa3530", [ALC883_3ST_6ch_INTEL] = "3stack-6ch-intel", [ALC1200_ASUS_P5Q] = "asus-p5q", + [ALC889A_MB31] = "mb31", + [ALC883_SONY_VAIO_TT] = "sony-vaio-tt", [ALC883_AUTO] = "auto", }; @@ -8693,14 +9057,20 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { ALC888_ACER_ASPIRE_4930G), SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G", ALC888_ACER_ASPIRE_4930G), + SND_PCI_QUIRK(0x1025, 0x0145, "Acer Aspire 8930G", + ALC888_ACER_ASPIRE_8930G), + SND_PCI_QUIRK(0x1025, 0x0146, "Acer Aspire 6935G", + ALC888_ACER_ASPIRE_8930G), SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC883_AUTO), SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC883_AUTO), SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G", ALC888_ACER_ASPIRE_4930G), SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G", - ALC888_ACER_ASPIRE_4930G), - /* default Acer */ - SND_PCI_QUIRK_VENDOR(0x1025, "Acer laptop", ALC883_ACER), + ALC888_ACER_ASPIRE_6530G), + /* default Acer -- disabled as it causes more problems. + * model=auto should work fine now + */ + /* SND_PCI_QUIRK_VENDOR(0x1025, "Acer laptop", ALC883_ACER), */ SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL), SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG), SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP), @@ -8736,6 +9106,7 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG), SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG), SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG), + SND_PCI_QUIRK(0x1462, 0x6510, "MSI GX620", ALC883_TARGA_8ch_DIG), SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG), SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG), SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG), @@ -8743,6 +9114,7 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { SND_PCI_QUIRK(0x1462, 0x7267, "MSI", ALC883_3ST_6ch_DIG), SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG), SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG), + SND_PCI_QUIRK(0x1462, 0x7350, "MSI", ALC883_6ST_DIG), SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG), SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG), SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720), @@ -8768,6 +9140,7 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { SND_PCI_QUIRK(0x8086, 0x2503, "82801H", ALC883_MITAC), SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC883_3ST_6ch_INTEL), SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch), + SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC883_SONY_VAIO_TT), {} }; @@ -8838,8 +9211,8 @@ static struct alc_config_preset alc883_presets[] = { .input_mux = &alc883_capture_source, }, [ALC883_TARGA_DIG] = { - .mixers = { alc883_tagra_mixer, alc883_chmode_mixer }, - .init_verbs = { alc883_init_verbs, alc883_tagra_verbs}, + .mixers = { alc883_targa_mixer, alc883_chmode_mixer }, + .init_verbs = { alc883_init_verbs, alc883_targa_verbs}, .num_dacs = ARRAY_SIZE(alc883_dac_nids), .dac_nids = alc883_dac_nids, .dig_out_nid = ALC883_DIGOUT_NID, @@ -8847,12 +9220,12 @@ static struct alc_config_preset alc883_presets[] = { .channel_mode = alc883_3ST_6ch_modes, .need_dac_fix = 1, .input_mux = &alc883_capture_source, - .unsol_event = alc883_tagra_unsol_event, - .init_hook = alc883_tagra_automute, + .unsol_event = alc883_targa_unsol_event, + .init_hook = alc883_targa_init_hook, }, [ALC883_TARGA_2ch_DIG] = { - .mixers = { alc883_tagra_2ch_mixer}, - .init_verbs = { alc883_init_verbs, alc883_tagra_verbs}, + .mixers = { alc883_targa_2ch_mixer}, + .init_verbs = { alc883_init_verbs, alc883_targa_verbs}, .num_dacs = ARRAY_SIZE(alc883_dac_nids), .dac_nids = alc883_dac_nids, .adc_nids = alc883_adc_nids_alt, @@ -8861,8 +9234,26 @@ static struct alc_config_preset alc883_presets[] = { .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_capture_source, - .unsol_event = alc883_tagra_unsol_event, - .init_hook = alc883_tagra_automute, + .unsol_event = alc883_targa_unsol_event, + .init_hook = alc883_targa_init_hook, + }, + [ALC883_TARGA_8ch_DIG] = { + .mixers = { alc883_base_mixer, alc883_chmode_mixer }, + .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs, + alc883_targa_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev), + .adc_nids = alc883_adc_nids_rev, + .capsrc_nids = alc883_capsrc_nids_rev, + .dig_out_nid = ALC883_DIGOUT_NID, + .dig_in_nid = ALC883_DIGIN_NID, + .num_channel_mode = ARRAY_SIZE(alc883_4ST_8ch_modes), + .channel_mode = alc883_4ST_8ch_modes, + .need_dac_fix = 1, + .input_mux = &alc883_capture_source, + .unsol_event = alc883_targa_unsol_event, + .init_hook = alc883_targa_init_hook, }, [ALC883_ACER] = { .mixers = { alc883_base_mixer }, @@ -8887,8 +9278,8 @@ static struct alc_config_preset alc883_presets[] = { .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_capture_source, - .unsol_event = alc883_acer_aspire_unsol_event, - .init_hook = alc883_acer_aspire_automute, + .unsol_event = alc_automute_amp_unsol_event, + .init_hook = alc883_acer_aspire_init_hook, }, [ALC888_ACER_ASPIRE_4930G] = { .mixers = { alc888_base_mixer, @@ -8907,8 +9298,47 @@ static struct alc_config_preset alc883_presets[] = { .num_mux_defs = ARRAY_SIZE(alc888_2_capture_sources), .input_mux = alc888_2_capture_sources, - .unsol_event = alc888_acer_aspire_4930g_unsol_event, - .init_hook = alc888_acer_aspire_4930g_automute, + .unsol_event = alc_automute_amp_unsol_event, + .init_hook = alc888_acer_aspire_4930g_init_hook, + }, + [ALC888_ACER_ASPIRE_6530G] = { + .mixers = { alc888_acer_aspire_6530_mixer }, + .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs, + alc888_acer_aspire_6530g_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev), + .adc_nids = alc883_adc_nids_rev, + .capsrc_nids = alc883_capsrc_nids_rev, + .dig_out_nid = ALC883_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), + .channel_mode = alc883_3ST_2ch_modes, + .num_mux_defs = + ARRAY_SIZE(alc888_2_capture_sources), + .input_mux = alc888_acer_aspire_6530_sources, + .unsol_event = alc_automute_amp_unsol_event, + .init_hook = alc888_acer_aspire_4930g_init_hook, + }, + [ALC888_ACER_ASPIRE_8930G] = { + .mixers = { alc888_base_mixer, + alc883_chmode_mixer }, + .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs, + alc889_acer_aspire_8930g_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc889_adc_nids), + .adc_nids = alc889_adc_nids, + .capsrc_nids = alc889_capsrc_nids, + .dig_out_nid = ALC883_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), + .channel_mode = alc883_3ST_6ch_modes, + .need_dac_fix = 1, + .const_channel_count = 6, + .num_mux_defs = + ARRAY_SIZE(alc889_capture_sources), + .input_mux = alc889_capture_sources, + .unsol_event = alc_automute_amp_unsol_event, + .init_hook = alc889_acer_aspire_8930g_init_hook, }, [ALC883_MEDION] = { .mixers = { alc883_fivestack_mixer, @@ -8932,8 +9362,8 @@ static struct alc_config_preset alc883_presets[] = { .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_capture_source, - .unsol_event = alc883_medion_md2_unsol_event, - .init_hook = alc883_medion_md2_automute, + .unsol_event = alc_automute_amp_unsol_event, + .init_hook = alc883_medion_md2_init_hook, }, [ALC883_LAPTOP_EAPD] = { .mixers = { alc883_base_mixer }, @@ -8954,7 +9384,7 @@ static struct alc_config_preset alc883_presets[] = { .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_capture_source, .unsol_event = alc883_clevo_m720_unsol_event, - .init_hook = alc883_clevo_m720_automute, + .init_hook = alc883_clevo_m720_init_hook, }, [ALC883_LENOVO_101E_2ch] = { .mixers = { alc883_lenovo_101e_2ch_mixer}, @@ -8978,8 +9408,8 @@ static struct alc_config_preset alc883_presets[] = { .channel_mode = alc883_3ST_2ch_modes, .need_dac_fix = 1, .input_mux = &alc883_lenovo_nb0763_capture_source, - .unsol_event = alc883_medion_md2_unsol_event, - .init_hook = alc883_medion_md2_automute, + .unsol_event = alc_automute_amp_unsol_event, + .init_hook = alc883_medion_md2_init_hook, }, [ALC888_LENOVO_MS7195_DIG] = { .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, @@ -8995,7 +9425,7 @@ static struct alc_config_preset alc883_presets[] = { .init_hook = alc888_lenovo_ms7195_front_automute, }, [ALC883_HAIER_W66] = { - .mixers = { alc883_tagra_2ch_mixer}, + .mixers = { alc883_targa_2ch_mixer}, .init_verbs = { alc883_init_verbs, alc883_haier_w66_verbs}, .num_dacs = ARRAY_SIZE(alc883_dac_nids), .dac_nids = alc883_dac_nids, @@ -9003,8 +9433,8 @@ static struct alc_config_preset alc883_presets[] = { .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_capture_source, - .unsol_event = alc883_haier_w66_unsol_event, - .init_hook = alc883_haier_w66_automute, + .unsol_event = alc_automute_amp_unsol_event, + .init_hook = alc883_haier_w66_init_hook, }, [ALC888_3ST_HP] = { .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, @@ -9015,8 +9445,8 @@ static struct alc_config_preset alc883_presets[] = { .channel_mode = alc888_3st_hp_modes, .need_dac_fix = 1, .input_mux = &alc883_capture_source, - .unsol_event = alc888_3st_hp_unsol_event, - .init_hook = alc888_3st_hp_front_automute, + .unsol_event = alc_automute_amp_unsol_event, + .init_hook = alc888_3st_hp_init_hook, }, [ALC888_6ST_DELL] = { .mixers = { alc883_base_mixer, alc883_chmode_mixer }, @@ -9028,8 +9458,8 @@ static struct alc_config_preset alc883_presets[] = { .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes), .channel_mode = alc883_sixstack_modes, .input_mux = &alc883_capture_source, - .unsol_event = alc888_6st_dell_unsol_event, - .init_hook = alc888_6st_dell_front_automute, + .unsol_event = alc_automute_amp_unsol_event, + .init_hook = alc888_6st_dell_init_hook, }, [ALC883_MITAC] = { .mixers = { alc883_mitac_mixer }, @@ -9039,8 +9469,8 @@ static struct alc_config_preset alc883_presets[] = { .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_capture_source, - .unsol_event = alc883_mitac_unsol_event, - .init_hook = alc883_mitac_automute, + .unsol_event = alc_automute_amp_unsol_event, + .init_hook = alc883_mitac_init_hook, }, [ALC883_FUJITSU_PI2515] = { .mixers = { alc883_2ch_fujitsu_pi2515_mixer }, @@ -9052,8 +9482,8 @@ static struct alc_config_preset alc883_presets[] = { .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_fujitsu_pi2515_capture_source, - .unsol_event = alc883_2ch_fujitsu_pi2515_unsol_event, - .init_hook = alc883_2ch_fujitsu_pi2515_automute, + .unsol_event = alc_automute_amp_unsol_event, + .init_hook = alc883_2ch_fujitsu_pi2515_init_hook, }, [ALC888_FUJITSU_XA3530] = { .mixers = { alc888_base_mixer, alc883_chmode_mixer }, @@ -9070,8 +9500,8 @@ static struct alc_config_preset alc883_presets[] = { .num_mux_defs = ARRAY_SIZE(alc888_2_capture_sources), .input_mux = alc888_2_capture_sources, - .unsol_event = alc888_fujitsu_xa3530_unsol_event, - .init_hook = alc888_fujitsu_xa3530_automute, + .unsol_event = alc_automute_amp_unsol_event, + .init_hook = alc888_fujitsu_xa3530_init_hook, }, [ALC888_LENOVO_SKY] = { .mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer }, @@ -9083,8 +9513,8 @@ static struct alc_config_preset alc883_presets[] = { .channel_mode = alc883_sixstack_modes, .need_dac_fix = 1, .input_mux = &alc883_lenovo_sky_capture_source, - .unsol_event = alc883_lenovo_sky_unsol_event, - .init_hook = alc888_lenovo_sky_front_automute, + .unsol_event = alc_automute_amp_unsol_event, + .init_hook = alc888_lenovo_sky_init_hook, }, [ALC888_ASUS_M90V] = { .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, @@ -9112,7 +9542,7 @@ static struct alc_config_preset alc883_presets[] = { .channel_mode = alc883_3ST_2ch_modes, .need_dac_fix = 1, .input_mux = &alc883_asus_eee1601_capture_source, - .unsol_event = alc883_eee1601_unsol_event, + .unsol_event = alc_sku_unsol_event, .init_hook = alc883_eee1601_inithook, }, [ALC1200_ASUS_P5Q] = { @@ -9127,6 +9557,32 @@ static struct alc_config_preset alc883_presets[] = { .channel_mode = alc883_sixstack_modes, .input_mux = &alc883_capture_source, }, + [ALC889A_MB31] = { + .mixers = { alc889A_mb31_mixer, alc883_chmode_mixer}, + .init_verbs = { alc883_init_verbs, alc889A_mb31_verbs, + alc880_gpio1_init_verbs }, + .adc_nids = alc883_adc_nids, + .num_adc_nids = ARRAY_SIZE(alc883_adc_nids), + .dac_nids = alc883_dac_nids, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .channel_mode = alc889A_mb31_6ch_modes, + .num_channel_mode = ARRAY_SIZE(alc889A_mb31_6ch_modes), + .input_mux = &alc889A_mb31_capture_source, + .dig_out_nid = ALC883_DIGOUT_NID, + .unsol_event = alc889A_mb31_unsol_event, + .init_hook = alc889A_mb31_automute, + }, + [ALC883_SONY_VAIO_TT] = { + .mixers = { alc883_vaiott_mixer }, + .init_verbs = { alc883_init_verbs, alc883_vaiott_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), + .channel_mode = alc883_3ST_2ch_modes, + .input_mux = &alc883_capture_source, + .unsol_event = alc_automute_amp_unsol_event, + .init_hook = alc883_vaiott_init_hook, + }, }; @@ -9155,7 +9611,6 @@ static void alc883_auto_init_multi_out(struct hda_codec *codec) struct alc_spec *spec = codec->spec; int i; - alc_subsystem_id(codec, 0x15, 0x1b, 0x14); for (i = 0; i <= HDA_SIDE; i++) { hda_nid_t nid = spec->autocfg.line_out_pins[i]; int pin_type = get_pin_type(spec->autocfg.line_out_type); @@ -9273,10 +9728,18 @@ static int patch_alc883(struct hda_codec *codec) board_config = snd_hda_check_board_config(codec, ALC883_MODEL_LAST, alc883_models, alc883_cfg_tbl); - if (board_config < 0) { - printk(KERN_INFO "hda_codec: Unknown model for ALC883, " - "trying auto-probe from BIOS...\n"); - board_config = ALC883_AUTO; + if (board_config < 0 || board_config >= ALC883_MODEL_LAST) { + /* Pick up systems that don't supply PCI SSID */ + switch (codec->subsystem_id) { + case 0x106b3600: /* Macbook 3.1 */ + board_config = ALC889A_MB31; + break; + default: + printk(KERN_INFO + "hda_codec: Unknown model for %s, trying " + "auto-probe from BIOS...\n", codec->chip_name); + board_config = ALC883_AUTO; + } } if (board_config == ALC883_AUTO) { @@ -9304,43 +9767,29 @@ static int patch_alc883(struct hda_codec *codec) switch (codec->vendor_id) { case 0x10ec0888: - if (codec->revision_id == 0x100101) { - spec->stream_name_analog = "ALC1200 Analog"; - spec->stream_name_digital = "ALC1200 Digital"; - } else { - spec->stream_name_analog = "ALC888 Analog"; - spec->stream_name_digital = "ALC888 Digital"; - } if (!spec->num_adc_nids) { spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids); spec->adc_nids = alc883_adc_nids; } if (!spec->capsrc_nids) spec->capsrc_nids = alc883_capsrc_nids; - spec->capture_style = CAPT_MIX; /* matrix-style capture */ + spec->init_amp = ALC_INIT_DEFAULT; /* always initialize */ break; case 0x10ec0889: - spec->stream_name_analog = "ALC889 Analog"; - spec->stream_name_digital = "ALC889 Digital"; if (!spec->num_adc_nids) { spec->num_adc_nids = ARRAY_SIZE(alc889_adc_nids); spec->adc_nids = alc889_adc_nids; } if (!spec->capsrc_nids) spec->capsrc_nids = alc889_capsrc_nids; - spec->capture_style = CAPT_1MUX_MIX; /* 1mux/Nmix-style - capture */ break; default: - spec->stream_name_analog = "ALC883 Analog"; - spec->stream_name_digital = "ALC883 Digital"; if (!spec->num_adc_nids) { spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids); spec->adc_nids = alc883_adc_nids; } if (!spec->capsrc_nids) spec->capsrc_nids = alc883_capsrc_nids; - spec->capture_style = CAPT_MIX; /* matrix-style capture */ break; } @@ -9413,24 +9862,6 @@ static struct snd_kcontrol_new alc262_base_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc262_hippo1_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), - /*HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),*/ - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - { } /* end */ -}; - /* update HP, line and mono-out pins according to the master switch */ static void alc262_hp_master_update(struct hda_codec *codec) { @@ -9486,14 +9917,7 @@ static void alc262_hp_wildwest_unsol_event(struct hda_codec *codec, alc262_hp_wildwest_automute(codec); } -static int alc262_hp_master_sw_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - *ucontrol->value.integer.value = spec->master_sw; - return 0; -} +#define alc262_hp_master_sw_get alc260_hp_master_sw_get static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -9509,14 +9933,17 @@ static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol, return 1; } +#define ALC262_HP_MASTER_SWITCH \ + { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = "Master Playback Switch", \ + .info = snd_ctl_boolean_mono_info, \ + .get = alc262_hp_master_sw_get, \ + .put = alc262_hp_master_sw_put, \ + } + static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .info = snd_ctl_boolean_mono_info, - .get = alc262_hp_master_sw_get, - .put = alc262_hp_master_sw_put, - }, + ALC262_HP_MASTER_SWITCH, HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), @@ -9540,13 +9967,7 @@ static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = { }; static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .info = snd_ctl_boolean_mono_info, - .get = alc262_hp_master_sw_get, - .put = alc262_hp_master_sw_put, - }, + ALC262_HP_MASTER_SWITCH, HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), @@ -9573,32 +9994,13 @@ static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = { }; /* mute/unmute internal speaker according to the hp jack and mute state */ -static void alc262_hp_t5735_automute(struct hda_codec *codec, int force) +static void alc262_hp_t5735_init_hook(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - if (force || !spec->sense_updated) { - unsigned int present; - present = snd_hda_codec_read(codec, 0x15, 0, - AC_VERB_GET_PIN_SENSE, 0); - spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0; - spec->sense_updated = 1; - } - snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0, HDA_AMP_MUTE, - spec->jack_present ? HDA_AMP_MUTE : 0); -} - -static void alc262_hp_t5735_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) != ALC880_HP_EVENT) - return; - alc262_hp_t5735_automute(codec, 1); -} - -static void alc262_hp_t5735_init_hook(struct hda_codec *codec) -{ - alc262_hp_t5735_automute(codec, 1); + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x0c; /* HACK: not actually a pin */ + alc_automute_amp(codec); } static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = { @@ -9651,46 +10053,132 @@ static struct hda_input_mux alc262_hp_rp5700_capture_source = { }, }; -/* bind hp and internal speaker mute (with plug check) */ -static int alc262_sony_master_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +/* bind hp and internal speaker mute (with plug check) as master switch */ +static void alc262_hippo_master_update(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + hda_nid_t hp_nid = spec->autocfg.hp_pins[0]; + hda_nid_t line_nid = spec->autocfg.line_out_pins[0]; + hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0]; + unsigned int mute; + + /* HP */ + mute = spec->master_sw ? 0 : HDA_AMP_MUTE; + snd_hda_codec_amp_stereo(codec, hp_nid, HDA_OUTPUT, 0, + HDA_AMP_MUTE, mute); + /* mute internal speaker per jack sense */ + if (spec->jack_present) + mute = HDA_AMP_MUTE; + if (line_nid) + snd_hda_codec_amp_stereo(codec, line_nid, HDA_OUTPUT, 0, + HDA_AMP_MUTE, mute); + if (speaker_nid && speaker_nid != line_nid) + snd_hda_codec_amp_stereo(codec, speaker_nid, HDA_OUTPUT, 0, + HDA_AMP_MUTE, mute); +} + +#define alc262_hippo_master_sw_get alc262_hp_master_sw_get + +static int alc262_hippo_master_sw_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - long *valp = ucontrol->value.integer.value; - int change; + struct alc_spec *spec = codec->spec; + int val = !!*ucontrol->value.integer.value; - /* change hp mute */ - change = snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, - HDA_AMP_MUTE, - valp[0] ? 0 : HDA_AMP_MUTE); - change |= snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, - HDA_AMP_MUTE, - valp[1] ? 0 : HDA_AMP_MUTE); - if (change) { - /* change speaker according to HP jack state */ - struct alc_spec *spec = codec->spec; - unsigned int mute; - if (spec->jack_present) - mute = HDA_AMP_MUTE; - else - mute = snd_hda_codec_amp_read(codec, 0x15, 0, - HDA_OUTPUT, 0); - snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, - HDA_AMP_MUTE, mute); - } - return change; + if (val == spec->master_sw) + return 0; + spec->master_sw = val; + alc262_hippo_master_update(codec); + return 1; } +#define ALC262_HIPPO_MASTER_SWITCH \ + { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = "Master Playback Switch", \ + .info = snd_ctl_boolean_mono_info, \ + .get = alc262_hippo_master_sw_get, \ + .put = alc262_hippo_master_sw_put, \ + } + +static struct snd_kcontrol_new alc262_hippo_mixer[] = { + ALC262_HIPPO_MASTER_SWITCH, + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + { } /* end */ +}; + +static struct snd_kcontrol_new alc262_hippo1_mixer[] = { + HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + ALC262_HIPPO_MASTER_SWITCH, + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), + { } /* end */ +}; + +/* mute/unmute internal speaker according to the hp jack and mute state */ +static void alc262_hippo_automute(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + hda_nid_t hp_nid = spec->autocfg.hp_pins[0]; + unsigned int present; + + /* need to execute and sync at first */ + snd_hda_codec_read(codec, hp_nid, 0, AC_VERB_SET_PIN_SENSE, 0); + present = snd_hda_codec_read(codec, hp_nid, 0, + AC_VERB_GET_PIN_SENSE, 0); + spec->jack_present = (present & 0x80000000) != 0; + alc262_hippo_master_update(codec); +} + +static void alc262_hippo_unsol_event(struct hda_codec *codec, unsigned int res) +{ + if ((res >> 26) != ALC880_HP_EVENT) + return; + alc262_hippo_automute(codec); +} + +static void alc262_hippo_init_hook(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + alc262_hippo_automute(codec); +} + +static void alc262_hippo1_init_hook(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.speaker_pins[0] = 0x14; + alc262_hippo_automute(codec); +} + + static struct snd_kcontrol_new alc262_sony_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .info = snd_hda_mixer_amp_switch_info, - .get = snd_hda_mixer_amp_switch_get, - .put = alc262_sony_master_sw_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT), - }, + ALC262_HIPPO_MASTER_SWITCH, HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), @@ -9699,8 +10187,8 @@ static struct snd_kcontrol_new alc262_sony_mixer[] = { }; static struct snd_kcontrol_new alc262_benq_t31_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + ALC262_HIPPO_MASTER_SWITCH, HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), @@ -9741,34 +10229,15 @@ static struct hda_verb alc262_tyan_verbs[] = { }; /* unsolicited event for HP jack sensing */ -static void alc262_tyan_automute(struct hda_codec *codec) +static void alc262_tyan_init_hook(struct hda_codec *codec) { - unsigned int mute; - unsigned int present; + struct alc_spec *spec = codec->spec; - snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0); - present = snd_hda_codec_read(codec, 0x1b, 0, - AC_VERB_GET_PIN_SENSE, 0); - present = (present & 0x80000000) != 0; - if (present) { - /* mute line output on ATX panel */ - snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, - HDA_AMP_MUTE, HDA_AMP_MUTE); - } else { - /* unmute line output if necessary */ - mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0); - snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, - HDA_AMP_MUTE, mute); - } + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.speaker_pins[0] = 0x15; + alc_automute_amp(codec); } -static void alc262_tyan_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) != ALC880_HP_EVENT) - return; - alc262_tyan_automute(codec); -} #define alc262_capture_mixer alc882_capture_mixer #define alc262_capture_alt_mixer alc882_capture_alt_mixer @@ -9923,99 +10392,25 @@ static void alc262_dmic_automute(struct hda_codec *codec) AC_VERB_SET_CONNECT_SEL, present ? 0x0 : 0x09); } -/* toggle speaker-output according to the hp-jack state */ -static void alc262_toshiba_s06_speaker_automute(struct hda_codec *codec) -{ - unsigned int present; - unsigned char bits; - - present = snd_hda_codec_read(codec, 0x15, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? 0 : PIN_OUT; - snd_hda_codec_write(codec, 0x14, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, bits); -} - - /* unsolicited event for HP jack sensing */ static void alc262_toshiba_s06_unsol_event(struct hda_codec *codec, unsigned int res) { - if ((res >> 26) == ALC880_HP_EVENT) - alc262_toshiba_s06_speaker_automute(codec); if ((res >> 26) == ALC880_MIC_EVENT) alc262_dmic_automute(codec); - + else + alc_sku_unsol_event(codec, res); } static void alc262_toshiba_s06_init_hook(struct hda_codec *codec) -{ - alc262_toshiba_s06_speaker_automute(codec); - alc262_dmic_automute(codec); -} - -/* mute/unmute internal speaker according to the hp jack and mute state */ -static void alc262_hippo_automute(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - unsigned int mute; - unsigned int present; - /* need to execute and sync at first */ - snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0); - present = snd_hda_codec_read(codec, 0x15, 0, - AC_VERB_GET_PIN_SENSE, 0); - spec->jack_present = (present & 0x80000000) != 0; - if (spec->jack_present) { - /* mute internal speaker */ - snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, - HDA_AMP_MUTE, HDA_AMP_MUTE); - } else { - /* unmute internal speaker if necessary */ - mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0); - snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, - HDA_AMP_MUTE, mute); - } -} - -/* unsolicited event for HP jack sensing */ -static void alc262_hippo_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) != ALC880_HP_EVENT) - return; - alc262_hippo_automute(codec); -} - -static void alc262_hippo1_automute(struct hda_codec *codec) -{ - unsigned int mute; - unsigned int present; - - snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0); - present = snd_hda_codec_read(codec, 0x1b, 0, - AC_VERB_GET_PIN_SENSE, 0); - present = (present & 0x80000000) != 0; - if (present) { - /* mute internal speaker */ - snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, - HDA_AMP_MUTE, HDA_AMP_MUTE); - } else { - /* unmute internal speaker if necessary */ - mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0); - snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, - HDA_AMP_MUTE, mute); - } -} - -/* unsolicited event for HP jack sensing */ -static void alc262_hippo1_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) != ALC880_HP_EVENT) - return; - alc262_hippo1_automute(codec); + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + alc_automute_pin(codec); + alc262_dmic_automute(codec); } /* @@ -10285,14 +10680,7 @@ static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = { static struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = { HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .info = snd_hda_mixer_amp_switch_info, - .get = snd_hda_mixer_amp_switch_get, - .put = alc262_sony_master_sw_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT), - }, + ALC262_HIPPO_MASTER_SWITCH, HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), @@ -10513,9 +10901,27 @@ static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec, return 0; } -/* identical with ALC880 */ -#define alc262_auto_create_analog_input_ctls \ - alc880_auto_create_analog_input_ctls +static int alc262_auto_create_analog_input_ctls(struct alc_spec *spec, + const struct auto_pin_cfg *cfg) +{ + int err; + + err = alc880_auto_create_analog_input_ctls(spec, cfg); + if (err < 0) + return err; + /* digital-mic input pin is excluded in alc880_auto_create..() + * because it's under 0x18 + */ + if (cfg->input_pins[AUTO_PIN_MIC] == 0x12 || + cfg->input_pins[AUTO_PIN_FRONT_MIC] == 0x12) { + struct hda_input_mux *imux = &spec->private_imux[0]; + imux->items[imux->num_items].label = "Int Mic"; + imux->items[imux->num_items].index = 0x09; + imux->num_items++; + } + return 0; +} + /* * generic initialization of ADC, input mixers and output mixers @@ -10639,31 +11045,46 @@ static struct hda_verb alc262_HP_BPC_init_verbs[] = { {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, /* FIXME: use matrix-type input source selection */ - /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ - /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ + /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 0b, 12 */ + /* Input mixer1: only unmute Mic */ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))}, /* Input mixer2 */ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))}, /* Input mixer3 */ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))}, {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, @@ -10788,7 +11209,7 @@ static struct hda_verb alc262_toshiba_rx1_unsol_verbs[] = { #define alc262_loopbacks alc880_loopbacks #endif -/* pcm configuration: identiacal with ALC880 */ +/* pcm configuration: identical with ALC880 */ #define alc262_pcm_analog_playback alc880_pcm_analog_playback #define alc262_pcm_analog_capture alc880_pcm_analog_capture #define alc262_pcm_digital_playback alc880_pcm_digital_playback @@ -10843,6 +11264,8 @@ static int alc262_parse_auto_config(struct hda_codec *codec) if (err < 0) return err; + alc_ssid_check(codec, 0x15, 0x14, 0x1b); + return 1; } @@ -10915,6 +11338,7 @@ static struct snd_pci_quirk alc262_cfg_tbl[] = { SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO), SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD), SND_PCI_QUIRK(0x104d, 0x9016, "Sony VAIO", ALC262_AUTO), /* dig-only */ + SND_PCI_QUIRK(0x104d, 0x9025, "Sony VAIO Z21MN", ALC262_TOSHIBA_S06), SND_PCI_QUIRK_MASK(0x104d, 0xff00, 0x9000, "Sony VAIO", ALC262_SONY_ASSAMD), SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1", @@ -10945,7 +11369,7 @@ static struct alc_config_preset alc262_presets[] = { .input_mux = &alc262_capture_source, }, [ALC262_HIPPO] = { - .mixers = { alc262_base_mixer }, + .mixers = { alc262_hippo_mixer }, .init_verbs = { alc262_init_verbs, alc262_hippo_unsol_verbs}, .num_dacs = ARRAY_SIZE(alc262_dac_nids), .dac_nids = alc262_dac_nids, @@ -10955,7 +11379,7 @@ static struct alc_config_preset alc262_presets[] = { .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, .unsol_event = alc262_hippo_unsol_event, - .init_hook = alc262_hippo_automute, + .init_hook = alc262_hippo_init_hook, }, [ALC262_HIPPO_1] = { .mixers = { alc262_hippo1_mixer }, @@ -10967,8 +11391,8 @@ static struct alc_config_preset alc262_presets[] = { .num_channel_mode = ARRAY_SIZE(alc262_modes), .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, - .unsol_event = alc262_hippo1_unsol_event, - .init_hook = alc262_hippo1_automute, + .unsol_event = alc262_hippo_unsol_event, + .init_hook = alc262_hippo1_init_hook, }, [ALC262_FUJITSU] = { .mixers = { alc262_fujitsu_mixer }, @@ -11030,7 +11454,7 @@ static struct alc_config_preset alc262_presets[] = { .num_channel_mode = ARRAY_SIZE(alc262_modes), .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, - .unsol_event = alc262_hp_t5735_unsol_event, + .unsol_event = alc_automute_amp_unsol_event, .init_hook = alc262_hp_t5735_init_hook, }, [ALC262_HP_RP5700] = { @@ -11062,7 +11486,7 @@ static struct alc_config_preset alc262_presets[] = { .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, .unsol_event = alc262_hippo_unsol_event, - .init_hook = alc262_hippo_automute, + .init_hook = alc262_hippo_init_hook, }, [ALC262_BENQ_T31] = { .mixers = { alc262_benq_t31_mixer }, @@ -11074,7 +11498,7 @@ static struct alc_config_preset alc262_presets[] = { .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, .unsol_event = alc262_hippo_unsol_event, - .init_hook = alc262_hippo_automute, + .init_hook = alc262_hippo_init_hook, }, [ALC262_ULTRA] = { .mixers = { alc262_ultra_mixer }, @@ -11122,6 +11546,7 @@ static struct alc_config_preset alc262_presets[] = { .capsrc_nids = alc262_dmic_capsrc_nids, .dac_nids = alc262_dac_nids, .adc_nids = alc262_dmic_adc_nids, /* ADC0 */ + .num_adc_nids = 1, /* single ADC */ .dig_out_nid = ALC262_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc262_modes), .channel_mode = alc262_modes, @@ -11139,7 +11564,7 @@ static struct alc_config_preset alc262_presets[] = { .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, .unsol_event = alc262_hippo_unsol_event, - .init_hook = alc262_hippo_automute, + .init_hook = alc262_hippo_init_hook, }, [ALC262_TYAN] = { .mixers = { alc262_tyan_mixer }, @@ -11151,8 +11576,8 @@ static struct alc_config_preset alc262_presets[] = { .num_channel_mode = ARRAY_SIZE(alc262_modes), .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, - .unsol_event = alc262_tyan_unsol_event, - .init_hook = alc262_tyan_automute, + .unsol_event = alc_automute_amp_unsol_event, + .init_hook = alc262_tyan_init_hook, }, }; @@ -11187,8 +11612,8 @@ static int patch_alc262(struct hda_codec *codec) alc262_cfg_tbl); if (board_config < 0) { - printk(KERN_INFO "hda_codec: Unknown model for ALC262, " - "trying auto-probe from BIOS...\n"); + printk(KERN_INFO "hda_codec: Unknown model for %s, " + "trying auto-probe from BIOS...\n", codec->chip_name); board_config = ALC262_AUTO; } @@ -11217,29 +11642,42 @@ static int patch_alc262(struct hda_codec *codec) if (board_config != ALC262_AUTO) setup_preset(spec, &alc262_presets[board_config]); - spec->stream_name_analog = "ALC262 Analog"; spec->stream_analog_playback = &alc262_pcm_analog_playback; spec->stream_analog_capture = &alc262_pcm_analog_capture; - spec->stream_name_digital = "ALC262 Digital"; spec->stream_digital_playback = &alc262_pcm_digital_playback; spec->stream_digital_capture = &alc262_pcm_digital_capture; - spec->capture_style = CAPT_MIX; if (!spec->adc_nids && spec->input_mux) { - /* check whether NID 0x07 is valid */ - unsigned int wcap = get_wcaps(codec, 0x07); - - /* get type */ - wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; - if (wcap != AC_WID_AUD_IN) { - spec->adc_nids = alc262_adc_nids_alt; - spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids_alt); - spec->capsrc_nids = alc262_capsrc_nids_alt; + int i; + /* check whether the digital-mic has to be supported */ + for (i = 0; i < spec->input_mux->num_items; i++) { + if (spec->input_mux->items[i].index >= 9) + break; + } + if (i < spec->input_mux->num_items) { + /* use only ADC0 */ + spec->adc_nids = alc262_dmic_adc_nids; + spec->num_adc_nids = 1; + spec->capsrc_nids = alc262_dmic_capsrc_nids; } else { - spec->adc_nids = alc262_adc_nids; - spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids); - spec->capsrc_nids = alc262_capsrc_nids; + /* all analog inputs */ + /* check whether NID 0x07 is valid */ + unsigned int wcap = get_wcaps(codec, 0x07); + + /* get type */ + wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; + if (wcap != AC_WID_AUD_IN) { + spec->adc_nids = alc262_adc_nids_alt; + spec->num_adc_nids = + ARRAY_SIZE(alc262_adc_nids_alt); + spec->capsrc_nids = alc262_capsrc_nids_alt; + } else { + spec->adc_nids = alc262_adc_nids; + spec->num_adc_nids = + ARRAY_SIZE(alc262_adc_nids); + spec->capsrc_nids = alc262_capsrc_nids; + } } } if (!spec->cap_mixer && !spec->no_analog) @@ -11296,6 +11734,17 @@ static struct snd_kcontrol_new alc268_base_mixer[] = { { } }; +static struct snd_kcontrol_new alc268_toshiba_mixer[] = { + /* output mixer control */ + HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT), + ALC262_HIPPO_MASTER_SWITCH, + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT), + { } +}; + /* bind Beep switches of both NID 0x0f and 0x10 */ static struct hda_bind_ctls alc268_bind_beep_sw = { .ops = &snd_hda_bind_sw, @@ -11319,8 +11768,6 @@ static struct hda_verb alc268_eapd_verbs[] = { }; /* Toshiba specific */ -#define alc268_toshiba_automute alc262_hippo_automute - static struct hda_verb alc268_toshiba_verbs[] = { {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, { } /* end */ @@ -11456,13 +11903,8 @@ static struct hda_verb alc268_acer_verbs[] = { }; /* unsolicited event for HP jack sensing */ -static void alc268_toshiba_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) != ALC880_HP_EVENT) - return; - alc268_toshiba_automute(codec); -} +#define alc268_toshiba_unsol_event alc262_hippo_unsol_event +#define alc268_toshiba_init_hook alc262_hippo_init_hook static void alc268_acer_unsol_event(struct hda_codec *codec, unsigned int res) @@ -11537,30 +11979,15 @@ static struct hda_verb alc268_dell_verbs[] = { }; /* mute/unmute internal speaker according to the hp jack and mute state */ -static void alc268_dell_automute(struct hda_codec *codec) +static void alc268_dell_init_hook(struct hda_codec *codec) { - unsigned int present; - unsigned int mute; + struct alc_spec *spec = codec->spec; - present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0); - if (present & 0x80000000) - mute = HDA_AMP_MUTE; - else - mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0); - snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, - HDA_AMP_MUTE, mute); + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + alc_automute_pin(codec); } -static void alc268_dell_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) != ALC880_HP_EVENT) - return; - alc268_dell_automute(codec); -} - -#define alc268_dell_init_hook alc268_dell_automute - static struct snd_kcontrol_new alc267_quanta_il1_mixer[] = { HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), @@ -11579,16 +12006,6 @@ static struct hda_verb alc267_quanta_il1_verbs[] = { { } }; -static void alc267_quanta_il1_hp_automute(struct hda_codec *codec) -{ - unsigned int present; - - present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0) - & AC_PINSENSE_PRESENCE; - snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, - present ? 0 : PIN_OUT); -} - static void alc267_quanta_il1_mic_automute(struct hda_codec *codec) { unsigned int present; @@ -11600,9 +12017,13 @@ static void alc267_quanta_il1_mic_automute(struct hda_codec *codec) present ? 0x00 : 0x01); } -static void alc267_quanta_il1_automute(struct hda_codec *codec) +static void alc267_quanta_il1_init_hook(struct hda_codec *codec) { - alc267_quanta_il1_hp_automute(codec); + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + alc_automute_pin(codec); alc267_quanta_il1_mic_automute(codec); } @@ -11610,12 +12031,12 @@ static void alc267_quanta_il1_unsol_event(struct hda_codec *codec, unsigned int res) { switch (res >> 26) { - case ALC880_HP_EVENT: - alc267_quanta_il1_hp_automute(codec); - break; case ALC880_MIC_EVENT: alc267_quanta_il1_mic_automute(codec); break; + default: + alc_sku_unsol_event(codec, res); + break; } } @@ -11960,7 +12381,7 @@ static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec) AC_VERB_SET_AMP_GAIN_MUTE, dac_vol2); } -/* pcm configuration: identiacal with ALC880 */ +/* pcm configuration: identical with ALC880 */ #define alc268_pcm_analog_playback alc880_pcm_analog_playback #define alc268_pcm_analog_capture alc880_pcm_analog_capture #define alc268_pcm_analog_alt_capture alc880_pcm_analog_alt_capture @@ -12063,16 +12484,16 @@ static struct snd_pci_quirk alc268_cfg_tbl[] = { ALC268_ACER_ASPIRE_ONE), SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL), SND_PCI_QUIRK(0x1028, 0x02b0, "Dell Inspiron Mini9", ALC268_DELL), - SND_PCI_QUIRK(0x103c, 0x30cc, "TOSHIBA", ALC268_TOSHIBA), - SND_PCI_QUIRK(0x103c, 0x30f1, "HP TX25xx series", ALC268_TOSHIBA), + SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP TX25xx series", + ALC268_TOSHIBA), SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST), - SND_PCI_QUIRK(0x1179, 0xff10, "TOSHIBA A205", ALC268_TOSHIBA), - SND_PCI_QUIRK(0x1179, 0xff50, "TOSHIBA A305", ALC268_TOSHIBA), - SND_PCI_QUIRK(0x1179, 0xff64, "TOSHIBA L305", ALC268_TOSHIBA), + SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO), + SND_PCI_QUIRK_MASK(0x1179, 0xff00, 0xff00, "TOSHIBA A/Lx05", + ALC268_TOSHIBA), SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA), SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER), SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1), - SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO), + SND_PCI_QUIRK(0x1854, 0x1775, "LG R510", ALC268_DELL), {} }; @@ -12090,7 +12511,7 @@ static struct alc_config_preset alc268_presets[] = { .channel_mode = alc268_modes, .input_mux = &alc268_capture_source, .unsol_event = alc267_quanta_il1_unsol_event, - .init_hook = alc267_quanta_il1_automute, + .init_hook = alc267_quanta_il1_init_hook, }, [ALC268_3ST] = { .mixers = { alc268_base_mixer, alc268_capture_alt_mixer, @@ -12108,7 +12529,7 @@ static struct alc_config_preset alc268_presets[] = { .input_mux = &alc268_capture_source, }, [ALC268_TOSHIBA] = { - .mixers = { alc268_base_mixer, alc268_capture_alt_mixer, + .mixers = { alc268_toshiba_mixer, alc268_capture_alt_mixer, alc268_beep_mixer }, .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, alc268_toshiba_verbs }, @@ -12122,7 +12543,7 @@ static struct alc_config_preset alc268_presets[] = { .channel_mode = alc268_modes, .input_mux = &alc268_capture_source, .unsol_event = alc268_toshiba_unsol_event, - .init_hook = alc268_toshiba_automute, + .init_hook = alc268_toshiba_init_hook, }, [ALC268_ACER] = { .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer, @@ -12185,7 +12606,7 @@ static struct alc_config_preset alc268_presets[] = { .hp_nid = 0x02, .num_channel_mode = ARRAY_SIZE(alc268_modes), .channel_mode = alc268_modes, - .unsol_event = alc268_dell_unsol_event, + .unsol_event = alc_sku_unsol_event, .init_hook = alc268_dell_init_hook, .input_mux = &alc268_capture_source, }, @@ -12205,7 +12626,7 @@ static struct alc_config_preset alc268_presets[] = { .channel_mode = alc268_modes, .input_mux = &alc268_capture_source, .unsol_event = alc268_toshiba_unsol_event, - .init_hook = alc268_toshiba_automute + .init_hook = alc268_toshiba_init_hook }, #ifdef CONFIG_SND_DEBUG [ALC268_TEST] = { @@ -12243,8 +12664,8 @@ static int patch_alc268(struct hda_codec *codec) alc268_cfg_tbl); if (board_config < 0 || board_config >= ALC268_MODEL_LAST) { - printk(KERN_INFO "hda_codec: Unknown model for ALC268, " - "trying auto-probe from BIOS...\n"); + printk(KERN_INFO "hda_codec: Unknown model for %s, " + "trying auto-probe from BIOS...\n", codec->chip_name); board_config = ALC268_AUTO; } @@ -12265,14 +12686,6 @@ static int patch_alc268(struct hda_codec *codec) if (board_config != ALC268_AUTO) setup_preset(spec, &alc268_presets[board_config]); - if (codec->vendor_id == 0x10ec0267) { - spec->stream_name_analog = "ALC267 Analog"; - spec->stream_name_digital = "ALC267 Digital"; - } else { - spec->stream_name_analog = "ALC268 Analog"; - spec->stream_name_digital = "ALC268 Digital"; - } - spec->stream_analog_playback = &alc268_pcm_analog_playback; spec->stream_analog_capture = &alc268_pcm_analog_capture; spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture; @@ -12854,32 +13267,14 @@ static int alc269_auto_create_multi_out_ctls(struct alc_spec *spec, return 0; } -static int alc269_auto_create_analog_input_ctls(struct alc_spec *spec, - const struct auto_pin_cfg *cfg) -{ - int err; - - err = alc880_auto_create_analog_input_ctls(spec, cfg); - if (err < 0) - return err; - /* digital-mic input pin is excluded in alc880_auto_create..() - * because it's under 0x18 - */ - if (cfg->input_pins[AUTO_PIN_MIC] == 0x12 || - cfg->input_pins[AUTO_PIN_FRONT_MIC] == 0x12) { - struct hda_input_mux *imux = &spec->private_imux[0]; - imux->items[imux->num_items].label = "Int Mic"; - imux->items[imux->num_items].index = 0x05; - imux->num_items++; - } - return 0; -} +#define alc269_auto_create_analog_input_ctls \ + alc262_auto_create_analog_input_ctls #ifdef CONFIG_SND_HDA_POWER_SAVE #define alc269_loopbacks alc880_loopbacks #endif -/* pcm configuration: identiacal with ALC880 */ +/* pcm configuration: identical with ALC880 */ #define alc269_pcm_analog_playback alc880_pcm_analog_playback #define alc269_pcm_analog_capture alc880_pcm_analog_capture #define alc269_pcm_digital_playback alc880_pcm_digital_playback @@ -13099,8 +13494,8 @@ static int patch_alc269(struct hda_codec *codec) alc269_cfg_tbl); if (board_config < 0) { - printk(KERN_INFO "hda_codec: Unknown model for ALC269, " - "trying auto-probe from BIOS...\n"); + printk(KERN_INFO "hda_codec: Unknown model for %s, " + "trying auto-probe from BIOS...\n", codec->chip_name); board_config = ALC269_AUTO; } @@ -13127,7 +13522,6 @@ static int patch_alc269(struct hda_codec *codec) if (board_config != ALC269_AUTO) setup_preset(spec, &alc269_presets[board_config]); - spec->stream_name_analog = "ALC269 Analog"; if (codec->subsystem_id == 0x17aa3bf8) { /* Due to a hardware problem on Lenovo Ideadpad, we need to * fix the sample rate of analog I/O to 44.1kHz @@ -13138,7 +13532,6 @@ static int patch_alc269(struct hda_codec *codec) spec->stream_analog_playback = &alc269_pcm_analog_playback; spec->stream_analog_capture = &alc269_pcm_analog_capture; } - spec->stream_name_digital = "ALC269 Digital"; spec->stream_digital_playback = &alc269_pcm_digital_playback; spec->stream_digital_capture = &alc269_pcm_digital_capture; @@ -13743,7 +14136,7 @@ static void alc861_toshiba_unsol_event(struct hda_codec *codec, alc861_toshiba_automute(codec); } -/* pcm configuration: identiacal with ALC880 */ +/* pcm configuration: identical with ALC880 */ #define alc861_pcm_analog_playback alc880_pcm_analog_playback #define alc861_pcm_analog_capture alc880_pcm_analog_capture #define alc861_pcm_digital_playback alc880_pcm_digital_playback @@ -13927,7 +14320,6 @@ static void alc861_auto_init_multi_out(struct hda_codec *codec) struct alc_spec *spec = codec->spec; int i; - alc_subsystem_id(codec, 0x0e, 0x0f, 0x0b); for (i = 0; i < spec->autocfg.line_outs; i++) { hda_nid_t nid = spec->autocfg.line_out_pins[i]; int pin_type = get_pin_type(spec->autocfg.line_out_type); @@ -14010,6 +14402,8 @@ static int alc861_parse_auto_config(struct hda_codec *codec) spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids); set_capture_mixer(spec); + alc_ssid_check(codec, 0x0e, 0x0f, 0x0b); + return 1; } @@ -14199,8 +14593,8 @@ static int patch_alc861(struct hda_codec *codec) alc861_cfg_tbl); if (board_config < 0) { - printk(KERN_INFO "hda_codec: Unknown model for ALC861, " - "trying auto-probe from BIOS...\n"); + printk(KERN_INFO "hda_codec: Unknown model for %s, " + "trying auto-probe from BIOS...\n", codec->chip_name); board_config = ALC861_AUTO; } @@ -14227,11 +14621,9 @@ static int patch_alc861(struct hda_codec *codec) if (board_config != ALC861_AUTO) setup_preset(spec, &alc861_presets[board_config]); - spec->stream_name_analog = "ALC861 Analog"; spec->stream_analog_playback = &alc861_pcm_analog_playback; spec->stream_analog_capture = &alc861_pcm_analog_capture; - spec->stream_name_digital = "ALC861 Digital"; spec->stream_digital_playback = &alc861_pcm_digital_playback; spec->stream_digital_capture = &alc861_pcm_digital_capture; @@ -14267,7 +14659,7 @@ static hda_nid_t alc861vd_dac_nids[4] = { /* dac_nids for ALC660vd are in a different order - according to * Realtek's driver. - * This should probably tesult in a different mixer for 6stack models + * This should probably result in a different mixer for 6stack models * of ALC660vd codecs, but for now there is only 3stack mixer * - and it is the same as in 861vd. * adc_nids in ALC660vd are (is) the same as in 861vd @@ -14618,19 +15010,6 @@ static struct hda_verb alc861vd_lenovo_unsol_verbs[] = { {} }; -/* toggle speaker-output according to the hp-jack state */ -static void alc861vd_lenovo_hp_automute(struct hda_codec *codec) -{ - unsigned int present; - unsigned char bits; - - present = snd_hda_codec_read(codec, 0x1b, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? HDA_AMP_MUTE : 0; - snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); -} - static void alc861vd_lenovo_mic_automute(struct hda_codec *codec) { unsigned int present; @@ -14643,9 +15022,13 @@ static void alc861vd_lenovo_mic_automute(struct hda_codec *codec) HDA_AMP_MUTE, bits); } -static void alc861vd_lenovo_automute(struct hda_codec *codec) +static void alc861vd_lenovo_init_hook(struct hda_codec *codec) { - alc861vd_lenovo_hp_automute(codec); + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x1b; + spec->autocfg.speaker_pins[0] = 0x14; + alc_automute_amp(codec); alc861vd_lenovo_mic_automute(codec); } @@ -14653,12 +15036,12 @@ static void alc861vd_lenovo_unsol_event(struct hda_codec *codec, unsigned int res) { switch (res >> 26) { - case ALC880_HP_EVENT: - alc861vd_lenovo_hp_automute(codec); - break; case ALC880_MIC_EVENT: alc861vd_lenovo_mic_automute(codec); break; + default: + alc_automute_amp_unsol_event(codec, res); + break; } } @@ -14708,27 +15091,20 @@ static struct hda_verb alc861vd_dallas_verbs[] = { }; /* toggle speaker-output according to the hp-jack state */ -static void alc861vd_dallas_automute(struct hda_codec *codec) +static void alc861vd_dallas_init_hook(struct hda_codec *codec) { - unsigned int present; + struct alc_spec *spec = codec->spec; - present = snd_hda_codec_read(codec, 0x15, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, - HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); -} - -static void alc861vd_dallas_unsol_event(struct hda_codec *codec, unsigned int res) -{ - if ((res >> 26) == ALC880_HP_EVENT) - alc861vd_dallas_automute(codec); + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + alc_automute_amp(codec); } #ifdef CONFIG_SND_HDA_POWER_SAVE #define alc861vd_loopbacks alc880_loopbacks #endif -/* pcm configuration: identiacal with ALC880 */ +/* pcm configuration: identical with ALC880 */ #define alc861vd_pcm_analog_playback alc880_pcm_analog_playback #define alc861vd_pcm_analog_capture alc880_pcm_analog_capture #define alc861vd_pcm_digital_playback alc880_pcm_digital_playback @@ -14835,7 +15211,7 @@ static struct alc_config_preset alc861vd_presets[] = { .channel_mode = alc861vd_3stack_2ch_modes, .input_mux = &alc861vd_capture_source, .unsol_event = alc861vd_lenovo_unsol_event, - .init_hook = alc861vd_lenovo_automute, + .init_hook = alc861vd_lenovo_init_hook, }, [ALC861VD_DALLAS] = { .mixers = { alc861vd_dallas_mixer }, @@ -14845,8 +15221,8 @@ static struct alc_config_preset alc861vd_presets[] = { .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), .channel_mode = alc861vd_3stack_2ch_modes, .input_mux = &alc861vd_dallas_capture_source, - .unsol_event = alc861vd_dallas_unsol_event, - .init_hook = alc861vd_dallas_automute, + .unsol_event = alc_automute_amp_unsol_event, + .init_hook = alc861vd_dallas_init_hook, }, [ALC861VD_HP] = { .mixers = { alc861vd_hp_mixer }, @@ -14857,8 +15233,8 @@ static struct alc_config_preset alc861vd_presets[] = { .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), .channel_mode = alc861vd_3stack_2ch_modes, .input_mux = &alc861vd_hp_capture_source, - .unsol_event = alc861vd_dallas_unsol_event, - .init_hook = alc861vd_dallas_automute, + .unsol_event = alc_automute_amp_unsol_event, + .init_hook = alc861vd_dallas_init_hook, }, [ALC660VD_ASUS_V1S] = { .mixers = { alc861vd_lenovo_mixer }, @@ -14873,7 +15249,7 @@ static struct alc_config_preset alc861vd_presets[] = { .channel_mode = alc861vd_3stack_2ch_modes, .input_mux = &alc861vd_capture_source, .unsol_event = alc861vd_lenovo_unsol_event, - .init_hook = alc861vd_lenovo_automute, + .init_hook = alc861vd_lenovo_init_hook, }, }; @@ -14891,7 +15267,6 @@ static void alc861vd_auto_init_multi_out(struct hda_codec *codec) struct alc_spec *spec = codec->spec; int i; - alc_subsystem_id(codec, 0x15, 0x1b, 0x14); for (i = 0; i <= HDA_SIDE; i++) { hda_nid_t nid = spec->autocfg.line_out_pins[i]; int pin_type = get_pin_type(spec->autocfg.line_out_type); @@ -14908,7 +15283,7 @@ static void alc861vd_auto_init_hp_out(struct hda_codec *codec) hda_nid_t pin; pin = spec->autocfg.hp_pins[0]; - if (pin) /* connect to front and use dac 0 */ + if (pin) /* connect to front and use dac 0 */ alc861vd_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); pin = spec->autocfg.speaker_pins[0]; if (pin) @@ -15109,6 +15484,8 @@ static int alc861vd_parse_auto_config(struct hda_codec *codec) if (err < 0) return err; + alc_ssid_check(codec, 0x15, 0x1b, 0x14); + return 1; } @@ -15140,8 +15517,8 @@ static int patch_alc861vd(struct hda_codec *codec) alc861vd_cfg_tbl); if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) { - printk(KERN_INFO "hda_codec: Unknown model for ALC660VD/" - "ALC861VD, trying auto-probe from BIOS...\n"); + printk(KERN_INFO "hda_codec: Unknown model for %s, " + "trying auto-probe from BIOS...\n", codec->chip_name); board_config = ALC861VD_AUTO; } @@ -15169,13 +15546,8 @@ static int patch_alc861vd(struct hda_codec *codec) setup_preset(spec, &alc861vd_presets[board_config]); if (codec->vendor_id == 0x10ec0660) { - spec->stream_name_analog = "ALC660-VD Analog"; - spec->stream_name_digital = "ALC660-VD Digital"; /* always turn on EAPD */ add_verb(spec, alc660vd_eapd_verbs); - } else { - spec->stream_name_analog = "ALC861VD Analog"; - spec->stream_name_digital = "ALC861VD Digital"; } spec->stream_analog_playback = &alc861vd_pcm_analog_playback; @@ -15187,7 +15559,6 @@ static int patch_alc861vd(struct hda_codec *codec) spec->adc_nids = alc861vd_adc_nids; spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids); spec->capsrc_nids = alc861vd_capsrc_nids; - spec->capture_style = CAPT_MIX; set_capture_mixer(spec); set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); @@ -15289,6 +15660,38 @@ static struct hda_input_mux alc663_m51va_capture_source = { }, }; +#if 1 /* set to 0 for testing other input sources below */ +static struct hda_input_mux alc272_nc10_capture_source = { + .num_items = 2, + .items = { + { "Autoselect Mic", 0x0 }, + { "Internal Mic", 0x1 }, + }, +}; +#else +static struct hda_input_mux alc272_nc10_capture_source = { + .num_items = 16, + .items = { + { "Autoselect Mic", 0x0 }, + { "Internal Mic", 0x1 }, + { "In-0x02", 0x2 }, + { "In-0x03", 0x3 }, + { "In-0x04", 0x4 }, + { "In-0x05", 0x5 }, + { "In-0x06", 0x6 }, + { "In-0x07", 0x7 }, + { "In-0x08", 0x8 }, + { "In-0x09", 0x9 }, + { "In-0x0a", 0x0a }, + { "In-0x0b", 0x0b }, + { "In-0x0c", 0x0c }, + { "In-0x0d", 0x0d }, + { "In-0x0e", 0x0e }, + { "In-0x0f", 0x0f }, + }, +}; +#endif + /* * 2ch mode */ @@ -15428,10 +15831,8 @@ static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = { }; static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = { - HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Line-Out Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT), + ALC262_HIPPO_MASTER_SWITCH, HDA_CODEC_VOLUME("e-Mic Boost", 0x18, 0, HDA_INPUT), HDA_CODEC_VOLUME("e-Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), @@ -15444,15 +15845,11 @@ static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = { }; static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = { - HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Line-Out Playback Switch", 0x14, 0x0, HDA_OUTPUT), + ALC262_HIPPO_MASTER_SWITCH, + HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x03, 2, HDA_INPUT), HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x04, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x04, 2, 2, HDA_INPUT), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), @@ -15960,51 +16357,25 @@ static void alc662_eeepc_mic_automute(struct hda_codec *codec) static void alc662_eeepc_unsol_event(struct hda_codec *codec, unsigned int res) { - if ((res >> 26) == ALC880_HP_EVENT) - alc262_hippo1_automute( codec ); - if ((res >> 26) == ALC880_MIC_EVENT) alc662_eeepc_mic_automute(codec); + else + alc262_hippo_unsol_event(codec, res); } static void alc662_eeepc_inithook(struct hda_codec *codec) { - alc262_hippo1_automute( codec ); + alc262_hippo1_init_hook(codec); alc662_eeepc_mic_automute(codec); } -static void alc662_eeepc_ep20_automute(struct hda_codec *codec) -{ - unsigned int mute; - unsigned int present; - - snd_hda_codec_read(codec, 0x14, 0, AC_VERB_SET_PIN_SENSE, 0); - present = snd_hda_codec_read(codec, 0x14, 0, - AC_VERB_GET_PIN_SENSE, 0); - present = (present & 0x80000000) != 0; - if (present) { - /* mute internal speaker */ - snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0, - HDA_AMP_MUTE, HDA_AMP_MUTE); - } else { - /* unmute internal speaker if necessary */ - mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0); - snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0, - HDA_AMP_MUTE, mute); - } -} - -/* unsolicited event for HP jack sensing */ -static void alc662_eeepc_ep20_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) == ALC880_HP_EVENT) - alc662_eeepc_ep20_automute(codec); -} - static void alc662_eeepc_ep20_inithook(struct hda_codec *codec) { - alc662_eeepc_ep20_automute(codec); + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x14; + spec->autocfg.speaker_pins[0] = 0x1b; + alc262_hippo_master_update(codec); } static void alc663_m51va_speaker_automute(struct hda_codec *codec) @@ -16338,35 +16709,9 @@ static void alc663_g50v_inithook(struct hda_codec *codec) alc662_eeepc_mic_automute(codec); } -/* bind hp and internal speaker mute (with plug check) */ -static int alc662_ecs_master_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - long *valp = ucontrol->value.integer.value; - int change; - - change = snd_hda_codec_amp_update(codec, 0x1b, 0, HDA_OUTPUT, 0, - HDA_AMP_MUTE, - valp[0] ? 0 : HDA_AMP_MUTE); - change |= snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0, - HDA_AMP_MUTE, - valp[1] ? 0 : HDA_AMP_MUTE); - if (change) - alc262_hippo1_automute(codec); - return change; -} - static struct snd_kcontrol_new alc662_ecs_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .info = snd_hda_mixer_amp_switch_info, - .get = snd_hda_mixer_amp_switch_get, - .put = alc662_ecs_master_sw_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT), - }, + ALC262_HIPPO_MASTER_SWITCH, HDA_CODEC_VOLUME("e-Mic/LineIn Boost", 0x18, 0, HDA_INPUT), HDA_CODEC_VOLUME("e-Mic/LineIn Playback Volume", 0x0b, 0x0, HDA_INPUT), @@ -16378,12 +16723,29 @@ static struct snd_kcontrol_new alc662_ecs_mixer[] = { { } /* end */ }; +static struct snd_kcontrol_new alc272_nc10_mixer[] = { + /* Master Playback automatically created from Speaker and Headphone */ + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT), + + HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT), + + HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT), + { } /* end */ +}; + #ifdef CONFIG_SND_HDA_POWER_SAVE #define alc662_loopbacks alc880_loopbacks #endif -/* pcm configuration: identiacal with ALC880 */ +/* pcm configuration: identical with ALC880 */ #define alc662_pcm_analog_playback alc880_pcm_analog_playback #define alc662_pcm_analog_capture alc880_pcm_analog_capture #define alc662_pcm_digital_playback alc880_pcm_digital_playback @@ -16411,6 +16773,9 @@ static const char *alc662_models[ALC662_MODEL_LAST] = { [ALC663_ASUS_MODE4] = "asus-mode4", [ALC663_ASUS_MODE5] = "asus-mode5", [ALC663_ASUS_MODE6] = "asus-mode6", + [ALC272_DELL] = "dell", + [ALC272_DELL_ZM1] = "dell-zm1", + [ALC272_SAMSUNG_NC10] = "samsung-nc10", [ALC662_AUTO] = "auto", }; @@ -16468,6 +16833,7 @@ static struct snd_pci_quirk alc662_cfg_tbl[] = { SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS), SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K", ALC662_3ST_6ch_DIG), + SND_PCI_QUIRK(0x144d, 0xca00, "Samsung NC10", ALC272_SAMSUNG_NC10), SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L", ALC662_3ST_6ch_DIG), SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG), @@ -16558,7 +16924,7 @@ static struct alc_config_preset alc662_presets[] = { .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes), .channel_mode = alc662_3ST_6ch_modes, .input_mux = &alc662_lenovo_101e_capture_source, - .unsol_event = alc662_eeepc_ep20_unsol_event, + .unsol_event = alc662_eeepc_unsol_event, .init_hook = alc662_eeepc_ep20_inithook, }, [ALC662_ECS] = { @@ -16739,6 +17105,18 @@ static struct alc_config_preset alc662_presets[] = { .unsol_event = alc663_m51va_unsol_event, .init_hook = alc663_m51va_inithook, }, + [ALC272_SAMSUNG_NC10] = { + .mixers = { alc272_nc10_mixer }, + .init_verbs = { alc662_init_verbs, + alc663_21jd_amic_init_verbs }, + .num_dacs = ARRAY_SIZE(alc272_dac_nids), + .dac_nids = alc272_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + .input_mux = &alc272_nc10_capture_source, + .unsol_event = alc663_mode4_unsol_event, + .init_hook = alc663_mode4_inithook, + }, }; @@ -16933,7 +17311,6 @@ static void alc662_auto_init_multi_out(struct hda_codec *codec) struct alc_spec *spec = codec->spec; int i; - alc_subsystem_id(codec, 0x15, 0x1b, 0x14); for (i = 0; i <= HDA_SIDE; i++) { hda_nid_t nid = spec->autocfg.line_out_pins[i]; int pin_type = get_pin_type(spec->autocfg.line_out_type); @@ -17030,6 +17407,8 @@ static int alc662_parse_auto_config(struct hda_codec *codec) if (err < 0) return err; + alc_ssid_check(codec, 0x15, 0x1b, 0x14); + return 1; } @@ -17062,8 +17441,8 @@ static int patch_alc662(struct hda_codec *codec) alc662_models, alc662_cfg_tbl); if (board_config < 0) { - printk(KERN_INFO "hda_codec: Unknown model for ALC662, " - "trying auto-probe from BIOS...\n"); + printk(KERN_INFO "hda_codec: Unknown model for %s, " + "trying auto-probe from BIOS...\n", codec->chip_name); board_config = ALC662_AUTO; } @@ -17090,17 +17469,6 @@ static int patch_alc662(struct hda_codec *codec) if (board_config != ALC662_AUTO) setup_preset(spec, &alc662_presets[board_config]); - if (codec->vendor_id == 0x10ec0663) { - spec->stream_name_analog = "ALC663 Analog"; - spec->stream_name_digital = "ALC663 Digital"; - } else if (codec->vendor_id == 0x10ec0272) { - spec->stream_name_analog = "ALC272 Analog"; - spec->stream_name_digital = "ALC272 Digital"; - } else { - spec->stream_name_analog = "ALC662 Analog"; - spec->stream_name_digital = "ALC662 Digital"; - } - spec->stream_analog_playback = &alc662_pcm_analog_playback; spec->stream_analog_capture = &alc662_pcm_analog_capture; @@ -17110,7 +17478,6 @@ static int patch_alc662(struct hda_codec *codec) spec->adc_nids = alc662_adc_nids; spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids); spec->capsrc_nids = alc662_capsrc_nids; - spec->capture_style = CAPT_MIX; if (!spec->cap_mixer) set_capture_mixer(spec); diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index d2fd8ef6aef8..14f3c3e0f62d 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -100,6 +100,7 @@ enum { STAC_HP_M4, STAC_HP_DV5, STAC_HP_HDX, + STAC_HP_DV4_1222NR, STAC_92HD71BXX_MODELS }; @@ -193,6 +194,7 @@ struct sigmatel_spec { unsigned int gpio_dir; unsigned int gpio_data; unsigned int gpio_mute; + unsigned int gpio_led; /* stream */ unsigned int stream_delay; @@ -634,6 +636,40 @@ static int stac92xx_smux_enum_put(struct snd_kcontrol *kcontrol, return 0; } +static unsigned int stac92xx_vref_set(struct hda_codec *codec, + hda_nid_t nid, unsigned int new_vref) +{ + int error; + unsigned int pincfg; + pincfg = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + + pincfg &= 0xff; + pincfg &= ~(AC_PINCTL_VREFEN | AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN); + pincfg |= new_vref; + + if (new_vref == AC_PINCTL_VREF_HIZ) + pincfg |= AC_PINCTL_OUT_EN; + else + pincfg |= AC_PINCTL_IN_EN; + + error = snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, pincfg); + if (error < 0) + return error; + else + return 1; +} + +static unsigned int stac92xx_vref_get(struct hda_codec *codec, hda_nid_t nid) +{ + unsigned int vref; + vref = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + vref &= AC_PINCTL_VREFEN; + return vref; +} + static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); @@ -995,6 +1031,17 @@ static struct hda_verb stac9205_core_init[] = { .private_value = verb_read | (verb_write << 16), \ } +#define DC_BIAS(xname, idx, nid) \ + { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .index = idx, \ + .info = stac92xx_dc_bias_info, \ + .get = stac92xx_dc_bias_get, \ + .put = stac92xx_dc_bias_put, \ + .private_value = nid, \ + } + static struct snd_kcontrol_new stac9200_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT), HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT), @@ -1543,6 +1590,8 @@ static struct snd_pci_quirk stac9200_cfg_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF), + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xfb30, + "SigmaTel",STAC_9205_REF), SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101, "DFI LanParty", STAC_REF), /* Dell laptops have BIOS problem */ @@ -1837,6 +1886,7 @@ static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = { [STAC_HP_M4] = NULL, [STAC_HP_DV5] = NULL, [STAC_HP_HDX] = NULL, + [STAC_HP_DV4_1222NR] = NULL, }; static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = { @@ -1848,6 +1898,7 @@ static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = { [STAC_HP_M4] = "hp-m4", [STAC_HP_DV5] = "hp-dv5", [STAC_HP_HDX] = "hp-hdx", + [STAC_HP_DV4_1222NR] = "hp-dv4-1222nr", }; static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = { @@ -1856,6 +1907,8 @@ static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = { "DFI LanParty", STAC_92HD71BXX_REF), SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101, "DFI LanParty", STAC_92HD71BXX_REF), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30fb, + "HP dv4-1222nr", STAC_HP_DV4_1222NR), SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x3080, "HP", STAC_HP_DV5), SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x30f0, @@ -2545,7 +2598,8 @@ static int stac92xx_build_pcms(struct hda_codec *codec) return 0; } -static unsigned int stac92xx_get_vref(struct hda_codec *codec, hda_nid_t nid) +static unsigned int stac92xx_get_default_vref(struct hda_codec *codec, + hda_nid_t nid) { unsigned int pincap = snd_hda_query_pin_caps(codec, nid); pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT; @@ -2599,15 +2653,108 @@ static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol, return 1; } -#define stac92xx_io_switch_info snd_ctl_boolean_mono_info +static int stac92xx_dc_bias_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + int i; + static char *texts[] = { + "Mic In", "Line In", "Line Out" + }; + + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct sigmatel_spec *spec = codec->spec; + hda_nid_t nid = kcontrol->private_value; + + if (nid == spec->mic_switch || nid == spec->line_switch) + i = 3; + else + i = 2; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->value.enumerated.items = i; + uinfo->count = 1; + if (uinfo->value.enumerated.item >= i) + uinfo->value.enumerated.item = i-1; + strcpy(uinfo->value.enumerated.name, + texts[uinfo->value.enumerated.item]); + + return 0; +} + +static int stac92xx_dc_bias_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value; + unsigned int vref = stac92xx_vref_get(codec, nid); + + if (vref == stac92xx_get_default_vref(codec, nid)) + ucontrol->value.enumerated.item[0] = 0; + else if (vref == AC_PINCTL_VREF_GRD) + ucontrol->value.enumerated.item[0] = 1; + else if (vref == AC_PINCTL_VREF_HIZ) + ucontrol->value.enumerated.item[0] = 2; + + return 0; +} + +static int stac92xx_dc_bias_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + unsigned int new_vref = 0; + int error; + hda_nid_t nid = kcontrol->private_value; + + if (ucontrol->value.enumerated.item[0] == 0) + new_vref = stac92xx_get_default_vref(codec, nid); + else if (ucontrol->value.enumerated.item[0] == 1) + new_vref = AC_PINCTL_VREF_GRD; + else if (ucontrol->value.enumerated.item[0] == 2) + new_vref = AC_PINCTL_VREF_HIZ; + else + return 0; + + if (new_vref != stac92xx_vref_get(codec, nid)) { + error = stac92xx_vref_set(codec, nid, new_vref); + return error; + } + + return 0; +} + +static int stac92xx_io_switch_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + static char *texts[2]; + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct sigmatel_spec *spec = codec->spec; + + if (kcontrol->private_value == spec->line_switch) + texts[0] = "Line In"; + else + texts[0] = "Mic In"; + texts[1] = "Line Out"; + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->value.enumerated.items = 2; + uinfo->count = 1; + + if (uinfo->value.enumerated.item >= 2) + uinfo->value.enumerated.item = 1; + strcpy(uinfo->value.enumerated.name, + texts[uinfo->value.enumerated.item]); + + return 0; +} static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct sigmatel_spec *spec = codec->spec; - int io_idx = kcontrol-> private_value & 0xff; + hda_nid_t nid = kcontrol->private_value; + int io_idx = (nid == spec->mic_switch) ? 1 : 0; - ucontrol->value.integer.value[0] = spec->io_switch[io_idx]; + ucontrol->value.enumerated.item[0] = spec->io_switch[io_idx]; return 0; } @@ -2615,9 +2762,9 @@ static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct sigmatel_spec *spec = codec->spec; - hda_nid_t nid = kcontrol->private_value >> 8; - int io_idx = kcontrol-> private_value & 0xff; - unsigned short val = !!ucontrol->value.integer.value[0]; + hda_nid_t nid = kcontrol->private_value; + int io_idx = (nid == spec->mic_switch) ? 1 : 0; + unsigned short val = !!ucontrol->value.enumerated.item[0]; spec->io_switch[io_idx] = val; @@ -2626,7 +2773,7 @@ static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ else { unsigned int pinctl = AC_PINCTL_IN_EN; if (io_idx) /* set VREF for mic */ - pinctl |= stac92xx_get_vref(codec, nid); + pinctl |= stac92xx_get_default_vref(codec, nid); stac92xx_auto_set_pinctl(codec, nid, pinctl); } @@ -2707,7 +2854,8 @@ enum { STAC_CTL_WIDGET_AMP_VOL, STAC_CTL_WIDGET_HP_SWITCH, STAC_CTL_WIDGET_IO_SWITCH, - STAC_CTL_WIDGET_CLFE_SWITCH + STAC_CTL_WIDGET_CLFE_SWITCH, + STAC_CTL_WIDGET_DC_BIAS }; static struct snd_kcontrol_new stac92xx_control_templates[] = { @@ -2719,6 +2867,7 @@ static struct snd_kcontrol_new stac92xx_control_templates[] = { STAC_CODEC_HP_SWITCH(NULL), STAC_CODEC_IO_SWITCH(NULL, 0), STAC_CODEC_CLFE_SWITCH(NULL, 0), + DC_BIAS(NULL, 0, 0), }; /* add dynamic controls */ @@ -2782,6 +2931,34 @@ static struct snd_kcontrol_new stac_input_src_temp = { .put = stac92xx_mux_enum_put, }; +static inline int stac92xx_add_jack_mode_control(struct hda_codec *codec, + hda_nid_t nid, int idx) +{ + int def_conf = snd_hda_codec_get_pincfg(codec, nid); + int control = 0; + struct sigmatel_spec *spec = codec->spec; + char name[22]; + + if (!((get_defcfg_connect(def_conf)) & AC_JACK_PORT_FIXED)) { + if (stac92xx_get_default_vref(codec, nid) == AC_PINCTL_VREF_GRD + && nid == spec->line_switch) + control = STAC_CTL_WIDGET_IO_SWITCH; + else if (snd_hda_query_pin_caps(codec, nid) + & (AC_PINCAP_VREF_GRD << AC_PINCAP_VREF_SHIFT)) + control = STAC_CTL_WIDGET_DC_BIAS; + else if (nid == spec->mic_switch) + control = STAC_CTL_WIDGET_IO_SWITCH; + } + + if (control) { + strcpy(name, auto_pin_cfg_labels[idx]); + return stac92xx_add_control(codec->spec, control, + strcat(name, " Jack Mode"), nid); + } + + return 0; +} + static int stac92xx_add_input_source(struct sigmatel_spec *spec) { struct snd_kcontrol_new *knew; @@ -3144,7 +3321,9 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { struct sigmatel_spec *spec = codec->spec; + hda_nid_t nid; int err; + int idx; err = create_multi_out_ctls(codec, cfg->line_outs, cfg->line_out_pins, spec->multiout.dac_nids, @@ -3161,20 +3340,13 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec, return err; } - if (spec->line_switch) { - err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH, - "Line In as Output Switch", - spec->line_switch << 8); - if (err < 0) - return err; - } - - if (spec->mic_switch) { - err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH, - "Mic as Output Switch", - (spec->mic_switch << 8) | 1); - if (err < 0) - return err; + for (idx = AUTO_PIN_MIC; idx <= AUTO_PIN_FRONT_LINE; idx++) { + nid = cfg->input_pins[idx]; + if (nid) { + err = stac92xx_add_jack_mode_control(codec, nid, idx); + if (err < 0) + return err; + } } return 0; @@ -3639,6 +3811,8 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out err = snd_hda_attach_beep_device(codec, nid); if (err < 0) return err; + /* IDT/STAC codecs have linear beep tone parameter */ + codec->beep->linear_tone = 1; /* if no beep switch is available, make its own one */ caps = query_amp_caps(codec, nid, HDA_OUTPUT); if (codec->beep && @@ -3861,7 +4035,7 @@ static void stac_gpio_set(struct hda_codec *codec, unsigned int mask, AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */ } -#ifdef CONFIG_SND_JACK +#ifdef CONFIG_SND_HDA_INPUT_JACK static void stac92xx_free_jack_priv(struct snd_jack *jack) { struct sigmatel_jack *jacks = jack->private_data; @@ -3873,7 +4047,7 @@ static void stac92xx_free_jack_priv(struct snd_jack *jack) static int stac92xx_add_jack(struct hda_codec *codec, hda_nid_t nid, int type) { -#ifdef CONFIG_SND_JACK +#ifdef CONFIG_SND_HDA_INPUT_JACK struct sigmatel_spec *spec = codec->spec; struct sigmatel_jack *jack; int def_conf = snd_hda_codec_get_pincfg(codec, nid); @@ -4082,7 +4256,7 @@ static int stac92xx_init(struct hda_codec *codec) unsigned int pinctl, conf; if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC) { /* for mic pins, force to initialize */ - pinctl = stac92xx_get_vref(codec, nid); + pinctl = stac92xx_get_default_vref(codec, nid); pinctl |= AC_PINCTL_IN_EN; stac92xx_auto_set_pinctl(codec, nid, pinctl); } else { @@ -4162,7 +4336,7 @@ static int stac92xx_init(struct hda_codec *codec) static void stac92xx_free_jacks(struct hda_codec *codec) { -#ifdef CONFIG_SND_JACK +#ifdef CONFIG_SND_HDA_INPUT_JACK /* free jack instances manually when clearing/reconfiguring */ struct sigmatel_spec *spec = codec->spec; if (!codec->bus->shutdown && spec->jacks.list) { @@ -4535,17 +4709,19 @@ static int stac92xx_resume(struct hda_codec *codec) return 0; } - /* - * using power check for controlling mute led of HP HDX notebooks + * using power check for controlling mute led of HP notebooks * check for mute state only on Speakers (nid = 0x10) * * For this feature CONFIG_SND_HDA_POWER_SAVE is needed, otherwise * the LED is NOT working properly ! + * + * Changed name to reflect that it now works for any designated + * model, not just HP HDX. */ #ifdef CONFIG_SND_HDA_POWER_SAVE -static int stac92xx_hp_hdx_check_power_status(struct hda_codec *codec, +static int stac92xx_hp_check_power_status(struct hda_codec *codec, hda_nid_t nid) { struct sigmatel_spec *spec = codec->spec; @@ -4553,9 +4729,9 @@ static int stac92xx_hp_hdx_check_power_status(struct hda_codec *codec, if (nid == 0x10) { if (snd_hda_codec_amp_read(codec, nid, 0, HDA_OUTPUT, 0) & HDA_AMP_MUTE) - spec->gpio_data &= ~0x08; /* orange */ + spec->gpio_data &= ~spec->gpio_led; /* orange */ else - spec->gpio_data |= 0x08; /* white */ + spec->gpio_data |= spec->gpio_led; /* white */ stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, @@ -5201,6 +5377,15 @@ again: if (get_wcaps(codec, 0xa) & AC_WCAP_IN_AMP) snd_hda_sequence_write_cache(codec, unmute_init); + /* Some HP machines seem to have unstable codec communications + * especially with ATI fglrx driver. For recovering from the + * CORB/RIRB stall, allow the BUS reset and keep always sync + */ + if (spec->board_config == STAC_HP_DV5) { + codec->bus->sync_write = 1; + codec->bus->allow_bus_reset = 1; + } + spec->aloopback_ctl = stac92hd71bxx_loopback; spec->aloopback_mask = 0x50; spec->aloopback_shift = 0; @@ -5234,6 +5419,15 @@ again: spec->num_smuxes = 0; spec->num_dmuxes = 1; break; + case STAC_HP_DV4_1222NR: + spec->num_dmics = 1; + /* I don't know if it needs 1 or 2 smuxes - will wait for + * bug reports to fix if needed + */ + spec->num_smuxes = 1; + spec->num_dmuxes = 1; + spec->gpio_led = 0x01; + /* fallthrough */ case STAC_HP_DV5: snd_hda_codec_set_pincfg(codec, 0x0d, 0x90170010); stac92xx_auto_set_pinctl(codec, 0x0d, AC_PINCTL_OUT_EN); @@ -5242,22 +5436,21 @@ again: spec->num_dmics = 1; spec->num_dmuxes = 1; spec->num_smuxes = 1; - /* - * For controlling MUTE LED on HP HDX16/HDX18 notebooks, - * the CONFIG_SND_HDA_POWER_SAVE is needed to be set. - */ -#ifdef CONFIG_SND_HDA_POWER_SAVE /* orange/white mute led on GPIO3, orange=0, white=1 */ - spec->gpio_mask |= 0x08; - spec->gpio_dir |= 0x08; - spec->gpio_data |= 0x08; /* set to white */ + spec->gpio_led = 0x08; + break; + } +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (spec->gpio_led) { + spec->gpio_mask |= spec->gpio_led; + spec->gpio_dir |= spec->gpio_led; + spec->gpio_data |= spec->gpio_led; /* register check_power_status callback. */ codec->patch_ops.check_power_status = - stac92xx_hp_hdx_check_power_status; + stac92xx_hp_check_power_status; + } #endif - break; - }; spec->multiout.dac_nids = spec->dac_nids; if (spec->dinput_mux) @@ -5282,7 +5475,7 @@ again: codec->proc_widget_hook = stac92hd7x_proc_hook; return 0; -}; +} static int patch_stac922x(struct hda_codec *codec) { @@ -5437,7 +5630,7 @@ static int patch_stac927x(struct hda_codec *codec) /* correct the device field to SPDIF out */ snd_hda_codec_set_pincfg(codec, 0x21, 0x01442070); break; - }; + } /* configure the analog microphone on some laptops */ snd_hda_codec_set_pincfg(codec, 0x0c, 0x90a79130); /* correct the front output jack as a hp out */ @@ -5747,6 +5940,7 @@ static struct hda_codec_preset snd_hda_preset_sigmatel[] = { { .id = 0x83847661, .name = "CXD9872RD/K", .patch = patch_stac9872 }, { .id = 0x83847662, .name = "STAC9872AK", .patch = patch_stac9872 }, { .id = 0x83847664, .name = "CXD9872AKD", .patch = patch_stac9872 }, + { .id = 0x83847698, .name = "STAC9205", .patch = patch_stac9205 }, { .id = 0x838476a0, .name = "STAC9205", .patch = patch_stac9205 }, { .id = 0x838476a1, .name = "STAC9205D", .patch = patch_stac9205 }, { .id = 0x838476a2, .name = "STAC9204", .patch = patch_stac9205 }, diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index b25a5cc637d6..8e004fb6961a 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -205,7 +205,7 @@ struct via_spec { /* playback */ struct hda_multi_out multiout; - hda_nid_t extra_dig_out_nid; + hda_nid_t slave_dig_outs[2]; /* capture */ unsigned int num_adc_nids; @@ -731,21 +731,6 @@ static int via_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, return snd_hda_multi_out_dig_close(codec, &spec->multiout); } -/* setup SPDIF output stream */ -static void setup_dig_playback_stream(struct hda_codec *codec, hda_nid_t nid, - unsigned int stream_tag, unsigned int format) -{ - /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */ - if (codec->spdif_ctls & AC_DIG1_ENABLE) - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, - codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff); - snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format); - /* turn on again (if needed) */ - if (codec->spdif_ctls & AC_DIG1_ENABLE) - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, - codec->spdif_ctls & 0xff); -} - static int via_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, struct hda_codec *codec, unsigned int stream_tag, @@ -753,19 +738,16 @@ static int via_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, struct snd_pcm_substream *substream) { struct via_spec *spec = codec->spec; - hda_nid_t nid; + return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, + stream_tag, format, substream); +} - /* 1st or 2nd S/PDIF */ - if (substream->number == 0) - nid = spec->multiout.dig_out_nid; - else if (substream->number == 1) - nid = spec->extra_dig_out_nid; - else - return -1; - - mutex_lock(&codec->spdif_mutex); - setup_dig_playback_stream(codec, nid, stream_tag, format); - mutex_unlock(&codec->spdif_mutex); +static int via_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct via_spec *spec = codec->spec; + snd_hda_multi_out_dig_cleanup(codec, &spec->multiout); return 0; } @@ -842,7 +824,8 @@ static struct hda_pcm_stream vt1708_pcm_digital_playback = { .ops = { .open = via_dig_playback_pcm_open, .close = via_dig_playback_pcm_close, - .prepare = via_dig_playback_pcm_prepare + .prepare = via_dig_playback_pcm_prepare, + .cleanup = via_dig_playback_pcm_cleanup }, }; @@ -874,13 +857,6 @@ static int via_build_controls(struct hda_codec *codec) if (err < 0) return err; spec->multiout.share_spdif = 1; - - if (spec->extra_dig_out_nid) { - err = snd_hda_create_spdif_out_ctls(codec, - spec->extra_dig_out_nid); - if (err < 0) - return err; - } } if (spec->dig_in_nid) { err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); @@ -1013,10 +989,6 @@ static void via_unsol_event(struct hda_codec *codec, via_gpio_control(codec); } -static hda_nid_t slave_dig_outs[] = { - 0, -}; - static int via_init(struct hda_codec *codec) { struct via_spec *spec = codec->spec; @@ -1051,8 +1023,9 @@ static int via_init(struct hda_codec *codec) snd_hda_codec_write(codec, spec->autocfg.dig_in_pin, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN); - /* no slave outs */ - codec->slave_dig_outs = slave_dig_outs; + /* assign slave outs */ + if (spec->slave_dig_outs[0]) + codec->slave_dig_outs = spec->slave_dig_outs; return 0; } @@ -2134,7 +2107,8 @@ static struct hda_pcm_stream vt1708B_pcm_digital_playback = { .ops = { .open = via_dig_playback_pcm_open, .close = via_dig_playback_pcm_close, - .prepare = via_dig_playback_pcm_prepare + .prepare = via_dig_playback_pcm_prepare, + .cleanup = via_dig_playback_pcm_cleanup }, }; @@ -2589,14 +2563,15 @@ static struct hda_pcm_stream vt1708S_pcm_analog_capture = { }; static struct hda_pcm_stream vt1708S_pcm_digital_playback = { - .substreams = 2, + .substreams = 1, .channels_min = 2, .channels_max = 2, /* NID is set in via_build_pcms */ .ops = { .open = via_dig_playback_pcm_open, .close = via_dig_playback_pcm_close, - .prepare = via_dig_playback_pcm_prepare + .prepare = via_dig_playback_pcm_prepare, + .cleanup = via_dig_playback_pcm_cleanup }, }; @@ -2805,14 +2780,37 @@ static int vt1708S_auto_create_analog_input_ctls(struct via_spec *spec, return 0; } +/* fill out digital output widgets; one for master and one for slave outputs */ +static void fill_dig_outs(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + int i; + + for (i = 0; i < spec->autocfg.dig_outs; i++) { + hda_nid_t nid; + int conn; + + nid = spec->autocfg.dig_out_pins[i]; + if (!nid) + continue; + conn = snd_hda_get_connections(codec, nid, &nid, 1); + if (conn < 1) + continue; + if (!spec->multiout.dig_out_nid) + spec->multiout.dig_out_nid = nid; + else { + spec->slave_dig_outs[0] = nid; + break; /* at most two dig outs */ + } + } +} + static int vt1708S_parse_auto_config(struct hda_codec *codec) { struct via_spec *spec = codec->spec; int err; - static hda_nid_t vt1708s_ignore[] = {0x21, 0}; - err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, - vt1708s_ignore); + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); if (err < 0) return err; err = vt1708S_auto_fill_dac_nids(spec, &spec->autocfg); @@ -2833,10 +2831,7 @@ static int vt1708S_parse_auto_config(struct hda_codec *codec) spec->multiout.max_channels = spec->multiout.num_dacs * 2; - if (spec->autocfg.dig_outs) - spec->multiout.dig_out_nid = VT1708S_DIGOUT_NID; - - spec->extra_dig_out_nid = 0x15; + fill_dig_outs(codec); if (spec->kctls.list) spec->mixers[spec->num_mixers++] = spec->kctls.list; @@ -3000,7 +2995,8 @@ static struct hda_pcm_stream vt1702_pcm_digital_playback = { .ops = { .open = via_dig_playback_pcm_open, .close = via_dig_playback_pcm_close, - .prepare = via_dig_playback_pcm_prepare + .prepare = via_dig_playback_pcm_prepare, + .cleanup = via_dig_playback_pcm_cleanup }, }; @@ -3128,10 +3124,8 @@ static int vt1702_parse_auto_config(struct hda_codec *codec) { struct via_spec *spec = codec->spec; int err; - static hda_nid_t vt1702_ignore[] = {0x1C, 0}; - err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, - vt1702_ignore); + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); if (err < 0) return err; err = vt1702_auto_fill_dac_nids(spec, &spec->autocfg); @@ -3152,10 +3146,7 @@ static int vt1702_parse_auto_config(struct hda_codec *codec) spec->multiout.max_channels = spec->multiout.num_dacs * 2; - if (spec->autocfg.dig_outs) - spec->multiout.dig_out_nid = VT1702_DIGOUT_NID; - - spec->extra_dig_out_nid = 0x1B; + fill_dig_outs(codec); if (spec->kctls.list) spec->mixers[spec->num_mixers++] = spec->kctls.list; diff --git a/sound/pci/ice1712/Makefile b/sound/pci/ice1712/Makefile index f99fe089495d..536eae2ccf94 100644 --- a/sound/pci/ice1712/Makefile +++ b/sound/pci/ice1712/Makefile @@ -5,7 +5,7 @@ snd-ice17xx-ak4xxx-objs := ak4xxx.o snd-ice1712-objs := ice1712.o delta.o hoontech.o ews.o -snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o vt1720_mobo.o pontis.o prodigy192.o prodigy_hifi.o juli.o phase.o wtm.o se.o +snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o vt1720_mobo.o pontis.o prodigy192.o prodigy_hifi.o juli.o phase.o wtm.o se.o maya44.o # Toplevel Module Dependency obj-$(CONFIG_SND_ICE1712) += snd-ice1712.o snd-ice17xx-ak4xxx.o diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h index fdae6deba16b..adc909ec125c 100644 --- a/sound/pci/ice1712/ice1712.h +++ b/sound/pci/ice1712/ice1712.h @@ -335,6 +335,7 @@ struct snd_ice1712 { unsigned int force_rdma1:1; /* VT1720/4 - RDMA1 as non-spdif */ unsigned int midi_output:1; /* VT1720/4: MIDI output triggered */ unsigned int midi_input:1; /* VT1720/4: MIDI input triggered */ + unsigned int own_routing:1; /* VT1720/4: use own routing ctls */ unsigned int num_total_dacs; /* total DACs */ unsigned int num_total_adcs; /* total ADCs */ unsigned int cur_rate; /* current rate */ @@ -458,10 +459,17 @@ static inline int snd_ice1712_gpio_read_bits(struct snd_ice1712 *ice, return snd_ice1712_gpio_read(ice) & mask; } +/* route access functions */ +int snd_ice1724_get_route_val(struct snd_ice1712 *ice, int shift); +int snd_ice1724_put_route_val(struct snd_ice1712 *ice, unsigned int val, + int shift); + int snd_ice1712_spdif_build_controls(struct snd_ice1712 *ice); -int snd_ice1712_akm4xxx_init(struct snd_akm4xxx *ak, const struct snd_akm4xxx *template, - const struct snd_ak4xxx_private *priv, struct snd_ice1712 *ice); +int snd_ice1712_akm4xxx_init(struct snd_akm4xxx *ak, + const struct snd_akm4xxx *template, + const struct snd_ak4xxx_private *priv, + struct snd_ice1712 *ice); void snd_ice1712_akm4xxx_free(struct snd_ice1712 *ice); int snd_ice1712_akm4xxx_build_controls(struct snd_ice1712 *ice); diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index 128510e77a78..36ade77cf371 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -49,6 +49,7 @@ #include "prodigy192.h" #include "prodigy_hifi.h" #include "juli.h" +#include "maya44.h" #include "phase.h" #include "wtm.h" #include "se.h" @@ -65,6 +66,7 @@ MODULE_SUPPORTED_DEVICE("{" PRODIGY192_DEVICE_DESC PRODIGY_HIFI_DEVICE_DESC JULI_DEVICE_DESC + MAYA44_DEVICE_DESC PHASE_DEVICE_DESC WTM_DEVICE_DESC SE_DEVICE_DESC @@ -626,7 +628,7 @@ static unsigned char stdclock_set_mclk(struct snd_ice1712 *ice, return 0; } -static void snd_vt1724_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate, +static int snd_vt1724_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate, int force) { unsigned long flags; @@ -634,17 +636,18 @@ static void snd_vt1724_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate, unsigned int i, old_rate; if (rate > ice->hw_rates->list[ice->hw_rates->count - 1]) - return; + return -EINVAL; + spin_lock_irqsave(&ice->reg_lock, flags); if ((inb(ICEMT1724(ice, DMA_CONTROL)) & DMA_STARTS) || (inb(ICEMT1724(ice, DMA_PAUSE)) & DMA_PAUSES)) { /* running? we cannot change the rate now... */ spin_unlock_irqrestore(&ice->reg_lock, flags); - return; + return -EBUSY; } if (!force && is_pro_rate_locked(ice)) { spin_unlock_irqrestore(&ice->reg_lock, flags); - return; + return (rate == ice->cur_rate) ? 0 : -EBUSY; } old_rate = ice->get_rate(ice); @@ -652,7 +655,7 @@ static void snd_vt1724_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate, ice->set_rate(ice, rate); else if (rate == ice->cur_rate) { spin_unlock_irqrestore(&ice->reg_lock, flags); - return; + return 0; } ice->cur_rate = rate; @@ -674,13 +677,15 @@ static void snd_vt1724_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate, } if (ice->spdif.ops.setup_rate) ice->spdif.ops.setup_rate(ice, rate); + + return 0; } static int snd_vt1724_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); - int i, chs; + int i, chs, err; chs = params_channels(hw_params); mutex_lock(&ice->open_mutex); @@ -715,7 +720,11 @@ static int snd_vt1724_pcm_hw_params(struct snd_pcm_substream *substream, } } mutex_unlock(&ice->open_mutex); - snd_vt1724_set_pro_rate(ice, params_rate(hw_params), 0); + + err = snd_vt1724_set_pro_rate(ice, params_rate(hw_params), 0); + if (err < 0) + return err; + return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); } @@ -848,20 +857,39 @@ static snd_pcm_uframes_t snd_vt1724_pcm_pointer(struct snd_pcm_substream *substr #endif } -static const struct vt1724_pcm_reg vt1724_playback_pro_reg = { +static const struct vt1724_pcm_reg vt1724_pdma0_reg = { .addr = VT1724_MT_PLAYBACK_ADDR, .size = VT1724_MT_PLAYBACK_SIZE, .count = VT1724_MT_PLAYBACK_COUNT, .start = VT1724_PDMA0_START, }; -static const struct vt1724_pcm_reg vt1724_capture_pro_reg = { +static const struct vt1724_pcm_reg vt1724_pdma4_reg = { + .addr = VT1724_MT_PDMA4_ADDR, + .size = VT1724_MT_PDMA4_SIZE, + .count = VT1724_MT_PDMA4_COUNT, + .start = VT1724_PDMA4_START, +}; + +static const struct vt1724_pcm_reg vt1724_rdma0_reg = { .addr = VT1724_MT_CAPTURE_ADDR, .size = VT1724_MT_CAPTURE_SIZE, .count = VT1724_MT_CAPTURE_COUNT, .start = VT1724_RDMA0_START, }; +static const struct vt1724_pcm_reg vt1724_rdma1_reg = { + .addr = VT1724_MT_RDMA1_ADDR, + .size = VT1724_MT_RDMA1_SIZE, + .count = VT1724_MT_RDMA1_COUNT, + .start = VT1724_RDMA1_START, +}; + +#define vt1724_playback_pro_reg vt1724_pdma0_reg +#define vt1724_playback_spdif_reg vt1724_pdma4_reg +#define vt1724_capture_pro_reg vt1724_rdma0_reg +#define vt1724_capture_spdif_reg vt1724_rdma1_reg + static const struct snd_pcm_hardware snd_vt1724_playback_pro = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | @@ -1077,20 +1105,6 @@ static int __devinit snd_vt1724_pcm_profi(struct snd_ice1712 *ice, int device) * SPDIF PCM */ -static const struct vt1724_pcm_reg vt1724_playback_spdif_reg = { - .addr = VT1724_MT_PDMA4_ADDR, - .size = VT1724_MT_PDMA4_SIZE, - .count = VT1724_MT_PDMA4_COUNT, - .start = VT1724_PDMA4_START, -}; - -static const struct vt1724_pcm_reg vt1724_capture_spdif_reg = { - .addr = VT1724_MT_RDMA1_ADDR, - .size = VT1724_MT_RDMA1_SIZE, - .count = VT1724_MT_RDMA1_COUNT, - .start = VT1724_RDMA1_START, -}; - /* update spdif control bits; call with reg_lock */ static void update_spdif_bits(struct snd_ice1712 *ice, unsigned int val) { @@ -1963,7 +1977,7 @@ static inline int digital_route_shift(int idx) return idx * 3; } -static int get_route_val(struct snd_ice1712 *ice, int shift) +int snd_ice1724_get_route_val(struct snd_ice1712 *ice, int shift) { unsigned long val; unsigned char eitem; @@ -1982,7 +1996,8 @@ static int get_route_val(struct snd_ice1712 *ice, int shift) return eitem; } -static int put_route_val(struct snd_ice1712 *ice, unsigned int val, int shift) +int snd_ice1724_put_route_val(struct snd_ice1712 *ice, unsigned int val, + int shift) { unsigned int old_val, nval; int change; @@ -2010,7 +2025,7 @@ static int snd_vt1724_pro_route_analog_get(struct snd_kcontrol *kcontrol, struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); ucontrol->value.enumerated.item[0] = - get_route_val(ice, analog_route_shift(idx)); + snd_ice1724_get_route_val(ice, analog_route_shift(idx)); return 0; } @@ -2019,8 +2034,9 @@ static int snd_vt1724_pro_route_analog_put(struct snd_kcontrol *kcontrol, { struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - return put_route_val(ice, ucontrol->value.enumerated.item[0], - analog_route_shift(idx)); + return snd_ice1724_put_route_val(ice, + ucontrol->value.enumerated.item[0], + analog_route_shift(idx)); } static int snd_vt1724_pro_route_spdif_get(struct snd_kcontrol *kcontrol, @@ -2029,7 +2045,7 @@ static int snd_vt1724_pro_route_spdif_get(struct snd_kcontrol *kcontrol, struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); ucontrol->value.enumerated.item[0] = - get_route_val(ice, digital_route_shift(idx)); + snd_ice1724_get_route_val(ice, digital_route_shift(idx)); return 0; } @@ -2038,11 +2054,13 @@ static int snd_vt1724_pro_route_spdif_put(struct snd_kcontrol *kcontrol, { struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - return put_route_val(ice, ucontrol->value.enumerated.item[0], - digital_route_shift(idx)); + return snd_ice1724_put_route_val(ice, + ucontrol->value.enumerated.item[0], + digital_route_shift(idx)); } -static struct snd_kcontrol_new snd_vt1724_mixer_pro_analog_route __devinitdata = { +static struct snd_kcontrol_new snd_vt1724_mixer_pro_analog_route __devinitdata = +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "H/W Playback Route", .info = snd_vt1724_pro_route_info, @@ -2109,6 +2127,7 @@ static struct snd_ice1712_card_info *card_tables[] __devinitdata = { snd_vt1724_prodigy_hifi_cards, snd_vt1724_prodigy192_cards, snd_vt1724_juli_cards, + snd_vt1724_maya44_cards, snd_vt1724_phase_cards, snd_vt1724_wtm_cards, snd_vt1724_se_cards, @@ -2246,8 +2265,10 @@ static int __devinit snd_vt1724_read_eeprom(struct snd_ice1712 *ice, static void __devinit snd_vt1724_chip_reset(struct snd_ice1712 *ice) { outb(VT1724_RESET , ICEREG1724(ice, CONTROL)); + inb(ICEREG1724(ice, CONTROL)); /* pci posting flush */ msleep(10); outb(0, ICEREG1724(ice, CONTROL)); + inb(ICEREG1724(ice, CONTROL)); /* pci posting flush */ msleep(10); } @@ -2277,9 +2298,12 @@ static int __devinit snd_vt1724_spdif_build_controls(struct snd_ice1712 *ice) if (snd_BUG_ON(!ice->pcm)) return -EIO; - err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_vt1724_mixer_pro_spdif_route, ice)); - if (err < 0) - return err; + if (!ice->own_routing) { + err = snd_ctl_add(ice->card, + snd_ctl_new1(&snd_vt1724_mixer_pro_spdif_route, ice)); + if (err < 0) + return err; + } err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_vt1724_spdif_switch, ice)); if (err < 0) @@ -2326,7 +2350,7 @@ static int __devinit snd_vt1724_build_controls(struct snd_ice1712 *ice) if (err < 0) return err; - if (ice->num_total_dacs > 0) { + if (!ice->own_routing && ice->num_total_dacs > 0) { struct snd_kcontrol_new tmp = snd_vt1724_mixer_pro_analog_route; tmp.count = ice->num_total_dacs; if (ice->vt1720 && tmp.count > 2) diff --git a/sound/pci/ice1712/maya44.c b/sound/pci/ice1712/maya44.c new file mode 100644 index 000000000000..3e1c20ae2f1c --- /dev/null +++ b/sound/pci/ice1712/maya44.c @@ -0,0 +1,779 @@ +/* + * ALSA driver for ICEnsemble VT1724 (Envy24HT) + * + * Lowlevel functions for ESI Maya44 cards + * + * Copyright (c) 2009 Takashi Iwai + * Based on the patches by Rainer Zimmermann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "ice1712.h" +#include "envy24ht.h" +#include "maya44.h" + +/* WM8776 register indexes */ +#define WM8776_REG_HEADPHONE_L 0x00 +#define WM8776_REG_HEADPHONE_R 0x01 +#define WM8776_REG_HEADPHONE_MASTER 0x02 +#define WM8776_REG_DAC_ATTEN_L 0x03 +#define WM8776_REG_DAC_ATTEN_R 0x04 +#define WM8776_REG_DAC_ATTEN_MASTER 0x05 +#define WM8776_REG_DAC_PHASE 0x06 +#define WM8776_REG_DAC_CONTROL 0x07 +#define WM8776_REG_DAC_MUTE 0x08 +#define WM8776_REG_DAC_DEEMPH 0x09 +#define WM8776_REG_DAC_IF_CONTROL 0x0a +#define WM8776_REG_ADC_IF_CONTROL 0x0b +#define WM8776_REG_MASTER_MODE_CONTROL 0x0c +#define WM8776_REG_POWERDOWN 0x0d +#define WM8776_REG_ADC_ATTEN_L 0x0e +#define WM8776_REG_ADC_ATTEN_R 0x0f +#define WM8776_REG_ADC_ALC1 0x10 +#define WM8776_REG_ADC_ALC2 0x11 +#define WM8776_REG_ADC_ALC3 0x12 +#define WM8776_REG_ADC_NOISE_GATE 0x13 +#define WM8776_REG_ADC_LIMITER 0x14 +#define WM8776_REG_ADC_MUX 0x15 +#define WM8776_REG_OUTPUT_MUX 0x16 +#define WM8776_REG_RESET 0x17 + +#define WM8776_NUM_REGS 0x18 + +/* clock ratio identifiers for snd_wm8776_set_rate() */ +#define WM8776_CLOCK_RATIO_128FS 0 +#define WM8776_CLOCK_RATIO_192FS 1 +#define WM8776_CLOCK_RATIO_256FS 2 +#define WM8776_CLOCK_RATIO_384FS 3 +#define WM8776_CLOCK_RATIO_512FS 4 +#define WM8776_CLOCK_RATIO_768FS 5 + +enum { WM_VOL_HP, WM_VOL_DAC, WM_VOL_ADC, WM_NUM_VOLS }; +enum { WM_SW_DAC, WM_SW_BYPASS, WM_NUM_SWITCHES }; + +struct snd_wm8776 { + unsigned char addr; + unsigned short regs[WM8776_NUM_REGS]; + unsigned char volumes[WM_NUM_VOLS][2]; + unsigned int switch_bits; +}; + +struct snd_maya44 { + struct snd_ice1712 *ice; + struct snd_wm8776 wm[2]; + struct mutex mutex; +}; + + +/* write the given register and save the data to the cache */ +static void wm8776_write(struct snd_ice1712 *ice, struct snd_wm8776 *wm, + unsigned char reg, unsigned short val) +{ + /* + * WM8776 registers are up to 9 bits wide, bit 8 is placed in the LSB + * of the address field + */ + snd_vt1724_write_i2c(ice, wm->addr, + (reg << 1) | ((val >> 8) & 1), + val & 0xff); + wm->regs[reg] = val; +} + +/* + * update the given register with and/or mask and save the data to the cache + */ +static int wm8776_write_bits(struct snd_ice1712 *ice, struct snd_wm8776 *wm, + unsigned char reg, + unsigned short mask, unsigned short val) +{ + val |= wm->regs[reg] & ~mask; + if (val != wm->regs[reg]) { + wm8776_write(ice, wm, reg, val); + return 1; + } + return 0; +} + + +/* + * WM8776 volume controls + */ + +struct maya_vol_info { + unsigned int maxval; /* volume range: 0..maxval */ + unsigned char regs[2]; /* left and right registers */ + unsigned short mask; /* value mask */ + unsigned short offset; /* zero-value offset */ + unsigned short mute; /* mute bit */ + unsigned short update; /* update bits */ + unsigned char mux_bits[2]; /* extra bits for ADC mute */ +}; + +static struct maya_vol_info vol_info[WM_NUM_VOLS] = { + [WM_VOL_HP] = { + .maxval = 80, + .regs = { WM8776_REG_HEADPHONE_L, WM8776_REG_HEADPHONE_R }, + .mask = 0x7f, + .offset = 0x30, + .mute = 0x00, + .update = 0x180, /* update and zero-cross enable */ + }, + [WM_VOL_DAC] = { + .maxval = 255, + .regs = { WM8776_REG_DAC_ATTEN_L, WM8776_REG_DAC_ATTEN_R }, + .mask = 0xff, + .offset = 0x01, + .mute = 0x00, + .update = 0x100, /* zero-cross enable */ + }, + [WM_VOL_ADC] = { + .maxval = 91, + .regs = { WM8776_REG_ADC_ATTEN_L, WM8776_REG_ADC_ATTEN_R }, + .mask = 0xff, + .offset = 0xa5, + .mute = 0xa5, + .update = 0x100, /* update */ + .mux_bits = { 0x80, 0x40 }, /* ADCMUX bits */ + }, +}; + +/* + * dB tables + */ +/* headphone output: mute, -73..+6db (1db step) */ +static const DECLARE_TLV_DB_SCALE(db_scale_hp, -7400, 100, 1); +/* DAC output: mute, -127..0db (0.5db step) */ +static const DECLARE_TLV_DB_SCALE(db_scale_dac, -12750, 50, 1); +/* ADC gain: mute, -21..+24db (0.5db step) */ +static const DECLARE_TLV_DB_SCALE(db_scale_adc, -2100, 50, 1); + +static int maya_vol_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + unsigned int idx = kcontrol->private_value; + struct maya_vol_info *vol = &vol_info[idx]; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 2; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = vol->maxval; + return 0; +} + +static int maya_vol_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); + struct snd_wm8776 *wm = + &chip->wm[snd_ctl_get_ioff(kcontrol, &ucontrol->id)]; + unsigned int idx = kcontrol->private_value; + + mutex_lock(&chip->mutex); + ucontrol->value.integer.value[0] = wm->volumes[idx][0]; + ucontrol->value.integer.value[1] = wm->volumes[idx][1]; + mutex_unlock(&chip->mutex); + return 0; +} + +static int maya_vol_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); + struct snd_wm8776 *wm = + &chip->wm[snd_ctl_get_ioff(kcontrol, &ucontrol->id)]; + unsigned int idx = kcontrol->private_value; + struct maya_vol_info *vol = &vol_info[idx]; + unsigned int val, data; + int ch, changed = 0; + + mutex_lock(&chip->mutex); + for (ch = 0; ch < 2; ch++) { + val = ucontrol->value.integer.value[ch]; + if (val > vol->maxval) + val = vol->maxval; + if (val == wm->volumes[idx][ch]) + continue; + if (!val) + data = vol->mute; + else + data = (val - 1) + vol->offset; + data |= vol->update; + changed |= wm8776_write_bits(chip->ice, wm, vol->regs[ch], + vol->mask | vol->update, data); + if (vol->mux_bits[ch]) + wm8776_write_bits(chip->ice, wm, WM8776_REG_ADC_MUX, + vol->mux_bits[ch], + val ? 0 : vol->mux_bits[ch]); + wm->volumes[idx][ch] = val; + } + mutex_unlock(&chip->mutex); + return changed; +} + +/* + * WM8776 switch controls + */ + +#define COMPOSE_SW_VAL(idx, reg, mask) ((idx) | ((reg) << 8) | ((mask) << 16)) +#define GET_SW_VAL_IDX(val) ((val) & 0xff) +#define GET_SW_VAL_REG(val) (((val) >> 8) & 0xff) +#define GET_SW_VAL_MASK(val) (((val) >> 16) & 0xff) + +#define maya_sw_info snd_ctl_boolean_mono_info + +static int maya_sw_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); + struct snd_wm8776 *wm = + &chip->wm[snd_ctl_get_ioff(kcontrol, &ucontrol->id)]; + unsigned int idx = GET_SW_VAL_IDX(kcontrol->private_value); + + ucontrol->value.integer.value[0] = (wm->switch_bits >> idx) & 1; + return 0; +} + +static int maya_sw_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); + struct snd_wm8776 *wm = + &chip->wm[snd_ctl_get_ioff(kcontrol, &ucontrol->id)]; + unsigned int idx = GET_SW_VAL_IDX(kcontrol->private_value); + unsigned int mask, val; + int changed; + + mutex_lock(&chip->mutex); + mask = 1 << idx; + wm->switch_bits &= ~mask; + val = ucontrol->value.integer.value[0]; + if (val) + wm->switch_bits |= mask; + mask = GET_SW_VAL_MASK(kcontrol->private_value); + changed = wm8776_write_bits(chip->ice, wm, + GET_SW_VAL_REG(kcontrol->private_value), + mask, val ? mask : 0); + mutex_unlock(&chip->mutex); + return changed; +} + +/* + * GPIO pins (known ones for maya44) + */ +#define GPIO_PHANTOM_OFF 2 +#define GPIO_MIC_RELAY 4 +#define GPIO_SPDIF_IN_INV 5 +#define GPIO_MUST_BE_0 7 + +/* + * GPIO switch controls + */ + +#define COMPOSE_GPIO_VAL(shift, inv) ((shift) | ((inv) << 8)) +#define GET_GPIO_VAL_SHIFT(val) ((val) & 0xff) +#define GET_GPIO_VAL_INV(val) (((val) >> 8) & 1) + +static int maya_set_gpio_bits(struct snd_ice1712 *ice, unsigned int mask, + unsigned int bits) +{ + unsigned int data; + data = snd_ice1712_gpio_read(ice); + if ((data & mask) == bits) + return 0; + snd_ice1712_gpio_write(ice, (data & ~mask) | bits); + return 1; +} + +#define maya_gpio_sw_info snd_ctl_boolean_mono_info + +static int maya_gpio_sw_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); + unsigned int shift = GET_GPIO_VAL_SHIFT(kcontrol->private_value); + unsigned int val; + + val = (snd_ice1712_gpio_read(chip->ice) >> shift) & 1; + if (GET_GPIO_VAL_INV(kcontrol->private_value)) + val = !val; + ucontrol->value.integer.value[0] = val; + return 0; +} + +static int maya_gpio_sw_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); + unsigned int shift = GET_GPIO_VAL_SHIFT(kcontrol->private_value); + unsigned int val, mask; + int changed; + + mutex_lock(&chip->mutex); + mask = 1 << shift; + val = ucontrol->value.integer.value[0]; + if (GET_GPIO_VAL_INV(kcontrol->private_value)) + val = !val; + val = val ? mask : 0; + changed = maya_set_gpio_bits(chip->ice, mask, val); + mutex_unlock(&chip->mutex); + return changed; +} + +/* + * capture source selection + */ + +/* known working input slots (0-4) */ +#define MAYA_LINE_IN 1 /* in-2 */ +#define MAYA_MIC_IN 4 /* in-5 */ + +static void wm8776_select_input(struct snd_maya44 *chip, int idx, int line) +{ + wm8776_write_bits(chip->ice, &chip->wm[idx], WM8776_REG_ADC_MUX, + 0x1f, 1 << line); +} + +static int maya_rec_src_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + static char *texts[] = { "Line", "Mic" }; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = ARRAY_SIZE(texts); + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = + uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, + texts[uinfo->value.enumerated.item]); + return 0; +} + +static int maya_rec_src_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); + int sel; + + if (snd_ice1712_gpio_read(chip->ice) & (1 << GPIO_MIC_RELAY)) + sel = 1; + else + sel = 0; + ucontrol->value.enumerated.item[0] = sel; + return 0; +} + +static int maya_rec_src_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); + int sel = ucontrol->value.enumerated.item[0]; + int changed; + + mutex_lock(&chip->mutex); + changed = maya_set_gpio_bits(chip->ice, GPIO_MIC_RELAY, + sel ? GPIO_MIC_RELAY : 0); + wm8776_select_input(chip, 0, sel ? MAYA_MIC_IN : MAYA_LINE_IN); + mutex_unlock(&chip->mutex); + return changed; +} + +/* + * Maya44 routing switch settings have different meanings than the standard + * ice1724 switches as defined in snd_vt1724_pro_route_info (ice1724.c). + */ +static int maya_pb_route_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + static char *texts[] = { + "PCM Out", /* 0 */ + "Input 1", "Input 2", "Input 3", "Input 4" + }; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = ARRAY_SIZE(texts); + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = + uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, + texts[uinfo->value.enumerated.item]); + return 0; +} + +static int maya_pb_route_shift(int idx) +{ + static const unsigned char shift[10] = + { 8, 20, 0, 3, 11, 23, 14, 26, 17, 29 }; + return shift[idx % 10]; +} + +static int maya_pb_route_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); + int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + ucontrol->value.enumerated.item[0] = + snd_ice1724_get_route_val(chip->ice, maya_pb_route_shift(idx)); + return 0; +} + +static int maya_pb_route_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); + int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + return snd_ice1724_put_route_val(chip->ice, + ucontrol->value.enumerated.item[0], + maya_pb_route_shift(idx)); +} + + +/* + * controls to be added + */ + +static struct snd_kcontrol_new maya_controls[] __devinitdata = { + { + .name = "Crossmix Playback Volume", + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ, + .info = maya_vol_info, + .get = maya_vol_get, + .put = maya_vol_put, + .tlv = { .p = db_scale_hp }, + .private_value = WM_VOL_HP, + .count = 2, + }, + { + .name = "PCM Playback Volume", + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ, + .info = maya_vol_info, + .get = maya_vol_get, + .put = maya_vol_put, + .tlv = { .p = db_scale_dac }, + .private_value = WM_VOL_DAC, + .count = 2, + }, + { + .name = "Line Capture Volume", + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ, + .info = maya_vol_info, + .get = maya_vol_get, + .put = maya_vol_put, + .tlv = { .p = db_scale_adc }, + .private_value = WM_VOL_ADC, + .count = 2, + }, + { + .name = "PCM Playback Switch", + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .info = maya_sw_info, + .get = maya_sw_get, + .put = maya_sw_put, + .private_value = COMPOSE_SW_VAL(WM_SW_DAC, + WM8776_REG_OUTPUT_MUX, 0x01), + .count = 2, + }, + { + .name = "Bypass Playback Switch", + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .info = maya_sw_info, + .get = maya_sw_get, + .put = maya_sw_put, + .private_value = COMPOSE_SW_VAL(WM_SW_BYPASS, + WM8776_REG_OUTPUT_MUX, 0x04), + .count = 2, + }, + { + .name = "Capture Source", + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .info = maya_rec_src_info, + .get = maya_rec_src_get, + .put = maya_rec_src_put, + }, + { + .name = "Mic Phantom Power Switch", + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .info = maya_gpio_sw_info, + .get = maya_gpio_sw_get, + .put = maya_gpio_sw_put, + .private_value = COMPOSE_GPIO_VAL(GPIO_PHANTOM_OFF, 1), + }, + { + .name = "SPDIF Capture Switch", + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .info = maya_gpio_sw_info, + .get = maya_gpio_sw_get, + .put = maya_gpio_sw_put, + .private_value = COMPOSE_GPIO_VAL(GPIO_SPDIF_IN_INV, 1), + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "H/W Playback Route", + .info = maya_pb_route_info, + .get = maya_pb_route_get, + .put = maya_pb_route_put, + .count = 4, /* FIXME: do controls 5-9 have any meaning? */ + }, +}; + +static int __devinit maya44_add_controls(struct snd_ice1712 *ice) +{ + int err, i; + + for (i = 0; i < ARRAY_SIZE(maya_controls); i++) { + err = snd_ctl_add(ice->card, snd_ctl_new1(&maya_controls[i], + ice->spec)); + if (err < 0) + return err; + } + return 0; +} + + +/* + * initialize a wm8776 chip + */ +static void __devinit wm8776_init(struct snd_ice1712 *ice, + struct snd_wm8776 *wm, unsigned int addr) +{ + static const unsigned short inits_wm8776[] = { + 0x02, 0x100, /* R2: headphone L+R muted + update */ + 0x05, 0x100, /* R5: DAC output L+R muted + update */ + 0x06, 0x000, /* R6: DAC output phase normal */ + 0x07, 0x091, /* R7: DAC enable zero cross detection, + normal output */ + 0x08, 0x000, /* R8: DAC soft mute off */ + 0x09, 0x000, /* R9: no deemph, DAC zero detect disabled */ + 0x0a, 0x022, /* R10: DAC I2C mode, std polarities, 24bit */ + 0x0b, 0x022, /* R11: ADC I2C mode, std polarities, 24bit, + highpass filter enabled */ + 0x0c, 0x042, /* R12: ADC+DAC slave, ADC+DAC 44,1kHz */ + 0x0d, 0x000, /* R13: all power up */ + 0x0e, 0x100, /* R14: ADC left muted, + enable zero cross detection */ + 0x0f, 0x100, /* R15: ADC right muted, + enable zero cross detection */ + /* R16: ALC...*/ + 0x11, 0x000, /* R17: disable ALC */ + /* R18: ALC...*/ + /* R19: noise gate...*/ + 0x15, 0x000, /* R21: ADC input mux init, mute all inputs */ + 0x16, 0x001, /* R22: output mux, select DAC */ + 0xff, 0xff + }; + + const unsigned short *ptr; + unsigned char reg; + unsigned short data; + + wm->addr = addr; + /* enable DAC output; mute bypass, aux & all inputs */ + wm->switch_bits = (1 << WM_SW_DAC); + + ptr = inits_wm8776; + while (*ptr != 0xff) { + reg = *ptr++; + data = *ptr++; + wm8776_write(ice, wm, reg, data); + } +} + + +/* + * change the rate on the WM8776 codecs. + * this assumes that the VT17xx's rate is changed by the calling function. + * NOTE: even though the WM8776's are running in slave mode and rate + * selection is automatic, we need to call snd_wm8776_set_rate() here + * to make sure some flags are set correctly. + */ +static void set_rate(struct snd_ice1712 *ice, unsigned int rate) +{ + struct snd_maya44 *chip = ice->spec; + unsigned int ratio, adc_ratio, val; + int i; + + switch (rate) { + case 192000: + ratio = WM8776_CLOCK_RATIO_128FS; + break; + case 176400: + ratio = WM8776_CLOCK_RATIO_128FS; + break; + case 96000: + ratio = WM8776_CLOCK_RATIO_256FS; + break; + case 88200: + ratio = WM8776_CLOCK_RATIO_384FS; + break; + case 48000: + ratio = WM8776_CLOCK_RATIO_512FS; + break; + case 44100: + ratio = WM8776_CLOCK_RATIO_512FS; + break; + case 32000: + ratio = WM8776_CLOCK_RATIO_768FS; + break; + case 0: + /* no hint - S/PDIF input is master, simply return */ + return; + default: + snd_BUG(); + return; + } + + /* + * this currently sets the same rate for ADC and DAC, but limits + * ADC rate to 256X (96kHz). For 256X mode (96kHz), this sets ADC + * oversampling to 64x, as recommended by WM8776 datasheet. + * Setting the rate is not really necessary in slave mode. + */ + adc_ratio = ratio; + if (adc_ratio < WM8776_CLOCK_RATIO_256FS) + adc_ratio = WM8776_CLOCK_RATIO_256FS; + + val = adc_ratio; + if (adc_ratio == WM8776_CLOCK_RATIO_256FS) + val |= 8; + val |= ratio << 4; + + mutex_lock(&chip->mutex); + for (i = 0; i < 2; i++) + wm8776_write_bits(ice, &chip->wm[i], + WM8776_REG_MASTER_MODE_CONTROL, + 0x180, val); + mutex_unlock(&chip->mutex); +} + +/* + * supported sample rates (to override the default one) + */ + +static unsigned int rates[] = { + 32000, 44100, 48000, 64000, 88200, 96000, 176400, 192000 +}; + +/* playback rates: 32..192 kHz */ +static struct snd_pcm_hw_constraint_list dac_rates = { + .count = ARRAY_SIZE(rates), + .list = rates, + .mask = 0 +}; + + +/* + * chip addresses on I2C bus + */ +static unsigned char wm8776_addr[2] __devinitdata = { + 0x34, 0x36, /* codec 0 & 1 */ +}; + +/* + * initialize the chip + */ +static int __devinit maya44_init(struct snd_ice1712 *ice) +{ + int i; + struct snd_maya44 *chip; + + chip = kzalloc(sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + mutex_init(&chip->mutex); + chip->ice = ice; + ice->spec = chip; + + /* initialise codecs */ + ice->num_total_dacs = 4; + ice->num_total_adcs = 4; + ice->akm_codecs = 0; + + for (i = 0; i < 2; i++) { + wm8776_init(ice, &chip->wm[i], wm8776_addr[i]); + wm8776_select_input(chip, i, MAYA_LINE_IN); + } + + /* set card specific rates */ + ice->hw_rates = &dac_rates; + + /* register change rate notifier */ + ice->gpio.set_pro_rate = set_rate; + + /* RDMA1 (2nd input channel) is used for ADC by default */ + ice->force_rdma1 = 1; + + /* have an own routing control */ + ice->own_routing = 1; + + return 0; +} + + +/* + * Maya44 boards don't provide the EEPROM data except for the vendor IDs. + * hence the driver needs to sets up it properly. + */ + +static unsigned char maya44_eeprom[] __devinitdata = { + [ICE_EEP2_SYSCONF] = 0x45, + /* clock xin1=49.152MHz, mpu401, 2 stereo ADCs+DACs */ + [ICE_EEP2_ACLINK] = 0x80, + /* I2S */ + [ICE_EEP2_I2S] = 0xf8, + /* vol, 96k, 24bit, 192k */ + [ICE_EEP2_SPDIF] = 0xc3, + /* enable spdif out, spdif out supp, spdif-in, ext spdif out */ + [ICE_EEP2_GPIO_DIR] = 0xff, + [ICE_EEP2_GPIO_DIR1] = 0xff, + [ICE_EEP2_GPIO_DIR2] = 0xff, + [ICE_EEP2_GPIO_MASK] = 0/*0x9f*/, + [ICE_EEP2_GPIO_MASK1] = 0/*0xff*/, + [ICE_EEP2_GPIO_MASK2] = 0/*0x7f*/, + [ICE_EEP2_GPIO_STATE] = (1 << GPIO_PHANTOM_OFF) | + (1 << GPIO_SPDIF_IN_INV), + [ICE_EEP2_GPIO_STATE1] = 0x00, + [ICE_EEP2_GPIO_STATE2] = 0x00, +}; + +/* entry point */ +struct snd_ice1712_card_info snd_vt1724_maya44_cards[] __devinitdata = { + { + .subvendor = VT1724_SUBDEVICE_MAYA44, + .name = "ESI Maya44", + .model = "maya44", + .chip_init = maya44_init, + .build_controls = maya44_add_controls, + .eeprom_size = sizeof(maya44_eeprom), + .eeprom_data = maya44_eeprom, + }, + { } /* terminator */ +}; diff --git a/sound/pci/ice1712/maya44.h b/sound/pci/ice1712/maya44.h new file mode 100644 index 000000000000..eafd03a8f4b5 --- /dev/null +++ b/sound/pci/ice1712/maya44.h @@ -0,0 +1,10 @@ +#ifndef __SOUND_MAYA44_H +#define __SOUND_MAYA44_H + +#define MAYA44_DEVICE_DESC "{ESI,Maya44}," + +#define VT1724_SUBDEVICE_MAYA44 0x34315441 /* Maya44 */ + +extern struct snd_ice1712_card_info snd_vt1724_maya44_cards[]; + +#endif /* __SOUND_MAYA44_H */ diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 173bebf9f51d..8aa5687f392a 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -356,8 +356,6 @@ struct ichdev { unsigned int position; unsigned int pos_shift; unsigned int last_pos; - unsigned long last_pos_jiffies; - unsigned int jiffy_to_bytes; int frags; int lvi; int lvi_frag; @@ -844,7 +842,6 @@ static int snd_intel8x0_pcm_trigger(struct snd_pcm_substream *substream, int cmd case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: val = ICH_IOCE | ICH_STARTBM; ichdev->last_pos = ichdev->position; - ichdev->last_pos_jiffies = jiffies; break; case SNDRV_PCM_TRIGGER_SUSPEND: ichdev->suspended = 1; @@ -1048,7 +1045,6 @@ static int snd_intel8x0_pcm_prepare(struct snd_pcm_substream *substream) ichdev->pos_shift = (runtime->sample_bits > 16) ? 2 : 1; } snd_intel8x0_setup_periods(chip, ichdev); - ichdev->jiffy_to_bytes = (runtime->rate * 4 * ichdev->pos_shift) / HZ; return 0; } @@ -1073,19 +1069,23 @@ static snd_pcm_uframes_t snd_intel8x0_pcm_pointer(struct snd_pcm_substream *subs ptr1 == igetword(chip, ichdev->reg_offset + ichdev->roff_picb)) break; } while (timeout--); + ptr = ichdev->last_pos; if (ptr1 != 0) { ptr1 <<= ichdev->pos_shift; ptr = ichdev->fragsize1 - ptr1; ptr += position; - ichdev->last_pos = ptr; - ichdev->last_pos_jiffies = jiffies; - } else { - ptr1 = jiffies - ichdev->last_pos_jiffies; - if (ptr1) - ptr1 -= 1; - ptr = ichdev->last_pos + ptr1 * ichdev->jiffy_to_bytes; - ptr %= ichdev->size; + if (ptr < ichdev->last_pos) { + unsigned int pos_base, last_base; + pos_base = position / ichdev->fragsize1; + last_base = ichdev->last_pos / ichdev->fragsize1; + /* another sanity check; ptr1 can go back to full + * before the base position is updated + */ + if (pos_base == last_base) + ptr = ichdev->last_pos; + } } + ichdev->last_pos = ptr; spin_unlock(&chip->reg_lock); if (ptr >= ichdev->size) return 0; diff --git a/sound/pci/lx6464es/Makefile b/sound/pci/lx6464es/Makefile new file mode 100644 index 000000000000..eb04a6c73d8b --- /dev/null +++ b/sound/pci/lx6464es/Makefile @@ -0,0 +1,2 @@ +snd-lx6464es-objs := lx6464es.o lx_core.o +obj-$(CONFIG_SND_LX6464ES) += snd-lx6464es.o diff --git a/sound/pci/lx6464es/lx6464es.c b/sound/pci/lx6464es/lx6464es.c new file mode 100644 index 000000000000..18da2ef04d09 --- /dev/null +++ b/sound/pci/lx6464es/lx6464es.c @@ -0,0 +1,1159 @@ +/* -*- linux-c -*- * + * + * ALSA driver for the digigram lx6464es interface + * + * Copyright (c) 2008, 2009 Tim Blechmann + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include "lx6464es.h" + +MODULE_AUTHOR("Tim Blechmann"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("digigram lx6464es"); +MODULE_SUPPORTED_DEVICE("{digigram lx6464es{}}"); + + +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; +static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; +static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; + +module_param_array(index, int, NULL, 0444); +MODULE_PARM_DESC(index, "Index value for Digigram LX6464ES interface."); +module_param_array(id, charp, NULL, 0444); +MODULE_PARM_DESC(id, "ID string for Digigram LX6464ES interface."); +module_param_array(enable, bool, NULL, 0444); +MODULE_PARM_DESC(enable, "Enable/disable specific Digigram LX6464ES soundcards."); + +static const char card_name[] = "LX6464ES"; + + +#define PCI_DEVICE_ID_PLX_LX6464ES PCI_DEVICE_ID_PLX_9056 + +static struct pci_device_id snd_lx6464es_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_LX6464ES), + .subvendor = PCI_VENDOR_ID_DIGIGRAM, + .subdevice = PCI_SUBDEVICE_ID_DIGIGRAM_LX6464ES_SERIAL_SUBSYSTEM + }, /* LX6464ES */ + { PCI_DEVICE(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_LX6464ES), + .subvendor = PCI_VENDOR_ID_DIGIGRAM, + .subdevice = PCI_SUBDEVICE_ID_DIGIGRAM_LX6464ES_CAE_SERIAL_SUBSYSTEM + }, /* LX6464ES-CAE */ + { 0, }, +}; + +MODULE_DEVICE_TABLE(pci, snd_lx6464es_ids); + + + +/* PGO pour USERo dans le registre pci_0x06/loc_0xEC */ +#define CHIPSC_RESET_XILINX (1L<<16) + + +/* alsa callbacks */ +static struct snd_pcm_hardware lx_caps = { + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_SYNC_START), + .formats = (SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S16_BE | + SNDRV_PCM_FMTBIT_S24_3LE | + SNDRV_PCM_FMTBIT_S24_3BE), + .rates = (SNDRV_PCM_RATE_CONTINUOUS | + SNDRV_PCM_RATE_8000_192000), + .rate_min = 8000, + .rate_max = 192000, + .channels_min = 2, + .channels_max = 64, + .buffer_bytes_max = 64*2*3*MICROBLAZE_IBL_MAX*MAX_STREAM_BUFFER, + .period_bytes_min = (2*2*MICROBLAZE_IBL_MIN*2), + .period_bytes_max = (4*64*MICROBLAZE_IBL_MAX*MAX_STREAM_BUFFER), + .periods_min = 2, + .periods_max = MAX_STREAM_BUFFER, +}; + +static int lx_set_granularity(struct lx6464es *chip, u32 gran); + + +static int lx_hardware_open(struct lx6464es *chip, + struct snd_pcm_substream *substream) +{ + int err = 0; + struct snd_pcm_runtime *runtime = substream->runtime; + int channels = runtime->channels; + int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); + + snd_pcm_uframes_t period_size = runtime->period_size; + + snd_printd(LXP "allocating pipe for %d channels\n", channels); + err = lx_pipe_allocate(chip, 0, is_capture, channels); + if (err < 0) { + snd_printk(KERN_ERR LXP "allocating pipe failed\n"); + return err; + } + + err = lx_set_granularity(chip, period_size); + if (err < 0) { + snd_printk(KERN_ERR LXP "setting granularity to %ld failed\n", + period_size); + return err; + } + + return 0; +} + +static int lx_hardware_start(struct lx6464es *chip, + struct snd_pcm_substream *substream) +{ + int err = 0; + struct snd_pcm_runtime *runtime = substream->runtime; + int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); + + snd_printd(LXP "setting stream format\n"); + err = lx_stream_set_format(chip, runtime, 0, is_capture); + if (err < 0) { + snd_printk(KERN_ERR LXP "setting stream format failed\n"); + return err; + } + + snd_printd(LXP "starting pipe\n"); + err = lx_pipe_start(chip, 0, is_capture); + if (err < 0) { + snd_printk(KERN_ERR LXP "starting pipe failed\n"); + return err; + } + + snd_printd(LXP "waiting for pipe to start\n"); + err = lx_pipe_wait_for_start(chip, 0, is_capture); + if (err < 0) { + snd_printk(KERN_ERR LXP "waiting for pipe failed\n"); + return err; + } + + return err; +} + + +static int lx_hardware_stop(struct lx6464es *chip, + struct snd_pcm_substream *substream) +{ + int err = 0; + int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); + + snd_printd(LXP "pausing pipe\n"); + err = lx_pipe_pause(chip, 0, is_capture); + if (err < 0) { + snd_printk(KERN_ERR LXP "pausing pipe failed\n"); + return err; + } + + snd_printd(LXP "waiting for pipe to become idle\n"); + err = lx_pipe_wait_for_idle(chip, 0, is_capture); + if (err < 0) { + snd_printk(KERN_ERR LXP "waiting for pipe failed\n"); + return err; + } + + snd_printd(LXP "stopping pipe\n"); + err = lx_pipe_stop(chip, 0, is_capture); + if (err < 0) { + snd_printk(LXP "stopping pipe failed\n"); + return err; + } + + return err; +} + + +static int lx_hardware_close(struct lx6464es *chip, + struct snd_pcm_substream *substream) +{ + int err = 0; + int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); + + snd_printd(LXP "releasing pipe\n"); + err = lx_pipe_release(chip, 0, is_capture); + if (err < 0) { + snd_printk(LXP "releasing pipe failed\n"); + return err; + } + + return err; +} + + +static int lx_pcm_open(struct snd_pcm_substream *substream) +{ + struct lx6464es *chip = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + int err = 0; + int board_rate; + + snd_printdd("->lx_pcm_open\n"); + mutex_lock(&chip->setup_mutex); + + /* copy the struct snd_pcm_hardware struct */ + runtime->hw = lx_caps; + +#if 0 + /* buffer-size should better be multiple of period-size */ + err = snd_pcm_hw_constraint_integer(runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + if (err < 0) { + snd_printk(KERN_WARNING LXP "could not constrain periods\n"); + goto exit; + } +#endif + + /* the clock rate cannot be changed */ + board_rate = chip->board_sample_rate; + err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_RATE, + board_rate, board_rate); + + if (err < 0) { + snd_printk(KERN_WARNING LXP "could not constrain periods\n"); + goto exit; + } + + /* constrain period size */ + err = snd_pcm_hw_constraint_minmax(runtime, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, + MICROBLAZE_IBL_MIN, + MICROBLAZE_IBL_MAX); + if (err < 0) { + snd_printk(KERN_WARNING LXP + "could not constrain period size\n"); + goto exit; + } + + snd_pcm_hw_constraint_step(runtime, 0, + SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 32); + + snd_pcm_set_sync(substream); + err = 0; + +exit: + runtime->private_data = chip; + + mutex_unlock(&chip->setup_mutex); + snd_printdd("<-lx_pcm_open, %d\n", err); + return err; +} + +static int lx_pcm_close(struct snd_pcm_substream *substream) +{ + int err = 0; + snd_printdd("->lx_pcm_close\n"); + return err; +} + +static snd_pcm_uframes_t lx_pcm_stream_pointer(struct snd_pcm_substream + *substream) +{ + struct lx6464es *chip = snd_pcm_substream_chip(substream); + snd_pcm_uframes_t pos; + unsigned long flags; + int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); + + struct lx_stream *lx_stream = is_capture ? &chip->capture_stream : + &chip->playback_stream; + + snd_printdd("->lx_pcm_stream_pointer\n"); + + spin_lock_irqsave(&chip->lock, flags); + pos = lx_stream->frame_pos * substream->runtime->period_size; + spin_unlock_irqrestore(&chip->lock, flags); + + snd_printdd(LXP "stream_pointer at %ld\n", pos); + return pos; +} + +static int lx_pcm_prepare(struct snd_pcm_substream *substream) +{ + struct lx6464es *chip = snd_pcm_substream_chip(substream); + int err = 0; + const int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); + + snd_printdd("->lx_pcm_prepare\n"); + + mutex_lock(&chip->setup_mutex); + + if (chip->hardware_running[is_capture]) { + err = lx_hardware_stop(chip, substream); + if (err < 0) { + snd_printk(KERN_ERR LXP "failed to stop hardware. " + "Error code %d\n", err); + goto exit; + } + + err = lx_hardware_close(chip, substream); + if (err < 0) { + snd_printk(KERN_ERR LXP "failed to close hardware. " + "Error code %d\n", err); + goto exit; + } + } + + snd_printd(LXP "opening hardware\n"); + err = lx_hardware_open(chip, substream); + if (err < 0) { + snd_printk(KERN_ERR LXP "failed to open hardware. " + "Error code %d\n", err); + goto exit; + } + + err = lx_hardware_start(chip, substream); + if (err < 0) { + snd_printk(KERN_ERR LXP "failed to start hardware. " + "Error code %d\n", err); + goto exit; + } + + chip->hardware_running[is_capture] = 1; + + if (chip->board_sample_rate != substream->runtime->rate) { + if (!err) + chip->board_sample_rate = substream->runtime->rate; + } + +exit: + mutex_unlock(&chip->setup_mutex); + return err; +} + +static int lx_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params, int is_capture) +{ + struct lx6464es *chip = snd_pcm_substream_chip(substream); + int err = 0; + + snd_printdd("->lx_pcm_hw_params\n"); + + mutex_lock(&chip->setup_mutex); + + /* set dma buffer */ + err = snd_pcm_lib_malloc_pages(substream, + params_buffer_bytes(hw_params)); + + if (is_capture) + chip->capture_stream.stream = substream; + else + chip->playback_stream.stream = substream; + + mutex_unlock(&chip->setup_mutex); + return err; +} + +static int lx_pcm_hw_params_playback(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + return lx_pcm_hw_params(substream, hw_params, 0); +} + +static int lx_pcm_hw_params_capture(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + return lx_pcm_hw_params(substream, hw_params, 1); +} + +static int lx_pcm_hw_free(struct snd_pcm_substream *substream) +{ + struct lx6464es *chip = snd_pcm_substream_chip(substream); + int err = 0; + int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); + + snd_printdd("->lx_pcm_hw_free\n"); + mutex_lock(&chip->setup_mutex); + + if (chip->hardware_running[is_capture]) { + err = lx_hardware_stop(chip, substream); + if (err < 0) { + snd_printk(KERN_ERR LXP "failed to stop hardware. " + "Error code %d\n", err); + goto exit; + } + + err = lx_hardware_close(chip, substream); + if (err < 0) { + snd_printk(KERN_ERR LXP "failed to close hardware. " + "Error code %d\n", err); + goto exit; + } + + chip->hardware_running[is_capture] = 0; + } + + err = snd_pcm_lib_free_pages(substream); + + if (is_capture) + chip->capture_stream.stream = 0; + else + chip->playback_stream.stream = 0; + +exit: + mutex_unlock(&chip->setup_mutex); + return err; +} + +static void lx_trigger_start(struct lx6464es *chip, struct lx_stream *lx_stream) +{ + struct snd_pcm_substream *substream = lx_stream->stream; + const int is_capture = lx_stream->is_capture; + + int err; + + const u32 channels = substream->runtime->channels; + const u32 bytes_per_frame = channels * 3; + const u32 period_size = substream->runtime->period_size; + const u32 periods = substream->runtime->periods; + const u32 period_bytes = period_size * bytes_per_frame; + + dma_addr_t buf = substream->dma_buffer.addr; + int i; + + u32 needed, freed; + u32 size_array[5]; + + for (i = 0; i != periods; ++i) { + u32 buffer_index = 0; + + err = lx_buffer_ask(chip, 0, is_capture, &needed, &freed, + size_array); + snd_printdd(LXP "starting: needed %d, freed %d\n", + needed, freed); + + err = lx_buffer_give(chip, 0, is_capture, period_bytes, + lower_32_bits(buf), upper_32_bits(buf), + &buffer_index); + + snd_printdd(LXP "starting: buffer index %x on %p (%d bytes)\n", + buffer_index, (void *)buf, period_bytes); + buf += period_bytes; + } + + err = lx_buffer_ask(chip, 0, is_capture, &needed, &freed, size_array); + snd_printdd(LXP "starting: needed %d, freed %d\n", needed, freed); + + snd_printd(LXP "starting: starting stream\n"); + err = lx_stream_start(chip, 0, is_capture); + if (err < 0) + snd_printk(KERN_ERR LXP "couldn't start stream\n"); + else + lx_stream->status = LX_STREAM_STATUS_RUNNING; + + lx_stream->frame_pos = 0; +} + +static void lx_trigger_stop(struct lx6464es *chip, struct lx_stream *lx_stream) +{ + const int is_capture = lx_stream->is_capture; + int err; + + snd_printd(LXP "stopping: stopping stream\n"); + err = lx_stream_stop(chip, 0, is_capture); + if (err < 0) + snd_printk(KERN_ERR LXP "couldn't stop stream\n"); + else + lx_stream->status = LX_STREAM_STATUS_FREE; + +} + +static void lx_trigger_tasklet_dispatch_stream(struct lx6464es *chip, + struct lx_stream *lx_stream) +{ + switch (lx_stream->status) { + case LX_STREAM_STATUS_SCHEDULE_RUN: + lx_trigger_start(chip, lx_stream); + break; + + case LX_STREAM_STATUS_SCHEDULE_STOP: + lx_trigger_stop(chip, lx_stream); + break; + + default: + break; + } +} + +static void lx_trigger_tasklet(unsigned long data) +{ + struct lx6464es *chip = (struct lx6464es *)data; + unsigned long flags; + + snd_printdd("->lx_trigger_tasklet\n"); + + spin_lock_irqsave(&chip->lock, flags); + lx_trigger_tasklet_dispatch_stream(chip, &chip->capture_stream); + lx_trigger_tasklet_dispatch_stream(chip, &chip->playback_stream); + spin_unlock_irqrestore(&chip->lock, flags); +} + +static int lx_pcm_trigger_dispatch(struct lx6464es *chip, + struct lx_stream *lx_stream, int cmd) +{ + int err = 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + lx_stream->status = LX_STREAM_STATUS_SCHEDULE_RUN; + break; + + case SNDRV_PCM_TRIGGER_STOP: + lx_stream->status = LX_STREAM_STATUS_SCHEDULE_STOP; + break; + + default: + err = -EINVAL; + goto exit; + } + tasklet_schedule(&chip->trigger_tasklet); + +exit: + return err; +} + + +static int lx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct lx6464es *chip = snd_pcm_substream_chip(substream); + const int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); + struct lx_stream *stream = is_capture ? &chip->capture_stream : + &chip->playback_stream; + + snd_printdd("->lx_pcm_trigger\n"); + + return lx_pcm_trigger_dispatch(chip, stream, cmd); +} + +static int snd_lx6464es_free(struct lx6464es *chip) +{ + snd_printdd("->snd_lx6464es_free\n"); + + lx_irq_disable(chip); + + if (chip->irq >= 0) + free_irq(chip->irq, chip); + + iounmap(chip->port_dsp_bar); + ioport_unmap(chip->port_plx_remapped); + + pci_release_regions(chip->pci); + pci_disable_device(chip->pci); + + kfree(chip); + + return 0; +} + +static int snd_lx6464es_dev_free(struct snd_device *device) +{ + return snd_lx6464es_free(device->device_data); +} + +/* reset the dsp during initialization */ +static int __devinit lx_init_xilinx_reset(struct lx6464es *chip) +{ + int i; + u32 plx_reg = lx_plx_reg_read(chip, ePLX_CHIPSC); + + snd_printdd("->lx_init_xilinx_reset\n"); + + /* activate reset of xilinx */ + plx_reg &= ~CHIPSC_RESET_XILINX; + + lx_plx_reg_write(chip, ePLX_CHIPSC, plx_reg); + msleep(1); + + lx_plx_reg_write(chip, ePLX_MBOX3, 0); + msleep(1); + + plx_reg |= CHIPSC_RESET_XILINX; + lx_plx_reg_write(chip, ePLX_CHIPSC, plx_reg); + + /* deactivate reset of xilinx */ + for (i = 0; i != 100; ++i) { + u32 reg_mbox3; + msleep(10); + reg_mbox3 = lx_plx_reg_read(chip, ePLX_MBOX3); + if (reg_mbox3) { + snd_printd(LXP "xilinx reset done\n"); + snd_printdd(LXP "xilinx took %d loops\n", i); + break; + } + } + + /* todo: add some error handling? */ + + /* clear mr */ + lx_dsp_reg_write(chip, eReg_CSM, 0); + + /* le xilinx ES peut ne pas etre encore pret, on attend. */ + msleep(600); + + return 0; +} + +static int __devinit lx_init_xilinx_test(struct lx6464es *chip) +{ + u32 reg; + + snd_printdd("->lx_init_xilinx_test\n"); + + /* TEST if we have access to Xilinx/MicroBlaze */ + lx_dsp_reg_write(chip, eReg_CSM, 0); + + reg = lx_dsp_reg_read(chip, eReg_CSM); + + if (reg) { + snd_printk(KERN_ERR LXP "Problem: Reg_CSM %x.\n", reg); + + /* PCI9056_SPACE0_REMAP */ + lx_plx_reg_write(chip, ePLX_PCICR, 1); + + reg = lx_dsp_reg_read(chip, eReg_CSM); + if (reg) { + snd_printk(KERN_ERR LXP "Error: Reg_CSM %x.\n", reg); + return -EAGAIN; /* seems to be appropriate */ + } + } + + snd_printd(LXP "Xilinx/MicroBlaze access test successful\n"); + + return 0; +} + +/* initialize ethersound */ +static int __devinit lx_init_ethersound_config(struct lx6464es *chip) +{ + int i; + u32 orig_conf_es = lx_dsp_reg_read(chip, eReg_CONFES); + + u32 default_conf_es = (64 << IOCR_OUTPUTS_OFFSET) | + (64 << IOCR_INPUTS_OFFSET) | + (FREQ_RATIO_SINGLE_MODE << FREQ_RATIO_OFFSET); + + u32 conf_es = (orig_conf_es & CONFES_READ_PART_MASK) + | (default_conf_es & CONFES_WRITE_PART_MASK); + + snd_printdd("->lx_init_ethersound\n"); + + chip->freq_ratio = FREQ_RATIO_SINGLE_MODE; + + /* + * write it to the card ! + * this actually kicks the ES xilinx, the first time since poweron. + * the MAC address in the Reg_ADMACESMSB Reg_ADMACESLSB registers + * is not ready before this is done, and the bit 2 in Reg_CSES is set. + * */ + lx_dsp_reg_write(chip, eReg_CONFES, conf_es); + + for (i = 0; i != 1000; ++i) { + if (lx_dsp_reg_read(chip, eReg_CSES) & 4) { + snd_printd(LXP "ethersound initialized after %dms\n", + i); + goto ethersound_initialized; + } + msleep(1); + } + snd_printk(KERN_WARNING LXP + "ethersound could not be initialized after %dms\n", i); + return -ETIMEDOUT; + + ethersound_initialized: + snd_printd(LXP "ethersound initialized\n"); + return 0; +} + +static int __devinit lx_init_get_version_features(struct lx6464es *chip) +{ + u32 dsp_version; + + int err; + + snd_printdd("->lx_init_get_version_features\n"); + + err = lx_dsp_get_version(chip, &dsp_version); + + if (err == 0) { + u32 freq; + + snd_printk(LXP "DSP version: V%02d.%02d #%d\n", + (dsp_version>>16) & 0xff, (dsp_version>>8) & 0xff, + dsp_version & 0xff); + + /* later: what firmware version do we expect? */ + + /* retrieve Play/Rec features */ + /* done here because we may have to handle alternate + * DSP files. */ + /* later */ + + /* init the EtherSound sample rate */ + err = lx_dsp_get_clock_frequency(chip, &freq); + if (err == 0) + chip->board_sample_rate = freq; + snd_printd(LXP "actual clock frequency %d\n", freq); + } else { + snd_printk(KERN_ERR LXP "DSP corrupted \n"); + err = -EAGAIN; + } + + return err; +} + +static int lx_set_granularity(struct lx6464es *chip, u32 gran) +{ + int err = 0; + u32 snapped_gran = MICROBLAZE_IBL_MIN; + + snd_printdd("->lx_set_granularity\n"); + + /* blocksize is a power of 2 */ + while ((snapped_gran < gran) && + (snapped_gran < MICROBLAZE_IBL_MAX)) { + snapped_gran *= 2; + } + + if (snapped_gran == chip->pcm_granularity) + return 0; + + err = lx_dsp_set_granularity(chip, snapped_gran); + if (err < 0) { + snd_printk(KERN_WARNING LXP "could not set granularity\n"); + err = -EAGAIN; + } + + if (snapped_gran != gran) + snd_printk(LXP "snapped blocksize to %d\n", snapped_gran); + + snd_printd(LXP "set blocksize on board %d\n", snapped_gran); + chip->pcm_granularity = snapped_gran; + + return err; +} + +/* initialize and test the xilinx dsp chip */ +static int __devinit lx_init_dsp(struct lx6464es *chip) +{ + int err; + u8 mac_address[6]; + int i; + + snd_printdd("->lx_init_dsp\n"); + + snd_printd(LXP "initialize board\n"); + err = lx_init_xilinx_reset(chip); + if (err) + return err; + + snd_printd(LXP "testing board\n"); + err = lx_init_xilinx_test(chip); + if (err) + return err; + + snd_printd(LXP "initialize ethersound configuration\n"); + err = lx_init_ethersound_config(chip); + if (err) + return err; + + lx_irq_enable(chip); + + /** \todo the mac address should be ready by not, but it isn't, + * so we wait for it */ + for (i = 0; i != 1000; ++i) { + err = lx_dsp_get_mac(chip, mac_address); + if (err) + return err; + if (mac_address[0] || mac_address[1] || mac_address[2] || + mac_address[3] || mac_address[4] || mac_address[5]) + goto mac_ready; + msleep(1); + } + return -ETIMEDOUT; + +mac_ready: + snd_printd(LXP "mac address ready read after: %dms\n", i); + snd_printk(LXP "mac address: %02X.%02X.%02X.%02X.%02X.%02X\n", + mac_address[0], mac_address[1], mac_address[2], + mac_address[3], mac_address[4], mac_address[5]); + + err = lx_init_get_version_features(chip); + if (err) + return err; + + lx_set_granularity(chip, MICROBLAZE_IBL_DEFAULT); + + chip->playback_mute = 0; + + return err; +} + +static struct snd_pcm_ops lx_ops_playback = { + .open = lx_pcm_open, + .close = lx_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .prepare = lx_pcm_prepare, + .hw_params = lx_pcm_hw_params_playback, + .hw_free = lx_pcm_hw_free, + .trigger = lx_pcm_trigger, + .pointer = lx_pcm_stream_pointer, +}; + +static struct snd_pcm_ops lx_ops_capture = { + .open = lx_pcm_open, + .close = lx_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .prepare = lx_pcm_prepare, + .hw_params = lx_pcm_hw_params_capture, + .hw_free = lx_pcm_hw_free, + .trigger = lx_pcm_trigger, + .pointer = lx_pcm_stream_pointer, +}; + +static int __devinit lx_pcm_create(struct lx6464es *chip) +{ + int err; + struct snd_pcm *pcm; + + u32 size = 64 * /* channels */ + 3 * /* 24 bit samples */ + MAX_STREAM_BUFFER * /* periods */ + MICROBLAZE_IBL_MAX * /* frames per period */ + 2; /* duplex */ + + size = PAGE_ALIGN(size); + + /* hardcoded device name & channel count */ + err = snd_pcm_new(chip->card, (char *)card_name, 0, + 1, 1, &pcm); + + pcm->private_data = chip; + + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &lx_ops_playback); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &lx_ops_capture); + + pcm->info_flags = 0; + strcpy(pcm->name, card_name); + + err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(chip->pci), + size, size); + if (err < 0) + return err; + + chip->pcm = pcm; + chip->capture_stream.is_capture = 1; + + return 0; +} + +static int lx_control_playback_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int lx_control_playback_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct lx6464es *chip = snd_kcontrol_chip(kcontrol); + ucontrol->value.integer.value[0] = chip->playback_mute; + return 0; +} + +static int lx_control_playback_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct lx6464es *chip = snd_kcontrol_chip(kcontrol); + int changed = 0; + int current_value = chip->playback_mute; + + if (current_value != ucontrol->value.integer.value[0]) { + lx_level_unmute(chip, 0, !current_value); + chip->playback_mute = !current_value; + changed = 1; + } + return changed; +} + +static struct snd_kcontrol_new lx_control_playback_switch __devinitdata = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "PCM Playback Switch", + .index = 0, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .private_value = 0, + .info = lx_control_playback_info, + .get = lx_control_playback_get, + .put = lx_control_playback_put +}; + + + +static void lx_proc_levels_read(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) +{ + u32 levels[64]; + int err; + int i, j; + struct lx6464es *chip = entry->private_data; + + snd_iprintf(buffer, "capture levels:\n"); + err = lx_level_peaks(chip, 1, 64, levels); + if (err < 0) + return; + + for (i = 0; i != 8; ++i) { + for (j = 0; j != 8; ++j) + snd_iprintf(buffer, "%08x ", levels[i*8+j]); + snd_iprintf(buffer, "\n"); + } + + snd_iprintf(buffer, "\nplayback levels:\n"); + + err = lx_level_peaks(chip, 0, 64, levels); + if (err < 0) + return; + + for (i = 0; i != 8; ++i) { + for (j = 0; j != 8; ++j) + snd_iprintf(buffer, "%08x ", levels[i*8+j]); + snd_iprintf(buffer, "\n"); + } + + snd_iprintf(buffer, "\n"); +} + +static int __devinit lx_proc_create(struct snd_card *card, struct lx6464es *chip) +{ + struct snd_info_entry *entry; + int err = snd_card_proc_new(card, "levels", &entry); + if (err < 0) + return err; + + snd_info_set_text_ops(entry, chip, lx_proc_levels_read); + return 0; +} + + +static int __devinit snd_lx6464es_create(struct snd_card *card, + struct pci_dev *pci, + struct lx6464es **rchip) +{ + struct lx6464es *chip; + int err; + + static struct snd_device_ops ops = { + .dev_free = snd_lx6464es_dev_free, + }; + + snd_printdd("->snd_lx6464es_create\n"); + + *rchip = NULL; + + /* enable PCI device */ + err = pci_enable_device(pci); + if (err < 0) + return err; + + pci_set_master(pci); + + /* check if we can restrict PCI DMA transfers to 32 bits */ + err = pci_set_dma_mask(pci, DMA_BIT_MASK(32)); + if (err < 0) { + snd_printk(KERN_ERR "architecture does not support " + "32bit PCI busmaster DMA\n"); + pci_disable_device(pci); + return -ENXIO; + } + + chip = kzalloc(sizeof(*chip), GFP_KERNEL); + if (chip == NULL) { + err = -ENOMEM; + goto alloc_failed; + } + + chip->card = card; + chip->pci = pci; + chip->irq = -1; + + /* initialize synchronization structs */ + spin_lock_init(&chip->lock); + spin_lock_init(&chip->msg_lock); + mutex_init(&chip->setup_mutex); + tasklet_init(&chip->trigger_tasklet, lx_trigger_tasklet, + (unsigned long)chip); + tasklet_init(&chip->tasklet_capture, lx_tasklet_capture, + (unsigned long)chip); + tasklet_init(&chip->tasklet_playback, lx_tasklet_playback, + (unsigned long)chip); + + /* request resources */ + err = pci_request_regions(pci, card_name); + if (err < 0) + goto request_regions_failed; + + /* plx port */ + chip->port_plx = pci_resource_start(pci, 1); + chip->port_plx_remapped = ioport_map(chip->port_plx, + pci_resource_len(pci, 1)); + + /* dsp port */ + chip->port_dsp_bar = pci_ioremap_bar(pci, 2); + + err = request_irq(pci->irq, lx_interrupt, IRQF_SHARED, + card_name, chip); + if (err) { + snd_printk(KERN_ERR LXP "unable to grab IRQ %d\n", pci->irq); + goto request_irq_failed; + } + chip->irq = pci->irq; + + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); + if (err < 0) + goto device_new_failed; + + err = lx_init_dsp(chip); + if (err < 0) { + snd_printk(KERN_ERR LXP "error during DSP initialization\n"); + return err; + } + + err = lx_pcm_create(chip); + if (err < 0) + return err; + + err = lx_proc_create(card, chip); + if (err < 0) + return err; + + err = snd_ctl_add(card, snd_ctl_new1(&lx_control_playback_switch, + chip)); + if (err < 0) + return err; + + snd_card_set_dev(card, &pci->dev); + + *rchip = chip; + return 0; + +device_new_failed: + free_irq(pci->irq, chip); + +request_irq_failed: + pci_release_regions(pci); + +request_regions_failed: + kfree(chip); + +alloc_failed: + pci_disable_device(pci); + + return err; +} + +static int __devinit snd_lx6464es_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) +{ + static int dev; + struct snd_card *card; + struct lx6464es *chip; + int err; + + snd_printdd("->snd_lx6464es_probe\n"); + + if (dev >= SNDRV_CARDS) + return -ENODEV; + if (!enable[dev]) { + dev++; + return -ENOENT; + } + + err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); + if (err < 0) + return err; + + err = snd_lx6464es_create(card, pci, &chip); + if (err < 0) { + snd_printk(KERN_ERR LXP "error during snd_lx6464es_create\n"); + goto out_free; + } + + strcpy(card->driver, "lx6464es"); + strcpy(card->shortname, "Digigram LX6464ES"); + sprintf(card->longname, "%s at 0x%lx, 0x%p, irq %i", + card->shortname, chip->port_plx, + chip->port_dsp_bar, chip->irq); + + err = snd_card_register(card); + if (err < 0) + goto out_free; + + snd_printdd(LXP "initialization successful\n"); + pci_set_drvdata(pci, card); + dev++; + return 0; + +out_free: + snd_card_free(card); + return err; + +} + +static void __devexit snd_lx6464es_remove(struct pci_dev *pci) +{ + snd_card_free(pci_get_drvdata(pci)); + pci_set_drvdata(pci, NULL); +} + + +static struct pci_driver driver = { + .name = "Digigram LX6464ES", + .id_table = snd_lx6464es_ids, + .probe = snd_lx6464es_probe, + .remove = __devexit_p(snd_lx6464es_remove), +}; + + +/* module initialization */ +static int __init mod_init(void) +{ + return pci_register_driver(&driver); +} + +static void __exit mod_exit(void) +{ + pci_unregister_driver(&driver); +} + +module_init(mod_init); +module_exit(mod_exit); diff --git a/sound/pci/lx6464es/lx6464es.h b/sound/pci/lx6464es/lx6464es.h new file mode 100644 index 000000000000..012c010c8c89 --- /dev/null +++ b/sound/pci/lx6464es/lx6464es.h @@ -0,0 +1,114 @@ +/* -*- linux-c -*- * + * + * ALSA driver for the digigram lx6464es interface + * + * Copyright (c) 2009 Tim Blechmann + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#ifndef LX6464ES_H +#define LX6464ES_H + +#include +#include + +#include +#include + +#include "lx_core.h" + +#define LXP "LX6464ES: " + +enum { + ES_cmd_free = 0, /* no command executing */ + ES_cmd_processing = 1, /* execution of a read/write command */ + ES_read_pending = 2, /* a asynchron read command is pending */ + ES_read_finishing = 3, /* a read command has finished waiting (set by + * Interrupt or CancelIrp) */ +}; + +enum lx_stream_status { + LX_STREAM_STATUS_FREE, +/* LX_STREAM_STATUS_OPEN, */ + LX_STREAM_STATUS_SCHEDULE_RUN, +/* LX_STREAM_STATUS_STARTED, */ + LX_STREAM_STATUS_RUNNING, + LX_STREAM_STATUS_SCHEDULE_STOP, +/* LX_STREAM_STATUS_STOPPED, */ +/* LX_STREAM_STATUS_PAUSED */ +}; + + +struct lx_stream { + struct snd_pcm_substream *stream; + snd_pcm_uframes_t frame_pos; + enum lx_stream_status status; /* free, open, running, draining + * pause */ + int is_capture:1; +}; + + +struct lx6464es { + struct snd_card *card; + struct pci_dev *pci; + int irq; + + spinlock_t lock; /* interrupt spinlock */ + struct mutex setup_mutex; /* mutex used in hw_params, open + * and close */ + + struct tasklet_struct trigger_tasklet; /* trigger tasklet */ + struct tasklet_struct tasklet_capture; + struct tasklet_struct tasklet_playback; + + /* ports */ + unsigned long port_plx; /* io port (size=256) */ + void __iomem *port_plx_remapped; /* remapped plx port */ + void __iomem *port_dsp_bar; /* memory port (32-bit, + * non-prefetchable, + * size=8K) */ + + /* messaging */ + spinlock_t msg_lock; /* message spinlock */ + atomic_t send_message_locked; + struct lx_rmh rmh; + + /* configuration */ + uint freq_ratio : 2; + uint playback_mute : 1; + uint hardware_running[2]; + u32 board_sample_rate; /* sample rate read from + * board */ + u32 sample_rate; /* our sample rate */ + u16 pcm_granularity; /* board blocksize */ + + /* dma */ + struct snd_dma_buffer capture_dma_buf; + struct snd_dma_buffer playback_dma_buf; + + /* pcm */ + struct snd_pcm *pcm; + + /* streams */ + struct lx_stream capture_stream; + struct lx_stream playback_stream; +}; + + +#endif /* LX6464ES_H */ diff --git a/sound/pci/lx6464es/lx_core.c b/sound/pci/lx6464es/lx_core.c new file mode 100644 index 000000000000..5812780d6e89 --- /dev/null +++ b/sound/pci/lx6464es/lx_core.c @@ -0,0 +1,1444 @@ +/* -*- linux-c -*- * + * + * ALSA driver for the digigram lx6464es interface + * low-level interface + * + * Copyright (c) 2009 Tim Blechmann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +/* #define RMH_DEBUG 1 */ + +#include +#include +#include + +#include "lx6464es.h" +#include "lx_core.h" + +/* low-level register access */ + +static const unsigned long dsp_port_offsets[] = { + 0, + 0x400, + 0x401, + 0x402, + 0x403, + 0x404, + 0x405, + 0x406, + 0x407, + 0x408, + 0x409, + 0x40a, + 0x40b, + 0x40c, + + 0x410, + 0x411, + 0x412, + 0x413, + 0x414, + 0x415, + 0x416, + + 0x420, + 0x430, + 0x431, + 0x432, + 0x433, + 0x434, + 0x440 +}; + +static void __iomem *lx_dsp_register(struct lx6464es *chip, int port) +{ + void __iomem *base_address = chip->port_dsp_bar; + return base_address + dsp_port_offsets[port]*4; +} + +unsigned long lx_dsp_reg_read(struct lx6464es *chip, int port) +{ + void __iomem *address = lx_dsp_register(chip, port); + return ioread32(address); +} + +void lx_dsp_reg_readbuf(struct lx6464es *chip, int port, u32 *data, u32 len) +{ + void __iomem *address = lx_dsp_register(chip, port); + memcpy_fromio(data, address, len*sizeof(u32)); +} + + +void lx_dsp_reg_write(struct lx6464es *chip, int port, unsigned data) +{ + void __iomem *address = lx_dsp_register(chip, port); + iowrite32(data, address); +} + +void lx_dsp_reg_writebuf(struct lx6464es *chip, int port, const u32 *data, + u32 len) +{ + void __iomem *address = lx_dsp_register(chip, port); + memcpy_toio(address, data, len*sizeof(u32)); +} + + +static const unsigned long plx_port_offsets[] = { + 0x04, + 0x40, + 0x44, + 0x48, + 0x4c, + 0x50, + 0x54, + 0x58, + 0x5c, + 0x64, + 0x68, + 0x6C +}; + +static void __iomem *lx_plx_register(struct lx6464es *chip, int port) +{ + void __iomem *base_address = chip->port_plx_remapped; + return base_address + plx_port_offsets[port]; +} + +unsigned long lx_plx_reg_read(struct lx6464es *chip, int port) +{ + void __iomem *address = lx_plx_register(chip, port); + return ioread32(address); +} + +void lx_plx_reg_write(struct lx6464es *chip, int port, u32 data) +{ + void __iomem *address = lx_plx_register(chip, port); + iowrite32(data, address); +} + +u32 lx_plx_mbox_read(struct lx6464es *chip, int mbox_nr) +{ + int index; + + switch (mbox_nr) { + case 1: + index = ePLX_MBOX1; break; + case 2: + index = ePLX_MBOX2; break; + case 3: + index = ePLX_MBOX3; break; + case 4: + index = ePLX_MBOX4; break; + case 5: + index = ePLX_MBOX5; break; + case 6: + index = ePLX_MBOX6; break; + case 7: + index = ePLX_MBOX7; break; + case 0: /* reserved for HF flags */ + snd_BUG(); + default: + return 0xdeadbeef; + } + + return lx_plx_reg_read(chip, index); +} + +int lx_plx_mbox_write(struct lx6464es *chip, int mbox_nr, u32 value) +{ + int index = -1; + + switch (mbox_nr) { + case 1: + index = ePLX_MBOX1; break; + case 3: + index = ePLX_MBOX3; break; + case 4: + index = ePLX_MBOX4; break; + case 5: + index = ePLX_MBOX5; break; + case 6: + index = ePLX_MBOX6; break; + case 7: + index = ePLX_MBOX7; break; + case 0: /* reserved for HF flags */ + case 2: /* reserved for Pipe States + * the DSP keeps an image of it */ + snd_BUG(); + return -EBADRQC; + } + + lx_plx_reg_write(chip, index, value); + return 0; +} + + +/* rmh */ + +#ifdef CONFIG_SND_DEBUG +#define CMD_NAME(a) a +#else +#define CMD_NAME(a) NULL +#endif + +#define Reg_CSM_MR 0x00000002 +#define Reg_CSM_MC 0x00000001 + +struct dsp_cmd_info { + u32 dcCodeOp; /* Op Code of the command (usually 1st 24-bits + * word).*/ + u16 dcCmdLength; /* Command length in words of 24 bits.*/ + u16 dcStatusType; /* Status type: 0 for fixed length, 1 for + * random. */ + u16 dcStatusLength; /* Status length (if fixed).*/ + char *dcOpName; +}; + +/* + Initialization and control data for the Microblaze interface + - OpCode: + the opcode field of the command set at the proper offset + - CmdLength + the number of command words + - StatusType + offset in the status registers: 0 means that the return value may be + different from 0, and must be read + - StatusLength + the number of status words (in addition to the return value) +*/ + +static struct dsp_cmd_info dsp_commands[] = +{ + { (CMD_00_INFO_DEBUG << OPCODE_OFFSET) , 1 /*custom*/ + , 1 , 0 /**/ , CMD_NAME("INFO_DEBUG") }, + { (CMD_01_GET_SYS_CFG << OPCODE_OFFSET) , 1 /**/ + , 1 , 2 /**/ , CMD_NAME("GET_SYS_CFG") }, + { (CMD_02_SET_GRANULARITY << OPCODE_OFFSET) , 1 /**/ + , 1 , 0 /**/ , CMD_NAME("SET_GRANULARITY") }, + { (CMD_03_SET_TIMER_IRQ << OPCODE_OFFSET) , 1 /**/ + , 1 , 0 /**/ , CMD_NAME("SET_TIMER_IRQ") }, + { (CMD_04_GET_EVENT << OPCODE_OFFSET) , 1 /**/ + , 1 , 0 /*up to 10*/ , CMD_NAME("GET_EVENT") }, + { (CMD_05_GET_PIPES << OPCODE_OFFSET) , 1 /**/ + , 1 , 2 /*up to 4*/ , CMD_NAME("GET_PIPES") }, + { (CMD_06_ALLOCATE_PIPE << OPCODE_OFFSET) , 1 /**/ + , 0 , 0 /**/ , CMD_NAME("ALLOCATE_PIPE") }, + { (CMD_07_RELEASE_PIPE << OPCODE_OFFSET) , 1 /**/ + , 0 , 0 /**/ , CMD_NAME("RELEASE_PIPE") }, + { (CMD_08_ASK_BUFFERS << OPCODE_OFFSET) , 1 /**/ + , 1 , MAX_STREAM_BUFFER , CMD_NAME("ASK_BUFFERS") }, + { (CMD_09_STOP_PIPE << OPCODE_OFFSET) , 1 /**/ + , 0 , 0 /*up to 2*/ , CMD_NAME("STOP_PIPE") }, + { (CMD_0A_GET_PIPE_SPL_COUNT << OPCODE_OFFSET) , 1 /**/ + , 1 , 1 /*up to 2*/ , CMD_NAME("GET_PIPE_SPL_COUNT") }, + { (CMD_0B_TOGGLE_PIPE_STATE << OPCODE_OFFSET) , 1 /*up to 5*/ + , 1 , 0 /**/ , CMD_NAME("TOGGLE_PIPE_STATE") }, + { (CMD_0C_DEF_STREAM << OPCODE_OFFSET) , 1 /*up to 4*/ + , 1 , 0 /**/ , CMD_NAME("DEF_STREAM") }, + { (CMD_0D_SET_MUTE << OPCODE_OFFSET) , 3 /**/ + , 1 , 0 /**/ , CMD_NAME("SET_MUTE") }, + { (CMD_0E_GET_STREAM_SPL_COUNT << OPCODE_OFFSET) , 1/**/ + , 1 , 2 /**/ , CMD_NAME("GET_STREAM_SPL_COUNT") }, + { (CMD_0F_UPDATE_BUFFER << OPCODE_OFFSET) , 3 /*up to 4*/ + , 0 , 1 /**/ , CMD_NAME("UPDATE_BUFFER") }, + { (CMD_10_GET_BUFFER << OPCODE_OFFSET) , 1 /**/ + , 1 , 4 /**/ , CMD_NAME("GET_BUFFER") }, + { (CMD_11_CANCEL_BUFFER << OPCODE_OFFSET) , 1 /**/ + , 1 , 1 /*up to 4*/ , CMD_NAME("CANCEL_BUFFER") }, + { (CMD_12_GET_PEAK << OPCODE_OFFSET) , 1 /**/ + , 1 , 1 /**/ , CMD_NAME("GET_PEAK") }, + { (CMD_13_SET_STREAM_STATE << OPCODE_OFFSET) , 1 /**/ + , 1 , 0 /**/ , CMD_NAME("SET_STREAM_STATE") }, +}; + +static void lx_message_init(struct lx_rmh *rmh, enum cmd_mb_opcodes cmd) +{ + snd_BUG_ON(cmd >= CMD_14_INVALID); + + rmh->cmd[0] = dsp_commands[cmd].dcCodeOp; + rmh->cmd_len = dsp_commands[cmd].dcCmdLength; + rmh->stat_len = dsp_commands[cmd].dcStatusLength; + rmh->dsp_stat = dsp_commands[cmd].dcStatusType; + rmh->cmd_idx = cmd; + memset(&rmh->cmd[1], 0, (REG_CRM_NUMBER - 1) * sizeof(u32)); + +#ifdef CONFIG_SND_DEBUG + memset(rmh->stat, 0, REG_CRM_NUMBER * sizeof(u32)); +#endif +#ifdef RMH_DEBUG + rmh->cmd_idx = cmd; +#endif +} + +#ifdef RMH_DEBUG +#define LXRMH "lx6464es rmh: " +static void lx_message_dump(struct lx_rmh *rmh) +{ + u8 idx = rmh->cmd_idx; + int i; + + snd_printk(LXRMH "command %s\n", dsp_commands[idx].dcOpName); + + for (i = 0; i != rmh->cmd_len; ++i) + snd_printk(LXRMH "\tcmd[%d] %08x\n", i, rmh->cmd[i]); + + for (i = 0; i != rmh->stat_len; ++i) + snd_printk(LXRMH "\tstat[%d]: %08x\n", i, rmh->stat[i]); + snd_printk("\n"); +} +#else +static inline void lx_message_dump(struct lx_rmh *rmh) +{} +#endif + + + +/* sleep 500 - 100 = 400 times 100us -> the timeout is >= 40 ms */ +#define XILINX_TIMEOUT_MS 40 +#define XILINX_POLL_NO_SLEEP 100 +#define XILINX_POLL_ITERATIONS 150 + +#if 0 /* not used now */ +static int lx_message_send(struct lx6464es *chip, struct lx_rmh *rmh) +{ + u32 reg = ED_DSP_TIMED_OUT; + int dwloop; + int answer_received; + + if (lx_dsp_reg_read(chip, eReg_CSM) & (Reg_CSM_MC | Reg_CSM_MR)) { + snd_printk(KERN_ERR LXP "PIOSendMessage eReg_CSM %x\n", reg); + return -EBUSY; + } + + /* write command */ + lx_dsp_reg_writebuf(chip, eReg_CRM1, rmh->cmd, rmh->cmd_len); + + snd_BUG_ON(atomic_read(&chip->send_message_locked) != 0); + atomic_set(&chip->send_message_locked, 1); + + /* MicoBlaze gogogo */ + lx_dsp_reg_write(chip, eReg_CSM, Reg_CSM_MC); + + /* wait for interrupt to answer */ + for (dwloop = 0; dwloop != XILINX_TIMEOUT_MS; ++dwloop) { + answer_received = atomic_read(&chip->send_message_locked); + if (answer_received == 0) + break; + msleep(1); + } + + if (answer_received == 0) { + /* in Debug mode verify Reg_CSM_MR */ + snd_BUG_ON(!(lx_dsp_reg_read(chip, eReg_CSM) & Reg_CSM_MR)); + + /* command finished, read status */ + if (rmh->dsp_stat == 0) + reg = lx_dsp_reg_read(chip, eReg_CRM1); + else + reg = 0; + } else { + int i; + snd_printk(KERN_WARNING LXP "TIMEOUT lx_message_send! " + "Interrupts disabled?\n"); + + /* attente bit Reg_CSM_MR */ + for (i = 0; i != XILINX_POLL_ITERATIONS; i++) { + if ((lx_dsp_reg_read(chip, eReg_CSM) & Reg_CSM_MR)) { + if (rmh->dsp_stat == 0) + reg = lx_dsp_reg_read(chip, eReg_CRM1); + else + reg = 0; + goto polling_successful; + } + + if (i > XILINX_POLL_NO_SLEEP) + msleep(1); + } + snd_printk(KERN_WARNING LXP "TIMEOUT lx_message_send! " + "polling failed\n"); + +polling_successful: + atomic_set(&chip->send_message_locked, 0); + } + + if ((reg & ERROR_VALUE) == 0) { + /* read response */ + if (rmh->stat_len) { + snd_BUG_ON(rmh->stat_len >= (REG_CRM_NUMBER-1)); + + lx_dsp_reg_readbuf(chip, eReg_CRM2, rmh->stat, + rmh->stat_len); + } + } else + snd_printk(KERN_WARNING LXP "lx_message_send: error_value %x\n", + reg); + + /* clear Reg_CSM_MR */ + lx_dsp_reg_write(chip, eReg_CSM, 0); + + switch (reg) { + case ED_DSP_TIMED_OUT: + snd_printk(KERN_WARNING LXP "lx_message_send: dsp timeout\n"); + return -ETIMEDOUT; + + case ED_DSP_CRASHED: + snd_printk(KERN_WARNING LXP "lx_message_send: dsp crashed\n"); + return -EAGAIN; + } + + lx_message_dump(rmh); + return 0; +} +#endif /* not used now */ + +static int lx_message_send_atomic(struct lx6464es *chip, struct lx_rmh *rmh) +{ + u32 reg = ED_DSP_TIMED_OUT; + int dwloop; + + if (lx_dsp_reg_read(chip, eReg_CSM) & (Reg_CSM_MC | Reg_CSM_MR)) { + snd_printk(KERN_ERR LXP "PIOSendMessage eReg_CSM %x\n", reg); + return -EBUSY; + } + + /* write command */ + lx_dsp_reg_writebuf(chip, eReg_CRM1, rmh->cmd, rmh->cmd_len); + + /* MicoBlaze gogogo */ + lx_dsp_reg_write(chip, eReg_CSM, Reg_CSM_MC); + + /* wait for interrupt to answer */ + for (dwloop = 0; dwloop != XILINX_TIMEOUT_MS * 1000; ++dwloop) { + if (lx_dsp_reg_read(chip, eReg_CSM) & Reg_CSM_MR) { + if (rmh->dsp_stat == 0) + reg = lx_dsp_reg_read(chip, eReg_CRM1); + else + reg = 0; + goto polling_successful; + } else + udelay(1); + } + snd_printk(KERN_WARNING LXP "TIMEOUT lx_message_send_atomic! " + "polling failed\n"); + +polling_successful: + if ((reg & ERROR_VALUE) == 0) { + /* read response */ + if (rmh->stat_len) { + snd_BUG_ON(rmh->stat_len >= (REG_CRM_NUMBER-1)); + lx_dsp_reg_readbuf(chip, eReg_CRM2, rmh->stat, + rmh->stat_len); + } + } else + snd_printk(LXP "rmh error: %08x\n", reg); + + /* clear Reg_CSM_MR */ + lx_dsp_reg_write(chip, eReg_CSM, 0); + + switch (reg) { + case ED_DSP_TIMED_OUT: + snd_printk(KERN_WARNING LXP "lx_message_send: dsp timeout\n"); + return -ETIMEDOUT; + + case ED_DSP_CRASHED: + snd_printk(KERN_WARNING LXP "lx_message_send: dsp crashed\n"); + return -EAGAIN; + } + + lx_message_dump(rmh); + + return reg; +} + + +/* low-level dsp access */ +int __devinit lx_dsp_get_version(struct lx6464es *chip, u32 *rdsp_version) +{ + u16 ret; + unsigned long flags; + + spin_lock_irqsave(&chip->msg_lock, flags); + + lx_message_init(&chip->rmh, CMD_01_GET_SYS_CFG); + ret = lx_message_send_atomic(chip, &chip->rmh); + + *rdsp_version = chip->rmh.stat[1]; + spin_unlock_irqrestore(&chip->msg_lock, flags); + return ret; +} + +int lx_dsp_get_clock_frequency(struct lx6464es *chip, u32 *rfreq) +{ + u16 ret = 0; + unsigned long flags; + u32 freq_raw = 0; + u32 freq = 0; + u32 frequency = 0; + + spin_lock_irqsave(&chip->msg_lock, flags); + + lx_message_init(&chip->rmh, CMD_01_GET_SYS_CFG); + ret = lx_message_send_atomic(chip, &chip->rmh); + + if (ret == 0) { + freq_raw = chip->rmh.stat[0] >> FREQ_FIELD_OFFSET; + freq = freq_raw & XES_FREQ_COUNT8_MASK; + + if ((freq < XES_FREQ_COUNT8_48_MAX) || + (freq > XES_FREQ_COUNT8_44_MIN)) + frequency = 0; /* unknown */ + else if (freq >= XES_FREQ_COUNT8_44_MAX) + frequency = 44100; + else + frequency = 48000; + } + + spin_unlock_irqrestore(&chip->msg_lock, flags); + + *rfreq = frequency * chip->freq_ratio; + + return ret; +} + +int lx_dsp_get_mac(struct lx6464es *chip, u8 *mac_address) +{ + u32 macmsb, maclsb; + + macmsb = lx_dsp_reg_read(chip, eReg_ADMACESMSB) & 0x00FFFFFF; + maclsb = lx_dsp_reg_read(chip, eReg_ADMACESLSB) & 0x00FFFFFF; + + /* todo: endianess handling */ + mac_address[5] = ((u8 *)(&maclsb))[0]; + mac_address[4] = ((u8 *)(&maclsb))[1]; + mac_address[3] = ((u8 *)(&maclsb))[2]; + mac_address[2] = ((u8 *)(&macmsb))[0]; + mac_address[1] = ((u8 *)(&macmsb))[1]; + mac_address[0] = ((u8 *)(&macmsb))[2]; + + return 0; +} + + +int lx_dsp_set_granularity(struct lx6464es *chip, u32 gran) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&chip->msg_lock, flags); + + lx_message_init(&chip->rmh, CMD_02_SET_GRANULARITY); + chip->rmh.cmd[0] |= gran; + + ret = lx_message_send_atomic(chip, &chip->rmh); + spin_unlock_irqrestore(&chip->msg_lock, flags); + return ret; +} + +int lx_dsp_read_async_events(struct lx6464es *chip, u32 *data) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&chip->msg_lock, flags); + + lx_message_init(&chip->rmh, CMD_04_GET_EVENT); + chip->rmh.stat_len = 9; /* we don't necessarily need the full length */ + + ret = lx_message_send_atomic(chip, &chip->rmh); + + if (!ret) + memcpy(data, chip->rmh.stat, chip->rmh.stat_len * sizeof(u32)); + + spin_unlock_irqrestore(&chip->msg_lock, flags); + return ret; +} + +#define CSES_TIMEOUT 100 /* microseconds */ +#define CSES_CE 0x0001 +#define CSES_BROADCAST 0x0002 +#define CSES_UPDATE_LDSV 0x0004 + +int lx_dsp_es_check_pipeline(struct lx6464es *chip) +{ + int i; + + for (i = 0; i != CSES_TIMEOUT; ++i) { + /* + * le bit CSES_UPDATE_LDSV est à 1 dés que le macprog + * est pret. il re-passe à 0 lorsque le premier read a + * été fait. pour l'instant on retire le test car ce bit + * passe a 1 environ 200 à 400 ms aprés que le registre + * confES à été écrit (kick du xilinx ES). + * + * On ne teste que le bit CE. + * */ + + u32 cses = lx_dsp_reg_read(chip, eReg_CSES); + + if ((cses & CSES_CE) == 0) + return 0; + + udelay(1); + } + + return -ETIMEDOUT; +} + + +#define PIPE_INFO_TO_CMD(capture, pipe) \ + ((u32)((u32)(pipe) | ((capture) ? ID_IS_CAPTURE : 0L)) << ID_OFFSET) + + + +/* low-level pipe handling */ +int lx_pipe_allocate(struct lx6464es *chip, u32 pipe, int is_capture, + int channels) +{ + int err; + unsigned long flags; + + u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); + + spin_lock_irqsave(&chip->msg_lock, flags); + lx_message_init(&chip->rmh, CMD_06_ALLOCATE_PIPE); + + chip->rmh.cmd[0] |= pipe_cmd; + chip->rmh.cmd[0] |= channels; + + err = lx_message_send_atomic(chip, &chip->rmh); + spin_unlock_irqrestore(&chip->msg_lock, flags); + + if (err != 0) + snd_printk(KERN_ERR "lx6464es: could not allocate pipe\n"); + + return err; +} + +int lx_pipe_release(struct lx6464es *chip, u32 pipe, int is_capture) +{ + int err; + unsigned long flags; + + u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); + + spin_lock_irqsave(&chip->msg_lock, flags); + lx_message_init(&chip->rmh, CMD_07_RELEASE_PIPE); + + chip->rmh.cmd[0] |= pipe_cmd; + + err = lx_message_send_atomic(chip, &chip->rmh); + spin_unlock_irqrestore(&chip->msg_lock, flags); + + return err; +} + +int lx_buffer_ask(struct lx6464es *chip, u32 pipe, int is_capture, + u32 *r_needed, u32 *r_freed, u32 *size_array) +{ + int err; + unsigned long flags; + + u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); + +#ifdef CONFIG_SND_DEBUG + if (size_array) + memset(size_array, 0, sizeof(u32)*MAX_STREAM_BUFFER); +#endif + + *r_needed = 0; + *r_freed = 0; + + spin_lock_irqsave(&chip->msg_lock, flags); + lx_message_init(&chip->rmh, CMD_08_ASK_BUFFERS); + + chip->rmh.cmd[0] |= pipe_cmd; + + err = lx_message_send_atomic(chip, &chip->rmh); + + if (!err) { + int i; + for (i = 0; i < MAX_STREAM_BUFFER; ++i) { + u32 stat = chip->rmh.stat[i]; + if (stat & (BF_EOB << BUFF_FLAGS_OFFSET)) { + /* finished */ + *r_freed += 1; + if (size_array) + size_array[i] = stat & MASK_DATA_SIZE; + } else if ((stat & (BF_VALID << BUFF_FLAGS_OFFSET)) + == 0) + /* free */ + *r_needed += 1; + } + +#if 0 + snd_printdd(LXP "CMD_08_ASK_BUFFERS: needed %d, freed %d\n", + *r_needed, *r_freed); + for (i = 0; i < MAX_STREAM_BUFFER; ++i) { + for (i = 0; i != chip->rmh.stat_len; ++i) + snd_printdd(" stat[%d]: %x, %x\n", i, + chip->rmh.stat[i], + chip->rmh.stat[i] & MASK_DATA_SIZE); + } +#endif + } + + spin_unlock_irqrestore(&chip->msg_lock, flags); + return err; +} + + +int lx_pipe_stop(struct lx6464es *chip, u32 pipe, int is_capture) +{ + int err; + unsigned long flags; + + u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); + + spin_lock_irqsave(&chip->msg_lock, flags); + lx_message_init(&chip->rmh, CMD_09_STOP_PIPE); + + chip->rmh.cmd[0] |= pipe_cmd; + + err = lx_message_send_atomic(chip, &chip->rmh); + + spin_unlock_irqrestore(&chip->msg_lock, flags); + return err; +} + +static int lx_pipe_toggle_state(struct lx6464es *chip, u32 pipe, int is_capture) +{ + int err; + unsigned long flags; + + u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); + + spin_lock_irqsave(&chip->msg_lock, flags); + lx_message_init(&chip->rmh, CMD_0B_TOGGLE_PIPE_STATE); + + chip->rmh.cmd[0] |= pipe_cmd; + + err = lx_message_send_atomic(chip, &chip->rmh); + + spin_unlock_irqrestore(&chip->msg_lock, flags); + return err; +} + + +int lx_pipe_start(struct lx6464es *chip, u32 pipe, int is_capture) +{ + int err; + + err = lx_pipe_wait_for_idle(chip, pipe, is_capture); + if (err < 0) + return err; + + err = lx_pipe_toggle_state(chip, pipe, is_capture); + + return err; +} + +int lx_pipe_pause(struct lx6464es *chip, u32 pipe, int is_capture) +{ + int err = 0; + + err = lx_pipe_wait_for_start(chip, pipe, is_capture); + if (err < 0) + return err; + + err = lx_pipe_toggle_state(chip, pipe, is_capture); + + return err; +} + + +int lx_pipe_sample_count(struct lx6464es *chip, u32 pipe, int is_capture, + u64 *rsample_count) +{ + int err; + unsigned long flags; + + u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); + + spin_lock_irqsave(&chip->msg_lock, flags); + lx_message_init(&chip->rmh, CMD_0A_GET_PIPE_SPL_COUNT); + + chip->rmh.cmd[0] |= pipe_cmd; + chip->rmh.stat_len = 2; /* need all words here! */ + + err = lx_message_send_atomic(chip, &chip->rmh); /* don't sleep! */ + + if (err != 0) + snd_printk(KERN_ERR + "lx6464es: could not query pipe's sample count\n"); + else { + *rsample_count = ((u64)(chip->rmh.stat[0] & MASK_SPL_COUNT_HI) + << 24) /* hi part */ + + chip->rmh.stat[1]; /* lo part */ + } + + spin_unlock_irqrestore(&chip->msg_lock, flags); + return err; +} + +int lx_pipe_state(struct lx6464es *chip, u32 pipe, int is_capture, u16 *rstate) +{ + int err; + unsigned long flags; + + u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); + + spin_lock_irqsave(&chip->msg_lock, flags); + lx_message_init(&chip->rmh, CMD_0A_GET_PIPE_SPL_COUNT); + + chip->rmh.cmd[0] |= pipe_cmd; + + err = lx_message_send_atomic(chip, &chip->rmh); + + if (err != 0) + snd_printk(KERN_ERR "lx6464es: could not query pipe's state\n"); + else + *rstate = (chip->rmh.stat[0] >> PSTATE_OFFSET) & 0x0F; + + spin_unlock_irqrestore(&chip->msg_lock, flags); + return err; +} + +static int lx_pipe_wait_for_state(struct lx6464es *chip, u32 pipe, + int is_capture, u16 state) +{ + int i; + + /* max 2*PCMOnlyGranularity = 2*1024 at 44100 = < 50 ms: + * timeout 50 ms */ + for (i = 0; i != 50; ++i) { + u16 current_state; + int err = lx_pipe_state(chip, pipe, is_capture, ¤t_state); + + if (err < 0) + return err; + + if (current_state == state) + return 0; + + mdelay(1); + } + + return -ETIMEDOUT; +} + +int lx_pipe_wait_for_start(struct lx6464es *chip, u32 pipe, int is_capture) +{ + return lx_pipe_wait_for_state(chip, pipe, is_capture, PSTATE_RUN); +} + +int lx_pipe_wait_for_idle(struct lx6464es *chip, u32 pipe, int is_capture) +{ + return lx_pipe_wait_for_state(chip, pipe, is_capture, PSTATE_IDLE); +} + +/* low-level stream handling */ +int lx_stream_set_state(struct lx6464es *chip, u32 pipe, + int is_capture, enum stream_state_t state) +{ + int err; + unsigned long flags; + + u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); + + spin_lock_irqsave(&chip->msg_lock, flags); + lx_message_init(&chip->rmh, CMD_13_SET_STREAM_STATE); + + chip->rmh.cmd[0] |= pipe_cmd; + chip->rmh.cmd[0] |= state; + + err = lx_message_send_atomic(chip, &chip->rmh); + spin_unlock_irqrestore(&chip->msg_lock, flags); + + return err; +} + +int lx_stream_set_format(struct lx6464es *chip, struct snd_pcm_runtime *runtime, + u32 pipe, int is_capture) +{ + int err; + unsigned long flags; + + u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); + + u32 channels = runtime->channels; + + if (runtime->channels != channels) + snd_printk(KERN_ERR LXP "channel count mismatch: %d vs %d", + runtime->channels, channels); + + spin_lock_irqsave(&chip->msg_lock, flags); + lx_message_init(&chip->rmh, CMD_0C_DEF_STREAM); + + chip->rmh.cmd[0] |= pipe_cmd; + + if (runtime->sample_bits == 16) + /* 16 bit format */ + chip->rmh.cmd[0] |= (STREAM_FMT_16b << STREAM_FMT_OFFSET); + + if (snd_pcm_format_little_endian(runtime->format)) + /* little endian/intel format */ + chip->rmh.cmd[0] |= (STREAM_FMT_intel << STREAM_FMT_OFFSET); + + chip->rmh.cmd[0] |= channels-1; + + err = lx_message_send_atomic(chip, &chip->rmh); + spin_unlock_irqrestore(&chip->msg_lock, flags); + + return err; +} + +int lx_stream_state(struct lx6464es *chip, u32 pipe, int is_capture, + int *rstate) +{ + int err; + unsigned long flags; + + u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); + + spin_lock_irqsave(&chip->msg_lock, flags); + lx_message_init(&chip->rmh, CMD_0E_GET_STREAM_SPL_COUNT); + + chip->rmh.cmd[0] |= pipe_cmd; + + err = lx_message_send_atomic(chip, &chip->rmh); + + *rstate = (chip->rmh.stat[0] & SF_START) ? START_STATE : PAUSE_STATE; + + spin_unlock_irqrestore(&chip->msg_lock, flags); + return err; +} + +int lx_stream_sample_position(struct lx6464es *chip, u32 pipe, int is_capture, + u64 *r_bytepos) +{ + int err; + unsigned long flags; + + u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); + + spin_lock_irqsave(&chip->msg_lock, flags); + lx_message_init(&chip->rmh, CMD_0E_GET_STREAM_SPL_COUNT); + + chip->rmh.cmd[0] |= pipe_cmd; + + err = lx_message_send_atomic(chip, &chip->rmh); + + *r_bytepos = ((u64) (chip->rmh.stat[0] & MASK_SPL_COUNT_HI) + << 32) /* hi part */ + + chip->rmh.stat[1]; /* lo part */ + + spin_unlock_irqrestore(&chip->msg_lock, flags); + return err; +} + +/* low-level buffer handling */ +int lx_buffer_give(struct lx6464es *chip, u32 pipe, int is_capture, + u32 buffer_size, u32 buf_address_lo, u32 buf_address_hi, + u32 *r_buffer_index) +{ + int err; + unsigned long flags; + + u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); + + spin_lock_irqsave(&chip->msg_lock, flags); + lx_message_init(&chip->rmh, CMD_0F_UPDATE_BUFFER); + + chip->rmh.cmd[0] |= pipe_cmd; + chip->rmh.cmd[0] |= BF_NOTIFY_EOB; /* request interrupt notification */ + + /* todo: pause request, circular buffer */ + + chip->rmh.cmd[1] = buffer_size & MASK_DATA_SIZE; + chip->rmh.cmd[2] = buf_address_lo; + + if (buf_address_hi) { + chip->rmh.cmd_len = 4; + chip->rmh.cmd[3] = buf_address_hi; + chip->rmh.cmd[0] |= BF_64BITS_ADR; + } + + err = lx_message_send_atomic(chip, &chip->rmh); + + if (err == 0) { + *r_buffer_index = chip->rmh.stat[0]; + goto done; + } + + if (err == EB_RBUFFERS_TABLE_OVERFLOW) + snd_printk(LXP "lx_buffer_give EB_RBUFFERS_TABLE_OVERFLOW\n"); + + if (err == EB_INVALID_STREAM) + snd_printk(LXP "lx_buffer_give EB_INVALID_STREAM\n"); + + if (err == EB_CMD_REFUSED) + snd_printk(LXP "lx_buffer_give EB_CMD_REFUSED\n"); + + done: + spin_unlock_irqrestore(&chip->msg_lock, flags); + return err; +} + +int lx_buffer_free(struct lx6464es *chip, u32 pipe, int is_capture, + u32 *r_buffer_size) +{ + int err; + unsigned long flags; + + u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); + + spin_lock_irqsave(&chip->msg_lock, flags); + lx_message_init(&chip->rmh, CMD_11_CANCEL_BUFFER); + + chip->rmh.cmd[0] |= pipe_cmd; + chip->rmh.cmd[0] |= MASK_BUFFER_ID; /* ask for the current buffer: the + * microblaze will seek for it */ + + err = lx_message_send_atomic(chip, &chip->rmh); + + if (err == 0) + *r_buffer_size = chip->rmh.stat[0] & MASK_DATA_SIZE; + + spin_unlock_irqrestore(&chip->msg_lock, flags); + return err; +} + +int lx_buffer_cancel(struct lx6464es *chip, u32 pipe, int is_capture, + u32 buffer_index) +{ + int err; + unsigned long flags; + + u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); + + spin_lock_irqsave(&chip->msg_lock, flags); + lx_message_init(&chip->rmh, CMD_11_CANCEL_BUFFER); + + chip->rmh.cmd[0] |= pipe_cmd; + chip->rmh.cmd[0] |= buffer_index; + + err = lx_message_send_atomic(chip, &chip->rmh); + + spin_unlock_irqrestore(&chip->msg_lock, flags); + return err; +} + + +/* low-level gain/peak handling + * + * \todo: can we unmute capture/playback channels independently? + * + * */ +int lx_level_unmute(struct lx6464es *chip, int is_capture, int unmute) +{ + int err; + unsigned long flags; + + /* bit set to 1: channel muted */ + u64 mute_mask = unmute ? 0 : 0xFFFFFFFFFFFFFFFFLLU; + + spin_lock_irqsave(&chip->msg_lock, flags); + lx_message_init(&chip->rmh, CMD_0D_SET_MUTE); + + chip->rmh.cmd[0] |= PIPE_INFO_TO_CMD(is_capture, 0); + + chip->rmh.cmd[1] = (u32)(mute_mask >> (u64)32); /* hi part */ + chip->rmh.cmd[2] = (u32)(mute_mask & (u64)0xFFFFFFFF); /* lo part */ + + snd_printk("mute %x %x %x\n", chip->rmh.cmd[0], chip->rmh.cmd[1], + chip->rmh.cmd[2]); + + err = lx_message_send_atomic(chip, &chip->rmh); + + spin_unlock_irqrestore(&chip->msg_lock, flags); + return err; +} + +static u32 peak_map[] = { + 0x00000109, /* -90.308dB */ + 0x0000083B, /* -72.247dB */ + 0x000020C4, /* -60.205dB */ + 0x00008273, /* -48.030dB */ + 0x00020756, /* -36.005dB */ + 0x00040C37, /* -30.001dB */ + 0x00081385, /* -24.002dB */ + 0x00101D3F, /* -18.000dB */ + 0x0016C310, /* -15.000dB */ + 0x002026F2, /* -12.001dB */ + 0x002D6A86, /* -9.000dB */ + 0x004026E6, /* -6.004dB */ + 0x005A9DF6, /* -3.000dB */ + 0x0065AC8B, /* -2.000dB */ + 0x00721481, /* -1.000dB */ + 0x007FFFFF, /* FS */ +}; + +int lx_level_peaks(struct lx6464es *chip, int is_capture, int channels, + u32 *r_levels) +{ + int err = 0; + unsigned long flags; + int i; + spin_lock_irqsave(&chip->msg_lock, flags); + + for (i = 0; i < channels; i += 4) { + u32 s0, s1, s2, s3; + + lx_message_init(&chip->rmh, CMD_12_GET_PEAK); + chip->rmh.cmd[0] |= PIPE_INFO_TO_CMD(is_capture, i); + + err = lx_message_send_atomic(chip, &chip->rmh); + + if (err == 0) { + s0 = peak_map[chip->rmh.stat[0] & 0x0F]; + s1 = peak_map[(chip->rmh.stat[0] >> 4) & 0xf]; + s2 = peak_map[(chip->rmh.stat[0] >> 8) & 0xf]; + s3 = peak_map[(chip->rmh.stat[0] >> 12) & 0xf]; + } else + s0 = s1 = s2 = s3 = 0; + + r_levels[0] = s0; + r_levels[1] = s1; + r_levels[2] = s2; + r_levels[3] = s3; + + r_levels += 4; + } + + spin_unlock_irqrestore(&chip->msg_lock, flags); + return err; +} + +/* interrupt handling */ +#define PCX_IRQ_NONE 0 +#define IRQCS_ACTIVE_PCIDB 0x00002000L /* Bit nø 13 */ +#define IRQCS_ENABLE_PCIIRQ 0x00000100L /* Bit nø 08 */ +#define IRQCS_ENABLE_PCIDB 0x00000200L /* Bit nø 09 */ + +static u32 lx_interrupt_test_ack(struct lx6464es *chip) +{ + u32 irqcs = lx_plx_reg_read(chip, ePLX_IRQCS); + + /* Test if PCI Doorbell interrupt is active */ + if (irqcs & IRQCS_ACTIVE_PCIDB) { + u32 temp; + irqcs = PCX_IRQ_NONE; + + while ((temp = lx_plx_reg_read(chip, ePLX_L2PCIDB))) { + /* RAZ interrupt */ + irqcs |= temp; + lx_plx_reg_write(chip, ePLX_L2PCIDB, temp); + } + + return irqcs; + } + return PCX_IRQ_NONE; +} + +static int lx_interrupt_ack(struct lx6464es *chip, u32 *r_irqsrc, + int *r_async_pending, int *r_async_escmd) +{ + u32 irq_async; + u32 irqsrc = lx_interrupt_test_ack(chip); + + if (irqsrc == PCX_IRQ_NONE) + return 0; + + *r_irqsrc = irqsrc; + + irq_async = irqsrc & MASK_SYS_ASYNC_EVENTS; /* + EtherSound response + * (set by xilinx) + EOB */ + + if (irq_async & MASK_SYS_STATUS_ESA) { + irq_async &= ~MASK_SYS_STATUS_ESA; + *r_async_escmd = 1; + } + + if (irqsrc & MASK_SYS_STATUS_CMD_DONE) + /* xilinx command notification */ + atomic_set(&chip->send_message_locked, 0); + + if (irq_async) { + /* snd_printd("interrupt: async event pending\n"); */ + *r_async_pending = 1; + } + + return 1; +} + +static int lx_interrupt_handle_async_events(struct lx6464es *chip, u32 irqsrc, + int *r_freq_changed, + u64 *r_notified_in_pipe_mask, + u64 *r_notified_out_pipe_mask) +{ + int err; + u32 stat[9]; /* answer from CMD_04_GET_EVENT */ + + /* On peut optimiser pour ne pas lire les evenements vides + * les mots de réponse sont dans l'ordre suivant : + * Stat[0] mot de status général + * Stat[1] fin de buffer OUT pF + * Stat[2] fin de buffer OUT pf + * Stat[3] fin de buffer IN pF + * Stat[4] fin de buffer IN pf + * Stat[5] underrun poid fort + * Stat[6] underrun poid faible + * Stat[7] overrun poid fort + * Stat[8] overrun poid faible + * */ + + u64 orun_mask; + u64 urun_mask; +#if 0 + int has_underrun = (irqsrc & MASK_SYS_STATUS_URUN) ? 1 : 0; + int has_overrun = (irqsrc & MASK_SYS_STATUS_ORUN) ? 1 : 0; +#endif + int eb_pending_out = (irqsrc & MASK_SYS_STATUS_EOBO) ? 1 : 0; + int eb_pending_in = (irqsrc & MASK_SYS_STATUS_EOBI) ? 1 : 0; + + *r_freq_changed = (irqsrc & MASK_SYS_STATUS_FREQ) ? 1 : 0; + + err = lx_dsp_read_async_events(chip, stat); + if (err < 0) + return err; + + if (eb_pending_in) { + *r_notified_in_pipe_mask = ((u64)stat[3] << 32) + + stat[4]; + snd_printdd(LXP "interrupt: EOBI pending %llx\n", + *r_notified_in_pipe_mask); + } + if (eb_pending_out) { + *r_notified_out_pipe_mask = ((u64)stat[1] << 32) + + stat[2]; + snd_printdd(LXP "interrupt: EOBO pending %llx\n", + *r_notified_out_pipe_mask); + } + + orun_mask = ((u64)stat[7] << 32) + stat[8]; + urun_mask = ((u64)stat[5] << 32) + stat[6]; + + /* todo: handle xrun notification */ + + return err; +} + +static int lx_interrupt_request_new_buffer(struct lx6464es *chip, + struct lx_stream *lx_stream) +{ + struct snd_pcm_substream *substream = lx_stream->stream; + int is_capture = lx_stream->is_capture; + int err; + unsigned long flags; + + const u32 channels = substream->runtime->channels; + const u32 bytes_per_frame = channels * 3; + const u32 period_size = substream->runtime->period_size; + const u32 period_bytes = period_size * bytes_per_frame; + const u32 pos = lx_stream->frame_pos; + const u32 next_pos = ((pos+1) == substream->runtime->periods) ? + 0 : pos + 1; + + dma_addr_t buf = substream->dma_buffer.addr + pos * period_bytes; + u32 buf_hi = 0; + u32 buf_lo = 0; + u32 buffer_index = 0; + + u32 needed, freed; + u32 size_array[MAX_STREAM_BUFFER]; + + snd_printdd("->lx_interrupt_request_new_buffer\n"); + + spin_lock_irqsave(&chip->lock, flags); + + err = lx_buffer_ask(chip, 0, is_capture, &needed, &freed, size_array); + snd_printdd(LXP "interrupt: needed %d, freed %d\n", needed, freed); + + unpack_pointer(buf, &buf_lo, &buf_hi); + err = lx_buffer_give(chip, 0, is_capture, period_bytes, buf_lo, buf_hi, + &buffer_index); + snd_printdd(LXP "interrupt: gave buffer index %x on %p (%d bytes)\n", + buffer_index, (void *)buf, period_bytes); + + lx_stream->frame_pos = next_pos; + spin_unlock_irqrestore(&chip->lock, flags); + + return err; +} + +void lx_tasklet_playback(unsigned long data) +{ + struct lx6464es *chip = (struct lx6464es *)data; + struct lx_stream *lx_stream = &chip->playback_stream; + int err; + + snd_printdd("->lx_tasklet_playback\n"); + + err = lx_interrupt_request_new_buffer(chip, lx_stream); + if (err < 0) + snd_printk(KERN_ERR LXP + "cannot request new buffer for playback\n"); + + snd_pcm_period_elapsed(lx_stream->stream); +} + +void lx_tasklet_capture(unsigned long data) +{ + struct lx6464es *chip = (struct lx6464es *)data; + struct lx_stream *lx_stream = &chip->capture_stream; + int err; + + snd_printdd("->lx_tasklet_capture\n"); + err = lx_interrupt_request_new_buffer(chip, lx_stream); + if (err < 0) + snd_printk(KERN_ERR LXP + "cannot request new buffer for capture\n"); + + snd_pcm_period_elapsed(lx_stream->stream); +} + + + +static int lx_interrupt_handle_audio_transfer(struct lx6464es *chip, + u64 notified_in_pipe_mask, + u64 notified_out_pipe_mask) +{ + int err = 0; + + if (notified_in_pipe_mask) { + snd_printdd(LXP "requesting audio transfer for capture\n"); + tasklet_hi_schedule(&chip->tasklet_capture); + } + + if (notified_out_pipe_mask) { + snd_printdd(LXP "requesting audio transfer for playback\n"); + tasklet_hi_schedule(&chip->tasklet_playback); + } + + return err; +} + + +irqreturn_t lx_interrupt(int irq, void *dev_id) +{ + struct lx6464es *chip = dev_id; + int async_pending, async_escmd; + u32 irqsrc; + + spin_lock(&chip->lock); + + snd_printdd("**************************************************\n"); + + if (!lx_interrupt_ack(chip, &irqsrc, &async_pending, &async_escmd)) { + spin_unlock(&chip->lock); + snd_printdd("IRQ_NONE\n"); + return IRQ_NONE; /* this device did not cause the interrupt */ + } + + if (irqsrc & MASK_SYS_STATUS_CMD_DONE) + goto exit; + +#if 0 + if (irqsrc & MASK_SYS_STATUS_EOBI) + snd_printdd(LXP "interrupt: EOBI\n"); + + if (irqsrc & MASK_SYS_STATUS_EOBO) + snd_printdd(LXP "interrupt: EOBO\n"); + + if (irqsrc & MASK_SYS_STATUS_URUN) + snd_printdd(LXP "interrupt: URUN\n"); + + if (irqsrc & MASK_SYS_STATUS_ORUN) + snd_printdd(LXP "interrupt: ORUN\n"); +#endif + + if (async_pending) { + u64 notified_in_pipe_mask = 0; + u64 notified_out_pipe_mask = 0; + int freq_changed; + int err; + + /* handle async events */ + err = lx_interrupt_handle_async_events(chip, irqsrc, + &freq_changed, + ¬ified_in_pipe_mask, + ¬ified_out_pipe_mask); + if (err) + snd_printk(KERN_ERR LXP + "error handling async events\n"); + + err = lx_interrupt_handle_audio_transfer(chip, + notified_in_pipe_mask, + notified_out_pipe_mask + ); + if (err) + snd_printk(KERN_ERR LXP + "error during audio transfer\n"); + } + + if (async_escmd) { +#if 0 + /* backdoor for ethersound commands + * + * for now, we do not need this + * + * */ + + snd_printdd("lx6464es: interrupt requests escmd handling\n"); +#endif + } + +exit: + spin_unlock(&chip->lock); + return IRQ_HANDLED; /* this device caused the interrupt */ +} + + +static void lx_irq_set(struct lx6464es *chip, int enable) +{ + u32 reg = lx_plx_reg_read(chip, ePLX_IRQCS); + + /* enable/disable interrupts + * + * Set the Doorbell and PCI interrupt enable bits + * + * */ + if (enable) + reg |= (IRQCS_ENABLE_PCIIRQ | IRQCS_ENABLE_PCIDB); + else + reg &= ~(IRQCS_ENABLE_PCIIRQ | IRQCS_ENABLE_PCIDB); + lx_plx_reg_write(chip, ePLX_IRQCS, reg); +} + +void lx_irq_enable(struct lx6464es *chip) +{ + snd_printdd("->lx_irq_enable\n"); + lx_irq_set(chip, 1); +} + +void lx_irq_disable(struct lx6464es *chip) +{ + snd_printdd("->lx_irq_disable\n"); + lx_irq_set(chip, 0); +} diff --git a/sound/pci/lx6464es/lx_core.h b/sound/pci/lx6464es/lx_core.h new file mode 100644 index 000000000000..6bd9cbbbc68d --- /dev/null +++ b/sound/pci/lx6464es/lx_core.h @@ -0,0 +1,242 @@ +/* -*- linux-c -*- * + * + * ALSA driver for the digigram lx6464es interface + * low-level interface + * + * Copyright (c) 2009 Tim Blechmann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#ifndef LX_CORE_H +#define LX_CORE_H + +#include + +#include "lx_defs.h" + +#define REG_CRM_NUMBER 12 + +struct lx6464es; + +/* low-level register access */ + +/* dsp register access */ +enum { + eReg_BASE, + eReg_CSM, + eReg_CRM1, + eReg_CRM2, + eReg_CRM3, + eReg_CRM4, + eReg_CRM5, + eReg_CRM6, + eReg_CRM7, + eReg_CRM8, + eReg_CRM9, + eReg_CRM10, + eReg_CRM11, + eReg_CRM12, + + eReg_ICR, + eReg_CVR, + eReg_ISR, + eReg_RXHTXH, + eReg_RXMTXM, + eReg_RHLTXL, + eReg_RESETDSP, + + eReg_CSUF, + eReg_CSES, + eReg_CRESMSB, + eReg_CRESLSB, + eReg_ADMACESMSB, + eReg_ADMACESLSB, + eReg_CONFES, + + eMaxPortLx +}; + +unsigned long lx_dsp_reg_read(struct lx6464es *chip, int port); +void lx_dsp_reg_readbuf(struct lx6464es *chip, int port, u32 *data, u32 len); +void lx_dsp_reg_write(struct lx6464es *chip, int port, unsigned data); +void lx_dsp_reg_writebuf(struct lx6464es *chip, int port, const u32 *data, + u32 len); + +/* plx register access */ +enum { + ePLX_PCICR, + + ePLX_MBOX0, + ePLX_MBOX1, + ePLX_MBOX2, + ePLX_MBOX3, + ePLX_MBOX4, + ePLX_MBOX5, + ePLX_MBOX6, + ePLX_MBOX7, + + ePLX_L2PCIDB, + ePLX_IRQCS, + ePLX_CHIPSC, + + eMaxPort +}; + +unsigned long lx_plx_reg_read(struct lx6464es *chip, int port); +void lx_plx_reg_write(struct lx6464es *chip, int port, u32 data); + +/* rhm */ +struct lx_rmh { + u16 cmd_len; /* length of the command to send (WORDs) */ + u16 stat_len; /* length of the status received (WORDs) */ + u16 dsp_stat; /* status type, RMP_SSIZE_XXX */ + u16 cmd_idx; /* index of the command */ + u32 cmd[REG_CRM_NUMBER]; + u32 stat[REG_CRM_NUMBER]; +}; + + +/* low-level dsp access */ +int __devinit lx_dsp_get_version(struct lx6464es *chip, u32 *rdsp_version); +int lx_dsp_get_clock_frequency(struct lx6464es *chip, u32 *rfreq); +int lx_dsp_set_granularity(struct lx6464es *chip, u32 gran); +int lx_dsp_read_async_events(struct lx6464es *chip, u32 *data); +int lx_dsp_get_mac(struct lx6464es *chip, u8 *mac_address); + + +/* low-level pipe handling */ +int lx_pipe_allocate(struct lx6464es *chip, u32 pipe, int is_capture, + int channels); +int lx_pipe_release(struct lx6464es *chip, u32 pipe, int is_capture); +int lx_pipe_sample_count(struct lx6464es *chip, u32 pipe, int is_capture, + u64 *rsample_count); +int lx_pipe_state(struct lx6464es *chip, u32 pipe, int is_capture, u16 *rstate); +int lx_pipe_stop(struct lx6464es *chip, u32 pipe, int is_capture); +int lx_pipe_start(struct lx6464es *chip, u32 pipe, int is_capture); +int lx_pipe_pause(struct lx6464es *chip, u32 pipe, int is_capture); + +int lx_pipe_wait_for_start(struct lx6464es *chip, u32 pipe, int is_capture); +int lx_pipe_wait_for_idle(struct lx6464es *chip, u32 pipe, int is_capture); + +/* low-level stream handling */ +int lx_stream_set_format(struct lx6464es *chip, struct snd_pcm_runtime *runtime, + u32 pipe, int is_capture); +int lx_stream_state(struct lx6464es *chip, u32 pipe, int is_capture, + int *rstate); +int lx_stream_sample_position(struct lx6464es *chip, u32 pipe, int is_capture, + u64 *r_bytepos); + +int lx_stream_set_state(struct lx6464es *chip, u32 pipe, + int is_capture, enum stream_state_t state); + +static inline int lx_stream_start(struct lx6464es *chip, u32 pipe, + int is_capture) +{ + snd_printdd("->lx_stream_start\n"); + return lx_stream_set_state(chip, pipe, is_capture, SSTATE_RUN); +} + +static inline int lx_stream_pause(struct lx6464es *chip, u32 pipe, + int is_capture) +{ + snd_printdd("->lx_stream_pause\n"); + return lx_stream_set_state(chip, pipe, is_capture, SSTATE_PAUSE); +} + +static inline int lx_stream_stop(struct lx6464es *chip, u32 pipe, + int is_capture) +{ + snd_printdd("->lx_stream_stop\n"); + return lx_stream_set_state(chip, pipe, is_capture, SSTATE_STOP); +} + +/* low-level buffer handling */ +int lx_buffer_ask(struct lx6464es *chip, u32 pipe, int is_capture, + u32 *r_needed, u32 *r_freed, u32 *size_array); +int lx_buffer_give(struct lx6464es *chip, u32 pipe, int is_capture, + u32 buffer_size, u32 buf_address_lo, u32 buf_address_hi, + u32 *r_buffer_index); +int lx_buffer_free(struct lx6464es *chip, u32 pipe, int is_capture, + u32 *r_buffer_size); +int lx_buffer_cancel(struct lx6464es *chip, u32 pipe, int is_capture, + u32 buffer_index); + +/* low-level gain/peak handling */ +int lx_level_unmute(struct lx6464es *chip, int is_capture, int unmute); +int lx_level_peaks(struct lx6464es *chip, int is_capture, int channels, + u32 *r_levels); + + +/* interrupt handling */ +irqreturn_t lx_interrupt(int irq, void *dev_id); +void lx_irq_enable(struct lx6464es *chip); +void lx_irq_disable(struct lx6464es *chip); + +void lx_tasklet_capture(unsigned long data); +void lx_tasklet_playback(unsigned long data); + + +/* Stream Format Header Defines (for LIN and IEEE754) */ +#define HEADER_FMT_BASE HEADER_FMT_BASE_LIN +#define HEADER_FMT_BASE_LIN 0xFED00000 +#define HEADER_FMT_BASE_FLOAT 0xFAD00000 +#define HEADER_FMT_MONO 0x00000080 /* bit 23 in header_lo. WARNING: old + * bit 22 is ignored in float + * format */ +#define HEADER_FMT_INTEL 0x00008000 +#define HEADER_FMT_16BITS 0x00002000 +#define HEADER_FMT_24BITS 0x00004000 +#define HEADER_FMT_UPTO11 0x00000200 /* frequency is less or equ. to 11k. + * */ +#define HEADER_FMT_UPTO32 0x00000100 /* frequency is over 11k and less + * then 32k.*/ + + +#define BIT_FMP_HEADER 23 +#define BIT_FMP_SD 22 +#define BIT_FMP_MULTICHANNEL 19 + +#define START_STATE 1 +#define PAUSE_STATE 0 + + + + + +/* from PcxAll_e.h */ +/* Start/Pause condition for pipes (PCXStartPipe, PCXPausePipe) */ +#define START_PAUSE_IMMEDIATE 0 +#define START_PAUSE_ON_SYNCHRO 1 +#define START_PAUSE_ON_TIME_CODE 2 + + +/* Pipe / Stream state */ +#define START_STATE 1 +#define PAUSE_STATE 0 + +static inline void unpack_pointer(dma_addr_t ptr, u32 *r_low, u32 *r_high) +{ + *r_low = (u32)(ptr & 0xffffffff); +#if BITS_PER_LONG == 32 + *r_high = 0; +#else + *r_high = (u32)((u64)ptr>>32); +#endif +} + +#endif /* LX_CORE_H */ diff --git a/sound/pci/lx6464es/lx_defs.h b/sound/pci/lx6464es/lx_defs.h new file mode 100644 index 000000000000..49d36bdd512c --- /dev/null +++ b/sound/pci/lx6464es/lx_defs.h @@ -0,0 +1,376 @@ +/* -*- linux-c -*- * + * + * ALSA driver for the digigram lx6464es interface + * adapted upstream headers + * + * Copyright (c) 2009 Tim Blechmann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#ifndef LX_DEFS_H +#define LX_DEFS_H + +/* code adapted from ethersound.h */ +#define XES_FREQ_COUNT8_MASK 0x00001FFF /* compteur 25MHz entre 8 ech. */ +#define XES_FREQ_COUNT8_44_MIN 0x00001288 /* 25M / + * [ 44k - ( 44.1k + 48k ) / 2 ] + * * 8 */ +#define XES_FREQ_COUNT8_44_MAX 0x000010F0 /* 25M / [ ( 44.1k + 48k ) / 2 ] + * * 8 */ +#define XES_FREQ_COUNT8_48_MAX 0x00000F08 /* 25M / + * [ 48k + ( 44.1k + 48k ) / 2 ] + * * 8 */ + +/* code adapted from LXES_registers.h */ + +#define IOCR_OUTPUTS_OFFSET 0 /* (rw) offset for the number of OUTs in the + * ConfES register. */ +#define IOCR_INPUTS_OFFSET 8 /* (rw) offset for the number of INs in the + * ConfES register. */ +#define FREQ_RATIO_OFFSET 19 /* (rw) offset for frequency ratio in the + * ConfES register. */ +#define FREQ_RATIO_SINGLE_MODE 0x01 /* value for single mode frequency ratio: + * sample rate = frequency rate. */ + +#define CONFES_READ_PART_MASK 0x00070000 +#define CONFES_WRITE_PART_MASK 0x00F80000 + +/* code adapted from if_drv_mb.h */ + +#define MASK_SYS_STATUS_ERROR (1L << 31) /* events that lead to a PCI irq if + * not yet pending */ +#define MASK_SYS_STATUS_URUN (1L << 30) +#define MASK_SYS_STATUS_ORUN (1L << 29) +#define MASK_SYS_STATUS_EOBO (1L << 28) +#define MASK_SYS_STATUS_EOBI (1L << 27) +#define MASK_SYS_STATUS_FREQ (1L << 26) +#define MASK_SYS_STATUS_ESA (1L << 25) /* reserved, this is set by the + * XES */ +#define MASK_SYS_STATUS_TIMER (1L << 24) + +#define MASK_SYS_ASYNC_EVENTS (MASK_SYS_STATUS_ERROR | \ + MASK_SYS_STATUS_URUN | \ + MASK_SYS_STATUS_ORUN | \ + MASK_SYS_STATUS_EOBO | \ + MASK_SYS_STATUS_EOBI | \ + MASK_SYS_STATUS_FREQ | \ + MASK_SYS_STATUS_ESA) + +#define MASK_SYS_PCI_EVENTS (MASK_SYS_ASYNC_EVENTS | \ + MASK_SYS_STATUS_TIMER) + +#define MASK_SYS_TIMER_COUNT 0x0000FFFF + +#define MASK_SYS_STATUS_EOT_PLX (1L << 22) /* event that remains + * internal: reserved fo end + * of plx dma */ +#define MASK_SYS_STATUS_XES (1L << 21) /* event that remains + * internal: pending XES + * IRQ */ +#define MASK_SYS_STATUS_CMD_DONE (1L << 20) /* alternate command + * management: notify driver + * instead of polling */ + + +#define MAX_STREAM_BUFFER 5 /* max amount of stream buffers. */ + +#define MICROBLAZE_IBL_MIN 32 +#define MICROBLAZE_IBL_DEFAULT 128 +#define MICROBLAZE_IBL_MAX 512 +/* #define MASK_GRANULARITY (2*MICROBLAZE_IBL_MAX-1) */ + + + +/* command opcodes, see reference for details */ + +/* + the capture bit position in the object_id field in driver commands + depends upon the number of managed channels. For now, 64 IN + 64 OUT are + supported. HOwever, the communication protocol forsees 1024 channels, hence + bit 10 indicates a capture (input) object). +*/ +#define ID_IS_CAPTURE (1L << 10) +#define ID_OFFSET 13 /* object ID is at the 13th bit in the + * 1st command word.*/ +#define ID_CH_MASK 0x3F +#define OPCODE_OFFSET 24 /* offset of the command opcode in the first + * command word.*/ + +enum cmd_mb_opcodes { + CMD_00_INFO_DEBUG = 0x00, + CMD_01_GET_SYS_CFG = 0x01, + CMD_02_SET_GRANULARITY = 0x02, + CMD_03_SET_TIMER_IRQ = 0x03, + CMD_04_GET_EVENT = 0x04, + CMD_05_GET_PIPES = 0x05, + + CMD_06_ALLOCATE_PIPE = 0x06, + CMD_07_RELEASE_PIPE = 0x07, + CMD_08_ASK_BUFFERS = 0x08, + CMD_09_STOP_PIPE = 0x09, + CMD_0A_GET_PIPE_SPL_COUNT = 0x0a, + CMD_0B_TOGGLE_PIPE_STATE = 0x0b, + + CMD_0C_DEF_STREAM = 0x0c, + CMD_0D_SET_MUTE = 0x0d, + CMD_0E_GET_STREAM_SPL_COUNT = 0x0e, + CMD_0F_UPDATE_BUFFER = 0x0f, + CMD_10_GET_BUFFER = 0x10, + CMD_11_CANCEL_BUFFER = 0x11, + CMD_12_GET_PEAK = 0x12, + CMD_13_SET_STREAM_STATE = 0x13, + CMD_14_INVALID = 0x14, +}; + +/* pipe states */ +enum pipe_state_t { + PSTATE_IDLE = 0, /* the pipe is not processed in the XES_IRQ + * (free or stopped, or paused). */ + PSTATE_RUN = 1, /* sustained play/record state. */ + PSTATE_PURGE = 2, /* the ES channels are now off, render pipes do + * not DMA, record pipe do a last DMA. */ + PSTATE_ACQUIRE = 3, /* the ES channels are now on, render pipes do + * not yet increase their sample count, record + * pipes do not DMA. */ + PSTATE_CLOSING = 4, /* the pipe is releasing, and may not yet + * receive an "alloc" command. */ +}; + +/* stream states */ +enum stream_state_t { + SSTATE_STOP = 0x00, /* setting to stop resets the stream spl + * count.*/ + SSTATE_RUN = (0x01 << 0), /* start DMA and spl count handling. */ + SSTATE_PAUSE = (0x01 << 1), /* pause DMA and spl count handling. */ +}; + +/* buffer flags */ +enum buffer_flags { + BF_VALID = 0x80, /* set if the buffer is valid, clear if free.*/ + BF_CURRENT = 0x40, /* set if this is the current buffer (there is + * always a current buffer).*/ + BF_NOTIFY_EOB = 0x20, /* set if this buffer must cause a PCI event + * when finished.*/ + BF_CIRCULAR = 0x10, /* set if buffer[1] must be copied to buffer[0] + * by the end of this buffer.*/ + BF_64BITS_ADR = 0x08, /* set if the hi part of the address is valid.*/ + BF_xx = 0x04, /* future extension.*/ + BF_EOB = 0x02, /* set if finished, but not yet free.*/ + BF_PAUSE = 0x01, /* pause stream at buffer end.*/ + BF_ZERO = 0x00, /* no flags (init).*/ +}; + +/** +* Stream Flags definitions +*/ +enum stream_flags { + SF_ZERO = 0x00000000, /* no flags (stream invalid). */ + SF_VALID = 0x10000000, /* the stream has a valid DMA_conf + * info (setstreamformat). */ + SF_XRUN = 0x20000000, /* the stream is un x-run state. */ + SF_START = 0x40000000, /* the DMA is running.*/ + SF_ASIO = 0x80000000, /* ASIO.*/ +}; + + +#define MASK_SPL_COUNT_HI 0x00FFFFFF /* 4 MSBits are status bits */ +#define PSTATE_OFFSET 28 /* 4 MSBits are status bits */ + + +#define MASK_STREAM_HAS_MAPPING (1L << 12) +#define MASK_STREAM_IS_ASIO (1L << 9) +#define STREAM_FMT_OFFSET 10 /* the stream fmt bits start at the 10th + * bit in the command word. */ + +#define STREAM_FMT_16b 0x02 +#define STREAM_FMT_intel 0x01 + +#define FREQ_FIELD_OFFSET 15 /* offset of the freq field in the response + * word */ + +#define BUFF_FLAGS_OFFSET 24 /* offset of the buffer flags in the + * response word. */ +#define MASK_DATA_SIZE 0x00FFFFFF /* this must match the field size of + * datasize in the buffer_t structure. */ + +#define MASK_BUFFER_ID 0xFF /* the cancel command awaits a buffer ID, + * may be 0xFF for "current". */ + + +/* code adapted from PcxErr_e.h */ + +/* Bits masks */ + +#define ERROR_MASK 0x8000 + +#define SOURCE_MASK 0x7800 + +#define E_SOURCE_BOARD 0x4000 /* 8 >> 1 */ +#define E_SOURCE_DRV 0x2000 /* 4 >> 1 */ +#define E_SOURCE_API 0x1000 /* 2 >> 1 */ +/* Error tools */ +#define E_SOURCE_TOOLS 0x0800 /* 1 >> 1 */ +/* Error pcxaudio */ +#define E_SOURCE_AUDIO 0x1800 /* 3 >> 1 */ +/* Error virtual pcx */ +#define E_SOURCE_VPCX 0x2800 /* 5 >> 1 */ +/* Error dispatcher */ +#define E_SOURCE_DISPATCHER 0x3000 /* 6 >> 1 */ +/* Error from CobraNet firmware */ +#define E_SOURCE_COBRANET 0x3800 /* 7 >> 1 */ + +#define E_SOURCE_USER 0x7800 + +#define CLASS_MASK 0x0700 + +#define CODE_MASK 0x00FF + +/* Bits values */ + +/* Values for the error/warning bit */ +#define ERROR_VALUE 0x8000 +#define WARNING_VALUE 0x0000 + +/* Class values */ +#define E_CLASS_GENERAL 0x0000 +#define E_CLASS_INVALID_CMD 0x0100 +#define E_CLASS_INVALID_STD_OBJECT 0x0200 +#define E_CLASS_RSRC_IMPOSSIBLE 0x0300 +#define E_CLASS_WRONG_CONTEXT 0x0400 +#define E_CLASS_BAD_SPECIFIC_PARAMETER 0x0500 +#define E_CLASS_REAL_TIME_ERROR 0x0600 +#define E_CLASS_DIRECTSHOW 0x0700 +#define E_CLASS_FREE 0x0700 + + +/* Complete DRV error code for the general class */ +#define ED_GN (ERROR_VALUE | E_SOURCE_DRV | E_CLASS_GENERAL) +#define ED_CONCURRENCY (ED_GN | 0x01) +#define ED_DSP_CRASHED (ED_GN | 0x02) +#define ED_UNKNOWN_BOARD (ED_GN | 0x03) +#define ED_NOT_INSTALLED (ED_GN | 0x04) +#define ED_CANNOT_OPEN_SVC_MANAGER (ED_GN | 0x05) +#define ED_CANNOT_READ_REGISTRY (ED_GN | 0x06) +#define ED_DSP_VERSION_MISMATCH (ED_GN | 0x07) +#define ED_UNAVAILABLE_FEATURE (ED_GN | 0x08) +#define ED_CANCELLED (ED_GN | 0x09) +#define ED_NO_RESPONSE_AT_IRQA (ED_GN | 0x10) +#define ED_INVALID_ADDRESS (ED_GN | 0x11) +#define ED_DSP_CORRUPTED (ED_GN | 0x12) +#define ED_PENDING_OPERATION (ED_GN | 0x13) +#define ED_NET_ALLOCATE_MEMORY_IMPOSSIBLE (ED_GN | 0x14) +#define ED_NET_REGISTER_ERROR (ED_GN | 0x15) +#define ED_NET_THREAD_ERROR (ED_GN | 0x16) +#define ED_NET_OPEN_ERROR (ED_GN | 0x17) +#define ED_NET_CLOSE_ERROR (ED_GN | 0x18) +#define ED_NET_NO_MORE_PACKET (ED_GN | 0x19) +#define ED_NET_NO_MORE_BUFFER (ED_GN | 0x1A) +#define ED_NET_SEND_ERROR (ED_GN | 0x1B) +#define ED_NET_RECEIVE_ERROR (ED_GN | 0x1C) +#define ED_NET_WRONG_MSG_SIZE (ED_GN | 0x1D) +#define ED_NET_WAIT_ERROR (ED_GN | 0x1E) +#define ED_NET_EEPROM_ERROR (ED_GN | 0x1F) +#define ED_INVALID_RS232_COM_NUMBER (ED_GN | 0x20) +#define ED_INVALID_RS232_INIT (ED_GN | 0x21) +#define ED_FILE_ERROR (ED_GN | 0x22) +#define ED_INVALID_GPIO_CMD (ED_GN | 0x23) +#define ED_RS232_ALREADY_OPENED (ED_GN | 0x24) +#define ED_RS232_NOT_OPENED (ED_GN | 0x25) +#define ED_GPIO_ALREADY_OPENED (ED_GN | 0x26) +#define ED_GPIO_NOT_OPENED (ED_GN | 0x27) +#define ED_REGISTRY_ERROR (ED_GN | 0x28) /* <- NCX */ +#define ED_INVALID_SERVICE (ED_GN | 0x29) /* <- NCX */ + +#define ED_READ_FILE_ALREADY_OPENED (ED_GN | 0x2a) /* <- Decalage + * pour RCX + * (old 0x28) + * */ +#define ED_READ_FILE_INVALID_COMMAND (ED_GN | 0x2b) /* ~ */ +#define ED_READ_FILE_INVALID_PARAMETER (ED_GN | 0x2c) /* ~ */ +#define ED_READ_FILE_ALREADY_CLOSED (ED_GN | 0x2d) /* ~ */ +#define ED_READ_FILE_NO_INFORMATION (ED_GN | 0x2e) /* ~ */ +#define ED_READ_FILE_INVALID_HANDLE (ED_GN | 0x2f) /* ~ */ +#define ED_READ_FILE_END_OF_FILE (ED_GN | 0x30) /* ~ */ +#define ED_READ_FILE_ERROR (ED_GN | 0x31) /* ~ */ + +#define ED_DSP_CRASHED_EXC_DSPSTACK_OVERFLOW (ED_GN | 0x32) /* <- Decalage pour + * PCX (old 0x14) */ +#define ED_DSP_CRASHED_EXC_SYSSTACK_OVERFLOW (ED_GN | 0x33) /* ~ */ +#define ED_DSP_CRASHED_EXC_ILLEGAL (ED_GN | 0x34) /* ~ */ +#define ED_DSP_CRASHED_EXC_TIMER_REENTRY (ED_GN | 0x35) /* ~ */ +#define ED_DSP_CRASHED_EXC_FATAL_ERROR (ED_GN | 0x36) /* ~ */ + +#define ED_FLASH_PCCARD_NOT_PRESENT (ED_GN | 0x37) + +#define ED_NO_CURRENT_CLOCK (ED_GN | 0x38) + +/* Complete DRV error code for real time class */ +#define ED_RT (ERROR_VALUE | E_SOURCE_DRV | E_CLASS_REAL_TIME_ERROR) +#define ED_DSP_TIMED_OUT (ED_RT | 0x01) +#define ED_DSP_CHK_TIMED_OUT (ED_RT | 0x02) +#define ED_STREAM_OVERRUN (ED_RT | 0x03) +#define ED_DSP_BUSY (ED_RT | 0x04) +#define ED_DSP_SEMAPHORE_TIME_OUT (ED_RT | 0x05) +#define ED_BOARD_TIME_OUT (ED_RT | 0x06) +#define ED_XILINX_ERROR (ED_RT | 0x07) +#define ED_COBRANET_ITF_NOT_RESPONDING (ED_RT | 0x08) + +/* Complete BOARD error code for the invaid standard object class */ +#define EB_ISO (ERROR_VALUE | E_SOURCE_BOARD | \ + E_CLASS_INVALID_STD_OBJECT) +#define EB_INVALID_EFFECT (EB_ISO | 0x00) +#define EB_INVALID_PIPE (EB_ISO | 0x40) +#define EB_INVALID_STREAM (EB_ISO | 0x80) +#define EB_INVALID_AUDIO (EB_ISO | 0xC0) + +/* Complete BOARD error code for impossible resource allocation class */ +#define EB_RI (ERROR_VALUE | E_SOURCE_BOARD | E_CLASS_RSRC_IMPOSSIBLE) +#define EB_ALLOCATE_ALL_STREAM_TRANSFERT_BUFFERS_IMPOSSIBLE (EB_RI | 0x01) +#define EB_ALLOCATE_PIPE_SAMPLE_BUFFER_IMPOSSIBLE (EB_RI | 0x02) + +#define EB_ALLOCATE_MEM_STREAM_IMPOSSIBLE \ + EB_ALLOCATE_ALL_STREAM_TRANSFERT_BUFFERS_IMPOSSIBLE +#define EB_ALLOCATE_MEM_PIPE_IMPOSSIBLE \ + EB_ALLOCATE_PIPE_SAMPLE_BUFFER_IMPOSSIBLE + +#define EB_ALLOCATE_DIFFERED_CMD_IMPOSSIBLE (EB_RI | 0x03) +#define EB_TOO_MANY_DIFFERED_CMD (EB_RI | 0x04) +#define EB_RBUFFERS_TABLE_OVERFLOW (EB_RI | 0x05) +#define EB_ALLOCATE_EFFECTS_IMPOSSIBLE (EB_RI | 0x08) +#define EB_ALLOCATE_EFFECT_POS_IMPOSSIBLE (EB_RI | 0x09) +#define EB_RBUFFER_NOT_AVAILABLE (EB_RI | 0x0A) +#define EB_ALLOCATE_CONTEXT_LIII_IMPOSSIBLE (EB_RI | 0x0B) +#define EB_STATUS_DIALOG_IMPOSSIBLE (EB_RI | 0x1D) +#define EB_CONTROL_CMD_IMPOSSIBLE (EB_RI | 0x1E) +#define EB_STATUS_SEND_IMPOSSIBLE (EB_RI | 0x1F) +#define EB_ALLOCATE_PIPE_IMPOSSIBLE (EB_RI | 0x40) +#define EB_ALLOCATE_STREAM_IMPOSSIBLE (EB_RI | 0x80) +#define EB_ALLOCATE_AUDIO_IMPOSSIBLE (EB_RI | 0xC0) + +/* Complete BOARD error code for wrong call context class */ +#define EB_WCC (ERROR_VALUE | E_SOURCE_BOARD | E_CLASS_WRONG_CONTEXT) +#define EB_CMD_REFUSED (EB_WCC | 0x00) +#define EB_START_STREAM_REFUSED (EB_WCC | 0xFC) +#define EB_SPC_REFUSED (EB_WCC | 0xFD) +#define EB_CSN_REFUSED (EB_WCC | 0xFE) +#define EB_CSE_REFUSED (EB_WCC | 0xFF) + + + + +#endif /* LX_DEFS_H */ diff --git a/sound/pci/oxygen/oxygen_pcm.c b/sound/pci/oxygen/oxygen_pcm.c index c262049961e1..3b5ca70c9d4d 100644 --- a/sound/pci/oxygen/oxygen_pcm.c +++ b/sound/pci/oxygen/oxygen_pcm.c @@ -487,10 +487,14 @@ static int oxygen_hw_free(struct snd_pcm_substream *substream) { struct oxygen *chip = snd_pcm_substream_chip(substream); unsigned int channel = oxygen_substream_channel(substream); + unsigned int channel_mask = 1 << channel; spin_lock_irq(&chip->reg_lock); - chip->interrupt_mask &= ~(1 << channel); + chip->interrupt_mask &= ~channel_mask; oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, chip->interrupt_mask); + + oxygen_set_bits8(chip, OXYGEN_DMA_FLUSH, channel_mask); + oxygen_clear_bits8(chip, OXYGEN_DMA_FLUSH, channel_mask); spin_unlock_irq(&chip->reg_lock); return snd_pcm_lib_free_pages(substream); diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c index bc5ce11c8b14..bf971f7cfdc6 100644 --- a/sound/pci/oxygen/virtuoso.c +++ b/sound/pci/oxygen/virtuoso.c @@ -113,8 +113,8 @@ */ /* - * Xonar Essence STX - * ----------------- + * Xonar Essence ST (Deluxe)/STX + * ----------------------------- * * CMI8788: * @@ -180,6 +180,8 @@ enum { MODEL_DX, MODEL_HDAV, /* without daughterboard */ MODEL_HDAV_H6, /* with H6 daughterboard */ + MODEL_ST, + MODEL_ST_H6, MODEL_STX, }; @@ -188,8 +190,10 @@ static struct pci_device_id xonar_ids[] __devinitdata = { { OXYGEN_PCI_SUBID(0x1043, 0x8275), .driver_data = MODEL_DX }, { OXYGEN_PCI_SUBID(0x1043, 0x82b7), .driver_data = MODEL_D2X }, { OXYGEN_PCI_SUBID(0x1043, 0x8314), .driver_data = MODEL_HDAV }, + { OXYGEN_PCI_SUBID(0x1043, 0x8327), .driver_data = MODEL_DX }, { OXYGEN_PCI_SUBID(0x1043, 0x834f), .driver_data = MODEL_D1 }, { OXYGEN_PCI_SUBID(0x1043, 0x835c), .driver_data = MODEL_STX }, + { OXYGEN_PCI_SUBID(0x1043, 0x835d), .driver_data = MODEL_ST }, { OXYGEN_PCI_SUBID_BROKEN_EEPROM }, { } }; @@ -210,9 +214,9 @@ MODULE_DEVICE_TABLE(pci, xonar_ids); #define GPIO_DX_FRONT_PANEL 0x0002 #define GPIO_DX_INPUT_ROUTE 0x0100 -#define GPIO_HDAV_DB_MASK 0x0030 -#define GPIO_HDAV_DB_H6 0x0000 -#define GPIO_HDAV_DB_XX 0x0020 +#define GPIO_DB_MASK 0x0030 +#define GPIO_DB_H6 0x0000 +#define GPIO_DB_XX 0x0020 #define GPIO_ST_HP_REAR 0x0002 #define GPIO_ST_HP 0x0080 @@ -530,7 +534,7 @@ static void xonar_hdav_init(struct oxygen *chip) snd_component_add(chip->card, "CS5381"); } -static void xonar_stx_init(struct oxygen *chip) +static void xonar_st_init(struct oxygen *chip) { struct xonar_data *data = chip->model_data; @@ -539,12 +543,11 @@ static void xonar_stx_init(struct oxygen *chip) OXYGEN_2WIRE_INTERRUPT_MASK | OXYGEN_2WIRE_SPEED_FAST); + if (chip->model.private_data == MODEL_ST_H6) + chip->model.dac_channels = 8; data->anti_pop_delay = 100; - data->dacs = 1; + data->dacs = chip->model.private_data == MODEL_ST_H6 ? 4 : 1; data->output_enable_bit = GPIO_DX_OUTPUT_ENABLE; - data->ext_power_reg = OXYGEN_GPI_DATA; - data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; - data->ext_power_bit = GPI_DX_EXT_POWER; data->pcm1796_oversampling = PCM1796_OS_64; pcm1796_init(chip); @@ -560,6 +563,17 @@ static void xonar_stx_init(struct oxygen *chip) snd_component_add(chip->card, "CS5381"); } +static void xonar_stx_init(struct oxygen *chip) +{ + struct xonar_data *data = chip->model_data; + + data->ext_power_reg = OXYGEN_GPI_DATA; + data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; + data->ext_power_bit = GPI_DX_EXT_POWER; + + xonar_st_init(chip); +} + static void xonar_disable_output(struct oxygen *chip) { struct xonar_data *data = chip->model_data; @@ -1021,7 +1035,8 @@ static const struct oxygen_model model_xonar_hdav = { .model_data_size = sizeof(struct xonar_data), .device_config = PLAYBACK_0_TO_I2S | PLAYBACK_1_TO_SPDIF | - CAPTURE_0_FROM_I2S_2, + CAPTURE_0_FROM_I2S_2 | + CAPTURE_1_FROM_SPDIF, .dac_channels = 8, .dac_volume_min = 255 - 2*60, .dac_volume_max = 255, @@ -1034,7 +1049,7 @@ static const struct oxygen_model model_xonar_hdav = { static const struct oxygen_model model_xonar_st = { .longname = "Asus Virtuoso 100", .chip = "AV200", - .init = xonar_stx_init, + .init = xonar_st_init, .control_filter = xonar_st_control_filter, .mixer_init = xonar_st_mixer_init, .cleanup = xonar_st_cleanup, @@ -1067,6 +1082,7 @@ static int __devinit get_xonar_model(struct oxygen *chip, [MODEL_D2] = &model_xonar_d2, [MODEL_D2X] = &model_xonar_d2, [MODEL_HDAV] = &model_xonar_hdav, + [MODEL_ST] = &model_xonar_st, [MODEL_STX] = &model_xonar_st, }; static const char *const names[] = { @@ -1076,6 +1092,8 @@ static int __devinit get_xonar_model(struct oxygen *chip, [MODEL_D2X] = "Xonar D2X", [MODEL_HDAV] = "Xonar HDAV1.3", [MODEL_HDAV_H6] = "Xonar HDAV1.3+H6", + [MODEL_ST] = "Xonar Essence ST", + [MODEL_ST_H6] = "Xonar Essence ST+H6", [MODEL_STX] = "Xonar Essence STX", }; unsigned int model = id->driver_data; @@ -1092,21 +1110,27 @@ static int __devinit get_xonar_model(struct oxygen *chip, chip->model.init = xonar_dx_init; break; case MODEL_HDAV: - oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, - GPIO_HDAV_DB_MASK); - switch (oxygen_read16(chip, OXYGEN_GPIO_DATA) & - GPIO_HDAV_DB_MASK) { - case GPIO_HDAV_DB_H6: + oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_DB_MASK); + switch (oxygen_read16(chip, OXYGEN_GPIO_DATA) & GPIO_DB_MASK) { + case GPIO_DB_H6: model = MODEL_HDAV_H6; break; - case GPIO_HDAV_DB_XX: + case GPIO_DB_XX: snd_printk(KERN_ERR "unknown daughterboard\n"); return -ENODEV; } break; + case MODEL_ST: + oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_DB_MASK); + switch (oxygen_read16(chip, OXYGEN_GPIO_DATA) & GPIO_DB_MASK) { + case GPIO_DB_H6: + model = MODEL_ST_H6; + break; + } + break; case MODEL_STX: - oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, - GPIO_HDAV_DB_MASK); + chip->model.init = xonar_stx_init; + oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_DB_MASK); break; } diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c index e51a5ef1954d..235a71e5ac8d 100644 --- a/sound/pci/riptide/riptide.c +++ b/sound/pci/riptide/riptide.c @@ -507,41 +507,19 @@ static int riptide_reset(struct cmdif *cif, struct snd_riptide *chip); */ static struct pci_device_id snd_riptide_ids[] = { - { - .vendor = 0x127a,.device = 0x4310, - .subvendor = PCI_ANY_ID,.subdevice = PCI_ANY_ID, - }, - { - .vendor = 0x127a,.device = 0x4320, - .subvendor = PCI_ANY_ID,.subdevice = PCI_ANY_ID, - }, - { - .vendor = 0x127a,.device = 0x4330, - .subvendor = PCI_ANY_ID,.subdevice = PCI_ANY_ID, - }, - { - .vendor = 0x127a,.device = 0x4340, - .subvendor = PCI_ANY_ID,.subdevice = PCI_ANY_ID, - }, + { PCI_DEVICE(0x127a, 0x4310) }, + { PCI_DEVICE(0x127a, 0x4320) }, + { PCI_DEVICE(0x127a, 0x4330) }, + { PCI_DEVICE(0x127a, 0x4340) }, {0,}, }; #ifdef SUPPORT_JOYSTICK static struct pci_device_id snd_riptide_joystick_ids[] __devinitdata = { - { - .vendor = 0x127a,.device = 0x4312, - .subvendor = PCI_ANY_ID,.subdevice = PCI_ANY_ID, - }, - { - .vendor = 0x127a,.device = 0x4322, - .subvendor = PCI_ANY_ID,.subdevice = PCI_ANY_ID, - }, - {.vendor = 0x127a,.device = 0x4332, - .subvendor = PCI_ANY_ID,.subdevice = PCI_ANY_ID, - }, - {.vendor = 0x127a,.device = 0x4342, - .subvendor = PCI_ANY_ID,.subdevice = PCI_ANY_ID, - }, + { PCI_DEVICE(0x127a, 0x4312) }, + { PCI_DEVICE(0x127a, 0x4322) }, + { PCI_DEVICE(0x127a, 0x4332) }, + { PCI_DEVICE(0x127a, 0x4342) }, {0,}, }; #endif @@ -1209,12 +1187,79 @@ static int riptide_resume(struct pci_dev *pci) } #endif +static int try_to_load_firmware(struct cmdif *cif, struct snd_riptide *chip) +{ + union firmware_version firmware = { .ret = CMDRET_ZERO }; + int i, timeout, err; + + for (i = 0; i < 2; i++) { + WRITE_PORT_ULONG(cif->hwport->port[i].data1, 0); + WRITE_PORT_ULONG(cif->hwport->port[i].data2, 0); + } + SET_GRESET(cif->hwport); + udelay(100); + UNSET_GRESET(cif->hwport); + udelay(100); + + for (timeout = 100000; --timeout; udelay(10)) { + if (IS_READY(cif->hwport) && !IS_GERR(cif->hwport)) + break; + } + if (!timeout) { + snd_printk(KERN_ERR + "Riptide: device not ready, audio status: 0x%x " + "ready: %d gerr: %d\n", + READ_AUDIO_STATUS(cif->hwport), + IS_READY(cif->hwport), IS_GERR(cif->hwport)); + return -EIO; + } else { + snd_printdd + ("Riptide: audio status: 0x%x ready: %d gerr: %d\n", + READ_AUDIO_STATUS(cif->hwport), + IS_READY(cif->hwport), IS_GERR(cif->hwport)); + } + + SEND_GETV(cif, &firmware.ret); + snd_printdd("Firmware version: ASIC: %d CODEC %d AUXDSP %d PROG %d\n", + firmware.firmware.ASIC, firmware.firmware.CODEC, + firmware.firmware.AUXDSP, firmware.firmware.PROG); + + for (i = 0; i < FIRMWARE_VERSIONS; i++) { + if (!memcmp(&firmware_versions[i], &firmware, sizeof(firmware))) + break; + } + if (i >= FIRMWARE_VERSIONS) + return 0; /* no match */ + + if (!chip) + return 1; /* OK */ + + snd_printdd("Writing Firmware\n"); + if (!chip->fw_entry) { + err = request_firmware(&chip->fw_entry, "riptide.hex", + &chip->pci->dev); + if (err) { + snd_printk(KERN_ERR + "Riptide: Firmware not available %d\n", err); + return -EIO; + } + } + err = loadfirmware(cif, chip->fw_entry->data, chip->fw_entry->size); + if (err) { + snd_printk(KERN_ERR + "Riptide: Could not load firmware %d\n", err); + return err; + } + + chip->firmware = firmware; + + return 1; /* OK */ +} + static int riptide_reset(struct cmdif *cif, struct snd_riptide *chip) { - int timeout, tries; union cmdret rptr = CMDRET_ZERO; - union firmware_version firmware; - int i, j, err, has_firmware; + int err, tries; if (!cif) return -EINVAL; @@ -1227,75 +1272,11 @@ static int riptide_reset(struct cmdif *cif, struct snd_riptide *chip) cif->is_reset = 0; tries = RESET_TRIES; - has_firmware = 0; - while (has_firmware == 0 && tries-- > 0) { - for (i = 0; i < 2; i++) { - WRITE_PORT_ULONG(cif->hwport->port[i].data1, 0); - WRITE_PORT_ULONG(cif->hwport->port[i].data2, 0); - } - SET_GRESET(cif->hwport); - udelay(100); - UNSET_GRESET(cif->hwport); - udelay(100); - - for (timeout = 100000; --timeout; udelay(10)) { - if (IS_READY(cif->hwport) && !IS_GERR(cif->hwport)) - break; - } - if (timeout == 0) { - snd_printk(KERN_ERR - "Riptide: device not ready, audio status: 0x%x ready: %d gerr: %d\n", - READ_AUDIO_STATUS(cif->hwport), - IS_READY(cif->hwport), IS_GERR(cif->hwport)); - return -EIO; - } else { - snd_printdd - ("Riptide: audio status: 0x%x ready: %d gerr: %d\n", - READ_AUDIO_STATUS(cif->hwport), - IS_READY(cif->hwport), IS_GERR(cif->hwport)); - } - - SEND_GETV(cif, &rptr); - for (i = 0; i < 4; i++) - firmware.ret.retwords[i] = rptr.retwords[i]; - - snd_printdd - ("Firmware version: ASIC: %d CODEC %d AUXDSP %d PROG %d\n", - firmware.firmware.ASIC, firmware.firmware.CODEC, - firmware.firmware.AUXDSP, firmware.firmware.PROG); - - for (j = 0; j < FIRMWARE_VERSIONS; j++) { - has_firmware = 1; - for (i = 0; i < 4; i++) { - if (firmware_versions[j].ret.retwords[i] != - firmware.ret.retwords[i]) - has_firmware = 0; - } - if (has_firmware) - break; - } - - if (chip != NULL && has_firmware == 0) { - snd_printdd("Writing Firmware\n"); - if (!chip->fw_entry) { - if ((err = - request_firmware(&chip->fw_entry, - "riptide.hex", - &chip->pci->dev)) != 0) { - snd_printk(KERN_ERR - "Riptide: Firmware not available %d\n", - err); - return -EIO; - } - } - err = loadfirmware(cif, chip->fw_entry->data, - chip->fw_entry->size); - if (err) - snd_printk(KERN_ERR - "Riptide: Could not load firmware %d\n", - err); - } - } + do { + err = try_to_load_firmware(cif, chip); + if (err < 0) + return err; + } while (!err && --tries); SEND_SACR(cif, 0, AC97_RESET); SEND_RACR(cif, AC97_RESET, &rptr); @@ -1337,11 +1318,6 @@ static int riptide_reset(struct cmdif *cif, struct snd_riptide *chip) SET_AIE(cif->hwport); SET_AIACK(cif->hwport); cif->is_reset = 1; - if (chip) { - for (i = 0; i < 4; i++) - chip->firmware.ret.retwords[i] = - firmware.ret.retwords[i]; - } return 0; } @@ -2038,14 +2014,12 @@ static int __devinit snd_riptide_mixer(struct snd_riptide *chip) } #ifdef SUPPORT_JOYSTICK -static int have_joystick; -static struct pci_dev *riptide_gameport_pci; -static struct gameport *riptide_gameport; static int __devinit snd_riptide_joystick_probe(struct pci_dev *pci, const struct pci_device_id *id) { static int dev; + struct gameport *gameport; if (dev >= SNDRV_CARDS) return -ENODEV; @@ -2054,36 +2028,33 @@ snd_riptide_joystick_probe(struct pci_dev *pci, const struct pci_device_id *id) return -ENOENT; } - if (joystick_port[dev]) { - riptide_gameport = gameport_allocate_port(); - if (riptide_gameport) { - if (!request_region - (joystick_port[dev], 8, "Riptide gameport")) { - snd_printk(KERN_WARNING - "Riptide: cannot grab gameport 0x%x\n", - joystick_port[dev]); - gameport_free_port(riptide_gameport); - riptide_gameport = NULL; - } else { - riptide_gameport_pci = pci; - riptide_gameport->io = joystick_port[dev]; - gameport_register_port(riptide_gameport); - } - } + if (!joystick_port[dev++]) + return 0; + + gameport = gameport_allocate_port(); + if (!gameport) + return -ENOMEM; + if (!request_region(joystick_port[dev], 8, "Riptide gameport")) { + snd_printk(KERN_WARNING + "Riptide: cannot grab gameport 0x%x\n", + joystick_port[dev]); + gameport_free_port(gameport); + return -EBUSY; } - dev++; + + gameport->io = joystick_port[dev]; + gameport_register_port(gameport); + pci_set_drvdata(pci, gameport); return 0; } static void __devexit snd_riptide_joystick_remove(struct pci_dev *pci) { - if (riptide_gameport) { - if (riptide_gameport_pci == pci) { - release_region(riptide_gameport->io, 8); - riptide_gameport_pci = NULL; - gameport_unregister_port(riptide_gameport); - riptide_gameport = NULL; - } + struct gameport *gameport = pci_get_drvdata(pci); + if (gameport) { + release_region(gameport->io, 8); + gameport_unregister_port(gameport); + pci_set_drvdata(pci, NULL); } } #endif @@ -2094,8 +2065,8 @@ snd_card_riptide_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) static int dev; struct snd_card *card; struct snd_riptide *chip; - unsigned short addr; - int err = 0; + unsigned short val; + int err; if (dev >= SNDRV_CARDS) return -ENODEV; @@ -2107,60 +2078,63 @@ snd_card_riptide_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); if (err < 0) return err; - if ((err = snd_riptide_create(card, pci, &chip)) < 0) { - snd_card_free(card); - return err; - } + err = snd_riptide_create(card, pci, &chip); + if (err < 0) + goto error; card->private_data = chip; - if ((err = snd_riptide_pcm(chip, 0, NULL)) < 0) { - snd_card_free(card); - return err; - } - if ((err = snd_riptide_mixer(chip)) < 0) { - snd_card_free(card); - return err; - } - pci_write_config_word(chip->pci, PCI_EXT_Legacy_Mask, LEGACY_ENABLE_ALL - | (opl3_port[dev] ? LEGACY_ENABLE_FM : 0) + err = snd_riptide_pcm(chip, 0, NULL); + if (err < 0) + goto error; + err = snd_riptide_mixer(chip); + if (err < 0) + goto error; + + val = LEGACY_ENABLE_ALL; + if (opl3_port[dev]) + val |= LEGACY_ENABLE_FM; #ifdef SUPPORT_JOYSTICK - | (joystick_port[dev] ? LEGACY_ENABLE_GAMEPORT : - 0) + if (joystick_port[dev]) + val |= LEGACY_ENABLE_GAMEPORT; #endif - | (mpu_port[dev] - ? (LEGACY_ENABLE_MPU_INT | LEGACY_ENABLE_MPU) : - 0) - | ((chip->irq << 4) & 0xF0)); - if ((addr = mpu_port[dev]) != 0) { - pci_write_config_word(chip->pci, PCI_EXT_MPU_Base, addr); - if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_RIPTIDE, - addr, 0, chip->irq, 0, - &chip->rmidi)) < 0) + if (mpu_port[dev]) + val |= LEGACY_ENABLE_MPU_INT | LEGACY_ENABLE_MPU; + val |= (chip->irq << 4) & 0xf0; + pci_write_config_word(chip->pci, PCI_EXT_Legacy_Mask, val); + if (mpu_port[dev]) { + val = mpu_port[dev]; + pci_write_config_word(chip->pci, PCI_EXT_MPU_Base, val); + err = snd_mpu401_uart_new(card, 0, MPU401_HW_RIPTIDE, + val, 0, chip->irq, 0, + &chip->rmidi); + if (err < 0) snd_printk(KERN_WARNING "Riptide: Can't Allocate MPU at 0x%x\n", - addr); + val); else - chip->mpuaddr = addr; + chip->mpuaddr = val; } - if ((addr = opl3_port[dev]) != 0) { - pci_write_config_word(chip->pci, PCI_EXT_FM_Base, addr); - if ((err = snd_opl3_create(card, addr, addr + 2, - OPL3_HW_RIPTIDE, 0, - &chip->opl3)) < 0) + if (opl3_port[dev]) { + val = opl3_port[dev]; + pci_write_config_word(chip->pci, PCI_EXT_FM_Base, val); + err = snd_opl3_create(card, val, val + 2, + OPL3_HW_RIPTIDE, 0, &chip->opl3); + if (err < 0) snd_printk(KERN_WARNING "Riptide: Can't Allocate OPL3 at 0x%x\n", - addr); + val); else { - chip->opladdr = addr; - if ((err = - snd_opl3_hwdep_new(chip->opl3, 0, 1, NULL)) < 0) + chip->opladdr = val; + err = snd_opl3_hwdep_new(chip->opl3, 0, 1, NULL); + if (err < 0) snd_printk(KERN_WARNING "Riptide: Can't Allocate OPL3-HWDEP\n"); } } #ifdef SUPPORT_JOYSTICK - if ((addr = joystick_port[dev]) != 0) { - pci_write_config_word(chip->pci, PCI_EXT_Game_Base, addr); - chip->gameaddr = addr; + if (joystick_port[dev]) { + val = joystick_port[dev]; + pci_write_config_word(chip->pci, PCI_EXT_Game_Base, val); + chip->gameaddr = val; } #endif @@ -2178,13 +2152,16 @@ snd_card_riptide_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) chip->opladdr); #endif snd_riptide_proc_init(chip); - if ((err = snd_card_register(card)) < 0) { - snd_card_free(card); - return err; - } + err = snd_card_register(card); + if (err < 0) + goto error; pci_set_drvdata(pci, card); dev++; return 0; + + error: + snd_card_free(card); + return err; } static void __devexit snd_card_riptide_remove(struct pci_dev *pci) @@ -2216,14 +2193,11 @@ static struct pci_driver joystick_driver = { static int __init alsa_card_riptide_init(void) { int err; - if ((err = pci_register_driver(&driver)) < 0) + err = pci_register_driver(&driver); + if (err < 0) return err; #if defined(SUPPORT_JOYSTICK) - if (pci_register_driver(&joystick_driver) < 0) { - have_joystick = 0; - snd_printk(KERN_INFO "no joystick found\n"); - } else - have_joystick = 1; + pci_register_driver(&joystick_driver); #endif return 0; } @@ -2232,8 +2206,7 @@ static void __exit alsa_card_riptide_exit(void) { pci_unregister_driver(&driver); #if defined(SUPPORT_JOYSTICK) - if (have_joystick) - pci_unregister_driver(&joystick_driver); + pci_unregister_driver(&joystick_driver); #endif } diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index 314e73531bd1..3da5c029f93b 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -402,9 +403,9 @@ MODULE_FIRMWARE("digiface_firmware_rev11.bin"); #define HDSP_DMA_AREA_BYTES ((HDSP_MAX_CHANNELS+1) * HDSP_CHANNEL_BUFFER_BYTES) #define HDSP_DMA_AREA_KILOBYTES (HDSP_DMA_AREA_BYTES/1024) -/* use hotplug firmeare loader? */ +/* use hotplug firmware loader? */ #if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE) -#if !defined(HDSP_USE_HWDEP_LOADER) && !defined(CONFIG_SND_HDSP) +#if !defined(HDSP_USE_HWDEP_LOADER) #define HDSP_FW_LOADER #endif #endif @@ -1047,7 +1048,6 @@ static int hdsp_set_interrupt_interval(struct hdsp *s, unsigned int frames) static void hdsp_set_dds_value(struct hdsp *hdsp, int rate) { u64 n; - u32 r; if (rate >= 112000) rate /= 4; @@ -1055,7 +1055,7 @@ static void hdsp_set_dds_value(struct hdsp *hdsp, int rate) rate /= 2; n = DDS_NUMERATOR; - div64_32(&n, rate, &r); + n = div_u64(n, rate); /* n should be less than 2^32 for being written to FREQ register */ snd_BUG_ON(n >> 32); /* HDSP_freqReg and HDSP_resetPointer are the same, so keep the DDS @@ -3097,7 +3097,6 @@ static int snd_hdsp_get_adat_sync_check(struct snd_kcontrol *kcontrol, struct sn static int hdsp_dds_offset(struct hdsp *hdsp) { u64 n; - u32 r; unsigned int dds_value = hdsp->dds_value; int system_sample_rate = hdsp->system_sample_rate; @@ -3109,7 +3108,7 @@ static int hdsp_dds_offset(struct hdsp *hdsp) * dds_value = n / rate * rate = n / dds_value */ - div64_32(&n, dds_value, &r); + n = div_u64(n, dds_value); if (system_sample_rate >= 112000) n *= 4; else if (system_sample_rate >= 56000) diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index bac2dc0c5d85..0dce331a2a3b 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -831,7 +832,6 @@ static int hdspm_set_interrupt_interval(struct hdspm * s, unsigned int frames) static void hdspm_set_dds_value(struct hdspm *hdspm, int rate) { u64 n; - u32 r; if (rate >= 112000) rate /= 4; @@ -844,7 +844,7 @@ static void hdspm_set_dds_value(struct hdspm *hdspm, int rate) */ /* n = 104857600000000ULL; */ /* = 2^20 * 10^8 */ n = 110100480000000ULL; /* Value checked for AES32 and MADI */ - div64_32(&n, rate, &r); + n = div_u64(n, rate); /* n should be less than 2^32 for being written to FREQ register */ snd_BUG_ON(n >> 32); hdspm_write(hdspm, HDSPM_freqReg, (u32)n); diff --git a/sound/pci/sis7019.h b/sound/pci/sis7019.h index 013b6739a742..bc8c76819408 100644 --- a/sound/pci/sis7019.h +++ b/sound/pci/sis7019.h @@ -203,7 +203,7 @@ #define SIS_WEISR_B 0xac -/* Playback DMA parameters (paramter RAM) */ +/* Playback DMA parameters (parameter RAM) */ #define SIS_PLAY_DMA_OFFSET 0x0000 #define SIS_PLAY_DMA_SIZE 0x10 #define SIS_PLAY_DMA_ADDR(addr, num) \ @@ -228,7 +228,7 @@ #define SIS_PLAY_DMA_SSO_MASK 0xffff0000 #define SIS_PLAY_DMA_ESO_MASK 0x0000ffff -/* Capture DMA parameters (paramter RAM) */ +/* Capture DMA parameters (parameter RAM) */ #define SIS_CAPTURE_DMA_OFFSET 0x0800 #define SIS_CAPTURE_DMA_SIZE 0x10 #define SIS_CAPTURE_DMA_ADDR(addr, num) \ diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 1ef58c51c213..949fcaf6b70e 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -85,6 +85,7 @@ static int joystick; static int ac97_clock = 48000; static char *ac97_quirk; static int dxs_support; +static int nodelay; module_param(index, int, 0444); MODULE_PARM_DESC(index, "Index value for VIA 82xx bridge."); @@ -102,6 +103,8 @@ module_param(ac97_quirk, charp, 0444); MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware."); module_param(dxs_support, int, 0444); MODULE_PARM_DESC(dxs_support, "Support for DXS channels (0 = auto, 1 = enable, 2 = disable, 3 = 48k only, 4 = no VRA, 5 = enable any sample rate)"); +module_param(nodelay, int, 0444); +MODULE_PARM_DESC(nodelay, "Disable 500ms init delay"); /* just for backward compatibility */ static int enable; @@ -549,7 +552,8 @@ static void snd_via82xx_codec_wait(struct snd_ac97 *ac97) int err; err = snd_via82xx_codec_ready(chip, ac97->num); /* here we need to wait fairly for long time.. */ - msleep(500); + if (!nodelay) + msleep(500); } static void snd_via82xx_codec_write(struct snd_ac97 *ac97, diff --git a/sound/pci/vx222/vx222_ops.c b/sound/pci/vx222/vx222_ops.c index c0efe4491116..6416d3f0c7be 100644 --- a/sound/pci/vx222/vx222_ops.c +++ b/sound/pci/vx222/vx222_ops.c @@ -367,7 +367,7 @@ static int vx2_load_xilinx_binary(struct vx_core *chip, const struct firmware *x unsigned int port; const unsigned char *image; - /* XILINX reset (wait at least 1 milisecond between reset on and off). */ + /* XILINX reset (wait at least 1 millisecond between reset on and off). */ vx_outl(chip, CNTRL, VX_CNTRL_REGISTER_VALUE | VX_XILINX_RESET_MASK); vx_inl(chip, CNTRL); msleep(10); diff --git a/sound/ppc/awacs.c b/sound/ppc/awacs.c index 80df9b1f651e..2cc0eda4f20e 100644 --- a/sound/ppc/awacs.c +++ b/sound/ppc/awacs.c @@ -477,7 +477,7 @@ static int snd_pmac_awacs_put_master_amp(struct snd_kcontrol *kcontrol, #define AMP_CH_SPK 0 #define AMP_CH_HD 1 -static struct snd_kcontrol_new snd_pmac_awacs_amp_vol[] __initdata = { +static struct snd_kcontrol_new snd_pmac_awacs_amp_vol[] __devinitdata = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PC Speaker Playback Volume", .info = snd_pmac_awacs_info_volume_amp, @@ -514,7 +514,7 @@ static struct snd_kcontrol_new snd_pmac_awacs_amp_vol[] __initdata = { }, }; -static struct snd_kcontrol_new snd_pmac_awacs_amp_hp_sw __initdata = { +static struct snd_kcontrol_new snd_pmac_awacs_amp_hp_sw __devinitdata = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Headphone Playback Switch", .info = snd_pmac_boolean_stereo_info, @@ -523,7 +523,7 @@ static struct snd_kcontrol_new snd_pmac_awacs_amp_hp_sw __initdata = { .private_value = AMP_CH_HD, }; -static struct snd_kcontrol_new snd_pmac_awacs_amp_spk_sw __initdata = { +static struct snd_kcontrol_new snd_pmac_awacs_amp_spk_sw __devinitdata = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PC Speaker Playback Switch", .info = snd_pmac_boolean_stereo_info, @@ -595,46 +595,46 @@ static int snd_pmac_screamer_mic_boost_put(struct snd_kcontrol *kcontrol, /* * lists of mixer elements */ -static struct snd_kcontrol_new snd_pmac_awacs_mixers[] __initdata = { +static struct snd_kcontrol_new snd_pmac_awacs_mixers[] __devinitdata = { AWACS_SWITCH("Master Capture Switch", 1, SHIFT_LOOPTHRU, 0), AWACS_VOLUME("Master Capture Volume", 0, 4, 0), /* AWACS_SWITCH("Unknown Playback Switch", 6, SHIFT_PAROUT0, 0), */ }; -static struct snd_kcontrol_new snd_pmac_screamer_mixers_beige[] __initdata = { +static struct snd_kcontrol_new snd_pmac_screamer_mixers_beige[] __devinitdata = { AWACS_VOLUME("Master Playback Volume", 2, 6, 1), AWACS_VOLUME("Play-through Playback Volume", 5, 6, 1), AWACS_SWITCH("Line Capture Switch", 0, SHIFT_MUX_MIC, 0), AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_LINE, 0), }; -static struct snd_kcontrol_new snd_pmac_screamer_mixers_lo[] __initdata = { +static struct snd_kcontrol_new snd_pmac_screamer_mixers_lo[] __devinitdata = { AWACS_VOLUME("Line out Playback Volume", 2, 6, 1), }; -static struct snd_kcontrol_new snd_pmac_screamer_mixers_imac[] __initdata = { +static struct snd_kcontrol_new snd_pmac_screamer_mixers_imac[] __devinitdata = { AWACS_VOLUME("Play-through Playback Volume", 5, 6, 1), AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_CD, 0), }; -static struct snd_kcontrol_new snd_pmac_screamer_mixers_g4agp[] __initdata = { +static struct snd_kcontrol_new snd_pmac_screamer_mixers_g4agp[] __devinitdata = { AWACS_VOLUME("Line out Playback Volume", 2, 6, 1), AWACS_VOLUME("Master Playback Volume", 5, 6, 1), AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_CD, 0), AWACS_SWITCH("Line Capture Switch", 0, SHIFT_MUX_MIC, 0), }; -static struct snd_kcontrol_new snd_pmac_awacs_mixers_pmac7500[] __initdata = { +static struct snd_kcontrol_new snd_pmac_awacs_mixers_pmac7500[] __devinitdata = { AWACS_VOLUME("Line out Playback Volume", 2, 6, 1), AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_CD, 0), AWACS_SWITCH("Line Capture Switch", 0, SHIFT_MUX_MIC, 0), }; -static struct snd_kcontrol_new snd_pmac_awacs_mixers_pmac5500[] __initdata = { +static struct snd_kcontrol_new snd_pmac_awacs_mixers_pmac5500[] __devinitdata = { AWACS_VOLUME("Headphone Playback Volume", 2, 6, 1), }; -static struct snd_kcontrol_new snd_pmac_awacs_mixers_pmac[] __initdata = { +static struct snd_kcontrol_new snd_pmac_awacs_mixers_pmac[] __devinitdata = { AWACS_VOLUME("Master Playback Volume", 2, 6, 1), AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_CD, 0), }; @@ -642,34 +642,34 @@ static struct snd_kcontrol_new snd_pmac_awacs_mixers_pmac[] __initdata = { /* FIXME: is this correct order? * screamer (powerbook G3 pismo) seems to have different bits... */ -static struct snd_kcontrol_new snd_pmac_awacs_mixers2[] __initdata = { +static struct snd_kcontrol_new snd_pmac_awacs_mixers2[] __devinitdata = { AWACS_SWITCH("Line Capture Switch", 0, SHIFT_MUX_LINE, 0), AWACS_SWITCH("Mic Capture Switch", 0, SHIFT_MUX_MIC, 0), }; -static struct snd_kcontrol_new snd_pmac_screamer_mixers2[] __initdata = { +static struct snd_kcontrol_new snd_pmac_screamer_mixers2[] __devinitdata = { AWACS_SWITCH("Line Capture Switch", 0, SHIFT_MUX_MIC, 0), AWACS_SWITCH("Mic Capture Switch", 0, SHIFT_MUX_LINE, 0), }; -static struct snd_kcontrol_new snd_pmac_awacs_mixers2_pmac5500[] __initdata = { +static struct snd_kcontrol_new snd_pmac_awacs_mixers2_pmac5500[] __devinitdata = { AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_CD, 0), }; -static struct snd_kcontrol_new snd_pmac_awacs_master_sw __initdata = +static struct snd_kcontrol_new snd_pmac_awacs_master_sw __devinitdata = AWACS_SWITCH("Master Playback Switch", 1, SHIFT_HDMUTE, 1); -static struct snd_kcontrol_new snd_pmac_awacs_master_sw_imac __initdata = +static struct snd_kcontrol_new snd_pmac_awacs_master_sw_imac __devinitdata = AWACS_SWITCH("Line out Playback Switch", 1, SHIFT_HDMUTE, 1); -static struct snd_kcontrol_new snd_pmac_awacs_master_sw_pmac5500 __initdata = +static struct snd_kcontrol_new snd_pmac_awacs_master_sw_pmac5500 __devinitdata = AWACS_SWITCH("Headphone Playback Switch", 1, SHIFT_HDMUTE, 1); -static struct snd_kcontrol_new snd_pmac_awacs_mic_boost[] __initdata = { +static struct snd_kcontrol_new snd_pmac_awacs_mic_boost[] __devinitdata = { AWACS_SWITCH("Mic Boost Capture Switch", 0, SHIFT_GAINLINE, 0), }; -static struct snd_kcontrol_new snd_pmac_screamer_mic_boost[] __initdata = { +static struct snd_kcontrol_new snd_pmac_screamer_mic_boost[] __devinitdata = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Mic Boost Capture Volume", .info = snd_pmac_screamer_mic_boost_info, @@ -678,34 +678,34 @@ static struct snd_kcontrol_new snd_pmac_screamer_mic_boost[] __initdata = { }, }; -static struct snd_kcontrol_new snd_pmac_awacs_mic_boost_pmac7500[] __initdata = +static struct snd_kcontrol_new snd_pmac_awacs_mic_boost_pmac7500[] __devinitdata = { AWACS_SWITCH("Line Boost Capture Switch", 0, SHIFT_GAINLINE, 0), }; -static struct snd_kcontrol_new snd_pmac_screamer_mic_boost_beige[] __initdata = +static struct snd_kcontrol_new snd_pmac_screamer_mic_boost_beige[] __devinitdata = { AWACS_SWITCH("Line Boost Capture Switch", 0, SHIFT_GAINLINE, 0), AWACS_SWITCH("CD Boost Capture Switch", 6, SHIFT_MIC_BOOST, 0), }; -static struct snd_kcontrol_new snd_pmac_screamer_mic_boost_imac[] __initdata = +static struct snd_kcontrol_new snd_pmac_screamer_mic_boost_imac[] __devinitdata = { AWACS_SWITCH("Line Boost Capture Switch", 0, SHIFT_GAINLINE, 0), AWACS_SWITCH("Mic Boost Capture Switch", 6, SHIFT_MIC_BOOST, 0), }; -static struct snd_kcontrol_new snd_pmac_awacs_speaker_vol[] __initdata = { +static struct snd_kcontrol_new snd_pmac_awacs_speaker_vol[] __devinitdata = { AWACS_VOLUME("PC Speaker Playback Volume", 4, 6, 1), }; -static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw __initdata = +static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw __devinitdata = AWACS_SWITCH("PC Speaker Playback Switch", 1, SHIFT_SPKMUTE, 1); -static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw_imac1 __initdata = +static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw_imac1 __devinitdata = AWACS_SWITCH("PC Speaker Playback Switch", 1, SHIFT_PAROUT1, 1); -static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw_imac2 __initdata = +static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw_imac2 __devinitdata = AWACS_SWITCH("PC Speaker Playback Switch", 1, SHIFT_PAROUT1, 0); @@ -872,7 +872,7 @@ static void snd_pmac_awacs_update_automute(struct snd_pmac *chip, int do_notify) /* * initialize chip */ -int __init +int __devinit snd_pmac_awacs_init(struct snd_pmac *chip) { int pm7500 = IS_PM7500; diff --git a/sound/ppc/beep.c b/sound/ppc/beep.c index 89f5c328acfe..a9d350789f55 100644 --- a/sound/ppc/beep.c +++ b/sound/ppc/beep.c @@ -215,7 +215,7 @@ static struct snd_kcontrol_new snd_pmac_beep_mixer = { }; /* Initialize beep stuff */ -int __init snd_pmac_attach_beep(struct snd_pmac *chip) +int __devinit snd_pmac_attach_beep(struct snd_pmac *chip) { struct pmac_beep *beep; struct input_dev *input_dev; diff --git a/sound/ppc/burgundy.c b/sound/ppc/burgundy.c index 45a76297c38d..16ed240e423c 100644 --- a/sound/ppc/burgundy.c +++ b/sound/ppc/burgundy.c @@ -46,12 +46,12 @@ snd_pmac_burgundy_extend_wait(struct snd_pmac *chip) timeout = 50; while (!(in_le32(&chip->awacs->codec_stat) & MASK_EXTEND) && timeout--) udelay(1); - if (! timeout) + if (timeout < 0) printk(KERN_DEBUG "burgundy_extend_wait: timeout #1\n"); timeout = 50; while ((in_le32(&chip->awacs->codec_stat) & MASK_EXTEND) && timeout--) udelay(1); - if (! timeout) + if (timeout < 0) printk(KERN_DEBUG "burgundy_extend_wait: timeout #2\n"); } @@ -468,7 +468,7 @@ static int snd_pmac_burgundy_put_switch_b(struct snd_kcontrol *kcontrol, /* * Burgundy mixers */ -static struct snd_kcontrol_new snd_pmac_burgundy_mixers[] __initdata = { +static struct snd_kcontrol_new snd_pmac_burgundy_mixers[] __devinitdata = { BURGUNDY_VOLUME_W("Master Playback Volume", 0, MASK_ADDR_BURGUNDY_MASTER_VOLUME, 8), BURGUNDY_VOLUME_W("CD Capture Volume", 0, @@ -496,7 +496,7 @@ static struct snd_kcontrol_new snd_pmac_burgundy_mixers[] __initdata = { */ BURGUNDY_SWITCH_B("PCM Capture Switch", 0, MASK_ADDR_BURGUNDY_HOSTIFEH, 0x01, 0, 0) }; -static struct snd_kcontrol_new snd_pmac_burgundy_mixers_imac[] __initdata = { +static struct snd_kcontrol_new snd_pmac_burgundy_mixers_imac[] __devinitdata = { BURGUNDY_VOLUME_W("Line in Capture Volume", 0, MASK_ADDR_BURGUNDY_VOLLINE, 16), BURGUNDY_VOLUME_W("Mic Capture Volume", 0, @@ -522,7 +522,7 @@ static struct snd_kcontrol_new snd_pmac_burgundy_mixers_imac[] __initdata = { BURGUNDY_SWITCH_B("Mic Boost Capture Switch", 0, MASK_ADDR_BURGUNDY_INPBOOST, 0x40, 0x80, 1) }; -static struct snd_kcontrol_new snd_pmac_burgundy_mixers_pmac[] __initdata = { +static struct snd_kcontrol_new snd_pmac_burgundy_mixers_pmac[] __devinitdata = { BURGUNDY_VOLUME_W("Line in Capture Volume", 0, MASK_ADDR_BURGUNDY_VOLMIC, 16), BURGUNDY_VOLUME_B("Line in Gain Capture Volume", 0, @@ -538,33 +538,33 @@ static struct snd_kcontrol_new snd_pmac_burgundy_mixers_pmac[] __initdata = { /* BURGUNDY_SWITCH_B("Line in Boost Capture Switch", 0, * MASK_ADDR_BURGUNDY_INPBOOST, 0x40, 0x80, 1) */ }; -static struct snd_kcontrol_new snd_pmac_burgundy_master_sw_imac __initdata = +static struct snd_kcontrol_new snd_pmac_burgundy_master_sw_imac __devinitdata = BURGUNDY_SWITCH_B("Master Playback Switch", 0, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, BURGUNDY_OUTPUT_LEFT | BURGUNDY_LINEOUT_LEFT | BURGUNDY_HP_LEFT, BURGUNDY_OUTPUT_RIGHT | BURGUNDY_LINEOUT_RIGHT | BURGUNDY_HP_RIGHT, 1); -static struct snd_kcontrol_new snd_pmac_burgundy_master_sw_pmac __initdata = +static struct snd_kcontrol_new snd_pmac_burgundy_master_sw_pmac __devinitdata = BURGUNDY_SWITCH_B("Master Playback Switch", 0, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, BURGUNDY_OUTPUT_INTERN | BURGUNDY_OUTPUT_LEFT, BURGUNDY_OUTPUT_RIGHT, 1); -static struct snd_kcontrol_new snd_pmac_burgundy_speaker_sw_imac __initdata = +static struct snd_kcontrol_new snd_pmac_burgundy_speaker_sw_imac __devinitdata = BURGUNDY_SWITCH_B("PC Speaker Playback Switch", 0, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, BURGUNDY_OUTPUT_LEFT, BURGUNDY_OUTPUT_RIGHT, 1); -static struct snd_kcontrol_new snd_pmac_burgundy_speaker_sw_pmac __initdata = +static struct snd_kcontrol_new snd_pmac_burgundy_speaker_sw_pmac __devinitdata = BURGUNDY_SWITCH_B("PC Speaker Playback Switch", 0, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, BURGUNDY_OUTPUT_INTERN, 0, 0); -static struct snd_kcontrol_new snd_pmac_burgundy_line_sw_imac __initdata = +static struct snd_kcontrol_new snd_pmac_burgundy_line_sw_imac __devinitdata = BURGUNDY_SWITCH_B("Line out Playback Switch", 0, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, BURGUNDY_LINEOUT_LEFT, BURGUNDY_LINEOUT_RIGHT, 1); -static struct snd_kcontrol_new snd_pmac_burgundy_line_sw_pmac __initdata = +static struct snd_kcontrol_new snd_pmac_burgundy_line_sw_pmac __devinitdata = BURGUNDY_SWITCH_B("Line out Playback Switch", 0, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, BURGUNDY_OUTPUT_LEFT, BURGUNDY_OUTPUT_RIGHT, 1); -static struct snd_kcontrol_new snd_pmac_burgundy_hp_sw_imac __initdata = +static struct snd_kcontrol_new snd_pmac_burgundy_hp_sw_imac __devinitdata = BURGUNDY_SWITCH_B("Headphone Playback Switch", 0, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, BURGUNDY_HP_LEFT, BURGUNDY_HP_RIGHT, 1); @@ -618,7 +618,7 @@ static void snd_pmac_burgundy_update_automute(struct snd_pmac *chip, int do_noti /* * initialize burgundy */ -int __init snd_pmac_burgundy_init(struct snd_pmac *chip) +int __devinit snd_pmac_burgundy_init(struct snd_pmac *chip) { int imac = machine_is_compatible("iMac"); int i, err; diff --git a/sound/ppc/daca.c b/sound/ppc/daca.c index f8d478c2da62..24200b7bdace 100644 --- a/sound/ppc/daca.c +++ b/sound/ppc/daca.c @@ -244,7 +244,7 @@ static void daca_cleanup(struct snd_pmac *chip) } /* exported */ -int __init snd_pmac_daca_init(struct snd_pmac *chip) +int __devinit snd_pmac_daca_init(struct snd_pmac *chip) { int i, err; struct pmac_daca *mix; diff --git a/sound/ppc/keywest.c b/sound/ppc/keywest.c index a5afb2682e7f..835fa19ed461 100644 --- a/sound/ppc/keywest.c +++ b/sound/ppc/keywest.c @@ -33,10 +33,6 @@ static struct pmac_keywest *keywest_ctx; -#ifndef i2c_device_name -#define i2c_device_name(x) ((x)->name) -#endif - static int keywest_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -56,7 +52,7 @@ static int keywest_attach_adapter(struct i2c_adapter *adapter) if (! keywest_ctx) return -EINVAL; - if (strncmp(i2c_device_name(adapter), "mac-io", 6)) + if (strncmp(adapter->name, "mac-io", 6)) return 0; /* ignored */ memset(&info, 0, sizeof(struct i2c_board_info)); @@ -109,7 +105,7 @@ void snd_pmac_keywest_cleanup(struct pmac_keywest *i2c) } } -int __init snd_pmac_tumbler_post_init(void) +int __devinit snd_pmac_tumbler_post_init(void) { int err; @@ -124,7 +120,7 @@ int __init snd_pmac_tumbler_post_init(void) } /* exported */ -int __init snd_pmac_keywest_init(struct pmac_keywest *i2c) +int __devinit snd_pmac_keywest_init(struct pmac_keywest *i2c) { int err; diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c index 9b4e9c316695..7bc492ee77ec 100644 --- a/sound/ppc/pmac.c +++ b/sound/ppc/pmac.c @@ -702,7 +702,7 @@ static struct snd_pcm_ops snd_pmac_capture_ops = { .pointer = snd_pmac_capture_pointer, }; -int __init snd_pmac_pcm_new(struct snd_pmac *chip) +int __devinit snd_pmac_pcm_new(struct snd_pmac *chip) { struct snd_pcm *pcm; int err; @@ -908,7 +908,7 @@ static int snd_pmac_dev_free(struct snd_device *device) * check the machine support byteswap (little-endian) */ -static void __init detect_byte_swap(struct snd_pmac *chip) +static void __devinit detect_byte_swap(struct snd_pmac *chip) { struct device_node *mio; @@ -934,7 +934,7 @@ static void __init detect_byte_swap(struct snd_pmac *chip) /* * detect a sound chip */ -static int __init snd_pmac_detect(struct snd_pmac *chip) +static int __devinit snd_pmac_detect(struct snd_pmac *chip) { struct device_node *sound; struct device_node *dn; @@ -1143,7 +1143,7 @@ static int pmac_hp_detect_get(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new auto_mute_controls[] __initdata = { +static struct snd_kcontrol_new auto_mute_controls[] __devinitdata = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Auto Mute Switch", .info = snd_pmac_boolean_mono_info, @@ -1158,7 +1158,7 @@ static struct snd_kcontrol_new auto_mute_controls[] __initdata = { }, }; -int __init snd_pmac_add_automute(struct snd_pmac *chip) +int __devinit snd_pmac_add_automute(struct snd_pmac *chip) { int err; chip->auto_mute = 1; @@ -1175,7 +1175,7 @@ int __init snd_pmac_add_automute(struct snd_pmac *chip) /* * create and detect a pmac chip record */ -int __init snd_pmac_new(struct snd_card *card, struct snd_pmac **chip_return) +int __devinit snd_pmac_new(struct snd_card *card, struct snd_pmac **chip_return) { struct snd_pmac *chip; struct device_node *np; diff --git a/sound/ppc/snd_ps3.c b/sound/ppc/snd_ps3.c index f361c26506aa..53c81a547613 100644 --- a/sound/ppc/snd_ps3.c +++ b/sound/ppc/snd_ps3.c @@ -18,80 +18,30 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include +#include #include -#include -#include #include +#include +#include + +#include +#include #include #include -#include -#include #include +#include #include -#include -#include -#include -#include + #include +#include #include #include #include -#include "snd_ps3_reg.h" #include "snd_ps3.h" +#include "snd_ps3_reg.h" -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("PS3 sound driver"); -MODULE_AUTHOR("Sony Computer Entertainment Inc."); - -/* module entries */ -static int __init snd_ps3_init(void); -static void __exit snd_ps3_exit(void); - -/* ALSA snd driver ops */ -static int snd_ps3_pcm_open(struct snd_pcm_substream *substream); -static int snd_ps3_pcm_close(struct snd_pcm_substream *substream); -static int snd_ps3_pcm_prepare(struct snd_pcm_substream *substream); -static int snd_ps3_pcm_trigger(struct snd_pcm_substream *substream, - int cmd); -static snd_pcm_uframes_t snd_ps3_pcm_pointer(struct snd_pcm_substream - *substream); -static int snd_ps3_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params); -static int snd_ps3_pcm_hw_free(struct snd_pcm_substream *substream); - - -/* ps3_system_bus_driver entries */ -static int __init snd_ps3_driver_probe(struct ps3_system_bus_device *dev); -static int snd_ps3_driver_remove(struct ps3_system_bus_device *dev); - -/* address setup */ -static int snd_ps3_map_mmio(void); -static void snd_ps3_unmap_mmio(void); -static int snd_ps3_allocate_irq(void); -static void snd_ps3_free_irq(void); -static void snd_ps3_audio_set_base_addr(uint64_t ioaddr_start); - -/* interrupt handler */ -static irqreturn_t snd_ps3_interrupt(int irq, void *dev_id); - - -/* set sampling rate/format */ -static int snd_ps3_set_avsetting(struct snd_pcm_substream *substream); -/* take effect parameter change */ -static int snd_ps3_change_avsetting(struct snd_ps3_card_info *card); -/* initialize avsetting and take it effect */ -static int snd_ps3_init_avsetting(struct snd_ps3_card_info *card); -/* setup dma */ -static int snd_ps3_program_dma(struct snd_ps3_card_info *card, - enum snd_ps3_dma_filltype filltype); -static void snd_ps3_wait_for_dma_stop(struct snd_ps3_card_info *card); - -static dma_addr_t v_to_bus(struct snd_ps3_card_info *, void *vaddr, int ch); - - -module_init(snd_ps3_init); -module_exit(snd_ps3_exit); /* * global @@ -165,25 +115,13 @@ static const struct snd_pcm_hardware snd_ps3_pcm_hw = { .fifo_size = PS3_AUDIO_FIFO_SIZE }; -static struct snd_pcm_ops snd_ps3_pcm_spdif_ops = -{ - .open = snd_ps3_pcm_open, - .close = snd_ps3_pcm_close, - .prepare = snd_ps3_pcm_prepare, - .ioctl = snd_pcm_lib_ioctl, - .trigger = snd_ps3_pcm_trigger, - .pointer = snd_ps3_pcm_pointer, - .hw_params = snd_ps3_pcm_hw_params, - .hw_free = snd_ps3_pcm_hw_free -}; - static int snd_ps3_verify_dma_stop(struct snd_ps3_card_info *card, int count, int force_stop) { int dma_ch, done, retries, stop_forced = 0; uint32_t status; - for (dma_ch = 0; dma_ch < 8; dma_ch ++) { + for (dma_ch = 0; dma_ch < 8; dma_ch++) { retries = count; do { status = read_reg(PS3_AUDIO_KICK(dma_ch)) & @@ -259,9 +197,7 @@ static void snd_ps3_kick_dma(struct snd_ps3_card_info *card) /* * convert virtual addr to ioif bus addr. */ -static dma_addr_t v_to_bus(struct snd_ps3_card_info *card, - void * paddr, - int ch) +static dma_addr_t v_to_bus(struct snd_ps3_card_info *card, void *paddr, int ch) { return card->dma_start_bus_addr[ch] + (paddr - card->dma_start_vaddr[ch]); @@ -321,7 +257,7 @@ static int snd_ps3_program_dma(struct snd_ps3_card_info *card, spin_lock_irqsave(&card->dma_lock, irqsave); for (ch = 0; ch < 2; ch++) { start_vaddr = card->dma_next_transfer_vaddr[0]; - for (stage = 0; stage < fill_stages; stage ++) { + for (stage = 0; stage < fill_stages; stage++) { dma_ch = stage * 2 + ch; if (silent) dma_addr = card->null_buffer_start_dma_addr; @@ -371,6 +307,71 @@ static int snd_ps3_program_dma(struct snd_ps3_card_info *card, return 0; } +/* + * Interrupt handler + */ +static irqreturn_t snd_ps3_interrupt(int irq, void *dev_id) +{ + + uint32_t port_intr; + int underflow_occured = 0; + struct snd_ps3_card_info *card = dev_id; + + if (!card->running) { + update_reg(PS3_AUDIO_AX_IS, 0); + update_reg(PS3_AUDIO_INTR_0, 0); + return IRQ_HANDLED; + } + + port_intr = read_reg(PS3_AUDIO_AX_IS); + /* + *serial buffer empty detected (every 4 times), + *program next dma and kick it + */ + if (port_intr & PS3_AUDIO_AX_IE_ASOBEIE(0)) { + write_reg(PS3_AUDIO_AX_IS, PS3_AUDIO_AX_IE_ASOBEIE(0)); + if (port_intr & PS3_AUDIO_AX_IE_ASOBUIE(0)) { + write_reg(PS3_AUDIO_AX_IS, port_intr); + underflow_occured = 1; + } + if (card->silent) { + /* we are still in silent time */ + snd_ps3_program_dma(card, + (underflow_occured) ? + SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL : + SND_PS3_DMA_FILLTYPE_SILENT_RUNNING); + snd_ps3_kick_dma(card); + card->silent--; + } else { + snd_ps3_program_dma(card, + (underflow_occured) ? + SND_PS3_DMA_FILLTYPE_FIRSTFILL : + SND_PS3_DMA_FILLTYPE_RUNNING); + snd_ps3_kick_dma(card); + snd_pcm_period_elapsed(card->substream); + } + } else if (port_intr & PS3_AUDIO_AX_IE_ASOBUIE(0)) { + write_reg(PS3_AUDIO_AX_IS, PS3_AUDIO_AX_IE_ASOBUIE(0)); + /* + * serial out underflow, but buffer empty not detected. + * in this case, fill fifo with 0 to recover. After + * filling dummy data, serial automatically start to + * consume them and then will generate normal buffer + * empty interrupts. + * If both buffer underflow and buffer empty are occured, + * it is better to do nomal data transfer than empty one + */ + snd_ps3_program_dma(card, + SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL); + snd_ps3_kick_dma(card); + snd_ps3_program_dma(card, + SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL); + snd_ps3_kick_dma(card); + } + /* clear interrupt cause */ + return IRQ_HANDLED; +}; + /* * audio mute on/off * mute_on : 0 output enabled @@ -381,6 +382,142 @@ static int snd_ps3_mute(int mute_on) return ps3av_audio_mute(mute_on); } +/* + * av setting + * NOTE: calling this function may generate audio interrupt. + */ +static int snd_ps3_change_avsetting(struct snd_ps3_card_info *card) +{ + int ret, retries, i; + pr_debug("%s: start\n", __func__); + + ret = ps3av_set_audio_mode(card->avs.avs_audio_ch, + card->avs.avs_audio_rate, + card->avs.avs_audio_width, + card->avs.avs_audio_format, + card->avs.avs_audio_source); + /* + * Reset the following unwanted settings: + */ + + /* disable all 3wire buffers */ + update_mask_reg(PS3_AUDIO_AO_3WMCTRL, + ~(PS3_AUDIO_AO_3WMCTRL_ASOEN(0) | + PS3_AUDIO_AO_3WMCTRL_ASOEN(1) | + PS3_AUDIO_AO_3WMCTRL_ASOEN(2) | + PS3_AUDIO_AO_3WMCTRL_ASOEN(3)), + 0); + wmb(); /* ensure the hardware sees the change */ + /* wait for actually stopped */ + retries = 1000; + while ((read_reg(PS3_AUDIO_AO_3WMCTRL) & + (PS3_AUDIO_AO_3WMCTRL_ASORUN(0) | + PS3_AUDIO_AO_3WMCTRL_ASORUN(1) | + PS3_AUDIO_AO_3WMCTRL_ASORUN(2) | + PS3_AUDIO_AO_3WMCTRL_ASORUN(3))) && + --retries) { + udelay(1); + } + + /* reset buffer pointer */ + for (i = 0; i < 4; i++) { + update_reg(PS3_AUDIO_AO_3WCTRL(i), + PS3_AUDIO_AO_3WCTRL_ASOBRST_RESET); + udelay(10); + } + wmb(); /* ensure the hardware actually start resetting */ + + /* enable 3wire#0 buffer */ + update_reg(PS3_AUDIO_AO_3WMCTRL, PS3_AUDIO_AO_3WMCTRL_ASOEN(0)); + + + /* In 24bit mode,ALSA inserts a zero byte at first byte of per sample */ + update_mask_reg(PS3_AUDIO_AO_3WCTRL(0), + ~PS3_AUDIO_AO_3WCTRL_ASODF, + PS3_AUDIO_AO_3WCTRL_ASODF_LSB); + update_mask_reg(PS3_AUDIO_AO_SPDCTRL(0), + ~PS3_AUDIO_AO_SPDCTRL_SPODF, + PS3_AUDIO_AO_SPDCTRL_SPODF_LSB); + /* ensure all the setting above is written back to register */ + wmb(); + /* avsetting driver altered AX_IE, caller must reset it if you want */ + pr_debug("%s: end\n", __func__); + return ret; +} + +/* + * set sampling rate according to the substream + */ +static int snd_ps3_set_avsetting(struct snd_pcm_substream *substream) +{ + struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream); + struct snd_ps3_avsetting_info avs; + int ret; + + avs = card->avs; + + pr_debug("%s: called freq=%d width=%d\n", __func__, + substream->runtime->rate, + snd_pcm_format_width(substream->runtime->format)); + + pr_debug("%s: before freq=%d width=%d\n", __func__, + card->avs.avs_audio_rate, card->avs.avs_audio_width); + + /* sample rate */ + switch (substream->runtime->rate) { + case 44100: + avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_44K; + break; + case 48000: + avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_48K; + break; + case 88200: + avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_88K; + break; + case 96000: + avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_96K; + break; + default: + pr_info("%s: invalid rate %d\n", __func__, + substream->runtime->rate); + return 1; + } + + /* width */ + switch (snd_pcm_format_width(substream->runtime->format)) { + case 16: + avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_16; + break; + case 24: + avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_24; + break; + default: + pr_info("%s: invalid width %d\n", __func__, + snd_pcm_format_width(substream->runtime->format)); + return 1; + } + + memcpy(avs.avs_cs_info, ps3av_mode_cs_info, 8); + + if (memcmp(&card->avs, &avs, sizeof(avs))) { + pr_debug("%s: after freq=%d width=%d\n", __func__, + card->avs.avs_audio_rate, card->avs.avs_audio_width); + + card->avs = avs; + snd_ps3_change_avsetting(card); + ret = 0; + } else + ret = 1; + + /* check CS non-audio bit and mute accordingly */ + if (avs.avs_cs_info[0] & 0x02) + ps3av_audio_mute_analog(1); /* mute if non-audio */ + else + ps3av_audio_mute_analog(0); + + return ret; +} + /* * PCM operators */ @@ -406,6 +543,13 @@ static int snd_ps3_pcm_open(struct snd_pcm_substream *substream) return 0; }; +static int snd_ps3_pcm_close(struct snd_pcm_substream *substream) +{ + /* mute on */ + snd_ps3_mute(1); + return 0; +}; + static int snd_ps3_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { @@ -417,6 +561,13 @@ static int snd_ps3_pcm_hw_params(struct snd_pcm_substream *substream, return 0; }; +static int snd_ps3_pcm_hw_free(struct snd_pcm_substream *substream) +{ + int ret; + ret = snd_pcm_lib_free_pages(substream); + return ret; +}; + static int snd_ps3_delay_to_bytes(struct snd_pcm_substream *substream, unsigned int delay_ms) { @@ -556,202 +707,6 @@ static snd_pcm_uframes_t snd_ps3_pcm_pointer( return ret; }; -static int snd_ps3_pcm_hw_free(struct snd_pcm_substream *substream) -{ - int ret; - ret = snd_pcm_lib_free_pages(substream); - return ret; -}; - -static int snd_ps3_pcm_close(struct snd_pcm_substream *substream) -{ - /* mute on */ - snd_ps3_mute(1); - return 0; -}; - -static void snd_ps3_audio_fixup(struct snd_ps3_card_info *card) -{ - /* - * avsetting driver seems to never change the followings - * so, init them here once - */ - - /* no dma interrupt needed */ - write_reg(PS3_AUDIO_INTR_EN_0, 0); - - /* use every 4 buffer empty interrupt */ - update_mask_reg(PS3_AUDIO_AX_IC, - PS3_AUDIO_AX_IC_AASOIMD_MASK, - PS3_AUDIO_AX_IC_AASOIMD_EVERY4); - - /* enable 3wire clocks */ - update_mask_reg(PS3_AUDIO_AO_3WMCTRL, - ~(PS3_AUDIO_AO_3WMCTRL_ASOBCLKD_DISABLED | - PS3_AUDIO_AO_3WMCTRL_ASOLRCKD_DISABLED), - 0); - update_reg(PS3_AUDIO_AO_3WMCTRL, - PS3_AUDIO_AO_3WMCTRL_ASOPLRCK_DEFAULT); -} - -/* - * av setting - * NOTE: calling this function may generate audio interrupt. - */ -static int snd_ps3_change_avsetting(struct snd_ps3_card_info *card) -{ - int ret, retries, i; - pr_debug("%s: start\n", __func__); - - ret = ps3av_set_audio_mode(card->avs.avs_audio_ch, - card->avs.avs_audio_rate, - card->avs.avs_audio_width, - card->avs.avs_audio_format, - card->avs.avs_audio_source); - /* - * Reset the following unwanted settings: - */ - - /* disable all 3wire buffers */ - update_mask_reg(PS3_AUDIO_AO_3WMCTRL, - ~(PS3_AUDIO_AO_3WMCTRL_ASOEN(0) | - PS3_AUDIO_AO_3WMCTRL_ASOEN(1) | - PS3_AUDIO_AO_3WMCTRL_ASOEN(2) | - PS3_AUDIO_AO_3WMCTRL_ASOEN(3)), - 0); - wmb(); /* ensure the hardware sees the change */ - /* wait for actually stopped */ - retries = 1000; - while ((read_reg(PS3_AUDIO_AO_3WMCTRL) & - (PS3_AUDIO_AO_3WMCTRL_ASORUN(0) | - PS3_AUDIO_AO_3WMCTRL_ASORUN(1) | - PS3_AUDIO_AO_3WMCTRL_ASORUN(2) | - PS3_AUDIO_AO_3WMCTRL_ASORUN(3))) && - --retries) { - udelay(1); - } - - /* reset buffer pointer */ - for (i = 0; i < 4; i++) { - update_reg(PS3_AUDIO_AO_3WCTRL(i), - PS3_AUDIO_AO_3WCTRL_ASOBRST_RESET); - udelay(10); - } - wmb(); /* ensure the hardware actually start resetting */ - - /* enable 3wire#0 buffer */ - update_reg(PS3_AUDIO_AO_3WMCTRL, PS3_AUDIO_AO_3WMCTRL_ASOEN(0)); - - - /* In 24bit mode,ALSA inserts a zero byte at first byte of per sample */ - update_mask_reg(PS3_AUDIO_AO_3WCTRL(0), - ~PS3_AUDIO_AO_3WCTRL_ASODF, - PS3_AUDIO_AO_3WCTRL_ASODF_LSB); - update_mask_reg(PS3_AUDIO_AO_SPDCTRL(0), - ~PS3_AUDIO_AO_SPDCTRL_SPODF, - PS3_AUDIO_AO_SPDCTRL_SPODF_LSB); - /* ensure all the setting above is written back to register */ - wmb(); - /* avsetting driver altered AX_IE, caller must reset it if you want */ - pr_debug("%s: end\n", __func__); - return ret; -} - -static int snd_ps3_init_avsetting(struct snd_ps3_card_info *card) -{ - int ret; - pr_debug("%s: start\n", __func__); - card->avs.avs_audio_ch = PS3AV_CMD_AUDIO_NUM_OF_CH_2; - card->avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_48K; - card->avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_16; - card->avs.avs_audio_format = PS3AV_CMD_AUDIO_FORMAT_PCM; - card->avs.avs_audio_source = PS3AV_CMD_AUDIO_SOURCE_SERIAL; - memcpy(card->avs.avs_cs_info, ps3av_mode_cs_info, 8); - - ret = snd_ps3_change_avsetting(card); - - snd_ps3_audio_fixup(card); - - /* to start to generate SPDIF signal, fill data */ - snd_ps3_program_dma(card, SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL); - snd_ps3_kick_dma(card); - pr_debug("%s: end\n", __func__); - return ret; -} - -/* - * set sampling rate according to the substream - */ -static int snd_ps3_set_avsetting(struct snd_pcm_substream *substream) -{ - struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream); - struct snd_ps3_avsetting_info avs; - int ret; - - avs = card->avs; - - pr_debug("%s: called freq=%d width=%d\n", __func__, - substream->runtime->rate, - snd_pcm_format_width(substream->runtime->format)); - - pr_debug("%s: before freq=%d width=%d\n", __func__, - card->avs.avs_audio_rate, card->avs.avs_audio_width); - - /* sample rate */ - switch (substream->runtime->rate) { - case 44100: - avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_44K; - break; - case 48000: - avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_48K; - break; - case 88200: - avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_88K; - break; - case 96000: - avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_96K; - break; - default: - pr_info("%s: invalid rate %d\n", __func__, - substream->runtime->rate); - return 1; - } - - /* width */ - switch (snd_pcm_format_width(substream->runtime->format)) { - case 16: - avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_16; - break; - case 24: - avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_24; - break; - default: - pr_info("%s: invalid width %d\n", __func__, - snd_pcm_format_width(substream->runtime->format)); - return 1; - } - - memcpy(avs.avs_cs_info, ps3av_mode_cs_info, 8); - - if (memcmp(&card->avs, &avs, sizeof(avs))) { - pr_debug("%s: after freq=%d width=%d\n", __func__, - card->avs.avs_audio_rate, card->avs.avs_audio_width); - - card->avs = avs; - snd_ps3_change_avsetting(card); - ret = 0; - } else - ret = 1; - - /* check CS non-audio bit and mute accordingly */ - if (avs.avs_cs_info[0] & 0x02) - ps3av_audio_mute_analog(1); /* mute if non-audio */ - else - ps3av_audio_mute_analog(0); - - return ret; -} - /* * SPDIF status bits controls */ @@ -798,28 +753,39 @@ static struct snd_kcontrol_new spdif_ctls[] = { { .access = SNDRV_CTL_ELEM_ACCESS_READ, .iface = SNDRV_CTL_ELEM_IFACE_PCM, - .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK), + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, CON_MASK), .info = snd_ps3_spdif_mask_info, .get = snd_ps3_spdif_cmask_get, }, { .access = SNDRV_CTL_ELEM_ACCESS_READ, .iface = SNDRV_CTL_ELEM_IFACE_PCM, - .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK), + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, PRO_MASK), .info = snd_ps3_spdif_mask_info, .get = snd_ps3_spdif_pmask_get, }, { .iface = SNDRV_CTL_ELEM_IFACE_PCM, - .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), .info = snd_ps3_spdif_mask_info, .get = snd_ps3_spdif_default_get, .put = snd_ps3_spdif_default_put, }, }; +static struct snd_pcm_ops snd_ps3_pcm_spdif_ops = { + .open = snd_ps3_pcm_open, + .close = snd_ps3_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_ps3_pcm_hw_params, + .hw_free = snd_ps3_pcm_hw_free, + .prepare = snd_ps3_pcm_prepare, + .trigger = snd_ps3_pcm_trigger, + .pointer = snd_ps3_pcm_pointer, +}; -static int snd_ps3_map_mmio(void) + +static int __devinit snd_ps3_map_mmio(void) { the_card.mapped_mmio_vaddr = ioremap(the_card.ps3_dev->m_region->bus_addr, @@ -841,7 +807,7 @@ static void snd_ps3_unmap_mmio(void) the_card.mapped_mmio_vaddr = NULL; } -static int snd_ps3_allocate_irq(void) +static int __devinit snd_ps3_allocate_irq(void) { int ret; u64 lpar_addr, lpar_size; @@ -899,7 +865,7 @@ static void snd_ps3_free_irq(void) ps3_irq_plug_destroy(the_card.irq_no); } -static void snd_ps3_audio_set_base_addr(uint64_t ioaddr_start) +static void __devinit snd_ps3_audio_set_base_addr(uint64_t ioaddr_start) { uint64_t val; int ret; @@ -915,7 +881,53 @@ static void snd_ps3_audio_set_base_addr(uint64_t ioaddr_start) ret); } -static int __init snd_ps3_driver_probe(struct ps3_system_bus_device *dev) +static void __devinit snd_ps3_audio_fixup(struct snd_ps3_card_info *card) +{ + /* + * avsetting driver seems to never change the followings + * so, init them here once + */ + + /* no dma interrupt needed */ + write_reg(PS3_AUDIO_INTR_EN_0, 0); + + /* use every 4 buffer empty interrupt */ + update_mask_reg(PS3_AUDIO_AX_IC, + PS3_AUDIO_AX_IC_AASOIMD_MASK, + PS3_AUDIO_AX_IC_AASOIMD_EVERY4); + + /* enable 3wire clocks */ + update_mask_reg(PS3_AUDIO_AO_3WMCTRL, + ~(PS3_AUDIO_AO_3WMCTRL_ASOBCLKD_DISABLED | + PS3_AUDIO_AO_3WMCTRL_ASOLRCKD_DISABLED), + 0); + update_reg(PS3_AUDIO_AO_3WMCTRL, + PS3_AUDIO_AO_3WMCTRL_ASOPLRCK_DEFAULT); +} + +static int __devinit snd_ps3_init_avsetting(struct snd_ps3_card_info *card) +{ + int ret; + pr_debug("%s: start\n", __func__); + card->avs.avs_audio_ch = PS3AV_CMD_AUDIO_NUM_OF_CH_2; + card->avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_48K; + card->avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_16; + card->avs.avs_audio_format = PS3AV_CMD_AUDIO_FORMAT_PCM; + card->avs.avs_audio_source = PS3AV_CMD_AUDIO_SOURCE_SERIAL; + memcpy(card->avs.avs_cs_info, ps3av_mode_cs_info, 8); + + ret = snd_ps3_change_avsetting(card); + + snd_ps3_audio_fixup(card); + + /* to start to generate SPDIF signal, fill data */ + snd_ps3_program_dma(card, SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL); + snd_ps3_kick_dma(card); + pr_debug("%s: end\n", __func__); + return ret; +} + +static int __devinit snd_ps3_driver_probe(struct ps3_system_bus_device *dev) { int i, ret; u64 lpar_addr, lpar_size; @@ -1020,11 +1032,12 @@ static int __init snd_ps3_driver_probe(struct ps3_system_bus_device *dev) * its size should be lager than PS3_AUDIO_FIFO_STAGE_SIZE * 2 * PAGE_SIZE is enogh */ - if (!(the_card.null_buffer_start_vaddr = - dma_alloc_coherent(&the_card.ps3_dev->core, - PAGE_SIZE, - &the_card.null_buffer_start_dma_addr, - GFP_KERNEL))) { + the_card.null_buffer_start_vaddr = + dma_alloc_coherent(&the_card.ps3_dev->core, + PAGE_SIZE, + &the_card.null_buffer_start_dma_addr, + GFP_KERNEL); + if (!the_card.null_buffer_start_vaddr) { pr_info("%s: nullbuffer alloc failed\n", __func__); goto clean_preallocate; } @@ -1114,71 +1127,6 @@ static struct ps3_system_bus_driver snd_ps3_bus_driver_info = { }; -/* - * Interrupt handler - */ -static irqreturn_t snd_ps3_interrupt(int irq, void *dev_id) -{ - - uint32_t port_intr; - int underflow_occured = 0; - struct snd_ps3_card_info *card = dev_id; - - if (!card->running) { - update_reg(PS3_AUDIO_AX_IS, 0); - update_reg(PS3_AUDIO_INTR_0, 0); - return IRQ_HANDLED; - } - - port_intr = read_reg(PS3_AUDIO_AX_IS); - /* - *serial buffer empty detected (every 4 times), - *program next dma and kick it - */ - if (port_intr & PS3_AUDIO_AX_IE_ASOBEIE(0)) { - write_reg(PS3_AUDIO_AX_IS, PS3_AUDIO_AX_IE_ASOBEIE(0)); - if (port_intr & PS3_AUDIO_AX_IE_ASOBUIE(0)) { - write_reg(PS3_AUDIO_AX_IS, port_intr); - underflow_occured = 1; - } - if (card->silent) { - /* we are still in silent time */ - snd_ps3_program_dma(card, - (underflow_occured) ? - SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL : - SND_PS3_DMA_FILLTYPE_SILENT_RUNNING); - snd_ps3_kick_dma(card); - card->silent --; - } else { - snd_ps3_program_dma(card, - (underflow_occured) ? - SND_PS3_DMA_FILLTYPE_FIRSTFILL : - SND_PS3_DMA_FILLTYPE_RUNNING); - snd_ps3_kick_dma(card); - snd_pcm_period_elapsed(card->substream); - } - } else if (port_intr & PS3_AUDIO_AX_IE_ASOBUIE(0)) { - write_reg(PS3_AUDIO_AX_IS, PS3_AUDIO_AX_IE_ASOBUIE(0)); - /* - * serial out underflow, but buffer empty not detected. - * in this case, fill fifo with 0 to recover. After - * filling dummy data, serial automatically start to - * consume them and then will generate normal buffer - * empty interrupts. - * If both buffer underflow and buffer empty are occured, - * it is better to do nomal data transfer than empty one - */ - snd_ps3_program_dma(card, - SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL); - snd_ps3_kick_dma(card); - snd_ps3_program_dma(card, - SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL); - snd_ps3_kick_dma(card); - } - /* clear interrupt cause */ - return IRQ_HANDLED; -}; - /* * module/subsystem initialize/terminate */ @@ -1197,10 +1145,15 @@ static int __init snd_ps3_init(void) return ret; } +module_init(snd_ps3_init); static void __exit snd_ps3_exit(void) { ps3_system_bus_driver_unregister(&snd_ps3_bus_driver_info); } +module_exit(snd_ps3_exit); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("PS3 sound driver"); +MODULE_AUTHOR("Sony Computer Entertainment Inc."); MODULE_ALIAS(PS3_MODULE_ALIAS_SOUND); diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c index 40222fcc0878..08e584d1453a 100644 --- a/sound/ppc/tumbler.c +++ b/sound/ppc/tumbler.c @@ -838,7 +838,7 @@ static int snapper_put_capture_source(struct snd_kcontrol *kcontrol, /* */ -static struct snd_kcontrol_new tumbler_mixers[] __initdata = { +static struct snd_kcontrol_new tumbler_mixers[] __devinitdata = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Volume", .info = tumbler_info_master_volume, @@ -862,7 +862,7 @@ static struct snd_kcontrol_new tumbler_mixers[] __initdata = { }, }; -static struct snd_kcontrol_new snapper_mixers[] __initdata = { +static struct snd_kcontrol_new snapper_mixers[] __devinitdata = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Volume", .info = tumbler_info_master_volume, @@ -895,7 +895,7 @@ static struct snd_kcontrol_new snapper_mixers[] __initdata = { }, }; -static struct snd_kcontrol_new tumbler_hp_sw __initdata = { +static struct snd_kcontrol_new tumbler_hp_sw __devinitdata = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Headphone Playback Switch", .info = snd_pmac_boolean_mono_info, @@ -903,7 +903,7 @@ static struct snd_kcontrol_new tumbler_hp_sw __initdata = { .put = tumbler_put_mute_switch, .private_value = TUMBLER_MUTE_HP, }; -static struct snd_kcontrol_new tumbler_speaker_sw __initdata = { +static struct snd_kcontrol_new tumbler_speaker_sw __devinitdata = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PC Speaker Playback Switch", .info = snd_pmac_boolean_mono_info, @@ -911,7 +911,7 @@ static struct snd_kcontrol_new tumbler_speaker_sw __initdata = { .put = tumbler_put_mute_switch, .private_value = TUMBLER_MUTE_AMP, }; -static struct snd_kcontrol_new tumbler_lineout_sw __initdata = { +static struct snd_kcontrol_new tumbler_lineout_sw __devinitdata = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Line Out Playback Switch", .info = snd_pmac_boolean_mono_info, @@ -919,7 +919,7 @@ static struct snd_kcontrol_new tumbler_lineout_sw __initdata = { .put = tumbler_put_mute_switch, .private_value = TUMBLER_MUTE_LINE, }; -static struct snd_kcontrol_new tumbler_drc_sw __initdata = { +static struct snd_kcontrol_new tumbler_drc_sw __devinitdata = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "DRC Switch", .info = snd_pmac_boolean_mono_info, @@ -1269,7 +1269,7 @@ static void tumbler_resume(struct snd_pmac *chip) #endif /* initialize tumbler */ -static int __init tumbler_init(struct snd_pmac *chip) +static int __devinit tumbler_init(struct snd_pmac *chip) { int irq; struct pmac_tumbler *mix = chip->mixer_data; @@ -1339,7 +1339,7 @@ static void tumbler_cleanup(struct snd_pmac *chip) } /* exported */ -int __init snd_pmac_tumbler_init(struct snd_pmac *chip) +int __devinit snd_pmac_tumbler_init(struct snd_pmac *chip) { int i, err; struct pmac_tumbler *mix; diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index 3d2bb6fc6dcc..d3e786a9a0a7 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -32,7 +32,9 @@ source "sound/soc/fsl/Kconfig" source "sound/soc/omap/Kconfig" source "sound/soc/pxa/Kconfig" source "sound/soc/s3c24xx/Kconfig" +source "sound/soc/s6000/Kconfig" source "sound/soc/sh/Kconfig" +source "sound/soc/txx9/Kconfig" # Supported codecs source "sound/soc/codecs/Kconfig" diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 0237879fd412..6f1e28de23cf 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -10,4 +10,6 @@ obj-$(CONFIG_SND_SOC) += fsl/ obj-$(CONFIG_SND_SOC) += omap/ obj-$(CONFIG_SND_SOC) += pxa/ obj-$(CONFIG_SND_SOC) += s3c24xx/ +obj-$(CONFIG_SND_SOC) += s6000/ obj-$(CONFIG_SND_SOC) += sh/ +obj-$(CONFIG_SND_SOC) += txx9/ diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig index a608d7009dbd..e720d5e6f04c 100644 --- a/sound/soc/atmel/Kconfig +++ b/sound/soc/atmel/Kconfig @@ -41,3 +41,11 @@ config SND_AT32_SOC_PLAYPAQ_SLAVE and FRAME signals on the PlayPaq. Unless you want to play with the AT32 as the SSC master, you probably want to say N here, as this will give you better sound quality. + +config SND_AT91_SOC_AFEB9260 + tristate "SoC Audio support for AFEB9260 board" + depends on ARCH_AT91 && MACH_AFEB9260 && SND_ATMEL_SOC + select SND_ATMEL_SOC_SSC + select SND_SOC_TLV320AIC23 + help + Say Y here to support sound on AFEB9260 board. diff --git a/sound/soc/atmel/Makefile b/sound/soc/atmel/Makefile index f54a7cc68e66..e7ea56bd5f82 100644 --- a/sound/soc/atmel/Makefile +++ b/sound/soc/atmel/Makefile @@ -13,3 +13,4 @@ snd-soc-playpaq-objs := playpaq_wm8510.o obj-$(CONFIG_SND_AT91_SOC_SAM9G20_WM8731) += snd-soc-sam9g20-wm8731.o obj-$(CONFIG_SND_AT32_SOC_PLAYPAQ) += snd-soc-playpaq.o +obj-$(CONFIG_SND_AT91_SOC_AFEB9260) += snd-soc-afeb9260.o diff --git a/sound/soc/atmel/playpaq_wm8510.c b/sound/soc/atmel/playpaq_wm8510.c index 70657534e6b1..9eb610c2ba91 100644 --- a/sound/soc/atmel/playpaq_wm8510.c +++ b/sound/soc/atmel/playpaq_wm8510.c @@ -117,7 +117,7 @@ static struct ssc_clock_data playpaq_wm8510_calc_ssc_clock( * Find actual rate, compare to requested rate */ actual_rate = (cd.ssc_rate / (cd.cmr_div * 2)) / (2 * (cd.period + 1)); - pr_debug("playpaq_wm8510: Request rate = %d, actual rate = %d\n", + pr_debug("playpaq_wm8510: Request rate = %u, actual rate = %u\n", rate, actual_rate); diff --git a/sound/soc/atmel/snd-soc-afeb9260.c b/sound/soc/atmel/snd-soc-afeb9260.c new file mode 100644 index 000000000000..23349de27313 --- /dev/null +++ b/sound/soc/atmel/snd-soc-afeb9260.c @@ -0,0 +1,203 @@ +/* + * afeb9260.c -- SoC audio for AFEB9260 + * + * Copyright (C) 2009 Sergey Lapin + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "../codecs/tlv320aic23.h" +#include "atmel-pcm.h" +#include "atmel_ssc_dai.h" + +#define CODEC_CLOCK 12000000 + +static int afeb9260_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + int err; + + /* Set codec DAI configuration */ + err = snd_soc_dai_set_fmt(codec_dai, + SND_SOC_DAIFMT_I2S| + SND_SOC_DAIFMT_NB_IF | + SND_SOC_DAIFMT_CBM_CFM); + if (err < 0) { + printk(KERN_ERR "can't set codec DAI configuration\n"); + return err; + } + + /* Set cpu DAI configuration */ + err = snd_soc_dai_set_fmt(cpu_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_IF | + SND_SOC_DAIFMT_CBM_CFM); + if (err < 0) { + printk(KERN_ERR "can't set cpu DAI configuration\n"); + return err; + } + + /* Set the codec system clock for DAC and ADC */ + err = + snd_soc_dai_set_sysclk(codec_dai, 0, CODEC_CLOCK, SND_SOC_CLOCK_IN); + + if (err < 0) { + printk(KERN_ERR "can't set codec system clock\n"); + return err; + } + + return err; +} + +static struct snd_soc_ops afeb9260_ops = { + .hw_params = afeb9260_hw_params, +}; + +static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_LINE("Line In", NULL), + SND_SOC_DAPM_MIC("Mic Jack", NULL), +}; + +static const struct snd_soc_dapm_route audio_map[] = { + {"Headphone Jack", NULL, "LHPOUT"}, + {"Headphone Jack", NULL, "RHPOUT"}, + + {"LLINEIN", NULL, "Line In"}, + {"RLINEIN", NULL, "Line In"}, + + {"MICIN", NULL, "Mic Jack"}, +}; + +static int afeb9260_tlv320aic23_init(struct snd_soc_codec *codec) +{ + + /* Add afeb9260 specific widgets */ + snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets, + ARRAY_SIZE(tlv320aic23_dapm_widgets)); + + /* Set up afeb9260 specific audio path audio_map */ + snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); + + snd_soc_dapm_enable_pin(codec, "Headphone Jack"); + snd_soc_dapm_enable_pin(codec, "Line In"); + snd_soc_dapm_enable_pin(codec, "Mic Jack"); + + snd_soc_dapm_sync(codec); + + return 0; +} + +/* Digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link afeb9260_dai = { + .name = "TLV320AIC23", + .stream_name = "AIC23", + .cpu_dai = &atmel_ssc_dai[0], + .codec_dai = &tlv320aic23_dai, + .init = afeb9260_tlv320aic23_init, + .ops = &afeb9260_ops, +}; + +/* Audio machine driver */ +static struct snd_soc_card snd_soc_machine_afeb9260 = { + .name = "AFEB9260", + .platform = &atmel_soc_platform, + .dai_link = &afeb9260_dai, + .num_links = 1, +}; + +/* Audio subsystem */ +static struct snd_soc_device afeb9260_snd_devdata = { + .card = &snd_soc_machine_afeb9260, + .codec_dev = &soc_codec_dev_tlv320aic23, +}; + +static struct platform_device *afeb9260_snd_device; + +static int __init afeb9260_soc_init(void) +{ + int err; + struct device *dev; + struct atmel_ssc_info *ssc_p = afeb9260_dai.cpu_dai->private_data; + struct ssc_device *ssc = NULL; + + if (!(machine_is_afeb9260())) + return -ENODEV; + + ssc = ssc_request(0); + if (IS_ERR(ssc)) { + printk(KERN_ERR "ASoC: Failed to request SSC 0\n"); + err = PTR_ERR(ssc); + ssc = NULL; + goto err_ssc; + } + ssc_p->ssc = ssc; + + afeb9260_snd_device = platform_device_alloc("soc-audio", -1); + if (!afeb9260_snd_device) { + printk(KERN_ERR "ASoC: Platform device allocation failed\n"); + return -ENOMEM; + } + + platform_set_drvdata(afeb9260_snd_device, &afeb9260_snd_devdata); + afeb9260_snd_devdata.dev = &afeb9260_snd_device->dev; + err = platform_device_add(afeb9260_snd_device); + if (err) + goto err1; + + dev = &afeb9260_snd_device->dev; + + return 0; +err1: + platform_device_del(afeb9260_snd_device); + platform_device_put(afeb9260_snd_device); +err_ssc: + return err; + +} + +static void __exit afeb9260_soc_exit(void) +{ + platform_device_unregister(afeb9260_snd_device); +} + +module_init(afeb9260_soc_init); +module_exit(afeb9260_soc_exit); + +MODULE_AUTHOR("Sergey Lapin "); +MODULE_DESCRIPTION("ALSA SoC for AFEB9260"); +MODULE_LICENSE("GPL"); + diff --git a/sound/soc/blackfin/bf5xx-ac97.c b/sound/soc/blackfin/bf5xx-ac97.c index 8a935f2d1767..b1ed423fabd5 100644 --- a/sound/soc/blackfin/bf5xx-ac97.c +++ b/sound/soc/blackfin/bf5xx-ac97.c @@ -31,6 +31,15 @@ #include "bf5xx-sport.h" #include "bf5xx-ac97.h" +/* Anomaly notes: + * 05000250 - AD1980 is running in TDM mode and RFS/TFS are generated by SPORT + * contrtoller. But, RFSDIV and TFSDIV are always set to 16*16-1, + * while the max AC97 data size is 13*16. The DIV is always larger + * than data size. AD73311 and ad2602 are not running in TDM mode. + * AD1836 and AD73322 depend on external RFS/TFS only. So, this + * anomaly does not affect blackfin sound drivers. +*/ + static int *cmd_count; static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM; diff --git a/sound/soc/blackfin/bf5xx-i2s.c b/sound/soc/blackfin/bf5xx-i2s.c index 964824419678..af06904bab0f 100644 --- a/sound/soc/blackfin/bf5xx-i2s.c +++ b/sound/soc/blackfin/bf5xx-i2s.c @@ -50,6 +50,7 @@ struct bf5xx_i2s_port { u16 tcr2; u16 rcr2; int counter; + int configured; }; static struct bf5xx_i2s_port bf5xx_i2s; @@ -168,7 +169,7 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream, break; } - if (bf5xx_i2s.counter == 1) { + if (!bf5xx_i2s.configured) { /* * TX and RX are not independent,they are enabled at the * same time, even if only one side is running. So, we @@ -177,6 +178,7 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream, * * CPU DAI:slave mode. */ + bf5xx_i2s.configured = 1; ret = sport_config_rx(sport_handle, bf5xx_i2s.rcr1, bf5xx_i2s.rcr2, 0, 0); if (ret) { @@ -200,6 +202,9 @@ static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream, { pr_debug("%s enter\n", __func__); bf5xx_i2s.counter--; + /* No active stream, SPORT is allowed to be configured again. */ + if (!bf5xx_i2s.counter) + bf5xx_i2s.configured = 0; } static int bf5xx_i2s_probe(struct platform_device *pdev, @@ -244,8 +249,7 @@ static int bf5xx_i2s_suspend(struct snd_soc_dai *dai) return 0; } -static int bf5xx_i2s_resume(struct platform_device *pdev, - struct snd_soc_dai *dai) +static int bf5xx_i2s_resume(struct snd_soc_dai *dai) { int ret; struct sport_device *sport = diff --git a/sound/soc/blackfin/bf5xx-sport.c b/sound/soc/blackfin/bf5xx-sport.c index b7953c8cf838..469ce7fab20c 100644 --- a/sound/soc/blackfin/bf5xx-sport.c +++ b/sound/soc/blackfin/bf5xx-sport.c @@ -190,7 +190,7 @@ static inline int sport_hook_rx_dummy(struct sport_device *sport) desc = get_dma_next_desc_ptr(sport->dma_rx_chan); /* Copy the descriptor which will be damaged to backup */ temp_desc = *desc; - desc->x_count = 0xa; + desc->x_count = sport->dummy_count / 2; desc->y_count = 0; desc->next_desc_addr = sport->dummy_rx_desc; local_irq_restore(flags); @@ -309,7 +309,7 @@ static inline int sport_hook_tx_dummy(struct sport_device *sport) desc = get_dma_next_desc_ptr(sport->dma_tx_chan); /* Store the descriptor which will be damaged */ temp_desc = *desc; - desc->x_count = 0xa; + desc->x_count = sport->dummy_count / 2; desc->y_count = 0; desc->next_desc_addr = sport->dummy_tx_desc; local_irq_restore(flags); diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index b6c7f7a01cb0..bbc97fd76648 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -18,7 +18,9 @@ config SND_SOC_ALL_CODECS select SND_SOC_AK4535 if I2C select SND_SOC_CS4270 if I2C select SND_SOC_PCM3008 + select SND_SOC_SPDIF select SND_SOC_SSM2602 if I2C + select SND_SOC_STAC9766 if SND_SOC_AC97_BUS select SND_SOC_TLV320AIC23 if I2C select SND_SOC_TLV320AIC26 if SPI_MASTER select SND_SOC_TLV320AIC3X if I2C @@ -35,8 +37,12 @@ config SND_SOC_ALL_CODECS select SND_SOC_WM8753 if SND_SOC_I2C_AND_SPI select SND_SOC_WM8900 if I2C select SND_SOC_WM8903 if I2C + select SND_SOC_WM8940 if I2C + select SND_SOC_WM8960 if I2C select SND_SOC_WM8971 if I2C + select SND_SOC_WM8988 if SND_SOC_I2C_AND_SPI select SND_SOC_WM8990 if I2C + select SND_SOC_WM9081 if I2C select SND_SOC_WM9705 if SND_SOC_AC97_BUS select SND_SOC_WM9712 if SND_SOC_AC97_BUS select SND_SOC_WM9713 if SND_SOC_AC97_BUS @@ -86,9 +92,15 @@ config SND_SOC_L3 config SND_SOC_PCM3008 tristate +config SND_SOC_SPDIF + tristate + config SND_SOC_SSM2602 tristate +config SND_SOC_STAC9766 + tristate + config SND_SOC_TLV320AIC23 tristate @@ -138,12 +150,24 @@ config SND_SOC_WM8900 config SND_SOC_WM8903 tristate +config SND_SOC_WM8940 + tristate + +config SND_SOC_WM8960 + tristate + config SND_SOC_WM8971 tristate +config SND_SOC_WM8988 + tristate + config SND_SOC_WM8990 tristate +config SND_SOC_WM9081 + tristate + config SND_SOC_WM9705 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index f2653803ede8..8b7530546f4d 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -6,7 +6,9 @@ snd-soc-ak4535-objs := ak4535.o snd-soc-cs4270-objs := cs4270.o snd-soc-l3-objs := l3.o snd-soc-pcm3008-objs := pcm3008.o +snd-soc-spdif-objs := spdif_transciever.o snd-soc-ssm2602-objs := ssm2602.o +snd-soc-stac9766-objs := stac9766.o snd-soc-tlv320aic23-objs := tlv320aic23.o snd-soc-tlv320aic26-objs := tlv320aic26.o snd-soc-tlv320aic3x-objs := tlv320aic3x.o @@ -23,8 +25,12 @@ snd-soc-wm8750-objs := wm8750.o snd-soc-wm8753-objs := wm8753.o snd-soc-wm8900-objs := wm8900.o snd-soc-wm8903-objs := wm8903.o +snd-soc-wm8940-objs := wm8940.o +snd-soc-wm8960-objs := wm8960.o snd-soc-wm8971-objs := wm8971.o +snd-soc-wm8988-objs := wm8988.o snd-soc-wm8990-objs := wm8990.o +snd-soc-wm9081-objs := wm9081.o snd-soc-wm9705-objs := wm9705.o snd-soc-wm9712-objs := wm9712.o snd-soc-wm9713-objs := wm9713.o @@ -37,7 +43,9 @@ obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o +obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif.o obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o +obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o @@ -55,7 +63,11 @@ obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o obj-$(CONFIG_SND_SOC_WM8900) += snd-soc-wm8900.o obj-$(CONFIG_SND_SOC_WM8903) += snd-soc-wm8903.o obj-$(CONFIG_SND_SOC_WM8971) += snd-soc-wm8971.o +obj-$(CONFIG_SND_SOC_WM8940) += snd-soc-wm8940.o +obj-$(CONFIG_SND_SOC_WM8960) += snd-soc-wm8960.o +obj-$(CONFIG_SND_SOC_WM8988) += snd-soc-wm8988.o obj-$(CONFIG_SND_SOC_WM8990) += snd-soc-wm8990.o +obj-$(CONFIG_SND_SOC_WM9081) += snd-soc-wm9081.o obj-$(CONFIG_SND_SOC_WM9705) += snd-soc-wm9705.o obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c index b0d4af145b87..932299bb5d1e 100644 --- a/sound/soc/codecs/ac97.c +++ b/sound/soc/codecs/ac97.c @@ -53,13 +53,13 @@ struct snd_soc_dai ac97_dai = { .channels_min = 1, .channels_max = 2, .rates = STD_AC97_RATES, - .formats = SNDRV_PCM_FMTBIT_S16_LE,}, + .formats = SND_SOC_STD_AC97_FMTS,}, .capture = { .stream_name = "AC97 Capture", .channels_min = 1, .channels_max = 2, .rates = STD_AC97_RATES, - .formats = SNDRV_PCM_FMTBIT_S16_LE,}, + .formats = SND_SOC_STD_AC97_FMTS,}, .ops = &ac97_dai_ops, }; EXPORT_SYMBOL_GPL(ac97_dai); diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index ddb3b08ac23c..d7440a982d22 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c @@ -137,13 +137,13 @@ struct snd_soc_dai ad1980_dai = { .channels_min = 2, .channels_max = 6, .rates = SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, }, + .formats = SND_SOC_STD_AC97_FMTS, }, .capture = { .stream_name = "Capture", .channels_min = 2, .channels_max = 2, .rates = SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, }, + .formats = SND_SOC_STD_AC97_FMTS, }, }; EXPORT_SYMBOL_GPL(ad1980_dai); diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index 7fa09a387622..a32b8226c8a4 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c @@ -18,7 +18,7 @@ * - The machine driver's 'startup' function must call * cs4270_set_dai_sysclk() with the value of MCLK. * - Only I2S and left-justified modes are supported - * - Power management is not supported + * - Power management is supported */ #include @@ -27,6 +27,7 @@ #include #include #include +#include #include "cs4270.h" @@ -56,6 +57,7 @@ #define CS4270_FIRSTREG 0x01 #define CS4270_LASTREG 0x08 #define CS4270_NUMREGS (CS4270_LASTREG - CS4270_FIRSTREG + 1) +#define CS4270_I2C_INCR 0x80 /* Bit masks for the CS4270 registers */ #define CS4270_CHIPID_ID 0xF0 @@ -64,6 +66,8 @@ #define CS4270_PWRCTL_PDN_ADC 0x20 #define CS4270_PWRCTL_PDN_DAC 0x02 #define CS4270_PWRCTL_PDN 0x01 +#define CS4270_PWRCTL_PDN_ALL \ + (CS4270_PWRCTL_PDN_ADC | CS4270_PWRCTL_PDN_DAC | CS4270_PWRCTL_PDN) #define CS4270_MODE_SPEED_MASK 0x30 #define CS4270_MODE_1X 0x00 #define CS4270_MODE_2X 0x10 @@ -109,6 +113,7 @@ struct cs4270_private { unsigned int mclk; /* Input frequency of the MCLK pin */ unsigned int mode; /* The mode (I2S or left-justified) */ unsigned int slave_mode; + unsigned int manual_mute; }; /** @@ -295,7 +300,7 @@ static int cs4270_fill_cache(struct snd_soc_codec *codec) s32 length; length = i2c_smbus_read_i2c_block_data(i2c_client, - CS4270_FIRSTREG | 0x80, CS4270_NUMREGS, cache); + CS4270_FIRSTREG | CS4270_I2C_INCR, CS4270_NUMREGS, cache); if (length != CS4270_NUMREGS) { dev_err(codec->dev, "i2c read failure, addr=0x%x\n", @@ -453,7 +458,7 @@ static int cs4270_hw_params(struct snd_pcm_substream *substream, } /** - * cs4270_mute - enable/disable the CS4270 external mute + * cs4270_dai_mute - enable/disable the CS4270 external mute * @dai: the SOC DAI * @mute: 0 = disable mute, 1 = enable mute * @@ -462,21 +467,52 @@ static int cs4270_hw_params(struct snd_pcm_substream *substream, * board does not have the MUTEA or MUTEB pins connected to such circuitry, * then this function will do nothing. */ -static int cs4270_mute(struct snd_soc_dai *dai, int mute) +static int cs4270_dai_mute(struct snd_soc_dai *dai, int mute) { struct snd_soc_codec *codec = dai->codec; + struct cs4270_private *cs4270 = codec->private_data; int reg6; reg6 = snd_soc_read(codec, CS4270_MUTE); if (mute) reg6 |= CS4270_MUTE_DAC_A | CS4270_MUTE_DAC_B; - else + else { reg6 &= ~(CS4270_MUTE_DAC_A | CS4270_MUTE_DAC_B); + reg6 |= cs4270->manual_mute; + } return snd_soc_write(codec, CS4270_MUTE, reg6); } +/** + * cs4270_soc_put_mute - put callback for the 'Master Playback switch' + * alsa control. + * @kcontrol: mixer control + * @ucontrol: control element information + * + * This function basically passes the arguments on to the generic + * snd_soc_put_volsw() function and saves the mute information in + * our private data structure. This is because we want to prevent + * cs4270_dai_mute() neglecting the user's decision to manually + * mute the codec's output. + * + * Returns 0 for success. + */ +static int cs4270_soc_put_mute(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct cs4270_private *cs4270 = codec->private_data; + int left = !ucontrol->value.integer.value[0]; + int right = !ucontrol->value.integer.value[1]; + + cs4270->manual_mute = (left ? CS4270_MUTE_DAC_A : 0) | + (right ? CS4270_MUTE_DAC_B : 0); + + return snd_soc_put_volsw(kcontrol, ucontrol); +} + /* A list of non-DAPM controls that the CS4270 supports */ static const struct snd_kcontrol_new cs4270_snd_controls[] = { SOC_DOUBLE_R("Master Playback Volume", @@ -486,7 +522,9 @@ static const struct snd_kcontrol_new cs4270_snd_controls[] = { SOC_SINGLE("Zero Cross Switch", CS4270_TRANS, 5, 1, 0), SOC_SINGLE("Popguard Switch", CS4270_MODE, 0, 1, 1), SOC_SINGLE("Auto-Mute Switch", CS4270_MUTE, 5, 1, 0), - SOC_DOUBLE("Master Capture Switch", CS4270_MUTE, 3, 4, 1, 0) + SOC_DOUBLE("Master Capture Switch", CS4270_MUTE, 3, 4, 1, 1), + SOC_DOUBLE_EXT("Master Playback Switch", CS4270_MUTE, 0, 1, 1, 1, + snd_soc_get_volsw, cs4270_soc_put_mute), }; /* @@ -506,7 +544,7 @@ static struct snd_soc_dai_ops cs4270_dai_ops = { .hw_params = cs4270_hw_params, .set_sysclk = cs4270_set_dai_sysclk, .set_fmt = cs4270_set_dai_fmt, - .digital_mute = cs4270_mute, + .digital_mute = cs4270_dai_mute, }; struct snd_soc_dai cs4270_dai = { @@ -753,6 +791,57 @@ static struct i2c_device_id cs4270_id[] = { }; MODULE_DEVICE_TABLE(i2c, cs4270_id); +#ifdef CONFIG_PM + +/* This suspend/resume implementation can handle both - a simple standby + * where the codec remains powered, and a full suspend, where the voltage + * domain the codec is connected to is teared down and/or any other hardware + * reset condition is asserted. + * + * The codec's own power saving features are enabled in the suspend callback, + * and all registers are written back to the hardware when resuming. + */ + +static int cs4270_i2c_suspend(struct i2c_client *client, pm_message_t mesg) +{ + struct cs4270_private *cs4270 = i2c_get_clientdata(client); + struct snd_soc_codec *codec = &cs4270->codec; + int reg = snd_soc_read(codec, CS4270_PWRCTL) | CS4270_PWRCTL_PDN_ALL; + + return snd_soc_write(codec, CS4270_PWRCTL, reg); +} + +static int cs4270_i2c_resume(struct i2c_client *client) +{ + struct cs4270_private *cs4270 = i2c_get_clientdata(client); + struct snd_soc_codec *codec = &cs4270->codec; + int reg; + + /* In case the device was put to hard reset during sleep, we need to + * wait 500ns here before any I2C communication. */ + ndelay(500); + + /* first restore the entire register cache ... */ + for (reg = CS4270_FIRSTREG; reg <= CS4270_LASTREG; reg++) { + u8 val = snd_soc_read(codec, reg); + + if (i2c_smbus_write_byte_data(client, reg, val)) { + dev_err(codec->dev, "i2c write failed\n"); + return -EIO; + } + } + + /* ... then disable the power-down bits */ + reg = snd_soc_read(codec, CS4270_PWRCTL); + reg &= ~CS4270_PWRCTL_PDN_ALL; + + return snd_soc_write(codec, CS4270_PWRCTL, reg); +} +#else +#define cs4270_i2c_suspend NULL +#define cs4270_i2c_resume NULL +#endif /* CONFIG_PM */ + /* * cs4270_i2c_driver - I2C device identification * @@ -767,6 +856,8 @@ static struct i2c_driver cs4270_i2c_driver = { .id_table = cs4270_id, .probe = cs4270_i2c_probe, .remove = cs4270_i2c_remove, + .suspend = cs4270_i2c_suspend, + .resume = cs4270_i2c_resume, }; /* diff --git a/sound/soc/codecs/spdif_transciever.c b/sound/soc/codecs/spdif_transciever.c new file mode 100644 index 000000000000..218b33adad90 --- /dev/null +++ b/sound/soc/codecs/spdif_transciever.c @@ -0,0 +1,71 @@ +/* + * ALSA SoC SPDIF DIT driver + * + * This driver is used by controllers which can operate in DIT (SPDI/F) where + * no codec is needed. This file provides stub codec that can be used + * in these configurations. TI DaVinci Audio controller uses this driver. + * + * Author: Steve Chen, + * Copyright: (C) 2009 MontaVista Software, Inc., + * Copyright: (C) 2009 Texas Instruments, India + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include + +#include "spdif_transciever.h" + +#define STUB_RATES SNDRV_PCM_RATE_8000_96000 +#define STUB_FORMATS SNDRV_PCM_FMTBIT_S16_LE + +struct snd_soc_dai dit_stub_dai = { + .name = "DIT", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 384, + .rates = STUB_RATES, + .formats = STUB_FORMATS, + }, +}; + +static int spdif_dit_probe(struct platform_device *pdev) +{ + dit_stub_dai.dev = &pdev->dev; + return snd_soc_register_dai(&dit_stub_dai); +} + +static int spdif_dit_remove(struct platform_device *pdev) +{ + snd_soc_unregister_dai(&dit_stub_dai); + return 0; +} + +static struct platform_driver spdif_dit_driver = { + .probe = spdif_dit_probe, + .remove = spdif_dit_remove, + .driver = { + .name = "spdif-dit", + .owner = THIS_MODULE, + }, +}; + +static int __init dit_modinit(void) +{ + return platform_driver_register(&spdif_dit_driver); +} + +static void __exit dit_exit(void) +{ + platform_driver_unregister(&spdif_dit_driver); +} + +module_init(dit_modinit); +module_exit(dit_exit); + diff --git a/sound/soc/codecs/spdif_transciever.h b/sound/soc/codecs/spdif_transciever.h new file mode 100644 index 000000000000..296f2eb6c4ef --- /dev/null +++ b/sound/soc/codecs/spdif_transciever.h @@ -0,0 +1,17 @@ +/* + * ALSA SoC DIT/DIR driver header + * + * Author: Steve Chen, + * Copyright: (C) 2008 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 version 2 as + * published by the Free Software Foundation. + */ + +#ifndef CODEC_STUBS_H +#define CODEC_STUBS_H + +extern struct snd_soc_dai dit_stub_dai; + +#endif /* CODEC_STUBS_H */ diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index 87f606c76822..c550750c79c0 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c @@ -336,15 +336,17 @@ static int ssm2602_startup(struct snd_pcm_substream *substream, master_runtime->sample_bits, master_runtime->rate); - snd_pcm_hw_constraint_minmax(substream->runtime, - SNDRV_PCM_HW_PARAM_RATE, - master_runtime->rate, - master_runtime->rate); + if (master_runtime->rate != 0) + snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_RATE, + master_runtime->rate, + master_runtime->rate); - snd_pcm_hw_constraint_minmax(substream->runtime, - SNDRV_PCM_HW_PARAM_SAMPLE_BITS, - master_runtime->sample_bits, - master_runtime->sample_bits); + if (master_runtime->sample_bits != 0) + snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_SAMPLE_BITS, + master_runtime->sample_bits, + master_runtime->sample_bits); ssm2602->slave_substream = substream; } else @@ -372,6 +374,7 @@ static void ssm2602_shutdown(struct snd_pcm_substream *substream, struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->card->codec; struct ssm2602_priv *ssm2602 = codec->private_data; + /* deactivate */ if (!codec->active) ssm2602_write(codec, SSM2602_ACTIVE, 0); @@ -497,11 +500,9 @@ static int ssm2602_set_bias_level(struct snd_soc_codec *codec, return 0; } -#define SSM2602_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ - SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ - SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\ - SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\ - SNDRV_PCM_RATE_96000) +#define SSM2602_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_32000 |\ + SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\ + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) #define SSM2602_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c new file mode 100644 index 000000000000..8ad4b7b3e3ba --- /dev/null +++ b/sound/soc/codecs/stac9766.c @@ -0,0 +1,463 @@ +/* + * stac9766.c -- ALSA SoC STAC9766 codec support + * + * Copyright 2009 Jon Smirl, Digispeaker + * Author: Jon Smirl + * + * 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. + * + * Features:- + * + * o Support for AC97 Codec, S/PDIF + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "stac9766.h" + +#define STAC9766_VERSION "0.10" + +/* + * STAC9766 register cache + */ +static const u16 stac9766_reg[] = { + 0x6A90, 0x8000, 0x8000, 0x8000, /* 6 */ + 0x0000, 0x0000, 0x8008, 0x8008, /* e */ + 0x8808, 0x8808, 0x8808, 0x8808, /* 16 */ + 0x8808, 0x0000, 0x8000, 0x0000, /* 1e */ + 0x0000, 0x0000, 0x0000, 0x000f, /* 26 */ + 0x0a05, 0x0400, 0xbb80, 0x0000, /* 2e */ + 0x0000, 0xbb80, 0x0000, 0x0000, /* 36 */ + 0x0000, 0x2000, 0x0000, 0x0100, /* 3e */ + 0x0000, 0x0000, 0x0080, 0x0000, /* 46 */ + 0x0000, 0x0000, 0x0003, 0xffff, /* 4e */ + 0x0000, 0x0000, 0x0000, 0x0000, /* 56 */ + 0x4000, 0x0000, 0x0000, 0x0000, /* 5e */ + 0x1201, 0xFFFF, 0xFFFF, 0x0000, /* 66 */ + 0x0000, 0x0000, 0x0000, 0x0000, /* 6e */ + 0x0000, 0x0000, 0x0000, 0x0006, /* 76 */ + 0x0000, 0x0000, 0x0000, 0x0000, /* 7e */ +}; + +static const char *stac9766_record_mux[] = {"Mic", "CD", "Video", "AUX", + "Line", "Stereo Mix", "Mono Mix", "Phone"}; +static const char *stac9766_mono_mux[] = {"Mix", "Mic"}; +static const char *stac9766_mic_mux[] = {"Mic1", "Mic2"}; +static const char *stac9766_SPDIF_mux[] = {"PCM", "ADC Record"}; +static const char *stac9766_popbypass_mux[] = {"Normal", "Bypass Mixer"}; +static const char *stac9766_record_all_mux[] = {"All analog", + "Analog plus DAC"}; +static const char *stac9766_boost1[] = {"0dB", "10dB"}; +static const char *stac9766_boost2[] = {"0dB", "20dB"}; +static const char *stac9766_stereo_mic[] = {"Off", "On"}; + +static const struct soc_enum stac9766_record_enum = + SOC_ENUM_DOUBLE(AC97_REC_SEL, 8, 0, 8, stac9766_record_mux); +static const struct soc_enum stac9766_mono_enum = + SOC_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 9, 2, stac9766_mono_mux); +static const struct soc_enum stac9766_mic_enum = + SOC_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 8, 2, stac9766_mic_mux); +static const struct soc_enum stac9766_SPDIF_enum = + SOC_ENUM_SINGLE(AC97_STAC_DA_CONTROL, 1, 2, stac9766_SPDIF_mux); +static const struct soc_enum stac9766_popbypass_enum = + SOC_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 15, 2, stac9766_popbypass_mux); +static const struct soc_enum stac9766_record_all_enum = + SOC_ENUM_SINGLE(AC97_STAC_ANALOG_SPECIAL, 12, 2, + stac9766_record_all_mux); +static const struct soc_enum stac9766_boost1_enum = + SOC_ENUM_SINGLE(AC97_MIC, 6, 2, stac9766_boost1); /* 0/10dB */ +static const struct soc_enum stac9766_boost2_enum = + SOC_ENUM_SINGLE(AC97_STAC_ANALOG_SPECIAL, 2, 2, stac9766_boost2); /* 0/20dB */ +static const struct soc_enum stac9766_stereo_mic_enum = + SOC_ENUM_SINGLE(AC97_STAC_STEREO_MIC, 2, 1, stac9766_stereo_mic); + +static const DECLARE_TLV_DB_LINEAR(master_tlv, -4600, 0); +static const DECLARE_TLV_DB_LINEAR(record_tlv, 0, 2250); +static const DECLARE_TLV_DB_LINEAR(beep_tlv, -4500, 0); +static const DECLARE_TLV_DB_LINEAR(mix_tlv, -3450, 1200); + +static const struct snd_kcontrol_new stac9766_snd_ac97_controls[] = { + SOC_DOUBLE_TLV("Speaker Volume", AC97_MASTER, 8, 0, 31, 1, master_tlv), + SOC_SINGLE("Speaker Switch", AC97_MASTER, 15, 1, 1), + SOC_DOUBLE_TLV("Headphone Volume", AC97_HEADPHONE, 8, 0, 31, 1, + master_tlv), + SOC_SINGLE("Headphone Switch", AC97_HEADPHONE, 15, 1, 1), + SOC_SINGLE_TLV("Mono Out Volume", AC97_MASTER_MONO, 0, 31, 1, + master_tlv), + SOC_SINGLE("Mono Out Switch", AC97_MASTER_MONO, 15, 1, 1), + + SOC_DOUBLE_TLV("Record Volume", AC97_REC_GAIN, 8, 0, 15, 0, record_tlv), + SOC_SINGLE("Record Switch", AC97_REC_GAIN, 15, 1, 1), + + + SOC_SINGLE_TLV("Beep Volume", AC97_PC_BEEP, 1, 15, 1, beep_tlv), + SOC_SINGLE("Beep Switch", AC97_PC_BEEP, 15, 1, 1), + SOC_SINGLE("Beep Frequency", AC97_PC_BEEP, 5, 127, 1), + SOC_SINGLE_TLV("Phone Volume", AC97_PHONE, 0, 31, 1, mix_tlv), + SOC_SINGLE("Phone Switch", AC97_PHONE, 15, 1, 1), + + SOC_ENUM("Mic Boost1", stac9766_boost1_enum), + SOC_ENUM("Mic Boost2", stac9766_boost2_enum), + SOC_SINGLE_TLV("Mic Volume", AC97_MIC, 0, 31, 1, mix_tlv), + SOC_SINGLE("Mic Switch", AC97_MIC, 15, 1, 1), + SOC_ENUM("Stereo Mic", stac9766_stereo_mic_enum), + + SOC_DOUBLE_TLV("Line Volume", AC97_LINE, 8, 0, 31, 1, mix_tlv), + SOC_SINGLE("Line Switch", AC97_LINE, 15, 1, 1), + SOC_DOUBLE_TLV("CD Volume", AC97_CD, 8, 0, 31, 1, mix_tlv), + SOC_SINGLE("CD Switch", AC97_CD, 15, 1, 1), + SOC_DOUBLE_TLV("AUX Volume", AC97_AUX, 8, 0, 31, 1, mix_tlv), + SOC_SINGLE("AUX Switch", AC97_AUX, 15, 1, 1), + SOC_DOUBLE_TLV("Video Volume", AC97_VIDEO, 8, 0, 31, 1, mix_tlv), + SOC_SINGLE("Video Switch", AC97_VIDEO, 15, 1, 1), + + SOC_DOUBLE_TLV("DAC Volume", AC97_PCM, 8, 0, 31, 1, mix_tlv), + SOC_SINGLE("DAC Switch", AC97_PCM, 15, 1, 1), + SOC_SINGLE("Loopback Test Switch", AC97_GENERAL_PURPOSE, 7, 1, 0), + SOC_SINGLE("3D Volume", AC97_3D_CONTROL, 3, 2, 1), + SOC_SINGLE("3D Switch", AC97_GENERAL_PURPOSE, 13, 1, 0), + + SOC_ENUM("SPDIF Mux", stac9766_SPDIF_enum), + SOC_ENUM("Mic1/2 Mux", stac9766_mic_enum), + SOC_ENUM("Record All Mux", stac9766_record_all_enum), + SOC_ENUM("Record Mux", stac9766_record_enum), + SOC_ENUM("Mono Mux", stac9766_mono_enum), + SOC_ENUM("Pop Bypass Mux", stac9766_popbypass_enum), +}; + +static int stac9766_ac97_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int val) +{ + u16 *cache = codec->reg_cache; + + if (reg > AC97_STAC_PAGE0) { + stac9766_ac97_write(codec, AC97_INT_PAGING, 0); + soc_ac97_ops.write(codec->ac97, reg, val); + stac9766_ac97_write(codec, AC97_INT_PAGING, 1); + return 0; + } + if (reg / 2 > ARRAY_SIZE(stac9766_reg)) + return -EIO; + + soc_ac97_ops.write(codec->ac97, reg, val); + cache[reg / 2] = val; + return 0; +} + +static unsigned int stac9766_ac97_read(struct snd_soc_codec *codec, + unsigned int reg) +{ + u16 val = 0, *cache = codec->reg_cache; + + if (reg > AC97_STAC_PAGE0) { + stac9766_ac97_write(codec, AC97_INT_PAGING, 0); + val = soc_ac97_ops.read(codec->ac97, reg - AC97_STAC_PAGE0); + stac9766_ac97_write(codec, AC97_INT_PAGING, 1); + return val; + } + if (reg / 2 > ARRAY_SIZE(stac9766_reg)) + return -EIO; + + if (reg == AC97_RESET || reg == AC97_GPIO_STATUS || + reg == AC97_INT_PAGING || reg == AC97_VENDOR_ID1 || + reg == AC97_VENDOR_ID2) { + + val = soc_ac97_ops.read(codec->ac97, reg); + return val; + } + return cache[reg / 2]; +} + +static int ac97_analog_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct snd_pcm_runtime *runtime = substream->runtime; + unsigned short reg, vra; + + vra = stac9766_ac97_read(codec, AC97_EXTENDED_STATUS); + + vra |= 0x1; /* enable variable rate audio */ + + stac9766_ac97_write(codec, AC97_EXTENDED_STATUS, vra); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + reg = AC97_PCM_FRONT_DAC_RATE; + else + reg = AC97_PCM_LR_ADC_RATE; + + return stac9766_ac97_write(codec, reg, runtime->rate); +} + +static int ac97_digital_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct snd_pcm_runtime *runtime = substream->runtime; + unsigned short reg, vra; + + stac9766_ac97_write(codec, AC97_SPDIF, 0x2002); + + vra = stac9766_ac97_read(codec, AC97_EXTENDED_STATUS); + vra |= 0x5; /* Enable VRA and SPDIF out */ + + stac9766_ac97_write(codec, AC97_EXTENDED_STATUS, vra); + + reg = AC97_PCM_FRONT_DAC_RATE; + + return stac9766_ac97_write(codec, reg, runtime->rate); +} + +static int ac97_digital_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + unsigned short vra; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_STOP: + vra = stac9766_ac97_read(codec, AC97_EXTENDED_STATUS); + vra &= !0x04; + stac9766_ac97_write(codec, AC97_EXTENDED_STATUS, vra); + break; + } + return 0; +} + +static int stac9766_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + switch (level) { + case SND_SOC_BIAS_ON: /* full On */ + case SND_SOC_BIAS_PREPARE: /* partial On */ + case SND_SOC_BIAS_STANDBY: /* Off, with power */ + stac9766_ac97_write(codec, AC97_POWERDOWN, 0x0000); + break; + case SND_SOC_BIAS_OFF: /* Off, without power */ + /* disable everything including AC link */ + stac9766_ac97_write(codec, AC97_POWERDOWN, 0xffff); + break; + } + codec->bias_level = level; + return 0; +} + +static int stac9766_reset(struct snd_soc_codec *codec, int try_warm) +{ + if (try_warm && soc_ac97_ops.warm_reset) { + soc_ac97_ops.warm_reset(codec->ac97); + if (stac9766_ac97_read(codec, 0) == stac9766_reg[0]) + return 1; + } + + soc_ac97_ops.reset(codec->ac97); + if (soc_ac97_ops.warm_reset) + soc_ac97_ops.warm_reset(codec->ac97); + if (stac9766_ac97_read(codec, 0) != stac9766_reg[0]) + return -EIO; + return 0; +} + +static int stac9766_codec_suspend(struct platform_device *pdev, + pm_message_t state) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + + stac9766_set_bias_level(codec, SND_SOC_BIAS_OFF); + return 0; +} + +static int stac9766_codec_resume(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + u16 id, reset; + + reset = 0; + /* give the codec an AC97 warm reset to start the link */ +reset: + if (reset > 5) { + printk(KERN_ERR "stac9766 failed to resume"); + return -EIO; + } + codec->ac97->bus->ops->warm_reset(codec->ac97); + id = soc_ac97_ops.read(codec->ac97, AC97_VENDOR_ID2); + if (id != 0x4c13) { + stac9766_reset(codec, 0); + reset++; + goto reset; + } + stac9766_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + if (codec->suspend_bias_level == SND_SOC_BIAS_ON) + stac9766_set_bias_level(codec, SND_SOC_BIAS_ON); + + return 0; +} + +static struct snd_soc_dai_ops stac9766_dai_ops_analog = { + .prepare = ac97_analog_prepare, +}; + +static struct snd_soc_dai_ops stac9766_dai_ops_digital = { + .prepare = ac97_digital_prepare, + .trigger = ac97_digital_trigger, +}; + +struct snd_soc_dai stac9766_dai[] = { +{ + .name = "stac9766 analog", + .id = 0, + .ac97_control = 1, + + /* stream cababilities */ + .playback = { + .stream_name = "stac9766 analog", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SND_SOC_STD_AC97_FMTS, + }, + .capture = { + .stream_name = "stac9766 analog", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SND_SOC_STD_AC97_FMTS, + }, + /* alsa ops */ + .ops = &stac9766_dai_ops_analog, +}, +{ + .name = "stac9766 IEC958", + .id = 1, + .ac97_control = 1, + + /* stream cababilities */ + .playback = { + .stream_name = "stac9766 IEC958", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_32000 | \ + SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE, + }, + /* alsa ops */ + .ops = &stac9766_dai_ops_digital, +} +}; +EXPORT_SYMBOL_GPL(stac9766_dai); + +static int stac9766_codec_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec; + int ret = 0; + + printk(KERN_INFO "STAC9766 SoC Audio Codec %s\n", STAC9766_VERSION); + + socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); + if (socdev->card->codec == NULL) + return -ENOMEM; + codec = socdev->card->codec; + mutex_init(&codec->mutex); + + codec->reg_cache = kmemdup(stac9766_reg, sizeof(stac9766_reg), + GFP_KERNEL); + if (codec->reg_cache == NULL) { + ret = -ENOMEM; + goto cache_err; + } + codec->reg_cache_size = sizeof(stac9766_reg); + codec->reg_cache_step = 2; + + codec->name = "STAC9766"; + codec->owner = THIS_MODULE; + codec->dai = stac9766_dai; + codec->num_dai = ARRAY_SIZE(stac9766_dai); + codec->write = stac9766_ac97_write; + codec->read = stac9766_ac97_read; + codec->set_bias_level = stac9766_set_bias_level; + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + + ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0); + if (ret < 0) + goto codec_err; + + /* register pcms */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) + goto pcm_err; + + /* do a cold reset for the controller and then try + * a warm reset followed by an optional cold reset for codec */ + stac9766_reset(codec, 0); + ret = stac9766_reset(codec, 1); + if (ret < 0) { + printk(KERN_ERR "Failed to reset STAC9766: AC97 link error\n"); + goto reset_err; + } + + stac9766_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + snd_soc_add_controls(codec, stac9766_snd_ac97_controls, + ARRAY_SIZE(stac9766_snd_ac97_controls)); + + ret = snd_soc_init_card(socdev); + if (ret < 0) + goto reset_err; + return 0; + +reset_err: + snd_soc_free_pcms(socdev); +pcm_err: + snd_soc_free_ac97_codec(codec); +codec_err: + kfree(codec->private_data); +cache_err: + kfree(socdev->card->codec); + socdev->card->codec = NULL; + return ret; +} + +static int stac9766_codec_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + + if (codec == NULL) + return 0; + + snd_soc_free_pcms(socdev); + snd_soc_free_ac97_codec(codec); + kfree(codec->reg_cache); + kfree(codec); + return 0; +} + +struct snd_soc_codec_device soc_codec_dev_stac9766 = { + .probe = stac9766_codec_probe, + .remove = stac9766_codec_remove, + .suspend = stac9766_codec_suspend, + .resume = stac9766_codec_resume, +}; +EXPORT_SYMBOL_GPL(soc_codec_dev_stac9766); + +MODULE_DESCRIPTION("ASoC stac9766 driver"); +MODULE_AUTHOR("Jon Smirl "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/stac9766.h b/sound/soc/codecs/stac9766.h new file mode 100644 index 000000000000..65642eb8393e --- /dev/null +++ b/sound/soc/codecs/stac9766.h @@ -0,0 +1,21 @@ +/* + * stac9766.h -- STAC9766 Soc Audio driver + */ + +#ifndef _STAC9766_H +#define _STAC9766_H + +#define AC97_STAC_PAGE0 0x1000 +#define AC97_STAC_DA_CONTROL (AC97_STAC_PAGE0 | 0x6A) +#define AC97_STAC_ANALOG_SPECIAL (AC97_STAC_PAGE0 | 0x6E) +#define AC97_STAC_STEREO_MIC 0x78 + +/* STAC9766 DAI ID's */ +#define STAC9766_DAI_AC97_ANALOG 0 +#define STAC9766_DAI_AC97_DIGITAL 1 + +extern struct snd_soc_dai stac9766_dai[]; +extern struct snd_soc_codec_device soc_codec_dev_stac9766; + + +#endif diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index c3f4afb5d017..0b8dcb5cd729 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c @@ -86,7 +86,7 @@ static int tlv320aic23_write(struct snd_soc_codec *codec, unsigned int reg, */ if ((reg < 0 || reg > 9) && (reg != 15)) { - printk(KERN_WARNING "%s Invalid register R%d\n", __func__, reg); + printk(KERN_WARNING "%s Invalid register R%u\n", __func__, reg); return -1; } @@ -98,7 +98,7 @@ static int tlv320aic23_write(struct snd_soc_codec *codec, unsigned int reg, if (codec->hw_write(codec->control_data, data, 2) == 2) return 0; - printk(KERN_ERR "%s cannot write %03x to register R%d\n", __func__, + printk(KERN_ERR "%s cannot write %03x to register R%u\n", __func__, value, reg); return -EIO; @@ -273,14 +273,14 @@ static const unsigned short sr_valid_mask[] = { * Every divisor is a factor of 11*12 */ #define SR_MULT (11*12) -#define A(x) (x) ? (SR_MULT/x) : 0 +#define A(x) (SR_MULT/x) static const unsigned char sr_adc_mult_table[] = { - A(2), A(2), A(12), A(12), A(0), A(0), A(3), A(1), - A(2), A(2), A(11), A(11), A(0), A(0), A(0), A(1) + A(2), A(2), A(12), A(12), 0, 0, A(3), A(1), + A(2), A(2), A(11), A(11), 0, 0, 0, A(1) }; static const unsigned char sr_dac_mult_table[] = { - A(2), A(12), A(2), A(12), A(0), A(0), A(3), A(1), - A(2), A(11), A(2), A(11), A(0), A(0), A(0), A(1) + A(2), A(12), A(2), A(12), 0, 0, A(3), A(1), + A(2), A(11), A(2), A(11), 0, 0, 0, A(1) }; static unsigned get_score(int adc, int adc_l, int adc_h, int need_adc, @@ -523,6 +523,8 @@ static int tlv320aic23_set_dai_fmt(struct snd_soc_dai *codec_dai, case SND_SOC_DAIFMT_I2S: iface_reg |= TLV320AIC23_FOR_I2S; break; + case SND_SOC_DAIFMT_DSP_A: + iface_reg |= TLV320AIC23_LRP_ON; case SND_SOC_DAIFMT_DSP_B: iface_reg |= TLV320AIC23_FOR_DSP; break; diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index df7c8c281d2f..4dbb853eef5a 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -115,6 +115,7 @@ static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = { 0x00, /* REG_VIBRA_PWM_SET (0x47) */ 0x00, /* REG_ANAMIC_GAIN (0x48) */ 0x00, /* REG_MISC_SET_2 (0x49) */ + 0x00, /* REG_SW_SHADOW (0x4A) - Shadow, non HW register */ }; /* codec private data */ @@ -125,6 +126,17 @@ struct twl4030_priv { struct snd_pcm_substream *master_substream; struct snd_pcm_substream *slave_substream; + + unsigned int configured; + unsigned int rate; + unsigned int sample_bits; + unsigned int channels; + + unsigned int sysclk; + + /* Headset output state handling */ + unsigned int hsl_enabled; + unsigned int hsr_enabled; }; /* @@ -161,7 +173,11 @@ static int twl4030_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { twl4030_write_reg_cache(codec, reg, value); - return twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, value, reg); + if (likely(reg < TWL4030_REG_SW_SHADOW)) + return twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, value, + reg); + else + return 0; } static void twl4030_codec_enable(struct snd_soc_codec *codec, int enable) @@ -188,6 +204,7 @@ static void twl4030_codec_enable(struct snd_soc_codec *codec, int enable) static void twl4030_init_chip(struct snd_soc_codec *codec) { + u8 *cache = codec->reg_cache; int i; /* clear CODECPDZ prior to setting register defaults */ @@ -195,7 +212,7 @@ static void twl4030_init_chip(struct snd_soc_codec *codec) /* set all audio section registers to reasonable defaults */ for (i = TWL4030_REG_OPTION; i <= TWL4030_REG_MISC_SET_2; i++) - twl4030_write(codec, i, twl4030_reg[i]); + twl4030_write(codec, i, cache[i]); } @@ -232,7 +249,7 @@ static void twl4030_codec_mute(struct snd_soc_codec *codec, int mute) TWL4030_REG_PRECKL_CTL); reg_val = twl4030_read_reg_cache(codec, TWL4030_REG_PRECKR_CTL); twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, - reg_val & (~TWL4030_PRECKL_GAIN), + reg_val & (~TWL4030_PRECKR_GAIN), TWL4030_REG_PRECKR_CTL); /* Disable PLL */ @@ -316,104 +333,60 @@ static void twl4030_power_down(struct snd_soc_codec *codec) } /* Earpiece */ -static const char *twl4030_earpiece_texts[] = - {"Off", "DACL1", "DACL2", "DACR1"}; - -static const unsigned int twl4030_earpiece_values[] = - {0x0, 0x1, 0x2, 0x4}; - -static const struct soc_enum twl4030_earpiece_enum = - SOC_VALUE_ENUM_SINGLE(TWL4030_REG_EAR_CTL, 1, 0x7, - ARRAY_SIZE(twl4030_earpiece_texts), - twl4030_earpiece_texts, - twl4030_earpiece_values); - -static const struct snd_kcontrol_new twl4030_dapm_earpiece_control = -SOC_DAPM_VALUE_ENUM("Route", twl4030_earpiece_enum); +static const struct snd_kcontrol_new twl4030_dapm_earpiece_controls[] = { + SOC_DAPM_SINGLE("Voice", TWL4030_REG_EAR_CTL, 0, 1, 0), + SOC_DAPM_SINGLE("AudioL1", TWL4030_REG_EAR_CTL, 1, 1, 0), + SOC_DAPM_SINGLE("AudioL2", TWL4030_REG_EAR_CTL, 2, 1, 0), + SOC_DAPM_SINGLE("AudioR1", TWL4030_REG_EAR_CTL, 3, 1, 0), +}; /* PreDrive Left */ -static const char *twl4030_predrivel_texts[] = - {"Off", "DACL1", "DACL2", "DACR2"}; - -static const unsigned int twl4030_predrivel_values[] = - {0x0, 0x1, 0x2, 0x4}; - -static const struct soc_enum twl4030_predrivel_enum = - SOC_VALUE_ENUM_SINGLE(TWL4030_REG_PREDL_CTL, 1, 0x7, - ARRAY_SIZE(twl4030_predrivel_texts), - twl4030_predrivel_texts, - twl4030_predrivel_values); - -static const struct snd_kcontrol_new twl4030_dapm_predrivel_control = -SOC_DAPM_VALUE_ENUM("Route", twl4030_predrivel_enum); +static const struct snd_kcontrol_new twl4030_dapm_predrivel_controls[] = { + SOC_DAPM_SINGLE("Voice", TWL4030_REG_PREDL_CTL, 0, 1, 0), + SOC_DAPM_SINGLE("AudioL1", TWL4030_REG_PREDL_CTL, 1, 1, 0), + SOC_DAPM_SINGLE("AudioL2", TWL4030_REG_PREDL_CTL, 2, 1, 0), + SOC_DAPM_SINGLE("AudioR2", TWL4030_REG_PREDL_CTL, 3, 1, 0), +}; /* PreDrive Right */ -static const char *twl4030_predriver_texts[] = - {"Off", "DACR1", "DACR2", "DACL2"}; - -static const unsigned int twl4030_predriver_values[] = - {0x0, 0x1, 0x2, 0x4}; - -static const struct soc_enum twl4030_predriver_enum = - SOC_VALUE_ENUM_SINGLE(TWL4030_REG_PREDR_CTL, 1, 0x7, - ARRAY_SIZE(twl4030_predriver_texts), - twl4030_predriver_texts, - twl4030_predriver_values); - -static const struct snd_kcontrol_new twl4030_dapm_predriver_control = -SOC_DAPM_VALUE_ENUM("Route", twl4030_predriver_enum); +static const struct snd_kcontrol_new twl4030_dapm_predriver_controls[] = { + SOC_DAPM_SINGLE("Voice", TWL4030_REG_PREDR_CTL, 0, 1, 0), + SOC_DAPM_SINGLE("AudioR1", TWL4030_REG_PREDR_CTL, 1, 1, 0), + SOC_DAPM_SINGLE("AudioR2", TWL4030_REG_PREDR_CTL, 2, 1, 0), + SOC_DAPM_SINGLE("AudioL2", TWL4030_REG_PREDR_CTL, 3, 1, 0), +}; /* Headset Left */ -static const char *twl4030_hsol_texts[] = - {"Off", "DACL1", "DACL2"}; - -static const struct soc_enum twl4030_hsol_enum = - SOC_ENUM_SINGLE(TWL4030_REG_HS_SEL, 1, - ARRAY_SIZE(twl4030_hsol_texts), - twl4030_hsol_texts); - -static const struct snd_kcontrol_new twl4030_dapm_hsol_control = -SOC_DAPM_ENUM("Route", twl4030_hsol_enum); +static const struct snd_kcontrol_new twl4030_dapm_hsol_controls[] = { + SOC_DAPM_SINGLE("Voice", TWL4030_REG_HS_SEL, 0, 1, 0), + SOC_DAPM_SINGLE("AudioL1", TWL4030_REG_HS_SEL, 1, 1, 0), + SOC_DAPM_SINGLE("AudioL2", TWL4030_REG_HS_SEL, 2, 1, 0), +}; /* Headset Right */ -static const char *twl4030_hsor_texts[] = - {"Off", "DACR1", "DACR2"}; - -static const struct soc_enum twl4030_hsor_enum = - SOC_ENUM_SINGLE(TWL4030_REG_HS_SEL, 4, - ARRAY_SIZE(twl4030_hsor_texts), - twl4030_hsor_texts); - -static const struct snd_kcontrol_new twl4030_dapm_hsor_control = -SOC_DAPM_ENUM("Route", twl4030_hsor_enum); +static const struct snd_kcontrol_new twl4030_dapm_hsor_controls[] = { + SOC_DAPM_SINGLE("Voice", TWL4030_REG_HS_SEL, 3, 1, 0), + SOC_DAPM_SINGLE("AudioR1", TWL4030_REG_HS_SEL, 4, 1, 0), + SOC_DAPM_SINGLE("AudioR2", TWL4030_REG_HS_SEL, 5, 1, 0), +}; /* Carkit Left */ -static const char *twl4030_carkitl_texts[] = - {"Off", "DACL1", "DACL2"}; - -static const struct soc_enum twl4030_carkitl_enum = - SOC_ENUM_SINGLE(TWL4030_REG_PRECKL_CTL, 1, - ARRAY_SIZE(twl4030_carkitl_texts), - twl4030_carkitl_texts); - -static const struct snd_kcontrol_new twl4030_dapm_carkitl_control = -SOC_DAPM_ENUM("Route", twl4030_carkitl_enum); +static const struct snd_kcontrol_new twl4030_dapm_carkitl_controls[] = { + SOC_DAPM_SINGLE("Voice", TWL4030_REG_PRECKL_CTL, 0, 1, 0), + SOC_DAPM_SINGLE("AudioL1", TWL4030_REG_PRECKL_CTL, 1, 1, 0), + SOC_DAPM_SINGLE("AudioL2", TWL4030_REG_PRECKL_CTL, 2, 1, 0), +}; /* Carkit Right */ -static const char *twl4030_carkitr_texts[] = - {"Off", "DACR1", "DACR2"}; - -static const struct soc_enum twl4030_carkitr_enum = - SOC_ENUM_SINGLE(TWL4030_REG_PRECKR_CTL, 1, - ARRAY_SIZE(twl4030_carkitr_texts), - twl4030_carkitr_texts); - -static const struct snd_kcontrol_new twl4030_dapm_carkitr_control = -SOC_DAPM_ENUM("Route", twl4030_carkitr_enum); +static const struct snd_kcontrol_new twl4030_dapm_carkitr_controls[] = { + SOC_DAPM_SINGLE("Voice", TWL4030_REG_PRECKR_CTL, 0, 1, 0), + SOC_DAPM_SINGLE("AudioR1", TWL4030_REG_PRECKR_CTL, 1, 1, 0), + SOC_DAPM_SINGLE("AudioR2", TWL4030_REG_PRECKR_CTL, 2, 1, 0), +}; /* Handsfree Left */ static const char *twl4030_handsfreel_texts[] = - {"Voice", "DACL1", "DACL2", "DACR2"}; + {"Voice", "AudioL1", "AudioL2", "AudioR2"}; static const struct soc_enum twl4030_handsfreel_enum = SOC_ENUM_SINGLE(TWL4030_REG_HFL_CTL, 0, @@ -423,9 +396,13 @@ static const struct soc_enum twl4030_handsfreel_enum = static const struct snd_kcontrol_new twl4030_dapm_handsfreel_control = SOC_DAPM_ENUM("Route", twl4030_handsfreel_enum); +/* Handsfree Left virtual mute */ +static const struct snd_kcontrol_new twl4030_dapm_handsfreelmute_control = + SOC_DAPM_SINGLE("Switch", TWL4030_REG_SW_SHADOW, 0, 1, 0); + /* Handsfree Right */ static const char *twl4030_handsfreer_texts[] = - {"Voice", "DACR1", "DACR2", "DACL2"}; + {"Voice", "AudioR1", "AudioR2", "AudioL2"}; static const struct soc_enum twl4030_handsfreer_enum = SOC_ENUM_SINGLE(TWL4030_REG_HFR_CTL, 0, @@ -435,37 +412,48 @@ static const struct soc_enum twl4030_handsfreer_enum = static const struct snd_kcontrol_new twl4030_dapm_handsfreer_control = SOC_DAPM_ENUM("Route", twl4030_handsfreer_enum); +/* Handsfree Right virtual mute */ +static const struct snd_kcontrol_new twl4030_dapm_handsfreermute_control = + SOC_DAPM_SINGLE("Switch", TWL4030_REG_SW_SHADOW, 1, 1, 0); + +/* Vibra */ +/* Vibra audio path selection */ +static const char *twl4030_vibra_texts[] = + {"AudioL1", "AudioR1", "AudioL2", "AudioR2"}; + +static const struct soc_enum twl4030_vibra_enum = + SOC_ENUM_SINGLE(TWL4030_REG_VIBRA_CTL, 2, + ARRAY_SIZE(twl4030_vibra_texts), + twl4030_vibra_texts); + +static const struct snd_kcontrol_new twl4030_dapm_vibra_control = +SOC_DAPM_ENUM("Route", twl4030_vibra_enum); + +/* Vibra path selection: local vibrator (PWM) or audio driven */ +static const char *twl4030_vibrapath_texts[] = + {"Local vibrator", "Audio"}; + +static const struct soc_enum twl4030_vibrapath_enum = + SOC_ENUM_SINGLE(TWL4030_REG_VIBRA_CTL, 4, + ARRAY_SIZE(twl4030_vibrapath_texts), + twl4030_vibrapath_texts); + +static const struct snd_kcontrol_new twl4030_dapm_vibrapath_control = +SOC_DAPM_ENUM("Route", twl4030_vibrapath_enum); + /* Left analog microphone selection */ -static const char *twl4030_analoglmic_texts[] = - {"Off", "Main mic", "Headset mic", "AUXL", "Carkit mic"}; - -static const unsigned int twl4030_analoglmic_values[] = - {0x0, 0x1, 0x2, 0x4, 0x8}; - -static const struct soc_enum twl4030_analoglmic_enum = - SOC_VALUE_ENUM_SINGLE(TWL4030_REG_ANAMICL, 0, 0xf, - ARRAY_SIZE(twl4030_analoglmic_texts), - twl4030_analoglmic_texts, - twl4030_analoglmic_values); - -static const struct snd_kcontrol_new twl4030_dapm_analoglmic_control = -SOC_DAPM_VALUE_ENUM("Route", twl4030_analoglmic_enum); +static const struct snd_kcontrol_new twl4030_dapm_analoglmic_controls[] = { + SOC_DAPM_SINGLE("Main mic", TWL4030_REG_ANAMICL, 0, 1, 0), + SOC_DAPM_SINGLE("Headset mic", TWL4030_REG_ANAMICL, 1, 1, 0), + SOC_DAPM_SINGLE("AUXL", TWL4030_REG_ANAMICL, 2, 1, 0), + SOC_DAPM_SINGLE("Carkit mic", TWL4030_REG_ANAMICL, 3, 1, 0), +}; /* Right analog microphone selection */ -static const char *twl4030_analogrmic_texts[] = - {"Off", "Sub mic", "AUXR"}; - -static const unsigned int twl4030_analogrmic_values[] = - {0x0, 0x1, 0x4}; - -static const struct soc_enum twl4030_analogrmic_enum = - SOC_VALUE_ENUM_SINGLE(TWL4030_REG_ANAMICR, 0, 0x5, - ARRAY_SIZE(twl4030_analogrmic_texts), - twl4030_analogrmic_texts, - twl4030_analogrmic_values); - -static const struct snd_kcontrol_new twl4030_dapm_analogrmic_control = -SOC_DAPM_VALUE_ENUM("Route", twl4030_analogrmic_enum); +static const struct snd_kcontrol_new twl4030_dapm_analogrmic_controls[] = { + SOC_DAPM_SINGLE("Sub mic", TWL4030_REG_ANAMICR, 0, 1, 0), + SOC_DAPM_SINGLE("AUXR", TWL4030_REG_ANAMICR, 2, 1, 0), +}; /* TX1 L/R Analog/Digital microphone selection */ static const char *twl4030_micpathtx1_texts[] = @@ -507,6 +495,10 @@ static const struct snd_kcontrol_new twl4030_dapm_abypassr2_control = static const struct snd_kcontrol_new twl4030_dapm_abypassl2_control = SOC_DAPM_SINGLE("Switch", TWL4030_REG_ARXL2_APGA_CTL, 2, 1, 0); +/* Analog bypass for Voice */ +static const struct snd_kcontrol_new twl4030_dapm_abypassv_control = + SOC_DAPM_SINGLE("Switch", TWL4030_REG_VDL_APGA_CTL, 2, 1, 0); + /* Digital bypass gain, 0 mutes the bypass */ static const unsigned int twl4030_dapm_dbypass_tlv[] = { TLV_DB_RANGE_HEAD(2), @@ -526,6 +518,18 @@ static const struct snd_kcontrol_new twl4030_dapm_dbypassr_control = TWL4030_REG_ATX2ARXPGA, 0, 7, 0, twl4030_dapm_dbypass_tlv); +/* + * Voice Sidetone GAIN volume control: + * from -51 to -10 dB in 1 dB steps (mute instead of -51 dB) + */ +static DECLARE_TLV_DB_SCALE(twl4030_dapm_dbypassv_tlv, -5100, 100, 1); + +/* Digital bypass voice: sidetone (VUL -> VDL)*/ +static const struct snd_kcontrol_new twl4030_dapm_dbypassv_control = + SOC_DAPM_SINGLE_TLV("Volume", + TWL4030_REG_VSTPGA, 0, 0x29, 0, + twl4030_dapm_dbypassv_tlv); + static int micpath_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -556,63 +560,143 @@ static int micpath_event(struct snd_soc_dapm_widget *w, return 0; } -static int handsfree_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) +static void handsfree_ramp(struct snd_soc_codec *codec, int reg, int ramp) { - struct soc_enum *e = (struct soc_enum *)w->kcontrols->private_value; unsigned char hs_ctl; - hs_ctl = twl4030_read_reg_cache(w->codec, e->reg); + hs_ctl = twl4030_read_reg_cache(codec, reg); - if (hs_ctl & TWL4030_HF_CTL_REF_EN) { + if (ramp) { + /* HF ramp-up */ + hs_ctl |= TWL4030_HF_CTL_REF_EN; + twl4030_write(codec, reg, hs_ctl); + udelay(10); hs_ctl |= TWL4030_HF_CTL_RAMP_EN; - twl4030_write(w->codec, e->reg, hs_ctl); + twl4030_write(codec, reg, hs_ctl); + udelay(40); hs_ctl |= TWL4030_HF_CTL_LOOP_EN; - twl4030_write(w->codec, e->reg, hs_ctl); hs_ctl |= TWL4030_HF_CTL_HB_EN; - twl4030_write(w->codec, e->reg, hs_ctl); + twl4030_write(codec, reg, hs_ctl); } else { - hs_ctl &= ~(TWL4030_HF_CTL_RAMP_EN | TWL4030_HF_CTL_LOOP_EN - | TWL4030_HF_CTL_HB_EN); - twl4030_write(w->codec, e->reg, hs_ctl); + /* HF ramp-down */ + hs_ctl &= ~TWL4030_HF_CTL_LOOP_EN; + hs_ctl &= ~TWL4030_HF_CTL_HB_EN; + twl4030_write(codec, reg, hs_ctl); + hs_ctl &= ~TWL4030_HF_CTL_RAMP_EN; + twl4030_write(codec, reg, hs_ctl); + udelay(40); + hs_ctl &= ~TWL4030_HF_CTL_REF_EN; + twl4030_write(codec, reg, hs_ctl); } +} +static int handsfreelpga_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + switch (event) { + case SND_SOC_DAPM_POST_PMU: + handsfree_ramp(w->codec, TWL4030_REG_HFL_CTL, 1); + break; + case SND_SOC_DAPM_POST_PMD: + handsfree_ramp(w->codec, TWL4030_REG_HFL_CTL, 0); + break; + } return 0; } -static int headsetl_event(struct snd_soc_dapm_widget *w, +static int handsfreerpga_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - unsigned char hs_gain, hs_pop; - - /* Save the current volume */ - hs_gain = twl4030_read_reg_cache(w->codec, TWL4030_REG_HS_GAIN_SET); - hs_pop = twl4030_read_reg_cache(w->codec, TWL4030_REG_HS_POPN_SET); - switch (event) { case SND_SOC_DAPM_POST_PMU: - /* Do the anti-pop/bias ramp enable according to the TRM */ - hs_pop |= TWL4030_VMID_EN; - twl4030_write(w->codec, TWL4030_REG_HS_POPN_SET, hs_pop); - /* Is this needed? Can we just use whatever gain here? */ - twl4030_write(w->codec, TWL4030_REG_HS_GAIN_SET, - (hs_gain & (~0x0f)) | 0x0a); - hs_pop |= TWL4030_RAMP_EN; - twl4030_write(w->codec, TWL4030_REG_HS_POPN_SET, hs_pop); - - /* Restore the original volume */ - twl4030_write(w->codec, TWL4030_REG_HS_GAIN_SET, hs_gain); + handsfree_ramp(w->codec, TWL4030_REG_HFR_CTL, 1); break; case SND_SOC_DAPM_POST_PMD: - /* Do the anti-pop/bias ramp disable according to the TRM */ + handsfree_ramp(w->codec, TWL4030_REG_HFR_CTL, 0); + break; + } + return 0; +} + +static void headset_ramp(struct snd_soc_codec *codec, int ramp) +{ + unsigned char hs_gain, hs_pop; + struct twl4030_priv *twl4030 = codec->private_data; + /* Base values for ramp delay calculation: 2^19 - 2^26 */ + unsigned int ramp_base[] = {524288, 1048576, 2097152, 4194304, + 8388608, 16777216, 33554432, 67108864}; + + hs_gain = twl4030_read_reg_cache(codec, TWL4030_REG_HS_GAIN_SET); + hs_pop = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET); + + if (ramp) { + /* Headset ramp-up according to the TRM */ + hs_pop |= TWL4030_VMID_EN; + twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop); + twl4030_write(codec, TWL4030_REG_HS_GAIN_SET, hs_gain); + hs_pop |= TWL4030_RAMP_EN; + twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop); + } else { + /* Headset ramp-down _not_ according to + * the TRM, but in a way that it is working */ hs_pop &= ~TWL4030_RAMP_EN; - twl4030_write(w->codec, TWL4030_REG_HS_POPN_SET, hs_pop); + twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop); + /* Wait ramp delay time + 1, so the VMID can settle */ + mdelay((ramp_base[(hs_pop & TWL4030_RAMP_DELAY) >> 2] / + twl4030->sysclk) + 1); /* Bypass the reg_cache to mute the headset */ twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, hs_gain & (~0x0f), TWL4030_REG_HS_GAIN_SET); + hs_pop &= ~TWL4030_VMID_EN; - twl4030_write(w->codec, TWL4030_REG_HS_POPN_SET, hs_pop); + twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop); + } +} + +static int headsetlpga_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct twl4030_priv *twl4030 = w->codec->private_data; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + /* Do the ramp-up only once */ + if (!twl4030->hsr_enabled) + headset_ramp(w->codec, 1); + + twl4030->hsl_enabled = 1; + break; + case SND_SOC_DAPM_POST_PMD: + /* Do the ramp-down only if both headsetL/R is disabled */ + if (!twl4030->hsr_enabled) + headset_ramp(w->codec, 0); + + twl4030->hsl_enabled = 0; + break; + } + return 0; +} + +static int headsetrpga_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct twl4030_priv *twl4030 = w->codec->private_data; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + /* Do the ramp-up only once */ + if (!twl4030->hsl_enabled) + headset_ramp(w->codec, 1); + + twl4030->hsr_enabled = 1; + break; + case SND_SOC_DAPM_POST_PMD: + /* Do the ramp-down only if both headsetL/R is disabled */ + if (!twl4030->hsl_enabled) + headset_ramp(w->codec, 0); + + twl4030->hsr_enabled = 0; break; } return 0; @@ -624,7 +708,7 @@ static int bypass_event(struct snd_soc_dapm_widget *w, struct soc_mixer_control *m = (struct soc_mixer_control *)w->kcontrols->private_value; struct twl4030_priv *twl4030 = w->codec->private_data; - unsigned char reg; + unsigned char reg, misc; reg = twl4030_read_reg_cache(w->codec, m->reg); @@ -636,14 +720,34 @@ static int bypass_event(struct snd_soc_dapm_widget *w, else twl4030->bypass_state &= ~(1 << (m->reg - TWL4030_REG_ARXL1_APGA_CTL)); + } else if (m->reg == TWL4030_REG_VDL_APGA_CTL) { + /* Analog voice bypass */ + if (reg & (1 << m->shift)) + twl4030->bypass_state |= (1 << 4); + else + twl4030->bypass_state &= ~(1 << 4); + } else if (m->reg == TWL4030_REG_VSTPGA) { + /* Voice digital bypass */ + if (reg) + twl4030->bypass_state |= (1 << 5); + else + twl4030->bypass_state &= ~(1 << 5); } else { /* Digital bypass */ if (reg & (0x7 << m->shift)) - twl4030->bypass_state |= (1 << (m->shift ? 5 : 4)); + twl4030->bypass_state |= (1 << (m->shift ? 7 : 6)); else - twl4030->bypass_state &= ~(1 << (m->shift ? 5 : 4)); + twl4030->bypass_state &= ~(1 << (m->shift ? 7 : 6)); } + /* Enable master analog loopback mode if any analog switch is enabled*/ + misc = twl4030_read_reg_cache(w->codec, TWL4030_REG_MISC_SET_1); + if (twl4030->bypass_state & 0x1F) + misc |= TWL4030_FMLOOP_EN; + else + misc &= ~TWL4030_FMLOOP_EN; + twl4030_write(w->codec, TWL4030_REG_MISC_SET_1, misc); + if (w->codec->bias_level == SND_SOC_BIAS_STANDBY) { if (twl4030->bypass_state) twl4030_codec_mute(w->codec, 0); @@ -810,6 +914,48 @@ static int snd_soc_put_volsw_r2_twl4030(struct snd_kcontrol *kcontrol, return err; } +/* Codec operation modes */ +static const char *twl4030_op_modes_texts[] = { + "Option 2 (voice/audio)", "Option 1 (audio)" +}; + +static const struct soc_enum twl4030_op_modes_enum = + SOC_ENUM_SINGLE(TWL4030_REG_CODEC_MODE, 0, + ARRAY_SIZE(twl4030_op_modes_texts), + twl4030_op_modes_texts); + +int snd_soc_put_twl4030_opmode_enum_double(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct twl4030_priv *twl4030 = codec->private_data; + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned short val; + unsigned short mask, bitmask; + + if (twl4030->configured) { + printk(KERN_ERR "twl4030 operation mode cannot be " + "changed on-the-fly\n"); + return -EBUSY; + } + + for (bitmask = 1; bitmask < e->max; bitmask <<= 1) + ; + if (ucontrol->value.enumerated.item[0] > e->max - 1) + return -EINVAL; + + val = ucontrol->value.enumerated.item[0] << e->shift_l; + mask = (bitmask - 1) << e->shift_l; + if (e->shift_l != e->shift_r) { + if (ucontrol->value.enumerated.item[1] > e->max - 1) + return -EINVAL; + val |= ucontrol->value.enumerated.item[1] << e->shift_r; + mask |= (bitmask - 1) << e->shift_r; + } + + return snd_soc_update_bits(codec, e->reg, mask, val); +} + /* * FGAIN volume control: * from -62 to 0 dB in 1 dB steps (mute instead of -63 dB) @@ -823,6 +969,12 @@ static DECLARE_TLV_DB_SCALE(digital_fine_tlv, -6300, 100, 1); */ static DECLARE_TLV_DB_SCALE(digital_coarse_tlv, 0, 600, 0); +/* + * Voice Downlink GAIN volume control: + * from -37 to 12 dB in 1 dB steps (mute instead of -37 dB) + */ +static DECLARE_TLV_DB_SCALE(digital_voice_downlink_tlv, -3700, 100, 1); + /* * Analog playback gain * -24 dB to 12 dB in 2 dB steps @@ -864,7 +1016,32 @@ static const struct soc_enum twl4030_rampdelay_enum = ARRAY_SIZE(twl4030_rampdelay_texts), twl4030_rampdelay_texts); +/* Vibra H-bridge direction mode */ +static const char *twl4030_vibradirmode_texts[] = { + "Vibra H-bridge direction", "Audio data MSB", +}; + +static const struct soc_enum twl4030_vibradirmode_enum = + SOC_ENUM_SINGLE(TWL4030_REG_VIBRA_CTL, 5, + ARRAY_SIZE(twl4030_vibradirmode_texts), + twl4030_vibradirmode_texts); + +/* Vibra H-bridge direction */ +static const char *twl4030_vibradir_texts[] = { + "Positive polarity", "Negative polarity", +}; + +static const struct soc_enum twl4030_vibradir_enum = + SOC_ENUM_SINGLE(TWL4030_REG_VIBRA_CTL, 1, + ARRAY_SIZE(twl4030_vibradir_texts), + twl4030_vibradir_texts); + static const struct snd_kcontrol_new twl4030_snd_controls[] = { + /* Codec operation mode control */ + SOC_ENUM_EXT("Codec Operation Mode", twl4030_op_modes_enum, + snd_soc_get_enum_double, + snd_soc_put_twl4030_opmode_enum_double), + /* Common playback gain controls */ SOC_DOUBLE_R_TLV("DAC1 Digital Fine Playback Volume", TWL4030_REG_ARXL1PGA, TWL4030_REG_ARXR1PGA, @@ -893,6 +1070,16 @@ static const struct snd_kcontrol_new twl4030_snd_controls[] = { TWL4030_REG_ARXL2_APGA_CTL, TWL4030_REG_ARXR2_APGA_CTL, 1, 1, 0), + /* Common voice downlink gain controls */ + SOC_SINGLE_TLV("DAC Voice Digital Downlink Volume", + TWL4030_REG_VRXPGA, 0, 0x31, 0, digital_voice_downlink_tlv), + + SOC_SINGLE_TLV("DAC Voice Analog Downlink Volume", + TWL4030_REG_VDL_APGA_CTL, 3, 0x12, 1, analog_tlv), + + SOC_SINGLE("DAC Voice Analog Downlink Switch", + TWL4030_REG_VDL_APGA_CTL, 1, 1, 0), + /* Separate output gain controls */ SOC_DOUBLE_R_TLV_TWL4030("PreDriv Playback Volume", TWL4030_REG_PREDL_CTL, TWL4030_REG_PREDR_CTL, @@ -920,6 +1107,9 @@ static const struct snd_kcontrol_new twl4030_snd_controls[] = { 0, 3, 5, 0, input_gain_tlv), SOC_ENUM("HS ramp delay", twl4030_rampdelay_enum), + + SOC_ENUM("Vibra H-bridge mode", twl4030_vibradirmode_enum), + SOC_ENUM("Vibra H-bridge direction", twl4030_vibradir_enum), }; static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { @@ -947,26 +1137,19 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("CARKITR"), SND_SOC_DAPM_OUTPUT("HFL"), SND_SOC_DAPM_OUTPUT("HFR"), + SND_SOC_DAPM_OUTPUT("VIBRA"), /* DACs */ - SND_SOC_DAPM_DAC("DAC Right1", "Right Front Playback", + SND_SOC_DAPM_DAC("DAC Right1", "Right Front HiFi Playback", SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_DAC("DAC Left1", "Left Front Playback", + SND_SOC_DAPM_DAC("DAC Left1", "Left Front HiFi Playback", SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_DAC("DAC Right2", "Right Rear Playback", + SND_SOC_DAPM_DAC("DAC Right2", "Right Rear HiFi Playback", SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_DAC("DAC Left2", "Left Rear Playback", + SND_SOC_DAPM_DAC("DAC Left2", "Left Rear HiFi Playback", + SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_DAC("DAC Voice", "Voice Playback", SND_SOC_NOPM, 0, 0), - - /* Analog PGAs */ - SND_SOC_DAPM_PGA("ARXR1_APGA", TWL4030_REG_ARXR1_APGA_CTL, - 0, 0, NULL, 0), - SND_SOC_DAPM_PGA("ARXL1_APGA", TWL4030_REG_ARXL1_APGA_CTL, - 0, 0, NULL, 0), - SND_SOC_DAPM_PGA("ARXR2_APGA", TWL4030_REG_ARXR2_APGA_CTL, - 0, 0, NULL, 0), - SND_SOC_DAPM_PGA("ARXL2_APGA", TWL4030_REG_ARXL2_APGA_CTL, - 0, 0, NULL, 0), /* Analog bypasses */ SND_SOC_DAPM_SWITCH_E("Right1 Analog Loopback", SND_SOC_NOPM, 0, 0, @@ -981,6 +1164,9 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { SND_SOC_DAPM_SWITCH_E("Left2 Analog Loopback", SND_SOC_NOPM, 0, 0, &twl4030_dapm_abypassl2_control, bypass_event, SND_SOC_DAPM_POST_REG), + SND_SOC_DAPM_SWITCH_E("Voice Analog Loopback", SND_SOC_NOPM, 0, 0, + &twl4030_dapm_abypassv_control, + bypass_event, SND_SOC_DAPM_POST_REG), /* Digital bypasses */ SND_SOC_DAPM_SWITCH_E("Left Digital Loopback", SND_SOC_NOPM, 0, 0, @@ -989,43 +1175,88 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { SND_SOC_DAPM_SWITCH_E("Right Digital Loopback", SND_SOC_NOPM, 0, 0, &twl4030_dapm_dbypassr_control, bypass_event, SND_SOC_DAPM_POST_REG), + SND_SOC_DAPM_SWITCH_E("Voice Digital Loopback", SND_SOC_NOPM, 0, 0, + &twl4030_dapm_dbypassv_control, bypass_event, + SND_SOC_DAPM_POST_REG), - SND_SOC_DAPM_MIXER("Analog R1 Playback Mixer", TWL4030_REG_AVDAC_CTL, - 0, 0, NULL, 0), - SND_SOC_DAPM_MIXER("Analog L1 Playback Mixer", TWL4030_REG_AVDAC_CTL, - 1, 0, NULL, 0), - SND_SOC_DAPM_MIXER("Analog R2 Playback Mixer", TWL4030_REG_AVDAC_CTL, - 2, 0, NULL, 0), - SND_SOC_DAPM_MIXER("Analog L2 Playback Mixer", TWL4030_REG_AVDAC_CTL, - 3, 0, NULL, 0), + /* Digital mixers, power control for the physical DACs */ + SND_SOC_DAPM_MIXER("Digital R1 Playback Mixer", + TWL4030_REG_AVDAC_CTL, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("Digital L1 Playback Mixer", + TWL4030_REG_AVDAC_CTL, 1, 0, NULL, 0), + SND_SOC_DAPM_MIXER("Digital R2 Playback Mixer", + TWL4030_REG_AVDAC_CTL, 2, 0, NULL, 0), + SND_SOC_DAPM_MIXER("Digital L2 Playback Mixer", + TWL4030_REG_AVDAC_CTL, 3, 0, NULL, 0), + SND_SOC_DAPM_MIXER("Digital Voice Playback Mixer", + TWL4030_REG_AVDAC_CTL, 4, 0, NULL, 0), + + /* Analog mixers, power control for the physical PGAs */ + SND_SOC_DAPM_MIXER("Analog R1 Playback Mixer", + TWL4030_REG_ARXR1_APGA_CTL, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("Analog L1 Playback Mixer", + TWL4030_REG_ARXL1_APGA_CTL, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("Analog R2 Playback Mixer", + TWL4030_REG_ARXR2_APGA_CTL, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("Analog L2 Playback Mixer", + TWL4030_REG_ARXL2_APGA_CTL, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("Analog Voice Playback Mixer", + TWL4030_REG_VDL_APGA_CTL, 0, 0, NULL, 0), + + /* Output MIXER controls */ + /* Earpiece */ + SND_SOC_DAPM_MIXER("Earpiece Mixer", SND_SOC_NOPM, 0, 0, + &twl4030_dapm_earpiece_controls[0], + ARRAY_SIZE(twl4030_dapm_earpiece_controls)), + /* PreDrivL/R */ + SND_SOC_DAPM_MIXER("PredriveL Mixer", SND_SOC_NOPM, 0, 0, + &twl4030_dapm_predrivel_controls[0], + ARRAY_SIZE(twl4030_dapm_predrivel_controls)), + SND_SOC_DAPM_MIXER("PredriveR Mixer", SND_SOC_NOPM, 0, 0, + &twl4030_dapm_predriver_controls[0], + ARRAY_SIZE(twl4030_dapm_predriver_controls)), + /* HeadsetL/R */ + SND_SOC_DAPM_MIXER("HeadsetL Mixer", SND_SOC_NOPM, 0, 0, + &twl4030_dapm_hsol_controls[0], + ARRAY_SIZE(twl4030_dapm_hsol_controls)), + SND_SOC_DAPM_PGA_E("HeadsetL PGA", SND_SOC_NOPM, + 0, 0, NULL, 0, headsetlpga_event, + SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER("HeadsetR Mixer", SND_SOC_NOPM, 0, 0, + &twl4030_dapm_hsor_controls[0], + ARRAY_SIZE(twl4030_dapm_hsor_controls)), + SND_SOC_DAPM_PGA_E("HeadsetR PGA", SND_SOC_NOPM, + 0, 0, NULL, 0, headsetrpga_event, + SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD), + /* CarkitL/R */ + SND_SOC_DAPM_MIXER("CarkitL Mixer", SND_SOC_NOPM, 0, 0, + &twl4030_dapm_carkitl_controls[0], + ARRAY_SIZE(twl4030_dapm_carkitl_controls)), + SND_SOC_DAPM_MIXER("CarkitR Mixer", SND_SOC_NOPM, 0, 0, + &twl4030_dapm_carkitr_controls[0], + ARRAY_SIZE(twl4030_dapm_carkitr_controls)), /* Output MUX controls */ - /* Earpiece */ - SND_SOC_DAPM_VALUE_MUX("Earpiece Mux", SND_SOC_NOPM, 0, 0, - &twl4030_dapm_earpiece_control), - /* PreDrivL/R */ - SND_SOC_DAPM_VALUE_MUX("PredriveL Mux", SND_SOC_NOPM, 0, 0, - &twl4030_dapm_predrivel_control), - SND_SOC_DAPM_VALUE_MUX("PredriveR Mux", SND_SOC_NOPM, 0, 0, - &twl4030_dapm_predriver_control), - /* HeadsetL/R */ - SND_SOC_DAPM_MUX_E("HeadsetL Mux", SND_SOC_NOPM, 0, 0, - &twl4030_dapm_hsol_control, headsetl_event, - SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_MUX("HeadsetR Mux", SND_SOC_NOPM, 0, 0, - &twl4030_dapm_hsor_control), - /* CarkitL/R */ - SND_SOC_DAPM_MUX("CarkitL Mux", SND_SOC_NOPM, 0, 0, - &twl4030_dapm_carkitl_control), - SND_SOC_DAPM_MUX("CarkitR Mux", SND_SOC_NOPM, 0, 0, - &twl4030_dapm_carkitr_control), /* HandsfreeL/R */ - SND_SOC_DAPM_MUX_E("HandsfreeL Mux", TWL4030_REG_HFL_CTL, 5, 0, - &twl4030_dapm_handsfreel_control, handsfree_event, - SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_MUX_E("HandsfreeR Mux", TWL4030_REG_HFR_CTL, 5, 0, - &twl4030_dapm_handsfreer_control, handsfree_event, - SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX("HandsfreeL Mux", SND_SOC_NOPM, 0, 0, + &twl4030_dapm_handsfreel_control), + SND_SOC_DAPM_SWITCH("HandsfreeL Switch", SND_SOC_NOPM, 0, 0, + &twl4030_dapm_handsfreelmute_control), + SND_SOC_DAPM_PGA_E("HandsfreeL PGA", SND_SOC_NOPM, + 0, 0, NULL, 0, handsfreelpga_event, + SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX("HandsfreeR Mux", SND_SOC_NOPM, 5, 0, + &twl4030_dapm_handsfreer_control), + SND_SOC_DAPM_SWITCH("HandsfreeR Switch", SND_SOC_NOPM, 0, 0, + &twl4030_dapm_handsfreermute_control), + SND_SOC_DAPM_PGA_E("HandsfreeR PGA", SND_SOC_NOPM, + 0, 0, NULL, 0, handsfreerpga_event, + SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD), + /* Vibra */ + SND_SOC_DAPM_MUX("Vibra Mux", TWL4030_REG_VIBRA_CTL, 0, 0, + &twl4030_dapm_vibra_control), + SND_SOC_DAPM_MUX("Vibra Route", SND_SOC_NOPM, 0, 0, + &twl4030_dapm_vibrapath_control), /* Introducing four virtual ADC, since TWL4030 have four channel for capture */ @@ -1050,11 +1281,15 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD| SND_SOC_DAPM_POST_REG), - /* Analog input muxes with switch for the capture amplifiers */ - SND_SOC_DAPM_VALUE_MUX("Analog Left Capture Route", - TWL4030_REG_ANAMICL, 4, 0, &twl4030_dapm_analoglmic_control), - SND_SOC_DAPM_VALUE_MUX("Analog Right Capture Route", - TWL4030_REG_ANAMICR, 4, 0, &twl4030_dapm_analogrmic_control), + /* Analog input mixers for the capture amplifiers */ + SND_SOC_DAPM_MIXER("Analog Left Capture Route", + TWL4030_REG_ANAMICL, 4, 0, + &twl4030_dapm_analoglmic_controls[0], + ARRAY_SIZE(twl4030_dapm_analoglmic_controls)), + SND_SOC_DAPM_MIXER("Analog Right Capture Route", + TWL4030_REG_ANAMICR, 4, 0, + &twl4030_dapm_analogrmic_controls[0], + ARRAY_SIZE(twl4030_dapm_analogrmic_controls)), SND_SOC_DAPM_PGA("ADC Physical Left", TWL4030_REG_AVADC_CTL, 3, 0, NULL, 0), @@ -1073,62 +1308,86 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { }; static const struct snd_soc_dapm_route intercon[] = { - {"Analog L1 Playback Mixer", NULL, "DAC Left1"}, - {"Analog R1 Playback Mixer", NULL, "DAC Right1"}, - {"Analog L2 Playback Mixer", NULL, "DAC Left2"}, - {"Analog R2 Playback Mixer", NULL, "DAC Right2"}, + {"Digital L1 Playback Mixer", NULL, "DAC Left1"}, + {"Digital R1 Playback Mixer", NULL, "DAC Right1"}, + {"Digital L2 Playback Mixer", NULL, "DAC Left2"}, + {"Digital R2 Playback Mixer", NULL, "DAC Right2"}, + {"Digital Voice Playback Mixer", NULL, "DAC Voice"}, - {"ARXL1_APGA", NULL, "Analog L1 Playback Mixer"}, - {"ARXR1_APGA", NULL, "Analog R1 Playback Mixer"}, - {"ARXL2_APGA", NULL, "Analog L2 Playback Mixer"}, - {"ARXR2_APGA", NULL, "Analog R2 Playback Mixer"}, + {"Analog L1 Playback Mixer", NULL, "Digital L1 Playback Mixer"}, + {"Analog R1 Playback Mixer", NULL, "Digital R1 Playback Mixer"}, + {"Analog L2 Playback Mixer", NULL, "Digital L2 Playback Mixer"}, + {"Analog R2 Playback Mixer", NULL, "Digital R2 Playback Mixer"}, + {"Analog Voice Playback Mixer", NULL, "Digital Voice Playback Mixer"}, /* Internal playback routings */ /* Earpiece */ - {"Earpiece Mux", "DACL1", "ARXL1_APGA"}, - {"Earpiece Mux", "DACL2", "ARXL2_APGA"}, - {"Earpiece Mux", "DACR1", "ARXR1_APGA"}, + {"Earpiece Mixer", "Voice", "Analog Voice Playback Mixer"}, + {"Earpiece Mixer", "AudioL1", "Analog L1 Playback Mixer"}, + {"Earpiece Mixer", "AudioL2", "Analog L2 Playback Mixer"}, + {"Earpiece Mixer", "AudioR1", "Analog R1 Playback Mixer"}, /* PreDrivL */ - {"PredriveL Mux", "DACL1", "ARXL1_APGA"}, - {"PredriveL Mux", "DACL2", "ARXL2_APGA"}, - {"PredriveL Mux", "DACR2", "ARXR2_APGA"}, + {"PredriveL Mixer", "Voice", "Analog Voice Playback Mixer"}, + {"PredriveL Mixer", "AudioL1", "Analog L1 Playback Mixer"}, + {"PredriveL Mixer", "AudioL2", "Analog L2 Playback Mixer"}, + {"PredriveL Mixer", "AudioR2", "Analog R2 Playback Mixer"}, /* PreDrivR */ - {"PredriveR Mux", "DACR1", "ARXR1_APGA"}, - {"PredriveR Mux", "DACR2", "ARXR2_APGA"}, - {"PredriveR Mux", "DACL2", "ARXL2_APGA"}, + {"PredriveR Mixer", "Voice", "Analog Voice Playback Mixer"}, + {"PredriveR Mixer", "AudioR1", "Analog R1 Playback Mixer"}, + {"PredriveR Mixer", "AudioR2", "Analog R2 Playback Mixer"}, + {"PredriveR Mixer", "AudioL2", "Analog L2 Playback Mixer"}, /* HeadsetL */ - {"HeadsetL Mux", "DACL1", "ARXL1_APGA"}, - {"HeadsetL Mux", "DACL2", "ARXL2_APGA"}, + {"HeadsetL Mixer", "Voice", "Analog Voice Playback Mixer"}, + {"HeadsetL Mixer", "AudioL1", "Analog L1 Playback Mixer"}, + {"HeadsetL Mixer", "AudioL2", "Analog L2 Playback Mixer"}, + {"HeadsetL PGA", NULL, "HeadsetL Mixer"}, /* HeadsetR */ - {"HeadsetR Mux", "DACR1", "ARXR1_APGA"}, - {"HeadsetR Mux", "DACR2", "ARXR2_APGA"}, + {"HeadsetR Mixer", "Voice", "Analog Voice Playback Mixer"}, + {"HeadsetR Mixer", "AudioR1", "Analog R1 Playback Mixer"}, + {"HeadsetR Mixer", "AudioR2", "Analog R2 Playback Mixer"}, + {"HeadsetR PGA", NULL, "HeadsetR Mixer"}, /* CarkitL */ - {"CarkitL Mux", "DACL1", "ARXL1_APGA"}, - {"CarkitL Mux", "DACL2", "ARXL2_APGA"}, + {"CarkitL Mixer", "Voice", "Analog Voice Playback Mixer"}, + {"CarkitL Mixer", "AudioL1", "Analog L1 Playback Mixer"}, + {"CarkitL Mixer", "AudioL2", "Analog L2 Playback Mixer"}, /* CarkitR */ - {"CarkitR Mux", "DACR1", "ARXR1_APGA"}, - {"CarkitR Mux", "DACR2", "ARXR2_APGA"}, + {"CarkitR Mixer", "Voice", "Analog Voice Playback Mixer"}, + {"CarkitR Mixer", "AudioR1", "Analog R1 Playback Mixer"}, + {"CarkitR Mixer", "AudioR2", "Analog R2 Playback Mixer"}, /* HandsfreeL */ - {"HandsfreeL Mux", "DACL1", "ARXL1_APGA"}, - {"HandsfreeL Mux", "DACL2", "ARXL2_APGA"}, - {"HandsfreeL Mux", "DACR2", "ARXR2_APGA"}, + {"HandsfreeL Mux", "Voice", "Analog Voice Playback Mixer"}, + {"HandsfreeL Mux", "AudioL1", "Analog L1 Playback Mixer"}, + {"HandsfreeL Mux", "AudioL2", "Analog L2 Playback Mixer"}, + {"HandsfreeL Mux", "AudioR2", "Analog R2 Playback Mixer"}, + {"HandsfreeL Switch", "Switch", "HandsfreeL Mux"}, + {"HandsfreeL PGA", NULL, "HandsfreeL Switch"}, /* HandsfreeR */ - {"HandsfreeR Mux", "DACR1", "ARXR1_APGA"}, - {"HandsfreeR Mux", "DACR2", "ARXR2_APGA"}, - {"HandsfreeR Mux", "DACL2", "ARXL2_APGA"}, + {"HandsfreeR Mux", "Voice", "Analog Voice Playback Mixer"}, + {"HandsfreeR Mux", "AudioR1", "Analog R1 Playback Mixer"}, + {"HandsfreeR Mux", "AudioR2", "Analog R2 Playback Mixer"}, + {"HandsfreeR Mux", "AudioL2", "Analog L2 Playback Mixer"}, + {"HandsfreeR Switch", "Switch", "HandsfreeR Mux"}, + {"HandsfreeR PGA", NULL, "HandsfreeR Switch"}, + /* Vibra */ + {"Vibra Mux", "AudioL1", "DAC Left1"}, + {"Vibra Mux", "AudioR1", "DAC Right1"}, + {"Vibra Mux", "AudioL2", "DAC Left2"}, + {"Vibra Mux", "AudioR2", "DAC Right2"}, /* outputs */ - {"OUTL", NULL, "ARXL2_APGA"}, - {"OUTR", NULL, "ARXR2_APGA"}, - {"EARPIECE", NULL, "Earpiece Mux"}, - {"PREDRIVEL", NULL, "PredriveL Mux"}, - {"PREDRIVER", NULL, "PredriveR Mux"}, - {"HSOL", NULL, "HeadsetL Mux"}, - {"HSOR", NULL, "HeadsetR Mux"}, - {"CARKITL", NULL, "CarkitL Mux"}, - {"CARKITR", NULL, "CarkitR Mux"}, - {"HFL", NULL, "HandsfreeL Mux"}, - {"HFR", NULL, "HandsfreeR Mux"}, + {"OUTL", NULL, "Analog L2 Playback Mixer"}, + {"OUTR", NULL, "Analog R2 Playback Mixer"}, + {"EARPIECE", NULL, "Earpiece Mixer"}, + {"PREDRIVEL", NULL, "PredriveL Mixer"}, + {"PREDRIVER", NULL, "PredriveR Mixer"}, + {"HSOL", NULL, "HeadsetL PGA"}, + {"HSOR", NULL, "HeadsetR PGA"}, + {"CARKITL", NULL, "CarkitL Mixer"}, + {"CARKITR", NULL, "CarkitR Mixer"}, + {"HFL", NULL, "HandsfreeL PGA"}, + {"HFR", NULL, "HandsfreeR PGA"}, + {"Vibra Route", "Audio", "Vibra Mux"}, + {"VIBRA", NULL, "Vibra Route"}, /* Capture path */ {"Analog Left Capture Route", "Main mic", "MAINMIC"}, @@ -1168,18 +1427,22 @@ static const struct snd_soc_dapm_route intercon[] = { {"Left1 Analog Loopback", "Switch", "Analog Left Capture Route"}, {"Right2 Analog Loopback", "Switch", "Analog Right Capture Route"}, {"Left2 Analog Loopback", "Switch", "Analog Left Capture Route"}, + {"Voice Analog Loopback", "Switch", "Analog Left Capture Route"}, {"Analog R1 Playback Mixer", NULL, "Right1 Analog Loopback"}, {"Analog L1 Playback Mixer", NULL, "Left1 Analog Loopback"}, {"Analog R2 Playback Mixer", NULL, "Right2 Analog Loopback"}, {"Analog L2 Playback Mixer", NULL, "Left2 Analog Loopback"}, + {"Analog Voice Playback Mixer", NULL, "Voice Analog Loopback"}, /* Digital bypass routes */ {"Right Digital Loopback", "Volume", "TX1 Capture Route"}, {"Left Digital Loopback", "Volume", "TX1 Capture Route"}, + {"Voice Digital Loopback", "Volume", "TX2 Capture Route"}, - {"Analog R2 Playback Mixer", NULL, "Right Digital Loopback"}, - {"Analog L2 Playback Mixer", NULL, "Left Digital Loopback"}, + {"Digital R2 Playback Mixer", NULL, "Right Digital Loopback"}, + {"Digital L2 Playback Mixer", NULL, "Left Digital Loopback"}, + {"Digital Voice Playback Mixer", NULL, "Voice Digital Loopback"}, }; @@ -1226,6 +1489,58 @@ static int twl4030_set_bias_level(struct snd_soc_codec *codec, return 0; } +static void twl4030_constraints(struct twl4030_priv *twl4030, + struct snd_pcm_substream *mst_substream) +{ + struct snd_pcm_substream *slv_substream; + + /* Pick the stream, which need to be constrained */ + if (mst_substream == twl4030->master_substream) + slv_substream = twl4030->slave_substream; + else if (mst_substream == twl4030->slave_substream) + slv_substream = twl4030->master_substream; + else /* This should not happen.. */ + return; + + /* Set the constraints according to the already configured stream */ + snd_pcm_hw_constraint_minmax(slv_substream->runtime, + SNDRV_PCM_HW_PARAM_RATE, + twl4030->rate, + twl4030->rate); + + snd_pcm_hw_constraint_minmax(slv_substream->runtime, + SNDRV_PCM_HW_PARAM_SAMPLE_BITS, + twl4030->sample_bits, + twl4030->sample_bits); + + snd_pcm_hw_constraint_minmax(slv_substream->runtime, + SNDRV_PCM_HW_PARAM_CHANNELS, + twl4030->channels, + twl4030->channels); +} + +/* In case of 4 channel mode, the RX1 L/R for playback and the TX2 L/R for + * capture has to be enabled/disabled. */ +static void twl4030_tdm_enable(struct snd_soc_codec *codec, int direction, + int enable) +{ + u8 reg, mask; + + reg = twl4030_read_reg_cache(codec, TWL4030_REG_OPTION); + + if (direction == SNDRV_PCM_STREAM_PLAYBACK) + mask = TWL4030_ARXL1_VRX_EN | TWL4030_ARXR1_EN; + else + mask = TWL4030_ATXL2_VTXL_EN | TWL4030_ATXR2_VTXR_EN; + + if (enable) + reg |= mask; + else + reg &= ~mask; + + twl4030_write(codec, TWL4030_REG_OPTION, reg); +} + static int twl4030_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -1234,26 +1549,25 @@ static int twl4030_startup(struct snd_pcm_substream *substream, struct snd_soc_codec *codec = socdev->card->codec; struct twl4030_priv *twl4030 = codec->private_data; - /* If we already have a playback or capture going then constrain - * this substream to match it. - */ if (twl4030->master_substream) { - struct snd_pcm_runtime *master_runtime; - master_runtime = twl4030->master_substream->runtime; - - snd_pcm_hw_constraint_minmax(substream->runtime, - SNDRV_PCM_HW_PARAM_RATE, - master_runtime->rate, - master_runtime->rate); - - snd_pcm_hw_constraint_minmax(substream->runtime, - SNDRV_PCM_HW_PARAM_SAMPLE_BITS, - master_runtime->sample_bits, - master_runtime->sample_bits); - twl4030->slave_substream = substream; - } else + /* The DAI has one configuration for playback and capture, so + * if the DAI has been already configured then constrain this + * substream to match it. */ + if (twl4030->configured) + twl4030_constraints(twl4030, twl4030->master_substream); + } else { + if (!(twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE) & + TWL4030_OPTION_1)) { + /* In option2 4 channel is not supported, set the + * constraint for the first stream for channels, the + * second stream will 'inherit' this cosntraint */ + snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_CHANNELS, + 2, 2); + } twl4030->master_substream = substream; + } return 0; } @@ -1270,6 +1584,17 @@ static void twl4030_shutdown(struct snd_pcm_substream *substream, twl4030->master_substream = twl4030->slave_substream; twl4030->slave_substream = NULL; + + /* If all streams are closed, or the remaining stream has not yet + * been configured than set the DAI as not configured. */ + if (!twl4030->master_substream) + twl4030->configured = 0; + else if (!twl4030->master_substream->runtime->channels) + twl4030->configured = 0; + + /* If the closing substream had 4 channel, do the necessary cleanup */ + if (substream->runtime->channels == 4) + twl4030_tdm_enable(codec, substream->stream, 0); } static int twl4030_hw_params(struct snd_pcm_substream *substream, @@ -1282,8 +1607,24 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream, struct twl4030_priv *twl4030 = codec->private_data; u8 mode, old_mode, format, old_format; - if (substream == twl4030->slave_substream) - /* Ignoring hw_params for slave substream */ + /* If the substream has 4 channel, do the necessary setup */ + if (params_channels(params) == 4) { + u8 format, mode; + + format = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF); + mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE); + + /* Safety check: are we in the correct operating mode and + * the interface is in TDM mode? */ + if ((mode & TWL4030_OPTION_1) && + ((format & TWL4030_AIF_FORMAT) == TWL4030_AIF_FORMAT_TDM)) + twl4030_tdm_enable(codec, substream->stream, 1); + else + return -EINVAL; + } + + if (twl4030->configured) + /* Ignoring hw_params for already configured DAI */ return 0; /* bit rate */ @@ -1363,6 +1704,21 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream, /* set CODECPDZ afterwards */ twl4030_codec_enable(codec, 1); } + + /* Store the important parameters for the DAI configuration and set + * the DAI as configured */ + twl4030->configured = 1; + twl4030->rate = params_rate(params); + twl4030->sample_bits = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min; + twl4030->channels = params_channels(params); + + /* If both playback and capture streams are open, and one of them + * is setting the hw parameters right now (since we are here), set + * constraints to the other stream to match the current one. */ + if (twl4030->slave_substream) + twl4030_constraints(twl4030, substream); + return 0; } @@ -1370,17 +1726,21 @@ static int twl4030_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id, unsigned int freq, int dir) { struct snd_soc_codec *codec = codec_dai->codec; + struct twl4030_priv *twl4030 = codec->private_data; u8 infreq; switch (freq) { case 19200000: infreq = TWL4030_APLL_INFREQ_19200KHZ; + twl4030->sysclk = 19200; break; case 26000000: infreq = TWL4030_APLL_INFREQ_26000KHZ; + twl4030->sysclk = 26000; break; case 38400000: infreq = TWL4030_APLL_INFREQ_38400KHZ; + twl4030->sysclk = 38400; break; default: printk(KERN_ERR "TWL4030 set sysclk: unknown rate %d\n", @@ -1424,6 +1784,9 @@ static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai, case SND_SOC_DAIFMT_I2S: format |= TWL4030_AIF_FORMAT_CODEC; break; + case SND_SOC_DAIFMT_DSP_A: + format |= TWL4030_AIF_FORMAT_TDM; + break; default: return -EINVAL; } @@ -1443,6 +1806,180 @@ static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai, return 0; } +/* In case of voice mode, the RX1 L(VRX) for downlink and the TX2 L/R + * (VTXL, VTXR) for uplink has to be enabled/disabled. */ +static void twl4030_voice_enable(struct snd_soc_codec *codec, int direction, + int enable) +{ + u8 reg, mask; + + reg = twl4030_read_reg_cache(codec, TWL4030_REG_OPTION); + + if (direction == SNDRV_PCM_STREAM_PLAYBACK) + mask = TWL4030_ARXL1_VRX_EN; + else + mask = TWL4030_ATXL2_VTXL_EN | TWL4030_ATXR2_VTXR_EN; + + if (enable) + reg |= mask; + else + reg &= ~mask; + + twl4030_write(codec, TWL4030_REG_OPTION, reg); +} + +static int twl4030_voice_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->card->codec; + u8 infreq; + u8 mode; + + /* If the system master clock is not 26MHz, the voice PCM interface is + * not avilable. + */ + infreq = twl4030_read_reg_cache(codec, TWL4030_REG_APLL_CTL) + & TWL4030_APLL_INFREQ; + + if (infreq != TWL4030_APLL_INFREQ_26000KHZ) { + printk(KERN_ERR "TWL4030 voice startup: " + "MCLK is not 26MHz, call set_sysclk() on init\n"); + return -EINVAL; + } + + /* If the codec mode is not option2, the voice PCM interface is not + * avilable. + */ + mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE) + & TWL4030_OPT_MODE; + + if (mode != TWL4030_OPTION_2) { + printk(KERN_ERR "TWL4030 voice startup: " + "the codec mode is not option2\n"); + return -EINVAL; + } + + return 0; +} + +static void twl4030_voice_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->card->codec; + + /* Enable voice digital filters */ + twl4030_voice_enable(codec, substream->stream, 0); +} + +static int twl4030_voice_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->card->codec; + u8 old_mode, mode; + + /* Enable voice digital filters */ + twl4030_voice_enable(codec, substream->stream, 1); + + /* bit rate */ + old_mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE) + & ~(TWL4030_CODECPDZ); + mode = old_mode; + + switch (params_rate(params)) { + case 8000: + mode &= ~(TWL4030_SEL_16K); + break; + case 16000: + mode |= TWL4030_SEL_16K; + break; + default: + printk(KERN_ERR "TWL4030 voice hw params: unknown rate %d\n", + params_rate(params)); + return -EINVAL; + } + + if (mode != old_mode) { + /* change rate and set CODECPDZ */ + twl4030_codec_enable(codec, 0); + twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode); + twl4030_codec_enable(codec, 1); + } + + return 0; +} + +static int twl4030_voice_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = codec_dai->codec; + u8 infreq; + + switch (freq) { + case 26000000: + infreq = TWL4030_APLL_INFREQ_26000KHZ; + break; + default: + printk(KERN_ERR "TWL4030 voice set sysclk: unknown rate %d\n", + freq); + return -EINVAL; + } + + infreq |= TWL4030_APLL_EN; + twl4030_write(codec, TWL4030_REG_APLL_CTL, infreq); + + return 0; +} + +static int twl4030_voice_set_dai_fmt(struct snd_soc_dai *codec_dai, + unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + u8 old_format, format; + + /* get format */ + old_format = twl4030_read_reg_cache(codec, TWL4030_REG_VOICE_IF); + format = old_format; + + /* set master/slave audio interface */ + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFM: + format &= ~(TWL4030_VIF_SLAVE_EN); + break; + case SND_SOC_DAIFMT_CBS_CFS: + format |= TWL4030_VIF_SLAVE_EN; + break; + default: + return -EINVAL; + } + + /* clock inversion */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_IB_NF: + format &= ~(TWL4030_VIF_FORMAT); + break; + case SND_SOC_DAIFMT_NB_IF: + format |= TWL4030_VIF_FORMAT; + break; + default: + return -EINVAL; + } + + if (format != old_format) { + /* change format and set CODECPDZ */ + twl4030_codec_enable(codec, 0); + twl4030_write(codec, TWL4030_REG_VOICE_IF, format); + twl4030_codec_enable(codec, 1); + } + + return 0; +} + #define TWL4030_RATES (SNDRV_PCM_RATE_8000_48000) #define TWL4030_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_S24_LE) @@ -1454,21 +1991,47 @@ static struct snd_soc_dai_ops twl4030_dai_ops = { .set_fmt = twl4030_set_dai_fmt, }; -struct snd_soc_dai twl4030_dai = { +static struct snd_soc_dai_ops twl4030_dai_voice_ops = { + .startup = twl4030_voice_startup, + .shutdown = twl4030_voice_shutdown, + .hw_params = twl4030_voice_hw_params, + .set_sysclk = twl4030_voice_set_dai_sysclk, + .set_fmt = twl4030_voice_set_dai_fmt, +}; + +struct snd_soc_dai twl4030_dai[] = { +{ .name = "twl4030", .playback = { - .stream_name = "Playback", + .stream_name = "HiFi Playback", .channels_min = 2, - .channels_max = 2, + .channels_max = 4, .rates = TWL4030_RATES | SNDRV_PCM_RATE_96000, .formats = TWL4030_FORMATS,}, .capture = { .stream_name = "Capture", .channels_min = 2, - .channels_max = 2, + .channels_max = 4, .rates = TWL4030_RATES, .formats = TWL4030_FORMATS,}, .ops = &twl4030_dai_ops, +}, +{ + .name = "twl4030 Voice", + .playback = { + .stream_name = "Voice Playback", + .channels_min = 1, + .channels_max = 1, + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000, + .formats = SNDRV_PCM_FMTBIT_S16_LE,}, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000, + .formats = SNDRV_PCM_FMTBIT_S16_LE,}, + .ops = &twl4030_dai_voice_ops, +}, }; EXPORT_SYMBOL_GPL(twl4030_dai); @@ -1500,6 +2063,8 @@ static int twl4030_resume(struct platform_device *pdev) static int twl4030_init(struct snd_soc_device *socdev) { struct snd_soc_codec *codec = socdev->card->codec; + struct twl4030_setup_data *setup = socdev->codec_data; + struct twl4030_priv *twl4030 = codec->private_data; int ret = 0; printk(KERN_INFO "TWL4030 Audio Codec init \n"); @@ -1509,14 +2074,31 @@ static int twl4030_init(struct snd_soc_device *socdev) codec->read = twl4030_read_reg_cache; codec->write = twl4030_write; codec->set_bias_level = twl4030_set_bias_level; - codec->dai = &twl4030_dai; - codec->num_dai = 1; + codec->dai = twl4030_dai; + codec->num_dai = ARRAY_SIZE(twl4030_dai), codec->reg_cache_size = sizeof(twl4030_reg); codec->reg_cache = kmemdup(twl4030_reg, sizeof(twl4030_reg), GFP_KERNEL); if (codec->reg_cache == NULL) return -ENOMEM; + /* Configuration for headset ramp delay from setup data */ + if (setup) { + unsigned char hs_pop; + + if (setup->sysclk) + twl4030->sysclk = setup->sysclk; + else + twl4030->sysclk = 26000; + + hs_pop = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET); + hs_pop &= ~TWL4030_RAMP_DELAY; + hs_pop |= (setup->ramp_delay_value << 2); + twl4030_write_reg_cache(codec, TWL4030_REG_HS_POPN_SET, hs_pop); + } else { + twl4030->sysclk = 26000; + } + /* register pcms */ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); if (ret < 0) { @@ -1604,13 +2186,13 @@ EXPORT_SYMBOL_GPL(soc_codec_dev_twl4030); static int __init twl4030_modinit(void) { - return snd_soc_register_dai(&twl4030_dai); + return snd_soc_register_dais(&twl4030_dai[0], ARRAY_SIZE(twl4030_dai)); } module_init(twl4030_modinit); static void __exit twl4030_exit(void) { - snd_soc_unregister_dai(&twl4030_dai); + snd_soc_unregister_dais(&twl4030_dai[0], ARRAY_SIZE(twl4030_dai)); } module_exit(twl4030_exit); diff --git a/sound/soc/codecs/twl4030.h b/sound/soc/codecs/twl4030.h index cb63765db1df..fe5f395d9e4f 100644 --- a/sound/soc/codecs/twl4030.h +++ b/sound/soc/codecs/twl4030.h @@ -92,8 +92,9 @@ #define TWL4030_REG_VIBRA_PWM_SET 0x47 #define TWL4030_REG_ANAMIC_GAIN 0x48 #define TWL4030_REG_MISC_SET_2 0x49 +#define TWL4030_REG_SW_SHADOW 0x4A -#define TWL4030_CACHEREGNUM (TWL4030_REG_MISC_SET_2 + 1) +#define TWL4030_CACHEREGNUM (TWL4030_REG_SW_SHADOW + 1) /* Bitfield Definitions */ @@ -110,9 +111,22 @@ #define TWL4030_APLL_RATE_44100 0x90 #define TWL4030_APLL_RATE_48000 0xA0 #define TWL4030_APLL_RATE_96000 0xE0 -#define TWL4030_SEL_16K 0x04 +#define TWL4030_SEL_16K 0x08 #define TWL4030_CODECPDZ 0x02 #define TWL4030_OPT_MODE 0x01 +#define TWL4030_OPTION_1 (1 << 0) +#define TWL4030_OPTION_2 (0 << 0) + +/* TWL4030_OPTION (0x02) Fields */ + +#define TWL4030_ATXL1_EN (1 << 0) +#define TWL4030_ATXR1_EN (1 << 1) +#define TWL4030_ATXL2_VTXL_EN (1 << 2) +#define TWL4030_ATXR2_VTXR_EN (1 << 3) +#define TWL4030_ARXL1_VRX_EN (1 << 4) +#define TWL4030_ARXR1_EN (1 << 5) +#define TWL4030_ARXL2_EN (1 << 6) +#define TWL4030_ARXR2_EN (1 << 7) /* TWL4030_REG_MICBIAS_CTL (0x04) Fields */ @@ -171,6 +185,17 @@ #define TWL4030_CLK256FS_EN 0x02 #define TWL4030_AIF_EN 0x01 +/* VOICE_IF (0x0F) Fields */ + +#define TWL4030_VIF_SLAVE_EN 0x80 +#define TWL4030_VIF_DIN_EN 0x40 +#define TWL4030_VIF_DOUT_EN 0x20 +#define TWL4030_VIF_SWAP 0x10 +#define TWL4030_VIF_FORMAT 0x08 +#define TWL4030_VIF_TRI_EN 0x04 +#define TWL4030_VIF_SUB_EN 0x02 +#define TWL4030_VIF_EN 0x01 + /* EAR_CTL (0x21) */ #define TWL4030_EAR_GAIN 0x30 @@ -236,7 +261,19 @@ #define TWL4030_SMOOTH_ANAVOL_EN 0x02 #define TWL4030_DIGMIC_LR_SWAP_EN 0x01 -extern struct snd_soc_dai twl4030_dai; +/* TWL4030_REG_SW_SHADOW (0x4A) Fields */ +#define TWL4030_HFL_EN 0x01 +#define TWL4030_HFR_EN 0x02 + +#define TWL4030_DAI_HIFI 0 +#define TWL4030_DAI_VOICE 1 + +extern struct snd_soc_dai twl4030_dai[2]; extern struct snd_soc_codec_device soc_codec_dev_twl4030; +struct twl4030_setup_data { + unsigned int ramp_delay_value; + unsigned int sysclk; +}; + #endif /* End of __TWL4030_AUDIO_H__ */ diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c index ddefb8f80145..269b108e1de6 100644 --- a/sound/soc/codecs/uda134x.c +++ b/sound/soc/codecs/uda134x.c @@ -101,7 +101,7 @@ static int uda134x_write(struct snd_soc_codec *codec, unsigned int reg, pr_debug("%s reg: %02X, value:%02X\n", __func__, reg, value); if (reg >= UDA134X_REGS_NUM) { - printk(KERN_ERR "%s unkown register: reg: %d", + printk(KERN_ERR "%s unkown register: reg: %u", __func__, reg); return -EINVAL; } @@ -296,7 +296,7 @@ static int uda134x_set_dai_sysclk(struct snd_soc_dai *codec_dai, struct snd_soc_codec *codec = codec_dai->codec; struct uda134x_priv *uda134x = codec->private_data; - pr_debug("%s clk_id: %d, freq: %d, dir: %d\n", __func__, + pr_debug("%s clk_id: %d, freq: %u, dir: %d\n", __func__, clk_id, freq, dir); /* Anything between 256fs*8Khz and 512fs*48Khz should be acceptable diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index 0275321ff8ab..e7348d341b76 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c @@ -1108,7 +1108,7 @@ static int wm8350_set_fll(struct snd_soc_dai *codec_dai, if (ret < 0) return ret; dev_dbg(wm8350->dev, - "FLL in %d FLL out %d N 0x%x K 0x%x div %d ratio %d", + "FLL in %u FLL out %u N 0x%x K 0x%x div %d ratio %d", freq_in, freq_out, fll_div.n, fll_div.k, fll_div.div, fll_div.ratio); diff --git a/sound/soc/codecs/wm8350.h b/sound/soc/codecs/wm8350.h index d11bd9288cf9..d088eb4b88bb 100644 --- a/sound/soc/codecs/wm8350.h +++ b/sound/soc/codecs/wm8350.h @@ -13,6 +13,7 @@ #define _WM8350_H #include +#include extern struct snd_soc_dai wm8350_dai; extern struct snd_soc_codec_device soc_codec_dev_wm8350; diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c index 510efa604008..502eefac1ecd 100644 --- a/sound/soc/codecs/wm8400.c +++ b/sound/soc/codecs/wm8400.c @@ -954,7 +954,7 @@ static int fll_factors(struct wm8400_priv *wm8400, struct fll_factors *factors, factors->outdiv *= 2; if (factors->outdiv > 32) { dev_err(wm8400->wm8400->dev, - "Unsupported FLL output frequency %dHz\n", + "Unsupported FLL output frequency %uHz\n", Fout); return -EINVAL; } @@ -1003,7 +1003,7 @@ static int fll_factors(struct wm8400_priv *wm8400, struct fll_factors *factors, factors->k = K / 10; dev_dbg(wm8400->wm8400->dev, - "FLL: Fref=%d Fout=%d N=%x K=%x, FRATIO=%x OUTDIV=%x\n", + "FLL: Fref=%u Fout=%u N=%x K=%x, FRATIO=%x OUTDIV=%x\n", Fref, Fout, factors->n, factors->k, factors->fratio, factors->outdiv); @@ -1473,8 +1473,8 @@ static int wm8400_codec_probe(struct platform_device *dev) codec = &priv->codec; codec->private_data = priv; - codec->control_data = dev->dev.driver_data; - priv->wm8400 = dev->dev.driver_data; + codec->control_data = dev_get_drvdata(&dev->dev); + priv->wm8400 = dev_get_drvdata(&dev->dev); ret = regulator_bulk_get(priv->wm8400->dev, ARRAY_SIZE(power), &power[0]); diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c index 6a4cea09c45d..c8b8dba85890 100644 --- a/sound/soc/codecs/wm8510.c +++ b/sound/soc/codecs/wm8510.c @@ -298,7 +298,7 @@ static void pll_factors(unsigned int target, unsigned int source) if ((Ndiv < 6) || (Ndiv > 12)) printk(KERN_WARNING - "WM8510 N value %d outwith recommended range!d\n", + "WM8510 N value %u outwith recommended range!d\n", Ndiv); pll_div.n = Ndiv; diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index 9f6be3d31ac0..86c4b24db817 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c @@ -415,7 +415,7 @@ static int pll_factors(struct _pll_div *pll_div, unsigned int target, unsigned int K, Ndiv, Nmod; int i; - pr_debug("wm8580: PLL %dHz->%dHz\n", source, target); + pr_debug("wm8580: PLL %uHz->%uHz\n", source, target); /* Scale the output frequency up; the PLL should run in the * region of 90-100MHz. @@ -447,7 +447,7 @@ static int pll_factors(struct _pll_div *pll_div, unsigned int target, if ((Ndiv < 5) || (Ndiv > 13)) { printk(KERN_ERR - "WM8580 N=%d outside supported range\n", Ndiv); + "WM8580 N=%u outside supported range\n", Ndiv); return -EINVAL; } diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index e043e3f60008..7a205876ef4f 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -666,14 +666,14 @@ static int __devinit wm8731_spi_probe(struct spi_device *spi) codec->hw_write = (hw_write_t)wm8731_spi_write; codec->dev = &spi->dev; - spi->dev.driver_data = wm8731; + dev_set_drvdata(&spi->dev, wm8731); return wm8731_register(wm8731); } static int __devexit wm8731_spi_remove(struct spi_device *spi) { - struct wm8731_priv *wm8731 = spi->dev.driver_data; + struct wm8731_priv *wm8731 = dev_get_drvdata(&spi->dev); wm8731_unregister(wm8731); diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index a6e8f3f7f052..d28eeaceb857 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c @@ -703,7 +703,7 @@ static void pll_factors(struct _pll_div *pll_div, unsigned int target, if ((Ndiv < 6) || (Ndiv > 12)) printk(KERN_WARNING - "wm8753: unsupported N = %d\n", Ndiv); + "wm8753: unsupported N = %u\n", Ndiv); pll_div->n = Ndiv; Nmod = target % source; @@ -1822,14 +1822,14 @@ static int __devinit wm8753_spi_probe(struct spi_device *spi) codec->hw_write = (hw_write_t)wm8753_spi_write; codec->dev = &spi->dev; - spi->dev.driver_data = wm8753; + dev_set_drvdata(&spi->dev, wm8753); return wm8753_register(wm8753); } static int __devexit wm8753_spi_remove(struct spi_device *spi) { - struct wm8753_priv *wm8753 = spi->dev.driver_data; + struct wm8753_priv *wm8753 = dev_get_drvdata(&spi->dev); wm8753_unregister(wm8753); return 0; } diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index 46c5ea1ff921..3c78945244b8 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c @@ -778,11 +778,11 @@ static int fll_factors(struct _fll_div *fll_div, unsigned int Fref, } if (target > 100000000) - printk(KERN_WARNING "wm8900: FLL rate %d out of range, Fref=%d" - " Fout=%d\n", target, Fref, Fout); + printk(KERN_WARNING "wm8900: FLL rate %u out of range, Fref=%u" + " Fout=%u\n", target, Fref, Fout); if (div > 32) { printk(KERN_ERR "wm8900: Invalid FLL division rate %u, " - "Fref=%d, Fout=%d, target=%d\n", + "Fref=%u, Fout=%u, target=%u\n", div, Fref, Fout, target); return -EINVAL; } diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index 8cf571f1a803..e8d2e3e14c45 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -217,7 +217,6 @@ struct wm8903_priv { int sysclk; /* Reference counts */ - int charge_pump_users; int class_w_users; int playback_active; int capture_active; @@ -373,6 +372,15 @@ static void wm8903_reset(struct snd_soc_codec *codec) #define WM8903_OUTPUT_INT 0x2 #define WM8903_OUTPUT_IN 0x1 +static int wm8903_cp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + WARN_ON(event != SND_SOC_DAPM_POST_PMU); + mdelay(4); + + return 0; +} + /* * Event for headphone and line out amplifier power changes. Special * power up/down sequences are required in order to maximise pop/click @@ -382,19 +390,20 @@ static int wm8903_output_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = w->codec; - struct wm8903_priv *wm8903 = codec->private_data; - struct i2c_client *i2c = codec->control_data; u16 val; u16 reg; + u16 dcs_reg; + u16 dcs_bit; int shift; - u16 cp_reg = wm8903_read(codec, WM8903_CHARGE_PUMP_0); switch (w->reg) { case WM8903_POWER_MANAGEMENT_2: reg = WM8903_ANALOGUE_HP_0; + dcs_bit = 0 + w->shift; break; case WM8903_POWER_MANAGEMENT_3: reg = WM8903_ANALOGUE_LINEOUT_0; + dcs_bit = 2 + w->shift; break; default: BUG(); @@ -419,18 +428,6 @@ static int wm8903_output_event(struct snd_soc_dapm_widget *w, /* Short the output */ val &= ~(WM8903_OUTPUT_SHORT << shift); wm8903_write(codec, reg, val); - - wm8903->charge_pump_users++; - - dev_dbg(&i2c->dev, "Charge pump use count now %d\n", - wm8903->charge_pump_users); - - if (wm8903->charge_pump_users == 1) { - dev_dbg(&i2c->dev, "Enabling charge pump\n"); - wm8903_write(codec, WM8903_CHARGE_PUMP_0, - cp_reg | WM8903_CP_ENA); - mdelay(4); - } } if (event & SND_SOC_DAPM_POST_PMU) { @@ -446,6 +443,11 @@ static int wm8903_output_event(struct snd_soc_dapm_widget *w, val |= (WM8903_OUTPUT_OUT << shift); wm8903_write(codec, reg, val); + /* Enable the DC servo */ + dcs_reg = wm8903_read(codec, WM8903_DC_SERVO_0); + dcs_reg |= dcs_bit; + wm8903_write(codec, WM8903_DC_SERVO_0, dcs_reg); + /* Remove the short */ val |= (WM8903_OUTPUT_SHORT << shift); wm8903_write(codec, reg, val); @@ -458,25 +460,17 @@ static int wm8903_output_event(struct snd_soc_dapm_widget *w, val &= ~(WM8903_OUTPUT_SHORT << shift); wm8903_write(codec, reg, val); + /* Disable the DC servo */ + dcs_reg = wm8903_read(codec, WM8903_DC_SERVO_0); + dcs_reg &= ~dcs_bit; + wm8903_write(codec, WM8903_DC_SERVO_0, dcs_reg); + /* Then disable the intermediate and output stages */ val &= ~((WM8903_OUTPUT_OUT | WM8903_OUTPUT_INT | WM8903_OUTPUT_IN) << shift); wm8903_write(codec, reg, val); } - if (event & SND_SOC_DAPM_POST_PMD) { - wm8903->charge_pump_users--; - - dev_dbg(&i2c->dev, "Charge pump use count now %d\n", - wm8903->charge_pump_users); - - if (wm8903->charge_pump_users == 0) { - dev_dbg(&i2c->dev, "Disabling charge pump\n"); - wm8903_write(codec, WM8903_CHARGE_PUMP_0, - cp_reg & ~WM8903_CP_ENA); - } - } - return 0; } @@ -539,6 +533,7 @@ static int wm8903_class_w_put(struct snd_kcontrol *kcontrol, /* ALSA can only do steps of .01dB */ static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1); +static const DECLARE_TLV_DB_SCALE(digital_sidetone_tlv, -3600, 300, 0); static const DECLARE_TLV_DB_SCALE(out_tlv, -5700, 100, 0); static const DECLARE_TLV_DB_SCALE(drc_tlv_thresh, 0, 75, 0); @@ -657,6 +652,16 @@ static const struct soc_enum rinput_inv_enum = SOC_ENUM_SINGLE(WM8903_ANALOGUE_RIGHT_INPUT_1, 4, 3, rinput_mux_text); +static const char *sidetone_text[] = { + "None", "Left", "Right" +}; + +static const struct soc_enum lsidetone_enum = + SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_0, 2, 3, sidetone_text); + +static const struct soc_enum rsidetone_enum = + SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_0, 0, 3, sidetone_text); + static const struct snd_kcontrol_new wm8903_snd_controls[] = { /* Input PGAs - No TLV since the scale depends on PGA mode */ @@ -700,6 +705,9 @@ SOC_DOUBLE_R_TLV("Digital Capture Volume", WM8903_ADC_DIGITAL_VOLUME_LEFT, SOC_ENUM("ADC Companding Mode", adc_companding), SOC_SINGLE("ADC Companding Switch", WM8903_AUDIO_INTERFACE_0, 3, 1, 0), +SOC_DOUBLE_TLV("Digital Sidetone Volume", WM8903_DAC_DIGITAL_0, 4, 8, + 12, 0, digital_sidetone_tlv), + /* DAC */ SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8903_DAC_DIGITAL_VOLUME_LEFT, WM8903_DAC_DIGITAL_VOLUME_RIGHT, 1, 120, 0, digital_tlv), @@ -762,6 +770,12 @@ static const struct snd_kcontrol_new rinput_mux = static const struct snd_kcontrol_new rinput_inv_mux = SOC_DAPM_ENUM("Right Inverting Input Mux", rinput_inv_enum); +static const struct snd_kcontrol_new lsidetone_mux = + SOC_DAPM_ENUM("DACL Sidetone Mux", lsidetone_enum); + +static const struct snd_kcontrol_new rsidetone_mux = + SOC_DAPM_ENUM("DACR Sidetone Mux", rsidetone_enum); + static const struct snd_kcontrol_new left_output_mixer[] = { SOC_DAPM_SINGLE("DACL Switch", WM8903_ANALOGUE_LEFT_MIX_0, 3, 1, 0), SOC_DAPM_SINGLE("DACR Switch", WM8903_ANALOGUE_LEFT_MIX_0, 2, 1, 0), @@ -828,6 +842,9 @@ SND_SOC_DAPM_PGA("Right Input PGA", WM8903_POWER_MANAGEMENT_0, 0, 0, NULL, 0), SND_SOC_DAPM_ADC("ADCL", "Left HiFi Capture", WM8903_POWER_MANAGEMENT_6, 1, 0), SND_SOC_DAPM_ADC("ADCR", "Right HiFi Capture", WM8903_POWER_MANAGEMENT_6, 0, 0), +SND_SOC_DAPM_MUX("DACL Sidetone", SND_SOC_NOPM, 0, 0, &lsidetone_mux), +SND_SOC_DAPM_MUX("DACR Sidetone", SND_SOC_NOPM, 0, 0, &rsidetone_mux), + SND_SOC_DAPM_DAC("DACL", "Left Playback", WM8903_POWER_MANAGEMENT_6, 3, 0), SND_SOC_DAPM_DAC("DACR", "Right Playback", WM8903_POWER_MANAGEMENT_6, 2, 0), @@ -844,26 +861,29 @@ SND_SOC_DAPM_MIXER("Right Speaker Mixer", WM8903_POWER_MANAGEMENT_4, 0, 0, SND_SOC_DAPM_PGA_E("Left Headphone Output PGA", WM8903_POWER_MANAGEMENT_2, 1, 0, NULL, 0, wm8903_output_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PRE_PMD), SND_SOC_DAPM_PGA_E("Right Headphone Output PGA", WM8903_POWER_MANAGEMENT_2, 0, 0, NULL, 0, wm8903_output_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PRE_PMD), SND_SOC_DAPM_PGA_E("Left Line Output PGA", WM8903_POWER_MANAGEMENT_3, 1, 0, NULL, 0, wm8903_output_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PRE_PMD), SND_SOC_DAPM_PGA_E("Right Line Output PGA", WM8903_POWER_MANAGEMENT_3, 0, 0, NULL, 0, wm8903_output_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PRE_PMD), SND_SOC_DAPM_PGA("Left Speaker PGA", WM8903_POWER_MANAGEMENT_5, 1, 0, NULL, 0), SND_SOC_DAPM_PGA("Right Speaker PGA", WM8903_POWER_MANAGEMENT_5, 0, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("Charge Pump", WM8903_CHARGE_PUMP_0, 0, 0, + wm8903_cp_event, SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_SUPPLY("CLK_DSP", WM8903_CLOCK_RATES_2, 1, 0, NULL, 0), }; static const struct snd_soc_dapm_route intercon[] = { @@ -909,7 +929,19 @@ static const struct snd_soc_dapm_route intercon[] = { { "Right Input PGA", NULL, "Right Input Mode Mux" }, { "ADCL", NULL, "Left Input PGA" }, + { "ADCL", NULL, "CLK_DSP" }, { "ADCR", NULL, "Right Input PGA" }, + { "ADCR", NULL, "CLK_DSP" }, + + { "DACL Sidetone", "Left", "ADCL" }, + { "DACL Sidetone", "Right", "ADCR" }, + { "DACR Sidetone", "Left", "ADCL" }, + { "DACR Sidetone", "Right", "ADCR" }, + + { "DACL", NULL, "DACL Sidetone" }, + { "DACL", NULL, "CLK_DSP" }, + { "DACR", NULL, "DACR Sidetone" }, + { "DACR", NULL, "CLK_DSP" }, { "Left Output Mixer", "Left Bypass Switch", "Left Input PGA" }, { "Left Output Mixer", "Right Bypass Switch", "Right Input PGA" }, @@ -951,6 +983,11 @@ static const struct snd_soc_dapm_route intercon[] = { { "ROP", NULL, "Right Speaker PGA" }, { "RON", NULL, "Right Speaker PGA" }, + + { "Left Headphone Output PGA", NULL, "Charge Pump" }, + { "Right Headphone Output PGA", NULL, "Charge Pump" }, + { "Left Line Output PGA", NULL, "Charge Pump" }, + { "Right Line Output PGA", NULL, "Charge Pump" }, }; static int wm8903_add_widgets(struct snd_soc_codec *codec) @@ -985,6 +1022,11 @@ static int wm8903_set_bias_level(struct snd_soc_codec *codec, wm8903_write(codec, WM8903_CLOCK_RATES_2, WM8903_CLK_SYS_ENA); + /* Change DC servo dither level in startup sequence */ + wm8903_write(codec, WM8903_WRITE_SEQUENCER_0, 0x11); + wm8903_write(codec, WM8903_WRITE_SEQUENCER_1, 0x1257); + wm8903_write(codec, WM8903_WRITE_SEQUENCER_2, 0x2); + wm8903_run_sequence(codec, 0); wm8903_sync_reg_cache(codec, codec->reg_cache); @@ -1215,22 +1257,18 @@ static struct { int div; } bclk_divs[] = { { 10, 0 }, - { 15, 1 }, { 20, 2 }, { 30, 3 }, { 40, 4 }, { 50, 5 }, - { 55, 6 }, { 60, 7 }, { 80, 8 }, { 100, 9 }, - { 110, 10 }, { 120, 11 }, { 160, 12 }, { 200, 13 }, { 220, 14 }, { 240, 15 }, - { 250, 16 }, { 300, 17 }, { 320, 18 }, { 440, 19 }, @@ -1277,14 +1315,8 @@ static int wm8903_startup(struct snd_pcm_substream *substream, if (wm8903->master_substream) { master_runtime = wm8903->master_substream->runtime; - dev_dbg(&i2c->dev, "Constraining to %d bits at %dHz\n", - master_runtime->sample_bits, - master_runtime->rate); - - snd_pcm_hw_constraint_minmax(substream->runtime, - SNDRV_PCM_HW_PARAM_RATE, - master_runtime->rate, - master_runtime->rate); + dev_dbg(&i2c->dev, "Constraining to %d bits\n", + master_runtime->sample_bits); snd_pcm_hw_constraint_minmax(substream->runtime, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, @@ -1523,6 +1555,7 @@ struct snd_soc_dai wm8903_dai = { .formats = WM8903_FORMATS, }, .ops = &wm8903_dai_ops, + .symmetric_rates = 1, }; EXPORT_SYMBOL_GPL(wm8903_dai); diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c new file mode 100644 index 000000000000..b8e17d6bc1f7 --- /dev/null +++ b/sound/soc/codecs/wm8940.c @@ -0,0 +1,955 @@ +/* + * wm8940.c -- WM8940 ALSA Soc Audio driver + * + * Author: Jonathan Cameron + * + * Based on wm8510.c + * Copyright 2006 Wolfson Microelectronics PLC. + * Author: Liam Girdwood + * + * 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. + * + * Not currently handled: + * Notch filter control + * AUXMode (inverting vs mixer) + * No means to obtain current gain if alc enabled. + * No use made of gpio + * Fast VMID discharge for power down + * Soft Start + * DLR and ALR Swaps not enabled + * Digital Sidetone not supported + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wm8940.h" + +struct wm8940_priv { + unsigned int sysclk; + u16 reg_cache[WM8940_CACHEREGNUM]; + struct snd_soc_codec codec; +}; + +static u16 wm8940_reg_defaults[] = { + 0x8940, /* Soft Reset */ + 0x0000, /* Power 1 */ + 0x0000, /* Power 2 */ + 0x0000, /* Power 3 */ + 0x0010, /* Interface Control */ + 0x0000, /* Companding Control */ + 0x0140, /* Clock Control */ + 0x0000, /* Additional Controls */ + 0x0000, /* GPIO Control */ + 0x0002, /* Auto Increment Control */ + 0x0000, /* DAC Control */ + 0x00FF, /* DAC Volume */ + 0, + 0, + 0x0100, /* ADC Control */ + 0x00FF, /* ADC Volume */ + 0x0000, /* Notch Filter 1 Control 1 */ + 0x0000, /* Notch Filter 1 Control 2 */ + 0x0000, /* Notch Filter 2 Control 1 */ + 0x0000, /* Notch Filter 2 Control 2 */ + 0x0000, /* Notch Filter 3 Control 1 */ + 0x0000, /* Notch Filter 3 Control 2 */ + 0x0000, /* Notch Filter 4 Control 1 */ + 0x0000, /* Notch Filter 4 Control 2 */ + 0x0032, /* DAC Limit Control 1 */ + 0x0000, /* DAC Limit Control 2 */ + 0, + 0, + 0, + 0, + 0, + 0, + 0x0038, /* ALC Control 1 */ + 0x000B, /* ALC Control 2 */ + 0x0032, /* ALC Control 3 */ + 0x0000, /* Noise Gate */ + 0x0041, /* PLLN */ + 0x000C, /* PLLK1 */ + 0x0093, /* PLLK2 */ + 0x00E9, /* PLLK3 */ + 0, + 0, + 0x0030, /* ALC Control 4 */ + 0, + 0x0002, /* Input Control */ + 0x0050, /* PGA Gain */ + 0, + 0x0002, /* ADC Boost Control */ + 0, + 0x0002, /* Output Control */ + 0x0000, /* Speaker Mixer Control */ + 0, + 0, + 0, + 0x0079, /* Speaker Volume */ + 0, + 0x0000, /* Mono Mixer Control */ +}; + +static inline unsigned int wm8940_read_reg_cache(struct snd_soc_codec *codec, + unsigned int reg) +{ + u16 *cache = codec->reg_cache; + + if (reg >= ARRAY_SIZE(wm8940_reg_defaults)) + return -1; + + return cache[reg]; +} + +static inline int wm8940_write_reg_cache(struct snd_soc_codec *codec, + u16 reg, unsigned int value) +{ + u16 *cache = codec->reg_cache; + + if (reg >= ARRAY_SIZE(wm8940_reg_defaults)) + return -1; + + cache[reg] = value; + + return 0; +} + +static int wm8940_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + int ret; + u8 data[3] = { reg, + (value & 0xff00) >> 8, + (value & 0x00ff) + }; + + wm8940_write_reg_cache(codec, reg, value); + + ret = codec->hw_write(codec->control_data, data, 3); + + if (ret < 0) + return ret; + else if (ret != 3) + return -EIO; + return 0; +} + +static const char *wm8940_companding[] = { "Off", "NC", "u-law", "A-law" }; +static const struct soc_enum wm8940_adc_companding_enum += SOC_ENUM_SINGLE(WM8940_COMPANDINGCTL, 1, 4, wm8940_companding); +static const struct soc_enum wm8940_dac_companding_enum += SOC_ENUM_SINGLE(WM8940_COMPANDINGCTL, 3, 4, wm8940_companding); + +static const char *wm8940_alc_mode_text[] = {"ALC", "Limiter"}; +static const struct soc_enum wm8940_alc_mode_enum += SOC_ENUM_SINGLE(WM8940_ALC3, 8, 2, wm8940_alc_mode_text); + +static const char *wm8940_mic_bias_level_text[] = {"0.9", "0.65"}; +static const struct soc_enum wm8940_mic_bias_level_enum += SOC_ENUM_SINGLE(WM8940_INPUTCTL, 8, 2, wm8940_mic_bias_level_text); + +static const char *wm8940_filter_mode_text[] = {"Audio", "Application"}; +static const struct soc_enum wm8940_filter_mode_enum += SOC_ENUM_SINGLE(WM8940_ADC, 7, 2, wm8940_filter_mode_text); + +static DECLARE_TLV_DB_SCALE(wm8940_spk_vol_tlv, -5700, 100, 1); +static DECLARE_TLV_DB_SCALE(wm8940_att_tlv, -1000, 1000, 0); +static DECLARE_TLV_DB_SCALE(wm8940_pga_vol_tlv, -1200, 75, 0); +static DECLARE_TLV_DB_SCALE(wm8940_alc_min_tlv, -1200, 600, 0); +static DECLARE_TLV_DB_SCALE(wm8940_alc_max_tlv, 675, 600, 0); +static DECLARE_TLV_DB_SCALE(wm8940_alc_tar_tlv, -2250, 50, 0); +static DECLARE_TLV_DB_SCALE(wm8940_lim_boost_tlv, 0, 100, 0); +static DECLARE_TLV_DB_SCALE(wm8940_lim_thresh_tlv, -600, 100, 0); +static DECLARE_TLV_DB_SCALE(wm8940_adc_tlv, -12750, 50, 1); +static DECLARE_TLV_DB_SCALE(wm8940_capture_boost_vol_tlv, 0, 2000, 0); + +static const struct snd_kcontrol_new wm8940_snd_controls[] = { + SOC_SINGLE("Digital Loopback Switch", WM8940_COMPANDINGCTL, + 6, 1, 0), + SOC_ENUM("DAC Companding", wm8940_dac_companding_enum), + SOC_ENUM("ADC Companding", wm8940_adc_companding_enum), + + SOC_ENUM("ALC Mode", wm8940_alc_mode_enum), + SOC_SINGLE("ALC Switch", WM8940_ALC1, 8, 1, 0), + SOC_SINGLE_TLV("ALC Capture Max Gain", WM8940_ALC1, + 3, 7, 1, wm8940_alc_max_tlv), + SOC_SINGLE_TLV("ALC Capture Min Gain", WM8940_ALC1, + 0, 7, 0, wm8940_alc_min_tlv), + SOC_SINGLE_TLV("ALC Capture Target", WM8940_ALC2, + 0, 14, 0, wm8940_alc_tar_tlv), + SOC_SINGLE("ALC Capture Hold", WM8940_ALC2, 4, 10, 0), + SOC_SINGLE("ALC Capture Decay", WM8940_ALC3, 4, 10, 0), + SOC_SINGLE("ALC Capture Attach", WM8940_ALC3, 0, 10, 0), + SOC_SINGLE("ALC ZC Switch", WM8940_ALC4, 1, 1, 0), + SOC_SINGLE("ALC Capture Noise Gate Switch", WM8940_NOISEGATE, + 3, 1, 0), + SOC_SINGLE("ALC Capture Noise Gate Threshold", WM8940_NOISEGATE, + 0, 7, 0), + + SOC_SINGLE("DAC Playback Limiter Switch", WM8940_DACLIM1, 8, 1, 0), + SOC_SINGLE("DAC Playback Limiter Attack", WM8940_DACLIM1, 0, 9, 0), + SOC_SINGLE("DAC Playback Limiter Decay", WM8940_DACLIM1, 4, 11, 0), + SOC_SINGLE_TLV("DAC Playback Limiter Threshold", WM8940_DACLIM2, + 4, 9, 1, wm8940_lim_thresh_tlv), + SOC_SINGLE_TLV("DAC Playback Limiter Boost", WM8940_DACLIM2, + 0, 12, 0, wm8940_lim_boost_tlv), + + SOC_SINGLE("Capture PGA ZC Switch", WM8940_PGAGAIN, 7, 1, 0), + SOC_SINGLE_TLV("Capture PGA Volume", WM8940_PGAGAIN, + 0, 63, 0, wm8940_pga_vol_tlv), + SOC_SINGLE_TLV("Digital Playback Volume", WM8940_DACVOL, + 0, 255, 0, wm8940_adc_tlv), + SOC_SINGLE_TLV("Digital Capture Volume", WM8940_ADCVOL, + 0, 255, 0, wm8940_adc_tlv), + SOC_ENUM("Mic Bias Level", wm8940_mic_bias_level_enum), + SOC_SINGLE_TLV("Capture Boost Volue", WM8940_ADCBOOST, + 8, 1, 0, wm8940_capture_boost_vol_tlv), + SOC_SINGLE_TLV("Speaker Playback Volume", WM8940_SPKVOL, + 0, 63, 0, wm8940_spk_vol_tlv), + SOC_SINGLE("Speaker Playback Switch", WM8940_SPKVOL, 6, 1, 1), + + SOC_SINGLE_TLV("Speaker Mixer Line Bypass Volume", WM8940_SPKVOL, + 8, 1, 1, wm8940_att_tlv), + SOC_SINGLE("Speaker Playback ZC Switch", WM8940_SPKVOL, 7, 1, 0), + + SOC_SINGLE("Mono Out Switch", WM8940_MONOMIX, 6, 1, 1), + SOC_SINGLE_TLV("Mono Mixer Line Bypass Volume", WM8940_MONOMIX, + 7, 1, 1, wm8940_att_tlv), + + SOC_SINGLE("High Pass Filter Switch", WM8940_ADC, 8, 1, 0), + SOC_ENUM("High Pass Filter Mode", wm8940_filter_mode_enum), + SOC_SINGLE("High Pass Filter Cut Off", WM8940_ADC, 4, 7, 0), + SOC_SINGLE("ADC Inversion Switch", WM8940_ADC, 0, 1, 0), + SOC_SINGLE("DAC Inversion Switch", WM8940_DAC, 0, 1, 0), + SOC_SINGLE("DAC Auto Mute Switch", WM8940_DAC, 2, 1, 0), + SOC_SINGLE("ZC Timeout Clock Switch", WM8940_ADDCNTRL, 0, 1, 0), +}; + +static const struct snd_kcontrol_new wm8940_speaker_mixer_controls[] = { + SOC_DAPM_SINGLE("Line Bypass Switch", WM8940_SPKMIX, 1, 1, 0), + SOC_DAPM_SINGLE("Aux Playback Switch", WM8940_SPKMIX, 5, 1, 0), + SOC_DAPM_SINGLE("PCM Playback Switch", WM8940_SPKMIX, 0, 1, 0), +}; + +static const struct snd_kcontrol_new wm8940_mono_mixer_controls[] = { + SOC_DAPM_SINGLE("Line Bypass Switch", WM8940_MONOMIX, 1, 1, 0), + SOC_DAPM_SINGLE("Aux Playback Switch", WM8940_MONOMIX, 2, 1, 0), + SOC_DAPM_SINGLE("PCM Playback Switch", WM8940_MONOMIX, 0, 1, 0), +}; + +static DECLARE_TLV_DB_SCALE(wm8940_boost_vol_tlv, -1500, 300, 1); +static const struct snd_kcontrol_new wm8940_input_boost_controls[] = { + SOC_DAPM_SINGLE("Mic PGA Switch", WM8940_PGAGAIN, 6, 1, 1), + SOC_DAPM_SINGLE_TLV("Aux Volume", WM8940_ADCBOOST, + 0, 7, 0, wm8940_boost_vol_tlv), + SOC_DAPM_SINGLE_TLV("Mic Volume", WM8940_ADCBOOST, + 4, 7, 0, wm8940_boost_vol_tlv), +}; + +static const struct snd_kcontrol_new wm8940_micpga_controls[] = { + SOC_DAPM_SINGLE("AUX Switch", WM8940_INPUTCTL, 2, 1, 0), + SOC_DAPM_SINGLE("MICP Switch", WM8940_INPUTCTL, 0, 1, 0), + SOC_DAPM_SINGLE("MICN Switch", WM8940_INPUTCTL, 1, 1, 0), +}; + +static const struct snd_soc_dapm_widget wm8940_dapm_widgets[] = { + SND_SOC_DAPM_MIXER("Speaker Mixer", WM8940_POWER3, 2, 0, + &wm8940_speaker_mixer_controls[0], + ARRAY_SIZE(wm8940_speaker_mixer_controls)), + SND_SOC_DAPM_MIXER("Mono Mixer", WM8940_POWER3, 3, 0, + &wm8940_mono_mixer_controls[0], + ARRAY_SIZE(wm8940_mono_mixer_controls)), + SND_SOC_DAPM_DAC("DAC", "HiFi Playback", WM8940_POWER3, 0, 0), + + SND_SOC_DAPM_PGA("SpkN Out", WM8940_POWER3, 5, 0, NULL, 0), + SND_SOC_DAPM_PGA("SpkP Out", WM8940_POWER3, 6, 0, NULL, 0), + SND_SOC_DAPM_PGA("Mono Out", WM8940_POWER3, 7, 0, NULL, 0), + SND_SOC_DAPM_OUTPUT("MONOOUT"), + SND_SOC_DAPM_OUTPUT("SPKOUTP"), + SND_SOC_DAPM_OUTPUT("SPKOUTN"), + + SND_SOC_DAPM_PGA("Aux Input", WM8940_POWER1, 6, 0, NULL, 0), + SND_SOC_DAPM_ADC("ADC", "HiFi Capture", WM8940_POWER2, 0, 0), + SND_SOC_DAPM_MIXER("Mic PGA", WM8940_POWER2, 2, 0, + &wm8940_micpga_controls[0], + ARRAY_SIZE(wm8940_micpga_controls)), + SND_SOC_DAPM_MIXER("Boost Mixer", WM8940_POWER2, 4, 0, + &wm8940_input_boost_controls[0], + ARRAY_SIZE(wm8940_input_boost_controls)), + SND_SOC_DAPM_MICBIAS("Mic Bias", WM8940_POWER1, 4, 0), + + SND_SOC_DAPM_INPUT("MICN"), + SND_SOC_DAPM_INPUT("MICP"), + SND_SOC_DAPM_INPUT("AUX"), +}; + +static const struct snd_soc_dapm_route audio_map[] = { + /* Mono output mixer */ + {"Mono Mixer", "PCM Playback Switch", "DAC"}, + {"Mono Mixer", "Aux Playback Switch", "Aux Input"}, + {"Mono Mixer", "Line Bypass Switch", "Boost Mixer"}, + + /* Speaker output mixer */ + {"Speaker Mixer", "PCM Playback Switch", "DAC"}, + {"Speaker Mixer", "Aux Playback Switch", "Aux Input"}, + {"Speaker Mixer", "Line Bypass Switch", "Boost Mixer"}, + + /* Outputs */ + {"Mono Out", NULL, "Mono Mixer"}, + {"MONOOUT", NULL, "Mono Out"}, + {"SpkN Out", NULL, "Speaker Mixer"}, + {"SpkP Out", NULL, "Speaker Mixer"}, + {"SPKOUTN", NULL, "SpkN Out"}, + {"SPKOUTP", NULL, "SpkP Out"}, + + /* Microphone PGA */ + {"Mic PGA", "MICN Switch", "MICN"}, + {"Mic PGA", "MICP Switch", "MICP"}, + {"Mic PGA", "AUX Switch", "AUX"}, + + /* Boost Mixer */ + {"Boost Mixer", "Mic PGA Switch", "Mic PGA"}, + {"Boost Mixer", "Mic Volume", "MICP"}, + {"Boost Mixer", "Aux Volume", "Aux Input"}, + + {"ADC", NULL, "Boost Mixer"}, +}; + +static int wm8940_add_widgets(struct snd_soc_codec *codec) +{ + int ret; + + ret = snd_soc_dapm_new_controls(codec, wm8940_dapm_widgets, + ARRAY_SIZE(wm8940_dapm_widgets)); + if (ret) + goto error_ret; + ret = snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); + if (ret) + goto error_ret; + ret = snd_soc_dapm_new_widgets(codec); + +error_ret: + return ret; +} + +#define wm8940_reset(c) wm8940_write(c, WM8940_SOFTRESET, 0); + +static int wm8940_set_dai_fmt(struct snd_soc_dai *codec_dai, + unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + u16 iface = wm8940_read_reg_cache(codec, WM8940_IFACE) & 0xFE67; + u16 clk = wm8940_read_reg_cache(codec, WM8940_CLOCK) & 0x1fe; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + clk |= 1; + break; + case SND_SOC_DAIFMT_CBS_CFS: + break; + default: + return -EINVAL; + } + wm8940_write(codec, WM8940_CLOCK, clk); + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + iface |= (2 << 3); + break; + case SND_SOC_DAIFMT_LEFT_J: + iface |= (1 << 3); + break; + case SND_SOC_DAIFMT_RIGHT_J: + break; + case SND_SOC_DAIFMT_DSP_A: + iface |= (3 << 3); + break; + case SND_SOC_DAIFMT_DSP_B: + iface |= (3 << 3) | (1 << 7); + break; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_NB_IF: + iface |= (1 << 7); + break; + case SND_SOC_DAIFMT_IB_NF: + iface |= (1 << 8); + break; + case SND_SOC_DAIFMT_IB_IF: + iface |= (1 << 8) | (1 << 7); + break; + } + + wm8940_write(codec, WM8940_IFACE, iface); + + return 0; +} + +static int wm8940_i2s_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->card->codec; + u16 iface = wm8940_read_reg_cache(codec, WM8940_IFACE) & 0xFD9F; + u16 addcntrl = wm8940_read_reg_cache(codec, WM8940_ADDCNTRL) & 0xFFF1; + u16 companding = wm8940_read_reg_cache(codec, + WM8940_COMPANDINGCTL) & 0xFFDF; + int ret; + + /* LoutR control */ + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE + && params_channels(params) == 2) + iface |= (1 << 9); + + switch (params_rate(params)) { + case SNDRV_PCM_RATE_8000: + addcntrl |= (0x5 << 1); + break; + case SNDRV_PCM_RATE_11025: + addcntrl |= (0x4 << 1); + break; + case SNDRV_PCM_RATE_16000: + addcntrl |= (0x3 << 1); + break; + case SNDRV_PCM_RATE_22050: + addcntrl |= (0x2 << 1); + break; + case SNDRV_PCM_RATE_32000: + addcntrl |= (0x1 << 1); + break; + case SNDRV_PCM_RATE_44100: + case SNDRV_PCM_RATE_48000: + break; + } + ret = wm8940_write(codec, WM8940_ADDCNTRL, addcntrl); + if (ret) + goto error_ret; + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S8: + companding = companding | (1 << 5); + break; + case SNDRV_PCM_FORMAT_S16_LE: + break; + case SNDRV_PCM_FORMAT_S20_3LE: + iface |= (1 << 5); + break; + case SNDRV_PCM_FORMAT_S24_LE: + iface |= (2 << 5); + break; + case SNDRV_PCM_FORMAT_S32_LE: + iface |= (3 << 5); + break; + } + ret = wm8940_write(codec, WM8940_COMPANDINGCTL, companding); + if (ret) + goto error_ret; + ret = wm8940_write(codec, WM8940_IFACE, iface); + +error_ret: + return ret; +} + +static int wm8940_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_codec *codec = dai->codec; + u16 mute_reg = wm8940_read_reg_cache(codec, WM8940_DAC) & 0xffbf; + + if (mute) + mute_reg |= 0x40; + + return wm8940_write(codec, WM8940_DAC, mute_reg); +} + +static int wm8940_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + u16 val; + u16 pwr_reg = wm8940_read_reg_cache(codec, WM8940_POWER1) & 0x1F0; + int ret = 0; + + switch (level) { + case SND_SOC_BIAS_ON: + /* ensure bufioen and biasen */ + pwr_reg |= (1 << 2) | (1 << 3); + /* Enable thermal shutdown */ + val = wm8940_read_reg_cache(codec, WM8940_OUTPUTCTL); + ret = wm8940_write(codec, WM8940_OUTPUTCTL, val | 0x2); + if (ret) + break; + /* set vmid to 75k */ + ret = wm8940_write(codec, WM8940_POWER1, pwr_reg | 0x1); + break; + case SND_SOC_BIAS_PREPARE: + /* ensure bufioen and biasen */ + pwr_reg |= (1 << 2) | (1 << 3); + ret = wm8940_write(codec, WM8940_POWER1, pwr_reg | 0x1); + break; + case SND_SOC_BIAS_STANDBY: + /* ensure bufioen and biasen */ + pwr_reg |= (1 << 2) | (1 << 3); + /* set vmid to 300k for standby */ + ret = wm8940_write(codec, WM8940_POWER1, pwr_reg | 0x2); + break; + case SND_SOC_BIAS_OFF: + ret = wm8940_write(codec, WM8940_POWER1, pwr_reg); + break; + } + + return ret; +} + +struct pll_ { + unsigned int pre_scale:2; + unsigned int n:4; + unsigned int k; +}; + +static struct pll_ pll_div; + +/* The size in bits of the pll divide multiplied by 10 + * to allow rounding later */ +#define FIXED_PLL_SIZE ((1 << 24) * 10) +static void pll_factors(unsigned int target, unsigned int source) +{ + unsigned long long Kpart; + unsigned int K, Ndiv, Nmod; + /* The left shift ist to avoid accuracy loss when right shifting */ + Ndiv = target / source; + + if (Ndiv > 12) { + source <<= 1; + /* Multiply by 2 */ + pll_div.pre_scale = 0; + Ndiv = target / source; + } else if (Ndiv < 3) { + source >>= 2; + /* Divide by 4 */ + pll_div.pre_scale = 3; + Ndiv = target / source; + } else if (Ndiv < 6) { + source >>= 1; + /* divide by 2 */ + pll_div.pre_scale = 2; + Ndiv = target / source; + } else + pll_div.pre_scale = 1; + + if ((Ndiv < 6) || (Ndiv > 12)) + printk(KERN_WARNING + "WM8940 N value %d outwith recommended range!d\n", + Ndiv); + + pll_div.n = Ndiv; + Nmod = target % source; + Kpart = FIXED_PLL_SIZE * (long long)Nmod; + + do_div(Kpart, source); + + K = Kpart & 0xFFFFFFFF; + + /* Check if we need to round */ + if ((K % 10) >= 5) + K += 5; + + /* Move down to proper range now rounding is done */ + K /= 10; + + pll_div.k = K; +} + +/* Untested at the moment */ +static int wm8940_set_dai_pll(struct snd_soc_dai *codec_dai, + int pll_id, unsigned int freq_in, unsigned int freq_out) +{ + struct snd_soc_codec *codec = codec_dai->codec; + u16 reg; + + /* Turn off PLL */ + reg = wm8940_read_reg_cache(codec, WM8940_POWER1); + wm8940_write(codec, WM8940_POWER1, reg & 0x1df); + + if (freq_in == 0 || freq_out == 0) { + /* Clock CODEC directly from MCLK */ + reg = wm8940_read_reg_cache(codec, WM8940_CLOCK); + wm8940_write(codec, WM8940_CLOCK, reg & 0x0ff); + /* Pll power down */ + wm8940_write(codec, WM8940_PLLN, (1 << 7)); + return 0; + } + + /* Pll is followed by a frequency divide by 4 */ + pll_factors(freq_out*4, freq_in); + if (pll_div.k) + wm8940_write(codec, WM8940_PLLN, + (pll_div.pre_scale << 4) | pll_div.n | (1 << 6)); + else /* No factional component */ + wm8940_write(codec, WM8940_PLLN, + (pll_div.pre_scale << 4) | pll_div.n); + wm8940_write(codec, WM8940_PLLK1, pll_div.k >> 18); + wm8940_write(codec, WM8940_PLLK2, (pll_div.k >> 9) & 0x1ff); + wm8940_write(codec, WM8940_PLLK3, pll_div.k & 0x1ff); + /* Enable the PLL */ + reg = wm8940_read_reg_cache(codec, WM8940_POWER1); + wm8940_write(codec, WM8940_POWER1, reg | 0x020); + + /* Run CODEC from PLL instead of MCLK */ + reg = wm8940_read_reg_cache(codec, WM8940_CLOCK); + wm8940_write(codec, WM8940_CLOCK, reg | 0x100); + + return 0; +} + +static int wm8940_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct wm8940_priv *wm8940 = codec->private_data; + + switch (freq) { + case 11289600: + case 12000000: + case 12288000: + case 16934400: + case 18432000: + wm8940->sysclk = freq; + return 0; + } + return -EINVAL; +} + +static int wm8940_set_dai_clkdiv(struct snd_soc_dai *codec_dai, + int div_id, int div) +{ + struct snd_soc_codec *codec = codec_dai->codec; + u16 reg; + int ret = 0; + + switch (div_id) { + case WM8940_BCLKDIV: + reg = wm8940_read_reg_cache(codec, WM8940_CLOCK) & 0xFFEF3; + ret = wm8940_write(codec, WM8940_CLOCK, reg | (div << 2)); + break; + case WM8940_MCLKDIV: + reg = wm8940_read_reg_cache(codec, WM8940_CLOCK) & 0xFF1F; + ret = wm8940_write(codec, WM8940_CLOCK, reg | (div << 5)); + break; + case WM8940_OPCLKDIV: + reg = wm8940_read_reg_cache(codec, WM8940_ADDCNTRL) & 0xFFCF; + ret = wm8940_write(codec, WM8940_ADDCNTRL, reg | (div << 4)); + break; + } + return ret; +} + +#define WM8940_RATES SNDRV_PCM_RATE_8000_48000 + +#define WM8940_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ + SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_ops wm8940_dai_ops = { + .hw_params = wm8940_i2s_hw_params, + .set_sysclk = wm8940_set_dai_sysclk, + .digital_mute = wm8940_mute, + .set_fmt = wm8940_set_dai_fmt, + .set_clkdiv = wm8940_set_dai_clkdiv, + .set_pll = wm8940_set_dai_pll, +}; + +struct snd_soc_dai wm8940_dai = { + .name = "WM8940", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = WM8940_RATES, + .formats = WM8940_FORMATS, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = WM8940_RATES, + .formats = WM8940_FORMATS, + }, + .ops = &wm8940_dai_ops, + .symmetric_rates = 1, +}; +EXPORT_SYMBOL_GPL(wm8940_dai); + +static int wm8940_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + + return wm8940_set_bias_level(codec, SND_SOC_BIAS_OFF); +} + +static int wm8940_resume(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + int i; + int ret; + u8 data[3]; + u16 *cache = codec->reg_cache; + + /* Sync reg_cache with the hardware + * Could use auto incremented writes to speed this up + */ + for (i = 0; i < ARRAY_SIZE(wm8940_reg_defaults); i++) { + data[0] = i; + data[1] = (cache[i] & 0xFF00) >> 8; + data[2] = cache[i] & 0x00FF; + ret = codec->hw_write(codec->control_data, data, 3); + if (ret < 0) + goto error_ret; + else if (ret != 3) { + ret = -EIO; + goto error_ret; + } + } + ret = wm8940_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + if (ret) + goto error_ret; + ret = wm8940_set_bias_level(codec, codec->suspend_bias_level); + +error_ret: + return ret; +} + +static struct snd_soc_codec *wm8940_codec; + +static int wm8940_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec; + + int ret = 0; + + if (wm8940_codec == NULL) { + dev_err(&pdev->dev, "Codec device not registered\n"); + return -ENODEV; + } + + socdev->card->codec = wm8940_codec; + codec = wm8940_codec; + + mutex_init(&codec->mutex); + /* register pcms */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + dev_err(codec->dev, "failed to create pcms: %d\n", ret); + goto pcm_err; + } + + ret = snd_soc_add_controls(codec, wm8940_snd_controls, + ARRAY_SIZE(wm8940_snd_controls)); + if (ret) + goto error_free_pcms; + ret = wm8940_add_widgets(codec); + if (ret) + goto error_free_pcms; + + ret = snd_soc_init_card(socdev); + if (ret < 0) { + dev_err(codec->dev, "failed to register card: %d\n", ret); + goto error_free_pcms; + } + + return ret; + +error_free_pcms: + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); +pcm_err: + return ret; +} + +static int wm8940_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); + + return 0; +} + +struct snd_soc_codec_device soc_codec_dev_wm8940 = { + .probe = wm8940_probe, + .remove = wm8940_remove, + .suspend = wm8940_suspend, + .resume = wm8940_resume, +}; +EXPORT_SYMBOL_GPL(soc_codec_dev_wm8940); + +static int wm8940_register(struct wm8940_priv *wm8940) +{ + struct wm8940_setup_data *pdata = wm8940->codec.dev->platform_data; + struct snd_soc_codec *codec = &wm8940->codec; + int ret; + u16 reg; + if (wm8940_codec) { + dev_err(codec->dev, "Another WM8940 is registered\n"); + return -EINVAL; + } + + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + + codec->private_data = wm8940; + codec->name = "WM8940"; + codec->owner = THIS_MODULE; + codec->read = wm8940_read_reg_cache; + codec->write = wm8940_write; + codec->bias_level = SND_SOC_BIAS_OFF; + codec->set_bias_level = wm8940_set_bias_level; + codec->dai = &wm8940_dai; + codec->num_dai = 1; + codec->reg_cache_size = ARRAY_SIZE(wm8940_reg_defaults); + codec->reg_cache = &wm8940->reg_cache; + + memcpy(codec->reg_cache, wm8940_reg_defaults, + sizeof(wm8940_reg_defaults)); + + ret = wm8940_reset(codec); + if (ret < 0) { + dev_err(codec->dev, "Failed to issue reset\n"); + return ret; + } + + wm8940_dai.dev = codec->dev; + + wm8940_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + ret = wm8940_write(codec, WM8940_POWER1, 0x180); + if (ret < 0) + return ret; + + if (!pdata) + dev_warn(codec->dev, "No platform data supplied\n"); + else { + reg = wm8940_read_reg_cache(codec, WM8940_OUTPUTCTL); + ret = wm8940_write(codec, WM8940_OUTPUTCTL, reg | pdata->vroi); + if (ret < 0) + return ret; + } + + + wm8940_codec = codec; + + ret = snd_soc_register_codec(codec); + if (ret) { + dev_err(codec->dev, "Failed to register codec: %d\n", ret); + return ret; + } + + ret = snd_soc_register_dai(&wm8940_dai); + if (ret) { + dev_err(codec->dev, "Failed to register DAI: %d\n", ret); + snd_soc_unregister_codec(codec); + return ret; + } + + return 0; +} + +static void wm8940_unregister(struct wm8940_priv *wm8940) +{ + wm8940_set_bias_level(&wm8940->codec, SND_SOC_BIAS_OFF); + snd_soc_unregister_dai(&wm8940_dai); + snd_soc_unregister_codec(&wm8940->codec); + kfree(wm8940); + wm8940_codec = NULL; +} + +static int wm8940_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct wm8940_priv *wm8940; + struct snd_soc_codec *codec; + + wm8940 = kzalloc(sizeof *wm8940, GFP_KERNEL); + if (wm8940 == NULL) + return -ENOMEM; + + codec = &wm8940->codec; + codec->hw_write = (hw_write_t)i2c_master_send; + i2c_set_clientdata(i2c, wm8940); + codec->control_data = i2c; + codec->dev = &i2c->dev; + + return wm8940_register(wm8940); +} + +static int __devexit wm8940_i2c_remove(struct i2c_client *client) +{ + struct wm8940_priv *wm8940 = i2c_get_clientdata(client); + + wm8940_unregister(wm8940); + + return 0; +} + +static const struct i2c_device_id wm8940_i2c_id[] = { + { "wm8940", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, wm8940_i2c_id); + +static struct i2c_driver wm8940_i2c_driver = { + .driver = { + .name = "WM8940 I2C Codec", + .owner = THIS_MODULE, + }, + .probe = wm8940_i2c_probe, + .remove = __devexit_p(wm8940_i2c_remove), + .id_table = wm8940_i2c_id, +}; + +static int __init wm8940_modinit(void) +{ + int ret; + + ret = i2c_add_driver(&wm8940_i2c_driver); + if (ret) + printk(KERN_ERR "Failed to register WM8940 I2C driver: %d\n", + ret); + return ret; +} +module_init(wm8940_modinit); + +static void __exit wm8940_exit(void) +{ + i2c_del_driver(&wm8940_i2c_driver); +} +module_exit(wm8940_exit); + +MODULE_DESCRIPTION("ASoC WM8940 driver"); +MODULE_AUTHOR("Jonathan Cameron"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8940.h b/sound/soc/codecs/wm8940.h new file mode 100644 index 000000000000..8410eed3ef84 --- /dev/null +++ b/sound/soc/codecs/wm8940.h @@ -0,0 +1,104 @@ +/* + * wm8940.h -- WM8940 Soc Audio driver + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _WM8940_H +#define _WM8940_H + +struct wm8940_setup_data { + /* Vref to analogue output resistance */ +#define WM8940_VROI_1K 0 +#define WM8940_VROI_30K 1 + unsigned int vroi:1; +}; +extern struct snd_soc_dai wm8940_dai; +extern struct snd_soc_codec_device soc_codec_dev_wm8940; + +/* WM8940 register space */ +#define WM8940_SOFTRESET 0x00 +#define WM8940_POWER1 0x01 +#define WM8940_POWER2 0x02 +#define WM8940_POWER3 0x03 +#define WM8940_IFACE 0x04 +#define WM8940_COMPANDINGCTL 0x05 +#define WM8940_CLOCK 0x06 +#define WM8940_ADDCNTRL 0x07 +#define WM8940_GPIO 0x08 +#define WM8940_CTLINT 0x09 +#define WM8940_DAC 0x0A +#define WM8940_DACVOL 0x0B + +#define WM8940_ADC 0x0E +#define WM8940_ADCVOL 0x0F +#define WM8940_NOTCH1 0x10 +#define WM8940_NOTCH2 0x11 +#define WM8940_NOTCH3 0x12 +#define WM8940_NOTCH4 0x13 +#define WM8940_NOTCH5 0x14 +#define WM8940_NOTCH6 0x15 +#define WM8940_NOTCH7 0x16 +#define WM8940_NOTCH8 0x17 +#define WM8940_DACLIM1 0x18 +#define WM8940_DACLIM2 0x19 + +#define WM8940_ALC1 0x20 +#define WM8940_ALC2 0x21 +#define WM8940_ALC3 0x22 +#define WM8940_NOISEGATE 0x23 +#define WM8940_PLLN 0x24 +#define WM8940_PLLK1 0x25 +#define WM8940_PLLK2 0x26 +#define WM8940_PLLK3 0x27 + +#define WM8940_ALC4 0x2A + +#define WM8940_INPUTCTL 0x2C +#define WM8940_PGAGAIN 0x2D + +#define WM8940_ADCBOOST 0x2F + +#define WM8940_OUTPUTCTL 0x31 +#define WM8940_SPKMIX 0x32 + +#define WM8940_SPKVOL 0x36 + +#define WM8940_MONOMIX 0x38 + +#define WM8940_CACHEREGNUM 0x57 + + +/* Clock divider Id's */ +#define WM8940_BCLKDIV 0 +#define WM8940_MCLKDIV 1 +#define WM8940_OPCLKDIV 2 + +/* MCLK clock dividers */ +#define WM8940_MCLKDIV_1 0 +#define WM8940_MCLKDIV_1_5 1 +#define WM8940_MCLKDIV_2 2 +#define WM8940_MCLKDIV_3 3 +#define WM8940_MCLKDIV_4 4 +#define WM8940_MCLKDIV_6 5 +#define WM8940_MCLKDIV_8 6 +#define WM8940_MCLKDIV_12 7 + +/* BCLK clock dividers */ +#define WM8940_BCLKDIV_1 0 +#define WM8940_BCLKDIV_2 1 +#define WM8940_BCLKDIV_4 2 +#define WM8940_BCLKDIV_8 3 +#define WM8940_BCLKDIV_16 4 +#define WM8940_BCLKDIV_32 5 + +/* PLL Out Dividers */ +#define WM8940_OPCLKDIV_1 0 +#define WM8940_OPCLKDIV_2 1 +#define WM8940_OPCLKDIV_3 2 +#define WM8940_OPCLKDIV_4 3 + +#endif /* _WM8940_H */ + diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c new file mode 100644 index 000000000000..e224d8add170 --- /dev/null +++ b/sound/soc/codecs/wm8960.c @@ -0,0 +1,969 @@ +/* + * wm8960.c -- WM8960 ALSA SoC Audio driver + * + * Author: Liam Girdwood + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wm8960.h" + +#define AUDIO_NAME "wm8960" + +struct snd_soc_codec_device soc_codec_dev_wm8960; + +/* R25 - Power 1 */ +#define WM8960_VREF 0x40 + +/* R28 - Anti-pop 1 */ +#define WM8960_POBCTRL 0x80 +#define WM8960_BUFDCOPEN 0x10 +#define WM8960_BUFIOEN 0x08 +#define WM8960_SOFT_ST 0x04 +#define WM8960_HPSTBY 0x01 + +/* R29 - Anti-pop 2 */ +#define WM8960_DISOP 0x40 + +/* + * wm8960 register cache + * We can't read the WM8960 register space when we are + * using 2 wire for device control, so we cache them instead. + */ +static const u16 wm8960_reg[WM8960_CACHEREGNUM] = { + 0x0097, 0x0097, 0x0000, 0x0000, + 0x0000, 0x0008, 0x0000, 0x000a, + 0x01c0, 0x0000, 0x00ff, 0x00ff, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x007b, 0x0100, 0x0032, + 0x0000, 0x00c3, 0x00c3, 0x01c0, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0100, 0x0100, 0x0050, 0x0050, + 0x0050, 0x0050, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0040, 0x0000, + 0x0000, 0x0050, 0x0050, 0x0000, + 0x0002, 0x0037, 0x004d, 0x0080, + 0x0008, 0x0031, 0x0026, 0x00e9, +}; + +struct wm8960_priv { + u16 reg_cache[WM8960_CACHEREGNUM]; + struct snd_soc_codec codec; +}; + +/* + * read wm8960 register cache + */ +static inline unsigned int wm8960_read_reg_cache(struct snd_soc_codec *codec, + unsigned int reg) +{ + u16 *cache = codec->reg_cache; + if (reg == WM8960_RESET) + return 0; + if (reg >= WM8960_CACHEREGNUM) + return -1; + return cache[reg]; +} + +/* + * write wm8960 register cache + */ +static inline void wm8960_write_reg_cache(struct snd_soc_codec *codec, + u16 reg, unsigned int value) +{ + u16 *cache = codec->reg_cache; + if (reg >= WM8960_CACHEREGNUM) + return; + cache[reg] = value; +} + +static inline unsigned int wm8960_read(struct snd_soc_codec *codec, + unsigned int reg) +{ + return wm8960_read_reg_cache(codec, reg); +} + +/* + * write to the WM8960 register space + */ +static int wm8960_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + u8 data[2]; + + /* data is + * D15..D9 WM8960 register offset + * D8...D0 register data + */ + data[0] = (reg << 1) | ((value >> 8) & 0x0001); + data[1] = value & 0x00ff; + + wm8960_write_reg_cache(codec, reg, value); + if (codec->hw_write(codec->control_data, data, 2) == 2) + return 0; + else + return -EIO; +} + +#define wm8960_reset(c) wm8960_write(c, WM8960_RESET, 0) + +/* enumerated controls */ +static const char *wm8960_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"}; +static const char *wm8960_polarity[] = {"No Inversion", "Left Inverted", + "Right Inverted", "Stereo Inversion"}; +static const char *wm8960_3d_upper_cutoff[] = {"High", "Low"}; +static const char *wm8960_3d_lower_cutoff[] = {"Low", "High"}; +static const char *wm8960_alcfunc[] = {"Off", "Right", "Left", "Stereo"}; +static const char *wm8960_alcmode[] = {"ALC", "Limiter"}; + +static const struct soc_enum wm8960_enum[] = { + SOC_ENUM_SINGLE(WM8960_DACCTL1, 1, 4, wm8960_deemph), + SOC_ENUM_SINGLE(WM8960_DACCTL1, 5, 4, wm8960_polarity), + SOC_ENUM_SINGLE(WM8960_DACCTL2, 5, 4, wm8960_polarity), + SOC_ENUM_SINGLE(WM8960_3D, 6, 2, wm8960_3d_upper_cutoff), + SOC_ENUM_SINGLE(WM8960_3D, 5, 2, wm8960_3d_lower_cutoff), + SOC_ENUM_SINGLE(WM8960_ALC1, 7, 4, wm8960_alcfunc), + SOC_ENUM_SINGLE(WM8960_ALC3, 8, 2, wm8960_alcmode), +}; + +static const DECLARE_TLV_DB_SCALE(adc_tlv, -9700, 50, 0); +static const DECLARE_TLV_DB_SCALE(dac_tlv, -12700, 50, 1); +static const DECLARE_TLV_DB_SCALE(bypass_tlv, -2100, 300, 0); +static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1); + +static const struct snd_kcontrol_new wm8960_snd_controls[] = { +SOC_DOUBLE_R_TLV("Capture Volume", WM8960_LINVOL, WM8960_RINVOL, + 0, 63, 0, adc_tlv), +SOC_DOUBLE_R("Capture Volume ZC Switch", WM8960_LINVOL, WM8960_RINVOL, + 6, 1, 0), +SOC_DOUBLE_R("Capture Switch", WM8960_LINVOL, WM8960_RINVOL, + 7, 1, 0), + +SOC_DOUBLE_R_TLV("Playback Volume", WM8960_LDAC, WM8960_RDAC, + 0, 255, 0, dac_tlv), + +SOC_DOUBLE_R_TLV("Headphone Playback Volume", WM8960_LOUT1, WM8960_ROUT1, + 0, 127, 0, out_tlv), +SOC_DOUBLE_R("Headphone Playback ZC Switch", WM8960_LOUT1, WM8960_ROUT1, + 7, 1, 0), + +SOC_DOUBLE_R_TLV("Speaker Playback Volume", WM8960_LOUT2, WM8960_ROUT2, + 0, 127, 0, out_tlv), +SOC_DOUBLE_R("Speaker Playback ZC Switch", WM8960_LOUT2, WM8960_ROUT2, + 7, 1, 0), +SOC_SINGLE("Speaker DC Volume", WM8960_CLASSD3, 3, 5, 0), +SOC_SINGLE("Speaker AC Volume", WM8960_CLASSD3, 0, 5, 0), + +SOC_SINGLE("PCM Playback -6dB Switch", WM8960_DACCTL1, 7, 1, 0), +SOC_ENUM("ADC Polarity", wm8960_enum[1]), +SOC_ENUM("Playback De-emphasis", wm8960_enum[0]), +SOC_SINGLE("ADC High Pass Filter Switch", WM8960_DACCTL1, 0, 1, 0), + +SOC_ENUM("DAC Polarity", wm8960_enum[2]), + +SOC_ENUM("3D Filter Upper Cut-Off", wm8960_enum[3]), +SOC_ENUM("3D Filter Lower Cut-Off", wm8960_enum[4]), +SOC_SINGLE("3D Volume", WM8960_3D, 1, 15, 0), +SOC_SINGLE("3D Switch", WM8960_3D, 0, 1, 0), + +SOC_ENUM("ALC Function", wm8960_enum[5]), +SOC_SINGLE("ALC Max Gain", WM8960_ALC1, 4, 7, 0), +SOC_SINGLE("ALC Target", WM8960_ALC1, 0, 15, 1), +SOC_SINGLE("ALC Min Gain", WM8960_ALC2, 4, 7, 0), +SOC_SINGLE("ALC Hold Time", WM8960_ALC2, 0, 15, 0), +SOC_ENUM("ALC Mode", wm8960_enum[6]), +SOC_SINGLE("ALC Decay", WM8960_ALC3, 4, 15, 0), +SOC_SINGLE("ALC Attack", WM8960_ALC3, 0, 15, 0), + +SOC_SINGLE("Noise Gate Threshold", WM8960_NOISEG, 3, 31, 0), +SOC_SINGLE("Noise Gate Switch", WM8960_NOISEG, 0, 1, 0), + +SOC_DOUBLE_R("ADC PCM Capture Volume", WM8960_LINPATH, WM8960_RINPATH, + 0, 127, 0), + +SOC_SINGLE_TLV("Left Output Mixer Boost Bypass Volume", + WM8960_BYPASS1, 4, 7, 1, bypass_tlv), +SOC_SINGLE_TLV("Left Output Mixer LINPUT3 Volume", + WM8960_LOUTMIX, 4, 7, 1, bypass_tlv), +SOC_SINGLE_TLV("Right Output Mixer Boost Bypass Volume", + WM8960_BYPASS2, 4, 7, 1, bypass_tlv), +SOC_SINGLE_TLV("Right Output Mixer RINPUT3 Volume", + WM8960_ROUTMIX, 4, 7, 1, bypass_tlv), +}; + +static const struct snd_kcontrol_new wm8960_lin_boost[] = { +SOC_DAPM_SINGLE("LINPUT2 Switch", WM8960_LINPATH, 6, 1, 0), +SOC_DAPM_SINGLE("LINPUT3 Switch", WM8960_LINPATH, 7, 1, 0), +SOC_DAPM_SINGLE("LINPUT1 Switch", WM8960_LINPATH, 8, 1, 0), +}; + +static const struct snd_kcontrol_new wm8960_lin[] = { +SOC_DAPM_SINGLE("Boost Switch", WM8960_LINPATH, 3, 1, 0), +}; + +static const struct snd_kcontrol_new wm8960_rin_boost[] = { +SOC_DAPM_SINGLE("RINPUT2 Switch", WM8960_RINPATH, 6, 1, 0), +SOC_DAPM_SINGLE("RINPUT3 Switch", WM8960_RINPATH, 7, 1, 0), +SOC_DAPM_SINGLE("RINPUT1 Switch", WM8960_RINPATH, 8, 1, 0), +}; + +static const struct snd_kcontrol_new wm8960_rin[] = { +SOC_DAPM_SINGLE("Boost Switch", WM8960_RINPATH, 3, 1, 0), +}; + +static const struct snd_kcontrol_new wm8960_loutput_mixer[] = { +SOC_DAPM_SINGLE("PCM Playback Switch", WM8960_LOUTMIX, 8, 1, 0), +SOC_DAPM_SINGLE("LINPUT3 Switch", WM8960_LOUTMIX, 7, 1, 0), +SOC_DAPM_SINGLE("Boost Bypass Switch", WM8960_BYPASS1, 7, 1, 0), +}; + +static const struct snd_kcontrol_new wm8960_routput_mixer[] = { +SOC_DAPM_SINGLE("PCM Playback Switch", WM8960_ROUTMIX, 8, 1, 0), +SOC_DAPM_SINGLE("RINPUT3 Switch", WM8960_ROUTMIX, 7, 1, 0), +SOC_DAPM_SINGLE("Boost Bypass Switch", WM8960_BYPASS2, 7, 1, 0), +}; + +static const struct snd_kcontrol_new wm8960_mono_out[] = { +SOC_DAPM_SINGLE("Left Switch", WM8960_MONOMIX1, 7, 1, 0), +SOC_DAPM_SINGLE("Right Switch", WM8960_MONOMIX2, 7, 1, 0), +}; + +static const struct snd_soc_dapm_widget wm8960_dapm_widgets[] = { +SND_SOC_DAPM_INPUT("LINPUT1"), +SND_SOC_DAPM_INPUT("RINPUT1"), +SND_SOC_DAPM_INPUT("LINPUT2"), +SND_SOC_DAPM_INPUT("RINPUT2"), +SND_SOC_DAPM_INPUT("LINPUT3"), +SND_SOC_DAPM_INPUT("RINPUT3"), + +SND_SOC_DAPM_MICBIAS("MICB", WM8960_POWER1, 1, 0), + +SND_SOC_DAPM_MIXER("Left Boost Mixer", WM8960_POWER1, 5, 0, + wm8960_lin_boost, ARRAY_SIZE(wm8960_lin_boost)), +SND_SOC_DAPM_MIXER("Right Boost Mixer", WM8960_POWER1, 4, 0, + wm8960_rin_boost, ARRAY_SIZE(wm8960_rin_boost)), + +SND_SOC_DAPM_MIXER("Left Input Mixer", WM8960_POWER3, 5, 0, + wm8960_lin, ARRAY_SIZE(wm8960_lin)), +SND_SOC_DAPM_MIXER("Right Input Mixer", WM8960_POWER3, 4, 0, + wm8960_rin, ARRAY_SIZE(wm8960_rin)), + +SND_SOC_DAPM_ADC("Left ADC", "Capture", WM8960_POWER2, 3, 0), +SND_SOC_DAPM_ADC("Right ADC", "Capture", WM8960_POWER2, 2, 0), + +SND_SOC_DAPM_DAC("Left DAC", "Playback", WM8960_POWER2, 8, 0), +SND_SOC_DAPM_DAC("Right DAC", "Playback", WM8960_POWER2, 7, 0), + +SND_SOC_DAPM_MIXER("Left Output Mixer", WM8960_POWER3, 3, 0, + &wm8960_loutput_mixer[0], + ARRAY_SIZE(wm8960_loutput_mixer)), +SND_SOC_DAPM_MIXER("Right Output Mixer", WM8960_POWER3, 2, 0, + &wm8960_routput_mixer[0], + ARRAY_SIZE(wm8960_routput_mixer)), + +SND_SOC_DAPM_MIXER("Mono Output Mixer", WM8960_POWER2, 1, 0, + &wm8960_mono_out[0], + ARRAY_SIZE(wm8960_mono_out)), + +SND_SOC_DAPM_PGA("LOUT1 PGA", WM8960_POWER2, 6, 0, NULL, 0), +SND_SOC_DAPM_PGA("ROUT1 PGA", WM8960_POWER2, 5, 0, NULL, 0), + +SND_SOC_DAPM_PGA("Left Speaker PGA", WM8960_POWER2, 4, 0, NULL, 0), +SND_SOC_DAPM_PGA("Right Speaker PGA", WM8960_POWER2, 3, 0, NULL, 0), + +SND_SOC_DAPM_PGA("Right Speaker Output", WM8960_CLASSD1, 7, 0, NULL, 0), +SND_SOC_DAPM_PGA("Left Speaker Output", WM8960_CLASSD1, 6, 0, NULL, 0), + +SND_SOC_DAPM_OUTPUT("SPK_LP"), +SND_SOC_DAPM_OUTPUT("SPK_LN"), +SND_SOC_DAPM_OUTPUT("HP_L"), +SND_SOC_DAPM_OUTPUT("HP_R"), +SND_SOC_DAPM_OUTPUT("SPK_RP"), +SND_SOC_DAPM_OUTPUT("SPK_RN"), +SND_SOC_DAPM_OUTPUT("OUT3"), +}; + +static const struct snd_soc_dapm_route audio_paths[] = { + { "Left Boost Mixer", "LINPUT1 Switch", "LINPUT1" }, + { "Left Boost Mixer", "LINPUT2 Switch", "LINPUT2" }, + { "Left Boost Mixer", "LINPUT3 Switch", "LINPUT3" }, + + { "Left Input Mixer", "Boost Switch", "Left Boost Mixer", }, + { "Left Input Mixer", NULL, "LINPUT1", }, /* Really Boost Switch */ + { "Left Input Mixer", NULL, "LINPUT2" }, + { "Left Input Mixer", NULL, "LINPUT3" }, + + { "Right Boost Mixer", "RINPUT1 Switch", "RINPUT1" }, + { "Right Boost Mixer", "RINPUT2 Switch", "RINPUT2" }, + { "Right Boost Mixer", "RINPUT3 Switch", "RINPUT3" }, + + { "Right Input Mixer", "Boost Switch", "Right Boost Mixer", }, + { "Right Input Mixer", NULL, "RINPUT1", }, /* Really Boost Switch */ + { "Right Input Mixer", NULL, "RINPUT2" }, + { "Right Input Mixer", NULL, "LINPUT3" }, + + { "Left ADC", NULL, "Left Input Mixer" }, + { "Right ADC", NULL, "Right Input Mixer" }, + + { "Left Output Mixer", "LINPUT3 Switch", "LINPUT3" }, + { "Left Output Mixer", "Boost Bypass Switch", "Left Boost Mixer"} , + { "Left Output Mixer", "PCM Playback Switch", "Left DAC" }, + + { "Right Output Mixer", "RINPUT3 Switch", "RINPUT3" }, + { "Right Output Mixer", "Boost Bypass Switch", "Right Boost Mixer" } , + { "Right Output Mixer", "PCM Playback Switch", "Right DAC" }, + + { "Mono Output Mixer", "Left Switch", "Left Output Mixer" }, + { "Mono Output Mixer", "Right Switch", "Right Output Mixer" }, + + { "LOUT1 PGA", NULL, "Left Output Mixer" }, + { "ROUT1 PGA", NULL, "Right Output Mixer" }, + + { "HP_L", NULL, "LOUT1 PGA" }, + { "HP_R", NULL, "ROUT1 PGA" }, + + { "Left Speaker PGA", NULL, "Left Output Mixer" }, + { "Right Speaker PGA", NULL, "Right Output Mixer" }, + + { "Left Speaker Output", NULL, "Left Speaker PGA" }, + { "Right Speaker Output", NULL, "Right Speaker PGA" }, + + { "SPK_LN", NULL, "Left Speaker Output" }, + { "SPK_LP", NULL, "Left Speaker Output" }, + { "SPK_RN", NULL, "Right Speaker Output" }, + { "SPK_RP", NULL, "Right Speaker Output" }, + + { "OUT3", NULL, "Mono Output Mixer", } +}; + +static int wm8960_add_widgets(struct snd_soc_codec *codec) +{ + snd_soc_dapm_new_controls(codec, wm8960_dapm_widgets, + ARRAY_SIZE(wm8960_dapm_widgets)); + + snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths)); + + snd_soc_dapm_new_widgets(codec); + return 0; +} + +static int wm8960_set_dai_fmt(struct snd_soc_dai *codec_dai, + unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + u16 iface = 0; + + /* set master/slave audio interface */ + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + iface |= 0x0040; + break; + case SND_SOC_DAIFMT_CBS_CFS: + break; + default: + return -EINVAL; + } + + /* interface format */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + iface |= 0x0002; + break; + case SND_SOC_DAIFMT_RIGHT_J: + break; + case SND_SOC_DAIFMT_LEFT_J: + iface |= 0x0001; + break; + case SND_SOC_DAIFMT_DSP_A: + iface |= 0x0003; + break; + case SND_SOC_DAIFMT_DSP_B: + iface |= 0x0013; + break; + default: + return -EINVAL; + } + + /* clock inversion */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_IF: + iface |= 0x0090; + break; + case SND_SOC_DAIFMT_IB_NF: + iface |= 0x0080; + break; + case SND_SOC_DAIFMT_NB_IF: + iface |= 0x0010; + break; + default: + return -EINVAL; + } + + /* set iface */ + wm8960_write(codec, WM8960_IFACE1, iface); + return 0; +} + +static int wm8960_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->card->codec; + u16 iface = wm8960_read(codec, WM8960_IFACE1) & 0xfff3; + + /* bit size */ + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + break; + case SNDRV_PCM_FORMAT_S20_3LE: + iface |= 0x0004; + break; + case SNDRV_PCM_FORMAT_S24_LE: + iface |= 0x0008; + break; + } + + /* set iface */ + wm8960_write(codec, WM8960_IFACE1, iface); + return 0; +} + +static int wm8960_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_codec *codec = dai->codec; + u16 mute_reg = wm8960_read(codec, WM8960_DACCTL1) & 0xfff7; + + if (mute) + wm8960_write(codec, WM8960_DACCTL1, mute_reg | 0x8); + else + wm8960_write(codec, WM8960_DACCTL1, mute_reg); + return 0; +} + +static int wm8960_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + struct wm8960_data *pdata = codec->dev->platform_data; + u16 reg; + + switch (level) { + case SND_SOC_BIAS_ON: + break; + + case SND_SOC_BIAS_PREPARE: + /* Set VMID to 2x50k */ + reg = wm8960_read(codec, WM8960_POWER1); + reg &= ~0x180; + reg |= 0x80; + wm8960_write(codec, WM8960_POWER1, reg); + break; + + case SND_SOC_BIAS_STANDBY: + if (codec->bias_level == SND_SOC_BIAS_OFF) { + /* Enable anti-pop features */ + wm8960_write(codec, WM8960_APOP1, + WM8960_POBCTRL | WM8960_SOFT_ST | + WM8960_BUFDCOPEN | WM8960_BUFIOEN); + + /* Discharge HP output */ + reg = WM8960_DISOP; + if (pdata) + reg |= pdata->dres << 4; + wm8960_write(codec, WM8960_APOP2, reg); + + msleep(400); + + wm8960_write(codec, WM8960_APOP2, 0); + + /* Enable & ramp VMID at 2x50k */ + reg = wm8960_read(codec, WM8960_POWER1); + reg |= 0x80; + wm8960_write(codec, WM8960_POWER1, reg); + msleep(100); + + /* Enable VREF */ + wm8960_write(codec, WM8960_POWER1, reg | WM8960_VREF); + + /* Disable anti-pop features */ + wm8960_write(codec, WM8960_APOP1, WM8960_BUFIOEN); + } + + /* Set VMID to 2x250k */ + reg = wm8960_read(codec, WM8960_POWER1); + reg &= ~0x180; + reg |= 0x100; + wm8960_write(codec, WM8960_POWER1, reg); + break; + + case SND_SOC_BIAS_OFF: + /* Enable anti-pop features */ + wm8960_write(codec, WM8960_APOP1, + WM8960_POBCTRL | WM8960_SOFT_ST | + WM8960_BUFDCOPEN | WM8960_BUFIOEN); + + /* Disable VMID and VREF, let them discharge */ + wm8960_write(codec, WM8960_POWER1, 0); + msleep(600); + + wm8960_write(codec, WM8960_APOP1, 0); + break; + } + + codec->bias_level = level; + + return 0; +} + +/* PLL divisors */ +struct _pll_div { + u32 pre_div:1; + u32 n:4; + u32 k:24; +}; + +/* The size in bits of the pll divide multiplied by 10 + * to allow rounding later */ +#define FIXED_PLL_SIZE ((1 << 24) * 10) + +static int pll_factors(unsigned int source, unsigned int target, + struct _pll_div *pll_div) +{ + unsigned long long Kpart; + unsigned int K, Ndiv, Nmod; + + pr_debug("WM8960 PLL: setting %dHz->%dHz\n", source, target); + + /* Scale up target to PLL operating frequency */ + target *= 4; + + Ndiv = target / source; + if (Ndiv < 6) { + source >>= 1; + pll_div->pre_div = 1; + Ndiv = target / source; + } else + pll_div->pre_div = 0; + + if ((Ndiv < 6) || (Ndiv > 12)) { + pr_err("WM8960 PLL: Unsupported N=%d\n", Ndiv); + return -EINVAL; + } + + pll_div->n = Ndiv; + Nmod = target % source; + Kpart = FIXED_PLL_SIZE * (long long)Nmod; + + do_div(Kpart, source); + + K = Kpart & 0xFFFFFFFF; + + /* Check if we need to round */ + if ((K % 10) >= 5) + K += 5; + + /* Move down to proper range now rounding is done */ + K /= 10; + + pll_div->k = K; + + pr_debug("WM8960 PLL: N=%x K=%x pre_div=%d\n", + pll_div->n, pll_div->k, pll_div->pre_div); + + return 0; +} + +static int wm8960_set_dai_pll(struct snd_soc_dai *codec_dai, + int pll_id, unsigned int freq_in, unsigned int freq_out) +{ + struct snd_soc_codec *codec = codec_dai->codec; + u16 reg; + static struct _pll_div pll_div; + int ret; + + if (freq_in && freq_out) { + ret = pll_factors(freq_in, freq_out, &pll_div); + if (ret != 0) + return ret; + } + + /* Disable the PLL: even if we are changing the frequency the + * PLL needs to be disabled while we do so. */ + wm8960_write(codec, WM8960_CLOCK1, + wm8960_read(codec, WM8960_CLOCK1) & ~1); + wm8960_write(codec, WM8960_POWER2, + wm8960_read(codec, WM8960_POWER2) & ~1); + + if (!freq_in || !freq_out) + return 0; + + reg = wm8960_read(codec, WM8960_PLL1) & ~0x3f; + reg |= pll_div.pre_div << 4; + reg |= pll_div.n; + + if (pll_div.k) { + reg |= 0x20; + + wm8960_write(codec, WM8960_PLL2, (pll_div.k >> 18) & 0x3f); + wm8960_write(codec, WM8960_PLL3, (pll_div.k >> 9) & 0x1ff); + wm8960_write(codec, WM8960_PLL4, pll_div.k & 0x1ff); + } + wm8960_write(codec, WM8960_PLL1, reg); + + /* Turn it on */ + wm8960_write(codec, WM8960_POWER2, + wm8960_read(codec, WM8960_POWER2) | 1); + msleep(250); + wm8960_write(codec, WM8960_CLOCK1, + wm8960_read(codec, WM8960_CLOCK1) | 1); + + return 0; +} + +static int wm8960_set_dai_clkdiv(struct snd_soc_dai *codec_dai, + int div_id, int div) +{ + struct snd_soc_codec *codec = codec_dai->codec; + u16 reg; + + switch (div_id) { + case WM8960_SYSCLKSEL: + reg = wm8960_read(codec, WM8960_CLOCK1) & 0x1fe; + wm8960_write(codec, WM8960_CLOCK1, reg | div); + break; + case WM8960_SYSCLKDIV: + reg = wm8960_read(codec, WM8960_CLOCK1) & 0x1f9; + wm8960_write(codec, WM8960_CLOCK1, reg | div); + break; + case WM8960_DACDIV: + reg = wm8960_read(codec, WM8960_CLOCK1) & 0x1c7; + wm8960_write(codec, WM8960_CLOCK1, reg | div); + break; + case WM8960_OPCLKDIV: + reg = wm8960_read(codec, WM8960_PLL1) & 0x03f; + wm8960_write(codec, WM8960_PLL1, reg | div); + break; + case WM8960_DCLKDIV: + reg = wm8960_read(codec, WM8960_CLOCK2) & 0x03f; + wm8960_write(codec, WM8960_CLOCK2, reg | div); + break; + case WM8960_TOCLKSEL: + reg = wm8960_read(codec, WM8960_ADDCTL1) & 0x1fd; + wm8960_write(codec, WM8960_ADDCTL1, reg | div); + break; + default: + return -EINVAL; + } + + return 0; +} + +#define WM8960_RATES SNDRV_PCM_RATE_8000_48000 + +#define WM8960_FORMATS \ + (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE) + +static struct snd_soc_dai_ops wm8960_dai_ops = { + .hw_params = wm8960_hw_params, + .digital_mute = wm8960_mute, + .set_fmt = wm8960_set_dai_fmt, + .set_clkdiv = wm8960_set_dai_clkdiv, + .set_pll = wm8960_set_dai_pll, +}; + +struct snd_soc_dai wm8960_dai = { + .name = "WM8960", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = WM8960_RATES, + .formats = WM8960_FORMATS,}, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = WM8960_RATES, + .formats = WM8960_FORMATS,}, + .ops = &wm8960_dai_ops, + .symmetric_rates = 1, +}; +EXPORT_SYMBOL_GPL(wm8960_dai); + +static int wm8960_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + + wm8960_set_bias_level(codec, SND_SOC_BIAS_OFF); + return 0; +} + +static int wm8960_resume(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + int i; + u8 data[2]; + u16 *cache = codec->reg_cache; + + /* Sync reg_cache with the hardware */ + for (i = 0; i < ARRAY_SIZE(wm8960_reg); i++) { + data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); + data[1] = cache[i] & 0x00ff; + codec->hw_write(codec->control_data, data, 2); + } + + wm8960_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + wm8960_set_bias_level(codec, codec->suspend_bias_level); + return 0; +} + +static struct snd_soc_codec *wm8960_codec; + +static int wm8960_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec; + int ret = 0; + + if (wm8960_codec == NULL) { + dev_err(&pdev->dev, "Codec device not registered\n"); + return -ENODEV; + } + + socdev->card->codec = wm8960_codec; + codec = wm8960_codec; + + /* register pcms */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + dev_err(codec->dev, "failed to create pcms: %d\n", ret); + goto pcm_err; + } + + snd_soc_add_controls(codec, wm8960_snd_controls, + ARRAY_SIZE(wm8960_snd_controls)); + wm8960_add_widgets(codec); + ret = snd_soc_init_card(socdev); + if (ret < 0) { + dev_err(codec->dev, "failed to register card: %d\n", ret); + goto card_err; + } + + return ret; + +card_err: + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); +pcm_err: + return ret; +} + +/* power down chip */ +static int wm8960_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); + + return 0; +} + +struct snd_soc_codec_device soc_codec_dev_wm8960 = { + .probe = wm8960_probe, + .remove = wm8960_remove, + .suspend = wm8960_suspend, + .resume = wm8960_resume, +}; +EXPORT_SYMBOL_GPL(soc_codec_dev_wm8960); + +static int wm8960_register(struct wm8960_priv *wm8960) +{ + struct wm8960_data *pdata = wm8960->codec.dev->platform_data; + struct snd_soc_codec *codec = &wm8960->codec; + int ret; + u16 reg; + + if (wm8960_codec) { + dev_err(codec->dev, "Another WM8960 is registered\n"); + return -EINVAL; + } + + if (!pdata) { + dev_warn(codec->dev, "No platform data supplied\n"); + } else { + if (pdata->dres > WM8960_DRES_MAX) { + dev_err(codec->dev, "Invalid DRES: %d\n", pdata->dres); + pdata->dres = 0; + } + } + + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + + codec->private_data = wm8960; + codec->name = "WM8960"; + codec->owner = THIS_MODULE; + codec->read = wm8960_read_reg_cache; + codec->write = wm8960_write; + codec->bias_level = SND_SOC_BIAS_OFF; + codec->set_bias_level = wm8960_set_bias_level; + codec->dai = &wm8960_dai; + codec->num_dai = 1; + codec->reg_cache_size = WM8960_CACHEREGNUM; + codec->reg_cache = &wm8960->reg_cache; + + memcpy(codec->reg_cache, wm8960_reg, sizeof(wm8960_reg)); + + ret = wm8960_reset(codec); + if (ret < 0) { + dev_err(codec->dev, "Failed to issue reset\n"); + return ret; + } + + wm8960_dai.dev = codec->dev; + + wm8960_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + /* Latch the update bits */ + reg = wm8960_read(codec, WM8960_LINVOL); + wm8960_write(codec, WM8960_LINVOL, reg | 0x100); + reg = wm8960_read(codec, WM8960_RINVOL); + wm8960_write(codec, WM8960_RINVOL, reg | 0x100); + reg = wm8960_read(codec, WM8960_LADC); + wm8960_write(codec, WM8960_LADC, reg | 0x100); + reg = wm8960_read(codec, WM8960_RADC); + wm8960_write(codec, WM8960_RADC, reg | 0x100); + reg = wm8960_read(codec, WM8960_LDAC); + wm8960_write(codec, WM8960_LDAC, reg | 0x100); + reg = wm8960_read(codec, WM8960_RDAC); + wm8960_write(codec, WM8960_RDAC, reg | 0x100); + reg = wm8960_read(codec, WM8960_LOUT1); + wm8960_write(codec, WM8960_LOUT1, reg | 0x100); + reg = wm8960_read(codec, WM8960_ROUT1); + wm8960_write(codec, WM8960_ROUT1, reg | 0x100); + reg = wm8960_read(codec, WM8960_LOUT2); + wm8960_write(codec, WM8960_LOUT2, reg | 0x100); + reg = wm8960_read(codec, WM8960_ROUT2); + wm8960_write(codec, WM8960_ROUT2, reg | 0x100); + + wm8960_codec = codec; + + ret = snd_soc_register_codec(codec); + if (ret != 0) { + dev_err(codec->dev, "Failed to register codec: %d\n", ret); + return ret; + } + + ret = snd_soc_register_dai(&wm8960_dai); + if (ret != 0) { + dev_err(codec->dev, "Failed to register DAI: %d\n", ret); + snd_soc_unregister_codec(codec); + return ret; + } + + return 0; +} + +static void wm8960_unregister(struct wm8960_priv *wm8960) +{ + wm8960_set_bias_level(&wm8960->codec, SND_SOC_BIAS_OFF); + snd_soc_unregister_dai(&wm8960_dai); + snd_soc_unregister_codec(&wm8960->codec); + kfree(wm8960); + wm8960_codec = NULL; +} + +static __devinit int wm8960_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct wm8960_priv *wm8960; + struct snd_soc_codec *codec; + + wm8960 = kzalloc(sizeof(struct wm8960_priv), GFP_KERNEL); + if (wm8960 == NULL) + return -ENOMEM; + + codec = &wm8960->codec; + codec->hw_write = (hw_write_t)i2c_master_send; + + i2c_set_clientdata(i2c, wm8960); + codec->control_data = i2c; + + codec->dev = &i2c->dev; + + return wm8960_register(wm8960); +} + +static __devexit int wm8960_i2c_remove(struct i2c_client *client) +{ + struct wm8960_priv *wm8960 = i2c_get_clientdata(client); + wm8960_unregister(wm8960); + return 0; +} + +static const struct i2c_device_id wm8960_i2c_id[] = { + { "wm8960", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, wm8960_i2c_id); + +static struct i2c_driver wm8960_i2c_driver = { + .driver = { + .name = "WM8960 I2C Codec", + .owner = THIS_MODULE, + }, + .probe = wm8960_i2c_probe, + .remove = __devexit_p(wm8960_i2c_remove), + .id_table = wm8960_i2c_id, +}; + +static int __init wm8960_modinit(void) +{ + int ret; + + ret = i2c_add_driver(&wm8960_i2c_driver); + if (ret != 0) { + printk(KERN_ERR "Failed to register WM8960 I2C driver: %d\n", + ret); + } + + return ret; +} +module_init(wm8960_modinit); + +static void __exit wm8960_exit(void) +{ + i2c_del_driver(&wm8960_i2c_driver); +} +module_exit(wm8960_exit); + + +MODULE_DESCRIPTION("ASoC WM8960 driver"); +MODULE_AUTHOR("Liam Girdwood"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8960.h b/sound/soc/codecs/wm8960.h new file mode 100644 index 000000000000..c9af56c9d9d4 --- /dev/null +++ b/sound/soc/codecs/wm8960.h @@ -0,0 +1,127 @@ +/* + * wm8960.h -- WM8960 Soc Audio driver + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _WM8960_H +#define _WM8960_H + +/* WM8960 register space */ + + +#define WM8960_CACHEREGNUM 56 + +#define WM8960_LINVOL 0x0 +#define WM8960_RINVOL 0x1 +#define WM8960_LOUT1 0x2 +#define WM8960_ROUT1 0x3 +#define WM8960_CLOCK1 0x4 +#define WM8960_DACCTL1 0x5 +#define WM8960_DACCTL2 0x6 +#define WM8960_IFACE1 0x7 +#define WM8960_CLOCK2 0x8 +#define WM8960_IFACE2 0x9 +#define WM8960_LDAC 0xa +#define WM8960_RDAC 0xb + +#define WM8960_RESET 0xf +#define WM8960_3D 0x10 +#define WM8960_ALC1 0x11 +#define WM8960_ALC2 0x12 +#define WM8960_ALC3 0x13 +#define WM8960_NOISEG 0x14 +#define WM8960_LADC 0x15 +#define WM8960_RADC 0x16 +#define WM8960_ADDCTL1 0x17 +#define WM8960_ADDCTL2 0x18 +#define WM8960_POWER1 0x19 +#define WM8960_POWER2 0x1a +#define WM8960_ADDCTL3 0x1b +#define WM8960_APOP1 0x1c +#define WM8960_APOP2 0x1d + +#define WM8960_LINPATH 0x20 +#define WM8960_RINPATH 0x21 +#define WM8960_LOUTMIX 0x22 + +#define WM8960_ROUTMIX 0x25 +#define WM8960_MONOMIX1 0x26 +#define WM8960_MONOMIX2 0x27 +#define WM8960_LOUT2 0x28 +#define WM8960_ROUT2 0x29 +#define WM8960_MONO 0x2a +#define WM8960_INBMIX1 0x2b +#define WM8960_INBMIX2 0x2c +#define WM8960_BYPASS1 0x2d +#define WM8960_BYPASS2 0x2e +#define WM8960_POWER3 0x2f +#define WM8960_ADDCTL4 0x30 +#define WM8960_CLASSD1 0x31 + +#define WM8960_CLASSD3 0x33 +#define WM8960_PLL1 0x34 +#define WM8960_PLL2 0x35 +#define WM8960_PLL3 0x36 +#define WM8960_PLL4 0x37 + + +/* + * WM8960 Clock dividers + */ +#define WM8960_SYSCLKDIV 0 +#define WM8960_DACDIV 1 +#define WM8960_OPCLKDIV 2 +#define WM8960_DCLKDIV 3 +#define WM8960_TOCLKSEL 4 +#define WM8960_SYSCLKSEL 5 + +#define WM8960_SYSCLK_DIV_1 (0 << 1) +#define WM8960_SYSCLK_DIV_2 (2 << 1) + +#define WM8960_SYSCLK_MCLK (0 << 0) +#define WM8960_SYSCLK_PLL (1 << 0) + +#define WM8960_DAC_DIV_1 (0 << 3) +#define WM8960_DAC_DIV_1_5 (1 << 3) +#define WM8960_DAC_DIV_2 (2 << 3) +#define WM8960_DAC_DIV_3 (3 << 3) +#define WM8960_DAC_DIV_4 (4 << 3) +#define WM8960_DAC_DIV_5_5 (5 << 3) +#define WM8960_DAC_DIV_6 (6 << 3) + +#define WM8960_DCLK_DIV_1_5 (0 << 6) +#define WM8960_DCLK_DIV_2 (1 << 6) +#define WM8960_DCLK_DIV_3 (2 << 6) +#define WM8960_DCLK_DIV_4 (3 << 6) +#define WM8960_DCLK_DIV_6 (4 << 6) +#define WM8960_DCLK_DIV_8 (5 << 6) +#define WM8960_DCLK_DIV_12 (6 << 6) +#define WM8960_DCLK_DIV_16 (7 << 6) + +#define WM8960_TOCLK_F19 (0 << 1) +#define WM8960_TOCLK_F21 (1 << 1) + +#define WM8960_OPCLK_DIV_1 (0 << 0) +#define WM8960_OPCLK_DIV_2 (1 << 0) +#define WM8960_OPCLK_DIV_3 (2 << 0) +#define WM8960_OPCLK_DIV_4 (3 << 0) +#define WM8960_OPCLK_DIV_5_5 (4 << 0) +#define WM8960_OPCLK_DIV_6 (5 << 0) + +extern struct snd_soc_dai wm8960_dai; +extern struct snd_soc_codec_device soc_codec_dev_wm8960; + +#define WM8960_DRES_400R 0 +#define WM8960_DRES_200R 1 +#define WM8960_DRES_600R 2 +#define WM8960_DRES_150R 3 +#define WM8960_DRES_MAX 3 + +struct wm8960_data { + int dres; +}; + +#endif diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c new file mode 100644 index 000000000000..c05f71803aa8 --- /dev/null +++ b/sound/soc/codecs/wm8988.c @@ -0,0 +1,1097 @@ +/* + * wm8988.c -- WM8988 ALSA SoC audio driver + * + * Copyright 2009 Wolfson Microelectronics plc + * Copyright 2005 Openedhand Ltd. + * + * Author: Mark Brown + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wm8988.h" + +/* + * wm8988 register cache + * We can't read the WM8988 register space when we + * are using 2 wire for device control, so we cache them instead. + */ +static const u16 wm8988_reg[] = { + 0x0097, 0x0097, 0x0079, 0x0079, /* 0 */ + 0x0000, 0x0008, 0x0000, 0x000a, /* 4 */ + 0x0000, 0x0000, 0x00ff, 0x00ff, /* 8 */ + 0x000f, 0x000f, 0x0000, 0x0000, /* 12 */ + 0x0000, 0x007b, 0x0000, 0x0032, /* 16 */ + 0x0000, 0x00c3, 0x00c3, 0x00c0, /* 20 */ + 0x0000, 0x0000, 0x0000, 0x0000, /* 24 */ + 0x0000, 0x0000, 0x0000, 0x0000, /* 28 */ + 0x0000, 0x0000, 0x0050, 0x0050, /* 32 */ + 0x0050, 0x0050, 0x0050, 0x0050, /* 36 */ + 0x0079, 0x0079, 0x0079, /* 40 */ +}; + +/* codec private data */ +struct wm8988_priv { + unsigned int sysclk; + struct snd_soc_codec codec; + struct snd_pcm_hw_constraint_list *sysclk_constraints; + u16 reg_cache[WM8988_NUM_REG]; +}; + + +/* + * read wm8988 register cache + */ +static inline unsigned int wm8988_read_reg_cache(struct snd_soc_codec *codec, + unsigned int reg) +{ + u16 *cache = codec->reg_cache; + if (reg > WM8988_NUM_REG) + return -1; + return cache[reg]; +} + +/* + * write wm8988 register cache + */ +static inline void wm8988_write_reg_cache(struct snd_soc_codec *codec, + unsigned int reg, unsigned int value) +{ + u16 *cache = codec->reg_cache; + if (reg > WM8988_NUM_REG) + return; + cache[reg] = value; +} + +static int wm8988_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + u8 data[2]; + + /* data is + * D15..D9 WM8753 register offset + * D8...D0 register data + */ + data[0] = (reg << 1) | ((value >> 8) & 0x0001); + data[1] = value & 0x00ff; + + wm8988_write_reg_cache(codec, reg, value); + if (codec->hw_write(codec->control_data, data, 2) == 2) + return 0; + else + return -EIO; +} + +#define wm8988_reset(c) wm8988_write(c, WM8988_RESET, 0) + +/* + * WM8988 Controls + */ + +static const char *bass_boost_txt[] = {"Linear Control", "Adaptive Boost"}; +static const struct soc_enum bass_boost = + SOC_ENUM_SINGLE(WM8988_BASS, 7, 2, bass_boost_txt); + +static const char *bass_filter_txt[] = { "130Hz @ 48kHz", "200Hz @ 48kHz" }; +static const struct soc_enum bass_filter = + SOC_ENUM_SINGLE(WM8988_BASS, 6, 2, bass_filter_txt); + +static const char *treble_txt[] = {"8kHz", "4kHz"}; +static const struct soc_enum treble = + SOC_ENUM_SINGLE(WM8988_TREBLE, 6, 2, treble_txt); + +static const char *stereo_3d_lc_txt[] = {"200Hz", "500Hz"}; +static const struct soc_enum stereo_3d_lc = + SOC_ENUM_SINGLE(WM8988_3D, 5, 2, stereo_3d_lc_txt); + +static const char *stereo_3d_uc_txt[] = {"2.2kHz", "1.5kHz"}; +static const struct soc_enum stereo_3d_uc = + SOC_ENUM_SINGLE(WM8988_3D, 6, 2, stereo_3d_uc_txt); + +static const char *stereo_3d_func_txt[] = {"Capture", "Playback"}; +static const struct soc_enum stereo_3d_func = + SOC_ENUM_SINGLE(WM8988_3D, 7, 2, stereo_3d_func_txt); + +static const char *alc_func_txt[] = {"Off", "Right", "Left", "Stereo"}; +static const struct soc_enum alc_func = + SOC_ENUM_SINGLE(WM8988_ALC1, 7, 4, alc_func_txt); + +static const char *ng_type_txt[] = {"Constant PGA Gain", + "Mute ADC Output"}; +static const struct soc_enum ng_type = + SOC_ENUM_SINGLE(WM8988_NGATE, 1, 2, ng_type_txt); + +static const char *deemph_txt[] = {"None", "32Khz", "44.1Khz", "48Khz"}; +static const struct soc_enum deemph = + SOC_ENUM_SINGLE(WM8988_ADCDAC, 1, 4, deemph_txt); + +static const char *adcpol_txt[] = {"Normal", "L Invert", "R Invert", + "L + R Invert"}; +static const struct soc_enum adcpol = + SOC_ENUM_SINGLE(WM8988_ADCDAC, 5, 4, adcpol_txt); + +static const DECLARE_TLV_DB_SCALE(pga_tlv, -1725, 75, 0); +static const DECLARE_TLV_DB_SCALE(adc_tlv, -9750, 50, 1); +static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1); +static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1); +static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0); + +static const struct snd_kcontrol_new wm8988_snd_controls[] = { + +SOC_ENUM("Bass Boost", bass_boost), +SOC_ENUM("Bass Filter", bass_filter), +SOC_SINGLE("Bass Volume", WM8988_BASS, 0, 15, 1), + +SOC_SINGLE("Treble Volume", WM8988_TREBLE, 0, 15, 0), +SOC_ENUM("Treble Cut-off", treble), + +SOC_SINGLE("3D Switch", WM8988_3D, 0, 1, 0), +SOC_SINGLE("3D Volume", WM8988_3D, 1, 15, 0), +SOC_ENUM("3D Lower Cut-off", stereo_3d_lc), +SOC_ENUM("3D Upper Cut-off", stereo_3d_uc), +SOC_ENUM("3D Mode", stereo_3d_func), + +SOC_SINGLE("ALC Capture Target Volume", WM8988_ALC1, 0, 7, 0), +SOC_SINGLE("ALC Capture Max Volume", WM8988_ALC1, 4, 7, 0), +SOC_ENUM("ALC Capture Function", alc_func), +SOC_SINGLE("ALC Capture ZC Switch", WM8988_ALC2, 7, 1, 0), +SOC_SINGLE("ALC Capture Hold Time", WM8988_ALC2, 0, 15, 0), +SOC_SINGLE("ALC Capture Decay Time", WM8988_ALC3, 4, 15, 0), +SOC_SINGLE("ALC Capture Attack Time", WM8988_ALC3, 0, 15, 0), +SOC_SINGLE("ALC Capture NG Threshold", WM8988_NGATE, 3, 31, 0), +SOC_ENUM("ALC Capture NG Type", ng_type), +SOC_SINGLE("ALC Capture NG Switch", WM8988_NGATE, 0, 1, 0), + +SOC_SINGLE("ZC Timeout Switch", WM8988_ADCTL1, 0, 1, 0), + +SOC_DOUBLE_R_TLV("Capture Digital Volume", WM8988_LADC, WM8988_RADC, + 0, 255, 0, adc_tlv), +SOC_DOUBLE_R_TLV("Capture Volume", WM8988_LINVOL, WM8988_RINVOL, + 0, 63, 0, pga_tlv), +SOC_DOUBLE_R("Capture ZC Switch", WM8988_LINVOL, WM8988_RINVOL, 6, 1, 0), +SOC_DOUBLE_R("Capture Switch", WM8988_LINVOL, WM8988_RINVOL, 7, 1, 1), + +SOC_ENUM("Playback De-emphasis", deemph), + +SOC_ENUM("Capture Polarity", adcpol), +SOC_SINGLE("Playback 6dB Attenuate", WM8988_ADCDAC, 7, 1, 0), +SOC_SINGLE("Capture 6dB Attenuate", WM8988_ADCDAC, 8, 1, 0), + +SOC_DOUBLE_R_TLV("PCM Volume", WM8988_LDAC, WM8988_RDAC, 0, 255, 0, dac_tlv), + +SOC_SINGLE_TLV("Left Mixer Left Bypass Volume", WM8988_LOUTM1, 4, 7, 1, + bypass_tlv), +SOC_SINGLE_TLV("Left Mixer Right Bypass Volume", WM8988_LOUTM2, 4, 7, 1, + bypass_tlv), +SOC_SINGLE_TLV("Right Mixer Left Bypass Volume", WM8988_ROUTM1, 4, 7, 1, + bypass_tlv), +SOC_SINGLE_TLV("Right Mixer Right Bypass Volume", WM8988_ROUTM2, 4, 7, 1, + bypass_tlv), + +SOC_DOUBLE_R("Output 1 Playback ZC Switch", WM8988_LOUT1V, + WM8988_ROUT1V, 7, 1, 0), +SOC_DOUBLE_R_TLV("Output 1 Playback Volume", WM8988_LOUT1V, WM8988_ROUT1V, + 0, 127, 0, out_tlv), + +SOC_DOUBLE_R("Output 2 Playback ZC Switch", WM8988_LOUT2V, + WM8988_ROUT2V, 7, 1, 0), +SOC_DOUBLE_R_TLV("Output 2 Playback Volume", WM8988_LOUT2V, WM8988_ROUT2V, + 0, 127, 0, out_tlv), + +}; + +/* + * DAPM Controls + */ + +static int wm8988_lrc_control(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + u16 adctl2 = wm8988_read_reg_cache(codec, WM8988_ADCTL2); + + /* Use the DAC to gate LRC if active, otherwise use ADC */ + if (wm8988_read_reg_cache(codec, WM8988_PWR2) & 0x180) + adctl2 &= ~0x4; + else + adctl2 |= 0x4; + + return wm8988_write(codec, WM8988_ADCTL2, adctl2); +} + +static const char *wm8988_line_texts[] = { + "Line 1", "Line 2", "PGA", "Differential"}; + +static const unsigned int wm8988_line_values[] = { + 0, 1, 3, 4}; + +static const struct soc_enum wm8988_lline_enum = + SOC_VALUE_ENUM_SINGLE(WM8988_LOUTM1, 0, 7, + ARRAY_SIZE(wm8988_line_texts), + wm8988_line_texts, + wm8988_line_values); +static const struct snd_kcontrol_new wm8988_left_line_controls = + SOC_DAPM_VALUE_ENUM("Route", wm8988_lline_enum); + +static const struct soc_enum wm8988_rline_enum = + SOC_VALUE_ENUM_SINGLE(WM8988_ROUTM1, 0, 7, + ARRAY_SIZE(wm8988_line_texts), + wm8988_line_texts, + wm8988_line_values); +static const struct snd_kcontrol_new wm8988_right_line_controls = + SOC_DAPM_VALUE_ENUM("Route", wm8988_lline_enum); + +/* Left Mixer */ +static const struct snd_kcontrol_new wm8988_left_mixer_controls[] = { + SOC_DAPM_SINGLE("Playback Switch", WM8988_LOUTM1, 8, 1, 0), + SOC_DAPM_SINGLE("Left Bypass Switch", WM8988_LOUTM1, 7, 1, 0), + SOC_DAPM_SINGLE("Right Playback Switch", WM8988_LOUTM2, 8, 1, 0), + SOC_DAPM_SINGLE("Right Bypass Switch", WM8988_LOUTM2, 7, 1, 0), +}; + +/* Right Mixer */ +static const struct snd_kcontrol_new wm8988_right_mixer_controls[] = { + SOC_DAPM_SINGLE("Left Playback Switch", WM8988_ROUTM1, 8, 1, 0), + SOC_DAPM_SINGLE("Left Bypass Switch", WM8988_ROUTM1, 7, 1, 0), + SOC_DAPM_SINGLE("Playback Switch", WM8988_ROUTM2, 8, 1, 0), + SOC_DAPM_SINGLE("Right Bypass Switch", WM8988_ROUTM2, 7, 1, 0), +}; + +static const char *wm8988_pga_sel[] = {"Line 1", "Line 2", "Differential"}; +static const unsigned int wm8988_pga_val[] = { 0, 1, 3 }; + +/* Left PGA Mux */ +static const struct soc_enum wm8988_lpga_enum = + SOC_VALUE_ENUM_SINGLE(WM8988_LADCIN, 6, 3, + ARRAY_SIZE(wm8988_pga_sel), + wm8988_pga_sel, + wm8988_pga_val); +static const struct snd_kcontrol_new wm8988_left_pga_controls = + SOC_DAPM_VALUE_ENUM("Route", wm8988_lpga_enum); + +/* Right PGA Mux */ +static const struct soc_enum wm8988_rpga_enum = + SOC_VALUE_ENUM_SINGLE(WM8988_RADCIN, 6, 3, + ARRAY_SIZE(wm8988_pga_sel), + wm8988_pga_sel, + wm8988_pga_val); +static const struct snd_kcontrol_new wm8988_right_pga_controls = + SOC_DAPM_VALUE_ENUM("Route", wm8988_rpga_enum); + +/* Differential Mux */ +static const char *wm8988_diff_sel[] = {"Line 1", "Line 2"}; +static const struct soc_enum diffmux = + SOC_ENUM_SINGLE(WM8988_ADCIN, 8, 2, wm8988_diff_sel); +static const struct snd_kcontrol_new wm8988_diffmux_controls = + SOC_DAPM_ENUM("Route", diffmux); + +/* Mono ADC Mux */ +static const char *wm8988_mono_mux[] = {"Stereo", "Mono (Left)", + "Mono (Right)", "Digital Mono"}; +static const struct soc_enum monomux = + SOC_ENUM_SINGLE(WM8988_ADCIN, 6, 4, wm8988_mono_mux); +static const struct snd_kcontrol_new wm8988_monomux_controls = + SOC_DAPM_ENUM("Route", monomux); + +static const struct snd_soc_dapm_widget wm8988_dapm_widgets[] = { + SND_SOC_DAPM_MICBIAS("Mic Bias", WM8988_PWR1, 1, 0), + + SND_SOC_DAPM_MUX("Differential Mux", SND_SOC_NOPM, 0, 0, + &wm8988_diffmux_controls), + SND_SOC_DAPM_MUX("Left ADC Mux", SND_SOC_NOPM, 0, 0, + &wm8988_monomux_controls), + SND_SOC_DAPM_MUX("Right ADC Mux", SND_SOC_NOPM, 0, 0, + &wm8988_monomux_controls), + + SND_SOC_DAPM_MUX("Left PGA Mux", WM8988_PWR1, 5, 0, + &wm8988_left_pga_controls), + SND_SOC_DAPM_MUX("Right PGA Mux", WM8988_PWR1, 4, 0, + &wm8988_right_pga_controls), + + SND_SOC_DAPM_MUX("Left Line Mux", SND_SOC_NOPM, 0, 0, + &wm8988_left_line_controls), + SND_SOC_DAPM_MUX("Right Line Mux", SND_SOC_NOPM, 0, 0, + &wm8988_right_line_controls), + + SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8988_PWR1, 2, 0), + SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8988_PWR1, 3, 0), + + SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8988_PWR2, 7, 0), + SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8988_PWR2, 8, 0), + + SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0, + &wm8988_left_mixer_controls[0], + ARRAY_SIZE(wm8988_left_mixer_controls)), + SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0, + &wm8988_right_mixer_controls[0], + ARRAY_SIZE(wm8988_right_mixer_controls)), + + SND_SOC_DAPM_PGA("Right Out 2", WM8988_PWR2, 3, 0, NULL, 0), + SND_SOC_DAPM_PGA("Left Out 2", WM8988_PWR2, 4, 0, NULL, 0), + SND_SOC_DAPM_PGA("Right Out 1", WM8988_PWR2, 5, 0, NULL, 0), + SND_SOC_DAPM_PGA("Left Out 1", WM8988_PWR2, 6, 0, NULL, 0), + + SND_SOC_DAPM_POST("LRC control", wm8988_lrc_control), + + SND_SOC_DAPM_OUTPUT("LOUT1"), + SND_SOC_DAPM_OUTPUT("ROUT1"), + SND_SOC_DAPM_OUTPUT("LOUT2"), + SND_SOC_DAPM_OUTPUT("ROUT2"), + SND_SOC_DAPM_OUTPUT("VREF"), + + SND_SOC_DAPM_INPUT("LINPUT1"), + SND_SOC_DAPM_INPUT("LINPUT2"), + SND_SOC_DAPM_INPUT("RINPUT1"), + SND_SOC_DAPM_INPUT("RINPUT2"), +}; + +static const struct snd_soc_dapm_route audio_map[] = { + + { "Left Line Mux", "Line 1", "LINPUT1" }, + { "Left Line Mux", "Line 2", "LINPUT2" }, + { "Left Line Mux", "PGA", "Left PGA Mux" }, + { "Left Line Mux", "Differential", "Differential Mux" }, + + { "Right Line Mux", "Line 1", "RINPUT1" }, + { "Right Line Mux", "Line 2", "RINPUT2" }, + { "Right Line Mux", "PGA", "Right PGA Mux" }, + { "Right Line Mux", "Differential", "Differential Mux" }, + + { "Left PGA Mux", "Line 1", "LINPUT1" }, + { "Left PGA Mux", "Line 2", "LINPUT2" }, + { "Left PGA Mux", "Differential", "Differential Mux" }, + + { "Right PGA Mux", "Line 1", "RINPUT1" }, + { "Right PGA Mux", "Line 2", "RINPUT2" }, + { "Right PGA Mux", "Differential", "Differential Mux" }, + + { "Differential Mux", "Line 1", "LINPUT1" }, + { "Differential Mux", "Line 1", "RINPUT1" }, + { "Differential Mux", "Line 2", "LINPUT2" }, + { "Differential Mux", "Line 2", "RINPUT2" }, + + { "Left ADC Mux", "Stereo", "Left PGA Mux" }, + { "Left ADC Mux", "Mono (Left)", "Left PGA Mux" }, + { "Left ADC Mux", "Digital Mono", "Left PGA Mux" }, + + { "Right ADC Mux", "Stereo", "Right PGA Mux" }, + { "Right ADC Mux", "Mono (Right)", "Right PGA Mux" }, + { "Right ADC Mux", "Digital Mono", "Right PGA Mux" }, + + { "Left ADC", NULL, "Left ADC Mux" }, + { "Right ADC", NULL, "Right ADC Mux" }, + + { "Left Line Mux", "Line 1", "LINPUT1" }, + { "Left Line Mux", "Line 2", "LINPUT2" }, + { "Left Line Mux", "PGA", "Left PGA Mux" }, + { "Left Line Mux", "Differential", "Differential Mux" }, + + { "Right Line Mux", "Line 1", "RINPUT1" }, + { "Right Line Mux", "Line 2", "RINPUT2" }, + { "Right Line Mux", "PGA", "Right PGA Mux" }, + { "Right Line Mux", "Differential", "Differential Mux" }, + + { "Left Mixer", "Playback Switch", "Left DAC" }, + { "Left Mixer", "Left Bypass Switch", "Left Line Mux" }, + { "Left Mixer", "Right Playback Switch", "Right DAC" }, + { "Left Mixer", "Right Bypass Switch", "Right Line Mux" }, + + { "Right Mixer", "Left Playback Switch", "Left DAC" }, + { "Right Mixer", "Left Bypass Switch", "Left Line Mux" }, + { "Right Mixer", "Playback Switch", "Right DAC" }, + { "Right Mixer", "Right Bypass Switch", "Right Line Mux" }, + + { "Left Out 1", NULL, "Left Mixer" }, + { "LOUT1", NULL, "Left Out 1" }, + { "Right Out 1", NULL, "Right Mixer" }, + { "ROUT1", NULL, "Right Out 1" }, + + { "Left Out 2", NULL, "Left Mixer" }, + { "LOUT2", NULL, "Left Out 2" }, + { "Right Out 2", NULL, "Right Mixer" }, + { "ROUT2", NULL, "Right Out 2" }, +}; + +struct _coeff_div { + u32 mclk; + u32 rate; + u16 fs; + u8 sr:5; + u8 usb:1; +}; + +/* codec hifi mclk clock divider coefficients */ +static const struct _coeff_div coeff_div[] = { + /* 8k */ + {12288000, 8000, 1536, 0x6, 0x0}, + {11289600, 8000, 1408, 0x16, 0x0}, + {18432000, 8000, 2304, 0x7, 0x0}, + {16934400, 8000, 2112, 0x17, 0x0}, + {12000000, 8000, 1500, 0x6, 0x1}, + + /* 11.025k */ + {11289600, 11025, 1024, 0x18, 0x0}, + {16934400, 11025, 1536, 0x19, 0x0}, + {12000000, 11025, 1088, 0x19, 0x1}, + + /* 16k */ + {12288000, 16000, 768, 0xa, 0x0}, + {18432000, 16000, 1152, 0xb, 0x0}, + {12000000, 16000, 750, 0xa, 0x1}, + + /* 22.05k */ + {11289600, 22050, 512, 0x1a, 0x0}, + {16934400, 22050, 768, 0x1b, 0x0}, + {12000000, 22050, 544, 0x1b, 0x1}, + + /* 32k */ + {12288000, 32000, 384, 0xc, 0x0}, + {18432000, 32000, 576, 0xd, 0x0}, + {12000000, 32000, 375, 0xa, 0x1}, + + /* 44.1k */ + {11289600, 44100, 256, 0x10, 0x0}, + {16934400, 44100, 384, 0x11, 0x0}, + {12000000, 44100, 272, 0x11, 0x1}, + + /* 48k */ + {12288000, 48000, 256, 0x0, 0x0}, + {18432000, 48000, 384, 0x1, 0x0}, + {12000000, 48000, 250, 0x0, 0x1}, + + /* 88.2k */ + {11289600, 88200, 128, 0x1e, 0x0}, + {16934400, 88200, 192, 0x1f, 0x0}, + {12000000, 88200, 136, 0x1f, 0x1}, + + /* 96k */ + {12288000, 96000, 128, 0xe, 0x0}, + {18432000, 96000, 192, 0xf, 0x0}, + {12000000, 96000, 125, 0xe, 0x1}, +}; + +static inline int get_coeff(int mclk, int rate) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(coeff_div); i++) { + if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk) + return i; + } + + return -EINVAL; +} + +/* The set of rates we can generate from the above for each SYSCLK */ + +static unsigned int rates_12288[] = { + 8000, 12000, 16000, 24000, 24000, 32000, 48000, 96000, +}; + +static struct snd_pcm_hw_constraint_list constraints_12288 = { + .count = ARRAY_SIZE(rates_12288), + .list = rates_12288, +}; + +static unsigned int rates_112896[] = { + 8000, 11025, 22050, 44100, +}; + +static struct snd_pcm_hw_constraint_list constraints_112896 = { + .count = ARRAY_SIZE(rates_112896), + .list = rates_112896, +}; + +static unsigned int rates_12[] = { + 8000, 11025, 12000, 16000, 22050, 2400, 32000, 41100, 48000, + 48000, 88235, 96000, +}; + +static struct snd_pcm_hw_constraint_list constraints_12 = { + .count = ARRAY_SIZE(rates_12), + .list = rates_12, +}; + +/* + * Note that this should be called from init rather than from hw_params. + */ +static int wm8988_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct wm8988_priv *wm8988 = codec->private_data; + + switch (freq) { + case 11289600: + case 18432000: + case 22579200: + case 36864000: + wm8988->sysclk_constraints = &constraints_112896; + wm8988->sysclk = freq; + return 0; + + case 12288000: + case 16934400: + case 24576000: + case 33868800: + wm8988->sysclk_constraints = &constraints_12288; + wm8988->sysclk = freq; + return 0; + + case 12000000: + case 24000000: + wm8988->sysclk_constraints = &constraints_12; + wm8988->sysclk = freq; + return 0; + } + return -EINVAL; +} + +static int wm8988_set_dai_fmt(struct snd_soc_dai *codec_dai, + unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + u16 iface = 0; + + /* set master/slave audio interface */ + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + iface = 0x0040; + break; + case SND_SOC_DAIFMT_CBS_CFS: + break; + default: + return -EINVAL; + } + + /* interface format */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + iface |= 0x0002; + break; + case SND_SOC_DAIFMT_RIGHT_J: + break; + case SND_SOC_DAIFMT_LEFT_J: + iface |= 0x0001; + break; + case SND_SOC_DAIFMT_DSP_A: + iface |= 0x0003; + break; + case SND_SOC_DAIFMT_DSP_B: + iface |= 0x0013; + break; + default: + return -EINVAL; + } + + /* clock inversion */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_IF: + iface |= 0x0090; + break; + case SND_SOC_DAIFMT_IB_NF: + iface |= 0x0080; + break; + case SND_SOC_DAIFMT_NB_IF: + iface |= 0x0010; + break; + default: + return -EINVAL; + } + + wm8988_write(codec, WM8988_IFACE, iface); + return 0; +} + +static int wm8988_pcm_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct wm8988_priv *wm8988 = codec->private_data; + + /* The set of sample rates that can be supported depends on the + * MCLK supplied to the CODEC - enforce this. + */ + if (!wm8988->sysclk) { + dev_err(codec->dev, + "No MCLK configured, call set_sysclk() on init\n"); + return -EINVAL; + } + + snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + wm8988->sysclk_constraints); + + return 0; +} + +static int wm8988_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->card->codec; + struct wm8988_priv *wm8988 = codec->private_data; + u16 iface = wm8988_read_reg_cache(codec, WM8988_IFACE) & 0x1f3; + u16 srate = wm8988_read_reg_cache(codec, WM8988_SRATE) & 0x180; + int coeff; + + coeff = get_coeff(wm8988->sysclk, params_rate(params)); + if (coeff < 0) { + coeff = get_coeff(wm8988->sysclk / 2, params_rate(params)); + srate |= 0x40; + } + if (coeff < 0) { + dev_err(codec->dev, + "Unable to configure sample rate %dHz with %dHz MCLK\n", + params_rate(params), wm8988->sysclk); + return coeff; + } + + /* bit size */ + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + break; + case SNDRV_PCM_FORMAT_S20_3LE: + iface |= 0x0004; + break; + case SNDRV_PCM_FORMAT_S24_LE: + iface |= 0x0008; + break; + case SNDRV_PCM_FORMAT_S32_LE: + iface |= 0x000c; + break; + } + + /* set iface & srate */ + wm8988_write(codec, WM8988_IFACE, iface); + if (coeff >= 0) + wm8988_write(codec, WM8988_SRATE, srate | + (coeff_div[coeff].sr << 1) | coeff_div[coeff].usb); + + return 0; +} + +static int wm8988_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_codec *codec = dai->codec; + u16 mute_reg = wm8988_read_reg_cache(codec, WM8988_ADCDAC) & 0xfff7; + + if (mute) + wm8988_write(codec, WM8988_ADCDAC, mute_reg | 0x8); + else + wm8988_write(codec, WM8988_ADCDAC, mute_reg); + return 0; +} + +static int wm8988_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + u16 pwr_reg = wm8988_read_reg_cache(codec, WM8988_PWR1) & ~0x1c1; + + switch (level) { + case SND_SOC_BIAS_ON: + break; + + case SND_SOC_BIAS_PREPARE: + /* VREF, VMID=2x50k, digital enabled */ + wm8988_write(codec, WM8988_PWR1, pwr_reg | 0x00c0); + break; + + case SND_SOC_BIAS_STANDBY: + if (codec->bias_level == SND_SOC_BIAS_OFF) { + /* VREF, VMID=2x5k */ + wm8988_write(codec, WM8988_PWR1, pwr_reg | 0x1c1); + + /* Charge caps */ + msleep(100); + } + + /* VREF, VMID=2*500k, digital stopped */ + wm8988_write(codec, WM8988_PWR1, pwr_reg | 0x0141); + break; + + case SND_SOC_BIAS_OFF: + wm8988_write(codec, WM8988_PWR1, 0x0000); + break; + } + codec->bias_level = level; + return 0; +} + +#define WM8988_RATES SNDRV_PCM_RATE_8000_96000 + +#define WM8988_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ + SNDRV_PCM_FMTBIT_S24_LE) + +static struct snd_soc_dai_ops wm8988_ops = { + .startup = wm8988_pcm_startup, + .hw_params = wm8988_pcm_hw_params, + .set_fmt = wm8988_set_dai_fmt, + .set_sysclk = wm8988_set_dai_sysclk, + .digital_mute = wm8988_mute, +}; + +struct snd_soc_dai wm8988_dai = { + .name = "WM8988", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = WM8988_RATES, + .formats = WM8988_FORMATS, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = WM8988_RATES, + .formats = WM8988_FORMATS, + }, + .ops = &wm8988_ops, + .symmetric_rates = 1, +}; +EXPORT_SYMBOL_GPL(wm8988_dai); + +static int wm8988_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + + wm8988_set_bias_level(codec, SND_SOC_BIAS_OFF); + return 0; +} + +static int wm8988_resume(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + int i; + u8 data[2]; + u16 *cache = codec->reg_cache; + + /* Sync reg_cache with the hardware */ + for (i = 0; i < WM8988_NUM_REG; i++) { + if (i == WM8988_RESET) + continue; + data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); + data[1] = cache[i] & 0x00ff; + codec->hw_write(codec->control_data, data, 2); + } + + wm8988_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + return 0; +} + +static struct snd_soc_codec *wm8988_codec; + +static int wm8988_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec; + int ret = 0; + + if (wm8988_codec == NULL) { + dev_err(&pdev->dev, "Codec device not registered\n"); + return -ENODEV; + } + + socdev->card->codec = wm8988_codec; + codec = wm8988_codec; + + /* register pcms */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + dev_err(codec->dev, "failed to create pcms: %d\n", ret); + goto pcm_err; + } + + snd_soc_add_controls(codec, wm8988_snd_controls, + ARRAY_SIZE(wm8988_snd_controls)); + snd_soc_dapm_new_controls(codec, wm8988_dapm_widgets, + ARRAY_SIZE(wm8988_dapm_widgets)); + snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); + snd_soc_dapm_new_widgets(codec); + + ret = snd_soc_init_card(socdev); + if (ret < 0) { + dev_err(codec->dev, "failed to register card: %d\n", ret); + goto card_err; + } + + return ret; + +card_err: + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); +pcm_err: + return ret; +} + +static int wm8988_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); + + return 0; +} + +struct snd_soc_codec_device soc_codec_dev_wm8988 = { + .probe = wm8988_probe, + .remove = wm8988_remove, + .suspend = wm8988_suspend, + .resume = wm8988_resume, +}; +EXPORT_SYMBOL_GPL(soc_codec_dev_wm8988); + +static int wm8988_register(struct wm8988_priv *wm8988) +{ + struct snd_soc_codec *codec = &wm8988->codec; + int ret; + u16 reg; + + if (wm8988_codec) { + dev_err(codec->dev, "Another WM8988 is registered\n"); + ret = -EINVAL; + goto err; + } + + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + + codec->private_data = wm8988; + codec->name = "WM8988"; + codec->owner = THIS_MODULE; + codec->read = wm8988_read_reg_cache; + codec->write = wm8988_write; + codec->dai = &wm8988_dai; + codec->num_dai = 1; + codec->reg_cache_size = ARRAY_SIZE(wm8988->reg_cache); + codec->reg_cache = &wm8988->reg_cache; + codec->bias_level = SND_SOC_BIAS_OFF; + codec->set_bias_level = wm8988_set_bias_level; + + memcpy(codec->reg_cache, wm8988_reg, + sizeof(wm8988_reg)); + + ret = wm8988_reset(codec); + if (ret < 0) { + dev_err(codec->dev, "Failed to issue reset\n"); + return ret; + } + + /* set the update bits (we always update left then right) */ + reg = wm8988_read_reg_cache(codec, WM8988_RADC); + wm8988_write(codec, WM8988_RADC, reg | 0x100); + reg = wm8988_read_reg_cache(codec, WM8988_RDAC); + wm8988_write(codec, WM8988_RDAC, reg | 0x0100); + reg = wm8988_read_reg_cache(codec, WM8988_ROUT1V); + wm8988_write(codec, WM8988_ROUT1V, reg | 0x0100); + reg = wm8988_read_reg_cache(codec, WM8988_ROUT2V); + wm8988_write(codec, WM8988_ROUT2V, reg | 0x0100); + reg = wm8988_read_reg_cache(codec, WM8988_RINVOL); + wm8988_write(codec, WM8988_RINVOL, reg | 0x0100); + + wm8988_set_bias_level(&wm8988->codec, SND_SOC_BIAS_STANDBY); + + wm8988_dai.dev = codec->dev; + + wm8988_codec = codec; + + ret = snd_soc_register_codec(codec); + if (ret != 0) { + dev_err(codec->dev, "Failed to register codec: %d\n", ret); + return ret; + } + + ret = snd_soc_register_dai(&wm8988_dai); + if (ret != 0) { + dev_err(codec->dev, "Failed to register DAI: %d\n", ret); + snd_soc_unregister_codec(codec); + return ret; + } + + return 0; + +err: + kfree(wm8988); + return ret; +} + +static void wm8988_unregister(struct wm8988_priv *wm8988) +{ + wm8988_set_bias_level(&wm8988->codec, SND_SOC_BIAS_OFF); + snd_soc_unregister_dai(&wm8988_dai); + snd_soc_unregister_codec(&wm8988->codec); + kfree(wm8988); + wm8988_codec = NULL; +} + +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +static int wm8988_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct wm8988_priv *wm8988; + struct snd_soc_codec *codec; + + wm8988 = kzalloc(sizeof(struct wm8988_priv), GFP_KERNEL); + if (wm8988 == NULL) + return -ENOMEM; + + codec = &wm8988->codec; + codec->hw_write = (hw_write_t)i2c_master_send; + + i2c_set_clientdata(i2c, wm8988); + codec->control_data = i2c; + + codec->dev = &i2c->dev; + + return wm8988_register(wm8988); +} + +static int wm8988_i2c_remove(struct i2c_client *client) +{ + struct wm8988_priv *wm8988 = i2c_get_clientdata(client); + wm8988_unregister(wm8988); + return 0; +} + +static const struct i2c_device_id wm8988_i2c_id[] = { + { "wm8988", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, wm8988_i2c_id); + +static struct i2c_driver wm8988_i2c_driver = { + .driver = { + .name = "WM8988", + .owner = THIS_MODULE, + }, + .probe = wm8988_i2c_probe, + .remove = wm8988_i2c_remove, + .id_table = wm8988_i2c_id, +}; +#endif + +#if defined(CONFIG_SPI_MASTER) +static int wm8988_spi_write(struct spi_device *spi, const char *data, int len) +{ + struct spi_transfer t; + struct spi_message m; + u8 msg[2]; + + if (len <= 0) + return 0; + + msg[0] = data[0]; + msg[1] = data[1]; + + spi_message_init(&m); + memset(&t, 0, (sizeof t)); + + t.tx_buf = &msg[0]; + t.len = len; + + spi_message_add_tail(&t, &m); + spi_sync(spi, &m); + + return len; +} + +static int __devinit wm8988_spi_probe(struct spi_device *spi) +{ + struct wm8988_priv *wm8988; + struct snd_soc_codec *codec; + + wm8988 = kzalloc(sizeof(struct wm8988_priv), GFP_KERNEL); + if (wm8988 == NULL) + return -ENOMEM; + + codec = &wm8988->codec; + codec->hw_write = (hw_write_t)wm8988_spi_write; + codec->control_data = spi; + codec->dev = &spi->dev; + + spi->dev.driver_data = wm8988; + + return wm8988_register(wm8988); +} + +static int __devexit wm8988_spi_remove(struct spi_device *spi) +{ + struct wm8988_priv *wm8988 = spi->dev.driver_data; + + wm8988_unregister(wm8988); + + return 0; +} + +static struct spi_driver wm8988_spi_driver = { + .driver = { + .name = "wm8988", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = wm8988_spi_probe, + .remove = __devexit_p(wm8988_spi_remove), +}; +#endif + +static int __init wm8988_modinit(void) +{ + int ret; + +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + ret = i2c_add_driver(&wm8988_i2c_driver); + if (ret != 0) + pr_err("WM8988: Unable to register I2C driver: %d\n", ret); +#endif +#if defined(CONFIG_SPI_MASTER) + ret = spi_register_driver(&wm8988_spi_driver); + if (ret != 0) + pr_err("WM8988: Unable to register SPI driver: %d\n", ret); +#endif + return ret; +} +module_init(wm8988_modinit); + +static void __exit wm8988_exit(void) +{ +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + i2c_del_driver(&wm8988_i2c_driver); +#endif +#if defined(CONFIG_SPI_MASTER) + spi_unregister_driver(&wm8988_spi_driver); +#endif +} +module_exit(wm8988_exit); + + +MODULE_DESCRIPTION("ASoC WM8988 driver"); +MODULE_AUTHOR("Mark Brown "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8988.h b/sound/soc/codecs/wm8988.h new file mode 100644 index 000000000000..4552d37fdd41 --- /dev/null +++ b/sound/soc/codecs/wm8988.h @@ -0,0 +1,60 @@ +/* + * Copyright 2005 Openedhand Ltd. + * + * Author: Richard Purdie + * + * Based on WM8753.h + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#ifndef _WM8988_H +#define _WM8988_H + +/* WM8988 register space */ + +#define WM8988_LINVOL 0x00 +#define WM8988_RINVOL 0x01 +#define WM8988_LOUT1V 0x02 +#define WM8988_ROUT1V 0x03 +#define WM8988_ADCDAC 0x05 +#define WM8988_IFACE 0x07 +#define WM8988_SRATE 0x08 +#define WM8988_LDAC 0x0a +#define WM8988_RDAC 0x0b +#define WM8988_BASS 0x0c +#define WM8988_TREBLE 0x0d +#define WM8988_RESET 0x0f +#define WM8988_3D 0x10 +#define WM8988_ALC1 0x11 +#define WM8988_ALC2 0x12 +#define WM8988_ALC3 0x13 +#define WM8988_NGATE 0x14 +#define WM8988_LADC 0x15 +#define WM8988_RADC 0x16 +#define WM8988_ADCTL1 0x17 +#define WM8988_ADCTL2 0x18 +#define WM8988_PWR1 0x19 +#define WM8988_PWR2 0x1a +#define WM8988_ADCTL3 0x1b +#define WM8988_ADCIN 0x1f +#define WM8988_LADCIN 0x20 +#define WM8988_RADCIN 0x21 +#define WM8988_LOUTM1 0x22 +#define WM8988_LOUTM2 0x23 +#define WM8988_ROUTM1 0x24 +#define WM8988_ROUTM2 0x25 +#define WM8988_LOUT2V 0x28 +#define WM8988_ROUT2V 0x29 +#define WM8988_LPPB 0x43 +#define WM8988_NUM_REG 0x44 + +#define WM8988_SYSCLK 0 + +extern struct snd_soc_dai wm8988_dai; +extern struct snd_soc_codec_device soc_codec_dev_wm8988; + +#endif diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index 40cd274eb1ef..d029818350e9 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c @@ -998,7 +998,7 @@ static void pll_factors(struct _pll_div *pll_div, unsigned int target, if ((Ndiv < 6) || (Ndiv > 12)) printk(KERN_WARNING - "WM8990 N value outwith recommended range! N = %d\n", Ndiv); + "WM8990 N value outwith recommended range! N = %u\n", Ndiv); pll_div->n = Ndiv; Nmod = target % source; diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c new file mode 100644 index 000000000000..86fc57e25f97 --- /dev/null +++ b/sound/soc/codecs/wm9081.c @@ -0,0 +1,1534 @@ +/* + * wm9081.c -- WM9081 ALSA SoC Audio driver + * + * Author: Mark Brown + * + * Copyright 2009 Wolfson Microelectronics plc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "wm9081.h" + +static u16 wm9081_reg_defaults[] = { + 0x0000, /* R0 - Software Reset */ + 0x0000, /* R1 */ + 0x00B9, /* R2 - Analogue Lineout */ + 0x00B9, /* R3 - Analogue Speaker PGA */ + 0x0001, /* R4 - VMID Control */ + 0x0068, /* R5 - Bias Control 1 */ + 0x0000, /* R6 */ + 0x0000, /* R7 - Analogue Mixer */ + 0x0000, /* R8 - Anti Pop Control */ + 0x01DB, /* R9 - Analogue Speaker 1 */ + 0x0018, /* R10 - Analogue Speaker 2 */ + 0x0180, /* R11 - Power Management */ + 0x0000, /* R12 - Clock Control 1 */ + 0x0038, /* R13 - Clock Control 2 */ + 0x4000, /* R14 - Clock Control 3 */ + 0x0000, /* R15 */ + 0x0000, /* R16 - FLL Control 1 */ + 0x0200, /* R17 - FLL Control 2 */ + 0x0000, /* R18 - FLL Control 3 */ + 0x0204, /* R19 - FLL Control 4 */ + 0x0000, /* R20 - FLL Control 5 */ + 0x0000, /* R21 */ + 0x0000, /* R22 - Audio Interface 1 */ + 0x0002, /* R23 - Audio Interface 2 */ + 0x0008, /* R24 - Audio Interface 3 */ + 0x0022, /* R25 - Audio Interface 4 */ + 0x0000, /* R26 - Interrupt Status */ + 0x0006, /* R27 - Interrupt Status Mask */ + 0x0000, /* R28 - Interrupt Polarity */ + 0x0000, /* R29 - Interrupt Control */ + 0x00C0, /* R30 - DAC Digital 1 */ + 0x0008, /* R31 - DAC Digital 2 */ + 0x09AF, /* R32 - DRC 1 */ + 0x4201, /* R33 - DRC 2 */ + 0x0000, /* R34 - DRC 3 */ + 0x0000, /* R35 - DRC 4 */ + 0x0000, /* R36 */ + 0x0000, /* R37 */ + 0x0000, /* R38 - Write Sequencer 1 */ + 0x0000, /* R39 - Write Sequencer 2 */ + 0x0002, /* R40 - MW Slave 1 */ + 0x0000, /* R41 */ + 0x0000, /* R42 - EQ 1 */ + 0x0000, /* R43 - EQ 2 */ + 0x0FCA, /* R44 - EQ 3 */ + 0x0400, /* R45 - EQ 4 */ + 0x00B8, /* R46 - EQ 5 */ + 0x1EB5, /* R47 - EQ 6 */ + 0xF145, /* R48 - EQ 7 */ + 0x0B75, /* R49 - EQ 8 */ + 0x01C5, /* R50 - EQ 9 */ + 0x169E, /* R51 - EQ 10 */ + 0xF829, /* R52 - EQ 11 */ + 0x07AD, /* R53 - EQ 12 */ + 0x1103, /* R54 - EQ 13 */ + 0x1C58, /* R55 - EQ 14 */ + 0xF373, /* R56 - EQ 15 */ + 0x0A54, /* R57 - EQ 16 */ + 0x0558, /* R58 - EQ 17 */ + 0x0564, /* R59 - EQ 18 */ + 0x0559, /* R60 - EQ 19 */ + 0x4000, /* R61 - EQ 20 */ +}; + +static struct { + int ratio; + int clk_sys_rate; +} clk_sys_rates[] = { + { 64, 0 }, + { 128, 1 }, + { 192, 2 }, + { 256, 3 }, + { 384, 4 }, + { 512, 5 }, + { 768, 6 }, + { 1024, 7 }, + { 1408, 8 }, + { 1536, 9 }, +}; + +static struct { + int rate; + int sample_rate; +} sample_rates[] = { + { 8000, 0 }, + { 11025, 1 }, + { 12000, 2 }, + { 16000, 3 }, + { 22050, 4 }, + { 24000, 5 }, + { 32000, 6 }, + { 44100, 7 }, + { 48000, 8 }, + { 88200, 9 }, + { 96000, 10 }, +}; + +static struct { + int div; /* *10 due to .5s */ + int bclk_div; +} bclk_divs[] = { + { 10, 0 }, + { 15, 1 }, + { 20, 2 }, + { 30, 3 }, + { 40, 4 }, + { 50, 5 }, + { 55, 6 }, + { 60, 7 }, + { 80, 8 }, + { 100, 9 }, + { 110, 10 }, + { 120, 11 }, + { 160, 12 }, + { 200, 13 }, + { 220, 14 }, + { 240, 15 }, + { 250, 16 }, + { 300, 17 }, + { 320, 18 }, + { 440, 19 }, + { 480, 20 }, +}; + +struct wm9081_priv { + struct snd_soc_codec codec; + u16 reg_cache[WM9081_MAX_REGISTER + 1]; + int sysclk_source; + int mclk_rate; + int sysclk_rate; + int fs; + int bclk; + int master; + int fll_fref; + int fll_fout; + struct wm9081_retune_mobile_config *retune; +}; + +static int wm9081_reg_is_volatile(int reg) +{ + switch (reg) { + default: + return 0; + } +} + +static unsigned int wm9081_read_reg_cache(struct snd_soc_codec *codec, + unsigned int reg) +{ + u16 *cache = codec->reg_cache; + BUG_ON(reg > WM9081_MAX_REGISTER); + return cache[reg]; +} + +static unsigned int wm9081_read_hw(struct snd_soc_codec *codec, u8 reg) +{ + struct i2c_msg xfer[2]; + u16 data; + int ret; + struct i2c_client *client = codec->control_data; + + BUG_ON(reg > WM9081_MAX_REGISTER); + + /* Write register */ + xfer[0].addr = client->addr; + xfer[0].flags = 0; + xfer[0].len = 1; + xfer[0].buf = ® + + /* Read data */ + xfer[1].addr = client->addr; + xfer[1].flags = I2C_M_RD; + xfer[1].len = 2; + xfer[1].buf = (u8 *)&data; + + ret = i2c_transfer(client->adapter, xfer, 2); + if (ret != 2) { + dev_err(&client->dev, "i2c_transfer() returned %d\n", ret); + return 0; + } + + return (data >> 8) | ((data & 0xff) << 8); +} + +static unsigned int wm9081_read(struct snd_soc_codec *codec, unsigned int reg) +{ + if (wm9081_reg_is_volatile(reg)) + return wm9081_read_hw(codec, reg); + else + return wm9081_read_reg_cache(codec, reg); +} + +static int wm9081_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + u16 *cache = codec->reg_cache; + u8 data[3]; + + BUG_ON(reg > WM9081_MAX_REGISTER); + + if (!wm9081_reg_is_volatile(reg)) + cache[reg] = value; + + data[0] = reg; + data[1] = value >> 8; + data[2] = value & 0x00ff; + + if (codec->hw_write(codec->control_data, data, 3) == 3) + return 0; + else + return -EIO; +} + +static int wm9081_reset(struct snd_soc_codec *codec) +{ + return wm9081_write(codec, WM9081_SOFTWARE_RESET, 0); +} + +static const DECLARE_TLV_DB_SCALE(drc_in_tlv, -4500, 75, 0); +static const DECLARE_TLV_DB_SCALE(drc_out_tlv, -2250, 75, 0); +static const DECLARE_TLV_DB_SCALE(drc_min_tlv, -1800, 600, 0); +static unsigned int drc_max_tlv[] = { + TLV_DB_RANGE_HEAD(4), + 0, 0, TLV_DB_SCALE_ITEM(1200, 0, 0), + 1, 1, TLV_DB_SCALE_ITEM(1800, 0, 0), + 2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0), + 3, 3, TLV_DB_SCALE_ITEM(3600, 0, 0), +}; +static const DECLARE_TLV_DB_SCALE(drc_qr_tlv, 1200, 600, 0); +static const DECLARE_TLV_DB_SCALE(drc_startup_tlv, -300, 50, 0); + +static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); + +static const DECLARE_TLV_DB_SCALE(in_tlv, -600, 600, 0); +static const DECLARE_TLV_DB_SCALE(dac_tlv, -7200, 75, 1); +static const DECLARE_TLV_DB_SCALE(out_tlv, -5700, 100, 0); + +static const char *drc_high_text[] = { + "1", + "1/2", + "1/4", + "1/8", + "1/16", + "0", +}; + +static const struct soc_enum drc_high = + SOC_ENUM_SINGLE(WM9081_DRC_3, 3, 6, drc_high_text); + +static const char *drc_low_text[] = { + "1", + "1/2", + "1/4", + "1/8", + "0", +}; + +static const struct soc_enum drc_low = + SOC_ENUM_SINGLE(WM9081_DRC_3, 0, 5, drc_low_text); + +static const char *drc_atk_text[] = { + "181us", + "181us", + "363us", + "726us", + "1.45ms", + "2.9ms", + "5.8ms", + "11.6ms", + "23.2ms", + "46.4ms", + "92.8ms", + "185.6ms", +}; + +static const struct soc_enum drc_atk = + SOC_ENUM_SINGLE(WM9081_DRC_2, 12, 12, drc_atk_text); + +static const char *drc_dcy_text[] = { + "186ms", + "372ms", + "743ms", + "1.49s", + "2.97s", + "5.94s", + "11.89s", + "23.78s", + "47.56s", +}; + +static const struct soc_enum drc_dcy = + SOC_ENUM_SINGLE(WM9081_DRC_2, 8, 9, drc_dcy_text); + +static const char *drc_qr_dcy_text[] = { + "0.725ms", + "1.45ms", + "5.8ms", +}; + +static const struct soc_enum drc_qr_dcy = + SOC_ENUM_SINGLE(WM9081_DRC_2, 4, 3, drc_qr_dcy_text); + +static const char *dac_deemph_text[] = { + "None", + "32kHz", + "44.1kHz", + "48kHz", +}; + +static const struct soc_enum dac_deemph = + SOC_ENUM_SINGLE(WM9081_DAC_DIGITAL_2, 1, 4, dac_deemph_text); + +static const char *speaker_mode_text[] = { + "Class D", + "Class AB", +}; + +static const struct soc_enum speaker_mode = + SOC_ENUM_SINGLE(WM9081_ANALOGUE_SPEAKER_2, 6, 2, speaker_mode_text); + +static int speaker_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + unsigned int reg; + + reg = wm9081_read(codec, WM9081_ANALOGUE_SPEAKER_2); + if (reg & WM9081_SPK_MODE) + ucontrol->value.integer.value[0] = 1; + else + ucontrol->value.integer.value[0] = 0; + + return 0; +} + +/* + * Stop any attempts to change speaker mode while the speaker is enabled. + * + * We also have some special anti-pop controls dependant on speaker + * mode which must be changed along with the mode. + */ +static int speaker_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + unsigned int reg_pwr = wm9081_read(codec, WM9081_POWER_MANAGEMENT); + unsigned int reg2 = wm9081_read(codec, WM9081_ANALOGUE_SPEAKER_2); + + /* Are we changing anything? */ + if (ucontrol->value.integer.value[0] == + ((reg2 & WM9081_SPK_MODE) != 0)) + return 0; + + /* Don't try to change modes while enabled */ + if (reg_pwr & WM9081_SPK_ENA) + return -EINVAL; + + if (ucontrol->value.integer.value[0]) { + /* Class AB */ + reg2 &= ~(WM9081_SPK_INV_MUTE | WM9081_OUT_SPK_CTRL); + reg2 |= WM9081_SPK_MODE; + } else { + /* Class D */ + reg2 |= WM9081_SPK_INV_MUTE | WM9081_OUT_SPK_CTRL; + reg2 &= ~WM9081_SPK_MODE; + } + + wm9081_write(codec, WM9081_ANALOGUE_SPEAKER_2, reg2); + + return 0; +} + +static const struct snd_kcontrol_new wm9081_snd_controls[] = { +SOC_SINGLE_TLV("IN1 Volume", WM9081_ANALOGUE_MIXER, 1, 1, 1, in_tlv), +SOC_SINGLE_TLV("IN2 Volume", WM9081_ANALOGUE_MIXER, 3, 1, 1, in_tlv), + +SOC_SINGLE_TLV("Playback Volume", WM9081_DAC_DIGITAL_1, 1, 96, 0, dac_tlv), + +SOC_SINGLE("LINEOUT Switch", WM9081_ANALOGUE_LINEOUT, 7, 1, 1), +SOC_SINGLE("LINEOUT ZC Switch", WM9081_ANALOGUE_LINEOUT, 6, 1, 0), +SOC_SINGLE_TLV("LINEOUT Volume", WM9081_ANALOGUE_LINEOUT, 0, 63, 0, out_tlv), + +SOC_SINGLE("DRC Switch", WM9081_DRC_1, 15, 1, 0), +SOC_ENUM("DRC High Slope", drc_high), +SOC_ENUM("DRC Low Slope", drc_low), +SOC_SINGLE_TLV("DRC Input Volume", WM9081_DRC_4, 5, 60, 1, drc_in_tlv), +SOC_SINGLE_TLV("DRC Output Volume", WM9081_DRC_4, 0, 30, 1, drc_out_tlv), +SOC_SINGLE_TLV("DRC Minimum Volume", WM9081_DRC_2, 2, 3, 1, drc_min_tlv), +SOC_SINGLE_TLV("DRC Maximum Volume", WM9081_DRC_2, 0, 3, 0, drc_max_tlv), +SOC_ENUM("DRC Attack", drc_atk), +SOC_ENUM("DRC Decay", drc_dcy), +SOC_SINGLE("DRC Quick Release Switch", WM9081_DRC_1, 2, 1, 0), +SOC_SINGLE_TLV("DRC Quick Release Volume", WM9081_DRC_2, 6, 3, 0, drc_qr_tlv), +SOC_ENUM("DRC Quick Release Decay", drc_qr_dcy), +SOC_SINGLE_TLV("DRC Startup Volume", WM9081_DRC_1, 6, 18, 0, drc_startup_tlv), + +SOC_SINGLE("EQ Switch", WM9081_EQ_1, 0, 1, 0), + +SOC_SINGLE("Speaker DC Volume", WM9081_ANALOGUE_SPEAKER_1, 3, 5, 0), +SOC_SINGLE("Speaker AC Volume", WM9081_ANALOGUE_SPEAKER_1, 0, 5, 0), +SOC_SINGLE("Speaker Switch", WM9081_ANALOGUE_SPEAKER_PGA, 7, 1, 1), +SOC_SINGLE("Speaker ZC Switch", WM9081_ANALOGUE_SPEAKER_PGA, 6, 1, 0), +SOC_SINGLE_TLV("Speaker Volume", WM9081_ANALOGUE_SPEAKER_PGA, 0, 63, 0, + out_tlv), +SOC_ENUM("DAC Deemphasis", dac_deemph), +SOC_ENUM_EXT("Speaker Mode", speaker_mode, speaker_mode_get, speaker_mode_put), +}; + +static const struct snd_kcontrol_new wm9081_eq_controls[] = { +SOC_SINGLE_TLV("EQ1 Volume", WM9081_EQ_1, 11, 24, 0, eq_tlv), +SOC_SINGLE_TLV("EQ2 Volume", WM9081_EQ_1, 6, 24, 0, eq_tlv), +SOC_SINGLE_TLV("EQ3 Volume", WM9081_EQ_1, 1, 24, 0, eq_tlv), +SOC_SINGLE_TLV("EQ4 Volume", WM9081_EQ_2, 11, 24, 0, eq_tlv), +SOC_SINGLE_TLV("EQ5 Volume", WM9081_EQ_2, 6, 24, 0, eq_tlv), +}; + +static const struct snd_kcontrol_new mixer[] = { +SOC_DAPM_SINGLE("IN1 Switch", WM9081_ANALOGUE_MIXER, 0, 1, 0), +SOC_DAPM_SINGLE("IN2 Switch", WM9081_ANALOGUE_MIXER, 2, 1, 0), +SOC_DAPM_SINGLE("Playback Switch", WM9081_ANALOGUE_MIXER, 4, 1, 0), +}; + +static int speaker_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + unsigned int reg = wm9081_read(codec, WM9081_POWER_MANAGEMENT); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + reg |= WM9081_SPK_ENA; + break; + + case SND_SOC_DAPM_PRE_PMD: + reg &= ~WM9081_SPK_ENA; + break; + } + + wm9081_write(codec, WM9081_POWER_MANAGEMENT, reg); + + return 0; +} + +struct _fll_div { + u16 fll_fratio; + u16 fll_outdiv; + u16 fll_clk_ref_div; + u16 n; + u16 k; +}; + +/* The size in bits of the FLL divide multiplied by 10 + * to allow rounding later */ +#define FIXED_FLL_SIZE ((1 << 16) * 10) + +static struct { + unsigned int min; + unsigned int max; + u16 fll_fratio; + int ratio; +} fll_fratios[] = { + { 0, 64000, 4, 16 }, + { 64000, 128000, 3, 8 }, + { 128000, 256000, 2, 4 }, + { 256000, 1000000, 1, 2 }, + { 1000000, 13500000, 0, 1 }, +}; + +static int fll_factors(struct _fll_div *fll_div, unsigned int Fref, + unsigned int Fout) +{ + u64 Kpart; + unsigned int K, Ndiv, Nmod, target; + unsigned int div; + int i; + + /* Fref must be <=13.5MHz */ + div = 1; + while ((Fref / div) > 13500000) { + div *= 2; + + if (div > 8) { + pr_err("Can't scale %dMHz input down to <=13.5MHz\n", + Fref); + return -EINVAL; + } + } + fll_div->fll_clk_ref_div = div / 2; + + pr_debug("Fref=%u Fout=%u\n", Fref, Fout); + + /* Apply the division for our remaining calculations */ + Fref /= div; + + /* Fvco should be 90-100MHz; don't check the upper bound */ + div = 0; + target = Fout * 2; + while (target < 90000000) { + div++; + target *= 2; + if (div > 7) { + pr_err("Unable to find FLL_OUTDIV for Fout=%uHz\n", + Fout); + return -EINVAL; + } + } + fll_div->fll_outdiv = div; + + pr_debug("Fvco=%dHz\n", target); + + /* Find an appropraite FLL_FRATIO and factor it out of the target */ + for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) { + if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) { + fll_div->fll_fratio = fll_fratios[i].fll_fratio; + target /= fll_fratios[i].ratio; + break; + } + } + if (i == ARRAY_SIZE(fll_fratios)) { + pr_err("Unable to find FLL_FRATIO for Fref=%uHz\n", Fref); + return -EINVAL; + } + + /* Now, calculate N.K */ + Ndiv = target / Fref; + + fll_div->n = Ndiv; + Nmod = target % Fref; + pr_debug("Nmod=%d\n", Nmod); + + /* Calculate fractional part - scale up so we can round. */ + Kpart = FIXED_FLL_SIZE * (long long)Nmod; + + do_div(Kpart, Fref); + + K = Kpart & 0xFFFFFFFF; + + if ((K % 10) >= 5) + K += 5; + + /* Move down to proper range now rounding is done */ + fll_div->k = K / 10; + + pr_debug("N=%x K=%x FLL_FRATIO=%x FLL_OUTDIV=%x FLL_CLK_REF_DIV=%x\n", + fll_div->n, fll_div->k, + fll_div->fll_fratio, fll_div->fll_outdiv, + fll_div->fll_clk_ref_div); + + return 0; +} + +static int wm9081_set_fll(struct snd_soc_codec *codec, int fll_id, + unsigned int Fref, unsigned int Fout) +{ + struct wm9081_priv *wm9081 = codec->private_data; + u16 reg1, reg4, reg5; + struct _fll_div fll_div; + int ret; + int clk_sys_reg; + + /* Any change? */ + if (Fref == wm9081->fll_fref && Fout == wm9081->fll_fout) + return 0; + + /* Disable the FLL */ + if (Fout == 0) { + dev_dbg(codec->dev, "FLL disabled\n"); + wm9081->fll_fref = 0; + wm9081->fll_fout = 0; + + return 0; + } + + ret = fll_factors(&fll_div, Fref, Fout); + if (ret != 0) + return ret; + + reg5 = wm9081_read(codec, WM9081_FLL_CONTROL_5); + reg5 &= ~WM9081_FLL_CLK_SRC_MASK; + + switch (fll_id) { + case WM9081_SYSCLK_FLL_MCLK: + reg5 |= 0x1; + break; + + default: + dev_err(codec->dev, "Unknown FLL ID %d\n", fll_id); + return -EINVAL; + } + + /* Disable CLK_SYS while we reconfigure */ + clk_sys_reg = wm9081_read(codec, WM9081_CLOCK_CONTROL_3); + if (clk_sys_reg & WM9081_CLK_SYS_ENA) + wm9081_write(codec, WM9081_CLOCK_CONTROL_3, + clk_sys_reg & ~WM9081_CLK_SYS_ENA); + + /* Any FLL configuration change requires that the FLL be + * disabled first. */ + reg1 = wm9081_read(codec, WM9081_FLL_CONTROL_1); + reg1 &= ~WM9081_FLL_ENA; + wm9081_write(codec, WM9081_FLL_CONTROL_1, reg1); + + /* Apply the configuration */ + if (fll_div.k) + reg1 |= WM9081_FLL_FRAC_MASK; + else + reg1 &= ~WM9081_FLL_FRAC_MASK; + wm9081_write(codec, WM9081_FLL_CONTROL_1, reg1); + + wm9081_write(codec, WM9081_FLL_CONTROL_2, + (fll_div.fll_outdiv << WM9081_FLL_OUTDIV_SHIFT) | + (fll_div.fll_fratio << WM9081_FLL_FRATIO_SHIFT)); + wm9081_write(codec, WM9081_FLL_CONTROL_3, fll_div.k); + + reg4 = wm9081_read(codec, WM9081_FLL_CONTROL_4); + reg4 &= ~WM9081_FLL_N_MASK; + reg4 |= fll_div.n << WM9081_FLL_N_SHIFT; + wm9081_write(codec, WM9081_FLL_CONTROL_4, reg4); + + reg5 &= ~WM9081_FLL_CLK_REF_DIV_MASK; + reg5 |= fll_div.fll_clk_ref_div << WM9081_FLL_CLK_REF_DIV_SHIFT; + wm9081_write(codec, WM9081_FLL_CONTROL_5, reg5); + + /* Enable the FLL */ + wm9081_write(codec, WM9081_FLL_CONTROL_1, reg1 | WM9081_FLL_ENA); + + /* Then bring CLK_SYS up again if it was disabled */ + if (clk_sys_reg & WM9081_CLK_SYS_ENA) + wm9081_write(codec, WM9081_CLOCK_CONTROL_3, clk_sys_reg); + + dev_dbg(codec->dev, "FLL enabled at %dHz->%dHz\n", Fref, Fout); + + wm9081->fll_fref = Fref; + wm9081->fll_fout = Fout; + + return 0; +} + +static int configure_clock(struct snd_soc_codec *codec) +{ + struct wm9081_priv *wm9081 = codec->private_data; + int new_sysclk, i, target; + unsigned int reg; + int ret = 0; + int mclkdiv = 0; + int fll = 0; + + switch (wm9081->sysclk_source) { + case WM9081_SYSCLK_MCLK: + if (wm9081->mclk_rate > 12225000) { + mclkdiv = 1; + wm9081->sysclk_rate = wm9081->mclk_rate / 2; + } else { + wm9081->sysclk_rate = wm9081->mclk_rate; + } + wm9081_set_fll(codec, WM9081_SYSCLK_FLL_MCLK, 0, 0); + break; + + case WM9081_SYSCLK_FLL_MCLK: + /* If we have a sample rate calculate a CLK_SYS that + * gives us a suitable DAC configuration, plus BCLK. + * Ideally we would check to see if we can clock + * directly from MCLK and only use the FLL if this is + * not the case, though care must be taken with free + * running mode. + */ + if (wm9081->master && wm9081->bclk) { + /* Make sure we can generate CLK_SYS and BCLK + * and that we've got 3MHz for optimal + * performance. */ + for (i = 0; i < ARRAY_SIZE(clk_sys_rates); i++) { + target = wm9081->fs * clk_sys_rates[i].ratio; + new_sysclk = target; + if (target >= wm9081->bclk && + target > 3000000) + break; + } + } else if (wm9081->fs) { + for (i = 0; i < ARRAY_SIZE(clk_sys_rates); i++) { + new_sysclk = clk_sys_rates[i].ratio + * wm9081->fs; + if (new_sysclk > 3000000) + break; + } + } else { + new_sysclk = 12288000; + } + + ret = wm9081_set_fll(codec, WM9081_SYSCLK_FLL_MCLK, + wm9081->mclk_rate, new_sysclk); + if (ret == 0) { + wm9081->sysclk_rate = new_sysclk; + + /* Switch SYSCLK over to FLL */ + fll = 1; + } else { + wm9081->sysclk_rate = wm9081->mclk_rate; + } + break; + + default: + return -EINVAL; + } + + reg = wm9081_read(codec, WM9081_CLOCK_CONTROL_1); + if (mclkdiv) + reg |= WM9081_MCLKDIV2; + else + reg &= ~WM9081_MCLKDIV2; + wm9081_write(codec, WM9081_CLOCK_CONTROL_1, reg); + + reg = wm9081_read(codec, WM9081_CLOCK_CONTROL_3); + if (fll) + reg |= WM9081_CLK_SRC_SEL; + else + reg &= ~WM9081_CLK_SRC_SEL; + wm9081_write(codec, WM9081_CLOCK_CONTROL_3, reg); + + dev_dbg(codec->dev, "CLK_SYS is %dHz\n", wm9081->sysclk_rate); + + return ret; +} + +static int clk_sys_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + struct wm9081_priv *wm9081 = codec->private_data; + + /* This should be done on init() for bypass paths */ + switch (wm9081->sysclk_source) { + case WM9081_SYSCLK_MCLK: + dev_dbg(codec->dev, "Using %dHz MCLK\n", wm9081->mclk_rate); + break; + case WM9081_SYSCLK_FLL_MCLK: + dev_dbg(codec->dev, "Using %dHz MCLK with FLL\n", + wm9081->mclk_rate); + break; + default: + dev_err(codec->dev, "System clock not configured\n"); + return -EINVAL; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + configure_clock(codec); + break; + + case SND_SOC_DAPM_POST_PMD: + /* Disable the FLL if it's running */ + wm9081_set_fll(codec, 0, 0, 0); + break; + } + + return 0; +} + +static const struct snd_soc_dapm_widget wm9081_dapm_widgets[] = { +SND_SOC_DAPM_INPUT("IN1"), +SND_SOC_DAPM_INPUT("IN2"), + +SND_SOC_DAPM_DAC("DAC", "HiFi Playback", WM9081_POWER_MANAGEMENT, 0, 0), + +SND_SOC_DAPM_MIXER_NAMED_CTL("Mixer", SND_SOC_NOPM, 0, 0, + mixer, ARRAY_SIZE(mixer)), + +SND_SOC_DAPM_PGA("LINEOUT PGA", WM9081_POWER_MANAGEMENT, 4, 0, NULL, 0), + +SND_SOC_DAPM_PGA_E("Speaker PGA", WM9081_POWER_MANAGEMENT, 2, 0, NULL, 0, + speaker_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + +SND_SOC_DAPM_OUTPUT("LINEOUT"), +SND_SOC_DAPM_OUTPUT("SPKN"), +SND_SOC_DAPM_OUTPUT("SPKP"), + +SND_SOC_DAPM_SUPPLY("CLK_SYS", WM9081_CLOCK_CONTROL_3, 0, 0, clk_sys_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_SUPPLY("CLK_DSP", WM9081_CLOCK_CONTROL_3, 1, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("TOCLK", WM9081_CLOCK_CONTROL_3, 2, 0, NULL, 0), +}; + + +static const struct snd_soc_dapm_route audio_paths[] = { + { "DAC", NULL, "CLK_SYS" }, + { "DAC", NULL, "CLK_DSP" }, + + { "Mixer", "IN1 Switch", "IN1" }, + { "Mixer", "IN2 Switch", "IN2" }, + { "Mixer", "Playback Switch", "DAC" }, + + { "LINEOUT PGA", NULL, "Mixer" }, + { "LINEOUT PGA", NULL, "TOCLK" }, + { "LINEOUT PGA", NULL, "CLK_SYS" }, + + { "LINEOUT", NULL, "LINEOUT PGA" }, + + { "Speaker PGA", NULL, "Mixer" }, + { "Speaker PGA", NULL, "TOCLK" }, + { "Speaker PGA", NULL, "CLK_SYS" }, + + { "SPKN", NULL, "Speaker PGA" }, + { "SPKP", NULL, "Speaker PGA" }, +}; + +static int wm9081_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + u16 reg; + + switch (level) { + case SND_SOC_BIAS_ON: + break; + + case SND_SOC_BIAS_PREPARE: + /* VMID=2*40k */ + reg = wm9081_read(codec, WM9081_VMID_CONTROL); + reg &= ~WM9081_VMID_SEL_MASK; + reg |= 0x2; + wm9081_write(codec, WM9081_VMID_CONTROL, reg); + + /* Normal bias current */ + reg = wm9081_read(codec, WM9081_BIAS_CONTROL_1); + reg &= ~WM9081_STBY_BIAS_ENA; + wm9081_write(codec, WM9081_BIAS_CONTROL_1, reg); + break; + + case SND_SOC_BIAS_STANDBY: + /* Initial cold start */ + if (codec->bias_level == SND_SOC_BIAS_OFF) { + /* Disable LINEOUT discharge */ + reg = wm9081_read(codec, WM9081_ANTI_POP_CONTROL); + reg &= ~WM9081_LINEOUT_DISCH; + wm9081_write(codec, WM9081_ANTI_POP_CONTROL, reg); + + /* Select startup bias source */ + reg = wm9081_read(codec, WM9081_BIAS_CONTROL_1); + reg |= WM9081_BIAS_SRC | WM9081_BIAS_ENA; + wm9081_write(codec, WM9081_BIAS_CONTROL_1, reg); + + /* VMID 2*4k; Soft VMID ramp enable */ + reg = wm9081_read(codec, WM9081_VMID_CONTROL); + reg |= WM9081_VMID_RAMP | 0x6; + wm9081_write(codec, WM9081_VMID_CONTROL, reg); + + mdelay(100); + + /* Normal bias enable & soft start off */ + reg |= WM9081_BIAS_ENA; + reg &= ~WM9081_VMID_RAMP; + wm9081_write(codec, WM9081_VMID_CONTROL, reg); + + /* Standard bias source */ + reg = wm9081_read(codec, WM9081_BIAS_CONTROL_1); + reg &= ~WM9081_BIAS_SRC; + wm9081_write(codec, WM9081_BIAS_CONTROL_1, reg); + } + + /* VMID 2*240k */ + reg = wm9081_read(codec, WM9081_BIAS_CONTROL_1); + reg &= ~WM9081_VMID_SEL_MASK; + reg |= 0x40; + wm9081_write(codec, WM9081_VMID_CONTROL, reg); + + /* Standby bias current on */ + reg = wm9081_read(codec, WM9081_BIAS_CONTROL_1); + reg |= WM9081_STBY_BIAS_ENA; + wm9081_write(codec, WM9081_BIAS_CONTROL_1, reg); + break; + + case SND_SOC_BIAS_OFF: + /* Startup bias source */ + reg = wm9081_read(codec, WM9081_BIAS_CONTROL_1); + reg |= WM9081_BIAS_SRC; + wm9081_write(codec, WM9081_BIAS_CONTROL_1, reg); + + /* Disable VMID and biases with soft ramping */ + reg = wm9081_read(codec, WM9081_VMID_CONTROL); + reg &= ~(WM9081_VMID_SEL_MASK | WM9081_BIAS_ENA); + reg |= WM9081_VMID_RAMP; + wm9081_write(codec, WM9081_VMID_CONTROL, reg); + + /* Actively discharge LINEOUT */ + reg = wm9081_read(codec, WM9081_ANTI_POP_CONTROL); + reg |= WM9081_LINEOUT_DISCH; + wm9081_write(codec, WM9081_ANTI_POP_CONTROL, reg); + break; + } + + codec->bias_level = level; + + return 0; +} + +static int wm9081_set_dai_fmt(struct snd_soc_dai *dai, + unsigned int fmt) +{ + struct snd_soc_codec *codec = dai->codec; + struct wm9081_priv *wm9081 = codec->private_data; + unsigned int aif2 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_2); + + aif2 &= ~(WM9081_AIF_BCLK_INV | WM9081_AIF_LRCLK_INV | + WM9081_BCLK_DIR | WM9081_LRCLK_DIR | WM9081_AIF_FMT_MASK); + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + wm9081->master = 0; + break; + case SND_SOC_DAIFMT_CBS_CFM: + aif2 |= WM9081_LRCLK_DIR; + wm9081->master = 1; + break; + case SND_SOC_DAIFMT_CBM_CFS: + aif2 |= WM9081_BCLK_DIR; + wm9081->master = 1; + break; + case SND_SOC_DAIFMT_CBM_CFM: + aif2 |= WM9081_LRCLK_DIR | WM9081_BCLK_DIR; + wm9081->master = 1; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_B: + aif2 |= WM9081_AIF_LRCLK_INV; + case SND_SOC_DAIFMT_DSP_A: + aif2 |= 0x3; + break; + case SND_SOC_DAIFMT_I2S: + aif2 |= 0x2; + break; + case SND_SOC_DAIFMT_RIGHT_J: + break; + case SND_SOC_DAIFMT_LEFT_J: + aif2 |= 0x1; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + case SND_SOC_DAIFMT_DSP_B: + /* frame inversion not valid for DSP modes */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_NF: + aif2 |= WM9081_AIF_BCLK_INV; + break; + default: + return -EINVAL; + } + break; + + case SND_SOC_DAIFMT_I2S: + case SND_SOC_DAIFMT_RIGHT_J: + case SND_SOC_DAIFMT_LEFT_J: + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_IF: + aif2 |= WM9081_AIF_BCLK_INV | WM9081_AIF_LRCLK_INV; + break; + case SND_SOC_DAIFMT_IB_NF: + aif2 |= WM9081_AIF_BCLK_INV; + break; + case SND_SOC_DAIFMT_NB_IF: + aif2 |= WM9081_AIF_LRCLK_INV; + break; + default: + return -EINVAL; + } + break; + default: + return -EINVAL; + } + + wm9081_write(codec, WM9081_AUDIO_INTERFACE_2, aif2); + + return 0; +} + +static int wm9081_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct wm9081_priv *wm9081 = codec->private_data; + int ret, i, best, best_val, cur_val; + unsigned int clk_ctrl2, aif1, aif2, aif3, aif4; + + clk_ctrl2 = wm9081_read(codec, WM9081_CLOCK_CONTROL_2); + clk_ctrl2 &= ~(WM9081_CLK_SYS_RATE_MASK | WM9081_SAMPLE_RATE_MASK); + + aif1 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_1); + + aif2 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_2); + aif2 &= ~WM9081_AIF_WL_MASK; + + aif3 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_3); + aif3 &= ~WM9081_BCLK_DIV_MASK; + + aif4 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_4); + aif4 &= ~WM9081_LRCLK_RATE_MASK; + + /* What BCLK do we need? */ + wm9081->fs = params_rate(params); + wm9081->bclk = 2 * wm9081->fs; + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + wm9081->bclk *= 16; + break; + case SNDRV_PCM_FORMAT_S20_3LE: + wm9081->bclk *= 20; + aif2 |= 0x4; + break; + case SNDRV_PCM_FORMAT_S24_LE: + wm9081->bclk *= 24; + aif2 |= 0x8; + break; + case SNDRV_PCM_FORMAT_S32_LE: + wm9081->bclk *= 32; + aif2 |= 0xc; + break; + default: + return -EINVAL; + } + + if (aif1 & WM9081_AIFDAC_TDM_MODE_MASK) { + int slots = ((aif1 & WM9081_AIFDAC_TDM_MODE_MASK) >> + WM9081_AIFDAC_TDM_MODE_SHIFT) + 1; + wm9081->bclk *= slots; + } + + dev_dbg(codec->dev, "Target BCLK is %dHz\n", wm9081->bclk); + + ret = configure_clock(codec); + if (ret != 0) + return ret; + + /* Select nearest CLK_SYS_RATE */ + best = 0; + best_val = abs((wm9081->sysclk_rate / clk_sys_rates[0].ratio) + - wm9081->fs); + for (i = 1; i < ARRAY_SIZE(clk_sys_rates); i++) { + cur_val = abs((wm9081->sysclk_rate / + clk_sys_rates[i].ratio) - wm9081->fs);; + if (cur_val < best_val) { + best = i; + best_val = cur_val; + } + } + dev_dbg(codec->dev, "Selected CLK_SYS_RATIO of %d\n", + clk_sys_rates[best].ratio); + clk_ctrl2 |= (clk_sys_rates[best].clk_sys_rate + << WM9081_CLK_SYS_RATE_SHIFT); + + /* SAMPLE_RATE */ + best = 0; + best_val = abs(wm9081->fs - sample_rates[0].rate); + for (i = 1; i < ARRAY_SIZE(sample_rates); i++) { + /* Closest match */ + cur_val = abs(wm9081->fs - sample_rates[i].rate); + if (cur_val < best_val) { + best = i; + best_val = cur_val; + } + } + dev_dbg(codec->dev, "Selected SAMPLE_RATE of %dHz\n", + sample_rates[best].rate); + clk_ctrl2 |= (sample_rates[best].sample_rate + << WM9081_SAMPLE_RATE_SHIFT); + + /* BCLK_DIV */ + best = 0; + best_val = INT_MAX; + for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) { + cur_val = ((wm9081->sysclk_rate * 10) / bclk_divs[i].div) + - wm9081->bclk; + if (cur_val < 0) /* Table is sorted */ + break; + if (cur_val < best_val) { + best = i; + best_val = cur_val; + } + } + wm9081->bclk = (wm9081->sysclk_rate * 10) / bclk_divs[best].div; + dev_dbg(codec->dev, "Selected BCLK_DIV of %d for %dHz BCLK\n", + bclk_divs[best].div, wm9081->bclk); + aif3 |= bclk_divs[best].bclk_div; + + /* LRCLK is a simple fraction of BCLK */ + dev_dbg(codec->dev, "LRCLK_RATE is %d\n", wm9081->bclk / wm9081->fs); + aif4 |= wm9081->bclk / wm9081->fs; + + /* Apply a ReTune Mobile configuration if it's in use */ + if (wm9081->retune) { + struct wm9081_retune_mobile_config *retune = wm9081->retune; + struct wm9081_retune_mobile_setting *s; + int eq1; + + best = 0; + best_val = abs(retune->configs[0].rate - wm9081->fs); + for (i = 0; i < retune->num_configs; i++) { + cur_val = abs(retune->configs[i].rate - wm9081->fs); + if (cur_val < best_val) { + best_val = cur_val; + best = i; + } + } + s = &retune->configs[best]; + + dev_dbg(codec->dev, "ReTune Mobile %s tuned for %dHz\n", + s->name, s->rate); + + /* If the EQ is enabled then disable it while we write out */ + eq1 = wm9081_read(codec, WM9081_EQ_1) & WM9081_EQ_ENA; + if (eq1 & WM9081_EQ_ENA) + wm9081_write(codec, WM9081_EQ_1, 0); + + /* Write out the other values */ + for (i = 1; i < ARRAY_SIZE(s->config); i++) + wm9081_write(codec, WM9081_EQ_1 + i, s->config[i]); + + eq1 |= (s->config[0] & ~WM9081_EQ_ENA); + wm9081_write(codec, WM9081_EQ_1, eq1); + } + + wm9081_write(codec, WM9081_CLOCK_CONTROL_2, clk_ctrl2); + wm9081_write(codec, WM9081_AUDIO_INTERFACE_2, aif2); + wm9081_write(codec, WM9081_AUDIO_INTERFACE_3, aif3); + wm9081_write(codec, WM9081_AUDIO_INTERFACE_4, aif4); + + return 0; +} + +static int wm9081_digital_mute(struct snd_soc_dai *codec_dai, int mute) +{ + struct snd_soc_codec *codec = codec_dai->codec; + unsigned int reg; + + reg = wm9081_read(codec, WM9081_DAC_DIGITAL_2); + + if (mute) + reg |= WM9081_DAC_MUTE; + else + reg &= ~WM9081_DAC_MUTE; + + wm9081_write(codec, WM9081_DAC_DIGITAL_2, reg); + + return 0; +} + +static int wm9081_set_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct wm9081_priv *wm9081 = codec->private_data; + + switch (clk_id) { + case WM9081_SYSCLK_MCLK: + case WM9081_SYSCLK_FLL_MCLK: + wm9081->sysclk_source = clk_id; + wm9081->mclk_rate = freq; + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int wm9081_set_tdm_slot(struct snd_soc_dai *dai, + unsigned int mask, int slots) +{ + struct snd_soc_codec *codec = dai->codec; + unsigned int aif1 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_1); + + aif1 &= ~(WM9081_AIFDAC_TDM_SLOT_MASK | WM9081_AIFDAC_TDM_MODE_MASK); + + if (slots < 1 || slots > 4) + return -EINVAL; + + aif1 |= (slots - 1) << WM9081_AIFDAC_TDM_MODE_SHIFT; + + switch (mask) { + case 1: + break; + case 2: + aif1 |= 0x10; + break; + case 4: + aif1 |= 0x20; + break; + case 8: + aif1 |= 0x30; + break; + default: + return -EINVAL; + } + + wm9081_write(codec, WM9081_AUDIO_INTERFACE_1, aif1); + + return 0; +} + +#define WM9081_RATES SNDRV_PCM_RATE_8000_96000 + +#define WM9081_FORMATS \ + (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_ops wm9081_dai_ops = { + .hw_params = wm9081_hw_params, + .set_sysclk = wm9081_set_sysclk, + .set_fmt = wm9081_set_dai_fmt, + .digital_mute = wm9081_digital_mute, + .set_tdm_slot = wm9081_set_tdm_slot, +}; + +/* We report two channels because the CODEC processes a stereo signal, even + * though it is only capable of handling a mono output. + */ +struct snd_soc_dai wm9081_dai = { + .name = "WM9081", + .playback = { + .stream_name = "HiFi Playback", + .channels_min = 1, + .channels_max = 2, + .rates = WM9081_RATES, + .formats = WM9081_FORMATS, + }, + .ops = &wm9081_dai_ops, +}; +EXPORT_SYMBOL_GPL(wm9081_dai); + + +static struct snd_soc_codec *wm9081_codec; + +static int wm9081_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec; + struct wm9081_priv *wm9081; + int ret = 0; + + if (wm9081_codec == NULL) { + dev_err(&pdev->dev, "Codec device not registered\n"); + return -ENODEV; + } + + socdev->card->codec = wm9081_codec; + codec = wm9081_codec; + wm9081 = codec->private_data; + + /* register pcms */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + dev_err(codec->dev, "failed to create pcms: %d\n", ret); + goto pcm_err; + } + + snd_soc_add_controls(codec, wm9081_snd_controls, + ARRAY_SIZE(wm9081_snd_controls)); + if (!wm9081->retune) { + dev_dbg(codec->dev, + "No ReTune Mobile data, using normal EQ\n"); + snd_soc_add_controls(codec, wm9081_eq_controls, + ARRAY_SIZE(wm9081_eq_controls)); + } + + snd_soc_dapm_new_controls(codec, wm9081_dapm_widgets, + ARRAY_SIZE(wm9081_dapm_widgets)); + snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths)); + snd_soc_dapm_new_widgets(codec); + + ret = snd_soc_init_card(socdev); + if (ret < 0) { + dev_err(codec->dev, "failed to register card: %d\n", ret); + goto card_err; + } + + return ret; + +card_err: + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); +pcm_err: + return ret; +} + +static int wm9081_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); + + return 0; +} + +#ifdef CONFIG_PM +static int wm9081_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + + wm9081_set_bias_level(codec, SND_SOC_BIAS_OFF); + + return 0; +} + +static int wm9081_resume(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + u16 *reg_cache = codec->reg_cache; + int i; + + for (i = 0; i < codec->reg_cache_size; i++) { + if (i == WM9081_SOFTWARE_RESET) + continue; + + wm9081_write(codec, i, reg_cache[i]); + } + + wm9081_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + return 0; +} +#else +#define wm9081_suspend NULL +#define wm9081_resume NULL +#endif + +struct snd_soc_codec_device soc_codec_dev_wm9081 = { + .probe = wm9081_probe, + .remove = wm9081_remove, + .suspend = wm9081_suspend, + .resume = wm9081_resume, +}; +EXPORT_SYMBOL_GPL(soc_codec_dev_wm9081); + +static int wm9081_register(struct wm9081_priv *wm9081) +{ + struct snd_soc_codec *codec = &wm9081->codec; + int ret; + u16 reg; + + if (wm9081_codec) { + dev_err(codec->dev, "Another WM9081 is registered\n"); + ret = -EINVAL; + goto err; + } + + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + + codec->private_data = wm9081; + codec->name = "WM9081"; + codec->owner = THIS_MODULE; + codec->read = wm9081_read; + codec->write = wm9081_write; + codec->dai = &wm9081_dai; + codec->num_dai = 1; + codec->reg_cache_size = ARRAY_SIZE(wm9081->reg_cache); + codec->reg_cache = &wm9081->reg_cache; + codec->bias_level = SND_SOC_BIAS_OFF; + codec->set_bias_level = wm9081_set_bias_level; + + memcpy(codec->reg_cache, wm9081_reg_defaults, + sizeof(wm9081_reg_defaults)); + + reg = wm9081_read_hw(codec, WM9081_SOFTWARE_RESET); + if (reg != 0x9081) { + dev_err(codec->dev, "Device is not a WM9081: ID=0x%x\n", reg); + ret = -EINVAL; + goto err; + } + + ret = wm9081_reset(codec); + if (ret < 0) { + dev_err(codec->dev, "Failed to issue reset\n"); + return ret; + } + + wm9081_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + /* Enable zero cross by default */ + reg = wm9081_read(codec, WM9081_ANALOGUE_LINEOUT); + wm9081_write(codec, WM9081_ANALOGUE_LINEOUT, reg | WM9081_LINEOUTZC); + reg = wm9081_read(codec, WM9081_ANALOGUE_SPEAKER_PGA); + wm9081_write(codec, WM9081_ANALOGUE_SPEAKER_PGA, + reg | WM9081_SPKPGAZC); + + wm9081_dai.dev = codec->dev; + + wm9081_codec = codec; + + ret = snd_soc_register_codec(codec); + if (ret != 0) { + dev_err(codec->dev, "Failed to register codec: %d\n", ret); + return ret; + } + + ret = snd_soc_register_dai(&wm9081_dai); + if (ret != 0) { + dev_err(codec->dev, "Failed to register DAI: %d\n", ret); + snd_soc_unregister_codec(codec); + return ret; + } + + return 0; + +err: + kfree(wm9081); + return ret; +} + +static void wm9081_unregister(struct wm9081_priv *wm9081) +{ + wm9081_set_bias_level(&wm9081->codec, SND_SOC_BIAS_OFF); + snd_soc_unregister_dai(&wm9081_dai); + snd_soc_unregister_codec(&wm9081->codec); + kfree(wm9081); + wm9081_codec = NULL; +} + +static __devinit int wm9081_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct wm9081_priv *wm9081; + struct snd_soc_codec *codec; + + wm9081 = kzalloc(sizeof(struct wm9081_priv), GFP_KERNEL); + if (wm9081 == NULL) + return -ENOMEM; + + codec = &wm9081->codec; + codec->hw_write = (hw_write_t)i2c_master_send; + wm9081->retune = i2c->dev.platform_data; + + i2c_set_clientdata(i2c, wm9081); + codec->control_data = i2c; + + codec->dev = &i2c->dev; + + return wm9081_register(wm9081); +} + +static __devexit int wm9081_i2c_remove(struct i2c_client *client) +{ + struct wm9081_priv *wm9081 = i2c_get_clientdata(client); + wm9081_unregister(wm9081); + return 0; +} + +static const struct i2c_device_id wm9081_i2c_id[] = { + { "wm9081", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, wm9081_i2c_id); + +static struct i2c_driver wm9081_i2c_driver = { + .driver = { + .name = "wm9081", + .owner = THIS_MODULE, + }, + .probe = wm9081_i2c_probe, + .remove = __devexit_p(wm9081_i2c_remove), + .id_table = wm9081_i2c_id, +}; + +static int __init wm9081_modinit(void) +{ + int ret; + + ret = i2c_add_driver(&wm9081_i2c_driver); + if (ret != 0) { + printk(KERN_ERR "Failed to register WM9081 I2C driver: %d\n", + ret); + } + + return ret; +} +module_init(wm9081_modinit); + +static void __exit wm9081_exit(void) +{ + i2c_del_driver(&wm9081_i2c_driver); +} +module_exit(wm9081_exit); + + +MODULE_DESCRIPTION("ASoC WM9081 driver"); +MODULE_AUTHOR("Mark Brown "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm9081.h b/sound/soc/codecs/wm9081.h new file mode 100644 index 000000000000..42d3bc757021 --- /dev/null +++ b/sound/soc/codecs/wm9081.h @@ -0,0 +1,787 @@ +#ifndef WM9081_H +#define WM9081_H + +/* + * wm9081.c -- WM9081 ALSA SoC Audio driver + * + * Author: Mark Brown + * + * Copyright 2009 Wolfson Microelectronics plc + * + * 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 + +extern struct snd_soc_dai wm9081_dai; +extern struct snd_soc_codec_device soc_codec_dev_wm9081; + +/* + * SYSCLK sources + */ +#define WM9081_SYSCLK_MCLK 1 /* Use MCLK without FLL */ +#define WM9081_SYSCLK_FLL_MCLK 2 /* Use MCLK, enabling FLL if required */ + +/* + * Register values. + */ +#define WM9081_SOFTWARE_RESET 0x00 +#define WM9081_ANALOGUE_LINEOUT 0x02 +#define WM9081_ANALOGUE_SPEAKER_PGA 0x03 +#define WM9081_VMID_CONTROL 0x04 +#define WM9081_BIAS_CONTROL_1 0x05 +#define WM9081_ANALOGUE_MIXER 0x07 +#define WM9081_ANTI_POP_CONTROL 0x08 +#define WM9081_ANALOGUE_SPEAKER_1 0x09 +#define WM9081_ANALOGUE_SPEAKER_2 0x0A +#define WM9081_POWER_MANAGEMENT 0x0B +#define WM9081_CLOCK_CONTROL_1 0x0C +#define WM9081_CLOCK_CONTROL_2 0x0D +#define WM9081_CLOCK_CONTROL_3 0x0E +#define WM9081_FLL_CONTROL_1 0x10 +#define WM9081_FLL_CONTROL_2 0x11 +#define WM9081_FLL_CONTROL_3 0x12 +#define WM9081_FLL_CONTROL_4 0x13 +#define WM9081_FLL_CONTROL_5 0x14 +#define WM9081_AUDIO_INTERFACE_1 0x16 +#define WM9081_AUDIO_INTERFACE_2 0x17 +#define WM9081_AUDIO_INTERFACE_3 0x18 +#define WM9081_AUDIO_INTERFACE_4 0x19 +#define WM9081_INTERRUPT_STATUS 0x1A +#define WM9081_INTERRUPT_STATUS_MASK 0x1B +#define WM9081_INTERRUPT_POLARITY 0x1C +#define WM9081_INTERRUPT_CONTROL 0x1D +#define WM9081_DAC_DIGITAL_1 0x1E +#define WM9081_DAC_DIGITAL_2 0x1F +#define WM9081_DRC_1 0x20 +#define WM9081_DRC_2 0x21 +#define WM9081_DRC_3 0x22 +#define WM9081_DRC_4 0x23 +#define WM9081_WRITE_SEQUENCER_1 0x26 +#define WM9081_WRITE_SEQUENCER_2 0x27 +#define WM9081_MW_SLAVE_1 0x28 +#define WM9081_EQ_1 0x2A +#define WM9081_EQ_2 0x2B +#define WM9081_EQ_3 0x2C +#define WM9081_EQ_4 0x2D +#define WM9081_EQ_5 0x2E +#define WM9081_EQ_6 0x2F +#define WM9081_EQ_7 0x30 +#define WM9081_EQ_8 0x31 +#define WM9081_EQ_9 0x32 +#define WM9081_EQ_10 0x33 +#define WM9081_EQ_11 0x34 +#define WM9081_EQ_12 0x35 +#define WM9081_EQ_13 0x36 +#define WM9081_EQ_14 0x37 +#define WM9081_EQ_15 0x38 +#define WM9081_EQ_16 0x39 +#define WM9081_EQ_17 0x3A +#define WM9081_EQ_18 0x3B +#define WM9081_EQ_19 0x3C +#define WM9081_EQ_20 0x3D + +#define WM9081_REGISTER_COUNT 55 +#define WM9081_MAX_REGISTER 0x3D + +/* + * Field Definitions. + */ + +/* + * R0 (0x00) - Software Reset + */ +#define WM9081_SW_RST_DEV_ID1_MASK 0xFFFF /* SW_RST_DEV_ID1 - [15:0] */ +#define WM9081_SW_RST_DEV_ID1_SHIFT 0 /* SW_RST_DEV_ID1 - [15:0] */ +#define WM9081_SW_RST_DEV_ID1_WIDTH 16 /* SW_RST_DEV_ID1 - [15:0] */ + +/* + * R2 (0x02) - Analogue Lineout + */ +#define WM9081_LINEOUT_MUTE 0x0080 /* LINEOUT_MUTE */ +#define WM9081_LINEOUT_MUTE_MASK 0x0080 /* LINEOUT_MUTE */ +#define WM9081_LINEOUT_MUTE_SHIFT 7 /* LINEOUT_MUTE */ +#define WM9081_LINEOUT_MUTE_WIDTH 1 /* LINEOUT_MUTE */ +#define WM9081_LINEOUTZC 0x0040 /* LINEOUTZC */ +#define WM9081_LINEOUTZC_MASK 0x0040 /* LINEOUTZC */ +#define WM9081_LINEOUTZC_SHIFT 6 /* LINEOUTZC */ +#define WM9081_LINEOUTZC_WIDTH 1 /* LINEOUTZC */ +#define WM9081_LINEOUT_VOL_MASK 0x003F /* LINEOUT_VOL - [5:0] */ +#define WM9081_LINEOUT_VOL_SHIFT 0 /* LINEOUT_VOL - [5:0] */ +#define WM9081_LINEOUT_VOL_WIDTH 6 /* LINEOUT_VOL - [5:0] */ + +/* + * R3 (0x03) - Analogue Speaker PGA + */ +#define WM9081_SPKPGA_MUTE 0x0080 /* SPKPGA_MUTE */ +#define WM9081_SPKPGA_MUTE_MASK 0x0080 /* SPKPGA_MUTE */ +#define WM9081_SPKPGA_MUTE_SHIFT 7 /* SPKPGA_MUTE */ +#define WM9081_SPKPGA_MUTE_WIDTH 1 /* SPKPGA_MUTE */ +#define WM9081_SPKPGAZC 0x0040 /* SPKPGAZC */ +#define WM9081_SPKPGAZC_MASK 0x0040 /* SPKPGAZC */ +#define WM9081_SPKPGAZC_SHIFT 6 /* SPKPGAZC */ +#define WM9081_SPKPGAZC_WIDTH 1 /* SPKPGAZC */ +#define WM9081_SPKPGA_VOL_MASK 0x003F /* SPKPGA_VOL - [5:0] */ +#define WM9081_SPKPGA_VOL_SHIFT 0 /* SPKPGA_VOL - [5:0] */ +#define WM9081_SPKPGA_VOL_WIDTH 6 /* SPKPGA_VOL - [5:0] */ + +/* + * R4 (0x04) - VMID Control + */ +#define WM9081_VMID_BUF_ENA 0x0020 /* VMID_BUF_ENA */ +#define WM9081_VMID_BUF_ENA_MASK 0x0020 /* VMID_BUF_ENA */ +#define WM9081_VMID_BUF_ENA_SHIFT 5 /* VMID_BUF_ENA */ +#define WM9081_VMID_BUF_ENA_WIDTH 1 /* VMID_BUF_ENA */ +#define WM9081_VMID_RAMP 0x0008 /* VMID_RAMP */ +#define WM9081_VMID_RAMP_MASK 0x0008 /* VMID_RAMP */ +#define WM9081_VMID_RAMP_SHIFT 3 /* VMID_RAMP */ +#define WM9081_VMID_RAMP_WIDTH 1 /* VMID_RAMP */ +#define WM9081_VMID_SEL_MASK 0x0006 /* VMID_SEL - [2:1] */ +#define WM9081_VMID_SEL_SHIFT 1 /* VMID_SEL - [2:1] */ +#define WM9081_VMID_SEL_WIDTH 2 /* VMID_SEL - [2:1] */ +#define WM9081_VMID_FAST_ST 0x0001 /* VMID_FAST_ST */ +#define WM9081_VMID_FAST_ST_MASK 0x0001 /* VMID_FAST_ST */ +#define WM9081_VMID_FAST_ST_SHIFT 0 /* VMID_FAST_ST */ +#define WM9081_VMID_FAST_ST_WIDTH 1 /* VMID_FAST_ST */ + +/* + * R5 (0x05) - Bias Control 1 + */ +#define WM9081_BIAS_SRC 0x0040 /* BIAS_SRC */ +#define WM9081_BIAS_SRC_MASK 0x0040 /* BIAS_SRC */ +#define WM9081_BIAS_SRC_SHIFT 6 /* BIAS_SRC */ +#define WM9081_BIAS_SRC_WIDTH 1 /* BIAS_SRC */ +#define WM9081_STBY_BIAS_LVL 0x0020 /* STBY_BIAS_LVL */ +#define WM9081_STBY_BIAS_LVL_MASK 0x0020 /* STBY_BIAS_LVL */ +#define WM9081_STBY_BIAS_LVL_SHIFT 5 /* STBY_BIAS_LVL */ +#define WM9081_STBY_BIAS_LVL_WIDTH 1 /* STBY_BIAS_LVL */ +#define WM9081_STBY_BIAS_ENA 0x0010 /* STBY_BIAS_ENA */ +#define WM9081_STBY_BIAS_ENA_MASK 0x0010 /* STBY_BIAS_ENA */ +#define WM9081_STBY_BIAS_ENA_SHIFT 4 /* STBY_BIAS_ENA */ +#define WM9081_STBY_BIAS_ENA_WIDTH 1 /* STBY_BIAS_ENA */ +#define WM9081_BIAS_LVL_MASK 0x000C /* BIAS_LVL - [3:2] */ +#define WM9081_BIAS_LVL_SHIFT 2 /* BIAS_LVL - [3:2] */ +#define WM9081_BIAS_LVL_WIDTH 2 /* BIAS_LVL - [3:2] */ +#define WM9081_BIAS_ENA 0x0002 /* BIAS_ENA */ +#define WM9081_BIAS_ENA_MASK 0x0002 /* BIAS_ENA */ +#define WM9081_BIAS_ENA_SHIFT 1 /* BIAS_ENA */ +#define WM9081_BIAS_ENA_WIDTH 1 /* BIAS_ENA */ +#define WM9081_STARTUP_BIAS_ENA 0x0001 /* STARTUP_BIAS_ENA */ +#define WM9081_STARTUP_BIAS_ENA_MASK 0x0001 /* STARTUP_BIAS_ENA */ +#define WM9081_STARTUP_BIAS_ENA_SHIFT 0 /* STARTUP_BIAS_ENA */ +#define WM9081_STARTUP_BIAS_ENA_WIDTH 1 /* STARTUP_BIAS_ENA */ + +/* + * R7 (0x07) - Analogue Mixer + */ +#define WM9081_DAC_SEL 0x0010 /* DAC_SEL */ +#define WM9081_DAC_SEL_MASK 0x0010 /* DAC_SEL */ +#define WM9081_DAC_SEL_SHIFT 4 /* DAC_SEL */ +#define WM9081_DAC_SEL_WIDTH 1 /* DAC_SEL */ +#define WM9081_IN2_VOL 0x0008 /* IN2_VOL */ +#define WM9081_IN2_VOL_MASK 0x0008 /* IN2_VOL */ +#define WM9081_IN2_VOL_SHIFT 3 /* IN2_VOL */ +#define WM9081_IN2_VOL_WIDTH 1 /* IN2_VOL */ +#define WM9081_IN2_ENA 0x0004 /* IN2_ENA */ +#define WM9081_IN2_ENA_MASK 0x0004 /* IN2_ENA */ +#define WM9081_IN2_ENA_SHIFT 2 /* IN2_ENA */ +#define WM9081_IN2_ENA_WIDTH 1 /* IN2_ENA */ +#define WM9081_IN1_VOL 0x0002 /* IN1_VOL */ +#define WM9081_IN1_VOL_MASK 0x0002 /* IN1_VOL */ +#define WM9081_IN1_VOL_SHIFT 1 /* IN1_VOL */ +#define WM9081_IN1_VOL_WIDTH 1 /* IN1_VOL */ +#define WM9081_IN1_ENA 0x0001 /* IN1_ENA */ +#define WM9081_IN1_ENA_MASK 0x0001 /* IN1_ENA */ +#define WM9081_IN1_ENA_SHIFT 0 /* IN1_ENA */ +#define WM9081_IN1_ENA_WIDTH 1 /* IN1_ENA */ + +/* + * R8 (0x08) - Anti Pop Control + */ +#define WM9081_LINEOUT_DISCH 0x0004 /* LINEOUT_DISCH */ +#define WM9081_LINEOUT_DISCH_MASK 0x0004 /* LINEOUT_DISCH */ +#define WM9081_LINEOUT_DISCH_SHIFT 2 /* LINEOUT_DISCH */ +#define WM9081_LINEOUT_DISCH_WIDTH 1 /* LINEOUT_DISCH */ +#define WM9081_LINEOUT_VROI 0x0002 /* LINEOUT_VROI */ +#define WM9081_LINEOUT_VROI_MASK 0x0002 /* LINEOUT_VROI */ +#define WM9081_LINEOUT_VROI_SHIFT 1 /* LINEOUT_VROI */ +#define WM9081_LINEOUT_VROI_WIDTH 1 /* LINEOUT_VROI */ +#define WM9081_LINEOUT_CLAMP 0x0001 /* LINEOUT_CLAMP */ +#define WM9081_LINEOUT_CLAMP_MASK 0x0001 /* LINEOUT_CLAMP */ +#define WM9081_LINEOUT_CLAMP_SHIFT 0 /* LINEOUT_CLAMP */ +#define WM9081_LINEOUT_CLAMP_WIDTH 1 /* LINEOUT_CLAMP */ + +/* + * R9 (0x09) - Analogue Speaker 1 + */ +#define WM9081_SPK_DCGAIN_MASK 0x0038 /* SPK_DCGAIN - [5:3] */ +#define WM9081_SPK_DCGAIN_SHIFT 3 /* SPK_DCGAIN - [5:3] */ +#define WM9081_SPK_DCGAIN_WIDTH 3 /* SPK_DCGAIN - [5:3] */ +#define WM9081_SPK_ACGAIN_MASK 0x0007 /* SPK_ACGAIN - [2:0] */ +#define WM9081_SPK_ACGAIN_SHIFT 0 /* SPK_ACGAIN - [2:0] */ +#define WM9081_SPK_ACGAIN_WIDTH 3 /* SPK_ACGAIN - [2:0] */ + +/* + * R10 (0x0A) - Analogue Speaker 2 + */ +#define WM9081_SPK_MODE 0x0040 /* SPK_MODE */ +#define WM9081_SPK_MODE_MASK 0x0040 /* SPK_MODE */ +#define WM9081_SPK_MODE_SHIFT 6 /* SPK_MODE */ +#define WM9081_SPK_MODE_WIDTH 1 /* SPK_MODE */ +#define WM9081_SPK_INV_MUTE 0x0010 /* SPK_INV_MUTE */ +#define WM9081_SPK_INV_MUTE_MASK 0x0010 /* SPK_INV_MUTE */ +#define WM9081_SPK_INV_MUTE_SHIFT 4 /* SPK_INV_MUTE */ +#define WM9081_SPK_INV_MUTE_WIDTH 1 /* SPK_INV_MUTE */ +#define WM9081_OUT_SPK_CTRL 0x0008 /* OUT_SPK_CTRL */ +#define WM9081_OUT_SPK_CTRL_MASK 0x0008 /* OUT_SPK_CTRL */ +#define WM9081_OUT_SPK_CTRL_SHIFT 3 /* OUT_SPK_CTRL */ +#define WM9081_OUT_SPK_CTRL_WIDTH 1 /* OUT_SPK_CTRL */ + +/* + * R11 (0x0B) - Power Management + */ +#define WM9081_TSHUT_ENA 0x0100 /* TSHUT_ENA */ +#define WM9081_TSHUT_ENA_MASK 0x0100 /* TSHUT_ENA */ +#define WM9081_TSHUT_ENA_SHIFT 8 /* TSHUT_ENA */ +#define WM9081_TSHUT_ENA_WIDTH 1 /* TSHUT_ENA */ +#define WM9081_TSENSE_ENA 0x0080 /* TSENSE_ENA */ +#define WM9081_TSENSE_ENA_MASK 0x0080 /* TSENSE_ENA */ +#define WM9081_TSENSE_ENA_SHIFT 7 /* TSENSE_ENA */ +#define WM9081_TSENSE_ENA_WIDTH 1 /* TSENSE_ENA */ +#define WM9081_TEMP_SHUT 0x0040 /* TEMP_SHUT */ +#define WM9081_TEMP_SHUT_MASK 0x0040 /* TEMP_SHUT */ +#define WM9081_TEMP_SHUT_SHIFT 6 /* TEMP_SHUT */ +#define WM9081_TEMP_SHUT_WIDTH 1 /* TEMP_SHUT */ +#define WM9081_LINEOUT_ENA 0x0010 /* LINEOUT_ENA */ +#define WM9081_LINEOUT_ENA_MASK 0x0010 /* LINEOUT_ENA */ +#define WM9081_LINEOUT_ENA_SHIFT 4 /* LINEOUT_ENA */ +#define WM9081_LINEOUT_ENA_WIDTH 1 /* LINEOUT_ENA */ +#define WM9081_SPKPGA_ENA 0x0004 /* SPKPGA_ENA */ +#define WM9081_SPKPGA_ENA_MASK 0x0004 /* SPKPGA_ENA */ +#define WM9081_SPKPGA_ENA_SHIFT 2 /* SPKPGA_ENA */ +#define WM9081_SPKPGA_ENA_WIDTH 1 /* SPKPGA_ENA */ +#define WM9081_SPK_ENA 0x0002 /* SPK_ENA */ +#define WM9081_SPK_ENA_MASK 0x0002 /* SPK_ENA */ +#define WM9081_SPK_ENA_SHIFT 1 /* SPK_ENA */ +#define WM9081_SPK_ENA_WIDTH 1 /* SPK_ENA */ +#define WM9081_DAC_ENA 0x0001 /* DAC_ENA */ +#define WM9081_DAC_ENA_MASK 0x0001 /* DAC_ENA */ +#define WM9081_DAC_ENA_SHIFT 0 /* DAC_ENA */ +#define WM9081_DAC_ENA_WIDTH 1 /* DAC_ENA */ + +/* + * R12 (0x0C) - Clock Control 1 + */ +#define WM9081_CLK_OP_DIV_MASK 0x1C00 /* CLK_OP_DIV - [12:10] */ +#define WM9081_CLK_OP_DIV_SHIFT 10 /* CLK_OP_DIV - [12:10] */ +#define WM9081_CLK_OP_DIV_WIDTH 3 /* CLK_OP_DIV - [12:10] */ +#define WM9081_CLK_TO_DIV_MASK 0x0300 /* CLK_TO_DIV - [9:8] */ +#define WM9081_CLK_TO_DIV_SHIFT 8 /* CLK_TO_DIV - [9:8] */ +#define WM9081_CLK_TO_DIV_WIDTH 2 /* CLK_TO_DIV - [9:8] */ +#define WM9081_MCLKDIV2 0x0080 /* MCLKDIV2 */ +#define WM9081_MCLKDIV2_MASK 0x0080 /* MCLKDIV2 */ +#define WM9081_MCLKDIV2_SHIFT 7 /* MCLKDIV2 */ +#define WM9081_MCLKDIV2_WIDTH 1 /* MCLKDIV2 */ + +/* + * R13 (0x0D) - Clock Control 2 + */ +#define WM9081_CLK_SYS_RATE_MASK 0x00F0 /* CLK_SYS_RATE - [7:4] */ +#define WM9081_CLK_SYS_RATE_SHIFT 4 /* CLK_SYS_RATE - [7:4] */ +#define WM9081_CLK_SYS_RATE_WIDTH 4 /* CLK_SYS_RATE - [7:4] */ +#define WM9081_SAMPLE_RATE_MASK 0x000F /* SAMPLE_RATE - [3:0] */ +#define WM9081_SAMPLE_RATE_SHIFT 0 /* SAMPLE_RATE - [3:0] */ +#define WM9081_SAMPLE_RATE_WIDTH 4 /* SAMPLE_RATE - [3:0] */ + +/* + * R14 (0x0E) - Clock Control 3 + */ +#define WM9081_CLK_SRC_SEL 0x2000 /* CLK_SRC_SEL */ +#define WM9081_CLK_SRC_SEL_MASK 0x2000 /* CLK_SRC_SEL */ +#define WM9081_CLK_SRC_SEL_SHIFT 13 /* CLK_SRC_SEL */ +#define WM9081_CLK_SRC_SEL_WIDTH 1 /* CLK_SRC_SEL */ +#define WM9081_CLK_OP_ENA 0x0020 /* CLK_OP_ENA */ +#define WM9081_CLK_OP_ENA_MASK 0x0020 /* CLK_OP_ENA */ +#define WM9081_CLK_OP_ENA_SHIFT 5 /* CLK_OP_ENA */ +#define WM9081_CLK_OP_ENA_WIDTH 1 /* CLK_OP_ENA */ +#define WM9081_CLK_TO_ENA 0x0004 /* CLK_TO_ENA */ +#define WM9081_CLK_TO_ENA_MASK 0x0004 /* CLK_TO_ENA */ +#define WM9081_CLK_TO_ENA_SHIFT 2 /* CLK_TO_ENA */ +#define WM9081_CLK_TO_ENA_WIDTH 1 /* CLK_TO_ENA */ +#define WM9081_CLK_DSP_ENA 0x0002 /* CLK_DSP_ENA */ +#define WM9081_CLK_DSP_ENA_MASK 0x0002 /* CLK_DSP_ENA */ +#define WM9081_CLK_DSP_ENA_SHIFT 1 /* CLK_DSP_ENA */ +#define WM9081_CLK_DSP_ENA_WIDTH 1 /* CLK_DSP_ENA */ +#define WM9081_CLK_SYS_ENA 0x0001 /* CLK_SYS_ENA */ +#define WM9081_CLK_SYS_ENA_MASK 0x0001 /* CLK_SYS_ENA */ +#define WM9081_CLK_SYS_ENA_SHIFT 0 /* CLK_SYS_ENA */ +#define WM9081_CLK_SYS_ENA_WIDTH 1 /* CLK_SYS_ENA */ + +/* + * R16 (0x10) - FLL Control 1 + */ +#define WM9081_FLL_HOLD 0x0008 /* FLL_HOLD */ +#define WM9081_FLL_HOLD_MASK 0x0008 /* FLL_HOLD */ +#define WM9081_FLL_HOLD_SHIFT 3 /* FLL_HOLD */ +#define WM9081_FLL_HOLD_WIDTH 1 /* FLL_HOLD */ +#define WM9081_FLL_FRAC 0x0004 /* FLL_FRAC */ +#define WM9081_FLL_FRAC_MASK 0x0004 /* FLL_FRAC */ +#define WM9081_FLL_FRAC_SHIFT 2 /* FLL_FRAC */ +#define WM9081_FLL_FRAC_WIDTH 1 /* FLL_FRAC */ +#define WM9081_FLL_ENA 0x0001 /* FLL_ENA */ +#define WM9081_FLL_ENA_MASK 0x0001 /* FLL_ENA */ +#define WM9081_FLL_ENA_SHIFT 0 /* FLL_ENA */ +#define WM9081_FLL_ENA_WIDTH 1 /* FLL_ENA */ + +/* + * R17 (0x11) - FLL Control 2 + */ +#define WM9081_FLL_OUTDIV_MASK 0x0700 /* FLL_OUTDIV - [10:8] */ +#define WM9081_FLL_OUTDIV_SHIFT 8 /* FLL_OUTDIV - [10:8] */ +#define WM9081_FLL_OUTDIV_WIDTH 3 /* FLL_OUTDIV - [10:8] */ +#define WM9081_FLL_CTRL_RATE_MASK 0x0070 /* FLL_CTRL_RATE - [6:4] */ +#define WM9081_FLL_CTRL_RATE_SHIFT 4 /* FLL_CTRL_RATE - [6:4] */ +#define WM9081_FLL_CTRL_RATE_WIDTH 3 /* FLL_CTRL_RATE - [6:4] */ +#define WM9081_FLL_FRATIO_MASK 0x0007 /* FLL_FRATIO - [2:0] */ +#define WM9081_FLL_FRATIO_SHIFT 0 /* FLL_FRATIO - [2:0] */ +#define WM9081_FLL_FRATIO_WIDTH 3 /* FLL_FRATIO - [2:0] */ + +/* + * R18 (0x12) - FLL Control 3 + */ +#define WM9081_FLL_K_MASK 0xFFFF /* FLL_K - [15:0] */ +#define WM9081_FLL_K_SHIFT 0 /* FLL_K - [15:0] */ +#define WM9081_FLL_K_WIDTH 16 /* FLL_K - [15:0] */ + +/* + * R19 (0x13) - FLL Control 4 + */ +#define WM9081_FLL_N_MASK 0x7FE0 /* FLL_N - [14:5] */ +#define WM9081_FLL_N_SHIFT 5 /* FLL_N - [14:5] */ +#define WM9081_FLL_N_WIDTH 10 /* FLL_N - [14:5] */ +#define WM9081_FLL_GAIN_MASK 0x000F /* FLL_GAIN - [3:0] */ +#define WM9081_FLL_GAIN_SHIFT 0 /* FLL_GAIN - [3:0] */ +#define WM9081_FLL_GAIN_WIDTH 4 /* FLL_GAIN - [3:0] */ + +/* + * R20 (0x14) - FLL Control 5 + */ +#define WM9081_FLL_CLK_REF_DIV_MASK 0x0018 /* FLL_CLK_REF_DIV - [4:3] */ +#define WM9081_FLL_CLK_REF_DIV_SHIFT 3 /* FLL_CLK_REF_DIV - [4:3] */ +#define WM9081_FLL_CLK_REF_DIV_WIDTH 2 /* FLL_CLK_REF_DIV - [4:3] */ +#define WM9081_FLL_CLK_SRC_MASK 0x0003 /* FLL_CLK_SRC - [1:0] */ +#define WM9081_FLL_CLK_SRC_SHIFT 0 /* FLL_CLK_SRC - [1:0] */ +#define WM9081_FLL_CLK_SRC_WIDTH 2 /* FLL_CLK_SRC - [1:0] */ + +/* + * R22 (0x16) - Audio Interface 1 + */ +#define WM9081_AIFDAC_CHAN 0x0040 /* AIFDAC_CHAN */ +#define WM9081_AIFDAC_CHAN_MASK 0x0040 /* AIFDAC_CHAN */ +#define WM9081_AIFDAC_CHAN_SHIFT 6 /* AIFDAC_CHAN */ +#define WM9081_AIFDAC_CHAN_WIDTH 1 /* AIFDAC_CHAN */ +#define WM9081_AIFDAC_TDM_SLOT_MASK 0x0030 /* AIFDAC_TDM_SLOT - [5:4] */ +#define WM9081_AIFDAC_TDM_SLOT_SHIFT 4 /* AIFDAC_TDM_SLOT - [5:4] */ +#define WM9081_AIFDAC_TDM_SLOT_WIDTH 2 /* AIFDAC_TDM_SLOT - [5:4] */ +#define WM9081_AIFDAC_TDM_MODE_MASK 0x000C /* AIFDAC_TDM_MODE - [3:2] */ +#define WM9081_AIFDAC_TDM_MODE_SHIFT 2 /* AIFDAC_TDM_MODE - [3:2] */ +#define WM9081_AIFDAC_TDM_MODE_WIDTH 2 /* AIFDAC_TDM_MODE - [3:2] */ +#define WM9081_DAC_COMP 0x0002 /* DAC_COMP */ +#define WM9081_DAC_COMP_MASK 0x0002 /* DAC_COMP */ +#define WM9081_DAC_COMP_SHIFT 1 /* DAC_COMP */ +#define WM9081_DAC_COMP_WIDTH 1 /* DAC_COMP */ +#define WM9081_DAC_COMPMODE 0x0001 /* DAC_COMPMODE */ +#define WM9081_DAC_COMPMODE_MASK 0x0001 /* DAC_COMPMODE */ +#define WM9081_DAC_COMPMODE_SHIFT 0 /* DAC_COMPMODE */ +#define WM9081_DAC_COMPMODE_WIDTH 1 /* DAC_COMPMODE */ + +/* + * R23 (0x17) - Audio Interface 2 + */ +#define WM9081_AIF_TRIS 0x0200 /* AIF_TRIS */ +#define WM9081_AIF_TRIS_MASK 0x0200 /* AIF_TRIS */ +#define WM9081_AIF_TRIS_SHIFT 9 /* AIF_TRIS */ +#define WM9081_AIF_TRIS_WIDTH 1 /* AIF_TRIS */ +#define WM9081_DAC_DAT_INV 0x0100 /* DAC_DAT_INV */ +#define WM9081_DAC_DAT_INV_MASK 0x0100 /* DAC_DAT_INV */ +#define WM9081_DAC_DAT_INV_SHIFT 8 /* DAC_DAT_INV */ +#define WM9081_DAC_DAT_INV_WIDTH 1 /* DAC_DAT_INV */ +#define WM9081_AIF_BCLK_INV 0x0080 /* AIF_BCLK_INV */ +#define WM9081_AIF_BCLK_INV_MASK 0x0080 /* AIF_BCLK_INV */ +#define WM9081_AIF_BCLK_INV_SHIFT 7 /* AIF_BCLK_INV */ +#define WM9081_AIF_BCLK_INV_WIDTH 1 /* AIF_BCLK_INV */ +#define WM9081_BCLK_DIR 0x0040 /* BCLK_DIR */ +#define WM9081_BCLK_DIR_MASK 0x0040 /* BCLK_DIR */ +#define WM9081_BCLK_DIR_SHIFT 6 /* BCLK_DIR */ +#define WM9081_BCLK_DIR_WIDTH 1 /* BCLK_DIR */ +#define WM9081_LRCLK_DIR 0x0020 /* LRCLK_DIR */ +#define WM9081_LRCLK_DIR_MASK 0x0020 /* LRCLK_DIR */ +#define WM9081_LRCLK_DIR_SHIFT 5 /* LRCLK_DIR */ +#define WM9081_LRCLK_DIR_WIDTH 1 /* LRCLK_DIR */ +#define WM9081_AIF_LRCLK_INV 0x0010 /* AIF_LRCLK_INV */ +#define WM9081_AIF_LRCLK_INV_MASK 0x0010 /* AIF_LRCLK_INV */ +#define WM9081_AIF_LRCLK_INV_SHIFT 4 /* AIF_LRCLK_INV */ +#define WM9081_AIF_LRCLK_INV_WIDTH 1 /* AIF_LRCLK_INV */ +#define WM9081_AIF_WL_MASK 0x000C /* AIF_WL - [3:2] */ +#define WM9081_AIF_WL_SHIFT 2 /* AIF_WL - [3:2] */ +#define WM9081_AIF_WL_WIDTH 2 /* AIF_WL - [3:2] */ +#define WM9081_AIF_FMT_MASK 0x0003 /* AIF_FMT - [1:0] */ +#define WM9081_AIF_FMT_SHIFT 0 /* AIF_FMT - [1:0] */ +#define WM9081_AIF_FMT_WIDTH 2 /* AIF_FMT - [1:0] */ + +/* + * R24 (0x18) - Audio Interface 3 + */ +#define WM9081_BCLK_DIV_MASK 0x001F /* BCLK_DIV - [4:0] */ +#define WM9081_BCLK_DIV_SHIFT 0 /* BCLK_DIV - [4:0] */ +#define WM9081_BCLK_DIV_WIDTH 5 /* BCLK_DIV - [4:0] */ + +/* + * R25 (0x19) - Audio Interface 4 + */ +#define WM9081_LRCLK_RATE_MASK 0x07FF /* LRCLK_RATE - [10:0] */ +#define WM9081_LRCLK_RATE_SHIFT 0 /* LRCLK_RATE - [10:0] */ +#define WM9081_LRCLK_RATE_WIDTH 11 /* LRCLK_RATE - [10:0] */ + +/* + * R26 (0x1A) - Interrupt Status + */ +#define WM9081_WSEQ_BUSY_EINT 0x0004 /* WSEQ_BUSY_EINT */ +#define WM9081_WSEQ_BUSY_EINT_MASK 0x0004 /* WSEQ_BUSY_EINT */ +#define WM9081_WSEQ_BUSY_EINT_SHIFT 2 /* WSEQ_BUSY_EINT */ +#define WM9081_WSEQ_BUSY_EINT_WIDTH 1 /* WSEQ_BUSY_EINT */ +#define WM9081_TSHUT_EINT 0x0001 /* TSHUT_EINT */ +#define WM9081_TSHUT_EINT_MASK 0x0001 /* TSHUT_EINT */ +#define WM9081_TSHUT_EINT_SHIFT 0 /* TSHUT_EINT */ +#define WM9081_TSHUT_EINT_WIDTH 1 /* TSHUT_EINT */ + +/* + * R27 (0x1B) - Interrupt Status Mask + */ +#define WM9081_IM_WSEQ_BUSY_EINT 0x0004 /* IM_WSEQ_BUSY_EINT */ +#define WM9081_IM_WSEQ_BUSY_EINT_MASK 0x0004 /* IM_WSEQ_BUSY_EINT */ +#define WM9081_IM_WSEQ_BUSY_EINT_SHIFT 2 /* IM_WSEQ_BUSY_EINT */ +#define WM9081_IM_WSEQ_BUSY_EINT_WIDTH 1 /* IM_WSEQ_BUSY_EINT */ +#define WM9081_IM_TSHUT_EINT 0x0001 /* IM_TSHUT_EINT */ +#define WM9081_IM_TSHUT_EINT_MASK 0x0001 /* IM_TSHUT_EINT */ +#define WM9081_IM_TSHUT_EINT_SHIFT 0 /* IM_TSHUT_EINT */ +#define WM9081_IM_TSHUT_EINT_WIDTH 1 /* IM_TSHUT_EINT */ + +/* + * R28 (0x1C) - Interrupt Polarity + */ +#define WM9081_TSHUT_INV 0x0001 /* TSHUT_INV */ +#define WM9081_TSHUT_INV_MASK 0x0001 /* TSHUT_INV */ +#define WM9081_TSHUT_INV_SHIFT 0 /* TSHUT_INV */ +#define WM9081_TSHUT_INV_WIDTH 1 /* TSHUT_INV */ + +/* + * R29 (0x1D) - Interrupt Control + */ +#define WM9081_IRQ_POL 0x8000 /* IRQ_POL */ +#define WM9081_IRQ_POL_MASK 0x8000 /* IRQ_POL */ +#define WM9081_IRQ_POL_SHIFT 15 /* IRQ_POL */ +#define WM9081_IRQ_POL_WIDTH 1 /* IRQ_POL */ +#define WM9081_IRQ_OP_CTRL 0x0001 /* IRQ_OP_CTRL */ +#define WM9081_IRQ_OP_CTRL_MASK 0x0001 /* IRQ_OP_CTRL */ +#define WM9081_IRQ_OP_CTRL_SHIFT 0 /* IRQ_OP_CTRL */ +#define WM9081_IRQ_OP_CTRL_WIDTH 1 /* IRQ_OP_CTRL */ + +/* + * R30 (0x1E) - DAC Digital 1 + */ +#define WM9081_DAC_VOL_MASK 0x00FF /* DAC_VOL - [7:0] */ +#define WM9081_DAC_VOL_SHIFT 0 /* DAC_VOL - [7:0] */ +#define WM9081_DAC_VOL_WIDTH 8 /* DAC_VOL - [7:0] */ + +/* + * R31 (0x1F) - DAC Digital 2 + */ +#define WM9081_DAC_MUTERATE 0x0400 /* DAC_MUTERATE */ +#define WM9081_DAC_MUTERATE_MASK 0x0400 /* DAC_MUTERATE */ +#define WM9081_DAC_MUTERATE_SHIFT 10 /* DAC_MUTERATE */ +#define WM9081_DAC_MUTERATE_WIDTH 1 /* DAC_MUTERATE */ +#define WM9081_DAC_MUTEMODE 0x0200 /* DAC_MUTEMODE */ +#define WM9081_DAC_MUTEMODE_MASK 0x0200 /* DAC_MUTEMODE */ +#define WM9081_DAC_MUTEMODE_SHIFT 9 /* DAC_MUTEMODE */ +#define WM9081_DAC_MUTEMODE_WIDTH 1 /* DAC_MUTEMODE */ +#define WM9081_DAC_MUTE 0x0008 /* DAC_MUTE */ +#define WM9081_DAC_MUTE_MASK 0x0008 /* DAC_MUTE */ +#define WM9081_DAC_MUTE_SHIFT 3 /* DAC_MUTE */ +#define WM9081_DAC_MUTE_WIDTH 1 /* DAC_MUTE */ +#define WM9081_DEEMPH_MASK 0x0006 /* DEEMPH - [2:1] */ +#define WM9081_DEEMPH_SHIFT 1 /* DEEMPH - [2:1] */ +#define WM9081_DEEMPH_WIDTH 2 /* DEEMPH - [2:1] */ + +/* + * R32 (0x20) - DRC 1 + */ +#define WM9081_DRC_ENA 0x8000 /* DRC_ENA */ +#define WM9081_DRC_ENA_MASK 0x8000 /* DRC_ENA */ +#define WM9081_DRC_ENA_SHIFT 15 /* DRC_ENA */ +#define WM9081_DRC_ENA_WIDTH 1 /* DRC_ENA */ +#define WM9081_DRC_STARTUP_GAIN_MASK 0x07C0 /* DRC_STARTUP_GAIN - [10:6] */ +#define WM9081_DRC_STARTUP_GAIN_SHIFT 6 /* DRC_STARTUP_GAIN - [10:6] */ +#define WM9081_DRC_STARTUP_GAIN_WIDTH 5 /* DRC_STARTUP_GAIN - [10:6] */ +#define WM9081_DRC_FF_DLY 0x0020 /* DRC_FF_DLY */ +#define WM9081_DRC_FF_DLY_MASK 0x0020 /* DRC_FF_DLY */ +#define WM9081_DRC_FF_DLY_SHIFT 5 /* DRC_FF_DLY */ +#define WM9081_DRC_FF_DLY_WIDTH 1 /* DRC_FF_DLY */ +#define WM9081_DRC_QR 0x0004 /* DRC_QR */ +#define WM9081_DRC_QR_MASK 0x0004 /* DRC_QR */ +#define WM9081_DRC_QR_SHIFT 2 /* DRC_QR */ +#define WM9081_DRC_QR_WIDTH 1 /* DRC_QR */ +#define WM9081_DRC_ANTICLIP 0x0002 /* DRC_ANTICLIP */ +#define WM9081_DRC_ANTICLIP_MASK 0x0002 /* DRC_ANTICLIP */ +#define WM9081_DRC_ANTICLIP_SHIFT 1 /* DRC_ANTICLIP */ +#define WM9081_DRC_ANTICLIP_WIDTH 1 /* DRC_ANTICLIP */ + +/* + * R33 (0x21) - DRC 2 + */ +#define WM9081_DRC_ATK_MASK 0xF000 /* DRC_ATK - [15:12] */ +#define WM9081_DRC_ATK_SHIFT 12 /* DRC_ATK - [15:12] */ +#define WM9081_DRC_ATK_WIDTH 4 /* DRC_ATK - [15:12] */ +#define WM9081_DRC_DCY_MASK 0x0F00 /* DRC_DCY - [11:8] */ +#define WM9081_DRC_DCY_SHIFT 8 /* DRC_DCY - [11:8] */ +#define WM9081_DRC_DCY_WIDTH 4 /* DRC_DCY - [11:8] */ +#define WM9081_DRC_QR_THR_MASK 0x00C0 /* DRC_QR_THR - [7:6] */ +#define WM9081_DRC_QR_THR_SHIFT 6 /* DRC_QR_THR - [7:6] */ +#define WM9081_DRC_QR_THR_WIDTH 2 /* DRC_QR_THR - [7:6] */ +#define WM9081_DRC_QR_DCY_MASK 0x0030 /* DRC_QR_DCY - [5:4] */ +#define WM9081_DRC_QR_DCY_SHIFT 4 /* DRC_QR_DCY - [5:4] */ +#define WM9081_DRC_QR_DCY_WIDTH 2 /* DRC_QR_DCY - [5:4] */ +#define WM9081_DRC_MINGAIN_MASK 0x000C /* DRC_MINGAIN - [3:2] */ +#define WM9081_DRC_MINGAIN_SHIFT 2 /* DRC_MINGAIN - [3:2] */ +#define WM9081_DRC_MINGAIN_WIDTH 2 /* DRC_MINGAIN - [3:2] */ +#define WM9081_DRC_MAXGAIN_MASK 0x0003 /* DRC_MAXGAIN - [1:0] */ +#define WM9081_DRC_MAXGAIN_SHIFT 0 /* DRC_MAXGAIN - [1:0] */ +#define WM9081_DRC_MAXGAIN_WIDTH 2 /* DRC_MAXGAIN - [1:0] */ + +/* + * R34 (0x22) - DRC 3 + */ +#define WM9081_DRC_HI_COMP_MASK 0x0038 /* DRC_HI_COMP - [5:3] */ +#define WM9081_DRC_HI_COMP_SHIFT 3 /* DRC_HI_COMP - [5:3] */ +#define WM9081_DRC_HI_COMP_WIDTH 3 /* DRC_HI_COMP - [5:3] */ +#define WM9081_DRC_LO_COMP_MASK 0x0007 /* DRC_LO_COMP - [2:0] */ +#define WM9081_DRC_LO_COMP_SHIFT 0 /* DRC_LO_COMP - [2:0] */ +#define WM9081_DRC_LO_COMP_WIDTH 3 /* DRC_LO_COMP - [2:0] */ + +/* + * R35 (0x23) - DRC 4 + */ +#define WM9081_DRC_KNEE_IP_MASK 0x07E0 /* DRC_KNEE_IP - [10:5] */ +#define WM9081_DRC_KNEE_IP_SHIFT 5 /* DRC_KNEE_IP - [10:5] */ +#define WM9081_DRC_KNEE_IP_WIDTH 6 /* DRC_KNEE_IP - [10:5] */ +#define WM9081_DRC_KNEE_OP_MASK 0x001F /* DRC_KNEE_OP - [4:0] */ +#define WM9081_DRC_KNEE_OP_SHIFT 0 /* DRC_KNEE_OP - [4:0] */ +#define WM9081_DRC_KNEE_OP_WIDTH 5 /* DRC_KNEE_OP - [4:0] */ + +/* + * R38 (0x26) - Write Sequencer 1 + */ +#define WM9081_WSEQ_ENA 0x8000 /* WSEQ_ENA */ +#define WM9081_WSEQ_ENA_MASK 0x8000 /* WSEQ_ENA */ +#define WM9081_WSEQ_ENA_SHIFT 15 /* WSEQ_ENA */ +#define WM9081_WSEQ_ENA_WIDTH 1 /* WSEQ_ENA */ +#define WM9081_WSEQ_ABORT 0x0200 /* WSEQ_ABORT */ +#define WM9081_WSEQ_ABORT_MASK 0x0200 /* WSEQ_ABORT */ +#define WM9081_WSEQ_ABORT_SHIFT 9 /* WSEQ_ABORT */ +#define WM9081_WSEQ_ABORT_WIDTH 1 /* WSEQ_ABORT */ +#define WM9081_WSEQ_START 0x0100 /* WSEQ_START */ +#define WM9081_WSEQ_START_MASK 0x0100 /* WSEQ_START */ +#define WM9081_WSEQ_START_SHIFT 8 /* WSEQ_START */ +#define WM9081_WSEQ_START_WIDTH 1 /* WSEQ_START */ +#define WM9081_WSEQ_START_INDEX_MASK 0x007F /* WSEQ_START_INDEX - [6:0] */ +#define WM9081_WSEQ_START_INDEX_SHIFT 0 /* WSEQ_START_INDEX - [6:0] */ +#define WM9081_WSEQ_START_INDEX_WIDTH 7 /* WSEQ_START_INDEX - [6:0] */ + +/* + * R39 (0x27) - Write Sequencer 2 + */ +#define WM9081_WSEQ_CURRENT_INDEX_MASK 0x07F0 /* WSEQ_CURRENT_INDEX - [10:4] */ +#define WM9081_WSEQ_CURRENT_INDEX_SHIFT 4 /* WSEQ_CURRENT_INDEX - [10:4] */ +#define WM9081_WSEQ_CURRENT_INDEX_WIDTH 7 /* WSEQ_CURRENT_INDEX - [10:4] */ +#define WM9081_WSEQ_BUSY 0x0001 /* WSEQ_BUSY */ +#define WM9081_WSEQ_BUSY_MASK 0x0001 /* WSEQ_BUSY */ +#define WM9081_WSEQ_BUSY_SHIFT 0 /* WSEQ_BUSY */ +#define WM9081_WSEQ_BUSY_WIDTH 1 /* WSEQ_BUSY */ + +/* + * R40 (0x28) - MW Slave 1 + */ +#define WM9081_SPI_CFG 0x0020 /* SPI_CFG */ +#define WM9081_SPI_CFG_MASK 0x0020 /* SPI_CFG */ +#define WM9081_SPI_CFG_SHIFT 5 /* SPI_CFG */ +#define WM9081_SPI_CFG_WIDTH 1 /* SPI_CFG */ +#define WM9081_SPI_4WIRE 0x0010 /* SPI_4WIRE */ +#define WM9081_SPI_4WIRE_MASK 0x0010 /* SPI_4WIRE */ +#define WM9081_SPI_4WIRE_SHIFT 4 /* SPI_4WIRE */ +#define WM9081_SPI_4WIRE_WIDTH 1 /* SPI_4WIRE */ +#define WM9081_ARA_ENA 0x0008 /* ARA_ENA */ +#define WM9081_ARA_ENA_MASK 0x0008 /* ARA_ENA */ +#define WM9081_ARA_ENA_SHIFT 3 /* ARA_ENA */ +#define WM9081_ARA_ENA_WIDTH 1 /* ARA_ENA */ +#define WM9081_AUTO_INC 0x0002 /* AUTO_INC */ +#define WM9081_AUTO_INC_MASK 0x0002 /* AUTO_INC */ +#define WM9081_AUTO_INC_SHIFT 1 /* AUTO_INC */ +#define WM9081_AUTO_INC_WIDTH 1 /* AUTO_INC */ + +/* + * R42 (0x2A) - EQ 1 + */ +#define WM9081_EQ_B1_GAIN_MASK 0xF800 /* EQ_B1_GAIN - [15:11] */ +#define WM9081_EQ_B1_GAIN_SHIFT 11 /* EQ_B1_GAIN - [15:11] */ +#define WM9081_EQ_B1_GAIN_WIDTH 5 /* EQ_B1_GAIN - [15:11] */ +#define WM9081_EQ_B2_GAIN_MASK 0x07C0 /* EQ_B2_GAIN - [10:6] */ +#define WM9081_EQ_B2_GAIN_SHIFT 6 /* EQ_B2_GAIN - [10:6] */ +#define WM9081_EQ_B2_GAIN_WIDTH 5 /* EQ_B2_GAIN - [10:6] */ +#define WM9081_EQ_B4_GAIN_MASK 0x003E /* EQ_B4_GAIN - [5:1] */ +#define WM9081_EQ_B4_GAIN_SHIFT 1 /* EQ_B4_GAIN - [5:1] */ +#define WM9081_EQ_B4_GAIN_WIDTH 5 /* EQ_B4_GAIN - [5:1] */ +#define WM9081_EQ_ENA 0x0001 /* EQ_ENA */ +#define WM9081_EQ_ENA_MASK 0x0001 /* EQ_ENA */ +#define WM9081_EQ_ENA_SHIFT 0 /* EQ_ENA */ +#define WM9081_EQ_ENA_WIDTH 1 /* EQ_ENA */ + +/* + * R43 (0x2B) - EQ 2 + */ +#define WM9081_EQ_B3_GAIN_MASK 0xF800 /* EQ_B3_GAIN - [15:11] */ +#define WM9081_EQ_B3_GAIN_SHIFT 11 /* EQ_B3_GAIN - [15:11] */ +#define WM9081_EQ_B3_GAIN_WIDTH 5 /* EQ_B3_GAIN - [15:11] */ +#define WM9081_EQ_B5_GAIN_MASK 0x07C0 /* EQ_B5_GAIN - [10:6] */ +#define WM9081_EQ_B5_GAIN_SHIFT 6 /* EQ_B5_GAIN - [10:6] */ +#define WM9081_EQ_B5_GAIN_WIDTH 5 /* EQ_B5_GAIN - [10:6] */ + +/* + * R44 (0x2C) - EQ 3 + */ +#define WM9081_EQ_B1_A_MASK 0xFFFF /* EQ_B1_A - [15:0] */ +#define WM9081_EQ_B1_A_SHIFT 0 /* EQ_B1_A - [15:0] */ +#define WM9081_EQ_B1_A_WIDTH 16 /* EQ_B1_A - [15:0] */ + +/* + * R45 (0x2D) - EQ 4 + */ +#define WM9081_EQ_B1_B_MASK 0xFFFF /* EQ_B1_B - [15:0] */ +#define WM9081_EQ_B1_B_SHIFT 0 /* EQ_B1_B - [15:0] */ +#define WM9081_EQ_B1_B_WIDTH 16 /* EQ_B1_B - [15:0] */ + +/* + * R46 (0x2E) - EQ 5 + */ +#define WM9081_EQ_B1_PG_MASK 0xFFFF /* EQ_B1_PG - [15:0] */ +#define WM9081_EQ_B1_PG_SHIFT 0 /* EQ_B1_PG - [15:0] */ +#define WM9081_EQ_B1_PG_WIDTH 16 /* EQ_B1_PG - [15:0] */ + +/* + * R47 (0x2F) - EQ 6 + */ +#define WM9081_EQ_B2_A_MASK 0xFFFF /* EQ_B2_A - [15:0] */ +#define WM9081_EQ_B2_A_SHIFT 0 /* EQ_B2_A - [15:0] */ +#define WM9081_EQ_B2_A_WIDTH 16 /* EQ_B2_A - [15:0] */ + +/* + * R48 (0x30) - EQ 7 + */ +#define WM9081_EQ_B2_B_MASK 0xFFFF /* EQ_B2_B - [15:0] */ +#define WM9081_EQ_B2_B_SHIFT 0 /* EQ_B2_B - [15:0] */ +#define WM9081_EQ_B2_B_WIDTH 16 /* EQ_B2_B - [15:0] */ + +/* + * R49 (0x31) - EQ 8 + */ +#define WM9081_EQ_B2_C_MASK 0xFFFF /* EQ_B2_C - [15:0] */ +#define WM9081_EQ_B2_C_SHIFT 0 /* EQ_B2_C - [15:0] */ +#define WM9081_EQ_B2_C_WIDTH 16 /* EQ_B2_C - [15:0] */ + +/* + * R50 (0x32) - EQ 9 + */ +#define WM9081_EQ_B2_PG_MASK 0xFFFF /* EQ_B2_PG - [15:0] */ +#define WM9081_EQ_B2_PG_SHIFT 0 /* EQ_B2_PG - [15:0] */ +#define WM9081_EQ_B2_PG_WIDTH 16 /* EQ_B2_PG - [15:0] */ + +/* + * R51 (0x33) - EQ 10 + */ +#define WM9081_EQ_B4_A_MASK 0xFFFF /* EQ_B4_A - [15:0] */ +#define WM9081_EQ_B4_A_SHIFT 0 /* EQ_B4_A - [15:0] */ +#define WM9081_EQ_B4_A_WIDTH 16 /* EQ_B4_A - [15:0] */ + +/* + * R52 (0x34) - EQ 11 + */ +#define WM9081_EQ_B4_B_MASK 0xFFFF /* EQ_B4_B - [15:0] */ +#define WM9081_EQ_B4_B_SHIFT 0 /* EQ_B4_B - [15:0] */ +#define WM9081_EQ_B4_B_WIDTH 16 /* EQ_B4_B - [15:0] */ + +/* + * R53 (0x35) - EQ 12 + */ +#define WM9081_EQ_B4_C_MASK 0xFFFF /* EQ_B4_C - [15:0] */ +#define WM9081_EQ_B4_C_SHIFT 0 /* EQ_B4_C - [15:0] */ +#define WM9081_EQ_B4_C_WIDTH 16 /* EQ_B4_C - [15:0] */ + +/* + * R54 (0x36) - EQ 13 + */ +#define WM9081_EQ_B4_PG_MASK 0xFFFF /* EQ_B4_PG - [15:0] */ +#define WM9081_EQ_B4_PG_SHIFT 0 /* EQ_B4_PG - [15:0] */ +#define WM9081_EQ_B4_PG_WIDTH 16 /* EQ_B4_PG - [15:0] */ + +/* + * R55 (0x37) - EQ 14 + */ +#define WM9081_EQ_B3_A_MASK 0xFFFF /* EQ_B3_A - [15:0] */ +#define WM9081_EQ_B3_A_SHIFT 0 /* EQ_B3_A - [15:0] */ +#define WM9081_EQ_B3_A_WIDTH 16 /* EQ_B3_A - [15:0] */ + +/* + * R56 (0x38) - EQ 15 + */ +#define WM9081_EQ_B3_B_MASK 0xFFFF /* EQ_B3_B - [15:0] */ +#define WM9081_EQ_B3_B_SHIFT 0 /* EQ_B3_B - [15:0] */ +#define WM9081_EQ_B3_B_WIDTH 16 /* EQ_B3_B - [15:0] */ + +/* + * R57 (0x39) - EQ 16 + */ +#define WM9081_EQ_B3_C_MASK 0xFFFF /* EQ_B3_C - [15:0] */ +#define WM9081_EQ_B3_C_SHIFT 0 /* EQ_B3_C - [15:0] */ +#define WM9081_EQ_B3_C_WIDTH 16 /* EQ_B3_C - [15:0] */ + +/* + * R58 (0x3A) - EQ 17 + */ +#define WM9081_EQ_B3_PG_MASK 0xFFFF /* EQ_B3_PG - [15:0] */ +#define WM9081_EQ_B3_PG_SHIFT 0 /* EQ_B3_PG - [15:0] */ +#define WM9081_EQ_B3_PG_WIDTH 16 /* EQ_B3_PG - [15:0] */ + +/* + * R59 (0x3B) - EQ 18 + */ +#define WM9081_EQ_B5_A_MASK 0xFFFF /* EQ_B5_A - [15:0] */ +#define WM9081_EQ_B5_A_SHIFT 0 /* EQ_B5_A - [15:0] */ +#define WM9081_EQ_B5_A_WIDTH 16 /* EQ_B5_A - [15:0] */ + +/* + * R60 (0x3C) - EQ 19 + */ +#define WM9081_EQ_B5_B_MASK 0xFFFF /* EQ_B5_B - [15:0] */ +#define WM9081_EQ_B5_B_SHIFT 0 /* EQ_B5_B - [15:0] */ +#define WM9081_EQ_B5_B_WIDTH 16 /* EQ_B5_B - [15:0] */ + +/* + * R61 (0x3D) - EQ 20 + */ +#define WM9081_EQ_B5_PG_MASK 0xFFFF /* EQ_B5_PG - [15:0] */ +#define WM9081_EQ_B5_PG_SHIFT 0 /* EQ_B5_PG - [15:0] */ +#define WM9081_EQ_B5_PG_WIDTH 16 /* EQ_B5_PG - [15:0] */ + + +#endif diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c index c2d1a7a18fa3..fa88b463e71f 100644 --- a/sound/soc/codecs/wm9705.c +++ b/sound/soc/codecs/wm9705.c @@ -282,14 +282,14 @@ struct snd_soc_dai wm9705_dai[] = { .channels_min = 1, .channels_max = 2, .rates = WM9705_AC97_RATES, - .formats = SNDRV_PCM_FMTBIT_S16_LE, + .formats = SND_SOC_STD_AC97_FMTS, }, .capture = { .stream_name = "HiFi Capture", .channels_min = 1, .channels_max = 2, .rates = WM9705_AC97_RATES, - .formats = SNDRV_PCM_FMTBIT_S16_LE, + .formats = SND_SOC_STD_AC97_FMTS, }, .ops = &wm9705_dai_ops, }, diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index 765cf1e7369e..1fd4e88f50cf 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -534,13 +534,13 @@ struct snd_soc_dai wm9712_dai[] = { .channels_min = 1, .channels_max = 2, .rates = WM9712_AC97_RATES, - .formats = SNDRV_PCM_FMTBIT_S16_LE,}, + .formats = SND_SOC_STD_AC97_FMTS,}, .capture = { .stream_name = "HiFi Capture", .channels_min = 1, .channels_max = 2, .rates = WM9712_AC97_RATES, - .formats = SNDRV_PCM_FMTBIT_S16_LE,}, + .formats = SND_SOC_STD_AC97_FMTS,}, .ops = &wm9712_dai_ops_hifi, }, { @@ -550,7 +550,7 @@ struct snd_soc_dai wm9712_dai[] = { .channels_min = 1, .channels_max = 1, .rates = WM9712_AC97_RATES, - .formats = SNDRV_PCM_FMTBIT_S16_LE,}, + .formats = SND_SOC_STD_AC97_FMTS,}, .ops = &wm9712_dai_ops_aux, } }; @@ -585,6 +585,8 @@ static int wm9712_reset(struct snd_soc_codec *codec, int try_warm) } soc_ac97_ops.reset(codec->ac97); + if (soc_ac97_ops.warm_reset) + soc_ac97_ops.warm_reset(codec->ac97); if (ac97_read(codec, 0) != wm9712_reg[0]) goto err; return 0; diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index 523bad077fa0..abed37acf787 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -189,6 +189,26 @@ SOC_SINGLE("3D Lower Cut-off Switch", AC97_REC_GAIN_MIC, 4, 1, 0), SOC_SINGLE("3D Depth", AC97_REC_GAIN_MIC, 0, 15, 1), }; +static int wm9713_voice_shutdown(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + u16 status, rate; + + BUG_ON(event != SND_SOC_DAPM_PRE_PMD); + + /* Gracefully shut down the voice interface. */ + status = ac97_read(codec, AC97_EXTENDED_MID) | 0x1000; + rate = ac97_read(codec, AC97_HANDSET_RATE) & 0xF0FF; + ac97_write(codec, AC97_HANDSET_RATE, rate | 0x0200); + schedule_timeout_interruptible(msecs_to_jiffies(1)); + ac97_write(codec, AC97_HANDSET_RATE, rate | 0x0F00); + ac97_write(codec, AC97_EXTENDED_MID, status); + + return 0; +} + + /* We have to create a fake left and right HP mixers because * the codec only has a single control that is shared by both channels. * This makes it impossible to determine the audio path using the current @@ -400,7 +420,8 @@ SND_SOC_DAPM_MIXER("AC97 Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("HP Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("Line Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("Capture Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), -SND_SOC_DAPM_DAC("Voice DAC", "Voice Playback", AC97_EXTENDED_MID, 12, 1), +SND_SOC_DAPM_DAC_E("Voice DAC", "Voice Playback", AC97_EXTENDED_MID, 12, 1, + wm9713_voice_shutdown, SND_SOC_DAPM_PRE_PMD), SND_SOC_DAPM_DAC("Aux DAC", "Aux Playback", AC97_EXTENDED_MID, 11, 1), SND_SOC_DAPM_PGA("Left ADC", AC97_EXTENDED_MID, 5, 1, NULL, 0), SND_SOC_DAPM_PGA("Right ADC", AC97_EXTENDED_MID, 4, 1, NULL, 0), @@ -689,7 +710,7 @@ static void pll_factors(struct _pll_div *pll_div, unsigned int source) Ndiv = target / source; if ((Ndiv < 5) || (Ndiv > 12)) printk(KERN_WARNING - "WM9713 PLL N value %d out of recommended range!\n", + "WM9713 PLL N value %u out of recommended range!\n", Ndiv); pll_div->n = Ndiv; @@ -936,21 +957,6 @@ static int wm9713_pcm_hw_params(struct snd_pcm_substream *substream, return 0; } -static void wm9713_voiceshutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_codec *codec = dai->codec; - u16 status, rate; - - /* Gracefully shut down the voice interface. */ - status = ac97_read(codec, AC97_EXTENDED_STATUS) | 0x1000; - rate = ac97_read(codec, AC97_HANDSET_RATE) & 0xF0FF; - ac97_write(codec, AC97_HANDSET_RATE, rate | 0x0200); - schedule_timeout_interruptible(msecs_to_jiffies(1)); - ac97_write(codec, AC97_HANDSET_RATE, rate | 0x0F00); - ac97_write(codec, AC97_EXTENDED_MID, status); -} - static int ac97_hifi_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -1019,7 +1025,6 @@ static struct snd_soc_dai_ops wm9713_dai_ops_aux = { static struct snd_soc_dai_ops wm9713_dai_ops_voice = { .hw_params = wm9713_pcm_hw_params, - .shutdown = wm9713_voiceshutdown, .set_clkdiv = wm9713_set_dai_clkdiv, .set_pll = wm9713_set_dai_pll, .set_fmt = wm9713_set_dai_fmt, @@ -1035,13 +1040,13 @@ struct snd_soc_dai wm9713_dai[] = { .channels_min = 1, .channels_max = 2, .rates = WM9713_RATES, - .formats = SNDRV_PCM_FMTBIT_S16_LE,}, + .formats = SND_SOC_STD_AC97_FMTS,}, .capture = { .stream_name = "HiFi Capture", .channels_min = 1, .channels_max = 2, .rates = WM9713_RATES, - .formats = SNDRV_PCM_FMTBIT_S16_LE,}, + .formats = SND_SOC_STD_AC97_FMTS,}, .ops = &wm9713_dai_ops_hifi, }, { @@ -1051,7 +1056,7 @@ struct snd_soc_dai wm9713_dai[] = { .channels_min = 1, .channels_max = 1, .rates = WM9713_RATES, - .formats = SNDRV_PCM_FMTBIT_S16_LE,}, + .formats = SND_SOC_STD_AC97_FMTS,}, .ops = &wm9713_dai_ops_aux, }, { @@ -1069,6 +1074,7 @@ struct snd_soc_dai wm9713_dai[] = { .rates = WM9713_PCM_RATES, .formats = WM9713_PCM_FORMATS,}, .ops = &wm9713_dai_ops_voice, + .symmetric_rates = 1, }, }; EXPORT_SYMBOL_GPL(wm9713_dai); diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 9fc908283371..5dbebf82249c 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -1,5 +1,8 @@ config SND_SOC_OF_SIMPLE tristate + +config SND_MPC52xx_DMA + tristate # ASoC platform support for the Freescale MPC8610 SOC. This compiles drivers # for the SSI and the Elo DMA controller. You will still need to select @@ -22,7 +25,34 @@ config SND_SOC_MPC8610_HPCD config SND_SOC_MPC5200_I2S tristate "Freescale MPC5200 PSC in I2S mode driver" depends on PPC_MPC52xx && PPC_BESTCOMM - select SND_SOC_OF_SIMPLE + select SND_MPC52xx_DMA select PPC_BESTCOMM_GEN_BD help Say Y here to support the MPC5200 PSCs in I2S mode. + +config SND_SOC_MPC5200_AC97 + tristate "Freescale MPC5200 PSC in AC97 mode driver" + depends on PPC_MPC52xx && PPC_BESTCOMM + select AC97_BUS + select SND_MPC52xx_DMA + select PPC_BESTCOMM_GEN_BD + help + Say Y here to support the MPC5200 PSCs in AC97 mode. + +config SND_MPC52xx_SOC_PCM030 + tristate "SoC AC97 Audio support for Phytec pcm030 and WM9712" + depends on PPC_MPC5200_SIMPLE && BROKEN + select SND_SOC_MPC5200_AC97 + select SND_SOC_WM9712 + help + Say Y if you want to add support for sound on the Phytec pcm030 + baseboard. + +config SND_MPC52xx_SOC_EFIKA + tristate "SoC AC97 Audio support for bbplan Efika and STAC9766" + depends on PPC_EFIKA && BROKEN + select SND_SOC_MPC5200_AC97 + select SND_SOC_STAC9766 + help + Say Y if you want to add support for sound on the Efika. + diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index f85134c86387..a83a73967ec6 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile @@ -10,5 +10,12 @@ snd-soc-fsl-ssi-objs := fsl_ssi.o snd-soc-fsl-dma-objs := fsl_dma.o obj-$(CONFIG_SND_SOC_MPC8610) += snd-soc-fsl-ssi.o snd-soc-fsl-dma.o +# MPC5200 Platform Support +obj-$(CONFIG_SND_MPC52xx_DMA) += mpc5200_dma.o obj-$(CONFIG_SND_SOC_MPC5200_I2S) += mpc5200_psc_i2s.o +obj-$(CONFIG_SND_SOC_MPC5200_AC97) += mpc5200_psc_ac97.o + +# MPC5200 Machine Support +obj-$(CONFIG_SND_MPC52xx_SOC_PCM030) += pcm030-audio-fabric.o +obj-$(CONFIG_SND_MPC52xx_SOC_EFIKA) += efika-audio-fabric.o diff --git a/sound/soc/fsl/efika-audio-fabric.c b/sound/soc/fsl/efika-audio-fabric.c new file mode 100644 index 000000000000..85b0e7569504 --- /dev/null +++ b/sound/soc/fsl/efika-audio-fabric.c @@ -0,0 +1,90 @@ +/* + * Efika driver for the PSC of the Freescale MPC52xx + * configured as AC97 interface + * + * Copyright 2008 Jon Smirl, Digispeaker + * Author: Jon Smirl + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "mpc5200_dma.h" +#include "mpc5200_psc_ac97.h" +#include "../codecs/stac9766.h" + +static struct snd_soc_device device; +static struct snd_soc_card card; + +static struct snd_soc_dai_link efika_fabric_dai[] = { +{ + .name = "AC97", + .stream_name = "AC97 Analog", + .codec_dai = &stac9766_dai[STAC9766_DAI_AC97_ANALOG], + .cpu_dai = &psc_ac97_dai[MPC5200_AC97_NORMAL], +}, +{ + .name = "AC97", + .stream_name = "AC97 IEC958", + .codec_dai = &stac9766_dai[STAC9766_DAI_AC97_DIGITAL], + .cpu_dai = &psc_ac97_dai[MPC5200_AC97_SPDIF], +}, +}; + +static __init int efika_fabric_init(void) +{ + struct platform_device *pdev; + int rc; + + if (!machine_is_compatible("bplan,efika")) + return -ENODEV; + + card.platform = &mpc5200_audio_dma_platform; + card.name = "Efika"; + card.dai_link = efika_fabric_dai; + card.num_links = ARRAY_SIZE(efika_fabric_dai); + + device.card = &card; + device.codec_dev = &soc_codec_dev_stac9766; + + pdev = platform_device_alloc("soc-audio", 1); + if (!pdev) { + pr_err("efika_fabric_init: platform_device_alloc() failed\n"); + return -ENODEV; + } + + platform_set_drvdata(pdev, &device); + device.dev = &pdev->dev; + + rc = platform_device_add(pdev); + if (rc) { + pr_err("efika_fabric_init: platform_device_add() failed\n"); + return -ENODEV; + } + return 0; +} + +module_init(efika_fabric_init); + + +MODULE_AUTHOR("Jon Smirl "); +MODULE_DESCRIPTION(DRV_NAME ": mpc5200 Efika fabric driver"); +MODULE_LICENSE("GPL"); + diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 3711d8454d96..93f0f38a32c9 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -375,18 +375,14 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream, struct snd_pcm_runtime *first_runtime = ssi_private->first_stream->runtime; - if (!first_runtime->rate || !first_runtime->sample_bits) { + if (!first_runtime->sample_bits) { dev_err(substream->pcm->card->dev, - "set sample rate and size in %s stream first\n", + "set sample size in %s stream first\n", substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? "capture" : "playback"); return -EAGAIN; } - snd_pcm_hw_constraint_minmax(substream->runtime, - SNDRV_PCM_HW_PARAM_RATE, - first_runtime->rate, first_runtime->rate); - /* If we're in synchronous mode, then we need to constrain * the sample size as well. We don't support independent sample * rates in asynchronous mode. @@ -674,7 +670,7 @@ struct snd_soc_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info) ssi_private->dev = ssi_info->dev; ssi_private->asynchronous = ssi_info->asynchronous; - ssi_private->dev->driver_data = fsl_ssi_dai; + dev_set_drvdata(ssi_private->dev, fsl_ssi_dai); /* Initialize the the device_attribute structure */ dev_attr->attr.name = "ssi-stats"; @@ -693,6 +689,7 @@ struct snd_soc_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info) fsl_ssi_dai->name = ssi_private->name; fsl_ssi_dai->id = ssi_info->id; fsl_ssi_dai->dev = ssi_info->dev; + fsl_ssi_dai->symmetric_rates = 1; ret = snd_soc_register_dai(fsl_ssi_dai); if (ret != 0) { diff --git a/sound/soc/fsl/mpc5200_dma.c b/sound/soc/fsl/mpc5200_dma.c new file mode 100644 index 000000000000..efec33a1c5bd --- /dev/null +++ b/sound/soc/fsl/mpc5200_dma.c @@ -0,0 +1,564 @@ +/* + * Freescale MPC5200 PSC DMA + * ALSA SoC Platform driver + * + * Copyright (C) 2008 Secret Lab Technologies Ltd. + * Copyright (C) 2009 Jon Smirl, Digispeaker + */ + +#include +#include + +#include + +#include +#include +#include + +#include "mpc5200_dma.h" + +/* + * Interrupt handlers + */ +static irqreturn_t psc_dma_status_irq(int irq, void *_psc_dma) +{ + struct psc_dma *psc_dma = _psc_dma; + struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs; + u16 isr; + + isr = in_be16(®s->mpc52xx_psc_isr); + + /* Playback underrun error */ + if (psc_dma->playback.active && (isr & MPC52xx_PSC_IMR_TXEMP)) + psc_dma->stats.underrun_count++; + + /* Capture overrun error */ + if (psc_dma->capture.active && (isr & MPC52xx_PSC_IMR_ORERR)) + psc_dma->stats.overrun_count++; + + out_8(®s->command, MPC52xx_PSC_RST_ERR_STAT); + + return IRQ_HANDLED; +} + +/** + * psc_dma_bcom_enqueue_next_buffer - Enqueue another audio buffer + * @s: pointer to stream private data structure + * + * Enqueues another audio period buffer into the bestcomm queue. + * + * Note: The routine must only be called when there is space available in + * the queue. Otherwise the enqueue will fail and the audio ring buffer + * will get out of sync + */ +static void psc_dma_bcom_enqueue_next_buffer(struct psc_dma_stream *s) +{ + struct bcom_bd *bd; + + /* Prepare and enqueue the next buffer descriptor */ + bd = bcom_prepare_next_buffer(s->bcom_task); + bd->status = s->period_bytes; + bd->data[0] = s->period_next_pt; + bcom_submit_next_buffer(s->bcom_task, NULL); + + /* Update for next period */ + s->period_next_pt += s->period_bytes; + if (s->period_next_pt >= s->period_end) + s->period_next_pt = s->period_start; +} + +static void psc_dma_bcom_enqueue_tx(struct psc_dma_stream *s) +{ + while (s->appl_ptr < s->runtime->control->appl_ptr) { + + if (bcom_queue_full(s->bcom_task)) + return; + + s->appl_ptr += s->period_size; + + psc_dma_bcom_enqueue_next_buffer(s); + } +} + +/* Bestcomm DMA irq handler */ +static irqreturn_t psc_dma_bcom_irq_tx(int irq, void *_psc_dma_stream) +{ + struct psc_dma_stream *s = _psc_dma_stream; + + spin_lock(&s->psc_dma->lock); + /* For each finished period, dequeue the completed period buffer + * and enqueue a new one in it's place. */ + while (bcom_buffer_done(s->bcom_task)) { + bcom_retrieve_buffer(s->bcom_task, NULL, NULL); + + s->period_current_pt += s->period_bytes; + if (s->period_current_pt >= s->period_end) + s->period_current_pt = s->period_start; + } + psc_dma_bcom_enqueue_tx(s); + spin_unlock(&s->psc_dma->lock); + + /* If the stream is active, then also inform the PCM middle layer + * of the period finished event. */ + if (s->active) + snd_pcm_period_elapsed(s->stream); + + return IRQ_HANDLED; +} + +static irqreturn_t psc_dma_bcom_irq_rx(int irq, void *_psc_dma_stream) +{ + struct psc_dma_stream *s = _psc_dma_stream; + + spin_lock(&s->psc_dma->lock); + /* For each finished period, dequeue the completed period buffer + * and enqueue a new one in it's place. */ + while (bcom_buffer_done(s->bcom_task)) { + bcom_retrieve_buffer(s->bcom_task, NULL, NULL); + + s->period_current_pt += s->period_bytes; + if (s->period_current_pt >= s->period_end) + s->period_current_pt = s->period_start; + + psc_dma_bcom_enqueue_next_buffer(s); + } + spin_unlock(&s->psc_dma->lock); + + /* If the stream is active, then also inform the PCM middle layer + * of the period finished event. */ + if (s->active) + snd_pcm_period_elapsed(s->stream); + + return IRQ_HANDLED; +} + +static int psc_dma_hw_free(struct snd_pcm_substream *substream) +{ + snd_pcm_set_runtime_buffer(substream, NULL); + return 0; +} + +/** + * psc_dma_trigger: start and stop the DMA transfer. + * + * This function is called by ALSA to start, stop, pause, and resume the DMA + * transfer of data. + */ +static int psc_dma_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data; + struct snd_pcm_runtime *runtime = substream->runtime; + struct psc_dma_stream *s; + struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs; + u16 imr; + unsigned long flags; + int i; + + if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) + s = &psc_dma->capture; + else + s = &psc_dma->playback; + + dev_dbg(psc_dma->dev, "psc_dma_trigger(substream=%p, cmd=%i)" + " stream_id=%i\n", + substream, cmd, substream->pstr->stream); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + s->period_bytes = frames_to_bytes(runtime, + runtime->period_size); + s->period_start = virt_to_phys(runtime->dma_area); + s->period_end = s->period_start + + (s->period_bytes * runtime->periods); + s->period_next_pt = s->period_start; + s->period_current_pt = s->period_start; + s->period_size = runtime->period_size; + s->active = 1; + + /* track appl_ptr so that we have a better chance of detecting + * end of stream and not over running it. + */ + s->runtime = runtime; + s->appl_ptr = s->runtime->control->appl_ptr - + (runtime->period_size * runtime->periods); + + /* Fill up the bestcomm bd queue and enable DMA. + * This will begin filling the PSC's fifo. + */ + spin_lock_irqsave(&psc_dma->lock, flags); + + if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) { + bcom_gen_bd_rx_reset(s->bcom_task); + for (i = 0; i < runtime->periods; i++) + if (!bcom_queue_full(s->bcom_task)) + psc_dma_bcom_enqueue_next_buffer(s); + } else { + bcom_gen_bd_tx_reset(s->bcom_task); + psc_dma_bcom_enqueue_tx(s); + } + + bcom_enable(s->bcom_task); + spin_unlock_irqrestore(&psc_dma->lock, flags); + + out_8(®s->command, MPC52xx_PSC_RST_ERR_STAT); + + break; + + case SNDRV_PCM_TRIGGER_STOP: + s->active = 0; + + spin_lock_irqsave(&psc_dma->lock, flags); + bcom_disable(s->bcom_task); + if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) + bcom_gen_bd_rx_reset(s->bcom_task); + else + bcom_gen_bd_tx_reset(s->bcom_task); + spin_unlock_irqrestore(&psc_dma->lock, flags); + + break; + + default: + dev_dbg(psc_dma->dev, "invalid command\n"); + return -EINVAL; + } + + /* Update interrupt enable settings */ + imr = 0; + if (psc_dma->playback.active) + imr |= MPC52xx_PSC_IMR_TXEMP; + if (psc_dma->capture.active) + imr |= MPC52xx_PSC_IMR_ORERR; + out_be16(®s->isr_imr.imr, psc_dma->imr | imr); + + return 0; +} + + +/* --------------------------------------------------------------------- + * The PSC DMA 'ASoC platform' driver + * + * Can be referenced by an 'ASoC machine' driver + * This driver only deals with the audio bus; it doesn't have any + * interaction with the attached codec + */ + +static const struct snd_pcm_hardware psc_dma_hardware = { + .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_BATCH, + .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE | + SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE, + .rate_min = 8000, + .rate_max = 48000, + .channels_min = 1, + .channels_max = 2, + .period_bytes_max = 1024 * 1024, + .period_bytes_min = 32, + .periods_min = 2, + .periods_max = 256, + .buffer_bytes_max = 2 * 1024 * 1024, + .fifo_size = 512, +}; + +static int psc_dma_open(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data; + struct psc_dma_stream *s; + int rc; + + dev_dbg(psc_dma->dev, "psc_dma_open(substream=%p)\n", substream); + + if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) + s = &psc_dma->capture; + else + s = &psc_dma->playback; + + snd_soc_set_runtime_hwparams(substream, &psc_dma_hardware); + + rc = snd_pcm_hw_constraint_integer(runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + if (rc < 0) { + dev_err(substream->pcm->card->dev, "invalid buffer size\n"); + return rc; + } + + s->stream = substream; + return 0; +} + +static int psc_dma_close(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data; + struct psc_dma_stream *s; + + dev_dbg(psc_dma->dev, "psc_dma_close(substream=%p)\n", substream); + + if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) + s = &psc_dma->capture; + else + s = &psc_dma->playback; + + if (!psc_dma->playback.active && + !psc_dma->capture.active) { + + /* Disable all interrupts and reset the PSC */ + out_be16(&psc_dma->psc_regs->isr_imr.imr, psc_dma->imr); + out_8(&psc_dma->psc_regs->command, 4 << 4); /* reset error */ + } + s->stream = NULL; + return 0; +} + +static snd_pcm_uframes_t +psc_dma_pointer(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data; + struct psc_dma_stream *s; + dma_addr_t count; + + if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) + s = &psc_dma->capture; + else + s = &psc_dma->playback; + + count = s->period_current_pt - s->period_start; + + return bytes_to_frames(substream->runtime, count); +} + +static int +psc_dma_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); + + return 0; +} + +static struct snd_pcm_ops psc_dma_ops = { + .open = psc_dma_open, + .close = psc_dma_close, + .hw_free = psc_dma_hw_free, + .ioctl = snd_pcm_lib_ioctl, + .pointer = psc_dma_pointer, + .trigger = psc_dma_trigger, + .hw_params = psc_dma_hw_params, +}; + +static u64 psc_dma_dmamask = 0xffffffff; +static int psc_dma_new(struct snd_card *card, struct snd_soc_dai *dai, + struct snd_pcm *pcm) +{ + struct snd_soc_pcm_runtime *rtd = pcm->private_data; + struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data; + size_t size = psc_dma_hardware.buffer_bytes_max; + int rc = 0; + + dev_dbg(rtd->socdev->dev, "psc_dma_new(card=%p, dai=%p, pcm=%p)\n", + card, dai, pcm); + + if (!card->dev->dma_mask) + card->dev->dma_mask = &psc_dma_dmamask; + if (!card->dev->coherent_dma_mask) + card->dev->coherent_dma_mask = 0xffffffff; + + if (pcm->streams[0].substream) { + rc = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->card->dev, + size, &pcm->streams[0].substream->dma_buffer); + if (rc) + goto playback_alloc_err; + } + + if (pcm->streams[1].substream) { + rc = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->card->dev, + size, &pcm->streams[1].substream->dma_buffer); + if (rc) + goto capture_alloc_err; + } + + if (rtd->socdev->card->codec->ac97) + rtd->socdev->card->codec->ac97->private_data = psc_dma; + + return 0; + + capture_alloc_err: + if (pcm->streams[0].substream) + snd_dma_free_pages(&pcm->streams[0].substream->dma_buffer); + + playback_alloc_err: + dev_err(card->dev, "Cannot allocate buffer(s)\n"); + + return -ENOMEM; +} + +static void psc_dma_free(struct snd_pcm *pcm) +{ + struct snd_soc_pcm_runtime *rtd = pcm->private_data; + struct snd_pcm_substream *substream; + int stream; + + dev_dbg(rtd->socdev->dev, "psc_dma_free(pcm=%p)\n", pcm); + + for (stream = 0; stream < 2; stream++) { + substream = pcm->streams[stream].substream; + if (substream) { + snd_dma_free_pages(&substream->dma_buffer); + substream->dma_buffer.area = NULL; + substream->dma_buffer.addr = 0; + } + } +} + +struct snd_soc_platform mpc5200_audio_dma_platform = { + .name = "mpc5200-psc-audio", + .pcm_ops = &psc_dma_ops, + .pcm_new = &psc_dma_new, + .pcm_free = &psc_dma_free, +}; +EXPORT_SYMBOL_GPL(mpc5200_audio_dma_platform); + +int mpc5200_audio_dma_create(struct of_device *op) +{ + phys_addr_t fifo; + struct psc_dma *psc_dma; + struct resource res; + int size, irq, rc; + const __be32 *prop; + void __iomem *regs; + + /* Fetch the registers and IRQ of the PSC */ + irq = irq_of_parse_and_map(op->node, 0); + if (of_address_to_resource(op->node, 0, &res)) { + dev_err(&op->dev, "Missing reg property\n"); + return -ENODEV; + } + regs = ioremap(res.start, 1 + res.end - res.start); + if (!regs) { + dev_err(&op->dev, "Could not map registers\n"); + return -ENODEV; + } + + /* Allocate and initialize the driver private data */ + psc_dma = kzalloc(sizeof *psc_dma, GFP_KERNEL); + if (!psc_dma) { + iounmap(regs); + return -ENOMEM; + } + + /* Get the PSC ID */ + prop = of_get_property(op->node, "cell-index", &size); + if (!prop || size < sizeof *prop) + return -ENODEV; + + spin_lock_init(&psc_dma->lock); + psc_dma->id = be32_to_cpu(*prop); + psc_dma->irq = irq; + psc_dma->psc_regs = regs; + psc_dma->fifo_regs = regs + sizeof *psc_dma->psc_regs; + psc_dma->dev = &op->dev; + psc_dma->playback.psc_dma = psc_dma; + psc_dma->capture.psc_dma = psc_dma; + snprintf(psc_dma->name, sizeof psc_dma->name, "PSC%u", psc_dma->id); + + /* Find the address of the fifo data registers and setup the + * DMA tasks */ + fifo = res.start + offsetof(struct mpc52xx_psc, buffer.buffer_32); + psc_dma->capture.bcom_task = + bcom_psc_gen_bd_rx_init(psc_dma->id, 10, fifo, 512); + psc_dma->playback.bcom_task = + bcom_psc_gen_bd_tx_init(psc_dma->id, 10, fifo); + if (!psc_dma->capture.bcom_task || + !psc_dma->playback.bcom_task) { + dev_err(&op->dev, "Could not allocate bestcomm tasks\n"); + iounmap(regs); + kfree(psc_dma); + return -ENODEV; + } + + /* Disable all interrupts and reset the PSC */ + out_be16(&psc_dma->psc_regs->isr_imr.imr, psc_dma->imr); + /* reset receiver */ + out_8(&psc_dma->psc_regs->command, MPC52xx_PSC_RST_RX); + /* reset transmitter */ + out_8(&psc_dma->psc_regs->command, MPC52xx_PSC_RST_TX); + /* reset error */ + out_8(&psc_dma->psc_regs->command, MPC52xx_PSC_RST_ERR_STAT); + /* reset mode */ + out_8(&psc_dma->psc_regs->command, MPC52xx_PSC_SEL_MODE_REG_1); + + /* Set up mode register; + * First write: RxRdy (FIFO Alarm) generates rx FIFO irq + * Second write: register Normal mode for non loopback + */ + out_8(&psc_dma->psc_regs->mode, 0); + out_8(&psc_dma->psc_regs->mode, 0); + + /* Set the TX and RX fifo alarm thresholds */ + out_be16(&psc_dma->fifo_regs->rfalarm, 0x100); + out_8(&psc_dma->fifo_regs->rfcntl, 0x4); + out_be16(&psc_dma->fifo_regs->tfalarm, 0x100); + out_8(&psc_dma->fifo_regs->tfcntl, 0x7); + + /* Lookup the IRQ numbers */ + psc_dma->playback.irq = + bcom_get_task_irq(psc_dma->playback.bcom_task); + psc_dma->capture.irq = + bcom_get_task_irq(psc_dma->capture.bcom_task); + + rc = request_irq(psc_dma->irq, &psc_dma_status_irq, IRQF_SHARED, + "psc-dma-status", psc_dma); + rc |= request_irq(psc_dma->capture.irq, + &psc_dma_bcom_irq_rx, IRQF_SHARED, + "psc-dma-capture", &psc_dma->capture); + rc |= request_irq(psc_dma->playback.irq, + &psc_dma_bcom_irq_tx, IRQF_SHARED, + "psc-dma-playback", &psc_dma->playback); + if (rc) { + free_irq(psc_dma->irq, psc_dma); + free_irq(psc_dma->capture.irq, + &psc_dma->capture); + free_irq(psc_dma->playback.irq, + &psc_dma->playback); + return -ENODEV; + } + + /* Save what we've done so it can be found again later */ + dev_set_drvdata(&op->dev, psc_dma); + + /* Tell the ASoC OF helpers about it */ + return snd_soc_register_platform(&mpc5200_audio_dma_platform); +} +EXPORT_SYMBOL_GPL(mpc5200_audio_dma_create); + +int mpc5200_audio_dma_destroy(struct of_device *op) +{ + struct psc_dma *psc_dma = dev_get_drvdata(&op->dev); + + dev_dbg(&op->dev, "mpc5200_audio_dma_destroy()\n"); + + snd_soc_unregister_platform(&mpc5200_audio_dma_platform); + + bcom_gen_bd_rx_release(psc_dma->capture.bcom_task); + bcom_gen_bd_tx_release(psc_dma->playback.bcom_task); + + /* Release irqs */ + free_irq(psc_dma->irq, psc_dma); + free_irq(psc_dma->capture.irq, &psc_dma->capture); + free_irq(psc_dma->playback.irq, &psc_dma->playback); + + iounmap(psc_dma->psc_regs); + kfree(psc_dma); + dev_set_drvdata(&op->dev, NULL); + + return 0; +} +EXPORT_SYMBOL_GPL(mpc5200_audio_dma_destroy); + +MODULE_AUTHOR("Grant Likely "); +MODULE_DESCRIPTION("Freescale MPC5200 PSC in DMA mode ASoC Driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/fsl/mpc5200_dma.h b/sound/soc/fsl/mpc5200_dma.h new file mode 100644 index 000000000000..2000803f06a7 --- /dev/null +++ b/sound/soc/fsl/mpc5200_dma.h @@ -0,0 +1,80 @@ +/* + * Freescale MPC5200 Audio DMA driver + */ + +#ifndef __SOUND_SOC_FSL_MPC5200_DMA_H__ +#define __SOUND_SOC_FSL_MPC5200_DMA_H__ + +#define PSC_STREAM_NAME_LEN 32 + +/** + * psc_ac97_stream - Data specific to a single stream (playback or capture) + * @active: flag indicating if the stream is active + * @psc_dma: pointer back to parent psc_dma data structure + * @bcom_task: bestcomm task structure + * @irq: irq number for bestcomm task + * @period_start: physical address of start of DMA region + * @period_end: physical address of end of DMA region + * @period_next_pt: physical address of next DMA buffer to enqueue + * @period_bytes: size of DMA period in bytes + */ +struct psc_dma_stream { + struct snd_pcm_runtime *runtime; + snd_pcm_uframes_t appl_ptr; + + int active; + struct psc_dma *psc_dma; + struct bcom_task *bcom_task; + int irq; + struct snd_pcm_substream *stream; + dma_addr_t period_start; + dma_addr_t period_end; + dma_addr_t period_next_pt; + dma_addr_t period_current_pt; + int period_bytes; + int period_size; +}; + +/** + * psc_dma - Private driver data + * @name: short name for this device ("PSC0", "PSC1", etc) + * @psc_regs: pointer to the PSC's registers + * @fifo_regs: pointer to the PSC's FIFO registers + * @irq: IRQ of this PSC + * @dev: struct device pointer + * @dai: the CPU DAI for this device + * @sicr: Base value used in serial interface control register; mode is ORed + * with this value. + * @playback: Playback stream context data + * @capture: Capture stream context data + */ +struct psc_dma { + char name[32]; + struct mpc52xx_psc __iomem *psc_regs; + struct mpc52xx_psc_fifo __iomem *fifo_regs; + unsigned int irq; + struct device *dev; + spinlock_t lock; + u32 sicr; + uint sysclk; + int imr; + int id; + unsigned int slots; + + /* per-stream data */ + struct psc_dma_stream playback; + struct psc_dma_stream capture; + + /* Statistics */ + struct { + unsigned long overrun_count; + unsigned long underrun_count; + } stats; +}; + +int mpc5200_audio_dma_create(struct of_device *op); +int mpc5200_audio_dma_destroy(struct of_device *op); + +extern struct snd_soc_platform mpc5200_audio_dma_platform; + +#endif /* __SOUND_SOC_FSL_MPC5200_DMA_H__ */ diff --git a/sound/soc/fsl/mpc5200_psc_ac97.c b/sound/soc/fsl/mpc5200_psc_ac97.c new file mode 100644 index 000000000000..794a247b3eb5 --- /dev/null +++ b/sound/soc/fsl/mpc5200_psc_ac97.c @@ -0,0 +1,329 @@ +/* + * linux/sound/mpc5200-ac97.c -- AC97 support for the Freescale MPC52xx chip. + * + * Copyright (C) 2009 Jon Smirl, Digispeaker + * Author: Jon Smirl + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include "mpc5200_dma.h" +#include "mpc5200_psc_ac97.h" + +#define DRV_NAME "mpc5200-psc-ac97" + +/* ALSA only supports a single AC97 device so static is recommend here */ +static struct psc_dma *psc_dma; + +static unsigned short psc_ac97_read(struct snd_ac97 *ac97, unsigned short reg) +{ + int status; + unsigned int val; + + /* Wait for command send status zero = ready */ + status = spin_event_timeout(!(in_be16(&psc_dma->psc_regs->sr_csr.status) & + MPC52xx_PSC_SR_CMDSEND), 100, 0); + if (status == 0) { + pr_err("timeout on ac97 bus (rdy)\n"); + return -ENODEV; + } + /* Send the read */ + out_be32(&psc_dma->psc_regs->ac97_cmd, (1<<31) | ((reg & 0x7f) << 24)); + + /* Wait for the answer */ + status = spin_event_timeout((in_be16(&psc_dma->psc_regs->sr_csr.status) & + MPC52xx_PSC_SR_DATA_VAL), 100, 0); + if (status == 0) { + pr_err("timeout on ac97 read (val) %x\n", + in_be16(&psc_dma->psc_regs->sr_csr.status)); + return -ENODEV; + } + /* Get the data */ + val = in_be32(&psc_dma->psc_regs->ac97_data); + if (((val >> 24) & 0x7f) != reg) { + pr_err("reg echo error on ac97 read\n"); + return -ENODEV; + } + val = (val >> 8) & 0xffff; + + return (unsigned short) val; +} + +static void psc_ac97_write(struct snd_ac97 *ac97, + unsigned short reg, unsigned short val) +{ + int status; + + /* Wait for command status zero = ready */ + status = spin_event_timeout(!(in_be16(&psc_dma->psc_regs->sr_csr.status) & + MPC52xx_PSC_SR_CMDSEND), 100, 0); + if (status == 0) { + pr_err("timeout on ac97 bus (write)\n"); + return; + } + /* Write data */ + out_be32(&psc_dma->psc_regs->ac97_cmd, + ((reg & 0x7f) << 24) | (val << 8)); +} + +static void psc_ac97_warm_reset(struct snd_ac97 *ac97) +{ + struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs; + + out_be32(®s->sicr, psc_dma->sicr | MPC52xx_PSC_SICR_AWR); + udelay(3); + out_be32(®s->sicr, psc_dma->sicr); +} + +static void psc_ac97_cold_reset(struct snd_ac97 *ac97) +{ + struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs; + + /* Do a cold reset */ + out_8(®s->op1, MPC52xx_PSC_OP_RES); + udelay(10); + out_8(®s->op0, MPC52xx_PSC_OP_RES); + udelay(50); + psc_ac97_warm_reset(ac97); +} + +struct snd_ac97_bus_ops soc_ac97_ops = { + .read = psc_ac97_read, + .write = psc_ac97_write, + .reset = psc_ac97_cold_reset, + .warm_reset = psc_ac97_warm_reset, +}; +EXPORT_SYMBOL_GPL(soc_ac97_ops); + +static int psc_ac97_hw_analog_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *cpu_dai) +{ + struct psc_dma *psc_dma = cpu_dai->private_data; + + dev_dbg(psc_dma->dev, "%s(substream=%p) p_size=%i p_bytes=%i" + " periods=%i buffer_size=%i buffer_bytes=%i channels=%i" + " rate=%i format=%i\n", + __func__, substream, params_period_size(params), + params_period_bytes(params), params_periods(params), + params_buffer_size(params), params_buffer_bytes(params), + params_channels(params), params_rate(params), + params_format(params)); + + + if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) { + if (params_channels(params) == 1) + psc_dma->slots |= 0x00000100; + else + psc_dma->slots |= 0x00000300; + } else { + if (params_channels(params) == 1) + psc_dma->slots |= 0x01000000; + else + psc_dma->slots |= 0x03000000; + } + out_be32(&psc_dma->psc_regs->ac97_slots, psc_dma->slots); + + return 0; +} + +static int psc_ac97_hw_digital_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *cpu_dai) +{ + struct psc_dma *psc_dma = cpu_dai->private_data; + + if (params_channels(params) == 1) + out_be32(&psc_dma->psc_regs->ac97_slots, 0x01000000); + else + out_be32(&psc_dma->psc_regs->ac97_slots, 0x03000000); + + return 0; +} + +static int psc_ac97_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_STOP: + if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) + psc_dma->slots &= 0xFFFF0000; + else + psc_dma->slots &= 0x0000FFFF; + + out_be32(&psc_dma->psc_regs->ac97_slots, psc_dma->slots); + break; + } + return 0; +} + +static int psc_ac97_probe(struct platform_device *pdev, + struct snd_soc_dai *cpu_dai) +{ + struct psc_dma *psc_dma = cpu_dai->private_data; + struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs; + + /* Go */ + out_8(®s->command, MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE); + return 0; +} + +/* --------------------------------------------------------------------- + * ALSA SoC Bindings + * + * - Digital Audio Interface (DAI) template + * - create/destroy dai hooks + */ + +/** + * psc_ac97_dai_template: template CPU Digital Audio Interface + */ +static struct snd_soc_dai_ops psc_ac97_analog_ops = { + .hw_params = psc_ac97_hw_analog_params, + .trigger = psc_ac97_trigger, +}; + +static struct snd_soc_dai_ops psc_ac97_digital_ops = { + .hw_params = psc_ac97_hw_digital_params, +}; + +struct snd_soc_dai psc_ac97_dai[] = { +{ + .name = "AC97", + .ac97_control = 1, + .probe = psc_ac97_probe, + .playback = { + .channels_min = 1, + .channels_max = 6, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S32_BE, + }, + .capture = { + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S32_BE, + }, + .ops = &psc_ac97_analog_ops, +}, +{ + .name = "SPDIF", + .ac97_control = 1, + .playback = { + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_32000 | \ + SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE, + }, + .ops = &psc_ac97_digital_ops, +} }; +EXPORT_SYMBOL_GPL(psc_ac97_dai); + + + +/* --------------------------------------------------------------------- + * OF platform bus binding code: + * - Probe/remove operations + * - OF device match table + */ +static int __devinit psc_ac97_of_probe(struct of_device *op, + const struct of_device_id *match) +{ + int rc, i; + struct snd_ac97 ac97; + struct mpc52xx_psc __iomem *regs; + + rc = mpc5200_audio_dma_create(op); + if (rc != 0) + return rc; + + for (i = 0; i < ARRAY_SIZE(psc_ac97_dai); i++) + psc_ac97_dai[i].dev = &op->dev; + + rc = snd_soc_register_dais(psc_ac97_dai, ARRAY_SIZE(psc_ac97_dai)); + if (rc != 0) { + dev_err(&op->dev, "Failed to register DAI\n"); + return rc; + } + + psc_dma = dev_get_drvdata(&op->dev); + regs = psc_dma->psc_regs; + ac97.private_data = psc_dma; + + for (i = 0; i < ARRAY_SIZE(psc_ac97_dai); i++) + psc_ac97_dai[i].private_data = psc_dma; + + psc_dma->imr = 0; + out_be16(&psc_dma->psc_regs->isr_imr.imr, psc_dma->imr); + + /* Configure the serial interface mode to AC97 */ + psc_dma->sicr = MPC52xx_PSC_SICR_SIM_AC97 | MPC52xx_PSC_SICR_ENAC97; + out_be32(®s->sicr, psc_dma->sicr); + + /* No slots active */ + out_be32(®s->ac97_slots, 0x00000000); + + return 0; +} + +static int __devexit psc_ac97_of_remove(struct of_device *op) +{ + return mpc5200_audio_dma_destroy(op); +} + +/* Match table for of_platform binding */ +static struct of_device_id psc_ac97_match[] __devinitdata = { + { .compatible = "fsl,mpc5200-psc-ac97", }, + { .compatible = "fsl,mpc5200b-psc-ac97", }, + {} +}; +MODULE_DEVICE_TABLE(of, psc_ac97_match); + +static struct of_platform_driver psc_ac97_driver = { + .match_table = psc_ac97_match, + .probe = psc_ac97_of_probe, + .remove = __devexit_p(psc_ac97_of_remove), + .driver = { + .name = "mpc5200-psc-ac97", + .owner = THIS_MODULE, + }, +}; + +/* --------------------------------------------------------------------- + * Module setup and teardown; simply register the of_platform driver + * for the PSC in AC97 mode. + */ +static int __init psc_ac97_init(void) +{ + return of_register_platform_driver(&psc_ac97_driver); +} +module_init(psc_ac97_init); + +static void __exit psc_ac97_exit(void) +{ + of_unregister_platform_driver(&psc_ac97_driver); +} +module_exit(psc_ac97_exit); + +MODULE_AUTHOR("Jon Smirl "); +MODULE_DESCRIPTION("mpc5200 AC97 module"); +MODULE_LICENSE("GPL"); + diff --git a/sound/soc/fsl/mpc5200_psc_ac97.h b/sound/soc/fsl/mpc5200_psc_ac97.h new file mode 100644 index 000000000000..4bc18c35c369 --- /dev/null +++ b/sound/soc/fsl/mpc5200_psc_ac97.h @@ -0,0 +1,15 @@ +/* + * Freescale MPC5200 PSC in AC97 mode + * ALSA SoC Digital Audio Interface (DAI) driver + * + */ + +#ifndef __SOUND_SOC_FSL_MPC52xx_PSC_AC97_H__ +#define __SOUND_SOC_FSL_MPC52xx_PSC_AC97_H__ + +extern struct snd_soc_dai psc_ac97_dai[]; + +#define MPC5200_AC97_NORMAL 0 +#define MPC5200_AC97_SPDIF 1 + +#endif /* __SOUND_SOC_FSL_MPC52xx_PSC_AC97_H__ */ diff --git a/sound/soc/fsl/mpc5200_psc_i2s.c b/sound/soc/fsl/mpc5200_psc_i2s.c index 1111c710118a..ce8de90fb94a 100644 --- a/sound/soc/fsl/mpc5200_psc_i2s.c +++ b/sound/soc/fsl/mpc5200_psc_i2s.c @@ -3,31 +3,21 @@ * ALSA SoC Digital Audio Interface (DAI) driver * * Copyright (C) 2008 Secret Lab Technologies Ltd. + * Copyright (C) 2009 Jon Smirl, Digispeaker */ -#include #include -#include -#include -#include #include #include -#include -#include #include #include -#include #include -#include -#include -#include #include -MODULE_AUTHOR("Grant Likely "); -MODULE_DESCRIPTION("Freescale MPC5200 PSC in I2S mode ASoC Driver"); -MODULE_LICENSE("GPL"); +#include "mpc5200_psc_i2s.h" +#include "mpc5200_dma.h" /** * PSC_I2S_RATES: sample rates supported by the I2S @@ -44,191 +34,17 @@ MODULE_LICENSE("GPL"); * PSC_I2S_FORMATS: audio formats supported by the PSC I2S mode */ #define PSC_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE | \ - SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S24_BE | \ - SNDRV_PCM_FMTBIT_S32_BE) - -/** - * psc_i2s_stream - Data specific to a single stream (playback or capture) - * @active: flag indicating if the stream is active - * @psc_i2s: pointer back to parent psc_i2s data structure - * @bcom_task: bestcomm task structure - * @irq: irq number for bestcomm task - * @period_start: physical address of start of DMA region - * @period_end: physical address of end of DMA region - * @period_next_pt: physical address of next DMA buffer to enqueue - * @period_bytes: size of DMA period in bytes - */ -struct psc_i2s_stream { - int active; - struct psc_i2s *psc_i2s; - struct bcom_task *bcom_task; - int irq; - struct snd_pcm_substream *stream; - dma_addr_t period_start; - dma_addr_t period_end; - dma_addr_t period_next_pt; - dma_addr_t period_current_pt; - int period_bytes; -}; - -/** - * psc_i2s - Private driver data - * @name: short name for this device ("PSC0", "PSC1", etc) - * @psc_regs: pointer to the PSC's registers - * @fifo_regs: pointer to the PSC's FIFO registers - * @irq: IRQ of this PSC - * @dev: struct device pointer - * @dai: the CPU DAI for this device - * @sicr: Base value used in serial interface control register; mode is ORed - * with this value. - * @playback: Playback stream context data - * @capture: Capture stream context data - */ -struct psc_i2s { - char name[32]; - struct mpc52xx_psc __iomem *psc_regs; - struct mpc52xx_psc_fifo __iomem *fifo_regs; - unsigned int irq; - struct device *dev; - struct snd_soc_dai dai; - spinlock_t lock; - u32 sicr; - - /* per-stream data */ - struct psc_i2s_stream playback; - struct psc_i2s_stream capture; - - /* Statistics */ - struct { - int overrun_count; - int underrun_count; - } stats; -}; - -/* - * Interrupt handlers - */ -static irqreturn_t psc_i2s_status_irq(int irq, void *_psc_i2s) -{ - struct psc_i2s *psc_i2s = _psc_i2s; - struct mpc52xx_psc __iomem *regs = psc_i2s->psc_regs; - u16 isr; - - isr = in_be16(®s->mpc52xx_psc_isr); - - /* Playback underrun error */ - if (psc_i2s->playback.active && (isr & MPC52xx_PSC_IMR_TXEMP)) - psc_i2s->stats.underrun_count++; - - /* Capture overrun error */ - if (psc_i2s->capture.active && (isr & MPC52xx_PSC_IMR_ORERR)) - psc_i2s->stats.overrun_count++; - - out_8(®s->command, 4 << 4); /* reset the error status */ - - return IRQ_HANDLED; -} - -/** - * psc_i2s_bcom_enqueue_next_buffer - Enqueue another audio buffer - * @s: pointer to stream private data structure - * - * Enqueues another audio period buffer into the bestcomm queue. - * - * Note: The routine must only be called when there is space available in - * the queue. Otherwise the enqueue will fail and the audio ring buffer - * will get out of sync - */ -static void psc_i2s_bcom_enqueue_next_buffer(struct psc_i2s_stream *s) -{ - struct bcom_bd *bd; - - /* Prepare and enqueue the next buffer descriptor */ - bd = bcom_prepare_next_buffer(s->bcom_task); - bd->status = s->period_bytes; - bd->data[0] = s->period_next_pt; - bcom_submit_next_buffer(s->bcom_task, NULL); - - /* Update for next period */ - s->period_next_pt += s->period_bytes; - if (s->period_next_pt >= s->period_end) - s->period_next_pt = s->period_start; -} - -/* Bestcomm DMA irq handler */ -static irqreturn_t psc_i2s_bcom_irq(int irq, void *_psc_i2s_stream) -{ - struct psc_i2s_stream *s = _psc_i2s_stream; - - /* For each finished period, dequeue the completed period buffer - * and enqueue a new one in it's place. */ - while (bcom_buffer_done(s->bcom_task)) { - bcom_retrieve_buffer(s->bcom_task, NULL, NULL); - s->period_current_pt += s->period_bytes; - if (s->period_current_pt >= s->period_end) - s->period_current_pt = s->period_start; - psc_i2s_bcom_enqueue_next_buffer(s); - bcom_enable(s->bcom_task); - } - - /* If the stream is active, then also inform the PCM middle layer - * of the period finished event. */ - if (s->active) - snd_pcm_period_elapsed(s->stream); - - return IRQ_HANDLED; -} - -/** - * psc_i2s_startup: create a new substream - * - * This is the first function called when a stream is opened. - * - * If this is the first stream open, then grab the IRQ and program most of - * the PSC registers. - */ -static int psc_i2s_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data; - int rc; - - dev_dbg(psc_i2s->dev, "psc_i2s_startup(substream=%p)\n", substream); - - if (!psc_i2s->playback.active && - !psc_i2s->capture.active) { - /* Setup the IRQs */ - rc = request_irq(psc_i2s->irq, &psc_i2s_status_irq, IRQF_SHARED, - "psc-i2s-status", psc_i2s); - rc |= request_irq(psc_i2s->capture.irq, - &psc_i2s_bcom_irq, IRQF_SHARED, - "psc-i2s-capture", &psc_i2s->capture); - rc |= request_irq(psc_i2s->playback.irq, - &psc_i2s_bcom_irq, IRQF_SHARED, - "psc-i2s-playback", &psc_i2s->playback); - if (rc) { - free_irq(psc_i2s->irq, psc_i2s); - free_irq(psc_i2s->capture.irq, - &psc_i2s->capture); - free_irq(psc_i2s->playback.irq, - &psc_i2s->playback); - return -ENODEV; - } - } - - return 0; -} + SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE) static int psc_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data; + struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data; u32 mode; - dev_dbg(psc_i2s->dev, "%s(substream=%p) p_size=%i p_bytes=%i" + dev_dbg(psc_dma->dev, "%s(substream=%p) p_size=%i p_bytes=%i" " periods=%i buffer_size=%i buffer_bytes=%i\n", __func__, substream, params_period_size(params), params_period_bytes(params), params_periods(params), @@ -248,174 +64,14 @@ static int psc_i2s_hw_params(struct snd_pcm_substream *substream, mode = MPC52xx_PSC_SICR_SIM_CODEC_32; break; default: - dev_dbg(psc_i2s->dev, "invalid format\n"); + dev_dbg(psc_dma->dev, "invalid format\n"); return -EINVAL; } - out_be32(&psc_i2s->psc_regs->sicr, psc_i2s->sicr | mode); - - snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); + out_be32(&psc_dma->psc_regs->sicr, psc_dma->sicr | mode); return 0; } -static int psc_i2s_hw_free(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - snd_pcm_set_runtime_buffer(substream, NULL); - return 0; -} - -/** - * psc_i2s_trigger: start and stop the DMA transfer. - * - * This function is called by ALSA to start, stop, pause, and resume the DMA - * transfer of data. - */ -static int psc_i2s_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data; - struct snd_pcm_runtime *runtime = substream->runtime; - struct psc_i2s_stream *s; - struct mpc52xx_psc __iomem *regs = psc_i2s->psc_regs; - u16 imr; - u8 psc_cmd; - unsigned long flags; - - if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) - s = &psc_i2s->capture; - else - s = &psc_i2s->playback; - - dev_dbg(psc_i2s->dev, "psc_i2s_trigger(substream=%p, cmd=%i)" - " stream_id=%i\n", - substream, cmd, substream->pstr->stream); - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - s->period_bytes = frames_to_bytes(runtime, - runtime->period_size); - s->period_start = virt_to_phys(runtime->dma_area); - s->period_end = s->period_start + - (s->period_bytes * runtime->periods); - s->period_next_pt = s->period_start; - s->period_current_pt = s->period_start; - s->active = 1; - - /* First; reset everything */ - if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) { - out_8(®s->command, MPC52xx_PSC_RST_RX); - out_8(®s->command, MPC52xx_PSC_RST_ERR_STAT); - } else { - out_8(®s->command, MPC52xx_PSC_RST_TX); - out_8(®s->command, MPC52xx_PSC_RST_ERR_STAT); - } - - /* Next, fill up the bestcomm bd queue and enable DMA. - * This will begin filling the PSC's fifo. */ - if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) - bcom_gen_bd_rx_reset(s->bcom_task); - else - bcom_gen_bd_tx_reset(s->bcom_task); - while (!bcom_queue_full(s->bcom_task)) - psc_i2s_bcom_enqueue_next_buffer(s); - bcom_enable(s->bcom_task); - - /* Due to errata in the i2s mode; need to line up enabling - * the transmitter with a transition on the frame sync - * line */ - - spin_lock_irqsave(&psc_i2s->lock, flags); - /* first make sure it is low */ - while ((in_8(®s->ipcr_acr.ipcr) & 0x80) != 0) - ; - /* then wait for the transition to high */ - while ((in_8(®s->ipcr_acr.ipcr) & 0x80) == 0) - ; - /* Finally, enable the PSC. - * Receiver must always be enabled; even when we only want - * transmit. (see 15.3.2.3 of MPC5200B User's Guide) */ - psc_cmd = MPC52xx_PSC_RX_ENABLE; - if (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK) - psc_cmd |= MPC52xx_PSC_TX_ENABLE; - out_8(®s->command, psc_cmd); - spin_unlock_irqrestore(&psc_i2s->lock, flags); - - break; - - case SNDRV_PCM_TRIGGER_STOP: - /* Turn off the PSC */ - s->active = 0; - if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) { - if (!psc_i2s->playback.active) { - out_8(®s->command, 2 << 4); /* reset rx */ - out_8(®s->command, 3 << 4); /* reset tx */ - out_8(®s->command, 4 << 4); /* reset err */ - } - } else { - out_8(®s->command, 3 << 4); /* reset tx */ - out_8(®s->command, 4 << 4); /* reset err */ - if (!psc_i2s->capture.active) - out_8(®s->command, 2 << 4); /* reset rx */ - } - - bcom_disable(s->bcom_task); - while (!bcom_queue_empty(s->bcom_task)) - bcom_retrieve_buffer(s->bcom_task, NULL, NULL); - - break; - - default: - dev_dbg(psc_i2s->dev, "invalid command\n"); - return -EINVAL; - } - - /* Update interrupt enable settings */ - imr = 0; - if (psc_i2s->playback.active) - imr |= MPC52xx_PSC_IMR_TXEMP; - if (psc_i2s->capture.active) - imr |= MPC52xx_PSC_IMR_ORERR; - out_be16(®s->isr_imr.imr, imr); - - return 0; -} - -/** - * psc_i2s_shutdown: shutdown the data transfer on a stream - * - * Shutdown the PSC if there are no other substreams open. - */ -static void psc_i2s_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data; - - dev_dbg(psc_i2s->dev, "psc_i2s_shutdown(substream=%p)\n", substream); - - /* - * If this is the last active substream, disable the PSC and release - * the IRQ. - */ - if (!psc_i2s->playback.active && - !psc_i2s->capture.active) { - - /* Disable all interrupts and reset the PSC */ - out_be16(&psc_i2s->psc_regs->isr_imr.imr, 0); - out_8(&psc_i2s->psc_regs->command, 3 << 4); /* reset tx */ - out_8(&psc_i2s->psc_regs->command, 2 << 4); /* reset rx */ - out_8(&psc_i2s->psc_regs->command, 1 << 4); /* reset mode */ - out_8(&psc_i2s->psc_regs->command, 4 << 4); /* reset error */ - - /* Release irqs */ - free_irq(psc_i2s->irq, psc_i2s); - free_irq(psc_i2s->capture.irq, &psc_i2s->capture); - free_irq(psc_i2s->playback.irq, &psc_i2s->playback); - } -} - /** * psc_i2s_set_sysclk: set the clock frequency and direction * @@ -433,8 +89,8 @@ static void psc_i2s_shutdown(struct snd_pcm_substream *substream, static int psc_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id, unsigned int freq, int dir) { - struct psc_i2s *psc_i2s = cpu_dai->private_data; - dev_dbg(psc_i2s->dev, "psc_i2s_set_sysclk(cpu_dai=%p, dir=%i)\n", + struct psc_dma *psc_dma = cpu_dai->private_data; + dev_dbg(psc_dma->dev, "psc_i2s_set_sysclk(cpu_dai=%p, dir=%i)\n", cpu_dai, dir); return (dir == SND_SOC_CLOCK_IN) ? 0 : -EINVAL; } @@ -452,8 +108,8 @@ static int psc_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, */ static int psc_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format) { - struct psc_i2s *psc_i2s = cpu_dai->private_data; - dev_dbg(psc_i2s->dev, "psc_i2s_set_fmt(cpu_dai=%p, format=%i)\n", + struct psc_dma *psc_dma = cpu_dai->private_data; + dev_dbg(psc_dma->dev, "psc_i2s_set_fmt(cpu_dai=%p, format=%i)\n", cpu_dai, format); return (format == SND_SOC_DAIFMT_I2S) ? 0 : -EINVAL; } @@ -469,16 +125,13 @@ static int psc_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format) * psc_i2s_dai_template: template CPU Digital Audio Interface */ static struct snd_soc_dai_ops psc_i2s_dai_ops = { - .startup = psc_i2s_startup, .hw_params = psc_i2s_hw_params, - .hw_free = psc_i2s_hw_free, - .shutdown = psc_i2s_shutdown, - .trigger = psc_i2s_trigger, .set_sysclk = psc_i2s_set_sysclk, .set_fmt = psc_i2s_set_fmt, }; -static struct snd_soc_dai psc_i2s_dai_template = { +struct snd_soc_dai psc_i2s_dai[] = {{ + .name = "I2S", .playback = { .channels_min = 2, .channels_max = 2, @@ -492,223 +145,8 @@ static struct snd_soc_dai psc_i2s_dai_template = { .formats = PSC_I2S_FORMATS, }, .ops = &psc_i2s_dai_ops, -}; - -/* --------------------------------------------------------------------- - * The PSC I2S 'ASoC platform' driver - * - * Can be referenced by an 'ASoC machine' driver - * This driver only deals with the audio bus; it doesn't have any - * interaction with the attached codec - */ - -static const struct snd_pcm_hardware psc_i2s_pcm_hardware = { - .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_BATCH, - .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE | - SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE, - .rate_min = 8000, - .rate_max = 48000, - .channels_min = 2, - .channels_max = 2, - .period_bytes_max = 1024 * 1024, - .period_bytes_min = 32, - .periods_min = 2, - .periods_max = 256, - .buffer_bytes_max = 2 * 1024 * 1024, - .fifo_size = 0, -}; - -static int psc_i2s_pcm_open(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data; - struct psc_i2s_stream *s; - - dev_dbg(psc_i2s->dev, "psc_i2s_pcm_open(substream=%p)\n", substream); - - if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) - s = &psc_i2s->capture; - else - s = &psc_i2s->playback; - - snd_soc_set_runtime_hwparams(substream, &psc_i2s_pcm_hardware); - - s->stream = substream; - return 0; -} - -static int psc_i2s_pcm_close(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data; - struct psc_i2s_stream *s; - - dev_dbg(psc_i2s->dev, "psc_i2s_pcm_close(substream=%p)\n", substream); - - if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) - s = &psc_i2s->capture; - else - s = &psc_i2s->playback; - - s->stream = NULL; - return 0; -} - -static snd_pcm_uframes_t -psc_i2s_pcm_pointer(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data; - struct psc_i2s_stream *s; - dma_addr_t count; - - if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) - s = &psc_i2s->capture; - else - s = &psc_i2s->playback; - - count = s->period_current_pt - s->period_start; - - return bytes_to_frames(substream->runtime, count); -} - -static struct snd_pcm_ops psc_i2s_pcm_ops = { - .open = psc_i2s_pcm_open, - .close = psc_i2s_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .pointer = psc_i2s_pcm_pointer, -}; - -static u64 psc_i2s_pcm_dmamask = 0xffffffff; -static int psc_i2s_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, - struct snd_pcm *pcm) -{ - struct snd_soc_pcm_runtime *rtd = pcm->private_data; - size_t size = psc_i2s_pcm_hardware.buffer_bytes_max; - int rc = 0; - - dev_dbg(rtd->socdev->dev, "psc_i2s_pcm_new(card=%p, dai=%p, pcm=%p)\n", - card, dai, pcm); - - if (!card->dev->dma_mask) - card->dev->dma_mask = &psc_i2s_pcm_dmamask; - if (!card->dev->coherent_dma_mask) - card->dev->coherent_dma_mask = 0xffffffff; - - if (pcm->streams[0].substream) { - rc = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->dev, size, - &pcm->streams[0].substream->dma_buffer); - if (rc) - goto playback_alloc_err; - } - - if (pcm->streams[1].substream) { - rc = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->dev, size, - &pcm->streams[1].substream->dma_buffer); - if (rc) - goto capture_alloc_err; - } - - return 0; - - capture_alloc_err: - if (pcm->streams[0].substream) - snd_dma_free_pages(&pcm->streams[0].substream->dma_buffer); - playback_alloc_err: - dev_err(card->dev, "Cannot allocate buffer(s)\n"); - return -ENOMEM; -} - -static void psc_i2s_pcm_free(struct snd_pcm *pcm) -{ - struct snd_soc_pcm_runtime *rtd = pcm->private_data; - struct snd_pcm_substream *substream; - int stream; - - dev_dbg(rtd->socdev->dev, "psc_i2s_pcm_free(pcm=%p)\n", pcm); - - for (stream = 0; stream < 2; stream++) { - substream = pcm->streams[stream].substream; - if (substream) { - snd_dma_free_pages(&substream->dma_buffer); - substream->dma_buffer.area = NULL; - substream->dma_buffer.addr = 0; - } - } -} - -struct snd_soc_platform psc_i2s_pcm_soc_platform = { - .name = "mpc5200-psc-audio", - .pcm_ops = &psc_i2s_pcm_ops, - .pcm_new = &psc_i2s_pcm_new, - .pcm_free = &psc_i2s_pcm_free, -}; - -/* --------------------------------------------------------------------- - * Sysfs attributes for debugging - */ - -static ssize_t psc_i2s_status_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct psc_i2s *psc_i2s = dev_get_drvdata(dev); - - return sprintf(buf, "status=%.4x sicr=%.8x rfnum=%i rfstat=0x%.4x " - "tfnum=%i tfstat=0x%.4x\n", - in_be16(&psc_i2s->psc_regs->sr_csr.status), - in_be32(&psc_i2s->psc_regs->sicr), - in_be16(&psc_i2s->fifo_regs->rfnum) & 0x1ff, - in_be16(&psc_i2s->fifo_regs->rfstat), - in_be16(&psc_i2s->fifo_regs->tfnum) & 0x1ff, - in_be16(&psc_i2s->fifo_regs->tfstat)); -} - -static int *psc_i2s_get_stat_attr(struct psc_i2s *psc_i2s, const char *name) -{ - if (strcmp(name, "playback_underrun") == 0) - return &psc_i2s->stats.underrun_count; - if (strcmp(name, "capture_overrun") == 0) - return &psc_i2s->stats.overrun_count; - - return NULL; -} - -static ssize_t psc_i2s_stat_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct psc_i2s *psc_i2s = dev_get_drvdata(dev); - int *attrib; - - attrib = psc_i2s_get_stat_attr(psc_i2s, attr->attr.name); - if (!attrib) - return 0; - - return sprintf(buf, "%i\n", *attrib); -} - -static ssize_t psc_i2s_stat_store(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t count) -{ - struct psc_i2s *psc_i2s = dev_get_drvdata(dev); - int *attrib; - - attrib = psc_i2s_get_stat_attr(psc_i2s, attr->attr.name); - if (!attrib) - return 0; - - *attrib = simple_strtoul(buf, NULL, 0); - return count; -} - -static DEVICE_ATTR(status, 0644, psc_i2s_status_show, NULL); -static DEVICE_ATTR(playback_underrun, 0644, psc_i2s_stat_show, - psc_i2s_stat_store); -static DEVICE_ATTR(capture_overrun, 0644, psc_i2s_stat_show, - psc_i2s_stat_store); +} }; +EXPORT_SYMBOL_GPL(psc_i2s_dai); /* --------------------------------------------------------------------- * OF platform bus binding code: @@ -718,150 +156,65 @@ static DEVICE_ATTR(capture_overrun, 0644, psc_i2s_stat_show, static int __devinit psc_i2s_of_probe(struct of_device *op, const struct of_device_id *match) { - phys_addr_t fifo; - struct psc_i2s *psc_i2s; - struct resource res; - int size, psc_id, irq, rc; - const __be32 *prop; - void __iomem *regs; + int rc; + struct psc_dma *psc_dma; + struct mpc52xx_psc __iomem *regs; - dev_dbg(&op->dev, "probing psc i2s device\n"); + rc = mpc5200_audio_dma_create(op); + if (rc != 0) + return rc; - /* Get the PSC ID */ - prop = of_get_property(op->node, "cell-index", &size); - if (!prop || size < sizeof *prop) - return -ENODEV; - psc_id = be32_to_cpu(*prop); - - /* Fetch the registers and IRQ of the PSC */ - irq = irq_of_parse_and_map(op->node, 0); - if (of_address_to_resource(op->node, 0, &res)) { - dev_err(&op->dev, "Missing reg property\n"); - return -ENODEV; - } - regs = ioremap(res.start, 1 + res.end - res.start); - if (!regs) { - dev_err(&op->dev, "Could not map registers\n"); - return -ENODEV; + rc = snd_soc_register_dais(psc_i2s_dai, ARRAY_SIZE(psc_i2s_dai)); + if (rc != 0) { + pr_err("Failed to register DAI\n"); + return 0; } - /* Allocate and initialize the driver private data */ - psc_i2s = kzalloc(sizeof *psc_i2s, GFP_KERNEL); - if (!psc_i2s) { - iounmap(regs); - return -ENOMEM; - } - spin_lock_init(&psc_i2s->lock); - psc_i2s->irq = irq; - psc_i2s->psc_regs = regs; - psc_i2s->fifo_regs = regs + sizeof *psc_i2s->psc_regs; - psc_i2s->dev = &op->dev; - psc_i2s->playback.psc_i2s = psc_i2s; - psc_i2s->capture.psc_i2s = psc_i2s; - snprintf(psc_i2s->name, sizeof psc_i2s->name, "PSC%u", psc_id+1); - - /* Fill out the CPU DAI structure */ - memcpy(&psc_i2s->dai, &psc_i2s_dai_template, sizeof psc_i2s->dai); - psc_i2s->dai.private_data = psc_i2s; - psc_i2s->dai.name = psc_i2s->name; - psc_i2s->dai.id = psc_id; - - /* Find the address of the fifo data registers and setup the - * DMA tasks */ - fifo = res.start + offsetof(struct mpc52xx_psc, buffer.buffer_32); - psc_i2s->capture.bcom_task = - bcom_psc_gen_bd_rx_init(psc_id, 10, fifo, 512); - psc_i2s->playback.bcom_task = - bcom_psc_gen_bd_tx_init(psc_id, 10, fifo); - if (!psc_i2s->capture.bcom_task || - !psc_i2s->playback.bcom_task) { - dev_err(&op->dev, "Could not allocate bestcomm tasks\n"); - iounmap(regs); - kfree(psc_i2s); - return -ENODEV; - } - - /* Disable all interrupts and reset the PSC */ - out_be16(&psc_i2s->psc_regs->isr_imr.imr, 0); - out_8(&psc_i2s->psc_regs->command, 3 << 4); /* reset transmitter */ - out_8(&psc_i2s->psc_regs->command, 2 << 4); /* reset receiver */ - out_8(&psc_i2s->psc_regs->command, 1 << 4); /* reset mode */ - out_8(&psc_i2s->psc_regs->command, 4 << 4); /* reset error */ + psc_dma = dev_get_drvdata(&op->dev); + regs = psc_dma->psc_regs; /* Configure the serial interface mode; defaulting to CODEC8 mode */ - psc_i2s->sicr = MPC52xx_PSC_SICR_DTS1 | MPC52xx_PSC_SICR_I2S | + psc_dma->sicr = MPC52xx_PSC_SICR_DTS1 | MPC52xx_PSC_SICR_I2S | MPC52xx_PSC_SICR_CLKPOL; - if (of_get_property(op->node, "fsl,cellslave", NULL)) - psc_i2s->sicr |= MPC52xx_PSC_SICR_CELLSLAVE | - MPC52xx_PSC_SICR_GENCLK; - out_be32(&psc_i2s->psc_regs->sicr, - psc_i2s->sicr | MPC52xx_PSC_SICR_SIM_CODEC_8); + out_be32(&psc_dma->psc_regs->sicr, + psc_dma->sicr | MPC52xx_PSC_SICR_SIM_CODEC_8); /* Check for the codec handle. If it is not present then we * are done */ if (!of_get_property(op->node, "codec-handle", NULL)) return 0; - /* Set up mode register; - * First write: RxRdy (FIFO Alarm) generates rx FIFO irq - * Second write: register Normal mode for non loopback - */ - out_8(&psc_i2s->psc_regs->mode, 0); - out_8(&psc_i2s->psc_regs->mode, 0); + /* Due to errata in the dma mode; need to line up enabling + * the transmitter with a transition on the frame sync + * line */ - /* Set the TX and RX fifo alarm thresholds */ - out_be16(&psc_i2s->fifo_regs->rfalarm, 0x100); - out_8(&psc_i2s->fifo_regs->rfcntl, 0x4); - out_be16(&psc_i2s->fifo_regs->tfalarm, 0x100); - out_8(&psc_i2s->fifo_regs->tfcntl, 0x7); + /* first make sure it is low */ + while ((in_8(®s->ipcr_acr.ipcr) & 0x80) != 0) + ; + /* then wait for the transition to high */ + while ((in_8(®s->ipcr_acr.ipcr) & 0x80) == 0) + ; + /* Finally, enable the PSC. + * Receiver must always be enabled; even when we only want + * transmit. (see 15.3.2.3 of MPC5200B User's Guide) */ - /* Lookup the IRQ numbers */ - psc_i2s->playback.irq = - bcom_get_task_irq(psc_i2s->playback.bcom_task); - psc_i2s->capture.irq = - bcom_get_task_irq(psc_i2s->capture.bcom_task); - - /* Save what we've done so it can be found again later */ - dev_set_drvdata(&op->dev, psc_i2s); - - /* Register the SYSFS files */ - rc = device_create_file(psc_i2s->dev, &dev_attr_status); - rc |= device_create_file(psc_i2s->dev, &dev_attr_capture_overrun); - rc |= device_create_file(psc_i2s->dev, &dev_attr_playback_underrun); - if (rc) - dev_info(psc_i2s->dev, "error creating sysfs files\n"); - - snd_soc_register_platform(&psc_i2s_pcm_soc_platform); - - /* Tell the ASoC OF helpers about it */ - of_snd_soc_register_platform(&psc_i2s_pcm_soc_platform, op->node, - &psc_i2s->dai); + /* Go */ + out_8(&psc_dma->psc_regs->command, + MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE); return 0; + } static int __devexit psc_i2s_of_remove(struct of_device *op) { - struct psc_i2s *psc_i2s = dev_get_drvdata(&op->dev); - - dev_dbg(&op->dev, "psc_i2s_remove()\n"); - - snd_soc_unregister_platform(&psc_i2s_pcm_soc_platform); - - bcom_gen_bd_rx_release(psc_i2s->capture.bcom_task); - bcom_gen_bd_tx_release(psc_i2s->playback.bcom_task); - - iounmap(psc_i2s->psc_regs); - iounmap(psc_i2s->fifo_regs); - kfree(psc_i2s); - dev_set_drvdata(&op->dev, NULL); - - return 0; + return mpc5200_audio_dma_destroy(op); } /* Match table for of_platform binding */ static struct of_device_id psc_i2s_match[] __devinitdata = { { .compatible = "fsl,mpc5200-psc-i2s", }, + { .compatible = "fsl,mpc5200b-psc-i2s", }, {} }; MODULE_DEVICE_TABLE(of, psc_i2s_match); @@ -892,4 +245,7 @@ static void __exit psc_i2s_exit(void) } module_exit(psc_i2s_exit); +MODULE_AUTHOR("Grant Likely "); +MODULE_DESCRIPTION("Freescale MPC5200 PSC in I2S mode ASoC Driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/fsl/mpc5200_psc_i2s.h b/sound/soc/fsl/mpc5200_psc_i2s.h new file mode 100644 index 000000000000..ce55e070fdf3 --- /dev/null +++ b/sound/soc/fsl/mpc5200_psc_i2s.h @@ -0,0 +1,12 @@ +/* + * Freescale MPC5200 PSC in I2S mode + * ALSA SoC Digital Audio Interface (DAI) driver + * + */ + +#ifndef __SOUND_SOC_FSL_MPC52xx_PSC_I2S_H__ +#define __SOUND_SOC_FSL_MPC52xx_PSC_I2S_H__ + +extern struct snd_soc_dai psc_i2s_dai[]; + +#endif /* __SOUND_SOC_FSL_MPC52xx_PSC_I2S_H__ */ diff --git a/sound/soc/fsl/pcm030-audio-fabric.c b/sound/soc/fsl/pcm030-audio-fabric.c new file mode 100644 index 000000000000..8766f7a3893d --- /dev/null +++ b/sound/soc/fsl/pcm030-audio-fabric.c @@ -0,0 +1,90 @@ +/* + * Phytec pcm030 driver for the PSC of the Freescale MPC52xx + * configured as AC97 interface + * + * Copyright 2008 Jon Smirl, Digispeaker + * Author: Jon Smirl + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "mpc5200_dma.h" +#include "mpc5200_psc_ac97.h" +#include "../codecs/wm9712.h" + +static struct snd_soc_device device; +static struct snd_soc_card card; + +static struct snd_soc_dai_link pcm030_fabric_dai[] = { +{ + .name = "AC97", + .stream_name = "AC97 Analog", + .codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI], + .cpu_dai = &psc_ac97_dai[MPC5200_AC97_NORMAL], +}, +{ + .name = "AC97", + .stream_name = "AC97 IEC958", + .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX], + .cpu_dai = &psc_ac97_dai[MPC5200_AC97_SPDIF], +}, +}; + +static __init int pcm030_fabric_init(void) +{ + struct platform_device *pdev; + int rc; + + if (!machine_is_compatible("phytec,pcm030")) + return -ENODEV; + + card.platform = &mpc5200_audio_dma_platform; + card.name = "pcm030"; + card.dai_link = pcm030_fabric_dai; + card.num_links = ARRAY_SIZE(pcm030_fabric_dai); + + device.card = &card; + device.codec_dev = &soc_codec_dev_wm9712; + + pdev = platform_device_alloc("soc-audio", 1); + if (!pdev) { + pr_err("pcm030_fabric_init: platform_device_alloc() failed\n"); + return -ENODEV; + } + + platform_set_drvdata(pdev, &device); + device.dev = &pdev->dev; + + rc = platform_device_add(pdev); + if (rc) { + pr_err("pcm030_fabric_init: platform_device_add() failed\n"); + return -ENODEV; + } + return 0; +} + +module_init(pcm030_fabric_init); + + +MODULE_AUTHOR("Jon Smirl "); +MODULE_DESCRIPTION(DRV_NAME ": mpc5200 pcm030 fabric driver"); +MODULE_LICENSE("GPL"); + diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index 675732e724d5..b771238662b6 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig @@ -39,6 +39,14 @@ config SND_OMAP_SOC_OMAP2EVM help Say Y if you want to add support for SoC audio on the omap2evm board. +config SND_OMAP_SOC_OMAP3EVM + tristate "SoC Audio support for OMAP3EVM board" + depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP3EVM + select SND_OMAP_SOC_MCBSP + select SND_SOC_TWL4030 + help + Say Y if you want to add support for SoC audio on the omap3evm board. + config SND_OMAP_SOC_SDP3430 tristate "SoC Audio support for Texas Instruments SDP3430" depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP_3430SDP diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile index 0c9e4ac37660..a37f49862389 100644 --- a/sound/soc/omap/Makefile +++ b/sound/soc/omap/Makefile @@ -10,6 +10,7 @@ snd-soc-n810-objs := n810.o snd-soc-osk5912-objs := osk5912.o snd-soc-overo-objs := overo.o snd-soc-omap2evm-objs := omap2evm.o +snd-soc-omap3evm-objs := omap3evm.o snd-soc-sdp3430-objs := sdp3430.o snd-soc-omap3pandora-objs := omap3pandora.o snd-soc-omap3beagle-objs := omap3beagle.o @@ -18,6 +19,7 @@ obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o obj-$(CONFIG_SND_OMAP_SOC_OVERO) += snd-soc-overo.o obj-$(CONFIG_MACH_OMAP2EVM) += snd-soc-omap2evm.o +obj-$(CONFIG_MACH_OMAP3EVM) += snd-soc-omap3evm.o obj-$(CONFIG_SND_OMAP_SOC_SDP3430) += snd-soc-sdp3430.o obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o obj-$(CONFIG_SND_OMAP_SOC_OMAP3_BEAGLE) += snd-soc-omap3beagle.o diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c index 91ef17992de5..b60b1dfbc435 100644 --- a/sound/soc/omap/n810.c +++ b/sound/soc/omap/n810.c @@ -383,10 +383,9 @@ static int __init n810_soc_init(void) clk_set_parent(sys_clkout2_src, func96m_clk); clk_set_rate(sys_clkout2, 12000000); - if (gpio_request(N810_HEADSET_AMP_GPIO, "hs_amp") < 0) - BUG(); - if (gpio_request(N810_SPEAKER_AMP_GPIO, "spk_amp") < 0) - BUG(); + BUG_ON((gpio_request(N810_HEADSET_AMP_GPIO, "hs_amp") < 0) || + (gpio_request(N810_SPEAKER_AMP_GPIO, "spk_amp") < 0)); + gpio_direction_output(N810_HEADSET_AMP_GPIO, 0); gpio_direction_output(N810_SPEAKER_AMP_GPIO, 0); diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 912614283848..a5d46a7b196a 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -215,8 +215,9 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs; int dma, bus_id = mcbsp_data->bus_id, id = cpu_dai->id; - int wlen, channels; + int wlen, channels, wpf; unsigned long port; + unsigned int format; if (cpu_class_is_omap1()) { dma = omap1_dma_reqs[bus_id][substream->stream]; @@ -244,18 +245,24 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, return 0; } - channels = params_channels(params); + format = mcbsp_data->fmt & SND_SOC_DAIFMT_FORMAT_MASK; + wpf = channels = params_channels(params); switch (channels) { case 2: - /* Use dual-phase frames */ - regs->rcr2 |= RPHASE; - regs->xcr2 |= XPHASE; + if (format == SND_SOC_DAIFMT_I2S) { + /* Use dual-phase frames */ + regs->rcr2 |= RPHASE; + regs->xcr2 |= XPHASE; + /* Set 1 word per (McBSP) frame for phase1 and phase2 */ + wpf--; + regs->rcr2 |= RFRLEN2(wpf - 1); + regs->xcr2 |= XFRLEN2(wpf - 1); + } case 1: - /* Set 1 word per (McBSP) frame */ - regs->rcr2 |= RFRLEN2(1 - 1); - regs->rcr1 |= RFRLEN1(1 - 1); - regs->xcr2 |= XFRLEN2(1 - 1); - regs->xcr1 |= XFRLEN1(1 - 1); + case 4: + /* Set word per (McBSP) frame for phase1 */ + regs->rcr1 |= RFRLEN1(wpf - 1); + regs->xcr1 |= XFRLEN1(wpf - 1); break; default: /* Unsupported number of channels */ @@ -277,11 +284,12 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, } /* Set FS period and length in terms of bit clock periods */ - switch (mcbsp_data->fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + switch (format) { case SND_SOC_DAIFMT_I2S: - regs->srgr2 |= FPER(wlen * 2 - 1); + regs->srgr2 |= FPER(wlen * channels - 1); regs->srgr1 |= FWID(wlen - 1); break; + case SND_SOC_DAIFMT_DSP_A: case SND_SOC_DAIFMT_DSP_B: regs->srgr2 |= FPER(wlen * channels - 1); regs->srgr1 |= FWID(0); @@ -326,6 +334,13 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai, regs->rcr2 |= RDATDLY(1); regs->xcr2 |= XDATDLY(1); break; + case SND_SOC_DAIFMT_DSP_A: + /* 1-bit data delay */ + regs->rcr2 |= RDATDLY(1); + regs->xcr2 |= XDATDLY(1); + /* Invert FS polarity configuration */ + temp_fmt ^= SND_SOC_DAIFMT_NB_IF; + break; case SND_SOC_DAIFMT_DSP_B: /* 0-bit data delay */ regs->rcr2 |= RDATDLY(0); @@ -492,13 +507,13 @@ static struct snd_soc_dai_ops omap_mcbsp_dai_ops = { .id = (link_id), \ .playback = { \ .channels_min = 1, \ - .channels_max = 2, \ + .channels_max = 4, \ .rates = OMAP_MCBSP_RATES, \ .formats = SNDRV_PCM_FMTBIT_S16_LE, \ }, \ .capture = { \ .channels_min = 1, \ - .channels_max = 2, \ + .channels_max = 4, \ .rates = OMAP_MCBSP_RATES, \ .formats = SNDRV_PCM_FMTBIT_S16_LE, \ }, \ diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c index 07cf7f46b584..6454e15f7d28 100644 --- a/sound/soc/omap/omap-pcm.c +++ b/sound/soc/omap/omap-pcm.c @@ -87,8 +87,10 @@ static int omap_pcm_hw_params(struct snd_pcm_substream *substream, struct omap_pcm_dma_data *dma_data = rtd->dai->cpu_dai->dma_data; int err = 0; + /* return if this is a bufferless transfer e.g. + * codec <--> BT codec or GSM modem -- lg FIXME */ if (!dma_data) - return -ENODEV; + return 0; snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); runtime->dma_bytes = params_buffer_bytes(params); @@ -134,6 +136,11 @@ static int omap_pcm_prepare(struct snd_pcm_substream *substream) struct omap_pcm_dma_data *dma_data = prtd->dma_data; struct omap_dma_channel_params dma_params; + /* return if this is a bufferless transfer e.g. + * codec <--> BT codec or GSM modem -- lg FIXME */ + if (!prtd->dma_data) + return 0; + memset(&dma_params, 0, sizeof(dma_params)); /* * Note: Regardless of interface data formats supported by OMAP McBSP diff --git a/sound/soc/omap/omap2evm.c b/sound/soc/omap/omap2evm.c index 0c2322dcf02a..027e1a40f8a1 100644 --- a/sound/soc/omap/omap2evm.c +++ b/sound/soc/omap/omap2evm.c @@ -86,7 +86,7 @@ static struct snd_soc_dai_link omap2evm_dai = { .name = "TWL4030", .stream_name = "TWL4030", .cpu_dai = &omap_mcbsp_dai[0], - .codec_dai = &twl4030_dai, + .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI], .ops = &omap2evm_ops, }; diff --git a/sound/soc/omap/omap3beagle.c b/sound/soc/omap/omap3beagle.c index fd24a4acd2f5..b0cff9f33b7e 100644 --- a/sound/soc/omap/omap3beagle.c +++ b/sound/soc/omap/omap3beagle.c @@ -41,23 +41,33 @@ static int omap3beagle_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + unsigned int fmt; int ret; + switch (params_channels(params)) { + case 2: /* Stereo I2S mode */ + fmt = SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM; + break; + case 4: /* Four channel TDM mode */ + fmt = SND_SOC_DAIFMT_DSP_A | + SND_SOC_DAIFMT_IB_NF | + SND_SOC_DAIFMT_CBM_CFM; + break; + default: + return -EINVAL; + } + /* Set codec DAI configuration */ - ret = snd_soc_dai_set_fmt(codec_dai, - SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM); + ret = snd_soc_dai_set_fmt(codec_dai, fmt); if (ret < 0) { printk(KERN_ERR "can't set codec DAI configuration\n"); return ret; } /* Set cpu DAI configuration */ - ret = snd_soc_dai_set_fmt(cpu_dai, - SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM); + ret = snd_soc_dai_set_fmt(cpu_dai, fmt); if (ret < 0) { printk(KERN_ERR "can't set cpu DAI configuration\n"); return ret; @@ -83,7 +93,7 @@ static struct snd_soc_dai_link omap3beagle_dai = { .name = "TWL4030", .stream_name = "TWL4030", .cpu_dai = &omap_mcbsp_dai[0], - .codec_dai = &twl4030_dai, + .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI], .ops = &omap3beagle_ops, }; diff --git a/sound/soc/omap/omap3evm.c b/sound/soc/omap/omap3evm.c new file mode 100644 index 000000000000..9114c263077b --- /dev/null +++ b/sound/soc/omap/omap3evm.c @@ -0,0 +1,147 @@ +/* + * omap3evm.c -- ALSA SoC support for OMAP3 EVM + * + * Author: Anuj Aggarwal + * + * Based on sound/soc/omap/beagle.c by Steve Sakoman + * + * Copyright (C) 2008 Texas Instruments, Incorporated + * + * 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 distributed "as is" WITHOUT ANY WARRANTY of any kind, + * whether express or implied; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "omap-mcbsp.h" +#include "omap-pcm.h" +#include "../codecs/twl4030.h" + +static int omap3evm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + int ret; + + /* Set codec DAI configuration */ + ret = snd_soc_dai_set_fmt(codec_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM); + if (ret < 0) { + printk(KERN_ERR "Can't set codec DAI configuration\n"); + return ret; + } + + /* Set cpu DAI configuration */ + ret = snd_soc_dai_set_fmt(cpu_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM); + if (ret < 0) { + printk(KERN_ERR "Can't set cpu DAI configuration\n"); + return ret; + } + + /* Set the codec system clock for DAC and ADC */ + ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000, + SND_SOC_CLOCK_IN); + if (ret < 0) { + printk(KERN_ERR "Can't set codec system clock\n"); + return ret; + } + + return 0; +} + +static struct snd_soc_ops omap3evm_ops = { + .hw_params = omap3evm_hw_params, +}; + +/* Digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link omap3evm_dai = { + .name = "TWL4030", + .stream_name = "TWL4030", + .cpu_dai = &omap_mcbsp_dai[0], + .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI], + .ops = &omap3evm_ops, +}; + +/* Audio machine driver */ +static struct snd_soc_card snd_soc_omap3evm = { + .name = "omap3evm", + .platform = &omap_soc_platform, + .dai_link = &omap3evm_dai, + .num_links = 1, +}; + +/* Audio subsystem */ +static struct snd_soc_device omap3evm_snd_devdata = { + .card = &snd_soc_omap3evm, + .codec_dev = &soc_codec_dev_twl4030, +}; + +static struct platform_device *omap3evm_snd_device; + +static int __init omap3evm_soc_init(void) +{ + int ret; + + if (!machine_is_omap3evm()) { + pr_err("Not OMAP3 EVM!\n"); + return -ENODEV; + } + pr_info("OMAP3 EVM SoC init\n"); + + omap3evm_snd_device = platform_device_alloc("soc-audio", -1); + if (!omap3evm_snd_device) { + printk(KERN_ERR "Platform device allocation failed\n"); + return -ENOMEM; + } + + platform_set_drvdata(omap3evm_snd_device, &omap3evm_snd_devdata); + omap3evm_snd_devdata.dev = &omap3evm_snd_device->dev; + *(unsigned int *)omap3evm_dai.cpu_dai->private_data = 1; + + ret = platform_device_add(omap3evm_snd_device); + if (ret) + goto err1; + + return 0; + +err1: + printk(KERN_ERR "Unable to add platform device\n"); + platform_device_put(omap3evm_snd_device); + + return ret; +} + +static void __exit omap3evm_soc_exit(void) +{ + platform_device_unregister(omap3evm_snd_device); +} + +module_init(omap3evm_soc_init); +module_exit(omap3evm_soc_exit); + +MODULE_AUTHOR("Anuj Aggarwal "); +MODULE_DESCRIPTION("ALSA SoC OMAP3 EVM"); +MODULE_LICENSE("GPLv2"); diff --git a/sound/soc/omap/omap3pandora.c b/sound/soc/omap/omap3pandora.c index fe282d4ef422..ad219aaf7cb8 100644 --- a/sound/soc/omap/omap3pandora.c +++ b/sound/soc/omap/omap3pandora.c @@ -228,14 +228,14 @@ static struct snd_soc_dai_link omap3pandora_dai[] = { .name = "PCM1773", .stream_name = "HiFi Out", .cpu_dai = &omap_mcbsp_dai[0], - .codec_dai = &twl4030_dai, + .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI], .ops = &omap3pandora_out_ops, .init = omap3pandora_out_init, }, { .name = "TWL4030", .stream_name = "Line/Mic In", .cpu_dai = &omap_mcbsp_dai[1], - .codec_dai = &twl4030_dai, + .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI], .ops = &omap3pandora_in_ops, .init = omap3pandora_in_init, } diff --git a/sound/soc/omap/overo.c b/sound/soc/omap/overo.c index a72dc4e159e5..ec4f8fd8b3a2 100644 --- a/sound/soc/omap/overo.c +++ b/sound/soc/omap/overo.c @@ -83,7 +83,7 @@ static struct snd_soc_dai_link overo_dai = { .name = "TWL4030", .stream_name = "TWL4030", .cpu_dai = &omap_mcbsp_dai[0], - .codec_dai = &twl4030_dai, + .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI], .ops = &overo_ops, }; diff --git a/sound/soc/omap/sdp3430.c b/sound/soc/omap/sdp3430.c index 10f1c867f11d..b719e5db4f57 100644 --- a/sound/soc/omap/sdp3430.c +++ b/sound/soc/omap/sdp3430.c @@ -84,6 +84,49 @@ static struct snd_soc_ops sdp3430_ops = { .hw_params = sdp3430_hw_params, }; +static int sdp3430_hw_voice_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + int ret; + + /* Set codec DAI configuration */ + ret = snd_soc_dai_set_fmt(codec_dai, + SND_SOC_DAIFMT_DSP_A | + SND_SOC_DAIFMT_IB_NF | + SND_SOC_DAIFMT_CBS_CFM); + if (ret) { + printk(KERN_ERR "can't set codec DAI configuration\n"); + return ret; + } + + /* Set cpu DAI configuration */ + ret = snd_soc_dai_set_fmt(cpu_dai, + SND_SOC_DAIFMT_DSP_A | + SND_SOC_DAIFMT_IB_NF | + SND_SOC_DAIFMT_CBM_CFM); + if (ret < 0) { + printk(KERN_ERR "can't set cpu DAI configuration\n"); + return ret; + } + + /* Set the codec system clock for DAC and ADC */ + ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000, + SND_SOC_CLOCK_IN); + if (ret < 0) { + printk(KERN_ERR "can't set codec system clock\n"); + return ret; + } + + return 0; +} + +static struct snd_soc_ops sdp3430_voice_ops = { + .hw_params = sdp3430_hw_voice_params, +}; + /* Headset jack */ static struct snd_soc_jack hs_jack; @@ -192,28 +235,58 @@ static int sdp3430_twl4030_init(struct snd_soc_codec *codec) return ret; } +static int sdp3430_twl4030_voice_init(struct snd_soc_codec *codec) +{ + unsigned short reg; + + /* Enable voice interface */ + reg = codec->read(codec, TWL4030_REG_VOICE_IF); + reg |= TWL4030_VIF_DIN_EN | TWL4030_VIF_DOUT_EN | TWL4030_VIF_EN; + codec->write(codec, TWL4030_REG_VOICE_IF, reg); + + return 0; +} + + /* Digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link sdp3430_dai = { - .name = "TWL4030", - .stream_name = "TWL4030", - .cpu_dai = &omap_mcbsp_dai[0], - .codec_dai = &twl4030_dai, - .init = sdp3430_twl4030_init, - .ops = &sdp3430_ops, +static struct snd_soc_dai_link sdp3430_dai[] = { + { + .name = "TWL4030 I2S", + .stream_name = "TWL4030 Audio", + .cpu_dai = &omap_mcbsp_dai[0], + .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI], + .init = sdp3430_twl4030_init, + .ops = &sdp3430_ops, + }, + { + .name = "TWL4030 PCM", + .stream_name = "TWL4030 Voice", + .cpu_dai = &omap_mcbsp_dai[1], + .codec_dai = &twl4030_dai[TWL4030_DAI_VOICE], + .init = sdp3430_twl4030_voice_init, + .ops = &sdp3430_voice_ops, + }, }; /* Audio machine driver */ static struct snd_soc_card snd_soc_sdp3430 = { .name = "SDP3430", .platform = &omap_soc_platform, - .dai_link = &sdp3430_dai, - .num_links = 1, + .dai_link = sdp3430_dai, + .num_links = ARRAY_SIZE(sdp3430_dai), +}; + +/* twl4030 setup */ +static struct twl4030_setup_data twl4030_setup = { + .ramp_delay_value = 3, + .sysclk = 26000, }; /* Audio subsystem */ static struct snd_soc_device sdp3430_snd_devdata = { .card = &snd_soc_sdp3430, .codec_dev = &soc_codec_dev_twl4030, + .codec_data = &twl4030_setup, }; static struct platform_device *sdp3430_snd_device; @@ -236,7 +309,8 @@ static int __init sdp3430_soc_init(void) platform_set_drvdata(sdp3430_snd_device, &sdp3430_snd_devdata); sdp3430_snd_devdata.dev = &sdp3430_snd_device->dev; - *(unsigned int *)sdp3430_dai.cpu_dai->private_data = 1; /* McBSP2 */ + *(unsigned int *)sdp3430_dai[0].cpu_dai->private_data = 1; /* McBSP2 */ + *(unsigned int *)sdp3430_dai[1].cpu_dai->private_data = 2; /* McBSP3 */ ret = platform_device_add(sdp3430_snd_device); if (ret) diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig index ad8a10fe6298..6375b4ea525d 100644 --- a/sound/soc/pxa/Kconfig +++ b/sound/soc/pxa/Kconfig @@ -89,22 +89,23 @@ config SND_PXA2XX_SOC_E800 Toshiba e800 PDA config SND_PXA2XX_SOC_EM_X270 - tristate "SoC Audio support for CompuLab EM-x270" + tristate "SoC Audio support for CompuLab EM-x270, eXeda and CM-X300" depends on SND_PXA2XX_SOC && MACH_EM_X270 select SND_PXA2XX_SOC_AC97 select SND_SOC_WM9712 help Say Y if you want to add support for SoC audio on - CompuLab EM-x270. + CompuLab EM-x270, eXeda and CM-X300 machines. config SND_PXA2XX_SOC_PALM27X - bool "SoC Audio support for Palm T|X, T5 and LifeDrive" - depends on SND_PXA2XX_SOC && (MACH_PALMLD || MACH_PALMTX || MACH_PALMT5) + bool "SoC Audio support for Palm T|X, T5, E2 and LifeDrive" + depends on SND_PXA2XX_SOC && (MACH_PALMLD || MACH_PALMTX || \ + MACH_PALMT5 || MACH_PALMTE2) select SND_PXA2XX_SOC_AC97 select SND_SOC_WM9712 help Say Y if you want to add support for SoC audio on - Palm T|X, T5 or LifeDrive handheld computer. + Palm T|X, T5, E2 or LifeDrive handheld computer. config SND_SOC_ZYLONITE tristate "SoC Audio support for Marvell Zylonite" @@ -134,3 +135,12 @@ config SND_PXA2XX_SOC_MIOA701 help Say Y if you want to add support for SoC audio on the MIO A701. + +config SND_PXA2XX_SOC_IMOTE2 + tristate "SoC Audio support for IMote 2" + depends on SND_PXA2XX_SOC && MACH_INTELMOTE2 + select SND_PXA2XX_SOC_I2S + select SND_SOC_WM8940 + help + Say Y if you want to add support for SoC audio on the + IMote 2. diff --git a/sound/soc/pxa/Makefile b/sound/soc/pxa/Makefile index 4b90c3ccae45..6e096b480335 100644 --- a/sound/soc/pxa/Makefile +++ b/sound/soc/pxa/Makefile @@ -22,6 +22,7 @@ snd-soc-palm27x-objs := palm27x.o snd-soc-zylonite-objs := zylonite.o snd-soc-magician-objs := magician.o snd-soc-mioa701-objs := mioa701_wm9713.o +snd-soc-imote2-objs := imote2.o obj-$(CONFIG_SND_PXA2XX_SOC_CORGI) += snd-soc-corgi.o obj-$(CONFIG_SND_PXA2XX_SOC_POODLE) += snd-soc-poodle.o @@ -35,3 +36,4 @@ obj-$(CONFIG_SND_PXA2XX_SOC_PALM27X) += snd-soc-palm27x.o obj-$(CONFIG_SND_PXA2XX_SOC_MAGICIAN) += snd-soc-magician.o obj-$(CONFIG_SND_PXA2XX_SOC_MIOA701) += snd-soc-mioa701.o obj-$(CONFIG_SND_SOC_ZYLONITE) += snd-soc-zylonite.o +obj-$(CONFIG_SND_PXA2XX_SOC_IMOTE2) += snd-soc-imote2.o diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c index d5be2b30cda5..fefe1a57f31a 100644 --- a/sound/soc/pxa/corgi.c +++ b/sound/soc/pxa/corgi.c @@ -320,38 +320,6 @@ static struct snd_soc_device corgi_snd_devdata = { .codec_dev = &soc_codec_dev_wm8731, }; -/* - * FIXME: This is a temporary bodge to avoid cross-tree merge issues. - * New drivers should register the wm8731 I2C device in the machine - * setup code (under arch/arm for ARM systems). - */ -static int wm8731_i2c_register(void) -{ - struct i2c_board_info info; - struct i2c_adapter *adapter; - struct i2c_client *client; - - memset(&info, 0, sizeof(struct i2c_board_info)); - info.addr = 0x1b; - strlcpy(info.type, "wm8731", I2C_NAME_SIZE); - - adapter = i2c_get_adapter(0); - if (!adapter) { - printk(KERN_ERR "can't get i2c adapter 0\n"); - return -ENODEV; - } - - client = i2c_new_device(adapter, &info); - i2c_put_adapter(adapter); - if (!client) { - printk(KERN_ERR "can't add i2c device at 0x%x\n", - (unsigned int)info.addr); - return -ENODEV; - } - - return 0; -} - static struct platform_device *corgi_snd_device; static int __init corgi_init(void) @@ -362,10 +330,6 @@ static int __init corgi_init(void) machine_is_husky())) return -ENODEV; - ret = wm8731_i2c_register(); - if (ret != 0) - return ret; - corgi_snd_device = platform_device_alloc("soc-audio", -1); if (!corgi_snd_device) return -ENOMEM; diff --git a/sound/soc/pxa/em-x270.c b/sound/soc/pxa/em-x270.c index 949be9c2a01b..f4756e4025fd 100644 --- a/sound/soc/pxa/em-x270.c +++ b/sound/soc/pxa/em-x270.c @@ -1,7 +1,7 @@ /* - * em-x270.c -- SoC audio for EM-X270 + * SoC audio driver for EM-X270, eXeda and CM-X300 * - * Copyright 2007 CompuLab, Ltd. + * Copyright 2007, 2009 CompuLab, Ltd. * * Author: Mike Rapoport * @@ -68,7 +68,8 @@ static int __init em_x270_init(void) { int ret; - if (!machine_is_em_x270()) + if (!(machine_is_em_x270() || machine_is_exeda() + || machine_is_cm_x300())) return -ENODEV; em_x270_snd_device = platform_device_alloc("soc-audio", -1); @@ -95,5 +96,5 @@ module_exit(em_x270_exit); /* Module information */ MODULE_AUTHOR("Mike Rapoport"); -MODULE_DESCRIPTION("ALSA SoC EM-X270"); +MODULE_DESCRIPTION("ALSA SoC EM-X270, eXeda and CM-X300"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/pxa/imote2.c b/sound/soc/pxa/imote2.c new file mode 100644 index 000000000000..405587a01160 --- /dev/null +++ b/sound/soc/pxa/imote2.c @@ -0,0 +1,114 @@ + +#include +#include + +#include + +#include "../codecs/wm8940.h" +#include "pxa2xx-i2s.h" +#include "pxa2xx-pcm.h" + +static int imote2_asoc_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + unsigned int clk = 0; + int ret; + + switch (params_rate(params)) { + case 8000: + case 16000: + case 48000: + case 96000: + clk = 12288000; + break; + case 11025: + case 22050: + case 44100: + clk = 11289600; + break; + } + + /* set codec DAI configuration */ + ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S + | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) + return ret; + + /* CPU should be clock master */ + ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S + | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_sysclk(codec_dai, 0, clk, + SND_SOC_CLOCK_IN); + if (ret < 0) + return ret; + + /* set the I2S system clock as input (unused) */ + ret = snd_soc_dai_set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, clk, + SND_SOC_CLOCK_OUT); + + return ret; +} + +static struct snd_soc_ops imote2_asoc_ops = { + .hw_params = imote2_asoc_hw_params, +}; + +static struct snd_soc_dai_link imote2_dai = { + .name = "WM8940", + .stream_name = "WM8940", + .cpu_dai = &pxa_i2s_dai, + .codec_dai = &wm8940_dai, + .ops = &imote2_asoc_ops, +}; + +static struct snd_soc_card snd_soc_imote2 = { + .name = "Imote2", + .platform = &pxa2xx_soc_platform, + .dai_link = &imote2_dai, + .num_links = 1, +}; + +static struct snd_soc_device imote2_snd_devdata = { + .card = &snd_soc_imote2, + .codec_dev = &soc_codec_dev_wm8940, +}; + +static struct platform_device *imote2_snd_device; + +static int __init imote2_asoc_init(void) +{ + int ret; + + if (!machine_is_intelmote2()) + return -ENODEV; + imote2_snd_device = platform_device_alloc("soc-audio", -1); + if (!imote2_snd_device) + return -ENOMEM; + + platform_set_drvdata(imote2_snd_device, &imote2_snd_devdata); + imote2_snd_devdata.dev = &imote2_snd_device->dev; + ret = platform_device_add(imote2_snd_device); + if (ret) + platform_device_put(imote2_snd_device); + + return ret; +} +module_init(imote2_asoc_init); + +static void __exit imote2_asoc_exit(void) +{ + platform_device_unregister(imote2_snd_device); +} +module_exit(imote2_asoc_exit); + +MODULE_AUTHOR("Jonathan Cameron"); +MODULE_DESCRIPTION("ALSA SoC Imote 2"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/pxa/magician.c b/sound/soc/pxa/magician.c index 0625c342a1c9..326955dea36c 100644 --- a/sound/soc/pxa/magician.c +++ b/sound/soc/pxa/magician.c @@ -106,7 +106,7 @@ static int magician_playback_hw_params(struct snd_pcm_substream *substream, /* 513156 Hz ~= _2_ * 8000 Hz * 32 (+0.23%) */ acds = PXA_SSP_CLK_AUDIO_DIV_16; break; - case 32: + default: /* 32 */ /* 1026312 Hz ~= _2_ * 8000 Hz * 64 (+0.23%) */ acds = PXA_SSP_CLK_AUDIO_DIV_8; } @@ -118,7 +118,7 @@ static int magician_playback_hw_params(struct snd_pcm_substream *substream, /* 351375 Hz ~= 11025 Hz * 32 (-0.41%) */ acds = PXA_SSP_CLK_AUDIO_DIV_4; break; - case 32: + default: /* 32 */ /* 702750 Hz ~= 11025 Hz * 64 (-0.41%) */ acds = PXA_SSP_CLK_AUDIO_DIV_2; } @@ -130,7 +130,7 @@ static int magician_playback_hw_params(struct snd_pcm_substream *substream, /* 702750 Hz ~= 22050 Hz * 32 (-0.41%) */ acds = PXA_SSP_CLK_AUDIO_DIV_2; break; - case 32: + default: /* 32 */ /* 1405500 Hz ~= 22050 Hz * 64 (-0.41%) */ acds = PXA_SSP_CLK_AUDIO_DIV_1; } @@ -142,7 +142,7 @@ static int magician_playback_hw_params(struct snd_pcm_substream *substream, /* 1405500 Hz ~= 44100 Hz * 32 (-0.41%) */ acds = PXA_SSP_CLK_AUDIO_DIV_2; break; - case 32: + default: /* 32 */ /* 2811000 Hz ~= 44100 Hz * 64 (-0.41%) */ acds = PXA_SSP_CLK_AUDIO_DIV_1; } @@ -154,19 +154,20 @@ static int magician_playback_hw_params(struct snd_pcm_substream *substream, /* 1529375 Hz ~= 48000 Hz * 32 (-0.44%) */ acds = PXA_SSP_CLK_AUDIO_DIV_2; break; - case 32: + default: /* 32 */ /* 3058750 Hz ~= 48000 Hz * 64 (-0.44%) */ acds = PXA_SSP_CLK_AUDIO_DIV_1; } break; case 96000: + default: acps = 12235000; switch (width) { case 16: /* 3058750 Hz ~= 96000 Hz * 32 (-0.44%) */ acds = PXA_SSP_CLK_AUDIO_DIV_1; break; - case 32: + default: /* 32 */ /* 6117500 Hz ~= 96000 Hz * 64 (-0.44%) */ acds = PXA_SSP_CLK_AUDIO_DIV_2; div4 = PXA_SSP_CLK_SCDB_1; @@ -183,7 +184,7 @@ static int magician_playback_hw_params(struct snd_pcm_substream *substream, /* set cpu DAI configuration */ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A | - SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBS_CFS); + SND_SOC_DAIFMT_NB_IF | SND_SOC_DAIFMT_CBS_CFS); if (ret < 0) return ret; diff --git a/sound/soc/pxa/palm27x.c b/sound/soc/pxa/palm27x.c index 44fcc4e01e08..e6102fda0a7f 100644 --- a/sound/soc/pxa/palm27x.c +++ b/sound/soc/pxa/palm27x.c @@ -205,7 +205,7 @@ static int palm27x_asoc_probe(struct platform_device *pdev) int ret; if (!(machine_is_palmtx() || machine_is_palmt5() || - machine_is_palmld())) + machine_is_palmld() || machine_is_palmte2())) return -ENODEV; if (pdev->dev.platform_data) diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c index a51058f66747..c5f36e0eab58 100644 --- a/sound/soc/pxa/poodle.c +++ b/sound/soc/pxa/poodle.c @@ -280,38 +280,6 @@ static struct snd_soc_card snd_soc_poodle = { .num_links = 1, }; -/* - * FIXME: This is a temporary bodge to avoid cross-tree merge issues. - * New drivers should register the wm8731 I2C device in the machine - * setup code (under arch/arm for ARM systems). - */ -static int wm8731_i2c_register(void) -{ - struct i2c_board_info info; - struct i2c_adapter *adapter; - struct i2c_client *client; - - memset(&info, 0, sizeof(struct i2c_board_info)); - info.addr = 0x1b; - strlcpy(info.type, "wm8731", I2C_NAME_SIZE); - - adapter = i2c_get_adapter(0); - if (!adapter) { - printk(KERN_ERR "can't get i2c adapter 0\n"); - return -ENODEV; - } - - client = i2c_new_device(adapter, &info); - i2c_put_adapter(adapter); - if (!client) { - printk(KERN_ERR "can't add i2c device at 0x%x\n", - (unsigned int)info.addr); - return -ENODEV; - } - - return 0; -} - /* poodle audio subsystem */ static struct snd_soc_device poodle_snd_devdata = { .card = &snd_soc_poodle, @@ -327,10 +295,6 @@ static int __init poodle_init(void) if (!machine_is_poodle()) return -ENODEV; - ret = wm8731_i2c_register(); - if (ret != 0) - return ret; - locomo_gpio_set_dir(&poodle_locomo_device.dev, POODLE_LOCOMO_GPIO_AMP_ON, 0); /* should we mute HP at startup - burning power ?*/ diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index 286be31545df..19c45409d94c 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c @@ -50,139 +50,6 @@ struct ssp_priv { #endif }; -#define PXA2xx_SSP1_BASE 0x41000000 -#define PXA27x_SSP2_BASE 0x41700000 -#define PXA27x_SSP3_BASE 0x41900000 -#define PXA3xx_SSP4_BASE 0x41a00000 - -static struct pxa2xx_pcm_dma_params pxa_ssp1_pcm_mono_out = { - .name = "SSP1 PCM Mono out", - .dev_addr = PXA2xx_SSP1_BASE + SSDR, - .drcmr = &DRCMR(14), - .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | - DCMD_BURST16 | DCMD_WIDTH2, -}; - -static struct pxa2xx_pcm_dma_params pxa_ssp1_pcm_mono_in = { - .name = "SSP1 PCM Mono in", - .dev_addr = PXA2xx_SSP1_BASE + SSDR, - .drcmr = &DRCMR(13), - .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | - DCMD_BURST16 | DCMD_WIDTH2, -}; - -static struct pxa2xx_pcm_dma_params pxa_ssp1_pcm_stereo_out = { - .name = "SSP1 PCM Stereo out", - .dev_addr = PXA2xx_SSP1_BASE + SSDR, - .drcmr = &DRCMR(14), - .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | - DCMD_BURST16 | DCMD_WIDTH4, -}; - -static struct pxa2xx_pcm_dma_params pxa_ssp1_pcm_stereo_in = { - .name = "SSP1 PCM Stereo in", - .dev_addr = PXA2xx_SSP1_BASE + SSDR, - .drcmr = &DRCMR(13), - .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | - DCMD_BURST16 | DCMD_WIDTH4, -}; - -static struct pxa2xx_pcm_dma_params pxa_ssp2_pcm_mono_out = { - .name = "SSP2 PCM Mono out", - .dev_addr = PXA27x_SSP2_BASE + SSDR, - .drcmr = &DRCMR(16), - .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | - DCMD_BURST16 | DCMD_WIDTH2, -}; - -static struct pxa2xx_pcm_dma_params pxa_ssp2_pcm_mono_in = { - .name = "SSP2 PCM Mono in", - .dev_addr = PXA27x_SSP2_BASE + SSDR, - .drcmr = &DRCMR(15), - .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | - DCMD_BURST16 | DCMD_WIDTH2, -}; - -static struct pxa2xx_pcm_dma_params pxa_ssp2_pcm_stereo_out = { - .name = "SSP2 PCM Stereo out", - .dev_addr = PXA27x_SSP2_BASE + SSDR, - .drcmr = &DRCMR(16), - .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | - DCMD_BURST16 | DCMD_WIDTH4, -}; - -static struct pxa2xx_pcm_dma_params pxa_ssp2_pcm_stereo_in = { - .name = "SSP2 PCM Stereo in", - .dev_addr = PXA27x_SSP2_BASE + SSDR, - .drcmr = &DRCMR(15), - .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | - DCMD_BURST16 | DCMD_WIDTH4, -}; - -static struct pxa2xx_pcm_dma_params pxa_ssp3_pcm_mono_out = { - .name = "SSP3 PCM Mono out", - .dev_addr = PXA27x_SSP3_BASE + SSDR, - .drcmr = &DRCMR(67), - .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | - DCMD_BURST16 | DCMD_WIDTH2, -}; - -static struct pxa2xx_pcm_dma_params pxa_ssp3_pcm_mono_in = { - .name = "SSP3 PCM Mono in", - .dev_addr = PXA27x_SSP3_BASE + SSDR, - .drcmr = &DRCMR(66), - .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | - DCMD_BURST16 | DCMD_WIDTH2, -}; - -static struct pxa2xx_pcm_dma_params pxa_ssp3_pcm_stereo_out = { - .name = "SSP3 PCM Stereo out", - .dev_addr = PXA27x_SSP3_BASE + SSDR, - .drcmr = &DRCMR(67), - .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | - DCMD_BURST16 | DCMD_WIDTH4, -}; - -static struct pxa2xx_pcm_dma_params pxa_ssp3_pcm_stereo_in = { - .name = "SSP3 PCM Stereo in", - .dev_addr = PXA27x_SSP3_BASE + SSDR, - .drcmr = &DRCMR(66), - .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | - DCMD_BURST16 | DCMD_WIDTH4, -}; - -static struct pxa2xx_pcm_dma_params pxa_ssp4_pcm_mono_out = { - .name = "SSP4 PCM Mono out", - .dev_addr = PXA3xx_SSP4_BASE + SSDR, - .drcmr = &DRCMR(67), - .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | - DCMD_BURST16 | DCMD_WIDTH2, -}; - -static struct pxa2xx_pcm_dma_params pxa_ssp4_pcm_mono_in = { - .name = "SSP4 PCM Mono in", - .dev_addr = PXA3xx_SSP4_BASE + SSDR, - .drcmr = &DRCMR(66), - .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | - DCMD_BURST16 | DCMD_WIDTH2, -}; - -static struct pxa2xx_pcm_dma_params pxa_ssp4_pcm_stereo_out = { - .name = "SSP4 PCM Stereo out", - .dev_addr = PXA3xx_SSP4_BASE + SSDR, - .drcmr = &DRCMR(67), - .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | - DCMD_BURST16 | DCMD_WIDTH4, -}; - -static struct pxa2xx_pcm_dma_params pxa_ssp4_pcm_stereo_in = { - .name = "SSP4 PCM Stereo in", - .dev_addr = PXA3xx_SSP4_BASE + SSDR, - .drcmr = &DRCMR(66), - .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | - DCMD_BURST16 | DCMD_WIDTH4, -}; - static void dump_registers(struct ssp_device *ssp) { dev_dbg(&ssp->pdev->dev, "SSCR0 0x%08x SSCR1 0x%08x SSTO 0x%08x\n", @@ -194,25 +61,33 @@ static void dump_registers(struct ssp_device *ssp) ssp_read_reg(ssp, SSACD)); } -static struct pxa2xx_pcm_dma_params *ssp_dma_params[4][4] = { - { - &pxa_ssp1_pcm_mono_out, &pxa_ssp1_pcm_mono_in, - &pxa_ssp1_pcm_stereo_out, &pxa_ssp1_pcm_stereo_in, - }, - { - &pxa_ssp2_pcm_mono_out, &pxa_ssp2_pcm_mono_in, - &pxa_ssp2_pcm_stereo_out, &pxa_ssp2_pcm_stereo_in, - }, - { - &pxa_ssp3_pcm_mono_out, &pxa_ssp3_pcm_mono_in, - &pxa_ssp3_pcm_stereo_out, &pxa_ssp3_pcm_stereo_in, - }, - { - &pxa_ssp4_pcm_mono_out, &pxa_ssp4_pcm_mono_in, - &pxa_ssp4_pcm_stereo_out, &pxa_ssp4_pcm_stereo_in, - }, +struct pxa2xx_pcm_dma_data { + struct pxa2xx_pcm_dma_params params; + char name[20]; }; +static struct pxa2xx_pcm_dma_params * +ssp_get_dma_params(struct ssp_device *ssp, int width4, int out) +{ + struct pxa2xx_pcm_dma_data *dma; + + dma = kzalloc(sizeof(struct pxa2xx_pcm_dma_data), GFP_KERNEL); + if (dma == NULL) + return NULL; + + snprintf(dma->name, 20, "SSP%d PCM %s %s", ssp->port_id, + width4 ? "32-bit" : "16-bit", out ? "out" : "in"); + + dma->params.name = dma->name; + dma->params.drcmr = &DRCMR(out ? ssp->drcmr_tx : ssp->drcmr_rx); + dma->params.dcmd = (out ? (DCMD_INCSRCADDR | DCMD_FLOWTRG) : + (DCMD_INCTRGADDR | DCMD_FLOWSRC)) | + (width4 ? DCMD_WIDTH4 : DCMD_WIDTH2) | DCMD_BURST16; + dma->params.dev_addr = ssp->phys_base + SSDR; + + return &dma->params; +} + static int pxa_ssp_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -227,6 +102,11 @@ static int pxa_ssp_startup(struct snd_pcm_substream *substream, clk_enable(priv->dev.ssp->clk); ssp_disable(&priv->dev); } + + if (cpu_dai->dma_data) { + kfree(cpu_dai->dma_data); + cpu_dai->dma_data = NULL; + } return ret; } @@ -241,6 +121,11 @@ static void pxa_ssp_shutdown(struct snd_pcm_substream *substream, ssp_disable(&priv->dev); clk_disable(priv->dev.ssp->clk); } + + if (cpu_dai->dma_data) { + kfree(cpu_dai->dma_data); + cpu_dai->dma_data = NULL; + } } #ifdef CONFIG_PM @@ -323,7 +208,7 @@ static int pxa_ssp_set_dai_sysclk(struct snd_soc_dai *cpu_dai, ~(SSCR0_ECS | SSCR0_NCS | SSCR0_MOD | SSCR0_ACS); dev_dbg(&ssp->pdev->dev, - "pxa_ssp_set_dai_sysclk id: %d, clk_id %d, freq %d\n", + "pxa_ssp_set_dai_sysclk id: %d, clk_id %d, freq %u\n", cpu_dai->id, clk_id, freq); switch (clk_id) { @@ -472,7 +357,7 @@ static int pxa_ssp_set_dai_pll(struct snd_soc_dai *cpu_dai, ssacd |= (0x6 << 4); dev_dbg(&ssp->pdev->dev, - "Using SSACDD %x to supply %dHz\n", + "Using SSACDD %x to supply %uHz\n", val, freq_out); break; } @@ -589,7 +474,10 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai, case SND_SOC_DAIFMT_NB_IF: break; case SND_SOC_DAIFMT_IB_IF: - sspsp |= SSPSP_SCMODE(3); + sspsp |= SSPSP_SCMODE(2); + break; + case SND_SOC_DAIFMT_IB_NF: + sspsp |= SSPSP_SCMODE(2) | SSPSP_SFRMP; break; default: return -EINVAL; @@ -606,7 +494,13 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai, case SND_SOC_DAIFMT_NB_NF: sspsp |= SSPSP_SFRMP; break; + case SND_SOC_DAIFMT_NB_IF: + break; case SND_SOC_DAIFMT_IB_IF: + sspsp |= SSPSP_SCMODE(2); + break; + case SND_SOC_DAIFMT_IB_NF: + sspsp |= SSPSP_SCMODE(2) | SSPSP_SFRMP; break; default: return -EINVAL; @@ -644,25 +538,23 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; struct ssp_priv *priv = cpu_dai->private_data; struct ssp_device *ssp = priv->dev.ssp; - int dma = 0, chn = params_channels(params); + int chn = params_channels(params); u32 sscr0; u32 sspsp; int width = snd_pcm_format_physical_width(params_format(params)); int ttsa = ssp_read_reg(ssp, SSTSA) & 0xf; - /* select correct DMA params */ - if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) - dma = 1; /* capture DMA offset is 1,3 */ + /* generate correct DMA params */ + if (cpu_dai->dma_data) + kfree(cpu_dai->dma_data); + /* Network mode with one active slot (ttsa == 1) can be used * to force 16-bit frame width on the wire (for S16_LE), even * with two channels. Use 16-bit DMA transfers for this case. */ - if (((chn == 2) && (ttsa != 1)) || (width == 32)) - dma += 2; /* 32-bit DMA offset is 2, 16-bit is 0 */ - - cpu_dai->dma_data = ssp_dma_params[cpu_dai->id][dma]; - - dev_dbg(&ssp->pdev->dev, "pxa_ssp_hw_params: dma %d\n", dma); + cpu_dai->dma_data = ssp_get_dma_params(ssp, + ((chn == 2) && (ttsa != 1)) || (width == 32), + substream->stream == SNDRV_PCM_STREAM_PLAYBACK); /* we can only change the settings if the port is not in use */ if (ssp_read_reg(ssp, SSCR0) & SSCR0_SSE) diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c index 2f4b6e489b78..4743e262895d 100644 --- a/sound/soc/pxa/pxa2xx-i2s.c +++ b/sound/soc/pxa/pxa2xx-i2s.c @@ -106,10 +106,8 @@ static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream, if (IS_ERR(clk_i2s)) return PTR_ERR(clk_i2s); - if (!cpu_dai->active) { - SACR0 |= SACR0_RST; + if (!cpu_dai->active) SACR0 = 0; - } return 0; } @@ -178,9 +176,7 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream, /* is port used by another stream */ if (!(SACR0 & SACR0_ENB)) { - SACR0 = 0; - SACR1 = 0; if (pxa_i2s.master) SACR0 |= SACR0_BCKD; @@ -226,6 +222,10 @@ static int pxa2xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd, switch (cmd) { case SNDRV_PCM_TRIGGER_START: + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + SACR1 &= ~SACR1_DRPL; + else + SACR1 &= ~SACR1_DREC; SACR0 |= SACR0_ENB; break; case SNDRV_PCM_TRIGGER_RESUME: @@ -252,21 +252,16 @@ static void pxa2xx_i2s_shutdown(struct snd_pcm_substream *substream, SAIMR &= ~SAIMR_RFS; } - if (SACR1 & (SACR1_DREC | SACR1_DRPL)) { + if ((SACR1 & (SACR1_DREC | SACR1_DRPL)) == (SACR1_DREC | SACR1_DRPL)) { SACR0 &= ~SACR0_ENB; pxa_i2s_wait(); clk_disable(clk_i2s); } - - clk_put(clk_i2s); } #ifdef CONFIG_PM static int pxa2xx_i2s_suspend(struct snd_soc_dai *dai) { - if (!dai->active) - return 0; - /* store registers */ pxa_i2s.sacr0 = SACR0; pxa_i2s.sacr1 = SACR1; @@ -281,16 +276,14 @@ static int pxa2xx_i2s_suspend(struct snd_soc_dai *dai) static int pxa2xx_i2s_resume(struct snd_soc_dai *dai) { - if (!dai->active) - return 0; - pxa_i2s_wait(); - SACR0 = pxa_i2s.sacr0 &= ~SACR0_ENB; + SACR0 = pxa_i2s.sacr0 & ~SACR0_ENB; SACR1 = pxa_i2s.sacr1; SAIMR = pxa_i2s.saimr; SADIV = pxa_i2s.sadiv; - SACR0 |= SACR0_ENB; + + SACR0 = pxa_i2s.sacr0; return 0; } @@ -329,6 +322,7 @@ struct snd_soc_dai pxa_i2s_dai = { .rates = PXA2XX_I2S_RATES, .formats = SNDRV_PCM_FMTBIT_S16_LE,}, .ops = &pxa_i2s_dai_ops, + .symmetric_rates = 1, }; EXPORT_SYMBOL_GPL(pxa_i2s_dai); @@ -346,6 +340,19 @@ static int pxa2xx_i2s_probe(struct platform_device *dev) if (ret != 0) clk_put(clk_i2s); + /* + * PXA Developer's Manual: + * If SACR0[ENB] is toggled in the middle of a normal operation, + * the SACR0[RST] bit must also be set and cleared to reset all + * I2S controller registers. + */ + SACR0 = SACR0_RST; + SACR0 = 0; + /* Make sure RPL and REC are disabled */ + SACR1 = SACR1_DRPL | SACR1_DREC; + /* Along with FIFO servicing */ + SAIMR &= ~(SAIMR_RFS | SAIMR_TFS); + return ret; } diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c index 289fadf60b10..906709e6dd5f 100644 --- a/sound/soc/s3c24xx/neo1973_wm8753.c +++ b/sound/soc/s3c24xx/neo1973_wm8753.c @@ -345,9 +345,11 @@ static void lm4857_write_regs(void) static int lm4857_get_reg(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - int reg = kcontrol->private_value & 0xFF; - int shift = (kcontrol->private_value >> 8) & 0x0F; - int mask = (kcontrol->private_value >> 16) & 0xFF; + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + int reg = mc->reg; + int shift = mc->shift; + int mask = mc->max; pr_debug("Entered %s\n", __func__); @@ -358,9 +360,11 @@ static int lm4857_get_reg(struct snd_kcontrol *kcontrol, static int lm4857_set_reg(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - int reg = kcontrol->private_value & 0xFF; - int shift = (kcontrol->private_value >> 8) & 0x0F; - int mask = (kcontrol->private_value >> 16) & 0xFF; + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + int reg = mc->reg; + int shift = mc->shift; + int mask = mc->max; if (((lm4857_regs[reg] >> shift) & mask) == ucontrol->value.integer.value[0]) diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.c b/sound/soc/s3c24xx/s3c-i2s-v2.c index ab680aac3fcb..1a283170ca92 100644 --- a/sound/soc/s3c24xx/s3c-i2s-v2.c +++ b/sound/soc/s3c24xx/s3c-i2s-v2.c @@ -37,6 +37,20 @@ #include "s3c-i2s-v2.h" +#undef S3C_IIS_V2_SUPPORTED + +#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413) +#define S3C_IIS_V2_SUPPORTED +#endif + +#ifdef CONFIG_PLAT_S3C64XX +#define S3C_IIS_V2_SUPPORTED +#endif + +#ifndef S3C_IIS_V2_SUPPORTED +#error Unsupported CPU model +#endif + #define S3C2412_I2S_DEBUG_CON 0 static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai) @@ -75,7 +89,7 @@ static inline void dbg_showcon(const char *fn, u32 con) /* Turn on or off the transmission path. */ -void s3c2412_snd_txctrl(struct s3c_i2sv2_info *i2s, int on) +static void s3c2412_snd_txctrl(struct s3c_i2sv2_info *i2s, int on) { void __iomem *regs = i2s->regs; u32 fic, con, mod; @@ -105,7 +119,9 @@ void s3c2412_snd_txctrl(struct s3c_i2sv2_info *i2s, int on) break; default: - dev_err(i2s->dev, "TXEN: Invalid MODE in IISMOD\n"); + dev_err(i2s->dev, "TXEN: Invalid MODE %x in IISMOD\n", + mod & S3C2412_IISMOD_MODE_MASK); + break; } writel(con, regs + S3C2412_IISCON); @@ -132,7 +148,9 @@ void s3c2412_snd_txctrl(struct s3c_i2sv2_info *i2s, int on) break; default: - dev_err(i2s->dev, "TXDIS: Invalid MODE in IISMOD\n"); + dev_err(i2s->dev, "TXDIS: Invalid MODE %x in IISMOD\n", + mod & S3C2412_IISMOD_MODE_MASK); + break; } writel(mod, regs + S3C2412_IISMOD); @@ -143,9 +161,8 @@ void s3c2412_snd_txctrl(struct s3c_i2sv2_info *i2s, int on) dbg_showcon(__func__, con); pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic); } -EXPORT_SYMBOL_GPL(s3c2412_snd_txctrl); -void s3c2412_snd_rxctrl(struct s3c_i2sv2_info *i2s, int on) +static void s3c2412_snd_rxctrl(struct s3c_i2sv2_info *i2s, int on) { void __iomem *regs = i2s->regs; u32 fic, con, mod; @@ -175,7 +192,8 @@ void s3c2412_snd_rxctrl(struct s3c_i2sv2_info *i2s, int on) break; default: - dev_err(i2s->dev, "RXEN: Invalid MODE in IISMOD\n"); + dev_err(i2s->dev, "RXEN: Invalid MODE %x in IISMOD\n", + mod & S3C2412_IISMOD_MODE_MASK); } writel(mod, regs + S3C2412_IISMOD); @@ -199,7 +217,8 @@ void s3c2412_snd_rxctrl(struct s3c_i2sv2_info *i2s, int on) break; default: - dev_err(i2s->dev, "RXEN: Invalid MODE in IISMOD\n"); + dev_err(i2s->dev, "RXDIS: Invalid MODE %x in IISMOD\n", + mod & S3C2412_IISMOD_MODE_MASK); } writel(con, regs + S3C2412_IISCON); @@ -209,7 +228,6 @@ void s3c2412_snd_rxctrl(struct s3c_i2sv2_info *i2s, int on) fic = readl(regs + S3C2412_IISFIC); pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic); } -EXPORT_SYMBOL_GPL(s3c2412_snd_rxctrl); /* * Wait for the LR signal to allow synchronisation to the L/R clock @@ -266,7 +284,7 @@ static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai, */ #define IISMOD_MASTER_MASK (1 << 11) #define IISMOD_SLAVE (1 << 11) -#define IISMOD_MASTER (0x0) +#define IISMOD_MASTER (0 << 11) #endif switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { @@ -281,7 +299,7 @@ static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai, iismod |= IISMOD_MASTER; break; default: - pr_debug("unknwon master/slave format\n"); + pr_err("unknwon master/slave format\n"); return -EINVAL; } @@ -298,7 +316,7 @@ static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai, iismod |= S3C2412_IISMOD_SDF_IIS; break; default: - pr_debug("Unknown data format\n"); + pr_err("Unknown data format\n"); return -EINVAL; } @@ -327,6 +345,7 @@ static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream, iismod = readl(i2s->regs + S3C2412_IISMOD); pr_debug("%s: r: IISMOD: %x\n", __func__, iismod); +#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413) switch (params_format(params)) { case SNDRV_PCM_FORMAT_S8: iismod |= S3C2412_IISMOD_8BIT; @@ -335,6 +354,25 @@ static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream, iismod &= ~S3C2412_IISMOD_8BIT; break; } +#endif + +#ifdef CONFIG_PLAT_S3C64XX + iismod &= ~0x606; + /* Sample size */ + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S8: + /* 8 bit sample, 16fs BCLK */ + iismod |= 0x2004; + break; + case SNDRV_PCM_FORMAT_S16_LE: + /* 16 bit sample, 32fs BCLK */ + break; + case SNDRV_PCM_FORMAT_S24_LE: + /* 24 bit sample, 48fs BCLK */ + iismod |= 0x4002; + break; + } +#endif writel(iismod, i2s->regs + S3C2412_IISMOD); pr_debug("%s: w: IISMOD: %x\n", __func__, iismod); @@ -489,6 +527,8 @@ int s3c_i2sv2_iis_calc_rate(struct s3c_i2sv2_rate_calc *info, unsigned int best_rate = 0; unsigned int best_deviation = INT_MAX; + pr_debug("Input clock rate %ldHz\n", clkrate); + if (fstab == NULL) fstab = iis_fs_tab; @@ -507,7 +547,7 @@ int s3c_i2sv2_iis_calc_rate(struct s3c_i2sv2_rate_calc *info, actual = clkrate / (fsdiv * div); deviation = actual - rate; - printk(KERN_DEBUG "%dfs: div %d => result %d, deviation %d\n", + printk(KERN_DEBUG "%ufs: div %u => result %u, deviation %d\n", fsdiv, div, actual, deviation); deviation = abs(deviation); @@ -523,7 +563,7 @@ int s3c_i2sv2_iis_calc_rate(struct s3c_i2sv2_rate_calc *info, break; } - printk(KERN_DEBUG "best: fs=%d, div=%d, rate=%d\n", + printk(KERN_DEBUG "best: fs=%u, div=%u, rate=%u\n", best_fs, best_div, best_rate); info->fs_div = best_fs; @@ -539,12 +579,31 @@ int s3c_i2sv2_probe(struct platform_device *pdev, unsigned long base) { struct device *dev = &pdev->dev; + unsigned int iismod; i2s->dev = dev; /* record our i2s structure for later use in the callbacks */ dai->private_data = i2s; + if (!base) { + struct resource *res = platform_get_resource(pdev, + IORESOURCE_MEM, + 0); + if (!res) { + dev_err(dev, "Unable to get register resource\n"); + return -ENXIO; + } + + if (!request_mem_region(res->start, resource_size(res), + "s3c64xx-i2s-v4")) { + dev_err(dev, "Unable to request register region\n"); + return -EBUSY; + } + + base = res->start; + } + i2s->regs = ioremap(base, 0x100); if (i2s->regs == NULL) { dev_err(dev, "cannot ioremap registers\n"); @@ -560,12 +619,16 @@ int s3c_i2sv2_probe(struct platform_device *pdev, clk_enable(i2s->iis_pclk); + /* Mark ourselves as in TXRX mode so we can run through our cleanup + * process without warnings. */ + iismod = readl(i2s->regs + S3C2412_IISMOD); + iismod |= S3C2412_IISMOD_MODE_TXRX; + writel(iismod, i2s->regs + S3C2412_IISMOD); s3c2412_snd_txctrl(i2s, 0); s3c2412_snd_rxctrl(i2s, 0); return 0; } - EXPORT_SYMBOL_GPL(s3c_i2sv2_probe); #ifdef CONFIG_PM diff --git a/sound/soc/s3c24xx/s3c2412-i2s.c b/sound/soc/s3c24xx/s3c2412-i2s.c index b7e0b3f0bfc8..a587ec40b449 100644 --- a/sound/soc/s3c24xx/s3c2412-i2s.c +++ b/sound/soc/s3c24xx/s3c2412-i2s.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -120,7 +121,7 @@ static int s3c2412_i2s_probe(struct platform_device *pdev, s3c2412_i2s.iis_cclk = clk_get(&pdev->dev, "i2sclk"); if (s3c2412_i2s.iis_cclk == NULL) { - pr_debug("failed to get i2sclk clock\n"); + pr_err("failed to get i2sclk clock\n"); iounmap(s3c2412_i2s.regs); return -ENODEV; } diff --git a/sound/soc/s3c24xx/s3c2443-ac97.c b/sound/soc/s3c24xx/s3c2443-ac97.c index 3698f707c44d..3f03d5ddfacd 100644 --- a/sound/soc/s3c24xx/s3c2443-ac97.c +++ b/sound/soc/s3c24xx/s3c2443-ac97.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/s3c24xx/s3c24xx-i2s.c index cc066964dad6..556e35f0ab73 100644 --- a/sound/soc/s3c24xx/s3c24xx-i2s.c +++ b/sound/soc/s3c24xx/s3c24xx-i2s.c @@ -21,6 +21,8 @@ #include #include #include +#include + #include #include #include diff --git a/sound/soc/s3c24xx/s3c24xx-pcm.c b/sound/soc/s3c24xx/s3c24xx-pcm.c index 169ddad31575..eecfa5eba06b 100644 --- a/sound/soc/s3c24xx/s3c24xx-pcm.c +++ b/sound/soc/s3c24xx/s3c24xx-pcm.c @@ -218,24 +218,17 @@ static int s3c24xx_pcm_prepare(struct snd_pcm_substream *substream) * sync to pclk, half-word transfers to the IIS-FIFO. */ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { s3c2410_dma_devconfig(prtd->params->channel, - S3C2410_DMASRC_MEM, S3C2410_DISRCC_INC | - S3C2410_DISRCC_APB, prtd->params->dma_addr); - - s3c2410_dma_config(prtd->params->channel, - prtd->params->dma_size, - S3C2410_DCON_SYNC_PCLK | - S3C2410_DCON_HANDSHAKE); + S3C2410_DMASRC_MEM, + prtd->params->dma_addr); } else { - s3c2410_dma_config(prtd->params->channel, - prtd->params->dma_size, - S3C2410_DCON_HANDSHAKE | - S3C2410_DCON_SYNC_PCLK); - s3c2410_dma_devconfig(prtd->params->channel, - S3C2410_DMASRC_HW, 0x3, - prtd->params->dma_addr); + S3C2410_DMASRC_HW, + prtd->params->dma_addr); } + s3c2410_dma_config(prtd->params->channel, + prtd->params->dma_size); + /* flush the DMA channel */ s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_FLUSH); prtd->dma_loaded = 0; diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.c b/sound/soc/s3c24xx/s3c64xx-i2s.c index 33c5de7e255f..3c06c401d0fb 100644 --- a/sound/soc/s3c24xx/s3c64xx-i2s.c +++ b/sound/soc/s3c24xx/s3c64xx-i2s.c @@ -108,48 +108,19 @@ static int s3c64xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, return 0; } - -unsigned long s3c64xx_i2s_get_clockrate(struct snd_soc_dai *dai) +struct clk *s3c64xx_i2s_get_clock(struct snd_soc_dai *dai) { struct s3c_i2sv2_info *i2s = to_info(dai); - return clk_get_rate(i2s->iis_cclk); + return i2s->iis_cclk; } -EXPORT_SYMBOL_GPL(s3c64xx_i2s_get_clockrate); +EXPORT_SYMBOL_GPL(s3c64xx_i2s_get_clock); static int s3c64xx_i2s_probe(struct platform_device *pdev, struct snd_soc_dai *dai) { - struct device *dev = &pdev->dev; - struct s3c_i2sv2_info *i2s; - int ret; - - dev_dbg(dev, "%s: probing dai %d\n", __func__, pdev->id); - - if (pdev->id < 0 || pdev->id > ARRAY_SIZE(s3c64xx_i2s)) { - dev_err(dev, "id %d out of range\n", pdev->id); - return -EINVAL; - } - - i2s = &s3c64xx_i2s[pdev->id]; - - ret = s3c_i2sv2_probe(pdev, dai, i2s, - pdev->id ? S3C64XX_PA_IIS1 : S3C64XX_PA_IIS0); - if (ret) - return ret; - - i2s->dma_capture = &s3c64xx_i2s_pcm_stereo_in[pdev->id]; - i2s->dma_playback = &s3c64xx_i2s_pcm_stereo_out[pdev->id]; - - i2s->iis_cclk = clk_get(dev, "audio-bus"); - if (IS_ERR(i2s->iis_cclk)) { - dev_err(dev, "failed to get audio-bus"); - iounmap(i2s->regs); - return -ENODEV; - } - /* configure GPIO for i2s port */ - switch (pdev->id) { + switch (dai->id) { case 0: s3c_gpio_cfgpin(S3C64XX_GPD(0), S3C64XX_GPD0_I2S0_CLK); s3c_gpio_cfgpin(S3C64XX_GPD(1), S3C64XX_GPD1_I2S0_CDCLK); @@ -175,41 +146,122 @@ static int s3c64xx_i2s_probe(struct platform_device *pdev, SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) #define S3C64XX_I2S_FMTS \ - (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE) + (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE) static struct snd_soc_dai_ops s3c64xx_i2s_dai_ops = { .set_sysclk = s3c64xx_i2s_set_sysclk, }; -struct snd_soc_dai s3c64xx_i2s_dai = { - .name = "s3c64xx-i2s", - .id = 0, - .probe = s3c64xx_i2s_probe, - .playback = { - .channels_min = 2, - .channels_max = 2, - .rates = S3C64XX_I2S_RATES, - .formats = S3C64XX_I2S_FMTS, +struct snd_soc_dai s3c64xx_i2s_dai[] = { + { + .name = "s3c64xx-i2s", + .id = 0, + .probe = s3c64xx_i2s_probe, + .playback = { + .channels_min = 2, + .channels_max = 2, + .rates = S3C64XX_I2S_RATES, + .formats = S3C64XX_I2S_FMTS, + }, + .capture = { + .channels_min = 2, + .channels_max = 2, + .rates = S3C64XX_I2S_RATES, + .formats = S3C64XX_I2S_FMTS, + }, + .ops = &s3c64xx_i2s_dai_ops, + .symmetric_rates = 1, }, - .capture = { - .channels_min = 2, - .channels_max = 2, - .rates = S3C64XX_I2S_RATES, - .formats = S3C64XX_I2S_FMTS, + { + .name = "s3c64xx-i2s", + .id = 1, + .probe = s3c64xx_i2s_probe, + .playback = { + .channels_min = 2, + .channels_max = 2, + .rates = S3C64XX_I2S_RATES, + .formats = S3C64XX_I2S_FMTS, + }, + .capture = { + .channels_min = 2, + .channels_max = 2, + .rates = S3C64XX_I2S_RATES, + .formats = S3C64XX_I2S_FMTS, + }, + .ops = &s3c64xx_i2s_dai_ops, + .symmetric_rates = 1, }, - .ops = &s3c64xx_i2s_dai_ops, }; EXPORT_SYMBOL_GPL(s3c64xx_i2s_dai); +static __devinit int s3c64xx_iis_dev_probe(struct platform_device *pdev) +{ + struct s3c_i2sv2_info *i2s; + struct snd_soc_dai *dai; + int ret; + + if (pdev->id >= ARRAY_SIZE(s3c64xx_i2s)) { + dev_err(&pdev->dev, "id %d out of range\n", pdev->id); + return -EINVAL; + } + + i2s = &s3c64xx_i2s[pdev->id]; + dai = &s3c64xx_i2s_dai[pdev->id]; + dai->dev = &pdev->dev; + + i2s->dma_capture = &s3c64xx_i2s_pcm_stereo_in[pdev->id]; + i2s->dma_playback = &s3c64xx_i2s_pcm_stereo_out[pdev->id]; + + i2s->iis_cclk = clk_get(&pdev->dev, "audio-bus"); + if (IS_ERR(i2s->iis_cclk)) { + dev_err(&pdev->dev, "failed to get audio-bus\n"); + ret = PTR_ERR(i2s->iis_cclk); + goto err; + } + + ret = s3c_i2sv2_probe(pdev, dai, i2s, 0); + if (ret) + goto err_clk; + + ret = s3c_i2sv2_register_dai(dai); + if (ret != 0) + goto err_i2sv2; + + return 0; + +err_i2sv2: + /* Not implemented for I2Sv2 core yet */ +err_clk: + clk_put(i2s->iis_cclk); +err: + return ret; +} + +static __devexit int s3c64xx_iis_dev_remove(struct platform_device *pdev) +{ + dev_err(&pdev->dev, "Device removal not yet supported\n"); + return 0; +} + +static struct platform_driver s3c64xx_iis_driver = { + .probe = s3c64xx_iis_dev_probe, + .remove = s3c64xx_iis_dev_remove, + .driver = { + .name = "s3c64xx-iis", + .owner = THIS_MODULE, + }, +}; + static int __init s3c64xx_i2s_init(void) { - return s3c_i2sv2_register_dai(&s3c64xx_i2s_dai); + return platform_driver_register(&s3c64xx_iis_driver); } module_init(s3c64xx_i2s_init); static void __exit s3c64xx_i2s_exit(void) { - snd_soc_unregister_dai(&s3c64xx_i2s_dai); + platform_driver_unregister(&s3c64xx_iis_driver); } module_exit(s3c64xx_i2s_exit); @@ -217,6 +269,3 @@ module_exit(s3c64xx_i2s_exit); MODULE_AUTHOR("Ben Dooks, "); MODULE_DESCRIPTION("S3C64XX I2S SoC Interface"); MODULE_LICENSE("GPL"); - - - diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.h b/sound/soc/s3c24xx/s3c64xx-i2s.h index b7ffe3c38b66..02148cee2613 100644 --- a/sound/soc/s3c24xx/s3c64xx-i2s.h +++ b/sound/soc/s3c24xx/s3c64xx-i2s.h @@ -15,6 +15,8 @@ #ifndef __SND_SOC_S3C24XX_S3C64XX_I2S_H #define __SND_SOC_S3C24XX_S3C64XX_I2S_H __FILE__ +struct clk; + #include "s3c-i2s-v2.h" #define S3C64XX_DIV_BCLK S3C_I2SV2_DIV_BCLK @@ -24,8 +26,8 @@ #define S3C64XX_CLKSRC_PCLK (0) #define S3C64XX_CLKSRC_MUX (1) -extern struct snd_soc_dai s3c64xx_i2s_dai; +extern struct snd_soc_dai s3c64xx_i2s_dai[]; -extern unsigned long s3c64xx_i2s_get_clockrate(struct snd_soc_dai *cpu_dai); +extern struct clk *s3c64xx_i2s_get_clock(struct snd_soc_dai *dai); #endif /* __SND_SOC_S3C24XX_S3C64XX_I2S_H */ diff --git a/sound/soc/s6000/Kconfig b/sound/soc/s6000/Kconfig new file mode 100644 index 000000000000..c74eb3d4a47c --- /dev/null +++ b/sound/soc/s6000/Kconfig @@ -0,0 +1,19 @@ +config SND_S6000_SOC + tristate "SoC Audio for the Stretch s6000 family" + depends on XTENSA_VARIANT_S6000 + help + Say Y or M if you want to add support for codecs attached to + s6000 family chips. You will also need to select the platform + to support below. + +config SND_S6000_SOC_I2S + tristate + +config SND_S6000_SOC_S6IPCAM + tristate "SoC Audio support for Stretch 6105 IP Camera" + depends on SND_S6000_SOC && XTENSA_PLATFORM_S6105 + select SND_S6000_SOC_I2S + select SND_SOC_TLV320AIC3X + help + Say Y if you want to add support for SoC audio on the + Stretch s6105 IP Camera Reference Design. diff --git a/sound/soc/s6000/Makefile b/sound/soc/s6000/Makefile new file mode 100644 index 000000000000..7a613612e010 --- /dev/null +++ b/sound/soc/s6000/Makefile @@ -0,0 +1,11 @@ +# s6000 Platform Support +snd-soc-s6000-objs := s6000-pcm.o +snd-soc-s6000-i2s-objs := s6000-i2s.o + +obj-$(CONFIG_SND_S6000_SOC) += snd-soc-s6000.o +obj-$(CONFIG_SND_S6000_SOC_I2S) += snd-soc-s6000-i2s.o + +# s6105 Machine Support +snd-soc-s6ipcam-objs := s6105-ipcam.o + +obj-$(CONFIG_SND_S6000_SOC_S6IPCAM) += snd-soc-s6ipcam.o diff --git a/sound/soc/s6000/s6000-i2s.c b/sound/soc/s6000/s6000-i2s.c new file mode 100644 index 000000000000..c5cda187ecab --- /dev/null +++ b/sound/soc/s6000/s6000-i2s.c @@ -0,0 +1,629 @@ +/* + * ALSA SoC I2S Audio Layer for the Stretch S6000 family + * + * Author: Daniel Gloeckner, + * Copyright: (C) 2009 emlix GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "s6000-i2s.h" +#include "s6000-pcm.h" + +struct s6000_i2s_dev { + dma_addr_t sifbase; + u8 __iomem *scbbase; + unsigned int wide; + unsigned int channel_in; + unsigned int channel_out; + unsigned int lines_in; + unsigned int lines_out; + struct s6000_pcm_dma_params dma_params; +}; + +#define S6_I2S_INTERRUPT_STATUS 0x00 +#define S6_I2S_INT_OVERRUN 1 +#define S6_I2S_INT_UNDERRUN 2 +#define S6_I2S_INT_ALIGNMENT 4 +#define S6_I2S_INTERRUPT_ENABLE 0x04 +#define S6_I2S_INTERRUPT_RAW 0x08 +#define S6_I2S_INTERRUPT_CLEAR 0x0C +#define S6_I2S_INTERRUPT_SET 0x10 +#define S6_I2S_MODE 0x20 +#define S6_I2S_DUAL 0 +#define S6_I2S_WIDE 1 +#define S6_I2S_TX_DEFAULT 0x24 +#define S6_I2S_DATA_CFG(c) (0x40 + 0x10 * (c)) +#define S6_I2S_IN 0 +#define S6_I2S_OUT 1 +#define S6_I2S_UNUSED 2 +#define S6_I2S_INTERFACE_CFG(c) (0x44 + 0x10 * (c)) +#define S6_I2S_DIV_MASK 0x001fff +#define S6_I2S_16BIT 0x000000 +#define S6_I2S_20BIT 0x002000 +#define S6_I2S_24BIT 0x004000 +#define S6_I2S_32BIT 0x006000 +#define S6_I2S_BITS_MASK 0x006000 +#define S6_I2S_MEM_16BIT 0x000000 +#define S6_I2S_MEM_32BIT 0x008000 +#define S6_I2S_MEM_MASK 0x008000 +#define S6_I2S_CHANNELS_SHIFT 16 +#define S6_I2S_CHANNELS_MASK 0x030000 +#define S6_I2S_SCK_IN 0x000000 +#define S6_I2S_SCK_OUT 0x040000 +#define S6_I2S_SCK_DIR 0x040000 +#define S6_I2S_WS_IN 0x000000 +#define S6_I2S_WS_OUT 0x080000 +#define S6_I2S_WS_DIR 0x080000 +#define S6_I2S_LEFT_FIRST 0x000000 +#define S6_I2S_RIGHT_FIRST 0x100000 +#define S6_I2S_FIRST 0x100000 +#define S6_I2S_CUR_SCK 0x200000 +#define S6_I2S_CUR_WS 0x400000 +#define S6_I2S_ENABLE(c) (0x48 + 0x10 * (c)) +#define S6_I2S_DISABLE_IF 0x02 +#define S6_I2S_ENABLE_IF 0x03 +#define S6_I2S_IS_BUSY 0x04 +#define S6_I2S_DMA_ACTIVE 0x08 +#define S6_I2S_IS_ENABLED 0x10 + +#define S6_I2S_NUM_LINES 4 + +#define S6_I2S_SIF_PORT0 0x0000000 +#define S6_I2S_SIF_PORT1 0x0000080 /* docs say 0x0000010 */ + +static inline void s6_i2s_write_reg(struct s6000_i2s_dev *dev, int reg, u32 val) +{ + writel(val, dev->scbbase + reg); +} + +static inline u32 s6_i2s_read_reg(struct s6000_i2s_dev *dev, int reg) +{ + return readl(dev->scbbase + reg); +} + +static inline void s6_i2s_mod_reg(struct s6000_i2s_dev *dev, int reg, + u32 mask, u32 val) +{ + val ^= s6_i2s_read_reg(dev, reg) & ~mask; + s6_i2s_write_reg(dev, reg, val); +} + +static void s6000_i2s_start_channel(struct s6000_i2s_dev *dev, int channel) +{ + int i, j, cur, prev; + + /* + * Wait for WCLK to toggle 5 times before enabling the channel + * s6000 Family Datasheet 3.6.4: + * "At least two cycles of WS must occur between commands + * to disable or enable the interface" + */ + j = 0; + prev = ~S6_I2S_CUR_WS; + for (i = 1000000; --i && j < 6; ) { + cur = s6_i2s_read_reg(dev, S6_I2S_INTERFACE_CFG(channel)) + & S6_I2S_CUR_WS; + if (prev != cur) { + prev = cur; + j++; + } + } + if (j < 6) + printk(KERN_WARNING "s6000-i2s: timeout waiting for WCLK\n"); + + s6_i2s_write_reg(dev, S6_I2S_ENABLE(channel), S6_I2S_ENABLE_IF); +} + +static void s6000_i2s_stop_channel(struct s6000_i2s_dev *dev, int channel) +{ + s6_i2s_write_reg(dev, S6_I2S_ENABLE(channel), S6_I2S_DISABLE_IF); +} + +static void s6000_i2s_start(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct s6000_i2s_dev *dev = rtd->dai->cpu_dai->private_data; + int channel; + + channel = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? + dev->channel_out : dev->channel_in; + + s6000_i2s_start_channel(dev, channel); +} + +static void s6000_i2s_stop(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct s6000_i2s_dev *dev = rtd->dai->cpu_dai->private_data; + int channel; + + channel = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? + dev->channel_out : dev->channel_in; + + s6000_i2s_stop_channel(dev, channel); +} + +static int s6000_i2s_trigger(struct snd_pcm_substream *substream, int cmd, + int after) +{ + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE) ^ !after) + s6000_i2s_start(substream); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + if (!after) + s6000_i2s_stop(substream); + } + return 0; +} + +static unsigned int s6000_i2s_int_sources(struct s6000_i2s_dev *dev) +{ + unsigned int pending; + pending = s6_i2s_read_reg(dev, S6_I2S_INTERRUPT_RAW); + pending &= S6_I2S_INT_ALIGNMENT | + S6_I2S_INT_UNDERRUN | + S6_I2S_INT_OVERRUN; + s6_i2s_write_reg(dev, S6_I2S_INTERRUPT_CLEAR, pending); + + return pending; +} + +static unsigned int s6000_i2s_check_xrun(struct snd_soc_dai *cpu_dai) +{ + struct s6000_i2s_dev *dev = cpu_dai->private_data; + unsigned int errors; + unsigned int ret; + + errors = s6000_i2s_int_sources(dev); + if (likely(!errors)) + return 0; + + ret = 0; + if (errors & S6_I2S_INT_ALIGNMENT) + printk(KERN_ERR "s6000-i2s: WCLK misaligned\n"); + if (errors & S6_I2S_INT_UNDERRUN) + ret |= 1 << SNDRV_PCM_STREAM_PLAYBACK; + if (errors & S6_I2S_INT_OVERRUN) + ret |= 1 << SNDRV_PCM_STREAM_CAPTURE; + return ret; +} + +static void s6000_i2s_wait_disabled(struct s6000_i2s_dev *dev) +{ + int channel; + int n = 50; + for (channel = 0; channel < 2; channel++) { + while (--n >= 0) { + int v = s6_i2s_read_reg(dev, S6_I2S_ENABLE(channel)); + if ((v & S6_I2S_IS_ENABLED) + || !(v & (S6_I2S_DMA_ACTIVE | S6_I2S_IS_BUSY))) + break; + udelay(20); + } + } + if (n < 0) + printk(KERN_WARNING "s6000-i2s: timeout disabling interfaces"); +} + +static int s6000_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, + unsigned int fmt) +{ + struct s6000_i2s_dev *dev = cpu_dai->private_data; + u32 w; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + w = S6_I2S_SCK_IN | S6_I2S_WS_IN; + break; + case SND_SOC_DAIFMT_CBS_CFM: + w = S6_I2S_SCK_OUT | S6_I2S_WS_IN; + break; + case SND_SOC_DAIFMT_CBM_CFS: + w = S6_I2S_SCK_IN | S6_I2S_WS_OUT; + break; + case SND_SOC_DAIFMT_CBS_CFS: + w = S6_I2S_SCK_OUT | S6_I2S_WS_OUT; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + w |= S6_I2S_LEFT_FIRST; + break; + case SND_SOC_DAIFMT_NB_IF: + w |= S6_I2S_RIGHT_FIRST; + break; + default: + return -EINVAL; + } + + s6_i2s_mod_reg(dev, S6_I2S_INTERFACE_CFG(0), + S6_I2S_FIRST | S6_I2S_WS_DIR | S6_I2S_SCK_DIR, w); + s6_i2s_mod_reg(dev, S6_I2S_INTERFACE_CFG(1), + S6_I2S_FIRST | S6_I2S_WS_DIR | S6_I2S_SCK_DIR, w); + + return 0; +} + +static int s6000_i2s_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div) +{ + struct s6000_i2s_dev *dev = dai->private_data; + + if (!div || (div & 1) || div > (S6_I2S_DIV_MASK + 1) * 2) + return -EINVAL; + + s6_i2s_mod_reg(dev, S6_I2S_INTERFACE_CFG(div_id), + S6_I2S_DIV_MASK, div / 2 - 1); + return 0; +} + +static int s6000_i2s_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct s6000_i2s_dev *dev = dai->private_data; + int interf; + u32 w = 0; + + if (dev->wide) + interf = 0; + else { + w |= (((params_channels(params) - 2) / 2) + << S6_I2S_CHANNELS_SHIFT) & S6_I2S_CHANNELS_MASK; + interf = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + ? dev->channel_out : dev->channel_in; + } + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + w |= S6_I2S_16BIT | S6_I2S_MEM_16BIT; + break; + case SNDRV_PCM_FORMAT_S32_LE: + w |= S6_I2S_32BIT | S6_I2S_MEM_32BIT; + break; + default: + printk(KERN_WARNING "s6000-i2s: unsupported PCM format %x\n", + params_format(params)); + return -EINVAL; + } + + if (s6_i2s_read_reg(dev, S6_I2S_INTERFACE_CFG(interf)) + & S6_I2S_IS_ENABLED) { + printk(KERN_ERR "s6000-i2s: interface already enabled\n"); + return -EBUSY; + } + + s6_i2s_mod_reg(dev, S6_I2S_INTERFACE_CFG(interf), + S6_I2S_CHANNELS_MASK|S6_I2S_MEM_MASK|S6_I2S_BITS_MASK, + w); + + return 0; +} + +static int s6000_i2s_dai_probe(struct platform_device *pdev, + struct snd_soc_dai *dai) +{ + struct s6000_i2s_dev *dev = dai->private_data; + struct s6000_snd_platform_data *pdata = pdev->dev.platform_data; + + if (!pdata) + return -EINVAL; + + dev->wide = pdata->wide; + dev->channel_in = pdata->channel_in; + dev->channel_out = pdata->channel_out; + dev->lines_in = pdata->lines_in; + dev->lines_out = pdata->lines_out; + + s6_i2s_write_reg(dev, S6_I2S_MODE, + dev->wide ? S6_I2S_WIDE : S6_I2S_DUAL); + + if (dev->wide) { + int i; + + if (dev->lines_in + dev->lines_out > S6_I2S_NUM_LINES) + return -EINVAL; + + dev->channel_in = 0; + dev->channel_out = 1; + dai->capture.channels_min = 2 * dev->lines_in; + dai->capture.channels_max = dai->capture.channels_min; + dai->playback.channels_min = 2 * dev->lines_out; + dai->playback.channels_max = dai->playback.channels_min; + + for (i = 0; i < dev->lines_out; i++) + s6_i2s_write_reg(dev, S6_I2S_DATA_CFG(i), S6_I2S_OUT); + + for (; i < S6_I2S_NUM_LINES - dev->lines_in; i++) + s6_i2s_write_reg(dev, S6_I2S_DATA_CFG(i), + S6_I2S_UNUSED); + + for (; i < S6_I2S_NUM_LINES; i++) + s6_i2s_write_reg(dev, S6_I2S_DATA_CFG(i), S6_I2S_IN); + } else { + unsigned int cfg[2] = {S6_I2S_UNUSED, S6_I2S_UNUSED}; + + if (dev->lines_in > 1 || dev->lines_out > 1) + return -EINVAL; + + dai->capture.channels_min = 2 * dev->lines_in; + dai->capture.channels_max = 8 * dev->lines_in; + dai->playback.channels_min = 2 * dev->lines_out; + dai->playback.channels_max = 8 * dev->lines_out; + + if (dev->lines_in) + cfg[dev->channel_in] = S6_I2S_IN; + if (dev->lines_out) + cfg[dev->channel_out] = S6_I2S_OUT; + + s6_i2s_write_reg(dev, S6_I2S_DATA_CFG(0), cfg[0]); + s6_i2s_write_reg(dev, S6_I2S_DATA_CFG(1), cfg[1]); + } + + if (dev->lines_out) { + if (dev->lines_in) { + if (!dev->dma_params.dma_out) + return -ENODEV; + } else { + dev->dma_params.dma_out = dev->dma_params.dma_in; + dev->dma_params.dma_in = 0; + } + } + dev->dma_params.sif_in = dev->sifbase + (dev->channel_in ? + S6_I2S_SIF_PORT1 : S6_I2S_SIF_PORT0); + dev->dma_params.sif_out = dev->sifbase + (dev->channel_out ? + S6_I2S_SIF_PORT1 : S6_I2S_SIF_PORT0); + dev->dma_params.same_rate = pdata->same_rate | pdata->wide; + return 0; +} + +#define S6000_I2S_RATES (SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_5512 | \ + SNDRV_PCM_RATE_8000_192000) +#define S6000_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_ops s6000_i2s_dai_ops = { + .set_fmt = s6000_i2s_set_dai_fmt, + .set_clkdiv = s6000_i2s_set_clkdiv, + .hw_params = s6000_i2s_hw_params, +}; + +struct snd_soc_dai s6000_i2s_dai = { + .name = "s6000-i2s", + .id = 0, + .probe = s6000_i2s_dai_probe, + .playback = { + .channels_min = 2, + .channels_max = 8, + .formats = S6000_I2S_FORMATS, + .rates = S6000_I2S_RATES, + .rate_min = 0, + .rate_max = 1562500, + }, + .capture = { + .channels_min = 2, + .channels_max = 8, + .formats = S6000_I2S_FORMATS, + .rates = S6000_I2S_RATES, + .rate_min = 0, + .rate_max = 1562500, + }, + .ops = &s6000_i2s_dai_ops, +} +EXPORT_SYMBOL_GPL(s6000_i2s_dai); + +static int __devinit s6000_i2s_probe(struct platform_device *pdev) +{ + struct s6000_i2s_dev *dev; + struct resource *scbmem, *sifmem, *region, *dma1, *dma2; + u8 __iomem *mmio; + int ret; + + scbmem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!scbmem) { + dev_err(&pdev->dev, "no mem resource?\n"); + ret = -ENODEV; + goto err_release_none; + } + + region = request_mem_region(scbmem->start, + scbmem->end - scbmem->start + 1, + pdev->name); + if (!region) { + dev_err(&pdev->dev, "I2S SCB region already claimed\n"); + ret = -EBUSY; + goto err_release_none; + } + + mmio = ioremap(scbmem->start, scbmem->end - scbmem->start + 1); + if (!mmio) { + dev_err(&pdev->dev, "can't ioremap SCB region\n"); + ret = -ENOMEM; + goto err_release_scb; + } + + sifmem = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!sifmem) { + dev_err(&pdev->dev, "no second mem resource?\n"); + ret = -ENODEV; + goto err_release_map; + } + + region = request_mem_region(sifmem->start, + sifmem->end - sifmem->start + 1, + pdev->name); + if (!region) { + dev_err(&pdev->dev, "I2S SIF region already claimed\n"); + ret = -EBUSY; + goto err_release_map; + } + + dma1 = platform_get_resource(pdev, IORESOURCE_DMA, 0); + if (!dma1) { + dev_err(&pdev->dev, "no dma resource?\n"); + ret = -ENODEV; + goto err_release_sif; + } + + region = request_mem_region(dma1->start, dma1->end - dma1->start + 1, + pdev->name); + if (!region) { + dev_err(&pdev->dev, "I2S DMA region already claimed\n"); + ret = -EBUSY; + goto err_release_sif; + } + + dma2 = platform_get_resource(pdev, IORESOURCE_DMA, 1); + if (dma2) { + region = request_mem_region(dma2->start, + dma2->end - dma2->start + 1, + pdev->name); + if (!region) { + dev_err(&pdev->dev, + "I2S DMA region already claimed\n"); + ret = -EBUSY; + goto err_release_dma1; + } + } + + dev = kzalloc(sizeof(struct s6000_i2s_dev), GFP_KERNEL); + if (!dev) { + ret = -ENOMEM; + goto err_release_dma2; + } + + s6000_i2s_dai.dev = &pdev->dev; + s6000_i2s_dai.private_data = dev; + s6000_i2s_dai.dma_data = &dev->dma_params; + + dev->sifbase = sifmem->start; + dev->scbbase = mmio; + + s6_i2s_write_reg(dev, S6_I2S_INTERRUPT_ENABLE, 0); + s6_i2s_write_reg(dev, S6_I2S_INTERRUPT_CLEAR, + S6_I2S_INT_ALIGNMENT | + S6_I2S_INT_UNDERRUN | + S6_I2S_INT_OVERRUN); + + s6000_i2s_stop_channel(dev, 0); + s6000_i2s_stop_channel(dev, 1); + s6000_i2s_wait_disabled(dev); + + dev->dma_params.check_xrun = s6000_i2s_check_xrun; + dev->dma_params.trigger = s6000_i2s_trigger; + dev->dma_params.dma_in = dma1->start; + dev->dma_params.dma_out = dma2 ? dma2->start : 0; + dev->dma_params.irq = platform_get_irq(pdev, 0); + if (dev->dma_params.irq < 0) { + dev_err(&pdev->dev, "no irq resource?\n"); + ret = -ENODEV; + goto err_release_dev; + } + + s6_i2s_write_reg(dev, S6_I2S_INTERRUPT_ENABLE, + S6_I2S_INT_ALIGNMENT | + S6_I2S_INT_UNDERRUN | + S6_I2S_INT_OVERRUN); + + ret = snd_soc_register_dai(&s6000_i2s_dai); + if (ret) + goto err_release_dev; + + return 0; + +err_release_dev: + kfree(dev); +err_release_dma2: + if (dma2) + release_mem_region(dma2->start, dma2->end - dma2->start + 1); +err_release_dma1: + release_mem_region(dma1->start, dma1->end - dma1->start + 1); +err_release_sif: + release_mem_region(sifmem->start, (sifmem->end - sifmem->start) + 1); +err_release_map: + iounmap(mmio); +err_release_scb: + release_mem_region(scbmem->start, (scbmem->end - scbmem->start) + 1); +err_release_none: + return ret; +} + +static void __devexit s6000_i2s_remove(struct platform_device *pdev) +{ + struct s6000_i2s_dev *dev = s6000_i2s_dai.private_data; + struct resource *region; + void __iomem *mmio = dev->scbbase; + + snd_soc_unregister_dai(&s6000_i2s_dai); + + s6000_i2s_stop_channel(dev, 0); + s6000_i2s_stop_channel(dev, 1); + + s6_i2s_write_reg(dev, S6_I2S_INTERRUPT_ENABLE, 0); + s6000_i2s_dai.private_data = 0; + kfree(dev); + + region = platform_get_resource(pdev, IORESOURCE_DMA, 0); + release_mem_region(region->start, region->end - region->start + 1); + + region = platform_get_resource(pdev, IORESOURCE_DMA, 1); + if (region) + release_mem_region(region->start, + region->end - region->start + 1); + + region = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(region->start, (region->end - region->start) + 1); + + iounmap(mmio); + region = platform_get_resource(pdev, IORESOURCE_IO, 0); + release_mem_region(region->start, (region->end - region->start) + 1); +} + +static struct platform_driver s6000_i2s_driver = { + .probe = s6000_i2s_probe, + .remove = __devexit_p(s6000_i2s_remove), + .driver = { + .name = "s6000-i2s", + .owner = THIS_MODULE, + }, +}; + +static int __init s6000_i2s_init(void) +{ + return platform_driver_register(&s6000_i2s_driver); +} +module_init(s6000_i2s_init); + +static void __exit s6000_i2s_exit(void) +{ + platform_driver_unregister(&s6000_i2s_driver); +} +module_exit(s6000_i2s_exit); + +MODULE_AUTHOR("Daniel Gloeckner"); +MODULE_DESCRIPTION("Stretch s6000 family I2S SoC Interface"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/s6000/s6000-i2s.h b/sound/soc/s6000/s6000-i2s.h new file mode 100644 index 000000000000..2375fdfe6dba --- /dev/null +++ b/sound/soc/s6000/s6000-i2s.h @@ -0,0 +1,25 @@ +/* + * ALSA SoC I2S Audio Layer for the Stretch s6000 family + * + * Author: Daniel Gloeckner, + * Copyright: (C) 2009 emlix GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _S6000_I2S_H +#define _S6000_I2S_H + +extern struct snd_soc_dai s6000_i2s_dai; + +struct s6000_snd_platform_data { + int lines_in; + int lines_out; + int channel_in; + int channel_out; + int wide; + int same_rate; +}; +#endif diff --git a/sound/soc/s6000/s6000-pcm.c b/sound/soc/s6000/s6000-pcm.c new file mode 100644 index 000000000000..83b8028e209d --- /dev/null +++ b/sound/soc/s6000/s6000-pcm.c @@ -0,0 +1,497 @@ +/* + * ALSA PCM interface for the Stetch s6000 family + * + * Author: Daniel Gloeckner, + * Copyright: (C) 2009 emlix GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "s6000-pcm.h" + +#define S6_PCM_PREALLOCATE_SIZE (96 * 1024) +#define S6_PCM_PREALLOCATE_MAX (2048 * 1024) + +static struct snd_pcm_hardware s6000_pcm_hardware = { + .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_JOINT_DUPLEX), + .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE), + .rates = (SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_5512 | \ + SNDRV_PCM_RATE_8000_192000), + .rate_min = 0, + .rate_max = 1562500, + .channels_min = 2, + .channels_max = 8, + .buffer_bytes_max = 0x7ffffff0, + .period_bytes_min = 16, + .period_bytes_max = 0xfffff0, + .periods_min = 2, + .periods_max = 1024, /* no limit */ + .fifo_size = 0, +}; + +struct s6000_runtime_data { + spinlock_t lock; + int period; /* current DMA period */ +}; + +static void s6000_pcm_enqueue_dma(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct s6000_runtime_data *prtd = runtime->private_data; + struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; + struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; + int channel; + unsigned int period_size; + unsigned int dma_offset; + dma_addr_t dma_pos; + dma_addr_t src, dst; + + period_size = snd_pcm_lib_period_bytes(substream); + dma_offset = prtd->period * period_size; + dma_pos = runtime->dma_addr + dma_offset; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + src = dma_pos; + dst = par->sif_out; + channel = par->dma_out; + } else { + src = par->sif_in; + dst = dma_pos; + channel = par->dma_in; + } + + if (!s6dmac_channel_enabled(DMA_MASK_DMAC(channel), + DMA_INDEX_CHNL(channel))) + return; + + if (s6dmac_fifo_full(DMA_MASK_DMAC(channel), DMA_INDEX_CHNL(channel))) { + printk(KERN_ERR "s6000-pcm: fifo full\n"); + return; + } + + BUG_ON(period_size & 15); + s6dmac_put_fifo(DMA_MASK_DMAC(channel), DMA_INDEX_CHNL(channel), + src, dst, period_size); + + prtd->period++; + if (unlikely(prtd->period >= runtime->periods)) + prtd->period = 0; +} + +static irqreturn_t s6000_pcm_irq(int irq, void *data) +{ + struct snd_pcm *pcm = data; + struct snd_soc_pcm_runtime *runtime = pcm->private_data; + struct s6000_pcm_dma_params *params = runtime->dai->cpu_dai->dma_data; + struct s6000_runtime_data *prtd; + unsigned int has_xrun; + int i, ret = IRQ_NONE; + u32 channel[2] = { + [SNDRV_PCM_STREAM_PLAYBACK] = params->dma_out, + [SNDRV_PCM_STREAM_CAPTURE] = params->dma_in + }; + + has_xrun = params->check_xrun(runtime->dai->cpu_dai); + + for (i = 0; i < ARRAY_SIZE(channel); ++i) { + struct snd_pcm_substream *substream = pcm->streams[i].substream; + unsigned int pending; + + if (!channel[i]) + continue; + + if (unlikely(has_xrun & (1 << i)) && + substream->runtime && + snd_pcm_running(substream)) { + dev_dbg(pcm->dev, "xrun\n"); + snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); + ret = IRQ_HANDLED; + } + + pending = s6dmac_int_sources(DMA_MASK_DMAC(channel[i]), + DMA_INDEX_CHNL(channel[i])); + + if (pending & 1) { + ret = IRQ_HANDLED; + if (likely(substream->runtime && + snd_pcm_running(substream))) { + snd_pcm_period_elapsed(substream); + dev_dbg(pcm->dev, "period elapsed %x %x\n", + s6dmac_cur_src(DMA_MASK_DMAC(channel[i]), + DMA_INDEX_CHNL(channel[i])), + s6dmac_cur_dst(DMA_MASK_DMAC(channel[i]), + DMA_INDEX_CHNL(channel[i]))); + prtd = substream->runtime->private_data; + spin_lock(&prtd->lock); + s6000_pcm_enqueue_dma(substream); + spin_unlock(&prtd->lock); + } + } + + if (unlikely(pending & ~7)) { + if (pending & (1 << 3)) + printk(KERN_WARNING + "s6000-pcm: DMA %x Underflow\n", + channel[i]); + if (pending & (1 << 4)) + printk(KERN_WARNING + "s6000-pcm: DMA %x Overflow\n", + channel[i]); + if (pending & 0x1e0) + printk(KERN_WARNING + "s6000-pcm: DMA %x Master Error " + "(mask %x)\n", + channel[i], pending >> 5); + + } + } + + return ret; +} + +static int s6000_pcm_start(struct snd_pcm_substream *substream) +{ + struct s6000_runtime_data *prtd = substream->runtime->private_data; + struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; + struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; + unsigned long flags; + int srcinc; + u32 dma; + + spin_lock_irqsave(&prtd->lock, flags); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + srcinc = 1; + dma = par->dma_out; + } else { + srcinc = 0; + dma = par->dma_in; + } + s6dmac_enable_chan(DMA_MASK_DMAC(dma), DMA_INDEX_CHNL(dma), + 1 /* priority 1 (0 is max) */, + 0 /* peripheral requests w/o xfer length mode */, + srcinc /* source address increment */, + srcinc^1 /* destination address increment */, + 0 /* chunksize 0 (skip impossible on this dma) */, + 0 /* source skip after chunk (impossible) */, + 0 /* destination skip after chunk (impossible) */, + 4 /* 16 byte burst size */, + -1 /* don't conserve bandwidth */, + 0 /* low watermark irq descriptor theshold */, + 0 /* disable hardware timestamps */, + 1 /* enable channel */); + + s6000_pcm_enqueue_dma(substream); + s6000_pcm_enqueue_dma(substream); + + spin_unlock_irqrestore(&prtd->lock, flags); + + return 0; +} + +static int s6000_pcm_stop(struct snd_pcm_substream *substream) +{ + struct s6000_runtime_data *prtd = substream->runtime->private_data; + struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; + struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; + unsigned long flags; + u32 channel; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + channel = par->dma_out; + else + channel = par->dma_in; + + s6dmac_set_terminal_count(DMA_MASK_DMAC(channel), + DMA_INDEX_CHNL(channel), 0); + + spin_lock_irqsave(&prtd->lock, flags); + + s6dmac_disable_chan(DMA_MASK_DMAC(channel), DMA_INDEX_CHNL(channel)); + + spin_unlock_irqrestore(&prtd->lock, flags); + + return 0; +} + +static int s6000_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; + struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; + int ret; + + ret = par->trigger(substream, cmd, 0); + if (ret < 0) + return ret; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + ret = s6000_pcm_start(substream); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + ret = s6000_pcm_stop(substream); + break; + default: + ret = -EINVAL; + } + if (ret < 0) + return ret; + + return par->trigger(substream, cmd, 1); +} + +static int s6000_pcm_prepare(struct snd_pcm_substream *substream) +{ + struct s6000_runtime_data *prtd = substream->runtime->private_data; + + prtd->period = 0; + + return 0; +} + +static snd_pcm_uframes_t s6000_pcm_pointer(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; + struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; + struct snd_pcm_runtime *runtime = substream->runtime; + struct s6000_runtime_data *prtd = runtime->private_data; + unsigned long flags; + unsigned int offset; + dma_addr_t count; + + spin_lock_irqsave(&prtd->lock, flags); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + count = s6dmac_cur_src(DMA_MASK_DMAC(par->dma_out), + DMA_INDEX_CHNL(par->dma_out)); + else + count = s6dmac_cur_dst(DMA_MASK_DMAC(par->dma_in), + DMA_INDEX_CHNL(par->dma_in)); + + count -= runtime->dma_addr; + + spin_unlock_irqrestore(&prtd->lock, flags); + + offset = bytes_to_frames(runtime, count); + if (unlikely(offset >= runtime->buffer_size)) + offset = 0; + + return offset; +} + +static int s6000_pcm_open(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; + struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; + struct snd_pcm_runtime *runtime = substream->runtime; + struct s6000_runtime_data *prtd; + int ret; + + snd_soc_set_runtime_hwparams(substream, &s6000_pcm_hardware); + + ret = snd_pcm_hw_constraint_step(runtime, 0, + SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 16); + if (ret < 0) + return ret; + ret = snd_pcm_hw_constraint_step(runtime, 0, + SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 16); + if (ret < 0) + return ret; + ret = snd_pcm_hw_constraint_integer(runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + if (ret < 0) + return ret; + + if (par->same_rate) { + int rate; + spin_lock(&par->lock); /* needed? */ + rate = par->rate; + spin_unlock(&par->lock); + if (rate != -1) { + ret = snd_pcm_hw_constraint_minmax(runtime, + SNDRV_PCM_HW_PARAM_RATE, + rate, rate); + if (ret < 0) + return ret; + } + } + + prtd = kzalloc(sizeof(struct s6000_runtime_data), GFP_KERNEL); + if (prtd == NULL) + return -ENOMEM; + + spin_lock_init(&prtd->lock); + + runtime->private_data = prtd; + + return 0; +} + +static int s6000_pcm_close(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct s6000_runtime_data *prtd = runtime->private_data; + + kfree(prtd); + + return 0; +} + +static int s6000_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; + struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; + int ret; + ret = snd_pcm_lib_malloc_pages(substream, + params_buffer_bytes(hw_params)); + if (ret < 0) { + printk(KERN_WARNING "s6000-pcm: allocation of memory failed\n"); + return ret; + } + + if (par->same_rate) { + spin_lock(&par->lock); + if (par->rate == -1 || + !(par->in_use & ~(1 << substream->stream))) { + par->rate = params_rate(hw_params); + par->in_use |= 1 << substream->stream; + } else if (params_rate(hw_params) != par->rate) { + snd_pcm_lib_free_pages(substream); + par->in_use &= ~(1 << substream->stream); + ret = -EBUSY; + } + spin_unlock(&par->lock); + } + return ret; +} + +static int s6000_pcm_hw_free(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; + struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; + + spin_lock(&par->lock); + par->in_use &= ~(1 << substream->stream); + if (!par->in_use) + par->rate = -1; + spin_unlock(&par->lock); + + return snd_pcm_lib_free_pages(substream); +} + +static struct snd_pcm_ops s6000_pcm_ops = { + .open = s6000_pcm_open, + .close = s6000_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = s6000_pcm_hw_params, + .hw_free = s6000_pcm_hw_free, + .trigger = s6000_pcm_trigger, + .prepare = s6000_pcm_prepare, + .pointer = s6000_pcm_pointer, +}; + +static void s6000_pcm_free(struct snd_pcm *pcm) +{ + struct snd_soc_pcm_runtime *runtime = pcm->private_data; + struct s6000_pcm_dma_params *params = runtime->dai->cpu_dai->dma_data; + + free_irq(params->irq, pcm); + snd_pcm_lib_preallocate_free_for_all(pcm); +} + +static u64 s6000_pcm_dmamask = DMA_32BIT_MASK; + +static int s6000_pcm_new(struct snd_card *card, + struct snd_soc_dai *dai, struct snd_pcm *pcm) +{ + struct snd_soc_pcm_runtime *runtime = pcm->private_data; + struct s6000_pcm_dma_params *params = runtime->dai->cpu_dai->dma_data; + int res; + + if (!card->dev->dma_mask) + card->dev->dma_mask = &s6000_pcm_dmamask; + if (!card->dev->coherent_dma_mask) + card->dev->coherent_dma_mask = DMA_32BIT_MASK; + + if (params->dma_in) { + s6dmac_disable_chan(DMA_MASK_DMAC(params->dma_in), + DMA_INDEX_CHNL(params->dma_in)); + s6dmac_int_sources(DMA_MASK_DMAC(params->dma_in), + DMA_INDEX_CHNL(params->dma_in)); + } + + if (params->dma_out) { + s6dmac_disable_chan(DMA_MASK_DMAC(params->dma_out), + DMA_INDEX_CHNL(params->dma_out)); + s6dmac_int_sources(DMA_MASK_DMAC(params->dma_out), + DMA_INDEX_CHNL(params->dma_out)); + } + + res = request_irq(params->irq, s6000_pcm_irq, IRQF_SHARED, + s6000_soc_platform.name, pcm); + if (res) { + printk(KERN_ERR "s6000-pcm couldn't get IRQ\n"); + return res; + } + + res = snd_pcm_lib_preallocate_pages_for_all(pcm, + SNDRV_DMA_TYPE_DEV, + card->dev, + S6_PCM_PREALLOCATE_SIZE, + S6_PCM_PREALLOCATE_MAX); + if (res) + printk(KERN_WARNING "s6000-pcm: preallocation failed\n"); + + spin_lock_init(¶ms->lock); + params->in_use = 0; + params->rate = -1; + return 0; +} + +struct snd_soc_platform s6000_soc_platform = { + .name = "s6000-audio", + .pcm_ops = &s6000_pcm_ops, + .pcm_new = s6000_pcm_new, + .pcm_free = s6000_pcm_free, +}; +EXPORT_SYMBOL_GPL(s6000_soc_platform); + +static int __init s6000_pcm_init(void) +{ + return snd_soc_register_platform(&s6000_soc_platform); +} +module_init(s6000_pcm_init); + +static void __exit s6000_pcm_exit(void) +{ + snd_soc_unregister_platform(&s6000_soc_platform); +} +module_exit(s6000_pcm_exit); + +MODULE_AUTHOR("Daniel Gloeckner"); +MODULE_DESCRIPTION("Stretch s6000 family PCM DMA module"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/s6000/s6000-pcm.h b/sound/soc/s6000/s6000-pcm.h new file mode 100644 index 000000000000..96f23f6f52bf --- /dev/null +++ b/sound/soc/s6000/s6000-pcm.h @@ -0,0 +1,35 @@ +/* + * ALSA PCM interface for the Stretch s6000 family + * + * Author: Daniel Gloeckner, + * Copyright: (C) 2009 emlix GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _S6000_PCM_H +#define _S6000_PCM_H + +struct snd_soc_dai; +struct snd_pcm_substream; + +struct s6000_pcm_dma_params { + unsigned int (*check_xrun)(struct snd_soc_dai *cpu_dai); + int (*trigger)(struct snd_pcm_substream *substream, int cmd, int after); + dma_addr_t sif_in; + dma_addr_t sif_out; + u32 dma_in; + u32 dma_out; + int irq; + int same_rate; + + spinlock_t lock; + int in_use; + int rate; +}; + +extern struct snd_soc_platform s6000_soc_platform; + +#endif diff --git a/sound/soc/s6000/s6105-ipcam.c b/sound/soc/s6000/s6105-ipcam.c new file mode 100644 index 000000000000..b5f95f9781c1 --- /dev/null +++ b/sound/soc/s6000/s6105-ipcam.c @@ -0,0 +1,244 @@ +/* + * ASoC driver for Stretch s6105 IP camera platform + * + * Author: Daniel Gloeckner, + * Copyright: (C) 2009 emlix GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "../codecs/tlv320aic3x.h" +#include "s6000-pcm.h" +#include "s6000-i2s.h" + +#define S6105_CAM_CODEC_CLOCK 12288000 + +static int s6105_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + int ret = 0; + + /* set codec DAI configuration */ + ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_CBM_CFM); + if (ret < 0) + return ret; + + /* set cpu DAI configuration */ + ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBM_CFM | + SND_SOC_DAIFMT_NB_NF); + if (ret < 0) + return ret; + + /* set the codec system clock */ + ret = snd_soc_dai_set_sysclk(codec_dai, 0, S6105_CAM_CODEC_CLOCK, + SND_SOC_CLOCK_OUT); + if (ret < 0) + return ret; + + return 0; +} + +static struct snd_soc_ops s6105_ops = { + .hw_params = s6105_hw_params, +}; + +/* s6105 machine dapm widgets */ +static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { + SND_SOC_DAPM_LINE("Audio Out Differential", NULL), + SND_SOC_DAPM_LINE("Audio Out Stereo", NULL), + SND_SOC_DAPM_LINE("Audio In", NULL), +}; + +/* s6105 machine audio_mapnections to the codec pins */ +static const struct snd_soc_dapm_route audio_map[] = { + /* Audio Out connected to HPLOUT, HPLCOM, HPROUT */ + {"Audio Out Differential", NULL, "HPLOUT"}, + {"Audio Out Differential", NULL, "HPLCOM"}, + {"Audio Out Stereo", NULL, "HPLOUT"}, + {"Audio Out Stereo", NULL, "HPROUT"}, + + /* Audio In connected to LINE1L, LINE1R */ + {"LINE1L", NULL, "Audio In"}, + {"LINE1R", NULL, "Audio In"}, +}; + +static int output_type_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 2; + if (uinfo->value.enumerated.item) { + uinfo->value.enumerated.item = 1; + strcpy(uinfo->value.enumerated.name, "HPLOUT/HPROUT"); + } else { + strcpy(uinfo->value.enumerated.name, "HPLOUT/HPLCOM"); + } + return 0; +} + +static int output_type_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.enumerated.item[0] = kcontrol->private_value; + return 0; +} + +static int output_type_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = kcontrol->private_data; + unsigned int val = (ucontrol->value.enumerated.item[0] != 0); + char *differential = "Audio Out Differential"; + char *stereo = "Audio Out Stereo"; + + if (kcontrol->private_value == val) + return 0; + kcontrol->private_value = val; + snd_soc_dapm_disable_pin(codec, val ? differential : stereo); + snd_soc_dapm_sync(codec); + snd_soc_dapm_enable_pin(codec, val ? stereo : differential); + snd_soc_dapm_sync(codec); + + return 1; +} + +static const struct snd_kcontrol_new audio_out_mux = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Output Mux", + .index = 0, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = output_type_info, + .get = output_type_get, + .put = output_type_put, + .private_value = 1 /* default to stereo */ +}; + +/* Logic for a aic3x as connected on the s6105 ip camera ref design */ +static int s6105_aic3x_init(struct snd_soc_codec *codec) +{ + /* Add s6105 specific widgets */ + snd_soc_dapm_new_controls(codec, aic3x_dapm_widgets, + ARRAY_SIZE(aic3x_dapm_widgets)); + + /* Set up s6105 specific audio path audio_map */ + snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); + + /* not present */ + snd_soc_dapm_nc_pin(codec, "MONO_LOUT"); + snd_soc_dapm_nc_pin(codec, "LINE2L"); + snd_soc_dapm_nc_pin(codec, "LINE2R"); + + /* not connected */ + snd_soc_dapm_nc_pin(codec, "MIC3L"); /* LINE2L on this chip */ + snd_soc_dapm_nc_pin(codec, "MIC3R"); /* LINE2R on this chip */ + snd_soc_dapm_nc_pin(codec, "LLOUT"); + snd_soc_dapm_nc_pin(codec, "RLOUT"); + snd_soc_dapm_nc_pin(codec, "HPRCOM"); + + /* always connected */ + snd_soc_dapm_enable_pin(codec, "Audio In"); + + /* must correspond to audio_out_mux.private_value initializer */ + snd_soc_dapm_disable_pin(codec, "Audio Out Differential"); + snd_soc_dapm_sync(codec); + snd_soc_dapm_enable_pin(codec, "Audio Out Stereo"); + + snd_soc_dapm_sync(codec); + + snd_ctl_add(codec->card, snd_ctl_new1(&audio_out_mux, codec)); + + return 0; +} + +/* s6105 digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link s6105_dai = { + .name = "TLV320AIC31", + .stream_name = "AIC31", + .cpu_dai = &s6000_i2s_dai, + .codec_dai = &aic3x_dai, + .init = s6105_aic3x_init, + .ops = &s6105_ops, +}; + +/* s6105 audio machine driver */ +static struct snd_soc_card snd_soc_card_s6105 = { + .name = "Stretch IP Camera", + .platform = &s6000_soc_platform, + .dai_link = &s6105_dai, + .num_links = 1, +}; + +/* s6105 audio private data */ +static struct aic3x_setup_data s6105_aic3x_setup = { + .i2c_bus = 0, + .i2c_address = 0x18, +}; + +/* s6105 audio subsystem */ +static struct snd_soc_device s6105_snd_devdata = { + .card = &snd_soc_card_s6105, + .codec_dev = &soc_codec_dev_aic3x, + .codec_data = &s6105_aic3x_setup, +}; + +static struct s6000_snd_platform_data __initdata s6105_snd_data = { + .wide = 0, + .channel_in = 0, + .channel_out = 1, + .lines_in = 1, + .lines_out = 1, + .same_rate = 1, +}; + +static struct platform_device *s6105_snd_device; + +static int __init s6105_init(void) +{ + int ret; + + s6105_snd_device = platform_device_alloc("soc-audio", -1); + if (!s6105_snd_device) + return -ENOMEM; + + platform_set_drvdata(s6105_snd_device, &s6105_snd_devdata); + s6105_snd_devdata.dev = &s6105_snd_device->dev; + platform_device_add_data(s6105_snd_device, &s6105_snd_data, + sizeof(s6105_snd_data)); + + ret = platform_device_add(s6105_snd_device); + if (ret) + platform_device_put(s6105_snd_device); + + return ret; +} + +static void __exit s6105_exit(void) +{ + platform_device_unregister(s6105_snd_device); +} + +module_init(s6105_init); +module_exit(s6105_exit); + +MODULE_AUTHOR("Daniel Gloeckner"); +MODULE_DESCRIPTION("Stretch s6105 IP camera ASoC driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/sh/ssi.c b/sound/soc/sh/ssi.c index 56fa0872abbb..b378096cadb1 100644 --- a/sound/soc/sh/ssi.c +++ b/sound/soc/sh/ssi.c @@ -145,7 +145,7 @@ static int ssi_hw_params(struct snd_pcm_substream *substream, recv = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? 0 : 1; pr_debug("ssi_hw_params() enter\nssicr was %08lx\n", ssicr); - pr_debug("bits: %d channels: %d\n", bits, channels); + pr_debug("bits: %u channels: %u\n", bits, channels); ssicr &= ~(CR_TRMD | CR_CHNL_MASK | CR_DWL_MASK | CR_PDTA | CR_SWL_MASK); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 1cd149b9ce69..1d70829464ef 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -113,6 +113,35 @@ static int soc_ac97_dev_register(struct snd_soc_codec *codec) } #endif +static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_card *card = socdev->card; + struct snd_soc_dai_link *machine = rtd->dai; + struct snd_soc_dai *cpu_dai = machine->cpu_dai; + struct snd_soc_dai *codec_dai = machine->codec_dai; + int ret; + + if (codec_dai->symmetric_rates || cpu_dai->symmetric_rates || + machine->symmetric_rates) { + dev_dbg(card->dev, "Symmetry forces %dHz rate\n", + machine->rate); + + ret = snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_RATE, + machine->rate, + machine->rate); + if (ret < 0) { + dev_err(card->dev, + "Unable to apply rate symmetry constraint: %d\n", ret); + return ret; + } + } + + return 0; +} + /* * Called by ALSA when a PCM substream is opened, the runtime->hw record is * then initialized and any private data can be allocated. This also calls @@ -221,6 +250,13 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) goto machine_err; } + /* Symmetry only applies if we've already got an active stream. */ + if (cpu_dai->active || codec_dai->active) { + ret = soc_pcm_apply_symmetry(substream); + if (ret != 0) + goto machine_err; + } + pr_debug("asoc: %s <-> %s info:\n", codec_dai->name, cpu_dai->name); pr_debug("asoc: rate mask 0x%x\n", runtime->hw.rates); pr_debug("asoc: min ch %d max ch %d\n", runtime->hw.channels_min, @@ -263,7 +299,6 @@ static void close_delayed_work(struct work_struct *work) { struct snd_soc_card *card = container_of(work, struct snd_soc_card, delayed_work.work); - struct snd_soc_device *socdev = card->socdev; struct snd_soc_codec *codec = card->codec; struct snd_soc_dai *codec_dai; int i; @@ -279,27 +314,10 @@ static void close_delayed_work(struct work_struct *work) /* are we waiting on this codec DAI stream */ if (codec_dai->pop_wait == 1) { - - /* Reduce power if no longer active */ - if (codec->active == 0) { - pr_debug("pop wq D1 %s %s\n", codec->name, - codec_dai->playback.stream_name); - snd_soc_dapm_set_bias_level(socdev, - SND_SOC_BIAS_PREPARE); - } - codec_dai->pop_wait = 0; snd_soc_dapm_stream_event(codec, codec_dai->playback.stream_name, SND_SOC_DAPM_STREAM_STOP); - - /* Fall into standby if no longer active */ - if (codec->active == 0) { - pr_debug("pop wq D3 %s %s\n", codec->name, - codec_dai->playback.stream_name); - snd_soc_dapm_set_bias_level(socdev, - SND_SOC_BIAS_STANDBY); - } } } mutex_unlock(&pcm_mutex); @@ -363,10 +381,6 @@ static int soc_codec_close(struct snd_pcm_substream *substream) snd_soc_dapm_stream_event(codec, codec_dai->capture.stream_name, SND_SOC_DAPM_STREAM_STOP); - - if (codec->active == 0 && codec_dai->pop_wait == 0) - snd_soc_dapm_set_bias_level(socdev, - SND_SOC_BIAS_STANDBY); } mutex_unlock(&pcm_mutex); @@ -431,36 +445,16 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) cancel_delayed_work(&card->delayed_work); } - /* do we need to power up codec */ - if (codec->bias_level != SND_SOC_BIAS_ON) { - snd_soc_dapm_set_bias_level(socdev, - SND_SOC_BIAS_PREPARE); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + snd_soc_dapm_stream_event(codec, + codec_dai->playback.stream_name, + SND_SOC_DAPM_STREAM_START); + else + snd_soc_dapm_stream_event(codec, + codec_dai->capture.stream_name, + SND_SOC_DAPM_STREAM_START); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - snd_soc_dapm_stream_event(codec, - codec_dai->playback.stream_name, - SND_SOC_DAPM_STREAM_START); - else - snd_soc_dapm_stream_event(codec, - codec_dai->capture.stream_name, - SND_SOC_DAPM_STREAM_START); - - snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_ON); - snd_soc_dai_digital_mute(codec_dai, 0); - - } else { - /* codec already powered - power on widgets */ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - snd_soc_dapm_stream_event(codec, - codec_dai->playback.stream_name, - SND_SOC_DAPM_STREAM_START); - else - snd_soc_dapm_stream_event(codec, - codec_dai->capture.stream_name, - SND_SOC_DAPM_STREAM_START); - - snd_soc_dai_digital_mute(codec_dai, 0); - } + snd_soc_dai_digital_mute(codec_dai, 0); out: mutex_unlock(&pcm_mutex); @@ -521,6 +515,8 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, } } + machine->rate = params_rate(params); + out: mutex_unlock(&pcm_mutex); return ret; @@ -632,6 +628,12 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) struct snd_soc_codec *codec = card->codec; int i; + /* If the initialization of this soc device failed, there is no codec + * associated with it. Just bail out in this case. + */ + if (!codec) + return 0; + /* Due to the resume being scheduled into a workqueue we could * suspend before that's finished - wait for it to complete. */ @@ -1334,6 +1336,7 @@ int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid) return ret; } + codec->socdev = socdev; codec->card->dev = socdev->dev; codec->card->private_data = codec; strncpy(codec->card->driver, codec->name, sizeof(codec->card->driver)); @@ -1386,6 +1389,9 @@ int snd_soc_init_card(struct snd_soc_device *socdev) snprintf(codec->card->longname, sizeof(codec->card->longname), "%s (%s)", card->name, codec->name); + /* Make sure all DAPM widgets are instantiated */ + snd_soc_dapm_new_widgets(codec); + ret = snd_card_register(codec->card); if (ret < 0) { printk(KERN_ERR "asoc: failed to register soundcard for %s\n", @@ -1744,7 +1750,7 @@ int snd_soc_info_volsw_ext(struct snd_kcontrol *kcontrol, { int max = kcontrol->private_value; - if (max == 1) + if (max == 1 && !strstr(kcontrol->id.name, " Volume")) uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; else uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; @@ -1774,7 +1780,7 @@ int snd_soc_info_volsw(struct snd_kcontrol *kcontrol, unsigned int shift = mc->shift; unsigned int rshift = mc->rshift; - if (max == 1) + if (max == 1 && !strstr(kcontrol->id.name, " Volume")) uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; else uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; @@ -1881,7 +1887,7 @@ int snd_soc_info_volsw_2r(struct snd_kcontrol *kcontrol, (struct soc_mixer_control *)kcontrol->private_value; int max = mc->max; - if (max == 1) + if (max == 1 && !strstr(kcontrol->id.name, " Volume")) uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; else uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; @@ -2065,7 +2071,7 @@ EXPORT_SYMBOL_GPL(snd_soc_put_volsw_s8); int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int freq, int dir) { - if (dai->ops->set_sysclk) + if (dai->ops && dai->ops->set_sysclk) return dai->ops->set_sysclk(dai, clk_id, freq, dir); else return -EINVAL; @@ -2085,7 +2091,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk); int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div) { - if (dai->ops->set_clkdiv) + if (dai->ops && dai->ops->set_clkdiv) return dai->ops->set_clkdiv(dai, div_id, div); else return -EINVAL; @@ -2104,7 +2110,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_clkdiv); int snd_soc_dai_set_pll(struct snd_soc_dai *dai, int pll_id, unsigned int freq_in, unsigned int freq_out) { - if (dai->ops->set_pll) + if (dai->ops && dai->ops->set_pll) return dai->ops->set_pll(dai, pll_id, freq_in, freq_out); else return -EINVAL; @@ -2120,7 +2126,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_pll); */ int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { - if (dai->ops->set_fmt) + if (dai->ops && dai->ops->set_fmt) return dai->ops->set_fmt(dai, fmt); else return -EINVAL; @@ -2139,7 +2145,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt); int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int mask, int slots) { - if (dai->ops->set_sysclk) + if (dai->ops && dai->ops->set_tdm_slot) return dai->ops->set_tdm_slot(dai, mask, slots); else return -EINVAL; @@ -2155,7 +2161,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot); */ int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate) { - if (dai->ops->set_sysclk) + if (dai->ops && dai->ops->set_tristate) return dai->ops->set_tristate(dai, tristate); else return -EINVAL; @@ -2171,7 +2177,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_tristate); */ int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute) { - if (dai->ops->digital_mute) + if (dai->ops && dai->ops->digital_mute) return dai->ops->digital_mute(dai, mute); else return -EINVAL; @@ -2352,6 +2358,39 @@ void snd_soc_unregister_platform(struct snd_soc_platform *platform) } EXPORT_SYMBOL_GPL(snd_soc_unregister_platform); +static u64 codec_format_map[] = { + SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE, + SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE, + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE, + SNDRV_PCM_FMTBIT_U24_LE | SNDRV_PCM_FMTBIT_U24_BE, + SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE, + SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_U32_BE, + SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_U24_3BE, + SNDRV_PCM_FMTBIT_U24_3LE | SNDRV_PCM_FMTBIT_U24_3BE, + SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE, + SNDRV_PCM_FMTBIT_U20_3LE | SNDRV_PCM_FMTBIT_U20_3BE, + SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE, + SNDRV_PCM_FMTBIT_U18_3LE | SNDRV_PCM_FMTBIT_U18_3BE, + SNDRV_PCM_FMTBIT_FLOAT_LE | SNDRV_PCM_FMTBIT_FLOAT_BE, + SNDRV_PCM_FMTBIT_FLOAT64_LE | SNDRV_PCM_FMTBIT_FLOAT64_BE, + SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE + | SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE, +}; + +/* Fix up the DAI formats for endianness: codecs don't actually see + * the endianness of the data but we're using the CPU format + * definitions which do need to include endianness so we ensure that + * codec DAIs always have both big and little endian variants set. + */ +static void fixup_codec_formats(struct snd_soc_pcm_stream *stream) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(codec_format_map); i++) + if (stream->formats & codec_format_map[i]) + stream->formats |= codec_format_map[i]; +} + /** * snd_soc_register_codec - Register a codec with the ASoC core * @@ -2359,6 +2398,8 @@ EXPORT_SYMBOL_GPL(snd_soc_unregister_platform); */ int snd_soc_register_codec(struct snd_soc_codec *codec) { + int i; + if (!codec->name) return -EINVAL; @@ -2368,6 +2409,11 @@ int snd_soc_register_codec(struct snd_soc_codec *codec) INIT_LIST_HEAD(&codec->list); + for (i = 0; i < codec->num_dai; i++) { + fixup_codec_formats(&codec->dai[i].playback); + fixup_codec_formats(&codec->dai[i].capture); + } + mutex_lock(&client_mutex); list_add(&codec->list, &codec_list); snd_soc_instantiate_cards(); diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 735903a74675..21c69074aa17 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -12,7 +12,7 @@ * Features: * o Changes power status of internal codec blocks depending on the * dynamic configuration of codec internal audio paths and active - * DAC's/ADC's. + * DACs/ADCs. * o Platform power domain - can support external components i.e. amps and * mic/meadphone insertion events. * o Automatic Mic Bias support @@ -52,23 +52,21 @@ /* dapm power sequences - make this per codec in the future */ static int dapm_up_seq[] = { - snd_soc_dapm_pre, snd_soc_dapm_micbias, snd_soc_dapm_mic, - snd_soc_dapm_mux, snd_soc_dapm_value_mux, snd_soc_dapm_dac, - snd_soc_dapm_mixer, snd_soc_dapm_mixer_named_ctl, snd_soc_dapm_pga, - snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk, snd_soc_dapm_post + snd_soc_dapm_pre, snd_soc_dapm_supply, snd_soc_dapm_micbias, + snd_soc_dapm_mic, snd_soc_dapm_mux, snd_soc_dapm_value_mux, + snd_soc_dapm_dac, snd_soc_dapm_mixer, snd_soc_dapm_mixer_named_ctl, + snd_soc_dapm_pga, snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk, + snd_soc_dapm_post }; static int dapm_down_seq[] = { snd_soc_dapm_pre, snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk, snd_soc_dapm_pga, snd_soc_dapm_mixer_named_ctl, snd_soc_dapm_mixer, snd_soc_dapm_dac, snd_soc_dapm_mic, snd_soc_dapm_micbias, - snd_soc_dapm_mux, snd_soc_dapm_value_mux, snd_soc_dapm_post + snd_soc_dapm_mux, snd_soc_dapm_value_mux, snd_soc_dapm_supply, + snd_soc_dapm_post }; -static int dapm_status = 1; -module_param(dapm_status, int, 0); -MODULE_PARM_DESC(dapm_status, "enable DPM sysfs entries"); - static void pop_wait(u32 pop_time) { if (pop_time) @@ -96,6 +94,48 @@ static inline struct snd_soc_dapm_widget *dapm_cnew_widget( return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL); } +/** + * snd_soc_dapm_set_bias_level - set the bias level for the system + * @socdev: audio device + * @level: level to configure + * + * Configure the bias (power) levels for the SoC audio device. + * + * Returns 0 for success else error. + */ +static int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev, + enum snd_soc_bias_level level) +{ + struct snd_soc_card *card = socdev->card; + struct snd_soc_codec *codec = socdev->card->codec; + int ret = 0; + + switch (level) { + case SND_SOC_BIAS_ON: + dev_dbg(socdev->dev, "Setting full bias\n"); + break; + case SND_SOC_BIAS_PREPARE: + dev_dbg(socdev->dev, "Setting bias prepare\n"); + break; + case SND_SOC_BIAS_STANDBY: + dev_dbg(socdev->dev, "Setting standby bias\n"); + break; + case SND_SOC_BIAS_OFF: + dev_dbg(socdev->dev, "Setting bias off\n"); + break; + default: + dev_err(socdev->dev, "Setting invalid bias %d\n", level); + return -EINVAL; + } + + if (card->set_bias_level) + ret = card->set_bias_level(card, level); + if (ret == 0 && codec->set_bias_level) + ret = codec->set_bias_level(codec, level); + + return ret; +} + /* set up initial codec paths */ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, struct snd_soc_dapm_path *p, int i) @@ -165,6 +205,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, case snd_soc_dapm_dac: case snd_soc_dapm_micbias: case snd_soc_dapm_vmid: + case snd_soc_dapm_supply: p->connect = 1; break; /* does effect routing - dynamically connected */ @@ -179,7 +220,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, } } -/* connect mux widget to it's interconnecting audio paths */ +/* connect mux widget to its interconnecting audio paths */ static int dapm_connect_mux(struct snd_soc_codec *codec, struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest, struct snd_soc_dapm_path *path, const char *control_name, @@ -202,7 +243,7 @@ static int dapm_connect_mux(struct snd_soc_codec *codec, return -ENODEV; } -/* connect mixer widget to it's interconnecting audio paths */ +/* connect mixer widget to its interconnecting audio paths */ static int dapm_connect_mixer(struct snd_soc_codec *codec, struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest, struct snd_soc_dapm_path *path, const char *control_name) @@ -357,8 +398,9 @@ static int dapm_new_mixer(struct snd_soc_codec *codec, path->long_name); ret = snd_ctl_add(codec->card, path->kcontrol); if (ret < 0) { - printk(KERN_ERR "asoc: failed to add dapm kcontrol %s\n", - path->long_name); + printk(KERN_ERR "asoc: failed to add dapm kcontrol %s: %d\n", + path->long_name, + ret); kfree(path->long_name); path->long_name = NULL; return ret; @@ -434,6 +476,9 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget) struct snd_soc_dapm_path *path; int con = 0; + if (widget->id == snd_soc_dapm_supply) + return 0; + if (widget->id == snd_soc_dapm_adc && widget->active) return 1; @@ -470,6 +515,9 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget) struct snd_soc_dapm_path *path; int con = 0; + if (widget->id == snd_soc_dapm_supply) + return 0; + /* active stream ? */ if (widget->id == snd_soc_dapm_dac && widget->active) return 1; @@ -521,6 +569,126 @@ int dapm_reg_event(struct snd_soc_dapm_widget *w, } EXPORT_SYMBOL_GPL(dapm_reg_event); +/* Standard power change method, used to apply power changes to most + * widgets. + */ +static int dapm_generic_apply_power(struct snd_soc_dapm_widget *w) +{ + int ret; + + /* call any power change event handlers */ + if (w->event) + pr_debug("power %s event for %s flags %x\n", + w->power ? "on" : "off", + w->name, w->event_flags); + + /* power up pre event */ + if (w->power && w->event && + (w->event_flags & SND_SOC_DAPM_PRE_PMU)) { + ret = w->event(w, NULL, SND_SOC_DAPM_PRE_PMU); + if (ret < 0) + return ret; + } + + /* power down pre event */ + if (!w->power && w->event && + (w->event_flags & SND_SOC_DAPM_PRE_PMD)) { + ret = w->event(w, NULL, SND_SOC_DAPM_PRE_PMD); + if (ret < 0) + return ret; + } + + /* Lower PGA volume to reduce pops */ + if (w->id == snd_soc_dapm_pga && !w->power) + dapm_set_pga(w, w->power); + + dapm_update_bits(w); + + /* Raise PGA volume to reduce pops */ + if (w->id == snd_soc_dapm_pga && w->power) + dapm_set_pga(w, w->power); + + /* power up post event */ + if (w->power && w->event && + (w->event_flags & SND_SOC_DAPM_POST_PMU)) { + ret = w->event(w, + NULL, SND_SOC_DAPM_POST_PMU); + if (ret < 0) + return ret; + } + + /* power down post event */ + if (!w->power && w->event && + (w->event_flags & SND_SOC_DAPM_POST_PMD)) { + ret = w->event(w, NULL, SND_SOC_DAPM_POST_PMD); + if (ret < 0) + return ret; + } + + return 0; +} + +/* Generic check to see if a widget should be powered. + */ +static int dapm_generic_check_power(struct snd_soc_dapm_widget *w) +{ + int in, out; + + in = is_connected_input_ep(w); + dapm_clear_walk(w->codec); + out = is_connected_output_ep(w); + dapm_clear_walk(w->codec); + return out != 0 && in != 0; +} + +/* Check to see if an ADC has power */ +static int dapm_adc_check_power(struct snd_soc_dapm_widget *w) +{ + int in; + + if (w->active) { + in = is_connected_input_ep(w); + dapm_clear_walk(w->codec); + return in != 0; + } else { + return dapm_generic_check_power(w); + } +} + +/* Check to see if a DAC has power */ +static int dapm_dac_check_power(struct snd_soc_dapm_widget *w) +{ + int out; + + if (w->active) { + out = is_connected_output_ep(w); + dapm_clear_walk(w->codec); + return out != 0; + } else { + return dapm_generic_check_power(w); + } +} + +/* Check to see if a power supply is needed */ +static int dapm_supply_check_power(struct snd_soc_dapm_widget *w) +{ + struct snd_soc_dapm_path *path; + int power = 0; + + /* Check if one of our outputs is connected */ + list_for_each_entry(path, &w->sinks, list_source) { + if (path->sink && path->sink->power_check && + path->sink->power_check(path->sink)) { + power = 1; + break; + } + } + + dapm_clear_walk(w->codec); + + return power; +} + /* * Scan a single DAPM widget for a complete audio path and update the * power status appropriately. @@ -528,32 +696,10 @@ EXPORT_SYMBOL_GPL(dapm_reg_event); static int dapm_power_widget(struct snd_soc_codec *codec, int event, struct snd_soc_dapm_widget *w) { - int in, out, power_change, power, ret; + int ret; - /* vmid - no action */ - if (w->id == snd_soc_dapm_vmid) - return 0; - - /* active ADC */ - if (w->id == snd_soc_dapm_adc && w->active) { - in = is_connected_input_ep(w); - dapm_clear_walk(w->codec); - w->power = (in != 0) ? 1 : 0; - dapm_update_bits(w); - return 0; - } - - /* active DAC */ - if (w->id == snd_soc_dapm_dac && w->active) { - out = is_connected_output_ep(w); - dapm_clear_walk(w->codec); - w->power = (out != 0) ? 1 : 0; - dapm_update_bits(w); - return 0; - } - - /* pre and post event widgets */ - if (w->id == snd_soc_dapm_pre) { + switch (w->id) { + case snd_soc_dapm_pre: if (!w->event) return 0; @@ -569,8 +715,8 @@ static int dapm_power_widget(struct snd_soc_codec *codec, int event, return ret; } return 0; - } - if (w->id == snd_soc_dapm_post) { + + case snd_soc_dapm_post: if (!w->event) return 0; @@ -586,70 +732,10 @@ static int dapm_power_widget(struct snd_soc_codec *codec, int event, return ret; } return 0; + + default: + return dapm_generic_apply_power(w); } - - /* all other widgets */ - in = is_connected_input_ep(w); - dapm_clear_walk(w->codec); - out = is_connected_output_ep(w); - dapm_clear_walk(w->codec); - power = (out != 0 && in != 0) ? 1 : 0; - power_change = (w->power == power) ? 0 : 1; - w->power = power; - - if (!power_change) - return 0; - - /* call any power change event handlers */ - if (w->event) - pr_debug("power %s event for %s flags %x\n", - w->power ? "on" : "off", - w->name, w->event_flags); - - /* power up pre event */ - if (power && w->event && - (w->event_flags & SND_SOC_DAPM_PRE_PMU)) { - ret = w->event(w, NULL, SND_SOC_DAPM_PRE_PMU); - if (ret < 0) - return ret; - } - - /* power down pre event */ - if (!power && w->event && - (w->event_flags & SND_SOC_DAPM_PRE_PMD)) { - ret = w->event(w, NULL, SND_SOC_DAPM_PRE_PMD); - if (ret < 0) - return ret; - } - - /* Lower PGA volume to reduce pops */ - if (w->id == snd_soc_dapm_pga && !power) - dapm_set_pga(w, power); - - dapm_update_bits(w); - - /* Raise PGA volume to reduce pops */ - if (w->id == snd_soc_dapm_pga && power) - dapm_set_pga(w, power); - - /* power up post event */ - if (power && w->event && - (w->event_flags & SND_SOC_DAPM_POST_PMU)) { - ret = w->event(w, - NULL, SND_SOC_DAPM_POST_PMU); - if (ret < 0) - return ret; - } - - /* power down post event */ - if (!power && w->event && - (w->event_flags & SND_SOC_DAPM_POST_PMD)) { - ret = w->event(w, NULL, SND_SOC_DAPM_POST_PMD); - if (ret < 0) - return ret; - } - - return 0; } /* @@ -663,31 +749,102 @@ static int dapm_power_widget(struct snd_soc_codec *codec, int event, */ static int dapm_power_widgets(struct snd_soc_codec *codec, int event) { + struct snd_soc_device *socdev = codec->socdev; struct snd_soc_dapm_widget *w; - int i, c = 1, *seq = NULL, ret = 0; + int ret = 0; + int i, power; + int sys_power = 0; - /* do we have a sequenced stream event */ - if (event == SND_SOC_DAPM_STREAM_START) { - c = ARRAY_SIZE(dapm_up_seq); - seq = dapm_up_seq; - } else if (event == SND_SOC_DAPM_STREAM_STOP) { - c = ARRAY_SIZE(dapm_down_seq); - seq = dapm_down_seq; + INIT_LIST_HEAD(&codec->up_list); + INIT_LIST_HEAD(&codec->down_list); + + /* Check which widgets we need to power and store them in + * lists indicating if they should be powered up or down. + */ + list_for_each_entry(w, &codec->dapm_widgets, list) { + switch (w->id) { + case snd_soc_dapm_pre: + list_add_tail(&codec->down_list, &w->power_list); + break; + case snd_soc_dapm_post: + list_add_tail(&codec->up_list, &w->power_list); + break; + + default: + if (!w->power_check) + continue; + + power = w->power_check(w); + if (power) + sys_power = 1; + + if (w->power == power) + continue; + + if (power) + list_add_tail(&w->power_list, &codec->up_list); + else + list_add_tail(&w->power_list, + &codec->down_list); + + w->power = power; + break; + } } - for (i = 0; i < c; i++) { - list_for_each_entry(w, &codec->dapm_widgets, list) { + /* If we're changing to all on or all off then prepare */ + if ((sys_power && codec->bias_level == SND_SOC_BIAS_STANDBY) || + (!sys_power && codec->bias_level == SND_SOC_BIAS_ON)) { + ret = snd_soc_dapm_set_bias_level(socdev, + SND_SOC_BIAS_PREPARE); + if (ret != 0) + pr_err("Failed to prepare bias: %d\n", ret); + } + /* Power down widgets first; try to avoid amplifying pops. */ + for (i = 0; i < ARRAY_SIZE(dapm_down_seq); i++) { + list_for_each_entry(w, &codec->down_list, power_list) { /* is widget in stream order */ - if (seq && seq[i] && w->id != seq[i]) + if (w->id != dapm_down_seq[i]) continue; ret = dapm_power_widget(codec, event, w); if (ret != 0) - return ret; + pr_err("Failed to power down %s: %d\n", + w->name, ret); } } + /* Now power up. */ + for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++) { + list_for_each_entry(w, &codec->up_list, power_list) { + /* is widget in stream order */ + if (w->id != dapm_up_seq[i]) + continue; + + ret = dapm_power_widget(codec, event, w); + if (ret != 0) + pr_err("Failed to power up %s: %d\n", + w->name, ret); + } + } + + /* If we just powered the last thing off drop to standby bias */ + if (codec->bias_level == SND_SOC_BIAS_PREPARE && !sys_power) { + ret = snd_soc_dapm_set_bias_level(socdev, + SND_SOC_BIAS_STANDBY); + if (ret != 0) + pr_err("Failed to apply standby bias: %d\n", ret); + } + + /* If we just powered up then move to active bias */ + if (codec->bias_level == SND_SOC_BIAS_PREPARE && sys_power) { + ret = snd_soc_dapm_set_bias_level(socdev, + SND_SOC_BIAS_ON); + if (ret != 0) + pr_err("Failed to apply active bias: %d\n", ret); + } + return 0; } @@ -723,6 +880,7 @@ static void dbg_dump_dapm(struct snd_soc_codec* codec, const char *action) case snd_soc_dapm_pga: case snd_soc_dapm_mixer: case snd_soc_dapm_mixer_named_ctl: + case snd_soc_dapm_supply: if (w->name) { in = is_connected_input_ep(w); dapm_clear_walk(w->codec); @@ -851,6 +1009,7 @@ static ssize_t dapm_widget_show(struct device *dev, case snd_soc_dapm_pga: case snd_soc_dapm_mixer: case snd_soc_dapm_mixer_named_ctl: + case snd_soc_dapm_supply: if (w->name) count += sprintf(buf + count, "%s: %s\n", w->name, w->power ? "On":"Off"); @@ -883,16 +1042,12 @@ static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL); int snd_soc_dapm_sys_add(struct device *dev) { - if (!dapm_status) - return 0; return device_create_file(dev, &dev_attr_dapm_widget); } static void snd_soc_dapm_sys_remove(struct device *dev) { - if (dapm_status) { - device_remove_file(dev, &dev_attr_dapm_widget); - } + device_remove_file(dev, &dev_attr_dapm_widget); } /* free all dapm widgets and resources */ @@ -1015,6 +1170,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_codec *codec, case snd_soc_dapm_vmid: case snd_soc_dapm_pre: case snd_soc_dapm_post: + case snd_soc_dapm_supply: list_add(&path->list, &codec->dapm_paths); list_add(&path->list_sink, &wsink->sources); list_add(&path->list_source, &wsource->sinks); @@ -1108,15 +1264,22 @@ int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec) case snd_soc_dapm_switch: case snd_soc_dapm_mixer: case snd_soc_dapm_mixer_named_ctl: + w->power_check = dapm_generic_check_power; dapm_new_mixer(codec, w); break; case snd_soc_dapm_mux: case snd_soc_dapm_value_mux: + w->power_check = dapm_generic_check_power; dapm_new_mux(codec, w); break; case snd_soc_dapm_adc: + w->power_check = dapm_adc_check_power; + break; case snd_soc_dapm_dac: + w->power_check = dapm_dac_check_power; + break; case snd_soc_dapm_pga: + w->power_check = dapm_generic_check_power; dapm_new_pga(codec, w); break; case snd_soc_dapm_input: @@ -1126,6 +1289,10 @@ int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec) case snd_soc_dapm_hp: case snd_soc_dapm_mic: case snd_soc_dapm_line: + w->power_check = dapm_generic_check_power; + break; + case snd_soc_dapm_supply: + w->power_check = dapm_supply_check_power; case snd_soc_dapm_vmid: case snd_soc_dapm_pre: case snd_soc_dapm_post: @@ -1625,36 +1792,12 @@ int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, } EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event); -/** - * snd_soc_dapm_set_bias_level - set the bias level for the system - * @socdev: audio device - * @level: level to configure - * - * Configure the bias (power) levels for the SoC audio device. - * - * Returns 0 for success else error. - */ -int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev, - enum snd_soc_bias_level level) -{ - struct snd_soc_card *card = socdev->card; - struct snd_soc_codec *codec = socdev->card->codec; - int ret = 0; - - if (card->set_bias_level) - ret = card->set_bias_level(card, level); - if (ret == 0 && codec->set_bias_level) - ret = codec->set_bias_level(codec, level); - - return ret; -} - /** * snd_soc_dapm_enable_pin - enable pin. * @codec: SoC codec * @pin: pin name * - * Enables input/output pin and it's parents or children widgets iff there is + * Enables input/output pin and its parents or children widgets iff there is * a valid audio route and active audio stream. * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to * do any widget power switching. @@ -1670,7 +1813,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin); * @codec: SoC codec * @pin: pin name * - * Disables input/output pin and it's parents or children widgets. + * Disables input/output pin and its parents or children widgets. * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to * do any widget power switching. */ diff --git a/sound/soc/txx9/Kconfig b/sound/soc/txx9/Kconfig new file mode 100644 index 000000000000..ebc9327eae71 --- /dev/null +++ b/sound/soc/txx9/Kconfig @@ -0,0 +1,29 @@ +## +## TXx9 ACLC +## +config SND_SOC_TXX9ACLC + tristate "SoC Audio for TXx9" + depends on HAS_TXX9_ACLC && TXX9_DMAC + help + This option enables support for the AC Link Controllers in TXx9 SoC. + +config HAS_TXX9_ACLC + bool + +config SND_SOC_TXX9ACLC_AC97 + tristate + select AC97_BUS + select SND_AC97_CODEC + select SND_SOC_AC97_BUS + + +## +## Boards +## +config SND_SOC_TXX9ACLC_GENERIC + tristate "Generic TXx9 ACLC sound machine" + depends on SND_SOC_TXX9ACLC + select SND_SOC_TXX9ACLC_AC97 + select SND_SOC_AC97_CODEC + help + This is a generic AC97 sound machine for use in TXx9 based systems. diff --git a/sound/soc/txx9/Makefile b/sound/soc/txx9/Makefile new file mode 100644 index 000000000000..551f16c0c4f9 --- /dev/null +++ b/sound/soc/txx9/Makefile @@ -0,0 +1,11 @@ +# Platform +snd-soc-txx9aclc-objs := txx9aclc.o +snd-soc-txx9aclc-ac97-objs := txx9aclc-ac97.o + +obj-$(CONFIG_SND_SOC_TXX9ACLC) += snd-soc-txx9aclc.o +obj-$(CONFIG_SND_SOC_TXX9ACLC_AC97) += snd-soc-txx9aclc-ac97.o + +# Machine +snd-soc-txx9aclc-generic-objs := txx9aclc-generic.o + +obj-$(CONFIG_SND_SOC_TXX9ACLC_GENERIC) += snd-soc-txx9aclc-generic.o diff --git a/sound/soc/txx9/txx9aclc-ac97.c b/sound/soc/txx9/txx9aclc-ac97.c new file mode 100644 index 000000000000..0f83bdb9b16f --- /dev/null +++ b/sound/soc/txx9/txx9aclc-ac97.c @@ -0,0 +1,255 @@ +/* + * TXx9 ACLC AC97 driver + * + * Copyright (C) 2009 Atsushi Nemoto + * + * Based on RBTX49xx patch from CELF patch archive. + * (C) Copyright TOSHIBA CORPORATION 2004-2006 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "txx9aclc.h" + +#define AC97_DIR \ + (SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE) + +#define AC97_RATES \ + SNDRV_PCM_RATE_8000_48000 + +#ifdef __BIG_ENDIAN +#define AC97_FMTS SNDRV_PCM_FMTBIT_S16_BE +#else +#define AC97_FMTS SNDRV_PCM_FMTBIT_S16_LE +#endif + +static DECLARE_WAIT_QUEUE_HEAD(ac97_waitq); + +/* REVISIT: How to find txx9aclc_soc_device from snd_ac97? */ +static struct txx9aclc_soc_device *txx9aclc_soc_dev; + +static int txx9aclc_regready(struct txx9aclc_soc_device *dev) +{ + struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev); + + return __raw_readl(drvdata->base + ACINTSTS) & ACINT_REGACCRDY; +} + +/* AC97 controller reads codec register */ +static unsigned short txx9aclc_ac97_read(struct snd_ac97 *ac97, + unsigned short reg) +{ + struct txx9aclc_soc_device *dev = txx9aclc_soc_dev; + struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev); + void __iomem *base = drvdata->base; + u32 dat; + + if (!(__raw_readl(base + ACINTSTS) & ACINT_CODECRDY(ac97->num))) + return 0xffff; + reg |= ac97->num << 7; + dat = (reg << ACREGACC_REG_SHIFT) | ACREGACC_READ; + __raw_writel(dat, base + ACREGACC); + __raw_writel(ACINT_REGACCRDY, base + ACINTEN); + if (!wait_event_timeout(ac97_waitq, txx9aclc_regready(dev), HZ)) { + __raw_writel(ACINT_REGACCRDY, base + ACINTDIS); + dev_err(dev->soc_dev.dev, "ac97 read timeout (reg %#x)\n", reg); + dat = 0xffff; + goto done; + } + dat = __raw_readl(base + ACREGACC); + if (((dat >> ACREGACC_REG_SHIFT) & 0xff) != reg) { + dev_err(dev->soc_dev.dev, "reg mismatch %x with %x\n", + dat, reg); + dat = 0xffff; + goto done; + } + dat = (dat >> ACREGACC_DAT_SHIFT) & 0xffff; +done: + __raw_writel(ACINT_REGACCRDY, base + ACINTDIS); + return dat; +} + +/* AC97 controller writes to codec register */ +static void txx9aclc_ac97_write(struct snd_ac97 *ac97, unsigned short reg, + unsigned short val) +{ + struct txx9aclc_soc_device *dev = txx9aclc_soc_dev; + struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev); + void __iomem *base = drvdata->base; + + __raw_writel(((reg | (ac97->num << 7)) << ACREGACC_REG_SHIFT) | + (val << ACREGACC_DAT_SHIFT), + base + ACREGACC); + __raw_writel(ACINT_REGACCRDY, base + ACINTEN); + if (!wait_event_timeout(ac97_waitq, txx9aclc_regready(dev), HZ)) { + dev_err(dev->soc_dev.dev, + "ac97 write timeout (reg %#x)\n", reg); + } + __raw_writel(ACINT_REGACCRDY, base + ACINTDIS); +} + +static void txx9aclc_ac97_cold_reset(struct snd_ac97 *ac97) +{ + struct txx9aclc_soc_device *dev = txx9aclc_soc_dev; + struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev); + void __iomem *base = drvdata->base; + u32 ready = ACINT_CODECRDY(ac97->num) | ACINT_REGACCRDY; + + __raw_writel(ACCTL_ENLINK, base + ACCTLDIS); + mmiowb(); + udelay(1); + __raw_writel(ACCTL_ENLINK, base + ACCTLEN); + /* wait for primary codec ready status */ + __raw_writel(ready, base + ACINTEN); + if (!wait_event_timeout(ac97_waitq, + (__raw_readl(base + ACINTSTS) & ready) == ready, + HZ)) { + dev_err(&ac97->dev, "primary codec is not ready " + "(status %#x)\n", + __raw_readl(base + ACINTSTS)); + } + __raw_writel(ACINT_REGACCRDY, base + ACINTSTS); + __raw_writel(ready, base + ACINTDIS); +} + +/* AC97 controller operations */ +struct snd_ac97_bus_ops soc_ac97_ops = { + .read = txx9aclc_ac97_read, + .write = txx9aclc_ac97_write, + .reset = txx9aclc_ac97_cold_reset, +}; +EXPORT_SYMBOL_GPL(soc_ac97_ops); + +static irqreturn_t txx9aclc_ac97_irq(int irq, void *dev_id) +{ + struct txx9aclc_plat_drvdata *drvdata = dev_id; + void __iomem *base = drvdata->base; + + __raw_writel(__raw_readl(base + ACINTMSTS), base + ACINTDIS); + wake_up(&ac97_waitq); + return IRQ_HANDLED; +} + +static int txx9aclc_ac97_probe(struct platform_device *pdev, + struct snd_soc_dai *dai) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct txx9aclc_soc_device *dev = + container_of(socdev, struct txx9aclc_soc_device, soc_dev); + + dev->aclc_pdev = to_platform_device(dai->dev); + txx9aclc_soc_dev = dev; + return 0; +} + +static void txx9aclc_ac97_remove(struct platform_device *pdev, + struct snd_soc_dai *dai) +{ + struct platform_device *aclc_pdev = to_platform_device(dai->dev); + struct txx9aclc_plat_drvdata *drvdata = platform_get_drvdata(aclc_pdev); + + /* disable AC-link */ + __raw_writel(ACCTL_ENLINK, drvdata->base + ACCTLDIS); + txx9aclc_soc_dev = NULL; +} + +struct snd_soc_dai txx9aclc_ac97_dai = { + .name = "txx9aclc_ac97", + .ac97_control = 1, + .probe = txx9aclc_ac97_probe, + .remove = txx9aclc_ac97_remove, + .playback = { + .rates = AC97_RATES, + .formats = AC97_FMTS, + .channels_min = 2, + .channels_max = 2, + }, + .capture = { + .rates = AC97_RATES, + .formats = AC97_FMTS, + .channels_min = 2, + .channels_max = 2, + }, +}; +EXPORT_SYMBOL_GPL(txx9aclc_ac97_dai); + +static int __devinit txx9aclc_ac97_dev_probe(struct platform_device *pdev) +{ + struct txx9aclc_plat_drvdata *drvdata; + struct resource *r; + int err; + int irq; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!r) + return -EBUSY; + + if (!devm_request_mem_region(&pdev->dev, r->start, resource_size(r), + dev_name(&pdev->dev))) + return -EBUSY; + + drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL); + if (!drvdata) + return -ENOMEM; + platform_set_drvdata(pdev, drvdata); + drvdata->physbase = r->start; + if (sizeof(drvdata->physbase) > sizeof(r->start) && + r->start >= TXX9_DIRECTMAP_BASE && + r->start < TXX9_DIRECTMAP_BASE + 0x400000) + drvdata->physbase |= 0xf00000000ull; + drvdata->base = devm_ioremap(&pdev->dev, r->start, resource_size(r)); + if (!drvdata->base) + return -EBUSY; + err = devm_request_irq(&pdev->dev, irq, txx9aclc_ac97_irq, + IRQF_DISABLED, dev_name(&pdev->dev), drvdata); + if (err < 0) + return err; + + txx9aclc_ac97_dai.dev = &pdev->dev; + return snd_soc_register_dai(&txx9aclc_ac97_dai); +} + +static int __devexit txx9aclc_ac97_dev_remove(struct platform_device *pdev) +{ + snd_soc_unregister_dai(&txx9aclc_ac97_dai); + return 0; +} + +static struct platform_driver txx9aclc_ac97_driver = { + .probe = txx9aclc_ac97_dev_probe, + .remove = __devexit_p(txx9aclc_ac97_dev_remove), + .driver = { + .name = "txx9aclc-ac97", + .owner = THIS_MODULE, + }, +}; + +static int __init txx9aclc_ac97_init(void) +{ + return platform_driver_register(&txx9aclc_ac97_driver); +} + +static void __exit txx9aclc_ac97_exit(void) +{ + platform_driver_unregister(&txx9aclc_ac97_driver); +} + +module_init(txx9aclc_ac97_init); +module_exit(txx9aclc_ac97_exit); + +MODULE_AUTHOR("Atsushi Nemoto "); +MODULE_DESCRIPTION("TXx9 ACLC AC97 driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/txx9/txx9aclc-generic.c b/sound/soc/txx9/txx9aclc-generic.c new file mode 100644 index 000000000000..3175de9a92cb --- /dev/null +++ b/sound/soc/txx9/txx9aclc-generic.c @@ -0,0 +1,98 @@ +/* + * Generic TXx9 ACLC machine driver + * + * Copyright (C) 2009 Atsushi Nemoto + * + * Based on RBTX49xx patch from CELF patch archive. + * (C) Copyright TOSHIBA CORPORATION 2004-2006 + * + * 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 is a very generic AC97 sound machine driver for boards which + * have (AC97) audio at ACLC (e.g. RBTX49XX boards). + */ + +#include +#include +#include +#include +#include +#include "../codecs/ac97.h" +#include "txx9aclc.h" + +static struct snd_soc_dai_link txx9aclc_generic_dai = { + .name = "AC97", + .stream_name = "AC97 HiFi", + .cpu_dai = &txx9aclc_ac97_dai, + .codec_dai = &ac97_dai, +}; + +static struct snd_soc_card txx9aclc_generic_card = { + .name = "Generic TXx9 ACLC Audio", + .platform = &txx9aclc_soc_platform, + .dai_link = &txx9aclc_generic_dai, + .num_links = 1, +}; + +static struct txx9aclc_soc_device txx9aclc_generic_soc_device = { + .soc_dev = { + .card = &txx9aclc_generic_card, + .codec_dev = &soc_codec_dev_ac97, + }, +}; + +static int __init txx9aclc_generic_probe(struct platform_device *pdev) +{ + struct txx9aclc_soc_device *dev = &txx9aclc_generic_soc_device; + struct platform_device *soc_pdev; + int ret; + + soc_pdev = platform_device_alloc("soc-audio", -1); + if (!soc_pdev) + return -ENOMEM; + platform_set_drvdata(soc_pdev, &dev->soc_dev); + dev->soc_dev.dev = &soc_pdev->dev; + ret = platform_device_add(soc_pdev); + if (ret) { + platform_device_put(soc_pdev); + return ret; + } + platform_set_drvdata(pdev, soc_pdev); + return 0; +} + +static int __exit txx9aclc_generic_remove(struct platform_device *pdev) +{ + struct platform_device *soc_pdev = platform_get_drvdata(pdev); + + platform_device_unregister(soc_pdev); + return 0; +} + +static struct platform_driver txx9aclc_generic_driver = { + .remove = txx9aclc_generic_remove, + .driver = { + .name = "txx9aclc-generic", + .owner = THIS_MODULE, + }, +}; + +static int __init txx9aclc_generic_init(void) +{ + return platform_driver_probe(&txx9aclc_generic_driver, + txx9aclc_generic_probe); +} + +static void __exit txx9aclc_generic_exit(void) +{ + platform_driver_unregister(&txx9aclc_generic_driver); +} + +module_init(txx9aclc_generic_init); +module_exit(txx9aclc_generic_exit); + +MODULE_AUTHOR("Atsushi Nemoto "); +MODULE_DESCRIPTION("Generic TXx9 ACLC ALSA SoC audio driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/txx9/txx9aclc.c b/sound/soc/txx9/txx9aclc.c new file mode 100644 index 000000000000..938a58a5a244 --- /dev/null +++ b/sound/soc/txx9/txx9aclc.c @@ -0,0 +1,430 @@ +/* + * Generic TXx9 ACLC platform driver + * + * Copyright (C) 2009 Atsushi Nemoto + * + * Based on RBTX49xx patch from CELF patch archive. + * (C) Copyright TOSHIBA CORPORATION 2004-2006 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "txx9aclc.h" + +static const struct snd_pcm_hardware txx9aclc_pcm_hardware = { + /* + * REVISIT: SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID + * needs more works for noncoherent MIPS. + */ + .info = SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BATCH | + SNDRV_PCM_INFO_PAUSE, +#ifdef __BIG_ENDIAN + .formats = SNDRV_PCM_FMTBIT_S16_BE, +#else + .formats = SNDRV_PCM_FMTBIT_S16_LE, +#endif + .period_bytes_min = 1024, + .period_bytes_max = 8 * 1024, + .periods_min = 2, + .periods_max = 4096, + .buffer_bytes_max = 32 * 1024, +}; + +static int txx9aclc_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); + struct snd_soc_device *socdev = rtd->socdev; + struct snd_pcm_runtime *runtime = substream->runtime; + struct txx9aclc_dmadata *dmadata = runtime->private_data; + int ret; + + ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); + if (ret < 0) + return ret; + + dev_dbg(socdev->dev, + "runtime->dma_area = %#lx dma_addr = %#lx dma_bytes = %zd " + "runtime->min_align %ld\n", + (unsigned long)runtime->dma_area, + (unsigned long)runtime->dma_addr, runtime->dma_bytes, + runtime->min_align); + dev_dbg(socdev->dev, + "periods %d period_bytes %d stream %d\n", + params_periods(params), params_period_bytes(params), + substream->stream); + + dmadata->substream = substream; + dmadata->pos = 0; + return 0; +} + +static int txx9aclc_pcm_hw_free(struct snd_pcm_substream *substream) +{ + return snd_pcm_lib_free_pages(substream); +} + +static int txx9aclc_pcm_prepare(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct txx9aclc_dmadata *dmadata = runtime->private_data; + + dmadata->dma_addr = runtime->dma_addr; + dmadata->buffer_bytes = snd_pcm_lib_buffer_bytes(substream); + dmadata->period_bytes = snd_pcm_lib_period_bytes(substream); + + if (dmadata->buffer_bytes == dmadata->period_bytes) { + dmadata->frag_bytes = dmadata->period_bytes >> 1; + dmadata->frags = 2; + } else { + dmadata->frag_bytes = dmadata->period_bytes; + dmadata->frags = dmadata->buffer_bytes / dmadata->period_bytes; + } + dmadata->frag_count = 0; + dmadata->pos = 0; + return 0; +} + +static void txx9aclc_dma_complete(void *arg) +{ + struct txx9aclc_dmadata *dmadata = arg; + unsigned long flags; + + /* dma completion handler cannot submit new operations */ + spin_lock_irqsave(&dmadata->dma_lock, flags); + if (dmadata->frag_count >= 0) { + dmadata->dmacount--; + BUG_ON(dmadata->dmacount < 0); + tasklet_schedule(&dmadata->tasklet); + } + spin_unlock_irqrestore(&dmadata->dma_lock, flags); +} + +static struct dma_async_tx_descriptor * +txx9aclc_dma_submit(struct txx9aclc_dmadata *dmadata, dma_addr_t buf_dma_addr) +{ + struct dma_chan *chan = dmadata->dma_chan; + struct dma_async_tx_descriptor *desc; + struct scatterlist sg; + + sg_init_table(&sg, 1); + sg_set_page(&sg, pfn_to_page(PFN_DOWN(buf_dma_addr)), + dmadata->frag_bytes, buf_dma_addr & (PAGE_SIZE - 1)); + sg_dma_address(&sg) = buf_dma_addr; + desc = chan->device->device_prep_slave_sg(chan, &sg, 1, + dmadata->substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? + DMA_TO_DEVICE : DMA_FROM_DEVICE, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) { + dev_err(&chan->dev->device, "cannot prepare slave dma\n"); + return NULL; + } + desc->callback = txx9aclc_dma_complete; + desc->callback_param = dmadata; + desc->tx_submit(desc); + return desc; +} + +#define NR_DMA_CHAIN 2 + +static void txx9aclc_dma_tasklet(unsigned long data) +{ + struct txx9aclc_dmadata *dmadata = (struct txx9aclc_dmadata *)data; + struct dma_chan *chan = dmadata->dma_chan; + struct dma_async_tx_descriptor *desc; + struct snd_pcm_substream *substream = dmadata->substream; + u32 ctlbit = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? + ACCTL_AUDODMA : ACCTL_AUDIDMA; + int i; + unsigned long flags; + + spin_lock_irqsave(&dmadata->dma_lock, flags); + if (dmadata->frag_count < 0) { + struct txx9aclc_soc_device *dev = + container_of(dmadata, struct txx9aclc_soc_device, + dmadata[substream->stream]); + struct txx9aclc_plat_drvdata *drvdata = + txx9aclc_get_plat_drvdata(dev); + void __iomem *base = drvdata->base; + + spin_unlock_irqrestore(&dmadata->dma_lock, flags); + chan->device->device_terminate_all(chan); + /* first time */ + for (i = 0; i < NR_DMA_CHAIN; i++) { + desc = txx9aclc_dma_submit(dmadata, + dmadata->dma_addr + i * dmadata->frag_bytes); + if (!desc) + return; + } + dmadata->dmacount = NR_DMA_CHAIN; + chan->device->device_issue_pending(chan); + spin_lock_irqsave(&dmadata->dma_lock, flags); + __raw_writel(ctlbit, base + ACCTLEN); + dmadata->frag_count = NR_DMA_CHAIN % dmadata->frags; + spin_unlock_irqrestore(&dmadata->dma_lock, flags); + return; + } + BUG_ON(dmadata->dmacount >= NR_DMA_CHAIN); + while (dmadata->dmacount < NR_DMA_CHAIN) { + dmadata->dmacount++; + spin_unlock_irqrestore(&dmadata->dma_lock, flags); + desc = txx9aclc_dma_submit(dmadata, + dmadata->dma_addr + + dmadata->frag_count * dmadata->frag_bytes); + if (!desc) + return; + chan->device->device_issue_pending(chan); + + spin_lock_irqsave(&dmadata->dma_lock, flags); + dmadata->frag_count++; + dmadata->frag_count %= dmadata->frags; + dmadata->pos += dmadata->frag_bytes; + dmadata->pos %= dmadata->buffer_bytes; + if ((dmadata->frag_count * dmadata->frag_bytes) % + dmadata->period_bytes == 0) + snd_pcm_period_elapsed(substream); + } + spin_unlock_irqrestore(&dmadata->dma_lock, flags); +} + +static int txx9aclc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct txx9aclc_dmadata *dmadata = substream->runtime->private_data; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct txx9aclc_soc_device *dev = + container_of(rtd->socdev, struct txx9aclc_soc_device, soc_dev); + struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev); + void __iomem *base = drvdata->base; + unsigned long flags; + int ret = 0; + u32 ctlbit = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? + ACCTL_AUDODMA : ACCTL_AUDIDMA; + + spin_lock_irqsave(&dmadata->dma_lock, flags); + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + dmadata->frag_count = -1; + tasklet_schedule(&dmadata->tasklet); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + case SNDRV_PCM_TRIGGER_SUSPEND: + __raw_writel(ctlbit, base + ACCTLDIS); + break; + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + case SNDRV_PCM_TRIGGER_RESUME: + __raw_writel(ctlbit, base + ACCTLEN); + break; + default: + ret = -EINVAL; + } + spin_unlock_irqrestore(&dmadata->dma_lock, flags); + return ret; +} + +static snd_pcm_uframes_t +txx9aclc_pcm_pointer(struct snd_pcm_substream *substream) +{ + struct txx9aclc_dmadata *dmadata = substream->runtime->private_data; + + return bytes_to_frames(substream->runtime, dmadata->pos); +} + +static int txx9aclc_pcm_open(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct txx9aclc_soc_device *dev = + container_of(rtd->socdev, struct txx9aclc_soc_device, soc_dev); + struct txx9aclc_dmadata *dmadata = &dev->dmadata[substream->stream]; + int ret; + + ret = snd_soc_set_runtime_hwparams(substream, &txx9aclc_pcm_hardware); + if (ret) + return ret; + /* ensure that buffer size is a multiple of period size */ + ret = snd_pcm_hw_constraint_integer(substream->runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + if (ret < 0) + return ret; + substream->runtime->private_data = dmadata; + return 0; +} + +static int txx9aclc_pcm_close(struct snd_pcm_substream *substream) +{ + struct txx9aclc_dmadata *dmadata = substream->runtime->private_data; + struct dma_chan *chan = dmadata->dma_chan; + + dmadata->frag_count = -1; + chan->device->device_terminate_all(chan); + return 0; +} + +static struct snd_pcm_ops txx9aclc_pcm_ops = { + .open = txx9aclc_pcm_open, + .close = txx9aclc_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = txx9aclc_pcm_hw_params, + .hw_free = txx9aclc_pcm_hw_free, + .prepare = txx9aclc_pcm_prepare, + .trigger = txx9aclc_pcm_trigger, + .pointer = txx9aclc_pcm_pointer, +}; + +static void txx9aclc_pcm_free_dma_buffers(struct snd_pcm *pcm) +{ + snd_pcm_lib_preallocate_free_for_all(pcm); +} + +static int txx9aclc_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, + struct snd_pcm *pcm) +{ + return snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + card->dev, 64 * 1024, 4 * 1024 * 1024); +} + +static bool filter(struct dma_chan *chan, void *param) +{ + struct txx9aclc_dmadata *dmadata = param; + char devname[20 + 2]; /* FIXME: old BUS_ID_SIZE + 2 */ + + snprintf(devname, sizeof(devname), "%s.%d", dmadata->dma_res->name, + (int)dmadata->dma_res->start); + if (strcmp(dev_name(chan->device->dev), devname) == 0) { + chan->private = &dmadata->dma_slave; + return true; + } + return false; +} + +static int txx9aclc_dma_init(struct txx9aclc_soc_device *dev, + struct txx9aclc_dmadata *dmadata) +{ + struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev); + struct txx9dmac_slave *ds = &dmadata->dma_slave; + dma_cap_mask_t mask; + + spin_lock_init(&dmadata->dma_lock); + + ds->reg_width = sizeof(u32); + if (dmadata->stream == SNDRV_PCM_STREAM_PLAYBACK) { + ds->tx_reg = drvdata->physbase + ACAUDODAT; + ds->rx_reg = 0; + } else { + ds->tx_reg = 0; + ds->rx_reg = drvdata->physbase + ACAUDIDAT; + } + + /* Try to grab a DMA channel */ + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + dmadata->dma_chan = dma_request_channel(mask, filter, dmadata); + if (!dmadata->dma_chan) { + dev_err(dev->soc_dev.dev, + "DMA channel for %s is not available\n", + dmadata->stream == SNDRV_PCM_STREAM_PLAYBACK ? + "playback" : "capture"); + return -EBUSY; + } + tasklet_init(&dmadata->tasklet, txx9aclc_dma_tasklet, + (unsigned long)dmadata); + return 0; +} + +static int txx9aclc_pcm_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct txx9aclc_soc_device *dev = + container_of(socdev, struct txx9aclc_soc_device, soc_dev); + struct resource *r; + int i; + int ret; + + dev->dmadata[0].stream = SNDRV_PCM_STREAM_PLAYBACK; + dev->dmadata[1].stream = SNDRV_PCM_STREAM_CAPTURE; + for (i = 0; i < 2; i++) { + r = platform_get_resource(dev->aclc_pdev, IORESOURCE_DMA, i); + if (!r) { + ret = -EBUSY; + goto exit; + } + dev->dmadata[i].dma_res = r; + ret = txx9aclc_dma_init(dev, &dev->dmadata[i]); + if (ret) + goto exit; + } + return 0; + +exit: + for (i = 0; i < 2; i++) { + if (dev->dmadata[i].dma_chan) + dma_release_channel(dev->dmadata[i].dma_chan); + dev->dmadata[i].dma_chan = NULL; + } + return ret; +} + +static int txx9aclc_pcm_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct txx9aclc_soc_device *dev = + container_of(socdev, struct txx9aclc_soc_device, soc_dev); + struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev); + void __iomem *base = drvdata->base; + int i; + + /* disable all FIFO DMAs */ + __raw_writel(ACCTL_AUDODMA | ACCTL_AUDIDMA, base + ACCTLDIS); + /* dummy R/W to clear pending DMAREQ if any */ + __raw_writel(__raw_readl(base + ACAUDIDAT), base + ACAUDODAT); + + for (i = 0; i < 2; i++) { + struct txx9aclc_dmadata *dmadata = &dev->dmadata[i]; + struct dma_chan *chan = dmadata->dma_chan; + if (chan) { + dmadata->frag_count = -1; + chan->device->device_terminate_all(chan); + dma_release_channel(chan); + } + dev->dmadata[i].dma_chan = NULL; + } + return 0; +} + +struct snd_soc_platform txx9aclc_soc_platform = { + .name = "txx9aclc-audio", + .probe = txx9aclc_pcm_probe, + .remove = txx9aclc_pcm_remove, + .pcm_ops = &txx9aclc_pcm_ops, + .pcm_new = txx9aclc_pcm_new, + .pcm_free = txx9aclc_pcm_free_dma_buffers, +}; +EXPORT_SYMBOL_GPL(txx9aclc_soc_platform); + +static int __init txx9aclc_soc_platform_init(void) +{ + return snd_soc_register_platform(&txx9aclc_soc_platform); +} + +static void __exit txx9aclc_soc_platform_exit(void) +{ + snd_soc_unregister_platform(&txx9aclc_soc_platform); +} + +module_init(txx9aclc_soc_platform_init); +module_exit(txx9aclc_soc_platform_exit); + +MODULE_AUTHOR("Atsushi Nemoto "); +MODULE_DESCRIPTION("TXx9 ACLC Audio DMA driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/txx9/txx9aclc.h b/sound/soc/txx9/txx9aclc.h new file mode 100644 index 000000000000..6769aab41b33 --- /dev/null +++ b/sound/soc/txx9/txx9aclc.h @@ -0,0 +1,83 @@ +/* + * TXx9 SoC AC Link Controller + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __TXX9ACLC_H +#define __TXX9ACLC_H + +#include +#include + +#define ACCTLEN 0x00 /* control enable */ +#define ACCTLDIS 0x04 /* control disable */ +#define ACCTL_ENLINK 0x00000001 /* enable/disable AC-link */ +#define ACCTL_AUDODMA 0x00000100 /* AUDODMA enable/disable */ +#define ACCTL_AUDIDMA 0x00001000 /* AUDIDMA enable/disable */ +#define ACCTL_AUDOEHLT 0x00010000 /* AUDO error halt + enable/disable */ +#define ACCTL_AUDIEHLT 0x00100000 /* AUDI error halt + enable/disable */ +#define ACREGACC 0x08 /* codec register access */ +#define ACREGACC_DAT_SHIFT 0 /* data field */ +#define ACREGACC_REG_SHIFT 16 /* address field */ +#define ACREGACC_CODECID_SHIFT 24 /* CODEC ID field */ +#define ACREGACC_READ 0x80000000 /* CODEC read */ +#define ACREGACC_WRITE 0x00000000 /* CODEC write */ +#define ACINTSTS 0x10 /* interrupt status */ +#define ACINTMSTS 0x14 /* interrupt masked status */ +#define ACINTEN 0x18 /* interrupt enable */ +#define ACINTDIS 0x1c /* interrupt disable */ +#define ACINT_CODECRDY(n) (0x00000001 << (n)) /* CODECn ready */ +#define ACINT_REGACCRDY 0x00000010 /* ACREGACC ready */ +#define ACINT_AUDOERR 0x00000100 /* AUDO underrun error */ +#define ACINT_AUDIERR 0x00001000 /* AUDI overrun error */ +#define ACDMASTS 0x80 /* DMA request status */ +#define ACDMA_AUDO 0x00000001 /* AUDODMA pending */ +#define ACDMA_AUDI 0x00000010 /* AUDIDMA pending */ +#define ACAUDODAT 0xa0 /* audio out data */ +#define ACAUDIDAT 0xb0 /* audio in data */ +#define ACREVID 0xfc /* revision ID */ + +struct txx9aclc_dmadata { + struct resource *dma_res; + struct txx9dmac_slave dma_slave; + struct dma_chan *dma_chan; + struct tasklet_struct tasklet; + spinlock_t dma_lock; + int stream; /* SNDRV_PCM_STREAM_PLAYBACK or SNDRV_PCM_STREAM_CAPTURE */ + struct snd_pcm_substream *substream; + unsigned long pos; + dma_addr_t dma_addr; + unsigned long buffer_bytes; + unsigned long period_bytes; + unsigned long frag_bytes; + int frags; + int frag_count; + int dmacount; +}; + +struct txx9aclc_plat_drvdata { + void __iomem *base; + u64 physbase; +}; + +struct txx9aclc_soc_device { + struct snd_soc_device soc_dev; + struct platform_device *aclc_pdev; /* for ioresources, drvdata */ + struct txx9aclc_dmadata dmadata[2]; +}; + +static inline struct txx9aclc_plat_drvdata *txx9aclc_get_plat_drvdata( + struct txx9aclc_soc_device *sdev) +{ + return platform_get_drvdata(sdev->aclc_pdev); +} + +extern struct snd_soc_platform txx9aclc_soc_platform; +extern struct snd_soc_dai txx9aclc_ac97_dai; + +#endif /* __TXX9ACLC_H */ diff --git a/sound/sound_core.c b/sound/sound_core.c index 2b302bbffe73..12522e6913d9 100644 --- a/sound/sound_core.c +++ b/sound/sound_core.c @@ -27,6 +27,11 @@ MODULE_DESCRIPTION("Core sound module"); MODULE_AUTHOR("Alan Cox"); MODULE_LICENSE("GPL"); +static char *sound_nodename(struct device *dev) +{ + return kasprintf(GFP_KERNEL, "snd/%s", dev_name(dev)); +} + static int __init init_soundcore(void) { int rc; @@ -41,6 +46,8 @@ static int __init init_soundcore(void) return PTR_ERR(sound_class); } + sound_class->nodename = sound_nodename; + return 0; } diff --git a/sound/synth/Makefile b/sound/synth/Makefile index e99fd76caa17..11eb06ac2eca 100644 --- a/sound/synth/Makefile +++ b/sound/synth/Makefile @@ -5,16 +5,8 @@ snd-util-mem-objs := util_mem.o -# -# this function returns: -# "m" - CONFIG_SND_SEQUENCER is m -# - CONFIG_SND_SEQUENCER is undefined -# otherwise parameter #1 value -# -sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1))) - # Toplevel Module Dependency obj-$(CONFIG_SND_EMU10K1) += snd-util-mem.o obj-$(CONFIG_SND_TRIDENT) += snd-util-mem.o -obj-$(call sequencer,$(CONFIG_SND_SBAWE)) += snd-util-mem.o -obj-$(call sequencer,$(CONFIG_SND)) += emux/ +obj-$(CONFIG_SND_SBAWE_SEQ) += snd-util-mem.o +obj-$(CONFIG_SND_SEQUENCER) += emux/ diff --git a/sound/synth/emux/Makefile b/sound/synth/emux/Makefile index b69035240cf6..328594e6152d 100644 --- a/sound/synth/emux/Makefile +++ b/sound/synth/emux/Makefile @@ -7,14 +7,6 @@ snd-emux-synth-objs := emux.o emux_synth.o emux_seq.o emux_nrpn.o \ emux_effect.o emux_proc.o emux_hwdep.o soundfont.o \ $(if $(CONFIG_SND_SEQUENCER_OSS),emux_oss.o) -# -# this function returns: -# "m" - CONFIG_SND_SEQUENCER is m -# - CONFIG_SND_SEQUENCER is undefined -# otherwise parameter #1 value -# -sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1))) - # Toplevel Module Dependencies -obj-$(call sequencer,$(CONFIG_SND_SBAWE)) += snd-emux-synth.o -obj-$(call sequencer,$(CONFIG_SND_EMU10K1)) += snd-emux-synth.o +obj-$(CONFIG_SND_SBAWE_SEQ) += snd-emux-synth.o +obj-$(CONFIG_SND_EMU10K1_SEQ) += snd-emux-synth.o diff --git a/sound/usb/caiaq/audio.c b/sound/usb/caiaq/audio.c index b13ce767ac72..8f9b60c5d74c 100644 --- a/sound/usb/caiaq/audio.c +++ b/sound/usb/caiaq/audio.c @@ -42,10 +42,10 @@ (stream << 1) | (~(i / (dev->n_streams * BYTES_PER_SAMPLE_USB)) & 1) static struct snd_pcm_hardware snd_usb_caiaq_pcm_hardware = { - .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | + .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER), .formats = SNDRV_PCM_FMTBIT_S24_3BE, - .rates = (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | + .rates = (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000), .rate_min = 44100, .rate_max = 0, /* will overwrite later */ @@ -68,7 +68,7 @@ activate_substream(struct snd_usb_caiaqdev *dev, dev->sub_capture[sub->number] = sub; } -static void +static void deactivate_substream(struct snd_usb_caiaqdev *dev, struct snd_pcm_substream *sub) { @@ -118,7 +118,7 @@ static int stream_start(struct snd_usb_caiaqdev *dev) return -EPIPE; } } - + return 0; } @@ -129,7 +129,7 @@ static void stream_stop(struct snd_usb_caiaqdev *dev) debug("%s(%p)\n", __func__, dev); if (!dev->streaming) return; - + dev->streaming = 0; for (i = 0; i < N_URBS; i++) { @@ -154,7 +154,7 @@ static int snd_usb_caiaq_substream_close(struct snd_pcm_substream *substream) debug("%s(%p)\n", __func__, substream); if (all_substreams_zero(dev->sub_playback) && all_substreams_zero(dev->sub_capture)) { - /* when the last client has stopped streaming, + /* when the last client has stopped streaming, * all sample rates are allowed again */ stream_stop(dev); dev->pcm_info.rates = dev->samplerates; @@ -194,30 +194,31 @@ static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; debug("%s(%p)\n", __func__, substream); - + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { dev->period_out_count[index] = BYTES_PER_SAMPLE + 1; dev->audio_out_buf_pos[index] = BYTES_PER_SAMPLE + 1; } else { - dev->period_in_count[index] = BYTES_PER_SAMPLE; - dev->audio_in_buf_pos[index] = BYTES_PER_SAMPLE; + int in_pos = (dev->spec.data_alignment == 2) ? 0 : 2; + dev->period_in_count[index] = BYTES_PER_SAMPLE + in_pos; + dev->audio_in_buf_pos[index] = BYTES_PER_SAMPLE + in_pos; } if (dev->streaming) return 0; - + /* the first client that opens a stream defines the sample rate * setting for all subsequent calls, until the last client closed. */ for (i=0; i < ARRAY_SIZE(rates); i++) if (runtime->rate == rates[i]) dev->pcm_info.rates = 1 << i; - + snd_pcm_limit_hw_rates(runtime); bytes_per_sample = BYTES_PER_SAMPLE; if (dev->spec.data_alignment == 2) bytes_per_sample++; - + bpp = ((runtime->rate / 8000) + CLOCK_DRIFT_TOLERANCE) * bytes_per_sample * CHANNELS_PER_STREAM * dev->n_streams; @@ -232,7 +233,7 @@ static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream) ret = stream_start(dev); if (ret) return ret; - + dev->output_running = 0; wait_event_timeout(dev->prepare_wait_queue, dev->output_running, HZ); if (!dev->output_running) { @@ -273,7 +274,7 @@ snd_usb_caiaq_pcm_pointer(struct snd_pcm_substream *sub) return SNDRV_PCM_POS_XRUN; if (sub->stream == SNDRV_PCM_STREAM_PLAYBACK) - return bytes_to_frames(sub->runtime, + return bytes_to_frames(sub->runtime, dev->audio_out_buf_pos[index]); else return bytes_to_frames(sub->runtime, @@ -291,7 +292,7 @@ static struct snd_pcm_ops snd_usb_caiaq_ops = { .trigger = snd_usb_caiaq_pcm_trigger, .pointer = snd_usb_caiaq_pcm_pointer }; - + static void check_for_elapsed_periods(struct snd_usb_caiaqdev *dev, struct snd_pcm_substream **subs) { @@ -333,7 +334,7 @@ static void read_in_urb_mode0(struct snd_usb_caiaqdev *dev, struct snd_pcm_runtime *rt = sub->runtime; char *audio_buf = rt->dma_area; int sz = frames_to_bytes(rt, rt->buffer_size); - audio_buf[dev->audio_in_buf_pos[stream]++] + audio_buf[dev->audio_in_buf_pos[stream]++] = usb_buf[i]; dev->period_in_count[stream]++; if (dev->audio_in_buf_pos[stream] == sz) @@ -354,14 +355,14 @@ static void read_in_urb_mode2(struct snd_usb_caiaqdev *dev, for (i = 0; i < iso->actual_length;) { if (i % (dev->n_streams * BYTES_PER_SAMPLE_USB) == 0) { - for (stream = 0; - stream < dev->n_streams; + for (stream = 0; + stream < dev->n_streams; stream++, i++) { if (dev->first_packet) continue; check_byte = MAKE_CHECKBYTE(dev, stream, i); - + if ((usb_buf[i] & 0x3f) != check_byte) dev->input_panic = 1; @@ -410,21 +411,21 @@ static void read_in_urb(struct snd_usb_caiaqdev *dev, } if ((dev->input_panic || dev->output_panic) && !dev->warned) { - debug("streaming error detected %s %s\n", + debug("streaming error detected %s %s\n", dev->input_panic ? "(input)" : "", dev->output_panic ? "(output)" : ""); dev->warned = 1; } } -static void fill_out_urb(struct snd_usb_caiaqdev *dev, - struct urb *urb, +static void fill_out_urb(struct snd_usb_caiaqdev *dev, + struct urb *urb, const struct usb_iso_packet_descriptor *iso) { unsigned char *usb_buf = urb->transfer_buffer + iso->offset; struct snd_pcm_substream *sub; int stream, i; - + for (i = 0; i < iso->length;) { for (stream = 0; stream < dev->n_streams; stream++, i++) { sub = dev->sub_playback[stream]; @@ -444,7 +445,7 @@ static void fill_out_urb(struct snd_usb_caiaqdev *dev, /* fill in the check bytes */ if (dev->spec.data_alignment == 2 && - i % (dev->n_streams * BYTES_PER_SAMPLE_USB) == + i % (dev->n_streams * BYTES_PER_SAMPLE_USB) == (dev->n_streams * CHANNELS_PER_STREAM)) for (stream = 0; stream < dev->n_streams; stream++, i++) usb_buf[i] = MAKE_CHECKBYTE(dev, stream, i); @@ -453,7 +454,7 @@ static void fill_out_urb(struct snd_usb_caiaqdev *dev, static void read_completed(struct urb *urb) { - struct snd_usb_caiaq_cb_info *info = urb->context; + struct snd_usb_caiaq_cb_info *info = urb->context; struct snd_usb_caiaqdev *dev; struct urb *out; int frame, len, send_it = 0, outframe = 0; @@ -478,7 +479,7 @@ static void read_completed(struct urb *urb) out->iso_frame_desc[outframe].length = len; out->iso_frame_desc[outframe].actual_length = 0; out->iso_frame_desc[outframe].offset = BYTES_PER_FRAME * frame; - + if (len > 0) { spin_lock(&dev->spinlock); fill_out_urb(dev, out, &out->iso_frame_desc[outframe]); @@ -497,14 +498,14 @@ static void read_completed(struct urb *urb) out->transfer_flags = URB_ISO_ASAP; usb_submit_urb(out, GFP_ATOMIC); } - + /* re-submit inbound urb */ for (frame = 0; frame < FRAMES_PER_URB; frame++) { urb->iso_frame_desc[frame].offset = BYTES_PER_FRAME * frame; urb->iso_frame_desc[frame].length = BYTES_PER_FRAME; urb->iso_frame_desc[frame].actual_length = 0; } - + urb->number_of_packets = FRAMES_PER_URB; urb->transfer_flags = URB_ISO_ASAP; usb_submit_urb(urb, GFP_ATOMIC); @@ -528,7 +529,7 @@ static struct urb **alloc_urbs(struct snd_usb_caiaqdev *dev, int dir, int *ret) struct usb_device *usb_dev = dev->chip.dev; unsigned int pipe; - pipe = (dir == SNDRV_PCM_STREAM_PLAYBACK) ? + pipe = (dir == SNDRV_PCM_STREAM_PLAYBACK) ? usb_sndisocpipe(usb_dev, ENDPOINT_PLAYBACK) : usb_rcvisocpipe(usb_dev, ENDPOINT_CAPTURE); @@ -547,25 +548,25 @@ static struct urb **alloc_urbs(struct snd_usb_caiaqdev *dev, int dir, int *ret) return urbs; } - urbs[i]->transfer_buffer = + urbs[i]->transfer_buffer = kmalloc(FRAMES_PER_URB * BYTES_PER_FRAME, GFP_KERNEL); if (!urbs[i]->transfer_buffer) { log("unable to kmalloc() transfer buffer, OOM!?\n"); *ret = -ENOMEM; return urbs; } - + for (frame = 0; frame < FRAMES_PER_URB; frame++) { - struct usb_iso_packet_descriptor *iso = + struct usb_iso_packet_descriptor *iso = &urbs[i]->iso_frame_desc[frame]; - + iso->offset = BYTES_PER_FRAME * frame; iso->length = BYTES_PER_FRAME; } - + urbs[i]->dev = usb_dev; urbs[i]->pipe = pipe; - urbs[i]->transfer_buffer_length = FRAMES_PER_URB + urbs[i]->transfer_buffer_length = FRAMES_PER_URB * BYTES_PER_FRAME; urbs[i]->context = &dev->data_cb_info[i]; urbs[i]->interval = 1; @@ -589,7 +590,7 @@ static void free_urbs(struct urb **urbs) for (i = 0; i < N_URBS; i++) { if (!urbs[i]) continue; - + usb_kill_urb(urbs[i]); kfree(urbs[i]->transfer_buffer); usb_free_urb(urbs[i]); @@ -602,11 +603,11 @@ int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev) { int i, ret; - dev->n_audio_in = max(dev->spec.num_analog_audio_in, - dev->spec.num_digital_audio_in) / + dev->n_audio_in = max(dev->spec.num_analog_audio_in, + dev->spec.num_digital_audio_in) / CHANNELS_PER_STREAM; dev->n_audio_out = max(dev->spec.num_analog_audio_out, - dev->spec.num_digital_audio_out) / + dev->spec.num_digital_audio_out) / CHANNELS_PER_STREAM; dev->n_streams = max(dev->n_audio_in, dev->n_audio_out); @@ -619,7 +620,7 @@ int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev) return -EINVAL; } - ret = snd_pcm_new(dev->chip.card, dev->product_name, 0, + ret = snd_pcm_new(dev->chip.card, dev->product_name, 0, dev->n_audio_out, dev->n_audio_in, &dev->pcm); if (ret < 0) { @@ -632,7 +633,7 @@ int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev) memset(dev->sub_playback, 0, sizeof(dev->sub_playback)); memset(dev->sub_capture, 0, sizeof(dev->sub_capture)); - + memcpy(&dev->pcm_info, &snd_usb_caiaq_pcm_hardware, sizeof(snd_usb_caiaq_pcm_hardware)); @@ -651,9 +652,9 @@ int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev) break; } - snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK, + snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_usb_caiaq_ops); - snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_CAPTURE, + snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_usb_caiaq_ops); snd_pcm_lib_preallocate_pages_for_all(dev->pcm, @@ -662,7 +663,7 @@ int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev) MAX_BUFFER_SIZE, MAX_BUFFER_SIZE); dev->data_cb_info = - kmalloc(sizeof(struct snd_usb_caiaq_cb_info) * N_URBS, + kmalloc(sizeof(struct snd_usb_caiaq_cb_info) * N_URBS, GFP_KERNEL); if (!dev->data_cb_info) @@ -672,14 +673,14 @@ int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev) dev->data_cb_info[i].dev = dev; dev->data_cb_info[i].index = i; } - + dev->data_urbs_in = alloc_urbs(dev, SNDRV_PCM_STREAM_CAPTURE, &ret); if (ret < 0) { kfree(dev->data_cb_info); free_urbs(dev->data_urbs_in); return ret; } - + dev->data_urbs_out = alloc_urbs(dev, SNDRV_PCM_STREAM_PLAYBACK, &ret); if (ret < 0) { kfree(dev->data_cb_info); diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c index 515de1cd2a3e..0e5db719de24 100644 --- a/sound/usb/caiaq/device.c +++ b/sound/usb/caiaq/device.c @@ -35,7 +35,7 @@ #include "input.h" MODULE_AUTHOR("Daniel Mack "); -MODULE_DESCRIPTION("caiaq USB audio, version 1.3.14"); +MODULE_DESCRIPTION("caiaq USB audio, version 1.3.17"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2}," "{Native Instruments, RigKontrol3}," @@ -79,7 +79,7 @@ static struct usb_device_id snd_usb_id_table[] = { { .match_flags = USB_DEVICE_ID_MATCH_DEVICE, .idVendor = USB_VID_NATIVEINSTRUMENTS, - .idProduct = USB_PID_RIGKONTROL2 + .idProduct = USB_PID_RIGKONTROL2 }, { .match_flags = USB_DEVICE_ID_MATCH_DEVICE, @@ -197,7 +197,7 @@ int snd_usb_caiaq_send_command(struct snd_usb_caiaqdev *dev, if (buffer && len > 0) memcpy(dev->ep1_out_buf+1, buffer, len); - + dev->ep1_out_buf[0] = command; return usb_bulk_msg(usb_dev, usb_sndbulkpipe(usb_dev, 1), dev->ep1_out_buf, len+1, &actual_len, 200); @@ -208,7 +208,7 @@ int snd_usb_caiaq_set_audio_params (struct snd_usb_caiaqdev *dev, { int ret; char tmp[5]; - + switch (rate) { case 44100: tmp[0] = SAMPLERATE_44100; break; case 48000: tmp[0] = SAMPLERATE_48000; break; @@ -237,12 +237,12 @@ int snd_usb_caiaq_set_audio_params (struct snd_usb_caiaqdev *dev, if (ret) return ret; - - if (!wait_event_timeout(dev->ep1_wait_queue, + + if (!wait_event_timeout(dev->ep1_wait_queue, dev->audio_parm_answer >= 0, HZ)) return -EPIPE; - - if (dev->audio_parm_answer != 1) + + if (dev->audio_parm_answer != 1) debug("unable to set the device's audio params\n"); else dev->bpp = bpp; @@ -250,8 +250,8 @@ int snd_usb_caiaq_set_audio_params (struct snd_usb_caiaqdev *dev, return dev->audio_parm_answer == 1 ? 0 : -EINVAL; } -int snd_usb_caiaq_set_auto_msg (struct snd_usb_caiaqdev *dev, - int digital, int analog, int erp) +int snd_usb_caiaq_set_auto_msg(struct snd_usb_caiaqdev *dev, + int digital, int analog, int erp) { char tmp[3] = { digital, analog, erp }; return snd_usb_caiaq_send_command(dev, EP1_CMD_AUTO_MSG, @@ -262,7 +262,7 @@ static void __devinit setup_card(struct snd_usb_caiaqdev *dev) { int ret; char val[4]; - + /* device-specific startup specials */ switch (dev->chip.usb_id) { case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2): @@ -314,7 +314,7 @@ static void __devinit setup_card(struct snd_usb_caiaqdev *dev) dev->control_state, 1); break; } - + if (dev->spec.num_analog_audio_out + dev->spec.num_analog_audio_in + dev->spec.num_digital_audio_out + @@ -323,7 +323,7 @@ static void __devinit setup_card(struct snd_usb_caiaqdev *dev) if (ret < 0) log("Unable to set up audio system (ret=%d)\n", ret); } - + if (dev->spec.num_midi_in + dev->spec.num_midi_out > 0) { ret = snd_usb_caiaq_midi_init(dev); @@ -363,7 +363,7 @@ static int create_card(struct usb_device* usb_dev, struct snd_card **cardp) if (devnum >= SNDRV_CARDS) return -ENODEV; - err = snd_card_create(index[devnum], id[devnum], THIS_MODULE, + err = snd_card_create(index[devnum], id[devnum], THIS_MODULE, sizeof(struct snd_usb_caiaqdev), &card); if (err < 0) return err; @@ -382,11 +382,11 @@ static int create_card(struct usb_device* usb_dev, struct snd_card **cardp) static int __devinit init_card(struct snd_usb_caiaqdev *dev) { - char *c; + char *c, usbpath[32]; struct usb_device *usb_dev = dev->chip.dev; struct snd_card *card = dev->chip.card; int err, len; - + if (usb_set_interface(usb_dev, 0, 1) != 0) { log("can't set alt interface.\n"); return -EIO; @@ -395,19 +395,19 @@ static int __devinit init_card(struct snd_usb_caiaqdev *dev) usb_init_urb(&dev->ep1_in_urb); usb_init_urb(&dev->midi_out_urb); - usb_fill_bulk_urb(&dev->ep1_in_urb, usb_dev, + usb_fill_bulk_urb(&dev->ep1_in_urb, usb_dev, usb_rcvbulkpipe(usb_dev, 0x1), - dev->ep1_in_buf, EP1_BUFSIZE, + dev->ep1_in_buf, EP1_BUFSIZE, usb_ep1_command_reply_dispatch, dev); - usb_fill_bulk_urb(&dev->midi_out_urb, usb_dev, + usb_fill_bulk_urb(&dev->midi_out_urb, usb_dev, usb_sndbulkpipe(usb_dev, 0x1), - dev->midi_out_buf, EP1_BUFSIZE, + dev->midi_out_buf, EP1_BUFSIZE, snd_usb_caiaq_midi_output_done, dev); - + init_waitqueue_head(&dev->ep1_wait_queue); init_waitqueue_head(&dev->prepare_wait_queue); - + if (usb_submit_urb(&dev->ep1_in_urb, GFP_KERNEL) != 0) return -EIO; @@ -420,47 +420,52 @@ static int __devinit init_card(struct snd_usb_caiaqdev *dev) usb_string(usb_dev, usb_dev->descriptor.iManufacturer, dev->vendor_name, CAIAQ_USB_STR_LEN); - + usb_string(usb_dev, usb_dev->descriptor.iProduct, dev->product_name, CAIAQ_USB_STR_LEN); - - usb_string(usb_dev, usb_dev->descriptor.iSerialNumber, - dev->serial, CAIAQ_USB_STR_LEN); - /* terminate serial string at first white space occurence */ - c = strchr(dev->serial, ' '); - if (c) - *c = '\0'; - - strcpy(card->driver, MODNAME); - strcpy(card->shortname, dev->product_name); + strlcpy(card->driver, MODNAME, sizeof(card->driver)); + strlcpy(card->shortname, dev->product_name, sizeof(card->shortname)); + strlcpy(card->mixername, dev->product_name, sizeof(card->mixername)); - len = snprintf(card->longname, sizeof(card->longname), - "%s %s (serial %s, ", - dev->vendor_name, dev->product_name, dev->serial); + /* if the id was not passed as module option, fill it with a shortened + * version of the product string which does not contain any + * whitespaces */ - if (len < sizeof(card->longname) - 2) - len += usb_make_path(usb_dev, card->longname + len, - sizeof(card->longname) - len); + if (*card->id == '\0') { + char id[sizeof(card->id)]; + + memset(id, 0, sizeof(id)); + + for (c = card->shortname, len = 0; + *c && len < sizeof(card->id); c++) + if (*c != ' ') + id[len++] = *c; + + snd_card_set_id(card, id); + } + + usb_make_path(usb_dev, usbpath, sizeof(usbpath)); + snprintf(card->longname, sizeof(card->longname), + "%s %s (%s)", + dev->vendor_name, dev->product_name, usbpath); - card->longname[len++] = ')'; - card->longname[len] = '\0'; setup_card(dev); return 0; } -static int __devinit snd_probe(struct usb_interface *intf, +static int __devinit snd_probe(struct usb_interface *intf, const struct usb_device_id *id) { int ret; struct snd_card *card; struct usb_device *device = interface_to_usbdev(intf); - + ret = create_card(device, &card); - + if (ret < 0) return ret; - + usb_set_intfdata(intf, card); ret = init_card(caiaqdev(card)); if (ret < 0) { @@ -468,7 +473,7 @@ static int __devinit snd_probe(struct usb_interface *intf, snd_card_free(card); return ret; } - + return 0; } @@ -489,10 +494,10 @@ static void snd_disconnect(struct usb_interface *intf) snd_usb_caiaq_input_free(dev); #endif snd_usb_caiaq_audio_free(dev); - + usb_kill_urb(&dev->ep1_in_urb); usb_kill_urb(&dev->midi_out_urb); - + snd_card_free(card); usb_reset_device(interface_to_usbdev(intf)); } diff --git a/sound/usb/caiaq/device.h b/sound/usb/caiaq/device.h index 4cce1ad7493d..ece73514854e 100644 --- a/sound/usb/caiaq/device.h +++ b/sound/usb/caiaq/device.h @@ -81,7 +81,6 @@ struct snd_usb_caiaqdev { char vendor_name[CAIAQ_USB_STR_LEN]; char product_name[CAIAQ_USB_STR_LEN]; - char serial[CAIAQ_USB_STR_LEN]; int n_streams, n_audio_in, n_audio_out; int streaming, first_packet, output_running; diff --git a/sound/usb/caiaq/midi.c b/sound/usb/caiaq/midi.c index 8fa8cd88d763..538e8c00d31a 100644 --- a/sound/usb/caiaq/midi.c +++ b/sound/usb/caiaq/midi.c @@ -40,7 +40,7 @@ static void snd_usb_caiaq_midi_input_trigger(struct snd_rawmidi_substream *subst if (!dev) return; - + dev->midi_receive_substream = up ? substream : NULL; } @@ -64,18 +64,18 @@ static void snd_usb_caiaq_midi_send(struct snd_usb_caiaqdev *dev, struct snd_rawmidi_substream *substream) { int len, ret; - + dev->midi_out_buf[0] = EP1_CMD_MIDI_WRITE; dev->midi_out_buf[1] = 0; /* port */ len = snd_rawmidi_transmit(substream, dev->midi_out_buf + 3, EP1_BUFSIZE - 3); - + if (len <= 0) return; - + dev->midi_out_buf[2] = len; dev->midi_out_urb.transfer_buffer_length = len+3; - + ret = usb_submit_urb(&dev->midi_out_urb, GFP_ATOMIC); if (ret < 0) log("snd_usb_caiaq_midi_send(%p): usb_submit_urb() failed," @@ -88,7 +88,7 @@ static void snd_usb_caiaq_midi_send(struct snd_usb_caiaqdev *dev, static void snd_usb_caiaq_midi_output_trigger(struct snd_rawmidi_substream *substream, int up) { struct snd_usb_caiaqdev *dev = substream->rmidi->private_data; - + if (up) { dev->midi_out_substream = substream; if (!dev->midi_out_active) @@ -113,12 +113,12 @@ static struct snd_rawmidi_ops snd_usb_caiaq_midi_input = .trigger = snd_usb_caiaq_midi_input_trigger, }; -void snd_usb_caiaq_midi_handle_input(struct snd_usb_caiaqdev *dev, +void snd_usb_caiaq_midi_handle_input(struct snd_usb_caiaqdev *dev, int port, const char *buf, int len) { if (!dev->midi_receive_substream) return; - + snd_rawmidi_receive(dev->midi_receive_substream, buf, len); } @@ -142,16 +142,16 @@ int snd_usb_caiaq_midi_init(struct snd_usb_caiaqdev *device) if (device->spec.num_midi_out > 0) { rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT; - snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, + snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_usb_caiaq_midi_output); } if (device->spec.num_midi_in > 0) { rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT; - snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, + snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_usb_caiaq_midi_input); } - + device->rmidi = rmidi; return 0; @@ -160,7 +160,7 @@ int snd_usb_caiaq_midi_init(struct snd_usb_caiaqdev *device) void snd_usb_caiaq_midi_output_done(struct urb* urb) { struct snd_usb_caiaqdev *dev = urb->context; - + dev->midi_out_active = 0; if (urb->status != 0) return; diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index a6b88482637b..c7b902358b7b 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -627,6 +627,7 @@ static int prepare_playback_urb(struct snd_usb_substream *subs, subs->hwptr_done += offs; if (subs->hwptr_done >= runtime->buffer_size) subs->hwptr_done -= runtime->buffer_size; + runtime->delay += offs; spin_unlock_irqrestore(&subs->lock, flags); urb->transfer_buffer_length = offs * stride; if (period_elapsed) @@ -636,12 +637,22 @@ static int prepare_playback_urb(struct snd_usb_substream *subs, /* * process after playback data complete - * - nothing to do + * - decrease the delay count again */ static int retire_playback_urb(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *urb) { + unsigned long flags; + int stride = runtime->frame_bits >> 3; + int processed = urb->transfer_buffer_length / stride; + + spin_lock_irqsave(&subs->lock, flags); + if (processed > runtime->delay) + runtime->delay = 0; + else + runtime->delay -= processed; + spin_unlock_irqrestore(&subs->lock, flags); return 0; } @@ -1520,6 +1531,7 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) subs->hwptr_done = 0; subs->transfer_done = 0; subs->phase = 0; + runtime->delay = 0; /* clear urbs (to be sure) */ deactivate_urbs(subs, 0, 1); @@ -3279,6 +3291,25 @@ static int snd_usb_cm106_boot_quirk(struct usb_device *dev) return snd_usb_cm106_write_int_reg(dev, 2, 0x8004); } +/* + * C-Media CM6206 is based on CM106 with two additional + * registers that are not documented in the data sheet. + * Values here are chosen based on sniffing USB traffic + * under Windows. + */ +static int snd_usb_cm6206_boot_quirk(struct usb_device *dev) +{ + int err, reg; + int val[] = {0x200c, 0x3000, 0xf800, 0x143f, 0x0000, 0x3000}; + + for (reg = 0; reg < ARRAY_SIZE(val); reg++) { + err = snd_usb_cm106_write_int_reg(dev, reg, val[reg]); + if (err < 0) + return err; + } + + return err; +} /* * Setup quirks @@ -3565,6 +3596,12 @@ static void *snd_usb_audio_probe(struct usb_device *dev, goto __err_val; } + /* C-Media CM6206 / CM106-Like Sound Device */ + if (id == USB_ID(0x0d8c, 0x0102)) { + if (snd_usb_cm6206_boot_quirk(dev) < 0) + goto __err_val; + } + /* * found a config. now register to ALSA */ diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index ecb58e7a6245..4bd3a7a0edc1 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -423,7 +423,7 @@ static int set_ctl_value(struct usb_mixer_elem_info *cval, int request, int vali value_set = convert_bytes_value(cval, value_set); buf[0] = value_set & 0xff; buf[1] = (value_set >> 8) & 0xff; - while (timeout -- > 0) + while (timeout-- > 0) if (snd_usb_ctl_msg(cval->mixer->chip->dev, usb_sndctrlpipe(cval->mixer->chip->dev, 0), request, diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h index 5d955aaad85f..f6f201eb24ce 100644 --- a/sound/usb/usbquirks.h +++ b/sound/usb/usbquirks.h @@ -1469,6 +1469,41 @@ YAMAHA_DEVICE(0x7010, "UB99"), } } }, +{ + /* Edirol M-16DX */ + /* FIXME: This quirk gives a good-working capture stream but the + * playback seems problematic because of lacking of sync + * with capture stream. It needs to sync with the capture + * clock. As now, you'll get frequent sound distortions + * via the playback. + */ + USB_DEVICE(0x0582, 0x00c4), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const struct snd_usb_audio_quirk[]) { + { + .ifnum = 0, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const struct snd_usb_midi_endpoint_info) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, + { + .ifnum = -1 + } + } + } +}, { /* BOSS GT-10 */ USB_DEVICE(0x0582, 0x00da), @@ -1950,6 +1985,14 @@ YAMAHA_DEVICE(0x7010, "UB99"), .type = QUIRK_MIDI_STANDARD_INTERFACE } }, +{ + USB_DEVICE(0x0ccd, 0x0028), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + .vendor_name = "TerraTec", + .product_name = "Aureon5.1MkII", + .ifnum = QUIRK_NO_INTERFACE + } +}, { USB_DEVICE(0x0ccd, 0x0035), .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { diff --git a/tools/perf/.gitignore b/tools/perf/.gitignore new file mode 100644 index 000000000000..d69a759a1046 --- /dev/null +++ b/tools/perf/.gitignore @@ -0,0 +1,16 @@ +PERF-BUILD-OPTIONS +PERF-CFLAGS +PERF-GUI-VARS +PERF-VERSION-FILE +perf +perf-help +perf-record +perf-report +perf-stat +perf-top +perf*.1 +perf*.xml +common-cmds.h +tags +TAGS +cscope* diff --git a/tools/perf/Documentation/Makefile b/tools/perf/Documentation/Makefile new file mode 100644 index 000000000000..5457192e1b41 --- /dev/null +++ b/tools/perf/Documentation/Makefile @@ -0,0 +1,300 @@ +MAN1_TXT= \ + $(filter-out $(addsuffix .txt, $(ARTICLES) $(SP_ARTICLES)), \ + $(wildcard perf-*.txt)) \ + perf.txt +MAN5_TXT= +MAN7_TXT= + +MAN_TXT = $(MAN1_TXT) $(MAN5_TXT) $(MAN7_TXT) +MAN_XML=$(patsubst %.txt,%.xml,$(MAN_TXT)) +MAN_HTML=$(patsubst %.txt,%.html,$(MAN_TXT)) + +DOC_HTML=$(MAN_HTML) + +ARTICLES = +# with their own formatting rules. +SP_ARTICLES = +API_DOCS = $(patsubst %.txt,%,$(filter-out technical/api-index-skel.txt technical/api-index.txt, $(wildcard technical/api-*.txt))) +SP_ARTICLES += $(API_DOCS) +SP_ARTICLES += technical/api-index + +DOC_HTML += $(patsubst %,%.html,$(ARTICLES) $(SP_ARTICLES)) + +DOC_MAN1=$(patsubst %.txt,%.1,$(MAN1_TXT)) +DOC_MAN5=$(patsubst %.txt,%.5,$(MAN5_TXT)) +DOC_MAN7=$(patsubst %.txt,%.7,$(MAN7_TXT)) + +prefix?=$(HOME) +bindir?=$(prefix)/bin +htmldir?=$(prefix)/share/doc/perf-doc +pdfdir?=$(prefix)/share/doc/perf-doc +mandir?=$(prefix)/share/man +man1dir=$(mandir)/man1 +man5dir=$(mandir)/man5 +man7dir=$(mandir)/man7 +# DESTDIR= + +ASCIIDOC=asciidoc +ASCIIDOC_EXTRA = +MANPAGE_XSL = manpage-normal.xsl +XMLTO_EXTRA = +INSTALL?=install +RM ?= rm -f +DOC_REF = origin/man +HTML_REF = origin/html + +infodir?=$(prefix)/share/info +MAKEINFO=makeinfo +INSTALL_INFO=install-info +DOCBOOK2X_TEXI=docbook2x-texi +DBLATEX=dblatex +ifndef PERL_PATH + PERL_PATH = /usr/bin/perl +endif + +-include ../config.mak.autogen +-include ../config.mak + +# +# For asciidoc ... +# -7.1.2, no extra settings are needed. +# 8.0-, set ASCIIDOC8. +# + +# +# For docbook-xsl ... +# -1.68.1, set ASCIIDOC_NO_ROFF? (based on changelog from 1.73.0) +# 1.69.0, no extra settings are needed? +# 1.69.1-1.71.0, set DOCBOOK_SUPPRESS_SP? +# 1.71.1, no extra settings are needed? +# 1.72.0, set DOCBOOK_XSL_172. +# 1.73.0-, set ASCIIDOC_NO_ROFF +# + +# +# If you had been using DOCBOOK_XSL_172 in an attempt to get rid +# of 'the ".ft C" problem' in your generated manpages, and you +# instead ended up with weird characters around callouts, try +# using ASCIIDOC_NO_ROFF instead (it works fine with ASCIIDOC8). +# + +ifdef ASCIIDOC8 +ASCIIDOC_EXTRA += -a asciidoc7compatible +endif +ifdef DOCBOOK_XSL_172 +ASCIIDOC_EXTRA += -a perf-asciidoc-no-roff +MANPAGE_XSL = manpage-1.72.xsl +else + ifdef ASCIIDOC_NO_ROFF + # docbook-xsl after 1.72 needs the regular XSL, but will not + # pass-thru raw roff codes from asciidoc.conf, so turn them off. + ASCIIDOC_EXTRA += -a perf-asciidoc-no-roff + endif +endif +ifdef MAN_BOLD_LITERAL +XMLTO_EXTRA += -m manpage-bold-literal.xsl +endif +ifdef DOCBOOK_SUPPRESS_SP +XMLTO_EXTRA += -m manpage-suppress-sp.xsl +endif + +SHELL_PATH ?= $(SHELL) +# Shell quote; +SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) + +# +# Please note that there is a minor bug in asciidoc. +# The version after 6.0.3 _will_ include the patch found here: +# http://marc.theaimsgroup.com/?l=perf&m=111558757202243&w=2 +# +# Until that version is released you may have to apply the patch +# yourself - yes, all 6 characters of it! +# + +QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir +QUIET_SUBDIR1 = + +ifneq ($(findstring $(MAKEFLAGS),w),w) +PRINT_DIR = --no-print-directory +else # "make -w" +NO_SUBDIR = : +endif + +ifneq ($(findstring $(MAKEFLAGS),s),s) +ifndef V + QUIET_ASCIIDOC = @echo ' ' ASCIIDOC $@; + QUIET_XMLTO = @echo ' ' XMLTO $@; + QUIET_DB2TEXI = @echo ' ' DB2TEXI $@; + QUIET_MAKEINFO = @echo ' ' MAKEINFO $@; + QUIET_DBLATEX = @echo ' ' DBLATEX $@; + QUIET_XSLTPROC = @echo ' ' XSLTPROC $@; + QUIET_GEN = @echo ' ' GEN $@; + QUIET_STDERR = 2> /dev/null + QUIET_SUBDIR0 = +@subdir= + QUIET_SUBDIR1 = ;$(NO_SUBDIR) echo ' ' SUBDIR $$subdir; \ + $(MAKE) $(PRINT_DIR) -C $$subdir + export V +endif +endif + +all: html man + +html: $(DOC_HTML) + +$(DOC_HTML) $(DOC_MAN1) $(DOC_MAN5) $(DOC_MAN7): asciidoc.conf + +man: man1 man5 man7 +man1: $(DOC_MAN1) +man5: $(DOC_MAN5) +man7: $(DOC_MAN7) + +info: perf.info perfman.info + +pdf: user-manual.pdf + +install: install-man + +install-man: man + $(INSTALL) -d -m 755 $(DESTDIR)$(man1dir) +# $(INSTALL) -d -m 755 $(DESTDIR)$(man5dir) +# $(INSTALL) -d -m 755 $(DESTDIR)$(man7dir) + $(INSTALL) -m 644 $(DOC_MAN1) $(DESTDIR)$(man1dir) +# $(INSTALL) -m 644 $(DOC_MAN5) $(DESTDIR)$(man5dir) +# $(INSTALL) -m 644 $(DOC_MAN7) $(DESTDIR)$(man7dir) + +install-info: info + $(INSTALL) -d -m 755 $(DESTDIR)$(infodir) + $(INSTALL) -m 644 perf.info perfman.info $(DESTDIR)$(infodir) + if test -r $(DESTDIR)$(infodir)/dir; then \ + $(INSTALL_INFO) --info-dir=$(DESTDIR)$(infodir) perf.info ;\ + $(INSTALL_INFO) --info-dir=$(DESTDIR)$(infodir) perfman.info ;\ + else \ + echo "No directory found in $(DESTDIR)$(infodir)" >&2 ; \ + fi + +install-pdf: pdf + $(INSTALL) -d -m 755 $(DESTDIR)$(pdfdir) + $(INSTALL) -m 644 user-manual.pdf $(DESTDIR)$(pdfdir) + +install-html: html + '$(SHELL_PATH_SQ)' ./install-webdoc.sh $(DESTDIR)$(htmldir) + +../PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE + $(QUIET_SUBDIR0)../ $(QUIET_SUBDIR1) PERF-VERSION-FILE + +-include ../PERF-VERSION-FILE + +# +# Determine "include::" file references in asciidoc files. +# +doc.dep : $(wildcard *.txt) build-docdep.perl + $(QUIET_GEN)$(RM) $@+ $@ && \ + $(PERL_PATH) ./build-docdep.perl >$@+ $(QUIET_STDERR) && \ + mv $@+ $@ + +-include doc.dep + +cmds_txt = cmds-ancillaryinterrogators.txt \ + cmds-ancillarymanipulators.txt \ + cmds-mainporcelain.txt \ + cmds-plumbinginterrogators.txt \ + cmds-plumbingmanipulators.txt \ + cmds-synchingrepositories.txt \ + cmds-synchelpers.txt \ + cmds-purehelpers.txt \ + cmds-foreignscminterface.txt + +$(cmds_txt): cmd-list.made + +cmd-list.made: cmd-list.perl ../command-list.txt $(MAN1_TXT) + $(QUIET_GEN)$(RM) $@ && \ + $(PERL_PATH) ./cmd-list.perl ../command-list.txt $(QUIET_STDERR) && \ + date >$@ + +clean: + $(RM) *.xml *.xml+ *.html *.html+ *.1 *.5 *.7 + $(RM) *.texi *.texi+ *.texi++ perf.info perfman.info + $(RM) howto-index.txt howto/*.html doc.dep + $(RM) technical/api-*.html technical/api-index.txt + $(RM) $(cmds_txt) *.made + +$(MAN_HTML): %.html : %.txt + $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \ + $(ASCIIDOC) -b xhtml11 -d manpage -f asciidoc.conf \ + $(ASCIIDOC_EXTRA) -aperf_version=$(PERF_VERSION) -o $@+ $< && \ + mv $@+ $@ + +%.1 %.5 %.7 : %.xml + $(QUIET_XMLTO)$(RM) $@ && \ + xmlto -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $< + +%.xml : %.txt + $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \ + $(ASCIIDOC) -b docbook -d manpage -f asciidoc.conf \ + $(ASCIIDOC_EXTRA) -aperf_version=$(PERF_VERSION) -o $@+ $< && \ + mv $@+ $@ + +XSLT = docbook.xsl +XSLTOPTS = --xinclude --stringparam html.stylesheet docbook-xsl.css + +user-manual.html: user-manual.xml + $(QUIET_XSLTPROC)xsltproc $(XSLTOPTS) -o $@ $(XSLT) $< + +perf.info: user-manual.texi + $(QUIET_MAKEINFO)$(MAKEINFO) --no-split -o $@ user-manual.texi + +user-manual.texi: user-manual.xml + $(QUIET_DB2TEXI)$(RM) $@+ $@ && \ + $(DOCBOOK2X_TEXI) user-manual.xml --encoding=UTF-8 --to-stdout >$@++ && \ + $(PERL_PATH) fix-texi.perl <$@++ >$@+ && \ + rm $@++ && \ + mv $@+ $@ + +user-manual.pdf: user-manual.xml + $(QUIET_DBLATEX)$(RM) $@+ $@ && \ + $(DBLATEX) -o $@+ -p /etc/asciidoc/dblatex/asciidoc-dblatex.xsl -s /etc/asciidoc/dblatex/asciidoc-dblatex.sty $< && \ + mv $@+ $@ + +perfman.texi: $(MAN_XML) cat-texi.perl + $(QUIET_DB2TEXI)$(RM) $@+ $@ && \ + ($(foreach xml,$(MAN_XML),$(DOCBOOK2X_TEXI) --encoding=UTF-8 \ + --to-stdout $(xml) &&) true) > $@++ && \ + $(PERL_PATH) cat-texi.perl $@ <$@++ >$@+ && \ + rm $@++ && \ + mv $@+ $@ + +perfman.info: perfman.texi + $(QUIET_MAKEINFO)$(MAKEINFO) --no-split --no-validate $*.texi + +$(patsubst %.txt,%.texi,$(MAN_TXT)): %.texi : %.xml + $(QUIET_DB2TEXI)$(RM) $@+ $@ && \ + $(DOCBOOK2X_TEXI) --to-stdout $*.xml >$@+ && \ + mv $@+ $@ + +howto-index.txt: howto-index.sh $(wildcard howto/*.txt) + $(QUIET_GEN)$(RM) $@+ $@ && \ + '$(SHELL_PATH_SQ)' ./howto-index.sh $(wildcard howto/*.txt) >$@+ && \ + mv $@+ $@ + +$(patsubst %,%.html,$(ARTICLES)) : %.html : %.txt + $(QUIET_ASCIIDOC)$(ASCIIDOC) -b xhtml11 $*.txt + +WEBDOC_DEST = /pub/software/tools/perf/docs + +$(patsubst %.txt,%.html,$(wildcard howto/*.txt)): %.html : %.txt + $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \ + sed -e '1,/^$$/d' $< | $(ASCIIDOC) -b xhtml11 - >$@+ && \ + mv $@+ $@ + +install-webdoc : html + '$(SHELL_PATH_SQ)' ./install-webdoc.sh $(WEBDOC_DEST) + +quick-install: quick-install-man + +quick-install-man: + '$(SHELL_PATH_SQ)' ./install-doc-quick.sh $(DOC_REF) $(DESTDIR)$(mandir) + +quick-install-html: + '$(SHELL_PATH_SQ)' ./install-doc-quick.sh $(HTML_REF) $(DESTDIR)$(htmldir) + +.PHONY: .FORCE-PERF-VERSION-FILE diff --git a/tools/perf/Documentation/asciidoc.conf b/tools/perf/Documentation/asciidoc.conf new file mode 100644 index 000000000000..356b23a40339 --- /dev/null +++ b/tools/perf/Documentation/asciidoc.conf @@ -0,0 +1,91 @@ +## linkperf: macro +# +# Usage: linkperf:command[manpage-section] +# +# Note, {0} is the manpage section, while {target} is the command. +# +# Show PERF link as: (
); if section is defined, else just show +# the command. + +[macros] +(?su)[\\]?(?Plinkperf):(?P\S*?)\[(?P.*?)\]= + +[attributes] +asterisk=* +plus=+ +caret=^ +startsb=[ +endsb=] +tilde=~ + +ifdef::backend-docbook[] +[linkperf-inlinemacro] +{0%{target}} +{0#} +{0#{target}{0}} +{0#} +endif::backend-docbook[] + +ifdef::backend-docbook[] +ifndef::perf-asciidoc-no-roff[] +# "unbreak" docbook-xsl v1.68 for manpages. v1.69 works with or without this. +# v1.72 breaks with this because it replaces dots not in roff requests. +[listingblock] +{title} + +ifdef::doctype-manpage[] + .ft C +endif::doctype-manpage[] +| +ifdef::doctype-manpage[] + .ft +endif::doctype-manpage[] + +{title#} +endif::perf-asciidoc-no-roff[] + +ifdef::perf-asciidoc-no-roff[] +ifdef::doctype-manpage[] +# The following two small workarounds insert a simple paragraph after screen +[listingblock] +{title} + +| + +{title#} + +[verseblock] +{title} +{title%} +{title#} +| + +{title#} +{title%} +endif::doctype-manpage[] +endif::perf-asciidoc-no-roff[] +endif::backend-docbook[] + +ifdef::doctype-manpage[] +ifdef::backend-docbook[] +[header] +template::[header-declarations] + + +{mantitle} +{manvolnum} +perf +{perf_version} +perf Manual + + + {manname} + {manpurpose} + +endif::backend-docbook[] +endif::doctype-manpage[] + +ifdef::backend-xhtml11[] +[linkperf-inlinemacro] +{target}{0?({0})} +endif::backend-xhtml11[] diff --git a/tools/perf/Documentation/manpage-1.72.xsl b/tools/perf/Documentation/manpage-1.72.xsl new file mode 100644 index 000000000000..b4d315cb8c47 --- /dev/null +++ b/tools/perf/Documentation/manpage-1.72.xsl @@ -0,0 +1,14 @@ + + + + + + + + + + diff --git a/tools/perf/Documentation/manpage-base.xsl b/tools/perf/Documentation/manpage-base.xsl new file mode 100644 index 000000000000..a264fa616093 --- /dev/null +++ b/tools/perf/Documentation/manpage-base.xsl @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + sp + + + + + + + + br + + + diff --git a/tools/perf/Documentation/manpage-bold-literal.xsl b/tools/perf/Documentation/manpage-bold-literal.xsl new file mode 100644 index 000000000000..608eb5df6281 --- /dev/null +++ b/tools/perf/Documentation/manpage-bold-literal.xsl @@ -0,0 +1,17 @@ + + + + + + + fB + + + fR + + + diff --git a/tools/perf/Documentation/manpage-normal.xsl b/tools/perf/Documentation/manpage-normal.xsl new file mode 100644 index 000000000000..a48f5b11f3dc --- /dev/null +++ b/tools/perf/Documentation/manpage-normal.xsl @@ -0,0 +1,13 @@ + + + + + + +\ +. + + diff --git a/tools/perf/Documentation/manpage-suppress-sp.xsl b/tools/perf/Documentation/manpage-suppress-sp.xsl new file mode 100644 index 000000000000..a63c7632a87d --- /dev/null +++ b/tools/perf/Documentation/manpage-suppress-sp.xsl @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + diff --git a/tools/perf/Documentation/perf-annotate.txt b/tools/perf/Documentation/perf-annotate.txt new file mode 100644 index 000000000000..c9dcade06831 --- /dev/null +++ b/tools/perf/Documentation/perf-annotate.txt @@ -0,0 +1,29 @@ +perf-annotate(1) +============== + +NAME +---- +perf-annotate - Read perf.data (created by perf record) and display annotated code + +SYNOPSIS +-------- +[verse] +'perf annotate' [-i | --input=file] symbol_name + +DESCRIPTION +----------- +This command reads the input file and displays an annotated version of the +code. If the object file has debug symbols then the source code will be +displayed alongside assembly code. + +If there is no debug info in the object, then annotated assembly is displayed. + +OPTIONS +------- +-i:: +--input=:: + Input file name. (default: perf.data) + +SEE ALSO +-------- +linkperf:perf-record[1] diff --git a/tools/perf/Documentation/perf-help.txt b/tools/perf/Documentation/perf-help.txt new file mode 100644 index 000000000000..514391818d1f --- /dev/null +++ b/tools/perf/Documentation/perf-help.txt @@ -0,0 +1,38 @@ +perf-help(1) +============ + +NAME +---- +perf-help - display help information about perf + +SYNOPSIS +-------- +'perf help' [-a|--all] [COMMAND] + +DESCRIPTION +----------- + +With no options and no COMMAND given, the synopsis of the 'perf' +command and a list of the most commonly used perf commands are printed +on the standard output. + +If the option '--all' or '-a' is given, then all available commands are +printed on the standard output. + +If a perf command is named, a manual page for that command is brought +up. The 'man' program is used by default for this purpose, but this +can be overridden by other options or configuration variables. + +Note that `perf --help ...` is identical to `perf help ...` because the +former is internally converted into the latter. + +OPTIONS +------- +-a:: +--all:: + Prints all the available commands on the standard output. This + option supersedes any other option. + +PERF +---- +Part of the linkperf:perf[1] suite diff --git a/tools/perf/Documentation/perf-list.txt b/tools/perf/Documentation/perf-list.txt new file mode 100644 index 000000000000..8290b9422668 --- /dev/null +++ b/tools/perf/Documentation/perf-list.txt @@ -0,0 +1,25 @@ +perf-list(1) +============ + +NAME +---- +perf-list - List all symbolic event types + +SYNOPSIS +-------- +[verse] +'perf list' + +DESCRIPTION +----------- +This command displays the symbolic event types which can be selected in the +various perf commands with the -e option. + +OPTIONS +------- +None + +SEE ALSO +-------- +linkperf:perf-stat[1], linkperf:perf-top[1], +linkperf:perf-record[1] diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt new file mode 100644 index 000000000000..1dbc1eeb4c01 --- /dev/null +++ b/tools/perf/Documentation/perf-record.txt @@ -0,0 +1,42 @@ +perf-record(1) +============== + +NAME +---- +perf-record - Run a command and record its profile into perf.data + +SYNOPSIS +-------- +[verse] +'perf record' [-e | --event=EVENT] [-l] [-a] +'perf record' [-e | --event=EVENT] [-l] [-a] -- [] + +DESCRIPTION +----------- +This command runs a command and gathers a performance counter profile +from it, into perf.data - without displaying anything. + +This file can then be inspected later on, using 'perf report'. + + +OPTIONS +------- +...:: + Any command you can specify in a shell. + +-e:: +--event=:: + Select the PMU event. Selection can be a symbolic event name + (use 'perf list' to list all events) or a raw PMU + event (eventsel+umask) in the form of rNNN where NNN is a + hexadecimal event descriptor. + +-a:: + system-wide collection + +-l:: + scale counter values + +SEE ALSO +-------- +linkperf:perf-stat[1], linkperf:perf-list[1] diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt new file mode 100644 index 000000000000..52d3fc6846a9 --- /dev/null +++ b/tools/perf/Documentation/perf-report.txt @@ -0,0 +1,26 @@ +perf-report(1) +============== + +NAME +---- +perf-report - Read perf.data (created by perf record) and display the profile + +SYNOPSIS +-------- +[verse] +'perf report' [-i | --input=file] + +DESCRIPTION +----------- +This command displays the performance counter profile information recorded +via perf report. + +OPTIONS +------- +-i:: +--input=:: + Input file name. (default: perf.data) + +SEE ALSO +-------- +linkperf:perf-stat[1] diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt new file mode 100644 index 000000000000..c368a72721d7 --- /dev/null +++ b/tools/perf/Documentation/perf-stat.txt @@ -0,0 +1,66 @@ +perf-stat(1) +============ + +NAME +---- +perf-stat - Run a command and gather performance counter statistics + +SYNOPSIS +-------- +[verse] +'perf stat' [-e | --event=EVENT] [-l] [-a] +'perf stat' [-e | --event=EVENT] [-l] [-a] -- [] + +DESCRIPTION +----------- +This command runs a command and gathers performance counter statistics +from it. + + +OPTIONS +------- +...:: + Any command you can specify in a shell. + + +-e:: +--event=:: + Select the PMU event. Selection can be a symbolic event name + (use 'perf list' to list all events) or a raw PMU + event (eventsel+umask) in the form of rNNN where NNN is a + hexadecimal event descriptor. + +-i:: +--inherit:: + child tasks inherit counters +-p:: +--pid=:: + stat events on existing pid + +-a:: + system-wide collection + +-l:: + scale counter values + +EXAMPLES +-------- + +$ perf stat -- make -j + + Performance counter stats for 'make -j': + + 8117.370256 task clock ticks # 11.281 CPU utilization factor + 678 context switches # 0.000 M/sec + 133 CPU migrations # 0.000 M/sec + 235724 pagefaults # 0.029 M/sec + 24821162526 CPU cycles # 3057.784 M/sec + 18687303457 instructions # 2302.138 M/sec + 172158895 cache references # 21.209 M/sec + 27075259 cache misses # 3.335 M/sec + + Wall-clock time elapsed: 719.554352 msecs + +SEE ALSO +-------- +linkperf:perf-top[1], linkperf:perf-list[1] diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt new file mode 100644 index 000000000000..539d01289725 --- /dev/null +++ b/tools/perf/Documentation/perf-top.txt @@ -0,0 +1,39 @@ +perf-top(1) +=========== + +NAME +---- +perf-top - Run a command and profile it + +SYNOPSIS +-------- +[verse] +'perf top' [-e | --event=EVENT] [-l] [-a] + +DESCRIPTION +----------- +This command runs a command and gathers a performance counter profile +from it. + + +OPTIONS +------- +...:: + Any command you can specify in a shell. + +-e:: +--event=:: + Select the PMU event. Selection can be a symbolic event name + (use 'perf list' to list all events) or a raw PMU + event (eventsel+umask) in the form of rNNN where NNN is a + hexadecimal event descriptor. + +-a:: + system-wide collection + +-l:: + scale counter values + +SEE ALSO +-------- +linkperf:perf-stat[1], linkperf:perf-list[1] diff --git a/tools/perf/Documentation/perf.txt b/tools/perf/Documentation/perf.txt new file mode 100644 index 000000000000..69c832557199 --- /dev/null +++ b/tools/perf/Documentation/perf.txt @@ -0,0 +1,24 @@ +perf(1) +======= + +NAME +---- +perf - Performance analysis tools for Linux + +SYNOPSIS +-------- +[verse] +'perf' [--version] [--help] COMMAND [ARGS] + +DESCRIPTION +----------- +Performance counters for Linux are are a new kernel-based subsystem +that provide a framework for all things performance analysis. It +covers hardware level (CPU/PMU, Performance Monitoring Unit) features +and software features (software counters, tracepoints) as well. + +SEE ALSO +-------- +linkperf:perf-stat[1], linkperf:perf-top[1], +linkperf:perf-record[1], linkperf:perf-report[1], +linkperf:perf-list[1] diff --git a/tools/perf/Makefile b/tools/perf/Makefile new file mode 100644 index 000000000000..36d7eef49913 --- /dev/null +++ b/tools/perf/Makefile @@ -0,0 +1,935 @@ +# The default target of this Makefile is... +all:: + +# Define V=1 to have a more verbose compile. +# +# Define SNPRINTF_RETURNS_BOGUS if your are on a system which snprintf() +# or vsnprintf() return -1 instead of number of characters which would +# have been written to the final string if enough space had been available. +# +# Define FREAD_READS_DIRECTORIES if your are on a system which succeeds +# when attempting to read from an fopen'ed directory. +# +# Define NO_OPENSSL environment variable if you do not have OpenSSL. +# This also implies MOZILLA_SHA1. +# +# Define CURLDIR=/foo/bar if your curl header and library files are in +# /foo/bar/include and /foo/bar/lib directories. +# +# Define EXPATDIR=/foo/bar if your expat header and library files are in +# /foo/bar/include and /foo/bar/lib directories. +# +# Define NO_D_INO_IN_DIRENT if you don't have d_ino in your struct dirent. +# +# Define NO_D_TYPE_IN_DIRENT if your platform defines DT_UNKNOWN but lacks +# d_type in struct dirent (latest Cygwin -- will be fixed soonish). +# +# Define NO_C99_FORMAT if your formatted IO functions (printf/scanf et.al.) +# do not support the 'size specifiers' introduced by C99, namely ll, hh, +# j, z, t. (representing long long int, char, intmax_t, size_t, ptrdiff_t). +# some C compilers supported these specifiers prior to C99 as an extension. +# +# Define NO_STRCASESTR if you don't have strcasestr. +# +# Define NO_MEMMEM if you don't have memmem. +# +# Define NO_STRTOUMAX if you don't have strtoumax in the C library. +# If your compiler also does not support long long or does not have +# strtoull, define NO_STRTOULL. +# +# Define NO_SETENV if you don't have setenv in the C library. +# +# Define NO_UNSETENV if you don't have unsetenv in the C library. +# +# Define NO_MKDTEMP if you don't have mkdtemp in the C library. +# +# Define NO_SYS_SELECT_H if you don't have sys/select.h. +# +# Define NO_SYMLINK_HEAD if you never want .perf/HEAD to be a symbolic link. +# Enable it on Windows. By default, symrefs are still used. +# +# Define NO_SVN_TESTS if you want to skip time-consuming SVN interoperability +# tests. These tests take up a significant amount of the total test time +# but are not needed unless you plan to talk to SVN repos. +# +# Define NO_FINK if you are building on Darwin/Mac OS X, have Fink +# installed in /sw, but don't want PERF to link against any libraries +# installed there. If defined you may specify your own (or Fink's) +# include directories and library directories by defining CFLAGS +# and LDFLAGS appropriately. +# +# Define NO_DARWIN_PORTS if you are building on Darwin/Mac OS X, +# have DarwinPorts installed in /opt/local, but don't want PERF to +# link against any libraries installed there. If defined you may +# specify your own (or DarwinPort's) include directories and +# library directories by defining CFLAGS and LDFLAGS appropriately. +# +# Define PPC_SHA1 environment variable when running make to make use of +# a bundled SHA1 routine optimized for PowerPC. +# +# Define ARM_SHA1 environment variable when running make to make use of +# a bundled SHA1 routine optimized for ARM. +# +# Define MOZILLA_SHA1 environment variable when running make to make use of +# a bundled SHA1 routine coming from Mozilla. It is GPL'd and should be fast +# on non-x86 architectures (e.g. PowerPC), while the OpenSSL version (default +# choice) has very fast version optimized for i586. +# +# Define NEEDS_SSL_WITH_CRYPTO if you need -lcrypto with -lssl (Darwin). +# +# Define NEEDS_LIBICONV if linking with libc is not enough (Darwin). +# +# Define NEEDS_SOCKET if linking with libc is not enough (SunOS, +# Patrick Mauritz). +# +# Define NO_MMAP if you want to avoid mmap. +# +# Define NO_PTHREADS if you do not have or do not want to use Pthreads. +# +# Define NO_PREAD if you have a problem with pread() system call (e.g. +# cygwin.dll before v1.5.22). +# +# Define NO_FAST_WORKING_DIRECTORY if accessing objects in pack files is +# generally faster on your platform than accessing the working directory. +# +# Define NO_TRUSTABLE_FILEMODE if your filesystem may claim to support +# the executable mode bit, but doesn't really do so. +# +# Define NO_IPV6 if you lack IPv6 support and getaddrinfo(). +# +# Define NO_SOCKADDR_STORAGE if your platform does not have struct +# sockaddr_storage. +# +# Define NO_ICONV if your libc does not properly support iconv. +# +# Define OLD_ICONV if your library has an old iconv(), where the second +# (input buffer pointer) parameter is declared with type (const char **). +# +# Define NO_DEFLATE_BOUND if your zlib does not have deflateBound. +# +# Define NO_R_TO_GCC_LINKER if your gcc does not like "-R/path/lib" +# that tells runtime paths to dynamic libraries; +# "-Wl,-rpath=/path/lib" is used instead. +# +# Define USE_NSEC below if you want perf to care about sub-second file mtimes +# and ctimes. Note that you need recent glibc (at least 2.2.4) for this, and +# it will BREAK YOUR LOCAL DIFFS! show-diff and anything using it will likely +# randomly break unless your underlying filesystem supports those sub-second +# times (my ext3 doesn't). +# +# Define USE_ST_TIMESPEC if your "struct stat" uses "st_ctimespec" instead of +# "st_ctim" +# +# Define NO_NSEC if your "struct stat" does not have "st_ctim.tv_nsec" +# available. This automatically turns USE_NSEC off. +# +# Define USE_STDEV below if you want perf to care about the underlying device +# change being considered an inode change from the update-index perspective. +# +# Define NO_ST_BLOCKS_IN_STRUCT_STAT if your platform does not have st_blocks +# field that counts the on-disk footprint in 512-byte blocks. +# +# Define ASCIIDOC8 if you want to format documentation with AsciiDoc 8 +# +# Define DOCBOOK_XSL_172 if you want to format man pages with DocBook XSL v1.72. +# +# Define NO_PERL_MAKEMAKER if you cannot use Makefiles generated by perl's +# MakeMaker (e.g. using ActiveState under Cygwin). +# +# Define NO_PERL if you do not want Perl scripts or libraries at all. +# +# Define INTERNAL_QSORT to use Git's implementation of qsort(), which +# is a simplified version of the merge sort used in glibc. This is +# recommended if Git triggers O(n^2) behavior in your platform's qsort(). +# +# Define NO_EXTERNAL_GREP if you don't want "perf grep" to ever call +# your external grep (e.g., if your system lacks grep, if its grep is +# broken, or spawning external process is slower than built-in grep perf has). + +PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE + @$(SHELL_PATH) util/PERF-VERSION-GEN +-include PERF-VERSION-FILE + +uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not') +uname_M := $(shell sh -c 'uname -m 2>/dev/null || echo not') +uname_O := $(shell sh -c 'uname -o 2>/dev/null || echo not') +uname_R := $(shell sh -c 'uname -r 2>/dev/null || echo not') +uname_P := $(shell sh -c 'uname -p 2>/dev/null || echo not') +uname_V := $(shell sh -c 'uname -v 2>/dev/null || echo not') + +# If we're on a 64-bit kernel, use -m64 +ifneq ($(patsubst %64,%,$(uname_M)),$(uname_M)) + M64 := -m64 +endif + +# CFLAGS and LDFLAGS are for the users to override from the command line. + +CFLAGS = $(M64) -ggdb3 -Wall -Wstrict-prototypes -Wmissing-declarations -Wmissing-prototypes -std=gnu99 -Wdeclaration-after-statement -Werror -O6 +LDFLAGS = -lpthread -lrt -lelf -lm +ALL_CFLAGS = $(CFLAGS) +ALL_LDFLAGS = $(LDFLAGS) +STRIP ?= strip + +# Among the variables below, these: +# perfexecdir +# template_dir +# mandir +# infodir +# htmldir +# ETC_PERFCONFIG (but not sysconfdir) +# can be specified as a relative path some/where/else; +# this is interpreted as relative to $(prefix) and "perf" at +# runtime figures out where they are based on the path to the executable. +# This can help installing the suite in a relocatable way. + +prefix = $(HOME) +bindir_relative = bin +bindir = $(prefix)/$(bindir_relative) +mandir = share/man +infodir = share/info +perfexecdir = libexec/perf-core +sharedir = $(prefix)/share +template_dir = share/perf-core/templates +htmldir = share/doc/perf-doc +ifeq ($(prefix),/usr) +sysconfdir = /etc +ETC_PERFCONFIG = $(sysconfdir)/perfconfig +else +sysconfdir = $(prefix)/etc +ETC_PERFCONFIG = etc/perfconfig +endif +lib = lib +# DESTDIR= + +export prefix bindir sharedir sysconfdir + +CC = gcc +AR = ar +RM = rm -f +TAR = tar +FIND = find +INSTALL = install +RPMBUILD = rpmbuild +PTHREAD_LIBS = -lpthread + +# sparse is architecture-neutral, which means that we need to tell it +# explicitly what architecture to check for. Fix this up for yours.. +SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__ + + + +### --- END CONFIGURATION SECTION --- + +# Those must not be GNU-specific; they are shared with perl/ which may +# be built by a different compiler. (Note that this is an artifact now +# but it still might be nice to keep that distinction.) +BASIC_CFLAGS = +BASIC_LDFLAGS = + +# Guard against environment variables +BUILTIN_OBJS = +BUILT_INS = +COMPAT_CFLAGS = +COMPAT_OBJS = +LIB_H = +LIB_OBJS = +SCRIPT_PERL = +SCRIPT_SH = +TEST_PROGRAMS = + +# +# No scripts right now: +# + +# SCRIPT_SH += perf-am.sh + +# +# No Perl scripts right now: +# + +# SCRIPT_PERL += perf-add--interactive.perl + +SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \ + $(patsubst %.perl,%,$(SCRIPT_PERL)) + +# Empty... +EXTRA_PROGRAMS = + +# ... and all the rest that could be moved out of bindir to perfexecdir +PROGRAMS += $(EXTRA_PROGRAMS) + +# +# Single 'perf' binary right now: +# +PROGRAMS += perf + +# List built-in command $C whose implementation cmd_$C() is not in +# builtin-$C.o but is linked in as part of some other command. +# +# None right now: +# +# BUILT_INS += perf-init $X + +# what 'all' will build and 'install' will install, in perfexecdir +ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS) + +# what 'all' will build but not install in perfexecdir +OTHER_PROGRAMS = perf$X + +# Set paths to tools early so that they can be used for version tests. +ifndef SHELL_PATH + SHELL_PATH = /bin/sh +endif +ifndef PERL_PATH + PERL_PATH = /usr/bin/perl +endif + +export PERL_PATH + +LIB_FILE=libperf.a + +LIB_H += ../../include/linux/perf_counter.h +LIB_H += perf.h +LIB_H += types.h +LIB_H += util/list.h +LIB_H += util/rbtree.h +LIB_H += util/levenshtein.h +LIB_H += util/parse-options.h +LIB_H += util/parse-events.h +LIB_H += util/quote.h +LIB_H += util/util.h +LIB_H += util/help.h +LIB_H += util/strbuf.h +LIB_H += util/string.h +LIB_H += util/run-command.h +LIB_H += util/sigchain.h +LIB_H += util/symbol.h +LIB_H += util/color.h + +LIB_OBJS += util/abspath.o +LIB_OBJS += util/alias.o +LIB_OBJS += util/config.o +LIB_OBJS += util/ctype.o +LIB_OBJS += util/environment.o +LIB_OBJS += util/exec_cmd.o +LIB_OBJS += util/help.o +LIB_OBJS += util/levenshtein.o +LIB_OBJS += util/parse-options.o +LIB_OBJS += util/parse-events.o +LIB_OBJS += util/path.o +LIB_OBJS += util/rbtree.o +LIB_OBJS += util/run-command.o +LIB_OBJS += util/quote.o +LIB_OBJS += util/strbuf.o +LIB_OBJS += util/string.o +LIB_OBJS += util/usage.o +LIB_OBJS += util/wrapper.o +LIB_OBJS += util/sigchain.o +LIB_OBJS += util/symbol.o +LIB_OBJS += util/color.o +LIB_OBJS += util/pager.o + +BUILTIN_OBJS += builtin-annotate.o +BUILTIN_OBJS += builtin-help.o +BUILTIN_OBJS += builtin-list.o +BUILTIN_OBJS += builtin-record.o +BUILTIN_OBJS += builtin-report.o +BUILTIN_OBJS += builtin-stat.o +BUILTIN_OBJS += builtin-top.o + +PERFLIBS = $(LIB_FILE) +EXTLIBS = + +# +# Platform specific tweaks +# + +# We choose to avoid "if .. else if .. else .. endif endif" +# because maintaining the nesting to match is a pain. If +# we had "elif" things would have been much nicer... + +-include config.mak.autogen +-include config.mak + +ifeq ($(uname_S),Darwin) + ifndef NO_FINK + ifeq ($(shell test -d /sw/lib && echo y),y) + BASIC_CFLAGS += -I/sw/include + BASIC_LDFLAGS += -L/sw/lib + endif + endif + ifndef NO_DARWIN_PORTS + ifeq ($(shell test -d /opt/local/lib && echo y),y) + BASIC_CFLAGS += -I/opt/local/include + BASIC_LDFLAGS += -L/opt/local/lib + endif + endif + PTHREAD_LIBS = +endif + +ifndef CC_LD_DYNPATH + ifdef NO_R_TO_GCC_LINKER + # Some gcc does not accept and pass -R to the linker to specify + # the runtime dynamic library path. + CC_LD_DYNPATH = -Wl,-rpath, + else + CC_LD_DYNPATH = -R + endif +endif + +ifdef ZLIB_PATH + BASIC_CFLAGS += -I$(ZLIB_PATH)/include + EXTLIBS += -L$(ZLIB_PATH)/$(lib) $(CC_LD_DYNPATH)$(ZLIB_PATH)/$(lib) +endif +EXTLIBS += -lz + +ifdef NEEDS_SOCKET + EXTLIBS += -lsocket +endif +ifdef NEEDS_NSL + EXTLIBS += -lnsl +endif +ifdef NO_D_TYPE_IN_DIRENT + BASIC_CFLAGS += -DNO_D_TYPE_IN_DIRENT +endif +ifdef NO_D_INO_IN_DIRENT + BASIC_CFLAGS += -DNO_D_INO_IN_DIRENT +endif +ifdef NO_ST_BLOCKS_IN_STRUCT_STAT + BASIC_CFLAGS += -DNO_ST_BLOCKS_IN_STRUCT_STAT +endif +ifdef USE_NSEC + BASIC_CFLAGS += -DUSE_NSEC +endif +ifdef USE_ST_TIMESPEC + BASIC_CFLAGS += -DUSE_ST_TIMESPEC +endif +ifdef NO_NSEC + BASIC_CFLAGS += -DNO_NSEC +endif +ifdef NO_C99_FORMAT + BASIC_CFLAGS += -DNO_C99_FORMAT +endif +ifdef SNPRINTF_RETURNS_BOGUS + COMPAT_CFLAGS += -DSNPRINTF_RETURNS_BOGUS + COMPAT_OBJS += compat/snprintf.o +endif +ifdef FREAD_READS_DIRECTORIES + COMPAT_CFLAGS += -DFREAD_READS_DIRECTORIES + COMPAT_OBJS += compat/fopen.o +endif +ifdef NO_SYMLINK_HEAD + BASIC_CFLAGS += -DNO_SYMLINK_HEAD +endif +ifdef NO_STRCASESTR + COMPAT_CFLAGS += -DNO_STRCASESTR + COMPAT_OBJS += compat/strcasestr.o +endif +ifdef NO_STRTOUMAX + COMPAT_CFLAGS += -DNO_STRTOUMAX + COMPAT_OBJS += compat/strtoumax.o +endif +ifdef NO_STRTOULL + COMPAT_CFLAGS += -DNO_STRTOULL +endif +ifdef NO_SETENV + COMPAT_CFLAGS += -DNO_SETENV + COMPAT_OBJS += compat/setenv.o +endif +ifdef NO_MKDTEMP + COMPAT_CFLAGS += -DNO_MKDTEMP + COMPAT_OBJS += compat/mkdtemp.o +endif +ifdef NO_UNSETENV + COMPAT_CFLAGS += -DNO_UNSETENV + COMPAT_OBJS += compat/unsetenv.o +endif +ifdef NO_SYS_SELECT_H + BASIC_CFLAGS += -DNO_SYS_SELECT_H +endif +ifdef NO_MMAP + COMPAT_CFLAGS += -DNO_MMAP + COMPAT_OBJS += compat/mmap.o +else + ifdef USE_WIN32_MMAP + COMPAT_CFLAGS += -DUSE_WIN32_MMAP + COMPAT_OBJS += compat/win32mmap.o + endif +endif +ifdef NO_PREAD + COMPAT_CFLAGS += -DNO_PREAD + COMPAT_OBJS += compat/pread.o +endif +ifdef NO_FAST_WORKING_DIRECTORY + BASIC_CFLAGS += -DNO_FAST_WORKING_DIRECTORY +endif +ifdef NO_TRUSTABLE_FILEMODE + BASIC_CFLAGS += -DNO_TRUSTABLE_FILEMODE +endif +ifdef NO_IPV6 + BASIC_CFLAGS += -DNO_IPV6 +endif +ifdef NO_UINTMAX_T + BASIC_CFLAGS += -Duintmax_t=uint32_t +endif +ifdef NO_SOCKADDR_STORAGE +ifdef NO_IPV6 + BASIC_CFLAGS += -Dsockaddr_storage=sockaddr_in +else + BASIC_CFLAGS += -Dsockaddr_storage=sockaddr_in6 +endif +endif +ifdef NO_INET_NTOP + LIB_OBJS += compat/inet_ntop.o +endif +ifdef NO_INET_PTON + LIB_OBJS += compat/inet_pton.o +endif + +ifdef NO_ICONV + BASIC_CFLAGS += -DNO_ICONV +endif + +ifdef OLD_ICONV + BASIC_CFLAGS += -DOLD_ICONV +endif + +ifdef NO_DEFLATE_BOUND + BASIC_CFLAGS += -DNO_DEFLATE_BOUND +endif + +ifdef PPC_SHA1 + SHA1_HEADER = "ppc/sha1.h" + LIB_OBJS += ppc/sha1.o ppc/sha1ppc.o +else +ifdef ARM_SHA1 + SHA1_HEADER = "arm/sha1.h" + LIB_OBJS += arm/sha1.o arm/sha1_arm.o +else +ifdef MOZILLA_SHA1 + SHA1_HEADER = "mozilla-sha1/sha1.h" + LIB_OBJS += mozilla-sha1/sha1.o +else + SHA1_HEADER = + EXTLIBS += $(LIB_4_CRYPTO) +endif +endif +endif +ifdef NO_PERL_MAKEMAKER + export NO_PERL_MAKEMAKER +endif +ifdef NO_HSTRERROR + COMPAT_CFLAGS += -DNO_HSTRERROR + COMPAT_OBJS += compat/hstrerror.o +endif +ifdef NO_MEMMEM + COMPAT_CFLAGS += -DNO_MEMMEM + COMPAT_OBJS += compat/memmem.o +endif +ifdef INTERNAL_QSORT + COMPAT_CFLAGS += -DINTERNAL_QSORT + COMPAT_OBJS += compat/qsort.o +endif +ifdef RUNTIME_PREFIX + COMPAT_CFLAGS += -DRUNTIME_PREFIX +endif + +ifdef DIR_HAS_BSD_GROUP_SEMANTICS + COMPAT_CFLAGS += -DDIR_HAS_BSD_GROUP_SEMANTICS +endif +ifdef NO_EXTERNAL_GREP + BASIC_CFLAGS += -DNO_EXTERNAL_GREP +endif + +ifeq ($(PERL_PATH),) +NO_PERL=NoThanks +endif + +QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir +QUIET_SUBDIR1 = + +ifneq ($(findstring $(MAKEFLAGS),w),w) +PRINT_DIR = --no-print-directory +else # "make -w" +NO_SUBDIR = : +endif + +ifneq ($(findstring $(MAKEFLAGS),s),s) +ifndef V + QUIET_CC = @echo ' ' CC $@; + QUIET_AR = @echo ' ' AR $@; + QUIET_LINK = @echo ' ' LINK $@; + QUIET_BUILT_IN = @echo ' ' BUILTIN $@; + QUIET_GEN = @echo ' ' GEN $@; + QUIET_SUBDIR0 = +@subdir= + QUIET_SUBDIR1 = ;$(NO_SUBDIR) echo ' ' SUBDIR $$subdir; \ + $(MAKE) $(PRINT_DIR) -C $$subdir + export V + export QUIET_GEN + export QUIET_BUILT_IN +endif +endif + +ifdef ASCIIDOC8 + export ASCIIDOC8 +endif + +# Shell quote (do not use $(call) to accommodate ancient setups); + +SHA1_HEADER_SQ = $(subst ','\'',$(SHA1_HEADER)) +ETC_PERFCONFIG_SQ = $(subst ','\'',$(ETC_PERFCONFIG)) + +DESTDIR_SQ = $(subst ','\'',$(DESTDIR)) +bindir_SQ = $(subst ','\'',$(bindir)) +bindir_relative_SQ = $(subst ','\'',$(bindir_relative)) +mandir_SQ = $(subst ','\'',$(mandir)) +infodir_SQ = $(subst ','\'',$(infodir)) +perfexecdir_SQ = $(subst ','\'',$(perfexecdir)) +template_dir_SQ = $(subst ','\'',$(template_dir)) +htmldir_SQ = $(subst ','\'',$(htmldir)) +prefix_SQ = $(subst ','\'',$(prefix)) + +SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) +PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH)) + +LIBS = $(PERFLIBS) $(EXTLIBS) + +BASIC_CFLAGS += -DSHA1_HEADER='$(SHA1_HEADER_SQ)' \ + $(COMPAT_CFLAGS) +LIB_OBJS += $(COMPAT_OBJS) + +ALL_CFLAGS += $(BASIC_CFLAGS) +ALL_LDFLAGS += $(BASIC_LDFLAGS) + +export TAR INSTALL DESTDIR SHELL_PATH + + +### Build rules + +SHELL = $(SHELL_PATH) + +all:: shell_compatibility_test $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) PERF-BUILD-OPTIONS +ifneq (,$X) + $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) perf$X)), test '$p' -ef '$p$X' || $(RM) '$p';) +endif + +all:: + +please_set_SHELL_PATH_to_a_more_modern_shell: + @$$(:) + +shell_compatibility_test: please_set_SHELL_PATH_to_a_more_modern_shell + +strip: $(PROGRAMS) perf$X + $(STRIP) $(STRIP_OPTS) $(PROGRAMS) perf$X + +perf.o: perf.c common-cmds.h PERF-CFLAGS + $(QUIET_CC)$(CC) -DPERF_VERSION='"$(PERF_VERSION)"' \ + '-DPERF_HTML_PATH="$(htmldir_SQ)"' \ + $(ALL_CFLAGS) -c $(filter %.c,$^) + +perf$X: perf.o $(BUILTIN_OBJS) $(PERFLIBS) + $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ perf.o \ + $(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS) + +builtin-help.o: builtin-help.c common-cmds.h PERF-CFLAGS + $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) \ + '-DPERF_HTML_PATH="$(htmldir_SQ)"' \ + '-DPERF_MAN_PATH="$(mandir_SQ)"' \ + '-DPERF_INFO_PATH="$(infodir_SQ)"' $< + +$(BUILT_INS): perf$X + $(QUIET_BUILT_IN)$(RM) $@ && \ + ln perf$X $@ 2>/dev/null || \ + ln -s perf$X $@ 2>/dev/null || \ + cp perf$X $@ + +common-cmds.h: util/generate-cmdlist.sh command-list.txt + +common-cmds.h: $(wildcard Documentation/perf-*.txt) + $(QUIET_GEN)util/generate-cmdlist.sh > $@+ && mv $@+ $@ + +$(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh + $(QUIET_GEN)$(RM) $@ $@+ && \ + sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \ + -e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \ + -e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \ + -e 's/@@PERF_VERSION@@/$(PERF_VERSION)/g' \ + -e 's/@@NO_CURL@@/$(NO_CURL)/g' \ + $@.sh >$@+ && \ + chmod +x $@+ && \ + mv $@+ $@ + +configure: configure.ac + $(QUIET_GEN)$(RM) $@ $<+ && \ + sed -e 's/@@PERF_VERSION@@/$(PERF_VERSION)/g' \ + $< > $<+ && \ + autoconf -o $@ $<+ && \ + $(RM) $<+ + +# These can record PERF_VERSION +perf.o perf.spec \ + $(patsubst %.sh,%,$(SCRIPT_SH)) \ + $(patsubst %.perl,%,$(SCRIPT_PERL)) \ + : PERF-VERSION-FILE + +%.o: %.c PERF-CFLAGS + $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) $< +%.s: %.c PERF-CFLAGS + $(QUIET_CC)$(CC) -S $(ALL_CFLAGS) $< +%.o: %.S + $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) $< + +util/exec_cmd.o: util/exec_cmd.c PERF-CFLAGS + $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) \ + '-DPERF_EXEC_PATH="$(perfexecdir_SQ)"' \ + '-DBINDIR="$(bindir_relative_SQ)"' \ + '-DPREFIX="$(prefix_SQ)"' \ + $< + +builtin-init-db.o: builtin-init-db.c PERF-CFLAGS + $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DDEFAULT_PERF_TEMPLATE_DIR='"$(template_dir_SQ)"' $< + +util/config.o: util/config.c PERF-CFLAGS + $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< + +perf-%$X: %.o $(PERFLIBS) + $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) + +$(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H) +$(patsubst perf-%$X,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h) +builtin-revert.o wt-status.o: wt-status.h + +$(LIB_FILE): $(LIB_OBJS) + $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS) + +doc: + $(MAKE) -C Documentation all + +man: + $(MAKE) -C Documentation man + +html: + $(MAKE) -C Documentation html + +info: + $(MAKE) -C Documentation info + +pdf: + $(MAKE) -C Documentation pdf + +TAGS: + $(RM) TAGS + $(FIND) . -name '*.[hcS]' -print | xargs etags -a + +tags: + $(RM) tags + $(FIND) . -name '*.[hcS]' -print | xargs ctags -a + +cscope: + $(RM) cscope* + $(FIND) . -name '*.[hcS]' -print | xargs cscope -b + +### Detect prefix changes +TRACK_CFLAGS = $(subst ','\'',$(ALL_CFLAGS)):\ + $(bindir_SQ):$(perfexecdir_SQ):$(template_dir_SQ):$(prefix_SQ) + +PERF-CFLAGS: .FORCE-PERF-CFLAGS + @FLAGS='$(TRACK_CFLAGS)'; \ + if test x"$$FLAGS" != x"`cat PERF-CFLAGS 2>/dev/null`" ; then \ + echo 1>&2 " * new build flags or prefix"; \ + echo "$$FLAGS" >PERF-CFLAGS; \ + fi + +# We need to apply sq twice, once to protect from the shell +# that runs PERF-BUILD-OPTIONS, and then again to protect it +# and the first level quoting from the shell that runs "echo". +PERF-BUILD-OPTIONS: .FORCE-PERF-BUILD-OPTIONS + @echo SHELL_PATH=\''$(subst ','\'',$(SHELL_PATH_SQ))'\' >$@ + @echo TAR=\''$(subst ','\'',$(subst ','\'',$(TAR)))'\' >>$@ + @echo NO_CURL=\''$(subst ','\'',$(subst ','\'',$(NO_CURL)))'\' >>$@ + @echo NO_PERL=\''$(subst ','\'',$(subst ','\'',$(NO_PERL)))'\' >>$@ + +### Testing rules + +# +# None right now: +# +# TEST_PROGRAMS += test-something$X + +all:: $(TEST_PROGRAMS) + +# GNU make supports exporting all variables by "export" without parameters. +# However, the environment gets quite big, and some programs have problems +# with that. + +export NO_SVN_TESTS + +check: common-cmds.h + if sparse; \ + then \ + for i in *.c */*.c; \ + do \ + sparse $(ALL_CFLAGS) $(SPARSE_FLAGS) $$i || exit; \ + done; \ + else \ + echo 2>&1 "Did you mean 'make test'?"; \ + exit 1; \ + fi + +remove-dashes: + ./fixup-builtins $(BUILT_INS) $(PROGRAMS) $(SCRIPTS) + +### Installation rules + +ifneq ($(filter /%,$(firstword $(template_dir))),) +template_instdir = $(template_dir) +else +template_instdir = $(prefix)/$(template_dir) +endif +export template_instdir + +ifneq ($(filter /%,$(firstword $(perfexecdir))),) +perfexec_instdir = $(perfexecdir) +else +perfexec_instdir = $(prefix)/$(perfexecdir) +endif +perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir)) +export perfexec_instdir + +install: all + $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)' + $(INSTALL) perf$X '$(DESTDIR_SQ)$(bindir_SQ)' +ifdef BUILT_INS + $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' + $(INSTALL) $(BUILT_INS) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' +ifneq (,$X) + $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) perf$X)), $(RM) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/$p';) +endif +endif + +install-doc: + $(MAKE) -C Documentation install + +install-man: + $(MAKE) -C Documentation install-man + +install-html: + $(MAKE) -C Documentation install-html + +install-info: + $(MAKE) -C Documentation install-info + +install-pdf: + $(MAKE) -C Documentation install-pdf + +quick-install-doc: + $(MAKE) -C Documentation quick-install + +quick-install-man: + $(MAKE) -C Documentation quick-install-man + +quick-install-html: + $(MAKE) -C Documentation quick-install-html + + +### Maintainer's dist rules +# +# None right now +# +# +# perf.spec: perf.spec.in +# sed -e 's/@@VERSION@@/$(PERF_VERSION)/g' < $< > $@+ +# mv $@+ $@ +# +# PERF_TARNAME=perf-$(PERF_VERSION) +# dist: perf.spec perf-archive$(X) configure +# ./perf-archive --format=tar \ +# --prefix=$(PERF_TARNAME)/ HEAD^{tree} > $(PERF_TARNAME).tar +# @mkdir -p $(PERF_TARNAME) +# @cp perf.spec configure $(PERF_TARNAME) +# @echo $(PERF_VERSION) > $(PERF_TARNAME)/version +# $(TAR) rf $(PERF_TARNAME).tar \ +# $(PERF_TARNAME)/perf.spec \ +# $(PERF_TARNAME)/configure \ +# $(PERF_TARNAME)/version +# @$(RM) -r $(PERF_TARNAME) +# gzip -f -9 $(PERF_TARNAME).tar +# +# htmldocs = perf-htmldocs-$(PERF_VERSION) +# manpages = perf-manpages-$(PERF_VERSION) +# dist-doc: +# $(RM) -r .doc-tmp-dir +# mkdir .doc-tmp-dir +# $(MAKE) -C Documentation WEBDOC_DEST=../.doc-tmp-dir install-webdoc +# cd .doc-tmp-dir && $(TAR) cf ../$(htmldocs).tar . +# gzip -n -9 -f $(htmldocs).tar +# : +# $(RM) -r .doc-tmp-dir +# mkdir -p .doc-tmp-dir/man1 .doc-tmp-dir/man5 .doc-tmp-dir/man7 +# $(MAKE) -C Documentation DESTDIR=./ \ +# man1dir=../.doc-tmp-dir/man1 \ +# man5dir=../.doc-tmp-dir/man5 \ +# man7dir=../.doc-tmp-dir/man7 \ +# install +# cd .doc-tmp-dir && $(TAR) cf ../$(manpages).tar . +# gzip -n -9 -f $(manpages).tar +# $(RM) -r .doc-tmp-dir +# +# rpm: dist +# $(RPMBUILD) -ta $(PERF_TARNAME).tar.gz + +### Cleaning rules + +distclean: clean +# $(RM) configure + +clean: + $(RM) *.o */*.o $(LIB_FILE) + $(RM) $(ALL_PROGRAMS) $(BUILT_INS) perf$X + $(RM) $(TEST_PROGRAMS) + $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo common-cmds.h TAGS tags cscope* + $(RM) -r autom4te.cache + $(RM) config.log config.mak.autogen config.mak.append config.status config.cache + $(RM) -r $(PERF_TARNAME) .doc-tmp-dir + $(RM) $(PERF_TARNAME).tar.gz perf-core_$(PERF_VERSION)-*.tar.gz + $(RM) $(htmldocs).tar.gz $(manpages).tar.gz + $(MAKE) -C Documentation/ clean + $(RM) PERF-VERSION-FILE PERF-CFLAGS PERF-BUILD-OPTIONS + +.PHONY: all install clean strip +.PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell +.PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS +.PHONY: .FORCE-PERF-BUILD-OPTIONS + +### Make sure built-ins do not have dups and listed in perf.c +# +check-builtins:: + ./check-builtins.sh + +### Test suite coverage testing +# +# None right now +# +# .PHONY: coverage coverage-clean coverage-build coverage-report +# +# coverage: +# $(MAKE) coverage-build +# $(MAKE) coverage-report +# +# coverage-clean: +# rm -f *.gcda *.gcno +# +# COVERAGE_CFLAGS = $(CFLAGS) -O0 -ftest-coverage -fprofile-arcs +# COVERAGE_LDFLAGS = $(CFLAGS) -O0 -lgcov +# +# coverage-build: coverage-clean +# $(MAKE) CFLAGS="$(COVERAGE_CFLAGS)" LDFLAGS="$(COVERAGE_LDFLAGS)" all +# $(MAKE) CFLAGS="$(COVERAGE_CFLAGS)" LDFLAGS="$(COVERAGE_LDFLAGS)" \ +# -j1 test +# +# coverage-report: +# gcov -b *.c */*.c +# grep '^function.*called 0 ' *.c.gcov */*.c.gcov \ +# | sed -e 's/\([^:]*\)\.gcov: *function \([^ ]*\) called.*/\1: \2/' \ +# | tee coverage-untested-functions diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c new file mode 100644 index 000000000000..7e58e3ad1508 --- /dev/null +++ b/tools/perf/builtin-annotate.c @@ -0,0 +1,1522 @@ +/* + * builtin-annotate.c + * + * Builtin annotate command: Analyze the perf.data input file, + * look up and read DSOs and symbol information and display + * a histogram of results, along various sorting keys. + */ +#include "builtin.h" + +#include "util/util.h" + +#include "util/color.h" +#include "util/list.h" +#include "util/cache.h" +#include "util/rbtree.h" +#include "util/symbol.h" +#include "util/string.h" + +#include "perf.h" + +#include "util/parse-options.h" +#include "util/parse-events.h" + +#define SHOW_KERNEL 1 +#define SHOW_USER 2 +#define SHOW_HV 4 + +#define MIN_GREEN 0.5 +#define MIN_RED 5.0 + + +static char const *input_name = "perf.data"; +static char *vmlinux = "vmlinux"; + +static char default_sort_order[] = "comm,symbol"; +static char *sort_order = default_sort_order; + +static int input; +static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV; + +static int dump_trace = 0; +#define dprintf(x...) do { if (dump_trace) printf(x); } while (0) + +static int verbose; + +static int print_line; + +static unsigned long page_size; +static unsigned long mmap_window = 32; + +struct ip_event { + struct perf_event_header header; + u64 ip; + u32 pid, tid; +}; + +struct mmap_event { + struct perf_event_header header; + u32 pid, tid; + u64 start; + u64 len; + u64 pgoff; + char filename[PATH_MAX]; +}; + +struct comm_event { + struct perf_event_header header; + u32 pid, tid; + char comm[16]; +}; + +struct fork_event { + struct perf_event_header header; + u32 pid, ppid; +}; + +struct period_event { + struct perf_event_header header; + u64 time; + u64 id; + u64 sample_period; +}; + +typedef union event_union { + struct perf_event_header header; + struct ip_event ip; + struct mmap_event mmap; + struct comm_event comm; + struct fork_event fork; + struct period_event period; +} event_t; + + +struct sym_ext { + struct rb_node node; + double percent; + char *path; +}; + +static LIST_HEAD(dsos); +static struct dso *kernel_dso; +static struct dso *vdso; + + +static void dsos__add(struct dso *dso) +{ + list_add_tail(&dso->node, &dsos); +} + +static struct dso *dsos__find(const char *name) +{ + struct dso *pos; + + list_for_each_entry(pos, &dsos, node) + if (strcmp(pos->name, name) == 0) + return pos; + return NULL; +} + +static struct dso *dsos__findnew(const char *name) +{ + struct dso *dso = dsos__find(name); + int nr; + + if (dso) + return dso; + + dso = dso__new(name, 0); + if (!dso) + goto out_delete_dso; + + nr = dso__load(dso, NULL, verbose); + if (nr < 0) { + if (verbose) + fprintf(stderr, "Failed to open: %s\n", name); + goto out_delete_dso; + } + if (!nr && verbose) { + fprintf(stderr, + "No symbols found in: %s, maybe install a debug package?\n", + name); + } + + dsos__add(dso); + + return dso; + +out_delete_dso: + dso__delete(dso); + return NULL; +} + +static void dsos__fprintf(FILE *fp) +{ + struct dso *pos; + + list_for_each_entry(pos, &dsos, node) + dso__fprintf(pos, fp); +} + +static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip) +{ + return dso__find_symbol(kernel_dso, ip); +} + +static int load_kernel(void) +{ + int err; + + kernel_dso = dso__new("[kernel]", 0); + if (!kernel_dso) + return -1; + + err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose); + if (err) { + dso__delete(kernel_dso); + kernel_dso = NULL; + } else + dsos__add(kernel_dso); + + vdso = dso__new("[vdso]", 0); + if (!vdso) + return -1; + + vdso->find_symbol = vdso__find_symbol; + + dsos__add(vdso); + + return err; +} + +struct map { + struct list_head node; + u64 start; + u64 end; + u64 pgoff; + u64 (*map_ip)(struct map *, u64); + struct dso *dso; +}; + +static u64 map__map_ip(struct map *map, u64 ip) +{ + return ip - map->start + map->pgoff; +} + +static u64 vdso__map_ip(struct map *map, u64 ip) +{ + return ip; +} + +static struct map *map__new(struct mmap_event *event) +{ + struct map *self = malloc(sizeof(*self)); + + if (self != NULL) { + const char *filename = event->filename; + + self->start = event->start; + self->end = event->start + event->len; + self->pgoff = event->pgoff; + + self->dso = dsos__findnew(filename); + if (self->dso == NULL) + goto out_delete; + + if (self->dso == vdso) + self->map_ip = vdso__map_ip; + else + self->map_ip = map__map_ip; + } + return self; +out_delete: + free(self); + return NULL; +} + +static struct map *map__clone(struct map *self) +{ + struct map *map = malloc(sizeof(*self)); + + if (!map) + return NULL; + + memcpy(map, self, sizeof(*self)); + + return map; +} + +static int map__overlap(struct map *l, struct map *r) +{ + if (l->start > r->start) { + struct map *t = l; + l = r; + r = t; + } + + if (l->end > r->start) + return 1; + + return 0; +} + +static size_t map__fprintf(struct map *self, FILE *fp) +{ + return fprintf(fp, " %Lx-%Lx %Lx %s\n", + self->start, self->end, self->pgoff, self->dso->name); +} + + +struct thread { + struct rb_node rb_node; + struct list_head maps; + pid_t pid; + char *comm; +}; + +static struct thread *thread__new(pid_t pid) +{ + struct thread *self = malloc(sizeof(*self)); + + if (self != NULL) { + self->pid = pid; + self->comm = malloc(32); + if (self->comm) + snprintf(self->comm, 32, ":%d", self->pid); + INIT_LIST_HEAD(&self->maps); + } + + return self; +} + +static int thread__set_comm(struct thread *self, const char *comm) +{ + if (self->comm) + free(self->comm); + self->comm = strdup(comm); + return self->comm ? 0 : -ENOMEM; +} + +static size_t thread__fprintf(struct thread *self, FILE *fp) +{ + struct map *pos; + size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm); + + list_for_each_entry(pos, &self->maps, node) + ret += map__fprintf(pos, fp); + + return ret; +} + + +static struct rb_root threads; +static struct thread *last_match; + +static struct thread *threads__findnew(pid_t pid) +{ + struct rb_node **p = &threads.rb_node; + struct rb_node *parent = NULL; + struct thread *th; + + /* + * Font-end cache - PID lookups come in blocks, + * so most of the time we dont have to look up + * the full rbtree: + */ + if (last_match && last_match->pid == pid) + return last_match; + + while (*p != NULL) { + parent = *p; + th = rb_entry(parent, struct thread, rb_node); + + if (th->pid == pid) { + last_match = th; + return th; + } + + if (pid < th->pid) + p = &(*p)->rb_left; + else + p = &(*p)->rb_right; + } + + th = thread__new(pid); + if (th != NULL) { + rb_link_node(&th->rb_node, parent, p); + rb_insert_color(&th->rb_node, &threads); + last_match = th; + } + + return th; +} + +static void thread__insert_map(struct thread *self, struct map *map) +{ + struct map *pos, *tmp; + + list_for_each_entry_safe(pos, tmp, &self->maps, node) { + if (map__overlap(pos, map)) { + list_del_init(&pos->node); + /* XXX leaks dsos */ + free(pos); + } + } + + list_add_tail(&map->node, &self->maps); +} + +static int thread__fork(struct thread *self, struct thread *parent) +{ + struct map *map; + + if (self->comm) + free(self->comm); + self->comm = strdup(parent->comm); + if (!self->comm) + return -ENOMEM; + + list_for_each_entry(map, &parent->maps, node) { + struct map *new = map__clone(map); + if (!new) + return -ENOMEM; + thread__insert_map(self, new); + } + + return 0; +} + +static struct map *thread__find_map(struct thread *self, u64 ip) +{ + struct map *pos; + + if (self == NULL) + return NULL; + + list_for_each_entry(pos, &self->maps, node) + if (ip >= pos->start && ip <= pos->end) + return pos; + + return NULL; +} + +static size_t threads__fprintf(FILE *fp) +{ + size_t ret = 0; + struct rb_node *nd; + + for (nd = rb_first(&threads); nd; nd = rb_next(nd)) { + struct thread *pos = rb_entry(nd, struct thread, rb_node); + + ret += thread__fprintf(pos, fp); + } + + return ret; +} + +/* + * histogram, sorted on item, collects counts + */ + +static struct rb_root hist; + +struct hist_entry { + struct rb_node rb_node; + + struct thread *thread; + struct map *map; + struct dso *dso; + struct symbol *sym; + u64 ip; + char level; + + uint32_t count; +}; + +/* + * configurable sorting bits + */ + +struct sort_entry { + struct list_head list; + + char *header; + + int64_t (*cmp)(struct hist_entry *, struct hist_entry *); + int64_t (*collapse)(struct hist_entry *, struct hist_entry *); + size_t (*print)(FILE *fp, struct hist_entry *); +}; + +/* --sort pid */ + +static int64_t +sort__thread_cmp(struct hist_entry *left, struct hist_entry *right) +{ + return right->thread->pid - left->thread->pid; +} + +static size_t +sort__thread_print(FILE *fp, struct hist_entry *self) +{ + return fprintf(fp, "%16s:%5d", self->thread->comm ?: "", self->thread->pid); +} + +static struct sort_entry sort_thread = { + .header = " Command: Pid", + .cmp = sort__thread_cmp, + .print = sort__thread_print, +}; + +/* --sort comm */ + +static int64_t +sort__comm_cmp(struct hist_entry *left, struct hist_entry *right) +{ + return right->thread->pid - left->thread->pid; +} + +static int64_t +sort__comm_collapse(struct hist_entry *left, struct hist_entry *right) +{ + char *comm_l = left->thread->comm; + char *comm_r = right->thread->comm; + + if (!comm_l || !comm_r) { + if (!comm_l && !comm_r) + return 0; + else if (!comm_l) + return -1; + else + return 1; + } + + return strcmp(comm_l, comm_r); +} + +static size_t +sort__comm_print(FILE *fp, struct hist_entry *self) +{ + return fprintf(fp, "%16s", self->thread->comm); +} + +static struct sort_entry sort_comm = { + .header = " Command", + .cmp = sort__comm_cmp, + .collapse = sort__comm_collapse, + .print = sort__comm_print, +}; + +/* --sort dso */ + +static int64_t +sort__dso_cmp(struct hist_entry *left, struct hist_entry *right) +{ + struct dso *dso_l = left->dso; + struct dso *dso_r = right->dso; + + if (!dso_l || !dso_r) { + if (!dso_l && !dso_r) + return 0; + else if (!dso_l) + return -1; + else + return 1; + } + + return strcmp(dso_l->name, dso_r->name); +} + +static size_t +sort__dso_print(FILE *fp, struct hist_entry *self) +{ + if (self->dso) + return fprintf(fp, "%-25s", self->dso->name); + + return fprintf(fp, "%016llx ", (u64)self->ip); +} + +static struct sort_entry sort_dso = { + .header = "Shared Object ", + .cmp = sort__dso_cmp, + .print = sort__dso_print, +}; + +/* --sort symbol */ + +static int64_t +sort__sym_cmp(struct hist_entry *left, struct hist_entry *right) +{ + u64 ip_l, ip_r; + + if (left->sym == right->sym) + return 0; + + ip_l = left->sym ? left->sym->start : left->ip; + ip_r = right->sym ? right->sym->start : right->ip; + + return (int64_t)(ip_r - ip_l); +} + +static size_t +sort__sym_print(FILE *fp, struct hist_entry *self) +{ + size_t ret = 0; + + if (verbose) + ret += fprintf(fp, "%#018llx ", (u64)self->ip); + + if (self->sym) { + ret += fprintf(fp, "[%c] %s", + self->dso == kernel_dso ? 'k' : '.', self->sym->name); + } else { + ret += fprintf(fp, "%#016llx", (u64)self->ip); + } + + return ret; +} + +static struct sort_entry sort_sym = { + .header = "Symbol", + .cmp = sort__sym_cmp, + .print = sort__sym_print, +}; + +static int sort__need_collapse = 0; + +struct sort_dimension { + char *name; + struct sort_entry *entry; + int taken; +}; + +static struct sort_dimension sort_dimensions[] = { + { .name = "pid", .entry = &sort_thread, }, + { .name = "comm", .entry = &sort_comm, }, + { .name = "dso", .entry = &sort_dso, }, + { .name = "symbol", .entry = &sort_sym, }, +}; + +static LIST_HEAD(hist_entry__sort_list); + +static int sort_dimension__add(char *tok) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) { + struct sort_dimension *sd = &sort_dimensions[i]; + + if (sd->taken) + continue; + + if (strncasecmp(tok, sd->name, strlen(tok))) + continue; + + if (sd->entry->collapse) + sort__need_collapse = 1; + + list_add_tail(&sd->entry->list, &hist_entry__sort_list); + sd->taken = 1; + + return 0; + } + + return -ESRCH; +} + +static int64_t +hist_entry__cmp(struct hist_entry *left, struct hist_entry *right) +{ + struct sort_entry *se; + int64_t cmp = 0; + + list_for_each_entry(se, &hist_entry__sort_list, list) { + cmp = se->cmp(left, right); + if (cmp) + break; + } + + return cmp; +} + +static int64_t +hist_entry__collapse(struct hist_entry *left, struct hist_entry *right) +{ + struct sort_entry *se; + int64_t cmp = 0; + + list_for_each_entry(se, &hist_entry__sort_list, list) { + int64_t (*f)(struct hist_entry *, struct hist_entry *); + + f = se->collapse ?: se->cmp; + + cmp = f(left, right); + if (cmp) + break; + } + + return cmp; +} + +/* + * collect histogram counts + */ +static void hist_hit(struct hist_entry *he, u64 ip) +{ + unsigned int sym_size, offset; + struct symbol *sym = he->sym; + + he->count++; + + if (!sym || !sym->hist) + return; + + sym_size = sym->end - sym->start; + offset = ip - sym->start; + + if (offset >= sym_size) + return; + + sym->hist_sum++; + sym->hist[offset]++; + + if (verbose >= 3) + printf("%p %s: count++ [ip: %p, %08Lx] => %Ld\n", + (void *)(unsigned long)he->sym->start, + he->sym->name, + (void *)(unsigned long)ip, ip - he->sym->start, + sym->hist[offset]); +} + +static int +hist_entry__add(struct thread *thread, struct map *map, struct dso *dso, + struct symbol *sym, u64 ip, char level) +{ + struct rb_node **p = &hist.rb_node; + struct rb_node *parent = NULL; + struct hist_entry *he; + struct hist_entry entry = { + .thread = thread, + .map = map, + .dso = dso, + .sym = sym, + .ip = ip, + .level = level, + .count = 1, + }; + int cmp; + + while (*p != NULL) { + parent = *p; + he = rb_entry(parent, struct hist_entry, rb_node); + + cmp = hist_entry__cmp(&entry, he); + + if (!cmp) { + hist_hit(he, ip); + + return 0; + } + + if (cmp < 0) + p = &(*p)->rb_left; + else + p = &(*p)->rb_right; + } + + he = malloc(sizeof(*he)); + if (!he) + return -ENOMEM; + *he = entry; + rb_link_node(&he->rb_node, parent, p); + rb_insert_color(&he->rb_node, &hist); + + return 0; +} + +static void hist_entry__free(struct hist_entry *he) +{ + free(he); +} + +/* + * collapse the histogram + */ + +static struct rb_root collapse_hists; + +static void collapse__insert_entry(struct hist_entry *he) +{ + struct rb_node **p = &collapse_hists.rb_node; + struct rb_node *parent = NULL; + struct hist_entry *iter; + int64_t cmp; + + while (*p != NULL) { + parent = *p; + iter = rb_entry(parent, struct hist_entry, rb_node); + + cmp = hist_entry__collapse(iter, he); + + if (!cmp) { + iter->count += he->count; + hist_entry__free(he); + return; + } + + if (cmp < 0) + p = &(*p)->rb_left; + else + p = &(*p)->rb_right; + } + + rb_link_node(&he->rb_node, parent, p); + rb_insert_color(&he->rb_node, &collapse_hists); +} + +static void collapse__resort(void) +{ + struct rb_node *next; + struct hist_entry *n; + + if (!sort__need_collapse) + return; + + next = rb_first(&hist); + while (next) { + n = rb_entry(next, struct hist_entry, rb_node); + next = rb_next(&n->rb_node); + + rb_erase(&n->rb_node, &hist); + collapse__insert_entry(n); + } +} + +/* + * reverse the map, sort on count. + */ + +static struct rb_root output_hists; + +static void output__insert_entry(struct hist_entry *he) +{ + struct rb_node **p = &output_hists.rb_node; + struct rb_node *parent = NULL; + struct hist_entry *iter; + + while (*p != NULL) { + parent = *p; + iter = rb_entry(parent, struct hist_entry, rb_node); + + if (he->count > iter->count) + p = &(*p)->rb_left; + else + p = &(*p)->rb_right; + } + + rb_link_node(&he->rb_node, parent, p); + rb_insert_color(&he->rb_node, &output_hists); +} + +static void output__resort(void) +{ + struct rb_node *next; + struct hist_entry *n; + struct rb_root *tree = &hist; + + if (sort__need_collapse) + tree = &collapse_hists; + + next = rb_first(tree); + + while (next) { + n = rb_entry(next, struct hist_entry, rb_node); + next = rb_next(&n->rb_node); + + rb_erase(&n->rb_node, tree); + output__insert_entry(n); + } +} + +static void register_idle_thread(void) +{ + struct thread *thread = threads__findnew(0); + + if (thread == NULL || + thread__set_comm(thread, "[idle]")) { + fprintf(stderr, "problem inserting idle task.\n"); + exit(-1); + } +} + +static unsigned long total = 0, + total_mmap = 0, + total_comm = 0, + total_fork = 0, + total_unknown = 0; + +static int +process_overflow_event(event_t *event, unsigned long offset, unsigned long head) +{ + char level; + int show = 0; + struct dso *dso = NULL; + struct thread *thread = threads__findnew(event->ip.pid); + u64 ip = event->ip.ip; + struct map *map = NULL; + + dprintf("%p [%p]: PERF_EVENT (IP, %d): %d: %p\n", + (void *)(offset + head), + (void *)(long)(event->header.size), + event->header.misc, + event->ip.pid, + (void *)(long)ip); + + dprintf(" ... thread: %s:%d\n", thread->comm, thread->pid); + + if (thread == NULL) { + fprintf(stderr, "problem processing %d event, skipping it.\n", + event->header.type); + return -1; + } + + if (event->header.misc & PERF_EVENT_MISC_KERNEL) { + show = SHOW_KERNEL; + level = 'k'; + + dso = kernel_dso; + + dprintf(" ...... dso: %s\n", dso->name); + + } else if (event->header.misc & PERF_EVENT_MISC_USER) { + + show = SHOW_USER; + level = '.'; + + map = thread__find_map(thread, ip); + if (map != NULL) { + ip = map->map_ip(map, ip); + dso = map->dso; + } else { + /* + * If this is outside of all known maps, + * and is a negative address, try to look it + * up in the kernel dso, as it might be a + * vsyscall (which executes in user-mode): + */ + if ((long long)ip < 0) + dso = kernel_dso; + } + dprintf(" ...... dso: %s\n", dso ? dso->name : ""); + + } else { + show = SHOW_HV; + level = 'H'; + dprintf(" ...... dso: [hypervisor]\n"); + } + + if (show & show_mask) { + struct symbol *sym = NULL; + + if (dso) + sym = dso->find_symbol(dso, ip); + + if (hist_entry__add(thread, map, dso, sym, ip, level)) { + fprintf(stderr, + "problem incrementing symbol count, skipping event\n"); + return -1; + } + } + total++; + + return 0; +} + +static int +process_mmap_event(event_t *event, unsigned long offset, unsigned long head) +{ + struct thread *thread = threads__findnew(event->mmap.pid); + struct map *map = map__new(&event->mmap); + + dprintf("%p [%p]: PERF_EVENT_MMAP %d: [%p(%p) @ %p]: %s\n", + (void *)(offset + head), + (void *)(long)(event->header.size), + event->mmap.pid, + (void *)(long)event->mmap.start, + (void *)(long)event->mmap.len, + (void *)(long)event->mmap.pgoff, + event->mmap.filename); + + if (thread == NULL || map == NULL) { + dprintf("problem processing PERF_EVENT_MMAP, skipping event.\n"); + return 0; + } + + thread__insert_map(thread, map); + total_mmap++; + + return 0; +} + +static int +process_comm_event(event_t *event, unsigned long offset, unsigned long head) +{ + struct thread *thread = threads__findnew(event->comm.pid); + + dprintf("%p [%p]: PERF_EVENT_COMM: %s:%d\n", + (void *)(offset + head), + (void *)(long)(event->header.size), + event->comm.comm, event->comm.pid); + + if (thread == NULL || + thread__set_comm(thread, event->comm.comm)) { + dprintf("problem processing PERF_EVENT_COMM, skipping event.\n"); + return -1; + } + total_comm++; + + return 0; +} + +static int +process_fork_event(event_t *event, unsigned long offset, unsigned long head) +{ + struct thread *thread = threads__findnew(event->fork.pid); + struct thread *parent = threads__findnew(event->fork.ppid); + + dprintf("%p [%p]: PERF_EVENT_FORK: %d:%d\n", + (void *)(offset + head), + (void *)(long)(event->header.size), + event->fork.pid, event->fork.ppid); + + if (!thread || !parent || thread__fork(thread, parent)) { + dprintf("problem processing PERF_EVENT_FORK, skipping event.\n"); + return -1; + } + total_fork++; + + return 0; +} + +static int +process_period_event(event_t *event, unsigned long offset, unsigned long head) +{ + dprintf("%p [%p]: PERF_EVENT_PERIOD: time:%Ld, id:%Ld: period:%Ld\n", + (void *)(offset + head), + (void *)(long)(event->header.size), + event->period.time, + event->period.id, + event->period.sample_period); + + return 0; +} + +static int +process_event(event_t *event, unsigned long offset, unsigned long head) +{ + if (event->header.misc & PERF_EVENT_MISC_OVERFLOW) + return process_overflow_event(event, offset, head); + + switch (event->header.type) { + case PERF_EVENT_MMAP: + return process_mmap_event(event, offset, head); + + case PERF_EVENT_COMM: + return process_comm_event(event, offset, head); + + case PERF_EVENT_FORK: + return process_fork_event(event, offset, head); + + case PERF_EVENT_PERIOD: + return process_period_event(event, offset, head); + /* + * We dont process them right now but they are fine: + */ + + case PERF_EVENT_THROTTLE: + case PERF_EVENT_UNTHROTTLE: + return 0; + + default: + return -1; + } + + return 0; +} + +static char *get_color(double percent) +{ + char *color = PERF_COLOR_NORMAL; + + /* + * We color high-overhead entries in red, mid-overhead + * entries in green - and keep the low overhead places + * normal: + */ + if (percent >= MIN_RED) + color = PERF_COLOR_RED; + else { + if (percent > MIN_GREEN) + color = PERF_COLOR_GREEN; + } + return color; +} + +static int +parse_line(FILE *file, struct symbol *sym, u64 start, u64 len) +{ + char *line = NULL, *tmp, *tmp2; + static const char *prev_line; + static const char *prev_color; + unsigned int offset; + size_t line_len; + u64 line_ip; + int ret; + char *c; + + if (getline(&line, &line_len, file) < 0) + return -1; + if (!line) + return -1; + + c = strchr(line, '\n'); + if (c) + *c = 0; + + line_ip = -1; + offset = 0; + ret = -2; + + /* + * Strip leading spaces: + */ + tmp = line; + while (*tmp) { + if (*tmp != ' ') + break; + tmp++; + } + + if (*tmp) { + /* + * Parse hexa addresses followed by ':' + */ + line_ip = strtoull(tmp, &tmp2, 16); + if (*tmp2 != ':') + line_ip = -1; + } + + if (line_ip != -1) { + const char *path = NULL; + unsigned int hits = 0; + double percent = 0.0; + char *color; + struct sym_ext *sym_ext = sym->priv; + + offset = line_ip - start; + if (offset < len) + hits = sym->hist[offset]; + + if (offset < len && sym_ext) { + path = sym_ext[offset].path; + percent = sym_ext[offset].percent; + } else if (sym->hist_sum) + percent = 100.0 * hits / sym->hist_sum; + + color = get_color(percent); + + /* + * Also color the filename and line if needed, with + * the same color than the percentage. Don't print it + * twice for close colored ip with the same filename:line + */ + if (path) { + if (!prev_line || strcmp(prev_line, path) + || color != prev_color) { + color_fprintf(stdout, color, " %s", path); + prev_line = path; + prev_color = color; + } + } + + color_fprintf(stdout, color, " %7.2f", percent); + printf(" : "); + color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", line); + } else { + if (!*line) + printf(" :\n"); + else + printf(" : %s\n", line); + } + + return 0; +} + +static struct rb_root root_sym_ext; + +static void insert_source_line(struct sym_ext *sym_ext) +{ + struct sym_ext *iter; + struct rb_node **p = &root_sym_ext.rb_node; + struct rb_node *parent = NULL; + + while (*p != NULL) { + parent = *p; + iter = rb_entry(parent, struct sym_ext, node); + + if (sym_ext->percent > iter->percent) + p = &(*p)->rb_left; + else + p = &(*p)->rb_right; + } + + rb_link_node(&sym_ext->node, parent, p); + rb_insert_color(&sym_ext->node, &root_sym_ext); +} + +static void free_source_line(struct symbol *sym, int len) +{ + struct sym_ext *sym_ext = sym->priv; + int i; + + if (!sym_ext) + return; + + for (i = 0; i < len; i++) + free(sym_ext[i].path); + free(sym_ext); + + sym->priv = NULL; + root_sym_ext = RB_ROOT; +} + +/* Get the filename:line for the colored entries */ +static void +get_source_line(struct symbol *sym, u64 start, int len, char *filename) +{ + int i; + char cmd[PATH_MAX * 2]; + struct sym_ext *sym_ext; + + if (!sym->hist_sum) + return; + + sym->priv = calloc(len, sizeof(struct sym_ext)); + if (!sym->priv) + return; + + sym_ext = sym->priv; + + for (i = 0; i < len; i++) { + char *path = NULL; + size_t line_len; + u64 offset; + FILE *fp; + + sym_ext[i].percent = 100.0 * sym->hist[i] / sym->hist_sum; + if (sym_ext[i].percent <= 0.5) + continue; + + offset = start + i; + sprintf(cmd, "addr2line -e %s %016llx", filename, offset); + fp = popen(cmd, "r"); + if (!fp) + continue; + + if (getline(&path, &line_len, fp) < 0 || !line_len) + goto next; + + sym_ext[i].path = malloc(sizeof(char) * line_len + 1); + if (!sym_ext[i].path) + goto next; + + strcpy(sym_ext[i].path, path); + insert_source_line(&sym_ext[i]); + + next: + pclose(fp); + } +} + +static void print_summary(char *filename) +{ + struct sym_ext *sym_ext; + struct rb_node *node; + + printf("\nSorted summary for file %s\n", filename); + printf("----------------------------------------------\n\n"); + + if (RB_EMPTY_ROOT(&root_sym_ext)) { + printf(" Nothing higher than %1.1f%%\n", MIN_GREEN); + return; + } + + node = rb_first(&root_sym_ext); + while (node) { + double percent; + char *color; + char *path; + + sym_ext = rb_entry(node, struct sym_ext, node); + percent = sym_ext->percent; + color = get_color(percent); + path = sym_ext->path; + + color_fprintf(stdout, color, " %7.2f %s", percent, path); + node = rb_next(node); + } +} + +static void annotate_sym(struct dso *dso, struct symbol *sym) +{ + char *filename = dso->name; + u64 start, end, len; + char command[PATH_MAX*2]; + FILE *file; + + if (!filename) + return; + if (dso == kernel_dso) + filename = vmlinux; + + start = sym->obj_start; + if (!start) + start = sym->start; + + end = start + sym->end - sym->start + 1; + len = sym->end - sym->start; + + if (print_line) { + get_source_line(sym, start, len, filename); + print_summary(filename); + } + + printf("\n\n------------------------------------------------\n"); + printf(" Percent | Source code & Disassembly of %s\n", filename); + printf("------------------------------------------------\n"); + + if (verbose >= 2) + printf("annotating [%p] %30s : [%p] %30s\n", dso, dso->name, sym, sym->name); + + sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s", (u64)start, (u64)end, filename); + + if (verbose >= 3) + printf("doing: %s\n", command); + + file = popen(command, "r"); + if (!file) + return; + + while (!feof(file)) { + if (parse_line(file, sym, start, len) < 0) + break; + } + + pclose(file); + if (print_line) + free_source_line(sym, len); +} + +static void find_annotations(void) +{ + struct rb_node *nd; + struct dso *dso; + int count = 0; + + list_for_each_entry(dso, &dsos, node) { + + for (nd = rb_first(&dso->syms); nd; nd = rb_next(nd)) { + struct symbol *sym = rb_entry(nd, struct symbol, rb_node); + + if (sym->hist) { + annotate_sym(dso, sym); + count++; + } + } + } + + if (!count) + printf(" Error: symbol '%s' not present amongst the samples.\n", sym_hist_filter); +} + +static int __cmd_annotate(void) +{ + int ret, rc = EXIT_FAILURE; + unsigned long offset = 0; + unsigned long head = 0; + struct stat stat; + event_t *event; + uint32_t size; + char *buf; + + register_idle_thread(); + + input = open(input_name, O_RDONLY); + if (input < 0) { + perror("failed to open file"); + exit(-1); + } + + ret = fstat(input, &stat); + if (ret < 0) { + perror("failed to stat file"); + exit(-1); + } + + if (!stat.st_size) { + fprintf(stderr, "zero-sized file, nothing to do!\n"); + exit(0); + } + + if (load_kernel() < 0) { + perror("failed to load kernel symbols"); + return EXIT_FAILURE; + } + +remap: + buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ, + MAP_SHARED, input, offset); + if (buf == MAP_FAILED) { + perror("failed to mmap file"); + exit(-1); + } + +more: + event = (event_t *)(buf + head); + + size = event->header.size; + if (!size) + size = 8; + + if (head + event->header.size >= page_size * mmap_window) { + unsigned long shift = page_size * (head / page_size); + int ret; + + ret = munmap(buf, page_size * mmap_window); + assert(ret == 0); + + offset += shift; + head -= shift; + goto remap; + } + + size = event->header.size; + + dprintf("%p [%p]: event: %d\n", + (void *)(offset + head), + (void *)(long)event->header.size, + event->header.type); + + if (!size || process_event(event, offset, head) < 0) { + + dprintf("%p [%p]: skipping unknown header type: %d\n", + (void *)(offset + head), + (void *)(long)(event->header.size), + event->header.type); + + total_unknown++; + + /* + * assume we lost track of the stream, check alignment, and + * increment a single u64 in the hope to catch on again 'soon'. + */ + + if (unlikely(head & 7)) + head &= ~7ULL; + + size = 8; + } + + head += size; + + if (offset + head < stat.st_size) + goto more; + + rc = EXIT_SUCCESS; + close(input); + + dprintf(" IP events: %10ld\n", total); + dprintf(" mmap events: %10ld\n", total_mmap); + dprintf(" comm events: %10ld\n", total_comm); + dprintf(" fork events: %10ld\n", total_fork); + dprintf(" unknown events: %10ld\n", total_unknown); + + if (dump_trace) + return 0; + + if (verbose >= 3) + threads__fprintf(stdout); + + if (verbose >= 2) + dsos__fprintf(stdout); + + collapse__resort(); + output__resort(); + + find_annotations(); + + return rc; +} + +static const char * const annotate_usage[] = { + "perf annotate [] ", + NULL +}; + +static const struct option options[] = { + OPT_STRING('i', "input", &input_name, "file", + "input file name"), + OPT_STRING('s', "symbol", &sym_hist_filter, "symbol", + "symbol to annotate"), + OPT_BOOLEAN('v', "verbose", &verbose, + "be more verbose (show symbol address, etc)"), + OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, + "dump raw trace in ASCII"), + OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"), + OPT_BOOLEAN('l', "print-line", &print_line, + "print matching source lines (may be slow)"), + OPT_END() +}; + +static void setup_sorting(void) +{ + char *tmp, *tok, *str = strdup(sort_order); + + for (tok = strtok_r(str, ", ", &tmp); + tok; tok = strtok_r(NULL, ", ", &tmp)) { + if (sort_dimension__add(tok) < 0) { + error("Unknown --sort key: `%s'", tok); + usage_with_options(annotate_usage, options); + } + } + + free(str); +} + +int cmd_annotate(int argc, const char **argv, const char *prefix) +{ + symbol__init(); + + page_size = getpagesize(); + + argc = parse_options(argc, argv, options, annotate_usage, 0); + + setup_sorting(); + + if (argc) { + /* + * Special case: if there's an argument left then assume tha + * it's a symbol filter: + */ + if (argc > 1) + usage_with_options(annotate_usage, options); + + sym_hist_filter = argv[0]; + } + + if (!sym_hist_filter) + usage_with_options(annotate_usage, options); + + setup_pager(); + + return __cmd_annotate(); +} diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c new file mode 100644 index 000000000000..0f32dc3f3c4c --- /dev/null +++ b/tools/perf/builtin-help.c @@ -0,0 +1,461 @@ +/* + * builtin-help.c + * + * Builtin help command + */ +#include "util/cache.h" +#include "builtin.h" +#include "util/exec_cmd.h" +#include "common-cmds.h" +#include "util/parse-options.h" +#include "util/run-command.h" +#include "util/help.h" + +static struct man_viewer_list { + struct man_viewer_list *next; + char name[FLEX_ARRAY]; +} *man_viewer_list; + +static struct man_viewer_info_list { + struct man_viewer_info_list *next; + const char *info; + char name[FLEX_ARRAY]; +} *man_viewer_info_list; + +enum help_format { + HELP_FORMAT_MAN, + HELP_FORMAT_INFO, + HELP_FORMAT_WEB, +}; + +static int show_all = 0; +static enum help_format help_format = HELP_FORMAT_MAN; +static struct option builtin_help_options[] = { + OPT_BOOLEAN('a', "all", &show_all, "print all available commands"), + OPT_SET_INT('m', "man", &help_format, "show man page", HELP_FORMAT_MAN), + OPT_SET_INT('w', "web", &help_format, "show manual in web browser", + HELP_FORMAT_WEB), + OPT_SET_INT('i', "info", &help_format, "show info page", + HELP_FORMAT_INFO), + OPT_END(), +}; + +static const char * const builtin_help_usage[] = { + "perf help [--all] [--man|--web|--info] [command]", + NULL +}; + +static enum help_format parse_help_format(const char *format) +{ + if (!strcmp(format, "man")) + return HELP_FORMAT_MAN; + if (!strcmp(format, "info")) + return HELP_FORMAT_INFO; + if (!strcmp(format, "web") || !strcmp(format, "html")) + return HELP_FORMAT_WEB; + die("unrecognized help format '%s'", format); +} + +static const char *get_man_viewer_info(const char *name) +{ + struct man_viewer_info_list *viewer; + + for (viewer = man_viewer_info_list; viewer; viewer = viewer->next) + { + if (!strcasecmp(name, viewer->name)) + return viewer->info; + } + return NULL; +} + +static int check_emacsclient_version(void) +{ + struct strbuf buffer = STRBUF_INIT; + struct child_process ec_process; + const char *argv_ec[] = { "emacsclient", "--version", NULL }; + int version; + + /* emacsclient prints its version number on stderr */ + memset(&ec_process, 0, sizeof(ec_process)); + ec_process.argv = argv_ec; + ec_process.err = -1; + ec_process.stdout_to_stderr = 1; + if (start_command(&ec_process)) { + fprintf(stderr, "Failed to start emacsclient.\n"); + return -1; + } + strbuf_read(&buffer, ec_process.err, 20); + close(ec_process.err); + + /* + * Don't bother checking return value, because "emacsclient --version" + * seems to always exits with code 1. + */ + finish_command(&ec_process); + + if (prefixcmp(buffer.buf, "emacsclient")) { + fprintf(stderr, "Failed to parse emacsclient version.\n"); + strbuf_release(&buffer); + return -1; + } + + strbuf_remove(&buffer, 0, strlen("emacsclient")); + version = atoi(buffer.buf); + + if (version < 22) { + fprintf(stderr, + "emacsclient version '%d' too old (< 22).\n", + version); + strbuf_release(&buffer); + return -1; + } + + strbuf_release(&buffer); + return 0; +} + +static void exec_woman_emacs(const char* path, const char *page) +{ + if (!check_emacsclient_version()) { + /* This works only with emacsclient version >= 22. */ + struct strbuf man_page = STRBUF_INIT; + + if (!path) + path = "emacsclient"; + strbuf_addf(&man_page, "(woman \"%s\")", page); + execlp(path, "emacsclient", "-e", man_page.buf, NULL); + warning("failed to exec '%s': %s", path, strerror(errno)); + } +} + +static void exec_man_konqueror(const char* path, const char *page) +{ + const char *display = getenv("DISPLAY"); + if (display && *display) { + struct strbuf man_page = STRBUF_INIT; + const char *filename = "kfmclient"; + + /* It's simpler to launch konqueror using kfmclient. */ + if (path) { + const char *file = strrchr(path, '/'); + if (file && !strcmp(file + 1, "konqueror")) { + char *new = strdup(path); + char *dest = strrchr(new, '/'); + + /* strlen("konqueror") == strlen("kfmclient") */ + strcpy(dest + 1, "kfmclient"); + path = new; + } + if (file) + filename = file; + } else + path = "kfmclient"; + strbuf_addf(&man_page, "man:%s(1)", page); + execlp(path, filename, "newTab", man_page.buf, NULL); + warning("failed to exec '%s': %s", path, strerror(errno)); + } +} + +static void exec_man_man(const char* path, const char *page) +{ + if (!path) + path = "man"; + execlp(path, "man", page, NULL); + warning("failed to exec '%s': %s", path, strerror(errno)); +} + +static void exec_man_cmd(const char *cmd, const char *page) +{ + struct strbuf shell_cmd = STRBUF_INIT; + strbuf_addf(&shell_cmd, "%s %s", cmd, page); + execl("/bin/sh", "sh", "-c", shell_cmd.buf, NULL); + warning("failed to exec '%s': %s", cmd, strerror(errno)); +} + +static void add_man_viewer(const char *name) +{ + struct man_viewer_list **p = &man_viewer_list; + size_t len = strlen(name); + + while (*p) + p = &((*p)->next); + *p = calloc(1, (sizeof(**p) + len + 1)); + strncpy((*p)->name, name, len); +} + +static int supported_man_viewer(const char *name, size_t len) +{ + return (!strncasecmp("man", name, len) || + !strncasecmp("woman", name, len) || + !strncasecmp("konqueror", name, len)); +} + +static void do_add_man_viewer_info(const char *name, + size_t len, + const char *value) +{ + struct man_viewer_info_list *new = calloc(1, sizeof(*new) + len + 1); + + strncpy(new->name, name, len); + new->info = strdup(value); + new->next = man_viewer_info_list; + man_viewer_info_list = new; +} + +static int add_man_viewer_path(const char *name, + size_t len, + const char *value) +{ + if (supported_man_viewer(name, len)) + do_add_man_viewer_info(name, len, value); + else + warning("'%s': path for unsupported man viewer.\n" + "Please consider using 'man..cmd' instead.", + name); + + return 0; +} + +static int add_man_viewer_cmd(const char *name, + size_t len, + const char *value) +{ + if (supported_man_viewer(name, len)) + warning("'%s': cmd for supported man viewer.\n" + "Please consider using 'man..path' instead.", + name); + else + do_add_man_viewer_info(name, len, value); + + return 0; +} + +static int add_man_viewer_info(const char *var, const char *value) +{ + const char *name = var + 4; + const char *subkey = strrchr(name, '.'); + + if (!subkey) + return error("Config with no key for man viewer: %s", name); + + if (!strcmp(subkey, ".path")) { + if (!value) + return config_error_nonbool(var); + return add_man_viewer_path(name, subkey - name, value); + } + if (!strcmp(subkey, ".cmd")) { + if (!value) + return config_error_nonbool(var); + return add_man_viewer_cmd(name, subkey - name, value); + } + + warning("'%s': unsupported man viewer sub key.", subkey); + return 0; +} + +static int perf_help_config(const char *var, const char *value, void *cb) +{ + if (!strcmp(var, "help.format")) { + if (!value) + return config_error_nonbool(var); + help_format = parse_help_format(value); + return 0; + } + if (!strcmp(var, "man.viewer")) { + if (!value) + return config_error_nonbool(var); + add_man_viewer(value); + return 0; + } + if (!prefixcmp(var, "man.")) + return add_man_viewer_info(var, value); + + return perf_default_config(var, value, cb); +} + +static struct cmdnames main_cmds, other_cmds; + +void list_common_cmds_help(void) +{ + int i, longest = 0; + + for (i = 0; i < ARRAY_SIZE(common_cmds); i++) { + if (longest < strlen(common_cmds[i].name)) + longest = strlen(common_cmds[i].name); + } + + puts(" The most commonly used perf commands are:"); + for (i = 0; i < ARRAY_SIZE(common_cmds); i++) { + printf(" %s ", common_cmds[i].name); + mput_char(' ', longest - strlen(common_cmds[i].name)); + puts(common_cmds[i].help); + } +} + +static int is_perf_command(const char *s) +{ + return is_in_cmdlist(&main_cmds, s) || + is_in_cmdlist(&other_cmds, s); +} + +static const char *prepend(const char *prefix, const char *cmd) +{ + size_t pre_len = strlen(prefix); + size_t cmd_len = strlen(cmd); + char *p = malloc(pre_len + cmd_len + 1); + memcpy(p, prefix, pre_len); + strcpy(p + pre_len, cmd); + return p; +} + +static const char *cmd_to_page(const char *perf_cmd) +{ + if (!perf_cmd) + return "perf"; + else if (!prefixcmp(perf_cmd, "perf")) + return perf_cmd; + else if (is_perf_command(perf_cmd)) + return prepend("perf-", perf_cmd); + else + return prepend("perf-", perf_cmd); +} + +static void setup_man_path(void) +{ + struct strbuf new_path = STRBUF_INIT; + const char *old_path = getenv("MANPATH"); + + /* We should always put ':' after our path. If there is no + * old_path, the ':' at the end will let 'man' to try + * system-wide paths after ours to find the manual page. If + * there is old_path, we need ':' as delimiter. */ + strbuf_addstr(&new_path, system_path(PERF_MAN_PATH)); + strbuf_addch(&new_path, ':'); + if (old_path) + strbuf_addstr(&new_path, old_path); + + setenv("MANPATH", new_path.buf, 1); + + strbuf_release(&new_path); +} + +static void exec_viewer(const char *name, const char *page) +{ + const char *info = get_man_viewer_info(name); + + if (!strcasecmp(name, "man")) + exec_man_man(info, page); + else if (!strcasecmp(name, "woman")) + exec_woman_emacs(info, page); + else if (!strcasecmp(name, "konqueror")) + exec_man_konqueror(info, page); + else if (info) + exec_man_cmd(info, page); + else + warning("'%s': unknown man viewer.", name); +} + +static void show_man_page(const char *perf_cmd) +{ + struct man_viewer_list *viewer; + const char *page = cmd_to_page(perf_cmd); + const char *fallback = getenv("PERF_MAN_VIEWER"); + + setup_man_path(); + for (viewer = man_viewer_list; viewer; viewer = viewer->next) + { + exec_viewer(viewer->name, page); /* will return when unable */ + } + if (fallback) + exec_viewer(fallback, page); + exec_viewer("man", page); + die("no man viewer handled the request"); +} + +static void show_info_page(const char *perf_cmd) +{ + const char *page = cmd_to_page(perf_cmd); + setenv("INFOPATH", system_path(PERF_INFO_PATH), 1); + execlp("info", "info", "perfman", page, NULL); +} + +static void get_html_page_path(struct strbuf *page_path, const char *page) +{ + struct stat st; + const char *html_path = system_path(PERF_HTML_PATH); + + /* Check that we have a perf documentation directory. */ + if (stat(mkpath("%s/perf.html", html_path), &st) + || !S_ISREG(st.st_mode)) + die("'%s': not a documentation directory.", html_path); + + strbuf_init(page_path, 0); + strbuf_addf(page_path, "%s/%s.html", html_path, page); +} + +/* + * If open_html is not defined in a platform-specific way (see for + * example compat/mingw.h), we use the script web--browse to display + * HTML. + */ +#ifndef open_html +static void open_html(const char *path) +{ + execl_perf_cmd("web--browse", "-c", "help.browser", path, NULL); +} +#endif + +static void show_html_page(const char *perf_cmd) +{ + const char *page = cmd_to_page(perf_cmd); + struct strbuf page_path; /* it leaks but we exec bellow */ + + get_html_page_path(&page_path, page); + + open_html(page_path.buf); +} + +int cmd_help(int argc, const char **argv, const char *prefix) +{ + const char *alias; + load_command_list("perf-", &main_cmds, &other_cmds); + + perf_config(perf_help_config, NULL); + + argc = parse_options(argc, argv, builtin_help_options, + builtin_help_usage, 0); + + if (show_all) { + printf("\n usage: %s\n\n", perf_usage_string); + list_commands("perf commands", &main_cmds, &other_cmds); + printf(" %s\n\n", perf_more_info_string); + return 0; + } + + if (!argv[0]) { + printf("\n usage: %s\n\n", perf_usage_string); + list_common_cmds_help(); + printf("\n %s\n\n", perf_more_info_string); + return 0; + } + + alias = alias_lookup(argv[0]); + if (alias && !is_perf_command(argv[0])) { + printf("`perf %s' is aliased to `%s'\n", argv[0], alias); + return 0; + } + + switch (help_format) { + case HELP_FORMAT_MAN: + show_man_page(argv[0]); + break; + case HELP_FORMAT_INFO: + show_info_page(argv[0]); + break; + case HELP_FORMAT_WEB: + show_html_page(argv[0]); + break; + } + + return 0; +} diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c new file mode 100644 index 000000000000..fe60e37c96ef --- /dev/null +++ b/tools/perf/builtin-list.c @@ -0,0 +1,20 @@ +/* + * builtin-list.c + * + * Builtin list command: list all event types + * + * Copyright (C) 2009, Thomas Gleixner + * Copyright (C) 2008-2009, Red Hat Inc, Ingo Molnar + */ +#include "builtin.h" + +#include "perf.h" + +#include "util/parse-options.h" +#include "util/parse-events.h" + +int cmd_list(int argc, const char **argv, const char *prefix) +{ + print_events(); + return 0; +} diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c new file mode 100644 index 000000000000..d7ebbd757543 --- /dev/null +++ b/tools/perf/builtin-record.c @@ -0,0 +1,628 @@ +/* + * builtin-record.c + * + * Builtin record command: Record the profile of a workload + * (or a CPU, or a PID) into the perf.data output file - for + * later analysis via perf report. + */ +#include "builtin.h" + +#include "perf.h" + +#include "util/util.h" +#include "util/parse-options.h" +#include "util/parse-events.h" +#include "util/string.h" + +#include +#include + +#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a)-1) +#define __ALIGN_MASK(x, mask) (((x)+(mask))&~(mask)) + +static int fd[MAX_NR_CPUS][MAX_COUNTERS]; + +static long default_interval = 100000; + +static int nr_cpus = 0; +static unsigned int page_size; +static unsigned int mmap_pages = 128; +static int freq = 0; +static int output; +static const char *output_name = "perf.data"; +static int group = 0; +static unsigned int realtime_prio = 0; +static int system_wide = 0; +static pid_t target_pid = -1; +static int inherit = 1; +static int force = 0; +static int append_file = 0; +static int call_graph = 0; +static int verbose = 0; + +static long samples; +static struct timeval last_read; +static struct timeval this_read; + +static u64 bytes_written; + +static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS]; + +static int nr_poll; +static int nr_cpu; + +static int file_new = 1; +static struct perf_file_header file_header; + +struct mmap_event { + struct perf_event_header header; + u32 pid; + u32 tid; + u64 start; + u64 len; + u64 pgoff; + char filename[PATH_MAX]; +}; + +struct comm_event { + struct perf_event_header header; + u32 pid; + u32 tid; + char comm[16]; +}; + + +struct mmap_data { + int counter; + void *base; + unsigned int mask; + unsigned int prev; +}; + +static struct mmap_data mmap_array[MAX_NR_CPUS][MAX_COUNTERS]; + +static unsigned long mmap_read_head(struct mmap_data *md) +{ + struct perf_counter_mmap_page *pc = md->base; + long head; + + head = pc->data_head; + rmb(); + + return head; +} + +static void mmap_write_tail(struct mmap_data *md, unsigned long tail) +{ + struct perf_counter_mmap_page *pc = md->base; + + /* + * ensure all reads are done before we write the tail out. + */ + /* mb(); */ + pc->data_tail = tail; +} + +static void write_output(void *buf, size_t size) +{ + while (size) { + int ret = write(output, buf, size); + + if (ret < 0) + die("failed to write"); + + size -= ret; + buf += ret; + + bytes_written += ret; + } +} + +static void mmap_read(struct mmap_data *md) +{ + unsigned int head = mmap_read_head(md); + unsigned int old = md->prev; + unsigned char *data = md->base + page_size; + unsigned long size; + void *buf; + int diff; + + gettimeofday(&this_read, NULL); + + /* + * If we're further behind than half the buffer, there's a chance + * the writer will bite our tail and mess up the samples under us. + * + * If we somehow ended up ahead of the head, we got messed up. + * + * In either case, truncate and restart at head. + */ + diff = head - old; + if (diff < 0) { + struct timeval iv; + unsigned long msecs; + + timersub(&this_read, &last_read, &iv); + msecs = iv.tv_sec*1000 + iv.tv_usec/1000; + + fprintf(stderr, "WARNING: failed to keep up with mmap data." + " Last read %lu msecs ago.\n", msecs); + + /* + * head points to a known good entry, start there. + */ + old = head; + } + + last_read = this_read; + + if (old != head) + samples++; + + size = head - old; + + if ((old & md->mask) + size != (head & md->mask)) { + buf = &data[old & md->mask]; + size = md->mask + 1 - (old & md->mask); + old += size; + + write_output(buf, size); + } + + buf = &data[old & md->mask]; + size = head - old; + old += size; + + write_output(buf, size); + + md->prev = old; + mmap_write_tail(md, old); +} + +static volatile int done = 0; +static volatile int signr = -1; + +static void sig_handler(int sig) +{ + done = 1; + signr = sig; +} + +static void sig_atexit(void) +{ + if (signr == -1) + return; + + signal(signr, SIG_DFL); + kill(getpid(), signr); +} + +static void pid_synthesize_comm_event(pid_t pid, int full) +{ + struct comm_event comm_ev; + char filename[PATH_MAX]; + char bf[BUFSIZ]; + int fd; + size_t size; + char *field, *sep; + DIR *tasks; + struct dirent dirent, *next; + + snprintf(filename, sizeof(filename), "/proc/%d/stat", pid); + + fd = open(filename, O_RDONLY); + if (fd < 0) { + /* + * We raced with a task exiting - just return: + */ + if (verbose) + fprintf(stderr, "couldn't open %s\n", filename); + return; + } + if (read(fd, bf, sizeof(bf)) < 0) { + fprintf(stderr, "couldn't read %s\n", filename); + exit(EXIT_FAILURE); + } + close(fd); + + /* 9027 (cat) R 6747 9027 6747 34816 9027 ... */ + memset(&comm_ev, 0, sizeof(comm_ev)); + field = strchr(bf, '('); + if (field == NULL) + goto out_failure; + sep = strchr(++field, ')'); + if (sep == NULL) + goto out_failure; + size = sep - field; + memcpy(comm_ev.comm, field, size++); + + comm_ev.pid = pid; + comm_ev.header.type = PERF_EVENT_COMM; + size = ALIGN(size, sizeof(u64)); + comm_ev.header.size = sizeof(comm_ev) - (sizeof(comm_ev.comm) - size); + + if (!full) { + comm_ev.tid = pid; + + write_output(&comm_ev, comm_ev.header.size); + return; + } + + snprintf(filename, sizeof(filename), "/proc/%d/task", pid); + + tasks = opendir(filename); + while (!readdir_r(tasks, &dirent, &next) && next) { + char *end; + pid = strtol(dirent.d_name, &end, 10); + if (*end) + continue; + + comm_ev.tid = pid; + + write_output(&comm_ev, comm_ev.header.size); + } + closedir(tasks); + return; + +out_failure: + fprintf(stderr, "couldn't get COMM and pgid, malformed %s\n", + filename); + exit(EXIT_FAILURE); +} + +static void pid_synthesize_mmap_samples(pid_t pid) +{ + char filename[PATH_MAX]; + FILE *fp; + + snprintf(filename, sizeof(filename), "/proc/%d/maps", pid); + + fp = fopen(filename, "r"); + if (fp == NULL) { + /* + * We raced with a task exiting - just return: + */ + if (verbose) + fprintf(stderr, "couldn't open %s\n", filename); + return; + } + while (1) { + char bf[BUFSIZ], *pbf = bf; + struct mmap_event mmap_ev = { + .header.type = PERF_EVENT_MMAP, + }; + int n; + size_t size; + if (fgets(bf, sizeof(bf), fp) == NULL) + break; + + /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */ + n = hex2u64(pbf, &mmap_ev.start); + if (n < 0) + continue; + pbf += n + 1; + n = hex2u64(pbf, &mmap_ev.len); + if (n < 0) + continue; + pbf += n + 3; + if (*pbf == 'x') { /* vm_exec */ + char *execname = strrchr(bf, ' '); + + if (execname == NULL || execname[1] != '/') + continue; + + execname += 1; + size = strlen(execname); + execname[size - 1] = '\0'; /* Remove \n */ + memcpy(mmap_ev.filename, execname, size); + size = ALIGN(size, sizeof(u64)); + mmap_ev.len -= mmap_ev.start; + mmap_ev.header.size = (sizeof(mmap_ev) - + (sizeof(mmap_ev.filename) - size)); + mmap_ev.pid = pid; + mmap_ev.tid = pid; + + write_output(&mmap_ev, mmap_ev.header.size); + } + } + + fclose(fp); +} + +static void synthesize_samples(void) +{ + DIR *proc; + struct dirent dirent, *next; + + proc = opendir("/proc"); + + while (!readdir_r(proc, &dirent, &next) && next) { + char *end; + pid_t pid; + + pid = strtol(dirent.d_name, &end, 10); + if (*end) /* only interested in proper numerical dirents */ + continue; + + pid_synthesize_comm_event(pid, 1); + pid_synthesize_mmap_samples(pid); + } + + closedir(proc); +} + +static int group_fd; + +static void create_counter(int counter, int cpu, pid_t pid) +{ + struct perf_counter_attr *attr = attrs + counter; + int track = 1; + + attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; + + if (freq) { + attr->sample_type |= PERF_SAMPLE_PERIOD; + attr->freq = 1; + attr->sample_freq = freq; + } + + if (call_graph) + attr->sample_type |= PERF_SAMPLE_CALLCHAIN; + + if (file_new) { + file_header.sample_type = attr->sample_type; + } else { + if (file_header.sample_type != attr->sample_type) { + fprintf(stderr, "incompatible append\n"); + exit(-1); + } + } + + attr->mmap = track; + attr->comm = track; + attr->inherit = (cpu < 0) && inherit; + attr->disabled = 1; + + track = 0; /* only the first counter needs these */ + +try_again: + fd[nr_cpu][counter] = sys_perf_counter_open(attr, pid, cpu, group_fd, 0); + + if (fd[nr_cpu][counter] < 0) { + int err = errno; + + if (err == EPERM) + die("Permission error - are you root?\n"); + + /* + * If it's cycles then fall back to hrtimer + * based cpu-clock-tick sw counter, which + * is always available even if no PMU support: + */ + if (attr->type == PERF_TYPE_HARDWARE + && attr->config == PERF_COUNT_HW_CPU_CYCLES) { + + if (verbose) + warning(" ... trying to fall back to cpu-clock-ticks\n"); + attr->type = PERF_TYPE_SOFTWARE; + attr->config = PERF_COUNT_SW_CPU_CLOCK; + goto try_again; + } + printf("\n"); + error("perfcounter syscall returned with %d (%s)\n", + fd[nr_cpu][counter], strerror(err)); + die("No CONFIG_PERF_COUNTERS=y kernel support configured?\n"); + exit(-1); + } + + assert(fd[nr_cpu][counter] >= 0); + fcntl(fd[nr_cpu][counter], F_SETFL, O_NONBLOCK); + + /* + * First counter acts as the group leader: + */ + if (group && group_fd == -1) + group_fd = fd[nr_cpu][counter]; + + event_array[nr_poll].fd = fd[nr_cpu][counter]; + event_array[nr_poll].events = POLLIN; + nr_poll++; + + mmap_array[nr_cpu][counter].counter = counter; + mmap_array[nr_cpu][counter].prev = 0; + mmap_array[nr_cpu][counter].mask = mmap_pages*page_size - 1; + mmap_array[nr_cpu][counter].base = mmap(NULL, (mmap_pages+1)*page_size, + PROT_READ|PROT_WRITE, MAP_SHARED, fd[nr_cpu][counter], 0); + if (mmap_array[nr_cpu][counter].base == MAP_FAILED) { + error("failed to mmap with %d (%s)\n", errno, strerror(errno)); + exit(-1); + } + + ioctl(fd[nr_cpu][counter], PERF_COUNTER_IOC_ENABLE); +} + +static void open_counters(int cpu, pid_t pid) +{ + int counter; + + if (pid > 0) { + pid_synthesize_comm_event(pid, 0); + pid_synthesize_mmap_samples(pid); + } + + group_fd = -1; + for (counter = 0; counter < nr_counters; counter++) + create_counter(counter, cpu, pid); + + nr_cpu++; +} + +static void atexit_header(void) +{ + file_header.data_size += bytes_written; + + if (pwrite(output, &file_header, sizeof(file_header), 0) == -1) + perror("failed to write on file headers"); +} + +static int __cmd_record(int argc, const char **argv) +{ + int i, counter; + struct stat st; + pid_t pid; + int flags; + int ret; + + page_size = sysconf(_SC_PAGE_SIZE); + nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); + assert(nr_cpus <= MAX_NR_CPUS); + assert(nr_cpus >= 0); + + atexit(sig_atexit); + signal(SIGCHLD, sig_handler); + signal(SIGINT, sig_handler); + + if (!stat(output_name, &st) && !force && !append_file) { + fprintf(stderr, "Error, output file %s exists, use -A to append or -f to overwrite.\n", + output_name); + exit(-1); + } + + flags = O_CREAT|O_RDWR; + if (append_file) + file_new = 0; + else + flags |= O_TRUNC; + + output = open(output_name, flags, S_IRUSR|S_IWUSR); + if (output < 0) { + perror("failed to create output file"); + exit(-1); + } + + if (!file_new) { + if (read(output, &file_header, sizeof(file_header)) == -1) { + perror("failed to read file headers"); + exit(-1); + } + + lseek(output, file_header.data_size, SEEK_CUR); + } + + atexit(atexit_header); + + if (!system_wide) { + open_counters(-1, target_pid != -1 ? target_pid : getpid()); + } else for (i = 0; i < nr_cpus; i++) + open_counters(i, target_pid); + + if (target_pid == -1 && argc) { + pid = fork(); + if (pid < 0) + perror("failed to fork"); + + if (!pid) { + if (execvp(argv[0], (char **)argv)) { + perror(argv[0]); + exit(-1); + } + } + } + + if (realtime_prio) { + struct sched_param param; + + param.sched_priority = realtime_prio; + if (sched_setscheduler(0, SCHED_FIFO, ¶m)) { + printf("Could not set realtime priority.\n"); + exit(-1); + } + } + + if (system_wide) + synthesize_samples(); + + while (!done) { + int hits = samples; + + for (i = 0; i < nr_cpu; i++) { + for (counter = 0; counter < nr_counters; counter++) + mmap_read(&mmap_array[i][counter]); + } + + if (hits == samples) + ret = poll(event_array, nr_poll, 100); + } + + /* + * Approximate RIP event size: 24 bytes. + */ + fprintf(stderr, + "[ perf record: Captured and wrote %.3f MB %s (~%lld samples) ]\n", + (double)bytes_written / 1024.0 / 1024.0, + output_name, + bytes_written / 24); + + return 0; +} + +static const char * const record_usage[] = { + "perf record [] []", + "perf record [] -- []", + NULL +}; + +static const struct option options[] = { + OPT_CALLBACK('e', "event", NULL, "event", + "event selector. use 'perf list' to list available events", + parse_events), + OPT_INTEGER('p', "pid", &target_pid, + "record events on existing pid"), + OPT_INTEGER('r', "realtime", &realtime_prio, + "collect data with this RT SCHED_FIFO priority"), + OPT_BOOLEAN('a', "all-cpus", &system_wide, + "system-wide collection from all CPUs"), + OPT_BOOLEAN('A', "append", &append_file, + "append to the output file to do incremental profiling"), + OPT_BOOLEAN('f', "force", &force, + "overwrite existing data file"), + OPT_LONG('c', "count", &default_interval, + "event period to sample"), + OPT_STRING('o', "output", &output_name, "file", + "output file name"), + OPT_BOOLEAN('i', "inherit", &inherit, + "child tasks inherit counters"), + OPT_INTEGER('F', "freq", &freq, + "profile at this frequency"), + OPT_INTEGER('m', "mmap-pages", &mmap_pages, + "number of mmap data pages"), + OPT_BOOLEAN('g', "call-graph", &call_graph, + "do call-graph (stack chain/backtrace) recording"), + OPT_BOOLEAN('v', "verbose", &verbose, + "be more verbose (show counter open errors, etc)"), + OPT_END() +}; + +int cmd_record(int argc, const char **argv, const char *prefix) +{ + int counter; + + argc = parse_options(argc, argv, options, record_usage, 0); + if (!argc && target_pid == -1 && !system_wide) + usage_with_options(record_usage, options); + + if (!nr_counters) { + nr_counters = 1; + attrs[0].type = PERF_TYPE_HARDWARE; + attrs[0].config = PERF_COUNT_HW_CPU_CYCLES; + } + + for (counter = 0; counter < nr_counters; counter++) { + if (attrs[counter].sample_period) + continue; + + attrs[counter].sample_period = default_interval; + } + + return __cmd_record(argc, argv); +} diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c new file mode 100644 index 000000000000..5eb5566f0c95 --- /dev/null +++ b/tools/perf/builtin-report.c @@ -0,0 +1,1581 @@ +/* + * builtin-report.c + * + * Builtin report command: Analyze the perf.data input file, + * look up and read DSOs and symbol information and display + * a histogram of results, along various sorting keys. + */ +#include "builtin.h" + +#include "util/util.h" + +#include "util/color.h" +#include "util/list.h" +#include "util/cache.h" +#include "util/rbtree.h" +#include "util/symbol.h" +#include "util/string.h" + +#include "perf.h" + +#include "util/parse-options.h" +#include "util/parse-events.h" + +#define SHOW_KERNEL 1 +#define SHOW_USER 2 +#define SHOW_HV 4 + +static char const *input_name = "perf.data"; +static char *vmlinux = NULL; + +static char default_sort_order[] = "comm,dso"; +static char *sort_order = default_sort_order; + +static int input; +static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV; + +static int dump_trace = 0; +#define dprintf(x...) do { if (dump_trace) printf(x); } while (0) +#define cdprintf(x...) do { if (dump_trace) color_fprintf(stdout, color, x); } while (0) + +static int verbose; +#define eprintf(x...) do { if (verbose) fprintf(stderr, x); } while (0) + +static int full_paths; + +static unsigned long page_size; +static unsigned long mmap_window = 32; + +static char default_parent_pattern[] = "^sys_|^do_page_fault"; +static char *parent_pattern = default_parent_pattern; +static regex_t parent_regex; + +static int exclude_other = 1; + +struct ip_event { + struct perf_event_header header; + u64 ip; + u32 pid, tid; + unsigned char __more_data[]; +}; + +struct ip_callchain { + u64 nr; + u64 ips[0]; +}; + +struct mmap_event { + struct perf_event_header header; + u32 pid, tid; + u64 start; + u64 len; + u64 pgoff; + char filename[PATH_MAX]; +}; + +struct comm_event { + struct perf_event_header header; + u32 pid, tid; + char comm[16]; +}; + +struct fork_event { + struct perf_event_header header; + u32 pid, ppid; +}; + +struct period_event { + struct perf_event_header header; + u64 time; + u64 id; + u64 sample_period; +}; + +struct lost_event { + struct perf_event_header header; + u64 id; + u64 lost; +}; + +typedef union event_union { + struct perf_event_header header; + struct ip_event ip; + struct mmap_event mmap; + struct comm_event comm; + struct fork_event fork; + struct period_event period; + struct lost_event lost; +} event_t; + +static LIST_HEAD(dsos); +static struct dso *kernel_dso; +static struct dso *vdso; + +static void dsos__add(struct dso *dso) +{ + list_add_tail(&dso->node, &dsos); +} + +static struct dso *dsos__find(const char *name) +{ + struct dso *pos; + + list_for_each_entry(pos, &dsos, node) + if (strcmp(pos->name, name) == 0) + return pos; + return NULL; +} + +static struct dso *dsos__findnew(const char *name) +{ + struct dso *dso = dsos__find(name); + int nr; + + if (dso) + return dso; + + dso = dso__new(name, 0); + if (!dso) + goto out_delete_dso; + + nr = dso__load(dso, NULL, verbose); + if (nr < 0) { + eprintf("Failed to open: %s\n", name); + goto out_delete_dso; + } + if (!nr) + eprintf("No symbols found in: %s, maybe install a debug package?\n", name); + + dsos__add(dso); + + return dso; + +out_delete_dso: + dso__delete(dso); + return NULL; +} + +static void dsos__fprintf(FILE *fp) +{ + struct dso *pos; + + list_for_each_entry(pos, &dsos, node) + dso__fprintf(pos, fp); +} + +static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip) +{ + return dso__find_symbol(kernel_dso, ip); +} + +static int load_kernel(void) +{ + int err; + + kernel_dso = dso__new("[kernel]", 0); + if (!kernel_dso) + return -1; + + err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose); + if (err) { + dso__delete(kernel_dso); + kernel_dso = NULL; + } else + dsos__add(kernel_dso); + + vdso = dso__new("[vdso]", 0); + if (!vdso) + return -1; + + vdso->find_symbol = vdso__find_symbol; + + dsos__add(vdso); + + return err; +} + +static char __cwd[PATH_MAX]; +static char *cwd = __cwd; +static int cwdlen; + +static int strcommon(const char *pathname) +{ + int n = 0; + + while (pathname[n] == cwd[n] && n < cwdlen) + ++n; + + return n; +} + +struct map { + struct list_head node; + u64 start; + u64 end; + u64 pgoff; + u64 (*map_ip)(struct map *, u64); + struct dso *dso; +}; + +static u64 map__map_ip(struct map *map, u64 ip) +{ + return ip - map->start + map->pgoff; +} + +static u64 vdso__map_ip(struct map *map, u64 ip) +{ + return ip; +} + +static inline int is_anon_memory(const char *filename) +{ + return strcmp(filename, "//anon") == 0; +} + +static struct map *map__new(struct mmap_event *event) +{ + struct map *self = malloc(sizeof(*self)); + + if (self != NULL) { + const char *filename = event->filename; + char newfilename[PATH_MAX]; + int anon; + + if (cwd) { + int n = strcommon(filename); + + if (n == cwdlen) { + snprintf(newfilename, sizeof(newfilename), + ".%s", filename + n); + filename = newfilename; + } + } + + anon = is_anon_memory(filename); + + if (anon) { + snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", event->pid); + filename = newfilename; + } + + self->start = event->start; + self->end = event->start + event->len; + self->pgoff = event->pgoff; + + self->dso = dsos__findnew(filename); + if (self->dso == NULL) + goto out_delete; + + if (self->dso == vdso || anon) + self->map_ip = vdso__map_ip; + else + self->map_ip = map__map_ip; + } + return self; +out_delete: + free(self); + return NULL; +} + +static struct map *map__clone(struct map *self) +{ + struct map *map = malloc(sizeof(*self)); + + if (!map) + return NULL; + + memcpy(map, self, sizeof(*self)); + + return map; +} + +static int map__overlap(struct map *l, struct map *r) +{ + if (l->start > r->start) { + struct map *t = l; + l = r; + r = t; + } + + if (l->end > r->start) + return 1; + + return 0; +} + +static size_t map__fprintf(struct map *self, FILE *fp) +{ + return fprintf(fp, " %Lx-%Lx %Lx %s\n", + self->start, self->end, self->pgoff, self->dso->name); +} + + +struct thread { + struct rb_node rb_node; + struct list_head maps; + pid_t pid; + char *comm; +}; + +static struct thread *thread__new(pid_t pid) +{ + struct thread *self = malloc(sizeof(*self)); + + if (self != NULL) { + self->pid = pid; + self->comm = malloc(32); + if (self->comm) + snprintf(self->comm, 32, ":%d", self->pid); + INIT_LIST_HEAD(&self->maps); + } + + return self; +} + +static int thread__set_comm(struct thread *self, const char *comm) +{ + if (self->comm) + free(self->comm); + self->comm = strdup(comm); + return self->comm ? 0 : -ENOMEM; +} + +static size_t thread__fprintf(struct thread *self, FILE *fp) +{ + struct map *pos; + size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm); + + list_for_each_entry(pos, &self->maps, node) + ret += map__fprintf(pos, fp); + + return ret; +} + + +static struct rb_root threads; +static struct thread *last_match; + +static struct thread *threads__findnew(pid_t pid) +{ + struct rb_node **p = &threads.rb_node; + struct rb_node *parent = NULL; + struct thread *th; + + /* + * Font-end cache - PID lookups come in blocks, + * so most of the time we dont have to look up + * the full rbtree: + */ + if (last_match && last_match->pid == pid) + return last_match; + + while (*p != NULL) { + parent = *p; + th = rb_entry(parent, struct thread, rb_node); + + if (th->pid == pid) { + last_match = th; + return th; + } + + if (pid < th->pid) + p = &(*p)->rb_left; + else + p = &(*p)->rb_right; + } + + th = thread__new(pid); + if (th != NULL) { + rb_link_node(&th->rb_node, parent, p); + rb_insert_color(&th->rb_node, &threads); + last_match = th; + } + + return th; +} + +static void thread__insert_map(struct thread *self, struct map *map) +{ + struct map *pos, *tmp; + + list_for_each_entry_safe(pos, tmp, &self->maps, node) { + if (map__overlap(pos, map)) { + list_del_init(&pos->node); + /* XXX leaks dsos */ + free(pos); + } + } + + list_add_tail(&map->node, &self->maps); +} + +static int thread__fork(struct thread *self, struct thread *parent) +{ + struct map *map; + + if (self->comm) + free(self->comm); + self->comm = strdup(parent->comm); + if (!self->comm) + return -ENOMEM; + + list_for_each_entry(map, &parent->maps, node) { + struct map *new = map__clone(map); + if (!new) + return -ENOMEM; + thread__insert_map(self, new); + } + + return 0; +} + +static struct map *thread__find_map(struct thread *self, u64 ip) +{ + struct map *pos; + + if (self == NULL) + return NULL; + + list_for_each_entry(pos, &self->maps, node) + if (ip >= pos->start && ip <= pos->end) + return pos; + + return NULL; +} + +static size_t threads__fprintf(FILE *fp) +{ + size_t ret = 0; + struct rb_node *nd; + + for (nd = rb_first(&threads); nd; nd = rb_next(nd)) { + struct thread *pos = rb_entry(nd, struct thread, rb_node); + + ret += thread__fprintf(pos, fp); + } + + return ret; +} + +/* + * histogram, sorted on item, collects counts + */ + +static struct rb_root hist; + +struct hist_entry { + struct rb_node rb_node; + + struct thread *thread; + struct map *map; + struct dso *dso; + struct symbol *sym; + struct symbol *parent; + u64 ip; + char level; + + u64 count; +}; + +/* + * configurable sorting bits + */ + +struct sort_entry { + struct list_head list; + + char *header; + + int64_t (*cmp)(struct hist_entry *, struct hist_entry *); + int64_t (*collapse)(struct hist_entry *, struct hist_entry *); + size_t (*print)(FILE *fp, struct hist_entry *); +}; + +static int64_t cmp_null(void *l, void *r) +{ + if (!l && !r) + return 0; + else if (!l) + return -1; + else + return 1; +} + +/* --sort pid */ + +static int64_t +sort__thread_cmp(struct hist_entry *left, struct hist_entry *right) +{ + return right->thread->pid - left->thread->pid; +} + +static size_t +sort__thread_print(FILE *fp, struct hist_entry *self) +{ + return fprintf(fp, "%16s:%5d", self->thread->comm ?: "", self->thread->pid); +} + +static struct sort_entry sort_thread = { + .header = " Command: Pid", + .cmp = sort__thread_cmp, + .print = sort__thread_print, +}; + +/* --sort comm */ + +static int64_t +sort__comm_cmp(struct hist_entry *left, struct hist_entry *right) +{ + return right->thread->pid - left->thread->pid; +} + +static int64_t +sort__comm_collapse(struct hist_entry *left, struct hist_entry *right) +{ + char *comm_l = left->thread->comm; + char *comm_r = right->thread->comm; + + if (!comm_l || !comm_r) + return cmp_null(comm_l, comm_r); + + return strcmp(comm_l, comm_r); +} + +static size_t +sort__comm_print(FILE *fp, struct hist_entry *self) +{ + return fprintf(fp, "%16s", self->thread->comm); +} + +static struct sort_entry sort_comm = { + .header = " Command", + .cmp = sort__comm_cmp, + .collapse = sort__comm_collapse, + .print = sort__comm_print, +}; + +/* --sort dso */ + +static int64_t +sort__dso_cmp(struct hist_entry *left, struct hist_entry *right) +{ + struct dso *dso_l = left->dso; + struct dso *dso_r = right->dso; + + if (!dso_l || !dso_r) + return cmp_null(dso_l, dso_r); + + return strcmp(dso_l->name, dso_r->name); +} + +static size_t +sort__dso_print(FILE *fp, struct hist_entry *self) +{ + if (self->dso) + return fprintf(fp, "%-25s", self->dso->name); + + return fprintf(fp, "%016llx ", (u64)self->ip); +} + +static struct sort_entry sort_dso = { + .header = "Shared Object ", + .cmp = sort__dso_cmp, + .print = sort__dso_print, +}; + +/* --sort symbol */ + +static int64_t +sort__sym_cmp(struct hist_entry *left, struct hist_entry *right) +{ + u64 ip_l, ip_r; + + if (left->sym == right->sym) + return 0; + + ip_l = left->sym ? left->sym->start : left->ip; + ip_r = right->sym ? right->sym->start : right->ip; + + return (int64_t)(ip_r - ip_l); +} + +static size_t +sort__sym_print(FILE *fp, struct hist_entry *self) +{ + size_t ret = 0; + + if (verbose) + ret += fprintf(fp, "%#018llx ", (u64)self->ip); + + if (self->sym) { + ret += fprintf(fp, "[%c] %s", + self->dso == kernel_dso ? 'k' : '.', self->sym->name); + } else { + ret += fprintf(fp, "%#016llx", (u64)self->ip); + } + + return ret; +} + +static struct sort_entry sort_sym = { + .header = "Symbol", + .cmp = sort__sym_cmp, + .print = sort__sym_print, +}; + +/* --sort parent */ + +static int64_t +sort__parent_cmp(struct hist_entry *left, struct hist_entry *right) +{ + struct symbol *sym_l = left->parent; + struct symbol *sym_r = right->parent; + + if (!sym_l || !sym_r) + return cmp_null(sym_l, sym_r); + + return strcmp(sym_l->name, sym_r->name); +} + +static size_t +sort__parent_print(FILE *fp, struct hist_entry *self) +{ + size_t ret = 0; + + ret += fprintf(fp, "%-20s", self->parent ? self->parent->name : "[other]"); + + return ret; +} + +static struct sort_entry sort_parent = { + .header = "Parent symbol ", + .cmp = sort__parent_cmp, + .print = sort__parent_print, +}; + +static int sort__need_collapse = 0; +static int sort__has_parent = 0; + +struct sort_dimension { + char *name; + struct sort_entry *entry; + int taken; +}; + +static struct sort_dimension sort_dimensions[] = { + { .name = "pid", .entry = &sort_thread, }, + { .name = "comm", .entry = &sort_comm, }, + { .name = "dso", .entry = &sort_dso, }, + { .name = "symbol", .entry = &sort_sym, }, + { .name = "parent", .entry = &sort_parent, }, +}; + +static LIST_HEAD(hist_entry__sort_list); + +static int sort_dimension__add(char *tok) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) { + struct sort_dimension *sd = &sort_dimensions[i]; + + if (sd->taken) + continue; + + if (strncasecmp(tok, sd->name, strlen(tok))) + continue; + + if (sd->entry->collapse) + sort__need_collapse = 1; + + if (sd->entry == &sort_parent) { + int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED); + if (ret) { + char err[BUFSIZ]; + + regerror(ret, &parent_regex, err, sizeof(err)); + fprintf(stderr, "Invalid regex: %s\n%s", + parent_pattern, err); + exit(-1); + } + sort__has_parent = 1; + } + + list_add_tail(&sd->entry->list, &hist_entry__sort_list); + sd->taken = 1; + + return 0; + } + + return -ESRCH; +} + +static int64_t +hist_entry__cmp(struct hist_entry *left, struct hist_entry *right) +{ + struct sort_entry *se; + int64_t cmp = 0; + + list_for_each_entry(se, &hist_entry__sort_list, list) { + cmp = se->cmp(left, right); + if (cmp) + break; + } + + return cmp; +} + +static int64_t +hist_entry__collapse(struct hist_entry *left, struct hist_entry *right) +{ + struct sort_entry *se; + int64_t cmp = 0; + + list_for_each_entry(se, &hist_entry__sort_list, list) { + int64_t (*f)(struct hist_entry *, struct hist_entry *); + + f = se->collapse ?: se->cmp; + + cmp = f(left, right); + if (cmp) + break; + } + + return cmp; +} + +static size_t +hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples) +{ + struct sort_entry *se; + size_t ret; + + if (exclude_other && !self->parent) + return 0; + + if (total_samples) { + double percent = self->count * 100.0 / total_samples; + char *color = PERF_COLOR_NORMAL; + + /* + * We color high-overhead entries in red, mid-overhead + * entries in green - and keep the low overhead places + * normal: + */ + if (percent >= 5.0) { + color = PERF_COLOR_RED; + } else { + if (percent >= 0.5) + color = PERF_COLOR_GREEN; + } + + ret = color_fprintf(fp, color, " %6.2f%%", + (self->count * 100.0) / total_samples); + } else + ret = fprintf(fp, "%12Ld ", self->count); + + list_for_each_entry(se, &hist_entry__sort_list, list) { + if (exclude_other && (se == &sort_parent)) + continue; + + fprintf(fp, " "); + ret += se->print(fp, self); + } + + ret += fprintf(fp, "\n"); + + return ret; +} + +/* + * + */ + +static struct symbol * +resolve_symbol(struct thread *thread, struct map **mapp, + struct dso **dsop, u64 *ipp) +{ + struct dso *dso = dsop ? *dsop : NULL; + struct map *map = mapp ? *mapp : NULL; + uint64_t ip = *ipp; + + if (!thread) + return NULL; + + if (dso) + goto got_dso; + + if (map) + goto got_map; + + map = thread__find_map(thread, ip); + if (map != NULL) { + if (mapp) + *mapp = map; +got_map: + ip = map->map_ip(map, ip); + *ipp = ip; + + dso = map->dso; + } else { + /* + * If this is outside of all known maps, + * and is a negative address, try to look it + * up in the kernel dso, as it might be a + * vsyscall (which executes in user-mode): + */ + if ((long long)ip < 0) + dso = kernel_dso; + } + dprintf(" ...... dso: %s\n", dso ? dso->name : ""); + + if (dsop) + *dsop = dso; + + if (!dso) + return NULL; +got_dso: + return dso->find_symbol(dso, ip); +} + +static int call__match(struct symbol *sym) +{ + if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0)) + return 1; + + return 0; +} + +/* + * collect histogram counts + */ + +static int +hist_entry__add(struct thread *thread, struct map *map, struct dso *dso, + struct symbol *sym, u64 ip, struct ip_callchain *chain, + char level, u64 count) +{ + struct rb_node **p = &hist.rb_node; + struct rb_node *parent = NULL; + struct hist_entry *he; + struct hist_entry entry = { + .thread = thread, + .map = map, + .dso = dso, + .sym = sym, + .ip = ip, + .level = level, + .count = count, + .parent = NULL, + }; + int cmp; + + if (sort__has_parent && chain) { + u64 context = PERF_CONTEXT_MAX; + int i; + + for (i = 0; i < chain->nr; i++) { + u64 ip = chain->ips[i]; + struct dso *dso = NULL; + struct symbol *sym; + + if (ip >= PERF_CONTEXT_MAX) { + context = ip; + continue; + } + + switch (context) { + case PERF_CONTEXT_KERNEL: + dso = kernel_dso; + break; + default: + break; + } + + sym = resolve_symbol(thread, NULL, &dso, &ip); + + if (sym && call__match(sym)) { + entry.parent = sym; + break; + } + } + } + + while (*p != NULL) { + parent = *p; + he = rb_entry(parent, struct hist_entry, rb_node); + + cmp = hist_entry__cmp(&entry, he); + + if (!cmp) { + he->count += count; + return 0; + } + + if (cmp < 0) + p = &(*p)->rb_left; + else + p = &(*p)->rb_right; + } + + he = malloc(sizeof(*he)); + if (!he) + return -ENOMEM; + *he = entry; + rb_link_node(&he->rb_node, parent, p); + rb_insert_color(&he->rb_node, &hist); + + return 0; +} + +static void hist_entry__free(struct hist_entry *he) +{ + free(he); +} + +/* + * collapse the histogram + */ + +static struct rb_root collapse_hists; + +static void collapse__insert_entry(struct hist_entry *he) +{ + struct rb_node **p = &collapse_hists.rb_node; + struct rb_node *parent = NULL; + struct hist_entry *iter; + int64_t cmp; + + while (*p != NULL) { + parent = *p; + iter = rb_entry(parent, struct hist_entry, rb_node); + + cmp = hist_entry__collapse(iter, he); + + if (!cmp) { + iter->count += he->count; + hist_entry__free(he); + return; + } + + if (cmp < 0) + p = &(*p)->rb_left; + else + p = &(*p)->rb_right; + } + + rb_link_node(&he->rb_node, parent, p); + rb_insert_color(&he->rb_node, &collapse_hists); +} + +static void collapse__resort(void) +{ + struct rb_node *next; + struct hist_entry *n; + + if (!sort__need_collapse) + return; + + next = rb_first(&hist); + while (next) { + n = rb_entry(next, struct hist_entry, rb_node); + next = rb_next(&n->rb_node); + + rb_erase(&n->rb_node, &hist); + collapse__insert_entry(n); + } +} + +/* + * reverse the map, sort on count. + */ + +static struct rb_root output_hists; + +static void output__insert_entry(struct hist_entry *he) +{ + struct rb_node **p = &output_hists.rb_node; + struct rb_node *parent = NULL; + struct hist_entry *iter; + + while (*p != NULL) { + parent = *p; + iter = rb_entry(parent, struct hist_entry, rb_node); + + if (he->count > iter->count) + p = &(*p)->rb_left; + else + p = &(*p)->rb_right; + } + + rb_link_node(&he->rb_node, parent, p); + rb_insert_color(&he->rb_node, &output_hists); +} + +static void output__resort(void) +{ + struct rb_node *next; + struct hist_entry *n; + struct rb_root *tree = &hist; + + if (sort__need_collapse) + tree = &collapse_hists; + + next = rb_first(tree); + + while (next) { + n = rb_entry(next, struct hist_entry, rb_node); + next = rb_next(&n->rb_node); + + rb_erase(&n->rb_node, tree); + output__insert_entry(n); + } +} + +static size_t output__fprintf(FILE *fp, u64 total_samples) +{ + struct hist_entry *pos; + struct sort_entry *se; + struct rb_node *nd; + size_t ret = 0; + + fprintf(fp, "\n"); + fprintf(fp, "#\n"); + fprintf(fp, "# (%Ld samples)\n", (u64)total_samples); + fprintf(fp, "#\n"); + + fprintf(fp, "# Overhead"); + list_for_each_entry(se, &hist_entry__sort_list, list) { + if (exclude_other && (se == &sort_parent)) + continue; + fprintf(fp, " %s", se->header); + } + fprintf(fp, "\n"); + + fprintf(fp, "# ........"); + list_for_each_entry(se, &hist_entry__sort_list, list) { + int i; + + if (exclude_other && (se == &sort_parent)) + continue; + + fprintf(fp, " "); + for (i = 0; i < strlen(se->header); i++) + fprintf(fp, "."); + } + fprintf(fp, "\n"); + + fprintf(fp, "#\n"); + + for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) { + pos = rb_entry(nd, struct hist_entry, rb_node); + ret += hist_entry__fprintf(fp, pos, total_samples); + } + + if (sort_order == default_sort_order && + parent_pattern == default_parent_pattern) { + fprintf(fp, "#\n"); + fprintf(fp, "# (For more details, try: perf report --sort comm,dso,symbol)\n"); + fprintf(fp, "#\n"); + } + fprintf(fp, "\n"); + + return ret; +} + +static void register_idle_thread(void) +{ + struct thread *thread = threads__findnew(0); + + if (thread == NULL || + thread__set_comm(thread, "[idle]")) { + fprintf(stderr, "problem inserting idle task.\n"); + exit(-1); + } +} + +static unsigned long total = 0, + total_mmap = 0, + total_comm = 0, + total_fork = 0, + total_unknown = 0, + total_lost = 0; + +static int validate_chain(struct ip_callchain *chain, event_t *event) +{ + unsigned int chain_size; + + chain_size = event->header.size; + chain_size -= (unsigned long)&event->ip.__more_data - (unsigned long)event; + + if (chain->nr*sizeof(u64) > chain_size) + return -1; + + return 0; +} + +static int +process_overflow_event(event_t *event, unsigned long offset, unsigned long head) +{ + char level; + int show = 0; + struct dso *dso = NULL; + struct thread *thread = threads__findnew(event->ip.pid); + u64 ip = event->ip.ip; + u64 period = 1; + struct map *map = NULL; + void *more_data = event->ip.__more_data; + struct ip_callchain *chain = NULL; + + if (event->header.type & PERF_SAMPLE_PERIOD) { + period = *(u64 *)more_data; + more_data += sizeof(u64); + } + + dprintf("%p [%p]: PERF_EVENT (IP, %d): %d: %p period: %Ld\n", + (void *)(offset + head), + (void *)(long)(event->header.size), + event->header.misc, + event->ip.pid, + (void *)(long)ip, + (long long)period); + + if (event->header.type & PERF_SAMPLE_CALLCHAIN) { + int i; + + chain = (void *)more_data; + + dprintf("... chain: nr:%Lu\n", chain->nr); + + if (validate_chain(chain, event) < 0) { + eprintf("call-chain problem with event, skipping it.\n"); + return 0; + } + + if (dump_trace) { + for (i = 0; i < chain->nr; i++) + dprintf("..... %2d: %016Lx\n", i, chain->ips[i]); + } + } + + dprintf(" ... thread: %s:%d\n", thread->comm, thread->pid); + + if (thread == NULL) { + eprintf("problem processing %d event, skipping it.\n", + event->header.type); + return -1; + } + + if (event->header.misc & PERF_EVENT_MISC_KERNEL) { + show = SHOW_KERNEL; + level = 'k'; + + dso = kernel_dso; + + dprintf(" ...... dso: %s\n", dso->name); + + } else if (event->header.misc & PERF_EVENT_MISC_USER) { + + show = SHOW_USER; + level = '.'; + + } else { + show = SHOW_HV; + level = 'H'; + dprintf(" ...... dso: [hypervisor]\n"); + } + + if (show & show_mask) { + struct symbol *sym = resolve_symbol(thread, &map, &dso, &ip); + + if (hist_entry__add(thread, map, dso, sym, ip, chain, level, period)) { + eprintf("problem incrementing symbol count, skipping event\n"); + return -1; + } + } + total += period; + + return 0; +} + +static int +process_mmap_event(event_t *event, unsigned long offset, unsigned long head) +{ + struct thread *thread = threads__findnew(event->mmap.pid); + struct map *map = map__new(&event->mmap); + + dprintf("%p [%p]: PERF_EVENT_MMAP %d: [%p(%p) @ %p]: %s\n", + (void *)(offset + head), + (void *)(long)(event->header.size), + event->mmap.pid, + (void *)(long)event->mmap.start, + (void *)(long)event->mmap.len, + (void *)(long)event->mmap.pgoff, + event->mmap.filename); + + if (thread == NULL || map == NULL) { + dprintf("problem processing PERF_EVENT_MMAP, skipping event.\n"); + return 0; + } + + thread__insert_map(thread, map); + total_mmap++; + + return 0; +} + +static int +process_comm_event(event_t *event, unsigned long offset, unsigned long head) +{ + struct thread *thread = threads__findnew(event->comm.pid); + + dprintf("%p [%p]: PERF_EVENT_COMM: %s:%d\n", + (void *)(offset + head), + (void *)(long)(event->header.size), + event->comm.comm, event->comm.pid); + + if (thread == NULL || + thread__set_comm(thread, event->comm.comm)) { + dprintf("problem processing PERF_EVENT_COMM, skipping event.\n"); + return -1; + } + total_comm++; + + return 0; +} + +static int +process_fork_event(event_t *event, unsigned long offset, unsigned long head) +{ + struct thread *thread = threads__findnew(event->fork.pid); + struct thread *parent = threads__findnew(event->fork.ppid); + + dprintf("%p [%p]: PERF_EVENT_FORK: %d:%d\n", + (void *)(offset + head), + (void *)(long)(event->header.size), + event->fork.pid, event->fork.ppid); + + if (!thread || !parent || thread__fork(thread, parent)) { + dprintf("problem processing PERF_EVENT_FORK, skipping event.\n"); + return -1; + } + total_fork++; + + return 0; +} + +static int +process_period_event(event_t *event, unsigned long offset, unsigned long head) +{ + dprintf("%p [%p]: PERF_EVENT_PERIOD: time:%Ld, id:%Ld: period:%Ld\n", + (void *)(offset + head), + (void *)(long)(event->header.size), + event->period.time, + event->period.id, + event->period.sample_period); + + return 0; +} + +static int +process_lost_event(event_t *event, unsigned long offset, unsigned long head) +{ + dprintf("%p [%p]: PERF_EVENT_LOST: id:%Ld: lost:%Ld\n", + (void *)(offset + head), + (void *)(long)(event->header.size), + event->lost.id, + event->lost.lost); + + total_lost += event->lost.lost; + + return 0; +} + +static void trace_event(event_t *event) +{ + unsigned char *raw_event = (void *)event; + char *color = PERF_COLOR_BLUE; + int i, j; + + if (!dump_trace) + return; + + dprintf("."); + cdprintf("\n. ... raw event: size %d bytes\n", event->header.size); + + for (i = 0; i < event->header.size; i++) { + if ((i & 15) == 0) { + dprintf("."); + cdprintf(" %04x: ", i); + } + + cdprintf(" %02x", raw_event[i]); + + if (((i & 15) == 15) || i == event->header.size-1) { + cdprintf(" "); + for (j = 0; j < 15-(i & 15); j++) + cdprintf(" "); + for (j = 0; j < (i & 15); j++) { + if (isprint(raw_event[i-15+j])) + cdprintf("%c", raw_event[i-15+j]); + else + cdprintf("."); + } + cdprintf("\n"); + } + } + dprintf(".\n"); +} + +static int +process_event(event_t *event, unsigned long offset, unsigned long head) +{ + trace_event(event); + + if (event->header.misc & PERF_EVENT_MISC_OVERFLOW) + return process_overflow_event(event, offset, head); + + switch (event->header.type) { + case PERF_EVENT_MMAP: + return process_mmap_event(event, offset, head); + + case PERF_EVENT_COMM: + return process_comm_event(event, offset, head); + + case PERF_EVENT_FORK: + return process_fork_event(event, offset, head); + + case PERF_EVENT_PERIOD: + return process_period_event(event, offset, head); + + case PERF_EVENT_LOST: + return process_lost_event(event, offset, head); + + /* + * We dont process them right now but they are fine: + */ + + case PERF_EVENT_THROTTLE: + case PERF_EVENT_UNTHROTTLE: + return 0; + + default: + return -1; + } + + return 0; +} + +static struct perf_file_header file_header; + +static int __cmd_report(void) +{ + int ret, rc = EXIT_FAILURE; + unsigned long offset = 0; + unsigned long head = sizeof(file_header); + struct stat stat; + event_t *event; + uint32_t size; + char *buf; + + register_idle_thread(); + + input = open(input_name, O_RDONLY); + if (input < 0) { + fprintf(stderr, " failed to open file: %s", input_name); + if (!strcmp(input_name, "perf.data")) + fprintf(stderr, " (try 'perf record' first)"); + fprintf(stderr, "\n"); + exit(-1); + } + + ret = fstat(input, &stat); + if (ret < 0) { + perror("failed to stat file"); + exit(-1); + } + + if (!stat.st_size) { + fprintf(stderr, "zero-sized file, nothing to do!\n"); + exit(0); + } + + if (read(input, &file_header, sizeof(file_header)) == -1) { + perror("failed to read file headers"); + exit(-1); + } + + if (sort__has_parent && + !(file_header.sample_type & PERF_SAMPLE_CALLCHAIN)) { + fprintf(stderr, "selected --sort parent, but no callchain data\n"); + exit(-1); + } + + if (load_kernel() < 0) { + perror("failed to load kernel symbols"); + return EXIT_FAILURE; + } + + if (!full_paths) { + if (getcwd(__cwd, sizeof(__cwd)) == NULL) { + perror("failed to get the current directory"); + return EXIT_FAILURE; + } + cwdlen = strlen(cwd); + } else { + cwd = NULL; + cwdlen = 0; + } +remap: + buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ, + MAP_SHARED, input, offset); + if (buf == MAP_FAILED) { + perror("failed to mmap file"); + exit(-1); + } + +more: + event = (event_t *)(buf + head); + + size = event->header.size; + if (!size) + size = 8; + + if (head + event->header.size >= page_size * mmap_window) { + unsigned long shift = page_size * (head / page_size); + int ret; + + ret = munmap(buf, page_size * mmap_window); + assert(ret == 0); + + offset += shift; + head -= shift; + goto remap; + } + + size = event->header.size; + + dprintf("\n%p [%p]: event: %d\n", + (void *)(offset + head), + (void *)(long)event->header.size, + event->header.type); + + if (!size || process_event(event, offset, head) < 0) { + + dprintf("%p [%p]: skipping unknown header type: %d\n", + (void *)(offset + head), + (void *)(long)(event->header.size), + event->header.type); + + total_unknown++; + + /* + * assume we lost track of the stream, check alignment, and + * increment a single u64 in the hope to catch on again 'soon'. + */ + + if (unlikely(head & 7)) + head &= ~7ULL; + + size = 8; + } + + head += size; + + if (offset + head >= sizeof(file_header) + file_header.data_size) + goto done; + + if (offset + head < stat.st_size) + goto more; + +done: + rc = EXIT_SUCCESS; + close(input); + + dprintf(" IP events: %10ld\n", total); + dprintf(" mmap events: %10ld\n", total_mmap); + dprintf(" comm events: %10ld\n", total_comm); + dprintf(" fork events: %10ld\n", total_fork); + dprintf(" lost events: %10ld\n", total_lost); + dprintf(" unknown events: %10ld\n", total_unknown); + + if (dump_trace) + return 0; + + if (verbose >= 3) + threads__fprintf(stdout); + + if (verbose >= 2) + dsos__fprintf(stdout); + + collapse__resort(); + output__resort(); + output__fprintf(stdout, total); + + return rc; +} + +static const char * const report_usage[] = { + "perf report [] ", + NULL +}; + +static const struct option options[] = { + OPT_STRING('i', "input", &input_name, "file", + "input file name"), + OPT_BOOLEAN('v', "verbose", &verbose, + "be more verbose (show symbol address, etc)"), + OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, + "dump raw trace in ASCII"), + OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"), + OPT_STRING('s', "sort", &sort_order, "key[,key2...]", + "sort by key(s): pid, comm, dso, symbol, parent"), + OPT_BOOLEAN('P', "full-paths", &full_paths, + "Don't shorten the pathnames taking into account the cwd"), + OPT_STRING('p', "parent", &parent_pattern, "regex", + "regex filter to identify parent, see: '--sort parent'"), + OPT_BOOLEAN('x', "exclude-other", &exclude_other, + "Only display entries with parent-match"), + OPT_END() +}; + +static void setup_sorting(void) +{ + char *tmp, *tok, *str = strdup(sort_order); + + for (tok = strtok_r(str, ", ", &tmp); + tok; tok = strtok_r(NULL, ", ", &tmp)) { + if (sort_dimension__add(tok) < 0) { + error("Unknown --sort key: `%s'", tok); + usage_with_options(report_usage, options); + } + } + + free(str); +} + +int cmd_report(int argc, const char **argv, const char *prefix) +{ + symbol__init(); + + page_size = getpagesize(); + + argc = parse_options(argc, argv, options, report_usage, 0); + + setup_sorting(); + + if (parent_pattern != default_parent_pattern) + sort_dimension__add("parent"); + else + exclude_other = 0; + + /* + * Any (unrecognized) arguments left? + */ + if (argc) + usage_with_options(report_usage, options); + + setup_pager(); + + return __cmd_report(); +} diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c new file mode 100644 index 000000000000..6d3eeac1ea25 --- /dev/null +++ b/tools/perf/builtin-stat.c @@ -0,0 +1,521 @@ +/* + * builtin-stat.c + * + * Builtin stat command: Give a precise performance counters summary + * overview about any workload, CPU or specific PID. + * + * Sample output: + + $ perf stat ~/hackbench 10 + Time: 0.104 + + Performance counter stats for '/home/mingo/hackbench': + + 1255.538611 task clock ticks # 10.143 CPU utilization factor + 54011 context switches # 0.043 M/sec + 385 CPU migrations # 0.000 M/sec + 17755 pagefaults # 0.014 M/sec + 3808323185 CPU cycles # 3033.219 M/sec + 1575111190 instructions # 1254.530 M/sec + 17367895 cache references # 13.833 M/sec + 7674421 cache misses # 6.112 M/sec + + Wall-clock time elapsed: 123.786620 msecs + + * + * Copyright (C) 2008, Red Hat Inc, Ingo Molnar + * + * Improvements and fixes by: + * + * Arjan van de Ven + * Yanmin Zhang + * Wu Fengguang + * Mike Galbraith + * Paul Mackerras + * + * Released under the GPL v2. (and only v2, not any later version) + */ + +#include "perf.h" +#include "builtin.h" +#include "util/util.h" +#include "util/parse-options.h" +#include "util/parse-events.h" + +#include +#include + +static struct perf_counter_attr default_attrs[MAX_COUNTERS] = { + + { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK }, + { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES}, + { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CPU_MIGRATIONS }, + { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS }, + + { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES }, + { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_INSTRUCTIONS }, + { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CACHE_REFERENCES}, + { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CACHE_MISSES }, + +}; + +static int system_wide = 0; +static int inherit = 1; +static int verbose = 0; + +static int fd[MAX_NR_CPUS][MAX_COUNTERS]; + +static int target_pid = -1; +static int nr_cpus = 0; +static unsigned int page_size; + +static int scale = 1; + +static const unsigned int default_count[] = { + 1000000, + 1000000, + 10000, + 10000, + 1000000, + 10000, +}; + +#define MAX_RUN 100 + +static int run_count = 1; +static int run_idx = 0; + +static u64 event_res[MAX_RUN][MAX_COUNTERS][3]; +static u64 event_scaled[MAX_RUN][MAX_COUNTERS]; + +//static u64 event_hist[MAX_RUN][MAX_COUNTERS][3]; + + +static u64 runtime_nsecs[MAX_RUN]; +static u64 walltime_nsecs[MAX_RUN]; +static u64 runtime_cycles[MAX_RUN]; + +static u64 event_res_avg[MAX_COUNTERS][3]; +static u64 event_res_noise[MAX_COUNTERS][3]; + +static u64 event_scaled_avg[MAX_COUNTERS]; + +static u64 runtime_nsecs_avg; +static u64 runtime_nsecs_noise; + +static u64 walltime_nsecs_avg; +static u64 walltime_nsecs_noise; + +static u64 runtime_cycles_avg; +static u64 runtime_cycles_noise; + +static void create_perf_stat_counter(int counter) +{ + struct perf_counter_attr *attr = attrs + counter; + + if (scale) + attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | + PERF_FORMAT_TOTAL_TIME_RUNNING; + + if (system_wide) { + int cpu; + for (cpu = 0; cpu < nr_cpus; cpu ++) { + fd[cpu][counter] = sys_perf_counter_open(attr, -1, cpu, -1, 0); + if (fd[cpu][counter] < 0 && verbose) { + printf("Error: counter %d, sys_perf_counter_open() syscall returned with %d (%s)\n", counter, fd[cpu][counter], strerror(errno)); + } + } + } else { + attr->inherit = inherit; + attr->disabled = 1; + + fd[0][counter] = sys_perf_counter_open(attr, 0, -1, -1, 0); + if (fd[0][counter] < 0 && verbose) { + printf("Error: counter %d, sys_perf_counter_open() syscall returned with %d (%s)\n", counter, fd[0][counter], strerror(errno)); + } + } +} + +/* + * Does the counter have nsecs as a unit? + */ +static inline int nsec_counter(int counter) +{ + if (attrs[counter].type != PERF_TYPE_SOFTWARE) + return 0; + + if (attrs[counter].config == PERF_COUNT_SW_CPU_CLOCK) + return 1; + + if (attrs[counter].config == PERF_COUNT_SW_TASK_CLOCK) + return 1; + + return 0; +} + +/* + * Read out the results of a single counter: + */ +static void read_counter(int counter) +{ + u64 *count, single_count[3]; + ssize_t res; + int cpu, nv; + int scaled; + + count = event_res[run_idx][counter]; + + count[0] = count[1] = count[2] = 0; + + nv = scale ? 3 : 1; + for (cpu = 0; cpu < nr_cpus; cpu ++) { + if (fd[cpu][counter] < 0) + continue; + + res = read(fd[cpu][counter], single_count, nv * sizeof(u64)); + assert(res == nv * sizeof(u64)); + close(fd[cpu][counter]); + fd[cpu][counter] = -1; + + count[0] += single_count[0]; + if (scale) { + count[1] += single_count[1]; + count[2] += single_count[2]; + } + } + + scaled = 0; + if (scale) { + if (count[2] == 0) { + event_scaled[run_idx][counter] = -1; + count[0] = 0; + return; + } + + if (count[2] < count[1]) { + event_scaled[run_idx][counter] = 1; + count[0] = (unsigned long long) + ((double)count[0] * count[1] / count[2] + 0.5); + } + } + /* + * Save the full runtime - to allow normalization during printout: + */ + if (attrs[counter].type == PERF_TYPE_SOFTWARE && + attrs[counter].config == PERF_COUNT_SW_TASK_CLOCK) + runtime_nsecs[run_idx] = count[0]; + if (attrs[counter].type == PERF_TYPE_HARDWARE && + attrs[counter].config == PERF_COUNT_HW_CPU_CYCLES) + runtime_cycles[run_idx] = count[0]; +} + +static int run_perf_stat(int argc, const char **argv) +{ + unsigned long long t0, t1; + int status = 0; + int counter; + int pid; + + if (!system_wide) + nr_cpus = 1; + + for (counter = 0; counter < nr_counters; counter++) + create_perf_stat_counter(counter); + + /* + * Enable counters and exec the command: + */ + t0 = rdclock(); + prctl(PR_TASK_PERF_COUNTERS_ENABLE); + + if ((pid = fork()) < 0) + perror("failed to fork"); + + if (!pid) { + if (execvp(argv[0], (char **)argv)) { + perror(argv[0]); + exit(-1); + } + } + + wait(&status); + + prctl(PR_TASK_PERF_COUNTERS_DISABLE); + t1 = rdclock(); + + walltime_nsecs[run_idx] = t1 - t0; + + for (counter = 0; counter < nr_counters; counter++) + read_counter(counter); + + return WEXITSTATUS(status); +} + +static void print_noise(u64 *count, u64 *noise) +{ + if (run_count > 1) + fprintf(stderr, " ( +- %7.3f%% )", + (double)noise[0]/(count[0]+1)*100.0); +} + +static void nsec_printout(int counter, u64 *count, u64 *noise) +{ + double msecs = (double)count[0] / 1000000; + + fprintf(stderr, " %14.6f %-20s", msecs, event_name(counter)); + + if (attrs[counter].type == PERF_TYPE_SOFTWARE && + attrs[counter].config == PERF_COUNT_SW_TASK_CLOCK) { + + if (walltime_nsecs_avg) + fprintf(stderr, " # %10.3f CPUs ", + (double)count[0] / (double)walltime_nsecs_avg); + } + print_noise(count, noise); +} + +static void abs_printout(int counter, u64 *count, u64 *noise) +{ + fprintf(stderr, " %14Ld %-20s", count[0], event_name(counter)); + + if (runtime_cycles_avg && + attrs[counter].type == PERF_TYPE_HARDWARE && + attrs[counter].config == PERF_COUNT_HW_INSTRUCTIONS) { + + fprintf(stderr, " # %10.3f IPC ", + (double)count[0] / (double)runtime_cycles_avg); + } else { + if (runtime_nsecs_avg) { + fprintf(stderr, " # %10.3f M/sec", + (double)count[0]/runtime_nsecs_avg*1000.0); + } + } + print_noise(count, noise); +} + +/* + * Print out the results of a single counter: + */ +static void print_counter(int counter) +{ + u64 *count, *noise; + int scaled; + + count = event_res_avg[counter]; + noise = event_res_noise[counter]; + scaled = event_scaled_avg[counter]; + + if (scaled == -1) { + fprintf(stderr, " %14s %-20s\n", + "", event_name(counter)); + return; + } + + if (nsec_counter(counter)) + nsec_printout(counter, count, noise); + else + abs_printout(counter, count, noise); + + if (scaled) + fprintf(stderr, " (scaled from %.2f%%)", + (double) count[2] / count[1] * 100); + + fprintf(stderr, "\n"); +} + +/* + * normalize_noise noise values down to stddev: + */ +static void normalize_noise(u64 *val) +{ + double res; + + res = (double)*val / (run_count * sqrt((double)run_count)); + + *val = (u64)res; +} + +static void update_avg(const char *name, int idx, u64 *avg, u64 *val) +{ + *avg += *val; + + if (verbose > 1) + fprintf(stderr, "debug: %20s[%d]: %Ld\n", name, idx, *val); +} +/* + * Calculate the averages and noises: + */ +static void calc_avg(void) +{ + int i, j; + + if (verbose > 1) + fprintf(stderr, "\n"); + + for (i = 0; i < run_count; i++) { + update_avg("runtime", 0, &runtime_nsecs_avg, runtime_nsecs + i); + update_avg("walltime", 0, &walltime_nsecs_avg, walltime_nsecs + i); + update_avg("runtime_cycles", 0, &runtime_cycles_avg, runtime_cycles + i); + + for (j = 0; j < nr_counters; j++) { + update_avg("counter/0", j, + event_res_avg[j]+0, event_res[i][j]+0); + update_avg("counter/1", j, + event_res_avg[j]+1, event_res[i][j]+1); + update_avg("counter/2", j, + event_res_avg[j]+2, event_res[i][j]+2); + update_avg("scaled", j, + event_scaled_avg + j, event_scaled[i]+j); + } + } + runtime_nsecs_avg /= run_count; + walltime_nsecs_avg /= run_count; + runtime_cycles_avg /= run_count; + + for (j = 0; j < nr_counters; j++) { + event_res_avg[j][0] /= run_count; + event_res_avg[j][1] /= run_count; + event_res_avg[j][2] /= run_count; + } + + for (i = 0; i < run_count; i++) { + runtime_nsecs_noise += + abs((s64)(runtime_nsecs[i] - runtime_nsecs_avg)); + walltime_nsecs_noise += + abs((s64)(walltime_nsecs[i] - walltime_nsecs_avg)); + runtime_cycles_noise += + abs((s64)(runtime_cycles[i] - runtime_cycles_avg)); + + for (j = 0; j < nr_counters; j++) { + event_res_noise[j][0] += + abs((s64)(event_res[i][j][0] - event_res_avg[j][0])); + event_res_noise[j][1] += + abs((s64)(event_res[i][j][1] - event_res_avg[j][1])); + event_res_noise[j][2] += + abs((s64)(event_res[i][j][2] - event_res_avg[j][2])); + } + } + + normalize_noise(&runtime_nsecs_noise); + normalize_noise(&walltime_nsecs_noise); + normalize_noise(&runtime_cycles_noise); + + for (j = 0; j < nr_counters; j++) { + normalize_noise(&event_res_noise[j][0]); + normalize_noise(&event_res_noise[j][1]); + normalize_noise(&event_res_noise[j][2]); + } +} + +static void print_stat(int argc, const char **argv) +{ + int i, counter; + + calc_avg(); + + fflush(stdout); + + fprintf(stderr, "\n"); + fprintf(stderr, " Performance counter stats for \'%s", argv[0]); + + for (i = 1; i < argc; i++) + fprintf(stderr, " %s", argv[i]); + + fprintf(stderr, "\'"); + if (run_count > 1) + fprintf(stderr, " (%d runs)", run_count); + fprintf(stderr, ":\n\n"); + + for (counter = 0; counter < nr_counters; counter++) + print_counter(counter); + + + fprintf(stderr, "\n"); + fprintf(stderr, " %14.9f seconds time elapsed.\n", + (double)walltime_nsecs_avg/1e9); + fprintf(stderr, "\n"); +} + +static volatile int signr = -1; + +static void skip_signal(int signo) +{ + signr = signo; +} + +static void sig_atexit(void) +{ + if (signr == -1) + return; + + signal(signr, SIG_DFL); + kill(getpid(), signr); +} + +static const char * const stat_usage[] = { + "perf stat [] ", + NULL +}; + +static const struct option options[] = { + OPT_CALLBACK('e', "event", NULL, "event", + "event selector. use 'perf list' to list available events", + parse_events), + OPT_BOOLEAN('i', "inherit", &inherit, + "child tasks inherit counters"), + OPT_INTEGER('p', "pid", &target_pid, + "stat events on existing pid"), + OPT_BOOLEAN('a', "all-cpus", &system_wide, + "system-wide collection from all CPUs"), + OPT_BOOLEAN('S', "scale", &scale, + "scale/normalize counters"), + OPT_BOOLEAN('v', "verbose", &verbose, + "be more verbose (show counter open errors, etc)"), + OPT_INTEGER('r', "repeat", &run_count, + "repeat command and print average + stddev (max: 100)"), + OPT_END() +}; + +int cmd_stat(int argc, const char **argv, const char *prefix) +{ + int status; + + page_size = sysconf(_SC_PAGE_SIZE); + + memcpy(attrs, default_attrs, sizeof(attrs)); + + argc = parse_options(argc, argv, options, stat_usage, 0); + if (!argc) + usage_with_options(stat_usage, options); + if (run_count <= 0 || run_count > MAX_RUN) + usage_with_options(stat_usage, options); + + if (!nr_counters) + nr_counters = 8; + + nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); + assert(nr_cpus <= MAX_NR_CPUS); + assert(nr_cpus >= 0); + + /* + * We dont want to block the signals - that would cause + * child tasks to inherit that and Ctrl-C would not work. + * What we want is for Ctrl-C to work in the exec()-ed + * task, but being ignored by perf stat itself: + */ + atexit(sig_atexit); + signal(SIGINT, skip_signal); + signal(SIGALRM, skip_signal); + signal(SIGABRT, skip_signal); + + status = 0; + for (run_idx = 0; run_idx < run_count; run_idx++) { + if (run_count != 1 && verbose) + fprintf(stderr, "[ perf stat: executing run #%d ... ]\n", run_idx+1); + status = run_perf_stat(argc, argv); + } + + print_stat(argc, argv); + + return status; +} diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c new file mode 100644 index 000000000000..5352b5e352ed --- /dev/null +++ b/tools/perf/builtin-top.c @@ -0,0 +1,736 @@ +/* + * builtin-top.c + * + * Builtin top command: Display a continuously updated profile of + * any workload, CPU or specific PID. + * + * Copyright (C) 2008, Red Hat Inc, Ingo Molnar + * + * Improvements and fixes by: + * + * Arjan van de Ven + * Yanmin Zhang + * Wu Fengguang + * Mike Galbraith + * Paul Mackerras + * + * Released under the GPL v2. (and only v2, not any later version) + */ +#include "builtin.h" + +#include "perf.h" + +#include "util/symbol.h" +#include "util/color.h" +#include "util/util.h" +#include "util/rbtree.h" +#include "util/parse-options.h" +#include "util/parse-events.h" + +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static int fd[MAX_NR_CPUS][MAX_COUNTERS]; + +static int system_wide = 0; + +static int default_interval = 100000; + +static u64 count_filter = 5; +static int print_entries = 15; + +static int target_pid = -1; +static int profile_cpu = -1; +static int nr_cpus = 0; +static unsigned int realtime_prio = 0; +static int group = 0; +static unsigned int page_size; +static unsigned int mmap_pages = 16; +static int freq = 0; +static int verbose = 0; + +static char *sym_filter; +static unsigned long filter_start; +static unsigned long filter_end; + +static int delay_secs = 2; +static int zero; +static int dump_symtab; + +/* + * Symbols + */ + +static u64 min_ip; +static u64 max_ip = -1ll; + +struct sym_entry { + struct rb_node rb_node; + struct list_head node; + unsigned long count[MAX_COUNTERS]; + unsigned long snap_count; + double weight; + int skip; +}; + +struct sym_entry *sym_filter_entry; + +struct dso *kernel_dso; + +/* + * Symbols will be added here in record_ip and will get out + * after decayed. + */ +static LIST_HEAD(active_symbols); +static pthread_mutex_t active_symbols_lock = PTHREAD_MUTEX_INITIALIZER; + +/* + * Ordering weight: count-1 * count-2 * ... / count-n + */ +static double sym_weight(const struct sym_entry *sym) +{ + double weight = sym->snap_count; + int counter; + + for (counter = 1; counter < nr_counters-1; counter++) + weight *= sym->count[counter]; + + weight /= (sym->count[counter] + 1); + + return weight; +} + +static long samples; +static long userspace_samples; +static const char CONSOLE_CLEAR[] = ""; + +static void __list_insert_active_sym(struct sym_entry *syme) +{ + list_add(&syme->node, &active_symbols); +} + +static void list_remove_active_sym(struct sym_entry *syme) +{ + pthread_mutex_lock(&active_symbols_lock); + list_del_init(&syme->node); + pthread_mutex_unlock(&active_symbols_lock); +} + +static void rb_insert_active_sym(struct rb_root *tree, struct sym_entry *se) +{ + struct rb_node **p = &tree->rb_node; + struct rb_node *parent = NULL; + struct sym_entry *iter; + + while (*p != NULL) { + parent = *p; + iter = rb_entry(parent, struct sym_entry, rb_node); + + if (se->weight > iter->weight) + p = &(*p)->rb_left; + else + p = &(*p)->rb_right; + } + + rb_link_node(&se->rb_node, parent, p); + rb_insert_color(&se->rb_node, tree); +} + +static void print_sym_table(void) +{ + int printed = 0, j; + int counter; + float samples_per_sec = samples/delay_secs; + float ksamples_per_sec = (samples-userspace_samples)/delay_secs; + float sum_ksamples = 0.0; + struct sym_entry *syme, *n; + struct rb_root tmp = RB_ROOT; + struct rb_node *nd; + + samples = userspace_samples = 0; + + /* Sort the active symbols */ + pthread_mutex_lock(&active_symbols_lock); + syme = list_entry(active_symbols.next, struct sym_entry, node); + pthread_mutex_unlock(&active_symbols_lock); + + list_for_each_entry_safe_from(syme, n, &active_symbols, node) { + syme->snap_count = syme->count[0]; + if (syme->snap_count != 0) { + syme->weight = sym_weight(syme); + rb_insert_active_sym(&tmp, syme); + sum_ksamples += syme->snap_count; + + for (j = 0; j < nr_counters; j++) + syme->count[j] = zero ? 0 : syme->count[j] * 7 / 8; + } else + list_remove_active_sym(syme); + } + + puts(CONSOLE_CLEAR); + + printf( +"------------------------------------------------------------------------------\n"); + printf( " PerfTop:%8.0f irqs/sec kernel:%4.1f%% [", + samples_per_sec, + 100.0 - (100.0*((samples_per_sec-ksamples_per_sec)/samples_per_sec))); + + if (nr_counters == 1) { + printf("%Ld", (u64)attrs[0].sample_period); + if (freq) + printf("Hz "); + else + printf(" "); + } + + for (counter = 0; counter < nr_counters; counter++) { + if (counter) + printf("/"); + + printf("%s", event_name(counter)); + } + + printf( "], "); + + if (target_pid != -1) + printf(" (target_pid: %d", target_pid); + else + printf(" (all"); + + if (profile_cpu != -1) + printf(", cpu: %d)\n", profile_cpu); + else { + if (target_pid != -1) + printf(")\n"); + else + printf(", %d CPUs)\n", nr_cpus); + } + + printf("------------------------------------------------------------------------------\n\n"); + + if (nr_counters == 1) + printf(" samples pcnt"); + else + printf(" weight samples pcnt"); + + printf(" RIP kernel function\n" + " ______ _______ _____ ________________ _______________\n\n" + ); + + for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) { + struct sym_entry *syme = rb_entry(nd, struct sym_entry, rb_node); + struct symbol *sym = (struct symbol *)(syme + 1); + char *color = PERF_COLOR_NORMAL; + double pcnt; + + if (++printed > print_entries || syme->snap_count < count_filter) + continue; + + pcnt = 100.0 - (100.0 * ((sum_ksamples - syme->snap_count) / + sum_ksamples)); + + /* + * We color high-overhead entries in red, mid-overhead + * entries in green - and keep the low overhead places + * normal: + */ + if (pcnt >= 5.0) { + color = PERF_COLOR_RED; + } else { + if (pcnt >= 0.5) + color = PERF_COLOR_GREEN; + } + + if (nr_counters == 1) + printf("%20.2f - ", syme->weight); + else + printf("%9.1f %10ld - ", syme->weight, syme->snap_count); + + color_fprintf(stdout, color, "%4.1f%%", pcnt); + printf(" - %016llx : %s\n", sym->start, sym->name); + } +} + +static void *display_thread(void *arg) +{ + struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; + int delay_msecs = delay_secs * 1000; + + printf("PerfTop refresh period: %d seconds\n", delay_secs); + + do { + print_sym_table(); + } while (!poll(&stdin_poll, 1, delay_msecs) == 1); + + printf("key pressed - exiting.\n"); + exit(0); + + return NULL; +} + +static int symbol_filter(struct dso *self, struct symbol *sym) +{ + static int filter_match; + struct sym_entry *syme; + const char *name = sym->name; + + if (!strcmp(name, "_text") || + !strcmp(name, "_etext") || + !strcmp(name, "_sinittext") || + !strncmp("init_module", name, 11) || + !strncmp("cleanup_module", name, 14) || + strstr(name, "_text_start") || + strstr(name, "_text_end")) + return 1; + + syme = dso__sym_priv(self, sym); + /* Tag samples to be skipped. */ + if (!strcmp("default_idle", name) || + !strcmp("cpu_idle", name) || + !strcmp("enter_idle", name) || + !strcmp("exit_idle", name) || + !strcmp("mwait_idle", name)) + syme->skip = 1; + + if (filter_match == 1) { + filter_end = sym->start; + filter_match = -1; + if (filter_end - filter_start > 10000) { + fprintf(stderr, + "hm, too large filter symbol <%s> - skipping.\n", + sym_filter); + fprintf(stderr, "symbol filter start: %016lx\n", + filter_start); + fprintf(stderr, " end: %016lx\n", + filter_end); + filter_end = filter_start = 0; + sym_filter = NULL; + sleep(1); + } + } + + if (filter_match == 0 && sym_filter && !strcmp(name, sym_filter)) { + filter_match = 1; + filter_start = sym->start; + } + + + return 0; +} + +static int parse_symbols(void) +{ + struct rb_node *node; + struct symbol *sym; + + kernel_dso = dso__new("[kernel]", sizeof(struct sym_entry)); + if (kernel_dso == NULL) + return -1; + + if (dso__load_kernel(kernel_dso, NULL, symbol_filter, 1) != 0) + goto out_delete_dso; + + node = rb_first(&kernel_dso->syms); + sym = rb_entry(node, struct symbol, rb_node); + min_ip = sym->start; + + node = rb_last(&kernel_dso->syms); + sym = rb_entry(node, struct symbol, rb_node); + max_ip = sym->end; + + if (dump_symtab) + dso__fprintf(kernel_dso, stderr); + + return 0; + +out_delete_dso: + dso__delete(kernel_dso); + kernel_dso = NULL; + return -1; +} + +#define TRACE_COUNT 3 + +/* + * Binary search in the histogram table and record the hit: + */ +static void record_ip(u64 ip, int counter) +{ + struct symbol *sym = dso__find_symbol(kernel_dso, ip); + + if (sym != NULL) { + struct sym_entry *syme = dso__sym_priv(kernel_dso, sym); + + if (!syme->skip) { + syme->count[counter]++; + pthread_mutex_lock(&active_symbols_lock); + if (list_empty(&syme->node) || !syme->node.next) + __list_insert_active_sym(syme); + pthread_mutex_unlock(&active_symbols_lock); + return; + } + } + + samples--; +} + +static void process_event(u64 ip, int counter) +{ + samples++; + + if (ip < min_ip || ip > max_ip) { + userspace_samples++; + return; + } + + record_ip(ip, counter); +} + +struct mmap_data { + int counter; + void *base; + unsigned int mask; + unsigned int prev; +}; + +static unsigned int mmap_read_head(struct mmap_data *md) +{ + struct perf_counter_mmap_page *pc = md->base; + int head; + + head = pc->data_head; + rmb(); + + return head; +} + +struct timeval last_read, this_read; + +static void mmap_read_counter(struct mmap_data *md) +{ + unsigned int head = mmap_read_head(md); + unsigned int old = md->prev; + unsigned char *data = md->base + page_size; + int diff; + + gettimeofday(&this_read, NULL); + + /* + * If we're further behind than half the buffer, there's a chance + * the writer will bite our tail and mess up the samples under us. + * + * If we somehow ended up ahead of the head, we got messed up. + * + * In either case, truncate and restart at head. + */ + diff = head - old; + if (diff > md->mask / 2 || diff < 0) { + struct timeval iv; + unsigned long msecs; + + timersub(&this_read, &last_read, &iv); + msecs = iv.tv_sec*1000 + iv.tv_usec/1000; + + fprintf(stderr, "WARNING: failed to keep up with mmap data." + " Last read %lu msecs ago.\n", msecs); + + /* + * head points to a known good entry, start there. + */ + old = head; + } + + last_read = this_read; + + for (; old != head;) { + struct ip_event { + struct perf_event_header header; + u64 ip; + u32 pid, target_pid; + }; + struct mmap_event { + struct perf_event_header header; + u32 pid, target_pid; + u64 start; + u64 len; + u64 pgoff; + char filename[PATH_MAX]; + }; + + typedef union event_union { + struct perf_event_header header; + struct ip_event ip; + struct mmap_event mmap; + } event_t; + + event_t *event = (event_t *)&data[old & md->mask]; + + event_t event_copy; + + size_t size = event->header.size; + + /* + * Event straddles the mmap boundary -- header should always + * be inside due to u64 alignment of output. + */ + if ((old & md->mask) + size != ((old + size) & md->mask)) { + unsigned int offset = old; + unsigned int len = min(sizeof(*event), size), cpy; + void *dst = &event_copy; + + do { + cpy = min(md->mask + 1 - (offset & md->mask), len); + memcpy(dst, &data[offset & md->mask], cpy); + offset += cpy; + dst += cpy; + len -= cpy; + } while (len); + + event = &event_copy; + } + + old += size; + + if (event->header.misc & PERF_EVENT_MISC_OVERFLOW) { + if (event->header.type & PERF_SAMPLE_IP) + process_event(event->ip.ip, md->counter); + } + } + + md->prev = old; +} + +static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS]; +static struct mmap_data mmap_array[MAX_NR_CPUS][MAX_COUNTERS]; + +static void mmap_read(void) +{ + int i, counter; + + for (i = 0; i < nr_cpus; i++) { + for (counter = 0; counter < nr_counters; counter++) + mmap_read_counter(&mmap_array[i][counter]); + } +} + +int nr_poll; +int group_fd; + +static void start_counter(int i, int counter) +{ + struct perf_counter_attr *attr; + unsigned int cpu; + + cpu = profile_cpu; + if (target_pid == -1 && profile_cpu == -1) + cpu = i; + + attr = attrs + counter; + + attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; + attr->freq = freq; + +try_again: + fd[i][counter] = sys_perf_counter_open(attr, target_pid, cpu, group_fd, 0); + + if (fd[i][counter] < 0) { + int err = errno; + + if (err == EPERM) + die("No permission - are you root?\n"); + /* + * If it's cycles then fall back to hrtimer + * based cpu-clock-tick sw counter, which + * is always available even if no PMU support: + */ + if (attr->type == PERF_TYPE_HARDWARE + && attr->config == PERF_COUNT_HW_CPU_CYCLES) { + + if (verbose) + warning(" ... trying to fall back to cpu-clock-ticks\n"); + + attr->type = PERF_TYPE_SOFTWARE; + attr->config = PERF_COUNT_SW_CPU_CLOCK; + goto try_again; + } + printf("\n"); + error("perfcounter syscall returned with %d (%s)\n", + fd[i][counter], strerror(err)); + die("No CONFIG_PERF_COUNTERS=y kernel support configured?\n"); + exit(-1); + } + assert(fd[i][counter] >= 0); + fcntl(fd[i][counter], F_SETFL, O_NONBLOCK); + + /* + * First counter acts as the group leader: + */ + if (group && group_fd == -1) + group_fd = fd[i][counter]; + + event_array[nr_poll].fd = fd[i][counter]; + event_array[nr_poll].events = POLLIN; + nr_poll++; + + mmap_array[i][counter].counter = counter; + mmap_array[i][counter].prev = 0; + mmap_array[i][counter].mask = mmap_pages*page_size - 1; + mmap_array[i][counter].base = mmap(NULL, (mmap_pages+1)*page_size, + PROT_READ, MAP_SHARED, fd[i][counter], 0); + if (mmap_array[i][counter].base == MAP_FAILED) + die("failed to mmap with %d (%s)\n", errno, strerror(errno)); +} + +static int __cmd_top(void) +{ + pthread_t thread; + int i, counter; + int ret; + + for (i = 0; i < nr_cpus; i++) { + group_fd = -1; + for (counter = 0; counter < nr_counters; counter++) + start_counter(i, counter); + } + + /* Wait for a minimal set of events before starting the snapshot */ + poll(event_array, nr_poll, 100); + + mmap_read(); + + if (pthread_create(&thread, NULL, display_thread, NULL)) { + printf("Could not create display thread.\n"); + exit(-1); + } + + if (realtime_prio) { + struct sched_param param; + + param.sched_priority = realtime_prio; + if (sched_setscheduler(0, SCHED_FIFO, ¶m)) { + printf("Could not set realtime priority.\n"); + exit(-1); + } + } + + while (1) { + int hits = samples; + + mmap_read(); + + if (hits == samples) + ret = poll(event_array, nr_poll, 100); + } + + return 0; +} + +static const char * const top_usage[] = { + "perf top []", + NULL +}; + +static const struct option options[] = { + OPT_CALLBACK('e', "event", NULL, "event", + "event selector. use 'perf list' to list available events", + parse_events), + OPT_INTEGER('c', "count", &default_interval, + "event period to sample"), + OPT_INTEGER('p', "pid", &target_pid, + "profile events on existing pid"), + OPT_BOOLEAN('a', "all-cpus", &system_wide, + "system-wide collection from all CPUs"), + OPT_INTEGER('C', "CPU", &profile_cpu, + "CPU to profile on"), + OPT_INTEGER('m', "mmap-pages", &mmap_pages, + "number of mmap data pages"), + OPT_INTEGER('r', "realtime", &realtime_prio, + "collect data with this RT SCHED_FIFO priority"), + OPT_INTEGER('d', "delay", &delay_secs, + "number of seconds to delay between refreshes"), + OPT_BOOLEAN('D', "dump-symtab", &dump_symtab, + "dump the symbol table used for profiling"), + OPT_INTEGER('f', "count-filter", &count_filter, + "only display functions with more events than this"), + OPT_BOOLEAN('g', "group", &group, + "put the counters into a counter group"), + OPT_STRING('s', "sym-filter", &sym_filter, "pattern", + "only display symbols matchig this pattern"), + OPT_BOOLEAN('z', "zero", &group, + "zero history across updates"), + OPT_INTEGER('F', "freq", &freq, + "profile at this frequency"), + OPT_INTEGER('E', "entries", &print_entries, + "display this many functions"), + OPT_BOOLEAN('v', "verbose", &verbose, + "be more verbose (show counter open errors, etc)"), + OPT_END() +}; + +int cmd_top(int argc, const char **argv, const char *prefix) +{ + int counter; + + page_size = sysconf(_SC_PAGE_SIZE); + + argc = parse_options(argc, argv, options, top_usage, 0); + if (argc) + usage_with_options(top_usage, options); + + if (freq) { + default_interval = freq; + freq = 1; + } + + /* CPU and PID are mutually exclusive */ + if (target_pid != -1 && profile_cpu != -1) { + printf("WARNING: PID switch overriding CPU\n"); + sleep(1); + profile_cpu = -1; + } + + if (!nr_counters) + nr_counters = 1; + + if (delay_secs < 1) + delay_secs = 1; + + parse_symbols(); + + /* + * Fill in the ones not specifically initialized via -c: + */ + for (counter = 0; counter < nr_counters; counter++) { + if (attrs[counter].sample_period) + continue; + + attrs[counter].sample_period = default_interval; + } + + nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); + assert(nr_cpus <= MAX_NR_CPUS); + assert(nr_cpus >= 0); + + if (target_pid != -1 || profile_cpu != -1) + nr_cpus = 1; + + return __cmd_top(); +} diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h new file mode 100644 index 000000000000..51d168230ee7 --- /dev/null +++ b/tools/perf/builtin.h @@ -0,0 +1,26 @@ +#ifndef BUILTIN_H +#define BUILTIN_H + +#include "util/util.h" +#include "util/strbuf.h" + +extern const char perf_version_string[]; +extern const char perf_usage_string[]; +extern const char perf_more_info_string[]; + +extern void list_common_cmds_help(void); +extern const char *help_unknown_cmd(const char *cmd); +extern void prune_packed_objects(int); +extern int read_line_with_nul(char *buf, int size, FILE *file); +extern int check_pager_config(const char *cmd); + +extern int cmd_annotate(int argc, const char **argv, const char *prefix); +extern int cmd_help(int argc, const char **argv, const char *prefix); +extern int cmd_record(int argc, const char **argv, const char *prefix); +extern int cmd_report(int argc, const char **argv, const char *prefix); +extern int cmd_stat(int argc, const char **argv, const char *prefix); +extern int cmd_top(int argc, const char **argv, const char *prefix); +extern int cmd_version(int argc, const char **argv, const char *prefix); +extern int cmd_list(int argc, const char **argv, const char *prefix); + +#endif diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt new file mode 100644 index 000000000000..eebce30afbc0 --- /dev/null +++ b/tools/perf/command-list.txt @@ -0,0 +1,10 @@ +# +# List of known perf commands. +# command name category [deprecated] [common] +# +perf-annotate mainporcelain common +perf-list mainporcelain common +perf-record mainporcelain common +perf-report mainporcelain common +perf-stat mainporcelain common +perf-top mainporcelain common diff --git a/tools/perf/design.txt b/tools/perf/design.txt new file mode 100644 index 000000000000..f71e0d245cba --- /dev/null +++ b/tools/perf/design.txt @@ -0,0 +1,457 @@ + +Performance Counters for Linux +------------------------------ + +Performance counters are special hardware registers available on most modern +CPUs. These registers count the number of certain types of hw events: such +as instructions executed, cachemisses suffered, or branches mis-predicted - +without slowing down the kernel or applications. These registers can also +trigger interrupts when a threshold number of events have passed - and can +thus be used to profile the code that runs on that CPU. + +The Linux Performance Counter subsystem provides an abstraction of these +hardware capabilities. It provides per task and per CPU counters, counter +groups, and it provides event capabilities on top of those. It +provides "virtual" 64-bit counters, regardless of the width of the +underlying hardware counters. + +Performance counters are accessed via special file descriptors. +There's one file descriptor per virtual counter used. + +The special file descriptor is opened via the perf_counter_open() +system call: + + int sys_perf_counter_open(struct perf_counter_hw_event *hw_event_uptr, + pid_t pid, int cpu, int group_fd, + unsigned long flags); + +The syscall returns the new fd. The fd can be used via the normal +VFS system calls: read() can be used to read the counter, fcntl() +can be used to set the blocking mode, etc. + +Multiple counters can be kept open at a time, and the counters +can be poll()ed. + +When creating a new counter fd, 'perf_counter_hw_event' is: + +struct perf_counter_hw_event { + /* + * The MSB of the config word signifies if the rest contains cpu + * specific (raw) counter configuration data, if unset, the next + * 7 bits are an event type and the rest of the bits are the event + * identifier. + */ + __u64 config; + + __u64 irq_period; + __u32 record_type; + __u32 read_format; + + __u64 disabled : 1, /* off by default */ + inherit : 1, /* children inherit it */ + pinned : 1, /* must always be on PMU */ + exclusive : 1, /* only group on PMU */ + exclude_user : 1, /* don't count user */ + exclude_kernel : 1, /* ditto kernel */ + exclude_hv : 1, /* ditto hypervisor */ + exclude_idle : 1, /* don't count when idle */ + mmap : 1, /* include mmap data */ + munmap : 1, /* include munmap data */ + comm : 1, /* include comm data */ + + __reserved_1 : 52; + + __u32 extra_config_len; + __u32 wakeup_events; /* wakeup every n events */ + + __u64 __reserved_2; + __u64 __reserved_3; +}; + +The 'config' field specifies what the counter should count. It +is divided into 3 bit-fields: + +raw_type: 1 bit (most significant bit) 0x8000_0000_0000_0000 +type: 7 bits (next most significant) 0x7f00_0000_0000_0000 +event_id: 56 bits (least significant) 0x00ff_ffff_ffff_ffff + +If 'raw_type' is 1, then the counter will count a hardware event +specified by the remaining 63 bits of event_config. The encoding is +machine-specific. + +If 'raw_type' is 0, then the 'type' field says what kind of counter +this is, with the following encoding: + +enum perf_event_types { + PERF_TYPE_HARDWARE = 0, + PERF_TYPE_SOFTWARE = 1, + PERF_TYPE_TRACEPOINT = 2, +}; + +A counter of PERF_TYPE_HARDWARE will count the hardware event +specified by 'event_id': + +/* + * Generalized performance counter event types, used by the hw_event.event_id + * parameter of the sys_perf_counter_open() syscall: + */ +enum hw_event_ids { + /* + * Common hardware events, generalized by the kernel: + */ + PERF_COUNT_HW_CPU_CYCLES = 0, + PERF_COUNT_HW_INSTRUCTIONS = 1, + PERF_COUNT_HW_CACHE_REFERENCES = 2, + PERF_COUNT_HW_CACHE_MISSES = 3, + PERF_COUNT_HW_BRANCH_INSTRUCTIONS = 4, + PERF_COUNT_HW_BRANCH_MISSES = 5, + PERF_COUNT_HW_BUS_CYCLES = 6, +}; + +These are standardized types of events that work relatively uniformly +on all CPUs that implement Performance Counters support under Linux, +although there may be variations (e.g., different CPUs might count +cache references and misses at different levels of the cache hierarchy). +If a CPU is not able to count the selected event, then the system call +will return -EINVAL. + +More hw_event_types are supported as well, but they are CPU-specific +and accessed as raw events. For example, to count "External bus +cycles while bus lock signal asserted" events on Intel Core CPUs, pass +in a 0x4064 event_id value and set hw_event.raw_type to 1. + +A counter of type PERF_TYPE_SOFTWARE will count one of the available +software events, selected by 'event_id': + +/* + * Special "software" counters provided by the kernel, even if the hardware + * does not support performance counters. These counters measure various + * physical and sw events of the kernel (and allow the profiling of them as + * well): + */ +enum sw_event_ids { + PERF_COUNT_SW_CPU_CLOCK = 0, + PERF_COUNT_SW_TASK_CLOCK = 1, + PERF_COUNT_SW_PAGE_FAULTS = 2, + PERF_COUNT_SW_CONTEXT_SWITCHES = 3, + PERF_COUNT_SW_CPU_MIGRATIONS = 4, + PERF_COUNT_SW_PAGE_FAULTS_MIN = 5, + PERF_COUNT_SW_PAGE_FAULTS_MAJ = 6, +}; + +Counters of the type PERF_TYPE_TRACEPOINT are available when the ftrace event +tracer is available, and event_id values can be obtained from +/debug/tracing/events/*/*/id + + +Counters come in two flavours: counting counters and sampling +counters. A "counting" counter is one that is used for counting the +number of events that occur, and is characterised by having +irq_period = 0. + + +A read() on a counter returns the current value of the counter and possible +additional values as specified by 'read_format', each value is a u64 (8 bytes) +in size. + +/* + * Bits that can be set in hw_event.read_format to request that + * reads on the counter should return the indicated quantities, + * in increasing order of bit value, after the counter value. + */ +enum perf_counter_read_format { + PERF_FORMAT_TOTAL_TIME_ENABLED = 1, + PERF_FORMAT_TOTAL_TIME_RUNNING = 2, +}; + +Using these additional values one can establish the overcommit ratio for a +particular counter allowing one to take the round-robin scheduling effect +into account. + + +A "sampling" counter is one that is set up to generate an interrupt +every N events, where N is given by 'irq_period'. A sampling counter +has irq_period > 0. The record_type controls what data is recorded on each +interrupt: + +/* + * Bits that can be set in hw_event.record_type to request information + * in the overflow packets. + */ +enum perf_counter_record_format { + PERF_RECORD_IP = 1U << 0, + PERF_RECORD_TID = 1U << 1, + PERF_RECORD_TIME = 1U << 2, + PERF_RECORD_ADDR = 1U << 3, + PERF_RECORD_GROUP = 1U << 4, + PERF_RECORD_CALLCHAIN = 1U << 5, +}; + +Such (and other) events will be recorded in a ring-buffer, which is +available to user-space using mmap() (see below). + +The 'disabled' bit specifies whether the counter starts out disabled +or enabled. If it is initially disabled, it can be enabled by ioctl +or prctl (see below). + +The 'inherit' bit, if set, specifies that this counter should count +events on descendant tasks as well as the task specified. This only +applies to new descendents, not to any existing descendents at the +time the counter is created (nor to any new descendents of existing +descendents). + +The 'pinned' bit, if set, specifies that the counter should always be +on the CPU if at all possible. It only applies to hardware counters +and only to group leaders. If a pinned counter cannot be put onto the +CPU (e.g. because there are not enough hardware counters or because of +a conflict with some other event), then the counter goes into an +'error' state, where reads return end-of-file (i.e. read() returns 0) +until the counter is subsequently enabled or disabled. + +The 'exclusive' bit, if set, specifies that when this counter's group +is on the CPU, it should be the only group using the CPU's counters. +In future, this will allow sophisticated monitoring programs to supply +extra configuration information via 'extra_config_len' to exploit +advanced features of the CPU's Performance Monitor Unit (PMU) that are +not otherwise accessible and that might disrupt other hardware +counters. + +The 'exclude_user', 'exclude_kernel' and 'exclude_hv' bits provide a +way to request that counting of events be restricted to times when the +CPU is in user, kernel and/or hypervisor mode. + +The 'mmap' and 'munmap' bits allow recording of PROT_EXEC mmap/munmap +operations, these can be used to relate userspace IP addresses to actual +code, even after the mapping (or even the whole process) is gone, +these events are recorded in the ring-buffer (see below). + +The 'comm' bit allows tracking of process comm data on process creation. +This too is recorded in the ring-buffer (see below). + +The 'pid' parameter to the perf_counter_open() system call allows the +counter to be specific to a task: + + pid == 0: if the pid parameter is zero, the counter is attached to the + current task. + + pid > 0: the counter is attached to a specific task (if the current task + has sufficient privilege to do so) + + pid < 0: all tasks are counted (per cpu counters) + +The 'cpu' parameter allows a counter to be made specific to a CPU: + + cpu >= 0: the counter is restricted to a specific CPU + cpu == -1: the counter counts on all CPUs + +(Note: the combination of 'pid == -1' and 'cpu == -1' is not valid.) + +A 'pid > 0' and 'cpu == -1' counter is a per task counter that counts +events of that task and 'follows' that task to whatever CPU the task +gets schedule to. Per task counters can be created by any user, for +their own tasks. + +A 'pid == -1' and 'cpu == x' counter is a per CPU counter that counts +all events on CPU-x. Per CPU counters need CAP_SYS_ADMIN privilege. + +The 'flags' parameter is currently unused and must be zero. + +The 'group_fd' parameter allows counter "groups" to be set up. A +counter group has one counter which is the group "leader". The leader +is created first, with group_fd = -1 in the perf_counter_open call +that creates it. The rest of the group members are created +subsequently, with group_fd giving the fd of the group leader. +(A single counter on its own is created with group_fd = -1 and is +considered to be a group with only 1 member.) + +A counter group is scheduled onto the CPU as a unit, that is, it will +only be put onto the CPU if all of the counters in the group can be +put onto the CPU. This means that the values of the member counters +can be meaningfully compared, added, divided (to get ratios), etc., +with each other, since they have counted events for the same set of +executed instructions. + + +Like stated, asynchronous events, like counter overflow or PROT_EXEC mmap +tracking are logged into a ring-buffer. This ring-buffer is created and +accessed through mmap(). + +The mmap size should be 1+2^n pages, where the first page is a meta-data page +(struct perf_counter_mmap_page) that contains various bits of information such +as where the ring-buffer head is. + +/* + * Structure of the page that can be mapped via mmap + */ +struct perf_counter_mmap_page { + __u32 version; /* version number of this structure */ + __u32 compat_version; /* lowest version this is compat with */ + + /* + * Bits needed to read the hw counters in user-space. + * + * u32 seq; + * s64 count; + * + * do { + * seq = pc->lock; + * + * barrier() + * if (pc->index) { + * count = pmc_read(pc->index - 1); + * count += pc->offset; + * } else + * goto regular_read; + * + * barrier(); + * } while (pc->lock != seq); + * + * NOTE: for obvious reason this only works on self-monitoring + * processes. + */ + __u32 lock; /* seqlock for synchronization */ + __u32 index; /* hardware counter identifier */ + __s64 offset; /* add to hardware counter value */ + + /* + * Control data for the mmap() data buffer. + * + * User-space reading this value should issue an rmb(), on SMP capable + * platforms, after reading this value -- see perf_counter_wakeup(). + */ + __u32 data_head; /* head in the data section */ +}; + +NOTE: the hw-counter userspace bits are arch specific and are currently only + implemented on powerpc. + +The following 2^n pages are the ring-buffer which contains events of the form: + +#define PERF_EVENT_MISC_KERNEL (1 << 0) +#define PERF_EVENT_MISC_USER (1 << 1) +#define PERF_EVENT_MISC_OVERFLOW (1 << 2) + +struct perf_event_header { + __u32 type; + __u16 misc; + __u16 size; +}; + +enum perf_event_type { + + /* + * The MMAP events record the PROT_EXEC mappings so that we can + * correlate userspace IPs to code. They have the following structure: + * + * struct { + * struct perf_event_header header; + * + * u32 pid, tid; + * u64 addr; + * u64 len; + * u64 pgoff; + * char filename[]; + * }; + */ + PERF_EVENT_MMAP = 1, + PERF_EVENT_MUNMAP = 2, + + /* + * struct { + * struct perf_event_header header; + * + * u32 pid, tid; + * char comm[]; + * }; + */ + PERF_EVENT_COMM = 3, + + /* + * When header.misc & PERF_EVENT_MISC_OVERFLOW the event_type field + * will be PERF_RECORD_* + * + * struct { + * struct perf_event_header header; + * + * { u64 ip; } && PERF_RECORD_IP + * { u32 pid, tid; } && PERF_RECORD_TID + * { u64 time; } && PERF_RECORD_TIME + * { u64 addr; } && PERF_RECORD_ADDR + * + * { u64 nr; + * { u64 event, val; } cnt[nr]; } && PERF_RECORD_GROUP + * + * { u16 nr, + * hv, + * kernel, + * user; + * u64 ips[nr]; } && PERF_RECORD_CALLCHAIN + * }; + */ +}; + +NOTE: PERF_RECORD_CALLCHAIN is arch specific and currently only implemented + on x86. + +Notification of new events is possible through poll()/select()/epoll() and +fcntl() managing signals. + +Normally a notification is generated for every page filled, however one can +additionally set perf_counter_hw_event.wakeup_events to generate one every +so many counter overflow events. + +Future work will include a splice() interface to the ring-buffer. + + +Counters can be enabled and disabled in two ways: via ioctl and via +prctl. When a counter is disabled, it doesn't count or generate +events but does continue to exist and maintain its count value. + +An individual counter or counter group can be enabled with + + ioctl(fd, PERF_COUNTER_IOC_ENABLE); + +or disabled with + + ioctl(fd, PERF_COUNTER_IOC_DISABLE); + +Enabling or disabling the leader of a group enables or disables the +whole group; that is, while the group leader is disabled, none of the +counters in the group will count. Enabling or disabling a member of a +group other than the leader only affects that counter - disabling an +non-leader stops that counter from counting but doesn't affect any +other counter. + +Additionally, non-inherited overflow counters can use + + ioctl(fd, PERF_COUNTER_IOC_REFRESH, nr); + +to enable a counter for 'nr' events, after which it gets disabled again. + +A process can enable or disable all the counter groups that are +attached to it, using prctl: + + prctl(PR_TASK_PERF_COUNTERS_ENABLE); + + prctl(PR_TASK_PERF_COUNTERS_DISABLE); + +This applies to all counters on the current process, whether created +by this process or by another, and doesn't affect any counters that +this process has created on other processes. It only enables or +disables the group leaders, not any other members in the groups. + + +Arch requirements +----------------- + +If your architecture does not have hardware performance metrics, you can +still use the generic software counters based on hrtimers for sampling. + +So to start with, in order to add HAVE_PERF_COUNTERS to your Kconfig, you +will need at least this: + - asm/perf_counter.h - a basic stub will suffice at first + - support for atomic64 types (and associated helper functions) + - set_perf_counter_pending() implemented + +If your architecture does have hardware capabilities, you can override the +weak stub hw_perf_counter_init() to register hardware counters. diff --git a/tools/perf/perf.c b/tools/perf/perf.c new file mode 100644 index 000000000000..4eb725933703 --- /dev/null +++ b/tools/perf/perf.c @@ -0,0 +1,428 @@ +/* + * perf.c + * + * Performance analysis utility. + * + * This is the main hub from which the sub-commands (perf stat, + * perf top, perf record, perf report, etc.) are started. + */ +#include "builtin.h" + +#include "util/exec_cmd.h" +#include "util/cache.h" +#include "util/quote.h" +#include "util/run-command.h" + +const char perf_usage_string[] = + "perf [--version] [--help] COMMAND [ARGS]"; + +const char perf_more_info_string[] = + "See 'perf help COMMAND' for more information on a specific command."; + +static int use_pager = -1; +struct pager_config { + const char *cmd; + int val; +}; + +static int pager_command_config(const char *var, const char *value, void *data) +{ + struct pager_config *c = data; + if (!prefixcmp(var, "pager.") && !strcmp(var + 6, c->cmd)) + c->val = perf_config_bool(var, value); + return 0; +} + +/* returns 0 for "no pager", 1 for "use pager", and -1 for "not specified" */ +int check_pager_config(const char *cmd) +{ + struct pager_config c; + c.cmd = cmd; + c.val = -1; + perf_config(pager_command_config, &c); + return c.val; +} + +static void commit_pager_choice(void) { + switch (use_pager) { + case 0: + setenv("PERF_PAGER", "cat", 1); + break; + case 1: + /* setup_pager(); */ + break; + default: + break; + } +} + +static int handle_options(const char*** argv, int* argc, int* envchanged) +{ + int handled = 0; + + while (*argc > 0) { + const char *cmd = (*argv)[0]; + if (cmd[0] != '-') + break; + + /* + * For legacy reasons, the "version" and "help" + * commands can be written with "--" prepended + * to make them look like flags. + */ + if (!strcmp(cmd, "--help") || !strcmp(cmd, "--version")) + break; + + /* + * Check remaining flags. + */ + if (!prefixcmp(cmd, "--exec-path")) { + cmd += 11; + if (*cmd == '=') + perf_set_argv_exec_path(cmd + 1); + else { + puts(perf_exec_path()); + exit(0); + } + } else if (!strcmp(cmd, "--html-path")) { + puts(system_path(PERF_HTML_PATH)); + exit(0); + } else if (!strcmp(cmd, "-p") || !strcmp(cmd, "--paginate")) { + use_pager = 1; + } else if (!strcmp(cmd, "--no-pager")) { + use_pager = 0; + if (envchanged) + *envchanged = 1; + } else if (!strcmp(cmd, "--perf-dir")) { + if (*argc < 2) { + fprintf(stderr, "No directory given for --perf-dir.\n" ); + usage(perf_usage_string); + } + setenv(PERF_DIR_ENVIRONMENT, (*argv)[1], 1); + if (envchanged) + *envchanged = 1; + (*argv)++; + (*argc)--; + handled++; + } else if (!prefixcmp(cmd, "--perf-dir=")) { + setenv(PERF_DIR_ENVIRONMENT, cmd + 10, 1); + if (envchanged) + *envchanged = 1; + } else if (!strcmp(cmd, "--work-tree")) { + if (*argc < 2) { + fprintf(stderr, "No directory given for --work-tree.\n" ); + usage(perf_usage_string); + } + setenv(PERF_WORK_TREE_ENVIRONMENT, (*argv)[1], 1); + if (envchanged) + *envchanged = 1; + (*argv)++; + (*argc)--; + } else if (!prefixcmp(cmd, "--work-tree=")) { + setenv(PERF_WORK_TREE_ENVIRONMENT, cmd + 12, 1); + if (envchanged) + *envchanged = 1; + } else { + fprintf(stderr, "Unknown option: %s\n", cmd); + usage(perf_usage_string); + } + + (*argv)++; + (*argc)--; + handled++; + } + return handled; +} + +static int handle_alias(int *argcp, const char ***argv) +{ + int envchanged = 0, ret = 0, saved_errno = errno; + int count, option_count; + const char** new_argv; + const char *alias_command; + char *alias_string; + + alias_command = (*argv)[0]; + alias_string = alias_lookup(alias_command); + if (alias_string) { + if (alias_string[0] == '!') { + if (*argcp > 1) { + struct strbuf buf; + + strbuf_init(&buf, PATH_MAX); + strbuf_addstr(&buf, alias_string); + sq_quote_argv(&buf, (*argv) + 1, PATH_MAX); + free(alias_string); + alias_string = buf.buf; + } + ret = system(alias_string + 1); + if (ret >= 0 && WIFEXITED(ret) && + WEXITSTATUS(ret) != 127) + exit(WEXITSTATUS(ret)); + die("Failed to run '%s' when expanding alias '%s'", + alias_string + 1, alias_command); + } + count = split_cmdline(alias_string, &new_argv); + if (count < 0) + die("Bad alias.%s string", alias_command); + option_count = handle_options(&new_argv, &count, &envchanged); + if (envchanged) + die("alias '%s' changes environment variables\n" + "You can use '!perf' in the alias to do this.", + alias_command); + memmove(new_argv - option_count, new_argv, + count * sizeof(char *)); + new_argv -= option_count; + + if (count < 1) + die("empty alias for %s", alias_command); + + if (!strcmp(alias_command, new_argv[0])) + die("recursive alias: %s", alias_command); + + new_argv = realloc(new_argv, sizeof(char*) * + (count + *argcp + 1)); + /* insert after command name */ + memcpy(new_argv + count, *argv + 1, sizeof(char*) * *argcp); + new_argv[count+*argcp] = NULL; + + *argv = new_argv; + *argcp += count - 1; + + ret = 1; + } + + errno = saved_errno; + + return ret; +} + +const char perf_version_string[] = PERF_VERSION; + +#define RUN_SETUP (1<<0) +#define USE_PAGER (1<<1) +/* + * require working tree to be present -- anything uses this needs + * RUN_SETUP for reading from the configuration file. + */ +#define NEED_WORK_TREE (1<<2) + +struct cmd_struct { + const char *cmd; + int (*fn)(int, const char **, const char *); + int option; +}; + +static int run_builtin(struct cmd_struct *p, int argc, const char **argv) +{ + int status; + struct stat st; + const char *prefix; + + prefix = NULL; + if (p->option & RUN_SETUP) + prefix = NULL; /* setup_perf_directory(); */ + + if (use_pager == -1 && p->option & RUN_SETUP) + use_pager = check_pager_config(p->cmd); + if (use_pager == -1 && p->option & USE_PAGER) + use_pager = 1; + commit_pager_choice(); + + if (p->option & NEED_WORK_TREE) + /* setup_work_tree() */; + + status = p->fn(argc, argv, prefix); + if (status) + return status & 0xff; + + /* Somebody closed stdout? */ + if (fstat(fileno(stdout), &st)) + return 0; + /* Ignore write errors for pipes and sockets.. */ + if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode)) + return 0; + + /* Check for ENOSPC and EIO errors.. */ + if (fflush(stdout)) + die("write failure on standard output: %s", strerror(errno)); + if (ferror(stdout)) + die("unknown write failure on standard output"); + if (fclose(stdout)) + die("close failed on standard output: %s", strerror(errno)); + return 0; +} + +static void handle_internal_command(int argc, const char **argv) +{ + const char *cmd = argv[0]; + static struct cmd_struct commands[] = { + { "help", cmd_help, 0 }, + { "list", cmd_list, 0 }, + { "record", cmd_record, 0 }, + { "report", cmd_report, 0 }, + { "stat", cmd_stat, 0 }, + { "top", cmd_top, 0 }, + { "annotate", cmd_annotate, 0 }, + { "version", cmd_version, 0 }, + }; + int i; + static const char ext[] = STRIP_EXTENSION; + + if (sizeof(ext) > 1) { + i = strlen(argv[0]) - strlen(ext); + if (i > 0 && !strcmp(argv[0] + i, ext)) { + char *argv0 = strdup(argv[0]); + argv[0] = cmd = argv0; + argv0[i] = '\0'; + } + } + + /* Turn "perf cmd --help" into "perf help cmd" */ + if (argc > 1 && !strcmp(argv[1], "--help")) { + argv[1] = argv[0]; + argv[0] = cmd = "help"; + } + + for (i = 0; i < ARRAY_SIZE(commands); i++) { + struct cmd_struct *p = commands+i; + if (strcmp(p->cmd, cmd)) + continue; + exit(run_builtin(p, argc, argv)); + } +} + +static void execv_dashed_external(const char **argv) +{ + struct strbuf cmd = STRBUF_INIT; + const char *tmp; + int status; + + strbuf_addf(&cmd, "perf-%s", argv[0]); + + /* + * argv[0] must be the perf command, but the argv array + * belongs to the caller, and may be reused in + * subsequent loop iterations. Save argv[0] and + * restore it on error. + */ + tmp = argv[0]; + argv[0] = cmd.buf; + + /* + * if we fail because the command is not found, it is + * OK to return. Otherwise, we just pass along the status code. + */ + status = run_command_v_opt(argv, 0); + if (status != -ERR_RUN_COMMAND_EXEC) { + if (IS_RUN_COMMAND_ERR(status)) + die("unable to run '%s'", argv[0]); + exit(-status); + } + errno = ENOENT; /* as if we called execvp */ + + argv[0] = tmp; + + strbuf_release(&cmd); +} + +static int run_argv(int *argcp, const char ***argv) +{ + int done_alias = 0; + + while (1) { + /* See if it's an internal command */ + handle_internal_command(*argcp, *argv); + + /* .. then try the external ones */ + execv_dashed_external(*argv); + + /* It could be an alias -- this works around the insanity + * of overriding "perf log" with "perf show" by having + * alias.log = show + */ + if (done_alias || !handle_alias(argcp, argv)) + break; + done_alias = 1; + } + + return done_alias; +} + + +int main(int argc, const char **argv) +{ + const char *cmd; + + cmd = perf_extract_argv0_path(argv[0]); + if (!cmd) + cmd = "perf-help"; + + /* + * "perf-xxxx" is the same as "perf xxxx", but we obviously: + * + * - cannot take flags in between the "perf" and the "xxxx". + * - cannot execute it externally (since it would just do + * the same thing over again) + * + * So we just directly call the internal command handler, and + * die if that one cannot handle it. + */ + if (!prefixcmp(cmd, "perf-")) { + cmd += 5; + argv[0] = cmd; + handle_internal_command(argc, argv); + die("cannot handle %s internally", cmd); + } + + /* Look for flags.. */ + argv++; + argc--; + handle_options(&argv, &argc, NULL); + commit_pager_choice(); + if (argc > 0) { + if (!prefixcmp(argv[0], "--")) + argv[0] += 2; + } else { + /* The user didn't specify a command; give them help */ + printf("\n usage: %s\n\n", perf_usage_string); + list_common_cmds_help(); + printf("\n %s\n\n", perf_more_info_string); + exit(1); + } + cmd = argv[0]; + + /* + * We use PATH to find perf commands, but we prepend some higher + * precidence paths: the "--exec-path" option, the PERF_EXEC_PATH + * environment, and the $(perfexecdir) from the Makefile at build + * time. + */ + setup_path(); + + while (1) { + static int done_help = 0; + static int was_alias = 0; + + was_alias = run_argv(&argc, &argv); + if (errno != ENOENT) + break; + + if (was_alias) { + fprintf(stderr, "Expansion of alias '%s' failed; " + "'%s' is not a perf-command\n", + cmd, argv[0]); + exit(1); + } + if (!done_help) { + cmd = argv[0] = help_unknown_cmd(cmd); + done_help = 1; + } else + break; + } + + fprintf(stderr, "Failed to run command '%s': %s\n", + cmd, strerror(errno)); + + return 1; +} diff --git a/tools/perf/perf.h b/tools/perf/perf.h new file mode 100644 index 000000000000..ceb68aa51f7f --- /dev/null +++ b/tools/perf/perf.h @@ -0,0 +1,81 @@ +#ifndef _PERF_PERF_H +#define _PERF_PERF_H + +#if defined(__x86_64__) || defined(__i386__) +#include "../../arch/x86/include/asm/unistd.h" +#define rmb() asm volatile("lfence" ::: "memory") +#define cpu_relax() asm volatile("rep; nop" ::: "memory"); +#endif + +#ifdef __powerpc__ +#include "../../arch/powerpc/include/asm/unistd.h" +#define rmb() asm volatile ("sync" ::: "memory") +#define cpu_relax() asm volatile ("" ::: "memory"); +#endif + +#ifdef __s390__ +#include "../../arch/s390/include/asm/unistd.h" +#define rmb() asm volatile("bcr 15,0" ::: "memory") +#define cpu_relax() asm volatile("" ::: "memory"); +#endif + +#include +#include +#include +#include + +#include "../../include/linux/perf_counter.h" +#include "types.h" + +/* + * prctl(PR_TASK_PERF_COUNTERS_DISABLE) will (cheaply) disable all + * counters in the current task. + */ +#define PR_TASK_PERF_COUNTERS_DISABLE 31 +#define PR_TASK_PERF_COUNTERS_ENABLE 32 + +#ifndef NSEC_PER_SEC +# define NSEC_PER_SEC 1000000000ULL +#endif + +static inline unsigned long long rdclock(void) +{ + struct timespec ts; + + clock_gettime(CLOCK_MONOTONIC, &ts); + return ts.tv_sec * 1000000000ULL + ts.tv_nsec; +} + +/* + * Pick up some kernel type conventions: + */ +#define __user +#define asmlinkage + +#define unlikely(x) __builtin_expect(!!(x), 0) +#define min(x, y) ({ \ + typeof(x) _min1 = (x); \ + typeof(y) _min2 = (y); \ + (void) (&_min1 == &_min2); \ + _min1 < _min2 ? _min1 : _min2; }) + +static inline int +sys_perf_counter_open(struct perf_counter_attr *attr, + pid_t pid, int cpu, int group_fd, + unsigned long flags) +{ + attr->size = sizeof(*attr); + return syscall(__NR_perf_counter_open, attr, pid, cpu, + group_fd, flags); +} + +#define MAX_COUNTERS 256 +#define MAX_NR_CPUS 256 + +struct perf_file_header { + u64 version; + u64 sample_type; + u64 data_size; +}; + +#endif diff --git a/tools/perf/types.h b/tools/perf/types.h new file mode 100644 index 000000000000..5e75f9005940 --- /dev/null +++ b/tools/perf/types.h @@ -0,0 +1,17 @@ +#ifndef _PERF_TYPES_H +#define _PERF_TYPES_H + +/* + * We define u64 as unsigned long long for every architecture + * so that we can print it with %Lx without getting warnings. + */ +typedef unsigned long long u64; +typedef signed long long s64; +typedef unsigned int u32; +typedef signed int s32; +typedef unsigned short u16; +typedef signed short s16; +typedef unsigned char u8; +typedef signed char s8; + +#endif /* _PERF_TYPES_H */ diff --git a/tools/perf/util/PERF-VERSION-GEN b/tools/perf/util/PERF-VERSION-GEN new file mode 100755 index 000000000000..c561d1538c03 --- /dev/null +++ b/tools/perf/util/PERF-VERSION-GEN @@ -0,0 +1,42 @@ +#!/bin/sh + +GVF=PERF-VERSION-FILE +DEF_VER=v0.0.1.PERF + +LF=' +' + +# First see if there is a version file (included in release tarballs), +# then try git-describe, then default. +if test -f version +then + VN=$(cat version) || VN="$DEF_VER" +elif test -d .git -o -f .git && + VN=$(git describe --abbrev=4 HEAD 2>/dev/null) && + case "$VN" in + *$LF*) (exit 1) ;; + v[0-9]*) + git update-index -q --refresh + test -z "$(git diff-index --name-only HEAD --)" || + VN="$VN-dirty" ;; + esac +then + VN=$(echo "$VN" | sed -e 's/-/./g'); +else + VN="$DEF_VER" +fi + +VN=$(expr "$VN" : v*'\(.*\)') + +if test -r $GVF +then + VC=$(sed -e 's/^PERF_VERSION = //' <$GVF) +else + VC=unset +fi +test "$VN" = "$VC" || { + echo >&2 "PERF_VERSION = $VN" + echo "PERF_VERSION = $VN" >$GVF +} + + diff --git a/tools/perf/util/abspath.c b/tools/perf/util/abspath.c new file mode 100644 index 000000000000..61d33b81fc97 --- /dev/null +++ b/tools/perf/util/abspath.c @@ -0,0 +1,117 @@ +#include "cache.h" + +/* + * Do not use this for inspecting *tracked* content. When path is a + * symlink to a directory, we do not want to say it is a directory when + * dealing with tracked content in the working tree. + */ +static int is_directory(const char *path) +{ + struct stat st; + return (!stat(path, &st) && S_ISDIR(st.st_mode)); +} + +/* We allow "recursive" symbolic links. Only within reason, though. */ +#define MAXDEPTH 5 + +const char *make_absolute_path(const char *path) +{ + static char bufs[2][PATH_MAX + 1], *buf = bufs[0], *next_buf = bufs[1]; + char cwd[1024] = ""; + int buf_index = 1, len; + + int depth = MAXDEPTH; + char *last_elem = NULL; + struct stat st; + + if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX) + die ("Too long path: %.*s", 60, path); + + while (depth--) { + if (!is_directory(buf)) { + char *last_slash = strrchr(buf, '/'); + if (last_slash) { + *last_slash = '\0'; + last_elem = xstrdup(last_slash + 1); + } else { + last_elem = xstrdup(buf); + *buf = '\0'; + } + } + + if (*buf) { + if (!*cwd && !getcwd(cwd, sizeof(cwd))) + die ("Could not get current working directory"); + + if (chdir(buf)) + die ("Could not switch to '%s'", buf); + } + if (!getcwd(buf, PATH_MAX)) + die ("Could not get current working directory"); + + if (last_elem) { + int len = strlen(buf); + if (len + strlen(last_elem) + 2 > PATH_MAX) + die ("Too long path name: '%s/%s'", + buf, last_elem); + buf[len] = '/'; + strcpy(buf + len + 1, last_elem); + free(last_elem); + last_elem = NULL; + } + + if (!lstat(buf, &st) && S_ISLNK(st.st_mode)) { + len = readlink(buf, next_buf, PATH_MAX); + if (len < 0) + die ("Invalid symlink: %s", buf); + if (PATH_MAX <= len) + die("symbolic link too long: %s", buf); + next_buf[len] = '\0'; + buf = next_buf; + buf_index = 1 - buf_index; + next_buf = bufs[buf_index]; + } else + break; + } + + if (*cwd && chdir(cwd)) + die ("Could not change back to '%s'", cwd); + + return buf; +} + +static const char *get_pwd_cwd(void) +{ + static char cwd[PATH_MAX + 1]; + char *pwd; + struct stat cwd_stat, pwd_stat; + if (getcwd(cwd, PATH_MAX) == NULL) + return NULL; + pwd = getenv("PWD"); + if (pwd && strcmp(pwd, cwd)) { + stat(cwd, &cwd_stat); + if (!stat(pwd, &pwd_stat) && + pwd_stat.st_dev == cwd_stat.st_dev && + pwd_stat.st_ino == cwd_stat.st_ino) { + strlcpy(cwd, pwd, PATH_MAX); + } + } + return cwd; +} + +const char *make_nonrelative_path(const char *path) +{ + static char buf[PATH_MAX + 1]; + + if (is_absolute_path(path)) { + if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX) + die("Too long path: %.*s", 60, path); + } else { + const char *cwd = get_pwd_cwd(); + if (!cwd) + die("Cannot determine the current working directory"); + if (snprintf(buf, PATH_MAX, "%s/%s", cwd, path) >= PATH_MAX) + die("Too long path: %.*s", 60, path); + } + return buf; +} diff --git a/tools/perf/util/alias.c b/tools/perf/util/alias.c new file mode 100644 index 000000000000..9b3dd2b428df --- /dev/null +++ b/tools/perf/util/alias.c @@ -0,0 +1,77 @@ +#include "cache.h" + +static const char *alias_key; +static char *alias_val; + +static int alias_lookup_cb(const char *k, const char *v, void *cb) +{ + if (!prefixcmp(k, "alias.") && !strcmp(k+6, alias_key)) { + if (!v) + return config_error_nonbool(k); + alias_val = strdup(v); + return 0; + } + return 0; +} + +char *alias_lookup(const char *alias) +{ + alias_key = alias; + alias_val = NULL; + perf_config(alias_lookup_cb, NULL); + return alias_val; +} + +int split_cmdline(char *cmdline, const char ***argv) +{ + int src, dst, count = 0, size = 16; + char quoted = 0; + + *argv = malloc(sizeof(char*) * size); + + /* split alias_string */ + (*argv)[count++] = cmdline; + for (src = dst = 0; cmdline[src];) { + char c = cmdline[src]; + if (!quoted && isspace(c)) { + cmdline[dst++] = 0; + while (cmdline[++src] + && isspace(cmdline[src])) + ; /* skip */ + if (count >= size) { + size += 16; + *argv = realloc(*argv, sizeof(char*) * size); + } + (*argv)[count++] = cmdline + dst; + } else if (!quoted && (c == '\'' || c == '"')) { + quoted = c; + src++; + } else if (c == quoted) { + quoted = 0; + src++; + } else { + if (c == '\\' && quoted != '\'') { + src++; + c = cmdline[src]; + if (!c) { + free(*argv); + *argv = NULL; + return error("cmdline ends with \\"); + } + } + cmdline[dst++] = c; + src++; + } + } + + cmdline[dst] = 0; + + if (quoted) { + free(*argv); + *argv = NULL; + return error("unclosed quote"); + } + + return count; +} + diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h new file mode 100644 index 000000000000..393d6146d13b --- /dev/null +++ b/tools/perf/util/cache.h @@ -0,0 +1,119 @@ +#ifndef CACHE_H +#define CACHE_H + +#include "util.h" +#include "strbuf.h" + +#define PERF_DIR_ENVIRONMENT "PERF_DIR" +#define PERF_WORK_TREE_ENVIRONMENT "PERF_WORK_TREE" +#define DEFAULT_PERF_DIR_ENVIRONMENT ".perf" +#define DB_ENVIRONMENT "PERF_OBJECT_DIRECTORY" +#define INDEX_ENVIRONMENT "PERF_INDEX_FILE" +#define GRAFT_ENVIRONMENT "PERF_GRAFT_FILE" +#define TEMPLATE_DIR_ENVIRONMENT "PERF_TEMPLATE_DIR" +#define CONFIG_ENVIRONMENT "PERF_CONFIG" +#define EXEC_PATH_ENVIRONMENT "PERF_EXEC_PATH" +#define CEILING_DIRECTORIES_ENVIRONMENT "PERF_CEILING_DIRECTORIES" +#define PERFATTRIBUTES_FILE ".perfattributes" +#define INFOATTRIBUTES_FILE "info/attributes" +#define ATTRIBUTE_MACRO_PREFIX "[attr]" + +typedef int (*config_fn_t)(const char *, const char *, void *); +extern int perf_default_config(const char *, const char *, void *); +extern int perf_config_from_file(config_fn_t fn, const char *, void *); +extern int perf_config(config_fn_t fn, void *); +extern int perf_parse_ulong(const char *, unsigned long *); +extern int perf_config_int(const char *, const char *); +extern unsigned long perf_config_ulong(const char *, const char *); +extern int perf_config_bool_or_int(const char *, const char *, int *); +extern int perf_config_bool(const char *, const char *); +extern int perf_config_string(const char **, const char *, const char *); +extern int perf_config_set(const char *, const char *); +extern int perf_config_set_multivar(const char *, const char *, const char *, int); +extern int perf_config_rename_section(const char *, const char *); +extern const char *perf_etc_perfconfig(void); +extern int check_repository_format_version(const char *var, const char *value, void *cb); +extern int perf_config_system(void); +extern int perf_config_global(void); +extern int config_error_nonbool(const char *); +extern const char *config_exclusive_filename; + +#define MAX_PERFNAME (1000) +extern char perf_default_email[MAX_PERFNAME]; +extern char perf_default_name[MAX_PERFNAME]; +extern int user_ident_explicitly_given; + +extern const char *perf_log_output_encoding; +extern const char *perf_mailmap_file; + +/* IO helper functions */ +extern void maybe_flush_or_die(FILE *, const char *); +extern int copy_fd(int ifd, int ofd); +extern int copy_file(const char *dst, const char *src, int mode); +extern ssize_t read_in_full(int fd, void *buf, size_t count); +extern ssize_t write_in_full(int fd, const void *buf, size_t count); +extern void write_or_die(int fd, const void *buf, size_t count); +extern int write_or_whine(int fd, const void *buf, size_t count, const char *msg); +extern int write_or_whine_pipe(int fd, const void *buf, size_t count, const char *msg); +extern void fsync_or_die(int fd, const char *); + +/* pager.c */ +extern void setup_pager(void); +extern const char *pager_program; +extern int pager_in_use(void); +extern int pager_use_color; + +extern const char *editor_program; +extern const char *excludes_file; + +char *alias_lookup(const char *alias); +int split_cmdline(char *cmdline, const char ***argv); + +#define alloc_nr(x) (((x)+16)*3/2) + +/* + * Realloc the buffer pointed at by variable 'x' so that it can hold + * at least 'nr' entries; the number of entries currently allocated + * is 'alloc', using the standard growing factor alloc_nr() macro. + * + * DO NOT USE any expression with side-effect for 'x' or 'alloc'. + */ +#define ALLOC_GROW(x, nr, alloc) \ + do { \ + if ((nr) > alloc) { \ + if (alloc_nr(alloc) < (nr)) \ + alloc = (nr); \ + else \ + alloc = alloc_nr(alloc); \ + x = xrealloc((x), alloc * sizeof(*(x))); \ + } \ + } while(0) + + +static inline int is_absolute_path(const char *path) +{ + return path[0] == '/'; +} + +const char *make_absolute_path(const char *path); +const char *make_nonrelative_path(const char *path); +const char *make_relative_path(const char *abs, const char *base); +int normalize_path_copy(char *dst, const char *src); +int longest_ancestor_length(const char *path, const char *prefix_list); +char *strip_path_suffix(const char *path, const char *suffix); + +extern char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2))); +extern char *perf_path(const char *fmt, ...) __attribute__((format (printf, 1, 2))); +/* perf_mkstemp() - create tmp file honoring TMPDIR variable */ +extern int perf_mkstemp(char *path, size_t len, const char *template); + +extern char *mksnpath(char *buf, size_t n, const char *fmt, ...) + __attribute__((format (printf, 3, 4))); +extern char *perf_snpath(char *buf, size_t n, const char *fmt, ...) + __attribute__((format (printf, 3, 4))); +extern char *perf_pathdup(const char *fmt, ...) + __attribute__((format (printf, 1, 2))); + +extern size_t strlcpy(char *dest, const char *src, size_t size); + +#endif /* CACHE_H */ diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c new file mode 100644 index 000000000000..9a8c20ccc53e --- /dev/null +++ b/tools/perf/util/color.c @@ -0,0 +1,241 @@ +#include "cache.h" +#include "color.h" + +int perf_use_color_default = -1; + +static int parse_color(const char *name, int len) +{ + static const char * const color_names[] = { + "normal", "black", "red", "green", "yellow", + "blue", "magenta", "cyan", "white" + }; + char *end; + int i; + for (i = 0; i < ARRAY_SIZE(color_names); i++) { + const char *str = color_names[i]; + if (!strncasecmp(name, str, len) && !str[len]) + return i - 1; + } + i = strtol(name, &end, 10); + if (end - name == len && i >= -1 && i <= 255) + return i; + return -2; +} + +static int parse_attr(const char *name, int len) +{ + static const int attr_values[] = { 1, 2, 4, 5, 7 }; + static const char * const attr_names[] = { + "bold", "dim", "ul", "blink", "reverse" + }; + int i; + for (i = 0; i < ARRAY_SIZE(attr_names); i++) { + const char *str = attr_names[i]; + if (!strncasecmp(name, str, len) && !str[len]) + return attr_values[i]; + } + return -1; +} + +void color_parse(const char *value, const char *var, char *dst) +{ + color_parse_mem(value, strlen(value), var, dst); +} + +void color_parse_mem(const char *value, int value_len, const char *var, + char *dst) +{ + const char *ptr = value; + int len = value_len; + int attr = -1; + int fg = -2; + int bg = -2; + + if (!strncasecmp(value, "reset", len)) { + strcpy(dst, PERF_COLOR_RESET); + return; + } + + /* [fg [bg]] [attr] */ + while (len > 0) { + const char *word = ptr; + int val, wordlen = 0; + + while (len > 0 && !isspace(word[wordlen])) { + wordlen++; + len--; + } + + ptr = word + wordlen; + while (len > 0 && isspace(*ptr)) { + ptr++; + len--; + } + + val = parse_color(word, wordlen); + if (val >= -1) { + if (fg == -2) { + fg = val; + continue; + } + if (bg == -2) { + bg = val; + continue; + } + goto bad; + } + val = parse_attr(word, wordlen); + if (val < 0 || attr != -1) + goto bad; + attr = val; + } + + if (attr >= 0 || fg >= 0 || bg >= 0) { + int sep = 0; + + *dst++ = '\033'; + *dst++ = '['; + if (attr >= 0) { + *dst++ = '0' + attr; + sep++; + } + if (fg >= 0) { + if (sep++) + *dst++ = ';'; + if (fg < 8) { + *dst++ = '3'; + *dst++ = '0' + fg; + } else { + dst += sprintf(dst, "38;5;%d", fg); + } + } + if (bg >= 0) { + if (sep++) + *dst++ = ';'; + if (bg < 8) { + *dst++ = '4'; + *dst++ = '0' + bg; + } else { + dst += sprintf(dst, "48;5;%d", bg); + } + } + *dst++ = 'm'; + } + *dst = 0; + return; +bad: + die("bad color value '%.*s' for variable '%s'", value_len, value, var); +} + +int perf_config_colorbool(const char *var, const char *value, int stdout_is_tty) +{ + if (value) { + if (!strcasecmp(value, "never")) + return 0; + if (!strcasecmp(value, "always")) + return 1; + if (!strcasecmp(value, "auto")) + goto auto_color; + } + + /* Missing or explicit false to turn off colorization */ + if (!perf_config_bool(var, value)) + return 0; + + /* any normal truth value defaults to 'auto' */ + auto_color: + if (stdout_is_tty < 0) + stdout_is_tty = isatty(1); + if (stdout_is_tty || (pager_in_use() && pager_use_color)) { + char *term = getenv("TERM"); + if (term && strcmp(term, "dumb")) + return 1; + } + return 0; +} + +int perf_color_default_config(const char *var, const char *value, void *cb) +{ + if (!strcmp(var, "color.ui")) { + perf_use_color_default = perf_config_colorbool(var, value, -1); + return 0; + } + + return perf_default_config(var, value, cb); +} + +static int color_vfprintf(FILE *fp, const char *color, const char *fmt, + va_list args, const char *trail) +{ + int r = 0; + + /* + * Auto-detect: + */ + if (perf_use_color_default < 0) { + if (isatty(1) || pager_in_use()) + perf_use_color_default = 1; + else + perf_use_color_default = 0; + } + + if (perf_use_color_default && *color) + r += fprintf(fp, "%s", color); + r += vfprintf(fp, fmt, args); + if (perf_use_color_default && *color) + r += fprintf(fp, "%s", PERF_COLOR_RESET); + if (trail) + r += fprintf(fp, "%s", trail); + return r; +} + + + +int color_fprintf(FILE *fp, const char *color, const char *fmt, ...) +{ + va_list args; + int r; + + va_start(args, fmt); + r = color_vfprintf(fp, color, fmt, args, NULL); + va_end(args); + return r; +} + +int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...) +{ + va_list args; + int r; + va_start(args, fmt); + r = color_vfprintf(fp, color, fmt, args, "\n"); + va_end(args); + return r; +} + +/* + * This function splits the buffer by newlines and colors the lines individually. + * + * Returns 0 on success. + */ +int color_fwrite_lines(FILE *fp, const char *color, + size_t count, const char *buf) +{ + if (!*color) + return fwrite(buf, count, 1, fp) != 1; + while (count) { + char *p = memchr(buf, '\n', count); + if (p != buf && (fputs(color, fp) < 0 || + fwrite(buf, p ? p - buf : count, 1, fp) != 1 || + fputs(PERF_COLOR_RESET, fp) < 0)) + return -1; + if (!p) + return 0; + if (fputc('\n', fp) < 0) + return -1; + count -= p + 1 - buf; + buf = p + 1; + } + return 0; +} + + diff --git a/tools/perf/util/color.h b/tools/perf/util/color.h new file mode 100644 index 000000000000..5abfd379582b --- /dev/null +++ b/tools/perf/util/color.h @@ -0,0 +1,36 @@ +#ifndef COLOR_H +#define COLOR_H + +/* "\033[1;38;5;2xx;48;5;2xxm\0" is 23 bytes */ +#define COLOR_MAXLEN 24 + +#define PERF_COLOR_NORMAL "" +#define PERF_COLOR_RESET "\033[m" +#define PERF_COLOR_BOLD "\033[1m" +#define PERF_COLOR_RED "\033[31m" +#define PERF_COLOR_GREEN "\033[32m" +#define PERF_COLOR_YELLOW "\033[33m" +#define PERF_COLOR_BLUE "\033[34m" +#define PERF_COLOR_MAGENTA "\033[35m" +#define PERF_COLOR_CYAN "\033[36m" +#define PERF_COLOR_BG_RED "\033[41m" + +/* + * This variable stores the value of color.ui + */ +extern int perf_use_color_default; + + +/* + * Use this instead of perf_default_config if you need the value of color.ui. + */ +int perf_color_default_config(const char *var, const char *value, void *cb); + +int perf_config_colorbool(const char *var, const char *value, int stdout_is_tty); +void color_parse(const char *value, const char *var, char *dst); +void color_parse_mem(const char *value, int len, const char *var, char *dst); +int color_fprintf(FILE *fp, const char *color, const char *fmt, ...); +int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...); +int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf); + +#endif /* COLOR_H */ diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c new file mode 100644 index 000000000000..3dd13faa6a27 --- /dev/null +++ b/tools/perf/util/config.c @@ -0,0 +1,873 @@ +/* + * GIT - The information manager from hell + * + * Copyright (C) Linus Torvalds, 2005 + * Copyright (C) Johannes Schindelin, 2005 + * + */ +#include "util.h" +#include "cache.h" +#include "exec_cmd.h" + +#define MAXNAME (256) + +static FILE *config_file; +static const char *config_file_name; +static int config_linenr; +static int config_file_eof; + +const char *config_exclusive_filename = NULL; + +static int get_next_char(void) +{ + int c; + FILE *f; + + c = '\n'; + if ((f = config_file) != NULL) { + c = fgetc(f); + if (c == '\r') { + /* DOS like systems */ + c = fgetc(f); + if (c != '\n') { + ungetc(c, f); + c = '\r'; + } + } + if (c == '\n') + config_linenr++; + if (c == EOF) { + config_file_eof = 1; + c = '\n'; + } + } + return c; +} + +static char *parse_value(void) +{ + static char value[1024]; + int quote = 0, comment = 0, len = 0, space = 0; + + for (;;) { + int c = get_next_char(); + if (len >= sizeof(value) - 1) + return NULL; + if (c == '\n') { + if (quote) + return NULL; + value[len] = 0; + return value; + } + if (comment) + continue; + if (isspace(c) && !quote) { + space = 1; + continue; + } + if (!quote) { + if (c == ';' || c == '#') { + comment = 1; + continue; + } + } + if (space) { + if (len) + value[len++] = ' '; + space = 0; + } + if (c == '\\') { + c = get_next_char(); + switch (c) { + case '\n': + continue; + case 't': + c = '\t'; + break; + case 'b': + c = '\b'; + break; + case 'n': + c = '\n'; + break; + /* Some characters escape as themselves */ + case '\\': case '"': + break; + /* Reject unknown escape sequences */ + default: + return NULL; + } + value[len++] = c; + continue; + } + if (c == '"') { + quote = 1-quote; + continue; + } + value[len++] = c; + } +} + +static inline int iskeychar(int c) +{ + return isalnum(c) || c == '-'; +} + +static int get_value(config_fn_t fn, void *data, char *name, unsigned int len) +{ + int c; + char *value; + + /* Get the full name */ + for (;;) { + c = get_next_char(); + if (config_file_eof) + break; + if (!iskeychar(c)) + break; + name[len++] = tolower(c); + if (len >= MAXNAME) + return -1; + } + name[len] = 0; + while (c == ' ' || c == '\t') + c = get_next_char(); + + value = NULL; + if (c != '\n') { + if (c != '=') + return -1; + value = parse_value(); + if (!value) + return -1; + } + return fn(name, value, data); +} + +static int get_extended_base_var(char *name, int baselen, int c) +{ + do { + if (c == '\n') + return -1; + c = get_next_char(); + } while (isspace(c)); + + /* We require the format to be '[base "extension"]' */ + if (c != '"') + return -1; + name[baselen++] = '.'; + + for (;;) { + int c = get_next_char(); + if (c == '\n') + return -1; + if (c == '"') + break; + if (c == '\\') { + c = get_next_char(); + if (c == '\n') + return -1; + } + name[baselen++] = c; + if (baselen > MAXNAME / 2) + return -1; + } + + /* Final ']' */ + if (get_next_char() != ']') + return -1; + return baselen; +} + +static int get_base_var(char *name) +{ + int baselen = 0; + + for (;;) { + int c = get_next_char(); + if (config_file_eof) + return -1; + if (c == ']') + return baselen; + if (isspace(c)) + return get_extended_base_var(name, baselen, c); + if (!iskeychar(c) && c != '.') + return -1; + if (baselen > MAXNAME / 2) + return -1; + name[baselen++] = tolower(c); + } +} + +static int perf_parse_file(config_fn_t fn, void *data) +{ + int comment = 0; + int baselen = 0; + static char var[MAXNAME]; + + /* U+FEFF Byte Order Mark in UTF8 */ + static const unsigned char *utf8_bom = (unsigned char *) "\xef\xbb\xbf"; + const unsigned char *bomptr = utf8_bom; + + for (;;) { + int c = get_next_char(); + if (bomptr && *bomptr) { + /* We are at the file beginning; skip UTF8-encoded BOM + * if present. Sane editors won't put this in on their + * own, but e.g. Windows Notepad will do it happily. */ + if ((unsigned char) c == *bomptr) { + bomptr++; + continue; + } else { + /* Do not tolerate partial BOM. */ + if (bomptr != utf8_bom) + break; + /* No BOM at file beginning. Cool. */ + bomptr = NULL; + } + } + if (c == '\n') { + if (config_file_eof) + return 0; + comment = 0; + continue; + } + if (comment || isspace(c)) + continue; + if (c == '#' || c == ';') { + comment = 1; + continue; + } + if (c == '[') { + baselen = get_base_var(var); + if (baselen <= 0) + break; + var[baselen++] = '.'; + var[baselen] = 0; + continue; + } + if (!isalpha(c)) + break; + var[baselen] = tolower(c); + if (get_value(fn, data, var, baselen+1) < 0) + break; + } + die("bad config file line %d in %s", config_linenr, config_file_name); +} + +static int parse_unit_factor(const char *end, unsigned long *val) +{ + if (!*end) + return 1; + else if (!strcasecmp(end, "k")) { + *val *= 1024; + return 1; + } + else if (!strcasecmp(end, "m")) { + *val *= 1024 * 1024; + return 1; + } + else if (!strcasecmp(end, "g")) { + *val *= 1024 * 1024 * 1024; + return 1; + } + return 0; +} + +static int perf_parse_long(const char *value, long *ret) +{ + if (value && *value) { + char *end; + long val = strtol(value, &end, 0); + unsigned long factor = 1; + if (!parse_unit_factor(end, &factor)) + return 0; + *ret = val * factor; + return 1; + } + return 0; +} + +int perf_parse_ulong(const char *value, unsigned long *ret) +{ + if (value && *value) { + char *end; + unsigned long val = strtoul(value, &end, 0); + if (!parse_unit_factor(end, &val)) + return 0; + *ret = val; + return 1; + } + return 0; +} + +static void die_bad_config(const char *name) +{ + if (config_file_name) + die("bad config value for '%s' in %s", name, config_file_name); + die("bad config value for '%s'", name); +} + +int perf_config_int(const char *name, const char *value) +{ + long ret = 0; + if (!perf_parse_long(value, &ret)) + die_bad_config(name); + return ret; +} + +unsigned long perf_config_ulong(const char *name, const char *value) +{ + unsigned long ret; + if (!perf_parse_ulong(value, &ret)) + die_bad_config(name); + return ret; +} + +int perf_config_bool_or_int(const char *name, const char *value, int *is_bool) +{ + *is_bool = 1; + if (!value) + return 1; + if (!*value) + return 0; + if (!strcasecmp(value, "true") || !strcasecmp(value, "yes") || !strcasecmp(value, "on")) + return 1; + if (!strcasecmp(value, "false") || !strcasecmp(value, "no") || !strcasecmp(value, "off")) + return 0; + *is_bool = 0; + return perf_config_int(name, value); +} + +int perf_config_bool(const char *name, const char *value) +{ + int discard; + return !!perf_config_bool_or_int(name, value, &discard); +} + +int perf_config_string(const char **dest, const char *var, const char *value) +{ + if (!value) + return config_error_nonbool(var); + *dest = strdup(value); + return 0; +} + +static int perf_default_core_config(const char *var, const char *value) +{ + /* Add other config variables here and to Documentation/config.txt. */ + return 0; +} + +int perf_default_config(const char *var, const char *value, void *dummy) +{ + if (!prefixcmp(var, "core.")) + return perf_default_core_config(var, value); + + /* Add other config variables here and to Documentation/config.txt. */ + return 0; +} + +int perf_config_from_file(config_fn_t fn, const char *filename, void *data) +{ + int ret; + FILE *f = fopen(filename, "r"); + + ret = -1; + if (f) { + config_file = f; + config_file_name = filename; + config_linenr = 1; + config_file_eof = 0; + ret = perf_parse_file(fn, data); + fclose(f); + config_file_name = NULL; + } + return ret; +} + +const char *perf_etc_perfconfig(void) +{ + static const char *system_wide; + if (!system_wide) + system_wide = system_path(ETC_PERFCONFIG); + return system_wide; +} + +static int perf_env_bool(const char *k, int def) +{ + const char *v = getenv(k); + return v ? perf_config_bool(k, v) : def; +} + +int perf_config_system(void) +{ + return !perf_env_bool("PERF_CONFIG_NOSYSTEM", 0); +} + +int perf_config_global(void) +{ + return !perf_env_bool("PERF_CONFIG_NOGLOBAL", 0); +} + +int perf_config(config_fn_t fn, void *data) +{ + int ret = 0, found = 0; + char *repo_config = NULL; + const char *home = NULL; + + /* Setting $PERF_CONFIG makes perf read _only_ the given config file. */ + if (config_exclusive_filename) + return perf_config_from_file(fn, config_exclusive_filename, data); + if (perf_config_system() && !access(perf_etc_perfconfig(), R_OK)) { + ret += perf_config_from_file(fn, perf_etc_perfconfig(), + data); + found += 1; + } + + home = getenv("HOME"); + if (perf_config_global() && home) { + char *user_config = strdup(mkpath("%s/.perfconfig", home)); + if (!access(user_config, R_OK)) { + ret += perf_config_from_file(fn, user_config, data); + found += 1; + } + free(user_config); + } + + repo_config = perf_pathdup("config"); + if (!access(repo_config, R_OK)) { + ret += perf_config_from_file(fn, repo_config, data); + found += 1; + } + free(repo_config); + if (found == 0) + return -1; + return ret; +} + +/* + * Find all the stuff for perf_config_set() below. + */ + +#define MAX_MATCHES 512 + +static struct { + int baselen; + char* key; + int do_not_match; + regex_t* value_regex; + int multi_replace; + size_t offset[MAX_MATCHES]; + enum { START, SECTION_SEEN, SECTION_END_SEEN, KEY_SEEN } state; + int seen; +} store; + +static int matches(const char* key, const char* value) +{ + return !strcmp(key, store.key) && + (store.value_regex == NULL || + (store.do_not_match ^ + !regexec(store.value_regex, value, 0, NULL, 0))); +} + +static int store_aux(const char* key, const char* value, void *cb) +{ + const char *ep; + size_t section_len; + + switch (store.state) { + case KEY_SEEN: + if (matches(key, value)) { + if (store.seen == 1 && store.multi_replace == 0) { + warning("%s has multiple values", key); + } else if (store.seen >= MAX_MATCHES) { + error("too many matches for %s", key); + return 1; + } + + store.offset[store.seen] = ftell(config_file); + store.seen++; + } + break; + case SECTION_SEEN: + /* + * What we are looking for is in store.key (both + * section and var), and its section part is baselen + * long. We found key (again, both section and var). + * We would want to know if this key is in the same + * section as what we are looking for. We already + * know we are in the same section as what should + * hold store.key. + */ + ep = strrchr(key, '.'); + section_len = ep - key; + + if ((section_len != store.baselen) || + memcmp(key, store.key, section_len+1)) { + store.state = SECTION_END_SEEN; + break; + } + + /* + * Do not increment matches: this is no match, but we + * just made sure we are in the desired section. + */ + store.offset[store.seen] = ftell(config_file); + /* fallthru */ + case SECTION_END_SEEN: + case START: + if (matches(key, value)) { + store.offset[store.seen] = ftell(config_file); + store.state = KEY_SEEN; + store.seen++; + } else { + if (strrchr(key, '.') - key == store.baselen && + !strncmp(key, store.key, store.baselen)) { + store.state = SECTION_SEEN; + store.offset[store.seen] = ftell(config_file); + } + } + } + return 0; +} + +static int store_write_section(int fd, const char* key) +{ + const char *dot; + int i, success; + struct strbuf sb = STRBUF_INIT; + + dot = memchr(key, '.', store.baselen); + if (dot) { + strbuf_addf(&sb, "[%.*s \"", (int)(dot - key), key); + for (i = dot - key + 1; i < store.baselen; i++) { + if (key[i] == '"' || key[i] == '\\') + strbuf_addch(&sb, '\\'); + strbuf_addch(&sb, key[i]); + } + strbuf_addstr(&sb, "\"]\n"); + } else { + strbuf_addf(&sb, "[%.*s]\n", store.baselen, key); + } + + success = write_in_full(fd, sb.buf, sb.len) == sb.len; + strbuf_release(&sb); + + return success; +} + +static int store_write_pair(int fd, const char* key, const char* value) +{ + int i, success; + int length = strlen(key + store.baselen + 1); + const char *quote = ""; + struct strbuf sb = STRBUF_INIT; + + /* + * Check to see if the value needs to be surrounded with a dq pair. + * Note that problematic characters are always backslash-quoted; this + * check is about not losing leading or trailing SP and strings that + * follow beginning-of-comment characters (i.e. ';' and '#') by the + * configuration parser. + */ + if (value[0] == ' ') + quote = "\""; + for (i = 0; value[i]; i++) + if (value[i] == ';' || value[i] == '#') + quote = "\""; + if (i && value[i - 1] == ' ') + quote = "\""; + + strbuf_addf(&sb, "\t%.*s = %s", + length, key + store.baselen + 1, quote); + + for (i = 0; value[i]; i++) + switch (value[i]) { + case '\n': + strbuf_addstr(&sb, "\\n"); + break; + case '\t': + strbuf_addstr(&sb, "\\t"); + break; + case '"': + case '\\': + strbuf_addch(&sb, '\\'); + default: + strbuf_addch(&sb, value[i]); + break; + } + strbuf_addf(&sb, "%s\n", quote); + + success = write_in_full(fd, sb.buf, sb.len) == sb.len; + strbuf_release(&sb); + + return success; +} + +static ssize_t find_beginning_of_line(const char* contents, size_t size, + size_t offset_, int* found_bracket) +{ + size_t equal_offset = size, bracket_offset = size; + ssize_t offset; + +contline: + for (offset = offset_-2; offset > 0 + && contents[offset] != '\n'; offset--) + switch (contents[offset]) { + case '=': equal_offset = offset; break; + case ']': bracket_offset = offset; break; + } + if (offset > 0 && contents[offset-1] == '\\') { + offset_ = offset; + goto contline; + } + if (bracket_offset < equal_offset) { + *found_bracket = 1; + offset = bracket_offset+1; + } else + offset++; + + return offset; +} + +int perf_config_set(const char* key, const char* value) +{ + return perf_config_set_multivar(key, value, NULL, 0); +} + +/* + * If value==NULL, unset in (remove from) config, + * if value_regex!=NULL, disregard key/value pairs where value does not match. + * if multi_replace==0, nothing, or only one matching key/value is replaced, + * else all matching key/values (regardless how many) are removed, + * before the new pair is written. + * + * Returns 0 on success. + * + * This function does this: + * + * - it locks the config file by creating ".perf/config.lock" + * + * - it then parses the config using store_aux() as validator to find + * the position on the key/value pair to replace. If it is to be unset, + * it must be found exactly once. + * + * - the config file is mmap()ed and the part before the match (if any) is + * written to the lock file, then the changed part and the rest. + * + * - the config file is removed and the lock file rename()d to it. + * + */ +int perf_config_set_multivar(const char* key, const char* value, + const char* value_regex, int multi_replace) +{ + int i, dot; + int fd = -1, in_fd; + int ret = 0; + char* config_filename; + const char* last_dot = strrchr(key, '.'); + + if (config_exclusive_filename) + config_filename = strdup(config_exclusive_filename); + else + config_filename = perf_pathdup("config"); + + /* + * Since "key" actually contains the section name and the real + * key name separated by a dot, we have to know where the dot is. + */ + + if (last_dot == NULL) { + error("key does not contain a section: %s", key); + ret = 2; + goto out_free; + } + store.baselen = last_dot - key; + + store.multi_replace = multi_replace; + + /* + * Validate the key and while at it, lower case it for matching. + */ + store.key = malloc(strlen(key) + 1); + dot = 0; + for (i = 0; key[i]; i++) { + unsigned char c = key[i]; + if (c == '.') + dot = 1; + /* Leave the extended basename untouched.. */ + if (!dot || i > store.baselen) { + if (!iskeychar(c) || (i == store.baselen+1 && !isalpha(c))) { + error("invalid key: %s", key); + free(store.key); + ret = 1; + goto out_free; + } + c = tolower(c); + } else if (c == '\n') { + error("invalid key (newline): %s", key); + free(store.key); + ret = 1; + goto out_free; + } + store.key[i] = c; + } + store.key[i] = 0; + + /* + * If .perf/config does not exist yet, write a minimal version. + */ + in_fd = open(config_filename, O_RDONLY); + if ( in_fd < 0 ) { + free(store.key); + + if ( ENOENT != errno ) { + error("opening %s: %s", config_filename, + strerror(errno)); + ret = 3; /* same as "invalid config file" */ + goto out_free; + } + /* if nothing to unset, error out */ + if (value == NULL) { + ret = 5; + goto out_free; + } + + store.key = (char*)key; + if (!store_write_section(fd, key) || + !store_write_pair(fd, key, value)) + goto write_err_out; + } else { + struct stat st; + char* contents; + size_t contents_sz, copy_begin, copy_end; + int i, new_line = 0; + + if (value_regex == NULL) + store.value_regex = NULL; + else { + if (value_regex[0] == '!') { + store.do_not_match = 1; + value_regex++; + } else + store.do_not_match = 0; + + store.value_regex = (regex_t*)malloc(sizeof(regex_t)); + if (regcomp(store.value_regex, value_regex, + REG_EXTENDED)) { + error("invalid pattern: %s", value_regex); + free(store.value_regex); + ret = 6; + goto out_free; + } + } + + store.offset[0] = 0; + store.state = START; + store.seen = 0; + + /* + * After this, store.offset will contain the *end* offset + * of the last match, or remain at 0 if no match was found. + * As a side effect, we make sure to transform only a valid + * existing config file. + */ + if (perf_config_from_file(store_aux, config_filename, NULL)) { + error("invalid config file %s", config_filename); + free(store.key); + if (store.value_regex != NULL) { + regfree(store.value_regex); + free(store.value_regex); + } + ret = 3; + goto out_free; + } + + free(store.key); + if (store.value_regex != NULL) { + regfree(store.value_regex); + free(store.value_regex); + } + + /* if nothing to unset, or too many matches, error out */ + if ((store.seen == 0 && value == NULL) || + (store.seen > 1 && multi_replace == 0)) { + ret = 5; + goto out_free; + } + + fstat(in_fd, &st); + contents_sz = xsize_t(st.st_size); + contents = mmap(NULL, contents_sz, PROT_READ, + MAP_PRIVATE, in_fd, 0); + close(in_fd); + + if (store.seen == 0) + store.seen = 1; + + for (i = 0, copy_begin = 0; i < store.seen; i++) { + if (store.offset[i] == 0) { + store.offset[i] = copy_end = contents_sz; + } else if (store.state != KEY_SEEN) { + copy_end = store.offset[i]; + } else + copy_end = find_beginning_of_line( + contents, contents_sz, + store.offset[i]-2, &new_line); + + if (copy_end > 0 && contents[copy_end-1] != '\n') + new_line = 1; + + /* write the first part of the config */ + if (copy_end > copy_begin) { + if (write_in_full(fd, contents + copy_begin, + copy_end - copy_begin) < + copy_end - copy_begin) + goto write_err_out; + if (new_line && + write_in_full(fd, "\n", 1) != 1) + goto write_err_out; + } + copy_begin = store.offset[i]; + } + + /* write the pair (value == NULL means unset) */ + if (value != NULL) { + if (store.state == START) { + if (!store_write_section(fd, key)) + goto write_err_out; + } + if (!store_write_pair(fd, key, value)) + goto write_err_out; + } + + /* write the rest of the config */ + if (copy_begin < contents_sz) + if (write_in_full(fd, contents + copy_begin, + contents_sz - copy_begin) < + contents_sz - copy_begin) + goto write_err_out; + + munmap(contents, contents_sz); + } + + ret = 0; + +out_free: + free(config_filename); + return ret; + +write_err_out: + goto out_free; + +} + +/* + * Call this to report error for your variable that should not + * get a boolean value (i.e. "[my] var" means "true"). + */ +int config_error_nonbool(const char *var) +{ + return error("Missing value for '%s'", var); +} diff --git a/tools/perf/util/ctype.c b/tools/perf/util/ctype.c new file mode 100644 index 000000000000..0b791bd346bc --- /dev/null +++ b/tools/perf/util/ctype.c @@ -0,0 +1,31 @@ +/* + * Sane locale-independent, ASCII ctype. + * + * No surprises, and works with signed and unsigned chars. + */ +#include "cache.h" + +enum { + S = GIT_SPACE, + A = GIT_ALPHA, + D = GIT_DIGIT, + G = GIT_GLOB_SPECIAL, /* *, ?, [, \\ */ + R = GIT_REGEX_SPECIAL, /* $, (, ), +, ., ^, {, | * */ + P = GIT_PRINT_EXTRA, /* printable - alpha - digit - glob - regex */ + + PS = GIT_SPACE | GIT_PRINT_EXTRA, +}; + +unsigned char sane_ctype[256] = { +/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ + + 0, 0, 0, 0, 0, 0, 0, 0, 0, S, S, 0, 0, S, 0, 0, /* 0.. 15 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16.. 31 */ + PS,P, P, P, R, P, P, P, R, R, G, R, P, P, R, P, /* 32.. 47 */ + D, D, D, D, D, D, D, D, D, D, P, P, P, P, P, G, /* 48.. 63 */ + P, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, /* 64.. 79 */ + A, A, A, A, A, A, A, A, A, A, A, G, G, P, R, P, /* 80.. 95 */ + P, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, /* 96..111 */ + A, A, A, A, A, A, A, A, A, A, A, R, R, P, P, 0, /* 112..127 */ + /* Nothing in the 128.. range */ +}; diff --git a/tools/perf/util/environment.c b/tools/perf/util/environment.c new file mode 100644 index 000000000000..275b0ee345f5 --- /dev/null +++ b/tools/perf/util/environment.c @@ -0,0 +1,9 @@ +/* + * We put all the perf config variables in this same object + * file, so that programs can link against the config parser + * without having to link against all the rest of perf. + */ +#include "cache.h" + +const char *pager_program; +int pager_use_color = 1; diff --git a/tools/perf/util/exec_cmd.c b/tools/perf/util/exec_cmd.c new file mode 100644 index 000000000000..d39292263153 --- /dev/null +++ b/tools/perf/util/exec_cmd.c @@ -0,0 +1,165 @@ +#include "cache.h" +#include "exec_cmd.h" +#include "quote.h" +#define MAX_ARGS 32 + +extern char **environ; +static const char *argv_exec_path; +static const char *argv0_path; + +const char *system_path(const char *path) +{ +#ifdef RUNTIME_PREFIX + static const char *prefix; +#else + static const char *prefix = PREFIX; +#endif + struct strbuf d = STRBUF_INIT; + + if (is_absolute_path(path)) + return path; + +#ifdef RUNTIME_PREFIX + assert(argv0_path); + assert(is_absolute_path(argv0_path)); + + if (!prefix && + !(prefix = strip_path_suffix(argv0_path, PERF_EXEC_PATH)) && + !(prefix = strip_path_suffix(argv0_path, BINDIR)) && + !(prefix = strip_path_suffix(argv0_path, "perf"))) { + prefix = PREFIX; + fprintf(stderr, "RUNTIME_PREFIX requested, " + "but prefix computation failed. " + "Using static fallback '%s'.\n", prefix); + } +#endif + + strbuf_addf(&d, "%s/%s", prefix, path); + path = strbuf_detach(&d, NULL); + return path; +} + +const char *perf_extract_argv0_path(const char *argv0) +{ + const char *slash; + + if (!argv0 || !*argv0) + return NULL; + slash = argv0 + strlen(argv0); + + while (argv0 <= slash && !is_dir_sep(*slash)) + slash--; + + if (slash >= argv0) { + argv0_path = strndup(argv0, slash - argv0); + return slash + 1; + } + + return argv0; +} + +void perf_set_argv_exec_path(const char *exec_path) +{ + argv_exec_path = exec_path; + /* + * Propagate this setting to external programs. + */ + setenv(EXEC_PATH_ENVIRONMENT, exec_path, 1); +} + + +/* Returns the highest-priority, location to look for perf programs. */ +const char *perf_exec_path(void) +{ + const char *env; + + if (argv_exec_path) + return argv_exec_path; + + env = getenv(EXEC_PATH_ENVIRONMENT); + if (env && *env) { + return env; + } + + return system_path(PERF_EXEC_PATH); +} + +static void add_path(struct strbuf *out, const char *path) +{ + if (path && *path) { + if (is_absolute_path(path)) + strbuf_addstr(out, path); + else + strbuf_addstr(out, make_nonrelative_path(path)); + + strbuf_addch(out, PATH_SEP); + } +} + +void setup_path(void) +{ + const char *old_path = getenv("PATH"); + struct strbuf new_path = STRBUF_INIT; + + add_path(&new_path, perf_exec_path()); + add_path(&new_path, argv0_path); + + if (old_path) + strbuf_addstr(&new_path, old_path); + else + strbuf_addstr(&new_path, "/usr/local/bin:/usr/bin:/bin"); + + setenv("PATH", new_path.buf, 1); + + strbuf_release(&new_path); +} + +const char **prepare_perf_cmd(const char **argv) +{ + int argc; + const char **nargv; + + for (argc = 0; argv[argc]; argc++) + ; /* just counting */ + nargv = malloc(sizeof(*nargv) * (argc + 2)); + + nargv[0] = "perf"; + for (argc = 0; argv[argc]; argc++) + nargv[argc + 1] = argv[argc]; + nargv[argc + 1] = NULL; + return nargv; +} + +int execv_perf_cmd(const char **argv) { + const char **nargv = prepare_perf_cmd(argv); + + /* execvp() can only ever return if it fails */ + execvp("perf", (char **)nargv); + + free(nargv); + return -1; +} + + +int execl_perf_cmd(const char *cmd,...) +{ + int argc; + const char *argv[MAX_ARGS + 1]; + const char *arg; + va_list param; + + va_start(param, cmd); + argv[0] = cmd; + argc = 1; + while (argc < MAX_ARGS) { + arg = argv[argc++] = va_arg(param, char *); + if (!arg) + break; + } + va_end(param); + if (MAX_ARGS <= argc) + return error("too many args to run %s", cmd); + + argv[argc] = NULL; + return execv_perf_cmd(argv); +} diff --git a/tools/perf/util/exec_cmd.h b/tools/perf/util/exec_cmd.h new file mode 100644 index 000000000000..effe25eb1545 --- /dev/null +++ b/tools/perf/util/exec_cmd.h @@ -0,0 +1,13 @@ +#ifndef PERF_EXEC_CMD_H +#define PERF_EXEC_CMD_H + +extern void perf_set_argv_exec_path(const char *exec_path); +extern const char *perf_extract_argv0_path(const char *path); +extern const char *perf_exec_path(void); +extern void setup_path(void); +extern const char **prepare_perf_cmd(const char **argv); +extern int execv_perf_cmd(const char **argv); /* NULL terminated */ +extern int execl_perf_cmd(const char *cmd, ...); +extern const char *system_path(const char *path); + +#endif /* PERF_EXEC_CMD_H */ diff --git a/tools/perf/util/generate-cmdlist.sh b/tools/perf/util/generate-cmdlist.sh new file mode 100755 index 000000000000..f06f6fd148f8 --- /dev/null +++ b/tools/perf/util/generate-cmdlist.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +echo "/* Automatically generated by $0 */ +struct cmdname_help +{ + char name[16]; + char help[80]; +}; + +static struct cmdname_help common_cmds[] = {" + +sed -n -e 's/^perf-\([^ ]*\)[ ].* common.*/\1/p' command-list.txt | +sort | +while read cmd +do + sed -n ' + /^NAME/,/perf-'"$cmd"'/H + ${ + x + s/.*perf-'"$cmd"' - \(.*\)/ {"'"$cmd"'", "\1"},/ + p + }' "Documentation/perf-$cmd.txt" +done +echo "};" diff --git a/tools/perf/util/help.c b/tools/perf/util/help.c new file mode 100644 index 000000000000..6653f7dd1d78 --- /dev/null +++ b/tools/perf/util/help.c @@ -0,0 +1,367 @@ +#include "cache.h" +#include "../builtin.h" +#include "exec_cmd.h" +#include "levenshtein.h" +#include "help.h" + +/* most GUI terminals set COLUMNS (although some don't export it) */ +static int term_columns(void) +{ + char *col_string = getenv("COLUMNS"); + int n_cols; + + if (col_string && (n_cols = atoi(col_string)) > 0) + return n_cols; + +#ifdef TIOCGWINSZ + { + struct winsize ws; + if (!ioctl(1, TIOCGWINSZ, &ws)) { + if (ws.ws_col) + return ws.ws_col; + } + } +#endif + + return 80; +} + +void add_cmdname(struct cmdnames *cmds, const char *name, int len) +{ + struct cmdname *ent = malloc(sizeof(*ent) + len + 1); + + ent->len = len; + memcpy(ent->name, name, len); + ent->name[len] = 0; + + ALLOC_GROW(cmds->names, cmds->cnt + 1, cmds->alloc); + cmds->names[cmds->cnt++] = ent; +} + +static void clean_cmdnames(struct cmdnames *cmds) +{ + int i; + for (i = 0; i < cmds->cnt; ++i) + free(cmds->names[i]); + free(cmds->names); + cmds->cnt = 0; + cmds->alloc = 0; +} + +static int cmdname_compare(const void *a_, const void *b_) +{ + struct cmdname *a = *(struct cmdname **)a_; + struct cmdname *b = *(struct cmdname **)b_; + return strcmp(a->name, b->name); +} + +static void uniq(struct cmdnames *cmds) +{ + int i, j; + + if (!cmds->cnt) + return; + + for (i = j = 1; i < cmds->cnt; i++) + if (strcmp(cmds->names[i]->name, cmds->names[i-1]->name)) + cmds->names[j++] = cmds->names[i]; + + cmds->cnt = j; +} + +void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes) +{ + int ci, cj, ei; + int cmp; + + ci = cj = ei = 0; + while (ci < cmds->cnt && ei < excludes->cnt) { + cmp = strcmp(cmds->names[ci]->name, excludes->names[ei]->name); + if (cmp < 0) + cmds->names[cj++] = cmds->names[ci++]; + else if (cmp == 0) + ci++, ei++; + else if (cmp > 0) + ei++; + } + + while (ci < cmds->cnt) + cmds->names[cj++] = cmds->names[ci++]; + + cmds->cnt = cj; +} + +static void pretty_print_string_list(struct cmdnames *cmds, int longest) +{ + int cols = 1, rows; + int space = longest + 1; /* min 1 SP between words */ + int max_cols = term_columns() - 1; /* don't print *on* the edge */ + int i, j; + + if (space < max_cols) + cols = max_cols / space; + rows = (cmds->cnt + cols - 1) / cols; + + for (i = 0; i < rows; i++) { + printf(" "); + + for (j = 0; j < cols; j++) { + int n = j * rows + i; + int size = space; + if (n >= cmds->cnt) + break; + if (j == cols-1 || n + rows >= cmds->cnt) + size = 1; + printf("%-*s", size, cmds->names[n]->name); + } + putchar('\n'); + } +} + +static int is_executable(const char *name) +{ + struct stat st; + + if (stat(name, &st) || /* stat, not lstat */ + !S_ISREG(st.st_mode)) + return 0; + +#ifdef __MINGW32__ + /* cannot trust the executable bit, peek into the file instead */ + char buf[3] = { 0 }; + int n; + int fd = open(name, O_RDONLY); + st.st_mode &= ~S_IXUSR; + if (fd >= 0) { + n = read(fd, buf, 2); + if (n == 2) + /* DOS executables start with "MZ" */ + if (!strcmp(buf, "#!") || !strcmp(buf, "MZ")) + st.st_mode |= S_IXUSR; + close(fd); + } +#endif + return st.st_mode & S_IXUSR; +} + +static void list_commands_in_dir(struct cmdnames *cmds, + const char *path, + const char *prefix) +{ + int prefix_len; + DIR *dir = opendir(path); + struct dirent *de; + struct strbuf buf = STRBUF_INIT; + int len; + + if (!dir) + return; + if (!prefix) + prefix = "perf-"; + prefix_len = strlen(prefix); + + strbuf_addf(&buf, "%s/", path); + len = buf.len; + + while ((de = readdir(dir)) != NULL) { + int entlen; + + if (prefixcmp(de->d_name, prefix)) + continue; + + strbuf_setlen(&buf, len); + strbuf_addstr(&buf, de->d_name); + if (!is_executable(buf.buf)) + continue; + + entlen = strlen(de->d_name) - prefix_len; + if (has_extension(de->d_name, ".exe")) + entlen -= 4; + + add_cmdname(cmds, de->d_name + prefix_len, entlen); + } + closedir(dir); + strbuf_release(&buf); +} + +void load_command_list(const char *prefix, + struct cmdnames *main_cmds, + struct cmdnames *other_cmds) +{ + const char *env_path = getenv("PATH"); + const char *exec_path = perf_exec_path(); + + if (exec_path) { + list_commands_in_dir(main_cmds, exec_path, prefix); + qsort(main_cmds->names, main_cmds->cnt, + sizeof(*main_cmds->names), cmdname_compare); + uniq(main_cmds); + } + + if (env_path) { + char *paths, *path, *colon; + path = paths = strdup(env_path); + while (1) { + if ((colon = strchr(path, PATH_SEP))) + *colon = 0; + if (!exec_path || strcmp(path, exec_path)) + list_commands_in_dir(other_cmds, path, prefix); + + if (!colon) + break; + path = colon + 1; + } + free(paths); + + qsort(other_cmds->names, other_cmds->cnt, + sizeof(*other_cmds->names), cmdname_compare); + uniq(other_cmds); + } + exclude_cmds(other_cmds, main_cmds); +} + +void list_commands(const char *title, struct cmdnames *main_cmds, + struct cmdnames *other_cmds) +{ + int i, longest = 0; + + for (i = 0; i < main_cmds->cnt; i++) + if (longest < main_cmds->names[i]->len) + longest = main_cmds->names[i]->len; + for (i = 0; i < other_cmds->cnt; i++) + if (longest < other_cmds->names[i]->len) + longest = other_cmds->names[i]->len; + + if (main_cmds->cnt) { + const char *exec_path = perf_exec_path(); + printf("available %s in '%s'\n", title, exec_path); + printf("----------------"); + mput_char('-', strlen(title) + strlen(exec_path)); + putchar('\n'); + pretty_print_string_list(main_cmds, longest); + putchar('\n'); + } + + if (other_cmds->cnt) { + printf("%s available from elsewhere on your $PATH\n", title); + printf("---------------------------------------"); + mput_char('-', strlen(title)); + putchar('\n'); + pretty_print_string_list(other_cmds, longest); + putchar('\n'); + } +} + +int is_in_cmdlist(struct cmdnames *c, const char *s) +{ + int i; + for (i = 0; i < c->cnt; i++) + if (!strcmp(s, c->names[i]->name)) + return 1; + return 0; +} + +static int autocorrect; +static struct cmdnames aliases; + +static int perf_unknown_cmd_config(const char *var, const char *value, void *cb) +{ + if (!strcmp(var, "help.autocorrect")) + autocorrect = perf_config_int(var,value); + /* Also use aliases for command lookup */ + if (!prefixcmp(var, "alias.")) + add_cmdname(&aliases, var + 6, strlen(var + 6)); + + return perf_default_config(var, value, cb); +} + +static int levenshtein_compare(const void *p1, const void *p2) +{ + const struct cmdname *const *c1 = p1, *const *c2 = p2; + const char *s1 = (*c1)->name, *s2 = (*c2)->name; + int l1 = (*c1)->len; + int l2 = (*c2)->len; + return l1 != l2 ? l1 - l2 : strcmp(s1, s2); +} + +static void add_cmd_list(struct cmdnames *cmds, struct cmdnames *old) +{ + int i; + ALLOC_GROW(cmds->names, cmds->cnt + old->cnt, cmds->alloc); + + for (i = 0; i < old->cnt; i++) + cmds->names[cmds->cnt++] = old->names[i]; + free(old->names); + old->cnt = 0; + old->names = NULL; +} + +const char *help_unknown_cmd(const char *cmd) +{ + int i, n = 0, best_similarity = 0; + struct cmdnames main_cmds, other_cmds; + + memset(&main_cmds, 0, sizeof(main_cmds)); + memset(&other_cmds, 0, sizeof(main_cmds)); + memset(&aliases, 0, sizeof(aliases)); + + perf_config(perf_unknown_cmd_config, NULL); + + load_command_list("perf-", &main_cmds, &other_cmds); + + add_cmd_list(&main_cmds, &aliases); + add_cmd_list(&main_cmds, &other_cmds); + qsort(main_cmds.names, main_cmds.cnt, + sizeof(main_cmds.names), cmdname_compare); + uniq(&main_cmds); + + if (main_cmds.cnt) { + /* This reuses cmdname->len for similarity index */ + for (i = 0; i < main_cmds.cnt; ++i) + main_cmds.names[i]->len = + levenshtein(cmd, main_cmds.names[i]->name, 0, 2, 1, 4); + + qsort(main_cmds.names, main_cmds.cnt, + sizeof(*main_cmds.names), levenshtein_compare); + + best_similarity = main_cmds.names[0]->len; + n = 1; + while (n < main_cmds.cnt && best_similarity == main_cmds.names[n]->len) + ++n; + } + + if (autocorrect && n == 1) { + const char *assumed = main_cmds.names[0]->name; + + main_cmds.names[0] = NULL; + clean_cmdnames(&main_cmds); + fprintf(stderr, "WARNING: You called a Git program named '%s', " + "which does not exist.\n" + "Continuing under the assumption that you meant '%s'\n", + cmd, assumed); + if (autocorrect > 0) { + fprintf(stderr, "in %0.1f seconds automatically...\n", + (float)autocorrect/10.0); + poll(NULL, 0, autocorrect * 100); + } + return assumed; + } + + fprintf(stderr, "perf: '%s' is not a perf-command. See 'perf --help'.\n", cmd); + + if (main_cmds.cnt && best_similarity < 6) { + fprintf(stderr, "\nDid you mean %s?\n", + n < 2 ? "this": "one of these"); + + for (i = 0; i < n; i++) + fprintf(stderr, "\t%s\n", main_cmds.names[i]->name); + } + + exit(1); +} + +int cmd_version(int argc, const char **argv, const char *prefix) +{ + printf("perf version %s\n", perf_version_string); + return 0; +} diff --git a/tools/perf/util/help.h b/tools/perf/util/help.h new file mode 100644 index 000000000000..56bc15406ffc --- /dev/null +++ b/tools/perf/util/help.h @@ -0,0 +1,29 @@ +#ifndef HELP_H +#define HELP_H + +struct cmdnames { + int alloc; + int cnt; + struct cmdname { + size_t len; /* also used for similarity index in help.c */ + char name[FLEX_ARRAY]; + } **names; +}; + +static inline void mput_char(char c, unsigned int num) +{ + while(num--) + putchar(c); +} + +void load_command_list(const char *prefix, + struct cmdnames *main_cmds, + struct cmdnames *other_cmds); +void add_cmdname(struct cmdnames *cmds, const char *name, int len); +/* Here we require that excludes is a sorted list. */ +void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes); +int is_in_cmdlist(struct cmdnames *c, const char *s); +void list_commands(const char *title, struct cmdnames *main_cmds, + struct cmdnames *other_cmds); + +#endif /* HELP_H */ diff --git a/tools/perf/util/levenshtein.c b/tools/perf/util/levenshtein.c new file mode 100644 index 000000000000..e521d1516df6 --- /dev/null +++ b/tools/perf/util/levenshtein.c @@ -0,0 +1,84 @@ +#include "cache.h" +#include "levenshtein.h" + +/* + * This function implements the Damerau-Levenshtein algorithm to + * calculate a distance between strings. + * + * Basically, it says how many letters need to be swapped, substituted, + * deleted from, or added to string1, at least, to get string2. + * + * The idea is to build a distance matrix for the substrings of both + * strings. To avoid a large space complexity, only the last three rows + * are kept in memory (if swaps had the same or higher cost as one deletion + * plus one insertion, only two rows would be needed). + * + * At any stage, "i + 1" denotes the length of the current substring of + * string1 that the distance is calculated for. + * + * row2 holds the current row, row1 the previous row (i.e. for the substring + * of string1 of length "i"), and row0 the row before that. + * + * In other words, at the start of the big loop, row2[j + 1] contains the + * Damerau-Levenshtein distance between the substring of string1 of length + * "i" and the substring of string2 of length "j + 1". + * + * All the big loop does is determine the partial minimum-cost paths. + * + * It does so by calculating the costs of the path ending in characters + * i (in string1) and j (in string2), respectively, given that the last + * operation is a substition, a swap, a deletion, or an insertion. + * + * This implementation allows the costs to be weighted: + * + * - w (as in "sWap") + * - s (as in "Substitution") + * - a (for insertion, AKA "Add") + * - d (as in "Deletion") + * + * Note that this algorithm calculates a distance _iff_ d == a. + */ +int levenshtein(const char *string1, const char *string2, + int w, int s, int a, int d) +{ + int len1 = strlen(string1), len2 = strlen(string2); + int *row0 = malloc(sizeof(int) * (len2 + 1)); + int *row1 = malloc(sizeof(int) * (len2 + 1)); + int *row2 = malloc(sizeof(int) * (len2 + 1)); + int i, j; + + for (j = 0; j <= len2; j++) + row1[j] = j * a; + for (i = 0; i < len1; i++) { + int *dummy; + + row2[0] = (i + 1) * d; + for (j = 0; j < len2; j++) { + /* substitution */ + row2[j + 1] = row1[j] + s * (string1[i] != string2[j]); + /* swap */ + if (i > 0 && j > 0 && string1[i - 1] == string2[j] && + string1[i] == string2[j - 1] && + row2[j + 1] > row0[j - 1] + w) + row2[j + 1] = row0[j - 1] + w; + /* deletion */ + if (row2[j + 1] > row1[j + 1] + d) + row2[j + 1] = row1[j + 1] + d; + /* insertion */ + if (row2[j + 1] > row2[j] + a) + row2[j + 1] = row2[j] + a; + } + + dummy = row0; + row0 = row1; + row1 = row2; + row2 = dummy; + } + + i = row1[len2]; + free(row0); + free(row1); + free(row2); + + return i; +} diff --git a/tools/perf/util/levenshtein.h b/tools/perf/util/levenshtein.h new file mode 100644 index 000000000000..0173abeef52c --- /dev/null +++ b/tools/perf/util/levenshtein.h @@ -0,0 +1,8 @@ +#ifndef LEVENSHTEIN_H +#define LEVENSHTEIN_H + +int levenshtein(const char *string1, const char *string2, + int swap_penalty, int substition_penalty, + int insertion_penalty, int deletion_penalty); + +#endif diff --git a/tools/perf/util/list.h b/tools/perf/util/list.h new file mode 100644 index 000000000000..e2548e8072cf --- /dev/null +++ b/tools/perf/util/list.h @@ -0,0 +1,603 @@ +#ifndef _LINUX_LIST_H +#define _LINUX_LIST_H +/* + Copyright (C) Cast of dozens, comes from the Linux kernel + + 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. +*/ + +#include + +/* + * These are non-NULL pointers that will result in page faults + * under normal circumstances, used to verify that nobody uses + * non-initialized list entries. + */ +#define LIST_POISON1 ((void *)0x00100100) +#define LIST_POISON2 ((void *)0x00200200) + +/** + * container_of - cast a member of a structure out to the containing structure + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + * + */ +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +/* + * Simple doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +struct list_head { + struct list_head *next, *prev; +}; + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +static inline void INIT_LIST_HEAD(struct list_head *list) +{ + list->next = list; + list->prev = list; +} + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +/** + * list_add - add a new entry + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static inline void list_add(struct list_head *new, struct list_head *head) +{ + __list_add(new, head, head->next); +} + +/** + * list_add_tail - add a new entry + * @new: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +static inline void list_add_tail(struct list_head *new, struct list_head *head) +{ + __list_add(new, head->prev, head); +} + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_del(struct list_head * prev, struct list_head * next) +{ + next->prev = prev; + prev->next = next; +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty on entry does not return true after this, the entry is + * in an undefined state. + */ +static inline void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->next = LIST_POISON1; + entry->prev = LIST_POISON2; +} + +/** + * list_del_range - deletes range of entries from list. + * @beging: first element in the range to delete from the list. + * @beging: first element in the range to delete from the list. + * Note: list_empty on the range of entries does not return true after this, + * the entries is in an undefined state. + */ +static inline void list_del_range(struct list_head *begin, + struct list_head *end) +{ + begin->prev->next = end->next; + end->next->prev = begin->prev; +} + +/** + * list_replace - replace old entry by new one + * @old : the element to be replaced + * @new : the new element to insert + * Note: if 'old' was empty, it will be overwritten. + */ +static inline void list_replace(struct list_head *old, + struct list_head *new) +{ + new->next = old->next; + new->next->prev = new; + new->prev = old->prev; + new->prev->next = new; +} + +static inline void list_replace_init(struct list_head *old, + struct list_head *new) +{ + list_replace(old, new); + INIT_LIST_HEAD(old); +} + +/** + * list_del_init - deletes entry from list and reinitialize it. + * @entry: the element to delete from the list. + */ +static inline void list_del_init(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + INIT_LIST_HEAD(entry); +} + +/** + * list_move - delete from one list and add as another's head + * @list: the entry to move + * @head: the head that will precede our entry + */ +static inline void list_move(struct list_head *list, struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add(list, head); +} + +/** + * list_move_tail - delete from one list and add as another's tail + * @list: the entry to move + * @head: the head that will follow our entry + */ +static inline void list_move_tail(struct list_head *list, + struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add_tail(list, head); +} + +/** + * list_is_last - tests whether @list is the last entry in list @head + * @list: the entry to test + * @head: the head of the list + */ +static inline int list_is_last(const struct list_head *list, + const struct list_head *head) +{ + return list->next == head; +} + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +static inline int list_empty(const struct list_head *head) +{ + return head->next == head; +} + +/** + * list_empty_careful - tests whether a list is empty and not being modified + * @head: the list to test + * + * Description: + * tests whether a list is empty _and_ checks that no other CPU might be + * in the process of modifying either member (next or prev) + * + * NOTE: using list_empty_careful() without synchronization + * can only be safe if the only activity that can happen + * to the list entry is list_del_init(). Eg. it cannot be used + * if another CPU could re-list_add() it. + */ +static inline int list_empty_careful(const struct list_head *head) +{ + struct list_head *next = head->next; + return (next == head) && (next == head->prev); +} + +static inline void __list_splice(struct list_head *list, + struct list_head *head) +{ + struct list_head *first = list->next; + struct list_head *last = list->prev; + struct list_head *at = head->next; + + first->prev = head; + head->next = first; + + last->next = at; + at->prev = last; +} + +/** + * list_splice - join two lists + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +static inline void list_splice(struct list_head *list, struct list_head *head) +{ + if (!list_empty(list)) + __list_splice(list, head); +} + +/** + * list_splice_init - join two lists and reinitialise the emptied list. + * @list: the new list to add. + * @head: the place to add it in the first list. + * + * The list at @list is reinitialised + */ +static inline void list_splice_init(struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) { + __list_splice(list, head); + INIT_LIST_HEAD(list); + } +} + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + */ +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +/** + * list_first_entry - get the first element from a list + * @ptr: the list head to take the element from. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + * + * Note, that list is expected to be not empty. + */ +#define list_first_entry(ptr, type, member) \ + list_entry((ptr)->next, type, member) + +/** + * list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + */ +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); \ + pos = pos->next) + +/** + * __list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + * + * This variant differs from list_for_each() in that it's the + * simplest possible list iteration code, no prefetching is done. + * Use this for code that knows the list to be very short (empty + * or 1 entry) most of the time. + */ +#define __list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * list_for_each_prev - iterate over a list backwards + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + */ +#define list_for_each_prev(pos, head) \ + for (pos = (head)->prev; pos != (head); \ + pos = pos->prev) + +/** + * list_for_each_safe - iterate over a list safe against removal of list entry + * @pos: the &struct list_head to use as a loop cursor. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +/** + * list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_reverse - iterate backwards over list of given type. + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_reverse(pos, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.prev, typeof(*pos), member)) + +/** + * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue + * @pos: the type * to use as a start point + * @head: the head of the list + * @member: the name of the list_struct within the struct. + * + * Prepares a pos entry for use as a start point in list_for_each_entry_continue. + */ +#define list_prepare_entry(pos, head, member) \ + ((pos) ? : list_entry(head, typeof(*pos), member)) + +/** + * list_for_each_entry_continue - continue iteration over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Continue to iterate over list of given type, continuing after + * the current position. + */ +#define list_for_each_entry_continue(pos, head, member) \ + for (pos = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_from - iterate over list of given type from the current point + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type, continuing from current position. + */ +#define list_for_each_entry_from(pos, head, member) \ + for (; &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_safe(pos, n, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_continue + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type, continuing after current point, + * safe against removal of list entry. + */ +#define list_for_each_entry_safe_continue(pos, n, head, member) \ + for (pos = list_entry(pos->member.next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_from + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type from current point, safe against + * removal of list entry. + */ +#define list_for_each_entry_safe_from(pos, n, head, member) \ + for (n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_reverse + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate backwards over list of given type, safe against removal + * of list entry. + */ +#define list_for_each_entry_safe_reverse(pos, n, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member), \ + n = list_entry(pos->member.prev, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.prev, typeof(*n), member)) + +/* + * Double linked lists with a single pointer list head. + * Mostly useful for hash tables where the two pointer list head is + * too wasteful. + * You lose the ability to access the tail in O(1). + */ + +struct hlist_head { + struct hlist_node *first; +}; + +struct hlist_node { + struct hlist_node *next, **pprev; +}; + +#define HLIST_HEAD_INIT { .first = NULL } +#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL } +#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) +static inline void INIT_HLIST_NODE(struct hlist_node *h) +{ + h->next = NULL; + h->pprev = NULL; +} + +static inline int hlist_unhashed(const struct hlist_node *h) +{ + return !h->pprev; +} + +static inline int hlist_empty(const struct hlist_head *h) +{ + return !h->first; +} + +static inline void __hlist_del(struct hlist_node *n) +{ + struct hlist_node *next = n->next; + struct hlist_node **pprev = n->pprev; + *pprev = next; + if (next) + next->pprev = pprev; +} + +static inline void hlist_del(struct hlist_node *n) +{ + __hlist_del(n); + n->next = LIST_POISON1; + n->pprev = LIST_POISON2; +} + +static inline void hlist_del_init(struct hlist_node *n) +{ + if (!hlist_unhashed(n)) { + __hlist_del(n); + INIT_HLIST_NODE(n); + } +} + +static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) +{ + struct hlist_node *first = h->first; + n->next = first; + if (first) + first->pprev = &n->next; + h->first = n; + n->pprev = &h->first; +} + +/* next must be != NULL */ +static inline void hlist_add_before(struct hlist_node *n, + struct hlist_node *next) +{ + n->pprev = next->pprev; + n->next = next; + next->pprev = &n->next; + *(n->pprev) = n; +} + +static inline void hlist_add_after(struct hlist_node *n, + struct hlist_node *next) +{ + next->next = n->next; + n->next = next; + next->pprev = &n->next; + + if(next->next) + next->next->pprev = &next->next; +} + +#define hlist_entry(ptr, type, member) container_of(ptr,type,member) + +#define hlist_for_each(pos, head) \ + for (pos = (head)->first; pos; \ + pos = pos->next) + +#define hlist_for_each_safe(pos, n, head) \ + for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \ + pos = n) + +/** + * hlist_for_each_entry - iterate over list of given type + * @tpos: the type * to use as a loop cursor. + * @pos: the &struct hlist_node to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry(tpos, pos, head, member) \ + for (pos = (head)->first; \ + pos && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) + +/** + * hlist_for_each_entry_continue - iterate over a hlist continuing after current point + * @tpos: the type * to use as a loop cursor. + * @pos: the &struct hlist_node to use as a loop cursor. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_continue(tpos, pos, member) \ + for (pos = (pos)->next; \ + pos && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) + +/** + * hlist_for_each_entry_from - iterate over a hlist continuing from current point + * @tpos: the type * to use as a loop cursor. + * @pos: the &struct hlist_node to use as a loop cursor. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_from(tpos, pos, member) \ + for (; pos && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) + +/** + * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @tpos: the type * to use as a loop cursor. + * @pos: the &struct hlist_node to use as a loop cursor. + * @n: another &struct hlist_node to use as temporary storage + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \ + for (pos = (head)->first; \ + pos && ({ n = pos->next; 1; }) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = n) + +#endif diff --git a/tools/perf/util/pager.c b/tools/perf/util/pager.c new file mode 100644 index 000000000000..a28bccae5458 --- /dev/null +++ b/tools/perf/util/pager.c @@ -0,0 +1,99 @@ +#include "cache.h" +#include "run-command.h" +#include "sigchain.h" + +/* + * This is split up from the rest of git so that we can do + * something different on Windows. + */ + +static int spawned_pager; + +#ifndef __MINGW32__ +static void pager_preexec(void) +{ + /* + * Work around bug in "less" by not starting it until we + * have real input + */ + fd_set in; + + FD_ZERO(&in); + FD_SET(0, &in); + select(1, &in, NULL, &in, NULL); + + setenv("LESS", "FRSX", 0); +} +#endif + +static const char *pager_argv[] = { "sh", "-c", NULL, NULL }; +static struct child_process pager_process; + +static void wait_for_pager(void) +{ + fflush(stdout); + fflush(stderr); + /* signal EOF to pager */ + close(1); + close(2); + finish_command(&pager_process); +} + +static void wait_for_pager_signal(int signo) +{ + wait_for_pager(); + sigchain_pop(signo); + raise(signo); +} + +void setup_pager(void) +{ + const char *pager = getenv("PERF_PAGER"); + + if (!isatty(1)) + return; + if (!pager) { + if (!pager_program) + perf_config(perf_default_config, NULL); + pager = pager_program; + } + if (!pager) + pager = getenv("PAGER"); + if (!pager) + pager = "less"; + else if (!*pager || !strcmp(pager, "cat")) + return; + + spawned_pager = 1; /* means we are emitting to terminal */ + + /* spawn the pager */ + pager_argv[2] = pager; + pager_process.argv = pager_argv; + pager_process.in = -1; +#ifndef __MINGW32__ + pager_process.preexec_cb = pager_preexec; +#endif + if (start_command(&pager_process)) + return; + + /* original process continues, but writes to the pipe */ + dup2(pager_process.in, 1); + if (isatty(2)) + dup2(pager_process.in, 2); + close(pager_process.in); + + /* this makes sure that the parent terminates after the pager */ + sigchain_push_common(wait_for_pager_signal); + atexit(wait_for_pager); +} + +int pager_in_use(void) +{ + const char *env; + + if (spawned_pager) + return 1; + + env = getenv("PERF_PAGER_IN_USE"); + return env ? perf_config_bool("PERF_PAGER_IN_USE", env) : 0; +} diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c new file mode 100644 index 000000000000..35d04da38d6a --- /dev/null +++ b/tools/perf/util/parse-events.c @@ -0,0 +1,316 @@ + +#include "../perf.h" +#include "util.h" +#include "parse-options.h" +#include "parse-events.h" +#include "exec_cmd.h" +#include "string.h" + +extern char *strcasestr(const char *haystack, const char *needle); + +int nr_counters; + +struct perf_counter_attr attrs[MAX_COUNTERS]; + +struct event_symbol { + u8 type; + u64 config; + char *symbol; +}; + +#define C(x, y) .type = PERF_TYPE_##x, .config = PERF_COUNT_##y +#define CR(x, y) .type = PERF_TYPE_##x, .config = y + +static struct event_symbol event_symbols[] = { + { C(HARDWARE, HW_CPU_CYCLES), "cpu-cycles", }, + { C(HARDWARE, HW_CPU_CYCLES), "cycles", }, + { C(HARDWARE, HW_INSTRUCTIONS), "instructions", }, + { C(HARDWARE, HW_CACHE_REFERENCES), "cache-references", }, + { C(HARDWARE, HW_CACHE_MISSES), "cache-misses", }, + { C(HARDWARE, HW_BRANCH_INSTRUCTIONS),"branch-instructions", }, + { C(HARDWARE, HW_BRANCH_INSTRUCTIONS),"branches", }, + { C(HARDWARE, HW_BRANCH_MISSES), "branch-misses", }, + { C(HARDWARE, HW_BUS_CYCLES), "bus-cycles", }, + + { C(SOFTWARE, SW_CPU_CLOCK), "cpu-clock", }, + { C(SOFTWARE, SW_TASK_CLOCK), "task-clock", }, + { C(SOFTWARE, SW_PAGE_FAULTS), "page-faults", }, + { C(SOFTWARE, SW_PAGE_FAULTS), "faults", }, + { C(SOFTWARE, SW_PAGE_FAULTS_MIN), "minor-faults", }, + { C(SOFTWARE, SW_PAGE_FAULTS_MAJ), "major-faults", }, + { C(SOFTWARE, SW_CONTEXT_SWITCHES), "context-switches", }, + { C(SOFTWARE, SW_CONTEXT_SWITCHES), "cs", }, + { C(SOFTWARE, SW_CPU_MIGRATIONS), "cpu-migrations", }, + { C(SOFTWARE, SW_CPU_MIGRATIONS), "migrations", }, +}; + +#define __PERF_COUNTER_FIELD(config, name) \ + ((config & PERF_COUNTER_##name##_MASK) >> PERF_COUNTER_##name##_SHIFT) + +#define PERF_COUNTER_RAW(config) __PERF_COUNTER_FIELD(config, RAW) +#define PERF_COUNTER_CONFIG(config) __PERF_COUNTER_FIELD(config, CONFIG) +#define PERF_COUNTER_TYPE(config) __PERF_COUNTER_FIELD(config, TYPE) +#define PERF_COUNTER_ID(config) __PERF_COUNTER_FIELD(config, EVENT) + +static char *hw_event_names[] = { + "cycles", + "instructions", + "cache-references", + "cache-misses", + "branches", + "branch-misses", + "bus-cycles", +}; + +static char *sw_event_names[] = { + "cpu-clock-msecs", + "task-clock-msecs", + "page-faults", + "context-switches", + "CPU-migrations", + "minor-faults", + "major-faults", +}; + +#define MAX_ALIASES 8 + +static char *hw_cache [][MAX_ALIASES] = { + { "L1-data" , "l1-d", "l1d" }, + { "L1-instruction" , "l1-i", "l1i" }, + { "L2" , "l2" }, + { "Data-TLB" , "dtlb", "d-tlb" }, + { "Instruction-TLB" , "itlb", "i-tlb" }, + { "Branch" , "bpu" , "btb", "bpc" }, +}; + +static char *hw_cache_op [][MAX_ALIASES] = { + { "Load" , "read" }, + { "Store" , "write" }, + { "Prefetch" , "speculative-read", "speculative-load" }, +}; + +static char *hw_cache_result [][MAX_ALIASES] = { + { "Reference" , "ops", "access" }, + { "Miss" }, +}; + +char *event_name(int counter) +{ + u64 config = attrs[counter].config; + int type = attrs[counter].type; + static char buf[32]; + + if (attrs[counter].type == PERF_TYPE_RAW) { + sprintf(buf, "raw 0x%llx", config); + return buf; + } + + switch (type) { + case PERF_TYPE_HARDWARE: + if (config < PERF_COUNT_HW_MAX) + return hw_event_names[config]; + return "unknown-hardware"; + + case PERF_TYPE_HW_CACHE: { + u8 cache_type, cache_op, cache_result; + static char name[100]; + + cache_type = (config >> 0) & 0xff; + if (cache_type > PERF_COUNT_HW_CACHE_MAX) + return "unknown-ext-hardware-cache-type"; + + cache_op = (config >> 8) & 0xff; + if (cache_op > PERF_COUNT_HW_CACHE_OP_MAX) + return "unknown-ext-hardware-cache-op"; + + cache_result = (config >> 16) & 0xff; + if (cache_result > PERF_COUNT_HW_CACHE_RESULT_MAX) + return "unknown-ext-hardware-cache-result"; + + sprintf(name, "%s-Cache-%s-%ses", + hw_cache[cache_type][0], + hw_cache_op[cache_op][0], + hw_cache_result[cache_result][0]); + + return name; + } + + case PERF_TYPE_SOFTWARE: + if (config < PERF_COUNT_SW_MAX) + return sw_event_names[config]; + return "unknown-software"; + + default: + break; + } + + return "unknown"; +} + +static int parse_aliases(const char *str, char *names[][MAX_ALIASES], int size) +{ + int i, j; + + for (i = 0; i < size; i++) { + for (j = 0; j < MAX_ALIASES; j++) { + if (!names[i][j]) + break; + if (strcasestr(str, names[i][j])) + return i; + } + } + + return -1; +} + +static int parse_generic_hw_symbols(const char *str, struct perf_counter_attr *attr) +{ + int cache_type = -1, cache_op = 0, cache_result = 0; + + cache_type = parse_aliases(str, hw_cache, PERF_COUNT_HW_CACHE_MAX); + /* + * No fallback - if we cannot get a clear cache type + * then bail out: + */ + if (cache_type == -1) + return -EINVAL; + + cache_op = parse_aliases(str, hw_cache_op, PERF_COUNT_HW_CACHE_OP_MAX); + /* + * Fall back to reads: + */ + if (cache_op == -1) + cache_op = PERF_COUNT_HW_CACHE_OP_READ; + + cache_result = parse_aliases(str, hw_cache_result, + PERF_COUNT_HW_CACHE_RESULT_MAX); + /* + * Fall back to accesses: + */ + if (cache_result == -1) + cache_result = PERF_COUNT_HW_CACHE_RESULT_ACCESS; + + attr->config = cache_type | (cache_op << 8) | (cache_result << 16); + attr->type = PERF_TYPE_HW_CACHE; + + return 0; +} + +/* + * Each event can have multiple symbolic names. + * Symbolic names are (almost) exactly matched. + */ +static int parse_event_symbols(const char *str, struct perf_counter_attr *attr) +{ + u64 config, id; + int type; + unsigned int i; + const char *sep, *pstr; + + if (str[0] == 'r' && hex2u64(str + 1, &config) > 0) { + attr->type = PERF_TYPE_RAW; + attr->config = config; + + return 0; + } + + pstr = str; + sep = strchr(pstr, ':'); + if (sep) { + type = atoi(pstr); + pstr = sep + 1; + id = atoi(pstr); + sep = strchr(pstr, ':'); + if (sep) { + pstr = sep + 1; + if (strchr(pstr, 'k')) + attr->exclude_user = 1; + if (strchr(pstr, 'u')) + attr->exclude_kernel = 1; + } + attr->type = type; + attr->config = id; + + return 0; + } + + for (i = 0; i < ARRAY_SIZE(event_symbols); i++) { + if (!strncmp(str, event_symbols[i].symbol, + strlen(event_symbols[i].symbol))) { + + attr->type = event_symbols[i].type; + attr->config = event_symbols[i].config; + + return 0; + } + } + + return parse_generic_hw_symbols(str, attr); +} + +int parse_events(const struct option *opt, const char *str, int unset) +{ + struct perf_counter_attr attr; + int ret; + + memset(&attr, 0, sizeof(attr)); +again: + if (nr_counters == MAX_COUNTERS) + return -1; + + ret = parse_event_symbols(str, &attr); + if (ret < 0) + return ret; + + attrs[nr_counters] = attr; + nr_counters++; + + str = strstr(str, ","); + if (str) { + str++; + goto again; + } + + return 0; +} + +static const char * const event_type_descriptors[] = { + "", + "Hardware event", + "Software event", + "Tracepoint event", + "Hardware cache event", +}; + +/* + * Print the help text for the event symbols: + */ +void print_events(void) +{ + struct event_symbol *syms = event_symbols; + unsigned int i, type, prev_type = -1; + + fprintf(stderr, "\n"); + fprintf(stderr, "List of pre-defined events (to be used in -e):\n"); + + for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) { + type = syms->type + 1; + if (type > ARRAY_SIZE(event_type_descriptors)) + type = 0; + + if (type != prev_type) + fprintf(stderr, "\n"); + + fprintf(stderr, " %-30s [%s]\n", syms->symbol, + event_type_descriptors[type]); + + prev_type = type; + } + + fprintf(stderr, "\n"); + fprintf(stderr, " %-30s [raw hardware event descriptor]\n", + "rNNN"); + fprintf(stderr, "\n"); + + exit(129); +} diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h new file mode 100644 index 000000000000..e3d552908e60 --- /dev/null +++ b/tools/perf/util/parse-events.h @@ -0,0 +1,17 @@ + +/* + * Parse symbolic events/counts passed in as options: + */ + +extern int nr_counters; + +extern struct perf_counter_attr attrs[MAX_COUNTERS]; + +extern char *event_name(int ctr); + +extern int parse_events(const struct option *opt, const char *str, int unset); + +#define EVENTS_HELP_MAX (128*1024) + +extern void print_events(void); + diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c new file mode 100644 index 000000000000..b3affb1658d2 --- /dev/null +++ b/tools/perf/util/parse-options.c @@ -0,0 +1,508 @@ +#include "util.h" +#include "parse-options.h" +#include "cache.h" + +#define OPT_SHORT 1 +#define OPT_UNSET 2 + +static int opterror(const struct option *opt, const char *reason, int flags) +{ + if (flags & OPT_SHORT) + return error("switch `%c' %s", opt->short_name, reason); + if (flags & OPT_UNSET) + return error("option `no-%s' %s", opt->long_name, reason); + return error("option `%s' %s", opt->long_name, reason); +} + +static int get_arg(struct parse_opt_ctx_t *p, const struct option *opt, + int flags, const char **arg) +{ + if (p->opt) { + *arg = p->opt; + p->opt = NULL; + } else if (p->argc == 1 && (opt->flags & PARSE_OPT_LASTARG_DEFAULT)) { + *arg = (const char *)opt->defval; + } else if (p->argc > 1) { + p->argc--; + *arg = *++p->argv; + } else + return opterror(opt, "requires a value", flags); + return 0; +} + +static int get_value(struct parse_opt_ctx_t *p, + const struct option *opt, int flags) +{ + const char *s, *arg = NULL; + const int unset = flags & OPT_UNSET; + + if (unset && p->opt) + return opterror(opt, "takes no value", flags); + if (unset && (opt->flags & PARSE_OPT_NONEG)) + return opterror(opt, "isn't available", flags); + + if (!(flags & OPT_SHORT) && p->opt) { + switch (opt->type) { + case OPTION_CALLBACK: + if (!(opt->flags & PARSE_OPT_NOARG)) + break; + /* FALLTHROUGH */ + case OPTION_BOOLEAN: + case OPTION_BIT: + case OPTION_SET_INT: + case OPTION_SET_PTR: + return opterror(opt, "takes no value", flags); + default: + break; + } + } + + switch (opt->type) { + case OPTION_BIT: + if (unset) + *(int *)opt->value &= ~opt->defval; + else + *(int *)opt->value |= opt->defval; + return 0; + + case OPTION_BOOLEAN: + *(int *)opt->value = unset ? 0 : *(int *)opt->value + 1; + return 0; + + case OPTION_SET_INT: + *(int *)opt->value = unset ? 0 : opt->defval; + return 0; + + case OPTION_SET_PTR: + *(void **)opt->value = unset ? NULL : (void *)opt->defval; + return 0; + + case OPTION_STRING: + if (unset) + *(const char **)opt->value = NULL; + else if (opt->flags & PARSE_OPT_OPTARG && !p->opt) + *(const char **)opt->value = (const char *)opt->defval; + else + return get_arg(p, opt, flags, (const char **)opt->value); + return 0; + + case OPTION_CALLBACK: + if (unset) + return (*opt->callback)(opt, NULL, 1) ? (-1) : 0; + if (opt->flags & PARSE_OPT_NOARG) + return (*opt->callback)(opt, NULL, 0) ? (-1) : 0; + if (opt->flags & PARSE_OPT_OPTARG && !p->opt) + return (*opt->callback)(opt, NULL, 0) ? (-1) : 0; + if (get_arg(p, opt, flags, &arg)) + return -1; + return (*opt->callback)(opt, arg, 0) ? (-1) : 0; + + case OPTION_INTEGER: + if (unset) { + *(int *)opt->value = 0; + return 0; + } + if (opt->flags & PARSE_OPT_OPTARG && !p->opt) { + *(int *)opt->value = opt->defval; + return 0; + } + if (get_arg(p, opt, flags, &arg)) + return -1; + *(int *)opt->value = strtol(arg, (char **)&s, 10); + if (*s) + return opterror(opt, "expects a numerical value", flags); + return 0; + + case OPTION_LONG: + if (unset) { + *(long *)opt->value = 0; + return 0; + } + if (opt->flags & PARSE_OPT_OPTARG && !p->opt) { + *(long *)opt->value = opt->defval; + return 0; + } + if (get_arg(p, opt, flags, &arg)) + return -1; + *(long *)opt->value = strtol(arg, (char **)&s, 10); + if (*s) + return opterror(opt, "expects a numerical value", flags); + return 0; + + default: + die("should not happen, someone must be hit on the forehead"); + } +} + +static int parse_short_opt(struct parse_opt_ctx_t *p, const struct option *options) +{ + for (; options->type != OPTION_END; options++) { + if (options->short_name == *p->opt) { + p->opt = p->opt[1] ? p->opt + 1 : NULL; + return get_value(p, options, OPT_SHORT); + } + } + return -2; +} + +static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg, + const struct option *options) +{ + const char *arg_end = strchr(arg, '='); + const struct option *abbrev_option = NULL, *ambiguous_option = NULL; + int abbrev_flags = 0, ambiguous_flags = 0; + + if (!arg_end) + arg_end = arg + strlen(arg); + + for (; options->type != OPTION_END; options++) { + const char *rest; + int flags = 0; + + if (!options->long_name) + continue; + + rest = skip_prefix(arg, options->long_name); + if (options->type == OPTION_ARGUMENT) { + if (!rest) + continue; + if (*rest == '=') + return opterror(options, "takes no value", flags); + if (*rest) + continue; + p->out[p->cpidx++] = arg - 2; + return 0; + } + if (!rest) { + /* abbreviated? */ + if (!strncmp(options->long_name, arg, arg_end - arg)) { +is_abbreviated: + if (abbrev_option) { + /* + * If this is abbreviated, it is + * ambiguous. So when there is no + * exact match later, we need to + * error out. + */ + ambiguous_option = abbrev_option; + ambiguous_flags = abbrev_flags; + } + if (!(flags & OPT_UNSET) && *arg_end) + p->opt = arg_end + 1; + abbrev_option = options; + abbrev_flags = flags; + continue; + } + /* negated and abbreviated very much? */ + if (!prefixcmp("no-", arg)) { + flags |= OPT_UNSET; + goto is_abbreviated; + } + /* negated? */ + if (strncmp(arg, "no-", 3)) + continue; + flags |= OPT_UNSET; + rest = skip_prefix(arg + 3, options->long_name); + /* abbreviated and negated? */ + if (!rest && !prefixcmp(options->long_name, arg + 3)) + goto is_abbreviated; + if (!rest) + continue; + } + if (*rest) { + if (*rest != '=') + continue; + p->opt = rest + 1; + } + return get_value(p, options, flags); + } + + if (ambiguous_option) + return error("Ambiguous option: %s " + "(could be --%s%s or --%s%s)", + arg, + (ambiguous_flags & OPT_UNSET) ? "no-" : "", + ambiguous_option->long_name, + (abbrev_flags & OPT_UNSET) ? "no-" : "", + abbrev_option->long_name); + if (abbrev_option) + return get_value(p, abbrev_option, abbrev_flags); + return -2; +} + +static void check_typos(const char *arg, const struct option *options) +{ + if (strlen(arg) < 3) + return; + + if (!prefixcmp(arg, "no-")) { + error ("did you mean `--%s` (with two dashes ?)", arg); + exit(129); + } + + for (; options->type != OPTION_END; options++) { + if (!options->long_name) + continue; + if (!prefixcmp(options->long_name, arg)) { + error ("did you mean `--%s` (with two dashes ?)", arg); + exit(129); + } + } +} + +void parse_options_start(struct parse_opt_ctx_t *ctx, + int argc, const char **argv, int flags) +{ + memset(ctx, 0, sizeof(*ctx)); + ctx->argc = argc - 1; + ctx->argv = argv + 1; + ctx->out = argv; + ctx->cpidx = ((flags & PARSE_OPT_KEEP_ARGV0) != 0); + ctx->flags = flags; + if ((flags & PARSE_OPT_KEEP_UNKNOWN) && + (flags & PARSE_OPT_STOP_AT_NON_OPTION)) + die("STOP_AT_NON_OPTION and KEEP_UNKNOWN don't go together"); +} + +static int usage_with_options_internal(const char * const *, + const struct option *, int); + +int parse_options_step(struct parse_opt_ctx_t *ctx, + const struct option *options, + const char * const usagestr[]) +{ + int internal_help = !(ctx->flags & PARSE_OPT_NO_INTERNAL_HELP); + + /* we must reset ->opt, unknown short option leave it dangling */ + ctx->opt = NULL; + + for (; ctx->argc; ctx->argc--, ctx->argv++) { + const char *arg = ctx->argv[0]; + + if (*arg != '-' || !arg[1]) { + if (ctx->flags & PARSE_OPT_STOP_AT_NON_OPTION) + break; + ctx->out[ctx->cpidx++] = ctx->argv[0]; + continue; + } + + if (arg[1] != '-') { + ctx->opt = arg + 1; + if (internal_help && *ctx->opt == 'h') + return parse_options_usage(usagestr, options); + switch (parse_short_opt(ctx, options)) { + case -1: + return parse_options_usage(usagestr, options); + case -2: + goto unknown; + } + if (ctx->opt) + check_typos(arg + 1, options); + while (ctx->opt) { + if (internal_help && *ctx->opt == 'h') + return parse_options_usage(usagestr, options); + switch (parse_short_opt(ctx, options)) { + case -1: + return parse_options_usage(usagestr, options); + case -2: + /* fake a short option thing to hide the fact that we may have + * started to parse aggregated stuff + * + * This is leaky, too bad. + */ + ctx->argv[0] = strdup(ctx->opt - 1); + *(char *)ctx->argv[0] = '-'; + goto unknown; + } + } + continue; + } + + if (!arg[2]) { /* "--" */ + if (!(ctx->flags & PARSE_OPT_KEEP_DASHDASH)) { + ctx->argc--; + ctx->argv++; + } + break; + } + + if (internal_help && !strcmp(arg + 2, "help-all")) + return usage_with_options_internal(usagestr, options, 1); + if (internal_help && !strcmp(arg + 2, "help")) + return parse_options_usage(usagestr, options); + switch (parse_long_opt(ctx, arg + 2, options)) { + case -1: + return parse_options_usage(usagestr, options); + case -2: + goto unknown; + } + continue; +unknown: + if (!(ctx->flags & PARSE_OPT_KEEP_UNKNOWN)) + return PARSE_OPT_UNKNOWN; + ctx->out[ctx->cpidx++] = ctx->argv[0]; + ctx->opt = NULL; + } + return PARSE_OPT_DONE; +} + +int parse_options_end(struct parse_opt_ctx_t *ctx) +{ + memmove(ctx->out + ctx->cpidx, ctx->argv, ctx->argc * sizeof(*ctx->out)); + ctx->out[ctx->cpidx + ctx->argc] = NULL; + return ctx->cpidx + ctx->argc; +} + +int parse_options(int argc, const char **argv, const struct option *options, + const char * const usagestr[], int flags) +{ + struct parse_opt_ctx_t ctx; + + parse_options_start(&ctx, argc, argv, flags); + switch (parse_options_step(&ctx, options, usagestr)) { + case PARSE_OPT_HELP: + exit(129); + case PARSE_OPT_DONE: + break; + default: /* PARSE_OPT_UNKNOWN */ + if (ctx.argv[0][1] == '-') { + error("unknown option `%s'", ctx.argv[0] + 2); + } else { + error("unknown switch `%c'", *ctx.opt); + } + usage_with_options(usagestr, options); + } + + return parse_options_end(&ctx); +} + +#define USAGE_OPTS_WIDTH 24 +#define USAGE_GAP 2 + +int usage_with_options_internal(const char * const *usagestr, + const struct option *opts, int full) +{ + if (!usagestr) + return PARSE_OPT_HELP; + + fprintf(stderr, "\n usage: %s\n", *usagestr++); + while (*usagestr && **usagestr) + fprintf(stderr, " or: %s\n", *usagestr++); + while (*usagestr) { + fprintf(stderr, "%s%s\n", + **usagestr ? " " : "", + *usagestr); + usagestr++; + } + + if (opts->type != OPTION_GROUP) + fputc('\n', stderr); + + for (; opts->type != OPTION_END; opts++) { + size_t pos; + int pad; + + if (opts->type == OPTION_GROUP) { + fputc('\n', stderr); + if (*opts->help) + fprintf(stderr, "%s\n", opts->help); + continue; + } + if (!full && (opts->flags & PARSE_OPT_HIDDEN)) + continue; + + pos = fprintf(stderr, " "); + if (opts->short_name) + pos += fprintf(stderr, "-%c", opts->short_name); + if (opts->long_name && opts->short_name) + pos += fprintf(stderr, ", "); + if (opts->long_name) + pos += fprintf(stderr, "--%s", opts->long_name); + + switch (opts->type) { + case OPTION_ARGUMENT: + break; + case OPTION_INTEGER: + if (opts->flags & PARSE_OPT_OPTARG) + if (opts->long_name) + pos += fprintf(stderr, "[=]"); + else + pos += fprintf(stderr, "[]"); + else + pos += fprintf(stderr, " "); + break; + case OPTION_CALLBACK: + if (opts->flags & PARSE_OPT_NOARG) + break; + /* FALLTHROUGH */ + case OPTION_STRING: + if (opts->argh) { + if (opts->flags & PARSE_OPT_OPTARG) + if (opts->long_name) + pos += fprintf(stderr, "[=<%s>]", opts->argh); + else + pos += fprintf(stderr, "[<%s>]", opts->argh); + else + pos += fprintf(stderr, " <%s>", opts->argh); + } else { + if (opts->flags & PARSE_OPT_OPTARG) + if (opts->long_name) + pos += fprintf(stderr, "[=...]"); + else + pos += fprintf(stderr, "[...]"); + else + pos += fprintf(stderr, " ..."); + } + break; + default: /* OPTION_{BIT,BOOLEAN,SET_INT,SET_PTR} */ + break; + } + + if (pos <= USAGE_OPTS_WIDTH) + pad = USAGE_OPTS_WIDTH - pos; + else { + fputc('\n', stderr); + pad = USAGE_OPTS_WIDTH; + } + fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help); + } + fputc('\n', stderr); + + return PARSE_OPT_HELP; +} + +void usage_with_options(const char * const *usagestr, + const struct option *opts) +{ + usage_with_options_internal(usagestr, opts, 0); + exit(129); +} + +int parse_options_usage(const char * const *usagestr, + const struct option *opts) +{ + return usage_with_options_internal(usagestr, opts, 0); +} + + +int parse_opt_verbosity_cb(const struct option *opt, const char *arg, + int unset) +{ + int *target = opt->value; + + if (unset) + /* --no-quiet, --no-verbose */ + *target = 0; + else if (opt->short_name == 'v') { + if (*target >= 0) + (*target)++; + else + *target = 1; + } else { + if (*target <= 0) + (*target)--; + else + *target = -1; + } + return 0; +} diff --git a/tools/perf/util/parse-options.h b/tools/perf/util/parse-options.h new file mode 100644 index 000000000000..a1039a6ce0eb --- /dev/null +++ b/tools/perf/util/parse-options.h @@ -0,0 +1,174 @@ +#ifndef PARSE_OPTIONS_H +#define PARSE_OPTIONS_H + +enum parse_opt_type { + /* special types */ + OPTION_END, + OPTION_ARGUMENT, + OPTION_GROUP, + /* options with no arguments */ + OPTION_BIT, + OPTION_BOOLEAN, /* _INCR would have been a better name */ + OPTION_SET_INT, + OPTION_SET_PTR, + /* options with arguments (usually) */ + OPTION_STRING, + OPTION_INTEGER, + OPTION_LONG, + OPTION_CALLBACK, +}; + +enum parse_opt_flags { + PARSE_OPT_KEEP_DASHDASH = 1, + PARSE_OPT_STOP_AT_NON_OPTION = 2, + PARSE_OPT_KEEP_ARGV0 = 4, + PARSE_OPT_KEEP_UNKNOWN = 8, + PARSE_OPT_NO_INTERNAL_HELP = 16, +}; + +enum parse_opt_option_flags { + PARSE_OPT_OPTARG = 1, + PARSE_OPT_NOARG = 2, + PARSE_OPT_NONEG = 4, + PARSE_OPT_HIDDEN = 8, + PARSE_OPT_LASTARG_DEFAULT = 16, +}; + +struct option; +typedef int parse_opt_cb(const struct option *, const char *arg, int unset); + +/* + * `type`:: + * holds the type of the option, you must have an OPTION_END last in your + * array. + * + * `short_name`:: + * the character to use as a short option name, '\0' if none. + * + * `long_name`:: + * the long option name, without the leading dashes, NULL if none. + * + * `value`:: + * stores pointers to the values to be filled. + * + * `argh`:: + * token to explain the kind of argument this option wants. Keep it + * homogenous across the repository. + * + * `help`:: + * the short help associated to what the option does. + * Must never be NULL (except for OPTION_END). + * OPTION_GROUP uses this pointer to store the group header. + * + * `flags`:: + * mask of parse_opt_option_flags. + * PARSE_OPT_OPTARG: says that the argument is optionnal (not for BOOLEANs) + * PARSE_OPT_NOARG: says that this option takes no argument, for CALLBACKs + * PARSE_OPT_NONEG: says that this option cannot be negated + * PARSE_OPT_HIDDEN this option is skipped in the default usage, showed in + * the long one. + * + * `callback`:: + * pointer to the callback to use for OPTION_CALLBACK. + * + * `defval`:: + * default value to fill (*->value) with for PARSE_OPT_OPTARG. + * OPTION_{BIT,SET_INT,SET_PTR} store the {mask,integer,pointer} to put in + * the value when met. + * CALLBACKS can use it like they want. + */ +struct option { + enum parse_opt_type type; + int short_name; + const char *long_name; + void *value; + const char *argh; + const char *help; + + int flags; + parse_opt_cb *callback; + intptr_t defval; +}; + +#define OPT_END() { OPTION_END } +#define OPT_ARGUMENT(l, h) { OPTION_ARGUMENT, 0, (l), NULL, NULL, (h) } +#define OPT_GROUP(h) { OPTION_GROUP, 0, NULL, NULL, NULL, (h) } +#define OPT_BIT(s, l, v, h, b) { OPTION_BIT, (s), (l), (v), NULL, (h), 0, NULL, (b) } +#define OPT_BOOLEAN(s, l, v, h) { OPTION_BOOLEAN, (s), (l), (v), NULL, (h) } +#define OPT_SET_INT(s, l, v, h, i) { OPTION_SET_INT, (s), (l), (v), NULL, (h), 0, NULL, (i) } +#define OPT_SET_PTR(s, l, v, h, p) { OPTION_SET_PTR, (s), (l), (v), NULL, (h), 0, NULL, (p) } +#define OPT_INTEGER(s, l, v, h) { OPTION_INTEGER, (s), (l), (v), NULL, (h) } +#define OPT_LONG(s, l, v, h) { OPTION_LONG, (s), (l), (v), NULL, (h) } +#define OPT_STRING(s, l, v, a, h) { OPTION_STRING, (s), (l), (v), (a), (h) } +#define OPT_DATE(s, l, v, h) \ + { OPTION_CALLBACK, (s), (l), (v), "time",(h), 0, \ + parse_opt_approxidate_cb } +#define OPT_CALLBACK(s, l, v, a, h, f) \ + { OPTION_CALLBACK, (s), (l), (v), (a), (h), 0, (f) } + +/* parse_options() will filter out the processed options and leave the + * non-option argments in argv[]. + * Returns the number of arguments left in argv[]. + */ +extern int parse_options(int argc, const char **argv, + const struct option *options, + const char * const usagestr[], int flags); + +extern NORETURN void usage_with_options(const char * const *usagestr, + const struct option *options); + +/*----- incremantal advanced APIs -----*/ + +enum { + PARSE_OPT_HELP = -1, + PARSE_OPT_DONE, + PARSE_OPT_UNKNOWN, +}; + +/* + * It's okay for the caller to consume argv/argc in the usual way. + * Other fields of that structure are private to parse-options and should not + * be modified in any way. + */ +struct parse_opt_ctx_t { + const char **argv; + const char **out; + int argc, cpidx; + const char *opt; + int flags; +}; + +extern int parse_options_usage(const char * const *usagestr, + const struct option *opts); + +extern void parse_options_start(struct parse_opt_ctx_t *ctx, + int argc, const char **argv, int flags); + +extern int parse_options_step(struct parse_opt_ctx_t *ctx, + const struct option *options, + const char * const usagestr[]); + +extern int parse_options_end(struct parse_opt_ctx_t *ctx); + + +/*----- some often used options -----*/ +extern int parse_opt_abbrev_cb(const struct option *, const char *, int); +extern int parse_opt_approxidate_cb(const struct option *, const char *, int); +extern int parse_opt_verbosity_cb(const struct option *, const char *, int); + +#define OPT__VERBOSE(var) OPT_BOOLEAN('v', "verbose", (var), "be verbose") +#define OPT__QUIET(var) OPT_BOOLEAN('q', "quiet", (var), "be quiet") +#define OPT__VERBOSITY(var) \ + { OPTION_CALLBACK, 'v', "verbose", (var), NULL, "be more verbose", \ + PARSE_OPT_NOARG, &parse_opt_verbosity_cb, 0 }, \ + { OPTION_CALLBACK, 'q', "quiet", (var), NULL, "be more quiet", \ + PARSE_OPT_NOARG, &parse_opt_verbosity_cb, 0 } +#define OPT__DRY_RUN(var) OPT_BOOLEAN('n', "dry-run", (var), "dry run") +#define OPT__ABBREV(var) \ + { OPTION_CALLBACK, 0, "abbrev", (var), "n", \ + "use digits to display SHA-1s", \ + PARSE_OPT_OPTARG, &parse_opt_abbrev_cb, 0 } + +extern const char *parse_options_fix_filename(const char *prefix, const char *file); + +#endif diff --git a/tools/perf/util/path.c b/tools/perf/util/path.c new file mode 100644 index 000000000000..a501a40dd2cb --- /dev/null +++ b/tools/perf/util/path.c @@ -0,0 +1,353 @@ +/* + * I'm tired of doing "vsnprintf()" etc just to open a + * file, so here's a "return static buffer with printf" + * interface for paths. + * + * It's obviously not thread-safe. Sue me. But it's quite + * useful for doing things like + * + * f = open(mkpath("%s/%s.perf", base, name), O_RDONLY); + * + * which is what it's designed for. + */ +#include "cache.h" + +static char bad_path[] = "/bad-path/"; +/* + * Two hacks: + */ + +static char *get_perf_dir(void) +{ + return "."; +} + +size_t strlcpy(char *dest, const char *src, size_t size) +{ + size_t ret = strlen(src); + + if (size) { + size_t len = (ret >= size) ? size - 1 : ret; + memcpy(dest, src, len); + dest[len] = '\0'; + } + return ret; +} + + +static char *get_pathname(void) +{ + static char pathname_array[4][PATH_MAX]; + static int index; + return pathname_array[3 & ++index]; +} + +static char *cleanup_path(char *path) +{ + /* Clean it up */ + if (!memcmp(path, "./", 2)) { + path += 2; + while (*path == '/') + path++; + } + return path; +} + +char *mksnpath(char *buf, size_t n, const char *fmt, ...) +{ + va_list args; + unsigned len; + + va_start(args, fmt); + len = vsnprintf(buf, n, fmt, args); + va_end(args); + if (len >= n) { + strlcpy(buf, bad_path, n); + return buf; + } + return cleanup_path(buf); +} + +static char *perf_vsnpath(char *buf, size_t n, const char *fmt, va_list args) +{ + const char *perf_dir = get_perf_dir(); + size_t len; + + len = strlen(perf_dir); + if (n < len + 1) + goto bad; + memcpy(buf, perf_dir, len); + if (len && !is_dir_sep(perf_dir[len-1])) + buf[len++] = '/'; + len += vsnprintf(buf + len, n - len, fmt, args); + if (len >= n) + goto bad; + return cleanup_path(buf); +bad: + strlcpy(buf, bad_path, n); + return buf; +} + +char *perf_snpath(char *buf, size_t n, const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + (void)perf_vsnpath(buf, n, fmt, args); + va_end(args); + return buf; +} + +char *perf_pathdup(const char *fmt, ...) +{ + char path[PATH_MAX]; + va_list args; + va_start(args, fmt); + (void)perf_vsnpath(path, sizeof(path), fmt, args); + va_end(args); + return xstrdup(path); +} + +char *mkpath(const char *fmt, ...) +{ + va_list args; + unsigned len; + char *pathname = get_pathname(); + + va_start(args, fmt); + len = vsnprintf(pathname, PATH_MAX, fmt, args); + va_end(args); + if (len >= PATH_MAX) + return bad_path; + return cleanup_path(pathname); +} + +char *perf_path(const char *fmt, ...) +{ + const char *perf_dir = get_perf_dir(); + char *pathname = get_pathname(); + va_list args; + unsigned len; + + len = strlen(perf_dir); + if (len > PATH_MAX-100) + return bad_path; + memcpy(pathname, perf_dir, len); + if (len && perf_dir[len-1] != '/') + pathname[len++] = '/'; + va_start(args, fmt); + len += vsnprintf(pathname + len, PATH_MAX - len, fmt, args); + va_end(args); + if (len >= PATH_MAX) + return bad_path; + return cleanup_path(pathname); +} + + +/* perf_mkstemp() - create tmp file honoring TMPDIR variable */ +int perf_mkstemp(char *path, size_t len, const char *template) +{ + const char *tmp; + size_t n; + + tmp = getenv("TMPDIR"); + if (!tmp) + tmp = "/tmp"; + n = snprintf(path, len, "%s/%s", tmp, template); + if (len <= n) { + errno = ENAMETOOLONG; + return -1; + } + return mkstemp(path); +} + + +const char *make_relative_path(const char *abs, const char *base) +{ + static char buf[PATH_MAX + 1]; + int baselen; + if (!base) + return abs; + baselen = strlen(base); + if (prefixcmp(abs, base)) + return abs; + if (abs[baselen] == '/') + baselen++; + else if (base[baselen - 1] != '/') + return abs; + strcpy(buf, abs + baselen); + return buf; +} + +/* + * It is okay if dst == src, but they should not overlap otherwise. + * + * Performs the following normalizations on src, storing the result in dst: + * - Ensures that components are separated by '/' (Windows only) + * - Squashes sequences of '/'. + * - Removes "." components. + * - Removes ".." components, and the components the precede them. + * Returns failure (non-zero) if a ".." component appears as first path + * component anytime during the normalization. Otherwise, returns success (0). + * + * Note that this function is purely textual. It does not follow symlinks, + * verify the existence of the path, or make any system calls. + */ +int normalize_path_copy(char *dst, const char *src) +{ + char *dst0; + + if (has_dos_drive_prefix(src)) { + *dst++ = *src++; + *dst++ = *src++; + } + dst0 = dst; + + if (is_dir_sep(*src)) { + *dst++ = '/'; + while (is_dir_sep(*src)) + src++; + } + + for (;;) { + char c = *src; + + /* + * A path component that begins with . could be + * special: + * (1) "." and ends -- ignore and terminate. + * (2) "./" -- ignore them, eat slash and continue. + * (3) ".." and ends -- strip one and terminate. + * (4) "../" -- strip one, eat slash and continue. + */ + if (c == '.') { + if (!src[1]) { + /* (1) */ + src++; + } else if (is_dir_sep(src[1])) { + /* (2) */ + src += 2; + while (is_dir_sep(*src)) + src++; + continue; + } else if (src[1] == '.') { + if (!src[2]) { + /* (3) */ + src += 2; + goto up_one; + } else if (is_dir_sep(src[2])) { + /* (4) */ + src += 3; + while (is_dir_sep(*src)) + src++; + goto up_one; + } + } + } + + /* copy up to the next '/', and eat all '/' */ + while ((c = *src++) != '\0' && !is_dir_sep(c)) + *dst++ = c; + if (is_dir_sep(c)) { + *dst++ = '/'; + while (is_dir_sep(c)) + c = *src++; + src--; + } else if (!c) + break; + continue; + + up_one: + /* + * dst0..dst is prefix portion, and dst[-1] is '/'; + * go up one level. + */ + dst--; /* go to trailing '/' */ + if (dst <= dst0) + return -1; + /* Windows: dst[-1] cannot be backslash anymore */ + while (dst0 < dst && dst[-1] != '/') + dst--; + } + *dst = '\0'; + return 0; +} + +/* + * path = Canonical absolute path + * prefix_list = Colon-separated list of absolute paths + * + * Determines, for each path in prefix_list, whether the "prefix" really + * is an ancestor directory of path. Returns the length of the longest + * ancestor directory, excluding any trailing slashes, or -1 if no prefix + * is an ancestor. (Note that this means 0 is returned if prefix_list is + * "/".) "/foo" is not considered an ancestor of "/foobar". Directories + * are not considered to be their own ancestors. path must be in a + * canonical form: empty components, or "." or ".." components are not + * allowed. prefix_list may be null, which is like "". + */ +int longest_ancestor_length(const char *path, const char *prefix_list) +{ + char buf[PATH_MAX+1]; + const char *ceil, *colon; + int len, max_len = -1; + + if (prefix_list == NULL || !strcmp(path, "/")) + return -1; + + for (colon = ceil = prefix_list; *colon; ceil = colon+1) { + for (colon = ceil; *colon && *colon != PATH_SEP; colon++); + len = colon - ceil; + if (len == 0 || len > PATH_MAX || !is_absolute_path(ceil)) + continue; + strlcpy(buf, ceil, len+1); + if (normalize_path_copy(buf, buf) < 0) + continue; + len = strlen(buf); + if (len > 0 && buf[len-1] == '/') + buf[--len] = '\0'; + + if (!strncmp(path, buf, len) && + path[len] == '/' && + len > max_len) { + max_len = len; + } + } + + return max_len; +} + +/* strip arbitrary amount of directory separators at end of path */ +static inline int chomp_trailing_dir_sep(const char *path, int len) +{ + while (len && is_dir_sep(path[len - 1])) + len--; + return len; +} + +/* + * If path ends with suffix (complete path components), returns the + * part before suffix (sans trailing directory separators). + * Otherwise returns NULL. + */ +char *strip_path_suffix(const char *path, const char *suffix) +{ + int path_len = strlen(path), suffix_len = strlen(suffix); + + while (suffix_len) { + if (!path_len) + return NULL; + + if (is_dir_sep(path[path_len - 1])) { + if (!is_dir_sep(suffix[suffix_len - 1])) + return NULL; + path_len = chomp_trailing_dir_sep(path, path_len); + suffix_len = chomp_trailing_dir_sep(suffix, suffix_len); + } + else if (path[--path_len] != suffix[--suffix_len]) + return NULL; + } + + if (path_len && !is_dir_sep(path[path_len - 1])) + return NULL; + return xstrndup(path, chomp_trailing_dir_sep(path, path_len)); +} diff --git a/tools/perf/util/quote.c b/tools/perf/util/quote.c new file mode 100644 index 000000000000..f18c5212bc92 --- /dev/null +++ b/tools/perf/util/quote.c @@ -0,0 +1,481 @@ +#include "cache.h" +#include "quote.h" + +int quote_path_fully = 1; + +/* Help to copy the thing properly quoted for the shell safety. + * any single quote is replaced with '\'', any exclamation point + * is replaced with '\!', and the whole thing is enclosed in a + * + * E.g. + * original sq_quote result + * name ==> name ==> 'name' + * a b ==> a b ==> 'a b' + * a'b ==> a'\''b ==> 'a'\''b' + * a!b ==> a'\!'b ==> 'a'\!'b' + */ +static inline int need_bs_quote(char c) +{ + return (c == '\'' || c == '!'); +} + +void sq_quote_buf(struct strbuf *dst, const char *src) +{ + char *to_free = NULL; + + if (dst->buf == src) + to_free = strbuf_detach(dst, NULL); + + strbuf_addch(dst, '\''); + while (*src) { + size_t len = strcspn(src, "'!"); + strbuf_add(dst, src, len); + src += len; + while (need_bs_quote(*src)) { + strbuf_addstr(dst, "'\\"); + strbuf_addch(dst, *src++); + strbuf_addch(dst, '\''); + } + } + strbuf_addch(dst, '\''); + free(to_free); +} + +void sq_quote_print(FILE *stream, const char *src) +{ + char c; + + fputc('\'', stream); + while ((c = *src++)) { + if (need_bs_quote(c)) { + fputs("'\\", stream); + fputc(c, stream); + fputc('\'', stream); + } else { + fputc(c, stream); + } + } + fputc('\'', stream); +} + +void sq_quote_argv(struct strbuf *dst, const char** argv, size_t maxlen) +{ + int i; + + /* Copy into destination buffer. */ + strbuf_grow(dst, 255); + for (i = 0; argv[i]; ++i) { + strbuf_addch(dst, ' '); + sq_quote_buf(dst, argv[i]); + if (maxlen && dst->len > maxlen) + die("Too many or long arguments"); + } +} + +char *sq_dequote_step(char *arg, char **next) +{ + char *dst = arg; + char *src = arg; + char c; + + if (*src != '\'') + return NULL; + for (;;) { + c = *++src; + if (!c) + return NULL; + if (c != '\'') { + *dst++ = c; + continue; + } + /* We stepped out of sq */ + switch (*++src) { + case '\0': + *dst = 0; + if (next) + *next = NULL; + return arg; + case '\\': + c = *++src; + if (need_bs_quote(c) && *++src == '\'') { + *dst++ = c; + continue; + } + /* Fallthrough */ + default: + if (!next || !isspace(*src)) + return NULL; + do { + c = *++src; + } while (isspace(c)); + *dst = 0; + *next = src; + return arg; + } + } +} + +char *sq_dequote(char *arg) +{ + return sq_dequote_step(arg, NULL); +} + +int sq_dequote_to_argv(char *arg, const char ***argv, int *nr, int *alloc) +{ + char *next = arg; + + if (!*arg) + return 0; + do { + char *dequoted = sq_dequote_step(next, &next); + if (!dequoted) + return -1; + ALLOC_GROW(*argv, *nr + 1, *alloc); + (*argv)[(*nr)++] = dequoted; + } while (next); + + return 0; +} + +/* 1 means: quote as octal + * 0 means: quote as octal if (quote_path_fully) + * -1 means: never quote + * c: quote as "\\c" + */ +#define X8(x) x, x, x, x, x, x, x, x +#define X16(x) X8(x), X8(x) +static signed char const sq_lookup[256] = { + /* 0 1 2 3 4 5 6 7 */ + /* 0x00 */ 1, 1, 1, 1, 1, 1, 1, 'a', + /* 0x08 */ 'b', 't', 'n', 'v', 'f', 'r', 1, 1, + /* 0x10 */ X16(1), + /* 0x20 */ -1, -1, '"', -1, -1, -1, -1, -1, + /* 0x28 */ X16(-1), X16(-1), X16(-1), + /* 0x58 */ -1, -1, -1, -1,'\\', -1, -1, -1, + /* 0x60 */ X16(-1), X8(-1), + /* 0x78 */ -1, -1, -1, -1, -1, -1, -1, 1, + /* 0x80 */ /* set to 0 */ +}; + +static inline int sq_must_quote(char c) +{ + return sq_lookup[(unsigned char)c] + quote_path_fully > 0; +} + +/* returns the longest prefix not needing a quote up to maxlen if positive. + This stops at the first \0 because it's marked as a character needing an + escape */ +static size_t next_quote_pos(const char *s, ssize_t maxlen) +{ + size_t len; + if (maxlen < 0) { + for (len = 0; !sq_must_quote(s[len]); len++); + } else { + for (len = 0; len < maxlen && !sq_must_quote(s[len]); len++); + } + return len; +} + +/* + * C-style name quoting. + * + * (1) if sb and fp are both NULL, inspect the input name and counts the + * number of bytes that are needed to hold c_style quoted version of name, + * counting the double quotes around it but not terminating NUL, and + * returns it. + * However, if name does not need c_style quoting, it returns 0. + * + * (2) if sb or fp are not NULL, it emits the c_style quoted version + * of name, enclosed with double quotes if asked and needed only. + * Return value is the same as in (1). + */ +static size_t quote_c_style_counted(const char *name, ssize_t maxlen, + struct strbuf *sb, FILE *fp, int no_dq) +{ +#undef EMIT +#define EMIT(c) \ + do { \ + if (sb) strbuf_addch(sb, (c)); \ + if (fp) fputc((c), fp); \ + count++; \ + } while (0) +#define EMITBUF(s, l) \ + do { \ + int __ret; \ + if (sb) strbuf_add(sb, (s), (l)); \ + if (fp) __ret = fwrite((s), (l), 1, fp); \ + count += (l); \ + } while (0) + + size_t len, count = 0; + const char *p = name; + + for (;;) { + int ch; + + len = next_quote_pos(p, maxlen); + if (len == maxlen || !p[len]) + break; + + if (!no_dq && p == name) + EMIT('"'); + + EMITBUF(p, len); + EMIT('\\'); + p += len; + ch = (unsigned char)*p++; + if (sq_lookup[ch] >= ' ') { + EMIT(sq_lookup[ch]); + } else { + EMIT(((ch >> 6) & 03) + '0'); + EMIT(((ch >> 3) & 07) + '0'); + EMIT(((ch >> 0) & 07) + '0'); + } + } + + EMITBUF(p, len); + if (p == name) /* no ending quote needed */ + return 0; + + if (!no_dq) + EMIT('"'); + return count; +} + +size_t quote_c_style(const char *name, struct strbuf *sb, FILE *fp, int nodq) +{ + return quote_c_style_counted(name, -1, sb, fp, nodq); +} + +void quote_two_c_style(struct strbuf *sb, const char *prefix, const char *path, int nodq) +{ + if (quote_c_style(prefix, NULL, NULL, 0) || + quote_c_style(path, NULL, NULL, 0)) { + if (!nodq) + strbuf_addch(sb, '"'); + quote_c_style(prefix, sb, NULL, 1); + quote_c_style(path, sb, NULL, 1); + if (!nodq) + strbuf_addch(sb, '"'); + } else { + strbuf_addstr(sb, prefix); + strbuf_addstr(sb, path); + } +} + +void write_name_quoted(const char *name, FILE *fp, int terminator) +{ + if (terminator) { + quote_c_style(name, NULL, fp, 0); + } else { + fputs(name, fp); + } + fputc(terminator, fp); +} + +extern void write_name_quotedpfx(const char *pfx, size_t pfxlen, + const char *name, FILE *fp, int terminator) +{ + int needquote = 0; + + if (terminator) { + needquote = next_quote_pos(pfx, pfxlen) < pfxlen + || name[next_quote_pos(name, -1)]; + } + if (needquote) { + fputc('"', fp); + quote_c_style_counted(pfx, pfxlen, NULL, fp, 1); + quote_c_style(name, NULL, fp, 1); + fputc('"', fp); + } else { + int ret; + + ret = fwrite(pfx, pfxlen, 1, fp); + fputs(name, fp); + } + fputc(terminator, fp); +} + +/* quote path as relative to the given prefix */ +char *quote_path_relative(const char *in, int len, + struct strbuf *out, const char *prefix) +{ + int needquote; + + if (len < 0) + len = strlen(in); + + /* "../" prefix itself does not need quoting, but "in" might. */ + needquote = next_quote_pos(in, len) < len; + strbuf_setlen(out, 0); + strbuf_grow(out, len); + + if (needquote) + strbuf_addch(out, '"'); + if (prefix) { + int off = 0; + while (prefix[off] && off < len && prefix[off] == in[off]) + if (prefix[off] == '/') { + prefix += off + 1; + in += off + 1; + len -= off + 1; + off = 0; + } else + off++; + + for (; *prefix; prefix++) + if (*prefix == '/') + strbuf_addstr(out, "../"); + } + + quote_c_style_counted (in, len, out, NULL, 1); + + if (needquote) + strbuf_addch(out, '"'); + if (!out->len) + strbuf_addstr(out, "./"); + + return out->buf; +} + +/* + * C-style name unquoting. + * + * Quoted should point at the opening double quote. + * + Returns 0 if it was able to unquote the string properly, and appends the + * result in the strbuf `sb'. + * + Returns -1 in case of error, and doesn't touch the strbuf. Though note + * that this function will allocate memory in the strbuf, so calling + * strbuf_release is mandatory whichever result unquote_c_style returns. + * + * Updates endp pointer to point at one past the ending double quote if given. + */ +int unquote_c_style(struct strbuf *sb, const char *quoted, const char **endp) +{ + size_t oldlen = sb->len, len; + int ch, ac; + + if (*quoted++ != '"') + return -1; + + for (;;) { + len = strcspn(quoted, "\"\\"); + strbuf_add(sb, quoted, len); + quoted += len; + + switch (*quoted++) { + case '"': + if (endp) + *endp = quoted; + return 0; + case '\\': + break; + default: + goto error; + } + + switch ((ch = *quoted++)) { + case 'a': ch = '\a'; break; + case 'b': ch = '\b'; break; + case 'f': ch = '\f'; break; + case 'n': ch = '\n'; break; + case 'r': ch = '\r'; break; + case 't': ch = '\t'; break; + case 'v': ch = '\v'; break; + + case '\\': case '"': + break; /* verbatim */ + + /* octal values with first digit over 4 overflow */ + case '0': case '1': case '2': case '3': + ac = ((ch - '0') << 6); + if ((ch = *quoted++) < '0' || '7' < ch) + goto error; + ac |= ((ch - '0') << 3); + if ((ch = *quoted++) < '0' || '7' < ch) + goto error; + ac |= (ch - '0'); + ch = ac; + break; + default: + goto error; + } + strbuf_addch(sb, ch); + } + + error: + strbuf_setlen(sb, oldlen); + return -1; +} + +/* quoting as a string literal for other languages */ + +void perl_quote_print(FILE *stream, const char *src) +{ + const char sq = '\''; + const char bq = '\\'; + char c; + + fputc(sq, stream); + while ((c = *src++)) { + if (c == sq || c == bq) + fputc(bq, stream); + fputc(c, stream); + } + fputc(sq, stream); +} + +void python_quote_print(FILE *stream, const char *src) +{ + const char sq = '\''; + const char bq = '\\'; + const char nl = '\n'; + char c; + + fputc(sq, stream); + while ((c = *src++)) { + if (c == nl) { + fputc(bq, stream); + fputc('n', stream); + continue; + } + if (c == sq || c == bq) + fputc(bq, stream); + fputc(c, stream); + } + fputc(sq, stream); +} + +void tcl_quote_print(FILE *stream, const char *src) +{ + char c; + + fputc('"', stream); + while ((c = *src++)) { + switch (c) { + case '[': case ']': + case '{': case '}': + case '$': case '\\': case '"': + fputc('\\', stream); + default: + fputc(c, stream); + break; + case '\f': + fputs("\\f", stream); + break; + case '\r': + fputs("\\r", stream); + break; + case '\n': + fputs("\\n", stream); + break; + case '\t': + fputs("\\t", stream); + break; + case '\v': + fputs("\\v", stream); + break; + } + } + fputc('"', stream); +} diff --git a/tools/perf/util/quote.h b/tools/perf/util/quote.h new file mode 100644 index 000000000000..5dfad89816db --- /dev/null +++ b/tools/perf/util/quote.h @@ -0,0 +1,68 @@ +#ifndef QUOTE_H +#define QUOTE_H + +#include +#include + +/* Help to copy the thing properly quoted for the shell safety. + * any single quote is replaced with '\'', any exclamation point + * is replaced with '\!', and the whole thing is enclosed in a + * single quote pair. + * + * For example, if you are passing the result to system() as an + * argument: + * + * sprintf(cmd, "foobar %s %s", sq_quote(arg0), sq_quote(arg1)) + * + * would be appropriate. If the system() is going to call ssh to + * run the command on the other side: + * + * sprintf(cmd, "git-diff-tree %s %s", sq_quote(arg0), sq_quote(arg1)); + * sprintf(rcmd, "ssh %s %s", sq_util/quote.host), sq_quote(cmd)); + * + * Note that the above examples leak memory! Remember to free result from + * sq_quote() in a real application. + * + * sq_quote_buf() writes to an existing buffer of specified size; it + * will return the number of characters that would have been written + * excluding the final null regardless of the buffer size. + */ + +extern void sq_quote_print(FILE *stream, const char *src); + +extern void sq_quote_buf(struct strbuf *, const char *src); +extern void sq_quote_argv(struct strbuf *, const char **argv, size_t maxlen); + +/* This unwraps what sq_quote() produces in place, but returns + * NULL if the input does not look like what sq_quote would have + * produced. + */ +extern char *sq_dequote(char *); + +/* + * Same as the above, but can be used to unwrap many arguments in the + * same string separated by space. "next" is changed to point to the + * next argument that should be passed as first parameter. When there + * is no more argument to be dequoted, "next" is updated to point to NULL. + */ +extern char *sq_dequote_step(char *arg, char **next); +extern int sq_dequote_to_argv(char *arg, const char ***argv, int *nr, int *alloc); + +extern int unquote_c_style(struct strbuf *, const char *quoted, const char **endp); +extern size_t quote_c_style(const char *name, struct strbuf *, FILE *, int no_dq); +extern void quote_two_c_style(struct strbuf *, const char *, const char *, int); + +extern void write_name_quoted(const char *name, FILE *, int terminator); +extern void write_name_quotedpfx(const char *pfx, size_t pfxlen, + const char *name, FILE *, int terminator); + +/* quote path as relative to the given prefix */ +char *quote_path_relative(const char *in, int len, + struct strbuf *out, const char *prefix); + +/* quoting as a string literal for other languages */ +extern void perl_quote_print(FILE *stream, const char *src); +extern void python_quote_print(FILE *stream, const char *src); +extern void tcl_quote_print(FILE *stream, const char *src); + +#endif diff --git a/tools/perf/util/rbtree.c b/tools/perf/util/rbtree.c new file mode 100644 index 000000000000..b15ba9c7cb3f --- /dev/null +++ b/tools/perf/util/rbtree.c @@ -0,0 +1,383 @@ +/* + Red Black Trees + (C) 1999 Andrea Arcangeli + (C) 2002 David Woodhouse + + 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 + + linux/lib/rbtree.c +*/ + +#include "rbtree.h" + +static void __rb_rotate_left(struct rb_node *node, struct rb_root *root) +{ + struct rb_node *right = node->rb_right; + struct rb_node *parent = rb_parent(node); + + if ((node->rb_right = right->rb_left)) + rb_set_parent(right->rb_left, node); + right->rb_left = node; + + rb_set_parent(right, parent); + + if (parent) + { + if (node == parent->rb_left) + parent->rb_left = right; + else + parent->rb_right = right; + } + else + root->rb_node = right; + rb_set_parent(node, right); +} + +static void __rb_rotate_right(struct rb_node *node, struct rb_root *root) +{ + struct rb_node *left = node->rb_left; + struct rb_node *parent = rb_parent(node); + + if ((node->rb_left = left->rb_right)) + rb_set_parent(left->rb_right, node); + left->rb_right = node; + + rb_set_parent(left, parent); + + if (parent) + { + if (node == parent->rb_right) + parent->rb_right = left; + else + parent->rb_left = left; + } + else + root->rb_node = left; + rb_set_parent(node, left); +} + +void rb_insert_color(struct rb_node *node, struct rb_root *root) +{ + struct rb_node *parent, *gparent; + + while ((parent = rb_parent(node)) && rb_is_red(parent)) + { + gparent = rb_parent(parent); + + if (parent == gparent->rb_left) + { + { + register struct rb_node *uncle = gparent->rb_right; + if (uncle && rb_is_red(uncle)) + { + rb_set_black(uncle); + rb_set_black(parent); + rb_set_red(gparent); + node = gparent; + continue; + } + } + + if (parent->rb_right == node) + { + register struct rb_node *tmp; + __rb_rotate_left(parent, root); + tmp = parent; + parent = node; + node = tmp; + } + + rb_set_black(parent); + rb_set_red(gparent); + __rb_rotate_right(gparent, root); + } else { + { + register struct rb_node *uncle = gparent->rb_left; + if (uncle && rb_is_red(uncle)) + { + rb_set_black(uncle); + rb_set_black(parent); + rb_set_red(gparent); + node = gparent; + continue; + } + } + + if (parent->rb_left == node) + { + register struct rb_node *tmp; + __rb_rotate_right(parent, root); + tmp = parent; + parent = node; + node = tmp; + } + + rb_set_black(parent); + rb_set_red(gparent); + __rb_rotate_left(gparent, root); + } + } + + rb_set_black(root->rb_node); +} + +static void __rb_erase_color(struct rb_node *node, struct rb_node *parent, + struct rb_root *root) +{ + struct rb_node *other; + + while ((!node || rb_is_black(node)) && node != root->rb_node) + { + if (parent->rb_left == node) + { + other = parent->rb_right; + if (rb_is_red(other)) + { + rb_set_black(other); + rb_set_red(parent); + __rb_rotate_left(parent, root); + other = parent->rb_right; + } + if ((!other->rb_left || rb_is_black(other->rb_left)) && + (!other->rb_right || rb_is_black(other->rb_right))) + { + rb_set_red(other); + node = parent; + parent = rb_parent(node); + } + else + { + if (!other->rb_right || rb_is_black(other->rb_right)) + { + rb_set_black(other->rb_left); + rb_set_red(other); + __rb_rotate_right(other, root); + other = parent->rb_right; + } + rb_set_color(other, rb_color(parent)); + rb_set_black(parent); + rb_set_black(other->rb_right); + __rb_rotate_left(parent, root); + node = root->rb_node; + break; + } + } + else + { + other = parent->rb_left; + if (rb_is_red(other)) + { + rb_set_black(other); + rb_set_red(parent); + __rb_rotate_right(parent, root); + other = parent->rb_left; + } + if ((!other->rb_left || rb_is_black(other->rb_left)) && + (!other->rb_right || rb_is_black(other->rb_right))) + { + rb_set_red(other); + node = parent; + parent = rb_parent(node); + } + else + { + if (!other->rb_left || rb_is_black(other->rb_left)) + { + rb_set_black(other->rb_right); + rb_set_red(other); + __rb_rotate_left(other, root); + other = parent->rb_left; + } + rb_set_color(other, rb_color(parent)); + rb_set_black(parent); + rb_set_black(other->rb_left); + __rb_rotate_right(parent, root); + node = root->rb_node; + break; + } + } + } + if (node) + rb_set_black(node); +} + +void rb_erase(struct rb_node *node, struct rb_root *root) +{ + struct rb_node *child, *parent; + int color; + + if (!node->rb_left) + child = node->rb_right; + else if (!node->rb_right) + child = node->rb_left; + else + { + struct rb_node *old = node, *left; + + node = node->rb_right; + while ((left = node->rb_left) != NULL) + node = left; + child = node->rb_right; + parent = rb_parent(node); + color = rb_color(node); + + if (child) + rb_set_parent(child, parent); + if (parent == old) { + parent->rb_right = child; + parent = node; + } else + parent->rb_left = child; + + node->rb_parent_color = old->rb_parent_color; + node->rb_right = old->rb_right; + node->rb_left = old->rb_left; + + if (rb_parent(old)) + { + if (rb_parent(old)->rb_left == old) + rb_parent(old)->rb_left = node; + else + rb_parent(old)->rb_right = node; + } else + root->rb_node = node; + + rb_set_parent(old->rb_left, node); + if (old->rb_right) + rb_set_parent(old->rb_right, node); + goto color; + } + + parent = rb_parent(node); + color = rb_color(node); + + if (child) + rb_set_parent(child, parent); + if (parent) + { + if (parent->rb_left == node) + parent->rb_left = child; + else + parent->rb_right = child; + } + else + root->rb_node = child; + + color: + if (color == RB_BLACK) + __rb_erase_color(child, parent, root); +} + +/* + * This function returns the first node (in sort order) of the tree. + */ +struct rb_node *rb_first(const struct rb_root *root) +{ + struct rb_node *n; + + n = root->rb_node; + if (!n) + return NULL; + while (n->rb_left) + n = n->rb_left; + return n; +} + +struct rb_node *rb_last(const struct rb_root *root) +{ + struct rb_node *n; + + n = root->rb_node; + if (!n) + return NULL; + while (n->rb_right) + n = n->rb_right; + return n; +} + +struct rb_node *rb_next(const struct rb_node *node) +{ + struct rb_node *parent; + + if (rb_parent(node) == node) + return NULL; + + /* If we have a right-hand child, go down and then left as far + as we can. */ + if (node->rb_right) { + node = node->rb_right; + while (node->rb_left) + node=node->rb_left; + return (struct rb_node *)node; + } + + /* No right-hand children. Everything down and left is + smaller than us, so any 'next' node must be in the general + direction of our parent. Go up the tree; any time the + ancestor is a right-hand child of its parent, keep going + up. First time it's a left-hand child of its parent, said + parent is our 'next' node. */ + while ((parent = rb_parent(node)) && node == parent->rb_right) + node = parent; + + return parent; +} + +struct rb_node *rb_prev(const struct rb_node *node) +{ + struct rb_node *parent; + + if (rb_parent(node) == node) + return NULL; + + /* If we have a left-hand child, go down and then right as far + as we can. */ + if (node->rb_left) { + node = node->rb_left; + while (node->rb_right) + node=node->rb_right; + return (struct rb_node *)node; + } + + /* No left-hand children. Go up till we find an ancestor which + is a right-hand child of its parent */ + while ((parent = rb_parent(node)) && node == parent->rb_left) + node = parent; + + return parent; +} + +void rb_replace_node(struct rb_node *victim, struct rb_node *new, + struct rb_root *root) +{ + struct rb_node *parent = rb_parent(victim); + + /* Set the surrounding nodes to point to the replacement */ + if (parent) { + if (victim == parent->rb_left) + parent->rb_left = new; + else + parent->rb_right = new; + } else { + root->rb_node = new; + } + if (victim->rb_left) + rb_set_parent(victim->rb_left, new); + if (victim->rb_right) + rb_set_parent(victim->rb_right, new); + + /* Copy the pointers/colour from the victim to the replacement */ + *new = *victim; +} diff --git a/tools/perf/util/rbtree.h b/tools/perf/util/rbtree.h new file mode 100644 index 000000000000..6bdc488a47fb --- /dev/null +++ b/tools/perf/util/rbtree.h @@ -0,0 +1,171 @@ +/* + Red Black Trees + (C) 1999 Andrea Arcangeli + + 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 + + linux/include/linux/rbtree.h + + To use rbtrees you'll have to implement your own insert and search cores. + This will avoid us to use callbacks and to drop drammatically performances. + I know it's not the cleaner way, but in C (not in C++) to get + performances and genericity... + + Some example of insert and search follows here. The search is a plain + normal search over an ordered tree. The insert instead must be implemented + int two steps: as first thing the code must insert the element in + order as a red leaf in the tree, then the support library function + rb_insert_color() must be called. Such function will do the + not trivial work to rebalance the rbtree if necessary. + +----------------------------------------------------------------------- +static inline struct page * rb_search_page_cache(struct inode * inode, + unsigned long offset) +{ + struct rb_node * n = inode->i_rb_page_cache.rb_node; + struct page * page; + + while (n) + { + page = rb_entry(n, struct page, rb_page_cache); + + if (offset < page->offset) + n = n->rb_left; + else if (offset > page->offset) + n = n->rb_right; + else + return page; + } + return NULL; +} + +static inline struct page * __rb_insert_page_cache(struct inode * inode, + unsigned long offset, + struct rb_node * node) +{ + struct rb_node ** p = &inode->i_rb_page_cache.rb_node; + struct rb_node * parent = NULL; + struct page * page; + + while (*p) + { + parent = *p; + page = rb_entry(parent, struct page, rb_page_cache); + + if (offset < page->offset) + p = &(*p)->rb_left; + else if (offset > page->offset) + p = &(*p)->rb_right; + else + return page; + } + + rb_link_node(node, parent, p); + + return NULL; +} + +static inline struct page * rb_insert_page_cache(struct inode * inode, + unsigned long offset, + struct rb_node * node) +{ + struct page * ret; + if ((ret = __rb_insert_page_cache(inode, offset, node))) + goto out; + rb_insert_color(node, &inode->i_rb_page_cache); + out: + return ret; +} +----------------------------------------------------------------------- +*/ + +#ifndef _LINUX_RBTREE_H +#define _LINUX_RBTREE_H + +#include + +/** + * container_of - cast a member of a structure out to the containing structure + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + * + */ +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +struct rb_node +{ + unsigned long rb_parent_color; +#define RB_RED 0 +#define RB_BLACK 1 + struct rb_node *rb_right; + struct rb_node *rb_left; +} __attribute__((aligned(sizeof(long)))); + /* The alignment might seem pointless, but allegedly CRIS needs it */ + +struct rb_root +{ + struct rb_node *rb_node; +}; + + +#define rb_parent(r) ((struct rb_node *)((r)->rb_parent_color & ~3)) +#define rb_color(r) ((r)->rb_parent_color & 1) +#define rb_is_red(r) (!rb_color(r)) +#define rb_is_black(r) rb_color(r) +#define rb_set_red(r) do { (r)->rb_parent_color &= ~1; } while (0) +#define rb_set_black(r) do { (r)->rb_parent_color |= 1; } while (0) + +static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p) +{ + rb->rb_parent_color = (rb->rb_parent_color & 3) | (unsigned long)p; +} +static inline void rb_set_color(struct rb_node *rb, int color) +{ + rb->rb_parent_color = (rb->rb_parent_color & ~1) | color; +} + +#define RB_ROOT (struct rb_root) { NULL, } +#define rb_entry(ptr, type, member) container_of(ptr, type, member) + +#define RB_EMPTY_ROOT(root) ((root)->rb_node == NULL) +#define RB_EMPTY_NODE(node) (rb_parent(node) == node) +#define RB_CLEAR_NODE(node) (rb_set_parent(node, node)) + +extern void rb_insert_color(struct rb_node *, struct rb_root *); +extern void rb_erase(struct rb_node *, struct rb_root *); + +/* Find logical next and previous nodes in a tree */ +extern struct rb_node *rb_next(const struct rb_node *); +extern struct rb_node *rb_prev(const struct rb_node *); +extern struct rb_node *rb_first(const struct rb_root *); +extern struct rb_node *rb_last(const struct rb_root *); + +/* Fast replacement of a single node without remove/rebalance/add/rebalance */ +extern void rb_replace_node(struct rb_node *victim, struct rb_node *new, + struct rb_root *root); + +static inline void rb_link_node(struct rb_node * node, struct rb_node * parent, + struct rb_node ** rb_link) +{ + node->rb_parent_color = (unsigned long )parent; + node->rb_left = node->rb_right = NULL; + + *rb_link = node; +} + +#endif /* _LINUX_RBTREE_H */ diff --git a/tools/perf/util/run-command.c b/tools/perf/util/run-command.c new file mode 100644 index 000000000000..b2f5e854f40a --- /dev/null +++ b/tools/perf/util/run-command.c @@ -0,0 +1,395 @@ +#include "cache.h" +#include "run-command.h" +#include "exec_cmd.h" + +static inline void close_pair(int fd[2]) +{ + close(fd[0]); + close(fd[1]); +} + +static inline void dup_devnull(int to) +{ + int fd = open("/dev/null", O_RDWR); + dup2(fd, to); + close(fd); +} + +int start_command(struct child_process *cmd) +{ + int need_in, need_out, need_err; + int fdin[2], fdout[2], fderr[2]; + + /* + * In case of errors we must keep the promise to close FDs + * that have been passed in via ->in and ->out. + */ + + need_in = !cmd->no_stdin && cmd->in < 0; + if (need_in) { + if (pipe(fdin) < 0) { + if (cmd->out > 0) + close(cmd->out); + return -ERR_RUN_COMMAND_PIPE; + } + cmd->in = fdin[1]; + } + + need_out = !cmd->no_stdout + && !cmd->stdout_to_stderr + && cmd->out < 0; + if (need_out) { + if (pipe(fdout) < 0) { + if (need_in) + close_pair(fdin); + else if (cmd->in) + close(cmd->in); + return -ERR_RUN_COMMAND_PIPE; + } + cmd->out = fdout[0]; + } + + need_err = !cmd->no_stderr && cmd->err < 0; + if (need_err) { + if (pipe(fderr) < 0) { + if (need_in) + close_pair(fdin); + else if (cmd->in) + close(cmd->in); + if (need_out) + close_pair(fdout); + else if (cmd->out) + close(cmd->out); + return -ERR_RUN_COMMAND_PIPE; + } + cmd->err = fderr[0]; + } + +#ifndef __MINGW32__ + fflush(NULL); + cmd->pid = fork(); + if (!cmd->pid) { + if (cmd->no_stdin) + dup_devnull(0); + else if (need_in) { + dup2(fdin[0], 0); + close_pair(fdin); + } else if (cmd->in) { + dup2(cmd->in, 0); + close(cmd->in); + } + + if (cmd->no_stderr) + dup_devnull(2); + else if (need_err) { + dup2(fderr[1], 2); + close_pair(fderr); + } + + if (cmd->no_stdout) + dup_devnull(1); + else if (cmd->stdout_to_stderr) + dup2(2, 1); + else if (need_out) { + dup2(fdout[1], 1); + close_pair(fdout); + } else if (cmd->out > 1) { + dup2(cmd->out, 1); + close(cmd->out); + } + + if (cmd->dir && chdir(cmd->dir)) + die("exec %s: cd to %s failed (%s)", cmd->argv[0], + cmd->dir, strerror(errno)); + if (cmd->env) { + for (; *cmd->env; cmd->env++) { + if (strchr(*cmd->env, '=')) + putenv((char*)*cmd->env); + else + unsetenv(*cmd->env); + } + } + if (cmd->preexec_cb) + cmd->preexec_cb(); + if (cmd->perf_cmd) { + execv_perf_cmd(cmd->argv); + } else { + execvp(cmd->argv[0], (char *const*) cmd->argv); + } + exit(127); + } +#else + int s0 = -1, s1 = -1, s2 = -1; /* backups of stdin, stdout, stderr */ + const char **sargv = cmd->argv; + char **env = environ; + + if (cmd->no_stdin) { + s0 = dup(0); + dup_devnull(0); + } else if (need_in) { + s0 = dup(0); + dup2(fdin[0], 0); + } else if (cmd->in) { + s0 = dup(0); + dup2(cmd->in, 0); + } + + if (cmd->no_stderr) { + s2 = dup(2); + dup_devnull(2); + } else if (need_err) { + s2 = dup(2); + dup2(fderr[1], 2); + } + + if (cmd->no_stdout) { + s1 = dup(1); + dup_devnull(1); + } else if (cmd->stdout_to_stderr) { + s1 = dup(1); + dup2(2, 1); + } else if (need_out) { + s1 = dup(1); + dup2(fdout[1], 1); + } else if (cmd->out > 1) { + s1 = dup(1); + dup2(cmd->out, 1); + } + + if (cmd->dir) + die("chdir in start_command() not implemented"); + if (cmd->env) { + env = copy_environ(); + for (; *cmd->env; cmd->env++) + env = env_setenv(env, *cmd->env); + } + + if (cmd->perf_cmd) { + cmd->argv = prepare_perf_cmd(cmd->argv); + } + + cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, env); + + if (cmd->env) + free_environ(env); + if (cmd->perf_cmd) + free(cmd->argv); + + cmd->argv = sargv; + if (s0 >= 0) + dup2(s0, 0), close(s0); + if (s1 >= 0) + dup2(s1, 1), close(s1); + if (s2 >= 0) + dup2(s2, 2), close(s2); +#endif + + if (cmd->pid < 0) { + int err = errno; + if (need_in) + close_pair(fdin); + else if (cmd->in) + close(cmd->in); + if (need_out) + close_pair(fdout); + else if (cmd->out) + close(cmd->out); + if (need_err) + close_pair(fderr); + return err == ENOENT ? + -ERR_RUN_COMMAND_EXEC : + -ERR_RUN_COMMAND_FORK; + } + + if (need_in) + close(fdin[0]); + else if (cmd->in) + close(cmd->in); + + if (need_out) + close(fdout[1]); + else if (cmd->out) + close(cmd->out); + + if (need_err) + close(fderr[1]); + + return 0; +} + +static int wait_or_whine(pid_t pid) +{ + for (;;) { + int status, code; + pid_t waiting = waitpid(pid, &status, 0); + + if (waiting < 0) { + if (errno == EINTR) + continue; + error("waitpid failed (%s)", strerror(errno)); + return -ERR_RUN_COMMAND_WAITPID; + } + if (waiting != pid) + return -ERR_RUN_COMMAND_WAITPID_WRONG_PID; + if (WIFSIGNALED(status)) + return -ERR_RUN_COMMAND_WAITPID_SIGNAL; + + if (!WIFEXITED(status)) + return -ERR_RUN_COMMAND_WAITPID_NOEXIT; + code = WEXITSTATUS(status); + switch (code) { + case 127: + return -ERR_RUN_COMMAND_EXEC; + case 0: + return 0; + default: + return -code; + } + } +} + +int finish_command(struct child_process *cmd) +{ + return wait_or_whine(cmd->pid); +} + +int run_command(struct child_process *cmd) +{ + int code = start_command(cmd); + if (code) + return code; + return finish_command(cmd); +} + +static void prepare_run_command_v_opt(struct child_process *cmd, + const char **argv, + int opt) +{ + memset(cmd, 0, sizeof(*cmd)); + cmd->argv = argv; + cmd->no_stdin = opt & RUN_COMMAND_NO_STDIN ? 1 : 0; + cmd->perf_cmd = opt & RUN_PERF_CMD ? 1 : 0; + cmd->stdout_to_stderr = opt & RUN_COMMAND_STDOUT_TO_STDERR ? 1 : 0; +} + +int run_command_v_opt(const char **argv, int opt) +{ + struct child_process cmd; + prepare_run_command_v_opt(&cmd, argv, opt); + return run_command(&cmd); +} + +int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const char *const *env) +{ + struct child_process cmd; + prepare_run_command_v_opt(&cmd, argv, opt); + cmd.dir = dir; + cmd.env = env; + return run_command(&cmd); +} + +#ifdef __MINGW32__ +static __stdcall unsigned run_thread(void *data) +{ + struct async *async = data; + return async->proc(async->fd_for_proc, async->data); +} +#endif + +int start_async(struct async *async) +{ + int pipe_out[2]; + + if (pipe(pipe_out) < 0) + return error("cannot create pipe: %s", strerror(errno)); + async->out = pipe_out[0]; + +#ifndef __MINGW32__ + /* Flush stdio before fork() to avoid cloning buffers */ + fflush(NULL); + + async->pid = fork(); + if (async->pid < 0) { + error("fork (async) failed: %s", strerror(errno)); + close_pair(pipe_out); + return -1; + } + if (!async->pid) { + close(pipe_out[0]); + exit(!!async->proc(pipe_out[1], async->data)); + } + close(pipe_out[1]); +#else + async->fd_for_proc = pipe_out[1]; + async->tid = (HANDLE) _beginthreadex(NULL, 0, run_thread, async, 0, NULL); + if (!async->tid) { + error("cannot create thread: %s", strerror(errno)); + close_pair(pipe_out); + return -1; + } +#endif + return 0; +} + +int finish_async(struct async *async) +{ +#ifndef __MINGW32__ + int ret = 0; + + if (wait_or_whine(async->pid)) + ret = error("waitpid (async) failed"); +#else + DWORD ret = 0; + if (WaitForSingleObject(async->tid, INFINITE) != WAIT_OBJECT_0) + ret = error("waiting for thread failed: %lu", GetLastError()); + else if (!GetExitCodeThread(async->tid, &ret)) + ret = error("cannot get thread exit code: %lu", GetLastError()); + CloseHandle(async->tid); +#endif + return ret; +} + +int run_hook(const char *index_file, const char *name, ...) +{ + struct child_process hook; + const char **argv = NULL, *env[2]; + char index[PATH_MAX]; + va_list args; + int ret; + size_t i = 0, alloc = 0; + + if (access(perf_path("hooks/%s", name), X_OK) < 0) + return 0; + + va_start(args, name); + ALLOC_GROW(argv, i + 1, alloc); + argv[i++] = perf_path("hooks/%s", name); + while (argv[i-1]) { + ALLOC_GROW(argv, i + 1, alloc); + argv[i++] = va_arg(args, const char *); + } + va_end(args); + + memset(&hook, 0, sizeof(hook)); + hook.argv = argv; + hook.no_stdin = 1; + hook.stdout_to_stderr = 1; + if (index_file) { + snprintf(index, sizeof(index), "PERF_INDEX_FILE=%s", index_file); + env[0] = index; + env[1] = NULL; + hook.env = env; + } + + ret = start_command(&hook); + free(argv); + if (ret) { + warning("Could not spawn %s", argv[0]); + return ret; + } + ret = finish_command(&hook); + if (ret == -ERR_RUN_COMMAND_WAITPID_SIGNAL) + warning("%s exited due to uncaught signal", argv[0]); + + return ret; +} diff --git a/tools/perf/util/run-command.h b/tools/perf/util/run-command.h new file mode 100644 index 000000000000..328289f23669 --- /dev/null +++ b/tools/perf/util/run-command.h @@ -0,0 +1,93 @@ +#ifndef RUN_COMMAND_H +#define RUN_COMMAND_H + +enum { + ERR_RUN_COMMAND_FORK = 10000, + ERR_RUN_COMMAND_EXEC, + ERR_RUN_COMMAND_PIPE, + ERR_RUN_COMMAND_WAITPID, + ERR_RUN_COMMAND_WAITPID_WRONG_PID, + ERR_RUN_COMMAND_WAITPID_SIGNAL, + ERR_RUN_COMMAND_WAITPID_NOEXIT, +}; +#define IS_RUN_COMMAND_ERR(x) (-(x) >= ERR_RUN_COMMAND_FORK) + +struct child_process { + const char **argv; + pid_t pid; + /* + * Using .in, .out, .err: + * - Specify 0 for no redirections (child inherits stdin, stdout, + * stderr from parent). + * - Specify -1 to have a pipe allocated as follows: + * .in: returns the writable pipe end; parent writes to it, + * the readable pipe end becomes child's stdin + * .out, .err: returns the readable pipe end; parent reads from + * it, the writable pipe end becomes child's stdout/stderr + * The caller of start_command() must close the returned FDs + * after it has completed reading from/writing to it! + * - Specify > 0 to set a channel to a particular FD as follows: + * .in: a readable FD, becomes child's stdin + * .out: a writable FD, becomes child's stdout/stderr + * .err > 0 not supported + * The specified FD is closed by start_command(), even in case + * of errors! + */ + int in; + int out; + int err; + const char *dir; + const char *const *env; + unsigned no_stdin:1; + unsigned no_stdout:1; + unsigned no_stderr:1; + unsigned perf_cmd:1; /* if this is to be perf sub-command */ + unsigned stdout_to_stderr:1; + void (*preexec_cb)(void); +}; + +int start_command(struct child_process *); +int finish_command(struct child_process *); +int run_command(struct child_process *); + +extern int run_hook(const char *index_file, const char *name, ...); + +#define RUN_COMMAND_NO_STDIN 1 +#define RUN_PERF_CMD 2 /*If this is to be perf sub-command */ +#define RUN_COMMAND_STDOUT_TO_STDERR 4 +int run_command_v_opt(const char **argv, int opt); + +/* + * env (the environment) is to be formatted like environ: "VAR=VALUE". + * To unset an environment variable use just "VAR". + */ +int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const char *const *env); + +/* + * The purpose of the following functions is to feed a pipe by running + * a function asynchronously and providing output that the caller reads. + * + * It is expected that no synchronization and mutual exclusion between + * the caller and the feed function is necessary so that the function + * can run in a thread without interfering with the caller. + */ +struct async { + /* + * proc writes to fd and closes it; + * returns 0 on success, non-zero on failure + */ + int (*proc)(int fd, void *data); + void *data; + int out; /* caller reads from here and closes it */ +#ifndef __MINGW32__ + pid_t pid; +#else + HANDLE tid; + int fd_for_proc; +#endif +}; + +int start_async(struct async *async); +int finish_async(struct async *async); + +#endif diff --git a/tools/perf/util/sigchain.c b/tools/perf/util/sigchain.c new file mode 100644 index 000000000000..1118b99e57d3 --- /dev/null +++ b/tools/perf/util/sigchain.c @@ -0,0 +1,52 @@ +#include "sigchain.h" +#include "cache.h" + +#define SIGCHAIN_MAX_SIGNALS 32 + +struct sigchain_signal { + sigchain_fun *old; + int n; + int alloc; +}; +static struct sigchain_signal signals[SIGCHAIN_MAX_SIGNALS]; + +static void check_signum(int sig) +{ + if (sig < 1 || sig >= SIGCHAIN_MAX_SIGNALS) + die("BUG: signal out of range: %d", sig); +} + +int sigchain_push(int sig, sigchain_fun f) +{ + struct sigchain_signal *s = signals + sig; + check_signum(sig); + + ALLOC_GROW(s->old, s->n + 1, s->alloc); + s->old[s->n] = signal(sig, f); + if (s->old[s->n] == SIG_ERR) + return -1; + s->n++; + return 0; +} + +int sigchain_pop(int sig) +{ + struct sigchain_signal *s = signals + sig; + check_signum(sig); + if (s->n < 1) + return 0; + + if (signal(sig, s->old[s->n - 1]) == SIG_ERR) + return -1; + s->n--; + return 0; +} + +void sigchain_push_common(sigchain_fun f) +{ + sigchain_push(SIGINT, f); + sigchain_push(SIGHUP, f); + sigchain_push(SIGTERM, f); + sigchain_push(SIGQUIT, f); + sigchain_push(SIGPIPE, f); +} diff --git a/tools/perf/util/sigchain.h b/tools/perf/util/sigchain.h new file mode 100644 index 000000000000..618083bce0c6 --- /dev/null +++ b/tools/perf/util/sigchain.h @@ -0,0 +1,11 @@ +#ifndef SIGCHAIN_H +#define SIGCHAIN_H + +typedef void (*sigchain_fun)(int); + +int sigchain_push(int sig, sigchain_fun f); +int sigchain_pop(int sig); + +void sigchain_push_common(sigchain_fun f); + +#endif /* SIGCHAIN_H */ diff --git a/tools/perf/util/strbuf.c b/tools/perf/util/strbuf.c new file mode 100644 index 000000000000..eaba09306802 --- /dev/null +++ b/tools/perf/util/strbuf.c @@ -0,0 +1,359 @@ +#include "cache.h" + +int prefixcmp(const char *str, const char *prefix) +{ + for (; ; str++, prefix++) + if (!*prefix) + return 0; + else if (*str != *prefix) + return (unsigned char)*prefix - (unsigned char)*str; +} + +/* + * Used as the default ->buf value, so that people can always assume + * buf is non NULL and ->buf is NUL terminated even for a freshly + * initialized strbuf. + */ +char strbuf_slopbuf[1]; + +void strbuf_init(struct strbuf *sb, size_t hint) +{ + sb->alloc = sb->len = 0; + sb->buf = strbuf_slopbuf; + if (hint) + strbuf_grow(sb, hint); +} + +void strbuf_release(struct strbuf *sb) +{ + if (sb->alloc) { + free(sb->buf); + strbuf_init(sb, 0); + } +} + +char *strbuf_detach(struct strbuf *sb, size_t *sz) +{ + char *res = sb->alloc ? sb->buf : NULL; + if (sz) + *sz = sb->len; + strbuf_init(sb, 0); + return res; +} + +void strbuf_attach(struct strbuf *sb, void *buf, size_t len, size_t alloc) +{ + strbuf_release(sb); + sb->buf = buf; + sb->len = len; + sb->alloc = alloc; + strbuf_grow(sb, 0); + sb->buf[sb->len] = '\0'; +} + +void strbuf_grow(struct strbuf *sb, size_t extra) +{ + if (sb->len + extra + 1 <= sb->len) + die("you want to use way too much memory"); + if (!sb->alloc) + sb->buf = NULL; + ALLOC_GROW(sb->buf, sb->len + extra + 1, sb->alloc); +} + +void strbuf_trim(struct strbuf *sb) +{ + char *b = sb->buf; + while (sb->len > 0 && isspace((unsigned char)sb->buf[sb->len - 1])) + sb->len--; + while (sb->len > 0 && isspace(*b)) { + b++; + sb->len--; + } + memmove(sb->buf, b, sb->len); + sb->buf[sb->len] = '\0'; +} +void strbuf_rtrim(struct strbuf *sb) +{ + while (sb->len > 0 && isspace((unsigned char)sb->buf[sb->len - 1])) + sb->len--; + sb->buf[sb->len] = '\0'; +} + +void strbuf_ltrim(struct strbuf *sb) +{ + char *b = sb->buf; + while (sb->len > 0 && isspace(*b)) { + b++; + sb->len--; + } + memmove(sb->buf, b, sb->len); + sb->buf[sb->len] = '\0'; +} + +void strbuf_tolower(struct strbuf *sb) +{ + int i; + for (i = 0; i < sb->len; i++) + sb->buf[i] = tolower(sb->buf[i]); +} + +struct strbuf **strbuf_split(const struct strbuf *sb, int delim) +{ + int alloc = 2, pos = 0; + char *n, *p; + struct strbuf **ret; + struct strbuf *t; + + ret = calloc(alloc, sizeof(struct strbuf *)); + p = n = sb->buf; + while (n < sb->buf + sb->len) { + int len; + n = memchr(n, delim, sb->len - (n - sb->buf)); + if (pos + 1 >= alloc) { + alloc = alloc * 2; + ret = realloc(ret, sizeof(struct strbuf *) * alloc); + } + if (!n) + n = sb->buf + sb->len - 1; + len = n - p + 1; + t = malloc(sizeof(struct strbuf)); + strbuf_init(t, len); + strbuf_add(t, p, len); + ret[pos] = t; + ret[++pos] = NULL; + p = ++n; + } + return ret; +} + +void strbuf_list_free(struct strbuf **sbs) +{ + struct strbuf **s = sbs; + + while (*s) { + strbuf_release(*s); + free(*s++); + } + free(sbs); +} + +int strbuf_cmp(const struct strbuf *a, const struct strbuf *b) +{ + int len = a->len < b->len ? a->len: b->len; + int cmp = memcmp(a->buf, b->buf, len); + if (cmp) + return cmp; + return a->len < b->len ? -1: a->len != b->len; +} + +void strbuf_splice(struct strbuf *sb, size_t pos, size_t len, + const void *data, size_t dlen) +{ + if (pos + len < pos) + die("you want to use way too much memory"); + if (pos > sb->len) + die("`pos' is too far after the end of the buffer"); + if (pos + len > sb->len) + die("`pos + len' is too far after the end of the buffer"); + + if (dlen >= len) + strbuf_grow(sb, dlen - len); + memmove(sb->buf + pos + dlen, + sb->buf + pos + len, + sb->len - pos - len); + memcpy(sb->buf + pos, data, dlen); + strbuf_setlen(sb, sb->len + dlen - len); +} + +void strbuf_insert(struct strbuf *sb, size_t pos, const void *data, size_t len) +{ + strbuf_splice(sb, pos, 0, data, len); +} + +void strbuf_remove(struct strbuf *sb, size_t pos, size_t len) +{ + strbuf_splice(sb, pos, len, NULL, 0); +} + +void strbuf_add(struct strbuf *sb, const void *data, size_t len) +{ + strbuf_grow(sb, len); + memcpy(sb->buf + sb->len, data, len); + strbuf_setlen(sb, sb->len + len); +} + +void strbuf_adddup(struct strbuf *sb, size_t pos, size_t len) +{ + strbuf_grow(sb, len); + memcpy(sb->buf + sb->len, sb->buf + pos, len); + strbuf_setlen(sb, sb->len + len); +} + +void strbuf_addf(struct strbuf *sb, const char *fmt, ...) +{ + int len; + va_list ap; + + if (!strbuf_avail(sb)) + strbuf_grow(sb, 64); + va_start(ap, fmt); + len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap); + va_end(ap); + if (len < 0) + die("your vsnprintf is broken"); + if (len > strbuf_avail(sb)) { + strbuf_grow(sb, len); + va_start(ap, fmt); + len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap); + va_end(ap); + if (len > strbuf_avail(sb)) { + die("this should not happen, your snprintf is broken"); + } + } + strbuf_setlen(sb, sb->len + len); +} + +void strbuf_expand(struct strbuf *sb, const char *format, expand_fn_t fn, + void *context) +{ + for (;;) { + const char *percent; + size_t consumed; + + percent = strchrnul(format, '%'); + strbuf_add(sb, format, percent - format); + if (!*percent) + break; + format = percent + 1; + + consumed = fn(sb, format, context); + if (consumed) + format += consumed; + else + strbuf_addch(sb, '%'); + } +} + +size_t strbuf_expand_dict_cb(struct strbuf *sb, const char *placeholder, + void *context) +{ + struct strbuf_expand_dict_entry *e = context; + size_t len; + + for (; e->placeholder && (len = strlen(e->placeholder)); e++) { + if (!strncmp(placeholder, e->placeholder, len)) { + if (e->value) + strbuf_addstr(sb, e->value); + return len; + } + } + return 0; +} + +size_t strbuf_fread(struct strbuf *sb, size_t size, FILE *f) +{ + size_t res; + size_t oldalloc = sb->alloc; + + strbuf_grow(sb, size); + res = fread(sb->buf + sb->len, 1, size, f); + if (res > 0) + strbuf_setlen(sb, sb->len + res); + else if (res < 0 && oldalloc == 0) + strbuf_release(sb); + return res; +} + +ssize_t strbuf_read(struct strbuf *sb, int fd, size_t hint) +{ + size_t oldlen = sb->len; + size_t oldalloc = sb->alloc; + + strbuf_grow(sb, hint ? hint : 8192); + for (;;) { + ssize_t cnt; + + cnt = read(fd, sb->buf + sb->len, sb->alloc - sb->len - 1); + if (cnt < 0) { + if (oldalloc == 0) + strbuf_release(sb); + else + strbuf_setlen(sb, oldlen); + return -1; + } + if (!cnt) + break; + sb->len += cnt; + strbuf_grow(sb, 8192); + } + + sb->buf[sb->len] = '\0'; + return sb->len - oldlen; +} + +#define STRBUF_MAXLINK (2*PATH_MAX) + +int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint) +{ + size_t oldalloc = sb->alloc; + + if (hint < 32) + hint = 32; + + while (hint < STRBUF_MAXLINK) { + int len; + + strbuf_grow(sb, hint); + len = readlink(path, sb->buf, hint); + if (len < 0) { + if (errno != ERANGE) + break; + } else if (len < hint) { + strbuf_setlen(sb, len); + return 0; + } + + /* .. the buffer was too small - try again */ + hint *= 2; + } + if (oldalloc == 0) + strbuf_release(sb); + return -1; +} + +int strbuf_getline(struct strbuf *sb, FILE *fp, int term) +{ + int ch; + + strbuf_grow(sb, 0); + if (feof(fp)) + return EOF; + + strbuf_reset(sb); + while ((ch = fgetc(fp)) != EOF) { + if (ch == term) + break; + strbuf_grow(sb, 1); + sb->buf[sb->len++] = ch; + } + if (ch == EOF && sb->len == 0) + return EOF; + + sb->buf[sb->len] = '\0'; + return 0; +} + +int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint) +{ + int fd, len; + + fd = open(path, O_RDONLY); + if (fd < 0) + return -1; + len = strbuf_read(sb, fd, hint); + close(fd); + if (len < 0) + return -1; + + return len; +} diff --git a/tools/perf/util/strbuf.h b/tools/perf/util/strbuf.h new file mode 100644 index 000000000000..9ee908a3ec5d --- /dev/null +++ b/tools/perf/util/strbuf.h @@ -0,0 +1,137 @@ +#ifndef STRBUF_H +#define STRBUF_H + +/* + * Strbuf's can be use in many ways: as a byte array, or to store arbitrary + * long, overflow safe strings. + * + * Strbufs has some invariants that are very important to keep in mind: + * + * 1. the ->buf member is always malloc-ed, hence strbuf's can be used to + * build complex strings/buffers whose final size isn't easily known. + * + * It is NOT legal to copy the ->buf pointer away. + * `strbuf_detach' is the operation that detachs a buffer from its shell + * while keeping the shell valid wrt its invariants. + * + * 2. the ->buf member is a byte array that has at least ->len + 1 bytes + * allocated. The extra byte is used to store a '\0', allowing the ->buf + * member to be a valid C-string. Every strbuf function ensure this + * invariant is preserved. + * + * Note that it is OK to "play" with the buffer directly if you work it + * that way: + * + * strbuf_grow(sb, SOME_SIZE); + * ... Here, the memory array starting at sb->buf, and of length + * ... strbuf_avail(sb) is all yours, and you are sure that + * ... strbuf_avail(sb) is at least SOME_SIZE. + * strbuf_setlen(sb, sb->len + SOME_OTHER_SIZE); + * + * Of course, SOME_OTHER_SIZE must be smaller or equal to strbuf_avail(sb). + * + * Doing so is safe, though if it has to be done in many places, adding the + * missing API to the strbuf module is the way to go. + * + * XXX: do _not_ assume that the area that is yours is of size ->alloc - 1 + * even if it's true in the current implementation. Alloc is somehow a + * "private" member that should not be messed with. + */ + +#include + +extern char strbuf_slopbuf[]; +struct strbuf { + size_t alloc; + size_t len; + char *buf; +}; + +#define STRBUF_INIT { 0, 0, strbuf_slopbuf } + +/*----- strbuf life cycle -----*/ +extern void strbuf_init(struct strbuf *, size_t); +extern void strbuf_release(struct strbuf *); +extern char *strbuf_detach(struct strbuf *, size_t *); +extern void strbuf_attach(struct strbuf *, void *, size_t, size_t); +static inline void strbuf_swap(struct strbuf *a, struct strbuf *b) { + struct strbuf tmp = *a; + *a = *b; + *b = tmp; +} + +/*----- strbuf size related -----*/ +static inline size_t strbuf_avail(const struct strbuf *sb) { + return sb->alloc ? sb->alloc - sb->len - 1 : 0; +} + +extern void strbuf_grow(struct strbuf *, size_t); + +static inline void strbuf_setlen(struct strbuf *sb, size_t len) { + if (!sb->alloc) + strbuf_grow(sb, 0); + assert(len < sb->alloc); + sb->len = len; + sb->buf[len] = '\0'; +} +#define strbuf_reset(sb) strbuf_setlen(sb, 0) + +/*----- content related -----*/ +extern void strbuf_trim(struct strbuf *); +extern void strbuf_rtrim(struct strbuf *); +extern void strbuf_ltrim(struct strbuf *); +extern int strbuf_cmp(const struct strbuf *, const struct strbuf *); +extern void strbuf_tolower(struct strbuf *); + +extern struct strbuf **strbuf_split(const struct strbuf *, int delim); +extern void strbuf_list_free(struct strbuf **); + +/*----- add data in your buffer -----*/ +static inline void strbuf_addch(struct strbuf *sb, int c) { + strbuf_grow(sb, 1); + sb->buf[sb->len++] = c; + sb->buf[sb->len] = '\0'; +} + +extern void strbuf_insert(struct strbuf *, size_t pos, const void *, size_t); +extern void strbuf_remove(struct strbuf *, size_t pos, size_t len); + +/* splice pos..pos+len with given data */ +extern void strbuf_splice(struct strbuf *, size_t pos, size_t len, + const void *, size_t); + +extern void strbuf_add(struct strbuf *, const void *, size_t); +static inline void strbuf_addstr(struct strbuf *sb, const char *s) { + strbuf_add(sb, s, strlen(s)); +} +static inline void strbuf_addbuf(struct strbuf *sb, const struct strbuf *sb2) { + strbuf_add(sb, sb2->buf, sb2->len); +} +extern void strbuf_adddup(struct strbuf *sb, size_t pos, size_t len); + +typedef size_t (*expand_fn_t) (struct strbuf *sb, const char *placeholder, void *context); +extern void strbuf_expand(struct strbuf *sb, const char *format, expand_fn_t fn, void *context); +struct strbuf_expand_dict_entry { + const char *placeholder; + const char *value; +}; +extern size_t strbuf_expand_dict_cb(struct strbuf *sb, const char *placeholder, void *context); + +__attribute__((format(printf,2,3))) +extern void strbuf_addf(struct strbuf *sb, const char *fmt, ...); + +extern size_t strbuf_fread(struct strbuf *, size_t, FILE *); +/* XXX: if read fails, any partial read is undone */ +extern ssize_t strbuf_read(struct strbuf *, int fd, size_t hint); +extern int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint); +extern int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint); + +extern int strbuf_getline(struct strbuf *, FILE *, int); + +extern void stripspace(struct strbuf *buf, int skip_comments); +extern int launch_editor(const char *path, struct strbuf *buffer, const char *const *env); + +extern int strbuf_branchname(struct strbuf *sb, const char *name); +extern int strbuf_check_branch_ref(struct strbuf *sb, const char *name); + +#endif /* STRBUF_H */ diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c new file mode 100644 index 000000000000..c93eca9a7be3 --- /dev/null +++ b/tools/perf/util/string.c @@ -0,0 +1,34 @@ +#include "string.h" + +static int hex(char ch) +{ + if ((ch >= '0') && (ch <= '9')) + return ch - '0'; + if ((ch >= 'a') && (ch <= 'f')) + return ch - 'a' + 10; + if ((ch >= 'A') && (ch <= 'F')) + return ch - 'A' + 10; + return -1; +} + +/* + * While we find nice hex chars, build a long_val. + * Return number of chars processed. + */ +int hex2u64(const char *ptr, u64 *long_val) +{ + const char *p = ptr; + *long_val = 0; + + while (*p) { + const int hex_val = hex(*p); + + if (hex_val < 0) + break; + + *long_val = (*long_val << 4) | hex_val; + p++; + } + + return p - ptr; +} diff --git a/tools/perf/util/string.h b/tools/perf/util/string.h new file mode 100644 index 000000000000..37b03255b425 --- /dev/null +++ b/tools/perf/util/string.h @@ -0,0 +1,8 @@ +#ifndef _PERF_STRING_H_ +#define _PERF_STRING_H_ + +#include "../types.h" + +int hex2u64(const char *ptr, u64 *val); + +#endif diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c new file mode 100644 index 000000000000..86e14375e74e --- /dev/null +++ b/tools/perf/util/symbol.c @@ -0,0 +1,641 @@ +#include "util.h" +#include "../perf.h" +#include "string.h" +#include "symbol.h" + +#include +#include +#include + +const char *sym_hist_filter; + +static struct symbol *symbol__new(u64 start, u64 len, + const char *name, unsigned int priv_size, + u64 obj_start, int verbose) +{ + size_t namelen = strlen(name) + 1; + struct symbol *self = calloc(1, priv_size + sizeof(*self) + namelen); + + if (!self) + return NULL; + + if (verbose >= 2) + printf("new symbol: %016Lx [%08lx]: %s, hist: %p, obj_start: %p\n", + (u64)start, (unsigned long)len, name, self->hist, (void *)(unsigned long)obj_start); + + self->obj_start= obj_start; + self->hist = NULL; + self->hist_sum = 0; + + if (sym_hist_filter && !strcmp(name, sym_hist_filter)) + self->hist = calloc(sizeof(u64), len); + + if (priv_size) { + memset(self, 0, priv_size); + self = ((void *)self) + priv_size; + } + self->start = start; + self->end = start + len - 1; + memcpy(self->name, name, namelen); + + return self; +} + +static void symbol__delete(struct symbol *self, unsigned int priv_size) +{ + free(((void *)self) - priv_size); +} + +static size_t symbol__fprintf(struct symbol *self, FILE *fp) +{ + return fprintf(fp, " %llx-%llx %s\n", + self->start, self->end, self->name); +} + +struct dso *dso__new(const char *name, unsigned int sym_priv_size) +{ + struct dso *self = malloc(sizeof(*self) + strlen(name) + 1); + + if (self != NULL) { + strcpy(self->name, name); + self->syms = RB_ROOT; + self->sym_priv_size = sym_priv_size; + self->find_symbol = dso__find_symbol; + } + + return self; +} + +static void dso__delete_symbols(struct dso *self) +{ + struct symbol *pos; + struct rb_node *next = rb_first(&self->syms); + + while (next) { + pos = rb_entry(next, struct symbol, rb_node); + next = rb_next(&pos->rb_node); + rb_erase(&pos->rb_node, &self->syms); + symbol__delete(pos, self->sym_priv_size); + } +} + +void dso__delete(struct dso *self) +{ + dso__delete_symbols(self); + free(self); +} + +static void dso__insert_symbol(struct dso *self, struct symbol *sym) +{ + struct rb_node **p = &self->syms.rb_node; + struct rb_node *parent = NULL; + const u64 ip = sym->start; + struct symbol *s; + + while (*p != NULL) { + parent = *p; + s = rb_entry(parent, struct symbol, rb_node); + if (ip < s->start) + p = &(*p)->rb_left; + else + p = &(*p)->rb_right; + } + rb_link_node(&sym->rb_node, parent, p); + rb_insert_color(&sym->rb_node, &self->syms); +} + +struct symbol *dso__find_symbol(struct dso *self, u64 ip) +{ + struct rb_node *n; + + if (self == NULL) + return NULL; + + n = self->syms.rb_node; + + while (n) { + struct symbol *s = rb_entry(n, struct symbol, rb_node); + + if (ip < s->start) + n = n->rb_left; + else if (ip > s->end) + n = n->rb_right; + else + return s; + } + + return NULL; +} + +size_t dso__fprintf(struct dso *self, FILE *fp) +{ + size_t ret = fprintf(fp, "dso: %s\n", self->name); + + struct rb_node *nd; + for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) { + struct symbol *pos = rb_entry(nd, struct symbol, rb_node); + ret += symbol__fprintf(pos, fp); + } + + return ret; +} + +static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int verbose) +{ + struct rb_node *nd, *prevnd; + char *line = NULL; + size_t n; + FILE *file = fopen("/proc/kallsyms", "r"); + + if (file == NULL) + goto out_failure; + + while (!feof(file)) { + u64 start; + struct symbol *sym; + int line_len, len; + char symbol_type; + + line_len = getline(&line, &n, file); + if (line_len < 0) + break; + + if (!line) + goto out_failure; + + line[--line_len] = '\0'; /* \n */ + + len = hex2u64(line, &start); + + len++; + if (len + 2 >= line_len) + continue; + + symbol_type = toupper(line[len]); + /* + * We're interested only in code ('T'ext) + */ + if (symbol_type != 'T' && symbol_type != 'W') + continue; + /* + * Well fix up the end later, when we have all sorted. + */ + sym = symbol__new(start, 0xdead, line + len + 2, + self->sym_priv_size, 0, verbose); + + if (sym == NULL) + goto out_delete_line; + + if (filter && filter(self, sym)) + symbol__delete(sym, self->sym_priv_size); + else + dso__insert_symbol(self, sym); + } + + /* + * Now that we have all sorted out, just set the ->end of all + * symbols + */ + prevnd = rb_first(&self->syms); + + if (prevnd == NULL) + goto out_delete_line; + + for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { + struct symbol *prev = rb_entry(prevnd, struct symbol, rb_node), + *curr = rb_entry(nd, struct symbol, rb_node); + + prev->end = curr->start - 1; + prevnd = nd; + } + + free(line); + fclose(file); + + return 0; + +out_delete_line: + free(line); +out_failure: + return -1; +} + +static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int verbose) +{ + char *line = NULL; + size_t n; + FILE *file; + int nr_syms = 0; + + file = fopen(self->name, "r"); + if (file == NULL) + goto out_failure; + + while (!feof(file)) { + u64 start, size; + struct symbol *sym; + int line_len, len; + + line_len = getline(&line, &n, file); + if (line_len < 0) + break; + + if (!line) + goto out_failure; + + line[--line_len] = '\0'; /* \n */ + + len = hex2u64(line, &start); + + len++; + if (len + 2 >= line_len) + continue; + + len += hex2u64(line + len, &size); + + len++; + if (len + 2 >= line_len) + continue; + + sym = symbol__new(start, size, line + len, + self->sym_priv_size, start, verbose); + + if (sym == NULL) + goto out_delete_line; + + if (filter && filter(self, sym)) + symbol__delete(sym, self->sym_priv_size); + else { + dso__insert_symbol(self, sym); + nr_syms++; + } + } + + free(line); + fclose(file); + + return nr_syms; + +out_delete_line: + free(line); +out_failure: + return -1; +} + +/** + * elf_symtab__for_each_symbol - iterate thru all the symbols + * + * @self: struct elf_symtab instance to iterate + * @index: uint32_t index + * @sym: GElf_Sym iterator + */ +#define elf_symtab__for_each_symbol(syms, nr_syms, index, sym) \ + for (index = 0, gelf_getsym(syms, index, &sym);\ + index < nr_syms; \ + index++, gelf_getsym(syms, index, &sym)) + +static inline uint8_t elf_sym__type(const GElf_Sym *sym) +{ + return GELF_ST_TYPE(sym->st_info); +} + +static inline int elf_sym__is_function(const GElf_Sym *sym) +{ + return elf_sym__type(sym) == STT_FUNC && + sym->st_name != 0 && + sym->st_shndx != SHN_UNDEF && + sym->st_size != 0; +} + +static inline const char *elf_sym__name(const GElf_Sym *sym, + const Elf_Data *symstrs) +{ + return symstrs->d_buf + sym->st_name; +} + +static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, + GElf_Shdr *shp, const char *name, + size_t *index) +{ + Elf_Scn *sec = NULL; + size_t cnt = 1; + + while ((sec = elf_nextscn(elf, sec)) != NULL) { + char *str; + + gelf_getshdr(sec, shp); + str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name); + if (!strcmp(name, str)) { + if (index) + *index = cnt; + break; + } + ++cnt; + } + + return sec; +} + +#define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \ + for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \ + idx < nr_entries; \ + ++idx, pos = gelf_getrel(reldata, idx, &pos_mem)) + +#define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \ + for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \ + idx < nr_entries; \ + ++idx, pos = gelf_getrela(reldata, idx, &pos_mem)) + +static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf, + GElf_Ehdr *ehdr, Elf_Scn *scn_dynsym, + GElf_Shdr *shdr_dynsym, + size_t dynsym_idx, int verbose) +{ + uint32_t nr_rel_entries, idx; + GElf_Sym sym; + u64 plt_offset; + GElf_Shdr shdr_plt; + struct symbol *f; + GElf_Shdr shdr_rel_plt; + Elf_Data *reldata, *syms, *symstrs; + Elf_Scn *scn_plt_rel, *scn_symstrs; + char sympltname[1024]; + int nr = 0, symidx; + + scn_plt_rel = elf_section_by_name(elf, ehdr, &shdr_rel_plt, + ".rela.plt", NULL); + if (scn_plt_rel == NULL) { + scn_plt_rel = elf_section_by_name(elf, ehdr, &shdr_rel_plt, + ".rel.plt", NULL); + if (scn_plt_rel == NULL) + return 0; + } + + if (shdr_rel_plt.sh_link != dynsym_idx) + return 0; + + if (elf_section_by_name(elf, ehdr, &shdr_plt, ".plt", NULL) == NULL) + return 0; + + /* + * Fetch the relocation section to find the indexes to the GOT + * and the symbols in the .dynsym they refer to. + */ + reldata = elf_getdata(scn_plt_rel, NULL); + if (reldata == NULL) + return -1; + + syms = elf_getdata(scn_dynsym, NULL); + if (syms == NULL) + return -1; + + scn_symstrs = elf_getscn(elf, shdr_dynsym->sh_link); + if (scn_symstrs == NULL) + return -1; + + symstrs = elf_getdata(scn_symstrs, NULL); + if (symstrs == NULL) + return -1; + + nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize; + plt_offset = shdr_plt.sh_offset; + + if (shdr_rel_plt.sh_type == SHT_RELA) { + GElf_Rela pos_mem, *pos; + + elf_section__for_each_rela(reldata, pos, pos_mem, idx, + nr_rel_entries) { + symidx = GELF_R_SYM(pos->r_info); + plt_offset += shdr_plt.sh_entsize; + gelf_getsym(syms, symidx, &sym); + snprintf(sympltname, sizeof(sympltname), + "%s@plt", elf_sym__name(&sym, symstrs)); + + f = symbol__new(plt_offset, shdr_plt.sh_entsize, + sympltname, self->sym_priv_size, 0, verbose); + if (!f) + return -1; + + dso__insert_symbol(self, f); + ++nr; + } + } else if (shdr_rel_plt.sh_type == SHT_REL) { + GElf_Rel pos_mem, *pos; + elf_section__for_each_rel(reldata, pos, pos_mem, idx, + nr_rel_entries) { + symidx = GELF_R_SYM(pos->r_info); + plt_offset += shdr_plt.sh_entsize; + gelf_getsym(syms, symidx, &sym); + snprintf(sympltname, sizeof(sympltname), + "%s@plt", elf_sym__name(&sym, symstrs)); + + f = symbol__new(plt_offset, shdr_plt.sh_entsize, + sympltname, self->sym_priv_size, 0, verbose); + if (!f) + return -1; + + dso__insert_symbol(self, f); + ++nr; + } + } else { + /* + * TODO: There are still one more shdr_rel_plt.sh_type + * I have to investigate, but probably should be ignored. + */ + } + + return nr; +} + +static int dso__load_sym(struct dso *self, int fd, const char *name, + symbol_filter_t filter, int verbose) +{ + Elf_Data *symstrs; + uint32_t nr_syms; + int err = -1; + uint32_t index; + GElf_Ehdr ehdr; + GElf_Shdr shdr; + Elf_Data *syms; + GElf_Sym sym; + Elf_Scn *sec, *sec_dynsym; + Elf *elf; + size_t dynsym_idx; + int nr = 0; + + elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); + if (elf == NULL) { + if (verbose) + fprintf(stderr, "%s: cannot read %s ELF file.\n", + __func__, name); + goto out_close; + } + + if (gelf_getehdr(elf, &ehdr) == NULL) { + if (verbose) + fprintf(stderr, "%s: cannot get elf header.\n", __func__); + goto out_elf_end; + } + + /* + * We need to check if we have a .dynsym, so that we can handle the + * .plt, synthesizing its symbols, that aren't on the symtabs (be it + * .dynsym or .symtab) + */ + sec_dynsym = elf_section_by_name(elf, &ehdr, &shdr, + ".dynsym", &dynsym_idx); + if (sec_dynsym != NULL) { + nr = dso__synthesize_plt_symbols(self, elf, &ehdr, + sec_dynsym, &shdr, + dynsym_idx, verbose); + if (nr < 0) + goto out_elf_end; + } + + /* + * But if we have a full .symtab (that is a superset of .dynsym) we + * should add the symbols not in the .dynsyn + */ + sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL); + if (sec == NULL) { + if (sec_dynsym == NULL) + goto out_elf_end; + + sec = sec_dynsym; + gelf_getshdr(sec, &shdr); + } + + syms = elf_getdata(sec, NULL); + if (syms == NULL) + goto out_elf_end; + + sec = elf_getscn(elf, shdr.sh_link); + if (sec == NULL) + goto out_elf_end; + + symstrs = elf_getdata(sec, NULL); + if (symstrs == NULL) + goto out_elf_end; + + nr_syms = shdr.sh_size / shdr.sh_entsize; + + memset(&sym, 0, sizeof(sym)); + + elf_symtab__for_each_symbol(syms, nr_syms, index, sym) { + struct symbol *f; + u64 obj_start; + + if (!elf_sym__is_function(&sym)) + continue; + + sec = elf_getscn(elf, sym.st_shndx); + if (!sec) + goto out_elf_end; + + gelf_getshdr(sec, &shdr); + obj_start = sym.st_value; + + sym.st_value -= shdr.sh_addr - shdr.sh_offset; + + f = symbol__new(sym.st_value, sym.st_size, + elf_sym__name(&sym, symstrs), + self->sym_priv_size, obj_start, verbose); + if (!f) + goto out_elf_end; + + if (filter && filter(self, f)) + symbol__delete(f, self->sym_priv_size); + else { + dso__insert_symbol(self, f); + nr++; + } + } + + err = nr; +out_elf_end: + elf_end(elf); +out_close: + return err; +} + +int dso__load(struct dso *self, symbol_filter_t filter, int verbose) +{ + int size = strlen(self->name) + sizeof("/usr/lib/debug%s.debug"); + char *name = malloc(size); + int variant = 0; + int ret = -1; + int fd; + + if (!name) + return -1; + + if (strncmp(self->name, "/tmp/perf-", 10) == 0) + return dso__load_perf_map(self, filter, verbose); + +more: + do { + switch (variant) { + case 0: /* Fedora */ + snprintf(name, size, "/usr/lib/debug%s.debug", self->name); + break; + case 1: /* Ubuntu */ + snprintf(name, size, "/usr/lib/debug%s", self->name); + break; + case 2: /* Sane people */ + snprintf(name, size, "%s", self->name); + break; + + default: + goto out; + } + variant++; + + fd = open(name, O_RDONLY); + } while (fd < 0); + + ret = dso__load_sym(self, fd, name, filter, verbose); + close(fd); + + /* + * Some people seem to have debuginfo files _WITHOUT_ debug info!?!? + */ + if (!ret) + goto more; + +out: + free(name); + return ret; +} + +static int dso__load_vmlinux(struct dso *self, const char *vmlinux, + symbol_filter_t filter, int verbose) +{ + int err, fd = open(vmlinux, O_RDONLY); + + if (fd < 0) + return -1; + + err = dso__load_sym(self, fd, vmlinux, filter, verbose); + close(fd); + + return err; +} + +int dso__load_kernel(struct dso *self, const char *vmlinux, + symbol_filter_t filter, int verbose) +{ + int err = -1; + + if (vmlinux) + err = dso__load_vmlinux(self, vmlinux, filter, verbose); + + if (err) + err = dso__load_kallsyms(self, filter, verbose); + + return err; +} + +void symbol__init(void) +{ + elf_version(EV_CURRENT); +} diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h new file mode 100644 index 000000000000..ea332e56e458 --- /dev/null +++ b/tools/perf/util/symbol.h @@ -0,0 +1,49 @@ +#ifndef _PERF_SYMBOL_ +#define _PERF_SYMBOL_ 1 + +#include +#include "../types.h" +#include "list.h" +#include "rbtree.h" + +struct symbol { + struct rb_node rb_node; + u64 start; + u64 end; + u64 obj_start; + u64 hist_sum; + u64 *hist; + void *priv; + char name[0]; +}; + +struct dso { + struct list_head node; + struct rb_root syms; + unsigned int sym_priv_size; + struct symbol *(*find_symbol)(struct dso *, u64 ip); + char name[0]; +}; + +const char *sym_hist_filter; + +typedef int (*symbol_filter_t)(struct dso *self, struct symbol *sym); + +struct dso *dso__new(const char *name, unsigned int sym_priv_size); +void dso__delete(struct dso *self); + +static inline void *dso__sym_priv(struct dso *self, struct symbol *sym) +{ + return ((void *)sym) - self->sym_priv_size; +} + +struct symbol *dso__find_symbol(struct dso *self, u64 ip); + +int dso__load_kernel(struct dso *self, const char *vmlinux, + symbol_filter_t filter, int verbose); +int dso__load(struct dso *self, symbol_filter_t filter, int verbose); + +size_t dso__fprintf(struct dso *self, FILE *fp); + +void symbol__init(void); +#endif /* _PERF_SYMBOL_ */ diff --git a/tools/perf/util/usage.c b/tools/perf/util/usage.c new file mode 100644 index 000000000000..e16bf9a707e8 --- /dev/null +++ b/tools/perf/util/usage.c @@ -0,0 +1,80 @@ +/* + * GIT - The information manager from hell + * + * Copyright (C) Linus Torvalds, 2005 + */ +#include "util.h" + +static void report(const char *prefix, const char *err, va_list params) +{ + char msg[1024]; + vsnprintf(msg, sizeof(msg), err, params); + fprintf(stderr, " %s%s\n", prefix, msg); +} + +static NORETURN void usage_builtin(const char *err) +{ + fprintf(stderr, "\n Usage: %s\n", err); + exit(129); +} + +static NORETURN void die_builtin(const char *err, va_list params) +{ + report(" Fatal: ", err, params); + exit(128); +} + +static void error_builtin(const char *err, va_list params) +{ + report(" Error: ", err, params); +} + +static void warn_builtin(const char *warn, va_list params) +{ + report(" Warning: ", warn, params); +} + +/* If we are in a dlopen()ed .so write to a global variable would segfault + * (ugh), so keep things static. */ +static void (*usage_routine)(const char *err) NORETURN = usage_builtin; +static void (*die_routine)(const char *err, va_list params) NORETURN = die_builtin; +static void (*error_routine)(const char *err, va_list params) = error_builtin; +static void (*warn_routine)(const char *err, va_list params) = warn_builtin; + +void set_die_routine(void (*routine)(const char *err, va_list params) NORETURN) +{ + die_routine = routine; +} + +void usage(const char *err) +{ + usage_routine(err); +} + +void die(const char *err, ...) +{ + va_list params; + + va_start(params, err); + die_routine(err, params); + va_end(params); +} + +int error(const char *err, ...) +{ + va_list params; + + va_start(params, err); + error_routine(err, params); + va_end(params); + return -1; +} + +void warning(const char *warn, ...) +{ + va_list params; + + va_start(params, warn); + warn_routine(warn, params); + va_end(params); +} diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h new file mode 100644 index 000000000000..b8cfed776d81 --- /dev/null +++ b/tools/perf/util/util.h @@ -0,0 +1,408 @@ +#ifndef GIT_COMPAT_UTIL_H +#define GIT_COMPAT_UTIL_H + +#define _FILE_OFFSET_BITS 64 + +#ifndef FLEX_ARRAY +/* + * See if our compiler is known to support flexible array members. + */ +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +# define FLEX_ARRAY /* empty */ +#elif defined(__GNUC__) +# if (__GNUC__ >= 3) +# define FLEX_ARRAY /* empty */ +# else +# define FLEX_ARRAY 0 /* older GNU extension */ +# endif +#endif + +/* + * Otherwise, default to safer but a bit wasteful traditional style + */ +#ifndef FLEX_ARRAY +# define FLEX_ARRAY 1 +#endif +#endif + +#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) + +#ifdef __GNUC__ +#define TYPEOF(x) (__typeof__(x)) +#else +#define TYPEOF(x) +#endif + +#define MSB(x, bits) ((x) & TYPEOF(x)(~0ULL << (sizeof(x) * 8 - (bits)))) +#define HAS_MULTI_BITS(i) ((i) & ((i) - 1)) /* checks if an integer has more than 1 bit set */ + +/* Approximation of the length of the decimal representation of this type. */ +#define decimal_length(x) ((int)(sizeof(x) * 2.56 + 0.5) + 1) + +#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__USLC__) && !defined(_M_UNIX) +#define _XOPEN_SOURCE 600 /* glibc2 and AIX 5.3L need 500, OpenBSD needs 600 for S_ISLNK() */ +#define _XOPEN_SOURCE_EXTENDED 1 /* AIX 5.3L needs this */ +#endif +#define _ALL_SOURCE 1 +#define _GNU_SOURCE 1 +#define _BSD_SOURCE 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef __MINGW32__ +#include +#include +#include +#include +#ifndef NO_SYS_SELECT_H +#include +#endif +#include +#include +#include +#include +#include +#include +#if defined(__CYGWIN__) +#undef _XOPEN_SOURCE +#include +#define _XOPEN_SOURCE 600 +#include "compat/cygwin.h" +#else +#undef _ALL_SOURCE /* AIX 5.3L defines a struct list with _ALL_SOURCE. */ +#include +#define _ALL_SOURCE 1 +#endif +#else /* __MINGW32__ */ +/* pull in Windows compatibility stuff */ +#include "compat/mingw.h" +#endif /* __MINGW32__ */ + +#ifndef NO_ICONV +#include +#endif + +/* On most systems would have given us this, but + * not on some systems (e.g. GNU/Hurd). + */ +#ifndef PATH_MAX +#define PATH_MAX 4096 +#endif + +#ifndef PRIuMAX +#define PRIuMAX "llu" +#endif + +#ifndef PRIu32 +#define PRIu32 "u" +#endif + +#ifndef PRIx32 +#define PRIx32 "x" +#endif + +#ifndef PATH_SEP +#define PATH_SEP ':' +#endif + +#ifndef STRIP_EXTENSION +#define STRIP_EXTENSION "" +#endif + +#ifndef has_dos_drive_prefix +#define has_dos_drive_prefix(path) 0 +#endif + +#ifndef is_dir_sep +#define is_dir_sep(c) ((c) == '/') +#endif + +#ifdef __GNUC__ +#define NORETURN __attribute__((__noreturn__)) +#else +#define NORETURN +#ifndef __attribute__ +#define __attribute__(x) +#endif +#endif + +/* General helper functions */ +extern void usage(const char *err) NORETURN; +extern void die(const char *err, ...) NORETURN __attribute__((format (printf, 1, 2))); +extern int error(const char *err, ...) __attribute__((format (printf, 1, 2))); +extern void warning(const char *err, ...) __attribute__((format (printf, 1, 2))); + +extern void set_die_routine(void (*routine)(const char *err, va_list params) NORETURN); + +extern int prefixcmp(const char *str, const char *prefix); +extern time_t tm_to_time_t(const struct tm *tm); + +static inline const char *skip_prefix(const char *str, const char *prefix) +{ + size_t len = strlen(prefix); + return strncmp(str, prefix, len) ? NULL : str + len; +} + +#if defined(NO_MMAP) || defined(USE_WIN32_MMAP) + +#ifndef PROT_READ +#define PROT_READ 1 +#define PROT_WRITE 2 +#define MAP_PRIVATE 1 +#define MAP_FAILED ((void*)-1) +#endif + +#define mmap git_mmap +#define munmap git_munmap +extern void *git_mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset); +extern int git_munmap(void *start, size_t length); + +#else /* NO_MMAP || USE_WIN32_MMAP */ + +#include + +#endif /* NO_MMAP || USE_WIN32_MMAP */ + +#ifdef NO_MMAP + +/* This value must be multiple of (pagesize * 2) */ +#define DEFAULT_PACKED_GIT_WINDOW_SIZE (1 * 1024 * 1024) + +#else /* NO_MMAP */ + +/* This value must be multiple of (pagesize * 2) */ +#define DEFAULT_PACKED_GIT_WINDOW_SIZE \ + (sizeof(void*) >= 8 \ + ? 1 * 1024 * 1024 * 1024 \ + : 32 * 1024 * 1024) + +#endif /* NO_MMAP */ + +#ifdef NO_ST_BLOCKS_IN_STRUCT_STAT +#define on_disk_bytes(st) ((st).st_size) +#else +#define on_disk_bytes(st) ((st).st_blocks * 512) +#endif + +#define DEFAULT_PACKED_GIT_LIMIT \ + ((1024L * 1024L) * (sizeof(void*) >= 8 ? 8192 : 256)) + +#ifdef NO_PREAD +#define pread git_pread +extern ssize_t git_pread(int fd, void *buf, size_t count, off_t offset); +#endif +/* + * Forward decl that will remind us if its twin in cache.h changes. + * This function is used in compat/pread.c. But we can't include + * cache.h there. + */ +extern ssize_t read_in_full(int fd, void *buf, size_t count); + +#ifdef NO_SETENV +#define setenv gitsetenv +extern int gitsetenv(const char *, const char *, int); +#endif + +#ifdef NO_MKDTEMP +#define mkdtemp gitmkdtemp +extern char *gitmkdtemp(char *); +#endif + +#ifdef NO_UNSETENV +#define unsetenv gitunsetenv +extern void gitunsetenv(const char *); +#endif + +#ifdef NO_STRCASESTR +#define strcasestr gitstrcasestr +extern char *gitstrcasestr(const char *haystack, const char *needle); +#endif + +#ifdef NO_STRLCPY +#define strlcpy gitstrlcpy +extern size_t gitstrlcpy(char *, const char *, size_t); +#endif + +#ifdef NO_STRTOUMAX +#define strtoumax gitstrtoumax +extern uintmax_t gitstrtoumax(const char *, char **, int); +#endif + +#ifdef NO_HSTRERROR +#define hstrerror githstrerror +extern const char *githstrerror(int herror); +#endif + +#ifdef NO_MEMMEM +#define memmem gitmemmem +void *gitmemmem(const void *haystack, size_t haystacklen, + const void *needle, size_t needlelen); +#endif + +#ifdef FREAD_READS_DIRECTORIES +#ifdef fopen +#undef fopen +#endif +#define fopen(a,b) git_fopen(a,b) +extern FILE *git_fopen(const char*, const char*); +#endif + +#ifdef SNPRINTF_RETURNS_BOGUS +#define snprintf git_snprintf +extern int git_snprintf(char *str, size_t maxsize, + const char *format, ...); +#define vsnprintf git_vsnprintf +extern int git_vsnprintf(char *str, size_t maxsize, + const char *format, va_list ap); +#endif + +#ifdef __GLIBC_PREREQ +#if __GLIBC_PREREQ(2, 1) +#define HAVE_STRCHRNUL +#endif +#endif + +#ifndef HAVE_STRCHRNUL +#define strchrnul gitstrchrnul +static inline char *gitstrchrnul(const char *s, int c) +{ + while (*s && *s != c) + s++; + return (char *)s; +} +#endif + +/* + * Wrappers: + */ +extern char *xstrdup(const char *str); +extern void *xmalloc(size_t size); +extern void *xmemdupz(const void *data, size_t len); +extern char *xstrndup(const char *str, size_t len); +extern void *xrealloc(void *ptr, size_t size); +extern void *xcalloc(size_t nmemb, size_t size); +extern void *xmmap(void *start, size_t length, int prot, int flags, int fd, off_t offset); +extern ssize_t xread(int fd, void *buf, size_t len); +extern ssize_t xwrite(int fd, const void *buf, size_t len); +extern int xdup(int fd); +extern FILE *xfdopen(int fd, const char *mode); +extern int xmkstemp(char *template); + +static inline size_t xsize_t(off_t len) +{ + return (size_t)len; +} + +static inline int has_extension(const char *filename, const char *ext) +{ + size_t len = strlen(filename); + size_t extlen = strlen(ext); + return len > extlen && !memcmp(filename + len - extlen, ext, extlen); +} + +/* Sane ctype - no locale, and works with signed chars */ +#undef isascii +#undef isspace +#undef isdigit +#undef isalpha +#undef isalnum +#undef tolower +#undef toupper +extern unsigned char sane_ctype[256]; +#define GIT_SPACE 0x01 +#define GIT_DIGIT 0x02 +#define GIT_ALPHA 0x04 +#define GIT_GLOB_SPECIAL 0x08 +#define GIT_REGEX_SPECIAL 0x10 +#define GIT_PRINT_EXTRA 0x20 +#define GIT_PRINT 0x3E +#define sane_istest(x,mask) ((sane_ctype[(unsigned char)(x)] & (mask)) != 0) +#define isascii(x) (((x) & ~0x7f) == 0) +#define isspace(x) sane_istest(x,GIT_SPACE) +#define isdigit(x) sane_istest(x,GIT_DIGIT) +#define isalpha(x) sane_istest(x,GIT_ALPHA) +#define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT) +#define isprint(x) sane_istest(x,GIT_PRINT) +#define is_glob_special(x) sane_istest(x,GIT_GLOB_SPECIAL) +#define is_regex_special(x) sane_istest(x,GIT_GLOB_SPECIAL | GIT_REGEX_SPECIAL) +#define tolower(x) sane_case((unsigned char)(x), 0x20) +#define toupper(x) sane_case((unsigned char)(x), 0) + +static inline int sane_case(int x, int high) +{ + if (sane_istest(x, GIT_ALPHA)) + x = (x & ~0x20) | high; + return x; +} + +static inline int strtoul_ui(char const *s, int base, unsigned int *result) +{ + unsigned long ul; + char *p; + + errno = 0; + ul = strtoul(s, &p, base); + if (errno || *p || p == s || (unsigned int) ul != ul) + return -1; + *result = ul; + return 0; +} + +static inline int strtol_i(char const *s, int base, int *result) +{ + long ul; + char *p; + + errno = 0; + ul = strtol(s, &p, base); + if (errno || *p || p == s || (int) ul != ul) + return -1; + *result = ul; + return 0; +} + +#ifdef INTERNAL_QSORT +void git_qsort(void *base, size_t nmemb, size_t size, + int(*compar)(const void *, const void *)); +#define qsort git_qsort +#endif + +#ifndef DIR_HAS_BSD_GROUP_SEMANTICS +# define FORCE_DIR_SET_GID S_ISGID +#else +# define FORCE_DIR_SET_GID 0 +#endif + +#ifdef NO_NSEC +#undef USE_NSEC +#define ST_CTIME_NSEC(st) 0 +#define ST_MTIME_NSEC(st) 0 +#else +#ifdef USE_ST_TIMESPEC +#define ST_CTIME_NSEC(st) ((unsigned int)((st).st_ctimespec.tv_nsec)) +#define ST_MTIME_NSEC(st) ((unsigned int)((st).st_mtimespec.tv_nsec)) +#else +#define ST_CTIME_NSEC(st) ((unsigned int)((st).st_ctim.tv_nsec)) +#define ST_MTIME_NSEC(st) ((unsigned int)((st).st_mtim.tv_nsec)) +#endif +#endif + +#endif diff --git a/tools/perf/util/wrapper.c b/tools/perf/util/wrapper.c new file mode 100644 index 000000000000..6350d65f6d9e --- /dev/null +++ b/tools/perf/util/wrapper.c @@ -0,0 +1,206 @@ +/* + * Various trivial helper wrappers around standard functions + */ +#include "cache.h" + +/* + * There's no pack memory to release - but stay close to the Git + * version so wrap this away: + */ +static inline void release_pack_memory(size_t size, int flag) +{ +} + +char *xstrdup(const char *str) +{ + char *ret = strdup(str); + if (!ret) { + release_pack_memory(strlen(str) + 1, -1); + ret = strdup(str); + if (!ret) + die("Out of memory, strdup failed"); + } + return ret; +} + +void *xmalloc(size_t size) +{ + void *ret = malloc(size); + if (!ret && !size) + ret = malloc(1); + if (!ret) { + release_pack_memory(size, -1); + ret = malloc(size); + if (!ret && !size) + ret = malloc(1); + if (!ret) + die("Out of memory, malloc failed"); + } +#ifdef XMALLOC_POISON + memset(ret, 0xA5, size); +#endif + return ret; +} + +/* + * xmemdupz() allocates (len + 1) bytes of memory, duplicates "len" bytes of + * "data" to the allocated memory, zero terminates the allocated memory, + * and returns a pointer to the allocated memory. If the allocation fails, + * the program dies. + */ +void *xmemdupz(const void *data, size_t len) +{ + char *p = xmalloc(len + 1); + memcpy(p, data, len); + p[len] = '\0'; + return p; +} + +char *xstrndup(const char *str, size_t len) +{ + char *p = memchr(str, '\0', len); + return xmemdupz(str, p ? p - str : len); +} + +void *xrealloc(void *ptr, size_t size) +{ + void *ret = realloc(ptr, size); + if (!ret && !size) + ret = realloc(ptr, 1); + if (!ret) { + release_pack_memory(size, -1); + ret = realloc(ptr, size); + if (!ret && !size) + ret = realloc(ptr, 1); + if (!ret) + die("Out of memory, realloc failed"); + } + return ret; +} + +void *xcalloc(size_t nmemb, size_t size) +{ + void *ret = calloc(nmemb, size); + if (!ret && (!nmemb || !size)) + ret = calloc(1, 1); + if (!ret) { + release_pack_memory(nmemb * size, -1); + ret = calloc(nmemb, size); + if (!ret && (!nmemb || !size)) + ret = calloc(1, 1); + if (!ret) + die("Out of memory, calloc failed"); + } + return ret; +} + +void *xmmap(void *start, size_t length, + int prot, int flags, int fd, off_t offset) +{ + void *ret = mmap(start, length, prot, flags, fd, offset); + if (ret == MAP_FAILED) { + if (!length) + return NULL; + release_pack_memory(length, fd); + ret = mmap(start, length, prot, flags, fd, offset); + if (ret == MAP_FAILED) + die("Out of memory? mmap failed: %s", strerror(errno)); + } + return ret; +} + +/* + * xread() is the same a read(), but it automatically restarts read() + * operations with a recoverable error (EAGAIN and EINTR). xread() + * DOES NOT GUARANTEE that "len" bytes is read even if the data is available. + */ +ssize_t xread(int fd, void *buf, size_t len) +{ + ssize_t nr; + while (1) { + nr = read(fd, buf, len); + if ((nr < 0) && (errno == EAGAIN || errno == EINTR)) + continue; + return nr; + } +} + +/* + * xwrite() is the same a write(), but it automatically restarts write() + * operations with a recoverable error (EAGAIN and EINTR). xwrite() DOES NOT + * GUARANTEE that "len" bytes is written even if the operation is successful. + */ +ssize_t xwrite(int fd, const void *buf, size_t len) +{ + ssize_t nr; + while (1) { + nr = write(fd, buf, len); + if ((nr < 0) && (errno == EAGAIN || errno == EINTR)) + continue; + return nr; + } +} + +ssize_t read_in_full(int fd, void *buf, size_t count) +{ + char *p = buf; + ssize_t total = 0; + + while (count > 0) { + ssize_t loaded = xread(fd, p, count); + if (loaded <= 0) + return total ? total : loaded; + count -= loaded; + p += loaded; + total += loaded; + } + + return total; +} + +ssize_t write_in_full(int fd, const void *buf, size_t count) +{ + const char *p = buf; + ssize_t total = 0; + + while (count > 0) { + ssize_t written = xwrite(fd, p, count); + if (written < 0) + return -1; + if (!written) { + errno = ENOSPC; + return -1; + } + count -= written; + p += written; + total += written; + } + + return total; +} + +int xdup(int fd) +{ + int ret = dup(fd); + if (ret < 0) + die("dup failed: %s", strerror(errno)); + return ret; +} + +FILE *xfdopen(int fd, const char *mode) +{ + FILE *stream = fdopen(fd, mode); + if (stream == NULL) + die("Out of memory? fdopen failed: %s", strerror(errno)); + return stream; +} + +int xmkstemp(char *template) +{ + int fd; + + fd = mkstemp(template); + if (fd < 0) + die("Unable to create temporary file: %s", strerror(errno)); + return fd; +} diff --git a/virt/kvm/ioapic.c b/virt/kvm/ioapic.c index c3b99def9cbc..1eddae94bab3 100644 --- a/virt/kvm/ioapic.c +++ b/virt/kvm/ioapic.c @@ -85,7 +85,7 @@ static unsigned long ioapic_read_indirect(struct kvm_ioapic *ioapic, static int ioapic_service(struct kvm_ioapic *ioapic, unsigned int idx) { - union ioapic_redir_entry *pent; + union kvm_ioapic_redirect_entry *pent; int injected = -1; pent = &ioapic->redirtbl[idx]; @@ -142,149 +142,40 @@ static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val) } } -static int ioapic_inj_irq(struct kvm_ioapic *ioapic, - struct kvm_vcpu *vcpu, - u8 vector, u8 trig_mode, u8 delivery_mode) -{ - ioapic_debug("irq %d trig %d deliv %d\n", vector, trig_mode, - delivery_mode); - - ASSERT((delivery_mode == IOAPIC_FIXED) || - (delivery_mode == IOAPIC_LOWEST_PRIORITY)); - - return kvm_apic_set_irq(vcpu, vector, trig_mode); -} - -static void ioapic_inj_nmi(struct kvm_vcpu *vcpu) -{ - kvm_inject_nmi(vcpu); - kvm_vcpu_kick(vcpu); -} - -u32 kvm_ioapic_get_delivery_bitmask(struct kvm_ioapic *ioapic, u8 dest, - u8 dest_mode) -{ - u32 mask = 0; - int i; - struct kvm *kvm = ioapic->kvm; - struct kvm_vcpu *vcpu; - - ioapic_debug("dest %d dest_mode %d\n", dest, dest_mode); - - if (dest_mode == 0) { /* Physical mode. */ - if (dest == 0xFF) { /* Broadcast. */ - for (i = 0; i < KVM_MAX_VCPUS; ++i) - if (kvm->vcpus[i] && kvm->vcpus[i]->arch.apic) - mask |= 1 << i; - return mask; - } - for (i = 0; i < KVM_MAX_VCPUS; ++i) { - vcpu = kvm->vcpus[i]; - if (!vcpu) - continue; - if (kvm_apic_match_physical_addr(vcpu->arch.apic, dest)) { - if (vcpu->arch.apic) - mask = 1 << i; - break; - } - } - } else if (dest != 0) /* Logical mode, MDA non-zero. */ - for (i = 0; i < KVM_MAX_VCPUS; ++i) { - vcpu = kvm->vcpus[i]; - if (!vcpu) - continue; - if (vcpu->arch.apic && - kvm_apic_match_logical_addr(vcpu->arch.apic, dest)) - mask |= 1 << vcpu->vcpu_id; - } - ioapic_debug("mask %x\n", mask); - return mask; -} - static int ioapic_deliver(struct kvm_ioapic *ioapic, int irq) { - u8 dest = ioapic->redirtbl[irq].fields.dest_id; - u8 dest_mode = ioapic->redirtbl[irq].fields.dest_mode; - u8 delivery_mode = ioapic->redirtbl[irq].fields.delivery_mode; - u8 vector = ioapic->redirtbl[irq].fields.vector; - u8 trig_mode = ioapic->redirtbl[irq].fields.trig_mode; - u32 deliver_bitmask; - struct kvm_vcpu *vcpu; - int vcpu_id, r = -1; + union kvm_ioapic_redirect_entry *entry = &ioapic->redirtbl[irq]; + struct kvm_lapic_irq irqe; ioapic_debug("dest=%x dest_mode=%x delivery_mode=%x " "vector=%x trig_mode=%x\n", - dest, dest_mode, delivery_mode, vector, trig_mode); + entry->fields.dest, entry->fields.dest_mode, + entry->fields.delivery_mode, entry->fields.vector, + entry->fields.trig_mode); - deliver_bitmask = kvm_ioapic_get_delivery_bitmask(ioapic, dest, - dest_mode); - if (!deliver_bitmask) { - ioapic_debug("no target on destination\n"); - return 0; - } + irqe.dest_id = entry->fields.dest_id; + irqe.vector = entry->fields.vector; + irqe.dest_mode = entry->fields.dest_mode; + irqe.trig_mode = entry->fields.trig_mode; + irqe.delivery_mode = entry->fields.delivery_mode << 8; + irqe.level = 1; + irqe.shorthand = 0; - switch (delivery_mode) { - case IOAPIC_LOWEST_PRIORITY: - vcpu = kvm_get_lowest_prio_vcpu(ioapic->kvm, vector, - deliver_bitmask); #ifdef CONFIG_X86 - if (irq == 0) - vcpu = ioapic->kvm->vcpus[0]; -#endif - if (vcpu != NULL) - r = ioapic_inj_irq(ioapic, vcpu, vector, - trig_mode, delivery_mode); - else - ioapic_debug("null lowest prio vcpu: " - "mask=%x vector=%x delivery_mode=%x\n", - deliver_bitmask, vector, IOAPIC_LOWEST_PRIORITY); - break; - case IOAPIC_FIXED: -#ifdef CONFIG_X86 - if (irq == 0) - deliver_bitmask = 1; -#endif - 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) { - if (r < 0) - r = 0; - r += ioapic_inj_irq(ioapic, vcpu, vector, - trig_mode, delivery_mode); - } - } - break; - 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); - r = 1; - } - else - ioapic_debug("NMI to vcpu %d failed\n", - vcpu->vcpu_id); - } - break; - default: - printk(KERN_WARNING "Unsupported delivery mode %d\n", - delivery_mode); - break; + /* Always delivery PIT interrupt to vcpu 0 */ + if (irq == 0) { + irqe.dest_mode = 0; /* Physical mode. */ + irqe.dest_id = ioapic->kvm->vcpus[0]->vcpu_id; } - return r; +#endif + return kvm_irq_delivery_to_apic(ioapic->kvm, NULL, &irqe); } int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level) { u32 old_irr = ioapic->irr; u32 mask = 1 << irq; - union ioapic_redir_entry entry; + union kvm_ioapic_redirect_entry entry; int ret = 1; if (irq >= 0 && irq < IOAPIC_NUM_PINS) { @@ -305,7 +196,7 @@ int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level) static void __kvm_ioapic_update_eoi(struct kvm_ioapic *ioapic, int pin, int trigger_mode) { - union ioapic_redir_entry *ent; + union kvm_ioapic_redirect_entry *ent; ent = &ioapic->redirtbl[pin]; diff --git a/virt/kvm/ioapic.h b/virt/kvm/ioapic.h index a34bd5e6436b..7080b713c160 100644 --- a/virt/kvm/ioapic.h +++ b/virt/kvm/ioapic.h @@ -40,22 +40,7 @@ struct kvm_ioapic { u32 id; u32 irr; u32 pad; - union ioapic_redir_entry { - u64 bits; - struct { - u8 vector; - u8 delivery_mode:3; - u8 dest_mode:1; - u8 delivery_status:1; - u8 polarity:1; - u8 remote_irr:1; - u8 trig_mode:1; - u8 mask:1; - u8 reserve:7; - u8 reserved[4]; - u8 dest_id; - } fields; - } redirtbl[IOAPIC_NUM_PINS]; + union kvm_ioapic_redirect_entry redirtbl[IOAPIC_NUM_PINS]; struct kvm_io_device dev; struct kvm *kvm; void (*ack_notifier)(void *opaque, int irq); @@ -79,13 +64,13 @@ static inline struct kvm_ioapic *ioapic_irqchip(struct kvm *kvm) return kvm->arch.vioapic; } -struct kvm_vcpu *kvm_get_lowest_prio_vcpu(struct kvm *kvm, u8 vector, - unsigned long bitmap); +int kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source, + int short_hand, int dest, int dest_mode); +int kvm_apic_compare_prio(struct kvm_vcpu *vcpu1, struct kvm_vcpu *vcpu2); void kvm_ioapic_update_eoi(struct kvm *kvm, int vector, int trigger_mode); int kvm_ioapic_init(struct kvm *kvm); int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level); void kvm_ioapic_reset(struct kvm_ioapic *ioapic); -u32 kvm_ioapic_get_delivery_bitmask(struct kvm_ioapic *ioapic, u8 dest, - u8 dest_mode); - +int kvm_irq_delivery_to_apic(struct kvm *kvm, struct kvm_lapic *src, + struct kvm_lapic_irq *irq); #endif diff --git a/virt/kvm/iommu.c b/virt/kvm/iommu.c index 4c4037503600..15147583abd1 100644 --- a/virt/kvm/iommu.c +++ b/virt/kvm/iommu.c @@ -39,11 +39,16 @@ int kvm_iommu_map_pages(struct kvm *kvm, pfn_t pfn; int i, r = 0; struct iommu_domain *domain = kvm->arch.iommu_domain; + int flags; /* check if iommu exists and in use */ if (!domain) return 0; + flags = IOMMU_READ | IOMMU_WRITE; + if (kvm->arch.iommu_flags & KVM_IOMMU_CACHE_COHERENCY) + flags |= IOMMU_CACHE; + for (i = 0; i < npages; i++) { /* check if already mapped */ if (iommu_iova_to_phys(domain, gfn_to_gpa(gfn))) @@ -53,8 +58,7 @@ int kvm_iommu_map_pages(struct kvm *kvm, r = iommu_map_range(domain, gfn_to_gpa(gfn), pfn_to_hpa(pfn), - PAGE_SIZE, - IOMMU_READ | IOMMU_WRITE); + PAGE_SIZE, flags); if (r) { printk(KERN_ERR "kvm_iommu_map_address:" "iommu failed to map pfn=%lx\n", pfn); @@ -88,7 +92,7 @@ int kvm_assign_device(struct kvm *kvm, { struct pci_dev *pdev = NULL; struct iommu_domain *domain = kvm->arch.iommu_domain; - int r; + int r, last_flags; /* check if iommu exists and in use */ if (!domain) @@ -107,12 +111,29 @@ int kvm_assign_device(struct kvm *kvm, return r; } + last_flags = kvm->arch.iommu_flags; + if (iommu_domain_has_cap(kvm->arch.iommu_domain, + IOMMU_CAP_CACHE_COHERENCY)) + kvm->arch.iommu_flags |= KVM_IOMMU_CACHE_COHERENCY; + + /* Check if need to update IOMMU page table for guest memory */ + if ((last_flags ^ kvm->arch.iommu_flags) == + KVM_IOMMU_CACHE_COHERENCY) { + kvm_iommu_unmap_memslots(kvm); + r = kvm_iommu_map_memslots(kvm); + if (r) + goto out_unmap; + } + printk(KERN_DEBUG "assign device: host bdf = %x:%x:%x\n", assigned_dev->host_busnr, PCI_SLOT(assigned_dev->host_devfn), PCI_FUNC(assigned_dev->host_devfn)); return 0; +out_unmap: + kvm_iommu_unmap_memslots(kvm); + return r; } int kvm_deassign_device(struct kvm *kvm, diff --git a/virt/kvm/irq_comm.c b/virt/kvm/irq_comm.c index 864ac5483baa..a8bd466d00cc 100644 --- a/virt/kvm/irq_comm.c +++ b/virt/kvm/irq_comm.c @@ -22,6 +22,9 @@ #include #include +#ifdef CONFIG_IA64 +#include +#endif #include "irq.h" @@ -43,55 +46,71 @@ static int kvm_set_ioapic_irq(struct kvm_kernel_irq_routing_entry *e, return kvm_ioapic_set_irq(kvm->arch.vioapic, e->irqchip.pin, level); } +inline static bool kvm_is_dm_lowest_prio(struct kvm_lapic_irq *irq) +{ +#ifdef CONFIG_IA64 + return irq->delivery_mode == + (IOSAPIC_LOWEST_PRIORITY << IOSAPIC_DELIVERY_SHIFT); +#else + return irq->delivery_mode == APIC_DM_LOWEST; +#endif +} + +int kvm_irq_delivery_to_apic(struct kvm *kvm, struct kvm_lapic *src, + struct kvm_lapic_irq *irq) +{ + int i, r = -1; + struct kvm_vcpu *vcpu, *lowest = NULL; + + if (irq->dest_mode == 0 && irq->dest_id == 0xff && + kvm_is_dm_lowest_prio(irq)) + printk(KERN_INFO "kvm: apic: phys broadcast and lowest prio\n"); + + for (i = 0; i < KVM_MAX_VCPUS; i++) { + vcpu = kvm->vcpus[i]; + + if (!vcpu || !kvm_apic_present(vcpu)) + continue; + + if (!kvm_apic_match_dest(vcpu, src, irq->shorthand, + irq->dest_id, irq->dest_mode)) + continue; + + if (!kvm_is_dm_lowest_prio(irq)) { + if (r < 0) + r = 0; + r += kvm_apic_set_irq(vcpu, irq); + } else { + if (!lowest) + lowest = vcpu; + else if (kvm_apic_compare_prio(vcpu, lowest) < 0) + lowest = vcpu; + } + } + + if (lowest) + r = kvm_apic_set_irq(lowest, irq); + + return r; +} + static int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e, struct kvm *kvm, int level) { - int vcpu_id, r = -1; - struct kvm_vcpu *vcpu; - struct kvm_ioapic *ioapic = ioapic_irqchip(kvm); - int dest_id = (e->msi.address_lo & MSI_ADDR_DEST_ID_MASK) - >> MSI_ADDR_DEST_ID_SHIFT; - int vector = (e->msi.data & MSI_DATA_VECTOR_MASK) - >> MSI_DATA_VECTOR_SHIFT; - int dest_mode = test_bit(MSI_ADDR_DEST_MODE_SHIFT, - (unsigned long *)&e->msi.address_lo); - int trig_mode = test_bit(MSI_DATA_TRIGGER_SHIFT, - (unsigned long *)&e->msi.data); - int delivery_mode = test_bit(MSI_DATA_DELIVERY_MODE_SHIFT, - (unsigned long *)&e->msi.data); - u32 deliver_bitmask; + struct kvm_lapic_irq irq; - BUG_ON(!ioapic); + irq.dest_id = (e->msi.address_lo & + MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT; + irq.vector = (e->msi.data & + MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT; + irq.dest_mode = (1 << MSI_ADDR_DEST_MODE_SHIFT) & e->msi.address_lo; + irq.trig_mode = (1 << MSI_DATA_TRIGGER_SHIFT) & e->msi.data; + irq.delivery_mode = e->msi.data & 0x700; + irq.level = 1; + irq.shorthand = 0; - deliver_bitmask = kvm_ioapic_get_delivery_bitmask(ioapic, - dest_id, dest_mode); - /* IOAPIC delivery mode value is the same as MSI here */ - switch (delivery_mode) { - case IOAPIC_LOWEST_PRIORITY: - vcpu = kvm_get_lowest_prio_vcpu(ioapic->kvm, vector, - deliver_bitmask); - if (vcpu != NULL) - r = kvm_apic_set_irq(vcpu, vector, trig_mode); - else - printk(KERN_INFO "kvm: null lowest priority vcpu!\n"); - break; - case IOAPIC_FIXED: - 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) { - if (r < 0) - r = 0; - r += kvm_apic_set_irq(vcpu, vector, trig_mode); - } - } - break; - default: - break; - } - return r; + /* TODO Deal with RH bit of MSI message address */ + return kvm_irq_delivery_to_apic(kvm, NULL, &irq); } /* This should be called with the kvm->lock mutex held @@ -252,7 +271,7 @@ static int setup_routing_entry(struct kvm_kernel_irq_routing_entry *e, delta = 8; break; case KVM_IRQCHIP_IOAPIC: - e->set = kvm_set_ioapic_irq; + e->set = kvm_set_ioapic_irq; break; default: goto out; diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 4d0dd390aa50..764554350ed8 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -41,6 +41,8 @@ #include #include #include +#include +#include #include #include @@ -60,9 +62,6 @@ MODULE_AUTHOR("Qumranet"); MODULE_LICENSE("GPL"); -static int msi2intx = 1; -module_param(msi2intx, bool, 0); - DEFINE_SPINLOCK(kvm_lock); LIST_HEAD(vm_list); @@ -95,38 +94,96 @@ static struct kvm_assigned_dev_kernel *kvm_find_assigned_dev(struct list_head *h return NULL; } +static int find_index_from_host_irq(struct kvm_assigned_dev_kernel + *assigned_dev, int irq) +{ + int i, index; + struct msix_entry *host_msix_entries; + + host_msix_entries = assigned_dev->host_msix_entries; + + index = -1; + for (i = 0; i < assigned_dev->entries_nr; i++) + if (irq == host_msix_entries[i].vector) { + index = i; + break; + } + if (index < 0) { + printk(KERN_WARNING "Fail to find correlated MSI-X entry!\n"); + return 0; + } + + return index; +} + static void kvm_assigned_dev_interrupt_work_handler(struct work_struct *work) { struct kvm_assigned_dev_kernel *assigned_dev; + struct kvm *kvm; + int irq, i; assigned_dev = container_of(work, struct kvm_assigned_dev_kernel, interrupt_work); + kvm = assigned_dev->kvm; /* This is taken to safely inject irq inside the guest. When * the interrupt injection (or the ioapic code) uses a * finer-grained lock, update this */ - mutex_lock(&assigned_dev->kvm->lock); - kvm_set_irq(assigned_dev->kvm, assigned_dev->irq_source_id, - assigned_dev->guest_irq, 1); - - if (assigned_dev->irq_requested_type & KVM_ASSIGNED_DEV_GUEST_MSI) { - enable_irq(assigned_dev->host_irq); - assigned_dev->host_irq_disabled = false; + mutex_lock(&kvm->lock); + spin_lock_irq(&assigned_dev->assigned_dev_lock); + if (assigned_dev->irq_requested_type & KVM_DEV_IRQ_HOST_MSIX) { + struct kvm_guest_msix_entry *guest_entries = + assigned_dev->guest_msix_entries; + for (i = 0; i < assigned_dev->entries_nr; i++) { + if (!(guest_entries[i].flags & + KVM_ASSIGNED_MSIX_PENDING)) + continue; + guest_entries[i].flags &= ~KVM_ASSIGNED_MSIX_PENDING; + kvm_set_irq(assigned_dev->kvm, + assigned_dev->irq_source_id, + guest_entries[i].vector, 1); + irq = assigned_dev->host_msix_entries[i].vector; + if (irq != 0) + enable_irq(irq); + assigned_dev->host_irq_disabled = false; + } + } else { + kvm_set_irq(assigned_dev->kvm, assigned_dev->irq_source_id, + assigned_dev->guest_irq, 1); + if (assigned_dev->irq_requested_type & + KVM_DEV_IRQ_GUEST_MSI) { + enable_irq(assigned_dev->host_irq); + assigned_dev->host_irq_disabled = false; + } } + + spin_unlock_irq(&assigned_dev->assigned_dev_lock); mutex_unlock(&assigned_dev->kvm->lock); } static irqreturn_t kvm_assigned_dev_intr(int irq, void *dev_id) { + unsigned long flags; struct kvm_assigned_dev_kernel *assigned_dev = (struct kvm_assigned_dev_kernel *) dev_id; + spin_lock_irqsave(&assigned_dev->assigned_dev_lock, flags); + if (assigned_dev->irq_requested_type & KVM_DEV_IRQ_HOST_MSIX) { + int index = find_index_from_host_irq(assigned_dev, irq); + if (index < 0) + goto out; + assigned_dev->guest_msix_entries[index].flags |= + KVM_ASSIGNED_MSIX_PENDING; + } + schedule_work(&assigned_dev->interrupt_work); disable_irq_nosync(irq); assigned_dev->host_irq_disabled = true; +out: + spin_unlock_irqrestore(&assigned_dev->assigned_dev_lock, flags); return IRQ_HANDLED; } @@ -134,6 +191,7 @@ static irqreturn_t kvm_assigned_dev_intr(int irq, void *dev_id) static void kvm_assigned_dev_ack_irq(struct kvm_irq_ack_notifier *kian) { struct kvm_assigned_dev_kernel *dev; + unsigned long flags; if (kian->gsi == -1) return; @@ -146,28 +204,30 @@ static void kvm_assigned_dev_ack_irq(struct kvm_irq_ack_notifier *kian) /* The guest irq may be shared so this ack may be * from another device. */ + spin_lock_irqsave(&dev->assigned_dev_lock, flags); if (dev->host_irq_disabled) { enable_irq(dev->host_irq); dev->host_irq_disabled = false; } + spin_unlock_irqrestore(&dev->assigned_dev_lock, flags); } -/* The function implicit hold kvm->lock mutex due to cancel_work_sync() */ -static void kvm_free_assigned_irq(struct kvm *kvm, - struct kvm_assigned_dev_kernel *assigned_dev) +static void deassign_guest_irq(struct kvm *kvm, + struct kvm_assigned_dev_kernel *assigned_dev) { - if (!irqchip_in_kernel(kvm)) - return; - kvm_unregister_irq_ack_notifier(&assigned_dev->ack_notifier); + assigned_dev->ack_notifier.gsi = -1; if (assigned_dev->irq_source_id != -1) kvm_free_irq_source_id(kvm, assigned_dev->irq_source_id); assigned_dev->irq_source_id = -1; + assigned_dev->irq_requested_type &= ~(KVM_DEV_IRQ_GUEST_MASK); +} - if (!assigned_dev->irq_requested_type) - return; - +/* The function implicit hold kvm->lock mutex due to cancel_work_sync() */ +static void deassign_host_irq(struct kvm *kvm, + struct kvm_assigned_dev_kernel *assigned_dev) +{ /* * In kvm_free_device_irq, cancel_work_sync return true if: * 1. work is scheduled, and then cancelled. @@ -184,17 +244,64 @@ static void kvm_free_assigned_irq(struct kvm *kvm, * now, the kvm state is still legal for probably we also have to wait * interrupt_work done. */ - disable_irq_nosync(assigned_dev->host_irq); - cancel_work_sync(&assigned_dev->interrupt_work); + if (assigned_dev->irq_requested_type & KVM_DEV_IRQ_HOST_MSIX) { + int i; + for (i = 0; i < assigned_dev->entries_nr; i++) + disable_irq_nosync(assigned_dev-> + host_msix_entries[i].vector); - free_irq(assigned_dev->host_irq, (void *)assigned_dev); + cancel_work_sync(&assigned_dev->interrupt_work); - if (assigned_dev->irq_requested_type & KVM_ASSIGNED_DEV_HOST_MSI) - pci_disable_msi(assigned_dev->dev); + for (i = 0; i < assigned_dev->entries_nr; i++) + free_irq(assigned_dev->host_msix_entries[i].vector, + (void *)assigned_dev); - assigned_dev->irq_requested_type = 0; + assigned_dev->entries_nr = 0; + kfree(assigned_dev->host_msix_entries); + kfree(assigned_dev->guest_msix_entries); + pci_disable_msix(assigned_dev->dev); + } else { + /* Deal with MSI and INTx */ + disable_irq_nosync(assigned_dev->host_irq); + cancel_work_sync(&assigned_dev->interrupt_work); + + free_irq(assigned_dev->host_irq, (void *)assigned_dev); + + if (assigned_dev->irq_requested_type & KVM_DEV_IRQ_HOST_MSI) + pci_disable_msi(assigned_dev->dev); + } + + assigned_dev->irq_requested_type &= ~(KVM_DEV_IRQ_HOST_MASK); } +static int kvm_deassign_irq(struct kvm *kvm, + struct kvm_assigned_dev_kernel *assigned_dev, + unsigned long irq_requested_type) +{ + unsigned long guest_irq_type, host_irq_type; + + if (!irqchip_in_kernel(kvm)) + return -EINVAL; + /* no irq assignment to deassign */ + if (!assigned_dev->irq_requested_type) + return -ENXIO; + + host_irq_type = irq_requested_type & KVM_DEV_IRQ_HOST_MASK; + guest_irq_type = irq_requested_type & KVM_DEV_IRQ_GUEST_MASK; + + if (host_irq_type) + deassign_host_irq(kvm, assigned_dev); + if (guest_irq_type) + deassign_guest_irq(kvm, assigned_dev); + + return 0; +} + +static void kvm_free_assigned_irq(struct kvm *kvm, + struct kvm_assigned_dev_kernel *assigned_dev) +{ + kvm_deassign_irq(kvm, assigned_dev, assigned_dev->irq_requested_type); +} static void kvm_free_assigned_device(struct kvm *kvm, struct kvm_assigned_dev_kernel @@ -226,191 +333,245 @@ void kvm_free_all_assigned_devices(struct kvm *kvm) } } -static int assigned_device_update_intx(struct kvm *kvm, - struct kvm_assigned_dev_kernel *adev, - struct kvm_assigned_irq *airq) +static int assigned_device_enable_host_intx(struct kvm *kvm, + struct kvm_assigned_dev_kernel *dev) { - adev->guest_irq = airq->guest_irq; - adev->ack_notifier.gsi = airq->guest_irq; - - if (adev->irq_requested_type & KVM_ASSIGNED_DEV_HOST_INTX) - return 0; - - if (irqchip_in_kernel(kvm)) { - if (!msi2intx && - (adev->irq_requested_type & KVM_ASSIGNED_DEV_HOST_MSI)) { - free_irq(adev->host_irq, (void *)adev); - pci_disable_msi(adev->dev); - } - - if (!capable(CAP_SYS_RAWIO)) - return -EPERM; - - if (airq->host_irq) - adev->host_irq = airq->host_irq; - else - adev->host_irq = adev->dev->irq; - - /* Even though this is PCI, we don't want to use shared - * interrupts. Sharing host devices with guest-assigned devices - * on the same interrupt line is not a happy situation: there - * are going to be long delays in accepting, acking, etc. - */ - if (request_irq(adev->host_irq, kvm_assigned_dev_intr, - 0, "kvm_assigned_intx_device", (void *)adev)) - return -EIO; - } - - adev->irq_requested_type = KVM_ASSIGNED_DEV_GUEST_INTX | - KVM_ASSIGNED_DEV_HOST_INTX; + dev->host_irq = dev->dev->irq; + /* Even though this is PCI, we don't want to use shared + * interrupts. Sharing host devices with guest-assigned devices + * on the same interrupt line is not a happy situation: there + * are going to be long delays in accepting, acking, etc. + */ + if (request_irq(dev->host_irq, kvm_assigned_dev_intr, + 0, "kvm_assigned_intx_device", (void *)dev)) + return -EIO; return 0; } -#ifdef CONFIG_X86 -static int assigned_device_update_msi(struct kvm *kvm, - struct kvm_assigned_dev_kernel *adev, - struct kvm_assigned_irq *airq) +#ifdef __KVM_HAVE_MSI +static int assigned_device_enable_host_msi(struct kvm *kvm, + struct kvm_assigned_dev_kernel *dev) { int r; - adev->guest_irq = airq->guest_irq; - if (airq->flags & KVM_DEV_IRQ_ASSIGN_ENABLE_MSI) { - /* x86 don't care upper address of guest msi message addr */ - adev->irq_requested_type |= KVM_ASSIGNED_DEV_GUEST_MSI; - adev->irq_requested_type &= ~KVM_ASSIGNED_DEV_GUEST_INTX; - adev->ack_notifier.gsi = -1; - } else if (msi2intx) { - adev->irq_requested_type |= KVM_ASSIGNED_DEV_GUEST_INTX; - adev->irq_requested_type &= ~KVM_ASSIGNED_DEV_GUEST_MSI; - adev->ack_notifier.gsi = airq->guest_irq; - } else { - /* - * Guest require to disable device MSI, we disable MSI and - * re-enable INTx by default again. Notice it's only for - * non-msi2intx. - */ - assigned_device_update_intx(kvm, adev, airq); - return 0; + if (!dev->dev->msi_enabled) { + r = pci_enable_msi(dev->dev); + if (r) + return r; } - if (adev->irq_requested_type & KVM_ASSIGNED_DEV_HOST_MSI) - return 0; - - if (irqchip_in_kernel(kvm)) { - if (!msi2intx) { - if (adev->irq_requested_type & - KVM_ASSIGNED_DEV_HOST_INTX) - free_irq(adev->host_irq, (void *)adev); - - r = pci_enable_msi(adev->dev); - if (r) - return r; - } - - adev->host_irq = adev->dev->irq; - if (request_irq(adev->host_irq, kvm_assigned_dev_intr, 0, - "kvm_assigned_msi_device", (void *)adev)) - return -EIO; + dev->host_irq = dev->dev->irq; + if (request_irq(dev->host_irq, kvm_assigned_dev_intr, 0, + "kvm_assigned_msi_device", (void *)dev)) { + pci_disable_msi(dev->dev); + return -EIO; } - if (!msi2intx) - adev->irq_requested_type = KVM_ASSIGNED_DEV_GUEST_MSI; - - adev->irq_requested_type |= KVM_ASSIGNED_DEV_HOST_MSI; return 0; } #endif -static int kvm_vm_ioctl_assign_irq(struct kvm *kvm, - struct kvm_assigned_irq - *assigned_irq) +#ifdef __KVM_HAVE_MSIX +static int assigned_device_enable_host_msix(struct kvm *kvm, + struct kvm_assigned_dev_kernel *dev) { - int r = 0; + int i, r = -EINVAL; + + /* host_msix_entries and guest_msix_entries should have been + * initialized */ + if (dev->entries_nr == 0) + return r; + + r = pci_enable_msix(dev->dev, dev->host_msix_entries, dev->entries_nr); + if (r) + return r; + + for (i = 0; i < dev->entries_nr; i++) { + r = request_irq(dev->host_msix_entries[i].vector, + kvm_assigned_dev_intr, 0, + "kvm_assigned_msix_device", + (void *)dev); + /* FIXME: free requested_irq's on failure */ + if (r) + return r; + } + + return 0; +} + +#endif + +static int assigned_device_enable_guest_intx(struct kvm *kvm, + struct kvm_assigned_dev_kernel *dev, + struct kvm_assigned_irq *irq) +{ + dev->guest_irq = irq->guest_irq; + dev->ack_notifier.gsi = irq->guest_irq; + return 0; +} + +#ifdef __KVM_HAVE_MSI +static int assigned_device_enable_guest_msi(struct kvm *kvm, + struct kvm_assigned_dev_kernel *dev, + struct kvm_assigned_irq *irq) +{ + dev->guest_irq = irq->guest_irq; + dev->ack_notifier.gsi = -1; + return 0; +} +#endif +#ifdef __KVM_HAVE_MSIX +static int assigned_device_enable_guest_msix(struct kvm *kvm, + struct kvm_assigned_dev_kernel *dev, + struct kvm_assigned_irq *irq) +{ + dev->guest_irq = irq->guest_irq; + dev->ack_notifier.gsi = -1; + return 0; +} +#endif + +static int assign_host_irq(struct kvm *kvm, + struct kvm_assigned_dev_kernel *dev, + __u32 host_irq_type) +{ + int r = -EEXIST; + + if (dev->irq_requested_type & KVM_DEV_IRQ_HOST_MASK) + return r; + + switch (host_irq_type) { + case KVM_DEV_IRQ_HOST_INTX: + r = assigned_device_enable_host_intx(kvm, dev); + break; +#ifdef __KVM_HAVE_MSI + case KVM_DEV_IRQ_HOST_MSI: + r = assigned_device_enable_host_msi(kvm, dev); + break; +#endif +#ifdef __KVM_HAVE_MSIX + case KVM_DEV_IRQ_HOST_MSIX: + r = assigned_device_enable_host_msix(kvm, dev); + break; +#endif + default: + r = -EINVAL; + } + + if (!r) + dev->irq_requested_type |= host_irq_type; + + return r; +} + +static int assign_guest_irq(struct kvm *kvm, + struct kvm_assigned_dev_kernel *dev, + struct kvm_assigned_irq *irq, + unsigned long guest_irq_type) +{ + int id; + int r = -EEXIST; + + if (dev->irq_requested_type & KVM_DEV_IRQ_GUEST_MASK) + return r; + + id = kvm_request_irq_source_id(kvm); + if (id < 0) + return id; + + dev->irq_source_id = id; + + switch (guest_irq_type) { + case KVM_DEV_IRQ_GUEST_INTX: + r = assigned_device_enable_guest_intx(kvm, dev, irq); + break; +#ifdef __KVM_HAVE_MSI + case KVM_DEV_IRQ_GUEST_MSI: + r = assigned_device_enable_guest_msi(kvm, dev, irq); + break; +#endif +#ifdef __KVM_HAVE_MSIX + case KVM_DEV_IRQ_GUEST_MSIX: + r = assigned_device_enable_guest_msix(kvm, dev, irq); + break; +#endif + default: + r = -EINVAL; + } + + if (!r) { + dev->irq_requested_type |= guest_irq_type; + kvm_register_irq_ack_notifier(kvm, &dev->ack_notifier); + } else + kvm_free_irq_source_id(kvm, dev->irq_source_id); + + return r; +} + +/* TODO Deal with KVM_DEV_IRQ_ASSIGNED_MASK_MSIX */ +static int kvm_vm_ioctl_assign_irq(struct kvm *kvm, + struct kvm_assigned_irq *assigned_irq) +{ + int r = -EINVAL; + struct kvm_assigned_dev_kernel *match; + unsigned long host_irq_type, guest_irq_type; + + if (!capable(CAP_SYS_RAWIO)) + return -EPERM; + + if (!irqchip_in_kernel(kvm)) + return r; + + mutex_lock(&kvm->lock); + r = -ENODEV; + match = kvm_find_assigned_dev(&kvm->arch.assigned_dev_head, + assigned_irq->assigned_dev_id); + if (!match) + goto out; + + host_irq_type = (assigned_irq->flags & KVM_DEV_IRQ_HOST_MASK); + guest_irq_type = (assigned_irq->flags & KVM_DEV_IRQ_GUEST_MASK); + + r = -EINVAL; + /* can only assign one type at a time */ + if (hweight_long(host_irq_type) > 1) + goto out; + if (hweight_long(guest_irq_type) > 1) + goto out; + if (host_irq_type == 0 && guest_irq_type == 0) + goto out; + + r = 0; + if (host_irq_type) + r = assign_host_irq(kvm, match, host_irq_type); + if (r) + goto out; + + if (guest_irq_type) + r = assign_guest_irq(kvm, match, assigned_irq, guest_irq_type); +out: + mutex_unlock(&kvm->lock); + return r; +} + +static int kvm_vm_ioctl_deassign_dev_irq(struct kvm *kvm, + struct kvm_assigned_irq + *assigned_irq) +{ + int r = -ENODEV; struct kvm_assigned_dev_kernel *match; - u32 current_flags = 0, changed_flags; mutex_lock(&kvm->lock); match = kvm_find_assigned_dev(&kvm->arch.assigned_dev_head, assigned_irq->assigned_dev_id); - if (!match) { - mutex_unlock(&kvm->lock); - return -EINVAL; - } - - if (!match->irq_requested_type) { - INIT_WORK(&match->interrupt_work, - kvm_assigned_dev_interrupt_work_handler); - if (irqchip_in_kernel(kvm)) { - /* Register ack nofitier */ - match->ack_notifier.gsi = -1; - match->ack_notifier.irq_acked = - kvm_assigned_dev_ack_irq; - kvm_register_irq_ack_notifier(kvm, - &match->ack_notifier); - - /* Request IRQ source ID */ - r = kvm_request_irq_source_id(kvm); - if (r < 0) - goto out_release; - else - match->irq_source_id = r; - -#ifdef CONFIG_X86 - /* Determine host device irq type, we can know the - * result from dev->msi_enabled */ - if (msi2intx) - pci_enable_msi(match->dev); -#endif - } - } - - if ((match->irq_requested_type & KVM_ASSIGNED_DEV_HOST_MSI) && - (match->irq_requested_type & KVM_ASSIGNED_DEV_GUEST_MSI)) - current_flags |= KVM_DEV_IRQ_ASSIGN_ENABLE_MSI; - - changed_flags = assigned_irq->flags ^ current_flags; - - if ((changed_flags & KVM_DEV_IRQ_ASSIGN_MSI_ACTION) || - (msi2intx && match->dev->msi_enabled)) { -#ifdef CONFIG_X86 - r = assigned_device_update_msi(kvm, match, assigned_irq); - if (r) { - printk(KERN_WARNING "kvm: failed to enable " - "MSI device!\n"); - goto out_release; - } -#else - r = -ENOTTY; -#endif - } else if (assigned_irq->host_irq == 0 && match->dev->irq == 0) { - /* Host device IRQ 0 means don't support INTx */ - if (!msi2intx) { - printk(KERN_WARNING - "kvm: wait device to enable MSI!\n"); - r = 0; - } else { - printk(KERN_WARNING - "kvm: failed to enable MSI device!\n"); - r = -ENOTTY; - goto out_release; - } - } else { - /* Non-sharing INTx mode */ - r = assigned_device_update_intx(kvm, match, assigned_irq); - if (r) { - printk(KERN_WARNING "kvm: failed to enable " - "INTx device!\n"); - goto out_release; - } - } + if (!match) + goto out; + r = kvm_deassign_irq(kvm, match, assigned_irq->flags); +out: mutex_unlock(&kvm->lock); return r; -out_release: - mutex_unlock(&kvm->lock); - kvm_free_assigned_device(kvm, match); - return r; } static int kvm_vm_ioctl_assign_device(struct kvm *kvm, @@ -427,7 +588,7 @@ static int kvm_vm_ioctl_assign_device(struct kvm *kvm, assigned_dev->assigned_dev_id); if (match) { /* device already assigned */ - r = -EINVAL; + r = -EEXIST; goto out; } @@ -464,8 +625,12 @@ static int kvm_vm_ioctl_assign_device(struct kvm *kvm, match->host_devfn = assigned_dev->devfn; match->flags = assigned_dev->flags; match->dev = dev; + spin_lock_init(&match->assigned_dev_lock); match->irq_source_id = -1; match->kvm = kvm; + match->ack_notifier.irq_acked = kvm_assigned_dev_ack_irq; + INIT_WORK(&match->interrupt_work, + kvm_assigned_dev_interrupt_work_handler); list_add(&match->list, &kvm->arch.assigned_dev_head); @@ -878,6 +1043,8 @@ static void kvm_destroy_vm(struct kvm *kvm) #endif #if defined(CONFIG_MMU_NOTIFIER) && defined(KVM_ARCH_WANT_MMU_NOTIFIER) mmu_notifier_unregister(&kvm->mmu_notifier, kvm->mm); +#else + kvm_arch_flush_shadow(kvm); #endif kvm_arch_destroy_vm(kvm); mmdrop(mm); @@ -919,9 +1086,8 @@ int __kvm_set_memory_region(struct kvm *kvm, { int r; gfn_t base_gfn; - unsigned long npages; - int largepages; - unsigned long i; + unsigned long npages, ugfn; + unsigned long largepages, i; struct kvm_memory_slot *memslot; struct kvm_memory_slot old, new; @@ -1010,6 +1176,14 @@ int __kvm_set_memory_region(struct kvm *kvm, new.lpage_info[0].write_count = 1; if ((base_gfn+npages) % KVM_PAGES_PER_HPAGE) new.lpage_info[largepages-1].write_count = 1; + ugfn = new.userspace_addr >> PAGE_SHIFT; + /* + * If the gfn and userspace address are not aligned wrt each + * other, disable large page support for this slot + */ + if ((base_gfn ^ ugfn) & (KVM_PAGES_PER_HPAGE - 1)) + for (i = 0; i < largepages; ++i) + new.lpage_info[i].write_count = 1; } /* Allocate page dirty bitmap if needed */ @@ -1043,8 +1217,10 @@ int __kvm_set_memory_region(struct kvm *kvm, kvm_free_physmem_slot(&old, npages ? &new : NULL); /* Slot deletion case: we have to update the current slot */ + spin_lock(&kvm->mmu_lock); if (!npages) *memslot = old; + spin_unlock(&kvm->mmu_lock); #ifdef CONFIG_DMAR /* map the pages in iommu page table */ r = kvm_iommu_map_pages(kvm, base_gfn, npages); @@ -1454,12 +1630,14 @@ void kvm_vcpu_block(struct kvm_vcpu *vcpu) for (;;) { prepare_to_wait(&vcpu->wq, &wait, TASK_INTERRUPTIBLE); - if (kvm_cpu_has_interrupt(vcpu) || - kvm_cpu_has_pending_timer(vcpu) || - kvm_arch_vcpu_runnable(vcpu)) { + if ((kvm_arch_interrupt_allowed(vcpu) && + kvm_cpu_has_interrupt(vcpu)) || + kvm_arch_vcpu_runnable(vcpu)) { set_bit(KVM_REQ_UNHALT, &vcpu->requests); break; } + if (kvm_cpu_has_pending_timer(vcpu)) + break; if (signal_pending(current)) break; @@ -1593,6 +1771,88 @@ static int kvm_vcpu_ioctl_set_sigmask(struct kvm_vcpu *vcpu, sigset_t *sigset) return 0; } +#ifdef __KVM_HAVE_MSIX +static int kvm_vm_ioctl_set_msix_nr(struct kvm *kvm, + struct kvm_assigned_msix_nr *entry_nr) +{ + int r = 0; + struct kvm_assigned_dev_kernel *adev; + + mutex_lock(&kvm->lock); + + adev = kvm_find_assigned_dev(&kvm->arch.assigned_dev_head, + entry_nr->assigned_dev_id); + if (!adev) { + r = -EINVAL; + goto msix_nr_out; + } + + if (adev->entries_nr == 0) { + adev->entries_nr = entry_nr->entry_nr; + if (adev->entries_nr == 0 || + adev->entries_nr >= KVM_MAX_MSIX_PER_DEV) { + r = -EINVAL; + goto msix_nr_out; + } + + adev->host_msix_entries = kzalloc(sizeof(struct msix_entry) * + entry_nr->entry_nr, + GFP_KERNEL); + if (!adev->host_msix_entries) { + r = -ENOMEM; + goto msix_nr_out; + } + adev->guest_msix_entries = kzalloc( + sizeof(struct kvm_guest_msix_entry) * + entry_nr->entry_nr, GFP_KERNEL); + if (!adev->guest_msix_entries) { + kfree(adev->host_msix_entries); + r = -ENOMEM; + goto msix_nr_out; + } + } else /* Not allowed set MSI-X number twice */ + r = -EINVAL; +msix_nr_out: + mutex_unlock(&kvm->lock); + return r; +} + +static int kvm_vm_ioctl_set_msix_entry(struct kvm *kvm, + struct kvm_assigned_msix_entry *entry) +{ + int r = 0, i; + struct kvm_assigned_dev_kernel *adev; + + mutex_lock(&kvm->lock); + + adev = kvm_find_assigned_dev(&kvm->arch.assigned_dev_head, + entry->assigned_dev_id); + + if (!adev) { + r = -EINVAL; + goto msix_entry_out; + } + + for (i = 0; i < adev->entries_nr; i++) + if (adev->guest_msix_entries[i].vector == 0 || + adev->guest_msix_entries[i].entry == entry->entry) { + adev->guest_msix_entries[i].entry = entry->entry; + adev->guest_msix_entries[i].vector = entry->gsi; + adev->host_msix_entries[i].entry = entry->entry; + break; + } + if (i == adev->entries_nr) { + r = -ENOSPC; + goto msix_entry_out; + } + +msix_entry_out: + mutex_unlock(&kvm->lock); + + return r; +} +#endif + static long kvm_vcpu_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { @@ -1864,6 +2124,11 @@ static long kvm_vm_ioctl(struct file *filp, break; } case KVM_ASSIGN_IRQ: { + r = -EOPNOTSUPP; + break; + } +#ifdef KVM_CAP_ASSIGN_DEV_IRQ + case KVM_ASSIGN_DEV_IRQ: { struct kvm_assigned_irq assigned_irq; r = -EFAULT; @@ -1874,6 +2139,18 @@ static long kvm_vm_ioctl(struct file *filp, goto out; break; } + case KVM_DEASSIGN_DEV_IRQ: { + struct kvm_assigned_irq assigned_irq; + + r = -EFAULT; + if (copy_from_user(&assigned_irq, argp, sizeof assigned_irq)) + goto out; + r = kvm_vm_ioctl_deassign_dev_irq(kvm, &assigned_irq); + if (r) + goto out; + break; + } +#endif #endif #ifdef KVM_CAP_DEVICE_DEASSIGNMENT case KVM_DEASSIGN_PCI_DEVICE: { @@ -1917,7 +2194,29 @@ static long kvm_vm_ioctl(struct file *filp, vfree(entries); break; } +#ifdef __KVM_HAVE_MSIX + case KVM_ASSIGN_SET_MSIX_NR: { + struct kvm_assigned_msix_nr entry_nr; + r = -EFAULT; + if (copy_from_user(&entry_nr, argp, sizeof entry_nr)) + goto out; + r = kvm_vm_ioctl_set_msix_nr(kvm, &entry_nr); + if (r) + goto out; + break; + } + case KVM_ASSIGN_SET_MSIX_ENTRY: { + struct kvm_assigned_msix_entry entry; + r = -EFAULT; + if (copy_from_user(&entry, argp, sizeof entry)) + goto out; + r = kvm_vm_ioctl_set_msix_entry(kvm, &entry); + if (r) + goto out; + break; + } #endif +#endif /* KVM_CAP_IRQ_ROUTING */ default: r = kvm_arch_vm_ioctl(filp, ioctl, arg); } @@ -2112,15 +2411,15 @@ EXPORT_SYMBOL_GPL(kvm_handle_fault_on_reboot); static int kvm_reboot(struct notifier_block *notifier, unsigned long val, void *v) { - if (val == SYS_RESTART) { - /* - * Some (well, at least mine) BIOSes hang on reboot if - * in vmx root mode. - */ - printk(KERN_INFO "kvm: exiting hardware virtualization\n"); - kvm_rebooting = true; - on_each_cpu(hardware_disable, NULL, 1); - } + /* + * Some (well, at least mine) BIOSes hang on reboot if + * in vmx root mode. + * + * And Intel TXT required VMX off for all cpu when system shutdown. + */ + printk(KERN_INFO "kvm: exiting hardware virtualization\n"); + kvm_rebooting = true; + on_each_cpu(hardware_disable, NULL, 1); return NOTIFY_OK; } @@ -2305,7 +2604,6 @@ int kvm_init(void *opaque, unsigned int vcpu_size, r = -ENOMEM; goto out_free_0; } - cpumask_clear(cpus_hardware_enabled); r = kvm_arch_hardware_setup(); if (r < 0) @@ -2354,9 +2652,6 @@ int kvm_init(void *opaque, unsigned int vcpu_size, kvm_preempt_ops.sched_in = kvm_sched_in; kvm_preempt_ops.sched_out = kvm_sched_out; -#ifndef CONFIG_X86 - msi2intx = 0; -#endif return 0;